Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
陈曦
sub2api
Commits
034b84b7
Unverified
Commit
034b84b7
authored
Mar 08, 2026
by
Wesley Liddick
Committed by
GitHub
Mar 08, 2026
Browse files
Merge pull request #861 from bayma888/feature/usage-user-balance-popup
feat(ui): 使用记录页面点击用户邮箱可查看用户信息和充值记录
parents
1624523c
60c5949a
Changes
5
Hide whitespace changes
Inline
Side-by-side
frontend/src/components/admin/usage/UsageTable.vue
View file @
034b84b7
...
...
@@ -4,7 +4,15 @@
<DataTable
:columns=
"columns"
:data=
"data"
:loading=
"loading"
>
<template
#cell-user
="
{ row }">
<div
class=
"text-sm"
>
<span
class=
"font-medium text-gray-900 dark:text-white"
>
{{
row
.
user
?.
email
||
'
-
'
}}
</span>
<button
v-if=
"row.user?.email"
class=
"font-medium text-primary-600 underline decoration-dashed underline-offset-2 transition-colors hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300"
@
click=
"$emit('userClick', row.user_id, row.user?.email)"
:title=
"t('admin.usage.clickToViewBalance')"
>
{{
row
.
user
.
email
}}
</button>
<span
v-else
class=
"font-medium text-gray-900 dark:text-white"
>
-
</span>
<span
class=
"ml-1 text-gray-500 dark:text-gray-400"
>
#
{{
row
.
user_id
}}
</span>
</div>
</
template
>
...
...
@@ -278,6 +286,7 @@ import Icon from '@/components/icons/Icon.vue'
import
type
{
AdminUsageLog
}
from
'
@/types
'
defineProps
([
'
data
'
,
'
loading
'
,
'
columns
'
])
defineEmits
([
'
userClick
'
])
const
{
t
}
=
useI18n
()
// Tooltip state - cost
...
...
frontend/src/components/admin/user/UserBalanceHistoryModal.vue
View file @
034b84b7
...
...
@@ -54,6 +54,7 @@
/>
<!-- Deposit button - matches menu style -->
<button
v-if=
"!hideActions"
@
click=
"emit('deposit')"
class=
"flex items-center gap-2 rounded-lg border border-gray-200 bg-white px-3 py-2 text-sm text-gray-700 transition-colors hover:bg-gray-50 dark:border-dark-600 dark:bg-dark-800 dark:text-gray-300 dark:hover:bg-dark-700"
>
...
...
@@ -62,6 +63,7 @@
</button>
<!-- Withdraw button - matches menu style -->
<button
v-if=
"!hideActions"
@
click=
"emit('withdraw')"
class=
"flex items-center gap-2 rounded-lg border border-gray-200 bg-white px-3 py-2 text-sm text-gray-700 transition-colors hover:bg-gray-50 dark:border-dark-600 dark:bg-dark-800 dark:text-gray-300 dark:hover:bg-dark-700"
>
...
...
@@ -176,7 +178,7 @@ import BaseDialog from '@/components/common/BaseDialog.vue'
import
Select
from
'
@/components/common/Select.vue
'
import
Icon
from
'
@/components/icons/Icon.vue
'
const
props
=
defineProps
<
{
show
:
boolean
;
user
:
AdminUser
|
null
}
>
()
const
props
=
defineProps
<
{
show
:
boolean
;
user
:
AdminUser
|
null
;
hideActions
?:
boolean
}
>
()
const
emit
=
defineEmits
([
'
close
'
,
'
deposit
'
,
'
withdraw
'
])
const
{
t
}
=
useI18n
()
...
...
frontend/src/i18n/locales/en.ts
View file @
034b84b7
...
...
@@ -2875,6 +2875,8 @@ export default {
billingTypeBalance
:
'
Balance
'
,
billingTypeSubscription
:
'
Subscription
'
,
ipAddress
:
'
IP
'
,
clickToViewBalance
:
'
Click to view balance history
'
,
failedToLoadUser
:
'
Failed to load user info
'
,
cleanup
:
{
button
:
'
Cleanup
'
,
title
:
'
Cleanup Usage Records
'
,
...
...
frontend/src/i18n/locales/zh.ts
View file @
034b84b7
...
...
@@ -3043,6 +3043,8 @@ export default {
billingTypeBalance
:
'
钱包余额
'
,
billingTypeSubscription
:
'
订阅套餐
'
,
ipAddress
:
'
IP
'
,
clickToViewBalance
:
'
点击查看充值记录
'
,
failedToLoadUser
:
'
加载用户信息失败
'
,
cleanup
:
{
button
:
'
清理
'
,
title
:
'
清理使用记录
'
,
...
...
frontend/src/views/admin/UsageView.vue
View file @
034b84b7
...
...
@@ -54,7 +54,7 @@
</div>
</
template
>
</UsageFilters>
<UsageTable
:data=
"usageLogs"
:loading=
"loading"
:columns=
"visibleColumns"
/>
<UsageTable
:data=
"usageLogs"
:loading=
"loading"
:columns=
"visibleColumns"
@
userClick=
"handleUserClick"
/>
<Pagination
v-if=
"pagination.total > 0"
:page=
"pagination.page"
:total=
"pagination.total"
:page-size=
"pagination.page_size"
@
update:page=
"handlePageChange"
@
update:pageSize=
"handlePageSizeChange"
/>
</div>
</AppLayout>
...
...
@@ -66,6 +66,13 @@
:end-date=
"endDate"
@
close=
"cleanupDialogVisible = false"
/>
<!-- Balance history modal triggered from usage table user click -->
<UserBalanceHistoryModal
:show=
"showBalanceHistoryModal"
:user=
"balanceHistoryUser"
:hide-actions=
"true"
@
close=
"showBalanceHistoryModal = false; balanceHistoryUser = null"
/>
</template>
<
script
setup
lang=
"ts"
>
...
...
@@ -79,9 +86,10 @@ import AppLayout from '@/components/layout/AppLayout.vue'; import Pagination fro
import
UsageStatsCards
from
'
@/components/admin/usage/UsageStatsCards.vue
'
;
import
UsageFilters
from
'
@/components/admin/usage/UsageFilters.vue
'
import
UsageTable
from
'
@/components/admin/usage/UsageTable.vue
'
;
import
UsageExportProgress
from
'
@/components/admin/usage/UsageExportProgress.vue
'
import
UsageCleanupDialog
from
'
@/components/admin/usage/UsageCleanupDialog.vue
'
import
UserBalanceHistoryModal
from
'
@/components/admin/user/UserBalanceHistoryModal.vue
'
import
ModelDistributionChart
from
'
@/components/charts/ModelDistributionChart.vue
'
;
import
GroupDistributionChart
from
'
@/components/charts/GroupDistributionChart.vue
'
;
import
TokenUsageTrend
from
'
@/components/charts/TokenUsageTrend.vue
'
import
Icon
from
'
@/components/icons/Icon.vue
'
import
type
{
AdminUsageLog
,
TrendDataPoint
,
ModelStat
,
GroupStat
}
from
'
@/types
'
;
import
type
{
AdminUsageStatsResponse
,
AdminUsageQueryParams
}
from
'
@/api/admin/usage
'
import
type
{
AdminUsageLog
,
TrendDataPoint
,
ModelStat
,
GroupStat
,
AdminUser
}
from
'
@/types
'
;
import
type
{
AdminUsageStatsResponse
,
AdminUsageQueryParams
}
from
'
@/api/admin/usage
'
const
{
t
}
=
useI18n
()
const
appStore
=
useAppStore
()
...
...
@@ -91,6 +99,19 @@ let abortController: AbortController | null = null; let exportAbortController: A
let
chartReqSeq
=
0
const
exportProgress
=
reactive
({
show
:
false
,
progress
:
0
,
current
:
0
,
total
:
0
,
estimatedTime
:
''
})
const
cleanupDialogVisible
=
ref
(
false
)
// Balance history modal state
const
showBalanceHistoryModal
=
ref
(
false
)
const
balanceHistoryUser
=
ref
<
AdminUser
|
null
>
(
null
)
const
handleUserClick
=
async
(
userId
:
number
)
=>
{
try
{
const
user
=
await
adminAPI
.
users
.
getById
(
userId
)
balanceHistoryUser
.
value
=
user
showBalanceHistoryModal
.
value
=
true
}
catch
{
appStore
.
showError
(
t
(
'
admin.usage.failedToLoadUser
'
))
}
}
const
granularityOptions
=
computed
(()
=>
[{
value
:
'
day
'
,
label
:
t
(
'
admin.dashboard.day
'
)
},
{
value
:
'
hour
'
,
label
:
t
(
'
admin.dashboard.hour
'
)
}])
// Use local timezone to avoid UTC timezone issues
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment