using Microsoft.Extensions.DependencyInjection; using VolPro.Entity.DomainModels; using Warehouse.IRepositories; using System.Text.Json; namespace VolPro.Warehouse.Services; /// MC4.0 同步引擎:对象树 → 区域匹配 + 设备 Upsert public class SyncEngine { private readonly IServiceProvider _sp; public SyncEngine(IServiceProvider sp) => _sp = sp; private Iwarehouse_regionsRepository GetRegionRepo() => _sp.GetService()!; private Iwarehouse_devicepointRepository GetPointRepo() => _sp.GetService()!; private Ibase_deviceRepository GetDeviceRepo() => _sp.GetService()!; 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) { int pointId = await MatchOrCreatePoint(node); foreach (var child in node.Children) await ProcessNodeAsync(gatewayNodeId, adapterCode, child, null, stats); } else if (node.Type == 2) { 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 regionRepo = GetRegionRepo(); var regionDb = regionRepo.DbContext; var region = regionDb.Queryable() .First(x => x.RegionName == node.Name); if (region == null) { region = new warehouse_regions { RegionName = node.Name ?? $"MC4_{node.Id}" }; regionDb.Insertable(region).ExecuteCommand(); } var pointRepo = GetPointRepo(); var pointDb = pointRepo.DbContext; var point = pointDb.Queryable() .First(x => x.RegionId == region.Id); if (point == null) { point = new warehouse_devicepoint { PointName = node.Name ?? $"MC4_PT_{node.Id}", RegionId = region.Id }; pointDb.Insertable(point).ExecuteCommand(); } return point.PointID; } private async Task UpsertDevice(int gatewayNodeId, string adapterCode, Mc4TreeNode node, int? parentDeviceId) { var deviceRepo = GetDeviceRepo(); var db = deviceRepo.DbContext; var sourceId = node.Id.ToString(); var existing = db.Queryable() .First(x => x.AdapterCode == adapterCode && x.SourceId == sourceId); if (existing != null) { existing.IsOnline = "在线"; existing.LastSyncTime = DateTime.Now; existing.ParentDeviceId = parentDeviceId ?? existing.ParentDeviceId; if (node.Option != null) existing.ExtraData = JsonSerializer.Serialize(node.Option); db.Updateable(existing).ExecuteCommand(); return existing.DeviceId; } 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 ? JsonSerializer.Serialize(node.Option) : null }; db.Insertable(device).ExecuteCommand(); return device.DeviceId; } private static string MapCategory(int objectType, string? tag) => (objectType, tag) switch { (_, "温湿度") => "温湿度变送器", (_, "烟雾") => "烟雾报警器", (_, "气体") => "气体报警器", (_, "门磁") => "门磁", _ => "动环采集器" }; } public class SyncStats { public int Added; public int Updated; public Dictionary DeviceIds = new(); } 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(); }