feat(测试计划): 脑图执行用例优化-快捷键和样式

--story=1015918 --user=吕梦园
https://www.tapd.cn/55049933/prong/stories/view/1155049933001015918
This commit is contained in:
teukkk 2024-08-29 15:47:32 +08:00 committed by Craftsman
parent a63d9e811a
commit a2cf676081
4 changed files with 95 additions and 77 deletions

View File

@ -19,7 +19,7 @@
>
<template #extractMenu>
<!-- 缺陷 -->
<a-dropdown position="bl">
<a-dropdown trigger="hover" position="bl">
<a-tooltip
v-if="
props.canEdit &&
@ -166,6 +166,7 @@
import MsButton from '@/components/pure/ms-button/index.vue';
import MsDescription, { Description } from '@/components/pure/ms-description/index.vue';
import useShortCut from '@/components/pure/ms-minder-editor/hooks/useShortCut';
import MsMinderEditor from '@/components/pure/ms-minder-editor/minderEditor.vue';
import type { MinderJson, MinderJsonNode, MinderJsonNodeData } from '@/components/pure/ms-minder-editor/props';
import {
@ -178,6 +179,7 @@
setPriorityView,
} from '@/components/pure/ms-minder-editor/script/tool/utils';
import { MsFileItem } from '@/components/pure/ms-upload/types';
import { getMinderOperationParams } from '@/components/business/ms-minders/caseReviewMinder/utils';
import Attachment from '@/components/business/ms-minders/featureCaseMinder/attachment.vue';
import useMinderBaseApi from '@/components/business/ms-minders/featureCaseMinder/useMinderBaseApi';
import BugList from './bugList.vue';
@ -189,7 +191,13 @@
import ExecuteSubmit from '@/views/test-plan/testPlan/detail/featureCase/detail/executeSubmit.vue';
import { getCasePlanMinder } from '@/api/modules/case-management/caseReview';
import { associateBugToPlan, executeHistory, getCaseDetail, runFeatureCase } from '@/api/modules/test-plan/testPlan';
import {
associateBugToPlan,
batchExecuteCase,
executeHistory,
getCaseDetail,
runFeatureCase,
} from '@/api/modules/test-plan/testPlan';
import { defaultExecuteForm } from '@/config/testPlan';
import { useI18n } from '@/hooks/useI18n';
import useAppStore from '@/store/modules/app';
@ -201,7 +209,11 @@
import type { StepList } from '@/models/caseManagement/featureCase';
import type { TableQueryParams } from '@/models/common';
import { ModuleTreeNode } from '@/models/common';
import type { ExecuteFeatureCaseFormParams, ExecuteHistoryItem } from '@/models/testPlan/testPlan';
import type {
BatchExecuteFeatureCaseParams,
ExecuteFeatureCaseFormParams,
ExecuteHistoryItem,
} from '@/models/testPlan/testPlan';
import { AssociatedBugApiTypeEnum } from '@/enums/associateBugEnum';
import { LastExecuteResults } from '@/enums/caseEnum';
import { MinderEventName, MinderKeyEnum } from '@/enums/minderEnum';
@ -305,16 +317,6 @@
}
}
onMounted(() => {
initCaseTree();
//
window.minder._resourceColorMapping = {
[executionResultMap.SUCCESS.statusText]: 4,
[executionResultMap.ERROR.statusText]: 5,
[executionResultMap.BLOCKED.statusText]: 6,
};
});
watch(
() => props.activeModule,
() => {
@ -549,11 +551,17 @@
const executeVisible = ref(false);
//
function updateCaseActualResultNode(node: MinderJsonNode, content: string) {
const actualResultNode = node.children?.find((item: MinderJsonNode) =>
let actualResultNode = node.children?.find((item: MinderJsonNode) =>
item.data?.resource?.includes(actualResultTag)
);
if (actualResultNode) {
actualResultNode.setData('text', content ?? '').render();
} else {
actualResultNode = createNode(
{ resource: [actualResultTag], text: content ?? '', id: `actualResult-${node.data?.id}` },
node
);
handleRenderNode(node, [actualResultNode]);
}
}
function isActualResultNode(node: MinderJsonNode) {
@ -584,6 +592,24 @@
}
emit('refreshPlan');
}
async function handleShortCutExecute(status: LastExecuteResults) {
const selectedNodes: MinderJsonNode = window.minder.getSelectedNode();
if (!selectedNodes?.data?.resource?.includes(caseTag)) return;
try {
await batchExecuteCase({
projectId: appStore.currentProjectId,
testPlanId: props.planId,
lastExecResult: status,
content: '',
...getMinderOperationParams(selectedNodes),
} as BatchExecuteFeatureCaseParams);
//
handleExecuteDone(status, '');
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
}
const stepExecuteModelVisible = ref(false);
const caseNodeAboveSelectStep = ref(); //
@ -835,6 +861,32 @@
extraVisible.value = false;
}
const { unbindShortcuts } = useShortCut(
{
executeToError: () => {
handleShortCutExecute(LastExecuteResults.ERROR);
},
executeToBlocked: () => {
handleShortCutExecute(LastExecuteResults.BLOCKED);
},
executeToSuccess: () => {
handleShortCutExecute(LastExecuteResults.SUCCESS);
},
},
{}
);
onMounted(() => {
initCaseTree();
//
window.minder._resourceColorMapping = {
[executionResultMap.SUCCESS.statusText]: 4,
[executionResultMap.ERROR.statusText]: 5,
[executionResultMap.BLOCKED.statusText]: 6,
};
unbindShortcuts();
});
defineExpose({
initCaseTree,
});

View File

@ -1,7 +1,17 @@
import type { MinderJsonNode } from '../props';
import useMinderOperation, { type MinderOperationProps } from './useMinderOperation';
type ShortcutKey = 'expand' | 'enter' | 'appendSiblingNode' | 'appendChildNode' | 'undo' | 'redo' | 'delete';
type ShortcutKey =
| 'expand'
| 'enter'
| 'appendSiblingNode'
| 'appendChildNode'
| 'undo'
| 'redo'
| 'delete'
| 'executeToSuccess'
| 'executeToBlocked'
| 'executeToError';
// 快捷键事件映射combinationShortcuts中定义了组合键事件key为组合键value为事件名称
type Shortcuts = {
[key in ShortcutKey]?: () => void;
@ -11,6 +21,7 @@ export default function useShortCut(shortcuts: Shortcuts, options: MinderOperati
const { minderCopy, minderCut, minderPaste } = useMinderOperation(options);
const handleKeyDown = (event: KeyboardEvent) => {
event.preventDefault();
const nodes: MinderJsonNode[] = window.minder.getSelectedNodes();
if (nodes.length === 0) {
return;
@ -41,19 +52,26 @@ export default function useShortCut(shortcuts: Shortcuts, options: MinderOperati
'tab': 'appendChildNode',
'backspace': 'delete',
};
// 业务快捷键
const businessShortcuts: { [key: string]: ShortcutKey } = {
s: 'executeToSuccess', // 执行结果为成功
b: 'executeToBlocked', // 执行结果为阻塞
e: 'executeToError', // 执行结果为失败
};
let action;
if (isCtrlOrCmd && combinationShortcuts[key]) {
// 执行组合键事件
const action = combinationShortcuts[key];
if (shortcuts[action]) {
shortcuts[action]!();
}
action = combinationShortcuts[key];
} else if (singleShortcuts[key]) {
// 执行单键事件
const action = singleShortcuts[key];
if (shortcuts[action]) {
shortcuts[action]!();
}
action = singleShortcuts[key];
} else if (businessShortcuts[key]) {
// 执行业务快捷键事件
action = businessShortcuts[key];
}
if (action && shortcuts[action]) {
shortcuts[action]!();
}
};

View File

@ -121,7 +121,7 @@
class="ms-minder-dropdown"
:popup-translate="[0, 4]"
position="bl"
trigger="click"
trigger="hover"
@select="(val) => handleMinderMenuSelect(val)"
>
<a-tooltip :content="t('common.more')">

View File

@ -29,60 +29,8 @@ interface IJumpingRuntime {
container: HTMLElement;
}
// Nice: http://unixpapa.com/js/key.html
function isIntendToInput(e: KeyboardEvent): boolean {
if (e.ctrlKey || e.metaKey || e.altKey) return false;
// a-zA-Z
if (e.keyCode >= 65 && e.keyCode <= 90) return true;
// 0-9 以及其上面的符号
if (e.keyCode >= 48 && e.keyCode <= 57) return true;
// 小键盘区域 (除回车外)
if (e.keyCode !== 108 && e.keyCode >= 96 && e.keyCode <= 111) return true;
// 小键盘区域 (除回车外)
// @yinheli from pull request
if (e.keyCode !== 108 && e.keyCode >= 96 && e.keyCode <= 111) return true;
// 输入法
if (e.keyCode === 229 || e.keyCode === 0) return true;
return false;
}
function JumpingRuntime(this: IJumpingRuntime): void {
const { fsm, minder, receiver } = this;
const receiverElement = receiver.element;
// normal -> *
receiver.listen('normal', (e: KeyboardEvent) => {
// 为了防止处理进入edit模式而丢失处理的首字母,此时receiver必须为enable
receiver.enable();
/**
* check
* @editor Naixor
* @Date 2015-12-2
*/
switch (e.type) {
case 'keydown': {
if (minder.getSelectedNode()) {
if (isIntendToInput(e)) {
return fsm.jump('input', 'user-input');
}
} else {
receiverElement.innerHTML = '';
}
// normal -> normal shortcut
// fsm.jump('normal', 'shortcut-handle', e); TODO: 未来需要支持自定义快捷键处理逻辑
break;
}
case 'keyup': {
break;
}
default:
}
});
const { fsm, receiver } = this;
// input => normal
receiver.listen('input', (e: KeyboardEvent) => {