You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

443 lines
14 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// ============================================================================
// 【文件说明】HwPortalAjaxResult.cs - Ajax 统一响应结果类
// ============================================================================
// 这个类用于统一所有 API 接口的返回格式。
// 在 Java 若依RuoYi框架中有一个 AjaxResult 类做同样的事情。
//
// 统一返回格式的好处:
// 1. 前端可以用同一套逻辑处理所有接口响应
// 2. 便于统一添加日志、监控、错误处理
// 3. 接口文档更清晰,返回结构可预测
//
// 返回的 JSON 结构示例:
// 成功:{ "code": 200, "msg": "操作成功", "data": { ... } }
// 失败:{ "code": 500, "msg": "操作失败", "data": null }
// 警告:{ "code": 301, "msg": "警告信息", "data": null }
// ============================================================================
namespace Admin.NET.Plugin.HwPortal;
/// <summary>
/// Ajax 统一响应结果类。
/// <para>
/// 【设计模式 - 静态工厂方法模式】
/// 这个类大量使用了"静态工厂方法"设计模式:
/// - Success() 返回成功结果
/// - Error() 返回失败结果
/// - Warn() 返回警告结果
///
/// 对比 Java
/// Java 中你可能会写:
/// AjaxResult result = new AjaxResult();
/// result.put("code", 200);
/// result.put("msg", "操作成功");
///
/// C# 这里用静态工厂方法更优雅:
/// return HwPortalAjaxResult.Success("操作成功", data);
///
/// 好处:
/// 1. 代码更简洁,一行搞定
/// 2. 避免忘记设置 code/msg
/// 3. 可以在工厂方法里统一加日志、校验等逻辑
/// </para>
/// </summary>
public class HwPortalAjaxResult
{
/// <summary>
/// 返回码字段名。
/// <para>
/// 【C# 语法知识点 - const 常量】
/// const 是"编译期常量",值在编译时就确定了,不能修改。
///
/// 对比 Java
/// Java 写法public static final String CODE_TAG = "code";
/// C# 写法public const string CodeTag = "code";
///
/// const 和 readonly 的区别:
/// - const编译期确定值直接嵌入调用处类似宏替换
/// - readonly运行时确定可以在构造函数中赋值
///
/// 这里用 const 是因为字段名永远不会变,编译期确定更高效。
/// </para>
/// 与原 Java AjaxResult 的 CODE_TAG 对齐。
/// </summary>
public const string CodeTag = "code";
/// <summary>
/// 返回消息字段名。
/// 与原 Java AjaxResult 的 MSG_TAG 对齐。
/// </summary>
public const string MsgTag = "msg";
/// <summary>
/// 返回数据字段名。
/// 与原 Java AjaxResult 的 DATA_TAG 对齐。
/// </summary>
public const string DataTag = "data";
/// <summary>
/// 成功状态码。
/// HTTP 200 OK 的含义是"请求成功",这里借用这个惯例。
/// </summary>
public const int SuccessCode = 200;
/// <summary>
/// 警告状态码。
/// RuoYi 默认使用 301 作为 warnHTTP 301 是重定向,但这里只是借用数字)。
/// 警告通常表示"操作部分成功"或"需要用户注意但不阻断"的情况。
/// </summary>
public const int WarnCode = 301;
/// <summary>
/// 错误状态码。
/// HTTP 500 Internal Server Error 的含义是"服务器内部错误"。
/// 这里用于表示"操作失败"的业务错误。
/// </summary>
public const int ErrorCode = 500;
/// <summary>
/// 状态码。
/// <para>
/// 【C# 语法知识点 - 自动属性】
/// public int Code { get; set; }
/// 这是 C# 的"自动属性"语法,编译器自动生成后备字段和 get/set 方法。
///
/// 对比 Java
/// Java 需要手写 getter/setter
/// private int code;
/// public int getCode() { return code; }
/// public void setCode(int code) { this.code = code; }
/// </para>
/// </summary>
public int Code { get; set; }
/// <summary>
/// 返回消息。
/// </summary>
public string Msg { get; set; }
/// <summary>
/// 返回数据。
/// <para>
/// 【C# 语法知识点 - object 类型】
/// object 是 C# 的"根类型",所有类型都继承自 object。
/// 类似 Java 的 Object但 C# 的 object 可以是值类型int, bool 等)。
///
/// 为什么用 object
/// 因为 Data 可以是任何类型:
/// - 单个对象:{ "id": 1, "name": "张三" }
/// - 列表:[{ "id": 1 }, { "id": 2 }]
/// - 字符串:"操作成功"
/// - null没有数据
///
/// 使用 object 可以容纳所有可能的数据类型。
/// </para>
/// </summary>
public object Data { get; set; }
/// <summary>
/// 无参构造函数。
/// <para>
/// 【C# 语法知识点 - 构造函数】
/// 构造函数名称必须与类名相同,没有返回类型。
///
/// 对比 Java
/// Java 和 C# 的构造函数语法几乎一致。
///
/// 为什么需要无参构造函数?
/// 某些序列化框架(如 JSON 反序列化)需要无参构造函数来创建对象,
/// 然后再通过属性赋值。
/// </para>
/// </summary>
public HwPortalAjaxResult()
{
}
/// <summary>
/// 带参数的构造函数。
/// <para>
/// 【C# 语法知识点 - 可选参数 data = null】
/// object data = null 中的 = null 是"默认参数值"。
/// 调用时可以不传这个参数,自动使用默认值 null。
///
/// 对比 Java
/// Java 不支持可选参数,需要写多个重载构造函数:
/// public HwPortalAjaxResult(int code, String msg) { this(code, msg, null); }
/// public HwPortalAjaxResult(int code, String msg, Object data) { ... }
///
/// C# 一个构造函数就搞定了,更简洁。
/// </para>
/// </summary>
/// <param name="code">状态码</param>
/// <param name="msg">返回消息</param>
/// <param name="data">返回数据,默认为 null</param>
public HwPortalAjaxResult(int code, string msg, object data = null)
{
Code = code;
Msg = msg;
Data = data;
}
/// <summary>
/// 返回成功结果(默认消息)。
/// <para>
/// 【C# 语法知识点 - 静态工厂方法】
/// public static HwPortalAjaxResult Success()
/// 这是一个静态方法,返回类本身的实例。
///
/// 为什么用静态工厂方法而不是直接 new
/// 1. 命名更清晰Success() 比 new AjaxResult(200, "操作成功") 更易读
/// 2. 可以缓存常用实例(这里没做,但可以扩展)
/// 3. 可以返回子类(这里没用到,但这是工厂模式的优势)
///
/// 对比 Java
/// Java 的静态工厂方法写法一样:
/// public static AjaxResult success() { return new AjaxResult(200, "操作成功"); }
/// </para>
/// </summary>
/// <returns>成功结果实例</returns>
public static HwPortalAjaxResult Success()
{
// 方法重载链:调用带消息参数的版本
return Success("操作成功");
}
/// <summary>
/// 返回成功结果(带数据)。
/// </summary>
/// <param name="data">返回数据</param>
/// <returns>成功结果实例</returns>
public static HwPortalAjaxResult Success(object data)
{
return Success("操作成功", data);
}
/// <summary>
/// 返回成功结果(带自定义消息)。
/// </summary>
/// <param name="msg">返回消息</param>
/// <returns>成功结果实例</returns>
public static HwPortalAjaxResult Success(string msg)
{
return Success(msg, null);
}
/// <summary>
/// 返回成功结果(完整参数)。
/// <para>
/// 【C# 语法知识点 - 对象初始化器】
/// new HwPortalAjaxResult { Code = ..., Msg = ..., Data = ... }
/// 这是"对象初始化器"语法,可以在创建对象时直接给属性赋值。
///
/// 对比 Java
/// Java 需要这样写:
/// HwPortalAjaxResult result = new HwPortalAjaxResult();
/// result.setCode(SuccessCode);
/// result.setMsg(msg);
/// result.setData(data);
/// return result;
///
/// C# 一行搞定,更简洁。
/// </para>
/// </summary>
/// <param name="msg">返回消息</param>
/// <param name="data">返回数据</param>
/// <returns>成功结果实例</returns>
public static HwPortalAjaxResult Success(string msg, object data)
{
return new HwPortalAjaxResult
{
Code = SuccessCode,
Msg = msg,
Data = data
};
}
/// <summary>
/// 返回警告结果(仅消息)。
/// </summary>
/// <param name="msg">警告消息</param>
/// <returns>警告结果实例</returns>
public static HwPortalAjaxResult Warn(string msg)
{
return Warn(msg, null);
}
/// <summary>
/// 返回警告结果(带数据)。
/// </summary>
/// <param name="msg">警告消息</param>
/// <param name="data">返回数据</param>
/// <returns>警告结果实例</returns>
public static HwPortalAjaxResult Warn(string msg, object data)
{
return new HwPortalAjaxResult
{
Code = WarnCode,
Msg = msg,
Data = data
};
}
/// <summary>
/// 返回错误结果(默认消息)。
/// </summary>
/// <returns>错误结果实例</returns>
public static HwPortalAjaxResult Error()
{
return Error("操作失败");
}
/// <summary>
/// 返回错误结果(自定义消息)。
/// </summary>
/// <param name="msg">错误消息</param>
/// <returns>错误结果实例</returns>
public static HwPortalAjaxResult Error(string msg)
{
return Error(msg, null);
}
/// <summary>
/// 返回错误结果(带数据)。
/// </summary>
/// <param name="msg">错误消息</param>
/// <param name="data">返回数据</param>
/// <returns>错误结果实例</returns>
public static HwPortalAjaxResult Error(string msg, object data)
{
return new HwPortalAjaxResult
{
Code = ErrorCode,
Msg = msg,
Data = data
};
}
/// <summary>
/// 返回错误结果(自定义状态码)。
/// </summary>
/// <param name="code">自定义状态码</param>
/// <param name="msg">错误消息</param>
/// <returns>错误结果实例</returns>
public static HwPortalAjaxResult Error(int code, string msg)
{
return new HwPortalAjaxResult
{
Code = code,
Msg = msg,
Data = null
};
}
/// <summary>
/// 根据影响行数返回成功或失败结果。
/// <para>
/// 【业务场景】
/// 在数据库操作中,增删改会返回"影响行数"
/// - rows > 0表示操作成功有数据被修改
/// - rows = 0表示操作失败没有数据被修改
///
/// 这个方法把"影响行数"转换为"响应结果",简化控制器代码:
/// return ToAjax(await service.Insert(input));
///
/// 对比 Java 若依:
/// 若依的 BaseController.toAjax(int rows) 做同样的事情。
/// </para>
/// </summary>
/// <param name="rows">数据库影响行数</param>
/// <returns>成功或失败结果</returns>
public static HwPortalAjaxResult FromRows(int rows)
{
// 【三元运算符】
// condition ? valueIfTrue : valueIfFalse
// 和 Java 完全一样的语法。
//
// WhyRuoYi 的 BaseController.toAjax(int rows) 只根据影响行数返回成功/失败,
// 不会把 rows 本身塞进 data这里必须保持同一口径否则前端判断会漂移。
return rows > 0 ? Success() : Error();
}
/// <summary>
/// 判断是否成功。
/// </summary>
/// <returns>是否成功</returns>
public bool IsSuccess()
{
return Code == SuccessCode;
}
/// <summary>
/// 判断是否警告。
/// </summary>
/// <returns>是否警告</returns>
public bool IsWarn()
{
return Code == WarnCode;
}
/// <summary>
/// 判断是否错误。
/// </summary>
/// <returns>是否错误</returns>
public bool IsError()
{
return Code == ErrorCode;
}
/// <summary>
/// 链式设置字段值(兼容原 Java AjaxResult 的 put 方法)。
/// <para>
/// 【C# 语法知识点 - 链式调用】
/// 这个方法返回 this可以链式调用
/// result.Put("code", 200).Put("msg", "成功");
///
/// 对比 Java
/// Java 若依的 AjaxResult 继承自 HashMap可以
/// result.put("code", 200).put("msg", "成功");
///
/// C# 这里用强类型对象实现,只对常见字段做兼容。
/// </para>
/// <para>
/// 【C# 语法知识点 - StringComparison.OrdinalIgnoreCase】
/// OrdinalIgnoreCase 表示"忽略大小写的序号比较"。
/// 这样 "Code" 和 "code" 会被视为相同,提高容错性。
///
/// 对比 Java
/// Java 用 equalsIgnoreCase() 方法:
/// key.equalsIgnoreCase(CodeTag)
/// </para>
/// </summary>
/// <param name="key">字段名</param>
/// <param name="value">字段值</param>
/// <returns>当前实例,支持链式调用</returns>
public HwPortalAjaxResult Put(string key, object value)
{
// 【字符串比较的最佳实践】
// string.Equals(a, b, StringComparison.OrdinalIgnoreCase)
// 比 a.ToLower() == b.ToLower() 更高效,不会产生新字符串对象。
if (string.Equals(key, CodeTag, StringComparison.OrdinalIgnoreCase))
{
// 【类型转换】
// Convert.ToInt32 可以处理多种类型string, long, double 等。
// CultureInfo.InvariantCulture 表示使用"不变的格式规则"
// 避免不同地区的数字格式差异(如某些地区用逗号作小数点)。
Code = Convert.ToInt32(value, CultureInfo.InvariantCulture);
return this;
}
if (string.Equals(key, MsgTag, StringComparison.OrdinalIgnoreCase))
{
Msg = Convert.ToString(value, CultureInfo.InvariantCulture);
return this;
}
if (string.Equals(key, DataTag, StringComparison.OrdinalIgnoreCase))
{
Data = value;
}
return this;
}
}