feat(接口场景): 增加api/case请求参数的参数名称唯一的校验
This commit is contained in:
parent
43d696670f
commit
3a2adf5889
|
@ -75,8 +75,8 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { useVModel } from '@vueuse/core';
|
import { useVModel } from '@vueuse/core';
|
||||||
import { FormInstance } from '@arco-design/web-vue';
|
import { FormInstance, Message } from '@arco-design/web-vue';
|
||||||
import { cloneDeep } from 'lodash-es';
|
import { cloneDeep, debounce } from 'lodash-es';
|
||||||
|
|
||||||
import { LanguageEnum } from '@/components/pure/ms-code-editor/types';
|
import { LanguageEnum } from '@/components/pure/ms-code-editor/types';
|
||||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||||
|
@ -142,6 +142,7 @@
|
||||||
title: 'project.commonScript.ParameterNames',
|
title: 'project.commonScript.ParameterNames',
|
||||||
slotName: 'key',
|
slotName: 'key',
|
||||||
dataIndex: 'key',
|
dataIndex: 'key',
|
||||||
|
needValidRepeat: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'project.commonScript.ParameterValue',
|
title: 'project.commonScript.ParameterValue',
|
||||||
|
@ -179,9 +180,21 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const paramMessageList = ref<string[]>([]);
|
||||||
|
const setErrorMessageList = debounce((list: string[]) => {
|
||||||
|
paramMessageList.value = [...list];
|
||||||
|
}, 300);
|
||||||
|
provide('setErrorMessageList', setErrorMessageList);
|
||||||
|
|
||||||
function handleDrawerConfirm() {
|
function handleDrawerConfirm() {
|
||||||
formRef.value?.validate(async (errors) => {
|
formRef.value?.validate(async (errors) => {
|
||||||
if (!errors) {
|
if (!errors) {
|
||||||
|
if (paramMessageList.value.length) {
|
||||||
|
paramMessageList.value?.forEach((message) => {
|
||||||
|
Message.error(message);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
emit('save', form.value);
|
emit('save', form.value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
props.noContentPadding ? 'ms-drawer-no-content-padding' : '',
|
props.noContentPadding ? 'ms-drawer-no-content-padding' : '',
|
||||||
props.noTitle ? 'ms-drawer-no-title' : '',
|
props.noTitle ? 'ms-drawer-no-title' : '',
|
||||||
]"
|
]"
|
||||||
|
:on-before-cancel="handleBeforeCancel"
|
||||||
@cancel="handleCancel"
|
@cancel="handleCancel"
|
||||||
@close="handleClose"
|
@close="handleClose"
|
||||||
>
|
>
|
||||||
|
@ -150,6 +151,7 @@
|
||||||
drawerStyle?: Record<string, string>; // 抽屉样式
|
drawerStyle?: Record<string, string>; // 抽屉样式
|
||||||
showFullScreen?: boolean; // 是否显示全屏按钮
|
showFullScreen?: boolean; // 是否显示全屏按钮
|
||||||
maskClosable?: boolean; // 点击遮罩是否关闭
|
maskClosable?: boolean; // 点击遮罩是否关闭
|
||||||
|
handleBeforeCancel?: () => boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<DrawerProps>(), {
|
const props = withDefaults(defineProps<DrawerProps>(), {
|
||||||
|
@ -197,6 +199,11 @@
|
||||||
emit('close');
|
emit('close');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 关闭抽屉时进行拦截
|
||||||
|
const handleBeforeCancel = () => {
|
||||||
|
return props.handleBeforeCancel ? props.handleBeforeCancel() : true;
|
||||||
|
};
|
||||||
|
|
||||||
const resizing = ref(false); // 是否正在拖拽
|
const resizing = ref(false); // 是否正在拖拽
|
||||||
const drawerWidth = ref(props.width); // 抽屉初始宽度
|
const drawerWidth = ref(props.width); // 抽屉初始宽度
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
:show-continue="true"
|
:show-continue="true"
|
||||||
:footer="requestVModel.isNew === true"
|
:footer="requestVModel.isNew === true"
|
||||||
:ok-disabled="requestVModel.executeLoading || (isHttpProtocol && !requestVModel.url)"
|
:ok-disabled="requestVModel.executeLoading || (isHttpProtocol && !requestVModel.url)"
|
||||||
|
:handle-before-cancel="handleBeforeCancel"
|
||||||
show-full-screen
|
show-full-screen
|
||||||
@confirm="handleSave"
|
@confirm="handleSave"
|
||||||
@continue="handleContinue"
|
@continue="handleContinue"
|
||||||
|
@ -25,7 +26,7 @@
|
||||||
/>
|
/>
|
||||||
<a-tooltip v-if="!isShowEditStepNameInput" :content="title" position="bottom">
|
<a-tooltip v-if="!isShowEditStepNameInput" :content="title" position="bottom">
|
||||||
<div class="flex items-center gap-[4px]">
|
<div class="flex items-center gap-[4px]">
|
||||||
<div class="one-line-text">
|
<div class="one-line-text max-w-[300px]">
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</div>
|
</div>
|
||||||
<MsIcon
|
<MsIcon
|
||||||
|
@ -374,6 +375,7 @@
|
||||||
import apiMethodName from '@/views/api-test/components/apiMethodName.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 auth from '@/views/api-test/components/requestComposition/auth.vue';
|
import auth from '@/views/api-test/components/requestComposition/auth.vue';
|
||||||
|
import { TabErrorMessage } from '@/views/api-test/components/requestComposition/index.vue';
|
||||||
import postcondition from '@/views/api-test/components/requestComposition/postcondition.vue';
|
import postcondition from '@/views/api-test/components/requestComposition/postcondition.vue';
|
||||||
import precondition from '@/views/api-test/components/requestComposition/precondition.vue';
|
import precondition from '@/views/api-test/components/requestComposition/precondition.vue';
|
||||||
import response from '@/views/api-test/components/requestComposition/response/index.vue';
|
import response from '@/views/api-test/components/requestComposition/response/index.vue';
|
||||||
|
@ -444,6 +446,9 @@
|
||||||
linkFileIds: string[];
|
linkFileIds: string[];
|
||||||
deleteFileIds?: string[];
|
deleteFileIds?: string[];
|
||||||
unLinkFileIds?: string[];
|
unLinkFileIds?: string[];
|
||||||
|
errorMessageInfo?: {
|
||||||
|
[key: string]: Record<string, any>;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RequestParam = ExecuteApiRequestFullParams & {
|
export type RequestParam = ExecuteApiRequestFullParams & {
|
||||||
|
@ -544,6 +549,7 @@
|
||||||
responseActiveTab: ResponseComposition.BODY,
|
responseActiveTab: ResponseComposition.BODY,
|
||||||
isNew: true,
|
isNew: true,
|
||||||
executeLoading: false,
|
executeLoading: false,
|
||||||
|
errorMessageInfo: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
const requestVModel = ref<RequestParam>(defaultApiParams);
|
const requestVModel = ref<RequestParam>(defaultApiParams);
|
||||||
|
@ -1099,15 +1105,102 @@
|
||||||
emit('stopDebug');
|
emit('stopDebug');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initErrorMessageInfoItem(key) {
|
||||||
|
if (requestVModel.value.errorMessageInfo && !requestVModel.value.errorMessageInfo[key]) {
|
||||||
|
requestVModel.value.errorMessageInfo[key] = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setChildErrorMessage(key: number | string, listItem: TabErrorMessage) {
|
||||||
|
if (requestVModel.value.errorMessageInfo) {
|
||||||
|
requestVModel.value.errorMessageInfo[requestVModel.value.activeTab][key] = cloneDeep(listItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeTabErrorMessageList(tabKey: string, formErrorMessageList: string[]) {
|
||||||
|
if (!requestVModel.value.errorMessageInfo) return;
|
||||||
|
const label = contentTabList.value.find((item) => item.value === tabKey)?.label ?? '';
|
||||||
|
const listItem: TabErrorMessage = {
|
||||||
|
value: tabKey,
|
||||||
|
label,
|
||||||
|
messageList: formErrorMessageList,
|
||||||
|
};
|
||||||
|
initErrorMessageInfoItem(requestVModel.value.activeTab);
|
||||||
|
if (requestVModel.value.activeTab === RequestComposition.BODY) {
|
||||||
|
setChildErrorMessage(requestVModel.value.body.bodyType, listItem);
|
||||||
|
} else if (requestVModel.value.activeTab === RequestComposition.POST_CONDITION) {
|
||||||
|
setChildErrorMessage(requestVModel.value.children[0].postProcessorConfig.activeItemId as number, listItem);
|
||||||
|
} else if (requestVModel.value.activeTab === RequestComposition.PRECONDITION) {
|
||||||
|
setChildErrorMessage(requestVModel.value.children[0].preProcessorConfig.activeItemId as number, listItem);
|
||||||
|
} else {
|
||||||
|
requestVModel.value.errorMessageInfo[requestVModel.value.activeTab] = cloneDeep(listItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const setErrorMessageList = debounce((list: string[]) => {
|
||||||
|
changeTabErrorMessageList(requestVModel.value.activeTab, list);
|
||||||
|
}, 300);
|
||||||
|
provide('setErrorMessageList', setErrorMessageList);
|
||||||
|
|
||||||
|
// 需要最终提示的信息
|
||||||
|
function getFlattenedMessages() {
|
||||||
|
if (!requestVModel.value.errorMessageInfo) return;
|
||||||
|
const flattenedMessages: { label: string; messageList: string[] }[] = [];
|
||||||
|
const { errorMessageInfo } = requestVModel.value;
|
||||||
|
Object.entries(errorMessageInfo).forEach(([key, item]) => {
|
||||||
|
const label = item.label || Object.values(item)[0]?.label;
|
||||||
|
// 处理前后置已删除的
|
||||||
|
if ([RequestComposition.POST_CONDITION as string, RequestComposition.PRECONDITION as string].includes(key)) {
|
||||||
|
const processorIds = requestVModel.value.children[0][
|
||||||
|
key === RequestComposition.POST_CONDITION ? 'postProcessorConfig' : 'preProcessorConfig'
|
||||||
|
].processors.map((processorItem) => String(processorItem.id));
|
||||||
|
Object.entries(item).forEach(([childKey, childItem]) => {
|
||||||
|
if (!processorIds.includes(childKey)) {
|
||||||
|
childItem.messageList = [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const messageList: string[] =
|
||||||
|
item.messageList || [...new Set(Object.values(item).flatMap((child) => child.messageList))] || [];
|
||||||
|
if (messageList.length) {
|
||||||
|
flattenedMessages.push({ label, messageList: [...new Set(messageList)] });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return flattenedMessages;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showMessage() {
|
||||||
|
getFlattenedMessages()?.forEach(({ label, messageList }) => {
|
||||||
|
messageList?.forEach((message) => {
|
||||||
|
Message.error(`${label}${message}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function handleContinue() {
|
function handleContinue() {
|
||||||
|
// 检查全部的校验信息
|
||||||
|
if (getFlattenedMessages()?.length) {
|
||||||
|
showMessage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
emit('addStep', cloneDeep(makeRequestParams()));
|
emit('addStep', cloneDeep(makeRequestParams()));
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSave() {
|
function handleSave() {
|
||||||
handleContinue();
|
handleContinue();
|
||||||
|
if (getFlattenedMessages()?.length) return;
|
||||||
visible.value = false;
|
visible.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleBeforeCancel() {
|
||||||
|
// 检查全部的校验信息
|
||||||
|
if (getFlattenedMessages()?.length) {
|
||||||
|
showMessage();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
function handleClose() {
|
function handleClose() {
|
||||||
// 关闭时若不是创建行为则是编辑行为,需要触发 applyStep
|
// 关闭时若不是创建行为则是编辑行为,需要触发 applyStep
|
||||||
if (!requestVModel.value.isNew) {
|
if (!requestVModel.value.isNew) {
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
:footer="false"
|
:footer="false"
|
||||||
show-full-screen
|
show-full-screen
|
||||||
no-content-padding
|
no-content-padding
|
||||||
|
:handle-before-cancel="handleBeforeCancel"
|
||||||
@close="handleClose"
|
@close="handleClose"
|
||||||
>
|
>
|
||||||
<template #title>
|
<template #title>
|
||||||
|
@ -286,6 +287,7 @@
|
||||||
import replaceButton from './replaceButton.vue';
|
import replaceButton from './replaceButton.vue';
|
||||||
import stepType from './stepType/stepType.vue';
|
import stepType from './stepType/stepType.vue';
|
||||||
import auth from '@/views/api-test/components/requestComposition/auth.vue';
|
import auth from '@/views/api-test/components/requestComposition/auth.vue';
|
||||||
|
import { TabErrorMessage } from '@/views/api-test/components/requestComposition/index.vue';
|
||||||
import postcondition from '@/views/api-test/components/requestComposition/postcondition.vue';
|
import postcondition from '@/views/api-test/components/requestComposition/postcondition.vue';
|
||||||
import precondition from '@/views/api-test/components/requestComposition/precondition.vue';
|
import precondition from '@/views/api-test/components/requestComposition/precondition.vue';
|
||||||
import response from '@/views/api-test/components/requestComposition/response/index.vue';
|
import response from '@/views/api-test/components/requestComposition/response/index.vue';
|
||||||
|
@ -420,6 +422,7 @@
|
||||||
responseActiveTab: ResponseComposition.BODY,
|
responseActiveTab: ResponseComposition.BODY,
|
||||||
isNew: true,
|
isNew: true,
|
||||||
executeLoading: false,
|
executeLoading: false,
|
||||||
|
errorMessageInfo: {},
|
||||||
};
|
};
|
||||||
const requestVModel = ref<RequestParam>(defaultApiParams);
|
const requestVModel = ref<RequestParam>(defaultApiParams);
|
||||||
const _stepType = computed(() => {
|
const _stepType = computed(() => {
|
||||||
|
@ -938,6 +941,87 @@
|
||||||
emit('stopDebug');
|
emit('stopDebug');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initErrorMessageInfoItem(key) {
|
||||||
|
if (requestVModel.value.errorMessageInfo && !requestVModel.value.errorMessageInfo[key]) {
|
||||||
|
requestVModel.value.errorMessageInfo[key] = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setChildErrorMessage(key: number | string, listItem: TabErrorMessage) {
|
||||||
|
if (requestVModel.value.errorMessageInfo) {
|
||||||
|
requestVModel.value.errorMessageInfo[requestVModel.value.activeTab][key] = cloneDeep(listItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeTabErrorMessageList(tabKey: string, formErrorMessageList: string[]) {
|
||||||
|
if (!requestVModel.value.errorMessageInfo) return;
|
||||||
|
const label = contentTabList.value.find((item) => item.value === tabKey)?.label ?? '';
|
||||||
|
const listItem: TabErrorMessage = {
|
||||||
|
value: tabKey,
|
||||||
|
label,
|
||||||
|
messageList: formErrorMessageList,
|
||||||
|
};
|
||||||
|
initErrorMessageInfoItem(requestVModel.value.activeTab);
|
||||||
|
if (requestVModel.value.activeTab === RequestComposition.BODY) {
|
||||||
|
setChildErrorMessage(requestVModel.value.body.bodyType, listItem);
|
||||||
|
} else if (requestVModel.value.activeTab === RequestComposition.POST_CONDITION) {
|
||||||
|
setChildErrorMessage(requestVModel.value.children[0].postProcessorConfig.activeItemId as number, listItem);
|
||||||
|
} else if (requestVModel.value.activeTab === RequestComposition.PRECONDITION) {
|
||||||
|
setChildErrorMessage(requestVModel.value.children[0].preProcessorConfig.activeItemId as number, listItem);
|
||||||
|
} else {
|
||||||
|
requestVModel.value.errorMessageInfo[requestVModel.value.activeTab] = cloneDeep(listItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const setErrorMessageList = debounce((list: string[]) => {
|
||||||
|
changeTabErrorMessageList(requestVModel.value.activeTab, list);
|
||||||
|
}, 300);
|
||||||
|
provide('setErrorMessageList', setErrorMessageList);
|
||||||
|
|
||||||
|
// 需要最终提示的信息
|
||||||
|
function getFlattenedMessages() {
|
||||||
|
if (!requestVModel.value.errorMessageInfo) return;
|
||||||
|
const flattenedMessages: { label: string; messageList: string[] }[] = [];
|
||||||
|
const { errorMessageInfo } = requestVModel.value;
|
||||||
|
Object.entries(errorMessageInfo).forEach(([key, item]) => {
|
||||||
|
const label = item.label || Object.values(item)[0]?.label;
|
||||||
|
// 处理前后置已删除的
|
||||||
|
if ([RequestComposition.POST_CONDITION as string, RequestComposition.PRECONDITION as string].includes(key)) {
|
||||||
|
const processorIds = requestVModel.value.children[0][
|
||||||
|
key === RequestComposition.POST_CONDITION ? 'postProcessorConfig' : 'preProcessorConfig'
|
||||||
|
].processors.map((processorItem) => String(processorItem.id));
|
||||||
|
Object.entries(item).forEach(([childKey, childItem]) => {
|
||||||
|
if (!processorIds.includes(childKey)) {
|
||||||
|
childItem.messageList = [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const messageList: string[] =
|
||||||
|
item.messageList || [...new Set(Object.values(item).flatMap((child) => child.messageList))] || [];
|
||||||
|
if (messageList.length) {
|
||||||
|
flattenedMessages.push({ label, messageList: [...new Set(messageList)] });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return flattenedMessages;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showMessage() {
|
||||||
|
getFlattenedMessages()?.forEach(({ label, messageList }) => {
|
||||||
|
messageList?.forEach((message) => {
|
||||||
|
Message.error(`${label}${message}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleBeforeCancel() {
|
||||||
|
// 检查全部的校验信息
|
||||||
|
if (getFlattenedMessages()?.length) {
|
||||||
|
showMessage();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
function handleClose() {
|
function handleClose() {
|
||||||
// 关闭时若不是创建行为则是编辑行为,需要触发 applyStep,引用 case 不能更改不需要触发
|
// 关闭时若不是创建行为则是编辑行为,需要触发 applyStep,引用 case 不能更改不需要触发
|
||||||
if (!requestVModel.value.isNew && activeStep.value?.refType === ScenarioStepRefType.COPY) {
|
if (!requestVModel.value.isNew && activeStep.value?.refType === ScenarioStepRefType.COPY) {
|
||||||
|
|
Loading…
Reference in New Issue