feat(接口测试): 接口场景定时任务配置功能开发
This commit is contained in:
parent
b10350040d
commit
0beb6ebc10
|
@ -217,6 +217,17 @@ public class ApiScenarioController {
|
|||
return apiScenarioService.scheduleConfig(request, SessionUtils.getUserId());
|
||||
}
|
||||
|
||||
@GetMapping(value = "/schedule-config-delete/{scenarioId}")
|
||||
@Operation(summary = "接口测试-接口场景管理-删除定时任务配置")
|
||||
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_EXECUTE)
|
||||
@Log(type = OperationLogType.UPDATE, expression = "#msClass.scheduleLog(#request.getScenarioId())", msClass = ApiScenarioLogService.class)
|
||||
@CheckOwner(resourceId = "#request.getScenarioId()", resourceType = "api_scenario")
|
||||
@SendNotice(taskType = NoticeConstants.TaskType.SCHEDULE_TASK, event = NoticeConstants.Event.UPDATE, target = "#targetClass.getScheduleNotice(#request)", targetClass = ApiScenarioNoticeService.class)
|
||||
public void deleteScheduleConfig(@PathVariable String scenarioId) {
|
||||
apiValidateService.validateApiMenuInProject(scenarioId, ApiResource.API_SCENARIO.name());
|
||||
apiScenarioService.deleteScheduleConfig(scenarioId);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/association/page")
|
||||
@Operation(summary = "接口测试-接口场景管理-场景引用关系列表")
|
||||
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_READ)
|
||||
|
|
|
@ -22,14 +22,8 @@ public class ApiScenarioDTO extends ApiScenario {
|
|||
private String modulePath;
|
||||
@Schema(description = "环境名称")
|
||||
private String environmentName;
|
||||
@Schema(description = "定时任务ID")
|
||||
private String scheduleId;
|
||||
@Schema(description = "定时任务是否开启")
|
||||
private Boolean scheduleEnable;
|
||||
@Schema(description = "定时任务规则")
|
||||
private String scheduleCorn;
|
||||
@Schema(description = "定时任务配置")
|
||||
private ApiScenarioScheduleConfigRequest scheduleConfig;
|
||||
@Schema(description = "定时任务下一次执行时间")
|
||||
private Long scheduleExecuteTime;
|
||||
|
||||
|
||||
private Long nextTriggerTime;
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ import io.metersphere.sdk.domain.Environment;
|
|||
import io.metersphere.sdk.domain.EnvironmentExample;
|
||||
import io.metersphere.sdk.domain.EnvironmentGroup;
|
||||
import io.metersphere.sdk.domain.EnvironmentGroupExample;
|
||||
import io.metersphere.sdk.dto.api.task.ApiRunModeConfigDTO;
|
||||
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
import io.metersphere.sdk.file.FileCenter;
|
||||
|
@ -236,10 +237,17 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
}
|
||||
if (MapUtils.isNotEmpty(scheduleMap) && scheduleMap.containsKey(item.getId())) {
|
||||
Schedule schedule = scheduleMap.get(item.getId());
|
||||
item.setScheduleId(schedule.getId());
|
||||
item.setScheduleEnable(schedule.getEnable());
|
||||
item.setScheduleCorn(schedule.getValue());
|
||||
item.setScheduleExecuteTime(getNextTriggerTime(schedule.getValue()));
|
||||
ApiScenarioScheduleConfigRequest request = new ApiScenarioScheduleConfigRequest();
|
||||
request.setEnable(schedule.getEnable());
|
||||
request.setCron(schedule.getValue());
|
||||
request.setScenarioId(item.getId());
|
||||
if (schedule.getConfig() != null) {
|
||||
request.setConfig(JSON.parseObject(schedule.getConfig(), ApiRunModeConfigDTO.class));
|
||||
}
|
||||
item.setScheduleConfig(request);
|
||||
if (schedule.getEnable()) {
|
||||
item.setNextTriggerTime(getNextTriggerTime(schedule.getValue()));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -2390,6 +2398,9 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
}
|
||||
|
||||
|
||||
public void deleteScheduleConfig(String scenarioId) {
|
||||
scheduleService.deleteByResourceId(scenarioId, ApiScenarioScheduleJob.getJobKey(scenarioId), ApiScenarioScheduleJob.getTriggerKey(scenarioId));
|
||||
}
|
||||
public String scheduleConfig(ApiScenarioScheduleConfigRequest scheduleRequest, String operator) {
|
||||
ApiScenario apiScenario = apiScenarioMapper.selectByPrimaryKey(scheduleRequest.getScenarioId());
|
||||
ScheduleConfig scheduleConfig = ScheduleConfig.builder()
|
||||
|
|
|
@ -12,8 +12,8 @@ import io.metersphere.api.dto.definition.*;
|
|||
import io.metersphere.api.dto.request.ApiTransferRequest;
|
||||
import io.metersphere.api.dto.request.controller.*;
|
||||
import io.metersphere.api.dto.request.controller.loop.*;
|
||||
import io.metersphere.api.dto.request.http.MsHeader;
|
||||
import io.metersphere.api.dto.request.http.MsHTTPElement;
|
||||
import io.metersphere.api.dto.request.http.MsHeader;
|
||||
import io.metersphere.api.dto.request.http.QueryParam;
|
||||
import io.metersphere.api.dto.response.ApiScenarioBatchOperationResponse;
|
||||
import io.metersphere.api.dto.response.OperationDataInfo;
|
||||
|
@ -1945,6 +1945,7 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
@Order(23)
|
||||
void scheduleTest() throws Exception {
|
||||
String testUrl = "/schedule-config";
|
||||
String deleteUrl = "/schedule-config-delete/";
|
||||
|
||||
if (CollectionUtils.isEmpty(BATCH_OPERATION_SCENARIO_ID)) {
|
||||
this.batchCreateScenarios();
|
||||
|
@ -1952,6 +1953,7 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
|
||||
//使用最后一个场景ID用于做定时任务的测试
|
||||
String scenarioId = BATCH_OPERATION_SCENARIO_ID.getLast();
|
||||
deleteUrl += scenarioId;
|
||||
ApiScenarioScheduleConfigRequest request = new ApiScenarioScheduleConfigRequest();
|
||||
|
||||
request.setScenarioId(scenarioId);
|
||||
|
@ -1961,6 +1963,7 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
//先测试一下没有开启模块时接口能否使用
|
||||
apiScenarioBatchOperationTestService.removeApiModule(DEFAULT_PROJECT_ID);
|
||||
this.requestPost(testUrl, request).andExpect(status().is5xxServerError());
|
||||
this.requestGet(deleteUrl, request).andExpect(status().is5xxServerError());
|
||||
//恢复
|
||||
apiScenarioBatchOperationTestService.resetProjectModule(DEFAULT_PROJECT_ID);
|
||||
MvcResult result = this.requestPostAndReturn(testUrl, request);
|
||||
|
@ -2062,6 +2065,10 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
request.setCron(IDGenerator.nextStr());
|
||||
this.requestPost(testUrl, request).andExpect(status().is5xxServerError());
|
||||
|
||||
//测试删除
|
||||
this.requestGetWithOk(deleteUrl, request);
|
||||
apiScenarioBatchOperationTestService.checkScheduleIsRemove(scenarioId);
|
||||
|
||||
}
|
||||
|
||||
//30开始是关于删除和恢复的
|
||||
|
|
|
@ -53,6 +53,14 @@ public class ScheduleService {
|
|||
return null;
|
||||
}
|
||||
|
||||
public int deleteByResourceId(String scenarioId, JobKey jobKey, TriggerKey triggerKey) {
|
||||
ScheduleExample scheduleExample = new ScheduleExample();
|
||||
scheduleExample.createCriteria().andResourceIdEqualTo(scenarioId);
|
||||
|
||||
scheduleManager.removeJob(jobKey, triggerKey);
|
||||
return scheduleMapper.deleteByExample(scheduleExample);
|
||||
}
|
||||
|
||||
public int deleteByResourceId(String resourceId, String group) {
|
||||
ScheduleExample scheduleExample = new ScheduleExample();
|
||||
scheduleExample.createCriteria().andResourceIdEqualTo(resourceId);
|
||||
|
|
|
@ -27,6 +27,8 @@ import {
|
|||
RecycleScenarioUrl,
|
||||
ScenarioHistoryUrl,
|
||||
ScenarioPageUrl,
|
||||
ScenarioScheduleConfigDeleteUrl,
|
||||
ScenarioScheduleConfigUrl,
|
||||
ScenarioTransferFileUrl,
|
||||
ScenarioTransferModuleOptionsUrl,
|
||||
ScenarioTrashPageUrl,
|
||||
|
@ -44,6 +46,7 @@ import {
|
|||
ApiScenarioGetModuleParams,
|
||||
ApiScenarioModuleUpdateParams,
|
||||
ApiScenarioPageParams,
|
||||
ApiScenarioScheduleConfig,
|
||||
ApiScenarioTableItem,
|
||||
ApiScenarioUpdateDTO,
|
||||
ExecuteHistoryItem,
|
||||
|
@ -155,6 +158,16 @@ export function batchRunScenario(params: ApiScenarioBatchRunParams) {
|
|||
return MSR.post({ url: BatchRunScenarioUrl, params });
|
||||
}
|
||||
|
||||
// 批量编辑场景
|
||||
export function scenarioScheduleConfig(params: ApiScenarioScheduleConfig) {
|
||||
return MSR.post({ url: ScenarioScheduleConfigUrl, params });
|
||||
}
|
||||
|
||||
// 删除定时任务配置
|
||||
export function deleteScheduleConfig(id: string) {
|
||||
return MSR.get({ url: ScenarioScheduleConfigDeleteUrl, params: id });
|
||||
}
|
||||
|
||||
// 场景执行历史接口
|
||||
export function getExecuteHistory(data: ExecutePageParams) {
|
||||
return MSR.post<CommonList<ExecuteHistoryItem>>({ url: ExecuteHistoryUrl, data });
|
||||
|
|
|
@ -17,6 +17,8 @@ export const DebugScenarioUrl = '/api/scenario/debug'; // 接口场景调试(
|
|||
export const ExecuteScenarioUrl = '/api/scenario/run'; // 接口场景执行(保存报告)
|
||||
export const GetSystemRequestUrl = '/api/scenario/get/system-request'; // 获取导入的系统请求数据
|
||||
export const FollowScenarioUrl = '/api/scenario/follow'; // 关注/取消关注接口场景
|
||||
export const ScenarioScheduleConfigUrl = '/api/scenario/schedule-config'; // 场景定时任务
|
||||
export const ScenarioScheduleConfigDeleteUrl = '/api/scenario/schedule-config-delete/'; // 场景定时任务
|
||||
export const BatchRecycleScenarioUrl = '/api/scenario/batch-operation/delete-gc'; // 批量删除接口场景
|
||||
export const BatchMoveScenarioUrl = '/api/scenario/batch-operation/move'; // 批量移动接口场景
|
||||
export const BatchCopyScenarioUrl = '/api/scenario/batch-operation/copy'; // 批量复制接口场景
|
||||
|
|
|
@ -46,6 +46,18 @@ export interface ApiScenarioGetModuleParams {
|
|||
refId?: string;
|
||||
}
|
||||
|
||||
// 场景定时任务配置
|
||||
export interface ApiScenarioScheduleConfig {
|
||||
scenarioId: string;
|
||||
enable: boolean;
|
||||
cron: string;
|
||||
config: {
|
||||
poolId: string;
|
||||
grouped: false;
|
||||
environmentId?: string;
|
||||
};
|
||||
}
|
||||
|
||||
// 场景详情
|
||||
export interface ApiScenarioTableItem {
|
||||
id: string;
|
||||
|
@ -79,6 +91,7 @@ export interface ApiScenarioTableItem {
|
|||
description: string;
|
||||
status: RequestDefinitionStatus;
|
||||
customFields: ApiDefinitionCustomField[];
|
||||
scheduleConfig?: ApiScenarioScheduleConfig;
|
||||
}
|
||||
|
||||
// 场景列表查询参数
|
||||
|
|
|
@ -62,7 +62,46 @@
|
|||
</a-trigger>
|
||||
</template>
|
||||
<template #num="{ record }">
|
||||
<MsButton type="text" @click="openScenarioTab(record)">{{ record.num }}</MsButton>
|
||||
<div>
|
||||
<MsButton type="text" class="float-left" style="margin-right: 4px" @click="openScenarioTab(record)">{{
|
||||
record.num
|
||||
}}</MsButton>
|
||||
<div v-if="record.scheduleConfig && record.scheduleConfig.enable" class="float-right">
|
||||
<a-tooltip position="top">
|
||||
<template #content>
|
||||
<span>
|
||||
{{ t('apiScenario.schedule.table.tooltip.enable.one') }}
|
||||
</span>
|
||||
<br />
|
||||
<span>
|
||||
{{
|
||||
t('apiScenario.schedule.table.tooltip.enable.two', {
|
||||
time: dayjs(record.nextTriggerTime).format('YYYY-MM-DD HH:mm:ss'),
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
</template>
|
||||
<a-tag
|
||||
size="small"
|
||||
style="border-color: #00c261; color: #00c261; background-color: transparent"
|
||||
bordered
|
||||
@click="openScheduleModal(record)"
|
||||
>{{ t('apiScenario.schedule.abbreviation') }}</a-tag
|
||||
>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
<div v-if="record.scheduleConfig && !record.scheduleConfig.enable" class="float-right">
|
||||
<a-tooltip :content="t('apiScenario.schedule.table.tooltip.disable')" position="top">
|
||||
<a-tag
|
||||
size="small"
|
||||
style="border-color: #d4d4d8; color: #323233; background-color: transparent"
|
||||
bordered
|
||||
@click="openScheduleModal(record)"
|
||||
>{{ t('apiScenario.schedule.abbreviation') }}</a-tag
|
||||
>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #status="{ record }">
|
||||
<a-select
|
||||
|
@ -170,7 +209,10 @@
|
|||
{{ t('common.copy') }}
|
||||
</MsButton>
|
||||
<a-divider v-permission="['PROJECT_API_SCENARIO:READ+ADD']" direction="vertical" :margin="8"></a-divider>
|
||||
<MsTableMoreAction :list="tableMoreActionList" @select="handleTableMoreActionSelect($event, record)" />
|
||||
<MsTableMoreAction
|
||||
:list="getTableMoreActionList(record)"
|
||||
@select="handleTableMoreActionSelect($event, record)"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="hasAnyPermission(['PROJECT_API_SCENARIO:READ+ADD'])" #empty>
|
||||
<div class="flex w-full items-center justify-center p-[8px] text-[var(--color-text-4)]">
|
||||
|
@ -182,7 +224,117 @@
|
|||
</template>
|
||||
</ms-base-table>
|
||||
</div>
|
||||
<!-- 定时任务配置-->
|
||||
<a-modal v-model:visible="showScheduleModal" title-align="start" class="ms-modal-upload ms-modal-medium" :width="600">
|
||||
<template #title>
|
||||
<div>
|
||||
{{ scheduleModalTitle }}
|
||||
<div class="text-[var(--color-text-4)]">
|
||||
{{ '(' + tableRecord?.name + ')' }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<a-form ref="scheduleConfigRef" class="rounded-[4px]" :model="scheduleConfig" layout="vertical">
|
||||
<!-- 触发时间-->
|
||||
<a-form-item :label="t('apiScenario.schedule.task.schedule')">
|
||||
<a-select v-model:model-value="scheduleConfig.cron">
|
||||
<template #label="{ data }">
|
||||
<div class="flex items-center">
|
||||
{{ data.value }}
|
||||
<div class="ml-[4px] text-[var(--color-text-4)]">{{ data.label.split('?')[1] }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<a-option v-for="item of syncFrequencyOptions" :key="item.value" :value="item.value" class="block">
|
||||
<div class="flex w-full items-center justify-between">
|
||||
{{ item.value }}
|
||||
<div class="ml-[4px] text-[var(--color-text-4)]">{{ item.label }}</div>
|
||||
</div>
|
||||
</a-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<!-- 环境选择-->
|
||||
<a-form-item :label="t('case.execute.selectEnv')">
|
||||
<a-radio-group v-model:model-value="scheduleUseNewEnv" type="radio">
|
||||
<a-radio :value="false"
|
||||
>{{ t('case.execute.defaultEnv') }}
|
||||
<a-tooltip :content="t('case.execute.defaultEnvTip')" position="top">
|
||||
<icon-question-circle
|
||||
class="text-[var(--color-text-brand)] hover:text-[rgb(var(--primary-5))]"
|
||||
size="16"
|
||||
/>
|
||||
</a-tooltip>
|
||||
</a-radio>
|
||||
<a-radio :value="true">{{ t('case.execute.newEnv') }}</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<!-- 新环境 -->
|
||||
<a-form-item
|
||||
v-if="scheduleUseNewEnv"
|
||||
field="config.environmentId"
|
||||
:label="t('case.execute.newEnv')"
|
||||
:rules="[{ required: true, message: t('apiTestManagement.envRequired') }]"
|
||||
asterisk-position="end"
|
||||
required
|
||||
>
|
||||
<a-select v-model="scheduleConfig.config.environmentId" :placeholder="t('common.pleaseSelect')">
|
||||
<a-option v-for="item of environmentList" :key="item.id" :value="item.id">
|
||||
{{ t(item.name) }}
|
||||
</a-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<!-- 运行资源池 设计稿中最后一行取消margin-bottom-->
|
||||
<a-form-item
|
||||
field="config.poolId"
|
||||
:label="t('apiScenario.schedule.config.resource_pool')"
|
||||
:rules="[{ required: true, message: t('apiTestManagement.poolRequired') }]"
|
||||
asterisk-position="end"
|
||||
required
|
||||
class="mb-0"
|
||||
>
|
||||
<a-select v-model="scheduleConfig.config.poolId" :placeholder="t('common.pleaseSelect')">
|
||||
<a-option v-for="item of environmentList" :key="item.id" :value="item.id">
|
||||
{{ t(item.name) }}
|
||||
</a-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<template #footer>
|
||||
<div class="flex" :class="['justify-between']">
|
||||
<div class="flex flex-row items-center justify-center">
|
||||
<a-switch v-model="scheduleConfig.enable" class="mr-1" size="small" type="line" />
|
||||
<a-tooltip>
|
||||
<template #content>
|
||||
<span>
|
||||
{{ t('apiScenario.schedule.task.status.tooltip.one') }}
|
||||
</span>
|
||||
<br />
|
||||
<span>
|
||||
{{ t('apiScenario.schedule.task.status.tooltip.two') }}
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<span class="flex items-center">
|
||||
<span class="mr-1">{{ t('apiScenario.schedule.task.status') }}</span>
|
||||
<span class="mt-[2px]">
|
||||
<IconQuestionCircle class="h-[16px] w-[16px] text-[rgb(var(--primary-5))]" />
|
||||
</span>
|
||||
</span>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end">
|
||||
<a-button type="secondary" :disabled="scheduleModalLoading" @click="cancelScheduleModal">
|
||||
{{ t('common.cancel') }}
|
||||
</a-button>
|
||||
<a-button class="ml-3" type="primary" :loading="scheduleModalLoading" @click="saveScheduleModal">
|
||||
{{ t('common.save') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-modal>
|
||||
|
||||
<!-- 表格批量操作-->
|
||||
<a-modal v-model:visible="showBatchModal" title-align="start" class="ms-modal-upload ms-modal-medium" :width="480">
|
||||
<template #title>
|
||||
{{ t('common.batchEdit') }}
|
||||
|
@ -341,8 +493,9 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { FormInstance, Message } from '@arco-design/web-vue';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
|
@ -356,17 +509,19 @@
|
|||
import type { CaseLevel } from '@/components/business/ms-case-associate/types';
|
||||
import type { MsTreeNodeData } from '@/components/business/ms-tree/types';
|
||||
import apiStatus from '@/views/api-test/components/apiStatus.vue';
|
||||
import BatchRunModal from '@/views/api-test/components/batchRunModal.vue';
|
||||
import ExecutionStatus from '@/views/api-test/report/component/reportStatus.vue';
|
||||
import operationScenarioModuleTree from '@/views/api-test/scenario/components/operationScenarioModuleTree.vue';
|
||||
|
||||
import { getEnvList } from '@/api/modules/api-test/management';
|
||||
import {
|
||||
batchEditScenario,
|
||||
batchOptionScenario,
|
||||
batchRecycleScenario,
|
||||
batchRunScenario,
|
||||
deleteScheduleConfig,
|
||||
getScenarioPage,
|
||||
recycleScenario,
|
||||
scenarioScheduleConfig,
|
||||
updateScenario,
|
||||
} from '@/api/modules/api-test/scenario';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
@ -375,7 +530,8 @@
|
|||
import useAppStore from '@/store/modules/app';
|
||||
import { hasAnyPermission } from '@/utils/permission';
|
||||
|
||||
import { ApiScenarioTableItem, ApiScenarioUpdateDTO } from '@/models/apiTest/scenario';
|
||||
import { Environment } from '@/models/apiTest/management';
|
||||
import { ApiScenarioScheduleConfig, ApiScenarioTableItem, ApiScenarioUpdateDTO } from '@/models/apiTest/scenario';
|
||||
import { ApiScenarioStatus } from '@/enums/apiEnum';
|
||||
import { ReportEnum, ReportStatus } from '@/enums/reportEnum';
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
|
@ -400,6 +556,27 @@
|
|||
const appStore = useAppStore();
|
||||
const { t } = useI18n();
|
||||
const { openModal } = useModal();
|
||||
const tableRecord = ref<ApiScenarioTableItem>();
|
||||
const scheduleModalTitle = ref('');
|
||||
|
||||
const scheduleConfig = ref<ApiScenarioScheduleConfig>({
|
||||
scenarioId: '',
|
||||
enable: false,
|
||||
cron: '',
|
||||
config: {
|
||||
poolId: '',
|
||||
grouped: false,
|
||||
},
|
||||
});
|
||||
|
||||
const scheduleUseNewEnv = ref(false);
|
||||
|
||||
const environmentList = ref<Environment[]>();
|
||||
// 初始化环境列表
|
||||
async function initEnvList() {
|
||||
environmentList.value = await getEnvList(appStore.currentProjectId);
|
||||
}
|
||||
|
||||
const scenarioPriorityList = ref([
|
||||
{
|
||||
value: 'P0',
|
||||
|
@ -435,8 +612,8 @@
|
|||
sorter: true,
|
||||
},
|
||||
fixed: 'left',
|
||||
width: 100,
|
||||
showTooltip: true,
|
||||
width: 140,
|
||||
showTooltip: false,
|
||||
columnSelectorDisabled: true,
|
||||
},
|
||||
{
|
||||
|
@ -601,14 +778,40 @@
|
|||
},
|
||||
],
|
||||
};
|
||||
const tableMoreActionList = [
|
||||
{
|
||||
eventTag: 'delete',
|
||||
label: t('common.delete'),
|
||||
permission: ['PROJECT_API_SCENARIO:READ+DELETE'],
|
||||
danger: true,
|
||||
},
|
||||
];
|
||||
|
||||
function getTableMoreActionList(tableRow: ApiScenarioTableItem) {
|
||||
if (tableRow.scheduleConfig) {
|
||||
// 删除定时任务
|
||||
return [
|
||||
{
|
||||
eventTag: 'deleteSchedule',
|
||||
label: t('apiScenario.schedule.delete'),
|
||||
permission: ['PROJECT_API_SCENARIO:READ+EXECUTE'],
|
||||
danger: true,
|
||||
},
|
||||
{
|
||||
eventTag: 'delete',
|
||||
label: t('common.delete'),
|
||||
permission: ['PROJECT_API_SCENARIO:READ+DELETE'],
|
||||
danger: true,
|
||||
},
|
||||
];
|
||||
}
|
||||
return [
|
||||
{
|
||||
eventTag: 'schedule',
|
||||
label: t('apiScenario.schedule.create'),
|
||||
permission: ['PROJECT_API_SCENARIO:READ+EXECUTE'],
|
||||
danger: false,
|
||||
},
|
||||
{
|
||||
eventTag: 'delete',
|
||||
label: t('common.delete'),
|
||||
permission: ['PROJECT_API_SCENARIO:READ+DELETE'],
|
||||
danger: true,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
const statusFilterVisible = ref(false);
|
||||
const statusFilters = ref<string[]>([]);
|
||||
|
@ -760,6 +963,56 @@
|
|||
});
|
||||
}
|
||||
|
||||
const showScheduleModal = ref(false);
|
||||
const syncFrequencyOptions = [
|
||||
{ label: t('apiTestManagement.timeTaskHour'), value: '0 0 0/1 * * ? ' },
|
||||
{ label: t('apiTestManagement.timeTaskSixHour'), value: '0 0 0/6 * * ?' },
|
||||
{ label: t('apiTestManagement.timeTaskTwelveHour'), value: '0 0 0/12 * * ?' },
|
||||
{ label: t('apiTestManagement.timeTaskDay'), value: '0 0 0 * * ?' },
|
||||
];
|
||||
|
||||
function resetScheduleConfig(record: ApiScenarioTableItem) {
|
||||
// 初始化已选择的表格数据
|
||||
tableRecord.value = record;
|
||||
if (record.scheduleConfig) {
|
||||
scheduleConfig.value = cloneDeep(record.scheduleConfig);
|
||||
} else {
|
||||
// 初始化定时任务配置
|
||||
scheduleConfig.value = {
|
||||
scenarioId: record.id,
|
||||
enable: false,
|
||||
cron: '0 0 0/1 * * ? ',
|
||||
config: {
|
||||
poolId: '',
|
||||
grouped: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
scheduleUseNewEnv.value = !!scheduleConfig.value.config.environmentId;
|
||||
// 初始化环境
|
||||
initEnvList();
|
||||
// 初始化弹窗标题
|
||||
if (tableRecord.value.scheduleConfig) {
|
||||
scheduleModalTitle.value = t('apiScenario.schedule.update');
|
||||
} else {
|
||||
scheduleModalTitle.value = t('apiScenario.schedule.create');
|
||||
}
|
||||
}
|
||||
|
||||
function openScheduleModal(record: ApiScenarioTableItem) {
|
||||
resetScheduleConfig(record);
|
||||
showScheduleModal.value = true;
|
||||
}
|
||||
async function deleteScenarioSchedule(scenarioId: string) {
|
||||
try {
|
||||
await deleteScheduleConfig(scenarioId);
|
||||
Message.success(t('common.deleteSuccess'));
|
||||
loadScenarioList(false);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理表格更多按钮事件
|
||||
* @param item
|
||||
|
@ -769,11 +1022,48 @@
|
|||
case 'delete':
|
||||
deleteScenario(record);
|
||||
break;
|
||||
case 'schedule':
|
||||
openScheduleModal(record);
|
||||
break;
|
||||
case 'deleteSchedule':
|
||||
deleteScenarioSchedule(record.id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const scheduleConfigRef = ref<FormInstance>();
|
||||
const scheduleModalLoading = ref(false);
|
||||
|
||||
function cancelScheduleModal() {
|
||||
showScheduleModal.value = false;
|
||||
}
|
||||
function saveScheduleModal() {
|
||||
scheduleConfigRef.value?.validate(async (errors) => {
|
||||
if (!errors) {
|
||||
try {
|
||||
scheduleModalLoading.value = true;
|
||||
await scenarioScheduleConfig({ ...scheduleConfig.value });
|
||||
// 初始化弹窗标题
|
||||
if (tableRecord.value?.scheduleConfig) {
|
||||
Message.success(t('common.updateSuccess'));
|
||||
} else {
|
||||
Message.success(t('common.createSuccess'));
|
||||
}
|
||||
cancelScheduleModal();
|
||||
resetSelector();
|
||||
loadScenarioList(true);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
} finally {
|
||||
scheduleModalLoading.value = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理表格选中
|
||||
*/
|
||||
|
@ -783,7 +1073,9 @@
|
|||
|
||||
const showBatchModal = ref(false);
|
||||
const batchUpdateLoading = ref(false);
|
||||
|
||||
const batchFormRef = ref<FormInstance>();
|
||||
|
||||
const batchForm = ref({
|
||||
attr: '',
|
||||
value: '',
|
||||
|
|
|
@ -99,4 +99,17 @@ export default {
|
|||
'As long as the system extracts the returned cookie information from the result of a certain step, the subsequent steps will use this cookie. If a cookie variable is added to the request, it will also be overwritten',
|
||||
'apiScenario.setting.waitTime.tip':
|
||||
'When running a scenario, each step of the scenario will wait for a certain time after execution before triggering the next step to start execution',
|
||||
// 定时任务
|
||||
'apiScenario.schedule.create': 'Create schedule',
|
||||
'apiScenario.schedule.update': 'Update schedule',
|
||||
'apiScenario.schedule.delete': 'Delete schedule',
|
||||
'apiScenario.schedule.config.resource_pool': 'Resource pool',
|
||||
'apiScenario.schedule.task.status': 'Task status',
|
||||
'apiScenario.schedule.task.schedule': 'Trigger time',
|
||||
'apiScenario.schedule.abbreviation': 'SCHEDULE',
|
||||
'apiScenario.schedule.task.status.tooltip.one': 'Open: execute schedule task',
|
||||
'apiScenario.schedule.task.status.tooltip.two': 'Close: stop executing schedule task',
|
||||
'apiScenario.schedule.table.tooltip.enable.one': 'Schedule is open',
|
||||
'apiScenario.schedule.table.tooltip.enable.two': 'Next trigger time:{time}',
|
||||
'apiScenario.schedule.table.tooltip.disable': 'Schedule is close',
|
||||
};
|
||||
|
|
|
@ -222,4 +222,17 @@ export default {
|
|||
'apiScenario.setting.share.cookie.tip':
|
||||
'系统只要从某个步骤的结果内提取到返回的cookie信息,则后续步骤都会使用此 cookie ,如果请求添加了Cookie 变量也会被覆盖',
|
||||
'apiScenario.setting.waitTime.tip': '运行场景时,场景的每一个步骤执行后都会等待相应的时间再触发下一个步骤开始执行',
|
||||
// 定时任务
|
||||
'apiScenario.schedule.create': '创建定时任务',
|
||||
'apiScenario.schedule.update': '更新定时任务',
|
||||
'apiScenario.schedule.delete': '删除定时任务',
|
||||
'apiScenario.schedule.config.resource_pool': '运行资源池',
|
||||
'apiScenario.schedule.task.status': '任务状态',
|
||||
'apiScenario.schedule.task.schedule': '任务触发时间',
|
||||
'apiScenario.schedule.abbreviation': '定时',
|
||||
'apiScenario.schedule.task.status.tooltip.one': '开启:执行定时任务',
|
||||
'apiScenario.schedule.task.status.tooltip.two': '关闭:停止定时任务',
|
||||
'apiScenario.schedule.table.tooltip.enable.one': '定时任务已开启',
|
||||
'apiScenario.schedule.table.tooltip.enable.two': '下次运行时间:{time}',
|
||||
'apiScenario.schedule.table.tooltip.disable': '定时任务未开启',
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue