using Microsoft.Extensions.DependencyInjection; using VolPro.Entity.DomainModels; using Warehouse.IServices; namespace VolPro.Warehouse.Services; /// /// MC4.0 同步引擎:对象树 → 区域匹配 + 设备 Upsert /// public class SyncEngine { private readonly IServiceProvider _sp; public SyncEngine(IServiceProvider sp) => _sp = sp; private Iwarehouse_regionsService GetRegionService() => _sp.GetService()!; private Iwarehouse_devicepointService GetPointService() => _sp.GetService()!; private Ibase_deviceService GetDeviceService() => _sp.GetService()!; /// 处理 MC4.0 对象树,匹配区域并 Upsert 设备 public async Task ProcessMc4TreeAsync( int gatewayNodeId, string adapterCode, List tree) { var stats = new SyncStats(); foreach (var node in tree) await ProcessNodeAsync(gatewayNodeId, adapterCode, node, null, stats); return stats; } private async Task ProcessNodeAsync(int gatewayNodeId, string adapterCode, Mc4TreeNode node, int? parentDeviceId, SyncStats stats) { if (node.Type == 1) // 区域节点 → 匹配 warehouse_regions + warehouse_devicepoint { int pointId = await MatchOrCreatePoint(node); // 递归处理子节点,子设备归属到此点位 foreach (var child in node.Children) await ProcessNodeAsync(gatewayNodeId, adapterCode, child, null, stats); } else if (node.Type == 2) // 设备节点 → Upsert base_device { int deviceId = await UpsertDevice(gatewayNodeId, adapterCode, node, parentDeviceId); if (stats.DeviceIds.TryGetValue(node.Id, out _)) stats.Updated++; else stats.Added++; stats.DeviceIds[node.Id] = deviceId; foreach (var child in node.Children) await ProcessNodeAsync(gatewayNodeId, adapterCode, child, deviceId, stats); } } private async Task MatchOrCreatePoint(Mc4TreeNode node) { // 按名称匹配已有区域 var regionSvc = GetRegionService(); var region = await regionSvc.FindAsIQueryable(x => x.RegionsName == node.Name) .FirstOrDefaultAsync(); if (region == null) { region = new warehouse_regions { RegionsName = node.Name ?? $"MC4_{node.Id}", ParentId = null, CreateDate = DateTime.Now }; await regionSvc.AddAsync(region); } // 在此区域下找/建点位 var pointSvc = GetPointService(); var point = await pointSvc.FindAsIQueryable(x => x.RegionId == region.RegionsId) .FirstOrDefaultAsync(); if (point == null) { point = new warehouse_devicepoint { DevicePointName = node.Name ?? $"MC4_PT_{node.Id}", RegionId = region.RegionsId, CreateDate = DateTime.Now }; await pointSvc.AddAsync(point); } return point.DevicePointId; } private async Task UpsertDevice(int gatewayNodeId, string adapterCode, Mc4TreeNode node, int? parentDeviceId) { var svc = GetDeviceService(); var sourceId = node.Id.ToString(); var existing = await svc.FindAsIQueryable( x => x.AdapterCode == adapterCode && x.SourceId == sourceId) .FirstOrDefaultAsync(); if (existing != null) { existing.IsOnline = "在线"; existing.LastSyncTime = DateTime.Now; existing.ParentDeviceId = parentDeviceId ?? existing.ParentDeviceId; if (node.Option != null) existing.ExtraData = System.Text.Json.JsonSerializer.Serialize(node.Option); await svc.UpdateAsync(existing); return existing.DeviceId; } else { var device = new base_device { DeviceName = node.Name ?? $"MC4_DEV_{node.Id}", AdapterCode = adapterCode, SourceId = sourceId, DeviceCategory = MapCategory(node.ObjectType, node.Tag), DeviceGroup = "IoT设备", GatewayNodeId = gatewayNodeId, ParentDeviceId = parentDeviceId, IsParent = node.Children?.Count > 0 ? "是" : "否", IsOnline = "在线", Enable = "启用", LastSyncTime = DateTime.Now, CreateDate = DateTime.Now, ExtraData = node.Option != null ? System.Text.Json.JsonSerializer.Serialize(node.Option) : null }; await svc.AddAsync(device); return device.DeviceId; } } private static string MapCategory(int objectType, string? tag) => (objectType, tag) switch { (_, "温湿度") => "温湿度变送器", (_, "烟雾") => "烟雾报警器", (_, "气体") => "气体报警器", (_, "门磁") => "门磁", _ => "动环采集器" }; } public class SyncStats { public int Added { get; set; } public int Updated { get; set; } public Dictionary DeviceIds { get; set; } = new(); } /// 简化的 MC4 树节点(网关→Vol.Pro 传输用) public class Mc4TreeNode { public int Id { get; set; } public string? Name { get; set; } public int Type { get; set; } public int ObjectType { get; set; } public string? Tag { get; set; } public Dictionary? Option { get; set; } public List Children { get; set; } = new(); }