Merge pull request #4620 from cugxuan/codex/show-subscription-expiry-minute

feat(subscription): show expiry times to minute
This commit is contained in:
Wesley Liddick
2026-07-20 10:24:30 +08:00
committed by GitHub
4 changed files with 41 additions and 5 deletions
@@ -0,0 +1,15 @@
import { describe, expect, it } from 'vitest'
import { formatDateTimeToMinute } from '../format'
describe('formatDateTimeToMinute', () => {
it('formats local date and time without seconds', () => {
const value = new Date(2026, 6, 19, 20, 30, 45)
expect(formatDateTimeToMinute(value, 'en-GB')).toBe('19/07/2026, 20:30')
})
it('returns an empty string for an invalid date', () => {
expect(formatDateTimeToMinute(new Date('invalid'), 'en-GB')).toBe('')
})
})
+21
View File
@@ -149,6 +149,27 @@ export function formatDateTime(
return formatDate(date, options, localeOverride)
}
/**
* 格式化日期时间(精确到分钟)
*/
export function formatDateTimeToMinute(
date: string | Date | null | undefined,
localeOverride?: string
): string {
return formatDate(
date,
{
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
hour12: false
},
localeOverride
)
}
/**
* 格式化为 date 控件值(YYYY-MM-DD,使用本地时间)
*/
@@ -351,7 +351,7 @@
: 'text-gray-700 dark:text-gray-300'
"
>
{{ formatDateOnly(value) }}
{{ formatDateTimeToMinute(value) }}
</span>
<div v-if="getDaysRemaining(value) !== null" class="text-xs text-gray-500">
{{ getDaysRemaining(value) }} {{ t('admin.subscriptions.daysRemaining') }}
@@ -598,7 +598,7 @@
<span class="font-medium text-gray-900 dark:text-white">
{{
extendingSubscription.expires_at
? formatDateOnly(extendingSubscription.expires_at)
? formatDateTimeToMinute(extendingSubscription.expires_at)
: t('admin.subscriptions.noExpiration')
}}
</span>
@@ -764,7 +764,7 @@ import { adminAPI } from '@/api/admin'
import type { UserSubscription, Group, GroupPlatform, SubscriptionType } from '@/types'
import type { SimpleUser } from '@/api/admin/usage'
import type { Column } from '@/components/common/types'
import { formatDateOnly } from '@/utils/format'
import { formatDateTimeToMinute } from '@/utils/format'
import { getPersistedPageSize } from '@/composables/usePersistedPageSize'
import AppLayout from '@/components/layout/AppLayout.vue'
import TablePageLayout from '@/components/layout/TablePageLayout.vue'
@@ -256,7 +256,7 @@ import subscriptionsAPI from '@/api/subscriptions'
import type { UserSubscription } from '@/types'
import AppLayout from '@/components/layout/AppLayout.vue'
import Icon from '@/components/icons/Icon.vue'
import { formatDateOnly } from '@/utils/format'
import { formatDateTimeToMinute } from '@/utils/format'
import { hasPeakRate, formatPeakRateWindow, serverTimezoneLabel } from '@/utils/peak-rate'
import { platformBorderClass, platformBadgeClass, platformButtonClass, platformLabel } from '@/utils/platformColors'
import { getRemainingDurationParts, isOneTimeDailyQuota, type RemainingDurationParts } from '@/utils/subscriptionQuota'
@@ -322,7 +322,7 @@ function formatExpirationDate(expiresAt: string): string {
return t('userSubscriptions.status.expired')
}
const dateStr = formatDateOnly(expires)
const dateStr = formatDateTimeToMinute(expires)
if (days === 0) {
return `${dateStr} (${t('common.today')})`