feat: add admin reset subscription quota endpoint and UI

- Add AdminResetQuota service method to reset daily/weekly usage windows
- Add POST /api/v1/admin/subscriptions/:id/reset-quota handler and route
- Add resetQuota API function in frontend subscriptions client
- Add reset quota button, confirmation dialog, and handlers in SubscriptionsView
- Add i18n keys for reset quota feature in zh and en locales

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
haruka
2026-03-10 11:21:11 +08:00
parent ac6bde7a98
commit de18bce9aa
7 changed files with 135 additions and 0 deletions

View File

@@ -370,6 +370,14 @@
<Icon name="calendar" size="sm" />
<span class="text-xs">{{ t('admin.subscriptions.adjust') }}</span>
</button>
<button
v-if="row.status === 'active'"
@click="handleResetQuota(row)"
class="flex flex-col items-center gap-0.5 rounded-lg p-1.5 text-gray-500 transition-colors hover:bg-orange-50 hover:text-orange-600 dark:hover:bg-orange-900/20 dark:hover:text-orange-400"
>
<Icon name="refresh" size="sm" />
<span class="text-xs">{{ t('admin.subscriptions.resetQuota') }}</span>
</button>
<button
v-if="row.status === 'active'"
@click="handleRevoke(row)"
@@ -618,6 +626,17 @@
@confirm="confirmRevoke"
@cancel="showRevokeDialog = false"
/>
<!-- Reset Quota Confirmation Dialog -->
<ConfirmDialog
:show="showResetQuotaConfirm"
:title="t('admin.subscriptions.resetQuotaTitle')"
:message="t('admin.subscriptions.resetQuotaConfirm', { user: resettingSubscription?.user?.email })"
:confirm-text="t('admin.subscriptions.resetQuota')"
:cancel-text="t('common.cancel')"
@confirm="confirmResetQuota"
@cancel="showResetQuotaConfirm = false"
/>
</AppLayout>
</template>
@@ -812,7 +831,10 @@ const pagination = reactive({
const showAssignModal = ref(false)
const showExtendModal = ref(false)
const showRevokeDialog = ref(false)
const showResetQuotaConfirm = ref(false)
const submitting = ref(false)
const resettingSubscription = ref<UserSubscription | null>(null)
const resettingQuota = ref(false)
const extendingSubscription = ref<UserSubscription | null>(null)
const revokingSubscription = ref<UserSubscription | null>(null)
@@ -1121,6 +1143,28 @@ const confirmRevoke = async () => {
}
}
const handleResetQuota = (subscription: UserSubscription) => {
resettingSubscription.value = subscription
showResetQuotaConfirm.value = true
}
const confirmResetQuota = async () => {
if (!resettingSubscription.value) return
resettingQuota.value = true
try {
await adminAPI.subscriptions.resetQuota(resettingSubscription.value.id, { daily: true, weekly: true })
appStore.showSuccess(t('admin.subscriptions.quotaResetSuccess'))
showResetQuotaConfirm.value = false
resettingSubscription.value = null
await loadSubscriptions()
} catch (error: any) {
appStore.showError(error.response?.data?.detail || t('admin.subscriptions.failedToResetQuota'))
console.error('Error resetting quota:', error)
} finally {
resettingQuota.value = false
}
}
// Helper functions
const getDaysRemaining = (expiresAt: string): number | null => {
const now = new Date()