diff --git a/frontend/src/api/modules/test-plan/testPlan.ts b/frontend/src/api/modules/test-plan/testPlan.ts index c4581211b0..231aa8125c 100644 --- a/frontend/src/api/modules/test-plan/testPlan.ts +++ b/frontend/src/api/modules/test-plan/testPlan.ts @@ -2,17 +2,21 @@ import MSR from '@/api/http/index'; import { addTestPlanModuleUrl, DeleteTestPlanModuleUrl, + GetTestPlanListUrl, GetTestPlanModuleCountUrl, GetTestPlanModuleUrl, MoveTestPlanModuleUrl, updateTestPlanModuleUrl, } from '@/api/requrls/test-plan/testPlan'; -import type { CreateOrUpdateModule, ModulesTreeType, UpdateModule } from '@/models/caseManagement/featureCase'; +import type { CreateOrUpdateModule, UpdateModule } from '@/models/caseManagement/featureCase'; import type { CommonList, MoveModules, TableQueryParams } from '@/models/common'; +import { ModuleTreeNode } from '@/models/common'; +import type { TestPlanItem } from '@/models/testPlan/testPlan'; + // 获取模块树 export function getTestPlanModule(params: TableQueryParams) { - return MSR.get({ url: `${GetTestPlanModuleUrl}/${params.projectId}` }); + return MSR.get({ url: `${GetTestPlanModuleUrl}/${params.projectId}` }); } // 创建模块树 @@ -39,3 +43,8 @@ export function deletePlanModuleTree(id: string) { export function getPlanModulesCounts(data: TableQueryParams) { return MSR.post({ url: GetTestPlanModuleCountUrl, data }); } + +// 获取计划列表 +export function getTestPlanList(data: TableQueryParams) { + return MSR.post>({ url: GetTestPlanListUrl, data }); +} diff --git a/frontend/src/api/requrls/test-plan/testPlan.ts b/frontend/src/api/requrls/test-plan/testPlan.ts index bdcdf71f00..96d2962709 100644 --- a/frontend/src/api/requrls/test-plan/testPlan.ts +++ b/frontend/src/api/requrls/test-plan/testPlan.ts @@ -10,3 +10,5 @@ export const MoveTestPlanModuleUrl = '/test-plan/module/move'; export const DeleteTestPlanModuleUrl = '/test-plan/module/delete'; // 测试计划模块树数量 export const GetTestPlanModuleCountUrl = '/test-plan/module/count'; +// 测试计划列表 +export const GetTestPlanListUrl = '/test-plan/page'; diff --git a/frontend/src/components/pure/ms-table/select-all.vue b/frontend/src/components/pure/ms-table/select-all.vue index 91117e0f23..fd80c36ba6 100644 --- a/frontend/src/components/pure/ms-table/select-all.vue +++ b/frontend/src/components/pure/ms-table/select-all.vue @@ -80,8 +80,21 @@ emit('change', v as SelectAllEnum); }; + function hasUnselectedChildren( + data: MsTableDataItem>[], + selectedKeys: Set, + rowKey: string + ): boolean { + return data.some((item: any) => { + if (item.children && item.children.length > 0) { + return hasUnselectedChildren(item.children, selectedKeys, rowKey); + } + return !selectedKeys.has(item[rowKey]); + }); + } + const handleCheckChange = () => { - if (props.currentData.some((item) => !props.selectedKeys.has(item[props.rowKey]))) { + if (hasUnselectedChildren(props.currentData, props.selectedKeys, props.rowKey)) { // 当前页有数据没有勾选上,此时点击全选按钮代表全部选中 handleSelect(SelectAllEnum.CURRENT); } else { diff --git a/frontend/src/components/pure/ms-tag/ms-tag-group.vue b/frontend/src/components/pure/ms-tag/ms-tag-group.vue index df21f2b340..edbcc444d0 100644 --- a/frontend/src/components/pure/ms-tag/ms-tag-group.vue +++ b/frontend/src/components/pure/ms-tag/ms-tag-group.vue @@ -66,7 +66,7 @@ const getTagWidth = (tag: { [x: string]: any }) => { const tagStr = props.isStringTag ? tag : tag[props.nameKey]; - const tagWidth = tagStr.length; + const tagWidth = tagStr ? tagStr.length : 0; // 16个中文字符 return tagWidth < 16 ? tagWidth : 16; }; diff --git a/frontend/src/enums/testPlanEnum.ts b/frontend/src/enums/testPlanEnum.ts new file mode 100644 index 0000000000..b55fb505d8 --- /dev/null +++ b/frontend/src/enums/testPlanEnum.ts @@ -0,0 +1,7 @@ +export enum testPlanTypeEnum { + ALL = 'ALL', + TEST_PLAN = 'TEST_PLAN', + GROUP = 'GROUP', +} + +export default {}; diff --git a/frontend/src/locale/en-US/common.ts b/frontend/src/locale/en-US/common.ts index 8f51361596..f8627f47ea 100644 --- a/frontend/src/locale/en-US/common.ts +++ b/frontend/src/locale/en-US/common.ts @@ -122,6 +122,7 @@ export default { 'common.moveSuccess': 'Move successful', 'common.batchMove': 'Batch move', 'common.batchCopy': 'Batch copy', + 'common.batchCopySuccess': 'Batch copy successful', 'common.batchMoveSuccess': 'Batch move successful', 'common.importSuccess': 'Import successful', 'common.nameIsTooLang': 'The name exceeds 255 characters', @@ -157,4 +158,10 @@ export default { 'common.text': 'Text', 'common.resourceDeleted': 'Resource has been deleted', 'common.refresh': 'Refresh', + 'common.searchByNameAndId': 'Search by ID, name, or tag', + 'common.archive': 'archive', + 'common.running': 'Running', + 'common.unExecute': 'Not executed', + 'common.pass': 'Pass', + 'common.unPass': 'Fail pass', }; diff --git a/frontend/src/locale/zh-CN/common.ts b/frontend/src/locale/zh-CN/common.ts index e412b19eac..43c190b75e 100644 --- a/frontend/src/locale/zh-CN/common.ts +++ b/frontend/src/locale/zh-CN/common.ts @@ -123,6 +123,7 @@ export default { 'common.moveSuccess': '移动成功', 'common.batchMove': '批量移动', 'common.batchCopy': '批量复制', + 'common.batchCopySuccess': '批量复制成功', 'common.batchMoveSuccess': '批量移动成功', 'common.importSuccess': '导入成功', 'common.nameIsTooLang': '名称超过255个字符', @@ -157,4 +158,10 @@ export default { 'common.text': '文本', 'common.resourceDeleted': '资源已被删除', 'common.refresh': '刷新', + 'common.searchByNameAndId': '通过ID、名称或标签搜索', + 'common.archive': '归档', + 'common.running': '执行中', + 'common.unExecute': '未执行', + 'common.pass': '通过', + 'common.unPass': '不通过', }; diff --git a/frontend/src/models/testPlan/testPlan.ts b/frontend/src/models/testPlan/testPlan.ts index ff8b4c5632..cb605741c0 100644 --- a/frontend/src/models/testPlan/testPlan.ts +++ b/frontend/src/models/testPlan/testPlan.ts @@ -1 +1,27 @@ +// 计划分页 +export interface TestPlanItem { + id?: string; + projectId: string; + num: number; + name: string; + status: string; + type: string; + tags: string[]; + schedule: string; // 是否定时 + createUser: string; + createTime: string; + moduleName: string; + moduleId: string; + children: TestPlanItem[]; + childrenCount: number; + groupId: string; +} + +export interface ResourcesItem { + id: string; + name: string; + cpuRate: string; + status: boolean; +} + export default {}; diff --git a/frontend/src/router/routes/modules/testPlan.ts b/frontend/src/router/routes/modules/testPlan.ts index 42b6676e3a..19e067cb51 100644 --- a/frontend/src/router/routes/modules/testPlan.ts +++ b/frontend/src/router/routes/modules/testPlan.ts @@ -3,31 +3,31 @@ import { TestPlanRouteEnum } from '@/enums/routeEnum'; import { DEFAULT_LAYOUT } from '../base'; import type { AppRouteRecordRaw } from '../types'; -// const TestPlan: AppRouteRecordRaw = { -// path: '/test-plan', -// name: TestPlanRouteEnum.TEST_PLAN, -// redirect: '/test-plan/testPlanIndex', -// component: DEFAULT_LAYOUT, -// meta: { -// locale: 'menu.testPlan', -// icon: 'icon-icon_test-tracking_filled', -// order: 1, -// hideChildrenInMenu: true, -// roles: ['TEST_PLAN:READ'], -// }, -// children: [ -// // 测试计划 -// { -// path: 'testPlanIndex', -// name: TestPlanRouteEnum.TEST_PLAN_INDEX, -// component: () => import('@/views/test-plan/testPlan/index.vue'), -// meta: { -// locale: 'menu.testPlan', -// roles: ['TEST_PLAN:READ'], -// isTopMenu: true, -// }, -// }, -// ], -// }; +const TestPlan: AppRouteRecordRaw = { + path: '/test-plan', + name: TestPlanRouteEnum.TEST_PLAN, + redirect: '/test-plan/testPlanIndex', + component: DEFAULT_LAYOUT, + meta: { + locale: 'menu.testPlan', + icon: 'icon-icon_test-tracking_filled', + order: 1, + hideChildrenInMenu: true, + roles: ['*'], + }, + children: [ + // 测试计划 + { + path: 'testPlanIndex', + name: TestPlanRouteEnum.TEST_PLAN_INDEX, + component: () => import('@/views/test-plan/testPlan/index.vue'), + meta: { + locale: 'menu.testPlan', + roles: ['*'], + isTopMenu: true, + }, + }, + ], +}; -// export default TestPlan; +export default TestPlan; diff --git a/frontend/src/views/case-management/caseReview/components/index/moduleTree.vue b/frontend/src/views/case-management/caseReview/components/index/moduleTree.vue index d2f0b49210..b86a1474e7 100644 --- a/frontend/src/views/case-management/caseReview/components/index/moduleTree.vue +++ b/frontend/src/views/case-management/caseReview/components/index/moduleTree.vue @@ -7,7 +7,12 @@ allow-clear :max-length="255" /> - + {{ t('common.newCreate') }} @@ -225,7 +230,7 @@ }; return { ...e, - hideMoreAction: e.id === 'root', + hideMoreAction: e.id === 'root' || props.isModal, draggable: e.id !== 'root' && !props.isModal, disabled: e.id === activeFolder.value && props.isModal, count: props.modulesCount?.[e.id] || 0, // 避免模块数量先初始化完成了,数量没更新 diff --git a/frontend/src/views/project-management/taskCenter/component/apiCase.vue b/frontend/src/views/project-management/taskCenter/component/apiCase.vue index c7cb2e92bb..e71d6e0c25 100644 --- a/frontend/src/views/project-management/taskCenter/component/apiCase.vue +++ b/frontend/src/views/project-management/taskCenter/component/apiCase.vue @@ -19,6 +19,7 @@ v-bind="propsRes" ref="tableRef" :action-config="tableBatchActions" + :selectable="hasOperationPermission" v-on="propsEvent" @batch-action="handleTableBatch" > diff --git a/frontend/src/views/project-management/taskCenter/component/scheduledTask.vue b/frontend/src/views/project-management/taskCenter/component/scheduledTask.vue index 6b25f5e1ee..88be6c9142 100644 --- a/frontend/src/views/project-management/taskCenter/component/scheduledTask.vue +++ b/frontend/src/views/project-management/taskCenter/component/scheduledTask.vue @@ -22,6 +22,7 @@ v-bind="propsRes" ref="tableRef" :action-config="tableBatchActions" + :selectable="hasOperationPermission" v-on="propsEvent" @batch-action="handleTableBatch" > diff --git a/frontend/src/views/setting/organization/template/components/templateItem.vue b/frontend/src/views/setting/organization/template/components/templateItem.vue index 8fd2c61e78..aeecf0d75c 100644 --- a/frontend/src/views/setting/organization/template/components/templateItem.vue +++ b/frontend/src/views/setting/organization/template/components/templateItem.vue @@ -78,7 +78,6 @@ {{ t('common.cancel') }} - - - - - - - - - - - - - - - - - diff --git a/frontend/src/views/test-plan/testPlan/components/batchMoveOrCopy.vue b/frontend/src/views/test-plan/testPlan/components/batchMoveOrCopy.vue new file mode 100644 index 0000000000..cb13570706 --- /dev/null +++ b/frontend/src/views/test-plan/testPlan/components/batchMoveOrCopy.vue @@ -0,0 +1,178 @@ + + + + + diff --git a/frontend/src/views/test-plan/testPlan/components/planTable.vue b/frontend/src/views/test-plan/testPlan/components/planTable.vue index a52a80c176..f4ffb8446d 100644 --- a/frontend/src/views/test-plan/testPlan/components/planTable.vue +++ b/frontend/src/views/test-plan/testPlan/components/planTable.vue @@ -1,30 +1,223 @@ - + diff --git a/frontend/src/views/test-plan/testPlan/components/scheduledModal.vue b/frontend/src/views/test-plan/testPlan/components/scheduledModal.vue new file mode 100644 index 0000000000..74e38351c5 --- /dev/null +++ b/frontend/src/views/test-plan/testPlan/components/scheduledModal.vue @@ -0,0 +1,174 @@ + + + + + diff --git a/frontend/src/views/test-plan/testPlan/components/statusProgress.vue b/frontend/src/views/test-plan/testPlan/components/statusProgress.vue new file mode 100644 index 0000000000..03f1ecb103 --- /dev/null +++ b/frontend/src/views/test-plan/testPlan/components/statusProgress.vue @@ -0,0 +1,137 @@ + + + + + diff --git a/frontend/src/views/test-plan/testPlan/components/testPlanTree.vue b/frontend/src/views/test-plan/testPlan/components/testPlanTree.vue index 94228eee47..b509ec1c52 100644 --- a/frontend/src/views/test-plan/testPlan/components/testPlanTree.vue +++ b/frontend/src/views/test-plan/testPlan/components/testPlanTree.vue @@ -1,11 +1,5 @@ -