feat(接口场景): 场景步骤插件保存&查看&更新
This commit is contained in:
parent
886d566c21
commit
ff316eac16
|
@ -13,38 +13,38 @@ export default mergeConfig(
|
|||
},
|
||||
proxy: {
|
||||
'/ws': {
|
||||
target: 'http://172.16.200.18:8081/',
|
||||
target: 'http://192.168.8.200:8081/',
|
||||
changeOrigin: true,
|
||||
rewrite: (path: string) => path.replace(/^\/front\/ws/, ''),
|
||||
ws: true,
|
||||
},
|
||||
'/front': {
|
||||
target: 'http://172.16.200.18:8081/',
|
||||
target: 'http://192.168.8.200:8081/',
|
||||
changeOrigin: true,
|
||||
rewrite: (path: string) => path.replace(/^\/front/, ''),
|
||||
},
|
||||
'/file': {
|
||||
target: 'http://172.16.200.18:8081/',
|
||||
target: 'http://192.168.8.200:8081/',
|
||||
changeOrigin: true,
|
||||
rewrite: (path: string) => path.replace(/^\/front\/file/, ''),
|
||||
},
|
||||
'/attachment': {
|
||||
target: 'http://172.16.200.18:8081/',
|
||||
target: 'http://192.168.8.200:8081/',
|
||||
changeOrigin: true,
|
||||
rewrite: (path: string) => path.replace(/^\/front\/attachment/, ''),
|
||||
},
|
||||
'/bug/attachment': {
|
||||
target: 'http://172.16.200.18:8081/',
|
||||
target: 'http://192.168.8.200:8081/',
|
||||
changeOrigin: true,
|
||||
rewrite: (path: string) => path.replace(/^\/front\/bug\/attachment/, ''),
|
||||
},
|
||||
'/plugin/image': {
|
||||
target: 'http://172.16.200.18:8081/',
|
||||
target: 'http://192.168.8.200:8081/',
|
||||
changeOrigin: true,
|
||||
rewrite: (path: string) => path.replace(/^\/front\/plugin\/image/, ''),
|
||||
},
|
||||
'/base-display': {
|
||||
target: 'http://172.16.200.18:8081/',
|
||||
target: 'http://192.168.8.200:8081/',
|
||||
changeOrigin: true,
|
||||
rewrite: (path: string) => path.replace(/^\/front\/base-display/, ''),
|
||||
},
|
||||
|
|
|
@ -14,6 +14,7 @@ import {
|
|||
ExecuteHistoryUrl,
|
||||
GetModuleCountUrl,
|
||||
GetModuleTreeUrl,
|
||||
GetScenarioStepUrl,
|
||||
GetScenarioUrl,
|
||||
GetTrashModuleCountUrl,
|
||||
GetTrashModuleTreeUrl,
|
||||
|
@ -194,3 +195,8 @@ export function addScenario(params: Scenario) {
|
|||
export function getScenarioDetail(id: string) {
|
||||
return MSR.get<ScenarioDetail>({ url: GetScenarioUrl, params: id });
|
||||
}
|
||||
|
||||
// 获取场景步骤详情
|
||||
export function getScenarioStep(stepId: string | number) {
|
||||
return MSR.get({ url: GetScenarioStepUrl, params: stepId });
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ export const DeleteModuleUrl = '/api/scenario/module/delete'; // 删除模块
|
|||
export const ScenarioPageUrl = '/api/scenario/page'; // 接口场景列表
|
||||
export const AddScenarioUrl = '/api/scenario/add'; // 添加接口场景
|
||||
export const GetScenarioUrl = '/api/scenario/get'; // 获取接口场景详情
|
||||
export const GetScenarioStepUrl = '/api/scenario/step/get'; // 获取接口场景步骤详情
|
||||
export const UpdateScenarioUrl = '/api/scenario/update'; // 更新接口场景
|
||||
export const RecycleScenarioUrl = '/api/scenario/delete-to-gc'; // 删除接口场景
|
||||
export const BatchRecycleScenarioUrl = '/api/scenario/batch-operation/delete-gc'; // 批量删除接口场景
|
||||
|
|
|
@ -236,6 +236,7 @@
|
|||
const currentIndex = assertions.value.findIndex((item) => item.id === activeKey.value);
|
||||
const tmpArr = assertions.value;
|
||||
tmpArr[currentIndex] = cloneDeep(val);
|
||||
console.log('tmpArr', assertions.value, tmpArr);
|
||||
assertions.value = tmpArr;
|
||||
},
|
||||
});
|
||||
|
|
|
@ -313,7 +313,9 @@ export interface LoopStepDetail extends StepDetailsCommon {
|
|||
msCountController: CountController;
|
||||
whileController: WhileController;
|
||||
}
|
||||
export type ScenarioStepDetail = Partial<CustomApiStepDetail & ConditionStepDetail & LoopStepDetail>;
|
||||
export type ScenarioStepDetail = Partial<
|
||||
CustomApiStepDetail & ConditionStepDetail & LoopStepDetail & { protocol: string; method: RequestMethods }
|
||||
>;
|
||||
export interface ScenarioStepItem {
|
||||
id: string | number;
|
||||
sort: number;
|
||||
|
@ -324,7 +326,7 @@ export interface ScenarioStepItem {
|
|||
resourceNum?: string; // 详情或者引用的类型才有
|
||||
stepType: ScenarioStepType;
|
||||
refType: ScenarioStepRefType;
|
||||
config?: ScenarioStepDetail; // 对应场景里stepDetails里的详情信息,只有逻辑控制器需要
|
||||
config: ScenarioStepDetail; // 存储步骤列表需要展示的信息
|
||||
csvFileIds?: string[];
|
||||
projectId?: string;
|
||||
versionId?: string;
|
||||
|
|
|
@ -224,7 +224,7 @@ export function mapTree<T>(
|
|||
return _tree
|
||||
.map((node: TreeNode<T>, i: number) => {
|
||||
const fullPath = node.path ? `${_parentPath}/${node.path}`.replace(/\/+/g, '/') : '';
|
||||
node.sort = i + 1; // order从 1 开始
|
||||
node.sort = i + 1; // sort 从 1 开始
|
||||
node.parent = _parent || undefined; // 没有父节点说明是树的第一层
|
||||
const newNode = typeof customNodeFn === 'function' ? customNodeFn(node, fullPath) : node;
|
||||
if (newNode) {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
:width="960"
|
||||
no-content-padding
|
||||
:show-continue="true"
|
||||
:footer="!!requestVModel.isNew"
|
||||
:footer="requestVModel.isNew === true"
|
||||
@confirm="handleSave"
|
||||
@continue="handleContinue"
|
||||
@close="handleClose"
|
||||
|
@ -18,11 +18,21 @@
|
|||
/>
|
||||
{{ title }}
|
||||
</div>
|
||||
<div v-if="requestVModel.isNew" class="ml-auto flex items-center gap-[16px]">
|
||||
<div v-show="requestVModel.useEnv === 'false'" class="text-[14px] font-normal text-[var(--color-text-4)]">
|
||||
<div
|
||||
v-if="!props.step || props.step?.stepType === ScenarioStepType.CUSTOM_REQUEST"
|
||||
class="ml-auto flex items-center gap-[16px]"
|
||||
>
|
||||
<div
|
||||
v-show="!requestVModel.customizeRequestEnvEnable"
|
||||
class="text-[14px] font-normal text-[var(--color-text-4)]"
|
||||
>
|
||||
{{ t('apiScenario.env', { name: props.envDetailItem?.name }) }}
|
||||
</div>
|
||||
<a-select v-model:model-value="requestVModel.useEnv" class="w-[150px]" @change="handleUseEnvChange">
|
||||
<a-select
|
||||
v-model:model-value="requestVModel.customizeRequestEnvEnable"
|
||||
class="w-[150px]"
|
||||
@change="handleUseEnvChange"
|
||||
>
|
||||
<template #prefix>
|
||||
<div> {{ t('project.environmental.env') }} </div>
|
||||
</template>
|
||||
|
@ -348,7 +358,7 @@
|
|||
|
||||
export type RequestParam = ExecuteApiRequestFullParams & {
|
||||
response?: RequestTaskResult;
|
||||
useEnv: string;
|
||||
customizeRequestEnvEnable: boolean;
|
||||
request?: ExecuteApiRequestFullParams; // 请求参数集合
|
||||
} & RequestCustomAttr &
|
||||
TabItem;
|
||||
|
@ -389,7 +399,7 @@
|
|||
const defaultDebugParams: RequestParam = {
|
||||
type: 'api',
|
||||
id: '',
|
||||
useEnv: 'false',
|
||||
customizeRequestEnvEnable: false,
|
||||
protocol: 'HTTP',
|
||||
url: '',
|
||||
activeTab: RequestComposition.HEADER,
|
||||
|
@ -614,14 +624,22 @@
|
|||
* 控制插件表单字段显示
|
||||
*/
|
||||
function controlPluginFormFields() {
|
||||
const allFields = fApi.value?.fields();
|
||||
const currentFormFields = fApi.value?.fields();
|
||||
let fields: string[] = [];
|
||||
if (requestVModel.value.useEnv === 'true') {
|
||||
if (requestVModel.value.customizeRequestEnvEnable) {
|
||||
fields = pluginScriptMap.value[requestVModel.value.protocol].apiDefinitionFields || [];
|
||||
} else {
|
||||
fields = pluginScriptMap.value[requestVModel.value.protocol].apiDebugFields || [];
|
||||
}
|
||||
fApi.value?.hidden(true, allFields?.filter((e) => !fields.includes(e)) || []);
|
||||
// 确保fields展示完整
|
||||
if (currentFormFields && currentFormFields.length < fields.length) {
|
||||
fApi.value?.hidden(false, fields);
|
||||
fApi.value?.hidden(true, currentFormFields?.filter((e) => !fields.includes(e)) || []);
|
||||
fApi.value?.refresh();
|
||||
} else {
|
||||
// 隐藏多余的字段
|
||||
fApi.value?.hidden(true, currentFormFields?.filter((e) => !fields.includes(e)) || []);
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
|
@ -640,6 +658,7 @@
|
|||
form[key] = formData[key];
|
||||
});
|
||||
fApi.value?.setValue(cloneDeep(form));
|
||||
fApi.value?.clearValidateState();
|
||||
setTimeout(() => {
|
||||
// 初始化时赋值会触发表单数据变更,300ms 是为了与 handlePluginFormChange的防抖时间保持一致
|
||||
isInitPluginForm.value = true;
|
||||
|
@ -744,17 +763,6 @@
|
|||
const splitContainerRef = ref<HTMLElement>();
|
||||
const secondBoxHeight = ref(0);
|
||||
|
||||
watch(
|
||||
() => showResponse.value,
|
||||
(val) => {
|
||||
if (val) {
|
||||
splitBoxSize.value = 0.6;
|
||||
} else {
|
||||
splitBoxSize.value = 1;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => splitBoxSize.value,
|
||||
debounce((val) => {
|
||||
|
@ -785,9 +793,7 @@
|
|||
if (val) {
|
||||
verticalSplitBoxRef.value?.expand(0.6);
|
||||
} else {
|
||||
verticalSplitBoxRef.value?.collapse(
|
||||
splitContainerRef.value ? `${splitContainerRef.value.clientHeight - 42}px` : 0
|
||||
);
|
||||
verticalSplitBoxRef.value?.collapse(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -921,6 +927,7 @@
|
|||
protocol: requestVModel.value.protocol,
|
||||
method: isHttpProtocol.value ? requestVModel.value.method : requestVModel.value.protocol,
|
||||
name: requestVModel.value.name,
|
||||
customizeRequestEnvEnable: requestVModel.value.customizeRequestEnvEnable,
|
||||
children: [
|
||||
{
|
||||
polymorphicName: 'MsCommonElement', // 协议多态名称,写死MsCommonElement
|
||||
|
@ -1042,9 +1049,15 @@
|
|||
() => visible.value,
|
||||
async (val) => {
|
||||
if (val) {
|
||||
if (protocolOptions.value.length === 0) {
|
||||
await initProtocolList();
|
||||
}
|
||||
if (props.request) {
|
||||
console.log('props.request', props.request);
|
||||
requestVModel.value = cloneDeep(props.request);
|
||||
requestVModel.value = cloneDeep({
|
||||
...defaultDebugParams,
|
||||
...props.request,
|
||||
isNew: false,
|
||||
});
|
||||
if (
|
||||
_stepType.value.isQuoteApi ||
|
||||
isCopyApiNeedInit.value
|
||||
|
@ -1082,16 +1095,13 @@
|
|||
// });
|
||||
// }
|
||||
// }
|
||||
handleActiveDebugProtocolChange(requestVModel.value.protocol);
|
||||
} else {
|
||||
requestVModel.value = cloneDeep({
|
||||
...defaultDebugParams,
|
||||
id: getGenerateId(),
|
||||
});
|
||||
}
|
||||
await initProtocolList();
|
||||
if (props.request) {
|
||||
handleActiveDebugProtocolChange(requestVModel.value.protocol);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1100,6 +1110,19 @@
|
|||
);
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.hidden-second {
|
||||
:deep(.arco-split-trigger, .arco-split-pane-second) {
|
||||
@apply hidden;
|
||||
}
|
||||
}
|
||||
.show-second {
|
||||
:deep(.arco-split-trigger, .arco-split-pane-second) {
|
||||
@apply block;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.exec-btn {
|
||||
margin-right: 12px;
|
||||
|
@ -1126,14 +1149,4 @@
|
|||
:deep(.arco-tabs-tab) {
|
||||
@apply leading-none;
|
||||
}
|
||||
.hidden-second {
|
||||
:deep(.arco-split-trigger) {
|
||||
@apply hidden;
|
||||
}
|
||||
}
|
||||
.show-second {
|
||||
:deep(.arco-split-trigger) {
|
||||
@apply block;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
@close="handleClose"
|
||||
>
|
||||
<template #title>
|
||||
<stepType v-if="activeStep?.type" :type="activeStep?.type" class="mr-[4px]" />
|
||||
<stepType v-if="props.activeStep?.stepType" :step="props.activeStep" class="mr-[4px]" />
|
||||
<a-input
|
||||
v-if="activeStep?.name"
|
||||
v-show="isShowEditStepNameInput"
|
||||
|
@ -84,8 +84,7 @@
|
|||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||
import { ScenarioStepItem } from '../step/stepTree.vue';
|
||||
import stepType from './stepType.vue';
|
||||
import stepType from './stepType/stepType.vue';
|
||||
import executeButton from '@/views/api-test/components/executeButton.vue';
|
||||
import requestAndResponse from '@/views/api-test/components/requestAndResponse.vue';
|
||||
import { RequestParam } from '@/views/api-test/components/requestComposition/index.vue';
|
||||
|
@ -103,12 +102,14 @@
|
|||
import { getLocalConfig } from '@/api/modules/user/index';
|
||||
import { characterLimit, getGenerateId } from '@/utils';
|
||||
|
||||
import { ScenarioStepItem } from '@/models/apiTest/scenario';
|
||||
import { LocalConfig } from '@/models/user';
|
||||
import {
|
||||
RequestAuthType,
|
||||
RequestComposition,
|
||||
RequestMethods,
|
||||
ResponseComposition,
|
||||
ScenarioStepRefType,
|
||||
ScenarioStepType,
|
||||
} from '@/enums/apiEnum';
|
||||
|
||||
|
@ -202,6 +203,20 @@
|
|||
};
|
||||
|
||||
const requestVModel = ref<RequestParam>(props.request || cloneDeep(defaultCaseParams));
|
||||
const isCopyCase = computed(
|
||||
() =>
|
||||
props.activeStep?.stepType === ScenarioStepType.API_CASE && props.activeStep?.refType === ScenarioStepRefType.COPY
|
||||
);
|
||||
const isCopyNeedInit = computed(() => isCopyCase.value && props.request?.request === null);
|
||||
const isQuote = computed(
|
||||
() =>
|
||||
props.activeStep?.stepType === ScenarioStepType.API_CASE && props.activeStep?.refType === ScenarioStepRefType.REF
|
||||
);
|
||||
|
||||
const stepName = ref(props.activeStep?.name);
|
||||
watchEffect(() => {
|
||||
stepName.value = props.activeStep?.name;
|
||||
});
|
||||
|
||||
const executeRef = ref<InstanceType<typeof executeButton>>();
|
||||
const requestAndResponseRef = ref<InstanceType<typeof requestAndResponse>>();
|
||||
|
|
|
@ -7,45 +7,55 @@ import {
|
|||
WhileConditionType,
|
||||
} from '@/enums/apiEnum';
|
||||
|
||||
// 循环控制器
|
||||
export const defaultLoopController = {
|
||||
loopType: ScenarioStepLoopTypeEnum.LOOP_COUNT,
|
||||
forEachController: {
|
||||
loopTime: 0, // 循环间隔时间
|
||||
value: '', // 变量值
|
||||
variable: '', // 变量名
|
||||
},
|
||||
msCountController: {
|
||||
loops: 0, // 循环次数
|
||||
},
|
||||
whileController: {
|
||||
conditionType: WhileConditionType.CONDITION, // 条件类型
|
||||
timeout: 0, // 超时时间
|
||||
msWhileScript: {
|
||||
scriptValue: '', // 脚本值
|
||||
}, // 脚本
|
||||
msWhileVariable: {
|
||||
condition: RequestAssertionCondition.EQUALS, // 条件操作符
|
||||
value: '', // 变量值
|
||||
variable: '', // 变量名
|
||||
}, // 变量
|
||||
},
|
||||
};
|
||||
|
||||
// 自定义请求
|
||||
export const defaultCustomApiConfig = {
|
||||
customizeRequest: false, // 是否自定义请求
|
||||
customizeRequestEnvEnable: false, // 是否启用环境
|
||||
};
|
||||
|
||||
// 条件控制器
|
||||
export const defaultConditionController = {
|
||||
value: '', // 变量值
|
||||
variable: '', // 变量名
|
||||
condition: RequestAssertionCondition.EQUALS, // 条件操作符
|
||||
};
|
||||
|
||||
export const defaultStepItemCommon = {
|
||||
checked: false,
|
||||
expanded: false,
|
||||
enable: true,
|
||||
children: [],
|
||||
copyFromStepId: '', // 如果步骤是复制的,这个字段是复制的步骤id
|
||||
isNew: true, // 是否新建的步骤
|
||||
config: {
|
||||
id: '',
|
||||
copyFromStepId: '', // 如果步骤是复制的,这个字段是复制的步骤id
|
||||
name: '',
|
||||
enable: true,
|
||||
polymorphicName: '', // 多态名称,用于后台区分使用的是哪个组件
|
||||
// 自定义请求
|
||||
customizeRequest: false, // 是否自定义请求
|
||||
customizeRequestEnvEnable: false, // 是否启用环境
|
||||
// 条件控制器
|
||||
value: '', // 变量值
|
||||
variable: '', // 变量名
|
||||
condition: RequestAssertionCondition.EQUALS, // 条件操作符
|
||||
loopType: ScenarioStepLoopTypeEnum.LOOP_COUNT,
|
||||
forEachController: {
|
||||
loopTime: 0, // 循环间隔时间
|
||||
value: '', // 变量值
|
||||
variable: '', // 变量名
|
||||
},
|
||||
msCountController: {
|
||||
loops: 0, // 循环次数
|
||||
},
|
||||
whileController: {
|
||||
conditionType: WhileConditionType.CONDITION, // 条件类型
|
||||
timeout: 0, // 超时时间
|
||||
msWhileScript: {
|
||||
scriptValue: '', // 脚本值
|
||||
}, // 脚本
|
||||
msWhileVariable: {
|
||||
condition: RequestAssertionCondition.EQUALS, // 条件操作符
|
||||
value: '', // 变量值
|
||||
variable: '', // 变量名
|
||||
}, // 变量
|
||||
},
|
||||
waitTime: 0, // 等待时间
|
||||
},
|
||||
createActionsVisible: false,
|
||||
|
|
|
@ -54,7 +54,11 @@
|
|||
import { ScenarioAddStepActionType, ScenarioStepRefType, ScenarioStepType } from '@/enums/apiEnum';
|
||||
|
||||
import useCreateActions from './useCreateActions';
|
||||
import { defaultStepItemCommon } from '@/views/api-test/scenario/components/config';
|
||||
import {
|
||||
defaultConditionController,
|
||||
defaultLoopController,
|
||||
defaultStepItemCommon,
|
||||
} from '@/views/api-test/scenario/components/config';
|
||||
import { DropdownPosition } from '@arco-design/web-vue/es/dropdown/interface';
|
||||
|
||||
const props = defineProps<{
|
||||
|
@ -90,7 +94,7 @@
|
|||
default: undefined,
|
||||
});
|
||||
|
||||
const { handleCreateStep } = useCreateActions();
|
||||
const { handleCreateStep, buildInsertStepInfos } = useCreateActions();
|
||||
|
||||
/**
|
||||
* 处理创建步骤操作
|
||||
|
@ -112,15 +116,15 @@
|
|||
selectedKeys.value
|
||||
);
|
||||
} else {
|
||||
steps.value.push({
|
||||
...cloneDeep(defaultStepItemCommon),
|
||||
id: getGenerateId(),
|
||||
sort: steps.value.length + 1,
|
||||
stepType: ScenarioStepType.LOOP_CONTROLLER,
|
||||
refType: ScenarioStepRefType.DIRECT,
|
||||
name: t('apiScenario.loopControl'),
|
||||
projectId: appStore.currentProjectId,
|
||||
});
|
||||
steps.value.push(
|
||||
buildInsertStepInfos(
|
||||
[cloneDeep(defaultStepItemCommon)],
|
||||
ScenarioStepType.LOOP_CONTROLLER,
|
||||
ScenarioStepRefType.DIRECT,
|
||||
steps.value.length + 1,
|
||||
appStore.currentProjectId
|
||||
)[0]
|
||||
);
|
||||
}
|
||||
break;
|
||||
case ScenarioAddStepActionType.CONDITION_CONTROL:
|
||||
|
@ -137,15 +141,15 @@
|
|||
selectedKeys.value
|
||||
);
|
||||
} else {
|
||||
steps.value.push({
|
||||
...cloneDeep(defaultStepItemCommon),
|
||||
id: getGenerateId(),
|
||||
sort: steps.value.length + 1,
|
||||
stepType: ScenarioStepType.IF_CONTROLLER,
|
||||
refType: ScenarioStepRefType.DIRECT,
|
||||
name: t('apiScenario.conditionControl'),
|
||||
projectId: appStore.currentProjectId,
|
||||
});
|
||||
steps.value.push(
|
||||
buildInsertStepInfos(
|
||||
[cloneDeep(defaultStepItemCommon)],
|
||||
ScenarioStepType.IF_CONTROLLER,
|
||||
ScenarioStepRefType.DIRECT,
|
||||
steps.value.length + 1,
|
||||
appStore.currentProjectId
|
||||
)[0]
|
||||
);
|
||||
}
|
||||
break;
|
||||
case ScenarioAddStepActionType.ONLY_ONCE_CONTROL:
|
||||
|
@ -162,15 +166,15 @@
|
|||
selectedKeys.value
|
||||
);
|
||||
} else {
|
||||
steps.value.push({
|
||||
...cloneDeep(defaultStepItemCommon),
|
||||
id: getGenerateId(),
|
||||
sort: steps.value.length + 1,
|
||||
stepType: ScenarioStepType.ONCE_ONLY_CONTROLLER,
|
||||
refType: ScenarioStepRefType.DIRECT,
|
||||
name: t('apiScenario.onlyOnceControl'),
|
||||
projectId: appStore.currentProjectId,
|
||||
});
|
||||
steps.value.push(
|
||||
buildInsertStepInfos(
|
||||
[cloneDeep(defaultStepItemCommon)],
|
||||
ScenarioStepType.ONCE_ONLY_CONTROLLER,
|
||||
ScenarioStepRefType.DIRECT,
|
||||
steps.value.length + 1,
|
||||
appStore.currentProjectId
|
||||
)[0]
|
||||
);
|
||||
}
|
||||
break;
|
||||
case ScenarioAddStepActionType.WAIT_TIME:
|
||||
|
@ -187,15 +191,15 @@
|
|||
selectedKeys.value
|
||||
);
|
||||
} else {
|
||||
steps.value.push({
|
||||
...cloneDeep(defaultStepItemCommon),
|
||||
id: getGenerateId(),
|
||||
sort: steps.value.length + 1,
|
||||
stepType: ScenarioStepType.CONSTANT_TIMER,
|
||||
refType: ScenarioStepRefType.DIRECT,
|
||||
name: t('apiScenario.waitTime'),
|
||||
projectId: appStore.currentProjectId,
|
||||
});
|
||||
steps.value.push(
|
||||
buildInsertStepInfos(
|
||||
[cloneDeep(defaultStepItemCommon)],
|
||||
ScenarioStepType.CONSTANT_TIMER,
|
||||
ScenarioStepRefType.DIRECT,
|
||||
steps.value.length + 1,
|
||||
appStore.currentProjectId
|
||||
)[0]
|
||||
);
|
||||
}
|
||||
break;
|
||||
case ScenarioAddStepActionType.IMPORT_SYSTEM_API:
|
||||
|
|
|
@ -6,7 +6,7 @@ import { getGenerateId, insertNodes, TreeNode } from '@/utils';
|
|||
import { CreateStepAction, ScenarioStepItem } from '@/models/apiTest/scenario';
|
||||
import { ScenarioStepRefType, ScenarioStepType } from '@/enums/apiEnum';
|
||||
|
||||
import { defaultStepItemCommon } from '../../config';
|
||||
import { defaultConditionController, defaultLoopController, defaultStepItemCommon } from '../../config';
|
||||
|
||||
export default function useCreateActions() {
|
||||
const { t } = useI18n();
|
||||
|
@ -48,7 +48,6 @@ export default function useCreateActions() {
|
|||
id: getGenerateId(),
|
||||
...defaultStepInfo,
|
||||
};
|
||||
console.log('newStep', newStep);
|
||||
insertNodes<ScenarioStepItem>(
|
||||
step.parent?.children || steps,
|
||||
step.id,
|
||||
|
@ -70,7 +69,6 @@ export default function useCreateActions() {
|
|||
stepType: ScenarioStepType,
|
||||
refType: ScenarioStepRefType,
|
||||
startOrder: number,
|
||||
stepDetails: Record<string, any>,
|
||||
projectId: string
|
||||
): ScenarioStepItem[] {
|
||||
let name: string;
|
||||
|
@ -98,15 +96,40 @@ export default function useCreateActions() {
|
|||
}
|
||||
return newSteps.map((item, index) => {
|
||||
const id = getGenerateId();
|
||||
stepDetails[id] = item; // 导入系统请求的引用接口和 case 的时候需要先存储一下引用的接口/用例信息
|
||||
let resourceField = {};
|
||||
let config = {};
|
||||
if (stepType === ScenarioStepType.LOOP_CONTROLLER) {
|
||||
config = cloneDeep(defaultLoopController);
|
||||
} else if (stepType === ScenarioStepType.IF_CONTROLLER) {
|
||||
config = cloneDeep(defaultConditionController);
|
||||
}
|
||||
if (item.id) {
|
||||
// 引用复制接口、用例、场景时的源资源信息
|
||||
resourceField = {
|
||||
resourceId: item.id,
|
||||
resourceNum: item.num,
|
||||
resourceName: item.name,
|
||||
};
|
||||
}
|
||||
if (item.protocol) {
|
||||
// 自定义请求、api、case 添加协议和方法
|
||||
config = {
|
||||
...config,
|
||||
protocol: item.protocol,
|
||||
method: item.method,
|
||||
};
|
||||
}
|
||||
return {
|
||||
...cloneDeep(defaultStepItemCommon),
|
||||
...item,
|
||||
id,
|
||||
config: {
|
||||
...defaultStepItemCommon.config,
|
||||
...config,
|
||||
},
|
||||
stepType,
|
||||
refType,
|
||||
resourceId: item.id,
|
||||
resourceName: item.name,
|
||||
...resourceField,
|
||||
name: name || item.name,
|
||||
sort: startOrder + index,
|
||||
projectId,
|
||||
|
|
|
@ -44,10 +44,11 @@
|
|||
|
||||
const props = defineProps<{
|
||||
data: ConditionStepDetail;
|
||||
stepId: string | number;
|
||||
}>();
|
||||
const emit = defineEmits<{
|
||||
(e: 'change', innerData: ConditionStepDetail): void;
|
||||
(e: 'quickInput', dataKey: keyof ConditionStepDetail): void;
|
||||
(e: 'quickInput', dataKey: string): void;
|
||||
}>();
|
||||
|
||||
const { t } = useI18n();
|
||||
|
@ -70,8 +71,8 @@
|
|||
() => dbClick?.value.timeStamp,
|
||||
() => {
|
||||
// @ts-ignore
|
||||
if ((dbClick?.value.e?.target as Element).parentNode?.id.includes(innerData.value.id)) {
|
||||
emit('quickInput', 'value');
|
||||
if ((dbClick?.value.e?.target as Element).parentNode?.id.includes(props.stepId)) {
|
||||
emit('quickInput', 'conditionValue');
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -225,8 +225,8 @@
|
|||
emit(
|
||||
'quickInput',
|
||||
innerData.value.whileController.conditionType === WhileConditionType.CONDITION
|
||||
? 'whileController.msWhileVariable.value'
|
||||
: 'whileController.msWhileScript.scriptValue'
|
||||
? 'msWhileVariableValue'
|
||||
: 'msWhileVariableScriptValue'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
<template>
|
||||
<div class="flex items-center gap-[4px]">
|
||||
<a-popover position="bl" content-class="detail-popover" arrow-class="hidden">
|
||||
<!-- <a-popover position="bl" content-class="detail-popover" arrow-class="hidden">
|
||||
<MsIcon type="icon-icon-draft" class="text-[var(--color-text-4)] hover:text-[rgb(var(--primary-5))]" />
|
||||
<template #content>
|
||||
<div class="flex flex-col gap-[16px]">
|
||||
<div>
|
||||
<div class="mb-[2px] text-[var(--color-text-4)]">{{ t('apiScenario.belongProject') }}</div>
|
||||
<div class="text-[14px] text-[var(--color-text-1)]">
|
||||
<!-- {{ props.data.belongProjectName }} -->
|
||||
{{ props.data.belongProjectName }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
|
@ -18,7 +18,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-popover>
|
||||
</a-popover> -->
|
||||
<MsTag
|
||||
v-if="props.data.projectId !== appStore.currentProjectId"
|
||||
theme="outline"
|
||||
|
@ -35,17 +35,17 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
// import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useOpenNewPage from '@/hooks/useOpenNewPage';
|
||||
// import useOpenNewPage from '@/hooks/useOpenNewPage';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
|
||||
import { ScenarioStepItem } from '@/models/apiTest/scenario';
|
||||
import { ApiTestRouteEnum } from '@/enums/routeEnum';
|
||||
// import { ApiTestRouteEnum } from '@/enums/routeEnum';
|
||||
|
||||
import getStepType from '@/views/api-test/scenario/components/common/stepType/utils';
|
||||
// import getStepType from '@/views/api-test/scenario/components/common/stepType/utils';
|
||||
|
||||
const props = defineProps<{
|
||||
data: ScenarioStepItem;
|
||||
|
@ -53,27 +53,27 @@
|
|||
|
||||
const appStore = useAppStore();
|
||||
const { t } = useI18n();
|
||||
const { openNewPage } = useOpenNewPage();
|
||||
// const { openNewPage } = useOpenNewPage();
|
||||
|
||||
function goDetail() {
|
||||
const _stepType = getStepType(props.data);
|
||||
switch (true) {
|
||||
case _stepType.isCopyApi:
|
||||
case _stepType.isQuoteApi:
|
||||
openNewPage(ApiTestRouteEnum.API_TEST_MANAGEMENT, { dId: props.data.id, pId: props.data.projectId });
|
||||
break;
|
||||
case _stepType.isCopyScenario:
|
||||
case _stepType.isQuoteScenario:
|
||||
openNewPage(ApiTestRouteEnum.API_TEST_SCENARIO, { sId: props.data.id, pId: props.data.projectId });
|
||||
break;
|
||||
case _stepType.isQuoteCase:
|
||||
case _stepType.isCopyCase:
|
||||
openNewPage(ApiTestRouteEnum.API_TEST_MANAGEMENT, { cId: props.data.id, pId: props.data.projectId });
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
// function goDetail() {
|
||||
// const _stepType = getStepType(props.data);
|
||||
// switch (true) {
|
||||
// case _stepType.isCopyApi:
|
||||
// case _stepType.isQuoteApi:
|
||||
// openNewPage(ApiTestRouteEnum.API_TEST_MANAGEMENT, { dId: props.data.id, pId: props.data.projectId });
|
||||
// break;
|
||||
// case _stepType.isCopyScenario:
|
||||
// case _stepType.isQuoteScenario:
|
||||
// openNewPage(ApiTestRouteEnum.API_TEST_SCENARIO, { sId: props.data.id, pId: props.data.projectId });
|
||||
// break;
|
||||
// case _stepType.isQuoteCase:
|
||||
// case _stepType.isCopyCase:
|
||||
// openNewPage(ApiTestRouteEnum.API_TEST_MANAGEMENT, { cId: props.data.id, pId: props.data.projectId });
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
|
@ -87,7 +87,7 @@
|
|||
/>
|
||||
<!-- API、CASE、场景步骤名称 -->
|
||||
<template v-if="checkStepIsApi(step)">
|
||||
<apiMethodName v-if="checkStepShowMethod(step)" :method="step.method" />
|
||||
<apiMethodName v-if="checkStepShowMethod(step)" :method="step.config.method" />
|
||||
<div
|
||||
v-if="step.id === showStepNameEditInputStepId"
|
||||
class="name-warp absolute left-0 top-[-2px] z-10 w-[calc(100%-24px)]"
|
||||
|
@ -268,6 +268,7 @@
|
|||
import apiMethodName from '@/views/api-test/components/apiMethodName.vue';
|
||||
import { RequestParam as CaseRequestParam } from '@/views/api-test/components/requestComposition/index.vue';
|
||||
|
||||
import { getScenarioStep } from '@/api/modules/api-test/scenario';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import {
|
||||
|
@ -527,11 +528,9 @@
|
|||
function handleStepContentChange($event, step: ScenarioStepItem) {
|
||||
const realStep = findNodeByKey<ScenarioStepItem>(steps.value, step.id, 'id');
|
||||
if (realStep) {
|
||||
// Object.keys($event).forEach((key) => {
|
||||
// realStep.config[key] = $event[key];
|
||||
// });
|
||||
realStep.config = $event;
|
||||
console.log('handleStepContentChange', $event);
|
||||
Object.keys($event).forEach((key) => {
|
||||
realStep.config[key] = $event[key];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -566,12 +565,29 @@
|
|||
return undefined;
|
||||
});
|
||||
|
||||
async function getStepDetail(step: ScenarioStepItem) {
|
||||
try {
|
||||
appStore.showLoading();
|
||||
const res = await getScenarioStep(step.id);
|
||||
stepDetails.value[step.id] = {
|
||||
...res,
|
||||
protocol: step.config.protocol,
|
||||
method: step.config.method,
|
||||
};
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
} finally {
|
||||
appStore.hideLoading();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理步骤选中事件
|
||||
* @param _selectedKeys 选中的 key集合
|
||||
* @param step 点击的步骤节点
|
||||
*/
|
||||
function handleStepSelect(_selectedKeys: Array<string | number>, step: ScenarioStepItem) {
|
||||
async function handleStepSelect(_selectedKeys: Array<string | number>, step: ScenarioStepItem) {
|
||||
const _stepType = getStepType(step);
|
||||
const offspringIds: string[] = [];
|
||||
mapTree(step.children || [], (e) => {
|
||||
|
@ -580,9 +596,14 @@
|
|||
});
|
||||
selectedKeys.value = [step.id, ...offspringIds];
|
||||
if (_stepType.isCopyApi || _stepType.isQuoteApi || step.stepType === ScenarioStepType.CUSTOM_REQUEST) {
|
||||
// 复制 api、引用 api、自定义 api打开抽屉
|
||||
activeStep.value = step;
|
||||
if (stepDetails.value[step.id] === undefined) {
|
||||
// 详情映射中没有加载过该 api 详情,说明是初次查看详情,引用的 api 不需要在这里加载详情
|
||||
await getStepDetail(step);
|
||||
}
|
||||
customApiDrawerVisible.value = true;
|
||||
} else if ([ScenarioStepType.QUOTE_CASE, ScenarioStepType.COPY_CASE].includes(step.type)) {
|
||||
} else if (step.stepType === ScenarioStepType.API_CASE) {
|
||||
activeStep.value = step;
|
||||
customCaseDrawerVisible.value = true;
|
||||
} else if (step.stepType === ScenarioStepType.SCRIPT) {
|
||||
|
@ -653,7 +674,6 @@
|
|||
ScenarioStepType.API,
|
||||
refType,
|
||||
sort,
|
||||
stepDetails.value,
|
||||
appStore.currentProjectId
|
||||
);
|
||||
const insertCaseSteps = buildInsertStepInfos(
|
||||
|
@ -661,7 +681,6 @@
|
|||
ScenarioStepType.API_CASE,
|
||||
refType,
|
||||
sort + insertApiSteps.length,
|
||||
stepDetails.value,
|
||||
appStore.currentProjectId
|
||||
);
|
||||
const insertScenarioSteps = buildInsertStepInfos(
|
||||
|
@ -669,7 +688,6 @@
|
|||
ScenarioStepType.API_SCENARIO,
|
||||
refType,
|
||||
sort + insertApiSteps.length + insertCaseSteps.length,
|
||||
stepDetails.value,
|
||||
appStore.currentProjectId
|
||||
);
|
||||
const insertSteps = insertApiSteps.concat(insertCaseSteps).concat(insertScenarioSteps);
|
||||
|
@ -703,12 +721,17 @@
|
|||
} else {
|
||||
steps.value.push({
|
||||
...cloneDeep(defaultStepItemCommon),
|
||||
config: {
|
||||
customizeRequest: true,
|
||||
customizeRequestEnvEnable: request.customizeRequestEnvEnable,
|
||||
protocol: request.protocol,
|
||||
method: request.method,
|
||||
},
|
||||
id: request.id,
|
||||
sort: steps.value.length + 1,
|
||||
stepType: ScenarioStepType.CUSTOM_REQUEST,
|
||||
refType: ScenarioStepRefType.DIRECT,
|
||||
name: t('apiScenario.customApi'),
|
||||
method: request.method,
|
||||
projectId: appStore.currentProjectId,
|
||||
});
|
||||
}
|
||||
|
@ -719,6 +742,7 @@
|
|||
*/
|
||||
function applyApiStep(request: RequestParam | CaseRequestParam) {
|
||||
if (activeStep.value) {
|
||||
request.isNew = false;
|
||||
stepDetails.value[activeStep.value?.id] = request;
|
||||
activeStep.value = undefined;
|
||||
}
|
||||
|
@ -730,8 +754,8 @@
|
|||
function deleteCaseStep() {
|
||||
if (activeStep.value) {
|
||||
customCaseDrawerVisible.value = false;
|
||||
steps.value = steps.value.filter((item) => item.stepId !== activeStep.value?.stepId);
|
||||
delete stepsDetailMap.value[activeStep.value?.stepId];
|
||||
steps.value = steps.value.filter((item) => item.id !== activeStep.value?.id);
|
||||
delete stepDetails.value[activeStep.value?.id];
|
||||
activeStep.value = undefined;
|
||||
}
|
||||
}
|
||||
|
@ -851,6 +875,13 @@
|
|||
}
|
||||
quickInputDataKey.value = dataKey;
|
||||
quickInputParamValue.value = step.config?.[dataKey] || '';
|
||||
if (quickInputDataKey.value === 'msWhileVariableValue' && activeStep.value?.config.whileController) {
|
||||
quickInputParamValue.value = activeStep.value.config.whileController.msWhileVariable.value;
|
||||
} else if (quickInputDataKey.value === 'msWhileVariableScriptValue' && activeStep.value?.config.whileController) {
|
||||
quickInputParamValue.value = activeStep.value.config.whileController.msWhileScript.scriptValue;
|
||||
} else if (quickInputDataKey.value === 'conditionValue' && activeStep.value?.config) {
|
||||
quickInputParamValue.value = activeStep.value.config.value || '';
|
||||
}
|
||||
showQuickInput.value = true;
|
||||
}
|
||||
|
||||
|
@ -862,7 +893,13 @@
|
|||
|
||||
function applyQuickInput() {
|
||||
if (activeStep.value) {
|
||||
activeStep.value[quickInputDataKey.value] = quickInputParamValue.value;
|
||||
if (quickInputDataKey.value === 'msWhileVariableValue' && activeStep.value.config.whileController) {
|
||||
activeStep.value.config.whileController.msWhileVariable.value = quickInputParamValue.value;
|
||||
} else if (quickInputDataKey.value === 'msWhileVariableScriptValue' && activeStep.value.config.whileController) {
|
||||
activeStep.value.config.whileController.msWhileScript.scriptValue = quickInputParamValue.value;
|
||||
} else if (quickInputDataKey.value === 'conditionValue' && activeStep.value.config) {
|
||||
activeStep.value.config.value = quickInputParamValue.value;
|
||||
}
|
||||
showQuickInput.value = false;
|
||||
clearQuickInput();
|
||||
}
|
||||
|
|
|
@ -91,14 +91,9 @@
|
|||
import { useI18n } from '@/hooks/useI18n';
|
||||
import router from '@/router';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import { getGenerateId, mapTree, TreeNode } from '@/utils';
|
||||
import { getGenerateId } from '@/utils';
|
||||
|
||||
import {
|
||||
ApiScenarioGetModuleParams,
|
||||
ApiScenarioTableItem,
|
||||
Scenario,
|
||||
ScenarioStepItem,
|
||||
} from '@/models/apiTest/scenario';
|
||||
import { ApiScenarioGetModuleParams, ApiScenarioTableItem, Scenario } from '@/models/apiTest/scenario';
|
||||
import { ModuleTreeNode } from '@/models/common';
|
||||
import { ApiTestRouteEnum } from '@/enums/routeEnum';
|
||||
|
||||
|
@ -127,6 +122,7 @@
|
|||
...defaultScenarioInfo,
|
||||
id: isCopy ? getGenerateId() : defaultScenarioInfo.id || '',
|
||||
label: isCopy ? `copy-${defaultScenarioInfo.name}` : defaultScenarioInfo.name,
|
||||
isNew: false,
|
||||
});
|
||||
} else {
|
||||
apiTabs.value.push({
|
||||
|
@ -197,6 +193,8 @@
|
|||
projectId: appStore.currentProjectId,
|
||||
});
|
||||
const scenarioDetail = await getScenarioDetail(res.id);
|
||||
scenarioDetail.stepDetails = {};
|
||||
scenarioDetail.isNew = false;
|
||||
activeScenarioTab.value = scenarioDetail as ScenarioParams;
|
||||
} else {
|
||||
await updateScenario({
|
||||
|
@ -219,10 +217,6 @@
|
|||
appStore.showLoading();
|
||||
const res = await getScenarioDetail(record.id);
|
||||
res.stepDetails = {};
|
||||
// mapTree<ScenarioStepItem>(res.steps, (node: TreeNode<ScenarioStepItem>) => {
|
||||
// res.stepDetails[node.id] = node.config;
|
||||
// return node;
|
||||
// });
|
||||
newTab(res, isCopy);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
|
|
|
@ -116,8 +116,9 @@ export default {
|
|||
'apiScenario.variable': '变量名称{suffix}',
|
||||
'apiScenario.valuePrefix': '变量前缀',
|
||||
'apiScenario.value': '变量值',
|
||||
'apiScenario.whileController.msWhileVariable.value': '变量值',
|
||||
'apiScenario.whileController.msWhileScript.scriptValue': '表达式',
|
||||
'apiScenario.conditionValue': '变量值',
|
||||
'apiScenario.msWhileVariableValue': '变量值',
|
||||
'apiScenario.msWhileVariableScriptValue': '表达式',
|
||||
'apiScenario.condition': '条件',
|
||||
'apiScenario.expression': '表达式',
|
||||
'apiScenario.equal': '等于',
|
||||
|
|
Loading…
Reference in New Issue