using Microsoft.AspNetCore.Mvc;
using MiniExcelLibs;
using ZR.Model.Business.Dto;
using ZR.Service.Business.IBusinessService;
//创建时间:2025-09-21
namespace ZR.Admin.WebApi.Controllers.Business
{
///
/// 干线故障管理
///
[Route("business/OdfCableFaults")]
public class OdfCableFaultsController : BaseController
{
///
/// 干线故障接口
///
private readonly IOdfCableFaultsService _OdfCableFaultsService;
public OdfCableFaultsController(IOdfCableFaultsService OdfCableFaultsService)
{
_OdfCableFaultsService = OdfCableFaultsService;
}
///
/// 故障列表分页查询
///
///
///
[HttpGet("list")]
[ActionPermissionFilter(Permission = "odfcablefaults:list")]
public IActionResult GetList([FromQuery] OdfCableFaultsQueryDto parm)
{
var response = _OdfCableFaultsService.GetList(parm);
return SUCCESS(response);
}
///
/// 故障详情(含图片)
///
///
///
[HttpGet("{id}")]
[ActionPermissionFilter(Permission = "odfcablefaults:query")]
public IActionResult GetDetail(int id)
{
var response = _OdfCableFaultsService.GetDetail(id);
return SUCCESS(response);
}
///
/// 新增故障(图片已上传至COS,提交COS URL)
///
///
[HttpPost("add")]
[ActionPermissionFilter(Permission = "odfcablefaults:add")]
[Log(Title = "干线故障", BusinessType = BusinessType.INSERT)]
public async Task Add([FromBody] OdfCableFaultAddDto dto)
{
dto.UserId = HttpContext.GetUId();
var response = await _OdfCableFaultsService.AddFault(dto);
return ToResponse(response);
}
///
/// 增加故障频次
///
[HttpPost("incrementFaultCount/{id}")]
[ActionPermissionFilter(Permission = "odfcablefaults:edit")]
[Log(Title = "干线故障", BusinessType = BusinessType.UPDATE)]
public IActionResult IncrementFaultCount(int id)
{
var response = _OdfCableFaultsService.IncrementFaultCount(id);
return SUCCESS(response);
}
///
/// 更新表显里程矫正
///
[HttpPost("updateMileageCorrection/{id}")]
[ActionPermissionFilter(Permission = "odfcablefaults:edit")]
[Log(Title = "干线故障", BusinessType = BusinessType.UPDATE)]
public IActionResult UpdateMileageCorrection(int id, [FromBody] MileageCorrectionDto dto)
{
var response = _OdfCableFaultsService.UpdateMileageCorrection(id, dto.MileageCorrection);
return ToResponse(response);
}
///
/// 删除故障并级联删除图片(支持单个/批量)
///
///
[HttpPost("delete/{ids}")]
[ActionPermissionFilter(Permission = "odfcablefaults:delete")]
[Log(Title = "干线故障", BusinessType = BusinessType.DELETE)]
public IActionResult Delete(string ids)
{
var idList = ids.Split(',', StringSplitOptions.RemoveEmptyEntries)
.Select(s => int.TryParse(s.Trim(), out var v) ? v : 0)
.Where(v => v > 0)
.ToList();
if (idList.Count == 0)
{
return ToResponse(ResultCode.FAIL, "请选择要删除的数据");
}
int total = 0;
foreach (var id in idList)
{
total += _OdfCableFaultsService.Delete(id);
}
return ToResponse(total);
}
///
/// 导出故障列表
///
///
[Log(Title = "干线故障", BusinessType = BusinessType.EXPORT, IsSaveResponseData = false)]
[HttpGet("export")]
[ActionPermissionFilter(Permission = "odfcablefaults:export")]
public IActionResult Export([FromQuery] OdfCableFaultsQueryDto parm)
{
var list = _OdfCableFaultsService.ExportList(parm);
if (list == null || list.Count <= 0)
{
return ToResponse(ResultCode.FAIL, "没有要导出的数据");
}
// 批量查询频次时间记录
var faultIds = list.Select(item => item.Id).ToList();
var allFaultTimes = _OdfCableFaultsService.GetFaultTimesByFaultIds(faultIds);
// 填充计算字段
foreach (var item in list)
{
// 拼接所有故障时间(首次 + 增加的频次时间)
var times = new List();
times.Add(item.FaultTime.ToString("yyyy-MM-dd HH:mm:ss"));
if (allFaultTimes.ContainsKey(item.Id))
{
times.AddRange(allFaultTimes[item.Id].Select(t => t.ToString("yyyy-MM-dd HH:mm:ss")));
}
times.Sort();
item.FaultTimesDisplay = string.Join("\n", times);
// 表显故障里程 = 原始里程 + 矫正值
item.DisplayMileage = CalcDisplayMileage(item.Mileage, item.MileageCorrection);
}
var result = ExportExcelMini(list, "故障列表", "故障列表");
return ExportExcel(result.Item2, result.Item1);
}
///
/// 批量导入故障
///
[HttpPost("importData")]
[Log(Title = "干线故障导入", BusinessType = BusinessType.IMPORT, IsSaveRequestData = false)]
[ActionPermissionFilter(Permission = "odfcablefaults:import")]
public IActionResult ImportData([FromForm(Name = "file")] IFormFile formFile)
{
if (formFile == null || formFile.Length <= 0)
{
return ToResponse(ResultCode.FAIL, "请选择要导入的文件");
}
var logger = NLog.LogManager.GetCurrentClassLogger();
List list = new();
using (var stream = formFile.OpenReadStream())
{
// 使用动态查询读取原始数据,避免MiniExcel强类型映射丢失单元格内多行文本
var rows = stream.Query(useHeaderRow: true, startCell: "A1").ToList();
logger.Info($"[导入调试] 共读取到 {rows.Count} 行数据");
int rowIndex = 0;
foreach (var row in rows)
{
rowIndex++;
var dict = (IDictionary)row;
// 打印所有列名和值,用于调试
foreach (var kv in dict)
{
var valType = kv.Value?.GetType()?.Name ?? "null";
var valStr = kv.Value?.ToString() ?? "(null)";
// 转义换行符以便在日志中可见
var valEscaped = valStr.Replace("\r", "\\r").Replace("\n", "\\n");
logger.Info($"[导入调试] 行{rowIndex} 列[{kv.Key}] 类型={valType} 值=[{valEscaped}]");
}
var dto = new OdfCableFaultImportDto();
if (dict.TryGetValue("编号", out var idVal) && idVal != null && int.TryParse(idVal.ToString(), out var id))
dto.Id = id;
if (dict.TryGetValue("光缆编号", out var cableIdVal) && cableIdVal != null && int.TryParse(cableIdVal.ToString(), out var cableId))
dto.CableId = cableId;
// 故障时间:保留原始文本,支持单元格内多行时间
if (dict.TryGetValue("故障时间", out var ftVal) && ftVal != null)
{
if (ftVal is DateTime dt)
{
dto.FaultTime = dt.ToString("yyyy-MM-dd HH:mm:ss");
logger.Info($"[导入调试] 行{rowIndex} 故障时间是DateTime类型,值={dt:yyyy-MM-dd HH:mm:ss}");
}
else
{
dto.FaultTime = ftVal.ToString();
var escaped = dto.FaultTime.Replace("\r", "\\r").Replace("\n", "\\n");
logger.Info($"[导入调试] 行{rowIndex} 故障时间是{ftVal.GetType().Name}类型,值=[{escaped}]");
}
}
else
{
logger.Info($"[导入调试] 行{rowIndex} 未找到故障时间列");
}
if (dict.TryGetValue("故障发生频次", out var fcVal) && fcVal != null && int.TryParse(fcVal.ToString(), out var fc))
dto.FaultCount = fc;
if (dict.TryGetValue("人员", out var pVal) && pVal != null)
dto.Personnel = pVal.ToString();
if (dict.TryGetValue("故障原因", out var frVal) && frVal != null)
dto.FaultReason = frVal.ToString();
if (dict.TryGetValue("表显故障里程", out var mVal) && mVal != null)
dto.Mileage = mVal.ToString();
if (dict.TryGetValue("表显里程矫正", out var mcVal) && mcVal != null)
dto.MileageCorrection = mcVal.ToString();
if (dict.TryGetValue("地点", out var locVal) && locVal != null)
dto.Location = locVal.ToString();
if (dict.TryGetValue("纬度", out var latVal) && latVal != null && decimal.TryParse(latVal.ToString(), out var lat))
dto.Latitude = lat;
if (dict.TryGetValue("经度", out var lngVal) && lngVal != null && decimal.TryParse(lngVal.ToString(), out var lng))
dto.Longitude = lng;
if (dict.TryGetValue("备注", out var rmkVal) && rmkVal != null)
dto.Remark = rmkVal.ToString();
if (dict.TryGetValue("创建时间", out var caVal) && caVal != null && DateTime.TryParse(caVal.ToString(), out var ca))
dto.CreatedAt = ca;
if (dict.TryGetValue("所属光缆", out var cnVal) && cnVal != null)
dto.CableName = cnVal.ToString();
list.Add(dto);
}
}
if (list.Count <= 0)
{
return ToResponse(ResultCode.FAIL, "导入数据为空");
}
var (successCount, errorCount, errorMsg) = _OdfCableFaultsService.ImportFaults(list);
var msg = $"导入成功{successCount}条,失败{errorCount}条";
if (!string.IsNullOrEmpty(errorMsg))
{
msg += $"。{errorMsg}";
}
return SUCCESS(msg);
}
///
/// 干线故障导入模板下载
///
[HttpGet("importTemplate")]
[Log(Title = "干线故障模板", BusinessType = BusinessType.EXPORT, IsSaveResponseData = false)]
[AllowAnonymous]
public IActionResult ImportTemplateExcel()
{
var result = DownloadImportTemplate(new List() { }, "OdfCableFaults");
return ExportExcel(result.Item2, result.Item1);
}
///
/// 计算表显故障里程(自动加上表显里程矫正)
///
private static string CalcDisplayMileage(string mileage, string mileageCorrection)
{
if (decimal.TryParse(mileage, out var m) && decimal.TryParse(mileageCorrection, out var c))
{
return (m + c).ToString();
}
return mileage ?? "";
}
}
}