diff --git a/frontend/src/components/business/ms-associate-case/apiCaseTable.vue b/frontend/src/components/business/ms-associate-case/apiCaseTable.vue index 8c9d27ac65..e623896cfa 100644 --- a/frontend/src/components/business/ms-associate-case/apiCaseTable.vue +++ b/frontend/src/components/business/ms-associate-case/apiCaseTable.vue @@ -186,37 +186,47 @@ return undefined; } - const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector, setPagination, resetFilterParams } = - useTable( - getPageList.value, - { - columns, - showSetting: false, - selectable: true, - showSelectAll: true, - heightUsed: 310, - showSelectorAll: false, - }, - (record) => { - return { - ...record, - caseLevel: getCaseLevel(record), - tags: (record.tags || []).map((item: string, i: number) => { - return { - id: `${record.id}-${i}`, - name: item, - }; - }), - }; - } - ); + const { + propsRes, + propsEvent, + loadList, + setLoadListParams, + resetSelector, + setPagination, + resetFilterParams, + setTableSelected, + } = useTable( + getPageList.value, + { + columns, + showSetting: false, + selectable: true, + showSelectAll: true, + heightUsed: 310, + showSelectorAll: false, + }, + (record) => { + return { + ...record, + caseLevel: getCaseLevel(record), + tags: (record.tags || []).map((item: string, i: number) => { + return { + id: `${record.id}-${i}`, + name: item, + }; + }), + }; + } + ); async function getTableParams() { + const { excludeKeys } = propsRes.value; + return { keyword: props.keyword, projectId: props.currentProject, moduleIds: props.activeModule === 'all' || !props.activeModule ? [] : [props.activeModule, ...props.offspringIds], - excludeIds: [...(props.associatedIds || [])], // 已经存在的关联的id列表 + excludeIds: [...excludeKeys], condition: { keyword: props.keyword, }, @@ -226,6 +236,11 @@ } async function getModuleCount() { + if (props.associatedIds && props.associatedIds.length) { + props.associatedIds.forEach((hasNotAssociatedId) => { + setTableSelected(hasNotAssociatedId); + }); + } const tableParams = await getTableParams(); emit('getModuleCount', { ...tableParams, @@ -235,6 +250,11 @@ } async function loadCaseList() { + if (props.associatedIds && props.associatedIds.length) { + props.associatedIds.forEach((hasNotAssociatedId) => { + setTableSelected(hasNotAssociatedId); + }); + } const tableParams = await getTableParams(); setLoadListParams(tableParams); loadList(); @@ -296,7 +316,7 @@ const tableParams = getTableParams(); return { ...tableParams, - excludeIds: [...excludeKeys].concat(...(props.associatedIds || [])), + excludeIds: [...excludeKeys], selectIds: selectorStatus === 'all' ? [] : [...selectedKeys], selectAll: selectorStatus === 'all', associateApiType: 'API_CASE', diff --git a/frontend/src/components/business/ms-associate-case/apiTable.vue b/frontend/src/components/business/ms-associate-case/apiTable.vue index b2de725460..eaee81a47b 100644 --- a/frontend/src/components/business/ms-associate-case/apiTable.vue +++ b/frontend/src/components/business/ms-associate-case/apiTable.vue @@ -160,23 +160,32 @@ }, ]; - const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector, setPagination, resetFilterParams } = - useTable(getPublicLinkCaseListMap[props.getPageApiType][props.activeSourceType].API, { - columns, - showSetting: false, - selectable: true, - showSelectAll: true, - heightUsed: 310, - showSelectorAll: false, - }); + const { + propsRes, + propsEvent, + loadList, + setLoadListParams, + resetSelector, + setPagination, + resetFilterParams, + setTableSelected, + } = useTable(getPublicLinkCaseListMap[props.getPageApiType][props.activeSourceType].API, { + columns, + showSetting: false, + selectable: true, + showSelectAll: true, + heightUsed: 310, + showSelectorAll: false, + }); async function getTableParams() { + const { excludeKeys } = propsRes.value; return { keyword: props.keyword, projectId: props.currentProject, protocols: props.protocols, moduleIds: props.activeModule === 'all' || !props.activeModule ? [] : [props.activeModule, ...props.offspringIds], - excludeIds: [...(props.associatedIds || [])], // 已经存在的关联的id列表 + excludeIds: [...excludeKeys], condition: { keyword: props.keyword, }, @@ -194,6 +203,11 @@ } async function loadApiList() { + if (props.associatedIds && props.associatedIds.length) { + props.associatedIds.forEach((hasNotAssociatedId) => { + setTableSelected(hasNotAssociatedId); + }); + } const tableParams = await getTableParams(); setLoadListParams(tableParams); loadList(); @@ -255,7 +269,7 @@ const tableParams = getTableParams(); return { ...tableParams, - excludeIds: [...excludeKeys].concat(...(props.associatedIds || [])), + excludeIds: [...excludeKeys], selectIds: selectorStatus === 'all' ? [] : [...selectedKeys], selectAll: selectorStatus === 'all', associateApiType: 'API', diff --git a/frontend/src/components/business/ms-associate-case/caseTable.vue b/frontend/src/components/business/ms-associate-case/caseTable.vue index a5d172bcea..c28e29b385 100644 --- a/frontend/src/components/business/ms-associate-case/caseTable.vue +++ b/frontend/src/components/business/ms-associate-case/caseTable.vue @@ -82,6 +82,7 @@ (e: 'initModules'): void; (e: 'update:selectedIds'): void; }>(); + const innerSelectedIds = defineModel('selectedIds', { required: true }); const reviewResultOptions = computed(() => { return Object.keys(statusIconMap).map((key) => { @@ -194,37 +195,46 @@ return undefined; } - const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector, setPagination, resetFilterParams } = - useTable( - getPageList.value, - { - columns, - showSetting: false, - selectable: true, - showSelectAll: true, - heightUsed: 310, - showSelectorAll: false, - }, - (record) => { - return { - ...record, - caseLevel: getCaseLevel(record), - tags: (record.tags || []).map((item: string, i: number) => { - return { - id: `${record.id}-${i}`, - name: item, - }; - }), - }; - } - ); + const { + propsRes, + propsEvent, + loadList, + setLoadListParams, + resetSelector, + setPagination, + resetFilterParams, + setTableSelected, + } = useTable( + getPageList.value, + { + columns, + showSetting: false, + selectable: true, + showSelectAll: true, + heightUsed: 310, + showSelectorAll: false, + }, + (record) => { + return { + ...record, + caseLevel: getCaseLevel(record), + tags: (record.tags || []).map((item: string, i: number) => { + return { + id: `${record.id}-${i}`, + name: item, + }; + }), + }; + } + ); async function getTableParams() { + const { excludeKeys } = propsRes.value; return { keyword: props.keyword, projectId: props.currentProject, moduleIds: props.activeModule === 'all' || !props.activeModule ? [] : [props.activeModule, ...props.offspringIds], - excludeIds: [...(props.associatedIds || [])], // 已经存在的关联的id列表 + excludeIds: [...excludeKeys], condition: { keyword: props.keyword, filter: propsRes.value.filter, @@ -243,6 +253,11 @@ } async function loadCaseList() { + if (props.associatedIds && props.associatedIds.length) { + props.associatedIds.forEach((hasNotAssociatedId) => { + setTableSelected(hasNotAssociatedId); + }); + } const tableParams = await getTableParams(); setLoadListParams(tableParams); loadList(); @@ -256,11 +271,12 @@ const tableRef = ref>(); function getFunctionalSaveParams() { + console.log(111); const { excludeKeys, selectedKeys, selectorStatus } = propsRes.value; const tableParams = getTableParams(); return { ...tableParams, - excludeIds: [...excludeKeys].concat(...(props.associatedIds || [])), + excludeIds: [...excludeKeys], selectIds: selectorStatus === 'all' ? [] : [...selectedKeys], selectAll: selectorStatus === 'all', }; @@ -278,8 +294,6 @@ } ); - const innerSelectedIds = defineModel('selectedIds', { required: true }); - const selectIds = computed(() => { return [...propsRes.value.selectedKeys]; }); diff --git a/frontend/src/components/business/ms-associate-case/index.vue b/frontend/src/components/business/ms-associate-case/index.vue index ba7497ff3a..2d32f5d9ff 100644 --- a/frontend/src/components/business/ms-associate-case/index.vue +++ b/frontend/src/components/business/ms-associate-case/index.vue @@ -445,6 +445,9 @@ const selectPopVisible = ref(false); function loadCaseList() { + if (props.associatedIds && props.associatedIds.length > 0) { + selectedIds.value = props.associatedIds; + } switch (associationType.value) { case CaseLinkEnum.FUNCTIONAL: return functionalTableRef.value?.loadCaseList(); diff --git a/frontend/src/components/business/ms-associate-case/scenarioCaseTable.vue b/frontend/src/components/business/ms-associate-case/scenarioCaseTable.vue index 44498a9e8f..0a05dd70b0 100644 --- a/frontend/src/components/business/ms-associate-case/scenarioCaseTable.vue +++ b/frontend/src/components/business/ms-associate-case/scenarioCaseTable.vue @@ -180,22 +180,31 @@ const getPageList = computed(() => { return getPublicLinkCaseListMap[props.getPageApiType][props.activeSourceType]; }); - const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector, setPagination, resetFilterParams } = - useTable(getPageList.value, { - columns, - showSetting: false, - selectable: true, - showSelectAll: true, - heightUsed: 310, - showSelectorAll: false, - }); + const { + propsRes, + propsEvent, + loadList, + setLoadListParams, + resetSelector, + setPagination, + resetFilterParams, + setTableSelected, + } = useTable(getPageList.value, { + columns, + showSetting: false, + selectable: true, + showSelectAll: true, + heightUsed: 310, + showSelectorAll: false, + }); async function getTableParams() { + const { excludeKeys } = propsRes.value; return { keyword: props.keyword, projectId: props.currentProject, moduleIds: props.activeModule === 'all' || !props.activeModule ? [] : [props.activeModule, ...props.offspringIds], - excludeIds: [...(props.associatedIds || [])], // 已经存在的关联的id列表 + excludeIds: [...excludeKeys], condition: { keyword: props.keyword, filter: propsRes.value.filter, @@ -214,6 +223,11 @@ } async function loadScenarioList() { + if (props.associatedIds && props.associatedIds.length) { + props.associatedIds.forEach((hasNotAssociatedId) => { + setTableSelected(hasNotAssociatedId); + }); + } const tableParams = await getTableParams(); setLoadListParams(tableParams); loadList(); @@ -255,7 +269,7 @@ const tableParams = getTableParams(); return { ...tableParams, - excludeIds: [...excludeKeys].concat(...(props.associatedIds || [])), + excludeIds: [...excludeKeys], selectIds: selectorStatus === 'all' ? [] : [...selectedKeys], selectAll: selectorStatus === 'all', }; diff --git a/frontend/src/components/business/ms-minders/testPlanMinder/associateDrawer.vue b/frontend/src/components/business/ms-minders/testPlanMinder/associateDrawer.vue index 8ba100d345..bfcb4750ca 100644 --- a/frontend/src/components/business/ms-minders/testPlanMinder/associateDrawer.vue +++ b/frontend/src/components/business/ms-minders/testPlanMinder/associateDrawer.vue @@ -55,7 +55,7 @@ async function saveHandler(params: AssociateCaseRequest) { if (typeof props.saveApi !== 'function') { - emit('success', { ...params, functionalSelectIds: params.selectIds }); + emit('success', { ...params }); } else { try { confirmLoading.value = true; @@ -63,7 +63,7 @@ functionalSelectIds: params.selectIds, testPlanId: planId.value, }); - emit('success', { ...params, functionalSelectIds: params.selectIds }); + emit('success', { ...params }); Message.success(t('ms.case.associate.associateSuccess')); } catch (error) { // eslint-disable-next-line no-console diff --git a/frontend/src/components/business/ms-minders/testPlanMinder/index.vue b/frontend/src/components/business/ms-minders/testPlanMinder/index.vue index f8b21d5ad6..28a36af96d 100644 --- a/frontend/src/components/business/ms-minders/testPlanMinder/index.vue +++ b/frontend/src/components/business/ms-minders/testPlanMinder/index.vue @@ -107,7 +107,7 @@
{{ - t('caseManagement.caseReview.selectedCases', { + t('ms.minders.selectedCases', { count: selectedAssociateCasesParams.selectAll ? selectedAssociateCasesParams.totalCount : selectedAssociateCasesParams.selectIds.length, @@ -769,7 +769,6 @@ } catch (error) { // eslint-disable-next-line no-console console.log(error); - selectedAssociateCasesParams.value.selectIds = []; } finally { loading.value = false; tempMinderParams.value = { @@ -777,6 +776,7 @@ editList: [], deletedIds: [], }; + selectedAssociateCasesParams.value.selectIds = []; } } diff --git a/frontend/src/components/business/ms-minders/testPlanMinder/locale/en-US.ts b/frontend/src/components/business/ms-minders/testPlanMinder/locale/en-US.ts index 51a32fbc1d..22574d66be 100644 --- a/frontend/src/components/business/ms-minders/testPlanMinder/locale/en-US.ts +++ b/frontend/src/components/business/ms-minders/testPlanMinder/locale/en-US.ts @@ -19,4 +19,5 @@ export default { 'ms.minders.env': 'Environment', 'ms.minders.item': '{count} Strip', 'ms.minders.unsavedTip': 'Please save your changed configuration first!', + 'ms.minders.selectedCases': '{count} is selected', }; diff --git a/frontend/src/components/business/ms-minders/testPlanMinder/locale/zh-CN.ts b/frontend/src/components/business/ms-minders/testPlanMinder/locale/zh-CN.ts index 2f9bef29a5..56bb5dcd9e 100644 --- a/frontend/src/components/business/ms-minders/testPlanMinder/locale/zh-CN.ts +++ b/frontend/src/components/business/ms-minders/testPlanMinder/locale/zh-CN.ts @@ -19,4 +19,5 @@ export default { 'ms.minders.env': '环境', 'ms.minders.item': '{count}条', 'ms.minders.unsavedTip': '请先保存您更改的配置!', + 'ms.minders.selectedCases': '已选 {count} 条', }; diff --git a/frontend/src/config/pathMap.ts b/frontend/src/config/pathMap.ts index 6dd771149a..c3413630af 100644 --- a/frontend/src/config/pathMap.ts +++ b/frontend/src/config/pathMap.ts @@ -988,6 +988,28 @@ export const pathMap: PathMapItem[] = [ route: RouteEnum.TEST_PLAN_REPORT, permission: [], level: MENU_LEVEL[2], + children: [ + { + key: 'TEST_PLAN_REPORT_TEST_PLAN', // 测试计划报告 + locale: 'menu.apiTest.reportTestPlan', + route: RouteEnum.TEST_PLAN_REPORT, + permission: [], + level: MENU_LEVEL[2], + routeQuery: { + type: 'TEST_PLAN', + }, + }, + { + key: 'TEST_PLAN_REPORT_TEST_PLAN_GROUP', // 测试计划组报告 + locale: 'menu.apiTest.reportTestGroupPlan', + route: RouteEnum.TEST_PLAN_REPORT, + permission: [], + level: MENU_LEVEL[2], + routeQuery: { + type: 'GROUP', + }, + }, + ], }, ], }, diff --git a/frontend/src/config/testPlan.ts b/frontend/src/config/testPlan.ts index 62ae47332a..043113f03d 100644 --- a/frontend/src/config/testPlan.ts +++ b/frontend/src/config/testPlan.ts @@ -1,5 +1,7 @@ import { cloneDeep } from 'lodash-es'; +import { addCommasToNumber } from '@/utils'; + import type { PassRateCountDetail, planStatusType, TestPlanDetail } from '@/models/testPlan/testPlan'; import type { countDetail, PlanReportDetail, StatusListType } from '@/models/testPlan/testPlanReport'; import { LastExecuteResults } from '@/enums/caseEnum'; @@ -134,6 +136,31 @@ export const statusConfig: StatusListType[] = [ }, ]; +export const toolTipConfig = { + show: true, + trigger: 'item', + label: { + color: '#959598', + }, + backgroundColor: '#fff', + padding: 24, + borderWidth: 0, + formatter(params: any) { + const html = ` +
+
+
+
${params.name}
+
+
${addCommasToNumber(params.value)}
+
+ `; + return html; + }, +}; + export const commonConfig = { tooltip: { show: false, diff --git a/frontend/src/locale/en-US/common.ts b/frontend/src/locale/en-US/common.ts index c82eb2a9ef..d2f7bea356 100644 --- a/frontend/src/locale/en-US/common.ts +++ b/frontend/src/locale/en-US/common.ts @@ -164,6 +164,7 @@ export default { 'common.image': 'Image', 'common.text': 'Text', 'common.resourceDeleted': 'Resource has been deleted', + 'common.resourceExpired': 'Link has failed, please get it again', 'common.refresh': 'Refresh', 'common.searchByNameAndId': 'Search by ID, name, or tag', 'common.archive': 'archive', diff --git a/frontend/src/locale/en-US/index.ts b/frontend/src/locale/en-US/index.ts index 250ece514b..a98df68533 100644 --- a/frontend/src/locale/en-US/index.ts +++ b/frontend/src/locale/en-US/index.ts @@ -40,6 +40,8 @@ export default { 'menu.apiTest.apiScenario': 'Scenario', 'menu.apiTest.scenario.recycle': 'Recycle', 'menu.apiTest.report': 'Report', + 'menu.apiTest.reportTestPlan': 'Test report', + 'menu.apiTest.reportTestGroupPlan': 'Test Group Report', 'menu.apiTest.reportDetail': 'Report Detail', 'menu.uiTest': 'UI Test', 'menu.performanceTest': 'Performance Test', diff --git a/frontend/src/locale/zh-CN/common.ts b/frontend/src/locale/zh-CN/common.ts index 1b5a444b84..d5fd38c8e7 100644 --- a/frontend/src/locale/zh-CN/common.ts +++ b/frontend/src/locale/zh-CN/common.ts @@ -126,7 +126,7 @@ export default { 'common.move': '移动', 'common.moveSuccess': '移动成功', 'common.batchMove': '批量移动', - 'common.batchArchiveSuccess': '归档成功!', + 'common.batchArchiveSuccess': '归档成功', 'common.batchCopy': '批量复制', 'common.batchCopySuccess': '批量复制成功', 'common.batchMoveSuccess': '批量移动成功', @@ -163,6 +163,7 @@ export default { 'common.image': '图片', 'common.text': '文本', 'common.resourceDeleted': '资源已被删除', + 'common.resourceExpired': '链接已失效,请重新获取', 'common.refresh': '刷新', 'common.searchByIdName': '通过ID 或名称搜索', 'common.searchByIDNameTag': '通过ID、名称或标签搜索', diff --git a/frontend/src/locale/zh-CN/index.ts b/frontend/src/locale/zh-CN/index.ts index 77349fde68..e491f05ec6 100644 --- a/frontend/src/locale/zh-CN/index.ts +++ b/frontend/src/locale/zh-CN/index.ts @@ -39,6 +39,8 @@ export default { 'menu.apiTest.scenario': '场景', 'menu.apiTest.scenario.recycle': '回收站', 'menu.apiTest.report': '报告', + 'menu.apiTest.reportTestPlan': '测试报告', + 'menu.apiTest.reportTestGroupPlan': '测试组报告', 'menu.apiTest.reportDetail': '报告详情', 'menu.uiTest': 'UI测试', 'menu.workstation': '工作台', diff --git a/frontend/src/views/api-test/report/component/case/setReportChart.vue b/frontend/src/views/api-test/report/component/case/setReportChart.vue index cf40d97c47..408364dfc1 100644 --- a/frontend/src/views/api-test/report/component/case/setReportChart.vue +++ b/frontend/src/views/api-test/report/component/case/setReportChart.vue @@ -17,9 +17,10 @@
- -
-