Files
SecMPS/api_sqlsugar/VolPro.WebApi/Controllers/Warehouse/Partial/gateway_nodesController.cs

299 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
*接口编写处...
*如果接口需要做Action的权限验证请在Action上使用属性
*如: [ApiActionPermission("gateway_nodes",Enums.ActionPermissionOptions.Search)]
*/
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Http;
using VolPro.Entity.DomainModels;
using Warehouse.IServices;
namespace Warehouse.Controllers
{
public partial class gateway_nodesController
{
private readonly Igateway_nodesService _service;//访问业务代码
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly Ibase_deviceService _deviceService;
private readonly Iiot_alarmService _alarmService;
[ActivatorUtilitiesConstructor]
public gateway_nodesController(
Igateway_nodesService service,
IHttpContextAccessor httpContextAccessor,
Ibase_deviceService deviceService,
Iiot_alarmService alarmService
)
: base(service)
{
_service = service;
_httpContextAccessor = httpContextAccessor;
_deviceService = deviceService;
_alarmService = alarmService;
}
private readonly Ibase_deviceService _deviceService;
private readonly Iiot_alarmService _alarmService;
[ActivatorUtilitiesConstructor]
public gateway_nodesController(
Igateway_nodesService service,
IHttpContextAccessor httpContextAccessor,
Ibase_deviceService deviceService,
Iiot_alarmService alarmService
)
: base(service)
{
_service = service;
_httpContextAccessor = httpContextAccessor;
_deviceService = deviceService;
_alarmService = alarmService;
}
/// <summary>A1: 网关注册 (Upsert)</summary>
[HttpPost]
[Route("/api/gateway/register")]
public async Task<IActionResult> RegisterGateway([FromBody] GatewayRegisterRequest req)
{
if (string.IsNullOrEmpty(req.NodeCode) || string.IsNullOrEmpty(req.Token))
return BadRequest(new { message = "NodeCode and Token required" });
var existing = await _service.FindAsIQueryable(x => x.NodeCode == req.NodeCode)
.FirstOrDefaultAsync();
gateway_nodes entity;
if (existing != null)
{
// 验证 Token
if (existing.NodeToken != req.Token)
return StatusCode(401, new { message = "认证失败" });
entity = existing;
entity.AdapterTypes = req.AdapterTypes;
entity.BaseUrl = req.BaseUrl;
entity.IsOnline = "在线";
entity.LastHeartbeat = DateTime.Now;
await _service.UpdateAsync(entity);
}
else
{
entity = new gateway_nodes
{
NodeCode = req.NodeCode,
NodeName = req.NodeCode,
NodeToken = req.Token,
AdapterTypes = req.AdapterTypes,
BaseUrl = req.BaseUrl,
IsOnline = "在线",
LastHeartbeat = DateTime.Now,
Enable = "启用",
CreateDate = DateTime.Now
};
await _service.AddAsync(entity);
}
var devices = await _service.ServiceProvider.GetService<VolPro.WebApi.Controllers.Warehouse.base_deviceController>()
?.GetDevicesForGateway(entity.NodeId) ?? new List<object>();
return Ok(new { nodeId = entity.NodeId, devices });
}
/// <summary>A2: 心跳</summary>
[HttpPost]
[Route("/api/gateway/heartbeat")]
public async Task<IActionResult> GatewayHeartbeat([FromBody] GatewayHeartbeatRequest req)
{
var entity = await _service.FindAsIQueryable(x => x.NodeCode == req.NodeCode && x.NodeToken == req.Token)
.FirstOrDefaultAsync();
if (entity == null)
return StatusCode(401, new { message = "认证失败" });
entity.IsOnline = "在线";
entity.LastHeartbeat = DateTime.Now;
await _service.UpdateAsync(entity);
return Ok(new { status = "ok", serverTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") });
}
/// <summary>A3: 设备数据同步(字段分治 + parentSourceId映射</summary>
[HttpPost]
[Route("/api/gateway/sync/devices")]
public async Task<IActionResult> SyncDevices([FromBody] SyncDevicesRequest req)
{
var node = await _service.FindAsIQueryable(x => x.NodeCode == req.NodeCode && x.NodeToken == req.Token)
.FirstOrDefaultAsync();
if (node == null) return StatusCode(401, new { message = "认证失败" });
// 批量查询已有设备映射表(用于 parentSourceId 解析)
var codes = req.Devices.Select(d => d.AdapterCode).Distinct().ToList();
var existingIds = await _deviceService
.FindAsIQueryable(x => codes.Contains(x.AdapterCode) && x.GatewayNodeId == node.NodeId)
.ToDictionaryAsync(x => (x.AdapterCode, x.SourceId), x => x.DeviceId);
int added = 0, updated = 0;
foreach (var d in req.Devices)
{
var key = (d.AdapterCode, d.SourceId);
existingIds.TryGetValue(key, out var existingId);
bool isNew = existingId == 0;
// 解析 parentSourceId → ParentDeviceId
int? parentDeviceId = null;
if (!string.IsNullOrEmpty(d.ParentSourceId))
{
existingIds.TryGetValue((d.AdapterCode, d.ParentSourceId), out var pid);
if (pid > 0) parentDeviceId = pid;
}
// 首次入库写全量,已有记录仅更新网关字段
if (isNew)
{
var entity = new base_device
{
AdapterCode = d.AdapterCode,
SourceId = d.SourceId,
DeviceName = d.Name,
DeviceCategory = d.Category,
DeviceGroup = d.Group,
GatewayNodeId = node.NodeId,
IsParent = d.IsParent ? "是" : "否",
ParentDeviceId = parentDeviceId,
IsOnline = d.IsOnline ? "在线" : "离线",
IpAddress = d.IpAddress,
Port = d.Port,
ExtraData = d.ExtraData != null
? System.Text.Json.JsonSerializer.Serialize(d.ExtraData)
: null,
Enable = "启用",
LastSyncTime = DateTime.Now,
CreateDate = DateTime.Now
};
await _deviceService.AddAsync(entity);
added++;
}
else
{
var entity = await _deviceService.FindAsIQueryable(x => x.DeviceId == existingId).FirstOrDefaultAsync();
if (entity != null)
{
entity.IsOnline = d.IsOnline ? "在线" : "离线";
entity.IsParent = d.IsParent ? "是" : "否";
entity.ParentDeviceId = parentDeviceId ?? entity.ParentDeviceId;
entity.IpAddress = d.IpAddress;
entity.Port = d.Port;
entity.ExtraData = d.ExtraData != null
? System.Text.Json.JsonSerializer.Serialize(d.ExtraData)
: entity.ExtraData;
entity.LastSyncTime = DateTime.Now;
await _deviceService.UpdateAsync(entity);
updated++;
}
}
}
return Ok(new { added, updated, removed = 0 });
}
/// <summary>A4: 告警同步</summary>
[HttpPost]
[Route("/api/gateway/sync/alarms")]
public async Task<IActionResult> SyncAlarms([FromBody] SyncAlarmsRequest req)
{
var node = await _service.FindAsIQueryable(x => x.NodeCode == req.NodeCode && x.NodeToken == req.Token)
.FirstOrDefaultAsync();
if (node == null) return StatusCode(401, new { message = "认证失败" });
// 批量查出 DeviceSourceId → DeviceId 映射
var codes = req.Alarms.Select(a => a.AdapterCode).Distinct().ToList();
var srcIds = req.Alarms.Select(a => a.DeviceSourceId).ToList();
var deviceMap = await _deviceService
.FindAsIQueryable(x => codes.Contains(x.AdapterCode) && srcIds.Contains(x.SourceId))
.ToDictionaryAsync(x => (x.AdapterCode, x.SourceId), x => x.DeviceId);
int added = 0;
foreach (var a in req.Alarms)
{
// 跳过已存在的告警SourceAlarmId 去重)
var exists = await _alarmService
.FindAsIQueryable(x => x.SourceAlarmId == a.SourceAlarmId)
.AnyAsync();
if (exists) continue;
deviceMap.TryGetValue((a.AdapterCode, a.DeviceSourceId), out var deviceId);
var alarm = new iot_alarm
{
SourceAlarmId = a.SourceAlarmId,
DeviceId = deviceId > 0 ? deviceId : null,
AdapterCode = a.AdapterCode,
AlarmLevel = a.Level,
AlarmDesc = a.Desc,
AlarmValue = a.Value,
StartTime = DateTime.TryParse(a.StartTime, out var st) ? st : DateTime.Now,
State = "未确认",
CreateDate = DateTime.Now
};
await _alarmService.AddAsync(alarm);
added++;
}
return Ok(new { added });
}
}
public class GatewayRegisterRequest
{
public string NodeCode { get; set; } = "";
public string Token { get; set; } = "";
public string AdapterTypes { get; set; } = "";
public string BaseUrl { get; set; } = "";
}
public class GatewayHeartbeatRequest
{
public string NodeCode { get; set; } = "";
public string Token { get; set; } = "";
}
public class SyncDevicesRequest
{
public string NodeCode { get; set; } = "";
public string Token { get; set; } = "";
public List<SyncDeviceItem> Devices { get; set; } = new();
}
public class SyncDeviceItem
{
public string AdapterCode { get; set; } = "";
public string SourceId { get; set; } = "";
public string Name { get; set; } = "";
public string Category { get; set; } = "";
public string Group { get; set; } = "";
public bool IsParent { get; set; }
public string? ParentSourceId { get; set; }
public bool IsOnline { get; set; }
public string? IpAddress { get; set; }
public int? Port { get; set; }
public Dictionary<string, object?>? ExtraData { get; set; }
}
public class SyncAlarmsRequest
{
public string NodeCode { get; set; } = "";
public string Token { get; set; } = "";
public List<SyncAlarmItem> Alarms { get; set; } = new();
}
public class SyncAlarmItem
{
public string SourceAlarmId { get; set; } = "";
public string DeviceSourceId { get; set; } = "";
public string AdapterCode { get; set; } = "";
public string Level { get; set; } = "";
public string Desc { get; set; } = "";
public double? Value { get; set; }
public string StartTime { get; set; } = "";
}
}