feat: 增加自动审批

This commit is contained in:
cjy 2026-01-12 18:34:56 +08:00
parent a6e5d38a43
commit 09f598a1f4
3 changed files with 226 additions and 0 deletions

View File

@ -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()

View File

@ -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"
)

View File

@ -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
}