diff --git a/doc/db_init.sql b/doc/db_init.sql index cd18864..29a3c3e 100644 --- a/doc/db_init.sql +++ b/doc/db_init.sql @@ -1,27 +1,29 @@ -- ============================================ --- SecMPS v2.0 数据库建表脚本(8张表) +-- SecMPS v2.0 数据库建表脚本(6张表) -- 数据库: gljs_main --- 点位=子设备, 通过 base_device.ParentDeviceId 级联 +-- 扩展表已合并到 Base_Device.ExtraData(JSON) -- ============================================ USE gljs_main; -- ============================================ -- 1. 统一设备主表 --- 采集器/摄像机=父设备(IsParent=1) 探头/通道=子设备(ParentDeviceId) +-- ExtraData(JSON) 承载所有适配器特有字段 +-- DeviceGroup 路由到正确的网关Adapter和前端按钮组 -- ============================================ DROP TABLE IF EXISTS base_device; CREATE TABLE base_device ( DeviceId INT AUTO_INCREMENT COMMENT '设备ID', DeviceName NVARCHAR(100) NOT NULL COMMENT '设备名称', - AdapterCode NVARCHAR(50) NOT NULL COMMENT '来源适配器', + AdapterCode NVARCHAR(50) NOT NULL COMMENT '来源适配器(类型:实例)', SourceId NVARCHAR(100) NOT NULL COMMENT '源系统设备ID', DeviceCategory NVARCHAR(50) NOT NULL COMMENT '设备种类(数据字典:门磁/空调/智能断路器/人行道闸/车辆道闸/485钥匙柜/网络钥匙柜/紧急报警按钮/红外报警器/门禁一体机/除湿_恒湿机/空调控制器/烟雾报警器/气体报警器/温湿度变送器/摄像机/硬盘录像机/动环采集器)', + DeviceGroup NVARCHAR(20) NOT NULL COMMENT '设备分组(数据字典:视频设备/IoT设备/门禁设备/道闸设备/报警设备)', RegionId INT NULL COMMENT '所属区域ID', GatewayNodeId INT NULL COMMENT '所属网关节点ID', - IsParent NVARCHAR(20) NOT NULL DEFAULT '0' COMMENT '是否父设备(数据字典:是/否)', + IsParent NVARCHAR(20) NOT NULL DEFAULT '否' COMMENT '是否父设备(数据字典:是/否)', ParentDeviceId INT NULL COMMENT '父设备ID(自引用,子设备挂父设备下)', - IsOnline NVARCHAR(20) NOT NULL DEFAULT '0' COMMENT '在线状态(数据字典:在线/离线)', + IsOnline NVARCHAR(20) NOT NULL DEFAULT '离线' COMMENT '在线状态(数据字典:在线/离线)', IpAddress NVARCHAR(50) COMMENT 'IP地址', Port INT COMMENT '端口', Location NVARCHAR(200) COMMENT '安装位置', @@ -30,11 +32,11 @@ CREATE TABLE base_device ( MapModelId NVARCHAR(100) COMMENT '三维地图模型ID', MapModelScale FLOAT DEFAULT 1.0 COMMENT '模型缩放比例', MapModelRotation NVARCHAR(100) COMMENT '模型旋转角度(JSON)', - ExtraData TEXT COMMENT '源系统原始数据JSON', + ExtraData TEXT COMMENT '适配器扩展数据JSON(Owl/MC4/门禁字段均存于此)', LocalOverrides TEXT COMMENT '本地覆盖字段JSON', SyncVersion BIGINT DEFAULT 0 COMMENT '同步版本号', LastSyncTime DATETIME COMMENT '上次同步时间', - Enable NVARCHAR(20) DEFAULT '1' COMMENT '启用状态(数据字典:启用/禁用)', + Enable NVARCHAR(20) DEFAULT '启用' COMMENT '启用状态(数据字典:启用/禁用)', Remark NVARCHAR(500) COMMENT '备注', CreateID INT COMMENT '创建人ID', Creator NVARCHAR(50) COMMENT '创建人', @@ -46,40 +48,19 @@ CREATE TABLE base_device ( INDEX IX_Sync (AdapterCode, SourceId), INDEX IX_Region (RegionId), INDEX IX_Parent (ParentDeviceId), - INDEX IX_Category (DeviceCategory), - INDEX IX_Gateway (GatewayNodeId) + INDEX IX_Gateway (GatewayNodeId), + INDEX IX_Group (DeviceGroup) ) COMMENT '统一设备主表'; -- ============================================ --- 2. 视频设备扩展表 +-- 2. 视频通道表 -- DeviceId(INT) → base_device.DeviceId -- ============================================ -DROP TABLE IF EXISTS device_video_ext; -CREATE TABLE device_video_ext ( - ExtId INT AUTO_INCREMENT COMMENT '扩展记录ID', - DeviceId INT NOT NULL COMMENT '关联设备ID', - OwlDeviceId NVARCHAR(64) NOT NULL COMMENT 'Owl系统设备ID', - Protocol INT DEFAULT 1 COMMENT '接入协议', - Manufacturer NVARCHAR(100) COMMENT '厂商', - Model NVARCHAR(100) COMMENT '设备型号', - ChannelCount INT DEFAULT 0 COMMENT '通道数量', - OwlStatus NVARCHAR(500) COMMENT 'Owl原始状态JSON', - CreateDate DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - PRIMARY KEY (ExtId), - INDEX IX_Device (DeviceId), - INDEX IX_Owl (OwlDeviceId) -) COMMENT '视频设备扩展表'; - --- ============================================ --- 3. 视频通道扩展表 --- 存Owl通道的流地址/云台/录像能力等扩展信息 --- DeviceId(INT) → base_device.DeviceId(一台NVR可有多条通道记录,对应不同码流) --- ============================================ DROP TABLE IF EXISTS video_channel; CREATE TABLE video_channel ( ChannelId INT AUTO_INCREMENT COMMENT '通道记录ID', OwlChannelId NVARCHAR(64) NOT NULL COMMENT 'Owl系统通道ID', - DeviceId INT NOT NULL COMMENT '关联base_device设备ID', + DeviceId INT NOT NULL COMMENT '关联Base_Device设备ID', OwlStreamApp NVARCHAR(50) COMMENT 'Owl流应用名', OwlStreamName NVARCHAR(100) COMMENT 'Owl流名称', HasPtz TINYINT DEFAULT 0 COMMENT '是否支持云台', @@ -90,10 +71,10 @@ CREATE TABLE video_channel ( PRIMARY KEY (ChannelId), INDEX IX_Device (DeviceId), INDEX IX_Owl (OwlChannelId) -) COMMENT '视频通道扩展表'; +) COMMENT '视频通道表'; -- ============================================ --- 4. 录像记录表 +-- 3. 录像记录表 -- ChannelId(INT) → video_channel.ChannelId -- ============================================ DROP TABLE IF EXISTS video_record; @@ -115,32 +96,8 @@ CREATE TABLE video_record ( ) COMMENT '录像记录表'; -- ============================================ --- 5. IoT设备扩展表(含点位属性) +-- 4. 设备数据归档表 -- DeviceId(INT) → base_device.DeviceId --- 子设备(点位)的额外属性: PointIndex/Unit/IsControlPoint --- ============================================ -DROP TABLE IF EXISTS device_iot_ext; -CREATE TABLE device_iot_ext ( - ExtId INT AUTO_INCREMENT COMMENT '扩展记录ID', - DeviceId INT NOT NULL COMMENT '关联设备ID', - Mc4DeviceId INT NOT NULL COMMENT 'MC4.0设备ID', - PointIndex INT DEFAULT 0 COMMENT '点位索引(子设备用)', - PointTag NVARCHAR(100) COMMENT '点位标签', - Unit NVARCHAR(50) COMMENT '单位(数据字典:℃/%%/V/A/kW)', - IsControlPoint NVARCHAR(20) DEFAULT '0' COMMENT '是否控制点(数据字典:只读/可写)', - ObjectType INT COMMENT 'MC4.0对象类型', - Tag NVARCHAR(100) COMMENT '设备标签', - ParentId INT COMMENT 'MC4.0父级ID', - Mc4Option NVARCHAR(500) COMMENT 'MC4.0原始配置JSON', - CreateDate DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - PRIMARY KEY (ExtId), - INDEX IX_Device (DeviceId), - INDEX IX_Mc4 (Mc4DeviceId) -) COMMENT '采集设备扩展表'; - --- ============================================ --- 6. 设备数据归档表 --- DeviceId(INT) → base_device.DeviceId(直接指向子设备/点位) -- ============================================ DROP TABLE IF EXISTS iot_devicedata; CREATE TABLE iot_devicedata ( @@ -157,7 +114,7 @@ CREATE TABLE iot_devicedata ( ) COMMENT '设备数据归档表'; -- ============================================ --- 7. 告警记录表(通用) +-- 5. 告警记录表(通用) -- DeviceId(INT) → base_device.DeviceId -- ============================================ DROP TABLE IF EXISTS iot_alarm; @@ -166,14 +123,14 @@ CREATE TABLE iot_alarm ( SourceAlarmId NVARCHAR(100) NOT NULL COMMENT '源系统告警ID', DeviceId INT NOT NULL COMMENT '关联设备ID', AlarmType INT DEFAULT 0 COMMENT '告警类型', - AlarmLevel NVARCHAR(20) DEFAULT '1' COMMENT '告警等级(数据字典:提示/普通/重要/紧急)', + AlarmLevel NVARCHAR(20) DEFAULT '提示' COMMENT '告警等级(数据字典:提示/普通/重要/紧急)', AlarmDesc NVARCHAR(500) COMMENT '告警描述', AlarmValue DOUBLE COMMENT '触发值', StartTime DATETIME NOT NULL COMMENT '告警开始时间', EndTime DATETIME COMMENT '告警结束时间', ConfirmTime DATETIME COMMENT '确认时间', ConfirmUser NVARCHAR(50) COMMENT '确认人', - State NVARCHAR(20) DEFAULT '1' COMMENT '状态(数据字典:未确认/已确认/已结束)', + State NVARCHAR(20) DEFAULT '未确认' COMMENT '状态(数据字典:未确认/已确认/已结束)', AdapterCode NVARCHAR(50) COMMENT '来源适配器', CreateDate DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (AlarmId), @@ -183,10 +140,8 @@ CREATE TABLE iot_alarm ( INDEX IX_Level (AlarmLevel) ) COMMENT '告警记录表'; - -- ============================================ --- 8. 网关节点注册表 --- NodeCode=网关唯一编码 AdapterTypes=网关上报 +-- 6. 网关节点注册表 -- ============================================ DROP TABLE IF EXISTS gateway_nodes; CREATE TABLE gateway_nodes ( @@ -197,8 +152,8 @@ CREATE TABLE gateway_nodes ( AdapterTypes NVARCHAR(200) COMMENT '支持的适配器类型(网关上报)', BaseUrl NVARCHAR(200) COMMENT '网关自身地址(网关上报)', LastHeartbeat DATETIME COMMENT '上次心跳时间', - IsOnline NVARCHAR(20) DEFAULT '0' COMMENT '在线状态(数据字典:在线/离线)', - Enable NVARCHAR(20) DEFAULT '1' COMMENT '启用状态(数据字典:启用/禁用)', + IsOnline NVARCHAR(20) DEFAULT '离线' COMMENT '在线状态(数据字典:在线/离线)', + Enable NVARCHAR(20) DEFAULT '启用' COMMENT '启用状态(数据字典:启用/禁用)', Remark NVARCHAR(500) COMMENT '备注', CreateID INT COMMENT '创建人ID', Creator NVARCHAR(50) COMMENT '创建人', diff --git a/doc/整合方案/SecMPS_最终整合方案_v2.0.md b/doc/整合方案/SecMPS_最终整合方案_v2.0.md index 292e0d9..aa449c9 100644 --- a/doc/整合方案/SecMPS_最终整合方案_v2.0.md +++ b/doc/整合方案/SecMPS_最终整合方案_v2.0.md @@ -3,7 +3,6 @@ > **版本**: v2.0 > **日期**: 2026-05-16 > **状态**: 待实施 -> **替代**: v1.0 系列方案文档 --- @@ -12,12 +11,12 @@ ``` 前端层 web.vite 管理端(设备管理+网关管理) warehouse 大屏(Map/Live/IoT/Alarm) - | HTTP REST | HTTP REST + SignalR + | HTTP REST | HTTP REST + SignalR v v Vol.Pro 后端 (api_sqlsugar) DeviceManagerController / GatewayNodeController / SignalR Hubs Quartz: SyncDevicesJob / RealtimePollJob / AlarmPollJob - 数据库: 8 张表 (base_device / gateway_nodes / 扩展表...) + 数据库: 6 张表 (base_device / video_channel / video_record / iot_devicedata / iot_alarm / gateway_nodes) | 注册/下发设备/心跳/同步数据 v IntegrationGateway 实例A (:5100) IntegrationGateway 实例B (:5101) @@ -28,59 +27,33 @@ IntegrationGateway 实例A (:5100) IntegrationGateway 实例B (:5101) MC4.0 (:3000) Owl (:80) MC4.0 (:3000) 海康ISC (:80) ``` -### 网关多实例架构(方案 C+) +### 核心设计原则 -- Vol.Pro 管理网关实例:gateway_nodes 表注册所有网关节点 -- 网关启动时主动注册:POST /api/gateway/register 上报 NodeCode/Token/AdapterTypes/BaseUrl -- Vol.Pro 下发顶层设备:Base_Device.GatewayNodeId 关联设备归属 -- 网关无状态:配置只有 3 个值(NodeCode/Token/VolProUrl),挂了重装即恢复 -- AdapterCode 双段标识:"mc4:31号库房" 区分同类型多实例 -- 心跳机制:网关每 15s 上报心跳,Vol.Pro 超 30s 无心跳级联设备离线 +- **网关无状态**:配置仅 NodeCode/Token/VolProUrl,挂了重装即恢复 +- **AdapterCode 双段标识**:"mc4:31号库房" 区分同类型多实例 +- **DeviceGroup 路由**:基类表用字典字段决定适配器和行为,不依赖扩展表 +- **ExtraData JSON**:所有适配器特有字段存入 ExtraData,新增适配器不增表 +- **心跳机制**:网关 15s 心跳,Vol.Pro 超 30s 级联设备离线 --- -## 二、IntegrationGateway 设计 +## 二、网关架构(方案 C+) -### 2.1 项目结构(位于 gateway/ 独立文件夹) +### 2.1 网关注册与心跳流程 ``` -gateway/ -├── IntegrationGateway.sln -└── src/ - ├── IntegrationGateway.Host/ # WebAPI (:5100) - | ├── Controllers/ - | | ├── HealthController.cs - | | ├── DevicesController.cs - | | ├── PointsController.cs - | | ├── StreamsController.cs - | | ├── AlarmsController.cs - | | ├── SyncController.cs - | | └── RegisterController.cs # 网关注册/心跳 - | ├── appsettings.json # { NodeCode, Token, VolProUrl } - | └── Program.cs - ├── IntegrationGateway.Core/ - | ├── Abstractions/ → 7 个分型接口 - | ├── Models/ → 10 个标准化模型 - | └── Infrastructure/ → AdapterRegistry / TokenManager / RateLimiter - ├── IntegrationGateway.Adapters.Owl/ - └── IntegrationGateway.Adapters.MC4/ +管理端: 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 网关注册与心跳流程 - -``` -管理端: gateway_nodes 表新增记录 → 生成 NodeCode + Token -网关配置: appsettings.json { NodeCode, Token, VolProUrl } -网关启动 → POST /api/gateway/register { nodeCode,token,adapterTypes,baseUrl } -Vol.Pro 校验 Token → 更新 AdapterTypes/BaseUrl/IsOnline=1 -响应: { gatewayNodeId, devices: [Base_Device WHERE GatewayNodeId=当前网关] } -网关根据 AdapterCode 分流 → Adapter 连接第三方 → 发现子设备 -网关 → POST /api/gateway/sync → Vol.Pro 写入 Base_Device 及子设备 -网关每 15s → POST /api/gateway/heartbeat { nodeCode, token } -Vol.Pro 后台任务: IsOnline=1 且 LastHeartbeat < now-30s → IsOnline=0 → 级联设备离线 -``` - -### 2.3 网关配置 +### 2.2 网关配置 ```json { @@ -90,9 +63,7 @@ Vol.Pro 后台任务: IsOnline=1 且 LastHeartbeat < now-30s → IsOnline=0 → } ``` -适配器类型由网关启动时扫描已注册的 Adapter 类自动获取,无需在配置中声明。 - -### 2.4 适配器能力矩阵 +### 2.3 适配器能力矩阵 | 接口 | Owl | MC4.0 | 门禁(未来) | |------|:---:|:-----:|:----------:| @@ -103,7 +74,7 @@ Vol.Pro 后台任务: IsOnline=1 且 LastHeartbeat < now-30s → IsOnline=0 → | IHasAlarms | ⚠️ | ✅ | ✅ | | IAcceptsMetadataPush | ✅ | ❌ | ⚠️ | -### 2.5 双向同步引擎 +### 2.4 双向同步引擎 | 方向 | 说明 | MC4.0 | Owl | |------|------|-------|-----| @@ -111,7 +82,7 @@ Vol.Pro 后台任务: IsOnline=1 且 LastHeartbeat < now-30s → IsOnline=0 → | PushToSource | Vol.Pro→第三方 | 告警确认/控制 | 元数据/PTZ | | Bidirectional | 先写第三方再更新本地 | 告警确认 | — | -### 2.6 Gateway API +### 2.5 Gateway API ``` # 注册与心跳 @@ -132,7 +103,7 @@ GET /api/gateway/health --- -## 三、数据模型(8 张表) +## 三、数据模型(6 张表) ### 3.1 区域表 warehouse_regions(现有) @@ -142,7 +113,7 @@ GET /api/gateway/health | RegionName | nvarchar(255) | | ParentId | int? (自引用树) | -### 3.2 网关节点表 gateway_nodes(新建) +### 3.2 网关节点表 gateway_nodes | 字段 | 类型 | 说明 | |------|------|------| @@ -153,126 +124,151 @@ GET /api/gateway/health | AdapterTypes | NVARCHAR(200) | 适配器类型(网关上报) | | BaseUrl | NVARCHAR(200) | 网关地址(网关上报) | | LastHeartbeat | DATETIME | 上次心跳时间 | -| IsOnline | TINYINT DEFAULT 0 | 在线状态 | -| Enable | TINYINT DEFAULT 1 | 启用 | +| IsOnline | NVARCHAR(20) | 在线状态(字典: 在线/离线) | +| Enable | NVARCHAR(20) | 启用状态(字典: 启用/禁用) | -### 3.3 统一设备主表 Base_Device +### 3.3 统一设备主表 base_device | 字段 | 类型 | 说明 | |------|------|------| | DeviceId | INT AUTO_INCREMENT | Vol.Pro内部ID | -| DeviceName | NVARCHAR(100) | 本地名称 | +| DeviceName | NVARCHAR(100) | 设备名称 | | AdapterCode | NVARCHAR(50) | "mc4:31号库房"(类型:实例) | -| SourceId | NVARCHAR(100) | 第三方原始ID | -| DeviceCategory | NVARCHAR(50) | Video/IoT/Access/Barrier/Alarm(字典) | +| SourceId | NVARCHAR(100) | 源系统设备ID | +| **DeviceCategory** | NVARCHAR(50) | 设备种类(字典: 摄像机/温湿度变送器/...) | +| **DeviceGroup** | NVARCHAR(20) | 设备分组(字典: 视频设备/IoT设备/门禁设备/道闸设备/报警设备) | | RegionId | INT? | 所属区域ID | | GatewayNodeId | INT? | 所属网关节点ID | -| IsParent | TINYINT | 是否父设备 | +| IsParent | NVARCHAR(20) | 是否父设备(字典: 是/否) | | ParentDeviceId | INT? | 父设备自引用 | -| IsOnline | TINYINT | 在线状态 | +| IsOnline | NVARCHAR(20) | 在线状态(字典: 在线/离线) | | MapModelId | NVARCHAR(100) | VgoMap模型ID | | MapModelScale | FLOAT | | | MapModelRotation | NVARCHAR(100) | | -| Lat/Lng | DOUBLE | WGS84 | -| ExtraData | TEXT | 适配器原始JSON | +| **ExtraData** | TEXT | ★ 适配器扩展JSON(Owl/MC4/门禁字段均存于此) | | LocalOverrides | TEXT | 本地覆盖JSON | | SyncVersion | BIGINT | 乐观锁 | | LastSyncTime | DATETIME | | +| Enable | NVARCHAR(20) | 启用状态(字典: 启用/禁用) | 唯一约束: (AdapterCode, SourceId) -### 3.4 扩展表 +### 3.4 DeviceGroup 分组规则 -- Device_Video_Ext: 视频设备扩展(OwlDeviceId, Protocol, ChannelCount) -- Video_Channel: 视频通道扩展(OwlChannelId, DeviceId, OwlStreamApp/Name, HasPtz, SnapshotUrl) -- Video_Record: 录像记录(ChannelId, OwlRecordId, StartedAt, FilePath) -- Device_IoT_Ext: IoT设备扩展(Mc4DeviceId, PointIndex, Unit, IsControlPoint, ObjectType) -- IoT_DeviceData: 历史归档(DeviceId→子设备, PointValue, 仅存快照) -- IoT_Alarm: 通用告警(SourceAlarmId, DeviceId, AlarmLevel, State) +Vol.Pro 同步接口通过 DeviceGroup 路由,无需硬编码: -### 3.5 层级示例 +| 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 (32号库房网关, MC4+Owl) +gateway_nodes: gw-31ku warehouse_regions: 厂区 → 新库区 → 31号库房 -Base_Device (RegionId=3, GatewayNodeId=gw-31ku.NodeId): - 东北角高位摄像机 (Category=1, Device_Video_Ext) - 人员计数摄像机 (Category=1, Device_Video_Ext) - 动环采集器 (Category=2, IsParent=1, Device_IoT_Ext) - ├── 温湿度探头 (ParentDeviceId=采集器, Device_IoT_Ext.PointIndex=0) - ├── 空调控制器 (ParentDeviceId=采集器, Device_IoT_Ext.IsControlPoint=1) - ├── 除湿机 (ParentDeviceId=采集器) - └── 紧急报警按钮 (ParentDeviceId=采集器) +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 同步接口(新增适配器零改动) -### 4.1 布局 +```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(); +} ``` -+------------------+---------------------------------------+ -| 顶部工具栏 | | -+------------------+---------------------------------------+ -| 左侧区域树 | 右侧设备列表 | -| | | -| 📁 厂区 | 区域:31号库房 最后同步:05-15 | -| 📁 新库区 | +---------------------------------+ | -| 📁 31号库房 ● | | ▸动环采集器 MC4.0 █在线 | | -| 📁 11号库房 | | 东北角摄像机 Owl █在线 | | -| | +---------------------------------+ | -| [+新建区域] | | -+------------------+---------------------------------------+ -``` - -### 4.2 前端文件 - -``` -web.vite/src/views/warehouse/DeviceManager/ -├── index.vue # 主页面 -├── components/ -│ ├── RegionTree.vue # el-tree 区域树 -│ ├── DeviceTable.vue # el-table 可展开行 -│ ├── DeviceEditDialog.vue # 编辑弹框 -│ ├── MapBindingPanel.vue # 地图绑定面板 -│ ├── VideoDeviceActions.vue # 视频按钮组 -│ └── IoTDeviceActions.vue # IoT按钮组 -└── api/deviceManager.js -``` - -### 4.3 后端 API - -| 接口 | 说明 | -|------|------| -| GET /api/DeviceManager/GetRegionTree | 区域树+设备数量 | -| GET /api/DeviceManager/GetDevicesByRegion | 区域设备列表(含子设备) | -| PUT /api/DeviceManager/{deviceId} | 更新设备(含地图绑定) | -| POST /api/DeviceManager/SyncFromGateway | 手动同步 | - -### 4.4 操作按钮矩阵 - -| Category | 按钮 | -|----------|------| -| 1-视频 | 实时预览/云台控制/查看回放/获取快照/同步通道 | -| 2-IoT | 查看实时数据/设备控制/刷新点位/查看告警 | -| 3-门禁 | 远程开门/查看记录/查看告警 | -| 4-道闸 | 抬杆/落杆/查看记录 | --- -## 五、同步策略 +## 五、管理端统一设备页面 + +### 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, RegionId=叶子区域, GatewayNodeId=当前网关 +- type=2 节点 → Upsert base_device, DeviceGroup=IoT设备, ExtraData 存点位属性 - 模式: FullReplace, 频率限制: 2次/秒 ### Owl → 设备 -- GET /devices → Upsert Base_Device (Category=1, IsParent=1) -- GET /channels → Upsert Base_Device (ParentDeviceId=NVR) +- GET /devices → Upsert base_device (DeviceGroup=视频设备, IsParent=是) +- GET /channels → Upsert base_device (ParentDeviceId=NVR) + video_channel - Owl 无区域概念 → RegionId=NULL, 管理员手动分配 - 模式: Merge @@ -286,7 +282,7 @@ web.vite/src/views/warehouse/DeviceManager/ --- -## 六、部署拓扑 +## 七、部署拓扑 ``` Docker: Owl+ZLM (:80) MC4.0-1 (:3000) MC4.0-2 (:3000) @@ -311,11 +307,11 @@ Docker: Owl+ZLM (:80) MC4.0-1 (:3000) MC4.0-2 (:3000) --- -## 七、实施路线 +## 八、实施路线 | 阶段 | 工期 | 内容 | |------|------|------| -| Phase 0 | Day 1-2 | Gateway骨架 + 8张表建表 + 代码生成 | +| 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端改造 + 全链路联调 | @@ -325,19 +321,19 @@ Docker: Owl+ZLM (:80) MC4.0-1 (:3000) MC4.0-2 (:3000) --- -## 八、新增整合流程 +## 九、新增整合流程 以接入「海康门禁」为例: 1. 新建 IntegrationGateway.Adapters.HikvisionAccess 项目 -2. 实现 IHasFlatDevices + IHasAlarms -3. 注册到 Host → 网关启动时自动上报到 Vol.Pro -4. 前端新增 AccessDeviceActions.vue (~80行) -5. Vol.Pro 后端零改动 +2. 实现 IHasFlatDevices + IHasAlarms → 设备同步时填充 DeviceGroup=门禁设备 +3. 管理端字典加一条"门禁设备"分组 → 按钮自动出现 +4. Vol.Pro 同步接口零改动(ExtraData 承载门禁字段) +5. 前端新增 AccessDeviceActions.vue (~80行) 总工作量: 1-2 天 --- -## 九、代码组织规范 +## 十、代码组织规范 | 代码类型 | 路径 | 被覆盖? | |----------|------|:---:|