feat(report): 添加互换估值列配置功能
- 引入 Newtonsoft.Json 用于列配置的序列化处理 - 实现 ApplySwapValuationColumnConfig 方法应用用户自定义列配置 - 添加 ReorderSwapValuationColumns 方法重新排序可见列 - 在每日估值报告导出时同步业务字段显示状态和列顺序 - 使用临时工作表避免 EPPlus 扩列时的 ColumnMax 冲突 - 确保列配置损坏时不影响报告导出功能
This commit is contained in:
+131
@@ -1,4 +1,5 @@
|
||||
using BaseOUDAL;
|
||||
using Newtonsoft.Json;
|
||||
using OfficeOpenXml;
|
||||
using OfficeOpenXml.Style;
|
||||
using Org.BouncyCastle.Ocsp;
|
||||
@@ -309,6 +310,7 @@ namespace YLErp.Modules.ReportModule.SettlementReportModule
|
||||
, shouldDeleteSheet: true, needToPdf: false, callback: sheets =>
|
||||
{
|
||||
FormatSwapValuationDisplayCells(sheets, report.EodSwapPositions);
|
||||
ApplySwapValuationColumnConfig(sheets);
|
||||
});
|
||||
if (needToPdf)
|
||||
{
|
||||
@@ -384,6 +386,135 @@ namespace YLErp.Modules.ReportModule.SettlementReportModule
|
||||
cell.Style.Numberformat.Format = "@";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 每日估值报告的互换估值导出使用当前用户已保存的列配置,
|
||||
/// 同时同步业务字段的显示状态和列顺序。
|
||||
/// </summary>
|
||||
private void ApplySwapValuationColumnConfig(IEnumerable<ExcelWorksheet> sheets)
|
||||
{
|
||||
var worksheet = sheets.FirstOrDefault(x => x.Name == "互换估值");
|
||||
if (worksheet == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var config = configcolumnBLL.GetData(UserId, configcolumn_data.互换估值V1);
|
||||
if (string.IsNullOrWhiteSpace(config?.data))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<columnmodel> columns;
|
||||
try
|
||||
{
|
||||
columns = JsonConvert.DeserializeObject<List<columnmodel>>(config.data);
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
// 列配置损坏时保留完整的模板字段,不能导致每日估值报告导出失败。
|
||||
return;
|
||||
}
|
||||
|
||||
if (columns == null || !columns.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var columnIndexByName = new Dictionary<string, int>
|
||||
{
|
||||
["ConfrimNo"] = 1,
|
||||
["TradeNumber"] = 2,
|
||||
["position.PosiStartDate"] = 3,
|
||||
["MaturitySettlementDate"] = 4,
|
||||
["position.ValueDate"] = 5,
|
||||
["position.UnderlyingCode"] = 6,
|
||||
["InterestRate"] = 7,
|
||||
["position.PosiNotionalValue"] = 8,
|
||||
["position.PosiQuantity"] = 9,
|
||||
["PeriodAmount"] = 10,
|
||||
["DividendAmount"] = 11,
|
||||
["position.PosiGrossPrice"] = 12,
|
||||
["InitYtm"] = 13,
|
||||
["position.UnderlyingPrice"] = 14,
|
||||
["DayCount"] = 15,
|
||||
["FloatRateAbs"] = 16,
|
||||
["InterestAmount"] = 17,
|
||||
["position.PosiProfitSum"] = 18,
|
||||
["position.PosiFeePending"] = 19,
|
||||
["OpenMarginRate"] = 20,
|
||||
["MarginInterestAmount"] = 21,
|
||||
["OpenMarginAmount"] = 22,
|
||||
["AdditionalMarginAmount"] = 23,
|
||||
["NetSettmentAmount"] = 24,
|
||||
["TrsValue"] = 25
|
||||
};
|
||||
// 前端 _.uniqBy 保留首次出现的配置项,导出按相同规则过滤重复字段,
|
||||
// 并保留该列表的原始顺序作为 Excel 列顺序。
|
||||
var visibleColumnIndexes = new List<int>();
|
||||
var configuredNames = new HashSet<string>();
|
||||
foreach (var column in columns)
|
||||
{
|
||||
if (column == null || string.IsNullOrEmpty(column.name) || !configuredNames.Add(column.name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!column.hidden && columnIndexByName.TryGetValue(column.name, out var index))
|
||||
{
|
||||
visibleColumnIndexes.Add(index);
|
||||
}
|
||||
}
|
||||
|
||||
// 与前端一致:旧配置缺少的新增字段默认隐藏;若没有任何业务列可见,
|
||||
// 前端会回退展示全部默认列,导出保持模板默认顺序。
|
||||
if (!visibleColumnIndexes.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ReorderSwapValuationColumns(worksheet, visibleColumnIndexes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用临时工作表保存可见列,再按目标顺序复制回原工作表。
|
||||
/// 原工作表始终保持在模板的 25 列范围内,避免 EPPlus 扩列时触发 ColumnMax 冲突。
|
||||
/// </summary>
|
||||
private static void ReorderSwapValuationColumns(ExcelWorksheet worksheet, IReadOnlyList<int> visibleSourceIndexes)
|
||||
{
|
||||
var lastRow = worksheet.Dimension.End.Row;
|
||||
var originalColumnCount = worksheet.Dimension.End.Column;
|
||||
var workbook = worksheet.Workbook;
|
||||
var bufferName = "__swap_cols_" + Guid.NewGuid().ToString("N").Substring(0, 12);
|
||||
var buffer = workbook.Worksheets.Add(bufferName);
|
||||
try
|
||||
{
|
||||
for (var targetIndex = 0; targetIndex < visibleSourceIndexes.Count; targetIndex++)
|
||||
{
|
||||
var sourceColumn = visibleSourceIndexes[targetIndex];
|
||||
var bufferColumn = targetIndex + 1;
|
||||
worksheet.Cells[1, sourceColumn, lastRow, sourceColumn]
|
||||
.Copy(buffer.Cells[1, bufferColumn, lastRow, bufferColumn]);
|
||||
}
|
||||
|
||||
for (var targetIndex = 0; targetIndex < visibleSourceIndexes.Count; targetIndex++)
|
||||
{
|
||||
var targetColumn = targetIndex + 1;
|
||||
buffer.Cells[1, targetColumn, lastRow, targetColumn]
|
||||
.Copy(worksheet.Cells[1, targetColumn, lastRow, targetColumn]);
|
||||
}
|
||||
|
||||
var columnsToDelete = originalColumnCount - visibleSourceIndexes.Count;
|
||||
if (columnsToDelete > 0)
|
||||
{
|
||||
worksheet.DeleteColumn(visibleSourceIndexes.Count + 1, columnsToDelete);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
workbook.Worksheets.Delete(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 财务状况
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user