package handlers import ( "net/http" "strconv" "time" "ezops/internal/models" "github.com/gin-gonic/gin" "gorm.io/gorm" ) // AuditHandler 审计日志处理器 type AuditHandler struct { db *gorm.DB } // NewAuditHandler 创建审计日志处理器 func NewAuditHandler(db *gorm.DB) *AuditHandler { return &AuditHandler{db: db} } // ListAuditLogs 获取审计日志列表 // @Summary 获取审计日志列表 // @Description 获取审计日志列表,支持分页和筛选 // @Tags 审计日志 // @Accept json // @Produce json // @Param page query int false "页码" default(1) // @Param pageSize query int false "每页数量" default(20) // @Param module query string false "模块" // @Param action query string false "操作类型" // @Param username query string false "用户名" // @Param startTime query string false "开始时间" // @Param endTime query string false "结束时间" // @Success 200 {object} models.AuditLogListResponse // @Router /api/v1/audit/logs [get] func (h *AuditHandler) ListAuditLogs(c *gin.Context) { var req models.AuditLogQuery if err := c.ShouldBindQuery(&req); err != nil { c.JSON(http.StatusBadRequest, models.Response{Code: 400, Message: err.Error()}) return } // 设置默认值 if req.Page <= 0 { req.Page = 1 } if req.PageSize <= 0 { req.PageSize = 20 } // 构建查询 query := h.db.Model(&models.AuditLog{}) if req.Module != "" { query = query.Where("module = ?", req.Module) } if req.Action != "" { query = query.Where("action = ?", req.Action) } if req.Username != "" { query = query.Where("username LIKE ?", "%"+req.Username+"%") } if req.StartTime != "" { query = query.Where("created_at >= ?", req.StartTime) } if req.EndTime != "" { query = query.Where("created_at <= ?", req.EndTime) } // 获取总数 var total int64 if err := query.Count(&total).Error; err != nil { c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: "查询失败"}) return } // 获取列表 var logs []models.AuditLog if err := query.Order("created_at DESC"). Offset((req.Page - 1) * req.PageSize). Limit(req.PageSize). Find(&logs).Error; err != nil { c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: "查询失败"}) return } c.JSON(http.StatusOK, models.AuditLogListResponse{ List: logs, Total: total, }) } // GetAuditLogDetail 获取审计日志详情 // @Summary 获取审计日志详情 // @Description 获取指定ID的审计日志详情 // @Tags 审计日志 // @Accept json // @Produce json // @Param id path int true "日志ID" // @Success 200 {object} models.AuditLog // @Router /api/v1/audit/logs/{id} [get] func (h *AuditHandler) GetAuditLogDetail(c *gin.Context) { id, err := strconv.ParseUint(c.Param("id"), 10, 64) if err != nil { c.JSON(http.StatusBadRequest, models.Response{Code: 400, Message: "无效的日志ID"}) return } var log models.AuditLog if err := h.db.First(&log, id).Error; err != nil { if err == gorm.ErrRecordNotFound { c.JSON(http.StatusNotFound, models.Response{Code: 404, Message: "日志不存在"}) return } c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: "查询失败"}) return } c.JSON(http.StatusOK, log) } // GetAuditModules 获取审计模块列表 // @Summary 获取审计模块列表 // @Description 获取所有审计模块类型 // @Tags 审计日志 // @Accept json // @Produce json // @Success 200 {object} map[string]interface{} // @Router /api/v1/audit/modules [get] func (h *AuditHandler) GetAuditModules(c *gin.Context) { modules := []map[string]string{ {"value": "user", "label": "用户管理"}, {"value": "server", "label": "服务器管理"}, {"value": "k8s", "label": "Kubernetes"}, {"value": "alert", "label": "监控告警"}, {"value": "pipeline", "label": "应用发布"}, {"value": "automation", "label": "自动化运维"}, {"value": "approval", "label": "审批流程"}, {"value": "navigation", "label": "站内导航"}, {"value": "cloud_account", "label": "云账号管理"}, {"value": "domain", "label": "域名管理"}, } c.JSON(http.StatusOK, gin.H{"data": modules}) } // GetAuditActions 获取审计操作类型列表 // @Summary 获取审计操作类型列表 // @Description 获取所有审计操作类型 // @Tags 审计日志 // @Accept json // @Produce json // @Success 200 {object} map[string]interface{} // @Router /api/v1/audit/actions [get] func (h *AuditHandler) GetAuditActions(c *gin.Context) { actions := []map[string]string{ {"value": "create", "label": "创建"}, {"value": "update", "label": "更新"}, {"value": "delete", "label": "删除"}, {"value": "view", "label": "查看"}, {"value": "login", "label": "登录"}, {"value": "logout", "label": "登出"}, {"value": "execute", "label": "执行"}, {"value": "approve", "label": "审批"}, {"value": "reject", "label": "驳回"}, {"value": "import", "label": "导入"}, {"value": "export", "label": "导出"}, } c.JSON(http.StatusOK, gin.H{"data": actions}) } // ExportAuditLogs 导出审计日志 // @Summary 导出审计日志 // @Description 导出审计日志为Excel或CSV // @Tags 审计日志 // @Accept json // @Produce json // @Param module query string false "模块" // @Param action query string false "操作类型" // @Param username query string false "用户名" // @Param startTime query string false "开始时间" // @Param endTime query string false "结束时间" // @Param format query string false "导出格式" default("csv") Enums(csv, excel) // @Success 200 {file} binary // @Router /api/v1/audit/logs/export [get] func (h *AuditHandler) ExportAuditLogs(c *gin.Context) { var req models.AuditLogQuery if err := c.ShouldBindQuery(&req); err != nil { c.JSON(http.StatusBadRequest, models.Response{Code: 400, Message: err.Error()}) return } // 构建查询 query := h.db.Model(&models.AuditLog{}) if req.Module != "" { query = query.Where("module = ?", req.Module) } if req.Action != "" { query = query.Where("action = ?", req.Action) } if req.Username != "" { query = query.Where("username LIKE ?", "%"+req.Username+"%") } if req.StartTime != "" { query = query.Where("created_at >= ?", req.StartTime) } if req.EndTime != "" { query = query.Where("created_at <= ?", req.EndTime) } // 获取数据 var logs []models.AuditLog if err := query.Order("created_at DESC").Find(&logs).Error; err != nil { c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: "导出失败"}) return } // TODO: 实现CSV/Excel导出功能 // 这里返回JSON格式的数据,实际项目中应该生成CSV或Excel文件 c.JSON(http.StatusOK, gin.H{ "message": "导出成功", "count": len(logs), "data": logs, }) } // GetAuditStatistics 获取审计统计 // @Summary 获取审计统计 // @Description 获取审计日志统计信息 // @Tags 审计日志 // @Accept json // @Produce json // @Param days query int false "统计天数" default(7) // @Success 200 {object} map[string]interface{} // @Router /api/v1/audit/statistics [get] func (h *AuditHandler) GetAuditStatistics(c *gin.Context) { days, _ := strconv.Atoi(c.DefaultQuery("days", "7")) if days <= 0 { days = 7 } startTime := time.Now().AddDate(0, 0, -days) // 统计各模块的操作数量 var moduleStats []struct { Module string `json:"module"` Count int64 `json:"count"` } h.db.Model(&models.AuditLog{}). Select("module, COUNT(*) as count"). Where("created_at >= ?", startTime). Group("module"). Scan(&moduleStats) // 统计各操作类型的数量 var actionStats []struct { Action string `json:"action"` Count int64 `json:"count"` } h.db.Model(&models.AuditLog{}). Select("action, COUNT(*) as count"). Where("created_at >= ?", startTime). Group("action"). Scan(&actionStats) // 统计每日操作数量 var dailyStats []struct { Date string `json:"date"` Count int64 `json:"count"` } h.db.Model(&models.AuditLog{}). Select("DATE(created_at) as date, COUNT(*) as count"). Where("created_at >= ?", startTime). Group("DATE(created_at)"). Order("date"). Scan(&dailyStats) // 总记录数 var totalCount int64 h.db.Model(&models.AuditLog{}).Count(&totalCount) // 今日记录数 today := time.Now().Format("2006-01-02") var todayCount int64 h.db.Model(&models.AuditLog{}). Where("DATE(created_at) = ?", today). Count(&todayCount) c.JSON(http.StatusOK, gin.H{ "total_count": totalCount, "today_count": todayCount, "module_stats": moduleStats, "action_stats": actionStats, "daily_stats": dailyStats, }) } // ClearAuditLogs 清理审计日志 // @Summary 清理审计日志 // @Description 清理指定日期之前的审计日志 // @Tags 审计日志 // @Accept json // @Produce json // @Param request body map[string]string true "清理请求" // @Success 200 {object} map[string]interface{} // @Router /api/v1/audit/logs/clear [post] func (h *AuditHandler) ClearAuditLogs(c *gin.Context) { var req struct { BeforeDate string `json:"before_date" binding:"required"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, models.Response{Code: 400, Message: "无效的请求参数"}) return } // 解析日期 beforeDate, err := time.Parse("2006-01-02", req.BeforeDate) if err != nil { c.JSON(http.StatusBadRequest, models.Response{Code: 400, Message: "无效的日期格式"}) return } // 删除指定日期之前的日志 result := h.db.Where("created_at < ?", beforeDate).Delete(&models.AuditLog{}) if result.Error != nil { c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: "清理失败"}) return } // 记录审计日志 userID, _ := c.Get("userID") username, _ := c.Get("username") h.RecordAuditLog(userID.(uint), username.(string), "audit", "clear", "清理审计日志", gin.H{ "before_date": req.BeforeDate, "deleted": result.RowsAffected, }) c.JSON(http.StatusOK, gin.H{ "message": "清理成功", "deleted": result.RowsAffected, }) } // RecordAuditLog 记录审计日志 func (h *AuditHandler) RecordAuditLog(userID uint, username, module, action, description string, details interface{}) { uid := userID log := models.AuditLog{ UserID: &uid, Username: username, Module: module, Action: action, Resource: description, } h.db.Create(&log) }