From b29118595dc89c6a8cf2ec17c3b027714b106203 Mon Sep 17 00:00:00 2001 From: teukkk Date: Tue, 11 Jun 2024 17:08:39 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=B5=8B=E8=AF=95=E8=AE=A1=E5=88=92):=20?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E8=AE=A1=E5=88=92=E8=AF=A6=E6=83=85-?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E7=94=A8=E4=BE=8B-=E6=89=B9=E9=87=8F?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=89=A7=E8=A1=8C=E4=BA=BA&=E6=8B=96?= =?UTF-8?q?=E6=8B=BD=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/api/modules/test-plan/testPlan.ts | 16 ++ .../src/api/requrls/test-plan/testPlan.ts | 8 +- frontend/src/models/testPlan/testPlan.ts | 17 +- .../api-test/components/treeFolderAll.vue | 11 +- .../components/batchUpdateExecutorModal.vue | 124 ++++++++++++++ .../detail/apiCase/components/caseTable.vue | 110 ++++++------- .../detail/apiCase/components/caseTree.vue | 13 +- .../testPlan/detail/apiCase/index.vue | 7 +- .../apiScenario/components/scenarioTable.vue | 63 ++++---- .../featureCase/components/caseTable.vue | 151 +++--------------- .../views/test-plan/testPlan/detail/index.vue | 21 ++- .../views/test-plan/testPlan/locale/en-US.ts | 1 + .../views/test-plan/testPlan/locale/zh-CN.ts | 1 + 13 files changed, 308 insertions(+), 235 deletions(-) create mode 100644 frontend/src/views/test-plan/testPlan/components/batchUpdateExecutorModal.vue diff --git a/frontend/src/api/modules/test-plan/testPlan.ts b/frontend/src/api/modules/test-plan/testPlan.ts index f870e045df..a9e8fd2b5b 100644 --- a/frontend/src/api/modules/test-plan/testPlan.ts +++ b/frontend/src/api/modules/test-plan/testPlan.ts @@ -12,6 +12,7 @@ import { BatchEditTestPlanUrl, batchMovePlanUrl, BatchRunCaseUrl, + BatchUpdateApiCaseExecutorUrl, BatchUpdateCaseExecutorUrl, ConfigScheduleUrl, copyTestPlanUrl, @@ -44,6 +45,7 @@ import { PlanDetailExecuteHistoryUrl, planPassRateUrl, RunFeatureCaseUrl, + SortApiCaseUrl, SortFeatureCaseUrl, TestPlanAndGroupCopyUrl, TestPlanApiAssociatedPageUrl, @@ -67,6 +69,7 @@ import type { BatchApiCaseParams, BatchExecuteFeatureCaseParams, BatchFeatureCaseParams, + BatchUpdateApiCaseExecutorParams, BatchUpdateCaseExecutorParams, CreateTask, DisassociateCaseParams, @@ -84,6 +87,7 @@ import type { PlanDetailFeatureCaseItem, PlanDetailFeatureCaseListQueryParams, RunFeatureCaseParams, + SortApiCaseParams, SortFeatureCaseParams, TestPlanBaseParams, TestPlanDetail, @@ -273,6 +277,10 @@ export function getApiCaseModule(data: PlanDetailApiCaseTreeParams) { export function getApiCaseModuleCount(data: PlanDetailApiCaseQueryParams) { return MSR.post({ url: GetApiCaseModuleCountUrl, data }); } +// 计划详情-接口用例列表-拖拽排序 +export const sortApiCase = (data: SortApiCaseParams) => { + return MSR.post({ url: SortApiCaseUrl, data }); +}; // 计划详情-接口用例列表-取消关联用例 export function disassociateApiCase(data: DisassociateCaseParams) { return MSR.post({ url: DisassociateApiCaseUrl, data }); @@ -281,10 +289,18 @@ export function disassociateApiCase(data: DisassociateCaseParams) { export function batchDisassociateApiCase(data: BatchApiCaseParams) { return MSR.post({ url: BatchDisassociateApiCaseUrl, data }); } +// 计划详情-接口用例列表-批量更新执行人 +export function batchUpdateApiCaseExecutor(data: BatchUpdateApiCaseExecutorParams) { + return MSR.post({ url: BatchUpdateApiCaseExecutorUrl, data }); +} // 计划详情-接口场景列表 TODO 联调 export function getPlanDetailApiScenarioList(data: PlanDetailFeatureCaseListQueryParams) { return MSR.post>({ url: GetPlanDetailFeatureCaseListUrl, data }); } +// 计划详情-接口场景列表-批量更新执行人 TODO 联调 +export function batchUpdateApiScenarioExecutor(data: BatchUpdateApiCaseExecutorParams) { + return MSR.post({ url: BatchUpdateApiCaseExecutorUrl, data }); +} // 计划详情-执行历史 TODO 联调 export function getPlanDetailExecuteHistory(data: PlanDetailFeatureCaseListQueryParams) { return MSR.post>({ url: PlanDetailExecuteHistoryUrl, data }); diff --git a/frontend/src/api/requrls/test-plan/testPlan.ts b/frontend/src/api/requrls/test-plan/testPlan.ts index 6ebcb76f3f..a63f385de7 100644 --- a/frontend/src/api/requrls/test-plan/testPlan.ts +++ b/frontend/src/api/requrls/test-plan/testPlan.ts @@ -100,9 +100,13 @@ export const DeleteScheduleTaskUrl = 'test-plan/schedule-config-delete'; export const GetPlanDetailApiCaseListUrl = '/test-plan/api/case/page'; // 计划详情-接口用例模块树 export const GetApiCaseModuleUrl = '/test-plan/api/case/tree'; +// 计划详情-接口用例-获取模块数量 +export const GetApiCaseModuleCountUrl = '/test-plan/api/case/module/count'; +// 计划详情-接口用例列表-拖拽排序 +export const SortApiCaseUrl = '/test-plan/api/case/sort'; // 计划详情-接口用例列表-取消关联用例 export const DisassociateApiCaseUrl = '/test-plan/api/case/disassociate'; // 计划详情-接口用例列表-批量取消关联用例 export const BatchDisassociateApiCaseUrl = '/test-plan/api/case/batch/disassociate'; -// 计划详情-接口用例-获取模块数量 -export const GetApiCaseModuleCountUrl = '/test-plan/api/case/module/count'; +// 计划详情-接口用例列表-批量更新执行人 +export const BatchUpdateApiCaseExecutorUrl = '/test-plan/api/case/batch/update/executor'; diff --git a/frontend/src/models/testPlan/testPlan.ts b/frontend/src/models/testPlan/testPlan.ts index ad06ef0887..92885732c4 100644 --- a/frontend/src/models/testPlan/testPlan.ts +++ b/frontend/src/models/testPlan/testPlan.ts @@ -269,7 +269,7 @@ export interface PlanDetailApiCaseQueryParams extends TableQueryParams, TestPlan export interface PlanDetailApiCaseTreeParams { testPlanId: string; - treeType: 'MODULE' | 'COLLECTION'; + treeType: 'MODULE' | 'COLLECTION'; // 视图类型:模块是MODULE,测试集是COLLECTION } export interface PlanDetailApiCaseItem { @@ -281,7 +281,7 @@ export interface PlanDetailApiCaseItem { createUserName: string; lastExecResult: LastExecuteResults; lastExecTime: number; - lastExecResultReportId: string; + lastExecReportId: string; // 报告id executeUser: string; executeUserName: string; priority: string; @@ -290,17 +290,24 @@ export interface PlanDetailApiCaseItem { projectName: string; environmentId: string; environmentName: string; - testPlanCollectionId: string; - collectEnvironmentId: string; + testPlanCollectionId: string; // 测试集id } export interface BatchApiCaseParams extends BatchActionQueryParams { testPlanId: string; moduleIds?: string[]; - collectionId?: string; + collectionId?: string; // 测试集id protocols: string[]; } +export interface BatchUpdateApiCaseExecutorParams extends BatchApiCaseParams { + userId: string; // 执行人id +} + +export interface SortApiCaseParams extends DragSortParams { + testCollectionId: string; // 测试集id +} + // TODO: 联调 export interface PlanDetailApiScenarioItem { id: string; diff --git a/frontend/src/views/api-test/components/treeFolderAll.vue b/frontend/src/views/api-test/components/treeFolderAll.vue index 6800438ff0..76f2e5eb06 100644 --- a/frontend/src/views/api-test/components/treeFolderAll.vue +++ b/frontend/src/views/api-test/components/treeFolderAll.vue @@ -8,7 +8,13 @@ > @@ -101,14 +94,15 @@ import CaseLevel from '@/components/business/ms-case-associate/caseLevel.vue'; import ExecuteResult from '@/components/business/ms-case-associate/executeResult.vue'; import apiStatus from '@/views/api-test/components/apiStatus.vue'; + import BatchUpdateExecutorModal from '@/views/test-plan/testPlan/components/batchUpdateExecutorModal.vue'; import ReportDrawer from '@/views/test-plan/testPlan/detail/reportDrawer.vue'; import { - associationCaseToPlan, batchDisassociateApiCase, + batchUpdateApiCaseExecutor, disassociateApiCase, getPlanDetailApiCaseList, - sortFeatureCase, + sortApiCase, } from '@/api/modules/test-plan/testPlan'; import { useI18n } from '@/hooks/useI18n'; import useModal from '@/hooks/useModal'; @@ -124,11 +118,7 @@ import { FilterSlotNameEnum } from '@/enums/tableFilterEnum'; import { casePriorityOptions } from '@/views/api-test/components/config'; - import { - executionResultMap, - getCaseLevels, - getModules, - } from '@/views/case-management/caseManagementFeature/components/utils'; + import { executionResultMap, getModules } from '@/views/case-management/caseManagementFeature/components/utils'; const props = defineProps<{ modulesCount: Record; // 模块数量统计对象 @@ -137,9 +127,9 @@ offspringIds: string[]; planId: string; moduleTree: ModuleTreeNode[]; - repeatCase: boolean; canEdit: boolean; selectedProtocols: string[]; + treeType: 'MODULE' | 'COLLECTION'; }>(); const emit = defineEmits<{ @@ -188,7 +178,7 @@ }, { title: 'case.caseLevel', - dataIndex: 'caseLevel', + dataIndex: 'priority', slotName: 'caseLevel', filterConfig: { options: casePriorityOptions, @@ -242,7 +232,7 @@ }, { title: 'report.detail.api.executeEnv', - dataIndex: 'executeEnv', + dataIndex: 'environmentName', width: 150, showInTable: false, showDrag: true, @@ -288,21 +278,11 @@ return { ...record, lastExecResult: record.lastExecResult ?? LastExecuteResults.PENDING, - caseLevel: getCaseLevels(record.customFields), moduleId: getModules(record.moduleId, props.moduleTree), }; } ); - watch( - () => props.canEdit, - (val) => { - tableProps.value.draggableCondition = hasAnyPermission(['PROJECT_TEST_PLAN:READ+UPDATE']) && val; - }, - { - immediate: true, - } - ); const tableRef = ref>(); watch( () => hasOperationPermission.value, @@ -347,6 +327,7 @@ } return moduleIds; } + const collectionId = computed(() => (props.activeModule === 'all' ? '' : props.activeModule)); async function getTableParams(isBatch: boolean) { const selectModules = await getModuleIds(); const commonParams = { @@ -354,7 +335,7 @@ projectId: appStore.currentProjectId, moduleIds: selectModules, protocols: props.selectedProtocols, - collectionId: props.activeModule, + collectionId: collectionId.value, }; if (isBatch) { return { @@ -372,6 +353,20 @@ }; } + watch( + [() => props.canEdit, () => props.treeType, () => collectionId.value.length], + () => { + tableProps.value.draggableCondition = + hasAnyPermission(['PROJECT_TEST_PLAN:READ+UPDATE']) && + props.canEdit && + props.treeType === 'COLLECTION' && + !!collectionId.value.length; + }, + { + immediate: true, + } + ); + async function loadCaseList() { const tableParams = await getTableParams(false); setLoadListParams(tableParams); @@ -400,7 +395,7 @@ const reportId = ref(''); function showReport(record: PlanDetailApiCaseItem) { reportVisible.value = true; - reportId.value = record.lastExecResultReportId; + reportId.value = record.lastExecReportId; } const tableSelected = ref<(string | number)[]>([]); // 表格选中的 @@ -421,11 +416,15 @@ loadList(); } + function resetSelectorAndCaseList() { + resetSelector(); + loadList(); + } + // 拖拽排序 async function handleDragChange(params: DragSortParams) { try { - // TODO 联调 - await sortFeatureCase({ ...params, testPlanId: props.planId }); + await sortApiCase({ ...params, testCollectionId: collectionId.value }); Message.success(t('caseManagement.featureCase.sortSuccess')); loadCaseList(); } catch (error) { @@ -434,23 +433,6 @@ } } - // 复制用例 - async function handleCopyCase(record: PlanDetailApiCaseItem) { - try { - // TODO 联调 - await associationCaseToPlan({ - functionalSelectIds: [record.id], - testPlanId: props.planId, - }); - Message.success(t('ms.case.associate.associateSuccess')); - resetCaseList(); - emit('refresh'); - } catch (error) { - // eslint-disable-next-line no-console - console.log(error); - } - } - // 取消关联 const disassociateLoading = ref(false); async function handleDisassociateCase(record: PlanDetailApiCaseItem, done?: () => void) { @@ -504,10 +486,15 @@ }); } + // 批量修改执行人 + const batchUpdateExecutorModalVisible = ref(false); + const batchUpdateExecutorParams = ref(); + // 处理表格选中后批量操作 - function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) { + async function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) { tableSelected.value = params?.selectedIds || []; batchParams.value = { ...params, selectIds: params?.selectedIds }; + const tableParams = await getTableParams(true); switch (event.eventTag) { case 'execute': break; @@ -515,6 +502,13 @@ handleBatchDisassociateCase(); break; case 'changeExecutor': + batchUpdateExecutorParams.value = { + selectIds: tableSelected.value as string[], + selectAll: batchParams.value.selectAll, + excludeIds: batchParams.value?.excludeIds || [], + ...tableParams, + }; + batchUpdateExecutorModalVisible.value = true; break; case 'move': break; diff --git a/frontend/src/views/test-plan/testPlan/detail/apiCase/components/caseTree.vue b/frontend/src/views/test-plan/testPlan/detail/apiCase/components/caseTree.vue index 355d98327e..8553a9504e 100644 --- a/frontend/src/views/test-plan/testPlan/detail/apiCase/components/caseTree.vue +++ b/frontend/src/views/test-plan/testPlan/detail/apiCase/components/caseTree.vue @@ -88,7 +88,18 @@ const activeFolder = ref('all'); const allCount = ref(0); - const isExpandAll = ref(false); + const isExpandAll = ref(false); + + watch( + () => props.treeType, + (val) => { + if (val === 'COLLECTION') { + isExpandAll.value = undefined; + } else { + isExpandAll.value = false; + } + } + ); function setActiveFolder(id: string) { activeFolder.value = id; diff --git a/frontend/src/views/test-plan/testPlan/detail/apiCase/index.vue b/frontend/src/views/test-plan/testPlan/detail/apiCase/index.vue index 131bbfd334..3c7cbaa9d4 100644 --- a/frontend/src/views/test-plan/testPlan/detail/apiCase/index.vue +++ b/frontend/src/views/test-plan/testPlan/detail/apiCase/index.vue @@ -15,6 +15,7 @@ { + initModules(); + caseTableRef.value?.loadCaseList(); + }); } defineExpose({ diff --git a/frontend/src/views/test-plan/testPlan/detail/apiScenario/components/scenarioTable.vue b/frontend/src/views/test-plan/testPlan/detail/apiScenario/components/scenarioTable.vue index f1272f7ccf..ae0b9d8266 100644 --- a/frontend/src/views/test-plan/testPlan/detail/apiScenario/components/scenarioTable.vue +++ b/frontend/src/views/test-plan/testPlan/detail/apiScenario/components/scenarioTable.vue @@ -65,24 +65,17 @@ {{ t('common.cancelLink') }} - - - {{ t('common.copy') }} - + + @@ -104,11 +97,12 @@ import CaseLevel from '@/components/business/ms-case-associate/caseLevel.vue'; import ExecuteResult from '@/components/business/ms-case-associate/executeResult.vue'; import apiStatus from '@/views/api-test/components/apiStatus.vue'; + import BatchUpdateExecutorModal from '@/views/test-plan/testPlan/components/batchUpdateExecutorModal.vue'; import ReportDrawer from '@/views/test-plan/testPlan/detail/reportDrawer.vue'; import { - associationCaseToPlan, batchDisassociateCase, + batchUpdateApiScenarioExecutor, disassociateCase, getPlanDetailApiScenarioList, sortFeatureCase, @@ -142,7 +136,6 @@ offspringIds: string[]; planId: string; moduleTree: ModuleTreeNode[]; - repeatCase: boolean; canEdit: boolean; }>(); @@ -421,6 +414,11 @@ loadList(); } + function resetSelectorAndCaseList() { + resetSelector(); + loadList(); + } + // 拖拽排序 async function handleDragChange(params: DragSortParams) { try { @@ -434,23 +432,6 @@ } } - // 复制用例 - async function handleCopyCase(record: PlanDetailApiScenarioItem) { - try { - // TODO 联调 - await associationCaseToPlan({ - functionalSelectIds: [record.caseId], - testPlanId: props.planId, - }); - Message.success(t('ms.case.associate.associateSuccess')); - resetCaseList(); - emit('refresh'); - } catch (error) { - // eslint-disable-next-line no-console - console.log(error); - } - } - // 取消关联 const disassociateLoading = ref(false); async function handleDisassociateCase(record: PlanDetailApiScenarioItem, done?: () => void) { @@ -506,10 +487,15 @@ }); } + // 批量修改执行人 + const batchUpdateExecutorModalVisible = ref(false); + const batchUpdateExecutorParams = ref(); + // 处理表格选中后批量操作 - function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) { + async function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) { tableSelected.value = params?.selectedIds || []; batchParams.value = { ...params, selectIds: params?.selectedIds }; + const tableParams = await getTableParams(true); switch (event.eventTag) { case 'execute': break; @@ -517,6 +503,13 @@ handleBatchDisassociateCase(); break; case 'changeExecutor': + batchUpdateExecutorParams.value = { + selectIds: tableSelected.value as string[], + selectAll: batchParams.value.selectAll, + excludeIds: batchParams.value?.excludeIds || [], + ...tableParams, + }; + batchUpdateExecutorModalVisible.value = true; break; case 'move': break; diff --git a/frontend/src/views/test-plan/testPlan/detail/featureCase/components/caseTable.vue b/frontend/src/views/test-plan/testPlan/detail/featureCase/components/caseTable.vue index 71be9b78c2..9f44d2a828 100644 --- a/frontend/src/views/test-plan/testPlan/detail/featureCase/components/caseTable.vue +++ b/frontend/src/views/test-plan/testPlan/detail/featureCase/components/caseTable.vue @@ -78,21 +78,6 @@ {{ t('common.cancelLink') }} - - - {{ t('common.copy') }} - @@ -120,54 +105,20 @@ - - - - - - - - + :count="batchParams.currentSelectCount || tableSelected.length" + :params="batchUpdateExecutorParams" + :batch-update-executor="batchUpdateCaseExecutor" + @load-list="resetSelectorAndCaseList" + />