mirror of
https://github.com/zc-zhangchen/any-auto-register.git
synced 2026-05-10 17:29:35 +08:00
fix(contribution): improve redeem feedback and backend fallback
This commit is contained in:
@@ -24,6 +24,10 @@ KEY_INFO_CANDIDATES: list[tuple[str, str]] = [
|
||||
("POST", "/public/key-info"),
|
||||
("POST", "/public/key/info"),
|
||||
]
|
||||
REDEEM_CANDIDATES: list[tuple[str, str]] = [
|
||||
("POST", "/public/redeem"),
|
||||
("POST", "/api/contribution/redeem"),
|
||||
]
|
||||
|
||||
|
||||
class ContributionProxyRequest(BaseModel):
|
||||
@@ -94,9 +98,13 @@ def _request_json(
|
||||
data = {"raw": response.text}
|
||||
|
||||
if response.status_code >= 400:
|
||||
detail = data
|
||||
detail: Any = data
|
||||
if isinstance(data, dict):
|
||||
detail = data.get("error") or data.get("message") or data
|
||||
detail = data.get("detail") or data.get("error") or data.get("message") or data
|
||||
if isinstance(detail, dict):
|
||||
detail = detail.get("message") or detail.get("error") or detail.get("code") or json_dumps_safe(detail)
|
||||
if not isinstance(detail, str):
|
||||
detail = json_dumps_safe(detail)
|
||||
raise HTTPException(status_code=response.status_code, detail=detail)
|
||||
|
||||
if isinstance(data, dict):
|
||||
@@ -104,6 +112,15 @@ def _request_json(
|
||||
return {"data": data}
|
||||
|
||||
|
||||
def json_dumps_safe(value: Any) -> str:
|
||||
try:
|
||||
import json
|
||||
|
||||
return json.dumps(value, ensure_ascii=False)
|
||||
except Exception:
|
||||
return str(value)
|
||||
|
||||
|
||||
@router.post("/quota-stats")
|
||||
def get_quota_stats(body: ContributionProxyRequest):
|
||||
server_url = _resolve_server_url(body.server_url)
|
||||
@@ -221,16 +238,48 @@ def get_key_info(body: ContributionProxyRequest):
|
||||
def redeem(body: ContributionRedeemRequest):
|
||||
server_url = _resolve_server_url(body.server_url)
|
||||
key = _resolve_key(body.key)
|
||||
data = _request_json(
|
||||
"POST",
|
||||
server_url,
|
||||
"/public/redeem",
|
||||
key,
|
||||
payload={"amount_usd": body.amount_usd},
|
||||
)
|
||||
attempts: list[dict[str, Any]] = []
|
||||
data: dict[str, Any] | None = None
|
||||
endpoint_hit = ""
|
||||
|
||||
for method, endpoint in REDEEM_CANDIDATES:
|
||||
try:
|
||||
data = _request_json(
|
||||
method,
|
||||
server_url,
|
||||
endpoint,
|
||||
key,
|
||||
payload={"amount_usd": body.amount_usd},
|
||||
)
|
||||
endpoint_hit = endpoint
|
||||
break
|
||||
except HTTPException as exc:
|
||||
attempts.append(
|
||||
{
|
||||
"method": method,
|
||||
"endpoint": endpoint,
|
||||
"status_code": exc.status_code,
|
||||
"detail": exc.detail,
|
||||
}
|
||||
)
|
||||
|
||||
if data is None:
|
||||
raise HTTPException(
|
||||
status_code=502,
|
||||
detail={
|
||||
"message": "调用提现接口失败,请确认 codex2api 是否已启用 /public/redeem",
|
||||
"attempts": attempts,
|
||||
},
|
||||
)
|
||||
|
||||
redeemed_amount = data.get("redeemed_amount_usd")
|
||||
redeem_code = data.get("code")
|
||||
return {
|
||||
"ok": True,
|
||||
"endpoint": "/public/redeem",
|
||||
"endpoint": endpoint_hit or "/public/redeem",
|
||||
"redeemed_amount_usd": redeemed_amount,
|
||||
"code": redeem_code,
|
||||
"message": f"提现成功!额度:{redeemed_amount if redeemed_amount is not None else '-'} 兑换码:{redeem_code or '-'}",
|
||||
"data": data,
|
||||
}
|
||||
|
||||
|
||||
@@ -1106,6 +1106,13 @@ function ContributionPanel({
|
||||
const serverQuotaUsedPercent = pickNumber(serverInfo, ['quota_used_percent'])
|
||||
const serverQuotaRemainingPercent = pickNumber(serverInfo, ['quota_remaining_percent'])
|
||||
const serverQuotaRemainingAccounts = pickNumber(serverInfo, ['quota_remaining_accounts'])
|
||||
const redeemData = asRecord(redeemResponse?.['data']) || asRecord(redeemResponse)
|
||||
const redeemCode = pickString(redeemData, ['code', 'redeem_code', 'voucher_code'])
|
||||
const redeemedAmountUSD = pickNumber(redeemData, ['redeemed_amount_usd', 'redeemed_amount', 'amount_usd'])
|
||||
const redeemSuccessText =
|
||||
redeemResponse
|
||||
? `提现成功!额度:${redeemedAmountUSD !== null ? formatDisplayNumber(redeemedAmountUSD, 2) : '-'} 兑换码:${redeemCode || '-'}`
|
||||
: ''
|
||||
|
||||
const fetchStats = async (silent = false, keyOverride?: string) => {
|
||||
if (!contributionEnabled) {
|
||||
@@ -1172,11 +1179,21 @@ function ContributionPanel({
|
||||
amount_usd: redeemAmount,
|
||||
}),
|
||||
})
|
||||
setRedeemResponse(asRecord(data))
|
||||
message.success('提现请求已提交')
|
||||
const result = asRecord(data)
|
||||
const payload = asRecord(result?.['data']) || result
|
||||
const code = pickString(payload, ['code', 'redeem_code', 'voucher_code'])
|
||||
const amount = pickNumber(payload, ['redeemed_amount_usd', 'redeemed_amount', 'amount_usd'])
|
||||
setRedeemResponse(result)
|
||||
if (amount !== null || code) {
|
||||
message.success(`提现成功!额度:${amount !== null ? formatDisplayNumber(amount, 2) : '-'} 兑换码:${code || '-'}`)
|
||||
} else {
|
||||
message.success('提现成功')
|
||||
}
|
||||
await fetchStats(true)
|
||||
} catch (e: any) {
|
||||
message.error(String(e?.message || '提现失败'))
|
||||
const detail = String(e?.message || '提现失败')
|
||||
setRedeemResponse({ ok: false, error: detail })
|
||||
message.error(detail)
|
||||
} finally {
|
||||
setRedeeming(false)
|
||||
}
|
||||
@@ -1323,7 +1340,12 @@ function ContributionPanel({
|
||||
提现确认
|
||||
</Button>
|
||||
{redeemResponse ? (
|
||||
<pre style={{ marginTop: 8, whiteSpace: 'pre-wrap' }}>{formatResultText(redeemResponse)}</pre>
|
||||
<Alert
|
||||
type={redeemResponse.ok === false ? 'error' : 'success'}
|
||||
showIcon
|
||||
message={redeemResponse.ok === false ? `提现失败:${String(redeemResponse.error || '-')}` : redeemSuccessText}
|
||||
description={<pre style={{ margin: 0, whiteSpace: 'pre-wrap' }}>{formatResultText(redeemResponse)}</pre>}
|
||||
/>
|
||||
) : null}
|
||||
</Space>
|
||||
</Card>
|
||||
|
||||
Reference in New Issue
Block a user