From 2755ece84b4b854ca9baa1432e404afeeb620065 Mon Sep 17 00:00:00 2001 From: KuroSago Date: Wed, 7 May 2025 21:48:13 +0800 Subject: [PATCH] no message --- web/src/pages/Edit/components/Setting.vue | 1 + .../src/components/ToolBar/RemoveNode.vue | 1 + .../store/helpers/addCustomContentToNode.ts | 117 ++++++++++++++++++ .../mind-map/src/store/helpers/keyCommand.ts | 17 +++ .../mind-map/src/store/helpers/removeNode.ts | 20 +++ .../mind-map/src/store/helpers/usePlugin.ts | 2 + .../mind-map/src/store/modules/mindMap.ts | 54 +++++--- web3/packages/mind-map/src/types/index.d.ts | 8 ++ 8 files changed, 201 insertions(+), 19 deletions(-) create mode 100644 web3/packages/mind-map/src/store/helpers/addCustomContentToNode.ts create mode 100644 web3/packages/mind-map/src/store/helpers/keyCommand.ts diff --git a/web/src/pages/Edit/components/Setting.vue b/web/src/pages/Edit/components/Setting.vue index e8666344..19b45f6b 100644 --- a/web/src/pages/Edit/components/Setting.vue +++ b/web/src/pages/Edit/components/Setting.vue @@ -535,6 +535,7 @@ export default { // 更新其他配置 updateOtherConfig(key, value) { + console.log({key, value}) if (key === 'openBlankMode') { this.mindMap.updateConfig({ demonstrateConfig: { diff --git a/web3/packages/mind-map/src/components/ToolBar/RemoveNode.vue b/web3/packages/mind-map/src/components/ToolBar/RemoveNode.vue index f281c138..cb88f46b 100644 --- a/web3/packages/mind-map/src/components/ToolBar/RemoveNode.vue +++ b/web3/packages/mind-map/src/components/ToolBar/RemoveNode.vue @@ -23,6 +23,7 @@ function remove() { return true; }, nodeId: uid, + allowRemoveWithChildren : false }); } } diff --git a/web3/packages/mind-map/src/store/helpers/addCustomContentToNode.ts b/web3/packages/mind-map/src/store/helpers/addCustomContentToNode.ts new file mode 100644 index 00000000..b0cc75c8 --- /dev/null +++ b/web3/packages/mind-map/src/store/helpers/addCustomContentToNode.ts @@ -0,0 +1,117 @@ +import { insertChildNode } from "./insertChildNode"; +import { insertSiblingNode } from "./insertSiblingNode"; +import { useMindMapStore } from "../index"; + +const ICON_PLUS = '' +const ICON_EDIT = '' +const ICON_DELETE = '' + +/** + * 为节点添加自定义内容 - 添加按钮工具栏 + * @returns 自定义节点内容配置对象 + */ +export function getCustomNodeContent() { + // 按钮配置 + const buttonConfig = { + padding: 5, // 按钮内边距 + gap: 4, // 按钮间距 + fontSize: 12, // 字体大小 + height: 24, // 按钮高度 + // 每个按钮的估计宽度 (图标大约占12px + 左右内边距共10px) + buttonWidth: 22 + }; + + // 所有按钮配置 + const buttons = [ + { icon: ICON_PLUS, color: "#4CAF50", title: "添加子节点", action: "addChild" }, + { icon: ICON_EDIT, color: "#FF9800", title: "编辑节点", action: "edit" }, + { icon: ICON_DELETE, color: "#2196F3", title: "删除", action: "addSibling" }, + ]; + + // 预计算总宽度 + const totalWidth = buttons.length * buttonConfig.buttonWidth + + (buttons.length - 1) * buttonConfig.gap; + + return { + // 创建自定义DOM元素 + create: (node: any) => { + // 创建包含按钮的容器 + const container = document.createElement("div"); + container.style.display = "flex"; + container.style.gap = `${buttonConfig.gap}px`; + + // 通用创建按钮的函数,减少重复代码 + const createButton = (icon: string, color: string, title: string, action: string) => { + const btn = document.createElement("button"); + btn.innerHTML = icon; + btn.title = title; + + // 通用样式 + Object.assign(btn.style, { + border: "none", + background: color, + color: "white", + borderRadius: "3px", + cursor: "pointer", + padding: `2px ${buttonConfig.padding}px`, + fontSize: `${buttonConfig.fontSize}px`, + minWidth: `${buttonConfig.buttonWidth - buttonConfig.padding * 2}px` + }); + + btn.onclick = (e) => { + e.stopPropagation(); // 阻止事件冒泡 + + // 根据按钮类型执行不同操作 + switch (action) { + case "addChild": + insertChildNode({ + beforeInsertCallback: async () => ({ uid: "", text: "新子节点" }), + parentNodeId: node.uid, + }); + break; + case "addSibling": + insertSiblingNode({ + beforeInsertCallback: async () => ({ uid: "", text: "新同级节点" }), + nodeId: node.uid, + }); + break; + case "edit": + // const { getMindMapInstance } = useMindMapStore(); + break; + } + }; + + return btn; + }; + + // 创建并添加所有按钮 + buttons.forEach(buttonInfo => { + const btn = createButton( + buttonInfo.icon, + buttonInfo.color, + buttonInfo.title, + buttonInfo.action + ); + container.appendChild(btn); + }); + + // 返回容器元素和预计算的尺寸 + return { + el: container, + width: totalWidth, // 预计算的容器总宽度 + height: buttonConfig.height // 容器高度 + }; + }, + + // 处理生成的SVG.js的ForeignObject节点实例 + handle: ({ element, node }: { content: any; element: any; node: any }) => { + console.log({ element, node }) + node.height += 34 + // 设置自定义内容的位置 - 位于节点下方 + element.attr({ + x: 0, // 水平居中 + y: node.height + 5 // 位于节点下方5px的位置 + }); + }, + }; +} \ No newline at end of file diff --git a/web3/packages/mind-map/src/store/helpers/keyCommand.ts b/web3/packages/mind-map/src/store/helpers/keyCommand.ts new file mode 100644 index 00000000..fed294f1 --- /dev/null +++ b/web3/packages/mind-map/src/store/helpers/keyCommand.ts @@ -0,0 +1,17 @@ +import MindMap from "simple-mind-map"; +// import { keyMap } from 'simple-mind-map/src/core/command/keyMap' + +// 键盘事件 +export function keyCommand(MindMapConstructor: MindMap) { + removeKeyCommand(MindMapConstructor); +} + +// 移除指令 +export function removeKeyCommand(MindMapConstructor: MindMap) { + // console.log('移除指令 =>' , keyMap) + // Backspace // Tab // Enter + MindMapConstructor?.keyCommand?.removeShortcut('Tab' , null) + MindMapConstructor?.keyCommand?.removeShortcut('Enter' , null) + MindMapConstructor?.keyCommand?.removeShortcut('Backspace' , null) +// MindMapConstructor?.keyCommand?.pause(); +} diff --git a/web3/packages/mind-map/src/store/helpers/removeNode.ts b/web3/packages/mind-map/src/store/helpers/removeNode.ts index e8743346..b7d3e278 100644 --- a/web3/packages/mind-map/src/store/helpers/removeNode.ts +++ b/web3/packages/mind-map/src/store/helpers/removeNode.ts @@ -4,11 +4,13 @@ import { useMindMapStore } from "../../store/index"; * 删除节点 * @param beforeRemoveCallback 删除前执行的异步回调函数,如果返回false则取消删除操作 * @param nodeId 要删除的节点ID,如不提供则删除当前选中的节点 + * @param allowRemoveWithChildren 存在子节点时是否允许删除,默认为true * @returns 返回Promise,可用于链式调用 */ export async function removeNode(params: { beforeRemoveCallback?: () => Promise; nodeId?: string | number; + allowRemoveWithChildren?: boolean; }): Promise { const { getMindMapInstance } = useMindMapStore(); @@ -23,10 +25,28 @@ export async function removeNode(params: { const node = getMindMapInstance()?.renderer?.findNodeByUid( params.nodeId ); + if (node) { + // 检查节点是否有子节点且不允许删除有子节点的情况 + if (params.allowRemoveWithChildren === false) { + const children = node.children; + if (children && children.length > 0) { + console.warn("节点存在子节点,根据设置不允许删除"); + return; + } + } + return getMindMapInstance()?.execCommand("REMOVE_NODE", [node]); } } else { + // 删除当前选中的节点 + if (params.allowRemoveWithChildren === false) { + const selectedNode = getMindMapInstance()?.renderer?.activeNodeList[0]; + if (selectedNode && selectedNode.children && selectedNode.children.length > 0) { + console.warn("节点存在子节点,根据设置不允许删除"); + return; + } + } return getMindMapInstance()?.execCommand("REMOVE_NODE"); } } catch (error) { diff --git a/web3/packages/mind-map/src/store/helpers/usePlugin.ts b/web3/packages/mind-map/src/store/helpers/usePlugin.ts index 351f0148..92d0bda2 100644 --- a/web3/packages/mind-map/src/store/helpers/usePlugin.ts +++ b/web3/packages/mind-map/src/store/helpers/usePlugin.ts @@ -7,6 +7,7 @@ import ExportPDF from 'simple-mind-map/src/plugins/ExportPDF' import ExportXMind from 'simple-mind-map/src/plugins/ExportXMind' import Export from 'simple-mind-map/src/plugins/Export' import MindMapLayoutPro from 'simple-mind-map/src/plugins/MindMapLayoutPro' +// import RichText from 'simple-mind-map/src/plugins/RichText' export function usePlugins(MindMapConstructor: typeof MindMap) { @@ -15,4 +16,5 @@ export function usePlugins(MindMapConstructor: typeof MindMap) { MindMapConstructor.usePlugin(ExportXMind); MindMapConstructor.usePlugin(Export); MindMapConstructor.usePlugin(MindMapLayoutPro) + // MindMapConstructor.usePlugin(RichText); } \ No newline at end of file diff --git a/web3/packages/mind-map/src/store/modules/mindMap.ts b/web3/packages/mind-map/src/store/modules/mindMap.ts index a9078dbb..327a20fa 100644 --- a/web3/packages/mind-map/src/store/modules/mindMap.ts +++ b/web3/packages/mind-map/src/store/modules/mindMap.ts @@ -1,11 +1,13 @@ import { defineStore } from "pinia"; -import { ref , shallowRef } from "vue"; +import { ref, shallowRef } from "vue"; import { importFile } from "../helpers/import"; import { exportFile } from "../helpers/export"; import { usePlugins } from "../helpers/usePlugin"; import { insertChildNode } from "../helpers/insertChildNode"; import { insertSiblingNode } from "../helpers/insertSiblingNode"; import { removeNode } from "../helpers/removeNode"; +import { removeKeyCommand } from "../helpers/keyCommand"; +import { getCustomNodeContent } from "../helpers/addCustomContentToNode"; import type MindMapNode from "simple-mind-map/types/src/core/render/node/MindMapNode"; @@ -14,48 +16,62 @@ import MindMap from "simple-mind-map"; export const useMindMapStore = defineStore( "mindMapStore", () => { - let mindMapInstance : (MindMap | null) =null; + let mindMapInstance: MindMap | null = null; const mindMapData = ref(null); // 激活状态节点 - const activeNodes = shallowRef([]) - + const activeNodes = shallowRef([]); usePlugins(MindMap); function initMindMap(container: HTMLElement) { mindMapInstance = new MindMap({ el: container, - data : null, - layout: 'mindMap', + data: null, + layout: "mindMap", fit: false, nodeTextEditZIndex: 1000, nodeNoteTooltipZIndex: 1000, openRealtimeRenderOnNodeTextEdit: true, - enableAutoEnterTextEditWhenKeydown: true, - demonstrateConfig: { - openBlankMode: true + + isShowCreateChildBtnIcon: false, // 是否显示添加子节点按钮 + enableAutoEnterTextEditWhenKeydown: false, // 键盘输入时自动进入文本编辑 // .updateConfig({ 'openRealtimeRenderOnNodeTextEdit' : value}) + createNewNodeBehavior: "activeOnly", // 插入新节点的行为 // activeOnly - 只新建激活不编辑 + + + + customQuickCreateChildBtnClick: () => { + console.log("自定义添加按钮点击事件"); + }, + + isUseCustomNodeContent : true, // 是否使用自定义节点内容 + // 添加自定义节点内容 + addCustomContentToNode: getCustomNodeContent(), + + demonstrateConfig: { + openBlankMode: true, }, - }); // 监听节点激活事件 - mindMapInstance?.on('node_active', (_ : MindMapNode, activeNodeList : MindMapNode[]) => { - console.log('激活节点', activeNodeList); - activeNodes.value = activeNodeList - }) + mindMapInstance?.on( + "node_active", + (_: MindMapNode, activeNodeList: MindMapNode[]) => { + console.log("激活节点", activeNodeList); + activeNodes.value = activeNodeList; + } + ); + + // 关闭键盘事件 + removeKeyCommand(mindMapInstance); } - - - // 因为避免使用响应对象 - function getMindMapInstance (): MindMap | null { + function getMindMapInstance(): MindMap | null { return mindMapInstance; } - return { mindMapInstance, mindMapData, diff --git a/web3/packages/mind-map/src/types/index.d.ts b/web3/packages/mind-map/src/types/index.d.ts index 883a6b90..9368a7f5 100644 --- a/web3/packages/mind-map/src/types/index.d.ts +++ b/web3/packages/mind-map/src/types/index.d.ts @@ -31,4 +31,12 @@ declare module 'simple-mind-map/src/utils' { import * as utils from 'simple-mind-map/types/src/utils'; export = utils; } +declare module 'simple-mind-map/src/core/command/keyMap' { + import * as keyMap from 'simple-mind-map/types/src/core/command/keyMap'; + export = keyMap; +} +declare module 'simple-mind-map/src/plugins/RichText' { + import RichText from 'simple-mind-map/types/src/plugins/RichText'; + export default RichText; +}