mirror of
https://gitee.com/wanwujie/sub2api
synced 2026-04-08 09:10:20 +08:00
Merge pull request #959 from touwaeriol/feat/antigravity-403-detection
feat(antigravity): add 403 forbidden status detection and display
This commit is contained in:
@@ -36,6 +36,10 @@
|
||||
|
||||
<!-- Usage data -->
|
||||
<div v-else-if="usageInfo" class="space-y-1">
|
||||
<!-- API error (degraded response) -->
|
||||
<div v-if="usageInfo.error" class="text-xs text-amber-600 dark:text-amber-400 truncate max-w-[200px]" :title="usageInfo.error">
|
||||
{{ usageInfo.error }}
|
||||
</div>
|
||||
<!-- 5h Window -->
|
||||
<UsageProgressBar
|
||||
v-if="usageInfo.five_hour"
|
||||
@@ -189,8 +193,53 @@
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Forbidden state (403) -->
|
||||
<div v-if="isForbidden" class="space-y-1">
|
||||
<span
|
||||
:class="[
|
||||
'inline-block rounded px-1.5 py-0.5 text-[10px] font-medium',
|
||||
forbiddenBadgeClass
|
||||
]"
|
||||
>
|
||||
{{ forbiddenLabel }}
|
||||
</span>
|
||||
<div v-if="validationURL" class="flex items-center gap-1">
|
||||
<a
|
||||
:href="validationURL"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="text-[10px] text-blue-600 hover:text-blue-800 hover:underline dark:text-blue-400 dark:hover:text-blue-300"
|
||||
:title="t('admin.accounts.openVerification')"
|
||||
>
|
||||
{{ t('admin.accounts.openVerification') }}
|
||||
</a>
|
||||
<button
|
||||
type="button"
|
||||
class="text-[10px] text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
|
||||
:title="t('admin.accounts.copyLink')"
|
||||
@click="copyValidationURL"
|
||||
>
|
||||
{{ linkCopied ? t('admin.accounts.linkCopied') : t('admin.accounts.copyLink') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Needs reauth (401) -->
|
||||
<div v-else-if="needsReauth" class="space-y-1">
|
||||
<span class="inline-block rounded px-1.5 py-0.5 text-[10px] font-medium bg-orange-100 text-orange-700 dark:bg-orange-900/40 dark:text-orange-300">
|
||||
{{ t('admin.accounts.needsReauth') }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Degraded error (non-403, non-401) -->
|
||||
<div v-else-if="usageInfo?.error" class="space-y-1">
|
||||
<span class="inline-block rounded px-1.5 py-0.5 text-[10px] font-medium bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-300">
|
||||
{{ usageErrorLabel }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Loading state -->
|
||||
<div v-if="loading" class="space-y-1.5">
|
||||
<div v-else-if="loading" class="space-y-1.5">
|
||||
<div class="flex items-center gap-1">
|
||||
<div class="h-3 w-[32px] animate-pulse rounded bg-gray-200 dark:bg-gray-700"></div>
|
||||
<div class="h-1.5 w-8 animate-pulse rounded-full bg-gray-200 dark:bg-gray-700"></div>
|
||||
@@ -816,6 +865,51 @@ const hasIneligibleTiers = computed(() => {
|
||||
return Array.isArray(ineligibleTiers) && ineligibleTiers.length > 0
|
||||
})
|
||||
|
||||
// Antigravity 403 forbidden 状态
|
||||
const isForbidden = computed(() => !!usageInfo.value?.is_forbidden)
|
||||
const forbiddenType = computed(() => usageInfo.value?.forbidden_type || 'forbidden')
|
||||
const validationURL = computed(() => usageInfo.value?.validation_url || '')
|
||||
|
||||
// 需要重新授权(401)
|
||||
const needsReauth = computed(() => !!usageInfo.value?.needs_reauth)
|
||||
|
||||
// 降级错误标签(rate_limited / network_error)
|
||||
const usageErrorLabel = computed(() => {
|
||||
const code = usageInfo.value?.error_code
|
||||
if (code === 'rate_limited') return t('admin.accounts.rateLimited')
|
||||
return t('admin.accounts.usageError')
|
||||
})
|
||||
|
||||
const forbiddenLabel = computed(() => {
|
||||
switch (forbiddenType.value) {
|
||||
case 'validation':
|
||||
return t('admin.accounts.forbiddenValidation')
|
||||
case 'violation':
|
||||
return t('admin.accounts.forbiddenViolation')
|
||||
default:
|
||||
return t('admin.accounts.forbidden')
|
||||
}
|
||||
})
|
||||
|
||||
const forbiddenBadgeClass = computed(() => {
|
||||
if (forbiddenType.value === 'validation') {
|
||||
return 'bg-yellow-100 text-yellow-700 dark:bg-yellow-900/40 dark:text-yellow-300'
|
||||
}
|
||||
return 'bg-red-100 text-red-700 dark:bg-red-900/40 dark:text-red-300'
|
||||
})
|
||||
|
||||
const linkCopied = ref(false)
|
||||
const copyValidationURL = async () => {
|
||||
if (!validationURL.value) return
|
||||
try {
|
||||
await navigator.clipboard.writeText(validationURL.value)
|
||||
linkCopied.value = true
|
||||
setTimeout(() => { linkCopied.value = false }, 2000)
|
||||
} catch {
|
||||
// fallback: ignore
|
||||
}
|
||||
}
|
||||
|
||||
const loadUsage = async () => {
|
||||
if (!shouldFetchUsage.value) return
|
||||
|
||||
|
||||
Reference in New Issue
Block a user