refactor(接口场景): 场景执行状态优化&部分表格筛选状态初始化为空

This commit is contained in:
baiqi 2024-03-28 18:25:12 +08:00 committed by Craftsman
parent 7fe24a0d27
commit 9f67d9fb6b
27 changed files with 371 additions and 263 deletions

View File

@ -185,8 +185,8 @@ export function calculateMaxDepth(arr?: Node[], depth = 0) {
} }
export interface TreeNode<T> { export interface TreeNode<T> {
[key: string]: any;
children?: TreeNode<T>[]; children?: TreeNode<T>[];
[key: string]: any;
} }
/** /**

View File

@ -504,9 +504,9 @@
]; ];
const methodFilterVisible = ref(false); const methodFilterVisible = ref(false);
const methodFilters = ref(Object.keys(RequestMethods)); const methodFilters = ref<string[]>([]);
const statusFilterVisible = ref(false); const statusFilterVisible = ref(false);
const statusFilters = ref(Object.keys(RequestDefinitionStatus)); const statusFilters = ref<string[]>([]);
const tableStore = useTableStore(); const tableStore = useTableStore();
async function getModuleIds() { async function getModuleIds() {
@ -529,9 +529,8 @@
moduleIds, moduleIds,
protocol: props.protocol, protocol: props.protocol,
filter: { filter: {
status: status: statusFilters.value,
statusFilters.value.length === Object.keys(RequestDefinitionStatus).length ? undefined : statusFilters.value, method: methodFilters.value,
method: methodFilters.value.length === Object.keys(RequestMethods).length ? undefined : methodFilters.value,
}, },
}; };
setLoadListParams(params); setLoadListParams(params);

View File

@ -560,7 +560,7 @@
]; ];
const statusFilterVisible = ref(false); const statusFilterVisible = ref(false);
const statusFilters = ref(Object.keys(RequestDefinitionStatus)); const statusFilters = ref<string[]>([]);
const caseLevelFields = ref<Record<string, any>>({}); const caseLevelFields = ref<Record<string, any>>({});
const caseFilterVisible = ref(false); const caseFilterVisible = ref(false);
const caseFilters = ref<string[]>([]); const caseFilters = ref<string[]>([]);
@ -571,7 +571,7 @@
const lastReportStatusList = computed(() => { const lastReportStatusList = computed(() => {
return Object.keys(ReportStatus[ReportEnum.API_REPORT]); return Object.keys(ReportStatus[ReportEnum.API_REPORT]);
}); });
const lastReportStatusFilters = ref<string[]>(Object.keys(ReportStatus[ReportEnum.API_REPORT])); const lastReportStatusFilters = ref<string[]>([]);
async function getModuleIds() { async function getModuleIds() {
let moduleIds: string[] = []; let moduleIds: string[] = [];

View File

@ -118,10 +118,10 @@
import { ApiCaseExecuteHistoryItem } from '@/models/apiTest/management'; import { ApiCaseExecuteHistoryItem } from '@/models/apiTest/management';
import { ReportEnum, ReportStatus, TriggerModeLabel } from '@/enums/reportEnum'; import { ReportEnum, ReportStatus, TriggerModeLabel } from '@/enums/reportEnum';
const triggerModeListFilters = ref<string[]>(Object.keys(TriggerModeLabel)); const triggerModeListFilters = ref<string[]>();
const triggerModeFilterVisible = ref(false); const triggerModeFilterVisible = ref(false);
const statusFilterVisible = ref(false); const statusFilterVisible = ref(false);
const statusFilters = ref<string[]>(Object.keys(ReportStatus[ReportEnum.API_REPORT])); const statusFilters = ref<string[]>();
const statusList = computed(() => { const statusList = computed(() => {
return Object.keys(ReportStatus[ReportEnum.API_REPORT]); return Object.keys(ReportStatus[ReportEnum.API_REPORT]);
}); });

View File

@ -256,9 +256,9 @@
}; };
const methodFilterVisible = ref(false); const methodFilterVisible = ref(false);
const methodFilters = ref(Object.keys(RequestMethods)); const methodFilters = ref<string[]>([]);
const statusFilterVisible = ref(false); const statusFilterVisible = ref(false);
const statusFilters = ref(Object.keys(RequestDefinitionStatus)); const statusFilters = ref<string[]>([]);
const moduleIds = computed(() => { const moduleIds = computed(() => {
if (props.activeModule === 'all') { if (props.activeModule === 'all') {
return []; return [];

View File

@ -366,7 +366,7 @@
}; };
const statusFilterVisible = ref(false); const statusFilterVisible = ref(false);
const statusFilters = ref(Object.keys(RequestDefinitionStatus)); const statusFilters = ref<string[]>([]);
const caseLevelFields = ref<Record<string, any>>({}); const caseLevelFields = ref<Record<string, any>>({});
const caseFilterVisible = ref(false); const caseFilterVisible = ref(false);
const caseFilters = ref<string[]>([]); const caseFilters = ref<string[]>([]);
@ -375,7 +375,7 @@
}); });
const lastReportStatusFilterVisible = ref(false); const lastReportStatusFilterVisible = ref(false);
const lastReportStatusList = ['error', 'FakeError', 'success']; const lastReportStatusList = ['error', 'FakeError', 'success'];
const lastReportStatusFilters = ref<string[]>([...lastReportStatusList]); const lastReportStatusFilters = ref<string[]>([]);
const moduleIds = computed(() => { const moduleIds = computed(() => {
return props.activeModule === 'all' ? [] : [props.activeModule]; return props.activeModule === 'all' ? [] : [props.activeModule];

View File

@ -174,8 +174,8 @@
const statusFilterVisible = ref(false); const statusFilterVisible = ref(false);
const triggerModeFilterVisible = ref(false); const triggerModeFilterVisible = ref(false);
const statusListFilters = ref<string[]>(Object.keys(ReportStatus[props.moduleType])); const statusListFilters = ref<string[]>([]);
const triggerModeListFilters = ref<string[]>(Object.keys(TriggerModeLabel)); const triggerModeListFilters = ref<string[]>([]);
type ReportShowType = 'All' | 'INDEPENDENT' | 'INTEGRATED'; type ReportShowType = 'All' | 'INDEPENDENT' | 'INTEGRATED';
const showType = ref<ReportShowType>('All'); const showType = ref<ReportShowType>('All');
@ -287,7 +287,7 @@
moduleType: props.moduleType, moduleType: props.moduleType,
filter: { filter: {
status: statusListFilters.value, status: statusListFilters.value,
integrated: showType.value === 'All' ? undefined : Array.of((showType.value === 'INTEGRATED').toString()), integrated: Array.of((showType.value === 'INTEGRATED').toString()),
triggerMode: triggerModeListFilters.value, triggerMode: triggerModeListFilters.value,
}, },
}); });

View File

@ -10,13 +10,13 @@
@close="handleClose" @close="handleClose"
> >
<template #title> <template #title>
<div class="flex items-center gap-[8px]"> <div class="flex max-w-[60%] items-center gap-[8px]">
<stepTypeVue <stepTypeVue v-if="props.step" :step="props.step" />
v-if="props.step" <a-tooltip :content="title" position="bottom">
v-show="props.step.stepType !== ScenarioStepType.CUSTOM_REQUEST" <div class="one-line-text">
:step="props.step" {{ title }}
/> </div>
{{ title }} </a-tooltip>
</div> </div>
<div <div
v-if="!props.step || props.step?.stepType === ScenarioStepType.CUSTOM_REQUEST" v-if="!props.step || props.step?.stepType === ScenarioStepType.CUSTOM_REQUEST"
@ -475,7 +475,7 @@
if (_stepType.value.isCopyApi || _stepType.value.isQuoteApi) { if (_stepType.value.isCopyApi || _stepType.value.isQuoteApi) {
return props.step?.name; return props.step?.name;
} }
return t('apiScenario.customApi'); return props.step?.name || t('apiScenario.customApi');
}); });
const showEnvPrefix = computed( const showEnvPrefix = computed(
() => () =>

View File

@ -24,7 +24,7 @@
<div v-show="!isShowEditStepNameInput" class="flex flex-1 items-center justify-between"> <div v-show="!isShowEditStepNameInput" class="flex flex-1 items-center justify-between">
<div class="flex items-center gap-[8px]"> <div class="flex items-center gap-[8px]">
<a-tooltip :content="activeStep?.name"> <a-tooltip :content="activeStep?.name">
<span> {{ characterLimit(activeStep?.name) }}</span> <div class="one-line-text max-w-[300px]"> {{ characterLimit(activeStep?.name) }}</div>
</a-tooltip> </a-tooltip>
<MsIcon type="icon-icon_edit_outlined" class="edit-script-name-icon" @click="showEditScriptNameInput" /> <MsIcon type="icon-icon_edit_outlined" class="edit-script-name-icon" @click="showEditScriptNameInput" />
</div> </div>

View File

@ -38,8 +38,8 @@
text: 'common.success', text: 'common.success',
}, },
[ScenarioExecuteStatus.UN_EXECUTE]: { [ScenarioExecuteStatus.UN_EXECUTE]: {
bgColor: 'var(--color-text-4)', bgColor: 'var(--color-text-n8)',
color: 'var(--color-text-n9)', color: 'var(--color-text-1)',
text: 'apiScenario.unExecute', text: 'apiScenario.unExecute',
}, },
}; };

View File

@ -259,9 +259,9 @@
}); });
const methodFilterVisible = ref(false); const methodFilterVisible = ref(false);
const methodFilters = ref(Object.keys(RequestMethods)); const methodFilters = ref<string[]>([]);
const statusFilterVisible = ref(false); const statusFilterVisible = ref(false);
const statusFilters = ref(Object.keys(RequestDefinitionStatus)); const statusFilters = ref<string[]>([]);
const tableSelectedData = ref<MsTableDataItem<ApiCaseDetail | ApiDefinitionDetail | ApiScenarioTableItem>[]>([]); const tableSelectedData = ref<MsTableDataItem<ApiCaseDetail | ApiDefinitionDetail | ApiScenarioTableItem>[]>([]);
const tableSelectedKeys = computed(() => { const tableSelectedKeys = computed(() => {
return tableSelectedData.value.map((e) => e.id); return tableSelectedData.value.map((e) => e.id);
@ -332,11 +332,8 @@
moduleIds: ids || props.moduleIds, moduleIds: ids || props.moduleIds,
protocol: props.protocol, protocol: props.protocol,
filter: { filter: {
status: status: statusFilters.value,
statusFilters.value.length === Object.keys(RequestDefinitionStatus).length method: methodFilters.value,
? undefined
: statusFilters.value,
method: methodFilters.value.length === Object.keys(RequestMethods).length ? undefined : methodFilters.value,
}, },
}); });
currentTable.value.loadList(); currentTable.value.loadList();
@ -377,8 +374,8 @@
function resetTable() { function resetTable() {
currentTable.value.resetSelector(); currentTable.value.resetSelector();
keyword.value = ''; keyword.value = '';
methodFilters.value = Object.keys(RequestMethods); methodFilters.value = [];
statusFilters.value = Object.keys(RequestDefinitionStatus); statusFilters.value = [];
loadPage(); loadPage();
} }

View File

@ -101,10 +101,10 @@
import { ExecuteStatusFilters } from '@/enums/apiEnum'; import { ExecuteStatusFilters } from '@/enums/apiEnum';
import { TriggerModeLabel } from '@/enums/reportEnum'; import { TriggerModeLabel } from '@/enums/reportEnum';
const triggerModeListFilters = ref<string[]>(Object.keys(TriggerModeLabel)); const triggerModeListFilters = ref<string[]>([]);
const triggerModeFilterVisible = ref(false); const triggerModeFilterVisible = ref(false);
const statusFilterVisible = ref(false); const statusFilterVisible = ref(false);
const statusFilters = ref(Object.keys(ExecuteStatusFilters)); const statusFilters = ref<string[]>([]);
const tableQueryParams = ref<any>(); const tableQueryParams = ref<any>();
const keyword = ref(''); const keyword = ref('');

View File

@ -368,7 +368,7 @@
}>(); }>();
const lastReportStatusFilterVisible = ref(false); const lastReportStatusFilterVisible = ref(false);
const lastReportStatusListFilters = ref<string[]>(Object.keys(ReportStatus[ReportEnum.API_SCENARIO_REPORT])); const lastReportStatusListFilters = ref<string[]>([]);
const lastReportStatusFilters = computed(() => { const lastReportStatusFilters = computed(() => {
return Object.keys(ReportStatus[ReportEnum.API_SCENARIO_REPORT]); return Object.keys(ReportStatus[ReportEnum.API_SCENARIO_REPORT]);
}); });
@ -586,7 +586,7 @@
]; ];
const statusFilterVisible = ref(false); const statusFilterVisible = ref(false);
const statusFilters = ref(Object.keys(ApiScenarioStatus)); const statusFilters = ref<string[]>([]);
const tableStore = useTableStore(); const tableStore = useTableStore();
const activeModules = computed(() => { const activeModules = computed(() => {
@ -621,7 +621,7 @@
moduleIds, moduleIds,
filter: { filter: {
lastReportStatus: lastReportStatusListFilters.value, lastReportStatus: lastReportStatusListFilters.value,
status: statusFilters.value.length === Object.keys(ApiScenarioStatus).length ? undefined : statusFilters.value, status: statusFilters.value,
}, },
}; };
setLoadListParams(params); setLoadListParams(params);

View File

@ -168,18 +168,30 @@
stepTreeRef.value?.checkAll(checkedAll.value); stepTreeRef.value?.checkAll(checkedAll.value);
} }
watch(checkedKeys, (val) => { watch(
if (val.length === 0) { () => checkedKeys.value,
checkedAll.value = false; (val) => {
indeterminate.value = false; if (val.length === 0) {
} else if (val.length === totalStepCount.value) { checkedAll.value = false;
checkedAll.value = true; indeterminate.value = false;
indeterminate.value = false; } else if (val.length === totalStepCount.value) {
} else { checkedAll.value = true;
checkedAll.value = false; indeterminate.value = false;
indeterminate.value = true; } else {
checkedAll.value = false;
indeterminate.value = true;
}
} }
}); );
watch(
() => scenario.value.steps.length,
() => {
checkedKeys.value = [];
checkedAll.value = false;
indeterminate.value = false;
}
);
function expandAllStep() { function expandAllStep() {
isExpandAll.value = !isExpandAll.value; isExpandAll.value = !isExpandAll.value;
@ -259,14 +271,19 @@
if (!node.enable) { if (!node.enable) {
// id便waitingDebugStepDetails // id便waitingDebugStepDetails
checkedKeysSet.delete(node.id); checkedKeysSet.delete(node.id);
node.executeStatus = undefined;
} else if ( } else if (
[ScenarioStepType.API, ScenarioStepType.API_CASE, ScenarioStepType.CUSTOM_REQUEST].includes(node.stepType) [ScenarioStepType.API, ScenarioStepType.API_CASE, ScenarioStepType.CUSTOM_REQUEST].includes(node.stepType)
) { ) {
// //
node.executeStatus = ScenarioExecuteStatus.EXECUTING; node.executeStatus = ScenarioExecuteStatus.EXECUTING;
} else {
//
node.executeStatus = undefined;
} }
return !!node.enable; return !!node.enable;
} }
node.executeStatus = undefined; //
return false; return false;
}); });
const waitingDebugStepDetails = {}; const waitingDebugStepDetails = {};

View File

@ -179,8 +179,14 @@
<template #extraEnd="step"> <template #extraEnd="step">
<a-popover <a-popover
v-if=" v-if="
getExecuteStatus(step) === ScenarioExecuteStatus.SUCCESS || ![
getExecuteStatus(step) === ScenarioExecuteStatus.FAILED ScenarioStepType.LOOP_CONTROLLER,
ScenarioStepType.IF_CONTROLLER,
ScenarioStepType.ONCE_ONLY_CONTROLLER,
ScenarioStepType.CONSTANT_TIMER,
].includes(step.stepType) &&
(getExecuteStatus(step) === ScenarioExecuteStatus.SUCCESS ||
getExecuteStatus(step) === ScenarioExecuteStatus.FAILED)
" "
position="br" position="br"
content-class="scenario-step-response-popover" content-class="scenario-step-response-popover"

View File

@ -0,0 +1,66 @@
import { RequestResult } from '@/models/apiTest/common';
import { ScenarioStepItem } from '@/models/apiTest/scenario';
import { ScenarioExecuteStatus, ScenarioStepType } from '@/enums/apiEnum';
/**
*
* @param steps
*/
export default function updateStepStatus(
steps: ScenarioStepItem[],
stepResponses: Record<string | number, RequestResult>
) {
for (let i = 0; i < steps.length; i++) {
const node = steps[i];
if (
[
ScenarioStepType.LOOP_CONTROLLER,
ScenarioStepType.IF_CONTROLLER,
ScenarioStepType.ONCE_ONLY_CONTROLLER,
].includes(node.stepType)
) {
// 逻辑控制器内部可以放入任意步骤,所以它的最终执行结果是根据内部步骤的执行结果来判断的
let hasNotExecuted = false;
let hasFailure = false;
if (!node.children || node.children.length === 0) {
// 逻辑控制器内无步骤,则直接是未执行
node.executeStatus = ScenarioExecuteStatus.UN_EXECUTE;
} else {
for (let j = 0; j < node.children.length; j++) {
const childNode = node.children[j];
updateStepStatus([childNode], stepResponses);
if (
childNode.executeStatus &&
[ScenarioExecuteStatus.EXECUTING, ScenarioExecuteStatus.UN_EXECUTE].includes(childNode.executeStatus)
) {
// 子节点未执行或正在执行,则逻辑控制器也是未执行
hasNotExecuted = true;
} else if (childNode.executeStatus === ScenarioExecuteStatus.FAILED) {
// 子节点有一个失败,逻辑控制器就是失败
hasFailure = true;
}
}
// 递归完子节点后,判断当前逻辑控制器的状态
if (hasFailure) {
node.executeStatus = ScenarioExecuteStatus.FAILED;
} else if (hasNotExecuted) {
node.executeStatus = ScenarioExecuteStatus.UN_EXECUTE;
} else {
node.executeStatus = ScenarioExecuteStatus.SUCCESS;
}
}
} else if (node.stepType === ScenarioStepType.CONSTANT_TIMER) {
// 等待时间直接设置为成功
node.executeStatus = ScenarioExecuteStatus.SUCCESS;
} else if (node.executeStatus === ScenarioExecuteStatus.EXECUTING) {
// 非逻辑控制器直接更改本身状态
if (stepResponses[node.id]) {
node.executeStatus = stepResponses[node.id].isSuccessful
? ScenarioExecuteStatus.SUCCESS
: ScenarioExecuteStatus.FAILED;
} else {
node.executeStatus = ScenarioExecuteStatus.UN_EXECUTE;
}
}
}
}

