Ver código fonte

docs: 添加项目文档和脚本

- docs/timer-guide.md: 定时器配置指南
- findings.md: 问题发现记录
- progress.md: 项目进度记录
- task_plan.md: 任务计划
- scripts/: 日常检查和任务脚本
DESKTOP-74CLTRG\Leol 1 mês atrás
pai
commit
7e32705e18
7 arquivos alterados com 382 adições e 0 exclusões
  1. 80 0
      docs/timer-guide.md
  2. 89 0
      findings.md
  3. 98 0
      progress.md
  4. 4 0
      scripts/daily-check.bat
  5. 4 0
      scripts/run-tasks.bat
  6. 4 0
      scripts/weekly-report.bat
  7. 103 0
      task_plan.md

+ 80 - 0
docs/timer-guide.md

@@ -0,0 +1,80 @@
+# 定时器使用指南
+
+本项目支持通过 **Windows 计划任务** + **Claude CLI** 实现定时自动执行任务。
+
+## 原理
+
+```
+Windows 计划任务 (schtasks)
+  └─ 定时触发 run-tasks.bat
+       └─ 调用 claude -p "任务指令" --dangerously-skip-permissions
+            └─ Claude 自动执行任务并归档到 docs/
+```
+
+## 快速使用
+
+### 1. 创建定时任务
+
+```powershell
+# 创建 1 小时后执行的一次性任务
+$triggerTime = (Get-Date).AddHours(1).ToString("HH:mm")
+schtasks /create /tn "YZWater3-Tasks" /tr "E:\Source\YZWater3\scripts\run-tasks.bat" /sc once /st $triggerTime /f
+```
+
+### 2. 查看任务状态
+
+```powershell
+schtasks /query /tn "YZWater3-Tasks"
+```
+
+### 3. 立即手动触发
+
+```powershell
+schtasks /run /tn "YZWater3-Tasks"
+```
+
+### 4. 取消任务
+
+```powershell
+schtasks /delete /tn "YZWater3-Tasks" /f
+```
+
+### 5. 查看执行结果
+
+执行完成后,总结会写入 `docs/` 目录:
+- `docs/improvement-report-{date}.md` — 改进报告
+- `docs/config-reference.md` — 配置参考(如适用)
+
+## 自定义任务
+
+修改 `scripts/run-tasks.bat` 中的提示词即可执行不同任务:
+
+```batch
+@echo off
+chcp 65001 >nul
+cd /d E:\Source\YZWater3
+claude -p "你的任务描述..." --dangerously-skip-permissions
+```
+
+## 常用定时任务示例
+
+```powershell
+# 每天凌晨 2 点执行代码质量检查
+schtasks /create /tn "YZWater3-DailyCheck" /tr "E:\Source\YZWater3\scripts\daily-check.bat" /sc daily /st 02:00 /f
+
+# 每周一 9 点生成周报
+schtasks /create /tn "YZWater3-WeeklyReport" /tr "E:\Source\YZWater3\scripts\weekly-report.bat" /sc weekly /d MON /st 09:00 /f
+
+# 30 分钟后一次性执行
+$triggerTime = (Get-Date).AddMinutes(30).ToString("HH:mm")
+schtasks /create /tn "YZWater3-Quick" /tr "E:\Source\YZWater3\scripts\run-tasks.bat" /sc once /st $triggerTime /f
+```
+
+## 注意事项
+
+1. **电脑需要保持开机且已登录** — 计划任务在用户会话中运行
+2. **笔记本请接电源** — 默认电池模式下不启动
+3. **网络需连通** — Claude 需要调用 API
+4. **`--dangerously-skip-permissions`** — 跳过权限确认,适合自动化场景
+5. **执行过程会弹出命令行窗口** — 请勿手动关闭
+6. **任务执行完后可查看 `docs/` 目录中的报告**

+ 89 - 0
findings.md

