新增用户管理和个人信息功能,支持CRUD操作和密码修改

This commit is contained in:
2026-07-03 10:18:08 +08:00
parent ca9b1e751c
commit e65b31abb0
8 changed files with 801 additions and 4 deletions
+44
View File
@@ -66,6 +66,50 @@ func Login(c *gin.Context) {
})
}
type changePasswordRequest struct {
OldPassword string `json:"old_password" binding:"required"`
NewPassword string `json:"new_password" binding:"required"`
}
func ChangePassword(c *gin.Context) {
var req changePasswordRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "请输入原密码和新密码"})
return
}
if len(req.NewPassword) < 6 {
c.JSON(http.StatusBadRequest, gin.H{"error": "新密码长度不能少于6位"})
return
}
userID, _ := c.Get("user_id")
var user model.User
if err := db.DB.First(&user, userID).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"})
return
}
if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.OldPassword)); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "原密码错误"})
return
}
hash, err := bcrypt.GenerateFromPassword([]byte(req.NewPassword), bcrypt.DefaultCost)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "密码加密失败"})
return
}
if err := db.DB.Model(&user).Update("password", string(hash)).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "密码修改失败"})
return
}
c.JSON(http.StatusOK, gin.H{"message": "密码修改成功"})
}
func Me(c *gin.Context) {
userID, _ := c.Get("user_id")
username, _ := c.Get("username")
+202
View File
@@ -0,0 +1,202 @@
package handler
import (
"net/http"
"strconv"
"lmvpn/internal/db"
"lmvpn/internal/model"
"github.com/gin-gonic/gin"
"golang.org/x/crypto/bcrypt"
)
type createUserRequest struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
Role string `json:"role"`
Status *int `json:"status"`
}
type updateUserRequest struct {
Status *int `json:"status"`
Role string `json:"role"`
Password string `json:"password"`
}
type userResponse struct {
ID uint `json:"id"`
Username string `json:"username"`
Role string `json:"role"`
Status int `json:"status"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
func formatUser(u *model.User) userResponse {
return userResponse{
ID: u.ID,
Username: u.Username,
Role: u.Role,
Status: u.Status,
CreatedAt: u.CreatedAt.Format("2006-01-02 15:04:05"),
UpdatedAt: u.UpdatedAt.Format("2006-01-02 15:04:05"),
}
}
func ListUsers(c *gin.Context) {
var users []model.User
db.DB.Order("id asc").Find(&users)
result := make([]userResponse, len(users))
for i, u := range users {
result[i] = formatUser(&u)
}
c.JSON(http.StatusOK, gin.H{"users": result})
}
func CreateUser(c *gin.Context) {
var req createUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "参数错误"})
return
}
var exist model.User
if err := db.DB.Where("username = ?", req.Username).First(&exist).Error; err == nil {
c.JSON(http.StatusConflict, gin.H{"error": "用户名已存在"})
return
}
hash, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "密码加密失败"})
return
}
user := model.User{
Username: req.Username,
Password: string(hash),
Role: "user",
Status: 1,
}
if req.Role != "" {
user.Role = req.Role
}
if req.Status != nil {
user.Status = *req.Status
}
if err := db.DB.Create(&user).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "创建用户失败"})
return
}
c.JSON(http.StatusOK, formatUser(&user))
}
func UpdateUser(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "参数错误"})
return
}
currentUserID, _ := c.Get("user_id")
var user model.User
if err := db.DB.First(&user, id).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"})
return
}
var req updateUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "参数错误"})
return
}
updates := map[string]interface{}{}
if req.Status != nil {
updates["status"] = *req.Status
}
if req.Role != "" {
if user.ID == currentUserID.(uint) {
c.JSON(http.StatusBadRequest, gin.H{"error": "不能修改自己的角色"})
return
}
if req.Role != "admin" && user.Role == "admin" {
var adminCount int64
db.DB.Model(&model.User{}).Where("role = ?", "admin").Count(&adminCount)
if adminCount <= 1 {
c.JSON(http.StatusBadRequest, gin.H{"error": "系统至少需要保留一个管理员"})
return
}
}
updates["role"] = req.Role
}
if req.Password != "" {
hash, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "密码加密失败"})
return
}
updates["password"] = string(hash)
}
if len(updates) == 0 {
c.JSON(http.StatusBadRequest, gin.H{"error": "没有需要更新的字段"})
return
}
if err := db.DB.Model(&user).Updates(updates).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "更新用户失败"})
return
}
db.DB.First(&user, id)
c.JSON(http.StatusOK, formatUser(&user))
}
func DeleteUser(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "参数错误"})
return
}
currentUserID, _ := c.Get("user_id")
if uint(id) == currentUserID.(uint) {
c.JSON(http.StatusBadRequest, gin.H{"error": "不能删除自己"})
return
}
var user model.User
if err := db.DB.First(&user, id).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"})
return
}
if user.Role == "admin" {
var adminCount int64
db.DB.Model(&model.User{}).Where("role = ?", "admin").Count(&adminCount)
if adminCount <= 1 {
c.JSON(http.StatusBadRequest, gin.H{"error": "系统至少需要保留一个管理员"})
return
}
}
if err := db.DB.Delete(&user).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "删除用户失败"})
return
}
c.JSON(http.StatusOK, gin.H{"message": "删除成功"})
}