package service import ( "context" "strings" "time" "affiliate_dash/internal/model" ) type rockRefreshCacheItem struct { response *RockRefreshResponse cachedAt time.Time } // 腾讯活动链接按生成时间签名。同一提货号过期后重取链接,不另发新号。 const rockBindLinkMaxAge = 8 * time.Minute type rockBindLinkCacheItem struct { bindURL string qrURL string cachedAt time.Time } func (s *RockService) rememberBindLink(tokenID uint, bindURL, qrURL string) { bindURL = strings.TrimSpace(bindURL) if s == nil || tokenID == 0 || bindURL == "" { return } qrURL = strings.TrimSpace(qrURL) if qrURL == "" { qrURL = qrCodeURL(bindURL) } s.bindLinkCache.Store(tokenID, rockBindLinkCacheItem{ bindURL: bindURL, qrURL: qrURL, cachedAt: time.Now(), }) } // freshBindLink 只为仍在扫码的同一提货号重取活动链接。过期前复用缓存,避免每轮轮询都打 0666。 func (s *RockService) freshBindLink(ctx context.Context, tokenID uint, orderNo string) (string, string) { if s == nil || s.client == nil || tokenID == 0 { return "", "" } var token model.RockToken if err := s.db.WithContext(ctx).First(&token, tokenID).Error; err != nil { return "", "" } if token.Status != model.RockStatusUsing || strings.TrimSpace(token.RedeemCode) == "" { return "", "" } if orderNo = strings.TrimSpace(orderNo); orderNo != "" && token.AssignedOrderNo != "" && token.AssignedOrderNo != orderNo { return "", "" } if item, ok := s.bindLinkCache.Load(token.ID); ok { cached := item.(rockBindLinkCacheItem) if cached.bindURL != "" && time.Since(cached.cachedAt) < rockBindLinkMaxAge { return cached.bindURL, cached.qrURL } } detail, err := s.client.GetRedeemDetail(ctx, token.RedeemCode) if err != nil || detail == nil || strings.TrimSpace(detail.BindURL) == "" { if item, ok := s.bindLinkCache.Load(token.ID); ok { cached := item.(rockBindLinkCacheItem) return cached.bindURL, cached.qrURL } return "", "" } bindURL := strings.TrimSpace(detail.BindURL) qrURL := strings.TrimSpace(detail.QRURL) s.rememberBindLink(token.ID, bindURL, qrURL) if qrURL == "" { qrURL = qrCodeURL(bindURL) } return bindURL, qrURL }