feat(接口管理): 接口定义优化
This commit is contained in:
parent
2b8cdc5359
commit
1d0ef9a28a
|
@ -14,7 +14,7 @@
|
|||
:columns="jsonPathColumns"
|
||||
:scroll="{ minWidth: '700px' }"
|
||||
:default-param-item="jsonPathDefaultParamItem"
|
||||
@change="(data, isInit) => handleChange(data, !!isInit, 'jsonPath')"
|
||||
@change="(data) => handleChange(data, 'jsonPath')"
|
||||
@more-action-select="(e,r)=> handleExtractParamMoreActionSelect(e,r as ExpressionConfig)"
|
||||
>
|
||||
<template #expression="{ record, rowIndex }">
|
||||
|
@ -99,7 +99,7 @@
|
|||
:columns="xPathColumns"
|
||||
:scroll="{ minWidth: '700px' }"
|
||||
:default-param-item="xPathDefaultParamItem"
|
||||
@change="(data, isInit) => handleChange(data, !!isInit, 'xPath')"
|
||||
@change="(data) => handleChange(data, 'xPath')"
|
||||
@more-action-select="(e,r)=> handleExtractParamMoreActionSelect(e,r as ExpressionConfig)"
|
||||
>
|
||||
<template #expression="{ record, rowIndex }">
|
||||
|
@ -193,7 +193,7 @@
|
|||
:span-method="documentSpanMethod"
|
||||
is-tree-table
|
||||
@tree-delete="deleteAllParam"
|
||||
@change="(data, isInit) => handleChange(data, !!isInit, 'document')"
|
||||
@change="(data) => handleChange(data, 'document')"
|
||||
>
|
||||
<template #matchValueDelete="{ record }">
|
||||
<icon-minus-circle
|
||||
|
@ -234,7 +234,7 @@
|
|||
:columns="xPathColumns"
|
||||
:scroll="{ minWidth: '700px' }"
|
||||
:default-param-item="xPathDefaultParamItem"
|
||||
@change="(data, isInit) => handleChange(data, !!isInit, 'regular')"
|
||||
@change="(data) => handleChange(data, 'regular')"
|
||||
@more-action-select="(e,r)=> handleExtractParamMoreActionSelect(e,r as ExpressionConfig)"
|
||||
>
|
||||
<template #expression="{ record, rowIndex }">
|
||||
|
@ -473,10 +473,7 @@
|
|||
matchValue: '',
|
||||
enable: true,
|
||||
};
|
||||
const handleChange = (data: any[], isInit: boolean, type: string) => {
|
||||
if (isInit) {
|
||||
return;
|
||||
}
|
||||
const handleChange = (data: any[], type: string) => {
|
||||
if (type === 'jsonPath') {
|
||||
innerParams.value.jsonPath = data;
|
||||
} else if (type === 'xPath') {
|
||||
|
|
|
@ -20,7 +20,13 @@
|
|||
@click="handleTabClick(tab)"
|
||||
>
|
||||
<div :draggable="!!tab.draggable" class="flex items-center">
|
||||
<slot name="label" :tab="tab">{{ tab.label }}</slot>
|
||||
<slot name="label" :tab="tab">
|
||||
<a-tooltip :content="tab.label" :mouse-enter-delay="500">
|
||||
<div class="one-line-text flex max-w-[144px] items-center">
|
||||
{{ tab.label }}
|
||||
</div>
|
||||
</a-tooltip>
|
||||
</slot>
|
||||
<div v-if="tab.unSaved" class="ml-[8px] h-[8px] w-[8px] rounded-full bg-[rgb(var(--primary-5))]"></div>
|
||||
<MsButton
|
||||
v-if="props.atLeastOne ? props.tabs.length > 1 && tab.closable : tab.closable !== false"
|
||||
|
|
|
@ -551,7 +551,7 @@
|
|||
}
|
||||
);
|
||||
const emit = defineEmits<{
|
||||
(e: 'change', data: any[], isInit?: boolean): void; // 都触发这个事件以通知父组件参数数组被更改
|
||||
(e: 'change', data: any[]): void; // 都触发这个事件以通知父组件参数数组被更改
|
||||
(e: 'moreActionSelect', event: ActionsItem, record: Record<string, any>): void;
|
||||
(e: 'projectChange', projectId: string): void;
|
||||
(e: 'treeDelete', record: Record<string, any>): void;
|
||||
|
@ -583,6 +583,12 @@
|
|||
showPagination: false,
|
||||
});
|
||||
|
||||
function emitChange(from: string, isInit?: boolean) {
|
||||
if (!isInit) {
|
||||
emit('change', propsRes.value.data);
|
||||
}
|
||||
}
|
||||
|
||||
const selectedKeys = computed(() => propsRes.value.data.filter((e) => e.enable).map((e) => e.id));
|
||||
propsEvent.value.rowSelectChange = (key: string) => {
|
||||
propsRes.value.data = propsRes.value.data.map((e) => {
|
||||
|
@ -591,14 +597,14 @@
|
|||
}
|
||||
return e;
|
||||
});
|
||||
emit('change', propsRes.value.data);
|
||||
emitChange('rowSelectChange');
|
||||
};
|
||||
propsEvent.value.selectAllChange = (v: SelectAllEnum) => {
|
||||
propsRes.value.data = propsRes.value.data.map((e) => {
|
||||
e.enable = v !== SelectAllEnum.NONE;
|
||||
return e;
|
||||
});
|
||||
emit('change', propsRes.value.data);
|
||||
emitChange('selectAllChange');
|
||||
};
|
||||
|
||||
watch(
|
||||
|
@ -623,7 +629,7 @@
|
|||
return;
|
||||
}
|
||||
propsRes.value.data.splice(rowIndex, 1);
|
||||
emit('change', propsRes.value.data);
|
||||
emitChange('deleteParam');
|
||||
}
|
||||
|
||||
/** 断言-文档-Begin */
|
||||
|
@ -638,7 +644,7 @@
|
|||
e.mustInclude = val;
|
||||
});
|
||||
propsRes.value.data = data;
|
||||
emit('change', propsRes.value.data);
|
||||
emitChange('handleMustIncludeChange');
|
||||
};
|
||||
const handleMustContainColChange = (notEmit?: boolean) => {
|
||||
const { data } = propsRes.value;
|
||||
|
@ -654,7 +660,7 @@
|
|||
mustIncludeIndeterminate.value = true;
|
||||
}
|
||||
if (!notEmit) {
|
||||
emit('change', propsRes.value.data);
|
||||
emitChange('handleMustContainColChange');
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -668,7 +674,7 @@
|
|||
e.typeChecking = val;
|
||||
});
|
||||
propsRes.value.data = data;
|
||||
emit('change', propsRes.value.data);
|
||||
emitChange('handleTypeCheckingChange');
|
||||
};
|
||||
const handleTypeCheckingColChange = (notEmit?: boolean) => {
|
||||
const { data } = propsRes.value;
|
||||
|
@ -684,7 +690,7 @@
|
|||
typeCheckingIndeterminate.value = true;
|
||||
}
|
||||
if (!notEmit) {
|
||||
emit('change', propsRes.value.data);
|
||||
emitChange('handleTypeCheckingColChange');
|
||||
}
|
||||
};
|
||||
/** 断言-文档-end */
|
||||
|
@ -707,7 +713,7 @@
|
|||
|
||||
const handleEnvironment = (obj: Record<string, any>, record: Record<string, any>) => {
|
||||
record.domain = {};
|
||||
emit('change', propsRes.value.data);
|
||||
emitChange('handleEnvironment');
|
||||
};
|
||||
|
||||
const hostVisible = ref(false);
|
||||
|
@ -751,7 +757,7 @@
|
|||
* @param key 当前列的 key
|
||||
* @param isForce 是否强制添加
|
||||
*/
|
||||
function addTableLine(rowIndex: number, addLineDisabled?: boolean) {
|
||||
function addTableLine(rowIndex: number, addLineDisabled?: boolean, isInit?: boolean) {
|
||||
if (addLineDisabled) {
|
||||
return;
|
||||
}
|
||||
|
@ -763,7 +769,7 @@
|
|||
...cloneDeep(props.defaultParamItem), // 深拷贝,避免有嵌套引用类型,数据隔离
|
||||
enable: true, // 是否勾选
|
||||
} as any);
|
||||
emit('change', propsRes.value.data);
|
||||
emitChange('addTableLine', isInit);
|
||||
}
|
||||
handleMustContainColChange(true);
|
||||
handleTypeCheckingColChange(true);
|
||||
|
@ -786,7 +792,7 @@
|
|||
return item;
|
||||
});
|
||||
if (hasNoIdItem && !filterKeyValParams(arr, props.defaultParamItem).lastDataIsDefault && !props.isTreeTable) {
|
||||
addTableLine(arr.length - 1);
|
||||
addTableLine(arr.length - 1, false, true);
|
||||
}
|
||||
} else {
|
||||
const id = new Date().getTime().toString();
|
||||
|
@ -797,7 +803,7 @@
|
|||
enable: true, // 是否勾选
|
||||
},
|
||||
] as any[];
|
||||
emit('change', propsRes.value.data, true);
|
||||
emitChange('watch props.params', true);
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -808,7 +814,7 @@
|
|||
function toggleRequired(record: Record<string, any>, rowIndex: number) {
|
||||
record.required = !record.required;
|
||||
addTableLine(rowIndex);
|
||||
emit('change', propsRes.value.data);
|
||||
emitChange('toggleRequired');
|
||||
}
|
||||
|
||||
async function handleFileChange(
|
||||
|
@ -842,7 +848,7 @@
|
|||
}));
|
||||
}
|
||||
addTableLine(rowIndex);
|
||||
emit('change', propsRes.value.data);
|
||||
emitChange('handleFileChange');
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
|
@ -871,7 +877,7 @@
|
|||
showQuickInputParam.value = false;
|
||||
addTableLine(propsRes.value.data.findIndex((e) => e.id === activeQuickInputRecord.value.id));
|
||||
clearQuickInputParam();
|
||||
emit('change', propsRes.value.data);
|
||||
emitChange('applyQuickInputParam');
|
||||
}
|
||||
|
||||
const showQuickInputDesc = ref(false);
|
||||
|
@ -893,11 +899,11 @@
|
|||
showQuickInputDesc.value = false;
|
||||
addTableLine(propsRes.value.data.findIndex((e) => e.id === activeQuickInputRecord.value.id));
|
||||
clearQuickInputDesc();
|
||||
emit('change', propsRes.value.data);
|
||||
emitChange('applyQuickInputDesc');
|
||||
}
|
||||
|
||||
function handleDescChange() {
|
||||
emit('change', propsRes.value.data);
|
||||
emitChange('handleDescChange');
|
||||
}
|
||||
|
||||
function handleTypeChange(
|
||||
|
@ -917,7 +923,7 @@
|
|||
record.contentType = RequestContentTypeEnum.TEXT;
|
||||
}
|
||||
}
|
||||
emit('change', propsRes.value.data);
|
||||
emitChange('handleTypeChange');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
</a-empty>
|
||||
<div v-show="!pluginError || isHttpProtocol" class="flex h-full flex-col">
|
||||
<div class="px-[18px] pt-[8px]">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex flex-wrap items-center justify-between gap-[12px]">
|
||||
<div class="flex flex-1 items-center gap-[16px]">
|
||||
<a-select
|
||||
v-if="requestVModel.isNew"
|
||||
|
@ -54,41 +54,77 @@
|
|||
/>
|
||||
</a-input-group>
|
||||
</div>
|
||||
<div class="ml-[16px]">
|
||||
<a-dropdown-button
|
||||
v-if="!requestVModel.executeLoading && hasAnyPermission([props.permissionMap.execute])"
|
||||
:disabled="requestVModel.executeLoading || (isHttpProtocol && !requestVModel.url)"
|
||||
class="exec-btn"
|
||||
@click="() => execute(isPriorityLocalExec ? 'localExec' : 'serverExec')"
|
||||
@select="execute"
|
||||
<div>
|
||||
<a-radio-group
|
||||
v-if="props.isDefinition"
|
||||
v-model:model-value="requestVModel.mode"
|
||||
type="button"
|
||||
class="mr-[12px]"
|
||||
>
|
||||
{{ isPriorityLocalExec ? t('apiTestDebug.localExec') : t('apiTestDebug.serverExec') }}
|
||||
<template v-if="hasLocalExec" #icon>
|
||||
<icon-down />
|
||||
</template>
|
||||
<template v-if="hasLocalExec" #content>
|
||||
<a-doption :value="isPriorityLocalExec ? 'serverExec' : 'localExec'">
|
||||
{{ isPriorityLocalExec ? t('apiTestDebug.serverExec') : t('apiTestDebug.localExec') }}
|
||||
</a-doption>
|
||||
</template>
|
||||
</a-dropdown-button>
|
||||
<a-button v-else type="primary" class="mr-[12px]" @click="stopDebug">{{ t('common.stop') }}</a-button>
|
||||
<a-dropdown
|
||||
v-if="props.isDefinition && hasAnyPermission([props.permissionMap.create, props.permissionMap.update])"
|
||||
:loading="saveLoading || (isHttpProtocol && !requestVModel.url)"
|
||||
@select="handleSelect"
|
||||
<a-radio value="definition">{{ t('apiTestManagement.definition') }}</a-radio>
|
||||
<a-radio value="debug">{{ t('apiTestManagement.debug') }}</a-radio>
|
||||
</a-radio-group>
|
||||
<!-- 接口定义-调试模式下,可执行 -->
|
||||
<template
|
||||
v-if="
|
||||
(!props.isDefinition || (props.isDefinition && requestVModel.mode === 'debug')) &&
|
||||
hasAnyPermission([props.permissionMap.execute])
|
||||
"
|
||||
>
|
||||
<a-button type="secondary">
|
||||
<a-dropdown-button
|
||||
v-if="!requestVModel.executeLoading"
|
||||
:disabled="requestVModel.executeLoading || (isHttpProtocol && !requestVModel.url)"
|
||||
class="exec-btn"
|
||||
@click="() => execute(isPriorityLocalExec ? 'localExec' : 'serverExec')"
|
||||
@select="execute"
|
||||
>
|
||||
{{ isPriorityLocalExec ? t('apiTestDebug.localExec') : t('apiTestDebug.serverExec') }}
|
||||
<template v-if="hasLocalExec" #icon>
|
||||
<icon-down />
|
||||
</template>
|
||||
<template v-if="hasLocalExec" #content>
|
||||
<a-doption :value="isPriorityLocalExec ? 'serverExec' : 'localExec'">
|
||||
{{ isPriorityLocalExec ? t('apiTestDebug.serverExec') : t('apiTestDebug.localExec') }}
|
||||
</a-doption>
|
||||
</template>
|
||||
</a-dropdown-button>
|
||||
<a-button v-else type="primary" class="mr-[12px]" @click="stopDebug">{{ t('common.stop') }}</a-button>
|
||||
</template>
|
||||
<!-- 接口定义-且有保存或更新权限 -->
|
||||
<template
|
||||
v-if="
|
||||
props.isDefinition &&
|
||||
(requestVModel.isNew
|
||||
? hasAnyPermission([props.permissionMap.create])
|
||||
: hasAnyPermission([props.permissionMap.update]))
|
||||
"
|
||||
>
|
||||
<!-- 接口定义-调试模式,可保存或保存为新用例 -->
|
||||
<a-dropdown
|
||||
v-if="requestVModel.mode === 'debug'"
|
||||
:loading="saveLoading || (isHttpProtocol && !requestVModel.url)"
|
||||
@select="handleSelect"
|
||||
>
|
||||
<a-button type="secondary">
|
||||
{{ t('common.save') }}
|
||||
</a-button>
|
||||
<template #content>
|
||||
<a-doption value="save">{{ t('common.save') }}</a-doption>
|
||||
<a-doption value="saveAsCase">{{ t('apiTestManagement.saveAsCase') }}</a-doption>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
<!-- 接口定义-定义模式,直接保存接口定义 -->
|
||||
<a-button v-else type="primary" @click="() => handleSelect('save')">
|
||||
{{ t('common.save') }}
|
||||
</a-button>
|
||||
<template #content>
|
||||
<a-doption value="save">{{ t('common.save') }}</a-doption>
|
||||
<a-doption value="saveAsCase">{{ t('apiTestManagement.saveAsCase') }}</a-doption>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
<!-- 接口调试,支持快捷保存 -->
|
||||
<a-button
|
||||
v-else
|
||||
v-permission="[props.permissionMap.create, props.permissionMap.update]"
|
||||
v-else-if="
|
||||
requestVModel.isNew
|
||||
? hasAnyPermission([props.permissionMap.create])
|
||||
: hasAnyPermission([props.permissionMap.update])
|
||||
"
|
||||
type="secondary"
|
||||
:disabled="isHttpProtocol && !requestVModel.url"
|
||||
:loading="saveLoading"
|
||||
|
@ -102,7 +138,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ref="splitContainerRef" :class="splitContainerClass">
|
||||
<div ref="splitContainerRef" class="h-[calc(100%-40px)]">
|
||||
<MsSplitBox
|
||||
ref="splitBoxRef"
|
||||
v-model:size="splitBoxSize"
|
||||
|
@ -138,7 +174,13 @@
|
|||
v-model:api="fApi"
|
||||
:rule="currentPluginScript"
|
||||
:option="currentPluginOptions"
|
||||
@change="handlePluginFormChange"
|
||||
@change="
|
||||
() => {
|
||||
if (isInitPluginForm) {
|
||||
handlePluginFormChange();
|
||||
}
|
||||
}
|
||||
"
|
||||
/>
|
||||
</a-spin>
|
||||
<httpHeader
|
||||
|
@ -329,6 +371,8 @@
|
|||
isNew: boolean;
|
||||
protocol: string;
|
||||
activeTab: RequestComposition;
|
||||
mode?: 'definition' | 'debug';
|
||||
executeLoading: boolean; // 执行中loading
|
||||
}
|
||||
export type RequestParam = ExecuteApiRequestFullParams & {
|
||||
responseDefinition?: ResponseItem[];
|
||||
|
@ -364,7 +408,7 @@
|
|||
|
||||
const loading = defineModel<boolean>('detailLoading', { default: false });
|
||||
const requestVModel = defineModel<RequestParam>('request', { required: true });
|
||||
requestVModel.value.executeLoading = false; // 注册loading
|
||||
|
||||
const isHttpProtocol = computed(() => requestVModel.value.protocol === 'HTTP');
|
||||
const temporaryResponseMap = {}; // 缓存websocket返回的报告内容,避免执行接口后切换tab导致报告丢失
|
||||
const isInitPluginForm = ref(false);
|
||||
|
@ -392,7 +436,7 @@
|
|||
const commonContentTabKey = [
|
||||
RequestComposition.PRECONDITION,
|
||||
RequestComposition.POST_CONDITION,
|
||||
// RequestComposition.ASSERTION, TODO:断言暂时无
|
||||
RequestComposition.ASSERTION,
|
||||
];
|
||||
// 请求内容插件tab
|
||||
const pluginContentTab = [
|
||||
|
@ -443,10 +487,20 @@
|
|||
// 根据协议类型获取请求内容tab
|
||||
const contentTabList = computed(() => {
|
||||
if (isHttpProtocol.value) {
|
||||
if (props.isDefinition) {
|
||||
// 接口定义,定义模式隐藏前后置、断言
|
||||
return requestVModel.value.mode === 'debug'
|
||||
? httpContentTabList
|
||||
: httpContentTabList.filter((e) => !commonContentTabKey.includes(e.value));
|
||||
}
|
||||
// 接口调试无断言
|
||||
return props.isDefinition
|
||||
? httpContentTabList
|
||||
: httpContentTabList.filter((e) => e.value !== RequestComposition.ASSERTION);
|
||||
return httpContentTabList.filter((e) => e.value !== RequestComposition.ASSERTION);
|
||||
}
|
||||
if (props.isDefinition) {
|
||||
// 接口定义,定义模式隐藏前后置、断言
|
||||
return requestVModel.value.mode === 'definition'
|
||||
? pluginContentTab
|
||||
: [...pluginContentTab, ...httpContentTabList.filter((e) => commonContentTabKey.includes(e.value))];
|
||||
}
|
||||
return [...pluginContentTab, ...httpContentTabList.filter((e) => commonContentTabKey.includes(e.value))];
|
||||
});
|
||||
|
@ -536,6 +590,24 @@
|
|||
handleActiveDebugChange();
|
||||
}, 300);
|
||||
|
||||
/**
|
||||
* 控制插件表单字段显示
|
||||
*/
|
||||
function controlPluginFormFields() {
|
||||
const allFields = fApi.value?.fields();
|
||||
let fields: string[] = [];
|
||||
if (props.isDefinition) {
|
||||
// 接口定义使用接口定义的字段集
|
||||
// 根据 apiDefinitionFields 字段集合展示需要的字段,隐藏其他字段
|
||||
fields = pluginScriptMap.value[requestVModel.value.protocol].apiDefinitionFields || [];
|
||||
} else {
|
||||
// 根据 apiDebugFields 字段集合展示需要的字段,隐藏其他字段
|
||||
fields = pluginScriptMap.value[requestVModel.value.protocol].apiDebugFields || [];
|
||||
}
|
||||
fApi.value?.hidden(true, allFields?.filter((e) => !fields.includes(e)) || []);
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置插件表单数据
|
||||
*/
|
||||
|
@ -543,30 +615,26 @@
|
|||
const tempForm = temporaryPluginFormMap[requestVModel.value.id];
|
||||
if (tempForm || !requestVModel.value.isNew) {
|
||||
// 如果缓存的表单数据存在或者是编辑状态,则需要将之前的输入数据填充
|
||||
fApi.value?.nextRefresh(() => {
|
||||
fApi.value?.reload(currentPluginScript.value);
|
||||
const formData = tempForm || requestVModel.value;
|
||||
if (fApi.value) {
|
||||
const formData = tempForm || requestVModel.value;
|
||||
if (fApi.value) {
|
||||
fApi.value.nextTick(() => {
|
||||
const form = {};
|
||||
if (props.isDefinition) {
|
||||
// 接口定义使用接口定义的字段集
|
||||
pluginScriptMap.value[requestVModel.value.protocol].apiDefinitionFields?.forEach((key) => {
|
||||
form[key] = formData[key];
|
||||
});
|
||||
} else {
|
||||
pluginScriptMap.value[requestVModel.value.protocol].apiDebugFields?.forEach((key) => {
|
||||
form[key] = formData[key];
|
||||
});
|
||||
}
|
||||
controlPluginFormFields().forEach((key) => {
|
||||
form[key] = formData[key];
|
||||
});
|
||||
fApi.value?.setValue(form);
|
||||
}
|
||||
});
|
||||
nextTick(() => {
|
||||
isInitPluginForm.value = true;
|
||||
});
|
||||
setTimeout(() => {
|
||||
// 初始化时赋值会触发表单数据变更,300ms 是为了与 handlePluginFormChange的防抖时间保持一致
|
||||
isInitPluginForm.value = true;
|
||||
}, 300);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// 如果是没有缓存也不是编辑,则需要重置表单,因为 form-create 只有一个实例,已经被其他有数据的 tab 污染了,需要重置
|
||||
fApi.value?.nextTick(() => {
|
||||
controlPluginFormFields();
|
||||
});
|
||||
nextTick(() => {
|
||||
// 如果是没有缓存也不是编辑,则需要重置表单,因为 form-create 只有一个实例,已经被其他有数据的 tab 污染了,需要重置
|
||||
fApi.value?.resetFields();
|
||||
});
|
||||
}
|
||||
|
@ -582,6 +650,7 @@
|
|||
return;
|
||||
}
|
||||
pluginError.value = false;
|
||||
isInitPluginForm.value = false;
|
||||
if (pluginScriptMap.value[requestVModel.value.protocol] !== undefined) {
|
||||
setPluginFormData();
|
||||
// 已经初始化过
|
||||
|
@ -672,12 +741,6 @@
|
|||
const activeLayout = ref<'horizontal' | 'vertical'>('vertical');
|
||||
const splitContainerRef = ref<HTMLElement>();
|
||||
const secondBoxHeight = ref(0);
|
||||
const splitContainerClass = computed(() => {
|
||||
if (!showResponse.value) {
|
||||
return 'h-full';
|
||||
}
|
||||
return 'h-[calc(100%-40px)]';
|
||||
});
|
||||
|
||||
watch(
|
||||
() => splitBoxSize.value,
|
||||
|
@ -716,6 +779,17 @@
|
|||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => showResponse.value,
|
||||
(val) => {
|
||||
if (val) {
|
||||
changeExpand(true);
|
||||
} else {
|
||||
changeExpand(false);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
function handleActiveLayoutChange() {
|
||||
isExpanded.value = true;
|
||||
splitBoxSize.value = 0.6;
|
||||
|
@ -950,6 +1024,7 @@
|
|||
const res = await props.createApi({
|
||||
...makeRequestParams(),
|
||||
...saveModalForm.value,
|
||||
path: isHttpProtocol.value ? saveModalForm.value.path : undefined,
|
||||
...props.otherParams,
|
||||
});
|
||||
requestVModel.value.id = res.id;
|
||||
|
@ -979,33 +1054,29 @@
|
|||
*/
|
||||
async function handleSaveShortcut() {
|
||||
if (!requestVModel.value.isNew) {
|
||||
if (hasAnyPermission([props.permissionMap.update])) {
|
||||
// 更新接口不需要弹窗,直接更新保存
|
||||
updateDebug();
|
||||
}
|
||||
// 更新接口不需要弹窗,直接更新保存
|
||||
updateDebug();
|
||||
return;
|
||||
}
|
||||
if (hasAnyPermission([props.permissionMap.create])) {
|
||||
try {
|
||||
if (!isHttpProtocol.value) {
|
||||
// 插件需要校验动态表单
|
||||
await fApi.value?.validate();
|
||||
}
|
||||
saveModalForm.value = {
|
||||
name: requestVModel.value.name || '',
|
||||
path: requestVModel.value.url || '',
|
||||
moduleId: 'root',
|
||||
};
|
||||
saveModalVisible.value = true;
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
// 校验不通过则不进行保存
|
||||
requestVModel.value.activeTab = RequestComposition.PLUGIN;
|
||||
nextTick(() => {
|
||||
scrollIntoView(document.querySelector('.arco-form-item-message'), { block: 'center' });
|
||||
});
|
||||
try {
|
||||
if (!isHttpProtocol.value) {
|
||||
// 插件需要校验动态表单
|
||||
await fApi.value?.validate();
|
||||
}
|
||||
saveModalForm.value = {
|
||||
name: requestVModel.value.name || '',
|
||||
path: requestVModel.value.url || '',
|
||||
moduleId: 'root',
|
||||
};
|
||||
saveModalVisible.value = true;
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
// 校验不通过则不进行保存
|
||||
requestVModel.value.activeTab = RequestComposition.PLUGIN;
|
||||
nextTick(() => {
|
||||
scrollIntoView(document.querySelector('.arco-form-item-message'), { block: 'center' });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
class="flex items-center justify-between gap-[24px]"
|
||||
>
|
||||
<a-popover position="left" content-class="response-popover-content">
|
||||
<div :style="{ color: statusCodeColor }">
|
||||
<div class="one-line-text max-w-[200px]" :style="{ color: statusCodeColor }">
|
||||
{{ props.requestTaskResult.requestResults[0].responseResult.responseCode }}
|
||||
</div>
|
||||
<template #content>
|
||||
|
@ -225,6 +225,15 @@
|
|||
function setActiveResponse(val: 'content' | 'result') {
|
||||
activeResponseType.value = val;
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.requestTaskResult,
|
||||
(task) => {
|
||||
if (task) {
|
||||
setActiveResponse('result');
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
|
|
|
@ -249,6 +249,7 @@
|
|||
responseActiveTab: ResponseComposition.BODY,
|
||||
response: cloneDeep(defaultResponse),
|
||||
isNew: true,
|
||||
executeLoading: false,
|
||||
};
|
||||
const debugTabs = ref<RequestParam[]>([cloneDeep(defaultDebugParams)]);
|
||||
const activeDebug = ref<RequestParam>(debugTabs.value[0]);
|
||||
|
|
|
@ -6,21 +6,6 @@
|
|||
{{ t('apiTestManagement.showSubdirectory') }}
|
||||
</div>
|
||||
<div class="flex items-center gap-[8px]">
|
||||
<template v-if="!props.readOnly">
|
||||
<a-button type="outline" class="arco-btn-outline--secondary !p-[8px]">
|
||||
<template #icon>
|
||||
<icon-location class="text-[var(--color-text-4)]" />
|
||||
</template>
|
||||
</a-button>
|
||||
<MsSelect
|
||||
v-model:model-value="checkedEnv"
|
||||
mode="static"
|
||||
:options="envOptions"
|
||||
class="!w-[150px]"
|
||||
:search-keys="['label']"
|
||||
allow-search
|
||||
/>
|
||||
</template>
|
||||
<a-input-search
|
||||
v-model:model-value="keyword"
|
||||
:placeholder="t('apiTestManagement.searchPlaceholder')"
|
||||
|
@ -251,7 +236,6 @@
|
|||
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
|
||||
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
||||
import MsSelect from '@/components/business/ms-select';
|
||||
import apiMethodName from '@/views/api-test/components/apiMethodName.vue';
|
||||
import apiMethodSelect from '@/views/api-test/components/apiMethodSelect.vue';
|
||||
import apiStatus from '@/views/api-test/components/apiStatus.vue';
|
||||
|
@ -392,14 +376,6 @@
|
|||
width: 150,
|
||||
},
|
||||
];
|
||||
if (!props.readOnly) {
|
||||
const tableStore = useTableStore();
|
||||
await tableStore.initColumn(TableKeyEnum.API_TEST, columns, 'drawer');
|
||||
} else {
|
||||
columns = columns.filter(
|
||||
(item) => !['version', 'createTime', 'updateTime', 'operation'].includes(item.dataIndex as string)
|
||||
);
|
||||
}
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable(
|
||||
getDefinitionPage,
|
||||
{
|
||||
|
@ -758,6 +734,19 @@
|
|||
function openApiTab(record: ApiDefinitionDetail) {
|
||||
emit('openApiTab', record);
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
loadApiList,
|
||||
});
|
||||
|
||||
if (!props.readOnly) {
|
||||
const tableStore = useTableStore();
|
||||
await tableStore.initColumn(TableKeyEnum.API_TEST, columns, 'drawer');
|
||||
} else {
|
||||
columns = columns.filter(
|
||||
(item) => !['version', 'createTime', 'updateTime', 'operation'].includes(item.dataIndex as string)
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
|
@ -1,15 +1,29 @@
|
|||
<template>
|
||||
<div class="flex h-full flex-col">
|
||||
<div class="border-b border-[var(--color-text-n8)] px-[22px] pb-[16px]">
|
||||
<MsEditableTab v-model:active-tab="activeApiTab" v-model:tabs="apiTabs" @add="addApiTab">
|
||||
<MsEditableTab
|
||||
v-model:active-tab="activeApiTab"
|
||||
v-model:tabs="apiTabs"
|
||||
@add="addApiTab"
|
||||
@change="handleActiveTabChange"
|
||||
>
|
||||
<template #label="{ tab }">
|
||||
<apiMethodName v-if="tab.id !== 'all'" :method="tab.method" class="mr-[4px]" />
|
||||
{{ tab.name || tab.label }}
|
||||
<apiMethodName
|
||||
v-if="tab.id !== 'all'"
|
||||
:method="tab.protocol === 'HTTP' ? tab.method : tab.protocol"
|
||||
class="mr-[4px]"
|
||||
/>
|
||||
<a-tooltip :content="tab.name || tab.label" :mouse-enter-delay="500">
|
||||
<div class="one-line-text max-w-[144px]">
|
||||
{{ tab.name || tab.label }}
|
||||
</div>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</MsEditableTab>
|
||||
</div>
|
||||
<div v-show="activeApiTab.id === 'all'" class="flex-1">
|
||||
<apiTable
|
||||
ref="apiTableRef"
|
||||
:active-module="props.activeModule"
|
||||
:offspring-ids="props.offspringIds"
|
||||
:protocol="props.protocol"
|
||||
|
@ -112,18 +126,48 @@
|
|||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<a-dropdown @select="handleSelect">
|
||||
<a-button type="outline">
|
||||
<div class="flex items-center gap-[8px]">
|
||||
<icon-plus />
|
||||
{{ t('apiTestManagement.addDependency') }}
|
||||
<div class="mb-[8px] flex items-center">
|
||||
<div class="text-[var(--color-text-2)]">
|
||||
{{ t('apiTestManagement.addDependency') }}
|
||||
</div>
|
||||
<a-divider margin="4px" direction="vertical" />
|
||||
<MsButton
|
||||
type="text"
|
||||
class="font-medium"
|
||||
:disabled="activeApiTab.preDependency.length === 0 && activeApiTab.postDependency.length === 0"
|
||||
@click="clearAllDependency"
|
||||
>
|
||||
{{ t('apiTestManagement.clearSelected') }}
|
||||
</MsButton>
|
||||
</div>
|
||||
<div class="rounded-[var(--border-radius-small)] bg-[var(--color-text-n9)] p-[12px]">
|
||||
<div class="flex items-center">
|
||||
<div class="flex items-center gap-[4px] text-[var(--color-text-2)]">
|
||||
{{ t('apiTestManagement.preDependency') }}
|
||||
<div class="text-[rgb(var(--primary-5))]">
|
||||
{{ activeApiTab.preDependency.length }}
|
||||
</div>
|
||||
{{ t('apiTestManagement.dependencyUnit') }}
|
||||
</div>
|
||||
</a-button>
|
||||
<template #content>
|
||||
<a-doption value="pre">{{ t('apiTestManagement.preDependency') }}</a-doption>
|
||||
<a-doption value="post">{{ t('apiTestManagement.postDependency') }}</a-doption>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
<a-divider margin="8px" direction="vertical" />
|
||||
<MsButton type="text" class="font-medium" @click="handleDddDependency('pre')">
|
||||
{{ t('apiTestManagement.addPreDependency') }}
|
||||
</MsButton>
|
||||
</div>
|
||||
<div class="mt-[8px] flex items-center">
|
||||
<div class="flex items-center gap-[4px] text-[var(--color-text-2)]">
|
||||
{{ t('apiTestManagement.postDependency') }}
|
||||
<div class="text-[rgb(var(--primary-5))]">
|
||||
{{ activeApiTab.postDependency.length }}
|
||||
</div>
|
||||
{{ t('apiTestManagement.dependencyUnit') }}
|
||||
</div>
|
||||
<a-divider margin="8px" direction="vertical" />
|
||||
<MsButton type="text" class="font-medium" @click="handleDddDependency('post')">
|
||||
{{ t('apiTestManagement.addPostDependency') }}
|
||||
</MsButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</MsSplitBox>
|
||||
|
@ -141,6 +185,7 @@
|
|||
import { FormInstance, Message } from '@arco-design/web-vue';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsEditableTab from '@/components/pure/ms-editable-tab/index.vue';
|
||||
import { TabItem } from '@/components/pure/ms-editable-tab/types';
|
||||
// import MsFormCreate from '@/components/pure/ms-form-create/formCreate.vue';
|
||||
|
@ -188,13 +233,14 @@
|
|||
);
|
||||
|
||||
const props = defineProps<{
|
||||
allCount: number;
|
||||
activeModule: string;
|
||||
offspringIds: string[];
|
||||
moduleTree: ModuleTreeNode[]; // 模块树
|
||||
protocol: string;
|
||||
}>();
|
||||
const emit = defineEmits(['addDone']);
|
||||
const setActiveApi: ((params: RequestParam) => void) | undefined = inject('setActiveApi');
|
||||
const refreshModuleTree: (() => Promise<any>) | undefined = inject('refreshModuleTree');
|
||||
|
||||
const appStore = useAppStore();
|
||||
const { t } = useI18n();
|
||||
|
@ -202,7 +248,7 @@
|
|||
const apiTabs = ref<RequestParam[]>([
|
||||
{
|
||||
id: 'all',
|
||||
label: `${t('apiTestManagement.allApi')}(${props.allCount})`,
|
||||
label: t('apiTestManagement.allApi'),
|
||||
closable: false,
|
||||
} as RequestParam,
|
||||
]);
|
||||
|
@ -214,7 +260,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
const setActiveApi: ((params: RequestParam) => void) | undefined = inject('setActiveApi');
|
||||
watch(
|
||||
() => activeApiTab.value.id,
|
||||
() => {
|
||||
|
@ -338,6 +383,10 @@
|
|||
response: cloneDeep(defaultResponse),
|
||||
responseDefinition: [cloneDeep(defaultResponseItem)],
|
||||
isNew: true,
|
||||
mode: 'definition',
|
||||
executeLoading: false,
|
||||
preDependency: [], // 前置依赖
|
||||
postDependency: [], // 后置依赖
|
||||
};
|
||||
|
||||
function addApiTab(defaultProps?: Partial<TabItem>) {
|
||||
|
@ -345,7 +394,7 @@
|
|||
apiTabs.value.push({
|
||||
...cloneDeep(defaultDefinitionParams),
|
||||
moduleId: props.activeModule === 'all' ? 'root' : props.activeModule,
|
||||
label: t('apiTestDebug.newApi'),
|
||||
label: t('apiTestManagement.newApi'),
|
||||
id,
|
||||
isNew: !defaultProps?.id, // 新开的tab标记为前端新增的调试,因为此时都已经有id了;但是如果是查看打开的会有携带id
|
||||
...defaultProps,
|
||||
|
@ -353,6 +402,14 @@
|
|||
activeApiTab.value = apiTabs.value[apiTabs.value.length - 1] as RequestParam;
|
||||
}
|
||||
|
||||
const apiTableRef = ref<InstanceType<typeof apiTable>>();
|
||||
|
||||
function handleActiveTabChange(item: TabItem) {
|
||||
if (item.id === 'all') {
|
||||
apiTableRef.value?.loadApiList();
|
||||
}
|
||||
}
|
||||
|
||||
const loading = ref(false);
|
||||
async function openApiTab(apiInfo: ModuleTreeNode | ApiDefinitionDetail) {
|
||||
const isLoadedTabIndex = apiTabs.value.findIndex((e) => e.id === apiInfo.id);
|
||||
|
@ -403,7 +460,7 @@
|
|||
const showAddDependencyDrawer = ref(false);
|
||||
const addDependencyMode = ref<'pre' | 'post'>('pre');
|
||||
|
||||
function handleSelect(value: string | number | Record<string, any> | undefined) {
|
||||
function handleDddDependency(value: string | number | Record<string, any> | undefined) {
|
||||
switch (value) {
|
||||
case 'pre':
|
||||
addDependencyMode.value = 'pre';
|
||||
|
@ -418,6 +475,11 @@
|
|||
}
|
||||
}
|
||||
|
||||
function clearAllDependency() {
|
||||
activeApiTab.value.preDependency = [];
|
||||
activeApiTab.value.postDependency = [];
|
||||
}
|
||||
|
||||
const splitBoxRef = ref<InstanceType<typeof MsSplitBox>>();
|
||||
const activeApiTabFormRef = ref<FormInstance>();
|
||||
|
||||
|
@ -442,6 +504,9 @@
|
|||
activeApiTab.value.name = res.name;
|
||||
activeApiTab.value.label = res.name;
|
||||
activeApiTab.value.url = res.path;
|
||||
if (typeof refreshModuleTree === 'function') {
|
||||
refreshModuleTree();
|
||||
}
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
|
|
|
@ -5,14 +5,13 @@
|
|||
ref="apiRef"
|
||||
:module-tree="props.moduleTree"
|
||||
:active-module="props.activeModule"
|
||||
:all-count="props.allCount"
|
||||
:offspring-ids="props.offspringIds"
|
||||
:protocol="protocol"
|
||||
/>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="case" title="CASE" class="ms-api-tab-pane"> </a-tab-pane>
|
||||
<a-tab-pane key="mock" title="MOCK" class="ms-api-tab-pane"> </a-tab-pane>
|
||||
<a-tab-pane key="doc" :title="t('apiTestManagement.doc')" class="ms-api-tab-pane"> </a-tab-pane>
|
||||
<!-- <a-tab-pane key="doc" title="API Docs" class="ms-api-tab-pane"> </a-tab-pane> -->
|
||||
<template #extra>
|
||||
<div class="flex items-center gap-[8px] pr-[24px]">
|
||||
<a-button type="outline" class="arco-btn-outline--secondary !p-[8px]">
|
||||
|
@ -42,7 +41,6 @@
|
|||
import { ModuleTreeNode } from '@/models/common';
|
||||
|
||||
const props = defineProps<{
|
||||
allCount: number;
|
||||
activeModule: string;
|
||||
offspringIds: string[];
|
||||
protocol: string;
|
||||
|
|
|
@ -526,9 +526,13 @@
|
|||
initModuleCount();
|
||||
});
|
||||
|
||||
async function refresh() {
|
||||
await initModules();
|
||||
initModuleCount();
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
initModules,
|
||||
initModuleCount,
|
||||
refresh,
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
<template #first>
|
||||
<div class="p-[24px]">
|
||||
<moduleTree
|
||||
ref="moduleTreeRef"
|
||||
:active-node-id="activeApi?.id"
|
||||
@init="handleModuleInit"
|
||||
@new-api="newApi"
|
||||
|
@ -40,7 +41,6 @@
|
|||
<management
|
||||
ref="managementRef"
|
||||
:module-tree="folderTree"
|
||||
:all-count="allCount"
|
||||
:active-module="activeModule"
|
||||
:offspring-ids="offspringIds"
|
||||
:protocol="protocol"
|
||||
|
@ -65,11 +65,11 @@
|
|||
|
||||
const activeModule = ref<string>('all');
|
||||
const folderTree = ref<ModuleTreeNode[]>([]);
|
||||
const allCount = ref(0);
|
||||
const importDrawerVisible = ref(false);
|
||||
const offspringIds = ref<string[]>([]);
|
||||
const protocol = ref('HTTP');
|
||||
const activeApi = ref<RequestParam>();
|
||||
const moduleTreeRef = ref<InstanceType<typeof moduleTree>>();
|
||||
const managementRef = ref<InstanceType<typeof management>>();
|
||||
|
||||
function handleModuleInit(tree, _protocol: string) {
|
||||
|
@ -98,7 +98,13 @@
|
|||
protocol.value = val;
|
||||
}
|
||||
|
||||
function refreshModuleTree() {
|
||||
moduleTreeRef.value?.refresh();
|
||||
}
|
||||
|
||||
/** 向子孙组件提供方法 */
|
||||
provide('setActiveApi', setActiveApi);
|
||||
provide('refreshModuleTree', refreshModuleTree);
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
|
|
|
@ -1 +1,103 @@
|
|||
export default {};
|
||||
export default {
|
||||
'apiTestManagement.newApi': 'Create api',
|
||||
'apiTestManagement.importApi': 'Import api',
|
||||
'apiTestManagement.fileImport': 'Import file',
|
||||
'apiTestManagement.timeImport': 'Scheduled import',
|
||||
'apiTestManagement.addSubModule': 'Add submodule',
|
||||
'apiTestManagement.allApi': 'All api',
|
||||
'apiTestManagement.searchTip': 'Please enter module/api name',
|
||||
'apiTestManagement.moveSearchTip': 'Please enter the module name to search',
|
||||
'apiTestManagement.noMatchModule': 'No matching module/api yet',
|
||||
'apiTestManagement.execute': 'Execute',
|
||||
'apiTestManagement.share': 'Share API',
|
||||
'apiTestManagement.shareModule': 'Share module',
|
||||
'apiTestManagement.doc': 'Document',
|
||||
'apiTestManagement.closeAll': 'Close all tabs',
|
||||
'apiTestManagement.closeOther': 'Close other tabs',
|
||||
'apiTestManagement.showSubdirectory': 'Show subdirectory use case',
|
||||
'apiTestManagement.searchPlaceholder': 'Enter ID/name/api path search',
|
||||
'apiTestManagement.apiName': 'Api name',
|
||||
'apiTestManagement.apiType': 'Api type',
|
||||
'apiTestManagement.apiStatus': 'Status',
|
||||
'apiTestManagement.path': 'Path',
|
||||
'apiTestManagement.version': 'Version',
|
||||
'apiTestManagement.createTime': 'Creation time',
|
||||
'apiTestManagement.updateTime': 'Update time',
|
||||
'apiTestManagement.deprecate': 'Deprecated',
|
||||
'apiTestManagement.processing': 'Processing',
|
||||
'apiTestManagement.debugging': 'Debugging',
|
||||
'apiTestManagement.done': 'Completed',
|
||||
'apiTestManagement.deleteApiTipTitle': 'Are you sure you want to delete {name}?',
|
||||
'apiTestManagement.deleteApiTip':
|
||||
'After deletion, the interface will be placed in the recycle bin, where data recovery can be performed',
|
||||
'apiTestManagement.batchDeleteApiTip': 'Are you sure you want to delete {count} selected interfaces?',
|
||||
'apiTestManagement.batchModalSubTitle': '({count} interfaces selected)',
|
||||
'apiTestManagement.chooseAttr': 'Select properties',
|
||||
'apiTestManagement.attrRequired': 'Property cannot be empty',
|
||||
'apiTestManagement.batchUpdate': 'Batch update to',
|
||||
'apiTestManagement.valueRequired': 'Attribute value cannot be empty',
|
||||
'apiTestManagement.batchMoveConfirm': 'Move to selected module',
|
||||
'apiTestManagement.belongModule': 'Belonging module',
|
||||
'apiTestManagement.importMode': 'Import mode',
|
||||
'apiTestManagement.importModeTip1': 'Cover:',
|
||||
'apiTestManagement.importModeTip2':
|
||||
'1.If the request type + path is the same for the same interface, if the request parameter content is inconsistent, it will be overwritten.',
|
||||
'apiTestManagement.importModeTip3':
|
||||
'2.The same interface request type + path are the same, and the request parameter content is the same and does not change.',
|
||||
'apiTestManagement.importModeTip4':
|
||||
'3.If the interface is not the same and the request type + path is the same, add it',
|
||||
'apiTestManagement.importModeTip5': 'Not covered:',
|
||||
'apiTestManagement.importModeTip6':
|
||||
'1.If the same interface request type + path are the same, no changes will be made.',
|
||||
'apiTestManagement.importModeTip7': '2.If the request type + path are not the same for the same interface, add a new',
|
||||
'apiTestManagement.cover': 'Cover',
|
||||
'apiTestManagement.uncover': 'Not covered',
|
||||
'apiTestManagement.moreSetting': 'More settings',
|
||||
'apiTestManagement.importType': 'Import method',
|
||||
'apiTestManagement.urlImport': 'URL import',
|
||||
'apiTestManagement.syncImportCase': 'Synchronous import interface use case',
|
||||
'apiTestManagement.syncUpdateDirectory': 'Synchronously update the directory where the interface is located',
|
||||
'apiTestManagement.importSwaggerFileTip1': 'Supports json files of Swagger 3.0 version,',
|
||||
'apiTestManagement.importSwaggerFileTip2':
|
||||
'It is recommended to convert 2.0 files to 3.0 on the official website and then import them.',
|
||||
'apiTestManagement.importSwaggerFileTip3': ', the size does not exceed 50M',
|
||||
'apiTestManagement.urlImportPlaceholder': 'Please enter the OpenAPI/Swagger URL',
|
||||
'apiTestManagement.swaggerURLRequired': 'SwaggerURL cannot be empty',
|
||||
'apiTestManagement.basicAuth': 'Basic Authentication',
|
||||
'apiTestManagement.account': 'Account',
|
||||
'apiTestManagement.accountRequired': 'Account cannot be empty',
|
||||
'apiTestManagement.password': 'Password',
|
||||
'apiTestManagement.passwordRequired': 'Password can not be blank',
|
||||
'apiTestManagement.taskName': 'Task name',
|
||||
'apiTestManagement.taskNamePlaceholder': 'Please enter a task name',
|
||||
'apiTestManagement.taskNameRequired': 'Task name cannot be empty',
|
||||
'apiTestManagement.syncFrequency': 'Sync frequency',
|
||||
'apiTestManagement.timeTaskList': 'Scheduled task list',
|
||||
'apiTestManagement.timeTaskHour': '(per hour)',
|
||||
'apiTestManagement.timeTaskSixHour': '(every 6 hours)',
|
||||
'apiTestManagement.timeTaskTwelveHour': '(every 12 hours)',
|
||||
'apiTestManagement.timeTaskDay': '(every day)',
|
||||
'apiTestManagement.customFrequency': 'Custom frequency',
|
||||
'apiTestManagement.case': 'Case',
|
||||
'apiTestManagement.definition': 'Definition',
|
||||
'apiTestManagement.debug': 'Debug',
|
||||
'apiTestManagement.addDependency': 'Select dependency use case',
|
||||
'apiTestManagement.clearSelected': 'Clear selected use cases',
|
||||
'apiTestManagement.preDependency': 'Front interface',
|
||||
'apiTestManagement.addPreDependency': 'Add pre-dependency',
|
||||
'apiTestManagement.postDependency': 'Rear interface',
|
||||
'apiTestManagement.addPostDependency': 'Add post-dependency',
|
||||
'apiTestManagement.dependencyUnit': 'item',
|
||||
'apiTestManagement.saveAsCase': 'Save as new use case',
|
||||
'apiTestManagement.apiNamePlaceholder': 'Please enter the interface name',
|
||||
'apiTestManagement.executeResult': 'Execution result',
|
||||
'apiTestManagement.setDefault': 'Set as Default',
|
||||
'apiTestManagement.confirmDelete': 'Are you sure you want to delete {name}?',
|
||||
'apiTestManagement.response': 'Response{count}',
|
||||
'apiTestManagement.responseCode': 'Response code',
|
||||
'apiTestManagement.dynamicConversion': 'Dynamic conversion',
|
||||
'apiTestManagement.expandApi': 'Show all requests',
|
||||
'apiTestManagement.collapseApi': 'Hide all requests',
|
||||
'apiTestManagement.paramName': 'Parameter name',
|
||||
'apiTestManagement.paramVal': 'Parameter value',
|
||||
};
|
||||
|
|
|
@ -19,7 +19,6 @@ export default {
|
|||
'apiTestManagement.apiName': '接口名称',
|
||||
'apiTestManagement.apiType': '请求类型',
|
||||
'apiTestManagement.apiStatus': '状态',
|
||||
'apiTestManagement.responsiblePerson': '责任人',
|
||||
'apiTestManagement.path': '路径',
|
||||
'apiTestManagement.version': '版本',
|
||||
'apiTestManagement.createTime': '创建时间',
|
||||
|
@ -75,11 +74,14 @@ export default {
|
|||
'apiTestManagement.customFrequency': '自定义频率',
|
||||
'apiTestManagement.case': '用例',
|
||||
'apiTestManagement.definition': '定义',
|
||||
'apiTestManagement.addDependency': '添加依赖关系',
|
||||
'apiTestManagement.preDependency': '前置依赖',
|
||||
'apiTestManagement.debug': '调试',
|
||||
'apiTestManagement.addDependency': '选择依赖关系用例',
|
||||
'apiTestManagement.clearSelected': '清空已选用例',
|
||||
'apiTestManagement.preDependency': '前置接口',
|
||||
'apiTestManagement.addPreDependency': '添加前置依赖',
|
||||
'apiTestManagement.postDependency': '后置依赖',
|
||||
'apiTestManagement.postDependency': '后置接口',
|
||||
'apiTestManagement.addPostDependency': '添加后置依赖',
|
||||
'apiTestManagement.dependencyUnit': '条',
|
||||
'apiTestManagement.saveAsCase': '保存为新用例',
|
||||
'apiTestManagement.apiNamePlaceholder': '请输入接口名称',
|
||||
'apiTestManagement.executeResult': '执行结果',
|
||||
|
|
Loading…
Reference in New Issue