feat(测试计划): 测试计划详情-功能用例列表-复制和排序
This commit is contained in:
parent
bc4fed9553
commit
c170455ed5
|
@ -28,6 +28,7 @@ import {
|
||||||
planDetailBugPageUrl,
|
planDetailBugPageUrl,
|
||||||
planPassRateUrl,
|
planPassRateUrl,
|
||||||
RunFeatureCaseUrl,
|
RunFeatureCaseUrl,
|
||||||
|
SortFeatureCaseUrl,
|
||||||
updateTestPlanModuleUrl,
|
updateTestPlanModuleUrl,
|
||||||
UpdateTestPlanUrl,
|
UpdateTestPlanUrl,
|
||||||
} from '@/api/requrls/test-plan/testPlan';
|
} from '@/api/requrls/test-plan/testPlan';
|
||||||
|
@ -48,6 +49,7 @@ import type {
|
||||||
PlanDetailFeatureCaseItem,
|
PlanDetailFeatureCaseItem,
|
||||||
PlanDetailFeatureCaseListQueryParams,
|
PlanDetailFeatureCaseListQueryParams,
|
||||||
RunFeatureCaseParams,
|
RunFeatureCaseParams,
|
||||||
|
SortFeatureCaseParams,
|
||||||
TestPlanDetail,
|
TestPlanDetail,
|
||||||
TestPlanItem,
|
TestPlanItem,
|
||||||
UseCountType,
|
UseCountType,
|
||||||
|
@ -166,6 +168,10 @@ export function getFeatureCaseModule(planId: string) {
|
||||||
export function disassociateCase(data: DisassociateCaseParams) {
|
export function disassociateCase(data: DisassociateCaseParams) {
|
||||||
return MSR.post({ url: DisassociateCaseUrl, data });
|
return MSR.post({ url: DisassociateCaseUrl, data });
|
||||||
}
|
}
|
||||||
|
// 计划详情-功能用例列表-拖拽排序
|
||||||
|
export const sortFeatureCase = (data: SortFeatureCaseParams) => {
|
||||||
|
return MSR.post({ url: SortFeatureCaseUrl, data });
|
||||||
|
};
|
||||||
// 计划详情-功能用例列表-批量取消关联用例
|
// 计划详情-功能用例列表-批量取消关联用例
|
||||||
export function batchDisassociateCase(data: BatchFeatureCaseParams) {
|
export function batchDisassociateCase(data: BatchFeatureCaseParams) {
|
||||||
return MSR.post({ url: BatchDisassociateCaseUrl, data });
|
return MSR.post({ url: BatchDisassociateCaseUrl, data });
|
||||||
|
|
|
@ -48,6 +48,8 @@ export const GetPlanDetailFeatureCaseListUrl = '/test-plan/functional/case/page'
|
||||||
export const GetFeatureCaseModuleCountUrl = '/test-plan/functional/case/module/count';
|
export const GetFeatureCaseModuleCountUrl = '/test-plan/functional/case/module/count';
|
||||||
// 计划详情-功能用例模块树
|
// 计划详情-功能用例模块树
|
||||||
export const GetFeatureCaseModuleUrl = '/test-plan/functional/case/tree';
|
export const GetFeatureCaseModuleUrl = '/test-plan/functional/case/tree';
|
||||||
|
// 计划详情-功能用例列表-拖拽排序
|
||||||
|
export const SortFeatureCaseUrl = '/test-plan/functional/case/sort';
|
||||||
// 计划详情-功能用例-取消关联用例
|
// 计划详情-功能用例-取消关联用例
|
||||||
export const DisassociateCaseUrl = '/test-plan/functional/case/disassociate';
|
export const DisassociateCaseUrl = '/test-plan/functional/case/disassociate';
|
||||||
// 计划详情-功能用例-批量取消关联用例
|
// 计划详情-功能用例-批量取消关联用例
|
||||||
|
|
|
@ -180,4 +180,5 @@ export default {
|
||||||
'common.responsiblePerson': 'Responsible person',
|
'common.responsiblePerson': 'Responsible person',
|
||||||
'common.updateUserName': 'Update user name',
|
'common.updateUserName': 'Update user name',
|
||||||
'common.updateTime': 'Update time',
|
'common.updateTime': 'Update time',
|
||||||
|
'common.belongProject': 'Belong to Project',
|
||||||
};
|
};
|
||||||
|
|
|
@ -183,4 +183,5 @@ export default {
|
||||||
'common.responsiblePerson': '责任人',
|
'common.responsiblePerson': '责任人',
|
||||||
'common.updateUserName': '更新人',
|
'common.updateUserName': '更新人',
|
||||||
'common.updateTime': '更新时间',
|
'common.updateTime': '更新时间',
|
||||||
|
'common.belongProject': '所属项目',
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,10 +2,9 @@ import type { BatchActionQueryParams } from '@/components/pure/ms-table/type';
|
||||||
|
|
||||||
import type { customFieldsItem } from '@/models/caseManagement/featureCase';
|
import type { customFieldsItem } from '@/models/caseManagement/featureCase';
|
||||||
import type { TableQueryParams } from '@/models/common';
|
import type { TableQueryParams } from '@/models/common';
|
||||||
|
import { BatchApiParams, DragSortParams } from '@/models/common';
|
||||||
import { LastExecuteResults } from '@/enums/caseEnum';
|
import { LastExecuteResults } from '@/enums/caseEnum';
|
||||||
|
|
||||||
import { BatchApiParams } from '../common';
|
|
||||||
|
|
||||||
export type planStatusType = 'PREPARED' | 'UNDERWAY' | 'COMPLETED' | 'ARCHIVED';
|
export type planStatusType = 'PREPARED' | 'UNDERWAY' | 'COMPLETED' | 'ARCHIVED';
|
||||||
|
|
||||||
export interface AssociateFunctionalCaseItem {
|
export interface AssociateFunctionalCaseItem {
|
||||||
|
@ -188,6 +187,10 @@ export interface BatchUpdateCaseExecutorParams extends BatchFeatureCaseParams {
|
||||||
userId: string;
|
userId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SortFeatureCaseParams extends DragSortParams {
|
||||||
|
testPlanId: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface PassRateCountDetail {
|
export interface PassRateCountDetail {
|
||||||
id: string;
|
id: string;
|
||||||
passThreshold: number;
|
passThreshold: number;
|
||||||
|
|
|
@ -16,7 +16,13 @@
|
||||||
</template>
|
</template>
|
||||||
</a-button>
|
</a-button>
|
||||||
</div>
|
</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 }">
|
<template #num="{ record }">
|
||||||
<MsButton type="text" @click="toCaseDetail(record)">{{ record.num }}</MsButton>
|
<MsButton type="text" @click="toCaseDetail(record)">{{ record.num }}</MsButton>
|
||||||
</template>
|
</template>
|
||||||
|
@ -70,11 +76,18 @@
|
||||||
</MsPopconfirm>
|
</MsPopconfirm>
|
||||||
<!-- TODO: 修改permission -->
|
<!-- TODO: 修改permission -->
|
||||||
<a-divider
|
<a-divider
|
||||||
|
v-if="props.repeatCase"
|
||||||
v-permission="['PROJECT_API_DEFINITION_CASE:READ+EXECUTE']"
|
v-permission="['PROJECT_API_DEFINITION_CASE:READ+EXECUTE']"
|
||||||
direction="vertical"
|
direction="vertical"
|
||||||
:margin="8"
|
:margin="8"
|
||||||
></a-divider>
|
></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') }}
|
{{ t('common.copy') }}
|
||||||
</MsButton>
|
</MsButton>
|
||||||
</template>
|
</template>
|
||||||
|
@ -164,11 +177,13 @@
|
||||||
import ExecuteForm from '@/views/test-plan/testPlan/detail/featureCase/components/executeForm.vue';
|
import ExecuteForm from '@/views/test-plan/testPlan/detail/featureCase/components/executeForm.vue';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
associationCaseToPlan,
|
||||||
batchDisassociateCase,
|
batchDisassociateCase,
|
||||||
batchExecuteCase,
|
batchExecuteCase,
|
||||||
batchUpdateCaseExecutor,
|
batchUpdateCaseExecutor,
|
||||||
disassociateCase,
|
disassociateCase,
|
||||||
getPlanDetailFeatureCaseList,
|
getPlanDetailFeatureCaseList,
|
||||||
|
sortFeatureCase,
|
||||||
} from '@/api/modules/test-plan/testPlan';
|
} from '@/api/modules/test-plan/testPlan';
|
||||||
import { defaultExecuteForm } from '@/config/testPlan';
|
import { defaultExecuteForm } from '@/config/testPlan';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
@ -177,7 +192,7 @@
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
import { hasAnyPermission } from '@/utils/permission';
|
import { hasAnyPermission } from '@/utils/permission';
|
||||||
|
|
||||||
import { ModuleTreeNode } from '@/models/common';
|
import { DragSortParams, ModuleTreeNode } from '@/models/common';
|
||||||
import type {
|
import type {
|
||||||
ExecuteFeatureCaseFormParams,
|
ExecuteFeatureCaseFormParams,
|
||||||
PlanDetailFeatureCaseItem,
|
PlanDetailFeatureCaseItem,
|
||||||
|
@ -200,11 +215,12 @@
|
||||||
offspringIds: string[];
|
offspringIds: string[];
|
||||||
planId: string;
|
planId: string;
|
||||||
moduleTree: ModuleTreeNode[];
|
moduleTree: ModuleTreeNode[];
|
||||||
|
repeatCase: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'getModuleCount', params: PlanDetailFeatureCaseListQueryParams): void;
|
(e: 'getModuleCount', params: PlanDetailFeatureCaseListQueryParams): void;
|
||||||
(e: 'executeDone'): void;
|
(e: 'refresh'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -283,6 +299,14 @@
|
||||||
width: 200,
|
width: 200,
|
||||||
showDrag: true,
|
showDrag: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'common.belongProject',
|
||||||
|
dataIndex: 'projectName',
|
||||||
|
showTooltip: true,
|
||||||
|
showInTable: false,
|
||||||
|
showDrag: true,
|
||||||
|
width: 150,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'testPlan.featureCase.bugCount',
|
title: 'testPlan.featureCase.bugCount',
|
||||||
dataIndex: 'bugCount',
|
dataIndex: 'bugCount',
|
||||||
|
@ -410,6 +434,54 @@
|
||||||
loadList();
|
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() {
|
function handleBatchDisassociateCase() {
|
||||||
openModal({
|
openModal({
|
||||||
|
@ -426,6 +498,7 @@
|
||||||
});
|
});
|
||||||
Message.success(t('common.updateSuccess'));
|
Message.success(t('common.updateSuccess'));
|
||||||
resetCaseList();
|
resetCaseList();
|
||||||
|
emit('refresh');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
@ -451,7 +524,7 @@
|
||||||
Message.success(t('common.updateSuccess'));
|
Message.success(t('common.updateSuccess'));
|
||||||
resetSelector();
|
resetSelector();
|
||||||
loadList();
|
loadList();
|
||||||
emit('executeDone');
|
emit('refresh');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
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) {
|
function toCaseDetail(record: PlanDetailFeatureCaseItem) {
|
||||||
router.push({
|
router.push({
|
||||||
|
|
|
@ -14,11 +14,12 @@
|
||||||
<CaseTable
|
<CaseTable
|
||||||
ref="caseTableRef"
|
ref="caseTableRef"
|
||||||
:plan-id="planId"
|
:plan-id="planId"
|
||||||
|
:repeat-case="props.repeatCase"
|
||||||
:active-module="activeFolderId"
|
:active-module="activeFolderId"
|
||||||
:offspring-ids="offspringIds"
|
:offspring-ids="offspringIds"
|
||||||
:module-tree="moduleTree"
|
:module-tree="moduleTree"
|
||||||
@get-module-count="getModuleCount"
|
@get-module-count="getModuleCount"
|
||||||
@execute-done="emit('executeDone')"
|
@refresh="emit('refresh')"
|
||||||
></CaseTable>
|
></CaseTable>
|
||||||
</template>
|
</template>
|
||||||
</MsSplitBox>
|
</MsSplitBox>
|
||||||
|
@ -37,8 +38,12 @@
|
||||||
import { ModuleTreeNode } from '@/models/common';
|
import { ModuleTreeNode } from '@/models/common';
|
||||||
import type { PlanDetailFeatureCaseListQueryParams } from '@/models/testPlan/testPlan';
|
import type { PlanDetailFeatureCaseListQueryParams } from '@/models/testPlan/testPlan';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
repeatCase: boolean;
|
||||||
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'executeDone'): void;
|
(e: 'refresh'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
|
@ -88,7 +88,7 @@
|
||||||
</MsCard>
|
</MsCard>
|
||||||
<!-- special-height的174: 上面卡片高度158 + mt的16 -->
|
<!-- special-height的174: 上面卡片高度158 + mt的16 -->
|
||||||
<MsCard class="mt-[16px]" :special-height="174" simple has-breadcrumb no-content-padding>
|
<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 先不上 -->
|
<!-- TODO 先不上 -->
|
||||||
<!-- <BugManagement v-if="activeTab === 'defectList'" :plan-id="detail.id" /> -->
|
<!-- <BugManagement v-if="activeTab === 'defectList'" :plan-id="detail.id" /> -->
|
||||||
</MsCard>
|
</MsCard>
|
||||||
|
|
Loading…
Reference in New Issue