feat(接口测试): json-schema功能补充&批量添加参数问题修复

This commit is contained in:
baiqi 2024-07-12 18:18:46 +08:00 committed by 刘瑞斌
parent 5b01adde1c
commit 0619578403
9 changed files with 83 additions and 33 deletions

View File

@ -38,7 +38,7 @@
label=""
:rules="{
validator: (value, callback) => {
validRepeat(rowIndex, item.dataIndex as string, value, callback);
validRepeat(rowIndex, item.dataIndex as string, record[item.dataIndex as string], record, callback);
},
}"
:disabled="props.disabled || item.disabled || record.disabled"
@ -354,17 +354,31 @@
//
const formRef = ref<FormInstance>();
async function validRepeat(rowIndex: number, dataIndex: string, value: any, callback: (error?: string) => void) {
async function validRepeat(
rowIndex: number,
dataIndex: string,
value: any,
record: Record<string, any>,
callback: (error?: string) => void
) {
const currentColumn = props.columns.find((item) => item.dataIndex === dataIndex);
if (!currentColumn?.needValidRepeat) {
callback();
return;
}
propsRes.value.data?.forEach((row, index) => {
if (row[dataIndex].length && index !== rowIndex && row[dataIndex] === value) {
callback(`${t(currentColumn?.title as string)}${t('msFormTable.paramRepeatMessage')}`);
}
});
if (record.parent) {
(record.parent.children as Record<string, any>[])?.forEach((row, index) => {
if (row[dataIndex].length && index !== rowIndex && row[dataIndex] === value) {
callback(`${t(currentColumn?.title as string)}${t('msFormTable.paramRepeatMessage')}`);
}
});
} else {
propsRes.value.data?.forEach((row, index) => {
if (row[dataIndex].length && index !== rowIndex && row[dataIndex] === value) {
callback(`${t(currentColumn?.title as string)}${t('msFormTable.paramRepeatMessage')}`);
}
});
}
callback();
}

View File

@ -6,12 +6,7 @@
:columns="columns"
show-empty-tree
:selectable="false"
:row-selection="{
type: 'checkbox',
showCheckedAll: true,
checkStrictly: true,
width: 32,
}"
:row-selection="rowSelection"
:table-key="TableKeyEnum.JSON_SCHEMA"
:scroll="{ x: 'max-content' }"
:disabled="props.disabled"
@ -521,7 +516,7 @@
</template>
<script setup lang="ts">
import { SelectOptionData, TableData } from '@arco-design/web-vue';
import { SelectOptionData, TableData, TableRowSelection } from '@arco-design/web-vue';
import { cloneDeep } from 'lodash-es';
import MsButton from '@/components/pure/ms-button/index.vue';
@ -578,6 +573,17 @@
default: () => ['root'],
});
const rowSelection = computed<TableRowSelection | undefined>(() => {
if (props.disabled) {
return undefined;
}
return {
type: 'checkbox',
showCheckedAll: true,
checkStrictly: true,
width: 32,
};
});
//
watchEffect(() => {
if (data.value.length === 0) {
@ -676,6 +682,7 @@
size: 'medium',
columnSelectorDisabled: true,
fixed: 'left',
needValidRepeat: true,
},
{
title: t('ms.json.schema.type'),
@ -866,6 +873,7 @@
if (!selectedKeys.value.includes(child.id)) {
selectedKeys.value.push(child.id);
}
data.value = [...data.value];
}
/**

View File

@ -11,10 +11,11 @@ import type { JsonSchema, JsonSchemaItem, JsonSchemaTableItem } from './types';
* @param isRoot
*/
export function parseTableDataToJsonSchema(
schemaItem: JsonSchemaTableItem,
schemaItem?: JsonSchemaTableItem,
isRoot: boolean = true
): JsonSchema | JsonSchemaItem | undefined {
try {
if (!schemaItem) return undefined;
let schema: JsonSchema | JsonSchemaItem = { type: schemaItem.type };
// 对于 null 类型,只设置 type 和 enable 属性
@ -84,7 +85,10 @@ export function parseTableDataToJsonSchema(
*/
function createItem(key: string, value: any, parent?: JsonSchemaTableItem): JsonSchemaTableItem {
let exampleValue; // 默认情况下example 值为 undefined
const itemType = Array.isArray(value) ? 'array' : typeof value;
let itemType = Array.isArray(value) ? 'array' : typeof value;
if (value === null) {
itemType = 'null';
}
// 如果值不是对象或数组,则直接将值作为 example
if (itemType !== 'object' && itemType !== 'array') {
@ -110,7 +114,7 @@ function createItem(key: string, value: any, parent?: JsonSchemaTableItem): Json
* @param parent
*/
export function parseJsonToJsonSchemaTableData(
json: string | object | Array<any>,
json: string | object | Array<any> | null,
parent?: JsonSchemaTableItem
): { result: JsonSchemaTableItem[]; ids: Array<string> } {
if (typeof json === 'string') {
@ -145,11 +149,11 @@ export function parseJsonToJsonSchemaTableData(
const type = Array.isArray(json) ? 'array' : 'object';
const ids: Array<string> = [];
if (type === 'object' || type === 'array') {
if ((type === 'object' || type === 'array') && json !== null) {
// 遍历对象或数组
Object.entries(json).forEach(([key, value]) => {
const item: JsonSchemaTableItem = createItem(key, value, parent);
if (typeof value === 'object' || Array.isArray(value)) {
if ((typeof value === 'object' && value !== null) || Array.isArray(value)) {
const children = parseJsonToJsonSchemaTableData(value, item);
item.children = children.result;
ids.push(...children.ids);

View File

@ -71,6 +71,7 @@
disabled?: boolean;
typeTitle?: string;
hasStandard?: boolean; //
acceptTypes?: RequestParamsType[]; //
}>(),
{
noParamType: false,
@ -179,7 +180,9 @@
id: getGenerateId(),
...cloneDeep(props.defaultParamItem), //
key: key.trim(),
paramType: Object.values(RequestParamsType).includes(type?.trim() as unknown as RequestParamsType)
paramType: (props.acceptTypes || Object.values(RequestParamsType)).includes(
type?.trim() as unknown as RequestParamsType
)
? type?.trim()
: RequestParamsType.STRING,
required: stringToBoolean(required),

View File

@ -86,7 +86,7 @@
</div> -->
</div>
<a-spin v-else :loading="bodyLoading" class="block h-[calc(100%-34px)]">
<div class="mb-[8px] flex items-center justify-between">
<div v-if="innerParams.bodyType === RequestBodyFormat.JSON" class="mb-[8px] flex items-center justify-between">
<div class="flex items-center gap-[8px]">
<MsButton
type="text"
@ -126,7 +126,7 @@
</a-button>
</div>
<MsJsonSchema
v-if="innerParams.jsonBody.enableJsonSchema"
v-if="innerParams.jsonBody.enableJsonSchema && innerParams.bodyType === RequestBodyFormat.JSON"
ref="jsonSchemaRef"
v-model:data="innerParams.jsonBody.jsonSchemaTableData"
v-model:selectedKeys="innerParams.jsonBody.jsonSchemaTableSelectedRowKeys"
@ -140,16 +140,17 @@
height="100%"
:show-full-screen="false"
:show-theme-change="false"
:show-code-format="true"
:show-code-format="!(props.disabledExceptParam || props.disabledParamValue)"
:language="currentCodeLanguage"
is-adaptive
>
<template #rightTitle>
<a-button
v-if="innerParams.bodyType === RequestBodyFormat.JSON"
type="outline"
class="arco-btn-outline--secondary p-[0_8px]"
size="mini"
:disabled="props.disabledParamValue"
:disabled="props.disabledExceptParam || props.disabledParamValue"
@click="autoMakeJson"
>
<div class="text-[var(--color-text-1)]">{{ t('apiTestManagement.autoMake') }}</div>
@ -163,6 +164,7 @@
:disabled="props.disabledExceptParam"
:params="currentTableParams"
:default-param-item="defaultBodyParamsItem"
:accept-types="innerParams.bodyType === RequestBodyFormat.WWW_FORM ? wwwFormParamsTypes : undefined"
has-standard
@apply="handleBatchParamApply"
/>
@ -432,6 +434,9 @@
return LanguageEnum.PLAINTEXT;
});
const wwwFormParamsTypes = Object.values(RequestParamsType).filter(
(val) => ![RequestParamsType.JSON, RequestParamsType.FILE].includes(val)
);
/**
* 批量参数代码转换为参数表格数据
*/

View File

@ -28,6 +28,7 @@
:params="innerParams"
:disabled="props.disabledExceptParam"
:default-param-item="defaultRequestParamsItem"
:accept-types="queryParamsTypes"
has-standard
@apply="handleBatchParamApply"
/>
@ -62,6 +63,9 @@
const { t } = useI18n();
const innerParams = useVModel(props, 'params', emit);
const queryParamsTypes = Object.values(RequestParamsType).filter(
(val) => ![RequestParamsType.JSON, RequestParamsType.FILE].includes(val)
);
const columns = computed<ParamTableColumn[]>(() => [
{
title: 'apiTestDebug.paramName',
@ -74,12 +78,10 @@
dataIndex: 'paramType',
slotName: 'paramType',
hasRequired: true,
options: Object.values(RequestParamsType)
.filter((val) => ![RequestParamsType.JSON, RequestParamsType.FILE].includes(val))
.map((val) => ({
label: val,
value: val,
})),
options: queryParamsTypes.map((val) => ({
label: val,
value: val,
})),
width: 120,
},
{

View File

@ -147,7 +147,9 @@
"
>
<MsJsonSchema
v-if="activeResponse.body.jsonBody.enableJsonSchema"
v-if="
activeResponse.body.jsonBody.enableJsonSchema && activeResponse.body.bodyType === ResponseBodyFormat.JSON
"
ref="jsonSchemaRef"
v-model:data="activeResponse.body.jsonBody.jsonSchemaTableData"
v-model:selectedKeys="selectedKeys"
@ -165,7 +167,13 @@
show-code-format
>
<template #rightTitle>
<a-button type="outline" class="arco-btn-outline--secondary p-[0_8px]" size="mini" @click="autoMakeJson">
<a-button
v-if="activeResponse.body.bodyType === ResponseBodyFormat.JSON"
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>

View File

@ -28,6 +28,7 @@
:params="innerParams"
:disabled="props.disabledExceptParam"
:default-param-item="defaultRequestParamsItem"
:accept-types="restParamsTypes"
has-standard
@apply="handleBatchParamApply"
/>
@ -62,7 +63,9 @@
const { t } = useI18n();
const innerParams = useVModel(props, 'params', emit);
const restParamsTypes = Object.values(RequestParamsType).filter(
(val) => ![RequestParamsType.JSON, RequestParamsType.FILE].includes(val)
);
const columns = computed<ParamTableColumn[]>(() => [
{
title: 'apiTestDebug.paramName',

View File

@ -818,4 +818,7 @@
box-shadow: 0 0 7px 0 rgb(15 0 78 / 9%);
}
}
:deep(.arco-table-td-content) {
padding: 5px 8px;
}
</style>