Files
junhong_cmp_fiber/docs/enum-status-standards.md
huang e9ff14df0e
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled
规范: 新增枚举与状态字段规范并修复代理充值状态描述错误
- 新增 docs/enum-status-standards.md:完整的枚举/状态规范,涵盖 int vs string 选择、起始值约定、description 格式统一、constants 唯一真相来源、Response DTO 必须提供 status_name
- 更新 dto-standards SKILL.md:加入枚举规范要点,AI 写 DTO 时自动触发
- 更新 AGENTS.md:常量管理章节和 Code Review 检查清单各加入枚举检查项
- 修复 agent_recharge_dto.go:description 从错误的 3 个状态改为正确的 5 个状态(原 3:已取消 实为 3:已完成)
- 修复 agent_recharge service:toResponse 补充 StatusName 中文字段,防止前端映射出错
2026-04-11 11:25:58 +08:00

7.8 KiB
Raw Permalink Blame History

枚举与状态字段规范

背景:系统历史上存在 int/string 枚举混用、description 与常量定义脱节、响应字段不统一等问题,导致前端映射错误、接口文档失真。本规范统一所有枚举相关写法。


1. 类型选择int vs string

选择规则

场景 类型 理由
状态类:表示生命周期阶段(待支付→已完成→已关闭) int 便于范围查询、数值比较、DB 索引优化
布尔状态:启用/禁用、激活/未激活 int 与全局常量统一,0=禁用, 1=启用
类型/方式类:支付方式、订单类型、运营商、平台 string 语义更清晰,无需记忆数字含义
标识符类平台类型web/h5/all、角色来源 string 约定字符串值,自文档化

判断依据

这个字段表示"现在处于哪个阶段" → int
这个字段表示"它属于哪种类别/使用什么方式" → string

正确示例

// 状态类 → int
Status        int    `json:"status"`          // 充值状态1=待支付, 2=已支付...
PaymentStatus int    `json:"payment_status"`  // 订单支付状态

// 类型/方式类 → string
PaymentMethod string `json:"payment_method"`  // "wechat" | "offline"
OrderType     string `json:"order_type"`      // "single_card" | "device"
Platform      string `json:"platform"`        // "web" | "h5" | "all"

错误示例

// ❌ 状态用 string无法范围查询数字对比失效
Status string `json:"status"` // "pending" | "completed"

// ❌ 支付方式用 int前端必须维护不直观的数字映射
PaymentMethod int `json:"payment_method"` // 1=微信, 2=线下

2. Int 状态值约定

2.1 通用禁用/启用

必须使用全局常量,禁止自定义

// pkg/constants/constants.go
StatusDisabled = 0 // 禁用
StatusEnabled  = 1 // 启用

正确:

Status int `gorm:"comment:状态(0-禁用 1-启用);default:1"`

禁止(与全局常量语义相反):

// ❌ 不可以用 1=启用 2=禁用 这种方式
Status int `gorm:"comment:状态(1-启用 2-禁用)"`

2.2 生命周期状态

1 开始递增0 保留,避免与"未赋值/零值"混淆):

// 充值状态(标准示例)
const (
    RechargeStatusPending   = 1 // 待支付
    RechargeStatusPaid      = 2 // 已支付
    RechargeStatusCompleted = 3 // 已完成
    RechargeStatusClosed    = 4 // 已关闭
    RechargeStatusRefunded  = 5 // 已退款
)

2.3 特殊值

  • 跳跃值(如 99)仅用于明确需要人工干预的异常状态,必须加注释说明原因
  • 禁止在同一枚举中混用 0 起始和 1 起始

3. String 枚举值约定

  • 全小写字母 + 下划线 snake_case(禁止驼峰、禁止大写)
  • 必须在 pkg/constants/ 定义常量,禁止硬编码字符串
  • DTO 中必须加 validate:"oneof=..." 约束
// pkg/constants/constants.go
const (
    PaymentMethodWechat  = "wechat"   // 微信支付
    PaymentMethodOffline = "offline"  // 线下转账
)

// DTO 中
PaymentMethod string `json:"payment_method" validate:"required,oneof=wechat offline" description:"支付方式 (wechat:微信支付, offline:线下转账)"`

禁止:

// ❌ 硬编码字符串
if record.PaymentMethod == "wechat" { ... }

// ❌ 大写或驼峰
const PaymentMethodWechat = "Wechat"
const PaymentMethodWechat = "WECHAT"

