diff --git a/pkg/cron/task.go b/pkg/cron/task.go index 9c5d09f..45c9afe 100644 --- a/pkg/cron/task.go +++ b/pkg/cron/task.go @@ -32,6 +32,8 @@ func InitTasks() error { err = cm.AddTask("artistAutoConfirmAnalysis", "0 */1 * * * *", ArtistAutoConfirmAnalysisTask) err = cm.AddTask("refreshWorkAnalysisApprovalStatus", "0 */1 * * * *", RefreshWorkAnalysisApprovalStatusTask) + err = cm.AddTask("artistAutoConfirmReport", "0 */1 * * * *", ArtistAutoConfirmReportTask) + err = cm.AddTask("refreshCompetitiveReportApprovalStatus", "0 */1 * * * *", RefreshCompetitiveReportApprovalStatusTask) err = cm.AddTask("refreshArtistOrder", "0 */30 * * * *", RefreshArtistOrderTask) // 每天 00:30 和 12:30 执行 Ayrshare 指标采集任务 @@ -500,6 +502,43 @@ func ArtistAutoConfirmAnalysisTask() { } } +func ArtistAutoConfirmReportTask() { + now := float64(time.Now().Unix()) + opt := redis.ZRangeBy{ + Min: fmt.Sprintf("%d", 0), + Max: fmt.Sprintf("%f", now), + } + reportUuids, err := cache.RedisClient.ZRangeByScore(modelCast.AutoConfirmReportQueueKey, opt).Result() + if err != nil { + zap.L().Error("获取到期竞品报告任务失败", zap.Error(err)) + return + } + if len(reportUuids) == 0 { + zap.L().Debug("没有到期的竞品报告任务") + return + } + zap.L().Info("发现到期竞品报告任务", zap.Int("count", len(reportUuids))) + for _, reportUuid := range reportUuids { + serverCast.ProcessReportTask(context.Background(), reportUuid) + } +} + +func RefreshCompetitiveReportApprovalStatusTask() { + resp, err := service.CastProvider.ListCompetitiveReport(context.Background(), &cast.ListCompetitiveReportReq{ + Page: 1, + StatusList: []uint32{2}, // 状态为2表示待审批 + PageSize: 999999, + }) + if err != nil { + log.Printf("获取竞品报告列表失败: %v", err) + return + } + if resp.Data == nil || len(resp.Data) == 0 { + return + } + serverCast.RefreshCompetitiveReportApproval(nil, resp.Data) +} + // AyrshareMetricsCollectorTask Ayrshare 指标采集定时任务(每天 00:30 和 12:30 执行) func AyrshareMetricsCollectorTask() { serverCast.ExecuteAyrshareMetricsCollector() diff --git a/pkg/model/cast/work.go b/pkg/model/cast/work.go index 7739e79..4e062be 100644 --- a/pkg/model/cast/work.go +++ b/pkg/model/cast/work.go @@ -21,6 +21,9 @@ const ( AutoConfirmAnalysisQueueKey = "auto_confirm:analysis:queue" AutoConfirmAnalysisLockKey = "auto_confirm:analysis:lock:%s" + AutoConfirmReportQueueKey = "auto_confirm:report:queue" + AutoConfirmReportLockKey = "auto_confirm:report:lock:%s" + // AyrshareMetricsCollectorLockKey Ayrshare 指标采集任务锁 AyrshareMetricsCollectorLockKey = "ayrshare:metrics:collector:lock" ) diff --git a/pkg/service/cast/report.go b/pkg/service/cast/report.go index fa136c6..50d805e 100644 --- a/pkg/service/cast/report.go +++ b/pkg/service/cast/report.go @@ -1,11 +1,20 @@ package cast import ( + "context" + "fmt" + "fonchain-fiee/api/bundle" "fonchain-fiee/api/cast" + "fonchain-fiee/pkg/cache" + modelCast "fonchain-fiee/pkg/model/cast" "fonchain-fiee/pkg/service" "fonchain-fiee/pkg/utils" + "strconv" + "time" + "dubbo.apache.org/dubbo-go/v3/common/constant" "github.com/gin-gonic/gin" + "go.uber.org/zap" ) // CreateCompetitiveReport 创建竞品报告 @@ -112,6 +121,7 @@ func ListCompetitiveReport(ctx *gin.Context) { service.Error(ctx, err) return } + RefreshCompetitiveReportApproval(ctx, resp.Data) service.Success(ctx, resp) return } @@ -286,3 +296,177 @@ func ListCompetitiveReportSingleExport(ctx *gin.Context) { utils.ResponseXls(ctx, content, "竞品报告列表") return } + +// RefreshCompetitiveReportApproval 刷新竞品报告审批状态 +func RefreshCompetitiveReportApproval(ctx *gin.Context, data []*cast.CompetitiveReportInfo) { + if len(data) > 0 { + var reportUuidApprovalIDMap = make(map[int]string) + for _, v := range data { + // 状态为2表示待审批,需要获取详情来获取ApprovalID + if v.WorkReportStatus == 2 && v.ApprovalID != "" { + zap.L().Info("RefreshCompetitiveReportApproval", zap.Any("approvalID", v.ApprovalID)) + approvalID, _ := strconv.ParseUint(v.ApprovalID, 10, 64) + reportUuidApprovalIDMap[int(approvalID)] = v.Uuid + } + } + if len(reportUuidApprovalIDMap) > 0 { + _ = RefreshCompetitiveReportApprovalStatus(ctx, reportUuidApprovalIDMap) + } + } +} + +// RefreshCompetitiveReportApprovalStatus 刷新竞品报告审批状态详情 +func RefreshCompetitiveReportApprovalStatus(ctx *gin.Context, approvalIDReportUuidMap map[int]string) (err error) { + var castS = new(CastService) + var data = make(map[int]modelCast.Item) + var approvalIDs []int + for approvalId := range approvalIDReportUuidMap { + approvalIDs = append(approvalIDs, approvalId) + } + if len(approvalIDs) == 0 { + return + } + data, err = castS.ApprovalDetail(approvalIDs) + if err != nil { + return + } + // status: 1待审批 2审批通过 3审批不通过 6撤销发其中 7撤销完成 + var newData = make(map[int]modelCast.Item, len(approvalIDs)) + for _, v := range approvalIDs { + newData[v] = data[v] + } + newCtx := NewCtxWithUserInfo(ctx) + if len(newData) > 0 { + for approvalId, v := range newData { + if v.ID == 0 { + _, _ = service.CastProvider.UpdateCompetitiveReportStatus(newCtx, &cast.UpdateCompetitiveReportStatusReq{ + WorkAction: cast.WorkActionENUM_APPROVAL_DELETE, + Uuid: approvalIDReportUuidMap[approvalId], + ApprovalID: fmt.Sprint(approvalId), + ApprovalReply: "", + }) + continue + } + var workAction cast.WorkActionENUM + if v.Status == 2 { + workAction = cast.WorkActionENUM_APPROVAL_PASS + } else if v.Status == 3 { + workAction = cast.WorkActionENUM_APPROVAL_REJECT + } else { + continue + } + _, _ = service.CastProvider.UpdateCompetitiveReportStatus(newCtx, &cast.UpdateCompetitiveReportStatusReq{ + WorkAction: workAction, + Uuid: approvalIDReportUuidMap[approvalId], + ApprovalID: fmt.Sprint(approvalId), + ApprovalReply: v.Reply, + }) + } + } + return +} + +// ProcessReportTask 处理竞品报告自动确认任务 +func ProcessReportTask(ctx context.Context, reportUuid string) { + lockKey := fmt.Sprintf(modelCast.AutoConfirmReportLockKey, reportUuid) + reply := cache.RedisClient.SetNX(lockKey, "1", 5*time.Minute) + if !reply.Val() { + zap.L().Warn("竞品报告任务正在被其他实例处理", zap.String("reportUuid", reportUuid)) + return + } + defer func() { + cache.RedisClient.Del(lockKey) + }() + err := autoConfirmReport(ctx, reportUuid) + if err != nil { + zap.L().Error("竞品报告自动确认失败", + zap.String("reportUuid", reportUuid), + zap.Error(err)) + return + } + // 从队列中移除 + err = cache.RedisClient.ZRem(modelCast.AutoConfirmReportQueueKey, reportUuid).Err() + if err != nil { + zap.L().Error("从队列移除竞品报告任务失败", + zap.String("reportUuid", reportUuid), + zap.Error(err)) + } + zap.L().Info("竞品报告自动确认成功", zap.String("reportUuid", reportUuid)) +} + +// autoConfirmReport 自动确认竞品报告 +func autoConfirmReport(ctx context.Context, reportUuid string) (err error) { + var confirmRemark string + var isFailed bool + var usedType uint32 + infoResp, err := service.CastProvider.GetCompetitiveReport(context.Background(), &cast.GetCompetitiveReportDetailReq{ + Uuid: reportUuid, + }) + if err != nil { + zap.L().Error("autoConfirmReport GetCompetitiveReport", zap.Any("err", err)) + confirmRemark = "获取竞品报告详情失败:" + err.Error() + isFailed = true + return + } + if infoResp == nil { + zap.L().Error("autoConfirmReport GetCompetitiveReport返回nil") + return + } + + if infoResp.WorkReportStatus != 4 { // 4是待确认状态 + return + } + userID, _ := strconv.ParseInt(infoResp.ArtistID, 10, 64) + balanceInfoRes, err := service.BundleProvider.GetBundleBalanceByUserId(context.Background(), &bundle.GetBundleBalanceByUserIdReq{ + UserId: int32(userID), + }) + if err != nil { + zap.L().Error("autoConfirmReport GetBundleBalanceByUserId", zap.Any("err", err)) + confirmRemark = "获取余额失败:" + err.Error() + isFailed = true + } + + var addBalanceReq bundle.AddBundleBalanceReq + addBalanceReq.UserId = int32(userID) + // 检查数据分析余量 + if balanceInfoRes.DataAnalysisExtendConsumptionNumber >= balanceInfoRes.DataAnalysisExtendNumber { + confirmRemark = "数据分析余量不足" + isFailed = true + } + addBalanceReq.DataAnalysisConsumptionNumber = 1 + + zap.L().Info("autoConfirmReport AddBundleBalanceReq", zap.Any("addBalanceReq", &addBalanceReq)) + resp, err := service.BundleProvider.AddBundleBalance(context.Background(), &addBalanceReq) + if err != nil { + zap.L().Error("autoConfirmReport AddBundleBalance", zap.Any("err", err)) + confirmRemark = "扣除失败:" + err.Error() + isFailed = true + } + zap.L().Info("autoConfirmReport AddBundleBalanceResp", zap.Any("resp", resp)) + var confirmStatus uint32 = 1 + if isFailed { + usedType = 0 + confirmStatus = 3 + } else { + usedType = resp.UsedType + confirmRemark = "系统自动确认" + confirmStatus = 1 + } + var mm = make(map[string]interface{}, 3) + mm["userid"] = 0 + mm["name"] = "系统自动确定" + mm["phone"] = "" + newCtx := context.WithValue(context.Background(), constant.DubboCtxKey("attachment"), mm) + _, err = service.CastProvider.UpdateCompetitiveReportStatus(newCtx, &cast.UpdateCompetitiveReportStatusReq{ + WorkAction: cast.WorkActionENUM_CONFIRM, + Uuid: reportUuid, + ConfirmRemark: confirmRemark, + CostType: usedType, + ConfirmStatus: confirmStatus, + ConfirmType: 2, + }) + if err != nil { + return + } + return +}