package services import ( "errors" "fmt" "platform/pkg/u" "platform/web/core" m "platform/web/models" q "platform/web/queries" "time" "github.com/shopspring/decimal" "golang.org/x/crypto/bcrypt" "gorm.io/gen/field" "gorm.io/gorm" ) var User = &userService{} type userService struct{} func (s *userService) Get(q *q.Query, uid int32) (*m.User, error) { user, err := q.User. Where(q.User.ID.Eq(uid)).Take() if err != nil { return nil, core.NewServErr("查询用户失败", err) } return user, nil } func (s *userService) UpdateBalanceByAdmin(user *m.User, newBalance decimal.Decimal, adminId *int32) error { if user == nil { return core.NewServErr("用户不存在") } amount := newBalance.Sub(user.Balance) if amount.IsZero() { return nil } return q.Q.Transaction(func(q *q.Query) error { return s.UpdateBalance(q, user, amount, "管理员修改余额", adminId, nil) }) } func (s *userService) UpdateBalance(q *q.Query, user *m.User, amount decimal.Decimal, remark string, adminId *int32, billId *int32) error { balance := user.Balance.Add(amount) if balance.IsNegative() { return core.NewServErr("用户余额不足") } // 更新余额 _, err := q.User. Where( q.User.ID.Eq(user.ID), q.User.Balance.Eq(user.Balance), ). UpdateSimple( q.User.Balance.Value(balance), ) if err != nil { return core.NewServErr("更新用户余额失败", err) } // 新增动账记录 err = q.BalanceActivity.Create(&m.BalanceActivity{ UserID: user.ID, AdminID: adminId, BillID: billId, Amount: amount.StringFixed(2), BalancePrev: user.Balance.StringFixed(2), BalanceCurr: balance.StringFixed(2), Remark: &remark, }) if err != nil { return core.NewServErr("新增动账记录失败", err) } return nil } func userBalanceKey(uid int32) string { return fmt.Sprintf("user:%d:balance", uid) } type UpdateBalanceData struct { Amount int `json:"amount"` } func (data *UpdateBalanceData) TradeDetail(user *m.User) (*TradeDetail, error) { amount := decimal.NewFromInt(int64(data.Amount)).Div(decimal.NewFromInt(100)) return &TradeDetail{ data, m.TradeTypeRecharge, fmt.Sprintf("账户充值 - %s元", amount.StringFixed(2)), amount, amount, amount, nil, nil, }, nil } // CreateByAdmin 管理员创建用户的数据 func (s *userService) CreateByAdmin(data CreateUserByAdminData) error { var hashedPwd *string if data.Password != nil { hash, err := bcrypt.GenerateFromPassword([]byte(*data.Password), bcrypt.DefaultCost) if err != nil { return core.NewServErr("密码加密失败", err) } hashedPwd = u.P(string(hash)) } source := m.UserSourceAdd err := q.User.Create(&m.User{ Phone: data.Phone, AdminID: data.AdminID, DiscountID: data.DiscountID, Username: data.Username, Email: data.Email, Password: hashedPwd, Source: &source, Avatar: data.Avatar, Status: u.Else(data.Status, m.UserStatusEnabled), ContactQQ: data.ContactQQ, ContactWechat: data.ContactWechat, }) if errors.Is(err, gorm.ErrDuplicatedKey) { return core.NewBizErr("账号已存在,请检查手机号/用户名/邮箱是否重复") } if err != nil { return err } return nil } type CreateUserByAdminData struct { Phone string `json:"phone" validate:"required"` AdminID *int32 `json:"admin_id"` DiscountID *int32 `json:"discount_id"` Username *string `json:"username"` Email *string `json:"email"` Password *string `json:"password"` Avatar *string `json:"avatar"` Status *m.UserStatus `json:"status"` ContactQQ *string `json:"contact_qq"` ContactWechat *string `json:"contact_wechat"` } // UpdateByAdmin 管理员更新用户的数据 func (s *userService) UpdateByAdmin(data UpdateUserByAdminData) error { do := make([]field.AssignExpr, 0) if data.Phone != nil { do = append(do, q.User.Phone.Value(*data.Phone)) } if data.AdminID != nil { do = append(do, q.User.AdminID.Value(*data.AdminID)) } if data.DiscountID != nil { do = append(do, q.User.DiscountID.Value(*data.DiscountID)) } if data.Username != nil { do = append(do, q.User.Username.Value(*data.Username)) } if data.Email != nil { do = append(do, q.User.Email.Value(*data.Email)) } if data.Password != nil { hash, err := bcrypt.GenerateFromPassword([]byte(*data.Password), bcrypt.DefaultCost) if err != nil { return core.NewServErr("密码加密失败", err) } do = append(do, q.User.Password.Value(string(hash))) } if data.Name != nil { do = append(do, q.User.Name.Value(*data.Name)) } if data.Avatar != nil { do = append(do, q.User.Avatar.Value(*data.Avatar)) } if data.Status != nil { do = append(do, q.User.Status.Value(int(*data.Status))) } if data.IDType != nil { do = append(do, q.User.IDType.Value(int(*data.IDType))) } if data.IDNo != nil { do = append(do, q.User.IDNo.Value(*data.IDNo)) } if data.IDToken != nil { do = append(do, q.User.IDToken.Value(*data.IDToken)) } if data.ContactQQ != nil { do = append(do, q.User.ContactQQ.Value(*data.ContactQQ)) } if data.ContactWechat != nil { do = append(do, q.User.ContactWechat.Value(*data.ContactWechat)) } if len(do) == 0 { return nil } _, err := q.User.Where(q.User.ID.Eq(data.ID)).UpdateSimple(do...) if errors.Is(err, gorm.ErrDuplicatedKey) { return core.NewBizErr("账号已存在,请检查手机号/用户名/邮箱是否重复") } return err } type UpdateUserByAdminData struct { ID int32 `json:"id" validate:"required"` Phone *string `json:"phone"` AdminID *int32 `json:"admin_id"` DiscountID *int32 `json:"discount_id"` Username *string `json:"username"` Email *string `json:"email"` Password *string `json:"password"` Name *string `json:"name"` Avatar *string `json:"avatar"` Status *m.UserStatus `json:"status"` IDType *m.UserIDType `json:"id_type"` IDNo *string `json:"id_no"` IDToken *string `json:"id_token"` ContactQQ *string `json:"contact_qq"` ContactWechat *string `json:"contact_wechat"` } func (s *userService) RemoveByAdmin(id int32) error { _, err := q.User.Where(q.User.ID.Eq(id)).UpdateColumn(q.User.DeletedAt, time.Now()) return err }