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