2025-07-11 15:07:46 +08:00

568 lines
21 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using OfficeOpenXml;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace YD_AllHeartRates.Api.Utilities
{
public static class Tool
{
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<T>(Dictionary<string, List<T>> sheetDataList, List<string> 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<T>(worksheet, sheetData, fields);
}
return package.GetAsByteArray();
}
}
/// <summary>
/// 通用导入Excel
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="fileStream"></param>
/// <returns></returns>
public static List<T> ConvertExcelToList<T>(Stream fileStream) where T : new()
{
if (fileStream == null || !fileStream.CanRead || fileStream.Length == 0)
throw new Exception("文件流无效或为空。");
if (fileStream.CanSeek)
fileStream.Position = 0;
using var package = new ExcelPackage(fileStream);
if (package.Workbook.Worksheets.Count == 0)
throw new Exception("Excel 文件中不包含任何工作表。");
var worksheet = package.Workbook.Worksheets[1];
if (worksheet.Dimension == null)
throw new Exception("工作表中没有任何数据。");
var result = new List<T>();
var headerRow = worksheet.Cells[1, 1, 1, worksheet.Dimension.End.Column];
var headers = headerRow.Select(cell => cell.Text.Trim()).ToList();
var properties = typeof(T).GetProperties();
var displayNames = GetDisplayNames<T>();
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++)
{
// 跳过空行
bool isEmptyRow = true;
for (int col = 1; col <= worksheet.Dimension.End.Column; col++)
{
if (!string.IsNullOrWhiteSpace(worksheet.Cells[row, col].Text))
{
isEmptyRow = false;
break;
}
}
if (isEmptyRow)
continue;
var dataObject = new T();
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<object>();
var propertyType = property.PropertyType;
if (propertyType == typeof(DateTime?))
{
if (cellValue is double numericValue)
{
cellValue = DateTime.FromOADate(numericValue);
}
else if (cellValue is string stringValue)
{
if (DateTime.TryParseExact(stringValue, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var parsedDate) ||
DateTime.TryParseExact(stringValue, "M/d/yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out parsedDate))
{
cellValue = parsedDate;
}
else
{
throw new InvalidCastException($"无法将字符串 '{stringValue}' 转换为有效的日期。");
}
}
}
if (cellValue != null)
{
if (propertyType == typeof(DateTime?) && cellValue is DateTime dt)
{
property.SetValue(dataObject, dt);
}
else
{
var converted = Convert.ChangeType(cellValue, Nullable.GetUnderlyingType(propertyType) ?? propertyType);
property.SetValue(dataObject, converted);
}
}
}
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<string, string> GetDisplayNames<T>()
{
var displayNames = new Dictionary<string, string>();
var properties = typeof(T).GetProperties();
foreach (var property in properties)
{
var displayNameAttribute = property.GetCustomAttribute<DisplayAttribute>();
if (displayNameAttribute != null)
{
var propertyName = property.Name;
var displayName = displayNameAttribute.Name;
displayNames[propertyName] = displayName;
}
}
return displayNames;
}
/// <summary>
/// 导出Excel
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="worksheet"></param>
/// <param name="sheetData"></param>
/// <param name="fields"></param>
private static void ConfigureWorksheet<T>(ExcelWorksheet worksheet, IEnumerable<T> sheetData, List<string> fields)
{
// 添加表头
for (int i = 0; i < fields.Count; i++)
{
var fieldName = fields[i];
var displayName = GetDisplayName<T>(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<T>(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>(T obj, string propertyName)
{
var property = typeof(T).GetProperty(propertyName);
return property?.GetValue(obj);
}
/// <summary>
/// 获取类中所有得列名
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static List<string> GetPropertyNames<T>()
{
var propertyNames = new List<string>();
var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var property in properties)
{
// 获取属性上的 DisplayAttribute 特性
var displayAttribute = property.GetCustomAttribute<DisplayAttribute>();
// 检查 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}";
}
/// <summary>
/// 获取集合中位数
/// </summary>
/// <param name="values"></param>
/// <returns></returns>
public static double Median(this List<float> 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];
}
}
/// <summary>
/// 获取集合中位数
/// </summary>
/// <param name="values"></param>
/// <returns></returns>
public static double? Median(this List<double?> 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];
}
}
/// <summary>
/// 获取取样时间
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
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("时间转换失败");
}
}
/// <summary>
/// 获取枚举所有描述
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TEnum"></typeparam>
/// <param name="createItemFunc"></param>
/// <returns></returns>
public static List<T> GetEnumDescriptions<T, TEnum>(Func<int, string, T> createItemFunc) where TEnum : Enum
{
var enumDescriptions = new List<T>();
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;
}
/// <summary>
/// 获取枚举描述
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
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 ?? "";
}
/// <summary>
/// 测试类型枚举转换
/// </summary>
/// <param name="itemCode"></param>
/// <returns></returns>
//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<string, List<Dictionary<string, string>>> 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<Dictionary<string, string>> 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<T> WhereIF<T>(this IQueryable<T> query, bool condition, Expression<Func<T, bool>> predicate)
{
return condition ? query.Where(predicate) : query;
}
/// <summary>
/// DateTime转时间戳
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static long ToUnixTimeMilliseconds(this DateTime dateTime)
{
return new DateTimeOffset(dateTime).ToUnixTimeMilliseconds();
}
}
}