feat(测试计划): 测试计划详情-接口用例-批量修改执行人&拖拽排序
This commit is contained in:
parent
49345ac62a
commit
b29118595d
|
@ -12,6 +12,7 @@ import {
|
||||||
BatchEditTestPlanUrl,
|
BatchEditTestPlanUrl,
|
||||||
batchMovePlanUrl,
|
batchMovePlanUrl,
|
||||||
BatchRunCaseUrl,
|
BatchRunCaseUrl,
|
||||||
|
BatchUpdateApiCaseExecutorUrl,
|
||||||
BatchUpdateCaseExecutorUrl,
|
BatchUpdateCaseExecutorUrl,
|
||||||
ConfigScheduleUrl,
|
ConfigScheduleUrl,
|
||||||
copyTestPlanUrl,
|
copyTestPlanUrl,
|
||||||
|
@ -44,6 +45,7 @@ import {
|
||||||
PlanDetailExecuteHistoryUrl,
|
PlanDetailExecuteHistoryUrl,
|
||||||
planPassRateUrl,
|
planPassRateUrl,
|
||||||
RunFeatureCaseUrl,
|
RunFeatureCaseUrl,
|
||||||
|
SortApiCaseUrl,
|
||||||
SortFeatureCaseUrl,
|
SortFeatureCaseUrl,
|
||||||
TestPlanAndGroupCopyUrl,
|
TestPlanAndGroupCopyUrl,
|
||||||
TestPlanApiAssociatedPageUrl,
|
TestPlanApiAssociatedPageUrl,
|
||||||
|
@ -67,6 +69,7 @@ import type {
|
||||||
BatchApiCaseParams,
|
BatchApiCaseParams,
|
||||||
BatchExecuteFeatureCaseParams,
|
BatchExecuteFeatureCaseParams,
|
||||||
BatchFeatureCaseParams,
|
BatchFeatureCaseParams,
|
||||||
|
BatchUpdateApiCaseExecutorParams,
|
||||||
BatchUpdateCaseExecutorParams,
|
BatchUpdateCaseExecutorParams,
|
||||||
CreateTask,
|
CreateTask,
|
||||||
DisassociateCaseParams,
|
DisassociateCaseParams,
|
||||||
|
@ -84,6 +87,7 @@ import type {
|
||||||
PlanDetailFeatureCaseItem,
|
PlanDetailFeatureCaseItem,
|
||||||
PlanDetailFeatureCaseListQueryParams,
|
PlanDetailFeatureCaseListQueryParams,
|
||||||
RunFeatureCaseParams,
|
RunFeatureCaseParams,
|
||||||
|
SortApiCaseParams,
|
||||||
SortFeatureCaseParams,
|
SortFeatureCaseParams,
|
||||||
TestPlanBaseParams,
|
TestPlanBaseParams,
|
||||||
TestPlanDetail,
|
TestPlanDetail,
|
||||||
|
@ -273,6 +277,10 @@ export function getApiCaseModule(data: PlanDetailApiCaseTreeParams) {
|
||||||
export function getApiCaseModuleCount(data: PlanDetailApiCaseQueryParams) {
|
export function getApiCaseModuleCount(data: PlanDetailApiCaseQueryParams) {
|
||||||
return MSR.post({ url: GetApiCaseModuleCountUrl, data });
|
return MSR.post({ url: GetApiCaseModuleCountUrl, data });
|
||||||
}
|
}
|
||||||
|
// 计划详情-接口用例列表-拖拽排序
|
||||||
|
export const sortApiCase = (data: SortApiCaseParams) => {
|
||||||
|
return MSR.post({ url: SortApiCaseUrl, data });
|
||||||
|
};
|
||||||
// 计划详情-接口用例列表-取消关联用例
|
// 计划详情-接口用例列表-取消关联用例
|
||||||
export function disassociateApiCase(data: DisassociateCaseParams) {
|
export function disassociateApiCase(data: DisassociateCaseParams) {
|
||||||
return MSR.post({ url: DisassociateApiCaseUrl, data });
|
return MSR.post({ url: DisassociateApiCaseUrl, data });
|
||||||
|
@ -281,10 +289,18 @@ export function disassociateApiCase(data: DisassociateCaseParams) {
|
||||||
export function batchDisassociateApiCase(data: BatchApiCaseParams) {
|
export function batchDisassociateApiCase(data: BatchApiCaseParams) {
|
||||||
return MSR.post({ url: BatchDisassociateApiCaseUrl, data });
|
return MSR.post({ url: BatchDisassociateApiCaseUrl, data });
|
||||||
}
|
}
|
||||||
|
// 计划详情-接口用例列表-批量更新执行人
|
||||||
|
export function batchUpdateApiCaseExecutor(data: BatchUpdateApiCaseExecutorParams) {
|
||||||
|
return MSR.post({ url: BatchUpdateApiCaseExecutorUrl, data });
|
||||||
|
}
|
||||||
// 计划详情-接口场景列表 TODO 联调
|
// 计划详情-接口场景列表 TODO 联调
|
||||||
export function getPlanDetailApiScenarioList(data: PlanDetailFeatureCaseListQueryParams) {
|
export function getPlanDetailApiScenarioList(data: PlanDetailFeatureCaseListQueryParams) {
|
||||||
return MSR.post<CommonList<PlanDetailApiScenarioItem>>({ url: GetPlanDetailFeatureCaseListUrl, data });
|
return MSR.post<CommonList<PlanDetailApiScenarioItem>>({ url: GetPlanDetailFeatureCaseListUrl, data });
|
||||||
}
|
}
|
||||||
|
// 计划详情-接口场景列表-批量更新执行人 TODO 联调
|
||||||
|
export function batchUpdateApiScenarioExecutor(data: BatchUpdateApiCaseExecutorParams) {
|
||||||
|
return MSR.post({ url: BatchUpdateApiCaseExecutorUrl, data });
|
||||||
|
}
|
||||||
// 计划详情-执行历史 TODO 联调
|
// 计划详情-执行历史 TODO 联调
|
||||||
export function getPlanDetailExecuteHistory(data: PlanDetailFeatureCaseListQueryParams) {
|
export function getPlanDetailExecuteHistory(data: PlanDetailFeatureCaseListQueryParams) {
|
||||||
return MSR.post<CommonList<PlanDetailExecuteHistoryItem>>({ url: PlanDetailExecuteHistoryUrl, data });
|
return MSR.post<CommonList<PlanDetailExecuteHistoryItem>>({ url: PlanDetailExecuteHistoryUrl, data });
|
||||||
|
|
|
@ -100,9 +100,13 @@ export const DeleteScheduleTaskUrl = 'test-plan/schedule-config-delete';
|
||||||
export const GetPlanDetailApiCaseListUrl = '/test-plan/api/case/page';
|
export const GetPlanDetailApiCaseListUrl = '/test-plan/api/case/page';
|
||||||
// 计划详情-接口用例模块树
|
// 计划详情-接口用例模块树
|
||||||
export const GetApiCaseModuleUrl = '/test-plan/api/case/tree';
|
export const GetApiCaseModuleUrl = '/test-plan/api/case/tree';
|
||||||
|
// 计划详情-接口用例-获取模块数量
|
||||||
|
export const GetApiCaseModuleCountUrl = '/test-plan/api/case/module/count';
|
||||||
|
// 计划详情-接口用例列表-拖拽排序
|
||||||
|
export const SortApiCaseUrl = '/test-plan/api/case/sort';
|
||||||
// 计划详情-接口用例列表-取消关联用例
|
// 计划详情-接口用例列表-取消关联用例
|
||||||
export const DisassociateApiCaseUrl = '/test-plan/api/case/disassociate';
|
export const DisassociateApiCaseUrl = '/test-plan/api/case/disassociate';
|
||||||
// 计划详情-接口用例列表-批量取消关联用例
|
// 计划详情-接口用例列表-批量取消关联用例
|
||||||
export const BatchDisassociateApiCaseUrl = '/test-plan/api/case/batch/disassociate';
|
export const BatchDisassociateApiCaseUrl = '/test-plan/api/case/batch/disassociate';
|
||||||
// 计划详情-接口用例-获取模块数量
|
// 计划详情-接口用例列表-批量更新执行人
|
||||||
export const GetApiCaseModuleCountUrl = '/test-plan/api/case/module/count';
|
export const BatchUpdateApiCaseExecutorUrl = '/test-plan/api/case/batch/update/executor';
|
||||||
|
|
|
@ -269,7 +269,7 @@ export interface PlanDetailApiCaseQueryParams extends TableQueryParams, TestPlan
|
||||||
|
|
||||||
export interface PlanDetailApiCaseTreeParams {
|
export interface PlanDetailApiCaseTreeParams {
|
||||||
testPlanId: string;
|
testPlanId: string;
|
||||||
treeType: 'MODULE' | 'COLLECTION';
|
treeType: 'MODULE' | 'COLLECTION'; // 视图类型:模块是MODULE,测试集是COLLECTION
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PlanDetailApiCaseItem {
|
export interface PlanDetailApiCaseItem {
|
||||||
|
@ -281,7 +281,7 @@ export interface PlanDetailApiCaseItem {
|
||||||
createUserName: string;
|
createUserName: string;
|
||||||
lastExecResult: LastExecuteResults;
|
lastExecResult: LastExecuteResults;
|
||||||
lastExecTime: number;
|
lastExecTime: number;
|
||||||
lastExecResultReportId: string;
|
lastExecReportId: string; // 报告id
|
||||||
executeUser: string;
|
executeUser: string;
|
||||||
executeUserName: string;
|
executeUserName: string;
|
||||||
priority: string;
|
priority: string;
|
||||||
|
@ -290,17 +290,24 @@ export interface PlanDetailApiCaseItem {
|
||||||
projectName: string;
|
projectName: string;
|
||||||
environmentId: string;
|
environmentId: string;
|
||||||
environmentName: string;
|
environmentName: string;
|
||||||
testPlanCollectionId: string;
|
testPlanCollectionId: string; // 测试集id
|
||||||
collectEnvironmentId: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BatchApiCaseParams extends BatchActionQueryParams {
|
export interface BatchApiCaseParams extends BatchActionQueryParams {
|
||||||
testPlanId: string;
|
testPlanId: string;
|
||||||
moduleIds?: string[];
|
moduleIds?: string[];
|
||||||
collectionId?: string;
|
collectionId?: string; // 测试集id
|
||||||
protocols: string[];
|
protocols: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface BatchUpdateApiCaseExecutorParams extends BatchApiCaseParams {
|
||||||
|
userId: string; // 执行人id
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SortApiCaseParams extends DragSortParams {
|
||||||
|
testCollectionId: string; // 测试集id
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: 联调
|
// TODO: 联调
|
||||||
export interface PlanDetailApiScenarioItem {
|
export interface PlanDetailApiScenarioItem {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
|
@ -8,7 +8,13 @@
|
||||||
>
|
>
|
||||||
<template #expandLeft>
|
<template #expandLeft>
|
||||||
<a-dropdown v-model:popup-visible="visible" :hide-on-select="false">
|
<a-dropdown v-model:popup-visible="visible" :hide-on-select="false">
|
||||||
<MsButton type="icon" status="secondary" class="!mr-[4px] p-[4px]" @click="visible = !visible">
|
<MsButton
|
||||||
|
v-show="typeof isExpandAll !== 'undefined'"
|
||||||
|
type="icon"
|
||||||
|
status="secondary"
|
||||||
|
class="!mr-[4px] p-[4px]"
|
||||||
|
@click="visible = !visible"
|
||||||
|
>
|
||||||
<MsIcon :type="`${showExpandApi ? 'icon-icon_more_outlined' : 'icon-icon_protocol'}`" />
|
<MsIcon :type="`${showExpandApi ? 'icon-icon_more_outlined' : 'icon-icon_protocol'}`" />
|
||||||
</MsButton>
|
</MsButton>
|
||||||
<template #content>
|
<template #content>
|
||||||
|
@ -83,7 +89,8 @@
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const isExpandAll = defineModel<boolean>('isExpandAll', {
|
const isExpandAll = defineModel<boolean>('isExpandAll', {
|
||||||
required: true,
|
required: false,
|
||||||
|
default: undefined,
|
||||||
});
|
});
|
||||||
const isExpandApi = defineModel<boolean>('isExpandApi', {
|
const isExpandApi = defineModel<boolean>('isExpandApi', {
|
||||||
required: false,
|
required: false,
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
<template>
|
||||||
|
<a-modal
|
||||||
|
v-model:visible="visible"
|
||||||
|
title-align="start"
|
||||||
|
body-class="p-0"
|
||||||
|
:cancel-button-props="{ disabled: batchLoading }"
|
||||||
|
:ok-loading="batchLoading"
|
||||||
|
:ok-button-props="{ disabled: batchUpdateExecutorDisabled }"
|
||||||
|
:ok-text="t('common.update')"
|
||||||
|
@before-ok="handleBatchUpdateExecutor"
|
||||||
|
@close="resetBatchForm"
|
||||||
|
>
|
||||||
|
<template #title>
|
||||||
|
{{ t('testPlan.featureCase.batchChangeExecutor') }}
|
||||||
|
<div class="text-[var(--color-text-4)]">
|
||||||
|
{{
|
||||||
|
t('testPlan.testPlanIndex.selectedCount', {
|
||||||
|
count: props.count,
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<a-form ref="batchUpdateExecutorFormRef" :model="batchUpdateExecutorForm" layout="vertical">
|
||||||
|
<a-form-item
|
||||||
|
field="userId"
|
||||||
|
:label="t('testPlan.featureCase.executor')"
|
||||||
|
:rules="[{ required: true, message: t('testPlan.featureCase.requestExecutorRequired') }]"
|
||||||
|
asterisk-position="end"
|
||||||
|
class="mb-0"
|
||||||
|
>
|
||||||
|
<MsSelect
|
||||||
|
v-model:modelValue="batchUpdateExecutorForm.userId"
|
||||||
|
mode="static"
|
||||||
|
:placeholder="t('common.pleaseSelect')"
|
||||||
|
:loading="executorLoading"
|
||||||
|
:options="userOptions"
|
||||||
|
:search-keys="['label']"
|
||||||
|
allow-search
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { FormInstance, Message, SelectOptionData } from '@arco-design/web-vue';
|
||||||
|
|
||||||
|
import MsSelect from '@/components/business/ms-select';
|
||||||
|
|
||||||
|
import { GetTestPlanUsers } from '@/api/modules/test-plan/testPlan';
|
||||||
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
import useAppStore from '@/store/modules/app';
|
||||||
|
|
||||||
|
import { ReviewUserItem } from '@/models/caseManagement/caseReview';
|
||||||
|
import type { BatchUpdateApiCaseExecutorParams, BatchUpdateCaseExecutorParams } from '@/models/testPlan/testPlan';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
count: number;
|
||||||
|
params?: BatchUpdateCaseExecutorParams | BatchUpdateApiCaseExecutorParams;
|
||||||
|
batchUpdateExecutor: (...args: any) => Promise<any>; // 更新执行人接口
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'loadList'): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const visible = defineModel<boolean>('visible', {
|
||||||
|
required: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const appStore = useAppStore();
|
||||||
|
|
||||||
|
const batchUpdateExecutorFormRef = ref<FormInstance>();
|
||||||
|
const batchLoading = ref(false);
|
||||||
|
const batchUpdateExecutorForm = ref<{ userId: string }>({ userId: '' });
|
||||||
|
const batchUpdateExecutorDisabled = computed(() => !batchUpdateExecutorForm.value.userId.length);
|
||||||
|
const userOptions = ref<SelectOptionData[]>([]);
|
||||||
|
const executorLoading = ref(false);
|
||||||
|
async function initUserOptions() {
|
||||||
|
try {
|
||||||
|
executorLoading.value = true;
|
||||||
|
const res = await GetTestPlanUsers(appStore.currentProjectId, '');
|
||||||
|
userOptions.value = res.map((e: ReviewUserItem) => ({ label: e.name, value: e.id }));
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
} finally {
|
||||||
|
executorLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleBatchUpdateExecutor(done: (closed: boolean) => void) {
|
||||||
|
batchUpdateExecutorFormRef.value?.validate(async (errors) => {
|
||||||
|
if (!errors) {
|
||||||
|
try {
|
||||||
|
batchLoading.value = true;
|
||||||
|
await props.batchUpdateExecutor({
|
||||||
|
...props.params,
|
||||||
|
...batchUpdateExecutorForm.value,
|
||||||
|
});
|
||||||
|
Message.success(t('common.updateSuccess'));
|
||||||
|
emit('loadList');
|
||||||
|
done(true);
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
done(false);
|
||||||
|
} finally {
|
||||||
|
batchLoading.value = false;
|
||||||
|
done(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetBatchForm() {
|
||||||
|
batchUpdateExecutorForm.value = { userId: '' };
|
||||||
|
}
|
||||||
|
|
||||||
|
onBeforeMount(() => {
|
||||||
|
initUserOptions();
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -27,7 +27,7 @@
|
||||||
<CaseLevel :case-level="filterContent.value" />
|
<CaseLevel :case-level="filterContent.value" />
|
||||||
</template>
|
</template>
|
||||||
<template #caseLevel="{ record }">
|
<template #caseLevel="{ record }">
|
||||||
<CaseLevel :case-level="record.caseLevel" />
|
<CaseLevel :case-level="record.priority" />
|
||||||
</template>
|
</template>
|
||||||
<template #[FilterSlotNameEnum.CASE_MANAGEMENT_EXECUTE_RESULT]="{ filterContent }">
|
<template #[FilterSlotNameEnum.CASE_MANAGEMENT_EXECUTE_RESULT]="{ filterContent }">
|
||||||
<ExecuteResult :execute-result="filterContent.key" />
|
<ExecuteResult :execute-result="filterContent.key" />
|
||||||
|
@ -62,24 +62,17 @@
|
||||||
{{ t('common.cancelLink') }}
|
{{ t('common.cancelLink') }}
|
||||||
</MsButton>
|
</MsButton>
|
||||||
</MsPopconfirm>
|
</MsPopconfirm>
|
||||||
<a-divider
|
|
||||||
v-if="props.repeatCase"
|
|
||||||
v-permission="['PROJECT_TEST_PLAN:READ+ASSOCIATION']"
|
|
||||||
direction="vertical"
|
|
||||||
:margin="8"
|
|
||||||
></a-divider>
|
|
||||||
<MsButton
|
|
||||||
v-if="props.repeatCase"
|
|
||||||
v-permission="['PROJECT_TEST_PLAN:READ+ASSOCIATION']"
|
|
||||||
type="text"
|
|
||||||
class="!mr-0"
|
|
||||||
@click="handleCopyCase(record)"
|
|
||||||
>
|
|
||||||
{{ t('common.copy') }}
|
|
||||||
</MsButton>
|
|
||||||
</template>
|
</template>
|
||||||
</MsBaseTable>
|
</MsBaseTable>
|
||||||
<ReportDrawer v-model:visible="reportVisible" :report-id="reportId" />
|
<ReportDrawer v-model:visible="reportVisible" :report-id="reportId" />
|
||||||
|
<!-- 批量修改执行人 -->
|
||||||
|
<BatchUpdateExecutorModal
|
||||||
|
v-model:visible="batchUpdateExecutorModalVisible"
|
||||||
|
:count="batchParams.currentSelectCount || tableSelected.length"
|
||||||
|
:params="batchUpdateExecutorParams"
|
||||||
|
:batch-update-executor="batchUpdateApiCaseExecutor"
|
||||||
|
@load-list="resetSelectorAndCaseList"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -101,14 +94,15 @@
|
||||||
import CaseLevel from '@/components/business/ms-case-associate/caseLevel.vue';
|
import CaseLevel from '@/components/business/ms-case-associate/caseLevel.vue';
|
||||||
import ExecuteResult from '@/components/business/ms-case-associate/executeResult.vue';
|
import ExecuteResult from '@/components/business/ms-case-associate/executeResult.vue';
|
||||||
import apiStatus from '@/views/api-test/components/apiStatus.vue';
|
import apiStatus from '@/views/api-test/components/apiStatus.vue';
|
||||||
|
import BatchUpdateExecutorModal from '@/views/test-plan/testPlan/components/batchUpdateExecutorModal.vue';
|
||||||
import ReportDrawer from '@/views/test-plan/testPlan/detail/reportDrawer.vue';
|
import ReportDrawer from '@/views/test-plan/testPlan/detail/reportDrawer.vue';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
associationCaseToPlan,
|
|
||||||
batchDisassociateApiCase,
|
batchDisassociateApiCase,
|
||||||
|
batchUpdateApiCaseExecutor,
|
||||||
disassociateApiCase,
|
disassociateApiCase,
|
||||||
getPlanDetailApiCaseList,
|
getPlanDetailApiCaseList,
|
||||||
sortFeatureCase,
|
sortApiCase,
|
||||||
} from '@/api/modules/test-plan/testPlan';
|
} from '@/api/modules/test-plan/testPlan';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useModal from '@/hooks/useModal';
|
import useModal from '@/hooks/useModal';
|
||||||
|
@ -124,11 +118,7 @@
|
||||||
import { FilterSlotNameEnum } from '@/enums/tableFilterEnum';
|
import { FilterSlotNameEnum } from '@/enums/tableFilterEnum';
|
||||||
|
|
||||||
import { casePriorityOptions } from '@/views/api-test/components/config';
|
import { casePriorityOptions } from '@/views/api-test/components/config';
|
||||||
import {
|
import { executionResultMap, getModules } from '@/views/case-management/caseManagementFeature/components/utils';
|
||||||
executionResultMap,
|
|
||||||
getCaseLevels,
|
|
||||||
getModules,
|
|
||||||
} from '@/views/case-management/caseManagementFeature/components/utils';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
modulesCount: Record<string, number>; // 模块数量统计对象
|
modulesCount: Record<string, number>; // 模块数量统计对象
|
||||||
|
@ -137,9 +127,9 @@
|
||||||
offspringIds: string[];
|
offspringIds: string[];
|
||||||
planId: string;
|
planId: string;
|
||||||
moduleTree: ModuleTreeNode[];
|
moduleTree: ModuleTreeNode[];
|
||||||
repeatCase: boolean;
|
|
||||||
canEdit: boolean;
|
canEdit: boolean;
|
||||||
selectedProtocols: string[];
|
selectedProtocols: string[];
|
||||||
|
treeType: 'MODULE' | 'COLLECTION';
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
@ -188,7 +178,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'case.caseLevel',
|
title: 'case.caseLevel',
|
||||||
dataIndex: 'caseLevel',
|
dataIndex: 'priority',
|
||||||
slotName: 'caseLevel',
|
slotName: 'caseLevel',
|
||||||
filterConfig: {
|
filterConfig: {
|
||||||
options: casePriorityOptions,
|
options: casePriorityOptions,
|
||||||
|
@ -242,7 +232,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'report.detail.api.executeEnv',
|
title: 'report.detail.api.executeEnv',
|
||||||
dataIndex: 'executeEnv',
|
dataIndex: 'environmentName',
|
||||||
width: 150,
|
width: 150,
|
||||||
showInTable: false,
|
showInTable: false,
|
||||||
showDrag: true,
|
showDrag: true,
|
||||||
|
@ -288,21 +278,11 @@
|
||||||
return {
|
return {
|
||||||
...record,
|
...record,
|
||||||
lastExecResult: record.lastExecResult ?? LastExecuteResults.PENDING,
|
lastExecResult: record.lastExecResult ?? LastExecuteResults.PENDING,
|
||||||
caseLevel: getCaseLevels(record.customFields),
|
|
||||||
moduleId: getModules(record.moduleId, props.moduleTree),
|
moduleId: getModules(record.moduleId, props.moduleTree),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.canEdit,
|
|
||||||
(val) => {
|
|
||||||
tableProps.value.draggableCondition = hasAnyPermission(['PROJECT_TEST_PLAN:READ+UPDATE']) && val;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
immediate: true,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const tableRef = ref<InstanceType<typeof MsBaseTable>>();
|
const tableRef = ref<InstanceType<typeof MsBaseTable>>();
|
||||||
watch(
|
watch(
|
||||||
() => hasOperationPermission.value,
|
() => hasOperationPermission.value,
|
||||||
|
@ -347,6 +327,7 @@
|
||||||
}
|
}
|
||||||
return moduleIds;
|
return moduleIds;
|
||||||
}
|
}
|
||||||
|
const collectionId = computed(() => (props.activeModule === 'all' ? '' : props.activeModule));
|
||||||
async function getTableParams(isBatch: boolean) {
|
async function getTableParams(isBatch: boolean) {
|
||||||
const selectModules = await getModuleIds();
|
const selectModules = await getModuleIds();
|
||||||
const commonParams = {
|
const commonParams = {
|
||||||
|
@ -354,7 +335,7 @@
|
||||||
projectId: appStore.currentProjectId,
|
projectId: appStore.currentProjectId,
|
||||||
moduleIds: selectModules,
|
moduleIds: selectModules,
|
||||||
protocols: props.selectedProtocols,
|
protocols: props.selectedProtocols,
|
||||||
collectionId: props.activeModule,
|
collectionId: collectionId.value,
|
||||||
};
|
};
|
||||||
if (isBatch) {
|
if (isBatch) {
|
||||||
return {
|
return {
|
||||||
|
@ -372,6 +353,20 @@
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
[() => props.canEdit, () => props.treeType, () => collectionId.value.length],
|
||||||
|
() => {
|
||||||
|
tableProps.value.draggableCondition =
|
||||||
|
hasAnyPermission(['PROJECT_TEST_PLAN:READ+UPDATE']) &&
|
||||||
|
props.canEdit &&
|
||||||
|
props.treeType === 'COLLECTION' &&
|
||||||
|
!!collectionId.value.length;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
async function loadCaseList() {
|
async function loadCaseList() {
|
||||||
const tableParams = await getTableParams(false);
|
const tableParams = await getTableParams(false);
|
||||||
setLoadListParams(tableParams);
|
setLoadListParams(tableParams);
|
||||||
|
@ -400,7 +395,7 @@
|
||||||
const reportId = ref('');
|
const reportId = ref('');
|
||||||
function showReport(record: PlanDetailApiCaseItem) {
|
function showReport(record: PlanDetailApiCaseItem) {
|
||||||
reportVisible.value = true;
|
reportVisible.value = true;
|
||||||
reportId.value = record.lastExecResultReportId;
|
reportId.value = record.lastExecReportId;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tableSelected = ref<(string | number)[]>([]); // 表格选中的
|
const tableSelected = ref<(string | number)[]>([]); // 表格选中的
|
||||||
|
@ -421,11 +416,15 @@
|
||||||
loadList();
|
loadList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resetSelectorAndCaseList() {
|
||||||
|
resetSelector();
|
||||||
|
loadList();
|
||||||
|
}
|
||||||
|
|
||||||
// 拖拽排序
|
// 拖拽排序
|
||||||
async function handleDragChange(params: DragSortParams) {
|
async function handleDragChange(params: DragSortParams) {
|
||||||
try {
|
try {
|
||||||
// TODO 联调
|
await sortApiCase({ ...params, testCollectionId: collectionId.value });
|
||||||
await sortFeatureCase({ ...params, testPlanId: props.planId });
|
|
||||||
Message.success(t('caseManagement.featureCase.sortSuccess'));
|
Message.success(t('caseManagement.featureCase.sortSuccess'));
|
||||||
loadCaseList();
|
loadCaseList();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -434,23 +433,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 复制用例
|
|
||||||
async function handleCopyCase(record: PlanDetailApiCaseItem) {
|
|
||||||
try {
|
|
||||||
// TODO 联调
|
|
||||||
await associationCaseToPlan({
|
|
||||||
functionalSelectIds: [record.id],
|
|
||||||
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);
|
const disassociateLoading = ref(false);
|
||||||
async function handleDisassociateCase(record: PlanDetailApiCaseItem, done?: () => void) {
|
async function handleDisassociateCase(record: PlanDetailApiCaseItem, done?: () => void) {
|
||||||
|
@ -504,10 +486,15 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 批量修改执行人
|
||||||
|
const batchUpdateExecutorModalVisible = ref(false);
|
||||||
|
const batchUpdateExecutorParams = ref();
|
||||||
|
|
||||||
// 处理表格选中后批量操作
|
// 处理表格选中后批量操作
|
||||||
function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
|
async function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
|
||||||
tableSelected.value = params?.selectedIds || [];
|
tableSelected.value = params?.selectedIds || [];
|
||||||
batchParams.value = { ...params, selectIds: params?.selectedIds };
|
batchParams.value = { ...params, selectIds: params?.selectedIds };
|
||||||
|
const tableParams = await getTableParams(true);
|
||||||
switch (event.eventTag) {
|
switch (event.eventTag) {
|
||||||
case 'execute':
|
case 'execute':
|
||||||
break;
|
break;
|
||||||
|
@ -515,6 +502,13 @@
|
||||||
handleBatchDisassociateCase();
|
handleBatchDisassociateCase();
|
||||||
break;
|
break;
|
||||||
case 'changeExecutor':
|
case 'changeExecutor':
|
||||||
|
batchUpdateExecutorParams.value = {
|
||||||
|
selectIds: tableSelected.value as string[],
|
||||||
|
selectAll: batchParams.value.selectAll,
|
||||||
|
excludeIds: batchParams.value?.excludeIds || [],
|
||||||
|
...tableParams,
|
||||||
|
};
|
||||||
|
batchUpdateExecutorModalVisible.value = true;
|
||||||
break;
|
break;
|
||||||
case 'move':
|
case 'move':
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -88,7 +88,18 @@
|
||||||
|
|
||||||
const activeFolder = ref<string>('all');
|
const activeFolder = ref<string>('all');
|
||||||
const allCount = ref(0);
|
const allCount = ref(0);
|
||||||
const isExpandAll = ref(false);
|
const isExpandAll = ref<boolean | undefined>(false);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.treeType,
|
||||||
|
(val) => {
|
||||||
|
if (val === 'COLLECTION') {
|
||||||
|
isExpandAll.value = undefined;
|
||||||
|
} else {
|
||||||
|
isExpandAll.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
function setActiveFolder(id: string) {
|
function setActiveFolder(id: string) {
|
||||||
activeFolder.value = id;
|
activeFolder.value = id;
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
<CaseTable
|
<CaseTable
|
||||||
ref="caseTableRef"
|
ref="caseTableRef"
|
||||||
:plan-id="planId"
|
:plan-id="planId"
|
||||||
|
:tree-type="props.treeType"
|
||||||
:modules-count="modulesCount"
|
:modules-count="modulesCount"
|
||||||
:module-name="moduleName"
|
:module-name="moduleName"
|
||||||
:repeat-case="props.repeatCase"
|
:repeat-case="props.repeatCase"
|
||||||
|
@ -97,8 +98,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCaseTableList() {
|
function getCaseTableList() {
|
||||||
|
nextTick(() => {
|
||||||
initModules();
|
initModules();
|
||||||
caseTableRef.value?.loadCaseList();
|
caseTableRef.value?.loadCaseList();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
|
|
|
@ -65,24 +65,17 @@
|
||||||
{{ t('common.cancelLink') }}
|
{{ t('common.cancelLink') }}
|
||||||
</MsButton>
|
</MsButton>
|
||||||
</MsPopconfirm>
|
</MsPopconfirm>
|
||||||
<a-divider
|
|
||||||
v-if="props.repeatCase"
|
|
||||||
v-permission="['PROJECT_TEST_PLAN:READ+ASSOCIATION']"
|
|
||||||
direction="vertical"
|
|
||||||
:margin="8"
|
|
||||||
></a-divider>
|
|
||||||
<MsButton
|
|
||||||
v-if="props.repeatCase"
|
|
||||||
v-permission="['PROJECT_TEST_PLAN:READ+ASSOCIATION']"
|
|
||||||
type="text"
|
|
||||||
class="!mr-0"
|
|
||||||
@click="handleCopyCase(record)"
|
|
||||||
>
|
|
||||||
{{ t('common.copy') }}
|
|
||||||
</MsButton>
|
|
||||||
</template>
|
</template>
|
||||||
</MsBaseTable>
|
</MsBaseTable>
|
||||||
<ReportDrawer v-model:visible="reportVisible" :report-id="reportId" />
|
<ReportDrawer v-model:visible="reportVisible" :report-id="reportId" />
|
||||||
|
<!-- 批量修改执行人 -->
|
||||||
|
<BatchUpdateExecutorModal
|
||||||
|
v-model:visible="batchUpdateExecutorModalVisible"
|
||||||
|
:count="batchParams.currentSelectCount || tableSelected.length"
|
||||||
|
:params="batchUpdateExecutorParams"
|
||||||
|
:batch-update-executor="batchUpdateApiScenarioExecutor"
|
||||||
|
@load-list="resetSelectorAndCaseList"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -104,11 +97,12 @@
|
||||||
import CaseLevel from '@/components/business/ms-case-associate/caseLevel.vue';
|
import CaseLevel from '@/components/business/ms-case-associate/caseLevel.vue';
|
||||||
import ExecuteResult from '@/components/business/ms-case-associate/executeResult.vue';
|
import ExecuteResult from '@/components/business/ms-case-associate/executeResult.vue';
|
||||||
import apiStatus from '@/views/api-test/components/apiStatus.vue';
|
import apiStatus from '@/views/api-test/components/apiStatus.vue';
|
||||||
|
import BatchUpdateExecutorModal from '@/views/test-plan/testPlan/components/batchUpdateExecutorModal.vue';
|
||||||
import ReportDrawer from '@/views/test-plan/testPlan/detail/reportDrawer.vue';
|
import ReportDrawer from '@/views/test-plan/testPlan/detail/reportDrawer.vue';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
associationCaseToPlan,
|
|
||||||
batchDisassociateCase,
|
batchDisassociateCase,
|
||||||
|
batchUpdateApiScenarioExecutor,
|
||||||
disassociateCase,
|
disassociateCase,
|
||||||
getPlanDetailApiScenarioList,
|
getPlanDetailApiScenarioList,
|
||||||
sortFeatureCase,
|
sortFeatureCase,
|
||||||
|
@ -142,7 +136,6 @@
|
||||||
offspringIds: string[];
|
offspringIds: string[];
|
||||||
planId: string;
|
planId: string;
|
||||||
moduleTree: ModuleTreeNode[];
|
moduleTree: ModuleTreeNode[];
|
||||||
repeatCase: boolean;
|
|
||||||
canEdit: boolean;
|
canEdit: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
@ -421,6 +414,11 @@
|
||||||
loadList();
|
loadList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resetSelectorAndCaseList() {
|
||||||
|
resetSelector();
|
||||||
|
loadList();
|
||||||
|
}
|
||||||
|
|
||||||
// 拖拽排序
|
// 拖拽排序
|
||||||
async function handleDragChange(params: DragSortParams) {
|
async function handleDragChange(params: DragSortParams) {
|
||||||
try {
|
try {
|
||||||
|
@ -434,23 +432,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 复制用例
|
|
||||||
async function handleCopyCase(record: PlanDetailApiScenarioItem) {
|
|
||||||
try {
|
|
||||||
// TODO 联调
|
|
||||||
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);
|
const disassociateLoading = ref(false);
|
||||||
async function handleDisassociateCase(record: PlanDetailApiScenarioItem, done?: () => void) {
|
async function handleDisassociateCase(record: PlanDetailApiScenarioItem, done?: () => void) {
|
||||||
|
@ -506,10 +487,15 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 批量修改执行人
|
||||||
|
const batchUpdateExecutorModalVisible = ref(false);
|
||||||
|
const batchUpdateExecutorParams = ref();
|
||||||
|
|
||||||
// 处理表格选中后批量操作
|
// 处理表格选中后批量操作
|
||||||
function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
|
async function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
|
||||||
tableSelected.value = params?.selectedIds || [];
|
tableSelected.value = params?.selectedIds || [];
|
||||||
batchParams.value = { ...params, selectIds: params?.selectedIds };
|
batchParams.value = { ...params, selectIds: params?.selectedIds };
|
||||||
|
const tableParams = await getTableParams(true);
|
||||||
switch (event.eventTag) {
|
switch (event.eventTag) {
|
||||||
case 'execute':
|
case 'execute':
|
||||||
break;
|
break;
|
||||||
|
@ -517,6 +503,13 @@
|
||||||
handleBatchDisassociateCase();
|
handleBatchDisassociateCase();
|
||||||
break;
|
break;
|
||||||
case 'changeExecutor':
|
case 'changeExecutor':
|
||||||
|
batchUpdateExecutorParams.value = {
|
||||||
|
selectIds: tableSelected.value as string[],
|
||||||
|
selectAll: batchParams.value.selectAll,
|
||||||
|
excludeIds: batchParams.value?.excludeIds || [],
|
||||||
|
...tableParams,
|
||||||
|
};
|
||||||
|
batchUpdateExecutorModalVisible.value = true;
|
||||||
break;
|
break;
|
||||||
case 'move':
|
case 'move':
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -78,21 +78,6 @@
|
||||||
{{ t('common.cancelLink') }}
|
{{ t('common.cancelLink') }}
|
||||||
</MsButton>
|
</MsButton>
|
||||||
</MsPopconfirm>
|
</MsPopconfirm>
|
||||||
<a-divider
|
|
||||||
v-if="props.repeatCase"
|
|
||||||
v-permission="['PROJECT_TEST_PLAN:READ+ASSOCIATION']"
|
|
||||||
direction="vertical"
|
|
||||||
:margin="8"
|
|
||||||
></a-divider>
|
|
||||||
<MsButton
|
|
||||||
v-if="props.repeatCase"
|
|
||||||
v-permission="['PROJECT_TEST_PLAN:READ+ASSOCIATION']"
|
|
||||||
type="text"
|
|
||||||
class="!mr-0"
|
|
||||||
@click="handleCopyCase(record)"
|
|
||||||
>
|
|
||||||
{{ t('common.copy') }}
|
|
||||||
</MsButton>
|
|
||||||
</template>
|
</template>
|
||||||
</MsBaseTable>
|
</MsBaseTable>
|
||||||
<!-- 批量执行 -->
|
<!-- 批量执行 -->
|
||||||
|
@ -120,54 +105,20 @@
|
||||||
<ExecuteForm v-model:form="batchExecuteForm" />
|
<ExecuteForm v-model:form="batchExecuteForm" />
|
||||||
</a-modal>
|
</a-modal>
|
||||||
<!-- 批量修改执行人 -->
|
<!-- 批量修改执行人 -->
|
||||||
<a-modal
|
<BatchUpdateExecutorModal
|
||||||
v-model:visible="batchUpdateExecutorModalVisible"
|
v-model:visible="batchUpdateExecutorModalVisible"
|
||||||
title-align="start"
|
:count="batchParams.currentSelectCount || tableSelected.length"
|
||||||
body-class="p-0"
|
:params="batchUpdateExecutorParams"
|
||||||
:cancel-button-props="{ disabled: batchLoading }"
|
:batch-update-executor="batchUpdateCaseExecutor"
|
||||||
:ok-loading="batchLoading"
|
@load-list="resetSelectorAndCaseList"
|
||||||
:ok-button-props="{ disabled: batchUpdateExecutorDisabled }"
|
|
||||||
:ok-text="t('common.update')"
|
|
||||||
@before-ok="handleBatchUpdateExecutor"
|
|
||||||
@close="resetBatchForm"
|
|
||||||
>
|
|
||||||
<template #title>
|
|
||||||
{{ t('testPlan.featureCase.batchChangeExecutor') }}
|
|
||||||
<div class="text-[var(--color-text-4)]">
|
|
||||||
{{
|
|
||||||
t('testPlan.testPlanIndex.selectedCount', {
|
|
||||||
count: batchParams.currentSelectCount || tableSelected.length,
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<a-form ref="batchUpdateExecutorFormRef" :model="batchUpdateExecutorForm" layout="vertical">
|
|
||||||
<a-form-item
|
|
||||||
field="userId"
|
|
||||||
:label="t('testPlan.featureCase.executor')"
|
|
||||||
:rules="[{ required: true, message: t('testPlan.featureCase.requestExecutorRequired') }]"
|
|
||||||
asterisk-position="end"
|
|
||||||
class="mb-0"
|
|
||||||
>
|
|
||||||
<MsSelect
|
|
||||||
v-model:modelValue="batchUpdateExecutorForm.userId"
|
|
||||||
mode="static"
|
|
||||||
:placeholder="t('common.pleaseSelect')"
|
|
||||||
:loading="executorLoading"
|
|
||||||
:options="userOptions"
|
|
||||||
:search-keys="['label']"
|
|
||||||
allow-search
|
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
|
||||||
</a-form>
|
|
||||||
</a-modal>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onBeforeMount, ref } from 'vue';
|
import { computed, onBeforeMount, ref } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { FormInstance, Message, SelectOptionData } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
|
|
||||||
import { MsAdvanceFilter } from '@/components/pure/ms-advance-filter';
|
import { MsAdvanceFilter } from '@/components/pure/ms-advance-filter';
|
||||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||||
|
@ -182,18 +133,16 @@
|
||||||
import useTable from '@/components/pure/ms-table/useTable';
|
import useTable from '@/components/pure/ms-table/useTable';
|
||||||
import CaseLevel from '@/components/business/ms-case-associate/caseLevel.vue';
|
import CaseLevel from '@/components/business/ms-case-associate/caseLevel.vue';
|
||||||
import ExecuteResult from '@/components/business/ms-case-associate/executeResult.vue';
|
import ExecuteResult from '@/components/business/ms-case-associate/executeResult.vue';
|
||||||
import MsSelect from '@/components/business/ms-select';
|
|
||||||
import BugCountPopover from './bugCountPopover.vue';
|
import BugCountPopover from './bugCountPopover.vue';
|
||||||
|
import BatchUpdateExecutorModal from '@/views/test-plan/testPlan/components/batchUpdateExecutorModal.vue';
|
||||||
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,
|
||||||
GetTestPlanUsers,
|
|
||||||
runFeatureCase,
|
runFeatureCase,
|
||||||
sortFeatureCase,
|
sortFeatureCase,
|
||||||
} from '@/api/modules/test-plan/testPlan';
|
} from '@/api/modules/test-plan/testPlan';
|
||||||
|
@ -205,7 +154,6 @@
|
||||||
import { characterLimit } from '@/utils';
|
import { characterLimit } from '@/utils';
|
||||||
import { hasAnyPermission } from '@/utils/permission';
|
import { hasAnyPermission } from '@/utils/permission';
|
||||||
|
|
||||||
import { ReviewUserItem } from '@/models/caseManagement/caseReview';
|
|
||||||
import { DragSortParams, ModuleTreeNode } from '@/models/common';
|
import { DragSortParams, ModuleTreeNode } from '@/models/common';
|
||||||
import type {
|
import type {
|
||||||
ExecuteFeatureCaseFormParams,
|
ExecuteFeatureCaseFormParams,
|
||||||
|
@ -231,7 +179,6 @@
|
||||||
offspringIds: string[];
|
offspringIds: string[];
|
||||||
planId: string;
|
planId: string;
|
||||||
moduleTree: ModuleTreeNode[];
|
moduleTree: ModuleTreeNode[];
|
||||||
repeatCase: boolean;
|
|
||||||
canEdit: boolean;
|
canEdit: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
@ -492,6 +439,11 @@
|
||||||
loadList();
|
loadList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resetSelectorAndCaseList() {
|
||||||
|
resetSelector();
|
||||||
|
loadList();
|
||||||
|
}
|
||||||
|
|
||||||
// 拖拽排序
|
// 拖拽排序
|
||||||
async function handleDragChange(params: DragSortParams) {
|
async function handleDragChange(params: DragSortParams) {
|
||||||
try {
|
try {
|
||||||
|
@ -504,22 +456,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 复制用例
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新执行结果
|
// 更新执行结果
|
||||||
async function handleEditLastExecResult(record: PlanDetailFeatureCaseItem) {
|
async function handleEditLastExecResult(record: PlanDetailFeatureCaseItem) {
|
||||||
try {
|
try {
|
||||||
|
@ -619,61 +555,19 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 批量修改执行人
|
|
||||||
const batchUpdateExecutorFormRef = ref<FormInstance>();
|
|
||||||
const batchUpdateExecutorModalVisible = ref(false);
|
|
||||||
const batchUpdateExecutorForm = ref<{ userId: string }>({ userId: '' });
|
|
||||||
const batchUpdateExecutorDisabled = computed(() => !batchUpdateExecutorForm.value.userId.length);
|
|
||||||
const userOptions = ref<SelectOptionData[]>([]);
|
|
||||||
const executorLoading = ref(false);
|
|
||||||
async function initUserOptions() {
|
|
||||||
try {
|
|
||||||
executorLoading.value = true;
|
|
||||||
const res = await GetTestPlanUsers(appStore.currentProjectId, '');
|
|
||||||
userOptions.value = res.map((e: ReviewUserItem) => ({ label: e.name, value: e.id }));
|
|
||||||
} catch (error) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log(error);
|
|
||||||
} finally {
|
|
||||||
executorLoading.value = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleBatchUpdateExecutor() {
|
|
||||||
batchUpdateExecutorFormRef.value?.validate(async (errors) => {
|
|
||||||
if (!errors) {
|
|
||||||
try {
|
|
||||||
batchLoading.value = true;
|
|
||||||
const tableParams = await getTableParams(true);
|
|
||||||
await batchUpdateCaseExecutor({
|
|
||||||
selectIds: tableSelected.value as string[],
|
|
||||||
selectAll: batchParams.value.selectAll,
|
|
||||||
excludeIds: batchParams.value?.excludeIds || [],
|
|
||||||
...tableParams,
|
|
||||||
...batchUpdateExecutorForm.value,
|
|
||||||
});
|
|
||||||
Message.success(t('common.updateSuccess'));
|
|
||||||
resetSelector();
|
|
||||||
loadList();
|
|
||||||
} catch (error) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log(error);
|
|
||||||
} finally {
|
|
||||||
batchLoading.value = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function resetBatchForm() {
|
function resetBatchForm() {
|
||||||
batchExecuteForm.value = { ...defaultExecuteForm };
|
batchExecuteForm.value = { ...defaultExecuteForm };
|
||||||
batchUpdateExecutorForm.value = { userId: '' };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 批量修改执行人
|
||||||
|
const batchUpdateExecutorModalVisible = ref(false);
|
||||||
|
const batchUpdateExecutorParams = ref();
|
||||||
|
|
||||||
// 处理表格选中后批量操作
|
// 处理表格选中后批量操作
|
||||||
function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
|
async function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
|
||||||
tableSelected.value = params?.selectedIds || [];
|
tableSelected.value = params?.selectedIds || [];
|
||||||
batchParams.value = { ...params, selectIds: params?.selectedIds };
|
batchParams.value = { ...params, selectIds: params?.selectedIds };
|
||||||
|
const tableParams = await getTableParams(true);
|
||||||
switch (event.eventTag) {
|
switch (event.eventTag) {
|
||||||
case 'execute':
|
case 'execute':
|
||||||
batchExecuteModalVisible.value = true;
|
batchExecuteModalVisible.value = true;
|
||||||
|
@ -682,6 +576,12 @@
|
||||||
handleBatchDisassociateCase();
|
handleBatchDisassociateCase();
|
||||||
break;
|
break;
|
||||||
case 'changeExecutor':
|
case 'changeExecutor':
|
||||||
|
batchUpdateExecutorParams.value = {
|
||||||
|
selectIds: tableSelected.value as string[],
|
||||||
|
selectAll: batchParams.value.selectAll,
|
||||||
|
excludeIds: batchParams.value?.excludeIds || [],
|
||||||
|
...tableParams,
|
||||||
|
};
|
||||||
batchUpdateExecutorModalVisible.value = true;
|
batchUpdateExecutorModalVisible.value = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -707,7 +607,6 @@
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
loadCaseList();
|
loadCaseList();
|
||||||
initUserOptions();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
|
|
|
@ -19,6 +19,16 @@
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</template>
|
</template>
|
||||||
<template #headerRight>
|
<template #headerRight>
|
||||||
|
<a-switch
|
||||||
|
v-model="treeType"
|
||||||
|
size="small"
|
||||||
|
type="line"
|
||||||
|
checked-value="COLLECTION"
|
||||||
|
unchecked-value="MODULE"
|
||||||
|
class="mr-[4px]"
|
||||||
|
@change="loadActiveTabList"
|
||||||
|
/>
|
||||||
|
<span class="mr-[14px]">{{ t('testPlan.testPlanDetail.moduleView') }}</span>
|
||||||
<MsButton
|
<MsButton
|
||||||
v-if="hasAnyPermission(['PROJECT_TEST_PLAN:READ+ASSOCIATION']) && detail.status !== 'ARCHIVED'"
|
v-if="hasAnyPermission(['PROJECT_TEST_PLAN:READ+ASSOCIATION']) && detail.status !== 'ARCHIVED'"
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -108,11 +118,10 @@
|
||||||
@refresh="initDetail"
|
@refresh="initDetail"
|
||||||
/>
|
/>
|
||||||
<BugManagement v-if="activeTab === 'defectList'" :can-edit="detail.status !== 'ARCHIVED'" @refresh="initDetail" />
|
<BugManagement v-if="activeTab === 'defectList'" :can-edit="detail.status !== 'ARCHIVED'" @refresh="initDetail" />
|
||||||
<!-- TODO 切换模块视图 -->
|
|
||||||
<ApiCase
|
<ApiCase
|
||||||
v-if="activeTab === 'apiCase'"
|
v-if="activeTab === 'apiCase'"
|
||||||
ref="apiCaseRef"
|
ref="apiCaseRef"
|
||||||
tree-type="MODULE"
|
:tree-type="treeType"
|
||||||
:repeat-case="detail.repeatCase"
|
:repeat-case="detail.repeatCase"
|
||||||
:can-edit="detail.status !== 'ARCHIVED'"
|
:can-edit="detail.status !== 'ARCHIVED'"
|
||||||
@refresh="initDetail"
|
@refresh="initDetail"
|
||||||
|
@ -198,6 +207,7 @@
|
||||||
const detail = ref<TestPlanDetail>({
|
const detail = ref<TestPlanDetail>({
|
||||||
...testPlanDefaultDetail,
|
...testPlanDefaultDetail,
|
||||||
});
|
});
|
||||||
|
const treeType = ref<'MODULE' | 'COLLECTION'>('MODULE');
|
||||||
|
|
||||||
const countDetail = ref<PassRateCountDetail>({ ...defaultDetailCount });
|
const countDetail = ref<PassRateCountDetail>({ ...defaultDetailCount });
|
||||||
|
|
||||||
|
@ -419,8 +429,7 @@
|
||||||
const featureCaseRef = ref<InstanceType<typeof FeatureCase>>();
|
const featureCaseRef = ref<InstanceType<typeof FeatureCase>>();
|
||||||
const apiCaseRef = ref<InstanceType<typeof ApiCase>>();
|
const apiCaseRef = ref<InstanceType<typeof ApiCase>>();
|
||||||
const apiScenarioRef = ref<InstanceType<typeof ApiScenario>>();
|
const apiScenarioRef = ref<InstanceType<typeof ApiScenario>>();
|
||||||
function handleSuccess() {
|
function loadActiveTabList() {
|
||||||
initDetail();
|
|
||||||
switch (activeTab.value) {
|
switch (activeTab.value) {
|
||||||
case 'featureCase':
|
case 'featureCase':
|
||||||
featureCaseRef.value?.getCaseTableList();
|
featureCaseRef.value?.getCaseTableList();
|
||||||
|
@ -435,6 +444,10 @@
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function handleSuccess() {
|
||||||
|
initDetail();
|
||||||
|
loadActiveTabList();
|
||||||
|
}
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
initDetail();
|
initDetail();
|
||||||
|
|
|
@ -89,6 +89,7 @@ export default {
|
||||||
'testPlan.planForm.pickCases': 'Select cases',
|
'testPlan.planForm.pickCases': 'Select cases',
|
||||||
'testPlan.testPlanDetail.executed': 'Executed',
|
'testPlan.testPlanDetail.executed': 'Executed',
|
||||||
'testPlan.testPlanDetail.generateReport': 'Generate report',
|
'testPlan.testPlanDetail.generateReport': 'Generate report',
|
||||||
|
'testPlan.testPlanDetail.moduleView': 'Module View',
|
||||||
'testPlan.testPlanDetail.successfullyGenerated': 'Successfully generated',
|
'testPlan.testPlanDetail.successfullyGenerated': 'Successfully generated',
|
||||||
'testPlan.bugManagement.bug': 'Defect list',
|
'testPlan.bugManagement.bug': 'Defect list',
|
||||||
'testPlan.bugManagement.bugName': 'name',
|
'testPlan.bugManagement.bugName': 'name',
|
||||||
|
|
|
@ -84,6 +84,7 @@ export default {
|
||||||
'testPlan.planForm.pickCases': '选择用例',
|
'testPlan.planForm.pickCases': '选择用例',
|
||||||
'testPlan.testPlanDetail.executed': '已执行',
|
'testPlan.testPlanDetail.executed': '已执行',
|
||||||
'testPlan.testPlanDetail.generateReport': '生成报告',
|
'testPlan.testPlanDetail.generateReport': '生成报告',
|
||||||
|
'testPlan.testPlanDetail.moduleView': '模块视图',
|
||||||
'testPlan.testPlanDetail.successfullyGenerated': '生成成功',
|
'testPlan.testPlanDetail.successfullyGenerated': '生成成功',
|
||||||
'testPlan.bugManagement.bug': '缺陷列表',
|
'testPlan.bugManagement.bug': '缺陷列表',
|
||||||
'testPlan.bugManagement.bugName': '名称',
|
'testPlan.bugManagement.bugName': '名称',
|
||||||
|
|
Loading…
Reference in New Issue