diff --git a/src/components/Canvas/FlowCanvas/components/header-tools.vue b/src/components/Canvas/FlowCanvas/components/header-tools.vue index 10cffd2..7ef56c7 100644 --- a/src/components/Canvas/FlowCanvas/components/header-tools.vue +++ b/src/components/Canvas/FlowCanvas/components/header-tools.vue @@ -5,8 +5,8 @@ @@ -32,16 +32,36 @@ const stateManager = inject('stateManager') as any const toolManager = inject('toolManager') as any const tool = computed(() => stateManager.tool.value) + const historyIndex = computed(() => stateManager.historyIndex.value) + const historyList = computed(() => stateManager.historyList.value) + const isUndo = computed(() => !historyList.value[historyIndex.value - 1]) + const isRedo = computed(() => !historyList.value[historyIndex.value + 1]) const tools = ref([ - { name: TOOLS.SELECT, icon: 'c-select', iconSize: 16 }, - { name: TOOLS.MOVE, icon: 'c-move', iconSize: 18 }, - { name: TOOLS.TEXT, icon: 'c-text', iconSize: 18 }, + { name: TOOLS.SELECT, icon: 'c-select', iconSize: 16, disabled: ref(false) }, + { name: TOOLS.MOVE, icon: 'c-move', iconSize: 18, disabled: ref(false) }, + { name: TOOLS.TEXT, icon: 'c-text', iconSize: 18, disabled: ref(false) }, { type: 'line' }, - { name: TOOLS.UNDO, icon: 'c-undo', iconSize: 18 }, - { name: TOOLS.REDO, icon: 'c-redo', iconSize: 18 } + { + name: TOOLS.UNDO, + icon: 'c-undo', + iconSize: 18, + disabled: isUndo, + on: () => stateManager.undoState() + }, + { + name: TOOLS.REDO, + icon: 'c-redo', + iconSize: 18, + disabled: isRedo, + on: () => stateManager.redoState() + } ]) const onClickTool = (tool: any) => { - toolManager.setTool(tool) + if (tool.on) { + tool.on() + } else { + toolManager.setTool(tool.name) + } } @@ -79,10 +99,14 @@ height: 3rem; --svg-icon-color: #000; border-radius: 0.4rem; - &.active, - &:hover { + &:not(.disabled).active, + &:not(.disabled):hover { background-color: #dfdfdf; } + &.disabled { + opacity: 0.5; + cursor: not-allowed; + } } > button { width: 10rem; diff --git a/src/components/Canvas/FlowCanvas/manager/StateManager.ts b/src/components/Canvas/FlowCanvas/manager/StateManager.ts index 8cbb95b..049e844 100644 --- a/src/components/Canvas/FlowCanvas/manager/StateManager.ts +++ b/src/components/Canvas/FlowCanvas/manager/StateManager.ts @@ -16,9 +16,16 @@ export class StateManager { zoom: any tool: any cursor: any + // 节点是否可拖动 nodesDraggable: any + // 拖动时是否可以平移画布 panOnDrag: any + // 历史记录-撤回/重做 + mxHistory: any + historyList: any + historyIndex: any + // 管理器 eventManager: any flowManager: any @@ -38,17 +45,14 @@ export class StateManager { this.cursor = ref("") this.nodesDraggable = ref(false) this.panOnDrag = ref(false) + this.mxHistory = ref(50) + this.historyList = ref([]) + this.historyIndex = ref(0) + this.nodes = ref([]); this.nodes_ = computed(() => { return this.nodes.value.map((node, index) => { const obj = node; - // if (index === 0) { - // obj.type = NODE_TYPE.INPUT; - // } else if (index === this.nodes.value.length - 1) { - // obj.type = NODE_TYPE.OUTPUT; - // } else { - // obj.type = NODE_TYPE.SECONDARY; - // } const superiorID = node.data.superiorID; const isSuperior = this.nodes.value.some((v) => v.id === superiorID) const isSubord = this.nodes.value.some((v) => v.data.superiorID === node.id) @@ -68,17 +72,6 @@ export class StateManager { this.edges = computed(() => { const arr = [] this.nodes.value.forEach((node, index) => { - // if (index < this.nodes.value.length - 1) { - // const source = node.id - // const target = this.nodes.value[index + 1].id - // arr.push({ - // id: `el-${source}-${target}`, - // source: source, - // target: target, - // selectable: false, - // type: 'default' - // }) - // } const superiorID = node.data.superiorID; const isSuperior = this.nodes.value.some((v) => v.id === superiorID) if (superiorID && isSuperior) { @@ -99,28 +92,21 @@ export class StateManager { } /** 添加节点 */ addNode(node: NodesItem) { - this.nodes.value.push(node) + this.nodes.value.push(node); + this.recordState() } /** 删除节点 */ deleteNode(id: string) { this.nodes.value = this.nodes.value.filter((node: NodesItem) => node.id !== id) + this.recordState() } /** 获取节点 */ - getNodeById(id: string) { - return this.nodes.value.find((node: NodesItem) => node.id === id) - } + getNodeById(id: string) { return this.nodes.value.find((node: NodesItem) => node.id === id) } /** 获取下级节点 */ - getSubordNodeByID(id: string) { - return this.nodes.value.find((node: NodesItem) => node.data.superiorID === id) - } - getLastNode() { - return this.nodes.value[this.nodes.value.length - 1] - } + getSubordNodeByID(id: string) { return this.nodes.value.find((node: NodesItem) => node.data.superiorID === id) } + getLastNode() { return this.nodes.value[this.nodes.value.length - 1] } /** 设置工具 */ - setTool(tool: string) { - this.tool.value = tool - } - + setTool(tool: string) { this.tool.value = tool } /** 设置光标 */ setCursor(v: string) { this.cursor.value = v } /** 设置节点是否可拖动 */ @@ -128,11 +114,38 @@ export class StateManager { /** 设置是否可以平移画布 */ setPanOnDrag(v: boolean) { this.panOnDrag.value = v } /** 获取节点最大zIndex值 */ - getMaxZIndex() { - return this.nodes.value.reduce((max, node) => Math.max(max, node.zIndex), 0) - } + getMaxZIndex() { return this.nodes.value.reduce((max, node) => Math.max(max, node.zIndex), 0) } /** 获取节点最小zIndex值 */ - getMinZIndex() { - return this.nodes.value.reduce((min, node) => Math.min(min, node.zIndex), 0) + getMinZIndex() { return this.nodes.value.reduce((min, node) => Math.min(min, node.zIndex), 0) } + + /** 记录状态 */ + recordState() { + if (this.historyIndex.value < this.historyList.value.length - 1) { + this.historyList.value.splice(this.historyIndex.value) + } + const state = { + nodes: JSON.stringify(this.nodes.value) + } + this.historyList.value.push(state) + const size = this.historyList.value.length - this.mxHistory.value + if (size > 0) this.historyList.value.splice(0, size) + this.historyIndex.value = this.historyList.value.length - 1 } + /** 撤回状态 */ + undoState() { + var index = this.historyIndex.value - 1 + const state = this.historyList.value[index] + if (!state) return + this.historyIndex.value = index + this.nodes.value = JSON.parse(state.nodes) + } + /** 重做状态 */ + redoState() { + var index = this.historyIndex.value + 1 + const state = this.historyList.value[index] + if (!state) return + this.historyIndex.value = index + this.nodes.value = JSON.parse(state.nodes) + } + }