本次提交完成 add-wallet-transfer-tag-models 提案的实施和归档: ## 新增功能模块 - 钱包系统:用户/代理钱包管理,支持充值、扣款、退款、乐观锁防并发 - 换卡记录:物联卡更换历史追溯,包含套餐快照(JSONB) - 标签系统:设备/IoT卡/号卡的统一标签管理 - 运营商渠道:四大运营商(CMCC/CUCC/CTCC/CBN)的渠道管理 ## 数据库变更 - 新增 6 张表:tb_wallet, tb_wallet_transaction, tb_recharge_record, tb_card_replacement_record, tb_tag, tb_resource_tag - 修改 2 张表:tb_carrier(新增渠道字段), tb_order(新增混合支付字段) - 迁移版本:v6 → v7(执行时间 282.5ms) ## 代码变更 - 新增 8 个 Go 模型(符合统一规范:gorm.Model + BaseModel) - 新增 40+ 个常量定义(含完整中文注释) - 新增 7 个 Redis Key 生成函数 - 修复模型规范:移除重复字段,统一使用 gorm.Model 嵌入 ## 文档变更 - 新增 3 个业务文档:数据模型设计、字段说明、迁移验证报告 - 更新 AGENTS.md:新增 Model 模型规范和常量注释规范 - 新增 4 个 OpenSpec 规范:wallet, carrier, card-replacement, tag - 更新 1 个 OpenSpec 规范:iot-order(支持混合支付) ## 验证通过 - ✅ LSP 诊断:所有模型和常量文件无错误 - ✅ OpenSpec 验证:openspec validate --strict 通过 - ✅ 迁移执行:表结构创建成功,索引正确 - ✅ 提案归档:2026-01-13-add-wallet-transfer-tag-models 变更文件统计:29 个文件,新增 3682 行
72 lines
4.3 KiB
Go
72 lines
4.3 KiB
Go
package model
|
||
|
||
import (
|
||
"database/sql/driver"
|
||
"encoding/json"
|
||
"time"
|
||
|
||
"gorm.io/gorm"
|
||
)
|
||
|
||
// PackageSnapshot 套餐快照,记录换卡时的套餐信息
|
||
type PackageSnapshot struct {
|
||
PackageID uint `json:"package_id"` // 套餐ID
|
||
PackageName string `json:"package_name"` // 套餐名称
|
||
PackageType string `json:"package_type"` // 套餐类型
|
||
DataQuota int64 `json:"data_quota"` // 流量额度(KB)
|
||
DataUsed int64 `json:"data_used"` // 已使用流量(KB)
|
||
ValidFrom time.Time `json:"valid_from"` // 生效时间
|
||
ValidTo time.Time `json:"valid_to"` // 失效时间
|
||
Price int64 `json:"price"` // 套餐价格(分)
|
||
RemainingDays int `json:"remaining_days"` // 剩余天数
|
||
TransferReason string `json:"transfer_reason,omitempty"` // 转移原因
|
||
}
|
||
|
||
// Value 实现 driver.Valuer 接口
|
||
func (p PackageSnapshot) Value() (driver.Value, error) {
|
||
return json.Marshal(p)
|
||
}
|
||
|
||
// Scan 实现 sql.Scanner 接口
|
||
func (p *PackageSnapshot) Scan(value interface{}) error {
|
||
if value == nil {
|
||
return nil
|
||
}
|
||
bytes, ok := value.([]byte)
|
||
if !ok {
|
||
return nil
|
||
}
|
||
return json.Unmarshal(bytes, p)
|
||
}
|
||
|
||
// CardReplacementRecord 换卡记录模型
|
||
// 记录物联卡更换历史,包含套餐快照便于追溯
|
||
// 支持损坏、丢失、故障等多种换卡原因,需要审批流程
|
||
type CardReplacementRecord struct {
|
||
gorm.Model
|
||
BaseModel `gorm:"embedded"`
|
||
ReplacementNo string `gorm:"column:replacement_no;type:varchar(50);not null;uniqueIndex:idx_card_replacement_no,where:deleted_at IS NULL;comment:换卡单号" json:"replacement_no"`
|
||
OldCardID uint `gorm:"column:old_card_id;not null;index:idx_card_replacement_old_card;comment:老卡ID" json:"old_card_id"`
|
||
OldIccid string `gorm:"column:old_iccid;type:varchar(50);not null;comment:老卡ICCID" json:"old_iccid"`
|
||
NewCardID uint `gorm:"column:new_card_id;not null;index:idx_card_replacement_new_card;comment:新卡ID" json:"new_card_id"`
|
||
NewIccid string `gorm:"column:new_iccid;type:varchar(50);not null;comment:新卡ICCID" json:"new_iccid"`
|
||
OldOwnerType string `gorm:"column:old_owner_type;type:varchar(20);not null;index:idx_card_replacement_old_owner,priority:1;comment:老卡所有者类型" json:"old_owner_type"`
|
||
OldOwnerID uint `gorm:"column:old_owner_id;not null;index:idx_card_replacement_old_owner,priority:2;comment:老卡所有者ID" json:"old_owner_id"`
|
||
OldAgentID *uint `gorm:"column:old_agent_id;comment:老卡代理ID" json:"old_agent_id,omitempty"`
|
||
NewOwnerType string `gorm:"column:new_owner_type;type:varchar(20);not null;index:idx_card_replacement_new_owner,priority:1;comment:新卡所有者类型" json:"new_owner_type"`
|
||
NewOwnerID uint `gorm:"column:new_owner_id;not null;index:idx_card_replacement_new_owner,priority:2;comment:新卡所有者ID" json:"new_owner_id"`
|
||
NewAgentID *uint `gorm:"column:new_agent_id;comment:新卡代理ID" json:"new_agent_id,omitempty"`
|
||
PackageSnapshot *PackageSnapshot `gorm:"column:package_snapshot;type:jsonb;comment:套餐快照" json:"package_snapshot,omitempty"`
|
||
ReplacementReason string `gorm:"column:replacement_reason;type:varchar(20);not null;comment:换卡原因 damaged-损坏 lost-丢失 malfunction-故障 upgrade-升级 other-其他" json:"replacement_reason"`
|
||
Remark *string `gorm:"column:remark;type:text;comment:备注" json:"remark,omitempty"`
|
||
Status int `gorm:"column:status;type:int;not null;default:1;index:idx_card_replacement_status;comment:换卡状态 1-待审批 2-已通过 3-已拒绝 4-已完成" json:"status"`
|
||
ApprovedBy *uint `gorm:"column:approved_by;comment:审批人ID" json:"approved_by,omitempty"`
|
||
ApprovedAt *time.Time `gorm:"column:approved_at;comment:审批时间" json:"approved_at,omitempty"`
|
||
CompletedAt *time.Time `gorm:"column:completed_at;comment:完成时间" json:"completed_at,omitempty"`
|
||
}
|
||
|
||
// TableName 指定表名
|
||
func (CardReplacementRecord) TableName() string {
|
||
return "tb_card_replacement_record"
|
||
}
|