设备类添加产品字段、添加物模型类,新增产品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
@@ -0,0 +1,178 @@
using DeviceCommand.Base;
using Model;
using Model.Dto.Config;
using Model.Entity.Config;
using ORM;
using Service.Interface.Config;
using SqlSugar;
using System;
using System.Net;
using System.Threading.Tasks;
namespace Service.Implement.Config
{
/// <summary>
/// 设备指令下发 服务实现
/// 目前无网关运行时/采集引擎:每次调用先落一条设备日志(始终可验证),
/// 设备在线时才实际尝试 Modbus 写(GatewayCode 需为 "ip:port",默认 127.0.0.1:502)。
/// </summary>
public class DeviceCommandService : IDeviceCommandService
{
public async Task<Result> SendCommandAsync(DeviceCommandDto dto)
{
if (dto == null || !long.TryParse(dto.Id, out var deviceId) || deviceId <= 0)
return Result.Error("设备Id无效");
if (string.IsNullOrWhiteSpace(dto.PointId) || !long.TryParse(dto.PointId, out var pointId) || pointId <= 0)
return Result.Error("物模型点Id无效");
var now = DateTime.Now;
// 载入设备与点
var device = await SqlSugarContext.DbContext.Queryable<IotDeviceEntity>()
.Where(x => x.Id == deviceId && x.IsDel == 0).FirstAsync();
if (device == null)
return Result.Error("设备不存在或已被删除");
var point = await SqlSugarContext.DbContext.Queryable<ThingModelPointEntity>()
.Where(x => x.Id == pointId && x.OwnerType == ThingOwnerTypeEnum.Device && x.OwnerId == deviceId && x.IsDel == 0).FirstAsync();
if (point == null)
return Result.Error("物模型点不存在或不属于该设备");
// 校验可写
if (point.Rw == ThingRwEnum.ReadOnly)
return Result.Error($"点【{point.Name ?? point.Code}】为只读,无法下发指令");
if (device.ProtocolType != IotDeviceProtocolEnum.ModbusTcp)
return Result.Error("当前仅支持 Modbus TCP 协议设备下发指令");
try
{
// 模拟模式 / 设备离线 → 只记录、不发网络报文
if (dto.IsSimulated || device.OnlineStatus != IotDeviceOnlineStatusEnum.Online)
{
await WriteLogAsync(device, "Warn", "指令", dto.IsSimulated
? $"【模拟】点 {point.Name ?? point.Code} 下发值 {dto.Value}(未发送网络报文)"
: $"设备离线,指令已记录但未发送(点 {point.Name ?? point.Code} 值 {dto.Value}");
return dto.IsSimulated
? Result.Success()
: Result.Error("设备离线,指令已记录但未发送");
}
// 实际 Modbus 写
var (host, port) = ParseGateway(device.GatewayCode);
using var modbus = new ModbusTcp();
modbus.ConfigureDevice(host, port, 3000, 3000);
bool connected = await modbus.ConnectAsync();
if (!connected)
{
await WriteLogAsync(device, "Error", "指令",
$"网关 {device.GatewayCode} 连接失败,指令未发送(点 {point.Name ?? point.Code} 值 {dto.Value}");
return Result.Error($"网关 {device.GatewayCode} 连接失败,指令未发送");
}
string desc;
if (point.RegisterType == ThingRegisterTypeEnum.Coil)
{
bool coil = dto.Value != 0;
await modbus.WriteSingleCoilAsync(device.SlaveId, point.Address, coil);
desc = $"写线圈 {point.Name ?? point.Code} 地址 {point.Address} = {coil}";
}
else if (point.DataType == ThingDataTypeEnum.Int32 || point.DataType == ThingDataTypeEnum.Float)
{
// 32 位类型占连续 2 个寄存器,走 FC16 连写(Int32 按有符号整数编码,Float 按 IEEE754 编码)
ushort[] words = ToWords(dto.Value, point);
await modbus.WriteMultipleRegistersAsync(device.SlaveId, point.Address, words);
desc = $"写双寄存器 {point.Name ?? point.Code} 地址 {point.Address}~{point.Address + 1} = [{words[0]}, {words[1]}](工程值 {dto.Value}";
}
else
{
ushort raw = ToRaw(dto.Value, point);
await modbus.WriteSingleRegisterAsync(device.SlaveId, point.Address, raw);
desc = $"写寄存器 {point.Name ?? point.Code} 地址 {point.Address} = {raw}(工程值 {dto.Value}";
}
await SqlSugarContext.DbContext.Updateable<IotDeviceEntity>()
.SetColumns(x => new IotDeviceEntity { LastCollectTime = now, LastError = null })
.Where(x => x.Id == device.Id).ExecuteCommandAsync();
await WriteLogAsync(device, "Info", "指令", $"下发成功:{desc}");
return Result.Success();
}
catch (Exception ex)
{
await WriteLogAsync(device, "Error", "指令", $"下发失败:{ex.Message}");
return Result.Error($"指令下发异常:{ex.Message}", ex);
}
}
/// <summary>
/// 工程值 → 寄存器原始值:raw = (value - Offset) / Scale,取整并夹到寄存器范围
/// Int16 按有符号处理(补码),其余类型按 0..65535
/// </summary>
private static ushort ToRaw(double value, ThingModelPointEntity point)
{
double raw = (value - point.Offset) / point.Scale;
if (point.DataType == ThingDataTypeEnum.Int16)
{
if (raw <= short.MinValue) return unchecked((ushort)short.MinValue);
if (raw >= short.MaxValue) return (ushort)short.MaxValue;
return unchecked((ushort)(short)Math.Round(raw));
}
if (raw <= 0) return 0;
if (raw >= 65535) return 65535;
return (ushort)Math.Round(raw);
}
/// <summary>
/// 工程值 → 32 位双寄存器字数组(raw32 = (value - Offset) / Scale
/// Int32 按有符号整数编码,Float 按 IEEE754 编码;字序按 Modbus 常规高字在前(AB CD
/// </summary>
private static ushort[] ToWords(double value, ThingModelPointEntity point)
{
uint bits;
if (point.DataType == ThingDataTypeEnum.Float)
{
bits = BitConverter.SingleToUInt32Bits((float)((value - point.Offset) / point.Scale));
}
else
{
double raw = Math.Round((value - point.Offset) / point.Scale);
if (raw < int.MinValue) raw = int.MinValue;
if (raw > int.MaxValue) raw = int.MaxValue;
bits = unchecked((uint)(int)raw);
}
return new[] { (ushort)(bits >> 16), (ushort)(bits & 0xFFFF) };
}
/// <summary>
/// 解析 GatewayCode 为 host:port;非法/缺失回退 127.0.0.1:502
/// </summary>
private static (string host, int port) ParseGateway(string? gatewayCode)
{
if (!string.IsNullOrWhiteSpace(gatewayCode))
{
var idx = gatewayCode.LastIndexOf(':');
if (idx > 0 && IPAddress.TryParse(gatewayCode[..idx], out _) && int.TryParse(gatewayCode[(idx + 1)..], out var p) && p > 0)
return (gatewayCode[..idx], p);
}
return ("127.0.0.1", 502);
}
/// <summary>
/// 写一条设备日志(设备独享日志,前端设备日志抽屉可见)
/// </summary>
private static async Task WriteLogAsync(IotDeviceEntity device, string level, string logType, string message)
{
var now = DateTime.Now;
await SqlSugarContext.DbContext.Insertable(new DeviceLogEntity
{
DeviceId = device.Id,
DeviceCode = device.Code,
Level = level,
LogType = logType,
Message = message,
LogTime = now,
CreateTime = now
}).ExecuteCommandAsync();
}
}
}
+36 -4
View File
@@ -7,6 +7,7 @@ using Service.Interface.Config;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Service.Implement.Config
@@ -17,9 +18,9 @@ namespace Service.Implement.Config
public class DeviceService : IDeviceService
{
/// <summary>
/// 分页查询设备列表(支持关键字搜索编号/名称/类型)
/// 分页查询设备列表(支持关键字搜索编号/名称/类型,可按所属产品筛选
/// </summary>
public async Task<Result<List<IotDeviceDto>>> GetPagedAsync(int pageIndex, int pageSize, RefAsync<int> total, string? keyword)
public async Task<Result<List<IotDeviceDto>>> GetPagedAsync(int pageIndex, int pageSize, RefAsync<int> total, string? keyword, long? productId = null)
{
try
{
@@ -27,10 +28,13 @@ namespace Service.Implement.Config
.Where(x => x.IsDel == 0)
.WhereIF(!string.IsNullOrWhiteSpace(keyword),
x => x.Code.Contains(keyword!) || x.Name.Contains(keyword!) || x.DeviceType.Contains(keyword!))
.WhereIF(productId.HasValue && productId.Value > 0, x => x.ProductId == productId!.Value)
.OrderBy(x => x.CreateTime, OrderByType.Desc)
.ToPageListAsync(pageIndex, pageSize, total);
return Result<List<IotDeviceDto>>.Success(list.ToDtoList());
var dtos = list.ToDtoList();
await FillProductNames(dtos);
return Result<List<IotDeviceDto>>.Success(dtos);
}
catch (Exception ex)
{
@@ -50,7 +54,10 @@ namespace Service.Implement.Config
.FirstAsync();
if (entity == null)
return Result<IotDeviceDto>.Error("设备不存在或已被删除");
return Result<IotDeviceDto>.Success(entity.ToDto());
var dto = entity.ToDto();
await FillProductNames(new List<IotDeviceDto> { dto });
return Result<IotDeviceDto>.Success(dto);
}
catch (Exception ex)
{
@@ -157,5 +164,30 @@ namespace Service.Implement.Config
return Result<List<DeviceLogDto>>.Error("查询设备日志失败", ex);
}
}
/// <summary>
/// 给设备 DTO 填充所属产品的型号/名称(ProductName 展示用)
/// </summary>
private async Task FillProductNames(List<IotDeviceDto> dtos)
{
if (dtos == null || dtos.Count == 0)
return;
var ids = dtos.Where(x => long.TryParse(x.ProductId, out var pid) && pid > 0)
.Select(x => long.Parse(x.ProductId!)).Distinct().ToList();
if (ids.Count == 0)
return;
var products = await SqlSugarContext.DbContext.Queryable<ProductEntity>()
.Where(x => ids.Contains(x.Id) && x.IsDel == 0)
.ToListAsync();
var map = products.ToDictionary(p => p.Id, p => p.Name ?? p.Model);
foreach (var d in dtos)
{
if (long.TryParse(d.ProductId, out var pid) && map.TryGetValue(pid, out var name))
d.ProductName = name;
}
}
}
}
+247 -4
View File
@@ -1,12 +1,255 @@
using Service.Interface;
using Model;
using Model.Dto.Config;
using Model.Entity.Config;
using Model.Mapper;
using ORM;
using Service.Interface.Config;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Service.Implement
namespace Service.Implement.Config
{
/// <summary>
/// 产品管理 服务实现
/// 产品管理(含产品分类)服务实现
/// </summary>
public class ProductService : IProductService
{
// TODO: 实现 产品管理 相关方法
// ===================== 产品分类 =====================
public async Task<Result<List<ProductCategoryDto>>> GetCategoriesAsync()
{
try
{
var list = await SqlSugarContext.DbContext.Queryable<ProductCategoryEntity>()
.Where(x => x.IsDel == 0)
.OrderBy(x => x.Sort)
.ToListAsync();
return Result<List<ProductCategoryDto>>.Success(list.ToDtoList());
}
catch (Exception ex)
{
return Result<List<ProductCategoryDto>>.Error("查询产品分类失败", ex);
}
}
public async Task<Result> AddCategoryAsync(ProductCategoryDto dto)
{
if (dto == null || string.IsNullOrWhiteSpace(dto.Code))
return Result.Error("分类编码不能为空");
try
{
bool exists = await SqlSugarContext.DbContext.Queryable<ProductCategoryEntity>()
.AnyAsync(x => x.Code == dto.Code && x.IsDel == 0);
if (exists)
return Result.Error($"分类编码【{dto.Code}】已存在");
var entity = dto.ToEntity();
entity.CreateTime = DateTime.Now;
await SqlSugarContext.DbContext.Insertable(entity).ExecuteCommandAsync();
return Result.Success();
}
catch (Exception ex)
{
return Result.Error("新增产品分类失败", ex);
}
}
public async Task<Result> UpdateCategoryAsync(ProductCategoryDto dto)
{
var entity = dto?.ToEntity();
if (entity == null || entity.Id <= 0)
return Result.Error("分类Id无效");
try
{
bool exists = await SqlSugarContext.DbContext.Queryable<ProductCategoryEntity>()
.AnyAsync(x => x.Code == entity.Code && x.IsDel == 0 && x.Id != entity.Id);
if (exists)
return Result.Error($"分类编码【{entity.Code}】已存在");
await SqlSugarContext.DbContext.Updateable(entity)
.IgnoreColumns(x => new { x.CreateTime, x.IsDel })
.ExecuteCommandAsync();
return Result.Success();
}
catch (Exception ex)
{
return Result.Error("修改产品分类失败", ex);
}
}
public async Task<Result> DeleteCategoryAsync(long id)
{
if (id <= 0)
return Result.Error("分类Id无效");
try
{
await SqlSugarContext.DbContext.Updateable<ProductCategoryEntity>()
.SetColumns(x => x.IsDel == 1)
.Where(x => x.Id == id)
.ExecuteCommandAsync();
return Result.Success();
}
catch (Exception ex)
{
return Result.Error("删除产品分类失败", ex);
}
}
// ===================== 产品 =====================
public async Task<Result<List<ProductDto>>> GetPagedAsync(int pageIndex, int pageSize, RefAsync<int> total, string? keyword, long categoryId)
{
try
{
var list = await SqlSugarContext.DbContext.Queryable<ProductEntity>()
.Where(x => x.IsDel == 0)
.WhereIF(!string.IsNullOrWhiteSpace(keyword),
x => x.Model.Contains(keyword!) || (x.Name != null && x.Name.Contains(keyword!)))
.WhereIF(categoryId > 0, x => x.CategoryId == categoryId)
.OrderBy(x => x.CreateTime, OrderByType.Desc)
.ToPageListAsync(pageIndex, pageSize, total);
var dtos = list.ToDtoList();
await FillCategoryNames(dtos);
return Result<List<ProductDto>>.Success(dtos);
}
catch (Exception ex)
{
return Result<List<ProductDto>>.Error("查询产品列表失败", ex);
}
}
public async Task<Result<List<ProductOptionDto>>> GetOptionsAsync()
{
try
{
var list = await SqlSugarContext.DbContext.Queryable<ProductEntity>()
.Where(x => x.IsDel == 0 && x.IsEnabled)
.OrderBy(x => x.Model)
.ToListAsync();
return Result<List<ProductOptionDto>>.Success(list.ToOptionDtoList());
}
catch (Exception ex)
{
return Result<List<ProductOptionDto>>.Error("查询产品选项失败", ex);
}
}
public async Task<Result<ProductDto>> GetByIdAsync(long id)
{
try
{
var entity = await SqlSugarContext.DbContext.Queryable<ProductEntity>()
.Where(x => x.Id == id && x.IsDel == 0)
.FirstAsync();
if (entity == null)
return Result<ProductDto>.Error("产品不存在或已被删除");
var dto = entity.ToDto();
await FillCategoryNames(new List<ProductDto> { dto });
return Result<ProductDto>.Success(dto);
}
catch (Exception ex)
{
return Result<ProductDto>.Error("查询产品详情失败", ex);
}
}
public async Task<Result> AddAsync(ProductDto dto)
{
if (dto == null || string.IsNullOrWhiteSpace(dto.Model))
return Result.Error("产品型号不能为空");
try
{
bool exists = await SqlSugarContext.DbContext.Queryable<ProductEntity>()
.AnyAsync(x => x.Model == dto.Model && x.IsDel == 0);
if (exists)
return Result.Error($"产品型号【{dto.Model}】已存在");
var entity = dto.ToEntity();
entity.CreateTime = DateTime.Now;
await SqlSugarContext.DbContext.Insertable(entity).ExecuteCommandAsync();
return Result.Success();
}
catch (Exception ex)
{
return Result.Error("新增产品失败", ex);
}
}
public async Task<Result> UpdateAsync(ProductDto dto)
{
var entity = dto?.ToEntity();
if (entity == null || entity.Id <= 0)
return Result.Error("产品Id无效");
try
{
bool exists = await SqlSugarContext.DbContext.Queryable<ProductEntity>()
.AnyAsync(x => x.Model == entity.Model && x.IsDel == 0 && x.Id != entity.Id);
if (exists)
return Result.Error($"产品型号【{entity.Model}】已存在");
await SqlSugarContext.DbContext.Updateable(entity)
.IgnoreColumns(x => new { x.CreateTime, x.IsDel })
.ExecuteCommandAsync();
return Result.Success();
}
catch (Exception ex)
{
return Result.Error("修改产品失败", ex);
}
}
public async Task<Result> DeleteAsync(long id)
{
if (id <= 0)
return Result.Error("产品Id无效");
try
{
await SqlSugarContext.DbContext.Updateable<ProductEntity>()
.SetColumns(x => x.IsDel == 1)
.Where(x => x.Id == id)
.ExecuteCommandAsync();
return Result.Success();
}
catch (Exception ex)
{
return Result.Error("删除产品失败", ex);
}
}
/// <summary>
/// 给产品 DTO 填充分类名称(供列表/详情展示)
/// </summary>
private async Task FillCategoryNames(List<ProductDto> dtos)
{
if (dtos == null || dtos.Count == 0)
return;
var ids = dtos.Where(x => x.CategoryId != null && long.TryParse(x.CategoryId, out _))
.Select(x => long.Parse(x.CategoryId!)).Distinct().ToList();
if (ids.Count == 0)
return;
var categories = await SqlSugarContext.DbContext.Queryable<ProductCategoryEntity>()
.Where(x => ids.Contains(x.Id) && x.IsDel == 0)
.ToListAsync();
var map = categories.ToDictionary(c => c.Id, c => c.Name);
foreach (var d in dtos)
{
if (long.TryParse(d.CategoryId, out var cid) && map.TryGetValue(cid, out var name))
d.CategoryName = name;
}
}
}
}
@@ -0,0 +1,126 @@
using Model;
using Model.Dto.Config;
using Model.Entity.Config;
using Model.Mapper;
using ORM;
using Service.Interface.Config;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Service.Implement.Config
{
/// <summary>
/// 物模型点 服务实现(产品/设备通用,按 OwnerType+OwnerId 归属)
/// </summary>
public class ThingPointService : IThingPointService
{
public async Task<Result<List<ThingModelPointDto>>> GetListAsync(int ownerType, long ownerId, string? keyword)
{
try
{
var list = await SqlSugarContext.DbContext.Queryable<ThingModelPointEntity>()
.Where(x => x.IsDel == 0)
.Where(x => x.OwnerType == (ThingOwnerTypeEnum)ownerType && x.OwnerId == ownerId)
.WhereIF(!string.IsNullOrWhiteSpace(keyword),
x => x.Code.Contains(keyword!) || (x.Name != null && x.Name.Contains(keyword!)))
.OrderBy(x => x.Sort)
.ToListAsync();
return Result<List<ThingModelPointDto>>.Success(list.ToDtoList());
}
catch (Exception ex)
{
return Result<List<ThingModelPointDto>>.Error("查询物模型点失败", ex);
}
}
public async Task<Result<ThingModelPointDto>> GetByIdAsync(long id)
{
try
{
var entity = await SqlSugarContext.DbContext.Queryable<ThingModelPointEntity>()
.Where(x => x.Id == id && x.IsDel == 0)
.FirstAsync();
if (entity == null)
return Result<ThingModelPointDto>.Error("物模型点不存在或已被删除");
return Result<ThingModelPointDto>.Success(entity.ToDto());
}
catch (Exception ex)
{
return Result<ThingModelPointDto>.Error("查询物模型点失败", ex);
}
}
public async Task<Result> AddAsync(ThingModelPointDto dto)
{
if (dto == null || string.IsNullOrWhiteSpace(dto.Code))
return Result.Error("点编码不能为空");
if (dto.OwnerId == null || !long.TryParse(dto.OwnerId, out var ownerId) || ownerId <= 0)
return Result.Error("归属对象Id无效");
try
{
bool exists = await SqlSugarContext.DbContext.Queryable<ThingModelPointEntity>()
.AnyAsync(x => x.OwnerType == dto.OwnerType && x.OwnerId == ownerId
&& x.Code == dto.Code && x.IsDel == 0);
if (exists)
return Result.Error($"点编码【{dto.Code}】在该归属下已存在");
var entity = dto.ToEntity();
entity.CreateTime = DateTime.Now;
await SqlSugarContext.DbContext.Insertable(entity).ExecuteCommandAsync();
return Result.Success();
}
catch (Exception ex)
{
return Result.Error("新增物模型点失败", ex);
}
}
public async Task<Result> UpdateAsync(ThingModelPointDto dto)
{
var entity = dto?.ToEntity();
if (entity == null || entity.Id <= 0)
return Result.Error("物模型点Id无效");
try
{
bool exists = await SqlSugarContext.DbContext.Queryable<ThingModelPointEntity>()
.AnyAsync(x => x.OwnerType == entity.OwnerType && x.OwnerId == entity.OwnerId
&& x.Code == entity.Code && x.IsDel == 0 && x.Id != entity.Id);
if (exists)
return Result.Error($"点编码【{entity.Code}】在该归属下已存在");
await SqlSugarContext.DbContext.Updateable(entity)
.IgnoreColumns(x => new { x.CreateTime, x.IsDel, x.OwnerType, x.OwnerId })
.ExecuteCommandAsync();
return Result.Success();
}
catch (Exception ex)
{
return Result.Error("修改物模型点失败", ex);
}
}
public async Task<Result> DeleteAsync(long id)
{
if (id <= 0)
return Result.Error("物模型点Id无效");
try
{
await SqlSugarContext.DbContext.Updateable<ThingModelPointEntity>()
.SetColumns(x => x.IsDel == 1)
.Where(x => x.Id == id)
.ExecuteCommandAsync();
return Result.Success();
}
catch (Exception ex)
{
return Result.Error("删除物模型点失败", ex);
}
}
}
}
@@ -16,14 +16,14 @@ namespace Service.Implement
public class AlertRuleService : IAlertRuleService
{
/// <summary>
/// 获取全告警规则列表
/// 获取全告警规则列表OwnerType=0,不含产品/设备归属规则)
/// </summary>
public async Task<Result<List<AlertRuleDto>>> GetListAsync()
{
try
{
var list = await SqlSugarContext.DbContext.Queryable<AlertRuleEntity>()
.Where(x => x.IsDel == 0)
.Where(x => x.IsDel == 0 && x.OwnerType == 0)
.OrderBy(x => x.CreateTime, SqlSugar.OrderByType.Desc)
.ToListAsync();
@@ -36,6 +36,27 @@ namespace Service.Implement
}
}
/// <summary>
/// 获取某归属对象下的规则列表(OwnerType=产品/设备,可选按点过滤)
/// </summary>
public async Task<Result<List<AlertRuleDto>>> GetOwnerRulesAsync(int ownerType, long ownerId, string? pointCode)
{
try
{
var list = await SqlSugarContext.DbContext.Queryable<AlertRuleEntity>()
.Where(x => x.IsDel == 0 && x.OwnerType == (byte)ownerType && x.OwnerId == ownerId)
.WhereIF(!string.IsNullOrWhiteSpace(pointCode), x => x.PointCode == pointCode)
.OrderBy(x => x.CreateTime, SqlSugar.OrderByType.Desc)
.ToListAsync();
return Result<List<AlertRuleDto>>.Success(list.ToDtoList());
}
catch (Exception ex)
{
return Result<List<AlertRuleDto>>.Error("查询归属告警规则失败", ex);
}
}
/// <summary>
/// 新增告警规则(DTO → Entitystring Id 转 long
/// </summary>
@@ -0,0 +1,18 @@
using Model;
using Model.Dto.Config;
using System.Threading.Tasks;
namespace Service.Interface.Config
{
/// <summary>
/// 设备指令下发 服务接口
/// </summary>
public interface IDeviceCommandService
{
/// <summary>
/// 按物模型可写点向设备下发指令
/// 每次调用都会写入设备日志;网关不可达时优雅降级(记录未连通)。
/// </summary>
Task<Result> SendCommandAsync(DeviceCommandDto dto);
}
}
+2 -2
View File
@@ -12,9 +12,9 @@ namespace Service.Interface.Config
public interface IDeviceService
{
/// <summary>
/// 分页查询设备列表(支持关键字搜索编号/名称/类型)
/// 分页查询设备列表(支持关键字搜索编号/名称/类型,可按所属产品筛选
/// </summary>
Task<Result<List<IotDeviceDto>>> GetPagedAsync(int pageIndex, int pageSize, RefAsync<int> total, string? keyword);
Task<Result<List<IotDeviceDto>>> GetPagedAsync(int pageIndex, int pageSize, RefAsync<int> total, string? keyword, long? productId = null);
/// <summary>
/// 根据 Id 获取设备详情
+38 -3
View File
@@ -1,10 +1,45 @@
namespace Service.Interface
using Model;
using Model.Dto.Config;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Service.Interface.Config
{
/// <summary>
/// 产品管理 服务接口
/// 产品管理(含产品分类)服务接口
/// </summary>
public interface IProductService
{
// TODO: 定义 产品管理 相关方法
// ===== 产品分类 =====
/// <summary>产品分类列表</summary>
Task<Result<List<ProductCategoryDto>>> GetCategoriesAsync();
/// <summary>新增产品分类</summary>
Task<Result> AddCategoryAsync(ProductCategoryDto dto);
/// <summary>修改产品分类</summary>
Task<Result> UpdateCategoryAsync(ProductCategoryDto dto);
/// <summary>删除产品分类(软删除)</summary>
Task<Result> DeleteCategoryAsync(long id);
// ===== 产品 =====
/// <summary>分页查询产品列表(关键字搜型号/名称;可按分类筛选)</summary>
Task<Result<List<ProductDto>>> GetPagedAsync(int pageIndex, int pageSize, SqlSugar.RefAsync<int> total, string? keyword, long categoryId);
/// <summary>下拉选项(不分页,设备选择所属产品用)</summary>
Task<Result<List<ProductOptionDto>>> GetOptionsAsync();
/// <summary>产品详情</summary>
Task<Result<ProductDto>> GetByIdAsync(long id);
/// <summary>新增产品(型号唯一校验)</summary>
Task<Result> AddAsync(ProductDto dto);
/// <summary>修改产品</summary>
Task<Result> UpdateAsync(ProductDto dto);
/// <summary>删除产品(软删除)</summary>
Task<Result> DeleteAsync(long id);
}
}
@@ -0,0 +1,28 @@
using Model;
using Model.Dto.Config;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Service.Interface.Config
{
/// <summary>
/// 物模型点 服务接口(产品/设备通用,按 OwnerType+OwnerId 归属)
/// </summary>
public interface IThingPointService
{
/// <summary>查询某归属下的点列表</summary>
Task<Result<List<ThingModelPointDto>>> GetListAsync(int ownerType, long ownerId, string? keyword);
/// <summary>查询单点详情</summary>
Task<Result<ThingModelPointDto>> GetByIdAsync(long id);
/// <summary>新增点(同一归属内 Code 唯一)</summary>
Task<Result> AddAsync(ThingModelPointDto dto);
/// <summary>修改点</summary>
Task<Result> UpdateAsync(ThingModelPointDto dto);
/// <summary>删除点(软删除)</summary>
Task<Result> DeleteAsync(long id);
}
}
@@ -1,6 +1,5 @@
using Model;
using Model.Dto.Inspection;
using Model.Entity.Inspection;
using System.Collections.Generic;
using System.Threading.Tasks;
@@ -12,10 +11,15 @@ namespace Service.Interface
public interface IAlertRuleService
{
/// <summary>
/// 获取全告警规则列表
/// 获取全告警规则列表OwnerType=0,不含产品/设备归属规则)
/// </summary>
Task<Result<List<AlertRuleDto>>> GetListAsync();
/// <summary>
/// 获取某归属对象下的规则列表(OwnerType=产品/设备,可选按点过滤)
/// </summary>
Task<Result<List<AlertRuleDto>>> GetOwnerRulesAsync(int ownerType, long ownerId, string? pointCode);
/// <summary>
/// 新增告警规则(前端传 DTOId 为 string
/// </summary>
+1
View File
@@ -13,6 +13,7 @@
<ItemGroup>
<ProjectReference Include="..\Common\Common.csproj" />
<ProjectReference Include="..\DeviceCommand\DeviceCommand.csproj" />
<ProjectReference Include="..\Logger\Logger.csproj" />
<ProjectReference Include="..\Model\Model.csproj" />
<ProjectReference Include="..\ORM\ORM.csproj" />