|
|
@ -7,14 +7,13 @@ import type Viewport from '@/core/engine/Viewport.ts' |
|
|
// 差异类型定义
|
|
|
// 差异类型定义
|
|
|
interface DataDiff { |
|
|
interface DataDiff { |
|
|
added: ItemJson[] |
|
|
added: ItemJson[] |
|
|
removed: string[] |
|
|
removed: ItemJson[] |
|
|
updated: ItemJson[] |
|
|
updated: { before: ItemJson; after: ItemJson }[] |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 历史记录项
|
|
|
// 历史记录项
|
|
|
interface HistoryStep { |
|
|
interface HistoryStep { |
|
|
diff: DataDiff |
|
|
diff: DataDiff |
|
|
snapshot: Map<string, ItemJson> |
|
|
|
|
|
timestamp: number |
|
|
timestamp: number |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -35,11 +34,24 @@ interface HistoryStep { |
|
|
* 主要难点: |
|
|
* 主要难点: |
|
|
* - 单张地图数据量可能超过 10000 个对象, 需要高效的管理数据状态 |
|
|
* - 单张地图数据量可能超过 10000 个对象, 需要高效的管理数据状态 |
|
|
* |
|
|
* |
|
|
* // 修改坐标点
|
|
|
* // 用例1, 修改
|
|
|
* stateManager.beginStateUpdate();stateManager.vdata.items[1].tf[0] = [-10, 0, 4];stateManager.endStateUpdate(); |
|
|
* stateManager.beginStateUpdate();stateManager.vdata.items[1].tf[0] = [-10, 0, 4];stateManager.endStateUpdate(); |
|
|
|
|
|
* stateManager.undo() |
|
|
|
|
|
* stateManager.redo() |
|
|
|
|
|
* |
|
|
|
|
|
* // 用例2 添加
|
|
|
|
|
|
* stateManager.beginStateUpdate(); |
|
|
|
|
|
* stateManager.vdata.items[3].dt.center.push('p5'); |
|
|
|
|
|
* stateManager.vdata.items.push({ id: 'p5', t: 'measure', tf: [[-6.0, 0, 8], [0, 0, 0], [0.25, 0.1, 0.25]], dt: { center: ['p4'] } }); |
|
|
|
|
|
* stateManager.endStateUpdate(); |
|
|
|
|
|
* |
|
|
|
|
|
* stateManager.undo(); |
|
|
|
|
|
* stateManager.redo(); |
|
|
* |
|
|
* |
|
|
* // 撤销操作
|
|
|
* // 用例3 删除
|
|
|
|
|
|
* stateManager.beginStateUpdate(); stateManager.vdata.items.splice(3, 1); stateManager.endStateUpdate(); |
|
|
* stateManager.undo() |
|
|
* stateManager.undo() |
|
|
|
|
|
* stateManager.redo() |
|
|
* |
|
|
* |
|
|
*/ |
|
|
*/ |
|
|
export default class StateManager { |
|
|
export default class StateManager { |
|
|
@ -76,10 +88,9 @@ export default class StateManager { |
|
|
private historySteps: HistoryStep[] = [] |
|
|
private historySteps: HistoryStep[] = [] |
|
|
private historyIndex = -1 |
|
|
private historyIndex = -1 |
|
|
private readonly maxHistorySteps = 20 |
|
|
private readonly maxHistorySteps = 20 |
|
|
private readonly historyBufferSize: number |
|
|
|
|
|
|
|
|
|
|
|
// 变化追踪器
|
|
|
// 变化追踪器
|
|
|
private changeTracker: DataDiff = { |
|
|
private readonly changeTracker: DataDiff = { |
|
|
added: [], |
|
|
added: [], |
|
|
removed: [], |
|
|
removed: [], |
|
|
updated: [] |
|
|
updated: [] |
|
|
@ -88,13 +99,12 @@ export default class StateManager { |
|
|
/** |
|
|
/** |
|
|
* 数据快照(用于差异计算) |
|
|
* 数据快照(用于差异计算) |
|
|
*/ |
|
|
*/ |
|
|
private lastSnapshot: Map<string, ItemJson> = new Map() |
|
|
private lastStateDict = new Map<string, ItemJson>() |
|
|
|
|
|
|
|
|
// 自动保存相关
|
|
|
// 自动保存相关
|
|
|
private autoSaveInterval: number | null = null |
|
|
private autoSaveInterval: number | null = null |
|
|
private autoSaveIntervalMs = 5000 // 5秒自动保存
|
|
|
// 是否有待保存的更改
|
|
|
private pendingChanges = false // 是否有待保存的更改
|
|
|
private pendingChanges = false |
|
|
private lastAutoSaveTime = 0 // 上次自动保存时间
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* @param id 唯一场景标识符, 用于做临时存储的 key |
|
|
* @param id 唯一场景标识符, 用于做临时存储的 key |
|
|
@ -106,22 +116,18 @@ export default class StateManager { |
|
|
this.storeKey = `-tmp-yvan-lcc-${this.id}` |
|
|
this.storeKey = `-tmp-yvan-lcc-${this.id}` |
|
|
this.entityManager = viewport.entityManager |
|
|
this.entityManager = viewport.entityManager |
|
|
|
|
|
|
|
|
this.historyBufferSize = bufferSize |
|
|
// this.historySteps = Array.from({ length: this.maxHistorySteps }, () => null)
|
|
|
// 初始化固定大小的历史缓冲区
|
|
|
this.historySteps = [] |
|
|
this.historySteps = new Array(this.maxHistorySteps).fill(null) |
|
|
|
|
|
|
|
|
|
|
|
// 启动自动保存定时器
|
|
|
|
|
|
this.startAutoSave() |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* 开始用户操作(创建数据快照) |
|
|
* 开始用户操作(创建数据快照) |
|
|
*/ |
|
|
*/ |
|
|
beginStateUpdate() { |
|
|
beginStateUpdate() { |
|
|
this.lastSnapshot = new Map( |
|
|
this.lastStateDict = new Map(this.vdata.items.map(item => [item.id, _.cloneDeep(item)])) |
|
|
this.vdata.items.map(item => [item.id, _.cloneDeep(item)]) |
|
|
this.changeTracker.added.length = 0 |
|
|
) |
|
|
this.changeTracker.removed.length = 0 |
|
|
this.changeTracker = { added: [], removed: [], updated: [] } |
|
|
this.changeTracker.updated.length = 0 |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
@ -130,42 +136,50 @@ export default class StateManager { |
|
|
endStateUpdate() { |
|
|
endStateUpdate() { |
|
|
this.calculateDiff() |
|
|
this.calculateDiff() |
|
|
this.saveStep() |
|
|
this.saveStep() |
|
|
this.syncDataState() |
|
|
this.syncDataState(this.changeTracker) |
|
|
this.isChanged.value = true |
|
|
this.isChanged.value = true |
|
|
this.pendingChanges = true // 标记有需要保存的更改
|
|
|
this.pendingChanges = true // 标记有需要保存的更改
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 差异反转方法
|
|
|
|
|
|
private invertDiff(diff: DataDiff): DataDiff { |
|
|
|
|
|
return { |
|
|
|
|
|
added: diff.removed, |
|
|
|
|
|
removed: diff.added, |
|
|
|
|
|
updated: diff.updated.map(u => ({ before: u.after, after: u.before })) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
// 计算当前状态与快照的差异
|
|
|
* 计算当前状态与快照的差异 |
|
|
|
|
|
*/ |
|
|
|
|
|
private calculateDiff() { |
|
|
private calculateDiff() { |
|
|
const currentMap = new Map( |
|
|
const currentMap = new Map(this.vdata.items.map(item => [item.id, item])) |
|
|
this.vdata.items.map(item => [item.id, item]) |
|
|
const added: ItemJson[] = [] |
|
|
) |
|
|
const removed: ItemJson[] = [] |
|
|
|
|
|
const updated: { before: ItemJson; after: ItemJson }[] = [] |
|
|
|
|
|
|
|
|
// 检测删除的项目
|
|
|
// 检查删除 & 更新
|
|
|
for (const [id] of this.lastSnapshot) { |
|
|
for (const [id, item] of this.lastStateDict.entries()) { |
|
|
if (!currentMap.has(id)) { |
|
|
if (!currentMap.has(id)) { |
|
|
this.changeTracker.removed.push(id) |
|
|
removed.push(item) |
|
|
|
|
|
|
|
|
|
|
|
} else if (!_.isEqual(item, currentMap.get(id))) { |
|
|
|
|
|
updated.push({ |
|
|
|
|
|
before: item, |
|
|
|
|
|
after: currentMap.get(id) |
|
|
|
|
|
}) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 检测新增和更新的项目
|
|
|
// 检查新增
|
|
|
for (const [id, currentItem] of currentMap) { |
|
|
for (const [id, item] of currentMap.entries()) { |
|
|
const lastItem = this.lastSnapshot.get(id) |
|
|
if (!this.lastStateDict.has(id)) { |
|
|
|
|
|
added.push(item) |
|
|
if (!lastItem) { |
|
|
|
|
|
this.changeTracker.added.push(currentItem) |
|
|
|
|
|
} else if (!_.isEqual(lastItem, currentItem)) { |
|
|
|
|
|
this.changeTracker.updated.push(currentItem) |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 清除空变更
|
|
|
this.changeTracker.added = added |
|
|
if (this.changeTracker.added.length === 0) delete this.changeTracker.added |
|
|
this.changeTracker.removed = removed |
|
|
if (this.changeTracker.removed.length === 0) delete this.changeTracker.removed |
|
|
this.changeTracker.updated = updated |
|
|
if (this.changeTracker.updated.length === 0) delete this.changeTracker.updated |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -173,25 +187,27 @@ export default class StateManager { |
|
|
* 保存差异到历史记录 |
|
|
* 保存差异到历史记录 |
|
|
*/ |
|
|
*/ |
|
|
private saveStep() { |
|
|
private saveStep() { |
|
|
// 跳过空变更
|
|
|
const { added, removed, updated } = this.changeTracker |
|
|
if ( |
|
|
if (added.length === 0 && removed.length === 0 && updated.length === 0) return |
|
|
(!this.changeTracker.added || this.changeTracker.added.length === 0) && |
|
|
|
|
|
(!this.changeTracker.removed || this.changeTracker.removed.length === 0) && |
|
|
// 深拷贝差异对象
|
|
|
(!this.changeTracker.updated || this.changeTracker.updated.length === 0) |
|
|
const clonedDiff = { |
|
|
) { |
|
|
added: _.cloneDeep(added), |
|
|
return |
|
|
removed: _.cloneDeep(removed), |
|
|
|
|
|
updated: _.cloneDeep(updated) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 使用循环缓冲区存储历史记录
|
|
|
const step: HistoryStep = { |
|
|
const nextIndex = (this.historyIndex + 1) % this.maxHistorySteps |
|
|
diff: clonedDiff, |
|
|
this.historySteps[nextIndex] = { |
|
|
|
|
|
diff: _.cloneDeep(this.changeTracker), |
|
|
|
|
|
snapshot: _.cloneDeep(this.lastSnapshot), |
|
|
|
|
|
timestamp: Date.now() |
|
|
timestamp: Date.now() |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
this.historyIndex = nextIndex |
|
|
if (this.historySteps.length >= this.maxHistorySteps) { |
|
|
this.pendingChanges = true // 标记有需要保存的更改
|
|
|
this.historySteps.shift() |
|
|
|
|
|
} |
|
|
|
|
|
this.historySteps.push(step) |
|
|
|
|
|
this.historyIndex = this.historySteps.length - 1 |
|
|
|
|
|
this.pendingChanges = true |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -203,49 +219,77 @@ export default class StateManager { |
|
|
* - 调用 entityManager.deleteEntity(id) 删除场景中的实体 |
|
|
* - 调用 entityManager.deleteEntity(id) 删除场景中的实体 |
|
|
* - 调用 entityManager.endEntityUpdate() 结束更新场景 |
|
|
* - 调用 entityManager.endEntityUpdate() 结束更新场景 |
|
|
*/ |
|
|
*/ |
|
|
syncDataState() { |
|
|
syncDataState(diff: DataDiff) { |
|
|
// 没有变化时跳过同步
|
|
|
// 没有变化时跳过同步
|
|
|
if ( |
|
|
if ( |
|
|
(!this.changeTracker.added || this.changeTracker.added.length === 0) && |
|
|
diff.added.length === 0 && |
|
|
(!this.changeTracker.removed || this.changeTracker.removed.length === 0) && |
|
|
diff.removed.length === 0 && |
|
|
(!this.changeTracker.updated || this.changeTracker.updated.length === 0) |
|
|
diff.updated.length === 0 |
|
|
) { |
|
|
) { |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
console.log('[StateManager] 同步数据状态,变更:', diff) |
|
|
|
|
|
|
|
|
this.entityManager.beginEntityUpdate() |
|
|
this.entityManager.beginEntityUpdate() |
|
|
|
|
|
|
|
|
// 处理删除
|
|
|
// 处理删除
|
|
|
if (this.changeTracker.removed) { |
|
|
for (const item of diff.removed) { |
|
|
for (const id of this.changeTracker.removed) { |
|
|
this.entityManager.deleteEntity(item.id) |
|
|
this.entityManager.deleteEntity(id) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 处理新增
|
|
|
for (const item of diff.added) { |
|
|
if (this.changeTracker.added) { |
|
|
|
|
|
for (const item of this.changeTracker.added) { |
|
|
|
|
|
this.entityManager.createOrUpdateEntity(item) |
|
|
this.entityManager.createOrUpdateEntity(item) |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 处理更新
|
|
|
for (const { after } of diff.updated) { |
|
|
if (this.changeTracker.updated) { |
|
|
this.entityManager.createOrUpdateEntity(after) |
|
|
for (const item of this.changeTracker.updated) { |
|
|
|
|
|
this.entityManager.createOrUpdateEntity(item) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
this.entityManager.endEntityUpdate() |
|
|
this.entityManager.endEntityUpdate() |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 撤销 |
|
|
|
|
|
*/ |
|
|
|
|
|
undo() { |
|
|
|
|
|
if (!this.undoEnabled()) return |
|
|
|
|
|
|
|
|
|
|
|
const step = this.historySteps[this.historyIndex] |
|
|
|
|
|
if (!step) return |
|
|
|
|
|
|
|
|
|
|
|
// 生成和应用反转差异
|
|
|
|
|
|
const reverseDiff = this.invertDiff(step.diff) |
|
|
|
|
|
this.applyDiff(reverseDiff) |
|
|
|
|
|
this.syncDataState(reverseDiff) |
|
|
|
|
|
this.historyIndex-- |
|
|
|
|
|
this.isChanged.value = true |
|
|
|
|
|
this.pendingChanges = true |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 重做 |
|
|
|
|
|
*/ |
|
|
|
|
|
redo() { |
|
|
|
|
|
if (!this.redoEnabled()) return |
|
|
|
|
|
|
|
|
|
|
|
this.historyIndex++ |
|
|
|
|
|
const step = this.historySteps[this.historyIndex] |
|
|
|
|
|
if (!step) return |
|
|
|
|
|
|
|
|
|
|
|
this.applyDiff(step.diff) |
|
|
|
|
|
this.syncDataState(step.diff) |
|
|
|
|
|
|
|
|
|
|
|
this.isChanged.value = true |
|
|
|
|
|
this.pendingChanges = true |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* 从外部加载数据 |
|
|
* 从外部加载数据 |
|
|
*/ |
|
|
*/ |
|
|
async load(data: Partial<VData>) { |
|
|
async load(data: Partial<VData>) { |
|
|
this.isLoading.value = true |
|
|
this.isLoading.value = true |
|
|
this.historySteps = new Array(this.maxHistorySteps).fill(null) |
|
|
this.historySteps = Array.from({ length: this.maxHistorySteps }, () => null) |
|
|
this.historyIndex = -1 |
|
|
this.historyIndex = -1 |
|
|
|
|
|
|
|
|
try { |
|
|
try { |
|
|
@ -259,7 +303,9 @@ export default class StateManager { |
|
|
isChanged: false, |
|
|
isChanged: false, |
|
|
...data |
|
|
...data |
|
|
} |
|
|
} |
|
|
this.fullSync() // 同步到视口
|
|
|
|
|
|
|
|
|
// 同步到视口
|
|
|
|
|
|
this.fullSync() |
|
|
|
|
|
|
|
|
// 初始状态作为第一步
|
|
|
// 初始状态作为第一步
|
|
|
this.beginStateUpdate() |
|
|
this.beginStateUpdate() |
|
|
@ -270,8 +316,6 @@ export default class StateManager { |
|
|
|
|
|
|
|
|
// 强制保存一次初始状态
|
|
|
// 强制保存一次初始状态
|
|
|
await this.saveToLocalstore() |
|
|
await this.saveToLocalstore() |
|
|
this.pendingChanges = false |
|
|
|
|
|
|
|
|
|
|
|
console.log('[StateManager] 加载完成,共', data.items.length, '个对象') |
|
|
console.log('[StateManager] 加载完成,共', data.items.length, '个对象') |
|
|
|
|
|
|
|
|
} finally { |
|
|
} finally { |
|
|
@ -281,109 +325,67 @@ export default class StateManager { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
// 差异应用方法
|
|
|
* 撤销 |
|
|
|
|
|
*/ |
|
|
|
|
|
undo() { |
|
|
|
|
|
if (!this.undoEnabled()) return |
|
|
|
|
|
|
|
|
|
|
|
const step = this.historySteps[this.historyIndex] |
|
|
|
|
|
if (!step) return |
|
|
|
|
|
|
|
|
|
|
|
this.applyReverseDiff(step.diff) |
|
|
|
|
|
this.historyIndex = (this.historyIndex - 1 + this.maxHistorySteps) % this.maxHistorySteps |
|
|
|
|
|
this.isChanged.value = true |
|
|
|
|
|
this.pendingChanges = true |
|
|
|
|
|
|
|
|
|
|
|
this.lastSnapshot = new Map( |
|
|
|
|
|
this.vdata.items.map(item => [item.id, _.cloneDeep(item)]) |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
this.syncDataState() |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 重做 |
|
|
|
|
|
*/ |
|
|
|
|
|
redo() { |
|
|
|
|
|
if (!this.redoEnabled()) return |
|
|
|
|
|
|
|
|
|
|
|
this.historyIndex = (this.historyIndex + 1) % this.maxHistorySteps |
|
|
|
|
|
const step = this.historySteps[this.historyIndex] |
|
|
|
|
|
if (!step) return |
|
|
|
|
|
|
|
|
|
|
|
this.applyDiff(step.diff) |
|
|
|
|
|
this.isChanged.value = true |
|
|
|
|
|
this.pendingChanges = true |
|
|
|
|
|
|
|
|
|
|
|
this.lastSnapshot = new Map( |
|
|
|
|
|
this.vdata.items.map(item => [item.id, _.cloneDeep(item)]) |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
this.syncDataState() |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 应用正向差异 |
|
|
|
|
|
*/ |
|
|
|
|
|
private applyDiff(diff: DataDiff) { |
|
|
private applyDiff(diff: DataDiff) { |
|
|
// 处理删除
|
|
|
const { added, removed, updated } = diff |
|
|
if (diff.removed) { |
|
|
|
|
|
this.vdata.items = this.vdata.items.filter(item => !diff.removed.includes(item.id)) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 处理新增
|
|
|
|
|
|
if (diff.added) { |
|
|
|
|
|
this.vdata.items.push(...diff.added) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 处理更新
|
|
|
|
|
|
if (diff.updated) { |
|
|
|
|
|
const updateMap = new Map(diff.updated.map(item => [item.id, item])) |
|
|
|
|
|
this.vdata.items = this.vdata.items.map(item => |
|
|
|
|
|
updateMap.has(item.id) ? updateMap.get(item.id)! : item |
|
|
|
|
|
) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 应用反向差异(用于撤销) |
|
|
|
|
|
*/ |
|
|
|
|
|
private applyReverseDiff(diff: DataDiff) { |
|
|
|
|
|
// 反向处理:删除 → 添加
|
|
|
|
|
|
if (diff.removed) { |
|
|
|
|
|
// 从历史快照恢复被删除的项目
|
|
|
|
|
|
const restoredItems = diff.removed |
|
|
|
|
|
.map(id => this.lastSnapshot.get(id)) |
|
|
|
|
|
.filter(Boolean) as ItemJson[] |
|
|
|
|
|
|
|
|
|
|
|
this.vdata.items.push(...restoredItems) |
|
|
// 删除
|
|
|
} |
|
|
const removedIds = new Set(removed.map(item => item.id)) |
|
|
|
|
|
_.remove(this.vdata.items, item => removedIds.has(item.id)) |
|
|
// 反向处理:添加 → 删除
|
|
|
|
|
|
if (diff.added) { |
|
|
|
|
|
const addedIds = new Set(diff.added.map(item => item.id)) |
|
|
|
|
|
this.vdata.items = this.vdata.items.filter(item => !addedIds.has(item.id)) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 反向处理:更新 → 恢复旧值
|
|
|
// 新增
|
|
|
if (diff.updated) { |
|
|
const addedIds = new Set(added.map(i => i.id)) |
|
|
const restoreMap = new Map( |
|
|
_.remove(this.vdata.items, item => addedIds.has(item.id)) |
|
|
diff.updated |
|
|
this.vdata.items.push(...added) |
|
|
.map(item => [item.id, this.lastSnapshot.get(item.id)]) |
|
|
|
|
|
.filter(([, item]) => !!item) as [string, ItemJson][] |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
for (const [key, itemJson] of restoreMap) { |
|
|
// 更新
|
|
|
|
|
|
const updateMap = new Map(updated.map(u => [u.after.id, u.after])) |
|
|
|
|
|
for (const [key, after] of updateMap) { |
|
|
const idx = _.findIndex(this.vdata.items, (item => item.id === key)) |
|
|
const idx = _.findIndex(this.vdata.items, (item => item.id === key)) |
|
|
if (idx >= 0) { |
|
|
if (idx >= 0) { |
|
|
Object.assign(this.vdata.items[idx], itemJson) |
|
|
Object.assign(this.vdata.items[idx], after) |
|
|
} |
|
|
} else { |
|
|
|
|
|
this.vdata.items.push(after) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// /**
|
|
|
|
|
|
// * 应用反向差异(用于撤销)
|
|
|
|
|
|
// */
|
|
|
|
|
|
// private applyReverseDiff(diff: DataDiff) {
|
|
|
|
|
|
// const { added, removed, updated } = diff
|
|
|
|
|
|
//
|
|
|
|
|
|
// // 恢复删除
|
|
|
|
|
|
// const restored = removed
|
|
|
|
|
|
// .map(id => {
|
|
|
|
|
|
// const found = this.vdata.items.find(i => i.id === id)
|
|
|
|
|
|
// return found ? _.cloneDeep(found) : null
|
|
|
|
|
|
// })
|
|
|
|
|
|
// .filter(Boolean) as ItemJson[]
|
|
|
|
|
|
//
|
|
|
|
|
|
// // 删除新增
|
|
|
|
|
|
// const addedIds = new Set(added.map(a => a.id))
|
|
|
|
|
|
// _.remove(this.vdata.items, (item => addedIds.has(item.id)))
|
|
|
|
|
|
//
|
|
|
|
|
|
// // 恢复更新
|
|
|
|
|
|
// const restoreMap = new Map(updated.map(u => [u.after.id, u.before]))
|
|
|
|
|
|
// for (const [key, itemJson] of restoreMap) {
|
|
|
|
|
|
// const idx = _.findIndex(this.vdata.items, (item => item.id === key))
|
|
|
|
|
|
// if (idx >= 0) {
|
|
|
|
|
|
// Object.assign(this.vdata.items[idx], itemJson)
|
|
|
|
|
|
// } else {
|
|
|
|
|
|
// this.vdata.items.push(itemJson)
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
//
|
|
|
|
|
|
// // 添加恢复的条目
|
|
|
|
|
|
// this.vdata.items.push(...restored)
|
|
|
|
|
|
//
|
|
|
|
|
|
// // 更新 lastStateDict
|
|
|
|
|
|
// this.lastStateDict = new Map(this.vdata.items.map(item => [item.id, _.cloneDeep(item)]))
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
private fullSync() { |
|
|
private fullSync() { |
|
|
this.entityManager.beginEntityUpdate() |
|
|
this.entityManager.beginEntityUpdate() |
|
|
this.vdata.items.forEach(item => { |
|
|
this.vdata.items.forEach(item => { |
|
|
@ -393,7 +395,7 @@ export default class StateManager { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
undoEnabled() { |
|
|
undoEnabled() { |
|
|
return this.historyIndex >= 0 && this.historySteps[this.historyIndex] |
|
|
return this.historyIndex >= 0 |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
redoEnabled() { |
|
|
redoEnabled() { |
|
|
@ -521,23 +523,6 @@ export default class StateManager { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* 检查是否需要自动保存并执行 |
|
|
|
|
|
*/ |
|
|
|
|
|
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() { |
|
|
destroy() { |
|
|
@ -546,17 +531,5 @@ export default class StateManager { |
|
|
delete this.vdata |
|
|
delete this.vdata |
|
|
delete this.historySteps |
|
|
delete this.historySteps |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 获取自动保存状态 |
|
|
|
|
|
*/ |
|
|
|
|
|
getAutoSaveStatus() { |
|
|
|
|
|
return { |
|
|
|
|
|
enabled: this.autoSaveInterval !== null, |
|
|
|
|
|
interval: this.autoSaveIntervalMs, |
|
|
|
|
|
lastSaveTime: this.lastAutoSaveTime, |
|
|
|
|
|
pendingChanges: this.pendingChanges |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|