using DocumentFormat.OpenXml.Spreadsheet; using DocumentFormat.OpenXml.Wordprocessing; 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 Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Hosting; using MiniExcelLibs; using MiniExcelLibs.OpenXml; using NPOI.HSSF.UserModel; using NPOI.SS.Formula.Functions; using NPOI.SS.UserModel; using NPOI.XSSF.UserModel; using System.Collections; using System.Globalization; namespace IRaCIS.Core.Application.Service; public static class ExcelExportHelper { //MiniExcel_Export /// /// /// /// /// /// 文件名前缀 /// /// /// /// /// /// public static async Task DataExportAsync(string code, ExcelExportInfo data, string exportFileNamePrefix, IRepository _commonDocumentRepository, IWebHostEnvironment _hostEnvironment, IDictionaryService? _dictionaryService = null, Type? translateType = null, CriterionType? criterionType = null) { var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US; //判断是否有字典翻译 object translateData = data; 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(); foreach (var key in dic.Keys) { //是数组 那么找到对应的属性 进行翻译 if (dic[key].GetType().GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IList<>))) { var newObjList = new List(); var no = 1; foreach (var item in dic[key] as IList) { var itemDic = item.ConvertToDictionary(); //处理集合里面时间类型,根据当前语言将时间转变为字符串 foreach (var itemValuePair in itemDic) { if (DateTime.TryParse(itemValuePair.Value?.ToString(), out DateTime result)) { itemDic[itemValuePair.Key] = ExportExcelConverterDate.DateTimeInternationalToString(result); } } foreach (var needTranslateProperty in needTranslatePropertyList) { //翻译的属性依赖其他属性 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; } var (physicalPath, fileName) = await FileStoreHelper.GetCommonDocPhysicalFilePathAsync(_hostEnvironment, _commonDocumentRepository, code); //模板路径 var tplPath = physicalPath; #region 根据中英文 删除模板sheet // 打开模板文件 var templateFile = new FileStream(tplPath, FileMode.Open, FileAccess.Read); // 获取文件流 var templateStream = new MemoryStream(); templateFile.CopyTo(templateStream); templateStream.Seek(0, SeekOrigin.Begin); var workbook = new XSSFWorkbook(templateStream); int sheetCount = workbook.NumberOfSheets; if (sheetCount == 2) { if (isEn_US) { workbook.RemoveSheetAt(0); } else { workbook.RemoveSheetAt(1); } var memoryStream2 = new MemoryStream(); workbook.Write(memoryStream2, true); memoryStream2.Seek(0, SeekOrigin.Begin); templateStream = memoryStream2; } // 文件名称 从sheet里面取 //fileNmae = workbook.GetSheetName(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); return new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") { FileDownloadName = $"{(string.IsNullOrEmpty(exportFileNamePrefix) ? "" : exportFileNamePrefix + "_")}{Path.GetFileNameWithoutExtension(fileName)}_{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx" }; #endregion } public class DynamicColumnConfig { public int AutoColumnStartIndex { get; set; } public int AutoColumnRowIndex { get; set; } public int BackMoveCount { get; set; } public List ColumnNameList { get; set; } public List TranslateDicNameList { get; set; } //动态取数据的集合名 public string DynamicListName { get; set; } //动态数据翻译的取字典的属性名 public string DynamicItemDicName { get; set; } //取值的属性名 public string DynamicItemValueName { get; set; } } public static async Task<(MemoryStream, string)> DataExport_NpoiTestAsync(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].GetType().GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IList<>))) //if (dic[key].GetType().IsAssignableFrom(typeof(JArray))) { var newObjList = new List(); var no = 1; foreach (var item in dic[key] as IList) //foreach (var item in dic[key] as JArray) { //var itemDic = JsonConvert.DeserializeObject>(item.ToJsonNotIgnoreNull()); var itemDic = item.ConvertToDictionary(); //处理集合里面时间类型,根据当前语言将时间转变为字符串 foreach (var itemValuePair in itemDic) { if (DateTime.TryParse(itemValuePair.Value?.ToString(), out DateTime result)) { itemDic[itemValuePair.Key] = ExportExcelConverterDate.DateTimeInternationalToString(result); } } foreach (var needTranslateProperty in needTranslatePropertyList) { //翻译的属性依赖其他属性 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; #region 根据中英文 删除模板sheet // 打开模板文件 var templateFile = new FileStream(tplPath, FileMode.Open, FileAccess.Read); // 获取文件流 var templateStream = new MemoryStream(); templateFile.CopyTo(templateStream); templateStream.Seek(0, SeekOrigin.Begin); var workbook = new XSSFWorkbook(templateStream); 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 row = sheet.GetRow(dynamicColumnConfig.AutoColumnRowIndex); var templateRow = sheet.GetRow(dynamicColumnConfig.AutoColumnRowIndex + 1); var needAddCount = dynamicColumnConfig.ColumnNameList.Count; var colunmAddIndex = dynamicColumnConfig.AutoColumnStartIndex + dynamicColumnConfig.BackMoveCount; //创建新的列 for (int i = 0; i < needAddCount; i++) { row.CreateCell(i + colunmAddIndex); } //移动Title 和下面的模板标识 for (int i = colunmAddIndex + needAddCount; i < colunmAddIndex; i--) { row.GetCell(i).SetCellValue(row.GetCell(i - needAddCount).StringCellValue); templateRow.GetCell(i).SetCellValue(templateRow.GetCell(i - needAddCount).StringCellValue); } //设置动态Tilte for (int i = dynamicColumnConfig.AutoColumnStartIndex; i < dynamicColumnConfig.AutoColumnStartIndex + needAddCount; i++) { var name = dynamicColumnConfig.ColumnNameList[i - dynamicColumnConfig.AutoColumnStartIndex]; row.GetCell(i).SetCellValue(name); } } var memoryStream2 = new MemoryStream(); workbook.Write(memoryStream2, true); memoryStream2.Seek(0, SeekOrigin.Begin); templateStream = memoryStream2; } #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 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 + 3); var itemDic = itemResult.ConvertToDictionary(); var itemList = itemDic[dynamicColumnConfig.DynamicListName] as IList; foreach (var item in itemList) { var writeIndex = itemList.IndexOf(item) + dynamicColumnConfig.AutoColumnStartIndex; var itemDicName = itemDic[dynamicColumnConfig.DynamicItemDicName].ToString(); var itemValue = itemDic[dynamicColumnConfig.DynamicItemValueName].ToString(); 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 } /// /// 导出文件模板 /// /// /// public static async Task ExportTemplateAsync(ExportTemplateServiceDto inDto) { var (physicalPath, fileName) = await FileStoreHelper.GetCommonDocPhysicalFilePathAsync(inDto.hostEnvironment, inDto.commonDocumentRepository, inDto.TemplateCode); //模板路径 var tplPath = physicalPath; #region 根据中英文 删除模板sheet // 打开模板文件 var templateFile = new FileStream(tplPath, FileMode.Open, FileAccess.Read); // 获取文件流 var templateStream = new MemoryStream(); templateFile.CopyTo(templateStream); templateStream.Seek(0, SeekOrigin.Begin); var workbook = new XSSFWorkbook(templateStream); int sheetCount = workbook.NumberOfSheets; if (sheetCount == 2) { if (inDto.IsEnglish) { workbook.RemoveSheetAt(0); } else { workbook.RemoveSheetAt(1); } } #endregion ISheet sheet = workbook.GetSheetAt(0); // 获取第一个工作表 for (int i = 0; i < sheet.LastRowNum + 1; i++) { IRow row = sheet.GetRow(i); for (int j = 0; j < sheet.LastRowNum; j++) { ICell cell = row.GetCell(j); foreach (var property in inDto.Data.GetType().GetProperties()) { var value = property.GetValue(inDto.Data); if (cell != null && cell.ToString() == "{{" + property.Name + "}}") { sheet.GetRow(i).GetCell(j).SetCellValue(value.ToString()); } } } } 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") { FileDownloadName = $"{(string.IsNullOrEmpty(inDto.ExportFileName) ? "" : inDto.ExportFileName + "_")}{Path.GetFileNameWithoutExtension(fileName)}_{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx" }; } }