3ddd4db126
Adds /api/users endpoints (admin only) plus /api/users/assignable (admin + technician) used by the aftersales reassign picker. Guards prevent self-demotion, self-deletion, and removing the last admin. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
210 lines
5.4 KiB
Go
210 lines
5.4 KiB
Go
package controllers
|
||
|
||
import (
|
||
"net/http"
|
||
"strconv"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
|
||
"git.beifan.cn/trace-system/backend-go/models"
|
||
"git.beifan.cn/trace-system/backend-go/services"
|
||
)
|
||
|
||
// UsersController 用户管理控制器
|
||
type UsersController struct {
|
||
usersService services.UsersService
|
||
}
|
||
|
||
// NewUsersController 创建用户管理控制器实例
|
||
func NewUsersController() *UsersController {
|
||
return &UsersController{
|
||
usersService: services.UsersService{},
|
||
}
|
||
}
|
||
|
||
// Create 创建用户(管理员)
|
||
// @Summary 创建用户
|
||
// @Tags 用户管理
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security BearerAuth
|
||
// @Param data body models.CreateUserDTO true "用户数据"
|
||
// @Success 200 {object} models.DataResponse
|
||
// @Failure 400 {object} models.ErrorResponse
|
||
// @Failure 401 {object} models.ErrorResponse
|
||
// @Router /users [post]
|
||
func (c *UsersController) Create(ctx *gin.Context) {
|
||
var dto models.CreateUserDTO
|
||
if !BindJSON(ctx, &dto) {
|
||
return
|
||
}
|
||
|
||
user, err := c.usersService.Create(dto)
|
||
if err != nil {
|
||
ErrorResponse(ctx, http.StatusBadRequest, err.Error())
|
||
return
|
||
}
|
||
|
||
SuccessResponse(ctx, "用户创建成功", gin.H{
|
||
"user": user,
|
||
})
|
||
}
|
||
|
||
// FindAll 用户列表
|
||
// @Summary 用户列表
|
||
// @Tags 用户管理
|
||
// @Produce json
|
||
// @Security BearerAuth
|
||
// @Param page query int false "页码"
|
||
// @Param limit query int false "每页数量"
|
||
// @Param role query string false "角色筛选"
|
||
// @Param search query string false "搜索"
|
||
// @Success 200 {object} models.PaginationResponse
|
||
// @Failure 401 {object} models.ErrorResponse
|
||
// @Router /users [get]
|
||
func (c *UsersController) FindAll(ctx *gin.Context) {
|
||
page, _ := strconv.Atoi(ctx.DefaultQuery("page", "1"))
|
||
limit, _ := strconv.Atoi(ctx.DefaultQuery("limit", "20"))
|
||
role := ctx.DefaultQuery("role", "")
|
||
search := ctx.DefaultQuery("search", "")
|
||
|
||
users, total, totalPages, err := c.usersService.FindAll(page, limit, role, search)
|
||
if err != nil {
|
||
ErrorResponse(ctx, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
SuccessResponse(ctx, "获取用户列表成功", gin.H{
|
||
"data": users,
|
||
"pagination": gin.H{
|
||
"page": page,
|
||
"limit": limit,
|
||
"total": total,
|
||
"totalPages": totalPages,
|
||
},
|
||
})
|
||
}
|
||
|
||
// FindAssignable 获取可分配的用户(admin + technician)
|
||
// @Summary 获取可分配用户列表
|
||
// @Description 用于售后工单分配选择技术员/管理员,无需分页
|
||
// @Tags 用户管理
|
||
// @Produce json
|
||
// @Security BearerAuth
|
||
// @Success 200 {object} models.DataResponse
|
||
// @Failure 401 {object} models.ErrorResponse
|
||
// @Router /users/assignable [get]
|
||
func (c *UsersController) FindAssignable(ctx *gin.Context) {
|
||
users, err := c.usersService.FindAssignable()
|
||
if err != nil {
|
||
ErrorResponse(ctx, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
SuccessResponse(ctx, "获取可分配用户成功", gin.H{
|
||
"data": users,
|
||
})
|
||
}
|
||
|
||
// Update 更新用户信息
|
||
// @Summary 更新用户
|
||
// @Tags 用户管理
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security BearerAuth
|
||
// @Param id path int true "用户 ID"
|
||
// @Param data body models.UpdateUserDTO true "更新数据"
|
||
// @Success 200 {object} models.DataResponse
|
||
// @Failure 400 {object} models.ErrorResponse
|
||
// @Failure 401 {object} models.ErrorResponse
|
||
// @Router /users/{id} [patch]
|
||
func (c *UsersController) Update(ctx *gin.Context) {
|
||
userModel, ok := GetCurrentUser(ctx)
|
||
if !ok {
|
||
return
|
||
}
|
||
|
||
id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
|
||
if err != nil {
|
||
ErrorResponse(ctx, http.StatusBadRequest, "无效的用户 ID")
|
||
return
|
||
}
|
||
|
||
var dto models.UpdateUserDTO
|
||
if !BindJSON(ctx, &dto) {
|
||
return
|
||
}
|
||
|
||
user, err := c.usersService.Update(uint(id), dto, userModel.ID)
|
||
if err != nil {
|
||
ErrorResponse(ctx, http.StatusBadRequest, err.Error())
|
||
return
|
||
}
|
||
|
||
SuccessResponse(ctx, "用户更新成功", gin.H{
|
||
"user": user,
|
||
})
|
||
}
|
||
|
||
// ResetPassword 重置用户密码
|
||
// @Summary 重置密码
|
||
// @Tags 用户管理
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security BearerAuth
|
||
// @Param id path int true "用户 ID"
|
||
// @Param data body models.AdminResetPasswordDTO true "新密码"
|
||
// @Success 200 {object} models.BaseResponse
|
||
// @Failure 400 {object} models.ErrorResponse
|
||
// @Failure 401 {object} models.ErrorResponse
|
||
// @Router /users/{id}/reset-password [post]
|
||
func (c *UsersController) ResetPassword(ctx *gin.Context) {
|
||
id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
|
||
if err != nil {
|
||
ErrorResponse(ctx, http.StatusBadRequest, "无效的用户 ID")
|
||
return
|
||
}
|
||
|
||
var dto models.AdminResetPasswordDTO
|
||
if !BindJSON(ctx, &dto) {
|
||
return
|
||
}
|
||
|
||
if err := c.usersService.ResetPassword(uint(id), dto.NewPassword); err != nil {
|
||
ErrorResponse(ctx, http.StatusBadRequest, err.Error())
|
||
return
|
||
}
|
||
|
||
SuccessResponse(ctx, "密码重置成功")
|
||
}
|
||
|
||
// Delete 删除用户
|
||
// @Summary 删除用户
|
||
// @Tags 用户管理
|
||
// @Produce json
|
||
// @Security BearerAuth
|
||
// @Param id path int true "用户 ID"
|
||
// @Success 200 {object} models.BaseResponse
|
||
// @Failure 400 {object} models.ErrorResponse
|
||
// @Failure 401 {object} models.ErrorResponse
|
||
// @Router /users/{id} [delete]
|
||
func (c *UsersController) Delete(ctx *gin.Context) {
|
||
userModel, ok := GetCurrentUser(ctx)
|
||
if !ok {
|
||
return
|
||
}
|
||
|
||
id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
|
||
if err != nil {
|
||
ErrorResponse(ctx, http.StatusBadRequest, "无效的用户 ID")
|
||
return
|
||
}
|
||
|
||
if err := c.usersService.Delete(uint(id), userModel.ID); err != nil {
|
||
ErrorResponse(ctx, http.StatusBadRequest, err.Error())
|
||
return
|
||
}
|
||
|
||
SuccessResponse(ctx, "用户删除成功")
|
||
}
|