2026-03-18 21:51:17 +08:00
|
|
|
|
package admin
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"NetworkAuth/controllers"
|
|
|
|
|
|
"NetworkAuth/models"
|
2026-03-19 19:17:37 +08:00
|
|
|
|
"NetworkAuth/services"
|
2026-03-18 21:51:17 +08:00
|
|
|
|
"strconv"
|
|
|
|
|
|
"strings"
|
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
// 全局变量
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
var loginLogBaseController = controllers.NewBaseController()
|
|
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
// 辅助函数
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
// RecordLoginLog 记录登录日志
|
|
|
|
|
|
func RecordLoginLog(c *gin.Context, username string, status int, message string) {
|
|
|
|
|
|
db, ok := loginLogBaseController.GetDB(c)
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
log := models.LoginLog{
|
|
|
|
|
|
Type: "admin",
|
|
|
|
|
|
Username: username,
|
|
|
|
|
|
IP: c.ClientIP(),
|
|
|
|
|
|
Status: status,
|
|
|
|
|
|
Message: message,
|
|
|
|
|
|
UserAgent: c.Request.UserAgent(),
|
|
|
|
|
|
CreatedAt: time.Now(),
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if err := db.Create(&log).Error; err != nil {
|
|
|
|
|
|
logrus.WithError(err).Error("Failed to create login log")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
// API处理器
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
// LoginLogsListHandler 登录日志列表API处理器
|
|
|
|
|
|
func LoginLogsListHandler(c *gin.Context) {
|
|
|
|
|
|
// 获取分页参数
|
2026-03-19 19:17:37 +08:00
|
|
|
|
page, limit := loginLogBaseController.GetPaginationParams(c)
|
2026-03-18 21:51:17 +08:00
|
|
|
|
|
2026-03-28 23:30:02 +08:00
|
|
|
|
// 获取数据库连接
|
2026-03-18 21:51:17 +08:00
|
|
|
|
db, ok := loginLogBaseController.GetDB(c)
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 兼容旧数据(Type为空)和新数据(Type=admin)
|
|
|
|
|
|
query := db.Model(&models.LoginLog{}).Where("type = ? OR type = ? OR type IS NULL", "admin", "")
|
|
|
|
|
|
|
|
|
|
|
|
// 筛选条件:用户名
|
|
|
|
|
|
if username := strings.TrimSpace(c.Query("username")); username != "" {
|
|
|
|
|
|
query = query.Where("username = ?", username)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 筛选条件:IP
|
|
|
|
|
|
if ip := strings.TrimSpace(c.Query("ip")); ip != "" {
|
|
|
|
|
|
query = query.Where("ip = ?", ip)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 筛选条件:状态
|
|
|
|
|
|
if statusStr := strings.TrimSpace(c.Query("status")); statusStr != "" {
|
|
|
|
|
|
if status, err := strconv.Atoi(statusStr); err == nil {
|
|
|
|
|
|
query = query.Where("status = ?", status)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 筛选条件:时间范围
|
2026-03-19 19:17:37 +08:00
|
|
|
|
query = loginLogBaseController.ApplyTimeRangeQuery(c, query, "created_at")
|
2026-03-18 21:51:17 +08:00
|
|
|
|
|
2026-03-19 19:17:37 +08:00
|
|
|
|
// 泛型分页查询
|
|
|
|
|
|
logs, total, err := services.Paginate[models.LoginLog](query, page, limit, "created_at DESC")
|
|
|
|
|
|
if err != nil {
|
2026-03-18 21:51:17 +08:00
|
|
|
|
loginLogBaseController.HandleInternalError(c, "获取日志列表失败", err)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 转换数据格式
|
|
|
|
|
|
var list []map[string]interface{}
|
|
|
|
|
|
for _, log := range logs {
|
|
|
|
|
|
list = append(list, map[string]interface{}{
|
|
|
|
|
|
"id": log.ID,
|
|
|
|
|
|
"username": log.Username,
|
|
|
|
|
|
"ip": log.IP,
|
|
|
|
|
|
"status": log.Status,
|
|
|
|
|
|
"message": log.Message,
|
|
|
|
|
|
"user_agent": log.UserAgent,
|
|
|
|
|
|
"created_at": log.CreatedAt,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
loginLogBaseController.HandleSuccess(c, "ok", gin.H{
|
|
|
|
|
|
"list": list,
|
|
|
|
|
|
"total": total,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// LoginLogsClearHandler 清空登录日志API处理器
|
|
|
|
|
|
func LoginLogsClearHandler(c *gin.Context) {
|
|
|
|
|
|
db, ok := loginLogBaseController.GetDB(c)
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 物理删除所有登录日志
|
|
|
|
|
|
if err := db.Where("type = ?", "admin").Delete(&models.LoginLog{}).Error; err != nil {
|
|
|
|
|
|
logrus.WithError(err).Error("Failed to clear login logs")
|
|
|
|
|
|
loginLogBaseController.HandleInternalError(c, "清空登录日志失败", err)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 记录操作日志
|
2026-03-28 23:30:02 +08:00
|
|
|
|
var operator, operatorUUID string
|
|
|
|
|
|
if claims, _, err := GetCurrentAdminUserWithRefresh(c); err == nil && claims != nil {
|
|
|
|
|
|
operator = claims.Username
|
|
|
|
|
|
operatorUUID = claims.UUID
|
|
|
|
|
|
} else {
|
|
|
|
|
|
operator = "admin"
|
|
|
|
|
|
operatorUUID = "00000000-0000-0000-0000-000000000000"
|
|
|
|
|
|
}
|
2026-03-18 21:51:17 +08:00
|
|
|
|
|
|
|
|
|
|
log := models.OperationLog{
|
|
|
|
|
|
OperationType: "清空登录日志",
|
|
|
|
|
|
Operator: operator,
|
2026-03-28 23:30:02 +08:00
|
|
|
|
OperatorUUID: operatorUUID,
|
2026-03-18 21:51:17 +08:00
|
|
|
|
Details: "管理员清空了所有登录日志",
|
|
|
|
|
|
CreatedAt: time.Now(),
|
|
|
|
|
|
}
|
|
|
|
|
|
db.Create(&log)
|
|
|
|
|
|
|
|
|
|
|
|
loginLogBaseController.HandleSuccess(c, "登录日志已清空", nil)
|
|
|
|
|
|
}
|