feat(接口管理): 插件增删改查接口联调
This commit is contained in:
parent
33fda25e5f
commit
e0d1d6f3ed
|
@ -170,7 +170,6 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useVModel } from '@vueuse/core';
|
|
||||||
import { Message, TagData } from '@arco-design/web-vue';
|
import { Message, TagData } from '@arco-design/web-vue';
|
||||||
|
|
||||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||||
|
@ -281,9 +280,10 @@
|
||||||
label: fileItem[props.fields.name] || fileItem.name || '',
|
label: fileItem[props.fields.name] || fileItem.name || '',
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
innerFileList.value = [fileItem];
|
||||||
inputFileName.value = fileItem.name || '';
|
inputFileName.value = fileItem.name || '';
|
||||||
}
|
}
|
||||||
emit('change', _fileList, { ...fileItem, local: true });
|
emit('change', innerFileList.value, { ...fileItem, local: true });
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
// 在 emit 文件上去之后再关闭菜单
|
// 在 emit 文件上去之后再关闭菜单
|
||||||
buttonDropDownVisible.value = false;
|
buttonDropDownVisible.value = false;
|
||||||
|
@ -302,7 +302,7 @@
|
||||||
// 监视文件列表处理关联和本地文件
|
// 监视文件列表处理关联和本地文件
|
||||||
watch(
|
watch(
|
||||||
() => innerFileList.value,
|
() => innerFileList.value,
|
||||||
() => {
|
(arr) => {
|
||||||
getListFunParams.value.combine.hiddenIds = innerFileList.value
|
getListFunParams.value.combine.hiddenIds = innerFileList.value
|
||||||
.filter((item) => !item.local)
|
.filter((item) => !item.local)
|
||||||
.map((item) => item[props.fields.id] || item.uid);
|
.map((item) => item[props.fields.id] || item.uid);
|
||||||
|
|
|
@ -269,6 +269,7 @@ export interface TimeWaitingProcessor extends ExecuteConditionProcessorCommon {
|
||||||
export type ExpressionType = RequestExtractExpressionEnum;
|
export type ExpressionType = RequestExtractExpressionEnum;
|
||||||
// 表达式配置
|
// 表达式配置
|
||||||
export interface ExpressionCommonConfig {
|
export interface ExpressionCommonConfig {
|
||||||
|
id?: number | string; // 前端渲染使用字段
|
||||||
enable: boolean; // 是否启用
|
enable: boolean; // 是否启用
|
||||||
expression: string;
|
expression: string;
|
||||||
extractType: ExpressionType; // 表达式类型
|
extractType: ExpressionType; // 表达式类型
|
||||||
|
|
|
@ -41,10 +41,10 @@
|
||||||
const config = statusMap[props.status];
|
const config = statusMap[props.status];
|
||||||
return {
|
return {
|
||||||
style: {
|
style: {
|
||||||
backgroundColor: config.bgColor,
|
backgroundColor: config?.bgColor,
|
||||||
color: config.color,
|
color: config?.color,
|
||||||
},
|
},
|
||||||
text: t(config.text),
|
text: t(config?.text),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -244,7 +244,7 @@
|
||||||
<div v-else-if="condition.processorType === RequestConditionProcessor.EXTRACT">
|
<div v-else-if="condition.processorType === RequestConditionProcessor.EXTRACT">
|
||||||
<paramTable
|
<paramTable
|
||||||
ref="extractParamsTableRef"
|
ref="extractParamsTableRef"
|
||||||
v-model:params="condition.extractParams"
|
v-model:params="condition.extractors"
|
||||||
:default-param-item="defaultExtractParamItem"
|
:default-param-item="defaultExtractParamItem"
|
||||||
:columns="extractParamsColumns"
|
:columns="extractParamsColumns"
|
||||||
:selectable="false"
|
:selectable="false"
|
||||||
|
@ -272,6 +272,7 @@
|
||||||
v-model:model-value="record.expression"
|
v-model:model-value="record.expression"
|
||||||
class="ms-params-input"
|
class="ms-params-input"
|
||||||
:max-length="255"
|
:max-length="255"
|
||||||
|
size="mini"
|
||||||
@input="() => handleExpressionChange(rowIndex)"
|
@input="() => handleExpressionChange(rowIndex)"
|
||||||
@change="() => handleExpressionChange(rowIndex)"
|
@change="() => handleExpressionChange(rowIndex)"
|
||||||
>
|
>
|
||||||
|
@ -649,7 +650,7 @@ if (!result){
|
||||||
const disabledExpressionSuffix = ref(false);
|
const disabledExpressionSuffix = ref(false);
|
||||||
|
|
||||||
function handleExtractParamTableChange(resultArr: any[], isInit?: boolean) {
|
function handleExtractParamTableChange(resultArr: any[], isInit?: boolean) {
|
||||||
condition.value.extractParams = [...resultArr];
|
condition.value.extractors = [...resultArr];
|
||||||
if (!isInit) {
|
if (!isInit) {
|
||||||
emit('change');
|
emit('change');
|
||||||
}
|
}
|
||||||
|
@ -697,13 +698,13 @@ if (!result){
|
||||||
* 提取参数表格-应用更多设置
|
* 提取参数表格-应用更多设置
|
||||||
*/
|
*/
|
||||||
function applyMoreSetting(record: ExpressionConfig) {
|
function applyMoreSetting(record: ExpressionConfig) {
|
||||||
condition.value.extractParams = condition.value.extractParams?.map((e) => {
|
condition.value.extractors = condition.value.extractors?.map((e) => {
|
||||||
if (e.id === activeRecord.value.id) {
|
if (e.id === activeRecord.value.id) {
|
||||||
record.moreSettingPopoverVisible = false;
|
record.moreSettingPopoverVisible = false;
|
||||||
return {
|
return {
|
||||||
...activeRecord.value,
|
...activeRecord.value,
|
||||||
moreSettingPopoverVisible: false,
|
moreSettingPopoverVisible: false,
|
||||||
} as any; // TOOD: 这里的后台类型应该是不对的,需要修改
|
};
|
||||||
}
|
}
|
||||||
return e;
|
return e;
|
||||||
});
|
});
|
||||||
|
@ -714,7 +715,7 @@ if (!result){
|
||||||
* 提取参数表格-保存快速提取的配置
|
* 提取参数表格-保存快速提取的配置
|
||||||
*/
|
*/
|
||||||
function handleFastExtractionApply(config: RegexExtract | JSONPathExtract | XPathExtract) {
|
function handleFastExtractionApply(config: RegexExtract | JSONPathExtract | XPathExtract) {
|
||||||
condition.value.extractParams = condition.value.extractParams?.map((e) => {
|
condition.value.extractors = condition.value.extractors?.map((e) => {
|
||||||
if (e.id === activeRecord.value.id) {
|
if (e.id === activeRecord.value.id) {
|
||||||
return {
|
return {
|
||||||
...e,
|
...e,
|
||||||
|
@ -726,7 +727,7 @@ if (!result){
|
||||||
fastExtractionVisible.value = false;
|
fastExtractionVisible.value = false;
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
extractParamsTableRef.value?.addTableLine(
|
extractParamsTableRef.value?.addTableLine(
|
||||||
condition.value.extractParams?.findIndex((e) => e.id === activeRecord.value.id) || 0
|
condition.value.extractors?.findIndex((e) => e.id === activeRecord.value.id) || 0
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
emit('change');
|
emit('change');
|
||||||
|
|
|
@ -120,20 +120,23 @@
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
// case RequestConditionProcessor.SQL:
|
case RequestConditionProcessor.SQL:
|
||||||
// data.value.push({
|
data.value.push({
|
||||||
// id,
|
id,
|
||||||
// enableCommonScript: false,
|
processorType: RequestConditionProcessor.SQL,
|
||||||
// desc: '',
|
enableCommonScript: false,
|
||||||
// enable: true,
|
description: '',
|
||||||
// sqlSource: {
|
enable: true,
|
||||||
// scriptName: '',
|
dataSourceId: '',
|
||||||
// script: '',
|
environmentId: '',
|
||||||
// storageType: 'column',
|
queryTimeout: 0,
|
||||||
// params: [],
|
resultVariable: '',
|
||||||
// },
|
script: '',
|
||||||
// });
|
variableNames: '',
|
||||||
// break;
|
variables: [],
|
||||||
|
extractParams: [],
|
||||||
|
});
|
||||||
|
break;
|
||||||
case RequestConditionProcessor.TIME_WAITING:
|
case RequestConditionProcessor.TIME_WAITING:
|
||||||
data.value.push({
|
data.value.push({
|
||||||
id,
|
id,
|
||||||
|
|
|
@ -216,12 +216,13 @@
|
||||||
break;
|
break;
|
||||||
case RequestExtractExpressionEnum.JSON_PATH:
|
case RequestExtractExpressionEnum.JSON_PATH:
|
||||||
try {
|
try {
|
||||||
matchResult.value = JSONPath({
|
matchResult.value =
|
||||||
|
JSONPath({
|
||||||
json: props.response ? JSON.parse(props.response) : '',
|
json: props.response ? JSON.parse(props.response) : '',
|
||||||
path: expressionForm.value.expression,
|
path: expressionForm.value.expression,
|
||||||
});
|
}) || [];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
matchResult.value = JSONPath({ json: props.response || '', path: expressionForm.value.expression });
|
matchResult.value = JSONPath({ json: props.response || '', path: expressionForm.value.expression }) || [];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case RequestExtractExpressionEnum.REGEX:
|
case RequestExtractExpressionEnum.REGEX:
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
{{ t('apiTestDebug.expressionMatchRule') }}
|
{{ t('apiTestDebug.expressionMatchRule') }}
|
||||||
</div>
|
</div>
|
||||||
<a-radio-group v-model:model-value="expressionForm.expressionMatchingRule" size="small">
|
<a-radio-group v-model:model-value="expressionForm.expressionMatchingRule" size="small">
|
||||||
<a-radio :value="RequestExtractExpressionRuleType.EXPRESSION.toLowerCase()">
|
<a-radio :value="RequestExtractExpressionRuleType.EXPRESSION">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
{{ t('apiTestDebug.matchExpression') }}
|
{{ t('apiTestDebug.matchExpression') }}
|
||||||
<a-tooltip :content="t('apiTestDebug.matchExpressionTip')" :content-style="{ maxWidth: '500px' }">
|
<a-tooltip :content="t('apiTestDebug.matchExpressionTip')" :content-style="{ maxWidth: '500px' }">
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</a-radio>
|
</a-radio>
|
||||||
<a-radio :value="RequestExtractExpressionRuleType.GROUP.toLowerCase()">
|
<a-radio :value="RequestExtractExpressionRuleType.GROUP">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
{{ t('apiTestDebug.matchGroup') }}
|
{{ t('apiTestDebug.matchGroup') }}
|
||||||
<a-tooltip :content="t('apiTestDebug.matchGroupTip')" :content-style="{ maxWidth: '500px' }">
|
<a-tooltip :content="t('apiTestDebug.matchGroupTip')" :content-style="{ maxWidth: '500px' }">
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
{{ t('apiTestDebug.resultMatchRule') }}
|
{{ t('apiTestDebug.resultMatchRule') }}
|
||||||
</div>
|
</div>
|
||||||
<a-radio-group v-model:model-value="expressionForm.resultMatchingRule" size="small">
|
<a-radio-group v-model:model-value="expressionForm.resultMatchingRule" size="small">
|
||||||
<a-radio :value="RequestExtractResultMatchingRule.RANDOM.toLowerCase()">
|
<a-radio :value="RequestExtractResultMatchingRule.RANDOM">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
{{ t('apiTestDebug.randomMatch') }}
|
{{ t('apiTestDebug.randomMatch') }}
|
||||||
<a-tooltip :content="t('apiTestDebug.randomMatchTip')" :content-style="{ maxWidth: '400px' }">
|
<a-tooltip :content="t('apiTestDebug.randomMatchTip')" :content-style="{ maxWidth: '400px' }">
|
||||||
|
@ -45,7 +45,7 @@
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</a-radio>
|
</a-radio>
|
||||||
<a-radio :value="RequestExtractResultMatchingRule.SPECIFIC.toLowerCase()">
|
<a-radio :value="RequestExtractResultMatchingRule.SPECIFIC">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
{{ t('apiTestDebug.specifyMatch') }}
|
{{ t('apiTestDebug.specifyMatch') }}
|
||||||
<a-tooltip :content="t('apiTestDebug.specifyMatchTip')" :content-style="{ maxWidth: '400px' }">
|
<a-tooltip :content="t('apiTestDebug.specifyMatchTip')" :content-style="{ maxWidth: '400px' }">
|
||||||
|
@ -56,7 +56,7 @@
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</a-radio>
|
</a-radio>
|
||||||
<a-radio :value="RequestExtractResultMatchingRule.ALL.toLowerCase()">
|
<a-radio :value="RequestExtractResultMatchingRule.ALL">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
{{ t('apiTestDebug.allMatch') }}
|
{{ t('apiTestDebug.allMatch') }}
|
||||||
<a-tooltip :content="t('apiTestDebug.allMatchTip')" :content-style="{ maxWidth: '400px' }">
|
<a-tooltip :content="t('apiTestDebug.allMatchTip')" :content-style="{ maxWidth: '400px' }">
|
||||||
|
|
|
@ -111,9 +111,9 @@
|
||||||
@change="(val) => handleTypeChange(val, record, rowIndex, columnConfig.addLineDisabled)"
|
@change="(val) => handleTypeChange(val, record, rowIndex, columnConfig.addLineDisabled)"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #expressionType="{ record, columnConfig, rowIndex }">
|
<template #extractType="{ record, columnConfig, rowIndex }">
|
||||||
<a-select
|
<a-select
|
||||||
v-model:model-value="record.expressionType"
|
v-model:model-value="record.extractType"
|
||||||
:options="columnConfig.typeOptions || []"
|
:options="columnConfig.typeOptions || []"
|
||||||
class="param-input w-[110px]"
|
class="param-input w-[110px]"
|
||||||
size="mini"
|
size="mini"
|
||||||
|
|
|
@ -49,7 +49,6 @@
|
||||||
import { ref, watch } from 'vue';
|
import { ref, watch } from 'vue';
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
|
|
||||||
import { addDebugModule, updateDebug, updateDebugModule } from '@/api/modules/api-test/debug';
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
|
|
||||||
|
@ -74,6 +73,9 @@
|
||||||
parentId?: string; // 父节点 id
|
parentId?: string; // 父节点 id
|
||||||
nodeId?: string; // 节点 id
|
nodeId?: string; // 节点 id
|
||||||
popupOffset?: number;
|
popupOffset?: number;
|
||||||
|
addModuleApi?: (params: { projectId: string; parentId: string; name: string }) => Promise<any>;
|
||||||
|
updateModuleApi?: (params: { id: string; name: string }) => Promise<any>;
|
||||||
|
updateApiNodeApi?: (params: { id: string; name: string }) => Promise<any>;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits(['update:visible', 'close', 'addFinish', 'renameFinish', 'updateDescFinish']);
|
const emit = defineEmits(['update:visible', 'close', 'addFinish', 'renameFinish', 'updateDescFinish']);
|
||||||
|
@ -121,26 +123,26 @@
|
||||||
if (!errors) {
|
if (!errors) {
|
||||||
try {
|
try {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
if (props.mode === 'add') {
|
if (props.mode === 'add' && props.addModuleApi) {
|
||||||
// 添加根级模块
|
// 添加根级模块
|
||||||
await addDebugModule({
|
await props.addModuleApi({
|
||||||
projectId: appStore.currentProjectId,
|
projectId: appStore.currentProjectId,
|
||||||
parentId: props.parentId || '',
|
parentId: props.parentId || '',
|
||||||
name: form.value.field,
|
name: form.value.field,
|
||||||
});
|
});
|
||||||
Message.success(t('common.addSuccess'));
|
Message.success(t('common.addSuccess'));
|
||||||
emit('addFinish', form.value.field);
|
emit('addFinish', form.value.field);
|
||||||
} else if (props.mode === 'rename' && props.nodeType === 'API') {
|
} else if (props.mode === 'rename' && props.nodeType === 'API' && props.updateApiNodeApi) {
|
||||||
// 接口节点重命名
|
// 接口节点重命名
|
||||||
await updateDebug({
|
await props.updateApiNodeApi({
|
||||||
id: props.nodeId || '',
|
id: props.nodeId || '',
|
||||||
name: form.value.field,
|
name: form.value.field,
|
||||||
});
|
});
|
||||||
Message.success(t('common.updateSuccess'));
|
Message.success(t('common.updateSuccess'));
|
||||||
emit('renameFinish', form.value.field, props.nodeId);
|
emit('renameFinish', form.value.field, props.nodeId);
|
||||||
} else if (props.mode === 'rename') {
|
} else if (props.mode === 'rename' && props.updateModuleApi) {
|
||||||
// 模块重命名
|
// 模块重命名
|
||||||
await updateDebugModule({
|
await props.updateModuleApi({
|
||||||
id: props.nodeId || '',
|
id: props.nodeId || '',
|
||||||
name: form.value.field,
|
name: form.value.field,
|
||||||
});
|
});
|
||||||
|
|
|
@ -86,7 +86,7 @@
|
||||||
<MsCodeEditor
|
<MsCodeEditor
|
||||||
v-model:model-value="currentBodyCode"
|
v-model:model-value="currentBodyCode"
|
||||||
class="flex-1"
|
class="flex-1"
|
||||||
theme="MS-text"
|
theme="vs"
|
||||||
height="100%"
|
height="100%"
|
||||||
:show-full-screen="false"
|
:show-full-screen="false"
|
||||||
:show-theme-change="false"
|
:show-theme-change="false"
|
||||||
|
@ -121,7 +121,7 @@
|
||||||
params: ExecuteBody;
|
params: ExecuteBody;
|
||||||
layout: 'horizontal' | 'vertical';
|
layout: 'horizontal' | 'vertical';
|
||||||
secondBoxHeight: number;
|
secondBoxHeight: number;
|
||||||
uploadTempFileApi?: (file: MsFileItem) => Promise<any>; // 上传临时文件接口
|
uploadTempFileApi?: (file: File) => Promise<any>; // 上传临时文件接口
|
||||||
fileSaveAsSourceId?: string | number; // 文件转存关联的资源id
|
fileSaveAsSourceId?: string | number; // 文件转存关联的资源id
|
||||||
fileSaveAsApi?: (params: TransferFileParams) => Promise<string>; // 文件转存接口
|
fileSaveAsApi?: (params: TransferFileParams) => Promise<string>; // 文件转存接口
|
||||||
fileModuleOptionsApi?: (projectId: string) => Promise<ModuleTreeNode[]>; // 文件转存目录下拉框接口
|
fileModuleOptionsApi?: (projectId: string) => Promise<ModuleTreeNode[]>; // 文件转存目录下拉框接口
|
||||||
|
@ -135,18 +135,18 @@
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const innerParams = useVModel(props, 'params', emit);
|
const innerParams = useVModel(props, 'params', emit);
|
||||||
const fileList = ref<any[]>(
|
const fileList = ref<MsFileItem[]>([]);
|
||||||
innerParams.value.binaryBody && innerParams.value.binaryBody.file ? [innerParams.value.binaryBody.file] : []
|
|
||||||
);
|
|
||||||
|
|
||||||
async function handleFileChange(files: MsFileItem[]) {
|
onBeforeMount(() => {
|
||||||
if (files.length === 0) {
|
if (innerParams.value.binaryBody && innerParams.value.binaryBody.file) {
|
||||||
innerParams.value.binaryBody.file = undefined;
|
fileList.value = [innerParams.value.binaryBody.file as unknown as MsFileItem];
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function handleFileChange() {
|
||||||
if (!props.uploadTempFileApi) return;
|
if (!props.uploadTempFileApi) return;
|
||||||
try {
|
try {
|
||||||
if (fileList.value[0]?.local) {
|
if (fileList.value[0]?.local && fileList.value[0].file) {
|
||||||
appStore.showLoading();
|
appStore.showLoading();
|
||||||
const res = await props.uploadTempFileApi(fileList.value[0].file);
|
const res = await props.uploadTempFileApi(fileList.value[0].file);
|
||||||
innerParams.value.binaryBody.file = {
|
innerParams.value.binaryBody.file = {
|
||||||
|
@ -160,7 +160,7 @@
|
||||||
} else {
|
} else {
|
||||||
innerParams.value.binaryBody.file = {
|
innerParams.value.binaryBody.file = {
|
||||||
...fileList.value[0],
|
...fileList.value[0],
|
||||||
fileId: fileList.value[0].uid,
|
fileId: fileList.value[0]?.uid,
|
||||||
fileName: fileList.value[0]?.originalName || '',
|
fileName: fileList.value[0]?.originalName || '',
|
||||||
fileAlias: fileList.value[0]?.name || '',
|
fileAlias: fileList.value[0]?.name || '',
|
||||||
local: false,
|
local: false,
|
||||||
|
|
|
@ -43,7 +43,9 @@
|
||||||
<a-input
|
<a-input
|
||||||
v-model:model-value="requestVModel.url"
|
v-model:model-value="requestVModel.url"
|
||||||
:max-length="255"
|
:max-length="255"
|
||||||
:placeholder="t('apiTestDebug.urlPlaceholder')"
|
:placeholder="
|
||||||
|
props.isDefinition ? t('apiTestDebug.definitionUrlPlaceholder') : t('apiTestDebug.urlPlaceholder')
|
||||||
|
"
|
||||||
allow-clear
|
allow-clear
|
||||||
@change="handleUrlChange"
|
@change="handleUrlChange"
|
||||||
/>
|
/>
|
||||||
|
@ -51,8 +53,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="ml-[16px]">
|
<div class="ml-[16px]">
|
||||||
<a-dropdown-button
|
<a-dropdown-button
|
||||||
v-if="!requestVModel.executeLoading"
|
v-if="!requestVModel.executeLoading && hasAnyPermission([props.permissionMap.execute])"
|
||||||
v-permission="[props.permissionMap.execute]"
|
|
||||||
:disabled="requestVModel.executeLoading || (isHttpProtocol && !requestVModel.url)"
|
:disabled="requestVModel.executeLoading || (isHttpProtocol && !requestVModel.url)"
|
||||||
class="exec-btn"
|
class="exec-btn"
|
||||||
@click="() => execute(isPriorityLocalExec ? 'localExec' : 'serverExec')"
|
@click="() => execute(isPriorityLocalExec ? 'localExec' : 'serverExec')"
|
||||||
|
@ -70,12 +71,14 @@
|
||||||
</a-dropdown-button>
|
</a-dropdown-button>
|
||||||
<a-button v-else type="primary" class="mr-[12px]" @click="stopDebug">{{ t('common.stop') }}</a-button>
|
<a-button v-else type="primary" class="mr-[12px]" @click="stopDebug">{{ t('common.stop') }}</a-button>
|
||||||
<a-dropdown
|
<a-dropdown
|
||||||
v-if="props.isDefinition"
|
v-if="props.isDefinition && hasAnyPermission([props.permissionMap.create, props.permissionMap.update])"
|
||||||
v-permission="[props.permissionMap.create, props.permissionMap.update]"
|
|
||||||
:loading="saveLoading || (isHttpProtocol && !requestVModel.url)"
|
:loading="saveLoading || (isHttpProtocol && !requestVModel.url)"
|
||||||
@select="handleSelect"
|
@select="handleSelect"
|
||||||
>
|
>
|
||||||
<a-button :disabled="requestVModel.url.trim() === '' || requestVModel.name.trim() === ''" type="secondary">
|
<a-button
|
||||||
|
:disabled="(isHttpProtocol && requestVModel.url.trim() === '') || requestVModel.name.trim() === ''"
|
||||||
|
type="secondary"
|
||||||
|
>
|
||||||
{{ t('common.save') }}
|
{{ t('common.save') }}
|
||||||
</a-button>
|
</a-button>
|
||||||
<template #content>
|
<template #content>
|
||||||
|
@ -147,14 +150,14 @@
|
||||||
@change="handlePluginFormChange"
|
@change="handlePluginFormChange"
|
||||||
/>
|
/>
|
||||||
</a-spin>
|
</a-spin>
|
||||||
<debugHeader
|
<httpHeader
|
||||||
v-if="requestVModel.activeTab === RequestComposition.HEADER"
|
v-if="requestVModel.activeTab === RequestComposition.HEADER"
|
||||||
v-model:params="requestVModel.headers"
|
v-model:params="requestVModel.headers"
|
||||||
:layout="activeLayout"
|
:layout="activeLayout"
|
||||||
:second-box-height="secondBoxHeight"
|
:second-box-height="secondBoxHeight"
|
||||||
@change="handleActiveDebugChange"
|
@change="handleActiveDebugChange"
|
||||||
/>
|
/>
|
||||||
<debugBody
|
<httpBody
|
||||||
v-else-if="requestVModel.activeTab === RequestComposition.BODY"
|
v-else-if="requestVModel.activeTab === RequestComposition.BODY"
|
||||||
v-model:params="requestVModel.body"
|
v-model:params="requestVModel.body"
|
||||||
:layout="activeLayout"
|
:layout="activeLayout"
|
||||||
|
@ -165,14 +168,14 @@
|
||||||
:file-module-options-api="props.fileModuleOptionsApi"
|
:file-module-options-api="props.fileModuleOptionsApi"
|
||||||
@change="handleActiveDebugChange"
|
@change="handleActiveDebugChange"
|
||||||
/>
|
/>
|
||||||
<debugQuery
|
<httpQuery
|
||||||
v-else-if="requestVModel.activeTab === RequestComposition.QUERY"
|
v-else-if="requestVModel.activeTab === RequestComposition.QUERY"
|
||||||
v-model:params="requestVModel.query"
|
v-model:params="requestVModel.query"
|
||||||
:layout="activeLayout"
|
:layout="activeLayout"
|
||||||
:second-box-height="secondBoxHeight"
|
:second-box-height="secondBoxHeight"
|
||||||
@change="handleActiveDebugChange"
|
@change="handleActiveDebugChange"
|
||||||
/>
|
/>
|
||||||
<debugRest
|
<httpRest
|
||||||
v-else-if="requestVModel.activeTab === RequestComposition.REST"
|
v-else-if="requestVModel.activeTab === RequestComposition.REST"
|
||||||
v-model:params="requestVModel.rest"
|
v-model:params="requestVModel.rest"
|
||||||
:layout="activeLayout"
|
:layout="activeLayout"
|
||||||
|
@ -182,6 +185,7 @@
|
||||||
<precondition
|
<precondition
|
||||||
v-else-if="requestVModel.activeTab === RequestComposition.PRECONDITION"
|
v-else-if="requestVModel.activeTab === RequestComposition.PRECONDITION"
|
||||||
v-model:config="requestVModel.children[0].preProcessorConfig"
|
v-model:config="requestVModel.children[0].preProcessorConfig"
|
||||||
|
:is-definition="props.isDefinition"
|
||||||
@change="handleActiveDebugChange"
|
@change="handleActiveDebugChange"
|
||||||
/>
|
/>
|
||||||
<postcondition
|
<postcondition
|
||||||
|
@ -190,14 +194,15 @@
|
||||||
:response="requestVModel.response?.requestResults[0]?.responseResult.body"
|
:response="requestVModel.response?.requestResults[0]?.responseResult.body"
|
||||||
:layout="activeLayout"
|
:layout="activeLayout"
|
||||||
:second-box-height="secondBoxHeight"
|
:second-box-height="secondBoxHeight"
|
||||||
|
:is-definition="props.isDefinition"
|
||||||
@change="handleActiveDebugChange"
|
@change="handleActiveDebugChange"
|
||||||
/>
|
/>
|
||||||
<debugAuth
|
<auth
|
||||||
v-else-if="requestVModel.activeTab === RequestComposition.AUTH"
|
v-else-if="requestVModel.activeTab === RequestComposition.AUTH"
|
||||||
v-model:params="requestVModel.authConfig"
|
v-model:params="requestVModel.authConfig"
|
||||||
@change="handleActiveDebugChange"
|
@change="handleActiveDebugChange"
|
||||||
/>
|
/>
|
||||||
<debugSetting
|
<setting
|
||||||
v-else-if="requestVModel.activeTab === RequestComposition.SETTING"
|
v-else-if="requestVModel.activeTab === RequestComposition.SETTING"
|
||||||
v-model:params="requestVModel.otherConfig"
|
v-model:params="requestVModel.otherConfig"
|
||||||
@change="handleActiveDebugChange"
|
@change="handleActiveDebugChange"
|
||||||
|
@ -280,11 +285,11 @@
|
||||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||||
import MsSplitBox from '@/components/pure/ms-split-box/index.vue';
|
import MsSplitBox from '@/components/pure/ms-split-box/index.vue';
|
||||||
import MsTab from '@/components/pure/ms-tab/index.vue';
|
import MsTab from '@/components/pure/ms-tab/index.vue';
|
||||||
import debugAuth from './auth.vue';
|
import auth from './auth.vue';
|
||||||
import postcondition from './postcondition.vue';
|
import postcondition from './postcondition.vue';
|
||||||
import precondition from './precondition.vue';
|
import precondition from './precondition.vue';
|
||||||
import response from './response/index.vue';
|
import response from './response/index.vue';
|
||||||
import debugSetting from './setting.vue';
|
import setting from './setting.vue';
|
||||||
import apiMethodName from '@/views/api-test/components/apiMethodName.vue';
|
import apiMethodName from '@/views/api-test/components/apiMethodName.vue';
|
||||||
import apiMethodSelect from '@/views/api-test/components/apiMethodSelect.vue';
|
import apiMethodSelect from '@/views/api-test/components/apiMethodSelect.vue';
|
||||||
|
|
||||||
|
@ -323,10 +328,10 @@
|
||||||
import type { Api } from '@form-create/arco-design';
|
import type { Api } from '@form-create/arco-design';
|
||||||
|
|
||||||
// 懒加载Http协议组件
|
// 懒加载Http协议组件
|
||||||
const debugHeader = defineAsyncComponent(() => import('./header.vue'));
|
const httpHeader = defineAsyncComponent(() => import('./header.vue'));
|
||||||
const debugBody = defineAsyncComponent(() => import('./body.vue'));
|
const httpBody = defineAsyncComponent(() => import('./body.vue'));
|
||||||
const debugQuery = defineAsyncComponent(() => import('./query.vue'));
|
const httpQuery = defineAsyncComponent(() => import('./query.vue'));
|
||||||
const debugRest = defineAsyncComponent(() => import('./rest.vue'));
|
const httpRest = defineAsyncComponent(() => import('./rest.vue'));
|
||||||
|
|
||||||
export interface RequestCustomAttr {
|
export interface RequestCustomAttr {
|
||||||
isNew: boolean;
|
isNew: boolean;
|
||||||
|
@ -615,9 +620,13 @@
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => requestVModel.value.id,
|
() => requestVModel.value.id,
|
||||||
() => {
|
async () => {
|
||||||
if (requestVModel.value.protocol !== 'HTTP') {
|
if (requestVModel.value.protocol !== 'HTTP') {
|
||||||
requestVModel.value.activeTab = RequestComposition.PLUGIN;
|
requestVModel.value.activeTab = RequestComposition.PLUGIN;
|
||||||
|
if (protocolOptions.value.length === 0) {
|
||||||
|
// 还没初始化过协议列表,则初始化;在这里初始化是为了阻塞脚本的初始化,避免脚本初始化时协议列表还没初始化
|
||||||
|
await initProtocolList();
|
||||||
|
}
|
||||||
initPluginScript();
|
initPluginScript();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -846,6 +855,7 @@
|
||||||
...parseRequestBodyResult,
|
...parseRequestBodyResult,
|
||||||
projectId: appStore.currentProjectId,
|
projectId: appStore.currentProjectId,
|
||||||
frontendDebug: executeType === 'localExec',
|
frontendDebug: executeType === 'localExec',
|
||||||
|
isNew: requestVModel.value.isNew,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1004,7 +1014,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
initProtocolList();
|
|
||||||
initLocalConfig();
|
initLocalConfig();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<condition
|
<condition
|
||||||
v-model:list="innerConfig.processors"
|
v-model:list="innerConfig.processors"
|
||||||
:condition-types="[RequestConditionProcessor.SCRIPT]"
|
:condition-types="conditionTypes"
|
||||||
add-text="apiTestDebug.postCondition"
|
add-text="apiTestDebug.postCondition"
|
||||||
:response="props.response"
|
:response="props.response"
|
||||||
:height-used="heightUsed"
|
:height-used="heightUsed"
|
||||||
@change="emit('change')"
|
@change="emit('change')"
|
||||||
>
|
>
|
||||||
<!-- <template #titleRight>
|
<template v-if="props.isDefinition" #titleRight>
|
||||||
<a-switch v-model:model-value="innerConfig.enableGlobal" size="small" type="line"></a-switch>
|
<a-switch v-model:model-value="innerConfig.enableGlobal" size="small" type="line"></a-switch>
|
||||||
<div class="ml-[8px] text-[var(--color-text-1)]">{{ t('apiTestDebug.openGlobalPostCondition') }}</div>
|
<div class="ml-[8px] text-[var(--color-text-1)]">{{ t('apiTestDebug.openGlobalPostCondition') }}</div>
|
||||||
<a-tooltip :content="t('apiTestDebug.openGlobalPostConditionTip')" position="left">
|
<a-tooltip :content="t('apiTestDebug.openGlobalPostConditionTip')" position="left">
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
size="16"
|
size="16"
|
||||||
/>
|
/>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</template> -->
|
</template>
|
||||||
</condition>
|
</condition>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -25,23 +25,24 @@
|
||||||
|
|
||||||
import condition from '@/views/api-test/components/condition/index.vue';
|
import condition from '@/views/api-test/components/condition/index.vue';
|
||||||
|
|
||||||
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
|
||||||
import { ExecuteConditionConfig, ExecuteConditionProcessor } from '@/models/apiTest/common';
|
import { ExecuteConditionConfig, ExecuteConditionProcessor } from '@/models/apiTest/common';
|
||||||
import { RequestConditionProcessor } from '@/enums/apiEnum';
|
import { RequestConditionProcessor } from '@/enums/apiEnum';
|
||||||
|
|
||||||
// import { useI18n } from '@/hooks/useI18n';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
config: ExecuteConditionConfig;
|
config: ExecuteConditionConfig;
|
||||||
secondBoxHeight?: number;
|
secondBoxHeight?: number;
|
||||||
layout: 'horizontal' | 'vertical';
|
layout: 'horizontal' | 'vertical';
|
||||||
response?: string; // 响应内容
|
response?: string; // 响应内容
|
||||||
|
isDefinition?: boolean; // 是否是定义页面
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'update:params', params: ExecuteConditionProcessor[]): void;
|
(e: 'update:params', params: ExecuteConditionProcessor[]): void;
|
||||||
(e: 'change'): void;
|
(e: 'change'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
// const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const innerConfig = useVModel(props, 'config', emit);
|
const innerConfig = useVModel(props, 'config', emit);
|
||||||
const heightUsed = computed(() => {
|
const heightUsed = computed(() => {
|
||||||
if (props.layout === 'horizontal') {
|
if (props.layout === 'horizontal') {
|
||||||
|
@ -49,6 +50,13 @@
|
||||||
}
|
}
|
||||||
return 428 + (props.secondBoxHeight || 0);
|
return 428 + (props.secondBoxHeight || 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const conditionTypes = computed(() => {
|
||||||
|
if (props.isDefinition) {
|
||||||
|
return [RequestConditionProcessor.SCRIPT, RequestConditionProcessor.SQL, RequestConditionProcessor.EXTRACT];
|
||||||
|
}
|
||||||
|
return [RequestConditionProcessor.SCRIPT];
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
<style lang="less" scoped></style>
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<condition
|
<condition
|
||||||
v-model:list="innerConfig.processors"
|
v-model:list="innerConfig.processors"
|
||||||
:condition-types="[RequestConditionProcessor.SCRIPT, RequestConditionProcessor.TIME_WAITING]"
|
:condition-types="conditionTypes"
|
||||||
add-text="apiTestDebug.precondition"
|
add-text="apiTestDebug.precondition"
|
||||||
@change="emit('change')"
|
@change="emit('change')"
|
||||||
/>
|
>
|
||||||
|
<template v-if="props.isDefinition" #titleRight>
|
||||||
<!-- <template #titleRight>
|
|
||||||
<a-switch v-model:model-value="innerConfig.enableGlobal" size="small" type="line"></a-switch>
|
<a-switch v-model:model-value="innerConfig.enableGlobal" size="small" type="line"></a-switch>
|
||||||
<div class="ml-[8px] text-[var(--color-text-1)]">{{ t('apiTestDebug.openGlobalPrecondition') }}</div>
|
<div class="ml-[8px] text-[var(--color-text-1)]">{{ t('apiTestDebug.openGlobalPrecondition') }}</div>
|
||||||
<a-tooltip :content="t('apiTestDebug.openGlobalPreconditionTip')" position="left">
|
<a-tooltip :content="t('apiTestDebug.openGlobalPreconditionTip')" position="left">
|
||||||
|
@ -15,7 +14,8 @@
|
||||||
size="16"
|
size="16"
|
||||||
/>
|
/>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</template> -->
|
</template>
|
||||||
|
</condition>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
@ -23,21 +23,29 @@
|
||||||
|
|
||||||
import condition from '@/views/api-test/components/condition/index.vue';
|
import condition from '@/views/api-test/components/condition/index.vue';
|
||||||
|
|
||||||
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
|
||||||
import { ExecuteConditionConfig } from '@/models/apiTest/common';
|
import { ExecuteConditionConfig } from '@/models/apiTest/common';
|
||||||
import { RequestConditionProcessor } from '@/enums/apiEnum';
|
import { RequestConditionProcessor } from '@/enums/apiEnum';
|
||||||
|
|
||||||
// import { useI18n } from '@/hooks/useI18n';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
config: ExecuteConditionConfig;
|
config: ExecuteConditionConfig;
|
||||||
|
isDefinition?: boolean; // 是否是定义页面
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'update:config', params: ExecuteConditionConfig): void;
|
(e: 'update:config', params: ExecuteConditionConfig): void;
|
||||||
(e: 'change'): void;
|
(e: 'change'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
// const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const innerConfig = useVModel(props, 'config', emit);
|
const innerConfig = useVModel(props, 'config', emit);
|
||||||
|
|
||||||
|
const conditionTypes = computed(() => {
|
||||||
|
if (props.isDefinition) {
|
||||||
|
return [RequestConditionProcessor.SCRIPT, RequestConditionProcessor.SQL, RequestConditionProcessor.TIME_WAITING];
|
||||||
|
}
|
||||||
|
return [RequestConditionProcessor.SCRIPT, RequestConditionProcessor.TIME_WAITING];
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
<style lang="less" scoped></style>
|
||||||
|
|
|
@ -109,7 +109,6 @@
|
||||||
:show-theme-change="false"
|
:show-theme-change="false"
|
||||||
:show-language-change="false"
|
:show-language-change="false"
|
||||||
:show-charset-change="false"
|
:show-charset-change="false"
|
||||||
read-only
|
|
||||||
>
|
>
|
||||||
<template #rightTitle>
|
<template #rightTitle>
|
||||||
<a-button type="outline" class="arco-btn-outline--secondary p-[0_8px]" size="mini" @click="copyScript">
|
<a-button type="outline" class="arco-btn-outline--secondary p-[0_8px]" size="mini" @click="copyScript">
|
||||||
|
@ -171,7 +170,7 @@
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
responseDefinition: ResponseDefinition[];
|
responseDefinition: ResponseDefinition[];
|
||||||
uploadTempFileApi?: (...args) => Promise<any>; // 上传临时文件接口
|
uploadTempFileApi?: (file: File) => Promise<any>; // 上传临时文件接口
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'change'): void;
|
(e: 'change'): void;
|
||||||
|
@ -322,20 +321,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileList = ref<any[]>(
|
const fileList = ref<MsFileItem[]>([]);
|
||||||
activeResponse.value.body.binaryBody && activeResponse.value.body.binaryBody.file
|
onBeforeMount(() => {
|
||||||
? [activeResponse.value.body.binaryBody.file]
|
if (activeResponse.value.body.binaryBody && activeResponse.value.body.binaryBody.file) {
|
||||||
: []
|
fileList.value = [activeResponse.value.body.binaryBody.file as unknown as MsFileItem];
|
||||||
);
|
|
||||||
|
|
||||||
async function handleFileChange(files: MsFileItem[]) {
|
|
||||||
if (files.length === 0) {
|
|
||||||
activeResponse.value.body.binaryBody.file = undefined;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function handleFileChange() {
|
||||||
if (!props.uploadTempFileApi) return;
|
if (!props.uploadTempFileApi) return;
|
||||||
try {
|
try {
|
||||||
if (fileList.value[0]?.local) {
|
if (fileList.value[0]?.local && fileList.value[0].file) {
|
||||||
appStore.showLoading();
|
appStore.showLoading();
|
||||||
const res = await props.uploadTempFileApi(fileList.value[0].file);
|
const res = await props.uploadTempFileApi(fileList.value[0].file);
|
||||||
activeResponse.value.body.binaryBody.file = {
|
activeResponse.value.body.binaryBody.file = {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="h-full rounded-[var(--border-radius-small)] border border-[var(--color-text-n8)] p-[16px]">
|
<div class="setting">
|
||||||
<a-form :model="settingForm" layout="vertical">
|
<a-form :model="settingForm" layout="vertical">
|
||||||
<div class="flex items-center gap-[32px]">
|
<div class="flex items-center gap-[32px]">
|
||||||
<a-form-item class="flex-1">
|
<a-form-item class="flex-1">
|
||||||
|
@ -99,4 +99,13 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
<style lang="less" scoped>
|
||||||
|
.setting {
|
||||||
|
@apply h-full overflow-y-auto;
|
||||||
|
.ms-scroll-bar();
|
||||||
|
|
||||||
|
padding: 16px;
|
||||||
|
border: 1px solid var(--color-text-n8);
|
||||||
|
border-radius: var(--border-radius-small);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
mode="add"
|
mode="add"
|
||||||
:all-names="rootModulesName"
|
:all-names="rootModulesName"
|
||||||
parent-id="NONE"
|
parent-id="NONE"
|
||||||
|
:add-module-api="addDebugModule"
|
||||||
@add-finish="initModules"
|
@add-finish="initModules"
|
||||||
>
|
>
|
||||||
<MsButton v-permission="['PROJECT_API_DEBUG:READ+ADD']" type="icon" class="!mr-0 p-[2px]">
|
<MsButton v-permission="['PROJECT_API_DEBUG:READ+ADD']" type="icon" class="!mr-0 p-[2px]">
|
||||||
|
@ -100,6 +101,7 @@
|
||||||
:field-config="{ field: renameFolderTitle }"
|
:field-config="{ field: renameFolderTitle }"
|
||||||
:all-names="(nodeData.children || []).map((e: ModuleTreeNode) => e.name || '')"
|
:all-names="(nodeData.children || []).map((e: ModuleTreeNode) => e.name || '')"
|
||||||
:node-type="nodeData.type"
|
:node-type="nodeData.type"
|
||||||
|
:add-module-api="addDebugModule"
|
||||||
@close="resetFocusNodeKey"
|
@close="resetFocusNodeKey"
|
||||||
@rename-finish="handleRenameFinish"
|
@rename-finish="handleRenameFinish"
|
||||||
>
|
>
|
||||||
|
@ -111,6 +113,8 @@
|
||||||
mode="add"
|
mode="add"
|
||||||
:all-names="(nodeData.children || []).map((e: ModuleTreeNode) => e.name || '')"
|
:all-names="(nodeData.children || []).map((e: ModuleTreeNode) => e.name || '')"
|
||||||
:parent-id="nodeData.id"
|
:parent-id="nodeData.id"
|
||||||
|
:update-module-api="updateDebugModule"
|
||||||
|
:update-api-node-api="updateDebug"
|
||||||
@close="resetFocusNodeKey"
|
@close="resetFocusNodeKey"
|
||||||
@add-finish="() => initModules()"
|
@add-finish="() => initModules()"
|
||||||
>
|
>
|
||||||
|
@ -137,12 +141,15 @@
|
||||||
import popConfirm from '@/views/api-test/components/popConfirm.vue';
|
import popConfirm from '@/views/api-test/components/popConfirm.vue';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
addDebugModule,
|
||||||
deleteDebug,
|
deleteDebug,
|
||||||
deleteDebugModule,
|
deleteDebugModule,
|
||||||
dragDebug,
|
dragDebug,
|
||||||
getDebugModuleCount,
|
getDebugModuleCount,
|
||||||
getDebugModules,
|
getDebugModules,
|
||||||
moveDebugModule,
|
moveDebugModule,
|
||||||
|
updateDebug,
|
||||||
|
updateDebugModule,
|
||||||
} from '@/api/modules/api-test/debug';
|
} from '@/api/modules/api-test/debug';
|
||||||
import { dropPositionMap } from '@/config/common';
|
import { dropPositionMap } from '@/config/common';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
|
|
@ -2,6 +2,7 @@ export default {
|
||||||
'apiTestDebug.newApi': 'New request',
|
'apiTestDebug.newApi': 'New request',
|
||||||
'apiTestDebug.importApi': 'Import request',
|
'apiTestDebug.importApi': 'Import request',
|
||||||
'apiTestDebug.urlPlaceholder': 'Please enter the full URL including http or https',
|
'apiTestDebug.urlPlaceholder': 'Please enter the full URL including http or https',
|
||||||
|
'apiTestDebug.definitionUrlPlaceholder': 'Enter the interface URL, starting with "/"',
|
||||||
'apiTestDebug.serverExec': 'Server execution',
|
'apiTestDebug.serverExec': 'Server execution',
|
||||||
'apiTestDebug.localExec': 'Local execution',
|
'apiTestDebug.localExec': 'Local execution',
|
||||||
'apiTestDebug.noMatchModule': 'No matching module data yet',
|
'apiTestDebug.noMatchModule': 'No matching module data yet',
|
||||||
|
|
|
@ -2,6 +2,7 @@ export default {
|
||||||
'apiTestDebug.newApi': '新建请求',
|
'apiTestDebug.newApi': '新建请求',
|
||||||
'apiTestDebug.importApi': '导入请求',
|
'apiTestDebug.importApi': '导入请求',
|
||||||
'apiTestDebug.urlPlaceholder': '请输入包含 http 或 https 的完整URL',
|
'apiTestDebug.urlPlaceholder': '请输入包含 http 或 https 的完整URL',
|
||||||
|
'apiTestDebug.definitionUrlPlaceholder': '输入接口URL,以“/”开始',
|
||||||
'apiTestDebug.serverExec': '服务端执行',
|
'apiTestDebug.serverExec': '服务端执行',
|
||||||
'apiTestDebug.localExec': '本地执行',
|
'apiTestDebug.localExec': '本地执行',
|
||||||
'apiTestDebug.noMatchModule': '暂无匹配的模块数据',
|
'apiTestDebug.noMatchModule': '暂无匹配的模块数据',
|
||||||
|
|
|
@ -11,12 +11,14 @@
|
||||||
read-only
|
read-only
|
||||||
@init="(val) => (folderTree = val)"
|
@init="(val) => (folderTree = val)"
|
||||||
@folder-node-select="handleNodeSelect"
|
@folder-node-select="handleNodeSelect"
|
||||||
|
@change-protocol="handleProtocolChange"
|
||||||
/>
|
/>
|
||||||
<a-divider direction="vertical" :margin="16"></a-divider>
|
<a-divider direction="vertical" :margin="16"></a-divider>
|
||||||
<apiTable
|
<apiTable
|
||||||
:active-module="activeModule"
|
:active-module="activeModule"
|
||||||
:offspring-ids="offspringIds"
|
:offspring-ids="offspringIds"
|
||||||
class="flex-1 overflow-hidden !pl-0 !pr-[16px]"
|
class="flex-1 overflow-hidden !pl-0 !pr-[16px]"
|
||||||
|
:protocol="protocol"
|
||||||
read-only
|
read-only
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -46,11 +48,16 @@
|
||||||
const folderTree = ref<ModuleTreeNode[]>([]);
|
const folderTree = ref<ModuleTreeNode[]>([]);
|
||||||
const activeModule = ref<string>('all');
|
const activeModule = ref<string>('all');
|
||||||
const offspringIds = ref<string[]>([]);
|
const offspringIds = ref<string[]>([]);
|
||||||
|
const protocol = ref('HTTP');
|
||||||
|
|
||||||
function handleNodeSelect(keys: string[], _offspringIds: string[]) {
|
function handleNodeSelect(keys: string[], _offspringIds: string[]) {
|
||||||
[activeModule.value] = keys;
|
[activeModule.value] = keys;
|
||||||
offspringIds.value = _offspringIds;
|
offspringIds.value = _offspringIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleProtocolChange(val: string) {
|
||||||
|
protocol.value = val;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
<style lang="less" scoped></style>
|
||||||
|
|
|
@ -52,10 +52,10 @@
|
||||||
trigger="click"
|
trigger="click"
|
||||||
@popup-visible-change="handleFilterHidden"
|
@popup-visible-change="handleFilterHidden"
|
||||||
>
|
>
|
||||||
<a-button type="text" class="arco-btn-text--secondary" @click="methodFilterVisible = true">
|
<MsButton type="text" class="arco-btn-text--secondary" @click="methodFilterVisible = true">
|
||||||
{{ t(columnConfig.title as string) }}
|
{{ t(columnConfig.title as string) }}
|
||||||
<icon-down :class="methodFilterVisible ? 'text-[rgb(var(--primary-5))]' : ''" />
|
<icon-down :class="methodFilterVisible ? 'text-[rgb(var(--primary-5))]' : ''" />
|
||||||
</a-button>
|
</MsButton>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div class="arco-table-filters-content">
|
<div class="arco-table-filters-content">
|
||||||
<div class="flex items-center justify-center px-[6px] py-[2px]">
|
<div class="flex items-center justify-center px-[6px] py-[2px]">
|
||||||
|
@ -75,16 +75,16 @@
|
||||||
trigger="click"
|
trigger="click"
|
||||||
@popup-visible-change="handleFilterHidden"
|
@popup-visible-change="handleFilterHidden"
|
||||||
>
|
>
|
||||||
<a-button type="text" class="arco-btn-text--secondary" @click="statusFilterVisible = true">
|
<MsButton type="text" class="arco-btn-text--secondary ml-[10px]" @click="statusFilterVisible = true">
|
||||||
{{ t(columnConfig.title as string) }}
|
{{ t(columnConfig.title as string) }}
|
||||||
<icon-down :class="statusFilterVisible ? 'text-[rgb(var(--primary-5))]' : ''" />
|
<icon-down :class="statusFilterVisible ? 'text-[rgb(var(--primary-5))]' : ''" />
|
||||||
</a-button>
|
</MsButton>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div class="arco-table-filters-content">
|
<div class="arco-table-filters-content">
|
||||||
<div class="flex items-center justify-center px-[6px] py-[2px]">
|
<div class="flex items-center justify-center px-[6px] py-[2px]">
|
||||||
<a-checkbox-group v-model:model-value="statusFilters" direction="vertical" size="small">
|
<a-checkbox-group v-model:model-value="statusFilters" direction="vertical" size="small">
|
||||||
<a-checkbox v-for="key of RequestDefinitionStatus" :key="key" :value="key">
|
<a-checkbox v-for="val of Object.values(RequestDefinitionStatus)" :key="val" :value="val">
|
||||||
<apiStatus :status="key" />
|
<apiStatus :status="val" />
|
||||||
</a-checkbox>
|
</a-checkbox>
|
||||||
</a-checkbox-group>
|
</a-checkbox-group>
|
||||||
</div>
|
</div>
|
||||||
|
@ -108,7 +108,7 @@
|
||||||
<template #label>
|
<template #label>
|
||||||
<apiStatus :status="record.status" />
|
<apiStatus :status="record.status" />
|
||||||
</template>
|
</template>
|
||||||
<a-option v-for="item of RequestDefinitionStatus" :key="item" :value="item">
|
<a-option v-for="item of Object.values(RequestDefinitionStatus)" :key="item" :value="item">
|
||||||
<apiStatus :status="item" />
|
<apiStatus :status="item" />
|
||||||
</a-option>
|
</a-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
|
@ -271,6 +271,7 @@
|
||||||
class?: string;
|
class?: string;
|
||||||
activeModule: string;
|
activeModule: string;
|
||||||
offspringIds: string[];
|
offspringIds: string[];
|
||||||
|
protocol: string; // 查看的协议类型
|
||||||
readOnly?: boolean; // 是否是只读模式
|
readOnly?: boolean; // 是否是只读模式
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
@ -346,12 +347,6 @@
|
||||||
titleSlotName: 'statusFilter',
|
titleSlotName: 'statusFilter',
|
||||||
width: 130,
|
width: 130,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: 'apiTestManagement.responsiblePerson',
|
|
||||||
dataIndex: 'createUserName',
|
|
||||||
showTooltip: true,
|
|
||||||
width: 120,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: 'apiTestManagement.path',
|
title: 'apiTestManagement.path',
|
||||||
slotName: 'path',
|
slotName: 'path',
|
||||||
|
@ -474,6 +469,7 @@
|
||||||
projectId: appStore.currentProjectId,
|
projectId: appStore.currentProjectId,
|
||||||
moduleIds: moduleIds.value,
|
moduleIds: moduleIds.value,
|
||||||
env: checkedEnv.value,
|
env: checkedEnv.value,
|
||||||
|
protocol: props.protocol,
|
||||||
filter: { status: statusFilters.value, type: methodFilters.value },
|
filter: { status: statusFilters.value, type: methodFilters.value },
|
||||||
};
|
};
|
||||||
setLoadListParams(params);
|
setLoadListParams(params);
|
||||||
|
@ -495,6 +491,13 @@
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.protocol,
|
||||||
|
() => {
|
||||||
|
loadApiList();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
function handleFilterHidden(val: boolean) {
|
function handleFilterHidden(val: boolean) {
|
||||||
if (!val) {
|
if (!val) {
|
||||||
loadApiList();
|
loadApiList();
|
||||||
|
|
|
@ -9,7 +9,12 @@
|
||||||
</MsEditableTab>
|
</MsEditableTab>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="activeApiTab.id === 'all'" class="flex-1">
|
<div v-show="activeApiTab.id === 'all'" class="flex-1">
|
||||||
<apiTable :active-module="props.activeModule" :offspring-ids="props.offspringIds" @open-api-tab="openApiTab" />
|
<apiTable
|
||||||
|
:active-module="props.activeModule"
|
||||||
|
:offspring-ids="props.offspringIds"
|
||||||
|
:protocol="props.protocol"
|
||||||
|
@open-api-tab="openApiTab"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="activeApiTab.id !== 'all'" class="flex-1 overflow-hidden">
|
<div v-if="activeApiTab.id !== 'all'" class="flex-1 overflow-hidden">
|
||||||
<a-tabs default-active-key="definition" animation lazy-load class="ms-api-tab-nav">
|
<a-tabs default-active-key="definition" animation lazy-load class="ms-api-tab-nav">
|
||||||
|
@ -68,7 +73,7 @@
|
||||||
<template #label>
|
<template #label>
|
||||||
<apiStatus :status="activeApiTab.status" />
|
<apiStatus :status="activeApiTab.status" />
|
||||||
</template>
|
</template>
|
||||||
<a-option v-for="item of RequestDefinitionStatus" :key="item" :value="item">
|
<a-option v-for="item of Object.values(RequestDefinitionStatus)" :key="item" :value="item">
|
||||||
<apiStatus :status="item" />
|
<apiStatus :status="item" />
|
||||||
</a-option>
|
</a-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
|
@ -178,6 +183,7 @@
|
||||||
activeModule: string;
|
activeModule: string;
|
||||||
offspringIds: string[];
|
offspringIds: string[];
|
||||||
moduleTree: ModuleTreeNode[]; // 模块树
|
moduleTree: ModuleTreeNode[]; // 模块树
|
||||||
|
protocol: string;
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits(['addDone']);
|
const emit = defineEmits(['addDone']);
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
:active-module="props.activeModule"
|
:active-module="props.activeModule"
|
||||||
:all-count="props.allCount"
|
:all-count="props.allCount"
|
||||||
:offspring-ids="props.offspringIds"
|
:offspring-ids="props.offspringIds"
|
||||||
|
:protocol="protocol"
|
||||||
/>
|
/>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane key="case" title="CASE" class="ms-api-tab-pane"> </a-tab-pane>
|
<a-tab-pane key="case" title="CASE" class="ms-api-tab-pane"> </a-tab-pane>
|
||||||
|
@ -26,6 +27,7 @@
|
||||||
allCount: number;
|
allCount: number;
|
||||||
activeModule: string;
|
activeModule: string;
|
||||||
offspringIds: string[];
|
offspringIds: string[];
|
||||||
|
protocol: string;
|
||||||
moduleTree: ModuleTreeNode[]; // 模块树
|
moduleTree: ModuleTreeNode[]; // 模块树
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,13 @@
|
||||||
<a-doption value="addModule">{{ t('apiTestManagement.addSubModule') }}</a-doption>
|
<a-doption value="addModule">{{ t('apiTestManagement.addSubModule') }}</a-doption>
|
||||||
</template>
|
</template>
|
||||||
</a-dropdown>
|
</a-dropdown>
|
||||||
<popConfirm mode="add" :all-names="rootModulesName" parent-id="NONE" @add-finish="initModules">
|
<popConfirm
|
||||||
|
mode="add"
|
||||||
|
:all-names="rootModulesName"
|
||||||
|
parent-id="NONE"
|
||||||
|
:add-module-api="addModule"
|
||||||
|
@add-finish="initModules"
|
||||||
|
>
|
||||||
<span id="addModulePopSpan"></span>
|
<span id="addModulePopSpan"></span>
|
||||||
</popConfirm>
|
</popConfirm>
|
||||||
</template>
|
</template>
|
||||||
|
@ -105,6 +111,7 @@
|
||||||
mode="add"
|
mode="add"
|
||||||
:all-names="(nodeData.children || []).map((e: ModuleTreeNode) => e.name || '')"
|
:all-names="(nodeData.children || []).map((e: ModuleTreeNode) => e.name || '')"
|
||||||
:parent-id="nodeData.id"
|
:parent-id="nodeData.id"
|
||||||
|
:add-module-api="addModule"
|
||||||
@close="resetFocusNodeKey"
|
@close="resetFocusNodeKey"
|
||||||
@add-finish="() => initModules()"
|
@add-finish="() => initModules()"
|
||||||
>
|
>
|
||||||
|
@ -119,6 +126,8 @@
|
||||||
:node-id="nodeData.id"
|
:node-id="nodeData.id"
|
||||||
:field-config="{ field: renameFolderTitle }"
|
:field-config="{ field: renameFolderTitle }"
|
||||||
:all-names="(nodeData.children || []).map((e: ModuleTreeNode) => e.name || '')"
|
:all-names="(nodeData.children || []).map((e: ModuleTreeNode) => e.name || '')"
|
||||||
|
:update-module-api="updateModule"
|
||||||
|
:update-api-node-api="updateModule"
|
||||||
@close="resetFocusNodeKey"
|
@close="resetFocusNodeKey"
|
||||||
@rename-finish="initModules"
|
@rename-finish="initModules"
|
||||||
>
|
>
|
||||||
|
@ -144,11 +153,13 @@
|
||||||
|
|
||||||
import { getProtocolList } from '@/api/modules/api-test/common';
|
import { getProtocolList } from '@/api/modules/api-test/common';
|
||||||
import {
|
import {
|
||||||
|
addModule,
|
||||||
deleteModule,
|
deleteModule,
|
||||||
getModuleCount,
|
getModuleCount,
|
||||||
getModuleTree,
|
getModuleTree,
|
||||||
getModuleTreeOnlyModules,
|
getModuleTreeOnlyModules,
|
||||||
moveModule,
|
moveModule,
|
||||||
|
updateModule,
|
||||||
} from '@/api/modules/api-test/management';
|
} from '@/api/modules/api-test/management';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useModal from '@/hooks/useModal';
|
import useModal from '@/hooks/useModal';
|
||||||
|
@ -168,7 +179,7 @@
|
||||||
activeModule: 'all',
|
activeModule: 'all',
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const emit = defineEmits(['init', 'newApi', 'import', 'folderNodeSelect', 'clickApiNode']);
|
const emit = defineEmits(['init', 'newApi', 'import', 'folderNodeSelect', 'clickApiNode', 'changeProtocol']);
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -345,7 +356,7 @@
|
||||||
if (isSetDefaultKey) {
|
if (isSetDefaultKey) {
|
||||||
selectedKeys.value = [folderTree.value[0].id];
|
selectedKeys.value = [folderTree.value[0].id];
|
||||||
}
|
}
|
||||||
emit('init', folderTree.value);
|
emit('init', folderTree.value, moduleProtocol.value);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
@ -377,6 +388,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleProtocolChange() {
|
async function handleProtocolChange() {
|
||||||
|
emit('changeProtocol', moduleProtocol.value);
|
||||||
await initModules();
|
await initModules();
|
||||||
initModuleCount();
|
initModuleCount();
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,12 @@
|
||||||
<div class="p-[24px]">
|
<div class="p-[24px]">
|
||||||
<moduleTree
|
<moduleTree
|
||||||
:active-node-id="activeApi?.id"
|
:active-node-id="activeApi?.id"
|
||||||
@init="(val) => (folderTree = val)"
|
@init="handleModuleInit"
|
||||||
@new-api="newApi"
|
@new-api="newApi"
|
||||||
@import="importDrawerVisible = true"
|
@import="importDrawerVisible = true"
|
||||||
@folder-node-select="handleNodeSelect"
|
@folder-node-select="handleNodeSelect"
|
||||||
@click-api-node="handleApiNodeClick"
|
@click-api-node="handleApiNodeClick"
|
||||||
|
@change-protocol="handleProtocolChange"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="b-0 absolute w-[88%]">
|
<!-- <div class="b-0 absolute w-[88%]">
|
||||||
|
@ -42,6 +43,7 @@
|
||||||
:all-count="allCount"
|
:all-count="allCount"
|
||||||
:active-module="activeModule"
|
:active-module="activeModule"
|
||||||
:offspring-ids="offspringIds"
|
:offspring-ids="offspringIds"
|
||||||
|
:protocol="protocol"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -66,9 +68,15 @@
|
||||||
const allCount = ref(0);
|
const allCount = ref(0);
|
||||||
const importDrawerVisible = ref(false);
|
const importDrawerVisible = ref(false);
|
||||||
const offspringIds = ref<string[]>([]);
|
const offspringIds = ref<string[]>([]);
|
||||||
|
const protocol = ref('HTTP');
|
||||||
const activeApi = ref<RequestParam>();
|
const activeApi = ref<RequestParam>();
|
||||||
const managementRef = ref<InstanceType<typeof management>>();
|
const managementRef = ref<InstanceType<typeof management>>();
|
||||||
|
|
||||||
|
function handleModuleInit(tree, _protocol: string) {
|
||||||
|
folderTree.value = tree;
|
||||||
|
protocol.value = _protocol;
|
||||||
|
}
|
||||||
|
|
||||||
function newApi() {
|
function newApi() {
|
||||||
managementRef.value?.newTab();
|
managementRef.value?.newTab();
|
||||||
}
|
}
|
||||||
|
@ -86,6 +94,10 @@
|
||||||
activeApi.value = params;
|
activeApi.value = params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleProtocolChange(val: string) {
|
||||||
|
protocol.value = val;
|
||||||
|
}
|
||||||
|
|
||||||
provide('setActiveApi', setActiveApi);
|
provide('setActiveApi', setActiveApi);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue