package admin import ( "NetworkAuth/controllers" "NetworkAuth/models" "NetworkAuth/services" "strconv" "strings" "time" "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" "gorm.io/gorm" ) // ============================================================================ // 全局变量 // ============================================================================ 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) { // 获取分页参数 page, limit := loginLogBaseController.GetPaginationParams(c) // 获取数据库连接 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) } } // 筛选条件:时间范围 query = loginLogBaseController.ApplyTimeRangeQuery(c, query, "created_at") // 泛型分页查询 logs, total, err := services.Paginate[models.LoginLog](query, page, limit, "created_at DESC") if err != nil { 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.Session(&gorm.Session{AllowGlobalUpdate: true}).Unscoped().Where("type = ? OR type = ? OR type IS NULL", "admin", "").Delete(&models.LoginLog{}).Error; err != nil { logrus.WithError(err).Error("Failed to clear login logs") loginLogBaseController.HandleInternalError(c, "清空登录日志失败", err) return } // 记录操作日志 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" } log := models.OperationLog{ OperationType: "清空登录日志", Operator: operator, OperatorUUID: operatorUUID, Details: "管理员清空了所有登录日志", CreatedAt: time.Now(), } db.Create(&log) loginLogBaseController.HandleSuccess(c, "登录日志已清空", nil) }