Files
doubaochat/backend/api/admin.go
T

360 lines
9.4 KiB
Go
Raw Normal View History

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)
}
}