diff --git a/IRaCIS.Core.Application/Helper/FileDocProcess/ExcelExportHelper.cs b/IRaCIS.Core.Application/Helper/FileDocProcess/ExcelExportHelper.cs
index 5c740d0a5..a172b38d1 100644
--- a/IRaCIS.Core.Application/Helper/FileDocProcess/ExcelExportHelper.cs
+++ b/IRaCIS.Core.Application/Helper/FileDocProcess/ExcelExportHelper.cs
@@ -1,27 +1,15 @@
-using DocumentFormat.OpenXml.Spreadsheet;
-using DocumentFormat.OpenXml.Wordprocessing;
-using FellowOakDicom.Imaging.LUT;
+using ClosedXML.Excel;
+using DocumentFormat.OpenXml.Spreadsheet;
using IRaCIS.Application.Contracts;
using IRaCIS.Application.Interfaces;
-using IRaCIS.Core.API._ServiceExtensions.NewtonsoftJson;
using IRaCIS.Core.Application.Helper;
-using IRaCIS.Core.Domain.Share;
-using IRaCIS.Core.Infra.EFCore.Migrations;
-using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Hosting;
using MiniExcelLibs;
using MiniExcelLibs.OpenXml;
using Newtonsoft.Json;
-using NPOI.HSSF.UserModel;
-using NPOI.SS.Formula.Functions;
-using NPOI.SS.UserModel;
-using NPOI.XSSF.UserModel;
-using SharpCompress.Common;
using System.Collections;
using System.Globalization;
-using Xceed.Document.NET;
namespace IRaCIS.Core.Application.Service;
@@ -155,19 +143,19 @@ public static class ExcelExportHelper
templateFile.CopyTo(templateStream);
templateStream.Seek(0, SeekOrigin.Begin);
- var workbook = new XSSFWorkbook(templateStream);
+ using var workbook = new XLWorkbook(templateStream);
- int sheetCount = workbook.NumberOfSheets;
+ int sheetCount = workbook.Worksheets.Count;
if (sheetCount == 2)
{
if (isEn_US)
{
- workbook.RemoveSheetAt(0);
+ workbook.Worksheets.Delete(1); // 删除第1个(索引1)
}
else
{
- workbook.RemoveSheetAt(1);
+ workbook.Worksheets.Delete(2); // 删除第2个(索引2)
}
//中文替换项目术语
@@ -175,47 +163,36 @@ public static class ExcelExportHelper
{
var replaceObjectList = data.TrialObjectNameList;
- var sheet = workbook.GetSheetAt(0);
+ // ClosedXML 获取第一个工作表
+ var worksheet = workbook.Worksheet(1); // 索引从1开始
- int rowCount = sheet.PhysicalNumberOfRows;
+ // 获取使用的行范围(不包括空行)
+ var rowsUsed = worksheet.RowsUsed();
- for (int rowIndex = 0; rowIndex < rowCount; rowIndex++)
+ foreach (var row in rowsUsed)
{
- var row = sheet.GetRow(rowIndex);
+ // 获取该行有数据的单元格
+ var cellsUsed = row.CellsUsed(c => c.DataType == XLDataType.Text);
- if (row != null)
+ foreach (var cell in cellsUsed)
{
+ var cellValue = cell.GetString();
- var colums = row.LastCellNum;
-
- for (int colIndex = 0; colIndex < colums; colIndex++)
+ var find = replaceObjectList.FirstOrDefault(t => t.Name == cellValue);
+ if (find != null)
{
- var cell = row.GetCell(colIndex);
-
- // 只处理字符串类型的单元格
- if (cell != null)
- {
- var cellValue = cell.StringCellValue;
-
- var find = replaceObjectList.FirstOrDefault(t => t.Name == cellValue);
- if (find != null)
- {
- cell.SetCellValue(find.TrialName);
- }
- }
+ cell.SetValue(find.TrialName);
}
}
-
}
}
using (var memoryStream2 = new MemoryStream())
{
- workbook.Write(memoryStream2, true);
-
+ workbook.SaveAs(memoryStream2);
memoryStream2.Seek(0, SeekOrigin.Begin);
-
templateStream = memoryStream2;
+
}
@@ -252,17 +229,17 @@ public static class ExcelExportHelper
public class DynamicColumnConfig
{
///
- /// 增加动态列开始索引 从0 开始算
+ /// 增加动态列开始索引 npoi从0开始 现在ClosedXML 从1开始
///
public int AutoColumnStartIndex { get; set; }
///
- /// 动态列开始的行index 从0开始
+ /// 动态列开始的行index npoi从0开始 现在ClosedXML 从1开始
///
public int AutoColumnTitleRowIndex { get; set; }
///
- /// 模板列最后的索引
+ /// 模板列最后的索引 npoi从0开始 现在ClosedXML 从1开始
///
public int TempalteLastColumnIndex { get; set; }
@@ -442,177 +419,174 @@ public static class ExcelExportHelper
templateFile.CopyTo(templateStream);
templateStream.Seek(0, SeekOrigin.Begin);
- var workbook = new XSSFWorkbook(templateStream);
- int sheetCount = workbook.NumberOfSheets;
+ using var workbook = new XLWorkbook(templateStream);
+
+ int sheetCount = workbook.Worksheets.Count;
if (sheetCount == 2)
{
if (isEn_US)
{
- workbook.RemoveSheetAt(0);
+ workbook.Worksheets.Delete(1); // 删除第1个(索引1)
}
else
{
- workbook.RemoveSheetAt(1);
+ workbook.Worksheets.Delete(2); // 删除第2个(索引2)
}
#region 中文替换项目术语
+ //中文替换项目术语
if (data.TrialObjectNameList?.Count > 0)
{
var replaceObjectList = data.TrialObjectNameList;
- var sheet = workbook.GetSheetAt(0);
+ // ClosedXML 获取第一个工作表
+ var worksheet = workbook.Worksheet(1); // 索引从1开始
- int rowCount = sheet.PhysicalNumberOfRows;
+ // 获取使用的行范围(不包括空行)
+ var rowsUsed = worksheet.RowsUsed();
- for (int rowIndex = 0; rowIndex < rowCount; rowIndex++)
+ foreach (var row in rowsUsed)
{
- var row = sheet.GetRow(rowIndex);
- if (row != null)
+ // 获取该行使用的列范围
+ var cellsUsed = row.CellsUsed();
+
+ foreach (var cell in cellsUsed)
{
- var colums = row.LastCellNum;
+ var cellValue = cell.GetString();
- for (int colIndex = 0; colIndex < colums; colIndex++)
- {
- var cell = row.GetCell(colIndex);
-
- // 只处理字符串类型的单元格
- if (cell != null)
+ var find = replaceObjectList.FirstOrDefault(t => t.Name == cellValue);
+ if (find != null)
{
- var cellValue = cell.StringCellValue;
-
- var find = replaceObjectList.FirstOrDefault(t => t.Name == cellValue);
- if (find != null)
- {
- cell.SetCellValue(find.TrialName);
- }
+ cell.SetValue(find.TrialName);
}
- }
+
}
}
}
- #endregion
+ #endregion
+
if (dynamicColumnConfig != null)
{
- //var isCdics = dynamicColumnConfig.CDISCList.Count > 0;
-
var isCdics = dynamicColumnConfig.IsCDISCExport;
- var sheet = workbook.GetSheetAt(0);
+ // ClosedXML 获取工作表(索引从1开始)
+ var worksheet = workbook.Worksheet(1);
- var cdicsRow = sheet.GetRow(dynamicColumnConfig.AutoColumnTitleRowIndex - 1);
- var titelRow = sheet.GetRow(dynamicColumnConfig.AutoColumnTitleRowIndex);
- var templateRow = sheet.GetRow(dynamicColumnConfig.AutoColumnTitleRowIndex + 1);
+ // 获取行(ClosedXML 行索引从1开始,AutoColumnTitleRowIndex 已经改了保持不变)
+ var cdicsRow = worksheet.Row(dynamicColumnConfig.AutoColumnTitleRowIndex-1); // 原 NPOI: -1
+ var titelRow = worksheet.Row(dynamicColumnConfig.AutoColumnTitleRowIndex); // 原 NPOI: 不变
+ var templateRow = worksheet.Row(dynamicColumnConfig.AutoColumnTitleRowIndex + 1); // 原 NPOI: +1
- //动态移除列的数量
+ // 动态移除列的数量
var dynamicRemoveColunmCount = dynamicColumnConfig.RemoveColunmIndexList.Count();
- //在动态列开始前移除的数量
- var beforeDynamicRemoveCount = dynamicColumnConfig.RemoveColunmIndexList.Where(t => t < dynamicColumnConfig.AutoColumnStartIndex).Count();
+ // 在动态列开始前移除的数量
+ var beforeDynamicRemoveCount = dynamicColumnConfig.RemoveColunmIndexList.Count(t => t < dynamicColumnConfig.AutoColumnStartIndex);
- //动态添加列的数量
+ // 动态添加列的数量
var needAddCount = dynamicColumnConfig.ColumnIdNameList.Count;
- //原始表 最终索引
+ // 原始表最终索引(NPOI 从0开始,ClosedXML 从1开始,但这里存储的是逻辑索引,后续转换)
var originTotalEndIndex = dynamicColumnConfig.TempalteLastColumnIndex;
- //减去动态移除后原始结束索引
+ // 减去动态移除后原始结束索引
var originRemoveEndIndex = originTotalEndIndex - dynamicRemoveColunmCount;
- //最终表 动态列开始索引
+ // 最终表动态列开始索引
var dynamicColunmStartIndex = dynamicColumnConfig.AutoColumnStartIndex - beforeDynamicRemoveCount;
- //最终表 动态列的终止索引
+ // 最终表动态列的终止索引
var dynamicColunmEndIndex = dynamicColunmStartIndex + needAddCount - 1;
- //最终表 最终索引
+ // 最终表最终索引
var totalColunmEndIndex = originTotalEndIndex + needAddCount - dynamicRemoveColunmCount;
-
- //动态列后需要移动的数量
+ // 删除需要动态删除的列 从大到小移除,否则索引会变
+ // 动态列后需要移动的数量
var backMoveCount = totalColunmEndIndex - dynamicColunmEndIndex;
- //删除需要动态删除的列 从大到小移除,否则索引会变
+ // 删除需要动态删除的列(从大到小移除,否则索引会变)
+ // 注意:ClosedXML 可以直接使用 Delete() 方法,但为了保持原逻辑,这里使用手动移动
foreach (var removeIndex in dynamicColumnConfig.RemoveColunmIndexList.OrderByDescending(t => t))
{
- //将后面的列向前移动
+ // 将后面的列向前移动
for (var i = 0; i < originTotalEndIndex - removeIndex; i++)
{
- Console.WriteLine(titelRow.GetCell(removeIndex + i + 1).StringCellValue);
- titelRow.GetCell(removeIndex + i).SetCellValue(titelRow.GetCell(removeIndex + i + 1).StringCellValue);
- templateRow.GetCell(removeIndex + i).SetCellValue(templateRow.GetCell(removeIndex + i + 1).StringCellValue);
+
+ int currentCol = removeIndex + i ;
+ int nextCol = removeIndex + i + 1;
- //后面的数据要清空
- titelRow.GetCell(removeIndex + i + 1).SetCellValue("");
- templateRow.GetCell(removeIndex + i + 1).SetCellValue("");
+ Console.WriteLine(titelRow.Cell(nextCol).GetString());
+ // 移动值
+ titelRow.Cell(currentCol).SetValue(titelRow.Cell(nextCol).GetString());
+ templateRow.Cell(currentCol).SetValue(templateRow.Cell(nextCol).GetString());
+
+ // 清空后面的数据
+ titelRow.Cell(nextCol).SetValue(string.Empty);
+ templateRow.Cell(nextCol).SetValue(string.Empty);
}
-
}
- //创建新的列
+ // 创建新的列(ClosedXML 不需要显式创建,直接设置值即可)
for (int i = originRemoveEndIndex; i < originRemoveEndIndex + needAddCount; i++)
{
+ int colIndex = i + 1;
- titelRow.CreateCell(i + 1);
- templateRow.CreateCell(i + 1);
-
+ // 不需要 CreateCell,直接设置值即可
if (isCdics)
{
- cdicsRow.CreateCell(i + 1);
+ cdicsRow.Cell(colIndex).SetValue(string.Empty);
}
+ titelRow.Cell(colIndex).SetValue(string.Empty);
+ templateRow.Cell(colIndex).SetValue(string.Empty);
}
- //移动Title 和下面的模板标识
+ // 移动 Title 和下面的模板标识
var gap = totalColunmEndIndex - originRemoveEndIndex;
for (int i = totalColunmEndIndex; i > dynamicColunmEndIndex; i--)
{
+ int currentCol = i ;
+ int sourceCol = i - gap ;
- titelRow.GetCell(i).SetCellValue(titelRow.GetCell(i - gap).StringCellValue);
-
- templateRow.GetCell(i).SetCellValue(templateRow.GetCell(i - gap).StringCellValue);
+ titelRow.Cell(currentCol).SetValue(titelRow.Cell(sourceCol).GetString());
+ templateRow.Cell(currentCol).SetValue(templateRow.Cell(sourceCol).GetString());
if (isCdics)
{
- cdicsRow.GetCell(i).SetCellValue(cdicsRow.GetCell(i - gap).StringCellValue);
+ cdicsRow.Cell(currentCol).SetValue(cdicsRow.Cell(sourceCol).GetString());
}
}
-
-
- //设置动态Tilte
-
+ // 设置动态 Title
for (int i = dynamicColunmStartIndex; i < dynamicColunmStartIndex + needAddCount; i++)
{
+ int colIndex = i ;
+ var index = i - dynamicColunmStartIndex;
+ var name = dynamicColumnConfig.ColumnIdNameList[index].Name;
- var name = dynamicColumnConfig.ColumnIdNameList[i - dynamicColunmStartIndex].Name;
-
- titelRow.GetCell(i).SetCellValue(name);
- templateRow.GetCell(i).SetCellValue("");
+ titelRow.Cell(colIndex).SetValue(name);
+ templateRow.Cell(colIndex).SetValue(string.Empty);
if (isCdics)
{
- var cdicsCode = dynamicColumnConfig.ColumnIdNameList[i - dynamicColunmStartIndex].CDISCCode;
-
- cdicsRow.GetCell(i).SetCellValue(cdicsCode);
+ var cdicsCode = dynamicColumnConfig.ColumnIdNameList[index].CDISCCode;
+ cdicsRow.Cell(colIndex).SetValue(cdicsCode);
}
}
-
}
-
using (var memoryStream2 = new MemoryStream())
{
- workbook.Write(memoryStream2, true);
-
+ workbook.SaveAs(memoryStream2);
memoryStream2.Seek(0, SeekOrigin.Begin);
-
templateStream = memoryStream2;
}
@@ -643,9 +617,9 @@ public static class ExcelExportHelper
var dynamicTranslateDataList = await _dictionaryService.GetBasicDataSelect(dynamicColumnConfig.TranslateDicNameList.ToArray());
- // 使用NPOI 进行二次处理
- var wb = new XSSFWorkbook(memoryStream);
- var sheet = wb.GetSheetAt(0);
+ // 使用 ClosedXML 进行二次处理
+ using var wb = new XLWorkbook(memoryStream);
+ var worksheet = wb.Worksheet(1); // 获取第一个工作表,索引从1开始
var list = translatedDic["List"] as IList;
@@ -653,8 +627,8 @@ public static class ExcelExportHelper
{
var index = list.IndexOf(itemResult);
- //从第四行开始处理动态列
- var row = sheet.GetRow(index + dynamicColumnConfig.AutoColumnTitleRowIndex + 1);
+ // 从第四行开始处理动态列
+ var row = worksheet.Row(index + dynamicColumnConfig.AutoColumnTitleRowIndex + 1); // +2 因为 NPOI 从0,ClosedXML 从1
var itemDic = itemResult.ToDictionary();
@@ -675,11 +649,11 @@ public static class ExcelExportHelper
if (isExcelAddDataWithName)
{
- writeIndex = dynamicColumnConfig.ColumnNameList.IndexOf(iteObjDic[dynamicColumnConfig.DynamicItemTitleName].ToString()) + dynamicColumnConfig.AutoColumnStartIndex;
+ writeIndex = dynamicColumnConfig.ColumnNameList.IndexOf(iteObjDic[dynamicColumnConfig.DynamicItemTitleName].ToString()) + dynamicColumnConfig.AutoColumnStartIndex ; // +1 因为 ClosedXML 列从1开始
}
else
{
- writeIndex = dynamicColumnConfig.ColumnIdList.IndexOf(iteObjDic[dynamicColumnConfig.DynamicItemTitleId].ToString()) + dynamicColumnConfig.AutoColumnStartIndex;
+ writeIndex = dynamicColumnConfig.ColumnIdList.IndexOf(iteObjDic[dynamicColumnConfig.DynamicItemTitleId].ToString()) + dynamicColumnConfig.AutoColumnStartIndex ; // +1 因为 ClosedXML 列从1开始
}
@@ -723,7 +697,8 @@ public static class ExcelExportHelper
}
- row.GetCell(writeIndex).SetCellValue(translatedItemData);
+ // ClosedXML 设置单元格值
+ row.Cell(writeIndex).SetValue(translatedItemData);
}
else
@@ -732,13 +707,11 @@ public static class ExcelExportHelper
if (unit.IsNotNullOrEmpty() && unit == "9")
{
- row.GetCell(writeIndex).SetCellValue(itemValue + "%");
-
+ row.Cell(writeIndex).SetValue(itemValue + "%");
}
else
{
- row.GetCell(writeIndex).SetCellValue(itemValue);
-
+ row.Cell(writeIndex).SetValue(itemValue);
}
@@ -748,7 +721,7 @@ public static class ExcelExportHelper
}
var memoryStream2 = new MemoryStream();
- wb.Write(memoryStream2, true);
+ wb.SaveAs(memoryStream2, true);
memoryStream2.Seek(0, SeekOrigin.Begin);
memoryStream = memoryStream2;
@@ -764,323 +737,6 @@ public static class ExcelExportHelper
#endregion
}
- ///
- /// 暂时废弃--合并到上面
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public static async Task<(MemoryStream, string)> CDISC_DataExport_Async(string code, ExcelExportInfo data, IRepository _commonDocumentRepository, IWebHostEnvironment _hostEnvironment, IDictionaryService? _dictionaryService = null, Type? translateType = null, CriterionType? criterionType = null, DynamicColumnConfig? dynamicColumnConfig = null)
- {
- var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
- //判断是否有字典翻译
-
- object translateData = data;
-
- Dictionary translatedDic = default;
-
- if (_dictionaryService != null && translateType != null)
- {
-
- //一个值 对应不同的字典翻译
- var needTranslatePropertyList = translateType.GetProperties().Where(t => t.IsDefined(typeof(DictionaryTranslateAttribute), true))
- .SelectMany(c =>
- c.GetCustomAttributes(typeof(DictionaryTranslateAttribute), false).Select(f => (DictionaryTranslateAttribute?)f).Where(t => t.CriterionType == criterionType || t.CriterionType == null)
- .Select(k => new { c.Name, k.DicParentCode, k.IsTranslateDenpendOtherProperty, k.DependPropertyName, k.DependPropertyValueStr })
- ).ToList();
-
-
-
- //字典表查询出所有需要翻译的数据
-
- var translateDataList = await _dictionaryService.GetBasicDataSelect(needTranslatePropertyList.Select(t => t.DicParentCode).Distinct().ToArray());
-
- var dic = data.ConvertToDictionary();
- //var dic = (JsonConvert.DeserializeObject>(data.ToJsonNotIgnoreNull())).IfNullThrowException();
-
- foreach (var key in dic.Keys)
- {
- //是数组 那么找到对应的属性 进行翻译
- if (dic[key] != null && dic[key].GetType().GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IList<>)))
- //if (dic[key].GetType().IsAssignableFrom(typeof(JArray)))
- {
-
- var newObjList = new List