ClosedXML 替代 npoi 修改

This commit is contained in:
2026-04-29 20:19:01 +08:00
parent 7707b339dc
commit 8bf0be9699
31 changed files with 336 additions and 943 deletions
@@ -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
{
/// <summary>
/// 增加动态列开始索引 从0 开始
/// 增加动态列开始索引 npoi从0开始 现在ClosedXML 从1开始
/// </summary>
public int AutoColumnStartIndex { get; set; }
/// <summary>
/// 动态列开始的行index 从0开始
/// 动态列开始的行index npoi从0开始 现在ClosedXML 从1开始
/// </summary>
public int AutoColumnTitleRowIndex { get; set; }
/// <summary>
/// 模板列最后的索引
/// 模板列最后的索引 npoi从0开始 现在ClosedXML 从1开始
/// </summary>
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 从0ClosedXML 从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
}
/// <summary>
/// 暂时废弃--合并到上面
/// </summary>
/// <param name="code"></param>
/// <param name="data"></param>
/// <param name="_commonDocumentRepository"></param>
/// <param name="_hostEnvironment"></param>
/// <param name="_dictionaryService"></param>
/// <param name="translateType"></param>
/// <param name="criterionType"></param>
/// <param name="dynamicColumnConfig"></param>
/// <returns></returns>
public static async Task<(MemoryStream, string)> CDISC_DataExport_Async(string code, ExcelExportInfo data, IRepository<CommonDocument> _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<string, object> 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<IDictionary<string, object>>(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<object>();
var no = 1;
foreach (var item in dic[key] as IList)
//foreach (var item in dic[key] as JArray)
{
//var itemDic = JsonConvert.DeserializeObject<IDictionary<string, object>>(item.ToJsonNotIgnoreNull());
var itemDic = item.ConvertToDictionary();
foreach (var needTranslateProperty in needTranslatePropertyList)
{
if (itemDic.Keys.Any(t => t == needTranslateProperty.Name))
{
//翻译的属性依赖其他属性
if (needTranslateProperty.IsTranslateDenpendOtherProperty)
{
if (itemDic[needTranslateProperty.DependPropertyName]?.ToString().ToLower() == needTranslateProperty.DependPropertyValueStr.ToLower())
{
var beforeValue = itemDic[needTranslateProperty.Name]?.ToString();
itemDic[needTranslateProperty.Name] = translateDataList[needTranslateProperty.DicParentCode].Where(t => t.Code.ToLower() == beforeValue?.ToLower()).Select(t => isEn_US ? t.Value : t.ValueCN).FirstOrDefault() ?? String.Empty;
}
}
//普通翻译 或者某一标准翻译
else
{
var beforeValue = itemDic[needTranslateProperty.Name]?.ToString();
itemDic[needTranslateProperty.Name] = translateDataList[needTranslateProperty.DicParentCode].Where(t => t.Code.ToLower() == beforeValue?.ToLower()).Select(t => isEn_US ? t.Value : t.ValueCN).FirstOrDefault() ?? String.Empty;
}
}
}
itemDic.Add("No", no++);
newObjList.Add(itemDic);
}
dic[key] = newObjList;
}
}
//data = dic;
translateData = dic;
translatedDic = dic;
}
var (physicalPath, fileName) = await FileStoreHelper.GetCommonDocPhysicalFilePathAsync(_hostEnvironment, _commonDocumentRepository, code);
//模板路径
var tplPath = physicalPath;
// 获取文件流
var templateStream = new MemoryStream();
#region sheet
// 打开模板文件
var templateFileStream = new FileStream(tplPath, FileMode.Open, FileAccess.Read);
var workbook = new XSSFWorkbook(templateFileStream);
int sheetCount = workbook.NumberOfSheets;
if (sheetCount == 2)
{
if (isEn_US)
{
workbook.RemoveSheetAt(0);
}
else
{
workbook.RemoveSheetAt(1);
}
if (dynamicColumnConfig != null)
{
var sheet = workbook.GetSheetAt(0);
var cdicsRow = sheet.GetRow(dynamicColumnConfig.AutoColumnTitleRowIndex - 1);
var titelRow = sheet.GetRow(dynamicColumnConfig.AutoColumnTitleRowIndex);
var templateRow = sheet.GetRow(dynamicColumnConfig.AutoColumnTitleRowIndex + 1);
//动态移除列的数量
var dynamicRemoveColunmCount = dynamicColumnConfig.RemoveColunmIndexList.Count();
//在动态列开始前移除的数量
var beforeDynamicRemoveCount = dynamicColumnConfig.RemoveColunmIndexList.Where(t => t < dynamicColumnConfig.AutoColumnStartIndex).Count();
//动态添加列的数量
var needAddCount = dynamicColumnConfig.ColumnIdNameList.Count;
//原始表 最终索引
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;
//删除需要动态删除的列 从大到小移除,否则索引会变
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);
//后面的数据要清空
titelRow.GetCell(removeIndex + i + 1).SetCellValue("");
templateRow.GetCell(removeIndex + i + 1).SetCellValue("");
}
}
//创建新的列
for (int i = originTotalEndIndex; i < originTotalEndIndex + needAddCount; i++)
{
cdicsRow.CreateCell(i + 1);
titelRow.CreateCell(i + 1);
templateRow.CreateCell(i + 1);
}
//移动Title 和下面的模板标识
var gap = totalColunmEndIndex - originRemoveEndIndex;
for (int i = totalColunmEndIndex; i > dynamicColunmEndIndex; i--)
{
titelRow.GetCell(i).SetCellValue(titelRow.GetCell(i - gap).StringCellValue);
templateRow.GetCell(i).SetCellValue(templateRow.GetCell(i - gap).StringCellValue);
}
//设置动态Tilte
for (int i = dynamicColunmStartIndex; i < dynamicColunmStartIndex + needAddCount; i++)
{
var name = dynamicColumnConfig.ColumnIdNameList[i - dynamicColunmStartIndex].Name;
var cdicsCode = dynamicColumnConfig.ColumnIdNameList[i - dynamicColunmStartIndex].CDISCCode;
cdicsRow.GetCell(i).SetCellValue(cdicsCode);
titelRow.GetCell(i).SetCellValue(name);
templateRow.GetCell(i).SetCellValue("");
}
}
workbook.Write(templateStream, leaveOpen: true);
templateStream.Position = 0;
}
#endregion
#region MiniExcel
var memoryStream = new MemoryStream();
var config = new OpenXmlConfiguration()
{
IgnoreTemplateParameterMissing = true,
};
await MiniExcel.SaveAsByTemplateAsync(memoryStream, templateStream.ToArray(), translateData, config);
memoryStream.Seek(0, SeekOrigin.Begin);
if (dynamicColumnConfig != null)
{
var isExcelAddDataWithName = dynamicColumnConfig.ColumnIdNameList.Select(t => t.Id).Count() == 1;
var dynamicTranslateDataList = await _dictionaryService.GetBasicDataSelect(dynamicColumnConfig.TranslateDicNameList.ToArray());
// 使用NPOI 进行二次处理
var wb = new XSSFWorkbook(memoryStream);
var sheet = wb.GetSheetAt(0);
var list = translatedDic["List"] as IList;
foreach (var itemResult in list)
{
var index = list.IndexOf(itemResult);
//从第四行开始处理动态列
var row = sheet.GetRow(index + dynamicColumnConfig.AutoColumnTitleRowIndex + 1);
var itemDic = itemResult.ToDictionary();
var itemList = itemDic[dynamicColumnConfig.DynamicListName] as IList;
//这个数组是动态的,有的多,有的少,所以在此对比Title 一致才赋值
foreach (var itemObj in itemList)
{
var iteObjDic = itemObj.ToDictionary();
var itemDicName = iteObjDic[dynamicColumnConfig.DynamicItemDicName]?.ToString();
var itemValue = iteObjDic[dynamicColumnConfig.DynamicItemValueName]?.ToString();
//var writeIndex = itemList.IndexOf(itemObj) + dynamicColumnConfig.AutoColumnStartIndex;
var writeIndex = 0;
if (isExcelAddDataWithName)
{
writeIndex = dynamicColumnConfig.ColumnNameList.IndexOf(iteObjDic[dynamicColumnConfig.DynamicItemTitleName].ToString()) + dynamicColumnConfig.AutoColumnStartIndex;
}
else
{
writeIndex = dynamicColumnConfig.ColumnIdList.IndexOf(iteObjDic[dynamicColumnConfig.DynamicItemTitleId].ToString()) + dynamicColumnConfig.AutoColumnStartIndex;
}
if (itemDicName.IsNotNullOrEmpty())
{
var translatedItemData = dynamicTranslateDataList[itemDicName].Where(t => t.Code.ToLower() == itemValue?.ToLower()).Select(t => isEn_US ? t.Value : t.ValueCN).FirstOrDefault() ?? String.Empty;
row.GetCell(writeIndex).SetCellValue(translatedItemData);
}
else
{
row.GetCell(writeIndex).SetCellValue(itemValue);
}
}
}
var memoryStream2 = new MemoryStream();
wb.Write(memoryStream2, true);
memoryStream2.Seek(0, SeekOrigin.Begin);
memoryStream = memoryStream2;
}
return (memoryStream, fileName);
#endregion
}
@@ -1104,38 +760,28 @@ public static class ExcelExportHelper
// 打开模板文件
using var templateFileStream = new FileStream(tplPath, FileMode.Open, FileAccess.Read);
using var workbook = new XSSFWorkbook(templateFileStream);
using var workbook = new XLWorkbook(templateFileStream);
int sheetCount = workbook.NumberOfSheets;
int sheetCount = workbook.Worksheets.Count;
int removeRowIndex = 1; // 要删除的行(0-based
int removeRowIndex = 2; // ClosedXML 中行索引从 1 开始,所以第2行对应 NPOI 的第1行
for (int i = 0; i < sheetCount; i++)
for (int i = 1; i <= sheetCount; i++) // ClosedXML 工作表索引从 1 开始
{
var sheet = workbook.GetSheetAt(i);
var worksheet = workbook.Worksheet(i);
// 2 删除行
var row = sheet.GetRow(removeRowIndex);
if (row != null)
// 删除行
var row = worksheet.Row(removeRowIndex);
if (!row.IsEmpty() || row.CellsUsed().Any()) // 检查行是否存在数据
{
sheet.RemoveRow(row);
}
// 3 上移后续行
if (removeRowIndex < sheet.LastRowNum)
{
sheet.ShiftRows(
removeRowIndex + 1,
sheet.LastRowNum,
-1,
true, // copyRowHeight
false // resetOriginalRowHeight
);
row.Delete(); // ClosedXML 直接删除行
}
}
workbook.Write(templateStream, leaveOpen: true);
workbook.SaveAs(templateStream);
templateStream.Position = 0;
}
else
{
@@ -1182,72 +828,64 @@ public static class ExcelExportHelper
//模板路径
var tplPath = physicalPath;
#region sheet
#region sheet使 ClosedXML
// 打开模板文件
var templateFile = new FileStream(tplPath, FileMode.Open, FileAccess.Read);
using var templateFileStream = new FileStream(tplPath, FileMode.Open, FileAccess.Read);
using var workbook = new XLWorkbook(templateFileStream);
// 获取文件流
var templateStream = new MemoryStream();
templateFile.CopyTo(templateStream);
templateStream.Seek(0, SeekOrigin.Begin);
var workbook = new XSSFWorkbook(templateStream);
int sheetCount = workbook.NumberOfSheets;
int sheetCount = workbook.Worksheets.Count;
if (sheetCount == 2)
{
if (inDto.IsEnglish)
{
workbook.RemoveSheetAt(0);
workbook.Worksheet(1).Delete(); // 删除第一个工作表
}
else
{
workbook.RemoveSheetAt(1);
workbook.Worksheet(2).Delete(); // 删除第二个工作表
}
}
#endregion
// 获取第一个工作表(删除后剩下的那个)
var worksheet = workbook.Worksheet(1);
ISheet sheet = workbook.GetSheetAt(0); // 获取第一个工作表
// 遍历所有行和列,替换模板占位符
var rowsUsed = worksheet.RowsUsed();
for (int i = 0; i < sheet.LastRowNum + 1; i++)
foreach (var row in rowsUsed)
{
IRow row = sheet.GetRow(i);
for (int j = 0; j < sheet.LastRowNum; j++)
var cellsUsed = row.CellsUsed(c => c.DataType == XLDataType.Text);
foreach (var cell in cellsUsed)
{
ICell cell = row.GetCell(j);
var cellValue = cell.GetString();
// 检查是否包含模板占位符 {{PropertyName}}
foreach (var property in inDto.Data.GetType().GetProperties())
{
var value = property.GetValue(inDto.Data);
if (cell != null && cell.ToString() == "{{" + property.Name + "}}")
var placeholder = "{{" + property.Name + "}}";
if (cellValue.Contains(placeholder))
{
sheet.GetRow(i).GetCell(j).SetCellValue(value.ToString());
var value = property.GetValue(inDto.Data);
var newValue = cellValue.Replace(placeholder, value?.ToString() ?? string.Empty);
cell.SetValue(newValue);
}
}
}
}
var memoryStream = new MemoryStream();
workbook.SaveAs(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
var memoryStream2 = new MemoryStream();
workbook.Write(memoryStream2, true);
memoryStream2.Seek(0, SeekOrigin.Begin);
templateStream = memoryStream2;
return new FileStreamResult(templateStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
return new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
{
FileDownloadName = $"{(string.IsNullOrEmpty(inDto.ExportFileName) ? "" : inDto.ExportFileName + "_")}{Path.GetFileNameWithoutExtension(fileName)}_{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx"
};
}
@@ -1,6 +1,4 @@
using IRaCIS.Core.Domain.Share;
using NPOI.XWPF.UserModel;
using System.Globalization;
using System.Globalization;
using Xceed.Document.NET;
using Xceed.Words.NET;
@@ -54,42 +52,42 @@ public static class WordTempleteHelper
}
public static void Npoi_GetInternationalTempleteStream(string filePath, Stream memoryStream)
{
//public static void Npoi_GetInternationalTempleteStream(string filePath, Stream memoryStream)
//{
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
// var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
XWPFDocument doc = new XWPFDocument(fs);
// using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
// {
// XWPFDocument doc = new XWPFDocument(fs);
// 查找包含指定书签的段落及其索引
var bookmarkParagraph = doc.Paragraphs
.FirstOrDefault(p => p.GetCTP().GetBookmarkStartList().Any(b => b.name == StaticData.CultureInfo.en_US_bookMark));
// // 查找包含指定书签的段落及其索引
// var bookmarkParagraph = doc.Paragraphs
// .FirstOrDefault(p => p.GetCTP().GetBookmarkStartList().Any(b => b.name == StaticData.CultureInfo.en_US_bookMark));
if (bookmarkParagraph != null)
{
int bookmarkIndex = doc.Paragraphs.IndexOf(bookmarkParagraph);
// if (bookmarkParagraph != null)
// {
// int bookmarkIndex = doc.Paragraphs.IndexOf(bookmarkParagraph);
if (isEn_US)
{
// 从书签所在段落开始,删除之前的所有段落
for (int i = bookmarkIndex - 1; i >= 0; i--)
{
doc.RemoveBodyElement(i);
}
}
else
{
// 删除书签之后的所有段落
for (int i = doc.Paragraphs.Count - 1; i >= bookmarkIndex; i--)
{
doc.RemoveBodyElement(i);
}
}
}
doc.Write(memoryStream);
}
}
// if (isEn_US)
// {
// // 从书签所在段落开始,删除之前的所有段落
// for (int i = bookmarkIndex - 1; i >= 0; i--)
// {
// doc.RemoveBodyElement(i);
// }
// }
// else
// {
// // 删除书签之后的所有段落
// for (int i = doc.Paragraphs.Count - 1; i >= bookmarkIndex; i--)
// {
// doc.RemoveBodyElement(i);
// }
// }
// }
// doc.Write(memoryStream);
// }
//}
}