odf_new/server/ZR.Service/Business/OdfPortsService.cs
zpc 4ac2cd85c4 feat(odf-ports): Add port side support for optical distribution frame ports
- Add PortSide property to distinguish between left (0) and right (1) sides of optical frames
- Implement row number parsing logic to handle both letter (A-C) and numeric formats
- Update port name generation to support both sides: letter format (A-1) for left side, numeric format (1-1) for right side
- Add RowNumberRaw property to capture raw input before parsing and conversion
- Add RowNumberDisplay property for display purposes while keeping RowNumber as internal numeric value
- Mark PortSide and RowNumber as ExcelIgnore to prevent export conflicts
- Clean up formatting inconsistencies in OdfPortsDto class
- Update port query logic to include PortSide in filtering criteria
- Enhance port creation to properly assign PortSide based on rack type and row format
2026-04-04 18:31:19 +08:00

412 lines
16 KiB
C#
Raw Permalink 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.Attribute;
using Infrastructure.Extensions;
using ZR.Model.Business.Dto;
using ZR.Model.Business;
using ZR.Repository;
using ZR.Service.Business.IBusinessService;
namespace ZR.Service.Business
{
/// <summary>
/// 端口Service业务层处理
/// </summary>
[AppService(ServiceType = typeof(IOdfPortsService), ServiceLifetime = LifeTime.Transient)]
public class OdfPortsService : BaseService<OdfPorts>, IOdfPortsService
{
/// <summary>
/// 查询端口列表
/// </summary>
/// <param name="parm"></param>
/// <returns></returns>
public PagedInfo<OdfPortsDto> GetList(OdfPortsQuerysDto parm)
{
var predicate = QueryExp(parm);
var response = Queryable()
//.OrderBy("Id asc")
.Where(predicate.ToExpression())
.OrderBy("RoomId asc,RackId asc,FrameId asc,RowNumber asc,PortNumber Asc")
//.OrderBy(it => it.RoomId)
//.OrderBy(it => it.RackId)
//.OrderBy(it => it.Id)
//.OrderBy(it => it.Name)
.ToPage<OdfPorts, OdfPortsDto>(parm);
return response;
}
/// <summary>
/// 查询端口列表
/// </summary>
/// <param name="parm"></param>
/// <returns></returns>
public PagedInfo<OdfPortsDto> GetList(OdfPortsQueryDto parm)
{
var predicate = QueryExp(parm);
var response = Queryable()
//.OrderBy("Id asc")
.Where(predicate.ToExpression())
.OrderBy("RoomId asc,RackId asc,FrameId asc,RowNumber asc,PortNumber Asc")
.ToPage<OdfPorts, OdfPortsDto>(parm);
return response;
}
/// <summary>
/// 获取详情
/// </summary>
/// <param name="Id"></param>
/// <returns></returns>
public OdfPorts GetInfo(int Id)
{
var response = Queryable()
.Where(x => x.Id == Id)
.First();
return response;
}
/// <summary>
/// 添加端口
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public OdfPorts AddOdfPorts(OdfPorts model)
{
return Insertable(model).ExecuteReturnEntity();
}
/// <summary>
/// 修改端口
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public int UpdateOdfPorts(OdfPorts model)
{
return Update(model, true, "修改端口");
}
/// <summary>
/// 导入端口
/// </summary>
/// <returns></returns>
public (string, object, object) ImportOdfPorts(List<OdfPorts> list)
{
var x = Context.Storageable(list)
.SplitInsert(it => !it.Any())
.SplitError(x => x.Item.Name.IsEmpty(), "端口名称不能为空")
.SplitError(x => x.Item.RoomId.IsEmpty(), "机房ID不能为空")
.SplitError(x => x.Item.RoomName.IsEmpty(), "机房名称不能为空")
.SplitError(x => x.Item.RackId.IsEmpty(), "机架ID不能为空")
.SplitError(x => x.Item.RackName.IsEmpty(), "机架名称不能为空")
.SplitError(x => x.Item.FrameId.IsEmpty(), "框ID不能为空")
.SplitError(x => x.Item.FrameName.IsEmpty(), "框名称不能为空")
.SplitError(x => x.Item.DeptId.IsEmpty(), "部门ID不能为空")
.SplitError(x => x.Item.RowNumber.IsEmpty(), "行号1-6不能为空")
.SplitError(x => x.Item.PortNumber.IsEmpty(), "端口号1-12不能为空")
.SplitError(x => x.Item.Status.IsEmpty(), "连接状态0正常1断开不能为空")
.SplitError(x => x.Item.CreatedAt.IsEmpty(), "创建时间不能为空")
.SplitError(x => x.Item.UpdatedAt.IsEmpty(), "修改时间不能为空")
//.WhereColumns(it => it.UserName)//如果不是主键可以这样实现多字段it=>new{it.x1,it.x2}
.ToStorage();
var result = x.AsInsertable.ExecuteCommand();//插入可插入部分;
string msg = $"插入{x.InsertList.Count} 更新{x.UpdateList.Count} 错误数据{x.ErrorList.Count} 不计算数据{x.IgnoreList.Count} 删除数据{x.DeleteList.Count} 总共{x.TotalList.Count}";
Console.WriteLine(msg);
//输出错误信息
foreach (var item in x.ErrorList)
{
Console.WriteLine("错误" + item.StorageMessage);
}
foreach (var item in x.IgnoreList)
{
Console.WriteLine("忽略" + item.StorageMessage);
}
return (msg, x.ErrorList, x.IgnoreList);
}
/// <summary>
/// 导出端口
/// </summary>
/// <param name="parm"></param>
/// <returns></returns>
public PagedInfo<OdfPortsfDto> ExportList(OdfPortsQueryDto parm)
{
parm.PageNum = 1;
parm.PageSize = 10000000;
var predicate = QueryExp(parm);
var response = Queryable()
.Where(predicate.ToExpression())
.OrderBy("RoomId asc,RackId asc,FrameId asc,RowNumber asc,PortSide asc,PortNumber Asc")
.Select((it) => new OdfPortsfDto()
{
}, true)
.ToPage(parm);
// 查询机架类型
var rackIds = response.Result.Select(r => r.RackId).Distinct().ToList();
var racks = Context.Queryable<OdfRacks>()
.Where(r => rackIds.Contains(r.Id))
.Select(r => new { r.Id, r.RackType })
.ToList();
var rackTypeDict = racks.ToDictionary(r => r.Id, r => r.RackType);
foreach (var item in response.Result)
{
if (rackTypeDict.TryGetValue(item.RackId, out var rackType))
{
item.RackType = rackType;
}
// 光交箱左侧行号转为字母
if (item.RackType == 1 && item.PortSide == 0)
{
item.RowNumberDisplay = ((char)(64 + item.RowNumber)).ToString();
}
else
{
item.RowNumberDisplay = item.RowNumber.ToString();
}
}
return response;
}
/// <summary>
/// 导出端口
/// </summary>
/// <param name="parm"></param>
/// <returns></returns>
public PagedInfo<OdfPortsfDto> ExportList(OdfPortsQuerysDto parm)
{
parm.PageNum = 1;
parm.PageSize = 10000000;
var predicate = QueryExp(parm);
var response = Queryable()
.Where(predicate.ToExpression())
.OrderBy("RoomId asc,RackId asc,FrameId asc,RowNumber asc,PortSide asc,PortNumber Asc")
.Select((it) => new OdfPortsfDto()
{
}, true)
.ToPage(parm);
// 查询机架类型
var rackIds = response.Result.Select(r => r.RackId).Distinct().ToList();
var racks = Context.Queryable<OdfRacks>()
.Where(r => rackIds.Contains(r.Id))
.Select(r => new { r.Id, r.RackType })
.ToList();
var rackTypeDict = racks.ToDictionary(r => r.Id, r => r.RackType);
foreach (var item in response.Result)
{
if (rackTypeDict.TryGetValue(item.RackId, out var rackType))
{
item.RackType = rackType;
}
// 光交箱左侧行号转为字母
if (item.RackType == 1 && item.PortSide == 0)
{
item.RowNumberDisplay = ((char)(64 + item.RowNumber)).ToString();
}
else
{
item.RowNumberDisplay = item.RowNumber.ToString();
}
}
return response;
}
/// <summary>
/// 导出端口(与导入模板格式一致,导出后可直接导入)
/// </summary>
/// <param name="parm"></param>
/// <returns></returns>
public PagedInfo<OdfPortsExportForImportDto> ExportListForImport(OdfPortsQueryDto parm)
{
parm.PageNum = 1;
parm.PageSize = 10000000;
parm.Sort = string.Empty; // 清除排序,避免字段不存在报错
var predicate = QueryExp(parm);
var response = Queryable()
.Where(predicate.ToExpression())
.OrderBy("RoomId asc,RackId asc,FrameId asc,RowNumber asc,PortSide asc,PortNumber Asc")
.Select((it) => new OdfPortsExportForImportDto()
{
RoomName = it.RoomName,
RackName = it.RackName,
FrameName = it.FrameName,
RowNumber = it.RowNumber,
PortNumber = it.PortNumber,
Status = it.Status,
Remarks = it.Remarks ?? "",
OpticalAttenuation = it.OpticalAttenuation ?? "",
HistoryRemarks = it.HistoryRemarks ?? "",
DeptName = it.DeptName ?? "",
OpticalCableOffRemarks = it.OpticalCableOffRemarks ?? "",
EquipmentModel = it.EquipmentModel ?? "",
BusinessType = it.BusinessType ?? "",
CreatedAt = it.CreatedAt,
UpdatedAt = it.UpdatedAt,
PortSide = it.PortSide
})
.ToPage(parm);
// 查询所有相关机架的类型信息,用于填充 RackType
var rackIds = response.Result.Select(r => r.RackName).Distinct().ToList();
var racks = Context.Queryable<OdfRacks>()
.Where(r => rackIds.Contains(r.RackName))
.Select(r => new { r.Id, r.RackName, r.RackType })
.ToList();
var rackTypeDict = racks.GroupBy(r => r.RackName)
.ToDictionary(g => g.Key, g => g.First().RackType);
// 反向解析 Remarks 字段,拆分出 业务名称、1号端口、2号端口、3号端口
foreach (var item in response.Result)
{
// 填充机架类型
if (rackTypeDict.TryGetValue(item.RackName, out var rackType))
{
item.RackType = rackType;
}
// 光交箱左侧行号转为字母 A,B,C,D...
if (item.RackType == 1 && item.PortSide == 0)
{
item.RowNumberDisplay = ((char)(64 + item.RowNumber)).ToString(); // 1->A, 2->B, 3->C...
}
else
{
item.RowNumberDisplay = item.RowNumber.ToString();
}
ParseRemarksToFields(item);
}
return response;
}
/// <summary>
/// 反向解析 Remarks 字段
/// 格式:{业务名称} {设备型号} {业务类型} {1号端口}/{2号端口}/{3号端口}
/// </summary>
private void ParseRemarksToFields(OdfPortsExportForImportDto item)
{
try
{
if (string.IsNullOrWhiteSpace(item.Remarks))
{
item.YeWuMingCheng = "";
item.One = "";
item.Two = "";
item.Three = "";
return;
}
var remarks = item.Remarks.Trim();
// 尝试按空格分割
var parts = remarks.Split(' ', StringSplitOptions.RemoveEmptyEntries);
if (parts.Length >= 1)
{
item.YeWuMingCheng = parts[0]; // 第一部分是业务名称
}
// 查找最后一个包含 "/" 的部分,那是端口信息
var lastPart = parts.Length > 0 ? parts[parts.Length - 1] : "";
if (lastPart.Contains("/"))
{
var portParts = lastPart.Split('/');
item.One = portParts.Length > 0 ? portParts[0] : "";
item.Two = portParts.Length > 1 ? portParts[1] : "";
item.Three = portParts.Length > 2 ? portParts[2] : "";
}
else
{
item.YeWuMingCheng = "";
item.One = "";
item.Two = "";
item.Three = "";
}
}
catch
{
// 解析失败,设为空
item.YeWuMingCheng = "";
item.One = "";
item.Two = "";
item.Three = "";
}
}
/// <summary>
/// 查询导出表达式
/// </summary>
/// <param name="parm"></param>
/// <returns></returns>
private static Expressionable<OdfPorts> QueryExp(OdfPortsQuerysDto parm)
{
var predicate = Expressionable.Create<OdfPorts>();
predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.RoomName), it => it.RoomName.Contains(parm.RoomName));
predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.RackName), it => it.RackName.Contains(parm.RackName));
predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.FrameName), it => it.FrameName.Contains(parm.FrameName));
predicate = predicate.AndIF(parm.Status != null, it => it.Status == parm.Status);
predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.Remarks), it => it.Remarks.Contains(parm.Remarks));
predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.OpticalAttenuation), it => it.OpticalAttenuation.Contains(parm.OpticalAttenuation));
predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.HistoryRemarks), it => it.HistoryRemarks.Contains(parm.HistoryRemarks));
if (!string.IsNullOrEmpty(parm.OpticalCableOffRemarks))
{
predicate = predicate.And(f => f.OpticalCableOffRemarks.Contains(parm.OpticalCableOffRemarks));
}
return predicate;
}
/// <summary>
/// 查询导出表达式
/// </summary>
/// <param name="parm"></param>
/// <returns></returns>
private static Expressionable<OdfPorts> QueryExp(OdfPortsQueryDto parm)
{
var predicate = Expressionable.Create<OdfPorts>();
if (parm.RoomId != null)
{
predicate = predicate.And(f => f.RoomId == parm.RoomId);
}
if (parm.RacksId != null)
{
predicate = predicate.And(f => f.RackId == parm.RacksId);
}
if (parm.FramesId != null)
{
predicate = predicate.And(f => f.FrameId == parm.FramesId);
}
if (!string.IsNullOrEmpty(parm.Name))
{
predicate = predicate.And(f => f.Name.Contains(parm.Name));
}
if (!string.IsNullOrEmpty(parm.Remarks))
{
predicate = predicate.And(f => f.Remarks.Contains(parm.Remarks));
}
if (!string.IsNullOrEmpty(parm.HistoryRemarks))
{
predicate = predicate.And(f => f.HistoryRemarks.Contains(parm.HistoryRemarks));
}
if (!string.IsNullOrEmpty(parm.OpticalCableOffRemarks))
{
predicate = predicate.And(f => f.OpticalCableOffRemarks.Contains(parm.OpticalCableOffRemarks));
}
return predicate;
}
}
}