fix(all): 修复部分 bug
This commit is contained in:
parent
cd57414bd2
commit
8438be13ee
|
@ -95,7 +95,7 @@ export const pathMap: PathMapItem[] = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'API_TEST_MANAGEMENT_RECYCLE', // 接口测试-回收站
|
key: 'API_TEST_MANAGEMENT_RECYCLE', // 接口测试-回收站
|
||||||
locale: 'menu.bugManagement.bugRecycle',
|
locale: 'menu.apiTest.scenario.recycle',
|
||||||
route: RouteEnum.API_TEST_MANAGEMENT_RECYCLE,
|
route: RouteEnum.API_TEST_MANAGEMENT_RECYCLE,
|
||||||
permission: [],
|
permission: [],
|
||||||
level: MENU_LEVEL[2],
|
level: MENU_LEVEL[2],
|
||||||
|
@ -103,15 +103,29 @@ export const pathMap: PathMapItem[] = [
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'API_SCENARIO_MANAGEMENT_SCENARIO', // 接口测试-场景
|
key: 'API_TEST_SCENARIO_MANAGEMENT', // 接口测试-场景
|
||||||
locale: 'menu.apiTest.scenario',
|
locale: 'menu.apiTest.scenario',
|
||||||
route: RouteEnum.API_TEST_SCENARIO,
|
route: RouteEnum.API_TEST_SCENARIO,
|
||||||
permission: [],
|
permission: [],
|
||||||
level: MENU_LEVEL[2],
|
level: MENU_LEVEL[2],
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
key: 'API_TEST_SCENARIO_RECYCLE', // 接口测试-回收站
|
key: 'API_TEST_SCENARIO_MANAGEMENT_SCENARIO', // 接口测试-场景
|
||||||
locale: 'menu.bugManagement.bugRecycle',
|
locale: 'menu.apiTest.scenario',
|
||||||
|
route: RouteEnum.API_TEST_SCENARIO,
|
||||||
|
permission: [],
|
||||||
|
level: MENU_LEVEL[2],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'API_TEST_SCENARIO_MANAGEMENT_MODULE', // 接口测试-场景-模块
|
||||||
|
locale: 'common.module',
|
||||||
|
route: RouteEnum.API_TEST_SCENARIO,
|
||||||
|
permission: [],
|
||||||
|
level: MENU_LEVEL[2],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'API_TEST_SCENARIO_RECYCLE', // 接口测试-场景-回收站
|
||||||
|
locale: 'menu.apiTest.scenario.recycle',
|
||||||
route: RouteEnum.API_TEST_SCENARIO_RECYCLE,
|
route: RouteEnum.API_TEST_SCENARIO_RECYCLE,
|
||||||
permission: [],
|
permission: [],
|
||||||
level: MENU_LEVEL[2],
|
level: MENU_LEVEL[2],
|
||||||
|
|
|
@ -31,6 +31,7 @@ export default {
|
||||||
'menu.apiTest.management': 'API',
|
'menu.apiTest.management': 'API',
|
||||||
'menu.apiTest.management.definition': 'API',
|
'menu.apiTest.management.definition': 'API',
|
||||||
'menu.apiTest.scenario': 'Scenario',
|
'menu.apiTest.scenario': 'Scenario',
|
||||||
|
'menu.apiTest.scenario.recycle': 'Recycle',
|
||||||
'menu.apiTest.report': 'Report',
|
'menu.apiTest.report': 'Report',
|
||||||
'menu.uiTest': 'UI Test',
|
'menu.uiTest': 'UI Test',
|
||||||
'menu.performanceTest': 'Performance Test',
|
'menu.performanceTest': 'Performance Test',
|
||||||
|
|
|
@ -32,6 +32,7 @@ export default {
|
||||||
'menu.apiTest.api': 'API列表',
|
'menu.apiTest.api': 'API列表',
|
||||||
'menu.apiTest.apiScenario': '场景',
|
'menu.apiTest.apiScenario': '场景',
|
||||||
'menu.apiTest.scenario': '场景',
|
'menu.apiTest.scenario': '场景',
|
||||||
|
'menu.apiTest.scenario.recycle': '回收站',
|
||||||
'menu.apiTest.report': '报告',
|
'menu.apiTest.report': '报告',
|
||||||
'menu.uiTest': 'UI测试',
|
'menu.uiTest': 'UI测试',
|
||||||
'menu.workstation': '工作台',
|
'menu.workstation': '工作台',
|
||||||
|
|
|
@ -99,6 +99,7 @@ export default {
|
||||||
'apiTestDebug.storageByResult': 'Store by result',
|
'apiTestDebug.storageByResult': 'Store by result',
|
||||||
'apiTestDebug.storageByResultPlaceholder': 'E.g. {a}; Subsequent use such as {b}',
|
'apiTestDebug.storageByResultPlaceholder': 'E.g. {a}; Subsequent use such as {b}',
|
||||||
'apiTestDebug.extractParameter': 'Extract',
|
'apiTestDebug.extractParameter': 'Extract',
|
||||||
|
'apiTestDebug.sqlExtractParameter': 'Extract values by column',
|
||||||
'apiTestDebug.searchTip': 'Please enter a group name',
|
'apiTestDebug.searchTip': 'Please enter a group name',
|
||||||
'apiTestDebug.allRequest': 'All requests',
|
'apiTestDebug.allRequest': 'All requests',
|
||||||
'apiTestDebug.deleteFolderTipTitle': 'Remove the `{name}` module?',
|
'apiTestDebug.deleteFolderTipTitle': 'Remove the `{name}` module?',
|
||||||
|
|
|
@ -93,6 +93,7 @@ export default {
|
||||||
'apiTestDebug.storageByResult': '按结果存储',
|
'apiTestDebug.storageByResult': '按结果存储',
|
||||||
'apiTestDebug.storageByResultPlaceholder': '如 {a}; 后续使用如{b}',
|
'apiTestDebug.storageByResultPlaceholder': '如 {a}; 后续使用如{b}',
|
||||||
'apiTestDebug.extractParameter': '提取参数',
|
'apiTestDebug.extractParameter': '提取参数',
|
||||||
|
'apiTestDebug.sqlExtractParameter': '按列提取值',
|
||||||
'apiTestDebug.searchTip': '请输入模块/请求名称',
|
'apiTestDebug.searchTip': '请输入模块/请求名称',
|
||||||
'apiTestDebug.allRequest': '全部请求',
|
'apiTestDebug.allRequest': '全部请求',
|
||||||
'apiTestDebug.deleteFolderTipTitle': '是否删除 {name} 模块?',
|
'apiTestDebug.deleteFolderTipTitle': '是否删除 {name} 模块?',
|
||||||
|
|
|
@ -184,9 +184,9 @@
|
||||||
:max-length="255"
|
:max-length="255"
|
||||||
class="flex-1"
|
class="flex-1"
|
||||||
></a-input>
|
></a-input>
|
||||||
<MsButton type="text" @click="taskDrawerVisible = true">{{
|
<MsButton type="text" @click="taskDrawerVisible = true">
|
||||||
t('apiTestManagement.timeTaskList')
|
{{ t('apiTestManagement.timeTaskList') }}
|
||||||
}}</MsButton>
|
</MsButton>
|
||||||
</div>
|
</div>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item
|
<a-form-item
|
||||||
|
@ -501,6 +501,11 @@
|
||||||
name: importForm.value.name,
|
name: importForm.value.name,
|
||||||
});
|
});
|
||||||
Message.success(t('apiTestManagement.createTaskSuccess'));
|
Message.success(t('apiTestManagement.createTaskSuccess'));
|
||||||
|
importForm.value = { ...defaultForm };
|
||||||
|
importFormRef.value?.resetFields();
|
||||||
|
importType.value = 'time';
|
||||||
|
fileList.value = [];
|
||||||
|
moreSettingActive.value = [];
|
||||||
taskDrawerVisible.value = true;
|
taskDrawerVisible.value = true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
|
|
|
@ -14,6 +14,7 @@ export default {
|
||||||
'apiTestManagement.disableTaskSuccess': 'Closing the scheduled import task successfully',
|
'apiTestManagement.disableTaskSuccess': 'Closing the scheduled import task successfully',
|
||||||
'apiTestManagement.addSubModule': 'Add submodule',
|
'apiTestManagement.addSubModule': 'Add submodule',
|
||||||
'apiTestManagement.allApi': 'All api',
|
'apiTestManagement.allApi': 'All api',
|
||||||
|
'apiTestManagement.allCase': 'All case',
|
||||||
'apiTestManagement.searchTip': 'Please enter module/api name',
|
'apiTestManagement.searchTip': 'Please enter module/api name',
|
||||||
'apiTestManagement.moveSearchTip': 'Please enter the module name to search',
|
'apiTestManagement.moveSearchTip': 'Please enter the module name to search',
|
||||||
'apiTestManagement.noMatchModule': 'No matching module/api yet',
|
'apiTestManagement.noMatchModule': 'No matching module/api yet',
|
||||||
|
|
|
@ -14,6 +14,7 @@ export default {
|
||||||
'apiTestManagement.disableTaskSuccess': '关闭定时导入任务成功',
|
'apiTestManagement.disableTaskSuccess': '关闭定时导入任务成功',
|
||||||
'apiTestManagement.addSubModule': '添加子模块',
|
'apiTestManagement.addSubModule': '添加子模块',
|
||||||
'apiTestManagement.allApi': '全部接口',
|
'apiTestManagement.allApi': '全部接口',
|
||||||
|
'apiTestManagement.allCase': '全部用例',
|
||||||
'apiTestManagement.searchTip': '请输入模块/接口名称',
|
'apiTestManagement.searchTip': '请输入模块/接口名称',
|
||||||
'apiTestManagement.moveSearchTip': '请输入模块名称搜索',
|
'apiTestManagement.moveSearchTip': '请输入模块名称搜索',
|
||||||
'apiTestManagement.noMatchModule': '暂无匹配的模块/接口',
|
'apiTestManagement.noMatchModule': '暂无匹配的模块/接口',
|
||||||
|
|
|
@ -178,7 +178,6 @@
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
import { cloneDeep } from 'lodash-es';
|
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="mb-[12px] flex items-center gap-[8px]">
|
<div class="mb-[8px] flex items-center gap-[8px]">
|
||||||
<a-input v-model:model-value="moduleKeyword" :placeholder="t('apiScenario.quoteTreeSearchTip')" allow-clear />
|
<a-input v-model:model-value="moduleKeyword" :placeholder="t('apiScenario.quoteTreeSearchTip')" allow-clear />
|
||||||
<a-tooltip :content="isExpandAll ? t('apiScenario.collapseAll') : t('apiScenario.expandAllStep')">
|
<a-tooltip :content="isExpandAll ? t('apiScenario.collapseAll') : t('apiScenario.expandAllStep')">
|
||||||
<a-button
|
<a-button
|
||||||
|
@ -13,6 +13,14 @@
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="folder" @click="setActiveFolder('all')">
|
||||||
|
<div :class="allFolderClass">
|
||||||
|
<MsIcon type="icon-icon_folder_filled1" class="folder-icon" />
|
||||||
|
<div class="folder-name">{{ folderText }}</div>
|
||||||
|
<div class="folder-count">({{ allScenarioCount }})</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a-divider class="my-[8px]" />
|
||||||
<a-spin class="w-full" :loading="loading">
|
<a-spin class="w-full" :loading="loading">
|
||||||
<MsTree
|
<MsTree
|
||||||
v-model:selected-keys="selectedKeys"
|
v-model:selected-keys="selectedKeys"
|
||||||
|
@ -85,6 +93,26 @@
|
||||||
const isExpandAll = ref(false);
|
const isExpandAll = ref(false);
|
||||||
const moduleCountMap = ref<Record<string, number>>({});
|
const moduleCountMap = ref<Record<string, number>>({});
|
||||||
const selectedKeys = ref<string[]>([]);
|
const selectedKeys = ref<string[]>([]);
|
||||||
|
const folderText = computed(() => {
|
||||||
|
if (props.type === 'api') {
|
||||||
|
return t('apiTestManagement.allApi');
|
||||||
|
}
|
||||||
|
if (props.type === 'case') {
|
||||||
|
return t('apiTestManagement.allCase');
|
||||||
|
}
|
||||||
|
if (props.type === 'scenario') {
|
||||||
|
return t('apiScenario.tree.folder.allScenario');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const allScenarioCount = computed(() => moduleCountMap.value.all || 0);
|
||||||
|
const allFolderClass = computed(() =>
|
||||||
|
selectedKeys.value[0] === 'all' ? 'folder-text folder-text--active' : 'folder-text'
|
||||||
|
);
|
||||||
|
|
||||||
|
function setActiveFolder(id: string) {
|
||||||
|
selectedKeys.value = [id];
|
||||||
|
emit('select', [], { id, name: folderText.value });
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化模块树
|
* 初始化模块树
|
||||||
|
@ -104,8 +132,7 @@
|
||||||
} else if (type === 'scenario') {
|
} else if (type === 'scenario') {
|
||||||
folderTree.value = await getScenarioModuleTree(params);
|
folderTree.value = await getScenarioModuleTree(params);
|
||||||
}
|
}
|
||||||
selectedKeys.value = [folderTree.value[0]?.id];
|
setActiveFolder('all');
|
||||||
emit('select', [folderTree.value[0]?.id], folderTree.value[0]);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
@ -154,6 +181,36 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
.folder {
|
||||||
|
@apply flex cursor-pointer items-center justify-between;
|
||||||
|
|
||||||
|
padding: 8px 4px;
|
||||||
|
border-radius: var(--border-radius-small);
|
||||||
|
&:hover {
|
||||||
|
background-color: rgb(var(--primary-1));
|
||||||
|
}
|
||||||
|
.folder-text {
|
||||||
|
@apply flex flex-1 cursor-pointer items-center;
|
||||||
|
.folder-icon {
|
||||||
|
margin-right: 4px;
|
||||||
|
color: var(--color-text-4);
|
||||||
|
}
|
||||||
|
.folder-name {
|
||||||
|
color: var(--color-text-1);
|
||||||
|
}
|
||||||
|
.folder-count {
|
||||||
|
margin-left: 4px;
|
||||||
|
color: var(--color-text-4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.folder-text--active {
|
||||||
|
.folder-icon,
|
||||||
|
.folder-name,
|
||||||
|
.folder-count {
|
||||||
|
color: rgb(var(--primary-5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.expand-btn {
|
.expand-btn {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
.arco-icon {
|
.arco-icon {
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
:page-size="1"
|
:page-size="1"
|
||||||
:total="props.loopTotal"
|
:total="props.loopTotal"
|
||||||
:show-jumper="props.loopTotal > 5"
|
:show-jumper="props.loopTotal > 5"
|
||||||
|
:base-size="Infinity"
|
||||||
show-total
|
show-total
|
||||||
size="mini"
|
size="mini"
|
||||||
class="loop-pagination"
|
class="loop-pagination"
|
||||||
|
|
|
@ -60,7 +60,11 @@
|
||||||
<div class="text-[var(--color-text-1)]">{{ t('common.fail') }}</div>
|
<div class="text-[var(--color-text-1)]">{{ t('common.fail') }}</div>
|
||||||
<div class="text-[rgb(var(--success-6))]">{{ scenario.executeFailCount }}</div>
|
<div class="text-[rgb(var(--success-6))]">{{ scenario.executeFailCount }}</div>
|
||||||
</div>
|
</div>
|
||||||
<MsButton v-if="scenario.isDebug === false && !scenario.executeLoading" type="text" @click="checkReport">
|
<MsButton
|
||||||
|
v-if="scenario.isDebug === false && !scenario.executeLoading && !scenario.isNew"
|
||||||
|
type="text"
|
||||||
|
@click="checkReport"
|
||||||
|
>
|
||||||
{{ t('apiScenario.checkReport') }}
|
{{ t('apiScenario.checkReport') }}
|
||||||
</MsButton>
|
</MsButton>
|
||||||
</div>
|
</div>
|
||||||
|
@ -267,6 +271,7 @@
|
||||||
|
|
||||||
function checkReport() {
|
function checkReport() {
|
||||||
openNewPage(ApiTestRouteEnum.API_TEST_REPORT, {
|
openNewPage(ApiTestRouteEnum.API_TEST_REPORT, {
|
||||||
|
type: 'API_SCENARIO',
|
||||||
reportId: scenario.value.reportId,
|
reportId: scenario.value.reportId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1203,9 +1203,12 @@
|
||||||
|
|
||||||
function handleStopExecute(step?: ScenarioStepItem) {
|
function handleStopExecute(step?: ScenarioStepItem) {
|
||||||
if (step?.reportId) {
|
if (step?.reportId) {
|
||||||
|
const realStep = findNodeByKey<ScenarioStepItem>(steps.value, step.uniqueId, 'uniqueId');
|
||||||
websocketMap[step.reportId].close();
|
websocketMap[step.reportId].close();
|
||||||
step.isExecuting = false;
|
if (realStep) {
|
||||||
step.executeStatus = undefined;
|
realStep.isExecuting = false;
|
||||||
|
updateStepStatus([realStep as ScenarioStepItem], scenario.value.stepResponses);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -311,6 +311,19 @@
|
||||||
setStepExecuteStatus(activeScenarioTab.value);
|
setStepExecuteStatus(activeScenarioTab.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const folderTree = ref<ModuleTreeNode[]>([]);
|
||||||
|
const folderTreePathMap = ref<Record<string, any>>({});
|
||||||
|
const activeModule = ref<string>('all');
|
||||||
|
const activeFolder = ref<string>('all');
|
||||||
|
const offspringIds = ref<string[]>([]);
|
||||||
|
const isShowScenario = ref(false);
|
||||||
|
|
||||||
|
// 获取激活用例类型样式
|
||||||
|
const getActiveClass = (type: string) => {
|
||||||
|
return activeFolder.value === type ? 'folder-text case-active' : 'folder-text';
|
||||||
|
};
|
||||||
|
const recycleModulesCount = ref(0);
|
||||||
|
|
||||||
function newTab(defaultScenarioInfo?: Scenario, action?: 'copy' | 'execute') {
|
function newTab(defaultScenarioInfo?: Scenario, action?: 'copy' | 'execute') {
|
||||||
if (defaultScenarioInfo) {
|
if (defaultScenarioInfo) {
|
||||||
const isCopy = action === 'copy';
|
const isCopy = action === 'copy';
|
||||||
|
@ -382,7 +395,7 @@
|
||||||
...cloneDeep(defaultScenario),
|
...cloneDeep(defaultScenario),
|
||||||
id: getGenerateId(),
|
id: getGenerateId(),
|
||||||
label: `${t('apiScenario.createScenario')}${scenarioTabs.value.length}`,
|
label: `${t('apiScenario.createScenario')}${scenarioTabs.value.length}`,
|
||||||
moduleId: 'root',
|
moduleId: activeModule.value === 'all' ? 'root' : activeModule.value,
|
||||||
projectId: appStore.currentProjectId,
|
projectId: appStore.currentProjectId,
|
||||||
priority: 'P0',
|
priority: 'P0',
|
||||||
});
|
});
|
||||||
|
@ -390,19 +403,6 @@
|
||||||
activeScenarioTab.value = scenarioTabs.value[scenarioTabs.value.length - 1] as ScenarioParams;
|
activeScenarioTab.value = scenarioTabs.value[scenarioTabs.value.length - 1] as ScenarioParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
const folderTree = ref<ModuleTreeNode[]>([]);
|
|
||||||
const folderTreePathMap = ref<Record<string, any>>({});
|
|
||||||
const activeModule = ref<string>('all');
|
|
||||||
const activeFolder = ref<string>('all');
|
|
||||||
const offspringIds = ref<string[]>([]);
|
|
||||||
const isShowScenario = ref(false);
|
|
||||||
|
|
||||||
// 获取激活用例类型样式
|
|
||||||
const getActiveClass = (type: string) => {
|
|
||||||
return activeFolder.value === type ? 'folder-text case-active' : 'folder-text';
|
|
||||||
};
|
|
||||||
const recycleModulesCount = ref(0);
|
|
||||||
|
|
||||||
const scenarioModuleTreeRef = ref<InstanceType<typeof scenarioModuleTree>>();
|
const scenarioModuleTreeRef = ref<InstanceType<typeof scenarioModuleTree>>();
|
||||||
|
|
||||||
function handleModuleInit(tree: any, _protocol: string, pathMap: Record<string, any>) {
|
function handleModuleInit(tree: any, _protocol: string, pathMap: Record<string, any>) {
|
||||||
|
|
Loading…
Reference in New Issue