refactor(接口管理): 接口定义-布局重构&另存为用例
This commit is contained in:
parent
ad99fd8f92
commit
63d905dc60
|
@ -1,5 +1,6 @@
|
||||||
import MSR from '@/api/http/index';
|
import MSR from '@/api/http/index';
|
||||||
import {
|
import {
|
||||||
|
AddCaseUrl,
|
||||||
AddDefinitionScheduleUrl,
|
AddDefinitionScheduleUrl,
|
||||||
AddDefinitionUrl,
|
AddDefinitionUrl,
|
||||||
AddModuleUrl,
|
AddModuleUrl,
|
||||||
|
@ -53,6 +54,7 @@ import {
|
||||||
|
|
||||||
import { ExecuteRequestParams } from '@/models/apiTest/common';
|
import { ExecuteRequestParams } from '@/models/apiTest/common';
|
||||||
import {
|
import {
|
||||||
|
AddApiCaseParams,
|
||||||
ApiCaseBatchEditParams,
|
ApiCaseBatchEditParams,
|
||||||
ApiCaseBatchParams,
|
ApiCaseBatchParams,
|
||||||
ApiCaseDetail,
|
ApiCaseDetail,
|
||||||
|
@ -342,3 +344,8 @@ export function batchEditCase(data: ApiCaseBatchEditParams) {
|
||||||
export function dragSort(data: DragSortParams) {
|
export function dragSort(data: DragSortParams) {
|
||||||
return MSR.post({ url: SortCaseUrl, data });
|
return MSR.post({ url: SortCaseUrl, data });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加接口用例
|
||||||
|
export function addCase(data: AddApiCaseParams) {
|
||||||
|
return MSR.post({ url: AddCaseUrl, data });
|
||||||
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ export const ToggleFollowDefinitionUrl = '/api/definition/follow'; // 接口定
|
||||||
export const OperationHistoryUrl = '/api/definition/operation-history'; // 接口定义-变更历史
|
export const OperationHistoryUrl = '/api/definition/operation-history'; // 接口定义-变更历史
|
||||||
export const SaveOperationHistoryUrl = '/api/definition/operation-history/save'; // 接口定义-另存变更历史为指定版本
|
export const SaveOperationHistoryUrl = '/api/definition/operation-history/save'; // 接口定义-另存变更历史为指定版本
|
||||||
export const RecoverOperationHistoryUrl = '/api/definition/operation-history/recover'; // 接口定义-变更历史恢复
|
export const RecoverOperationHistoryUrl = '/api/definition/operation-history/recover'; // 接口定义-变更历史恢复
|
||||||
|
export const DefinitionReferenceUrl = '/api/definition/get-reference'; // 获取接口引用关系
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mock
|
* Mock
|
||||||
|
@ -42,11 +43,6 @@ export const DefinitionMockPageUrl = '/api/definition/mock/page'; // mock列表
|
||||||
export const UpdateMockStatusUrl = '/api/definition/mock/enable/'; // 更新mock状态
|
export const UpdateMockStatusUrl = '/api/definition/mock/enable/'; // 更新mock状态
|
||||||
export const DeleteMockUrl = '/api/definition/mock/delete'; // 刪除mock
|
export const DeleteMockUrl = '/api/definition/mock/delete'; // 刪除mock
|
||||||
|
|
||||||
/**
|
|
||||||
* 接口引用关系
|
|
||||||
*/
|
|
||||||
export const DefinitionReferenceUrl = '/api/definition/get-reference'; // 获取接口引用关系
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* api回收站
|
* api回收站
|
||||||
*/
|
*/
|
||||||
|
@ -65,3 +61,4 @@ export const DeleteCaseUrl = '/api/case/delete'; // 删除接口用例
|
||||||
export const BatchDeleteCaseUrl = '/api/case/batch/delete'; // 批量删除接口用例
|
export const BatchDeleteCaseUrl = '/api/case/batch/delete'; // 批量删除接口用例
|
||||||
export const BatchEditCaseUrl = '/api/case/batch/edit'; // 批量编辑接口用例
|
export const BatchEditCaseUrl = '/api/case/batch/edit'; // 批量编辑接口用例
|
||||||
export const SortCaseUrl = '/api/case/edit/pos'; // 接口用例拖拽
|
export const SortCaseUrl = '/api/case/edit/pos'; // 接口用例拖拽
|
||||||
|
export const AddCaseUrl = '/api/case/add'; // 添加用例
|
||||||
|
|
|
@ -243,9 +243,6 @@
|
||||||
});
|
});
|
||||||
const buttonDropDownVisible = ref(false);
|
const buttonDropDownVisible = ref(false);
|
||||||
|
|
||||||
watchEffect(() => {
|
|
||||||
console.log('innerFileList', innerFileList.value);
|
|
||||||
});
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
// 回显文件
|
// 回显文件
|
||||||
const defaultFiles = innerFileList.value.filter((item) => item) || [];
|
const defaultFiles = innerFileList.value.filter((item) => item) || [];
|
||||||
|
|
|
@ -193,9 +193,6 @@
|
||||||
<div class="ms-params-popover-title !mb-[8px]">
|
<div class="ms-params-popover-title !mb-[8px]">
|
||||||
{{ t('ms.paramsInput.value') }}
|
{{ t('ms.paramsInput.value') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="ms-params-popover-subtitle">
|
|
||||||
{{ t('ms.paramsInput.value') }}
|
|
||||||
</div>
|
|
||||||
<div class="ms-params-popover-value mb-[8px]">
|
<div class="ms-params-popover-value mb-[8px]">
|
||||||
{{ innerValue }}
|
{{ innerValue }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -702,7 +699,7 @@
|
||||||
margin-bottom: 2px;
|
margin-bottom: 2px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
color: var(--color-text-4);
|
color: var(--color-text-1);
|
||||||
}
|
}
|
||||||
.ms-params-popover-value {
|
.ms-params-popover-value {
|
||||||
min-width: 100px;
|
min-width: 100px;
|
||||||
|
|
|
@ -21,7 +21,10 @@
|
||||||
:style="{ width: item.width }"
|
:style="{ width: item.width }"
|
||||||
>
|
>
|
||||||
<div class="text-[var(--color-text-4)]">{{ t(item.locale) }}</div>
|
<div class="text-[var(--color-text-4)]">{{ t(item.locale) }}</div>
|
||||||
<MsTagGroup v-if="Array.isArray(item.value)" :tag-list="item.value" size="small" is-string-tag />
|
<div v-if="Array.isArray(item.value)">
|
||||||
|
<MsTagGroup v-if="item.value.length > 0" :tag-list="item.value" size="small" is-string-tag />
|
||||||
|
<div v-else>-</div>
|
||||||
|
</div>
|
||||||
<slot v-else :name="item.key" :value="item.value">
|
<slot v-else :name="item.key" :value="item.value">
|
||||||
<a-tooltip :content="item.value" :disabled="isEmpty(item.value)">
|
<a-tooltip :content="item.value" :disabled="isEmpty(item.value)">
|
||||||
<div class="text-[var(--color-text-1)]">{{ item.value || '-' }}</div>
|
<div class="text-[var(--color-text-1)]">{{ item.value || '-' }}</div>
|
||||||
|
|
|
@ -21,13 +21,13 @@
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="props.direction === 'horizontal' && props.expandDirection === 'right' && !props.disabled"
|
v-if="props.direction === 'horizontal' && props.expandDirection === 'right' && !props.disabled"
|
||||||
class="absolute right-0 h-full w-[16px]"
|
class="absolute right-0 h-full w-[12px]"
|
||||||
>
|
>
|
||||||
<div class="expand-icon expand-icon--left" @click="() => changeExpand()">
|
<div class="expand-icon expand-icon--left" @click="() => changeExpand()">
|
||||||
<MsIcon
|
<MsIcon
|
||||||
:type="isExpanded ? 'icon-icon_up-left_outlined' : 'icon-icon_down-right_outlined'"
|
:type="isExpanded ? 'icon-icon_up-left_outlined' : 'icon-icon_down-right_outlined'"
|
||||||
class="text-[var(--color-text-brand)]"
|
class="!w-auto text-[var(--color-text-brand)]"
|
||||||
size="12"
|
size="9"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -43,13 +43,13 @@
|
||||||
<div class="ms-split-box-second">
|
<div class="ms-split-box-second">
|
||||||
<div
|
<div
|
||||||
v-if="props.direction === 'horizontal' && props.expandDirection === 'left' && !props.disabled"
|
v-if="props.direction === 'horizontal' && props.expandDirection === 'left' && !props.disabled"
|
||||||
class="absolute h-full w-[16px]"
|
class="absolute h-full w-[12px]"
|
||||||
>
|
>
|
||||||
<div class="expand-icon" @click="() => changeExpand()">
|
<div class="expand-icon" @click="() => changeExpand()">
|
||||||
<MsIcon
|
<MsIcon
|
||||||
:type="isExpanded ? 'icon-icon_up-left_outlined' : 'icon-icon_down-right_outlined'"
|
:type="isExpanded ? 'icon-icon_up-left_outlined' : 'icon-icon_down-right_outlined'"
|
||||||
class="text-[var(--color-text-brand)]"
|
class="!w-auto text-[var(--color-text-brand)]"
|
||||||
size="12"
|
size="9"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -207,3 +207,9 @@ export enum RequestExtractResultMatchingRule {
|
||||||
RANDOM = 'RANDOM', // 随机匹配
|
RANDOM = 'RANDOM', // 随机匹配
|
||||||
SPECIFIC = 'SPECIFIC', // 指定匹配
|
SPECIFIC = 'SPECIFIC', // 指定匹配
|
||||||
}
|
}
|
||||||
|
// 接口用例状态
|
||||||
|
export enum RequestCaseStatus {
|
||||||
|
DEPRECATED = 'DEPRECATED',
|
||||||
|
PROCESSING = 'PROCESSING',
|
||||||
|
DONE = 'DONE',
|
||||||
|
}
|
||||||
|
|
|
@ -131,4 +131,5 @@ export default {
|
||||||
'common.unFollowSuccess': 'Unfollow successfully',
|
'common.unFollowSuccess': 'Unfollow successfully',
|
||||||
'common.share': 'Share',
|
'common.share': 'Share',
|
||||||
'common.notRemind': `Don't remind again`,
|
'common.notRemind': `Don't remind again`,
|
||||||
|
'common.status': 'Status',
|
||||||
};
|
};
|
||||||
|
|
|
@ -134,4 +134,5 @@ export default {
|
||||||
'common.unFollowSuccess': '取消关注成功',
|
'common.unFollowSuccess': '取消关注成功',
|
||||||
'common.share': '分享',
|
'common.share': '分享',
|
||||||
'common.notRemind': '不再提醒',
|
'common.notRemind': '不再提醒',
|
||||||
|
'common.status': '状态',
|
||||||
};
|
};
|
||||||
|
|
|
@ -331,3 +331,11 @@ export interface ApiCaseBatchEditParams extends ApiCaseBatchParams {
|
||||||
environmentId?: string;
|
environmentId?: string;
|
||||||
type: string;
|
type: string;
|
||||||
}
|
}
|
||||||
|
// 添加用例参数
|
||||||
|
export interface AddApiCaseParams extends ExecuteRequestParams {
|
||||||
|
name: string;
|
||||||
|
priority: string;
|
||||||
|
status: string;
|
||||||
|
apiDefinitionId: string | number;
|
||||||
|
tags: string[];
|
||||||
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ export interface CommonParams {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
export interface EnvConfig {
|
export interface EnvConfig {
|
||||||
|
id?: string;
|
||||||
commonParams?: CommonParams;
|
commonParams?: CommonParams;
|
||||||
commonVariables: EnvConfigItem[];
|
commonVariables: EnvConfigItem[];
|
||||||
httpConfig: EnvConfigItem[];
|
httpConfig: EnvConfigItem[];
|
||||||
|
|
|
@ -273,7 +273,7 @@
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</div>
|
</div>
|
||||||
<paramTable
|
<paramTable
|
||||||
v-model:params="condition.extractParams"
|
:params="condition.extractParams"
|
||||||
:columns="sqlSourceColumns"
|
:columns="sqlSourceColumns"
|
||||||
:selectable="false"
|
:selectable="false"
|
||||||
:default-param-item="defaultKeyValueParamItem"
|
:default-param-item="defaultKeyValueParamItem"
|
||||||
|
@ -301,6 +301,7 @@
|
||||||
mode="button"
|
mode="button"
|
||||||
:step="100"
|
:step="100"
|
||||||
:min="0"
|
:min="0"
|
||||||
|
:precision="0"
|
||||||
class="w-[160px]"
|
class="w-[160px]"
|
||||||
model-event="input"
|
model-event="input"
|
||||||
/>
|
/>
|
||||||
|
@ -309,7 +310,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.extractors"
|
:params="condition.extractors"
|
||||||
:default-param-item="defaultExtractParamItem"
|
:default-param-item="defaultExtractParamItem"
|
||||||
:columns="extractParamsColumns"
|
:columns="extractParamsColumns"
|
||||||
:selectable="false"
|
:selectable="false"
|
||||||
|
@ -842,8 +843,10 @@ if (!result){
|
||||||
const protocolList = ref<ProtocolItem[]>([]);
|
const protocolList = ref<ProtocolItem[]>([]);
|
||||||
onBeforeMount(async () => {
|
onBeforeMount(async () => {
|
||||||
try {
|
try {
|
||||||
|
// TODO:数据从外面传进来
|
||||||
protocolList.value = await getProtocolList(appStore.currentOrgId);
|
protocolList.value = await getProtocolList(appStore.currentOrgId);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -899,12 +902,6 @@ if (!result){
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
color: var(--color-text-1);
|
color: var(--color-text-1);
|
||||||
}
|
}
|
||||||
.param-popover-subtitle {
|
|
||||||
margin-bottom: 2px;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 16px;
|
|
||||||
color: var(--color-text-4);
|
|
||||||
}
|
|
||||||
.param-popover-value {
|
.param-popover-value {
|
||||||
min-width: 100px;
|
min-width: 100px;
|
||||||
max-width: 280px;
|
max-width: 280px;
|
||||||
|
|
|
@ -5,7 +5,13 @@ import {
|
||||||
KeyValueParam,
|
KeyValueParam,
|
||||||
ResponseDefinition,
|
ResponseDefinition,
|
||||||
} from '@/models/apiTest/common';
|
} from '@/models/apiTest/common';
|
||||||
import { RequestContentTypeEnum, RequestParamsType, ResponseBodyFormat, ResponseComposition } from '@/enums/apiEnum';
|
import {
|
||||||
|
RequestCaseStatus,
|
||||||
|
RequestContentTypeEnum,
|
||||||
|
RequestParamsType,
|
||||||
|
ResponseBodyFormat,
|
||||||
|
ResponseComposition,
|
||||||
|
} from '@/enums/apiEnum';
|
||||||
|
|
||||||
// 请求 body 参数表格默认行的值
|
// 请求 body 参数表格默认行的值
|
||||||
export const defaultBodyParamsItem: ExecuteRequestFormBodyFormValue = {
|
export const defaultBodyParamsItem: ExecuteRequestFormBodyFormValue = {
|
||||||
|
@ -83,3 +89,18 @@ export const defaultKeyValueParamItem: KeyValueParam = {
|
||||||
|
|
||||||
// 请求的响应 response 的响应状态码集合
|
// 请求的响应 response 的响应状态码集合
|
||||||
export const statusCodes = [200, 201, 202, 203, 204, 205, 400, 401, 402, 403, 404, 405, 500, 501, 502, 503, 504, 505];
|
export const statusCodes = [200, 201, 202, 203, 204, 205, 400, 401, 402, 403, 404, 405, 500, 501, 502, 503, 504, 505];
|
||||||
|
|
||||||
|
// 用例等级选项
|
||||||
|
export const casePriorityOptions = [
|
||||||
|
{ label: 'P0', value: 'P0' },
|
||||||
|
{ label: 'P1', value: 'P1' },
|
||||||
|
{ label: 'P2', value: 'P2' },
|
||||||
|
{ label: 'P3', value: 'P3' },
|
||||||
|
];
|
||||||
|
|
||||||
|
// 用例状态选项
|
||||||
|
export const caseStatusOptions = [
|
||||||
|
{ label: 'apiTestManagement.processing', value: RequestCaseStatus.PROCESSING },
|
||||||
|
{ label: 'apiTestManagement.deprecate', value: RequestCaseStatus.DEPRECATED },
|
||||||
|
{ label: 'apiTestManagement.done', value: RequestCaseStatus.DONE },
|
||||||
|
];
|
||||||
|
|
|
@ -66,12 +66,6 @@
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
color: var(--color-text-1);
|
color: var(--color-text-1);
|
||||||
}
|
}
|
||||||
.param-popover-subtitle {
|
|
||||||
margin-bottom: 2px;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 16px;
|
|
||||||
color: var(--color-text-4);
|
|
||||||
}
|
|
||||||
.param-popover-value {
|
.param-popover-value {
|
||||||
min-width: 100px;
|
min-width: 100px;
|
||||||
max-width: 280px;
|
max-width: 280px;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<MsFormTable v-bind="props" :data="paramsData">
|
<MsFormTable v-bind="props" :data="paramsData" @change="handleFormTableChange">
|
||||||
<!-- 展开行-->
|
<!-- 展开行-->
|
||||||
<template #expand-icon="{ record }">
|
<template #expand-icon="{ record }">
|
||||||
<div class="flex flex-row items-center gap-[2px] text-[var(--color-text-4)]">
|
<div class="flex flex-row items-center gap-[2px] text-[var(--color-text-4)]">
|
||||||
|
@ -341,7 +341,7 @@
|
||||||
<span v-else></span>
|
<span v-else></span>
|
||||||
</template>
|
</template>
|
||||||
<template #host="{ record }">
|
<template #host="{ record }">
|
||||||
<MsTagGroup
|
<MsTagsGroup
|
||||||
v-if="Array.isArray(record.domain)"
|
v-if="Array.isArray(record.domain)"
|
||||||
:tag-list="getDomain(record.domain)"
|
:tag-list="getDomain(record.domain)"
|
||||||
size="small"
|
size="small"
|
||||||
|
@ -459,7 +459,6 @@
|
||||||
import MsFormTable, { FormTableColumn } from '@/components/pure/ms-form-table/index.vue';
|
import MsFormTable, { FormTableColumn } from '@/components/pure/ms-form-table/index.vue';
|
||||||
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
|
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
|
||||||
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||||
import MsTagGroup from '@/components/pure/ms-tag/ms-tag-group.vue';
|
|
||||||
import MsTagsGroup from '@/components/pure/ms-tag/ms-tag-group.vue';
|
import MsTagsGroup from '@/components/pure/ms-tag/ms-tag-group.vue';
|
||||||
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
||||||
import { MsFileItem } from '@/components/pure/ms-upload/types';
|
import { MsFileItem } from '@/components/pure/ms-upload/types';
|
||||||
|
@ -495,7 +494,7 @@
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
params?: any[];
|
params?: Record<string, any>[];
|
||||||
defaultParamItem?: Record<string, any>; // 默认参数项,用于添加新行时的默认值
|
defaultParamItem?: Record<string, any>; // 默认参数项,用于添加新行时的默认值
|
||||||
columns: ParamTableColumn[];
|
columns: ParamTableColumn[];
|
||||||
scroll?: {
|
scroll?: {
|
||||||
|
@ -548,7 +547,7 @@
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'change', data: any[]): void; // 都触发这个事件以通知父组件参数数组被更改
|
(e: 'change', data: Record<string, any>[], isInit?: boolean): void; // 都触发这个事件以通知父组件参数数组被更改
|
||||||
(e: 'moreActionSelect', event: ActionsItem, record: Record<string, any>): void;
|
(e: 'moreActionSelect', event: ActionsItem, record: Record<string, any>): void;
|
||||||
(e: 'projectChange', projectId: string): void;
|
(e: 'projectChange', projectId: string): void;
|
||||||
(e: 'treeDelete', record: Record<string, any>): void;
|
(e: 'treeDelete', record: Record<string, any>): void;
|
||||||
|
@ -557,12 +556,10 @@
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const paramsData = ref<any[]>(props.params);
|
const paramsData = ref<Record<string, any>[]>([]);
|
||||||
|
|
||||||
function emitChange(from: string, isInit?: boolean) {
|
function emitChange(from: string, isInit?: boolean) {
|
||||||
if (!isInit) {
|
emit('change', paramsData.value, isInit);
|
||||||
emit('change', paramsData.value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const paramsLength = computed(() => paramsData.value.length);
|
const paramsLength = computed(() => paramsData.value.length);
|
||||||
|
@ -659,28 +656,28 @@
|
||||||
|
|
||||||
const hostVisible = ref(false);
|
const hostVisible = ref(false);
|
||||||
const hostData = ref<any[]>([]);
|
const hostData = ref<any[]>([]);
|
||||||
const hostColumn = [
|
// const hostColumn = [
|
||||||
{
|
// {
|
||||||
title: t('project.environmental.http.host'),
|
// title: t('project.environmental.http.host'),
|
||||||
dataIndex: 'host',
|
// dataIndex: 'host',
|
||||||
showTooltip: true,
|
// showTooltip: true,
|
||||||
width: 300,
|
// width: 300,
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
title: t('project.environmental.http.desc'),
|
// title: t('project.environmental.http.desc'),
|
||||||
dataIndex: 'description',
|
// dataIndex: 'description',
|
||||||
},
|
// },
|
||||||
];
|
// ];
|
||||||
|
|
||||||
const showHostModal = (record: Record<string, any>) => {
|
const showHostModal = (record: Record<string, any>) => {
|
||||||
hostVisible.value = true;
|
hostVisible.value = true;
|
||||||
hostData.value = record.domain || [];
|
hostData.value = record.domain || [];
|
||||||
};
|
};
|
||||||
|
|
||||||
const hostModalClose = () => {
|
// const hostModalClose = () => {
|
||||||
hostVisible.value = false;
|
// hostVisible.value = false;
|
||||||
hostData.value = [];
|
// hostData.value = [];
|
||||||
};
|
// };
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
if (props.columns.some((e) => e.dataIndex === 'projectId')) {
|
if (props.columns.some((e) => e.dataIndex === 'projectId')) {
|
||||||
|
@ -698,6 +695,7 @@
|
||||||
*/
|
*/
|
||||||
function addTableLine(rowIndex: number, addLineDisabled?: boolean, isInit?: boolean) {
|
function addTableLine(rowIndex: number, addLineDisabled?: boolean, isInit?: boolean) {
|
||||||
if (addLineDisabled) {
|
if (addLineDisabled) {
|
||||||
|
emitChange('addTableLine addLineDisabled', isInit);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (rowIndex === paramsData.value.length - 1) {
|
if (rowIndex === paramsData.value.length - 1) {
|
||||||
|
@ -708,8 +706,8 @@
|
||||||
...cloneDeep(props.defaultParamItem), // 深拷贝,避免有嵌套引用类型,数据隔离
|
...cloneDeep(props.defaultParamItem), // 深拷贝,避免有嵌套引用类型,数据隔离
|
||||||
enable: true, // 是否勾选
|
enable: true, // 是否勾选
|
||||||
} as any);
|
} as any);
|
||||||
emitChange('addTableLine', isInit);
|
|
||||||
}
|
}
|
||||||
|
emitChange('addTableLine', isInit);
|
||||||
handleMustContainColChange(true);
|
handleMustContainColChange(true);
|
||||||
handleTypeCheckingColChange(true);
|
handleTypeCheckingColChange(true);
|
||||||
}
|
}
|
||||||
|
@ -920,6 +918,11 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleFormTableChange(data: any[]) {
|
||||||
|
paramsData.value = [...data];
|
||||||
|
emitChange('handleFormTableChange');
|
||||||
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
addTableLine,
|
addTableLine,
|
||||||
});
|
});
|
||||||
|
@ -942,12 +945,6 @@
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
color: var(--color-text-1);
|
color: var(--color-text-1);
|
||||||
}
|
}
|
||||||
.param-popover-subtitle {
|
|
||||||
margin-bottom: 2px;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 16px;
|
|
||||||
color: var(--color-text-4);
|
|
||||||
}
|
|
||||||
.param-popover-value {
|
.param-popover-value {
|
||||||
min-width: 100px;
|
min-width: 100px;
|
||||||
max-width: 280px;
|
max-width: 280px;
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
</div>
|
</div>
|
||||||
<paramTable
|
<paramTable
|
||||||
v-else-if="innerParams.bodyType === RequestBodyFormat.FORM_DATA"
|
v-else-if="innerParams.bodyType === RequestBodyFormat.FORM_DATA"
|
||||||
v-model:params="currentTableParams"
|
:params="currentTableParams"
|
||||||
:scroll="{ minWidth: 1160 }"
|
:scroll="{ minWidth: 1160 }"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:height-used="heightUsed"
|
:height-used="heightUsed"
|
||||||
|
@ -40,7 +40,7 @@
|
||||||
/>
|
/>
|
||||||
<paramTable
|
<paramTable
|
||||||
v-else-if="innerParams.bodyType === RequestBodyFormat.WWW_FORM"
|
v-else-if="innerParams.bodyType === RequestBodyFormat.WWW_FORM"
|
||||||
v-model:params="currentTableParams"
|
:params="currentTableParams"
|
||||||
:scroll="{ minWidth: 1160 }"
|
:scroll="{ minWidth: 1160 }"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:height-used="heightUsed"
|
:height-used="heightUsed"
|
||||||
|
@ -115,6 +115,7 @@
|
||||||
import { RequestBodyFormat, RequestParamsType } from '@/enums/apiEnum';
|
import { RequestBodyFormat, RequestParamsType } from '@/enums/apiEnum';
|
||||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||||
|
|
||||||
|
import { filterKeyValParams } from '../utils';
|
||||||
import { defaultBodyParamsItem } from '@/views/api-test/components/config';
|
import { defaultBodyParamsItem } from '@/views/api-test/components/config';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
@ -315,14 +316,15 @@
|
||||||
*/
|
*/
|
||||||
function handleBatchParamApply(resultArr: any[]) {
|
function handleBatchParamApply(resultArr: any[]) {
|
||||||
const files = currentTableParams.value.filter((item) => item.paramType === RequestParamsType.FILE);
|
const files = currentTableParams.value.filter((item) => item.paramType === RequestParamsType.FILE);
|
||||||
if (resultArr.length < currentTableParams.value.length) {
|
const filterResult = filterKeyValParams(currentTableParams.value, defaultBodyParamsItem);
|
||||||
currentTableParams.value.splice(0, currentTableParams.value.length - 1, ...files, ...resultArr);
|
if (filterResult.lastDataIsDefault) {
|
||||||
} else {
|
|
||||||
currentTableParams.value = [
|
currentTableParams.value = [
|
||||||
...files,
|
...files,
|
||||||
...resultArr,
|
...resultArr,
|
||||||
currentTableParams.value[currentTableParams.value.length - 1],
|
currentTableParams.value[currentTableParams.value.length - 1],
|
||||||
].filter(Boolean);
|
].filter(Boolean);
|
||||||
|
} else {
|
||||||
|
currentTableParams.value = [...files, ...resultArr].filter(Boolean);
|
||||||
}
|
}
|
||||||
emit('change');
|
emit('change');
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,10 +24,9 @@
|
||||||
import batchAddKeyVal from '@/views/api-test/components/batchAddKeyVal.vue';
|
import batchAddKeyVal from '@/views/api-test/components/batchAddKeyVal.vue';
|
||||||
import paramTable, { ParamTableColumn } from '@/views/api-test/components/paramTable.vue';
|
import paramTable, { ParamTableColumn } from '@/views/api-test/components/paramTable.vue';
|
||||||
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
|
||||||
|
|
||||||
import { EnableKeyValueParam } from '@/models/apiTest/common';
|
import { EnableKeyValueParam } from '@/models/apiTest/common';
|
||||||
|
|
||||||
|
import { filterKeyValParams } from '../utils';
|
||||||
import { defaultHeaderParamsItem } from '@/views/api-test/components/config';
|
import { defaultHeaderParamsItem } from '@/views/api-test/components/config';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
@ -41,8 +40,6 @@
|
||||||
(e: 'change'): void; // 数据发生变化
|
(e: 'change'): void; // 数据发生变化
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
const innerParams = useVModel(props, 'params', emit);
|
const innerParams = useVModel(props, 'params', emit);
|
||||||
|
|
||||||
const columns: ParamTableColumn[] = [
|
const columns: ParamTableColumn[] = [
|
||||||
|
@ -80,10 +77,11 @@
|
||||||
* 批量参数代码转换为参数表格数据
|
* 批量参数代码转换为参数表格数据
|
||||||
*/
|
*/
|
||||||
function handleBatchParamApply(resultArr: any[]) {
|
function handleBatchParamApply(resultArr: any[]) {
|
||||||
if (resultArr.length < innerParams.value.length) {
|
const filterResult = filterKeyValParams(innerParams.value, defaultHeaderParamsItem);
|
||||||
innerParams.value.splice(0, innerParams.value.length - 1, ...resultArr);
|
if (filterResult.lastDataIsDefault) {
|
||||||
|
innerParams.value = [...resultArr, innerParams.value[innerParams.value.length - 1]].filter(Boolean);
|
||||||
} else {
|
} else {
|
||||||
innerParams.value = [...resultArr, innerParams.value[innerParams.value.length - 1]];
|
innerParams.value = resultArr.filter(Boolean);
|
||||||
}
|
}
|
||||||
emit('change');
|
emit('change');
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,7 @@
|
||||||
</template>
|
</template>
|
||||||
</a-dropdown>
|
</a-dropdown>
|
||||||
<!-- 接口定义-定义模式,直接保存接口定义 -->
|
<!-- 接口定义-定义模式,直接保存接口定义 -->
|
||||||
<a-button v-else type="primary" @click="() => handleSelect('save')">
|
<a-button v-else type="primary" :loading="saveLoading" @click="() => handleSelect('save')">
|
||||||
{{ t('common.save') }}
|
{{ t('common.save') }}
|
||||||
</a-button>
|
</a-button>
|
||||||
</template>
|
</template>
|
||||||
|
@ -138,32 +138,44 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div ref="splitContainerRef" class="h-[calc(100%-40px)]">
|
<div class="px-[16px]">
|
||||||
|
<MsTab
|
||||||
|
v-model:active-key="requestVModel.activeTab"
|
||||||
|
:content-tab-list="contentTabList"
|
||||||
|
:get-text-func="getTabBadge"
|
||||||
|
class="no-content relative mt-[8px]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div ref="splitContainerRef" class="h-[calc(100%-97px)]">
|
||||||
<MsSplitBox
|
<MsSplitBox
|
||||||
ref="splitBoxRef"
|
ref="horizontalSplitBoxRef"
|
||||||
|
:size="props.isDefinition ? 0.7 : 1"
|
||||||
|
:max="props.isDefinition ? 0.9 : 1"
|
||||||
|
:min="props.isDefinition ? 0.7 : 1"
|
||||||
|
:disabled="!props.isDefinition"
|
||||||
|
:class="!props.isDefinition ? 'hidden-second' : ''"
|
||||||
|
:first-container-class="!props.isDefinition ? 'border-r-0' : ''"
|
||||||
|
direction="horizontal"
|
||||||
|
expand-direction="right"
|
||||||
|
>
|
||||||
|
<template #first>
|
||||||
|
<MsSplitBox
|
||||||
|
ref="verticalSplitBoxRef"
|
||||||
v-model:size="splitBoxSize"
|
v-model:size="splitBoxSize"
|
||||||
:max="!showResponse ? 1 : 0.98"
|
:max="!showResponse ? 1 : 0.98"
|
||||||
min="10px"
|
min="10px"
|
||||||
:direction="activeLayout"
|
:direction="activeLayout"
|
||||||
second-container-class="!overflow-y-hidden"
|
second-container-class="!overflow-y-hidden"
|
||||||
:class="!showResponse ? 'hidden-second' : ''"
|
:class="!showResponse ? 'hidden-second' : ''"
|
||||||
@expand-change="handleExpandChange"
|
@expand-change="handleVerticalExpandChange"
|
||||||
>
|
>
|
||||||
<template #first>
|
<template #first>
|
||||||
<a-spin class="block h-full w-full" :loading="requestVModel.executeLoading || loading">
|
<a-spin class="block h-full w-full" :loading="requestVModel.executeLoading || loading">
|
||||||
<div
|
<div
|
||||||
:class="`flex h-full min-w-[800px] flex-col px-[18px] pb-[16px] ${
|
:class="`flex h-full min-w-[800px] flex-col p-[16px] ${
|
||||||
activeLayout === 'horizontal' ? ' pr-[16px]' : ''
|
activeLayout === 'horizontal' ? ' pr-[16px]' : ''
|
||||||
}`"
|
}`"
|
||||||
>
|
>
|
||||||
<div>
|
|
||||||
<MsTab
|
|
||||||
v-model:active-key="requestVModel.activeTab"
|
|
||||||
:content-tab-list="contentTabList"
|
|
||||||
:get-text-func="getTabBadge"
|
|
||||||
class="no-content relative mb-[8px] border-b border-[var(--color-text-n8)]"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="tab-pane-container">
|
<div class="tab-pane-container">
|
||||||
<a-spin
|
<a-spin
|
||||||
v-if="requestVModel.activeTab === RequestComposition.PLUGIN"
|
v-if="requestVModel.activeTab === RequestComposition.PLUGIN"
|
||||||
|
@ -253,19 +265,126 @@
|
||||||
:is-http-protocol="isHttpProtocol"
|
:is-http-protocol="isHttpProtocol"
|
||||||
:is-priority-local-exec="isPriorityLocalExec"
|
:is-priority-local-exec="isPriorityLocalExec"
|
||||||
:request-url="requestVModel.url"
|
:request-url="requestVModel.url"
|
||||||
:is-expanded="isExpanded"
|
:is-expanded="isVerticalExpanded"
|
||||||
:hide-layout-switch="props.hideResponseLayoutSwitch"
|
:hide-layout-switch="props.hideResponseLayoutSwitch"
|
||||||
:request-task-result="requestVModel.response"
|
:request-task-result="requestVModel.response"
|
||||||
:is-edit="props.isDefinition && isHttpProtocol"
|
:is-edit="props.isDefinition && isHttpProtocol"
|
||||||
:upload-temp-file-api="props.uploadTempFileApi"
|
:upload-temp-file-api="props.uploadTempFileApi"
|
||||||
:loading="requestVModel.executeLoading || loading"
|
:loading="requestVModel.executeLoading || loading"
|
||||||
@change-expand="changeExpand"
|
@change-expand="changeVerticalExpand"
|
||||||
@change-layout="handleActiveLayoutChange"
|
@change-layout="handleActiveLayoutChange"
|
||||||
@change="handleActiveDebugChange"
|
@change="handleActiveDebugChange"
|
||||||
@execute="execute"
|
@execute="execute"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</MsSplitBox>
|
</MsSplitBox>
|
||||||
|
</template>
|
||||||
|
<template v-if="props.isDefinition" #second>
|
||||||
|
<div class="p-[16px]">
|
||||||
|
<!-- TODO:第一版没有模板 -->
|
||||||
|
<!-- <MsFormCreate v-model:api="fApi" :rule="currentApiTemplateRules" :option="options" /> -->
|
||||||
|
<a-form ref="activeApiTabFormRef" :model="requestVModel" layout="vertical">
|
||||||
|
<a-form-item
|
||||||
|
field="name"
|
||||||
|
:label="t('apiTestManagement.apiName')"
|
||||||
|
class="mb-[16px]"
|
||||||
|
:rules="[{ required: true, message: t('apiTestManagement.apiNameRequired') }]"
|
||||||
|
>
|
||||||
|
<a-input
|
||||||
|
v-model:model-value="requestVModel.name"
|
||||||
|
:max-length="255"
|
||||||
|
:placeholder="t('apiTestManagement.apiNamePlaceholder')"
|
||||||
|
allow-clear
|
||||||
|
@change="handleActiveApiChange"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item :label="t('apiTestManagement.belongModule')" class="mb-[16px]">
|
||||||
|
<a-tree-select
|
||||||
|
v-model:modelValue="requestVModel.moduleId"
|
||||||
|
:data="selectTree"
|
||||||
|
:field-names="{ title: 'name', key: 'id', children: 'children' }"
|
||||||
|
:tree-props="{
|
||||||
|
virtualListProps: {
|
||||||
|
height: 200,
|
||||||
|
threshold: 200,
|
||||||
|
},
|
||||||
|
}"
|
||||||
|
allow-search
|
||||||
|
@change="handleActiveApiChange"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item :label="t('apiTestManagement.apiStatus')" class="mb-[16px]">
|
||||||
|
<a-select
|
||||||
|
v-model:model-value="requestVModel.status"
|
||||||
|
:placeholder="t('common.pleaseSelect')"
|
||||||
|
class="param-input w-full"
|
||||||
|
@change="handleActiveApiChange"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
<apiStatus :status="requestVModel.status" />
|
||||||
|
</template>
|
||||||
|
<a-option v-for="item of Object.values(RequestDefinitionStatus)" :key="item" :value="item">
|
||||||
|
<apiStatus :status="item" />
|
||||||
|
</a-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item :label="t('common.tag')" class="mb-[16px]">
|
||||||
|
<MsTagsInput v-model:model-value="requestVModel.tags" @change="handleActiveApiChange" />
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item :label="t('common.desc')" class="mb-[16px]">
|
||||||
|
<a-textarea
|
||||||
|
v-model:model-value="requestVModel.description"
|
||||||
|
:max-length="1000"
|
||||||
|
@change="handleActiveApiChange"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
<!-- TODO:第一版先不做依赖 -->
|
||||||
|
<!-- <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="requestVModel.preDependency.length === 0 && requestVModel.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))]">
|
||||||
|
{{ requestVModel.preDependency.length }}
|
||||||
|
</div>
|
||||||
|
{{ t('apiTestManagement.dependencyUnit') }}
|
||||||
|
</div>
|
||||||
|
<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))]">
|
||||||
|
{{ requestVModel.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>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a-modal
|
<a-modal
|
||||||
|
@ -285,7 +404,11 @@
|
||||||
:rules="[{ required: true, message: t('apiTestDebug.requestNameRequired') }]"
|
:rules="[{ required: true, message: t('apiTestDebug.requestNameRequired') }]"
|
||||||
asterisk-position="end"
|
asterisk-position="end"
|
||||||
>
|
>
|
||||||
<a-input v-model:model-value="saveModalForm.name" :placeholder="t('apiTestDebug.requestNamePlaceholder')" />
|
<a-input
|
||||||
|
v-model:model-value="saveModalForm.name"
|
||||||
|
:max-length="255"
|
||||||
|
:placeholder="t('apiTestDebug.requestNamePlaceholder')"
|
||||||
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item
|
<a-form-item
|
||||||
v-if="isHttpProtocol"
|
v-if="isHttpProtocol"
|
||||||
|
@ -294,7 +417,11 @@
|
||||||
:rules="[{ required: true, message: t('apiTestDebug.requestUrlRequired') }]"
|
:rules="[{ required: true, message: t('apiTestDebug.requestUrlRequired') }]"
|
||||||
asterisk-position="end"
|
asterisk-position="end"
|
||||||
>
|
>
|
||||||
<a-input v-model:model-value="saveModalForm.path" :placeholder="t('apiTestDebug.commonPlaceholder')" />
|
<a-input
|
||||||
|
v-model:model-value="saveModalForm.path"
|
||||||
|
:max-length="255"
|
||||||
|
:placeholder="t('apiTestDebug.commonPlaceholder')"
|
||||||
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item :label="t('apiTestDebug.requestModule')" class="mb-0">
|
<a-form-item :label="t('apiTestDebug.requestModule')" class="mb-0">
|
||||||
<a-tree-select
|
<a-tree-select
|
||||||
|
@ -312,6 +439,43 @@
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
|
<a-modal
|
||||||
|
v-model:visible="saveCaseModalVisible"
|
||||||
|
:title="t('common.save')"
|
||||||
|
:ok-loading="saveCaseLoading"
|
||||||
|
class="ms-modal-form"
|
||||||
|
title-align="start"
|
||||||
|
body-class="!p-0"
|
||||||
|
@before-ok="saveAsCase"
|
||||||
|
@cancel="handleSaveCaseCancel"
|
||||||
|
>
|
||||||
|
<a-form ref="saveCaseModalFormRef" :model="saveCaseModalForm" layout="vertical">
|
||||||
|
<a-form-item
|
||||||
|
field="name"
|
||||||
|
:label="t('case.caseName')"
|
||||||
|
:rules="[{ required: true, message: t('case.caseNameRequired') }]"
|
||||||
|
asterisk-position="end"
|
||||||
|
>
|
||||||
|
<a-input v-model:model-value="saveCaseModalForm.name" :placeholder="t('case.caseNamePlaceholder')" />
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item field="priority" :label="t('case.caseLevel')">
|
||||||
|
<a-select v-model:model-value="saveCaseModalForm.priority" :options="casePriorityOptions"></a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item field="status" :label="t('common.status')">
|
||||||
|
<a-select v-model:model-value="saveCaseModalForm.status" :options="caseStatusOptions"></a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item field="tags" :label="t('common.tag')">
|
||||||
|
<MsTagsInput
|
||||||
|
v-model:model-value="saveCaseModalForm.tags"
|
||||||
|
placeholder="common.tagsInputPlaceholder"
|
||||||
|
allow-clear
|
||||||
|
unique-value
|
||||||
|
retain-input-value
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-modal>
|
||||||
|
<addDependencyDrawer v-if="props.isDefinition" v-model:visible="showAddDependencyDrawer" :mode="addDependencyMode" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
@ -323,6 +487,7 @@
|
||||||
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 MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
||||||
import auth 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';
|
||||||
|
@ -330,8 +495,10 @@
|
||||||
import setting 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';
|
||||||
|
import apiStatus from '@/views/api-test/components/apiStatus.vue';
|
||||||
|
|
||||||
import { getPluginScript, getProtocolList } from '@/api/modules/api-test/common';
|
import { getPluginScript, getProtocolList } from '@/api/modules/api-test/common';
|
||||||
|
import { addCase } from '@/api/modules/api-test/management';
|
||||||
import { getSocket } from '@/api/modules/project-management/commonScript';
|
import { getSocket } from '@/api/modules/project-management/commonScript';
|
||||||
import { getLocalConfig } from '@/api/modules/user/index';
|
import { getLocalConfig } from '@/api/modules/user/index';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
@ -348,18 +515,24 @@
|
||||||
PluginConfig,
|
PluginConfig,
|
||||||
RequestTaskResult,
|
RequestTaskResult,
|
||||||
} from '@/models/apiTest/common';
|
} from '@/models/apiTest/common';
|
||||||
|
import { AddApiCaseParams } from '@/models/apiTest/management';
|
||||||
import { ModuleTreeNode, TransferFileParams } from '@/models/common';
|
import { ModuleTreeNode, TransferFileParams } from '@/models/common';
|
||||||
|
import { EnvConfig } from '@/models/projectManagement/environmental';
|
||||||
import {
|
import {
|
||||||
RequestAuthType,
|
RequestAuthType,
|
||||||
RequestBodyFormat,
|
RequestBodyFormat,
|
||||||
|
RequestCaseStatus,
|
||||||
RequestComposition,
|
RequestComposition,
|
||||||
RequestConditionProcessor,
|
RequestConditionProcessor,
|
||||||
|
RequestDefinitionStatus,
|
||||||
RequestMethods,
|
RequestMethods,
|
||||||
RequestParamsType,
|
RequestParamsType,
|
||||||
} from '@/enums/apiEnum';
|
} from '@/enums/apiEnum';
|
||||||
|
|
||||||
import type { ResponseItem } from './response/edit.vue';
|
import type { ResponseItem } from './response/edit.vue';
|
||||||
import {
|
import {
|
||||||
|
casePriorityOptions,
|
||||||
|
caseStatusOptions,
|
||||||
defaultBodyParamsItem,
|
defaultBodyParamsItem,
|
||||||
defaultHeaderParamsItem,
|
defaultHeaderParamsItem,
|
||||||
defaultKeyValueParamItem,
|
defaultKeyValueParamItem,
|
||||||
|
@ -373,6 +546,9 @@
|
||||||
const httpBody = defineAsyncComponent(() => import('./body.vue'));
|
const httpBody = defineAsyncComponent(() => import('./body.vue'));
|
||||||
const httpQuery = defineAsyncComponent(() => import('./query.vue'));
|
const httpQuery = defineAsyncComponent(() => import('./query.vue'));
|
||||||
const httpRest = defineAsyncComponent(() => import('./rest.vue'));
|
const httpRest = defineAsyncComponent(() => import('./rest.vue'));
|
||||||
|
const addDependencyDrawer = defineAsyncComponent(
|
||||||
|
() => import('@/views/api-test/management/components/addDependencyDrawer.vue')
|
||||||
|
);
|
||||||
|
|
||||||
export interface RequestCustomAttr {
|
export interface RequestCustomAttr {
|
||||||
isNew: boolean;
|
isNew: boolean;
|
||||||
|
@ -395,6 +571,7 @@
|
||||||
isDefinition?: boolean; // 是否是接口定义模式
|
isDefinition?: boolean; // 是否是接口定义模式
|
||||||
hideResponseLayoutSwitch?: boolean; // 是否隐藏响应体的布局切换
|
hideResponseLayoutSwitch?: boolean; // 是否隐藏响应体的布局切换
|
||||||
otherParams?: Record<string, any>; // 保存请求时的其他参数
|
otherParams?: Record<string, any>; // 保存请求时的其他参数
|
||||||
|
currentEnvConfig?: EnvConfig;
|
||||||
executeApi: (params: ExecuteRequestParams) => Promise<any>; // 执行接口
|
executeApi: (params: ExecuteRequestParams) => Promise<any>; // 执行接口
|
||||||
localExecuteApi: (url: string, params: ExecuteRequestParams) => Promise<any>; // 本地执行接口
|
localExecuteApi: (url: string, params: ExecuteRequestParams) => Promise<any>; // 本地执行接口
|
||||||
createApi: (...args) => Promise<any>; // 创建接口
|
createApi: (...args) => Promise<any>; // 创建接口
|
||||||
|
@ -409,7 +586,7 @@
|
||||||
update: string;
|
update: string;
|
||||||
};
|
};
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits(['addDone', 'save', 'saveAsCase']);
|
const emit = defineEmits(['addDone']);
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -768,18 +945,18 @@
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const splitBoxRef = ref<InstanceType<typeof MsSplitBox>>();
|
const horizontalSplitBoxRef = ref<InstanceType<typeof MsSplitBox>>();
|
||||||
const isExpanded = ref(true);
|
const verticalSplitBoxRef = ref<InstanceType<typeof MsSplitBox>>();
|
||||||
|
const isVerticalExpanded = ref(true);
|
||||||
function handleExpandChange(val: boolean) {
|
function handleVerticalExpandChange(val: boolean) {
|
||||||
isExpanded.value = val;
|
isVerticalExpanded.value = val;
|
||||||
}
|
}
|
||||||
function changeExpand(val: boolean) {
|
function changeVerticalExpand(val: boolean) {
|
||||||
isExpanded.value = val;
|
isVerticalExpanded.value = val;
|
||||||
if (val) {
|
if (val) {
|
||||||
splitBoxRef.value?.expand(0.6);
|
verticalSplitBoxRef.value?.expand(0.6);
|
||||||
} else {
|
} else {
|
||||||
splitBoxRef.value?.collapse(
|
verticalSplitBoxRef.value?.collapse(
|
||||||
splitContainerRef.value
|
splitContainerRef.value
|
||||||
? `${splitContainerRef.value.clientHeight - (props.hideResponseLayoutSwitch ? 37 : 42)}px`
|
? `${splitContainerRef.value.clientHeight - (props.hideResponseLayoutSwitch ? 37 : 42)}px`
|
||||||
: 0
|
: 0
|
||||||
|
@ -791,17 +968,23 @@
|
||||||
() => showResponse.value,
|
() => showResponse.value,
|
||||||
(val) => {
|
(val) => {
|
||||||
if (val) {
|
if (val) {
|
||||||
changeExpand(true);
|
changeVerticalExpand(true);
|
||||||
} else {
|
} else {
|
||||||
changeExpand(false);
|
changeVerticalExpand(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
function handleActiveLayoutChange() {
|
function handleActiveLayoutChange() {
|
||||||
isExpanded.value = true;
|
isVerticalExpanded.value = true;
|
||||||
splitBoxSize.value = 0.6;
|
splitBoxSize.value = 0.6;
|
||||||
splitBoxRef.value?.expand(0.6);
|
verticalSplitBoxRef.value?.expand(0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleActiveApiChange() {
|
||||||
|
if (requestVModel.value) {
|
||||||
|
requestVModel.value.unSaved = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const reportId = ref('');
|
const reportId = ref('');
|
||||||
|
@ -876,6 +1059,7 @@
|
||||||
* @param executeType 执行类型,执行时传入
|
* @param executeType 执行类型,执行时传入
|
||||||
*/
|
*/
|
||||||
function makeRequestParams(executeType?: 'localExec' | 'serverExec') {
|
function makeRequestParams(executeType?: 'localExec' | 'serverExec') {
|
||||||
|
const isExecute = executeType === 'localExec' || executeType === 'serverExec';
|
||||||
const { formDataBody, wwwFormBody } = requestVModel.value.body;
|
const { formDataBody, wwwFormBody } = requestVModel.value.body;
|
||||||
const polymorphicName = protocolOptions.value.find(
|
const polymorphicName = protocolOptions.value.find(
|
||||||
(e) => e.value === requestVModel.value.protocol
|
(e) => e.value === requestVModel.value.protocol
|
||||||
|
@ -883,8 +1067,16 @@
|
||||||
let parseRequestBodyResult;
|
let parseRequestBodyResult;
|
||||||
let requestParams;
|
let requestParams;
|
||||||
if (isHttpProtocol.value) {
|
if (isHttpProtocol.value) {
|
||||||
const realFormDataBodyValues = filterKeyValParams(formDataBody.formValues, defaultBodyParamsItem).validParams;
|
const realFormDataBodyValues = filterKeyValParams(
|
||||||
const realWwwFormBodyValues = filterKeyValParams(wwwFormBody.formValues, defaultBodyParamsItem).validParams;
|
formDataBody.formValues,
|
||||||
|
defaultBodyParamsItem,
|
||||||
|
isExecute
|
||||||
|
).validParams;
|
||||||
|
const realWwwFormBodyValues = filterKeyValParams(
|
||||||
|
wwwFormBody.formValues,
|
||||||
|
defaultBodyParamsItem,
|
||||||
|
isExecute
|
||||||
|
).validParams;
|
||||||
parseRequestBodyResult = parseRequestBodyFiles(
|
parseRequestBodyResult = parseRequestBodyFiles(
|
||||||
requestVModel.value.body,
|
requestVModel.value.body,
|
||||||
requestVModel.value.uploadFileIds, // 外面解析详情的时候传入
|
requestVModel.value.uploadFileIds, // 外面解析详情的时候传入
|
||||||
|
@ -901,12 +1093,12 @@
|
||||||
formValues: realWwwFormBodyValues,
|
formValues: realWwwFormBodyValues,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
headers: filterKeyValParams(requestVModel.value.headers, defaultHeaderParamsItem).validParams,
|
headers: filterKeyValParams(requestVModel.value.headers, defaultHeaderParamsItem, isExecute).validParams,
|
||||||
method: requestVModel.value.method,
|
method: requestVModel.value.method,
|
||||||
otherConfig: requestVModel.value.otherConfig,
|
otherConfig: requestVModel.value.otherConfig,
|
||||||
path: requestVModel.value.url || requestVModel.value.path,
|
path: requestVModel.value.url || requestVModel.value.path,
|
||||||
query: filterKeyValParams(requestVModel.value.query, defaultRequestParamsItem).validParams,
|
query: filterKeyValParams(requestVModel.value.query, defaultRequestParamsItem, isExecute).validParams,
|
||||||
rest: filterKeyValParams(requestVModel.value.rest, defaultRequestParamsItem).validParams,
|
rest: filterKeyValParams(requestVModel.value.rest, defaultRequestParamsItem, isExecute).validParams,
|
||||||
url: requestVModel.value.url,
|
url: requestVModel.value.url,
|
||||||
polymorphicName,
|
polymorphicName,
|
||||||
};
|
};
|
||||||
|
@ -932,7 +1124,7 @@
|
||||||
status: requestVModel.value.status,
|
status: requestVModel.value.status,
|
||||||
response: requestVModel.value.responseDefinition?.map((e) => ({
|
response: requestVModel.value.responseDefinition?.map((e) => ({
|
||||||
...e,
|
...e,
|
||||||
headers: filterKeyValParams(e.headers, defaultKeyValueParamItem).validParams,
|
headers: filterKeyValParams(e.headers, defaultKeyValueParamItem, isExecute).validParams,
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
@ -942,7 +1134,7 @@
|
||||||
return {
|
return {
|
||||||
id: requestVModel.value.id.toString(),
|
id: requestVModel.value.id.toString(),
|
||||||
reportId: reportId.value,
|
reportId: reportId.value,
|
||||||
environmentId: '',
|
environmentId: props.currentEnvConfig?.id || '',
|
||||||
name: requestName,
|
name: requestName,
|
||||||
moduleId: requestModuleId,
|
moduleId: requestModuleId,
|
||||||
...apiDefinitionParams,
|
...apiDefinitionParams,
|
||||||
|
@ -1018,7 +1210,7 @@
|
||||||
requestVModel.value.executeLoading = false;
|
requestVModel.value.executeLoading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateDebug() {
|
async function updateRequest() {
|
||||||
try {
|
try {
|
||||||
saveLoading.value = true;
|
saveLoading.value = true;
|
||||||
await props.updateApi({
|
await props.updateApi({
|
||||||
|
@ -1039,38 +1231,58 @@
|
||||||
/**
|
/**
|
||||||
* 保存请求
|
* 保存请求
|
||||||
*/
|
*/
|
||||||
async function handleSave(done: (closed: boolean) => void) {
|
async function realSave(fullParams?: Record<string, any>, silence?: boolean) {
|
||||||
saveModalFormRef.value?.validate(async (errors) => {
|
|
||||||
if (!errors) {
|
|
||||||
try {
|
try {
|
||||||
|
if (!silence) {
|
||||||
saveLoading.value = true;
|
saveLoading.value = true;
|
||||||
if (requestVModel.value.isNew) {
|
}
|
||||||
// 若是新建的,走添加
|
let params;
|
||||||
const res = await props.createApi({
|
if (props.isDefinition) {
|
||||||
...makeRequestParams(),
|
params = {
|
||||||
|
...(fullParams || makeRequestParams()),
|
||||||
|
...props.otherParams,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
params = {
|
||||||
|
...(fullParams || makeRequestParams()),
|
||||||
...saveModalForm.value,
|
...saveModalForm.value,
|
||||||
path: isHttpProtocol.value ? saveModalForm.value.path : undefined,
|
path: isHttpProtocol.value ? saveModalForm.value.path : undefined,
|
||||||
...props.otherParams,
|
...props.otherParams,
|
||||||
});
|
};
|
||||||
|
}
|
||||||
|
const res = await props.createApi(params);
|
||||||
|
if (!silence) {
|
||||||
|
Message.success(t('common.saveSuccess'));
|
||||||
|
}
|
||||||
requestVModel.value.id = res.id;
|
requestVModel.value.id = res.id;
|
||||||
requestVModel.value.num = res.num;
|
requestVModel.value.num = res.num;
|
||||||
requestVModel.value.isNew = false;
|
requestVModel.value.isNew = false;
|
||||||
Message.success(t('common.saveSuccess'));
|
|
||||||
requestVModel.value.unSaved = false;
|
requestVModel.value.unSaved = false;
|
||||||
requestVModel.value.name = saveModalForm.value.name;
|
requestVModel.value.name = res.name;
|
||||||
requestVModel.value.label = saveModalForm.value.name;
|
requestVModel.value.label = res.name;
|
||||||
requestVModel.value.url = saveModalForm.value.path;
|
requestVModel.value.url = res.path;
|
||||||
saveLoading.value = false;
|
requestVModel.value.path = res.path;
|
||||||
|
console.log('requestVModel.value', requestVModel.value);
|
||||||
|
if (!props.isDefinition) {
|
||||||
saveModalVisible.value = false;
|
saveModalVisible.value = false;
|
||||||
done(true);
|
}
|
||||||
|
if (!silence) {
|
||||||
|
saveLoading.value = false;
|
||||||
emit('addDone');
|
emit('addDone');
|
||||||
} else {
|
|
||||||
updateDebug();
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
saveLoading.value = false;
|
saveLoading.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleSave(done: (closed: boolean) => void) {
|
||||||
|
saveModalFormRef.value?.validate(async (errors) => {
|
||||||
|
if (!errors) {
|
||||||
|
await realSave();
|
||||||
|
done(true);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
done(false);
|
done(false);
|
||||||
}
|
}
|
||||||
|
@ -1079,22 +1291,27 @@
|
||||||
* 保存快捷键处理
|
* 保存快捷键处理
|
||||||
*/
|
*/
|
||||||
async function handleSaveShortcut() {
|
async function handleSaveShortcut() {
|
||||||
if (!requestVModel.value.isNew) {
|
|
||||||
// 更新接口不需要弹窗,直接更新保存
|
|
||||||
updateDebug();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
if (!isHttpProtocol.value) {
|
if (!isHttpProtocol.value) {
|
||||||
// 插件需要校验动态表单
|
// 插件需要校验动态表单
|
||||||
await fApi.value?.validate();
|
await fApi.value?.validate();
|
||||||
}
|
}
|
||||||
|
if (!requestVModel.value.isNew) {
|
||||||
|
// 更新接口不需要弹窗,直接更新保存
|
||||||
|
updateRequest();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!props.isDefinition) {
|
||||||
|
// 接口调试需要弹窗保存
|
||||||
saveModalForm.value = {
|
saveModalForm.value = {
|
||||||
name: requestVModel.value.name || '',
|
name: requestVModel.value.name || '',
|
||||||
path: requestVModel.value.url || '',
|
path: requestVModel.value.url || '',
|
||||||
moduleId: 'root',
|
moduleId: 'root',
|
||||||
};
|
};
|
||||||
saveModalVisible.value = true;
|
saveModalVisible.value = true;
|
||||||
|
} else {
|
||||||
|
realSave();
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
@ -1106,6 +1323,78 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const saveCaseModalVisible = ref(false);
|
||||||
|
const saveCaseLoading = ref(false);
|
||||||
|
const saveCaseModalForm = ref({
|
||||||
|
name: '',
|
||||||
|
priority: 'P0',
|
||||||
|
status: RequestCaseStatus.PROCESSING,
|
||||||
|
tags: [],
|
||||||
|
});
|
||||||
|
const saveCaseModalFormRef = ref<FormInstance>();
|
||||||
|
|
||||||
|
function handleSaveCaseCancel() {
|
||||||
|
saveCaseModalForm.value = {
|
||||||
|
name: '',
|
||||||
|
priority: 'P0',
|
||||||
|
status: RequestCaseStatus.PROCESSING,
|
||||||
|
tags: [],
|
||||||
|
};
|
||||||
|
saveCaseModalVisible.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存为用例
|
||||||
|
function saveAsCase() {
|
||||||
|
saveCaseModalFormRef.value?.validate(async (errors) => {
|
||||||
|
if (!errors) {
|
||||||
|
try {
|
||||||
|
saveCaseLoading.value = true;
|
||||||
|
const definitionParams = makeRequestParams();
|
||||||
|
if (requestVModel.value.isNew) {
|
||||||
|
// 未保存过的接口保存为用例,先保存接口定义,再保存为用例
|
||||||
|
await realSave(definitionParams, true);
|
||||||
|
}
|
||||||
|
const params: AddApiCaseParams = {
|
||||||
|
...definitionParams,
|
||||||
|
...saveCaseModalForm.value,
|
||||||
|
projectId: appStore.currentProjectId,
|
||||||
|
environmentId: props.currentEnvConfig?.id || '',
|
||||||
|
apiDefinitionId: requestVModel.value.id,
|
||||||
|
};
|
||||||
|
await addCase(params);
|
||||||
|
emit('addDone');
|
||||||
|
Message.success(t('common.saveSuccess'));
|
||||||
|
saveCaseModalVisible.value = false;
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
} finally {
|
||||||
|
saveCaseLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 未保存过的接口保存为用例,先保存接口定义,再保存为用例
|
||||||
|
async function saveNewDefinition() {
|
||||||
|
try {
|
||||||
|
if (!isHttpProtocol.value) {
|
||||||
|
// 插件需要校验动态表单
|
||||||
|
await fApi.value?.validate();
|
||||||
|
}
|
||||||
|
saveCaseModalVisible.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' });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const activeApiTabFormRef = ref<FormInstance>();
|
||||||
const isUrlError = ref(false);
|
const isUrlError = ref(false);
|
||||||
function handleSelect(value: string | number | Record<string, any> | undefined) {
|
function handleSelect(value: string | number | Record<string, any> | undefined) {
|
||||||
if (requestVModel.value.url === '' && requestVModel.value.protocol === 'HTTP') {
|
if (requestVModel.value.url === '' && requestVModel.value.protocol === 'HTTP') {
|
||||||
|
@ -1113,18 +1402,62 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
isUrlError.value = false;
|
isUrlError.value = false;
|
||||||
|
activeApiTabFormRef.value?.validate(async (errors) => {
|
||||||
|
if (errors) {
|
||||||
|
horizontalSplitBoxRef.value?.expand();
|
||||||
|
} else {
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case 'save':
|
case 'save':
|
||||||
emit('save', makeRequestParams());
|
handleSaveShortcut();
|
||||||
break;
|
break;
|
||||||
case 'saveAsCase':
|
case 'saveAsCase':
|
||||||
emit('saveAsCase', makeRequestParams());
|
saveNewDefinition();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// const fApi = ref();
|
||||||
|
// const options = {
|
||||||
|
// form: {
|
||||||
|
// layout: 'vertical',
|
||||||
|
// labelPosition: 'right',
|
||||||
|
// size: 'small',
|
||||||
|
// labelWidth: '00px',
|
||||||
|
// hideRequiredAsterisk: false,
|
||||||
|
// showMessage: true,
|
||||||
|
// inlineMessage: false,
|
||||||
|
// scrollToFirstError: true,
|
||||||
|
// },
|
||||||
|
// submitBtn: false,
|
||||||
|
// resetBtn: false,
|
||||||
|
// };
|
||||||
|
// const currentApiTemplateRules = [];
|
||||||
|
const showAddDependencyDrawer = ref(false);
|
||||||
|
const addDependencyMode = ref<'pre' | 'post'>('pre');
|
||||||
|
|
||||||
|
// function handleDddDependency(value: string | number | Record<string, any> | undefined) {
|
||||||
|
// switch (value) {
|
||||||
|
// case 'pre':
|
||||||
|
// addDependencyMode.value = 'pre';
|
||||||
|
// showAddDependencyDrawer.value = true;
|
||||||
|
// break;
|
||||||
|
// case 'post':
|
||||||
|
// addDependencyMode.value = 'post';
|
||||||
|
// showAddDependencyDrawer.value = true;
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// function clearAllDependency() {
|
||||||
|
// activeApiTab.value.preDependency = [];
|
||||||
|
// activeApiTab.value.postDependency = [];
|
||||||
|
// }
|
||||||
|
|
||||||
function handleCancel() {
|
function handleCancel() {
|
||||||
saveModalFormRef.value?.resetFields();
|
saveModalFormRef.value?.resetFields();
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<paramTable
|
<paramTable
|
||||||
v-model:params="innerParams"
|
:params="innerParams"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:height-used="heightUsed"
|
:height-used="heightUsed"
|
||||||
:scroll="{ minWidth: 1160 }"
|
:scroll="{ minWidth: 1160 }"
|
||||||
|
@ -36,6 +36,7 @@
|
||||||
import { ExecuteRequestCommonParam } from '@/models/apiTest/common';
|
import { ExecuteRequestCommonParam } from '@/models/apiTest/common';
|
||||||
import { RequestParamsType } from '@/enums/apiEnum';
|
import { RequestParamsType } from '@/enums/apiEnum';
|
||||||
|
|
||||||
|
import { filterKeyValParams } from '../utils';
|
||||||
import { defaultRequestParamsItem } from '@/views/api-test/components/config';
|
import { defaultRequestParamsItem } from '@/views/api-test/components/config';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
@ -130,10 +131,11 @@
|
||||||
* 批量参数代码转换为参数表格数据
|
* 批量参数代码转换为参数表格数据
|
||||||
*/
|
*/
|
||||||
function handleBatchParamApply(resultArr: any[]) {
|
function handleBatchParamApply(resultArr: any[]) {
|
||||||
if (resultArr.length < innerParams.value.length) {
|
const filterResult = filterKeyValParams(innerParams.value, defaultRequestParamsItem);
|
||||||
innerParams.value.splice(0, innerParams.value.length - 1, ...resultArr);
|
if (filterResult.lastDataIsDefault) {
|
||||||
|
innerParams.value = [...resultArr, innerParams.value[innerParams.value.length - 1]].filter(Boolean);
|
||||||
} else {
|
} else {
|
||||||
innerParams.value = [...resultArr, innerParams.value[innerParams.value.length - 1]];
|
innerParams.value = resultArr.filter(Boolean);
|
||||||
}
|
}
|
||||||
emit('change');
|
emit('change');
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,7 +146,7 @@
|
||||||
</template>
|
</template>
|
||||||
<paramTable
|
<paramTable
|
||||||
v-else-if="activeResponse.responseActiveTab === ResponseComposition.HEADER"
|
v-else-if="activeResponse.responseActiveTab === ResponseComposition.HEADER"
|
||||||
v-model:params="activeResponse.headers"
|
:params="activeResponse.headers"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:default-param-item="defaultKeyValueParamItem"
|
:default-param-item="defaultKeyValueParamItem"
|
||||||
:selectable="false"
|
:selectable="false"
|
||||||
|
|
|
@ -153,7 +153,7 @@
|
||||||
activeTab: ResponseComposition;
|
activeTab: ResponseComposition;
|
||||||
isExpanded: boolean;
|
isExpanded: boolean;
|
||||||
isPriorityLocalExec: boolean;
|
isPriorityLocalExec: boolean;
|
||||||
requestUrl: string;
|
requestUrl?: string;
|
||||||
isHttpProtocol: boolean;
|
isHttpProtocol: boolean;
|
||||||
activeLayout?: Direction;
|
activeLayout?: Direction;
|
||||||
responseDefinition?: ResponseItem[];
|
responseDefinition?: ResponseItem[];
|
||||||
|
|
|
@ -102,7 +102,7 @@
|
||||||
requestResult?: RequestResult;
|
requestResult?: RequestResult;
|
||||||
console?: string;
|
console?: string;
|
||||||
isPriorityLocalExec: boolean;
|
isPriorityLocalExec: boolean;
|
||||||
requestUrl: string;
|
requestUrl?: string;
|
||||||
isHttpProtocol: boolean;
|
isHttpProtocol: boolean;
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits(['execute']);
|
const emit = defineEmits(['execute']);
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<paramTable
|
<paramTable
|
||||||
v-model:params="innerParams"
|
:params="innerParams"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:height-used="heightUsed"
|
:height-used="heightUsed"
|
||||||
:scroll="{ minWidth: 1160 }"
|
:scroll="{ minWidth: 1160 }"
|
||||||
|
@ -36,6 +36,7 @@
|
||||||
import { ExecuteRequestCommonParam } from '@/models/apiTest/common';
|
import { ExecuteRequestCommonParam } from '@/models/apiTest/common';
|
||||||
import { RequestParamsType } from '@/enums/apiEnum';
|
import { RequestParamsType } from '@/enums/apiEnum';
|
||||||
|
|
||||||
|
import { filterKeyValParams } from '../utils';
|
||||||
import { defaultRequestParamsItem } from '@/views/api-test/components/config';
|
import { defaultRequestParamsItem } from '@/views/api-test/components/config';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
@ -131,10 +132,11 @@
|
||||||
* 批量参数代码转换为参数表格数据
|
* 批量参数代码转换为参数表格数据
|
||||||
*/
|
*/
|
||||||
function handleBatchParamApply(resultArr: any[]) {
|
function handleBatchParamApply(resultArr: any[]) {
|
||||||
if (resultArr.length < innerParams.value.length) {
|
const filterResult = filterKeyValParams(innerParams.value, defaultRequestParamsItem);
|
||||||
innerParams.value.splice(0, innerParams.value.length - 1, ...resultArr);
|
if (filterResult.lastDataIsDefault) {
|
||||||
|
innerParams.value = [...resultArr, innerParams.value[innerParams.value.length - 1]].filter(Boolean);
|
||||||
} else {
|
} else {
|
||||||
innerParams.value = [...resultArr, innerParams.value[innerParams.value.length - 1]];
|
innerParams.value = resultArr.filter(Boolean);
|
||||||
}
|
}
|
||||||
emit('change');
|
emit('change');
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,8 +115,13 @@ export function parseRequestBodyFiles(
|
||||||
* 过滤无效参数
|
* 过滤无效参数
|
||||||
* @param params 原始参数数组
|
* @param params 原始参数数组
|
||||||
* @param defaultParamItem 默认参数项
|
* @param defaultParamItem 默认参数项
|
||||||
|
* @param filterEnable 是否过滤 enable 为 false 的参数
|
||||||
*/
|
*/
|
||||||
export function filterKeyValParams<T>(params: (T & Record<string, any>)[], defaultParamItem: Record<string, any>) {
|
export function filterKeyValParams<T>(
|
||||||
|
params: (T & Record<string, any>)[],
|
||||||
|
defaultParamItem: Record<string, any>,
|
||||||
|
filterEnable = false
|
||||||
|
) {
|
||||||
const lastData = cloneDeep(params[params.length - 1]);
|
const lastData = cloneDeep(params[params.length - 1]);
|
||||||
const defaultParam = cloneDeep(defaultParamItem);
|
const defaultParam = cloneDeep(defaultParamItem);
|
||||||
if (!lastData || !defaultParam) {
|
if (!lastData || !defaultParam) {
|
||||||
|
@ -138,6 +143,9 @@ export function filterKeyValParams<T>(params: (T & Record<string, any>)[], defau
|
||||||
} else {
|
} else {
|
||||||
validParams = params;
|
validParams = params;
|
||||||
}
|
}
|
||||||
|
if (filterEnable) {
|
||||||
|
validParams = validParams.filter((e) => e.enable === true);
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
lastDataIsDefault,
|
lastDataIsDefault,
|
||||||
validParams,
|
validParams,
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
:add-module-api="addDebugModule"
|
: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 type="icon" class="!mr-0 p-[2px]">
|
||||||
<MsIcon
|
<MsIcon
|
||||||
type="icon-icon_create_planarity"
|
type="icon-icon_create_planarity"
|
||||||
size="18"
|
size="18"
|
||||||
|
|
|
@ -72,6 +72,8 @@ export default {
|
||||||
'apiTestDebug.preconditionScriptName': 'Pre-script name',
|
'apiTestDebug.preconditionScriptName': 'Pre-script name',
|
||||||
'apiTestDebug.preconditionAssociatedSceneResult': 'Associated scene result',
|
'apiTestDebug.preconditionAssociatedSceneResult': 'Associated scene result',
|
||||||
'apiTestDebug.preconditionScriptNamePlaceholder': 'Please enter the pre-script name',
|
'apiTestDebug.preconditionScriptNamePlaceholder': 'Please enter the pre-script name',
|
||||||
|
'apiTestDebug.postConditionScriptName': 'Postscript name',
|
||||||
|
'apiTestDebug.postConditionScriptNamePlaceholder': 'Please enter the postscript name',
|
||||||
'apiTestDebug.preconditionAssociateResultDesc':
|
'apiTestDebug.preconditionAssociateResultDesc':
|
||||||
'Counted in the scene execution result as a custom script step. Execution error will affect the final scene execution result',
|
'Counted in the scene execution result as a custom script step. Execution error will affect the final scene execution result',
|
||||||
'apiTestDebug.manual': 'Manual entry',
|
'apiTestDebug.manual': 'Manual entry',
|
||||||
|
|
|
@ -68,6 +68,8 @@ export default {
|
||||||
'apiTestDebug.preconditionScriptName': '前置脚本名称',
|
'apiTestDebug.preconditionScriptName': '前置脚本名称',
|
||||||
'apiTestDebug.preconditionAssociatedSceneResult': '关联场景结果',
|
'apiTestDebug.preconditionAssociatedSceneResult': '关联场景结果',
|
||||||
'apiTestDebug.preconditionScriptNamePlaceholder': '请输入前置脚本名称',
|
'apiTestDebug.preconditionScriptNamePlaceholder': '请输入前置脚本名称',
|
||||||
|
'apiTestDebug.postConditionScriptName': '后置脚本名称',
|
||||||
|
'apiTestDebug.postConditionScriptNamePlaceholder': '请输入后置脚本名称',
|
||||||
'apiTestDebug.preconditionAssociateResultDesc':
|
'apiTestDebug.preconditionAssociateResultDesc':
|
||||||
'当作自定义脚本步骤统计到场景执行结果中,执行报错时会影响场景的最终执行结果',
|
'当作自定义脚本步骤统计到场景执行结果中,执行报错时会影响场景的最终执行结果',
|
||||||
'apiTestDebug.manual': '手动录入',
|
'apiTestDebug.manual': '手动录入',
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||||
import apiTable from './apiTable.vue';
|
import apiTable from './management/api/apiTable.vue';
|
||||||
import moduleTree from '@/views/api-test/management/components/moduleTree.vue';
|
import moduleTree from '@/views/api-test/management/components/moduleTree.vue';
|
||||||
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="['p-[16px_22px]', props.class]">
|
<div :class="['p-[0_16px_16px_16px]', props.class]">
|
||||||
<div class="mb-[16px] flex items-center justify-between">
|
<div class="mb-[16px] flex items-center justify-between">
|
||||||
<div class="flex items-center gap-[8px]">
|
<div class="flex items-center gap-[8px]">
|
||||||
<a-input-search
|
<a-input-search
|
||||||
|
@ -26,6 +26,7 @@
|
||||||
v-on="propsEvent"
|
v-on="propsEvent"
|
||||||
@selected-change="handleTableSelect"
|
@selected-change="handleTableSelect"
|
||||||
@batch-action="handleTableBatch"
|
@batch-action="handleTableBatch"
|
||||||
|
@drag-change="handleTableDragSort"
|
||||||
>
|
>
|
||||||
<template v-if="props.protocol === 'HTTP'" #methodFilter="{ columnConfig }">
|
<template v-if="props.protocol === 'HTTP'" #methodFilter="{ columnConfig }">
|
||||||
<a-trigger
|
<a-trigger
|
||||||
|
@ -81,28 +82,30 @@
|
||||||
v-if="props.protocol === 'HTTP'"
|
v-if="props.protocol === 'HTTP'"
|
||||||
v-model:model-value="record.method"
|
v-model:model-value="record.method"
|
||||||
class="param-input w-full"
|
class="param-input w-full"
|
||||||
|
size="mini"
|
||||||
@change="() => handleMethodChange(record)"
|
@change="() => handleMethodChange(record)"
|
||||||
>
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
<apiMethodName :method="record.method" is-tag />
|
<apiMethodName :method="record.method" tag-size="small" is-tag />
|
||||||
</template>
|
</template>
|
||||||
<a-option v-for="item of Object.values(RequestMethods)" :key="item" :value="item">
|
<a-option v-for="item of Object.values(RequestMethods)" :key="item" :value="item">
|
||||||
<apiMethodName :method="item" is-tag />
|
<apiMethodName :method="item" tag-size="small" is-tag />
|
||||||
</a-option>
|
</a-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
<apiMethodName v-else :method="record.method" is-tag />
|
<apiMethodName v-else :method="record.method" tag-size="small" is-tag />
|
||||||
</template>
|
</template>
|
||||||
<template #status="{ record }">
|
<template #status="{ record }">
|
||||||
<a-select
|
<a-select
|
||||||
v-model:model-value="record.status"
|
v-model:model-value="record.status"
|
||||||
class="param-input w-full"
|
class="param-input w-full"
|
||||||
|
size="mini"
|
||||||
@change="() => handleStatusChange(record)"
|
@change="() => handleStatusChange(record)"
|
||||||
>
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
<apiStatus :status="record.status" />
|
<apiStatus :status="record.status" size="small" />
|
||||||
</template>
|
</template>
|
||||||
<a-option v-for="item of Object.values(RequestDefinitionStatus)" :key="item" :value="item">
|
<a-option v-for="item of Object.values(RequestDefinitionStatus)" :key="item" :value="item">
|
||||||
<apiStatus :status="item" />
|
<apiStatus :status="item" size="small" />
|
||||||
</a-option>
|
</a-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</template>
|
</template>
|
||||||
|
@ -253,6 +256,7 @@
|
||||||
batchUpdateDefinition,
|
batchUpdateDefinition,
|
||||||
deleteDefinition,
|
deleteDefinition,
|
||||||
getDefinitionPage,
|
getDefinitionPage,
|
||||||
|
sortDefinition,
|
||||||
updateDefinition,
|
updateDefinition,
|
||||||
} from '@/api/modules/api-test/management';
|
} from '@/api/modules/api-test/management';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
@ -261,6 +265,7 @@
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
|
|
||||||
import { ApiDefinitionDetail } from '@/models/apiTest/management';
|
import { ApiDefinitionDetail } from '@/models/apiTest/management';
|
||||||
|
import { DragSortParams } from '@/models/common';
|
||||||
import { RequestDefinitionStatus, RequestMethods } from '@/enums/apiEnum';
|
import { RequestDefinitionStatus, RequestMethods } from '@/enums/apiEnum';
|
||||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||||
|
|
||||||
|
@ -375,7 +380,7 @@
|
||||||
selectable: true,
|
selectable: true,
|
||||||
showSelectAll: !props.readOnly,
|
showSelectAll: !props.readOnly,
|
||||||
draggable: props.readOnly ? undefined : { type: 'handle', width: 32 },
|
draggable: props.readOnly ? undefined : { type: 'handle', width: 32 },
|
||||||
heightUsed: 374,
|
heightUsed: 308,
|
||||||
},
|
},
|
||||||
(item) => ({
|
(item) => ({
|
||||||
...item,
|
...item,
|
||||||
|
@ -754,6 +759,20 @@
|
||||||
emit('openCopyApiTab', record);
|
emit('openCopyApiTab', record);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 拖拽排序
|
||||||
|
async function handleTableDragSort(params: DragSortParams) {
|
||||||
|
try {
|
||||||
|
await sortDefinition({
|
||||||
|
...params,
|
||||||
|
moduleId: moduleIds.value[0] || '',
|
||||||
|
});
|
||||||
|
Message.success(t('caseManagement.featureCase.sortSuccess'));
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
loadApiList,
|
loadApiList,
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,27 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="flex h-full flex-col">
|
<div class="flex flex-1 flex-col overflow-hidden">
|
||||||
<div class="border-b border-[var(--color-text-n8)] px-[22px] pb-[16px]">
|
<div v-show="activeApiTab.id === 'all'" class="flex-1 pt-[16px]">
|
||||||
<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.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
|
<apiTable
|
||||||
ref="apiTableRef"
|
ref="apiTableRef"
|
||||||
:active-module="props.activeModule"
|
:active-module="props.activeModule"
|
||||||
|
@ -48,15 +27,6 @@
|
||||||
/>
|
/>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane key="definition" :title="t('apiTestManagement.definition')" class="ms-api-tab-pane">
|
<a-tab-pane key="definition" :title="t('apiTestManagement.definition')" class="ms-api-tab-pane">
|
||||||
<MsSplitBox
|
|
||||||
ref="splitBoxRef"
|
|
||||||
:size="0.7"
|
|
||||||
:max="0.9"
|
|
||||||
:min="0.7"
|
|
||||||
direction="horizontal"
|
|
||||||
expand-direction="right"
|
|
||||||
>
|
|
||||||
<template #first>
|
|
||||||
<requestComposition
|
<requestComposition
|
||||||
v-model:detail-loading="loading"
|
v-model:detail-loading="loading"
|
||||||
v-model:request="activeApiTab"
|
v-model:request="activeApiTab"
|
||||||
|
@ -75,118 +45,10 @@
|
||||||
:file-save-as-source-id="activeApiTab.id"
|
:file-save-as-source-id="activeApiTab.id"
|
||||||
:file-module-options-api="getTransferOptions"
|
:file-module-options-api="getTransferOptions"
|
||||||
:file-save-as-api="transferFile"
|
:file-save-as-api="transferFile"
|
||||||
|
:current-env-config="currentEnvConfig"
|
||||||
is-definition
|
is-definition
|
||||||
@add-done="emit('addDone')"
|
@add-done="handleAddDone"
|
||||||
@save="handleSave"
|
|
||||||
@save-as-case="handleSaveAsCase"
|
|
||||||
/>
|
/>
|
||||||
</template>
|
|
||||||
<template #second>
|
|
||||||
<div class="p-[18px]">
|
|
||||||
<!-- TODO:第一版没有模板 -->
|
|
||||||
<!-- <MsFormCreate v-model:api="fApi" :rule="currentApiTemplateRules" :option="options" /> -->
|
|
||||||
<a-form ref="activeApiTabFormRef" :model="activeApiTab" layout="vertical">
|
|
||||||
<a-form-item
|
|
||||||
field="name"
|
|
||||||
:label="t('apiTestManagement.apiName')"
|
|
||||||
class="mb-[16px]"
|
|
||||||
:rules="[{ required: true, message: t('apiTestManagement.apiNameRequired') }]"
|
|
||||||
>
|
|
||||||
<a-input
|
|
||||||
v-model:model-value="activeApiTab.name"
|
|
||||||
:max-length="255"
|
|
||||||
:placeholder="t('apiTestManagement.apiNamePlaceholder')"
|
|
||||||
allow-clear
|
|
||||||
@change="handleActiveApiChange"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item :label="t('apiTestManagement.belongModule')" class="mb-[16px]">
|
|
||||||
<a-tree-select
|
|
||||||
v-model:modelValue="activeApiTab.moduleId"
|
|
||||||
:data="selectTree"
|
|
||||||
:field-names="{ title: 'name', key: 'id', children: 'children' }"
|
|
||||||
:tree-props="{
|
|
||||||
virtualListProps: {
|
|
||||||
height: 200,
|
|
||||||
threshold: 200,
|
|
||||||
},
|
|
||||||
}"
|
|
||||||
allow-search
|
|
||||||
@change="handleActiveApiChange"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item :label="t('apiTestManagement.apiStatus')" class="mb-[16px]">
|
|
||||||
<a-select
|
|
||||||
v-model:model-value="activeApiTab.status"
|
|
||||||
:placeholder="t('common.pleaseSelect')"
|
|
||||||
class="param-input w-full"
|
|
||||||
@change="handleActiveApiChange"
|
|
||||||
>
|
|
||||||
<template #label>
|
|
||||||
<apiStatus :status="activeApiTab.status" />
|
|
||||||
</template>
|
|
||||||
<a-option v-for="item of Object.values(RequestDefinitionStatus)" :key="item" :value="item">
|
|
||||||
<apiStatus :status="item" />
|
|
||||||
</a-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item :label="t('common.tag')" class="mb-[16px]">
|
|
||||||
<MsTagsInput v-model:model-value="activeApiTab.tags" @change="handleActiveApiChange" />
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item :label="t('common.desc')" class="mb-[16px]">
|
|
||||||
<a-textarea
|
|
||||||
v-model:model-value="activeApiTab.description"
|
|
||||||
:max-length="1000"
|
|
||||||
@change="handleActiveApiChange"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
</a-form>
|
|
||||||
<!-- TODO:第一版先不做依赖 -->
|
|
||||||
<!-- <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-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>
|
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane v-if="!activeApiTab.isNew" key="case" :title="t('apiTestManagement.case')" class="ms-api-tab-pane">
|
<a-tab-pane v-if="!activeApiTab.isNew" key="case" :title="t('apiTestManagement.case')" class="ms-api-tab-pane">
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
|
@ -194,23 +56,15 @@
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<addDependencyDrawer v-model:visible="showAddDependencyDrawer" :mode="addDependencyMode" />
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { FormInstance, Message } from '@arco-design/web-vue';
|
|
||||||
import { cloneDeep } from 'lodash-es';
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
|
||||||
// import MsButton from '@/components/pure/ms-button/index.vue';
|
// 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 { TabItem } from '@/components/pure/ms-editable-tab/types';
|
||||||
// import MsFormCreate from '@/components/pure/ms-form-create/formCreate.vue';
|
// import MsFormCreate from '@/components/pure/ms-form-create/formCreate.vue';
|
||||||
import MsSplitBox from '@/components/pure/ms-split-box/index.vue';
|
|
||||||
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
|
||||||
import addDependencyDrawer from './addDependencyDrawer.vue';
|
|
||||||
import apiTable from './apiTable.vue';
|
import apiTable from './apiTable.vue';
|
||||||
import apiMethodName from '@/views/api-test/components/apiMethodName.vue';
|
|
||||||
import apiStatus from '@/views/api-test/components/apiStatus.vue';
|
|
||||||
|
|
||||||
import { getProtocolList, localExecuteApiDebug } from '@/api/modules/api-test/common';
|
import { getProtocolList, localExecuteApiDebug } from '@/api/modules/api-test/common';
|
||||||
import {
|
import {
|
||||||
|
@ -224,15 +78,11 @@
|
||||||
} from '@/api/modules/api-test/management';
|
} from '@/api/modules/api-test/management';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
import { filterTree } from '@/utils';
|
|
||||||
|
|
||||||
import { ExecuteBody, ProtocolItem, RequestTaskResult } from '@/models/apiTest/common';
|
import { ExecuteBody, ProtocolItem, RequestTaskResult } from '@/models/apiTest/common';
|
||||||
import {
|
import { ApiDefinitionDetail } from '@/models/apiTest/management';
|
||||||
ApiDefinitionCreateParams,
|
|
||||||
ApiDefinitionDetail,
|
|
||||||
ApiDefinitionUpdateParams,
|
|
||||||
} from '@/models/apiTest/management';
|
|
||||||
import { ModuleTreeNode } from '@/models/common';
|
import { ModuleTreeNode } from '@/models/common';
|
||||||
|
import { EnvConfig } from '@/models/projectManagement/environmental';
|
||||||
import {
|
import {
|
||||||
RequestAuthType,
|
RequestAuthType,
|
||||||
RequestBodyFormat,
|
RequestBodyFormat,
|
||||||
|
@ -258,13 +108,22 @@
|
||||||
protocol: string;
|
protocol: string;
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits(['addDone']);
|
const emit = defineEmits(['addDone']);
|
||||||
const definitionActiveKey = ref('definition');
|
|
||||||
const setActiveApi: ((params: RequestParam) => void) | undefined = inject('setActiveApi');
|
|
||||||
const refreshModuleTree: (() => Promise<any>) | undefined = inject('refreshModuleTree');
|
const refreshModuleTree: (() => Promise<any>) | undefined = inject('refreshModuleTree');
|
||||||
|
|
||||||
|
const definitionActiveKey = ref('definition');
|
||||||
|
const currentEnvConfig = inject<Ref<EnvConfig>>('currentEnvConfig');
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const apiTabs = defineModel<RequestParam[]>('apiTabs', {
|
||||||
|
required: true,
|
||||||
|
});
|
||||||
|
const activeApiTab = defineModel<RequestParam>('activeApiTab', {
|
||||||
|
required: true,
|
||||||
|
});
|
||||||
|
|
||||||
const protocols = ref<ProtocolItem[]>([]);
|
const protocols = ref<ProtocolItem[]>([]);
|
||||||
async function initProtocolList() {
|
async function initProtocolList() {
|
||||||
try {
|
try {
|
||||||
|
@ -279,37 +138,6 @@
|
||||||
initProtocolList();
|
initProtocolList();
|
||||||
});
|
});
|
||||||
|
|
||||||
const apiTabs = ref<RequestParam[]>([
|
|
||||||
{
|
|
||||||
id: 'all',
|
|
||||||
label: t('apiTestManagement.allApi'),
|
|
||||||
closable: false,
|
|
||||||
} as RequestParam,
|
|
||||||
]);
|
|
||||||
const activeApiTab = ref<RequestParam>(apiTabs.value[0] as RequestParam);
|
|
||||||
|
|
||||||
function handleActiveApiChange() {
|
|
||||||
if (activeApiTab.value) {
|
|
||||||
activeApiTab.value.unSaved = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => activeApiTab.value.id,
|
|
||||||
() => {
|
|
||||||
if (typeof setActiveApi === 'function') {
|
|
||||||
setActiveApi(activeApiTab.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const selectTree = computed(() =>
|
|
||||||
filterTree(cloneDeep(props.moduleTree), (e) => {
|
|
||||||
e.draggable = false;
|
|
||||||
return e.type === 'MODULE';
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
const initDefaultId = `definition-${Date.now()}`;
|
const initDefaultId = `definition-${Date.now()}`;
|
||||||
const defaultBodyParams: ExecuteBody = {
|
const defaultBodyParams: ExecuteBody = {
|
||||||
bodyType: RequestBodyFormat.NONE,
|
bodyType: RequestBodyFormat.NONE,
|
||||||
|
@ -438,11 +266,14 @@
|
||||||
|
|
||||||
const apiTableRef = ref<InstanceType<typeof apiTable>>();
|
const apiTableRef = ref<InstanceType<typeof apiTable>>();
|
||||||
|
|
||||||
function handleActiveTabChange(item: TabItem) {
|
watch(
|
||||||
if (item.id === 'all') {
|
() => activeApiTab.value.id,
|
||||||
|
(id) => {
|
||||||
|
if (id === 'all') {
|
||||||
apiTableRef.value?.loadApiList();
|
apiTableRef.value?.loadApiList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
async function openApiTab(apiInfo: ModuleTreeNode | ApiDefinitionDetail | string, isCopy = false) {
|
async function openApiTab(apiInfo: ModuleTreeNode | ApiDefinitionDetail | string, isCopy = false) {
|
||||||
|
@ -487,84 +318,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// const fApi = ref();
|
function handleAddDone() {
|
||||||
// const options = {
|
definitionActiveKey.value = 'preview'; // 保存完毕后切换到预览页
|
||||||
// form: {
|
|
||||||
// layout: 'vertical',
|
|
||||||
// labelPosition: 'right',
|
|
||||||
// size: 'small',
|
|
||||||
// labelWidth: '00px',
|
|
||||||
// hideRequiredAsterisk: false,
|
|
||||||
// showMessage: true,
|
|
||||||
// inlineMessage: false,
|
|
||||||
// scrollToFirstError: true,
|
|
||||||
// },
|
|
||||||
// submitBtn: false,
|
|
||||||
// resetBtn: false,
|
|
||||||
// };
|
|
||||||
// const currentApiTemplateRules = [];
|
|
||||||
const showAddDependencyDrawer = ref(false);
|
|
||||||
const addDependencyMode = ref<'pre' | 'post'>('pre');
|
|
||||||
|
|
||||||
// function handleDddDependency(value: string | number | Record<string, any> | undefined) {
|
|
||||||
// switch (value) {
|
|
||||||
// case 'pre':
|
|
||||||
// addDependencyMode.value = 'pre';
|
|
||||||
// showAddDependencyDrawer.value = true;
|
|
||||||
// break;
|
|
||||||
// case 'post':
|
|
||||||
// addDependencyMode.value = 'post';
|
|
||||||
// showAddDependencyDrawer.value = true;
|
|
||||||
// break;
|
|
||||||
// default:
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// function clearAllDependency() {
|
|
||||||
// activeApiTab.value.preDependency = [];
|
|
||||||
// activeApiTab.value.postDependency = [];
|
|
||||||
// }
|
|
||||||
|
|
||||||
const splitBoxRef = ref<InstanceType<typeof MsSplitBox>>();
|
|
||||||
const activeApiTabFormRef = ref<FormInstance>();
|
|
||||||
|
|
||||||
function handleSave(params: ApiDefinitionCreateParams) {
|
|
||||||
activeApiTabFormRef.value?.validate(async (errors) => {
|
|
||||||
if (errors) {
|
|
||||||
splitBoxRef.value?.expand();
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
appStore.showLoading();
|
|
||||||
let res;
|
|
||||||
params.versionId = 'v1.0';
|
|
||||||
if (params.isNew) {
|
|
||||||
res = await addDefinition(params);
|
|
||||||
} else {
|
|
||||||
res = await updateDefinition(params as ApiDefinitionUpdateParams);
|
|
||||||
}
|
|
||||||
activeApiTab.value.id = res.id;
|
|
||||||
activeApiTab.value.isNew = false;
|
|
||||||
Message.success(t('common.saveSuccess'));
|
|
||||||
activeApiTab.value.unSaved = false;
|
|
||||||
activeApiTab.value.name = res.name;
|
|
||||||
activeApiTab.value.label = res.name;
|
|
||||||
activeApiTab.value.url = res.path;
|
|
||||||
if (typeof refreshModuleTree === 'function') {
|
if (typeof refreshModuleTree === 'function') {
|
||||||
refreshModuleTree();
|
refreshModuleTree();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log(error);
|
|
||||||
} finally {
|
|
||||||
appStore.hideLoading();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleSaveAsCase(params: ApiDefinitionCreateParams) {
|
|
||||||
console.log(params);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshTable() {
|
function refreshTable() {
|
||||||
|
@ -579,12 +337,15 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.ms-api-tab-nav {
|
:deep(.ms-api-tab-nav) {
|
||||||
@apply h-full;
|
@apply h-full;
|
||||||
:deep(.arco-tabs-content) {
|
.arco-tabs-nav-tab {
|
||||||
|
border-bottom: 1px solid var(--color-text-n8);
|
||||||
|
}
|
||||||
|
.arco-tabs-content {
|
||||||
@apply pt-0;
|
@apply pt-0;
|
||||||
|
|
||||||
height: calc(100% - 51px);
|
height: calc(100% - 48px);
|
||||||
.arco-tabs-content-list {
|
.arco-tabs-content-list {
|
||||||
@apply h-full;
|
@apply h-full;
|
||||||
.arco-tabs-pane {
|
.arco-tabs-pane {
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
</template>
|
</template>
|
||||||
<div class="detail-collapse-item">
|
<div class="detail-collapse-item">
|
||||||
<template v-if="props.detail.protocol === 'HTTP'">
|
<template v-if="props.detail.protocol === 'HTTP'">
|
||||||
<div v-if="preivewDetail.headers.length > 0" class="detail-item">
|
<div v-if="previewDetail.headers.length > 0" class="detail-item">
|
||||||
<div class="detail-item-title">
|
<div class="detail-item-title">
|
||||||
<div class="detail-item-title-text">{{ t('apiTestManagement.requestHeader') }}</div>
|
<div class="detail-item-title-text">{{ t('apiTestManagement.requestHeader') }}</div>
|
||||||
<a-radio-group v-model:model-value="headerShowType" type="button" size="mini">
|
<a-radio-group v-model:model-value="headerShowType" type="button" size="mini">
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
<MsFormTable
|
<MsFormTable
|
||||||
v-show="headerShowType === 'table'"
|
v-show="headerShowType === 'table'"
|
||||||
:columns="headerColumns"
|
:columns="headerColumns"
|
||||||
:data="preivewDetail.headers || []"
|
:data="previewDetail.headers || []"
|
||||||
:selectable="false"
|
:selectable="false"
|
||||||
/>
|
/>
|
||||||
<MsCodeEditor
|
<MsCodeEditor
|
||||||
|
@ -53,7 +53,7 @@
|
||||||
</MsCodeEditor>
|
</MsCodeEditor>
|
||||||
<a-divider type="dashed" :margin="0" class="!mt-[16px] border-[var(--color-text-n8)]" />
|
<a-divider type="dashed" :margin="0" class="!mt-[16px] border-[var(--color-text-n8)]" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="preivewDetail.query.length > 0" class="detail-item">
|
<div v-if="previewDetail.query.length > 0" class="detail-item">
|
||||||
<div class="detail-item-title">
|
<div class="detail-item-title">
|
||||||
<div class="detail-item-title-text">Query</div>
|
<div class="detail-item-title-text">Query</div>
|
||||||
<a-radio-group v-model:model-value="queryShowType" type="button" size="mini">
|
<a-radio-group v-model:model-value="queryShowType" type="button" size="mini">
|
||||||
|
@ -64,7 +64,7 @@
|
||||||
<MsFormTable
|
<MsFormTable
|
||||||
v-show="queryShowType === 'table'"
|
v-show="queryShowType === 'table'"
|
||||||
:columns="queryRestColumns"
|
:columns="queryRestColumns"
|
||||||
:data="preivewDetail.query || []"
|
:data="previewDetail.query || []"
|
||||||
:selectable="false"
|
:selectable="false"
|
||||||
/>
|
/>
|
||||||
<MsCodeEditor
|
<MsCodeEditor
|
||||||
|
@ -92,7 +92,7 @@
|
||||||
</MsCodeEditor>
|
</MsCodeEditor>
|
||||||
<a-divider type="dashed" :margin="0" class="!mt-[16px] border-[var(--color-text-n8)]" />
|
<a-divider type="dashed" :margin="0" class="!mt-[16px] border-[var(--color-text-n8)]" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="preivewDetail.rest.length > 0" class="detail-item">
|
<div v-if="previewDetail.rest.length > 0" class="detail-item">
|
||||||
<div class="detail-item-title">
|
<div class="detail-item-title">
|
||||||
<div class="detail-item-title-text">Rest</div>
|
<div class="detail-item-title-text">Rest</div>
|
||||||
<a-radio-group v-model:model-value="restShowType" type="button" size="mini">
|
<a-radio-group v-model:model-value="restShowType" type="button" size="mini">
|
||||||
|
@ -103,7 +103,7 @@
|
||||||
<MsFormTable
|
<MsFormTable
|
||||||
v-show="restShowType === 'table'"
|
v-show="restShowType === 'table'"
|
||||||
:columns="queryRestColumns"
|
:columns="queryRestColumns"
|
||||||
:data="preivewDetail.rest || []"
|
:data="previewDetail.rest || []"
|
||||||
:selectable="false"
|
:selectable="false"
|
||||||
/>
|
/>
|
||||||
<MsCodeEditor
|
<MsCodeEditor
|
||||||
|
@ -134,10 +134,10 @@
|
||||||
<div class="detail-item">
|
<div class="detail-item">
|
||||||
<div class="detail-item-title">
|
<div class="detail-item-title">
|
||||||
<div class="detail-item-title-text">
|
<div class="detail-item-title-text">
|
||||||
{{ `${t('apiTestManagement.requestBody')}-${preivewDetail.body.bodyType}` }}
|
{{ `${t('apiTestManagement.requestBody')}-${previewDetail.body.bodyType}` }}
|
||||||
</div>
|
</div>
|
||||||
<!-- <a-radio-group
|
<!-- <a-radio-group
|
||||||
v-if="preivewDetail.body.bodyType !== RequestBodyFormat.NONE"
|
v-if="previewDetail.body.bodyType !== RequestBodyFormat.NONE"
|
||||||
v-model:model-value="bodyShowType"
|
v-model:model-value="bodyShowType"
|
||||||
type="button"
|
type="button"
|
||||||
size="mini"
|
size="mini"
|
||||||
|
@ -147,15 +147,16 @@
|
||||||
</a-radio-group> -->
|
</a-radio-group> -->
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="preivewDetail.body.bodyType === RequestBodyFormat.NONE"
|
v-if="previewDetail.body.bodyType === RequestBodyFormat.NONE"
|
||||||
class="flex h-[100px] items-center justify-center rounded-[var(--border-radius-small)] bg-[var(--color-text-n9)] text-[var(--color-text-4)]"
|
class="flex h-[100px] items-center justify-center rounded-[var(--border-radius-small)] bg-[var(--color-text-n9)] text-[var(--color-text-4)]"
|
||||||
>
|
>
|
||||||
{{ t('apiTestDebug.noneBody') }}
|
{{ t('apiTestDebug.noneBody') }}
|
||||||
</div>
|
</div>
|
||||||
<MsFormTable
|
<MsFormTable
|
||||||
v-else-if="
|
v-else-if="
|
||||||
preivewDetail.body.bodyType === RequestBodyFormat.FORM_DATA ||
|
previewDetail.body.bodyType === RequestBodyFormat.FORM_DATA ||
|
||||||
preivewDetail.body.bodyType === RequestBodyFormat.WWW_FORM
|
previewDetail.body.bodyType === RequestBodyFormat.WWW_FORM ||
|
||||||
|
previewDetail.body.bodyType === RequestBodyFormat.BINARY
|
||||||
"
|
"
|
||||||
:columns="bodyColumns"
|
:columns="bodyColumns"
|
||||||
:data="bodyTableData"
|
:data="bodyTableData"
|
||||||
|
@ -164,7 +165,7 @@
|
||||||
<MsCodeEditor
|
<MsCodeEditor
|
||||||
v-else-if="
|
v-else-if="
|
||||||
[RequestBodyFormat.JSON, RequestBodyFormat.RAW, RequestBodyFormat.XML].includes(
|
[RequestBodyFormat.JSON, RequestBodyFormat.RAW, RequestBodyFormat.XML].includes(
|
||||||
preivewDetail.body.bodyType
|
previewDetail.body.bodyType
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
:model-value="bodyCode"
|
:model-value="bodyCode"
|
||||||
|
@ -235,8 +236,8 @@
|
||||||
</a-collapse-item>
|
</a-collapse-item>
|
||||||
<a-collapse-item
|
<a-collapse-item
|
||||||
v-if="
|
v-if="
|
||||||
preivewDetail.responseDefinition &&
|
previewDetail.responseDefinition &&
|
||||||
preivewDetail.responseDefinition.length > 0 &&
|
previewDetail.responseDefinition.length > 0 &&
|
||||||
props.detail.protocol === 'HTTP'
|
props.detail.protocol === 'HTTP'
|
||||||
"
|
"
|
||||||
key="response"
|
key="response"
|
||||||
|
@ -254,7 +255,7 @@
|
||||||
</template>
|
</template>
|
||||||
<MsEditableTab
|
<MsEditableTab
|
||||||
v-model:active-tab="activeResponse"
|
v-model:active-tab="activeResponse"
|
||||||
:tabs="preivewDetail.responseDefinition?.map((e) => ({ ...e, closable: false })) || []"
|
:tabs="previewDetail.responseDefinition?.map((e) => ({ ...e, closable: false })) || []"
|
||||||
hide-more-action
|
hide-more-action
|
||||||
readonly
|
readonly
|
||||||
class="my-[8px]"
|
class="my-[8px]"
|
||||||
|
@ -272,8 +273,14 @@
|
||||||
{{ `${t('apiTestDebug.responseBody')}-${activeResponse?.body.bodyType}` }}
|
{{ `${t('apiTestDebug.responseBody')}-${activeResponse?.body.bodyType}` }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<MsFormTable
|
||||||
|
v-if="activeResponse?.body.bodyType === ResponseBodyFormat.BINARY"
|
||||||
|
:columns="responseBodyColumns"
|
||||||
|
:data="responseBodyTableData"
|
||||||
|
:selectable="false"
|
||||||
|
/>
|
||||||
<MsCodeEditor
|
<MsCodeEditor
|
||||||
v-if="activeResponse?.body.bodyType !== ResponseBodyFormat.BINARY"
|
v-else
|
||||||
:model-value="responseCode"
|
:model-value="responseCode"
|
||||||
class="flex-1"
|
class="flex-1"
|
||||||
theme="vs"
|
theme="vs"
|
||||||
|
@ -329,7 +336,6 @@
|
||||||
import { RequestBodyFormat, RequestParamsType, ResponseBodyFormat } from '@/enums/apiEnum';
|
import { RequestBodyFormat, RequestParamsType, ResponseBodyFormat } from '@/enums/apiEnum';
|
||||||
|
|
||||||
import type { RequestParam } from '@/views/api-test/components/requestComposition/index.vue';
|
import type { RequestParam } from '@/views/api-test/components/requestComposition/index.vue';
|
||||||
import { getValidRequestTableParams } from '@/views/api-test/components/utils';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
detail: RequestParam;
|
detail: RequestParam;
|
||||||
|
@ -339,7 +345,7 @@
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { copy, isSupported } = useClipboard();
|
const { copy, isSupported } = useClipboard();
|
||||||
|
|
||||||
const preivewDetail = ref<RequestParam>(cloneDeep(props.detail));
|
const previewDetail = ref<RequestParam>(props.detail);
|
||||||
const activeResponse = ref<TabItem & ResponseItem>();
|
const activeResponse = ref<TabItem & ResponseItem>();
|
||||||
|
|
||||||
const pluginLoading = ref(false);
|
const pluginLoading = ref(false);
|
||||||
|
@ -358,21 +364,21 @@
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const pluginTableData = computed(() => {
|
const pluginTableData = computed(() => {
|
||||||
if (pluginScriptMap.value[preivewDetail.value.protocol]) {
|
if (pluginScriptMap.value[previewDetail.value.protocol]) {
|
||||||
return (
|
return (
|
||||||
pluginScriptMap.value[preivewDetail.value.protocol].apiDefinitionFields?.map((e) => ({
|
pluginScriptMap.value[previewDetail.value.protocol].apiDefinitionFields?.map((e) => ({
|
||||||
key: e,
|
key: e,
|
||||||
value: preivewDetail.value[e],
|
value: previewDetail.value[e],
|
||||||
})) || []
|
})) || []
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
});
|
});
|
||||||
const pluginRawCode = computed(() => {
|
const pluginRawCode = computed(() => {
|
||||||
if (pluginScriptMap.value[preivewDetail.value.protocol]) {
|
if (pluginScriptMap.value[previewDetail.value.protocol]) {
|
||||||
return (
|
return (
|
||||||
pluginScriptMap.value[preivewDetail.value.protocol].apiDefinitionFields
|
pluginScriptMap.value[previewDetail.value.protocol].apiDefinitionFields
|
||||||
?.map((e) => `${e}:${preivewDetail.value[e]}`)
|
?.map((e) => `${e}:${previewDetail.value[e]}`)
|
||||||
.join('\n') || ''
|
.join('\n') || ''
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -404,28 +410,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
preivewDetail.value = cloneDeep(props.detail); // props.detail是嵌套的引用类型,防止不必要的修改来源影响props.detail的数据
|
previewDetail.value = cloneDeep(props.detail); // props.detail是嵌套的引用类型,防止不必要的修改来源影响props.detail的数据
|
||||||
const tableParam = getValidRequestTableParams(preivewDetail.value); // 在编辑props.detail时,参数表格会多出一行默认数据,需要去除
|
[activeResponse.value] = previewDetail.value.responseDefinition || [];
|
||||||
preivewDetail.value = {
|
if (previewDetail.value.protocol !== 'HTTP') {
|
||||||
...preivewDetail.value,
|
|
||||||
body: {
|
|
||||||
...preivewDetail.value.body,
|
|
||||||
formDataBody: {
|
|
||||||
formValues: tableParam.formDataBodyTableParams,
|
|
||||||
},
|
|
||||||
wwwFormBody: {
|
|
||||||
formValues: tableParam.wwwFormBodyTableParams,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
headers: tableParam.headers,
|
|
||||||
rest: tableParam.rest,
|
|
||||||
query: tableParam.query,
|
|
||||||
responseDefinition: tableParam.response,
|
|
||||||
};
|
|
||||||
[activeResponse.value] = tableParam.response;
|
|
||||||
if (preivewDetail.value.protocol !== 'HTTP') {
|
|
||||||
// 初始化插件脚本
|
// 初始化插件脚本
|
||||||
initPluginScript(preivewDetail.value.protocol);
|
initPluginScript(previewDetail.value.protocol);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -463,7 +452,7 @@
|
||||||
];
|
];
|
||||||
const headerShowType = ref('table');
|
const headerShowType = ref('table');
|
||||||
const headerRawCode = computed(() => {
|
const headerRawCode = computed(() => {
|
||||||
return preivewDetail.value.headers?.map((item) => `${item.key}:${item.value}`).join('\n');
|
return previewDetail.value.headers?.map((item) => `${item.key}:${item.value}`).join('\n');
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -523,17 +512,19 @@
|
||||||
];
|
];
|
||||||
const queryShowType = ref('table');
|
const queryShowType = ref('table');
|
||||||
const queryRawCode = computed(() => {
|
const queryRawCode = computed(() => {
|
||||||
return preivewDetail.value.query?.map((item) => `${item.key}:${item.value}`).join('\n');
|
return previewDetail.value.query?.map((item) => `${item.key}:${item.value}`).join('\n');
|
||||||
});
|
});
|
||||||
const restShowType = ref('table');
|
const restShowType = ref('table');
|
||||||
const restRawCode = computed(() => {
|
const restRawCode = computed(() => {
|
||||||
return preivewDetail.value.rest?.map((item) => `${item.key}:${item.value}`).join('\n');
|
return previewDetail.value.rest?.map((item) => `${item.key}:${item.value}`).join('\n');
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 请求体
|
* 请求体
|
||||||
*/
|
*/
|
||||||
const bodyColumns: FormTableColumn[] = [
|
const bodyColumns = computed<FormTableColumn[]>(() => {
|
||||||
|
if ([RequestBodyFormat.FORM_DATA, RequestBodyFormat.WWW_FORM].includes(previewDetail.value.body.bodyType)) {
|
||||||
|
return [
|
||||||
{
|
{
|
||||||
title: 'apiTestManagement.paramName',
|
title: 'apiTestManagement.paramName',
|
||||||
dataIndex: 'key',
|
dataIndex: 'key',
|
||||||
|
@ -587,41 +578,64 @@
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
title: 'common.desc',
|
||||||
|
dataIndex: 'description',
|
||||||
|
inputType: 'text',
|
||||||
|
showTooltip: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'apiTestManagement.paramVal',
|
||||||
|
dataIndex: 'value',
|
||||||
|
inputType: 'text',
|
||||||
|
showTooltip: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
// const bodyShowType = ref('table');
|
// const bodyShowType = ref('table');
|
||||||
const bodyTableData = computed(() => {
|
const bodyTableData = computed(() => {
|
||||||
switch (preivewDetail.value.body.bodyType) {
|
switch (previewDetail.value.body.bodyType) {
|
||||||
case RequestBodyFormat.FORM_DATA:
|
case RequestBodyFormat.FORM_DATA:
|
||||||
return (preivewDetail.value.body.formDataBody?.formValues || []).map((e) => ({
|
return (previewDetail.value.body.formDataBody?.formValues || []).map((e) => ({
|
||||||
...e,
|
...e,
|
||||||
value: e.paramType === RequestParamsType.FILE ? e.files?.map((file) => file.fileName).join('\n') : e.value,
|
value: e.paramType === RequestParamsType.FILE ? e.files?.map((file) => file.fileName).join('\n') : e.value,
|
||||||
}));
|
}));
|
||||||
case RequestBodyFormat.WWW_FORM:
|
case RequestBodyFormat.WWW_FORM:
|
||||||
return preivewDetail.value.body.wwwFormBody?.formValues || [];
|
return previewDetail.value.body.wwwFormBody?.formValues || [];
|
||||||
|
case RequestBodyFormat.BINARY:
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
description: previewDetail.value.body.binaryBody.description,
|
||||||
|
value: previewDetail.value.body.binaryBody.file?.fileName,
|
||||||
|
},
|
||||||
|
];
|
||||||
default:
|
default:
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const bodyCode = computed(() => {
|
const bodyCode = computed(() => {
|
||||||
switch (preivewDetail.value.body.bodyType) {
|
switch (previewDetail.value.body.bodyType) {
|
||||||
case RequestBodyFormat.FORM_DATA:
|
case RequestBodyFormat.FORM_DATA:
|
||||||
return preivewDetail.value.body.formDataBody?.formValues?.map((item) => `${item.key}:${item.value}`).join('\n');
|
return previewDetail.value.body.formDataBody?.formValues?.map((item) => `${item.key}:${item.value}`).join('\n');
|
||||||
case RequestBodyFormat.WWW_FORM:
|
case RequestBodyFormat.WWW_FORM:
|
||||||
return preivewDetail.value.body.wwwFormBody?.formValues?.map((item) => `${item.key}:${item.value}`).join('\n');
|
return previewDetail.value.body.wwwFormBody?.formValues?.map((item) => `${item.key}:${item.value}`).join('\n');
|
||||||
case RequestBodyFormat.RAW:
|
case RequestBodyFormat.RAW:
|
||||||
return preivewDetail.value.body.rawBody?.value;
|
return previewDetail.value.body.rawBody?.value;
|
||||||
case RequestBodyFormat.JSON:
|
case RequestBodyFormat.JSON:
|
||||||
return preivewDetail.value.body.jsonBody?.jsonValue;
|
return previewDetail.value.body.jsonBody?.jsonValue;
|
||||||
case RequestBodyFormat.XML:
|
case RequestBodyFormat.XML:
|
||||||
return preivewDetail.value.body.xmlBody?.value;
|
return previewDetail.value.body.xmlBody?.value;
|
||||||
default:
|
default:
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const bodyCodeLanguage = computed(() => {
|
const bodyCodeLanguage = computed(() => {
|
||||||
if (preivewDetail.value.body.bodyType === RequestBodyFormat.JSON) {
|
if (previewDetail.value.body.bodyType === RequestBodyFormat.JSON) {
|
||||||
return LanguageEnum.JSON;
|
return LanguageEnum.JSON;
|
||||||
}
|
}
|
||||||
if (preivewDetail.value.body.bodyType === RequestBodyFormat.XML) {
|
if (previewDetail.value.body.bodyType === RequestBodyFormat.XML) {
|
||||||
return LanguageEnum.XML;
|
return LanguageEnum.XML;
|
||||||
}
|
}
|
||||||
return LanguageEnum.PLAINTEXT;
|
return LanguageEnum.PLAINTEXT;
|
||||||
|
@ -663,6 +677,30 @@
|
||||||
inputType: 'text',
|
inputType: 'text',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
const responseBodyColumns: FormTableColumn[] = [
|
||||||
|
{
|
||||||
|
title: 'common.desc',
|
||||||
|
dataIndex: 'description',
|
||||||
|
inputType: 'text',
|
||||||
|
showTooltip: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'apiTestManagement.paramVal',
|
||||||
|
dataIndex: 'value',
|
||||||
|
inputType: 'text',
|
||||||
|
showTooltip: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const responseBodyTableData = computed(() => {
|
||||||
|
return activeResponse.value?.body.bodyType === ResponseBodyFormat.BINARY
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
description: activeResponse.value?.body.binaryBody.description,
|
||||||
|
value: activeResponse.value?.body.binaryBody.file?.fileName,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [];
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|
|
@ -123,7 +123,7 @@
|
||||||
{
|
{
|
||||||
key: 'path',
|
key: 'path',
|
||||||
locale: 'apiTestManagement.path',
|
locale: 'apiTestManagement.path',
|
||||||
value: previewDetail.value.path,
|
value: previewDetail.value.url || previewDetail.value.path,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'tags',
|
key: 'tags',
|
||||||
|
|
|
@ -1,61 +1,69 @@
|
||||||
<template>
|
<template>
|
||||||
<a-tabs v-model:active-key="activeTab" animation lazy-load class="ms-api-tab-nav">
|
<div class="flex gap-[8px] px-[16px] pt-[16px]">
|
||||||
<a-tab-pane key="api" title="API" class="ms-api-tab-pane">
|
<a-select v-model:model-value="currentTab" class="w-[80px]" :options="tabOptions" />
|
||||||
<api
|
<MsEditableTab
|
||||||
ref="apiRef"
|
v-model:active-tab="activeApiTab"
|
||||||
:module-tree="props.moduleTree"
|
v-model:tabs="apiTabs"
|
||||||
:active-module="props.activeModule"
|
class="flex-1 overflow-hidden"
|
||||||
:offspring-ids="props.offspringIds"
|
@add="newTab"
|
||||||
:protocol="protocol"
|
>
|
||||||
|
<template #label="{ tab }">
|
||||||
|
<apiMethodName
|
||||||
|
v-if="tab.id !== 'all'"
|
||||||
|
:method="tab.protocol === 'HTTP' ? tab.method : tab.protocol"
|
||||||
|
class="mr-[4px]"
|
||||||
/>
|
/>
|
||||||
</a-tab-pane>
|
<a-tooltip :content="tab.name || tab.label" :mouse-enter-delay="500">
|
||||||
<a-tab-pane key="case" title="CASE" class="ms-api-tab-pane">
|
<div class="one-line-text max-w-[144px]">
|
||||||
<apiCase :active-module="props.activeModule" :offspring-ids="props.offspringIds" :protocol="protocol" />
|
{{ tab.name || tab.label }}
|
||||||
</a-tab-pane>
|
</div>
|
||||||
<!-- <a-tab-pane key="mock" title="MOCK" class="ms-api-tab-pane">
|
</a-tooltip>
|
||||||
<mock-table
|
|
||||||
ref="mockRef"
|
|
||||||
:module-tree="props.moduleTree"
|
|
||||||
:active-module="props.activeModule"
|
|
||||||
:offspring-ids="props.offspringIds"
|
|
||||||
:protocol="protocol"
|
|
||||||
/>
|
|
||||||
</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]">
|
|
||||||
<template #icon>
|
|
||||||
<icon-location class="text-[var(--color-text-4)]" />
|
|
||||||
</template>
|
</template>
|
||||||
</a-button>
|
</MsEditableTab>
|
||||||
<MsSelect
|
<a-select
|
||||||
v-model:model-value="currentEnv"
|
v-model:model-value="currentEnv"
|
||||||
mode="static"
|
|
||||||
:options="envOptions"
|
:options="envOptions"
|
||||||
class="!w-[150px]"
|
class="!w-[200px] pl-0 pr-[8px]"
|
||||||
:search-keys="['label']"
|
|
||||||
:loading="envLoading"
|
:loading="envLoading"
|
||||||
allow-search
|
allow-search
|
||||||
@change="initEnvironment"
|
@change="initEnvironment"
|
||||||
/>
|
>
|
||||||
|
<template #prefix>
|
||||||
|
<div class="flex cursor-pointer p-[8px]" @click.stop="goEnv">
|
||||||
|
<icon-location class="text-[var(--color-text-4)]" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</a-tabs>
|
</a-select>
|
||||||
|
</div>
|
||||||
|
<api
|
||||||
|
v-if="currentTab === 'api'"
|
||||||
|
ref="apiRef"
|
||||||
|
v-model:active-api-tab="activeApiTab"
|
||||||
|
v-model:api-tabs="apiTabs"
|
||||||
|
:active-module="props.activeModule"
|
||||||
|
:offspring-ids="props.offspringIds"
|
||||||
|
:protocol="props.protocol"
|
||||||
|
:module-tree="props.moduleTree"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { SelectOptionData } from '@arco-design/web-vue';
|
import { SelectOptionData } from '@arco-design/web-vue';
|
||||||
|
|
||||||
import MsSelect from '@/components/business/ms-select';
|
import MsEditableTab from '@/components/pure/ms-editable-tab/index.vue';
|
||||||
import api from './api/index.vue';
|
import api from './api/index.vue';
|
||||||
import apiCase from './case/index.vue';
|
import apiMethodName from '@/views/api-test/components/apiMethodName.vue';
|
||||||
|
import { RequestParam } from '@/views/api-test/components/requestComposition/index.vue';
|
||||||
|
|
||||||
// import MockTable from '@/views/api-test/management/components/management/mock/mockTable.vue';
|
// import MockTable from '@/views/api-test/management/components/management/mock/mockTable.vue';
|
||||||
import { getEnvironment, getEnvList } from '@/api/modules/api-test/common';
|
import { getEnvironment, getEnvList } from '@/api/modules/api-test/common';
|
||||||
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
import router from '@/router';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
|
|
||||||
import { ModuleTreeNode } from '@/models/common';
|
import { ModuleTreeNode } from '@/models/common';
|
||||||
|
import { EnvConfig } from '@/models/projectManagement/environmental';
|
||||||
|
import { ProjectManagementRouteEnum } from '@/enums/routeEnum';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
activeModule: string;
|
activeModule: string;
|
||||||
|
@ -65,8 +73,16 @@
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const setActiveApi: ((params: RequestParam) => void) | undefined = inject('setActiveApi');
|
||||||
|
|
||||||
|
const currentTab = ref('api');
|
||||||
|
const tabOptions = [
|
||||||
|
{ label: 'API', value: 'api' },
|
||||||
|
{ label: 'CASE', value: 'case' },
|
||||||
|
];
|
||||||
|
|
||||||
const activeTab = ref('api');
|
|
||||||
const apiRef = ref<InstanceType<typeof api>>();
|
const apiRef = ref<InstanceType<typeof api>>();
|
||||||
|
|
||||||
function newTab(apiInfo?: ModuleTreeNode | string) {
|
function newTab(apiInfo?: ModuleTreeNode | string) {
|
||||||
|
@ -77,14 +93,33 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const apiTabs = ref<RequestParam[]>([
|
||||||
|
{
|
||||||
|
id: 'all',
|
||||||
|
label: t('apiTestManagement.allApi'),
|
||||||
|
closable: false,
|
||||||
|
} as RequestParam,
|
||||||
|
]);
|
||||||
|
const activeApiTab = ref<RequestParam>(apiTabs.value[0] as RequestParam);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => activeApiTab.value.id,
|
||||||
|
() => {
|
||||||
|
if (typeof setActiveApi === 'function') {
|
||||||
|
setActiveApi(activeApiTab.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const currentEnv = ref('');
|
const currentEnv = ref('');
|
||||||
const currentEnvConfig = ref({});
|
const currentEnvConfig = ref<EnvConfig>();
|
||||||
const envLoading = ref(false);
|
const envLoading = ref(false);
|
||||||
const envOptions = ref<SelectOptionData[]>([]);
|
const envOptions = ref<SelectOptionData[]>([]);
|
||||||
|
|
||||||
async function initEnvironment() {
|
async function initEnvironment() {
|
||||||
try {
|
try {
|
||||||
currentEnvConfig.value = await getEnvironment(currentEnv.value);
|
currentEnvConfig.value = await getEnvironment(currentEnv.value);
|
||||||
|
currentEnvConfig.value.id = currentEnv.value;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
@ -113,6 +148,12 @@
|
||||||
apiRef.value?.refreshTable();
|
apiRef.value?.refreshTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function goEnv() {
|
||||||
|
router.push({
|
||||||
|
name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_ENVIRONMENT_MANAGEMENT,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
initEnvList();
|
initEnvList();
|
||||||
});
|
});
|
||||||
|
@ -127,19 +168,10 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.ms-api-tab-nav {
|
.ms-input-group--prepend();
|
||||||
@apply h-full;
|
:deep(.arco-select-view-prefix) {
|
||||||
:deep(.arco-tabs-content) {
|
margin-right: 8px;
|
||||||
height: calc(100% - 51px);
|
padding-right: 0;
|
||||||
.arco-tabs-content-list {
|
border-right: 1px solid var(--color-text-input-border);
|
||||||
@apply h-full;
|
|
||||||
.arco-tabs-pane {
|
|
||||||
@apply h-full;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.arco-tabs-nav) {
|
|
||||||
border-bottom: 1px solid var(--color-text-n8);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -32,7 +32,8 @@
|
||||||
:content="isExpandApi ? t('apiTestManagement.collapseApi') : t('apiTestManagement.expandApi')"
|
:content="isExpandApi ? t('apiTestManagement.collapseApi') : t('apiTestManagement.expandApi')"
|
||||||
>
|
>
|
||||||
<MsButton type="icon" status="secondary" class="!mr-0 p-[4px]" @click="changeApiExpand">
|
<MsButton type="icon" status="secondary" class="!mr-0 p-[4px]" @click="changeApiExpand">
|
||||||
<MsIcon :type="isExpandApi ? 'icon-icon_collapse_interface' : 'icon-icon_expand_interface'" />
|
<icon-eye-invisible v-if="isExpandApi" />
|
||||||
|
<icon-eye v-else />
|
||||||
</MsButton>
|
</MsButton>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<a-tooltip :content="isExpandAll ? t('common.collapseAll') : t('common.expandAll')">
|
<a-tooltip :content="isExpandAll ? t('common.collapseAll') : t('common.expandAll')">
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<MsCard :min-width="1180" simple no-content-padding>
|
<MsCard simple no-content-padding>
|
||||||
<MsSplitBox :size="0.25" :max="0.5">
|
<MsSplitBox :size="0.25" :max="0.5">
|
||||||
<template #first>
|
<template #first>
|
||||||
<div class="p-[9px]">
|
<div class="p-[16px]">
|
||||||
<moduleTree
|
<moduleTree
|
||||||
ref="moduleTreeRef"
|
ref="moduleTreeRef"
|
||||||
:active-node-id="activeApi?.id"
|
:active-node-id="activeApi?.id"
|
||||||
|
|
|
@ -168,4 +168,6 @@ export default {
|
||||||
'case.batchDeleteCaseTip': 'Are you sure you want to delete {count} selected cases?',
|
'case.batchDeleteCaseTip': 'Are you sure you want to delete {count} selected cases?',
|
||||||
'case.deleteCaseTip':
|
'case.deleteCaseTip':
|
||||||
'Deleting an case will result in the execution failure of the test task that references the use case. Please be cautious!',
|
'Deleting an case will result in the execution failure of the test task that references the use case. Please be cautious!',
|
||||||
|
'apiTestManagement.click': 'Click',
|
||||||
|
'apiTestManagement.getResponse': 'Get response content',
|
||||||
};
|
};
|
||||||
|
|
|
@ -149,6 +149,8 @@ export default {
|
||||||
'apiTestManagement.getResponse': '获取响应内容',
|
'apiTestManagement.getResponse': '获取响应内容',
|
||||||
'case.allCase': '全部CASE',
|
'case.allCase': '全部CASE',
|
||||||
'case.caseName': '用例名称',
|
'case.caseName': '用例名称',
|
||||||
|
'case.caseNameRequired': '用例名称不能为空',
|
||||||
|
'case.caseNamePlaceholder': '请输入用例名称',
|
||||||
'case.caseLevel': '用例等级',
|
'case.caseLevel': '用例等级',
|
||||||
'case.caseEnvironment': '用例环境',
|
'case.caseEnvironment': '用例环境',
|
||||||
'case.tableColumnCreateUser': '创建人',
|
'case.tableColumnCreateUser': '创建人',
|
||||||
|
|
Loading…
Reference in New Issue