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

251 lines
7.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 枚举与状态字段规范
**背景**:系统历史上存在 int/string 枚举混用、description 与常量定义脱节、响应字段不统一等问题,导致前端映射错误、接口文档失真。本规范统一所有枚举相关写法。
---
## 1. 类型选择int vs string
### 选择规则
| 场景 | 类型 | 理由 |
|------|------|------|
| **状态类**:表示生命周期阶段(待支付→已完成→已关闭) | `int` | 便于范围查询、数值比较、DB 索引优化 |
| **布尔状态**:启用/禁用、激活/未激活 | `int` | 与全局常量统一,`0=禁用, 1=启用` |
| **类型/方式类**:支付方式、订单类型、运营商、平台 | `string` | 语义更清晰,无需记忆数字含义 |
| **标识符类**平台类型web/h5/all、角色来源 | `string` | 约定字符串值,自文档化 |
### 判断依据
```
这个字段表示"现在处于哪个阶段" → int
这个字段表示"它属于哪种类别/使用什么方式" → string
```
### ✅ 正确示例
```go
// 状态类 → 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"
```
### ❌ 错误示例
```go
// ❌ 状态用 string无法范围查询数字对比失效
Status string `json:"status"` // "pending" | "completed"
// ❌ 支付方式用 int前端必须维护不直观的数字映射
PaymentMethod int `json:"payment_method"` // 1=微信, 2=线下
```
---
## 2. Int 状态值约定
### 2.1 通用禁用/启用
**必须使用全局常量,禁止自定义**
```go
// pkg/constants/constants.go
StatusDisabled = 0 // 禁用
StatusEnabled = 1 // 启用
```
✅ 正确:
```go
Status int `gorm:"comment:状态(0-禁用 1-启用);default:1"`
```
❌ 禁止(与全局常量语义相反):
```go
// ❌ 不可以用 1=启用 2=禁用 这种方式
Status int `gorm:"comment:状态(1-启用 2-禁用)"`
```
### 2.2 生命周期状态
**1** 开始递增0 保留,避免与"未赋值/零值"混淆):
```go
// 充值状态(标准示例)
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=..."` 约束
```go
// pkg/constants/constants.go
const (
PaymentMethodWechat = "wechat" // 微信支付
PaymentMethodOffline = "offline" // 线下转账
)
// DTO 中
PaymentMethod string `json:"payment_method" validate:"required,oneof=wechat offline" description:"支付方式 (wechat:微信支付, offline:线下转账)"`
```
❌ 禁止:
```go
// ❌ 硬编码字符串
if record.PaymentMethod == "wechat" { ... }
// ❌ 大写或驼峰
const PaymentMethodWechat = "Wechat"
const PaymentMethodWechat = "WECHAT"
```
---
## 4. Constants 是唯一真相来源
**DTO 的 description 枚举列表必须与 `pkg/constants/` 定义完全一致。**
### 操作规程
1. 先在 `pkg/constants/` 定义(或查找已有)枚举常量及注释
2. 将常量的注释**原文抄写**到 DTO description
```go
// 步骤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:已退款)"`
```
### 禁止行为
```go
// ❌ description 中的枚举值与 constants 不一致(本次 bug 根因)
// constants: RechargeStatusCompleted=3已完成
// dto 写的: 3:已取消 ← 完全错误!
Status int `json:"status" description:"状态 (1:待支付, 2:已完成, 3:已取消)"`
```
---
## 5. description 格式标准
**统一格式**`字段含义 (值1:中文含义1, 值2:中文含义2, ...)`
规则:
- 必须用**中文圆括号外**、**英文括号内**
- 值和含义之间用**冒号** `:`,不用等号 `=`
- 多个值之间用**逗号加空格** `, `
- 含义必须是**中文**,不可用英文
```go
// ✅ 统一格式
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` 文字字段。**
这是防止前端映射错误的关键措施。
```go
// ✅ 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 "未知"
}
}
```
**字段命名约定**
- `status``status_name`
- `payment_status``payment_status_name`
- `commission_status``commission_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_text``status int` | 需补充 `status int` |
> ⚠️ 已有数据的状态起始值(如 `1-启用 2-禁用`)改变前必须做 DB 数据迁移,改动前先评估影响。