From 55fec479081ffb35de0db11e8f0ca39beee483b0 Mon Sep 17 00:00:00 2001 From: luoyifan Date: Fri, 30 May 2025 22:56:20 +0800 Subject: [PATCH] =?UTF-8?q?=E7=8A=B6=E6=80=81=E7=AE=A1=E7=90=86=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/designer/StateManager.ts | 203 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 179 insertions(+), 24 deletions(-) diff --git a/src/designer/StateManager.ts b/src/designer/StateManager.ts index 7be560e..91f3eeb 100644 --- a/src/designer/StateManager.ts +++ b/src/designer/StateManager.ts @@ -89,6 +89,12 @@ export default class StateManager { */ private lastSnapshot: Map = new Map() + // 自动保存相关 + private autoSaveInterval: number | null = null + private autoSaveIntervalMs = 5000 // 5秒自动保存 + private pendingChanges = false // 是否有待保存的更改 + private lastAutoSaveTime = 0 // 上次自动保存时间 + /** * @param id 唯一场景标识符, 用于做临时存储的 key * @param viewport 视口对象, 用于获取、同步当前场景的状态 @@ -99,7 +105,10 @@ export default class StateManager { this.viewport = markRaw(viewport) this.historyBufferSize = bufferSize // 初始化固定大小的历史缓冲区 - this.historySteps = new Array(this.maxHistorySteps) + this.historySteps = new Array(this.maxHistorySteps).fill(null) + + // 启动自动保存定时器 + this.startAutoSave() } /** @@ -108,7 +117,7 @@ export default class StateManager { beginUserWrite() { // 创建当前状态快照(非深拷贝) this.lastSnapshot = new Map( - this.vdata.items.map(item => [item.id, item]) + this.vdata.items.map(item => [item.id, _.cloneDeep(item)]) ) this.changeTracker = { added: [], removed: [], updated: [] } } @@ -121,6 +130,7 @@ export default class StateManager { this.saveStep() this.syncDataState() this.isChanged.value = true + this.pendingChanges = true // 标记有需要保存的更改 } @@ -178,7 +188,7 @@ export default class StateManager { } this.historyIndex = nextIndex - this.saveToLocalstore() + this.pendingChanges = true // 标记有需要保存的更改 } @@ -232,18 +242,34 @@ export default class StateManager { */ async load(items: VDataItem[]) { this.isLoading.value = true + this.historySteps = new Array(this.maxHistorySteps).fill(null) + this.historyIndex = -1 try { + // 停止自动保存,避免在加载过程中触发 + this.stopAutoSave() + // 直接替换数组引用(避免响应式开销) this.vdata.items = items + this.fullSync() // 同步到视口 // 初始状态作为第一步 this.beginUserWrite() this.endUserWrite() this.isChanged.value = false + this.pendingChanges = false + + // 强制保存一次初始状态 + await this.saveToLocalstore() + this.pendingChanges = false + + console.log('[StateManager] 加载完成,共 ', items.length, '个对象') + } finally { this.isLoading.value = false + // 重新启动自动保存 + this.startAutoSave() } } @@ -255,6 +281,20 @@ export default class StateManager { } /** + * 强制保存到本地存储 + */ + async forceSave() { + try { + await this.saveToLocalstore() + this.pendingChanges = false + return true + } catch (error) { + console.error('[StateManager] 强制保存失败:', error) + return false + } + } + + /** * 撤销 */ undo() { @@ -266,6 +306,7 @@ export default class StateManager { this.applyReverseDiff(step.diff) this.historyIndex = (this.historyIndex - 1 + this.maxHistorySteps) % this.maxHistorySteps this.isChanged.value = true + this.pendingChanges = true this.syncDataState() } @@ -281,6 +322,7 @@ export default class StateManager { this.applyDiff(step.diff) this.isChanged.value = true + this.pendingChanges = true this.syncDataState() } @@ -306,6 +348,8 @@ export default class StateManager { updateMap.has(item.id) ? updateMap.get(item.id)! : item ) } + + this.lastSnapshot = new Map(this.vdata.items.map(item => [item.id, _.cloneDeep(item)])) } /** @@ -340,47 +384,158 @@ export default class StateManager { restoreMap.has(item.id) ? restoreMap.get(item.id)! : item ) } + + this.lastSnapshot = new Map(this.vdata.items.map(item => [item.id, _.cloneDeep(item)])) } - /** - * 保存到本地存储(防止数据丢失) - */ - async saveToLocalstore() { - // 只保存变化部分和关键元数据 - const saveData = { - diff: this.changeTracker, - timestamp: Date.now(), - itemsCount: this.vdata.items.length - } + // /** + // * 保存到本地存储(防止数据丢失) + // */ + // async saveToLocalstore() { + // // 只保存变化部分和关键元数据 + // const saveData = { + // diff: this.changeTracker, + // timestamp: Date.now(), + // itemsCount: this.vdata.items.length + // } + // + // await localforage.setItem(`scene-tmp-${this.id}`, saveData) + // } + // + // /** + // * 从本地存储加载数据 + // */ + // async loadFromLocalstore() { + // try { + // this.isLoading.value = true + // const saved: any = await localforage.getItem(`scene-tmp-${this.id}`) + // if (saved && saved.diff) { + // this.applyDiff(saved.diff) + // this.isChanged.value = true + // this.pendingChanges = true + // console.log('[StateManager] 从本地存储恢复 ', saved.itemsCount, '个对象') + // } + // + // } catch (error) { + // console.error('[StateManager] 从本地存储加载失败:', error) + // + // } finally { + // this.isLoading.value = false + // } + // } - await localforage.setItem(`scene-tmp-${this.id}`, saveData) + async saveToLocalstore() { + await localforage.setItem(`scene-tmp-${this.id}`, this.vdata) } - /** - * 从本地存储加载数据 - */ async loadFromLocalstore() { - const saved: any = await localforage.getItem(`scene-tmp-${this.id}`) - if (saved && saved.diff) { - this.applyDiff(saved.diff) - this.isChanged.value = true + try { + this.isLoading.value = true + const saved: VData = await localforage.getItem(`scene-tmp-${this.id}`) + if (saved) { + this.vdata.items = saved.items || [] + this.isChanged.value = saved.isChanged || false + this.pendingChanges = true + this.fullSync() // 同步到视口 + console.log('[StateManager] 从本地存储恢复', this.vdata.items.length, '个对象') + } + + } catch (error) { + console.error('[StateManager] 从本地存储加载失败:', error) + } finally { + this.isLoading.value = false } } + private fullSync() { + this.viewport.beginSync() + this.vdata.items.forEach(item => { + this.viewport.syncOnAppend(item) + }) + this.viewport.endSync() + } + undoEnabled() { - return this.historyIndex >= 0 && this.historySteps[this.historyIndex] !== undefined + return this.historyIndex >= 0 && this.historySteps[this.historyIndex] } redoEnabled() { const nextIndex = (this.historyIndex + 1) % this.maxHistorySteps - return this.historySteps[nextIndex] !== undefined + return !!this.historySteps[nextIndex] } /** * 删除本地存储 */ async removeLocalstore() { - await localforage.removeItem(`scene-tmp-${this.id}`) + try { + await localforage.removeItem(`scene-tmp-${this.id}`) + console.log('[StateManager] 本地存储已清除') + } catch (error) { + console.error('[StateManager] 清除本地存储失败:', error) + } + } + + /** + * 启动自动保存定时器 + */ + startAutoSave() { + if (this.autoSaveInterval) return + + this.autoSaveInterval = window.setInterval(() => { + this.autoSaveIfNeeded() + }, this.autoSaveIntervalMs) + } + + /** + * 停止自动保存定时器 + */ + stopAutoSave() { + if (this.autoSaveInterval) { + clearInterval(this.autoSaveInterval) + this.autoSaveInterval = null + } + } + + /** + * 检查是否需要自动保存并执行 + */ + private async autoSaveIfNeeded() { + // 没有变化或正在加载时跳过 + if (!this.pendingChanges || this.isLoading.value) return + + try { + await this.saveToLocalstore() + this.pendingChanges = false + this.lastAutoSaveTime = Date.now() + console.debug(`[StateManager] 自动保存成功 at ${new Date().toLocaleTimeString()}`) + } catch (error) { + console.error('[StateManager] 自动保存失败:', error) + } + } + + /** + * 销毁资源 + */ + destroy() { + this.stopAutoSave() + this.removeLocalstore().catch(console.error) + // 清理引用 + this.viewport = null as any + this.vdata.items = [] + this.historySteps = [] + } + + /** + * 获取自动保存状态 + */ + getAutoSaveStatus() { + return { + enabled: this.autoSaveInterval !== null, + interval: this.autoSaveIntervalMs, + lastSaveTime: this.lastAutoSaveTime, + pendingChanges: this.pendingChanges + } } }