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();
}