View File

@ -15,7 +15,7 @@
</a-tooltip> </a-tooltip>
</template> </template>
</MsEditableTab> </MsEditableTab>
<div v-if="activeScenarioTab.id !== 'all'" class="flex items-center gap-[8px]"> <div v-show="activeScenarioTab.id !== 'all'" class="flex items-center gap-[8px]">
<environmentSelect v-model:current-env-config="currentEnvConfig" /> <environmentSelect v-model:current-env-config="currentEnvConfig" />
<a-button type="primary" :loading="saveLoading" @click="saveScenario"> <a-button type="primary" :loading="saveLoading" @click="saveScenario">
{{ t('common.save') }} {{ t('common.save') }}
@ -124,10 +124,11 @@
} 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, ScenarioStepRefType, ScenarioStepType } 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';
import updateStepStatus from './components/utils';
// //
const detail = defineAsyncComponent(() => import('./detail/index.vue')); const detail = defineAsyncComponent(() => import('./detail/index.vue'));
@ -147,11 +148,215 @@
} as ScenarioParams, } as ScenarioParams,
]); ]);
const activeScenarioTab = ref<ScenarioParams>(scenarioTabs.value[0] as ScenarioParams); const activeScenarioTab = ref<ScenarioParams>(scenarioTabs.value[0] as ScenarioParams);
const currentEnvConfig = ref<EnvConfig>();
const executeButtonRef = ref<InstanceType<typeof executeButton>>();
const websocket = ref<WebSocket>();
const temporaryScenarioReportMap = {}; // websockettab
function setStepExecuteStatus() {
updateStepStatus(activeScenarioTab.value.steps, activeScenarioTab.value.stepResponses);
// activeScenarioTab.value.steps = mapTree<ScenarioStepItem>(activeScenarioTab.value.steps, (step) => {
// if (step.executeStatus === ScenarioExecuteStatus.EXECUTING) {
// //
// step.executeStatus = ScenarioExecuteStatus.UN_EXECUTE;
// }
// return step;
// });
}
/**
* 开启websocket监听接收执行结果
*/
function debugSocket(reportId?: string | number, executeType?: 'localExec' | 'serverExec', localExecuteUrl?: string) {
websocket.value = getSocket(
reportId || '',
executeType === 'localExec' ? '/ws/debug' : '',
executeType === 'localExec' ? localExecuteUrl : ''
);
websocket.value.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.msgType === 'EXEC_RESULT') {
if (activeScenarioTab.value.reportId === data.reportId) {
// tabtab
data.taskResult.requestResults.forEach((result) => {
activeScenarioTab.value.stepResponses[result.stepId] = {
...result,
console: data.taskResult.console,
};
if (result.isSuccessful) {
activeScenarioTab.value.executeSuccessCount += 1;
} else {
activeScenarioTab.value.executeFailCount += 1;
}
});
} else {
// tab
data.taskResult.requestResults.forEach((result) => {
if (activeScenarioTab.value.reportId) {
if (temporaryScenarioReportMap[activeScenarioTab.value.reportId] === undefined) {
temporaryScenarioReportMap[activeScenarioTab.value.reportId] = {};
}
temporaryScenarioReportMap[activeScenarioTab.value.reportId][result.stepId] = {
...result,
console: data.taskResult.console,
};
}
});
}
} else if (data.msgType === 'EXEC_END') {
// websocket
websocket.value?.close();
if (activeScenarioTab.value.reportId === data.reportId) {
activeScenarioTab.value.executeLoading = false;
activeScenarioTab.value.isExecute = false;
setStepExecuteStatus();
}
}
});
}
/**
* 实际执行函数
* @param executeParams 执行参数
* @param isExecute 是否执行否则是调试
* @param executeType 执行类型
* @param localExecuteUrl 本地执行地址
*/
async function realExecute(
executeParams: Pick<ApiScenarioDebugRequest, 'steps' | 'stepDetails' | 'reportId'>,
isExecute?: boolean,
executeType?: 'localExec' | 'serverExec',
localExecuteUrl?: string
) {
try {
activeScenarioTab.value.executeLoading = true;
debugSocket(executeParams.reportId, executeType, localExecuteUrl); // websocket
//
activeScenarioTab.value.executeTime = dayjs().format('YYYY-MM-DD HH:mm:ss');
activeScenarioTab.value.executeSuccessCount = 0;
activeScenarioTab.value.executeFailCount = 0;
activeScenarioTab.value.stepResponses = {};
activeScenarioTab.value.reportId = executeParams.reportId; // ID
activeScenarioTab.value.isDebug = !isExecute;
let res;
if (isExecute && executeType !== 'localExec' && !activeScenarioTab.value.isNew) {
//
res = await executeScenario({
id: activeScenarioTab.value.id,
grouped: false,
environmentId: currentEnvConfig.value?.id || '',
projectId: appStore.currentProjectId,
scenarioConfig: activeScenarioTab.value.scenarioConfig,
uploadFileIds: activeScenarioTab.value.uploadFileIds,
linkFileIds: activeScenarioTab.value.linkFileIds,
...executeParams,
steps: mapTree(executeParams.steps, (node) => {
return {
...node,
parent: null, // axios
};
}),
});
} else {
res = await debugScenario({
id: activeScenarioTab.value.id,
grouped: false,
environmentId: currentEnvConfig.value?.id || '',
projectId: appStore.currentProjectId,
scenarioConfig: activeScenarioTab.value.scenarioConfig,
uploadFileIds: activeScenarioTab.value.uploadFileIds,
linkFileIds: activeScenarioTab.value.linkFileIds,
frontendDebug: executeType === 'localExec',
...executeParams,
steps: mapTree(executeParams.steps, (node) => {
return {
...node,
parent: null, // axios
};
}),
});
}
if (executeType === 'localExec' && localExecuteUrl) {
// debug
await localExecuteApiDebug(localExecuteUrl, res);
}
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
websocket.value?.close();
activeScenarioTab.value.executeLoading = false;
setStepExecuteStatus();
}
}
/**
* 执行场景
* @param executeType 执行类型
* @param localExecuteUrl 本地执行地址
*/
function handleExecute(executeType?: 'localExec' | 'serverExec', localExecuteUrl?: string) {
const waitingDebugStepDetails = {};
const waitTingDebugSteps = filterTree(activeScenarioTab.value.steps, (node) => {
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;
});
realExecute(
{
steps: waitTingDebugSteps,
stepDetails: waitingDebugStepDetails,
reportId: getGenerateId(),
},
true,
executeType,
localExecuteUrl
);
}
function handleStopExecute() {
websocket.value?.close();
activeScenarioTab.value.executeLoading = false;
setStepExecuteStatus();
}
watch(
() => activeScenarioTab.value.id,
(val) => {
if (val !== 'all' && activeScenarioTab.value.reportId && !activeScenarioTab.value.executeLoading) {
// tab tab ID
const cacheReport = temporaryScenarioReportMap[activeScenarioTab.value.reportId];
if (cacheReport) {
//
Object.keys(cacheReport).forEach((stepId) => {
const result = cacheReport[stepId];
activeScenarioTab.value.stepResponses[stepId] = result;
if (result.isSuccessful) {
activeScenarioTab.value.executeSuccessCount += 1;
} else {
activeScenarioTab.value.executeFailCount += 1;
}
});
activeScenarioTab.value.executeLoading = false;
delete temporaryScenarioReportMap[activeScenarioTab.value.reportId]; //
setStepExecuteStatus();
}
}
}
);
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';
let copySteps = defaultScenarioInfo.steps; let copySteps: ScenarioStepItem[] = [];
if (isCopy) { if (isCopy) {
copySteps = mapTree(defaultScenarioInfo.steps, (node) => { copySteps = mapTree(defaultScenarioInfo.steps, (node) => {
return { return {
@ -160,6 +365,8 @@
id: getGenerateId(), id: getGenerateId(),
}; };
}); });
} else {
copySteps = mapTree(defaultScenarioInfo.steps);
} }
scenarioTabs.value.push({ scenarioTabs.value.push({
...defaultScenarioInfo, ...defaultScenarioInfo,
@ -168,9 +375,14 @@
label: isCopy ? `copy-${defaultScenarioInfo.name}` : defaultScenarioInfo.name, label: isCopy ? `copy-${defaultScenarioInfo.name}` : defaultScenarioInfo.name,
name: isCopy ? `copy-${defaultScenarioInfo.name}` : defaultScenarioInfo.name, name: isCopy ? `copy-${defaultScenarioInfo.name}` : defaultScenarioInfo.name,
isNew: isCopy, isNew: isCopy,
isExecute: action === 'execute',
stepResponses: {}, stepResponses: {},
}); });
if (action === 'execute') {
nextTick(() => {
// tab
handleExecute(executeButtonRef.value?.isPriorityLocalExec ? 'localExec' : 'serverExec');
});
}
} else { } else {
scenarioTabs.value.push({ scenarioTabs.value.push({
...cloneDeep(defaultScenario), ...cloneDeep(defaultScenario),
@ -190,8 +402,6 @@
const activeFolder = ref<string>('all'); const activeFolder = ref<string>('all');
const offspringIds = ref<string[]>([]); const offspringIds = ref<string[]>([]);
const isShowScenario = ref(false); const isShowScenario = ref(false);
const executeButtonRef = ref<InstanceType<typeof executeButton>>();
const currentEnvConfig = ref<EnvConfig>();
// //
const getActiveClass = (type: string) => { const getActiveClass = (type: string) => {
@ -320,181 +530,6 @@
} }
}); });
const websocket = ref<WebSocket>();
const temporaryScenarioReportMap = {}; // websockettab
/**
* 开启websocket监听接收执行结果
*/
function debugSocket(reportId?: string | number, executeType?: 'localExec' | 'serverExec', localExecuteUrl?: string) {
websocket.value = getSocket(
reportId || '',
executeType === 'localExec' ? '/ws/debug' : '',
executeType === 'localExec' ? localExecuteUrl : ''
);
websocket.value.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.msgType === 'EXEC_RESULT') {
if (activeScenarioTab.value.reportId === data.reportId) {
// tabtab
data.taskResult.requestResults.forEach((result) => {
activeScenarioTab.value.stepResponses[result.stepId] = {
...result,
console: data.taskResult.console,
};
if (result.isSuccessful) {
activeScenarioTab.value.executeSuccessCount += 1;
} else {
activeScenarioTab.value.executeFailCount += 1;
}
});
} else {
// tab
data.taskResult.requestResults.forEach((result) => {
if (activeScenarioTab.value.reportId) {
if (temporaryScenarioReportMap[activeScenarioTab.value.reportId] === undefined) {
temporaryScenarioReportMap[activeScenarioTab.value.reportId] = {};
}
temporaryScenarioReportMap[activeScenarioTab.value.reportId][result.stepId] = {
...result,
console: data.taskResult.console,
};
}
});
}
} else if (data.msgType === 'EXEC_END') {
// websocket
websocket.value?.close();
if (activeScenarioTab.value.reportId === data.reportId) {
activeScenarioTab.value.executeLoading = false;
activeScenarioTab.value.isExecute = false;
}
}
});
}
async function realExecute(
executeParams: Pick<ApiScenarioDebugRequest, 'steps' | 'stepDetails' | 'reportId'>,
isExecute?: boolean,
executeType?: 'localExec' | 'serverExec',
localExecuteUrl?: string
) {
try {
activeScenarioTab.value.executeLoading = true;
debugSocket(executeParams.reportId, executeType, localExecuteUrl); // websocket
//
activeScenarioTab.value.executeTime = dayjs().format('YYYY-MM-DD HH:mm:ss');
activeScenarioTab.value.executeSuccessCount = 0;
activeScenarioTab.value.executeFailCount = 0;
activeScenarioTab.value.stepResponses = {};
activeScenarioTab.value.reportId = executeParams.reportId; // ID
activeScenarioTab.value.isDebug = !isExecute;
let res;
if (isExecute && executeType !== 'localExec' && !activeScenarioTab.value.isNew) {
//
res = await executeScenario({
id: activeScenarioTab.value.id,
grouped: false,
environmentId: currentEnvConfig.value?.id || '',
projectId: appStore.currentProjectId,
scenarioConfig: activeScenarioTab.value.scenarioConfig,
uploadFileIds: activeScenarioTab.value.uploadFileIds,
linkFileIds: activeScenarioTab.value.linkFileIds,
...executeParams,
steps: mapTree(executeParams.steps, (node) => {
return {
...node,
parent: null, // axios
};
}),
});
} else {
res = await debugScenario({
id: activeScenarioTab.value.id,
grouped: false,
environmentId: currentEnvConfig.value?.id || '',
projectId: appStore.currentProjectId,
scenarioConfig: activeScenarioTab.value.scenarioConfig,
uploadFileIds: activeScenarioTab.value.uploadFileIds,
linkFileIds: activeScenarioTab.value.linkFileIds,
frontendDebug: executeType === 'localExec',
...executeParams,
steps: mapTree(executeParams.steps, (node) => {
return {
...node,
parent: null, // axios
};
}),
});
}
if (executeType === 'localExec' && localExecuteUrl) {
// debug
await localExecuteApiDebug(localExecuteUrl, res);
}
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
websocket.value?.close();
activeScenarioTab.value.executeLoading = false;
}
}
function handleExecute(executeType?: 'localExec' | 'serverExec', localExecuteUrl?: string) {
const waitingDebugStepDetails = {};
const waitTingDebugSteps = filterTree(activeScenarioTab.value.steps, (node) => {
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;
});
realExecute(
{
steps: waitTingDebugSteps,
stepDetails: waitingDebugStepDetails,
reportId: getGenerateId(),
},
true,
executeType,
localExecuteUrl
);
}
function handleStopExecute() {
websocket.value?.close();
activeScenarioTab.value.executeLoading = false;
}
watch(
() => activeScenarioTab.value.id,
(val) => {
if (val !== 'all' && activeScenarioTab.value.reportId && !activeScenarioTab.value.executeLoading) {
// tab tab ID
const cacheReport = temporaryScenarioReportMap[activeScenarioTab.value.reportId];
if (cacheReport) {
//
Object.keys(cacheReport).forEach((stepId) => {
const result = cacheReport[stepId];
activeScenarioTab.value.stepResponses[stepId] = result;
if (result.isSuccessful) {
activeScenarioTab.value.executeSuccessCount += 1;
} else {
activeScenarioTab.value.executeFailCount += 1;
}
});
activeScenarioTab.value.executeLoading = false;
delete temporaryScenarioReportMap[activeScenarioTab.value.reportId]; //
}
}
}
);
const isPriorityLocalExec = computed(() => executeButtonRef.value?.isPriorityLocalExec); const isPriorityLocalExec = computed(() => executeButtonRef.value?.isPriorityLocalExec);
const scenarioId = computed(() => activeScenarioTab.value.id); const scenarioId = computed(() => activeScenarioTab.value.id);
const scenarioExecuteLoading = computed(() => activeScenarioTab.value.executeLoading); const scenarioExecuteLoading = computed(() => activeScenarioTab.value.executeLoading);

