2026-06-28 23:24:57 +08:00

211 lines
6.0 KiB
Go

package adminuser
import (
"errors"
"fmt"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"hyapp-admin-server/internal/config"
"hyapp-admin-server/internal/model"
"hyapp-admin-server/internal/modules/shared"
"hyapp-admin-server/internal/repository"
"hyapp-admin-server/internal/response"
)
type Handler struct {
service *AdminUserService
audit shared.OperationLogger
}
func New(store *repository.Store, cfg config.Config, audit shared.OperationLogger) *Handler {
return &Handler{service: NewService(store, cfg), audit: audit}
}
func (h *Handler) ListUsers(c *gin.Context) {
options := shared.ListOptions(c)
users, total, err := h.service.ListUsers(shared.ActorFromContext(c), options)
if err != nil {
response.ServerError(c, "获取用户失败")
return
}
response.OK(c, response.Page{Items: shared.UserDTOs(users), Page: options.Page, PageSize: options.PageSize, Total: total})
}
func (h *Handler) CreateUser(c *gin.Context) {
var req userRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "用户参数不正确")
return
}
user, password, err := h.service.CreateUser(CreateUserInput{
Username: req.Username,
Name: req.Name,
Team: req.Team,
Status: req.Status,
Password: req.Password,
MFAEnabled: req.MFAEnabled,
RoleIDs: req.RoleIDs,
})
if err != nil {
response.BadRequest(c, err.Error())
return
}
shared.OperationLog(c, h.audit, "create-user", "admin_users", "success", user.Username)
response.Created(c, gin.H{"user": shared.UserDTO(*user), "initialPassword": password.Password})
}
func (h *Handler) GetUser(c *gin.Context) {
id, ok := shared.ParseID(c, "id")
if !ok {
return
}
user, err := h.service.GetUser(id)
if errors.Is(err, gorm.ErrRecordNotFound) {
response.NotFound(c, "用户不存在")
return
}
if err != nil {
response.ServerError(c, "获取用户失败")
return
}
response.OK(c, shared.UserDTO(*user))
}
func (h *Handler) ListUserMoneyScopes(c *gin.Context) {
id, ok := shared.ParseID(c, "id")
if !ok {
return
}
scopes, err := h.service.ListUserMoneyScopes(id)
if err != nil {
response.ServerError(c, "获取财务范围失败")
return
}
response.OK(c, gin.H{"items": moneyScopeDTOs(scopes), "total": len(scopes)})
}
func (h *Handler) ReplaceUserMoneyScopes(c *gin.Context) {
id, ok := shared.ParseID(c, "id")
if !ok {
return
}
var req moneyScopeRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "财务范围参数不正确")
return
}
input := make([]MoneyScopeInput, 0, len(req.Scopes))
for _, item := range req.Scopes {
input = append(input, MoneyScopeInput{AppCode: item.AppCode, RegionID: item.RegionID})
}
scopes, err := h.service.ReplaceUserMoneyScopes(id, input)
if err != nil {
response.BadRequest(c, err.Error())
return
}
shared.OperationLog(c, h.audit, "replace-user-money-scopes", "admin_user_money_scopes", "success", fmt.Sprintf("user_id=%d scopes=%d", id, len(scopes)))
response.OK(c, gin.H{"items": moneyScopeDTOs(scopes), "total": len(scopes)})
}
func (h *Handler) UpdateUser(c *gin.Context) {
id, ok := shared.ParseID(c, "id")
if !ok {
return
}
var req updateUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "用户参数不正确")
return
}
user, err := h.service.UpdateUser(id, UpdateUserInput{
Name: req.Name,
Team: req.Team,
Status: req.Status,
MFAEnabled: req.MFAEnabled,
RoleIDs: req.RoleIDs,
})
if err != nil {
response.BadRequest(c, err.Error())
return
}
shared.OperationLog(c, h.audit, "update-user", "admin_users", "success", user.Username)
response.OK(c, shared.UserDTO(*user))
}
func (h *Handler) UpdateUserStatus(c *gin.Context) {
id, ok := shared.ParseID(c, "id")
if !ok {
return
}
var req statusRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "状态参数不正确")
return
}
user, err := h.service.UpdateUserStatus(id, UserStatusInput{Status: req.Status})
if err != nil {
response.BadRequest(c, err.Error())
return
}
shared.OperationLog(c, h.audit, "update-user-status", "admin_users", "success", fmt.Sprintf("%s -> %s", user.Username, req.Status))
response.OK(c, shared.UserDTO(*user))
}
func (h *Handler) ResetUserPassword(c *gin.Context) {
id, ok := shared.ParseID(c, "id")
if !ok {
return
}
var req resetPasswordRequest
_ = c.ShouldBindJSON(&req)
password, err := h.service.ResetUserPassword(id, req.Password)
if err != nil {
response.BadRequest(c, err.Error())
return
}
shared.OperationLog(c, h.audit, "reset-user-password", "admin_users", "success", fmt.Sprintf("user_id=%d", id))
response.OK(c, gin.H{"reset": true, "initialPassword": password.Password})
}
func (h *Handler) BatchUpdateUserStatus(c *gin.Context) {
var req batchStatusRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "批量状态参数不正确")
return
}
if err := h.service.BatchUpdateUserStatus(BatchUserStatusInput{IDs: req.IDs, Status: req.Status}); err != nil {
response.BadRequest(c, err.Error())
return
}
shared.OperationLog(c, h.audit, "batch-update-user-status", "admin_users", "success", fmt.Sprintf("%d users -> %s", len(req.IDs), req.Status))
response.OK(c, gin.H{"updated": len(req.IDs)})
}
func (h *Handler) ExportUsers(c *gin.Context) {
export, err := h.service.ExportUsers(shared.ActorFromContext(c), shared.ListOptions(c))
if err != nil {
response.ServerError(c, "导出用户失败")
return
}
shared.OperationLog(c, h.audit, "export-users", "admin_users", "success", fmt.Sprintf("%d users", export.Count))
c.Header("Content-Disposition", "attachment; filename="+export.FileName)
c.Header("Content-Type", "text/csv; charset=utf-8")
c.Writer.WriteHeader(200)
_, _ = c.Writer.Write(export.Content)
}
func moneyScopeDTOs(scopes []model.UserMoneyScope) []gin.H {
out := make([]gin.H, 0, len(scopes))
for _, scope := range scopes {
out = append(out, gin.H{
"appCode": scope.AppCode,
"regionId": scope.RegionID,
"userId": scope.UserID,
})
}
return out
}