fix: harden bulk wallet balance adjustment

This commit is contained in:
RWDai
2026-09-23 16:29:47 +08:00
parent e25e240d16
commit 30bb0c3130
12 changed files with 370 additions and 35 deletions
+4
View File
@@ -183,6 +183,10 @@ export interface UserBatchActionResponse {
success: number
failed: number
failures: UserBatchActionFailure[]
interrupted?: boolean
completed_user_ids?: string[]
uncertain_user_ids?: string[]
unprocessed_user_ids?: string[]
warnings?: UserBatchSelectionWarning[]
action?: string
modified_fields?: string[]
@@ -210,6 +210,11 @@ const targetRoleWarning = computed(() => {
const executeButtonLabel = computed(() => legacyT(`确认${selectedActionLabel.value}(${impactCount.value})`))
const lastResultLabel = computed(() => {
if (!lastResult.value) return ''
if (lastResult.value.interrupted) {
return legacyT(
`批量操作中断:成功 ${lastResult.value.success} 个,结果待确认 ${lastResult.value.uncertain_user_ids?.length ?? 0} 个,尚未执行 ${lastResult.value.unprocessed_user_ids?.length ?? 0} 个`,
)
}
return legacyT(`成功 ${lastResult.value.success} 个,失败 ${lastResult.value.failed} 个`)
})
const lastResultFailuresLabel = computed(() => {
@@ -320,6 +325,11 @@ async function executeBatchAction(): Promise<void> {
try {
const result = await usersStore.batchAction(request)
lastResult.value = result
if (result.interrupted) {
warning(`${lastResultLabel.value};${legacyT('请核对余额后再重试,勿直接重试整批')}`)
emit('completed', result)
return
}
const message = legacyT(`批量操作完成:成功 ${result.success} 个,失败 ${result.failed} 个`)
if (result.failed > 0) {
warning(message)
@@ -7,11 +7,26 @@
<span v-if="failuresLabel">
{{ failuresLabel }}
</span>
<details v-if="result.interrupted" class="mt-2 border-t border-border/60 pt-2">
<summary class="cursor-pointer select-none">{{ legacyT('查看批次中断详情') }}</summary>
<div class="mt-2 max-h-32 space-y-1 overflow-auto break-all">
<p>{{ legacyT('已完成用户 ID') }}:{{ userIds(result.completed_user_ids) }}</p>
<p>{{ legacyT('结果待核对用户 ID') }}:{{ userIds(result.uncertain_user_ids) }}</p>
<p>{{ legacyT('尚未执行用户 ID') }}:{{ userIds(result.unprocessed_user_ids) }}</p>
</div>
</details>
</div>
</template>
<script setup lang="ts">
import type { UserBatchActionResponse } from '@/api/users'
import { useI18n } from '@/i18n'
const { legacyT } = useI18n()
function userIds(ids?: string[]): string {
return ids && ids.length > 0 ? ids.join(', ') : '-'
}
defineProps<{
result: UserBatchActionResponse | null
+11
View File
@@ -1464,6 +1464,16 @@ const legacyExactEnglishMessages: Record<string, string> = {
'扣减超过单个用户可用余额时,该用户余额将归零。': 'Deductions above an individual user’s available balance will be clamped to zero.',
'用户钱包不可用': 'User wallet is unavailable',
'当前为只读模式,无法批量调整用户钱包余额': 'Cannot adjust user wallet balances in read-only mode',
'余额调整结果未确认,批次已中止,请核对钱包后再重试': 'Balance adjustment result is uncertain; the batch stopped. Verify the wallet before retrying.',
'用户钱包更新结果未确认,批次已中止,请核对钱包后再重试': 'User wallet update result is uncertain; the batch stopped. Verify the wallet before retrying.',
'用户更新结果未确认,批次已中止,请核对后再重试': 'User update result is uncertain; the batch stopped. Verify the result before retrying.',
'读取用户状态失败,批次已中止,该用户未执行': 'Could not read user state; the batch stopped before processing this user.',
'因前序错误未执行': 'Not processed because an earlier operation failed',
'请核对余额后再重试,勿直接重试整批': 'Verify balances before retrying; do not retry the entire batch blindly.',
'查看批次中断详情': 'View interrupted batch details',
'已完成用户 ID': 'Completed user IDs',
'结果待核对用户 ID': 'User IDs with uncertain results',
'尚未执行用户 ID': 'Unprocessed user IDs',
'影响用户:': 'Affected users:',
'目标为当前筛选条件匹配的全部用户,执行前后端会重新解析。': 'Targets all users matching the current filters; the backend will resolve the selection again before execution.',
'目标为当前已勾选的用户,重复 ID 会自动去重。': 'Targets the currently selected users; duplicate IDs are deduplicated automatically.',
@@ -3061,6 +3071,7 @@ const legacyDynamicPatterns: Array<[RegExp, (match: RegExpMatchArray) => string]
[/^确认(启用|禁用|删除|重置)((.+))$/u, match => `Confirm ${translateLegacyText(match[1], 'en-US').toLowerCase()} (${match[2]})`],
[/^成功 (.+) 个,失败 (.+) 个$/u, match => `Succeeded ${match[1]}, failed ${match[2]}`],
[/^批量操作完成:成功 (.+) 个,失败 (.+) 个$/u, match => `Batch action complete: succeeded ${match[1]}, failed ${match[2]}`],
[/^批量操作中断:成功 (.+) 个,结果待确认 (.+) 个,尚未执行 (.+) 个$/u, match => `Batch interrupted: succeeded ${match[1]}, uncertain ${match[2]}, not processed ${match[3]}`],
[/^匹配 (.+) 个,当前页 (.+) 个,已选 (.+) 个$/u, match => `Matched ${match[1]} items, current page ${match[2]} items, selected ${match[3]} items`],
[/^已选 (.+) 个$/u, match => `Selected ${match[1]} items`],
[/^已强制下线 (.+) 个设备$/u, match => `Signed out ${match[1]} devices`],