feat(接口场景): 场景执行优化
This commit is contained in:
parent
348b926c6f
commit
d44b7d232e
|
@ -1,7 +1,7 @@
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: iconfont; /* Project id 3462279 */
|
font-family: iconfont; /* Project id 3462279 */
|
||||||
src: url('iconfont.woff2?t=1709537452442') format('woff2'), url('iconfont.woff?t=1709537452442') format('woff'),
|
src: url('iconfont.woff2?t=1711511079663') format('woff2'), url('iconfont.woff?t=1711511079663') format('woff'),
|
||||||
url('iconfont.ttf?t=1709537452442') format('truetype'), url('iconfont.svg?t=1709537452442#iconfont') format('svg');
|
url('iconfont.ttf?t=1711511079663') format('truetype'), url('iconfont.svg?t=1711511079663#iconfont') format('svg');
|
||||||
}
|
}
|
||||||
.iconfont {
|
.iconfont {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
@ -10,6 +10,18 @@
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-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 {
|
.icon-icon_expand_interface::before {
|
||||||
content: '\e7a3';
|
content: '\e7a3';
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -5,6 +5,34 @@
|
||||||
"css_prefix_text": "icon-",
|
"css_prefix_text": "icon-",
|
||||||
"description": "DE、MS项目icon管理",
|
"description": "DE、MS项目icon管理",
|
||||||
"glyphs": [
|
"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",
|
"icon_id": "39388088",
|
||||||
"name": "icon_expand_interface",
|
"name": "icon_expand_interface",
|
||||||
|
|
|
@ -14,6 +14,14 @@
|
||||||
/>
|
/>
|
||||||
<missing-glyph />
|
<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_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" />
|
<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 {
|
export interface CountController {
|
||||||
loops: number; // 循环次数
|
loops: number; // 循环次数
|
||||||
|
loopTime: number; // 循环间隔时间
|
||||||
}
|
}
|
||||||
export interface WhileScript {
|
export interface WhileScript {
|
||||||
scriptValue: string; // 脚本值
|
scriptValue: string; // 脚本值
|
||||||
|
@ -400,7 +401,7 @@ export interface ApiScenarioDebugRequest {
|
||||||
environmentId: string;
|
environmentId: string;
|
||||||
scenarioConfig: ScenarioConfig;
|
scenarioConfig: ScenarioConfig;
|
||||||
stepDetails: Record<string, ScenarioStepDetail>;
|
stepDetails: Record<string, ScenarioStepDetail>;
|
||||||
reportId?: string | number;
|
reportId: string | number;
|
||||||
steps: ScenarioStepItem[];
|
steps: ScenarioStepItem[];
|
||||||
projectId: string;
|
projectId: string;
|
||||||
uploadFileIds: string[];
|
uploadFileIds: string[];
|
||||||
|
|
|
@ -494,6 +494,10 @@ export function deleteNode<T>(treeArr: TreeNode<T>[], targetKey: string | number
|
||||||
const node = tree[i];
|
const node = tree[i];
|
||||||
if (node[customKey] === targetKey) {
|
if (node[customKey] === targetKey) {
|
||||||
tree.splice(i, 1); // 直接删除当前节点
|
tree.splice(i, 1); // 直接删除当前节点
|
||||||
|
// 重新调整剩余子节点的 sort 序号
|
||||||
|
for (let j = i; j < tree.length; j++) {
|
||||||
|
tree[j].sort = j + 1;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (Array.isArray(node.children)) {
|
if (Array.isArray(node.children)) {
|
||||||
|
@ -518,6 +522,10 @@ export function deleteNodes<T>(treeArr: TreeNode<T>[], targetKeys: (string | num
|
||||||
if (targetKeysSet.has(node[customKey])) {
|
if (targetKeysSet.has(node[customKey])) {
|
||||||
tree.splice(i, 1); // 直接删除当前节点
|
tree.splice(i, 1); // 直接删除当前节点
|
||||||
targetKeysSet.delete(node[customKey]); // 删除后从集合中移除
|
targetKeysSet.delete(node[customKey]); // 删除后从集合中移除
|
||||||
|
// 重新调整剩余子节点的 sort 序号
|
||||||
|
for (let j = i; j < tree.length; j++) {
|
||||||
|
tree[j].sort = j + 1;
|
||||||
|
}
|
||||||
} else if (Array.isArray(node.children)) {
|
} else if (Array.isArray(node.children)) {
|
||||||
deleteNodesInTree(node.children); // 递归删除子节点
|
deleteNodesInTree(node.children); // 递归删除子节点
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,23 +73,33 @@
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<a-dropdown-button
|
<a-dropdown-button
|
||||||
v-if="!requestVModel.executeLoading"
|
v-if="hasLocalExec"
|
||||||
:disabled="requestVModel.executeLoading || (isHttpProtocol && !requestVModel.url)"
|
:disabled="requestVModel.executeLoading || (isHttpProtocol && !requestVModel.url)"
|
||||||
class="exec-btn"
|
class="exec-btn"
|
||||||
@click="() => execute(isPriorityLocalExec ? 'localExec' : 'serverExec')"
|
@click="() => execute(isPriorityLocalExec ? 'localExec' : 'serverExec')"
|
||||||
@select="execute"
|
@select="execute"
|
||||||
>
|
>
|
||||||
{{ isPriorityLocalExec ? t('apiTestDebug.localExec') : t('apiTestDebug.serverExec') }}
|
{{ isPriorityLocalExec ? t('apiTestDebug.localExec') : t('apiTestDebug.serverExec') }}
|
||||||
<template v-if="hasLocalExec" #icon>
|
<template #icon>
|
||||||
<icon-down />
|
<icon-down />
|
||||||
</template>
|
</template>
|
||||||
<template v-if="hasLocalExec" #content>
|
<template #content>
|
||||||
<a-doption :value="isPriorityLocalExec ? 'serverExec' : 'localExec'">
|
<a-doption :value="isPriorityLocalExec ? 'serverExec' : 'localExec'">
|
||||||
{{ isPriorityLocalExec ? t('apiTestDebug.serverExec') : t('apiTestDebug.localExec') }}
|
{{ isPriorityLocalExec ? t('apiTestDebug.serverExec') : t('apiTestDebug.localExec') }}
|
||||||
</a-doption>
|
</a-doption>
|
||||||
</template>
|
</template>
|
||||||
</a-dropdown-button>
|
</a-dropdown-button>
|
||||||
<a-button v-else type="primary" class="mr-[12px]" @click="stopDebug">{{ t('common.stop') }}</a-button>
|
<a-button
|
||||||
|
v-else-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>
|
||||||
<!-- 接口定义-且有保存或更新权限 -->
|
<!-- 接口定义-且有保存或更新权限 -->
|
||||||
<template
|
<template
|
||||||
|
|
|
@ -474,7 +474,7 @@
|
||||||
watch(
|
watch(
|
||||||
() => props.stepResponses,
|
() => props.stepResponses,
|
||||||
(val) => {
|
(val) => {
|
||||||
if (val) {
|
if (val && val[requestVModel.value.stepId]) {
|
||||||
requestVModel.value.executeLoading = false;
|
requestVModel.value.executeLoading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -17,6 +17,7 @@ export const defaultLoopController = {
|
||||||
},
|
},
|
||||||
msCountController: {
|
msCountController: {
|
||||||
loops: 0, // 循环次数
|
loops: 0, // 循环次数
|
||||||
|
loopTime: 0, // 循环间隔时间
|
||||||
},
|
},
|
||||||
whileController: {
|
whileController: {
|
||||||
conditionType: WhileConditionType.CONDITION, // 条件类型
|
conditionType: WhileConditionType.CONDITION, // 条件类型
|
||||||
|
@ -65,6 +66,7 @@ export const defaultStepItemCommon = {
|
||||||
createActionsVisible: false,
|
createActionsVisible: false,
|
||||||
responsePopoverVisible: false,
|
responsePopoverVisible: false,
|
||||||
isExecuting: false,
|
isExecuting: false,
|
||||||
|
executeStatus: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const defaultScenario: Scenario = {
|
export const defaultScenario: Scenario = {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="mb-[16px] flex items-center justify-end">
|
<div class="mb-[8px] flex items-center justify-end">
|
||||||
<a-input-search
|
<a-input-search
|
||||||
v-model:model-value="keyword"
|
v-model:model-value="keyword"
|
||||||
:placeholder="t('apiScenario.executeHistory.searchPlaceholder')"
|
:placeholder="t('apiScenario.executeHistory.searchPlaceholder')"
|
||||||
|
@ -119,7 +119,7 @@
|
||||||
dataIndex: 'id',
|
dataIndex: 'id',
|
||||||
slotName: 'num',
|
slotName: 'num',
|
||||||
fixed: 'left',
|
fixed: 'left',
|
||||||
width: 100,
|
width: 150,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'apiScenario.executeHistory.execution.triggerMode',
|
title: 'apiScenario.executeHistory.execution.triggerMode',
|
||||||
|
@ -131,7 +131,7 @@
|
||||||
sortDirections: ['ascend', 'descend'],
|
sortDirections: ['ascend', 'descend'],
|
||||||
sorter: true,
|
sorter: true,
|
||||||
},
|
},
|
||||||
width: 150,
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'apiScenario.executeHistory.execution.status',
|
title: 'apiScenario.executeHistory.execution.status',
|
||||||
|
@ -142,14 +142,13 @@
|
||||||
sortDirections: ['ascend', 'descend'],
|
sortDirections: ['ascend', 'descend'],
|
||||||
sorter: true,
|
sorter: true,
|
||||||
},
|
},
|
||||||
width: 150,
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'apiScenario.executeHistory.execution.operator',
|
title: 'apiScenario.executeHistory.execution.operator',
|
||||||
dataIndex: 'createUser',
|
dataIndex: 'operationUser',
|
||||||
slotName: 'operationUser',
|
|
||||||
showTooltip: true,
|
showTooltip: true,
|
||||||
width: 150,
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'apiScenario.executeHistory.execution.operatorTime',
|
title: 'apiScenario.executeHistory.execution.operatorTime',
|
||||||
|
@ -159,7 +158,7 @@
|
||||||
sortDirections: ['ascend', 'descend'],
|
sortDirections: ['ascend', 'descend'],
|
||||||
sorter: true,
|
sorter: true,
|
||||||
},
|
},
|
||||||
width: 200,
|
width: 180,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'common.operation',
|
title: 'common.operation',
|
||||||
|
@ -168,7 +167,7 @@
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
showInTable: true,
|
showInTable: true,
|
||||||
showDrag: false,
|
showDrag: false,
|
||||||
width: 150,
|
width: 100,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -179,7 +178,7 @@
|
||||||
scroll: { x: '100%' },
|
scroll: { x: '100%' },
|
||||||
showSetting: false,
|
showSetting: false,
|
||||||
selectable: false,
|
selectable: false,
|
||||||
heightUsed: 374,
|
heightUsed: 398,
|
||||||
},
|
},
|
||||||
(item) => ({
|
(item) => ({
|
||||||
...item,
|
...item,
|
||||||
|
|
|
@ -131,7 +131,7 @@
|
||||||
import { countNodes } from '@/utils/tree';
|
import { countNodes } from '@/utils/tree';
|
||||||
|
|
||||||
import { ApiScenarioDebugRequest, Scenario } from '@/models/apiTest/scenario';
|
import { ApiScenarioDebugRequest, Scenario } from '@/models/apiTest/scenario';
|
||||||
import { ScenarioExecuteStatus } from '@/enums/apiEnum';
|
import { ScenarioExecuteStatus, ScenarioStepType } from '@/enums/apiEnum';
|
||||||
import { ApiTestRouteEnum } from '@/enums/routeEnum';
|
import { ApiTestRouteEnum } from '@/enums/routeEnum';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
@ -248,7 +248,10 @@
|
||||||
if (!node.enable) {
|
if (!node.enable) {
|
||||||
// 如果步骤未开启,则删除已选 id,方便下面waitingDebugStepDetails详情判断是否携带
|
// 如果步骤未开启,则删除已选 id,方便下面waitingDebugStepDetails详情判断是否携带
|
||||||
checkedKeysSet.delete(node.id);
|
checkedKeysSet.delete(node.id);
|
||||||
} else {
|
} else if (
|
||||||
|
[ScenarioStepType.API, ScenarioStepType.API_CASE, ScenarioStepType.CUSTOM_REQUEST].includes(node.stepType)
|
||||||
|
) {
|
||||||
|
// 请求和场景类型才直接显示执行中,其他控制器需要等待执行完毕才结算执行结果
|
||||||
node.executeStatus = ScenarioExecuteStatus.EXECUTING;
|
node.executeStatus = ScenarioExecuteStatus.EXECUTING;
|
||||||
}
|
}
|
||||||
return !!node.enable;
|
return !!node.enable;
|
||||||
|
|
|
@ -142,6 +142,7 @@
|
||||||
:disabled="!innerData.forEachController.loopTime"
|
:disabled="!innerData.forEachController.loopTime"
|
||||||
>
|
>
|
||||||
<a-input-number
|
<a-input-number
|
||||||
|
v-if="innerData.loopType === ScenarioStepLoopTypeEnum.FOREACH"
|
||||||
v-model:model-value="innerData.forEachController.loopTime"
|
v-model:model-value="innerData.forEachController.loopTime"
|
||||||
size="mini"
|
size="mini"
|
||||||
:step="1"
|
:step="1"
|
||||||
|
@ -156,6 +157,22 @@
|
||||||
<div class="text-[12px] text-[var(--color-text-4)]">{{ t('apiScenario.space') }}:</div>
|
<div class="text-[12px] text-[var(--color-text-4)]">{{ t('apiScenario.space') }}:</div>
|
||||||
</template>
|
</template>
|
||||||
</a-input-number>
|
</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>
|
</a-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</a-popover> -->
|
</a-popover> -->
|
||||||
<MsTag
|
<!-- <MsTag
|
||||||
v-if="props.data.projectId !== appStore.currentProjectId"
|
v-if="props.data.projectId !== appStore.currentProjectId"
|
||||||
theme="outline"
|
theme="outline"
|
||||||
size="small"
|
size="small"
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
{{ t('apiScenario.crossProject') }}
|
{{ t('apiScenario.crossProject') }}
|
||||||
</MsTag>
|
</MsTag> -->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -66,11 +66,19 @@
|
||||||
></a-switch>
|
></a-switch>
|
||||||
<!-- 步骤执行 -->
|
<!-- 步骤执行 -->
|
||||||
<MsIcon
|
<MsIcon
|
||||||
|
v-show="!step.isExecuting"
|
||||||
type="icon-icon_play-round_filled"
|
type="icon-icon_play-round_filled"
|
||||||
:size="18"
|
:size="18"
|
||||||
class="cursor-pointer text-[rgb(var(--link-6))]"
|
class="cursor-pointer text-[rgb(var(--link-6))]"
|
||||||
@click.stop="executeStep(step)"
|
@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>
|
</div>
|
||||||
<!-- 步骤类型 -->
|
<!-- 步骤类型 -->
|
||||||
<stepType :step="step" />
|
<stepType :step="step" />
|
||||||
|
@ -169,9 +177,10 @@
|
||||||
</template>
|
</template>
|
||||||
<template #extraEnd="step">
|
<template #extraEnd="step">
|
||||||
<a-popover
|
<a-popover
|
||||||
v-if="step.executeStatus"
|
v-if="step.executeStatus && checkStepIsApi(step)"
|
||||||
position="br"
|
position="br"
|
||||||
content-class="scenario-step-response-popover"
|
content-class="scenario-step-response-popover"
|
||||||
|
:disabled="![ScenarioExecuteStatus.SUCCESS, ScenarioExecuteStatus.FAILED].includes(step.executeStatus)"
|
||||||
@popup-visible-change="handleResponsePopoverVisibleChange($event, step)"
|
@popup-visible-change="handleResponsePopoverVisibleChange($event, step)"
|
||||||
>
|
>
|
||||||
<executeStatus :status="getExecuteStatus(step) || step.executeStatus" size="small" />
|
<executeStatus :status="getExecuteStatus(step) || step.executeStatus" size="small" />
|
||||||
|
@ -195,6 +204,11 @@
|
||||||
</responseResult>
|
</responseResult>
|
||||||
</template>
|
</template>
|
||||||
</a-popover>
|
</a-popover>
|
||||||
|
<executeStatus
|
||||||
|
v-else-if="step.executeStatus"
|
||||||
|
:status="getExecuteStatus(step) || step.executeStatus"
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="steps.length === 0 && stepKeyword.trim() !== ''" #empty>
|
<template v-if="steps.length === 0 && stepKeyword.trim() !== ''" #empty>
|
||||||
<div
|
<div
|
||||||
|
@ -220,7 +234,7 @@
|
||||||
:step-responses="scenario.stepResponses"
|
:step-responses="scenario.stepResponses"
|
||||||
@add-step="addCustomApiStep"
|
@add-step="addCustomApiStep"
|
||||||
@apply-step="applyApiStep"
|
@apply-step="applyApiStep"
|
||||||
@stop-debug="handleStopExecute"
|
@stop-debug="handleStopExecute(activeStep)"
|
||||||
@execute="handleApiExecute"
|
@execute="handleApiExecute"
|
||||||
/>
|
/>
|
||||||
<customCaseDrawer
|
<customCaseDrawer
|
||||||
|
@ -693,7 +707,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const websocket = ref<WebSocket>();
|
const websocketMap: Record<string | number, WebSocket> = {};
|
||||||
let temporaryStepReportMap = {}; // 缓存websocket返回的报告内容,避免执行接口后切换场景tab导致报告丢失
|
let temporaryStepReportMap = {}; // 缓存websocket返回的报告内容,避免执行接口后切换场景tab导致报告丢失
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
@ -715,16 +729,16 @@
|
||||||
*/
|
*/
|
||||||
function debugSocket(
|
function debugSocket(
|
||||||
step: ScenarioStepItem,
|
step: ScenarioStepItem,
|
||||||
reportId?: string | number,
|
reportId: string | number,
|
||||||
executeType?: 'localExec' | 'serverExec',
|
executeType?: 'localExec' | 'serverExec',
|
||||||
localExecuteUrl?: string
|
localExecuteUrl?: string
|
||||||
) {
|
) {
|
||||||
websocket.value = getSocket(
|
websocketMap[reportId] = getSocket(
|
||||||
reportId || '',
|
reportId || '',
|
||||||
executeType === 'localExec' ? '/ws/debug' : '',
|
executeType === 'localExec' ? '/ws/debug' : '',
|
||||||
executeType === 'localExec' ? localExecuteUrl : ''
|
executeType === 'localExec' ? localExecuteUrl : ''
|
||||||
);
|
);
|
||||||
websocket.value.addEventListener('message', (event) => {
|
websocketMap[reportId].addEventListener('message', (event) => {
|
||||||
const data = JSON.parse(event.data);
|
const data = JSON.parse(event.data);
|
||||||
if (data.msgType === 'EXEC_RESULT') {
|
if (data.msgType === 'EXEC_RESULT') {
|
||||||
if (step.reportId === data.reportId) {
|
if (step.reportId === data.reportId) {
|
||||||
|
@ -751,7 +765,7 @@
|
||||||
}
|
}
|
||||||
} else if (data.msgType === 'EXEC_END') {
|
} else if (data.msgType === 'EXEC_END') {
|
||||||
// 执行结束,关闭websocket
|
// 执行结束,关闭websocket
|
||||||
websocket.value?.close();
|
websocketMap[reportId].close();
|
||||||
if (step.reportId === data.reportId) {
|
if (step.reportId === data.reportId) {
|
||||||
step.isExecuting = false;
|
step.isExecuting = false;
|
||||||
}
|
}
|
||||||
|
@ -786,7 +800,7 @@
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
websocket.value?.close();
|
websocketMap[executeParams.reportId].close();
|
||||||
currentStep.isExecuting = false;
|
currentStep.isExecuting = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -843,14 +857,43 @@
|
||||||
},
|
},
|
||||||
executeType
|
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() {
|
function handleStopExecute(step?: ScenarioStepItem) {
|
||||||
websocket.value?.close();
|
if (step?.reportId) {
|
||||||
if (activeStep.value) {
|
websocketMap[step.reportId].close();
|
||||||
activeStep.value.isExecuting = false;
|
step.isExecuting = false;
|
||||||
activeStep.value.executeStatus = undefined;
|
step.executeStatus = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,7 @@
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import router from '@/router';
|
import router from '@/router';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
import { filterTree, getGenerateId } from '@/utils';
|
import { filterTree, getGenerateId, mapTree } from '@/utils';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ApiScenarioDebugRequest,
|
ApiScenarioDebugRequest,
|
||||||
|
@ -122,7 +122,7 @@
|
||||||
} from '@/models/apiTest/scenario';
|
} from '@/models/apiTest/scenario';
|
||||||
import { ModuleTreeNode } from '@/models/common';
|
import { ModuleTreeNode } from '@/models/common';
|
||||||
import { EnvConfig } from '@/models/projectManagement/environmental';
|
import { EnvConfig } from '@/models/projectManagement/environmental';
|
||||||
import { ScenarioExecuteStatus } from '@/enums/apiEnum';
|
import { ScenarioExecuteStatus, ScenarioStepType } from '@/enums/apiEnum';
|
||||||
import { ApiTestRouteEnum } from '@/enums/routeEnum';
|
import { ApiTestRouteEnum } from '@/enums/routeEnum';
|
||||||
|
|
||||||
import { defaultScenario } from './components/config';
|
import { defaultScenario } from './components/config';
|
||||||
|
@ -367,6 +367,12 @@
|
||||||
uploadFileIds: activeScenarioTab.value.uploadFileIds,
|
uploadFileIds: activeScenarioTab.value.uploadFileIds,
|
||||||
linkFileIds: activeScenarioTab.value.linkFileIds,
|
linkFileIds: activeScenarioTab.value.linkFileIds,
|
||||||
...executeParams,
|
...executeParams,
|
||||||
|
steps: mapTree(executeParams.steps, (node) => {
|
||||||
|
return {
|
||||||
|
...node,
|
||||||
|
parent: null, // 原树形结构存在循环引用,这里要去掉以免 axios 序列化失败
|
||||||
|
};
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res = await debugScenario({
|
res = await debugScenario({
|
||||||
|
@ -379,6 +385,12 @@
|
||||||
linkFileIds: activeScenarioTab.value.linkFileIds,
|
linkFileIds: activeScenarioTab.value.linkFileIds,
|
||||||
frontendDebug: executeType === 'localExec',
|
frontendDebug: executeType === 'localExec',
|
||||||
...executeParams,
|
...executeParams,
|
||||||
|
steps: mapTree(executeParams.steps, (node) => {
|
||||||
|
return {
|
||||||
|
...node,
|
||||||
|
parent: null, // 原树形结构存在循环引用,这里要去掉以免 axios 序列化失败
|
||||||
|
};
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (executeType === 'localExec' && localExecuteUrl) {
|
if (executeType === 'localExec' && localExecuteUrl) {
|
||||||
|
@ -398,6 +410,12 @@
|
||||||
if (node.enable) {
|
if (node.enable) {
|
||||||
node.executeStatus = ScenarioExecuteStatus.EXECUTING;
|
node.executeStatus = ScenarioExecuteStatus.EXECUTING;
|
||||||
waitingDebugStepDetails[node.id] = activeScenarioTab.value.stepDetails[node.id];
|
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;
|
return !!node.enable;
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue