feat(json-schema): ms-json-schema组件-json预览接口&json导入

This commit is contained in:
baiqi 2024-07-03 18:29:57 +08:00 committed by 刘瑞斌
parent d37fe74580
commit 2fc5db0745
8 changed files with 172 additions and 28 deletions

View File

@ -1,3 +1,5 @@
import type { JsonSchema } from '@/components/pure/ms-json-schema/types';
import MSR from '@/api/http/index'; import MSR from '@/api/http/index';
import { import {
AddCaseUrl, AddCaseUrl,
@ -19,6 +21,7 @@ import {
BatchUpdateDefinitionUrl, BatchUpdateDefinitionUrl,
CasePageUrl, CasePageUrl,
CheckDefinitionScheduleUrl, CheckDefinitionScheduleUrl,
ConvertJsonSchemaToJsonUrl,
CopyMockUrl, CopyMockUrl,
DebugCaseUrl, DebugCaseUrl,
DebugDefinitionUrl, DebugDefinitionUrl,
@ -298,6 +301,11 @@ export function getDefinitionReference(data: DefinitionReferencePageParams) {
return MSR.post({ url: DefinitionReferenceUrl, data }); return MSR.post({ url: DefinitionReferenceUrl, data });
} }
// 将json-schema转换为 json 数据
export function convertJsonSchemaToJson(data: JsonSchema) {
return MSR.post({ url: ConvertJsonSchemaToJsonUrl, data });
}
/** /**
* Mock * Mock
*/ */

View File

@ -35,6 +35,7 @@ export const OperationHistoryUrl = '/api/definition/operation-history'; // 接
export const SaveOperationHistoryUrl = '/api/definition/operation-history/save'; // 接口定义-另存变更历史为指定版本 export const SaveOperationHistoryUrl = '/api/definition/operation-history/save'; // 接口定义-另存变更历史为指定版本
export const RecoverOperationHistoryUrl = '/api/definition/operation-history/recover'; // 接口定义-变更历史恢复 export const RecoverOperationHistoryUrl = '/api/definition/operation-history/recover'; // 接口定义-变更历史恢复
export const DefinitionReferenceUrl = '/api/definition/get-reference'; // 获取接口引用关系 export const DefinitionReferenceUrl = '/api/definition/get-reference'; // 获取接口引用关系
export const ConvertJsonSchemaToJsonUrl = '/api/definition/preview'; // 将json-schema转换为 json 数据
/** /**
* Mock * Mock

View File

@ -363,7 +363,11 @@
}); });
const disabledPopover = computed(() => { const disabledPopover = computed(() => {
return !innerValue.value || innerValue.value.trim() === '' || isFocusAutoComplete.value; return (
!innerValue.value ||
(typeof innerValue.value === 'string' && innerValue.value.trim() === '') ||
isFocusAutoComplete.value
);
}); });
const paramSettingVisible = ref(false); const paramSettingVisible = ref(false);

View File

@ -421,7 +421,7 @@
<div> <div>
<div class="mb-[8px]">{{ t('ms.json.schema.preview') }}</div> <div class="mb-[8px]">{{ t('ms.json.schema.preview') }}</div>
<MsCodeEditor <MsCodeEditor
v-model:model-value="activePreviewValue" v-model:model-value="activePreviewJsonSchemaValue"
theme="vs" theme="vs"
height="500px" height="500px"
:show-full-screen="false" :show-full-screen="false"
@ -447,9 +447,9 @@
:show-full-screen="false" :show-full-screen="false"
> >
<template #leftTitle> <template #leftTitle>
<a-radio-group default-value="json" type="button" @change="batchAddValue = ''"> <a-radio-group v-model:model-value="batchAddType" type="button" @change="batchAddValue = ''">
<a-radio value="json">Json</a-radio> <a-radio value="json">Json</a-radio>
<a-radio value="jsonSchema">JsonSchema</a-radio> <a-radio value="schema">JsonSchema</a-radio>
</a-radio-group> </a-radio-group>
</template> </template>
<template #rightTitle> <template #rightTitle>
@ -462,14 +462,23 @@
</MsCodeEditor> </MsCodeEditor>
</MsDrawer> </MsDrawer>
<MsDrawer v-model:visible="previewDrawerVisible" :width="600" :title="t('common.preview')" :footer="false"> <MsDrawer v-model:visible="previewDrawerVisible" :width="600" :title="t('common.preview')" :footer="false">
<MsCodeEditor <a-spin class="block" :loading="previewDrawerLoading">
v-model:model-value="activePreviewValue" <MsCodeEditor
theme="vs" v-model:model-value="activePreviewValue"
height="100%" theme="vs"
:language="LanguageEnum.JSON" height="100%"
:show-full-screen="false" :language="LanguageEnum.JSON"
read-only :show-full-screen="false"
/> read-only
>
<template #leftTitle>
<a-radio-group v-model:model-value="previewShowType" type="button" @change="batchAddValue = ''">
<a-radio value="json">Json</a-radio>
<a-radio value="schema">JsonSchema</a-radio>
</a-radio-group>
</template>
</MsCodeEditor>
</a-spin>
</MsDrawer> </MsDrawer>
</template> </template>
@ -485,13 +494,14 @@
import MsParamsInput from '@/components/business/ms-params-input/index.vue'; import MsParamsInput from '@/components/business/ms-params-input/index.vue';
import MsQuickInput from '@/components/business/ms-quick-input/index.vue'; import MsQuickInput from '@/components/business/ms-quick-input/index.vue';
import { convertJsonSchemaToJson } from '@/api/modules/api-test/management';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import { getGenerateId, traverseTree } from '@/utils'; import { getGenerateId, traverseTree } from '@/utils';
import { TableKeyEnum } from '@/enums/tableEnum'; import { TableKeyEnum } from '@/enums/tableEnum';
import { JsonSchemaTableItem } from './types'; import { JsonSchema, JsonSchemaTableItem } from './types';
import { convertToJsonSchema } from './utils'; import { parseJsonToJsonSchemaTableItem, tableItemToJsonSchema } from './utils';
const { t } = useI18n(); const { t } = useI18n();
@ -828,38 +838,52 @@
const batchAddDrawerVisible = ref(false); const batchAddDrawerVisible = ref(false);
const batchAddValue = ref(''); const batchAddValue = ref('');
const batchAddType = ref<'json' | 'schema'>('json');
function batchAdd() { function batchAdd() {
batchAddDrawerVisible.value = true; batchAddDrawerVisible.value = true;
} }
function applyBatchAdd() { function applyBatchAdd() {
if (batchAddType.value === 'json') {
const res = parseJsonToJsonSchemaTableItem(batchAddValue.value);
if (res.result.length > 0) {
data.value = res.result;
selectedKeys.value = res.ids;
}
}
batchAddDrawerVisible.value = false; batchAddDrawerVisible.value = false;
} }
const settingDrawerVisible = ref(false); const settingDrawerVisible = ref(false);
const activeRecord = ref<any>({}); const activeRecord = ref<any>({});
const activePreviewValue = ref(''); const previewShowType = ref<'json' | 'schema'>('json');
const activePreviewJsonValue = ref('');
const activePreviewJsonSchemaValue = ref('');
const activePreviewValue = computed(() => {
return previewShowType.value === 'json' ? activePreviewJsonValue.value : activePreviewJsonSchemaValue.value;
});
function openSetting(record: JsonSchemaTableItem) { async function openSetting(record: JsonSchemaTableItem) {
// parent children // parent children
activeRecord.value = { activeRecord.value = {
...record, ...record,
}; };
try { try {
activePreviewValue.value = JSON.stringify(convertToJsonSchema(record, record.id === 'root')); const schema = tableItemToJsonSchema(record, record.id === 'root');
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);
activePreviewValue.value = t('ms.json.schema.convertFailed'); activePreviewJsonSchemaValue.value = t('ms.json.schema.convertFailed');
} finally { } finally {
settingDrawerVisible.value = true; settingDrawerVisible.value = true;
} }
} }
function handleSettingFormChange() { function handleSettingFormChange() {
activePreviewValue.value = JSON.stringify( activePreviewJsonSchemaValue.value = JSON.stringify(
convertToJsonSchema(activeRecord.value, activeRecord.value.id === 'root') tableItemToJsonSchema(activeRecord.value, activeRecord.value.id === 'root')
); );
} }
@ -901,9 +925,24 @@
} }
const previewDrawerVisible = ref(false); const previewDrawerVisible = ref(false);
function previewSchema() { const previewDrawerLoading = ref(false);
async function previewSchema() {
previewDrawerVisible.value = true; previewDrawerVisible.value = true;
activePreviewValue.value = JSON.stringify(convertToJsonSchema(data.value[0])); try {
previewDrawerLoading.value = true;
const schema = tableItemToJsonSchema(data.value[0]);
const res = await convertJsonSchemaToJson(schema as JsonSchema);
activePreviewJsonValue.value = JSON.stringify(res);
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');
} finally {
previewDrawerLoading.value = false;
}
} }
defineExpose({ defineExpose({

View File

@ -21,4 +21,5 @@ export default {
'ms.json.schema.convertFailed': '数据转换失败,请重试', 'ms.json.schema.convertFailed': '数据转换失败,请重试',
'ms.json.schema.minItems': '最小元素数量', 'ms.json.schema.minItems': '最小元素数量',
'ms.json.schema.maxItems': '最大元素数量', 'ms.json.schema.maxItems': '最大元素数量',
'ms.json.schema.illegalJsonConvertFailed': '转换失败请检查输入的json 结构是否合法',
}; };

View File

@ -17,7 +17,7 @@ export interface JsonSchemaCommon {
} }
// json-schema 表格组件的表格项 // json-schema 表格组件的表格项
export interface JsonSchemaTableItem extends JsonSchemaCommon { export interface JsonSchemaTableItem extends JsonSchemaCommon {
required?: string[]; // 是否必填 required?: boolean; // 是否必填
children?: JsonSchemaTableItem[]; children?: JsonSchemaTableItem[];
parent?: JsonSchemaTableItem; // 父级 parent?: JsonSchemaTableItem; // 父级
enumValues?: string; // 参数值的枚举 enumValues?: string; // 参数值的枚举

View File

@ -1,3 +1,8 @@
import { Message } from '@arco-design/web-vue';
import { useI18n } from '@/hooks/useI18n';
import { getGenerateId } from '@/utils';
import type { JsonSchema, JsonSchemaItem, JsonSchemaTableItem } from './types'; import type { JsonSchema, JsonSchemaItem, JsonSchemaTableItem } from './types';
/** /**
@ -5,7 +10,7 @@ import type { JsonSchema, JsonSchemaItem, JsonSchemaTableItem } from './types';
* @param schemaItem * @param schemaItem
* @param isRoot * @param isRoot
*/ */
export function convertToJsonSchema( export function tableItemToJsonSchema(
schemaItem: JsonSchemaTableItem, schemaItem: JsonSchemaTableItem,
isRoot: boolean = true isRoot: boolean = true
): JsonSchema | JsonSchemaItem { ): JsonSchema | JsonSchemaItem {
@ -41,7 +46,7 @@ export function convertToJsonSchema(
required: [], required: [],
}; };
schemaItem.children.forEach((child) => { schemaItem.children.forEach((child) => {
const childSchema = convertToJsonSchema(child, false); const childSchema = tableItemToJsonSchema(child, false);
schema.properties![child.title] = childSchema as JsonSchemaItem; schema.properties![child.title] = childSchema as JsonSchemaItem;
if (child.required) { if (child.required) {
schema.required!.push(child.title); schema.required!.push(child.title);
@ -54,11 +59,97 @@ export function convertToJsonSchema(
schema = { schema = {
type: 'array', type: 'array',
enable: schemaItem.enable, enable: schemaItem.enable,
items: schemaItem.children.map((child) => convertToJsonSchema(child, false) as JsonSchemaItem), items: schemaItem.children.map((child) => tableItemToJsonSchema(child, false) as JsonSchemaItem),
}; };
} }
} }
return schema; return schema;
} }
export default {};
/**
* json-schema
* @param key // key名
* @param value //
* @param parent
*/
function createItem(key: string, value: any, parent?: JsonSchemaTableItem): JsonSchemaTableItem {
let exampleValue; // 默认情况下example 值为 undefined
const itemType = Array.isArray(value) ? 'array' : typeof value;
// 如果值不是对象或数组,则直接将值作为 example
if (itemType !== 'object' && itemType !== 'array') {
exampleValue = typeof value === 'boolean' ? value.toString() : value;
}
return {
id: getGenerateId(),
title: key,
type: itemType,
description: '',
enable: true,
required: true,
defaultValue: '',
example: exampleValue, // 仅当值不是对象或数组时,才赋予 example 值
parent,
};
}
/**
* json json-schema
* @param json json
* @param parent
*/
export function parseJsonToJsonSchemaTableItem(
json: string | object | Array<any>,
parent?: JsonSchemaTableItem
): { result: JsonSchemaTableItem[]; ids: Array<string> } {
if (typeof json === 'string') {
// 尝试将 json 字符串转换为对象
try {
json = JSON.parse(json);
} catch (error) {
const { t } = useI18n();
Message.warning(t('ms.json.schema.illegalJsonConvertFailed'));
return { result: [], ids: [] };
}
}
if (!parent) {
// 创建根节点
const rootItem: JsonSchemaTableItem = {
id: 'root',
title: 'root',
type: Array.isArray(json) ? 'array' : 'object',
description: '',
enable: true,
required: true,
example: '',
defaultValue: '',
};
const children = parseJsonToJsonSchemaTableItem(json, rootItem);
rootItem.children = children.result;
children.ids.push(rootItem.id);
return { result: [rootItem], ids: children.ids };
}
const items: JsonSchemaTableItem[] = [];
const type = Array.isArray(json) ? 'array' : 'object';
const ids: Array<string> = [];
if (type === 'object' || type === 'array') {
// 遍历对象或数组
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);
item.children = children.result;
ids.push(...children.ids);
} else {
item.example = typeof value === 'boolean' ? value.toString() : value;
}
items.push(item);
ids.push(item.id);
});
}
return { result: items, ids };
}

View File

@ -276,7 +276,7 @@
}; };
} }
return { return {
height: 'calc(100vh - 298px)', height: 'calc(100vh - 250px)',
threshold: 200, threshold: 200,
fixedSize: true, fixedSize: true,
buffer: 15, // 10 padding buffer: 15, // 10 padding