package mysqldao import ( "context" "git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/global" "git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/mysqlmodel" "gorm.io/gorm" ) // UserDao 用户数据访问 type UserDao struct { db *gorm.DB } // NewUserDao 创建用户 DAO func NewUserDao() *UserDao { return &UserDao{db: global.MysqlEngine} } // UserListParams 用户分页列表筛选参数。 type UserListParams struct { Keyword string // 模糊匹配昵称/手机号/OpenID(任一命中) Status int8 // 状态筛选,0 表示全部 Page int Size int } // UserList 分页查询用户(关键词 + 状态筛选) func (d *UserDao) UserList(ctx context.Context, p UserListParams) ([]mysqlmodel.User, int64, error) { ctx, span := global.Tracer.Start(ctx, "mysqldao.UserList") defer span.End() var list []mysqlmodel.User var total int64 q := d.db.WithContext(ctx).Model(&mysqlmodel.User{}) if p.Keyword != "" { kw := "%" + p.Keyword + "%" q = q.Where("username LIKE ? OR phone LIKE ? OR wx_open_id LIKE ?", kw, kw, kw) } if p.Status != 0 { q = q.Where("status = ?", p.Status) } if err := q.Count(&total).Error; err != nil { span.RecordError(err) return nil, 0, err } if err := q.Offset((p.Page - 1) * p.Size).Limit(p.Size).Order("id DESC").Find(&list).Error; err != nil { span.RecordError(err) return nil, 0, err } return list, total, nil } // UserGetByID 按主键 ID 查询用户 func (d *UserDao) UserGetByID(ctx context.Context, userID int64) (*mysqlmodel.User, error) { ctx, span := global.Tracer.Start(ctx, "mysqldao.UserGetByID") defer span.End() var user mysqlmodel.User if err := d.db.WithContext(ctx).First(&user, userID).Error; err != nil { span.RecordError(err) return nil, err } return &user, nil } // UserGetByUUID 按 UUID 查询用户 func (d *UserDao) UserGetByUUID(ctx context.Context, userUUID string) (*mysqlmodel.User, error) { ctx, span := global.Tracer.Start(ctx, "mysqldao.UserGetByUUID") defer span.End() var user mysqlmodel.User if err := d.db.WithContext(ctx).Where("user_uuid = ?", userUUID).First(&user).Error; err != nil { span.RecordError(err) return nil, err } return &user, nil } // UserUpdateByID 按主键 ID 更新用户字段 func (d *UserDao) UserUpdateByID(ctx context.Context, userID int64, updates map[string]any) error { ctx, span := global.Tracer.Start(ctx, "mysqldao.UserUpdateByID") defer span.End() if err := d.db.WithContext(ctx).Model(&mysqlmodel.User{}).Where("id = ?", userID).Updates(updates).Error; err != nil { span.RecordError(err) return err } return nil } // QuotaListByUserID 查询用户的所有配额 func (d *UserDao) QuotaListByUserID(ctx context.Context, userID int64) ([]mysqlmodel.Quota, error) { ctx, span := global.Tracer.Start(ctx, "mysqldao.QuotaListByUserID") defer span.End() var quotas []mysqlmodel.Quota if err := d.db.WithContext(ctx).Where("user_id = ?", userID).Find("as).Error; err != nil { span.RecordError(err) return nil, err } return quotas, nil } // VIPAdjustWithFlow 事务内人工调整用户 VIP 并写流水。 func (d *UserDao) VIPAdjustWithFlow(ctx context.Context, user *mysqlmodel.User, flow *mysqlmodel.VIPFlowLog) error { ctx, span := global.Tracer.Start(ctx, "mysqldao.VIPAdjustWithFlow") defer span.End() return d.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { if err := tx.Model(&mysqlmodel.User{}). Where("id = ?", user.ID). Updates(map[string]any{ "vip_type": user.VIPType, "vip_start": user.VIPStart, "vip_expire": user.VIPExpire, }).Error; err != nil { return err } // 人工调整无订单号,用流水 UUID 填充 order_no 满足联合唯一索引。 if flow.OrderNo == "" { flow.OrderNo = genFlowUUID() } return tx.Create(flow).Error }) } // UserIDListAll 分批遍历全部用户 ID(通知广播用)。 func (d *UserDao) UserIDListAll(ctx context.Context, lastID int64, limit int) ([]int64, error) { ctx, span := global.Tracer.Start(ctx, "mysqldao.UserIDListAll") defer span.End() var ids []int64 if err := d.db.WithContext(ctx).Model(&mysqlmodel.User{}). Where("id > ?", lastID). Order("id ASC"). Limit(limit). Pluck("id", &ids).Error; err != nil { span.RecordError(err) return nil, err } return ids, nil }