View File

@ -162,7 +162,7 @@
}>(); }>();
const lastReportStatusFilterVisible = ref(false); const lastReportStatusFilterVisible = ref(false);
const lastReportStatusListFilters = ref<string[]>(Object.keys(ReportStatus[ReportEnum.API_SCENARIO_REPORT])); const lastReportStatusListFilters = ref<string[]>([]);
const lastReportStatusFilters = computed(() => { const lastReportStatusFilters = computed(() => {
return Object.keys(ReportStatus[ReportEnum.API_SCENARIO_REPORT]); return Object.keys(ReportStatus[ReportEnum.API_SCENARIO_REPORT]);
}); });
@ -335,7 +335,7 @@
}; };
const statusFilterVisible = ref(false); const statusFilterVisible = ref(false);
const statusFilters = ref(Object.keys(ApiScenarioStatus)); const statusFilters = ref<string[]>([]);
const tableStore = useTableStore(); const tableStore = useTableStore();
async function loadScenarioList(refreshTreeCount?: boolean) { async function loadScenarioList(refreshTreeCount?: boolean) {
@ -354,7 +354,7 @@
moduleIds, moduleIds,
filter: { filter: {
lastReportStatus: lastReportStatusListFilters.value, lastReportStatus: lastReportStatusListFilters.value,
status: statusFilters.value.length === Object.keys(ApiScenarioStatus).length ? undefined : statusFilters.value, status: statusFilters.value,
}, },
}; };
setLoadListParams(params); setLoadListParams(params);

View File

@ -876,9 +876,9 @@
excludeIds: [], excludeIds: [],
currentSelectCount: 0, currentSelectCount: 0,
}); });
const statusFilters = ref<string[]>(Object.keys(statusIconMap)); const statusFilters = ref<string[]>([]);
const caseFilters = ref<string[]>([]); const caseFilters = ref<string[]>([]);
const executeResultFilters = ref(Object.keys(executionResultMap)); const executeResultFilters = ref<string[]>([]);
async function initTableParams() { async function initTableParams() {
let moduleIds: string[] = []; let moduleIds: string[] = [];

View File

@ -633,14 +633,14 @@
}); });
// //
const statusFilters = ref<string[]>(Object.keys(statusIconMap)); const statusFilters = ref<string[]>([]);
const caseLevelFields = ref<Record<string, any>>({}); const caseLevelFields = ref<Record<string, any>>({});
const caseFilterVisible = ref(false); const caseFilterVisible = ref(false);
const caseLevelList = computed(() => { const caseLevelList = computed(() => {
return caseLevelFields.value?.options || []; return caseLevelFields.value?.options || [];
}); });
const caseFilters = ref<string[]>([]); const caseFilters = ref<string[]>([]);
const executeResultFilters = ref(Object.keys(executionResultMap)); const executeResultFilters = ref<string[]>([]);
const updateUserFilters = ref<string[]>([]); const updateUserFilters = ref<string[]>([]);
const createUserFilters = ref<string[]>([]); const createUserFilters = ref<string[]>([]);
const deleteUserFilters = ref<string[]>([]); const deleteUserFilters = ref<string[]>([]);

