From c9be17778d0c72a097702b9b1632085d76fb1944 Mon Sep 17 00:00:00 2001 From: Yanshan Chen Date: Mon, 14 Sep 2026 15:47:32 +0800 Subject: [PATCH] fix(accounts): consume reset credits without card details (#81) Allow count-only reset inventories to request upstream card selection without a credit ID. Preserve confirmation and idempotent retry guards, and place the fallback action in the shared modal footer with balanced inventory spacing. Co-authored-by: Yanshan Chen <16632048+chenyanshan@users.noreply.github.com> Co-authored-by: Codex --- .../openai/tests/transport/reset_credits.rs | 44 +++++++++++++++++++ .../AccountQuotaPanel/ResetCredits.vue | 38 ++++++++++++---- .../composables/useAccountResetCredits.ts | 18 +++++--- 3 files changed, 84 insertions(+), 16 deletions(-) diff --git a/backend/crates/providers/openai/tests/transport/reset_credits.rs b/backend/crates/providers/openai/tests/transport/reset_credits.rs index 785c82b96..173311ce1 100644 --- a/backend/crates/providers/openai/tests/transport/reset_credits.rs +++ b/backend/crates/providers/openai/tests/transport/reset_credits.rs @@ -146,6 +146,50 @@ async fn consume_should_send_exact_credit_and_redeem_request_id_without_retry() ); } +#[tokio::test] +async fn count_only_credits_should_allow_upstream_selected_consumption() { + let server = MockServer::start().await; + Mock::given(method("GET")) + .and(path("/api/codex/rate-limit-reset-credits")) + .respond_with(ResponseTemplate::new(200).set_body_json(json!({ + "available_count": 1, + "credits": [] + }))) + .expect(1) + .mount(&server) + .await; + Mock::given(method("POST")) + .and(path("/api/codex/rate-limit-reset-credits/consume")) + .respond_with(ResponseTemplate::new(200).set_body_json(json!({ "code": "reset" }))) + .expect(1) + .mount(&server) + .await; + let client = client(&server.uri()); + let credits = client + .list_rate_limit_reset_credits(context()) + .await + .expect("count-only reset credits"); + assert_eq!(credits.available_count, 1); + assert!(credits.credits.is_empty()); + + let redeem_request_id = + Uuid::parse_str("8fbf302d-11df-4bd5-82e4-08e4b3df7874").expect("redeem request ID"); + let result = client + .consume_rate_limit_reset_credit(context(), None, redeem_request_id) + .await + .expect("upstream-selected reset-credit consume"); + assert_eq!(result.code, "reset"); + let requests = server.received_requests().await.expect("received requests"); + let request = requests + .iter() + .find(|request| request.method == Method::POST) + .expect("consume request"); + assert_eq!( + serde_json::from_slice::(&request.body).expect("consume JSON"), + json!({ "redeem_request_id": "8fbf302d-11df-4bd5-82e4-08e4b3df7874" }) + ); +} + #[tokio::test] async fn consume_should_preserve_raw_upstream_error_and_never_retry() { let server = MockServer::start().await; diff --git a/frontend/src/views/accounts/components/AccountQuotaPanel/ResetCredits.vue b/frontend/src/views/accounts/components/AccountQuotaPanel/ResetCredits.vue index 9cb3dfbf2..c927bb70a 100644 --- a/frontend/src/views/accounts/components/AccountQuotaPanel/ResetCredits.vue +++ b/frontend/src/views/accounts/components/AccountQuotaPanel/ResetCredits.vue @@ -60,12 +60,18 @@ const triggerLabel = computed(() => { return hasSnapshot.value ? `查看主动重置卡,最近查询 ${availableCount.value} 张可用` : '查看主动重置卡' }) const showTriggerCount = computed(() => hasSnapshot.value && availableCount.value > 0) -const confirmCreditTitle = computed(() => creditTitle(consumptionCredit.value)) +const confirmCreditTitle = computed(() => consumptionCredit.value + ? creditTitle(consumptionCredit.value) + : '使用一次重置(由上游选择)') const creditItems = computed(() => availableCredits.value.map(credit => ({ id: credit.id, title: creditTitle(credit), expiry: expiryLabel(credit.expiresAt), }))) +const showCountOnlyAction = computed(() => !loadError.value + && hasSnapshot.value + && availableCount.value > 0 + && creditItems.value.length === 0) const countLabel = computed(() => { if (!hasSnapshot.value) return loading.value ? '查询中' : '待查询' @@ -159,7 +165,10 @@ function handleRequestConsume(creditId: string) {
-
+

使用限额重置

@@ -227,7 +236,7 @@ function handleRequestConsume(creditId: string) {
-