# SecMPS 统一问题清单 2026-06-03 修复方案 > **版本**: 1.0 > **日期**: 2026-06-03 > **基准**: `SecMPS统一问题清单20260603.md` > **原则**: 按优先级逐项修复,每项修复后编译验证;涉及网关/Vol.Pro 改动的放一组批量提交 --- ## 修复总览 | 阶段 | 优先级 | 涉及项目 | 文件数 | 预计 | |:---:|:---:|------|:---:|:---:| | F1 | P0-1 ~ P0-3 | gateway + Vol.Pro | 5 | 2h | | F2 | P1-1 ~ P1-6 | gateway + Vol.Pro + 库表 + 前端 | 8 | 4h | | F3 | P2-1 ~ P2-5 | gateway + warehouse | 8 | 2h | | F4 | P3-1 ~ P3-4 | gateway + 文档 | 4 | 1h | | **合计** | — | 4 项目 | **25** | **~9h** | --- ## 阶段 F1: P0 阻塞项修复(预计 2h) #### F1.1 [P0-1] RealtimePollJob 填充实现 - [ ] 编辑 `api_sqlsugar/Warehouse/Services/RealtimePollJob.cs` - [ ] 注入 `GatewayClient` + `Ibase_deviceRepository` - [ ] `Execute()` 中: 1. 查询在线 MC4 网关 (`gateway_nodes WHERE IsOnline=在线 AND AdapterTypes LIKE '%MC4%'`) 2. 查对应设备列表 (`base_device WHERE DeviceGroup='IoT设备' AND IsOnline=在线`) 3. 对每个设备调 `GatewayClient.GetRealtimeAsync(gwBaseUrl, adapterCode, sourceId)` 4. 结果写入 `iot_devicedata` 表(INSERT 新记录) - [ ] `dotnet build` → 0 错误 #### F1.2 [P0-2] 网关 A1 自注册 - [ ] 编辑 `gateway/src/IntegrationGateway.Host/Program.cs` - [ ] 在 `registry.InitializeAllAsync()` 后加入: ```csharp var nodeCode = gwCfg["NodeCode"] ?? "gw-default"; var nodeToken = gwCfg["NodeToken"] ?? ""; var adapterTypes = string.Join(",", registry.All.Select(a => a.AdapterCode)); await clientFactory.RegisterAsync(nodeCode, nodeToken, adapterTypes, volProUrl); ``` - [ ] `dotnet build` → 0 错误 #### F1.3 [P0-3] B 组路由认证 - [ ] 编辑 `gateway/src/IntegrationGateway.Host/Program.cs` - [ ] 在 `app.UseCors()` 之后添加中间件: ```csharp var gatewayKey = gwCfg["GatewayKey"]; if (!string.IsNullOrEmpty(gatewayKey)) { app.Use(async (context, next) => { var key = context.Request.Headers["X-Gateway-Key"].FirstOrDefault(); if (key == gatewayKey || context.Request.Path == "/") { await next(); } else { context.Response.StatusCode = 401; } }); } ``` - [ ] appsettings.json Gateway 段新增 `"GatewayKey": null` - [ ] Vol.Pro 端 `GatewayClient` 所有 HTTP 请求头自动附加 `X-Gateway-Key` - [ ] `dotnet build` → 0 错误 > **F1 提交点**: `Fix-P0: RealtimePollJob+A1自注册+B组认证` --- ## 阶段 F2: P1 重要项修复(预计 4h) #### F2.1 [P1-1] 网关新增批量实时值接口 - [ ] 编辑 `gateway/src/IntegrationGateway.Host/Program.cs` - [ ] 新增 B4-batch 路由: ```csharp app.MapPost("/api/gateway/realtime/{adapter}/batch", async (string adapter, BatchRealtimeRequest req) => { var a = registry.FindByCode(adapter); if (a == null) return Results.NotFound(); var results = new Dictionary>(); foreach (var deviceId in req.DeviceIds ?? new()) results[deviceId] = await a.GetRealtimeValuesAsync(deviceId); return Results.Ok(results); }); ``` - [ ] 新增 `record BatchRealtimeRequest(List? DeviceIds);` - [ ] `dotnet build` → 0 错误 #### F2.2 [P1-2] 批量级联离线标记 - [ ] 编辑 `api_sqlsugar/Warehouse/Services/HeartbeatMonitorJob.cs` - [ ] 替换逐条 `UpdateAsync` 为: ```csharp context.Repository.DbContext.Db.Ado.ExecuteCommand( "UPDATE base_device SET IsOnline='离线' WHERE GatewayNodeId=@id AND IsOnline='在线'", new { id = node.GatewayNodeId }); ``` - [ ] `dotnet build` → 0 错误 #### F2.3 [P1-3] 凭据安全化 - [ ] 编辑 `gateway/src/IntegrationGateway.Host/appsettings.json` - `NodeToken` → `null`, 加注释 "生产环境由 SECMPS_GATEWAY_TOKEN 环境变量注入" - Owl `Password` → `""`, 加注释 - KMS `ClientSecret` → `""`, 加注释 - [ ] 编辑 `gateway/src/IntegrationGateway.Host/Program.cs` - `gwCfg["NodeToken"]` → `Environment.GetEnvironmentVariable("SECMPS_GATEWAY_TOKEN") ?? gwCfg["NodeToken"]` - [ ] 编辑 `.gitignore` → 加 `**/bin/`、`**/obj/` - [ ] `git rm -r --cached gateway/src/IntegrationGateway.Host/bin/` #### F2.4 [P1-4] 前端网关地址统一化 - [ ] 编辑 `web.vite/public/index.html` 的 `window.apiConfig` → 加 `gatewayUrl: 'http://localhost:5100'` - [ ] 编辑 `web.vite/src/views/warehouse/device_manager/base_device.vue` - `const GW = 'http://localhost:5100'` → `const GW = window.apiConfig.gatewayUrl || 'http://localhost:5100'` - [ ] 编辑 `warehouse/src/api/gateway.ts` - `const GW_BASE = 'http://localhost:5100'` → 读取 `window.apiConfig.gatewayUrl` - [ ] 编辑 `warehouse/index.html` 的 `window.apiConfig` → 加 `gatewayUrl` #### F2.5 [P1-5] 规则引擎增加 DeviceId 映射 - [ ] 在规则引擎实现方案中增加 `BuildDeviceMappingAsync` 方法: ```csharp var deviceIds = rules.SelectMany(r => r.Conditions).Select(c => c.DeviceId).Distinct(); var devices = await _deviceRepo.FindAsync(d => deviceIds.Contains(d.DeviceId)); var map = devices.ToDictionary(d => d.DeviceId, d => (d.AdapterCode, d.SourceId)); ``` - [ ] 后续调网关时用 `map[cond.DeviceId]` 拼装 URL #### F2.6 [P1-6] 新建 warehouse_variable 表 - [ ] 执行 SQL: ```sql CREATE TABLE warehouse_variable ( VariableId INT IDENTITY PRIMARY KEY, DeviceId INT NOT NULL, VariableName NVARCHAR(255), -- 温度/湿度/人数 PointIndex INT DEFAULT 0, -- MC4 pointIndex Unit NVARCHAR(50), -- ℃/%/人 SortOrder INT DEFAULT 0 ); ``` - [ ] 在 Vol.Pro 代码生成器选择 `warehouse_variable`,生成全套 CRUD 代码 - [ ] 管理端字典 "变量列表" 绑定到 `warehouse_variable.VariableName` - [ ] 规则条件/动作的 `ValueId` 下拉框改为从 `warehouse_variable` 查询(JOIN `base_device.DeviceId`) > **F2 提交点**: `Fix-P1: B4-batch+批量离线+凭据安全+前端地址+DeviceId映射+变量表` --- ## 阶段 F3: P2 改善项修复(预计 2h) #### F3.1 [P2-1] 适配器异常日志 - [ ] 编辑 `gateway/src/IntegrationGateway.Adapters.Owl/OwlAdapter.cs` - [ ] 编辑 `gateway/src/IntegrationGateway.Adapters.MC4/Mc4Adapter.cs` - [ ] 编辑 `gateway/src/IntegrationGateway.Adapters.Kms/KmsAdapter.cs` - [ ] 所有 `catch { return false; }` → `catch (Exception ex) { Console.Error.WriteLine($"[{AdapterCode}] HealthCheck: {ex.Message}"); return false; }` - [ ] `dotnet build` → 0 错误 #### F3.2 [P2-2] 规则引擎滞后窗 - [ ] 在 `warehouse_rulecondition` 表新增字段: ```sql ALTER TABLE warehouse_rulecondition ADD RecoveryThreshold_Numeric DECIMAL(18,2) NULL, -- 恢复阈值(下界) RecoveryThreshold_Switch NVARCHAR(50) NULL; -- 恢复开关状态 ``` - [ ] `RuleEngineService.EvaluateCondition` 中加逻辑: ```csharp bool wasTriggered = cond.LastTriggered.HasValue; if (wasTriggered) return Compare(actualValue, "大于等于", cond.RecoveryThreshold_Numeric); else return Compare(actualValue, cond.CompareOperator, cond.TargetValue_Number); ``` #### F3.3 [P2-3] 条件级冷却 - [ ] `warehouse_rulecondition` 表新增 `LastTriggered DATETIME NULL`、`LastTriggerValue DECIMAL(18,2) NULL` - [ ] `RuleEngineService.EvaluateCondition` 中: - 如果 `DateTime.Now - cond.LastTriggered < rule.CooldownSec` → 跳过此条件 - 触发时更新 `LastTriggered` 和 `LastTriggerValue` #### F3.4 [P2-4] 生产环境移除 console.log - [ ] 编辑 `warehouse/vite.config.ts` ```typescript build: { terserOptions: { compress: { drop_console: true } } } ``` - [ ] 开发环境保留 `console.log`(仅 build 时移除) - [ ] `npm run build` → 确认无 console.log 残留 #### F3.5 [P2-5] 统一 gateway API 封装 - [ ] 复制 `warehouse/src/api/gateway.ts` → `web.vite/src/api/gateway.js` - 修改 `GW_BASE` 为 `window.apiConfig.gatewayUrl || 'http://localhost:5100'` - [ ] `web.vite/src/views/warehouse/device_manager/base_device.vue` - 删除内联 `const GW =` + `fetch()` → 改为 `import { gwGet, gwPost } from '@/api/gateway.js'` - 所有 `fetch(\`\${GW}/api/gateway/...\`)` → `gwGet(...)` / `gwPost(...)` > **F3 提交点**: `Fix-P2: 异常日志+滞后窗+条件冷却+console清理+API统一` --- ## 阶段 F4: P3 优化项(预计 1h) #### F4.1 [P3-1] 规则引擎并发动作执行 - [ ] 在规则引擎实现方案的 `ExecuteActionsAsync` 中: ```csharp var tasks = actions.Select(a => ExecuteSingleActionAsync(a, rule)); await Task.WhenAll(tasks); async Task ExecuteSingleActionAsync(Action a, Rule r) { using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); try { await DoAction(a, r, cts.Token); } catch (OperationCanceledException) { Log($"[RuleEngine] 动作超时: {a.id}"); } } ``` #### F4.2 [P3-2] 清理 bin/obj + .gitignore - [ ] `.gitignore` 追加规则(如未在 F2.3 中完成): ``` **/bin/ **/obj/ gateway/src/IntegrationGateway.Host/bin/ api_sqlsugar/**/bin/ ``` - [ ] `git rm -r --cached` 所有 bin/obj 目录 #### F4.3 [P3-3] 网关 Swagger - [ ] 编辑 `gateway/src/IntegrationGateway.Host/Program.cs`: ```csharp builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); // ... app.UseSwagger(); app.UseSwaggerUI(); ``` - [ ] 浏览器访问 `http://localhost:5100/swagger` 验证 #### F4.4 [P3-4] 同步设计文档路由数 - [ ] 编辑 `doc/设计文档/对接网关设计文档.md` → 路由表从 14 条更新为当前实际数 - [ ] 确认以下设计文档一致: 对接网关设计文档、规则引擎方案、KMS 设计文档 > **F4 提交点**: `Fix-P3: 并发动作+清理bin+Swagger+文档同步` --- ## 任务总览 | 编号 | 问题 | 涉及文件 | 预计 | |:---:|------|------|:---:| | P0-1 | RealtimePollJob 空壳 | RealtimePollJob.cs | 1h | | P0-2 | A1 自注册 | Program.cs | 30min | | P0-3 | B 组认证 | Program.cs + appsettings | 30min | | P1-1 | B4-batch | Program.cs | 30min | | P1-2 | 批量离线 | HeartbeatMonitorJob.cs | 20min | | P1-3 | 凭据安全 | appsettings + .gitignore + bin | 20min | | P1-4 | 前端地址 | base_device.vue + gateway.ts | 20min | | P1-5 | DeviceId 映射 | RuleEngineService | 30min | | P1-6 | 变量表 | SQL + 代码生成 + 前端 | 1h | | P2-1 | 异常日志 | OwlAdapter + MC4Adapter + KmsAdapter | 20min | | P2-2 | 滞后窗 | SQL + RuleEngineService | 30min | | P2-3 | 条件冷却 | SQL + RuleEngineService | 20min | | P2-4 | console 清理 | vite.config.ts | 10min | | P2-5 | API 统一 | gateway.js + base_device.vue | 30min | | P3-1 | 并发动作 | RuleEngineService | 15min | | P3-2 | bin 清理 | .gitignore + git rm | 5min | | P3-3 | Swagger | Program.cs | 10min | | P3-4 | 文档同步 | 设计文档 | 15min | > **总计**: 18 项 / 25 文件 / ~9h