package mysql import ( "context" "strings" "hyapp/pkg/appcode" "hyapp/pkg/xerr" "hyapp/services/wallet-service/internal/domain/ledger" ) // ListRechargeBills 查询 wallet-service 的充值账单投影,后台不能直接读写业务库内部语义。 func (r *Repository) ListRechargeBills(ctx context.Context, query ledger.ListRechargeBillsQuery) ([]ledger.RechargeBill, int64, error) { if r == nil || r.db == nil { return nil, 0, xerr.New(xerr.Unavailable, "mysql repository is not configured") } ctx = contextWithCommandApp(ctx, query.AppCode) query = normalizeRechargeBillsQuery(query) query.AppCode = appcode.FromContext(ctx) where, args := rechargeBillsWhereSQL(query) total, err := r.countRechargeBillRows(ctx, where, args...) if err != nil { return nil, 0, err } rows, err := r.db.QueryContext(ctx, ` SELECT rr.app_code, rr.transaction_id, wt.command_id, wt.biz_type, wt.status, wt.external_ref, rr.user_id, rr.seller_user_id, rr.seller_region_id, rr.target_region_id, rr.policy_id, rr.policy_version, rr.currency_code, rr.coin_amount, rr.usd_minor_amount, rr.exchange_coin_amount, rr.exchange_usd_minor_amount, rr.created_at_ms FROM wallet_recharge_records rr JOIN wallet_transactions wt ON wt.app_code = rr.app_code AND wt.transaction_id = rr.transaction_id `+where+` ORDER BY rr.created_at_ms DESC, rr.transaction_id DESC LIMIT ? OFFSET ?`, append(args, query.PageSize, resourceOffset(query.Page, query.PageSize))..., ) if err != nil { return nil, 0, err } defer rows.Close() items := make([]ledger.RechargeBill, 0, query.PageSize) for rows.Next() { var item ledger.RechargeBill if err := rows.Scan( &item.AppCode, &item.TransactionID, &item.CommandID, &item.RechargeType, &item.Status, &item.ExternalRef, &item.UserID, &item.SellerUserID, &item.SellerRegionID, &item.TargetRegionID, &item.PolicyID, &item.PolicyVersion, &item.CurrencyCode, &item.CoinAmount, &item.USDMinorAmount, &item.ExchangeCoinAmount, &item.ExchangeUSDMinorAmount, &item.CreatedAtMS, ); err != nil { return nil, 0, err } items = append(items, item) } if err := rows.Err(); err != nil { return nil, 0, err } return items, total, nil } func (r *Repository) countRechargeBillRows(ctx context.Context, where string, args ...any) (int64, error) { var total int64 err := r.db.QueryRowContext(ctx, ` SELECT COUNT(*) FROM wallet_recharge_records rr JOIN wallet_transactions wt ON wt.app_code = rr.app_code AND wt.transaction_id = rr.transaction_id `+where, args..., ).Scan(&total) return total, err } func normalizeRechargeBillsQuery(query ledger.ListRechargeBillsQuery) ledger.ListRechargeBillsQuery { query.AppCode = appcode.Normalize(query.AppCode) query.RechargeType = strings.ToLower(strings.TrimSpace(query.RechargeType)) query.Status = strings.ToLower(strings.TrimSpace(query.Status)) query.Keyword = strings.TrimSpace(query.Keyword) query.Page, query.PageSize = normalizePage(query.Page, query.PageSize) if query.EndAtMS > 0 && query.StartAtMS > query.EndAtMS { query.StartAtMS, query.EndAtMS = query.EndAtMS, query.StartAtMS } return query } func rechargeBillsWhereSQL(query ledger.ListRechargeBillsQuery) (string, []any) { where := `WHERE rr.app_code = ?` args := []any{query.AppCode} if query.UserID > 0 { where += ` AND rr.user_id = ?` args = append(args, query.UserID) } if query.SellerUserID > 0 { where += ` AND rr.seller_user_id = ?` args = append(args, query.SellerUserID) } if query.RegionID > 0 { where += ` AND rr.target_region_id = ?` args = append(args, query.RegionID) } if query.RechargeType != "" { where += ` AND wt.biz_type = ?` args = append(args, query.RechargeType) } if query.Status != "" { where += ` AND wt.status = ?` args = append(args, query.Status) } if query.StartAtMS > 0 { where += ` AND rr.created_at_ms >= ?` args = append(args, query.StartAtMS) } if query.EndAtMS > 0 { where += ` AND rr.created_at_ms < ?` args = append(args, query.EndAtMS) } if query.Keyword != "" { like := "%" + query.Keyword + "%" where += ` AND (rr.transaction_id LIKE ? OR wt.command_id LIKE ? OR wt.external_ref LIKE ? OR rr.policy_version LIKE ?)` args = append(args, like, like, like, like) } return where, args }