feat(测试计划): 测试计划详情-功能用例列表-批量执行和批量修改执行人
This commit is contained in:
parent
1d3331f5ff
commit
7a1b2f96c6
|
@ -9,6 +9,8 @@ import {
|
|||
batchDeletePlanUrl,
|
||||
BatchDisassociateCaseUrl,
|
||||
batchMovePlanUrl,
|
||||
BatchRunCaseUrl,
|
||||
BatchUpdateCaseExecutorUrl,
|
||||
copyTestPlanUrl,
|
||||
deletePlanUrl,
|
||||
DeleteTestPlanModuleUrl,
|
||||
|
@ -36,7 +38,9 @@ import { ModuleTreeNode } from '@/models/common';
|
|||
import type {
|
||||
AddTestPlanParams,
|
||||
AssociateCaseRequestType,
|
||||
BatchExecuteFeatureCaseParams,
|
||||
BatchFeatureCaseParams,
|
||||
BatchUpdateCaseExecutorParams,
|
||||
DisassociateCaseParams,
|
||||
FollowPlanParams,
|
||||
PassRateCountDetail,
|
||||
|
@ -166,6 +170,14 @@ export function disassociateCase(data: DisassociateCaseParams) {
|
|||
export function batchDisassociateCase(data: BatchFeatureCaseParams) {
|
||||
return MSR.post({ url: BatchDisassociateCaseUrl, data });
|
||||
}
|
||||
// 计划详情-功能用例列表-批量执行
|
||||
export function batchExecuteCase(data: BatchExecuteFeatureCaseParams) {
|
||||
return MSR.post({ url: BatchRunCaseUrl, data });
|
||||
}
|
||||
// 计划详情-功能用例列表-批量更新执行人
|
||||
export function batchUpdateCaseExecutor(data: BatchUpdateCaseExecutorParams) {
|
||||
return MSR.post({ url: BatchUpdateCaseExecutorUrl, data });
|
||||
}
|
||||
// 计划详情-功能用例-执行
|
||||
export function runFeatureCase(data: RunFeatureCaseParams) {
|
||||
return MSR.post({ url: RunFeatureCaseUrl, data });
|
||||
|
|
|
@ -54,3 +54,7 @@ export const DisassociateCaseUrl = '/test-plan/functional/case/disassociate';
|
|||
export const BatchDisassociateCaseUrl = '/test-plan/functional/case/batch/disassociate';
|
||||
// 计划详情-功能用例-执行
|
||||
export const RunFeatureCaseUrl = '/test-plan/functional/case/run';
|
||||
// 计划详情-功能用例-批量执行
|
||||
export const BatchRunCaseUrl = '/test-plan/functional/case/batch/run';
|
||||
// 计划详情-功能用例-批量更新执行人
|
||||
export const BatchUpdateCaseExecutorUrl = '/test-plan/functional/case/batch/update/executor';
|
||||
|
|
|
@ -162,6 +162,30 @@ export interface DisassociateCaseParams {
|
|||
export interface BatchFeatureCaseParams extends BatchActionQueryParams {
|
||||
testPlanId: string;
|
||||
moduleIds?: string[];
|
||||
projectId: string;
|
||||
}
|
||||
|
||||
export interface ExecuteFeatureCaseFormParams {
|
||||
lastExecResult: LastExecuteResults;
|
||||
content?: string;
|
||||
commentIds?: string[];
|
||||
planCommentFileIds?: string[];
|
||||
}
|
||||
|
||||
export interface RunFeatureCaseParams extends ExecuteFeatureCaseFormParams {
|
||||
projectId: string;
|
||||
id: string;
|
||||
testPlanId: string;
|
||||
caseId: string;
|
||||
notifier?: string;
|
||||
}
|
||||
|
||||
export interface BatchExecuteFeatureCaseParams extends BatchFeatureCaseParams, ExecuteFeatureCaseFormParams {
|
||||
notifier?: string;
|
||||
}
|
||||
|
||||
export interface BatchUpdateCaseExecutorParams extends BatchFeatureCaseParams {
|
||||
userId: string;
|
||||
}
|
||||
|
||||
export interface PassRateCountDetail {
|
||||
|
@ -180,19 +204,4 @@ export interface PassRateCountDetail {
|
|||
apiScenarioCount: number;
|
||||
}
|
||||
|
||||
export interface ExecuteFeatureCaseFormParams {
|
||||
lastExecResult: LastExecuteResults;
|
||||
content?: string;
|
||||
commentIds?: string[];
|
||||
planCommentFileIds?: string[];
|
||||
}
|
||||
|
||||
export interface RunFeatureCaseParams extends ExecuteFeatureCaseFormParams {
|
||||
projectId: string;
|
||||
id: string;
|
||||
testPlanId: string;
|
||||
caseId: string;
|
||||
notifier?: string;
|
||||
}
|
||||
|
||||
export default {};
|
||||
|
|
|
@ -47,7 +47,12 @@
|
|||
<span v-else class="text-[var(--color-text-2)]"><ExecuteResult :execute-result="record.lastExecResult" /></span>
|
||||
</template>
|
||||
<template #operation="{ record }">
|
||||
<MsButton v-permission="['PROJECT_API_DEFINITION_CASE:READ+EXECUTE']" type="text" class="!mr-0">
|
||||
<MsButton
|
||||
v-permission="['PROJECT_API_DEFINITION_CASE:READ+EXECUTE']"
|
||||
type="text"
|
||||
class="!mr-0"
|
||||
@click="toCaseDetail(record)"
|
||||
>
|
||||
{{ t('common.execute') }}
|
||||
</MsButton>
|
||||
<a-divider v-permission="['PROJECT_TEST_PLAN:READ+ASSOCIATION']" direction="vertical" :margin="8"></a-divider>
|
||||
|
@ -74,13 +79,79 @@
|
|||
</MsButton>
|
||||
</template>
|
||||
</MsBaseTable>
|
||||
<!-- 批量执行 -->
|
||||
<a-modal
|
||||
v-model:visible="batchExecuteModalVisible"
|
||||
title-align="start"
|
||||
body-class="p-0"
|
||||
:width="800"
|
||||
:cancel-button-props="{ disabled: batchLoading }"
|
||||
:ok-loading="batchLoading"
|
||||
:ok-text="t('caseManagement.caseReview.commitResult')"
|
||||
@before-ok="handleBatchExecute"
|
||||
@close="resetBatchForm"
|
||||
>
|
||||
<template #title>
|
||||
{{ t('testPlan.testPlanIndex.batchExecution') }}
|
||||
<div class="text-[var(--color-text-4)]">
|
||||
{{
|
||||
t('testPlan.testPlanIndex.selectedCount', {
|
||||
count: batchParams.currentSelectCount || tableSelected.length,
|
||||
})
|
||||
}}
|
||||
</div>
|
||||
</template>
|
||||
<ExecuteForm v-model:form="batchExecuteForm" />
|
||||
</a-modal>
|
||||
<!-- 批量修改执行人 -->
|
||||
<a-modal
|
||||
v-model:visible="batchUpdateExecutorModalVisible"
|
||||
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: 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="batchLoading"
|
||||
:options="userOptions"
|
||||
:search-keys="['label']"
|
||||
allow-search
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onBeforeMount, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { FormInstance, Message, SelectOptionData } from '@arco-design/web-vue';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsPopconfirm from '@/components/pure/ms-popconfirm/index.vue';
|
||||
|
@ -89,12 +160,17 @@
|
|||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
import CaseLevel from '@/components/business/ms-case-associate/caseLevel.vue';
|
||||
import ExecuteResult from '@/components/business/ms-case-associate/executeResult.vue';
|
||||
import MsSelect from '@/components/business/ms-select';
|
||||
import ExecuteForm from '@/views/test-plan/testPlan/detail/featureCase/components/executeForm.vue';
|
||||
|
||||
import {
|
||||
batchDisassociateCase,
|
||||
batchExecuteCase,
|
||||
batchUpdateCaseExecutor,
|
||||
disassociateCase,
|
||||
getPlanDetailFeatureCaseList,
|
||||
} from '@/api/modules/test-plan/testPlan';
|
||||
import { defaultExecuteForm } from '@/config/testPlan';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useModal from '@/hooks/useModal';
|
||||
import useTableStore from '@/hooks/useTableStore';
|
||||
|
@ -102,7 +178,11 @@
|
|||
import { hasAnyPermission } from '@/utils/permission';
|
||||
|
||||
import { ModuleTreeNode } from '@/models/common';
|
||||
import type { PlanDetailFeatureCaseItem, PlanDetailFeatureCaseListQueryParams } from '@/models/testPlan/testPlan';
|
||||
import type {
|
||||
ExecuteFeatureCaseFormParams,
|
||||
PlanDetailFeatureCaseItem,
|
||||
PlanDetailFeatureCaseListQueryParams,
|
||||
} from '@/models/testPlan/testPlan';
|
||||
import { LastExecuteResults } from '@/enums/caseEnum';
|
||||
import { TestPlanRouteEnum } from '@/enums/routeEnum';
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
|
@ -124,6 +204,7 @@
|
|||
|
||||
const emit = defineEmits<{
|
||||
(e: 'getModuleCount', params: PlanDetailFeatureCaseListQueryParams): void;
|
||||
(e: 'executeDone'): void;
|
||||
}>();
|
||||
|
||||
const { t } = useI18n();
|
||||
|
@ -270,14 +351,6 @@
|
|||
eventTag: 'disassociate',
|
||||
permission: ['PROJECT_TEST_PLAN:READ+ASSOCIATION'],
|
||||
},
|
||||
{
|
||||
isDivider: true,
|
||||
},
|
||||
{
|
||||
label: 'common.delete',
|
||||
eventTag: 'delete',
|
||||
danger: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
|
@ -362,16 +435,79 @@
|
|||
});
|
||||
}
|
||||
|
||||
// 批量执行
|
||||
const batchLoading = ref(false);
|
||||
const batchExecuteModalVisible = ref(false);
|
||||
const batchExecuteForm = ref<ExecuteFeatureCaseFormParams>({ ...defaultExecuteForm });
|
||||
async function handleBatchExecute() {
|
||||
try {
|
||||
batchLoading.value = true;
|
||||
await batchExecuteCase({
|
||||
...batchParams.value,
|
||||
...tableParams.value,
|
||||
...batchExecuteForm.value,
|
||||
notifier: batchExecuteForm.value?.commentIds?.join(';'),
|
||||
});
|
||||
Message.success(t('common.updateSuccess'));
|
||||
resetSelector();
|
||||
loadList();
|
||||
emit('executeDone');
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
} finally {
|
||||
batchLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 批量修改执行人
|
||||
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[]>([]); // TODO 接口联调
|
||||
async function handleBatchUpdateExecutor() {
|
||||
batchUpdateExecutorFormRef.value?.validate(async (errors) => {
|
||||
if (!errors) {
|
||||
try {
|
||||
batchLoading.value = true;
|
||||
await batchUpdateCaseExecutor({
|
||||
...batchParams.value,
|
||||
...tableParams.value,
|
||||
...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() {
|
||||
batchExecuteForm.value = { ...defaultExecuteForm };
|
||||
batchUpdateExecutorForm.value = { userId: '' };
|
||||
}
|
||||
|
||||
// 处理表格选中后批量操作
|
||||
function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
|
||||
tableSelected.value = params?.selectedIds || [];
|
||||
batchParams.value = params;
|
||||
switch (event.eventTag) {
|
||||
case 'execute':
|
||||
batchExecuteModalVisible.value = true;
|
||||
break;
|
||||
case 'disassociate':
|
||||
handleBatchDisassociateCase();
|
||||
break;
|
||||
case 'changeExecutor':
|
||||
batchUpdateExecutorModalVisible.value = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
import { executionResultMap } from '@/views/case-management/caseManagementFeature/components/utils';
|
||||
|
||||
const form = defineModel<ExecuteFeatureCaseFormParams>('form', {
|
||||
default: () => ({ ...defaultExecuteForm }),
|
||||
required: true,
|
||||
});
|
||||
|
||||
const formRef = ref<FormInstance>();
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
:offspring-ids="offspringIds"
|
||||
:module-tree="moduleTree"
|
||||
@get-module-count="getModuleCount"
|
||||
@execute-done="emit('executeDone')"
|
||||
></CaseTable>
|
||||
</template>
|
||||
</MsSplitBox>
|
||||
|
@ -36,6 +37,10 @@
|
|||
import { ModuleTreeNode } from '@/models/common';
|
||||
import type { PlanDetailFeatureCaseListQueryParams } from '@/models/testPlan/testPlan';
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'executeDone'): void;
|
||||
}>();
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const planId = ref(route.query.id as string);
|
||||
|
|
|
@ -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'" />
|
||||
<FeatureCase v-if="activeTab === 'featureCase'" @execute-done="getStatistics" />
|
||||
<!-- TODO 先不上 -->
|
||||
<!-- <BugManagement v-if="activeTab === 'defectList'" :plan-id="detail.id" /> -->
|
||||
</MsCard>
|
||||
|
|
|
@ -90,6 +90,8 @@ export default {
|
|||
'testPlan.featureCase.bugCount': 'Bug count',
|
||||
'testPlan.featureCase.executor': 'Executor',
|
||||
'testPlan.featureCase.changeExecutor': 'Change executor',
|
||||
'testPlan.featureCase.batchChangeExecutor': 'Batch modification executor',
|
||||
'testPlan.featureCase.requestExecutorRequired': 'Executor cannot be empty',
|
||||
'testPlan.featureCase.sort': 'sort',
|
||||
'testPlan.featureCase.executionHistory': 'Execution History',
|
||||
'testPlan.featureCase.noBugDataTooltip': 'No related defects, please',
|
||||
|
|
|
@ -88,6 +88,8 @@ export default {
|
|||
'testPlan.featureCase.bugCount': '缺陷数',
|
||||
'testPlan.featureCase.executor': '执行人',
|
||||
'testPlan.featureCase.changeExecutor': '修改执行人',
|
||||
'testPlan.featureCase.batchChangeExecutor': '批量修改执行人',
|
||||
'testPlan.featureCase.requestExecutorRequired': '执行人不能为空',
|
||||
'testPlan.featureCase.sort': '排序',
|
||||
'testPlan.featureCase.executionHistory': '执行历史',
|
||||
'testPlan.featureCase.noBugDataTooltip': '暂无可关联缺陷,请 ',
|
||||
|
|
Loading…
Reference in New Issue