mirror of
https://github.com/palxiao/poster-design.git
synced 2025-07-15 16:02:19 +08:00
refactor: history stack
This commit is contained in:
parent
4e5b92ff77
commit
7c9441c264
@ -24,11 +24,10 @@
|
||||
- 元素拖拽、组合、缩放、层级调整、对齐等操作。
|
||||
- 图片素材插入、替换、裁剪,图片容器等功能。
|
||||
- SVG 素材颜色、透明度编辑,文字花字组合。
|
||||
- 画布自定义尺寸、滚轮缩放、自适应画布
|
||||
- 支持图层管理、多画板管理、自适应画布。
|
||||
- 吸附对齐、辅助引导线、标尺功能。
|
||||
- 键盘快捷键、右键菜单快捷操作,复制删除等常用操作。
|
||||
- 风格二维码编辑,支持单色、渐变、自定义 logo 等。
|
||||
- 图层操作,支持拖拽变更层级。
|
||||
- 颜色调色板,原生级取色器颜色吸管(Chrome)。
|
||||
|
||||
## 快速开始
|
||||
|
16
package-lock.json
generated
16
package-lock.json
generated
@ -22,6 +22,8 @@
|
||||
"element-plus": "^2.6.3",
|
||||
"fontfaceobserver": "^2.1.0",
|
||||
"html2canvas": "^1.4.1",
|
||||
"immer": "^10.0.4",
|
||||
"microdiff": "^1.4.0",
|
||||
"mitt": "^3.0.1",
|
||||
"moveable": "^0.26.0",
|
||||
"moveable-helper": "^0.4.0",
|
||||
@ -2674,6 +2676,15 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/immer": {
|
||||
"version": "10.0.4",
|
||||
"resolved": "https://registry.npmjs.org/immer/-/immer-10.0.4.tgz",
|
||||
"integrity": "sha512-cuBuGK40P/sk5IzWa9QPUaAdvPHjkk1c+xYsd9oZw+YQQEV+10G0P5uMpGctZZKnyQ+ibRO08bD25nWLmYi2pw==",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/immer"
|
||||
}
|
||||
},
|
||||
"node_modules/import-fresh": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||
@ -2991,6 +3002,11 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/microdiff": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/microdiff/-/microdiff-1.4.0.tgz",
|
||||
"integrity": "sha512-OBKBOa1VBznvLPb/3ljeJaENVe0fO0lnWl77lR4vhPlQD71UpjEoRV5P0KdQkcjbFlBu1Oy2mEUBMU3wxcBAGg=="
|
||||
},
|
||||
"node_modules/micromatch": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
|
||||
|
@ -25,6 +25,8 @@
|
||||
"element-plus": "^2.6.3",
|
||||
"fontfaceobserver": "^2.1.0",
|
||||
"html2canvas": "^1.4.1",
|
||||
"immer": "^10.0.4",
|
||||
"microdiff": "^1.4.0",
|
||||
"mitt": "^3.0.1",
|
||||
"moveable": "^0.26.0",
|
||||
"moveable-helper": "^0.4.0",
|
||||
|
@ -3,13 +3,11 @@
|
||||
* @Date: 2023-07-10 14:58:48
|
||||
* @Description: 拖拽优化
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2023-11-22 18:11:15
|
||||
* @LastEditTime: 2024-04-18 16:17:36
|
||||
*/
|
||||
|
||||
import { useControlStore, useWidgetStore } from "@/store"
|
||||
|
||||
// import store from '@/store'
|
||||
|
||||
type TInitial = {
|
||||
offsetX: number
|
||||
offsetY: number
|
||||
|
76
src/common/hooks/history.ts
Normal file
76
src/common/hooks/history.ts
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2024-04-18 16:10:07
|
||||
* @Description: 事件自动注册,WebWorker处理差分补丁,双栈记录
|
||||
* 事件自动注册的逻辑是鼠标事件黑名单,键盘事件白名单,跑一段时间看看实际情况如何
|
||||
* 差分补丁目前已知的问题是,对于预期以外的影响状态树的修改,现在都会写进历史记录,看起来就像多了一段毫无变化的历史栈一样
|
||||
* 例如图层的 left 在修改后可能为 12.6262638 但为了输入框中显示友好,在 input 组件中将自动格式化为 12.63,这个逻辑以前不会有问题,现在则不能这么做了
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-04-18 18:40:27
|
||||
*/
|
||||
import { onMounted } from 'vue'
|
||||
import WebWorker from '@/utils/plugins/webWorker'
|
||||
import { useHistoryStore, useWidgetStore } from '@/store'
|
||||
|
||||
const blackClass: string[] = ['operation-item', 'icon-undo', 'icon-redo']
|
||||
const whiteKey: string[] = ['ArrowLeft', 'ArrowDown', 'ArrowRight', 'ArrowUp', 'Backspace']
|
||||
|
||||
const historyStore = useHistoryStore()
|
||||
const widgetStore = useWidgetStore()
|
||||
const historyWorker = new WebWorker('history')
|
||||
let processing = false
|
||||
let historyTimer: any = null
|
||||
|
||||
function noPutHistory(target: any) {
|
||||
const classList = Array.from(target.classList)
|
||||
return classList.filter((v: any) => blackClass.includes(v)).length > 0
|
||||
}
|
||||
|
||||
export default () => {
|
||||
historyWorker.start(null, (changes: any) => {
|
||||
changes.patches.length > 0 && historyStore.changeHistory(changes)
|
||||
processing = false
|
||||
})
|
||||
onMounted(() => {
|
||||
document.addEventListener(
|
||||
'mousedown',
|
||||
(e: any) => {
|
||||
if (noPutHistory(e.target)) return
|
||||
historyWorker.send(!processing ? { op: 'diff', data: JSON.stringify(widgetStore.dLayouts) } : null)
|
||||
processing = true
|
||||
},
|
||||
false,
|
||||
)
|
||||
document.addEventListener(
|
||||
'mouseup',
|
||||
(e: any) => {
|
||||
if (noPutHistory(e.target)) return
|
||||
clearTimeout(historyTimer)
|
||||
historyTimer = setTimeout(() => {
|
||||
historyWorker.send({ op: 'done', data: JSON.stringify(widgetStore.dLayouts) })
|
||||
}, 150)
|
||||
},
|
||||
false,
|
||||
)
|
||||
document.addEventListener(
|
||||
'keydown',
|
||||
(e) => {
|
||||
if (!whiteKey.includes(e.key)) return
|
||||
historyWorker.send(!processing ? { op: 'diff', data: JSON.stringify(widgetStore.dLayouts) } : null)
|
||||
processing = true
|
||||
},
|
||||
false,
|
||||
)
|
||||
document.addEventListener(
|
||||
'keyup',
|
||||
(e) => {
|
||||
if (!whiteKey.includes(e.key)) return
|
||||
clearTimeout(historyTimer)
|
||||
historyTimer = setTimeout(() => {
|
||||
historyWorker.send({ op: 'done', data: JSON.stringify(widgetStore.dLayouts) })
|
||||
}, 150)
|
||||
},
|
||||
false,
|
||||
)
|
||||
})
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
/*
|
||||
* @Author: Jeremy-Yu
|
||||
* @Date: 2024-02-14 14:58:48
|
||||
* @Description: 同意处理vue3 Mapgetters 已废弃
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2023-11-22 18:11:15
|
||||
*/
|
||||
|
||||
// import { ComputedRef, computed } from 'vue'
|
||||
|
||||
|
||||
// export function useSetupMapGetters<T extends string>(strList: T[]) {
|
||||
// const mapData: Partial<{[x in T]: ComputedRef}> = {}
|
||||
// const getters = useStore().getters
|
||||
|
||||
// strList.forEach(val => {
|
||||
// mapData[val] = computed(() => getters[val])
|
||||
// })
|
||||
|
||||
// return mapData as {[x in T]: ComputedRef}
|
||||
// }
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2024-04-11 17:27:58
|
||||
* @Description: 多画板操作界面
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-04-17 11:53:48
|
||||
* @LastEditTime: 2024-04-18 17:12:34
|
||||
-->
|
||||
<template>
|
||||
<div :style="{ position, bottom: -1 * st + 'px', left: sl + 'px' }" :class="['artboards', isFold ? 'fold' : 'unfold']">
|
||||
@ -130,7 +130,7 @@ function addLayer() {
|
||||
controlStore.setShowMoveable(false) // 清理掉上一次的选择框
|
||||
widgetStore.dLayouts.push({ global: getInitPage(), layers: [] })
|
||||
canvasStore.dCurrentPage = dLayouts.value.length - 1
|
||||
widgetStore.setDWidgets(widgetStore.getWidgets)
|
||||
widgetStore.setDWidgets(widgetStore.getWidgets())
|
||||
canvasStore.setDPage(getInitPage())
|
||||
canvasStore.updateDPage()
|
||||
widgetStore.selectWidget({ uuid: '-1' })
|
||||
@ -139,7 +139,7 @@ function addLayer() {
|
||||
function selectPoster(i: number) {
|
||||
controlStore.setShowMoveable(false) // 清理掉上一次的选择框
|
||||
canvasStore.dCurrentPage = i
|
||||
widgetStore.setDWidgets(widgetStore.getWidgets)
|
||||
widgetStore.setDWidgets(widgetStore.getWidgets())
|
||||
canvasStore.setDPage(dLayouts.value[i].global)
|
||||
widgetStore.selectWidget({ uuid: '-1' })
|
||||
}
|
||||
|
@ -37,7 +37,6 @@ const state = reactive({
|
||||
active: true,
|
||||
})
|
||||
const clickClassify = (index: number) => {
|
||||
console.log('index' ,index)
|
||||
state.activeWidgetClassify = index
|
||||
state.active = true
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2022-03-09 16:29:54
|
||||
* @Description: 处理和ctrl建相关的操作
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-03-15 17:34:51
|
||||
* @LastEditTime: 2024-04-18 17:35:57
|
||||
*/
|
||||
// import store from '@/store'
|
||||
import handlePaste from './handlePaste'
|
||||
@ -85,16 +85,14 @@ function paste() {
|
||||
*/
|
||||
function undo(shiftKey: any) {
|
||||
const historyStore = useHistoryStore()
|
||||
console.log(historyStore.dHistoryParams);
|
||||
shiftKey ? historyStore.handleHistory("redo") : historyStore.handleHistory('undo')
|
||||
|
||||
if (shiftKey) {
|
||||
if (!(historyStore.dHistoryParams.index === historyStore.dHistoryParams.length - 1)) {
|
||||
historyStore.handleHistory("redo")
|
||||
// store.dispatch('handleHistory', 'redo')
|
||||
}
|
||||
} else if (historyStore.dHistoryParams.index !== -1) {
|
||||
// this.handleHistory('undo')
|
||||
historyStore.handleHistory('undo')
|
||||
// store.dispatch('handleHistory', 'undo')
|
||||
}
|
||||
// if (shiftKey) {
|
||||
// if (!(historyStore.dHistoryParams.index === historyStore.dHistoryParams.length - 1)) {
|
||||
// historyStore.handleHistory("redo")
|
||||
// }
|
||||
// } else if (historyStore.dHistoryParams.index !== -1) {
|
||||
// // this.handleHistory('undo')
|
||||
// historyStore.handleHistory('undo')
|
||||
// }
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
* @Date: 2024-03-18 21:00:00
|
||||
* @Description: 画布全局配置
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-04-16 12:16:25
|
||||
* @LastEditTime: 2024-04-18 15:02:09
|
||||
*/
|
||||
|
||||
import { Store, defineStore } from 'pinia'
|
||||
|
@ -2,40 +2,61 @@
|
||||
* @Author: Jeremy Yu
|
||||
* @Date: 2024-03-18 21:00:00
|
||||
* @Description:
|
||||
* @LastEditors: Jeremy Yu <https://github.com/JeremyYu-cn>
|
||||
* @LastEditTime: 2024-03-27 21:00:00
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-04-18 18:35:16
|
||||
*/
|
||||
|
||||
import { useControlStore, useCanvasStore, useWidgetStore } from "@/store"
|
||||
import { THistoryStore } from ".."
|
||||
import { useControlStore, useCanvasStore, useWidgetStore } from '@/store'
|
||||
import { THistoryStore } from '..'
|
||||
import { enablePatches, applyPatches } from 'immer'
|
||||
enablePatches()
|
||||
|
||||
export default function handleHistory(store: THistoryStore, action: "undo" | "redo") {
|
||||
export default function handleHistory(store: THistoryStore, action: 'undo' | 'redo') {
|
||||
const pageStore = useCanvasStore()
|
||||
const controlStore = useControlStore()
|
||||
const widgetStore = useWidgetStore()
|
||||
controlStore.setShowMoveable(false) // 清理掉上一次的选择框
|
||||
// store.commit('setShowMoveable', false) // 清理掉上一次的选择框
|
||||
const history = store.dHistory
|
||||
const pageHistory = store.dPageHistory
|
||||
// controlStore.setShowMoveable(false) // 清理掉上一次的选择框
|
||||
// // store.commit('setShowMoveable', false) // 清理掉上一次的选择框
|
||||
// const history = store.dHistory
|
||||
// const pageHistory = store.dPageHistory
|
||||
const historyParams = store.dHistoryParams
|
||||
if (action === 'undo') {
|
||||
historyParams.index -= 1 // 下标向前移1 撤销
|
||||
console.log(historyParams.index)
|
||||
if (historyParams.index > -1) {
|
||||
widgetStore.setDWidgets(JSON.parse(history[historyParams.index]))
|
||||
pageStore.setDPage(JSON.parse(pageHistory[historyParams.index]))
|
||||
}
|
||||
} else if (action === 'redo') {
|
||||
historyParams.index += 1 // 下标向后移1 重做
|
||||
// 如果下标小于历史记录列表长度,直接取出历史记录
|
||||
// if (historyParams.index < historyParams.length) {
|
||||
widgetStore.setDWidgets(JSON.parse(history[historyParams.index]))
|
||||
pageStore.setDPage(JSON.parse(pageHistory[historyParams.index]))
|
||||
// } else {
|
||||
// // 否则设置下标为列表最后一项
|
||||
// historyParams.index = historyParams.length - 1
|
||||
// store.state.dWidgets = JSON.parse(history[historyParams.index])
|
||||
// store.state.dPage = JSON.parse(pageHistory[historyParams.index + 1])
|
||||
// }
|
||||
const { changes, inverseChanges } = store.dHistoryStack
|
||||
let index = historyParams.stackPointer
|
||||
const curLayouts = JSON.parse(JSON.stringify(widgetStore.dLayouts))
|
||||
switch (action) {
|
||||
case 'undo':
|
||||
if (inverseChanges.length > 0 && index >= 0) {
|
||||
const newLayouts = applyPatches(curLayouts, inverseChanges[index])
|
||||
widgetStore.setDLayouts(JSON.parse(JSON.stringify(newLayouts)))
|
||||
historyParams.stackPointer--
|
||||
}
|
||||
break
|
||||
case 'redo':
|
||||
if (changes.length > 0 && index !== changes.length - 1) {
|
||||
historyParams.stackPointer++
|
||||
const newLayouts = applyPatches(curLayouts, changes[index + 1])
|
||||
widgetStore.setDLayouts(JSON.parse(JSON.stringify(newLayouts)))
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
// if (action === 'undo') {
|
||||
// historyParams.index -= 1 // 下标向前移1 撤销
|
||||
// console.log(historyParams.index)
|
||||
// if (historyParams.index > -1) {
|
||||
// widgetStore.setDWidgets(JSON.parse(history[historyParams.index]))
|
||||
// pageStore.setDPage(JSON.parse(pageHistory[historyParams.index]))
|
||||
// }
|
||||
// } else if (action === 'redo') {
|
||||
// historyParams.index += 1 // 下标向后移1 重做
|
||||
// // 如果下标小于历史记录列表长度,直接取出历史记录
|
||||
// // if (historyParams.index < historyParams.length) {
|
||||
// widgetStore.setDWidgets(JSON.parse(history[historyParams.index]))
|
||||
// pageStore.setDPage(JSON.parse(pageHistory[historyParams.index]))
|
||||
// // } else {
|
||||
// // // 否则设置下标为列表最后一项
|
||||
// // historyParams.index = historyParams.length - 1
|
||||
// // store.state.dWidgets = JSON.parse(history[historyParams.index])
|
||||
// // store.state.dPage = JSON.parse(pageHistory[historyParams.index + 1])
|
||||
// // }
|
||||
// }
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2024-03-18 21:00:00
|
||||
* @Description:
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-04-02 21:10:53
|
||||
* @LastEditTime: 2024-04-18 18:17:13
|
||||
*/
|
||||
|
||||
import { useCanvasStore, useWidgetStore } from "@/store"
|
||||
@ -11,25 +11,27 @@ import { THistoryStore } from ".."
|
||||
|
||||
/** push操作历史记录 */
|
||||
export function pushHistory(store: THistoryStore, msg: string = "") {
|
||||
const pageStore = useCanvasStore()
|
||||
const widgetStore = useWidgetStore()
|
||||
console.log('history压栈', '来源: ' + msg)
|
||||
// 如果有上一次记录,并且与新纪录相同,那么不继续操作
|
||||
if (store.dHistory[store.dHistory.length - 1] && store.dHistory[store.dHistory.length - 1] === JSON.stringify(widgetStore.dWidgets)) {
|
||||
return
|
||||
}
|
||||
if (store.dHistoryParams.index < history.length - 1) {
|
||||
const index = store.dHistoryParams.index + 1
|
||||
const len = history.length - index
|
||||
store.dHistory.splice(index, len)
|
||||
store.dPageHistory.splice(index, len)
|
||||
store.dHistoryParams.length = store.dHistory.length
|
||||
store.dHistoryParams.index = store.dHistory.length - 1
|
||||
}
|
||||
store.dHistory.push(JSON.stringify(widgetStore.dWidgets))
|
||||
store.dPageHistory.push(JSON.stringify(pageStore.dPage))
|
||||
store.dHistoryParams.index = store.dHistory.length - 1
|
||||
store.dHistoryParams.length = store.dHistory.length
|
||||
console.error('历史记录功能已重构,该方法即将移除:pushHistory');
|
||||
|
||||
// const pageStore = useCanvasStore()
|
||||
// const widgetStore = useWidgetStore()
|
||||
// console.log('history压栈', '来源: ' + msg)
|
||||
// // 如果有上一次记录,并且与新纪录相同,那么不继续操作
|
||||
// if (store.dHistory[store.dHistory.length - 1] && store.dHistory[store.dHistory.length - 1] === JSON.stringify(widgetStore.dWidgets)) {
|
||||
// return
|
||||
// }
|
||||
// if (store.dHistoryParams.index < history.length - 1) {
|
||||
// const index = store.dHistoryParams.index + 1
|
||||
// const len = history.length - index
|
||||
// store.dHistory.splice(index, len)
|
||||
// store.dPageHistory.splice(index, len)
|
||||
// store.dHistoryParams.length = store.dHistory.length
|
||||
// store.dHistoryParams.index = store.dHistory.length - 1
|
||||
// }
|
||||
// store.dHistory.push(JSON.stringify(widgetStore.dWidgets))
|
||||
// store.dPageHistory.push(JSON.stringify(pageStore.dPage))
|
||||
// store.dHistoryParams.index = store.dHistory.length - 1
|
||||
// store.dHistoryParams.length = store.dHistory.length
|
||||
}
|
||||
|
||||
/** 添加颜色选择历史记录 */
|
||||
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2024-03-18 21:00:00
|
||||
* @Description:
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-04-15 16:53:51
|
||||
* @LastEditTime: 2024-04-18 15:41:25
|
||||
*/
|
||||
|
||||
import { Store, defineStore } from 'pinia'
|
||||
@ -15,6 +15,11 @@ export type THistoryParamData = {
|
||||
index: number
|
||||
length: number
|
||||
maxLength: number
|
||||
stackPointer: number
|
||||
}
|
||||
export type THsitoryStack = {
|
||||
changes: any[]
|
||||
inverseChanges: any[]
|
||||
}
|
||||
|
||||
type THistoryState = {
|
||||
@ -22,18 +27,18 @@ type THistoryState = {
|
||||
dHistory: string[]
|
||||
/** 记录历史操作对应的page */
|
||||
dPageHistory: string[]
|
||||
/** 记录差分补丁 */
|
||||
dHistoryStack: THsitoryStack
|
||||
/** 记录指针等数据 */
|
||||
dHistoryParams: THistoryParamData
|
||||
/** 记录历史选择的颜色 */
|
||||
dColorHistory: string[]
|
||||
}
|
||||
|
||||
type THistoryAction = {
|
||||
/**
|
||||
* 保存操作历史,
|
||||
* 修改数据、移动完成后都会自动保存
|
||||
* 同时会保存当前激活的组件的uuid,方便撤回时自动激活
|
||||
*/
|
||||
pushHistory: (msg?: string) => void
|
||||
/** 写入历史记录 */
|
||||
changeHistory: (patches: any) => void
|
||||
/**
|
||||
* 操作历史记录
|
||||
* action为undo表示撤销
|
||||
@ -51,6 +56,11 @@ const HistoryStore = defineStore<'historyStore', THistoryState, {}, THistoryActi
|
||||
index: -1,
|
||||
length: 0,
|
||||
maxLength: 20,
|
||||
stackPointer: -1
|
||||
},
|
||||
dHistoryStack: {
|
||||
changes: [],
|
||||
inverseChanges: [],
|
||||
},
|
||||
dColorHistory: [],
|
||||
dPageHistory: [],
|
||||
@ -60,12 +70,18 @@ const HistoryStore = defineStore<'historyStore', THistoryState, {}, THistoryActi
|
||||
pushHistory(msg) {
|
||||
pushHistory(this, msg)
|
||||
},
|
||||
changeHistory({ patches, inversePatches }) {
|
||||
const pointer = ++this.dHistoryParams.stackPointer
|
||||
// 如若之前撤销过,当新增记录时,后面的记录就清空了
|
||||
this.dHistoryStack.changes.length = pointer
|
||||
this.dHistoryStack.inverseChanges.length = pointer
|
||||
this.dHistoryStack.changes[pointer] = patches
|
||||
this.dHistoryStack.inverseChanges[pointer] = inversePatches
|
||||
},
|
||||
handleHistory(action) {
|
||||
const widgetStore = useWidgetStore()
|
||||
const pageStore = useCanvasStore()
|
||||
handleHistory(this, action)
|
||||
// 激活组件默认为page
|
||||
widgetStore.setdActiveElement(pageStore.dPage)
|
||||
// TODO: 操作后如果当前选中元素还在,则应当保留选择框
|
||||
// widgetStore.setdActiveElement(pageStore.dPage)
|
||||
},
|
||||
pushColorToHistory(color) {
|
||||
pushColorToHistory(this, color)
|
||||
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2024-03-28 21:00:00
|
||||
* @Description:
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-04-16 11:12:40
|
||||
* @LastEditTime: 2024-04-18 18:49:09
|
||||
*/
|
||||
|
||||
import { useCanvasStore, useHistoryStore } from '@/store'
|
||||
@ -240,11 +240,21 @@ export function setDWidgets(state: TWidgetStore, e: TdWidgetData[]) {
|
||||
updateDWidgets(state)
|
||||
}
|
||||
|
||||
export function setDLayouts(state: TWidgetStore, data: any[]) {
|
||||
state.dLayouts = data
|
||||
state.dWidgets = state.getWidgets()
|
||||
const pageStore = useCanvasStore()
|
||||
pageStore.setDPage(data[pageStore.dCurrentPage].global)
|
||||
setTimeout(() => {
|
||||
state.dActiveElement = pageStore.dPage
|
||||
}, 150);
|
||||
}
|
||||
|
||||
export function updateDWidgets(state: TWidgetStore) {
|
||||
const pageStore = useCanvasStore()
|
||||
const { dCurrentPage } = pageStore
|
||||
state.dLayouts[dCurrentPage].layers = state.dWidgets
|
||||
state.dWidgets = state.getWidgets
|
||||
state.dWidgets = state.getWidgets()
|
||||
}
|
||||
|
||||
// 锁定所有图层 / 再次调用时还原图层
|
||||
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2024-03-28 14:00:00
|
||||
* @Description:
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-04-15 16:54:45
|
||||
* @LastEditTime: 2024-04-18 15:14:48
|
||||
*/
|
||||
|
||||
import { useCanvasStore } from '@/store'
|
||||
@ -17,7 +17,7 @@ export type TWidgetJsonData = TPageState & {
|
||||
/** 返回组件Json数据 */
|
||||
export function widgetJsonData(state: TWidgetState) {
|
||||
const pageStore = useCanvasStore()
|
||||
const { dCurrentPage } = pageStore
|
||||
// const page: TWidgetJsonData = JSON.parse(JSON.stringify(pageStore.dPage))
|
||||
return state.dLayouts[dCurrentPage].layers
|
||||
!state.dLayouts[pageStore.dCurrentPage] && pageStore.dCurrentPage--
|
||||
return state.dLayouts[pageStore.dCurrentPage].layers
|
||||
}
|
||||
|
@ -3,20 +3,21 @@
|
||||
* @Date: 2024-03-18 21:00:00
|
||||
* @Description: Store方法export
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-04-16 10:07:13
|
||||
* @LastEditTime: 2024-04-18 17:11:51
|
||||
*/
|
||||
|
||||
import { Store, defineStore } from "pinia";
|
||||
import { useCanvasStore } from '@/store'
|
||||
import { TInidDMovePayload, TMovePayload, dMove, initDMove, setDropOver, setMouseEvent, setdActiveElement, updateGroupSize, updateHoverUuid } from "./actions";
|
||||
import { TPageState } from "@/store/design/canvas/d";
|
||||
import { TInitResize, TSize, TdResizePayload, dResize, initDResize, resize, autoResizeAll } from "./actions/resize";
|
||||
import { TUpdateWidgetMultiplePayload, TUpdateWidgetPayload, TsetWidgetStyleData, addWidget, deleteWidget, setDWidgets, updateDWidgets, setWidgetStyle, updateWidgetData, updateWidgetMultiple, lockWidgets } from "./actions/widget";
|
||||
import { TUpdateWidgetMultiplePayload, TUpdateWidgetPayload, TsetWidgetStyleData, addWidget, deleteWidget, setDWidgets, updateDWidgets, setWidgetStyle, updateWidgetData, updateWidgetMultiple, lockWidgets, setDLayouts } from "./actions/widget";
|
||||
import { addGroup } from "./actions/group";
|
||||
import { setTemplate } from "./actions/template";
|
||||
import { copyWidget, pasteWidget } from "./actions/clone";
|
||||
import { TSelectWidgetData, TselectItem, selectItem, selectWidget, selectWidgetsInOut } from "./actions/select";
|
||||
import { TUpdateAlignData, updateAlign } from "./actions/align";
|
||||
import { TWidgetJsonData, widgetJsonData } from "./getter";
|
||||
// import { TWidgetJsonData, widgetJsonData } from "./getter";
|
||||
import { TupdateLayerIndexData, ungroup, updateLayerIndex } from "./actions/layer";
|
||||
import pageDefault from "../canvas/page-default";
|
||||
|
||||
@ -80,7 +81,7 @@ export type TWidgetState = {
|
||||
}
|
||||
|
||||
type TGetter = {
|
||||
getWidgets(state: TWidgetState): TWidgetJsonData
|
||||
// getWidgets(state: TWidgetState): TWidgetJsonData
|
||||
}
|
||||
|
||||
type TAction = {
|
||||
@ -124,11 +125,13 @@ type TAction = {
|
||||
resize: (data: TSize) => void
|
||||
setWidgetStyle: (data: TsetWidgetStyleData) => void
|
||||
setDWidgets: (data: TdWidgetData[]) => void
|
||||
setDLayouts: (data: TdLayout) => void
|
||||
updateDWidgets: () => void
|
||||
lockWidgets: () => void
|
||||
setMouseEvent: (e: MouseEvent | null) => void
|
||||
setdActiveElement: (data: TdWidgetData) => void
|
||||
autoResizeAll: (data: TSize) => void
|
||||
getWidgets: () => TdWidgetData[]
|
||||
}
|
||||
|
||||
const WidgetStore = defineStore<"widgetStore", TWidgetState, TGetter, TAction>("widgetStore", {
|
||||
@ -160,11 +163,11 @@ const WidgetStore = defineStore<"widgetStore", TWidgetState, TGetter, TAction>("
|
||||
dCopyElement: [], // 复制的组件(可能是单个也可能是数组)
|
||||
}),
|
||||
|
||||
getters: {
|
||||
getWidgets(store) {
|
||||
return widgetJsonData(store)
|
||||
}
|
||||
},
|
||||
// getters: {
|
||||
// getWidgets(store) {
|
||||
// return widgetJsonData(store)
|
||||
// }
|
||||
// },
|
||||
|
||||
actions: {
|
||||
initDMove(payload) { initDMove(this, payload) },
|
||||
@ -195,7 +198,13 @@ const WidgetStore = defineStore<"widgetStore", TWidgetState, TGetter, TAction>("
|
||||
lockWidgets() { lockWidgets(this) },
|
||||
setMouseEvent(event) { setMouseEvent(this, event) },
|
||||
setdActiveElement(data) { setdActiveElement(this, data) },
|
||||
autoResizeAll(data) { autoResizeAll(this, data) }
|
||||
autoResizeAll(data) { autoResizeAll(this, data) },
|
||||
setDLayouts(data) { setDLayouts(this, data) },
|
||||
getWidgets() {
|
||||
const pageStore = useCanvasStore()
|
||||
!this.dLayouts[pageStore.dCurrentPage] && pageStore.dCurrentPage--
|
||||
return this.dLayouts[pageStore.dCurrentPage].layers
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -2,8 +2,8 @@
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2022-03-06 13:53:30
|
||||
* @Description: 计算密集型任务
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>, Jeremy Yu <https://github.com/JeremyYu-cn>
|
||||
* @LastEditTime: 2024-03-05 12:00:00
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-04-17 15:58:53
|
||||
*/
|
||||
export default class WebWorker {
|
||||
private worker: Worker | undefined
|
||||
@ -19,17 +19,20 @@ export default class WebWorker {
|
||||
}))
|
||||
}
|
||||
}
|
||||
public start(data: any) {
|
||||
public start(data?: any, cb?: Function) {
|
||||
return new Promise((resolve) => {
|
||||
if (!this.worker) resolve('')
|
||||
else {
|
||||
// 监听Web Worker的消息
|
||||
this.worker.onmessage = (e) => {
|
||||
resolve(e.data)
|
||||
cb ? cb(e.data) : resolve(e.data)
|
||||
}
|
||||
// 发送数据给Web Worker
|
||||
this.worker.postMessage(data)
|
||||
}
|
||||
})
|
||||
}
|
||||
public send(data?: any) {
|
||||
this.worker?.postMessage(data)
|
||||
}
|
||||
}
|
||||
|
42
src/utils/widgets/history.worker.ts
Normal file
42
src/utils/widgets/history.worker.ts
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2023-09-14 11:33:44
|
||||
* @Description: 历史记录处理
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-04-18 13:59:47
|
||||
*/
|
||||
import diff from 'microdiff'
|
||||
import { produce, applyPatches, enablePatches } from 'immer'
|
||||
enablePatches()
|
||||
const ops: any = {
|
||||
CHANGE: 'replace',
|
||||
CREATE: 'add',
|
||||
REMOVE: 'remove',
|
||||
}
|
||||
let cloneData = ''
|
||||
onmessage = async (e) => {
|
||||
if (!e.data) {
|
||||
return
|
||||
}
|
||||
if (e.data.op === 'done') {
|
||||
if (!cloneData) return
|
||||
let fork = JSON.parse(cloneData)
|
||||
let curArray = JSON.parse(e.data.data)
|
||||
// 比较数据差异
|
||||
let diffData: any = diff(fork, curArray)
|
||||
// 生成差分补丁
|
||||
fork = produce(
|
||||
fork,
|
||||
(draft) => {
|
||||
for (const d of diffData) {
|
||||
d.op = ops[d.type]
|
||||
}
|
||||
draft = applyPatches(draft, diffData)
|
||||
},
|
||||
(patches, inversePatches) => {
|
||||
self.postMessage({ patches, inversePatches })
|
||||
},
|
||||
)
|
||||
cloneData = ''
|
||||
} else cloneData = e.data.data
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
* @Description:
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastUpdateContent: Support typescript
|
||||
* @LastEditTime: 2024-04-16 11:35:11
|
||||
* @LastEditTime: 2024-04-18 18:14:36
|
||||
-->
|
||||
<template>
|
||||
<div id="page-design-index" ref="pageDesignIndex" class="page-design-bg-color">
|
||||
@ -89,6 +89,8 @@ import type { ButtonInstance } from 'element-plus'
|
||||
import Tour from './components/Tour.vue'
|
||||
import createDesign from '@/components/business/create-design'
|
||||
import multipleBoards from '@/components/modules/layout/multipleBoards'
|
||||
import useHistory from '@/common/hooks/history'
|
||||
useHistory()
|
||||
|
||||
const ref1 = ref<ButtonInstance>()
|
||||
const ref2 = ref<ButtonInstance>()
|
||||
@ -113,7 +115,7 @@ const historyStore = useHistoryStore()
|
||||
const groupStore = useGroupStore()
|
||||
const { dPage } = storeToRefs(useCanvasStore())
|
||||
const { dZoom } = storeToRefs(useCanvasStore())
|
||||
const { dHistoryParams } = storeToRefs(useHistoryStore())
|
||||
const { dHistoryParams, dHistoryStack } = storeToRefs(useHistoryStore())
|
||||
|
||||
const state = reactive<TState>({
|
||||
style: {
|
||||
@ -149,13 +151,14 @@ function jump2home() {
|
||||
}
|
||||
|
||||
const undoable = computed(() => {
|
||||
return !(
|
||||
dHistoryParams.value.index === -1 ||
|
||||
(dHistoryParams.value.index === 0 && dHistoryParams.value.length === dHistoryParams.value.maxLength))
|
||||
return dHistoryParams.value.stackPointer >= 0
|
||||
// return !(
|
||||
// dHistoryParams.value.index === -1 ||
|
||||
// (dHistoryParams.value.index === 0 && dHistoryParams.value.length === dHistoryParams.value.maxLength))
|
||||
})
|
||||
|
||||
const redoable = computed(() => {
|
||||
return !(dHistoryParams.value.index === dHistoryParams.value.length - 1)
|
||||
return !(dHistoryParams.value.stackPointer === dHistoryStack.value.changes.length - 1)
|
||||
})
|
||||
|
||||
function zoomSub() {
|
||||
@ -195,11 +198,9 @@ onBeforeUnmount(() => {
|
||||
document.removeEventListener('keyup', handleKeyup(controlStore, checkCtrl), false)
|
||||
document.oncontextmenu = null
|
||||
})
|
||||
// ...mapActions(['selectWidget', 'initGroupJson', 'handleHistory']),
|
||||
|
||||
function handleHistory(data: "undo" | "redo") {
|
||||
historyStore.handleHistory(data)
|
||||
// store.dispatch('handleHistory', data)
|
||||
}
|
||||
|
||||
function changeLineGuides() {
|
||||
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2022-01-12 11:26:53
|
||||
* @Description: 顶部操作按钮组
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-04-16 15:38:39
|
||||
* @LastEditTime: 2024-04-18 17:13:24
|
||||
-->
|
||||
<template>
|
||||
<div class="top-title"><el-input v-model="state.title" placeholder="未命名的设计" class="input-wrap" /></div>
|
||||
@ -221,10 +221,10 @@ async function load(cb: () => void) {
|
||||
} else {
|
||||
if (Array.isArray(data)) {
|
||||
widgetStore.dLayouts = data
|
||||
widgetStore.setDWidgets(widgetStore.getWidgets)
|
||||
widgetStore.setDWidgets(widgetStore.getWidgets())
|
||||
} else {
|
||||
widgetStore.dLayouts = [{global: data.page, layers: data.widgets}]
|
||||
id ? widgetStore.setDWidgets(widgetStore.getWidgets) : widgetStore.setTemplate(widgetStore.getWidgets)
|
||||
id ? widgetStore.setDWidgets(widgetStore.getWidgets()) : widgetStore.setTemplate(widgetStore.getWidgets())
|
||||
}
|
||||
pageStore.setDPage(pageStore.getDPage)
|
||||
// id ? widgetStore.setDWidgets(data.widgets) : widgetStore.setTemplate(data.widgets)
|
||||
|
Loading…
x
Reference in New Issue
Block a user