package order_package_invalidate import ( "context" "path/filepath" "time" "github.com/hibiken/asynq" "github.com/break/junhong_cmp_fiber/internal/model" "github.com/break/junhong_cmp_fiber/internal/model/dto" "github.com/break/junhong_cmp_fiber/internal/store" "github.com/break/junhong_cmp_fiber/internal/store/postgres" "github.com/break/junhong_cmp_fiber/pkg/constants" "github.com/break/junhong_cmp_fiber/pkg/errors" "github.com/break/junhong_cmp_fiber/pkg/middleware" "github.com/break/junhong_cmp_fiber/pkg/queue" ) // Service 订单套餐失效任务业务逻辑层 type Service struct { taskStore *postgres.OrderPackageInvalidateTaskStore queueClient *queue.Client } // New 创建 Service 实例 func New( taskStore *postgres.OrderPackageInvalidateTaskStore, queueClient *queue.Client, ) *Service { return &Service{ taskStore: taskStore, queueClient: queueClient, } } // InvalidateTaskPayload Worker 任务载荷 type InvalidateTaskPayload struct { TaskID uint `json:"task_id"` } // Create 创建订单套餐失效任务 func (s *Service) Create(ctx context.Context, req *dto.CreateOrderPackageInvalidateTaskRequest) (*dto.OrderPackageInvalidateTaskResponse, error) { userID := middleware.GetUserIDFromContext(ctx) if userID == 0 { return nil, errors.New(errors.CodeUnauthorized, "未授权访问") } task := &model.OrderPackageInvalidateTask{ TaskNo: s.taskStore.GenerateTaskNo(), Status: model.ImportTaskStatusPending, FileName: filepath.Base(req.FileKey), StorageKey: req.FileKey, VoucherKeys: model.StringJSONBArray(req.VoucherKeys), Remark: req.Remark, CreatorName: middleware.GetUsernameFromContext(ctx), FailedItems: model.ImportResultItems{}, Creator: userID, Updater: userID, } if err := s.taskStore.Create(ctx, task); err != nil { return nil, errors.Wrap(errors.CodeInternalError, err, "创建任务失败") } payload := InvalidateTaskPayload{TaskID: task.ID} err := s.queueClient.EnqueueTask( ctx, constants.TaskTypeOrderPackageInvalidate, payload, asynq.Queue(constants.QueueForTaskType(constants.TaskTypeOrderPackageInvalidate)), ) if err != nil { s.taskStore.UpdateStatus(ctx, task.ID, model.ImportTaskStatusFailed, "任务入队失败: "+err.Error()) } return s.toResponse(task), nil } // List 分页查询任务列表 func (s *Service) List(ctx context.Context, req *dto.ListOrderPackageInvalidateTaskRequest) (*dto.OrderPackageInvalidateTaskListResponse, error) { if req.Page <= 0 { req.Page = 1 } if req.PageSize <= 0 { req.PageSize = constants.DefaultPageSize } opts := &store.QueryOptions{ Page: req.Page, PageSize: req.PageSize, } filters := map[string]interface{}{} if req.Status != nil { filters["status"] = *req.Status } tasks, total, err := s.taskStore.List(ctx, opts, filters) if err != nil { return nil, errors.Wrap(errors.CodeInternalError, err, "查询任务列表失败") } list := make([]*dto.OrderPackageInvalidateTaskResponse, 0, len(tasks)) for _, t := range tasks { list = append(list, s.toResponse(t)) } return &dto.OrderPackageInvalidateTaskListResponse{ Total: total, Page: req.Page, PageSize: req.PageSize, List: list, }, nil } // GetByID 查询任务详情(含失败明细) func (s *Service) GetByID(ctx context.Context, id uint) (*dto.OrderPackageInvalidateTaskDetailResponse, error) { task, err := s.taskStore.GetByID(ctx, id) if err != nil { return nil, errors.New(errors.CodeNotFound, "任务不存在") } failedItems := make([]dto.InvalidateFailedItem, 0, len(task.FailedItems)) for _, item := range task.FailedItems { failedItems = append(failedItems, dto.InvalidateFailedItem{ Line: item.Line, OrderNo: item.ICCID, // 复用 ImportResultItem.ICCID 存储 order_no Reason: item.Reason, }) } return &dto.OrderPackageInvalidateTaskDetailResponse{ OrderPackageInvalidateTaskResponse: *s.toResponse(task), FailedItems: failedItems, }, nil } // toResponse 转换为响应 DTO func (s *Service) toResponse(task *model.OrderPackageInvalidateTask) *dto.OrderPackageInvalidateTaskResponse { resp := &dto.OrderPackageInvalidateTaskResponse{ ID: task.ID, TaskNo: task.TaskNo, Status: task.Status, StatusName: invalidateTaskStatusName(task.Status), TotalCount: task.TotalCount, SuccessCount: task.SuccessCount, FailCount: task.FailCount, FileName: task.FileName, VoucherKeys: []string(task.VoucherKeys), Remark: task.Remark, CreatorName: task.CreatorName, ErrorMessage: task.ErrorMessage, CreatedAt: task.CreatedAt.Format(time.RFC3339), UpdatedAt: task.UpdatedAt.Format(time.RFC3339), } if task.StartedAt != nil { t := task.StartedAt.Format(time.RFC3339) resp.StartedAt = &t } if task.CompletedAt != nil { t := task.CompletedAt.Format(time.RFC3339) resp.CompletedAt = &t } if resp.VoucherKeys == nil { resp.VoucherKeys = []string{} } return resp } // invalidateTaskStatusName 状态码转中文 func invalidateTaskStatusName(status int) string { switch status { case model.ImportTaskStatusPending: return "待处理" case model.ImportTaskStatusProcessing: return "处理中" case model.ImportTaskStatusCompleted: return "已完成" case model.ImportTaskStatusFailed: return "失败" default: return "未知" } }