Files
2026-09-11 01:47:20 +08:00

145 lines
4.2 KiB
Go

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(&quotas).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
}