merge: 合并远程分支并修复代码冲突

合并了远程分支 cb72262 的功能更新,同时保留了 ESLint 修复:

**冲突解决详情:**

1. AccountTableFilters.vue
   -  保留 emit 模式修复(避免 vue/no-mutating-props 错误)
   -  添加第三个筛选器 type(账户类型)
   -  新增 antigravity 平台和 inactive 状态选项

2. UserBalanceModal.vue
   -  保留 console.error 错误日志
   -  添加输入验证(金额校验、余额不足检查)
   -  使用 appStore.showError 向用户显示友好错误

3. AccountsView.vue
   -  保留所有 console.error 错误日志(避免 no-empty 错误)
   -  使用新 API:clearRateLimit 和 setSchedulable

4. UsageView.vue
   -  添加 console.error 错误日志
   -  添加图表功能(模型分布、使用趋势)
   -  添加粒度选择(按天/按小时)
   -  保留 XLSX 动态导入优化

**测试结果:**
-  Go tests: PASS
-  golangci-lint: 0 issues
-  ESLint: 0 errors
-  TypeScript: PASS

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
yangjianbo
2026-01-06 12:50:51 +08:00
121 changed files with 4244 additions and 3233 deletions

View File

@@ -3,22 +3,18 @@
<TablePageLayout>
<template #filters>
<div class="flex flex-wrap-reverse items-start justify-between gap-3">
<div class="min-w-0 flex-1">
<AccountTableFilters
v-model:searchQuery="params.search"
:filters="params"
@change="reload"
@update:searchQuery="debouncedReload"
/>
</div>
<div class="flex-shrink-0">
<AccountTableActions
:loading="loading"
@refresh="load"
@sync="showSync = true"
@create="showCreate = true"
/>
</div>
<AccountTableFilters
v-model:searchQuery="params.search"
:filters="params"
@change="reload"
@update:searchQuery="debouncedReload"
/>
<AccountTableActions
:loading="loading"
@refresh="load"
@sync="showSync = true"
@create="showCreate = true"
/>
</div>
</template>
<template #table>
@@ -201,10 +197,10 @@ const handleViewStats = (a: Account) => { statsAcc.value = a; showStats.value =
const handleReAuth = (a: Account) => { reAuthAcc.value = a; showReAuth.value = true }
const handleRefresh = async (a: Account) => { try { await adminAPI.accounts.refreshCredentials(a.id); load() } catch (error) { console.error('Failed to refresh credentials:', error) } }
const handleResetStatus = async (a: Account) => { try { await adminAPI.accounts.clearError(a.id); appStore.showSuccess(t('common.success')); load() } catch (error) { console.error('Failed to reset status:', error) } }
const handleClearRateLimit = async (a: Account) => { try { await adminAPI.accounts.clearError(a.id); appStore.showSuccess(t('common.success')); load() } catch (error) { console.error('Failed to clear rate limit:', error) } }
const handleClearRateLimit = async (a: Account) => { try { await adminAPI.accounts.clearRateLimit(a.id); appStore.showSuccess(t('common.success')); load() } catch (error) { console.error('Failed to clear rate limit:', error) } }
const handleDelete = (a: Account) => { deletingAcc.value = a; showDeleteDialog.value = true }
const confirmDelete = async () => { if(!deletingAcc.value) return; try { await adminAPI.accounts.delete(deletingAcc.value.id); showDeleteDialog.value = false; deletingAcc.value = null; reload() } catch (error) { console.error('Failed to delete account:', error) } }
const handleToggleSchedulable = async (a: Account) => { togglingSchedulable.value = a.id; try { await adminAPI.accounts.update(a.id, { schedulable: !a.schedulable }); load() } finally { togglingSchedulable.value = null } }
const handleToggleSchedulable = async (a: Account) => { togglingSchedulable.value = a.id; try { await adminAPI.accounts.setSchedulable(a.id, !a.schedulable); load() } finally { togglingSchedulable.value = null } }
const handleShowTempUnsched = (a: Account) => { tempUnschedAcc.value = a; showTempUnsched.value = true }
const handleTempUnschedReset = async () => { if(!tempUnschedAcc.value) return; try { await adminAPI.accounts.clearError(tempUnschedAcc.value.id); showTempUnsched.value = false; tempUnschedAcc.value = null; load() } catch (error) { console.error('Failed to reset temp unscheduled:', error) } }