This commit is contained in:
2025-07-11 21:05:58 +08:00
parent 5b4392894f
commit e3d64e7485
74 changed files with 14379 additions and 697 deletions

View File

@@ -0,0 +1,178 @@
package dto
import (
"time"
"tyapi-server/internal/domains/admin/entities"
)
// AdminLoginRequest 管理员登录请求
type AdminLoginRequest struct {
Username string `json:"username" binding:"required"` // 用户名
Password string `json:"password" binding:"required"` // 密码
}
// AdminLoginResponse 管理员登录响应
type AdminLoginResponse struct {
Token string `json:"token"` // JWT令牌
ExpiresAt time.Time `json:"expires_at"` // 过期时间
Admin AdminInfo `json:"admin"` // 管理员信息
}
// AdminInfo 管理员信息
type AdminInfo struct {
ID string `json:"id"` // 管理员ID
Username string `json:"username"` // 用户名
Email string `json:"email"` // 邮箱
Phone string `json:"phone"` // 手机号
RealName string `json:"real_name"` // 真实姓名
Role entities.AdminRole `json:"role"` // 角色
IsActive bool `json:"is_active"` // 是否激活
LastLoginAt *time.Time `json:"last_login_at"` // 最后登录时间
LoginCount int `json:"login_count"` // 登录次数
Permissions []string `json:"permissions"` // 权限列表
CreatedAt time.Time `json:"created_at"` // 创建时间
}
// AdminCreateRequest 创建管理员请求
type AdminCreateRequest struct {
Username string `json:"username" binding:"required"` // 用户名
Password string `json:"password" binding:"required"` // 密码
Email string `json:"email" binding:"required,email"` // 邮箱
Phone string `json:"phone"` // 手机号
RealName string `json:"real_name" binding:"required"` // 真实姓名
Role entities.AdminRole `json:"role" binding:"required"` // 角色
Permissions []string `json:"permissions"` // 权限列表
}
// AdminUpdateRequest 更新管理员请求
type AdminUpdateRequest struct {
Email string `json:"email" binding:"email"` // 邮箱
Phone string `json:"phone"` // 手机号
RealName string `json:"real_name"` // 真实姓名
Role entities.AdminRole `json:"role"` // 角色
IsActive *bool `json:"is_active"` // 是否激活
Permissions []string `json:"permissions"` // 权限列表
}
// AdminPasswordChangeRequest 修改密码请求
type AdminPasswordChangeRequest struct {
OldPassword string `json:"old_password" binding:"required"` // 旧密码
NewPassword string `json:"new_password" binding:"required"` // 新密码
}
// AdminListRequest 管理员列表请求
type AdminListRequest struct {
Page int `form:"page" binding:"min=1"` // 页码
PageSize int `form:"page_size" binding:"min=1,max=100"` // 每页数量
Username string `form:"username"` // 用户名搜索
Email string `form:"email"` // 邮箱搜索
Role string `form:"role"` // 角色筛选
IsActive *bool `form:"is_active"` // 状态筛选
}
// AdminListResponse 管理员列表响应
type AdminListResponse struct {
Total int64 `json:"total"` // 总数
Page int `json:"page"` // 当前页
Size int `json:"size"` // 每页数量
Admins []AdminInfo `json:"admins"` // 管理员列表
}
// AdminStatsResponse 管理员统计响应
type AdminStatsResponse struct {
TotalAdmins int64 `json:"total_admins"` // 总管理员数
ActiveAdmins int64 `json:"active_admins"` // 激活管理员数
TodayLogins int64 `json:"today_logins"` // 今日登录数
TotalOperations int64 `json:"total_operations"` // 总操作数
}
// AdminOperationLogRequest 操作日志请求
type AdminOperationLogRequest struct {
Page int `form:"page" binding:"min=1"` // 页码
PageSize int `form:"page_size" binding:"min=1,max=100"` // 每页数量
AdminID string `form:"admin_id"` // 管理员ID
Action string `form:"action"` // 操作类型
Resource string `form:"resource"` // 操作资源
Status string `form:"status"` // 操作状态
StartTime time.Time `form:"start_time"` // 开始时间
EndTime time.Time `form:"end_time"` // 结束时间
}
// AdminOperationLogResponse 操作日志响应
type AdminOperationLogResponse struct {
Total int64 `json:"total"` // 总数
Page int `json:"page"` // 当前页
Size int `json:"size"` // 每页数量
Logs []AdminOperationLogInfo `json:"logs"` // 日志列表
}
// AdminOperationLogInfo 操作日志信息
type AdminOperationLogInfo struct {
ID string `json:"id"` // 日志ID
AdminID string `json:"admin_id"` // 管理员ID
Username string `json:"username"` // 用户名
Action string `json:"action"` // 操作类型
Resource string `json:"resource"` // 操作资源
ResourceID string `json:"resource_id"` // 资源ID
Details string `json:"details"` // 操作详情
IP string `json:"ip"` // IP地址
UserAgent string `json:"user_agent"` // 用户代理
Status string `json:"status"` // 操作状态
Message string `json:"message"` // 操作消息
CreatedAt time.Time `json:"created_at"` // 创建时间
}
// AdminLoginLogRequest 登录日志请求
type AdminLoginLogRequest struct {
Page int `form:"page" binding:"min=1"` // 页码
PageSize int `form:"page_size" binding:"min=1,max=100"` // 每页数量
AdminID string `form:"admin_id"` // 管理员ID
Username string `form:"username"` // 用户名
Status string `form:"status"` // 登录状态
StartTime time.Time `form:"start_time"` // 开始时间
EndTime time.Time `form:"end_time"` // 结束时间
}
// AdminLoginLogResponse 登录日志响应
type AdminLoginLogResponse struct {
Total int64 `json:"total"` // 总数
Page int `json:"page"` // 当前页
Size int `json:"size"` // 每页数量
Logs []AdminLoginLogInfo `json:"logs"` // 日志列表
}
// AdminLoginLogInfo 登录日志信息
type AdminLoginLogInfo struct {
ID string `json:"id"` // 日志ID
AdminID string `json:"admin_id"` // 管理员ID
Username string `json:"username"` // 用户名
IP string `json:"ip"` // IP地址
UserAgent string `json:"user_agent"` // 用户代理
Status string `json:"status"` // 登录状态
Message string `json:"message"` // 登录消息
CreatedAt time.Time `json:"created_at"` // 创建时间
}
// PermissionInfo 权限信息
type PermissionInfo struct {
ID string `json:"id"` // 权限ID
Name string `json:"name"` // 权限名称
Code string `json:"code"` // 权限代码
Description string `json:"description"` // 权限描述
Module string `json:"module"` // 所属模块
IsActive bool `json:"is_active"` // 是否激活
CreatedAt time.Time `json:"created_at"` // 创建时间
}
// RolePermissionRequest 角色权限请求
type RolePermissionRequest struct {
Role entities.AdminRole `json:"role" binding:"required"` // 角色
PermissionIDs []string `json:"permission_ids" binding:"required"` // 权限ID列表
}
// RolePermissionResponse 角色权限响应
type RolePermissionResponse struct {
Role entities.AdminRole `json:"role"` // 角色
Permissions []PermissionInfo `json:"permissions"` // 权限列表
}

