package api import ( "net/http" "time" "d:\项目\dobaochet\backend\config" "d:\项目\dobaochet\backend\db" "d:\项目\dobaochet\backend\models" "d:\项目\dobaochet\backend\utils" "github.com/gin-gonic/gin" ) // AdminAPI 管理员API结构体 type AdminAPI struct { cfg *config.Config } // NewAdminAPI 创建管理员API实例 func NewAdminAPI(cfg *config.Config) *AdminAPI { return &AdminAPI{cfg: cfg} } // GetUsers 获取所有用户 func (api *AdminAPI) GetUsers(c *gin.Context) { // 分页参数 page := 1 pageSize := 10 c.Query("page") c.Query("page_size") // 查询用户列表 var users []models.User var total int64 db.GetDB().Model(&models.User{}).Count(&total) db.GetDB().Preload("Quota").Order("created_at desc").Offset((page - 1) * pageSize).Limit(pageSize).Find(&users) // 转换为响应格式 var userResponses []models.UserResponse for _, user := range users { userResponses = append(userResponses, models.UserResponse{ ID: user.ID, Username: user.Username, Email: user.Email, IsAdmin: user.IsAdmin, IsActive: user.IsActive, CreatedAt: user.CreatedAt, Quota: user.Quota, }) } c.JSON(http.StatusOK, gin.H{ "users": userResponses, "total": total, "page": page, "page_size": pageSize, "total_pages": (total + int64(pageSize) - 1) / int64(pageSize), }) } // GetUser 获取单个用户 func (api *AdminAPI) GetUser(c *gin.Context) { // 获取用户ID id := c.Param("id") // 查询用户 var user models.User if result := db.GetDB().Preload("Quota").First(&user, id); result.Error != nil { c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"}) return } c.JSON(http.StatusOK, models.UserResponse{ ID: user.ID, Username: user.Username, Email: user.Email, IsAdmin: user.IsAdmin, IsActive: user.IsActive, CreatedAt: user.CreatedAt, Quota: user.Quota, }) } // CreateUser 创建用户 func (api *AdminAPI) CreateUser(c *gin.Context) { var req struct { Username string `json:"username" binding:"required,min=3,max=50"` Email string `json:"email" binding:"required,email"` Password string `json:"password" binding:"required,min=6"` IsAdmin bool `json:"is_admin"` IsActive bool `json:"is_active"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 检查用户名是否已存在 var existingUser models.User if result := db.GetDB().Where("username = ?", req.Username).First(&existingUser); result.Error == nil { c.JSON(http.StatusConflict, gin.H{"error": "用户名已存在"}) return } // 检查邮箱是否已存在 if result := db.GetDB().Where("email = ?", req.Email).First(&existingUser); result.Error == nil { c.JSON(http.StatusConflict, gin.H{"error": "邮箱已存在"}) return } // 密码加密 hashedPassword, err := utils.HashPassword(req.Password) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "密码加密失败"}) return } // 创建用户 user := models.User{ Username: req.Username, Email: req.Email, Password: hashedPassword, IsAdmin: req.IsAdmin, IsActive: req.IsActive, LastLoginAt: time.Now(), Quota: models.Quota{ TotalTokens: api.cfg.Quota.DefaultTotalTokens, UsedTokens: 0, ResetAt: time.Now().Add(api.cfg.Quota.ResetInterval), TokenLimit: api.cfg.Quota.DefaultTokenLimit, }, } if result := db.GetDB().Create(&user); result.Error != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "创建用户失败"}) return } c.JSON(http.StatusCreated, models.UserResponse{ ID: user.ID, Username: user.Username, Email: user.Email, IsAdmin: user.IsAdmin, IsActive: user.IsActive, CreatedAt: user.CreatedAt, Quota: user.Quota, }) } // UpdateUser 更新用户 func (api *AdminAPI) UpdateUser(c *gin.Context) { // 获取用户ID id := c.Param("id") // 查询用户 var user models.User if result := db.GetDB().First(&user, id); result.Error != nil { c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"}) return } // 解析请求 var req struct { Email string `json:"email" binding:"omitempty,email"` IsAdmin bool `json:"is_admin"` IsActive bool `json:"is_active"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 更新用户信息 if req.Email != "" && req.Email != user.Email { // 检查邮箱是否已被使用 var existingUser models.User if result := db.GetDB().Where("email = ? AND id != ?", req.Email, user.ID).First(&existingUser); result.Error == nil { c.JSON(http.StatusConflict, gin.H{"error": "邮箱已被使用"}) return } user.Email = req.Email } user.IsAdmin = req.IsAdmin user.IsActive = req.IsActive if result := db.GetDB().Save(&user); result.Error != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "更新用户失败"}) return } // 重新加载用户信息 db.GetDB().Preload("Quota").First(&user, id) c.JSON(http.StatusOK, models.UserResponse{ ID: user.ID, Username: user.Username, Email: user.Email, IsAdmin: user.IsAdmin, IsActive: user.IsActive, CreatedAt: user.CreatedAt, Quota: user.Quota, }) } // DeleteUser 删除用户 func (api *AdminAPI) DeleteUser(c *gin.Context) { // 获取用户ID id := c.Param("id") // 检查是否是最后一个管理员 var user models.User if result := db.GetDB().First(&user, id); result.Error != nil { c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"}) return } if user.IsAdmin { var adminCount int64 db.GetDB().Model(&models.User{}).Where("is_admin = ?", true).Count(&adminCount) if adminCount <= 1 { c.JSON(http.StatusBadRequest, gin.H{"error": "不能删除最后一个管理员用户"}) return } } // 删除用户(级联删除相关数据) if result := db.GetDB().Delete(&user); result.Error != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "删除用户失败"}) return } c.JSON(http.StatusOK, gin.H{"message": "用户删除成功"}) } // UpdateUserQuota 更新用户配额 func (api *AdminAPI) UpdateUserQuota(c *gin.Context) { // 获取用户ID id := c.Param("id") // 查询用户 var user models.User if result := db.GetDB().Preload("Quota").First(&user, id); result.Error != nil { c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"}) return } // 解析请求 var req models.QuotaUpdateRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 更新配额 user.Quota.TotalTokens = req.TotalTokens user.Quota.TokenLimit = req.TokenLimit if result := db.GetDB().Save(&user.Quota); result.Error != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "更新配额失败"}) return } c.JSON(http.StatusOK, gin.H{ "message": "配额更新成功", "quota": user.Quota, }) } // ResetUserQuota 重置用户配额 func (api *AdminAPI) ResetUserQuota(c *gin.Context) { // 获取用户ID id := c.Param("id") // 查询用户 var user models.User if result := db.GetDB().Preload("Quota").First(&user, id); result.Error != nil { c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"}) return } // 重置配额 user.Quota.UsedTokens = 0 user.Quota.ResetAt = time.Now().Add(api.cfg.Quota.ResetInterval) if result := db.GetDB().Save(&user.Quota); result.Error != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "重置配额失败"}) return } c.JSON(http.StatusOK, gin.H{ "message": "配额重置成功", "quota": user.Quota, }) } // GetSystemStats 获取系统统计信息 func (api *AdminAPI) GetSystemStats(c *gin.Context) { // 用户统计 var totalUsers, activeUsers, adminUsers int64 db.GetDB().Model(&models.User{}).Count(&totalUsers) db.GetDB().Model(&models.User{}).Where("is_active = ?", true).Count(&activeUsers) db.GetDB().Model(&models.User{}).Where("is_admin = ?", true).Count(&adminUsers) // 对话统计 var totalConversations int64 db.GetDB().Model(&models.Conversation{}).Count(&totalConversations) // 消息统计 var totalMessages int64 db.GetDB().Model(&models.Message{}).Count(&totalMessages) // 配额统计 var totalTokens, usedTokens int64 db.GetDB().Model(&models.Quota{}).Select("sum(total_tokens) as total_tokens, sum(used_tokens) as used_tokens").Scan(&struct { TotalTokens int64 UsedTokens int64 }{TotalTokens: &totalTokens, UsedTokens: &usedTokens}) c.JSON(http.StatusOK, gin.H{ "users": gin.H{ "total": totalUsers, "active": activeUsers, "admin": adminUsers, }, "conversations": totalConversations, "messages": totalMessages, "quota": gin.H{ "total_tokens": totalTokens, "used_tokens": usedTokens, "usage_rate": float64(usedTokens) / float64(totalTokens) * 100, }, }) } // RegisterRoutes 注册管理员路由 func (api *AdminAPI) RegisterRoutes(router *gin.RouterGroup) { adminGroup := router.Group("/admin") adminGroup.Use(AuthMiddleware(api.cfg), AdminMiddleware()) { // 用户管理 adminGroup.GET("/users", api.GetUsers) adminGroup.GET("/users/:id", api.GetUser) adminGroup.POST("/users", api.CreateUser) adminGroup.PUT("/users/:id", api.UpdateUser) adminGroup.DELETE("/users/:id", api.DeleteUser) // 配额管理 adminGroup.PUT("/users/:id/quota", api.UpdateUserQuota) adminGroup.POST("/users/:id/quota/reset", api.ResetUserQuota) // 系统统计 adminGroup.GET("/stats", api.GetSystemStats) } }