设备类添加产品字段、添加物模型类,新增产品CRUD方法
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user