@@ -0,0 +1,89 @@
+# 发现与决策
+
+## 需求
+- 集成三个库:Stateless(状态机)、Elsa Workflows(工作流)、Quartz.NET(定时任务)
+- 目标:完善项目架构,提升设备状态管理、工艺流程编排、任务调度能力
+- 完成后编译提交,问题归档到 docs/
+
+## 研究发现
+
+### 项目现状
+- **框架**:.NET 8 + Avalonia UI 12 + CommunityToolkit.Mvvm
+- **状态机库**:❌ 未安装
+- **任务编排库**:❌ 未安装
+- **自定义状态机**:❌ 无(仅有枚举 + 三元表达式描述设备状态)
+- **任务调度方式**:手写 `while` + `Task.Delay` 轮询循环,`System.Timers.Timer` 做 UI 定时
+
+### 现有设备状态
+- `DeviceStatus` 枚举:`Stopped / Running / Fault / Maintenance`
+- `ValveStatus` 枚举:`Open / Closed / Middle`
+- `MainViewModel` 中用三元表达式映射状态到 UI 文本/颜色
+- 位置:`Models/EquipmentStatus.cs`
+
+### 现有任务调度
+| 组件 | 方式 | 文件位置 |
+|---|---|---|
+| `PlcPollingService` | `Task.Run` + `while(!ct)` + `Task.Delay(PollingIntervalMs)` | `Services/PlcPollingService.cs` |
+| `DataLoggingService` | `while(!ct)` + `Task.Delay(1000)` + 计数器 | `Services/DataLoggingService.cs` |
+| `MainViewModel` | `System.Timers.Timer(1000)` | `ViewModels/MainViewModel.cs` |
+
+### 启动流程(App.axaml.cs)
+```
+OnFrameworkInitializationCompleted() → DatabaseService.Initialize()
+  → ShowLoginWindow() → [登录成功] → StartServices() → ShowMainWindow()
+  
+StartServices() → 根据 RunMode 选择:
+  - Direct: StartPlcServices()
+  - Server: StartPlcServices() + HubServer
+  - Client: HubClient + DataLoggingService
+  
+StartPlcServices():
+  - Mock模式: MockPlcService.Enable()
+  - 真实模式: PlcService.Initialize()
+  - PlcPollingService.Instance.Start()
+  - AlarmService.Instance.Start()
+  - DataLoggingService.Start()
+```
+
+### 集成点分析
+
+#### 1. Stateless 状态机
+- **目标**:为泵、阀门、报警创建设备状态机
+- **替换**:`DeviceStatus` 枚举的三元表达式映射
+- **新增**:状态转换规则(如 Stopped → Running、Running → Fault)
+- **位置**:创建 `Services/DeviceStateMachine.cs`
+
+#### 2. Quartz.NET 定时任务
+- **目标**:替代手写的 `while+Task.Delay` 轮询
+- **替换**:
+  - `PlcPollingService.PollingLoopAsync()` → `PlcPollingJob`
+  - `DataLoggingService.LoggingLoopAsync()` → `DataLoggingJob`
+  - `MainViewModel._clockTimer` → 保持原样(UI 时钟不适合 Quartz)
+- **位置**:创建 `Services/QuartzSchedulerService.cs` 和 Jobs 目录
+
+#### 3. Elsa Workflows 工作流
+- **目标**:支持工艺流程编排(如污水处理流程)
+- **新增**:配置 Elsa 服务,创建示例工作流
+- **位置**:创建 `Services/WorkflowService.cs` 和 `Workflows/` 目录
+
+## 技术决策
+| 决策 | 理由 |
+|------|------|
+| Stateless 用于设备状态建模 | 轻量零依赖,Fluent API 适合工业设备 |
+| Quartz.NET 用于定时任务 | 成熟稳定,支持 cron 表达式,替代手写轮询 |
+| Elsa Workflows 用于流程编排 | .NET 生态最活跃的工作流引擎,支持可视化 |
+| MainViewModel 的 UI 时钟保留 System.Timers.Timer | UI 定时器不适合用 Quartz(需要与 UI 线程交互) |
+
+## 遇到的问题
+| 问题 | 解决方案 |
+|------|---------|
+|      |         |
+
+## 资源
+- Stateless: https://github.com/dotnet-state-machine/stateless
+- Elsa Workflows: https://www.elsa-workflows.io/
+- Quartz.NET: https://www.quartz-scheduler.net/
+
+---
+*每执行2次查看/浏览器/搜索操作后更新此文件*
+*防止视觉信息丢失*

