From 3445189a780fcc118f73725668e367ebe917fa78 Mon Sep 17 00:00:00 2001 From: baiqi Date: Tue, 3 Sep 2024 15:48:31 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E8=84=91=E5=9B=BE):=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E8=87=AA=E5=AE=9A=E4=B9=89=E4=B8=8B=E6=8B=89?= =?UTF-8?q?=E8=8F=9C=E5=8D=95&=E6=B5=8B=E8=AF=95=E8=A7=84=E5=88=92?= =?UTF-8?q?=E8=84=91=E5=9B=BE=E5=BF=AB=E6=8D=B7=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/ms-associate-case/index.vue | 8 +- .../ms-minders/testPlanMinder/index.vue | 97 ++++++++++++++----- .../hooks/useMinderTrigger.ts | 64 ++++++++++++ .../pure/ms-minder-editor/main/mainEditor.vue | 4 + .../ms-minder-editor/menu/nodeDropdown.vue | 54 +++++++++++ .../ms-minder-editor/menu/nodeFloatMenu.vue | 64 +++++------- .../pure/ms-minder-editor/minderEditor.vue | 2 + .../components/pure/ms-minder-editor/props.ts | 25 +++++ frontend/src/enums/minderEnum.ts | 1 + 9 files changed, 252 insertions(+), 67 deletions(-) create mode 100644 frontend/src/components/pure/ms-minder-editor/hooks/useMinderTrigger.ts create mode 100644 frontend/src/components/pure/ms-minder-editor/menu/nodeDropdown.vue diff --git a/frontend/src/components/business/ms-associate-case/index.vue b/frontend/src/components/business/ms-associate-case/index.vue index 28ab1321e2..500a335da6 100644 --- a/frontend/src/components/business/ms-associate-case/index.vue +++ b/frontend/src/components/business/ms-associate-case/index.vue @@ -206,7 +206,7 @@ { - switchingConfigFormData.value = false; - }); } function openCaseAssociateDrawer() { @@ -681,6 +702,19 @@ () => { if ([MinderEventName.EXPAND, MinderEventName.COLLAPSE].includes(minderStore.event.name)) { setCustomPriorityView(priorityTextMap); + } else if (minderStore.event.name === MinderEventName.DROPDOWN_SELECT) { + const node: PlanMinderNode = window.minder.getSelectedNode(); + if (node?.data?.level === 3 && node?.data?.resource?.[0] === resourcePoolTag) { + if (node.parent?.data) { + node.parent.data.testResourcePoolId = minderStore.event.params; + minderStore.dispatchEvent(MinderEventName.SAVE_MINDER); + } + } else if (node?.data?.level === 3 && node?.data?.resource?.[0] === envTag) { + if (node.parent?.data) { + node.parent.data.environmentId = minderStore.event.params; + minderStore.dispatchEvent(MinderEventName.SAVE_MINDER); + } + } } } ); @@ -716,6 +750,13 @@ } ); + /** + * 是否可以显示下拉菜单 + */ + const canShowDropdown = ref(false); + const dropdownList = ref([]); + const checkedVal = ref(); + /** * 处理节点选中 * @param node 节点 @@ -730,8 +771,7 @@ selectNodeExecuteMethod.value = undefined; } if (node.data?.level === 3 && node.data?.resource?.[0] === caseCountTag) { - window.minder.toggleSelect(node); - window.minder.selectById(node.parent?.data?.id); + canShowFloatMenu.value = false; if (!inInsertingNode.value && hasEditPermission && hasAnyPermission(['PROJECT_TEST_PLAN:READ+ASSOCIATION'])) { // 新增测试点时不自动弹出关联用例 associateCase(); @@ -740,8 +780,21 @@ node.data?.level === 3 && (node.data?.resource?.[0] === resourcePoolTag || node.data?.resource?.[0] === envTag) ) { - window.minder.toggleSelect(node); - window.minder.selectById(node.parent?.data?.id); + canShowFloatMenu.value = false; + canShowDropdown.value = !node.parent?.data?.extended; // 继承上级配置的测试点节点不显示下拉菜单 + if (node.data?.resource?.[0] === resourcePoolTag) { + dropdownList.value = resourcePoolOptions.value.map((item) => ({ + label: item.label || '', + value: item.value as string, + })); + checkedVal.value = node.parent?.data?.testResourcePoolId; + } else { + dropdownList.value = environmentOptions.value.map((item) => ({ + label: item.label || '', + value: item.value as string, + })); + checkedVal.value = node.parent?.data?.environmentId; + } } else { checkNodeCanShowMenu(node); if (extraVisible.value) { @@ -968,7 +1021,7 @@ } if (!configFormValidResult) return; loading.value = true; - await editPlanMinder(makeMinderParams(extraVisible.value ? window.minder.exportJson() : fullJson)); + await editPlanMinder(makeMinderParams(window.minder.exportJson())); Message.success(t('common.saveSuccess')); emit('save'); clearSelectedCases(); diff --git a/frontend/src/components/pure/ms-minder-editor/hooks/useMinderTrigger.ts b/frontend/src/components/pure/ms-minder-editor/hooks/useMinderTrigger.ts new file mode 100644 index 0000000000..9c2aae7509 --- /dev/null +++ b/frontend/src/components/pure/ms-minder-editor/hooks/useMinderTrigger.ts @@ -0,0 +1,64 @@ +import useMinderStore from '@/store/modules/components/minder-editor'; +import type { MinderCustomEvent, MinderNodePosition } from '@/store/modules/components/minder-editor/types'; +import { sleep } from '@/utils'; + +import { MinderEventName } from '@/enums/minderEnum'; + +import type { MinderJsonNode } from '../props'; +import { isNodeInMinderView } from '../script/tool/utils'; + +export default function useMinderTrigger( + handleSelect?: (event: MinderCustomEvent, selectedNodes: MinderJsonNode[]) => void +) { + const minderStore = useMinderStore(); + + const triggerVisible = ref(false); + const triggerOffset = ref([0, 0]); + + watch( + () => minderStore.event.eventId, + async () => { + if (window.minder) { + let nodePosition: MinderNodePosition | undefined; + const selectedNodes: MinderJsonNode[] = window.minder.getSelectedNodes(); + if (minderStore.event.name === MinderEventName.NODE_SELECT) { + nodePosition = minderStore.event.nodePosition; + if (handleSelect) { + handleSelect(minderStore.event, selectedNodes); + } + } + if (selectedNodes.length > 1) { + // 多选时隐藏悬浮菜单 + triggerVisible.value = false; + return; + } + if ([MinderEventName.VIEW_CHANGE, MinderEventName.DRAG_FINISH].includes(minderStore.event.name)) { + // 脑图画布移动时,重新计算节点位置 + await sleep(300); // 拖拽完毕后会有 300ms 的动画,等待动画结束后再计算 + nodePosition = window.minder.getSelectedNode()?.getRenderBox(); + } + const state = window.editor.fsm.state(); + if ( + nodePosition && + isNodeInMinderView(undefined, nodePosition, Math.min(nodePosition.width / 2, 200)) && + state !== 'input' + ) { + // 判断节点在脑图可视区域内且遮挡的节点不超过节点宽度的一半(超过 200px 则按 200px 算)且当前不是编辑名称状态,则显示菜单 + const nodeDomHeight = nodePosition.height || 0; + triggerOffset.value = [nodePosition.x, nodePosition.y + nodeDomHeight + 4]; // trigger显示在节点下方4px处 + triggerVisible.value = true; + } else { + triggerVisible.value = false; + } + } + }, + { + immediate: true, + } + ); + + return { + triggerVisible, + triggerOffset, + }; +} diff --git a/frontend/src/components/pure/ms-minder-editor/main/mainEditor.vue b/frontend/src/components/pure/ms-minder-editor/main/mainEditor.vue index 8dad666736..8214859678 100644 --- a/frontend/src/components/pure/ms-minder-editor/main/mainEditor.vue +++ b/frontend/src/components/pure/ms-minder-editor/main/mainEditor.vue @@ -29,6 +29,7 @@ + @@ -37,6 +38,7 @@ import { cloneDeep } from 'lodash-es'; import batchMenu from '../menu/batchMenu.vue'; + import nodeDropdown from '../menu/nodeDropdown.vue'; import nodeFloatMenu from '../menu/nodeFloatMenu.vue'; import minderHeader from './header.vue'; import Navigator from './navigator.vue'; @@ -50,6 +52,7 @@ import useEventListener from '../hooks/useMinderEventListener'; import { batchMenuProps, + dropdownMenuProps, editMenuProps, floatMenuProps, headerProps, @@ -72,6 +75,7 @@ ...tagProps, ...priorityProps, ...batchMenuProps, + ...dropdownMenuProps, }); const emit = defineEmits<{ (e: 'save', data: MinderJson, callback: () => void): void; diff --git a/frontend/src/components/pure/ms-minder-editor/menu/nodeDropdown.vue b/frontend/src/components/pure/ms-minder-editor/menu/nodeDropdown.vue new file mode 100644 index 0000000000..61d6ff736b --- /dev/null +++ b/frontend/src/components/pure/ms-minder-editor/menu/nodeDropdown.vue @@ -0,0 +1,54 @@ + + + + + diff --git a/frontend/src/components/pure/ms-minder-editor/menu/nodeFloatMenu.vue b/frontend/src/components/pure/ms-minder-editor/menu/nodeFloatMenu.vue index 4fbf1e5277..37ed55a2e1 100644 --- a/frontend/src/components/pure/ms-minder-editor/menu/nodeFloatMenu.vue +++ b/frontend/src/components/pure/ms-minder-editor/menu/nodeFloatMenu.vue @@ -195,15 +195,13 @@ import { useI18n } from '@/hooks/useI18n'; import useMinderStore from '@/store/modules/components/minder-editor/index'; - import { MinderNodePosition } from '@/store/modules/components/minder-editor/types'; - import { sleep } from '@/utils'; import { MinderEventName } from '@/enums/minderEnum'; import useMinderOperation from '../hooks/useMinderOperation'; import usePriority from '../hooks/useMinderPriority'; + import useMinderTrigger from '../hooks/useMinderTrigger'; import { floatMenuProps, mainEditorProps, MinderJsonNode, priorityColorMap, priorityProps, tagProps } from '../props'; - import { isNodeInMinderView } from '../script/tool/utils'; const props = defineProps({ ...mainEditorProps, @@ -227,45 +225,29 @@ }); const menuPopupOffset = ref([0, 0]); + const { triggerOffset, triggerVisible } = useMinderTrigger((event, selectedNodes) => { + currentNodeTags.value = event.nodes?.[0].data?.resource || []; + if (props.replaceableTags && !props.disabled) { + tags.value = props.replaceableTags(selectedNodes); + } else { + tags.value = []; + } + }); + watch( - () => minderStore.event.eventId, - async () => { - if (window.minder) { - let nodePosition: MinderNodePosition | undefined; - const selectedNodes: MinderJsonNode[] = window.minder.getSelectedNodes(); - if (minderStore.event.name === MinderEventName.NODE_SELECT) { - nodePosition = minderStore.event.nodePosition; - currentNodeTags.value = minderStore.event.nodes?.[0].data?.resource || []; - if (props.replaceableTags && !props.disabled) { - tags.value = props.replaceableTags(selectedNodes); - } else { - tags.value = []; - } - } - if (selectedNodes.length > 1) { - // 多选时隐藏悬浮菜单 - menuVisible.value = false; - return; - } - if ([MinderEventName.VIEW_CHANGE, MinderEventName.DRAG_FINISH].includes(minderStore.event.name)) { - // 脑图画布移动时,重新计算节点位置 - await sleep(300); // 拖拽完毕后会有 300ms 的动画,等待动画结束后再计算 - nodePosition = window.minder.getSelectedNode()?.getRenderBox(); - } - const state = window.editor.fsm.state(); - if ( - nodePosition && - isNodeInMinderView(undefined, nodePosition, Math.min(nodePosition.width / 2, 200)) && - state !== 'input' - ) { - // 判断节点在脑图可视区域内且遮挡的节点不超过节点宽度的一半(超过 200px 则按 200px 算)且当前不是编辑名称状态,则显示菜单 - const nodeDomHeight = nodePosition.height || 0; - menuPopupOffset.value = [nodePosition.x, nodePosition.y + nodeDomHeight + 4]; // 菜单显示在节点下方4px处 - menuVisible.value = true; - } else { - menuVisible.value = false; - } - } + () => triggerOffset.value, + (val) => { + menuPopupOffset.value = [val[0], val[1]]; + }, + { + immediate: true, + } + ); + + watch( + () => triggerVisible.value, + (val) => { + menuVisible.value = val; }, { immediate: true, diff --git a/frontend/src/components/pure/ms-minder-editor/minderEditor.vue b/frontend/src/components/pure/ms-minder-editor/minderEditor.vue index 38668dc09c..aecd4017de 100644 --- a/frontend/src/components/pure/ms-minder-editor/minderEditor.vue +++ b/frontend/src/components/pure/ms-minder-editor/minderEditor.vue @@ -39,6 +39,7 @@ import { batchMenuProps, delProps, + dropdownMenuProps, editMenuProps, floatMenuProps, headerProps, @@ -77,6 +78,7 @@ ...delProps, ...viewMenuProps, ...batchMenuProps, + ...dropdownMenuProps, }); const minderStore = useMinderStore(); diff --git a/frontend/src/components/pure/ms-minder-editor/props.ts b/frontend/src/components/pure/ms-minder-editor/props.ts index 76f65cc4f9..85ba23eab9 100644 --- a/frontend/src/components/pure/ms-minder-editor/props.ts +++ b/frontend/src/components/pure/ms-minder-editor/props.ts @@ -216,6 +216,31 @@ export const floatMenuProps = { default: false, }, }; + +export interface MinderDropdownListItem { + value: string; + label: string; + permission?: string[]; + onClick?: () => void; +} + +export const dropdownMenuProps = { + // 是否显示Dropdown + canShowDropdown: { + type: Boolean, + default: false, + }, + dropdownList: { + type: Array as PropType, + default() { + return []; + }, + }, + checkedVal: { + type: String as PropType, + default: undefined, + }, +}; export const batchMenuProps = { canShowMoreBatchMenu: { type: Boolean, diff --git a/frontend/src/enums/minderEnum.ts b/frontend/src/enums/minderEnum.ts index 4e7c73fd41..a967c258e8 100644 --- a/frontend/src/enums/minderEnum.ts +++ b/frontend/src/enums/minderEnum.ts @@ -16,6 +16,7 @@ export enum MinderEventName { 'MINDER_CHANGED' = 'MINDER_CHANGED', // 脑图更改事件 'SAVE_MINDER' = 'SAVE_MINDER', // 脑图保存事件 'DRAG_FINISH' = 'DRAG_FINISH', // 脑图节点拖拽结束事件 + 'DROPDOWN_SELECT' = 'DROPDOWN_SELECT', // 下拉菜单选中事件 } export enum MinderKeyEnum {