feat(接口调试): 接口调试文件参数联调&问题修复
This commit is contained in:
parent
d199f398ba
commit
716e5ead03
|
@ -4,6 +4,7 @@ import {
|
||||||
AddDebugModuleUrl,
|
AddDebugModuleUrl,
|
||||||
DeleteDebugModuleUrl,
|
DeleteDebugModuleUrl,
|
||||||
DeleteDebugUrl,
|
DeleteDebugUrl,
|
||||||
|
DragDebugUrl,
|
||||||
ExecuteApiDebugUrl,
|
ExecuteApiDebugUrl,
|
||||||
GetApiDebugDetailUrl,
|
GetApiDebugDetailUrl,
|
||||||
GetDebugModuleCountUrl,
|
GetDebugModuleCountUrl,
|
||||||
|
@ -11,6 +12,7 @@ import {
|
||||||
MoveDebugModuleUrl,
|
MoveDebugModuleUrl,
|
||||||
UpdateApiDebugUrl,
|
UpdateApiDebugUrl,
|
||||||
UpdateDebugModuleUrl,
|
UpdateDebugModuleUrl,
|
||||||
|
UploadTempFileUrl,
|
||||||
} from '@/api/requrls/api-test/debug';
|
} from '@/api/requrls/api-test/debug';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -21,7 +23,7 @@ import {
|
||||||
UpdateDebugModule,
|
UpdateDebugModule,
|
||||||
UpdateDebugParams,
|
UpdateDebugParams,
|
||||||
} from '@/models/apiTest/debug';
|
} from '@/models/apiTest/debug';
|
||||||
import { ModuleTreeNode, MoveModules } from '@/models/common';
|
import { DragSortParams, ModuleTreeNode, MoveModules } from '@/models/common';
|
||||||
|
|
||||||
// 获取模块树
|
// 获取模块树
|
||||||
export function getDebugModules() {
|
export function getDebugModules() {
|
||||||
|
@ -53,6 +55,11 @@ export function getDebugModuleCount(data: { keyword: string }) {
|
||||||
return MSR.post({ url: GetDebugModuleCountUrl, data });
|
return MSR.post({ url: GetDebugModuleCountUrl, data });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 拖拽调试节点
|
||||||
|
export function dragDebug(data: DragSortParams) {
|
||||||
|
return MSR.post({ url: DragDebugUrl, data });
|
||||||
|
}
|
||||||
|
|
||||||
// 执行调试
|
// 执行调试
|
||||||
export function executeDebug(data: ExecuteRequestParams) {
|
export function executeDebug(data: ExecuteRequestParams) {
|
||||||
return MSR.post<ExecuteRequestParams>({ url: ExecuteApiDebugUrl, data });
|
return MSR.post<ExecuteRequestParams>({ url: ExecuteApiDebugUrl, data });
|
||||||
|
@ -77,3 +84,8 @@ export function getDebugDetail(id: string) {
|
||||||
export function deleteDebug(id: string) {
|
export function deleteDebug(id: string) {
|
||||||
return MSR.get({ url: DeleteDebugUrl, params: id });
|
return MSR.get({ url: DeleteDebugUrl, params: id });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 上传文件
|
||||||
|
export function uploadTempFile(file: File) {
|
||||||
|
return MSR.uploadFile({ url: UploadTempFileUrl }, { fileList: [file] }, 'file');
|
||||||
|
}
|
||||||
|
|
|
@ -9,3 +9,5 @@ export const GetDebugModuleCountUrl = '/api/debug/module/count'; // 模块统计
|
||||||
export const AddDebugModuleUrl = '/api/debug/module/add'; // 添加模块
|
export const AddDebugModuleUrl = '/api/debug/module/add'; // 添加模块
|
||||||
export const GetDebugModulesUrl = '/api/debug/module/tree'; // 查询模块树
|
export const GetDebugModulesUrl = '/api/debug/module/tree'; // 查询模块树
|
||||||
export const DeleteDebugModuleUrl = '/api/debug/module/delete'; // 删除模块
|
export const DeleteDebugModuleUrl = '/api/debug/module/delete'; // 删除模块
|
||||||
|
export const DragDebugUrl = '/api/debug/edit/pos'; // 拖拽调试节点
|
||||||
|
export const UploadTempFileUrl = '/api/debug/upload/temp/file'; // 上传文件
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
<template>
|
||||||
|
<a-dropdown position="tl" trigger="hover">
|
||||||
|
<a-button size="mini" type="outline">
|
||||||
|
<template #icon> <icon-upload class="text-[14px] !text-[rgb(var(--primary-5))]" /> </template>
|
||||||
|
</a-button>
|
||||||
|
<template #content>
|
||||||
|
<a-upload
|
||||||
|
ref="uploadRef"
|
||||||
|
v-model:file-list="innerFileList"
|
||||||
|
:auto-upload="false"
|
||||||
|
:show-file-list="false"
|
||||||
|
:before-upload="beforeUpload"
|
||||||
|
@change="handleChange"
|
||||||
|
>
|
||||||
|
<template #upload-button>
|
||||||
|
<a-button size="small" type="text" class="ms-add-attachment-dropdown-btn">
|
||||||
|
<icon-upload class="mr-[8px]" />{{ t('ms.add.attachment.localUpload') }}
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
|
</a-upload>
|
||||||
|
<a-button size="small" type="text" class="ms-add-attachment-dropdown-btn" @click="emit('linkFile')">
|
||||||
|
<MsIcon type="icon-icon_link-copy_outlined" class="mr-[8px]" size="16" />
|
||||||
|
{{ t('ms.add.attachment.associateFile') }}
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
|
</a-dropdown>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { MsFileItem } from '@/components/pure/ms-upload/types';
|
||||||
|
|
||||||
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'upload', file: File): void;
|
||||||
|
(e: 'change', _fileList: MsFileItem[], fileItem: MsFileItem): void;
|
||||||
|
(e: 'linkFile'): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const innerFileList = defineModel<MsFileItem[]>('fileList', {
|
||||||
|
required: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
function beforeUpload(file: File) {
|
||||||
|
emit('upload', file);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleChange(_fileList: MsFileItem[], fileItem: MsFileItem) {
|
||||||
|
emit('change', _fileList, fileItem);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.ms-add-attachment-dropdown-btn {
|
||||||
|
padding-right: 8px;
|
||||||
|
padding-left: 8px;
|
||||||
|
color: var(--color-text-1) !important;
|
||||||
|
&:hover {
|
||||||
|
background: rgb(var(--primary-1)) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,12 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<a-form-item field="attachment" :label="t('caseManagement.featureCase.addAttachment')">
|
<a-form-item v-if="props.mode === 'button'" field="attachment" :label="t('caseManagement.featureCase.addAttachment')">
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<div class="mb-1">
|
<div class="mb-1">
|
||||||
<a-dropdown position="tr" trigger="hover">
|
<a-dropdown position="tr" trigger="hover">
|
||||||
<a-button type="outline">
|
<a-button type="outline">
|
||||||
<template #icon> <icon-plus class="text-[14px]" /> </template
|
<template #icon> <icon-plus class="text-[14px]" /> </template>
|
||||||
>{{ t('system.orgTemplate.addAttachment') }}</a-button
|
{{ t('system.orgTemplate.addAttachment') }}
|
||||||
>
|
</a-button>
|
||||||
<template #content>
|
<template #content>
|
||||||
<a-upload
|
<a-upload
|
||||||
ref="uploadRef"
|
ref="uploadRef"
|
||||||
|
@ -17,61 +17,212 @@
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
>
|
>
|
||||||
<template #upload-button>
|
<template #upload-button>
|
||||||
<a-button type="text" class="!text-[var(--color-text-1)]">
|
<a-button type="text" class="arco-dropdown-option !text-[var(--color-text-1)]">
|
||||||
<icon-upload />{{ t('caseManagement.featureCase.uploadFile') }}</a-button
|
<icon-upload />{{ t('caseManagement.featureCase.uploadFile') }}
|
||||||
>
|
</a-button>
|
||||||
</template>
|
</template>
|
||||||
</a-upload>
|
</a-upload>
|
||||||
<a-button type="text" class="!text-[var(--color-text-1)]" @click="associatedFile">
|
<a-button type="text" class="arco-dropdown-option !text-[var(--color-text-1)]" @click="associatedFile">
|
||||||
<MsIcon type="icon-icon_link-copy_outlined" size="16" />{{
|
<MsIcon type="icon-icon_link-copy_outlined" size="16" />
|
||||||
t('caseManagement.featureCase.associatedFile')
|
{{ t('caseManagement.featureCase.associatedFile') }}
|
||||||
}}</a-button
|
</a-button>
|
||||||
>
|
|
||||||
</template>
|
</template>
|
||||||
</a-dropdown>
|
</a-dropdown>
|
||||||
</div>
|
</div>
|
||||||
<div class="!hover:bg-[rgb(var(--primary-1))] !text-[var(--color-text-4)]">{{
|
<div class="!hover:bg-[rgb(var(--primary-1))] !text-[var(--color-text-4)]">
|
||||||
t('system.orgTemplate.addAttachmentTip')
|
{{ t('system.orgTemplate.addAttachmentTip') }}
|
||||||
}}</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<template v-else>
|
||||||
|
<div v-if="props.multiple" class="flex w-full items-center gap-[4px]">
|
||||||
|
<dropdownMenu v-model:file-list="innerFileList" @link-file="associatedFile" @change="handleChange" />
|
||||||
|
<MsTagsInput
|
||||||
|
v-model:model-value="inputFiles"
|
||||||
|
:class="props.inputClass"
|
||||||
|
placeholder=" "
|
||||||
|
:max-tag-count="1"
|
||||||
|
readonly
|
||||||
|
>
|
||||||
|
<template #tag="{ data }">
|
||||||
|
<MsTag :closable="!data.label.includes('+')" class="m-0 p-0" @close="() => handleClose(data)">
|
||||||
|
{{ data.label }}
|
||||||
|
</MsTag>
|
||||||
|
</template>
|
||||||
|
</MsTagsInput>
|
||||||
|
</div>
|
||||||
|
<div v-else class="flex w-full items-center gap-[4px]">
|
||||||
|
<dropdownMenu v-model:file-list="innerFileList" @link-file="associatedFile" @change="handleChange" />
|
||||||
|
<a-input
|
||||||
|
v-model:model-value="inputFileName"
|
||||||
|
:class="props.inputClass"
|
||||||
|
allow-clear
|
||||||
|
readonly
|
||||||
|
@clear="handleFileClear"
|
||||||
|
>
|
||||||
|
</a-input>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<LinkFileDrawer
|
||||||
|
v-model:visible="showDrawer"
|
||||||
|
:get-tree-request="getModules"
|
||||||
|
:get-count-request="getModulesCount"
|
||||||
|
:get-list-request="getAssociatedFileListUrl"
|
||||||
|
:get-list-fun-params="getListFunParams"
|
||||||
|
:selector-type="props.multiple ? 'checkbox' : 'radio'"
|
||||||
|
@save="saveSelectAssociatedFile"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useVModel } from '@vueuse/core';
|
import { useVModel } from '@vueuse/core';
|
||||||
|
import { TagData } from '@arco-design/web-vue';
|
||||||
|
|
||||||
|
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
|
||||||
|
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
||||||
import type { MsFileItem } from '@/components/pure/ms-upload/types';
|
import type { MsFileItem } from '@/components/pure/ms-upload/types';
|
||||||
|
import LinkFileDrawer from '@/components/business/ms-link-file/associatedFileDrawer.vue';
|
||||||
|
import dropdownMenu from './dropdownMenu.vue';
|
||||||
|
|
||||||
|
import { getAssociatedFileListUrl } from '@/api/modules/case-management/featureCase';
|
||||||
|
import { getModules, getModulesCount } from '@/api/modules/project-management/fileManagement';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
|
||||||
|
import { AssociatedList } from '@/models/caseManagement/featureCase';
|
||||||
|
import { TableQueryParams } from '@/models/common';
|
||||||
|
|
||||||
|
import { convertToFile } from '@/views/case-management/caseManagementFeature/components/utils';
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
mode: 'button' | 'input';
|
||||||
|
fileList: MsFileItem[];
|
||||||
|
multiple?: boolean;
|
||||||
|
inputClass?: string;
|
||||||
|
fields: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
mode: 'button',
|
||||||
|
multiple: true,
|
||||||
|
fields: () => ({
|
||||||
|
id: 'uid',
|
||||||
|
name: 'name',
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'update:fileList', fileList: MsFileItem[]): void;
|
||||||
|
(e: 'upload', file: File): void;
|
||||||
|
(e: 'change', _fileList: MsFileItem[], fileItem?: MsFileItem): void;
|
||||||
|
(e: 'linkFile'): void;
|
||||||
|
(e: 'deleteFile', fileId?: string | number): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
fileList: MsFileItem[];
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
|
||||||
(e: 'upload', file: File): void;
|
|
||||||
(e: 'change', _fileList: MsFileItem[], fileItem: MsFileItem): void;
|
|
||||||
(e: 'linkFile'): void;
|
|
||||||
(e: 'update:fileList', fileList: MsFileItem[]): void;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
// const innerFileList = ref<MsFileItem[]>([]);
|
|
||||||
const innerFileList = useVModel(props, 'fileList', emit);
|
const innerFileList = useVModel(props, 'fileList', emit);
|
||||||
|
const inputFileName = ref('');
|
||||||
|
const inputFiles = ref<TagData[]>([]);
|
||||||
|
const showDrawer = ref(false);
|
||||||
|
const getListFunParams = ref<TableQueryParams>({
|
||||||
|
combine: {
|
||||||
|
hiddenIds: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeMount(() => {
|
||||||
|
// 回显文件
|
||||||
|
const defaultFiles = props.fileList.filter((item) => item) || [];
|
||||||
|
if (defaultFiles.length > 0) {
|
||||||
|
if (props.multiple) {
|
||||||
|
inputFiles.value = defaultFiles.map((item) => ({
|
||||||
|
// 这里取自定义的字段名,因为存在查看的场景时不会与刚选择的文件信息一样
|
||||||
|
value: item?.[props.fields.id] || '',
|
||||||
|
label: item?.[props.fields.name] || '',
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
inputFileName.value = defaultFiles[0]?.[props.fields.name] || '';
|
||||||
|
}
|
||||||
|
getListFunParams.value.combine.hiddenIds = defaultFiles
|
||||||
|
.filter((item) => !item?.local)
|
||||||
|
.map((item) => item?.[props.fields.id] || '')
|
||||||
|
.filter((item) => item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function beforeUpload(file: File) {
|
function beforeUpload(file: File) {
|
||||||
emit('upload', file);
|
emit('upload', file);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleChange(_fileList: MsFileItem[], fileItem: MsFileItem) {
|
function handleChange(_fileList: MsFileItem[], fileItem: MsFileItem) {
|
||||||
innerFileList.value = _fileList;
|
innerFileList.value = _fileList.map((item) => ({ ...item, local: true }));
|
||||||
|
if (props.multiple) {
|
||||||
|
inputFiles.value = _fileList.map((item) => ({
|
||||||
|
value: item?.uid || '',
|
||||||
|
label: item?.name || '',
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
inputFileName.value = fileItem.name || '';
|
||||||
|
}
|
||||||
emit('change', _fileList, fileItem);
|
emit('change', _fileList, fileItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
function associatedFile() {
|
function associatedFile() {
|
||||||
emit('linkFile');
|
// TODO: 按钮模式逻辑待合并
|
||||||
|
if (props.mode === 'button') {
|
||||||
|
emit('linkFile');
|
||||||
|
} else {
|
||||||
|
showDrawer.value = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监视文件列表处理关联和本地文件
|
||||||
|
watch(
|
||||||
|
() => innerFileList.value,
|
||||||
|
() => {
|
||||||
|
getListFunParams.value.combine.hiddenIds = innerFileList.value
|
||||||
|
.filter((item) => !item.local)
|
||||||
|
.map((item) => item[props.fields.id] || item.uid);
|
||||||
|
},
|
||||||
|
{ deep: true, immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
// 处理关联文件
|
||||||
|
function saveSelectAssociatedFile(fileData: AssociatedList[]) {
|
||||||
|
const fileResultList = fileData.map((fileInfo) => convertToFile(fileInfo));
|
||||||
|
if (props.mode === 'button') {
|
||||||
|
innerFileList.value.push(...fileResultList);
|
||||||
|
} else if (props.multiple) {
|
||||||
|
innerFileList.value.push(...fileResultList);
|
||||||
|
inputFiles.value.push(
|
||||||
|
...fileResultList.map((item) => ({
|
||||||
|
value: item?.uid || '',
|
||||||
|
label: item?.name || '',
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// 单选文件
|
||||||
|
innerFileList.value = fileResultList;
|
||||||
|
inputFileName.value = fileResultList[0].name || '';
|
||||||
|
}
|
||||||
|
emit('change', innerFileList.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleClose(data: TagData) {
|
||||||
|
inputFiles.value = inputFiles.value.filter((item) => item.value !== data.value);
|
||||||
|
innerFileList.value = innerFileList.value.filter((item) => item[props.fields.id] !== data.value);
|
||||||
|
emit('deleteFile', data.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleFileClear() {
|
||||||
|
inputFileName.value = '';
|
||||||
|
inputFiles.value = [];
|
||||||
|
innerFileList.value = [];
|
||||||
|
emit('change', []);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style lang="less" scoped></style>
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
export default {
|
||||||
|
'ms.add.attachment.localUpload': 'Local upload',
|
||||||
|
'ms.add.attachment.associateFile': 'Associate file',
|
||||||
|
};
|
|
@ -0,0 +1,4 @@
|
||||||
|
export default {
|
||||||
|
'ms.add.attachment.localUpload': '本地上传',
|
||||||
|
'ms.add.attachment.associateFile': '关联文件',
|
||||||
|
};
|
|
@ -52,7 +52,7 @@
|
||||||
</template>
|
</template>
|
||||||
<a-input
|
<a-input
|
||||||
v-if="model.type === 'input'"
|
v-if="model.type === 'input'"
|
||||||
v-model="element[model.filed]"
|
v-model:model-value="element[model.filed]"
|
||||||
class="flex-1"
|
class="flex-1"
|
||||||
:placeholder="t(model.placeholder || '')"
|
:placeholder="t(model.placeholder || '')"
|
||||||
:max-length="model.maxLength || 255"
|
:max-length="model.maxLength || 255"
|
||||||
|
@ -61,11 +61,12 @@
|
||||||
/>
|
/>
|
||||||
<a-input-number
|
<a-input-number
|
||||||
v-if="model.type === 'inputNumber'"
|
v-if="model.type === 'inputNumber'"
|
||||||
v-model="element[model.filed]"
|
v-model:model-value="element[model.filed]"
|
||||||
class="flex-1"
|
class="flex-1"
|
||||||
:placeholder="t(model.placeholder || '')"
|
:placeholder="t(model.placeholder || '')"
|
||||||
:min="model.min"
|
:min="model.min"
|
||||||
:max="model.max || 9999999"
|
:max="model.max || 9999999"
|
||||||
|
model-event="input"
|
||||||
allow-clear
|
allow-clear
|
||||||
@change="emit('change')"
|
@change="emit('change')"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
:placeholder="t('project.commonScript.pleaseSelected')"
|
:placeholder="t('project.commonScript.pleaseSelected')"
|
||||||
@change="changeHandler"
|
@change="changeHandler"
|
||||||
>
|
>
|
||||||
<a-option v-for="item of languages" :key="item.value">
|
<a-option v-for="item of languages" :key="item.value" :value="item.value">
|
||||||
<a-tooltip :content="item.text">
|
<a-tooltip :content="item.text">
|
||||||
{{ item.text }}
|
{{ item.text }}
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
|
@ -64,8 +64,8 @@
|
||||||
(e: 'update:languagesType', value: Language): void;
|
(e: 'update:languagesType', value: Language): void;
|
||||||
(e: 'insert', code: string): void;
|
(e: 'insert', code: string): void;
|
||||||
(e: 'formApiImport'): void; // 从api 定义导入
|
(e: 'formApiImport'): void; // 从api 定义导入
|
||||||
(e: 'insertCommonScript'): void; // 从api 定义导入
|
(e: 'insertCommonScript'): void; // 插入公共脚本
|
||||||
(e: 'updateLanguages', value: Language): void; // 从api 定义导入
|
(e: 'updateLanguages', value: Language): void; // 更新语言类型
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const innerExpand = useVModel(props, 'expand', emit);
|
const innerExpand = useVModel(props, 'expand', emit);
|
||||||
|
@ -73,11 +73,11 @@
|
||||||
const innerLanguageType = useVModel(props, 'languagesType', emit);
|
const innerLanguageType = useVModel(props, 'languagesType', emit);
|
||||||
|
|
||||||
const languages = [
|
const languages = [
|
||||||
{ text: 'beanshellJSR223', value: 'beanshell-jsr233' },
|
{ text: 'beanshellJSR223', value: RequestConditionScriptLanguage.BEANSHELL_JSR233 },
|
||||||
{ text: 'beanshell', value: 'beanshell' },
|
{ text: 'beanshell', value: RequestConditionScriptLanguage.BEANSHELL },
|
||||||
{ text: 'python', value: 'python' },
|
{ text: 'python', value: RequestConditionScriptLanguage.PYTHON },
|
||||||
{ text: 'groovy', value: 'groovy' },
|
{ text: 'groovy', value: RequestConditionScriptLanguage.GROOVY },
|
||||||
{ text: 'javascript', value: 'javascript' },
|
{ text: 'javascript', value: RequestConditionScriptLanguage.JAVASCRIPT },
|
||||||
];
|
];
|
||||||
|
|
||||||
function expandedHandler() {
|
function expandedHandler() {
|
||||||
|
|
|
@ -14,9 +14,9 @@
|
||||||
{{ t('project.commonScript.clear') }}</MsTag
|
{{ t('project.commonScript.clear') }}</MsTag
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<MsTag class="cursor-pointer" theme="outline" @click="formatCoding">{{
|
<MsTag class="cursor-pointer" theme="outline" @click="formatCoding">
|
||||||
t('project.commonScript.formatting')
|
{{ t('project.commonScript.formatting') }}
|
||||||
}}</MsTag>
|
</MsTag>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="props.showType === 'commonScript'" class="flex bg-[var(--color-bg-3)]">
|
<div v-if="props.showType === 'commonScript'" class="flex bg-[var(--color-bg-3)]">
|
||||||
|
@ -179,6 +179,13 @@ ${item.script}
|
||||||
function clearCode() {
|
function clearCode() {
|
||||||
innerCodeValue.value = '';
|
innerCodeValue.value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
formatCoding,
|
||||||
|
insertHandler,
|
||||||
|
undoHandler,
|
||||||
|
clearCode,
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less"></style>
|
<style scoped lang="less"></style>
|
||||||
|
|
|
@ -4,11 +4,12 @@
|
||||||
:width="props.width"
|
:width="props.width"
|
||||||
:footer="false"
|
:footer="false"
|
||||||
class="ms-drawer"
|
class="ms-drawer"
|
||||||
|
:show-full-screen="props.showFullScreen"
|
||||||
no-content-padding
|
no-content-padding
|
||||||
unmount-on-close
|
unmount-on-close
|
||||||
>
|
>
|
||||||
<template #title>
|
<template #title>
|
||||||
<div class="flex w-full items-center">
|
<div class="flex flex-1 items-center">
|
||||||
<a-tooltip :content="props.title" position="bottom">
|
<a-tooltip :content="props.title" position="bottom">
|
||||||
<div class="one-line-text max-w-[300px]">
|
<div class="one-line-text max-w-[300px]">
|
||||||
{{ props.title }}
|
{{ props.title }}
|
||||||
|
@ -51,6 +52,7 @@
|
||||||
detailIndex: number; // 详情 下标
|
detailIndex: number; // 详情 下标
|
||||||
tableData: any[]; // 表格数据
|
tableData: any[]; // 表格数据
|
||||||
pagination: MsPaginationI; // 分页器对象
|
pagination: MsPaginationI; // 分页器对象
|
||||||
|
showFullScreen?: boolean; // 是否显示全屏按钮
|
||||||
pageChange: (page: number) => Promise<void>; // 分页变更函数
|
pageChange: (page: number) => Promise<void>; // 分页变更函数
|
||||||
getDetailFunc: (id: string) => Promise<any>; // 获取详情的请求函数
|
getDetailFunc: (id: string) => Promise<any>; // 获取详情的请求函数
|
||||||
}>();
|
}>();
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<MsDrawer
|
<MsDrawer
|
||||||
v-model:visible="showDrawer"
|
v-model:visible="showDrawer"
|
||||||
:mask="false"
|
|
||||||
:title="t('caseManagement.featureCase.associatedFile')"
|
:title="t('caseManagement.featureCase.associatedFile')"
|
||||||
:ok-text="t('caseManagement.featureCase.associated')"
|
:ok-text="t('caseManagement.featureCase.associated')"
|
||||||
:ok-loading="drawerLoading"
|
:ok-loading="drawerLoading"
|
||||||
|
@ -72,6 +71,7 @@
|
||||||
:show-type="showType"
|
:show-type="showType"
|
||||||
:get-list-request="props.getListRequest"
|
:get-list-request="props.getListRequest"
|
||||||
:get-list-fun-params="props.getListFunParams"
|
:get-list-fun-params="props.getListFunParams"
|
||||||
|
:selector-type="props.selectorType"
|
||||||
@init="handleModuleTableInit"
|
@init="handleModuleTableInit"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
@ -103,6 +103,7 @@
|
||||||
getCountRequest: (params: any) => Promise<Record<string, any>>; // 获取左侧树模块数量请求
|
getCountRequest: (params: any) => Promise<Record<string, any>>; // 获取左侧树模块数量请求
|
||||||
getListRequest: (params: TableQueryParams) => Promise<CommonList<AssociatedList>>; // 获取表格请求
|
getListRequest: (params: TableQueryParams) => Promise<CommonList<AssociatedList>>; // 获取表格请求
|
||||||
getListFunParams: TableQueryParams; // 关联表去重id
|
getListFunParams: TableQueryParams; // 关联表去重id
|
||||||
|
selectorType?: 'none' | 'checkbox' | 'radio';
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
@press-enter="searchList"
|
@press-enter="searchList"
|
||||||
/></div>
|
/></div>
|
||||||
</div>
|
</div>
|
||||||
<ms-base-table v-bind="propsRes" ref="tableRef" no-disable v-on="propsEvent">
|
<ms-base-table v-bind="propsRes" ref="tableRef" v-model:selected-key="selectedKey" no-disable v-on="propsEvent">
|
||||||
<template #name="{ record }">
|
<template #name="{ record }">
|
||||||
<MsTag
|
<MsTag
|
||||||
v-if="record.fileType.toLowerCase() === 'jar'"
|
v-if="record.fileType.toLowerCase() === 'jar'"
|
||||||
|
@ -83,6 +83,7 @@
|
||||||
showType: 'Module' | 'Storage'; // 展示类型
|
showType: 'Module' | 'Storage'; // 展示类型
|
||||||
storageList: Repository[]; // 存储库列表
|
storageList: Repository[]; // 存储库列表
|
||||||
getListFunParams: TableQueryParams; // 表格额外去重参数
|
getListFunParams: TableQueryParams; // 表格额外去重参数
|
||||||
|
selectorType?: 'none' | 'checkbox' | 'radio';
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'init', params: FileListQueryParams): void;
|
(e: 'init', params: FileListQueryParams): void;
|
||||||
|
@ -144,6 +145,7 @@
|
||||||
selectable: true,
|
selectable: true,
|
||||||
showSelectAll: true,
|
showSelectAll: true,
|
||||||
heightUsed: 300,
|
heightUsed: 300,
|
||||||
|
selectorType: props.selectorType || 'checkbox',
|
||||||
},
|
},
|
||||||
(item) => {
|
(item) => {
|
||||||
return {
|
return {
|
||||||
|
@ -278,8 +280,6 @@
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const tableSelected = ref<AssociatedList[]>([]);
|
|
||||||
|
|
||||||
const selectedIds = computed(() => {
|
const selectedIds = computed(() => {
|
||||||
return [...propsRes.value.selectedKeys];
|
return [...propsRes.value.selectedKeys];
|
||||||
});
|
});
|
||||||
|
@ -287,8 +287,21 @@
|
||||||
watch(
|
watch(
|
||||||
() => selectedIds.value,
|
() => selectedIds.value,
|
||||||
() => {
|
() => {
|
||||||
tableSelected.value = propsRes.value.data.filter((item: any) => selectedIds.value.indexOf(item.id) > -1);
|
emit(
|
||||||
emit('update:selectFile', tableSelected.value);
|
'update:selectFile',
|
||||||
|
propsRes.value.data.filter((item: any) => selectedIds.value.indexOf(item.id) > -1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const selectedKey = ref('');
|
||||||
|
watch(
|
||||||
|
() => selectedKey.value,
|
||||||
|
(key) => {
|
||||||
|
emit(
|
||||||
|
'update:selectFile',
|
||||||
|
propsRes.value.data.filter((item: any) => key === item.id)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
v-model:selected-keys="innerSelectedKeys"
|
v-model:selected-keys="innerSelectedKeys"
|
||||||
:data="treeData"
|
:data="treeData"
|
||||||
class="ms-tree"
|
class="ms-tree"
|
||||||
|
:allow-drop="handleAllowDrop"
|
||||||
|
@drag-start="onDragStart"
|
||||||
|
@drag-end="onDragEnd"
|
||||||
@drop="onDrop"
|
@drop="onDrop"
|
||||||
@select="select"
|
@select="select"
|
||||||
@check="checked"
|
@check="checked"
|
||||||
|
@ -117,6 +120,7 @@
|
||||||
| 'right'
|
| 'right'
|
||||||
| 'rt'
|
| 'rt'
|
||||||
| 'rb'; // 标题 tooltip 的位置
|
| 'rb'; // 标题 tooltip 的位置
|
||||||
|
allowDrop?: (dropNode: MsTreeNodeData, dropPosition: -1 | 0 | 1, dragNode?: MsTreeNodeData | null) => boolean; // 是否允许放置
|
||||||
filterMoreActionFunc?: (items: ActionsItem[], node: MsTreeNodeData) => ActionsItem[]; // 过滤更多操作按钮
|
filterMoreActionFunc?: (items: ActionsItem[], node: MsTreeNodeData) => ActionsItem[]; // 过滤更多操作按钮
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
|
@ -265,6 +269,23 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const tempDragNode = ref<MsTreeNodeData | null>(null);
|
||||||
|
|
||||||
|
function handleAllowDrop({ dropNode, dropPosition }: { dropNode: MsTreeNodeData; dropPosition: -1 | 0 | 1 }) {
|
||||||
|
if (props.allowDrop) {
|
||||||
|
return props.allowDrop(dropNode, dropPosition, tempDragNode.value);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onDragStart(e, node: MsTreeNodeData) {
|
||||||
|
tempDragNode.value = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onDragEnd() {
|
||||||
|
tempDragNode.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理拖拽结束
|
* 处理拖拽结束
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -9,6 +9,7 @@ export interface MsTreeFieldNames extends TreeFieldNames {
|
||||||
|
|
||||||
export type MsTreeNodeData = {
|
export type MsTreeNodeData = {
|
||||||
hideMoreAction?: boolean; // 隐藏更多操作
|
hideMoreAction?: boolean; // 隐藏更多操作
|
||||||
|
parentId?: string;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
} & TreeNodeData;
|
} & TreeNodeData;
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,9 @@
|
||||||
top: 12,
|
top: 12,
|
||||||
bottom: 12,
|
bottom: 12,
|
||||||
},
|
},
|
||||||
|
minimap: {
|
||||||
|
enabled: false, // 将代码块预览隐藏
|
||||||
|
},
|
||||||
...props,
|
...props,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,10 @@
|
||||||
:unique-value="props.uniqueValue"
|
:unique-value="props.uniqueValue"
|
||||||
:max-tag-count="props.maxTagCount"
|
:max-tag-count="props.maxTagCount"
|
||||||
:readonly="props.readonly"
|
:readonly="props.readonly"
|
||||||
|
:class="props.class"
|
||||||
@press-enter="tagInputEnter"
|
@press-enter="tagInputEnter"
|
||||||
@blur="tagInputBlur"
|
@blur="tagInputBlur"
|
||||||
|
@clear="emit('clear')"
|
||||||
>
|
>
|
||||||
<template v-if="$slots.prefix" #prefix>
|
<template v-if="$slots.prefix" #prefix>
|
||||||
<slot name="prefix"></slot>
|
<slot name="prefix"></slot>
|
||||||
|
@ -47,15 +49,17 @@
|
||||||
maxTagCount?: number;
|
maxTagCount?: number;
|
||||||
maxLength?: number;
|
maxLength?: number;
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
|
class?: string;
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
retainInputValue: true,
|
retainInputValue: true,
|
||||||
uniqueValue: true,
|
uniqueValue: true,
|
||||||
allowClear: true,
|
allowClear: true,
|
||||||
maxLength: 64,
|
maxLength: 64,
|
||||||
|
class: '',
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const emit = defineEmits(['update:modelValue', 'update:inputValue', 'change']);
|
const emit = defineEmits(['update:modelValue', 'update:inputValue', 'change', 'clear']);
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
export default {};
|
||||||
|
|
||||||
|
export const dropPositionMap: Record<string, any> = {
|
||||||
|
'-1': 'BEFORE',
|
||||||
|
'0': 'APPEND',
|
||||||
|
'1': 'AFTER',
|
||||||
|
};
|
|
@ -38,7 +38,7 @@ export interface ResponseTiming {
|
||||||
}
|
}
|
||||||
// key-value参数信息
|
// key-value参数信息
|
||||||
export interface KeyValueParam {
|
export interface KeyValueParam {
|
||||||
id: string; // id用于前端渲染,后台无此字段
|
id?: string; // id用于前端渲染,后台无此字段
|
||||||
key: string;
|
key: string;
|
||||||
value: string;
|
value: string;
|
||||||
[key: string]: any; // 用于前端渲染时填充的自定义信息,后台无此字段
|
[key: string]: any; // 用于前端渲染时填充的自定义信息,后台无此字段
|
||||||
|
@ -63,6 +63,8 @@ export type ExecuteRequestFormBodyFormValue = ExecuteRequestCommonParam & {
|
||||||
files?: {
|
files?: {
|
||||||
fileId: string;
|
fileId: string;
|
||||||
fileName: string;
|
fileName: string;
|
||||||
|
local: boolean; // 是否是本地上传的文件
|
||||||
|
[key: string]: any; // 用于前端渲染时填充的自定义信息,后台无此字段
|
||||||
}[];
|
}[];
|
||||||
contentType?: RequestContentTypeEnum & string;
|
contentType?: RequestContentTypeEnum & string;
|
||||||
};
|
};
|
||||||
|
@ -75,6 +77,8 @@ export interface ExecuteBinaryBody {
|
||||||
file?: {
|
file?: {
|
||||||
fileId: string;
|
fileId: string;
|
||||||
fileName: string;
|
fileName: string;
|
||||||
|
local: boolean; // 是否是本地上传的文件
|
||||||
|
[key: string]: any; // 用于前端渲染时填充的自定义信息,后台无此字段
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// 接口请求json-body参数集合信息
|
// 接口请求json-body参数集合信息
|
||||||
|
@ -296,7 +300,8 @@ export interface ExecuteRequestParams {
|
||||||
id?: string;
|
id?: string;
|
||||||
reportId: string;
|
reportId: string;
|
||||||
environmentId: string;
|
environmentId: string;
|
||||||
tempFileIds: string[];
|
uploadFileIds: string[];
|
||||||
|
linkFileIds: string[];
|
||||||
request: ExecuteHTTPRequestFullParams | ExecutePluginRequestParams;
|
request: ExecuteHTTPRequestFullParams | ExecutePluginRequestParams;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,3 +65,12 @@ export interface ModuleTreeNode {
|
||||||
parentId: string;
|
parentId: string;
|
||||||
path: string;
|
path: string;
|
||||||
}
|
}
|
||||||
|
// 拖拽排序
|
||||||
|
export type MoveMode = 'BEFORE' | 'AFTER' | 'APPEND';
|
||||||
|
export interface DragSortParams {
|
||||||
|
projectId: string;
|
||||||
|
targetId: string;
|
||||||
|
moveMode: MoveMode; // 拖拽类型
|
||||||
|
moveId: string;
|
||||||
|
moduleId?: string;
|
||||||
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
<MsIcon type="icon-icon_edit_outlined" class="edit-script-name-icon" @click="showEditScriptNameInput" />
|
<MsIcon type="icon-icon_edit_outlined" class="edit-script-name-icon" @click="showEditScriptNameInput" />
|
||||||
</div>
|
</div>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<a-popover class="h-auto" position="top">
|
<a-popover class="h-auto" position="right">
|
||||||
<div class="text-[rgb(var(--primary-5))]">{{ t('apiTestDebug.scriptEx') }}</div>
|
<div class="text-[rgb(var(--primary-5))]">{{ t('apiTestDebug.scriptEx') }}</div>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div class="mb-[8px] flex items-center justify-between">
|
<div class="mb-[8px] flex items-center justify-between">
|
||||||
|
@ -64,7 +64,7 @@
|
||||||
</a-popover>
|
</a-popover>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-[8px]">
|
<div class="flex items-center gap-[8px]">
|
||||||
<a-button type="outline" class="arco-btn-outline--secondary p-[0_8px]" size="mini">
|
<a-button type="outline" class="arco-btn-outline--secondary p-[0_8px]" size="mini" @click="undoScript">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<MsIcon type="icon-icon_undo_outlined" class="text-var(--color-text-4)" size="12" />
|
<MsIcon type="icon-icon_undo_outlined" class="text-var(--color-text-4)" size="12" />
|
||||||
</template>
|
</template>
|
||||||
|
@ -87,6 +87,7 @@
|
||||||
<div class="h-[calc(100%-24px)] min-h-[300px]">
|
<div class="h-[calc(100%-24px)] min-h-[300px]">
|
||||||
<MsScriptDefined
|
<MsScriptDefined
|
||||||
v-if="condition.script !== undefined && condition.scriptLanguage !== undefined"
|
v-if="condition.script !== undefined && condition.scriptLanguage !== undefined"
|
||||||
|
ref="scriptDefinedRef"
|
||||||
v-model:code="condition.script"
|
v-model:code="condition.script"
|
||||||
v-model:language="condition.scriptLanguage"
|
v-model:language="condition.scriptLanguage"
|
||||||
show-type="commonScript"
|
show-type="commonScript"
|
||||||
|
@ -402,8 +403,14 @@ org.apache.http.client.method . . . '' at line number 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const scriptDefinedRef = ref<InstanceType<typeof MsScriptDefined>>();
|
||||||
|
|
||||||
|
function undoScript() {
|
||||||
|
scriptDefinedRef.value?.undoHandler();
|
||||||
|
}
|
||||||
|
|
||||||
function clearScript() {
|
function clearScript() {
|
||||||
condition.value.enable = false;
|
condition.value.script = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -124,6 +124,18 @@
|
||||||
@input="(val) => addTableLine(val, 'value')"
|
@input="(val) => addTableLine(val, 'value')"
|
||||||
/>
|
/>
|
||||||
</a-popover>
|
</a-popover>
|
||||||
|
<MsAddAttachment
|
||||||
|
v-else-if="record.paramType === RequestParamsType.FILE"
|
||||||
|
v-model:file-list="record.files"
|
||||||
|
mode="input"
|
||||||
|
:multiple="true"
|
||||||
|
:fields="{
|
||||||
|
id: 'fileId',
|
||||||
|
name: 'fileName',
|
||||||
|
}"
|
||||||
|
input-class="param-input"
|
||||||
|
@change="(files) => handleFileChange(files, record)"
|
||||||
|
/>
|
||||||
<MsParamsInput
|
<MsParamsInput
|
||||||
v-else
|
v-else
|
||||||
v-model:value="record.value"
|
v-model:value="record.value"
|
||||||
|
@ -141,7 +153,7 @@
|
||||||
class="param-input param-input-number"
|
class="param-input param-input-number"
|
||||||
@change="(val) => addTableLine(val, 'minLength')"
|
@change="(val) => addTableLine(val, 'minLength')"
|
||||||
/>
|
/>
|
||||||
<div class="mx-[4px]">~</div>
|
<div class="mx-[4px]">{{ t('common.to') }}</div>
|
||||||
<a-input-number
|
<a-input-number
|
||||||
v-model:model-value="record.maxLength"
|
v-model:model-value="record.maxLength"
|
||||||
:placeholder="t('apiTestDebug.paramMax')"
|
:placeholder="t('apiTestDebug.paramMax')"
|
||||||
|
@ -317,7 +329,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 MsParamsInput from '@/components/business/ms-params-input/index.vue';
|
import { MsFileItem } from '@/components/pure/ms-upload/types';
|
||||||
import paramDescInput from './paramDescInput.vue';
|
import paramDescInput from './paramDescInput.vue';
|
||||||
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
@ -325,6 +337,9 @@
|
||||||
|
|
||||||
import { RequestBodyFormat, RequestContentTypeEnum, RequestParamsType } from '@/enums/apiEnum';
|
import { RequestBodyFormat, RequestContentTypeEnum, RequestParamsType } from '@/enums/apiEnum';
|
||||||
import { SelectAllEnum, TableKeyEnum } from '@/enums/tableEnum';
|
import { SelectAllEnum, TableKeyEnum } from '@/enums/tableEnum';
|
||||||
|
// 异步加载组件
|
||||||
|
const MsAddAttachment = defineAsyncComponent(() => import('@/components/business/ms-add-attachment/index.vue'));
|
||||||
|
const MsParamsInput = defineAsyncComponent(() => import('@/components/business/ms-params-input/index.vue'));
|
||||||
|
|
||||||
export type ParamTableColumn = MsTableColumnData & {
|
export type ParamTableColumn = MsTableColumnData & {
|
||||||
isNormal?: boolean; // 用于 value 列区分是普通输入框还是 MsParamsInput
|
isNormal?: boolean; // 用于 value 列区分是普通输入框还是 MsParamsInput
|
||||||
|
@ -356,6 +371,7 @@
|
||||||
showSelectorAll?: boolean; // 是否显示全选
|
showSelectorAll?: boolean; // 是否显示全选
|
||||||
isSimpleSetting?: boolean; // 是否简单Column设置
|
isSimpleSetting?: boolean; // 是否简单Column设置
|
||||||
response?: string; // 响应内容
|
response?: string; // 响应内容
|
||||||
|
uploadTempFileApi?: (...args) => Promise<any>; // 上传临时文件接口
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
params: () => [],
|
params: () => [],
|
||||||
|
@ -513,6 +529,34 @@
|
||||||
emit('change', propsRes.value.data);
|
emit('change', propsRes.value.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleFileChange(files: MsFileItem[], record: Record<string, any>) {
|
||||||
|
try {
|
||||||
|
if (props.uploadTempFileApi && files.length === 1) {
|
||||||
|
// 本地上传单次只能选一个文件
|
||||||
|
const fileItem = files[0];
|
||||||
|
const res = await props.uploadTempFileApi(fileItem.file);
|
||||||
|
record.files = [
|
||||||
|
{
|
||||||
|
...fileItem,
|
||||||
|
fileId: res.data,
|
||||||
|
fileName: fileItem.name || '',
|
||||||
|
local: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
record.files = files.map((e) => ({
|
||||||
|
...e,
|
||||||
|
fileId: e.uid || e.fileId || '',
|
||||||
|
fileName: e.name || e.fileName || '',
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
emit('change', propsRes.value.data);
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const showQuickInputParam = ref(false);
|
const showQuickInputParam = ref(false);
|
||||||
const activeQuickInputRecord = ref<any>({});
|
const activeQuickInputRecord = ref<any>({});
|
||||||
const quickInputParamValue = ref('');
|
const quickInputParamValue = ref('');
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
:show-setting="true"
|
:show-setting="true"
|
||||||
:table-key="TableKeyEnum.API_TEST_DEBUG_FORM_DATA"
|
:table-key="TableKeyEnum.API_TEST_DEBUG_FORM_DATA"
|
||||||
:default-param-item="defaultParamItem"
|
:default-param-item="defaultParamItem"
|
||||||
|
:upload-temp-file-api="props.uploadTempFileApi"
|
||||||
@change="handleParamTableChange"
|
@change="handleParamTableChange"
|
||||||
/>
|
/>
|
||||||
<paramTable
|
<paramTable
|
||||||
|
@ -47,15 +48,21 @@
|
||||||
/>
|
/>
|
||||||
<div v-else-if="innerParams.bodyType === RequestBodyFormat.BINARY">
|
<div v-else-if="innerParams.bodyType === RequestBodyFormat.BINARY">
|
||||||
<div class="mb-[16px] flex justify-between gap-[8px] bg-[var(--color-text-n9)] p-[12px]">
|
<div class="mb-[16px] flex justify-between gap-[8px] bg-[var(--color-text-n9)] p-[12px]">
|
||||||
<!--TODO:文件上传&关联组件-->
|
|
||||||
<a-input
|
<a-input
|
||||||
v-model:model-value="innerParams.binaryBody.description"
|
v-model:model-value="innerParams.binaryBody.description"
|
||||||
:placeholder="t('common.desc')"
|
:placeholder="t('common.desc')"
|
||||||
:max-length="255"
|
:max-length="255"
|
||||||
/>
|
/>
|
||||||
|
<MsAddAttachment
|
||||||
|
v-model:file-list="fileList"
|
||||||
|
mode="input"
|
||||||
|
:multiple="false"
|
||||||
|
:default-file-list="[innerParams.binaryBody.file]"
|
||||||
|
@change="handleFileChange"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center">
|
<!-- <div class="flex items-center">
|
||||||
<!-- <a-switch v-model:model-value="innerParams.binarySend" class="mr-[8px]" size="small" type="line"></a-switch> -->
|
<a-switch v-model:model-value="innerParams.binarySend" class="mr-[8px]" size="small" type="line"></a-switch>
|
||||||
<span>{{ t('apiTestDebug.sendAsMainText') }}</span>
|
<span>{{ t('apiTestDebug.sendAsMainText') }}</span>
|
||||||
<a-tooltip position="right">
|
<a-tooltip position="right">
|
||||||
<template #content>
|
<template #content>
|
||||||
|
@ -67,7 +74,7 @@
|
||||||
size="16"
|
size="16"
|
||||||
/>
|
/>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</div>
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="flex h-[calc(100%-100px)]">
|
<div v-else class="flex h-[calc(100%-100px)]">
|
||||||
<MsCodeEditor
|
<MsCodeEditor
|
||||||
|
@ -97,13 +104,15 @@
|
||||||
|
|
||||||
import MsCodeEditor from '@/components/pure/ms-code-editor/index.vue';
|
import MsCodeEditor from '@/components/pure/ms-code-editor/index.vue';
|
||||||
import { LanguageEnum } from '@/components/pure/ms-code-editor/types';
|
import { LanguageEnum } from '@/components/pure/ms-code-editor/types';
|
||||||
|
import { MsFileItem } from '@/components/pure/ms-upload/types';
|
||||||
|
import MsAddAttachment from '@/components/business/ms-add-attachment/index.vue';
|
||||||
import batchAddKeyVal from '@/views/api-test/components/batchAddKeyVal.vue';
|
import batchAddKeyVal from '@/views/api-test/components/batchAddKeyVal.vue';
|
||||||
import paramTable, { type ParamTableColumn } from '@/views/api-test/components/paramTable.vue';
|
import paramTable, { type ParamTableColumn } from '@/views/api-test/components/paramTable.vue';
|
||||||
|
|
||||||
import { requestBodyTypeMap } from '@/config/apiTest';
|
import { requestBodyTypeMap } from '@/config/apiTest';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
|
||||||
import { ExecuteBody } from '@/models/apiTest/debug';
|
import { ExecuteBody, ExecuteRequestFormBodyFormValue } from '@/models/apiTest/debug';
|
||||||
import { RequestBodyFormat, RequestContentTypeEnum, RequestParamsType } from '@/enums/apiEnum';
|
import { RequestBodyFormat, RequestContentTypeEnum, RequestParamsType } from '@/enums/apiEnum';
|
||||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||||
|
|
||||||
|
@ -111,6 +120,7 @@
|
||||||
params: ExecuteBody;
|
params: ExecuteBody;
|
||||||
layout: 'horizontal' | 'vertical';
|
layout: 'horizontal' | 'vertical';
|
||||||
secondBoxHeight: number;
|
secondBoxHeight: number;
|
||||||
|
uploadTempFileApi?: (...args) => Promise<any>; // 上传临时文件接口
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'update:params', value: any[]): void;
|
(e: 'update:params', value: any[]): void;
|
||||||
|
@ -120,7 +130,7 @@
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const innerParams = useVModel(props, 'params', emit);
|
const innerParams = useVModel(props, 'params', emit);
|
||||||
const defaultParamItem = {
|
const defaultParamItem: ExecuteRequestFormBodyFormValue = {
|
||||||
key: '',
|
key: '',
|
||||||
value: '',
|
value: '',
|
||||||
paramType: RequestParamsType.STRING,
|
paramType: RequestParamsType.STRING,
|
||||||
|
@ -131,58 +141,102 @@
|
||||||
encode: false,
|
encode: false,
|
||||||
enable: true,
|
enable: true,
|
||||||
contentType: RequestContentTypeEnum.TEXT,
|
contentType: RequestContentTypeEnum.TEXT,
|
||||||
|
files: [],
|
||||||
};
|
};
|
||||||
|
const fileList = ref<any[]>(
|
||||||
|
innerParams.value.binaryBody && innerParams.value.binaryBody.file ? [innerParams.value.binaryBody.file] : []
|
||||||
|
);
|
||||||
|
|
||||||
const columns = computed<ParamTableColumn[]>(() => [
|
async function handleFileChange(files: MsFileItem[]) {
|
||||||
{
|
if (files.length === 0) {
|
||||||
title: 'apiTestDebug.paramName',
|
innerParams.value.binaryBody.file = undefined;
|
||||||
dataIndex: 'key',
|
return;
|
||||||
slotName: 'key',
|
}
|
||||||
},
|
if (!props.uploadTempFileApi) return;
|
||||||
{
|
try {
|
||||||
title: 'apiTestDebug.paramType',
|
if (fileList.value[0]?.local) {
|
||||||
dataIndex: 'paramType',
|
const res = await props.uploadTempFileApi(fileList.value[0].file);
|
||||||
slotName: 'paramType',
|
innerParams.value.binaryBody.file = {
|
||||||
hasRequired: true,
|
...fileList.value[0],
|
||||||
typeOptions: Object.values(RequestParamsType).map((val) => ({
|
fileId: res.data,
|
||||||
label: val,
|
fileName: fileList.value[0]?.name || '',
|
||||||
value: val,
|
local: true,
|
||||||
})),
|
};
|
||||||
width: 120,
|
} else {
|
||||||
},
|
innerParams.value.binaryBody.file = {
|
||||||
{
|
...fileList.value[0],
|
||||||
title: 'apiTestDebug.paramValue',
|
fileId: fileList.value[0].uid,
|
||||||
dataIndex: 'value',
|
fileName: fileList.value[0]?.name || '',
|
||||||
slotName: 'value',
|
local: false,
|
||||||
width: 240,
|
};
|
||||||
},
|
}
|
||||||
{
|
emit('change');
|
||||||
title: 'apiTestDebug.paramLengthRange',
|
} catch (error) {
|
||||||
dataIndex: 'lengthRange',
|
// eslint-disable-next-line no-console
|
||||||
slotName: 'lengthRange',
|
console.log(error);
|
||||||
align: 'center',
|
}
|
||||||
width: 200,
|
}
|
||||||
},
|
|
||||||
{
|
const typeOptions = computed(() => {
|
||||||
title: 'apiTestDebug.encode',
|
const fullOptions = Object.values(RequestParamsType).map((val) => ({
|
||||||
dataIndex: 'encode',
|
label: val,
|
||||||
slotName: 'encode',
|
value: val,
|
||||||
titleSlotName: 'encodeTitle',
|
}));
|
||||||
width: 80,
|
if (innerParams.value.bodyType === RequestBodyFormat.FORM_DATA) {
|
||||||
},
|
return fullOptions;
|
||||||
{
|
}
|
||||||
title: 'apiTestDebug.desc',
|
return fullOptions.filter((item) => item.value !== RequestParamsType.FILE && item.value !== RequestParamsType.JSON);
|
||||||
dataIndex: 'description',
|
});
|
||||||
slotName: 'description',
|
const columns = computed<ParamTableColumn[]>(() => {
|
||||||
},
|
return [
|
||||||
{
|
{
|
||||||
title: '',
|
title: 'apiTestDebug.paramName',
|
||||||
slotName: 'operation',
|
dataIndex: 'key',
|
||||||
fixed: 'right',
|
slotName: 'key',
|
||||||
format: innerParams.value.bodyType,
|
},
|
||||||
width: innerParams.value.bodyType === RequestBodyFormat.FORM_DATA ? 90 : 50,
|
{
|
||||||
},
|
title: 'apiTestDebug.paramType',
|
||||||
]);
|
dataIndex: 'paramType',
|
||||||
|
slotName: 'paramType',
|
||||||
|
hasRequired: true,
|
||||||
|
typeOptions: typeOptions.value,
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'apiTestDebug.paramValue',
|
||||||
|
dataIndex: 'value',
|
||||||
|
slotName: 'value',
|
||||||
|
multiple: true,
|
||||||
|
width: 240,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'apiTestDebug.paramLengthRange',
|
||||||
|
dataIndex: 'lengthRange',
|
||||||
|
slotName: 'lengthRange',
|
||||||
|
align: 'center',
|
||||||
|
width: 200,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'apiTestDebug.encode',
|
||||||
|
dataIndex: 'encode',
|
||||||
|
slotName: 'encode',
|
||||||
|
titleSlotName: 'encodeTitle',
|
||||||
|
width: 80,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'apiTestDebug.desc',
|
||||||
|
dataIndex: 'description',
|
||||||
|
slotName: 'description',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '',
|
||||||
|
slotName: 'operation',
|
||||||
|
fixed: 'right',
|
||||||
|
format: innerParams.value.bodyType,
|
||||||
|
width: innerParams.value.bodyType === RequestBodyFormat.FORM_DATA ? 90 : 50,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
const heightUsed = ref<number | undefined>(undefined);
|
const heightUsed = ref<number | undefined>(undefined);
|
||||||
|
|
||||||
|
|
|
@ -4,13 +4,18 @@
|
||||||
<div class="mb-[8px] flex items-center justify-between">
|
<div class="mb-[8px] flex items-center justify-between">
|
||||||
<div class="flex flex-1">
|
<div class="flex flex-1">
|
||||||
<a-select
|
<a-select
|
||||||
|
v-if="requestVModel.isNew"
|
||||||
v-model:model-value="requestVModel.protocol"
|
v-model:model-value="requestVModel.protocol"
|
||||||
:options="protocolOptions"
|
:options="protocolOptions"
|
||||||
:loading="protocolLoading"
|
:loading="protocolLoading"
|
||||||
:disabled="!requestVModel.isNew"
|
|
||||||
class="mr-[4px] w-[90px]"
|
class="mr-[4px] w-[90px]"
|
||||||
@change="(val) => handleActiveDebugProtocolChange(val as string)"
|
@change="(val) => handleActiveDebugProtocolChange(val as string)"
|
||||||
/>
|
/>
|
||||||
|
<apiMethodName
|
||||||
|
v-else
|
||||||
|
:method="(requestVModel.protocol as RequestMethods)"
|
||||||
|
class="mr-[16px] flex h-[30px] items-center"
|
||||||
|
/>
|
||||||
<a-input-group v-if="isHttpProtocol" class="flex-1">
|
<a-input-group v-if="isHttpProtocol" class="flex-1">
|
||||||
<apiMethodSelect
|
<apiMethodSelect
|
||||||
v-model:model-value="requestVModel.method"
|
v-model:model-value="requestVModel.method"
|
||||||
|
@ -50,7 +55,7 @@
|
||||||
<a-doption value="saveAsCase">{{ t('apiTestManagement.saveAsCase') }}</a-doption>
|
<a-doption value="saveAsCase">{{ t('apiTestManagement.saveAsCase') }}</a-doption>
|
||||||
</template>
|
</template>
|
||||||
</a-dropdown>
|
</a-dropdown>
|
||||||
<a-button v-else type="secondary" @click="handleSaveShortcut">
|
<a-button v-else type="secondary" :loading="saveLoading" @click="handleSaveShortcut">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
{{ t('common.save') }}
|
{{ t('common.save') }}
|
||||||
<div class="text-[var(--color-text-4)]">(<icon-command size="14" />+S)</div>
|
<div class="text-[var(--color-text-4)]">(<icon-command size="14" />+S)</div>
|
||||||
|
@ -115,6 +120,7 @@
|
||||||
v-model:params="requestVModel.body"
|
v-model:params="requestVModel.body"
|
||||||
:layout="activeLayout"
|
:layout="activeLayout"
|
||||||
:second-box-height="secondBoxHeight"
|
:second-box-height="secondBoxHeight"
|
||||||
|
:upload-temp-file-api="props.uploadTempFileApi"
|
||||||
@change="handleActiveDebugChange"
|
@change="handleActiveDebugChange"
|
||||||
/>
|
/>
|
||||||
<debugQuery
|
<debugQuery
|
||||||
|
@ -223,6 +229,7 @@
|
||||||
import precondition from './precondition.vue';
|
import precondition from './precondition.vue';
|
||||||
import response from './response.vue';
|
import response from './response.vue';
|
||||||
import debugSetting from './setting.vue';
|
import debugSetting from './setting.vue';
|
||||||
|
import apiMethodName from '@/views/api-test/components/apiMethodName.vue';
|
||||||
import apiMethodSelect from '@/views/api-test/components/apiMethodSelect.vue';
|
import apiMethodSelect from '@/views/api-test/components/apiMethodSelect.vue';
|
||||||
|
|
||||||
import { getPluginScript, getProtocolList } from '@/api/modules/api-test/management';
|
import { getPluginScript, getProtocolList } from '@/api/modules/api-test/management';
|
||||||
|
@ -263,6 +270,7 @@
|
||||||
executeApi: (...args) => Promise<any>; // 执行接口
|
executeApi: (...args) => Promise<any>; // 执行接口
|
||||||
createApi: (...args) => Promise<any>; // 创建接口
|
createApi: (...args) => Promise<any>; // 创建接口
|
||||||
updateApi: (...args) => Promise<any>; // 更新接口
|
updateApi: (...args) => Promise<any>; // 更新接口
|
||||||
|
uploadTempFileApi?: (...args) => Promise<any>; // 上传临时文件接口
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits(['addDone']);
|
const emit = defineEmits(['addDone']);
|
||||||
|
|
||||||
|
@ -573,107 +581,6 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeRequestParams() {
|
|
||||||
const polymorphicName = protocolOptions.value.find(
|
|
||||||
(e) => e.value === requestVModel.value.protocol
|
|
||||||
)?.polymorphicName; // 协议多态名称
|
|
||||||
let requestParams;
|
|
||||||
if (isHttpProtocol.value) {
|
|
||||||
requestParams = {
|
|
||||||
authConfig: requestVModel.value.authConfig,
|
|
||||||
body: {
|
|
||||||
...requestVModel.value.body,
|
|
||||||
binaryBody: undefined,
|
|
||||||
formDataBody: {
|
|
||||||
formValues: requestVModel.value.body.formDataBody.formValues.filter(
|
|
||||||
(e, i) => i !== requestVModel.value.body.formDataBody.formValues.length - 1
|
|
||||||
), // 去掉最后一行空行
|
|
||||||
},
|
|
||||||
wwwFormBody: {
|
|
||||||
formValues: requestVModel.value.body.wwwFormBody.formValues.filter(
|
|
||||||
(e, i) => i !== requestVModel.value.body.wwwFormBody.formValues.length - 1
|
|
||||||
), // 去掉最后一行空行
|
|
||||||
},
|
|
||||||
}, // TODO:binaryBody还没对接
|
|
||||||
headers: requestVModel.value.headers.filter((e, i) => i !== requestVModel.value.headers.length - 1), // 去掉最后一行空行
|
|
||||||
method: requestVModel.value.method,
|
|
||||||
otherConfig: requestVModel.value.otherConfig,
|
|
||||||
path: requestVModel.value.url,
|
|
||||||
query: requestVModel.value.query.filter((e, i) => i !== requestVModel.value.query.length - 1), // 去掉最后一行空行
|
|
||||||
rest: requestVModel.value.rest.filter((e, i) => i !== requestVModel.value.rest.length - 1), // 去掉最后一行空行
|
|
||||||
url: requestVModel.value.url,
|
|
||||||
polymorphicName,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
requestParams = {
|
|
||||||
...fApi.value?.formData(),
|
|
||||||
polymorphicName,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
reportId.value = getGenerateId();
|
|
||||||
requestVModel.value.reportId = reportId.value; // 存储报告ID
|
|
||||||
debugSocket(); // 开启websocket
|
|
||||||
return {
|
|
||||||
id: requestVModel.value.id.toString(),
|
|
||||||
reportId: reportId.value,
|
|
||||||
environmentId: '',
|
|
||||||
tempFileIds: [],
|
|
||||||
request: {
|
|
||||||
...requestParams,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
polymorphicName: 'MsCommonElement', // 协议多态名称,写死MsCommonElement
|
|
||||||
assertionConfig: {
|
|
||||||
// TODO:暂时不做断言
|
|
||||||
enableGlobal: false,
|
|
||||||
assertions: [],
|
|
||||||
},
|
|
||||||
postProcessorConfig: requestVModel.value.children[0].postProcessorConfig,
|
|
||||||
preProcessorConfig: requestVModel.value.children[0].preProcessorConfig,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
projectId: appStore.currentProjectId,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行调试
|
|
||||||
* @param val 执行类型
|
|
||||||
*/
|
|
||||||
async function execute(execuetType?: 'localExec' | 'serverExec') {
|
|
||||||
// TODO:本地&服务端执行判断
|
|
||||||
if (isHttpProtocol.value) {
|
|
||||||
try {
|
|
||||||
requestVModel.value.executeLoading = true;
|
|
||||||
await props.executeApi(makeRequestParams());
|
|
||||||
} catch (error) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log(error);
|
|
||||||
requestVModel.value.executeLoading = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 插件需要校验动态表单
|
|
||||||
fApi.value?.validate(async (valid) => {
|
|
||||||
if (valid === true) {
|
|
||||||
try {
|
|
||||||
requestVModel.value.executeLoading = true;
|
|
||||||
await props.executeApi(makeRequestParams());
|
|
||||||
} catch (error) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log(error);
|
|
||||||
requestVModel.value.executeLoading = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
requestVModel.value.activeTab = RequestComposition.PLUGIN;
|
|
||||||
nextTick(() => {
|
|
||||||
scrollIntoView(document.querySelector('.arco-form-item-message'), { block: 'center' });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const saveModalVisible = ref(false);
|
const saveModalVisible = ref(false);
|
||||||
const saveModalForm = ref({
|
const saveModalForm = ref({
|
||||||
name: '',
|
name: '',
|
||||||
|
@ -698,7 +605,200 @@
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
function makeRequestParams() {
|
||||||
|
const { formDataBody, wwwFormBody, binaryBody } = requestVModel.value.body;
|
||||||
|
const polymorphicName = protocolOptions.value.find(
|
||||||
|
(e) => e.value === requestVModel.value.protocol
|
||||||
|
)?.polymorphicName; // 协议多态名称
|
||||||
|
const realFormDataBodyValues = formDataBody.formValues.filter((e, i) => i !== formDataBody.formValues.length - 1); // 去掉最后一行空行
|
||||||
|
const realWwwFormBodyValues = wwwFormBody.formValues.filter((e, i) => i !== wwwFormBody.formValues.length - 1); // 去掉最后一行空行
|
||||||
|
const uploadFileIds: string[] = [];
|
||||||
|
const linkFileIds: string[] = [];
|
||||||
|
// 获取上传文件和关联文件
|
||||||
|
for (let i = 0; i < formDataBody.formValues.length; i++) {
|
||||||
|
const item = formDataBody.formValues[i];
|
||||||
|
if (item.paramType === RequestParamsType.FILE) {
|
||||||
|
if (item.files) {
|
||||||
|
for (let j = 0; j < item.files.length; j++) {
|
||||||
|
const file = item.files[j];
|
||||||
|
if (file.isLocal) {
|
||||||
|
uploadFileIds.push(file.fileId);
|
||||||
|
} else {
|
||||||
|
linkFileIds.push(file.fileId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (binaryBody) {
|
||||||
|
if (binaryBody.file?.isLocal) {
|
||||||
|
uploadFileIds.push(binaryBody.file.fileId);
|
||||||
|
} else if (binaryBody.file?.fileId) {
|
||||||
|
linkFileIds.push(binaryBody.file.fileId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let requestParams;
|
||||||
|
if (isHttpProtocol.value) {
|
||||||
|
requestParams = {
|
||||||
|
authConfig: requestVModel.value.authConfig,
|
||||||
|
body: {
|
||||||
|
...requestVModel.value.body,
|
||||||
|
formDataBody: {
|
||||||
|
formValues: realFormDataBodyValues,
|
||||||
|
},
|
||||||
|
wwwFormBody: {
|
||||||
|
formValues: realWwwFormBodyValues,
|
||||||
|
},
|
||||||
|
}, // TODO:binaryBody还没对接
|
||||||
|
headers: requestVModel.value.headers.filter((e, i) => i !== requestVModel.value.headers.length - 1), // 去掉最后一行空行
|
||||||
|
method: requestVModel.value.method,
|
||||||
|
otherConfig: requestVModel.value.otherConfig,
|
||||||
|
path: requestVModel.value.url,
|
||||||
|
query: requestVModel.value.query.filter((e, i) => i !== requestVModel.value.query.length - 1), // 去掉最后一行空行
|
||||||
|
rest: requestVModel.value.rest.filter((e, i) => i !== requestVModel.value.rest.length - 1), // 去掉最后一行空行
|
||||||
|
url: requestVModel.value.url,
|
||||||
|
polymorphicName,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
requestParams = {
|
||||||
|
...fApi.value?.formData(),
|
||||||
|
polymorphicName,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
reportId.value = getGenerateId();
|
||||||
|
requestVModel.value.reportId = reportId.value; // 存储报告ID
|
||||||
|
debugSocket(); // 开启websocket
|
||||||
|
return {
|
||||||
|
id: requestVModel.value.id.toString(),
|
||||||
|
reportId: reportId.value,
|
||||||
|
environmentId: '',
|
||||||
|
name: saveModalForm.value.name || requestVModel.value.name,
|
||||||
|
request: {
|
||||||
|
...requestParams,
|
||||||
|
name: saveModalForm.value.name || requestVModel.value.name,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
polymorphicName: 'MsCommonElement', // 协议多态名称,写死MsCommonElement
|
||||||
|
assertionConfig: {
|
||||||
|
// TODO:暂时不做断言
|
||||||
|
enableGlobal: false,
|
||||||
|
assertions: [],
|
||||||
|
},
|
||||||
|
postProcessorConfig: requestVModel.value.children[0].postProcessorConfig,
|
||||||
|
preProcessorConfig: requestVModel.value.children[0].preProcessorConfig,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
uploadFileIds,
|
||||||
|
linkFileIds,
|
||||||
|
projectId: appStore.currentProjectId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行调试
|
||||||
|
* @param val 执行类型
|
||||||
|
*/
|
||||||
|
async function execute(execuetType?: 'localExec' | 'serverExec') {
|
||||||
|
// TODO:本地&服务端执行判断
|
||||||
|
if (isHttpProtocol.value) {
|
||||||
|
try {
|
||||||
|
requestVModel.value.executeLoading = true;
|
||||||
|
await props.executeApi(makeRequestParams());
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
requestVModel.value.executeLoading = false;
|
||||||
|
} finally {
|
||||||
|
websocket.value?.close();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 插件需要校验动态表单
|
||||||
|
fApi.value?.validate(async (valid) => {
|
||||||
|
if (valid === true) {
|
||||||
|
try {
|
||||||
|
requestVModel.value.executeLoading = true;
|
||||||
|
await props.executeApi(makeRequestParams());
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
requestVModel.value.executeLoading = false;
|
||||||
|
} finally {
|
||||||
|
websocket.value?.close();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
requestVModel.value.activeTab = RequestComposition.PLUGIN;
|
||||||
|
nextTick(() => {
|
||||||
|
scrollIntoView(document.querySelector('.arco-form-item-message'), { block: 'center' });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateDebug() {
|
||||||
|
try {
|
||||||
|
saveLoading.value = true;
|
||||||
|
await props.updateApi({
|
||||||
|
...makeRequestParams(),
|
||||||
|
...saveModalForm.value,
|
||||||
|
protocol: requestVModel.value.protocol,
|
||||||
|
method: isHttpProtocol.value ? requestVModel.value.method : requestVModel.value.protocol,
|
||||||
|
deleteFileIds: [], // TODO:删除文件集合
|
||||||
|
unLinkRefIds: [], // TODO:取消关联文件集合
|
||||||
|
});
|
||||||
|
Message.success(t('common.updateSuccess'));
|
||||||
|
requestVModel.value.unSaved = false;
|
||||||
|
requestVModel.value.name = saveModalForm.value.name;
|
||||||
|
requestVModel.value.label = saveModalForm.value.name;
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
} finally {
|
||||||
|
saveLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleSave(done: (closed: boolean) => void) {
|
||||||
|
saveModalFormRef.value?.validate(async (errors) => {
|
||||||
|
if (!errors) {
|
||||||
|
try {
|
||||||
|
saveLoading.value = true;
|
||||||
|
if (requestVModel.value.isNew) {
|
||||||
|
// 若是新建的调试,走添加
|
||||||
|
const res = await props.createApi({
|
||||||
|
...makeRequestParams(),
|
||||||
|
...saveModalForm.value,
|
||||||
|
protocol: requestVModel.value.protocol,
|
||||||
|
method: isHttpProtocol.value ? requestVModel.value.method : requestVModel.value.protocol,
|
||||||
|
});
|
||||||
|
requestVModel.value.id = res.id;
|
||||||
|
requestVModel.value.isNew = false;
|
||||||
|
Message.success(t('common.saveSuccess'));
|
||||||
|
requestVModel.value.unSaved = false;
|
||||||
|
requestVModel.value.name = saveModalForm.value.name;
|
||||||
|
requestVModel.value.label = saveModalForm.value.name;
|
||||||
|
} else {
|
||||||
|
updateDebug();
|
||||||
|
}
|
||||||
|
saveLoading.value = false;
|
||||||
|
saveModalVisible.value = false;
|
||||||
|
done(true);
|
||||||
|
emit('addDone');
|
||||||
|
} catch (error) {
|
||||||
|
saveLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
done(false);
|
||||||
|
}
|
||||||
|
|
||||||
async function handleSaveShortcut() {
|
async function handleSaveShortcut() {
|
||||||
|
if (!requestVModel.value.isNew) {
|
||||||
|
// 更新接口不需要弹窗,直接更新保存
|
||||||
|
updateDebug();
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
if (!isHttpProtocol.value) {
|
if (!isHttpProtocol.value) {
|
||||||
// 插件需要校验动态表单
|
// 插件需要校验动态表单
|
||||||
|
@ -738,51 +838,6 @@
|
||||||
saveModalFormRef.value?.resetFields();
|
saveModalFormRef.value?.resetFields();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleSave(done: (closed: boolean) => void) {
|
|
||||||
saveModalFormRef.value?.validate(async (errors) => {
|
|
||||||
if (!errors) {
|
|
||||||
try {
|
|
||||||
saveLoading.value = true;
|
|
||||||
if (requestVModel.value.isNew) {
|
|
||||||
// 若是新建的调试,走添加
|
|
||||||
const res = await props.createApi({
|
|
||||||
...makeRequestParams(),
|
|
||||||
...saveModalForm.value,
|
|
||||||
protocol: requestVModel.value.protocol,
|
|
||||||
method: isHttpProtocol.value ? requestVModel.value.method : requestVModel.value.protocol,
|
|
||||||
uploadFileIds: [],
|
|
||||||
linkFileIds: [],
|
|
||||||
});
|
|
||||||
requestVModel.value.id = res.id;
|
|
||||||
requestVModel.value.isNew = false;
|
|
||||||
} else {
|
|
||||||
await props.updateApi({
|
|
||||||
...makeRequestParams(),
|
|
||||||
...saveModalForm.value,
|
|
||||||
protocol: requestVModel.value.protocol,
|
|
||||||
method: isHttpProtocol.value ? requestVModel.value.method : requestVModel.value.protocol,
|
|
||||||
uploadFileIds: [],
|
|
||||||
linkFileIds: [],
|
|
||||||
deleteFileIds: [], // TODO:删除文件集合
|
|
||||||
unLinkRefIds: [], // TODO:取消关联文件集合
|
|
||||||
});
|
|
||||||
}
|
|
||||||
saveLoading.value = false;
|
|
||||||
saveModalVisible.value = false;
|
|
||||||
done(true);
|
|
||||||
requestVModel.value.unSaved = false;
|
|
||||||
requestVModel.value.name = saveModalForm.value.name;
|
|
||||||
requestVModel.value.label = saveModalForm.value.name;
|
|
||||||
emit('addDone');
|
|
||||||
Message.success(requestVModel.value.isNew ? t('common.saveSuccess') : t('common.updateSuccess'));
|
|
||||||
} catch (error) {
|
|
||||||
saveLoading.value = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
done(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
initProtocolList();
|
initProtocolList();
|
||||||
initLocalConfig();
|
initLocalConfig();
|
||||||
|
|
|
@ -33,14 +33,14 @@
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</div>
|
</div>
|
||||||
<a-form-item :label="t('apiTestDebug.certificateAlias')">
|
<!-- <a-form-item :label="t('apiTestDebug.certificateAlias')">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:model-value="settingForm.certificateAlias"
|
v-model:model-value="settingForm.certificateAlias"
|
||||||
:max-length="255"
|
:max-length="255"
|
||||||
:placeholder="t('apiTestDebug.commonPlaceholder')"
|
:placeholder="t('apiTestDebug.commonPlaceholder')"
|
||||||
class="w-[450px]"
|
class="w-[450px]"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item> -->
|
||||||
<a-form-item :label="t('apiTestDebug.redirect')">
|
<a-form-item :label="t('apiTestDebug.redirect')">
|
||||||
<a-radio
|
<a-radio
|
||||||
v-model:model-value="settingForm.followRedirects"
|
v-model:model-value="settingForm.followRedirects"
|
||||||
|
|
|
@ -55,9 +55,11 @@
|
||||||
children: 'children',
|
children: 'children',
|
||||||
count: 'count',
|
count: 'count',
|
||||||
}"
|
}"
|
||||||
|
:draggable="true"
|
||||||
:selectable="false"
|
:selectable="false"
|
||||||
block-node
|
block-node
|
||||||
title-tooltip-position="left"
|
title-tooltip-position="left"
|
||||||
|
:allow-drop="allowDrop"
|
||||||
@more-action-select="handleFolderMoreSelect"
|
@more-action-select="handleFolderMoreSelect"
|
||||||
@more-actions-close="moreActionsClose"
|
@more-actions-close="moreActionsClose"
|
||||||
@drop="handleDrop"
|
@drop="handleDrop"
|
||||||
|
@ -124,12 +126,15 @@
|
||||||
import {
|
import {
|
||||||
deleteDebug,
|
deleteDebug,
|
||||||
deleteDebugModule,
|
deleteDebugModule,
|
||||||
|
dragDebug,
|
||||||
getDebugModuleCount,
|
getDebugModuleCount,
|
||||||
getDebugModules,
|
getDebugModules,
|
||||||
moveDebugModule,
|
moveDebugModule,
|
||||||
} from '@/api/modules/api-test/debug';
|
} from '@/api/modules/api-test/debug';
|
||||||
|
import { dropPositionMap } from '@/config/common';
|
||||||
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 { mapTree } from '@/utils';
|
import { mapTree } from '@/utils';
|
||||||
|
|
||||||
import { ModuleTreeNode } from '@/models/common';
|
import { ModuleTreeNode } from '@/models/common';
|
||||||
|
@ -139,6 +144,7 @@
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits(['init', 'clickApiNode', 'newApi', 'import', 'renameFinish']);
|
const emit = defineEmits(['init', 'clickApiNode', 'newApi', 'import', 'renameFinish']);
|
||||||
|
|
||||||
|
const appStore = useAppStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { openModal } = useModal();
|
const { openModal } = useModal();
|
||||||
|
|
||||||
|
@ -204,6 +210,7 @@
|
||||||
return {
|
return {
|
||||||
...e,
|
...e,
|
||||||
hideMoreAction: e.id === 'root',
|
hideMoreAction: e.id === 'root',
|
||||||
|
draggable: e.id !== 'root',
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
rootModulesName.value = folderTree.value.map((e) => e.name || '');
|
rootModulesName.value = folderTree.value.map((e) => e.name || '');
|
||||||
|
@ -324,6 +331,18 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function allowDrop(dropNode: MsTreeNodeData, dropPosition: number, dragNode?: MsTreeNodeData | null) {
|
||||||
|
if (dropNode.type === 'API' && dropPosition === 0) {
|
||||||
|
// API节点不可添加子节点
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (dropNode.type === 'MODULE' && dragNode?.type === 'API' && dropPosition !== 0) {
|
||||||
|
// API节点不移动到模块的前后位置
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理文件夹树节点拖拽事件
|
* 处理文件夹树节点拖拽事件
|
||||||
* @param tree 树数据
|
* @param tree 树数据
|
||||||
|
@ -339,11 +358,21 @@
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
await moveDebugModule({
|
if (dragNode.type === 'MODULE') {
|
||||||
dragNodeId: dragNode.id as string,
|
await moveDebugModule({
|
||||||
dropNodeId: dropNode.id || '',
|
dragNodeId: dragNode.id as string,
|
||||||
dropPosition,
|
dropNodeId: dropNode.id || '',
|
||||||
});
|
dropPosition,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await dragDebug({
|
||||||
|
projectId: appStore.currentProjectId,
|
||||||
|
moveMode: dropPositionMap[dropPosition],
|
||||||
|
moveId: dropNode.id,
|
||||||
|
targetId: dragNode.id,
|
||||||
|
moduleId: dropNode.type === 'API' ? dropNode.parentId : dropNode.id, // 释放节点是 API,则传入它所属模块id;模块的话直接是模块id
|
||||||
|
});
|
||||||
|
}
|
||||||
Message.success(t('apiTestDebug.moduleMoveSuccess'));
|
Message.success(t('apiTestDebug.moduleMoveSuccess'));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
:create-api="addDebug"
|
:create-api="addDebug"
|
||||||
:update-api="updateDebug"
|
:update-api="updateDebug"
|
||||||
:execute-api="executeDebug"
|
:execute-api="executeDebug"
|
||||||
|
:upload-temp-file-api="uploadTempFile"
|
||||||
@add-done="handleDebugAddDone"
|
@add-done="handleDebugAddDone"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -88,7 +89,7 @@
|
||||||
import apiMethodName from '@/views/api-test/components/apiMethodName.vue';
|
import apiMethodName from '@/views/api-test/components/apiMethodName.vue';
|
||||||
import debug, { RequestParam } from '@/views/api-test/components/requestComposition/index.vue';
|
import debug, { RequestParam } from '@/views/api-test/components/requestComposition/index.vue';
|
||||||
|
|
||||||
import { addDebug, executeDebug, getDebugDetail, updateDebug } from '@/api/modules/api-test/debug';
|
import { addDebug, executeDebug, getDebugDetail, updateDebug, uploadTempFile } from '@/api/modules/api-test/debug';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import { parseCurlScript } from '@/utils';
|
import { parseCurlScript } from '@/utils';
|
||||||
|
|
||||||
|
|
|
@ -100,7 +100,7 @@ export default {
|
||||||
'apiTestDebug.deleteDebugTipContent': 'Deletion cannot be restored, please proceed with caution!',
|
'apiTestDebug.deleteDebugTipContent': 'Deletion cannot be restored, please proceed with caution!',
|
||||||
'apiTestDebug.deleteConfirm': 'Confirm delete',
|
'apiTestDebug.deleteConfirm': 'Confirm delete',
|
||||||
'apiTestDebug.deleteSuccess': 'Successfully deleted',
|
'apiTestDebug.deleteSuccess': 'Successfully deleted',
|
||||||
'apiTestDebug.moduleMoveSuccess': 'Module moved successfully',
|
'apiTestDebug.moduleMoveSuccess': 'Moved successfully',
|
||||||
'apiTestDebug.sqlSourceName': 'Data source name',
|
'apiTestDebug.sqlSourceName': 'Data source name',
|
||||||
'apiTestDebug.driver': 'Drive',
|
'apiTestDebug.driver': 'Drive',
|
||||||
'apiTestDebug.username': 'Username',
|
'apiTestDebug.username': 'Username',
|
||||||
|
|
|
@ -94,7 +94,7 @@ export default {
|
||||||
'apiTestDebug.deleteDebugTipContent': '删除后无法恢复,请谨慎操作!',
|
'apiTestDebug.deleteDebugTipContent': '删除后无法恢复,请谨慎操作!',
|
||||||
'apiTestDebug.deleteConfirm': '确认删除',
|
'apiTestDebug.deleteConfirm': '确认删除',
|
||||||
'apiTestDebug.deleteSuccess': '删除成功',
|
'apiTestDebug.deleteSuccess': '删除成功',
|
||||||
'apiTestDebug.moduleMoveSuccess': '模块移动成功',
|
'apiTestDebug.moduleMoveSuccess': '移动成功',
|
||||||
'apiTestDebug.sqlSourceName': '数据源名称',
|
'apiTestDebug.sqlSourceName': '数据源名称',
|
||||||
'apiTestDebug.driver': '驱动',
|
'apiTestDebug.driver': '驱动',
|
||||||
'apiTestDebug.username': '用户名',
|
'apiTestDebug.username': '用户名',
|
||||||
|
|
|
@ -79,7 +79,8 @@
|
||||||
:show-fill-icon="false"
|
:show-fill-icon="false"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<template v-if="isCheckedPerformance">
|
<!--TODO:暂无性能测试-->
|
||||||
|
<!-- <template v-if="isCheckedPerformance">
|
||||||
<a-form-item :label="t('system.resourcePool.mirror')" field="testResourceDTO.loadTestImage" class="form-item">
|
<a-form-item :label="t('system.resourcePool.mirror')" field="testResourceDTO.loadTestImage" class="form-item">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:model-value="form.testResourceDTO.loadTestImage"
|
v-model:model-value="form.testResourceDTO.loadTestImage"
|
||||||
|
@ -98,9 +99,9 @@
|
||||||
@fill="fillHeapByDefault"
|
@fill="fillHeapByDefault"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</template>
|
</template> -->
|
||||||
|
<!--TODO:暂无UI测试-->
|
||||||
<template v-if="isCheckedUI">
|
<!-- <template v-if="isCheckedUI">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label="t('system.resourcePool.uiGrid')"
|
:label="t('system.resourcePool.uiGrid')"
|
||||||
field="testResourceDTO.uiGrid"
|
field="testResourceDTO.uiGrid"
|
||||||
|
@ -131,7 +132,7 @@
|
||||||
class="w-[160px]"
|
class="w-[160px]"
|
||||||
></a-input-number>
|
></a-input-number>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</template>
|
</template> -->
|
||||||
|
|
||||||
<a-form-item v-if="isShowTypeItem" :label="t('system.resourcePool.type')" field="type" class="form-item">
|
<a-form-item v-if="isShowTypeItem" :label="t('system.resourcePool.type')" field="type" class="form-item">
|
||||||
<a-radio-group v-model:model-value="form.type" type="button" @change="changeResourceType">
|
<a-radio-group v-model:model-value="form.type" type="button" @change="changeResourceType">
|
||||||
|
|
Loading…
Reference in New Issue