|
@@ -679,14 +679,18 @@ Expected: PASS(2 绿)。
|
|
|
```
|
|
```
|
|
|
> `snapshot` 为该方法内构造的 `MonitorSnapshot` 局部变量名;若现有代码用对象初始化器一次性 `return new MonitorSnapshot{...}`,改为先赋给局部 `var snapshot = new MonitorSnapshot{...};` 再补上面映射,最后 `return snapshot;`。需要 `using System.Linq;`(AppData 已用 Linq)。
|
|
> `snapshot` 为该方法内构造的 `MonitorSnapshot` 局部变量名;若现有代码用对象初始化器一次性 `return new MonitorSnapshot{...}`,改为先赋给局部 `var snapshot = new MonitorSnapshot{...};` 再补上面映射,最后 `return snapshot;`。需要 `using System.Linq;`(AppData 已用 Linq)。
|
|
|
|
|
|
|
|
-- [ ] **Step 7: AppData 加 ReportStartupFaults(复用现有告警通道)**
|
|
|
|
|
|
|
+- [ ] **Step 7: AppData 加 ReportStartupFaults(复用现有 `reportAlarm` 报警闭环 —— 写 alarm 表/双端列表/短信电话通知/可消警)**
|
|
|
|
|
+
|
|
|
|
|
+> **2026-06-23 修正**:走 `SerialBinController.ReportAlarmController`(→ `/reportAlarm` → 报警责任链 → `alarm` 表 → front/operate 报警列表 + **短信/电话通知** + 静音/消警),**不走** `reportCloudAlarm`(那只发 IM 群消息、不入闭环)。状态码语义:每维度 **0=正常 / 1=异常 / -1=跳过**(`AlarmDTO` 接口确认;运行期 ComStateEvent 即按此只填 comState、其余 -1)。**无新增 alarmTypeKey、无 Java 改动。**
|
|
|
|
|
+>
|
|
|
|
|
+> `ReportAlarmController` 签名(`SerialBinController.cs`):`ReportAlarmController(string tlSn, int housesn, int houseState, int comState, int photoState, int wellSN, int airSwapState)`;经 `AppData.SerialBinController` 调用(与运行期 `HouseBin_HouseStateEvent` 同一入口)。
|
|
|
|
|
|
|
|
-参照现有 `MqttAlarm`(`AppData.cs:1350`,走 `HttpService.AlarmApi1`)与 `AlarmApi`(`HttpService.cs:54`,POST `/api/tl/control/alarm/reportCloudAlarm`,带 houseSn/wellSn)。新增:
|
|
|
|
|
```csharp
|
|
```csharp
|
|
|
/// <summary>
|
|
/// <summary>
|
|
|
- /// 上报启动期坏舱告警(每坏舱一条)。复用 HttpService.AlarmApi(reportCloudAlarm)。
|
|
|
|
|
- /// alarmTypeKey 按故障类型映射;paramList 携带原因/阶段。全 try 兜底,失败不影响启动。
|
|
|
|
|
- /// 注:新 alarmTypeKey 需在 Java 告警字典登记(否则落库被拒)—— 见计划「跨端依赖」。
|
|
|
|
|
|
|
+ /// 上报启动期坏舱告警(每坏舱一条),复用现有 reportAlarm 报警闭环:
|
|
|
|
|
+ /// 写 alarm 表 → front/operate 报警列表 + 短信/电话通知 + 可静音/恢复自动消警。
|
|
|
|
|
+ /// 维度码 0正常/1异常/-1跳过:相机类故障→photoState=1,串口/编号类→comState=1,其余维度 -1。
|
|
|
|
|
+ /// 全 try 兜底,失败不影响启动。无新增 alarmTypeKey、无 Java 改动。
|
|
|
/// </summary>
|
|
/// </summary>
|
|
|
public void ReportStartupFaults()
|
|
public void ReportStartupFaults()
|
|
|
{
|
|
{
|
|
@@ -695,24 +699,32 @@ Expected: PASS(2 绿)。
|
|
|
try { tlSn = TLSetting?.tlSn ?? ""; } catch { }
|
|
try { tlSn = TLSetting?.tlSn ?? ""; } catch { }
|
|
|
foreach (var f in StartupFaults)
|
|
foreach (var f in StartupFaults)
|
|
|
{
|
|
{
|
|
|
|
|
+ if (f.HouseSn <= 0) continue; // 舱号未知(相机/串口级)无法定位到舱,跳过上报(仍在 /status Faults 里可见)
|
|
|
try
|
|
try
|
|
|
{
|
|
{
|
|
|
- string key = f.Type == HouseFaultType.CcdSnMissing || f.Type == HouseFaultType.CameraDuplicateSn || f.Type == HouseFaultType.CameraReadFailed
|
|
|
|
|
- ? "HOUSE_CAMERA_FAULT"
|
|
|
|
|
- : (f.Type == HouseFaultType.SerialReadException ? "HOUSE_SERIAL_FAULT" : "HOUSE_INIT_EXCLUDED");
|
|
|
|
|
- HttpService.AlarmApi(tlSn, f.HouseSn > 0 ? f.HouseSn : 0, 0, key,
|
|
|
|
|
- new List<string> { f.Type.ToString(), f.Reason, f.Stage });
|
|
|
|
|
|
|
+ // 相机类故障 → 拍照状态异常;串口/编号类 → 串口状态异常;其余维度 -1 跳过(不误清别的告警)。
|
|
|
|
|
+ bool cameraFault = f.Type == HouseFaultType.CcdSnMissing
|
|
|
|
|
+ || f.Type == HouseFaultType.CcdSnDuplicate
|
|
|
|
|
+ || f.Type == HouseFaultType.CameraDuplicateSn
|
|
|
|
|
+ || f.Type == HouseFaultType.CameraReadFailed;
|
|
|
|
|
+ int comState = cameraFault ? -1 : 1; // 串口/编号/Init 异常
|
|
|
|
|
+ int photoState = cameraFault ? 1 : -1; // 相机异常
|
|
|
|
|
+ SerialBinController.ReportAlarmController(tlSn, f.HouseSn,
|
|
|
|
|
+ houseState: -1, comState: comState, photoState: photoState,
|
|
|
|
|
+ wellSN: -1, airSwapState: -1);
|
|
|
}
|
|
}
|
|
|
catch (Exception ex) { ExLog(ex, "ReportStartupFaults"); }
|
|
catch (Exception ex) { ExLog(ex, "ReportStartupFaults"); }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
+> ⚠ **真机确认点(Task7)**:报警链部分 handler 按 houseSn 查 `house`/`tlSetting`;被排除的坏舱可能未写入 house 表 → 若 alarm 未落库,Task7 记录并补一步(确保 house 行存在 / 或对排除舱另走内部 reportAlarmData)。
|
|
|
|
|
|
|
|
- [ ] **Step 8: 编译 + 跑全量单测**
|
|
- [ ] **Step 8: 编译 + 跑全量单测**
|
|
|
|
|
|
|
|
Run: `dotnet build ivf_tl_operate_2.0/control/ivf_tl_Control.sln -c Debug` → 0 错
|
|
Run: `dotnet build ivf_tl_operate_2.0/control/ivf_tl_Control.sln -c Debug` → 0 错
|
|
|
Run: `dotnet test ivf_tl_operate_2.0/control/IvfTl.ControlHost.Tests/IvfTl.ControlHost.Tests.csproj`
|
|
Run: `dotnet test ivf_tl_operate_2.0/control/IvfTl.ControlHost.Tests/IvfTl.ControlHost.Tests.csproj`
|
|
|
Expected: 既有 27 + 新增(HouseFault 2 + Policy 6 + Snapshot 2)= **37 绿 0 失败**。
|
|
Expected: 既有 27 + 新增(HouseFault 2 + Policy 6 + Snapshot 2)= **37 绿 0 失败**。
|
|
|
|
|
+**无新增 alarmTypeKey、无 Java 字典登记依赖**(复用现有 reportAlarm 闭环)。
|
|
|
|
|
|
|
|
- [ ] **Step 9: 提交**
|
|
- [ ] **Step 9: 提交**
|
|
|
|
|
|
|
@@ -755,20 +767,22 @@ git commit -m "docs(house-fault): 第一阶段 control 坏舱剔除真机拔插
|
|
|
|
|
|
|
|
# 后续阶段(提纲,第一阶段落地后单独拆细)
|
|
# 后续阶段(提纲,第一阶段落地后单独拆细)
|
|
|
|
|
|
|
|
-## 第二阶段:运行期故障升级 + 去抖(control,可自主)
|
|
|
|
|
-- `HouseBin/BufferBottleBin.MainThread`、`ComBin.StartSendCommandThread` 的 `catch` 里:同舱连续失败计数达阈值(去抖,避免每圈刷屏)→ 升级一条 `HouseFault{RuntimeFault}` 进 `AppData.StartupFaults`(改名/或新增 `RuntimeFaults`)+ `ReportStartupFaults` 同款上报 `HOUSE_RUNTIME_FAULT`;失败计数清零条件 = 该舱恢复一次成功通讯。
|
|
|
|
|
-- 纯逻辑(计数/阈值/去抖)可 TDD;升级动作真机验证(运行中拔串口/相机)。
|
|
|
|
|
|
|
+## 第二阶段:运行期故障升级(control,**先核实再决定是否做**)
|
|
|
|
|
+- **2026-06-23 修正**:核实发现**运行期串口/相机异常已接现有报警闭环**(`HouseBin.ComBin_ComStateEvent` → `HouseStateEvent` → `ReportAlarmController` → 报警链 → alarm 表 + 短信电话)。故本阶段**不再造并行通道**。
|
|
|
|
|
+- 真机阶段先核实现有运行期上报是否有缺口(如:某维度故障没触发 ComStateEvent、或失败需去抖防刷屏);**确有缺口才补**(在对应 catch 里按阈值/去抖调同一个 `ReportAlarmController`,维度码 0/1/-1)。无缺口则本阶段仅做真机确认、不改码。
|
|
|
|
|
+- 纯逻辑(计数/阈值/去抖)若需补,可 TDD;升级动作真机验证(运行中拔串口/相机)。
|
|
|
|
|
|
|
|
## 第三阶段:operate 监控页"舱故障"区(真机门控)
|
|
## 第三阶段:operate 监控页"舱故障"区(真机门控)
|
|
|
-- `ivf_tl_Operate` 监控页(读 `ControlClient` → `/status` 的 `snapshot.Faults`)新增"舱故障"区:红色高亮列出每故障舱(舱号/类型/时间/已隔离),与现有监控三块并列。
|
|
|
|
|
|
|
+- operate 报警走现有 alarm 闭环 → 顶部"系统异常(N)"+报警列表自动反映(无需改)。
|
|
|
|
|
+- 另:`ivf_tl_Operate` 监控页(读 `ControlClient` → `/status` 的 `snapshot.Faults`)新增"舱故障"区:红色高亮列出每**启动被隔离**舱(舱号/类型/时间/已隔离),补充 alarm 表不直接表达的"被隔离"信息。
|
|
|
- 复用现有轮询;UI 真机门控(需 operate 外壳跑起来,受僵尸 operate Mutex 影响,需先清)。
|
|
- 复用现有轮询;UI 真机门控(需 operate 外壳跑起来,受僵尸 operate Mutex 影响,需先清)。
|
|
|
|
|
|
|
|
-## 第四阶段:front 告警展示(真机门控)+ 跨端依赖
|
|
|
|
|
-- **跨端依赖(必须先确认):** 新 alarmTypeKey(`HOUSE_INIT_EXCLUDED`/`HOUSE_CAMERA_FAULT`/`HOUSE_SERIAL_FAULT`/`HOUSE_RUNTIME_FAULT`)需在 Java 告警字典/告警类型配置登记,否则 `reportCloudAlarm` 落库被拒、front 也无从展示。Task 7 Step 4 已先探;此阶段落地登记。
|
|
|
|
|
-- front 舱位图/告警列表:故障舱标红 + 统一文案("X 号舱相机故障,已隔离,其余舱正常");接现有 alarm_data + MQTT 流。
|
|
|
|
|
|
|
+## 第四阶段:front 告警展示(真机门控)
|
|
|
|
|
+- **2026-06-23 修正**:复用现有 `reportAlarm` 闭环 = **复用现成告警类型(串口异常/相机异常等),无新建 alarmTypeKey、无 Java 字典登记依赖**。坏舱告警进 alarm 表后,front 报警列表/舱位图**本来就会展示并标红**。
|
|
|
|
|
+- 本阶段只需真机确认:坏舱(尤其启动被排除舱)的告警在 front 列表正确显示(舱号/类型/时间)、文案达意;若展示文案需微调再动 front。接现有 alarm + MQTT 流。
|
|
|
|
|
|
|
|
## 第五阶段:真机拔插整体验收(spec §48-51 三条)
|
|
## 第五阶段:真机拔插整体验收(spec §48-51 三条)
|
|
|
-- ① 启动期半坏舱排除、其余正常;② 运行期拔串口/相机隔离、其余采集不中断;③ 双端(operate 监控页 + front)都明确显示故障舱(舱号/类型/时间)。
|
|
|
|
|
|
|
+- ① 启动期半坏舱排除、其余正常;② 运行期拔串口/相机隔离、其余采集不中断;③ 双端闭环(alarm 表落坏舱告警 → front 报警列表 + operate"系统异常"可见 + 监控页"舱故障"区显示被隔离舱;短信/电话按配置通知;恢复后消警)。
|
|
|
- 逐条回写 `待验证清单.md`。
|
|
- 逐条回写 `待验证清单.md`。
|
|
|
|
|
|
|
|
---
|
|
---
|
|
@@ -776,9 +790,10 @@ git commit -m "docs(house-fault): 第一阶段 control 坏舱剔除真机拔插
|
|
|
## 自查(写完对照 spec)
|
|
## 自查(写完对照 spec)
|
|
|
|
|
|
|
|
- **spec §27 启动期按舱容错** → Task 2(Policy 剔除)+ Task 3(SerialBin 登记)+ Task 4(InitTL 不再一刀切)+ Task 5(InitHouse 逐舱兜底)。✓
|
|
- **spec §27 启动期按舱容错** → Task 2(Policy 剔除)+ Task 3(SerialBin 登记)+ Task 4(InitTL 不再一刀切)+ Task 5(InitHouse 逐舱兜底)。✓
|
|
|
-- **spec §28 双端明确提示** → Task 6(快照 Faults + ReportStartupFaults 上报)覆盖 control 侧出口;operate/front 展示在第三/四阶段。✓(第一阶段做到"故障可被双端拿到",展示分阶段)
|
|
|
|
|
|
|
+- **spec §28 双端明确提示** → Task 6(快照 Faults + ReportStartupFaults 走 reportAlarm 闭环)覆盖 control 侧出口;operate/front 展示在第三/四阶段(复用现有 alarm 列表)。✓
|
|
|
- **spec §33-35 设计要点(区分致命/单舱、剔除坏舱、逐舱 try-catch)** → Task 2/3/4/5 一一对应。✓
|
|
- **spec §33-35 设计要点(区分致命/单舱、剔除坏舱、逐舱 try-catch)** → Task 2/3/4/5 一一对应。✓
|
|
|
-- **spec §38-41 统一上报(复用 alarm_data+MQTT、/status 加舱故障字段、运行期去抖)** → Task 6(复用 reportCloudAlarm + 快照字段)+ 第二阶段(去抖)。✓
|
|
|
|
|
-- **spec §48-51 真机验收** → Task 7(启动期)+ 第五阶段(运行期+双端)。✓
|
|
|
|
|
-- **类型一致性自查:** `HouseFault`(Entity)字段贯穿 SerialBin/InitTL/AppData;`HouseFaultRow`(MonitorSnapshot)与 AppData 映射字段名一致(HouseSn/FaultType/Reason/Stage/At/Isolated);`StartupFaultPolicy.RunnableHouses/IsFatal/BadHouseSns` 签名在 Task2 定义、Task4 调用一致;`AppData.StartupFaults`/`ReportStartupFaults` Task4 调用、Task6 定义一致(执行注:先做 Task6 再回填 Task4 调用,保证中途可编译)。✓
|
|
|
|
|
|
|
+- **spec §4.2 统一上报(2026-06-23 修正:复用现有 reportAlarm 报警闭环——alarm 表/双端列表/短信电话/消警,不走 reportCloudAlarm 群消息、无新建告警类型)** → Task 6(ReportStartupFaults 走 ReportAlarmController + 快照 Faults 字段)+ 第二阶段(运行期已接闭环,仅按需补)。✓
|
|
|
|
|
+- **spec §48-51 真机验收** → Task 7(启动期 + alarm 落库确认)+ 第五阶段(运行期+双端闭环)。✓
|
|
|
|
|
+- **类型一致性自查:** `HouseFault`(Entity)字段贯穿 SerialBin/InitTL/AppData;`HouseFaultRow`(MonitorSnapshot)与 AppData 映射字段名一致(HouseSn/FaultType/Reason/Stage/At/Isolated);`StartupFaultPolicy.RunnableHouses/IsFatal/BadHouseSns` 签名在 Task2 定义、Task4 调用一致;`AppData.StartupFaults`/`ReportStartupFaults` Task4 调用、Task6 定义一致;`ReportStartupFaults` 走 `SerialBinController.ReportAlarmController(tlSn,housesn,houseState,comState,photoState,wellSN,airSwapState)`(与运行期同入口)。**执行注:先做 Task6 再回填 Task4 调用,保证中途可编译。** ✓
|
|
|
|
|
+- **告警通道修正自查:** 已全文废弃 `reportCloudAlarm`/新建 `HOUSE_*` alarmTypeKey/Java 字典登记依赖;改走现有 `reportAlarm` 闭环(状态码 0/1/-1)。短信电话报警**保留并复用**(报警链内置 getNotifier→短信/电话模板)。✓
|
|
|
- **占位扫描:** 无 TBD/TODO;每代码步均有完整代码块。真机行为类步骤(Task3/4/5/7)给出确切编辑点 file:line 与验证预期,非"自行处理"。✓
|
|
- **占位扫描:** 无 TBD/TODO;每代码步均有完整代码块。真机行为类步骤(Task3/4/5/7)给出确切编辑点 file:line 与验证预期,非"自行处理"。✓
|