package system import ( "context" "encoding/json" "fmt" "kra/internal/biz/system" "kra/internal/server/middleware" "kra/pkg/jwt" "github.com/go-kratos/kratos/v2/errors" "github.com/go-kratos/kratos/v2/transport/http" ) // UserService 用户服务 type UserService struct { uc *system.UserUsecase jwtPkg *jwt.JWT } // NewUserService 创建用户服务 func NewUserService(uc *system.UserUsecase, jwtPkg *jwt.JWT) *UserService { return &UserService{uc: uc, jwtPkg: jwtPkg} } // LoginRequest 登录请求 type LoginRequest struct { Username string `json:"username"` Password string `json:"password"` Captcha string `json:"captcha"` CaptchaId string `json:"captchaId"` } // LoginResponse 登录响应 type LoginResponse struct { User *UserInfo `json:"user"` Token string `json:"token"` ExpiresAt int64 `json:"expiresAt"` } // UserInfo 用户信息 type UserInfo struct { ID uint `json:"id"` UUID string `json:"uuid"` Username string `json:"username"` NickName string `json:"nickName"` SideMode string `json:"sideMode"` HeaderImg string `json:"headerImg"` BaseColor string `json:"baseColor"` AuthorityId uint `json:"authorityId"` Phone string `json:"phone"` Email string `json:"email"` Enable int `json:"enable"` OriginSetting json.RawMessage `json:"originSetting,omitempty"` Authority *AuthorityInfo `json:"authority,omitempty"` Authorities []*AuthorityInfo `json:"authorities,omitempty"` } // AuthorityInfo 角色信息 type AuthorityInfo struct { AuthorityId uint `json:"authorityId"` AuthorityName string `json:"authorityName"` ParentId *uint `json:"parentId,omitempty"` DefaultRouter string `json:"defaultRouter"` } // Login 用户登录 func (s *UserService) Login(ctx context.Context, req *LoginRequest) (*LoginResponse, error) { user, err := s.uc.Login(ctx, req.Username, req.Password) if err != nil { return nil, errors.Unauthorized("LOGIN_FAILED", err.Error()) } if user.Enable != 1 { return nil, errors.Forbidden("USER_DISABLED", "用户被禁止登录") } // 生成 JWT token claims := s.jwtPkg.CreateClaims(jwt.BaseClaims{ UUID: user.UUID.String(), ID: uint(user.ID), Username: user.Username, NickName: user.NickName, AuthorityID: user.AuthorityId, }) token, err := s.jwtPkg.CreateToken(claims.BaseClaims) if err != nil { return nil, errors.InternalServer("TOKEN_ERROR", "生成token失败") } return &LoginResponse{ User: toUserInfo(user), Token: token, ExpiresAt: claims.ExpiresAt.UnixMilli(), }, nil } // RegisterRequest 注册请求 type RegisterRequest struct { Username string `json:"username"` Password string `json:"password"` NickName string `json:"nickName"` HeaderImg string `json:"headerImg"` AuthorityId uint `json:"authorityId"` AuthorityIds []uint `json:"authorityIds"` Phone string `json:"phone"` Email string `json:"email"` Enable int `json:"enable"` } // Register 用户注册 func (s *UserService) Register(ctx context.Context, req *RegisterRequest) (*UserInfo, error) { user := &system.User{ Username: req.Username, Password: req.Password, NickName: req.NickName, HeaderImg: req.HeaderImg, AuthorityId: req.AuthorityId, Phone: req.Phone, Email: req.Email, Enable: req.Enable, } created, err := s.uc.Register(ctx, user) if err != nil { return nil, errors.BadRequest("REGISTER_FAILED", err.Error()) } return toUserInfo(created), nil } // ChangePasswordRequest 修改密码请求 type ChangePasswordRequest struct { Password string `json:"password"` NewPassword string `json:"newPassword"` } // ChangePassword 修改密码 func (s *UserService) ChangePassword(ctx context.Context, userID uint, req *ChangePasswordRequest) error { return s.uc.ChangePassword(ctx, userID, req.Password, req.NewPassword) } // ResetPasswordRequest 重置密码请求 type ResetPasswordRequest struct { ID uint `json:"id"` Password string `json:"password"` } // ResetPassword 重置密码 func (s *UserService) ResetPassword(ctx context.Context, req *ResetPasswordRequest) error { return s.uc.ResetPassword(ctx, req.ID, req.Password) } // GetUserInfo 获取用户信息 func (s *UserService) GetUserInfo(ctx context.Context, uuid string) (*UserInfo, error) { user, err := s.uc.GetUserInfo(ctx, uuid) if err != nil { return nil, errors.NotFound("USER_NOT_FOUND", err.Error()) } return toUserInfo(user), nil } // GetUserListRequest 获取用户列表请求 type GetUserListRequest struct { Page int `json:"page"` PageSize int `json:"pageSize"` Username string `json:"username"` NickName string `json:"nickName"` Phone string `json:"phone"` Email string `json:"email"` } // GetUserListResponse 获取用户列表响应 type GetUserListResponse struct { List []*UserInfo `json:"list"` Total int64 `json:"total"` Page int `json:"page"` PageSize int `json:"pageSize"` } // GetUserList 获取用户列表 func (s *UserService) GetUserList(ctx context.Context, req *GetUserListRequest) (*GetUserListResponse, error) { filters := make(map[string]string) if req.Username != "" { filters["username"] = req.Username } if req.NickName != "" { filters["nick_name"] = req.NickName } if req.Phone != "" { filters["phone"] = req.Phone } if req.Email != "" { filters["email"] = req.Email } users, total, err := s.uc.GetUserList(ctx, req.Page, req.PageSize, filters) if err != nil { return nil, errors.InternalServer("LIST_ERROR", err.Error()) } list := make([]*UserInfo, len(users)) for i, u := range users { list[i] = toUserInfo(u) } return &GetUserListResponse{ List: list, Total: total, Page: req.Page, PageSize: req.PageSize, }, nil } // SetUserInfoRequest 设置用户信息请求(管理员用) type SetUserInfoRequest struct { ID uint `json:"id"` NickName string `json:"nickName"` HeaderImg string `json:"headerImg"` Phone string `json:"phone"` Email string `json:"email"` Enable int `json:"enable"` AuthorityIds []uint `json:"authorityIds"` } // SetUserInfo 设置用户信息 func (s *UserService) SetUserInfo(ctx context.Context, adminAuthorityID uint, req *SetUserInfoRequest) error { // 如果提供了AuthorityIds,先设置用户角色(与GVA保持一致) if len(req.AuthorityIds) > 0 { if err := s.uc.SetUserAuthorities(ctx, adminAuthorityID, req.ID, req.AuthorityIds); err != nil { return err } } user := &system.User{ ID: req.ID, NickName: req.NickName, HeaderImg: req.HeaderImg, Phone: req.Phone, Email: req.Email, Enable: req.Enable, } return s.uc.SetUserInfo(ctx, user) } // SetSelfInfoRequest 设置自己信息请求(用户用) type SetSelfInfoRequest struct { NickName string `json:"nickName"` HeaderImg string `json:"headerImg"` Phone string `json:"phone"` Email string `json:"email"` SideMode string `json:"sideMode"` BaseColor string `json:"baseColor"` } // SetSelfInfo 设置自己的信息 func (s *UserService) SetSelfInfo(ctx context.Context, userID uint, req *SetSelfInfoRequest) error { user := &system.User{ ID: userID, NickName: req.NickName, HeaderImg: req.HeaderImg, Phone: req.Phone, Email: req.Email, SideMode: req.SideMode, BaseColor: req.BaseColor, } return s.uc.SetSelfInfo(ctx, user) } // SetSelfSetting 设置自己的配置 func (s *UserService) SetSelfSetting(ctx context.Context, userID uint, setting json.RawMessage) error { return s.uc.SetSelfSetting(ctx, userID, setting) } // DeleteUser 删除用户 func (s *UserService) DeleteUser(ctx context.Context, id uint) error { return s.uc.DeleteUser(ctx, id) } // SetUserAuthorityRequest 设置用户角色请求 type SetUserAuthorityRequest struct { AuthorityId uint `json:"authorityId"` } // SetUserAuthorityResponse 设置用户角色响应 type SetUserAuthorityResponse struct { Token string `json:"token"` ExpiresAt int64 `json:"expiresAt"` } // SetUserAuthority 设置用户角色(切换角色)- 返回新token func (s *UserService) SetUserAuthority(ctx context.Context, userID uint, uuid string, username string, nickName string, req *SetUserAuthorityRequest) (*SetUserAuthorityResponse, error) { if err := s.uc.SetUserAuthority(ctx, userID, req.AuthorityId); err != nil { return nil, err } // 生成新的JWT token(与GVA保持一致) claims := s.jwtPkg.CreateClaims(jwt.BaseClaims{ UUID: uuid, ID: userID, Username: username, NickName: nickName, AuthorityID: req.AuthorityId, }) token, err := s.jwtPkg.CreateToken(claims.BaseClaims) if err != nil { return nil, errors.InternalServer("TOKEN_ERROR", "生成token失败") } return &SetUserAuthorityResponse{ Token: token, ExpiresAt: claims.ExpiresAt.UnixMilli(), }, nil } // SetUserAuthoritiesRequest 设置用户多角色请求 type SetUserAuthoritiesRequest struct { ID uint `json:"id"` AuthorityIds []uint `json:"authorityIds"` } // SetUserAuthorities 设置用户多角色 func (s *UserService) SetUserAuthorities(ctx context.Context, adminAuthorityID uint, req *SetUserAuthoritiesRequest) error { return s.uc.SetUserAuthorities(ctx, adminAuthorityID, req.ID, req.AuthorityIds) } // 转换函数 func toUserInfo(u *system.User) *UserInfo { info := &UserInfo{ ID: u.ID, UUID: u.UUID.String(), Username: u.Username, NickName: u.NickName, SideMode: u.SideMode, HeaderImg: u.HeaderImg, BaseColor: u.BaseColor, AuthorityId: u.AuthorityId, Phone: u.Phone, Email: u.Email, Enable: u.Enable, OriginSetting: u.OriginSetting, } if u.Authority != nil { info.Authority = &AuthorityInfo{ AuthorityId: u.Authority.AuthorityId, AuthorityName: u.Authority.AuthorityName, ParentId: u.Authority.ParentId, DefaultRouter: u.Authority.DefaultRouter, } } if len(u.Authorities) > 0 { info.Authorities = make([]*AuthorityInfo, len(u.Authorities)) for i, a := range u.Authorities { info.Authorities[i] = &AuthorityInfo{ AuthorityId: a.AuthorityId, AuthorityName: a.AuthorityName, ParentId: a.ParentId, DefaultRouter: a.DefaultRouter, } } } return info } // RegisterRoutes 注册路由 func (s *UserService) RegisterRoutes(srv *http.Server) { r := srv.Route("/") // 公开接口 r.POST("/base/login", s.handleLogin) // 需要认证的接口 r.POST("/user/register", s.handleRegister) r.POST("/user/changePassword", s.handleChangePassword) r.POST("/user/resetPassword", s.handleResetPassword) r.GET("/user/getUserInfo", s.handleGetUserInfo) r.POST("/user/getUserList", s.handleGetUserList) r.PUT("/user/setUserInfo", s.handleSetUserInfo) r.PUT("/user/setSelfInfo", s.handleSetSelfInfo) r.PUT("/user/setSelfSetting", s.handleSetSelfSetting) r.DELETE("/user/deleteUser", s.handleDeleteUser) r.POST("/user/setUserAuthority", s.handleSetUserAuthority) r.POST("/user/setUserAuthorities", s.handleSetUserAuthorities) } // HTTP Handlers func (s *UserService) handleLogin(ctx http.Context) error { var req LoginRequest if err := ctx.Bind(&req); err != nil { return err } resp, err := s.Login(ctx, &req) if err != nil { return err } return ctx.Result(200, map[string]any{ "code": 0, "msg": "登录成功", "data": resp, }) } func (s *UserService) handleRegister(ctx http.Context) error { var req RegisterRequest if err := ctx.Bind(&req); err != nil { return err } resp, err := s.Register(ctx, &req) if err != nil { return err } return ctx.Result(200, map[string]any{ "code": 0, "msg": "注册成功", "data": resp, }) } func (s *UserService) handleChangePassword(ctx http.Context) error { var req ChangePasswordRequest if err := ctx.Bind(&req); err != nil { return err } userID := middleware.GetUserID(ctx) if userID == 0 { return errors.Unauthorized("UNAUTHORIZED", "请先登录") } if err := s.ChangePassword(ctx, userID, &req); err != nil { return err } return ctx.Result(200, map[string]any{ "code": 0, "msg": "修改成功", }) } func (s *UserService) handleResetPassword(ctx http.Context) error { var req ResetPasswordRequest if err := ctx.Bind(&req); err != nil { return err } if err := s.ResetPassword(ctx, &req); err != nil { return err } return ctx.Result(200, map[string]any{ "code": 0, "msg": "重置成功", }) } func (s *UserService) handleGetUserInfo(ctx http.Context) error { claims, ok := middleware.GetClaims(ctx) if !ok { return errors.Unauthorized("UNAUTHORIZED", "请先登录") } resp, err := s.GetUserInfo(ctx, claims.UUID) if err != nil { return err } return ctx.Result(200, map[string]any{ "code": 0, "msg": "获取成功", "data": map[string]any{"userInfo": resp}, }) } func (s *UserService) handleGetUserList(ctx http.Context) error { var req GetUserListRequest if err := ctx.Bind(&req); err != nil { return err } resp, err := s.GetUserList(ctx, &req) if err != nil { return err } return ctx.Result(200, map[string]any{ "code": 0, "msg": "获取成功", "data": resp, }) } func (s *UserService) handleSetUserInfo(ctx http.Context) error { var req SetUserInfoRequest if err := ctx.Bind(&req); err != nil { return err } adminAuthorityID := middleware.GetAuthorityID(ctx) if adminAuthorityID == 0 { return errors.Unauthorized("UNAUTHORIZED", "请先登录") } if err := s.SetUserInfo(ctx, adminAuthorityID, &req); err != nil { return err } return ctx.Result(200, map[string]any{ "code": 0, "msg": "设置成功", }) } func (s *UserService) handleSetSelfInfo(ctx http.Context) error { var req SetSelfInfoRequest if err := ctx.Bind(&req); err != nil { return err } userID := middleware.GetUserID(ctx) if userID == 0 { return errors.Unauthorized("UNAUTHORIZED", "请先登录") } if err := s.SetSelfInfo(ctx, userID, &req); err != nil { return err } return ctx.Result(200, map[string]any{ "code": 0, "msg": "设置成功", }) } func (s *UserService) handleSetSelfSetting(ctx http.Context) error { var req json.RawMessage if err := ctx.Bind(&req); err != nil { return err } userID := middleware.GetUserID(ctx) if userID == 0 { return errors.Unauthorized("UNAUTHORIZED", "请先登录") } if err := s.SetSelfSetting(ctx, userID, req); err != nil { return err } return ctx.Result(200, map[string]any{ "code": 0, "msg": "设置成功", }) } func (s *UserService) handleDeleteUser(ctx http.Context) error { var req struct { ID uint `json:"id"` } if err := ctx.Bind(&req); err != nil { return err } // 不能删除自己 userID := middleware.GetUserID(ctx) if userID == req.ID { return errors.BadRequest("DELETE_SELF", "删除失败, 无法删除自己") } if err := s.DeleteUser(ctx, req.ID); err != nil { return err } return ctx.Result(200, map[string]any{ "code": 0, "msg": "删除成功", }) } func (s *UserService) handleSetUserAuthority(ctx http.Context) error { var req SetUserAuthorityRequest if err := ctx.Bind(&req); err != nil { return err } claims, ok := middleware.GetClaims(ctx) if !ok { return errors.Unauthorized("UNAUTHORIZED", "请先登录") } resp, err := s.SetUserAuthority(ctx, claims.BaseClaims.ID, claims.UUID, claims.Username, claims.NickName, &req) if err != nil { return err } // 设置响应头(与GVA保持一致) ctx.Response().Header().Set("new-token", resp.Token) ctx.Response().Header().Set("new-expires-at", fmt.Sprintf("%d", resp.ExpiresAt/1000)) return ctx.Result(200, map[string]any{ "code": 0, "msg": "修改成功", }) } func (s *UserService) handleSetUserAuthorities(ctx http.Context) error { var req SetUserAuthoritiesRequest if err := ctx.Bind(&req); err != nil { return err } adminAuthorityID := middleware.GetAuthorityID(ctx) if adminAuthorityID == 0 { return errors.Unauthorized("UNAUTHORIZED", "请先登录") } if err := s.SetUserAuthorities(ctx, adminAuthorityID, &req); err != nil { return err } return ctx.Result(200, map[string]any{ "code": 0, "msg": "修改成功", }) }