feat(定时任务): 测试计划&接口场景批量配置定时任务

This commit is contained in:
baiqi 2024-11-05 10:41:06 +08:00 committed by Craftsman
parent 9e5b3208b7
commit 33b82819ef
11 changed files with 159 additions and 18 deletions

View File

@ -1,7 +1,6 @@
import type { CaseLevel } from '@/components/business/ms-case-associate/types';
import MSR from '@/api/http/index';
import { ExportDefinitionUrl, StopApiExportUrl } from '@/api/requrls/api-test/management';
import {
AddModuleUrl,
AddScenarioUrl,
@ -35,6 +34,7 @@ import {
RecoverScenarioUrl,
RecycleScenarioUrl,
ScenarioAssociateExportUrl,
ScenarioBatchEditScheduleUrl,
ScenarioBatchExportLogUrl,
ScenarioExportLogUrl,
ScenarioHistoryUrl,
@ -54,12 +54,12 @@ import {
} from '@/api/requrls/api-test/scenario';
import { ExecuteConditionProcessor } from '@/models/apiTest/common';
import type { ApiDefinitionBatchExportParams } from '@/models/apiTest/management';
import {
ApiScenarioBatchDeleteParams,
ApiScenarioBatchEditParams,
ApiScenarioBatchOptionResult,
ApiScenarioBatchRunParams,
type ApiScenarioBatchScheduleConfig,
ApiScenarioDebugRequest,
ApiScenarioGetModuleParams,
ApiScenarioModuleUpdateParams,
@ -364,3 +364,8 @@ export function getScenarioDownloadFile(projectId: string, fileId: string) {
{ isTransformResponse: false }
);
}
// 批量编辑场景定时任务
export function scenarioBatchEditSchedule(data: ApiScenarioBatchScheduleConfig) {
return MSR.post({ url: ScenarioBatchEditScheduleUrl, data });
}

View File

@ -16,6 +16,7 @@ import {
batchArchivedPlanUrl,
BatchAssociatedBugToCaseUrl,
BatchAssociatedBugToMinderCaseUrl,
BatchConfigScheduleUrl,
batchCopyPlanUrl,
batchDeletePlanUrl,
BatchDisassociateApiCaseUrl,
@ -104,6 +105,7 @@ import { DragSortParams, ModuleTreeNode } from '@/models/common';
import type {
AddTestPlanParams,
BatchApiCaseParams,
BatchConfigSchedule,
BatchExecuteFeatureCaseParams,
BatchExecutePlan,
BatchFeatureCaseParams,
@ -426,6 +428,12 @@ export function dragPlanOnGroup(data: DragSortParams) {
export function configSchedule(data: CreateTask) {
return MSR.post({ url: ConfigScheduleUrl, data });
}
// 测试计划-批量配置定时任务
export function batchConfigSchedule(data: BatchConfigSchedule) {
return MSR.post({ url: BatchConfigScheduleUrl, data });
}
// 测试计划-计划&计划组-执行
export function executeSinglePlan(data: ExecutePlan) {
return MSR.post({ url: ExecuteSinglePlanUrl, data });

View File

@ -19,7 +19,7 @@ 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 ScenarioScheduleConfigDeleteUrl = '/api/scenario/schedule-config-delete'; // 删除场景定时任务
export const GetStepProjectInfoUrl = '/api/scenario/step/resource-info'; // 获取跨项目信息
export const BatchRecycleScenarioUrl = '/api/scenario/batch-operation/delete-gc'; // 批量删除接口场景
export const BatchMoveScenarioUrl = '/api/scenario/batch-operation/move'; // 批量移动接口场景
@ -50,3 +50,4 @@ export const ScenarioExportLogUrl = '/api/report/scenario/export'; // 场景导
export const ScenarioBatchExportLogUrl = '/api/report/scenario/batch-export'; // 场景批量导出报告日志记录
export const GetScenarioBatchExportParamsUrl = '/api/report/scenario/batch-param'; // 场景批量导出报告id 集合
export const ScenarioAssociateExportUrl = '/api/scenario/associate/all'; // 接口场景管理-场景导入系统参数
export const ScenarioBatchEditScheduleUrl = '/api/scenario/batch-operation/schedule-config'; // 批量编辑场景定时任务

View File

@ -94,6 +94,8 @@ export const TestPlanGroupOptionsUrl = 'test-plan/group-list';
export const dragPlanOnGroupUrl = '/test-plan/sort';
// 测试计划-创建定时任务
export const ConfigScheduleUrl = '/test-plan/schedule-config';
// 测试计划-批量配置定时任务
export const BatchConfigScheduleUrl = '/test-plan/batch-schedule-config';
// 测试计划-计划&计划组-执行
export const ExecuteSinglePlanUrl = '/test-plan-execute/single';
// 测试计划-计划&计划组-执行&批量执行

View File

@ -61,6 +61,11 @@ export interface ApiScenarioScheduleConfig {
};
}
// 场景-批量编辑定时任务参数
export interface ApiScenarioBatchScheduleConfig extends BatchActionQueryParams, Partial<ApiScenarioScheduleConfig> {
projectId: string;
}
// 场景详情
export interface ApiScenarioTableItem {
id: string;
@ -160,6 +165,8 @@ export interface ApiScenarioBatchEditParams extends ApiScenarioBatchParams {
// 修改优先级
priority?: string;
// 修改定时任务
scheduleOpen?: boolean;
}
// 批量编辑场景参数

View File

@ -396,6 +396,9 @@ export interface CreateTask {
cron: string;
runConfig: { runMode: 'SERIAL' | 'PARALLEL' };
}
export interface BatchConfigSchedule extends Partial<CreateTask>, BatchActionQueryParams {
projectId: string;
}
export interface BatchExecutePlan {
projectId?: string;
executeIds?: string[];

View File

@ -185,7 +185,12 @@
<template #title>
<div class="float-left">
{{ scheduleModalTitle }}
<a-tooltip v-if="translateTextToPX(tableRecord?.name) > 300">
<div v-if="isBatch" class="float-right flex text-[var(--color-text-4)]">
{{ '' }}
<div>{{ batchParams.currentSelectCount || batchParams.selectedIds?.length }}</div>
{{ '' }}
</div>
<a-tooltip v-else-if="translateTextToPX(tableRecord?.name) > 300">
<template #content>
<span>
{{ tableRecord?.name }}
@ -511,6 +516,7 @@
dragSort,
getScenarioPage,
recycleScenario,
scenarioBatchEditSchedule,
scenarioScheduleConfig,
updateScenarioPro,
updateScenarioStatus,
@ -859,6 +865,21 @@
},
],
moreAction: [
{
label: 'testPlan.testPlanIndex.openTimingTask',
eventTag: 'openTimingTask',
permission: ['PROJECT_API_SCENARIO:READ+EXECUTE'],
},
{
label: 'testPlan.testPlanIndex.closeTimingTask',
eventTag: 'closeTimingTask',
permission: ['PROJECT_API_SCENARIO:READ+EXECUTE'],
},
{
label: 'testPlan.testPlanIndex.editTimingTask',
eventTag: 'editTimingTask',
permission: ['PROJECT_API_SCENARIO:READ+EXECUTE'],
},
{
label: 'common.delete',
eventTag: 'delete',
@ -1132,6 +1153,7 @@
maskClosable: false,
onBeforeOk: async () => {
try {
appStore.showLoading();
if (isBatch) {
const batchConditionParams = await getBatchConditionParams();
await batchRecycleScenario({
@ -1150,12 +1172,15 @@
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
appStore.hideLoading();
}
},
hideCancel: false,
});
}
const isBatch = ref(false);
const showScheduleModal = ref(false);
async function resetScheduleConfig(record: ApiScenarioTableItem) {
@ -1191,6 +1216,7 @@
}
async function openScheduleModal(record: ApiScenarioTableItem) {
isBatch.value = false;
await resetScheduleConfig(record);
showScheduleModal.value = true;
}
@ -1245,7 +1271,15 @@
if (!scheduleUseNewEnv.value) {
updateParam.config.environmentId = undefined;
}
await scenarioScheduleConfig(updateParam);
if (isBatch.value) {
await scenarioBatchEditSchedule({
...batchParams.value,
projectId: appStore.currentProjectId,
...updateParam,
});
} else {
await scenarioScheduleConfig(updateParam);
}
//
if (tableRecord.value?.scheduleConfig) {
Message.success(t('common.updateSuccess'));
@ -1451,6 +1485,42 @@
}
}
/**
* 打开关闭定时任务
*/
async function handleBatchToggleSchedule(enable: boolean) {
try {
appStore.showLoading();
const filterParams = {
...propsRes.value.filter,
};
const { selectedIds, selectAll, excludeIds } = batchParams.value;
await batchEditScenario({
selectIds: selectedIds || [],
selectAll: !!selectAll,
excludeIds: excludeIds || [],
projectId: appStore.currentProjectId,
moduleIds: props.activeModule === 'all' ? [] : [props.activeModule, ...props.offspringIds],
condition: {
filter: filterParams,
keyword: keyword.value,
},
type: 'Schedule',
scheduleOpen: enable,
});
Message.success(
enable
? t('testPlan.testPlanGroup.enableScheduleTaskSuccess')
: t('testPlan.testPlanGroup.closeScheduleTaskSuccess')
);
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
appStore.hideLoading();
}
}
/**
* 处理表格选中后批量操作
* @param event 批量操作事件对象
@ -1488,9 +1558,20 @@
break;
case 'execute':
batchOptionParams.value = await getBatchConditionParams();
showBatchExecute.value = true;
break;
case 'openTimingTask':
handleBatchToggleSchedule(true);
break;
case 'closeTimingTask':
handleBatchToggleSchedule(false);
break;
case 'editTimingTask':
isBatch.value = true;
scheduleModalTitle.value = t('testPlan.testPlanIndex.batchUpdateScheduledTask');
showScheduleModal.value = true;
await initResourcePool();
break;
default:
break;
}

View File

@ -329,6 +329,8 @@
:type="planType"
:source-id="planSourceId"
:task-config="taskForm"
:is-batch="isBatch"
:batch-params="batchParams"
@handle-success="fetchData()"
/>
<ActionModal
@ -657,6 +659,11 @@
eventTag: 'closeTimingTask',
permission: ['PROJECT_TEST_PLAN:READ+EXECUTE'],
},
{
label: 'testPlan.testPlanIndex.editTimingTask',
eventTag: 'editTimingTask',
permission: ['PROJECT_TEST_PLAN:READ+EXECUTE'],
},
{
label: 'common.move',
eventTag: 'move',
@ -1329,6 +1336,9 @@
fetchData();
}
const showScheduledTaskModal = ref<boolean>(false);
const isBatch = ref(false);
/**
* 批量操作
*/
@ -1350,6 +1360,10 @@
case 'closeTimingTask':
handleStatusTimingTask(false);
break;
case 'editTimingTask':
isBatch.value = true;
showScheduledTaskModal.value = true;
break;
case 'archive':
handleArchive();
break;
@ -1365,16 +1379,16 @@
}
}
const showScheduledTaskModal = ref<boolean>(false);
const activeRecord = ref<TestPlanItem>();
const taskForm = ref<CreateTask>();
const planSourceId = ref<string>();
const planType = ref<keyof typeof testPlanTypeEnum>(testPlanTypeEnum.TEST_PLAN);
function handleScheduledTask(record: TestPlanItem) {
if (!hasAnyPermission(['PROJECT_TEST_PLAN:READ+EXECUTE'])) {
return;
}
isBatch.value = false;
planType.value = record.type;
planSourceId.value = record.id;
taskForm.value = cloneDeep(defaultCountDetailMap.value[record.id]?.scheduleConfig);

View File

@ -8,8 +8,12 @@
>
<template #title>
{{
props.taskConfig
? t('testPlan.testPlanIndex.updateScheduledTask')
props.taskConfig || props.isBatch
? t(
props.isBatch
? 'testPlan.testPlanIndex.batchUpdateScheduledTask'
: 'testPlan.testPlanIndex.updateScheduledTask'
)
: t('testPlan.testPlanIndex.createScheduledTask')
}}
</template>
@ -82,7 +86,7 @@
<div>
<a-button type="secondary" class="mr-3" @click="handleCancel">{{ t('system.plugin.pluginCancel') }}</a-button>
<a-button type="primary" :loading="confirmLoading" @click="handleCreate">
{{ props.taskConfig ? t('common.update') : t('common.create') }}
{{ props.taskConfig || props.isBatch ? t('common.update') : t('common.create') }}
</a-button>
</div>
</div>
@ -97,9 +101,11 @@
import { cloneDeep } from 'lodash-es';
import MsCronSelect from '@/components/pure/ms-cron-select/index.vue';
import { BatchActionQueryParams } from '@/components/pure/ms-table/type';
import { configSchedule } from '@/api/modules/test-plan/testPlan';
import { batchConfigSchedule, configSchedule } from '@/api/modules/test-plan/testPlan';
import { useI18n } from '@/hooks/useI18n';
import useAppStore from '@/store/modules/app';
import type { CreateTask } from '@/models/testPlan/testPlan';
import { testPlanTypeEnum } from '@/enums/testPlanEnum';
@ -110,6 +116,8 @@
taskConfig?: CreateTask;
type: keyof typeof testPlanTypeEnum;
sourceId?: string;
isBatch?: boolean;
batchParams?: BatchActionQueryParams;
}>();
const emit = defineEmits<{
@ -118,6 +126,8 @@
(e: 'handleSuccess'): void;
}>();
const appStore = useAppStore();
const showModalVisible = useVModel(props, 'visible', emit);
const initForm: CreateTask = {
@ -143,16 +153,22 @@
if (!errors) {
confirmLoading.value = true;
try {
if (props.sourceId) {
if (props.isBatch && props.batchParams) {
await batchConfigSchedule({
...props.batchParams,
...form.value,
projectId: appStore.currentProjectId,
});
} else if (props.sourceId) {
const params = {
...form.value,
resourceId: props.sourceId,
};
await configSchedule(params);
handleCancel();
emit('handleSuccess');
Message.success(props.taskConfig ? t('common.updateSuccess') : t('common.createSuccess'));
}
handleCancel();
emit('handleSuccess');
Message.success(props.taskConfig || props.isBatch ? t('common.updateSuccess') : t('common.createSuccess'));
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);

View File

@ -29,8 +29,9 @@ export default {
'testPlan.testPlanIndex.actualStartToEndTime': 'Actual times',
'testPlan.testPlanIndex.timing': 'Timing',
'testPlan.testPlanIndex.execute': 'execute',
'testPlan.testPlanIndex.openTimingTask': 'Open timing task',
'testPlan.testPlanIndex.closeTimingTask': 'Turn off a timed task',
'testPlan.testPlanIndex.openTimingTask': 'Open scheduled task',
'testPlan.testPlanIndex.closeTimingTask': 'Turn off a scheduled task',
'testPlan.testPlanIndex.editTimingTask': 'Editing scheduled tasks',
'testPlan.testPlanIndex.scheduledTaskOpened': 'The scheduled task has been enabled',
'testPlan.testPlanIndex.nextExecutionTime': 'Next execution time:',
'testPlan.testPlanIndex.scheduledTaskUnEnable': 'The scheduled task is not enabled',
@ -46,6 +47,7 @@ export default {
'Only completed test plans can be archived! \n after filing, implement information no longer update and editing, data unrecoverable, please careful operation.',
'testPlan.testPlanIndex.createScheduledTask': 'Create Scheduled Task',
'testPlan.testPlanIndex.updateScheduledTask': 'Update Scheduled Task',
'testPlan.testPlanIndex.batchUpdateScheduledTask': 'Batch Edit Scheduled Task',
'testPlan.testPlanIndex.deleteScheduledTask': 'Delete Scheduled Task',
'testPlan.testPlanIndex.configuration': 'config',
'testPlan.testPlanIndex.triggerTime': 'Trigger time',

View File

@ -29,6 +29,7 @@ export default {
'testPlan.testPlanIndex.execute': '执行',
'testPlan.testPlanIndex.openTimingTask': '开启定时任务',
'testPlan.testPlanIndex.closeTimingTask': '关闭定时任务',
'testPlan.testPlanIndex.editTimingTask': '编辑定时任务',
'testPlan.testPlanIndex.scheduledTaskOpened': '定时任务已开启',
'testPlan.testPlanIndex.nextExecutionTime': '下次执行时间:',
'testPlan.testPlanIndex.scheduledTaskUnEnable': '定时任务未开启',
@ -43,6 +44,7 @@ export default {
'仅 已完成 测试计划可归档!\r\n 归档后,执行信息不再更新且不可编辑,数据不可恢复,请谨慎操作!',
'testPlan.testPlanIndex.createScheduledTask': '创建定时任务',
'testPlan.testPlanIndex.updateScheduledTask': '更新定时任务',
'testPlan.testPlanIndex.batchUpdateScheduledTask': '批量编辑定时任务',
'testPlan.testPlanIndex.deleteScheduledTask': '删除定时任务',
'testPlan.testPlanIndex.configuration': '配置',
'testPlan.testPlanIndex.triggerTime': '触发时间',