feat(接口测试): 定义api支持高级搜索&优化视图交互

This commit is contained in:
teukkk 2024-09-06 19:21:09 +08:00 committed by 刘瑞斌
parent fa5a4200bb
commit 1320bfe264
14 changed files with 265 additions and 146 deletions

View File

@ -60,10 +60,10 @@
});
}
function validateForm(cb: () => void) {
function validateForm(cb: (param?: any) => void, params?: any) {
formRef.value?.validate(async (errors) => {
if (!errors) {
cb();
cb(params);
}
});
}

View File

@ -51,7 +51,7 @@
{{ t(option.title as string) }}
</a-option>
<a-divider
v-if="(props?.customList || [])?.length && (currentConfigList || []).length - 1 === currentOptionsIndex"
v-if="(props?.customList || [])?.length && !option.customField && currentOptions(item.dataIndex as string)[currentOptionsIndex+1]?.customField"
class="!my-1"
/>
</div>
@ -189,25 +189,28 @@
</a-button>
</div>
</a-form>
<MsButton type="text" class="mt-[5px]" @click="handleAddItem">
<MsButton type="text" class="mt-[5px] w-[fit-content]" @click="handleAddItem">
<MsIcon type="icon-icon_add_outlined" class="mr-[3px]" />
{{ t('advanceFilter.addCondition') }}
</MsButton>
<template #footer>
<div v-if="!isSaveAsView" class="flex items-center gap-[8px]">
<a-button type="primary" @click="handleFilter">{{ t('common.filter') }}</a-button>
<a-button v-if="!formModel?.id" type="primary" @click="handleSaveAndFilter">{{
t('advanceFilter.saveAndFilter')
}}</a-button>
<a-button v-if="formModel?.id" type="primary" @click="handleFilter">{{ t('common.filter') }}</a-button>
<a-button class="mr-[16px]" @click="handleReset">{{ t('common.reset') }}</a-button>
<MsButton
v-if="!isInternalViews(formModel?.id)"
v-if="!isInternalViews(formModel?.id) && formModel?.id"
type="text"
:loading="saveLoading"
class="!text-[var(--color-text-1)]"
@click="handleSaveView"
@click="handleSaveView()"
>
{{ t('common.save') }}
</MsButton>
<MsButton
v-if="formModel?.id && !isInternalViews(formModel?.id)"
v-if="(formModel?.id && !isInternalViews(formModel?.id)) || formModel?.id === 'all_data'"
type="text"
class="!text-[var(--color-text-1)]"
@click="handleToSaveAs"
@ -262,6 +265,7 @@
const emit = defineEmits<{
(e: 'handleFilter', value: FilterResult): void;
(e: 'refreshViewList'): void;
(e: 'changeViewToFirstCustom'): void;
}>();
const visible = defineModel<boolean>('visible', { required: true });
@ -397,12 +401,22 @@
}
function getParams() {
const conditions = formModel.value.list.map(({ value, operator, customField, dataIndex }) => ({
value,
operator,
customField: customField ?? false,
name: dataIndex,
}));
const conditions = formModel.value.list.map(({ type, value, operator, customField, dataIndex }) => {
let timeValue;
//
if (type === FilterType.DATE_PICKER) {
timeValue =
operator === OperatorEnum.BETWEEN
? [new Date(value[0]).getTime(), new Date(value[1]).getTime()]
: new Date(value).getTime();
}
return {
value: timeValue ?? value,
operator,
customField: customField ?? false,
name: dataIndex,
};
});
return { searchMode: formModel.value.searchMode, conditions };
}
@ -449,7 +463,7 @@
//
const saveLoading = ref(false);
function realSaveView() {
function realSaveView(isChangeView = false) {
formRef.value?.validate(async (errors) => {
if (!errors) {
try {
@ -466,7 +480,11 @@
}
Message.success(t('common.saveSuccess'));
savedFormModel.value = cloneDeep(formModel.value);
emit('refreshViewList');
if (!isChangeView) {
emit('refreshViewList');
} else {
emit('changeViewToFirstCustom');
}
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
@ -476,11 +494,11 @@
}
});
}
function handleSaveView() {
function handleSaveView(isChangeView = false) {
if (viewNameInputRef.value) {
viewNameInputRef.value?.validateForm(realSaveView);
viewNameInputRef.value?.validateForm(realSaveView, isChangeView);
} else {
realSaveView();
realSaveView(isChangeView);
}
}
@ -531,6 +549,9 @@
async function handleAddView() {
saveAsViewNameInputRef.value?.validateForm(realAddView);
}
function handleSaveAndFilter() {
handleSaveView(true);
}
defineExpose({
resetToNewViewForm,

View File

@ -77,6 +77,7 @@ export const CustomTypeMaps: Record<string, any> = {
propsKey: 'selectProps',
props: {
mode: 'static',
multiple: true,
valueKey: 'value',
labelKey: 'text',
options: [],
@ -171,10 +172,13 @@ export const CustomTypeMaps: Record<string, any> = {
// TODO lmy 计划详情功能用例增加:测试点;接口定义、计划详情接口用例增加:协议;
export function getAllDataDefaultConditions(viewType: ViewTypeEnum) {
const conditions = [
{ name: 'id', operator: OperatorEnum.CONTAINS },
{ name: 'num', operator: OperatorEnum.CONTAINS },
{ name: 'name', operator: OperatorEnum.CONTAINS },
{ name: 'moduleId', operator: OperatorEnum.BELONG_TO },
];
if ([ViewTypeEnum.API_DEFINITION].includes(viewType)) {
return [...conditions, { name: 'protocol', operator: OperatorEnum.BELONG_TO }];
}
return conditions;
}

View File

@ -127,6 +127,7 @@
:member-options="memberOptions"
@handle-filter="handleFilter"
@refresh-view-list="getUserViewList"
@change-view-to-first-custom="changeViewToFirstCustom"
/>
</template>
@ -149,7 +150,6 @@
import { FilterFormItem, FilterResult, ViewItem } from './type';
const props = defineProps<{
rowCount: number;
filterConfigList: FilterFormItem[]; //
customFieldsConfigList?: FilterFormItem[]; //
searchPlaceholder?: string;
@ -161,7 +161,7 @@
const emit = defineEmits<{
(e: 'keywordSearch', value: string | undefined): void; // keyword TODO: v-model:keyword
(e: 'advSearch', value: FilterResult, viewId: string): void; //
(e: 'advSearch', value: FilterResult, viewId: string, isAdvancedSearchMode: boolean): void; //
(e: 'refresh', value: FilterResult): void;
}>();
@ -275,7 +275,7 @@
//
isAdvancedSearchMode.value = currentView.value !== internalViews.value[0].id || haveConditions;
filterResult.value = filter;
emit('advSearch', filter, currentView.value);
emit('advSearch', filter, currentView.value, isAdvancedSearchMode.value);
};
const handleRefresh = () => {
@ -295,11 +295,17 @@
function clearFilter() {
if (currentView.value === internalViews.value[0].id) {
filterDrawerRef.value?.handleReset();
handleFilter({ searchMode: 'AND', conditions: [] });
} else {
currentView.value = internalViews.value[0].id;
}
}
async function changeViewToFirstCustom() {
await getUserViewList();
currentView.value = customViews.value[0].id;
}
defineExpose({
isAdvancedSearchMode,
});

View File

@ -42,4 +42,5 @@ export default {
'advanceFilter.filterContentRequired': 'Filter content cannot be empty',
'advanceFilter.filterTip': 'Filter mode, module filtering can only be operated in the current filter',
'advanceFilter.maxViewTip': 'Up to 10 views can be added',
'advanceFilter.saveAndFilter': 'Save And filter',
};

View File

@ -42,4 +42,5 @@ export default {
'advanceFilter.filterContentRequired': '筛选内容不能为空',
'advanceFilter.filterTip': '筛选模式,模块过滤仅可在当前过滤器中操作',
'advanceFilter.maxViewTip': '最多可添加 10 个视图',
'advanceFilter.saveAndFilter': '保存并筛选',
};

View File

@ -26,7 +26,6 @@ export default function useShortCut(shortcuts: Shortcuts, options: MinderOperati
const { minderCopy, minderCut, minderPaste } = useMinderOperation(options);
const handleKeyDown = (event: KeyboardEvent) => {
event.preventDefault();
const nodes: MinderJsonNode[] = window.minder.getSelectedNodes();
if (nodes.length === 0) {
return;

View File

@ -31,4 +31,6 @@ export enum FilterType {
export enum ViewTypeEnum {
FUNCTIONAL_CASE = 'functional-case',
API_DEFINITION = 'api-definition',
REVIEW_FUNCTIONAL_CASE = 'review-functional-case',
}

View File

@ -1,35 +1,28 @@
<template>
<div :class="['p-[0_16px_8px_16px]', props.class]">
<div class="mb-[16px] flex items-center justify-end">
<div class="flex items-center gap-[8px]">
<a-input-search
v-model:model-value="keyword"
:placeholder="t('apiTestManagement.searchPlaceholder')"
allow-clear
class="mr-[8px] w-[240px]"
@search="loadApiList(false)"
@press-enter="loadApiList(false)"
@clear="loadApiList(false)"
/>
<a-button type="outline" class="arco-btn-outline--secondary !p-[8px]" @click="loadApiList(false)">
<template #icon>
<icon-refresh class="text-[var(--color-text-4)]" />
</template>
</a-button>
</div>
</div>
<MsAdvanceFilter
ref="msAdvanceFilterRef"
v-model:keyword="keyword"
:view-type="ViewTypeEnum.API_DEFINITION"
:filter-config-list="filterConfigList"
:search-placeholder="t('apiTestManagement.searchPlaceholder')"
@keyword-search="loadApiList(false)"
@adv-search="handleAdvSearch"
@refresh="loadApiList(false)"
/>
<ms-base-table
ref="apiTableRef"
v-bind="propsRes"
:action-config="batchActions"
:first-column-width="44"
no-disable
class="mt-[16px]"
:not-show-table-filter="isAdvancedSearchMode"
filter-icon-align-left
v-on="propsEvent"
@selected-change="handleTableSelect"
@batch-action="handleTableBatch"
@drag-change="handleTableDragSort"
@module-change="loadApiList(false)"
>
<template #[FilterSlotNameEnum.API_TEST_API_REQUEST_METHODS]="{ filterContent }">
<apiMethodName :method="filterContent.value" />
@ -176,7 +169,7 @@
:disabled="batchForm.attr === ''"
>
<a-option v-for="item of valueOptions" :key="item.value" :value="item.value">
{{ t(item.name) }}
{{ item.name }}
</a-option>
</a-select>
</a-form-item>
@ -294,6 +287,8 @@
import { FormInstance, Message } from '@arco-design/web-vue';
import dayjs from 'dayjs';
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 MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import type { BatchActionParams, BatchActionQueryParams, MsTableColumn } from '@/components/pure/ms-table/type';
@ -307,7 +302,6 @@
import apiStatus from '@/views/api-test/components/apiStatus.vue';
import moduleTree from '@/views/api-test/management/components/moduleTree.vue';
import { getProtocolList } from '@/api/modules/api-test/common';
import {
batchDeleteDefinition,
batchMoveDefinition,
@ -329,7 +323,8 @@
import { ProtocolItem } from '@/models/apiTest/common';
import { ApiDefinitionDetail, ApiDefinitionGetModuleParams } from '@/models/apiTest/management';
import { DragSortParams } from '@/models/common';
import { DragSortParams, ModuleTreeNode } from '@/models/common';
import { FilterType, ViewTypeEnum } from '@/enums/advancedFilterEnum';
import { RequestDefinitionStatus, RequestImportFormat, RequestMethods } from '@/enums/apiEnum';
import { CacheTabTypeEnum } from '@/enums/cacheTabEnum';
import { TableKeyEnum } from '@/enums/tableEnum';
@ -347,6 +342,7 @@
selectedProtocols: string[]; //
readOnly?: boolean; //
refreshTimeStamp?: number;
moduleTreeData?: ModuleTreeNode[];
memberOptions: { label: string; value: string }[];
}>();
const emit = defineEmits<{
@ -354,6 +350,7 @@
(e: 'openCopyApiTab', record: ApiDefinitionDetail): void;
(e: 'addApiTab'): void;
(e: 'import'): void;
(e: 'handleAdvSearch', isStartAdvance: boolean): void;
(
e: 'openEditApiTab',
options: { apiInfo: ApiDefinitionDetail; isCopy: boolean; isExecute: boolean; isEdit: boolean }
@ -380,22 +377,7 @@
])
);
// TODO: store
const protocolList = ref<ProtocolItem[]>([]);
async function initProtocolList() {
try {
const res = await getProtocolList(appStore.currentOrgId);
protocolList.value = res.map((e) => ({
protocol: e.protocol,
polymorphicName: e.polymorphicName,
pluginId: e.pluginId,
}));
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
}
const protocolList = inject<Ref<ProtocolItem[]>>('protocols', ref([]));
const requestMethodsOptions = computed(() => {
const otherMethods = protocolList.value
.filter((e) => e.protocol !== 'HTTP')
@ -421,6 +403,24 @@
};
});
});
const apiStatusOptions = [
{
name: t('apiTestManagement.processing'),
value: RequestDefinitionStatus.PROCESSING,
},
{
name: t('apiTestManagement.done'),
value: RequestDefinitionStatus.DONE,
},
{
name: t('apiTestManagement.deprecate'),
value: RequestDefinitionStatus.DEPRECATED,
},
{
name: t('apiTestManagement.debugging'),
value: RequestDefinitionStatus.DEBUGGING,
},
];
const apiTableRef = ref();
let columns: MsTableColumn = [
{
@ -574,31 +574,31 @@
);
}
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable(
getDefinitionPage,
{
columns: props.readOnly ? columns : [],
scroll: { x: '100%' },
tableKey: props.readOnly ? undefined : TableKeyEnum.API_TEST,
showSetting: !props.readOnly,
selectable: hasAnyPermission([
'PROJECT_API_DEFINITION:READ+DELETE',
'PROJECT_API_DEFINITION:READ+EXECUTE',
'PROJECT_API_DEFINITION:READ+UPDATE',
]),
showSelectAll: !props.readOnly,
draggable: hasAnyPermission(['PROJECT_API_DEFINITION:READ+UPDATE']) ? { type: 'handle', width: 32 } : undefined,
heightUsed: 272,
paginationSize: 'mini',
showSubdirectory: true,
},
(item) => ({
...item,
fullPath: folderTreePathMap?.[item.moduleId],
createTime: dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss'),
updateTime: dayjs(item.updateTime).format('YYYY-MM-DD HH:mm:ss'),
})
);
const { propsRes, propsEvent, viewId, advanceFilter, setAdvanceFilter, loadList, setLoadListParams, resetSelector } =
useTable(
getDefinitionPage,
{
columns: props.readOnly ? columns : [],
scroll: { x: '100%' },
tableKey: props.readOnly ? undefined : TableKeyEnum.API_TEST,
showSetting: !props.readOnly,
selectable: hasAnyPermission([
'PROJECT_API_DEFINITION:READ+DELETE',
'PROJECT_API_DEFINITION:READ+EXECUTE',
'PROJECT_API_DEFINITION:READ+UPDATE',
]),
showSelectAll: !props.readOnly,
draggable: hasAnyPermission(['PROJECT_API_DEFINITION:READ+UPDATE']) ? { type: 'handle', width: 32 } : undefined,
heightUsed: 272,
paginationSize: 'mini',
},
(item) => ({
...item,
fullPath: folderTreePathMap?.[item.moduleId],
createTime: dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss'),
updateTime: dayjs(item.updateTime).format('YYYY-MM-DD HH:mm:ss'),
})
);
const batchActions = {
baseAction: [
{
@ -635,9 +635,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.API_TEST);
if (getAllChildren) {
@ -653,11 +655,13 @@
keyword: keyword.value,
projectId: appStore.currentProjectId,
moduleIds,
protocols: props.selectedProtocols,
protocols: isAdvancedSearchMode.value ? protocolList.value.map((item) => item.protocol) : props.selectedProtocols,
filter: propsRes.value.filter,
viewId: viewId.value,
combineSearch: advanceFilter,
};
if (!hasRefreshTree && typeof refreshModuleTreeCount === 'function') {
if (!hasRefreshTree && typeof refreshModuleTreeCount === 'function' && !isAdvancedSearchMode.value) {
refreshModuleTreeCount({
keyword: keyword.value,
filter: propsRes.value.filter,
@ -688,6 +692,105 @@
}
);
const filterConfigList = computed<FilterFormItem[]>(() => [
{
title: 'caseManagement.featureCase.tableColumnID',
dataIndex: 'num',
type: FilterType.INPUT,
},
{
title: 'apiTestManagement.apiName',
dataIndex: 'name',
type: FilterType.INPUT,
},
{
title: 'common.belongModule',
dataIndex: 'moduleId',
type: FilterType.TREE_SELECT,
treeSelectData: props.moduleTreeData,
treeSelectProps: {
fieldNames: {
title: 'name',
key: 'id',
children: 'children',
},
multiple: true,
treeCheckable: true,
treeCheckStrictly: true,
maxTagCount: 1,
},
},
{
title: 'apiTestManagement.protocol',
dataIndex: 'protocol',
type: FilterType.SELECT,
selectProps: {
multiple: true,
labelKey: 'protocol',
valueKey: 'protocol',
options: protocolList.value,
},
},
{
title: 'apiTestManagement.apiType',
dataIndex: 'method',
type: FilterType.SELECT,
selectProps: {
multiple: true,
labelKey: 'key',
options: requestMethodsOptions.value,
},
},
{
title: 'apiTestManagement.path',
dataIndex: 'path',
type: FilterType.INPUT,
},
{
title: 'apiTestManagement.apiStatus',
dataIndex: 'status',
type: FilterType.SELECT,
selectProps: {
multiple: true,
labelKey: 'name',
options: apiStatusOptions,
},
},
{
title: 'apiTestManagement.caseTotal',
dataIndex: 'caseTotal',
type: FilterType.NUMBER,
},
{
title: 'common.tag',
dataIndex: 'tags',
type: FilterType.TAGS_INPUT,
},
{
title: 'common.creator',
dataIndex: 'createUser',
type: FilterType.MEMBER,
},
{
title: 'common.createTime',
dataIndex: 'createTime',
type: FilterType.DATE_PICKER,
},
{
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 loadApiList(false); //
};
async function handleStatusChange(record: ApiDefinitionDetail) {
try {
await updateDefinition({
@ -702,7 +805,6 @@
}
function onMountedLoad() {
initProtocolList();
if (props.selectedProtocols.length > 0) {
loadApiList(true);
}
@ -731,6 +833,20 @@
excludeIds: [],
currentSelectCount: 0,
});
async function getBatchConditionParams() {
const selectModules = await getModuleIds();
return {
condition: {
keyword: keyword.value,
filter: propsRes.value.filter,
viewId: viewId.value,
combineSearch: advanceFilter,
},
projectId: appStore.currentProjectId,
protocols: isAdvancedSearchMode.value ? protocolList.value.map((item) => item.protocol) : props.selectedProtocols,
moduleIds: selectModules,
};
}
/**
* 删除接口
@ -757,18 +873,13 @@
onBeforeOk: async () => {
try {
if (isBatch) {
const batchConditionParams = await getBatchConditionParams();
await batchDeleteDefinition({
selectIds,
selectAll: !!params?.selectAll,
excludeIds: params?.excludeIds || [],
condition: {
keyword: keyword.value,
filter: propsRes.value.filter,
},
projectId: appStore.currentProjectId,
moduleIds: await getModuleIds(),
...batchConditionParams,
deleteAll: true,
protocols: props.selectedProtocols,
});
} else {
await deleteDefinition(record?.id as string);
@ -842,24 +953,7 @@
const valueOptions = computed(() => {
switch (batchForm.value.attr) {
case 'status':
return [
{
name: 'apiTestManagement.processing',
value: RequestDefinitionStatus.PROCESSING,
},
{
name: 'apiTestManagement.done',
value: RequestDefinitionStatus.DONE,
},
{
name: 'apiTestManagement.deprecate',
value: RequestDefinitionStatus.DEPRECATED,
},
{
name: 'apiTestManagement.debugging',
value: RequestDefinitionStatus.DEBUGGING,
},
];
return apiStatusOptions;
default:
return [];
}
@ -881,17 +975,12 @@
if (!errors) {
try {
batchUpdateLoading.value = true;
const batchConditionParams = await getBatchConditionParams();
await batchUpdateDefinition({
selectIds: batchParams.value?.selectedIds || [],
selectAll: !!batchParams.value?.selectAll,
excludeIds: batchParams.value?.excludeIds || [],
condition: {
keyword: keyword.value,
filter: propsRes.value.filter,
},
projectId: appStore.currentProjectId,
moduleIds: await getModuleIds(),
protocols: props.selectedProtocols,
...batchConditionParams,
type: batchForm.value.attr,
append: batchForm.value.append,
[batchForm.value.attr]: batchForm.value.attr === 'tags' ? batchForm.value.values : batchForm.value.value,
@ -923,18 +1012,13 @@
async function handleApiMove() {
try {
batchMoveApiLoading.value = true;
const batchConditionParams = await getBatchConditionParams();
await batchMoveDefinition({
selectIds: isBatchMove.value ? batchParams.value?.selectedIds || [] : [activeApi.value?.id || ''],
selectAll: !!batchParams.value?.selectAll,
excludeIds: batchParams.value?.excludeIds || [],
condition: {
keyword: keyword.value,
filter: propsRes.value.filter,
},
projectId: appStore.currentProjectId,
moduleIds: await getModuleIds(),
...batchConditionParams,
moduleId: selectedModuleKeys.value[0],
protocols: props.selectedProtocols,
});
Message.success(t('common.batchMoveSuccess'));
if (isBatchMove.value) {
@ -996,18 +1080,13 @@
async function exportApi() {
try {
exportLoading.value = true;
const batchConditionParams = await getBatchConditionParams();
const result = await exportApiDefinition(
{
selectIds: tableSelected.value as string[],
selectAll: !!batchParams.value?.selectAll,
excludeIds: batchParams.value?.excludeIds || [],
condition: {
keyword: keyword.value,
filter: propsRes.value.filter,
},
projectId: appStore.currentProjectId,
moduleIds: await getModuleIds(),
protocols: props.selectedProtocols,
...batchConditionParams,
exportApiCase: exportApiCase.value,
exportApiMock: exportApiMock.value,
sort: propsRes.value.sorter || {},

View File

@ -6,6 +6,7 @@
class="flex-1 pt-[8px]"
:active-module="props.activeModule"
:offspring-ids="props.offspringIds"
:module-tree-data="props.moduleTree"
:selected-protocols="props.selectedProtocols"
:refresh-time-stamp="refreshTableTimeStamp"
:member-options="memberOptions"
@ -14,6 +15,7 @@
@add-api-tab="addApiTab"
@import="() => emit('import')"
@open-edit-api-tab="openApiTab"
@handle-adv-search="(val) => emit('handleAdvSearch', val)"
/>
</keep-alive>
<div v-if="activeApiTab.id !== 'all'" class="flex-1 overflow-hidden">
@ -184,6 +186,7 @@
const emit = defineEmits<{
(e: 'deleteApi', id: string): void;
(e: 'import'): void;
(e: 'handleAdvSearch', isStartAdvance: boolean): void;
(e: 'openCaseTab', apiCaseDetail: ApiCaseDetail): void;
}>();

View File

@ -56,6 +56,7 @@
@import="emit('import')"
@open-case-tab="(apiCaseDetail:ApiCaseDetail)=>newCaseTab(apiCaseDetail.id)"
@delete-api="(id) => handleDeleteApiFromModuleTree(id)"
@handle-adv-search="(val) => emit('handleAdvSearch', val)"
/>
<apiCase
v-show="(activeApiTab.id === 'all' && currentTab === 'case') || activeApiTab.type === 'case'"
@ -131,6 +132,7 @@
}>();
const emit = defineEmits<{
(e: 'import'): void;
(e: 'handleAdvSearch', isStartAdvance: boolean): void;
}>();
const appStore = useAppStore();
const route = useRoute();
@ -399,9 +401,4 @@
<style lang="less" scoped>
.ms-input-group--prepend();
:deep(.arco-select-view-prefix) {
margin-right: 8px;
padding-right: 0;
border-right: 1px solid var(--color-text-input-border);
}
</style>

View File

@ -641,6 +641,7 @@
defineExpose({
refresh,
initModuleCount,
setActiveFolder,
});
</script>

View File

@ -1,6 +1,6 @@
<template>
<MsCard simple no-content-padding>
<MsSplitBox :size="300" :max="0.5">
<MsSplitBox :not-show-first="isAdvancedSearchMode" :size="300" :max="0.5">
<template #first>
<div class="flex flex-col">
<div class="p-[16px]" :style="{ height: `calc(100vh - 120px)` }">
@ -56,6 +56,7 @@
:offspring-ids="offspringIds"
:selected-protocols="selectedProtocols"
@import="importDrawerVisible = true"
@handle-adv-search="handleAdvSearch"
/>
</div>
</template>
@ -195,6 +196,12 @@
}
};
const isAdvancedSearchMode = ref(false);
function handleAdvSearch(isStartAdvance: boolean) {
isAdvancedSearchMode.value = isStartAdvance;
moduleTreeRef.value?.setActiveFolder('all');
}
/** 向子孙组件提供方法和值 */
provide('setActiveApi', setActiveApi);
provide('refreshModuleTree', refreshModuleTree);

View File

@ -10,7 +10,6 @@
:filter-config-list="filterConfigList"
:custom-fields-config-list="searchCustomFields"
:search-placeholder="t('caseManagement.featureCase.searchPlaceholder')"
:row-count="filterRowCount"
:count="props.modulesCount[props.activeFolder] || 0"
:name="moduleNamePath"
@keyword-search="fetchData"
@ -474,7 +473,6 @@
const minderStore = useMinderStore();
const keyword = ref<string>('');
const filterRowCount = ref(0);
const groupKeyword = ref<string>('');
const showType = ref<string>('list');
@ -776,7 +774,7 @@
const filterConfigList = computed<FilterFormItem[]>(() => [
{
title: 'caseManagement.featureCase.tableColumnID',
dataIndex: 'id',
dataIndex: 'num',
type: FilterType.INPUT,
},
{