diff --git a/YLErpDAL/Modules/ReportModule/SettlementReportModule/SettlementReportFotShanXiService.cs b/YLErpDAL/Modules/ReportModule/SettlementReportModule/SettlementReportFotShanXiService.cs index 565e604f..21736f28 100644 --- a/YLErpDAL/Modules/ReportModule/SettlementReportModule/SettlementReportFotShanXiService.cs +++ b/YLErpDAL/Modules/ReportModule/SettlementReportModule/SettlementReportFotShanXiService.cs @@ -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 = "@"; } + /// + /// 每日估值报告的互换估值导出使用当前用户已保存的列配置, + /// 同时同步业务字段的显示状态和列顺序。 + /// + private void ApplySwapValuationColumnConfig(IEnumerable 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 columns; + try + { + columns = JsonConvert.DeserializeObject>(config.data); + } + catch (JsonException) + { + // 列配置损坏时保留完整的模板字段,不能导致每日估值报告导出失败。 + return; + } + + if (columns == null || !columns.Any()) + { + return; + } + + var columnIndexByName = new Dictionary + { + ["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(); + var configuredNames = new HashSet(); + 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); + } + + /// + /// 使用临时工作表保存可见列,再按目标顺序复制回原工作表。 + /// 原工作表始终保持在模板的 25 列范围内,避免 EPPlus 扩列时触发 ColumnMax 冲突。 + /// + private static void ReorderSwapValuationColumns(ExcelWorksheet worksheet, IReadOnlyList 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); + } + } + /// /// 财务状况 ///