View File

@@ -0,0 +1,147 @@
package entities
import (
"time"
"gorm.io/gorm"
)
// AdminRole 管理员角色枚举
// 定义系统中不同级别的管理员角色,用于权限控制和功能分配
type AdminRole string
const (
RoleSuperAdmin AdminRole = "super_admin" // 超级管理员 - 拥有所有权限
RoleAdmin AdminRole = "admin" // 普通管理员 - 拥有大部分管理权限
RoleReviewer AdminRole = "reviewer" // 审核员 - 仅拥有审核相关权限
)
// Admin 管理员实体
// 系统管理员的核心信息,包括账户信息、权限配置、操作统计等
// 支持多角色管理,提供完整的权限控制和操作审计功能
type Admin struct {
// 基础标识
ID string `gorm:"primaryKey;type:varchar(36)" comment:"管理员唯一标识"`
Username string `gorm:"type:varchar(100);not null;uniqueIndex" comment:"登录用户名"`
Password string `gorm:"type:varchar(255);not null" comment:"登录密码(加密存储)"`
Email string `gorm:"type:varchar(255);not null;uniqueIndex" comment:"邮箱地址"`
Phone string `gorm:"type:varchar(20)" comment:"手机号码"`
RealName string `gorm:"type:varchar(100);not null" comment:"真实姓名"`
Role AdminRole `gorm:"type:varchar(50);not null;default:'reviewer'" comment:"管理员角色"`
// 状态信息 - 账户状态和登录统计
IsActive bool `gorm:"default:true" comment:"账户是否激活"`
LastLoginAt *time.Time `comment:"最后登录时间"`
LoginCount int `gorm:"default:0" comment:"登录次数统计"`
// 权限信息 - 细粒度权限控制
Permissions string `gorm:"type:text" comment:"权限列表(JSON格式存储)"`
// 审核统计 - 管理员的工作绩效统计
ReviewCount int `gorm:"default:0" comment:"审核总数"`
ApprovedCount int `gorm:"default:0" comment:"通过数量"`
RejectedCount int `gorm:"default:0" comment:"拒绝数量"`
// 时间戳字段
CreatedAt time.Time `gorm:"autoCreateTime" comment:"创建时间"`
UpdatedAt time.Time `gorm:"autoUpdateTime" comment:"更新时间"`
DeletedAt gorm.DeletedAt `gorm:"index" comment:"软删除时间"`
}
// AdminLoginLog 管理员登录日志实体
// 记录管理员的所有登录尝试,包括成功和失败的登录记录
// 用于安全审计和异常登录检测
type AdminLoginLog struct {
// 基础标识
ID string `gorm:"primaryKey;type:varchar(36)" comment:"日志记录唯一标识"`
AdminID string `gorm:"type:varchar(36);not null;index" comment:"管理员ID"`
Username string `gorm:"type:varchar(100);not null" comment:"登录用户名"`
IP string `gorm:"type:varchar(45);not null" comment:"登录IP地址"`
UserAgent string `gorm:"type:varchar(500)" comment:"客户端信息"`
Status string `gorm:"type:varchar(20);not null" comment:"登录状态(success/failed)"`
Message string `gorm:"type:varchar(500)" comment:"登录结果消息"`
// 时间戳字段
CreatedAt time.Time `gorm:"autoCreateTime" comment:"创建时间"`
}
// AdminOperationLog 管理员操作日志实体
// 记录管理员在系统中的所有重要操作,用于操作审计和问题追踪
// 支持操作类型、资源、详情等完整信息的记录
type AdminOperationLog struct {
// 基础标识
ID string `gorm:"primaryKey;type:varchar(36)" comment:"操作日志唯一标识"`
AdminID string `gorm:"type:varchar(36);not null;index" comment:"操作管理员ID"`
Username string `gorm:"type:varchar(100);not null" comment:"操作管理员用户名"`
Action string `gorm:"type:varchar(100);not null" comment:"操作类型"`
Resource string `gorm:"type:varchar(100);not null" comment:"操作资源"`
ResourceID string `gorm:"type:varchar(36)" comment:"资源ID"`
Details string `gorm:"type:text" comment:"操作详情(JSON格式)"`
IP string `gorm:"type:varchar(45);not null" comment:"操作IP地址"`
UserAgent string `gorm:"type:varchar(500)" comment:"客户端信息"`
Status string `gorm:"type:varchar(20);not null" comment:"操作状态(success/failed)"`
Message string `gorm:"type:varchar(500)" comment:"操作结果消息"`
// 时间戳字段
CreatedAt time.Time `gorm:"autoCreateTime" comment:"创建时间"`
}
// AdminPermission 管理员权限实体
// 定义系统中的所有权限项,支持模块化权限管理
// 每个权限都有唯一的代码标识,便于程序中的权限检查
type AdminPermission struct {
// 基础标识
ID string `gorm:"primaryKey;type:varchar(36)" comment:"权限唯一标识"`
Name string `gorm:"type:varchar(100);not null;uniqueIndex" comment:"权限名称"`
Code string `gorm:"type:varchar(100);not null;uniqueIndex" comment:"权限代码"`
Description string `gorm:"type:varchar(500)" comment:"权限描述"`
Module string `gorm:"type:varchar(50);not null" comment:"所属模块"`
IsActive bool `gorm:"default:true" comment:"权限是否启用"`
// 时间戳字段
CreatedAt time.Time `gorm:"autoCreateTime" comment:"创建时间"`
UpdatedAt time.Time `gorm:"autoUpdateTime" comment:"更新时间"`
DeletedAt gorm.DeletedAt `gorm:"index" comment:"软删除时间"`
}
// AdminRolePermission 角色权限关联实体
// 建立角色和权限之间的多对多关系,实现基于角色的权限控制(RBAC)
type AdminRolePermission struct {
// 基础标识
ID string `gorm:"primaryKey;type:varchar(36)" comment:"关联记录唯一标识"`
Role AdminRole `gorm:"type:varchar(50);not null;index" comment:"角色"`
PermissionID string `gorm:"type:varchar(36);not null;index" comment:"权限ID"`
// 时间戳字段
CreatedAt time.Time `gorm:"autoCreateTime" comment:"创建时间"`
}
// TableName 指定数据库表名
func (Admin) TableName() string {
return "admins"
}
// IsValid 检查管理员账户是否有效
// 判断管理员账户是否处于可用状态,包括激活状态和软删除状态检查
func (a *Admin) IsValid() bool {
return a.IsActive && a.DeletedAt.Time.IsZero()
}
// UpdateLastLoginAt 更新最后登录时间
// 在管理员成功登录后调用,记录最新的登录时间
func (a *Admin) UpdateLastLoginAt() {
now := time.Now()
a.LastLoginAt = &now
}
// Deactivate 停用管理员账户
// 将管理员账户设置为非激活状态,禁止登录和操作
func (a *Admin) Deactivate() {
a.IsActive = false
}
// Activate 激活管理员账户
// 重新启用管理员账户,允许正常登录和操作
func (a *Admin) Activate() {
a.IsActive = true
}

