odf_new/server/ZR.Admin.WebApi/Controllers/Business/OdfCableFaultsController.cs
zpc 996e1abc24
Some checks reported errors
continuous-integration/drone/push Build encountered an error
21
2026-04-21 21:57:28 +08:00

410 lines
17 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 Microsoft.AspNetCore.Mvc;
using MiniExcelLibs;
using ZR.Model.Business;
using ZR.Model.Business.Dto;
using ZR.Service.Business.IBusinessService;
//创建时间2025-09-21
namespace ZR.Admin.WebApi.Controllers.Business
{
/// <summary>
/// 干线故障管理
/// </summary>
[Route("business/OdfCableFaults")]
public class OdfCableFaultsController : BaseController
{
/// <summary>
/// 干线故障接口
/// </summary>
private readonly IOdfCableFaultsService _OdfCableFaultsService;
private readonly IOdfAuditLogsService _auditLogsService;
public OdfCableFaultsController(
IOdfCableFaultsService OdfCableFaultsService,
IOdfAuditLogsService auditLogsService)
{
_OdfCableFaultsService = OdfCableFaultsService;
_auditLogsService = auditLogsService;
}
/// <summary>
/// 故障列表分页查询
/// </summary>
/// <param name="parm"></param>
/// <returns></returns>
[HttpGet("list")]
[ActionPermissionFilter(Permission = "odfcablefaults:list")]
public IActionResult GetList([FromQuery] OdfCableFaultsQueryDto parm)
{
var deptId = HttpContext.GetDeptId();
var response = _OdfCableFaultsService.GetList(parm, deptId);
return SUCCESS(response);
}
/// <summary>
/// 故障详情(含图片)
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet("{id}")]
[ActionPermissionFilter(Permission = "odfcablefaults:query")]
public IActionResult GetDetail(int id)
{
var response = _OdfCableFaultsService.GetDetail(id);
return SUCCESS(response);
}
/// <summary>
/// 新增故障图片已上传至COS提交COS URL
/// </summary>
/// <returns></returns>
[HttpPost("add")]
[ActionPermissionFilter(Permission = "odfcablefaults:add")]
[Log(Title = "干线故障", BusinessType = BusinessType.INSERT)]
public async Task<IActionResult> Add([FromBody] OdfCableFaultAddDto dto)
{
dto.UserId = HttpContext.GetUId();
var response = await _OdfCableFaultsService.AddFault(dto);
// 手动记录 INSERT 审计日志
try
{
var newRecord = _OdfCableFaultsService.GetFirst(f => f.Id == response);
string newData = BuildAuditJson(new Dictionary<string, object>
{
["Id"] = newRecord.Id,
["关联光缆ID"] = newRecord.CableId,
["故障时间"] = newRecord.FaultTime,
["人员"] = newRecord.Personnel,
["故障原因"] = newRecord.FaultReason,
["表显故障里程"] = newRecord.Mileage,
["表显里程矫正"] = newRecord.MileageCorrection,
["地点描述"] = newRecord.Location,
["纬度"] = newRecord.Latitude,
["经度"] = newRecord.Longitude,
["备注"] = newRecord.Remark,
["提交人用户ID"] = newRecord.UserId,
["创建时间"] = newRecord.CreatedAt,
["更新时间"] = newRecord.UpdatedAt,
["故障发生频次"] = newRecord.FaultCount,
});
_auditLogsService.AddLog(BuildAuditLog("odf_cable_faults", response, "INSERT", null, newData));
}
catch (Exception ex)
{
NLog.LogManager.GetCurrentClassLogger().Error(ex, "审计日志写入失败");
}
return ToResponse(response);
}
/// <summary>
/// 增加故障频次
/// </summary>
[HttpPost("incrementFaultCount/{id}")]
[ActionPermissionFilter(Permission = "odfcablefaults:edit")]
[Log(Title = "干线故障", BusinessType = BusinessType.UPDATE)]
public IActionResult IncrementFaultCount(int id)
{
// 记录旧数据
var oldFault = _OdfCableFaultsService.GetFirst(f => f.Id == id);
string oldData = BuildAuditJson(new Dictionary<string, object>
{
["故障发生频次"] = oldFault.FaultCount,
["更新时间"] = oldFault.UpdatedAt,
});
// 执行更新
var response = _OdfCableFaultsService.IncrementFaultCount(id);
// 记录新数据
var newFault = _OdfCableFaultsService.GetFirst(f => f.Id == id);
string newData = BuildAuditJson(new Dictionary<string, object>
{
["故障发生频次"] = newFault.FaultCount,
["更新时间"] = newFault.UpdatedAt,
});
// 写入审计日志
try
{
_auditLogsService.AddLog(BuildAuditLog("odf_cable_faults", id, "UPDATE", oldData, newData));
}
catch (Exception ex)
{
NLog.LogManager.GetCurrentClassLogger().Error(ex, "审计日志写入失败");
}
return SUCCESS(response);
}
/// <summary>
/// 更新表显里程矫正
/// </summary>
[HttpPost("updateMileageCorrection/{id}")]
[ActionPermissionFilter(Permission = "odfcablefaults:edit")]
[Log(Title = "干线故障", BusinessType = BusinessType.UPDATE)]
public IActionResult UpdateMileageCorrection(int id, [FromBody] MileageCorrectionDto dto)
{
// 查旧数据
var oldRecord = _OdfCableFaultsService.GetFirst(f => f.Id == id);
string oldData = BuildAuditJson(new Dictionary<string, object>
{
["表显里程矫正"] = oldRecord.MileageCorrection,
["更新时间"] = oldRecord.UpdatedAt,
});
// 执行更新
var response = _OdfCableFaultsService.UpdateMileageCorrection(id, dto.MileageCorrection);
// 查新数据
var newRecord = _OdfCableFaultsService.GetFirst(f => f.Id == id);
string newData = BuildAuditJson(new Dictionary<string, object>
{
["表显里程矫正"] = newRecord.MileageCorrection,
["更新时间"] = newRecord.UpdatedAt,
});
// 写入审计日志
try
{
_auditLogsService.AddLog(BuildAuditLog("odf_cable_faults", id, "UPDATE", oldData, newData));
}
catch (Exception ex)
{
NLog.LogManager.GetCurrentClassLogger().Error(ex, "审计日志写入失败");
}
return ToResponse(response);
}
/// <summary>
/// 删除故障并级联删除图片(支持单个/批量)
/// </summary>
/// <returns></returns>
[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, "请选择要删除的数据");
}
// 循环每条记录分别记录 DELETE 审计日志
foreach (var id in idList)
{
var oldRecord = _OdfCableFaultsService.GetFirst(f => f.Id == id);
string oldData = BuildAuditJson(new Dictionary<string, object>
{
["Id"] = oldRecord.Id,
["关联光缆ID"] = oldRecord.CableId,
["故障时间"] = oldRecord.FaultTime,
["人员"] = oldRecord.Personnel,
["故障原因"] = oldRecord.FaultReason,
["表显故障里程"] = oldRecord.Mileage,
["表显里程矫正"] = oldRecord.MileageCorrection,
["地点描述"] = oldRecord.Location,
["纬度"] = oldRecord.Latitude,
["经度"] = oldRecord.Longitude,
["备注"] = oldRecord.Remark,
["提交人用户ID"] = oldRecord.UserId,
["创建时间"] = oldRecord.CreatedAt,
["更新时间"] = oldRecord.UpdatedAt,
["故障发生频次"] = oldRecord.FaultCount,
});
try
{
_auditLogsService.AddLog(BuildAuditLog("odf_cable_faults", id, "DELETE", oldData, null));
}
catch (Exception ex)
{
NLog.LogManager.GetCurrentClassLogger().Error(ex, "审计日志写入失败");
}
}
int total = 0;
foreach (var id in idList)
{
total += _OdfCableFaultsService.Delete(id);
}
return ToResponse(total);
}
/// <summary>
/// 导出故障列表
/// </summary>
/// <returns></returns>
[Log(Title = "干线故障", BusinessType = BusinessType.EXPORT, IsSaveResponseData = false)]
[HttpGet("export")]
[ActionPermissionFilter(Permission = "odfcablefaults:export")]
public IActionResult Export([FromQuery] OdfCableFaultsQueryDto parm)
{
var deptId = HttpContext.GetDeptId();
var list = _OdfCableFaultsService.ExportList(parm, deptId);
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<string>();
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);
}
/// <summary>
/// 批量导入故障
/// </summary>
[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<OdfCableFaultImportDto> 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<string, object>)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);
}
/// <summary>
/// 干线故障导入模板下载
/// </summary>
[HttpGet("importTemplate")]
[Log(Title = "干线故障模板", BusinessType = BusinessType.EXPORT, IsSaveResponseData = false)]
[AllowAnonymous]
public IActionResult ImportTemplateExcel()
{
var result = DownloadImportTemplate(new List<OdfCableFaultImportDto>() { }, "OdfCableFaults");
return ExportExcel(result.Item2, result.Item1);
}
/// <summary>
/// 计算表显故障里程(自动加上表显里程矫正)
/// </summary>
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 ?? "";
}
}
}