From df87c5654428bbbce1646bec69535ac39f0223c0 Mon Sep 17 00:00:00 2001
From: hang <872297557@qq.com>
Date: Fri, 5 Sep 2025 16:34:48 +0800
Subject: [PATCH 1/6] =?UTF-8?q?=E5=AF=BC=E8=A1=A8Excel=E5=A4=84=E7=90=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../FileDocProcess/ExcelExportHelper.cs | 450 ++++++-
.../IRaCIS.Core.Application.xml | 35 +-
.../Service/Common/ExcelExportService.cs | 1141 +++++++++--------
.../Service/QC/DTO/QCListViewModel.cs | 58 +-
.../Service/QC/_MapConfig.cs | 70 +-
5 files changed, 1185 insertions(+), 569 deletions(-)
diff --git a/IRaCIS.Core.Application/Helper/FileDocProcess/ExcelExportHelper.cs b/IRaCIS.Core.Application/Helper/FileDocProcess/ExcelExportHelper.cs
index 68ca83452..a0305fc0b 100644
--- a/IRaCIS.Core.Application/Helper/FileDocProcess/ExcelExportHelper.cs
+++ b/IRaCIS.Core.Application/Helper/FileDocProcess/ExcelExportHelper.cs
@@ -74,14 +74,15 @@ public static class ExcelExportHelper
{
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 itemValuePair in itemDic)
+ //{
+ // // 临床数据 1,1 会变成2024-01-01
+ // if (itemValuePair.Value?.ToString().Length > 8 && DateTime.TryParse(itemValuePair.Value?.ToString(), out DateTime result))
+ // {
+ // itemDic[itemValuePair.Key] = ExportExcelConverterDate.DateTimeInternationalToString(result);
+ // }
+ //}
foreach (var needTranslateProperty in needTranslatePropertyList)
@@ -242,6 +243,7 @@ public static class ExcelExportHelper
}
+
public class DynamicColumnConfig
{
///
@@ -254,13 +256,19 @@ public static class ExcelExportHelper
///
public int AutoColumnTitleRowIndex { get; set; }
-
+ ///
+ /// 模板列最后的索引
+ ///
public int TempalteLastColumnIndex { get; set; }
+ public bool IsCDISCExport { get; set; } = false;
+
+ //public List CDISCList { get; set; } = new List();
+
///
- /// 动态的列名
+ /// 动态的列名 如果Id 重复,那么就按照名称填充,否则就按照Id 填充列数据
///
- public List ColumnNameList { get; set; } = new List();
+ public List ColumnIdNameList { get; set; }
///
/// 动态翻译的字典名
@@ -287,7 +295,31 @@ public static class ExcelExportHelper
///
public string DynamicItemTitleName { get; set; }
+ public string DynamicItemTitleId { get; set; }
+
public List RemoveColunmIndexList { get; set; } = new List();
+
+ public class ColumItem
+ {
+ public Guid Id { get; set; }
+ public string Name { get; set; }
+
+ public string CDISCCode { get; set; }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is not ColumItem other) return false;
+ return Id == other.Id && Name == other.Name;
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(Id, Name);
+ }
+ }
+
+ public List ColumnIdList => ColumnIdNameList == null ? new List() : ColumnIdNameList.Select(t => t.Id.ToString()).ToList();
+ public List ColumnNameList => ColumnIdNameList == null ? new List() : ColumnIdNameList.Select(t => t.Name).ToList();
}
@@ -334,14 +366,14 @@ public static class ExcelExportHelper
//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 itemValuePair in itemDic)
+ //{
+ // if (itemValuePair.Value?.ToString().Length > 8 && DateTime.TryParse(itemValuePair.Value?.ToString(), out DateTime result))
+ // {
+ // itemDic[itemValuePair.Key] = ExportExcelConverterDate.DateTimeInternationalToString(result);
+ // }
+ //}
foreach (var needTranslateProperty in needTranslatePropertyList)
{
@@ -420,7 +452,7 @@ public static class ExcelExportHelper
workbook.RemoveSheetAt(1);
}
- //中文替换项目术语
+ #region 中文替换项目术语
if (data.TrialObjectNameList?.Count > 0)
{
var replaceObjectList = data.TrialObjectNameList;
@@ -456,21 +488,378 @@ public static class ExcelExportHelper
}
}
}
+ #endregion
+
+
if (dynamicColumnConfig != null)
{
+ //var isCdics = dynamicColumnConfig.CDISCList.Count > 0;
+
+ var isCdics = dynamicColumnConfig.IsCDISCExport;
+
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.ColumnNameList.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 = originRemoveEndIndex; i < originRemoveEndIndex + needAddCount; i++)
+ {
+
+ titelRow.CreateCell(i + 1);
+ templateRow.CreateCell(i + 1);
+
+ if (isCdics)
+ {
+ cdicsRow.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);
+
+ if (isCdics)
+ {
+ cdicsRow.GetCell(i).SetCellValue(cdicsRow.GetCell(i - gap).StringCellValue);
+ }
+ }
+
+
+
+ //设置动态Tilte
+
+ for (int i = dynamicColunmStartIndex; i < dynamicColunmStartIndex + needAddCount; i++)
+ {
+
+ var name = dynamicColumnConfig.ColumnIdNameList[i - dynamicColunmStartIndex].Name;
+
+ titelRow.GetCell(i).SetCellValue(name);
+ templateRow.GetCell(i).SetCellValue("");
+
+ if (isCdics)
+ {
+ var cdicsCode = dynamicColumnConfig.ColumnIdNameList[i - dynamicColunmStartIndex].CDISCCode;
+
+ cdicsRow.GetCell(i).SetCellValue(cdicsCode);
+ }
+ }
+
+ }
+
+
+ using (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("testmini.xlsx", templateStream.ToArray(), translateData);
+
+ await MiniExcel.SaveAsByTemplateAsync(memoryStream, templateStream.ToArray(), translateData, config);
+
+
+ memoryStream.Seek(0, SeekOrigin.Begin);
+
+ if (dynamicColumnConfig != null)
+ {
+ //Excel 列是按照名称填充 还是Id 填充
+ var isExcelAddDataWithName = dynamicColumnConfig.ColumnIdNameList.Select(t => t.Id).Distinct().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.ContainsKey(dynamicColumnConfig.DynamicItemDicName) ? 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
+ }
+
+ ///
+ /// 暂时废弃--合并到上面
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ 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