218 lines
7.0 KiB
C#
Raw Normal View History

2026-05-21 15:52:36 +08:00
using System.Text.Json.Serialization;
2026-05-22 14:29:22 +08:00
namespace FileShare_Common.Core
2026-05-21 15:52:36 +08:00
{
/// <summary>
/// 统一端点响应契约。
/// </summary>
public interface IApiResponse
{
/// <summary>是否成功。</summary>
bool Success { get; }
/// <summary>业务状态码。</summary>
int Code { get; }
}
2026-05-21 15:52:36 +08:00
/// <summary>
/// 统一 API 返回格式。
/// 所有接口的返回都包装为此格式,确保前端收到一致的数据结构。
/// </summary>
/// <typeparam name="T">业务数据类型</typeparam>
public class ApiResponse<T> : IApiResponse
2026-05-21 15:52:36 +08:00
{
/// <summary>是否成功</summary>
[JsonPropertyName("success")]
public bool Success { get; set; }
/// <summary>HTTP 状态码</summary>
[JsonPropertyName("code")]
public int Code { get; set; }
/// <summary>消息(成功时可为 null失败时包含错误描述</summary>
[JsonPropertyName("message")]
public string? Message { get; set; }
/// <summary>业务数据</summary>
[JsonPropertyName("data")]
public T? Data { get; set; }
/// <summary>时间戳</summary>
[JsonPropertyName("timestamp")]
public DateTime Timestamp { get; set; } = DateTime.Now;
/// <summary>请求追踪 ID用于排查问题</summary>
[JsonPropertyName("traceId")]
public string? TraceId { get; set; }
// ---- 快捷工厂方法 ----
/// <summary>成功返回(有数据)</summary>
public static ApiResponse<T> Ok(T data, string? message = null)
{
return new ApiResponse<T>
{
Success = true,
Code = 200,
Message = message,
Data = data,
};
}
/// <summary>失败返回</summary>
public static ApiResponse<T> Fail(int code, string message, T? data = default)
{
return new ApiResponse<T>
{
Success = false,
Code = code,
Message = message,
Data = data,
};
}
/// <summary>400 参数错误</summary>
public static ApiResponse<T> BadRequest(string message = "参数错误")
=> Fail(400, message);
/// <summary>401 未授权</summary>
public static ApiResponse<T> Unauthorized(string message = "未授权")
=> Fail(401, message);
/// <summary>403 无权限</summary>
public static ApiResponse<T> Forbidden(string message = "无权限")
=> Fail(403, message);
/// <summary>404 未找到</summary>
public static ApiResponse<T> NotFound(string message = "资源不存在")
=> Fail(404, message);
/// <summary>500 服务器内部错误</summary>
public static ApiResponse<T> ServerError(string message = "服务器内部错误")
=> Fail(500, message);
}
/// <summary>
/// 无数据的统一返回格式object? 版本)。
/// </summary>
public class ApiResponse : ApiResponse<object?>
{
/// <summary>成功返回(无数据)</summary>
public static ApiResponse Succeed(string? message = null)
{
return new ApiResponse
{
Success = true,
Code = 200,
Message = message,
Data = null,
};
}
/// <summary>失败返回</summary>
public static ApiResponse Failure(int code, string message)
{
return new ApiResponse
{
Success = false,
Code = code,
Message = message,
Data = null,
};
}
}
/// <summary>
/// 分页返回格式
/// </summary>
public class PagedResponse<T> : IApiResponse
2026-05-21 15:52:36 +08:00
{
/// <summary>
/// 获取或设置操作是否成功。
/// </summary>
[JsonPropertyName("success")]
public bool Success { get; set; } = true;
/// <summary>
/// 获取或设置业务状态码,默认 200。
/// </summary>
[JsonPropertyName("code")]
public int Code { get; set; } = 200;
/// <summary>
/// 获取或设置分页数据项列表。
/// </summary>
[JsonPropertyName("items")]
public List<T> Items { get; set; } = new();
/// <summary>
/// 获取或设置数据总条数。
/// </summary>
[JsonPropertyName("total")]
public int Total { get; set; }
/// <summary>
/// 获取或设置当前页码,从 1 开始。
/// </summary>
[JsonPropertyName("page")]
public int Page { get; set; } = 1;
/// <summary>
/// 获取或设置每页条数,默认 20。
/// </summary>
[JsonPropertyName("pageSize")]
public int PageSize { get; set; } = 20;
/// <summary>
/// 获取总页数(根据 Total 和 PageSize 自动计算)。
/// </summary>
[JsonPropertyName("totalPages")]
public int TotalPages => PageSize > 0 ? (int)Math.Ceiling((double)Total / PageSize) : 0;
/// <summary>
/// 从数据列表和分页参数创建分页响应。
/// </summary>
/// <param name="items">当前页数据项。</param>
/// <param name="total">数据总条数。</param>
/// <param name="page">当前页码。</param>
/// <param name="pageSize">每页条数。</param>
/// <returns>分页响应实例。</returns>
public static PagedResponse<T> From(List<T> items, int total, int page, int pageSize)
{
return new PagedResponse<T>
{
Items = items,
Total = total,
Page = page,
PageSize = pageSize,
};
}
}
/// <summary>
/// 端点返回辅助方法 —— 在 AppEndpoints 中快捷构建统一响应。
/// </summary>
public static class ResponseHelper
{
/// <summary>成功返回</summary>
public static ApiResponse<T> Ok<T>(T data, string? message = null)
=> ApiResponse<T>.Ok(data, message);
/// <summary>成功返回(无数据)</summary>
public static ApiResponse Succeed(string? message = null)
=> ApiResponse.Succeed(message);
/// <summary>失败返回</summary>
public static ApiResponse<T> Fail<T>(int code, string message, T? data = default)
=> ApiResponse<T>.Fail(code, message, data);
/// <summary>失败返回(无数据)</summary>
public static ApiResponse Failure(int code, string message)
=> ApiResponse.Failure(code, message);
/// <summary>分页返回</summary>
public static PagedResponse<T> Paged<T>(List<T> items, int total, int page, int pageSize)
=> PagedResponse<T>.From(items, total, page, pageSize);
}
}