feat(json-schema): ms-json-schema组件Done
This commit is contained in:
parent
9b97fe0664
commit
37a7993785
|
@ -72,7 +72,7 @@
|
|||
<style lang="less">
|
||||
/** 面包屑 **/
|
||||
.arco-breadcrumb-item {
|
||||
@apply cursor-pointer;
|
||||
@apply cursor-pointer break-keep;
|
||||
|
||||
color: var(--color-text-4);
|
||||
&:hover {
|
||||
|
|
|
@ -527,7 +527,7 @@
|
|||
if (node.children && node.children.length > 0) {
|
||||
waitingRenderNodes = waitingRenderNodes.concat(node.children);
|
||||
}
|
||||
if (total > list.length * current) {
|
||||
if (total > 100 * (current + 1)) {
|
||||
// 有更多用例
|
||||
const moreNode = window.minder.createNode(
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="flex w-full">
|
||||
<a-popover position="tl" :disabled="!modelValue || modelValue.trim() === ''" class="ms-params-input-popover">
|
||||
<template #content>
|
||||
<div v-if="props.title" class="ms-params-popover-title">
|
||||
|
@ -38,6 +38,7 @@
|
|||
@change="(val) => emit('change', val)"
|
||||
/>
|
||||
</a-popover>
|
||||
</div>
|
||||
<a-modal
|
||||
v-model:visible="showQuickInput"
|
||||
:title="props.title"
|
||||
|
@ -57,7 +58,6 @@
|
|||
:max-length="1000"
|
||||
/>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
|
|
@ -461,8 +461,14 @@
|
|||
</template>
|
||||
</MsCodeEditor>
|
||||
</MsDrawer>
|
||||
<MsDrawer v-model:visible="previewDrawerVisible" :width="600" :title="t('common.preview')" :footer="false">
|
||||
<a-spin class="block" :loading="previewDrawerLoading">
|
||||
<MsDrawer
|
||||
v-model:visible="previewDrawerVisible"
|
||||
:width="600"
|
||||
:title="t('common.preview')"
|
||||
:footer="false"
|
||||
@close="previewShowType = 'json'"
|
||||
>
|
||||
<a-spin class="block h-full w-full" :loading="previewDrawerLoading">
|
||||
<MsCodeEditor
|
||||
v-model:model-value="activePreviewValue"
|
||||
theme="vs"
|
||||
|
@ -500,8 +506,12 @@
|
|||
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
|
||||
import { JsonSchema, JsonSchemaTableItem } from './types';
|
||||
import { parseJsonToJsonSchemaTableItem, tableItemToJsonSchema } from './utils';
|
||||
import { JsonSchema, JsonSchemaItem, JsonSchemaTableItem } from './types';
|
||||
import {
|
||||
parseJsonToJsonSchemaTableData,
|
||||
parseSchemaToJsonSchemaTableData,
|
||||
parseTableDataToJsonSchema,
|
||||
} from './utils';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
|
@ -523,7 +533,19 @@
|
|||
children: undefined,
|
||||
};
|
||||
const data = defineModel<JsonSchemaTableItem[]>('data', {
|
||||
default: () => [
|
||||
default: () => [],
|
||||
});
|
||||
const expandKeys = defineModel<string[]>('expandKeys', {
|
||||
default: () => ['root'],
|
||||
});
|
||||
const selectedKeys = defineModel<string[]>('selectedKeys', {
|
||||
default: () => ['root'],
|
||||
});
|
||||
|
||||
// 初始化根节点
|
||||
watchEffect(() => {
|
||||
if (data.value.length === 0) {
|
||||
data.value = [
|
||||
{
|
||||
id: 'root',
|
||||
title: 'root',
|
||||
|
@ -542,10 +564,12 @@
|
|||
required: false,
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
];
|
||||
if (selectedKeys.value.length === 0) {
|
||||
selectedKeys.value = ['root'];
|
||||
}
|
||||
}
|
||||
});
|
||||
const expandKeys = ref<string[]>(['root']);
|
||||
const selectedKeys = ref<string[]>(['root']);
|
||||
|
||||
const typeOptions: SelectOptionData[] = [
|
||||
{
|
||||
|
@ -845,14 +869,22 @@
|
|||
}
|
||||
|
||||
function applyBatchAdd() {
|
||||
try {
|
||||
let res: { result: JsonSchemaTableItem[]; ids: Array<string> } = { result: [], ids: [] };
|
||||
if (batchAddType.value === 'json') {
|
||||
const res = parseJsonToJsonSchemaTableItem(batchAddValue.value);
|
||||
res = parseJsonToJsonSchemaTableData(batchAddValue.value);
|
||||
} else {
|
||||
res = parseSchemaToJsonSchemaTableData(batchAddValue.value);
|
||||
}
|
||||
if (res.result.length > 0) {
|
||||
data.value = res.result;
|
||||
selectedKeys.value = res.ids;
|
||||
}
|
||||
}
|
||||
batchAddDrawerVisible.value = false;
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
const settingDrawerVisible = ref(false);
|
||||
|
@ -870,7 +902,7 @@
|
|||
...record,
|
||||
};
|
||||
try {
|
||||
const schema = tableItemToJsonSchema(record, record.id === 'root');
|
||||
const schema = parseTableDataToJsonSchema(record, record.id === 'root');
|
||||
activePreviewJsonSchemaValue.value = JSON.stringify(schema);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
|
@ -883,7 +915,7 @@
|
|||
|
||||
function handleSettingFormChange() {
|
||||
activePreviewJsonSchemaValue.value = JSON.stringify(
|
||||
tableItemToJsonSchema(activeRecord.value, activeRecord.value.id === 'root')
|
||||
parseTableDataToJsonSchema(activeRecord.value, activeRecord.value.id === 'root')
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -927,19 +959,32 @@
|
|||
const previewDrawerVisible = ref(false);
|
||||
const previewDrawerLoading = ref(false);
|
||||
|
||||
/**
|
||||
* 预览 schema
|
||||
*/
|
||||
async function previewSchema() {
|
||||
previewDrawerVisible.value = true;
|
||||
try {
|
||||
previewDrawerLoading.value = true;
|
||||
const schema = tableItemToJsonSchema(data.value[0]);
|
||||
const res = await convertJsonSchemaToJson(schema as JsonSchema);
|
||||
activePreviewJsonValue.value = JSON.stringify(res);
|
||||
let schema: JsonSchema | JsonSchemaItem | undefined;
|
||||
try {
|
||||
// 先将表格数据转换为 json schema格式
|
||||
schema = parseTableDataToJsonSchema(data.value[0] as JsonSchemaTableItem);
|
||||
activePreviewJsonSchemaValue.value = JSON.stringify(schema);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
activePreviewJsonValue.value = t('ms.json.schema.convertFailed');
|
||||
activePreviewJsonSchemaValue.value = t('ms.json.schema.convertFailed');
|
||||
previewDrawerLoading.value = false;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// 再将 json schema 转换为 json 格式
|
||||
const res = await convertJsonSchemaToJson(schema as JsonSchema);
|
||||
activePreviewJsonValue.value = JSON.stringify(res);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
activePreviewJsonValue.value = t('ms.json.schema.convertFailed');
|
||||
} finally {
|
||||
previewDrawerLoading.value = false;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
export default {
|
||||
'ms.json.schema.name': 'Parameter Name',
|
||||
'ms.json.schema.nameNotNull': 'Parameter Name cannot be empty',
|
||||
'ms.json.schema.type': 'Type',
|
||||
'ms.json.schema.value': 'Parameter Value',
|
||||
'ms.json.schema.addChild': 'Add Child Field',
|
||||
'ms.json.schema.advancedSettings': 'Advanced Settings',
|
||||
'ms.json.schema.minLength': 'Minimum Length',
|
||||
'ms.json.schema.maxLength': 'Maximum Length',
|
||||
'ms.json.schema.minimum': 'Minimum Value',
|
||||
'ms.json.schema.maximum': 'Maximum Value',
|
||||
'ms.json.schema.default': 'Default Value',
|
||||
'ms.json.schema.enum': 'Enumeration',
|
||||
'ms.json.schema.enumPlaceholder': '1 line, 1 enumeration value',
|
||||
'ms.json.schema.regex': 'Regular Expression',
|
||||
'ms.json.schema.regexPlaceholder': 'e.g. {reg}',
|
||||
'ms.json.schema.format': 'Format',
|
||||
'ms.json.schema.preview': 'Preview',
|
||||
'ms.json.schema.batchAdd': 'Batch Add',
|
||||
'ms.json.schema.batchAddTip': 'Write in the format: "key":"value", e.g. "name":"natural"',
|
||||
'ms.json.schema.convertFailed': 'Data conversion failed, please try again',
|
||||
'ms.json.schema.minItems': 'Minimum number of items',
|
||||
'ms.json.schema.maxItems': 'Maximum number of items',
|
||||
'ms.json.schema.illegalJsonConvertFailed': 'Conversion failed, please check if the input JSON structure is valid',
|
||||
};
|
|
@ -2,7 +2,7 @@ export interface JsonSchemaCommon {
|
|||
id: string;
|
||||
title: string; // 参数名称
|
||||
type: string; // 参数类型
|
||||
description: string; // 参数描述
|
||||
description?: string; // 参数描述
|
||||
enable: boolean; // 是否启用
|
||||
example: string; // 参数值
|
||||
defaultValue: string | number | boolean; // 默认值
|
||||
|
@ -35,4 +35,5 @@ export interface JsonSchema {
|
|||
properties?: Record<string, JsonSchemaItem>;
|
||||
items?: JsonSchemaItem[];
|
||||
required?: string[];
|
||||
description?: string;
|
||||
}
|
||||
|
|
|
@ -10,10 +10,11 @@ import type { JsonSchema, JsonSchemaItem, JsonSchemaTableItem } from './types';
|
|||
* @param schemaItem 表格组件项
|
||||
* @param isRoot 是否为根节点
|
||||
*/
|
||||
export function tableItemToJsonSchema(
|
||||
export function parseTableDataToJsonSchema(
|
||||
schemaItem: JsonSchemaTableItem,
|
||||
isRoot: boolean = true
|
||||
): JsonSchema | JsonSchemaItem {
|
||||
): JsonSchema | JsonSchemaItem | undefined {
|
||||
try {
|
||||
let schema: JsonSchema | JsonSchemaItem = { type: schemaItem.type };
|
||||
|
||||
// 对于 null 类型,只设置 type 和 enable 属性
|
||||
|
@ -25,6 +26,7 @@ export function tableItemToJsonSchema(
|
|||
}
|
||||
|
||||
if (!isRoot) {
|
||||
// 非根节点,组装普通节点信息
|
||||
// 使用解构赋值和剩余参数来拷贝对象,同时排除 children、required、parent、id、title 属性
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { children, required, parent, id, title, ...copiedObject } = schemaItem;
|
||||
|
@ -39,6 +41,7 @@ export function tableItemToJsonSchema(
|
|||
|
||||
if (schemaItem.children && schemaItem.children.length > 0) {
|
||||
if (schemaItem.type === 'object') {
|
||||
// 对象类型
|
||||
schema = {
|
||||
type: 'object',
|
||||
enable: schemaItem.enable,
|
||||
|
@ -46,7 +49,7 @@ export function tableItemToJsonSchema(
|
|||
required: [],
|
||||
};
|
||||
schemaItem.children.forEach((child) => {
|
||||
const childSchema = tableItemToJsonSchema(child, false);
|
||||
const childSchema = parseTableDataToJsonSchema(child, false);
|
||||
schema.properties![child.title] = childSchema as JsonSchemaItem;
|
||||
if (child.required) {
|
||||
schema.required!.push(child.title);
|
||||
|
@ -56,15 +59,21 @@ export function tableItemToJsonSchema(
|
|||
delete schema.required;
|
||||
}
|
||||
} else if (schemaItem.type === 'array') {
|
||||
// 数组类型
|
||||
schema = {
|
||||
type: 'array',
|
||||
enable: schemaItem.enable,
|
||||
items: schemaItem.children.map((child) => tableItemToJsonSchema(child, false) as JsonSchemaItem),
|
||||
items: schemaItem.children.map((child) => parseTableDataToJsonSchema(child, false) as JsonSchemaItem),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return schema;
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -94,12 +103,13 @@ function createItem(key: string, value: any, parent?: JsonSchemaTableItem): Json
|
|||
parent,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 json 转换为 json-schema 表格组件的表格项
|
||||
* 将 json 转换为 json-schema 表格组件的数据结构
|
||||
* @param json json 字符串或对象或数组
|
||||
* @param parent 父级
|
||||
*/
|
||||
export function parseJsonToJsonSchemaTableItem(
|
||||
export function parseJsonToJsonSchemaTableData(
|
||||
json: string | object | Array<any>,
|
||||
parent?: JsonSchemaTableItem
|
||||
): { result: JsonSchemaTableItem[]; ids: Array<string> } {
|
||||
|
@ -125,7 +135,7 @@ export function parseJsonToJsonSchemaTableItem(
|
|||
example: '',
|
||||
defaultValue: '',
|
||||
};
|
||||
const children = parseJsonToJsonSchemaTableItem(json, rootItem);
|
||||
const children = parseJsonToJsonSchemaTableData(json, rootItem);
|
||||
rootItem.children = children.result;
|
||||
children.ids.push(rootItem.id);
|
||||
return { result: [rootItem], ids: children.ids };
|
||||
|
@ -140,7 +150,7 @@ export function parseJsonToJsonSchemaTableItem(
|
|||
Object.entries(json).forEach(([key, value]) => {
|
||||
const item: JsonSchemaTableItem = createItem(key, value, parent);
|
||||
if (typeof value === 'object' || Array.isArray(value)) {
|
||||
const children = parseJsonToJsonSchemaTableItem(value, item);
|
||||
const children = parseJsonToJsonSchemaTableData(value, item);
|
||||
item.children = children.result;
|
||||
ids.push(...children.ids);
|
||||
} else {
|
||||
|
@ -153,3 +163,76 @@ export function parseJsonToJsonSchemaTableItem(
|
|||
|
||||
return { result: items, ids };
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 json-schema 规范的结构转换为 json-schema 表格组件的数据结构
|
||||
* @param schema json-schema 规范的结构/字符串
|
||||
*/
|
||||
export function parseSchemaToJsonSchemaTableData(schema: string | JsonSchema): {
|
||||
result: JsonSchemaTableItem[];
|
||||
ids: Array<string>;
|
||||
} {
|
||||
const ids: Array<string> = ['root'];
|
||||
if (typeof schema === 'string') {
|
||||
// 尝试将 json 字符串转换为对象
|
||||
try {
|
||||
schema = JSON.parse(schema);
|
||||
} catch (error) {
|
||||
const { t } = useI18n();
|
||||
Message.warning(t('ms.json.schema.illegalJsonConvertFailed'));
|
||||
return { result: [], ids: [] };
|
||||
}
|
||||
}
|
||||
const parseNode = (
|
||||
node: JsonSchema | JsonSchemaItem,
|
||||
parent?: JsonSchemaTableItem,
|
||||
requiredFields?: string[]
|
||||
): JsonSchemaTableItem => {
|
||||
let item: JsonSchemaTableItem;
|
||||
|
||||
if (!parent) {
|
||||
// 根节点
|
||||
item = {
|
||||
id: 'root',
|
||||
title: 'root',
|
||||
type: node.type,
|
||||
description: node.description,
|
||||
enable: true,
|
||||
required: true,
|
||||
example: '',
|
||||
defaultValue: '',
|
||||
};
|
||||
} else {
|
||||
// 子孙节点
|
||||
// 剔除不需要的属性 properties、items
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { properties, items, ...copiedObj } = node;
|
||||
const itemId = getGenerateId();
|
||||
item = {
|
||||
...(copiedObj as JsonSchemaItem),
|
||||
id: itemId,
|
||||
required: requiredFields?.includes((node as JsonSchemaItem).title),
|
||||
enumValues: (node as JsonSchemaItem).enumValues?.join('\n'),
|
||||
parent,
|
||||
};
|
||||
if ((node as JsonSchemaItem).enable === true || (node as JsonSchemaItem).enable === undefined) {
|
||||
// 如果enable为true或者undefined,则设置为选中
|
||||
ids.push(itemId);
|
||||
}
|
||||
}
|
||||
|
||||
// 检查当前节点的required属性是否存在且为数组类型,然后传递当前节点的required属性给子节点判断是否必填
|
||||
const newRequiredFields = Array.isArray(node.required) ? node.required : undefined;
|
||||
|
||||
if ((node.type === 'object' && node.properties) || (node.type === 'array' && node.items)) {
|
||||
const children = node.type === 'object' ? node.properties : node.items;
|
||||
item.children = Object.entries(children || []).map(([key, childNode]) =>
|
||||
parseNode({ ...childNode, title: key }, item, newRequiredFields)
|
||||
);
|
||||
}
|
||||
return item;
|
||||
};
|
||||
|
||||
const result = [parseNode(schema as JsonSchema)];
|
||||
return { result, ids };
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Language } from '@/components/pure/ms-code-editor/types';
|
||||
import type { JsonSchemaItem } from '@/components/pure/ms-json-schema/types';
|
||||
import type { JsonSchema, JsonSchemaTableItem } from '@/components/pure/ms-json-schema/types';
|
||||
|
||||
import {
|
||||
type FullResponseAssertionType,
|
||||
|
@ -124,8 +124,10 @@ export interface ExecuteBinaryBody {
|
|||
export interface ExecuteJsonBody {
|
||||
enableJsonSchema?: boolean;
|
||||
enableTransition?: boolean;
|
||||
jsonSchema?: JsonSchemaItem[];
|
||||
jsonSchema?: JsonSchema;
|
||||
jsonValue: string;
|
||||
// 前端渲染字段
|
||||
jsonSchemaTableData?: JsonSchemaTableItem[];
|
||||
}
|
||||
// 执行请求配置
|
||||
export interface ExecuteOtherConfig {
|
||||
|
|
|
@ -89,8 +89,9 @@ export const defaultResponseItem: ResponseDefinition = {
|
|||
bodyType: ResponseBodyFormat.JSON,
|
||||
jsonBody: {
|
||||
jsonValue: '',
|
||||
enableJsonSchema: false,
|
||||
enableJsonSchema: true,
|
||||
enableTransition: false,
|
||||
jsonSchemaTableData: [],
|
||||
},
|
||||
xmlBody: {
|
||||
value: '',
|
||||
|
@ -117,6 +118,8 @@ export const defaultBodyParams: ExecuteBody = {
|
|||
},
|
||||
jsonBody: {
|
||||
jsonValue: '',
|
||||
enableJsonSchema: true,
|
||||
jsonSchemaTableData: [],
|
||||
},
|
||||
xmlBody: { value: '' },
|
||||
rawBody: { value: '' },
|
||||
|
@ -312,6 +315,8 @@ export const mockDefaultParams: MockParams = {
|
|||
},
|
||||
jsonBody: {
|
||||
jsonValue: '',
|
||||
enableJsonSchema: true,
|
||||
jsonSchemaTableData: [],
|
||||
},
|
||||
xmlBody: { value: '' },
|
||||
rawBody: { value: '' },
|
||||
|
@ -331,8 +336,9 @@ export const mockDefaultParams: MockParams = {
|
|||
bodyType: ResponseBodyFormat.JSON,
|
||||
jsonBody: {
|
||||
jsonValue: '',
|
||||
enableJsonSchema: false,
|
||||
enableJsonSchema: true,
|
||||
enableTransition: false,
|
||||
jsonSchemaTableData: [],
|
||||
},
|
||||
xmlBody: {
|
||||
value: '',
|
||||
|
|
|
@ -85,27 +85,35 @@
|
|||
</a-tooltip>
|
||||
</div> -->
|
||||
</div>
|
||||
<div v-else class="h-[calc(100%-34px)]">
|
||||
<a-spin v-else :loading="bodyLoading" class="block h-[calc(100%-34px)]">
|
||||
<div class="mb-[8px] flex items-center justify-between">
|
||||
<div class="flex items-center gap-[8px]">
|
||||
<MsButton
|
||||
type="text"
|
||||
class="!mr-0"
|
||||
:class="jsonType === 'Schema' ? 'font-medium !text-[rgb(var(--primary-5))]' : '!text-[var(--color-text-4)]'"
|
||||
@click="jsonType = 'Schema'"
|
||||
:class="
|
||||
innerParams.jsonBody.enableJsonSchema
|
||||
? 'font-medium !text-[rgb(var(--primary-5))]'
|
||||
: '!text-[var(--color-text-4)]'
|
||||
"
|
||||
@click="innerParams.jsonBody.enableJsonSchema = true"
|
||||
>Schema</MsButton
|
||||
>
|
||||
<a-divider :margin="0" direction="vertical"></a-divider>
|
||||
<MsButton
|
||||
type="text"
|
||||
class="!mr-0"
|
||||
:class="jsonType === 'Json' ? 'font-medium !text-[rgb(var(--primary-5))]' : '!text-[var(--color-text-4)]'"
|
||||
@click="jsonType = 'Json'"
|
||||
:class="
|
||||
!innerParams.jsonBody.enableJsonSchema
|
||||
? 'font-medium !text-[rgb(var(--primary-5))]'
|
||||
: '!text-[var(--color-text-4)]'
|
||||
"
|
||||
@click="innerParams.jsonBody.enableJsonSchema = false"
|
||||
>Json</MsButton
|
||||
>
|
||||
</div>
|
||||
<a-button
|
||||
v-show="jsonType === 'Schema'"
|
||||
v-show="innerParams.jsonBody.enableJsonSchema"
|
||||
type="outline"
|
||||
class="arco-btn-outline--secondary px-[8px]"
|
||||
size="small"
|
||||
|
@ -117,8 +125,14 @@
|
|||
</div>
|
||||
</a-button>
|
||||
</div>
|
||||
<MsJsonSchema
|
||||
v-if="innerParams.jsonBody.enableJsonSchema"
|
||||
ref="jsonSchemaRef"
|
||||
v-model:data="innerParams.jsonBody.jsonSchemaTableData"
|
||||
v-model:selectedKeys="selectedKeys"
|
||||
/>
|
||||
<MsCodeEditor
|
||||
v-if="jsonType === 'Json'"
|
||||
v-else
|
||||
v-model:model-value="currentBodyCode"
|
||||
:read-only="props.disabledExceptParam"
|
||||
theme="vs"
|
||||
|
@ -129,9 +143,13 @@
|
|||
:language="currentCodeLanguage"
|
||||
is-adaptive
|
||||
>
|
||||
<template #rightTitle>
|
||||
<a-button type="outline" class="arco-btn-outline--secondary p-[0_8px]" size="mini" @click="autoMakeJson">
|
||||
<div class="text-[var(--color-text-1)]">{{ t('apiTestManagement.autoMake') }}</div>
|
||||
</a-button>
|
||||
</template>
|
||||
</MsCodeEditor>
|
||||
<MsJsonSchema v-else ref="jsonSchemaRef" />
|
||||
</div>
|
||||
</a-spin>
|
||||
<batchAddKeyVal
|
||||
v-if="showParamTable"
|
||||
v-model:visible="batchAddKeyValVisible"
|
||||
|
@ -143,17 +161,19 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { TableColumnData } from '@arco-design/web-vue';
|
||||
import { Message, TableColumnData } from '@arco-design/web-vue';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsCodeEditor from '@/components/pure/ms-code-editor/index.vue';
|
||||
import { LanguageEnum } from '@/components/pure/ms-code-editor/types';
|
||||
import MsJsonSchema from '@/components/pure/ms-json-schema/index.vue';
|
||||
import { parseSchemaToJsonSchemaTableData, parseTableDataToJsonSchema } from '@/components/pure/ms-json-schema/utils';
|
||||
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 paramTable, { type ParamTableColumn } from '@/views/api-test/components/paramTable.vue';
|
||||
|
||||
import { convertJsonSchemaToJson } from '@/api/modules/api-test/management';
|
||||
import { requestBodyTypeMap } from '@/config/apiTest';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
|
@ -186,6 +206,9 @@
|
|||
const innerParams = defineModel<ExecuteBody>('params', {
|
||||
required: true,
|
||||
});
|
||||
const selectedKeys = ref<string[]>([]);
|
||||
const bodyLoading = ref(false);
|
||||
|
||||
const batchAddKeyValVisible = ref(false);
|
||||
const fileList = ref<MsFileItem[]>([]);
|
||||
|
||||
|
@ -202,6 +225,17 @@
|
|||
}
|
||||
);
|
||||
|
||||
watchEffect(() => {
|
||||
if (innerParams.value.jsonBody.jsonSchema) {
|
||||
const { result, ids } = parseSchemaToJsonSchemaTableData(innerParams.value.jsonBody.jsonSchema);
|
||||
innerParams.value.jsonBody.jsonSchemaTableData = result;
|
||||
selectedKeys.value = ids;
|
||||
} else {
|
||||
innerParams.value.jsonBody.jsonSchemaTableData = [];
|
||||
selectedKeys.value = [];
|
||||
}
|
||||
});
|
||||
|
||||
async function handleFileChange(files: MsFileItem[], file?: MsFileItem) {
|
||||
try {
|
||||
if (file?.local && file.file && props.uploadTempFileApi) {
|
||||
|
@ -320,15 +354,42 @@
|
|||
},
|
||||
});
|
||||
|
||||
const jsonType = ref<'Schema' | 'Json'>('Schema');
|
||||
const jsonSchemaRef = ref<InstanceType<typeof MsJsonSchema>>();
|
||||
|
||||
function previewJsonSchema() {
|
||||
if (jsonType.value === 'Schema') {
|
||||
if (innerParams.value.jsonBody.enableJsonSchema) {
|
||||
jsonSchemaRef.value?.previewSchema();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动转换json schema为json
|
||||
*/
|
||||
async function autoMakeJson() {
|
||||
if (!innerParams.value.jsonBody.enableJsonSchema) {
|
||||
try {
|
||||
bodyLoading.value = true;
|
||||
let schema = innerParams.value.jsonBody.jsonSchema;
|
||||
if (!schema && innerParams.value.jsonBody.jsonSchemaTableData) {
|
||||
// 若jsonSchema不存在,先将表格数据转换为 json schema格式
|
||||
schema = parseTableDataToJsonSchema(innerParams.value.jsonBody.jsonSchemaTableData[0]);
|
||||
}
|
||||
if (schema) {
|
||||
// 再将 json schema 转换为 json 格式
|
||||
const res = await convertJsonSchemaToJson(schema);
|
||||
innerParams.value.jsonBody.jsonValue = JSON.stringify(res);
|
||||
} else {
|
||||
Message.warning(t('apiTestManagement.pleaseInputJsonSchema'));
|
||||
}
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
} finally {
|
||||
bodyLoading.value = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 当前显示的代码
|
||||
const currentBodyCode = computed({
|
||||
get() {
|
||||
|
|
|
@ -432,6 +432,7 @@
|
|||
import { TabItem } from '@/components/pure/ms-editable-tab/types';
|
||||
import MsFormCreate from '@/components/pure/ms-form-create/formCreate.vue';
|
||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
import { parseTableDataToJsonSchema } from '@/components/pure/ms-json-schema/utils';
|
||||
import MsTab from '@/components/pure/ms-tab/index.vue';
|
||||
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
||||
import assertion from '@/components/business/ms-assertion/index.vue';
|
||||
|
@ -990,7 +991,7 @@
|
|||
*/
|
||||
function makeRequestParams(executeType?: 'localExec' | 'serverExec') {
|
||||
const isExecute = executeType === 'localExec' || executeType === 'serverExec';
|
||||
const { formDataBody, wwwFormBody } = requestVModel.value.body;
|
||||
const { formDataBody, wwwFormBody, jsonBody } = requestVModel.value.body;
|
||||
const polymorphicName = protocolOptions.value.find(
|
||||
(e) => e.value === requestVModel.value.protocol
|
||||
)?.polymorphicName; // 协议多态名称
|
||||
|
@ -1023,6 +1024,13 @@
|
|||
wwwFormBody: {
|
||||
formValues: realWwwFormBodyValues,
|
||||
},
|
||||
jsonBody: {
|
||||
jsonValue: jsonBody.jsonValue,
|
||||
enableJsonSchema: jsonBody.enableJsonSchema,
|
||||
jsonSchema: jsonBody.jsonSchemaTableData
|
||||
? parseTableDataToJsonSchema(jsonBody.jsonSchemaTableData[0])
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
headers: filterKeyValParams(requestVModel.value.headers, defaultHeaderParamsItem, isExecute).validParams,
|
||||
method: requestVModel.value.method,
|
||||
|
@ -1058,6 +1066,16 @@
|
|||
response: requestVModel.value.responseDefinition?.map((e) => ({
|
||||
...e,
|
||||
headers: filterKeyValParams(e.headers, defaultKeyValueParamItem, isExecute).validParams,
|
||||
body: {
|
||||
...e.body,
|
||||
jsonBody: {
|
||||
jsonValue: e.body.jsonBody.jsonValue,
|
||||
enableJsonSchema: jsonBody.enableJsonSchema,
|
||||
jsonSchema: e.body.jsonBody.jsonSchemaTableData
|
||||
? parseTableDataToJsonSchema(e.body.jsonBody.jsonSchemaTableData[0])
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
})),
|
||||
};
|
||||
} else {
|
||||
|
@ -1172,9 +1190,6 @@
|
|||
() => requestVModel.value.id,
|
||||
async () => {
|
||||
isSwitchingContent.value = true; // 正在切换内容
|
||||
nextTick(() => {
|
||||
isSwitchingContent.value = false; // 切换内容结束
|
||||
});
|
||||
if (requestVModel.value.protocol !== 'HTTP') {
|
||||
requestVModel.value.activeTab = RequestComposition.PLUGIN;
|
||||
if (protocolOptions.value.length === 0) {
|
||||
|
@ -1206,6 +1221,9 @@
|
|||
requestVModel.value.executeLoading = false;
|
||||
delete temporaryResponseMap[props.request.reportId];
|
||||
}
|
||||
nextTick(() => {
|
||||
isSwitchingContent.value = false; // 切换内容结束
|
||||
});
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
|
|
|
@ -96,20 +96,48 @@
|
|||
{{ ResponseBodyFormat[item].toLowerCase() }}
|
||||
</a-radio>
|
||||
</a-radio-group>
|
||||
<!-- <div v-if="activeResponse.body.bodyType === ResponseBodyFormat.JSON" class="ml-auto flex items-center">
|
||||
<a-radio-group
|
||||
v-model:model-value="activeResponse.body.jsonBody.enableJsonSchema"
|
||||
size="mini"
|
||||
@change="emit('change')"
|
||||
<div
|
||||
v-if="activeResponse.body.bodyType === ResponseBodyFormat.JSON"
|
||||
class="ml-auto flex items-center gap-[8px]"
|
||||
>
|
||||
<MsButton
|
||||
type="text"
|
||||
class="!mr-0"
|
||||
:class="
|
||||
activeResponse.body.jsonBody.enableJsonSchema
|
||||
? 'font-medium !text-[rgb(var(--primary-5))]'
|
||||
: '!text-[var(--color-text-4)]'
|
||||
"
|
||||
@click="activeResponse.body.jsonBody.enableJsonSchema = true"
|
||||
>
|
||||
Schema
|
||||
</MsButton>
|
||||
<a-divider :margin="0" direction="vertical"></a-divider>
|
||||
<MsButton
|
||||
type="text"
|
||||
class="!mr-0"
|
||||
:class="
|
||||
!activeResponse.body.jsonBody.enableJsonSchema
|
||||
? 'font-medium !text-[rgb(var(--primary-5))]'
|
||||
: '!text-[var(--color-text-4)]'
|
||||
"
|
||||
@click="activeResponse.body.jsonBody.enableJsonSchema = false"
|
||||
>
|
||||
Json
|
||||
</MsButton>
|
||||
<a-button
|
||||
v-show="activeResponse.body.jsonBody.enableJsonSchema"
|
||||
type="outline"
|
||||
class="arco-btn-outline--secondary ml-[16px] px-[8px]"
|
||||
size="small"
|
||||
@click="previewJsonSchema"
|
||||
>
|
||||
<a-radio :value="false">Json</a-radio>
|
||||
<a-radio class="mr-0" :value="true"> Json Schema </a-radio>
|
||||
</a-radio-group>
|
||||
<div class="flex items-center gap-[8px]">
|
||||
<a-switch v-model:model-value="activeResponse.body.jsonBody.enableTransition" size="small" type="line" />
|
||||
{{ t('apiTestManagement.dynamicConversion') }}
|
||||
<icon-eye />
|
||||
{{ t('common.preview') }}
|
||||
</div>
|
||||
</a-button>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
|
@ -118,12 +146,14 @@
|
|||
)
|
||||
"
|
||||
>
|
||||
<!-- <MsJsonSchema
|
||||
<MsJsonSchema
|
||||
v-if="activeResponse.body.jsonBody.enableJsonSchema"
|
||||
:data="activeResponse.body.jsonBody.jsonSchema"
|
||||
:columns="jsonSchemaColumns"
|
||||
/> -->
|
||||
ref="jsonSchemaRef"
|
||||
v-model:data="activeResponse.body.jsonBody.jsonSchemaTableData"
|
||||
v-model:selectedKeys="selectedKeys"
|
||||
/>
|
||||
<MsCodeEditor
|
||||
v-else
|
||||
ref="responseEditorRef"
|
||||
v-model:model-value="currentBodyCode"
|
||||
:language="currentCodeLanguage"
|
||||
|
@ -134,6 +164,11 @@
|
|||
:show-charset-change="false"
|
||||
show-code-format
|
||||
>
|
||||
<template #rightTitle>
|
||||
<a-button type="outline" class="arco-btn-outline--secondary p-[0_8px]" size="mini" @click="autoMakeJson">
|
||||
<div class="text-[var(--color-text-1)]">{{ t('apiTestManagement.autoMake') }}</div>
|
||||
</a-button>
|
||||
</template>
|
||||
</MsCodeEditor>
|
||||
</div>
|
||||
<div v-else>
|
||||
|
@ -194,14 +229,16 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsCodeEditor from '@/components/pure/ms-code-editor/index.vue';
|
||||
import { LanguageEnum } from '@/components/pure/ms-code-editor/types';
|
||||
import MsEditableTab from '@/components/pure/ms-editable-tab/index.vue';
|
||||
import { TabItem } from '@/components/pure/ms-editable-tab/types';
|
||||
// import { FormTableColumn } from '@/components/pure/ms-form-table/index.vue';
|
||||
// import MsJsonSchema from '@/components/pure/ms-json-schema/index.vue';
|
||||
import MsJsonSchema from '@/components/pure/ms-json-schema/index.vue';
|
||||
import { parseSchemaToJsonSchemaTableData, parseTableDataToJsonSchema } from '@/components/pure/ms-json-schema/utils';
|
||||
import MsMoreAction from '@/components/pure/ms-table-more-action/index.vue';
|
||||
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||
import { MsFileItem } from '@/components/pure/ms-upload/types';
|
||||
|
@ -209,6 +246,7 @@
|
|||
import paramTable, { ParamTableColumn } from '@/views/api-test/components/paramTable.vue';
|
||||
import popConfirm from '@/views/api-test/components/popConfirm.vue';
|
||||
|
||||
import { convertJsonSchemaToJson } from '@/api/modules/api-test/management';
|
||||
import { responseHeaderOption } from '@/config/apiTest';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
|
@ -350,20 +388,54 @@
|
|||
emit('change');
|
||||
}
|
||||
|
||||
// const jsonSchemaColumns: FormTableColumn[] = [
|
||||
// {
|
||||
// title: 'apiTestManagement.paramName',
|
||||
// dataIndex: 'key',
|
||||
// slotName: 'key',
|
||||
// inputType: 'input',
|
||||
// },
|
||||
// {
|
||||
// title: 'apiTestManagement.paramVal',
|
||||
// dataIndex: 'value',
|
||||
// slotName: 'value',
|
||||
// inputType: 'input',
|
||||
// },
|
||||
// ];
|
||||
const jsonSchemaRef = ref<InstanceType<typeof MsJsonSchema>>();
|
||||
const bodyLoading = ref(false);
|
||||
const selectedKeys = ref<string[]>([]);
|
||||
|
||||
watchEffect(() => {
|
||||
if (activeResponse.value.body.jsonBody.jsonSchema) {
|
||||
const { result, ids } = parseSchemaToJsonSchemaTableData(activeResponse.value.body.jsonBody.jsonSchema);
|
||||
activeResponse.value.body.jsonBody.jsonSchemaTableData = result;
|
||||
selectedKeys.value = ids;
|
||||
} else {
|
||||
activeResponse.value.body.jsonBody.jsonSchemaTableData = [];
|
||||
selectedKeys.value = [];
|
||||
}
|
||||
});
|
||||
|
||||
function previewJsonSchema() {
|
||||
if (activeResponse.value.body.jsonBody.enableJsonSchema) {
|
||||
jsonSchemaRef.value?.previewSchema();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动转换json schema为json
|
||||
*/
|
||||
async function autoMakeJson() {
|
||||
if (!activeResponse.value.body.jsonBody.enableJsonSchema) {
|
||||
try {
|
||||
bodyLoading.value = true;
|
||||
let schema = activeResponse.value.body.jsonBody.jsonSchema;
|
||||
if (!schema && activeResponse.value.body.jsonBody.jsonSchemaTableData) {
|
||||
// 若jsonSchema不存在,先将表格数据转换为 json schema格式
|
||||
schema = parseTableDataToJsonSchema(activeResponse.value.body.jsonBody.jsonSchemaTableData[0]);
|
||||
}
|
||||
if (schema) {
|
||||
// 再将 json schema 转换为 json 格式
|
||||
const res = await convertJsonSchemaToJson(schema);
|
||||
activeResponse.value.body.jsonBody.jsonValue = JSON.stringify(res);
|
||||
} else {
|
||||
Message.warning(t('apiTestManagement.pleaseInputJsonSchema'));
|
||||
}
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
} finally {
|
||||
bodyLoading.value = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 当前显示的代码
|
||||
const currentBodyCode = computed({
|
||||
|
|
|
@ -183,8 +183,9 @@
|
|||
if (!item.body.jsonBody) {
|
||||
item.body.jsonBody = {
|
||||
jsonValue: '',
|
||||
enableJsonSchema: false,
|
||||
enableJsonSchema: true,
|
||||
enableTransition: false,
|
||||
jsonSchemaTableData: [],
|
||||
};
|
||||
if (!item.body.xmlBody) {
|
||||
item.body.xmlBody = {
|
||||
|
|
|
@ -166,6 +166,8 @@ export default {
|
|||
'apiTestManagement.regex': 'Regular Expression',
|
||||
'apiTestManagement.caseTotal': 'Case total',
|
||||
'apiTestManagement.requestTypeTip': 'Note: Batch request type changes apply only to HTTP requests.',
|
||||
'apiTestManagement.autoMake': 'Auto Generate',
|
||||
'apiTestManagement.pleaseInputJsonSchema': 'Please enter Schema first before automatically generating it.',
|
||||
'case.execute.selectEnv': 'Select Environment',
|
||||
'case.execute.defaultEnv': 'Default Environment',
|
||||
'case.execute.newEnv': 'New Environment',
|
||||
|
|
|
@ -159,6 +159,8 @@ export default {
|
|||
'apiTestManagement.regex': '正则表达式',
|
||||
'apiTestManagement.caseTotal': '用例数',
|
||||
'apiTestManagement.requestTypeTip': '注:批量修改请求类型仅对HTTP协议的请求生效',
|
||||
'apiTestManagement.autoMake': '自动生成',
|
||||
'apiTestManagement.pleaseInputJsonSchema': '请先输入 Schema 后再进行自动生成',
|
||||
'case.execute.selectEnv': '环境选择',
|
||||
'case.execute.defaultEnv': '默认环境',
|
||||
'case.execute.newEnv': '新环境',
|
||||
|
|
Loading…
Reference in New Issue