package service import ( "context" "log" "strings" "affiliate_dash/internal/model" "gorm.io/gorm" ) // Token 生命周期事件类型。 const ( rockTokenEventCreated = "created" rockTokenEventStatusChanged = "status_changed" rockTokenEventDeleted = "deleted" rockTokenEventRestored = "restored" ) // Token 状态来源,用于前端展示流转原因。 const ( rockTokenSourceAssign = "assign" rockTokenSourceBindCheck = "bindcheck" rockTokenSourceRedeem = "redeem" rockTokenSourceRefresh = "refresh" rockTokenSourceRelease = "release" rockTokenSourceReset = "reset" rockTokenSourceManual = "manual" rockTokenSourceOrderCancel = "order_cancel" rockTokenSourcePurchase = "purchase" rockTokenSourcePackageSync = "package_sync" rockTokenSourceDelete = "delete" rockTokenSourceRestore = "restore" ) // writeRockTokenStatusLog 记录 Token 生命周期/状态变化。 // // 采用 best-effort:日志写入失败只打印错误,不影响主流程(避免因为审计表异常阻断发货)。 func writeRockTokenStatusLog(tx *gorm.DB, token *model.RockToken, eventType, from, to, source, reason string, forced bool, actorUserID *uint) { if tx == nil || token == nil || token.ID == 0 { return } entry := &model.RockTokenStatusLog{ TokenID: token.ID, UpstreamTokenID: strings.TrimSpace(token.UpstreamTokenID), EventType: eventType, FromStatus: from, ToStatus: to, Source: source, Reason: truncateRunes(strings.TrimSpace(reason), 240), Forced: forced, ActorUserID: actorUserID, } if err := tx.Create(entry).Error; err != nil { log.Printf("[Rock] 写入 Token 状态日志失败 token=%d %s->%s: %v", token.ID, from, to, err) } } // writeRockTokenStatusChange 仅在状态确实发生变化时写日志。 func writeRockTokenStatusChange(tx *gorm.DB, token *model.RockToken, from, to, source, reason string, forced bool, actorUserID *uint) { if strings.TrimSpace(from) == strings.TrimSpace(to) { return } writeRockTokenStatusLog(tx, token, rockTokenEventStatusChanged, from, to, source, reason, forced, actorUserID) } func truncateRunes(value string, limit int) string { if limit <= 0 { return "" } runes := []rune(value) if len(runes) <= limit { return value } return string(runes[:limit]) } // ListTokenStatusLogs 返回指定 Token 的状态历史(最新在前)。 func (s *RockService) ListTokenStatusLogs(ctx context.Context, tokenID uint) ([]model.RockTokenStatusLog, error) { var token model.RockToken if err := s.db.WithContext(ctx).Unscoped().First(&token, tokenID).Error; err != nil { return nil, err } var logs []model.RockTokenStatusLog if err := s.db.WithContext(ctx). Where("token_id = ?", tokenID). Order("id DESC"). Limit(200). Find(&logs).Error; err != nil { return nil, err } return logs, nil }