mirror of
https://gitee.com/fit2cloud-feizhiyun/MeterSphere.git
synced 2024-11-30 11:08:38 +08:00
feat(测试计划): 测试计划详情用例关联缺陷联调
This commit is contained in:
parent
11fe18e5d0
commit
e759d15c15
@ -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 });
|
||||
}
|
||||
|
@ -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';
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -382,6 +382,13 @@ export default function useTableProps<T>(
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props?.showSelectorAll,
|
||||
(val) => {
|
||||
propsRes.value.showSelectorAll = val;
|
||||
}
|
||||
);
|
||||
|
||||
// 事件触发组
|
||||
const propsEvent = ref({
|
||||
// 排序触发
|
||||
|
@ -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 {};
|
||||
|
@ -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 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],
|
||||
{
|
||||
scroll: { x: '100%' },
|
||||
columns,
|
||||
tableKey: TableKeyEnum.CASE_MANAGEMENT_TAB_DEFECT,
|
||||
selectable: true,
|
||||
showSelectorAll: props.showSelectorAll,
|
||||
heightUsed: 340,
|
||||
},
|
||||
totalCaseProps.value,
|
||||
(record) => {
|
||||
return {
|
||||
...record,
|
||||
@ -174,26 +183,25 @@
|
||||
}
|
||||
);
|
||||
|
||||
const getSingleBugTable = useTable(
|
||||
getModuleTreeApiMap[props.loadApi],
|
||||
{
|
||||
scroll: { x: '100%' },
|
||||
columns,
|
||||
tableKey: TableKeyEnum.CASE_MANAGEMENT_TAB_DEFECT,
|
||||
selectable: true,
|
||||
showSelectorAll: props.showSelectorAll,
|
||||
heightUsed: 340,
|
||||
const getSingleBugTable = useTable(getModuleTreeApiMap[props.loadApi], totalCaseProps.value, (record) => {
|
||||
return {
|
||||
...record,
|
||||
tags: (record.tags || []).map((item: string, i: number) => {
|
||||
return {
|
||||
id: `${record.id}-${i}`,
|
||||
name: item,
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.showSelectorAll,
|
||||
(val) => {
|
||||
totalCaseProps.value.showSelectorAll = val;
|
||||
},
|
||||
(record) => {
|
||||
return {
|
||||
...record,
|
||||
tags: (record.tags || []).map((item: string, i: number) => {
|
||||
return {
|
||||
id: `${record.id}-${i}`,
|
||||
name: item,
|
||||
};
|
||||
}),
|
||||
};
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -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;
|
||||
showLinkBugDrawer.value = true;
|
||||
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;
|
||||
|
@ -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;
|
||||
showLinkBugDrawer.value = true;
|
||||
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;
|
||||
|
@ -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',
|
||||
|
@ -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,24 +847,24 @@
|
||||
|
||||
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) {
|
||||
associatedCaseId.value = caseId;
|
||||
showCreateBugDrawer.value = true;
|
||||
|
||||
// 关联/关联缺陷
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 批量修改执行人 和 批量移动
|
||||
@ -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;
|
||||
|
@ -597,4 +597,14 @@
|
||||
:deep(.arco-tabs-content) {
|
||||
@apply hidden;
|
||||
}
|
||||
:deep(.arco-table-tr) {
|
||||
.operation-button {
|
||||
opacity: 0;
|
||||
}
|
||||
&:hover {
|
||||
.operation-button {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
Loading…
Reference in New Issue
Block a user