feat(测试计划): 测试计划详情用例关联缺陷联调

This commit is contained in:
xinxin.wu 2024-08-30 11:37:16 +08:00 committed by Craftsman
parent 11fe18e5d0
commit e759d15c15
12 changed files with 372 additions and 105 deletions

View File

@ -7,7 +7,11 @@ import {
ApiScenarioReportDetailStepUrl,
ApiScenarioReportDetailUrl,
archivedPlanUrl,
AssociatedBugToApiCaseUrl,
AssociatedBugToScenarioCaseUrl,
BatchAddBugToCaseUrl,
batchArchivedPlanUrl,
BatchAssociatedBugToCaseUrl,
batchCopyPlanUrl,
batchDeletePlanUrl,
BatchDisassociateApiCaseUrl,
@ -23,6 +27,8 @@ import {
BatchRunApiScenarioUrl,
BatchRunCaseUrl,
BatchUpdateCaseExecutorUrl,
CancelBugFromApiCaseUrl,
CancelBugFromScenarioCaseUrl,
ConfigScheduleUrl,
copyTestPlanUrl,
deletePlanUrl,
@ -56,7 +62,9 @@ import {
GetTestPlanModuleCountUrl,
GetTestPlanModuleUrl,
GetTestPlanUsersUrl,
GetUnAssociatedApiBugUrl,
GetUnAssociatedListUrl,
GetUnAssociatedScenarioBugUrl,
MoveTestPlanModuleUrl,
planDetailBugPageUrl,
PlanDetailExecuteHistoryUrl,
@ -439,7 +447,39 @@ export function testPlanAssociateModuleCount(data: TableQueryParams) {
export function getExecuteUserOption(projectId: string, keyword?: string) {
return MSR.get({ url: `${GetTestPlanExecutorOptionsUrl}/${projectId}`, params: { keyword } });
}
// 获取测试计划未关联抽屉缺陷列表
// 获取测试计划-功能用例-未关联抽屉缺陷列表
export function getTestPlanBugPage(data: TableQueryParams) {
return MSR.post<CommonList<CaseManagementTable>>({ url: GetUnAssociatedListUrl, data });
}
// 获取测试计划-接口用例-未关联抽屉缺陷列表
export function getTestPlanApiBugPage(data: TableQueryParams) {
return MSR.post<CommonList<CaseManagementTable>>({ url: GetUnAssociatedApiBugUrl, data });
}
// 获取测试计划-接口用例-未关联抽屉缺陷列表
export function getTestPlanScenarioBugPage(data: TableQueryParams) {
return MSR.post<CommonList<CaseManagementTable>>({ url: GetUnAssociatedScenarioBugUrl, data });
}
// 测试计划-用例详情-关联缺陷
export function associateBugToApiCase(data: TableQueryParams) {
return MSR.post({ url: AssociatedBugToApiCaseUrl, data });
}
// 测试计划-用例详情-关联缺陷
export function associateBugToScenarioCase(data: TableQueryParams) {
return MSR.post({ url: AssociatedBugToScenarioCaseUrl, data });
}
// 测试计划-接口用例-取消关联联缺陷
export function cancelBugFromApiCase(id: string) {
return MSR.get({ url: `${CancelBugFromApiCaseUrl}/${id}` });
}
// 测试计划-场景用例-取消关联联缺陷
export function cancelBugFromScenarioCase(id: string) {
return MSR.get({ url: `${CancelBugFromScenarioCaseUrl}/${id}` });
}
// 测试计划-详情-批量关联缺陷
export function batchAssociatedBugToCase(data: TableQueryParams) {
return MSR.post({ url: BatchAssociatedBugToCaseUrl, data });
}
// 测试计划-详情-批量新建缺陷
export function batchAddBugToCase(data: TableQueryParams) {
return MSR.post({ url: BatchAddBugToCaseUrl, data });
}

View File

@ -157,3 +157,19 @@ export const TestPlanAssociationUrl = '/test-plan/association/api/case/module/co
export const GetTestPlanExecutorOptionsUrl = '/test-plan-execute/user-option';
// 获取测试计划未关联缺陷列表
export const GetUnAssociatedListUrl = '/test-plan/functional/case/associate/bug/page';
// 获取测试计划未关联缺陷列表
export const GetUnAssociatedApiBugUrl = '/test-plan/api/case/associate/bug/page';
// 获取测试计划未关联缺陷列表
export const GetUnAssociatedScenarioBugUrl = '/test-plan/api/scenario/associate/bug/page';
// 测试计划-接口用例-单个用例关联缺陷
export const AssociatedBugToApiCaseUrl = '/test-plan/api/case/associate/bug';
// 测试计划-场景用例-单个用例关联缺陷
export const AssociatedBugToScenarioCaseUrl = '/test-plan/api/scenario/associate/bug';
// 测试计划-接口用例-取消关联联缺陷
export const CancelBugFromApiCaseUrl = '/test-plan/api/case/disassociate/bug';
// 测试计划-场景用例-取消关联联缺陷
export const CancelBugFromScenarioCaseUrl = '/test-plan/api/scenario/disassociate/bug';
// 测试计划-详情-用例列表-批量关联缺陷
export const BatchAssociatedBugToCaseUrl = '/test-plan/functional/case/batch/associate-bug';
// 测试计划-详情-用例列表-批量新建缺陷
export const BatchAddBugToCaseUrl = '/test-plan/functional/case/batch/add-bug';

View File

@ -23,16 +23,18 @@
import type { MsTableColumn, MsTableProps } from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable';
import { testPlanCancelBug } from '@/api/modules/test-plan/testPlan';
import { cancelBugFromApiCase, cancelBugFromScenarioCase, testPlanCancelBug } from '@/api/modules/test-plan/testPlan';
import { useI18n } from '@/hooks/useI18n';
import type { CaseBugItem } from '@/models/testPlan/testPlan';
import { CaseLinkEnum } from '@/enums/caseEnum';
import { TableKeyEnum } from '@/enums/tableEnum';
const props = defineProps<{
bugList?: CaseBugItem[]; //
canEdit: boolean;
bugCount: number;
caseType: CaseLinkEnum;
}>();
const emit = defineEmits<{
@ -85,11 +87,17 @@
propsRes.value.data = props.bugList || [];
});
const cancelBugMap: Record<string, (id: string) => Promise<any>> = {
FUNCTIONAL: testPlanCancelBug,
API: cancelBugFromApiCase,
SCENARIO: cancelBugFromScenarioCase,
};
//
async function cancelLink(id: string) {
try {
setLoading(true);
await testPlanCancelBug(id);
await cancelBugMap[props.caseType](id);
Message.success(t('common.unLinkSuccess'));
emit('loadList');
} catch (error) {

View File

@ -1,14 +1,21 @@
<template>
<div class="flex items-center">
<BugCountPopover :bug-list="bugList || []" :bug-count="bugCount" :can-edit="props.canEdit" @load-list="loadList" />
<div class="flex items-center" @click="selectedStyle">
<BugCountPopover
:case-type="props.caseType"
:bug-list="bugList || []"
:bug-count="bugCount"
:can-edit="props.canEdit"
@load-list="loadList"
/>
<a-dropdown
v-if="hasAllPermission(['PROJECT_BUG:READ', ...(props.linkBugPermission || [])])"
position="bl"
@select="handleSelect"
@popup-visible-change="popupVisibleChange"
>
<a-button
v-permission="['PROJECT_BUG:READ+ADD']"
class="arco-btn-outline--secondary ml-[8px] !p-[4px]"
:class="`${isSelected ? 'selected-class' : 'operation-button'} arco-btn-outline--secondary ml-[8px] !p-[4px]`"
type="outline"
size="small"
>
@ -34,6 +41,7 @@
import { hasAllPermission, hasAnyPermission } from '@/utils/permission';
import type { CaseBugItem } from '@/models/testPlan/testPlan';
import { CaseLinkEnum } from '@/enums/caseEnum';
const { t } = useI18n();
@ -41,6 +49,7 @@
resourceId: string; // id: id/id/id
bugCount: number; //
existedDefect: number; //
caseType: CaseLinkEnum; //
canEdit: boolean;
bugList?: CaseBugItem[];
linkBugPermission?: string[];
@ -63,6 +72,17 @@
}
}
const isSelected = ref<boolean>(false);
function selectedStyle() {
isSelected.value = true;
}
function popupVisibleChange(val: boolean) {
if (!val) {
isSelected.value = false;
}
}
function loadList() {
emit('loadList');
}
@ -70,7 +90,11 @@
<style scoped lang="less">
:deep(.arco-btn-outline--secondary) {
&:hover {
border-color: var(--color-text-n8) !important;
}
.selected-class {
opacity: 1;
&.arco-btn-outline--secondary {
border-color: rgb(var(--primary-5)) !important;
}
}

View File

@ -382,6 +382,13 @@ export default function useTableProps<T>(
}
);
watch(
() => props?.showSelectorAll,
(val) => {
propsRes.value.showSelectorAll = val;
}
);
// 事件触发组
const propsEvent = ref({
// 排序触发

View File

@ -2,6 +2,8 @@ export enum AssociatedBugApiTypeEnum {
FUNCTIONAL_BUG_LIST = 'FUNCTIONAL_BUG_LIST', // 功能用例关联缺陷
TEST_PLAN_BUG_LIST = 'TEST_PLAN_BUG_LIST', // 测试计划关联缺陷
BUG_TOTAL_LIST = 'BUG_TOTAL_LIST', // 批量关联总缺陷列表
API_BUG_LIST = 'API_BUG_LIST', // 接口用例缺陷列表
SCENARIO_BUG_LIST = 'SCENARIO_BUG_LIST', // 场景用例缺陷列表
}
export default {};

View File

@ -48,16 +48,21 @@
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import type { MsTableColumn } from '@/components/pure/ms-table/type';
import type { MsTableColumn, MsTableProps } from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable';
import BugNamePopover from '@/views/case-management/caseManagementFeature/components/tabContent/tabBug/bugNamePopover.vue';
import { getBugList } from '@/api/modules/bug-management';
import { getDrawerDebugPage } from '@/api/modules/case-management/featureCase';
import { getTestPlanBugPage } from '@/api/modules/test-plan/testPlan';
import {
getTestPlanApiBugPage,
getTestPlanBugPage,
getTestPlanScenarioBugPage,
} from '@/api/modules/test-plan/testPlan';
import { useI18n } from '@/hooks/useI18n';
import { useAppStore } from '@/store';
import { BugListItem } from '@/models/bug-management';
import { AssociatedBugApiTypeEnum } from '@/enums/associateBugEnum';
import { TableKeyEnum } from '@/enums/tableEnum';
@ -67,9 +72,11 @@
const appStore = useAppStore();
const getModuleTreeApiMap: Record<string, any> = {
[AssociatedBugApiTypeEnum.FUNCTIONAL_BUG_LIST]: getDrawerDebugPage, // -
[AssociatedBugApiTypeEnum.TEST_PLAN_BUG_LIST]: getTestPlanBugPage, // -
[AssociatedBugApiTypeEnum.FUNCTIONAL_BUG_LIST]: getDrawerDebugPage, // --
[AssociatedBugApiTypeEnum.TEST_PLAN_BUG_LIST]: getTestPlanBugPage, // --
[AssociatedBugApiTypeEnum.BUG_TOTAL_LIST]: getBugList, //
[AssociatedBugApiTypeEnum.API_BUG_LIST]: getTestPlanApiBugPage, // -
[AssociatedBugApiTypeEnum.SCENARIO_BUG_LIST]: getTestPlanScenarioBugPage, // -
};
const currentProjectId = computed(() => appStore.currentProjectId);
@ -151,16 +158,18 @@
},
];
const getTotalBugTable = useTable(
getModuleTreeApiMap[AssociatedBugApiTypeEnum.BUG_TOTAL_LIST],
{
const totalCaseProps = ref<Partial<MsTableProps<BugListItem>>>({
scroll: { x: '100%' },
columns,
tableKey: TableKeyEnum.CASE_MANAGEMENT_TAB_DEFECT,
selectable: true,
showSelectorAll: props.showSelectorAll,
heightUsed: 340,
},
});
const getTotalBugTable = useTable(
getModuleTreeApiMap[AssociatedBugApiTypeEnum.BUG_TOTAL_LIST],
totalCaseProps.value,
(record) => {
return {
...record,
@ -174,17 +183,7 @@
}
);
const getSingleBugTable = useTable(
getModuleTreeApiMap[props.loadApi],
{
scroll: { x: '100%' },
columns,
tableKey: TableKeyEnum.CASE_MANAGEMENT_TAB_DEFECT,
selectable: true,
showSelectorAll: props.showSelectorAll,
heightUsed: 340,
},
(record) => {
const getSingleBugTable = useTable(getModuleTreeApiMap[props.loadApi], totalCaseProps.value, (record) => {
return {
...record,
tags: (record.tags || []).map((item: string, i: number) => {
@ -194,6 +193,15 @@
};
}),
};
});
watch(
() => props.showSelectorAll,
(val) => {
totalCaseProps.value.showSelectorAll = val;
},
{
immediate: true,
}
);

View File

@ -39,14 +39,15 @@
</template>
<template #bugCount="{ record }">
<MsBugOperation
:case-type="CaseLinkEnum.API"
:can-edit="props.canEdit"
:bug-list="record.bugList"
:resource-id="record.id"
:bug-count="record.bugCount || 0"
:existed-defect="existedDefect"
@load-list="loadList"
@associated="associatedDefect(false, record.id)"
@create="newDefect(record.id)"
@load-list="refreshDetailAndList()"
@associated="associateAndCreateDefect(true, false, record)"
@create="associateAndCreateDefect(false, false, record)"
/>
</template>
<template #[FilterSlotNameEnum.API_TEST_CASE_API_LAST_EXECUTE_STATUS]="{ filterContent }">
@ -109,14 +110,20 @@
@load-list="resetCaseList"
/>
<!-- TODO 等待联调 -->
<AddDefectDrawer v-model:visible="showCreateBugDrawer" :extra-params="{ caseId: associatedCaseId }" />
<AddDefectDrawer
v-model:visible="showCreateBugDrawer"
:extra-params="{ caseId: associatedCaseId, testPlanId: props.planId, testPlanCaseId }"
@success="refreshDetailAndList()"
/>
<!-- TODO 等待联调 -->
<LinkDefectDrawer
v-model:visible="showLinkBugDrawer"
:case-id="associatedCaseId"
:load-api="AssociatedBugApiTypeEnum.TEST_PLAN_BUG_LIST"
:case-id="testPlanCaseId"
:load-api="AssociatedBugApiTypeEnum.API_BUG_LIST"
:is-batch="isBatchAssociate"
:drawer-loading="drawerLoading"
:show-selector-all="!isBatchAssociate"
@save="saveApiBugHandler"
/>
</div>
</template>
@ -147,6 +154,8 @@
import BatchApiMoveModal from '@/views/test-plan/testPlan/components/batchApiMoveModal.vue';
import {
associateBugToApiCase,
batchAssociatedBugToCase,
batchDisassociateApiCase,
batchMoveApiCase,
batchRunApiCase,
@ -165,9 +174,10 @@
import { characterLimit } from '@/utils';
import { hasAllPermission, hasAnyPermission } from '@/utils/permission';
import { DragSortParams, ModuleTreeNode } from '@/models/common';
import { DragSortParams, ModuleTreeNode, TableQueryParams } from '@/models/common';
import type { PlanDetailApiCaseItem, PlanDetailApiCaseQueryParams } from '@/models/testPlan/testPlan';
import { AssociatedBugApiTypeEnum } from '@/enums/associateBugEnum';
import { CaseLinkEnum } from '@/enums/caseEnum';
import { ReportEnum } from '@/enums/reportEnum';
import { ApiTestRouteEnum } from '@/enums/routeEnum';
import { TableKeyEnum } from '@/enums/tableEnum';
@ -547,6 +557,11 @@
loadList();
}
function refreshDetailAndList() {
emit('refresh');
loadCaseList();
}
//
async function handleDragChange(params: DragSortParams) {
try {
@ -654,24 +669,61 @@
const showLinkBugDrawer = ref(false);
const associatedCaseId = ref<string>();
const testPlanCaseId = ref<string>();
const existedDefect = inject<Ref<number>>('existedDefect', ref(0));
const showCreateBugDrawer = ref<boolean>(false);
const isBatchAssociate = ref(false);
//
function associatedDefect(isBatch: boolean, caseId?: string) {
function associateAndCreateDefect(isAssociate: boolean, isBatch: boolean, record?: PlanDetailApiCaseItem) {
isBatchAssociate.value = isBatch;
associatedCaseId.value = caseId;
if (record) {
const { id, apiTestCaseId } = record;
associatedCaseId.value = apiTestCaseId;
testPlanCaseId.value = id;
}
if (isAssociate) {
showLinkBugDrawer.value = true;
} else {
showCreateBugDrawer.value = true;
}
}
const drawerLoading = ref(false);
const showCreateBugDrawer = ref<boolean>(false);
//
async function saveApiBugHandler(params: TableQueryParams) {
try {
drawerLoading.value = true;
const tableParams = await getTableParams(true);
if (isBatchAssociate.value) {
await batchAssociatedBugToCase({
selectIds: tableSelected.value as string[],
selectAll: batchParams.value.selectAll,
excludeIds: batchParams.value?.excludeIds || [],
...tableParams,
bugIds: params.selectIds,
projectId: appStore.currentProjectId,
});
} else {
await associateBugToApiCase({
...params,
caseId: associatedCaseId.value,
testPlanId: props.planId,
testPlanCaseId: testPlanCaseId.value,
projectId: appStore.currentProjectId,
});
}
//
function newDefect(caseId?: string) {
associatedCaseId.value = caseId;
showCreateBugDrawer.value = true;
Message.success(t('caseManagement.featureCase.associatedSuccess'));
showLinkBugDrawer.value = false;
resetSelectorAndCaseList();
emit('refresh');
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
drawerLoading.value = false;
}
}
//
@ -700,10 +752,10 @@
batchMoveModalVisible.value = true;
break;
case 'linkDefect':
associatedDefect(true);
associateAndCreateDefect(true, true);
break;
case 'newBug':
newDefect();
associateAndCreateDefect(false, true);
break;
default:
break;

View File

@ -51,14 +51,15 @@
</template>
<template #bugCount="{ record }">
<MsBugOperation
:case-type="CaseLinkEnum.SCENARIO"
:can-edit="props.canEdit"
:bug-list="record.bugList"
:resource-id="record.id"
:bug-count="record.bugCount || 0"
:existed-defect="existedDefect"
@load-list="loadList"
@associated="associatedDefect(false, record.id)"
@create="newDefect(record.id)"
@load-list="refreshListAndDetail()"
@associated="associateAndCreateDefect(true, false, record)"
@create="associateAndCreateDefect(false, false, record)"
/>
</template>
<template v-if="props.canEdit" #operation="{ record }">
@ -109,14 +110,20 @@
/>
<!-- TODO 等待联调 -->
<AddDefectDrawer v-model:visible="showCreateBugDrawer" :extra-params="{ caseId: associatedCaseId }" />
<AddDefectDrawer
v-model:visible="showCreateBugDrawer"
:extra-params="{ caseId: associatedCaseId, testPlanId: props.planId, testPlanCaseId }"
@success="refreshListAndDetail()"
/>
<!-- TODO 等待联调 -->
<LinkDefectDrawer
v-model:visible="showLinkBugDrawer"
:case-id="associatedCaseId"
:load-api="AssociatedBugApiTypeEnum.TEST_PLAN_BUG_LIST"
:case-id="testPlanCaseId"
:load-api="AssociatedBugApiTypeEnum.SCENARIO_BUG_LIST"
:is-batch="isBatchAssociate"
:drawer-loading="drawerLoading"
:show-selector-all="!isBatchAssociate"
@save="saveScenarioBugHandler"
/>
</div>
</template>
@ -146,6 +153,8 @@
import BatchApiMoveModal from '@/views/test-plan/testPlan/components/batchApiMoveModal.vue';
import {
associateBugToScenarioCase,
batchAssociatedBugToCase,
batchDisassociateApiScenario,
batchMoveApiScenario,
batchRunApiScenario,
@ -164,9 +173,10 @@
import { characterLimit } from '@/utils';
import { hasAllPermission, hasAnyPermission } from '@/utils/permission';
import { DragSortParams, ModuleTreeNode } from '@/models/common';
import { DragSortParams, ModuleTreeNode, TableQueryParams } from '@/models/common';
import type { PlanDetailApiScenarioItem, PlanDetailApiScenarioQueryParams } from '@/models/testPlan/testPlan';
import { AssociatedBugApiTypeEnum } from '@/enums/associateBugEnum';
import { CaseLinkEnum } from '@/enums/caseEnum';
import { ReportEnum } from '@/enums/reportEnum';
import { ApiTestRouteEnum } from '@/enums/routeEnum';
import { TableKeyEnum } from '@/enums/tableEnum';
@ -489,6 +499,11 @@
loadCaseList();
}
function refreshListAndDetail() {
loadCaseList();
emit('refresh');
}
async function getModuleCount() {
const tableParams = await getTableParams(false);
emit('getModuleCount', {
@ -645,19 +660,59 @@
const isBatchAssociate = ref(false);
const showLinkBugDrawer = ref<boolean>(false);
const associatedCaseId = ref<string>();
const testPlanCaseId = ref<string>();
const showCreateBugDrawer = ref<boolean>(false);
const drawerLoading = ref<boolean>(false);
//
function associatedDefect(isBatch: boolean, caseId?: string) {
function associateAndCreateDefect(isAssociate: boolean, isBatch: boolean, record?: PlanDetailApiScenarioItem) {
isBatchAssociate.value = isBatch;
associatedCaseId.value = caseId;
if (record) {
const { id, apiScenarioId } = record;
associatedCaseId.value = apiScenarioId;
testPlanCaseId.value = id;
}
if (isAssociate) {
showLinkBugDrawer.value = true;
} else {
showCreateBugDrawer.value = true;
}
}
const showCreateBugDrawer = ref<boolean>(false);
//
function newDefect(caseId?: string) {
associatedCaseId.value = caseId;
showCreateBugDrawer.value = true;
//
async function saveScenarioBugHandler(params: TableQueryParams) {
try {
drawerLoading.value = true;
const tableParams = await getTableParams(true);
if (isBatchAssociate.value) {
await batchAssociatedBugToCase({
selectIds: tableSelected.value as string[],
selectAll: batchParams.value.selectAll,
excludeIds: batchParams.value?.excludeIds || [],
...tableParams,
bugIds: params.selectIds,
projectId: appStore.currentProjectId,
});
} else {
await associateBugToScenarioCase({
...params,
caseId: associatedCaseId.value,
testPlanId: props.planId,
testPlanCaseId: testPlanCaseId.value,
projectId: appStore.currentProjectId,
});
}
Message.success(t('caseManagement.featureCase.associatedSuccess'));
showLinkBugDrawer.value = false;
resetSelectorAndCaseList();
emit('refresh');
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
drawerLoading.value = false;
}
}
//
@ -682,10 +737,10 @@
batchMoveModalVisible.value = true;
break;
case 'linkDefect':
associatedDefect(true);
associateAndCreateDefect(true, true);
break;
case 'newBug':
newDefect();
associateAndCreateDefect(false, true);
break;
default:
break;

View File

@ -1,14 +1,17 @@
<template>
<a-popover position="br" content-class="case-count-popover" @popup-visible-change="popupChange">
<div class="one-line-text cursor-pointer px-0 text-[rgb(var(--primary-5))]">{{
props.bugItem.relateCases?.length ?? 0
}}</div>
<div class="one-line-text cursor-pointer px-0 text-[rgb(var(--primary-5))]">
{{ props.bugItem.relateCases?.length ?? 0 }}
</div>
<template #content>
<div class="w-[500px]">
<MsBaseTable v-bind="propsRes" v-on="propsEvent">
<template #num="{ record }">
<MsButton size="mini" type="text" @click="goCaseDetail(record.id)">{{ record.num }}</MsButton>
</template>
<template #type="{ record }">
<span>{{ getCaseType(record.type) || '-' }}</span>
</template>
</MsBaseTable>
</div>
</template>
@ -21,9 +24,11 @@
import type { MsTableColumn } from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable';
import { useI18n } from '@/hooks/useI18n';
import useOpenNewPage from '@/hooks/useOpenNewPage';
import type { PlanDetailBugItem } from '@/models/testPlan/testPlan';
import { CaseLinkEnum } from '@/enums/caseEnum';
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
import { TableKeyEnum } from '@/enums/tableEnum';
@ -32,6 +37,7 @@
}>();
const { openNewPage } = useOpenNewPage();
const { t } = useI18n();
const columns: MsTableColumn = [
{
@ -50,11 +56,25 @@
{
title: 'testPlan.caseType',
dataIndex: 'type',
slotName: 'type',
showTooltip: true,
width: 200,
},
];
function getCaseType(type: CaseLinkEnum) {
switch (type) {
case CaseLinkEnum.API:
return t('testPlan.testPlanIndex.apiCase');
case CaseLinkEnum.FUNCTIONAL:
return t('testPlan.testPlanIndex.functionalUseCase');
case CaseLinkEnum.SCENARIO:
return t('testPlan.testPlanIndex.apiScenarioCase');
default:
break;
}
}
const { propsRes, propsEvent } = useTable(undefined, {
columns,
size: 'mini',

View File

@ -80,14 +80,15 @@
</template>
<template #bugCount="{ record }">
<MsBugOperation
:case-type="CaseLinkEnum.FUNCTIONAL"
:can-edit="props.canEdit"
:bug-list="record.bugList"
:resource-id="record.id"
:bug-count="record.bugCount || 0"
:existed-defect="existedDefect"
@load-list="loadList"
@associated="associatedDefect(false, record.id)"
@create="newDefect(record.id)"
@load-list="refreshList()"
@associated="associateAndCreateDefect(true, false, record)"
@create="associateAndCreateDefect(false, false, record)"
/>
</template>
<template v-if="props.canEdit" #operation="{ record }">
@ -177,17 +178,18 @@
<!-- TODO 等待联调 -->
<AddDefectDrawer
v-model:visible="showCreateBugDrawer"
:extra-params="{ caseId: associatedCaseId }"
@success="refreshList"
:extra-params="{ caseId: associatedCaseId, testPlanId: props.planId, testPlanCaseId }"
@success="refreshList()"
/>
<!-- TODO 等待联调 -->
<LinkDefectDrawer
v-model:visible="showLinkBugDrawer"
:case-id="associatedCaseId"
:case-id="testPlanCaseId"
:drawer-loading="drawerLoading"
:load-api="AssociatedBugApiTypeEnum.TEST_PLAN_BUG_LIST"
:show-selector-all="!isBatchAssociate"
:is-batch="isBatchAssociate"
@save="saveHandler"
@save="saveFunctionBugHandler"
/>
</div>
</template>
@ -222,6 +224,8 @@
import ExecuteForm from '@/views/test-plan/testPlan/detail/featureCase/components/executeForm.vue';
import {
associateBugToPlan,
batchAssociatedBugToCase,
batchDisassociateCase,
batchExecuteCase,
batchMoveFeatureCase,
@ -243,7 +247,7 @@
import { DragSortParams, ModuleTreeNode, TableQueryParams } from '@/models/common';
import type { ExecuteFeatureCaseFormParams, PlanDetailFeatureCaseItem } from '@/models/testPlan/testPlan';
import { AssociatedBugApiTypeEnum } from '@/enums/associateBugEnum';
import { LastExecuteResults } from '@/enums/caseEnum';
import { CaseLinkEnum, LastExecuteResults } from '@/enums/caseEnum';
import { TestPlanRouteEnum } from '@/enums/routeEnum';
import { TableKeyEnum } from '@/enums/tableEnum';
import { FilterRemoteMethodsEnum, FilterSlotNameEnum } from '@/enums/tableFilterEnum';
@ -801,17 +805,38 @@
const showLinkBugDrawer = ref<boolean>(false);
const associatedCaseId = ref<string>();
const testPlanCaseId = ref<string>();
const drawerLoading = ref<boolean>(false);
const isBatchAssociate = ref(false);
// TODO
function saveHandler(params: TableQueryParams) {
//
async function saveFunctionBugHandler(params: TableQueryParams) {
try {
drawerLoading.value = true;
const tableParams = await getTableParams(true);
if (isBatchAssociate.value) {
await batchAssociatedBugToCase({
selectIds: tableSelected.value as string[],
selectAll: batchParams.value.selectAll,
excludeIds: batchParams.value?.excludeIds || [],
...tableParams,
projectId: appStore.currentProjectId,
bugIds: params.selectIds,
});
} else {
await associateBugToPlan({
...params,
projectId: appStore.currentProjectId,
caseId: associatedCaseId.value,
testPlanId: props.planId,
testPlanCaseId: testPlanCaseId.value,
});
}
Message.success(t('caseManagement.featureCase.associatedSuccess'));
resetCaseList();
initModules();
emit('refresh');
showLinkBugDrawer.value = false;
resetCaseList();
emit('refresh');
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
@ -822,25 +847,25 @@
function refreshList() {
resetCaseList();
initModules();
emit('refresh');
}
const isBatchAssociate = ref(false);
//
function associatedDefect(isBatch: boolean, caseId?: string) {
isBatchAssociate.value = isBatch;
associatedCaseId.value = caseId;
showLinkBugDrawer.value = true;
}
const showCreateBugDrawer = ref<boolean>(false);
//
function newDefect(caseId?: string) {
// /
function associateAndCreateDefect(isAssociate: boolean, isBatch: boolean, record?: PlanDetailFeatureCaseItem) {
isBatchAssociate.value = isBatch;
if (record) {
const { id, caseId } = record;
associatedCaseId.value = caseId;
testPlanCaseId.value = id;
}
if (isAssociate) {
showLinkBugDrawer.value = true;
} else {
showCreateBugDrawer.value = true;
}
}
//
const batchUpdateExecutorModalVisible = ref(false);
@ -861,10 +886,10 @@
batchMoveModalVisible.value = true;
break;
case 'linkDefect':
associatedDefect(true);
associateAndCreateDefect(true, true);
break;
case 'newBug':
newDefect();
associateAndCreateDefect(false, true);
break;
default:
break;

View File

@ -597,4 +597,14 @@
:deep(.arco-tabs-content) {
@apply hidden;
}
:deep(.arco-table-tr) {
.operation-button {
opacity: 0;
}
&:hover {
.operation-button {
opacity: 1;
}
}
}
</style>