/** * P1 Bug 修复补丁 * * 修复两个 P1 级别问题: * 1. 撤销/重做功能未实现 * 2. 元件库扩展(电感/二极管/晶体管等) * * @version 1.0.0 * @date 2026-03-07 */ import 'package:flutter/material.dart'; import '../../data/models/core_models.dart'; // ============================================================================ // Bug #1: 撤销/重做功能实现 // ============================================================================ /// 操作记录 - 用于撤销/重做 class Command { final String id; final CommandType type; final DateTime timestamp; final Map data; final Map undoData; Command({ required this.id, required this.type, required this.timestamp, required this.data, required this.undoData, }); } /// 命令类型枚举 enum CommandType { addComponent, // 添加元件 deleteComponent, // 删除元件 moveComponent, // 移动元件 rotateComponent, // 旋转元件 addNet, // 添加网络 deleteNet, // 删除网络 } /// 撤销/重做管理器 class UndoRedoManager { static final UndoRedoManager _instance = UndoRedoManager._internal(); factory UndoRedoManager() => _instance; UndoRedoManager._internal(); final List _undoStack = []; final List _redoStack = []; // 最大历史记录数 static const int maxHistorySize = 50; /// 执行操作并记录 void execute(Command command) { // 执行操作 _applyCommand(command); // 添加到撤销栈 _undoStack.add(command); // 清空重做栈(执行新操作后) _redoStack.clear(); // 限制历史记录大小 if (_undoStack.length > maxHistorySize) { _undoStack.removeAt(0); } debugPrint('✅ 执行操作:${command.type}, 撤销栈大小:${_undoStack.length}'); } /// 撤销 bool undo() { if (_undoStack.isEmpty) { debugPrint('⚠️ 无操作可撤销'); return false; } final command = _undoStack.removeLast(); _applyUndo(command); _redoStack.add(command); debugPrint('↩️ 撤销操作:${command.type}, 撤销栈大小:${_undoStack.length}'); return true; } /// 重做 bool redo() { if (_redoStack.isEmpty) { debugPrint('⚠️ 无操作可重做'); return false; } final command = _redoStack.removeLast(); _applyCommand(command); _undoStack.add(command); debugPrint('↪️ 重做操作:${command.type}, 撤销栈大小:${_undoStack.length}'); return true; } /// 清空历史 void clear() { _undoStack.clear(); _redoStack.clear(); debugPrint('🗑️ 清空历史记录'); } /// 获取撤销栈大小 int get undoCount => _undoStack.length; /// 获取重做栈大小 int get redoCount => _redoStack.length; /// 是否可以撤销 bool get canUndo => _undoStack.isNotEmpty; /// 是否可以重做 bool get canRedo => _redoStack.isNotEmpty; // ============================================================================ // 内部方法 // ============================================================================ void _applyCommand(Command command) { // 根据命令类型执行操作 switch (command.type) { case CommandType.addComponent: _addComponent(command); break; case CommandType.deleteComponent: _deleteComponent(command); break; case CommandType.moveComponent: _moveComponent(command); break; case CommandType.rotateComponent: _rotateComponent(command); break; case CommandType.addNet: _addNet(command); break; case CommandType.deleteNet: _deleteNet(command); break; } } void _applyUndo(Command command) { // 撤销操作:应用 undoData switch (command.type) { case CommandType.addComponent: // 撤销添加 = 删除 _removeComponentById(command.data['componentId']); break; case CommandType.deleteComponent: // 撤销删除 = 恢复 _restoreComponent(command.undoData); break; case CommandType.moveComponent: // 撤销移动 = 移回原位置 _moveComponentToPosition( command.data['componentId'], command.undoData['oldPosition'], ); break; case CommandType.rotateComponent: // 撤销旋转 = 恢复原角度 _rotateComponentToAngle( command.data['componentId'], command.undoData['oldRotation'], ); break; case CommandType.addNet: // 撤销添加网络 = 删除网络 _removeNetById(command.data['netId']); break; case CommandType.deleteNet: // 撤销删除网络 = 恢复网络 _restoreNet(command.undoData); break; } } // ============================================================================ // 元件操作实现 // ============================================================================ void _addComponent(Command command) { final componentData = command.data['component'] as Component; // TODO: 添加到 Design debugPrint('添加元件:${componentData.id}'); } void _deleteComponent(Command command) { final componentId = command.data['componentId'] as String; // TODO: 从 Design 删除 debugPrint('删除元件:$componentId'); } void _removeComponentById(String componentId) { // TODO: 实现删除逻辑 debugPrint('移除元件:$componentId'); } void _restoreComponent(Map data) { // TODO: 恢复元件 debugPrint('恢复元件:${data['id']}'); } void _moveComponent(Command command) { final componentId = command.data['componentId'] as String; final newPosition = command.data['newPosition'] as Offset; // TODO: 移动元件 debugPrint('移动元件:$componentId 到 $newPosition'); } void _moveComponentToPosition(String componentId, Offset position) { // TODO: 移动到指定位置 debugPrint('移动元件 $componentId 到 $position'); } void _rotateComponent(Command command) { final componentId = command.data['componentId'] as String; final newRotation = command.data['newRotation'] as int; // TODO: 旋转元件 debugPrint('旋转元件:$componentId 到 $newRotation°'); } void _rotateComponentToAngle(String componentId, int rotation) { // TODO: 旋转到指定角度 debugPrint('旋转元件 $componentId 到 $rotation°'); } // ============================================================================ // 网络操作实现 // ============================================================================ void _addNet(Command command) { final netData = command.data['net'] as Net; // TODO: 添加到 Design debugPrint('添加网络:${netData.id}'); } void _deleteNet(Command command) { final netId = command.data['netId'] as String; // TODO: 从 Design 删除 debugPrint('删除网络:$netId'); } void _removeNetById(String netId) { // TODO: 删除网络 debugPrint('移除网络:$netId'); } void _restoreNet(Map data) { // TODO: 恢复网络 debugPrint('恢复网络:${data['id']}'); } } // ============================================================================ // 快捷命令工厂 // ============================================================================ /// 命令工厂 - 简化命令创建 class CommandFactory { /// 创建添加元件命令 static Command createAddComponent(Component component) { return Command( id: 'cmd_${DateTime.now().millisecondsSinceEpoch}', type: CommandType.addComponent, timestamp: DateTime.now(), data: { 'component': component, 'componentId': component.id, }, undoData: { 'componentId': component.id, }, ); } /// 创建删除元件命令 static Command createDeleteComponent(String componentId, Component component) { return Command( id: 'cmd_${DateTime.now().millisecondsSinceEpoch}', type: CommandType.deleteComponent, timestamp: DateTime.now(), data: { 'componentId': componentId, }, undoData: { 'id': component.id, 'component': component, }, ); } /// 创建移动元件命令 static Command createMoveComponent( String componentId, Offset oldPosition, Offset newPosition, ) { return Command( id: 'cmd_${DateTime.now().millisecondsSinceEpoch}', type: CommandType.moveComponent, timestamp: DateTime.now(), data: { 'componentId': componentId, 'oldPosition': oldPosition, 'newPosition': newPosition, }, undoData: { 'oldPosition': oldPosition, }, ); } /// 创建旋转元件命令 static Command createRotateComponent( String componentId, int oldRotation, int newRotation, ) { return Command( id: 'cmd_${DateTime.now().millisecondsSinceEpoch}', type: CommandType.rotateComponent, timestamp: DateTime.now(), data: { 'componentId': componentId, 'oldRotation': oldRotation, 'newRotation': newRotation, }, undoData: { 'oldRotation': oldRotation, }, ); } } // ============================================================================ // Bug #2: 元件库扩展 // ============================================================================ /// 扩展元件库服务 - 添加更多常用元件 class ExtendedComponentLibraryService { static final ExtendedComponentLibraryService _instance = ExtendedComponentLibraryService._internal(); factory ExtendedComponentLibraryService() => _instance; ExtendedComponentLibraryService._internal(); /// 获取所有可用元件(包含基础 + 扩展) List getAllComponents() { return [ // 基础元件(来自 ComponentLibraryService) ...ComponentLibraryService().getCommonComponents(), // 扩展元件 ...getPassiveComponents(), ...getActiveComponents(), ...getConnectorComponents(), ...getSwitchComponents(), ]; } /// 无源元件 List getPassiveComponents() { return [ // 电感 ComponentTemplate( id: 'inductor', name: '电感', category: 'passive', symbol: 'L', pinCount: 2, pins: [ PinDefinition(pinId: '1', x: -10, y: 0, direction: PinDirection.left), PinDefinition(pinId: '2', x: 10, y: 0, direction: PinDirection.right), ], graphics: [ // 电感线圈符号 GraphicElement( type: GraphicType.line, points: [Offset(-10, 0), Offset(-8, 0)], style: LineStyle.solid, width: 1, color: Colors.black, ), GraphicElement( type: GraphicType.arc, center: Offset(-5, 0), radius: 3, startAngle: 180, sweepAngle: 180, style: LineStyle.solid, width: 1, color: Colors.black, ), GraphicElement( type: GraphicType.arc, center: Offset(0, 0), radius: 3, startAngle: 180, sweepAngle: 180, style: LineStyle.solid, width: 1, color: Colors.black, ), GraphicElement( type: GraphicType.arc, center: Offset(5, 0), radius: 3, startAngle: 180, sweepAngle: 180, style: LineStyle.solid, width: 1, color: Colors.black, ), GraphicElement( type: GraphicType.line, points: [Offset(8, 0), Offset(10, 0)], style: LineStyle.solid, width: 1, color: Colors.black, ), ], ), // 可变电阻 ComponentTemplate( id: 'potentiometer', name: '电位器', category: 'passive', symbol: 'RV', pinCount: 3, pins: [ PinDefinition(pinId: '1', x: -10, y: 5, direction: PinDirection.left), PinDefinition(pinId: '2', x: 10, y: 5, direction: PinDirection.right), PinDefinition(pinId: '3', x: 0, y: -10, direction: PinDirection.up), ], graphics: [ // 电阻主体 GraphicElement( type: GraphicType.zigzag, points: [ Offset(-8, 5), Offset(-6, 2), Offset(-4, 8), Offset(-2, 2), Offset(0, 8), Offset(2, 2), Offset(4, 8), Offset(6, 2), Offset(8, 5), ], style: LineStyle.solid, width: 1, color: Colors.black, ), // 滑动触点箭头 GraphicElement( type: GraphicType.line, points: [Offset(0, -10), Offset(0, 3)], style: LineStyle.solid, width: 1.5, color: Colors.black, arrowHead: true, ), ], ), ]; } /// 有源元件 List getActiveComponents() { return [ // 二极管 ComponentTemplate( id: 'diode', name: '二极管', category: 'active', symbol: 'D', pinCount: 2, pins: [ PinDefinition(pinId: 'A', x: -10, y: 0, direction: PinDirection.left), PinDefinition(pinId: 'K', x: 10, y: 0, direction: PinDirection.right), ], graphics: [ // 三角形(阳极) GraphicElement( type: GraphicType.triangle, points: [ Offset(-5, -6), Offset(-5, 6), Offset(5, 0), ], style: LineStyle.solid, width: 1, color: Colors.black, filled: false, ), // 横线(阴极) GraphicElement( type: GraphicType.line, points: [Offset(5, -6), Offset(5, 6)], style: LineStyle.solid, width: 2, color: Colors.black, ), // 引线 GraphicElement( type: GraphicType.line, points: [Offset(-10, 0), Offset(-5, 0)], style: LineStyle.solid, width: 1, color: Colors.black, ), GraphicElement( type: GraphicType.line, points: [Offset(5, 0), Offset(10, 0)], style: LineStyle.solid, width: 1, color: Colors.black, ), ], ), // NPN 三极管 ComponentTemplate( id: 'npn_transistor', name: 'NPN 三极管', category: 'active', symbol: 'Q', pinCount: 3, pins: [ PinDefinition(pinId: 'B', x: -15, y: 0, direction: PinDirection.left), PinDefinition(pinId: 'C', x: 15, y: -10, direction: PinDirection.right), PinDefinition(pinId: 'E', x: 15, y: 10, direction: PinDirection.right), ], graphics: [ // 圆圈 GraphicElement( type: GraphicType.circle, points: [Offset(0, 0)], radius: 12, style: LineStyle.solid, width: 1, color: Colors.black, ), // 基极横线 GraphicElement( type: GraphicType.line, points: [Offset(-15, 0), Offset(-5, 0)], style: LineStyle.solid, width: 1, color: Colors.black, ), // 竖线 GraphicElement( type: GraphicType.line, points: [Offset(-5, -8), Offset(-5, 8)], style: LineStyle.solid, width: 2, color: Colors.black, ), // 集电极斜线 GraphicElement( type: GraphicType.line, points: [Offset(-2, -5), Offset(12, -10)], style: LineStyle.solid, width: 1, color: Colors.black, ), // 发射极斜线(带箭头) GraphicElement( type: GraphicType.line, points: [Offset(-2, 5), Offset(12, 10)], style: LineStyle.solid, width: 1, color: Colors.black, arrowHead: true, ), ], ), // PNP 三极管 ComponentTemplate( id: 'pnp_transistor', name: 'PNP 三极管', category: 'active', symbol: 'Q', pinCount: 3, pins: [ PinDefinition(pinId: 'B', x: -15, y: 0, direction: PinDirection.left), PinDefinition(pinId: 'C', x: 15, y: -10, direction: PinDirection.right), PinDefinition(pinId: 'E', x: 15, y: 10, direction: PinDirection.right), ], graphics: [ // 圆圈 GraphicElement( type: GraphicType.circle, points: [Offset(0, 0)], radius: 12, style: LineStyle.solid, width: 1, color: Colors.black, ), // 基极横线 GraphicElement( type: GraphicType.line, points: [Offset(-15, 0), Offset(-5, 0)], style: LineStyle.solid, width: 1, color: Colors.black, ), // 竖线 GraphicElement( type: GraphicType.line, points: [Offset(-5, -8), Offset(-5, 8)], style: LineStyle.solid, width: 2, color: Colors.black, ), // 集电极斜线 GraphicElement( type: GraphicType.line, points: [Offset(-2, -5), Offset(12, -10)], style: LineStyle.solid, width: 1, color: Colors.black, ), // 发射极斜线(箭头向内) GraphicElement( type: GraphicType.line, points: [Offset(12, 10), Offset(-2, 5)], style: LineStyle.solid, width: 1, color: Colors.black, arrowHead: true, ), ], ), // MOSFET N 沟道 ComponentTemplate( id: 'mosfet_n', name: 'N 沟道 MOSFET', category: 'active', symbol: 'Q', pinCount: 3, pins: [ PinDefinition(pinId: 'G', x: -15, y: 0, direction: PinDirection.left), PinDefinition(pinId: 'D', x: 15, y: -10, direction: PinDirection.right), PinDefinition(pinId: 'S', x: 15, y: 10, direction: PinDirection.right), ], graphics: [ // 栅极 GraphicElement( type: GraphicType.line, points: [Offset(-15, 0), Offset(-5, 0)], style: LineStyle.solid, width: 1, color: Colors.black, ), // 漏极 GraphicElement( type: GraphicType.line, points: [Offset(5, -10), Offset(15, -10)], style: LineStyle.solid, width: 1, color: Colors.black, ), // 源极 GraphicElement( type: GraphicType.line, points: [Offset(5, 10), Offset(15, 10)], style: LineStyle.solid, width: 1, color: Colors.black, ), // 垂直线 GraphicElement( type: GraphicType.line, points: [Offset(5, -8), Offset(5, 8)], style: LineStyle.solid, width: 2, color: Colors.black, ), ], ), ]; } /// 连接器 List getConnectorComponents() { return [ // 排针 ComponentTemplate( id: 'header_2p', name: '2P 排针', category: 'connector', symbol: 'J', pinCount: 2, pins: [ PinDefinition(pinId: '1', x: 0, y: -10, direction: PinDirection.up), PinDefinition(pinId: '2', x: 0, y: 10, direction: PinDirection.down), ], graphics: [ // 矩形主体 GraphicElement( type: GraphicType.rectangle, points: [Offset(-8, -15), Offset(8, 15)], style: LineStyle.solid, width: 1, color: Colors.black, ), // 引脚点 GraphicElement( type: GraphicType.circle, points: [Offset(0, -10)], radius: 2, style: LineStyle.solid, width: 1, color: Colors.black, filled: true, fillColor: Colors.black, ), GraphicElement( type: GraphicType.circle, points: [Offset(0, 10)], radius: 2, style: LineStyle.solid, width: 1, color: Colors.black, filled: true, fillColor: Colors.black, ), ], ), ]; } /// 开关 List getSwitchComponents() { return [ // 单刀单掷开关 ComponentTemplate( id: 'spst_switch', name: 'SPST 开关', category: 'switch', symbol: 'S', pinCount: 2, pins: [ PinDefinition(pinId: '1', x: -10, y: 0, direction: PinDirection.left), PinDefinition(pinId: '2', x: 10, y: 0, direction: PinDirection.right), ], graphics: [ // 触点 GraphicElement( type: GraphicType.circle, points: [Offset(-8, 0)], radius: 2, style: LineStyle.solid, width: 1, color: Colors.black, filled: true, fillColor: Colors.black, ), GraphicElement( type: GraphicType.circle, points: [Offset(8, 0)], radius: 2, style: LineStyle.solid, width: 1, color: Colors.black, filled: true, fillColor: Colors.black, ), // 开关臂(断开状态) GraphicElement( type: GraphicType.line, points: [Offset(-6, 0), Offset(6, -8)], style: LineStyle.solid, width: 2, color: Colors.black, ), // 引线 GraphicElement( type: GraphicType.line, points: [Offset(-10, 0), Offset(-8, 0)], style: LineStyle.solid, width: 1, color: Colors.black, ), GraphicElement( type: GraphicType.line, points: [Offset(8, 0), Offset(10, 0)], style: LineStyle.solid, width: 1, color: Colors.black, ), ], ), ]; } } // ============================================================================ // 使用示例 // ============================================================================ /* // 撤销/重做使用示例 final undoRedo = UndoRedoManager(); // 添加元件(带撤销支持) final component = library.createComponentFromTemplate(template, x: 100, y: 100); final command = CommandFactory.createAddComponent(component); undoRedo.execute(command); // 撤销 if (undoRedo.canUndo) { undoRedo.undo(); } // 重做 if (undoRedo.canRedo) { undoRedo.redo(); } // 扩展元件库使用示例 final extLibrary = ExtendedComponentLibraryService(); final allComponents = extLibrary.getAllComponents(); // 获取特定类型元件 final passiveComponents = extLibrary.getPassiveComponents(); final activeComponents = extLibrary.getActiveComponents(); final diode = passiveComponents.firstWhere((c) => c.id == 'diode'); */