feat(接口场景): 场景执行优化
This commit is contained in:
parent
348b926c6f
commit
d44b7d232e
|
@ -1,7 +1,7 @@
|
|||
@font-face {
|
||||
font-family: iconfont; /* Project id 3462279 */
|
||||
src: url('iconfont.woff2?t=1709537452442') format('woff2'), url('iconfont.woff?t=1709537452442') format('woff'),
|
||||
url('iconfont.ttf?t=1709537452442') format('truetype'), url('iconfont.svg?t=1709537452442#iconfont') format('svg');
|
||||
src: url('iconfont.woff2?t=1711511079663') format('woff2'), url('iconfont.woff?t=1711511079663') format('woff'),
|
||||
url('iconfont.ttf?t=1711511079663') format('truetype'), url('iconfont.svg?t=1711511079663#iconfont') format('svg');
|
||||
}
|
||||
.iconfont {
|
||||
font-size: 16px;
|
||||
|
@ -10,6 +10,18 @@
|
|||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
.icon-icon_stop::before {
|
||||
content: '\e7a8';
|
||||
}
|
||||
.icon-icon_env1::before {
|
||||
content: '\e7a7';
|
||||
}
|
||||
.icon-icon_case::before {
|
||||
content: '\e7a6';
|
||||
}
|
||||
.icon-icon_env::before {
|
||||
content: '\e7a5';
|
||||
}
|
||||
.icon-icon_expand_interface::before {
|
||||
content: '\e7a3';
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -5,6 +5,34 @@
|
|||
"css_prefix_text": "icon-",
|
||||
"description": "DE、MS项目icon管理",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "39710057",
|
||||
"name": "icon_stop",
|
||||
"font_class": "icon_stop",
|
||||
"unicode": "e7a8",
|
||||
"unicode_decimal": 59304
|
||||
},
|
||||
{
|
||||
"icon_id": "39697414",
|
||||
"name": "icon_env",
|
||||
"font_class": "icon_env1",
|
||||
"unicode": "e7a7",
|
||||
"unicode_decimal": 59303
|
||||
},
|
||||
{
|
||||
"icon_id": "39697284",
|
||||
"name": "icon_case",
|
||||
"font_class": "icon_case",
|
||||
"unicode": "e7a6",
|
||||
"unicode_decimal": 59302
|
||||
},
|
||||
{
|
||||
"icon_id": "39582483",
|
||||
"name": "icon_env",
|
||||
"font_class": "icon_env",
|
||||
"unicode": "e7a5",
|
||||
"unicode_decimal": 59301
|
||||
},
|
||||
{
|
||||
"icon_id": "39388088",
|
||||
"name": "icon_expand_interface",
|
||||
|
|
|
@ -14,6 +14,14 @@
|
|||
/>
|
||||
<missing-glyph />
|
||||
|
||||
<glyph glyph-name="icon_stop" unicode="" d="M512 853.333333c259.2 0 469.333333-210.133333 469.333333-469.333333s-210.133333-469.333333-469.333333-469.333333S42.666667 124.8 42.666667 384 252.8 853.333333 512 853.333333z m0-85.333333a384 384 0 1 1 0-768 384 384 0 0 1 0 768zM405.333333 554.666667a42.666667 42.666667 0 0 0 42.666667-42.666667v-256a42.666667 42.666667 0 0 0-85.333333 0V512a42.666667 42.666667 0 0 0 42.666666 42.666667z m213.333334 0a42.666667 42.666667 0 0 0 42.666666-42.666667v-256a42.666667 42.666667 0 0 0-85.333333 0V512a42.666667 42.666667 0 0 0 42.666667 42.666667z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_env1" unicode="" d="M399.701333 810.666667a42.666667 42.666667 0 0 0 32.085334-14.506667L531.328 682.666667h362.410667c45.738667 0 83.968-34.346667 87.338666-78.933334L981.333333 597.333333v-554.666666c0-47.616-39.68-85.333333-87.594666-85.333334H130.261333C82.346667-42.666667 42.666667-4.949333 42.666667 42.666667V725.333333c0 47.616 39.68 85.333333 87.594666 85.333334h269.44z m-19.328-85.333334H130.261333C128.554667 725.333333 128 724.821333 128 725.333333v-682.666666c0 0.512 0.512 0 2.261333 0h763.477334c1.706667 0 2.261333 0.512 2.261333 0V597.333333c0-0.512-0.512 0-2.261333 0H512a42.666667 42.666667 0 0 0-32.085333 14.506667L380.373333 725.333333z m8.362667-279.808v-58.666666H246.186667v-43.690667h132.181333v-56.064H246.186667v-54.186667h146.602666V170.666667H161.109333v274.858666H388.693333z m187.861333-71.253333c21.12 0 37.632-6.272 49.578667-18.816 11.946667-12.586667 17.92-32 17.92-58.24V170.666667h-76.672v109.482666c0 12.501333-2.346667 21.333333-6.954667 26.538667-4.608 5.205333-11.093333 7.808-19.498666 7.808a27.733333 27.733333 0 0 1-22.485334-10.496c-5.76-7.04-8.661333-19.584-8.661333-37.717333V170.666667h-76.288v199.125333h71.04v-32.426667c10.666667 13.226667 21.376 22.698667 32.256 28.416 10.88 5.674667 24.149333 8.533333 39.765333 8.533334z m159.573334-4.48l38.613333-126.208 39.936 126.208h77.056L807.253333 170.666667h-67.669333l-82.901333 199.125333h79.530666z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_case" unicode="" d="M554.666667 853.333333l3.456-0.128 2.901333-0.341333a46.208 46.208 0 0 0 9.472-2.56l2.218667-0.981333a43.434667 43.434667 0 0 0 7.338666-4.352l0.938667-0.725334 0.341333-0.298666 3.498667-3.114667 213.333333-213.333333 2.901334-3.285334 1.237333-1.493333c0.768-1.024 1.450667-2.090667 2.133333-3.157333l0.896-1.578667c0.469333-0.853333 0.938667-1.706667 1.322667-2.56l0.981333-2.261333a42.154667 42.154667 0 0 0 2.730667-10.837334l0.128-1.28 0.128-2.346666L810.666667 597.333333v-213.333333h-85.333334V554.666667h-170.666666a42.666667 42.666667 0 0 0-42.368 37.674666L512 597.333333V768H128v-768h384v-85.333333H128a85.333333 85.333333 0 0 0-85.333333 85.333333V768a85.333333 85.333333 0 0 0 85.333333 85.333333h426.666667z m247.808-524.8c75.349333 0 129.237333-49.621333 136.192-113.322666h-90.965334c-5.248 22.058667-17.408 39.125333-45.781333 39.125333h-60.885333c-33.578667 0-55.04-24.576-55.04-54.186667l0.597333-157.141333c0-29.568 21.418667-54.144 55.04-54.144h60.842667c27.818667 0 39.424 16.042667 45.226666 37.589333h91.562667c-6.954667-62.634667-61.44-111.786667-136.192-111.786666h-62.037333c-78.805333 0-143.104 55.637333-143.104 123.818666L597.333333 204.202667c0 68.693333 64.341333 124.330667 143.146667 124.330666zM597.333333 707.626667V640h67.626667L597.333333 707.626667z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_env" unicode="" d="M647.168 810.666667a106.666667 106.666667 0 0 0 75.434667-31.232l82.304-82.346667 102.528-102.485333A106.666667 106.666667 0 0 0 938.666667 519.168V64a106.666667 106.666667 0 0 0-106.666667-106.666667h-640A106.666667 106.666667 0 0 0 85.333333 64v640A106.666667 106.666667 0 0 0 192 810.666667h455.168z m0-85.333334H192a21.333333 21.333333 0 0 1-21.333333-21.333333v-640a21.333333 21.333333 0 0 1 21.333333-21.333333h640a21.333333 21.333333 0 0 1 21.333333 21.333333V519.168a21.333333 21.333333 0 0 1-6.229333 15.104l-184.832 184.832A21.333333 21.333333 0 0 1 647.168 725.333333z m-247.765333-256v-45.568h-116.48v-33.877333h108.074666v-43.52H282.88v-42.069333h119.893333V256H213.333333v213.333333h186.069334z m153.6-55.296c17.28 0 30.762667-4.864 40.533333-14.634666 9.770667-9.728 14.634667-24.789333 14.634667-45.184V256h-62.677334v84.992c0 9.685333-1.877333 16.554667-5.674666 20.565333a20.821333 20.821333 0 0 1-15.957334 6.058667 23.168 23.168 0 0 1-18.346666-8.149333c-4.693333-5.418667-7.082667-15.189333-7.082667-29.269334V256H436.053333v154.538667h58.069334v-25.173334c8.704 10.282667 17.493333 17.621333 26.368 22.058667a72.533333 72.533333 0 0 0 32.512 6.613333z m130.432-3.498666l31.573333-97.92 32.64 97.92H810.666667L741.546667 256h-55.338667l-67.754667 154.538667h64.981334z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_expand_interface" unicode="" d="M827.733333 332.8a42.666667 42.666667 0 0 0 51.2-68.266667l-341.333333-256a42.666667 42.666667 0 0 0-51.2 0l-341.333333 256a42.666667 42.666667 0 1 0 51.2 68.266667l315.733333-236.8 315.733333 236.8zM853.333333 725.333333a42.666667 42.666667 0 0 0 0-85.333333H170.666667a42.666667 42.666667 0 1 0 0 85.333333h682.666666z m0-170.666666a42.666667 42.666667 0 0 0 0-85.333334H170.666667a42.666667 42.666667 0 1 0 0 85.333334h682.666666z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="icon_collapse_interface" unicode="" d="M196.266667 392.533333a42.666667 42.666667 0 0 0-51.2 68.266667l341.333333 256a42.666667 42.666667 0 0 0 51.2 0l341.333333-256a42.666667 42.666667 0 1 0-51.2-68.266667L512 629.333333 196.266667 392.533333zM170.666667 0a42.666667 42.666667 0 0 0 0 85.333333h682.666666a42.666667 42.666667 0 1 0 0-85.333333H170.666667z m0 170.666667a42.666667 42.666667 0 0 0 0 85.333333h682.666666a42.666667 42.666667 0 1 0 0-85.333333H170.666667z" horiz-adv-x="1024" />
|
||||
|
|
Before Width: | Height: | Size: 437 KiB After Width: | Height: | Size: 442 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -272,6 +272,7 @@ export interface ForEachController {
|
|||
}
|
||||
export interface CountController {
|
||||
loops: number; // 循环次数
|
||||
loopTime: number; // 循环间隔时间
|
||||
}
|
||||
export interface WhileScript {
|
||||
scriptValue: string; // 脚本值
|
||||
|
@ -400,7 +401,7 @@ export interface ApiScenarioDebugRequest {
|
|||
environmentId: string;
|
||||
scenarioConfig: ScenarioConfig;
|
||||
stepDetails: Record<string, ScenarioStepDetail>;
|
||||
reportId?: string | number;
|
||||
reportId: string | number;
|
||||
steps: ScenarioStepItem[];
|
||||
projectId: string;
|
||||
uploadFileIds: string[];
|
||||
|
|
|
@ -494,6 +494,10 @@ export function deleteNode<T>(treeArr: TreeNode<T>[], targetKey: string | number
|
|||
const node = tree[i];
|
||||
if (node[customKey] === targetKey) {
|
||||
tree.splice(i, 1); // 直接删除当前节点
|
||||
// 重新调整剩余子节点的 sort 序号
|
||||
for (let j = i; j < tree.length; j++) {
|
||||
tree[j].sort = j + 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (Array.isArray(node.children)) {
|
||||
|
@ -518,6 +522,10 @@ export function deleteNodes<T>(treeArr: TreeNode<T>[], targetKeys: (string | num
|
|||
if (targetKeysSet.has(node[customKey])) {
|
||||
tree.splice(i, 1); // 直接删除当前节点
|
||||
targetKeysSet.delete(node[customKey]); // 删除后从集合中移除
|
||||
// 重新调整剩余子节点的 sort 序号
|
||||
for (let j = i; j < tree.length; j++) {
|
||||
tree[j].sort = j + 1;
|
||||
}
|
||||
} else if (Array.isArray(node.children)) {
|
||||
deleteNodesInTree(node.children); // 递归删除子节点
|
||||
}
|
||||
|
|
|
@ -73,23 +73,33 @@
|
|||
"
|
||||
>
|
||||
<a-dropdown-button
|
||||
v-if="!requestVModel.executeLoading"
|
||||
v-if="hasLocalExec"
|
||||
:disabled="requestVModel.executeLoading || (isHttpProtocol && !requestVModel.url)"
|
||||
class="exec-btn"
|
||||
@click="() => execute(isPriorityLocalExec ? 'localExec' : 'serverExec')"
|
||||
@select="execute"
|
||||
>
|
||||
{{ isPriorityLocalExec ? t('apiTestDebug.localExec') : t('apiTestDebug.serverExec') }}
|
||||
<template v-if="hasLocalExec" #icon>
|
||||
<template #icon>
|
||||
<icon-down />
|
||||
</template>
|
||||
<template v-if="hasLocalExec" #content>
|
||||
<template #content>
|
||||
<a-doption :value="isPriorityLocalExec ? 'serverExec' : 'localExec'">
|
||||
{{ isPriorityLocalExec ? t('apiTestDebug.serverExec') : t('apiTestDebug.localExec') }}
|
||||
</a-doption>
|
||||
</template>
|
||||
</a-dropdown-button>
|
||||
<a-button v-else type="primary" class="mr-[12px]" @click="stopDebug">{{ t('common.stop') }}</a-button>
|
||||
<a-button
|
||||
v-else-if="!requestVModel.executeLoading"
|
||||
class="mr-[12px]"
|
||||
type="primary"
|
||||
@click="() => execute('serverExec')"
|
||||
>
|
||||
{{ t('apiTestDebug.serverExec') }}
|
||||
</a-button>
|
||||
<a-button v-else type="primary" class="mr-[12px]" @click="stopDebug">
|
||||
{{ t('common.stop') }}
|
||||
</a-button>
|
||||
</template>
|
||||
<!-- 接口定义-且有保存或更新权限 -->
|
||||
<template
|
||||
|
|
|
@ -474,7 +474,7 @@
|
|||
watch(
|
||||
() => props.stepResponses,
|
||||
(val) => {
|
||||
if (val) {
|
||||
if (val && val[requestVModel.value.stepId]) {
|
||||
requestVModel.value.executeLoading = false;
|
||||
}
|
||||
},
|
||||
|
|
|
@ -17,6 +17,7 @@ export const defaultLoopController = {
|
|||
},
|
||||
msCountController: {
|
||||
loops: 0, // 循环次数
|
||||
loopTime: 0, // 循环间隔时间
|
||||
},
|
||||
whileController: {
|
||||
conditionType: WhileConditionType.CONDITION, // 条件类型
|
||||
|
@ -65,6 +66,7 @@ export const defaultStepItemCommon = {
|
|||
createActionsVisible: false,
|
||||
responsePopoverVisible: false,
|
||||
isExecuting: false,
|
||||
executeStatus: undefined,
|
||||
};
|
||||
|
||||
export const defaultScenario: Scenario = {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="mb-[16px] flex items-center justify-end">
|
||||
<div class="mb-[8px] flex items-center justify-end">
|
||||
<a-input-search
|
||||
v-model:model-value="keyword"
|
||||
:placeholder="t('apiScenario.executeHistory.searchPlaceholder')"
|
||||
|
@ -119,7 +119,7 @@
|
|||
dataIndex: 'id',
|
||||
slotName: 'num',
|
||||
fixed: 'left',
|
||||
width: 100,
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: 'apiScenario.executeHistory.execution.triggerMode',
|
||||
|
@ -131,7 +131,7 @@
|
|||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
width: 150,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'apiScenario.executeHistory.execution.status',
|
||||
|
@ -142,14 +142,13 @@
|
|||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
width: 150,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'apiScenario.executeHistory.execution.operator',
|
||||
dataIndex: 'createUser',
|
||||
slotName: 'operationUser',
|
||||
dataIndex: 'operationUser',
|
||||
showTooltip: true,
|
||||
width: 150,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'apiScenario.executeHistory.execution.operatorTime',
|
||||
|
@ -159,7 +158,7 @@
|
|||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
width: 200,
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: 'common.operation',
|
||||
|
@ -168,7 +167,7 @@
|
|||
fixed: 'right',
|
||||
showInTable: true,
|
||||
showDrag: false,
|
||||
width: 150,
|
||||
width: 100,
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -179,7 +178,7 @@
|
|||
scroll: { x: '100%' },
|
||||
showSetting: false,
|
||||
selectable: false,
|
||||
heightUsed: 374,
|
||||
heightUsed: 398,
|
||||
},
|
||||
(item) => ({
|
||||
...item,
|
||||
|
|
|
@ -131,7 +131,7 @@
|
|||
import { countNodes } from '@/utils/tree';
|
||||
|
||||
import { ApiScenarioDebugRequest, Scenario } from '@/models/apiTest/scenario';
|
||||
import { ScenarioExecuteStatus } from '@/enums/apiEnum';
|
||||
import { ScenarioExecuteStatus, ScenarioStepType } from '@/enums/apiEnum';
|
||||
import { ApiTestRouteEnum } from '@/enums/routeEnum';
|
||||
|
||||
const props = defineProps<{
|
||||
|
@ -248,7 +248,10 @@
|
|||
if (!node.enable) {
|
||||
// 如果步骤未开启,则删除已选 id,方便下面waitingDebugStepDetails详情判断是否携带
|
||||
checkedKeysSet.delete(node.id);
|
||||
} else {
|
||||
} else if (
|
||||
[ScenarioStepType.API, ScenarioStepType.API_CASE, ScenarioStepType.CUSTOM_REQUEST].includes(node.stepType)
|
||||
) {
|
||||
// 请求和场景类型才直接显示执行中,其他控制器需要等待执行完毕才结算执行结果
|
||||
node.executeStatus = ScenarioExecuteStatus.EXECUTING;
|
||||
}
|
||||
return !!node.enable;
|
||||
|
|
|
@ -142,6 +142,7 @@
|
|||
:disabled="!innerData.forEachController.loopTime"
|
||||
>
|
||||
<a-input-number
|
||||
v-if="innerData.loopType === ScenarioStepLoopTypeEnum.FOREACH"
|
||||
v-model:model-value="innerData.forEachController.loopTime"
|
||||
size="mini"
|
||||
:step="1"
|
||||
|
@ -156,6 +157,22 @@
|
|||
<div class="text-[12px] text-[var(--color-text-4)]">{{ t('apiScenario.space') }}:</div>
|
||||
</template>
|
||||
</a-input-number>
|
||||
<a-input-number
|
||||
v-else-if="innerData.loopType === ScenarioStepLoopTypeEnum.LOOP_COUNT"
|
||||
v-model:model-value="innerData.msCountController.loopTime"
|
||||
size="mini"
|
||||
:step="1"
|
||||
:min="0"
|
||||
:precision="0"
|
||||
hide-button
|
||||
class="w-[110px] px-[8px]"
|
||||
model-event="input"
|
||||
@blur="handleInputChange"
|
||||
>
|
||||
<template #prefix>
|
||||
<div class="text-[12px] text-[var(--color-text-4)]">{{ t('apiScenario.space') }}:</div>
|
||||
</template>
|
||||
</a-input-number>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
</div>
|
||||
</template>
|
||||
</a-popover> -->
|
||||
<MsTag
|
||||
<!-- <MsTag
|
||||
v-if="props.data.projectId !== appStore.currentProjectId"
|
||||
theme="outline"
|
||||
size="small"
|
||||
|
@ -30,7 +30,7 @@
|
|||
}"
|
||||
>
|
||||
{{ t('apiScenario.crossProject') }}
|
||||
</MsTag>
|
||||
</MsTag> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -66,11 +66,19 @@
|
|||
></a-switch>
|
||||
<!-- 步骤执行 -->
|
||||
<MsIcon
|
||||
v-show="!step.isExecuting"
|
||||
type="icon-icon_play-round_filled"
|
||||
:size="18"
|
||||
class="cursor-pointer text-[rgb(var(--link-6))]"
|
||||
@click.stop="executeStep(step)"
|
||||
/>
|
||||
<MsIcon
|
||||
v-show="step.isExecuting"
|
||||
type="icon-icon_stop"
|
||||
:size="20"
|
||||
class="cursor-pointer text-[rgb(var(--link-6))]"
|
||||
@click.stop="handleStopExecute(step)"
|
||||
/>
|
||||
</div>
|
||||
<!-- 步骤类型 -->
|
||||
<stepType :step="step" />
|
||||
|
@ -169,9 +177,10 @@
|
|||
</template>
|
||||
<template #extraEnd="step">
|
||||
<a-popover
|
||||
v-if="step.executeStatus"
|
||||
v-if="step.executeStatus && checkStepIsApi(step)"
|
||||
position="br"
|
||||
content-class="scenario-step-response-popover"
|
||||
:disabled="![ScenarioExecuteStatus.SUCCESS, ScenarioExecuteStatus.FAILED].includes(step.executeStatus)"
|
||||
@popup-visible-change="handleResponsePopoverVisibleChange($event, step)"
|
||||
>
|
||||
<executeStatus :status="getExecuteStatus(step) || step.executeStatus" size="small" />
|
||||
|
@ -195,6 +204,11 @@
|
|||
</responseResult>
|
||||
</template>
|
||||
</a-popover>
|
||||
<executeStatus
|
||||
v-else-if="step.executeStatus"
|
||||
:status="getExecuteStatus(step) || step.executeStatus"
|
||||
size="small"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="steps.length === 0 && stepKeyword.trim() !== ''" #empty>
|
||||
<div
|
||||
|
@ -220,7 +234,7 @@
|
|||
:step-responses="scenario.stepResponses"
|
||||
@add-step="addCustomApiStep"
|
||||
@apply-step="applyApiStep"
|
||||
@stop-debug="handleStopExecute"
|
||||
@stop-debug="handleStopExecute(activeStep)"
|
||||
@execute="handleApiExecute"
|
||||
/>
|
||||
<customCaseDrawer
|
||||
|
@ -693,7 +707,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
const websocket = ref<WebSocket>();
|
||||
const websocketMap: Record<string | number, WebSocket> = {};
|
||||
let temporaryStepReportMap = {}; // 缓存websocket返回的报告内容,避免执行接口后切换场景tab导致报告丢失
|
||||
|
||||
watch(
|
||||
|
@ -715,16 +729,16 @@
|
|||
*/
|
||||
function debugSocket(
|
||||
step: ScenarioStepItem,
|
||||
reportId?: string | number,
|
||||
reportId: string | number,
|
||||
executeType?: 'localExec' | 'serverExec',
|
||||
localExecuteUrl?: string
|
||||
) {
|
||||
websocket.value = getSocket(
|
||||
websocketMap[reportId] = getSocket(
|
||||
reportId || '',
|
||||
executeType === 'localExec' ? '/ws/debug' : '',
|
||||
executeType === 'localExec' ? localExecuteUrl : ''
|
||||
);
|
||||
websocket.value.addEventListener('message', (event) => {
|
||||
websocketMap[reportId].addEventListener('message', (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
if (data.msgType === 'EXEC_RESULT') {
|
||||
if (step.reportId === data.reportId) {
|
||||
|
@ -751,7 +765,7 @@
|
|||
}
|
||||
} else if (data.msgType === 'EXEC_END') {
|
||||
// 执行结束,关闭websocket
|
||||
websocket.value?.close();
|
||||
websocketMap[reportId].close();
|
||||
if (step.reportId === data.reportId) {
|
||||
step.isExecuting = false;
|
||||
}
|
||||
|
@ -786,7 +800,7 @@
|
|||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
websocket.value?.close();
|
||||
websocketMap[executeParams.reportId].close();
|
||||
currentStep.isExecuting = false;
|
||||
}
|
||||
}
|
||||
|
@ -843,14 +857,43 @@
|
|||
},
|
||||
executeType
|
||||
);
|
||||
} else {
|
||||
// 步骤列表找不到该步骤,说明是新建的自定义请求还未保存,则临时创建一个步骤进行调试(不保存步骤信息)
|
||||
const reportId = getGenerateId();
|
||||
request.executeLoading = true;
|
||||
activeStep.value = {
|
||||
id: request.stepId,
|
||||
name: t('apiScenario.customApi'),
|
||||
stepType: ScenarioStepType.CUSTOM_REQUEST,
|
||||
refType: ScenarioStepRefType.DIRECT,
|
||||
sort: 1,
|
||||
enable: true,
|
||||
isNew: true,
|
||||
config: {},
|
||||
projectId: appStore.currentProjectId,
|
||||
isExecuting: false,
|
||||
reportId,
|
||||
};
|
||||
realExecute(
|
||||
{
|
||||
steps: [activeStep.value],
|
||||
stepDetails: {
|
||||
[request.stepId]: request,
|
||||
},
|
||||
reportId,
|
||||
uploadFileIds: request.uploadFileIds || [],
|
||||
linkFileIds: request.linkFileIds || [],
|
||||
},
|
||||
executeType
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function handleStopExecute() {
|
||||
websocket.value?.close();
|
||||
if (activeStep.value) {
|
||||
activeStep.value.isExecuting = false;
|
||||
activeStep.value.executeStatus = undefined;
|
||||
function handleStopExecute(step?: ScenarioStepItem) {
|
||||
if (step?.reportId) {
|
||||
websocketMap[step.reportId].close();
|
||||
step.isExecuting = false;
|
||||
step.executeStatus = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@
|
|||
import { useI18n } from '@/hooks/useI18n';
|
||||
import router from '@/router';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import { filterTree, getGenerateId } from '@/utils';
|
||||
import { filterTree, getGenerateId, mapTree } from '@/utils';
|
||||
|
||||
import {
|
||||
ApiScenarioDebugRequest,
|
||||
|
@ -122,7 +122,7 @@
|
|||
} from '@/models/apiTest/scenario';
|
||||
import { ModuleTreeNode } from '@/models/common';
|
||||
import { EnvConfig } from '@/models/projectManagement/environmental';
|
||||
import { ScenarioExecuteStatus } from '@/enums/apiEnum';
|
||||
import { ScenarioExecuteStatus, ScenarioStepType } from '@/enums/apiEnum';
|
||||
import { ApiTestRouteEnum } from '@/enums/routeEnum';
|
||||
|
||||
import { defaultScenario } from './components/config';
|
||||
|
@ -367,6 +367,12 @@
|
|||
uploadFileIds: activeScenarioTab.value.uploadFileIds,
|
||||
linkFileIds: activeScenarioTab.value.linkFileIds,
|
||||
...executeParams,
|
||||
steps: mapTree(executeParams.steps, (node) => {
|
||||
return {
|
||||
...node,
|
||||
parent: null, // 原树形结构存在循环引用,这里要去掉以免 axios 序列化失败
|
||||
};
|
||||
}),
|
||||
});
|
||||
} else {
|
||||
res = await debugScenario({
|
||||
|
@ -379,6 +385,12 @@
|
|||
linkFileIds: activeScenarioTab.value.linkFileIds,
|
||||
frontendDebug: executeType === 'localExec',
|
||||
...executeParams,
|
||||
steps: mapTree(executeParams.steps, (node) => {
|
||||
return {
|
||||
...node,
|
||||
parent: null, // 原树形结构存在循环引用,这里要去掉以免 axios 序列化失败
|
||||
};
|
||||
}),
|
||||
});
|
||||
}
|
||||
if (executeType === 'localExec' && localExecuteUrl) {
|
||||
|
@ -398,6 +410,12 @@
|
|||
if (node.enable) {
|
||||
node.executeStatus = ScenarioExecuteStatus.EXECUTING;
|
||||
waitingDebugStepDetails[node.id] = activeScenarioTab.value.stepDetails[node.id];
|
||||
if (
|
||||
[ScenarioStepType.API, ScenarioStepType.API_CASE, ScenarioStepType.CUSTOM_REQUEST].includes(node.stepType)
|
||||
) {
|
||||
// 请求和场景类型才直接显示执行中,其他控制器需要等待执行完毕才结算执行结果
|
||||
node.executeStatus = ScenarioExecuteStatus.EXECUTING;
|
||||
}
|
||||
}
|
||||
return !!node.enable;
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue