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);
}
}
}