mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-11-02 08:31:35 +00:00
Merge pull request #2557 from Arron196/fix/issue-2542-daily-card-expiry-mode
fix: 修复日卡跨日重复刷新额度
This commit is contained in:
@@ -246,7 +246,7 @@
|
||||
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<span>{{ formatResetTime(row.daily_window_start, 'daily') }}</span>
|
||||
<span>{{ formatDailyUsageWindow(row) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -758,6 +758,7 @@ import Select from '@/components/common/Select.vue'
|
||||
import GroupBadge from '@/components/common/GroupBadge.vue'
|
||||
import GroupOptionItem from '@/components/common/GroupOptionItem.vue'
|
||||
import Icon from '@/components/icons/Icon.vue'
|
||||
import { getRemainingDurationParts, isOneTimeDailyQuota, type RemainingDurationParts } from '@/utils/subscriptionQuota'
|
||||
|
||||
const { t } = useI18n()
|
||||
const appStore = useAppStore()
|
||||
@@ -1313,8 +1314,41 @@ const getProgressClass = (used: number | null | undefined, limit: number | null)
|
||||
return 'bg-green-500'
|
||||
}
|
||||
|
||||
const formatResetDuration = (parts: RemainingDurationParts): string => {
|
||||
if (parts.days > 0) {
|
||||
return t('admin.subscriptions.resetInDaysHours', { days: parts.days, hours: parts.hours })
|
||||
}
|
||||
|
||||
if (parts.hours > 0) {
|
||||
return t('admin.subscriptions.resetInHoursMinutes', { hours: parts.hours, minutes: parts.minutes })
|
||||
}
|
||||
|
||||
return t('admin.subscriptions.resetInMinutes', { minutes: parts.minutes })
|
||||
}
|
||||
|
||||
const formatQuotaEndDuration = (parts: RemainingDurationParts): string => {
|
||||
if (parts.days > 0) {
|
||||
return t('admin.subscriptions.quotaEndsInDaysHours', { days: parts.days, hours: parts.hours })
|
||||
}
|
||||
|
||||
if (parts.hours > 0) {
|
||||
return t('admin.subscriptions.quotaEndsInHoursMinutes', { hours: parts.hours, minutes: parts.minutes })
|
||||
}
|
||||
|
||||
return t('admin.subscriptions.quotaEndsInMinutes', { minutes: parts.minutes })
|
||||
}
|
||||
|
||||
const formatDailyUsageWindow = (subscription: UserSubscription): string => {
|
||||
if (isOneTimeDailyQuota(subscription) && subscription.expires_at) {
|
||||
const parts = getRemainingDurationParts(subscription.expires_at)
|
||||
return parts ? formatQuotaEndDuration(parts) : t('admin.subscriptions.windowNotActive')
|
||||
}
|
||||
|
||||
return formatResetTime(subscription.daily_window_start, 'daily')
|
||||
}
|
||||
|
||||
// Format reset time based on window start and period type
|
||||
const formatResetTime = (windowStart: string, period: 'daily' | 'weekly' | 'monthly'): string => {
|
||||
const formatResetTime = (windowStart: string | null, period: 'daily' | 'weekly' | 'monthly'): string => {
|
||||
if (!windowStart) return t('admin.subscriptions.windowNotActive')
|
||||
|
||||
const start = new Date(windowStart)
|
||||
@@ -1334,21 +1368,9 @@ const formatResetTime = (windowStart: string, period: 'daily' | 'weekly' | 'mont
|
||||
break
|
||||
}
|
||||
|
||||
const diffMs = resetTime.getTime() - now.getTime()
|
||||
if (diffMs <= 0) return t('admin.subscriptions.windowNotActive')
|
||||
const parts = getRemainingDurationParts(resetTime, now)
|
||||
|
||||
const diffSeconds = Math.floor(diffMs / 1000)
|
||||
const days = Math.floor(diffSeconds / 86400)
|
||||
const hours = Math.floor((diffSeconds % 86400) / 3600)
|
||||
const minutes = Math.floor((diffSeconds % 3600) / 60)
|
||||
|
||||
if (days > 0) {
|
||||
return t('admin.subscriptions.resetInDaysHours', { days, hours })
|
||||
} else if (hours > 0) {
|
||||
return t('admin.subscriptions.resetInHoursMinutes', { hours, minutes })
|
||||
} else {
|
||||
return t('admin.subscriptions.resetInMinutes', { minutes })
|
||||
}
|
||||
return parts ? formatResetDuration(parts) : t('admin.subscriptions.windowNotActive')
|
||||
}
|
||||
|
||||
// Handle click outside to close dropdowns
|
||||
|
||||
@@ -127,11 +127,7 @@
|
||||
v-if="subscription.daily_window_start"
|
||||
class="text-xs text-gray-500 dark:text-dark-400"
|
||||
>
|
||||
{{
|
||||
t('userSubscriptions.resetIn', {
|
||||
time: formatResetTime(subscription.daily_window_start, 24)
|
||||
})
|
||||
}}
|
||||
{{ formatDailyUsageWindow(subscription) }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -256,6 +252,7 @@ import AppLayout from '@/components/layout/AppLayout.vue'
|
||||
import Icon from '@/components/icons/Icon.vue'
|
||||
import { formatDateOnly } from '@/utils/format'
|
||||
import { platformBorderClass, platformBadgeClass, platformButtonClass, platformLabel } from '@/utils/platformColors'
|
||||
import { getRemainingDurationParts, isOneTimeDailyQuota, type RemainingDurationParts } from '@/utils/subscriptionQuota'
|
||||
|
||||
function platformAccentDotClass(p: string): string {
|
||||
switch (p) {
|
||||
@@ -334,30 +331,38 @@ function getExpirationClass(expiresAt: string): string {
|
||||
return 'text-gray-700 dark:text-gray-300'
|
||||
}
|
||||
|
||||
function formatDurationParts(parts: RemainingDurationParts): string {
|
||||
if (parts.days > 0) {
|
||||
return `${parts.days}d ${parts.hours}h`
|
||||
}
|
||||
|
||||
if (parts.hours > 0) {
|
||||
return `${parts.hours}h ${parts.minutes}m`
|
||||
}
|
||||
|
||||
return `${parts.minutes}m`
|
||||
}
|
||||
|
||||
function formatDailyUsageWindow(subscription: UserSubscription): string {
|
||||
if (isOneTimeDailyQuota(subscription) && subscription.expires_at) {
|
||||
const parts = getRemainingDurationParts(subscription.expires_at)
|
||||
if (!parts) return t('userSubscriptions.windowNotActive')
|
||||
return t('userSubscriptions.quotaEndsIn', { time: formatDurationParts(parts) })
|
||||
}
|
||||
|
||||
return t('userSubscriptions.resetIn', {
|
||||
time: formatResetTime(subscription.daily_window_start, 24)
|
||||
})
|
||||
}
|
||||
|
||||
function formatResetTime(windowStart: string | null, windowHours: number): string {
|
||||
if (!windowStart) return t('userSubscriptions.windowNotActive')
|
||||
|
||||
const start = new Date(windowStart)
|
||||
const end = new Date(start.getTime() + windowHours * 60 * 60 * 1000)
|
||||
const now = new Date()
|
||||
const diff = end.getTime() - now.getTime()
|
||||
const parts = getRemainingDurationParts(end)
|
||||
|
||||
if (diff <= 0) return t('userSubscriptions.windowNotActive')
|
||||
|
||||
const hours = Math.floor(diff / (1000 * 60 * 60))
|
||||
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60))
|
||||
|
||||
if (hours > 24) {
|
||||
const days = Math.floor(hours / 24)
|
||||
const remainingHours = hours % 24
|
||||
return `${days}d ${remainingHours}h`
|
||||
}
|
||||
|
||||
if (hours > 0) {
|
||||
return `${hours}h ${minutes}m`
|
||||
}
|
||||
|
||||
return `${minutes}m`
|
||||
return parts ? formatDurationParts(parts) : t('userSubscriptions.windowNotActive')
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
Reference in New Issue
Block a user