mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-14 12:02:27 +08:00
fix(accounts): readable window labels in Claude reset confirm (review R1-4)
- Map five_hour/seven_day/seven_day_overage_included to 5h/7d/7d overage
(raw key fallback) in the confirm message, credit tooltip and success message.
- Align zh/en confirm copy with the Codex dialog; {count} is the count
remaining after this use.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
dc2efc6b9a
commit
514ad0aa8e
@@ -191,11 +191,21 @@ const creditTitle = computed(() => {
|
||||
if (!credit) return ''
|
||||
const lines = [credit.label]
|
||||
if (credit.expires_at) lines.push(t('admin.accounts.claudeResetCredits.expiresAtFull', { time: formatTime(credit.expires_at, 'full') }))
|
||||
if (credit.clears.length) lines.push(t('admin.accounts.claudeResetCredits.clears', { windows: credit.clears.join(', ') }))
|
||||
if (credit.clears.length) lines.push(t('admin.accounts.claudeResetCredits.clears', { windows: windowLabels(credit.clears) }))
|
||||
if (credit.use_requires_limit) lines.push(t('admin.accounts.claudeResetCredits.requiresLimit'))
|
||||
return lines.join('\n')
|
||||
})
|
||||
|
||||
// 已知窗口显示为可读名称,未知窗口原样显示
|
||||
const windowKeys: Record<string, string> = {
|
||||
five_hour: 'fiveHour',
|
||||
seven_day: 'sevenDay',
|
||||
seven_day_overage_included: 'sevenDayOverage'
|
||||
}
|
||||
function windowLabels(windows?: string[]): string {
|
||||
return (windows ?? []).map(w => windowKeys[w] ? t(`admin.accounts.claudeResetCredits.windows.${windowKeys[w]}`) : w).join(', ')
|
||||
}
|
||||
|
||||
const countButtonTitle = computed(() => {
|
||||
if (!status.value) return t('admin.accounts.claudeResetCredits.countTooltipLoad')
|
||||
return [
|
||||
@@ -215,8 +225,8 @@ const redeemButtonTitle = computed(() => {
|
||||
const confirmMessage = computed(() => {
|
||||
const next = status.value?.credits.find(c => c.redeemable)
|
||||
return t('admin.accounts.claudeResetCredits.confirmMessage', {
|
||||
windows: next?.clears.join(', ') || '—',
|
||||
count: totalResets.value
|
||||
windows: windowLabels(next?.clears) || '—',
|
||||
count: Math.max(totalResets.value - 1, 0)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -242,7 +252,7 @@ function outcomeFeedback(result: ClaudeResetOutcome): { kind: 'success' | 'warni
|
||||
const key = 'admin.accounts.claudeResetCredits.outcome'
|
||||
switch (result.outcome) {
|
||||
case 'reset':
|
||||
return { kind: 'success', text: t(`${key}.reset`, { windows: result.cleared?.join(', ') || '—' }) }
|
||||
return { kind: 'success', text: t(`${key}.reset`, { windows: windowLabels(result.cleared) || '—' }) }
|
||||
case 'already_used':
|
||||
return { kind: 'warning', text: t(`${key}.alreadyUsed`) }
|
||||
case 'cooldown':
|
||||
|
||||
@@ -5,7 +5,8 @@ import type { Account } from '@/types'
|
||||
const getCredits = vi.hoisted(() => vi.fn())
|
||||
const redeem = vi.hoisted(() => vi.fn())
|
||||
vi.mock('@/api/admin/claudeResetCredits', () => ({ getClaudeResetCredits: getCredits, redeemClaudeResetCredit: redeem }))
|
||||
vi.mock('vue-i18n', () => ({ useI18n: () => ({ t: (key: string) => key }) }))
|
||||
const t = vi.hoisted(() => vi.fn((key: string, _params?: Record<string, unknown>) => key))
|
||||
vi.mock('vue-i18n', () => ({ useI18n: () => ({ t }) }))
|
||||
// Minimal stand-in exposing the dialog's show state and confirm/cancel events.
|
||||
vi.mock('@/components/common/ConfirmDialog.vue', () => ({
|
||||
default: {
|
||||
@@ -104,6 +105,11 @@ describe('Claude reset credit status', () => {
|
||||
const dialog = wrapper.get('[data-testid="confirm-dialog"]')
|
||||
expect(dialog.attributes('data-danger')).toBe('true')
|
||||
expect(dialog.text()).toContain('admin.accounts.claudeResetCredits.confirmMessage')
|
||||
// Known windows render as readable labels; count is what remains after this use.
|
||||
expect(t).toHaveBeenCalledWith('admin.accounts.claudeResetCredits.confirmMessage', {
|
||||
windows: 'admin.accounts.claudeResetCredits.windows.fiveHour, admin.accounts.claudeResetCredits.windows.sevenDay',
|
||||
count: 0
|
||||
})
|
||||
await wrapper.get('[data-testid="confirm-cancel"]').trigger('click')
|
||||
await flushPromises()
|
||||
expect(wrapper.find('[data-testid="confirm-dialog"]').exists()).toBe(false)
|
||||
@@ -193,6 +199,15 @@ describe('Claude reset credit status', () => {
|
||||
expect(redeem.mock.calls[1][1]).toBe(redeem.mock.calls[0][1])
|
||||
})
|
||||
|
||||
it('labels cleared windows and falls back to the raw key for unknown ones', async () => {
|
||||
const wrapper = await queried()
|
||||
redeem.mockResolvedValue({ outcome: 'reset', cleared: ['seven_day_overage_included', 'future_window'], replayed: false })
|
||||
await confirmReset(wrapper)
|
||||
expect(t).toHaveBeenCalledWith('admin.accounts.claudeResetCredits.outcome.reset', {
|
||||
windows: 'admin.accounts.claudeResetCredits.windows.sevenDayOverage, future_window'
|
||||
})
|
||||
})
|
||||
|
||||
it('tells the operator to retry later after an explicit unavailable answer', async () => {
|
||||
const wrapper = await queried()
|
||||
redeem.mockResolvedValue({ outcome: 'unknown', reason: 'upstream_unavailable', replayed: false })
|
||||
|
||||
@@ -943,8 +943,13 @@ export default {
|
||||
resetTooltipNeedQuery: 'Check the count first; reset is available once a usable credit is found',
|
||||
resetTooltipNone: 'No reset can be used right now',
|
||||
resetTooltipReady: 'Consume 1 reset to clear limit windows (asks for confirmation)',
|
||||
confirmTitle: 'Use a Claude reset',
|
||||
confirmMessage: 'This immediately consumes 1 reset and cannot be undone. Windows cleared: {windows}. Resets held: {count}. Continue?',
|
||||
confirmTitle: 'Confirm Claude Reset',
|
||||
confirmMessage: 'This will consume 1 reset credit to immediately restore the {windows} window(s) ({count} remaining). This action cannot be undone. Continue?',
|
||||
windows: {
|
||||
fiveHour: '5h',
|
||||
sevenDay: '7d',
|
||||
sevenDayOverage: '7d overage'
|
||||
},
|
||||
outcome: {
|
||||
reset: 'Reset applied; cleared: {windows}',
|
||||
alreadyUsed: 'This reset was already used; refreshing to confirm',
|
||||
|
||||
@@ -1044,8 +1044,13 @@ export default {
|
||||
resetTooltipNeedQuery: '请先点「次数」查询;查询到可用的重置后才能使用',
|
||||
resetTooltipNone: '当前没有可立即使用的重置',
|
||||
resetTooltipReady: '消耗 1 次重置,清除限额窗口(需确认)',
|
||||
confirmTitle: '使用 Claude 重置',
|
||||
confirmMessage: '将立即消耗 1 次重置,此操作不可撤销。将清除窗口:{windows}。当前持有 {count} 次。确定继续?',
|
||||
confirmTitle: '确认使用 Claude 重置',
|
||||
confirmMessage: '将消耗 1 次重置次数,立即恢复 {windows} 窗口,剩余 {count} 次。此操作不可撤销,确定继续吗?',
|
||||
windows: {
|
||||
fiveHour: '5h',
|
||||
sevenDay: '7d',
|
||||
sevenDayOverage: '7d 超额'
|
||||
},
|
||||
outcome: {
|
||||
reset: '重置成功,已清除:{windows}',
|
||||
alreadyUsed: '该重置已被使用,正在刷新确认',
|
||||
|
||||
Reference in New Issue
Block a user