diff --git a/frontend/src/api/modules/test-plan/testPlan.ts b/frontend/src/api/modules/test-plan/testPlan.ts index b8743734c5..4f6e20783d 100644 --- a/frontend/src/api/modules/test-plan/testPlan.ts +++ b/frontend/src/api/modules/test-plan/testPlan.ts @@ -16,6 +16,7 @@ import { DeleteTestPlanModuleUrl, DisassociateCaseUrl, followPlanUrl, + GetAssociatedBugUrl, GetFeatureCaseModuleCountUrl, GetFeatureCaseModuleUrl, GetPlanDetailFeatureCaseListUrl, @@ -29,6 +30,8 @@ import { planPassRateUrl, RunFeatureCaseUrl, SortFeatureCaseUrl, + TestPlanAssociateBugUrl, + TestPlanCancelBugUrl, updateTestPlanModuleUrl, UpdateTestPlanUrl, } from '@/api/requrls/test-plan/testPlan'; @@ -188,3 +191,15 @@ export function batchUpdateCaseExecutor(data: BatchUpdateCaseExecutorParams) { export function runFeatureCase(data: RunFeatureCaseParams) { return MSR.post({ url: RunFeatureCaseUrl, data }); } +// 测试计划-用例详情-缺陷列表 +export function associatedBugPage(data: TableQueryParams) { + return MSR.post({ url: GetAssociatedBugUrl, data }); +} +// 测试计划-用例详情-关联缺陷 +export function associateBugToPlan(data: TableQueryParams) { + return MSR.post({ url: TestPlanAssociateBugUrl, data }); +} +// 测试计划-用例详情-关联缺陷 +export function testPlanCancelBug(id: string) { + return MSR.get({ url: `${TestPlanCancelBugUrl}/${id}` }); +} diff --git a/frontend/src/api/requrls/test-plan/testPlan.ts b/frontend/src/api/requrls/test-plan/testPlan.ts index 03f8ca9dc3..f68b436698 100644 --- a/frontend/src/api/requrls/test-plan/testPlan.ts +++ b/frontend/src/api/requrls/test-plan/testPlan.ts @@ -56,6 +56,12 @@ export const DisassociateCaseUrl = '/test-plan/functional/case/disassociate'; export const BatchDisassociateCaseUrl = '/test-plan/functional/case/batch/disassociate'; // 计划详情-功能用例-执行 export const RunFeatureCaseUrl = '/test-plan/functional/case/run'; +// 测试计划-用例详情-缺陷列表 +export const GetAssociatedBugUrl = '/test-plan/functional/case/has/associate/bug/page'; +// 测试计划-用例详情-关联缺陷 +export const TestPlanAssociateBugUrl = '/test-plan/functional/case/associate/bug'; +// 测试计划-用例详情-取消关联缺陷 +export const TestPlanCancelBugUrl = '/test-plan/functional/case/disassociate/bug'; // 计划详情-功能用例-批量执行 export const BatchRunCaseUrl = '/test-plan/functional/case/batch/run'; // 计划详情-功能用例-批量更新执行人 diff --git a/frontend/src/components/business/ms-case-associate/executeResult.vue b/frontend/src/components/business/ms-case-associate/executeResult.vue index 747471f17f..59608492a6 100644 --- a/frontend/src/components/business/ms-case-associate/executeResult.vue +++ b/frontend/src/components/business/ms-case-associate/executeResult.vue @@ -4,9 +4,9 @@ :type="lastExecuteResultMap[props.executeResult]?.icon || ''" class="mr-1" :size="16" - :style="{ color: lastExecuteResultMap[props.executeResult].color }" + :style="{ color: lastExecuteResultMap[props.executeResult]?.color }" > - {{ status?.text || '' }} + {{ lastExecuteResultMap[props.executeResult]?.statusText || '-' }} @@ -24,46 +24,42 @@ }>(); const lastExecuteResultMap = { - UN_EXECUTED: { - label: 'UN_EXECUTED', - icon: StatusType.UN_EXECUTED, - statusText: 'caseManagement.featureCase.nonExecution', + PENDING: { + label: 'PENDING', + icon: StatusType.PENDING, + statusText: t('caseManagement.featureCase.nonExecution'), color: 'var(--color-text-brand)', }, - PASSED: { - label: 'PASSED', - icon: StatusType.PASSED, - statusText: 'common.success', + SUCCESS: { + label: 'SUCCESS', + icon: StatusType.SUCCESS, + statusText: t('common.success'), color: '', }, - SKIPPED: { - label: 'SKIPPED', - icon: StatusType.SKIPPED, - statusText: 'caseManagement.featureCase.skip', - color: 'rgb(var(--link-6))', - }, BLOCKED: { label: 'BLOCKED', icon: StatusType.BLOCKED, - statusText: 'caseManagement.featureCase.chokeUp', + statusText: t('caseManagement.featureCase.chokeUp'), color: 'rgb(var(--warning-6))', }, - FAILED: { - label: 'FAILED', - icon: StatusType.FAILED, - statusText: 'caseManagement.featureCase.failure', + ERROR: { + label: 'ERROR', + icon: StatusType.ERROR, + statusText: t('caseManagement.featureCase.failure'), color: '', }, }; - const status = computed(() => { - if (props.executeResult) { - const config = lastExecuteResultMap[props.executeResult]; - return { - text: t(config?.statusText || ''), - }; - } - }); + // const status = computed(() => { + // if (props.executeResult) { + // const config = lastExecuteResultMap[props.executeResult]; + // if (config) { + // return { + // text: t(config?.statusText || ''), + // }; + // } + // } + // }); diff --git a/frontend/src/components/pure/ms-table/base-table.vue b/frontend/src/components/pure/ms-table/base-table.vue index 0cb6cb4cab..6a7e33121a 100644 --- a/frontend/src/components/pure/ms-table/base-table.vue +++ b/frontend/src/components/pure/ms-table/base-table.vue @@ -66,8 +66,8 @@ :sortable="item.sortable" :filterable="item.filterable" :cell-class="item.cellClass" - :header-cell-class="`${ - item.headerCellClass || (item.filterConfig && hasSelectedFilter(item)) ? 'header-cell-filter' : '' + :header-cell-class="`${item.filterConfig && hasSelectedFilter(item) ? 'header-cell-filter' : ''} ${ + item.headerCellClass }`" :body-cell-class="item.bodyCellClass" :summary-cell-class="item.summaryCellClass" @@ -101,7 +101,7 @@ @init-data="handleInitColumn" /> { + return (attrs.filter || {}) as Record; + }); + const handleFilterConfirm = ( value: string[] | (string | number)[] | undefined, dataIndex: string, @@ -652,10 +656,6 @@ batchLeft.value = getBatchLeft(); }); - const filterData = computed(() => { - return (attrs.filter || {}) as Record; - }); - function hasSelectedFilter(item: MsTableColumnData) { if (item.filterConfig && item.dataIndex) { return (filterData.value[item.dataIndex] || []).length > 0; diff --git a/frontend/src/components/pure/ms-table/comp/defaultFilter.vue b/frontend/src/components/pure/ms-table/comp/defaultFilter.vue index 1c2e0e639e..f9312004de 100644 --- a/frontend/src/components/pure/ms-table/comp/defaultFilter.vue +++ b/frontend/src/components/pure/ms-table/comp/defaultFilter.vue @@ -160,7 +160,7 @@ const isNoFilter = computed(() => { if (props.filter && JSON.stringify(props.filter) !== '{}') { return !Object.keys(props.filter).some((key: any) => { - return props.filter[key].length > 0; + return (props.filter[key] || []).length > 0; }); } return true; diff --git a/frontend/src/components/pure/ms-table/comp/filterConfig.ts b/frontend/src/components/pure/ms-table/comp/filterConfig.ts index b5e09cfdec..cffd5ade76 100644 --- a/frontend/src/components/pure/ms-table/comp/filterConfig.ts +++ b/frontend/src/components/pure/ms-table/comp/filterConfig.ts @@ -1,4 +1,4 @@ -import { getProjectMemberOptions } from '@/api/modules/project-management/projectMember'; +import { getProjectOptions } from '@/api/modules/project-management/projectMember'; import { getProjectList } from '@/api/modules/setting/member'; import { getOrgOptions, getSystemProjectList } from '@/api/modules/system'; @@ -7,7 +7,7 @@ import { FilterRemoteMethodsEnum } from '@/enums/tableFilterEnum'; export function initRemoteOptionsFunc(remoteMethod: string, params: Record) { switch (remoteMethod) { case FilterRemoteMethodsEnum.PROJECT_PERMISSION_MEMBER: - return getProjectMemberOptions(params.projectId, params.keyword); + return getProjectOptions(params.projectId, params.keyword); case FilterRemoteMethodsEnum.SYSTEM_ORGANIZATION_LIST: return getOrgOptions(); case FilterRemoteMethodsEnum.SYSTEM_PROJECT_LIST: diff --git a/frontend/src/enums/caseEnum.ts b/frontend/src/enums/caseEnum.ts index d2c29652f6..284a113849 100644 --- a/frontend/src/enums/caseEnum.ts +++ b/frontend/src/enums/caseEnum.ts @@ -2,22 +2,21 @@ export enum StatusType { UN_REVIEWED = 'icon-icon_block_filled', // 未评审 UNDER_REVIEWED = 'icon-icon_testing', // 评审中 + SUCCESS = 'icon-icon_succeed_colorful', // 成功 PASS = 'icon-icon_succeed_colorful', // 已通过 UN_PASS = 'icon-icon_close_colorful', // 未通过 RE_REVIEWED = 'icon-icon_resubmit_filled', // 重新提审 - UN_EXECUTED = 'icon-icon_block_filled', // 未执行 PASSED = 'icon-icon_succeed_colorful', // 已执行 - FAILED = 'icon-icon_close_colorful', // 失败 + ERROR = 'icon-icon_close_colorful', // 失败 BLOCKED = 'icon-icon_block_filled', // 阻塞 - SKIPPED = 'icon-icon_skip_planarity', // 跳过 + PENDING = 'icon-icon_block_filled', // 未执行 } export enum LastExecuteResults { - UN_EXECUTED = 'UN_EXECUTED', - PASSED = 'PASSED', - SKIPPED = 'SKIPPED', + PENDING = 'PENDING', + SUCCESS = 'SUCCESS', BLOCKED = 'BLOCKED', - FAILED = 'FAILED', + ERROR = 'ERROR', } export enum CaseLinkEnum { diff --git a/frontend/src/enums/reportEnum.ts b/frontend/src/enums/reportEnum.ts index 7a97b1b1ea..304f3060c1 100644 --- a/frontend/src/enums/reportEnum.ts +++ b/frontend/src/enums/reportEnum.ts @@ -18,7 +18,14 @@ export enum TriggerModeLabel { BATCH = 'report.trigger.batch.execution', // 批量执行 API = 'report.trigger.interface', // 接口调用 } -export const ReportStatus = { +export enum TriggerModeLabelEnum { + MANUAL = 'MANUAL', // 手动执行 + SCHEDULE = 'SCHEDULE', // 定时任务 + BATCH = 'BATCH', // 批量执行 + API = 'API', // 接口调用 +} + +export const ReportStatus: Record> = { [ReportEnum.API_REPORT]: { SUCCESS: { icon: 'icon-icon_succeed_colorful', @@ -30,16 +37,16 @@ export const ReportStatus = { }, FAKE_ERROR: { icon: 'icon-icon_warning_colorful', - label: 'report.falseAlarm', + label: 'report.fake.error', }, STOPPED: { icon: 'icon-icon_block_filled', - label: 'report.stop', + label: 'report.stopped', color: '!var(--color-text-input-border)', }, RUNNING: { icon: 'icon-icon_testing', - label: 'report.inExecution', + label: 'report.status.running', color: '!text-[rgb(var(--link-6))]', }, // RERUNNING: { @@ -49,7 +56,7 @@ export const ReportStatus = { // }, PENDING: { icon: 'icon-icon_wait', - label: 'report.queuing', + label: 'report.status.pending', color: '!text-[rgb(var(--link-6))]', }, }, @@ -64,16 +71,16 @@ export const ReportStatus = { }, FAKE_ERROR: { icon: 'icon-icon_warning_colorful', - label: 'report.falseAlarm', + label: 'report.fake.error', }, STOPPED: { icon: 'icon-icon_block_filled', - label: 'report.stop', + label: 'report.stopped', color: 'var(--color-text-input-border)', }, RUNNING: { icon: 'icon-icon_testing', - label: 'report.inExecution', + label: 'report.status.running', color: '!text-[rgb(var(--link-6))]', }, // RERUNNING: { @@ -83,7 +90,7 @@ export const ReportStatus = { // }, PENDING: { icon: 'icon-icon_wait', - label: 'report.queuing', + label: 'report.status.pending', color: '!text-[rgb(var(--link-6))]', }, }, @@ -130,4 +137,5 @@ export const PlanReportStatus: Record = { }, }, }; + export default {}; diff --git a/frontend/src/enums/tableFilterEnum.ts b/frontend/src/enums/tableFilterEnum.ts index 60967e10d2..1efdd9e060 100644 --- a/frontend/src/enums/tableFilterEnum.ts +++ b/frontend/src/enums/tableFilterEnum.ts @@ -11,6 +11,13 @@ export enum FilterSlotNameEnum { PROJECT_MANAGEMENT_COMMON_SCRIPT = 'PROJECT_MANAGEMENT_COMMON_SCRIPT', // 项目管理公共脚本脚本状态 GLOBAL_TASK_CENTER_API_CASE_STATUS = 'GLOBAL_TASK_CENTER_API_CASE_STATUS', // 任务中心执行状态 GLOBAL_TASK_CENTER_API_CASE_TRIGGED_MODE = 'GLOBAL_TASK_CENTER_API_CASE_TRIGGED_MODE', // 任务中心触发方式 + API_TEST_CASE_API_STATUS = 'API_TEST_CASE_API_STATUS', // 接口测试-定义-用例列表-接口状态 + API_TEST_CASE_API_LAST_EXECUTE_STATUS = 'API_TEST_CASE_API_LAST_EXECUTE_STATUS', // 接口测试-定义-用例列表-最后执行状态 + API_TEST_CASE_API_REPORT_TRIGGED_METHOD = 'API_TEST_CASE_API_REPORT_TRIGGED_METHOD', // 接口测试-定义-用例列表-最后执行状态 + API_TEST_CASE_API_REPORT_EXECUTE_RESULT = 'API_TEST_CASE_API_REPORT_EXECUTE_RESULT', // 接口测试-定义-用例变更历史-最后执行结果 + GLOBAL_CHANGE_HISTORY_TYPE = 'GLOBAL_CHANGE_HISTORY_TYPE', // 变更历史类型 + API_TEST_SCENARIO_EXECUTE_RESULT = 'API_TEST_SCENARIO_EXECUTE_RESULT', // 接口测试-场景-变更历史-执行结果 + API_TEST_REPORT_TYPE = 'API_TEST_REPORT_TYPE', // 接口测试-报告-报告类型 } export enum FilterRemoteMethodsEnum { diff --git a/frontend/src/views/api-test/management/components/management/api/apiTable.vue b/frontend/src/views/api-test/management/components/management/api/apiTable.vue index b705021e6e..1c7f2326b5 100644 --- a/frontend/src/views/api-test/management/components/management/api/apiTable.vue +++ b/frontend/src/views/api-test/management/components/management/api/apiTable.vue @@ -19,6 +19,7 @@ - - - - {{ t(columnConfig.title as string) }} - - - - - - - - - - - - - - {{ t('common.reset') }} - - - {{ t('system.orgTemplate.confirm') }} - - - - - + + - - - - {{ t(columnConfig.title as string) }} - - - - - - - - - - - - - - {{ t('common.reset') }} - - - {{ t('system.orgTemplate.confirm') }} - - - - - + + {{ record.num }} @@ -115,6 +60,11 @@ {{ record.caseTotal }} + + + {{ characterLimit(record.createUserName) }} + + - - - - {{ item.label }} - - - { + return Object.values(RequestMethods).map((e) => { + return { + value: e, + key: e, + }; + }); + }); + const requestApiStatus = computed(() => { + return Object.values(RequestDefinitionStatus).map((e) => { + return { + value: e, + key: e, + }; + }); + }); + let columns: MsTableColumn = [ { title: 'ID', @@ -433,15 +387,21 @@ title: 'apiTestManagement.apiType', dataIndex: 'method', slotName: 'method', - titleSlotName: 'methodFilter', width: 140, showDrag: true, + filterConfig: { + options: requestMethodsOptions.value, + filterSlotName: FilterSlotNameEnum.API_TEST_API_REQUEST_METHODS, + }, }, { title: 'apiTestManagement.apiStatus', dataIndex: 'status', slotName: 'status', - titleSlotName: 'statusFilter', + filterConfig: { + options: requestApiStatus.value, + filterSlotName: FilterSlotNameEnum.API_TEST_API_REQUEST_API_STATUS, + }, width: 130, showDrag: true, }, @@ -498,10 +458,16 @@ { title: 'common.creator', slotName: 'createUserName', - dataIndex: 'createUserName', - titleSlotName: 'createUserFilter', + dataIndex: 'createUser', + filterConfig: { + mode: 'remote', + loadOptionParams: { + projectId: appStore.currentProjectId, + }, + remoteMethod: FilterRemoteMethodsEnum.PROJECT_PERMISSION_MEMBER, + placeholderText: t('caseManagement.featureCase.PleaseSelect'), + }, showInTable: true, - showTooltip: true, width: 200, showDrag: true, }, @@ -514,6 +480,21 @@ }, ]; + function initFilterColumn() { + columns = columns.map((item) => { + if (item.dataIndex === 'method') { + return { + ...item, + filterConfig: { + ...item.filterConfig, + options: props.protocol === 'HTTP' ? requestMethodsOptions.value : [], + }, + }; + } + return item; + }); + } + await initFilterColumn(); await tableStore.initColumn(TableKeyEnum.API_TEST, columns, 'drawer', true); if (props.readOnly) { columns = columns.filter( @@ -581,13 +562,6 @@ }, ]; - const methodFilterVisible = ref(false); - const methodFilters = ref([]); - const statusFilterVisible = ref(false); - const statusFilters = ref([]); - const createUserFilterVisible = ref(false); - const createUserFilters = ref([]); - async function getModuleIds() { let moduleIds: string[] = []; if (props.activeModule !== 'all') { @@ -607,21 +581,13 @@ projectId: appStore.currentProjectId, moduleIds, protocol: props.protocol, - filter: { - status: statusFilters.value, - method: methodFilters.value, - createUser: createUserFilters.value, - }, + filter: propsRes.value.filter, }; if (!hasRefreshTree && typeof refreshModuleTreeCount === 'function') { refreshModuleTreeCount({ keyword: keyword.value, - filter: { - status: statusFilters.value, - method: methodFilters.value, - createUser: createUserFilters.value, - }, + filter: propsRes.value.filter, moduleIds: [], protocol: props.protocol, projectId: appStore.currentProjectId, @@ -657,14 +623,6 @@ } ); - function handleFilterHidden(val: boolean) { - if (!val) { - loadApiList(false); - methodFilterVisible.value = false; - statusFilterVisible.value = false; - } - } - async function handleMethodChange(record: ApiDefinitionDetail) { try { await updateDefinition({ @@ -734,11 +692,7 @@ excludeIds: params?.excludeIds || [], condition: { keyword: keyword.value, - filter: { - status: statusFilters.value, - method: methodFilters.value, - createUser: createUserFilters.value, - }, + filter: propsRes.value.filter, }, projectId: appStore.currentProjectId, moduleIds: await getModuleIds(), @@ -861,11 +815,7 @@ excludeIds: batchParams.value?.excludeIds || [], condition: { keyword: keyword.value, - filter: { - status: statusFilters.value, - method: methodFilters.value, - createUser: createUserFilters.value, - }, + filter: propsRes.value.filter, }, projectId: appStore.currentProjectId, moduleIds: await getModuleIds(), @@ -906,11 +856,7 @@ excludeIds: batchParams.value?.excludeIds || [], condition: { keyword: keyword.value, - filter: { - status: statusFilters.value, - method: methodFilters.value, - createUser: createUserFilters.value, - }, + filter: propsRes.value.filter, }, projectId: appStore.currentProjectId, moduleIds: await getModuleIds(), @@ -943,18 +889,6 @@ selectedModuleKeys.value = []; } - function resetMethodFilter() { - methodFilters.value = []; - methodFilterVisible.value = false; - loadApiList(false); - } - - function resetStatusFilter() { - statusFilters.value = []; - statusFilterVisible.value = false; - loadApiList(false); - } - /** * 处理文件夹树节点选中事件 */ @@ -1013,6 +947,17 @@ console.log(error); } } + + const apiTableRef = ref(); + watch( + () => props.protocol, + (val) => { + if (val) { + initFilterColumn(); + apiTableRef.value.initColumn(columns); + } + } + ); diff --git a/frontend/src/views/test-plan/testPlan/detail/featureCase/detail/index.vue b/frontend/src/views/test-plan/testPlan/detail/featureCase/detail/index.vue index 10560e30e7..3d76b01c31 100644 --- a/frontend/src/views/test-plan/testPlan/detail/featureCase/detail/index.vue +++ b/frontend/src/views/test-plan/testPlan/detail/featureCase/detail/index.vue @@ -37,7 +37,7 @@ > {{ item.num }} - + {{ item.name }} @@ -120,9 +120,12 @@ /> - - - + + @@ -145,9 +148,9 @@ import ExecuteSubmit from './executeSubmit.vue'; import CaseTabDetail from '@/views/case-management/caseManagementFeature/components/tabContent/tabDetail.vue'; import EditCaseDetailDrawer from '@/views/case-management/caseReview/components/editCaseDetailDrawer.vue'; + import ExecutionHistory from '@/views/test-plan/testPlan/detail/featureCase/detail/executionHistory/index.vue'; import { getCaseDetail } from '@/api/modules/case-management/featureCase'; - // import ExecutionHistory from '@/views/test-plan/testPlan/detail/featureCase/detail/executionHistory/index.vue'; import { getPlanDetailFeatureCaseList, getTestPlanDetail } from '@/api/modules/test-plan/testPlan'; import { testPlanDefaultDetail } from '@/config/testPlan'; import { useI18n } from '@/hooks/useI18n';