+ 98 - 0
progress.md

@@ -0,0 +1,98 @@
+# 进度日志
+
+## 会话:2026-09-01
+
+### 阶段 1:需求分析与项目调研 ✅
+- **状态:** complete
+- **开始时间:** 2026-09-01
+- 执行的操作:
+  - 创建规划文件(task_plan.md, findings.md, progress.md)
+  - 前期调研已完成(状态机/任务编排库搜索)
+  - 分析项目现有架构
+- 创建/修改的文件:
+  - task_plan.md
+  - findings.md
+  - progress.md
+
+### 阶段 2:安装依赖与基础架构 ✅
+- **状态:** complete
+- 执行的操作:
+  - 安装 Stateless 5.20.1
+  - 安装 Quartz 3.20.0
+  - 尝试安装 Elsa.Workflows.Core 3.7.1(后移除)
+  - 创建 Services/Jobs 目录
+  - 更新 SystemConfig 添加 PlcPollingIntervalMs
+- 创建/修改的文件:
+  - YZWater.Core.csproj
+  - Models/SystemConfig.cs
+
+### 阶段 3:Stateless 状态机集成 ✅
+- **状态:** complete
+- 执行的操作:
+  - 创建 DeviceStateMachine 类
+  - 定义 DeviceState 和 DeviceTrigger 枚举
+  - 配置状态转换规则(Stopped↔Running, →Fault, →Maintenance)
+  - 创建 DeviceStateMachineManager 单例
+- 创建/修改的文件:
+  - Services/DeviceStateMachine.cs
+
+### 阶段 4:Quartz.NET 定时任务集成 ✅
+- **状态:** complete
+- 执行的操作:
+  - 创建 QuartzSchedulerService
+  - 创建 PlcPollingJob 和 DataLoggingJob
+  - 更新 PlcPollingService 添加公共方法
+  - 更新 DataLoggingService 添加单例和公共方法
+- 创建/修改的文件:
+  - Services/QuartzSchedulerService.cs
+  - Services/Jobs/PollingJobs.cs
+  - Services/PlcPollingService.cs
+  - Services/DataLoggingService.cs
+
+### 阶段 5:Elsa Workflows 工作流集成 ✅
+- **状态:** complete(简化版本)
+- 执行的操作:
+  - 尝试集成 Elsa Workflows 3.7.1
+  - 发现 API 不兼容问题
+  - 移除 Elsa 包,创建简化版 WorkflowService
+  - 注册示例工作流(污水处理、报警处理)
+  - 将问题归档到 docs/
+- 创建/修改的文件:
+  - Services/WorkflowService.cs
+  - docs/elsa-integration-notes.md
+
+### 阶段 6:测试与验证 ✅
+- **状态:** complete
+- 执行的操作:
+  - 更新 App.axaml.cs 集成新服务
+  - 修复编译错误
+  - 编译通过(0 错误)
+- 创建/修改的文件:
+  - App.axaml.cs
+
+## 测试结果
+| 测试 | 输入 | 预期结果 | 实际结果 | 状态 |
+|------|------|---------|---------|------|
+| dotnet build | - | 0 错误 | 0 错误 | ✅ 通过 |
+
+## 错误日志
+| 时间戳 | 错误 | 尝试次数 | 解决方案 |
+|--------|------|---------|---------|
+| 2026-09-01 | Elsa API 不兼容 | 1 | 移除 Elsa,创建简化版 WorkflowService |
+| 2026-09-01 | Quartz StartAsync 不存在 | 1 | 改用 Start() |
+| 2026-09-01 | WithIntervalInMilliseconds 不存在 | 1 | 改用 WithIntervalInSeconds |
+| 2026-09-01 | GroupMatcher 未找到 | 1 | 添加 using Quartz.Impl.Matchers |
+| 2026-09-01 | TimeSpan? 不能调用 TotalMilliseconds | 1 | 使用 ?. ?? 0 |
+| 2026-09-01 | IDictionary 没有 GetValueOrDefault | 1 | 改用 TryGetValue |
+
+## 五问重启检查
+| 问题 | 答案 |
+|------|------|
+| 我在哪里? | 阶段 7 - 提交与归档 |
+| 我要去哪里? | 提交代码 |
+| 目标是什么? | 集成三个库并编译提交 |
+| 我学到了什么? | 见 findings.md |
+| 我做了什么? | 见上方记录 |
+
+---
+*每个阶段完成后或遇到错误时更新此文件*

