feat(接口测试): 接口调试-导入curl
This commit is contained in:
parent
9de485fe9e
commit
8f4ddbbe87
|
@ -102,7 +102,7 @@ export const editorProps = {
|
||||||
// 是否显示字符集切换
|
// 是否显示字符集切换
|
||||||
showCharsetChange: {
|
showCharsetChange: {
|
||||||
type: Boolean as PropType<boolean>,
|
type: Boolean as PropType<boolean>,
|
||||||
default: true,
|
default: false,
|
||||||
},
|
},
|
||||||
// 是否显示主题切换
|
// 是否显示主题切换
|
||||||
showThemeChange: {
|
showThemeChange: {
|
||||||
|
|
|
@ -87,7 +87,7 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #cell="{ column, record, rowIndex }">
|
<template #cell="{ column, record, rowIndex }">
|
||||||
<div :class="{ 'flex flex-row items-center': !item.isTag && !item.align }">
|
<div :class="{ 'flex w-full flex-row items-center': !item.isTag && !item.align }">
|
||||||
<template v-if="item.dataIndex === SpecialColumnEnum.ENABLE">
|
<template v-if="item.dataIndex === SpecialColumnEnum.ENABLE">
|
||||||
<slot name="enable" v-bind="{ record }">
|
<slot name="enable" v-bind="{ record }">
|
||||||
<div v-if="record.enable" class="flex flex-row flex-nowrap items-center gap-[2px]">
|
<div v-if="record.enable" class="flex flex-row flex-nowrap items-center gap-[2px]">
|
||||||
|
|
|
@ -370,3 +370,69 @@ export function decodeStringToCharset(str: string, charset = 'UTF-8') {
|
||||||
const decoder = new TextDecoder(charset);
|
const decoder = new TextDecoder(charset);
|
||||||
return decoder.decode(encoder.encode(str));
|
return decoder.decode(encoder.encode(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ParsedCurlOptions {
|
||||||
|
url?: string;
|
||||||
|
queryParameters?: { name: string; value: string }[];
|
||||||
|
headers?: { name: string; value: string }[];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 解析 curl 脚本
|
||||||
|
* @param curlScript curl 脚本
|
||||||
|
*/
|
||||||
|
export function parseCurlScript(curlScript: string): ParsedCurlOptions {
|
||||||
|
const options: ParsedCurlOptions = {};
|
||||||
|
|
||||||
|
// 提取 URL
|
||||||
|
const [_, url] = curlScript.match(/curl\s+'([^']+)'/) || [];
|
||||||
|
if (url) {
|
||||||
|
options.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取 query 参数
|
||||||
|
const queryMatch = curlScript.match(/\?(.*?)'/);
|
||||||
|
if (queryMatch) {
|
||||||
|
const queryParams = queryMatch[1].split('&').map((param) => {
|
||||||
|
const [name, value] = param.split('=');
|
||||||
|
return { name, value };
|
||||||
|
});
|
||||||
|
options.queryParameters = queryParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取 header
|
||||||
|
const headersMatch = curlScript.match(/-H\s+'([^']+)'/g);
|
||||||
|
if (headersMatch) {
|
||||||
|
const headers = headersMatch.map((header) => {
|
||||||
|
const [, value] = header.match(/-H\s+'([^']+)'/) || [];
|
||||||
|
const [name, rawValue] = value.split(':');
|
||||||
|
const trimmedName = name.trim();
|
||||||
|
const trimmedValue = rawValue ? rawValue.trim() : '';
|
||||||
|
return { name: trimmedName, value: trimmedValue };
|
||||||
|
});
|
||||||
|
|
||||||
|
// 过滤常用的 HTTP header
|
||||||
|
const commonHeaders = [
|
||||||
|
'accept',
|
||||||
|
'accept-language',
|
||||||
|
'cache-control',
|
||||||
|
'content-type',
|
||||||
|
'origin',
|
||||||
|
'pragma',
|
||||||
|
'referer',
|
||||||
|
'sec-ch-ua',
|
||||||
|
'sec-ch-ua-mobile',
|
||||||
|
'sec-ch-ua-platform',
|
||||||
|
'sec-fetch-dest',
|
||||||
|
'sec-fetch-mode',
|
||||||
|
'sec-fetch-site',
|
||||||
|
'user-agent',
|
||||||
|
'Connection',
|
||||||
|
'Host',
|
||||||
|
'Accept-Encoding',
|
||||||
|
'X-Requested-With',
|
||||||
|
];
|
||||||
|
options.headers = headers.filter((header) => !commonHeaders.includes(header.name.toLowerCase()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
|
@ -485,7 +485,7 @@ org.apache.http.client.method . . . '' at line number 2
|
||||||
value: 'temp',
|
value: 'temp',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
width: 110,
|
width: 130,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'apiTestDebug.mode',
|
title: 'apiTestDebug.mode',
|
||||||
|
|
|
@ -65,7 +65,7 @@
|
||||||
<a-select
|
<a-select
|
||||||
v-model:model-value="record.type"
|
v-model:model-value="record.type"
|
||||||
:options="columnConfig.typeOptions || []"
|
:options="columnConfig.typeOptions || []"
|
||||||
class="param-input"
|
class="param-input w-full"
|
||||||
@change="(val) => handleTypeChange(val, record)"
|
@change="(val) => handleTypeChange(val, record)"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
@ -281,6 +281,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script async setup lang="ts">
|
<script async setup lang="ts">
|
||||||
|
import { isEqual } from 'lodash-es';
|
||||||
|
|
||||||
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 MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||||
|
@ -369,8 +371,7 @@
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'update:params', value: any[]): void;
|
(e: 'change', data: any[], isInit?: boolean): void; // 都触发这个事件以通知父组件参数数组被更改
|
||||||
(e: 'change', data: any[], isInit?: boolean): void;
|
|
||||||
(e: 'moreActionSelect', event: ActionsItem, record: Record<string, any>): void;
|
(e: 'moreActionSelect', event: ActionsItem, record: Record<string, any>): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
@ -397,24 +398,6 @@
|
||||||
isSimpleSetting: props.isSimpleSetting,
|
isSimpleSetting: props.isSimpleSetting,
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.params,
|
|
||||||
(val) => {
|
|
||||||
if (val.length > 0) {
|
|
||||||
propsRes.value.data = val;
|
|
||||||
} else {
|
|
||||||
propsRes.value.data = props.params.concat({
|
|
||||||
id: new Date().getTime(), // 默认给时间戳 id,若 props.defaultParamItem 有 id,则覆盖
|
|
||||||
...props.defaultParamItem,
|
|
||||||
});
|
|
||||||
emit('change', propsRes.value.data, true);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
immediate: true,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.heightUsed,
|
() => props.heightUsed,
|
||||||
(val) => {
|
(val) => {
|
||||||
|
@ -440,12 +423,13 @@
|
||||||
key?: string,
|
key?: string,
|
||||||
isForce?: boolean
|
isForce?: boolean
|
||||||
) {
|
) {
|
||||||
const lastData = propsRes.value.data[propsRes.value.data.length - 1];
|
const lastData = { ...propsRes.value.data[propsRes.value.data.length - 1] };
|
||||||
|
delete lastData.id;
|
||||||
// 当不传入输入值或对应列的 key 时,遍历整个数据对象判断是否有变化;当传入输入值或对应列的 key 时,判断对应列的值是否有变化
|
// 当不传入输入值或对应列的 key 时,遍历整个数据对象判断是否有变化;当传入输入值或对应列的 key 时,判断对应列的值是否有变化
|
||||||
const isNotChange =
|
const isNotChange =
|
||||||
val === undefined || key === undefined
|
val === undefined || key === undefined
|
||||||
? Object.keys(props.defaultParamItem).every((e) => lastData[e] === props.defaultParamItem[e])
|
? isEqual(lastData, props.defaultParamItem)
|
||||||
: JSON.stringify(lastData[key]) === JSON.stringify(props.defaultParamItem[key]);
|
: isEqual(lastData[key], props.defaultParamItem[key]);
|
||||||
if (isForce || (val !== '' && !isNotChange)) {
|
if (isForce || (val !== '' && !isNotChange)) {
|
||||||
propsRes.value.data.push({
|
propsRes.value.data.push({
|
||||||
id: new Date().getTime(),
|
id: new Date().getTime(),
|
||||||
|
@ -455,6 +439,32 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.params,
|
||||||
|
(val) => {
|
||||||
|
if (val.length > 0) {
|
||||||
|
const lastData = { ...val[val.length - 1] };
|
||||||
|
delete lastData.id; // 删除 id 属性,避免影响判断是否有变化
|
||||||
|
const isNotChange = isEqual(lastData, props.defaultParamItem);
|
||||||
|
propsRes.value.data = val;
|
||||||
|
if (!isNotChange) {
|
||||||
|
addTableLine();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
propsRes.value.data = [
|
||||||
|
{
|
||||||
|
id: new Date().getTime(), // 默认给时间戳 id,若 props.defaultParamItem 有 id,则覆盖
|
||||||
|
...props.defaultParamItem,
|
||||||
|
},
|
||||||
|
] as any[];
|
||||||
|
emit('change', propsRes.value.data, true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const showQuickInputParam = ref(false);
|
const showQuickInputParam = ref(false);
|
||||||
const activeQuickInputRecord = ref<any>({});
|
const activeQuickInputRecord = ref<any>({});
|
||||||
const quickInputParamValue = ref('');
|
const quickInputParamValue = ref('');
|
||||||
|
|
|
@ -72,7 +72,7 @@
|
||||||
{
|
{
|
||||||
title: 'apiTestDebug.maxConnection',
|
title: 'apiTestDebug.maxConnection',
|
||||||
dataIndex: 'maxConnection',
|
dataIndex: 'maxConnection',
|
||||||
width: 110,
|
width: 140,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'apiTestDebug.timeout',
|
title: 'apiTestDebug.timeout',
|
||||||
|
|
|
@ -329,14 +329,20 @@ Date: Wed, 13 Dec 2023 08:53:25 GMT`,
|
||||||
activeDebug.value.unSaved = true;
|
activeDebug.value.unSaved = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function addDebugTab() {
|
function addDebugTab(defaultProps?: Partial<TabItem>) {
|
||||||
const id = `debug-${Date.now()}`;
|
const id = `debug-${Date.now()}`;
|
||||||
debugTabs.value.push({
|
debugTabs.value.push({
|
||||||
...cloneDeep(defaultDebugParams),
|
...cloneDeep(defaultDebugParams),
|
||||||
module: props.module,
|
module: props.module,
|
||||||
id,
|
id,
|
||||||
|
...defaultProps,
|
||||||
});
|
});
|
||||||
activeRequestTab.value = id;
|
activeRequestTab.value = id;
|
||||||
|
nextTick(() => {
|
||||||
|
if (defaultProps) {
|
||||||
|
handleActiveDebugChange();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeDebugTab(tab: TabItem) {
|
function closeDebugTab(tab: TabItem) {
|
||||||
|
|
|
@ -82,6 +82,7 @@
|
||||||
title: 'apiTestDebug.paramLengthRange',
|
title: 'apiTestDebug.paramLengthRange',
|
||||||
dataIndex: 'lengthRange',
|
dataIndex: 'lengthRange',
|
||||||
slotName: 'lengthRange',
|
slotName: 'lengthRange',
|
||||||
|
align: 'center',
|
||||||
width: 200,
|
width: 200,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -82,6 +82,7 @@
|
||||||
title: 'apiTestDebug.paramLengthRange',
|
title: 'apiTestDebug.paramLengthRange',
|
||||||
dataIndex: 'lengthRange',
|
dataIndex: 'lengthRange',
|
||||||
slotName: 'lengthRange',
|
slotName: 'lengthRange',
|
||||||
|
align: 'center',
|
||||||
width: 200,
|
width: 200,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -120,7 +120,7 @@
|
||||||
modulesCount?: Record<string, number>; // 模块数量统计对象
|
modulesCount?: Record<string, number>; // 模块数量统计对象
|
||||||
isExpandAll?: boolean; // 是否展开所有节点
|
isExpandAll?: boolean; // 是否展开所有节点
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits(['init', 'change', 'newApi']);
|
const emit = defineEmits(['init', 'change', 'newApi', 'import']);
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -132,6 +132,7 @@
|
||||||
emit('newApi');
|
emit('newApi');
|
||||||
break;
|
break;
|
||||||
case 'import':
|
case 'import':
|
||||||
|
emit('import');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -3,7 +3,12 @@
|
||||||
<MsSplitBox :size="0.25" :max="0.5">
|
<MsSplitBox :size="0.25" :max="0.5">
|
||||||
<template #first>
|
<template #first>
|
||||||
<div class="p-[24px]">
|
<div class="p-[24px]">
|
||||||
<moduleTree @init="(val) => (folderTree = val)" @new-api="newApi" @change="(val) => (activeModule = val)" />
|
<moduleTree
|
||||||
|
@init="(val) => (folderTree = val)"
|
||||||
|
@new-api="newApi"
|
||||||
|
@change="(val) => (activeModule = val)"
|
||||||
|
@import="importDrawerVisible = true"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #second>
|
<template #second>
|
||||||
|
@ -13,23 +18,99 @@
|
||||||
</template>
|
</template>
|
||||||
</MsSplitBox>
|
</MsSplitBox>
|
||||||
</MsCard>
|
</MsCard>
|
||||||
|
<MsDrawer
|
||||||
|
v-model:visible="importDrawerVisible"
|
||||||
|
:width="680"
|
||||||
|
:ok-disabled="curlCode.trim() === ''"
|
||||||
|
disabled-width-drag
|
||||||
|
@cancel="curlCode = ''"
|
||||||
|
@confirm="handleCurlImportConfirm"
|
||||||
|
>
|
||||||
|
<template #title>
|
||||||
|
<a-tooltip position="right" :content="t('apiTestDebug.importByCURLTip')">
|
||||||
|
{{ t('apiTestDebug.importByCURL') }}
|
||||||
|
<icon-exclamation-circle
|
||||||
|
class="ml-[4px] text-[var(--color-text-brand)] hover:text-[rgb(var(--primary-5))]"
|
||||||
|
size="16"
|
||||||
|
/>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<div class="h-full">
|
||||||
|
<MsCodeEditor
|
||||||
|
v-if="importDrawerVisible"
|
||||||
|
v-model:model-value="curlCode"
|
||||||
|
theme="MS-text"
|
||||||
|
height="100%"
|
||||||
|
language="plaintext"
|
||||||
|
:show-theme-change="false"
|
||||||
|
:show-full-screen="false"
|
||||||
|
>
|
||||||
|
</MsCodeEditor>
|
||||||
|
</div>
|
||||||
|
</MsDrawer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import MsCard from '@/components/pure/ms-card/index.vue';
|
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||||
|
import MsCodeEditor from '@/components/pure/ms-code-editor/index.vue';
|
||||||
|
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||||
import MsSplitBox from '@/components/pure/ms-split-box/index.vue';
|
import MsSplitBox from '@/components/pure/ms-split-box/index.vue';
|
||||||
import debug from './components/debug/index.vue';
|
import debug from './components/debug/index.vue';
|
||||||
import moduleTree from './components/moduleTree.vue';
|
import moduleTree from './components/moduleTree.vue';
|
||||||
|
|
||||||
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
import { parseCurlScript } from '@/utils';
|
||||||
|
|
||||||
import { ModuleTreeNode } from '@/models/projectManagement/file';
|
import { ModuleTreeNode } from '@/models/projectManagement/file';
|
||||||
|
import { RequestContentTypeEnum } from '@/enums/apiEnum';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
const debugRef = ref<InstanceType<typeof debug>>();
|
const debugRef = ref<InstanceType<typeof debug>>();
|
||||||
const activeModule = ref<string>('root');
|
const activeModule = ref<string>('root');
|
||||||
const folderTree = ref<ModuleTreeNode[]>([]);
|
const folderTree = ref<ModuleTreeNode[]>([]);
|
||||||
|
const importDrawerVisible = ref(false);
|
||||||
|
const curlCode = ref('');
|
||||||
|
|
||||||
function newApi() {
|
function newApi() {
|
||||||
debugRef.value?.addDebugTab();
|
debugRef.value?.addDebugTab();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleCurlImportConfirm() {
|
||||||
|
const { url, headers, queryParameters } = parseCurlScript(curlCode.value);
|
||||||
|
debugRef.value?.addDebugTab({
|
||||||
|
url,
|
||||||
|
headerParams: headers?.map((e) => ({
|
||||||
|
required: false,
|
||||||
|
type: 'string',
|
||||||
|
min: undefined,
|
||||||
|
max: undefined,
|
||||||
|
contentType: RequestContentTypeEnum.TEXT,
|
||||||
|
tag: [],
|
||||||
|
desc: '',
|
||||||
|
encode: false,
|
||||||
|
enable: false,
|
||||||
|
mustContain: false,
|
||||||
|
...e,
|
||||||
|
})),
|
||||||
|
value: '',
|
||||||
|
queryParams: queryParameters?.map((e) => ({
|
||||||
|
required: false,
|
||||||
|
type: 'string',
|
||||||
|
min: undefined,
|
||||||
|
max: undefined,
|
||||||
|
contentType: RequestContentTypeEnum.TEXT,
|
||||||
|
tag: [],
|
||||||
|
desc: '',
|
||||||
|
encode: false,
|
||||||
|
enable: false,
|
||||||
|
mustContain: false,
|
||||||
|
...e,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
curlCode.value = '';
|
||||||
|
importDrawerVisible.value = false;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
<style lang="less" scoped></style>
|
||||||
|
|
|
@ -7,8 +7,8 @@ export default {
|
||||||
'apiTestDebug.noMatchModule': 'No matching module data yet',
|
'apiTestDebug.noMatchModule': 'No matching module data yet',
|
||||||
'apiTestDebug.header': 'Header',
|
'apiTestDebug.header': 'Header',
|
||||||
'apiTestDebug.body': 'Body',
|
'apiTestDebug.body': 'Body',
|
||||||
'apiTestDebug.prefix': 'Prefix',
|
'apiTestDebug.prefix': 'Precondition',
|
||||||
'apiTestDebug.post': 'Post',
|
'apiTestDebug.post': 'Postcondition',
|
||||||
'apiTestDebug.assertion': 'Assertion',
|
'apiTestDebug.assertion': 'Assertion',
|
||||||
'apiTestDebug.auth': 'Auth',
|
'apiTestDebug.auth': 'Auth',
|
||||||
'apiTestDebug.setting': 'Setting',
|
'apiTestDebug.setting': 'Setting',
|
||||||
|
@ -22,6 +22,15 @@ export default {
|
||||||
'apiTestDebug.paramValuePlaceholder': 'Starting with {at}, double-click to quickly enter',
|
'apiTestDebug.paramValuePlaceholder': 'Starting with {at}, double-click to quickly enter',
|
||||||
'apiTestDebug.paramValuePreview': 'Parameter preview',
|
'apiTestDebug.paramValuePreview': 'Parameter preview',
|
||||||
'apiTestDebug.desc': 'Description',
|
'apiTestDebug.desc': 'Description',
|
||||||
|
'apiTestDebug.paramRequired': 'Required',
|
||||||
|
'apiTestDebug.paramNotRequired': 'Optional',
|
||||||
|
'apiTestDebug.paramType': 'Param type',
|
||||||
|
'apiTestDebug.paramLengthRange': 'Length range',
|
||||||
|
'apiTestDebug.paramMin': 'Min',
|
||||||
|
'apiTestDebug.paramMax': 'Max',
|
||||||
|
'apiTestDebug.encode': 'Encoding',
|
||||||
|
'apiTestDebug.encodeTip1': 'On: Use encoding',
|
||||||
|
'apiTestDebug.encodeTip2': 'Off: No encoding is used',
|
||||||
'apiTestDebug.apply': 'Apply',
|
'apiTestDebug.apply': 'Apply',
|
||||||
'apiTestDebug.batchAddParamsTip': 'Writing format: parameter name: parameter value; such as nama: natural',
|
'apiTestDebug.batchAddParamsTip': 'Writing format: parameter name: parameter value; such as nama: natural',
|
||||||
'apiTestDebug.batchAddParamsTip2': 'Multiple records are separated by newlines.',
|
'apiTestDebug.batchAddParamsTip2': 'Multiple records are separated by newlines.',
|
||||||
|
@ -29,4 +38,146 @@ export default {
|
||||||
'Parameter names in batch addition are repeated. By default, the last data is the latest data.',
|
'Parameter names in batch addition are repeated. By default, the last data is the latest data.',
|
||||||
'apiTestDebug.quickInputParamsTip': 'Support Mock/JMeter/Json/Text/String, etc.',
|
'apiTestDebug.quickInputParamsTip': 'Support Mock/JMeter/Json/Text/String, etc.',
|
||||||
'apiTestDebug.descPlaceholder': 'Please enter content',
|
'apiTestDebug.descPlaceholder': 'Please enter content',
|
||||||
|
'apiTestDebug.noneBody': 'Request without Body',
|
||||||
|
'apiTestDebug.sendAsMainText': 'Send as main text',
|
||||||
|
'apiTestDebug.sendAsMainTextTip1':
|
||||||
|
'Enable: Directly read the file content and display it in the response body, such as: files in image format',
|
||||||
|
'apiTestDebug.sendAsMainTextTip2': 'Close: Return as download file',
|
||||||
|
'apiTestDebug.queryTip': 'In the address bar followed by ? The following parameters, such as updateapi?id=112',
|
||||||
|
'apiTestDebug.restTip': 'Parameters separated by slash/ in the address bar, such as updateapi/{id}',
|
||||||
|
'apiTestDebug.authType': 'Authentication',
|
||||||
|
'apiTestDebug.account': 'Account',
|
||||||
|
'apiTestDebug.accountRequired': 'Account cannot be empty',
|
||||||
|
'apiTestDebug.password': 'Password',
|
||||||
|
'apiTestDebug.passwordRequired': 'Password cannot be empty',
|
||||||
|
'apiTestDebug.commonPlaceholder': 'Please enter',
|
||||||
|
'apiTestDebug.connectTimeout': 'Connection timed out',
|
||||||
|
'apiTestDebug.responseTimeout': 'Response timeout',
|
||||||
|
'apiTestDebug.certificateAlias': 'Certificate alias',
|
||||||
|
'apiTestDebug.redirect': 'Redirect',
|
||||||
|
'apiTestDebug.follow': 'Follow',
|
||||||
|
'apiTestDebug.auto': 'Auto',
|
||||||
|
'apiTestDebug.precondition': 'Precondition',
|
||||||
|
'apiTestDebug.openGlobalPrecondition': 'Enable global precondition',
|
||||||
|
'apiTestDebug.openGlobalPreconditionTip':
|
||||||
|
'It is enabled by default. If it is disabled, the global precondition will not be executed when running this interface.',
|
||||||
|
'apiTestDebug.sql': 'SQL',
|
||||||
|
'apiTestDebug.sqlScript': 'SQL script',
|
||||||
|
'apiTestDebug.waitTime': 'Wait time',
|
||||||
|
'apiTestDebug.script': 'Script',
|
||||||
|
'apiTestDebug.preconditionScriptName': 'Pre-script name',
|
||||||
|
'apiTestDebug.preconditionScriptNamePlaceholder': 'Please enter the pre-script name',
|
||||||
|
'apiTestDebug.manual': 'Manual entry',
|
||||||
|
'apiTestDebug.quote': 'Quoting public scripts',
|
||||||
|
'apiTestDebug.commonScriptList': 'Public script list',
|
||||||
|
'apiTestDebug.scriptEx': 'Script case',
|
||||||
|
'apiTestDebug.copyNotSupport': 'Your browser does not support automatic copying, please copy manually',
|
||||||
|
'apiTestDebug.scriptExCopySuccess': 'Script case copied',
|
||||||
|
'apiTestDebug.parameters': 'Pass parameters',
|
||||||
|
'apiTestDebug.scriptContent': 'Script content',
|
||||||
|
'apiTestDebug.introduceSource': 'Introduce data sources',
|
||||||
|
'apiTestDebug.quoteSource': 'Reference data source',
|
||||||
|
'apiTestDebug.sourceList': 'Data source list',
|
||||||
|
'apiTestDebug.quoteSourcePlaceholder': 'Please select a data source',
|
||||||
|
'apiTestDebug.storageType': 'Storage method',
|
||||||
|
'apiTestDebug.storageTypeTip1':
|
||||||
|
'Store by column: Specify the names of columns extracted from the database result set; multiple columns can be separated by ","',
|
||||||
|
'apiTestDebug.storageTypeTip2':
|
||||||
|
'Store by result: Save the entire result set as a variable instead of saving each column value as a separate variable',
|
||||||
|
'apiTestDebug.storageByCol': 'Store by columns',
|
||||||
|
'apiTestDebug.storageByColPlaceholder': 'For example, {a} is changed to {b}',
|
||||||
|
'apiTestDebug.storageByResult': 'Store by result',
|
||||||
|
'apiTestDebug.storageByResultPlaceholder': 'Such as {a}',
|
||||||
|
'apiTestDebug.extractParameter': 'Extract',
|
||||||
|
'apiTestDebug.searchTip': 'Please enter a group name',
|
||||||
|
'apiTestDebug.allRequest': 'All requests',
|
||||||
|
'apiTestDebug.deleteFolderTipTitle': 'Remove the `{name}` module?',
|
||||||
|
'apiTestDebug.deleteFolderTipContent':
|
||||||
|
'This operation will delete the module and all resources under it, please operate with caution!',
|
||||||
|
'apiTestDebug.deleteConfirm': 'Confirm delete',
|
||||||
|
'apiTestDebug.deleteSuccess': 'Successfully deleted',
|
||||||
|
'apiTestDebug.moduleMoveSuccess': 'Module moved successfully',
|
||||||
|
'apiTestDebug.sqlSourceName': 'Data source name',
|
||||||
|
'apiTestDebug.driver': 'Drive',
|
||||||
|
'apiTestDebug.username': 'Username',
|
||||||
|
'apiTestDebug.maxConnection': 'Max connections',
|
||||||
|
'apiTestDebug.timeout': 'Timeout (ms)',
|
||||||
|
'apiTestDebug.postCondition': 'Postcondition',
|
||||||
|
'apiTestDebug.openGlobalPostCondition': 'Enable global postcondition',
|
||||||
|
'apiTestDebug.openGlobalPostConditionTip':
|
||||||
|
'It is enabled by default. If it is disabled, the global post-processing will not be executed when running this interface.',
|
||||||
|
'apiTestDebug.globalParameter': 'Global parameter',
|
||||||
|
'apiTestDebug.envParameter': 'Env parameters',
|
||||||
|
'apiTestDebug.tempParameter': 'Temporary parameters',
|
||||||
|
'apiTestDebug.mode': 'Type',
|
||||||
|
'apiTestDebug.range': 'Scope',
|
||||||
|
'apiTestDebug.expression': 'Expression',
|
||||||
|
'apiTestDebug.expressionTip1': 'Reason for unavailability:',
|
||||||
|
'apiTestDebug.expressionTip2': '1. Interface not implemented',
|
||||||
|
'apiTestDebug.expressionTip3': '2. There is no data in the response content',
|
||||||
|
'apiTestDebug.regular': 'Regular',
|
||||||
|
'apiTestDebug.fastExtraction': 'Quick extraction',
|
||||||
|
'apiTestDebug.regularExpression': 'Regular expression',
|
||||||
|
'apiTestDebug.regularExpressionRequired': 'Regular expression cannot be empty',
|
||||||
|
'apiTestDebug.regularExpressionPlaceholder': 'Such as {ex}',
|
||||||
|
'apiTestDebug.test': 'Test',
|
||||||
|
'apiTestDebug.JSONPathRequired': 'JSONPath cannot be empty',
|
||||||
|
'apiTestDebug.JSONPathPlaceholder': 'Such as $.users',
|
||||||
|
'apiTestDebug.XPathRequired': 'XPath cannot be empty',
|
||||||
|
'apiTestDebug.XPathPlaceholder': 'Such as /books/book[1]/title',
|
||||||
|
'apiTestDebug.matchResult': 'Match results',
|
||||||
|
'apiTestDebug.noMatchResult': 'No matching results',
|
||||||
|
'apiTestDebug.matchExpressionTip':
|
||||||
|
'{prefix} Gets the complete expression for matching, including all tag contents in the expression',
|
||||||
|
'apiTestDebug.matchGroupTip':
|
||||||
|
'{prefix} Gets the matching group in the expression for matching, including only the regular content in the expression',
|
||||||
|
'apiTestDebug.matchExpression': 'Matching expression',
|
||||||
|
'apiTestDebug.matchGroup': 'Matching group',
|
||||||
|
'apiTestDebug.moreSetting': 'More settings',
|
||||||
|
'apiTestDebug.expressionMatchRule': 'Expression matching rules',
|
||||||
|
'apiTestDebug.resultMatchRule': 'Result matching rules',
|
||||||
|
'apiTestDebug.randomMatch': 'Random match',
|
||||||
|
'apiTestDebug.randomMatchTip': 'Get any matching result',
|
||||||
|
'apiTestDebug.specifyMatch': 'Specify match',
|
||||||
|
'apiTestDebug.specifyMatchResult': 'Specify matching results',
|
||||||
|
'apiTestDebug.index': 'No.',
|
||||||
|
'apiTestDebug.unit': 'item',
|
||||||
|
'apiTestDebug.specifyMatchTip':
|
||||||
|
'The Nth matching result needs to be specified. If it exceeds the specified number, it will return empty.',
|
||||||
|
'apiTestDebug.allMatch': 'Match all',
|
||||||
|
'apiTestDebug.allMatchTip': 'The regular return is an array of matching results.',
|
||||||
|
'apiTestDebug.contentType': 'Response content format',
|
||||||
|
'apiTestDebug.responseTime': 'Response time',
|
||||||
|
'apiTestDebug.responseStage': 'Stage',
|
||||||
|
'apiTestDebug.time': 'Duration',
|
||||||
|
'apiTestDebug.ready': 'Preparation stage',
|
||||||
|
'apiTestDebug.socketInit': 'Socket init',
|
||||||
|
'apiTestDebug.dnsQuery': 'DNS query',
|
||||||
|
'apiTestDebug.tcpHandshake': 'TCP handshake',
|
||||||
|
'apiTestDebug.sslHandshake': 'SSL handshake',
|
||||||
|
'apiTestDebug.waitingTTFB': 'Waiting (TTFB)',
|
||||||
|
'apiTestDebug.downloadContent': 'Content download',
|
||||||
|
'apiTestDebug.deal': 'Deal with',
|
||||||
|
'apiTestDebug.total': 'Total',
|
||||||
|
'apiTestDebug.responseBody': 'Response body',
|
||||||
|
'apiTestDebug.responseHeader': 'Response header',
|
||||||
|
'apiTestDebug.realRequest': 'Real request',
|
||||||
|
'apiTestDebug.console': 'Console',
|
||||||
|
'apiTestDebug.extract': 'Extract',
|
||||||
|
'apiTestDebug.statusCode': 'Status code',
|
||||||
|
'apiTestDebug.responseSize': 'Response size',
|
||||||
|
'apiTestDebug.runningEnv': 'Operating environment',
|
||||||
|
'apiTestDebug.resourcePool': 'Resource pool',
|
||||||
|
'apiTestDebug.content': 'Content',
|
||||||
|
'apiTestDebug.status': 'Status',
|
||||||
|
'apiTestDebug.requestName': 'Request name',
|
||||||
|
'apiTestDebug.requestNameRequired': 'Request name cannot be empty',
|
||||||
|
'apiTestDebug.requestNamePlaceholder': 'Please enter a request name',
|
||||||
|
'apiTestDebug.requestUrl': 'Request URL',
|
||||||
|
'apiTestDebug.requestUrlRequired': 'Request URL cannot be empty',
|
||||||
|
'apiTestDebug.requestModule': 'Belonging module',
|
||||||
|
'apiTestDebug.closeOther': 'Close other',
|
||||||
|
'apiTestDebug.importByCURL': 'Import cURL',
|
||||||
|
'apiTestDebug.importByCURLTip':
|
||||||
|
'Supports quick import of packet capture data from tools such as Chrome, Charles or Fiddler',
|
||||||
};
|
};
|
||||||
|
|
|
@ -63,7 +63,7 @@ export default {
|
||||||
'apiTestDebug.waitTime': '等待时间',
|
'apiTestDebug.waitTime': '等待时间',
|
||||||
'apiTestDebug.script': '脚本操作',
|
'apiTestDebug.script': '脚本操作',
|
||||||
'apiTestDebug.preconditionScriptName': '前置脚本名称',
|
'apiTestDebug.preconditionScriptName': '前置脚本名称',
|
||||||
'apiTestDebug.preconditionScriptNamePlaceholder': '前置脚本名称',
|
'apiTestDebug.preconditionScriptNamePlaceholder': '请输入前置脚本名称',
|
||||||
'apiTestDebug.manual': '手动录入',
|
'apiTestDebug.manual': '手动录入',
|
||||||
'apiTestDebug.quote': '引用公共脚本',
|
'apiTestDebug.quote': '引用公共脚本',
|
||||||
'apiTestDebug.commonScriptList': '公共脚本列表',
|
'apiTestDebug.commonScriptList': '公共脚本列表',
|
||||||
|
@ -139,8 +139,8 @@ export default {
|
||||||
'apiTestDebug.contentType': '响应内容格式',
|
'apiTestDebug.contentType': '响应内容格式',
|
||||||
'apiTestDebug.responseTime': '响应时间',
|
'apiTestDebug.responseTime': '响应时间',
|
||||||
'apiTestDebug.responseStage': '阶段',
|
'apiTestDebug.responseStage': '阶段',
|
||||||
'apiTestDebug.time': '时间',
|
'apiTestDebug.time': '耗时',
|
||||||
'apiTestDebug.ready': '准备',
|
'apiTestDebug.ready': '准备阶段',
|
||||||
'apiTestDebug.socketInit': 'Socket 初始化',
|
'apiTestDebug.socketInit': 'Socket 初始化',
|
||||||
'apiTestDebug.dnsQuery': 'DNS 查询',
|
'apiTestDebug.dnsQuery': 'DNS 查询',
|
||||||
'apiTestDebug.tcpHandshake': 'TCP 握手',
|
'apiTestDebug.tcpHandshake': 'TCP 握手',
|
||||||
|
@ -167,4 +167,6 @@ export default {
|
||||||
'apiTestDebug.requestUrlRequired': '请求 URL不能为空',
|
'apiTestDebug.requestUrlRequired': '请求 URL不能为空',
|
||||||
'apiTestDebug.requestModule': '请求所属模块',
|
'apiTestDebug.requestModule': '请求所属模块',
|
||||||
'apiTestDebug.closeOther': '关闭其他请求',
|
'apiTestDebug.closeOther': '关闭其他请求',
|
||||||
|
'apiTestDebug.importByCURL': '导入 cURL',
|
||||||
|
'apiTestDebug.importByCURLTip': '支持快速导入 Chrome、Charles 或 Fiddler 等工具中的抓包数据',
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue