This repository has been archived on 2026-06-21. You can view files and clone it, but cannot push or open issues or pull requests.
Files
MetaLab/internal/service/admin_service.go
Victor_Jay 3937945b43 feat(admin): 管理首页标题修正、角色中文显示及用户总数补全
- 修正 admin layout title 后缀为「MetaLab 管理面板」
- 当前角色从原始字符串改为中文显示(注入 RoleDisplayName)
- 补全管理首页「用户总数」统计,新增 CountUsers 方法
- 遵循 ISP 最小接口,Service 复用已有 CountSearchUsers
2026-05-26 23:21:32 +08:00

146 lines
4.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package service
import (
"metazone.cc/metalab/internal/common"
"metazone.cc/metalab/internal/model"
)
// AdminService 管理后台业务逻辑
// 集中处理所有权限边界检查,避免胖控制器
type AdminService struct {
userRepo userAdminStore
}
// NewAdminService 构造函数
func NewAdminService(userRepo userAdminStore) *AdminService {
return &AdminService{userRepo: userRepo}
}
// ListUsersParams 用户列表查询参数
type ListUsersParams struct {
Keyword string // 搜索关键字(邮箱/用户名)
Role string // 角色筛选
Status string // 状态筛选
Page int // 页码
PageSize int // 每页条数
}
// ListUsersResult 用户列表查询结果
type ListUsersResult struct {
Users []model.User `json:"users"`
Total int64 `json:"total"`
Page int `json:"page"`
}
// ListUsers 分页搜索用户列表
func (s *AdminService) ListUsers(params ListUsersParams) (*ListUsersResult, error) {
if params.Page < 1 {
params.Page = 1
}
if params.PageSize < 1 || params.PageSize > 100 {
params.PageSize = 20
}
offset := (params.Page - 1) * params.PageSize
total, err := s.userRepo.CountSearchUsers(params.Keyword, params.Role, params.Status)
if err != nil {
return nil, err
}
users, err := s.userRepo.SearchUsers(params.Keyword, params.Role, params.Status, offset, params.PageSize)
if err != nil {
return nil, err
}
return &ListUsersResult{
Users: users,
Total: total,
Page: params.Page,
}, nil
}
// UpdateUserStatus 修改用户状态
// 权限规则:
// - 不可操作自己
// - Admin 只能设置 active/banned且只能操作 RoleUser
// - Owner 可设置 active/banned/locked可操作任何人除自己
func (s *AdminService) UpdateUserStatus(operatorUID, targetUID uint, newStatus string) error {
// 校验状态值合法性
switch newStatus {
case model.StatusActive, model.StatusBanned, model.StatusLocked:
default:
return common.ErrPermissionDenied
}
return s.checkAndOperate(operatorUID, targetUID, func(operator, target *model.User) error {
// locked 相关操作仅 owner
if target.Status == model.StatusLocked || newStatus == model.StatusLocked {
if !model.HasMinRole(operator.Role, model.RoleOwner) {
return common.ErrPermissionDenied
}
}
if err := s.userRepo.UpdateStatus(target.ID, newStatus); err != nil {
return err
}
// 锁定(删除)→ GORM 软删除释放邮箱;解锁 → 先查邮箱冲突再恢复
if newStatus == model.StatusLocked {
if err := s.userRepo.SoftDelete(target.ID); err != nil {
return err
}
} else if target.Status == model.StatusLocked && newStatus == model.StatusActive {
// 检查邮箱是否已被新用户注册(软删期间邮箱释放了)
collision, err := s.userRepo.ExistsByEmailExclude(target.Email, target.ID)
if err != nil {
return err
}
if collision {
return common.ErrEmailExists
}
if err := s.userRepo.Restore(target.ID); err != nil {
return err
}
}
// 修改状态必须立刻让 JWT 失效
return s.userRepo.IncrementTokenVersion(target.ID)
})
}
// ResetUserToken 强制下线(递增 token_version
func (s *AdminService) ResetUserToken(operatorUID, targetUID uint) error {
return s.checkAndOperate(operatorUID, targetUID, func(_ *model.User, target *model.User) error {
return s.userRepo.IncrementTokenVersion(target.ID)
})
}
// CountUsers 统计用户总数(管理首页用)
func (s *AdminService) CountUsers() (int64, error) {
return s.userRepo.CountSearchUsers("", "", "")
}
// checkAndOperate 通用权限检查 + 执行操作
func (s *AdminService) checkAndOperate(operatorUID, targetUID uint, operate func(*model.User, *model.User) error) error {
// 1. 不可操作自己
if operatorUID == targetUID {
return common.ErrPermissionDenied
}
// 2. 查操作者
operator, err := s.userRepo.FindByIDUnscoped(operatorUID)
if err != nil {
return common.ErrUserNotFound
}
// 3. 查目标含软删除用户locked 解锁需要查到)
target, err := s.userRepo.FindByIDUnscoped(targetUID)
if err != nil {
return common.ErrUserNotFound
}
// 4. 权限检查:操作者是否有权限操作目标角色
if !model.CanOperateRole(operator.Role, target.Role) {
return common.ErrPermissionDenied
}
return operate(operator, target)
}