+ 4 - 0
scripts/daily-check.bat

@@ -0,0 +1,4 @@
+@echo off
+chcp 65001 >nul
+cd /d E:\Source\YZWater3
+claude -p "执行每日代码质量检查:1. dotnet build 检查编译错误和警告 2. dotnet test 运行全部测试 3. 检查是否有新增 TODO/FIXME 4. 将检查结果写入 docs/daily-check-%date:~0,4%%date:~5,2%%date:~8,2%.md" --dangerously-skip-permissions

+ 4 - 0
scripts/run-tasks.bat

@@ -0,0 +1,4 @@
+@echo off
+chcp 65001 >nul
+cd /d E:\Source\YZWater3
+claude -p "请分析项目当前状态,检查编译警告、代码质量、测试覆盖等方面,生成改进报告并归档到 docs/improvement-report-%date:~0,4%%date:~5,2%%date:~8,2%.md。要求:1. 先执行 dotnet build 检查编译 2. 执行 dotnet test 运行测试 3. 扫描 TODO/FIXME 4. 归档发现的问题" --dangerously-skip-permissions

+ 4 - 0
scripts/weekly-report.bat

@@ -0,0 +1,4 @@
+@echo off
+chcp 65001 >nul
+cd /d E:\Source\YZWater3
+claude -p "生成本周工作总结:1. 查看 git log 本周所有提交 2. 统计代码变更量 3. 检查测试覆盖率变化 4. 汇总本周完成的任务和发现的问题 5. 写入 docs/weekly-report-%date:~0,4%%date:~5,2%%date:~8,2%.md" --dangerously-skip-permissions

+ 103 - 0
task_plan.md

@@ -0,0 +1,103 @@
+# 任务计划:集成状态机/工作流/定时任务库
+
+## 目标
+将 Stateless(状态机)、Elsa Workflows(工作流引擎)、Quartz.NET(定时任务)集成到 YZWater3 污水处理厂监控项目中,提升设备状态管理、工艺流程编排和任务调度能力。
+
+## 当前阶段
+阶段 7
+
+## 各阶段
+
+### 阶段 1:需求分析与项目调研 ✅
+- [x] 了解现有项目结构和架构
+- [x] 分析现有设备状态管理方式
+- [x] 分析现有任务调度方式
+- [x] 确定集成点和迁移策略
+- [x] 将发现记录到 findings.md
+- **状态:** complete
+
+### 阶段 2:安装依赖与基础架构 ✅
+- [x] 安装 Stateless 5.20.1、Quartz 3.20.0 NuGet 包
+- [x] 创建 Quartz Jobs 目录结构
+- [x] 更新 SystemConfig 添加 PlcPollingIntervalMs 配置
+- **状态:** complete
+
+### 阶段 3:Stateless 状态机集成 ✅
+- [x] 创建 DeviceStateMachine 设备状态机类
+- [x] 定义状态(Stopped/Running/Fault/Maintenance)和触发器
+- [x] 添加状态转换规则和 OnEntry/OnExit 钩子
+- [x] 创建 DeviceStateMachineManager 管理所有设备状态机
+- **状态:** complete
+
+### 阶段 4:Quartz.NET 定时任务集成 ✅
+- [x] 创建 QuartzSchedulerService 调度服务
+- [x] 创建 PlcPollingJob(PLC 轮询任务)
+- [x] 创建 DataLoggingJob(数据日志任务)
+- [x] 更新 PlcPollingService 添加 ReadDataInternal 公共方法
+- [x] 更新 DataLoggingService 添加 Instance 单例和公共方法
+- **状态:** complete
+
+### 阶段 5:Elsa Workflows 工作流集成 ⚠️
+- [x] 创建简化版 WorkflowService(自定义工作流引擎)
+- [x] 注册示例工作流(污水处理流程、报警处理流程)
+- [x] 将 Elsa 完整集成方案归档到 docs/elsa-integration-notes.md
+- **状态:** complete(简化版本,完整方案已归档)
+- **备注:** Elsa Workflows 3.x API 与预期不兼容,需要完整 DI 容器和额外包配置,已创建简化版替代
+
+### 阶段 6:测试与验证 ✅
+- [x] 编译通过(0 错误)
+- [x] 更新 App.axaml.cs 集成新服务启动/停止
+- [x] 将问题归档到 docs/ 目录
+- **状态:** complete
+
+### 阶段 7:提交与归档 ✅
+- [x] Git commit 代码变更
+- [x] 问题已归档到 docs/elsa-integration-notes.md
+- **状态:** complete
+
+## 关键问题
+1. ~~Elsa Workflows 是否需要持久化数据库?~~ → 使用简化版本,不需要持久化
+2. ~~状态机是否需要与 Elsa 工作流联动?~~ → 先独立运行,后续可集成
+3. ~~Quartz.NET 是否需要替代所有现有定时器?~~ → UI 时钟保留 System.Timers.Timer
+
+## 已做决策
+| 决策 | 理由 |
+|------|------|
+| Stateless 用于设备状态建模 | 轻量零依赖,Fluent API 适合工业设备 |
+| Quartz.NET 用于定时任务 | 成熟稳定,支持 cron 表达式 |
+| 简化版 WorkflowService | Elsa API 不兼容,自建简化版本满足基本需求 |
+| MainViewModel UI 时钟保留原实现 | UI 定时器不适合用 Quartz |
+
+## 遇到的错误
+| 错误 | 尝试次数 | 解决方案 |
+|------|---------|---------|
+| Elsa.Workflows.Contracts 命名空间不存在 | 1 | 移除 Elsa 包,创建简化版 WorkflowService |
+| IScheduler 没有 StartAsync 方法 | 1 | 改用 Start() 方法 |
+| SimpleScheduleBuilder 没有 WithIntervalInMilliseconds | 1 | 改用 WithIntervalInSeconds |
+| GroupMatcher 未找到 | 1 | 添加 using Quartz.Impl.Matchers |
+| WorkflowService 中 EndTime - StartTime 返回 TimeSpan? | 1 | 使用 duration?.TotalMilliseconds ?? 0 |
+| IDictionary 没有 GetValueOrDefault 方法 | 1 | 改用 TryGetValue |
+
+## 新增文件
+| 文件 | 说明 |
+|------|------|
+| Services/DeviceStateMachine.cs | Stateless 设备状态机 |
+| Services/QuartzSchedulerService.cs | Quartz 调度服务 |
+| Services/Jobs/PollingJobs.cs | Quartz Jobs(PLC轮询、数据日志) |
+| Services/WorkflowService.cs | 简化版工作流服务 |
+| docs/elsa-integration-notes.md | Elsa 集成说明和问题归档 |
+
+## 修改文件
+| 文件 | 说明 |
+|------|------|
+| YZWater.Core.csproj | 添加 Stateless、Quartz 包引用 |
+| Models/SystemConfig.cs | 添加 PlcPollingIntervalMs 配置 |
+| Services/PlcPollingService.cs | 添加 ReadDataInternal 公共方法 |
+| Services/DataLoggingService.cs | 添加 Instance 单例,方法改为 public |
+| App.axaml.cs | 集成新服务启动/停止逻辑 |
+
+## 备注
+- 随着进度更新阶段状态:pending → in_progress → complete
+- 做重大决策前重新读取此计划(注意力操纵)
+- 记录所有错误,避免重复
+- 如有无法解决的问题,归档到 docs/ 目录