using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using OfficeOpenXml; using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Globalization; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text; using System.Threading.Tasks; using VOL.Core.Extensions; using VOL.Core.Services; using VOL.Entity.Enum; namespace VOL.Core.Utilities { public static class Tool { public static string Upload(IFormFile file, string filePath) { string fullPath = filePath.MapPath(true); //string fileName = $"{DateTime.Now.ToString("yyyyMMddHHmmssfff")}.{file.FileName.Split(".")[1]}"; //string fileName = file.FileName.Split(".")[0]; try { if (!Directory.Exists(fullPath)) Directory.CreateDirectory(fullPath); if (File.Exists(file.FileName)) File.Delete(file.FileName); using (var stream = new FileStream(fullPath + file.FileName, FileMode.Create)) { file.CopyTo(stream); } } catch (Exception ex) { Logger.Error($"上传文件失败:Tool.Upload,路径:{filePath},失败文件:{file},{ex.Message + ex.StackTrace}"); } return $"{filePath}{file.FileName}"; } //public static void BatchUpload(List files, string filePath) //{ // string fullPath = filePath.MapPath(true); // //string fileName = $"{DateTime.Now.ToString("yyyyMMddHHmmssfff")}.{file.FileName.Split(".")[1]}"; // try // { // if (!Directory.Exists(fullPath)) Directory.CreateDirectory(fullPath); // foreach (var file in files) // { // string fileName = file.FileName.Split(".")[0]; // if (File.Exists(fileName)) // File.Delete(fileName); // using (var stream = new FileStream(fullPath + fileName, FileMode.Create)) // { // file.CopyTo(stream); // } // } // } // catch (Exception ex) // { // Logger.Error($"上传文件失败:Tool.Upload,路径:{filePath},失败文件:{files},{ex.Message + ex.StackTrace}"); // } // //return $"{filePath}{fileName}{file.FileName.Split(".")[1]}"; //} public static byte[] UploadFile(IFormFile file) { if (file != null && file.Length > 0) { using (var memoryStream = new MemoryStream()) { file.CopyTo(memoryStream); var fileData = memoryStream.ToArray(); return fileData; } } else { throw new Exception("未选择文件或文件大小为零。"); } } public static byte[] ExportToExcel(Dictionary> sheetDataList, List fields) { using (var package = new ExcelPackage(new FileInfo("filename.xlsx"))) { var sheetCount = sheetDataList.Count; foreach (var sheet in sheetDataList) { var sheetData = sheetDataList[sheet.Key]; var sheetName = sheet.Key; var worksheet = package.Workbook.Worksheets.Add(sheetName); ConfigureWorksheet(worksheet, sheetData, fields); } return package.GetAsByteArray(); } } /// /// 通用导入Excel /// /// /// /// public static List ConvertExcelToList(Stream fileStream) where T : new() { var result = new List(); using (var package = new ExcelPackage(fileStream)) { var worksheet = package.Workbook.Worksheets[1]; // 第一个工作表 if (worksheet.Dimension == null) throw new InvalidOperationException("工作表中没有任何数据。"); // 获取表头(第一行) var headerRow = worksheet.Cells[1, 1, 1, worksheet.Dimension.End.Column]; var headers = headerRow.Select(cell => cell.Text?.Trim()).ToList(); // 获取实体属性与显示名称的映射 var displayNameToPropertyMap = GetDisplayNameToPropertyMap(); // 从第二行开始解析数据 for (int row = 2; row <= worksheet.Dimension.End.Row; row++) { var dataObject = new T(); for (int col = 1; col <= displayNameToPropertyMap.Count; col++) { var header = headers[col - 1]; if (string.IsNullOrEmpty(header)) continue; if (!displayNameToPropertyMap.TryGetValue(header, out var property)) continue; // 找不到对应属性,忽略该列 try { var cellValue = worksheet.Cells[row, col].GetValue(); var propertyType = property.PropertyType; // ----- 日期类型处理(支持 DateTime / DateTime?)----- if (propertyType == typeof(DateTime) || propertyType == typeof(DateTime?)) { DateTime? parsedDate = null; // 情况1:Excel 日期存储为 OADate 数字 if (cellValue is double numericValue) { parsedDate = DateTime.FromOADate(numericValue); } // 情况2:字符串格式的日期 else if (cellValue is string dateStr && !string.IsNullOrWhiteSpace(dateStr)) { // 支持多种常见日期格式 string[] formats = new[] { "yyyy/M/d", // 2025/4/28 "yyyy/MM/dd", // 2025/04/28 "M/d/yyyy", // 4/28/2025 "yyyy-MM-dd", // 2025-04-28 "dd/MM/yyyy", // 28/04/2025 "yyyyMMdd", // 20250428 "d/M/yyyy" // 28/4/2025 }; if (DateTime.TryParseExact(dateStr, formats, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime dt)) { parsedDate = dt; } else if (DateTime.TryParse(dateStr, out dt)) // 兜底尝试系统解析 { parsedDate = dt; } else { throw new InvalidCastException($"无法将字符串 '{dateStr}' 转换为有效的日期。"); } } // 情况3:已经是 DateTime 实例(极少情况) else if (cellValue is DateTime dtValue) { parsedDate = dtValue; } // 根据属性是否可空赋值 if (propertyType == typeof(DateTime)) { if (parsedDate.HasValue) property.SetValue(dataObject, parsedDate.Value); else throw new InvalidCastException($"单元格值为空,无法赋给非空 DateTime 属性 '{property.Name}'。"); } else // DateTime? { property.SetValue(dataObject, parsedDate); } // 日期处理完成,跳过后续通用类型转换 continue; } // ----- 其他类型(int, double, string, bool, 枚举等)----- if (cellValue != null) { // 目标类型是枚举 if (propertyType.IsEnum) { // 尝试按字符串或数值转换 if (cellValue is string enumStr) cellValue = Enum.Parse(propertyType, enumStr, true); else cellValue = Enum.ToObject(propertyType, Convert.ChangeType(cellValue, Enum.GetUnderlyingType(propertyType))); } else { // 常规类型转换(如 string -> int, double -> int 等) cellValue = Convert.ChangeType(cellValue, propertyType); } property.SetValue(dataObject, cellValue); } } catch (Exception ex) { throw new InvalidCastException( $"行 {row} 列 {col}(列名: {header}):转换 Excel 单元格值 '{worksheet.Cells[row, col].Text}' 到属性 '{property.Name}' 失败。", ex); } } result.Add(dataObject); } } return result; } private static Dictionary GetDisplayNameToPropertyMap() { var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance); var dict = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (var prop in properties) { // 优先获取 DisplayAttribute 的 Name var displayAttr = prop.GetCustomAttribute(); if (displayAttr != null && !string.IsNullOrEmpty(displayAttr.Name)) { dict[displayAttr.Name] = prop; continue; } // 其次获取 DisplayNameAttribute var displayNameAttr = prop.GetCustomAttribute(); if (displayNameAttr != null && !string.IsNullOrEmpty(displayNameAttr.DisplayName)) { dict[displayNameAttr.DisplayName] = prop; continue; } // 最后使用属性原名 dict[prop.Name] = prop; } return dict; } private static Dictionary GetDisplayNames() { var displayNames = new Dictionary(); var properties = typeof(T).GetProperties(); foreach (var property in properties) { var displayNameAttribute = property.GetCustomAttribute(); if (displayNameAttribute != null) { var propertyName = property.Name; var displayName = displayNameAttribute.Name; displayNames[propertyName] = displayName; } } return displayNames; } /// /// 导出Excel /// /// /// /// /// private static void ConfigureWorksheet(ExcelWorksheet worksheet, IEnumerable sheetData, List fields) { // 添加表头 for (int i = 0; i < fields.Count; i++) { var fieldName = fields[i]; var displayName = GetDisplayName(fieldName); worksheet.Cells[1, i + 1].Value = displayName; } // 添加数据行 var dataList = sheetData.ToList(); for (int rowIndex = 0; rowIndex < dataList.Count; rowIndex++) { var rowData = dataList[rowIndex]; for (int colIndex = 0; colIndex < fields.Count; colIndex++) { var fieldName = fields[colIndex]; var value = GetPropertyValue(rowData, fieldName); // 设置值时处理日期时间 if (value is DateTime dateTimeValue) { worksheet.Cells[rowIndex + 2, colIndex + 1].Value = dateTimeValue; worksheet.Cells[rowIndex + 2, colIndex + 1].Style.Numberformat.Format = "yyyy-mm-dd hh:mm:ss"; } else { worksheet.Cells[rowIndex + 2, colIndex + 1].Value = value; } } } // 自动调整列宽 worksheet.Cells.AutoFitColumns(); } private static string GetDisplayName(string propertyName) { var property = typeof(T).GetProperty(propertyName); if (property != null) { var displayNameAttribute = property.GetCustomAttributes(typeof(DisplayAttribute), false).FirstOrDefault() as DisplayAttribute; if (displayNameAttribute != null) { return displayNameAttribute.Name; } } return propertyName; } private static object GetPropertyValue(T obj, string propertyName) { var property = typeof(T).GetProperty(propertyName); return property?.GetValue(obj); } /// /// 获取类中所有得列名 /// /// /// public static List GetPropertyNames() { var propertyNames = new List(); var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var property in properties) { // 获取属性上的 DisplayAttribute 特性 var displayAttribute = property.GetCustomAttribute(); // 检查 DisplayAttribute 特性的名称是否为 "IgnoreColumnAttribute",如果是,则忽略该属性 if (displayAttribute != null && displayAttribute.Name.ToLower() == "ignorecolumnattribute") { continue; } propertyNames.Add(property.Name); } return propertyNames; } public static string NumberToChinese(this int number) { // 定义中文数字数组 string[] chineseNumbers = { "零", "一", "二", "三", "四", "五", "六", "七", "八", "九" }; // 如果数字在 0 到 9 之间,则直接返回中文数字 if (number >= 0 && number <= 9) { return chineseNumbers[number]; } else { // 如果数字不在 0 到 9 之间,则抛出异常 throw new ArgumentOutOfRangeException(nameof(number), "Number must be between 0 and 9."); } } public static string IncrementId(string maxId) { // 获取当前日期的前缀(年年年年+月月+日日) string datePrefix = DateTime.Now.ToString("yyyyMMdd"); // 提取后4位编号部分 string numberPart = maxId.Substring(maxId.Length - 4); // 将编号部分转为整数并加1 if (!int.TryParse(numberPart, out int number)) { throw new InvalidOperationException("编号部分格式不正确,应为数字"); } // 检查编号是否超出范围 if (number >= 9999) { throw new InvalidOperationException("编号已达到最大值"); } // 返回新的编号,保持当前日期前缀和递增后的编号 return $"{datePrefix}{(number + 1):D4}"; } /// /// 获取集合中位数 /// /// /// public static double Median(this List values) { var sortedValues = values.OrderBy(x => x).ToList(); int count = sortedValues.Count; if (count % 2 == 0) { return (sortedValues[count / 2 - 1] + sortedValues[count / 2]) / 2.0; } else { return sortedValues[count / 2]; } } /// /// 获取集合中位数 /// /// /// public static double? Median(this List values) { // 过滤掉 null 值 var sortedValues = values.Where(x => x.HasValue) .Select(x => x.Value) .OrderBy(x => x) .ToList(); // 如果列表为空,返回 null if (sortedValues.Count == 0) return null; int count = sortedValues.Count; // 计算中位数 if (count % 2 == 0) { return (sortedValues[count / 2 - 1] + sortedValues[count / 2]) / 2.0; } else { return sortedValues[count / 2]; } } /// /// 获取取样时间 /// /// /// /// public static DateTime GetDateTimeFromFixedAsh(this string input) { string timePart; // 判断字符串中是否包含 '-',以确定截取的位置 int dashIndex = input.IndexOf('-'); if (dashIndex != -1) { // 截取 '-' 之前的部分 timePart = input.Substring(6, dashIndex - 6); } else { // 如果没有 '-',则直接截取后面的8位数字 timePart = input.Substring(6, 8); } // 将截取的时间字符串转换为 DateTime 类型 DateTime result; if (DateTime.TryParseExact(timePart, "yyyyMMdd", null, System.Globalization.DateTimeStyles.None, out result)) { return result; } else { throw new ArgumentException("时间转换失败"); } } /// /// 获取枚举所有描述 /// /// /// /// /// public static List GetEnumDescriptions(Func createItemFunc) where TEnum : Enum { var enumDescriptions = new List(); foreach (TEnum value in Enum.GetValues(typeof(TEnum))) { int intValue = Convert.ToInt32(value); if (intValue >= 1) { var descriptionAttribute = value.GetType() .GetField(value.ToString()) .GetCustomAttributes(typeof(DescriptionAttribute), false) .FirstOrDefault() as DescriptionAttribute; if (descriptionAttribute != null) { var item = createItemFunc(intValue, descriptionAttribute.Description); enumDescriptions.Add(item); } } } return enumDescriptions; } /// /// 获取枚举描述 /// /// /// public static string GetDescription(this Enum value) { if (value == null) { throw new ArgumentNullException(nameof(value), "Enum value cannot be null"); } // 获取字段信息 FieldInfo field = value.GetType().GetField(value.ToString()); if (field == null) { // 如果字段信息为空,返回默认的描述 return ""; } // 获取 DescriptionAttribute 特性 var attributes = field.GetCustomAttributes(typeof(DescriptionAttribute), false); var attribute = attributes.FirstOrDefault() as DescriptionAttribute; // 如果特性为空,返回空字符串 return attribute?.Description ?? ""; } /// /// 测试类型枚举转换 /// /// /// //public static CategoryEnumType? GetCategoryEnumTypeByItemCode(string itemCode) //{ // if (Enum.TryParse(typeof(Ai_CategoryEnumType), itemCode, true, out var aiCategoryEnum)) // { // var aiCategoryName = Enum.GetName(typeof(Ai_CategoryEnumType), aiCategoryEnum); // if (Enum.TryParse(typeof(CategoryEnumType), aiCategoryName, true, out var categoryEnum)) // { // return (CategoryEnumType)categoryEnum; // } // } // return null; // 如果找不到对应的映射值,返回 null 或者抛出异常 //} public static byte[] DicExportToExcel(Dictionary>> sheetDataList) { using (var package = new ExcelPackage()) { foreach (var sheet in sheetDataList) { var sheetName = sheet.Key; var sheetData = sheet.Value; var worksheet = package.Workbook.Worksheets.Add(sheetName); DicConfigureWorksheet(worksheet, sheetData); } return package.GetAsByteArray(); } } private static void DicConfigureWorksheet(ExcelWorksheet worksheet, List> sheetData) { // 假设所有字典在List中都有相同的Key集合,我们可以从第一个元素获取表头 if (sheetData.Count > 0) { int rowIndex = 1; // 从第一行开始 var firstRow = sheetData[0]; // 添加表头 int columnIndex = 1; // 从第一列开始 foreach (var header in firstRow) { worksheet.Cells[1, columnIndex++].Value = header.Key; } // 添加数据行 foreach (var rowDict in sheetData) { rowIndex++; columnIndex = 1; // 重置列索引 foreach (var cell in rowDict) { worksheet.Cells[rowIndex, columnIndex].Value = cell.Value; // 检查是否需要设置日期时间格式 if (DateTime.TryParse(cell.Value, out DateTime dateTimeValue)) { worksheet.Cells[rowIndex, columnIndex].Style.Numberformat.Format = "yyyy-mm-dd hh:mm:ss"; } columnIndex++; } } // 自动调整列宽 worksheet.Cells[worksheet.Dimension.Address].AutoFitColumns(); } } public static DateTime GetQuarterStartDate(int quarter, int year) { return quarter switch { 1 => new DateTime(year, 1, 1), 2 => new DateTime(year, 4, 1), 3 => new DateTime(year, 7, 1), 4 => new DateTime(year, 10, 1), _ => throw new ArgumentOutOfRangeException() }; } public static DateTime GetQuarterEndDate(int quarter, int year) { return quarter switch { 1 => new DateTime(year, 3, 31), 2 => new DateTime(year, 6, 30), 3 => new DateTime(year, 9, 30), 4 => new DateTime(year, 12, 31), _ => throw new ArgumentOutOfRangeException() }; } public static IQueryable WhereIF(this IQueryable query, bool condition, Expression> predicate) { return condition ? query.Where(predicate) : query; } /// /// DateTime转时间戳 /// /// /// public static long ToUnixTimeMilliseconds(this DateTime dateTime) { return new DateTimeOffset(dateTime).ToUnixTimeMilliseconds(); } public static string GetEnumNameByValue(int value) { if (Enum.IsDefined(typeof(SportsTestItemType), value)) { return ((SportsTestItemType)value).ToString(); } return ""; // Return an empty string if the value is not defined in the enum } /// /// 获取分数等级 /// /// /// /// public static string GetRank(this T score) where T : struct, IComparable { // 将 score 转换为 double 进行比较 double value = Convert.ToDouble(score); return value switch { >= 90 => "优秀", >= 80 => "良好", >= 60 => "及格", _ => "不及格" }; } /// /// 根据等级名称返回枚举 /// /// /// /// public static AchievementRank GetEnumByRankName(string rankName) { return rankName switch { "优秀" => AchievementRank.Excellent, "良好" => AchievementRank.Fine, "及格" => AchievementRank.Pass, "不及格" => AchievementRank.Fail, _ => throw new ArgumentException("Invalid rank name", nameof(rankName)) // Throw exception for invalid rank name }; } public static string ToChineseNumber(this int number) { string[] chineseNumbers = { "零", "一", "二", "三", "四", "五", "六", "七", "八", "九" }; if (number <= 0) throw new ArgumentException("Number must be greater than zero."); if (number < 10) return chineseNumbers[number]; if (number < 20) return "十" + (number % 10 == 0 ? "" : chineseNumbers[number % 10]); int tens = number / 10; int units = number % 10; return chineseNumbers[tens] + "十" + (units == 0 ? "" : chineseNumbers[units]); } } }