package service import ( "context" "fmt" "time" "github.com/user-management-system/internal/domain" "github.com/user-management-system/internal/pagination" "github.com/user-management-system/internal/repository" ) // OperationLogService 操作日志服务 type OperationLogService struct { operationLogRepo *repository.OperationLogRepository } // NewOperationLogService 创建操作日志服务 func NewOperationLogService(operationLogRepo *repository.OperationLogRepository) *OperationLogService { return &OperationLogService{operationLogRepo: operationLogRepo} } // RecordOperation 记录操作日志 func (s *OperationLogService) RecordOperation(ctx context.Context, req *RecordOperationRequest) error { log := &domain.OperationLog{ OperationType: req.OperationType, OperationName: req.OperationName, RequestMethod: req.RequestMethod, RequestPath: req.RequestPath, RequestParams: req.RequestParams, ResponseStatus: req.ResponseStatus, IP: req.IP, UserAgent: req.UserAgent, } if req.UserID != 0 { log.UserID = &req.UserID } return s.operationLogRepo.Create(ctx, log) } // RecordOperationRequest 记录操作请求 type RecordOperationRequest struct { UserID int64 `json:"user_id"` OperationType string `json:"operation_type"` OperationName string `json:"operation_name"` RequestMethod string `json:"request_method"` RequestPath string `json:"request_path"` RequestParams string `json:"request_params"` ResponseStatus int `json:"response_status"` IP string `json:"ip"` UserAgent string `json:"user_agent"` } // ListOperationLogRequest 操作日志列表请求 type ListOperationLogRequest struct { UserID int64 `json:"user_id" form:"user_id"` Method string `json:"method" form:"method"` Keyword string `json:"keyword" form:"keyword"` Page int `json:"page" form:"page"` PageSize int `json:"page_size" form:"page_size"` StartAt string `json:"start_at" form:"start_at"` EndAt string `json:"end_at" form:"end_at"` Cursor string `form:"cursor"` // Opaque cursor for keyset pagination Size int `form:"size"` // Page size when using cursor mode } // GetOperationLogs 获取操作日志列表 func (s *OperationLogService) GetOperationLogs(ctx context.Context, req *ListOperationLogRequest) ([]*domain.OperationLog, int64, error) { if req.Page <= 0 { req.Page = 1 } if req.PageSize <= 0 { req.PageSize = 20 } offset := (req.Page - 1) * req.PageSize // 按关键词搜索 if req.Keyword != "" { return s.operationLogRepo.Search(ctx, req.Keyword, offset, req.PageSize) } // 按用户 ID 查询 if req.UserID > 0 { return s.operationLogRepo.ListByUserID(ctx, req.UserID, offset, req.PageSize) } // 按 HTTP 方法查询 if req.Method != "" { return s.operationLogRepo.ListByMethod(ctx, req.Method, offset, req.PageSize) } // 按时间范围查询 if req.StartAt != "" && req.EndAt != "" { start, err1 := time.Parse(time.RFC3339, req.StartAt) end, err2 := time.Parse(time.RFC3339, req.EndAt) if err1 == nil && err2 == nil { return s.operationLogRepo.ListByTimeRange(ctx, start, end, offset, req.PageSize) } } return s.operationLogRepo.List(ctx, offset, req.PageSize) } // GetOperationLogsCursor 游标分页获取操作日志列表(推荐使用) func (s *OperationLogService) GetOperationLogsCursor(ctx context.Context, req *ListOperationLogRequest) (*CursorResult, error) { size := pagination.ClampPageSize(req.Size) cursor, err := pagination.Decode(req.Cursor) if err != nil { return nil, fmt.Errorf("invalid cursor: %w", err) } var items interface{} var hasMore bool logs, hm, err := s.operationLogRepo.ListCursor(ctx, size, cursor) if err != nil { return nil, err } items = logs hasMore = hm nextCursor := "" switch items := items.(type) { case []*domain.OperationLog: if len(items) > 0 { last := items[len(items)-1] nextCursor = pagination.BuildNextCursor(last.ID, last.CreatedAt) } } return &CursorResult{ Items: items, NextCursor: nextCursor, HasMore: hasMore, PageSize: size, }, nil } // GetMyOperationLogs 获取当前用户的操作日志 func (s *OperationLogService) GetMyOperationLogs(ctx context.Context, userID int64, page, pageSize int) ([]*domain.OperationLog, int64, error) { if page <= 0 { page = 1 } if pageSize <= 0 { pageSize = 20 } offset := (page - 1) * pageSize return s.operationLogRepo.ListByUserID(ctx, userID, offset, pageSize) } // CleanupOldLogs 清理旧日志(保留最近 N 天) func (s *OperationLogService) CleanupOldLogs(ctx context.Context, retentionDays int) error { return s.operationLogRepo.DeleteOlderThan(ctx, retentionDays) }