diff --git a/frontend/src/i18n/locales/en.ts b/frontend/src/i18n/locales/en.ts index 2b309af1..ae27d9cf 100644 --- a/frontend/src/i18n/locales/en.ts +++ b/frontend/src/i18n/locales/en.ts @@ -914,6 +914,7 @@ export default { failedToRevoke: 'Failed to revoke subscription', pleaseSelectUser: 'Please select a user', pleaseSelectGroup: 'Please select a group', + validityDaysRequired: 'Please enter a valid number of days (at least 1)', revokeConfirm: "Are you sure you want to revoke the subscription for '{user}'? This action cannot be undone." }, @@ -1652,6 +1653,11 @@ export default { failedToDelete: 'Failed to delete code', failedToDeleteUnused: 'Failed to delete unused codes', failedToCopy: 'Failed to copy codes', + types: { + balance: 'Balance', + concurrency: 'Concurrency', + subscription: 'Subscription' + }, selectGroup: 'Select Group', selectGroupPlaceholder: 'Choose a subscription group', validityDays: 'Validity Days', diff --git a/frontend/src/i18n/locales/zh.ts b/frontend/src/i18n/locales/zh.ts index 25dd929c..f401d9a0 100644 --- a/frontend/src/i18n/locales/zh.ts +++ b/frontend/src/i18n/locales/zh.ts @@ -991,6 +991,7 @@ export default { failedToRevoke: '撤销订阅失败', pleaseSelectUser: '请选择用户', pleaseSelectGroup: '请选择分组', + validityDaysRequired: '请输入有效的天数(至少1天)', revokeConfirm: "确定要撤销 '{user}' 的订阅吗?此操作无法撤销。" }, diff --git a/frontend/src/views/admin/GroupsView.vue b/frontend/src/views/admin/GroupsView.vue index 95918e6e..d8400041 100644 --- a/frontend/src/views/admin/GroupsView.vue +++ b/frontend/src/views/admin/GroupsView.vue @@ -7,7 +7,7 @@
[ const filterStatusOptions = computed(() => [ { value: '', label: t('admin.redeem.allStatus') }, { value: 'unused', label: t('admin.redeem.unused') }, - { value: 'used', label: t('admin.redeem.used') } + { value: 'used', label: t('admin.redeem.used') }, + { value: 'expired', label: t('admin.redeem.status.expired') } ]) const codes = ref([]) diff --git a/frontend/src/views/admin/SubscriptionsView.vue b/frontend/src/views/admin/SubscriptionsView.vue index a0b78062..50fe4cbe 100644 --- a/frontend/src/views/admin/SubscriptionsView.vue +++ b/frontend/src/views/admin/SubscriptionsView.vue @@ -877,6 +877,10 @@ const handleAssignSubscription = async () => { appStore.showError(t('admin.subscriptions.pleaseSelectGroup')) return } + if (!assignForm.validity_days || assignForm.validity_days < 1) { + appStore.showError(t('admin.subscriptions.validityDaysRequired')) + return + } submitting.value = true try { @@ -960,15 +964,17 @@ const isExpiringSoon = (expiresAt: string): boolean => { return days !== null && days <= 7 } -const getProgressWidth = (used: number, limit: number | null): string => { +const getProgressWidth = (used: number | null | undefined, limit: number | null): string => { if (!limit || limit === 0) return '0%' - const percentage = Math.min((used / limit) * 100, 100) + const usedValue = used ?? 0 + const percentage = Math.min((usedValue / limit) * 100, 100) return `${percentage}%` } -const getProgressClass = (used: number, limit: number | null): string => { +const getProgressClass = (used: number | null | undefined, limit: number | null): string => { if (!limit || limit === 0) return 'bg-gray-400' - const percentage = (used / limit) * 100 + const usedValue = used ?? 0 + const percentage = (usedValue / limit) * 100 if (percentage >= 90) return 'bg-red-500' if (percentage >= 70) return 'bg-orange-500' return 'bg-green-500'