mirror of
https://gitee.com/fit2cloud-feizhiyun/MeterSphere.git
synced 2024-12-02 20:19:16 +08:00
feat(测试计划): 测试计划详情-接口用例页面联调和取消关联
This commit is contained in:
parent
b3283e3d78
commit
5ad2775eb8
@ -7,6 +7,7 @@ import {
|
||||
batchArchivedPlanUrl,
|
||||
batchCopyPlanUrl,
|
||||
batchDeletePlanUrl,
|
||||
BatchDisassociateApiCaseUrl,
|
||||
BatchDisassociateCaseUrl,
|
||||
BatchEditTestPlanUrl,
|
||||
batchMovePlanUrl,
|
||||
@ -17,15 +18,19 @@ import {
|
||||
deletePlanUrl,
|
||||
DeleteScheduleTaskUrl,
|
||||
DeleteTestPlanModuleUrl,
|
||||
DisassociateApiCaseUrl,
|
||||
DisassociateCaseUrl,
|
||||
dragPlanOnGroupUrl,
|
||||
ExecuteHistoryUrl,
|
||||
ExecutePlanUrl,
|
||||
followPlanUrl,
|
||||
GenerateReportUrl,
|
||||
GetApiCaseModuleCountUrl,
|
||||
GetApiCaseModuleUrl,
|
||||
GetAssociatedBugUrl,
|
||||
GetFeatureCaseModuleCountUrl,
|
||||
GetFeatureCaseModuleUrl,
|
||||
GetPlanDetailApiCaseListUrl,
|
||||
GetPlanDetailFeatureCaseListUrl,
|
||||
getStatisticalCountUrl,
|
||||
GetTestPlanCaseListUrl,
|
||||
@ -59,6 +64,7 @@ import { DragSortParams, ModuleTreeNode } from '@/models/common';
|
||||
import type {
|
||||
AddTestPlanParams,
|
||||
AssociateCaseRequestType,
|
||||
BatchApiCaseParams,
|
||||
BatchExecuteFeatureCaseParams,
|
||||
BatchFeatureCaseParams,
|
||||
BatchUpdateCaseExecutorParams,
|
||||
@ -70,6 +76,8 @@ import type {
|
||||
FollowPlanParams,
|
||||
PassRateCountDetail,
|
||||
PlanDetailApiCaseItem,
|
||||
PlanDetailApiCaseQueryParams,
|
||||
PlanDetailApiCaseTreeParams,
|
||||
PlanDetailApiScenarioItem,
|
||||
PlanDetailBugItem,
|
||||
PlanDetailExecuteHistoryItem,
|
||||
@ -253,9 +261,25 @@ export function testPlanCancelBug(id: string) {
|
||||
export function executeHistory(data: ExecuteHistoryType) {
|
||||
return MSR.post<ExecuteHistoryItem[]>({ url: ExecuteHistoryUrl, data });
|
||||
}
|
||||
// 计划详情-接口用例列表 TODO 联调
|
||||
export function getPlanDetailApiCaseList(data: PlanDetailFeatureCaseListQueryParams) {
|
||||
return MSR.post<CommonList<PlanDetailApiCaseItem>>({ url: GetPlanDetailFeatureCaseListUrl, data });
|
||||
// 计划详情-接口用例列表
|
||||
export function getPlanDetailApiCaseList(data: PlanDetailApiCaseQueryParams) {
|
||||
return MSR.post<CommonList<PlanDetailApiCaseItem>>({ url: GetPlanDetailApiCaseListUrl, data });
|
||||
}
|
||||
// 计划详情-接口用例模块树
|
||||
export function getApiCaseModule(data: PlanDetailApiCaseTreeParams) {
|
||||
return MSR.post<ModuleTreeNode[]>({ url: GetApiCaseModuleUrl, data });
|
||||
}
|
||||
// 计划详情-接口用例-获取模块数量
|
||||
export function getApiCaseModuleCount(data: PlanDetailApiCaseQueryParams) {
|
||||
return MSR.post({ url: GetApiCaseModuleCountUrl, data });
|
||||
}
|
||||
// 计划详情-接口用例列表-取消关联用例
|
||||
export function disassociateApiCase(data: DisassociateCaseParams) {
|
||||
return MSR.post({ url: DisassociateApiCaseUrl, data });
|
||||
}
|
||||
// 计划详情-接口用例列表-批量取消关联用例
|
||||
export function batchDisassociateApiCase(data: BatchApiCaseParams) {
|
||||
return MSR.post({ url: BatchDisassociateApiCaseUrl, data });
|
||||
}
|
||||
// 计划详情-接口场景列表 TODO 联调
|
||||
export function getPlanDetailApiScenarioList(data: PlanDetailFeatureCaseListQueryParams) {
|
||||
|
@ -96,3 +96,13 @@ export const ConfigScheduleUrl = '/test-plan/schedule-config';
|
||||
export const ExecutePlanUrl = '/test-plan-execute/start';
|
||||
// 测试计划-删除定时任务
|
||||
export const DeleteScheduleTaskUrl = 'test-plan/schedule-config-delete';
|
||||
// 计划详情-接口用例列表
|
||||
export const GetPlanDetailApiCaseListUrl = '/test-plan/api/case/page';
|
||||
// 计划详情-接口用例模块树
|
||||
export const GetApiCaseModuleUrl = '/test-plan/api/case/tree';
|
||||
// 计划详情-接口用例列表-取消关联用例
|
||||
export const DisassociateApiCaseUrl = '/test-plan/api/case/disassociate';
|
||||
// 计划详情-接口用例列表-批量取消关联用例
|
||||
export const BatchDisassociateApiCaseUrl = '/test-plan/api/case/batch/disassociate';
|
||||
// 计划详情-接口用例-获取模块数量
|
||||
export const GetApiCaseModuleCountUrl = '/test-plan/api/case/module/count';
|
||||
|
@ -257,24 +257,48 @@ export interface BatchMoveParams extends TableQueryParams {
|
||||
targetId?: string | number;
|
||||
}
|
||||
|
||||
// TODO: 联调
|
||||
// 计划详情-接口用例
|
||||
export interface PlanDetailApiCaseQueryParams extends TableQueryParams, TestPlanBaseParams {
|
||||
apiDefinitionId?: string;
|
||||
protocols: string[];
|
||||
moduleIds?: string[];
|
||||
versionId?: string;
|
||||
refId?: string;
|
||||
collectionId?: string;
|
||||
}
|
||||
|
||||
export interface PlanDetailApiCaseTreeParams {
|
||||
testPlanId: string;
|
||||
treeType: 'MODULE' | 'COLLECTION';
|
||||
}
|
||||
|
||||
export interface PlanDetailApiCaseItem {
|
||||
id: string;
|
||||
num: string;
|
||||
num: number;
|
||||
name: string;
|
||||
moduleId: string;
|
||||
versionName: string;
|
||||
createUser: string;
|
||||
createUserName: string;
|
||||
lastExecResult: LastExecuteResults;
|
||||
lastExecTime: number;
|
||||
lastExecResultReportId: string;
|
||||
executeUser: string;
|
||||
executeUserName: string;
|
||||
bugCount: number;
|
||||
customFields: customFieldsItem[]; // 自定义字段集合
|
||||
caseId: string;
|
||||
priority: string;
|
||||
path: string;
|
||||
projectId: string;
|
||||
projectName: string;
|
||||
environmentId: string;
|
||||
environmentName: string;
|
||||
testPlanCollectionId: string;
|
||||
collectEnvironmentId: string;
|
||||
}
|
||||
|
||||
export interface BatchApiCaseParams extends BatchActionQueryParams {
|
||||
testPlanId: string;
|
||||
lastExecResultReportId: string;
|
||||
moduleIds?: string[];
|
||||
collectionId?: string;
|
||||
protocols: string[];
|
||||
}
|
||||
|
||||
// TODO: 联调
|
||||
|
@ -21,7 +21,11 @@
|
||||
<a-dsubmenu>
|
||||
<template #default>{{ t('ms.paramsInput.protocol') }}</template>
|
||||
<template #content>
|
||||
<a-checkbox :model-value="isCheckedAll" :indeterminate="indeterminate" @change="handleChangeAll"
|
||||
<a-checkbox
|
||||
class="checkbox-all"
|
||||
:model-value="isCheckedAll"
|
||||
:indeterminate="indeterminate"
|
||||
@change="handleChangeAll"
|
||||
>{{ t('common.all') }}
|
||||
</a-checkbox>
|
||||
<a-checkbox-group direction="vertical" :model-value="selectedProtocols" @change="handleGroupChange">
|
||||
@ -34,7 +38,11 @@
|
||||
</template>
|
||||
<!-- 没有 展开请求的开关 -->
|
||||
<template v-else>
|
||||
<a-checkbox :model-value="isCheckedAll" :indeterminate="indeterminate" @change="handleChangeAll"
|
||||
<a-checkbox
|
||||
class="checkbox-all"
|
||||
:model-value="isCheckedAll"
|
||||
:indeterminate="indeterminate"
|
||||
@change="handleChangeAll"
|
||||
>{{ t('common.all') }}
|
||||
</a-checkbox>
|
||||
<a-checkbox-group direction="vertical" :model-value="selectedProtocols" @change="handleGroupChange">
|
||||
@ -141,7 +149,17 @@
|
||||
.arco-dropdown {
|
||||
padding: 8px;
|
||||
.arco-dropdown-list .arco-dropdown-option {
|
||||
margin: 0;
|
||||
width: 107px;
|
||||
}
|
||||
.checkbox-all {
|
||||
border-bottom: 1px solid var(--color-text-n8);
|
||||
}
|
||||
.arco-checkbox {
|
||||
padding: 6px 12px;
|
||||
line-height: 24px;
|
||||
}
|
||||
.arco-switch {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
.api-expend {
|
||||
|
@ -84,7 +84,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onBeforeMount, ref } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
import { MsAdvanceFilter } from '@/components/pure/ms-advance-filter';
|
||||
@ -105,8 +105,8 @@
|
||||
|
||||
import {
|
||||
associationCaseToPlan,
|
||||
batchDisassociateCase,
|
||||
disassociateCase,
|
||||
batchDisassociateApiCase,
|
||||
disassociateApiCase,
|
||||
getPlanDetailApiCaseList,
|
||||
sortFeatureCase,
|
||||
} from '@/api/modules/test-plan/testPlan';
|
||||
@ -118,7 +118,7 @@
|
||||
import { hasAnyPermission } from '@/utils/permission';
|
||||
|
||||
import { DragSortParams, ModuleTreeNode } from '@/models/common';
|
||||
import type { PlanDetailApiCaseItem, PlanDetailFeatureCaseListQueryParams } from '@/models/testPlan/testPlan';
|
||||
import type { PlanDetailApiCaseItem, PlanDetailApiCaseQueryParams } from '@/models/testPlan/testPlan';
|
||||
import { LastExecuteResults } from '@/enums/caseEnum';
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
import { FilterSlotNameEnum } from '@/enums/tableFilterEnum';
|
||||
@ -139,10 +139,11 @@
|
||||
moduleTree: ModuleTreeNode[];
|
||||
repeatCase: boolean;
|
||||
canEdit: boolean;
|
||||
selectedProtocols: string[];
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'getModuleCount', params: PlanDetailFeatureCaseListQueryParams): void;
|
||||
(e: 'getModuleCount', params: PlanDetailApiCaseQueryParams): void;
|
||||
(e: 'refresh'): void;
|
||||
(e: 'initModules'): void;
|
||||
}>();
|
||||
@ -352,6 +353,8 @@
|
||||
testPlanId: props.planId,
|
||||
projectId: appStore.currentProjectId,
|
||||
moduleIds: selectModules,
|
||||
protocols: props.selectedProtocols,
|
||||
collectionId: props.activeModule,
|
||||
};
|
||||
if (isBatch) {
|
||||
return {
|
||||
@ -379,12 +382,9 @@
|
||||
pageSize: propsRes.value.msPagination?.pageSize,
|
||||
});
|
||||
}
|
||||
watch(
|
||||
() => props.activeModule,
|
||||
() => {
|
||||
loadCaseList();
|
||||
}
|
||||
);
|
||||
watch([() => props.activeModule, () => props.selectedProtocols], () => {
|
||||
loadCaseList();
|
||||
});
|
||||
|
||||
async function getModuleCount() {
|
||||
const tableParams = await getTableParams(false);
|
||||
@ -400,7 +400,7 @@
|
||||
const reportId = ref('');
|
||||
function showReport(record: PlanDetailApiCaseItem) {
|
||||
reportVisible.value = true;
|
||||
reportId.value = record.lastExecResultReportId; // TODO 联调
|
||||
reportId.value = record.lastExecResultReportId;
|
||||
}
|
||||
|
||||
const tableSelected = ref<(string | number)[]>([]); // 表格选中的
|
||||
@ -439,7 +439,7 @@
|
||||
try {
|
||||
// TODO 联调
|
||||
await associationCaseToPlan({
|
||||
functionalSelectIds: [record.caseId],
|
||||
functionalSelectIds: [record.id],
|
||||
testPlanId: props.planId,
|
||||
});
|
||||
Message.success(t('ms.case.associate.associateSuccess'));
|
||||
@ -456,8 +456,7 @@
|
||||
async function handleDisassociateCase(record: PlanDetailApiCaseItem, done?: () => void) {
|
||||
try {
|
||||
disassociateLoading.value = true;
|
||||
// TODO 联调
|
||||
await disassociateCase({ testPlanId: props.planId, id: record.id });
|
||||
await disassociateApiCase({ testPlanId: props.planId, id: record.id });
|
||||
if (done) {
|
||||
done();
|
||||
}
|
||||
@ -486,8 +485,7 @@
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
const tableParams = await getTableParams(true);
|
||||
// TODO 联调
|
||||
await batchDisassociateCase({
|
||||
await batchDisassociateApiCase({
|
||||
selectIds: tableSelected.value as string[],
|
||||
selectAll: batchParams.value.selectAll,
|
||||
excludeIds: batchParams.value?.excludeIds || [],
|
||||
@ -525,10 +523,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
loadCaseList();
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
resetSelector,
|
||||
loadCaseList,
|
||||
|
@ -15,6 +15,7 @@
|
||||
:all-count="allCount"
|
||||
:show-expand-api="false"
|
||||
@set-active-folder="setActiveFolder"
|
||||
@selected-protocols-change="selectedProtocolsChange"
|
||||
/>
|
||||
<a-divider class="my-[8px]" />
|
||||
<a-spin class="min-h-[200px] w-full" :loading="loading">
|
||||
@ -48,7 +49,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onBeforeMount, ref, watch } from 'vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useVModel } from '@vueuse/core';
|
||||
|
||||
@ -56,7 +57,7 @@
|
||||
import type { MsTreeNodeData } from '@/components/business/ms-tree/types';
|
||||
import TreeFolderAll from '@/views/api-test/components/treeFolderAll.vue';
|
||||
|
||||
import { getFeatureCaseModule } from '@/api/modules/test-plan/testPlan';
|
||||
import { getApiCaseModule } from '@/api/modules/test-plan/testPlan';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { mapTree } from '@/utils';
|
||||
|
||||
@ -65,10 +66,12 @@
|
||||
const props = defineProps<{
|
||||
modulesCount?: Record<string, number>; // 模块数量统计对象
|
||||
selectedKeys: string[]; // 选中的节点 key
|
||||
treeType: 'MODULE' | 'COLLECTION';
|
||||
}>();
|
||||
const emit = defineEmits<{
|
||||
(e: 'folderNodeSelect', ids: string[], _offspringIds: string[], nodeName?: string): void;
|
||||
(e: 'init', params: ModuleTreeNode[]): void;
|
||||
(e: 'changeProtocol', selectedProtocols: string[]): void;
|
||||
}>();
|
||||
|
||||
const route = useRoute();
|
||||
@ -102,8 +105,7 @@
|
||||
async function initModules() {
|
||||
try {
|
||||
loading.value = true;
|
||||
// TODO 联调
|
||||
const res = await getFeatureCaseModule(route.query.id as string);
|
||||
const res = await getApiCaseModule({ testPlanId: route.query.id as string, treeType: props.treeType });
|
||||
folderTree.value = mapTree<ModuleTreeNode>(res, (node) => {
|
||||
return {
|
||||
...node,
|
||||
@ -130,10 +132,6 @@
|
||||
emit('folderNodeSelect', _selectedKeys as string[], offspringIds, node.name);
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
initModules();
|
||||
});
|
||||
|
||||
// 初始化模块文件数量
|
||||
watch(
|
||||
() => props.modulesCount,
|
||||
@ -148,6 +146,11 @@
|
||||
}
|
||||
);
|
||||
|
||||
function selectedProtocolsChange() {
|
||||
emit('changeProtocol', selectedProtocols.value);
|
||||
initModules();
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
initModules,
|
||||
});
|
||||
|
@ -5,8 +5,10 @@
|
||||
ref="caseTreeRef"
|
||||
:modules-count="modulesCount"
|
||||
:selected-keys="selectedKeys"
|
||||
:tree-type="props.treeType"
|
||||
@folder-node-select="handleFolderNodeSelect"
|
||||
@init="initModuleTree"
|
||||
@change-protocol="handleProtocolChange"
|
||||
/>
|
||||
</template>
|
||||
<template #second>
|
||||
@ -20,6 +22,7 @@
|
||||
:offspring-ids="offspringIds"
|
||||
:module-tree="moduleTree"
|
||||
:can-edit="props.canEdit"
|
||||
:selected-protocols="selectedProtocols"
|
||||
@get-module-count="getModuleCount"
|
||||
@refresh="emit('refresh')"
|
||||
@init-modules="initModules"
|
||||
@ -36,14 +39,15 @@
|
||||
import CaseTable from './components/caseTable.vue';
|
||||
import CaseTree from './components/caseTree.vue';
|
||||
|
||||
import { getFeatureCaseModuleCount } from '@/api/modules/test-plan/testPlan';
|
||||
import { getApiCaseModuleCount } from '@/api/modules/test-plan/testPlan';
|
||||
|
||||
import { ModuleTreeNode } from '@/models/common';
|
||||
import type { PlanDetailFeatureCaseListQueryParams } from '@/models/testPlan/testPlan';
|
||||
import type { PlanDetailApiCaseQueryParams } from '@/models/testPlan/testPlan';
|
||||
|
||||
const props = defineProps<{
|
||||
repeatCase: boolean;
|
||||
canEdit: boolean;
|
||||
treeType: 'MODULE' | 'COLLECTION';
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
@ -54,10 +58,13 @@
|
||||
|
||||
const planId = ref(route.query.id as string);
|
||||
const modulesCount = ref<Record<string, any>>({});
|
||||
async function getModuleCount(params: PlanDetailFeatureCaseListQueryParams) {
|
||||
const selectedProtocols = ref<string[]>([]);
|
||||
function handleProtocolChange(val: string[]) {
|
||||
selectedProtocols.value = val;
|
||||
}
|
||||
async function getModuleCount(params: PlanDetailApiCaseQueryParams) {
|
||||
try {
|
||||
// TODO 联调
|
||||
modulesCount.value = await getFeatureCaseModuleCount(params);
|
||||
modulesCount.value = await getApiCaseModuleCount(params);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
|
@ -108,9 +108,11 @@
|
||||
@refresh="initDetail"
|
||||
/>
|
||||
<BugManagement v-if="activeTab === 'defectList'" :can-edit="detail.status !== 'ARCHIVED'" @refresh="initDetail" />
|
||||
<!-- TODO 切换模块视图 -->
|
||||
<ApiCase
|
||||
v-if="activeTab === 'apiCase'"
|
||||
ref="apiCaseRef"
|
||||
tree-type="MODULE"
|
||||
:repeat-case="detail.repeatCase"
|
||||
:can-edit="detail.status !== 'ARCHIVED'"
|
||||
@refresh="initDetail"
|
||||
|
Loading…
Reference in New Issue
Block a user