实现用户和组织模型(店铺、企业、个人客户)
核心功能: - 实现 7 级店铺层级体系(Shop 模型 + 层级校验) - 实现企业管理模型(Enterprise 模型) - 实现个人客户管理模型(PersonalCustomer 模型) - 重构 Account 模型关联关系(基于 EnterpriseID 而非 ParentID) - 完整的 Store 层和 Service 层实现 - 递归查询下级店铺功能(含 Redis 缓存) - 全面的单元测试覆盖(Shop/Enterprise/PersonalCustomer Store + Shop Service) 技术要点: - 显式指定所有 GORM 模型的数据库字段名(column: 标签) - 统一的字段命名规范(数据库用 snake_case,Go 用 PascalCase) - 完整的中文字段注释和业务逻辑说明 - 100% 测试覆盖(20+ 测试用例全部通过) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -52,10 +52,10 @@ const (
|
||||
|
||||
// RBAC 用户类型常量
|
||||
const (
|
||||
UserTypeRoot = 1 // root 用户(跳过数据权限过滤)
|
||||
UserTypeSuperAdmin = 1 // 超级管理员(跳过数据权限过滤)
|
||||
UserTypePlatform = 2 // 平台用户
|
||||
UserTypeAgent = 3 // 代理用户
|
||||
UserTypeEnterprise = 4 // 企业用户
|
||||
UserTypeAgent = 3 // 代理账号
|
||||
UserTypeEnterprise = 4 // 企业账号
|
||||
)
|
||||
|
||||
// RBAC 角色类型常量
|
||||
@@ -95,3 +95,8 @@ const (
|
||||
DefaultTimeout = 10 * time.Minute
|
||||
DefaultConcurrency = 10
|
||||
)
|
||||
|
||||
// 店铺配置常量
|
||||
const (
|
||||
MaxShopLevel = 7 // 店铺最大层级
|
||||
)
|
||||
|
||||
@@ -32,3 +32,10 @@ func RedisTaskStatusKey(taskID string) string {
|
||||
func RedisAccountSubordinatesKey(accountID uint) string {
|
||||
return fmt.Sprintf("account:subordinates:%d", accountID)
|
||||
}
|
||||
|
||||
// RedisShopSubordinatesKey 生成店铺下级 ID 列表的 Redis 键
|
||||
// 用途:缓存递归查询的下级店铺 ID 列表
|
||||
// 过期时间:30 分钟
|
||||
func RedisShopSubordinatesKey(shopID uint) string {
|
||||
return fmt.Sprintf("shop:subordinates:%d", shopID)
|
||||
}
|
||||
|
||||
@@ -36,6 +36,15 @@ const (
|
||||
CodeRoleAlreadyAssigned = 1026 // 角色已分配
|
||||
CodePermAlreadyAssigned = 1027 // 权限已分配
|
||||
|
||||
// 组织相关错误 (1030-1049)
|
||||
CodeShopNotFound = 1030 // 店铺不存在
|
||||
CodeShopCodeExists = 1031 // 店铺编号已存在
|
||||
CodeShopLevelExceeded = 1032 // 店铺层级超过最大值
|
||||
CodeEnterpriseNotFound = 1033 // 企业不存在
|
||||
CodeEnterpriseCodeExists = 1034 // 企业编号已存在
|
||||
CodeCustomerNotFound = 1035 // 个人客户不存在
|
||||
CodeCustomerPhoneExists = 1036 // 个人客户手机号已存在
|
||||
|
||||
// 服务端错误 (2000-2999) -> 5xx HTTP 状态码
|
||||
CodeInternalError = 2001 // 内部服务器错误
|
||||
CodeDatabaseError = 2002 // 数据库错误
|
||||
@@ -75,6 +84,13 @@ var errorMessages = map[int]string{
|
||||
CodeInvalidPermCode: "权限编码格式不正确(应为 module:action 格式)",
|
||||
CodeRoleAlreadyAssigned: "角色已分配",
|
||||
CodePermAlreadyAssigned: "权限已分配",
|
||||
CodeShopNotFound: "店铺不存在",
|
||||
CodeShopCodeExists: "店铺编号已存在",
|
||||
CodeShopLevelExceeded: "店铺层级不能超过 7 级",
|
||||
CodeEnterpriseNotFound: "企业不存在",
|
||||
CodeEnterpriseCodeExists: "企业编号已存在",
|
||||
CodeCustomerNotFound: "个人客户不存在",
|
||||
CodeCustomerPhoneExists: "个人客户手机号已存在",
|
||||
CodeInternalError: "内部服务器错误",
|
||||
CodeDatabaseError: "数据库错误",
|
||||
CodeRedisError: "缓存服务错误",
|
||||
|
||||
@@ -165,7 +165,7 @@ func TestDataPermissionCallback_SkipForRootUser(t *testing.T) {
|
||||
|
||||
// 设置 root 用户 context
|
||||
ctx := context.Background()
|
||||
ctx = middleware.SetUserContext(ctx, 1, constants.UserTypeRoot, 0)
|
||||
ctx = middleware.SetUserContext(ctx, 1, constants.UserTypeSuperAdmin, 0)
|
||||
|
||||
// 查询数据
|
||||
var results []TestModel
|
||||
|
||||
@@ -57,7 +57,7 @@ func GetShopIDFromContext(ctx context.Context) uint {
|
||||
// root 用户跳过数据权限过滤
|
||||
func IsRootUser(ctx context.Context) bool {
|
||||
userType := GetUserTypeFromContext(ctx)
|
||||
return userType == constants.UserTypeRoot
|
||||
return userType == constants.UserTypeSuperAdmin
|
||||
}
|
||||
|
||||
// SetUserToFiberContext 将用户信息设置到 Fiber context 的 Locals 中
|
||||
|
||||
Reference in New Issue
Block a user