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 Exception("工作表中没有任何数据。"); } // 获取 Excel 文件的表头(列名),假设第一行是表头 var headerRow = worksheet.Cells[1, 1, 1, worksheet.Dimension.End.Column]; var headers = headerRow.Select(cell => cell.Text.Trim()).ToList(); // 获取实体类的属性信息和 Display 属性的中文名 var properties = typeof(T).GetProperties(); var displayNames = GetDisplayNames(); // 为 Display 名称构建映射表(避免每次都做遍历) var displayNameToPropertyMap = properties .Where(p => displayNames.ContainsKey(p.Name)) .ToDictionary(p => displayNames[p.Name], p => p); // 从第二行开始解析数据(假设第一行是表头) for (int row = 2; row <= worksheet.Dimension.End.Row; row++) { var dataObject = new T(); // 遍历每一列,将 Excel 中的数据映射到实体类的属性上 for (int col = 1; col <= worksheet.Dimension.End.Column; col++) { var header = headers[col - 1]; if (displayNameToPropertyMap.TryGetValue(header, out var property)) { try { var cellValue = worksheet.Cells[row, col].GetValue(); var propertyType = property.PropertyType; // 处理 Excel 日期类型的特殊情况 if (propertyType == typeof(DateTime?)) { if (cellValue is double numericValue) { // 如果 Excel 中的值是数字(日期),将其转换为 DateTime 类型 cellValue = DateTime.FromOADate(numericValue); } else if (cellValue is string stringValue) { // 如果 Excel 单元格是字符串类型的日期(如 '2000-08-01') if (DateTime.TryParseExact(stringValue, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime parsedDate)) { cellValue = parsedDate; } else if (DateTime.TryParseExact(stringValue, "M/d/yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out parsedDate)) { cellValue = parsedDate; } else { // 无法解析为日期格式 throw new InvalidCastException($"无法将字符串 '{stringValue}' 转换为有效的日期。"); } } } // 确保转换后的类型与目标属性匹配 if (cellValue != null) { // 如果属性是 DateTime 类型并且值已经是 DateTime,无需再调用 Convert.ChangeType if (propertyType == typeof(DateTime?) && cellValue is DateTime?) { // 如果是日期类型,直接赋值 property.SetValue(dataObject, (DateTime?)cellValue); } else { // 尝试转换数据类型 cellValue = Convert.ChangeType(cellValue, propertyType); property.SetValue(dataObject, cellValue); } } } catch (Exception ex) { throw new InvalidCastException( $"行 {row} 列 {col}:转换 Excel 单元格值 '{worksheet.Cells[row, col].Text}' 到属性 '{property.Name}' 失败。", ex); } } } result.Add(dataObject); } } return result; } 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]); } } }