feat(接口调试): 联调98%
This commit is contained in:
parent
f777cb034e
commit
d3442f9de4
|
@ -10,6 +10,7 @@ import {
|
|||
GetDebugModuleCountUrl,
|
||||
GetDebugModulesUrl,
|
||||
MoveDebugModuleUrl,
|
||||
TestMockUrl,
|
||||
UpdateApiDebugUrl,
|
||||
UpdateDebugModuleUrl,
|
||||
UploadTempFileUrl,
|
||||
|
@ -85,6 +86,11 @@ export function deleteDebug(id: string) {
|
|||
return MSR.get({ url: DeleteDebugUrl, params: id });
|
||||
}
|
||||
|
||||
// 测试mock
|
||||
export function testMock(key: string) {
|
||||
return MSR.get({ url: TestMockUrl, params: key });
|
||||
}
|
||||
|
||||
// 上传文件
|
||||
export function uploadTempFile(file: File) {
|
||||
return MSR.uploadFile({ url: UploadTempFileUrl }, { fileList: [file] }, 'file');
|
||||
|
|
|
@ -3,6 +3,7 @@ export const AddApiDebugUrl = '/api/debug/add'; // 新增调试
|
|||
export const UpdateApiDebugUrl = '/api/debug/update'; // 更新调试
|
||||
export const GetApiDebugDetailUrl = '/api/debug/get'; // 获取接口调试详情
|
||||
export const DeleteDebugUrl = '/api/debug/delete'; // 删除调试
|
||||
export const TestMockUrl = '/api/test/mock'; // 测试mock
|
||||
export const UpdateDebugModuleUrl = '/api/debug/module/update'; // 更新模块
|
||||
export const MoveDebugModuleUrl = '/api/debug/module/move'; // 移动模块
|
||||
export const GetDebugModuleCountUrl = '/api/debug/module/count'; // 模块统计数量
|
||||
|
|
|
@ -37,25 +37,67 @@
|
|||
<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"
|
||||
:input-class="props.inputClass"
|
||||
placeholder=" "
|
||||
:max-tag-count="1"
|
||||
:size="props.inputSize"
|
||||
readonly
|
||||
class="!w-[calc(100%-28px)]"
|
||||
<a-popover
|
||||
v-model:popup-visible="inputFilesPopoverVisible"
|
||||
trigger="click"
|
||||
position="bottom"
|
||||
:disabled="inputFiles.length === 0"
|
||||
>
|
||||
<template #tag="{ data }">
|
||||
<MsTag
|
||||
:size="props.tagSize"
|
||||
class="m-0 border-none p-0"
|
||||
:self-style="{ backgroundColor: 'transparent !important' }"
|
||||
>
|
||||
{{ data.label }}
|
||||
</MsTag>
|
||||
<MsTagsInput
|
||||
v-model:model-value="inputFiles"
|
||||
:input-class="props.inputClass"
|
||||
placeholder=" "
|
||||
:max-tag-count="1"
|
||||
:size="props.inputSize"
|
||||
readonly
|
||||
class="!w-[calc(100%-28px)]"
|
||||
>
|
||||
<template v-if="alreadyDeleteFiles.length > 0" #prefix>
|
||||
<icon-exclamation-circle-fill class="!text-[rgb(var(--warning-6))]" :size="18" />
|
||||
</template>
|
||||
<template #tag="{ data }">
|
||||
<MsTag
|
||||
:size="props.tagSize"
|
||||
class="m-0 border-none p-0"
|
||||
:self-style="{ backgroundColor: 'transparent !important' }"
|
||||
:closable="data.value !== '__arco__more'"
|
||||
@close="handleClose(data)"
|
||||
>
|
||||
{{ data.value === '__arco__more' ? data.label.replace('...', '') : data.label }}
|
||||
</MsTag>
|
||||
</template>
|
||||
</MsTagsInput>
|
||||
<template #content>
|
||||
<div class="flex w-[200px] flex-col gap-[8px]">
|
||||
<template v-if="alreadyDeleteFiles.length > 0">
|
||||
<div class="flex items-center gap-[4px]">
|
||||
<icon-exclamation-circle-fill class="!text-[rgb(var(--warning-6))]" :size="18" />
|
||||
<div class="text-[var(--color-text-4)]">{{ t('ms.add.attachment.alreadyDelete') }}</div>
|
||||
<MsButton type="text" @click="clearDeletedFiles">{{ t('ms.add.attachment.quickClear') }}</MsButton>
|
||||
</div>
|
||||
<div class="file-list">
|
||||
<div v-for="file of alreadyDeleteFiles" :key="file.value">
|
||||
<MsTag size="small" max-width="100%" closable @close="handleClose(file)">
|
||||
{{ file.label }}
|
||||
</MsTag>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="otherFiles.length > 0">
|
||||
<div v-if="alreadyDeleteFiles.length > 0" class="mt-[4px] text-[var(--color-text-4)]">
|
||||
{{ t('ms.add.attachment.other') }}
|
||||
</div>
|
||||
<div class="file-list">
|
||||
<div v-for="file of otherFiles" :key="file.value">
|
||||
<MsTag size="small" max-width="100%" closable @close="handleClose(file)">
|
||||
{{ file.label }}
|
||||
</MsTag>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</MsTagsInput>
|
||||
</a-popover>
|
||||
</div>
|
||||
<div v-else class="flex w-full items-center gap-[4px]">
|
||||
<dropdownMenu v-model:file-list="innerFileList" @link-file="associatedFile" @change="handleChange" />
|
||||
|
@ -85,6 +127,7 @@
|
|||
import { useVModel } from '@vueuse/core';
|
||||
import { TagData } from '@arco-design/web-vue';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsTag, { Size } 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';
|
||||
|
@ -148,6 +191,7 @@
|
|||
if (defaultFiles.length > 0) {
|
||||
if (props.multiple) {
|
||||
inputFiles.value = defaultFiles.map((item) => ({
|
||||
...item,
|
||||
// 这里取自定义的字段名,因为存在查看的场景时不会与刚选择的文件信息一样
|
||||
value: item?.[props.fields.id] || '',
|
||||
label: item?.[props.fields.name] || '',
|
||||
|
@ -220,9 +264,24 @@
|
|||
emit('change', innerFileList.value);
|
||||
}
|
||||
|
||||
const inputFilesPopoverVisible = ref(false);
|
||||
const alreadyDeleteFiles = computed(() => {
|
||||
return inputFiles.value.filter((item) => item.delete);
|
||||
});
|
||||
const otherFiles = computed(() => {
|
||||
return inputFiles.value.filter((item) => !item.delete);
|
||||
});
|
||||
|
||||
function clearDeletedFiles() {
|
||||
inputFiles.value = inputFiles.value.filter((item) => !item.delete);
|
||||
}
|
||||
|
||||
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);
|
||||
if (innerFileList.value.length === 0) {
|
||||
inputFilesPopoverVisible.value = false;
|
||||
}
|
||||
emit('deleteFile', data.value);
|
||||
}
|
||||
|
||||
|
@ -235,6 +294,19 @@
|
|||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.file-list {
|
||||
@apply flex flex-col overflow-y-auto overflow-x-hidden;
|
||||
.ms-scroll-bar();
|
||||
|
||||
gap: 8px;
|
||||
max-height: 100px;
|
||||
}
|
||||
:deep(.arco-input-tag-has-prefix) {
|
||||
padding-left: 4px;
|
||||
}
|
||||
:deep(.arco-input-tag-prefix) {
|
||||
padding-right: 4px;
|
||||
}
|
||||
:deep(.arco-input-tag-inner) {
|
||||
@apply flex w-full items-center;
|
||||
.arco-input-tag-tag {
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
export default {
|
||||
'ms.add.attachment.localUpload': 'Local upload',
|
||||
'ms.add.attachment.associateFile': 'Associate file',
|
||||
'ms.add.attachment.alreadyDelete': 'Deleted files',
|
||||
'ms.add.attachment.other': 'Other files',
|
||||
'ms.add.attachment.quickClear': 'Clear',
|
||||
};
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
export default {
|
||||
'ms.add.attachment.localUpload': '本地上传',
|
||||
'ms.add.attachment.associateFile': '关联文件',
|
||||
'ms.add.attachment.alreadyDelete': '已被删除文件',
|
||||
'ms.add.attachment.other': '其他文件',
|
||||
'ms.add.attachment.quickClear': '一键移除',
|
||||
};
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
import { FormInstance } from '@arco-design/web-vue';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
import { LanguageEnum } from '@/components/pure/ms-code-editor/types';
|
||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||
import type { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
||||
|
@ -84,7 +85,7 @@
|
|||
import { getCommonScriptDetail, getSocket, testCommonScript } from '@/api/modules/project-management/commonScript';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import { getGenerateId, sleep } from '@/utils';
|
||||
import { getGenerateId } from '@/utils';
|
||||
|
||||
import type { AddOrUpdateCommonScript, ParamsRequestType } from '@/models/projectManagement/commonScript';
|
||||
|
||||
|
@ -127,7 +128,7 @@
|
|||
projectId: '',
|
||||
params: '',
|
||||
script: '',
|
||||
type: 'beanshell-jsr233',
|
||||
type: LanguageEnum.BEANSHELL_JSR233,
|
||||
result: '',
|
||||
};
|
||||
|
||||
|
|
|
@ -148,9 +148,10 @@
|
|||
<div
|
||||
:class="`flex ${data.isLeaf ? 'mr-[-26px] w-[270px]' : 'w-[120px]'} items-center justify-between`"
|
||||
>
|
||||
<a-tooltip :content="t(data.label)">
|
||||
<!-- {symbol: '|'}是为了解决vue-i18n中|是特殊功能符号,会被转换掉 -->
|
||||
<a-tooltip :content="t(data.label, { symbol: '|' })">
|
||||
<div :class="`one-line-text ${data.isLeaf ? 'max-w-[50%]' : ''}`" title="">
|
||||
{{ t(data.label) }}
|
||||
{{ t(data.label, { symbol: '|' }) }}
|
||||
</div>
|
||||
</a-tooltip>
|
||||
<a-tooltip v-if="data.isLeaf" :content="data.value">
|
||||
|
@ -164,9 +165,15 @@
|
|||
</a-form-item>
|
||||
</template>
|
||||
</a-form>
|
||||
<div class="mb-[16px] flex items-center gap-[16px] bg-[var(--color-text-n9)] p-[5px_8px]">
|
||||
<div
|
||||
v-if="paramForm.type === 'mock'"
|
||||
class="mb-[16px] flex items-center gap-[16px] bg-[var(--color-text-n9)] p-[5px_8px]"
|
||||
>
|
||||
<div class="text-[var(--color-text-3)]">{{ t('ms.paramsInput.preview') }}</div>
|
||||
<div class="text-[var(--color-text-1)]">{{ paramPreview }}</div>
|
||||
<a-spin :loading="previewLoading" class="flex gap-[8px]">
|
||||
<div class="text-[var(--color-text-1)]">{{ paramPreview }}</div>
|
||||
<MsButton type="text" @click="getMockValue">{{ t('ms.paramsInput.previewClick') }}</MsButton>
|
||||
</a-spin>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-end gap-[8px]">
|
||||
|
@ -192,12 +199,14 @@
|
|||
<div class="ms-params-popover-value mb-[8px]">
|
||||
{{ innerValue }}
|
||||
</div>
|
||||
<div class="ms-params-popover-subtitle">
|
||||
{{ t('ms.paramsInput.preview') }}
|
||||
</div>
|
||||
<div class="ms-params-popover-value">
|
||||
{{ innerValue }}
|
||||
</div>
|
||||
<template v-if="/^@/.test(innerValue)">
|
||||
<div class="ms-params-popover-subtitle">
|
||||
{{ t('ms.paramsInput.preview') }}
|
||||
</div>
|
||||
<div class="ms-params-popover-value">
|
||||
{{ paramPreview }}
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<a-auto-complete
|
||||
ref="autoCompleteRef"
|
||||
|
@ -230,12 +239,14 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import { useEventListener, useStorage, useVModel } from '@vueuse/core';
|
||||
import { cloneDeep, includes } from 'lodash-es';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
import MsCascader from '@/components/business/ms-cascader/index.vue';
|
||||
import paramsInputGroup from './paramsInputGroup.vue';
|
||||
|
||||
import { testMock } from '@/api/modules/api-test/debug';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
import {
|
||||
|
@ -322,11 +333,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
function selectAutoComplete(val: string) {
|
||||
innerValue.value = val;
|
||||
setLastTenParams(val);
|
||||
}
|
||||
|
||||
const autoCompleteRef = ref<InstanceType<typeof AutoComplete>>();
|
||||
|
||||
onMounted(() => {
|
||||
|
@ -365,7 +371,6 @@
|
|||
const paramFormRef = ref<FormInstance>();
|
||||
const paramTypeOptions: CascaderOption[] = cloneDeep(mockAllGroup);
|
||||
const paramFuncOptions: MockParamItem[] = cloneDeep(mockFunctions);
|
||||
const paramPreview = ref('xsxsxsxs');
|
||||
const currentParamsInputGroup = ref<MockParamInputGroupItem[]>([]);
|
||||
|
||||
/**
|
||||
|
@ -541,6 +546,35 @@
|
|||
return resultStr;
|
||||
}
|
||||
|
||||
const paramPreview = ref('');
|
||||
const previewLoading = ref(false);
|
||||
async function getMockValue(val?: string) {
|
||||
try {
|
||||
previewLoading.value = true;
|
||||
paramPreview.value = await testMock(val || applyMock());
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
paramPreview.value = '';
|
||||
} finally {
|
||||
previewLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => popoverVisible.value,
|
||||
(val) => {
|
||||
if (val && /^@/.test(innerValue.value)) {
|
||||
getMockValue(innerValue.value);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
function selectAutoComplete(val: string) {
|
||||
innerValue.value = val;
|
||||
setLastTenParams(val);
|
||||
}
|
||||
|
||||
function apply() {
|
||||
paramFormRef.value?.validate((errors) => {
|
||||
if (!errors) {
|
||||
|
|
|
@ -2,6 +2,7 @@ export default {
|
|||
'ms.paramsInput.value': 'Parameter value',
|
||||
'ms.paramsInput.placeholder': 'Starting with {at}, double-click to quickly enter',
|
||||
'ms.paramsInput.preview': 'Parameter preview',
|
||||
'ms.paramsInput.previewClick': 'Click to get',
|
||||
'ms.paramsInput.natural': 'Natural number',
|
||||
'ms.paramsInput.naturalDesc': 'Returns a random natural number',
|
||||
'ms.paramsInput.naturalRange': 'Natural numbers from 1-100',
|
||||
|
@ -162,7 +163,7 @@ export default {
|
|||
'ms.paramsInput.base': 'Basic variables',
|
||||
'ms.paramsInput.apply': 'Apply',
|
||||
'ms.paramsInput.variable': 'Variable',
|
||||
'ms.paramsInput.randomFromMultipleVars': 'Extract elements from a set of values of variables separated by |',
|
||||
'ms.paramsInput.randomFromMultipleVars': 'Extract elements from a set of values of variables separated by {symbol}',
|
||||
'ms.paramsInput.split': 'Split string into variables',
|
||||
'ms.paramsInput.eval': 'Compute variable expression',
|
||||
'ms.paramsInput.evalVar': 'Evaluate an expression stored in a variable',
|
||||
|
|
|
@ -2,6 +2,7 @@ export default {
|
|||
'ms.paramsInput.value': '参数值',
|
||||
'ms.paramsInput.placeholder': '以{at}开始,双击可快速输入',
|
||||
'ms.paramsInput.preview': '参数预览',
|
||||
'ms.paramsInput.previewClick': '点击获取',
|
||||
'ms.paramsInput.natural': '自然数',
|
||||
'ms.paramsInput.naturalDesc': '返回一个随机的自然数',
|
||||
'ms.paramsInput.naturalRange': '1-100自然数',
|
||||
|
@ -154,7 +155,7 @@ export default {
|
|||
'ms.paramsInput.base': '基础变量',
|
||||
'ms.paramsInput.apply': '应用',
|
||||
'ms.paramsInput.variable': '变量',
|
||||
'ms.paramsInput.randomFromMultipleVars': '从由|分隔的一组变量的值中提取元素',
|
||||
'ms.paramsInput.randomFromMultipleVars': '从由{symbol}分隔的一组变量的值中提取元素',
|
||||
'ms.paramsInput.split': '将字符串拆分为变量',
|
||||
'ms.paramsInput.eval': '计算变量表达式',
|
||||
'ms.paramsInput.evalVar': '计算存储在变量中的表达式',
|
||||
|
|
|
@ -20,7 +20,7 @@ export const LanguageEnum = {
|
|||
YAML: 'yaml' as const,
|
||||
SHELL: 'shell' as const,
|
||||
BEANSHELL: 'beanshell' as const,
|
||||
BEANSHELLJSR233: 'beanshell-jsr233' as const,
|
||||
BEANSHELL_JSR233: 'beanshell-jsr233' as const,
|
||||
GROOVY: 'groovy' as const,
|
||||
NASHORNSCRIPT: 'nashornScript' as const,
|
||||
RHINOSCRIPT: 'rhinoScript' as const,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div :class="`w-full ${props.class}`">
|
||||
<div :class="`flex w-full items-center ${props.class}`">
|
||||
<a-input-tag
|
||||
v-model:model-value="innerModelValue"
|
||||
v-model:input-value="innerInputValue"
|
||||
|
|
|
@ -99,6 +99,7 @@ export interface AssociatedList {
|
|||
tags: any;
|
||||
description: string;
|
||||
moduleName: string; // 模块名称
|
||||
originalName: string; // 文件原始名称
|
||||
moduleId: string;
|
||||
createUser: string;
|
||||
createTime: number | string;
|
||||
|
|
|
@ -166,6 +166,7 @@
|
|||
...fileList.value[0],
|
||||
fileId: res.data,
|
||||
fileName: fileList.value[0]?.name || '',
|
||||
fileAlias: fileList.value[0]?.name || '',
|
||||
local: true,
|
||||
};
|
||||
appStore.hideLoading();
|
||||
|
@ -173,7 +174,8 @@
|
|||
innerParams.value.binaryBody.file = {
|
||||
...fileList.value[0],
|
||||
fileId: fileList.value[0].uid,
|
||||
fileName: fileList.value[0]?.name || '',
|
||||
fileName: fileList.value[0]?.originalName || '',
|
||||
fileAlias: fileList.value[0]?.name || '',
|
||||
local: false,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -645,8 +645,8 @@
|
|||
const realWwwFormBodyValues = wwwFormBody.formValues.filter((e, i) => i !== wwwFormBody.formValues.length - 1); // 去掉最后一行空行
|
||||
parseRequestBodyResult = parseRequestBodyFiles(
|
||||
requestVModel.value.body,
|
||||
requestVModel.value.uploadFileIds,
|
||||
requestVModel.value.linkFileIds
|
||||
requestVModel.value.uploadFileIds, // 外面解析详情的时候传入
|
||||
requestVModel.value.linkFileIds // 外面解析详情的时候传入
|
||||
);
|
||||
requestParams = {
|
||||
authConfig: requestVModel.value.authConfig,
|
||||
|
@ -658,7 +658,7 @@
|
|||
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,
|
||||
|
@ -748,8 +748,6 @@
|
|||
...makeRequestParams(),
|
||||
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;
|
||||
|
|
|
@ -101,11 +101,12 @@ export function convertToFile(fileInfo: AssociatedList): MsFileItem {
|
|||
enable: fileInfo.enable || false,
|
||||
file,
|
||||
name: fileName,
|
||||
originalName: fileInfo.originalName,
|
||||
percent: 0,
|
||||
status: 'done',
|
||||
uid: id,
|
||||
url: `${gatewayAddress}/${fileInfo.filePath || ''}`,
|
||||
local,
|
||||
local: !!local,
|
||||
deleteContent: local ? '' : 'caseManagement.featureCase.cancelLink',
|
||||
isUpdateFlag,
|
||||
associateId,
|
||||
|
|
Loading…
Reference in New Issue