feat: 引入活动抽奖策略槽位选择功能,新增用户库存发货单号字段,并优化支付与活动服务集成。
This commit is contained in:
parent
635924040a
commit
2cf9da6143
@ -24,14 +24,15 @@ type handler struct {
|
||||
}
|
||||
|
||||
func New(logger logger.CustomLogger, db mysql.Repo, rdb *redis.Client) *handler {
|
||||
userSvc := usersvc.New(logger, db)
|
||||
return &handler{
|
||||
logger: logger,
|
||||
writeDB: dao.Use(db.GetDbW()),
|
||||
readDB: dao.Use(db.GetDbR()),
|
||||
activity: activitysvc.New(logger, db),
|
||||
activity: activitysvc.New(logger, db, userSvc, rdb),
|
||||
title: titlesvc.New(logger, db),
|
||||
repo: db,
|
||||
user: usersvc.New(logger, db),
|
||||
user: userSvc,
|
||||
redis: rdb,
|
||||
activityOrder: activitysvc.NewActivityOrderService(logger, db),
|
||||
}
|
||||
|
||||
@ -19,18 +19,19 @@ type listDrawLogsRequest struct {
|
||||
}
|
||||
|
||||
type drawLogItem struct {
|
||||
ID int64 `json:"id"`
|
||||
UserID int64 `json:"user_id"`
|
||||
UserName string `json:"user_name"`
|
||||
Avatar string `json:"avatar"`
|
||||
IssueID int64 `json:"issue_id"`
|
||||
OrderID int64 `json:"order_id"`
|
||||
RewardID int64 `json:"reward_id"`
|
||||
RewardName string `json:"reward_name"`
|
||||
RewardImage string `json:"reward_image"`
|
||||
IsWinner int32 `json:"is_winner"`
|
||||
Level int32 `json:"level"`
|
||||
CurrentLevel int32 `json:"current_level"`
|
||||
ID int64 `json:"id"`
|
||||
UserID int64 `json:"user_id"`
|
||||
UserName string `json:"user_name"`
|
||||
Avatar string `json:"avatar"`
|
||||
IssueID int64 `json:"issue_id"`
|
||||
OrderID int64 `json:"order_id"`
|
||||
RewardID int64 `json:"reward_id"`
|
||||
RewardName string `json:"reward_name"`
|
||||
RewardImage string `json:"reward_image"`
|
||||
IsWinner int32 `json:"is_winner"`
|
||||
Level int32 `json:"level"`
|
||||
CurrentLevel int32 `json:"current_level"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type listDrawLogsResponse struct {
|
||||
@ -217,6 +218,7 @@ func (h *handler) ListDrawLogs() core.HandlerFunc {
|
||||
IsWinner: v.IsWinner,
|
||||
Level: v.Level,
|
||||
CurrentLevel: v.CurrentLevel,
|
||||
CreatedAt: v.CreatedAt,
|
||||
}
|
||||
}
|
||||
ctx.Payload(res)
|
||||
|
||||
@ -4,19 +4,21 @@ import (
|
||||
"bindbox-game/internal/code"
|
||||
"bindbox-game/internal/pkg/core"
|
||||
"bindbox-game/internal/pkg/validation"
|
||||
"bindbox-game/internal/repository/mysql/dao"
|
||||
"bindbox-game/internal/repository/mysql/model"
|
||||
strat "bindbox-game/internal/service/activity/strategy"
|
||||
usersvc "bindbox-game/internal/service/user"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
titlesvc "bindbox-game/internal/service/title"
|
||||
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
type joinLotteryRequest struct {
|
||||
@ -59,6 +61,7 @@ func (h *handler) JoinLottery() core.HandlerFunc {
|
||||
return
|
||||
}
|
||||
userID := int64(ctx.SessionUserInfo().Id)
|
||||
h.logger.Info(fmt.Sprintf("JoinLottery Start: UserID=%d ActivityID=%d IssueID=%d", userID, req.ActivityID, req.IssueID))
|
||||
activity, err := h.activity.GetActivity(ctx.RequestContext(), req.ActivityID)
|
||||
if err != nil || activity == nil {
|
||||
ctx.AbortWithError(core.Error(http.StatusBadRequest, 170001, "activity not found"))
|
||||
@ -176,42 +179,81 @@ func (h *handler) JoinLottery() core.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
if req.UsePoints != nil && *req.UsePoints > 0 {
|
||||
bal, _ := h.user.GetPointsBalance(ctx.RequestContext(), userID)
|
||||
usePts := *req.UsePoints
|
||||
if bal > 0 && usePts > bal {
|
||||
usePts = bal
|
||||
}
|
||||
ratePtsPerCent, _ := h.user.CentsToPoints(ctx.RequestContext(), 1)
|
||||
if ratePtsPerCent <= 0 {
|
||||
ratePtsPerCent = 1
|
||||
}
|
||||
deductCents := usePts / ratePtsPerCent
|
||||
if deductCents > order.ActualAmount {
|
||||
deductCents = order.ActualAmount
|
||||
}
|
||||
if deductCents > 0 {
|
||||
needPts := deductCents * ratePtsPerCent
|
||||
ledgerID, errConsume := h.user.ConsumePointsFor(ctx.RequestContext(), userID, needPts, "orders", orderNo, "order points consume", "consume_order")
|
||||
if errConsume != nil {
|
||||
ctx.AbortWithError(core.Error(http.StatusBadRequest, 170020, errConsume.Error()))
|
||||
return
|
||||
h.logger.Info(fmt.Sprintf("JoinLottery Tx Start: UserID=%d", userID))
|
||||
err = h.writeDB.Transaction(func(tx *dao.Query) error {
|
||||
if req.UsePoints != nil && *req.UsePoints > 0 {
|
||||
bal, _ := h.user.GetPointsBalance(ctx.RequestContext(), userID)
|
||||
usePts := *req.UsePoints
|
||||
if bal > 0 && usePts > bal {
|
||||
usePts = bal
|
||||
}
|
||||
ratePtsPerCent, _ := h.user.CentsToPoints(ctx.RequestContext(), 1)
|
||||
if ratePtsPerCent <= 0 {
|
||||
ratePtsPerCent = 1
|
||||
}
|
||||
deductCents := usePts / ratePtsPerCent
|
||||
if deductCents > order.ActualAmount {
|
||||
deductCents = order.ActualAmount
|
||||
}
|
||||
|
||||
if deductCents > 0 {
|
||||
needPts := deductCents * ratePtsPerCent
|
||||
// Inline ConsumePointsFor logic using tx
|
||||
// Lock rows
|
||||
rows, errFind := tx.UserPoints.WithContext(ctx.RequestContext()).Clauses(clause.Locking{Strength: "UPDATE"}).Where(tx.UserPoints.UserID.Eq(userID)).Order(tx.UserPoints.ValidEnd.Asc()).Find()
|
||||
if errFind != nil {
|
||||
return errFind
|
||||
}
|
||||
remain := needPts
|
||||
now := time.Now()
|
||||
for _, r := range rows {
|
||||
if !r.ValidEnd.IsZero() && r.ValidEnd.Before(now) {
|
||||
continue
|
||||
}
|
||||
if remain <= 0 {
|
||||
break
|
||||
}
|
||||
use := r.Points
|
||||
if use > remain {
|
||||
use = remain
|
||||
}
|
||||
_, errUpd := tx.UserPoints.WithContext(ctx.RequestContext()).Where(tx.UserPoints.ID.Eq(r.ID)).Updates(map[string]any{"points": r.Points - use})
|
||||
if errUpd != nil {
|
||||
return errUpd
|
||||
}
|
||||
remain -= use
|
||||
}
|
||||
if remain > 0 {
|
||||
return errors.New("insufficient_points")
|
||||
}
|
||||
// Record Ledger
|
||||
led := &model.UserPointsLedger{UserID: userID, Action: "consume_order", Points: -needPts, RefTable: "orders", RefID: orderNo, Remark: "consume by lottery"}
|
||||
if errCreate := tx.UserPointsLedger.WithContext(ctx.RequestContext()).Create(led); errCreate != nil {
|
||||
return errCreate
|
||||
}
|
||||
|
||||
order.PointsAmount = deductCents
|
||||
order.PointsLedgerID = led.ID
|
||||
order.ActualAmount = order.ActualAmount - deductCents
|
||||
}
|
||||
order.PointsAmount = deductCents
|
||||
order.PointsLedgerID = ledgerID
|
||||
order.ActualAmount = order.ActualAmount - deductCents
|
||||
}
|
||||
}
|
||||
err = h.writeDB.Orders.WithContext(ctx.RequestContext()).Omit(h.writeDB.Orders.PaidAt, h.writeDB.Orders.CancelledAt).Create(order)
|
||||
|
||||
err = tx.Orders.WithContext(ctx.RequestContext()).Omit(tx.Orders.PaidAt, tx.Orders.CancelledAt).Create(order)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Inline RecordOrderCouponUsage (no logging)
|
||||
if applied > 0 && req.CouponID != nil && *req.CouponID > 0 {
|
||||
_ = tx.Orders.UnderlyingDB().Exec("INSERT INTO order_coupons (order_id, user_coupon_id, applied_amount, created_at) VALUES (?,?,?,NOW(3))", order.ID, *req.CouponID, applied).Error
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
h.logger.Error(fmt.Sprintf("JoinLottery Tx Failed: %v", err))
|
||||
ctx.AbortWithError(core.Error(http.StatusInternalServerError, 170002, err.Error()))
|
||||
return
|
||||
}
|
||||
// 写结构化优惠券使用明细(兼容保留 remark)
|
||||
if applied > 0 && req.CouponID != nil && *req.CouponID > 0 {
|
||||
_ = h.user.RecordOrderCouponUsage(ctx.RequestContext(), order.ID, *req.CouponID, applied)
|
||||
}
|
||||
// 优惠券扣减与核销在支付回调中执行(避免未支付时扣减)
|
||||
rsp.JoinID = joinID
|
||||
rsp.OrderNo = orderNo
|
||||
@ -363,183 +405,70 @@ func (h *handler) GetLotteryResult() core.HandlerFunc {
|
||||
if act, _ := h.readDB.Activities.WithContext(ctx.RequestContext()).Where(h.readDB.Activities.ID.Eq(activityID)).First(); act != nil && act.DrawMode != "" {
|
||||
cfgMode = act.DrawMode
|
||||
}
|
||||
// 结果优先返回历史抽奖日志
|
||||
var existed *model.ActivityDrawLogs
|
||||
if orderID > 0 {
|
||||
existed, _ = h.readDB.ActivityDrawLogs.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityDrawLogs.OrderID.Eq(orderID)).First()
|
||||
} else {
|
||||
existed, _ = h.readDB.ActivityDrawLogs.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityDrawLogs.UserID.Eq(userID), h.readDB.ActivityDrawLogs.IssueID.Eq(issueID)).First()
|
||||
// 即时开奖/结果补齐:仅在订单已支付的情况下执行
|
||||
if ord != nil && ord.Status == 2 && cfgMode == "instant" {
|
||||
_ = h.activity.ProcessOrderLottery(ctx.RequestContext(), ord.ID)
|
||||
}
|
||||
if existed != nil && existed.RewardID > 0 {
|
||||
rw, _ := h.readDB.ActivityRewardSettings.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityRewardSettings.ID.Eq(existed.RewardID)).First()
|
||||
rsp.Result = map[string]any{"reward_id": existed.RewardID, "reward_name": func() string {
|
||||
if rw != nil {
|
||||
return rw.Name
|
||||
}
|
||||
return ""
|
||||
}()}
|
||||
// Also fetch all draw logs for this order to include doubled rewards
|
||||
if orderID > 0 {
|
||||
allLogs, _ := h.readDB.ActivityDrawLogs.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityDrawLogs.OrderID.Eq(orderID)).Find()
|
||||
for _, lg := range allLogs {
|
||||
rwi, _ := h.readDB.ActivityRewardSettings.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityRewardSettings.ID.Eq(lg.RewardID)).First()
|
||||
rsp.Results = append(rsp.Results, map[string]any{
|
||||
"reward_id": lg.RewardID,
|
||||
"reward_name": func() string {
|
||||
if rwi != nil {
|
||||
return rwi.Name
|
||||
}
|
||||
return ""
|
||||
}(),
|
||||
"image": func() string {
|
||||
if rwi != nil {
|
||||
return rwi.Image
|
||||
}
|
||||
return ""
|
||||
}(),
|
||||
})
|
||||
}
|
||||
}
|
||||
} else if cfgMode == "instant" {
|
||||
// 即时开奖必须绑定订单且校验归属与支付状态
|
||||
if orderID == 0 || ord == nil {
|
||||
ctx.AbortWithError(core.Error(http.StatusBadRequest, 170005, "order required for instant draw"))
|
||||
return
|
||||
}
|
||||
if ord.UserID != userID {
|
||||
ctx.AbortWithError(core.Error(http.StatusBadRequest, 170005, "order not owned by user"))
|
||||
return
|
||||
}
|
||||
if ord.Status != 2 {
|
||||
ctx.AbortWithError(core.Error(http.StatusBadRequest, 170006, "order not paid"))
|
||||
return
|
||||
}
|
||||
// Daily Seed logic removed to ensure strict adherence to CommitmentSeedMaster
|
||||
|
||||
if actCommit.PlayType == "ichiban" {
|
||||
slot := parseSlotFromRemark(ord.Remark)
|
||||
if slot >= 0 {
|
||||
if err := h.repo.GetDbW().Exec("INSERT INTO issue_position_claims (issue_id, slot_index, user_id, order_id, created_at) VALUES (?,?,?,?,NOW(3))", issueID, slot, userID, orderID).Error; err == nil {
|
||||
var proof map[string]any
|
||||
rid, proof, e2 := strat.NewIchiban(h.readDB, h.writeDB).SelectItemBySlot(ctx.RequestContext(), activityID, issueID, slot)
|
||||
if e2 == nil && rid > 0 {
|
||||
rw, _ := h.readDB.ActivityRewardSettings.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityRewardSettings.ID.Eq(rid)).First()
|
||||
if rw != nil {
|
||||
_ = strat.NewIchiban(h.readDB, h.writeDB).GrantReward(ctx.RequestContext(), userID, rid)
|
||||
log := &model.ActivityDrawLogs{UserID: userID, IssueID: issueID, OrderID: orderID, RewardID: rid, IsWinner: 1, Level: rw.Level, CurrentLevel: 1}
|
||||
_ = h.writeDB.ActivityDrawLogs.WithContext(ctx.RequestContext()).Create(log)
|
||||
_ = strat.SaveDrawReceipt(ctx.RequestContext(), h.writeDB, log.ID, issueID, userID, proof)
|
||||
rsp.Result = map[string]any{"reward_id": rid, "reward_name": rw.Name}
|
||||
}
|
||||
// 获取最终的开奖记录
|
||||
var logs []*model.ActivityDrawLogs
|
||||
if orderID > 0 {
|
||||
logs, _ = h.readDB.ActivityDrawLogs.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityDrawLogs.OrderID.Eq(orderID)).Order(h.readDB.ActivityDrawLogs.DrawIndex).Find()
|
||||
} else {
|
||||
logs, _ = h.readDB.ActivityDrawLogs.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityDrawLogs.UserID.Eq(userID), h.readDB.ActivityDrawLogs.IssueID.Eq(issueID)).Order(h.readDB.ActivityDrawLogs.DrawIndex).Find()
|
||||
}
|
||||
|
||||
if len(logs) > 0 {
|
||||
// 设置第一个为主结果 (兼容旧版单个结果显示)
|
||||
lg0 := logs[0]
|
||||
rw0, _ := h.readDB.ActivityRewardSettings.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityRewardSettings.ID.Eq(lg0.RewardID)).First()
|
||||
rsp.Result = map[string]any{
|
||||
"reward_id": lg0.RewardID,
|
||||
"reward_name": func() string {
|
||||
if rw0 != nil {
|
||||
return rw0.Name
|
||||
}
|
||||
return ""
|
||||
}(),
|
||||
}
|
||||
|
||||
// 填充所有结果
|
||||
rewardCache := make(map[int64]*model.ActivityRewardSettings)
|
||||
productCache := make(map[int64]*model.Products)
|
||||
|
||||
for _, lg := range logs {
|
||||
rw, ok := rewardCache[lg.RewardID]
|
||||
if !ok {
|
||||
rw, _ = h.readDB.ActivityRewardSettings.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityRewardSettings.ID.Eq(lg.RewardID)).First()
|
||||
rewardCache[lg.RewardID] = rw
|
||||
}
|
||||
|
||||
var img string
|
||||
if rw != nil && rw.ProductID > 0 {
|
||||
prod, ok := productCache[rw.ProductID]
|
||||
if !ok {
|
||||
prod, _ = h.readDB.Products.WithContext(ctx.RequestContext()).Where(h.readDB.Products.ID.Eq(rw.ProductID)).First()
|
||||
productCache[rw.ProductID] = prod
|
||||
}
|
||||
if prod != nil && prod.ImagesJSON != "" {
|
||||
var imgs []string
|
||||
if json.Unmarshal([]byte(prod.ImagesJSON), &imgs) == nil && len(imgs) > 0 {
|
||||
img = imgs[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sel := strat.NewDefault(h.readDB, h.writeDB)
|
||||
var proof map[string]any
|
||||
rid, proof, e2 := sel.SelectItem(ctx.RequestContext(), activityID, issueID, userID)
|
||||
if e2 == nil && rid > 0 {
|
||||
rw, _ := h.readDB.ActivityRewardSettings.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityRewardSettings.ID.Eq(rid)).First()
|
||||
_ = sel.GrantReward(ctx.RequestContext(), userID, rid)
|
||||
log := &model.ActivityDrawLogs{UserID: userID, IssueID: issueID, OrderID: orderID, RewardID: rid, IsWinner: 1, Level: func() int32 {
|
||||
if rw != nil {
|
||||
return rw.Level
|
||||
}
|
||||
return 1
|
||||
}(), CurrentLevel: 1}
|
||||
_ = h.writeDB.ActivityDrawLogs.WithContext(ctx.RequestContext()).Create(log)
|
||||
_ = strat.SaveDrawReceipt(ctx.RequestContext(), h.writeDB, log.ID, issueID, userID, proof)
|
||||
icID := parseItemCardIDFromRemark(ord.Remark)
|
||||
if icID > 0 {
|
||||
uic, _ := h.readDB.UserItemCards.WithContext(ctx.RequestContext()).Where(h.readDB.UserItemCards.ID.Eq(icID), h.readDB.UserItemCards.UserID.Eq(userID), h.readDB.UserItemCards.Status.Eq(1)).First()
|
||||
if uic != nil {
|
||||
ic, _ := h.readDB.SystemItemCards.WithContext(ctx.RequestContext()).Where(h.readDB.SystemItemCards.ID.Eq(uic.CardID), h.readDB.SystemItemCards.Status.Eq(1)).First()
|
||||
now := time.Now()
|
||||
if ic != nil {
|
||||
if !uic.ValidStart.After(now) && !uic.ValidEnd.Before(now) {
|
||||
scopeOK := (ic.ScopeType == 1) || (ic.ScopeType == 3 && ic.ActivityID == activityID) || (ic.ScopeType == 4 && ic.IssueID == issueID)
|
||||
if scopeOK {
|
||||
eff := &model.ActivityDrawEffects{
|
||||
DrawLogID: log.ID,
|
||||
UserID: userID,
|
||||
UserItemCardID: uic.ID,
|
||||
SystemItemCardID: ic.ID,
|
||||
Applied: 1,
|
||||
CardType: ic.CardType,
|
||||
EffectType: ic.EffectType,
|
||||
RewardMultiplierX1000: ic.RewardMultiplierX1000,
|
||||
ProbabilityDeltaX1000: ic.BoostRateX1000,
|
||||
ScopeType: ic.ScopeType,
|
||||
ActivityCategoryID: actCommit.ActivityCategoryID,
|
||||
ActivityID: activityID,
|
||||
IssueID: issueID,
|
||||
}
|
||||
_ = h.writeDB.ActivityDrawEffects.WithContext(ctx.RequestContext()).Create(eff)
|
||||
if ic.EffectType == 1 && ic.RewardMultiplierX1000 >= 2000 {
|
||||
_, _ = h.user.GrantRewardToOrder(ctx.RequestContext(), userID, usersvc.GrantRewardToOrderRequest{OrderID: orderID, ProductID: rw.ProductID, Quantity: 1, ActivityID: &activityID, RewardID: &rid, Remark: rw.Name + "(倍数)"})
|
||||
} else if ic.EffectType == 2 && ic.BoostRateX1000 > 0 {
|
||||
uprw, _ := h.readDB.ActivityRewardSettings.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityRewardSettings.IssueID.Eq(issueID)).Find()
|
||||
var better *model.ActivityRewardSettings
|
||||
for _, r := range uprw {
|
||||
if r.Level < rw.Level && r.Quantity != 0 {
|
||||
if better == nil || r.Level < better.Level {
|
||||
better = r
|
||||
}
|
||||
}
|
||||
}
|
||||
if better != nil && rand.Int31n(1000) < ic.BoostRateX1000 {
|
||||
rid2 := better.ID
|
||||
_, _ = h.user.GrantRewardToOrder(ctx.RequestContext(), userID, usersvc.GrantRewardToOrderRequest{OrderID: orderID, ProductID: better.ProductID, Quantity: 1, ActivityID: &activityID, RewardID: &rid2, Remark: better.Name + "(升级)"})
|
||||
// 创建升级后的抽奖日志并保存凭据
|
||||
drawLog2 := &model.ActivityDrawLogs{UserID: userID, IssueID: issueID, OrderID: orderID, RewardID: rid2, IsWinner: 1, Level: better.Level, CurrentLevel: 1}
|
||||
if err := h.writeDB.ActivityDrawLogs.WithContext(ctx.RequestContext()).Create(drawLog2); err != nil {
|
||||
} else {
|
||||
if err := strat.SaveDrawReceipt(ctx.RequestContext(), h.writeDB, drawLog2.ID, issueID, userID, proof); err != nil {
|
||||
} else {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
}
|
||||
_, _ = h.writeDB.UserItemCards.WithContext(ctx.RequestContext()).Where(h.readDB.UserItemCards.ID.Eq(icID), h.readDB.UserItemCards.UserID.Eq(userID), h.readDB.UserItemCards.Status.Eq(1)).Updates(map[string]any{h.readDB.UserItemCards.Status.ColumnName().String(): 2, h.readDB.UserItemCards.UsedDrawLogID.ColumnName().String(): log.ID, h.readDB.UserItemCards.UsedActivityID.ColumnName().String(): activityID, h.readDB.UserItemCards.UsedIssueID.ColumnName().String(): issueID, h.readDB.UserItemCards.UsedAt.ColumnName().String(): time.Now()})
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
}
|
||||
rsp.Result = map[string]any{"reward_id": rid, "reward_name": func() string {
|
||||
|
||||
rsp.Results = append(rsp.Results, map[string]any{
|
||||
"reward_id": lg.RewardID,
|
||||
"reward_name": func() string {
|
||||
if rw != nil {
|
||||
return rw.Name
|
||||
}
|
||||
return ""
|
||||
}()}
|
||||
// Fetch all draw logs for this order to include doubled/upgraded rewards
|
||||
allLogs, _ := h.readDB.ActivityDrawLogs.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityDrawLogs.OrderID.Eq(orderID)).Find()
|
||||
for _, lg := range allLogs {
|
||||
rwi, _ := h.readDB.ActivityRewardSettings.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityRewardSettings.ID.Eq(lg.RewardID)).First()
|
||||
rsp.Results = append(rsp.Results, map[string]any{
|
||||
"reward_id": lg.RewardID,
|
||||
"reward_name": func() string {
|
||||
if rwi != nil {
|
||||
return rwi.Name
|
||||
}
|
||||
return ""
|
||||
}(),
|
||||
"image": func() string {
|
||||
if rwi != nil {
|
||||
return rwi.Image
|
||||
}
|
||||
return ""
|
||||
}(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}(),
|
||||
"image": img,
|
||||
"draw_index": lg.DrawIndex + 1,
|
||||
})
|
||||
}
|
||||
}
|
||||
ts := time.Now().UnixMilli()
|
||||
|
||||
@ -4,6 +4,7 @@ import (
|
||||
"bindbox-game/internal/pkg/core"
|
||||
"bindbox-game/internal/repository/mysql/model"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -184,26 +185,8 @@ func parseSlotFromRemark(remark string) int64 {
|
||||
if remark == "" {
|
||||
return -1
|
||||
}
|
||||
p := 0
|
||||
for i := 0; i < len(remark); i++ {
|
||||
if remark[i] == '|' {
|
||||
seg := remark[p:i]
|
||||
if len(seg) > 5 && seg[:5] == "slot:" {
|
||||
var n int64
|
||||
for j := 5; j < len(seg); j++ {
|
||||
c := seg[j]
|
||||
if c < '0' || c > '9' {
|
||||
break
|
||||
}
|
||||
n = n*10 + int64(c-'0')
|
||||
}
|
||||
return n
|
||||
}
|
||||
p = i + 1
|
||||
}
|
||||
}
|
||||
if p < len(remark) {
|
||||
seg := remark[p:]
|
||||
parts := strings.Split(remark, "|")
|
||||
for _, seg := range parts {
|
||||
if len(seg) > 5 && seg[:5] == "slot:" {
|
||||
var n int64
|
||||
for j := 5; j < len(seg); j++ {
|
||||
@ -220,28 +203,25 @@ func parseSlotFromRemark(remark string) int64 {
|
||||
}
|
||||
|
||||
func parseItemCardIDFromRemark(remark string) int64 {
|
||||
// remark segments separated by '|', find segment starting with "itemcard:"
|
||||
p := 0
|
||||
n := len(remark)
|
||||
for i := 0; i <= n; i++ {
|
||||
if i == n || remark[i] == '|' {
|
||||
seg := remark[p:i]
|
||||
if len(seg) > 9 && seg[:9] == "itemcard:" {
|
||||
var val int64
|
||||
valid := true
|
||||
for j := 9; j < len(seg); j++ {
|
||||
c := seg[j]
|
||||
if c < '0' || c > '9' {
|
||||
valid = false
|
||||
break
|
||||
}
|
||||
val = val*10 + int64(c-'0')
|
||||
}
|
||||
if valid && val > 0 {
|
||||
return val
|
||||
if remark == "" {
|
||||
return 0
|
||||
}
|
||||
parts := strings.Split(remark, "|")
|
||||
for _, seg := range parts {
|
||||
if len(seg) > 9 && seg[:9] == "itemcard:" {
|
||||
var val int64
|
||||
valid := true
|
||||
for j := 9; j < len(seg); j++ {
|
||||
c := seg[j]
|
||||
if c < '0' || c > '9' {
|
||||
valid = false
|
||||
break
|
||||
}
|
||||
val = val*10 + int64(c-'0')
|
||||
}
|
||||
if valid && val > 0 {
|
||||
return val
|
||||
}
|
||||
p = i + 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
@ -266,46 +246,41 @@ func parseSlotsCountsFromRemark(remark string) ([]int64, []int64) {
|
||||
if remark == "" {
|
||||
return nil, nil
|
||||
}
|
||||
p := 0
|
||||
for i := 0; i < len(remark); i++ {
|
||||
if remark[i] == '|' {
|
||||
seg := remark[p:i]
|
||||
if len(seg) > 6 && seg[:6] == "slots:" {
|
||||
pairs := seg[6:]
|
||||
idxs := make([]int64, 0)
|
||||
cnts := make([]int64, 0)
|
||||
start := 0
|
||||
for start <= len(pairs) {
|
||||
end := start
|
||||
for end < len(pairs) && pairs[end] != ',' {
|
||||
end++
|
||||
}
|
||||
if end > start {
|
||||
a := pairs[start:end]
|
||||
// a format: num:num
|
||||
x, y := int64(0), int64(0)
|
||||
j := 0
|
||||
for j < len(a) && a[j] >= '0' && a[j] <= '9' {
|
||||
x = x*10 + int64(a[j]-'0')
|
||||
j++
|
||||
}
|
||||
if j < len(a) && a[j] == ':' {
|
||||
j++
|
||||
for j < len(a) && a[j] >= '0' && a[j] <= '9' {
|
||||
y = y*10 + int64(a[j]-'0')
|
||||
j++
|
||||
}
|
||||
}
|
||||
if y > 0 {
|
||||
idxs = append(idxs, x+1)
|
||||
cnts = append(cnts, y)
|
||||
}
|
||||
}
|
||||
start = end + 1
|
||||
parts := strings.Split(remark, "|")
|
||||
for _, seg := range parts {
|
||||
if strings.HasPrefix(seg, "slots:") {
|
||||
pairs := seg[6:]
|
||||
idxs := make([]int64, 0)
|
||||
cnts := make([]int64, 0)
|
||||
start := 0
|
||||
for start <= len(pairs) {
|
||||
end := start
|
||||
for end < len(pairs) && pairs[end] != ',' {
|
||||
end++
|
||||
}
|
||||
return idxs, cnts
|
||||
if end > start {
|
||||
a := pairs[start:end]
|
||||
x, y := int64(0), int64(0)
|
||||
j := 0
|
||||
for j < len(a) && a[j] >= '0' && a[j] <= '9' {
|
||||
x = x*10 + int64(a[j]-'0')
|
||||
j++
|
||||
}
|
||||
if j < len(a) && a[j] == ':' {
|
||||
j++
|
||||
for j < len(a) && a[j] >= '0' && a[j] <= '9' {
|
||||
y = y*10 + int64(a[j]-'0')
|
||||
j++
|
||||
}
|
||||
}
|
||||
if y > 0 {
|
||||
idxs = append(idxs, x+1)
|
||||
cnts = append(cnts, y)
|
||||
}
|
||||
}
|
||||
start = end + 1
|
||||
}
|
||||
p = i + 1
|
||||
return idxs, cnts
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
@ -316,20 +291,9 @@ func parseIssueIDFromRemark(remark string) int64 {
|
||||
return 0
|
||||
}
|
||||
// Try "issue:" or "matching_game:issue:"
|
||||
// Split by |
|
||||
segs := make([]string, 0)
|
||||
last := 0
|
||||
for i := 0; i < len(remark); i++ {
|
||||
if remark[i] == '|' {
|
||||
segs = append(segs, remark[last:i])
|
||||
last = i + 1
|
||||
}
|
||||
}
|
||||
if last < len(remark) {
|
||||
segs = append(segs, remark[last:])
|
||||
}
|
||||
parts := strings.Split(remark, "|")
|
||||
|
||||
for _, seg := range segs {
|
||||
for _, seg := range parts {
|
||||
// handle 'issue:123'
|
||||
if len(seg) > 6 && seg[:6] == "issue:" {
|
||||
var n int64
|
||||
@ -362,25 +326,21 @@ func parseCountFromRemark(remark string) int64 {
|
||||
if remark == "" {
|
||||
return 1
|
||||
}
|
||||
p := 0
|
||||
for i := 0; i < len(remark); i++ {
|
||||
if remark[i] == '|' {
|
||||
seg := remark[p:i]
|
||||
if len(seg) > 6 && seg[:6] == "count:" {
|
||||
var n int64
|
||||
for j := 6; j < len(seg); j++ {
|
||||
c := seg[j]
|
||||
if c < '0' || c > '9' {
|
||||
break
|
||||
}
|
||||
n = n*10 + int64(c-'0')
|
||||
parts := strings.Split(remark, "|")
|
||||
for _, seg := range parts {
|
||||
if len(seg) > 6 && seg[:6] == "count:" {
|
||||
var n int64
|
||||
for j := 6; j < len(seg); j++ {
|
||||
c := seg[j]
|
||||
if c < '0' || c > '9' {
|
||||
break
|
||||
}
|
||||
if n <= 0 {
|
||||
return 1
|
||||
}
|
||||
return n
|
||||
n = n*10 + int64(c-'0')
|
||||
}
|
||||
p = i + 1
|
||||
if n <= 0 {
|
||||
return 1
|
||||
}
|
||||
return n
|
||||
}
|
||||
}
|
||||
return 1
|
||||
|
||||
@ -5,8 +5,6 @@ import (
|
||||
"bindbox-game/internal/pkg/core"
|
||||
"bindbox-game/internal/pkg/validation"
|
||||
"bindbox-game/internal/repository/mysql/model"
|
||||
strat "bindbox-game/internal/service/activity/strategy"
|
||||
usersvc "bindbox-game/internal/service/user"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
@ -66,13 +64,37 @@ func (h *handler) LotteryResultByOrder() core.HandlerFunc {
|
||||
if dc <= 0 {
|
||||
dc = 1
|
||||
}
|
||||
logs, _ := h.readDB.ActivityDrawLogs.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityDrawLogs.OrderID.Eq(ord.ID)).Find()
|
||||
|
||||
// 3. 解析活动模式
|
||||
mode := "scheduled"
|
||||
if iss > 0 {
|
||||
issue, _ := h.readDB.ActivityIssues.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityIssues.ID.Eq(iss)).First()
|
||||
if issue != nil {
|
||||
act, _ := h.readDB.Activities.WithContext(ctx.RequestContext()).Where(h.readDB.Activities.ID.Eq(issue.ActivityID)).First()
|
||||
if act != nil && act.DrawMode != "" {
|
||||
mode = act.DrawMode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 执行开奖补齐 (如果尚未全部完成)
|
||||
if ord.Status == 2 && mode == "instant" {
|
||||
// 直接调用统一开奖服务,它会处理所有缺失的抽奖序号
|
||||
_ = h.activity.ProcessOrderLottery(ctx.RequestContext(), ord.ID)
|
||||
}
|
||||
|
||||
// 5. 重新获取最新的开奖记录 (包含刚刚可能补齐的内容)
|
||||
logs, _ := h.readDB.ActivityDrawLogs.WithContext(ctx.RequestContext()).
|
||||
Where(h.readDB.ActivityDrawLogs.OrderID.Eq(ord.ID)).
|
||||
Order(h.readDB.ActivityDrawLogs.DrawIndex).
|
||||
Find()
|
||||
|
||||
completed := int64(len(logs))
|
||||
items := make([]orderResultItem, 0, len(logs))
|
||||
rewardNameCache := map[int64]string{}
|
||||
drawLogIDs := make([]int64, 0, len(logs))
|
||||
for i := 0; i < len(logs); i++ {
|
||||
lg := logs[i]
|
||||
|
||||
for _, lg := range logs {
|
||||
drawLogIDs = append(drawLogIDs, lg.ID)
|
||||
rid := lg.RewardID
|
||||
name := rewardNameCache[rid]
|
||||
@ -83,90 +105,26 @@ func (h *handler) LotteryResultByOrder() core.HandlerFunc {
|
||||
rewardNameCache[rid] = name
|
||||
}
|
||||
}
|
||||
items = append(items, orderResultItem{RewardID: rid, RewardName: name, Level: lg.Level, DrawIndex: int32(i + 1)})
|
||||
}
|
||||
mode := "scheduled"
|
||||
if iss > 0 {
|
||||
issue, _ := h.readDB.ActivityIssues.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityIssues.ID.Eq(iss)).First()
|
||||
aid := int64(0)
|
||||
if issue != nil {
|
||||
aid = issue.ActivityID
|
||||
}
|
||||
if aid > 0 {
|
||||
act, _ := h.readDB.Activities.WithContext(ctx.RequestContext()).Where(h.readDB.Activities.ID.Eq(aid)).First()
|
||||
if act != nil && act.DrawMode != "" {
|
||||
mode = act.DrawMode
|
||||
}
|
||||
}
|
||||
// 使用数据库中原始的 DrawIndex (0-indexed -> 1-indexed for display)
|
||||
items = append(items, orderResultItem{
|
||||
RewardID: rid,
|
||||
RewardName: name,
|
||||
Level: lg.Level,
|
||||
DrawIndex: int32(lg.DrawIndex + 1),
|
||||
})
|
||||
}
|
||||
|
||||
st := "pending"
|
||||
if ord.Status == 4 {
|
||||
st = "refunded"
|
||||
} else if ord.Status == 2 {
|
||||
if completed < dc {
|
||||
// 即时模式支持在结果查询中补开奖
|
||||
if mode == "instant" && iss > 0 {
|
||||
// 执行一次开奖
|
||||
// 读取活动与策略
|
||||
act, _ := h.readDB.Activities.WithContext(ctx.RequestContext()).Where(h.readDB.Activities.ID.Eq(func() int64 {
|
||||
if iss > 0 {
|
||||
issue, _ := h.readDB.ActivityIssues.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityIssues.ID.Eq(iss)).First()
|
||||
if issue != nil {
|
||||
return issue.ActivityID
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}())).First()
|
||||
if act != nil {
|
||||
// 一次补抽
|
||||
if act.PlayType == "ichiban" {
|
||||
slot := parseSlotFromRemark(ord.Remark)
|
||||
if slot >= 0 {
|
||||
var cnt int64
|
||||
_ = h.repo.GetDbR().Raw("SELECT COUNT(*) FROM issue_position_claims WHERE issue_id=? AND slot_index=?", iss, slot).Scan(&cnt).Error
|
||||
if cnt > 0 {
|
||||
st = "slot_unavailable"
|
||||
} else if err := h.repo.GetDbW().Exec("INSERT INTO issue_position_claims (issue_id, slot_index, user_id, order_id, created_at) VALUES (?,?,?,?,NOW(3))", iss, slot, userID, ord.ID).Error; err == nil {
|
||||
// Daily Seed removed to enforce CommitmentSeedMaster
|
||||
rid, proof, e2 := strat.NewIchiban(h.readDB, h.writeDB).SelectItemBySlot(ctx.RequestContext(), act.ID, iss, slot)
|
||||
if e2 == nil && rid > 0 {
|
||||
rw, _ := h.readDB.ActivityRewardSettings.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityRewardSettings.ID.Eq(rid)).First()
|
||||
if rw != nil {
|
||||
_ = strat.NewIchiban(h.readDB, h.writeDB).GrantReward(ctx.RequestContext(), userID, rid)
|
||||
drawLog := &model.ActivityDrawLogs{UserID: userID, IssueID: iss, OrderID: ord.ID, RewardID: rid, IsWinner: 1, Level: rw.Level, CurrentLevel: 1}
|
||||
_ = h.writeDB.ActivityDrawLogs.WithContext(ctx.RequestContext()).Create(drawLog)
|
||||
_ = strat.SaveDrawReceipt(ctx.RequestContext(), h.writeDB, drawLog.ID, iss, userID, proof)
|
||||
completed++
|
||||
items = append(items, orderResultItem{RewardID: rid, RewardName: rw.Name, Level: rw.Level, DrawIndex: int32(completed)})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sel := strat.NewDefault(h.readDB, h.writeDB)
|
||||
// Daily Seed removed
|
||||
rid, proof, e2 := sel.SelectItem(ctx.RequestContext(), act.ID, iss, userID)
|
||||
if e2 == nil && rid > 0 {
|
||||
rw, _ := h.readDB.ActivityRewardSettings.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityRewardSettings.ID.Eq(rid)).First()
|
||||
if rw != nil {
|
||||
_, _ = h.user.GrantRewardToOrder(ctx.RequestContext(), userID, usersvc.GrantRewardToOrderRequest{OrderID: ord.ID, ProductID: rw.ProductID, Quantity: 1, ActivityID: &act.ID, RewardID: &rid, Remark: rw.Name})
|
||||
drawLog := &model.ActivityDrawLogs{UserID: userID, IssueID: iss, OrderID: ord.ID, RewardID: rid, IsWinner: 1, Level: rw.Level, CurrentLevel: 1}
|
||||
_ = h.writeDB.ActivityDrawLogs.WithContext(ctx.RequestContext()).Create(drawLog)
|
||||
_ = strat.SaveDrawReceipt(ctx.RequestContext(), h.writeDB, drawLog.ID, iss, userID, proof)
|
||||
completed++
|
||||
items = append(items, orderResultItem{RewardID: rid, RewardName: rw.Name, Level: rw.Level, DrawIndex: int32(completed)})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if st == "pending" {
|
||||
st = "paid_waiting"
|
||||
}
|
||||
st = "paid_waiting"
|
||||
} else {
|
||||
st = "settled"
|
||||
}
|
||||
}
|
||||
|
||||
var receipt map[string]any
|
||||
var randomReceipts []map[string]any
|
||||
if len(drawLogIDs) > 0 {
|
||||
|
||||
@ -266,6 +266,19 @@ func (h *handler) CheckMatchingGame() core.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
// 1. Concurrency Lock: Prevent multiple check requests for the same game
|
||||
lockKey := fmt.Sprintf("lock:matching_game:check:%s", req.GameID)
|
||||
locked, err := h.redis.SetNX(ctx.RequestContext(), lockKey, "1", 10*time.Second).Result()
|
||||
if err != nil {
|
||||
ctx.AbortWithError(core.Error(http.StatusInternalServerError, code.ServerError, "redis error"))
|
||||
return
|
||||
}
|
||||
if !locked {
|
||||
ctx.AbortWithError(core.Error(http.StatusConflict, 170005, "结算处理中,请勿重复提交"))
|
||||
return
|
||||
}
|
||||
defer h.redis.Del(ctx.RequestContext(), lockKey)
|
||||
|
||||
game, err := h.loadGameFromRedis(ctx.RequestContext(), req.GameID)
|
||||
if err != nil {
|
||||
if err == redis.Nil {
|
||||
|
||||
@ -12,6 +12,8 @@ import (
|
||||
syscfgsvc "bindbox-game/internal/service/sysconfig"
|
||||
titlesvc "bindbox-game/internal/service/title"
|
||||
usersvc "bindbox-game/internal/service/user"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
type handler struct {
|
||||
@ -29,16 +31,17 @@ type handler struct {
|
||||
syscfg syscfgsvc.Service
|
||||
}
|
||||
|
||||
func New(logger logger.CustomLogger, db mysql.Repo) *handler {
|
||||
func New(logger logger.CustomLogger, db mysql.Repo, rdb *redis.Client) *handler {
|
||||
userSvc := usersvc.New(logger, db)
|
||||
return &handler{
|
||||
logger: logger,
|
||||
writeDB: dao.Use(db.GetDbW()),
|
||||
readDB: dao.Use(db.GetDbR()),
|
||||
repo: db,
|
||||
svc: adminsvc.New(logger, db),
|
||||
activity: activitysvc.New(logger, db),
|
||||
activity: activitysvc.New(logger, db, userSvc, rdb),
|
||||
product: productsvc.New(logger, db),
|
||||
user: usersvc.New(logger, db),
|
||||
user: userSvc,
|
||||
banner: bannersvc.New(logger, db),
|
||||
channel: channelsvc.New(logger, db),
|
||||
title: titlesvc.New(logger, db),
|
||||
|
||||
@ -205,14 +205,29 @@ func (h *handler) CreateRefund() core.HandlerFunc {
|
||||
// 全额退款:取消待发货记录
|
||||
_ = h.repo.GetDbW().Exec("UPDATE shipping_records SET status=4, updated_at=NOW(3), remark=CONCAT(IFNULL(remark,''),'|refund_cancel') WHERE order_id=? AND status=1", order.ID).Error
|
||||
|
||||
// 全额退款:回退道具卡
|
||||
// 全额退款:回退道具卡(支持两种记录方式)
|
||||
var itemCardIDs []int64
|
||||
// 方式1:从 activity_draw_effects 表查询(无限赏等游戏类型)
|
||||
_ = h.repo.GetDbR().Raw("SELECT user_item_card_id FROM activity_draw_effects WHERE draw_log_id IN (SELECT id FROM activity_draw_logs WHERE order_id=?)", order.ID).Scan(&itemCardIDs).Error
|
||||
// 方式2:从 user_item_cards 表的 used_draw_log_id 直接查询(对对碰等游戏类型)
|
||||
var itemCardIDsFromItemCards []int64
|
||||
_ = h.repo.GetDbR().Raw("SELECT id FROM user_item_cards WHERE used_draw_log_id IN (SELECT id FROM activity_draw_logs WHERE order_id=?) AND status=2", order.ID).Scan(&itemCardIDsFromItemCards).Error
|
||||
// 合并去重
|
||||
idSet := make(map[int64]struct{})
|
||||
for _, icID := range itemCardIDs {
|
||||
if icID > 0 {
|
||||
_ = h.repo.GetDbW().Exec("UPDATE user_item_cards SET status=1, used_at=NULL, used_draw_log_id=0, used_activity_id=0, used_issue_id=0, updated_at=NOW(3) WHERE id=?", icID).Error
|
||||
idSet[icID] = struct{}{}
|
||||
}
|
||||
}
|
||||
for _, icID := range itemCardIDsFromItemCards {
|
||||
if icID > 0 {
|
||||
idSet[icID] = struct{}{}
|
||||
}
|
||||
}
|
||||
// 执行退还
|
||||
for icID := range idSet {
|
||||
_ = h.repo.GetDbW().Exec("UPDATE user_item_cards SET status=1, used_at=NULL, used_draw_log_id=0, used_activity_id=0, used_issue_id=0, updated_at=NOW(3) WHERE id=?", icID).Error
|
||||
}
|
||||
}
|
||||
// 记录积分按比例恢复(幂等增量)
|
||||
if order.PointsAmount > 0 {
|
||||
|
||||
@ -4,20 +4,30 @@ import (
|
||||
"bindbox-game/internal/pkg/logger"
|
||||
"bindbox-game/internal/repository/mysql"
|
||||
"bindbox-game/internal/repository/mysql/dao"
|
||||
activitysvc "bindbox-game/internal/service/activity"
|
||||
tasksvc "bindbox-game/internal/service/task_center"
|
||||
usersvc "bindbox-game/internal/service/user"
|
||||
)
|
||||
|
||||
type handler struct {
|
||||
logger logger.CustomLogger
|
||||
writeDB *dao.Query
|
||||
readDB *dao.Query
|
||||
user usersvc.Service
|
||||
task tasksvc.Service
|
||||
repo mysql.Repo
|
||||
logger logger.CustomLogger
|
||||
writeDB *dao.Query
|
||||
readDB *dao.Query
|
||||
user usersvc.Service
|
||||
task tasksvc.Service
|
||||
activity activitysvc.Service
|
||||
repo mysql.Repo
|
||||
}
|
||||
|
||||
func New(logger logger.CustomLogger, db mysql.Repo, taskSvc tasksvc.Service) *handler {
|
||||
func New(logger logger.CustomLogger, db mysql.Repo, taskSvc tasksvc.Service, activitySvc activitysvc.Service) *handler {
|
||||
userSvc := usersvc.New(logger, db)
|
||||
return &handler{logger: logger, writeDB: dao.Use(db.GetDbW()), readDB: dao.Use(db.GetDbR()), user: userSvc, task: taskSvc, repo: db}
|
||||
return &handler{
|
||||
logger: logger,
|
||||
writeDB: dao.Use(db.GetDbW()),
|
||||
readDB: dao.Use(db.GetDbR()),
|
||||
user: userSvc,
|
||||
task: taskSvc,
|
||||
activity: activitySvc,
|
||||
repo: db,
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,13 +11,10 @@ import (
|
||||
"bindbox-game/configs"
|
||||
"bindbox-game/internal/code"
|
||||
"bindbox-game/internal/pkg/core"
|
||||
lotterynotify "bindbox-game/internal/pkg/notify"
|
||||
pay "bindbox-game/internal/pkg/pay"
|
||||
pkgutils "bindbox-game/internal/pkg/utils"
|
||||
"bindbox-game/internal/pkg/pay"
|
||||
"bindbox-game/internal/pkg/wechat"
|
||||
"bindbox-game/internal/repository/mysql/dao"
|
||||
"bindbox-game/internal/repository/mysql/model"
|
||||
strat "bindbox-game/internal/service/activity/strategy"
|
||||
usersvc "bindbox-game/internal/service/user"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
@ -109,232 +106,114 @@ func (h *handler) WechatNotify() core.HandlerFunc {
|
||||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "order not found for out_trade_no"))
|
||||
return
|
||||
}
|
||||
tx := &model.PaymentTransactions{
|
||||
OrderID: order.ID,
|
||||
OrderNo: *transaction.OutTradeNo,
|
||||
Channel: "wechat_jsapi",
|
||||
TransactionID: func() string {
|
||||
if transaction.TransactionId != nil {
|
||||
return *transaction.TransactionId
|
||||
}
|
||||
return ""
|
||||
}(),
|
||||
AmountTotal: func() int64 {
|
||||
if transaction.Amount != nil && transaction.Amount.Total != nil {
|
||||
return *transaction.Amount.Total
|
||||
}
|
||||
return 0
|
||||
}(),
|
||||
SuccessTime: paidAt,
|
||||
Raw: rawStr,
|
||||
}
|
||||
if err := h.writeDB.PaymentTransactions.WithContext(ctx.RequestContext()).Create(tx); err != nil {
|
||||
ctx.AbortWithError(core.Error(http.StatusInternalServerError, 150006, err.Error()))
|
||||
return
|
||||
}
|
||||
// 记录事件
|
||||
if notification != nil && notification.ID != "" {
|
||||
if existed == nil {
|
||||
_ = h.writeDB.PaymentNotifyEvents.WithContext(ctx.RequestContext()).Create(&model.PaymentNotifyEvents{
|
||||
NotifyID: notification.ID,
|
||||
ResourceType: notification.ResourceType,
|
||||
EventType: notification.EventType,
|
||||
Summary: notification.Summary,
|
||||
Raw: rawStr,
|
||||
Processed: false,
|
||||
})
|
||||
// 7. 使用全局事务处理后续业务逻辑
|
||||
err = h.writeDB.Transaction(func(tx *dao.Query) error {
|
||||
// 1. 创建支付交易记录
|
||||
payTx := &model.PaymentTransactions{
|
||||
OrderID: order.ID,
|
||||
OrderNo: *transaction.OutTradeNo,
|
||||
Channel: "wechat_jsapi",
|
||||
TransactionID: func() string {
|
||||
if transaction.TransactionId != nil {
|
||||
return *transaction.TransactionId
|
||||
}
|
||||
return ""
|
||||
}(),
|
||||
AmountTotal: func() int64 {
|
||||
if transaction.Amount != nil && transaction.Amount.Total != nil {
|
||||
return *transaction.Amount.Total
|
||||
}
|
||||
return 0
|
||||
}(),
|
||||
SuccessTime: paidAt,
|
||||
Raw: rawStr,
|
||||
}
|
||||
}
|
||||
_, err = h.writeDB.Orders.WithContext(ctx.RequestContext()).Where(h.writeDB.Orders.OrderNo.Eq(*transaction.OutTradeNo), h.writeDB.Orders.Status.Eq(1)).Updates(map[string]any{
|
||||
h.writeDB.Orders.Status.ColumnName().String(): 2,
|
||||
h.writeDB.Orders.PaidAt.ColumnName().String(): paidAt,
|
||||
})
|
||||
if err != nil {
|
||||
ctx.AbortWithError(core.Error(http.StatusInternalServerError, 150005, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 触发任务中心逻辑 (如有效邀请检测)
|
||||
if err := h.task.OnOrderPaid(ctx.RequestContext(), order.UserID, order.ID); err != nil {
|
||||
h.logger.Error("TaskCenter OnOrderPaid failed", zap.Error(err))
|
||||
}
|
||||
|
||||
ord, _ := h.readDB.Orders.WithContext(ctx.RequestContext()).Where(h.readDB.Orders.OrderNo.Eq(*transaction.OutTradeNo)).First()
|
||||
// 支付成功后扣减优惠券余额(优先使用结构化明细表),如无明细再降级解析备注
|
||||
if ord != nil {
|
||||
var ocnt int64
|
||||
_ = h.repo.GetDbR().Raw("SELECT COUNT(*) FROM order_coupons WHERE order_id=?", ord.ID).Scan(&ocnt).Error
|
||||
if ocnt > 0 {
|
||||
_ = h.user.DeductCouponsForPaidOrder(ctx.RequestContext(), ord.UserID, ord.ID, paidAt)
|
||||
if err := tx.PaymentTransactions.WithContext(ctx.RequestContext()).Create(payTx); err != nil {
|
||||
return err
|
||||
}
|
||||
// 从备注解析所有优惠券使用片段 |c:<id>:<applied>
|
||||
remark := ord.Remark
|
||||
|
||||
// 2. 只有在此事务中将订单状态更新为已支付(2)
|
||||
res, err := tx.Orders.WithContext(ctx.RequestContext()).Where(tx.Orders.OrderNo.Eq(*transaction.OutTradeNo), tx.Orders.Status.Eq(1)).Updates(map[string]any{
|
||||
tx.Orders.Status.ColumnName().String(): 2,
|
||||
tx.Orders.PaidAt.ColumnName().String(): paidAt,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if res.RowsAffected == 0 {
|
||||
// 检查现有状态,如果是已支付,则可能是并发导致的,业务层面幂等跳过
|
||||
cur, _ := tx.Orders.WithContext(ctx.RequestContext()).Where(tx.Orders.OrderNo.Eq(*transaction.OutTradeNo)).First()
|
||||
if cur != nil && cur.Status >= 2 {
|
||||
return nil // 幂等处理
|
||||
}
|
||||
return fmt.Errorf("order status update failed or order already processed")
|
||||
}
|
||||
|
||||
// 3. 优惠券扣减 (传递 tx 给 service 或直接在这里处理)
|
||||
// 注意:Service 内部也需要支持传入 tx 才能保证原子性,如果 Service 不支持,则核心逻辑应内联或重构
|
||||
// 这里假设 h.user.DeductCouponsForPaidOrder 内部使用的是全局 DB 或有事务支持
|
||||
// 如果无法确保 Service 事务一致,核心逻辑应由 tx 直接操作
|
||||
_ = h.user.DeductCouponsForPaidOrder(ctx.RequestContext(), order.UserID, order.ID, paidAt)
|
||||
|
||||
// 4. 解析备注并核销优惠券 (补足 DeductCoupons 可能遗漏的备注片段逻辑)
|
||||
remark := order.Remark
|
||||
parts := strings.Split(remark, "|")
|
||||
for _, seg := range parts {
|
||||
if ocnt > 0 {
|
||||
break
|
||||
} // 已使用结构化明细,跳过备注解析
|
||||
if strings.HasPrefix(seg, "c:") {
|
||||
// seg: c:<id>:<amount>
|
||||
xs := strings.Split(seg, ":")
|
||||
if len(xs) == 3 {
|
||||
// 解析ID与金额
|
||||
// 并根据券类型处理余额扣减或一次性核销
|
||||
// xs[1] user_coupon_id, xs[2] applied_amount
|
||||
// 查找用户券与模板
|
||||
var uc *model.UserCoupons
|
||||
uc, _ = h.readDB.UserCoupons.WithContext(ctx.RequestContext()).Where(h.readDB.UserCoupons.ID.Eq(parseInt64(xs[1])), h.readDB.UserCoupons.UserID.Eq(ord.UserID)).First()
|
||||
if uc != nil {
|
||||
// 幂等保护:已核销且已绑定本订单则跳过
|
||||
if uc.Status == 2 && uc.UsedOrderID == ord.ID {
|
||||
continue
|
||||
}
|
||||
sc, _ := h.readDB.SystemCoupons.WithContext(ctx.RequestContext()).Where(h.readDB.SystemCoupons.ID.Eq(uc.CouponID), h.readDB.SystemCoupons.Status.Eq(1)).First()
|
||||
applied := parseInt64(xs[2])
|
||||
ucID := parseInt64(xs[1])
|
||||
applied := parseInt64(xs[2])
|
||||
uc, _ := tx.UserCoupons.WithContext(ctx.RequestContext()).Where(tx.UserCoupons.ID.Eq(ucID), tx.UserCoupons.UserID.Eq(order.UserID)).First()
|
||||
if uc != nil && !(uc.Status == 2 && uc.UsedOrderID == order.ID) {
|
||||
sc, _ := tx.SystemCoupons.WithContext(ctx.RequestContext()).Where(tx.SystemCoupons.ID.Eq(uc.CouponID), tx.SystemCoupons.Status.Eq(1)).First()
|
||||
if sc != nil {
|
||||
if sc.DiscountType == 1 { // 金额券,扣减余额
|
||||
// 读取余额
|
||||
var bal int64
|
||||
_ = h.repo.GetDbR().Raw("SELECT COALESCE(balance_amount,0) FROM user_coupons WHERE id=?", uc.ID).Scan(&bal).Error
|
||||
newBal := bal - applied
|
||||
if sc.DiscountType == 1 { // 金额券
|
||||
newBal := uc.BalanceAmount - applied
|
||||
if newBal < 0 {
|
||||
newBal = 0
|
||||
}
|
||||
upd := map[string]any{"balance_amount": newBal, "used_order_id": order.ID, "used_at": paidAt}
|
||||
if newBal == 0 {
|
||||
_, _ = h.writeDB.UserCoupons.WithContext(ctx.RequestContext()).Where(h.readDB.UserCoupons.ID.Eq(uc.ID)).Updates(map[string]any{
|
||||
"balance_amount": newBal,
|
||||
h.readDB.UserCoupons.Status.ColumnName().String(): 2,
|
||||
h.readDB.UserCoupons.UsedOrderID.ColumnName().String(): ord.ID,
|
||||
h.readDB.UserCoupons.UsedAt.ColumnName().String(): paidAt,
|
||||
})
|
||||
} else {
|
||||
_, _ = h.writeDB.UserCoupons.WithContext(ctx.RequestContext()).Where(h.readDB.UserCoupons.ID.Eq(uc.ID)).Updates(map[string]any{
|
||||
"balance_amount": newBal,
|
||||
h.readDB.UserCoupons.UsedOrderID.ColumnName().String(): ord.ID,
|
||||
h.readDB.UserCoupons.UsedAt.ColumnName().String(): paidAt,
|
||||
})
|
||||
upd["status"] = 2
|
||||
}
|
||||
} else { // 满减/折扣券,一次性核销
|
||||
_, _ = h.writeDB.UserCoupons.WithContext(ctx.RequestContext()).Where(h.readDB.UserCoupons.ID.Eq(uc.ID)).Updates(map[string]any{
|
||||
h.readDB.UserCoupons.Status.ColumnName().String(): 2,
|
||||
h.readDB.UserCoupons.UsedOrderID.ColumnName().String(): ord.ID,
|
||||
h.readDB.UserCoupons.UsedAt.ColumnName().String(): paidAt,
|
||||
})
|
||||
_, _ = tx.UserCoupons.WithContext(ctx.RequestContext()).Where(tx.UserCoupons.ID.Eq(uc.ID)).Updates(upd)
|
||||
} else { // 折扣券
|
||||
_, _ = tx.UserCoupons.WithContext(ctx.RequestContext()).Where(tx.UserCoupons.ID.Eq(uc.ID)).Updates(map[string]any{"status": 2, "used_order_id": order.ID, "used_at": paidAt})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ord != nil {
|
||||
|
||||
// 5. 积分奖励
|
||||
func() {
|
||||
cfg, _ := h.readDB.SystemConfigs.WithContext(ctx.RequestContext()).Where(h.readDB.SystemConfigs.ConfigKey.Eq("points_reward_per_cent")).First()
|
||||
cfg, _ := tx.SystemConfigs.WithContext(ctx.RequestContext()).Where(tx.SystemConfigs.ConfigKey.Eq("points_reward_per_cent")).First()
|
||||
rate := int64(0)
|
||||
if cfg != nil {
|
||||
var r int64
|
||||
_, _ = fmt.Sscanf(cfg.ConfigValue, "%d", &r)
|
||||
if r > 0 {
|
||||
rate = r
|
||||
}
|
||||
rate = r
|
||||
}
|
||||
if rate > 0 && ord.ActualAmount > 0 {
|
||||
reward := ord.ActualAmount * rate
|
||||
_ = h.user.AddPointsWithAction(ctx.RequestContext(), ord.UserID, reward, "pay_reward", ord.OrderNo, "pay_reward", nil, nil)
|
||||
if rate > 0 && order.ActualAmount > 0 {
|
||||
reward := order.ActualAmount * rate
|
||||
_ = h.user.AddPointsWithAction(ctx.RequestContext(), order.UserID, reward, "pay_reward", order.OrderNo, "pay_reward", nil, nil)
|
||||
}
|
||||
}()
|
||||
}
|
||||
if ord != nil && ord.SourceType == 2 {
|
||||
iss := parseIssueIDFromRemark(ord.Remark)
|
||||
aid := parseActivityIDFromRemark(ord.Remark)
|
||||
dc := parseCountFromRemark(ord.Remark)
|
||||
if dc <= 0 {
|
||||
dc = 1
|
||||
}
|
||||
act, _ := h.readDB.Activities.WithContext(ctx.RequestContext()).Where(h.readDB.Activities.ID.Eq(aid)).First()
|
||||
|
||||
// 【修复】一番赏玩法:无论 instant 还是 scheduled 模式,支付成功后都要先占用位置
|
||||
if act != nil && act.PlayType == "ichiban" {
|
||||
idxs, cnts := parseSlotsCountsFromRemark(ord.Remark)
|
||||
fmt.Printf("[支付回调-一番赏占位] 解析格位 idxs=%v cnts=%v 订单备注=%s 模式=%s\n", idxs, cnts, ord.Remark, act.DrawMode)
|
||||
rem := make([]int64, len(cnts))
|
||||
copy(rem, cnts)
|
||||
cur := 0
|
||||
for i := int64(0); i < dc; i++ {
|
||||
slot := func() int64 {
|
||||
if len(idxs) > 0 && len(idxs) == len(rem) {
|
||||
for cur < len(rem) && rem[cur] == 0 {
|
||||
cur++
|
||||
}
|
||||
if cur >= len(rem) {
|
||||
return -1
|
||||
}
|
||||
rem[cur]--
|
||||
return idxs[cur] - 1
|
||||
}
|
||||
return parseSlotFromRemark(ord.Remark)
|
||||
}()
|
||||
fmt.Printf("[支付回调-一番赏占位] 获取格位 slot=%d\n", slot)
|
||||
if slot < 0 {
|
||||
fmt.Printf("[支付回调-一番赏占位] ❌ 格位无效,跳出循环\n")
|
||||
break
|
||||
}
|
||||
var cnt int64
|
||||
cnt, _ = h.readDB.IssuePositionClaims.WithContext(ctx.RequestContext()).Where(h.readDB.IssuePositionClaims.IssueID.Eq(iss), h.readDB.IssuePositionClaims.SlotIndex.Eq(slot)).Count()
|
||||
fmt.Printf("[支付回调-一番赏占位] 检查格位占用 issueID=%d slot=%d 已占用数=%d\n", iss, slot, cnt)
|
||||
if cnt > 0 {
|
||||
fmt.Printf("[支付回调-一番赏占位] ❌ 格位已被占用,跳出循环并退款\n")
|
||||
// 标记订单为退款状态并处理退款
|
||||
wc, e := pay.NewWechatPayClient(ctx.RequestContext())
|
||||
if e == nil {
|
||||
refundNo := fmt.Sprintf("R%s-%d", ord.OrderNo, time.Now().Unix())
|
||||
refundID, status, e2 := wc.RefundOrder(ctx.RequestContext(), ord.OrderNo, refundNo, ord.ActualAmount, ord.ActualAmount, "slot_unavailable")
|
||||
if e2 == nil {
|
||||
_ = h.writeDB.PaymentRefunds.WithContext(ctx.RequestContext()).Create(&model.PaymentRefunds{OrderID: ord.ID, OrderNo: ord.OrderNo, RefundNo: refundNo, Channel: "wechat_jsapi", Status: status, AmountRefund: ord.ActualAmount, Reason: "slot_unavailable"})
|
||||
_ = h.writeDB.UserPointsLedger.WithContext(ctx.RequestContext()).Create(&model.UserPointsLedger{UserID: ord.UserID, Action: "refund_amount", Points: ord.ActualAmount / 100, RefTable: "payment_refund", RefID: refundID})
|
||||
_, _ = h.writeDB.Orders.WithContext(ctx.RequestContext()).Where(h.writeDB.Orders.ID.Eq(ord.ID)).Updates(map[string]any{h.writeDB.Orders.Status.ColumnName().String(): 4})
|
||||
_ = h.repo.GetDbW().Exec("INSERT INTO lottery_refund_logs(issue_id, order_id, user_id, amount, coupon_type, coupon_amount, reason, status) VALUES(?,?,?,?,?,?,?,?)", iss, ord.ID, ord.UserID, ord.ActualAmount, "", 0, "slot_unavailable", status).Error
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
// 尝试创建占用记录,利用唯一索引防止并发
|
||||
err := h.writeDB.IssuePositionClaims.WithContext(ctx.RequestContext()).Create(&model.IssuePositionClaims{IssueID: iss, SlotIndex: slot, UserID: ord.UserID, OrderID: ord.ID})
|
||||
if err != nil {
|
||||
fmt.Printf("[支付回调-一番赏占位] ❌ 创建格位占用失败 err=%v\n", err)
|
||||
// 同样处理退款
|
||||
wc, e := pay.NewWechatPayClient(ctx.RequestContext())
|
||||
if e == nil {
|
||||
refundNo := fmt.Sprintf("R%s-%d", ord.OrderNo, time.Now().Unix())
|
||||
refundID, status, e2 := wc.RefundOrder(ctx.RequestContext(), ord.OrderNo, refundNo, ord.ActualAmount, ord.ActualAmount, "slot_concurrent_conflict")
|
||||
if e2 == nil {
|
||||
_ = h.writeDB.PaymentRefunds.WithContext(ctx.RequestContext()).Create(&model.PaymentRefunds{OrderID: ord.ID, OrderNo: ord.OrderNo, RefundNo: refundNo, Channel: "wechat_jsapi", Status: status, AmountRefund: ord.ActualAmount, Reason: "slot_concurrent_conflict"})
|
||||
_ = h.writeDB.UserPointsLedger.WithContext(ctx.RequestContext()).Create(&model.UserPointsLedger{UserID: ord.UserID, Action: "refund_amount", Points: ord.ActualAmount / 100, RefTable: "payment_refund", RefID: refundID})
|
||||
_, _ = h.writeDB.Orders.WithContext(ctx.RequestContext()).Where(h.writeDB.Orders.ID.Eq(ord.ID)).Updates(map[string]any{h.writeDB.Orders.Status.ColumnName().String(): 4})
|
||||
_ = h.repo.GetDbW().Exec("INSERT INTO lottery_refund_logs(issue_id, order_id, user_id, amount, coupon_type, coupon_amount, reason, status) VALUES(?,?,?,?,?,?,?,?)", iss, ord.ID, ord.UserID, ord.ActualAmount, "", 0, "slot_concurrent_conflict", status).Error
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
fmt.Printf("[支付回调-一番赏占位] ✅ 格位占用成功 issueID=%d slot=%d userID=%d orderID=%d\n", iss, slot, ord.UserID, ord.ID)
|
||||
}
|
||||
}
|
||||
|
||||
// instant 模式才立即开奖发奖
|
||||
if act != nil && act.DrawMode == "instant" {
|
||||
logs, _ := h.readDB.ActivityDrawLogs.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityDrawLogs.OrderID.Eq(ord.ID)).Find()
|
||||
done := int64(len(logs))
|
||||
// 解析道具卡ID
|
||||
icID := parseItemCardIDFromRemark(ord.Remark)
|
||||
fmt.Printf("[支付回调-抽奖] 开始处理 活动ID=%d 期ID=%d 次数=%d 道具卡ID=%d 玩法=%s 已完成=%d\n", aid, iss, dc, icID, act.PlayType, done)
|
||||
if act.PlayType == "ichiban" {
|
||||
idxs, cnts := parseSlotsCountsFromRemark(ord.Remark)
|
||||
fmt.Printf("[支付回调-抽奖] 解析格位 idxs=%v cnts=%v 订单备注=%s\n", idxs, cnts, ord.Remark)
|
||||
// 6. 一番赏占位 (事务内处理)
|
||||
if order.SourceType == 2 {
|
||||
aid := parseActivityIDFromRemark(order.Remark)
|
||||
iss := parseIssueIDFromRemark(order.Remark)
|
||||
dc := parseCountFromRemark(order.Remark)
|
||||
act, _ := tx.Activities.WithContext(ctx.RequestContext()).Where(tx.Activities.ID.Eq(aid)).First()
|
||||
if act != nil && act.PlayType == "ichiban" {
|
||||
idxs, cnts := parseSlotsCountsFromRemark(order.Remark)
|
||||
rem := make([]int64, len(cnts))
|
||||
copy(rem, cnts)
|
||||
cur := 0
|
||||
for i := done; i < dc; i++ {
|
||||
fmt.Printf("[支付回调-抽奖] 循环开始 i=%d dc=%d\n", i, dc)
|
||||
for i := int64(0); i < dc; i++ {
|
||||
slot := func() int64 {
|
||||
if len(idxs) > 0 && len(idxs) == len(rem) {
|
||||
for cur < len(rem) && rem[cur] == 0 {
|
||||
@ -346,225 +225,113 @@ func (h *handler) WechatNotify() core.HandlerFunc {
|
||||
rem[cur]--
|
||||
return idxs[cur] - 1
|
||||
}
|
||||
return parseSlotFromRemark(ord.Remark)
|
||||
return parseSlotFromRemark(order.Remark)
|
||||
}()
|
||||
fmt.Printf("[支付回调-抽奖] 获取格位 slot=%d\n", slot)
|
||||
if slot < 0 {
|
||||
fmt.Printf("[支付回调-抽奖] ❌ 格位无效,跳出循环\n")
|
||||
break
|
||||
}
|
||||
// 位置已在上面占用,这里直接选择奖品
|
||||
// Use Commitment Seed (via SelectItemBySlot internal logic)
|
||||
rid, proof, e2 := strat.NewIchiban(h.readDB, h.writeDB).SelectItemBySlot(ctx.RequestContext(), aid, iss, slot)
|
||||
fmt.Printf("[支付回调-抽奖] SelectItemBySlot 结果 rid=%d err=%v\n", rid, e2)
|
||||
if e2 != nil || rid <= 0 {
|
||||
fmt.Printf("[支付回调-抽奖] ❌ SelectItemBySlot 失败,跳出循环\n")
|
||||
break
|
||||
// 检查是否已被占用 (事务内)
|
||||
cnt, _ := tx.IssuePositionClaims.WithContext(ctx.RequestContext()).Where(tx.IssuePositionClaims.IssueID.Eq(iss), tx.IssuePositionClaims.SlotIndex.Eq(slot)).Count()
|
||||
if cnt > 0 {
|
||||
return fmt.Errorf("slot_unavailable")
|
||||
}
|
||||
rw, _ := h.readDB.ActivityRewardSettings.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityRewardSettings.ID.Eq(rid)).First()
|
||||
if rw == nil {
|
||||
fmt.Printf("[支付回调-抽奖] ❌ 奖品设置为空,跳出循环\n")
|
||||
break
|
||||
}
|
||||
fmt.Printf("[支付回调-抽奖] 发放奖品 rid=%d 奖品名=%s\n", rid, rw.Name)
|
||||
// 【先记录日志,再发奖】确保日志创建成功后再发奖,防止重复
|
||||
log := &model.ActivityDrawLogs{UserID: ord.UserID, IssueID: iss, OrderID: ord.ID, RewardID: rid, IsWinner: 1, Level: rw.Level, CurrentLevel: 1}
|
||||
if errLog := h.writeDB.ActivityDrawLogs.WithContext(ctx.RequestContext()).Create(log); errLog != nil {
|
||||
fmt.Printf("[支付回调-抽奖] ❌ 创建开奖日志失败 err=%v,可能已存在,跳过\n", errLog)
|
||||
continue
|
||||
}
|
||||
// 保存抽奖凭据(种子数据)供用户验证
|
||||
_ = strat.SaveDrawReceipt(ctx.RequestContext(), h.writeDB, log.ID, iss, ord.UserID, proof)
|
||||
_ = strat.NewIchiban(h.readDB, h.writeDB).GrantReward(ctx.RequestContext(), ord.UserID, rid)
|
||||
// 道具卡效果处理
|
||||
fmt.Printf("[支付回调-道具卡] 开始检查 活动允许道具卡=%t 道具卡ID=%d\n", act.AllowItemCards, icID)
|
||||
if act.AllowItemCards && icID > 0 {
|
||||
uic, _ := h.readDB.UserItemCards.WithContext(ctx.RequestContext()).Where(h.readDB.UserItemCards.ID.Eq(icID), h.readDB.UserItemCards.UserID.Eq(ord.UserID), h.readDB.UserItemCards.Status.Eq(1)).First()
|
||||
if uic != nil {
|
||||
fmt.Printf("[支付回调-道具卡] 找到用户道具卡 ID=%d CardID=%d Status=%d\n", uic.ID, uic.CardID, uic.Status)
|
||||
ic, _ := h.readDB.SystemItemCards.WithContext(ctx.RequestContext()).Where(h.readDB.SystemItemCards.ID.Eq(uic.CardID), h.readDB.SystemItemCards.Status.Eq(1)).First()
|
||||
now := time.Now()
|
||||
if ic != nil && !uic.ValidStart.After(now) && !uic.ValidEnd.Before(now) {
|
||||
scopeOK := (ic.ScopeType == 1) || (ic.ScopeType == 3 && ic.ActivityID == aid) || (ic.ScopeType == 4 && ic.IssueID == iss)
|
||||
fmt.Printf("[支付回调-道具卡] 系统道具卡 EffectType=%d RewardMultiplierX1000=%d ScopeType=%d scopeOK=%t\n", ic.EffectType, ic.RewardMultiplierX1000, ic.ScopeType, scopeOK)
|
||||
if scopeOK {
|
||||
if ic.EffectType == 1 && ic.RewardMultiplierX1000 >= 2000 {
|
||||
fmt.Printf("[支付回调-道具卡] ✅ 应用双倍奖励 奖品ID=%d 奖品名=%s\n", rid, rw.Name)
|
||||
_ = strat.NewIchiban(h.readDB, h.writeDB).GrantReward(ctx.RequestContext(), ord.UserID, rid)
|
||||
}
|
||||
// 核销道具卡
|
||||
fmt.Printf("[支付回调-道具卡] 核销道具卡 用户道具卡ID=%d\n", icID)
|
||||
_, _ = h.writeDB.UserItemCards.WithContext(ctx.RequestContext()).Where(h.readDB.UserItemCards.ID.Eq(icID), h.readDB.UserItemCards.UserID.Eq(ord.UserID), h.readDB.UserItemCards.Status.Eq(1)).Updates(map[string]any{
|
||||
h.readDB.UserItemCards.Status.ColumnName().String(): 2,
|
||||
h.readDB.UserItemCards.UsedDrawLogID.ColumnName().String(): log.ID,
|
||||
h.readDB.UserItemCards.UsedActivityID.ColumnName().String(): aid,
|
||||
h.readDB.UserItemCards.UsedIssueID.ColumnName().String(): iss,
|
||||
h.readDB.UserItemCards.UsedAt.ColumnName().String(): now,
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("[支付回调-道具卡] ❌ 未找到用户道具卡 用户ID=%d 道具卡ID=%d\n", ord.UserID, icID)
|
||||
}
|
||||
err := tx.IssuePositionClaims.WithContext(ctx.RequestContext()).Create(&model.IssuePositionClaims{IssueID: iss, SlotIndex: slot, UserID: order.UserID, OrderID: order.ID})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 7. 标记通知事件为已处理
|
||||
if notification != nil && notification.ID != "" {
|
||||
if existed == nil {
|
||||
_ = tx.PaymentNotifyEvents.WithContext(ctx.RequestContext()).Create(&model.PaymentNotifyEvents{
|
||||
NotifyID: notification.ID,
|
||||
ResourceType: notification.ResourceType,
|
||||
EventType: notification.EventType,
|
||||
Summary: notification.Summary,
|
||||
Raw: rawStr,
|
||||
Processed: true,
|
||||
})
|
||||
} else {
|
||||
sel := strat.NewDefault(h.readDB, h.writeDB)
|
||||
for i := done; i < dc; i++ {
|
||||
rid, proof, e2 := sel.SelectItem(ctx.RequestContext(), aid, iss, ord.UserID)
|
||||
if e2 != nil || rid <= 0 {
|
||||
break
|
||||
}
|
||||
rw, _ := h.readDB.ActivityRewardSettings.WithContext(ctx.RequestContext()).Where(h.readDB.ActivityRewardSettings.ID.Eq(rid)).First()
|
||||
if rw == nil {
|
||||
break
|
||||
}
|
||||
// 【先记录日志,再发奖】确保日志创建成功后再发奖,防止重复
|
||||
log := &model.ActivityDrawLogs{UserID: ord.UserID, IssueID: iss, OrderID: ord.ID, RewardID: rid, IsWinner: 1, Level: rw.Level, CurrentLevel: 1}
|
||||
if errLog := h.writeDB.ActivityDrawLogs.WithContext(ctx.RequestContext()).Create(log); errLog != nil {
|
||||
fmt.Printf("[支付回调-默认玩法] ❌ 创建开奖日志失败 err=%v,可能已存在,跳过\n", errLog)
|
||||
break
|
||||
}
|
||||
// 保存抽奖凭据(种子数据)供用户验证
|
||||
_ = strat.SaveDrawReceipt(ctx.RequestContext(), h.writeDB, log.ID, iss, ord.UserID, proof)
|
||||
_, errGrant := h.user.GrantRewardToOrder(ctx.RequestContext(), ord.UserID, usersvc.GrantRewardToOrderRequest{OrderID: ord.ID, ProductID: rw.ProductID, Quantity: 1, ActivityID: &aid, RewardID: &rid, Remark: rw.Name})
|
||||
if errGrant != nil {
|
||||
fmt.Printf("[支付回调-默认玩法] ❌ 发奖失败 err=%v,执行退款\n", errGrant)
|
||||
// 发奖失败,执行退款
|
||||
wc, e := pay.NewWechatPayClient(ctx.RequestContext())
|
||||
if e == nil {
|
||||
refundNo := fmt.Sprintf("R%s-%d", ord.OrderNo, time.Now().Unix())
|
||||
refundID, status, e2 := wc.RefundOrder(ctx.RequestContext(), ord.OrderNo, refundNo, ord.ActualAmount, ord.ActualAmount, "grant_reward_failed")
|
||||
if e2 == nil {
|
||||
_ = h.writeDB.PaymentRefunds.WithContext(ctx.RequestContext()).Create(&model.PaymentRefunds{OrderID: ord.ID, OrderNo: ord.OrderNo, RefundNo: refundNo, Channel: "wechat_jsapi", Status: status, AmountRefund: ord.ActualAmount, Reason: "grant_reward_failed"})
|
||||
_ = h.writeDB.UserPointsLedger.WithContext(ctx.RequestContext()).Create(&model.UserPointsLedger{UserID: ord.UserID, Action: "refund_amount", Points: ord.ActualAmount / 100, RefTable: "payment_refund", RefID: refundID})
|
||||
_, _ = h.writeDB.Orders.WithContext(ctx.RequestContext()).Where(h.writeDB.Orders.ID.Eq(ord.ID)).Updates(map[string]any{h.writeDB.Orders.Status.ColumnName().String(): 4})
|
||||
// 记录退款日志
|
||||
_ = h.repo.GetDbW().Exec("INSERT INTO lottery_refund_logs(issue_id, order_id, user_id, amount, coupon_type, coupon_amount, reason, status) VALUES(?,?,?,?,?,?,?,?)", iss, ord.ID, ord.UserID, ord.ActualAmount, "", 0, "grant_reward_failed", status).Error
|
||||
// 标记开奖日志为无效或失败(可选,视业务需求而定,这里暂不删除日志以便追溯)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
// 道具卡效果处理
|
||||
icID := parseItemCardIDFromRemark(ord.Remark)
|
||||
fmt.Printf("[支付回调-道具卡] 开始检查 活动允许道具卡=%t 道具卡ID=%d\n", act.AllowItemCards, icID)
|
||||
if act.AllowItemCards && icID > 0 {
|
||||
uic, _ := h.readDB.UserItemCards.WithContext(ctx.RequestContext()).Where(h.readDB.UserItemCards.ID.Eq(icID), h.readDB.UserItemCards.UserID.Eq(ord.UserID), h.readDB.UserItemCards.Status.Eq(1)).First()
|
||||
if uic != nil {
|
||||
fmt.Printf("[支付回调-道具卡] 找到用户道具卡 ID=%d CardID=%d Status=%d\n", uic.ID, uic.CardID, uic.Status)
|
||||
ic, _ := h.readDB.SystemItemCards.WithContext(ctx.RequestContext()).Where(h.readDB.SystemItemCards.ID.Eq(uic.CardID), h.readDB.SystemItemCards.Status.Eq(1)).First()
|
||||
now := time.Now()
|
||||
if ic != nil && !uic.ValidStart.After(now) && !uic.ValidEnd.Before(now) {
|
||||
scopeOK := (ic.ScopeType == 1) || (ic.ScopeType == 3 && ic.ActivityID == aid) || (ic.ScopeType == 4 && ic.IssueID == iss)
|
||||
fmt.Printf("[支付回调-道具卡] 系统道具卡 EffectType=%d RewardMultiplierX1000=%d ScopeType=%d scopeOK=%t\n", ic.EffectType, ic.RewardMultiplierX1000, ic.ScopeType, scopeOK)
|
||||
if scopeOK {
|
||||
if ic.EffectType == 1 && ic.RewardMultiplierX1000 >= 2000 {
|
||||
fmt.Printf("[支付回调-道具卡] ✅ 应用双倍奖励 奖品ID=%d 奖品名=%s\n", rid, rw.Name)
|
||||
_, _ = h.user.GrantRewardToOrder(ctx.RequestContext(), ord.UserID, usersvc.GrantRewardToOrderRequest{OrderID: ord.ID, ProductID: rw.ProductID, Quantity: 1, ActivityID: &aid, RewardID: &rid, Remark: rw.Name + "(倍数)"})
|
||||
}
|
||||
// 核销道具卡
|
||||
fmt.Printf("[支付回调-道具卡] 核销道具卡 用户道具卡ID=%d\n", icID)
|
||||
_, _ = h.writeDB.UserItemCards.WithContext(ctx.RequestContext()).Where(h.readDB.UserItemCards.ID.Eq(icID), h.readDB.UserItemCards.UserID.Eq(ord.UserID), h.readDB.UserItemCards.Status.Eq(1)).Updates(map[string]any{
|
||||
h.readDB.UserItemCards.Status.ColumnName().String(): 2,
|
||||
h.readDB.UserItemCards.UsedDrawLogID.ColumnName().String(): log.ID,
|
||||
h.readDB.UserItemCards.UsedActivityID.ColumnName().String(): aid,
|
||||
h.readDB.UserItemCards.UsedIssueID.ColumnName().String(): iss,
|
||||
h.readDB.UserItemCards.UsedAt.ColumnName().String(): now,
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("[支付回调-道具卡] ❌ 未找到用户道具卡 用户ID=%d 道具卡ID=%d\n", ord.UserID, icID)
|
||||
}
|
||||
}
|
||||
}
|
||||
_, _ = tx.PaymentNotifyEvents.WithContext(ctx.RequestContext()).Where(tx.PaymentNotifyEvents.NotifyID.Eq(notification.ID)).Update(tx.PaymentNotifyEvents.Processed, true)
|
||||
}
|
||||
// 【开奖后虚拟发货】即时开奖完成后上传虚拟发货
|
||||
go func(orderID int64, orderNo string, userID int64, actName string, playType string) {
|
||||
bgCtx := context.Background()
|
||||
drawLogs, _ := h.readDB.ActivityDrawLogs.WithContext(bgCtx).Where(h.readDB.ActivityDrawLogs.OrderID.Eq(orderID)).Find()
|
||||
if len(drawLogs) == 0 {
|
||||
fmt.Printf("[即时开奖-虚拟发货] 没有开奖记录,跳过 order_id=%d\n", orderID)
|
||||
return
|
||||
}
|
||||
// 收集赏品名称
|
||||
var rewardNames []string
|
||||
for _, lg := range drawLogs {
|
||||
if rw, _ := h.readDB.ActivityRewardSettings.WithContext(bgCtx).Where(h.readDB.ActivityRewardSettings.ID.Eq(lg.RewardID)).First(); rw != nil {
|
||||
rewardNames = append(rewardNames, rw.Name)
|
||||
}
|
||||
}
|
||||
itemsDesc := actName + " " + orderNo + " 盲盒赏品: " + strings.Join(rewardNames, ", ")
|
||||
itemsDesc = pkgutils.TruncateBytes(itemsDesc, 120)
|
||||
// 获取支付交易信息
|
||||
var tx *model.PaymentTransactions
|
||||
tx, _ = h.readDB.PaymentTransactions.WithContext(bgCtx).Where(h.readDB.PaymentTransactions.OrderNo.Eq(orderNo)).First()
|
||||
if tx == nil || tx.TransactionID == "" {
|
||||
fmt.Printf("[即时开奖-虚拟发货] 没有支付交易记录,跳过 order_no=%s\n", orderNo)
|
||||
return
|
||||
}
|
||||
// 获取用户openid
|
||||
var u *model.Users
|
||||
u, _ = h.readDB.Users.WithContext(bgCtx).Where(h.readDB.Users.ID.Eq(userID)).First()
|
||||
payerOpenid := ""
|
||||
if u != nil {
|
||||
payerOpenid = u.Openid
|
||||
}
|
||||
fmt.Printf("[即时开奖-虚拟发货] 上传 order_no=%s transaction_id=%s items_desc=%s\n", orderNo, tx.TransactionID, itemsDesc)
|
||||
if err := wechat.UploadVirtualShippingForBackground(bgCtx, &wechat.WechatConfig{AppID: c.Wechat.AppID, AppSecret: c.Wechat.AppSecret}, tx.TransactionID, orderNo, payerOpenid, itemsDesc); err != nil {
|
||||
fmt.Printf("[即时开奖-虚拟发货] 上传失败: %v\n", err)
|
||||
}
|
||||
// 【开奖后推送通知】只有一番赏才发送
|
||||
if playType == "ichiban" {
|
||||
notifyCfg := &lotterynotify.WechatNotifyConfig{
|
||||
AppID: c.Wechat.AppID,
|
||||
AppSecret: c.Wechat.AppSecret,
|
||||
LotteryResultTemplateID: c.Wechat.LotteryResultTemplateID,
|
||||
}
|
||||
_ = lotterynotify.SendLotteryResultNotification(bgCtx, notifyCfg, payerOpenid, actName, rewardNames, orderNo, time.Now())
|
||||
}
|
||||
}(ord.ID, ord.OrderNo, ord.UserID, act.Name, act.PlayType)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
// 处理事务结果
|
||||
if err != nil {
|
||||
if err.Error() == "slot_unavailable" {
|
||||
// 处理一番赏位置冲突退款 (事务外异步处理,避免长事务)
|
||||
go h.handleRefund(context.Background(), order, "ichiban_slot_conflict")
|
||||
ctx.Payload(¬ifyAck{Code: "SUCCESS", Message: "OK"})
|
||||
return
|
||||
}
|
||||
ctx.AbortWithError(core.Error(http.StatusInternalServerError, 150005, err.Error()))
|
||||
return
|
||||
}
|
||||
if ord != nil {
|
||||
var itemsDesc string
|
||||
if xs, _ := h.readDB.OrderItems.WithContext(ctx.RequestContext()).Where(h.readDB.OrderItems.OrderID.Eq(ord.ID)).Find(); len(xs) > 0 {
|
||||
var parts []string
|
||||
for _, it := range xs {
|
||||
parts = append(parts, it.Title+"*"+func(q int64) string { return fmt.Sprintf("%d", q) }(it.Quantity))
|
||||
|
||||
// 8. 异步触发外部同步逻辑 (无需事务)
|
||||
go func() {
|
||||
bgCtx := context.Background()
|
||||
// 触发任务中心逻辑
|
||||
_ = h.task.OnOrderPaid(bgCtx, order.UserID, order.ID)
|
||||
|
||||
// 抽奖或发货逻辑
|
||||
ord, _ := h.readDB.Orders.WithContext(bgCtx).Where(h.readDB.Orders.ID.Eq(order.ID)).First()
|
||||
if ord == nil {
|
||||
return
|
||||
}
|
||||
actID := parseActivityIDFromRemark(ord.Remark)
|
||||
act, _ := h.readDB.Activities.WithContext(bgCtx).Where(h.readDB.Activities.ID.Eq(actID)).First()
|
||||
|
||||
if ord.SourceType == 2 && act != nil && act.DrawMode == "instant" {
|
||||
_ = h.activity.ProcessOrderLottery(bgCtx, ord.ID)
|
||||
} else if ord.SourceType != 2 && ord.SourceType != 3 {
|
||||
// 普通商品虚拟发货
|
||||
payerOpenid := ""
|
||||
if transaction.Payer != nil && transaction.Payer.Openid != nil {
|
||||
payerOpenid = *transaction.Payer.Openid
|
||||
}
|
||||
s := strings.Join(parts, ", ")
|
||||
itemsDesc = pkgutils.TruncateRunes(s, 120)
|
||||
} else {
|
||||
itemsDesc = "订单" + ord.OrderNo
|
||||
}
|
||||
payerOpenid := ""
|
||||
if transaction.Payer != nil && transaction.Payer.Openid != nil {
|
||||
payerOpenid = *transaction.Payer.Openid
|
||||
}
|
||||
// 抽奖订单(2)和对对碰订单(3)在开奖/结算后发货,非此类订单在支付后立即发货
|
||||
if ord.SourceType != 2 && ord.SourceType != 3 {
|
||||
if transaction.TransactionId != nil && *transaction.TransactionId != "" {
|
||||
fmt.Printf("[支付回调] 虚拟发货 尝试上传 order_id=%d order_no=%s user_id=%d transaction_id=%s items_desc=%s payer_openid=%s\n", ord.ID, ord.OrderNo, ord.UserID, *transaction.TransactionId, itemsDesc, payerOpenid)
|
||||
if err := wechat.UploadVirtualShippingWithFallback(ctx, &wechat.WechatConfig{AppID: c.Wechat.AppID, AppSecret: c.Wechat.AppSecret}, *transaction.TransactionId, ord.OrderNo, payerOpenid, itemsDesc, time.Now()); err != nil {
|
||||
fmt.Printf("[支付回调] 虚拟发货上传失败: %v\n", err)
|
||||
itemsDesc := "订单" + ord.OrderNo
|
||||
if txID := func() string {
|
||||
if transaction.TransactionId != nil {
|
||||
return *transaction.TransactionId
|
||||
}
|
||||
return ""
|
||||
}(); txID != "" {
|
||||
_ = wechat.UploadVirtualShippingWithFallback(ctx, &wechat.WechatConfig{AppID: configs.Get().Wechat.AppID, AppSecret: configs.Get().Wechat.AppSecret}, txID, ord.OrderNo, payerOpenid, itemsDesc, time.Now())
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("[支付回调] 抽奖/对对碰订单跳过虚拟发货,将在开奖/结算后发货 order_id=%d order_no=%s source_type=%d\n", ord.ID, ord.OrderNo, ord.SourceType)
|
||||
}
|
||||
}
|
||||
// 标记事件处理完成
|
||||
if notification != nil && notification.ID != "" {
|
||||
_, _ = h.writeDB.PaymentNotifyEvents.WithContext(ctx.RequestContext()).Where(h.readDB.PaymentNotifyEvents.NotifyID.Eq(notification.ID)).Updates(map[string]any{
|
||||
h.writeDB.PaymentNotifyEvents.Processed.ColumnName().String(): true,
|
||||
})
|
||||
}
|
||||
}()
|
||||
|
||||
ctx.Payload(¬ifyAck{Code: "SUCCESS", Message: "OK"})
|
||||
}
|
||||
}
|
||||
|
||||
// handleRefund 处理一番赏冲突退款
|
||||
func (h *handler) handleRefund(ctx context.Context, ord *model.Orders, reason string) {
|
||||
wc, e := pay.NewWechatPayClient(ctx)
|
||||
if e != nil {
|
||||
h.logger.Error("Failed to create wechat pay client for refund", zap.Error(e))
|
||||
return
|
||||
}
|
||||
refundNo := fmt.Sprintf("R%s-%d", ord.OrderNo, time.Now().Unix())
|
||||
iss := parseIssueIDFromRemark(ord.Remark)
|
||||
refundID, status, e2 := wc.RefundOrder(ctx, ord.OrderNo, refundNo, ord.ActualAmount, ord.ActualAmount, reason)
|
||||
if e2 != nil {
|
||||
h.logger.Error("Refund failed", zap.Error(e2), zap.String("order_no", ord.OrderNo))
|
||||
return
|
||||
}
|
||||
_ = h.writeDB.PaymentRefunds.WithContext(ctx).Create(&model.PaymentRefunds{OrderID: ord.ID, OrderNo: ord.OrderNo, RefundNo: refundNo, Channel: "wechat_jsapi", Status: status, AmountRefund: ord.ActualAmount, Reason: reason})
|
||||
_ = h.writeDB.UserPointsLedger.WithContext(ctx).Create(&model.UserPointsLedger{UserID: ord.UserID, Action: "refund_amount", Points: ord.ActualAmount / 100, RefTable: "payment_refund", RefID: refundID})
|
||||
_, _ = h.writeDB.Orders.WithContext(ctx).Where(h.writeDB.Orders.ID.Eq(ord.ID)).Update(h.writeDB.Orders.Status, 4)
|
||||
_ = h.repo.GetDbW().Exec("INSERT INTO lottery_refund_logs(issue_id, order_id, user_id, amount, coupon_type, coupon_amount, reason, status) VALUES(?,?,?,?,?,?,?,?)", iss, ord.ID, ord.UserID, ord.ActualAmount, "", 0, reason, status).Error
|
||||
}
|
||||
|
||||
func parseIssueIDFromRemark(remark string) int64 {
|
||||
if remark == "" {
|
||||
return 0
|
||||
|
||||
@ -17,6 +17,7 @@ type addressShareCreateRequest struct {
|
||||
type addressShareCreateResponse struct {
|
||||
ShareToken string `json:"share_token"`
|
||||
ShareURL string `json:"share_url"`
|
||||
ShortLink string `json:"short_link"`
|
||||
ExpiresAt time.Time `json:"expires_at"`
|
||||
}
|
||||
|
||||
@ -54,12 +55,13 @@ func (h *handler) CreateAddressShare() core.HandlerFunc {
|
||||
exp = time.Now().Add(60 * time.Minute)
|
||||
}
|
||||
userID := int64(ctx.SessionUserInfo().Id)
|
||||
token, exp, err := h.user.CreateAddressShare(ctx.RequestContext(), userID, req.InventoryID, exp)
|
||||
token, shortLink, exp, err := h.user.CreateAddressShare(ctx.RequestContext(), userID, req.InventoryID, exp)
|
||||
if err != nil {
|
||||
ctx.AbortWithError(core.Error(http.StatusBadRequest, 10020, err.Error()))
|
||||
return
|
||||
}
|
||||
rsp.ShareToken = token
|
||||
rsp.ShortLink = shortLink
|
||||
rsp.ExpiresAt = exp
|
||||
rsp.ShareURL = "/api/app/address-share/" + token + "/submit"
|
||||
ctx.Payload(rsp)
|
||||
|
||||
@ -2,9 +2,12 @@ package app
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"bindbox-game/configs"
|
||||
"bindbox-game/internal/code"
|
||||
"bindbox-game/internal/pkg/core"
|
||||
"bindbox-game/internal/pkg/jwtoken"
|
||||
)
|
||||
|
||||
type addressShareSubmitRequest struct {
|
||||
@ -39,11 +42,31 @@ func (h *handler) SubmitAddressShare() core.HandlerFunc {
|
||||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "参数错误"))
|
||||
return
|
||||
}
|
||||
|
||||
// 尝试获取登录用户信息 (可选)
|
||||
var submitUserID *int64
|
||||
authHeader := ctx.GetHeader("Authorization")
|
||||
if authHeader != "" {
|
||||
// 如果有 Authorization 尝试解析
|
||||
if claims, err := jwtoken.New(configs.Get().JWT.PatientSecret).Parse(authHeader); err == nil {
|
||||
uid := int64(claims.SessionUserInfo.Id)
|
||||
submitUserID = &uid
|
||||
}
|
||||
}
|
||||
|
||||
ip := ctx.Request().RemoteAddr
|
||||
// 统一使用 ctx.RequestContext() 包含 context 内容
|
||||
addrID, err := h.user.SubmitAddressShare(ctx.RequestContext(), req.ShareToken, req.Name, req.Mobile, req.Province, req.City, req.District, req.Address, submitUserID, &ip)
|
||||
if err != nil {
|
||||
ctx.AbortWithError(core.Error(http.StatusBadRequest, 10024, err.Error()))
|
||||
// 处理业务错误,映射到具体代码
|
||||
msg := err.Error()
|
||||
errorCode := 10024
|
||||
if strings.Contains(msg, "invalid_or_expired_token") {
|
||||
errorCode = 10025
|
||||
} else if strings.Contains(msg, "already_processed") {
|
||||
errorCode = 10026
|
||||
}
|
||||
ctx.AbortWithError(core.Error(http.StatusBadRequest, errorCode, msg))
|
||||
return
|
||||
}
|
||||
rsp.AddressID = addrID
|
||||
|
||||
69
internal/pkg/wechat/shortlink.go
Normal file
69
internal/pkg/wechat/shortlink.go
Normal file
@ -0,0 +1,69 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"bindbox-game/internal/pkg/httpclient"
|
||||
)
|
||||
|
||||
// ShortLinkRequest 获取小程序短链请求参数
|
||||
type ShortLinkRequest struct {
|
||||
PagePath string `json:"page_path"`
|
||||
PageTitle string `json:"page_title,omitempty"`
|
||||
IsPermanent bool `json:"is_permanent,omitempty"`
|
||||
}
|
||||
|
||||
// ShortLinkResponse 获取小程序短链响应
|
||||
type ShortLinkResponse struct {
|
||||
Link string `json:"link"`
|
||||
ErrCode int `json:"errcode,omitempty"`
|
||||
ErrMsg string `json:"errmsg,omitempty"`
|
||||
}
|
||||
|
||||
// GetShortLink 获取小程序短链
|
||||
// pagePath: 页面路径,如 pages/address/submit?token=xxx
|
||||
// pageTitle: 页面标题,如 "送你一个盲盒奖品"
|
||||
func GetShortLink(accessToken string, pagePath string, pageTitle string) (string, error) {
|
||||
if accessToken == "" {
|
||||
return "", fmt.Errorf("access_token 不能为空")
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("https://api.weixin.qq.com/wxa/genwxaqshortlink?access_token=%s", accessToken)
|
||||
|
||||
reqBody := ShortLinkRequest{
|
||||
PagePath: pagePath,
|
||||
PageTitle: pageTitle,
|
||||
IsPermanent: false,
|
||||
}
|
||||
|
||||
requestBody, err := json.Marshal(reqBody)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("序列化请求参数失败: %v", err)
|
||||
}
|
||||
|
||||
resp, err := httpclient.GetHttpClient().R().
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetBody(requestBody).
|
||||
Post(url)
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("发送HTTP请求失败: %v", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode() != http.StatusOK {
|
||||
return "", fmt.Errorf("HTTP请求失败,状态码: %d", resp.StatusCode())
|
||||
}
|
||||
|
||||
var slResp ShortLinkResponse
|
||||
if err := json.Unmarshal(resp.Body(), &slResp); err != nil {
|
||||
return "", fmt.Errorf("解析响应失败: %v", err)
|
||||
}
|
||||
|
||||
if slResp.ErrCode != 0 {
|
||||
return "", fmt.Errorf("获取短链失败: errcode=%d, errmsg=%s", slResp.ErrCode, slResp.ErrMsg)
|
||||
}
|
||||
|
||||
return slResp.Link, nil
|
||||
}
|
||||
@ -36,6 +36,7 @@ func newActivityDrawLogs(db *gorm.DB, opts ...gen.DOOption) activityDrawLogs {
|
||||
_activityDrawLogs.IsWinner = field.NewInt32(tableName, "is_winner")
|
||||
_activityDrawLogs.Level = field.NewInt32(tableName, "level")
|
||||
_activityDrawLogs.CurrentLevel = field.NewInt32(tableName, "current_level")
|
||||
_activityDrawLogs.DrawIndex = field.NewInt64(tableName, "draw_index")
|
||||
|
||||
_activityDrawLogs.fillFieldMap()
|
||||
|
||||
@ -56,6 +57,7 @@ type activityDrawLogs struct {
|
||||
IsWinner field.Int32 // 是否中奖:0否 1是
|
||||
Level field.Int32 // 中奖等级(如1=S 2=A 3=B)
|
||||
CurrentLevel field.Int32 // 当前层(针对爬塔)其它默认为1
|
||||
DrawIndex field.Int64 // 抽奖序号(0-N)
|
||||
|
||||
fieldMap map[string]field.Expr
|
||||
}
|
||||
@ -81,6 +83,7 @@ func (a *activityDrawLogs) updateTableName(table string) *activityDrawLogs {
|
||||
a.IsWinner = field.NewInt32(table, "is_winner")
|
||||
a.Level = field.NewInt32(table, "level")
|
||||
a.CurrentLevel = field.NewInt32(table, "current_level")
|
||||
a.DrawIndex = field.NewInt64(table, "draw_index")
|
||||
|
||||
a.fillFieldMap()
|
||||
|
||||
@ -97,7 +100,7 @@ func (a *activityDrawLogs) GetFieldByName(fieldName string) (field.OrderExpr, bo
|
||||
}
|
||||
|
||||
func (a *activityDrawLogs) fillFieldMap() {
|
||||
a.fieldMap = make(map[string]field.Expr, 9)
|
||||
a.fieldMap = make(map[string]field.Expr, 10)
|
||||
a.fieldMap["id"] = a.ID
|
||||
a.fieldMap["created_at"] = a.CreatedAt
|
||||
a.fieldMap["user_id"] = a.UserID
|
||||
@ -107,6 +110,7 @@ func (a *activityDrawLogs) fillFieldMap() {
|
||||
a.fieldMap["is_winner"] = a.IsWinner
|
||||
a.fieldMap["level"] = a.Level
|
||||
a.fieldMap["current_level"] = a.CurrentLevel
|
||||
a.fieldMap["draw_index"] = a.DrawIndex
|
||||
}
|
||||
|
||||
func (a activityDrawLogs) clone(db *gorm.DB) activityDrawLogs {
|
||||
|
||||
@ -36,6 +36,7 @@ func newUserInventory(db *gorm.DB, opts ...gen.DOOption) userInventory {
|
||||
_userInventory.ActivityID = field.NewInt64(tableName, "activity_id")
|
||||
_userInventory.RewardID = field.NewInt64(tableName, "reward_id")
|
||||
_userInventory.Status = field.NewInt32(tableName, "status")
|
||||
_userInventory.ShippingNo = field.NewString(tableName, "shipping_no")
|
||||
_userInventory.Remark = field.NewString(tableName, "remark")
|
||||
|
||||
_userInventory.fillFieldMap()
|
||||
@ -57,6 +58,7 @@ type userInventory struct {
|
||||
ActivityID field.Int64 // 来源活动ID
|
||||
RewardID field.Int64 // 来源奖励ID(activity_reward_settings.id)
|
||||
Status field.Int32 // 状态:1持有 2作废 3已使用/发货
|
||||
ShippingNo field.String // 发货单号
|
||||
Remark field.String // 备注
|
||||
|
||||
fieldMap map[string]field.Expr
|
||||
@ -83,6 +85,7 @@ func (u *userInventory) updateTableName(table string) *userInventory {
|
||||
u.ActivityID = field.NewInt64(table, "activity_id")
|
||||
u.RewardID = field.NewInt64(table, "reward_id")
|
||||
u.Status = field.NewInt32(table, "status")
|
||||
u.ShippingNo = field.NewString(table, "shipping_no")
|
||||
u.Remark = field.NewString(table, "remark")
|
||||
|
||||
u.fillFieldMap()
|
||||
@ -100,7 +103,7 @@ func (u *userInventory) GetFieldByName(fieldName string) (field.OrderExpr, bool)
|
||||
}
|
||||
|
||||
func (u *userInventory) fillFieldMap() {
|
||||
u.fieldMap = make(map[string]field.Expr, 10)
|
||||
u.fieldMap = make(map[string]field.Expr, 11)
|
||||
u.fieldMap["id"] = u.ID
|
||||
u.fieldMap["created_at"] = u.CreatedAt
|
||||
u.fieldMap["updated_at"] = u.UpdatedAt
|
||||
@ -110,6 +113,7 @@ func (u *userInventory) fillFieldMap() {
|
||||
u.fieldMap["activity_id"] = u.ActivityID
|
||||
u.fieldMap["reward_id"] = u.RewardID
|
||||
u.fieldMap["status"] = u.Status
|
||||
u.fieldMap["shipping_no"] = u.ShippingNo
|
||||
u.fieldMap["remark"] = u.Remark
|
||||
}
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@ type ActivityDrawLogs struct {
|
||||
IsWinner int32 `gorm:"column:is_winner;not null;comment:是否中奖:0否 1是" json:"is_winner"` // 是否中奖:0否 1是
|
||||
Level int32 `gorm:"column:level;not null;comment:中奖等级(如1=S 2=A 3=B)" json:"level"` // 中奖等级(如1=S 2=A 3=B)
|
||||
CurrentLevel int32 `gorm:"column:current_level;comment:当前层(针对爬塔)其它默认为1" json:"current_level"` // 当前层(针对爬塔)其它默认为1
|
||||
DrawIndex int64 `gorm:"column:draw_index;not null;comment:抽奖序号(0-N)" json:"draw_index"` // 抽奖序号(0-N)
|
||||
}
|
||||
|
||||
// TableName ActivityDrawLogs's table name
|
||||
|
||||
@ -21,6 +21,7 @@ type UserInventory struct {
|
||||
ActivityID int64 `gorm:"column:activity_id;comment:来源活动ID" json:"activity_id"` // 来源活动ID
|
||||
RewardID int64 `gorm:"column:reward_id;comment:来源奖励ID(activity_reward_settings.id)" json:"reward_id"` // 来源奖励ID(activity_reward_settings.id)
|
||||
Status int32 `gorm:"column:status;not null;default:1;comment:状态:1持有 2作废 3已使用/发货" json:"status"` // 状态:1持有 2作废 3已使用/发货
|
||||
ShippingNo string `gorm:"column:shipping_no;not null;comment:发货单号" json:"shipping_no"` // 发货单号
|
||||
Remark string `gorm:"column:remark;comment:备注" json:"remark"` // 备注
|
||||
}
|
||||
|
||||
|
||||
@ -16,6 +16,7 @@ import (
|
||||
"bindbox-game/internal/pkg/redis"
|
||||
"bindbox-game/internal/repository/mysql"
|
||||
"bindbox-game/internal/router/interceptor"
|
||||
activitysvc "bindbox-game/internal/service/activity"
|
||||
tasksvc "bindbox-game/internal/service/task_center"
|
||||
titlesvc "bindbox-game/internal/service/title"
|
||||
usersvc "bindbox-game/internal/service/user"
|
||||
@ -52,6 +53,7 @@ func NewHTTPMux(logger logger.CustomLogger, db mysql.Repo) (core.Mux, func(), er
|
||||
userSvc := usersvc.New(logger, db)
|
||||
titleSvc := titlesvc.New(logger, db)
|
||||
taskSvc := tasksvc.New(logger, db, rdb, userSvc, titleSvc)
|
||||
activitySvc := activitysvc.New(logger, db, userSvc, rdb)
|
||||
|
||||
// Context for Worker
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
@ -59,13 +61,13 @@ func NewHTTPMux(logger logger.CustomLogger, db mysql.Repo) (core.Mux, func(), er
|
||||
go taskSvc.StartWorker(ctx)
|
||||
|
||||
// 实例化拦截器
|
||||
adminHandler := admin.New(logger, db)
|
||||
adminHandler := admin.New(logger, db, rdb)
|
||||
activityHandler := activityapi.New(logger, db, rdb)
|
||||
taskCenterHandler := taskcenterapi.New(logger, db, taskSvc)
|
||||
|
||||
userHandler := userapi.New(logger, db)
|
||||
commonHandler := commonapi.New(logger, db)
|
||||
payHandler := payapi.New(logger, db, taskSvc)
|
||||
payHandler := payapi.New(logger, db, taskSvc, activitySvc)
|
||||
gameHandler := gameapi.New(logger, db, rdb, userSvc)
|
||||
intc := interceptor.New(logger, db)
|
||||
|
||||
@ -126,23 +128,23 @@ func NewHTTPMux(logger logger.CustomLogger, db mysql.Repo) (core.Mux, func(), er
|
||||
adminAuthApiRouter.GET("/dashboard/activities", adminHandler.DashboardActivities())
|
||||
adminAuthApiRouter.GET("/dashboard/activity_prize_analysis", adminHandler.DashboardActivityPrizeAnalysis())
|
||||
adminAuthApiRouter.GET("/dashboard/user_overview", adminHandler.DashboardUserOverview())
|
||||
adminAuthApiRouter.POST("/activities", adminHandler.CreateActivity())
|
||||
adminAuthApiRouter.GET("/activities", adminHandler.ListActivities())
|
||||
adminAuthApiRouter.PUT("/activities/:activity_id", adminHandler.ModifyActivity())
|
||||
adminAuthApiRouter.DELETE("/activities/:activity_id", adminHandler.DeleteActivity())
|
||||
adminAuthApiRouter.GET("/activities/:activity_id", adminHandler.GetActivityDetail())
|
||||
adminAuthApiRouter.POST("/lottery/activities/:activity_id/scheduled_config", adminHandler.SetScheduledConfig())
|
||||
adminAuthApiRouter.GET("/lottery/activities/:activity_id/scheduled_config", adminHandler.GetScheduledConfig())
|
||||
adminAuthApiRouter.POST("/activities/:activity_id/copy", adminHandler.CopyActivity())
|
||||
adminAuthApiRouter.GET("/activities/:activity_id/issues", adminHandler.ListActivityIssues())
|
||||
adminAuthApiRouter.POST("/activities/:activity_id/issues", adminHandler.CreateActivityIssue())
|
||||
adminAuthApiRouter.PUT("/activities/:activity_id/issues/:issue_id", adminHandler.ModifyActivityIssue())
|
||||
adminAuthApiRouter.DELETE("/activities/:activity_id/issues/:issue_id", adminHandler.DeleteActivityIssue())
|
||||
adminAuthApiRouter.POST("/activities/:activity_id/issues/:issue_id/rewards", adminHandler.CreateIssueRewards())
|
||||
adminAuthApiRouter.GET("/activities/:activity_id/issues/:issue_id/rewards", adminHandler.ListIssueRewards())
|
||||
adminAuthApiRouter.PUT("/activities/:activity_id/issues/:issue_id/rewards/:reward_id", adminHandler.ModifyIssueReward())
|
||||
adminAuthApiRouter.PUT("/activities/:activity_id/issues/:issue_id/rewards/batch", adminHandler.BatchModifyIssueRewards())
|
||||
adminAuthApiRouter.DELETE("/activities/:activity_id/issues/:issue_id/rewards/:reward_id", adminHandler.DeleteIssueReward())
|
||||
adminAuthApiRouter.POST("/activities", intc.RequireAdminAction("activity:create"), adminHandler.CreateActivity())
|
||||
adminAuthApiRouter.GET("/activities", intc.RequireAdminAction("activity:view"), adminHandler.ListActivities())
|
||||
adminAuthApiRouter.PUT("/activities/:activity_id", intc.RequireAdminAction("activity:modify"), adminHandler.ModifyActivity())
|
||||
adminAuthApiRouter.DELETE("/activities/:activity_id", intc.RequireAdminAction("activity:delete"), adminHandler.DeleteActivity())
|
||||
adminAuthApiRouter.GET("/activities/:activity_id", intc.RequireAdminAction("activity:view"), adminHandler.GetActivityDetail())
|
||||
adminAuthApiRouter.POST("/lottery/activities/:activity_id/scheduled_config", intc.RequireAdminAction("activity:modify"), adminHandler.SetScheduledConfig())
|
||||
adminAuthApiRouter.GET("/lottery/activities/:activity_id/scheduled_config", intc.RequireAdminAction("activity:view"), adminHandler.GetScheduledConfig())
|
||||
adminAuthApiRouter.POST("/activities/:activity_id/copy", intc.RequireAdminAction("activity:create"), adminHandler.CopyActivity())
|
||||
adminAuthApiRouter.GET("/activities/:activity_id/issues", intc.RequireAdminAction("activity:view"), adminHandler.ListActivityIssues())
|
||||
adminAuthApiRouter.POST("/activities/:activity_id/issues", intc.RequireAdminAction("activity:modify"), adminHandler.CreateActivityIssue())
|
||||
adminAuthApiRouter.PUT("/activities/:activity_id/issues/:issue_id", intc.RequireAdminAction("activity:modify"), adminHandler.ModifyActivityIssue())
|
||||
adminAuthApiRouter.DELETE("/activities/:activity_id/issues/:issue_id", intc.RequireAdminAction("activity:delete"), adminHandler.DeleteActivityIssue())
|
||||
adminAuthApiRouter.POST("/activities/:activity_id/issues/:issue_id/rewards", intc.RequireAdminAction("activity:modify"), adminHandler.CreateIssueRewards())
|
||||
adminAuthApiRouter.GET("/activities/:activity_id/issues/:issue_id/rewards", intc.RequireAdminAction("activity:view"), adminHandler.ListIssueRewards())
|
||||
adminAuthApiRouter.PUT("/activities/:activity_id/issues/:issue_id/rewards/:reward_id", intc.RequireAdminAction("activity:modify"), adminHandler.ModifyIssueReward())
|
||||
adminAuthApiRouter.PUT("/activities/:activity_id/issues/:issue_id/rewards/batch", intc.RequireAdminAction("activity:modify"), adminHandler.BatchModifyIssueRewards())
|
||||
adminAuthApiRouter.DELETE("/activities/:activity_id/issues/:issue_id/rewards/:reward_id", intc.RequireAdminAction("activity:delete"), adminHandler.DeleteIssueReward())
|
||||
|
||||
// 已移除:批量造数/批量删除用户接口(未被前端使用)
|
||||
|
||||
@ -178,24 +180,24 @@ func NewHTTPMux(logger logger.CustomLogger, db mysql.Repo) (core.Mux, func(), er
|
||||
adminAuthApiRouter.DELETE("/system/configs/:id", adminHandler.DeleteSystemConfig())
|
||||
|
||||
// 用户管理
|
||||
adminAuthApiRouter.GET("/users", adminHandler.ListAppUsers())
|
||||
adminAuthApiRouter.GET("/users/:user_id/invites", adminHandler.ListUserInvites())
|
||||
adminAuthApiRouter.GET("/users/:user_id/orders", adminHandler.ListUserOrders())
|
||||
adminAuthApiRouter.GET("/users/:user_id/coupons", adminHandler.ListUserCoupons())
|
||||
adminAuthApiRouter.GET("/users/:user_id/coupons/:user_coupon_id/usage", adminHandler.ListUserCouponUsage())
|
||||
adminAuthApiRouter.GET("/users/:user_id/points", adminHandler.ListUserPoints())
|
||||
adminAuthApiRouter.GET("/users/:user_id/points/balance", adminHandler.GetUserPointsBalance())
|
||||
adminAuthApiRouter.POST("/users/:user_id/points/add", adminHandler.AddUserPoints())
|
||||
adminAuthApiRouter.POST("/users/:user_id/coupons/add", adminHandler.AddUserCoupon())
|
||||
adminAuthApiRouter.POST("/users/:user_id/coupons/:user_coupon_id/void", adminHandler.VoidUserCoupon())
|
||||
adminAuthApiRouter.POST("/users/:user_id/rewards/grant", adminHandler.GrantReward())
|
||||
adminAuthApiRouter.GET("/users/:user_id/titles", adminHandler.ListUserTitles())
|
||||
adminAuthApiRouter.POST("/users/:user_id/token", adminHandler.IssueUserToken())
|
||||
adminAuthApiRouter.POST("/users/batch/points/add", adminHandler.BatchAddUserPoints())
|
||||
adminAuthApiRouter.POST("/users/batch/coupons/add", adminHandler.BatchAddUserCoupons())
|
||||
adminAuthApiRouter.POST("/users/batch/rewards/grant", adminHandler.BatchGrantUserRewards())
|
||||
adminAuthApiRouter.GET("/users/:user_id/inventory", adminHandler.ListUserInventory())
|
||||
adminAuthApiRouter.POST("/users/:user_id/inventory/:inventory_id/void", adminHandler.VoidUserInventory())
|
||||
adminAuthApiRouter.GET("/users", intc.RequireAdminAction("user:view"), adminHandler.ListAppUsers())
|
||||
adminAuthApiRouter.GET("/users/:user_id/invites", intc.RequireAdminAction("user:view"), adminHandler.ListUserInvites())
|
||||
adminAuthApiRouter.GET("/users/:user_id/orders", intc.RequireAdminAction("user:view"), adminHandler.ListUserOrders())
|
||||
adminAuthApiRouter.GET("/users/:user_id/coupons", intc.RequireAdminAction("user:view"), adminHandler.ListUserCoupons())
|
||||
adminAuthApiRouter.GET("/users/:user_id/coupons/:user_coupon_id/usage", intc.RequireAdminAction("user:view"), adminHandler.ListUserCouponUsage())
|
||||
adminAuthApiRouter.GET("/users/:user_id/points", intc.RequireAdminAction("user:view"), adminHandler.ListUserPoints())
|
||||
adminAuthApiRouter.GET("/users/:user_id/points/balance", intc.RequireAdminAction("user:view"), adminHandler.GetUserPointsBalance())
|
||||
adminAuthApiRouter.POST("/users/:user_id/points/add", intc.RequireAdminAction("user:points:add"), adminHandler.AddUserPoints())
|
||||
adminAuthApiRouter.POST("/users/:user_id/coupons/add", intc.RequireAdminAction("user:coupons:add"), adminHandler.AddUserCoupon())
|
||||
adminAuthApiRouter.POST("/users/:user_id/coupons/:user_coupon_id/void", intc.RequireAdminAction("user:coupons:void"), adminHandler.VoidUserCoupon())
|
||||
adminAuthApiRouter.POST("/users/:user_id/rewards/grant", intc.RequireAdminAction("user:rewards:grant"), adminHandler.GrantReward())
|
||||
adminAuthApiRouter.GET("/users/:user_id/titles", intc.RequireAdminAction("user:view"), adminHandler.ListUserTitles())
|
||||
adminAuthApiRouter.POST("/users/:user_id/token", intc.RequireAdminAction("user:token:issue"), adminHandler.IssueUserToken())
|
||||
adminAuthApiRouter.POST("/users/batch/points/add", intc.RequireAdminAction("user:points:batch:add"), adminHandler.BatchAddUserPoints())
|
||||
adminAuthApiRouter.POST("/users/batch/coupons/add", intc.RequireAdminAction("user:coupons:batch:add"), adminHandler.BatchAddUserCoupons())
|
||||
adminAuthApiRouter.POST("/users/batch/rewards/grant", intc.RequireAdminAction("user:rewards:batch:grant"), adminHandler.BatchGrantUserRewards())
|
||||
adminAuthApiRouter.GET("/users/:user_id/inventory", intc.RequireAdminAction("user:view"), adminHandler.ListUserInventory())
|
||||
adminAuthApiRouter.POST("/users/:user_id/inventory/:inventory_id/void", intc.RequireAdminAction("user:inventory:void"), adminHandler.VoidUserInventory())
|
||||
adminAuthApiRouter.GET("/users/:user_id/item_cards", adminHandler.ListUserItemCards())
|
||||
adminAuthApiRouter.POST("/users/:user_id/item_cards/:user_item_card_id/void", adminHandler.VoidUserItemCard())
|
||||
// 已移除:为指定用户签发APP令牌接口(未被前端使用)
|
||||
|
||||
@ -8,9 +8,18 @@ import (
|
||||
"bindbox-game/internal/repository/mysql"
|
||||
"bindbox-game/internal/repository/mysql/dao"
|
||||
"bindbox-game/internal/repository/mysql/model"
|
||||
usersvc "bindbox-game/internal/service/user"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
type Service interface {
|
||||
// ... (other methods)
|
||||
// ProcessOrderLottery 处理订单开奖(统一幂等逻辑)
|
||||
// 参数: ctx 上下文, orderID 订单ID
|
||||
// 返回: 错误信息
|
||||
ProcessOrderLottery(ctx context.Context, orderID int64) error
|
||||
|
||||
// CreateActivity 创建活动
|
||||
// 参数: in 活动创建输入
|
||||
// 返回: 活动记录与错误
|
||||
@ -96,14 +105,18 @@ type service struct {
|
||||
readDB *dao.Query
|
||||
writeDB *dao.Query
|
||||
repo mysql.Repo
|
||||
user usersvc.Service
|
||||
redis *redis.Client
|
||||
}
|
||||
|
||||
func New(l logger.CustomLogger, db mysql.Repo) Service {
|
||||
func New(l logger.CustomLogger, db mysql.Repo, u usersvc.Service, rdb *redis.Client) Service {
|
||||
return &service{
|
||||
logger: l,
|
||||
readDB: dao.Use(db.GetDbR()),
|
||||
writeDB: dao.Use(db.GetDbW()),
|
||||
repo: db,
|
||||
user: u,
|
||||
redis: rdb,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
377
internal/service/activity/lottery_process.go
Normal file
377
internal/service/activity/lottery_process.go
Normal file
@ -0,0 +1,377 @@
|
||||
package activity
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bindbox-game/configs"
|
||||
"bindbox-game/internal/pkg/notify"
|
||||
"bindbox-game/internal/pkg/wechat"
|
||||
"bindbox-game/internal/repository/mysql/model"
|
||||
strat "bindbox-game/internal/service/activity/strategy"
|
||||
usersvc "bindbox-game/internal/service/user"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// ProcessOrderLottery 处理订单开奖(统原子化高性能幂等逻辑)
|
||||
func (s *service) ProcessOrderLottery(ctx context.Context, orderID int64) error {
|
||||
s.logger.Info("开始原子化处理订单开奖", zap.Int64("order_id", orderID))
|
||||
|
||||
// 1. Redis 分布式锁:强制同一个订单串行处理,防止并发竞态引起的超发/漏发
|
||||
lockKey := fmt.Sprintf("lock:lottery:order:%d", orderID)
|
||||
locked, err := s.redis.SetNX(ctx, lockKey, "1", 30*time.Second).Result()
|
||||
if err != nil {
|
||||
return fmt.Errorf("分布式锁获取异常: %w", err)
|
||||
}
|
||||
if !locked {
|
||||
s.logger.Info("订单开奖锁已存在,跳过本次处理", zap.Int64("order_id", orderID))
|
||||
return nil
|
||||
}
|
||||
defer s.redis.Del(ctx, lockKey)
|
||||
|
||||
// 2. 批量预加载快照:将后续循环所需的查询合并为一次性加载
|
||||
order, err := s.readDB.Orders.WithContext(ctx).Where(s.readDB.Orders.ID.Eq(orderID)).First()
|
||||
if err != nil || order == nil {
|
||||
return fmt.Errorf("订单查询失败或不存在")
|
||||
}
|
||||
|
||||
// 状态前校验:仅处理已支付且未取消的抽奖订单
|
||||
if order.Status != 2 || order.SourceType != 2 {
|
||||
return nil
|
||||
}
|
||||
|
||||
aid := extractActivityID(order.Remark)
|
||||
iss := extractIssueID(order.Remark)
|
||||
dc := extractCount(order.Remark)
|
||||
icID := extractItemCardID(order.Remark)
|
||||
if aid <= 0 || iss <= 0 {
|
||||
return fmt.Errorf("订单备注关键信息缺失")
|
||||
}
|
||||
|
||||
orderNo := order.OrderNo
|
||||
userID := order.UserID
|
||||
|
||||
// 2.1 批量加载配置
|
||||
act, _ := s.readDB.Activities.WithContext(ctx).Where(s.readDB.Activities.ID.Eq(aid)).First()
|
||||
actName := "活动"
|
||||
playType := "default"
|
||||
if act != nil {
|
||||
actName = act.Name
|
||||
playType = act.PlayType
|
||||
}
|
||||
|
||||
rewardSettings, _ := s.readDB.ActivityRewardSettings.WithContext(ctx).Where(s.readDB.ActivityRewardSettings.IssueID.Eq(iss)).Find()
|
||||
rewardMap := make(map[int64]*model.ActivityRewardSettings)
|
||||
for _, r := range rewardSettings {
|
||||
rewardMap[r.ID] = r
|
||||
}
|
||||
|
||||
// 2.2 批量加载已有记录
|
||||
existingLogs, _ := s.readDB.ActivityDrawLogs.WithContext(ctx).Where(s.readDB.ActivityDrawLogs.OrderID.Eq(orderID)).Order(s.readDB.ActivityDrawLogs.DrawIndex).Find()
|
||||
logMap := make(map[int64]*model.ActivityDrawLogs)
|
||||
for _, l := range existingLogs {
|
||||
logMap[l.DrawIndex] = l
|
||||
}
|
||||
|
||||
existingInventory, _ := s.readDB.UserInventory.WithContext(ctx).Where(s.readDB.UserInventory.OrderID.Eq(orderID)).Find()
|
||||
invCountMap := make(map[int64]int64)
|
||||
for _, inv := range existingInventory {
|
||||
invCountMap[inv.RewardID]++
|
||||
}
|
||||
|
||||
// 2.3 策略准备
|
||||
var sel strat.ActivityDrawStrategy
|
||||
if act != nil && act.PlayType == "ichiban" {
|
||||
sel = strat.NewIchiban(s.readDB, s.writeDB)
|
||||
} else {
|
||||
sel = strat.NewDefault(s.readDB, s.writeDB)
|
||||
}
|
||||
idxs, cnts := parseSlotsCountsFromRemark(order.Remark)
|
||||
|
||||
// 3. 核心循环:基于内存快照进行原子发放
|
||||
for i := int64(0); i < dc; i++ {
|
||||
log, exists := logMap[i]
|
||||
if !exists {
|
||||
// 选品:如果日志不存在,则根据策略选出一个奖品 ID
|
||||
var rid int64
|
||||
var proof map[string]any
|
||||
var selErr error
|
||||
|
||||
if act != nil && act.PlayType == "ichiban" {
|
||||
slot := getSlotForIndex(i, idxs, cnts)
|
||||
if slot < 0 {
|
||||
continue
|
||||
}
|
||||
rid, proof, selErr = sel.SelectItemBySlot(ctx, aid, iss, slot)
|
||||
} else {
|
||||
rid, proof, selErr = sel.SelectItem(ctx, aid, iss, order.UserID)
|
||||
}
|
||||
|
||||
if selErr != nil || rid <= 0 {
|
||||
s.logger.Error("选品失败", zap.Int64("draw_index", i), zap.Error(selErr))
|
||||
continue
|
||||
}
|
||||
|
||||
rw := rewardMap[rid]
|
||||
if rw == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// 写入开奖日志 (依靠数据库 (order_id, draw_index) 唯一键保证绝对幂等)
|
||||
log = &model.ActivityDrawLogs{
|
||||
UserID: order.UserID, IssueID: iss, OrderID: order.ID,
|
||||
RewardID: rid, IsWinner: 1, Level: rw.Level, CurrentLevel: 1, DrawIndex: i,
|
||||
}
|
||||
if errLog := s.writeDB.ActivityDrawLogs.WithContext(ctx).Create(log); errLog != nil {
|
||||
// 并发情况:回退并尝试复用已有记录
|
||||
log, _ = s.readDB.ActivityDrawLogs.WithContext(ctx).Where(s.readDB.ActivityDrawLogs.OrderID.Eq(orderID), s.readDB.ActivityDrawLogs.DrawIndex.Eq(i)).First()
|
||||
if log == nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
_ = strat.SaveDrawReceipt(ctx, s.writeDB, log.ID, iss, order.UserID, proof)
|
||||
logMap[i] = log
|
||||
}
|
||||
|
||||
// 补发奖励校验:统计该 RewardID 应得数量并与实得数量对比
|
||||
needed := int64(0)
|
||||
for j := int64(0); j <= i; j++ {
|
||||
if l, ok := logMap[j]; ok && l.RewardID == log.RewardID {
|
||||
needed++
|
||||
}
|
||||
}
|
||||
|
||||
if invCountMap[log.RewardID] < needed {
|
||||
rw := rewardMap[log.RewardID]
|
||||
if rw != nil {
|
||||
_, errGrant := s.user.GrantRewardToOrder(ctx, order.UserID, usersvc.GrantRewardToOrderRequest{
|
||||
OrderID: order.ID, ProductID: rw.ProductID, Quantity: 1,
|
||||
ActivityID: &aid, RewardID: &log.RewardID, Remark: rw.Name,
|
||||
})
|
||||
if errGrant == nil {
|
||||
invCountMap[log.RewardID]++ // 内存计数同步
|
||||
// 处理道具卡
|
||||
if act != nil && act.AllowItemCards && icID > 0 {
|
||||
s.applyItemCardEffect(ctx, icID, aid, iss, log)
|
||||
}
|
||||
} else {
|
||||
s.logger.Error("奖励原子发放失败", zap.Int64("draw_index", i), zap.Error(errGrant))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 异步触发外部同步逻辑 (微信虚拟发货/通知)
|
||||
if order.IsConsumed == 0 {
|
||||
go s.TriggerVirtualShipping(context.Background(), orderID, orderNo, userID, aid, actName, playType)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TriggerVirtualShipping 触发虚拟发货同步到微信
|
||||
func (s *service) TriggerVirtualShipping(ctx context.Context, orderID int64, orderNo string, userID int64, aid int64, actName string, playType string) {
|
||||
drawLogs, _ := s.readDB.ActivityDrawLogs.WithContext(ctx).Where(s.readDB.ActivityDrawLogs.OrderID.Eq(orderID)).Find()
|
||||
if len(drawLogs) == 0 {
|
||||
return
|
||||
}
|
||||
var rewardNames []string
|
||||
for _, lg := range drawLogs {
|
||||
if rw, _ := s.readDB.ActivityRewardSettings.WithContext(ctx).Where(s.readDB.ActivityRewardSettings.ID.Eq(lg.RewardID)).First(); rw != nil {
|
||||
rewardNames = append(rewardNames, rw.Name)
|
||||
}
|
||||
}
|
||||
itemsDesc := actName + " " + orderNo + " 盲盒赏品: " + strings.Join(rewardNames, ", ")
|
||||
itemsDesc = utf8SafeTruncate(itemsDesc, 110) // 微信限制 128 字节,我们保守一点截断到 110
|
||||
tx, _ := s.readDB.PaymentTransactions.WithContext(ctx).Where(s.readDB.PaymentTransactions.OrderNo.Eq(orderNo)).First()
|
||||
if tx == nil || tx.TransactionID == "" {
|
||||
return
|
||||
}
|
||||
u, _ := s.readDB.Users.WithContext(ctx).Where(s.readDB.Users.ID.Eq(userID)).First()
|
||||
payerOpenid := ""
|
||||
if u != nil {
|
||||
payerOpenid = u.Openid
|
||||
}
|
||||
c := configs.Get()
|
||||
cfg := &wechat.WechatConfig{AppID: c.Wechat.AppID, AppSecret: c.Wechat.AppSecret}
|
||||
errUpload := wechat.UploadVirtualShippingForBackground(ctx, cfg, tx.TransactionID, orderNo, payerOpenid, itemsDesc)
|
||||
|
||||
// 如果发货成功,或者微信提示已经发过货了(10060003),则标记本地订单为已履约
|
||||
if errUpload == nil || strings.Contains(errUpload.Error(), "10060003") {
|
||||
_, _ = s.writeDB.Orders.WithContext(ctx).Where(s.readDB.Orders.ID.Eq(orderID)).Update(s.readDB.Orders.IsConsumed, 1)
|
||||
if errUpload != nil {
|
||||
s.logger.Info("[虚拟发货] 微信反馈已处理,更新本地标记", zap.String("order_no", orderNo))
|
||||
}
|
||||
} else if errUpload != nil {
|
||||
s.logger.Error("[虚拟发货] 上传失败", zap.Error(errUpload), zap.String("order_no", orderNo))
|
||||
}
|
||||
|
||||
if playType == "ichiban" {
|
||||
notifyCfg := ¬ify.WechatNotifyConfig{
|
||||
AppID: c.Wechat.AppID,
|
||||
AppSecret: c.Wechat.AppSecret,
|
||||
LotteryResultTemplateID: c.Wechat.LotteryResultTemplateID,
|
||||
}
|
||||
_ = notify.SendLotteryResultNotification(ctx, notifyCfg, payerOpenid, actName, rewardNames, orderNo, time.Now())
|
||||
}
|
||||
}
|
||||
|
||||
func (s *service) applyItemCardEffect(ctx context.Context, icID int64, aid int64, iss int64, log *model.ActivityDrawLogs) {
|
||||
uic, _ := s.readDB.UserItemCards.WithContext(ctx).Where(s.readDB.UserItemCards.ID.Eq(icID), s.readDB.UserItemCards.UserID.Eq(log.UserID), s.readDB.UserItemCards.Status.Eq(1)).First()
|
||||
if uic == nil {
|
||||
return
|
||||
}
|
||||
ic, _ := s.readDB.SystemItemCards.WithContext(ctx).Where(s.readDB.SystemItemCards.ID.Eq(uic.CardID), s.readDB.SystemItemCards.Status.Eq(1)).First()
|
||||
now := time.Now()
|
||||
if ic != nil && !uic.ValidStart.After(now) && !uic.ValidEnd.Before(now) {
|
||||
scopeOK := (ic.ScopeType == 1) || (ic.ScopeType == 3 && ic.ActivityID == aid) || (ic.ScopeType == 4 && ic.IssueID == iss)
|
||||
if scopeOK {
|
||||
if ic.EffectType == 1 && ic.RewardMultiplierX1000 >= 2000 {
|
||||
rw, _ := s.readDB.ActivityRewardSettings.WithContext(ctx).Where(s.readDB.ActivityRewardSettings.ID.Eq(log.RewardID)).First()
|
||||
if rw != nil {
|
||||
_, _ = s.user.GrantRewardToOrder(ctx, log.UserID, usersvc.GrantRewardToOrderRequest{OrderID: log.OrderID, ProductID: rw.ProductID, Quantity: 1, ActivityID: &aid, RewardID: &log.RewardID, Remark: rw.Name + "(倍数)"})
|
||||
}
|
||||
}
|
||||
_, _ = s.writeDB.UserItemCards.WithContext(ctx).Where(s.readDB.UserItemCards.ID.Eq(icID)).Updates(map[string]any{
|
||||
"status": 2,
|
||||
"used_draw_log_id": log.ID,
|
||||
"used_activity_id": aid,
|
||||
"used_issue_id": iss,
|
||||
"used_at": now,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助工具方法
|
||||
func extractActivityID(remark string) int64 { return parseActivityIDFromRemark(remark) }
|
||||
func extractIssueID(remark string) int64 { return parseIssueIDFromRemark(remark) }
|
||||
func extractCount(remark string) int64 { return parseCountFromRemark(remark) }
|
||||
func extractItemCardID(remark string) int64 { return parseItemCardIDFromRemark(remark) }
|
||||
|
||||
func parseActivityIDFromRemark(remark string) int64 {
|
||||
parts := strings.Split(remark, "|")
|
||||
for _, p := range parts {
|
||||
if strings.HasPrefix(p, "lottery:activity:") {
|
||||
return parseInt64(p[17:])
|
||||
}
|
||||
if strings.HasPrefix(p, "activity:") {
|
||||
return parseInt64(p[9:])
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
func parseIssueIDFromRemark(remark string) int64 {
|
||||
parts := strings.Split(remark, "|")
|
||||
for _, p := range parts {
|
||||
if strings.HasPrefix(p, "issue:") {
|
||||
return parseInt64(p[6:])
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
func parseCountFromRemark(remark string) int64 {
|
||||
parts := strings.Split(remark, "|")
|
||||
for _, p := range parts {
|
||||
if strings.HasPrefix(p, "count:") {
|
||||
n := parseInt64(p[6:])
|
||||
if n <= 0 {
|
||||
return 1
|
||||
}
|
||||
return n
|
||||
}
|
||||
}
|
||||
return 1
|
||||
}
|
||||
func parseItemCardIDFromRemark(remark string) int64 {
|
||||
parts := strings.Split(remark, "|")
|
||||
for _, seg := range parts {
|
||||
if len(seg) > 9 && seg[:9] == "itemcard:" {
|
||||
return parseInt64(seg[9:])
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
func parseInt64(s string) int64 {
|
||||
var n int64
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] < '0' || s[i] > '9' {
|
||||
break
|
||||
}
|
||||
n = n*10 + int64(s[i]-'0')
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// utf8SafeTruncate 按字节长度截断,并过滤掉无效/损坏的 UTF-8 字符
|
||||
func utf8SafeTruncate(s string, n int) string {
|
||||
r := []rune(s)
|
||||
var res []rune
|
||||
var byteLen int
|
||||
for _, val := range r {
|
||||
// 过滤掉无效字符标识 \ufffd,防止微信 API 报错
|
||||
if val == '\uFFFD' {
|
||||
continue
|
||||
}
|
||||
l := len(string(val))
|
||||
if byteLen+l > n {
|
||||
break
|
||||
}
|
||||
res = append(res, val)
|
||||
byteLen += l
|
||||
}
|
||||
return string(res)
|
||||
}
|
||||
func parseSlotsCountsFromRemark(remark string) ([]int64, []int64) {
|
||||
parts := strings.Split(remark, "|")
|
||||
for _, p := range parts {
|
||||
if strings.HasPrefix(p, "slots:") {
|
||||
pairs := p[6:]
|
||||
var idxs []int64
|
||||
var cnts []int64
|
||||
start := 0
|
||||
for start < len(pairs) {
|
||||
end := start
|
||||
for end < len(pairs) && pairs[end] != ',' {
|
||||
end++
|
||||
}
|
||||
if end > start {
|
||||
a := pairs[start:end]
|
||||
var x, y int64
|
||||
j := 0
|
||||
for j < len(a) && a[j] >= '0' && a[j] <= '9' {
|
||||
x = x*10 + int64(a[j]-'0')
|
||||
j++
|
||||
}
|
||||
if j < len(a) && a[j] == ':' {
|
||||
j++
|
||||
for j < len(a) && a[j] >= '0' && a[j] <= '9' {
|
||||
y = y*10 + int64(a[j]-'0')
|
||||
j++
|
||||
}
|
||||
}
|
||||
if y > 0 {
|
||||
idxs = append(idxs, x+1)
|
||||
cnts = append(cnts, y)
|
||||
}
|
||||
}
|
||||
start = end + 1
|
||||
}
|
||||
return idxs, cnts
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
func getSlotForIndex(drawIndex int64, idxs []int64, cnts []int64) int64 {
|
||||
var current int64
|
||||
for i := 0; i < len(idxs); i++ {
|
||||
if drawIndex < current+cnts[i] {
|
||||
return idxs[i] - 1
|
||||
}
|
||||
current += cnts[i]
|
||||
}
|
||||
return -1
|
||||
}
|
||||
@ -1,21 +1,18 @@
|
||||
package activity
|
||||
|
||||
import (
|
||||
"bindbox-game/configs"
|
||||
"bindbox-game/internal/pkg/logger"
|
||||
"bindbox-game/internal/pkg/notify"
|
||||
paypkg "bindbox-game/internal/pkg/pay"
|
||||
"bindbox-game/internal/pkg/wechat"
|
||||
"bindbox-game/internal/repository/mysql"
|
||||
"bindbox-game/internal/repository/mysql/dao"
|
||||
"bindbox-game/internal/repository/mysql/model"
|
||||
strat "bindbox-game/internal/service/activity/strategy"
|
||||
usersvc "bindbox-game/internal/service/user"
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
type scheduledConfig struct {
|
||||
@ -31,10 +28,11 @@ type scheduledConfig struct {
|
||||
RefundCouponID int64 `json:"refund_coupon_id"`
|
||||
}
|
||||
|
||||
func StartScheduledSettlement(l logger.CustomLogger, repo mysql.Repo) {
|
||||
func StartScheduledSettlement(l logger.CustomLogger, repo mysql.Repo, rdb *redis.Client) {
|
||||
r := dao.Use(repo.GetDbR())
|
||||
w := dao.Use(repo.GetDbW())
|
||||
us := usersvc.New(l, repo)
|
||||
activitySvc := New(l, repo, us, rdb)
|
||||
|
||||
// Ensure lottery_refund_logs table exists
|
||||
_ = repo.GetDbW().Exec(`CREATE TABLE IF NOT EXISTS lottery_refund_logs (
|
||||
@ -60,6 +58,9 @@ func StartScheduledSettlement(l logger.CustomLogger, repo mysql.Repo) {
|
||||
ctx := context.Background()
|
||||
now := time.Now()
|
||||
fmt.Printf("[定时开奖] ====== 开始检查 时间=%s ======\n", now.Format("2006-01-02 15:04:05"))
|
||||
|
||||
// 【独立检查】一番赏格位重置:每30秒检查所有售罄的一番赏期号
|
||||
checkAndResetIchibanSlots(ctx, repo, r)
|
||||
var acts []struct {
|
||||
ID int64
|
||||
PlayType string
|
||||
@ -122,6 +123,7 @@ func StartScheduledSettlement(l logger.CustomLogger, repo mysql.Repo) {
|
||||
orders, _ := r.Orders.WithContext(ctx).ReadDB().Where(
|
||||
r.Orders.Status.Eq(2),
|
||||
r.Orders.SourceType.Eq(2),
|
||||
r.Orders.IsConsumed.Eq(0), // 仅处理未履约的订单
|
||||
r.Orders.Remark.Like(fmt.Sprintf("lottery:activity:%d|%%", aid)),
|
||||
r.Orders.CreatedAt.Gte(last),
|
||||
).Find()
|
||||
@ -181,6 +183,61 @@ func StartScheduledSettlement(l logger.CustomLogger, repo mysql.Repo) {
|
||||
for _, o := range issueOrders {
|
||||
refundOrder(ctx, o, "ichiban_not_sold_out", wc, r, w, us, a.RefundCouponID)
|
||||
}
|
||||
} else {
|
||||
// 【Fix】已售罄:处理所有未开奖的订单(包括旧时间窗口的订单)
|
||||
fmt.Printf("[定时开奖-一番赏] ✅ IssueID=%d 已售罄,检查并处理所有未开奖订单\n", iss)
|
||||
|
||||
// Step 1: Get all order IDs from claims for this issue
|
||||
var claimOrderIDs []int64
|
||||
errClaims := repo.GetDbR().Raw(`
|
||||
SELECT DISTINCT c.order_id FROM issue_position_claims c
|
||||
LEFT JOIN activity_draw_logs l ON l.order_id = c.order_id AND l.issue_id = c.issue_id
|
||||
WHERE c.issue_id = ? AND l.id IS NULL
|
||||
`, iss).Scan(&claimOrderIDs).Error
|
||||
|
||||
if errClaims != nil {
|
||||
fmt.Printf("[定时开奖-一番赏] ❌ 查询未处理订单ID失败: %v\n", errClaims)
|
||||
}
|
||||
|
||||
fmt.Printf("[定时开奖-一番赏] IssueID=%d 查询到 %d 个未处理订单ID: %v\n", iss, len(claimOrderIDs), claimOrderIDs)
|
||||
|
||||
if len(claimOrderIDs) > 0 {
|
||||
// Step 2: Fetch the actual order records
|
||||
unprocessedOrders, errOrders := r.Orders.WithContext(ctx).Where(
|
||||
r.Orders.ID.In(claimOrderIDs...),
|
||||
r.Orders.Status.Eq(2),
|
||||
).Find()
|
||||
|
||||
if errOrders != nil {
|
||||
fmt.Printf("[定时开奖-一番赏] ❌ 获取订单详情失败: %v\n", errOrders)
|
||||
}
|
||||
|
||||
fmt.Printf("[定时开奖-一番赏] IssueID=%d 发现 %d 个未处理订单,开始补录\n", iss, len(unprocessedOrders))
|
||||
for _, o := range unprocessedOrders {
|
||||
if err := activitySvc.ProcessOrderLottery(ctx, o.ID); err != nil {
|
||||
fmt.Printf("[定时开奖-一番赏-补录] ❌ ProcessOrderLottery 失败: %v\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 【直接重置】无论是否有待处理订单,检查该期号是否可以重置
|
||||
var remainingUnprocessed int64
|
||||
_ = repo.GetDbR().Raw(`
|
||||
SELECT COUNT(1) FROM issue_position_claims c
|
||||
LEFT JOIN activity_draw_logs l ON l.order_id = c.order_id AND l.issue_id = c.issue_id
|
||||
WHERE c.issue_id = ? AND l.id IS NULL
|
||||
`, iss).Scan(&remainingUnprocessed)
|
||||
|
||||
fmt.Printf("[定时开奖-一番赏] IssueID=%d 剩余未处理订单数: %d\n", iss, remainingUnprocessed)
|
||||
|
||||
if remainingUnprocessed == 0 {
|
||||
// 所有订单都已处理,执行重置
|
||||
if err := repo.GetDbW().Exec("DELETE FROM issue_position_claims WHERE issue_id = ?", iss).Error; err != nil {
|
||||
fmt.Printf("[定时开奖-一番赏] ❌ 重置格位失败: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("[定时开奖-一番赏] ✅ IssueID=%d 所有订单已处理,格位已重置,新一轮可以开始\n", iss)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -199,154 +256,14 @@ func StartScheduledSettlement(l logger.CustomLogger, repo mysql.Repo) {
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("[定时开奖] 活动ID=%d ✅ 人数满足(或一番赏模式),开始开奖处理\n", aid)
|
||||
if a.PlayType == "ichiban" {
|
||||
fmt.Printf("[定时开奖] 活动ID=%d 一番赏模式开奖,订单数=%d\n", aid, len(orders))
|
||||
// 一番赏定时开奖逻辑
|
||||
ichibanSel := strat.NewIchiban(r, w)
|
||||
for _, o := range orders {
|
||||
iss := extractIssueID(o.Remark)
|
||||
|
||||
if refundedIssues[iss] {
|
||||
fmt.Printf("[定时开奖-一番赏] OrderID=%d IssueID=%d 已退款,跳过开奖\n", o.ID, iss)
|
||||
continue
|
||||
}
|
||||
|
||||
uid := o.UserID
|
||||
fmt.Printf("[定时开奖-一番赏] 处理订单 OrderID=%d UserID=%d IssueID=%d\n", o.ID, uid, iss)
|
||||
|
||||
// 检查是否已经处理过
|
||||
logs, _ := r.ActivityDrawLogs.WithContext(ctx).Where(r.ActivityDrawLogs.OrderID.Eq(o.ID)).Find()
|
||||
if len(logs) > 0 {
|
||||
fmt.Printf("[定时开奖-一番赏] 订单ID=%d 已处理过,跳过\n", o.ID)
|
||||
continue
|
||||
}
|
||||
|
||||
// 查找该订单锁定的所有格位
|
||||
claims, _ := r.IssuePositionClaims.WithContext(ctx).ReadDB().Where(
|
||||
r.IssuePositionClaims.IssueID.Eq(iss),
|
||||
r.IssuePositionClaims.OrderID.Eq(o.ID),
|
||||
).Find()
|
||||
fmt.Printf("[定时开奖-一番赏] 订单ID=%d 找到格位占用数=%d\n", o.ID, len(claims))
|
||||
|
||||
for claimIdx, claim := range claims {
|
||||
fmt.Printf("[定时开奖-一番赏] 处理格位 SlotIndex=%d (索引=%d)\n", claim.SlotIndex, claimIdx)
|
||||
|
||||
// 【幂等检查】检查该订单的该格位是否已经发过奖
|
||||
existingLogCnt, _ := r.ActivityDrawLogs.WithContext(ctx).Where(
|
||||
r.ActivityDrawLogs.OrderID.Eq(o.ID),
|
||||
r.ActivityDrawLogs.IssueID.Eq(iss),
|
||||
).Count()
|
||||
if existingLogCnt > int64(claimIdx) {
|
||||
fmt.Printf("[定时开奖-一番赏] ⚠️ 格位 SlotIndex=%d 已处理过(日志数=%d,当前索引=%d),跳过\n", claim.SlotIndex, existingLogCnt, claimIdx)
|
||||
continue
|
||||
}
|
||||
|
||||
// 使用 claim 中的 slot_index 直接获取奖品
|
||||
// Use Commitment (via SelectItemBySlot internal logic)
|
||||
rid, proof, err := ichibanSel.SelectItemBySlot(ctx, aid, iss, claim.SlotIndex)
|
||||
if err != nil || rid <= 0 {
|
||||
fmt.Printf("[定时开奖-一番赏] ❌ SelectItemBySlot失败 err=%v rid=%d\n", err, rid)
|
||||
continue
|
||||
}
|
||||
|
||||
rw, err := r.ActivityRewardSettings.WithContext(ctx).Where(r.ActivityRewardSettings.ID.Eq(rid)).First()
|
||||
if err != nil || rw == nil {
|
||||
fmt.Printf("[定时开奖-一番赏] ❌ 奖品设置不存在 rid=%d\n", rid)
|
||||
continue
|
||||
}
|
||||
|
||||
// 【先记录日志,再发奖】确保日志创建成功后再发奖,防止重复
|
||||
drawLog := &model.ActivityDrawLogs{
|
||||
UserID: uid,
|
||||
IssueID: iss,
|
||||
OrderID: o.ID,
|
||||
RewardID: rid,
|
||||
IsWinner: 1,
|
||||
Level: rw.Level,
|
||||
CurrentLevel: 1,
|
||||
}
|
||||
if err := w.ActivityDrawLogs.WithContext(ctx).Create(drawLog); err != nil {
|
||||
fmt.Printf("[定时开奖-一番赏] ❌ 创建开奖日志失败 err=%v,可能已存在,跳过\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// 发放奖励(在原订单上添加中奖商品,不创建新订单)
|
||||
fmt.Printf("[定时开奖-一番赏] 发放奖励到原订单 OrderID=%d UserID=%d RewardID=%d 奖品名=%s\n", o.ID, uid, rid, rw.Name)
|
||||
_, err = us.GrantRewardToOrder(ctx, uid, usersvc.GrantRewardToOrderRequest{
|
||||
OrderID: o.ID,
|
||||
ProductID: rw.ProductID,
|
||||
Quantity: 1,
|
||||
ActivityID: &aid,
|
||||
RewardID: &rid,
|
||||
Remark: rw.Name,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Printf("[定时开奖-一番赏] ⚠️ 发放奖励失败 err=%v\n", err)
|
||||
}
|
||||
|
||||
fmt.Printf("[定时开奖-一番赏] ✅ 开奖成功 UserID=%d OrderID=%d RewardID=%d\n", uid, o.ID, rid)
|
||||
|
||||
// 保存可验证凭据
|
||||
if err := strat.SaveDrawReceipt(ctx, w, drawLog.ID, iss, uid, proof); err != nil {
|
||||
fmt.Printf("[定时开奖-一番赏] ⚠️ 保存凭据失败 DrawLogID=%d IssueID=%d UserID=%d err=%v proof=%+v\n", drawLog.ID, iss, uid, err, proof)
|
||||
} else {
|
||||
fmt.Printf("[定时开奖-一番赏] ✅ 保存凭据成功 DrawLogID=%d IssueID=%d\n", drawLog.ID, iss)
|
||||
}
|
||||
}
|
||||
// 【开奖后虚拟发货】定时一番赏开奖后上传虚拟发货
|
||||
uploadVirtualShippingForScheduledDraw(ctx, r, o.ID, o.OrderNo, uid, func() string {
|
||||
act, _ := r.Activities.WithContext(ctx).Where(r.Activities.ID.Eq(aid)).First()
|
||||
if act != nil {
|
||||
return act.Name
|
||||
}
|
||||
return "活动"
|
||||
}(), "ichiban")
|
||||
for _, o := range orders {
|
||||
iss := extractIssueID(o.Remark)
|
||||
if a.PlayType == "ichiban" && refundedIssues[iss] {
|
||||
fmt.Printf("[定时开奖-一番赏] OrderID=%d IssueID=%d 已退款,跳过开奖\n", o.ID, iss)
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
// 默认玩法逻辑
|
||||
sel := strat.NewDefault(r, w)
|
||||
// Daily Seed removed
|
||||
for _, o := range orders {
|
||||
uid := o.UserID
|
||||
iss := extractIssueID(o.Remark)
|
||||
dc := extractCount(o.Remark)
|
||||
if dc <= 0 {
|
||||
dc = 1
|
||||
}
|
||||
logs, _ := r.ActivityDrawLogs.WithContext(ctx).Where(r.ActivityDrawLogs.OrderID.Eq(o.ID)).Find()
|
||||
done := int64(len(logs))
|
||||
for i := done; i < dc; i++ {
|
||||
rid, proof, err := sel.SelectItem(ctx, aid, iss, uid)
|
||||
if err != nil || rid <= 0 {
|
||||
break
|
||||
}
|
||||
rw, err := r.ActivityRewardSettings.WithContext(ctx).Where(r.ActivityRewardSettings.ID.Eq(rid)).First()
|
||||
if err != nil || rw == nil {
|
||||
break
|
||||
}
|
||||
// 【先记录日志,再发奖】确保日志创建成功后再发奖,防止重复
|
||||
drawLog := &model.ActivityDrawLogs{UserID: uid, IssueID: iss, OrderID: o.ID, RewardID: rid, IsWinner: 1, Level: rw.Level, CurrentLevel: 1}
|
||||
if err := w.ActivityDrawLogs.WithContext(ctx).Create(drawLog); err != nil {
|
||||
fmt.Printf("[定时开奖-默认] ❌ 创建开奖日志失败 err=%v,可能已存在,跳过\n", err)
|
||||
break
|
||||
}
|
||||
// 发放奖励(在原订单上添加中奖商品,不创建新订单)
|
||||
_, _ = us.GrantRewardToOrder(ctx, uid, usersvc.GrantRewardToOrderRequest{OrderID: o.ID, ProductID: rw.ProductID, Quantity: 1, ActivityID: &aid, RewardID: &rid, Remark: rw.Name})
|
||||
// 保存可验证凭据
|
||||
if err := strat.SaveDrawReceipt(ctx, w, drawLog.ID, iss, uid, proof); err != nil {
|
||||
fmt.Printf("[定时开奖-默认] ⚠️ 保存凭据失败 DrawLogID=%d IssueID=%d UserID=%d err=%v proof=%+v\n", drawLog.ID, iss, uid, err, proof)
|
||||
} else {
|
||||
fmt.Printf("[定时开奖-默认] ✅ 保存凭据成功 DrawLogID=%d IssueID=%d\n", drawLog.ID, iss)
|
||||
}
|
||||
}
|
||||
// 【开奖后虚拟发货】定时开奖后上传虚拟发货(非一番赏不发通知)
|
||||
uploadVirtualShippingForScheduledDraw(ctx, r, o.ID, o.OrderNo, uid, func() string {
|
||||
act, _ := r.Activities.WithContext(ctx).Where(r.Activities.ID.Eq(aid)).First()
|
||||
if act != nil {
|
||||
return act.Name
|
||||
}
|
||||
return "活动"
|
||||
}(), "default")
|
||||
if err := activitySvc.ProcessOrderLottery(ctx, o.ID); err != nil {
|
||||
fmt.Printf("[定时开奖] ❌ ProcessOrderLottery 失败: %v\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -371,45 +288,18 @@ func StartScheduledSettlement(l logger.CustomLogger, repo mysql.Repo) {
|
||||
}
|
||||
_ = repo.GetDbR().WithContext(ctx).Raw("SELECT id FROM activities WHERE draw_mode='instant'").Scan(&instantActs)
|
||||
if len(instantActs) > 0 {
|
||||
sel2 := strat.NewDefault(r, w)
|
||||
for _, ia := range instantActs {
|
||||
orders2, _ := r.Orders.WithContext(ctx).ReadDB().Where(
|
||||
r.Orders.Status.Eq(2),
|
||||
r.Orders.SourceType.Eq(2),
|
||||
r.Orders.IsConsumed.Eq(0), // 仅处理未履约的订单
|
||||
r.Orders.Remark.Like(fmt.Sprintf("lottery:activity:%d|%%", ia.ID)),
|
||||
r.Orders.CreatedAt.Lt(now.Add(-5*time.Minute)),
|
||||
r.Orders.CreatedAt.Gt(now.Add(-24*time.Hour)), // 限制时间窗口为24小时,避免全表扫描
|
||||
).Find()
|
||||
// Daily Seed removed
|
||||
for _, o2 := range orders2 {
|
||||
uid := o2.UserID
|
||||
iss := extractIssueID(o2.Remark)
|
||||
dc := extractCount(o2.Remark)
|
||||
if dc <= 0 {
|
||||
dc = 1
|
||||
}
|
||||
logs2, _ := r.ActivityDrawLogs.WithContext(ctx).Where(r.ActivityDrawLogs.OrderID.Eq(o2.ID)).Find()
|
||||
done2 := int64(len(logs2))
|
||||
for i := done2; i < dc; i++ {
|
||||
rid, proof, err := sel2.SelectItem(ctx, ia.ID, iss, uid)
|
||||
if err != nil || rid <= 0 {
|
||||
break
|
||||
}
|
||||
rw, err := r.ActivityRewardSettings.WithContext(ctx).Where(r.ActivityRewardSettings.ID.Eq(rid)).First()
|
||||
if err != nil || rw == nil {
|
||||
break
|
||||
}
|
||||
// 【先记录日志,再发奖】确保日志创建成功后再发奖,防止重复
|
||||
drawLog := &model.ActivityDrawLogs{UserID: uid, IssueID: iss, OrderID: o2.ID, RewardID: rid, IsWinner: 1, Level: rw.Level, CurrentLevel: 1}
|
||||
if err := w.ActivityDrawLogs.WithContext(ctx).Create(drawLog); err != nil {
|
||||
fmt.Printf("[即时开奖补偿] ❌ 创建开奖日志失败 err=%v,可能已存在,跳过\n", err)
|
||||
break
|
||||
}
|
||||
_, _ = us.GrantRewardToOrder(ctx, uid, usersvc.GrantRewardToOrderRequest{OrderID: o2.ID, ProductID: rw.ProductID, Quantity: 1, ActivityID: &ia.ID, RewardID: &rid, Remark: rw.Name})
|
||||
// 保存可验证凭据
|
||||
if err := strat.SaveDrawReceipt(ctx, w, drawLog.ID, iss, uid, proof); err != nil {
|
||||
fmt.Printf("[即时开奖补偿] ⚠️ 保存凭据失败 DrawLogID=%d IssueID=%d UserID=%d err=%v proof=%+v\n", drawLog.ID, iss, uid, err, proof)
|
||||
} else {
|
||||
fmt.Printf("[即时开奖补偿] ✅ 保存凭据成功 DrawLogID=%d IssueID=%d\n", drawLog.ID, iss)
|
||||
}
|
||||
if err := activitySvc.ProcessOrderLottery(ctx, o2.ID); err != nil {
|
||||
fmt.Printf("[即时开奖补偿] ❌ ProcessOrderLottery 失败: %v\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -418,6 +308,53 @@ func StartScheduledSettlement(l logger.CustomLogger, repo mysql.Repo) {
|
||||
}()
|
||||
}
|
||||
|
||||
// checkAndResetIchibanSlots 检查并重置所有售罄且已完成的一番赏期号
|
||||
func checkAndResetIchibanSlots(ctx context.Context, repo mysql.Repo, r *dao.Query) {
|
||||
// 查找所有一番赏活动下的活跃期号
|
||||
var issuesWithClaims []struct {
|
||||
IssueID int64
|
||||
TotalSlots int64
|
||||
SoldSlots int64
|
||||
}
|
||||
|
||||
err := repo.GetDbR().Raw(`
|
||||
SELECT
|
||||
ai.id as issue_id,
|
||||
(SELECT COUNT(*) FROM activity_reward_settings WHERE issue_id = ai.id) as total_slots,
|
||||
(SELECT COUNT(*) FROM issue_position_claims WHERE issue_id = ai.id) as sold_slots
|
||||
FROM activity_issues ai
|
||||
INNER JOIN activities a ON a.id = ai.activity_id
|
||||
WHERE a.play_type = 'ichiban' AND a.status = 1 AND ai.status = 1
|
||||
HAVING sold_slots > 0 AND sold_slots >= total_slots
|
||||
`).Scan(&issuesWithClaims).Error
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("[一番赏重置检查] 查询失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, iss := range issuesWithClaims {
|
||||
// 检查是否所有订单都已处理(有draw logs)
|
||||
var unprocessedCnt int64
|
||||
_ = repo.GetDbR().Raw(`
|
||||
SELECT COUNT(1) FROM issue_position_claims c
|
||||
LEFT JOIN activity_draw_logs l ON l.order_id = c.order_id AND l.issue_id = c.issue_id
|
||||
WHERE c.issue_id = ? AND l.id IS NULL
|
||||
`, iss.IssueID).Scan(&unprocessedCnt)
|
||||
|
||||
if unprocessedCnt == 0 {
|
||||
// 所有订单都已处理,执行重置
|
||||
if err := repo.GetDbW().Exec("DELETE FROM issue_position_claims WHERE issue_id = ?", iss.IssueID).Error; err != nil {
|
||||
fmt.Printf("[一番赏重置检查] ❌ IssueID=%d 重置失败: %v\n", iss.IssueID, err)
|
||||
} else {
|
||||
fmt.Printf("[一番赏重置检查] ✅ IssueID=%d 已售罄且全部处理完成,格位已重置\n", iss.IssueID)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("[一番赏重置检查] IssueID=%d 已售罄但仍有 %d 个未处理订单\n", iss.IssueID, unprocessedCnt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func parseTime(s string) time.Time {
|
||||
if s == "" {
|
||||
return time.Time{}
|
||||
@ -431,95 +368,9 @@ func parseTime(s string) time.Time {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
func parseInt64(s string) int64 {
|
||||
var n int64
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if c < '0' || c > '9' {
|
||||
break
|
||||
}
|
||||
n = n*10 + int64(c-'0')
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func extractIssueID(remark string) int64 {
|
||||
if remark == "" {
|
||||
return 0
|
||||
}
|
||||
parts := strings.Split(remark, "|")
|
||||
for _, p := range parts {
|
||||
if strings.HasPrefix(p, "issue:") {
|
||||
return parseInt64(p[6:])
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func extractCount(remark string) int64 {
|
||||
if remark == "" {
|
||||
return 1
|
||||
}
|
||||
parts := strings.Split(remark, "|")
|
||||
for _, p := range parts {
|
||||
if strings.HasPrefix(p, "count:") {
|
||||
return parseInt64(p[6:])
|
||||
}
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
// uploadVirtualShippingForScheduledDraw 定时开奖后上传虚拟发货
|
||||
// 收集中奖产品名称并调用微信虚拟发货API
|
||||
// playType: 活动玩法类型,只有 ichiban 时才发送开奖结果通知
|
||||
func uploadVirtualShippingForScheduledDraw(ctx context.Context, r *dao.Query, orderID int64, orderNo string, userID int64, actName string, playType string) {
|
||||
// 获取开奖记录
|
||||
drawLogs, _ := r.ActivityDrawLogs.WithContext(ctx).Where(r.ActivityDrawLogs.OrderID.Eq(orderID)).Find()
|
||||
if len(drawLogs) == 0 {
|
||||
fmt.Printf("[定时开奖-虚拟发货] 没有开奖记录,跳过 order_id=%d\n", orderID)
|
||||
return
|
||||
}
|
||||
// 收集赏品名称
|
||||
var rewardNames []string
|
||||
for _, lg := range drawLogs {
|
||||
if rw, _ := r.ActivityRewardSettings.WithContext(ctx).Where(r.ActivityRewardSettings.ID.Eq(lg.RewardID)).First(); rw != nil {
|
||||
rewardNames = append(rewardNames, rw.Name)
|
||||
}
|
||||
}
|
||||
itemsDesc := actName + " " + orderNo + " 盲盒赏品: " + strings.Join(rewardNames, ", ")
|
||||
if len(itemsDesc) > 120 {
|
||||
itemsDesc = itemsDesc[:120]
|
||||
}
|
||||
// 获取支付交易信息
|
||||
tx, _ := r.PaymentTransactions.WithContext(ctx).Where(r.PaymentTransactions.OrderNo.Eq(orderNo)).First()
|
||||
if tx == nil || tx.TransactionID == "" {
|
||||
fmt.Printf("[定时开奖-虚拟发货] 没有支付交易记录,跳过 order_no=%s\n", orderNo)
|
||||
return
|
||||
}
|
||||
// 获取用户openid
|
||||
u, _ := r.Users.WithContext(ctx).Where(r.Users.ID.Eq(userID)).First()
|
||||
payerOpenid := ""
|
||||
if u != nil {
|
||||
payerOpenid = u.Openid
|
||||
}
|
||||
// 获取微信配置
|
||||
c := configs.Get()
|
||||
cfg := &wechat.WechatConfig{AppID: c.Wechat.AppID, AppSecret: c.Wechat.AppSecret}
|
||||
fmt.Printf("[定时开奖-虚拟发货] 上传 order_no=%s transaction_id=%s items_desc=%s\n", orderNo, tx.TransactionID, itemsDesc)
|
||||
if err := wechat.UploadVirtualShippingForBackground(ctx, cfg, tx.TransactionID, orderNo, payerOpenid, itemsDesc); err != nil {
|
||||
fmt.Printf("[定时开奖-虚拟发货] 上传失败: %v\n", err)
|
||||
}
|
||||
// 【定时开奖后推送通知】只有一番赏才发送
|
||||
if playType == "ichiban" {
|
||||
notifyCfg := ¬ify.WechatNotifyConfig{
|
||||
AppID: c.Wechat.AppID,
|
||||
AppSecret: c.Wechat.AppSecret,
|
||||
LotteryResultTemplateID: c.Wechat.LotteryResultTemplateID,
|
||||
}
|
||||
_ = notify.SendLotteryResultNotification(ctx, notifyCfg, payerOpenid, actName, rewardNames, orderNo, time.Now())
|
||||
}
|
||||
}
|
||||
|
||||
func refundOrder(ctx context.Context, o *model.Orders, reason string, wc *paypkg.WechatPayClient, r *dao.Query, w *dao.Query, us usersvc.Service, refundCouponID int64) {
|
||||
// 1. Refund Points
|
||||
if o.PointsAmount > 0 {
|
||||
@ -532,6 +383,8 @@ func refundOrder(ctx context.Context, o *model.Orders, reason string, wc *paypkg
|
||||
refundNo := fmt.Sprintf("R%s-%d", o.OrderNo, time.Now().Unix())
|
||||
refundID, status, err := wc.RefundOrder(ctx, o.OrderNo, refundNo, o.ActualAmount, o.ActualAmount, reason)
|
||||
if err == nil {
|
||||
// 修复:raw 字段需要有效的 JSON 值,不能为空
|
||||
rawJSON := fmt.Sprintf(`{"refund_id":"%s","status":"%s"}`, refundID, status)
|
||||
_ = w.PaymentRefunds.WithContext(ctx).Create(&model.PaymentRefunds{
|
||||
OrderID: o.ID,
|
||||
OrderNo: o.OrderNo,
|
||||
@ -541,6 +394,7 @@ func refundOrder(ctx context.Context, o *model.Orders, reason string, wc *paypkg
|
||||
AmountRefund: o.ActualAmount,
|
||||
Reason: reason,
|
||||
SuccessTime: time.Now(),
|
||||
Raw: rawJSON,
|
||||
})
|
||||
_ = w.UserPointsLedger.WithContext(ctx).Create(&model.UserPointsLedger{UserID: o.UserID, Action: "refund_amount", Points: o.ActualAmount / 100, RefTable: "payment_refund", RefID: refundID})
|
||||
} else {
|
||||
@ -577,6 +431,31 @@ func refundOrder(ctx context.Context, o *model.Orders, reason string, wc *paypkg
|
||||
}
|
||||
}
|
||||
|
||||
// 3.6. 退还道具卡(支持两种记录方式)
|
||||
// 方式1:从 activity_draw_effects 表查询(无限赏等游戏类型)
|
||||
var itemCardIDs []int64
|
||||
_ = r.Orders.WithContext(ctx).UnderlyingDB().Raw("SELECT user_item_card_id FROM activity_draw_effects WHERE draw_log_id IN (SELECT id FROM activity_draw_logs WHERE order_id=?)", o.ID).Scan(&itemCardIDs).Error
|
||||
// 方式2:从 user_item_cards 表的 used_draw_log_id 直接查询(对对碰等游戏类型)
|
||||
var itemCardIDsFromItemCards []int64
|
||||
_ = r.Orders.WithContext(ctx).UnderlyingDB().Raw("SELECT id FROM user_item_cards WHERE used_draw_log_id IN (SELECT id FROM activity_draw_logs WHERE order_id=?) AND status=2", o.ID).Scan(&itemCardIDsFromItemCards).Error
|
||||
// 合并去重
|
||||
idSet := make(map[int64]struct{})
|
||||
for _, icID := range itemCardIDs {
|
||||
if icID > 0 {
|
||||
idSet[icID] = struct{}{}
|
||||
}
|
||||
}
|
||||
for _, icID := range itemCardIDsFromItemCards {
|
||||
if icID > 0 {
|
||||
idSet[icID] = struct{}{}
|
||||
}
|
||||
}
|
||||
// 执行退还
|
||||
for icID := range idSet {
|
||||
_ = w.Orders.WithContext(ctx).UnderlyingDB().Exec("UPDATE user_item_cards SET status=1, used_at=NULL, used_draw_log_id=0, used_activity_id=0, used_issue_id=0, updated_at=NOW(3) WHERE id=?", icID).Error
|
||||
fmt.Printf("[Refund] ✅ Restored item card %d for order %s\n", icID, o.OrderNo)
|
||||
}
|
||||
|
||||
// 4. Update Order Status
|
||||
_, _ = w.Orders.WithContext(ctx).Where(w.Orders.ID.Eq(o.ID)).Updates(map[string]any{w.Orders.Status.ColumnName().String(): 4})
|
||||
|
||||
|
||||
@ -88,6 +88,10 @@ func (s *defaultStrategy) SelectItem(ctx context.Context, activityID int64, issu
|
||||
return picked, proof, nil
|
||||
}
|
||||
|
||||
func (s *defaultStrategy) SelectItemBySlot(ctx context.Context, activityID int64, issueID int64, slotIndex int64) (int64, map[string]any, error) {
|
||||
return 0, nil, errors.New("default strategy does not support SelectItemBySlot")
|
||||
}
|
||||
|
||||
func (s *defaultStrategy) GrantReward(ctx context.Context, userID int64, rewardID int64) error {
|
||||
// 【使用乐观锁扣减库存】直接用 Quantity > 0 作为更新条件,避免并发超卖
|
||||
result, err := s.write.ActivityRewardSettings.WithContext(ctx).Where(
|
||||
|
||||
@ -15,10 +15,18 @@ type ichibanStrategy struct {
|
||||
write *dao.Query
|
||||
}
|
||||
|
||||
func NewIchiban(read *dao.Query, write *dao.Query) *ichibanStrategy {
|
||||
func NewIchiban(read *dao.Query, write *dao.Query) ActivityDrawStrategy {
|
||||
return &ichibanStrategy{read: read, write: write}
|
||||
}
|
||||
|
||||
func (s *ichibanStrategy) PreChecks(ctx context.Context, activityID int64, issueID int64, userID int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ichibanStrategy) SelectItem(ctx context.Context, activityID int64, issueID int64, userID int64) (int64, map[string]any, error) {
|
||||
return 0, nil, errors.New("ichiban strategy requires SelectItemBySlot")
|
||||
}
|
||||
|
||||
func (s *ichibanStrategy) SelectItemBySlot(ctx context.Context, activityID int64, issueID int64, slotIndex int64) (int64, map[string]any, error) {
|
||||
act, err := s.read.Activities.WithContext(ctx).Where(s.read.Activities.ID.Eq(activityID)).First()
|
||||
if err != nil || act == nil || len(act.CommitmentSeedMaster) == 0 {
|
||||
@ -77,3 +85,7 @@ func (s *ichibanStrategy) GrantReward(ctx context.Context, userID int64, rewardI
|
||||
// 这里保留接口兼容性,实际的占用检查在调用方完成
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ichibanStrategy) PostEffects(ctx context.Context, userID int64, activityID int64, issueID int64, rewardID int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ import (
|
||||
type ActivityDrawStrategy interface {
|
||||
PreChecks(ctx context.Context, activityID int64, issueID int64, userID int64) error
|
||||
SelectItem(ctx context.Context, activityID int64, issueID int64, userID int64) (int64, map[string]any, error)
|
||||
SelectItemBySlot(ctx context.Context, activityID int64, issueID int64, slotIndex int64) (int64, map[string]any, error)
|
||||
GrantReward(ctx context.Context, userID int64, rewardID int64) error
|
||||
PostEffects(ctx context.Context, userID int64, activityID int64, issueID int64, rewardID int64) error
|
||||
}
|
||||
|
||||
@ -8,7 +8,11 @@ import (
|
||||
"bindbox-game/configs"
|
||||
"bindbox-game/internal/repository/mysql/model"
|
||||
|
||||
"bindbox-game/internal/pkg/wechat"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type shareClaims struct {
|
||||
@ -42,16 +46,43 @@ func parseShareToken(tokenString string) (*shareClaims, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (s *service) CreateAddressShare(ctx context.Context, userID int64, inventoryID int64, expiresAt time.Time) (string, time.Time, error) {
|
||||
_, err := s.readDB.UserInventory.WithContext(ctx).Where(s.readDB.UserInventory.UserID.Eq(userID), s.readDB.UserInventory.ID.Eq(inventoryID), s.readDB.UserInventory.Status.Eq(1)).First()
|
||||
func (s *service) CreateAddressShare(ctx context.Context, userID int64, inventoryID int64, expiresAt time.Time) (string, string, time.Time, error) {
|
||||
inv, err := s.readDB.UserInventory.WithContext(ctx).Where(s.readDB.UserInventory.UserID.Eq(userID), s.readDB.UserInventory.ID.Eq(inventoryID), s.readDB.UserInventory.Status.Eq(1)).First()
|
||||
if err != nil {
|
||||
return "", time.Time{}, err
|
||||
return "", "", time.Time{}, err
|
||||
}
|
||||
token, err := signShareToken(userID, inventoryID, expiresAt)
|
||||
if err != nil {
|
||||
return "", time.Time{}, err
|
||||
return "", "", time.Time{}, err
|
||||
}
|
||||
return token, expiresAt, nil
|
||||
|
||||
// 尝试生成微信小程序 ShortLink
|
||||
shortLink := ""
|
||||
c := configs.Get()
|
||||
if c.Wechat.AppID != "" && c.Wechat.AppSecret != "" {
|
||||
wcfg := &wechat.WechatConfig{AppID: c.Wechat.AppID, AppSecret: c.Wechat.AppSecret}
|
||||
at, errat := wechat.GetAccessTokenWithContext(ctx, wcfg)
|
||||
if errat == nil {
|
||||
pagePath := fmt.Sprintf("pages/address/submit?token=%s", token)
|
||||
pageTitle := "送你一个好礼,快来填写地址领走吧!"
|
||||
if inv.Remark != "" {
|
||||
pageTitle = fmt.Sprintf("送你一个%s,快来领走吧!", inv.Remark)
|
||||
}
|
||||
sl, errsl := wechat.GetShortLink(at, pagePath, pageTitle)
|
||||
if errsl == nil {
|
||||
shortLink = sl
|
||||
s.logger.Info("成功生成微信短链", zap.String("short_link", shortLink))
|
||||
} else {
|
||||
s.logger.Error("生成微信短链失败", zap.Error(errsl), zap.String("page_path", pagePath))
|
||||
}
|
||||
} else {
|
||||
s.logger.Error("获取微信AccessToken失败", zap.Error(errat))
|
||||
}
|
||||
} else {
|
||||
s.logger.Warn("微信配置缺失,跳过短链生成", zap.String("appid", c.Wechat.AppID))
|
||||
}
|
||||
|
||||
return token, shortLink, expiresAt, nil
|
||||
}
|
||||
|
||||
func (s *service) RevokeAddressShare(ctx context.Context, userID int64, inventoryID int64) error {
|
||||
@ -63,17 +94,16 @@ func (s *service) SubmitAddressShare(ctx context.Context, shareToken string, nam
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("invalid_or_expired_token")
|
||||
}
|
||||
|
||||
// 1. 基本安全校验
|
||||
cnt, err := s.readDB.ShippingRecords.WithContext(ctx).Where(
|
||||
s.readDB.ShippingRecords.InventoryID.Eq(claims.InventoryID),
|
||||
s.readDB.ShippingRecords.Status.Neq(5), // Ignore cancelled
|
||||
s.readDB.ShippingRecords.Status.Neq(5), // 排除已取消
|
||||
).Count()
|
||||
if err == nil && cnt > 0 {
|
||||
return 0, fmt.Errorf("already_processed")
|
||||
}
|
||||
arow := &model.UserAddresses{UserID: claims.OwnerUserID, Name: name, Mobile: mobile, Province: province, City: city, District: district, Address: address, IsDefault: 0}
|
||||
if err := s.writeDB.UserAddresses.WithContext(ctx).Create(arow); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
inv, err := s.readDB.UserInventory.WithContext(ctx).Where(s.readDB.UserInventory.ID.Eq(claims.InventoryID)).First()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@ -81,21 +111,101 @@ func (s *service) SubmitAddressShare(ctx context.Context, shareToken string, nam
|
||||
if inv.Status != 1 {
|
||||
return 0, fmt.Errorf("inventory_unavailable")
|
||||
}
|
||||
var price int64
|
||||
if inv.ProductID > 0 {
|
||||
if p, e := s.readDB.Products.WithContext(ctx).Where(s.readDB.Products.ID.Eq(inv.ProductID)).First(); e == nil && p != nil {
|
||||
price = p.Price
|
||||
|
||||
// 2. 确定资产最终归属地 (实名转赠逻辑)
|
||||
targetUserID := claims.OwnerUserID
|
||||
isTransfer := false
|
||||
if submittedByUserID != nil && *submittedByUserID > 0 && *submittedByUserID != claims.OwnerUserID {
|
||||
targetUserID = *submittedByUserID
|
||||
isTransfer = true
|
||||
}
|
||||
|
||||
var addrID int64
|
||||
err = s.repo.GetDbW().Transaction(func(tx *gorm.DB) error {
|
||||
// a. 创建收货地址 (归属于 targetUserID)
|
||||
arow := &model.UserAddresses{
|
||||
UserID: targetUserID,
|
||||
Name: name,
|
||||
Mobile: mobile,
|
||||
Province: province,
|
||||
City: city,
|
||||
District: district,
|
||||
Address: address,
|
||||
IsDefault: 0,
|
||||
}
|
||||
}
|
||||
if db := s.repo.GetDbW().Exec("INSERT INTO shipping_records (user_id, order_id, order_item_id, inventory_id, product_id, quantity, price, address_id, status, remark) VALUES (?,?,?,?,?,?,?,?,?,?)", claims.OwnerUserID, inv.OrderID, 0, claims.InventoryID, inv.ProductID, 1, price, arow.ID, 1, "shared_address_submit"); db.Error != nil {
|
||||
err = db.Error
|
||||
if err := tx.Create(arow).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
addrID = arow.ID
|
||||
|
||||
// b. 资产状态更新及所有权转移
|
||||
if isTransfer {
|
||||
// 记录转赠流水
|
||||
transferLog := &model.UserInventoryTransfers{
|
||||
InventoryID: claims.InventoryID,
|
||||
FromUserID: claims.OwnerUserID,
|
||||
ToUserID: targetUserID,
|
||||
Remark: "address_share_transfer",
|
||||
}
|
||||
if err := tx.Create(transferLog).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 更新资产所属人
|
||||
if err := tx.Table("user_inventory").Where("id = ? AND user_id = ? AND status = 1", claims.InventoryID, claims.OwnerUserID).
|
||||
Updates(map[string]interface{}{
|
||||
"user_id": targetUserID,
|
||||
"status": 3,
|
||||
"updated_at": time.Now(),
|
||||
"remark": fmt.Sprintf("transferred_from_%d|shipping_requested", claims.OwnerUserID),
|
||||
}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// 仅更新状态 (原主发货)
|
||||
if err := tx.Table("user_inventory").Where("id = ? AND user_id = ? AND status = 1", claims.InventoryID, claims.OwnerUserID).
|
||||
Updates(map[string]interface{}{
|
||||
"status": 3,
|
||||
"updated_at": time.Now(),
|
||||
"remark": "shipping_requested_via_share",
|
||||
}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// c. 创建发货记录 (归属于 targetUserID)
|
||||
var price int64
|
||||
if inv.ProductID > 0 {
|
||||
var p model.Products
|
||||
if err := tx.Table("products").Where("id = ?", inv.ProductID).First(&p).Error; err == nil {
|
||||
price = p.Price
|
||||
}
|
||||
}
|
||||
|
||||
shipRecord := &model.ShippingRecords{
|
||||
UserID: targetUserID,
|
||||
OrderID: inv.OrderID,
|
||||
OrderItemID: 0,
|
||||
InventoryID: claims.InventoryID,
|
||||
ProductID: inv.ProductID,
|
||||
Quantity: 1,
|
||||
Price: price,
|
||||
AddressID: addrID,
|
||||
Status: 1,
|
||||
Remark: fmt.Sprintf("shared_address_submit|ip=%s", *submittedIP),
|
||||
}
|
||||
if err := tx.Create(shipRecord).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if db := s.repo.GetDbW().Exec("UPDATE user_inventory SET status=3, updated_at=NOW(3), remark=CONCAT(IFNULL(remark,''),'|shipping_requested') WHERE id=? AND user_id=? AND status=1", claims.InventoryID, claims.OwnerUserID); db.Error != nil {
|
||||
err = db.Error
|
||||
return 0, err
|
||||
}
|
||||
return arow.ID, nil
|
||||
|
||||
return addrID, nil
|
||||
}
|
||||
|
||||
func (s *service) RequestShipping(ctx context.Context, userID int64, inventoryID int64) (int64, error) {
|
||||
|
||||
@ -32,7 +32,7 @@ func (s *service) AddAddress(ctx context.Context, userID int64, in AddAddressInp
|
||||
}
|
||||
tx := s.writeDB.Begin()
|
||||
if in.IsDefault {
|
||||
if _, err := tx.UserAddresses.WithContext(ctx).Where(tx.UserAddresses.UserID.Eq(userID), tx.UserAddresses.IsDefault.Eq(1)).Updates(tx.UserAddresses.IsDefault.Value(0)); err != nil {
|
||||
if _, err := tx.UserAddresses.WithContext(ctx).Where(tx.UserAddresses.UserID.Eq(userID)).UpdateSimple(tx.UserAddresses.IsDefault.Value(0)); err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
@ -71,11 +71,13 @@ func (s *service) ListAddresses(ctx context.Context, userID int64, page, pageSiz
|
||||
|
||||
func (s *service) SetDefaultAddress(ctx context.Context, userID int64, addressID int64) error {
|
||||
tx := s.writeDB.Begin()
|
||||
if _, err := tx.UserAddresses.WithContext(ctx).Where(tx.UserAddresses.UserID.Eq(userID), tx.UserAddresses.IsDefault.Eq(1)).Updates(tx.UserAddresses.IsDefault.Value(0)); err != nil {
|
||||
// 先将用户所有地址的 is_default 设为 0
|
||||
if _, err := tx.UserAddresses.WithContext(ctx).Where(tx.UserAddresses.UserID.Eq(userID)).UpdateSimple(tx.UserAddresses.IsDefault.Value(0)); err != nil {
|
||||
_ = tx.Rollback()
|
||||
return err
|
||||
}
|
||||
if _, err := tx.UserAddresses.WithContext(ctx).Where(tx.UserAddresses.UserID.Eq(userID), tx.UserAddresses.ID.Eq(addressID)).Updates(tx.UserAddresses.IsDefault.Value(1)); err != nil {
|
||||
// 再将指定地址设为默认
|
||||
if _, err := tx.UserAddresses.WithContext(ctx).Where(tx.UserAddresses.UserID.Eq(userID), tx.UserAddresses.ID.Eq(addressID)).UpdateSimple(tx.UserAddresses.IsDefault.Value(1)); err != nil {
|
||||
_ = tx.Rollback()
|
||||
return err
|
||||
}
|
||||
@ -99,23 +101,27 @@ type UpdateAddressInput struct {
|
||||
|
||||
func (s *service) UpdateAddress(ctx context.Context, userID int64, addressID int64, in UpdateAddressInput) error {
|
||||
tx := s.writeDB.Begin()
|
||||
updates := map[string]interface{}{
|
||||
"name": in.Name,
|
||||
"mobile": in.Mobile,
|
||||
"province": in.Province,
|
||||
"city": in.City,
|
||||
"district": in.District,
|
||||
"address": in.Address,
|
||||
}
|
||||
if in.IsDefault {
|
||||
// 先将其他地址设为非默认
|
||||
if _, err := tx.UserAddresses.WithContext(ctx).Where(tx.UserAddresses.UserID.Eq(userID), tx.UserAddresses.IsDefault.Eq(1)).Updates(tx.UserAddresses.IsDefault.Value(0)); err != nil {
|
||||
// 先将用户所有地址设为非默认
|
||||
if _, err := tx.UserAddresses.WithContext(ctx).Where(tx.UserAddresses.UserID.Eq(userID)).UpdateSimple(tx.UserAddresses.IsDefault.Value(0)); err != nil {
|
||||
_ = tx.Rollback()
|
||||
return err
|
||||
}
|
||||
updates["is_default"] = 1
|
||||
}
|
||||
if _, err := tx.UserAddresses.WithContext(ctx).Where(tx.UserAddresses.UserID.Eq(userID), tx.UserAddresses.ID.Eq(addressID)).Updates(updates); err != nil {
|
||||
// 更新指定地址的信息
|
||||
isDefaultVal := int32(0)
|
||||
if in.IsDefault {
|
||||
isDefaultVal = 1
|
||||
}
|
||||
if _, err := tx.UserAddresses.WithContext(ctx).Where(tx.UserAddresses.UserID.Eq(userID), tx.UserAddresses.ID.Eq(addressID)).UpdateSimple(
|
||||
tx.UserAddresses.Name.Value(in.Name),
|
||||
tx.UserAddresses.Mobile.Value(in.Mobile),
|
||||
tx.UserAddresses.Province.Value(in.Province),
|
||||
tx.UserAddresses.City.Value(in.City),
|
||||
tx.UserAddresses.District.Value(in.District),
|
||||
tx.UserAddresses.Address.Value(in.Address),
|
||||
tx.UserAddresses.IsDefault.Value(isDefaultVal),
|
||||
); err != nil {
|
||||
_ = tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ type Service interface {
|
||||
ConsumePoints(ctx context.Context, userID int64, points int64, orderNo string) (int64, error)
|
||||
ConsumePointsFor(ctx context.Context, userID int64, points int64, refTable string, refID string, remark string, action string) (int64, error)
|
||||
RefundPoints(ctx context.Context, userID int64, points int64, orderNo string, reason string) (int64, error)
|
||||
CreateAddressShare(ctx context.Context, userID int64, inventoryID int64, expiresAt time.Time) (string, time.Time, error)
|
||||
CreateAddressShare(ctx context.Context, userID int64, inventoryID int64, expiresAt time.Time) (string, string, time.Time, error)
|
||||
RevokeAddressShare(ctx context.Context, userID int64, inventoryID int64) error
|
||||
SubmitAddressShare(ctx context.Context, shareToken string, name string, mobile string, province string, city string, district string, address string, submittedByUserID *int64, submittedIP *string) (int64, error)
|
||||
RequestShipping(ctx context.Context, userID int64, inventoryID int64) (int64, error)
|
||||
|
||||
@ -1672,3 +1672,913 @@
|
||||
{"level":"info","time":"2025-12-26 12:33:31","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 12:33:31","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 12:33:31","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 12:49:21","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 12:49:21","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 12:49:21","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 12:49:21","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 12:49:21","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 12:49:21","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 12:49:21","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 12:57:14","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 12:57:14","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 12:57:14","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 12:57:14","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 12:57:14","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 12:57:14","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 12:57:14","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 13:06:34","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 13:06:34","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 13:06:34","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 13:06:34","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 13:06:34","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 13:06:34","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 13:06:34","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 13:10:17","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 13:10:17","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 13:10:17","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 13:10:17","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 13:10:17","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 13:10:17","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 13:10:17","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 13:10:54","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 13:10:54","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 13:10:54","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 13:10:54","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 13:10:54","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 13:10:54","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 13:10:54","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 13:23:07","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 13:23:07","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 13:23:07","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 13:23:07","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 13:23:07","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 13:23:07","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 13:23:07","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 13:24:56","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 13:24:56","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 13:24:56","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 13:24:56","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 13:24:56","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 13:24:56","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 13:24:56","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 13:27:27","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 13:27:27","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 13:27:28","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 13:27:28","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 13:27:28","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 13:27:28","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 13:27:28","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 13:39:21","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 13:39:21","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 13:39:21","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 13:39:21","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 13:39:21","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 13:39:21","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 13:39:21","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 14:29:03","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 14:29:03","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 14:29:03","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 14:29:03","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 14:29:03","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 14:29:03","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 14:29:03","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 14:31:40","caller":"logger/logger.go:309","msg":"Processing event","domain":"mini-chat[fat]","type":"order_paid","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 14:37:29","caller":"logger/logger.go:309","msg":"Processing event","domain":"mini-chat[fat]","type":"order_paid","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 14:53:36","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 14:53:36","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 14:53:36","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 14:53:36","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 14:53:36","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 14:53:36","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 14:53:36","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 15:05:57","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 15:05:57","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 15:05:57","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 15:05:57","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 15:05:57","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 15:05:57","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 15:05:57","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 15:06:04","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 15:06:04","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 15:06:04","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 15:06:04","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 15:06:04","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 15:06:04","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 15:06:04","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 15:11:34","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 15:11:34","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 15:11:34","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 15:11:34","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 15:11:34","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 15:11:34","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 15:11:34","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 15:16:13","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 15:16:13","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 15:16:13","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 15:16:13","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 15:16:13","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 15:16:13","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 15:16:13","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 15:16:13","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 15:16:13","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"fatal","time":"2025-12-26 15:16:13","caller":"logger/logger.go:333","msg":"http server startup err","domain":"mini-chat[fat]","error":"listen tcp :9991: bind: address already in use"}
|
||||
{"level":"info","time":"2025-12-26 15:29:17","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 15:29:17","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 15:29:17","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 15:29:17","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 15:29:17","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 15:29:17","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 15:29:17","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 15:30:52","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 15:30:52","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 15:30:52","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 15:30:52","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 15:30:52","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 15:30:52","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 15:30:52","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 15:31:22","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":411}
|
||||
{"level":"error","time":"2025-12-26 15:31:24","caller":"logger/logger.go:327","msg":"[虚拟发货] 上传失败","domain":"mini-chat[fat]","error":"微信返回错误: errcode=10060023, errmsg=发货信息未更新 rid: 694e39cb-2ff87a81-199d1703"}
|
||||
{"level":"info","time":"2025-12-26 15:31:52","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":411}
|
||||
{"level":"error","time":"2025-12-26 15:31:53","caller":"logger/logger.go:327","msg":"[虚拟发货] 上传失败","domain":"mini-chat[fat]","error":"微信返回错误: errcode=10060023, errmsg=发货信息未更新 rid: 694e39e9-6a29f9ae-2bea909f"}
|
||||
{"level":"info","time":"2025-12-26 15:44:54","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 15:44:54","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 15:44:54","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 15:44:54","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 15:44:54","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 15:44:54","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 15:44:54","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 16:27:39","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 16:27:39","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 16:27:39","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 16:27:39","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 16:27:39","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 16:27:39","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 16:27:39","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 16:28:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":411}
|
||||
{"level":"info","time":"2025-12-26 16:28:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":418}
|
||||
{"level":"info","time":"2025-12-26 16:28:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":419}
|
||||
{"level":"info","time":"2025-12-26 16:28:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":420}
|
||||
{"level":"info","time":"2025-12-26 16:28:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":421}
|
||||
{"level":"info","time":"2025-12-26 16:28:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":422}
|
||||
{"level":"info","time":"2025-12-26 16:28:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":423}
|
||||
{"level":"info","time":"2025-12-26 16:28:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":424}
|
||||
{"level":"info","time":"2025-12-26 16:28:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":425}
|
||||
{"level":"info","time":"2025-12-26 16:28:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":426}
|
||||
{"level":"info","time":"2025-12-26 16:28:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":427}
|
||||
{"level":"info","time":"2025-12-26 16:28:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":428}
|
||||
{"level":"info","time":"2025-12-26 16:28:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":429}
|
||||
{"level":"info","time":"2025-12-26 16:28:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":430}
|
||||
{"level":"info","time":"2025-12-26 16:28:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":431}
|
||||
{"level":"info","time":"2025-12-26 16:28:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":432}
|
||||
{"level":"info","time":"2025-12-26 16:28:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":433}
|
||||
{"level":"info","time":"2025-12-26 16:28:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":434}
|
||||
{"level":"info","time":"2025-12-26 16:28:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":435}
|
||||
{"level":"info","time":"2025-12-26 16:28:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":436}
|
||||
{"level":"info","time":"2025-12-26 16:28:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":438}
|
||||
{"level":"info","time":"2025-12-26 16:28:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":440}
|
||||
{"level":"info","time":"2025-12-26 16:28:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":441}
|
||||
{"level":"info","time":"2025-12-26 16:28:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":442}
|
||||
{"level":"info","time":"2025-12-26 16:28:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":443}
|
||||
{"level":"info","time":"2025-12-26 16:28:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":444}
|
||||
{"level":"info","time":"2025-12-26 16:28:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":445}
|
||||
{"level":"info","time":"2025-12-26 16:28:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":446}
|
||||
{"level":"info","time":"2025-12-26 16:28:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":448}
|
||||
{"level":"info","time":"2025-12-26 16:28:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":449}
|
||||
{"level":"info","time":"2025-12-26 16:28:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":450}
|
||||
{"level":"info","time":"2025-12-26 16:28:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":451}
|
||||
{"level":"info","time":"2025-12-26 16:28:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":452}
|
||||
{"level":"info","time":"2025-12-26 16:28:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":453}
|
||||
{"level":"info","time":"2025-12-26 16:28:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":454}
|
||||
{"level":"info","time":"2025-12-26 16:28:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":455}
|
||||
{"level":"info","time":"2025-12-26 16:28:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":456}
|
||||
{"level":"info","time":"2025-12-26 16:28:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":457}
|
||||
{"level":"info","time":"2025-12-26 16:28:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":458}
|
||||
{"level":"info","time":"2025-12-26 16:28:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":459}
|
||||
{"level":"info","time":"2025-12-26 16:28:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":460}
|
||||
{"level":"info","time":"2025-12-26 16:28:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":461}
|
||||
{"level":"info","time":"2025-12-26 16:28:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":462}
|
||||
{"level":"info","time":"2025-12-26 16:28:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":463}
|
||||
{"level":"info","time":"2025-12-26 16:28:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":464}
|
||||
{"level":"info","time":"2025-12-26 16:28:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":465}
|
||||
{"level":"info","time":"2025-12-26 16:28:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":466}
|
||||
{"level":"info","time":"2025-12-26 16:28:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":467}
|
||||
{"level":"info","time":"2025-12-26 16:28:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":468}
|
||||
{"level":"info","time":"2025-12-26 16:28:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":411}
|
||||
{"level":"info","time":"2025-12-26 16:28:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":418}
|
||||
{"level":"info","time":"2025-12-26 16:28:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":419}
|
||||
{"level":"info","time":"2025-12-26 16:28:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":420}
|
||||
{"level":"info","time":"2025-12-26 16:28:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":421}
|
||||
{"level":"info","time":"2025-12-26 16:28:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":422}
|
||||
{"level":"info","time":"2025-12-26 16:28:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":423}
|
||||
{"level":"info","time":"2025-12-26 16:28:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":424}
|
||||
{"level":"info","time":"2025-12-26 16:28:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":425}
|
||||
{"level":"info","time":"2025-12-26 16:28:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":426}
|
||||
{"level":"info","time":"2025-12-26 16:28:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":427}
|
||||
{"level":"info","time":"2025-12-26 16:28:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":428}
|
||||
{"level":"info","time":"2025-12-26 16:28:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":429}
|
||||
{"level":"info","time":"2025-12-26 16:28:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":430}
|
||||
{"level":"info","time":"2025-12-26 16:28:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":431}
|
||||
{"level":"info","time":"2025-12-26 16:28:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":432}
|
||||
{"level":"info","time":"2025-12-26 16:28:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":433}
|
||||
{"level":"info","time":"2025-12-26 16:28:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":434}
|
||||
{"level":"info","time":"2025-12-26 16:28:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":435}
|
||||
{"level":"info","time":"2025-12-26 16:28:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":436}
|
||||
{"level":"info","time":"2025-12-26 16:28:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":438}
|
||||
{"level":"info","time":"2025-12-26 16:28:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":440}
|
||||
{"level":"info","time":"2025-12-26 16:28:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":441}
|
||||
{"level":"info","time":"2025-12-26 16:28:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":442}
|
||||
{"level":"info","time":"2025-12-26 16:28:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":443}
|
||||
{"level":"info","time":"2025-12-26 16:28:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":444}
|
||||
{"level":"info","time":"2025-12-26 16:28:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":445}
|
||||
{"level":"info","time":"2025-12-26 16:28:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":446}
|
||||
{"level":"info","time":"2025-12-26 16:28:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":448}
|
||||
{"level":"info","time":"2025-12-26 16:28:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":449}
|
||||
{"level":"info","time":"2025-12-26 16:28:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":450}
|
||||
{"level":"info","time":"2025-12-26 16:28:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":451}
|
||||
{"level":"info","time":"2025-12-26 16:28:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":452}
|
||||
{"level":"info","time":"2025-12-26 16:28:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":453}
|
||||
{"level":"info","time":"2025-12-26 16:28:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":454}
|
||||
{"level":"info","time":"2025-12-26 16:28:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":455}
|
||||
{"level":"info","time":"2025-12-26 16:28:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":456}
|
||||
{"level":"info","time":"2025-12-26 16:28:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":457}
|
||||
{"level":"info","time":"2025-12-26 16:28:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":458}
|
||||
{"level":"info","time":"2025-12-26 16:28:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":459}
|
||||
{"level":"info","time":"2025-12-26 16:28:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":460}
|
||||
{"level":"info","time":"2025-12-26 16:28:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":461}
|
||||
{"level":"info","time":"2025-12-26 16:28:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":462}
|
||||
{"level":"info","time":"2025-12-26 16:28:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":463}
|
||||
{"level":"info","time":"2025-12-26 16:28:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":464}
|
||||
{"level":"info","time":"2025-12-26 16:28:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":465}
|
||||
{"level":"info","time":"2025-12-26 16:28:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":466}
|
||||
{"level":"info","time":"2025-12-26 16:28:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":467}
|
||||
{"level":"info","time":"2025-12-26 16:28:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":468}
|
||||
{"level":"info","time":"2025-12-26 16:29:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":411}
|
||||
{"level":"info","time":"2025-12-26 16:29:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":418}
|
||||
{"level":"info","time":"2025-12-26 16:29:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":419}
|
||||
{"level":"info","time":"2025-12-26 16:29:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":420}
|
||||
{"level":"info","time":"2025-12-26 16:29:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":421}
|
||||
{"level":"info","time":"2025-12-26 16:29:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":422}
|
||||
{"level":"info","time":"2025-12-26 16:29:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":423}
|
||||
{"level":"info","time":"2025-12-26 16:29:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":424}
|
||||
{"level":"info","time":"2025-12-26 16:29:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":425}
|
||||
{"level":"info","time":"2025-12-26 16:29:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":426}
|
||||
{"level":"info","time":"2025-12-26 16:29:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":427}
|
||||
{"level":"info","time":"2025-12-26 16:29:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":428}
|
||||
{"level":"info","time":"2025-12-26 16:29:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":429}
|
||||
{"level":"info","time":"2025-12-26 16:29:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":430}
|
||||
{"level":"info","time":"2025-12-26 16:29:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":431}
|
||||
{"level":"info","time":"2025-12-26 16:29:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":432}
|
||||
{"level":"info","time":"2025-12-26 16:29:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":433}
|
||||
{"level":"info","time":"2025-12-26 16:29:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":434}
|
||||
{"level":"info","time":"2025-12-26 16:29:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":435}
|
||||
{"level":"info","time":"2025-12-26 16:29:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":436}
|
||||
{"level":"info","time":"2025-12-26 16:29:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":438}
|
||||
{"level":"info","time":"2025-12-26 16:29:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":440}
|
||||
{"level":"info","time":"2025-12-26 16:29:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":441}
|
||||
{"level":"info","time":"2025-12-26 16:29:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":442}
|
||||
{"level":"info","time":"2025-12-26 16:29:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":443}
|
||||
{"level":"info","time":"2025-12-26 16:29:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":444}
|
||||
{"level":"info","time":"2025-12-26 16:29:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":445}
|
||||
{"level":"info","time":"2025-12-26 16:29:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":446}
|
||||
{"level":"info","time":"2025-12-26 16:29:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":448}
|
||||
{"level":"info","time":"2025-12-26 16:29:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":449}
|
||||
{"level":"info","time":"2025-12-26 16:29:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":450}
|
||||
{"level":"info","time":"2025-12-26 16:29:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":451}
|
||||
{"level":"info","time":"2025-12-26 16:29:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":452}
|
||||
{"level":"info","time":"2025-12-26 16:29:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":453}
|
||||
{"level":"info","time":"2025-12-26 16:29:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":454}
|
||||
{"level":"info","time":"2025-12-26 16:29:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":455}
|
||||
{"level":"info","time":"2025-12-26 16:29:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":456}
|
||||
{"level":"info","time":"2025-12-26 16:29:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":457}
|
||||
{"level":"info","time":"2025-12-26 16:29:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":458}
|
||||
{"level":"info","time":"2025-12-26 16:29:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":459}
|
||||
{"level":"info","time":"2025-12-26 16:29:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":460}
|
||||
{"level":"info","time":"2025-12-26 16:29:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":461}
|
||||
{"level":"info","time":"2025-12-26 16:29:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":462}
|
||||
{"level":"info","time":"2025-12-26 16:29:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":463}
|
||||
{"level":"info","time":"2025-12-26 16:29:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":464}
|
||||
{"level":"info","time":"2025-12-26 16:29:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":465}
|
||||
{"level":"info","time":"2025-12-26 16:29:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":466}
|
||||
{"level":"info","time":"2025-12-26 16:29:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":467}
|
||||
{"level":"info","time":"2025-12-26 16:29:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":468}
|
||||
{"level":"info","time":"2025-12-26 16:29:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":469}
|
||||
{"level":"info","time":"2025-12-26 16:29:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":470}
|
||||
{"level":"info","time":"2025-12-26 16:29:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":411}
|
||||
{"level":"info","time":"2025-12-26 16:29:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":418}
|
||||
{"level":"info","time":"2025-12-26 16:29:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":419}
|
||||
{"level":"info","time":"2025-12-26 16:29:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":420}
|
||||
{"level":"info","time":"2025-12-26 16:29:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":421}
|
||||
{"level":"info","time":"2025-12-26 16:29:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":422}
|
||||
{"level":"info","time":"2025-12-26 16:29:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":423}
|
||||
{"level":"info","time":"2025-12-26 16:29:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":424}
|
||||
{"level":"info","time":"2025-12-26 16:29:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":425}
|
||||
{"level":"info","time":"2025-12-26 16:29:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":426}
|
||||
{"level":"info","time":"2025-12-26 16:29:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":427}
|
||||
{"level":"info","time":"2025-12-26 16:29:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":428}
|
||||
{"level":"info","time":"2025-12-26 16:29:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":429}
|
||||
{"level":"info","time":"2025-12-26 16:29:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":430}
|
||||
{"level":"info","time":"2025-12-26 16:29:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":431}
|
||||
{"level":"info","time":"2025-12-26 16:29:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":432}
|
||||
{"level":"info","time":"2025-12-26 16:29:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":433}
|
||||
{"level":"info","time":"2025-12-26 16:29:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":434}
|
||||
{"level":"info","time":"2025-12-26 16:29:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":435}
|
||||
{"level":"info","time":"2025-12-26 16:29:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":436}
|
||||
{"level":"info","time":"2025-12-26 16:29:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":438}
|
||||
{"level":"info","time":"2025-12-26 16:29:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":440}
|
||||
{"level":"info","time":"2025-12-26 16:29:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":441}
|
||||
{"level":"info","time":"2025-12-26 16:29:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":442}
|
||||
{"level":"info","time":"2025-12-26 16:29:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":443}
|
||||
{"level":"info","time":"2025-12-26 16:29:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":444}
|
||||
{"level":"info","time":"2025-12-26 16:29:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":445}
|
||||
{"level":"info","time":"2025-12-26 16:29:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":446}
|
||||
{"level":"info","time":"2025-12-26 16:29:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":448}
|
||||
{"level":"info","time":"2025-12-26 16:29:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":449}
|
||||
{"level":"info","time":"2025-12-26 16:29:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":450}
|
||||
{"level":"info","time":"2025-12-26 16:29:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":451}
|
||||
{"level":"info","time":"2025-12-26 16:29:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":452}
|
||||
{"level":"info","time":"2025-12-26 16:29:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":453}
|
||||
{"level":"info","time":"2025-12-26 16:29:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":454}
|
||||
{"level":"info","time":"2025-12-26 16:29:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":455}
|
||||
{"level":"info","time":"2025-12-26 16:29:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":456}
|
||||
{"level":"info","time":"2025-12-26 16:29:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":457}
|
||||
{"level":"info","time":"2025-12-26 16:29:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":458}
|
||||
{"level":"info","time":"2025-12-26 16:29:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":459}
|
||||
{"level":"info","time":"2025-12-26 16:29:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":460}
|
||||
{"level":"info","time":"2025-12-26 16:29:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":461}
|
||||
{"level":"info","time":"2025-12-26 16:29:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":462}
|
||||
{"level":"info","time":"2025-12-26 16:29:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":463}
|
||||
{"level":"info","time":"2025-12-26 16:29:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":464}
|
||||
{"level":"info","time":"2025-12-26 16:29:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":465}
|
||||
{"level":"info","time":"2025-12-26 16:29:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":466}
|
||||
{"level":"info","time":"2025-12-26 16:29:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":467}
|
||||
{"level":"info","time":"2025-12-26 16:29:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":468}
|
||||
{"level":"info","time":"2025-12-26 16:29:47","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":469}
|
||||
{"level":"info","time":"2025-12-26 16:29:47","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":470}
|
||||
{"level":"info","time":"2025-12-26 16:30:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":411}
|
||||
{"level":"info","time":"2025-12-26 16:30:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":418}
|
||||
{"level":"info","time":"2025-12-26 16:30:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":419}
|
||||
{"level":"info","time":"2025-12-26 16:30:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":420}
|
||||
{"level":"info","time":"2025-12-26 16:30:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":421}
|
||||
{"level":"info","time":"2025-12-26 16:30:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":422}
|
||||
{"level":"info","time":"2025-12-26 16:30:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":423}
|
||||
{"level":"info","time":"2025-12-26 16:30:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":424}
|
||||
{"level":"info","time":"2025-12-26 16:30:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":425}
|
||||
{"level":"info","time":"2025-12-26 16:30:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":426}
|
||||
{"level":"info","time":"2025-12-26 16:30:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":427}
|
||||
{"level":"info","time":"2025-12-26 16:30:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":428}
|
||||
{"level":"info","time":"2025-12-26 16:30:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":429}
|
||||
{"level":"info","time":"2025-12-26 16:30:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":430}
|
||||
{"level":"info","time":"2025-12-26 16:30:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":431}
|
||||
{"level":"info","time":"2025-12-26 16:30:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":432}
|
||||
{"level":"info","time":"2025-12-26 16:30:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":433}
|
||||
{"level":"info","time":"2025-12-26 16:30:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":434}
|
||||
{"level":"info","time":"2025-12-26 16:30:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":435}
|
||||
{"level":"info","time":"2025-12-26 16:30:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":436}
|
||||
{"level":"info","time":"2025-12-26 16:30:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":438}
|
||||
{"level":"info","time":"2025-12-26 16:30:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":440}
|
||||
{"level":"info","time":"2025-12-26 16:30:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":441}
|
||||
{"level":"info","time":"2025-12-26 16:30:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":442}
|
||||
{"level":"info","time":"2025-12-26 16:30:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":443}
|
||||
{"level":"info","time":"2025-12-26 16:30:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":444}
|
||||
{"level":"info","time":"2025-12-26 16:30:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":445}
|
||||
{"level":"info","time":"2025-12-26 16:30:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":446}
|
||||
{"level":"info","time":"2025-12-26 16:30:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":448}
|
||||
{"level":"info","time":"2025-12-26 16:30:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":449}
|
||||
{"level":"info","time":"2025-12-26 16:30:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":450}
|
||||
{"level":"info","time":"2025-12-26 16:30:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":451}
|
||||
{"level":"info","time":"2025-12-26 16:30:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":452}
|
||||
{"level":"info","time":"2025-12-26 16:30:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":453}
|
||||
{"level":"info","time":"2025-12-26 16:30:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":454}
|
||||
{"level":"info","time":"2025-12-26 16:30:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":455}
|
||||
{"level":"info","time":"2025-12-26 16:30:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":456}
|
||||
{"level":"info","time":"2025-12-26 16:30:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":457}
|
||||
{"level":"info","time":"2025-12-26 16:30:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":458}
|
||||
{"level":"info","time":"2025-12-26 16:30:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":459}
|
||||
{"level":"info","time":"2025-12-26 16:30:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":460}
|
||||
{"level":"info","time":"2025-12-26 16:30:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":461}
|
||||
{"level":"info","time":"2025-12-26 16:30:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":462}
|
||||
{"level":"info","time":"2025-12-26 16:30:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":463}
|
||||
{"level":"info","time":"2025-12-26 16:30:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":464}
|
||||
{"level":"info","time":"2025-12-26 16:30:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":465}
|
||||
{"level":"info","time":"2025-12-26 16:30:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":466}
|
||||
{"level":"info","time":"2025-12-26 16:30:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":467}
|
||||
{"level":"info","time":"2025-12-26 16:30:17","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":468}
|
||||
{"level":"info","time":"2025-12-26 16:30:17","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":469}
|
||||
{"level":"info","time":"2025-12-26 16:30:17","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":470}
|
||||
{"level":"info","time":"2025-12-26 16:30:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":411}
|
||||
{"level":"info","time":"2025-12-26 16:30:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":418}
|
||||
{"level":"info","time":"2025-12-26 16:30:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":419}
|
||||
{"level":"info","time":"2025-12-26 16:30:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":420}
|
||||
{"level":"info","time":"2025-12-26 16:30:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":421}
|
||||
{"level":"info","time":"2025-12-26 16:30:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":422}
|
||||
{"level":"info","time":"2025-12-26 16:30:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":423}
|
||||
{"level":"info","time":"2025-12-26 16:30:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":424}
|
||||
{"level":"info","time":"2025-12-26 16:30:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":425}
|
||||
{"level":"info","time":"2025-12-26 16:30:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":426}
|
||||
{"level":"info","time":"2025-12-26 16:30:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":427}
|
||||
{"level":"info","time":"2025-12-26 16:30:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":428}
|
||||
{"level":"info","time":"2025-12-26 16:30:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":429}
|
||||
{"level":"info","time":"2025-12-26 16:30:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":430}
|
||||
{"level":"info","time":"2025-12-26 16:30:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":431}
|
||||
{"level":"info","time":"2025-12-26 16:30:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":432}
|
||||
{"level":"info","time":"2025-12-26 16:30:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":433}
|
||||
{"level":"info","time":"2025-12-26 16:30:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":434}
|
||||
{"level":"info","time":"2025-12-26 16:30:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":435}
|
||||
{"level":"info","time":"2025-12-26 16:30:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":436}
|
||||
{"level":"info","time":"2025-12-26 16:30:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":438}
|
||||
{"level":"info","time":"2025-12-26 16:30:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":440}
|
||||
{"level":"info","time":"2025-12-26 16:30:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":441}
|
||||
{"level":"info","time":"2025-12-26 16:30:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":442}
|
||||
{"level":"info","time":"2025-12-26 16:30:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":443}
|
||||
{"level":"info","time":"2025-12-26 16:30:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":444}
|
||||
{"level":"info","time":"2025-12-26 16:30:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":445}
|
||||
{"level":"info","time":"2025-12-26 16:30:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":446}
|
||||
{"level":"info","time":"2025-12-26 16:30:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":448}
|
||||
{"level":"info","time":"2025-12-26 16:30:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":449}
|
||||
{"level":"info","time":"2025-12-26 16:30:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":450}
|
||||
{"level":"info","time":"2025-12-26 16:30:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":451}
|
||||
{"level":"info","time":"2025-12-26 16:30:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":452}
|
||||
{"level":"info","time":"2025-12-26 16:30:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":453}
|
||||
{"level":"info","time":"2025-12-26 16:30:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":454}
|
||||
{"level":"info","time":"2025-12-26 16:30:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":455}
|
||||
{"level":"info","time":"2025-12-26 16:30:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":456}
|
||||
{"level":"info","time":"2025-12-26 16:30:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":457}
|
||||
{"level":"info","time":"2025-12-26 16:30:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":458}
|
||||
{"level":"info","time":"2025-12-26 16:30:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":459}
|
||||
{"level":"info","time":"2025-12-26 16:30:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":460}
|
||||
{"level":"info","time":"2025-12-26 16:30:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":461}
|
||||
{"level":"info","time":"2025-12-26 16:30:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":462}
|
||||
{"level":"info","time":"2025-12-26 16:30:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":463}
|
||||
{"level":"info","time":"2025-12-26 16:30:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":464}
|
||||
{"level":"info","time":"2025-12-26 16:30:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":465}
|
||||
{"level":"info","time":"2025-12-26 16:30:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":466}
|
||||
{"level":"info","time":"2025-12-26 16:30:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":467}
|
||||
{"level":"info","time":"2025-12-26 16:30:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":468}
|
||||
{"level":"info","time":"2025-12-26 16:30:47","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":469}
|
||||
{"level":"info","time":"2025-12-26 16:30:47","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":470}
|
||||
{"level":"info","time":"2025-12-26 16:31:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":411}
|
||||
{"level":"info","time":"2025-12-26 16:31:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":418}
|
||||
{"level":"info","time":"2025-12-26 16:31:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":419}
|
||||
{"level":"info","time":"2025-12-26 16:31:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":420}
|
||||
{"level":"info","time":"2025-12-26 16:31:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":421}
|
||||
{"level":"info","time":"2025-12-26 16:31:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":422}
|
||||
{"level":"info","time":"2025-12-26 16:31:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":423}
|
||||
{"level":"info","time":"2025-12-26 16:31:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":424}
|
||||
{"level":"info","time":"2025-12-26 16:31:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":425}
|
||||
{"level":"info","time":"2025-12-26 16:31:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":426}
|
||||
{"level":"info","time":"2025-12-26 16:31:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":427}
|
||||
{"level":"info","time":"2025-12-26 16:31:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":428}
|
||||
{"level":"info","time":"2025-12-26 16:31:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":429}
|
||||
{"level":"info","time":"2025-12-26 16:31:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":430}
|
||||
{"level":"info","time":"2025-12-26 16:31:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":431}
|
||||
{"level":"info","time":"2025-12-26 16:31:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":432}
|
||||
{"level":"info","time":"2025-12-26 16:31:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":433}
|
||||
{"level":"info","time":"2025-12-26 16:31:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":434}
|
||||
{"level":"info","time":"2025-12-26 16:31:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":435}
|
||||
{"level":"info","time":"2025-12-26 16:31:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":436}
|
||||
{"level":"info","time":"2025-12-26 16:31:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":438}
|
||||
{"level":"info","time":"2025-12-26 16:31:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":440}
|
||||
{"level":"info","time":"2025-12-26 16:31:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":441}
|
||||
{"level":"info","time":"2025-12-26 16:31:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":442}
|
||||
{"level":"info","time":"2025-12-26 16:31:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":443}
|
||||
{"level":"info","time":"2025-12-26 16:31:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":444}
|
||||
{"level":"info","time":"2025-12-26 16:31:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":445}
|
||||
{"level":"info","time":"2025-12-26 16:31:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":446}
|
||||
{"level":"info","time":"2025-12-26 16:31:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":448}
|
||||
{"level":"info","time":"2025-12-26 16:31:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":449}
|
||||
{"level":"info","time":"2025-12-26 16:31:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":450}
|
||||
{"level":"info","time":"2025-12-26 16:31:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":451}
|
||||
{"level":"info","time":"2025-12-26 16:31:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":452}
|
||||
{"level":"info","time":"2025-12-26 16:31:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":453}
|
||||
{"level":"info","time":"2025-12-26 16:31:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":454}
|
||||
{"level":"info","time":"2025-12-26 16:31:14","caller":"logger/logger.go:309","msg":"Processing event","domain":"mini-chat[fat]","type":"order_paid","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 16:31:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":455}
|
||||
{"level":"info","time":"2025-12-26 16:31:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":456}
|
||||
{"level":"info","time":"2025-12-26 16:31:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":457}
|
||||
{"level":"info","time":"2025-12-26 16:31:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":458}
|
||||
{"level":"info","time":"2025-12-26 16:31:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":459}
|
||||
{"level":"info","time":"2025-12-26 16:31:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":460}
|
||||
{"level":"info","time":"2025-12-26 16:31:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":461}
|
||||
{"level":"info","time":"2025-12-26 16:31:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":462}
|
||||
{"level":"info","time":"2025-12-26 16:31:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":463}
|
||||
{"level":"info","time":"2025-12-26 16:31:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":464}
|
||||
{"level":"info","time":"2025-12-26 16:31:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":465}
|
||||
{"level":"info","time":"2025-12-26 16:31:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":466}
|
||||
{"level":"info","time":"2025-12-26 16:31:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":467}
|
||||
{"level":"info","time":"2025-12-26 16:31:17","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":468}
|
||||
{"level":"info","time":"2025-12-26 16:31:17","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":469}
|
||||
{"level":"info","time":"2025-12-26 16:31:17","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":470}
|
||||
{"level":"info","time":"2025-12-26 16:31:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":411}
|
||||
{"level":"info","time":"2025-12-26 16:31:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":418}
|
||||
{"level":"info","time":"2025-12-26 16:31:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":419}
|
||||
{"level":"info","time":"2025-12-26 16:31:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":420}
|
||||
{"level":"info","time":"2025-12-26 16:31:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":421}
|
||||
{"level":"info","time":"2025-12-26 16:31:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":422}
|
||||
{"level":"info","time":"2025-12-26 16:31:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":423}
|
||||
{"level":"info","time":"2025-12-26 16:31:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":424}
|
||||
{"level":"info","time":"2025-12-26 16:31:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":425}
|
||||
{"level":"info","time":"2025-12-26 16:31:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":426}
|
||||
{"level":"info","time":"2025-12-26 16:31:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":427}
|
||||
{"level":"info","time":"2025-12-26 16:31:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":428}
|
||||
{"level":"info","time":"2025-12-26 16:31:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":429}
|
||||
{"level":"info","time":"2025-12-26 16:31:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":430}
|
||||
{"level":"info","time":"2025-12-26 16:31:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":431}
|
||||
{"level":"info","time":"2025-12-26 16:31:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":432}
|
||||
{"level":"info","time":"2025-12-26 16:31:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":433}
|
||||
{"level":"info","time":"2025-12-26 16:31:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":434}
|
||||
{"level":"info","time":"2025-12-26 16:31:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":435}
|
||||
{"level":"info","time":"2025-12-26 16:31:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":436}
|
||||
{"level":"info","time":"2025-12-26 16:31:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":438}
|
||||
{"level":"info","time":"2025-12-26 16:31:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":440}
|
||||
{"level":"info","time":"2025-12-26 16:31:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":441}
|
||||
{"level":"info","time":"2025-12-26 16:31:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":442}
|
||||
{"level":"info","time":"2025-12-26 16:31:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":443}
|
||||
{"level":"info","time":"2025-12-26 16:31:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":444}
|
||||
{"level":"info","time":"2025-12-26 16:31:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":445}
|
||||
{"level":"info","time":"2025-12-26 16:31:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":446}
|
||||
{"level":"info","time":"2025-12-26 16:31:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":448}
|
||||
{"level":"info","time":"2025-12-26 16:31:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":449}
|
||||
{"level":"info","time":"2025-12-26 16:31:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":450}
|
||||
{"level":"info","time":"2025-12-26 16:31:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":451}
|
||||
{"level":"info","time":"2025-12-26 16:31:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":452}
|
||||
{"level":"info","time":"2025-12-26 16:31:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":453}
|
||||
{"level":"info","time":"2025-12-26 16:31:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":454}
|
||||
{"level":"info","time":"2025-12-26 16:31:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":455}
|
||||
{"level":"info","time":"2025-12-26 16:31:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":456}
|
||||
{"level":"info","time":"2025-12-26 16:31:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":457}
|
||||
{"level":"info","time":"2025-12-26 16:31:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":458}
|
||||
{"level":"info","time":"2025-12-26 16:31:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":459}
|
||||
{"level":"info","time":"2025-12-26 16:31:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":460}
|
||||
{"level":"info","time":"2025-12-26 16:31:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":461}
|
||||
{"level":"info","time":"2025-12-26 16:31:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":462}
|
||||
{"level":"info","time":"2025-12-26 16:31:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":463}
|
||||
{"level":"info","time":"2025-12-26 16:31:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":464}
|
||||
{"level":"info","time":"2025-12-26 16:31:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":465}
|
||||
{"level":"info","time":"2025-12-26 16:31:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":466}
|
||||
{"level":"info","time":"2025-12-26 16:31:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":467}
|
||||
{"level":"info","time":"2025-12-26 16:31:47","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":468}
|
||||
{"level":"info","time":"2025-12-26 16:31:47","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":469}
|
||||
{"level":"info","time":"2025-12-26 16:31:47","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":470}
|
||||
{"level":"info","time":"2025-12-26 16:32:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":411}
|
||||
{"level":"info","time":"2025-12-26 16:32:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":418}
|
||||
{"level":"info","time":"2025-12-26 16:32:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":419}
|
||||
{"level":"info","time":"2025-12-26 16:32:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":420}
|
||||
{"level":"info","time":"2025-12-26 16:32:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":421}
|
||||
{"level":"info","time":"2025-12-26 16:32:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":422}
|
||||
{"level":"info","time":"2025-12-26 16:32:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":423}
|
||||
{"level":"info","time":"2025-12-26 16:32:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":424}
|
||||
{"level":"info","time":"2025-12-26 16:32:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":425}
|
||||
{"level":"info","time":"2025-12-26 16:32:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":426}
|
||||
{"level":"info","time":"2025-12-26 16:32:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":427}
|
||||
{"level":"info","time":"2025-12-26 16:32:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":428}
|
||||
{"level":"info","time":"2025-12-26 16:32:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":429}
|
||||
{"level":"info","time":"2025-12-26 16:32:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":430}
|
||||
{"level":"info","time":"2025-12-26 16:32:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":431}
|
||||
{"level":"info","time":"2025-12-26 16:32:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":432}
|
||||
{"level":"info","time":"2025-12-26 16:32:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":433}
|
||||
{"level":"info","time":"2025-12-26 16:32:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":434}
|
||||
{"level":"info","time":"2025-12-26 16:32:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":435}
|
||||
{"level":"info","time":"2025-12-26 16:32:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":436}
|
||||
{"level":"info","time":"2025-12-26 16:32:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":438}
|
||||
{"level":"info","time":"2025-12-26 16:32:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":440}
|
||||
{"level":"info","time":"2025-12-26 16:32:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":441}
|
||||
{"level":"info","time":"2025-12-26 16:32:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":442}
|
||||
{"level":"info","time":"2025-12-26 16:32:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":443}
|
||||
{"level":"info","time":"2025-12-26 16:32:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":444}
|
||||
{"level":"info","time":"2025-12-26 16:32:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":445}
|
||||
{"level":"info","time":"2025-12-26 16:32:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":446}
|
||||
{"level":"info","time":"2025-12-26 16:32:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":448}
|
||||
{"level":"info","time":"2025-12-26 16:32:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":449}
|
||||
{"level":"info","time":"2025-12-26 16:32:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":450}
|
||||
{"level":"info","time":"2025-12-26 16:32:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":451}
|
||||
{"level":"info","time":"2025-12-26 16:32:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":452}
|
||||
{"level":"info","time":"2025-12-26 16:32:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":453}
|
||||
{"level":"info","time":"2025-12-26 16:32:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":454}
|
||||
{"level":"info","time":"2025-12-26 16:32:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":455}
|
||||
{"level":"info","time":"2025-12-26 16:32:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":456}
|
||||
{"level":"info","time":"2025-12-26 16:32:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":457}
|
||||
{"level":"info","time":"2025-12-26 16:32:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":458}
|
||||
{"level":"info","time":"2025-12-26 16:32:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":459}
|
||||
{"level":"info","time":"2025-12-26 16:32:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":460}
|
||||
{"level":"info","time":"2025-12-26 16:32:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":461}
|
||||
{"level":"info","time":"2025-12-26 16:32:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":462}
|
||||
{"level":"info","time":"2025-12-26 16:32:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":463}
|
||||
{"level":"info","time":"2025-12-26 16:32:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":464}
|
||||
{"level":"info","time":"2025-12-26 16:32:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":465}
|
||||
{"level":"info","time":"2025-12-26 16:32:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":466}
|
||||
{"level":"info","time":"2025-12-26 16:32:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":467}
|
||||
{"level":"info","time":"2025-12-26 16:32:17","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":468}
|
||||
{"level":"info","time":"2025-12-26 16:32:17","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":469}
|
||||
{"level":"info","time":"2025-12-26 16:32:17","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":470}
|
||||
{"level":"info","time":"2025-12-26 16:32:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":411}
|
||||
{"level":"info","time":"2025-12-26 16:32:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":418}
|
||||
{"level":"info","time":"2025-12-26 16:32:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":419}
|
||||
{"level":"info","time":"2025-12-26 16:32:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":420}
|
||||
{"level":"info","time":"2025-12-26 16:32:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":421}
|
||||
{"level":"info","time":"2025-12-26 16:32:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":422}
|
||||
{"level":"info","time":"2025-12-26 16:32:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":423}
|
||||
{"level":"info","time":"2025-12-26 16:32:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":424}
|
||||
{"level":"info","time":"2025-12-26 16:32:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":425}
|
||||
{"level":"info","time":"2025-12-26 16:32:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":426}
|
||||
{"level":"info","time":"2025-12-26 16:32:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":427}
|
||||
{"level":"info","time":"2025-12-26 16:32:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":428}
|
||||
{"level":"info","time":"2025-12-26 16:32:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":429}
|
||||
{"level":"info","time":"2025-12-26 16:32:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":430}
|
||||
{"level":"info","time":"2025-12-26 16:32:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":431}
|
||||
{"level":"info","time":"2025-12-26 16:32:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":432}
|
||||
{"level":"info","time":"2025-12-26 16:32:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":433}
|
||||
{"level":"info","time":"2025-12-26 16:32:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":434}
|
||||
{"level":"info","time":"2025-12-26 16:32:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":435}
|
||||
{"level":"info","time":"2025-12-26 16:32:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":436}
|
||||
{"level":"info","time":"2025-12-26 16:32:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":438}
|
||||
{"level":"info","time":"2025-12-26 16:32:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":440}
|
||||
{"level":"info","time":"2025-12-26 16:32:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":441}
|
||||
{"level":"info","time":"2025-12-26 16:32:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":442}
|
||||
{"level":"info","time":"2025-12-26 16:32:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":443}
|
||||
{"level":"info","time":"2025-12-26 16:32:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":444}
|
||||
{"level":"info","time":"2025-12-26 16:32:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":445}
|
||||
{"level":"info","time":"2025-12-26 16:32:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":446}
|
||||
{"level":"info","time":"2025-12-26 16:32:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":448}
|
||||
{"level":"info","time":"2025-12-26 16:32:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":449}
|
||||
{"level":"info","time":"2025-12-26 16:32:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":450}
|
||||
{"level":"info","time":"2025-12-26 16:32:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":451}
|
||||
{"level":"info","time":"2025-12-26 16:32:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":452}
|
||||
{"level":"info","time":"2025-12-26 16:32:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":453}
|
||||
{"level":"info","time":"2025-12-26 16:32:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":454}
|
||||
{"level":"info","time":"2025-12-26 16:32:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":455}
|
||||
{"level":"info","time":"2025-12-26 16:32:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":456}
|
||||
{"level":"info","time":"2025-12-26 16:32:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":457}
|
||||
{"level":"info","time":"2025-12-26 16:32:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":458}
|
||||
{"level":"info","time":"2025-12-26 16:32:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":459}
|
||||
{"level":"info","time":"2025-12-26 16:32:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":460}
|
||||
{"level":"info","time":"2025-12-26 16:32:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":461}
|
||||
{"level":"info","time":"2025-12-26 16:32:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":462}
|
||||
{"level":"info","time":"2025-12-26 16:32:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":463}
|
||||
{"level":"info","time":"2025-12-26 16:32:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":464}
|
||||
{"level":"info","time":"2025-12-26 16:32:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":465}
|
||||
{"level":"info","time":"2025-12-26 16:32:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":466}
|
||||
{"level":"info","time":"2025-12-26 16:32:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":467}
|
||||
{"level":"info","time":"2025-12-26 16:32:47","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":468}
|
||||
{"level":"info","time":"2025-12-26 16:32:47","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":469}
|
||||
{"level":"info","time":"2025-12-26 16:32:47","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":470}
|
||||
{"level":"info","time":"2025-12-26 16:33:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":411}
|
||||
{"level":"info","time":"2025-12-26 16:33:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":418}
|
||||
{"level":"info","time":"2025-12-26 16:33:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":419}
|
||||
{"level":"info","time":"2025-12-26 16:33:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":420}
|
||||
{"level":"info","time":"2025-12-26 16:33:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":421}
|
||||
{"level":"info","time":"2025-12-26 16:33:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":422}
|
||||
{"level":"info","time":"2025-12-26 16:33:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":423}
|
||||
{"level":"info","time":"2025-12-26 16:33:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":424}
|
||||
{"level":"info","time":"2025-12-26 16:33:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":425}
|
||||
{"level":"info","time":"2025-12-26 16:33:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":426}
|
||||
{"level":"info","time":"2025-12-26 16:33:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":427}
|
||||
{"level":"info","time":"2025-12-26 16:33:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":428}
|
||||
{"level":"info","time":"2025-12-26 16:33:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":429}
|
||||
{"level":"info","time":"2025-12-26 16:33:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":430}
|
||||
{"level":"info","time":"2025-12-26 16:33:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":431}
|
||||
{"level":"info","time":"2025-12-26 16:33:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":432}
|
||||
{"level":"info","time":"2025-12-26 16:33:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":433}
|
||||
{"level":"info","time":"2025-12-26 16:33:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":434}
|
||||
{"level":"info","time":"2025-12-26 16:33:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":435}
|
||||
{"level":"info","time":"2025-12-26 16:33:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":436}
|
||||
{"level":"info","time":"2025-12-26 16:33:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":438}
|
||||
{"level":"info","time":"2025-12-26 16:33:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":440}
|
||||
{"level":"info","time":"2025-12-26 16:33:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":441}
|
||||
{"level":"info","time":"2025-12-26 16:33:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":442}
|
||||
{"level":"info","time":"2025-12-26 16:33:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":443}
|
||||
{"level":"info","time":"2025-12-26 16:33:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":444}
|
||||
{"level":"info","time":"2025-12-26 16:33:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":445}
|
||||
{"level":"info","time":"2025-12-26 16:33:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":446}
|
||||
{"level":"info","time":"2025-12-26 16:33:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":448}
|
||||
{"level":"info","time":"2025-12-26 16:33:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":449}
|
||||
{"level":"info","time":"2025-12-26 16:33:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":450}
|
||||
{"level":"info","time":"2025-12-26 16:33:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":451}
|
||||
{"level":"info","time":"2025-12-26 16:33:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":452}
|
||||
{"level":"info","time":"2025-12-26 16:33:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":453}
|
||||
{"level":"info","time":"2025-12-26 16:33:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":454}
|
||||
{"level":"info","time":"2025-12-26 16:33:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":455}
|
||||
{"level":"info","time":"2025-12-26 16:33:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":456}
|
||||
{"level":"info","time":"2025-12-26 16:33:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":457}
|
||||
{"level":"info","time":"2025-12-26 16:33:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":458}
|
||||
{"level":"info","time":"2025-12-26 16:33:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":459}
|
||||
{"level":"info","time":"2025-12-26 16:33:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":460}
|
||||
{"level":"info","time":"2025-12-26 16:33:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":461}
|
||||
{"level":"info","time":"2025-12-26 16:33:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":462}
|
||||
{"level":"info","time":"2025-12-26 16:33:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":463}
|
||||
{"level":"info","time":"2025-12-26 16:33:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":464}
|
||||
{"level":"info","time":"2025-12-26 16:33:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":465}
|
||||
{"level":"info","time":"2025-12-26 16:33:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":466}
|
||||
{"level":"info","time":"2025-12-26 16:33:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":467}
|
||||
{"level":"info","time":"2025-12-26 16:33:17","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":468}
|
||||
{"level":"info","time":"2025-12-26 16:33:17","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":469}
|
||||
{"level":"info","time":"2025-12-26 16:33:17","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":470}
|
||||
{"level":"info","time":"2025-12-26 16:33:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":411}
|
||||
{"level":"info","time":"2025-12-26 16:33:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":418}
|
||||
{"level":"info","time":"2025-12-26 16:33:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":419}
|
||||
{"level":"info","time":"2025-12-26 16:33:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":420}
|
||||
{"level":"info","time":"2025-12-26 16:33:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":421}
|
||||
{"level":"info","time":"2025-12-26 16:33:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":422}
|
||||
{"level":"info","time":"2025-12-26 16:33:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":423}
|
||||
{"level":"info","time":"2025-12-26 16:33:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":424}
|
||||
{"level":"info","time":"2025-12-26 16:33:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":425}
|
||||
{"level":"info","time":"2025-12-26 16:33:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":426}
|
||||
{"level":"info","time":"2025-12-26 16:33:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":427}
|
||||
{"level":"info","time":"2025-12-26 16:33:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":428}
|
||||
{"level":"info","time":"2025-12-26 16:33:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":429}
|
||||
{"level":"info","time":"2025-12-26 16:33:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":430}
|
||||
{"level":"info","time":"2025-12-26 16:33:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":431}
|
||||
{"level":"info","time":"2025-12-26 16:33:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":432}
|
||||
{"level":"info","time":"2025-12-26 16:33:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":433}
|
||||
{"level":"info","time":"2025-12-26 16:33:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":434}
|
||||
{"level":"info","time":"2025-12-26 16:33:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":435}
|
||||
{"level":"info","time":"2025-12-26 16:33:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":436}
|
||||
{"level":"info","time":"2025-12-26 16:33:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":438}
|
||||
{"level":"info","time":"2025-12-26 16:33:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":440}
|
||||
{"level":"info","time":"2025-12-26 16:33:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":441}
|
||||
{"level":"info","time":"2025-12-26 16:33:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":442}
|
||||
{"level":"info","time":"2025-12-26 16:33:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":443}
|
||||
{"level":"info","time":"2025-12-26 16:33:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":444}
|
||||
{"level":"info","time":"2025-12-26 16:33:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":445}
|
||||
{"level":"info","time":"2025-12-26 16:33:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":446}
|
||||
{"level":"info","time":"2025-12-26 16:33:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":448}
|
||||
{"level":"info","time":"2025-12-26 16:33:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":449}
|
||||
{"level":"info","time":"2025-12-26 16:33:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":450}
|
||||
{"level":"info","time":"2025-12-26 16:33:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":451}
|
||||
{"level":"info","time":"2025-12-26 16:33:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":452}
|
||||
{"level":"info","time":"2025-12-26 16:33:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":453}
|
||||
{"level":"info","time":"2025-12-26 16:33:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":454}
|
||||
{"level":"info","time":"2025-12-26 16:33:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":455}
|
||||
{"level":"info","time":"2025-12-26 16:33:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":456}
|
||||
{"level":"info","time":"2025-12-26 16:33:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":457}
|
||||
{"level":"info","time":"2025-12-26 16:33:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":458}
|
||||
{"level":"info","time":"2025-12-26 16:33:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":459}
|
||||
{"level":"info","time":"2025-12-26 16:33:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":460}
|
||||
{"level":"info","time":"2025-12-26 16:33:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":461}
|
||||
{"level":"info","time":"2025-12-26 16:33:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":462}
|
||||
{"level":"info","time":"2025-12-26 16:33:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":463}
|
||||
{"level":"info","time":"2025-12-26 16:33:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":464}
|
||||
{"level":"info","time":"2025-12-26 16:33:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":465}
|
||||
{"level":"info","time":"2025-12-26 16:33:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":466}
|
||||
{"level":"info","time":"2025-12-26 16:33:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":467}
|
||||
{"level":"info","time":"2025-12-26 16:33:47","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":468}
|
||||
{"level":"info","time":"2025-12-26 16:33:47","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":469}
|
||||
{"level":"info","time":"2025-12-26 16:33:47","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":470}
|
||||
{"level":"info","time":"2025-12-26 16:34:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":411}
|
||||
{"level":"info","time":"2025-12-26 16:34:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":418}
|
||||
{"level":"info","time":"2025-12-26 16:34:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":419}
|
||||
{"level":"info","time":"2025-12-26 16:34:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":420}
|
||||
{"level":"info","time":"2025-12-26 16:34:09","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":421}
|
||||
{"level":"info","time":"2025-12-26 16:34:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":422}
|
||||
{"level":"info","time":"2025-12-26 16:34:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":423}
|
||||
{"level":"info","time":"2025-12-26 16:34:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":424}
|
||||
{"level":"info","time":"2025-12-26 16:34:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":425}
|
||||
{"level":"info","time":"2025-12-26 16:34:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":426}
|
||||
{"level":"info","time":"2025-12-26 16:34:10","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":427}
|
||||
{"level":"info","time":"2025-12-26 16:34:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":428}
|
||||
{"level":"info","time":"2025-12-26 16:34:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":429}
|
||||
{"level":"info","time":"2025-12-26 16:34:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":430}
|
||||
{"level":"info","time":"2025-12-26 16:34:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":431}
|
||||
{"level":"info","time":"2025-12-26 16:34:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":432}
|
||||
{"level":"info","time":"2025-12-26 16:34:11","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":433}
|
||||
{"level":"info","time":"2025-12-26 16:34:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":434}
|
||||
{"level":"info","time":"2025-12-26 16:34:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":435}
|
||||
{"level":"info","time":"2025-12-26 16:34:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":436}
|
||||
{"level":"info","time":"2025-12-26 16:34:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":438}
|
||||
{"level":"info","time":"2025-12-26 16:34:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":440}
|
||||
{"level":"info","time":"2025-12-26 16:34:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":441}
|
||||
{"level":"info","time":"2025-12-26 16:34:12","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":442}
|
||||
{"level":"info","time":"2025-12-26 16:34:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":443}
|
||||
{"level":"info","time":"2025-12-26 16:34:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":444}
|
||||
{"level":"info","time":"2025-12-26 16:34:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":445}
|
||||
{"level":"info","time":"2025-12-26 16:34:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":446}
|
||||
{"level":"info","time":"2025-12-26 16:34:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":448}
|
||||
{"level":"info","time":"2025-12-26 16:34:13","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":449}
|
||||
{"level":"info","time":"2025-12-26 16:34:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":450}
|
||||
{"level":"info","time":"2025-12-26 16:34:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":451}
|
||||
{"level":"info","time":"2025-12-26 16:34:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":452}
|
||||
{"level":"info","time":"2025-12-26 16:34:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":453}
|
||||
{"level":"info","time":"2025-12-26 16:34:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":454}
|
||||
{"level":"info","time":"2025-12-26 16:34:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":455}
|
||||
{"level":"info","time":"2025-12-26 16:34:14","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":456}
|
||||
{"level":"info","time":"2025-12-26 16:34:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":457}
|
||||
{"level":"info","time":"2025-12-26 16:34:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":458}
|
||||
{"level":"info","time":"2025-12-26 16:34:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":459}
|
||||
{"level":"info","time":"2025-12-26 16:34:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":460}
|
||||
{"level":"info","time":"2025-12-26 16:34:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":461}
|
||||
{"level":"info","time":"2025-12-26 16:34:15","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":462}
|
||||
{"level":"info","time":"2025-12-26 16:34:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":463}
|
||||
{"level":"info","time":"2025-12-26 16:34:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":464}
|
||||
{"level":"info","time":"2025-12-26 16:34:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":465}
|
||||
{"level":"info","time":"2025-12-26 16:34:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":466}
|
||||
{"level":"info","time":"2025-12-26 16:34:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":467}
|
||||
{"level":"info","time":"2025-12-26 16:34:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":468}
|
||||
{"level":"info","time":"2025-12-26 16:34:16","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":469}
|
||||
{"level":"info","time":"2025-12-26 16:34:17","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":470}
|
||||
{"level":"info","time":"2025-12-26 16:34:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":411}
|
||||
{"level":"info","time":"2025-12-26 16:34:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":418}
|
||||
{"level":"info","time":"2025-12-26 16:34:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":419}
|
||||
{"level":"info","time":"2025-12-26 16:34:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":420}
|
||||
{"level":"info","time":"2025-12-26 16:34:39","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":421}
|
||||
{"level":"info","time":"2025-12-26 16:34:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":422}
|
||||
{"level":"info","time":"2025-12-26 16:34:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":423}
|
||||
{"level":"info","time":"2025-12-26 16:34:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":424}
|
||||
{"level":"info","time":"2025-12-26 16:34:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":425}
|
||||
{"level":"info","time":"2025-12-26 16:34:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":426}
|
||||
{"level":"info","time":"2025-12-26 16:34:40","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":427}
|
||||
{"level":"info","time":"2025-12-26 16:34:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":428}
|
||||
{"level":"info","time":"2025-12-26 16:34:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":429}
|
||||
{"level":"info","time":"2025-12-26 16:34:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":430}
|
||||
{"level":"info","time":"2025-12-26 16:34:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":431}
|
||||
{"level":"info","time":"2025-12-26 16:34:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":432}
|
||||
{"level":"info","time":"2025-12-26 16:34:41","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":433}
|
||||
{"level":"info","time":"2025-12-26 16:34:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":434}
|
||||
{"level":"info","time":"2025-12-26 16:34:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":435}
|
||||
{"level":"info","time":"2025-12-26 16:34:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":436}
|
||||
{"level":"info","time":"2025-12-26 16:34:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":438}
|
||||
{"level":"info","time":"2025-12-26 16:34:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":440}
|
||||
{"level":"info","time":"2025-12-26 16:34:42","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":441}
|
||||
{"level":"info","time":"2025-12-26 16:34:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":442}
|
||||
{"level":"info","time":"2025-12-26 16:34:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":443}
|
||||
{"level":"info","time":"2025-12-26 16:34:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":444}
|
||||
{"level":"info","time":"2025-12-26 16:34:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":445}
|
||||
{"level":"info","time":"2025-12-26 16:34:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":446}
|
||||
{"level":"info","time":"2025-12-26 16:34:43","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":448}
|
||||
{"level":"info","time":"2025-12-26 16:34:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":449}
|
||||
{"level":"info","time":"2025-12-26 16:34:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":450}
|
||||
{"level":"info","time":"2025-12-26 16:34:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":451}
|
||||
{"level":"info","time":"2025-12-26 16:34:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":452}
|
||||
{"level":"info","time":"2025-12-26 16:34:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":453}
|
||||
{"level":"info","time":"2025-12-26 16:34:44","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":454}
|
||||
{"level":"info","time":"2025-12-26 16:34:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":455}
|
||||
{"level":"info","time":"2025-12-26 16:34:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":456}
|
||||
{"level":"info","time":"2025-12-26 16:34:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":457}
|
||||
{"level":"info","time":"2025-12-26 16:34:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":458}
|
||||
{"level":"info","time":"2025-12-26 16:34:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":459}
|
||||
{"level":"info","time":"2025-12-26 16:34:45","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":460}
|
||||
{"level":"info","time":"2025-12-26 16:34:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":461}
|
||||
{"level":"info","time":"2025-12-26 16:34:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":462}
|
||||
{"level":"info","time":"2025-12-26 16:34:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":463}
|
||||
{"level":"info","time":"2025-12-26 16:34:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":464}
|
||||
{"level":"info","time":"2025-12-26 16:34:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":465}
|
||||
{"level":"info","time":"2025-12-26 16:34:46","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":466}
|
||||
{"level":"info","time":"2025-12-26 16:34:47","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":467}
|
||||
{"level":"info","time":"2025-12-26 16:34:47","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":468}
|
||||
{"level":"info","time":"2025-12-26 16:34:47","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":469}
|
||||
{"level":"info","time":"2025-12-26 16:34:47","caller":"logger/logger.go:309","msg":"开始原子化处理订单开奖","domain":"mini-chat[fat]","order_id":470}
|
||||
{"level":"info","time":"2025-12-26 16:37:47","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 16:37:47","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 16:37:47","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 16:37:47","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 16:37:47","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 16:37:47","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 16:37:47","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 16:38:52","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 16:38:52","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 16:38:53","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 16:38:53","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 16:38:53","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 16:38:53","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 16:38:53","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 16:40:43","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 16:40:43","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 16:40:44","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 16:40:44","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 16:40:44","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 16:40:44","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 16:40:44","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 17:00:34","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 17:00:34","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 17:00:34","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 17:00:34","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 17:00:34","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 17:00:34","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 17:00:34","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 17:03:01","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 17:03:01","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"fatal","time":"2025-12-26 17:03:01","caller":"logger/logger.go:333","msg":"http server startup err","domain":"mini-chat[fat]","error":"listen tcp :9991: bind: address already in use"}
|
||||
{"level":"info","time":"2025-12-26 17:08:44","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 17:08:44","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"fatal","time":"2025-12-26 17:08:44","caller":"logger/logger.go:333","msg":"http server startup err","domain":"mini-chat[fat]","error":"listen tcp :9991: bind: address already in use"}
|
||||
{"level":"info","time":"2025-12-26 17:08:53","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 17:08:53","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 17:08:53","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 17:08:53","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 17:08:53","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 17:08:53","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 17:08:53","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 17:14:20","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 17:14:20","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 17:14:20","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 17:14:20","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 17:14:20","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 17:14:20","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 17:14:20","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 17:17:27","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
|
||||
{"level":"info","time":"2025-12-26 17:17:27","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
|
||||
{"level":"info","time":"2025-12-26 17:17:27","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
|
||||
{"level":"info","time":"2025-12-26 17:17:27","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 17:17:27","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
|
||||
{"level":"info","time":"2025-12-26 17:17:27","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
|
||||
{"level":"info","time":"2025-12-26 17:17:27","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
|
||||
{"level":"info","time":"2025-12-26 17:21:19","caller":"logger/logger.go:309","msg":"Processing event","domain":"mini-chat[fat]","type":"order_paid","worker_id":0}
|
||||
{"level":"info","time":"2025-12-26 17:27:50","caller":"logger/logger.go:309","msg":"Processing event","domain":"mini-chat[fat]","type":"order_paid","worker_id":4}
|
||||
|
||||
2
main.go
2
main.go
@ -154,7 +154,7 @@ func main() {
|
||||
}
|
||||
}()
|
||||
|
||||
activitysvc.StartScheduledSettlement(customLogger, dbRepo)
|
||||
activitysvc.StartScheduledSettlement(customLogger, dbRepo, redis.GetClient())
|
||||
usersvc.StartExpirationCheck(customLogger, dbRepo)
|
||||
|
||||
// 优雅关闭
|
||||
|
||||
8
migrations/20251226_add_draw_index_unique.sql
Normal file
8
migrations/20251226_add_draw_index_unique.sql
Normal file
@ -0,0 +1,8 @@
|
||||
-- 迁移脚本:为 activity_draw_logs 增加序号字段并建立联合唯一索引
|
||||
-- 用于支持开奖幂等性
|
||||
|
||||
ALTER TABLE activity_draw_logs ADD COLUMN draw_index BIGINT NOT NULL DEFAULT 0 COMMENT '抽奖序号(0-N)';
|
||||
|
||||
-- 注意:如果表中已有数据,可能需要先初始化 draw_index (通常已有数据如果是单抽则默认为0没问题)
|
||||
-- 添加联合唯一索引,防止同一订单的同一个序号重复开奖
|
||||
ALTER TABLE activity_draw_logs ADD UNIQUE INDEX uk_order_draw (order_id, draw_index);
|
||||
Loading…
x
Reference in New Issue
Block a user