View File

@@ -0,0 +1,313 @@
package handlers
import (
"strconv"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
"tyapi-server/internal/domains/admin/dto"
"tyapi-server/internal/domains/admin/services"
"tyapi-server/internal/shared/interfaces"
)
// AdminHandler 管理员HTTP处理器
type AdminHandler struct {
adminService *services.AdminService
responseBuilder interfaces.ResponseBuilder
logger *zap.Logger
}
// NewAdminHandler 创建管理员HTTP处理器
func NewAdminHandler(
adminService *services.AdminService,
responseBuilder interfaces.ResponseBuilder,
logger *zap.Logger,
) *AdminHandler {
return &AdminHandler{
adminService: adminService,
responseBuilder: responseBuilder,
logger: logger,
}
}
// Login 管理员登录
// @Summary 管理员登录
// @Description 管理员登录接口
// @Tags 管理员认证
// @Accept json
// @Produce json
// @Param request body dto.AdminLoginRequest true "登录请求"
// @Success 200 {object} dto.AdminLoginResponse
// @Failure 400 {object} interfaces.ErrorResponse
// @Failure 401 {object} interfaces.ErrorResponse
// @Router /admin/login [post]
func (h *AdminHandler) Login(c *gin.Context) {
var req dto.AdminLoginRequest
if err := c.ShouldBindJSON(&req); err != nil {
h.logger.Warn("管理员登录参数验证失败", zap.Error(err))
h.responseBuilder.BadRequest(c, "请求参数错误")
return
}
// 获取客户端信息
clientIP := c.ClientIP()
userAgent := c.GetHeader("User-Agent")
// 调用服务
response, err := h.adminService.Login(c.Request.Context(), &req, clientIP, userAgent)
if err != nil {
h.logger.Error("管理员登录失败", zap.Error(err))
h.responseBuilder.Unauthorized(c, err.Error())
return
}
h.responseBuilder.Success(c, response, "登录成功")
}
// CreateAdmin 创建管理员
// @Summary 创建管理员
// @Description 创建新管理员账户
// @Tags 管理员管理
// @Accept json
// @Produce json
// @Param request body dto.AdminCreateRequest true "创建管理员请求"
// @Success 201 {object} interfaces.SuccessResponse
// @Failure 400 {object} interfaces.ErrorResponse
// @Failure 403 {object} interfaces.ErrorResponse
// @Router /admin [post]
func (h *AdminHandler) CreateAdmin(c *gin.Context) {
var req dto.AdminCreateRequest
if err := c.ShouldBindJSON(&req); err != nil {
h.logger.Warn("创建管理员参数验证失败", zap.Error(err))
h.responseBuilder.BadRequest(c, "请求参数错误")
return
}
// 获取当前操作的管理员ID从JWT中解析
operatorID := h.getCurrentAdminID(c)
// 调用服务
err := h.adminService.CreateAdmin(c.Request.Context(), &req, operatorID)
if err != nil {
h.logger.Error("创建管理员失败", zap.Error(err))
h.responseBuilder.BadRequest(c, err.Error())
return
}
h.responseBuilder.Created(c, nil, "管理员创建成功")
}
// UpdateAdmin 更新管理员
// @Summary 更新管理员
// @Description 更新管理员信息
// @Tags 管理员管理
// @Accept json
// @Produce json
// @Param id path string true "管理员ID"
// @Param request body dto.AdminUpdateRequest true "更新管理员请求"
// @Success 200 {object} interfaces.SuccessResponse
// @Failure 400 {object} interfaces.ErrorResponse
// @Failure 404 {object} interfaces.ErrorResponse
// @Router /admin/{id} [put]
func (h *AdminHandler) UpdateAdmin(c *gin.Context) {
adminID := c.Param("id")
if adminID == "" {
h.responseBuilder.BadRequest(c, "管理员ID不能为空")
return
}
var req dto.AdminUpdateRequest
if err := c.ShouldBindJSON(&req); err != nil {
h.logger.Warn("更新管理员参数验证失败", zap.Error(err))
h.responseBuilder.BadRequest(c, "请求参数错误")
return
}
// 获取当前操作的管理员ID
operatorID := h.getCurrentAdminID(c)
// 调用服务
err := h.adminService.UpdateAdmin(c.Request.Context(), adminID, &req, operatorID)
if err != nil {
h.logger.Error("更新管理员失败", zap.Error(err))
h.responseBuilder.BadRequest(c, err.Error())
return
}
h.responseBuilder.Success(c, nil, "管理员更新成功")
}
// ChangePassword 修改密码
// @Summary 修改密码
// @Description 管理员修改自己的密码
// @Tags 管理员管理
// @Accept json
// @Produce json
// @Param request body dto.AdminPasswordChangeRequest true "修改密码请求"
// @Success 200 {object} interfaces.SuccessResponse
// @Failure 400 {object} interfaces.ErrorResponse
// @Router /admin/change-password [post]
func (h *AdminHandler) ChangePassword(c *gin.Context) {
var req dto.AdminPasswordChangeRequest
if err := c.ShouldBindJSON(&req); err != nil {
h.logger.Warn("修改密码参数验证失败", zap.Error(err))
h.responseBuilder.BadRequest(c, "请求参数错误")
return
}
// 获取当前管理员ID
adminID := h.getCurrentAdminID(c)
// 调用服务
err := h.adminService.ChangePassword(c.Request.Context(), adminID, &req)
if err != nil {
h.logger.Error("修改密码失败", zap.Error(err))
h.responseBuilder.BadRequest(c, err.Error())
return
}
h.responseBuilder.Success(c, nil, "密码修改成功")
}
// ListAdmins 获取管理员列表
// @Summary 获取管理员列表
// @Description 分页获取管理员列表
// @Tags 管理员管理
// @Accept json
// @Produce json
// @Param page query int false "页码" default(1)
// @Param page_size query int false "每页数量" default(10)
// @Param username query string false "用户名搜索"
// @Param email query string false "邮箱搜索"
// @Param role query string false "角色筛选"
// @Param is_active query bool false "状态筛选"
// @Success 200 {object} dto.AdminListResponse
// @Failure 400 {object} interfaces.ErrorResponse
// @Router /admin [get]
func (h *AdminHandler) ListAdmins(c *gin.Context) {
var req dto.AdminListRequest
// 解析查询参数
if page, err := strconv.Atoi(c.DefaultQuery("page", "1")); err == nil {
req.Page = page
} else {
req.Page = 1
}
if pageSize, err := strconv.Atoi(c.DefaultQuery("page_size", "10")); err == nil {
req.PageSize = pageSize
} else {
req.PageSize = 10
}
req.Username = c.Query("username")
req.Email = c.Query("email")
req.Role = c.Query("role")
if isActiveStr := c.Query("is_active"); isActiveStr != "" {
if isActive, err := strconv.ParseBool(isActiveStr); err == nil {
req.IsActive = &isActive
}
}
// 调用服务
response, err := h.adminService.ListAdmins(c.Request.Context(), &req)
if err != nil {
h.logger.Error("获取管理员列表失败", zap.Error(err))
h.responseBuilder.InternalError(c, "获取管理员列表失败")
return
}
h.responseBuilder.Success(c, response, "获取管理员列表成功")
}
// GetAdminByID 根据ID获取管理员
// @Summary 获取管理员详情
// @Description 根据ID获取管理员详细信息
// @Tags 管理员管理
// @Accept json
// @Produce json
// @Param id path string true "管理员ID"
// @Success 200 {object} dto.AdminInfo
// @Failure 400 {object} interfaces.ErrorResponse
// @Failure 404 {object} interfaces.ErrorResponse
// @Router /admin/{id} [get]
func (h *AdminHandler) GetAdminByID(c *gin.Context) {
adminID := c.Param("id")
if adminID == "" {
h.responseBuilder.BadRequest(c, "管理员ID不能为空")
return
}
// 调用服务
admin, err := h.adminService.GetAdminByID(c.Request.Context(), adminID)
if err != nil {
h.logger.Error("获取管理员详情失败", zap.Error(err))
h.responseBuilder.NotFound(c, err.Error())
return
}
h.responseBuilder.Success(c, admin, "获取管理员详情成功")
}
// DeleteAdmin 删除管理员
// @Summary 删除管理员
// @Description 软删除管理员账户
// @Tags 管理员管理
// @Accept json
// @Produce json
// @Param id path string true "管理员ID"
// @Success 200 {object} interfaces.SuccessResponse
// @Failure 400 {object} interfaces.ErrorResponse
// @Failure 404 {object} interfaces.ErrorResponse
// @Router /admin/{id} [delete]
func (h *AdminHandler) DeleteAdmin(c *gin.Context) {
adminID := c.Param("id")
if adminID == "" {
h.responseBuilder.BadRequest(c, "管理员ID不能为空")
return
}
// 获取当前操作的管理员ID
operatorID := h.getCurrentAdminID(c)
// 调用服务
err := h.adminService.DeleteAdmin(c.Request.Context(), adminID, operatorID)
if err != nil {
h.logger.Error("删除管理员失败", zap.Error(err))
h.responseBuilder.BadRequest(c, err.Error())
return
}
h.responseBuilder.Success(c, nil, "管理员删除成功")
}
// GetAdminStats 获取管理员统计信息
// @Summary 获取管理员统计
// @Description 获取管理员相关的统计信息
// @Tags 管理员管理
// @Accept json
// @Produce json
// @Success 200 {object} dto.AdminStatsResponse
// @Failure 400 {object} interfaces.ErrorResponse
// @Router /admin/stats [get]
func (h *AdminHandler) GetAdminStats(c *gin.Context) {
// 调用服务
stats, err := h.adminService.GetAdminStats(c.Request.Context())
if err != nil {
h.logger.Error("获取管理员统计失败", zap.Error(err))
h.responseBuilder.InternalError(c, "获取统计信息失败")
return
}
h.responseBuilder.Success(c, stats, "获取统计信息成功")
}
// getCurrentAdminID 获取当前管理员ID
func (h *AdminHandler) getCurrentAdminID(c *gin.Context) string {
// 这里应该从JWT令牌中解析出管理员ID
// 为了简化这里返回一个模拟的ID
// 实际实现中应该从中间件中获取
return "current_admin_id"
}

