"第8天:同步引擎+区域匹配+设备Upsert+字段分治"

This commit is contained in:
2026-05-17 00:36:36 +08:00
parent 206eaad42d
commit b6d7e30b0d
44 changed files with 1877 additions and 7 deletions

View File

@@ -0,0 +1,304 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*如果数据库字段发生变化请在代码生器重新生成此Model
*/
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SqlSugar;
using VolPro.Entity.SystemModels;
namespace VolPro.Entity.DomainModels
{
[Entity(TableCnName = "设备管理",TableName = "base_device",DetailTable = new Type[] { typeof(video_channel),typeof(iot_devicedata),typeof(iot_alarm)},DetailTableCnName = "视频通道,数据归档,告警记录",DBServer = "ServiceDbContext")]
public partial class base_device:ServiceEntity
{
/// <summary>
///设备ID
/// </summary>
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
[Key]
[Display(Name ="设备ID")]
[Column(TypeName="int")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public int DeviceId { get; set; }
/// <summary>
///设备名称
/// </summary>
[Display(Name ="设备名称")]
[MaxLength(100)]
[Column(TypeName="nvarchar(100)")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public string DeviceName { get; set; }
/// <summary>
///来源适配器(类型:实例)
/// </summary>
[SugarColumn(IsPrimaryKey = true)]
[Key]
[Display(Name ="来源适配器(类型:实例)")]
[MaxLength(50)]
[Column(TypeName="nvarchar(50)")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public string AdapterCode { get; set; }
/// <summary>
///源系统设备ID
/// </summary>
[Display(Name ="源系统设备ID")]
[MaxLength(100)]
[Column(TypeName="nvarchar(100)")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public string SourceId { get; set; }
/// <summary>
///设备种类(数据字典)
/// </summary>
[Display(Name ="设备种类(数据字典)")]
[MaxLength(50)]
[Column(TypeName="nvarchar(50)")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public string DeviceCategory { get; set; }
/// <summary>
///设备分组(数据字典)
/// </summary>
[SugarColumn(IsPrimaryKey = true)]
[Key]
[Display(Name ="设备分组(数据字典)")]
[MaxLength(20)]
[Column(TypeName="nvarchar(20)")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public string DeviceGroup { get; set; }
/// <summary>
///所属点位ID
/// </summary>
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
[Key]
[Display(Name ="所属点位ID")]
[Column(TypeName="int")]
[Editable(true)]
public int? PointId { get; set; }
/// <summary>
///所属网关节点ID
/// </summary>
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
[Key]
[Display(Name ="所属网关节点ID")]
[Column(TypeName="int")]
[Editable(true)]
public int? GatewayNodeId { get; set; }
/// <summary>
///是否父设备(数据字典)
/// </summary>
[Display(Name ="是否父设备(数据字典)")]
[MaxLength(20)]
[Column(TypeName="nvarchar(20)")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public string IsParent { get; set; }
/// <summary>
///父设备ID(自引用,子设备挂父设备下)
/// </summary>
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
[Key]
[Display(Name ="父设备ID(自引用,子设备挂父设备下)")]
[Column(TypeName="int")]
[Editable(true)]
public int? ParentDeviceId { get; set; }
/// <summary>
///在线状态(数据字典)
/// </summary>
[Display(Name ="在线状态(数据字典)")]
[MaxLength(20)]
[Column(TypeName="nvarchar(20)")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public string IsOnline { get; set; }
/// <summary>
///IP地址
/// </summary>
[Display(Name ="IP地址")]
[MaxLength(50)]
[Column(TypeName="nvarchar(50)")]
[Editable(true)]
public string IpAddress { get; set; }
/// <summary>
///端口
/// </summary>
[Display(Name ="端口")]
[Column(TypeName="int")]
[Editable(true)]
public int? Port { get; set; }
/// <summary>
///安装位置
/// </summary>
[Display(Name ="安装位置")]
[MaxLength(200)]
[Column(TypeName="nvarchar(200)")]
[Editable(true)]
public string Location { get; set; }
/// <summary>
///纬度
/// </summary>
[Display(Name ="纬度")]
[Column(TypeName="double")]
[Editable(true)]
public decimal? Lat { get; set; }
/// <summary>
///经度
/// </summary>
[Display(Name ="经度")]
[Column(TypeName="double")]
[Editable(true)]
public decimal? Lng { get; set; }
/// <summary>
///三维地图模型ID
/// </summary>
[Display(Name ="三维地图模型ID")]
[MaxLength(100)]
[Column(TypeName="nvarchar(100)")]
[Editable(true)]
public string MapModelId { get; set; }
/// <summary>
///模型缩放比例
/// </summary>
[Display(Name ="模型缩放比例")]
[Column(TypeName="decimal")]
[Editable(true)]
public decimal? MapModelScale { get; set; }
/// <summary>
///模型旋转角度(JSON)
/// </summary>
[Display(Name ="模型旋转角度(JSON)")]
[MaxLength(100)]
[Column(TypeName="nvarchar(100)")]
[Editable(true)]
public string MapModelRotation { get; set; }
/// <summary>
///适配器扩展数据JSON(Owl/MC4/门禁字段均存于此)
/// </summary>
[Display(Name ="适配器扩展数据JSON(Owl/MC4/门禁字段均存于此)")]
[Column(TypeName="nvarchar(max)")]
[Editable(true)]
public string ExtraData { get; set; }
/// <summary>
///上次同步时间
/// </summary>
[Display(Name ="上次同步时间")]
[Column(TypeName="datetime")]
[Editable(true)]
public DateTime? LastSyncTime { get; set; }
/// <summary>
///启用状态(数据字典)
/// </summary>
[Display(Name ="启用状态(数据字典)")]
[MaxLength(20)]
[Column(TypeName="nvarchar(20)")]
[Editable(true)]
public string Enable { get; set; }
/// <summary>
///备注
/// </summary>
[Display(Name ="备注")]
[MaxLength(500)]
[Column(TypeName="nvarchar(500)")]
[Editable(true)]
public string Remark { get; set; }
/// <summary>
///创建人ID
/// </summary>
[Display(Name ="创建人ID")]
[Column(TypeName="int")]
[Editable(true)]
public int? CreateID { get; set; }
/// <summary>
///创建人
/// </summary>
[Display(Name ="创建人")]
[MaxLength(50)]
[Column(TypeName="nvarchar(50)")]
[Editable(true)]
public string Creator { get; set; }
/// <summary>
///创建时间
/// </summary>
[Display(Name ="创建时间")]
[Column(TypeName="datetime")]
[Editable(true)]
public DateTime? CreateDate { get; set; }
/// <summary>
///修改人ID
/// </summary>
[Display(Name ="修改人ID")]
[Column(TypeName="int")]
[Editable(true)]
public int? ModifyID { get; set; }
/// <summary>
///修改人
/// </summary>
[Display(Name ="修改人")]
[MaxLength(50)]
[Column(TypeName="nvarchar(50)")]
[Editable(true)]
public string Modifier { get; set; }
/// <summary>
///修改时间
/// </summary>
[Display(Name ="修改时间")]
[Column(TypeName="datetime")]
[Editable(true)]
public DateTime? ModifyDate { get; set; }
[Display(Name ="视频通道")]
[ForeignKey("DeviceId")][Navigate(NavigateType.OneToMany,nameof(DeviceId),nameof(DeviceId))]
public List<video_channel> video_channel { get; set; }
[Display(Name ="数据归档")]
[ForeignKey("DeviceId")][Navigate(NavigateType.OneToMany,nameof(DeviceId),nameof(DeviceId))]
public List<iot_devicedata> iot_devicedata { get; set; }
[Display(Name ="告警记录")]
[ForeignKey("DeviceId")][Navigate(NavigateType.OneToMany,nameof(DeviceId),nameof(DeviceId))]
public List<iot_alarm> iot_alarm { get; set; }
}
}

View File

@@ -0,0 +1,170 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*如果数据库字段发生变化请在代码生器重新生成此Model
*/
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SqlSugar;
using VolPro.Entity.SystemModels;
namespace VolPro.Entity.DomainModels
{
[Entity(TableCnName = "设备管理_网关节点",TableName = "gateway_nodes",DBServer = "ServiceDbContext")]
public partial class gateway_nodes:ServiceEntity
{
/// <summary>
///网关节点ID
/// </summary>
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
[Key]
[Display(Name ="网关节点ID")]
[Column(TypeName="int")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public int NodeId { get; set; }
/// <summary>
///网关唯一编码
/// </summary>
[SugarColumn(IsPrimaryKey = true)]
[Key]
[Display(Name ="网关唯一编码")]
[MaxLength(50)]
[Column(TypeName="nvarchar(50)")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public string NodeCode { get; set; }
/// <summary>
///网关名称
/// </summary>
[Display(Name ="网关名称")]
[MaxLength(100)]
[Column(TypeName="nvarchar(100)")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public string NodeName { get; set; }
/// <summary>
///认证令牌
/// </summary>
[Display(Name ="认证令牌")]
[MaxLength(100)]
[Column(TypeName="nvarchar(100)")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public string NodeToken { get; set; }
/// <summary>
///支持的适配器类型(网关上报)
/// </summary>
[Display(Name ="支持的适配器类型(网关上报)")]
[MaxLength(200)]
[Column(TypeName="nvarchar(200)")]
[Editable(true)]
public string AdapterTypes { get; set; }
/// <summary>
///网关自身地址(网关上报)
/// </summary>
[Display(Name ="网关自身地址(网关上报)")]
[MaxLength(200)]
[Column(TypeName="nvarchar(200)")]
[Editable(true)]
public string BaseUrl { get; set; }
/// <summary>
///上次心跳时间
/// </summary>
[Display(Name ="上次心跳时间")]
[Column(TypeName="datetime")]
[Editable(true)]
public DateTime? LastHeartbeat { get; set; }
/// <summary>
///在线状态(数据字典:在线/离线)
/// </summary>
[SugarColumn(IsPrimaryKey = true)]
[Key]
[Display(Name ="在线状态(数据字典:在线/离线)")]
[MaxLength(20)]
[Column(TypeName="nvarchar(20)")]
[Editable(true)]
public string IsOnline { get; set; }
/// <summary>
///启用状态(数据字典:启用/禁用)
/// </summary>
[Display(Name ="启用状态(数据字典:启用/禁用)")]
[MaxLength(20)]
[Column(TypeName="nvarchar(20)")]
[Editable(true)]
public string Enable { get; set; }
/// <summary>
///备注
/// </summary>
[Display(Name ="备注")]
[MaxLength(500)]
[Column(TypeName="nvarchar(500)")]
[Editable(true)]
public string Remark { get; set; }
/// <summary>
///创建人ID
/// </summary>
[Display(Name ="创建人ID")]
[Column(TypeName="int")]
[Editable(true)]
public int? CreateID { get; set; }
/// <summary>
///创建人
/// </summary>
[Display(Name ="创建人")]
[MaxLength(50)]
[Column(TypeName="nvarchar(50)")]
[Editable(true)]
public string Creator { get; set; }
/// <summary>
///创建时间
/// </summary>
[Display(Name ="创建时间")]
[Column(TypeName="datetime")]
[Editable(true)]
public DateTime? CreateDate { get; set; }
/// <summary>
///修改人ID
/// </summary>
[Display(Name ="修改人ID")]
[Column(TypeName="int")]
[Editable(true)]
public int? ModifyID { get; set; }
/// <summary>
///修改人
/// </summary>
[Display(Name ="修改人")]
[MaxLength(50)]
[Column(TypeName="nvarchar(50)")]
[Editable(true)]
public string Modifier { get; set; }
/// <summary>
///修改时间
/// </summary>
[Display(Name ="修改时间")]
[Column(TypeName="datetime")]
[Editable(true)]
public DateTime? ModifyDate { get; set; }
}
}

View File

@@ -0,0 +1,154 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*如果数据库字段发生变化请在代码生器重新生成此Model
*/
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SqlSugar;
using VolPro.Entity.SystemModels;
namespace VolPro.Entity.DomainModels
{
[Entity(TableCnName = "设备管理_告警记录",TableName = "iot_alarm",DBServer = "ServiceDbContext")]
public partial class iot_alarm:ServiceEntity
{
/// <summary>
///告警ID
/// </summary>
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
[Key]
[Display(Name ="告警ID")]
[Column(TypeName="int")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public int AlarmId { get; set; }
/// <summary>
///源系统告警ID
/// </summary>
[SugarColumn(IsPrimaryKey = true)]
[Key]
[Display(Name ="源系统告警ID")]
[MaxLength(100)]
[Column(TypeName="nvarchar(100)")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public string SourceAlarmId { get; set; }
/// <summary>
///关联设备ID
/// </summary>
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
[Key]
[Display(Name ="关联设备ID")]
[Column(TypeName="int")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public int DeviceId { get; set; }
/// <summary>
///告警类型
/// </summary>
[Display(Name ="告警类型")]
[Column(TypeName="int")]
[Editable(true)]
public int? AlarmType { get; set; }
/// <summary>
///告警等级(数据字典:提示/普通/重要/紧急)
/// </summary>
[SugarColumn(IsPrimaryKey = true)]
[Key]
[Display(Name ="告警等级(数据字典:提示/普通/重要/紧急)")]
[MaxLength(20)]
[Column(TypeName="nvarchar(20)")]
[Editable(true)]
public string AlarmLevel { get; set; }
/// <summary>
///告警描述
/// </summary>
[Display(Name ="告警描述")]
[MaxLength(500)]
[Column(TypeName="nvarchar(500)")]
[Editable(true)]
public string AlarmDesc { get; set; }
/// <summary>
///触发值
/// </summary>
[Display(Name ="触发值")]
[Column(TypeName="double")]
[Editable(true)]
public decimal? AlarmValue { get; set; }
/// <summary>
///告警开始时间
/// </summary>
[SugarColumn(IsPrimaryKey = true)]
[Key]
[Display(Name ="告警开始时间")]
[Column(TypeName="datetime")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public DateTime StartTime { get; set; }
/// <summary>
///告警结束时间
/// </summary>
[Display(Name ="告警结束时间")]
[Column(TypeName="datetime")]
[Editable(true)]
public DateTime? EndTime { get; set; }
/// <summary>
///确认时间
/// </summary>
[Display(Name ="确认时间")]
[Column(TypeName="datetime")]
[Editable(true)]
public DateTime? ConfirmTime { get; set; }
/// <summary>
///确认人
/// </summary>
[Display(Name ="确认人")]
[MaxLength(50)]
[Column(TypeName="nvarchar(50)")]
[Editable(true)]
public string ConfirmUser { get; set; }
/// <summary>
///状态(数据字典:未确认/已确认/已结束)
/// </summary>
[Display(Name ="状态(数据字典:未确认/已确认/已结束)")]
[MaxLength(20)]
[Column(TypeName="nvarchar(20)")]
[Editable(true)]
public string State { get; set; }
/// <summary>
///来源适配器
/// </summary>
[Display(Name ="来源适配器")]
[MaxLength(50)]
[Column(TypeName="nvarchar(50)")]
[Editable(true)]
public string AdapterCode { get; set; }
/// <summary>
///创建时间
/// </summary>
[Display(Name ="创建时间")]
[Column(TypeName="datetime")]
[Editable(true)]
public DateTime? CreateDate { get; set; }
}
}

View File

@@ -0,0 +1,87 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*如果数据库字段发生变化请在代码生器重新生成此Model
*/
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SqlSugar;
using VolPro.Entity.SystemModels;
namespace VolPro.Entity.DomainModels
{
[Entity(TableCnName = "设备管理_数据归档",TableName = "iot_devicedata",DBServer = "ServiceDbContext")]
public partial class iot_devicedata:ServiceEntity
{
/// <summary>
///数据记录ID
/// </summary>
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
[Key]
[Display(Name ="数据记录ID")]
[Column(TypeName="int")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public int DataId { get; set; }
/// <summary>
///关联设备ID(子设备/点位)
/// </summary>
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
[Key]
[Display(Name ="关联设备ID(子设备/点位)")]
[Column(TypeName="int")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public int DeviceId { get; set; }
/// <summary>
///点位数值
/// </summary>
[Display(Name ="点位数值")]
[Column(TypeName="double")]
[Editable(true)]
public decimal? PointValue { get; set; }
/// <summary>
///数据更新时间
/// </summary>
[Display(Name ="数据更新时间")]
[Column(TypeName="datetime")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public DateTime UpdateTime { get; set; }
/// <summary>
///采集间隔(毫秒)
/// </summary>
[Display(Name ="采集间隔(毫秒)")]
[Column(TypeName="int")]
[Editable(true)]
public int? Interval { get; set; }
/// <summary>
///归档类型(1小时/2日)
/// </summary>
[Display(Name ="归档类型(1小时/2日)")]
[Column(TypeName="int")]
[Editable(true)]
public int? ArchiveType { get; set; }
/// <summary>
///创建时间
/// </summary>
[SugarColumn(IsPrimaryKey = true)]
[Key]
[Display(Name ="创建时间")]
[Column(TypeName="datetime")]
[Editable(true)]
public DateTime? CreateDate { get; set; }
}
}

View File

@@ -0,0 +1,22 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*如果数据库字段发生变化请在代码生器重新生成此Model
*/
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SqlSugar;
using VolPro.Entity.SystemModels;
namespace VolPro.Entity.DomainModels
{
public partial class base_device
{
//此处配置字段(字段配置见此model的另一个partial),如果表中没有此字段请加上[SugarColumn(IsIgnore = true)]属性,否则会异常
}
}

View File

@@ -0,0 +1,22 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*如果数据库字段发生变化请在代码生器重新生成此Model
*/
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SqlSugar;
using VolPro.Entity.SystemModels;
namespace VolPro.Entity.DomainModels
{
public partial class gateway_nodes
{
//此处配置字段(字段配置见此model的另一个partial),如果表中没有此字段请加上[SugarColumn(IsIgnore = true)]属性,否则会异常
}
}

View File

@@ -0,0 +1,22 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*如果数据库字段发生变化请在代码生器重新生成此Model
*/
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SqlSugar;
using VolPro.Entity.SystemModels;
namespace VolPro.Entity.DomainModels
{
public partial class iot_alarm
{
//此处配置字段(字段配置见此model的另一个partial),如果表中没有此字段请加上[SugarColumn(IsIgnore = true)]属性,否则会异常
}
}

View File

@@ -0,0 +1,22 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*如果数据库字段发生变化请在代码生器重新生成此Model
*/
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SqlSugar;
using VolPro.Entity.SystemModels;
namespace VolPro.Entity.DomainModels
{
public partial class iot_devicedata
{
//此处配置字段(字段配置见此model的另一个partial),如果表中没有此字段请加上[SugarColumn(IsIgnore = true)]属性,否则会异常
}
}

View File

@@ -0,0 +1,22 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*如果数据库字段发生变化请在代码生器重新生成此Model
*/
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SqlSugar;
using VolPro.Entity.SystemModels;
namespace VolPro.Entity.DomainModels
{
public partial class video_channel
{
//此处配置字段(字段配置见此model的另一个partial),如果表中没有此字段请加上[SugarColumn(IsIgnore = true)]属性,否则会异常
}
}

View File

@@ -0,0 +1,22 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*如果数据库字段发生变化请在代码生器重新生成此Model
*/
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SqlSugar;
using VolPro.Entity.SystemModels;
namespace VolPro.Entity.DomainModels
{
public partial class video_record
{
//此处配置字段(字段配置见此model的另一个partial),如果表中没有此字段请加上[SugarColumn(IsIgnore = true)]属性,否则会异常
}
}

View File

@@ -0,0 +1,120 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*如果数据库字段发生变化请在代码生器重新生成此Model
*/
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SqlSugar;
using VolPro.Entity.SystemModels;
namespace VolPro.Entity.DomainModels
{
[Entity(TableCnName = "设备管理_视频通道",TableName = "video_channel",DetailTable = new Type[] { typeof(video_record)},DetailTableCnName = "录像记录",DBServer = "ServiceDbContext")]
public partial class video_channel:ServiceEntity
{
/// <summary>
///通道记录ID
/// </summary>
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
[Key]
[Display(Name ="通道记录ID")]
[Column(TypeName="int")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public int ChannelId { get; set; }
/// <summary>
///Owl系统通道ID
/// </summary>
[SugarColumn(IsPrimaryKey = true)]
[Key]
[Display(Name ="Owl系统通道ID")]
[MaxLength(64)]
[Column(TypeName="nvarchar(64)")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public string OwlChannelId { get; set; }
/// <summary>
///关联Base_Device设备ID
/// </summary>
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
[Key]
[Display(Name ="关联Base_Device设备ID")]
[Column(TypeName="int")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public int DeviceId { get; set; }
/// <summary>
///Owl流应用名
/// </summary>
[Display(Name ="Owl流应用名")]
[MaxLength(50)]
[Column(TypeName="nvarchar(50)")]
[Editable(true)]
public string OwlStreamApp { get; set; }
/// <summary>
///Owl流名称
/// </summary>
[Display(Name ="Owl流名称")]
[MaxLength(100)]
[Column(TypeName="nvarchar(100)")]
[Editable(true)]
public string OwlStreamName { get; set; }
/// <summary>
///是否支持云台
/// </summary>
[Display(Name ="是否支持云台")]
[Column(TypeName="tinyint")]
[Editable(true)]
public byte? HasPtz { get; set; }
/// <summary>
///是否支持录像
/// </summary>
[Display(Name ="是否支持录像")]
[Column(TypeName="tinyint")]
[Editable(true)]
public byte? HasRecording { get; set; }
/// <summary>
///录像模式
/// </summary>
[Display(Name ="录像模式")]
[Column(TypeName="int")]
[Editable(true)]
public int? RecordMode { get; set; }
/// <summary>
///快照地址
/// </summary>
[Display(Name ="快照地址")]
[MaxLength(500)]
[Column(TypeName="nvarchar(500)")]
[Editable(true)]
public string SnapshotUrl { get; set; }
/// <summary>
///创建时间
/// </summary>
[Display(Name ="创建时间")]
[Column(TypeName="datetime")]
[Editable(true)]
public DateTime? CreateDate { get; set; }
[Display(Name ="录像记录")]
[ForeignKey("ChannelId")][Navigate(NavigateType.OneToMany,nameof(ChannelId),nameof(ChannelId))]
public List<video_record> video_record { get; set; }
}
}

View File

@@ -0,0 +1,123 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*如果数据库字段发生变化请在代码生器重新生成此Model
*/
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SqlSugar;
using VolPro.Entity.SystemModels;
namespace VolPro.Entity.DomainModels
{
[Entity(TableCnName = "设备管理_录像记录",TableName = "video_record",DBServer = "ServiceDbContext")]
public partial class video_record:ServiceEntity
{
/// <summary>
///录像记录ID
/// </summary>
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
[Key]
[Display(Name ="录像记录ID")]
[Column(TypeName="int")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public int RecordId { get; set; }
/// <summary>
///关联通道ID
/// </summary>
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
[Key]
[Display(Name ="关联通道ID")]
[Column(TypeName="int")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public int ChannelId { get; set; }
/// <summary>
///Owl录像记录ID
/// </summary>
[Display(Name ="Owl录像记录ID")]
[Column(TypeName="int")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public int OwlRecordId { get; set; }
/// <summary>
///应用名
/// </summary>
[Display(Name ="应用名")]
[MaxLength(50)]
[Column(TypeName="nvarchar(50)")]
[Editable(true)]
public string App { get; set; }
/// <summary>
///流ID
/// </summary>
[Display(Name ="流ID")]
[MaxLength(100)]
[Column(TypeName="nvarchar(100)")]
[Editable(true)]
public string Stream { get; set; }
/// <summary>
///录像开始时间
/// </summary>
[SugarColumn(IsPrimaryKey = true)]
[Key]
[Display(Name ="录像开始时间")]
[Column(TypeName="datetime")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public DateTime StartedAt { get; set; }
/// <summary>
///录像结束时间
/// </summary>
[Display(Name ="录像结束时间")]
[Column(TypeName="datetime")]
[Editable(true)]
public DateTime? EndedAt { get; set; }
/// <summary>
///录像时长(秒)
/// </summary>
[Display(Name ="录像时长(秒)")]
[Column(TypeName="double")]
[Editable(true)]
public decimal? Duration { get; set; }
/// <summary>
///文件路径
/// </summary>
[Display(Name ="文件路径")]
[MaxLength(500)]
[Column(TypeName="nvarchar(500)")]
[Editable(true)]
public string FilePath { get; set; }
/// <summary>
///文件大小(字节)
/// </summary>
[Display(Name ="文件大小(字节)")]
[Column(TypeName="bigint")]
[Editable(true)]
public long? FileSize { get; set; }
/// <summary>
///创建时间
/// </summary>
[Display(Name ="创建时间")]
[Column(TypeName="datetime")]
[Editable(true)]
public DateTime? CreateDate { get; set; }
}
}

View File

@@ -19,25 +19,39 @@ namespace Warehouse.Controllers
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
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
IHttpContextAccessor httpContextAccessor,
Ibase_deviceService deviceService,
Iiot_alarmService alarmService
)
: base(service)
{
_service = service;
_httpContextAccessor = httpContextAccessor;
_deviceService = deviceService;
_alarmService = alarmService;
}
/// <summary>A1: 网关注册 (Upsert)</summary>
@@ -105,7 +119,7 @@ namespace Warehouse.Controllers
return Ok(new { status = "ok", serverTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") });
}
/// <summary>A3: 设备数据同步</summary>
/// <summary>A3: 设备数据同步(字段分治 + parentSourceId映射</summary>
[HttpPost]
[Route("/api/gateway/sync/devices")]
public async Task<IActionResult> SyncDevices([FromBody] SyncDevicesRequest req)
@@ -114,10 +128,71 @@ namespace Warehouse.Controllers
.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)
{
// delegate to base_device service
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 });
}
@@ -131,22 +206,36 @@ namespace Warehouse.Controllers
.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 = null, // resolved later
DeviceId = deviceId > 0 ? deviceId : null,
AdapterCode = a.AdapterCode,
AlarmLevel = a.Level,
AlarmDesc = a.Desc,
AlarmValue = a.Value,
StartTime = DateTime.Parse(a.StartTime),
StartTime = DateTime.TryParse(a.StartTime, out var st) ? st : DateTime.Now,
State = "未确认",
CreateDate = DateTime.Now
};
await _service.ServiceProvider.GetService<IIoT_AlarmService>()?.AddAsync(alarm);
await _alarmService.AddAsync(alarm);
added++;
}
return Ok(new { added });

View File

@@ -0,0 +1,21 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*如果要增加方法请在当前目录下Partial文件夹base_deviceController编写
*/
using Microsoft.AspNetCore.Mvc;
using VolPro.Core.Controllers.Basic;
using VolPro.Entity.AttributeManager;
using Warehouse.IServices;
namespace Warehouse.Controllers
{
[Route("api/base_device")]
[PermissionTable(Name = "base_device")]
public partial class base_deviceController : ApiBaseController<Ibase_deviceService>
{
public base_deviceController(Ibase_deviceService service)
: base(service)
{
}
}
}

View File

@@ -0,0 +1,21 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*如果要增加方法请在当前目录下Partial文件夹gateway_nodesController编写
*/
using Microsoft.AspNetCore.Mvc;
using VolPro.Core.Controllers.Basic;
using VolPro.Entity.AttributeManager;
using Warehouse.IServices;
namespace Warehouse.Controllers
{
[Route("api/gateway_nodes")]
[PermissionTable(Name = "gateway_nodes")]
public partial class gateway_nodesController : ApiBaseController<Igateway_nodesService>
{
public gateway_nodesController(Igateway_nodesService service)
: base(service)
{
}
}
}

View File

@@ -0,0 +1,21 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*如果要增加方法请在当前目录下Partial文件夹iot_alarmController编写
*/
using Microsoft.AspNetCore.Mvc;
using VolPro.Core.Controllers.Basic;
using VolPro.Entity.AttributeManager;
using Warehouse.IServices;
namespace Warehouse.Controllers
{
[Route("api/iot_alarm")]
[PermissionTable(Name = "iot_alarm")]
public partial class iot_alarmController : ApiBaseController<Iiot_alarmService>
{
public iot_alarmController(Iiot_alarmService service)
: base(service)
{
}
}
}

View File

@@ -0,0 +1,21 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*如果要增加方法请在当前目录下Partial文件夹iot_devicedataController编写
*/
using Microsoft.AspNetCore.Mvc;
using VolPro.Core.Controllers.Basic;
using VolPro.Entity.AttributeManager;
using Warehouse.IServices;
namespace Warehouse.Controllers
{
[Route("api/iot_devicedata")]
[PermissionTable(Name = "iot_devicedata")]
public partial class iot_devicedataController : ApiBaseController<Iiot_devicedataService>
{
public iot_devicedataController(Iiot_devicedataService service)
: base(service)
{
}
}
}

View File

@@ -0,0 +1,21 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*如果要增加方法请在当前目录下Partial文件夹video_channelController编写
*/
using Microsoft.AspNetCore.Mvc;
using VolPro.Core.Controllers.Basic;
using VolPro.Entity.AttributeManager;
using Warehouse.IServices;
namespace Warehouse.Controllers
{
[Route("api/video_channel")]
[PermissionTable(Name = "video_channel")]
public partial class video_channelController : ApiBaseController<Ivideo_channelService>
{
public video_channelController(Ivideo_channelService service)
: base(service)
{
}
}
}

View File

@@ -0,0 +1,21 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*如果要增加方法请在当前目录下Partial文件夹video_recordController编写
*/
using Microsoft.AspNetCore.Mvc;
using VolPro.Core.Controllers.Basic;
using VolPro.Entity.AttributeManager;
using Warehouse.IServices;
namespace Warehouse.Controllers
{
[Route("api/video_record")]
[PermissionTable(Name = "video_record")]
public partial class video_recordController : ApiBaseController<Ivideo_recordService>
{
public video_recordController(Ivideo_recordService service)
: base(service)
{
}
}
}

View File

@@ -0,0 +1,18 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*Repository提供数据库操作如果要增加数据库操作请在当前目录下Partial文件夹Ibase_deviceRepository编写接口
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VolPro.Core.BaseProvider;
using VolPro.Entity.DomainModels;
using VolPro.Core.Extensions.AutofacManager;
namespace Warehouse.IRepositories
{
public partial interface Ibase_deviceRepository : IDependency,IRepository<base_device>
{
}
}

View File

@@ -0,0 +1,18 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*Repository提供数据库操作如果要增加数据库操作请在当前目录下Partial文件夹Igateway_nodesRepository编写接口
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VolPro.Core.BaseProvider;
using VolPro.Entity.DomainModels;
using VolPro.Core.Extensions.AutofacManager;
namespace Warehouse.IRepositories
{
public partial interface Igateway_nodesRepository : IDependency,IRepository<gateway_nodes>
{
}
}

View File

@@ -0,0 +1,18 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*Repository提供数据库操作如果要增加数据库操作请在当前目录下Partial文件夹Iiot_alarmRepository编写接口
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VolPro.Core.BaseProvider;
using VolPro.Entity.DomainModels;
using VolPro.Core.Extensions.AutofacManager;
namespace Warehouse.IRepositories
{
public partial interface Iiot_alarmRepository : IDependency,IRepository<iot_alarm>
{
}
}

View File

@@ -0,0 +1,18 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*Repository提供数据库操作如果要增加数据库操作请在当前目录下Partial文件夹Iiot_devicedataRepository编写接口
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VolPro.Core.BaseProvider;
using VolPro.Entity.DomainModels;
using VolPro.Core.Extensions.AutofacManager;
namespace Warehouse.IRepositories
{
public partial interface Iiot_devicedataRepository : IDependency,IRepository<iot_devicedata>
{
}
}

View File

@@ -0,0 +1,18 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*Repository提供数据库操作如果要增加数据库操作请在当前目录下Partial文件夹Ivideo_channelRepository编写接口
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VolPro.Core.BaseProvider;
using VolPro.Entity.DomainModels;
using VolPro.Core.Extensions.AutofacManager;
namespace Warehouse.IRepositories
{
public partial interface Ivideo_channelRepository : IDependency,IRepository<video_channel>
{
}
}

View File

@@ -0,0 +1,18 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*Repository提供数据库操作如果要增加数据库操作请在当前目录下Partial文件夹Ivideo_recordRepository编写接口
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VolPro.Core.BaseProvider;
using VolPro.Entity.DomainModels;
using VolPro.Core.Extensions.AutofacManager;
namespace Warehouse.IRepositories
{
public partial interface Ivideo_recordRepository : IDependency,IRepository<video_record>
{
}
}

View File

@@ -0,0 +1,12 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*/
using VolPro.Core.BaseProvider;
using VolPro.Entity.DomainModels;
namespace Warehouse.IServices
{
public partial interface Ibase_deviceService : IService<base_device>
{
}
}

View File

@@ -0,0 +1,12 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*/
using VolPro.Core.BaseProvider;
using VolPro.Entity.DomainModels;
namespace Warehouse.IServices
{
public partial interface Igateway_nodesService : IService<gateway_nodes>
{
}
}

View File

@@ -0,0 +1,12 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*/
using VolPro.Core.BaseProvider;
using VolPro.Entity.DomainModels;
namespace Warehouse.IServices
{
public partial interface Iiot_alarmService : IService<iot_alarm>
{
}
}

View File

@@ -0,0 +1,12 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*/
using VolPro.Core.BaseProvider;
using VolPro.Entity.DomainModels;
namespace Warehouse.IServices
{
public partial interface Iiot_devicedataService : IService<iot_devicedata>
{
}
}

View File

@@ -0,0 +1,12 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*/
using VolPro.Core.BaseProvider;
using VolPro.Entity.DomainModels;
namespace Warehouse.IServices
{
public partial interface Ivideo_channelService : IService<video_channel>
{
}
}

View File

@@ -0,0 +1,12 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*/
using VolPro.Core.BaseProvider;
using VolPro.Entity.DomainModels;
namespace Warehouse.IServices
{
public partial interface Ivideo_recordService : IService<video_record>
{
}
}

View File

@@ -0,0 +1,13 @@
/*
*所有关于base_device类的业务代码接口应在此处编写
*/
using VolPro.Core.BaseProvider;
using VolPro.Entity.DomainModels;
using VolPro.Core.Utilities;
using System.Linq.Expressions;
namespace Warehouse.IServices
{
public partial interface Ibase_deviceService
{
}
}

View File

@@ -0,0 +1,13 @@
/*
*所有关于gateway_nodes类的业务代码接口应在此处编写
*/
using VolPro.Core.BaseProvider;
using VolPro.Entity.DomainModels;
using VolPro.Core.Utilities;
using System.Linq.Expressions;
namespace Warehouse.IServices
{
public partial interface Igateway_nodesService
{
}
}

View File

@@ -0,0 +1,13 @@
/*
*所有关于iot_alarm类的业务代码接口应在此处编写
*/
using VolPro.Core.BaseProvider;
using VolPro.Entity.DomainModels;
using VolPro.Core.Utilities;
using System.Linq.Expressions;
namespace Warehouse.IServices
{
public partial interface Iiot_alarmService
{
}
}

View File

@@ -0,0 +1,13 @@
/*
*所有关于iot_devicedata类的业务代码接口应在此处编写
*/
using VolPro.Core.BaseProvider;
using VolPro.Entity.DomainModels;
using VolPro.Core.Utilities;
using System.Linq.Expressions;
namespace Warehouse.IServices
{
public partial interface Iiot_devicedataService
{
}
}

View File

@@ -0,0 +1,13 @@
/*
*所有关于video_channel类的业务代码接口应在此处编写
*/
using VolPro.Core.BaseProvider;
using VolPro.Entity.DomainModels;
using VolPro.Core.Utilities;
using System.Linq.Expressions;
namespace Warehouse.IServices
{
public partial interface Ivideo_channelService
{
}
}

View File

@@ -0,0 +1,13 @@
/*
*所有关于video_record类的业务代码接口应在此处编写
*/
using VolPro.Core.BaseProvider;
using VolPro.Entity.DomainModels;
using VolPro.Core.Utilities;
using System.Linq.Expressions;
namespace Warehouse.IServices
{
public partial interface Ivideo_recordService
{
}
}

View File

@@ -0,0 +1,24 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*Repository提供数据库操作如果要增加数据库操作请在当前目录下Partial文件夹base_deviceRepository编写代码
*/
using Warehouse.IRepositories;
using VolPro.Core.BaseProvider;
using VolPro.Core.EFDbContext;
using VolPro.Core.Extensions.AutofacManager;
using VolPro.Entity.DomainModels;
namespace Warehouse.Repositories
{
public partial class base_deviceRepository : RepositoryBase<base_device> , Ibase_deviceRepository
{
public base_deviceRepository(ServiceDbContext dbContext)
: base(dbContext)
{
}
public static Ibase_deviceRepository Instance
{
get { return AutofacContainerModule.GetService<Ibase_deviceRepository>(); } }
}
}

View File

@@ -0,0 +1,24 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*Repository提供数据库操作如果要增加数据库操作请在当前目录下Partial文件夹gateway_nodesRepository编写代码
*/
using Warehouse.IRepositories;
using VolPro.Core.BaseProvider;
using VolPro.Core.EFDbContext;
using VolPro.Core.Extensions.AutofacManager;
using VolPro.Entity.DomainModels;
namespace Warehouse.Repositories
{
public partial class gateway_nodesRepository : RepositoryBase<gateway_nodes> , Igateway_nodesRepository
{
public gateway_nodesRepository(ServiceDbContext dbContext)
: base(dbContext)
{
}
public static Igateway_nodesRepository Instance
{
get { return AutofacContainerModule.GetService<Igateway_nodesRepository>(); } }
}
}

View File

@@ -0,0 +1,24 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*Repository提供数据库操作如果要增加数据库操作请在当前目录下Partial文件夹iot_alarmRepository编写代码
*/
using Warehouse.IRepositories;
using VolPro.Core.BaseProvider;
using VolPro.Core.EFDbContext;
using VolPro.Core.Extensions.AutofacManager;
using VolPro.Entity.DomainModels;
namespace Warehouse.Repositories
{
public partial class iot_alarmRepository : RepositoryBase<iot_alarm> , Iiot_alarmRepository
{
public iot_alarmRepository(ServiceDbContext dbContext)
: base(dbContext)
{
}
public static Iiot_alarmRepository Instance
{
get { return AutofacContainerModule.GetService<Iiot_alarmRepository>(); } }
}
}

View File

@@ -0,0 +1,24 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*Repository提供数据库操作如果要增加数据库操作请在当前目录下Partial文件夹iot_devicedataRepository编写代码
*/
using Warehouse.IRepositories;
using VolPro.Core.BaseProvider;
using VolPro.Core.EFDbContext;
using VolPro.Core.Extensions.AutofacManager;
using VolPro.Entity.DomainModels;
namespace Warehouse.Repositories
{
public partial class iot_devicedataRepository : RepositoryBase<iot_devicedata> , Iiot_devicedataRepository
{
public iot_devicedataRepository(ServiceDbContext dbContext)
: base(dbContext)
{
}
public static Iiot_devicedataRepository Instance
{
get { return AutofacContainerModule.GetService<Iiot_devicedataRepository>(); } }
}
}

View File

@@ -0,0 +1,24 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*Repository提供数据库操作如果要增加数据库操作请在当前目录下Partial文件夹video_channelRepository编写代码
*/
using Warehouse.IRepositories;
using VolPro.Core.BaseProvider;
using VolPro.Core.EFDbContext;
using VolPro.Core.Extensions.AutofacManager;
using VolPro.Entity.DomainModels;
namespace Warehouse.Repositories
{
public partial class video_channelRepository : RepositoryBase<video_channel> , Ivideo_channelRepository
{
public video_channelRepository(ServiceDbContext dbContext)
: base(dbContext)
{
}
public static Ivideo_channelRepository Instance
{
get { return AutofacContainerModule.GetService<Ivideo_channelRepository>(); } }
}
}

View File

@@ -0,0 +1,24 @@
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*Repository提供数据库操作如果要增加数据库操作请在当前目录下Partial文件夹video_recordRepository编写代码
*/
using Warehouse.IRepositories;
using VolPro.Core.BaseProvider;
using VolPro.Core.EFDbContext;
using VolPro.Core.Extensions.AutofacManager;
using VolPro.Entity.DomainModels;
namespace Warehouse.Repositories
{
public partial class video_recordRepository : RepositoryBase<video_record> , Ivideo_recordRepository
{
public video_recordRepository(ServiceDbContext dbContext)
: base(dbContext)
{
}
public static Ivideo_recordRepository Instance
{
get { return AutofacContainerModule.GetService<Ivideo_recordRepository>(); } }
}
}

View File

@@ -0,0 +1,163 @@
using Microsoft.Extensions.DependencyInjection;
using VolPro.Entity.DomainModels;
using Warehouse.IServices;
namespace VolPro.Warehouse.Services;
/// <summary>
/// MC4.0 同步引擎:对象树 → 区域匹配 + 设备 Upsert
/// </summary>
public class SyncEngine
{
private readonly IServiceProvider _sp;
public SyncEngine(IServiceProvider sp) => _sp = sp;
private Iwarehouse_regionsService GetRegionService() =>
_sp.GetService<Iwarehouse_regionsService>()!;
private Iwarehouse_devicepointService GetPointService() =>
_sp.GetService<Iwarehouse_devicepointService>()!;
private Ibase_deviceService GetDeviceService() =>
_sp.GetService<Ibase_deviceService>()!;
/// <summary>处理 MC4.0 对象树,匹配区域并 Upsert 设备</summary>
public async Task<SyncStats> ProcessMc4TreeAsync(
int gatewayNodeId, string adapterCode, List<Mc4TreeNode> 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<int> 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<int> 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<int, int> DeviceIds { get; set; } = new();
}
/// <summary>简化的 MC4 树节点网关→Vol.Pro 传输用)</summary>
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<string, object?>? Option { get; set; }
public List<Mc4TreeNode> Children { get; set; } = new();
}