Files
mce/internal/controller/admin/admin_controller.go
Victor_Jay f0bf450725 feat: 管理首页帖子总数统计(总数/已发布/待审核)
- PostRepo 新增 CountPostsByStatus 和 CountPending 方法
- Service 层定义 postAdminStatStore 接口 (ISP)
- AdminService 注入 postRepo,新增 PostStats 结构体和 GetPostStats 方法
- AdminController.Dashboard 调用 GetPostStats 并传参到模板
- Dashboard 帖子卡片显示总数 + 已发布 + 待审核(橙色徽章)
- DI 层将 AdminController 创建从 buildDepsCore 移至 buildDeps,以便注入 postRepo
2026-05-31 12:46:06 +08:00

154 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 admin
import (
"net/http"
"strconv"
"metazone.cc/metalab/internal/common"
"metazone.cc/metalab/internal/model"
"metazone.cc/metalab/internal/service"
"github.com/gin-gonic/gin"
)
// Note: service import kept for ListUsersParams / ListUsersResult DTOs
// AdminController 管理后台控制器
type AdminController struct {
adminService adminUseCase
}
// NewAdminController 构造函数
func NewAdminController(adminService adminUseCase) *AdminController {
return &AdminController{adminService: adminService}
}
// Dashboard 管理首页(欢迎页)
func (ac *AdminController) Dashboard(c *gin.Context) {
totalUsers, err := ac.adminService.CountUsers()
if err != nil {
totalUsers = 0
}
postStats, err := ac.adminService.GetPostStats()
if err != nil {
postStats = &service.PostStats{}
}
storeMetrics := ac.adminService.GetStoreMetrics()
c.HTML(http.StatusOK, "admin/dashboard/index.html", common.BuildAdminPageData(c, gin.H{
"Title": "管理首页",
"TotalUsers": totalUsers,
"PostTotal": postStats.Total,
"PostApproved": postStats.Approved,
"PostPending": postStats.Pending,
"StoreType": storeMetrics.Type,
"StoreHealthy": storeMetrics.Healthy,
"StoreDegraded": storeMetrics.Degraded,
"DegradedNote": storeMetrics.DegradedNote,
"ActiveSessions": storeMetrics.ActiveCount,
}))
}
// UsersPage 用户管理页面
func (ac *AdminController) UsersPage(c *gin.Context) {
c.HTML(http.StatusOK, "admin/users/index.html", common.BuildAdminPageData(c, gin.H{
"Title": "用户管理",
"ExtraCSS": "/admin/static/css/users.css",
"ExtraJS": "/admin/static/js/users.js",
"RoleNames": model.RoleDisplayNames,
"StatusNames": model.StatusDisplayNames,
}))
}
// ListUsers 用户列表 API分页 + 搜索 + 筛选)
func (ac *AdminController) ListUsers(c *gin.Context) {
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
params := service.ListUsersParams{
Keyword: c.Query("keyword"),
Role: c.Query("role"),
Status: c.Query("status"),
Page: page,
PageSize: pageSize,
}
result, err := ac.adminService.ListUsers(params)
if err != nil {
common.Error(c, http.StatusInternalServerError, "查询失败")
return
}
common.Ok(c, result)
}
// UpdateUserStatus 封禁/解封用户
func (ac *AdminController) UpdateUserStatus(c *gin.Context) {
targetUID, err := parseUIDParam(c)
if err != nil {
common.Error(c, http.StatusBadRequest, "无效的用户 ID")
return
}
var req struct {
Status string `json:"status" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
common.Error(c, http.StatusBadRequest, "参数错误")
return
}
operatorUID := c.GetUint("uid")
if err := ac.adminService.UpdateUserStatus(operatorUID, targetUID, req.Status); err != nil {
handleServiceError(c, err)
return
}
action := "封禁"
if req.Status == model.StatusActive {
action = "解封"
} else if req.Status == model.StatusLocked {
action = "已锁定"
}
common.OkMessage(c, action+"成功")
}
// ResetToken 强制用户下线
func (ac *AdminController) ResetToken(c *gin.Context) {
targetUID, err := parseUIDParam(c)
if err != nil {
common.Error(c, http.StatusBadRequest, "无效的用户 ID")
return
}
operatorUID := c.GetUint("uid")
if err := ac.adminService.ResetUserToken(operatorUID, targetUID); err != nil {
handleServiceError(c, err)
return
}
common.OkMessage(c, "已强制下线")
}
// parseUIDParam 从 URL 路径参数解析 uid
func parseUIDParam(c *gin.Context) (uint, error) {
uid, err := strconv.ParseUint(c.Param("uid"), 10, 64)
if err != nil {
return 0, err
}
return uint(uid), nil
}
// handleServiceError 统一处理 service 层返回的错误
func handleServiceError(c *gin.Context, err error) {
switch err {
case common.ErrPermissionDenied:
common.Error(c, http.StatusForbidden, "权限不足")
case common.ErrUserNotFound:
common.Error(c, http.StatusNotFound, "用户不存在")
case common.ErrEmailExists:
common.Error(c, http.StatusConflict, "该邮箱已被其他用户注册,无法解锁")
default:
common.Error(c, http.StatusInternalServerError, "操作失败")
}
}