feat(测试计划): 测试计划详情-功能用例列表-复制和排序

This commit is contained in:
teukkk 2024-05-16 16:58:52 +08:00 committed by 刘瑞斌
parent bc4fed9553
commit c170455ed5
8 changed files with 101 additions and 29 deletions

View File

@ -28,6 +28,7 @@ import {
planDetailBugPageUrl,
planPassRateUrl,
RunFeatureCaseUrl,
SortFeatureCaseUrl,
updateTestPlanModuleUrl,
UpdateTestPlanUrl,
} from '@/api/requrls/test-plan/testPlan';
@ -48,6 +49,7 @@ import type {
PlanDetailFeatureCaseItem,
PlanDetailFeatureCaseListQueryParams,
RunFeatureCaseParams,
SortFeatureCaseParams,
TestPlanDetail,
TestPlanItem,
UseCountType,
@ -166,6 +168,10 @@ export function getFeatureCaseModule(planId: string) {
export function disassociateCase(data: DisassociateCaseParams) {
return MSR.post({ url: DisassociateCaseUrl, data });
}
// 计划详情-功能用例列表-拖拽排序
export const sortFeatureCase = (data: SortFeatureCaseParams) => {
return MSR.post({ url: SortFeatureCaseUrl, data });
};
// 计划详情-功能用例列表-批量取消关联用例
export function batchDisassociateCase(data: BatchFeatureCaseParams) {
return MSR.post({ url: BatchDisassociateCaseUrl, data });

View File

@ -48,6 +48,8 @@ export const GetPlanDetailFeatureCaseListUrl = '/test-plan/functional/case/page'
export const GetFeatureCaseModuleCountUrl = '/test-plan/functional/case/module/count';
// 计划详情-功能用例模块树
export const GetFeatureCaseModuleUrl = '/test-plan/functional/case/tree';
// 计划详情-功能用例列表-拖拽排序
export const SortFeatureCaseUrl = '/test-plan/functional/case/sort';
// 计划详情-功能用例-取消关联用例
export const DisassociateCaseUrl = '/test-plan/functional/case/disassociate';
// 计划详情-功能用例-批量取消关联用例

View File

@ -180,4 +180,5 @@ export default {
'common.responsiblePerson': 'Responsible person',
'common.updateUserName': 'Update user name',
'common.updateTime': 'Update time',
'common.belongProject': 'Belong to Project',
};

View File

@ -183,4 +183,5 @@ export default {
'common.responsiblePerson': '责任人',
'common.updateUserName': '更新人',
'common.updateTime': '更新时间',
'common.belongProject': '所属项目',
};

View File

@ -2,10 +2,9 @@ import type { BatchActionQueryParams } from '@/components/pure/ms-table/type';
import type { customFieldsItem } from '@/models/caseManagement/featureCase';
import type { TableQueryParams } from '@/models/common';
import { BatchApiParams, DragSortParams } from '@/models/common';
import { LastExecuteResults } from '@/enums/caseEnum';
import { BatchApiParams } from '../common';
export type planStatusType = 'PREPARED' | 'UNDERWAY' | 'COMPLETED' | 'ARCHIVED';
export interface AssociateFunctionalCaseItem {
@ -188,6 +187,10 @@ export interface BatchUpdateCaseExecutorParams extends BatchFeatureCaseParams {
userId: string;
}
export interface SortFeatureCaseParams extends DragSortParams {
testPlanId: string;
}
export interface PassRateCountDetail {
id: string;
passThreshold: number;

View File

@ -16,7 +16,13 @@
</template>
</a-button>
</div>
<MsBaseTable v-bind="propsRes" :action-config="batchActions" v-on="propsEvent" @batch-action="handleTableBatch">
<MsBaseTable
v-bind="propsRes"
:action-config="batchActions"
v-on="propsEvent"
@batch-action="handleTableBatch"
@drag-change="handleDragChange"
>
<template #num="{ record }">
<MsButton type="text" @click="toCaseDetail(record)">{{ record.num }}</MsButton>
</template>
@ -70,11 +76,18 @@
</MsPopconfirm>
<!-- TODO: 修改permission -->
<a-divider
v-if="props.repeatCase"
v-permission="['PROJECT_API_DEFINITION_CASE:READ+EXECUTE']"
direction="vertical"
:margin="8"
></a-divider>
<MsButton v-permission="['PROJECT_API_DEFINITION_CASE:READ+ADD']" type="text" class="!mr-0">
<MsButton
v-if="props.repeatCase"
v-permission="['PROJECT_API_DEFINITION_CASE:READ+ADD']"
type="text"
class="!mr-0"
@click="handleCopyCase(record)"
>
{{ t('common.copy') }}
</MsButton>
</template>
@ -164,11 +177,13 @@
import ExecuteForm from '@/views/test-plan/testPlan/detail/featureCase/components/executeForm.vue';
import {
associationCaseToPlan,
batchDisassociateCase,
batchExecuteCase,
batchUpdateCaseExecutor,
disassociateCase,
getPlanDetailFeatureCaseList,
sortFeatureCase,
} from '@/api/modules/test-plan/testPlan';
import { defaultExecuteForm } from '@/config/testPlan';
import { useI18n } from '@/hooks/useI18n';
@ -177,7 +192,7 @@
import useAppStore from '@/store/modules/app';
import { hasAnyPermission } from '@/utils/permission';
import { ModuleTreeNode } from '@/models/common';
import { DragSortParams, ModuleTreeNode } from '@/models/common';
import type {
ExecuteFeatureCaseFormParams,
PlanDetailFeatureCaseItem,
@ -200,11 +215,12 @@
offspringIds: string[];
planId: string;
moduleTree: ModuleTreeNode[];
repeatCase: boolean;
}>();
const emit = defineEmits<{
(e: 'getModuleCount', params: PlanDetailFeatureCaseListQueryParams): void;
(e: 'executeDone'): void;
(e: 'refresh'): void;
}>();
const { t } = useI18n();
@ -283,6 +299,14 @@
width: 200,
showDrag: true,
},
{
title: 'common.belongProject',
dataIndex: 'projectName',
showTooltip: true,
showInTable: false,
showDrag: true,
width: 150,
},
{
title: 'testPlan.featureCase.bugCount',
dataIndex: 'bugCount',
@ -410,6 +434,54 @@
loadList();
}
//
async function handleDragChange(params: DragSortParams) {
try {
await sortFeatureCase({ ...params, testPlanId: props.planId });
Message.success(t('caseManagement.featureCase.sortSuccess'));
loadCaseList();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
}
//
async function handleCopyCase(record: PlanDetailFeatureCaseItem) {
try {
await associationCaseToPlan({
functionalSelectIds: [record.caseId],
testPlanId: props.planId,
});
Message.success(t('ms.case.associate.associateSuccess'));
resetCaseList();
emit('refresh');
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
}
//
const disassociateLoading = ref(false);
async function handleDisassociateCase(record: PlanDetailFeatureCaseItem, done?: () => void) {
try {
disassociateLoading.value = true;
await disassociateCase({ testPlanId: props.planId, id: record.id });
if (done) {
done();
}
Message.success(t('common.unLinkSuccess'));
resetCaseList();
emit('refresh');
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
disassociateLoading.value = false;
}
}
//
function handleBatchDisassociateCase() {
openModal({
@ -426,6 +498,7 @@
});
Message.success(t('common.updateSuccess'));
resetCaseList();
emit('refresh');
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
@ -451,7 +524,7 @@
Message.success(t('common.updateSuccess'));
resetSelector();
loadList();
emit('executeDone');
emit('refresh');
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
@ -513,25 +586,6 @@
}
}
//
const disassociateLoading = ref(false);
async function handleDisassociateCase(record: PlanDetailFeatureCaseItem, done?: () => void) {
try {
disassociateLoading.value = true;
await disassociateCase({ testPlanId: props.planId, id: record.id });
if (done) {
done();
}
Message.success(t('common.unLinkSuccess'));
resetCaseList();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
disassociateLoading.value = false;
}
}
//
function toCaseDetail(record: PlanDetailFeatureCaseItem) {
router.push({

View File

@ -14,11 +14,12 @@
<CaseTable
ref="caseTableRef"
:plan-id="planId"
:repeat-case="props.repeatCase"
:active-module="activeFolderId"
:offspring-ids="offspringIds"
:module-tree="moduleTree"
@get-module-count="getModuleCount"
@execute-done="emit('executeDone')"
@refresh="emit('refresh')"
></CaseTable>
</template>
</MsSplitBox>
@ -37,8 +38,12 @@
import { ModuleTreeNode } from '@/models/common';
import type { PlanDetailFeatureCaseListQueryParams } from '@/models/testPlan/testPlan';
const props = defineProps<{
repeatCase: boolean;
}>();
const emit = defineEmits<{
(e: 'executeDone'): void;
(e: 'refresh'): void;
}>();
const route = useRoute();

View File

@ -88,7 +88,7 @@
</MsCard>
<!-- special-height的174: 上面卡片高度158 + mt的16 -->
<MsCard class="mt-[16px]" :special-height="174" simple has-breadcrumb no-content-padding>
<FeatureCase v-if="activeTab === 'featureCase'" @execute-done="getStatistics" />
<FeatureCase v-if="activeTab === 'featureCase'" :repeat-case="detail.repeatCase" @refresh="getStatistics" />
<!-- TODO 先不上 -->
<!-- <BugManagement v-if="activeTab === 'defectList'" :plan-id="detail.id" /> -->
</MsCard>