/// 增量保存模块 /// /// 实现操作日志(Command Pattern),支持: /// - 快照 + 增量日志混合存储 /// - 撤销/重做功能 /// - 断点恢复 /// /// @version 0.1.0 /// @date 2026-03-07 import 'dart:convert'; import 'dart:typed_data'; // ============================================================================ // 操作类型枚举 // ============================================================================ /// 操作类型 enum OperationType { componentAdd, componentMove, componentRotate, componentDelete, netAdd, netConnect, netDelete, traceAdd, traceDelete, viaAdd, propertyChange, snapshot, } // ============================================================================ // 命令接口 // ============================================================================ /// 命令接口 (Command Pattern) abstract class Command { /// 执行命令 void execute(); /// 撤销命令 void undo(); /// 获取操作类型 OperationType get type; /// 获取时间戳 DateTime get timestamp; /// 序列化为 Map Map toJson(); /// 从 Map 反序列化 factory Command.fromJson(Map json); } // ============================================================================ // 具体命令实现 // ============================================================================ /// 添加元件命令 class AddComponentCommand implements Command { @override final OperationType type = OperationType.componentAdd; @override final DateTime timestamp; final Map component; final String? parentId; // 撤销时需要的信息 String? _createdId; AddComponentCommand({ required this.component, this.parentId, DateTime? timestamp, }) : timestamp = timestamp ?? DateTime.now(); @override void execute() { // 实际执行由 Editor 处理 _createdId = component['id']; } @override void undo() { // 删除创建的元件 } @override Map toJson() { return { 'type': 'componentAdd', 'timestamp': timestamp.millisecondsSinceEpoch, 'component': component, 'parentId': parentId, 'createdId': _createdId, }; } factory Command.fromJson(Map json) { switch (json['type']) { case 'componentAdd': return AddComponentCommand( component: json['component'] as Map, parentId: json['parentId'] as String?, timestamp: DateTime.fromMillisecondsSinceEpoch(json['timestamp'] as int), ); case 'componentMove': return MoveComponentCommand.fromJson(json); case 'componentRotate': return RotateComponentCommand.fromJson(json); case 'componentDelete': return DeleteComponentCommand.fromJson(json); case 'netAdd': return AddNetCommand.fromJson(json); case 'propertyChange': return PropertyChangeCommand.fromJson(json); case 'snapshot': return SnapshotCommand.fromJson(json); default: throw FormatException('Unknown command type: ${json['type']}'); } } } /// 移动元件命令 class MoveComponentCommand implements Command { @override final OperationType type = OperationType.componentMove; @override final DateTime timestamp; final String componentId; final num oldX; final num oldY; final num newX; final num newY; MoveComponentCommand({ required this.componentId, required this.oldX, required this.oldY, required this.newX, required this.newY, DateTime? timestamp, }) : timestamp = timestamp ?? DateTime.now(); @override void execute() { // 移动到新位置 (已经在执行时应用) } @override void undo() { // 移回旧位置 } @override Map toJson() { return { 'type': 'componentMove', 'timestamp': timestamp.millisecondsSinceEpoch, 'componentId': componentId, 'oldX': oldX, 'oldY': oldY, 'newX': newX, 'newY': newY, }; } factory MoveComponentCommand.fromJson(Map json) { return MoveComponentCommand( componentId: json['componentId'] as String, oldX: json['oldX'] as num, oldY: json['oldY'] as num, newX: json['newX'] as num, newY: json['newY'] as num, timestamp: DateTime.fromMillisecondsSinceEpoch(json['timestamp'] as int), ); } } /// 旋转元件命令 class RotateComponentCommand implements Command { @override final OperationType type = OperationType.componentRotate; @override final DateTime timestamp; final String componentId; final int oldRotation; final int newRotation; RotateComponentCommand({ required this.componentId, required this.oldRotation, required this.newRotation, DateTime? timestamp, }) : timestamp = timestamp ?? DateTime.now(); @override void execute() { // 旋转到新角度 } @override void undo() { // 旋转回旧角度 } @override Map toJson() { return { 'type': 'componentRotate', 'timestamp': timestamp.millisecondsSinceEpoch, 'componentId': componentId, 'oldRotation': oldRotation, 'newRotation': newRotation, }; } factory RotateComponentCommand.fromJson(Map json) { return RotateComponentCommand( componentId: json['componentId'] as String, oldRotation: json['oldRotation'] as int, newRotation: json['newRotation'] as int, timestamp: DateTime.fromMillisecondsSinceEpoch(json['timestamp'] as int), ); } } /// 删除元件命令 class DeleteComponentCommand implements Command { @override final OperationType type = OperationType.componentDelete; @override final DateTime timestamp; final String componentId; final Map component; DeleteComponentCommand({ required this.componentId, required this.component, DateTime? timestamp, }) : timestamp = timestamp ?? DateTime.now(); @override void execute() { // 删除元件 } @override void undo() { // 恢复元件 } @override Map toJson() { return { 'type': 'componentDelete', 'timestamp': timestamp.millisecondsSinceEpoch, 'componentId': componentId, 'component': component, }; } factory DeleteComponentCommand.fromJson(Map json) { return DeleteComponentCommand( componentId: json['componentId'] as String, component: json['component'] as Map, timestamp: DateTime.fromMillisecondsSinceEpoch(json['timestamp'] as int), ); } } /// 添加网络命令 class AddNetCommand implements Command { @override final OperationType type = OperationType.netAdd; @override final DateTime timestamp; final Map net; AddNetCommand({ required this.net, DateTime? timestamp, }) : timestamp = timestamp ?? DateTime.now(); @override void execute() { // 添加网络 } @override void undo() { // 删除网络 } @override Map toJson() { return { 'type': 'netAdd', 'timestamp': timestamp.millisecondsSinceEpoch, 'net': net, }; } factory AddNetCommand.fromJson(Map json) { return AddNetCommand( net: json['net'] as Map, timestamp: DateTime.fromMillisecondsSinceEpoch(json['timestamp'] as int), ); } } /// 属性变更命令 class PropertyChangeCommand implements Command { @override final OperationType type = OperationType.propertyChange; @override final DateTime timestamp; final String objectId; final String propertyName; final dynamic oldValue; final dynamic newValue; PropertyChangeCommand({ required this.objectId, required this.propertyName, required this.oldValue, required this.newValue, DateTime? timestamp, }) : timestamp = timestamp ?? DateTime.now(); @override void execute() { // 应用新值 } @override void undo() { // 恢复旧值 } @override Map toJson() { return { 'type': 'propertyChange', 'timestamp': timestamp.millisecondsSinceEpoch, 'objectId': objectId, 'propertyName': propertyName, 'oldValue': oldValue, 'newValue': newValue, }; } factory PropertyChangeCommand.fromJson(Map json) { return PropertyChangeCommand( objectId: json['objectId'] as String, propertyName: json['propertyName'] as String, oldValue: json['oldValue'], newValue: json['newValue'], timestamp: DateTime.fromMillisecondsSinceEpoch(json['timestamp'] as int), ); } } /// 快照命令 class SnapshotCommand implements Command { @override final OperationType type = OperationType.snapshot; @override final DateTime timestamp; final Map fullState; SnapshotCommand({ required this.fullState, DateTime? timestamp, }) : timestamp = timestamp ?? DateTime.now(); @override void execute() { // 保存完整状态 } @override void undo() { // 快照不支持撤销 } @override Map toJson() { return { 'type': 'snapshot', 'timestamp': timestamp.millisecondsSinceEpoch, 'fullState': fullState, }; } factory SnapshotCommand.fromJson(Map json) { return SnapshotCommand( fullState: json['fullState'] as Map, timestamp: DateTime.fromMillisecondsSinceEpoch(json['timestamp'] as int), ); } } // ============================================================================ // 操作历史记录 // ============================================================================ /// 操作历史记录管理器 class OperationHistory { final List _undoStack = []; final List _redoStack = []; /// 最大历史记录数 (移动端建议:50-100) final int maxStackSize; /// 快照间隔 (每 N 次操作生成一个快照) final int snapshotInterval; /// 当前操作计数 (用于快照生成) int _operationCount = 0; OperationHistory({ this.maxStackSize = 50, this.snapshotInterval = 100, }); /// 添加操作到历史记录 void push(Command command) { // 执行命令 command.execute(); // 添加到撤销栈 _undoStack.add(command); _operationCount++; // 清空重做栈 (新的操作使重做无效) _redoStack.clear(); // 检查是否需要生成快照 if (_operationCount % snapshotInterval == 0) { _generateSnapshot(); } // 限制栈大小 if (_undoStack.length > maxStackSize) { _undoStack.removeAt(0); } } /// 撤销操作 Command? undo() { if (_undoStack.isEmpty) { return null; } final command = _undoStack.removeLast(); command.undo(); _redoStack.add(command); return command; } /// 重做操作 Command? redo() { if (_redoStack.isEmpty) { return null; } final command = _redoStack.removeLast(); command.execute(); _undoStack.add(command); return command; } /// 是否可以撤销 bool get canUndo => _undoStack.isNotEmpty; /// 是否可以重做 bool get canRedo => _redoStack.isNotEmpty; /// 获取撤销栈大小 int get undoStackSize => _undoStack.length; /// 获取重做栈大小 int get redoStackSize => _redoStack.length; /// 清除历史记录 void clear() { _undoStack.clear(); _redoStack.clear(); _operationCount = 0; } /// 生成快照 void _generateSnapshot() { // 快照由外部提供完整状态 // 这里只生成标记 } /// 从快照恢复 void restoreFromSnapshot(Map snapshot) { clear(); // 恢复状态由外部处理 } /// 序列化为 JSON Map toJson() { return { 'undoStack': _undoStack.map((c) => c.toJson()).toList(), 'redoStack': _redoStack.map((c) => c.toJson()).toList(), 'operationCount': _operationCount, }; } /// 从 JSON 反序列化 factory OperationHistory.fromJson(Map json) { final history = OperationHistory( maxStackSize: json['maxStackSize'] as int? ?? 50, snapshotInterval: json['snapshotInterval'] as int? ?? 100, ); final undoList = json['undoStack'] as List? ?? []; for (final cmdJson in undoList) { history._undoStack.add(Command.fromJson(cmdJson as Map)); } final redoList = json['redoStack'] as List? ?? []; for (final cmdJson in redoList) { history._redoStack.add(Command.fromJson(cmdJson as Map)); } history._operationCount = json['operationCount'] as int? ?? 0; return history; } } // ============================================================================ // 增量保存管理器 // ============================================================================ /// 增量保存管理器 /// /// 管理快照和增量日志的混合存储 class IncrementalSaveManager { /// 操作历史记录 final OperationHistory history; /// 当前设计状态 Map? _currentState; /// 最后一个快照 Map? _lastSnapshot; /// 快照后的操作日志 final List _deltaLog = []; /// 自动保存间隔 (毫秒) final int autoSaveInterval; /// 是否自动保存 bool _autoSaveEnabled = false; IncrementalSaveManager({ OperationHistory? history, this.autoSaveInterval = 30000, // 30 秒 }) : history = history ?? OperationHistory(); /// 设置当前状态 void setCurrentState(Map state) { _currentState = state; } /// 记录操作 void recordOperation(Command command) { history.push(command); _deltaLog.add(command); // 标记为脏数据 if (_currentState != null) { _currentState!['metadata'] ??= {}; _currentState!['metadata']['isDirty'] = true; } } /// 创建快照 void createSnapshot(Map fullState) { _lastSnapshot = Map.from(fullState); _deltaLog.clear(); // 记录快照命令 history.push(SnapshotCommand(fullState: fullState)); // 清除脏标记 fullState['metadata'] ??= {}; fullState['metadata']['isDirty'] = false; fullState['metadata']['lastSavedAt'] = DateTime.now().millisecondsSinceEpoch; } /// 保存 (快照 + 增量) IncrementalSaveData save() { return IncrementalSaveData( snapshot: _lastSnapshot, deltaLog: _deltaLog.map((c) => c.toJson()).toList(), timestamp: DateTime.now(), ); } /// 从保存数据恢复 Map? restore(IncrementalSaveData saveData) { if (saveData.snapshot != null) { _currentState = Map.from(saveData.snapshot!); } // 应用增量操作 for (final cmdJson in saveData.deltaLog) { final command = Command.fromJson(cmdJson); command.execute(); _applyCommandToState(command); } return _currentState; } /// 应用命令到状态 void _applyCommandToState(Command command) { // 根据命令类型更新状态 switch (command.type) { case OperationType.componentAdd: _applyAddComponent(command as AddComponentCommand); break; case OperationType.componentMove: _applyMoveComponent(command as MoveComponentCommand); break; case OperationType.componentRotate: _applyRotateComponent(command as RotateComponentCommand); break; case OperationType.componentDelete: _applyDeleteComponent(command as DeleteComponentCommand); break; case OperationType.netAdd: _applyAddNet(command as AddNetCommand); break; case OperationType.propertyChange: _applyPropertyChange(command as PropertyChangeCommand); break; case OperationType.snapshot: _applySnapshot(command as SnapshotCommand); break; default: break; } } void _applyAddComponent(AddComponentCommand command) { if (_currentState == null) return; final tables = _currentState!['tables'] as Map?; if (tables == null) return; final components = tables['components'] as List?; if (components != null) { components.add(command.component); } } void _applyMoveComponent(MoveComponentCommand command) { if (_currentState == null) return; final tables = _currentState!['tables'] as Map?; if (tables == null) return; final components = tables['components'] as List?; if (components != null) { for (final comp in components) { if (comp is Map && comp['id'] == command.componentId) { comp['position'] ??= {}; comp['position']['x'] = command.newX; comp['position']['y'] = command.newY; break; } } } } void _applyRotateComponent(RotateComponentCommand command) { if (_currentState == null) return; final tables = _currentState!['tables'] as Map?; if (tables == null) return; final components = tables['components'] as List?; if (components != null) { for (final comp in components) { if (comp is Map && comp['id'] == command.componentId) { comp['position'] ??= {}; comp['position']['rotation'] = command.newRotation; break; } } } } void _applyDeleteComponent(DeleteComponentCommand command) { if (_currentState == null) return; final tables = _currentState!['tables'] as Map?; if (tables == null) return; final components = tables['components'] as List?; if (components != null) { components.removeWhere((comp) => comp is Map && comp['id'] == command.componentId ); } } void _applyAddNet(AddNetCommand command) { if (_currentState == null) return; final tables = _currentState!['tables'] as Map?; if (tables == null) return; final nets = tables['nets'] as List?; if (nets != null) { nets.add(command.net); } } void _applyPropertyChange(PropertyChangeCommand command) { if (_currentState == null) return; // 查找对象并更新属性 final tables = _currentState!['tables'] as Map?; if (tables == null) return; for (final table in tables.values) { if (table is List) { for (final obj in table) { if (obj is Map && obj['id'] == command.objectId) { obj[command.propertyName] = command.newValue; return; } } } } } void _applySnapshot(SnapshotCommand command) { _currentState = Map.from(command.fullState); _lastSnapshot = Map.from(command.fullState); } /// 启用自动保存 void enableAutoSave() { _autoSaveEnabled = true; } /// 禁用自动保存 void disableAutoSave() { _autoSaveEnabled = false; } /// 获取当前状态 Map? get currentState => _currentState; /// 获取最后快照 Map? get lastSnapshot => _lastSnapshot; /// 是否有未保存的更改 bool get isDirty => _deltaLog.isNotEmpty; /// 获取增量日志大小 int get deltaLogSize => _deltaLog.length; } // ============================================================================ // 保存数据 // ============================================================================ /// 增量保存数据 class IncrementalSaveData { /// 完整快照 (可能为 null,如果是纯增量保存) final Map? snapshot; /// 增量操作日志 final List> deltaLog; /// 保存时间戳 final DateTime timestamp; IncrementalSaveData({ this.snapshot, this.deltaLog = const [], required this.timestamp, }); /// 序列化为 JSON 字符串 String toJsonString() { return jsonEncode({ 'snapshot': snapshot, 'deltaLog': deltaLog, 'timestamp': timestamp.millisecondsSinceEpoch, }); } /// 从 JSON 字符串反序列化 factory IncrementalSaveData.fromJsonString(String jsonString) { final json = jsonDecode(jsonString) as Map; return IncrementalSaveData( snapshot: json['snapshot'] as Map?, deltaLog: (json['deltaLog'] as List? ?? []) .map((e) => e as Map) .toList(), timestamp: DateTime.fromMillisecondsSinceEpoch(json['timestamp'] as int), ); } /// 序列化为字节 (用于文件存储) Uint8List toBytes() { final jsonString = toJsonString(); return Uint8List.fromList(utf8.encode(jsonString)); } /// 从字节反序列化 factory IncrementalSaveData.fromBytes(Uint8List bytes) { final jsonString = utf8.decode(bytes); return IncrementalSaveData.fromJsonString(jsonString); } } // ============================================================================ // 断点恢复 // ============================================================================ /// 断点恢复管理器 class CheckpointManager { /// 检查点列表 final List _checkpoints = []; /// 最大检查点数 final int maxCheckpoints; CheckpointManager({this.maxCheckpoints = 10}); /// 创建检查点 void createCheckpoint( String name, Map state, String reason, ) { final checkpoint = Checkpoint( name: name, state: Map.from(state), reason: reason, timestamp: DateTime.now(), ); _checkpoints.add(checkpoint); // 限制检查点数量 if (_checkpoints.length > maxCheckpoints) { _checkpoints.removeAt(0); } } /// 获取最新检查点 Checkpoint? getLatestCheckpoint() { if (_checkpoints.isEmpty) { return null; } return _checkpoints.last; } /// 获取指定名称的检查点 Checkpoint? getCheckpoint(String name) { for (final checkpoint in _checkpoints) { if (checkpoint.name == name) { return checkpoint; } } return null; } /// 从检查点恢复 Map? restoreFromCheckpoint(String name) { final checkpoint = getCheckpoint(name); return checkpoint?.state; } /// 从最新检查点恢复 Map? restoreFromLatest() { final checkpoint = getLatestCheckpoint(); return checkpoint?.state; } /// 清除所有检查点 void clear() { _checkpoints.clear(); } /// 获取检查点列表 List get checkpoints => List.unmodifiable(_checkpoints); } /// 检查点 class Checkpoint { final String name; final Map state; final String reason; final DateTime timestamp; Checkpoint({ required this.name, required this.state, required this.reason, required this.timestamp, }); /// 序列化为 JSON Map toJson() { return { 'name': name, 'state': state, 'reason': reason, 'timestamp': timestamp.millisecondsSinceEpoch, }; } /// 从 JSON 反序列化 factory Checkpoint.fromJson(Map json) { return Checkpoint( name: json['name'] as String, state: json['state'] as Map, reason: json['reason'] as String, timestamp: DateTime.fromMillisecondsSinceEpoch(json['timestamp'] as int), ); } } // ============================================================================ // 公共 API // ============================================================================ /// 创建增量保存管理器 IncrementalSaveManager createIncrementalSaveManager({ int maxHistorySize = 50, int snapshotInterval = 100, int autoSaveInterval = 30000, }) { final history = OperationHistory( maxStackSize: maxHistorySize, snapshotInterval: snapshotInterval, ); return IncrementalSaveManager( history: history, autoSaveInterval: autoSaveInterval, ); } /// 创建断点恢复管理器 CheckpointManager createCheckpointManager({int maxCheckpoints = 10}) { return CheckpointManager(maxCheckpoints: maxCheckpoints); }