View File

@@ -0,0 +1,72 @@
package repositories
import (
"context"
"tyapi-server/internal/domains/admin/dto"
"tyapi-server/internal/domains/admin/entities"
"tyapi-server/internal/shared/interfaces"
)
// AdminRepository 管理员仓储接口
type AdminRepository interface {
interfaces.Repository[entities.Admin]
// 管理员认证
FindByUsername(ctx context.Context, username string) (*entities.Admin, error)
FindByEmail(ctx context.Context, email string) (*entities.Admin, error)
// 管理员管理
ListAdmins(ctx context.Context, req *dto.AdminListRequest) (*dto.AdminListResponse, error)
GetStats(ctx context.Context) (*dto.AdminStatsResponse, error)
// 权限管理
GetPermissionsByRole(ctx context.Context, role entities.AdminRole) ([]entities.AdminPermission, error)
UpdatePermissions(ctx context.Context, adminID string, permissions []string) error
// 统计信息
UpdateLoginStats(ctx context.Context, adminID string) error
UpdateReviewStats(ctx context.Context, adminID string, approved bool) error
}
// AdminLoginLogRepository 管理员登录日志仓储接口
type AdminLoginLogRepository interface {
interfaces.Repository[entities.AdminLoginLog]
// 日志查询
ListLogs(ctx context.Context, req *dto.AdminLoginLogRequest) (*dto.AdminLoginLogResponse, error)
// 统计查询
GetTodayLoginCount(ctx context.Context) (int64, error)
GetLoginCountByAdmin(ctx context.Context, adminID string, days int) (int64, error)
}
// AdminOperationLogRepository 管理员操作日志仓储接口
type AdminOperationLogRepository interface {
interfaces.Repository[entities.AdminOperationLog]
// 日志查询
ListLogs(ctx context.Context, req *dto.AdminOperationLogRequest) (*dto.AdminOperationLogResponse, error)
// 统计查询
GetTotalOperations(ctx context.Context) (int64, error)
GetOperationsByAdmin(ctx context.Context, adminID string, days int) (int64, error)
// 批量操作
BatchCreate(ctx context.Context, logs []entities.AdminOperationLog) error
}
// AdminPermissionRepository 管理员权限仓储接口
type AdminPermissionRepository interface {
interfaces.Repository[entities.AdminPermission]
// 权限查询
FindByCode(ctx context.Context, code string) (*entities.AdminPermission, error)
FindByModule(ctx context.Context, module string) ([]entities.AdminPermission, error)
ListActive(ctx context.Context) ([]entities.AdminPermission, error)
// 角色权限管理
GetPermissionsByRole(ctx context.Context, role entities.AdminRole) ([]entities.AdminPermission, error)
AssignPermissionsToRole(ctx context.Context, role entities.AdminRole, permissionIDs []string) error
RemovePermissionsFromRole(ctx context.Context, role entities.AdminRole, permissionIDs []string) error
}

