fix(接口测试): csv文件类型限制&场景步骤调整
This commit is contained in:
parent
586417e1bf
commit
b84a874aa9
|
@ -8,7 +8,7 @@
|
||||||
<template #content>
|
<template #content>
|
||||||
<MsUpload
|
<MsUpload
|
||||||
v-model:file-list="innerFileList"
|
v-model:file-list="innerFileList"
|
||||||
accept="none"
|
:accept="props.accept || 'none'"
|
||||||
:auto-upload="false"
|
:auto-upload="false"
|
||||||
:show-file-list="false"
|
:show-file-list="false"
|
||||||
:limit="50"
|
:limit="50"
|
||||||
|
@ -38,12 +38,13 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||||
import MsUpload from '@/components/pure/ms-upload/index.vue';
|
import MsUpload from '@/components/pure/ms-upload/index.vue';
|
||||||
import { MsFileItem } from '@/components/pure/ms-upload/types';
|
import { MsFileItem, UploadType } from '@/components/pure/ms-upload/types';
|
||||||
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
accept?: UploadType;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
<dropdownMenu
|
<dropdownMenu
|
||||||
:file-list="fileList"
|
:file-list="fileList"
|
||||||
:disabled="props.disabled"
|
:disabled="props.disabled"
|
||||||
|
:accept="props.accept"
|
||||||
@link-file="associatedFile"
|
@link-file="associatedFile"
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
/>
|
/>
|
||||||
|
@ -186,7 +187,12 @@
|
||||||
</a-popover>
|
</a-popover>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="flex w-full items-center gap-[4px]">
|
<div v-else class="flex w-full items-center gap-[4px]">
|
||||||
<dropdownMenu :disabled="props.disabled" @link-file="associatedFile" @change="handleChange" />
|
<dropdownMenu
|
||||||
|
:accept="props.accept"
|
||||||
|
:disabled="props.disabled"
|
||||||
|
@link-file="associatedFile"
|
||||||
|
@change="handleChange"
|
||||||
|
/>
|
||||||
<a-input
|
<a-input
|
||||||
v-model:model-value="inputFileName"
|
v-model:model-value="inputFileName"
|
||||||
:disabled="props.disabled"
|
:disabled="props.disabled"
|
||||||
|
@ -206,6 +212,7 @@
|
||||||
:get-list-request="getAssociatedFileListUrl"
|
:get-list-request="getAssociatedFileListUrl"
|
||||||
:get-list-fun-params="getListFunParams"
|
:get-list-fun-params="getListFunParams"
|
||||||
:selector-type="props.multiple ? 'checkbox' : 'radio'"
|
:selector-type="props.multiple ? 'checkbox' : 'radio'"
|
||||||
|
:filetype="props.accept"
|
||||||
@save="saveSelectAssociatedFile"
|
@save="saveSelectAssociatedFile"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
@ -218,7 +225,7 @@
|
||||||
import MsTag, { Size } from '@/components/pure/ms-tag/ms-tag.vue';
|
import MsTag, { Size } from '@/components/pure/ms-tag/ms-tag.vue';
|
||||||
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
||||||
import MsUpload from '@/components/pure/ms-upload/index.vue';
|
import MsUpload from '@/components/pure/ms-upload/index.vue';
|
||||||
import type { MsFileItem } from '@/components/pure/ms-upload/types';
|
import type { MsFileItem, UploadType } from '@/components/pure/ms-upload/types';
|
||||||
import LinkFileDrawer from '@/components/business/ms-link-file/associatedFileDrawer.vue';
|
import LinkFileDrawer from '@/components/business/ms-link-file/associatedFileDrawer.vue';
|
||||||
import dropdownMenu from './dropdownMenu.vue';
|
import dropdownMenu from './dropdownMenu.vue';
|
||||||
import saveAsFilePopover from './saveAsFilePopover.vue';
|
import saveAsFilePopover from './saveAsFilePopover.vue';
|
||||||
|
@ -237,6 +244,7 @@
|
||||||
defineProps<{
|
defineProps<{
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
mode?: 'button' | 'input';
|
mode?: 'button' | 'input';
|
||||||
|
accept?: UploadType;
|
||||||
multiple?: boolean;
|
multiple?: boolean;
|
||||||
inputClass?: string;
|
inputClass?: string;
|
||||||
inputSize?: 'small' | 'medium' | 'large' | 'mini';
|
inputSize?: 'small' | 'medium' | 'large' | 'mini';
|
||||||
|
|
|
@ -73,6 +73,7 @@
|
||||||
:get-list-fun-params="props.getListFunParams"
|
:get-list-fun-params="props.getListFunParams"
|
||||||
:selector-type="props.selectorType"
|
:selector-type="props.selectorType"
|
||||||
:file-all-count-by-storage="fileAllCountByStorage"
|
:file-all-count-by-storage="fileAllCountByStorage"
|
||||||
|
:filetype="props.filetype"
|
||||||
@init="handleModuleTableInit"
|
@init="handleModuleTableInit"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
@ -105,6 +106,7 @@
|
||||||
getListRequest: (params: TableQueryParams) => Promise<CommonList<AssociatedList>>; // 获取表格请求
|
getListRequest: (params: TableQueryParams) => Promise<CommonList<AssociatedList>>; // 获取表格请求
|
||||||
getListFunParams: TableQueryParams; // 关联表去重id
|
getListFunParams: TableQueryParams; // 关联表去重id
|
||||||
selectorType?: 'none' | 'checkbox' | 'radio';
|
selectorType?: 'none' | 'checkbox' | 'radio';
|
||||||
|
filetype?: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
|
|
@ -6,7 +6,13 @@
|
||||||
><span class="ml-[4px] text-[var(--color-text-4)]">({{ moduleInfo.count }})</span></div
|
><span class="ml-[4px] text-[var(--color-text-4)]">({{ moduleInfo.count }})</span></div
|
||||||
>
|
>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<a-select v-model="tableFileType" class="w-[240px]" :loading="fileTypeLoading" @change="searchList">
|
<a-select
|
||||||
|
v-model="tableFileType"
|
||||||
|
class="w-[240px]"
|
||||||
|
:loading="fileTypeLoading"
|
||||||
|
:disabled="!!props.filetype"
|
||||||
|
@change="searchList"
|
||||||
|
>
|
||||||
<a-option key="" value="">{{ t('common.all') }}</a-option>
|
<a-option key="" value="">{{ t('common.all') }}</a-option>
|
||||||
<a-option v-for="item of tableFileTypeOptions" :key="item" :value="item">
|
<a-option v-for="item of tableFileTypeOptions" :key="item" :value="item">
|
||||||
{{ item }}
|
{{ item }}
|
||||||
|
@ -91,6 +97,7 @@
|
||||||
getListFunParams: TableQueryParams; // 表格额外去重参数
|
getListFunParams: TableQueryParams; // 表格额外去重参数
|
||||||
selectorType?: 'none' | 'checkbox' | 'radio';
|
selectorType?: 'none' | 'checkbox' | 'radio';
|
||||||
fileAllCountByStorage: number;
|
fileAllCountByStorage: number;
|
||||||
|
filetype?: string;
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'init', params: FileListQueryParams): void;
|
(e: 'init', params: FileListQueryParams): void;
|
||||||
|
@ -98,7 +105,7 @@
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const tableFileTypeOptions = ref<string[]>([]);
|
const tableFileTypeOptions = ref<string[]>([]);
|
||||||
const tableFileType = ref(''); // 文件格式筛选
|
const tableFileType = ref(props.filetype || ''); // 文件格式筛选
|
||||||
const keyword = ref('');
|
const keyword = ref('');
|
||||||
const fileTypeLoading = ref(false);
|
const fileTypeLoading = ref(false);
|
||||||
const fileType = ref('module'); // 当前查看的文件类型,模块/存储库
|
const fileType = ref('module'); // 当前查看的文件类型,模块/存储库
|
||||||
|
@ -249,7 +256,7 @@
|
||||||
} else {
|
} else {
|
||||||
res = await getFileTypes(appStore.currentProjectId);
|
res = await getFileTypes(appStore.currentProjectId);
|
||||||
}
|
}
|
||||||
tableFileType.value = '';
|
tableFileType.value = props.filetype || '';
|
||||||
tableFileTypeOptions.value = res;
|
tableFileTypeOptions.value = res;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
|
|
|
@ -260,6 +260,7 @@
|
||||||
id: 'fileId',
|
id: 'fileId',
|
||||||
name: 'fileAlias',
|
name: 'fileAlias',
|
||||||
}"
|
}"
|
||||||
|
:accept="columnConfig.accept"
|
||||||
:file-save-as-source-id="props.fileSaveAsSourceId"
|
:file-save-as-source-id="props.fileSaveAsSourceId"
|
||||||
:file-save-as-api="props.fileSaveAsApi"
|
:file-save-as-api="props.fileSaveAsApi"
|
||||||
:file-module-options-api="props.fileModuleOptionsApi"
|
:file-module-options-api="props.fileModuleOptionsApi"
|
||||||
|
@ -280,7 +281,7 @@
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<!-- 文件 -->
|
<!-- 文件 -->
|
||||||
<template #file="{ record, rowIndex }">
|
<template #file="{ record, rowIndex, columnConfig }">
|
||||||
<MsAddAttachment
|
<MsAddAttachment
|
||||||
:file-list="[record.file]"
|
:file-list="[record.file]"
|
||||||
:disabled="props.disabledParamValue"
|
:disabled="props.disabledParamValue"
|
||||||
|
@ -290,6 +291,7 @@
|
||||||
id: 'fileId',
|
id: 'fileId',
|
||||||
name: 'fileAlias',
|
name: 'fileAlias',
|
||||||
}"
|
}"
|
||||||
|
:accept="columnConfig.accept"
|
||||||
:file-save-as-source-id="props.fileSaveAsSourceId"
|
:file-save-as-source-id="props.fileSaveAsSourceId"
|
||||||
:file-save-as-api="props.fileSaveAsApi"
|
:file-save-as-api="props.fileSaveAsApi"
|
||||||
:file-module-options-api="props.fileModuleOptionsApi"
|
:file-module-options-api="props.fileModuleOptionsApi"
|
||||||
|
@ -619,7 +621,7 @@
|
||||||
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||||
import MsTagsGroup from '@/components/pure/ms-tag/ms-tag-group.vue';
|
import MsTagsGroup from '@/components/pure/ms-tag/ms-tag-group.vue';
|
||||||
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
||||||
import { MsFileItem } from '@/components/pure/ms-upload/types';
|
import { MsFileItem, UploadType } from '@/components/pure/ms-upload/types';
|
||||||
import MsSelect from '@/components/business/ms-select/index';
|
import MsSelect from '@/components/business/ms-select/index';
|
||||||
import paramDescInput from './paramDescInput.vue';
|
import paramDescInput from './paramDescInput.vue';
|
||||||
import DomainModal from '@/views/project-management/environmental/components/envParams/popUp/domain.vue';
|
import DomainModal from '@/views/project-management/environmental/components/envParams/popUp/domain.vue';
|
||||||
|
@ -656,6 +658,7 @@
|
||||||
format?: RequestBodyFormat; // 用于 operation 列区分是否有请求体格式选择器
|
format?: RequestBodyFormat; // 用于 operation 列区分是否有请求体格式选择器
|
||||||
addLineDisabled?: boolean; // 用于 是否禁用添加新行
|
addLineDisabled?: boolean; // 用于 是否禁用添加新行
|
||||||
disabledColumn?: boolean; // 用于禁用某一列不能编辑
|
disabledColumn?: boolean; // 用于禁用某一列不能编辑
|
||||||
|
accept?: UploadType; // 用于文件上传列的 accept 属性
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
|
|
|
@ -169,6 +169,7 @@
|
||||||
title: 'apiScenario.params.file',
|
title: 'apiScenario.params.file',
|
||||||
dataIndex: 'file',
|
dataIndex: 'file',
|
||||||
slotName: 'file',
|
slotName: 'file',
|
||||||
|
accept: 'csv',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'apiScenario.table.columns.status',
|
title: 'apiScenario.table.columns.status',
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</div>
|
</div>
|
||||||
<MsIcon
|
<MsIcon
|
||||||
|
v-if="!props.step || !props.step.isQuoteScenarioStep"
|
||||||
type="icon-icon_edit_outlined"
|
type="icon-icon_edit_outlined"
|
||||||
class="cursor-pointer hover:text-[rgb(var(--primary-5))]"
|
class="cursor-pointer hover:text-[rgb(var(--primary-5))]"
|
||||||
@click="isShowEditStepNameInput = true"
|
@click="isShowEditStepNameInput = true"
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
>
|
>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<MsIcon
|
<MsIcon
|
||||||
|
v-if="!activeStep || !activeStep.isQuoteScenarioStep"
|
||||||
type="icon-icon_edit_outlined"
|
type="icon-icon_edit_outlined"
|
||||||
class="cursor-pointer hover:text-[rgb(var(--primary-5))]"
|
class="cursor-pointer hover:text-[rgb(var(--primary-5))]"
|
||||||
@click="showEditScriptNameInput"
|
@click="showEditScriptNameInput"
|
||||||
|
|
|
@ -480,7 +480,6 @@
|
||||||
import saveAsApiModal from '@/views/api-test/components/saveAsApiModal.vue';
|
import saveAsApiModal from '@/views/api-test/components/saveAsApiModal.vue';
|
||||||
|
|
||||||
import { addCase, getDefinitionDetail } from '@/api/modules/api-test/management';
|
import { addCase, getDefinitionDetail } from '@/api/modules/api-test/management';
|
||||||
import { getScenarioDetail, getScenarioStep } from '@/api/modules/api-test/scenario';
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useModal from '@/hooks/useModal';
|
import useModal from '@/hooks/useModal';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
|
@ -495,7 +494,6 @@
|
||||||
import {
|
import {
|
||||||
CreateStepAction,
|
CreateStepAction,
|
||||||
Scenario,
|
Scenario,
|
||||||
ScenarioStepConfig,
|
|
||||||
ScenarioStepDetails,
|
ScenarioStepDetails,
|
||||||
ScenarioStepFileParams,
|
ScenarioStepFileParams,
|
||||||
ScenarioStepItem,
|
ScenarioStepItem,
|
||||||
|
@ -514,7 +512,6 @@
|
||||||
import useStepNodeEdit from './useStepNodeEdit';
|
import useStepNodeEdit from './useStepNodeEdit';
|
||||||
import useStepOperation from './useStepOperation';
|
import useStepOperation from './useStepOperation';
|
||||||
import { casePriorityOptions, caseStatusOptions } from '@/views/api-test/components/config';
|
import { casePriorityOptions, caseStatusOptions } from '@/views/api-test/components/config';
|
||||||
import { parseRequestBodyFiles } from '@/views/api-test/components/utils';
|
|
||||||
import getStepType from '@/views/api-test/scenario/components/common/stepType/utils';
|
import getStepType from '@/views/api-test/scenario/components/common/stepType/utils';
|
||||||
import { defaultStepItemCommon } from '@/views/api-test/scenario/components/config';
|
import { defaultStepItemCommon } from '@/views/api-test/scenario/components/config';
|
||||||
|
|
||||||
|
@ -728,151 +725,68 @@
|
||||||
return stepMoreActions;
|
return stepMoreActions;
|
||||||
}
|
}
|
||||||
|
|
||||||
const scenarioConfigForm = ref<
|
|
||||||
ScenarioStepConfig & {
|
|
||||||
refType: ScenarioStepRefType;
|
|
||||||
}
|
|
||||||
>({
|
|
||||||
refType: ScenarioStepRefType.REF,
|
|
||||||
enableScenarioEnv: false,
|
|
||||||
useOriginScenarioParamPreferential: true,
|
|
||||||
useOriginScenarioParam: false,
|
|
||||||
});
|
|
||||||
const showScenarioConfig = ref(false);
|
const showScenarioConfig = ref(false);
|
||||||
// const scenarioConfigParamTip = computed(() => {
|
|
||||||
// if (!scenarioConfigForm.value.useOriginScenarioParam && !scenarioConfigForm.value.enableScenarioEnv) {
|
|
||||||
// // 非使用原场景参数-非选择源场景环境
|
|
||||||
// return t('apiScenario.notSource');
|
|
||||||
// }
|
|
||||||
// if (!scenarioConfigForm.value.useOriginScenarioParam && scenarioConfigForm.value.enableScenarioEnv) {
|
|
||||||
// // 非使用原场景参数-选择源场景环境
|
|
||||||
// return t('apiScenario.notSourceParamAndSourceEnv');
|
|
||||||
// }
|
|
||||||
// if (
|
|
||||||
// scenarioConfigForm.value.useOriginScenarioParam &&
|
|
||||||
// scenarioConfigForm.value.useOriginScenarioParamPreferential &&
|
|
||||||
// !scenarioConfigForm.value.enableScenarioEnv
|
|
||||||
// ) {
|
|
||||||
// // 使用原场景参数-优先使用原场景参数
|
|
||||||
// return t('apiScenario.sourceParamAndSource');
|
|
||||||
// }
|
|
||||||
// if (
|
|
||||||
// scenarioConfigForm.value.useOriginScenarioParam &&
|
|
||||||
// scenarioConfigForm.value.useOriginScenarioParamPreferential &&
|
|
||||||
// scenarioConfigForm.value.enableScenarioEnv
|
|
||||||
// ) {
|
|
||||||
// // 使用原场景参数-优先使用原场景参数-选择源场景环境
|
|
||||||
// return t('apiScenario.sourceParamAndSourceEnv');
|
|
||||||
// }
|
|
||||||
// if (
|
|
||||||
// scenarioConfigForm.value.useOriginScenarioParam &&
|
|
||||||
// !scenarioConfigForm.value.useOriginScenarioParamPreferential &&
|
|
||||||
// !scenarioConfigForm.value.enableScenarioEnv
|
|
||||||
// ) {
|
|
||||||
// // 使用原场景参数-优先使用当前场景参数
|
|
||||||
// return t('apiScenario.currentParamAndSource');
|
|
||||||
// }
|
|
||||||
// if (
|
|
||||||
// scenarioConfigForm.value.useOriginScenarioParam &&
|
|
||||||
// !scenarioConfigForm.value.useOriginScenarioParamPreferential &&
|
|
||||||
// scenarioConfigForm.value.enableScenarioEnv
|
|
||||||
// ) {
|
|
||||||
// // 使用原场景参数-优先使用当前场景参数-选择源场景环境
|
|
||||||
// return t('apiScenario.currentParamAndSourceEnv');
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
// 关闭场景配置弹窗
|
|
||||||
function cancelScenarioConfig() {
|
|
||||||
showScenarioConfig.value = false;
|
|
||||||
scenarioConfigForm.value = {
|
|
||||||
refType: ScenarioStepRefType.REF,
|
|
||||||
enableScenarioEnv: false,
|
|
||||||
useOriginScenarioParamPreferential: true,
|
|
||||||
useOriginScenarioParam: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 刷新引用场景的步骤数据
|
* 处理api、case、场景步骤名称编辑
|
||||||
*/
|
*/
|
||||||
async function refreshScenarioStepInfo(step: ScenarioStepItem, id: string | number) {
|
const showStepNameEditInputStepId = ref<string | number>('');
|
||||||
try {
|
const tempStepName = ref('');
|
||||||
loading.value = true;
|
/**
|
||||||
const res = await getScenarioDetail(id);
|
* 处理非 api、case、场景步骤名称编辑
|
||||||
if (step.children) {
|
*/
|
||||||
step.children = mapTree(res.steps || [], (child) => {
|
const showStepDescEditInputStepId = ref<string | number>('');
|
||||||
child.uniqueId = getGenerateId();
|
const tempStepDesc = ref('');
|
||||||
child.isQuoteScenarioStep = true; // 标记为引用场景下的子步骤
|
const importApiDrawerVisible = ref(false);
|
||||||
child.isRefScenarioStep = true; // 标记为完全引用场景
|
const customCaseDrawerVisible = ref(false);
|
||||||
child.draggable = false; // 引用场景下的任何步骤不可拖拽
|
const customApiDrawerVisible = ref(false);
|
||||||
if (selectedKeys.value.includes(step.uniqueId) && !selectedKeys.value.includes(child.uniqueId)) {
|
const scriptOperationDrawerVisible = ref(false);
|
||||||
// 如果有新增的子步骤,且当前步骤被选中,则这个新增的子步骤也要选中
|
|
||||||
selectedKeys.value.push(child.uniqueId);
|
|
||||||
}
|
|
||||||
return child;
|
|
||||||
}) as ScenarioStepItem[];
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log(error);
|
|
||||||
} finally {
|
|
||||||
loading.value = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 应用场景配置
|
const { handleStepExpand, handleStepSelect, deleteStep, handleDrop, getStepDetail } = useStepOperation({
|
||||||
async function saveScenarioConfig() {
|
scenario,
|
||||||
if (activeStep.value) {
|
steps,
|
||||||
const realStep = findNodeByKey<ScenarioStepItem>(steps.value, activeStep.value.uniqueId, 'uniqueId');
|
stepDetails,
|
||||||
if (realStep) {
|
activeStep,
|
||||||
realStep.refType = scenarioConfigForm.value.refType; // 更新场景引用类型
|
selectedKeys,
|
||||||
realStep.config = {
|
customApiDrawerVisible,
|
||||||
...realStep.config,
|
customCaseDrawerVisible,
|
||||||
...scenarioConfigForm.value,
|
scriptOperationDrawerVisible,
|
||||||
};
|
loading,
|
||||||
if (scenarioConfigForm.value.refType === ScenarioStepRefType.REF) {
|
});
|
||||||
// 更新子孙步骤完全引用
|
|
||||||
await refreshScenarioStepInfo(realStep as ScenarioStepItem, realStep.resourceId);
|
|
||||||
} else {
|
|
||||||
realStep.children = mapTree<ScenarioStepItem>(realStep.children || [], (child) => {
|
|
||||||
// 更新子孙步骤-步骤引用
|
|
||||||
child.isRefScenarioStep = false;
|
|
||||||
return child;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Message.success(t('apiScenario.setSuccess'));
|
|
||||||
scenario.value.unSaved = true;
|
|
||||||
cancelScenarioConfig();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getStepDetail(step: ScenarioStepItem) {
|
const showQuickInput = ref(false);
|
||||||
try {
|
const quickInputParamValue = ref<any>('');
|
||||||
appStore.showLoading();
|
const quickInputDataKey = ref('');
|
||||||
const res = await getScenarioStep(step.copyFromStepId || step.id);
|
|
||||||
let parseRequestBodyResult;
|
const {
|
||||||
if (step.config.protocol === 'HTTP' && res.body) {
|
setQuickInput,
|
||||||
parseRequestBodyResult = parseRequestBodyFiles(res.body); // 解析请求体中的文件,将详情中的文件 id 集合收集,更新时以判断文件是否删除以及是否新上传的文件
|
clearQuickInput,
|
||||||
}
|
applyQuickInput,
|
||||||
stepDetails.value[step.id] = {
|
handleStepDescClick,
|
||||||
...res,
|
applyStepDescChange,
|
||||||
stepId: step.id,
|
handleStepContentChange,
|
||||||
protocol: step.config.protocol || '',
|
handleStepToggleEnable,
|
||||||
method: step.config.method || '',
|
handleStepNameClick,
|
||||||
...parseRequestBodyResult,
|
applyStepNameChange,
|
||||||
};
|
saveScenarioConfig,
|
||||||
scenario.value.stepFileParam[step.id] = {
|
cancelScenarioConfig,
|
||||||
...parseRequestBodyResult,
|
scenarioConfigForm,
|
||||||
};
|
} = useStepNodeEdit({
|
||||||
} catch (error) {
|
steps,
|
||||||
// eslint-disable-next-line no-console
|
scenario,
|
||||||
console.log(error);
|
activeStep,
|
||||||
} finally {
|
quickInputDataKey,
|
||||||
appStore.hideLoading();
|
quickInputParamValue,
|
||||||
}
|
showQuickInput,
|
||||||
}
|
treeRef,
|
||||||
|
tempStepDesc,
|
||||||
|
showStepDescEditInputStepId,
|
||||||
|
tempStepName,
|
||||||
|
showStepNameEditInputStepId,
|
||||||
|
loading,
|
||||||
|
selectedKeys,
|
||||||
|
showScenarioConfig,
|
||||||
|
});
|
||||||
|
|
||||||
const saveNewApiModalVisible = ref(false);
|
const saveNewApiModalVisible = ref(false);
|
||||||
const tempApiDetail = ref<RequestParam>();
|
const tempApiDetail = ref<RequestParam>();
|
||||||
|
@ -1109,20 +1023,6 @@
|
||||||
treeRef.value?.checkAll(val);
|
treeRef.value?.checkAll(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理api、case、场景步骤名称编辑
|
|
||||||
*/
|
|
||||||
const showStepNameEditInputStepId = ref<string | number>('');
|
|
||||||
const tempStepName = ref('');
|
|
||||||
/**
|
|
||||||
* 处理非 api、case、场景步骤名称编辑
|
|
||||||
*/
|
|
||||||
const showStepDescEditInputStepId = ref<string | number>('');
|
|
||||||
const tempStepDesc = ref('');
|
|
||||||
const importApiDrawerVisible = ref(false);
|
|
||||||
const customCaseDrawerVisible = ref(false);
|
|
||||||
const customApiDrawerVisible = ref(false);
|
|
||||||
const scriptOperationDrawerVisible = ref(false);
|
|
||||||
const activeCreateAction = ref<CreateStepAction>(); // 用于抽屉操作创建步骤时记录当前插入类型
|
const activeCreateAction = ref<CreateStepAction>(); // 用于抽屉操作创建步骤时记录当前插入类型
|
||||||
const currentStepDetail = computed<ScenarioStepDetails | undefined>(() => {
|
const currentStepDetail = computed<ScenarioStepDetails | undefined>(() => {
|
||||||
if (activeStep.value) {
|
if (activeStep.value) {
|
||||||
|
@ -1143,18 +1043,6 @@
|
||||||
scenario.value.unSaved = true;
|
scenario.value.unSaved = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { handleStepExpand, handleStepSelect, deleteStep, handleDrop } = useStepOperation({
|
|
||||||
scenario,
|
|
||||||
steps,
|
|
||||||
stepDetails,
|
|
||||||
activeStep,
|
|
||||||
selectedKeys,
|
|
||||||
customApiDrawerVisible,
|
|
||||||
customCaseDrawerVisible,
|
|
||||||
scriptOperationDrawerVisible,
|
|
||||||
loading,
|
|
||||||
});
|
|
||||||
|
|
||||||
function handleReplaceStep(newStep: ScenarioStepItem) {
|
function handleReplaceStep(newStep: ScenarioStepItem) {
|
||||||
if (activeStep.value) {
|
if (activeStep.value) {
|
||||||
// 替换步骤,删除原本的详情数据
|
// 替换步骤,删除原本的详情数据
|
||||||
|
@ -1343,14 +1231,13 @@
|
||||||
}
|
}
|
||||||
if (activeStep.value) {
|
if (activeStep.value) {
|
||||||
const _stepType = getStepType(activeStep.value);
|
const _stepType = getStepType(activeStep.value);
|
||||||
if (_stepType.isQuoteCase || activeStep.value.isQuoteScenarioStep) {
|
if (_stepType.isQuoteCase && !activeStep.value.isQuoteScenarioStep) {
|
||||||
// 引用的 case 和引用的场景步骤都不可更改(除了步骤名)
|
|
||||||
activeStep.value.name = request.stepName || request.name;
|
activeStep.value.name = request.stepName || request.name;
|
||||||
stepDetails.value[activeStep.value.id] = request; // 为了设置一次正确的polymorphicName
|
stepDetails.value[activeStep.value.id] = request; // 为了设置一次正确的polymorphicName
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (activeStep.value) {
|
if (activeStep.value && !activeStep.value.isQuoteScenarioStep) {
|
||||||
request.isNew = false;
|
request.isNew = false;
|
||||||
stepDetails.value[activeStep.value.id] = request;
|
stepDetails.value[activeStep.value.id] = request;
|
||||||
scenario.value.stepFileParam[activeStep.value?.id] = {
|
scenario.value.stepFileParam[activeStep.value?.id] = {
|
||||||
|
@ -1363,10 +1250,9 @@
|
||||||
...activeStep.value.config,
|
...activeStep.value.config,
|
||||||
method: request.method,
|
method: request.method,
|
||||||
};
|
};
|
||||||
activeStep.value.name = request.stepName || request.name;
|
|
||||||
emit('updateResource', request.uploadFileIds, request.linkFileIds);
|
emit('updateResource', request.uploadFileIds, request.linkFileIds);
|
||||||
activeStep.value = undefined;
|
|
||||||
}
|
}
|
||||||
|
activeStep.value = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1408,7 +1294,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveScriptStep(name: string, scriptProcessor: ExecuteConditionProcessor, unSaved = false) {
|
function saveScriptStep(name: string, scriptProcessor: ExecuteConditionProcessor, unSaved = false) {
|
||||||
if (activeStep.value) {
|
if (activeStep.value && !activeStep.value.isQuoteScenarioStep) {
|
||||||
|
// 引用的场景步骤不需要存储详情
|
||||||
stepDetails.value[activeStep.value.id] = cloneDeep(scriptProcessor);
|
stepDetails.value[activeStep.value.id] = cloneDeep(scriptProcessor);
|
||||||
activeStep.value.name = name;
|
activeStep.value.name = name;
|
||||||
activeStep.value = undefined;
|
activeStep.value = undefined;
|
||||||
|
@ -1418,34 +1305,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const showQuickInput = ref(false);
|
|
||||||
const quickInputParamValue = ref<any>('');
|
|
||||||
const quickInputDataKey = ref('');
|
|
||||||
|
|
||||||
const {
|
|
||||||
setQuickInput,
|
|
||||||
clearQuickInput,
|
|
||||||
applyQuickInput,
|
|
||||||
handleStepDescClick,
|
|
||||||
applyStepDescChange,
|
|
||||||
handleStepContentChange,
|
|
||||||
handleStepToggleEnable,
|
|
||||||
handleStepNameClick,
|
|
||||||
applyStepNameChange,
|
|
||||||
} = useStepNodeEdit({
|
|
||||||
steps,
|
|
||||||
scenario,
|
|
||||||
activeStep,
|
|
||||||
quickInputDataKey,
|
|
||||||
quickInputParamValue,
|
|
||||||
showQuickInput,
|
|
||||||
treeRef,
|
|
||||||
tempStepDesc,
|
|
||||||
showStepDescEditInputStepId,
|
|
||||||
tempStepName,
|
|
||||||
showStepNameEditInputStepId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const dbClick = ref({
|
const dbClick = ref({
|
||||||
e: null as MouseEvent | null,
|
e: null as MouseEvent | null,
|
||||||
timeStamp: 0,
|
timeStamp: 0,
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
|
import { Message } from '@arco-design/web-vue';
|
||||||
|
|
||||||
import MsTree from '@/components/business/ms-tree/index.vue';
|
import MsTree from '@/components/business/ms-tree/index.vue';
|
||||||
|
|
||||||
import { findNodeByKey } from '@/utils';
|
import { getScenarioDetail } from '@/api/modules/api-test/scenario';
|
||||||
|
import { t } from '@/hooks/useI18n';
|
||||||
|
import { findNodeByKey, getGenerateId, mapTree } from '@/utils';
|
||||||
|
|
||||||
import type { Scenario, ScenarioStepDetail, ScenarioStepItem } from '@/models/apiTest/scenario';
|
import type { Scenario, ScenarioStepConfig, ScenarioStepDetail, ScenarioStepItem } from '@/models/apiTest/scenario';
|
||||||
|
import { ScenarioStepRefType } from '@/enums/apiEnum';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理步骤节点信息更改
|
* 处理步骤节点信息更改
|
||||||
|
@ -19,6 +24,9 @@ export default function useStepNodeEdit({
|
||||||
showStepDescEditInputStepId,
|
showStepDescEditInputStepId,
|
||||||
tempStepName,
|
tempStepName,
|
||||||
showStepNameEditInputStepId,
|
showStepNameEditInputStepId,
|
||||||
|
loading,
|
||||||
|
selectedKeys,
|
||||||
|
showScenarioConfig,
|
||||||
}: {
|
}: {
|
||||||
steps: Ref<ScenarioStepItem[]>;
|
steps: Ref<ScenarioStepItem[]>;
|
||||||
scenario: Ref<Scenario>;
|
scenario: Ref<Scenario>;
|
||||||
|
@ -31,6 +39,9 @@ export default function useStepNodeEdit({
|
||||||
showStepDescEditInputStepId: Ref<string | number>;
|
showStepDescEditInputStepId: Ref<string | number>;
|
||||||
tempStepName: Ref<string>;
|
tempStepName: Ref<string>;
|
||||||
showStepNameEditInputStepId: Ref<string | number>;
|
showStepNameEditInputStepId: Ref<string | number>;
|
||||||
|
loading: Ref<boolean>;
|
||||||
|
selectedKeys: Ref<Array<string | number>>;
|
||||||
|
showScenarioConfig: Ref<boolean>;
|
||||||
}) {
|
}) {
|
||||||
/**
|
/**
|
||||||
* 打开快速输入
|
* 打开快速输入
|
||||||
|
@ -162,6 +173,125 @@ export default function useStepNodeEdit({
|
||||||
scenario.value.unSaved = !!tempStepName.value;
|
scenario.value.unSaved = !!tempStepName.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const scenarioConfigForm = ref<
|
||||||
|
ScenarioStepConfig & {
|
||||||
|
refType: ScenarioStepRefType;
|
||||||
|
}
|
||||||
|
>({
|
||||||
|
refType: ScenarioStepRefType.REF,
|
||||||
|
enableScenarioEnv: false,
|
||||||
|
useOriginScenarioParamPreferential: true,
|
||||||
|
useOriginScenarioParam: false,
|
||||||
|
});
|
||||||
|
// const scenarioConfigParamTip = computed(() => {
|
||||||
|
// if (!scenarioConfigForm.value.useOriginScenarioParam && !scenarioConfigForm.value.enableScenarioEnv) {
|
||||||
|
// // 非使用原场景参数-非选择源场景环境
|
||||||
|
// return t('apiScenario.notSource');
|
||||||
|
// }
|
||||||
|
// if (!scenarioConfigForm.value.useOriginScenarioParam && scenarioConfigForm.value.enableScenarioEnv) {
|
||||||
|
// // 非使用原场景参数-选择源场景环境
|
||||||
|
// return t('apiScenario.notSourceParamAndSourceEnv');
|
||||||
|
// }
|
||||||
|
// if (
|
||||||
|
// scenarioConfigForm.value.useOriginScenarioParam &&
|
||||||
|
// scenarioConfigForm.value.useOriginScenarioParamPreferential &&
|
||||||
|
// !scenarioConfigForm.value.enableScenarioEnv
|
||||||
|
// ) {
|
||||||
|
// // 使用原场景参数-优先使用原场景参数
|
||||||
|
// return t('apiScenario.sourceParamAndSource');
|
||||||
|
// }
|
||||||
|
// if (
|
||||||
|
// scenarioConfigForm.value.useOriginScenarioParam &&
|
||||||
|
// scenarioConfigForm.value.useOriginScenarioParamPreferential &&
|
||||||
|
// scenarioConfigForm.value.enableScenarioEnv
|
||||||
|
// ) {
|
||||||
|
// // 使用原场景参数-优先使用原场景参数-选择源场景环境
|
||||||
|
// return t('apiScenario.sourceParamAndSourceEnv');
|
||||||
|
// }
|
||||||
|
// if (
|
||||||
|
// scenarioConfigForm.value.useOriginScenarioParam &&
|
||||||
|
// !scenarioConfigForm.value.useOriginScenarioParamPreferential &&
|
||||||
|
// !scenarioConfigForm.value.enableScenarioEnv
|
||||||
|
// ) {
|
||||||
|
// // 使用原场景参数-优先使用当前场景参数
|
||||||
|
// return t('apiScenario.currentParamAndSource');
|
||||||
|
// }
|
||||||
|
// if (
|
||||||
|
// scenarioConfigForm.value.useOriginScenarioParam &&
|
||||||
|
// !scenarioConfigForm.value.useOriginScenarioParamPreferential &&
|
||||||
|
// scenarioConfigForm.value.enableScenarioEnv
|
||||||
|
// ) {
|
||||||
|
// // 使用原场景参数-优先使用当前场景参数-选择源场景环境
|
||||||
|
// return t('apiScenario.currentParamAndSourceEnv');
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
// 关闭场景配置弹窗
|
||||||
|
function cancelScenarioConfig() {
|
||||||
|
showScenarioConfig.value = false;
|
||||||
|
scenarioConfigForm.value = {
|
||||||
|
refType: ScenarioStepRefType.REF,
|
||||||
|
enableScenarioEnv: false,
|
||||||
|
useOriginScenarioParamPreferential: true,
|
||||||
|
useOriginScenarioParam: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新引用场景的步骤数据
|
||||||
|
*/
|
||||||
|
async function refreshScenarioStepInfo(step: ScenarioStepItem, id: string | number) {
|
||||||
|
try {
|
||||||
|
loading.value = true;
|
||||||
|
const res = await getScenarioDetail(id);
|
||||||
|
if (step.children) {
|
||||||
|
step.children = mapTree(res.steps || [], (child) => {
|
||||||
|
child.uniqueId = getGenerateId();
|
||||||
|
child.isQuoteScenarioStep = true; // 标记为引用场景下的子步骤
|
||||||
|
child.isRefScenarioStep = true; // 标记为完全引用场景
|
||||||
|
child.draggable = false; // 引用场景下的任何步骤不可拖拽
|
||||||
|
if (selectedKeys.value.includes(step.uniqueId) && !selectedKeys.value.includes(child.uniqueId)) {
|
||||||
|
// 如果有新增的子步骤,且当前步骤被选中,则这个新增的子步骤也要选中
|
||||||
|
selectedKeys.value.push(child.uniqueId);
|
||||||
|
}
|
||||||
|
return child;
|
||||||
|
}) as ScenarioStepItem[];
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用场景配置
|
||||||
|
async function saveScenarioConfig() {
|
||||||
|
if (activeStep.value) {
|
||||||
|
const realStep = findNodeByKey<ScenarioStepItem>(steps.value, activeStep.value.uniqueId, 'uniqueId');
|
||||||
|
if (realStep) {
|
||||||
|
realStep.refType = scenarioConfigForm.value.refType; // 更新场景引用类型
|
||||||
|
realStep.config = {
|
||||||
|
...realStep.config,
|
||||||
|
...scenarioConfigForm.value,
|
||||||
|
};
|
||||||
|
if (scenarioConfigForm.value.refType === ScenarioStepRefType.REF) {
|
||||||
|
// 更新子孙步骤完全引用
|
||||||
|
await refreshScenarioStepInfo(realStep as ScenarioStepItem, realStep.resourceId);
|
||||||
|
} else {
|
||||||
|
realStep.children = mapTree<ScenarioStepItem>(realStep.children || [], (child) => {
|
||||||
|
// 更新子孙步骤-步骤引用
|
||||||
|
child.isRefScenarioStep = false;
|
||||||
|
return child;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Message.success(t('apiScenario.setSuccess'));
|
||||||
|
scenario.value.unSaved = true;
|
||||||
|
cancelScenarioConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
setQuickInput,
|
setQuickInput,
|
||||||
clearQuickInput,
|
clearQuickInput,
|
||||||
|
@ -172,5 +302,8 @@ export default function useStepNodeEdit({
|
||||||
handleStepToggleEnable,
|
handleStepToggleEnable,
|
||||||
handleStepNameClick,
|
handleStepNameClick,
|
||||||
applyStepNameChange,
|
applyStepNameChange,
|
||||||
|
saveScenarioConfig,
|
||||||
|
cancelScenarioConfig,
|
||||||
|
scenarioConfigForm,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -241,6 +241,7 @@ export default function useStepOperation({
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
getStepDetail,
|
||||||
handleStepExpand,
|
handleStepExpand,
|
||||||
handleStepSelect,
|
handleStepSelect,
|
||||||
deleteStep,
|
deleteStep,
|
||||||
|
|
|
@ -317,7 +317,10 @@
|
||||||
const waitTingDebugSteps = filterTree(activeScenarioTab.value.steps, (node) => {
|
const waitTingDebugSteps = filterTree(activeScenarioTab.value.steps, (node) => {
|
||||||
if (node.enable) {
|
if (node.enable) {
|
||||||
node.executeStatus = ScenarioExecuteStatus.EXECUTING;
|
node.executeStatus = ScenarioExecuteStatus.EXECUTING;
|
||||||
waitingDebugStepDetails[node.id] = activeScenarioTab.value.stepDetails[node.id];
|
if (!node.isQuoteScenarioStep) {
|
||||||
|
// 引用场景的步骤详情不传
|
||||||
|
waitingDebugStepDetails[node.id] = activeScenarioTab.value.stepDetails[node.id];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
node.executeStatus = undefined;
|
node.executeStatus = undefined;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue