package handlers import ( "errors" "platform/web/auth" "platform/web/core" g "platform/web/globals" m "platform/web/models" q "platform/web/queries" s "platform/web/services" "github.com/gofiber/fiber/v2" "github.com/shopspring/decimal" "golang.org/x/crypto/bcrypt" "gorm.io/gen/field" "gorm.io/gorm" ) // 分页获取用户 func PageUserByAdmin(c *fiber.Ctx) error { // 检查权限 _, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeUserRead) if err != nil { return err } // 解析请求参数 req := new(PageUserByAdminReq) if err := g.Validator.ParseBody(c, req); err != nil { return err } // 构建查询条件 do := q.User.Where() if req.Account != nil { do = do.Where(q.User.Where( q.User.Username.Like("%" + *req.Account + "%"), ).Or( q.User.Phone.Like("%" + *req.Account + "%"), ).Or( q.User.Email.Like("%" + *req.Account + "%"), )) } if req.Name != nil { do = do.Where(q.User.Name.Eq(*req.Name)) } if req.Identified != nil { if *req.Identified { do = do.Where(q.User.IDType.Gt(0)) } else { do = do.Where(q.User.IDType.Eq(0)) } } if req.Enabled != nil { if *req.Enabled { do = do.Where(q.User.Status.Eq(1)) } else { do = do.Where(q.User.Status.Eq(0)) } } if req.Assigned != nil { if *req.Assigned { do = do.Where(q.User.AdminID.IsNotNull()) } else { do = do.Where(q.User.AdminID.IsNull()) } } // 查询用户列表 users, total, err := q.User. Preload(q.User.Admin, q.User.Discount). Omit(q.User.Password, q.Admin.Password). Where(do). Order(q.User.CreatedAt.Desc()). FindByPage(req.GetOffset(), req.GetLimit()) if err != nil { return err } for _, user := range users { if user.IDNo != nil && len(*user.IDNo) == 18 { var str = *user.IDNo *user.IDNo = str[:6] + "****" + str[len(str)-2:] } if user.Admin != nil { user.Admin = &m.Admin{ Name: user.Admin.Name, } } } // 返回结果 return c.JSON(core.PageResp{ Total: int(total), Page: req.GetPage(), Size: req.GetSize(), List: users, }) } type PageUserByAdminReq struct { core.PageReq Account *string `json:"account,omitempty"` Name *string `json:"name,omitempty"` Identified *bool `json:"identified,omitempty"` Enabled *bool `json:"enabled,omitempty"` Assigned *bool `json:"assigned,omitempty"` } // 管理员获取单个用户 func GetUserByAdmin(c *fiber.Ctx) error { // 检查权限 _, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeUserReadOne) if err != nil { return err } // 解析请求参数 var req GetUserByAdminReq if err := g.Validator.ParseBody(c, &req); err != nil { return err } // 构建查询条件 do := q.User.Where() if req.Account != nil { do = do.Where(q.User.Where( q.User.Username.Like("%" + *req.Account + "%"), ).Or( q.User.Phone.Like("%" + *req.Account + "%"), ).Or( q.User.Email.Like("%" + *req.Account + "%"), )) } if req.Name != nil { do = do.Where(q.User.Name.Eq(*req.Name)) } // 查询用户 user, err := q.User. Preload(q.User.Admin, q.User.Discount). Omit(q.User.Password, q.Admin.Password). Where(do). Order(q.User.CreatedAt.Desc()). First() if err == gorm.ErrRecordNotFound { return core.NewBizErr("找不到用户") } if err != nil { return err } // 仅保留管理员名称 if user.Admin != nil { user.Admin = &m.Admin{ Name: user.Admin.Name, } } // 返回结果 return c.JSON(user) } type GetUserByAdminReq struct { Account *string `json:"account,omitempty"` Name *string `json:"name,omitempty"` } // 管理员创建用户 func CreateUserByAdmin(c *fiber.Ctx) error { _, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeUserWrite) if err != nil { return err } var req s.CreateUserByAdminData if err := g.Validator.ParseBody(c, &req); err != nil { return err } if err := s.User.CreateByAdmin(req); err != nil { return err } return c.JSON(nil) } // 管理员更新用户 func UpdateUserByAdmin(c *fiber.Ctx) error { _, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeUserWrite) if err != nil { return err } var req s.UpdateUserByAdminData if err := g.Validator.ParseBody(c, &req); err != nil { return err } if err := s.User.UpdateByAdmin(req); err != nil { return err } return c.JSON(nil) } // 管理员删除用户 func RemoveUserByAdmin(c *fiber.Ctx) error { _, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeUserWrite) if err != nil { return err } var req core.IdReq if err := g.Validator.ParseBody(c, &req); err != nil { return err } if err := s.User.RemoveByAdmin(req.Id); err != nil { return err } return c.JSON(nil) } // 管理员更新用户余额 func UpdateUserBalanceByAdmin(c *fiber.Ctx) error { authCtx, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeUserWriteBalance) if err != nil { return err } var req UpdateUserBalanceByAdminData if err := g.Validator.ParseBody(c, &req); err != nil { return err } user, err := s.User.Get(q.Q, req.UserID) if err != nil { return err } balance, err := decimal.NewFromString(req.Balance) if err != nil { return err } if err := s.User.UpdateBalanceByAdmin(user, balance, &authCtx.Admin.ID); err != nil { return err } return c.JSON(nil) } type UpdateUserBalanceByAdminData struct { UserID int32 `json:"user_id" validate:"required"` Balance string `json:"balance" validate:"required"` } // 绑定管理员 func BindAdmin(c *fiber.Ctx) error { // 检查权限 authCtx, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeUserWrite) if err != nil { return err } // 解析请求参数 req := new(struct { UserID int `json:"user_id" validate:"required"` }) if err := g.Validator.ParseBody(c, req); err != nil { return err } // 更新用户信息 result, err := q.User.Where( q.User.ID.Eq(int32(req.UserID)), q.User.AdminID.IsNull(), ).UpdateColumnSimple( q.User.AdminID.Value(authCtx.Admin.ID), ) if err != nil { return err } if result.RowsAffected == 0 { return core.NewBizErr("用户已绑定管理员") } // 返回结果 return c.SendStatus(fiber.StatusNoContent) } // 更新用户 func UpdateUser(c *fiber.Ctx) error { // 检查权限 authCtx, err := auth.GetAuthCtx(c).PermitUser() if err != nil { return err } // 解析请求参数 req := new(UpdateUserReq) if err := c.BodyParser(req); err != nil { return err } // 更新用户信息 do := make([]field.AssignExpr, 0) if req.Username != nil && *req.Username != "" { do = append(do, q.User.Username.Value(*req.Username)) } if req.Email != nil { if *req.Email == "" { do = append(do, q.User.Email.Null()) } else { do = append(do, q.User.Email.Value(*req.Email)) } } if req.ContactQQ != nil { do = append(do, q.User.ContactQQ.Value(*req.ContactQQ)) } if req.ContactWechat != nil { do = append(do, q.User.ContactWechat.Value(*req.ContactWechat)) } _, err = q.User. Where(q.User.ID.Eq(authCtx.User.ID)). UpdateSimple(do...) if errors.Is(err, gorm.ErrDuplicatedKey) { return core.NewBizErr("用户名或邮箱已被占用") } if err != nil { return err } // 返回结果 return c.SendStatus(fiber.StatusNoContent) } type UpdateUserReq struct { Username *string `json:"username" validate:"omitempty,min=3,max=20"` Email *string `json:"email" validate:"omitempty,email"` ContactQQ *string `json:"contact_qq" validate:"omitempty,qq"` ContactWechat *string `json:"contact_wechat" validate:"omitempty,wechat"` } // 更新账号信息 func UpdateAccount(c *fiber.Ctx) error { // 检查权限 authCtx, err := auth.GetAuthCtx(c).PermitUser() if err != nil { return err } // 解析请求参数 req := new(UpdateAccountReq) if err := c.BodyParser(req); err != nil { return err } // 更新用户信息 _, err = q.User. Where(q.User.ID.Eq(authCtx.User.ID)). Updates(m.User{ Username: &req.Username, Password: &req.Password, }) if err != nil { return err } // 返回结果 return c.SendStatus(fiber.StatusNoContent) } type UpdateAccountReq struct { Username string `json:"username" validate:"omitempty,min=3,max=20"` Password string `json:"password" validate:"omitempty,min=6,max=20"` } // 更新账号密码 func UpdatePassword(c *fiber.Ctx) error { // 检查权限 authCtx, err := auth.GetAuthCtx(c).PermitUser() if err != nil { return err } // 解析请求参数 req := new(UpdatePasswordReq) if err := c.BodyParser(req); err != nil { return err } // 验证手机令牌 if req.Code == "" { return fiber.NewError(fiber.StatusBadRequest, "验证码不能为空") } err = s.Verifier.VerifySms(c.Context(), authCtx.User.Phone, req.Code, s.VerifierSmsPurposePassword) if errors.Is(err, s.ErrVerifierServiceInvalid) { return core.NewBizErr(s.ErrVerifierServiceInvalid.Error()) } if err != nil { return err } // 更新密码 newHash, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost) if err != nil { return err } _, err = q.User. Where(q.User.ID.Eq(authCtx.User.ID)). UpdateColumn(q.User.Password, newHash) if err != nil { return err } // 返回结果 return c.SendStatus(fiber.StatusNoContent) } type UpdatePasswordReq struct { Code string `json:"code"` Password string `json:"password"` } // PageUserNotBindByAdmin 分页获取未绑定管理员的用户 func PageUserNotBindByAdmin(c *fiber.Ctx) error { // 检查权限 _, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeUserReadNotBind) if err != nil { return err } // 解析请求参数 req := new(PageUserNotBindByAdminReq) if err := g.Validator.ParseBody(c, req); err != nil { return err } // 构建查询条件(强制过滤未绑定管理员的用户) do := q.User.Where(q.User.AdminID.IsNull()) if req.Phone != nil { do = do.Where(q.User.Phone.Eq(*req.Phone)) } // 查询用户列表 users, total, err := q.User. Omit(q.User.Password, q.User.IDNo). Where(do). Order(q.User.CreatedAt.Desc()). FindByPage(req.GetOffset(), req.GetLimit()) if err != nil { return err } // 返回结果 return c.JSON(core.PageResp{ Total: int(total), Page: req.GetPage(), Size: req.GetSize(), List: users, }) } type PageUserNotBindByAdminReq struct { core.PageReq Phone *string `json:"phone,omitempty"` } // UpdateUserBalanceIncByAdmin 管理员增加用户余额 func UpdateUserBalanceIncByAdmin(c *fiber.Ctx) error { authCtx, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeUserWriteBalance) if err != nil { return err } var req UpdateUserBalanceChangeByAdminData if err := g.Validator.ParseBody(c, &req); err != nil { return err } amount, err := decimal.NewFromString(req.Amount) if err != nil { return err } if !amount.IsPositive() { return core.NewBizErr("金额必须为正数") } user, err := s.User.Get(q.Q, req.UserID) if err != nil { return err } newBalance := user.Balance.Add(amount) if err := s.User.UpdateBalanceByAdmin(user, newBalance, &authCtx.Admin.ID); err != nil { return err } return c.JSON(nil) } // UpdateUserBalanceDecByAdmin 管理员减少用户余额 func UpdateUserBalanceDecByAdmin(c *fiber.Ctx) error { authCtx, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeUserWriteBalance) if err != nil { return err } var req UpdateUserBalanceChangeByAdminData if err := g.Validator.ParseBody(c, &req); err != nil { return err } amount, err := decimal.NewFromString(req.Amount) if err != nil { return err } if !amount.IsPositive() { return core.NewBizErr("金额必须为正数") } user, err := s.User.Get(q.Q, req.UserID) if err != nil { return err } newBalance := user.Balance.Sub(amount) if err := s.User.UpdateBalanceByAdmin(user, newBalance, &authCtx.Admin.ID); err != nil { return err } return c.JSON(nil) } type UpdateUserBalanceChangeByAdminData struct { UserID int32 `json:"user_id" validate:"required"` Amount string `json:"amount" validate:"required"` }