Files
claude-relay-service/web/admin-spa/dist/assets/DashboardView-Bs_KlSzv.js
2025-08-06 02:30:41 +00:00

2 lines
32 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import{E as Ct}from"./element-plus-B8Fs_0jW.js";import{aR as wt,r as T,c as kt,aW as _t,o as mt,q as St,D as ot,V as Rt,x as S,z as t,P as y,u as n,O as R,L as H,Q as bt,ac as Dt,C as G,R as $t,K as At,al as It,y as $}from"./vue-vendor-CKToUHZx.js";import{a as J,_ as Ut}from"./index-D-2UnWMj.js";import{s as xt}from"./toast-BvwA7Mwb.js";import{C as vt}from"./chart-Cor9iTVD.js";import"./vendor-BDiMbLwQ.js";const Mt=wt("dashboard",()=>{const nt=T(!1),V=T({totalApiKeys:0,activeApiKeys:0,totalAccounts:0,activeAccounts:0,rateLimitedAccounts:0,todayRequests:0,totalRequests:0,todayTokens:0,todayInputTokens:0,todayOutputTokens:0,totalTokens:0,totalInputTokens:0,totalOutputTokens:0,totalCacheCreateTokens:0,totalCacheReadTokens:0,todayCacheCreateTokens:0,todayCacheReadTokens:0,systemRPM:0,systemTPM:0,realtimeRPM:0,realtimeTPM:0,metricsWindow:5,isHistoricalMetrics:!1,systemStatus:"正常",uptime:0,systemTimezone:8}),p=T({todayCosts:{totalCost:0,formatted:{totalCost:"$0.000000"}},totalCosts:{totalCost:0,formatted:{totalCost:"$0.000000"}}}),lt=T([]),q=T([]),X=T([]),I=T({data:[],topApiKeys:[],totalApiKeys:0}),o=T({type:"preset",preset:"7days",customStart:"",customEnd:"",customRange:null,presetOptions:[{value:"today",label:"今日",days:1},{value:"7days",label:"7天",days:7},{value:"30days",label:"30天",days:30}]}),C=T("day"),E=T("requests"),O=T([new Date(2e3,1,1,0,0,0),new Date(2e3,2,1,23,59,59)]),pt=kt(()=>{const i=V.value.uptime,l=Math.floor(i/86400),r=Math.floor(i%86400/3600),u=Math.floor(i%3600/60);return l>0?`${l}${r}小时`:r>0?`${r}小时 ${u}分钟`:`${u}分钟`});function D(i,l=!0){const r=i.getFullYear(),u=i.getMonth(),a=i.getDate();return l?new Date(Date.UTC(r,u,a-1,16,0,0,0)):new Date(Date.UTC(r,u,a,15,59,59,999))}async function yt(i=null){nt.value=!0;try{let l={today:"today",all:"all"};i&&(l={today:{today:"today",all:"today"},"7days":{today:"7days",all:"7days"},monthly:{today:"monthly",all:"monthly"},all:{today:"today",all:"all"}}[i]||l);const[r,u,a]=await Promise.all([J.get("/admin/dashboard"),J.get(`/admin/usage-costs?period=${l.today}`),J.get(`/admin/usage-costs?period=${l.all}`)]);if(r.success){const s=r.data.overview||{},d=r.data.recentActivity||{},m=r.data.systemAverages||{},c=r.data.realtimeMetrics||{},k=r.data.systemHealth||{};V.value={totalApiKeys:s.totalApiKeys||0,activeApiKeys:s.activeApiKeys||0,totalAccounts:s.totalClaudeAccounts||0,activeAccounts:s.activeClaudeAccounts||0,rateLimitedAccounts:s.rateLimitedClaudeAccounts||0,todayRequests:d.requestsToday||0,totalRequests:s.totalRequestsUsed||0,todayTokens:d.tokensToday||0,todayInputTokens:d.inputTokensToday||0,todayOutputTokens:d.outputTokensToday||0,totalTokens:s.totalTokensUsed||0,totalInputTokens:s.totalInputTokensUsed||0,totalOutputTokens:s.totalOutputTokensUsed||0,totalCacheCreateTokens:s.totalCacheCreateTokensUsed||0,totalCacheReadTokens:s.totalCacheReadTokensUsed||0,todayCacheCreateTokens:d.cacheCreateTokensToday||0,todayCacheReadTokens:d.cacheReadTokensToday||0,systemRPM:m.rpm||0,systemTPM:m.tpm||0,realtimeRPM:c.rpm||0,realtimeTPM:c.tpm||0,metricsWindow:c.windowMinutes||5,isHistoricalMetrics:c.isHistorical||!1,systemStatus:k.redisConnected?"正常":"异常",uptime:k.uptime||0,systemTimezone:r.data.systemTimezone||8}}u.success&&a.success&&(p.value={todayCosts:u.data.totalCosts||{totalCost:0,formatted:{totalCost:"$0.000000"}},totalCosts:a.data.totalCosts||{totalCost:0,formatted:{totalCost:"$0.000000"}}})}catch(l){console.error("加载仪表板数据失败:",l)}finally{nt.value=!1}}async function rt(i=7,l="day"){try{let r="/admin/usage-trend?";if(l==="hour")if(r+="granularity=hour",o.value.customRange&&o.value.customRange.length===2){const a=s=>{const[m,c]=s.split(" "),[k,K,P]=m.split("-").map(Number),[U,F,B]=c.split(":").map(Number);return new Date(Date.UTC(k,K-1,P,U-8,F,B)).toISOString()};r+=`&startDate=${encodeURIComponent(a(o.value.customRange[0]))}`,r+=`&endDate=${encodeURIComponent(a(o.value.customRange[1]))}`}else{const a=new Date;let s,d;if(o.value.type==="preset")switch(o.value.preset){case"last24h":d=new Date(a),s=new Date(a.getTime()-24*60*60*1e3);break;case"yesterday":const m=new Date;m.setDate(m.getDate()-1),s=D(m,!0),d=D(m,!1);break;case"dayBefore":const c=new Date;c.setDate(c.getDate()-2),s=D(c,!0),d=D(c,!1);break;default:s=new Date(a.getTime()-24*60*60*1e3),d=a}else s=new Date(a.getTime()-i*24*60*60*1e3),d=a;r+=`&startDate=${encodeURIComponent(s.toISOString())}`,r+=`&endDate=${encodeURIComponent(d.toISOString())}`}else r+=`granularity=day&days=${i}`;const u=await J.get(r);u.success&&(q.value=u.data)}catch(r){console.error("加载使用趋势失败:",r)}}async function it(i="daily"){try{let l=`/admin/model-stats?period=${i}`;if(o.value.type==="custom"||C.value==="hour"){if(o.value.customRange&&o.value.customRange.length===2){const u=a=>{const[d,m]=a.split(" "),[c,k,K]=d.split("-").map(Number),[P,U,F]=m.split(":").map(Number);return new Date(Date.UTC(c,k-1,K,P-8,U,F)).toISOString()};l+=`&startDate=${encodeURIComponent(u(o.value.customRange[0]))}`,l+=`&endDate=${encodeURIComponent(u(o.value.customRange[1]))}`}else if(C.value==="hour"&&o.value.type==="preset"){const u=new Date;let a,s;switch(o.value.preset){case"last24h":s=new Date(u),a=new Date(u.getTime()-24*60*60*1e3);break;case"yesterday":const d=new Date;d.setDate(d.getDate()-1),a=D(d,!0),s=D(d,!1);break;case"dayBefore":const m=new Date;m.setDate(m.getDate()-2),a=D(m,!0),s=D(m,!1);break;default:a=new Date(u.getTime()-24*60*60*1e3),s=u}l+=`&startDate=${encodeURIComponent(a.toISOString())}`,l+=`&endDate=${encodeURIComponent(s.toISOString())}`}}else if(o.value.type==="preset"&&C.value==="day"){const u=new Date;let a,s;const d=o.value.presetOptions.find(m=>m.value===o.value.preset);if(d){if(o.value.preset==="today")a=D(u,!0),s=D(u,!1);else{const m=new Date;m.setDate(m.getDate()-(d.days-1)),a=D(m,!0),s=D(u,!1)}l+=`&startDate=${encodeURIComponent(a.toISOString())}`,l+=`&endDate=${encodeURIComponent(s.toISOString())}`}}const r=await J.get(l);r.success&&(X.value=r.data)}catch(l){console.error("加载模型统计失败:",l)}}async function tt(i="requests"){try{let l="/admin/api-keys-usage-trend?",r=7;if(C.value==="hour")if(l+="granularity=hour",o.value.customRange&&o.value.customRange.length===2){const a=s=>{const[m,c]=s.split(" "),[k,K,P]=m.split("-").map(Number),[U,F,B]=c.split(":").map(Number);return new Date(Date.UTC(k,K-1,P,U-8,F,B)).toISOString()};l+=`&startDate=${encodeURIComponent(a(o.value.customRange[0]))}`,l+=`&endDate=${encodeURIComponent(a(o.value.customRange[1]))}`}else{const a=new Date;let s,d;if(o.value.type==="preset")switch(o.value.preset){case"last24h":d=new Date(a),s=new Date(a.getTime()-24*60*60*1e3);break;case"yesterday":const m=new Date;m.setDate(m.getDate()-1),s=D(m,!0),d=D(m,!1);break;case"dayBefore":const c=new Date;c.setDate(c.getDate()-2),s=D(c,!0),d=D(c,!1);break;default:s=new Date(a.getTime()-24*60*60*1e3),d=a}else s=new Date(a.getTime()-24*60*60*1e3),d=a;l+=`&startDate=${encodeURIComponent(s.toISOString())}`,l+=`&endDate=${encodeURIComponent(d.toISOString())}`}else r=o.value.type==="preset"?o.value.preset==="today"?1:o.value.preset==="7days"?7:30:Q(o.value.customStart,o.value.customEnd),l+=`granularity=day&days=${r}`;l+=`&metric=${i}`;const u=await J.get(l);u.success&&(I.value={data:u.data||[],topApiKeys:u.topApiKeys||[],totalApiKeys:u.totalApiKeys||0})}catch(l){console.error("加载API Keys趋势失败:",l)}}function j(i){o.value.type="preset",o.value.preset=i;const l=o.value.presetOptions.find(r=>r.value===i);if(l){const r=new Date;let u,a;if(C.value==="hour")switch(i){case"last24h":a=new Date(r),u=new Date(r.getTime()-24*60*60*1e3);break;case"yesterday":const s=new Date;s.setDate(s.getDate()-1),u=D(s,!0),a=D(s,!1);break;case"dayBefore":const d=new Date;d.setDate(d.getDate()-2),u=D(d,!0),a=D(d,!1);break}else u=new Date(r),a=new Date(r),i==="today"?(u.setHours(0,0,0,0),a.setHours(23,59,59,999)):(u.setDate(r.getDate()-(l.days-1)),u.setHours(0,0,0,0),a.setHours(23,59,59,999));if(o.value.customStart=u.toISOString().split("T")[0],o.value.customEnd=a.toISOString().split("T")[0],C.value==="hour"&&(i==="yesterday"||i==="dayBefore")){const s=new Date;i==="yesterday"?s.setDate(s.getDate()-1):s.setDate(s.getDate()-2);const d=s.getFullYear(),m=String(s.getMonth()+1).padStart(2,"0"),c=String(s.getDate()).padStart(2,"0");o.value.customRange=[`${d}-${m}-${c} 00:00:00`,`${d}-${m}-${c} 23:59:59`]}else{const s=d=>{const k=new Date(d.getTime()+288e5),K=k.getUTCFullYear(),P=String(k.getUTCMonth()+1).padStart(2,"0"),U=String(k.getUTCDate()).padStart(2,"0"),F=String(k.getUTCHours()).padStart(2,"0"),B=String(k.getUTCMinutes()).padStart(2,"0"),Z=String(k.getUTCSeconds()).padStart(2,"0");return`${K}-${P}-${U} ${F}:${B}:${Z}`};o.value.customRange=[s(u),s(a)]}}N()}function ft(i){if(i&&i.length===2){o.value.type="custom",o.value.preset="",o.value.customRange=i,o.value.customStart=i[0].split(" ")[0],o.value.customEnd=i[1].split(" ")[0],V.value.systemTimezone;const l=a=>{const[s,d]=a.split(" "),[m,c,k]=s.split("-").map(Number),[K,P,U]=d.split(":").map(Number);return new Date(m,c-1,k,K,P,U)},r=l(i[0]),u=l(i[1]);if(C.value==="hour"){if((u-r)/36e5>24){xt("小时粒度下日期范围不能超过24小时","warning");return}}else if(Math.ceil((u-r)/864e5)+1>31){xt("日期范围不能超过 31 天","warning");return}N()}else i===null&&j(C.value==="hour"?"last24h":"7days")}function et(i){if(C.value=i,i==="hour"){if(o.value.presetOptions=[{value:"last24h",label:"近24小时",hours:24},{value:"yesterday",label:"昨天",hours:24},{value:"dayBefore",label:"前天",hours:24}],o.value.type==="custom"&&o.value.customRange&&o.value.customRange.length===2){const l=new Date(o.value.customRange[0]);if((new Date(o.value.customRange[1])-l)/(1e3*60*60)>24){xt("小时粒度下日期范围不能超过24小时已切换到近24小时","warning"),j("last24h");return}}if(["today","7days","30days"].includes(o.value.preset)){j("last24h");return}}else if(o.value.presetOptions=[{value:"today",label:"今日",days:1},{value:"7days",label:"7天",days:7},{value:"30days",label:"30天",days:30}],["last24h","yesterday","dayBefore"].includes(o.value.preset)){j("7days");return}N()}async function N(){let i,l="monthly";if(o.value.type==="preset"){const r=o.value.presetOptions.find(u=>u.value===o.value.preset);C.value==="hour"?(i=1,l="daily"):(i=r?r.days:7,o.value.preset==="today"?l="daily":l="monthly")}else{if(C.value==="hour"){const r=new Date(o.value.customRange[0]),u=new Date(o.value.customRange[1]),a=Math.ceil((u-r)/(1e3*60*60));i=Math.ceil(a/24)||1}else i=Q(o.value.customStart,o.value.customEnd);l="daily"}await Promise.all([rt(i,C.value),it(l),tt(E.value)])}function Q(i,l){if(!i||!l)return 7;const r=new Date(i),u=new Date(l),a=Math.abs(u-r);return Math.ceil(a/(1e3*60*60*24))||7}function Y(i){return i>new Date}return{loading:nt,dashboardData:V,costsData:p,modelStats:lt,trendData:q,dashboardModelStats:X,apiKeysTrendData:I,dateFilter:o,trendGranularity:C,apiKeysTrendMetric:E,defaultTime:O,formattedUptime:pt,loadDashboardData:yt,loadUsageTrend:rt,loadModelStats:it,loadApiKeysTrend:tt,setDateFilterPreset:j,onCustomDateRangeChange:ft,setTrendGranularity:et,refreshChartsData:N,disabledDate:Y}}),Kt={class:"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3 sm:gap-4 md:gap-6 mb-4 sm:mb-6 md:mb-8"},Pt={class:"stat-card"},Ot={class:"flex items-center justify-between"},Ft={class:"text-2xl sm:text-3xl font-bold text-gray-900"},Bt={class:"text-xs text-gray-500 mt-1"},zt={class:"stat-card"},Ht={class:"flex items-center justify-between"},qt={class:"text-2xl sm:text-3xl font-bold text-gray-900"},Et={class:"text-xs text-gray-500 mt-1"},Nt={key:0,class:"text-yellow-600"},Lt={class:"stat-card"},Vt={class:"flex items-center justify-between"},jt={class:"text-2xl sm:text-3xl font-bold text-gray-900"},Yt={class:"text-xs text-gray-500 mt-1"},Wt={class:"stat-card"},Gt={class:"flex items-center justify-between"},Qt={class:"text-2xl sm:text-3xl font-bold text-green-600"},Zt={class:"text-xs text-gray-500 mt-1"},Jt={class:"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3 sm:gap-4 md:gap-6 mb-4 sm:mb-6 md:mb-8"},Xt={class:"stat-card"},te={class:"flex items-center justify-between"},ee={class:"flex-1 mr-8"},se={class:"flex items-baseline gap-2 mb-2 flex-wrap"},ae={class:"text-xl sm:text-2xl md:text-3xl font-bold text-blue-600"},oe={class:"text-sm text-green-600 font-medium"},ne={class:"text-xs text-gray-500"},le={class:"flex justify-between items-center flex-wrap gap-x-4"},re={class:"font-medium"},ie={class:"font-medium"},de={key:0,class:"text-purple-600"},ue={class:"font-medium"},ce={key:1,class:"text-purple-600"},me={class:"font-medium"},pe={class:"stat-card"},ye={class:"flex items-center justify-between"},fe={class:"flex-1 mr-8"},ge={class:"flex items-baseline gap-2 mb-2 flex-wrap"},xe={class:"text-xl sm:text-2xl md:text-3xl font-bold text-emerald-600"},ve={class:"text-sm text-green-600 font-medium"},he={class:"text-xs text-gray-500"},be={class:"flex justify-between items-center flex-wrap gap-x-4"},De={class:"font-medium"},ke={class:"font-medium"},Te={key:0,class:"text-purple-600"},Ce={class:"font-medium"},we={key:1,class:"text-purple-600"},_e={class:"font-medium"},Se={class:"stat-card"},Re={class:"flex items-center justify-between"},$e={class:"text-xs sm:text-sm font-semibold text-gray-600 mb-1"},Ae={class:"text-xs text-gray-400"},Ie={class:"text-2xl sm:text-3xl font-bold text-orange-600"},Ue={class:"text-xs text-gray-500 mt-1"},Me={key:0,class:"text-yellow-600"},Ke={class:"stat-card"},Pe={class:"flex items-center justify-between"},Oe={class:"text-xs sm:text-sm font-semibold text-gray-600 mb-1"},Fe={class:"text-xs text-gray-400"},Be={class:"text-2xl sm:text-3xl font-bold text-rose-600"},ze={class:"text-xs text-gray-500 mt-1"},He={key:0,class:"text-yellow-600"},qe={class:"mb-8"},Ee={class:"flex flex-col gap-4 mb-4 sm:mb-6"},Ne={class:"flex flex-col lg:flex-row gap-2 lg:items-center lg:justify-end"},Le={class:"flex gap-1 bg-gray-100 rounded-lg p-1 overflow-x-auto flex-shrink-0"},Ve=["onClick"],je={class:"flex gap-1 bg-gray-100 rounded-lg p-1"},Ye={class:"flex items-center gap-2"},We={key:0,class:"text-xs text-orange-600"},Ge={class:"flex items-center gap-2"},Qe={class:"flex items-center bg-gray-100 rounded-lg px-3 py-1"},Ze={class:"relative inline-flex items-center cursor-pointer"},Je={class:"ml-2.5 text-sm font-medium text-gray-600 select-none flex items-center gap-1"},Xe=["disabled"],ts={class:"hidden sm:inline"},es={class:"grid grid-cols-1 lg:grid-cols-2 gap-6"},ss={class:"card p-4 sm:p-6"},as={class:"relative",style:{height:"250px"}},os={class:"card p-4 sm:p-6"},ns={key:0,class:"text-center py-8"},ls={key:1,class:"overflow-auto max-h-[250px] sm:max-h-[300px]"},rs={class:"min-w-full"},is={class:"divide-y divide-gray-200"},ds={class:"px-2 sm:px-4 py-2 text-xs sm:text-sm text-gray-900"},us=["title"],cs={class:"px-2 sm:px-4 py-2 text-xs sm:text-sm text-gray-600 text-right hidden sm:table-cell"},ms={class:"px-2 sm:px-4 py-2 text-xs sm:text-sm text-gray-600 text-right"},ps={class:"px-2 sm:px-4 py-2 text-xs sm:text-sm text-green-600 text-right font-medium"},ys={class:"px-2 sm:px-4 py-2 text-xs sm:text-sm font-medium text-right hidden sm:table-cell"},fs={class:"inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-blue-100 text-blue-800"},gs={class:"mb-4 sm:mb-6 md:mb-8"},xs={class:"card p-4 sm:p-6"},vs={style:{height:"250px"},class:"sm:h-[300px]"},hs={class:"mb-4 sm:mb-6 md:mb-8"},bs={class:"card p-4 sm:p-6"},Ds={class:"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 mb-4"},ks={class:"flex gap-1 bg-gray-100 rounded-lg p-1"},Ts={class:"mb-4 text-xs sm:text-sm text-gray-600"},Cs={key:0},ws={key:1},_s={style:{height:"300px"},class:"sm:h-[350px]"},Ss={__name:"DashboardView",setup(nt){const V=Mt(),{dashboardData:p,costsData:lt,dashboardModelStats:q,trendData:X,apiKeysTrendData:I,formattedUptime:o,dateFilter:C,trendGranularity:E,apiKeysTrendMetric:O,defaultTime:pt}=_t(V),{loadDashboardData:D,loadApiKeysTrend:yt,setDateFilterPreset:rt,onCustomDateRangeChange:it,setTrendGranularity:tt,refreshChartsData:j,disabledDate:ft}=V,et=T(null),N=T(null),Q=T(null);let Y=null,i=null,l=null;const r=T(!1),u=T(30),a=T(null),s=T(0),d=T(null),m=T(!1);kt(()=>!r.value||s.value<=0?"":`${s.value}秒后刷新`);function c(v){return v>=1e6?(v/1e6).toFixed(2)+"M":v>=1e3?(v/1e3).toFixed(2)+"K":v.toString()}function k(v,e){if(!e||e.length===0)return 0;const w=e.reduce((g,L)=>g+L.allTokens,0);return w===0?0:(v/w*100).toFixed(1)}function K(){if(!et.value)return;Y&&Y.destroy();const v=q.value||[],e={labels:v.map(w=>w.model),datasets:[{data:v.map(w=>w.allTokens),backgroundColor:["#3B82F6","#10B981","#F59E0B","#EF4444","#8B5CF6","#EC4899","#14B8A6","#F97316","#6366F1","#84CC16"],borderWidth:0}]};Y=new vt(et.value,{type:"doughnut",data:e,options:{responsive:!0,maintainAspectRatio:!1,plugins:{legend:{position:"bottom",labels:{padding:15,usePointStyle:!0,font:{size:12}}},tooltip:{callbacks:{label:function(w){const g=w.label||"",L=c(w.parsed),st=k(w.parsed,v);return`${g}: ${L} (${st}%)`}}}}}})}function P(){var _;if(!N.value)return;i&&i.destroy();const v=X.value||[],e=v.map(f=>f.inputTokens||0),w=v.map(f=>f.outputTokens||0),g=v.map(f=>f.cacheCreateTokens||0),L=v.map(f=>f.cacheReadTokens||0),st=v.map(f=>f.requests||0),dt=v.map(f=>f.cost||0),ut=(_=v[0])!=null&&_.date?"date":"hour",M={labels:v.map(f=>{if(f.label)return f.label;if(ut==="hour"){const x=new Date(f.hour),A=String(x.getMonth()+1).padStart(2,"0"),W=String(x.getDate()).padStart(2,"0"),ct=String(x.getHours()).padStart(2,"0");return`${A}/${W} ${ct}:00`}const b=f.date;if(b&&b.includes("-")){const x=b.split("-");if(x.length>=3)return`${x[1]}/${x[2]}`}return f.date}),datasets:[{label:"输入Token",data:e,borderColor:"rgb(102, 126, 234)",backgroundColor:"rgba(102, 126, 234, 0.1)",tension:.3},{label:"输出Token",data:w,borderColor:"rgb(240, 147, 251)",backgroundColor:"rgba(240, 147, 251, 0.1)",tension:.3},{label:"缓存创建Token",data:g,borderColor:"rgb(59, 130, 246)",backgroundColor:"rgba(59, 130, 246, 0.1)",tension:.3},{label:"缓存读取Token",data:L,borderColor:"rgb(147, 51, 234)",backgroundColor:"rgba(147, 51, 234, 0.1)",tension:.3},{label:"费用 (USD)",data:dt,borderColor:"rgb(34, 197, 94)",backgroundColor:"rgba(34, 197, 94, 0.1)",tension:.3,yAxisID:"y2"},{label:"请求数",data:st,borderColor:"rgb(16, 185, 129)",backgroundColor:"rgba(16, 185, 129, 0.1)",tension:.3,yAxisID:"y1"}]};i=new vt(N.value,{type:"line",data:M,options:{responsive:!0,maintainAspectRatio:!1,interaction:{mode:"index",intersect:!1},plugins:{title:{display:!0,text:"Token使用趋势",font:{size:16,weight:"bold"}},legend:{position:"top"},tooltip:{mode:"index",intersect:!1,itemSort:function(f,b){const x=f.dataset.label||"",A=b.dataset.label||"";return x==="费用 (USD)"||A==="费用 (USD)"?x==="费用 (USD)"?-1:1:x==="请求数"||A==="请求数"?x==="请求数"?1:-1:b.parsed.y-f.parsed.y},callbacks:{label:function(f){const b=f.dataset.label||"";let x=f.parsed.y;return b==="费用 (USD)"?x<.01?b+": $"+x.toFixed(6):b+": $"+x.toFixed(4):b==="请求数"?b+": "+x.toLocaleString()+" 次":x>=1e6?b+": "+(x/1e6).toFixed(2)+"M tokens":x>=1e3?b+": "+(x/1e3).toFixed(2)+"K tokens":b+": "+x.toLocaleString()+" tokens"}}}},scales:{x:{type:"category",display:!0,title:{display:!0,text:E.value==="hour"?"时间":"日期"}},y:{type:"linear",display:!0,position:"left",title:{display:!0,text:"Token数量"},ticks:{callback:function(f){return c(f)}}},y1:{type:"linear",display:!0,position:"right",title:{display:!0,text:"请求数"},grid:{drawOnChartArea:!1},ticks:{callback:function(f){return f.toLocaleString()}}},y2:{type:"linear",display:!1,position:"right"}}}})}function U(){var dt,ut;if(!Q.value)return;l&&l.destroy();const v=I.value.data||[],e=O.value,w=["#3B82F6","#10B981","#F59E0B","#EF4444","#8B5CF6","#EC4899","#14B8A6","#F97316","#6366F1","#84CC16"],g=((dt=I.value.topApiKeys)==null?void 0:dt.map((h,M)=>{var b,x;const _=I.value.data.map(A=>!A.apiKeys||!A.apiKeys[h]?0:e==="tokens"?A.apiKeys[h].tokens:A.apiKeys[h].requests||0);return{label:((x=(b=I.value.data.find(A=>A.apiKeys&&A.apiKeys[h]))==null?void 0:b.apiKeys[h])==null?void 0:x.name)||`API Key ${h}`,data:_,borderColor:w[M%w.length],backgroundColor:w[M%w.length]+"20",tension:.4,fill:!1}}))||[],L=(ut=v[0])!=null&&ut.date?"date":"hour",st={labels:v.map(h=>{if(h.label)return h.label;if(L==="hour"){const _=new Date(h.hour),f=String(_.getMonth()+1).padStart(2,"0"),b=String(_.getDate()).padStart(2,"0"),x=String(_.getHours()).padStart(2,"0");return`${f}/${b} ${x}:00`}const M=h.date;if(M&&M.includes("-")){const _=M.split("-");if(_.length>=3)return`${_[1]}/${_[2]}`}return h.date}),datasets:g};l=new vt(Q.value,{type:"line",data:st,options:{responsive:!0,maintainAspectRatio:!1,plugins:{legend:{position:"bottom",labels:{padding:20,usePointStyle:!0,font:{size:12}}},tooltip:{mode:"index",intersect:!1,itemSort:function(h,M){return M.parsed.y-h.parsed.y},callbacks:{label:function(h){var ct;const M=h.dataset.label||"",_=h.parsed.y,f=h.dataIndex,b=I.value.data[f],A=h.chart.data.datasets.map((z,at)=>({value:z.data[f]||0,index:at})).sort((z,at)=>at.value-z.value).findIndex(z=>z.index===h.datasetIndex)+1;let W="";if(A===1?W="🥇 ":A===2?W="🥈 ":A===3&&(W="🥉 "),O.value==="tokens"){let z="";_>=1e6?z=(_/1e6).toFixed(2)+"M":_>=1e3?z=(_/1e3).toFixed(2)+"K":z=_.toLocaleString();const at=I.value.topApiKeys[h.datasetIndex],gt=(ct=b==null?void 0:b.apiKeys)==null?void 0:ct[at],Tt=(gt==null?void 0:gt.formattedCost)||"$0.00";return`${W}${M}: ${z} tokens (${Tt})`}else return`${W}${M}: ${_.toLocaleString()}`}}}},scales:{x:{type:"category",display:!0,title:{display:!0,text:E.value==="hour"?"时间":"日期"}},y:{beginAtZero:!0,title:{display:!0,text:O.value==="tokens"?"Token 数量":"请求次数"},ticks:{callback:function(h){return c(h)}}}}}})}async function F(){await yt(O.value),await ot(),U()}mt(q,()=>{ot(()=>K())}),mt(X,()=>{ot(()=>P())}),mt(I,()=>{ot(()=>U())});async function B(){if(!m.value){m.value=!0;try{await Promise.all([D(),j()])}finally{m.value=!1}}}function Z(){r.value&&(s.value=u.value,d.value&&clearInterval(d.value),a.value&&clearTimeout(a.value),d.value=setInterval(()=>{s.value--,s.value<=0&&clearInterval(d.value)},1e3),a.value=setTimeout(async()=>{await B(),r.value&&Z()},u.value*1e3))}function ht(){d.value&&(clearInterval(d.value),d.value=null),a.value&&(clearTimeout(a.value),a.value=null),s.value=0}return mt(r,v=>{v?Z():ht()}),St(async()=>{await B(),await ot(),K(),P(),U()}),Rt(()=>{ht(),Y&&Y.destroy(),i&&i.destroy(),l&&l.destroy()}),(v,e)=>{const w=Ct;return $(),S("div",null,[t("div",Kt,[t("div",Pt,[t("div",Ot,[t("div",null,[e[7]||(e[7]=t("p",{class:"text-xs sm:text-sm font-semibold text-gray-600 mb-1"}," 总API Keys ",-1)),t("p",Ft,y(n(p).totalApiKeys),1),t("p",Bt," 活跃: "+y(n(p).activeApiKeys||0),1)]),e[8]||(e[8]=t("div",{class:"stat-icon flex-shrink-0 bg-gradient-to-br from-blue-500 to-blue-600"},[t("i",{class:"fas fa-key"})],-1))])]),t("div",zt,[t("div",Ht,[t("div",null,[e[9]||(e[9]=t("p",{class:"text-xs sm:text-sm font-semibold text-gray-600 mb-1"}," 服务账户 ",-1)),t("p",qt,y(n(p).totalAccounts),1),t("p",Et,[R(" 活跃: "+y(n(p).activeAccounts||0)+" ",1),n(p).rateLimitedAccounts>0?($(),S("span",Nt," | 限流: "+y(n(p).rateLimitedAccounts),1)):H("",!0)])]),e[10]||(e[10]=t("div",{class:"stat-icon flex-shrink-0 bg-gradient-to-br from-green-500 to-green-600"},[t("i",{class:"fas fa-user-circle"})],-1))])]),t("div",Lt,[t("div",Vt,[t("div",null,[e[11]||(e[11]=t("p",{class:"text-xs sm:text-sm font-semibold text-gray-600 mb-1"}," 今日请求 ",-1)),t("p",jt,y(n(p).todayRequests),1),t("p",Yt," 总请求: "+y(c(n(p).totalRequests||0)),1)]),e[12]||(e[12]=t("div",{class:"stat-icon flex-shrink-0 bg-gradient-to-br from-purple-500 to-purple-600"},[t("i",{class:"fas fa-chart-line"})],-1))])]),t("div",Wt,[t("div",Gt,[t("div",null,[e[13]||(e[13]=t("p",{class:"text-xs sm:text-sm font-semibold text-gray-600 mb-1"}," 系统状态 ",-1)),t("p",Qt,y(n(p).systemStatus),1),t("p",Zt," 运行时间: "+y(n(o)),1)]),e[14]||(e[14]=t("div",{class:"stat-icon flex-shrink-0 bg-gradient-to-br from-yellow-500 to-orange-500"},[t("i",{class:"fas fa-heartbeat"})],-1))])])]),t("div",Jt,[t("div",Xt,[t("div",te,[t("div",ee,[e[19]||(e[19]=t("p",{class:"text-xs sm:text-sm font-semibold text-gray-600 mb-1"}," 今日Token ",-1)),t("div",se,[t("p",ae,y(c((n(p).todayInputTokens||0)+(n(p).todayOutputTokens||0)+(n(p).todayCacheCreateTokens||0)+(n(p).todayCacheReadTokens||0))),1),t("span",oe,"/ "+y(n(lt).todayCosts.formatted.totalCost),1)]),t("div",ne,[t("div",le,[t("span",null,[e[15]||(e[15]=R("输入: ",-1)),t("span",re,y(c(n(p).todayInputTokens||0)),1)]),t("span",null,[e[16]||(e[16]=R("输出: ",-1)),t("span",ie,y(c(n(p).todayOutputTokens||0)),1)]),(n(p).todayCacheCreateTokens||0)>0?($(),S("span",de,[e[17]||(e[17]=R("缓存创建: ",-1)),t("span",ue,y(c(n(p).todayCacheCreateTokens||0)),1)])):H("",!0),(n(p).todayCacheReadTokens||0)>0?($(),S("span",ce,[e[18]||(e[18]=R("缓存读取: ",-1)),t("span",me,y(c(n(p).todayCacheReadTokens||0)),1)])):H("",!0)])])]),e[20]||(e[20]=t("div",{class:"stat-icon flex-shrink-0 bg-gradient-to-br from-indigo-500 to-indigo-600"},[t("i",{class:"fas fa-coins"})],-1))])]),t("div",pe,[t("div",ye,[t("div",fe,[e[25]||(e[25]=t("p",{class:"text-xs sm:text-sm font-semibold text-gray-600 mb-1"}," 总Token消耗 ",-1)),t("div",ge,[t("p",xe,y(c((n(p).totalInputTokens||0)+(n(p).totalOutputTokens||0)+(n(p).totalCacheCreateTokens||0)+(n(p).totalCacheReadTokens||0))),1),t("span",ve,"/ "+y(n(lt).totalCosts.formatted.totalCost),1)]),t("div",he,[t("div",be,[t("span",null,[e[21]||(e[21]=R("输入: ",-1)),t("span",De,y(c(n(p).totalInputTokens||0)),1)]),t("span",null,[e[22]||(e[22]=R("输出: ",-1)),t("span",ke,y(c(n(p).totalOutputTokens||0)),1)]),(n(p).totalCacheCreateTokens||0)>0?($(),S("span",Te,[e[23]||(e[23]=R("缓存创建: ",-1)),t("span",Ce,y(c(n(p).totalCacheCreateTokens||0)),1)])):H("",!0),(n(p).totalCacheReadTokens||0)>0?($(),S("span",we,[e[24]||(e[24]=R("缓存读取: ",-1)),t("span",_e,y(c(n(p).totalCacheReadTokens||0)),1)])):H("",!0)])])]),e[26]||(e[26]=t("div",{class:"stat-icon flex-shrink-0 bg-gradient-to-br from-emerald-500 to-emerald-600"},[t("i",{class:"fas fa-database"})],-1))])]),t("div",Se,[t("div",Re,[t("div",null,[t("p",$e,[e[27]||(e[27]=R(" 实时RPM ",-1)),t("span",Ae,"("+y(n(p).metricsWindow)+"分钟)",1)]),t("p",Ie,y(n(p).realtimeRPM||0),1),t("p",Ue,[e[29]||(e[29]=R(" 每分钟请求数 ",-1)),n(p).isHistoricalMetrics?($(),S("span",Me,e[28]||(e[28]=[t("i",{class:"fas fa-exclamation-circle"},null,-1),R(" 历史数据 ",-1)]))):H("",!0)])]),e[30]||(e[30]=t("div",{class:"stat-icon flex-shrink-0 bg-gradient-to-br from-orange-500 to-orange-600"},[t("i",{class:"fas fa-tachometer-alt"})],-1))])]),t("div",Ke,[t("div",Pe,[t("div",null,[t("p",Oe,[e[31]||(e[31]=R(" 实时TPM ",-1)),t("span",Fe,"("+y(n(p).metricsWindow)+"分钟)",1)]),t("p",Be,y(c(n(p).realtimeTPM||0)),1),t("p",ze,[e[33]||(e[33]=R(" 每分钟Token数 ",-1)),n(p).isHistoricalMetrics?($(),S("span",He,e[32]||(e[32]=[t("i",{class:"fas fa-exclamation-circle"},null,-1),R(" 历史数据 ",-1)]))):H("",!0)])]),e[34]||(e[34]=t("div",{class:"stat-icon flex-shrink-0 bg-gradient-to-br from-rose-500 to-rose-600"},[t("i",{class:"fas fa-rocket"})],-1))])])]),t("div",qe,[t("div",Ee,[e[41]||(e[41]=t("h3",{class:"text-lg sm:text-xl font-bold text-gray-900"}," 模型使用分布与Token使用趋势 ",-1)),t("div",Ne,[t("div",Le,[($(!0),S(bt,null,Dt(n(C).presetOptions,g=>($(),S("button",{key:g.value,class:G(["px-3 py-1 rounded-md text-sm font-medium transition-colors",n(C).preset===g.value&&n(C).type==="preset"?"bg-white text-blue-600 shadow-sm":"text-gray-600 hover:text-gray-900"]),onClick:L=>n(rt)(g.value)},y(g.label),11,Ve))),128))]),t("div",je,[t("button",{class:G(["px-3 py-1 rounded-md text-sm font-medium transition-colors",n(E)==="day"?"bg-white text-blue-600 shadow-sm":"text-gray-600 hover:text-gray-900"]),onClick:e[0]||(e[0]=g=>n(tt)("day"))},e[35]||(e[35]=[t("i",{class:"fas fa-calendar-day mr-1"},null,-1),R("按天 ",-1)]),2),t("button",{class:G(["px-3 py-1 rounded-md text-sm font-medium transition-colors",n(E)==="hour"?"bg-white text-blue-600 shadow-sm":"text-gray-600 hover:text-gray-900"]),onClick:e[1]||(e[1]=g=>n(tt)("hour"))},e[36]||(e[36]=[t("i",{class:"fas fa-clock mr-1"},null,-1),R("按小时 ",-1)]),2)]),t("div",Ye,[$t(w,{modelValue:n(C).customRange,"onUpdate:modelValue":e[2]||(e[2]=g=>n(C).customRange=g),"default-time":n(pt),type:"datetimerange","range-separator":"至","start-placeholder":"开始日期","end-placeholder":"结束日期",format:"YYYY-MM-DD HH:mm:ss","value-format":"YYYY-MM-DD HH:mm:ss","disabled-date":n(ft),size:"default",class:"w-full lg:w-auto custom-date-picker",style:{"max-width":"400px"},onChange:n(it)},null,8,["modelValue","default-time","disabled-date","onChange"]),n(E)==="hour"?($(),S("span",We,e[37]||(e[37]=[t("i",{class:"fas fa-info-circle"},null,-1),R(" 最多24小时 ",-1)]))):H("",!0)]),t("div",Ge,[t("div",Qe,[t("label",Ze,[At(t("input",{"onUpdate:modelValue":e[3]||(e[3]=g=>r.value=g),type:"checkbox",class:"sr-only peer"},null,512),[[It,r.value]]),e[40]||(e[40]=t("div",{class:"relative w-9 h-5 bg-gray-300 peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-blue-300 rounded-full peer peer-checked:bg-blue-500 transition-all duration-200 after:content-[''] after:absolute after:top-0.5 after:left-[2px] after:bg-white after:w-4 after:h-4 after:rounded-full after:shadow-sm after:transition-transform after:duration-200 peer-checked:after:translate-x-4"},null,-1)),t("span",Je,[e[38]||(e[38]=t("i",{class:"fas fa-redo-alt text-xs text-gray-500"},null,-1)),e[39]||(e[39]=t("span",null,"自动刷新",-1)),r.value?($(),S("span",{key:0,class:G(["ml-1 text-xs text-blue-600 font-mono transition-opacity",s.value>0?"opacity-100":"opacity-0"])},y(s.value)+"s ",3)):H("",!0)])])]),t("button",{disabled:m.value,class:"px-3 py-1 rounded-md text-sm font-medium transition-colors bg-white text-blue-600 shadow-sm hover:bg-gray-50 border border-gray-300 flex items-center gap-1 sm:gap-2 disabled:opacity-50 disabled:cursor-not-allowed",title:"立即刷新数据",onClick:e[4]||(e[4]=g=>B())},[t("i",{class:G(["fas fa-sync-alt text-xs",{"animate-spin":m.value}])},null,2),t("span",ts,y(m.value?"刷新中":"刷新"),1)],8,Xe)])])]),t("div",es,[t("div",ss,[e[42]||(e[42]=t("h4",{class:"text-base sm:text-lg font-semibold text-gray-800 mb-4"}," Token使用分布 ",-1)),t("div",as,[t("canvas",{ref_key:"modelUsageChart",ref:et},null,512)])]),t("div",os,[e[45]||(e[45]=t("h4",{class:"text-base sm:text-lg font-semibold text-gray-800 mb-4"}," 详细统计数据 ",-1)),n(q).length===0?($(),S("div",ns,e[43]||(e[43]=[t("p",{class:"text-gray-500 text-sm sm:text-base"}," 暂无模型使用数据 ",-1)]))):($(),S("div",ls,[t("table",rs,[e[44]||(e[44]=t("thead",{class:"bg-gray-50 sticky top-0"},[t("tr",null,[t("th",{class:"px-2 sm:px-4 py-2 text-left text-xs font-medium text-gray-700"}," 模型 "),t("th",{class:"px-2 sm:px-4 py-2 text-right text-xs font-medium text-gray-700 hidden sm:table-cell"}," 请求数 "),t("th",{class:"px-2 sm:px-4 py-2 text-right text-xs font-medium text-gray-700"}," 总Token "),t("th",{class:"px-2 sm:px-4 py-2 text-right text-xs font-medium text-gray-700"}," 费用 "),t("th",{class:"px-2 sm:px-4 py-2 text-right text-xs font-medium text-gray-700 hidden sm:table-cell"}," 占比 ")])],-1)),t("tbody",is,[($(!0),S(bt,null,Dt(n(q),g=>($(),S("tr",{key:g.model,class:"hover:bg-gray-50"},[t("td",ds,[t("span",{class:"block truncate max-w-[100px] sm:max-w-none",title:g.model},y(g.model),9,us)]),t("td",cs,y(c(g.requests)),1),t("td",ms,y(c(g.allTokens)),1),t("td",ps,y(g.formatted?g.formatted.total:"$0.000000"),1),t("td",ys,[t("span",fs,y(k(g.allTokens,n(q)))+"% ",1)])]))),128))])])]))])])]),t("div",gs,[t("div",xs,[t("div",vs,[t("canvas",{ref_key:"usageTrendChart",ref:N},null,512)])])]),t("div",hs,[t("div",bs,[t("div",Ds,[e[48]||(e[48]=t("h3",{class:"text-base sm:text-lg font-semibold text-gray-900"}," API Keys 使用趋势 ",-1)),t("div",ks,[t("button",{class:G(["px-2 sm:px-3 py-1 rounded-md text-xs sm:text-sm font-medium transition-colors",n(O)==="requests"?"bg-white text-blue-600 shadow-sm":"text-gray-600 hover:text-gray-900"]),onClick:e[5]||(e[5]=g=>{O.value="requests",F()})},e[46]||(e[46]=[t("i",{class:"fas fa-exchange-alt mr-1"},null,-1),t("span",{class:"hidden sm:inline"},"请求次数",-1),t("span",{class:"sm:hidden"},"请求",-1)]),2),t("button",{class:G(["px-2 sm:px-3 py-1 rounded-md text-xs sm:text-sm font-medium transition-colors",n(O)==="tokens"?"bg-white text-blue-600 shadow-sm":"text-gray-600 hover:text-gray-900"]),onClick:e[6]||(e[6]=g=>{O.value="tokens",F()})},e[47]||(e[47]=[t("i",{class:"fas fa-coins mr-1"},null,-1),t("span",{class:"hidden sm:inline"},"Token 数量",-1),t("span",{class:"sm:hidden"},"Token",-1)]),2)])]),t("div",Ts,[n(I).totalApiKeys>10?($(),S("span",Cs," 共 "+y(n(I).totalApiKeys)+" 个 API Key显示使用量前 10 个 ",1)):($(),S("span",ws," 共 "+y(n(I).totalApiKeys)+" 个 API Key ",1))]),t("div",_s,[t("canvas",{ref_key:"apiKeysUsageTrendChart",ref:Q},null,512)])])])])}}},Ks=Ut(Ss,[["__scopeId","data-v-a1b368e2"]]);export{Ks as default};