From 2c48d8f947b0c686c07a6220c652ec72b1465b16 Mon Sep 17 00:00:00 2001 From: "xinxin.wu" Date: Fri, 10 May 2024 15:11:37 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=B5=8B=E8=AF=95=E8=AE=A1=E5=88=92):=20?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=B5=8B=E8=AF=95=E8=AE=A1=E5=88=92=E9=83=A8?= =?UTF-8?q?=E5=88=86=E7=BB=86=E8=8A=82=E5=92=8C=E8=AF=A6=E6=83=85=E7=BC=BA?= =?UTF-8?q?=E9=99=B7=E7=AE=A1=E7=90=86=E5=88=97=E8=A1=A8=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/api/modules/test-plan/testPlan.ts | 23 ++- .../src/api/requrls/test-plan/testPlan.ts | 6 + frontend/src/enums/tableEnum.ts | 2 + frontend/src/locale/en-US/common.ts | 1 + frontend/src/locale/zh-CN/common.ts | 1 + frontend/src/models/testPlan/testPlan.ts | 16 ++ .../views/api-test/management/locale/en-US.ts | 2 +- .../views/api-test/management/locale/zh-CN.ts | 4 +- .../api-test/report/component/scenarioCom.vue | 1 - .../tabContent/tabCase/tabCaseTable.vue | 3 +- .../taskCenter/component/scheduledTask.vue | 6 +- .../organizationAndProject/locale/zh-CN.ts | 2 +- .../testPlan/components/batchMoveOrCopy.vue | 16 +- .../testPlan/components/planTable.vue | 68 +++++--- .../testPlan/components/testPlanTree.vue | 25 ++- .../detail/bugManagement/caseCountPopover.vue | 74 ++++++++ .../testPlan/detail/bugManagement/index.vue | 161 ++++++++++++++++++ .../views/test-plan/testPlan/detail/index.vue | 5 +- .../src/views/test-plan/testPlan/index.vue | 6 +- .../views/test-plan/testPlan/locale/en-US.ts | 4 + .../views/test-plan/testPlan/locale/zh-CN.ts | 4 + 21 files changed, 382 insertions(+), 48 deletions(-) create mode 100644 frontend/src/views/test-plan/testPlan/detail/bugManagement/caseCountPopover.vue create mode 100644 frontend/src/views/test-plan/testPlan/detail/bugManagement/index.vue diff --git a/frontend/src/api/modules/test-plan/testPlan.ts b/frontend/src/api/modules/test-plan/testPlan.ts index 8aabc25492..def42b68c9 100644 --- a/frontend/src/api/modules/test-plan/testPlan.ts +++ b/frontend/src/api/modules/test-plan/testPlan.ts @@ -3,7 +3,9 @@ import { addTestPlanModuleUrl, AddTestPlanUrl, archivedPlanUrl, + batchCopyPlanUrl, batchDeletePlanUrl, + batchMovePlanUrl, deletePlanUrl, DeleteTestPlanModuleUrl, getStatisticalCountUrl, @@ -12,6 +14,7 @@ import { GetTestPlanModuleCountUrl, GetTestPlanModuleUrl, MoveTestPlanModuleUrl, + planDetailBugPageUrl, updateTestPlanModuleUrl, UpdateTestPlanUrl, } from '@/api/requrls/test-plan/testPlan'; @@ -19,7 +22,13 @@ import { import type { CreateOrUpdateModule, UpdateModule } from '@/models/caseManagement/featureCase'; import type { CommonList, MoveModules, TableQueryParams } from '@/models/common'; import { ModuleTreeNode } from '@/models/common'; -import type { AddTestPlanParams, TestPlanDetail, TestPlanItem, UseCountType } from '@/models/testPlan/testPlan'; +import type { + AddTestPlanParams, + PlanDetailBugItem, + TestPlanDetail, + TestPlanItem, + UseCountType, +} from '@/models/testPlan/testPlan'; // 获取模块树 export function getTestPlanModule(params: TableQueryParams) { @@ -86,3 +95,15 @@ export function getStatisticalCount(id: string) { export function archivedPlan(id: string | undefined) { return MSR.get({ url: `${archivedPlanUrl}/${id}` }); } +// 批量复制测试计划 +export function batchCopyPlan(data: TableQueryParams) { + return MSR.post({ url: batchCopyPlanUrl, data }); +} +// 批量移动测试计划 +export function batchMovePlan(data: TableQueryParams) { + return MSR.post({ url: batchMovePlanUrl, data }); +} +// 计划详情缺陷管理列表 +export function planDetailBugPage(data: TableQueryParams) { + return MSR.post>({ url: planDetailBugPageUrl, data }); +} diff --git a/frontend/src/api/requrls/test-plan/testPlan.ts b/frontend/src/api/requrls/test-plan/testPlan.ts index 6f8b5b1c8b..40389809b3 100644 --- a/frontend/src/api/requrls/test-plan/testPlan.ts +++ b/frontend/src/api/requrls/test-plan/testPlan.ts @@ -26,3 +26,9 @@ export const deletePlanUrl = '/test-plan/delete'; export const getStatisticalCountUrl = '/test-plan/getCount'; // 归档 export const archivedPlanUrl = '/test-plan/archived'; +// 批量复制 +export const batchCopyPlanUrl = '/test-plan/batch/copy'; +// 批量移动 +export const batchMovePlanUrl = '/test-plan/batch/move'; +// 计划详情缺陷管理列表 +export const planDetailBugPageUrl = '/test-plan/bug/page'; diff --git a/frontend/src/enums/tableEnum.ts b/frontend/src/enums/tableEnum.ts index 2097cc6a8b..13b609b587 100644 --- a/frontend/src/enums/tableEnum.ts +++ b/frontend/src/enums/tableEnum.ts @@ -63,6 +63,8 @@ export enum TableKeyEnum { PROJECT_MANAGEMENT_ENV_ALL_PARAM_HEADER = 'projectManagementEnvAllParamHeader', PROJECT_MANAGEMENT_ENV_ALL_PARAM_VARIABLE = 'projectManagementEnvAllParamVariable', TEST_PLAN_ALL_TABLE = 'testPlanAllTable', + TEST_PLAN_DETAIL_BUG_TABLE = 'testPlanDetailBug', + TEST_PLAN_DETAIL_BUG_TABLE_CASE_COUNT = 'testPlanDetailBugCaseCount', TASK_API_CASE_SYSTEM = 'taskCenterApiCaseSystem', TASK_API_CASE_ORGANIZATION = 'taskCenterApiCaseOrganization', TASK_API_CASE_PROJECT = 'taskCenterApiCaseProject', diff --git a/frontend/src/locale/en-US/common.ts b/frontend/src/locale/en-US/common.ts index 8e8e4d6b39..f7bd5922c2 100644 --- a/frontend/src/locale/en-US/common.ts +++ b/frontend/src/locale/en-US/common.ts @@ -139,6 +139,7 @@ export default { 'common.yes': 'Yes', 'common.no': 'No', 'common.creator': 'Creator', + 'common.createTime': 'Created time', 'common.followSuccess': 'Followed', 'common.unFollowSuccess': 'Unfollow successfully', 'common.share': 'Share', diff --git a/frontend/src/locale/zh-CN/common.ts b/frontend/src/locale/zh-CN/common.ts index dae6e4505f..32dbf3add5 100644 --- a/frontend/src/locale/zh-CN/common.ts +++ b/frontend/src/locale/zh-CN/common.ts @@ -139,6 +139,7 @@ export default { 'common.yes': '是', 'common.no': '否', 'common.creator': '创建人', + 'common.createTime': '创建时间', 'common.followSuccess': '关注成功', 'common.unFollowSuccess': '取消关注成功', 'common.share': '分享', diff --git a/frontend/src/models/testPlan/testPlan.ts b/frontend/src/models/testPlan/testPlan.ts index 0e8536a2f7..2195e07e02 100644 --- a/frontend/src/models/testPlan/testPlan.ts +++ b/frontend/src/models/testPlan/testPlan.ts @@ -98,4 +98,20 @@ export interface UseCountType { testProgress: string; // 测试进度 } +// 计划详情缺陷列表 +export interface PlanDetailBugItem { + id: string; + num: string; + title: string; + relateCase: { + id: string; + bugId: string; + name: string; + }[]; + handleUser: string; + status: string; + createUser: string; + createTime: number; +} + export default {}; diff --git a/frontend/src/views/api-test/management/locale/en-US.ts b/frontend/src/views/api-test/management/locale/en-US.ts index 471d208139..30baf8915b 100644 --- a/frontend/src/views/api-test/management/locale/en-US.ts +++ b/frontend/src/views/api-test/management/locale/en-US.ts @@ -35,7 +35,7 @@ export default { 'apiTestManagement.closeOther': 'Close other tabs', 'apiTestManagement.showSubdirectory': 'Show subdirectory use case', 'apiTestManagement.searchPlaceholder': 'Enter ID/name/api path search', - 'apiTestManagement.searchTaskPlaceholder': 'Enter resource Id/name search', + 'apiTestManagement.searchTaskPlaceholder': 'Enter resource Id/name/URL search', 'apiTestManagement.apiName': 'Api name', 'apiTestManagement.apiType': 'Api type', 'apiTestManagement.apiStatus': 'Status', diff --git a/frontend/src/views/api-test/management/locale/zh-CN.ts b/frontend/src/views/api-test/management/locale/zh-CN.ts index aa693880b1..63e89a1487 100644 --- a/frontend/src/views/api-test/management/locale/zh-CN.ts +++ b/frontend/src/views/api-test/management/locale/zh-CN.ts @@ -34,7 +34,7 @@ export default { 'apiTestManagement.closeOther': '关闭其他tab', 'apiTestManagement.showSubdirectory': '显示子目录用例', 'apiTestManagement.searchPlaceholder': '输入 ID/名称/api路径搜索', - 'apiTestManagement.searchTaskPlaceholder': '输入资源ID/名称搜索', + 'apiTestManagement.searchTaskPlaceholder': '输入资源ID/名称/URL搜索', 'apiTestManagement.apiName': '接口名称', 'apiTestManagement.apiType': '请求类型', 'apiTestManagement.apiStatus': '状态', @@ -79,7 +79,7 @@ export default { 'apiTestManagement.importSwaggerFileTip1': '支持 Swagger 3.0 版本的 json 文件,', 'apiTestManagement.importSwaggerFileTip2': '2.0 文件可以在官网一键转换 3.0', 'apiTestManagement.importSwaggerFileTip3': ',大小不超过 50M', - 'apiTestManagement.urlImportPlaceholder': '请输入OpenAPI/Swagger URL', + 'apiTestManagement.urlImportPlaceholder': '请输入OpenAPI/URL', 'apiTestManagement.swaggerURLRequired': 'SwaggerURL 不能为空', 'apiTestManagement.basicAuth': 'Basic Auth 认证', 'apiTestManagement.account': '账号', diff --git a/frontend/src/views/api-test/report/component/scenarioCom.vue b/frontend/src/views/api-test/report/component/scenarioCom.vue index 5c2d4419d2..5d74300573 100644 --- a/frontend/src/views/api-test/report/component/scenarioCom.vue +++ b/frontend/src/views/api-test/report/component/scenarioCom.vue @@ -175,7 +175,6 @@ import { ref } from 'vue'; import { useRoute } from 'vue-router'; - import MsChart from '@/components/pure/chart/index.vue'; import SetReportChart from './case/setReportChart.vue'; import ReportDetailHeader from './reportDetailHeader.vue'; import reportInfoHeader from './step/reportInfoHeaders.vue'; diff --git a/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabCase/tabCaseTable.vue b/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabCase/tabCaseTable.vue index 0db3b10579..07b7ac93b4 100644 --- a/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabCase/tabCaseTable.vue +++ b/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabCase/tabCaseTable.vue @@ -174,7 +174,7 @@ }, ]; - const { propsRes, propsEvent, loadList, setLoadListParams, setKeyword } = useTable(getAssociatedCasePage, { + const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(getAssociatedCasePage, { columns, tableKey: TableKeyEnum.CASE_MANAGEMENT_TAB_DEPENDENCY_PRE_CASE, scroll: { x: '100%' }, @@ -184,7 +184,6 @@ }); const innerVisible = ref(false); - const innerProject = ref(currentProjectId.value); const associateForm = ref({ reviewers: [], diff --git a/frontend/src/views/project-management/taskCenter/component/scheduledTask.vue b/frontend/src/views/project-management/taskCenter/component/scheduledTask.vue index 8bbbc838ba..7e1728d9e0 100644 --- a/frontend/src/views/project-management/taskCenter/component/scheduledTask.vue +++ b/frontend/src/views/project-management/taskCenter/component/scheduledTask.vue @@ -9,7 +9,11 @@
+ diff --git a/frontend/src/views/test-plan/testPlan/components/planTable.vue b/frontend/src/views/test-plan/testPlan/components/planTable.vue index 63b07e079b..546c59b741 100644 --- a/frontend/src/views/test-plan/testPlan/components/planTable.vue +++ b/frontend/src/views/test-plan/testPlan/components/planTable.vue @@ -24,7 +24,7 @@ -->
-
+
{{ props.activeFolder === 'all' ? t('testPlan.testPlanIndex.allTestPlan') : props.nodeName }}
({{ props.modulesCount[props.activeFolder] || 0 }}) @@ -279,11 +279,21 @@ import StatusProgress from './statusProgress.vue'; import statusTag from '@/views/case-management/caseReview/components/statusTag.vue'; - import { archivedPlan, batchDeletePlan, getTestPlanList, getTestPlanModule } from '@/api/modules/test-plan/testPlan'; + import { + archivedPlan, + batchCopyPlan, + batchDeletePlan, + batchMovePlan, + getTestPlanDetail, + getTestPlanList, + getTestPlanModule, + updateTestPlan, + } from '@/api/modules/test-plan/testPlan'; import { useI18n } from '@/hooks/useI18n'; import useModal from '@/hooks/useModal'; import { useAppStore, useTableStore } from '@/store'; import { characterLimit } from '@/utils'; + import { hasAnyPermission } from '@/utils/permission'; import type { planStatusType, TestPlanItem } from '@/models/testPlan/testPlan'; import { TestPlanRouteEnum } from '@/enums/routeEnum'; @@ -316,7 +326,7 @@ title: 'testPlan.testPlanIndex.ID', slotName: 'num', dataIndex: 'num', - width: 200, + width: 150, showInTable: true, showDrag: false, showTooltip: true, @@ -329,7 +339,7 @@ showInTable: true, showTooltip: true, width: 180, - editType: ColumnEditTypeEnum.INPUT, + editType: hasAnyPermission(['PROJECT_TEST_PLAN:READ+UPDATE']) ? ColumnEditTypeEnum.INPUT : undefined, sortable: { sortDirections: ['ascend', 'descend'], sorter: true, @@ -446,10 +456,18 @@ /** * 更新测试计划名称 */ - async function updatePlanName() { + async function updatePlanName(record: TestPlanItem) { try { - Message.success(t('common.updateSuccess')); - return Promise.resolve(true); + if (record.id) { + const detail = await getTestPlanDetail(record.id); + const params = { + ...detail, + name: record.name, + }; + await updateTestPlan(params); + Message.success(t('common.updateSuccess')); + return Promise.resolve(true); + } } catch (error) { console.log(error); return Promise.resolve(false); @@ -553,13 +571,15 @@ showSetting: true, heightUsed: 128, paginationSize: 'mini', + showSelectorAll: false, }, (item) => { return { ...item, tags: (item.tags || []).map((e: string) => ({ id: e, name: e })), }; - } + }, + updatePlanName ); const batchParams = ref({ @@ -605,9 +625,8 @@ loadList(); } - async function fetchData() { - resetSelector(); - await loadPlanList(); + // 获取父组件模块数量 + async function emitTableParams() { const tableParams = await initTableParams(); emit('init', { ...tableParams, @@ -616,6 +635,12 @@ }); } + async function fetchData() { + resetSelector(); + await loadPlanList(); + emitTableParams(); + } + // 测试计划详情 function openDetail(id: string) { router.push({ @@ -666,23 +691,25 @@ try { const params = { selectIds: batchParams.value.selectedIds || [], - selectAll: !!batchParams.value?.selectAll, - excludeIds: batchParams.value?.excludeIds || [], condition: { keyword: keyword.value, - filter: { - reviewStatus: statusFilters.value, - }, + filter: {}, combine: batchParams.value.condition, }, projectId: appStore.currentProjectId, moduleIds: [...selectNodeKeys.value], + type: showType.value, + moduleId: selectNodeKeys.value[0], }; if (modeType.value === 'copy') { + await batchCopyPlan(params); Message.success(t('common.batchCopySuccess')); } else { + await batchMovePlan(params); Message.success(t('common.batchMoveSuccess')); } + showBatchModal.value = false; + fetchData(); } catch (error) { console.log(error); } finally { @@ -812,9 +839,9 @@ } } - function deletePlan(record: any) {} + function deletePlan(record: TestPlanItem) {} - function copyHandler() {} + function copyHandler(record: TestPlanItem) {} const showScheduledTaskModal = ref(false); function handleScheduledTask() { @@ -854,7 +881,7 @@ function handleMoreActionSelect(item: ActionsItem, record: TestPlanItem) { switch (item.eventTag) { case 'copy': - copyHandler(); + copyHandler(record); break; case 'createScheduledTask': handleScheduledTask(); @@ -928,7 +955,8 @@ }); defineExpose({ - loadPlanList, + fetchData, + emitTableParams, }); await tableStore.initColumn(TableKeyEnum.TEST_PLAN_ALL_TABLE, columns, 'drawer'); diff --git a/frontend/src/views/test-plan/testPlan/components/testPlanTree.vue b/frontend/src/views/test-plan/testPlan/components/testPlanTree.vue index 70898de43e..395fb6fb55 100644 --- a/frontend/src/views/test-plan/testPlan/components/testPlanTree.vue +++ b/frontend/src/views/test-plan/testPlan/components/testPlanTree.vue @@ -3,7 +3,7 @@ @@ -111,7 +111,7 @@ const groupKeyword = ref(''); - const caseTree = ref([]); + const testPlanTree = ref([]); const setFocusKey = (node: MsTreeNodeData) => { focusNodeKey.value = node.id || ''; @@ -152,19 +152,18 @@ try { loading.value = true; const res = await getTestPlanModule({ projectId: currentProjectId.value }); - caseTree.value = mapTree(res, (e) => { + testPlanTree.value = mapTree(res, (e) => { return { ...e, hideMoreAction: e.id === 'root', draggable: e.id !== 'root', - disabled: e.id === props.activeFolder, count: props.modulesCount?.[e.id] || 0, }; }); if (isSetDefaultKey) { - selectedNodeKeys.value = [caseTree.value[0].id]; + selectedNodeKeys.value = [testPlanTree.value[0].id]; } - emits('init', caseTree.value); + emits('init', testPlanTree.value); } catch (error) { // eslint-disable-next-line no-console console.log(error); @@ -188,7 +187,7 @@ try { await deletePlanModuleTree(node.id); Message.success(t('common.deleteSuccess')); - initModules(true); + initModules(selectedNodeKeys.value[0] === node.id); } catch (error) { console.log(error); } @@ -207,7 +206,7 @@ } // 用例树节点选中事件 - const caseNodeSelect = (selectedKeys: (string | number)[], node: MsTreeNodeData) => { + const planNodeSelect = (selectedKeys: (string | number)[], node: MsTreeNodeData) => { const offspringIds: string[] = []; mapTree(node.children || [], (e) => { offspringIds.push(e.id); @@ -217,7 +216,7 @@ }; // 用例树节点更多事件 - const handleCaseMoreSelect = (item: ActionsItem, node: MsTreeNodeData) => { + const handlePlanMoreSelect = (item: ActionsItem, node: MsTreeNodeData) => { switch (item.eventTag) { case 'delete': deleteHandler(node); @@ -266,7 +265,7 @@ if (dropPosition === 0) { treeNode.value.children.push(dragNode); } - caseNodeSelect(dropNode.id, treeNode.value); + planNodeSelect(dropNode.id, treeNode.value); emits('dragUpdate'); } } @@ -347,7 +346,7 @@ watch( () => props.modulesCount, (obj) => { - caseTree.value = mapTree(caseTree.value, (node) => { + testPlanTree.value = mapTree(testPlanTree.value, (node) => { return { ...node, count: obj?.[node.id] || 0, diff --git a/frontend/src/views/test-plan/testPlan/detail/bugManagement/caseCountPopover.vue b/frontend/src/views/test-plan/testPlan/detail/bugManagement/caseCountPopover.vue new file mode 100644 index 0000000000..f7d89d216e --- /dev/null +++ b/frontend/src/views/test-plan/testPlan/detail/bugManagement/caseCountPopover.vue @@ -0,0 +1,74 @@ + + + + + diff --git a/frontend/src/views/test-plan/testPlan/detail/bugManagement/index.vue b/frontend/src/views/test-plan/testPlan/detail/bugManagement/index.vue new file mode 100644 index 0000000000..bbde3e011f --- /dev/null +++ b/frontend/src/views/test-plan/testPlan/detail/bugManagement/index.vue @@ -0,0 +1,161 @@ + + + + + diff --git a/frontend/src/views/test-plan/testPlan/detail/index.vue b/frontend/src/views/test-plan/testPlan/detail/index.vue index 8be87ce972..f6277e2e9b 100644 --- a/frontend/src/views/test-plan/testPlan/detail/index.vue +++ b/frontend/src/views/test-plan/testPlan/detail/index.vue @@ -72,7 +72,9 @@ - + + + diff --git a/frontend/src/views/test-plan/testPlan/locale/en-US.ts b/frontend/src/views/test-plan/testPlan/locale/en-US.ts index e919ba88d5..4ae953d917 100644 --- a/frontend/src/views/test-plan/testPlan/locale/en-US.ts +++ b/frontend/src/views/test-plan/testPlan/locale/en-US.ts @@ -81,4 +81,8 @@ export default { 'testPlan.planForm.repeatCaseTip2': 'Close: Cannot be associated with the same case repeatedly', 'testPlan.planForm.pickCases': 'Select cases', 'testPlan.testPlanDetail.executed': 'Executed', + 'testPlan.bugManagement.bug': 'Defect list', + 'testPlan.bugManagement.bugName': 'name', + 'testPlan.bugManagement.defectState': 'Defect state', + 'testPlan.bugManagement.caseClassification': 'Classification', }; diff --git a/frontend/src/views/test-plan/testPlan/locale/zh-CN.ts b/frontend/src/views/test-plan/testPlan/locale/zh-CN.ts index 475cb46176..ec90cbee18 100644 --- a/frontend/src/views/test-plan/testPlan/locale/zh-CN.ts +++ b/frontend/src/views/test-plan/testPlan/locale/zh-CN.ts @@ -79,4 +79,8 @@ export default { 'testPlan.planForm.repeatCaseTip2': '关闭:不可重复关联同一用例', 'testPlan.planForm.pickCases': '选择用例', 'testPlan.testPlanDetail.executed': '已执行', + 'testPlan.bugManagement.bug': '缺陷列表', + 'testPlan.bugManagement.bugName': '名称', + 'testPlan.bugManagement.defectState': '缺陷状态', + 'testPlan.bugManagement.caseClassification': '用例分类', };