using Infrastructure; using Infrastructure.Attribute; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using ZR.Model; using ZR.Model.Business; using ZR.Model.Business.Dto; using ZR.Model.Dto; using ZR.Repository; using ZR.Service.Business.IBusinessService; namespace ZR.Service.Business { /// /// 干线故障Service业务层处理 /// [AppService(ServiceType = typeof(IOdfCableFaultsService), ServiceLifetime = LifeTime.Transient)] public class OdfCableFaultsService : BaseService, IOdfCableFaultsService { /// /// 按 CableId 分页查询故障列表,联查光缆名称,按 FaultTime DESC 排序 /// public PagedInfo GetList(OdfCableFaultsQueryDto parm) { var predicate = QueryExp(parm); var total = 0; var list = Queryable() .Where(predicate.ToExpression()) .LeftJoin((f, c) => f.CableId == c.Id) .Select((f, c) => new { f.Id, f.CableId, f.FaultTime, f.Personnel, f.FaultReason, f.Mileage, f.MileageCorrection, f.Location, f.Latitude, f.Longitude, f.Remark, f.CreatedAt, CableName = c.CableName }) .MergeTable() .OrderByDescending(it => it.FaultTime) .ToPageList(parm.PageNum, parm.PageSize, ref total); return new PagedInfo { Result = list.Cast().ToList(), TotalNum = total, PageIndex = parm.PageNum, PageSize = parm.PageSize }; } /// /// 查询故障详情,联查光缆名称和图片列表 /// public object GetDetail(int id) { var fault = Queryable() .LeftJoin((f, c) => f.CableId == c.Id) .Where((f, c) => f.Id == id) .Select((f, c) => new { f.Id, f.CableId, f.FaultTime, f.Personnel, f.FaultReason, f.Mileage, f.MileageCorrection, f.Location, f.Latitude, f.Longitude, f.Remark, f.UserId, f.CreatedAt, CableName = c.CableName }) .First(); if (fault == null) { throw new CustomException("故障记录不存在"); } // 查询关联图片列表 var images = Context.Queryable() .Where(img => img.FaultId == id) .OrderBy(img => img.Id) .Select(img => new { img.Id, img.ImageUrl }) .ToList(); var faultTimes = Context.Queryable() .Where(t => t.FaultId == id) .OrderBy(t => t.FaultTime) .Select(t => new { t.Id, t.FaultTime }) .ToList(); return new { fault.Id, fault.CableId, fault.FaultTime, fault.Personnel, fault.FaultReason, fault.Mileage, fault.MileageCorrection, fault.Location, fault.Latitude, fault.Longitude, fault.Remark, fault.CableName, fault.CreatedAt, FaultCount = Context.Queryable().Where(f => f.Id == id).First()?.FaultCount ?? 1, FaultTimes = faultTimes, Images = images }; } /// /// 新增故障(含图片上传) /// public async Task AddFault(OdfCableFaultAddDto dto) { // 校验 CableId 存在 var cable = Context.Queryable() .Where(c => c.Id == dto.CableId) .First(); if (cable == null) { throw new CustomException("光缆不存在"); } // 校验至少 1 张图片 if (dto.Images == null || dto.Images.Length == 0) { throw new CustomException("请至少上传一张图片"); } // 插入故障记录 var model = new OdfCableFaults { CableId = dto.CableId, FaultTime = DateTime.Parse(dto.FaultTime), Personnel = dto.Personnel, FaultReason = dto.FaultReason, Mileage = dto.Mileage, MileageCorrection = dto.MileageCorrection, Location = dto.Location, Latitude = dto.Latitude, Longitude = dto.Longitude, Remark = dto.Remark, UserId = dto.UserId, CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now }; var faultEntity = Insertable(model).ExecuteReturnEntity(); int faultId = faultEntity.Id; // 保存图片文件并插入图片记录 IWebHostEnvironment webHostEnvironment = App.WebHostEnvironment; string webRootPath = webHostEnvironment.WebRootPath; string uploadDir = Path.Combine("uploads", "fault"); string fullDir = Path.Combine(webRootPath, uploadDir); if (!Directory.Exists(fullDir)) { Directory.CreateDirectory(fullDir); } foreach (var image in dto.Images) { string fileExt = Path.GetExtension(image.FileName); string fileName = $"{DateTime.Now:yyyyMMdd}_{Guid.NewGuid():N}{fileExt}"; string filePath = Path.Combine(fullDir, fileName); using (var stream = new FileStream(filePath, FileMode.Create)) { await image.CopyToAsync(stream); } string imageUrl = $"/{uploadDir}/{fileName}".Replace("\\", "/"); // 拼接完整URL,前端可直接使用 var request = App.HttpContext?.Request; if (request != null) { imageUrl = $"{request.Scheme}://{request.Host}{imageUrl}"; } var imageRecord = new OdfCableFaultImages { FaultId = faultId, ImageUrl = imageUrl, CreatedAt = DateTime.Now }; Context.Insertable(imageRecord).ExecuteCommand(); } return faultId; } /// /// 删除故障记录并级联删除关联图片 /// public int Delete(int id) { // 先删除关联图片记录 Context.Deleteable() .Where(img => img.FaultId == id) .ExecuteCommand(); // 再删除故障记录 return base.Delete(id); } /// /// 导出故障列表 /// public PagedInfo ExportList(OdfCableFaultsQueryDto parm) { parm.PageNum = 1; parm.PageSize = 100000; return GetList(parm); } /// /// 增加故障频次:FaultCount+1,同时插入一条时间记录 /// public object IncrementFaultCount(int id) { var fault = GetFirst(f => f.Id == id); if (fault == null) { throw new CustomException("故障记录不存在"); } fault.FaultCount += 1; fault.UpdatedAt = DateTime.Now; Update(fault, true); var now = DateTime.Now; var timeRecord = new OdfCableFaultTimes { FaultId = id, FaultTime = now, CreatedAt = now }; Context.Insertable(timeRecord).ExecuteCommand(); var faultTimes = Context.Queryable() .Where(t => t.FaultId == id) .OrderBy(t => t.FaultTime) .Select(t => new { t.Id, t.FaultTime }) .ToList(); return new { FaultCount = fault.FaultCount, FaultTimes = faultTimes }; } /// /// 查询表达式 /// private static Expressionable QueryExp(OdfCableFaultsQueryDto parm) { var predicate = Expressionable.Create(); predicate = predicate.AndIF(parm.CableId != null, it => it.CableId == parm.CableId); predicate = predicate.AndIF(parm.BeginFaultTime != null, it => it.FaultTime >= parm.BeginFaultTime); predicate = predicate.AndIF(parm.EndFaultTime != null, it => it.FaultTime <= parm.EndFaultTime); predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.FaultReason), it => it.FaultReason.Contains(parm.FaultReason)); return predicate; } /// /// 批量导入故障(导出的文件可直接导入) /// public (int successCount, int errorCount, string errorMsg) ImportFaults(List list) { int successCount = 0; int errorCount = 0; var errorMsgs = new List(); // 预查所有光缆,用于按名称匹配CableId var cableNames = list.Where(x => !string.IsNullOrWhiteSpace(x.CableName)).Select(x => x.CableName.Trim()).Distinct().ToList(); var cables = Context.Queryable().Where(c => cableNames.Contains(c.CableName)).ToList(); for (int i = 0; i < list.Count; i++) { var item = list[i]; int rowNum = i + 2; // Excel行号(第1行是表头) try { // 确定CableId:优先用光缆编号,其次按所属光缆名称匹配 int? cableId = item.CableId; if ((cableId == null || cableId == 0) && !string.IsNullOrWhiteSpace(item.CableName)) { var cable = cables.Find(c => c.CableName == item.CableName.Trim()); if (cable != null) { cableId = cable.Id; } } if (cableId == null || cableId == 0) { errorCount++; errorMsgs.Add($"第{rowNum}行:未找到匹配的光缆"); continue; } var model = new OdfCableFaults { CableId = cableId.Value, FaultTime = item.FaultTime ?? DateTime.Now, Personnel = item.Personnel, FaultReason = item.FaultReason, Mileage = item.Mileage, Location = item.Location, Latitude = item.Latitude ?? 0, Longitude = item.Longitude ?? 0, Remark = item.Remark, CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now }; Insertable(model).ExecuteCommand(); successCount++; } catch (Exception) { errorCount++; errorMsgs.Add($"第{rowNum}行:导入失败"); } } string errorMsg = errorMsgs.Count > 0 ? string.Join(";", errorMsgs.Take(10)) : ""; return (successCount, errorCount, errorMsg); } } }