diff --git a/backend/internal/pkg/usagestats/usage_log_types.go b/backend/internal/pkg/usagestats/usage_log_types.go index 8826c048..04414ebb 100644 --- a/backend/internal/pkg/usagestats/usage_log_types.go +++ b/backend/internal/pkg/usagestats/usage_log_types.go @@ -96,6 +96,7 @@ type UserUsageTrendPoint struct { Date string `json:"date"` UserID int64 `json:"user_id"` Email string `json:"email"` + Username string `json:"username"` Requests int64 `json:"requests"` Tokens int64 `json:"tokens"` Cost float64 `json:"cost"` // 标准计费 diff --git a/backend/internal/repository/usage_log_repo.go b/backend/internal/repository/usage_log_repo.go index aab66081..be2207db 100644 --- a/backend/internal/repository/usage_log_repo.go +++ b/backend/internal/repository/usage_log_repo.go @@ -2068,6 +2068,7 @@ func (r *usageLogRepository) GetUserUsageTrend(ctx context.Context, startTime, e TO_CHAR(u.created_at, '%s') as date, u.user_id, COALESCE(us.email, '') as email, + COALESCE(us.username, '') as username, 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.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 WHERE u.user_id IN (SELECT user_id FROM top_users) 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 `, dateFormat) @@ -2096,7 +2097,7 @@ func (r *usageLogRepository) GetUserUsageTrend(ctx context.Context, startTime, e results = make([]UserUsageTrendPoint, 0) for rows.Next() { 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 } results = append(results, row) diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index 5764134d..2181a011 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -1155,6 +1155,7 @@ export interface UserUsageTrendPoint { date: string user_id: number email: string + username: string requests: number tokens: number cost: number // 标准计费 diff --git a/frontend/src/views/admin/DashboardView.vue b/frontend/src/views/admin/DashboardView.vue index 82aa23a5..a1ee5a4d 100644 --- a/frontend/src/views/admin/DashboardView.vue +++ b/frontend/src/views/admin/DashboardView.vue @@ -412,23 +412,29 @@ const lineOptions = computed(() => ({ const userTrendChartData = computed(() => { if (!userTrend.value?.length) return null - // Extract display name from email (part before @) - const getDisplayName = (email: string, userId: number): string => { - if (email && email.includes('@')) { - return email.split('@')[0] + const getDisplayName = (point: UserUsageTrendPoint): string => { + const username = point.username?.trim() + if (username) { + 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 - const userGroups = new Map }>() + // Group by user_id to avoid merging different users with the same display name + const userGroups = new Map }>() const allDates = new Set() userTrend.value.forEach((point) => { allDates.add(point.date) - const key = getDisplayName(point.email, point.user_id) + const key = point.user_id 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) })