设备类添加产品字段、添加物模型类,新增产品CRUD方法

This commit is contained in:
2026-09-03 17:16:28 +08:00
parent cfa8e78d33
commit bcd6484f45
29 changed files with 1611 additions and 23 deletions
+28
View File
@@ -0,0 +1,28 @@
namespace Model.Dto.Config
{
/// <summary>
/// 设备指令下发请求 DTO
/// </summary>
public class DeviceCommandDto
{
/// <summary>
/// 设备主键 Idstring
/// </summary>
public string Id { get; set; }
/// <summary>
/// 物模型点 Id(string,决定写哪个寄存器/线圈)
/// </summary>
public string PointId { get; set; }
/// <summary>
/// 下发的工程值
/// </summary>
public double Value { get; set; }
/// <summary>
/// 是否仅记录(模拟/离线调试:不实际发网络报文)
/// </summary>
public bool IsSimulated { get; set; }
}
}
+6
View File
@@ -19,6 +19,12 @@ namespace Model.Dto.Config
/// <summary>设备类型(型号,对应 DeviceCommand 驱动类)</summary>
public string DeviceType { get; set; }
/// <summary>所属产品Idstring0=未分类)</summary>
public string ProductId { get; set; }
/// <summary>所属产品型号/名称(只读展示)</summary>
public string? ProductName { get; set; }
/// <summary>所属网关Code</summary>
public string GatewayCode { get; set; }
+26
View File
@@ -0,0 +1,26 @@
namespace Model.Dto.Config
{
/// <summary>
/// 产品分类 DTOId 由 long 改为 string,避免前端精度丢失)
/// </summary>
public class ProductCategoryDto
{
/// <summary>主键 Idlong → string</summary>
public string Id { get; set; }
/// <summary>分类编码</summary>
public string Code { get; set; }
/// <summary>分类名称</summary>
public string? Name { get; set; }
/// <summary>排序号</summary>
public int Sort { get; set; }
/// <summary>备注</summary>
public string? Remark { get; set; }
/// <summary>创建时间</summary>
public DateTime? CreateTime { get; set; }
}
}
+46
View File
@@ -0,0 +1,46 @@
using Model.Entity.Config;
namespace Model.Dto.Config
{
/// <summary>
/// 产品 DTOId 由 long 改为 string,避免前端精度丢失)
/// </summary>
public class ProductDto
{
/// <summary>主键 Idlong → string</summary>
public string Id { get; set; }
/// <summary>型号(唯一)</summary>
public string Model { get; set; }
/// <summary>产品名称</summary>
public string? Name { get; set; }
/// <summary>产品分类Id</summary>
public string CategoryId { get; set; }
/// <summary>分类名称(只读展示)</summary>
public string? CategoryName { get; set; }
/// <summary>制造商</summary>
public string? Manufacturer { get; set; }
/// <summary>产品描述</summary>
public string? Description { get; set; }
/// <summary>通讯协议</summary>
public IotDeviceProtocolEnum ProtocolType { get; set; }
/// <summary>消息模型</summary>
public string? MessageModel { get; set; }
/// <summary>是否启用</summary>
public bool IsEnabled { get; set; } = true;
/// <summary>备注</summary>
public string? Remark { get; set; }
/// <summary>创建时间</summary>
public DateTime? CreateTime { get; set; }
}
}
+17
View File
@@ -0,0 +1,17 @@
namespace Model.Dto.Config
{
/// <summary>
/// 产品下拉选项 DTO(设备选择"所属产品"、筛选下拉用)
/// </summary>
public class ProductOptionDto
{
/// <summary>主键 Idstring</summary>
public string Id { get; set; }
/// <summary>型号</summary>
public string Model { get; set; }
/// <summary>产品名称</summary>
public string? Name { get; set; }
}
}
+58
View File
@@ -0,0 +1,58 @@
using Model.Entity.Config;
namespace Model.Dto.Config
{
/// <summary>
/// 物模型点 DTOId 由 long 改为 string,避免前端精度丢失)
/// </summary>
public class ThingModelPointDto
{
/// <summary>主键 Idlong → string</summary>
public string Id { get; set; }
/// <summary>归属类型(1=产品 2=设备)</summary>
public ThingOwnerTypeEnum OwnerType { get; set; }
/// <summary>归属对象Idstring</summary>
public string OwnerId { get; set; }
/// <summary>点编码</summary>
public string Code { get; set; }
/// <summary>点名称</summary>
public string? Name { get; set; }
/// <summary>寄存器类型</summary>
public ThingRegisterTypeEnum RegisterType { get; set; }
/// <summary>读写权限</summary>
public ThingRwEnum Rw { get; set; }
/// <summary>数据类型</summary>
public ThingDataTypeEnum DataType { get; set; }
/// <summary>寄存器起始地址</summary>
public ushort Address { get; set; }
/// <summary>换算系数</summary>
public double Scale { get; set; } = 1;
/// <summary>偏移量</summary>
public double Offset { get; set; }
/// <summary>单位</summary>
public string? Unit { get; set; }
/// <summary>是否启用</summary>
public bool Enabled { get; set; } = true;
/// <summary>排序号</summary>
public int Sort { get; set; }
/// <summary>备注</summary>
public string? Remark { get; set; }
/// <summary>创建时间</summary>
public DateTime? CreateTime { get; set; }
}
}
+9
View File
@@ -8,6 +8,15 @@ namespace Model.Dto.Inspection
/// <summary>主键 Idlong → string</summary>
public string Id { get; set; }
/// <summary>归属类型(0=全局;1=产品 2=设备)</summary>
public byte OwnerType { get; set; }
/// <summary>归属对象Id0 表示全局)</summary>
public long OwnerId { get; set; }
/// <summary>绑定点编码(空表示整产品/设备级规则)</summary>
public string PointCode { get; set; }
/// <summary>删除状态(0、未删除;1、已删除)</summary>
public byte IsDel { get; set; }
+6
View File
@@ -27,6 +27,12 @@ namespace Model.Entity.Config
[SugarColumn(ColumnDescription = "设备类型", Length = 64)]
public string DeviceType { get; set; }
/// <summary>
/// 所属产品Id(关联 ProductEntity.Id,仅用于归类,0=未分类)
/// </summary>
[SugarColumn(ColumnDescription = "所属产品Id", DefaultValue = "0")]
public long ProductId { get; set; }
/// <summary>
/// 所属网关Code(对应网关实体/通道的标识,连接时据此刻查找 IP/端口/串口)
/// </summary>
@@ -0,0 +1,34 @@
using SqlSugar;
namespace Model.Entity.Config
{
/// <summary>
/// 产品分类(字典:维护产品分类,新增产品时可设置分类)
/// </summary>
public class ProductCategoryEntity : BaseEntity
{
/// <summary>
/// 分类编码
/// </summary>
[SugarColumn(ColumnDescription = "分类编码", Length = 50)]
public string Code { get; set; }
/// <summary>
/// 分类名称
/// </summary>
[SugarColumn(ColumnDescription = "分类名称", Length = 100, IsNullable = true)]
public string? Name { get; set; }
/// <summary>
/// 排序号
/// </summary>
[SugarColumn(ColumnDescription = "排序号")]
public int Sort { get; set; }
/// <summary>
/// 备注
/// </summary>
[SugarColumn(ColumnDescription = "备注", Length = 500, IsNullable = true)]
public string? Remark { get; set; }
}
}
+64
View File
@@ -0,0 +1,64 @@
using SqlSugar;
namespace Model.Entity.Config
{
/// <summary>
/// 产品(按型号区分;产品给设备归类,产品的物模型/告警等配置与设备相互独立)
/// </summary>
public class ProductEntity : BaseEntity
{
/// <summary>
/// 型号(唯一,如 GT-100
/// </summary>
[SugarColumn(ColumnDescription = "型号", Length = 100)]
public string Model { get; set; }
/// <summary>
/// 产品名称
/// </summary>
[SugarColumn(ColumnDescription = "产品名称", Length = 100, IsNullable = true)]
public string? Name { get; set; }
/// <summary>
/// 产品分类Id(关联 ProductCategoryEntity.Id0 表示未分类)
/// </summary>
[SugarColumn(ColumnDescription = "产品分类Id")]
public long CategoryId { get; set; }
/// <summary>
/// 制造商
/// </summary>
[SugarColumn(ColumnDescription = "制造商", Length = 100, IsNullable = true)]
public string? Manufacturer { get; set; }
/// <summary>
/// 产品描述
/// </summary>
[SugarColumn(ColumnDescription = "产品描述", Length = 500, IsNullable = true)]
public string? Description { get; set; }
/// <summary>
/// 通讯协议(复用 IotDeviceProtocolEnum:决定 DeviceCommand 驱动分支)
/// </summary>
[SugarColumn(ColumnDescription = "通讯协议")]
public IotDeviceProtocolEnum ProtocolType { get; set; } = IotDeviceProtocolEnum.ModbusTcp;
/// <summary>
/// 消息模型(消息协议/报文格式描述,如 JSON / 透传)
/// </summary>
[SugarColumn(ColumnDescription = "消息模型", Length = 64, IsNullable = true)]
public string? MessageModel { get; set; }
/// <summary>
/// 是否启用
/// </summary>
[SugarColumn(ColumnDescription = "是否启用")]
public bool IsEnabled { get; set; } = true;
/// <summary>
/// 备注
/// </summary>
[SugarColumn(ColumnDescription = "备注", Length = 500, IsNullable = true)]
public string? Remark { get; set; }
}
}
+91
View File
@@ -0,0 +1,91 @@
namespace Model.Entity.Config
{
/// <summary>
/// 物模型归属类型(物模型点表 OwnerType:点挂在哪一类对象下)
/// </summary>
public enum ThingOwnerTypeEnum
{
/// <summary>
/// 产品(型号)
/// </summary>
Product = 1,
/// <summary>
/// 设备(实例)
/// </summary>
Device = 2
}
/// <summary>
/// 点读写权限(决定该点是否可用于下发指令)
/// </summary>
public enum ThingRwEnum
{
/// <summary>
/// 只读
/// </summary>
ReadOnly = 1,
/// <summary>
/// 只写
/// </summary>
WriteOnly = 2,
/// <summary>
/// 读写
/// </summary>
ReadWrite = 3
}
/// <summary>
/// 寄存器类型
/// </summary>
public enum ThingRegisterTypeEnum
{
/// <summary>
/// 线圈(读/写 bool
/// </summary>
Coil = 1,
/// <summary>
/// 保持寄存器(读/写)
/// </summary>
HoldingRegister = 2,
/// <summary>
/// 输入寄存器(只读,如 UMC1300 的温度 PV)
/// </summary>
InputRegister = 3
}
/// <summary>
/// 数据类型
/// </summary>
public enum ThingDataTypeEnum
{
/// <summary>
/// 布尔
/// </summary>
Bool = 1,
/// <summary>
/// 16位有符号整数
/// </summary>
Int16 = 2,
/// <summary>
/// 16位无符号整数
/// </summary>
UInt16 = 3,
/// <summary>
/// 32位整数(占2寄存器,暂不支持下发)
/// </summary>
Int32 = 4,
/// <summary>
/// 32位浮点(占2寄存器,暂不支持下发)
/// </summary>
Float = 5
}
}
@@ -0,0 +1,95 @@
using SqlSugar;
namespace Model.Entity.Config
{
/// <summary>
/// 物模型点(属性/指令通用表;通过 OwnerType+OwnerId 归属产品或设备)
/// 一条点 = 一个寄存器/线圈映射;可写点即"下发指令"的入口
/// </summary>
public class ThingModelPointEntity : BaseEntity
{
/// <summary>
/// 归属类型(1=产品 2=设备)
/// </summary>
[SugarColumn(ColumnDescription = "归属类型")]
public ThingOwnerTypeEnum OwnerType { get; set; }
/// <summary>
/// 归属对象IdProductEntity.Id / IotDeviceEntity.Id
/// </summary>
[SugarColumn(ColumnDescription = "归属对象Id")]
public long OwnerId { get; set; }
/// <summary>
/// 点编码(同一归属内唯一,如 TempPV)
/// </summary>
[SugarColumn(ColumnDescription = "点编码", Length = 64)]
public string Code { get; set; }
/// <summary>
/// 点名称
/// </summary>
[SugarColumn(ColumnDescription = "点名称", Length = 100, IsNullable = true)]
public string? Name { get; set; }
/// <summary>
/// 寄存器类型(线圈/保持寄存器/输入寄存器)
/// </summary>
[SugarColumn(ColumnDescription = "寄存器类型")]
public ThingRegisterTypeEnum RegisterType { get; set; }
/// <summary>
/// 读写权限
/// </summary>
[SugarColumn(ColumnDescription = "读写权限")]
public ThingRwEnum Rw { get; set; }
/// <summary>
/// 数据类型
/// </summary>
[SugarColumn(ColumnDescription = "数据类型")]
public ThingDataTypeEnum DataType { get; set; }
/// <summary>
/// 寄存器起始地址
/// </summary>
[SugarColumn(ColumnDescription = "寄存器起始地址")]
public ushort Address { get; set; }
/// <summary>
/// 换算系数(工程值 = 寄存器原始值 / Scale + Offset,对应驱动内 SCALE
/// </summary>
[SugarColumn(ColumnDescription = "换算系数", DecimalDigits = 4)]
public double Scale { get; set; } = 1;
/// <summary>
/// 偏移量
/// </summary>
[SugarColumn(ColumnDescription = "偏移量", DecimalDigits = 4)]
public double Offset { get; set; }
/// <summary>
/// 单位
/// </summary>
[SugarColumn(ColumnDescription = "单位", Length = 16, IsNullable = true)]
public string? Unit { get; set; }
/// <summary>
/// 是否启用
/// </summary>
[SugarColumn(ColumnDescription = "是否启用")]
public bool Enabled { get; set; } = true;
/// <summary>
/// 排序号
/// </summary>
[SugarColumn(ColumnDescription = "排序号")]
public int Sort { get; set; }
/// <summary>
/// 备注
/// </summary>
[SugarColumn(ColumnDescription = "备注", Length = 500, IsNullable = true)]
public string? Remark { get; set; }
}
}
@@ -8,6 +8,24 @@ namespace Model.Entity.Inspection
/// </summary>
public class AlertRuleEntity : BaseEntity
{
/// <summary>
/// 归属类型(0=全局/旧数据;1=产品 2=设备)
/// </summary>
[SugarColumn(ColumnDescription = "归属类型", DefaultValue = "0")]
public byte OwnerType { get; set; }
/// <summary>
/// 归属对象IdProductEntity.Id / IotDeviceEntity.Id0 表示全局)
/// </summary>
[SugarColumn(ColumnDescription = "归属对象Id", DefaultValue = "0")]
public long OwnerId { get; set; }
/// <summary>
/// 绑定点编码(关联物模型点 Code;为空表示整产品/设备级规则)
/// </summary>
[SugarColumn(ColumnDescription = "绑定点编码", Length = 64, IsNullable = true)]
public string? PointCode { get; set; }
/// <summary>
/// 规则名称
/// </summary>
+189
View File
@@ -255,6 +255,9 @@ namespace Model.Mapper
return new AlertRuleDto
{
Id = entity.Id.ToString(),
OwnerType = entity.OwnerType,
OwnerId = entity.OwnerId,
PointCode = entity.PointCode,
IsDel = entity.IsDel,
CreateTime = entity.CreateTime,
RuleName = entity.RuleName,
@@ -352,6 +355,9 @@ namespace Model.Mapper
return new AlertRuleEntity
{
Id = ParseId(dto.Id),
OwnerType = dto.OwnerType,
OwnerId = dto.OwnerId,
PointCode = dto.PointCode,
IsDel = dto.IsDel,
CreateTime = dto.CreateTime,
RuleName = dto.RuleName,
@@ -403,6 +409,7 @@ namespace Model.Mapper
Code = entity.Code,
Name = entity.Name,
DeviceType = entity.DeviceType,
ProductId = entity.ProductId.ToString(),
GatewayCode = entity.GatewayCode,
SlaveId = entity.SlaveId,
Manufacturer = entity.Manufacturer,
@@ -437,6 +444,7 @@ namespace Model.Mapper
Code = dto.Code,
Name = dto.Name,
DeviceType = dto.DeviceType,
ProductId = ParseId(dto.ProductId),
GatewayCode = dto.GatewayCode,
SlaveId = dto.SlaveId,
Manufacturer = dto.Manufacturer,
@@ -476,5 +484,186 @@ namespace Model.Mapper
return entities?.Select(e => e.ToDto()).ToList() ?? new List<DeviceLogDto>();
}
#endregion
#region
/// <summary>
/// ProductCategoryEntity → ProductCategoryDto
/// </summary>
public static ProductCategoryDto ToDto(this ProductCategoryEntity entity)
{
if (entity == null) return null;
return new ProductCategoryDto
{
Id = entity.Id.ToString(),
Code = entity.Code,
Name = entity.Name,
Sort = entity.Sort,
Remark = entity.Remark,
CreateTime = entity.CreateTime
};
}
/// <summary>
/// List&lt;ProductCategoryEntity&gt; → List&lt;ProductCategoryDto&gt;
/// </summary>
public static List<ProductCategoryDto> ToDtoList(this List<ProductCategoryEntity> entities)
{
return entities?.Select(e => e.ToDto()).ToList() ?? new List<ProductCategoryDto>();
}
/// <summary>
/// ProductCategoryDto → ProductCategoryEntity(入参映射)
/// </summary>
public static ProductCategoryEntity ToEntity(this ProductCategoryDto dto)
{
if (dto == null) return null;
return new ProductCategoryEntity
{
Id = ParseId(dto.Id),
Code = dto.Code,
Name = dto.Name,
Sort = dto.Sort,
Remark = dto.Remark
};
}
#endregion
#region
/// <summary>
/// ProductEntity → ProductDto
/// </summary>
public static ProductDto ToDto(this ProductEntity entity)
{
if (entity == null) return null;
return new ProductDto
{
Id = entity.Id.ToString(),
Model = entity.Model,
Name = entity.Name,
CategoryId = entity.CategoryId.ToString(),
Manufacturer = entity.Manufacturer,
Description = entity.Description,
ProtocolType = entity.ProtocolType,
MessageModel = entity.MessageModel,
IsEnabled = entity.IsEnabled,
Remark = entity.Remark,
CreateTime = entity.CreateTime
};
}
/// <summary>
/// List&lt;ProductEntity&gt; → List&lt;ProductDto&gt;
/// </summary>
public static List<ProductDto> ToDtoList(this List<ProductEntity> entities)
{
return entities?.Select(e => e.ToDto()).ToList() ?? new List<ProductDto>();
}
/// <summary>
/// ProductDto → ProductEntity(入参映射,IsDel/CreateTime 等服务端管控字段不映射)
/// </summary>
public static ProductEntity ToEntity(this ProductDto dto)
{
if (dto == null) return null;
return new ProductEntity
{
Id = ParseId(dto.Id),
Model = dto.Model,
Name = dto.Name,
CategoryId = ParseId(dto.CategoryId),
Manufacturer = dto.Manufacturer,
Description = dto.Description,
ProtocolType = dto.ProtocolType,
MessageModel = dto.MessageModel,
IsEnabled = dto.IsEnabled,
Remark = dto.Remark
};
}
/// <summary>
/// ProductEntity → ProductOptionDto(下拉选项)
/// </summary>
public static ProductOptionDto ToOptionDto(this ProductEntity entity)
{
if (entity == null) return null;
return new ProductOptionDto
{
Id = entity.Id.ToString(),
Model = entity.Model,
Name = entity.Name
};
}
/// <summary>
/// List&lt;ProductEntity&gt; → List&lt;ProductOptionDto&gt;
/// </summary>
public static List<ProductOptionDto> ToOptionDtoList(this List<ProductEntity> entities)
{
return entities?.Select(e => e.ToOptionDto()).ToList() ?? new List<ProductOptionDto>();
}
#endregion
#region
/// <summary>
/// ThingModelPointEntity → ThingModelPointDto
/// </summary>
public static ThingModelPointDto ToDto(this ThingModelPointEntity entity)
{
if (entity == null) return null;
return new ThingModelPointDto
{
Id = entity.Id.ToString(),
OwnerType = entity.OwnerType,
OwnerId = entity.OwnerId.ToString(),
Code = entity.Code,
Name = entity.Name,
RegisterType = entity.RegisterType,
Rw = entity.Rw,
DataType = entity.DataType,
Address = entity.Address,
Scale = entity.Scale,
Offset = entity.Offset,
Unit = entity.Unit,
Enabled = entity.Enabled,
Sort = entity.Sort,
Remark = entity.Remark,
CreateTime = entity.CreateTime
};
}
/// <summary>
/// List&lt;ThingModelPointEntity&gt; → List&lt;ThingModelPointDto&gt;
/// </summary>
public static List<ThingModelPointDto> ToDtoList(this List<ThingModelPointEntity> entities)
{
return entities?.Select(e => e.ToDto()).ToList() ?? new List<ThingModelPointDto>();
}
/// <summary>
/// ThingModelPointDto → ThingModelPointEntity(入参映射)
/// </summary>
public static ThingModelPointEntity ToEntity(this ThingModelPointDto dto)
{
if (dto == null) return null;
return new ThingModelPointEntity
{
Id = ParseId(dto.Id),
OwnerType = dto.OwnerType,
OwnerId = ParseId(dto.OwnerId),
Code = dto.Code,
Name = dto.Name,
RegisterType = dto.RegisterType,
Rw = dto.Rw,
DataType = dto.DataType,
Address = dto.Address,
Scale = dto.Scale,
Offset = dto.Offset,
Unit = dto.Unit,
Enabled = dto.Enabled,
Sort = dto.Sort,
Remark = dto.Remark
};
}
#endregion
}
}