feat: Phase 1 完成 — 基础设施 + 用户认证 + 管理端 + 端到端验证

Phase 1 (基础设施与用户认证) 全部 11 个 Task 开发完成:

后端 (Go):
- Auth 模块: 注册/登录/JWT(有状态)/Profile/密码修改
- Admin 模块: 用户列表/详情/禁用/启用/角色分配/创建用户
- 中间件: JWT认证 + RBAC角色权限 + 请求日志 + CORS + Panic恢复
- Dockerfile 多阶段构建 + Docker Compose 全栈部署

前台 (uni-app):
- 登录/注册页面 + 自定义 TabBar + 个人中心
- 请求封装 + 状态管理 (Pinia)

管理端 (Vue 3 + Element Plus):
- 登录/仪表盘/用户列表/用户详情
- Axios 封装 + 路由守卫 + Pinia 状态管理

验证:
- 全流程 API 端到端测试通过
- Playwright 页面自动化验证通过
- code-reviewer 代码审查通过

Made-with: Cursor
This commit is contained in:
bujinyuan
2026-03-02 11:31:24 +08:00
parent e9bd4dd204
commit 4d03215fe4
63 changed files with 15908 additions and 102 deletions

View File

@@ -0,0 +1,202 @@
// Package controller 提供 admin 模块的 HTTP 请求处理
package controller
import (
"strconv"
"github.com/echochat/backend/app/admin/service"
"github.com/echochat/backend/app/dto"
"github.com/echochat/backend/pkg/logs"
"github.com/echochat/backend/pkg/middleware"
"github.com/echochat/backend/pkg/utils"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
// UserManageController 管理端用户管理控制器
type UserManageController struct {
userManageService *service.UserManageService
}
// NewUserManageController 创建用户管理控制器实例
func NewUserManageController(svc *service.UserManageService) *UserManageController {
return &UserManageController{userManageService: svc}
}
// GetUserList 获取用户列表
// GET /api/v1/admin/users?page=1&page_size=10&keyword=xxx&status=1
func (ctl *UserManageController) GetUserList(c *gin.Context) {
funcName := "controller.user_manage_controller.GetUserList"
ctx := c.Request.Context()
var req dto.UserListRequest
if err := c.ShouldBindQuery(&req); err != nil {
logs.Warn(ctx, funcName, "参数校验失败", zap.Error(err))
utils.ResponseBadRequest(c, "参数错误: "+err.Error())
return
}
logs.Info(ctx, funcName, "获取用户列表",
zap.Int("page", req.Page),
zap.Int("page_size", req.PageSize),
zap.String("keyword", req.Keyword),
)
resp, err := ctl.userManageService.GetUserList(ctx, &req)
if err != nil {
logs.Error(ctx, funcName, "获取用户列表失败", zap.Error(err))
utils.ResponseError(c, "获取用户列表失败")
return
}
utils.ResponseOK(c, resp)
}
// GetUserDetail 获取用户详情
// GET /api/v1/admin/users/:id
func (ctl *UserManageController) GetUserDetail(c *gin.Context) {
funcName := "controller.user_manage_controller.GetUserDetail"
ctx := c.Request.Context()
userID, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
utils.ResponseBadRequest(c, "无效的用户 ID")
return
}
logs.Info(ctx, funcName, "获取用户详情", zap.Int64("user_id", userID))
detail, err := ctl.userManageService.GetUserDetail(ctx, userID)
if err != nil {
if err == service.ErrUserNotFound {
utils.ResponseNotFound(c, "用户不存在")
return
}
logs.Error(ctx, funcName, "获取用户详情失败", zap.Error(err))
utils.ResponseError(c, "获取用户详情失败")
return
}
utils.ResponseOK(c, detail)
}
// UpdateUserStatus 更新用户状态(启用/禁用)
// PUT /api/v1/admin/users/:id/status
func (ctl *UserManageController) UpdateUserStatus(c *gin.Context) {
funcName := "controller.user_manage_controller.UpdateUserStatus"
ctx := c.Request.Context()
userID, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
utils.ResponseBadRequest(c, "无效的用户 ID")
return
}
var req dto.UpdateUserStatusRequest
if err := c.ShouldBindJSON(&req); err != nil {
logs.Warn(ctx, funcName, "参数校验失败", zap.Error(err))
utils.ResponseBadRequest(c, "参数错误: "+err.Error())
return
}
adminUserID, ok := middleware.GetCurrentUserID(c)
if !ok {
utils.ResponseUnauthorized(c, "无法获取当前用户信息")
return
}
logs.Info(ctx, funcName, "更新用户状态",
zap.Int64("target_user_id", userID),
zap.Int("status", req.Status),
zap.Int64("admin_user_id", adminUserID),
)
if err := ctl.userManageService.UpdateUserStatus(ctx, userID, req.Status, adminUserID); err != nil {
switch err {
case service.ErrUserNotFound:
utils.ResponseNotFound(c, "用户不存在")
case service.ErrCannotDisableSelf:
utils.ResponseBadRequest(c, "不能禁用自己的账号")
case service.ErrInvalidStatus:
utils.ResponseBadRequest(c, "无效的用户状态")
default:
logs.Error(ctx, funcName, "更新用户状态失败", zap.Error(err))
utils.ResponseError(c, "更新用户状态失败")
}
return
}
utils.ResponseOK(c, nil)
}
// AssignRole 分配角色
// PUT /api/v1/admin/users/:id/role
func (ctl *UserManageController) AssignRole(c *gin.Context) {
funcName := "controller.user_manage_controller.AssignRole"
ctx := c.Request.Context()
userID, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
utils.ResponseBadRequest(c, "无效的用户 ID")
return
}
var req dto.AssignRoleRequest
if err := c.ShouldBindJSON(&req); err != nil {
logs.Warn(ctx, funcName, "参数校验失败", zap.Error(err))
utils.ResponseBadRequest(c, "参数错误: "+err.Error())
return
}
logs.Info(ctx, funcName, "分配角色",
zap.Int64("user_id", userID),
zap.String("role_code", req.RoleCode),
)
if err := ctl.userManageService.AssignUserRole(ctx, userID, req.RoleCode); err != nil {
switch err {
case service.ErrUserNotFound:
utils.ResponseNotFound(c, "用户不存在")
case service.ErrInvalidRole:
utils.ResponseBadRequest(c, "无效的角色代码")
default:
logs.Error(ctx, funcName, "分配角色失败", zap.Error(err))
utils.ResponseError(c, "分配角色失败")
}
return
}
utils.ResponseOK(c, nil)
}
// CreateUser 管理员手动创建用户
// POST /api/v1/admin/users
func (ctl *UserManageController) CreateUser(c *gin.Context) {
funcName := "controller.user_manage_controller.CreateUser"
ctx := c.Request.Context()
var req dto.AdminCreateUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
logs.Warn(ctx, funcName, "参数校验失败", zap.Error(err))
utils.ResponseBadRequest(c, "参数错误: "+err.Error())
return
}
logs.Info(ctx, funcName, "管理员创建用户",
zap.String("username", req.Username),
zap.String("email", logs.MaskEmail(req.Email)),
)
userInfo, err := ctl.userManageService.CreateUser(ctx, &req)
if err != nil {
if err == service.ErrUserExists {
utils.ResponseBadRequest(c, "用户名或邮箱已被注册")
return
}
logs.Error(ctx, funcName, "创建用户失败", zap.Error(err))
utils.ResponseError(c, "创建用户失败")
return
}
utils.ResponseOK(c, userInfo)
}