Files
soul-yongping/soul-api/internal/handler/admin_users.go

241 lines
7.0 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 handler
import (
"net/http"
"strconv"
"strings"
"soul-api/internal/database"
"soul-api/internal/middleware"
"soul-api/internal/model"
"github.com/gin-gonic/gin"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)
// AdminUsersList GET /api/admin/users 管理员用户列表(仅 super_admin
func AdminUsersList(c *gin.Context) {
claims := middleware.GetAdminClaims(c)
if claims == nil || claims.Role != "super_admin" {
c.JSON(http.StatusForbidden, gin.H{"success": false, "error": "无权限"})
return
}
db := database.DB()
page, _ := strconv.Atoi(c.Query("page"))
if page < 1 {
page = 1
}
pageSize, _ := strconv.Atoi(c.Query("pageSize"))
if pageSize < 1 {
pageSize = 10
}
if pageSize > 100 {
pageSize = 100
}
search := strings.TrimSpace(c.Query("search"))
var total int64
q := db.Model(&model.AdminUser{})
if search != "" {
q = q.Where("username LIKE ? OR name LIKE ?", "%"+search+"%", "%"+search+"%")
}
if err := q.Count(&total).Error; err != nil {
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})
return
}
var list []model.AdminUser
offset := (page - 1) * pageSize
if err := q.Order("id ASC").Offset(offset).Limit(pageSize).Find(&list).Error; err != nil {
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})
return
}
records := make([]gin.H, 0, len(list))
for _, u := range list {
records = append(records, gin.H{
"id": u.ID,
"username": u.Username,
"role": u.Role,
"name": u.Name,
"status": u.Status,
"createdAt": u.CreatedAt,
"updatedAt": u.UpdatedAt,
})
}
totalPages := (int(total) + pageSize - 1) / pageSize
c.JSON(http.StatusOK, gin.H{
"success": true,
"records": records,
"total": total,
"page": page,
"pageSize": pageSize,
"totalPages": totalPages,
})
}
// AdminUsersAction POST/PUT/DELETE /api/admin/users 管理员用户增删改(仅 super_admin
func AdminUsersAction(c *gin.Context) {
claims := middleware.GetAdminClaims(c)
if claims == nil || claims.Role != "super_admin" {
c.JSON(http.StatusForbidden, gin.H{"success": false, "error": "无权限"})
return
}
db := database.DB()
switch c.Request.Method {
case http.MethodPost:
var body struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
Name string `json:"name"`
Role string `json:"role"`
}
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "参数错误"})
return
}
username := trimSpace(body.Username)
if len(username) < 2 {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "用户名至少 2 个字符"})
return
}
if len(body.Password) < 6 {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "密码至少 6 位"})
return
}
role := trimSpace(body.Role)
if role != "super_admin" && role != "admin" {
role = "admin"
}
hash, err := bcrypt.GenerateFromPassword([]byte(body.Password), bcrypt.DefaultCost)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": "密码加密失败"})
return
}
u := model.AdminUser{
Username: username,
PasswordHash: string(hash),
Role: role,
Name: trimSpace(body.Name),
Status: "active",
}
if err := db.Create(&u).Error; err != nil {
if strings.Contains(err.Error(), "Duplicate") || strings.Contains(err.Error(), "1062") {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "用户名已存在"})
return
}
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"data": gin.H{
"id": u.ID,
"username": u.Username,
"role": u.Role,
"name": u.Name,
"status": u.Status,
"createdAt": u.CreatedAt,
},
})
case http.MethodPut:
var body struct {
ID uint `json:"id" binding:"required"`
Password string `json:"password"`
Name string `json:"name"`
Role string `json:"role"`
Status string `json:"status"`
}
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "参数错误"})
return
}
var u model.AdminUser
if err := db.First(&u, body.ID).Error; err != nil {
if err == gorm.ErrRecordNotFound {
c.JSON(http.StatusNotFound, gin.H{"success": false, "error": "用户不存在"})
return
}
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})
return
}
updates := make(map[string]interface{})
updates["name"] = trimSpace(body.Name)
if body.Role == "super_admin" || body.Role == "admin" {
updates["role"] = body.Role
}
if body.Status == "active" || body.Status == "disabled" {
updates["status"] = body.Status
}
if body.Password != "" {
if len(body.Password) < 6 {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "新密码至少 6 位"})
return
}
hash, err := bcrypt.GenerateFromPassword([]byte(body.Password), bcrypt.DefaultCost)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": "密码加密失败"})
return
}
updates["password_hash"] = string(hash)
}
if len(updates) > 0 {
if err := db.Model(&u).Updates(updates).Error; err != nil {
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})
return
}
}
var updated model.AdminUser
_ = db.First(&updated, u.ID)
c.JSON(http.StatusOK, gin.H{
"success": true,
"data": gin.H{
"id": updated.ID,
"username": updated.Username,
"role": updated.Role,
"name": updated.Name,
"status": updated.Status,
"updatedAt": updated.UpdatedAt,
},
})
case http.MethodDelete:
id := c.Query("id")
if id == "" {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "缺少 id"})
return
}
uid64, err := strconv.ParseUint(strings.TrimSpace(id), 10, 32)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "id 无效"})
return
}
uid := uint(uid64)
var u model.AdminUser
if err := db.First(&u, uid).Error; err != nil {
if err == gorm.ErrRecordNotFound {
c.JSON(http.StatusOK, gin.H{"success": true})
return
}
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})
return
}
if u.Username == claims.Username {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "不能删除当前登录账号"})
return
}
if u.Role == "super_admin" {
var cnt int64
db.Model(&model.AdminUser{}).Where("role = ?", "super_admin").Count(&cnt)
if cnt <= 1 {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "至少保留一个超级管理员"})
return
}
}
if err := db.Delete(&u).Error; err != nil {
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"success": true})
default:
c.JSON(http.StatusMethodNotAllowed, gin.H{"success": false, "error": "方法不支持"})
}
}