feat(wallet,tag): 钱包和标签系统多租户改造
核心变更: - 钱包表:删除 user_id,添加 resource_type/resource_id(绑定资源而非用户) - 标签表:添加 enterprise_id/shop_id(实现三级隔离:全局/企业/店铺) - GORM Callback:自动数据权限过滤 - 迁移脚本:可重复执行,已验证回滚功能 钱包归属重构原因: - 旧设计:钱包绑定用户账号,个人客户卡/设备转手后新用户无法使用余额 - 新设计:钱包绑定资源(卡/设备/店铺),余额随资源流转 标签三级隔离: - 平台全局标签:所有用户可见 - 企业标签:仅该企业可见(企业内唯一) - 店铺标签:该店铺及下级可见(店铺内唯一) 测试覆盖: - 9 个单元测试验证标签多租户过滤(全部通过) - 迁移和回滚功能测试通过(测试环境) - OpenSpec 验证通过 变更 ID: fix-wallet-tag-multi-tenant 迁移版本: 000008 参考: openspec/changes/archive/2026-01-13-fix-wallet-tag-multi-tenant/
This commit is contained in:
@@ -6,13 +6,15 @@ import (
|
||||
|
||||
// Tag 标签模型
|
||||
// 用于设备、IoT卡、号卡的分类标记,支持自定义颜色
|
||||
// UsageCount 字段记录标签使用次数,便于展示热门标签
|
||||
// 支持企业、店铺、平台三级隔离
|
||||
type Tag struct {
|
||||
gorm.Model
|
||||
BaseModel `gorm:"embedded"`
|
||||
Name string `gorm:"column:name;type:varchar(100);not null;uniqueIndex:idx_tag_name,where:deleted_at IS NULL;comment:标签名称" json:"name"`
|
||||
Color *string `gorm:"column:color;type:varchar(20);comment:标签颜色(十六进制)" json:"color,omitempty"`
|
||||
UsageCount int `gorm:"column:usage_count;type:int;not null;default:0;index:idx_tag_usage;comment:使用次数" json:"usage_count"`
|
||||
BaseModel `gorm:"embedded"`
|
||||
Name string `gorm:"column:name;type:varchar(100);not null;uniqueIndex:idx_tag_enterprise_name,priority:2;uniqueIndex:idx_tag_shop_name,priority:2;uniqueIndex:idx_tag_global_name;comment:标签名称" json:"name"`
|
||||
EnterpriseID *uint `gorm:"column:enterprise_id;index:idx_tag_enterprise;uniqueIndex:idx_tag_enterprise_name,priority:1;comment:归属企业ID(NULL表示非企业标签)" json:"enterprise_id,omitempty"`
|
||||
ShopID *uint `gorm:"column:shop_id;index:idx_tag_shop;uniqueIndex:idx_tag_shop_name,priority:1;comment:归属店铺ID(NULL表示非店铺标签)" json:"shop_id,omitempty"`
|
||||
Color *string `gorm:"column:color;type:varchar(20);comment:标签颜色(十六进制)" json:"color,omitempty"`
|
||||
UsageCount int `gorm:"column:usage_count;type:int;not null;default:0;index:idx_tag_usage;comment:使用次数" json:"usage_count"`
|
||||
}
|
||||
|
||||
// TableName 指定表名
|
||||
@@ -22,13 +24,15 @@ func (Tag) TableName() string {
|
||||
|
||||
// ResourceTag 资源-标签关联模型
|
||||
// 统一管理设备、IoT卡、号卡与标签的多对多关系
|
||||
// ResourceType 取值: device/iot_card/number_card
|
||||
// 添加 enterprise_id 和 shop_id 用于权限控制,从资源所有者推断
|
||||
type ResourceTag struct {
|
||||
gorm.Model
|
||||
BaseModel `gorm:"embedded"`
|
||||
ResourceType string `gorm:"column:resource_type;type:varchar(20);not null;uniqueIndex:idx_resource_tag_unique,priority:1,where:deleted_at IS NULL;index:idx_resource_tag_resource,priority:1;index:idx_resource_tag_composite,priority:1;comment:资源类型 device-设备 iot_card-IoT卡 number_card-号卡" json:"resource_type"`
|
||||
ResourceID uint `gorm:"column:resource_id;not null;uniqueIndex:idx_resource_tag_unique,priority:2,where:deleted_at IS NULL;index:idx_resource_tag_resource,priority:2;comment:资源ID" json:"resource_id"`
|
||||
TagID uint `gorm:"column:tag_id;not null;uniqueIndex:idx_resource_tag_unique,priority:3,where:deleted_at IS NULL;index:idx_resource_tag_tag;index:idx_resource_tag_composite,priority:2;comment:标签ID" json:"tag_id"`
|
||||
EnterpriseID *uint `gorm:"column:enterprise_id;index:idx_resource_tag_enterprise;comment:归属企业ID(从资源推断)" json:"enterprise_id,omitempty"`
|
||||
ShopID *uint `gorm:"column:shop_id;index:idx_resource_tag_shop;comment:归属店铺ID(从资源推断)" json:"shop_id,omitempty"`
|
||||
}
|
||||
|
||||
// TableName 指定表名
|
||||
|
||||
@@ -9,16 +9,18 @@ import (
|
||||
)
|
||||
|
||||
// Wallet 钱包模型
|
||||
// 用户和代理的资金账户,支持充值、消费、提现等操作
|
||||
// 个人客户和代理商的资金账户,支持充值、消费、提现等操作
|
||||
// 使用乐观锁(version字段)防止并发余额冲突
|
||||
// 钱包归属资源(卡/设备/店铺),支持资源转手场景
|
||||
type Wallet struct {
|
||||
gorm.Model
|
||||
BaseModel `gorm:"embedded"`
|
||||
UserID uint `gorm:"column:user_id;not null;index:idx_wallet_user,priority:1;comment:用户ID" json:"user_id"`
|
||||
WalletType string `gorm:"column:wallet_type;type:varchar(20);not null;uniqueIndex:idx_wallet_user_type_currency,priority:2;comment:钱包类型 user-用户钱包 agent-代理钱包" json:"wallet_type"`
|
||||
ResourceType string `gorm:"column:resource_type;type:varchar(20);not null;uniqueIndex:idx_wallet_resource_type_currency,priority:1;index:idx_wallet_resource,priority:1;comment:资源类型 iot_card-物联网卡 device-设备 shop-店铺" json:"resource_type"`
|
||||
ResourceID uint `gorm:"column:resource_id;not null;uniqueIndex:idx_wallet_resource_type_currency,priority:2;index:idx_wallet_resource,priority:2;comment:资源ID" json:"resource_id"`
|
||||
WalletType string `gorm:"column:wallet_type;type:varchar(20);not null;uniqueIndex:idx_wallet_resource_type_currency,priority:3;comment:钱包类型 main-主钱包 commission-分佣钱包" json:"wallet_type"`
|
||||
Balance int64 `gorm:"column:balance;type:bigint;not null;default:0;comment:余额(分)" json:"balance"`
|
||||
FrozenBalance int64 `gorm:"column:frozen_balance;type:bigint;not null;default:0;comment:冻结余额(分)" json:"frozen_balance"`
|
||||
Currency string `gorm:"column:currency;type:varchar(10);not null;default:'CNY';uniqueIndex:idx_wallet_user_type_currency,priority:3;comment:币种" json:"currency"`
|
||||
Currency string `gorm:"column:currency;type:varchar(10);not null;default:'CNY';uniqueIndex:idx_wallet_resource_type_currency,priority:4;comment:币种" json:"currency"`
|
||||
Status int `gorm:"column:status;type:int;not null;default:1;index:idx_wallet_status;comment:钱包状态 1-正常 2-冻结 3-关闭" json:"status"`
|
||||
Version int `gorm:"column:version;type:int;not null;default:0;comment:版本号(乐观锁)" json:"version"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user