feat: show channel name in admin usage logs
This commit is contained in:
@@ -90,8 +90,11 @@ func (h *Handler) AdminUsage(c *gin.Context) {
|
|||||||
for _, l := range logs {
|
for _, l := range logs {
|
||||||
var uname string
|
var uname string
|
||||||
h.a.DB.Model(&store.User{}).Where("id = ?", l.UserID).Pluck("username", &uname)
|
h.a.DB.Model(&store.User{}).Where("id = ?", l.UserID).Pluck("username", &uname)
|
||||||
|
var chName string
|
||||||
|
h.a.DB.Model(&store.Channel{}).Where("id = ?", l.ChannelID).Pluck("name", &chName)
|
||||||
out = append(out, gin.H{
|
out = append(out, gin.H{
|
||||||
"id": l.ID, "user": uname, "user_id": l.UserID, "model": l.ModelName, "protocol": l.Protocol,
|
"id": l.ID, "user": uname, "user_id": l.UserID, "model": l.ModelName, "protocol": l.Protocol,
|
||||||
|
"channel_id": l.ChannelID, "channel": chName,
|
||||||
"input_tokens": l.InputTokens, "output_tokens": l.OutputTokens,
|
"input_tokens": l.InputTokens, "output_tokens": l.OutputTokens,
|
||||||
"cache_read_tokens": l.CacheReadTokens, "cost": l.Cost,
|
"cache_read_tokens": l.CacheReadTokens, "cost": l.Cost,
|
||||||
"latency_ms": l.LatencyMS, "status": l.Status, "error_code": l.ErrorCode,
|
"latency_ms": l.LatencyMS, "status": l.Status, "error_code": l.ErrorCode,
|
||||||
|
|||||||
@@ -82,6 +82,8 @@ export interface UsageLog {
|
|||||||
request_id: string
|
request_id: string
|
||||||
model: string
|
model: string
|
||||||
protocol: string
|
protocol: string
|
||||||
|
channel_id?: number
|
||||||
|
channel?: string
|
||||||
input_tokens: number
|
input_tokens: number
|
||||||
output_tokens: number
|
output_tokens: number
|
||||||
cache_read_tokens: number
|
cache_read_tokens: number
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ onMounted(load)
|
|||||||
<div class="flex items-start justify-between gap-2">
|
<div class="flex items-start justify-between gap-2">
|
||||||
<div class="min-w-0">
|
<div class="min-w-0">
|
||||||
<p class="truncate font-mono text-sm text-ink">{{ l.model }}</p>
|
<p class="truncate font-mono text-sm text-ink">{{ l.model }}</p>
|
||||||
<p class="mt-0.5 truncate text-xs text-muted">{{ l.user }}</p>
|
<p class="mt-0.5 truncate text-xs text-muted">{{ l.channel }} · {{ l.user }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex shrink-0 flex-col items-end gap-1">
|
<div class="flex shrink-0 flex-col items-end gap-1">
|
||||||
<Badge :variant="l.status === 'success' ? 'ok' : l.status === 'canceled' ? 'neutral' : 'err'">{{ l.status }}</Badge>
|
<Badge :variant="l.status === 'success' ? 'ok' : l.status === 'canceled' ? 'neutral' : 'err'">{{ l.status }}</Badge>
|
||||||
@@ -165,6 +165,7 @@ onMounted(load)
|
|||||||
<tr class="border-b border-edge text-left text-xs text-muted">
|
<tr class="border-b border-edge text-left text-xs text-muted">
|
||||||
<th scope="col" class="px-4 py-2.5 font-medium">用户</th>
|
<th scope="col" class="px-4 py-2.5 font-medium">用户</th>
|
||||||
<th scope="col" class="px-4 py-2.5 font-medium">模型</th>
|
<th scope="col" class="px-4 py-2.5 font-medium">模型</th>
|
||||||
|
<th scope="col" class="px-4 py-2.5 font-medium">渠道</th>
|
||||||
<th scope="col" class="px-4 py-2.5 font-medium">API 格式</th>
|
<th scope="col" class="px-4 py-2.5 font-medium">API 格式</th>
|
||||||
<th scope="col" class="px-4 py-2.5 font-medium">Token 入/出</th>
|
<th scope="col" class="px-4 py-2.5 font-medium">Token 入/出</th>
|
||||||
<th scope="col" class="px-4 py-2.5 font-medium">成本</th>
|
<th scope="col" class="px-4 py-2.5 font-medium">成本</th>
|
||||||
@@ -178,6 +179,7 @@ onMounted(load)
|
|||||||
<tr v-for="l in logs" :key="l.id" class="table-row">
|
<tr v-for="l in logs" :key="l.id" class="table-row">
|
||||||
<td class="px-4 py-2.5 text-xs text-ink">{{ l.user }}</td>
|
<td class="px-4 py-2.5 text-xs text-ink">{{ l.user }}</td>
|
||||||
<td class="px-4 py-2.5 font-mono text-xs text-ink">{{ l.model }}</td>
|
<td class="px-4 py-2.5 font-mono text-xs text-ink">{{ l.model }}</td>
|
||||||
|
<td class="px-4 py-2.5 font-mono text-xs text-muted">{{ l.channel || '-' }}</td>
|
||||||
<td class="px-4 py-2.5 font-mono text-xs text-muted">{{ protocolShort(l.protocol) }}</td>
|
<td class="px-4 py-2.5 font-mono text-xs text-muted">{{ protocolShort(l.protocol) }}</td>
|
||||||
<td class="px-4 py-2.5 mono-num text-xs text-muted">{{ l.input_tokens }}/{{ l.output_tokens }}</td>
|
<td class="px-4 py-2.5 mono-num text-xs text-muted">{{ l.input_tokens }}/{{ l.output_tokens }}</td>
|
||||||
<td class="px-4 py-2.5 mono-num text-xs text-ink">{{ fmtCost(l.cost) }}</td>
|
<td class="px-4 py-2.5 mono-num text-xs text-ink">{{ fmtCost(l.cost) }}</td>
|
||||||
@@ -192,7 +194,7 @@ onMounted(load)
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-if="logs.length === 0">
|
<tr v-if="logs.length === 0">
|
||||||
<td colspan="9" class="px-4 py-10 text-center text-sm text-muted">暂无请求记录</td>
|
<td colspan="10" class="px-4 py-10 text-center text-sm text-muted">暂无请求记录</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -212,6 +214,8 @@ onMounted(load)
|
|||||||
<div class="text-xs text-muted">
|
<div class="text-xs text-muted">
|
||||||
<span class="font-mono text-ink">{{ viewing.model }}</span>
|
<span class="font-mono text-ink">{{ viewing.model }}</span>
|
||||||
<span class="mx-1.5">·</span>
|
<span class="mx-1.5">·</span>
|
||||||
|
<span class="font-mono">{{ viewing.channel || '-' }}</span>
|
||||||
|
<span class="mx-1.5">·</span>
|
||||||
<span class="font-mono">{{ viewing.user || '-' }}</span>
|
<span class="font-mono">{{ viewing.user || '-' }}</span>
|
||||||
<span class="mx-1.5">·</span>
|
<span class="mx-1.5">·</span>
|
||||||
<span class="mono-num">{{ fmtTime(viewing.created_at) }}</span>
|
<span class="mono-num">{{ fmtTime(viewing.created_at) }}</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user