feat(测试计划): 高级筛选-计划详情页-接口用例
This commit is contained in:
parent
754f107737
commit
b08ce1508b
|
@ -311,7 +311,7 @@ export function getPlanDetailApiCaseList(data: PlanDetailApiCaseQueryParams) {
|
|||
}
|
||||
// 计划详情-接口用例模块树
|
||||
export function getApiCaseModule(data: PlanDetailApiCaseTreeParams) {
|
||||
return MSR.post<ModuleTreeNode[]>({ url: GetApiCaseModuleUrl, data });
|
||||
return MSR.post<ModuleTreeNode[]>({ url: GetApiCaseModuleUrl, data }, { ignoreCancelToken: true });
|
||||
}
|
||||
// 计划详情-接口用例-获取模块数量
|
||||
export function getApiCaseModuleCount(data: PlanDetailApiCaseQueryParams) {
|
||||
|
|
|
@ -180,6 +180,7 @@
|
|||
|
||||
defineExpose({
|
||||
selectedProtocols,
|
||||
allProtocolList,
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
<template>
|
||||
<div class="p-[16px]">
|
||||
<MsAdvanceFilter
|
||||
ref="msAdvanceFilterRef"
|
||||
v-model:keyword="keyword"
|
||||
:filter-config-list="[]"
|
||||
:custom-fields-config-list="[]"
|
||||
:count="props.modulesCount[props.activeModule] || 0"
|
||||
:name="moduleNamePath"
|
||||
:view-type="ViewTypeEnum.PLAN_API_CASE"
|
||||
:filter-config-list="filterConfigList"
|
||||
:search-placeholder="t('common.searchByIdName')"
|
||||
@keyword-search="loadCaseList()"
|
||||
@adv-search="loadCaseList()"
|
||||
@refresh="handleRefreshAll"
|
||||
@adv-search="handleAdvSearch"
|
||||
@refresh="handleRefreshAll()"
|
||||
/>
|
||||
<a-spin :loading="tableLoading" class="w-full">
|
||||
<MsBaseTable
|
||||
|
@ -17,12 +16,12 @@
|
|||
class="mt-[16px]"
|
||||
v-bind="propsRes"
|
||||
:action-config="batchActions"
|
||||
:not-show-table-filter="isAdvancedSearchMode"
|
||||
v-on="propsEvent"
|
||||
@batch-action="handleTableBatch"
|
||||
@drag-change="handleDragChange"
|
||||
@selected-change="handleTableSelect"
|
||||
@filter-change="getModuleCount"
|
||||
@module-change="loadCaseList(false)"
|
||||
>
|
||||
<template #num="{ record }">
|
||||
<MsButton type="text" @click="toDetail(record)">{{ record.num }}</MsButton>
|
||||
|
@ -137,7 +136,8 @@
|
|||
import { computed, ref } from 'vue';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
import { MsAdvanceFilter } from '@/components/pure/ms-advance-filter';
|
||||
import MsAdvanceFilter from '@/components/pure/ms-advance-filter/index.vue';
|
||||
import { FilterFormItem, FilterResult } from '@/components/pure/ms-advance-filter/type';
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsPopconfirm from '@/components/pure/ms-popconfirm/index.vue';
|
||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||
|
@ -158,6 +158,7 @@
|
|||
import LinkDefectDrawer from '@/views/case-management/components/linkDefectDrawer.vue';
|
||||
import BatchApiMoveModal from '@/views/test-plan/testPlan/components/batchApiMoveModal.vue';
|
||||
|
||||
import { getAssociatedProjectOptions } from '@/api/modules/case-management/featureCase';
|
||||
import {
|
||||
associateBugToApiCase,
|
||||
batchDisassociateApiCase,
|
||||
|
@ -165,6 +166,7 @@
|
|||
batchMoveApiCase,
|
||||
batchRunApiCase,
|
||||
disassociateApiCase,
|
||||
getApiCaseModule,
|
||||
getApiCaseReport,
|
||||
getApiCaseReportStep,
|
||||
getPlanDetailApiCaseList,
|
||||
|
@ -180,7 +182,9 @@
|
|||
import { hasAllPermission, hasAnyPermission } from '@/utils/permission';
|
||||
|
||||
import { DragSortParams, ModuleTreeNode, TableQueryParams } from '@/models/common';
|
||||
import type { ProjectListItem } from '@/models/setting/project';
|
||||
import type { PlanDetailApiCaseItem, PlanDetailApiCaseQueryParams } from '@/models/testPlan/testPlan';
|
||||
import { FilterType, ViewTypeEnum } from '@/enums/advancedFilterEnum';
|
||||
import { AssociatedBugApiTypeEnum } from '@/enums/associateBugEnum';
|
||||
import { CaseLinkEnum } from '@/enums/caseEnum';
|
||||
import { ReportEnum } from '@/enums/reportEnum';
|
||||
|
@ -188,11 +192,13 @@
|
|||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
import { FilterRemoteMethodsEnum, FilterSlotNameEnum } from '@/enums/tableFilterEnum';
|
||||
|
||||
import { casePriorityOptions, lastReportStatusListOptions } from '@/views/api-test/components/config';
|
||||
import {
|
||||
casePriorityOptions,
|
||||
caseStatusOptions,
|
||||
lastReportStatusListOptions,
|
||||
} from '@/views/api-test/components/config';
|
||||
|
||||
const props = defineProps<{
|
||||
modulesCount: Record<string, number>; // 模块数量统计对象
|
||||
moduleName: string;
|
||||
moduleParentId: string;
|
||||
activeModule: string;
|
||||
offspringIds: string[];
|
||||
|
@ -200,12 +206,14 @@
|
|||
moduleTree: ModuleTreeNode[];
|
||||
canEdit: boolean;
|
||||
selectedProtocols: string[];
|
||||
allProtocolList: string[];
|
||||
treeType: 'MODULE' | 'COLLECTION';
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'getModuleCount', params: PlanDetailApiCaseQueryParams): void;
|
||||
(e: 'refresh'): void;
|
||||
(e: 'handleAdvSearch', isStartAdvance: boolean): void;
|
||||
(e: 'initModules'): void;
|
||||
}>();
|
||||
|
||||
|
@ -216,9 +224,6 @@
|
|||
const appStore = useAppStore();
|
||||
|
||||
const keyword = ref('');
|
||||
const moduleNamePath = computed(() => {
|
||||
return props.activeModule === 'all' ? t('apiTestManagement.allApi') : props.moduleName;
|
||||
});
|
||||
|
||||
const hasOperationPermission = computed(
|
||||
() => hasAnyPermission(['PROJECT_TEST_PLAN:READ+EXECUTE', 'PROJECT_TEST_PLAN:READ+ASSOCIATION']) && props.canEdit
|
||||
|
@ -391,16 +396,13 @@
|
|||
tableKey: TableKeyEnum.TEST_PLAN_DETAIL_API_CASE,
|
||||
showSetting: true,
|
||||
heightUsed: 445,
|
||||
showSubdirectory: true,
|
||||
draggable: { type: 'handle' },
|
||||
draggableCondition: true,
|
||||
selectable: hasOperationPermission.value,
|
||||
});
|
||||
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable(
|
||||
getPlanDetailApiCaseList,
|
||||
tableProps.value
|
||||
);
|
||||
const { propsRes, propsEvent, viewId, advanceFilter, setAdvanceFilter, loadList, setLoadListParams, resetSelector } =
|
||||
useTable(getPlanDetailApiCaseList, tableProps.value);
|
||||
const existedDefect = inject<Ref<number>>('existedDefect', ref(0));
|
||||
|
||||
const tableRef = ref<InstanceType<typeof MsBaseTable>>();
|
||||
|
@ -449,9 +451,11 @@
|
|||
};
|
||||
});
|
||||
|
||||
const msAdvanceFilterRef = ref<InstanceType<typeof MsAdvanceFilter>>();
|
||||
const isAdvancedSearchMode = computed(() => msAdvanceFilterRef.value?.isAdvancedSearchMode);
|
||||
async function getModuleIds() {
|
||||
let moduleIds: string[] = [];
|
||||
if (props.activeModule !== 'all') {
|
||||
if (props.activeModule !== 'all' && !isAdvancedSearchMode.value) {
|
||||
moduleIds = [props.activeModule];
|
||||
const getAllChildren = await tableStore.getSubShow(TableKeyEnum.TEST_PLAN_DETAIL_API_CASE);
|
||||
if (getAllChildren) {
|
||||
|
@ -467,7 +471,7 @@
|
|||
const selectModules = await getModuleIds();
|
||||
const commonParams = {
|
||||
testPlanId: props.planId,
|
||||
protocols: props.selectedProtocols,
|
||||
protocols: isAdvancedSearchMode.value ? props.allProtocolList : props.selectedProtocols,
|
||||
...(props.treeType === 'COLLECTION' ? { collectionId: collectionId.value } : { moduleIds: selectModules }),
|
||||
};
|
||||
if (isBatch) {
|
||||
|
@ -475,6 +479,8 @@
|
|||
condition: {
|
||||
keyword: keyword.value,
|
||||
filter: propsRes.value.filter,
|
||||
viewId: viewId.value,
|
||||
combineSearch: advanceFilter,
|
||||
},
|
||||
projectId: props.activeModule !== 'all' && props.treeType === 'MODULE' ? props.moduleParentId : '',
|
||||
...commonParams,
|
||||
|
@ -506,10 +512,12 @@
|
|||
const tableParams = await getTableParams(false);
|
||||
setLoadListParams({
|
||||
...tableParams,
|
||||
viewId: viewId.value,
|
||||
combineSearch: advanceFilter,
|
||||
projectId: props.activeModule !== 'all' && props.treeType === 'MODULE' ? props.moduleParentId : '',
|
||||
});
|
||||
loadList();
|
||||
if (refreshTreeCount) {
|
||||
if (refreshTreeCount && !isAdvancedSearchMode.value) {
|
||||
emit('getModuleCount', {
|
||||
...tableParams,
|
||||
current: propsRes.value.msPagination?.current,
|
||||
|
@ -518,10 +526,213 @@
|
|||
}
|
||||
}
|
||||
|
||||
const projectList = ref<ProjectListItem[]>([]);
|
||||
async function initProjectList() {
|
||||
try {
|
||||
projectList.value = await getAssociatedProjectOptions(appStore.currentOrgId, CaseLinkEnum.API);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
const anotherTree = ref<ModuleTreeNode[]>([]);
|
||||
async function initAnotherModules() {
|
||||
try {
|
||||
const res = await getApiCaseModule({
|
||||
testPlanId: props.planId,
|
||||
treeType: props.treeType === 'MODULE' ? 'COLLECTION' : 'MODULE',
|
||||
});
|
||||
anotherTree.value = res;
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
const filterConfigList = computed<FilterFormItem[]>(() => [
|
||||
{
|
||||
title: 'caseManagement.featureCase.tableColumnID',
|
||||
dataIndex: 'num',
|
||||
type: FilterType.INPUT,
|
||||
},
|
||||
{
|
||||
title: 'case.caseName',
|
||||
dataIndex: 'name',
|
||||
type: FilterType.INPUT,
|
||||
},
|
||||
{
|
||||
title: 'ms.minders.testSet',
|
||||
dataIndex: 'testPlanCollectionId',
|
||||
type: FilterType.SELECT,
|
||||
selectProps: {
|
||||
labelKey: 'name',
|
||||
valueKey: 'id',
|
||||
multiple: true,
|
||||
options: props.treeType !== 'MODULE' ? props.moduleTree : anotherTree.value,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'common.belongModule',
|
||||
dataIndex: 'moduleId',
|
||||
type: FilterType.TREE_SELECT,
|
||||
treeSelectData: props.treeType === 'MODULE' ? props.moduleTree : anotherTree.value,
|
||||
treeSelectProps: {
|
||||
fieldNames: {
|
||||
title: 'name',
|
||||
key: 'id',
|
||||
children: 'children',
|
||||
},
|
||||
multiple: true,
|
||||
treeCheckable: true,
|
||||
treeCheckStrictly: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'common.belongProject',
|
||||
dataIndex: 'projectName',
|
||||
type: FilterType.SELECT,
|
||||
selectProps: {
|
||||
labelKey: 'name',
|
||||
valueKey: 'id',
|
||||
multiple: true,
|
||||
options: projectList.value,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'apiTestManagement.protocol',
|
||||
dataIndex: 'protocol',
|
||||
type: FilterType.SELECT,
|
||||
selectProps: {
|
||||
multiple: true,
|
||||
options: props.allProtocolList.map((item) => ({ label: item, value: item })),
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'case.caseLevel',
|
||||
dataIndex: 'priority',
|
||||
type: FilterType.SELECT,
|
||||
selectProps: {
|
||||
multiple: true,
|
||||
options: casePriorityOptions,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'common.executionResult',
|
||||
dataIndex: 'lastExecResult',
|
||||
type: FilterType.SELECT,
|
||||
selectProps: {
|
||||
multiple: true,
|
||||
options: lastReportStatusListOptions.value,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'apiTestManagement.apiStatus',
|
||||
dataIndex: 'status',
|
||||
type: FilterType.SELECT,
|
||||
selectProps: {
|
||||
multiple: true,
|
||||
options: caseStatusOptions.map((item) => ({ label: t(item.label), value: item.value })),
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'case.apiParamsChange',
|
||||
dataIndex: 'apiChange',
|
||||
type: FilterType.BOOLEAN,
|
||||
selectProps: {
|
||||
options: [
|
||||
{ label: t('case.withoutChanges'), value: false },
|
||||
{ label: t('case.withChanges'), value: true },
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'testPlan.featureCase.bugCount',
|
||||
dataIndex: 'bugCount',
|
||||
type: FilterType.NUMBER,
|
||||
numberProps: {
|
||||
min: 0,
|
||||
precision: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'apiTestManagement.path',
|
||||
dataIndex: 'path',
|
||||
type: FilterType.INPUT,
|
||||
},
|
||||
{
|
||||
title: 'case.passRate',
|
||||
dataIndex: 'passRate',
|
||||
type: FilterType.NUMBER,
|
||||
numberProps: {
|
||||
min: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'report.detail.api.executeEnv',
|
||||
dataIndex: 'environmentName',
|
||||
type: FilterType.SELECT,
|
||||
selectProps: {
|
||||
labelKey: 'name',
|
||||
valueKey: 'id',
|
||||
multiple: true,
|
||||
options: appStore.envList,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'common.tag',
|
||||
dataIndex: 'tags',
|
||||
type: FilterType.TAGS_INPUT,
|
||||
numberProps: {
|
||||
min: 0,
|
||||
precision: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'testPlan.featureCase.executor',
|
||||
dataIndex: 'executeUser',
|
||||
type: FilterType.MEMBER,
|
||||
},
|
||||
{
|
||||
title: 'common.creator',
|
||||
dataIndex: 'createUser',
|
||||
type: FilterType.MEMBER,
|
||||
},
|
||||
{
|
||||
title: 'common.createTime',
|
||||
dataIndex: 'createTime',
|
||||
type: FilterType.DATE_PICKER,
|
||||
},
|
||||
{
|
||||
title: 'common.updateUserName',
|
||||
dataIndex: 'updateUser',
|
||||
type: FilterType.MEMBER,
|
||||
},
|
||||
{
|
||||
title: 'common.updateTime',
|
||||
dataIndex: 'updateTime',
|
||||
type: FilterType.DATE_PICKER,
|
||||
},
|
||||
]);
|
||||
// 高级检索
|
||||
const handleAdvSearch = async (filter: FilterResult, id: string, isStartAdvance: boolean) => {
|
||||
resetSelector();
|
||||
emit('handleAdvSearch', isStartAdvance);
|
||||
keyword.value = '';
|
||||
setAdvanceFilter(filter, id);
|
||||
await loadCaseList(); // 基础筛选都清空
|
||||
};
|
||||
|
||||
watch([() => props.activeModule, () => props.selectedProtocols], () => {
|
||||
if (isAdvancedSearchMode.value) return;
|
||||
loadCaseList();
|
||||
});
|
||||
|
||||
onBeforeMount(() => {
|
||||
initAnotherModules();
|
||||
initProjectList();
|
||||
});
|
||||
|
||||
async function getModuleCount() {
|
||||
const tableParams = await getTableParams(false);
|
||||
emit('getModuleCount', {
|
||||
|
|
|
@ -120,6 +120,7 @@
|
|||
const selectedKeys = useVModel(props, 'selectedKeys', emit);
|
||||
const treeFolderAllRef = ref<InstanceType<typeof TreeFolderAll>>();
|
||||
const selectedProtocols = computed<string[]>(() => treeFolderAllRef.value?.selectedProtocols ?? []);
|
||||
const allProtocolList = computed<string[]>(() => treeFolderAllRef.value?.allProtocolList ?? []);
|
||||
|
||||
// 初始化模块树
|
||||
async function initModules() {
|
||||
|
@ -149,7 +150,7 @@
|
|||
return e;
|
||||
});
|
||||
activeFolder.value = node.id;
|
||||
emit('folderNodeSelect', _selectedKeys as string[], offspringIds, node.name, getNodeParentId(node));
|
||||
emit('folderNodeSelect', _selectedKeys as string[], offspringIds, getNodeParentId(node));
|
||||
}
|
||||
|
||||
// 初始化模块文件数量
|
||||
|
@ -176,6 +177,7 @@
|
|||
});
|
||||
|
||||
defineExpose({
|
||||
allProtocolList,
|
||||
initModules,
|
||||
setActiveFolder,
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<MsSplitBox>
|
||||
<MsSplitBox :not-show-first="isAdvancedSearchMode">
|
||||
<template #first>
|
||||
<div class="p-[16px]">
|
||||
<a-radio-group v-model:model-value="treeType" size="medium" class="mb-[16px] w-full" type="button">
|
||||
|
@ -22,8 +22,7 @@
|
|||
ref="caseTableRef"
|
||||
:plan-id="planId"
|
||||
:tree-type="treeType"
|
||||
:modules-count="modulesCount"
|
||||
:module-name="moduleName"
|
||||
:all-protocol-list="allProtocolList"
|
||||
:module-parent-id="moduleParentId"
|
||||
:active-module="activeFolderId"
|
||||
:offspring-ids="offspringIds"
|
||||
|
@ -32,6 +31,7 @@
|
|||
:selected-protocols="selectedProtocols"
|
||||
@get-module-count="getModuleCount"
|
||||
@refresh="emit('refresh')"
|
||||
@handle-adv-search="handleAdvSearch"
|
||||
@init-modules="initModules"
|
||||
></CaseTable>
|
||||
</template>
|
||||
|
@ -80,17 +80,15 @@
|
|||
|
||||
const caseTableRef = ref<InstanceType<typeof CaseTable>>();
|
||||
const activeFolderId = ref<string>('all');
|
||||
const moduleName = ref<string>('');
|
||||
const moduleParentId = ref<string>('');
|
||||
const offspringIds = ref<string[]>([]);
|
||||
const selectedKeys = computed({
|
||||
get: () => [activeFolderId.value],
|
||||
set: (val) => val,
|
||||
});
|
||||
function handleFolderNodeSelect(ids: string[], _offspringIds: string[], name?: string, parentId?: string) {
|
||||
function handleFolderNodeSelect(ids: string[], _offspringIds: string[], parentId?: string) {
|
||||
[activeFolderId.value] = ids;
|
||||
offspringIds.value = [..._offspringIds];
|
||||
moduleName.value = name ?? '';
|
||||
moduleParentId.value = parentId ?? '';
|
||||
caseTableRef.value?.resetSelector();
|
||||
}
|
||||
|
@ -101,10 +99,18 @@
|
|||
}
|
||||
|
||||
const caseTreeRef = ref<InstanceType<typeof CaseTree>>();
|
||||
const allProtocolList = computed<string[]>(() => caseTreeRef.value?.allProtocolList ?? []);
|
||||
|
||||
function initModules() {
|
||||
caseTreeRef.value?.initModules();
|
||||
}
|
||||
|
||||
const isAdvancedSearchMode = ref(false);
|
||||
function handleAdvSearch(isStartAdvance: boolean) {
|
||||
isAdvancedSearchMode.value = isStartAdvance;
|
||||
caseTreeRef.value?.setActiveFolder('all');
|
||||
}
|
||||
|
||||
const treeType = ref<'MODULE' | 'COLLECTION'>('COLLECTION');
|
||||
function getCaseTableList() {
|
||||
nextTick(() => {
|
||||
|
|
Loading…
Reference in New Issue