mirror of
https://gitee.com/wanwujie/sub2api
synced 2026-04-03 06:52:13 +08:00
Merge pull request #951 from wanXcode/fix/dashboard-user-trend-label
fix(dashboard): prefer username over email prefix in recent usage chart
This commit is contained in:
@@ -96,6 +96,7 @@ type UserUsageTrendPoint struct {
|
|||||||
Date string `json:"date"`
|
Date string `json:"date"`
|
||||||
UserID int64 `json:"user_id"`
|
UserID int64 `json:"user_id"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
|
Username string `json:"username"`
|
||||||
Requests int64 `json:"requests"`
|
Requests int64 `json:"requests"`
|
||||||
Tokens int64 `json:"tokens"`
|
Tokens int64 `json:"tokens"`
|
||||||
Cost float64 `json:"cost"` // 标准计费
|
Cost float64 `json:"cost"` // 标准计费
|
||||||
|
|||||||
@@ -2068,6 +2068,7 @@ func (r *usageLogRepository) GetUserUsageTrend(ctx context.Context, startTime, e
|
|||||||
TO_CHAR(u.created_at, '%s') as date,
|
TO_CHAR(u.created_at, '%s') as date,
|
||||||
u.user_id,
|
u.user_id,
|
||||||
COALESCE(us.email, '') as email,
|
COALESCE(us.email, '') as email,
|
||||||
|
COALESCE(us.username, '') as username,
|
||||||
COUNT(*) as requests,
|
COUNT(*) as requests,
|
||||||
COALESCE(SUM(u.input_tokens + u.output_tokens + u.cache_creation_tokens + u.cache_read_tokens), 0) as tokens,
|
COALESCE(SUM(u.input_tokens + u.output_tokens + u.cache_creation_tokens + u.cache_read_tokens), 0) as tokens,
|
||||||
COALESCE(SUM(u.total_cost), 0) as cost,
|
COALESCE(SUM(u.total_cost), 0) as cost,
|
||||||
@@ -2076,7 +2077,7 @@ func (r *usageLogRepository) GetUserUsageTrend(ctx context.Context, startTime, e
|
|||||||
LEFT JOIN users us ON u.user_id = us.id
|
LEFT JOIN users us ON u.user_id = us.id
|
||||||
WHERE u.user_id IN (SELECT user_id FROM top_users)
|
WHERE u.user_id IN (SELECT user_id FROM top_users)
|
||||||
AND u.created_at >= $4 AND u.created_at < $5
|
AND u.created_at >= $4 AND u.created_at < $5
|
||||||
GROUP BY date, u.user_id, us.email
|
GROUP BY date, u.user_id, us.email, us.username
|
||||||
ORDER BY date ASC, tokens DESC
|
ORDER BY date ASC, tokens DESC
|
||||||
`, dateFormat)
|
`, dateFormat)
|
||||||
|
|
||||||
@@ -2096,7 +2097,7 @@ func (r *usageLogRepository) GetUserUsageTrend(ctx context.Context, startTime, e
|
|||||||
results = make([]UserUsageTrendPoint, 0)
|
results = make([]UserUsageTrendPoint, 0)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var row UserUsageTrendPoint
|
var row UserUsageTrendPoint
|
||||||
if err = rows.Scan(&row.Date, &row.UserID, &row.Email, &row.Requests, &row.Tokens, &row.Cost, &row.ActualCost); err != nil {
|
if err = rows.Scan(&row.Date, &row.UserID, &row.Email, &row.Username, &row.Requests, &row.Tokens, &row.Cost, &row.ActualCost); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
results = append(results, row)
|
results = append(results, row)
|
||||||
|
|||||||
@@ -1155,6 +1155,7 @@ export interface UserUsageTrendPoint {
|
|||||||
date: string
|
date: string
|
||||||
user_id: number
|
user_id: number
|
||||||
email: string
|
email: string
|
||||||
|
username: string
|
||||||
requests: number
|
requests: number
|
||||||
tokens: number
|
tokens: number
|
||||||
cost: number // 标准计费
|
cost: number // 标准计费
|
||||||
|
|||||||
@@ -412,23 +412,29 @@ const lineOptions = computed(() => ({
|
|||||||
const userTrendChartData = computed(() => {
|
const userTrendChartData = computed(() => {
|
||||||
if (!userTrend.value?.length) return null
|
if (!userTrend.value?.length) return null
|
||||||
|
|
||||||
// Extract display name from email (part before @)
|
const getDisplayName = (point: UserUsageTrendPoint): string => {
|
||||||
const getDisplayName = (email: string, userId: number): string => {
|
const username = point.username?.trim()
|
||||||
if (email && email.includes('@')) {
|
if (username) {
|
||||||
return email.split('@')[0]
|
return username
|
||||||
}
|
}
|
||||||
return t('admin.redeem.userPrefix', { id: userId })
|
|
||||||
|
const email = point.email?.trim()
|
||||||
|
if (email) {
|
||||||
|
return email
|
||||||
|
}
|
||||||
|
|
||||||
|
return t('admin.redeem.userPrefix', { id: point.user_id })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Group by user
|
// Group by user_id to avoid merging different users with the same display name
|
||||||
const userGroups = new Map<string, { name: string; data: Map<string, number> }>()
|
const userGroups = new Map<number, { name: string; data: Map<string, number> }>()
|
||||||
const allDates = new Set<string>()
|
const allDates = new Set<string>()
|
||||||
|
|
||||||
userTrend.value.forEach((point) => {
|
userTrend.value.forEach((point) => {
|
||||||
allDates.add(point.date)
|
allDates.add(point.date)
|
||||||
const key = getDisplayName(point.email, point.user_id)
|
const key = point.user_id
|
||||||
if (!userGroups.has(key)) {
|
if (!userGroups.has(key)) {
|
||||||
userGroups.set(key, { name: key, data: new Map() })
|
userGroups.set(key, { name: getDisplayName(point), data: new Map() })
|
||||||
}
|
}
|
||||||
userGroups.get(key)!.data.set(point.date, point.tokens)
|
userGroups.get(key)!.data.set(point.date, point.tokens)
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user