odf_new/server/ZR.Service/Business/OdfCableFaultsService.cs
zpc 3da6b38d8e
All checks were successful
continuous-integration/drone/push Build is passing
21
2026-04-04 00:01:36 +08:00

443 lines
16 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
{
/// <summary>
/// 干线故障Service业务层处理
/// </summary>
[AppService(ServiceType = typeof(IOdfCableFaultsService), ServiceLifetime = LifeTime.Transient)]
public class OdfCableFaultsService : BaseService<OdfCableFaults>, IOdfCableFaultsService
{
/// <summary>
/// 按 CableId 分页查询故障列表,联查光缆名称,按 FaultTime DESC 排序
/// </summary>
public PagedInfo<dynamic> GetList(OdfCableFaultsQueryDto parm)
{
var predicate = QueryExp(parm);
var total = 0;
var list = Queryable()
.Where(predicate.ToExpression())
.LeftJoin<OdfCables>((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,
f.FaultCount,
CableName = c.CableName
})
.MergeTable()
.OrderByDescending(it => it.FaultTime)
.ToPageList(parm.PageNum, parm.PageSize, ref total);
// 批量查询频次时间记录
var faultIds = list.Select(x => x.Id).ToList();
var allFaultTimes = GetFaultTimesByFaultIds(faultIds);
var resultList = list.Select(item =>
{
var times = new List<string>();
if (allFaultTimes.ContainsKey(item.Id))
{
times = allFaultTimes[item.Id].Select(t => t.ToString("yyyy-MM-dd HH:mm:ss")).ToList();
}
return new
{
item.Id,
item.CableId,
item.FaultTime,
item.Personnel,
item.FaultReason,
item.Mileage,
item.MileageCorrection,
item.Location,
item.Latitude,
item.Longitude,
item.Remark,
item.CreatedAt,
item.FaultCount,
item.CableName,
FaultTimes = times
};
}).ToList();
return new PagedInfo<dynamic>
{
Result = resultList.Cast<dynamic>().ToList(),
TotalNum = total,
PageIndex = parm.PageNum,
PageSize = parm.PageSize
};
}
/// <summary>
/// 查询故障详情,联查光缆名称和图片列表
/// </summary>
public object GetDetail(int id)
{
var fault = Queryable()
.LeftJoin<OdfCables>((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<OdfCableFaultImages>()
.Where(img => img.FaultId == id)
.OrderBy(img => img.Id)
.Select(img => new { img.Id, img.ImageUrl })
.ToList();
var faultTimes = Context.Queryable<OdfCableFaultTimes>()
.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<OdfCableFaults>().Where(f => f.Id == id).First()?.FaultCount ?? 1,
FaultTimes = faultTimes,
Images = images
};
}
/// <summary>
/// 新增故障(含图片上传)
/// </summary>
public async Task<int> AddFault(OdfCableFaultAddDto dto)
{
// 校验 CableId 存在
var cable = Context.Queryable<OdfCables>()
.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;
}
/// <summary>
/// 删除故障记录并级联删除关联图片
/// </summary>
public int Delete(int id)
{
// 先删除关联图片记录
Context.Deleteable<OdfCableFaultImages>()
.Where(img => img.FaultId == id)
.ExecuteCommand();
// 再删除故障记录
return base.Delete(id);
}
/// <summary>
/// 导出故障列表
/// </summary>
public List<OdfCableFaultExportDto> ExportList(OdfCableFaultsQueryDto parm)
{
var predicate = QueryExp(parm);
return Queryable()
.Where(predicate.ToExpression())
.LeftJoin<OdfCables>((f, c) => f.CableId == c.Id)
.Select((f, c) => new OdfCableFaultExportDto
{
Id = f.Id,
CableId = f.CableId,
FaultTime = f.FaultTime,
Personnel = f.Personnel,
FaultReason = f.FaultReason,
Mileage = f.Mileage,
MileageCorrection = f.MileageCorrection,
Location = f.Location,
Latitude = f.Latitude,
Longitude = f.Longitude,
Remark = f.Remark,
CreatedAt = f.CreatedAt,
FaultCount = f.FaultCount,
CableName = c.CableName
})
.MergeTable()
.OrderByDescending(it => it.FaultTime)
.ToList();
}
/// <summary>
/// 增加故障频次FaultCount+1同时插入一条时间记录
/// </summary>
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<OdfCableFaultTimes>()
.Where(t => t.FaultId == id)
.OrderBy(t => t.FaultTime)
.Select(t => new { t.Id, t.FaultTime })
.ToList();
return new
{
FaultCount = fault.FaultCount,
FaultTimes = faultTimes
};
}
/// <summary>
/// 批量查询故障频次时间记录按故障ID分组
/// </summary>
public Dictionary<int, List<DateTime>> GetFaultTimesByFaultIds(List<int> faultIds)
{
if (faultIds == null || faultIds.Count == 0)
return new Dictionary<int, List<DateTime>>();
var records = Context.Queryable<OdfCableFaultTimes>()
.Where(t => faultIds.Contains(t.FaultId))
.OrderBy(t => t.FaultTime)
.ToList();
return records
.GroupBy(t => t.FaultId)
.ToDictionary(g => g.Key, g => g.Select(t => t.FaultTime).ToList());
}
/// <summary>
/// 查询表达式
/// </summary>
private static Expressionable<OdfCableFaults> QueryExp(OdfCableFaultsQueryDto parm)
{
var predicate = Expressionable.Create<OdfCableFaults>();
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;
}
/// <summary>
/// 批量导入故障(导出的文件可直接导入)
/// </summary>
public (int successCount, int errorCount, string errorMsg) ImportFaults(List<OdfCableFaultImportDto> list)
{
int successCount = 0;
int errorCount = 0;
var errorMsgs = new List<string>();
// 预查所有光缆用于按名称匹配CableId
var cableNames = list.Where(x => !string.IsNullOrWhiteSpace(x.CableName)).Select(x => x.CableName.Trim()).Distinct().ToList();
var cables = Context.Queryable<OdfCables>().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,
MileageCorrection = item.MileageCorrection,
Location = item.Location,
Latitude = item.Latitude ?? 0,
Longitude = item.Longitude ?? 0,
Remark = item.Remark,
FaultCount = item.FaultCount ?? 1,
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);
}
/// <summary>
/// 更新表显里程矫正
/// </summary>
public int UpdateMileageCorrection(int id, string mileageCorrection)
{
var fault = GetFirst(f => f.Id == id);
if (fault == null)
{
throw new CustomException("故障记录不存在");
}
fault.MileageCorrection = mileageCorrection;
fault.UpdatedAt = DateTime.Now;
return Update(fault, true);
}
}
}