Merge pull request #5243 from wucm667/feat/issue-5240-dashboard-username

fix(dashboard): show usernames in spending ranking
This commit is contained in:
Wesley Liddick
2026-08-04 16:15:21 +08:00
committed by GitHub
6 changed files with 40 additions and 22 deletions
@@ -149,6 +149,7 @@ type UserUsageTrendPoint struct {
type UserSpendingRankingItem struct {
UserID int64 `json:"user_id"`
Email string `json:"email"`
Username string `json:"username"`
ActualCost float64 `json:"actual_cost"` // 实际扣除
Requests int64 `json:"requests"`
Tokens int64 `json:"tokens"`
@@ -713,10 +713,10 @@ func TestUsageLogRepositoryGetUserSpendingRanking(t *testing.T) {
start := time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC)
end := start.Add(24 * time.Hour)
rows := sqlmock.NewRows([]string{"user_id", "email", "actual_cost", "requests", "tokens", "total_actual_cost", "total_requests", "total_tokens"}).
AddRow(int64(2), "beta@example.com", 12.5, int64(9), int64(900), 40.0, int64(30), int64(2600)).
AddRow(int64(1), "alpha@example.com", 12.5, int64(8), int64(800), 40.0, int64(30), int64(2600)).
AddRow(int64(3), "gamma@example.com", 4.25, int64(5), int64(300), 40.0, int64(30), int64(2600))
rows := sqlmock.NewRows([]string{"user_id", "email", "username", "actual_cost", "requests", "tokens", "total_actual_cost", "total_requests", "total_tokens"}).
AddRow(int64(2), "beta@example.com", "beta", 12.5, int64(9), int64(900), 40.0, int64(30), int64(2600)).
AddRow(int64(1), "alpha@example.com", "alpha", 12.5, int64(8), int64(800), 40.0, int64(30), int64(2600)).
AddRow(int64(3), "gamma@example.com", "", 4.25, int64(5), int64(300), 40.0, int64(30), int64(2600))
mock.ExpectQuery("WITH user_spend AS \\(").
WithArgs(start, end, 12).
@@ -726,8 +726,8 @@ func TestUsageLogRepositoryGetUserSpendingRanking(t *testing.T) {
require.NoError(t, err)
require.Equal(t, &usagestats.UserSpendingRankingResponse{
Ranking: []usagestats.UserSpendingRankingItem{
{UserID: 2, Email: "beta@example.com", ActualCost: 12.5, Requests: 9, Tokens: 900},
{UserID: 1, Email: "alpha@example.com", ActualCost: 12.5, Requests: 8, Tokens: 800},
{UserID: 2, Email: "beta@example.com", Username: "beta", ActualCost: 12.5, Requests: 9, Tokens: 900},
{UserID: 1, Email: "alpha@example.com", Username: "alpha", ActualCost: 12.5, Requests: 8, Tokens: 800},
{UserID: 3, Email: "gamma@example.com", ActualCost: 4.25, Requests: 5, Tokens: 300},
},
TotalActualCost: 40.0,
@@ -150,18 +150,20 @@ func (r *usageLogRepository) GetUserSpendingRanking(ctx context.Context, startTi
SELECT
u.user_id,
COALESCE(us.email, '') as email,
COALESCE(us.username, '') as username,
COALESCE(SUM(u.actual_cost), 0) as actual_cost,
COUNT(*) as requests,
COALESCE(SUM(u.input_tokens + u.output_tokens + u.cache_creation_tokens + u.cache_read_tokens), 0) as tokens
FROM usage_logs u
LEFT JOIN users us ON u.user_id = us.id
WHERE u.created_at >= $1 AND u.created_at < $2
GROUP BY u.user_id, us.email
GROUP BY u.user_id, us.email, us.username
),
ranked AS (
SELECT
user_id,
email,
username,
actual_cost,
requests,
tokens,
@@ -175,6 +177,7 @@ func (r *usageLogRepository) GetUserSpendingRanking(ctx context.Context, startTi
SELECT
user_id,
email,
username,
actual_cost,
requests,
tokens,
@@ -202,7 +205,7 @@ func (r *usageLogRepository) GetUserSpendingRanking(ctx context.Context, startTi
totalTokens := int64(0)
for rows.Next() {
var row UserSpendingRankingItem
if err = rows.Scan(&row.UserID, &row.Email, &row.ActualCost, &row.Requests, &row.Tokens, &totalActualCost, &totalRequests, &totalTokens); err != nil {
if err = rows.Scan(&row.UserID, &row.Email, &row.Username, &row.ActualCost, &row.Requests, &row.Tokens, &totalActualCost, &totalRequests, &totalTokens); err != nil {
return nil, err
}
ranking = append(ranking, row)