Easy.Common.Core
2026.4.18.1
dotnet add package Easy.Common.Core --version 2026.4.18.1
NuGet\Install-Package Easy.Common.Core -Version 2026.4.18.1
<PackageReference Include="Easy.Common.Core" Version="2026.4.18.1" />
<PackageVersion Include="Easy.Common.Core" Version="2026.4.18.1" />
<PackageReference Include="Easy.Common.Core" />
paket add Easy.Common.Core --version 2026.4.18.1
#r "nuget: Easy.Common.Core, 2026.4.18.1"
#:package Easy.Common.Core@2026.4.18.1
#addin nuget:?package=Easy.Common.Core&version=2026.4.18.1
#tool nuget:?package=Easy.Common.Core&version=2026.4.18.1
Easy.Common.Core
常用方法封装库,提供了一些常用的扩展方法和工具类,帮助开发者提高开发效率。
安装
<PackageReference Include="Easy.Common.Core" Version="2025.12.11.2" />
1. 通用结果类
1.1 ApiResult
//通用结果类ApiResult<T>,默认ApiResult<string>
ApiResult.Ok();
ApiResult.Ok(new { Id = 1, Name = "张三" });
ApiResult.Ok(new { Id = 1, Name = "张三" },"成功");
ApiResult.Fail("失败");
ApiResult.Fail("失败",HttpStatusCode.InternalServerError);
ApiResult.Fail("失败", new { Id = 1, Name = "张三" });
ApiResult.Fail("失败", new { Id = 1, Name = "张三" }, HttpStatusCode.InternalServerError);
1.2 ApiResultPlus
ApiResultPlus<TSuccess, TError> 是一个扩展的通用结果类,用于处理可能返回两种不同类型结果的场景:成功结果和错误结果。它的作用是提供一种更灵活的方式来封装操作结果,尤其是在需要区分成功和失败的情况下。
作用 区分成功和失败的结果类型:
TSuccess 表示成功时返回的数据类型。 TError 表示失败时返回的数据类型。 简化结果处理逻辑:
通过 Match 方法,可以分别对成功和失败的结果进行处理,而无需手动检查状态。 提高代码可读性:
使用 ApiResultPlus 可以让代码更清晰地表达操作的意图,避免混淆成功和失败的处理逻辑。 示例解释 以下代码展示了 ApiResultPlus 的使用:
public ApiResult GetResult(int type)
{
// 创建 ApiResultPlus 实例,表示成功返回类型为 string,失败返回类型为 ErrorInfo(成功和失败的两个类型可以是任意类型,但不能是相同类型)
var result = new ApiResultPlus<string, ErrorInfo>();
// 模拟业务逻辑
if (type == 1)
result = "成功"; // 设置成功数据
else
result = ErrorInfo.Error("发生错误"); // 设置失败信息
//使用扩展方法快速转换为 ApiResult
return result.ToApiResult();
// 或使用 Match 方法处理成功和失败的结果
var res = result.Match(
success =>
{
// 处理成功情况
return ApiResult.Ok(success); // 返回成功的 ApiResult
},
error =>
{
// 处理失败情况
return ApiResult.Fail(error.Msg, error.Data); // 返回失败的 ApiResult
}
);
return res; // 返回处理后的结果
}
1.2.1 swagger不显示nuget包类注释解决
//1.增加SchemaFilter
/// <summary>
/// ApiResult统一返回结构的SchemaFilter
/// </summary>
public class ApiResultSchemaFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (!context.Type.Name.StartsWith("ApiResult", StringComparison.OrdinalIgnoreCase))
return;
schema.Description = "统一返回结构";
foreach (var prop in schema.Properties)
{
var key = prop.Key.ToLowerInvariant(); // 忽略大小写
switch (key)
{
case "success":
prop.Value.Description = "是否成功";
break;
case "msg":
prop.Value.Description = "返回消息";
break;
case "data":
prop.Value.Description = "数据内容";
break;
case "statecode":
prop.Value.Description = "HTTP状态码";
break;
case "traceid":
prop.Value.Description = "消息唯一码";
break;
}
}
}
}
//2.在Swagger中注册SchemaFilter
services.AddSwaggerGen(c =>
{
c.SchemaFilter<ApiResultSchemaFilter>(); // 注册SchemaFilter
});
1.3 其他通用类
//分页
IPageList<T>
2. 常用扩展方法
// 空值判断
bool isStringNull = "".IsNull(); // 返回 true
List<int> list = new List<int>();
bool isListNull = list.IsNull(); // 返回 true
object obj = null;
bool isObjectNull = obj.IsNull(); // 返回 true
bool isStringNotNull = "Hello".IsNotNull(); // 返回 true
List<int> list2 = new List<int> { 1, 2, 3 };
bool isListNotNull = list2.IsNotNull(); // 返回 true
object obj2 = new object();
bool isObjectNotNull = obj2.IsNotNull(); // 返回 true
// 判断字符串是否为手机号码
bool isMobile = "12345678910".IsMobile(); // 返回 true
// 检测是否符合email格式
bool isEmailValid = "test@example.com".IsValidEmail(); // 返回 true
// 检测是否是正确的Url
bool isUrlValid = "https://www.example.com".IsUrl(); // 返回 true
// string 转 int 数组
int[] intArray = "1,2,3,4".StringToIntArray(); // 返回 {1, 2, 3, 4}
// String 转 string 数组
string[] stringArray = "apple,banana,orange".StringToStringArray(); // 返回 {"apple", "banana", "orange"}
// String 数组转 Int 数组
int[] intArrayFromStrArray = new string[] { "1", "2", "3" }.StringArrAyToIntArray(); // 返回 {1, 2, 3}
// string 转 Guid 数组
Guid[] guidArray = "f47ac10b-58cc-4372-a567-0e02b2c3d479,f47ac10b-58cc-4372-a567-0e02b2c3d480".StringToGuidArray(); // 返回 [{Guid1}, {Guid2}]
// 获取32位md5加密
string md5_32 = "password".Md5For32(); // 返回 32位的 MD5 字符串
// 获取16位md5加密
string md5_16 = "password".Md5For16(); // 返回 16位的 MD5 字符串
// 清除HTML中指定样式
string cleanHtml = "<div style='color:red;'>Text</div>".ClearHtml(new string[] { "style" }); // 返回 "<div>Text</div>"
// list 随机排序方法
List<int> sortedList = new List<int> { 1, 2, 3, 4, 5 }.RandomSortList(); // 返回随机排序的 List
// 截前后字符(串)
string interceptedText = "hello world".GetCaptureInterceptedText("world", all: true); // 返回 "hello"
// 密码加密方法
string encryptedPassword = "password".EnPassword(DateTime.Now); // 返回加密后的密码
// URL编码
string encodedUrl = "https://example.com?name=value".UrlEncode(); // 返回 URL 编码的字符串
// 获取10位时间戳
long timestamp10 = FoundationExtensions.GetTimeStampByTotalSeconds(); // 返回当前时间的10位时间戳
// 获取13位时间戳
long timestamp13 = FoundationExtensions.GetTimeStampByTotalMilliseconds(); // 返回当前时间的13位时间戳
// HmacSHA256加密
string hmacSHA256 = FoundationExtensions.HmacSHA256(1609459200, "secret"); // 返回 HMACSHA256 加密后的字符串
3. 时间扩展类
// 获取当前的毫秒时间戳
string msectime = DateTimeExtensions.Msectime(); // 返回当前的毫秒时间戳
// 获取剩余多久时间的文字描述
string remainingTimeDescription = DateTimeExtensions.GetRemainingTime(DateTime.Now.AddHours(1)); // 返回类似 "1小时0分0秒"
// 获取剩余多久时间的具体时间类型
int day, hours, minute, seconds;
DateTimeExtensions.GetBackTime(DateTime.Now.AddHours(1), out day, out hours, out minute, out seconds); // 返回具体的天、小时、分钟、秒
// 计算时间戳剩余多久时间
string timeAgo = DateTimeExtensions.TimeAgo(DateTime.Now.AddHours(-2)); // 返回类似 "2小时前"
// 获取当前是星期几
string currentWeek = DateTimeExtensions.GetWeek(); // 返回 "周一", "周二", "周三" 等
//获取两个时间间隔秒数(double,类型 如果需要int类型可以(int)seconds)
double seconds = DateTimeExtensions.GetSeconds(DateTime.Now, DateTime.Now.AddMinutes(5)); // 返回 300
4. 字典工具类
// 创建一个对象用于测试
var obj = new { Name = "Alice", Age = 28, Occupation = "Engineer" };
// 使用 DictionaryExtensions 类转换对象为字典
IDictionary<string, object> dictionary = DictionaryExtensions.ToDictonary(obj);
// 输出字典内容
foreach (var kvp in dictionary)
{
Console.WriteLine($"{kvp.Key}: {kvp.Value}");
}
// 输出:
// Name: Alice
// Age: 28
// Occupation: Engineer
5. 加密解密帮助类
// 原始文本
string plainText = "Hello, this is a secret message!";
// 使用 EncryptionExtensions 加密并缩短文本
string encryptedText = EncryptionExtensions.EncryptAndShorten(plainText);
Console.WriteLine("Encrypted and Shortened Text: " + encryptedText);
// 使用 EncryptionExtensions 解密并还原文本
string decryptedText = EncryptionExtensions.DecryptAndUnshorten(encryptedText);
Console.WriteLine("Decrypted and Unshortened Text: " + decryptedText);
// 输出结果:
// Encrypted and Shortened Text: <Base64Url Encoded Encrypted Data>
// Decrypted and Unshortened Text: Hello, this is a secret message!
6. 文件帮助类
// 获取文件夹名称
string filePath = @"C:\Users\Example\Documents\sample.txt";
string directoryName = FileExtensions.GetDirectoryName(filePath);
Console.WriteLine("文件夹名称: " + directoryName);
// 输出: 文件夹名称: C:\Users\Example\Documents
// 获取文件夹下的所有文件
string[] files = FileExtensions.GetFiles(@"C:\Users\Example\Documents", "*.txt", SearchOption.AllDirectories);
Console.WriteLine("文件列表: " + string.Join(", ", files));
// 获取文件内容
string fileContent = FileExtensions.GetFileConnent(filePath);
Console.WriteLine("文件内容: " + fileContent);
// 获取文件信息
FileInfo? fileInfo = FileExtensions.GetFileInfo(filePath);
if (fileInfo != null)
{
Console.WriteLine("文件大小: " + fileInfo.Length + " 字节");
}
// 文件备份
bool backupSuccess = FileExtensions.FileBackup(filePath);
Console.WriteLine("文件备份成功: " + backupSuccess);
// 获取文件内容(异步)
Task.Run(async () =>
{
string asyncFileContent = await FileExtensions.GetFileConnentAsync(filePath);
Console.WriteLine("异步获取的文件内容: " + asyncFileContent);
});
// 创建文件
string newFilePath = @"C:\Users\Example\Documents\newfile.txt";
string content = "你好,这是一个新文件!";
FileExtensions.CreateFile(newFilePath, content);
Console.WriteLine("新文件已创建,路径为: " + newFilePath);
// 创建文件夹
string newFolderPath = @"C:\Users\Example\Documents\NewFolder";
FileExtensions.CreateDirectory(newFolderPath);
Console.WriteLine("文件夹已创建,路径为: " + newFolderPath);
7. 数据转换
// 1. 将对象转换为基本数据类型
object obj1 = "123";
int intValue = obj1.ToInt(); // intValue = 123
object obj2 = "12345678901234";
long longValue = obj2.ToLong(); // longValue = 12345678901234
object obj3 = "3.14";
double doubleValue = obj3.ToDouble(); // doubleValue = 3.14
object obj4 = "Hello, World!";
string stringValue = obj4.ToStringValue(); // stringValue = "Hello, World!"
object obj5 = "10.5";
decimal decimalValue = obj5.ToDecimal(); // decimalValue = 10.5
object obj6 = "2025-04-28";
DateTime dateValue = obj6.ToDate(); // dateValue = 2025-04-28
object obj7 = "true";
bool boolValue = obj7.ToBool(); // boolValue = true
Console.WriteLine($"intValue: {intValue}, longValue: {longValue}, doubleValue: {doubleValue}, stringValue: {stringValue}, decimalValue: {decimalValue}, dateValue: {dateValue},boolValue: {boolValue}");
// 2. 将字典转换为实体对象
var dict = new Dictionary<string, object>
{
{ "Id", 1 },
{ "Name", "John Doe" },
{ "Age", 30 }
};
var person = dict.ToEntity<Person>(); // Person: Id = 1, Name = "John Doe", Age = 30
Console.WriteLine($"Person: Id = {person.Id}, Name = {person.Name}, Age = {person.Age}");
// 3. 将字典列表转换为实体对象列表
var dictList = new List<Dictionary<string, object>>()
{
new Dictionary<string, object>
{
{ "Id", 1 },
{ "Name", "John Doe" },
{ "Age", 30 }
},
new Dictionary<string, object>
{
{ "Id", 2 },
{ "Name", "Jane Smith" },
{ "Age", 28 }
}
};
var peopleList = dictList.ToList<Person>(); // peopleList 包含两个 Person 对象
foreach (var p in peopleList)
{
Console.WriteLine($"Person: Id = {p.Id}, Name = {p.Name}, Age = {p.Age}");
}
// 4. 将字符串转换为指定类型
string strValue = "123.45";
double doubleResult = strValue.ToType(typeof(double)); // doubleResult = 123.45
string dateString = "2025-04-28";
DateTime dateResult = (DateTime)dateString.ToType(typeof(DateTime)); // dateResult = 2025-04-28
Console.WriteLine($"doubleResult: {doubleResult}, dateResult: {dateResult}");
// 5. 将字符串转换为数值类型
string str = "100";
int? intValueNullable = str.ToValue<int>(); // intValueNullable = 100
string boolStr = "true";
bool? boolValueNullable = boolStr.ToValue<bool>(); // boolValueNullable = true
string decimalStr = "50.75";
decimal? decimalValueNullable = decimalStr.ToValue<decimal>(); // decimalValueNullable = 50.75
Console.WriteLine($"intValueNullable: {intValueNullable}, boolValueNullable: {boolValueNullable}, decimalValueNullable: {decimalValueNullable}");
// 6. 处理 null 值的转换
object nullValue = null;
int defaultIntValue = nullValue.ToInt(); // defaultIntValue = 0
object dbNullValue = DBNull.Value;
DateTime defaultDateValue = dbNullValue.ToDate(); // defaultDateValue = DateTime.MinValue
Console.WriteLine($"defaultIntValue: {defaultIntValue}, defaultDateValue: {defaultDateValue}");
8. 钉钉推送
//初始化
private DingTalkExtensions _dingTalkExtend = new DingTalkExtensions("src", "accessToken");
//每个方法都有bool返回值,表示是否发送成功
//发送文本消息
await _dingTalkExtend.SendTextMsgAsync("测试消息");
//发送链接消息
await _dingTalkExtend.SendLinkMsgAsync("测试标题", "测试内容", "图片地址", "消息跳转地址");
//发送markdown消息
await _dingTalkExtend.SendMarkdownMsgAsync("测试标题", "#测试内容(MD格式)");
9. HttpClientFactoryExtensions扩展
// IHttpClientFactory 已经在 DI 容器中注册(如果没有注册 下边调用的时候服务名空着就行,然后url写全地址)
// services.AddHttpClient("服务名称", c => { c.BaseAddress = new Uri("https://example.com"); });
//Get请求
var result = await _httpClientFactory.GetAsync<MyResponse>("服务名称", "/api/get");
// Post请求
// JSON
var resultJson = await _httpClientFactory.PostAsync<MyResponse>("服务名称", "/api/json", new { id = 1 });
// Form
var resultForm = await _httpClientFactory.PostFormAsync<MyResponse>("服务名称", "/api/form", new { id = 1, name = "Tom" });
// 单文件上传
var file = new FileParameter { Content = File.ReadAllBytes("test.png"), FileName = "test.png" };
var resultFile = await _httpClientFactory.PostMultipartAsync<MyResponse>("服务名称", "/api/file", new { file });
// 多文件上传 + 表单字段
var files = new[] { new FileParameter { Content = File.ReadAllBytes("a.png"), FileName = "a.png" } };
var resultMulti = await _httpClientFactory.PostMultipartAsync<MyResponse>("服务名称", "/api/multi", new { id = 123, files });
10. HttpClientExtensions扩展
用于直接扩展 HttpClient,不依赖 IHttpClientFactory 的服务名,适合你已经拿到 HttpClient 实例的场景。
using Easy.Common.Core;
using FileParameter = Easy.Common.Core.HttpClientFactoryExtensions.FileParameter;
var client = new HttpClient
{
BaseAddress = new Uri("https://example.com")
};
// GET 请求
var getResult = await client.GetAsync<MyResponse>("/api/get");
// POST JSON
var postJsonResult = await client.PostAsync<MyResponse>("/api/json", new { id = 1, name = "Tom" });
// POST Form
var postFormResult = await client.PostFormAsync<MyResponse>("/api/form", new { id = 1, name = "Tom" });
// 单文件上传
var file = new FileParameter
{
Content = File.ReadAllBytes("test.png"),
FileName = "test.png",
ContentType = "image/png"
};
var singleFileResult = await client.PostMultipartAsync<MyResponse>("/api/file", new { file });
// 多文件上传 + 表单字段
var files = new[]
{
new FileParameter { Content = File.ReadAllBytes("a.png"), FileName = "a.png", ContentType = "image/png" },
new FileParameter { Content = File.ReadAllBytes("b.png"), FileName = "b.png", ContentType = "image/png" }
};
var multiFileResult = await client.PostMultipartAsync<MyResponse>("/api/multi", new { id = 123, files });
说明:
- 所有方法在响应失败时会抛出异常(内部调用 EnsureSuccessStatusCode)。
- 当泛型返回类型 T 为 string 时,直接返回原始响应字符串。
- 其他返回类型默认使用 System.Text.Json 反序列化(驼峰命名、大小写不敏感)。
- 支持 CancellationToken 参数,可用于超时控制或请求取消。
11. NumberExtensions 数字扩展
// 保留小数位(四舍五入)
decimal d1 = 12.3456m;
double d2 = 12.3456;
var r1 = d1.RoundTo(2); // 12.35
var r2 = d2.RoundTo(3); // 12.346
// 判断是否在范围内(包含边界)
bool between1 = 10.IsBetween(1, 20); // true
bool between2 = 20.IsBetween(1, 20); // true
// 数值钳制
int clamped1 = 120.Clamp(0, 100); // 100
int clamped2 = (-5).Clamp(0, 100); // 0
// 判断 double 是否是有效数字
bool valid1 = 12.3.IsValidNumber(); // true
bool valid2 = double.NaN.IsValidNumber(); // false
bool valid3 = double.PositiveInfinity.IsValidNumber(); // false
// 添加正负符号
string sign1 = 123.45m.WithSign(); // "+123.45"
string sign2 = (-123.45m).WithSign(); // "-123.45"
string sign3 = 0m.WithSign(); // "0"
// 添加正负符号并保留小数位
string signFixed1 = 12.345m.WithSignAndDigits(2); // "+12.35"
string signFixed2 = (-12.345).WithSignAndDigits(2); // "-12.35"
// 固定小数位输出
string fixed1 = 12.3m.ToFixed(2); // "12.30"
string fixed2 = 12.3.ToFixed(4); // "12.3000"
string fixed3 = "12.3456".ToFixed(2); // "12.35"
12. HttpContextExtensions 请求上下文扩展
适用于 ASP.NET Core 场景,用于从 HttpContext 中快速获取客户端 IP、当前用户信息、Claim、请求地址和 User-Agent 等常见数据。
using System.Security.Claims;
using Easy.Common.Core;
app.MapGet("/context-demo", (HttpContext context) =>
{
var clientIp = context.GetClientIp();// 获取客户端 IP 地址
var userId = context.GetUserId();// 获取当前登录用户的 Id
var userName = context.GetUserName();// 获取当前登录用户的名称
var isAuthenticated = context.IsAuthenticated();// 判断当前请求是否已认证
var role = context.GetClaimValue(ClaimTypes.Role);// 获取当前用户的角色
var requestUrl = context.GetRequestUrl();// 获取当前请求的完整地址
var userAgent = context.GetUserAgent();// 获取当前请求的 User-Agent
return ApiResult.Ok(new
{
ClientIp = clientIp,
UserId = userId,
UserName = userName,
IsAuthenticated = isAuthenticated,
Role = role,
RequestUrl = requestUrl,
UserAgent = userAgent
});
});
12.1 GetClientIp
按以下顺序获取客户端 IP:
- X-Forwarded-For 请求头的第一个 IP
- X-Real-IP 请求头
- HttpContext.Connection.RemoteIpAddress
string ip = context.GetClientIp();
说明:
- 当服务部署在 Nginx、网关、负载均衡或反向代理之后时,通常会优先从代理头中取值。
- 如果 X-Forwarded-For 中包含多个 IP,例如 "client, proxy1, proxy2",该方法会返回第一个客户端 IP。
- 如果没有取到任何地址,则返回 "未知IP"。
12.2 GetUserId
从当前登录用户的 ClaimTypes.NameIdentifier 中读取用户 Id。
string userId = context.GetUserId();
说明:
- 适用于认证成功后把用户主键写入 NameIdentifier Claim 的场景。
- 如果当前请求未登录,或没有对应 Claim,则返回 null。
12.3 GetUserName
获取当前用户名称,本质上读取的是 context.User.Identity.Name。
string userName = context.GetUserName();
12.4 IsAuthenticated
判断当前请求是否已通过认证。
bool isAuthenticated = context.IsAuthenticated();
12.5 GetClaimValue
按 Claim 类型读取指定 Claim 值,适合读取角色、租户、邮箱、手机号等自定义身份信息。
string role = context.GetClaimValue(ClaimTypes.Role);
string email = context.GetClaimValue(ClaimTypes.Email);
string tenantId = context.GetClaimValue("tenant_id");
12.6 GetRequestUrl
获取当前请求的完整地址,包含协议、域名、路径和查询字符串。
string url = context.GetRequestUrl();
// 示例: https://api.example.com/order/list?page=1&pageSize=20
12.7 GetUserAgent
获取当前请求头中的 User-Agent。
string userAgent = context.GetUserAgent();
典型用途:
- 接口访问日志记录
- 用户操作审计
- 终端来源识别
- 风控与设备识别
13. EnumExtensions 枚举扩展
using System.ComponentModel;
public enum OrderStatus
{
[Description("待支付")]
Pending = 1,
[Description("已支付")]
Paid = 2,
Canceled = 3
}
var status1 = OrderStatus.Pending;
var status2 = OrderStatus.Canceled;
// 获取 Description 特性描述;若没有 Description,则返回枚举名称
string text1 = status1.GetDescription(); // "待支付"
string text2 = status2.GetDescription(); // "Canceled"
详细文档请访问 项目主页。
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Easy.Common.Core:
| Package | Downloads |
|---|---|
|
Easy.SqlSugar.Core
基于SqlSugar进行封装使用 |
|
|
Easy.Cache.Core
直接使用CsRedis/MemoryCache缓存内置自动切换 |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated | |
|---|---|---|---|
| 2026.4.18.1 | 284 | 4/18/2026 | |
| 2026.3.30.1 | 170 | 3/30/2026 | |
| 2026.3.23.1 | 97 | 3/23/2026 | |
| 2026.3.18.3 | 170 | 3/18/2026 | |
| 2026.3.18.2 | 91 | 3/18/2026 | |
| 2026.3.18.1 | 95 | 3/18/2026 | |
| 2025.12.11.2 | 506 | 12/11/2025 | |
| 2025.12.11.1 | 430 | 12/11/2025 | |
| 2025.12.5.1 | 208 | 12/5/2025 | |
| 2025.12.2.1 | 676 | 12/2/2025 | |
| 2025.11.25.1 | 244 | 11/25/2025 | |
| 2025.5.6.1 | 1,049 | 5/6/2025 | |
| 2025.4.30.5 | 196 | 4/30/2025 | |
| 2025.4.30.4 | 196 | 4/30/2025 | |
| 2025.4.30.3 | 186 | 4/30/2025 | |
| 2025.4.30.2 | 206 | 4/30/2025 | |
| 2025.4.30.1 | 183 | 4/30/2025 | |
| 2025.4.29.2 | 206 | 4/29/2025 | |
| 2025.4.29.1 | 206 | 4/29/2025 | |
| 2025.4.28.3 | 200 | 4/28/2025 |
常用方法封装