# 架构完善计划 > PLC 型号:**西门子 S7-200 Smart**,通信协议:**HslCommunication S7Net** > > 恢复的 4 组代码均有明确设计意图,但实现不完整。本计划按优先级排列,逐步将它们从"占位代码"推进到"生产可用"。 --- ## 阶段零:项目档案接线(扬杰二厂急需,快速补全) **目标**:将 `ProjectProfile` 中已定义但未接线的模型字段接入到服务层/ViewModel/UI。 **现状**: - `ProjectProfile` 定义了 8 个子配置(Pump/Tank/Gauge/Sensor/DI/DO/AlarmThresholds/ViewTemplate) - 核心路径(泵/水箱/仪表/传感器)已完整可用 - 但 DI/DO/报警阈值/泵扩展地址/ViewTemplate 只有模型,下游没有接线 **步骤**: | # | 任务 | 涉及文件 | 说明 | |---|------|----------|------| | 0.1 | 通用 DI 接入 | `PlcDataModel.cs` + `PlcPollingService.cs` + `ProjectViewModel.cs` + `ProjectView.axaml` | PlcPolling 读取 DigitalInputs → ViewModel 显示变频器故障 | | 0.2 | 通用 DO 接入 | `ProjectViewModel.cs` + `ProjectView.axaml` | 日流量复位/复位按钮点动写入 | | 0.3 | 泵扩展地址接入 | `PumpItemViewModel.cs` + `PlcPollingService.cs` + `ProjectView.axaml` | 中控/屏控状态读取、日台时清零、手自动状态 | | 0.4 | 报警阈值接入 | `ProjectViewModel.cs` | AlarmThresholds → AlarmService 超限报警 | | 0.5 | ViewTemplate 接入 | `MainViewModel.cs` | 根据 Profile.ViewTemplate 选择布局 | **完成标准**: - [ ] 扬杰二厂 JSON 中配置的所有地址均可读取/写入 - [ ] 变频器故障等 DI 信号在 UI 上可见 - [ ] 日流量复位、日台时清零等 DO 操作可执行 - [ ] 压力/液位超限自动触发报警 --- ## 阶段一:DI 渐进式迁移(基础,其他阶段的前置条件) **目标**:让 Service 可测试、可替换,为后续阶段打好基础。 **现状**: - 接口已定义(IPlcService / IAlarmService / IConfigService / IDatabaseService / IAuthService) - ServiceLocator 已实现,但零调用方 - 所有 Service 是 static class,不实现接口 **步骤**: | # | 任务 | 涉及文件 | 说明 | |---|------|----------|------| | 1.1 | 选择 1 个低风险 Service 试点 | `ConfigService` | 它无状态、无并发,最适合试点 | | 1.2 | ConfigService 从 static 改为实例类 | `ConfigService.cs` | 实现 `IConfigService`,保留 `Instance` 静态属性做兼容 | | 1.3 | ServiceLocator 注册 ConfigService | `ServiceCollectionExtensions.cs` | `services.AddSingleton(ConfigService.Instance)` | | 1.4 | 逐批替换调用方 | 所有 ViewModel/Service | `ConfigService.GetConfig()` → `ServiceLocator.GetService().GetConfig()` | | 1.5 | 重复 1.2~1.4 覆盖其他 Service | 按依赖顺序:IConfigService → IDatabaseService → IAuthService → IPlcService → IAlarmService | 每完成一个 Service 跑一次全量测试 | | 1.6 | (可选)引入构造函数注入 | `App.axaml.cs` | `services.BuildServiceProvider()` + ViewModel 通过构造函数接收依赖 | **完成标准**: - [ ] 所有 Service 实现对应接口 - [ ] ServiceLocator 有实际调用方(至少 ConfigService 全量替换完成) - [ ] 现有功能不受影响 --- ## 阶段二:DeviceStateMachine 完善(设备状态管理) **目标**:让泵/风机的状态转换有规则、可审计。 **现状**: - `DeviceStateMachine` 类已定义状态(Stopped/Running/Fault/Maintenance)和转换 - `DeviceStateMachineManager` 已实现,硬编码"5 泵 + 2 风机" - 使用 Stateless 库,但**没有与 PlcPollingService/AlarmService 联动** - 方法体只记日志 **步骤**: | # | 任务 | 涉及文件 | 说明 | |---|------|----------|------| | 2.1 | 从 ProjectProfile 读设备列表 | `DeviceStateMachine.cs` | `InitializeDefaultDevices()` 改为从 `ProjectService.CurrentProfile` 读设备,不再硬编码 | | 2.2 | 接入 PLC 数据驱动状态转换 | `DeviceStateMachine.cs` | 订阅 `PlcPollingService.DataUpdated` 事件,根据 `PumpRunning`/`PumpFault` 信号触发状态转换 | | 2.3 | 添加状态变更事件 | `DeviceStateMachine.cs` | `event Action StateChanged`,供 UI/通知消费 | | 2.4 | 接入 AlarmService | `AlarmService.cs` | 设备进入 Fault 状态时自动触发报警;报警恢复时自动转 Maintenance | | 2.5 | ViewAViewModel 消费状态机 | `ViewAViewModel.cs` | 替换手写的 `UpdateDeviceStatuses`,改读 DeviceStateMachine 的状态 | | 2.6 | 状态变更持久化 | `DeviceStateMachine.cs` | 写入 `equipment_statuses` 表,支持历史查询 | **完成标准**: - [ ] 泵/风机状态由状态机管理,不再用散落的 bool 字段 - [ ] 状态转换合法(Fault 不能直接 → Running) - [ ] 状态变更事件可供 UI 和通知消费 - [ ] 设备数量从项目配置读取 --- ## 阶段三:WorkflowService 完善(工艺流程编排) **目标**:让污水处理的多步骤流程可控、可配置。 **现状**: - `WorkflowService` 是简化版工作流引擎(Elsa 失败后的降级方案) - 只有 `RegisterSampleWorkflows()` 里的日志占位 - 没有与任何业务服务联动 **步骤**: | # | 任务 | 涉及文件 | 说明 | |---|------|----------|------| | 3.1 | 定义工作流模型 | `Models/WorkflowDefinition.cs` | `WorkflowDefinition`(步骤列表)、`WorkflowStep`(条件 + 动作 + 下一步) | | 3.2 | 从 JSON 配置加载工作流 | `WorkflowService.cs` | `Workflows` 配置节 → `WorkflowDefinition` 列表 | | 3.3 | 实现工作流执行引擎 | `WorkflowService.cs` | `ExecuteAsync(workflowId)`:按步骤执行,支持条件分支、等待、超时 | | 3.4 | 实现内置动作 | `WorkflowService.cs` | 预置动作:`StartPump`/`StopPump`/`CheckLevel`/`SendNotification` 等 | | 3.5 | 与 DeviceStateMachine 联动 | `WorkflowService.cs` | 工作流步骤可以查询/等待设备状态 | | 3.6 | UI 展示工作流状态 | `ViewFViewModel.cs` | 显示当前运行的工作流、步骤进度、历史执行记录 | **完成标准**: - [ ] 可通过 JSON 配置定义工作流 - [ ] 工作流能驱动实际控制(启停泵、阀门切换) - [ ] 工作流执行有审计日志 --- ## 阶段四:PlcDrivers 接入(多品牌 PLC 支持) **目标**:让项目支持西门子以外的 PLC 品牌。 **现状**: - 7 个驱动文件已恢复(Siemens/AllenBradley/Mitsubishi/Omron/ModbusTcp) - `PlcDriverFactory` 完整,但 `PlcService` 直接硬编码 `SiemensS7Net` - `PlcConfig` 地址格式是西门子专用的(VD100, Q0.0) **步骤**: | # | 任务 | 涉及文件 | 说明 | |---|------|----------|------| | 4.1 | PlcConfig 添加协议选择 | `PlcConfig.cs` + `yzwater-config.json` | 新增 `PlcProtocol` 配置项,默认 `SiemensS7` | | 4.2 | PlcService 使用 PlcDriverFactory | `PlcService.cs` | `ConnectAsync()` 中根据协议创建对应驱动,替换硬编码的 `SiemensS7Net` | | 4.3 | 统一地址格式 | `PlcConfig.cs` + 各驱动 | 定义通用地址模型,各驱动负责转换为品牌专用地址 | | 4.4 | UI 协议选择 | `ViewBView.axaml` + `ViewBViewModel.cs` | 参数设置页添加 PLC 品牌/协议下拉框 | | 4.5 | 集成测试 | `tests/` | 至少对 ModbusTcp 做一次真实连接测试 | **完成标准**: - [ ] `yzwater-config.json` 可配置 PLC 协议 - [ ] 至少 2 种协议可正常读写(Siemens + 另一品牌) - [ ] UI 可切换协议 --- ## 依赖关系 ``` 阶段零(项目档案接线)← 扬杰二厂急需,最先做 ↓ 阶段一(DI 迁移)← 基础,建议最先做(可与阶段零并行) ↓ 阶段二(状态机)← 需要 DI 让状态机可注入 ↓ 阶段三(工作流)← 依赖状态机的设备状态查询 阶段四(多品牌 PLC)← 独立,可随时启动(当前项目用 S7-200 Smart + Hsl S7 协议) ``` ## 时间估算 | 阶段 | 预估工作量 | 优先级 | |------|-----------|--------| | 阶段零:项目档案接线 | 1~2 天 | ⭐⭐⭐ 最高(扬杰二厂急需) | | 阶段一:DI 迁移 | 2~3 天 | ⭐⭐⭐ 最高(基础) | | 阶段二:状态机 | 3~4 天 | ⭐⭐⭐ 高(工业控制核心) | | 阶段三:工作流 | 4~5 天 | ⭐⭐ 中(自动化增值) | | 阶段四:多品牌 PLC | 2~3 天 | ⭐ 按需(有新项目时) |