View File

@@ -0,0 +1,341 @@
package repositories
import (
"context"
"encoding/json"
"fmt"
"time"
"go.uber.org/zap"
"gorm.io/gorm"
"tyapi-server/internal/domains/admin/dto"
"tyapi-server/internal/domains/admin/entities"
"tyapi-server/internal/shared/interfaces"
)
// GormAdminRepository 管理员GORM仓储实现
type GormAdminRepository struct {
db *gorm.DB
logger *zap.Logger
}
// NewGormAdminRepository 创建管理员GORM仓储
func NewGormAdminRepository(db *gorm.DB, logger *zap.Logger) *GormAdminRepository {
return &GormAdminRepository{
db: db,
logger: logger,
}
}
// Create 创建管理员
func (r *GormAdminRepository) Create(ctx context.Context, admin entities.Admin) error {
r.logger.Info("创建管理员", zap.String("username", admin.Username))
return r.db.WithContext(ctx).Create(&admin).Error
}
// GetByID 根据ID获取管理员
func (r *GormAdminRepository) GetByID(ctx context.Context, id string) (entities.Admin, error) {
var admin entities.Admin
err := r.db.WithContext(ctx).Where("id = ?", id).First(&admin).Error
return admin, err
}
// Update 更新管理员
func (r *GormAdminRepository) Update(ctx context.Context, admin entities.Admin) error {
r.logger.Info("更新管理员", zap.String("id", admin.ID))
return r.db.WithContext(ctx).Save(&admin).Error
}
// Delete 删除管理员
func (r *GormAdminRepository) Delete(ctx context.Context, id string) error {
r.logger.Info("删除管理员", zap.String("id", id))
return r.db.WithContext(ctx).Delete(&entities.Admin{}, "id = ?", id).Error
}
// SoftDelete 软删除管理员
func (r *GormAdminRepository) SoftDelete(ctx context.Context, id string) error {
r.logger.Info("软删除管理员", zap.String("id", id))
return r.db.WithContext(ctx).Delete(&entities.Admin{}, "id = ?", id).Error
}
// Restore 恢复管理员
func (r *GormAdminRepository) Restore(ctx context.Context, id string) error {
r.logger.Info("恢复管理员", zap.String("id", id))
return r.db.WithContext(ctx).Unscoped().Model(&entities.Admin{}).Where("id = ?", id).Update("deleted_at", nil).Error
}
// Count 统计管理员数量
func (r *GormAdminRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
var count int64
query := r.db.WithContext(ctx).Model(&entities.Admin{})
// 应用过滤条件
if options.Filters != nil {
for key, value := range options.Filters {
query = query.Where(key+" = ?", value)
}
}
// 应用搜索条件
if options.Search != "" {
query = query.Where("username LIKE ? OR email LIKE ? OR real_name LIKE ?",
"%"+options.Search+"%", "%"+options.Search+"%", "%"+options.Search+"%")
}
return count, query.Count(&count).Error
}
// Exists 检查管理员是否存在
func (r *GormAdminRepository) Exists(ctx context.Context, id string) (bool, error) {
var count int64
err := r.db.WithContext(ctx).Model(&entities.Admin{}).Where("id = ?", id).Count(&count).Error
return count > 0, err
}
// CreateBatch 批量创建管理员
func (r *GormAdminRepository) CreateBatch(ctx context.Context, admins []entities.Admin) error {
r.logger.Info("批量创建管理员", zap.Int("count", len(admins)))
return r.db.WithContext(ctx).Create(&admins).Error
}
// GetByIDs 根据ID列表获取管理员
func (r *GormAdminRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.Admin, error) {
var admins []entities.Admin
err := r.db.WithContext(ctx).Where("id IN ?", ids).Find(&admins).Error
return admins, err
}
// UpdateBatch 批量更新管理员
func (r *GormAdminRepository) UpdateBatch(ctx context.Context, admins []entities.Admin) error {
r.logger.Info("批量更新管理员", zap.Int("count", len(admins)))
return r.db.WithContext(ctx).Save(&admins).Error
}
// DeleteBatch 批量删除管理员
func (r *GormAdminRepository) DeleteBatch(ctx context.Context, ids []string) error {
r.logger.Info("批量删除管理员", zap.Strings("ids", ids))
return r.db.WithContext(ctx).Delete(&entities.Admin{}, "id IN ?", ids).Error
}
// List 获取管理员列表
func (r *GormAdminRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.Admin, error) {
var admins []entities.Admin
query := r.db.WithContext(ctx).Model(&entities.Admin{})
// 应用过滤条件
if options.Filters != nil {
for key, value := range options.Filters {
query = query.Where(key+" = ?", value)
}
}
// 应用搜索条件
if options.Search != "" {
query = query.Where("username LIKE ? OR email LIKE ? OR real_name LIKE ?",
"%"+options.Search+"%", "%"+options.Search+"%", "%"+options.Search+"%")
}
// 应用排序
if options.Sort != "" {
order := "ASC"
if options.Order != "" {
order = options.Order
}
query = query.Order(options.Sort + " " + order)
}
// 应用分页
if options.Page > 0 && options.PageSize > 0 {
offset := (options.Page - 1) * options.PageSize
query = query.Offset(offset).Limit(options.PageSize)
}
return admins, query.Find(&admins).Error
}
// WithTx 使用事务
func (r *GormAdminRepository) WithTx(tx interface{}) interfaces.Repository[entities.Admin] {
if gormTx, ok := tx.(*gorm.DB); ok {
return &GormAdminRepository{
db: gormTx,
logger: r.logger,
}
}
return r
}
// FindByUsername 根据用户名查找管理员
func (r *GormAdminRepository) FindByUsername(ctx context.Context, username string) (*entities.Admin, error) {
var admin entities.Admin
err := r.db.WithContext(ctx).Where("username = ?", username).First(&admin).Error
if err != nil {
return nil, err
}
return &admin, nil
}
// FindByEmail 根据邮箱查找管理员
func (r *GormAdminRepository) FindByEmail(ctx context.Context, email string) (*entities.Admin, error) {
var admin entities.Admin
err := r.db.WithContext(ctx).Where("email = ?", email).First(&admin).Error
if err != nil {
return nil, err
}
return &admin, nil
}
// ListAdmins 获取管理员列表(带分页和筛选)
func (r *GormAdminRepository) ListAdmins(ctx context.Context, req *dto.AdminListRequest) (*dto.AdminListResponse, error) {
var admins []entities.Admin
var total int64
query := r.db.WithContext(ctx).Model(&entities.Admin{})
// 应用筛选条件
if req.Username != "" {
query = query.Where("username LIKE ?", "%"+req.Username+"%")
}
if req.Email != "" {
query = query.Where("email LIKE ?", "%"+req.Email+"%")
}
if req.Role != "" {
query = query.Where("role = ?", req.Role)
}
if req.IsActive != nil {
query = query.Where("is_active = ?", *req.IsActive)
}
// 统计总数
if err := query.Count(&total).Error; err != nil {
return nil, err
}
// 应用分页
offset := (req.Page - 1) * req.PageSize
query = query.Offset(offset).Limit(req.PageSize)
// 默认排序
query = query.Order("created_at DESC")
// 查询数据
if err := query.Find(&admins).Error; err != nil {
return nil, err
}
// 转换为DTO
adminInfos := make([]dto.AdminInfo, len(admins))
for i, admin := range admins {
adminInfos[i] = r.convertToAdminInfo(admin)
}
return &dto.AdminListResponse{
Total: total,
Page: req.Page,
Size: req.PageSize,
Admins: adminInfos,
}, nil
}
// GetStats 获取管理员统计信息
func (r *GormAdminRepository) GetStats(ctx context.Context) (*dto.AdminStatsResponse, error) {
var stats dto.AdminStatsResponse
// 总管理员数
if err := r.db.WithContext(ctx).Model(&entities.Admin{}).Count(&stats.TotalAdmins).Error; err != nil {
return nil, err
}
// 激活管理员数
if err := r.db.WithContext(ctx).Model(&entities.Admin{}).Where("is_active = ?", true).Count(&stats.ActiveAdmins).Error; err != nil {
return nil, err
}
// 今日登录数
today := time.Now().Truncate(24 * time.Hour)
if err := r.db.WithContext(ctx).Model(&entities.AdminLoginLog{}).Where("created_at >= ?", today).Count(&stats.TodayLogins).Error; err != nil {
return nil, err
}
// 总操作数
if err := r.db.WithContext(ctx).Model(&entities.AdminOperationLog{}).Count(&stats.TotalOperations).Error; err != nil {
return nil, err
}
return &stats, nil
}
// GetPermissionsByRole 根据角色获取权限
func (r *GormAdminRepository) GetPermissionsByRole(ctx context.Context, role entities.AdminRole) ([]entities.AdminPermission, error) {
var permissions []entities.AdminPermission
query := r.db.WithContext(ctx).
Joins("JOIN admin_role_permissions ON admin_permissions.id = admin_role_permissions.permission_id").
Where("admin_role_permissions.role = ? AND admin_permissions.is_active = ?", role, true)
return permissions, query.Find(&permissions).Error
}
// UpdatePermissions 更新管理员权限
func (r *GormAdminRepository) UpdatePermissions(ctx context.Context, adminID string, permissions []string) error {
permissionsJSON, err := json.Marshal(permissions)
if err != nil {
return fmt.Errorf("序列化权限失败: %w", err)
}
return r.db.WithContext(ctx).
Model(&entities.Admin{}).
Where("id = ?", adminID).
Update("permissions", string(permissionsJSON)).Error
}
// UpdateLoginStats 更新登录统计
func (r *GormAdminRepository) UpdateLoginStats(ctx context.Context, adminID string) error {
return r.db.WithContext(ctx).
Model(&entities.Admin{}).
Where("id = ?", adminID).
Updates(map[string]interface{}{
"last_login_at": time.Now(),
"login_count": gorm.Expr("login_count + 1"),
}).Error
}
// UpdateReviewStats 更新审核统计
func (r *GormAdminRepository) UpdateReviewStats(ctx context.Context, adminID string, approved bool) error {
updates := map[string]interface{}{
"review_count": gorm.Expr("review_count + 1"),
}
if approved {
updates["approved_count"] = gorm.Expr("approved_count + 1")
} else {
updates["rejected_count"] = gorm.Expr("rejected_count + 1")
}
return r.db.WithContext(ctx).
Model(&entities.Admin{}).
Where("id = ?", adminID).
Updates(updates).Error
}
// convertToAdminInfo 转换为管理员信息DTO
func (r *GormAdminRepository) convertToAdminInfo(admin entities.Admin) dto.AdminInfo {
var permissions []string
if admin.Permissions != "" {
json.Unmarshal([]byte(admin.Permissions), &permissions)
}
return dto.AdminInfo{
ID: admin.ID,
Username: admin.Username,
Email: admin.Email,
Phone: admin.Phone,
RealName: admin.RealName,
Role: admin.Role,
IsActive: admin.IsActive,
LastLoginAt: admin.LastLoginAt,
LoginCount: admin.LoginCount,
Permissions: permissions,
CreatedAt: admin.CreatedAt,
}
}

