667 lines
25 KiB
C#
667 lines
25 KiB
C#
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<IFormFile> 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<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()
|
||
{
|
||
var result = new List<T>();
|
||
|
||
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<T>();
|
||
|
||
// 为 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<object>();
|
||
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<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.");
|
||
}
|
||
}
|
||
|
||
/// <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();
|
||
}
|
||
|
||
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
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取分数等级
|
||
/// </summary>
|
||
/// <typeparam name="T"></typeparam>
|
||
/// <param name="score"></param>
|
||
/// <returns></returns>
|
||
public static string GetRank<T>(this T score) where T : struct, IComparable
|
||
{
|
||
// 将 score 转换为 double 进行比较
|
||
double value = Convert.ToDouble(score);
|
||
|
||
return value switch
|
||
{
|
||
>= 90 => "优秀",
|
||
>= 80 => "良好",
|
||
>= 60 => "及格",
|
||
_ => "不及格"
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据等级名称返回枚举
|
||
/// </summary>
|
||
/// <param name="rankName"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="ArgumentException"></exception>
|
||
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]);
|
||
}
|
||
}
|
||
} |