View File

@ -240,9 +240,8 @@
import useFeatureCaseStore from '@/store/modules/case/featureCase'; import useFeatureCaseStore from '@/store/modules/case/featureCase';
import { hasAnyPermission } from '@/utils/permission'; import { hasAnyPermission } from '@/utils/permission';
import { BugListItem, BugOptionItem } from '@/models/bug-management'; import { BugOptionItem } from '@/models/bug-management';
import type { TableQueryParams } from '@/models/common'; import type { TableQueryParams } from '@/models/common';
import { CommonList } from '@/models/common';
const featureCaseStore = useFeatureCaseStore(); const featureCaseStore = useFeatureCaseStore();

View File

@ -473,7 +473,7 @@
async function initFilter() { async function initFilter() {
await featureStore.getDefaultTemplate(); await featureStore.getDefaultTemplate();
caseLevelList.value = featureStore.getSystemCaseLevelFields(); caseLevelList.value = featureStore.getSystemCaseLevelFields();
caseFilters.value = caseLevelList.value.map((item) => item.value); caseFilters.value = [];
} }
watch( watch(

View File

@ -350,7 +350,7 @@
const tableParams = ref<Record<string, any>>({}); const tableParams = ref<Record<string, any>>({});
const statusFilterVisible = ref(false); const statusFilterVisible = ref(false);
const statusFilters = ref<string[]>(Object.keys(reviewResultMap)); const statusFilters = ref<string[]>([]);
const hasOperationPermission = computed(() => const hasOperationPermission = computed(() =>
hasAnyPermission(['CASE_REVIEW:READ+REVIEW', 'CASE_REVIEW:READ+RELEVANCE']) hasAnyPermission(['CASE_REVIEW:READ+REVIEW', 'CASE_REVIEW:READ+RELEVANCE'])

View File

@ -495,7 +495,7 @@
}; };
const statusFilterVisible = ref(false); const statusFilterVisible = ref(false);
const statusFilters = ref<string[]>(Object.keys(reviewStatusMap)); const statusFilters = ref<string[]>([]);
const tableQueryParams = ref<any>(); const tableQueryParams = ref<any>();
async function searchReview(filter?: FilterResult) { async function searchReview(filter?: FilterResult) {
let moduleIds: string[] = []; let moduleIds: string[] = [];

View File

@ -107,7 +107,6 @@
import useTable from '@/components/pure/ms-table/useTable'; import useTable from '@/components/pure/ms-table/useTable';
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue'; import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
import { ActionsItem } from '@/components/pure/ms-table-more-action/types'; import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
import AddScriptDrawer from '@/components/business/ms-common-script/ms-addScriptDrawer.vue'; import AddScriptDrawer from '@/components/business/ms-common-script/ms-addScriptDrawer.vue';
import commonScriptStatus from './components/commonScriptStatus.vue'; import commonScriptStatus from './components/commonScriptStatus.vue';
import ScriptDetailDrawer from './components/scriptDetailDrawer.vue'; import ScriptDetailDrawer from './components/scriptDetailDrawer.vue';
@ -129,7 +128,7 @@
ParamsRequestType, ParamsRequestType,
} from '@/models/projectManagement/commonScript'; } from '@/models/projectManagement/commonScript';
import { CommonScriptStatusEnum } from '@/enums/commonScriptStatusEnum'; import { CommonScriptStatusEnum } from '@/enums/commonScriptStatusEnum';
import { ColumnEditTypeEnum, TableKeyEnum } from '@/enums/tableEnum'; import { TableKeyEnum } from '@/enums/tableEnum';
const appStore = useAppStore(); const appStore = useAppStore();
const currentProjectId = computed(() => appStore.currentProjectId); const currentProjectId = computed(() => appStore.currentProjectId);
@ -141,7 +140,7 @@
const { t } = useI18n(); const { t } = useI18n();
const statusFilterVisible = ref(false); const statusFilterVisible = ref(false);
const keyword = ref<string>(''); const keyword = ref<string>('');
const statusFilters = ref<string[]>(Object.keys(CommonScriptStatusEnum)); const statusFilters = ref<string[]>([]);
const hasOperationPermission = computed(() => const hasOperationPermission = computed(() =>
hasAnyPermission(['PROJECT_CUSTOM_FUNCTION:READ+UPDATE', 'PROJECT_CUSTOM_FUNCTION:READ+DELETE']) hasAnyPermission(['PROJECT_CUSTOM_FUNCTION:READ+UPDATE', 'PROJECT_CUSTOM_FUNCTION:READ+DELETE'])

View File

@ -112,7 +112,6 @@
} from '@/api/modules/project-management/taskCenter'; } from '@/api/modules/project-management/taskCenter';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal'; import useModal from '@/hooks/useModal';
import useOpenNewPage from '@/hooks/useOpenNewPage';
import { useTableStore } from '@/store'; import { useTableStore } from '@/store';
import { characterLimit } from '@/utils'; import { characterLimit } from '@/utils';
import { hasAnyPermission } from '@/utils/permission'; import { hasAnyPermission } from '@/utils/permission';
@ -135,16 +134,7 @@
}>(); }>();
const keyword = ref<string>(''); const keyword = ref<string>('');
const statusFilterVisible = ref(false); const statusFilterVisible = ref(false);
const statusListFilters = ref<string[]>(Object.keys(TaskStatus[props.moduleType])); const statusListFilters = ref<string[]>([]);
const { openNewPage } = useOpenNewPage();
const filterOptions = computed(() => {
return statusListFilters.value.map((item) => {
return {
label: item,
value: item,
};
});
});
const permissionsMap = { const permissionsMap = {
organization: { organization: {

View File

@ -218,7 +218,7 @@
const keyword = ref<string>(''); const keyword = ref<string>('');
const scrollWidth = ref<number>(3400); const scrollWidth = ref<number>(3400);
const statusFilterVisible = ref(false); const statusFilterVisible = ref(false);
const statusFilters = ref<string[]>(Object.keys(reviewStatusMap)); const statusFilters = ref<string[]>([]);
const tableBatchActions = { const tableBatchActions = {
baseAction: [ baseAction: [