# SecMPS 整合方案(最终版):IntegrationGateway + 统一设备管理 > **版本**: v2.0 > **日期**: 2026-05-16 > **状态**: 待实施 --- ## 一、总体架构 ``` 前端层 web.vite 管理端(设备管理+网关管理) warehouse 大屏(Map/Live/IoT/Alarm) | HTTP REST | HTTP REST + SignalR v v Vol.Pro 后端 (api_sqlsugar) DeviceManagerController / GatewayNodeController / SignalR Hubs Quartz: SyncDevicesJob / RealtimePollJob / AlarmPollJob 数据库: 6 张表 (base_device / video_channel / video_record / iot_devicedata / iot_alarm / gateway_nodes) | 注册/下发设备/心跳/同步数据 v IntegrationGateway 实例A (:5100) IntegrationGateway 实例B (:5101) NodeCode: gw-31ku NodeCode: gw-11ku Adapters: MC4 / Owl Adapters: MC4 / HikvisionISC | HTTP | HTTP v v MC4.0 (:3000) Owl (:80) MC4.0 (:3000) 海康ISC (:80) ``` ### 核心设计原则 - **网关无状态**:配置仅 NodeCode/Token/VolProUrl,挂了重装即恢复 - **AdapterCode 双段标识**:"mc4:31号库房" 区分同类型多实例 - **DeviceGroup 路由**:基类表用字典字段决定适配器和行为,不依赖扩展表 - **ExtraData JSON**:所有适配器特有字段存入 ExtraData,新增适配器不增表 - **心跳机制**:网关 15s 心跳,Vol.Pro 超 30s 级联设备离线 --- ## 二、网关架构(方案 C+) ### 2.1 网关注册与心跳流程 ``` 管理端: gateway_nodes 表新增 → 生成 NodeCode + Token 网关配置: { NodeCode, Token, VolProUrl } 网关启动 → POST /register { nodeCode,token,adapterTypes,baseUrl } Vol.Pro 校验 → 更新 AdapterTypes/BaseUrl/IsOnline=在线 响应: { gatewayNodeId, devices: [base_device WHERE GatewayNodeId=当前] } 网关按 AdapterCode 分流 → Adapter 连接第三方 → 发现子设备 网关 → POST /sync → Vol.Pro 写入 base_device(含 ExtraData) 网关每 15s → POST /heartbeat { nodeCode, token } Vol.Pro Job: IsOnline=在线 且 LastHeartbeat < now-30s → IsOnline=离线 → 级联设备离线 ``` ### 2.2 网关配置 ```json { "VolProBaseUrl": "http://localhost:9100", "NodeCode": "gw-31ku", "NodeToken": "xxxxxxxxxx" } ``` ### 2.3 适配器能力矩阵 | 接口 | Owl | MC4.0 | 门禁(未来) | |------|:---:|:-----:|:----------:| | IHasOwnDeviceTree | ❌ | ✅ | ❌ | | IHasFlatDevices | ✅ | ❌ | ✅ | | IHasPoints | ❌ | ✅ | ❌ | | IHasStreams | ✅ | ❌ | ❌ | | IHasAlarms | ⚠️ | ✅ | ✅ | | IAcceptsMetadataPush | ✅ | ❌ | ⚠️ | ### 2.4 双向同步引擎 | 方向 | 说明 | MC4.0 | Owl | |------|------|-------|-----| | PullToVolPro | 第三方→Vol.Pro | FullReplace | Merge | | PushToSource | Vol.Pro→第三方 | 告警确认/控制 | 元数据/PTZ | | Bidirectional | 先写第三方再更新本地 | 告警确认 | — | ### 2.5 Gateway API ``` # 注册与心跳 POST /api/gateway/register { nodeCode, token, adapterTypes, baseUrl } POST /api/gateway/heartbeat { nodeCode, token } # 设备与数据 GET /api/gateway/devices?adapter=&page=&size= GET /api/gateway/devices/sync?adapter= GET /api/gateway/realtime/{adapter}/{deviceId} POST /api/gateway/realtime/{adapter}/control GET /api/gateway/streams/{adapter}/{id}/live POST /api/gateway/streams/{adapter}/{id}/ptz GET /api/gateway/alarms/{adapter}?from=&to= POST /api/gateway/alarms/{adapter}/{id}/confirm GET /api/gateway/health ``` --- ## 三、数据模型(6 张表) ### 3.1 区域表 warehouse_regions(现有) | 字段 | 说明 | |------|------| | Id | int PK | | RegionName | nvarchar(255) | | ParentId | int? (自引用树) | ### 3.2 网关节点表 gateway_nodes | 字段 | 类型 | 说明 | |------|------|------| | NodeId | INT AUTO_INCREMENT | 网关节点ID | | NodeCode | NVARCHAR(50) | 网关唯一编码(管理端配置) | | NodeName | NVARCHAR(100) | 网关名称 | | NodeToken | NVARCHAR(100) | 认证令牌(管理端生成) | | AdapterTypes | NVARCHAR(200) | 适配器类型(网关上报) | | BaseUrl | NVARCHAR(200) | 网关地址(网关上报) | | LastHeartbeat | DATETIME | 上次心跳时间 | | IsOnline | NVARCHAR(20) | 在线状态(字典: 在线/离线) | | Enable | NVARCHAR(20) | 启用状态(字典: 启用/禁用) | ### 3.3 统一设备主表 base_device | 字段 | 类型 | 说明 | |------|------|------| | DeviceId | INT AUTO_INCREMENT | Vol.Pro内部ID | | DeviceName | NVARCHAR(100) | 设备名称 | | AdapterCode | NVARCHAR(50) | "mc4:31号库房"(类型:实例) | | SourceId | NVARCHAR(100) | 源系统设备ID | | **DeviceCategory** | NVARCHAR(50) | 设备种类(字典: 摄像机/温湿度变送器/...) | | **DeviceGroup** | NVARCHAR(20) | 设备分组(字典: 视频设备/IoT设备/门禁设备/道闸设备/报警设备) | | RegionId | INT? | 所属区域ID | | GatewayNodeId | INT? | 所属网关节点ID | | IsParent | NVARCHAR(20) | 是否父设备(字典: 是/否) | | ParentDeviceId | INT? | 父设备自引用 | | IsOnline | NVARCHAR(20) | 在线状态(字典: 在线/离线) | | MapModelId | NVARCHAR(100) | VgoMap模型ID | | MapModelScale | FLOAT | | | MapModelRotation | NVARCHAR(100) | | | **ExtraData** | TEXT | ★ 适配器扩展JSON(Owl/MC4/门禁字段均存于此) | | LocalOverrides | TEXT | 本地覆盖JSON | | SyncVersion | BIGINT | 乐观锁 | | LastSyncTime | DATETIME | | | Enable | NVARCHAR(20) | 启用状态(字典: 启用/禁用) | 唯一约束: (AdapterCode, SourceId) ### 3.4 DeviceGroup 分组规则 Vol.Pro 同步接口通过 DeviceGroup 路由,无需硬编码: | DeviceGroup | 网关适配器 | 前端按钮组 | 同步模式 | |:---:|------|------|:---:| | 视频设备 | OwlAdapter → IHasStreams | 实时预览/云台/回放/快照 | Merge | | IoT设备 | Mc4Adapter → IHasPoints | 实时数据/控制/告警 | FullReplace | | 门禁设备 | AccessAdapter | 远程开门/记录/告警 | Merge | | 道闸设备 | BarrierAdapter | 抬杆/落杆/记录 | Merge | | 报警设备 | AlarmAdapter | 查看告警/布防撤防 | Merge | ### 3.5 ExtraData 格式示例 ```json // 摄像机 (Owl) { "owlDeviceId": "gb_xxx", "protocol": "GB28181", "manufacturer": "海康" } // 温湿度变送器 (MC4子设备) { "mc4DeviceId": 1001, "pointIndex": 0, "unit": "℃", "isControlPoint": false } // 空调控制器 (MC4子设备) { "mc4DeviceId": 1002, "pointIndex": 2, "unit": null, "isControlPoint": true } // 未来门禁 { "hikDeviceId": "door_01", "doorType": "单门", "readerType": "IC卡" } ``` ### 3.6 层级示例 ``` gateway_nodes: gw-31ku warehouse_regions: 厂区 → 新库区 → 31号库房 base_device (RegionId=3, GatewayNodeId=gw-31ku.NodeId): 东北角高位摄像机 (DeviceGroup=视频设备, ExtraData={owlDeviceId,...}) 人员计数摄像机 (DeviceGroup=视频设备) 动环采集器 (DeviceGroup=IoT设备, IsParent=是) ├── 温湿度变送器 (ParentDeviceId=采集器, ExtraData={pointIndex:0,unit:"℃"}) ├── 空调控制器 (ParentDeviceId=采集器, ExtraData={pointIndex:2,isControlPoint:true}) ├── 除湿/恒湿机 (ParentDeviceId=采集器) └── 紧急报警按钮 (ParentDeviceId=采集器, DeviceGroup=报警设备) ``` --- ## 四、Vol.Pro 同步接口(新增适配器零改动) ```csharp // POST /api/gateway/sync public async Task SyncDevices(string nodeCode, List devices) { var node = await _db.gateway_nodes.FirstAsync(n => n.NodeCode == nodeCode); foreach (var d in devices) { var entity = await _db.base_device .FirstOrDefaultAsync(x => x.AdapterCode == d.AdapterCode && x.SourceId == d.SourceId) ?? new base_device(); entity.DeviceName = d.Name; entity.DeviceGroup = d.Group; // 字典: 视频设备/IoT设备/... entity.DeviceCategory = d.Category; // 字典: 摄像机/温湿度变送器/... entity.IsOnline = d.IsOnline ? "在线" : "离线"; entity.IsParent = d.IsParent ? "是" : "否"; entity.ParentDeviceId = d.ParentSourceId; // 网关同步过来的父级关系 entity.GatewayNodeId = node.NodeId; entity.ExtraData = d.ExtraDataJson; // ★ 一行,适配器字段全在这里 // ... 公共字段赋值 ... _db.base_device.Upsert(entity); } await _db.SaveChangesAsync(); } ``` --- ## 五、管理端统一设备页面 ### 5.1 操作按钮矩阵(按 DeviceGroup 路由) | DeviceGroup | 操作按钮 | |:---:|------| | 视频设备 | 实时预览 / 云台控制 / 查看回放 / 获取快照 / 同步通道 | | IoT设备 | 查看实时数据 / 设备控制 / 刷新点位 / 查看告警 | | 门禁设备 | 远程开门 / 查看记录 / 查看告警 | | 道闸设备 | 抬杆 / 落杆 / 查看记录 | | 报警设备 | 查看告警 / 布防撤防 | ### 5.2 前端按钮路由 ```javascript // DeviceTable.vue const actionMap = { '视频设备': VideoDeviceActions, 'IoT设备': IoTDeviceActions, '门禁设备': AccessDeviceActions, '道闸设备': BarrierDeviceActions, '报警设备': AlarmDeviceActions, } // 渲染: actionMap[device.DeviceGroup] ``` --- ## 六、同步策略 ### MC4.0 → 区域树+设备 - type=1 节点 → 名称匹配 warehouse_regions → 绑区或新建 - type=2 节点 → Upsert base_device, DeviceGroup=IoT设备, ExtraData 存点位属性 - 模式: FullReplace, 频率限制: 2次/秒 ### Owl → 设备 - GET /devices → Upsert base_device (DeviceGroup=视频设备, IsParent=是) - GET /channels → Upsert base_device (ParentDeviceId=NVR) + video_channel - Owl 无区域概念 → RegionId=NULL, 管理员手动分配 - 模式: Merge ### 反方向写回 | 操作 | Owl | MC4.0 | |------|:---:|:-----:| | 设备改名 | ✅ PUT /devices/:id | ❌ | | 告警确认 | ⚠️ | ✅ | | 设备控制 | ✅ PTZ | ✅ 点位写值 | --- ## 七、部署拓扑 ``` Docker: Owl+ZLM (:80) MC4.0-1 (:3000) MC4.0-2 (:3000) | | | +----------+-----------+-------------------+ | +----------+-----------+ | Gateway gw-31ku | Gateway gw-11ku | :5100 | :5101 +----------+-----------+ | +----------+-----------+ | VolPro.WebApi | | :9100 | | MySQL / Redis | +----------+-----------+ | +--------------+---------------+ | web.vite :9000 warehouse :9200 | +--------------------------------+ ``` --- ## 八、实施路线 | 阶段 | 工期 | 内容 | |------|------|------| | Phase 0 | Day 1-2 | Gateway骨架 + 6张表建表 + 代码生成 | | Phase 1 | Day 3-6 | OwlAdapter + 管理端视频设备页 | | Phase 2 | Day 7-11 | Mc4Adapter + IoT管理 + 区域树匹配 + SignalR | | Phase 3 | Day 12-17 | warehouse端改造 + 全链路联调 | | Phase 4 | Day 18-20 | 验证 + 缓冲 | 总计: 18-20 个工作日 --- ## 九、新增整合流程 以接入「海康门禁」为例: 1. 新建 IntegrationGateway.Adapters.HikvisionAccess 项目 2. 实现 IHasFlatDevices + IHasAlarms → 设备同步时填充 DeviceGroup=门禁设备 3. 管理端字典加一条"门禁设备"分组 → 按钮自动出现 4. Vol.Pro 同步接口零改动(ExtraData 承载门禁字段) 5. 前端新增 AccessDeviceActions.vue (~80行) 总工作量: 1-2 天 --- ## 十、代码组织规范 | 代码类型 | 路径 | 被覆盖? | |----------|------|:---:| | 第三方对接 | gateway/ | ❌ | | 扩展Controller | Controllers/*/Partial/ | ❌ | | Entity扩展 | DomainModels/*/partial/ | ❌ | | 前端业务逻辑 | extension/warehouse/*.jsx | ❌ | | 自定义页面 | views/warehouse/DeviceManager/ | ❌ | | 自动生成代码 | 生成器默认路径 | ✅ | --- > 取代: V1.0 系列所有整合方案文档