4. Constants 是唯一真相来源

DTO 的 description 枚举列表必须与 pkg/constants/ 定义完全一致。

操作规程

  1. 先在 pkg/constants/ 定义(或查找已有)枚举常量及注释
  2. 将常量的注释原文抄写到 DTO description
// 步骤1constants.go 中定义
const (
    RechargeStatusPending   = 1 // 待支付
    RechargeStatusPaid      = 2 // 已支付
    RechargeStatusCompleted = 3 // 已完成
    RechargeStatusClosed    = 4 // 已关闭
    RechargeStatusRefunded  = 5 // 已退款
)

// 步骤2DTO description 从上面抄写,格式统一
Status int `json:"status" description:"状态 (1:待支付, 2:已支付, 3:已完成, 4:已关闭, 5:已退款)"`

禁止行为

// ❌ description 中的枚举值与 constants 不一致(本次 bug 根因)
// constants: RechargeStatusCompleted=3已完成
// dto 写的:  3:已取消  ← 完全错误!
Status int `json:"status" description:"状态 (1:待支付, 2:已完成, 3:已取消)"`

5. description 格式标准

统一格式字段含义 (值1:中文含义1, 值2:中文含义2, ...)

规则:

  • 必须用中文圆括号外英文括号内
  • 值和含义之间用冒号 :,不用等号 =
  • 多个值之间用逗号加空格 ,
  • 含义必须是中文,不可用英文
// ✅ 统一格式
Status       int    `description:"状态 (1:待支付, 2:已支付, 3:已完成, 4:已关闭, 5:已退款)"`
Platform     string `description:"适用端口 (all:全部, web:Web后台, h5:H5端)"`
UserType     int    `description:"用户类型 (1:超级管理员, 2:平台用户, 3:代理账号, 4:企业账号)"`

// ❌ 格式混乱
Status int `description:"状态 (0=禁用, 1=启用)"`       // 用等号
Status int `description:"0=禁用 1=启用"`               // 无括号无逗号
Status int `description:"状态0待生效 1生效中 2已用完"` // 格式不统一

6. Response DTO 的状态字段

所有 Response DTO 中的 int 状态字段,必须同时提供对应的 xxx_name 文字字段。

这是防止前端映射错误的关键措施。

// ✅ Response DTO 标准写法
type AgentRechargeResponse struct {
    Status     int    `json:"status"      description:"状态 (1:待支付, 2:已支付, 3:已完成, 4:已关闭, 5:已退款)"`
    StatusName string `json:"status_name" description:"状态名称(中文)"`
    // ...
}

// Service 层 toResponse 函数中赋值
func statusName(status int) string {
    switch status {
    case constants.RechargeStatusPending:
        return "待支付"
    case constants.RechargeStatusPaid:
        return "已支付"
    case constants.RechargeStatusCompleted:
        return "已完成"
    case constants.RechargeStatusClosed:
        return "已关闭"
    case constants.RechargeStatusRefunded:
        return "已退款"
    default:
        return "未知"
    }
}

字段命名约定

  • statusstatus_name
  • payment_statuspayment_status_name
  • commission_statuscommission_status_name

例外Request DTO查询过滤、创建请求不需要 _name 字段。


7. Code Review 检查项

□ int/string 类型选择是否符合规则?
□ 禁/启用是否用了 0=禁用, 1=启用?(禁止 1=启用, 2=禁用)
□ string 枚举常量是否在 pkg/constants/ 定义?
□ dto description 是否从 constants 注释原文抄写?
□ description 格式是否统一(冒号、逗号、括号)?
□ Response DTO 是否同时有 status int 和 status_name string
□ 是否有遗漏的枚举值没有在 description 中列出?

8. 现存已知不一致(技术债,待修复)

文件 问题 正确值
internal/model/shop_package_allocation.go 1-启用 2-禁用 应改为 0-禁用 1-启用
internal/model/system.go 1-启用 2-禁用 需确认是否改 DB
internal/model/dto/agent_recharge_dto.go description 2:已完成, 3:已取消 应为 2:已支付, 3:已完成, 4:已关闭, 5:已退款
internal/model/dto/asset_wallet_dto.go 只有 status_textstatus int 需补充 status int

⚠️ 已有数据的状态起始值(如 1-启用 2-禁用)改变前必须做 DB 数据迁移,改动前先评估影响。