View File

@@ -0,0 +1,29 @@
package routes
import (
"github.com/gin-gonic/gin"
"tyapi-server/internal/domains/admin/handlers"
)
// RegisterAdminRoutes 注册管理员路由
func RegisterAdminRoutes(router *gin.Engine, adminHandler *handlers.AdminHandler) {
// 管理员路由组
adminGroup := router.Group("/api/admin")
{
// 认证相关路由(无需认证)
authGroup := adminGroup.Group("/auth")
{
authGroup.POST("/login", adminHandler.Login)
}
// 管理员管理路由(需要认证)
adminGroup.POST("", adminHandler.CreateAdmin) // 创建管理员
adminGroup.GET("", adminHandler.ListAdmins) // 获取管理员列表
adminGroup.GET("/stats", adminHandler.GetAdminStats) // 获取统计信息
adminGroup.GET("/:id", adminHandler.GetAdminByID) // 获取管理员详情
adminGroup.PUT("/:id", adminHandler.UpdateAdmin) // 更新管理员
adminGroup.DELETE("/:id", adminHandler.DeleteAdmin) // 删除管理员
adminGroup.POST("/change-password", adminHandler.ChangePassword) // 修改密码
}
}

View File

@@ -0,0 +1,431 @@
package services
import (
"context"
"crypto/rand"
"encoding/hex"
"encoding/json"
"fmt"
"time"
"go.uber.org/zap"
"golang.org/x/crypto/bcrypt"
"tyapi-server/internal/domains/admin/dto"
"tyapi-server/internal/domains/admin/entities"
"tyapi-server/internal/domains/admin/repositories"
"tyapi-server/internal/shared/interfaces"
)
// AdminService 管理员服务
type AdminService struct {
adminRepo repositories.AdminRepository
loginLogRepo repositories.AdminLoginLogRepository
operationLogRepo repositories.AdminOperationLogRepository
permissionRepo repositories.AdminPermissionRepository
responseBuilder interfaces.ResponseBuilder
logger *zap.Logger
}
// NewAdminService 创建管理员服务
func NewAdminService(
adminRepo repositories.AdminRepository,
loginLogRepo repositories.AdminLoginLogRepository,
operationLogRepo repositories.AdminOperationLogRepository,
permissionRepo repositories.AdminPermissionRepository,
responseBuilder interfaces.ResponseBuilder,
logger *zap.Logger,
) *AdminService {
return &AdminService{
adminRepo: adminRepo,
loginLogRepo: loginLogRepo,
operationLogRepo: operationLogRepo,
permissionRepo: permissionRepo,
responseBuilder: responseBuilder,
logger: logger,
}
}
// Login 管理员登录
func (s *AdminService) Login(ctx context.Context, req *dto.AdminLoginRequest, clientIP, userAgent string) (*dto.AdminLoginResponse, error) {
s.logger.Info("管理员登录", zap.String("username", req.Username))
// 查找管理员
admin, err := s.adminRepo.FindByUsername(ctx, req.Username)
if err != nil {
s.logger.Warn("管理员登录失败:用户不存在", zap.String("username", req.Username))
s.recordLoginLog(ctx, req.Username, clientIP, userAgent, "failed", "用户不存在")
return nil, fmt.Errorf("用户名或密码错误")
}
// 检查管理员状态
if !admin.IsActive {
s.logger.Warn("管理员登录失败:账户已禁用", zap.String("username", req.Username))
s.recordLoginLog(ctx, req.Username, clientIP, userAgent, "failed", "账户已禁用")
return nil, fmt.Errorf("账户已被禁用,请联系管理员")
}
// 验证密码
if err := bcrypt.CompareHashAndPassword([]byte(admin.Password), []byte(req.Password)); err != nil {
s.logger.Warn("管理员登录失败:密码错误", zap.String("username", req.Username))
s.recordLoginLog(ctx, req.Username, clientIP, userAgent, "failed", "密码错误")
return nil, fmt.Errorf("用户名或密码错误")
}
// 更新登录统计
if err := s.adminRepo.UpdateLoginStats(ctx, admin.ID); err != nil {
s.logger.Error("更新登录统计失败", zap.Error(err))
}
// 记录登录日志
s.recordLoginLog(ctx, req.Username, clientIP, userAgent, "success", "登录成功")
// 生成JWT令牌
token, expiresAt, err := s.generateJWTToken(admin)
if err != nil {
return nil, fmt.Errorf("生成令牌失败: %w", err)
}
// 获取权限列表
permissions, err := s.getAdminPermissions(ctx, admin)
if err != nil {
s.logger.Error("获取管理员权限失败", zap.Error(err))
permissions = []string{}
}
// 构建响应
adminInfo := dto.AdminInfo{
ID: admin.ID,
Username: admin.Username,
Email: admin.Email,
Phone: admin.Phone,
RealName: admin.RealName,
Role: admin.Role,
IsActive: admin.IsActive,
LastLoginAt: admin.LastLoginAt,
LoginCount: admin.LoginCount,
Permissions: permissions,
CreatedAt: admin.CreatedAt,
}
s.logger.Info("管理员登录成功", zap.String("username", req.Username))
return &dto.AdminLoginResponse{
Token: token,
ExpiresAt: expiresAt,
Admin: adminInfo,
}, nil
}
// CreateAdmin 创建管理员
func (s *AdminService) CreateAdmin(ctx context.Context, req *dto.AdminCreateRequest, operatorID string) error {
s.logger.Info("创建管理员", zap.String("username", req.Username))
// 检查用户名是否已存在
if _, err := s.adminRepo.FindByUsername(ctx, req.Username); err == nil {
return fmt.Errorf("用户名已存在")
}
// 检查邮箱是否已存在
if _, err := s.adminRepo.FindByEmail(ctx, req.Email); err == nil {
return fmt.Errorf("邮箱已存在")
}
// 加密密码
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
if err != nil {
return fmt.Errorf("密码加密失败: %w", err)
}
// 序列化权限
permissionsJSON := "[]"
if len(req.Permissions) > 0 {
permissionsBytes, err := json.Marshal(req.Permissions)
if err != nil {
return fmt.Errorf("权限序列化失败: %w", err)
}
permissionsJSON = string(permissionsBytes)
}
// 创建管理员
admin := entities.Admin{
ID: s.generateID(),
Username: req.Username,
Password: string(hashedPassword),
Email: req.Email,
Phone: req.Phone,
RealName: req.RealName,
Role: req.Role,
IsActive: true,
Permissions: permissionsJSON,
}
if err := s.adminRepo.Create(ctx, admin); err != nil {
return fmt.Errorf("创建管理员失败: %w", err)
}
// 记录操作日志
s.recordOperationLog(ctx, operatorID, "create", "admin", admin.ID, map[string]interface{}{
"username": req.Username,
"email": req.Email,
"role": req.Role,
}, "success", "创建管理员成功")
s.logger.Info("管理员创建成功", zap.String("username", req.Username))
return nil
}
// UpdateAdmin 更新管理员
func (s *AdminService) UpdateAdmin(ctx context.Context, adminID string, req *dto.AdminUpdateRequest, operatorID string) error {
s.logger.Info("更新管理员", zap.String("admin_id", adminID))
// 获取管理员
admin, err := s.adminRepo.GetByID(ctx, adminID)
if err != nil {
return fmt.Errorf("管理员不存在")
}
// 更新字段
if req.Email != "" {
// 检查邮箱是否被其他管理员使用
if existingAdmin, err := s.adminRepo.FindByEmail(ctx, req.Email); err == nil && existingAdmin.ID != adminID {
return fmt.Errorf("邮箱已被其他管理员使用")
}
admin.Email = req.Email
}
if req.Phone != "" {
admin.Phone = req.Phone
}
if req.RealName != "" {
admin.RealName = req.RealName
}
if req.Role != "" {
admin.Role = req.Role
}
if req.IsActive != nil {
admin.IsActive = *req.IsActive
}
if len(req.Permissions) > 0 {
permissionsJSON, err := json.Marshal(req.Permissions)
if err != nil {
return fmt.Errorf("权限序列化失败: %w", err)
}
admin.Permissions = string(permissionsJSON)
}
// 保存更新
if err := s.adminRepo.Update(ctx, admin); err != nil {
return fmt.Errorf("更新管理员失败: %w", err)
}
// 记录操作日志
s.recordOperationLog(ctx, operatorID, "update", "admin", adminID, map[string]interface{}{
"email": req.Email,
"phone": req.Phone,
"real_name": req.RealName,
"role": req.Role,
"is_active": req.IsActive,
}, "success", "更新管理员成功")
s.logger.Info("管理员更新成功", zap.String("admin_id", adminID))
return nil
}
// ChangePassword 修改密码
func (s *AdminService) ChangePassword(ctx context.Context, adminID string, req *dto.AdminPasswordChangeRequest) error {
s.logger.Info("修改管理员密码", zap.String("admin_id", adminID))
// 获取管理员
admin, err := s.adminRepo.GetByID(ctx, adminID)
if err != nil {
return fmt.Errorf("管理员不存在")
}
// 验证旧密码
if err := bcrypt.CompareHashAndPassword([]byte(admin.Password), []byte(req.OldPassword)); err != nil {
return fmt.Errorf("旧密码错误")
}
// 加密新密码
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.NewPassword), bcrypt.DefaultCost)
if err != nil {
return fmt.Errorf("密码加密失败: %w", err)
}
// 更新密码
admin.Password = string(hashedPassword)
if err := s.adminRepo.Update(ctx, admin); err != nil {
return fmt.Errorf("更新密码失败: %w", err)
}
// 记录操作日志
s.recordOperationLog(ctx, adminID, "change_password", "admin", adminID, nil, "success", "修改密码成功")
s.logger.Info("管理员密码修改成功", zap.String("admin_id", adminID))
return nil
}
// ListAdmins 获取管理员列表
func (s *AdminService) ListAdmins(ctx context.Context, req *dto.AdminListRequest) (*dto.AdminListResponse, error) {
s.logger.Info("获取管理员列表", zap.Int("page", req.Page), zap.Int("page_size", req.PageSize))
response, err := s.adminRepo.ListAdmins(ctx, req)
if err != nil {
return nil, fmt.Errorf("获取管理员列表失败: %w", err)
}
return response, nil
}
// GetAdminStats 获取管理员统计信息
func (s *AdminService) GetAdminStats(ctx context.Context) (*dto.AdminStatsResponse, error) {
s.logger.Info("获取管理员统计信息")
stats, err := s.adminRepo.GetStats(ctx)
if err != nil {
return nil, fmt.Errorf("获取统计信息失败: %w", err)
}
return stats, nil
}
// GetAdminByID 根据ID获取管理员
func (s *AdminService) GetAdminByID(ctx context.Context, adminID string) (*dto.AdminInfo, error) {
s.logger.Info("获取管理员信息", zap.String("admin_id", adminID))
admin, err := s.adminRepo.GetByID(ctx, adminID)
if err != nil {
return nil, fmt.Errorf("管理员不存在")
}
// 获取权限列表
permissions, err := s.getAdminPermissions(ctx, &admin)
if err != nil {
s.logger.Error("获取管理员权限失败", zap.Error(err))
permissions = []string{}
}
adminInfo := dto.AdminInfo{
ID: admin.ID,
Username: admin.Username,
Email: admin.Email,
Phone: admin.Phone,
RealName: admin.RealName,
Role: admin.Role,
IsActive: admin.IsActive,
LastLoginAt: admin.LastLoginAt,
LoginCount: admin.LoginCount,
Permissions: permissions,
CreatedAt: admin.CreatedAt,
}
return &adminInfo, nil
}
// DeleteAdmin 删除管理员
func (s *AdminService) DeleteAdmin(ctx context.Context, adminID string, operatorID string) error {
s.logger.Info("删除管理员", zap.String("admin_id", adminID))
// 检查管理员是否存在
if _, err := s.adminRepo.GetByID(ctx, adminID); err != nil {
return fmt.Errorf("管理员不存在")
}
// 软删除管理员
if err := s.adminRepo.SoftDelete(ctx, adminID); err != nil {
return fmt.Errorf("删除管理员失败: %w", err)
}
// 记录操作日志
s.recordOperationLog(ctx, operatorID, "delete", "admin", adminID, nil, "success", "删除管理员成功")
s.logger.Info("管理员删除成功", zap.String("admin_id", adminID))
return nil
}
// getAdminPermissions 获取管理员权限
func (s *AdminService) getAdminPermissions(ctx context.Context, admin *entities.Admin) ([]string, error) {
// 首先从角色获取权限
rolePermissions, err := s.adminRepo.GetPermissionsByRole(ctx, admin.Role)
if err != nil {
return nil, err
}
// 从角色权限中提取权限代码
permissions := make([]string, 0, len(rolePermissions))
for _, perm := range rolePermissions {
permissions = append(permissions, perm.Code)
}
// 如果有自定义权限,也添加进去
if admin.Permissions != "" {
var customPermissions []string
if err := json.Unmarshal([]byte(admin.Permissions), &customPermissions); err == nil {
permissions = append(permissions, customPermissions...)
}
}
return permissions, nil
}
// generateJWTToken 生成JWT令牌
func (s *AdminService) generateJWTToken(admin *entities.Admin) (string, time.Time, error) {
// 这里应该使用JWT库生成令牌
// 为了简化,这里返回一个模拟的令牌
token := fmt.Sprintf("admin_token_%s_%d", admin.ID, time.Now().Unix())
expiresAt := time.Now().Add(24 * time.Hour)
return token, expiresAt, nil
}
// generateID 生成ID
func (s *AdminService) generateID() string {
bytes := make([]byte, 16)
rand.Read(bytes)
return hex.EncodeToString(bytes)
}
// recordLoginLog 记录登录日志
func (s *AdminService) recordLoginLog(ctx context.Context, username, ip, userAgent, status, message string) {
log := entities.AdminLoginLog{
ID: s.generateID(),
Username: username,
IP: ip,
UserAgent: userAgent,
Status: status,
Message: message,
}
if err := s.loginLogRepo.Create(ctx, log); err != nil {
s.logger.Error("记录登录日志失败", zap.Error(err))
}
}
// recordOperationLog 记录操作日志
func (s *AdminService) recordOperationLog(ctx context.Context, adminID, action, resource, resourceID string, details map[string]interface{}, status, message string) {
detailsJSON := "{}"
if details != nil {
if bytes, err := json.Marshal(details); err == nil {
detailsJSON = string(bytes)
}
}
log := entities.AdminOperationLog{
ID: s.generateID(),
AdminID: adminID,
Action: action,
Resource: resource,
ResourceID: resourceID,
Details: detailsJSON,
Status: status,
Message: message,
}
if err := s.operationLogRepo.Create(ctx, log); err != nil {
s.logger.Error("记录操作日志失败", zap.Error(err))
}
}