diff --git a/VERSION b/VERSION
index baeb5d0c..6d4b6e1b 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.1.54
+1.1.55
diff --git a/web/admin-spa/dist/assets/AccountsView-CGu30Mq0.js b/web/admin-spa/dist/assets/AccountsView-z89aebep.js
similarity index 99%
rename from web/admin-spa/dist/assets/AccountsView-CGu30Mq0.js
rename to web/admin-spa/dist/assets/AccountsView-z89aebep.js
index d394da19..bb4c1452 100644
--- a/web/admin-spa/dist/assets/AccountsView-CGu30Mq0.js
+++ b/web/admin-spa/dist/assets/AccountsView-z89aebep.js
@@ -1,4 +1,4 @@
-import{r as T,aR as Te,o as O,V as Ae,x as u,y as i,z as e,L as $,K as w,al as xe,aY as te,aX as we,aq as j,aZ as Ue,C as G,O as h,c as se,P as U,I as le,a5 as ke,R as ne,an as H,u as W,q as Ve,Y as Ie,Q as je,ac as Se,B as ve}from"./vue-vendor-CKToUHZx.js";import{s as V}from"./toast-BvwA7Mwb.js";import{a as K,_ as Me}from"./index-D7YURYF2.js";import"./element-plus-B8Fs_0jW.js";import"./vendor-BDiMbLwQ.js";const oe=T(!1),ye=T({title:"",message:"",confirmText:"继续",cancelText:"取消"}),J=T(null);function he(){return{showConfirmModal:oe,confirmOptions:ye,showConfirm:(g,d,S="继续",I="取消")=>new Promise(C=>{ye.value={title:g,message:d,confirmText:S,cancelText:I},J.value=C,oe.value=!0}),handleConfirm:()=>{oe.value=!1,J.value&&(J.value(!0),J.value=null)},handleCancel:()=>{oe.value=!1,J.value&&(J.value(!1),J.value=null)}}}const $e=Te("accounts",()=>{const L=T([]),E=T([]),m=T([]),g=T(!1),d=T(null),S=T(""),I=T("asc"),C=async()=>{g.value=!0,d.value=null;try{const x=await K.get("/admin/claude-accounts");if(x.success)L.value=x.data||[];else throw new Error(x.message||"获取Claude账户失败")}catch(x){throw d.value=x.message,x}finally{g.value=!1}},A=async()=>{g.value=!0,d.value=null;try{const x=await K.get("/admin/claude-console-accounts");if(x.success)E.value=x.data||[];else throw new Error(x.message||"获取Claude Console账户失败")}catch(x){throw d.value=x.message,x}finally{g.value=!1}},y=async()=>{g.value=!0,d.value=null;try{const x=await K.get("/admin/gemini-accounts");if(x.success)m.value=x.data||[];else throw new Error(x.message||"获取Gemini账户失败")}catch(x){throw d.value=x.message,x}finally{g.value=!1}};return{claudeAccounts:L,claudeConsoleAccounts:E,geminiAccounts:m,loading:g,error:d,sortBy:S,sortOrder:I,fetchClaudeAccounts:C,fetchClaudeConsoleAccounts:A,fetchGeminiAccounts:y,fetchAllAccounts:async()=>{g.value=!0,d.value=null;try{await Promise.all([C(),A(),y()])}catch(x){throw d.value=x.message,x}finally{g.value=!1}},createClaudeAccount:async x=>{g.value=!0,d.value=null;try{const c=await K.post("/admin/claude-accounts",x);if(c.success)return await C(),c.data;throw new Error(c.message||"创建Claude账户失败")}catch(c){throw d.value=c.message,c}finally{g.value=!1}},createClaudeConsoleAccount:async x=>{g.value=!0,d.value=null;try{const c=await K.post("/admin/claude-console-accounts",x);if(c.success)return await A(),c.data;throw new Error(c.message||"创建Claude Console账户失败")}catch(c){throw d.value=c.message,c}finally{g.value=!1}},createGeminiAccount:async x=>{g.value=!0,d.value=null;try{const c=await K.post("/admin/gemini-accounts",x);if(c.success)return await y(),c.data;throw new Error(c.message||"创建Gemini账户失败")}catch(c){throw d.value=c.message,c}finally{g.value=!1}},updateClaudeAccount:async(x,c)=>{g.value=!0,d.value=null;try{const b=await K.put(`/admin/claude-accounts/${x}`,c);if(b.success)return await C(),b;throw new Error(b.message||"更新Claude账户失败")}catch(b){throw d.value=b.message,b}finally{g.value=!1}},updateClaudeConsoleAccount:async(x,c)=>{g.value=!0,d.value=null;try{const b=await K.put(`/admin/claude-console-accounts/${x}`,c);if(b.success)return await A(),b;throw new Error(b.message||"更新Claude Console账户失败")}catch(b){throw d.value=b.message,b}finally{g.value=!1}},updateGeminiAccount:async(x,c)=>{g.value=!0,d.value=null;try{const b=await K.put(`/admin/gemini-accounts/${x}`,c);if(b.success)return await y(),b;throw new Error(b.message||"更新Gemini账户失败")}catch(b){throw d.value=b.message,b}finally{g.value=!1}},toggleAccount:async(x,c)=>{g.value=!0,d.value=null;try{let b;x==="claude"?b=`/admin/claude-accounts/${c}/toggle`:x==="claude-console"?b=`/admin/claude-console-accounts/${c}/toggle`:b=`/admin/gemini-accounts/${c}/toggle`;const q=await K.put(b);if(q.success)return x==="claude"?await C():x==="claude-console"?await A():await y(),q;throw new Error(q.message||"切换状态失败")}catch(b){throw d.value=b.message,b}finally{g.value=!1}},deleteAccount:async(x,c)=>{g.value=!0,d.value=null;try{let b;x==="claude"?b=`/admin/claude-accounts/${c}`:x==="claude-console"?b=`/admin/claude-console-accounts/${c}`:b=`/admin/gemini-accounts/${c}`;const q=await K.delete(b);if(q.success)return x==="claude"?await C():x==="claude-console"?await A():await y(),q;throw new Error(q.message||"删除失败")}catch(b){throw d.value=b.message,b}finally{g.value=!1}},refreshClaudeToken:async x=>{g.value=!0,d.value=null;try{const c=await K.post(`/admin/claude-accounts/${x}/refresh`);if(c.success)return await C(),c;throw new Error(c.message||"Token刷新失败")}catch(c){throw d.value=c.message,c}finally{g.value=!1}},generateClaudeAuthUrl:async x=>{try{const c=await K.post("/admin/claude-accounts/generate-auth-url",x);if(c.success)return c.data;throw new Error(c.message||"生成授权URL失败")}catch(c){throw d.value=c.message,c}},exchangeClaudeCode:async x=>{try{const c=await K.post("/admin/claude-accounts/exchange-code",x);if(c.success)return c.data;throw new Error(c.message||"交换授权码失败")}catch(c){throw d.value=c.message,c}},generateGeminiAuthUrl:async x=>{try{const c=await K.post("/admin/gemini-accounts/generate-auth-url",x);if(c.success)return c.data;throw new Error(c.message||"生成授权URL失败")}catch(c){throw d.value=c.message,c}},exchangeGeminiCode:async x=>{try{const c=await K.post("/admin/gemini-accounts/exchange-code",x);if(c.success)return c.data;throw new Error(c.message||"交换授权码失败")}catch(c){throw d.value=c.message,c}},sortAccounts:x=>{S.value===x?I.value=I.value==="asc"?"desc":"asc":(S.value=x,I.value="asc")},reset:()=>{L.value=[],E.value=[],m.value=[],g.value=!1,d.value=null,S.value="",I.value="asc"}}}),Ke={class:"space-y-4"},Pe={class:"flex items-center justify-between"},Re={class:"flex items-center cursor-pointer"},Ge={key:0,class:"bg-gray-50 p-4 rounded-lg border border-gray-200 space-y-4"},Le={class:"grid grid-cols-2 gap-4"},De={class:"space-y-4"},Oe={class:"flex items-center"},Ee={key:0,class:"grid grid-cols-2 gap-4"},ze={class:"relative"},We=["type"],ge={__name:"ProxyConfig",props:{modelValue:{type:Object,default:()=>({enabled:!1,type:"socks5",host:"",port:"",username:"",password:""})}},emits:["update:modelValue"],setup(L,{emit:E}){const m=L,g=E,d=T({...m.modelValue}),S=T(!!(d.value.username||d.value.password)),I=T(!1);O(()=>m.modelValue,y=>{JSON.stringify(y)!==JSON.stringify(d.value)&&(d.value={...y},S.value=!!(y.username||y.password))},{deep:!0}),O(()=>d.value.enabled,y=>{A()}),O(()=>d.value.type,y=>{A()}),O(()=>d.value.host,y=>{A()}),O(()=>d.value.port,y=>{A()}),O(()=>d.value.username,y=>{A()}),O(()=>d.value.password,y=>{A()}),O(S,y=>{y||(d.value.username="",d.value.password="",A())});let C=null;function A(){C&&clearTimeout(C),C=setTimeout(()=>{const y={...d.value};S.value||(y.username="",y.password=""),g("update:modelValue",y)},100)}return Ae(()=>{C&&clearTimeout(C)}),(y,f)=>(i(),u("div",Ke,[e("div",Pe,[f[9]||(f[9]=e("h4",{class:"text-sm font-semibold text-gray-700"}," 代理设置 (可选) ",-1)),e("label",Re,[w(e("input",{"onUpdate:modelValue":f[0]||(f[0]=M=>d.value.enabled=M),type:"checkbox",class:"w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500"},null,512),[[xe,d.value.enabled]]),f[8]||(f[8]=e("span",{class:"ml-2 text-sm text-gray-700"},"启用代理",-1))])]),d.value.enabled?(i(),u("div",Ge,[f[17]||(f[17]=te('
配置代理以访问受限的网络资源。支持 SOCKS5 和 HTTP 代理。
请确保代理服务器稳定可用,否则会影响账户的正常使用。
',1)),e("div",null,[f[11]||(f[11]=e("label",{class:"block text-sm font-medium text-gray-700 mb-2"},"代理类型",-1)),w(e("select",{"onUpdate:modelValue":f[1]||(f[1]=M=>d.value.type=M),class:"form-input w-full"},f[10]||(f[10]=[e("option",{value:"socks5"}," SOCKS5 ",-1),e("option",{value:"http"}," HTTP ",-1),e("option",{value:"https"}," HTTPS ",-1)]),512),[[we,d.value.type]])]),e("div",Le,[e("div",null,[f[12]||(f[12]=e("label",{class:"block text-sm font-medium text-gray-700 mb-2"},"主机地址",-1)),w(e("input",{"onUpdate:modelValue":f[2]||(f[2]=M=>d.value.host=M),type:"text",placeholder:"例如: 192.168.1.100",class:"form-input w-full"},null,512),[[j,d.value.host]])]),e("div",null,[f[13]||(f[13]=e("label",{class:"block text-sm font-medium text-gray-700 mb-2"},"端口",-1)),w(e("input",{"onUpdate:modelValue":f[3]||(f[3]=M=>d.value.port=M),type:"number",placeholder:"例如: 1080",class:"form-input w-full"},null,512),[[j,d.value.port]])])]),e("div",De,[e("div",Oe,[w(e("input",{id:"proxyAuth","onUpdate:modelValue":f[4]||(f[4]=M=>S.value=M),type:"checkbox",class:"w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500"},null,512),[[xe,S.value]]),f[14]||(f[14]=e("label",{for:"proxyAuth",class:"ml-2 text-sm text-gray-700 cursor-pointer"}," 需要身份验证 ",-1))]),S.value?(i(),u("div",Ee,[e("div",null,[f[15]||(f[15]=e("label",{class:"block text-sm font-medium text-gray-700 mb-2"},"用户名",-1)),w(e("input",{"onUpdate:modelValue":f[5]||(f[5]=M=>d.value.username=M),type:"text",placeholder:"代理用户名",class:"form-input w-full"},null,512),[[j,d.value.username]])]),e("div",null,[f[16]||(f[16]=e("label",{class:"block text-sm font-medium text-gray-700 mb-2"},"密码",-1)),e("div",ze,[w(e("input",{"onUpdate:modelValue":f[6]||(f[6]=M=>d.value.password=M),type:I.value?"text":"password",placeholder:"代理密码",class:"form-input w-full pr-10"},null,8,We),[[Ue,d.value.password]]),e("button",{type:"button",class:"absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-gray-600",onClick:f[7]||(f[7]=M=>I.value=!I.value)},[e("i",{class:G(I.value?"fas fa-eye-slash":"fas fa-eye")},null,2)])])])])):$("",!0)]),f[18]||(f[18]=e("div",{class:"bg-blue-50 p-3 rounded-lg border border-blue-200"},[e("p",{class:"text-xs text-blue-700"},[e("i",{class:"fas fa-info-circle mr-1"}),e("strong",null,"提示:"),h("代理设置将用于所有与此账户相关的API请求。请确保代理服务器支持HTTPS流量转发。 ")])],-1))])):$("",!0)]))}},qe={class:"space-y-6"},Be={key:0},Ne={class:"bg-blue-50 p-6 rounded-lg border border-blue-200"},Fe={class:"flex items-start gap-4"},He={class:"flex-1"},_e={class:"space-y-4"},Je={class:"bg-white/80 rounded-lg p-4 border border-blue-300"},Ye={class:"flex items-start gap-3"},Qe={class:"flex-1"},Xe=["disabled"],Ze={key:0,class:"fas fa-link mr-2"},et={key:1,class:"loading-spinner mr-2"},tt={key:1,class:"space-y-3"},st={class:"flex items-center gap-2"},lt=["value"],at={class:"bg-white/80 rounded-lg p-4 border border-blue-300"},ot={class:"flex items-start gap-3"},nt={class:"flex-1"},rt={class:"space-y-3"},it={key:1},ut={class:"bg-green-50 p-6 rounded-lg border border-green-200"},dt={class:"flex items-start gap-4"},pt={class:"flex-1"},ct={class:"space-y-4"},mt={class:"bg-white/80 rounded-lg p-4 border border-green-300"},ft={class:"flex items-start gap-3"},xt={class:"flex-1"},vt=["disabled"],yt={key:0,class:"fas fa-link mr-2"},gt={key:1,class:"loading-spinner mr-2"},bt={key:1,class:"space-y-3"},wt={class:"flex items-center gap-2"},kt=["value"],ht={class:"bg-white/80 rounded-lg p-4 border border-green-300"},$t={class:"flex items-start gap-3"},Ct={class:"flex-1"},Tt={class:"space-y-3"},At={class:"flex gap-3 pt-4"},Ut=["disabled"],Vt={key:0,class:"loading-spinner mr-2"},It={__name:"OAuthFlow",props:{platform:{type:String,required:!0},proxy:{type:Object,default:null}},emits:["success","back"],setup(L,{emit:E}){const m=L,g=E,d=$e(),S=T(!1),I=T(!1),C=T(""),A=T(""),y=T(!1),f=T(""),M=se(()=>C.value&&A.value.trim());O(A,v=>{if(!v||typeof v!="string")return;const r=v.trim();if(!r)return;if(r.startsWith("http://")||r.startsWith("https://"))if(r.startsWith("http://localhost:45462"))try{const B=new URL(r).searchParams.get("code");B?(A.value=B,V("成功提取授权码!","success"),console.log("Successfully extracted authorization code from URL")):V("URL 中未找到授权码参数,请检查链接是否正确","error")}catch(N){console.error("Failed to parse URL:",N),V("链接格式错误,请检查是否为完整的 URL","error")}else if(m.platform==="gemini")try{const B=new URL(r).searchParams.get("code");B&&(A.value=B,V("成功提取授权码!","success"))}catch{}else V("请粘贴以 http://localhost:45462 开头的链接","error")});const D=async()=>{var v;S.value=!0;try{const r=(v=m.proxy)!=null&&v.enabled?{proxy:{type:m.proxy.type,host:m.proxy.host,port:parseInt(m.proxy.port),username:m.proxy.username||null,password:m.proxy.password||null}}:{};if(m.platform==="claude"){const R=await d.generateClaudeAuthUrl(r);C.value=R.authUrl,f.value=R.sessionId}else if(m.platform==="gemini"){const R=await d.generateGeminiAuthUrl(r);C.value=R.authUrl,f.value=R.sessionId}}catch(r){V(r.message||"生成授权链接失败","error")}finally{S.value=!1}},P=()=>{C.value="",A.value="",D()},_=async()=>{try{await navigator.clipboard.writeText(C.value),y.value=!0,V("链接已复制","success"),setTimeout(()=>{y.value=!1},2e3)}catch{const r=document.createElement("input");r.value=C.value,document.body.appendChild(r),r.select(),document.execCommand("copy"),document.body.removeChild(r),y.value=!0,V("链接已复制","success"),setTimeout(()=>{y.value=!1},2e3)}},s=async()=>{var v;if(M.value){I.value=!0;try{let r={};m.platform==="claude"?r={sessionId:f.value,callbackUrl:A.value.trim()}:m.platform==="gemini"&&(r={code:A.value.trim(),sessionId:f.value}),(v=m.proxy)!=null&&v.enabled&&(r.proxy={type:m.proxy.type,host:m.proxy.host,port:parseInt(m.proxy.port),username:m.proxy.username||null,password:m.proxy.password||null});let R;m.platform==="claude"?R=await d.exchangeClaudeCode(r):m.platform==="gemini"&&(R=await d.exchangeGeminiCode(r)),g("success",R)}catch(r){V(r.message||"授权失败,请检查授权码是否正确","error")}finally{I.value=!1}}};return(v,r)=>(i(),u("div",qe,[L.platform==="claude"?(i(),u("div",Be,[e("div",Ne,[e("div",Fe,[r[14]||(r[14]=e("div",{class:"w-10 h-10 bg-blue-500 rounded-lg flex items-center justify-center flex-shrink-0"},[e("i",{class:"fas fa-link text-white"})],-1)),e("div",He,[r[12]||(r[12]=e("h4",{class:"font-semibold text-blue-900 mb-3"}," Claude 账户授权 ",-1)),r[13]||(r[13]=e("p",{class:"text-sm text-blue-800 mb-4"}," 请按照以下步骤完成 Claude 账户的授权: ",-1)),e("div",_e,[e("div",Je,[e("div",Ye,[r[5]||(r[5]=e("div",{class:"w-6 h-6 bg-blue-600 text-white rounded-full flex items-center justify-center text-xs font-bold flex-shrink-0"}," 1 ",-1)),e("div",Qe,[r[4]||(r[4]=e("p",{class:"font-medium text-blue-900 mb-2"}," 点击下方按钮生成授权链接 ",-1)),C.value?(i(),u("div",tt,[e("div",st,[e("input",{type:"text",value:C.value,readonly:"",class:"form-input flex-1 text-xs font-mono bg-gray-50"},null,8,lt),e("button",{class:"px-3 py-2 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors",title:"复制链接",onClick:_},[e("i",{class:G(y.value?"fas fa-check text-green-500":"fas fa-copy")},null,2)])]),e("button",{class:"text-xs text-blue-600 hover:text-blue-700",onClick:P},r[3]||(r[3]=[e("i",{class:"fas fa-sync-alt mr-1"},null,-1),h("重新生成 ",-1)]))])):(i(),u("button",{key:0,disabled:S.value,class:"btn btn-primary px-4 py-2 text-sm",onClick:D},[S.value?(i(),u("div",et)):(i(),u("i",Ze)),h(" "+U(S.value?"生成中...":"生成授权链接"),1)],8,Xe))])])]),r[11]||(r[11]=te(' 2
在浏览器中打开链接并完成授权
请在新标签页中打开授权链接,登录您的 Claude 账户并授权。
注意:如果您设置了代理,请确保浏览器也使用相同的代理访问授权页面。
',1)),e("div",at,[e("div",ot,[r[10]||(r[10]=e("div",{class:"w-6 h-6 bg-blue-600 text-white rounded-full flex items-center justify-center text-xs font-bold flex-shrink-0"}," 3 ",-1)),e("div",nt,[r[8]||(r[8]=e("p",{class:"font-medium text-blue-900 mb-2"}," 输入 Authorization Code ",-1)),r[9]||(r[9]=e("p",{class:"text-sm text-blue-700 mb-3"},[h(" 授权完成后,页面会显示一个 "),e("strong",null,"Authorization Code"),h(",请将其复制并粘贴到下方输入框: ")],-1)),e("div",rt,[e("div",null,[r[6]||(r[6]=e("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},[e("i",{class:"fas fa-key text-blue-500 mr-2"}),h("Authorization Code ")],-1)),w(e("textarea",{"onUpdate:modelValue":r[0]||(r[0]=R=>A.value=R),rows:"3",class:"form-input w-full resize-none font-mono text-sm",placeholder:"粘贴从Claude页面获取的Authorization Code..."},null,512),[[j,A.value]])]),r[7]||(r[7]=e("p",{class:"text-xs text-gray-500 mt-2"},[e("i",{class:"fas fa-info-circle mr-1"}),h(" 请粘贴从Claude页面复制的Authorization Code ")],-1))])])])])])])])])])):L.platform==="gemini"?(i(),u("div",it,[e("div",ut,[e("div",dt,[r[26]||(r[26]=e("div",{class:"w-10 h-10 bg-green-500 rounded-lg flex items-center justify-center flex-shrink-0"},[e("i",{class:"fas fa-robot text-white"})],-1)),e("div",pt,[r[24]||(r[24]=e("h4",{class:"font-semibold text-green-900 mb-3"}," Gemini 账户授权 ",-1)),r[25]||(r[25]=e("p",{class:"text-sm text-green-800 mb-4"}," 请按照以下步骤完成 Gemini 账户的授权: ",-1)),e("div",ct,[e("div",mt,[e("div",ft,[r[17]||(r[17]=e("div",{class:"w-6 h-6 bg-green-600 text-white rounded-full flex items-center justify-center text-xs font-bold flex-shrink-0"}," 1 ",-1)),e("div",xt,[r[16]||(r[16]=e("p",{class:"font-medium text-green-900 mb-2"}," 点击下方按钮生成授权链接 ",-1)),C.value?(i(),u("div",bt,[e("div",wt,[e("input",{type:"text",value:C.value,readonly:"",class:"form-input flex-1 text-xs font-mono bg-gray-50"},null,8,kt),e("button",{class:"px-3 py-2 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors",title:"复制链接",onClick:_},[e("i",{class:G(y.value?"fas fa-check text-green-500":"fas fa-copy")},null,2)])]),e("button",{class:"text-xs text-green-600 hover:text-green-700",onClick:P},r[15]||(r[15]=[e("i",{class:"fas fa-sync-alt mr-1"},null,-1),h("重新生成 ",-1)]))])):(i(),u("button",{key:0,disabled:S.value,class:"btn btn-primary px-4 py-2 text-sm",onClick:D},[S.value?(i(),u("div",gt)):(i(),u("i",yt)),h(" "+U(S.value?"生成中...":"生成授权链接"),1)],8,vt))])])]),r[23]||(r[23]=te(' 2
在浏览器中打开链接并完成授权
- 点击上方的授权链接,在新页面中完成Google账号登录
- 点击“登录”按钮后可能会加载很慢(这是正常的)
- 如果超过1分钟还在加载,请按 F5 刷新页面
- 授权完成后会跳转到 http://localhost:45462 (可能显示无法访问)
提示:如果页面一直无法跳转,可以打开浏览器开发者工具(F12),F5刷新一下授权页再点击页面的登录按钮,在“网络”标签中找到以 localhost:45462 开头的请求,复制其完整URL。
',1)),e("div",ht,[e("div",$t,[r[22]||(r[22]=e("div",{class:"w-6 h-6 bg-green-600 text-white rounded-full flex items-center justify-center text-xs font-bold flex-shrink-0"}," 3 ",-1)),e("div",Ct,[r[20]||(r[20]=e("p",{class:"font-medium text-green-900 mb-2"}," 复制oauth后的链接 ",-1)),r[21]||(r[21]=e("p",{class:"text-sm text-green-700 mb-3"}," 复制浏览器地址栏的完整链接并粘贴到下方输入框: ",-1)),e("div",Tt,[e("div",null,[r[18]||(r[18]=e("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},[e("i",{class:"fas fa-key text-green-500 mr-2"}),h("复制oauth后的链接 ")],-1)),w(e("textarea",{"onUpdate:modelValue":r[1]||(r[1]=R=>A.value=R),rows:"3",class:"form-input w-full resize-none font-mono text-sm",placeholder:"粘贴以 http://localhost:45462 开头的完整链接..."},null,512),[[j,A.value]])]),r[19]||(r[19]=te(' 支持粘贴完整链接,系统会自动提取授权码
也可以直接粘贴授权码(code参数的值)
',1))])])])])])])])])])):$("",!0),e("div",At,[e("button",{type:"button",class:"flex-1 px-6 py-3 bg-gray-100 text-gray-700 rounded-xl font-semibold hover:bg-gray-200 transition-colors",onClick:r[2]||(r[2]=R=>v.$emit("back"))}," 上一步 "),e("button",{type:"button",disabled:!M.value||I.value,class:"btn btn-primary flex-1 py-3 px-6 font-semibold",onClick:s},[I.value?(i(),u("div",Vt)):$("",!0),h(" "+U(I.value?"验证中...":"完成授权"),1)],8,Ut)])]))}},jt={key:0,class:"fixed inset-0 modal z-50 flex items-center justify-center p-4"},St={class:"modal-content w-full max-w-md p-6 mx-auto"},Mt={class:"flex items-start gap-4 mb-6"},Kt={class:"flex-1"},Pt={class:"text-lg font-bold text-gray-900 mb-2"},Rt={class:"text-gray-600 text-sm leading-relaxed whitespace-pre-line"},Gt={class:"flex gap-3"},Ce={__name:"ConfirmModal",props:{show:{type:Boolean,required:!0},title:{type:String,default:""},message:{type:String,default:""},confirmText:{type:String,default:"继续"},cancelText:{type:String,default:"取消"}},emits:["confirm","cancel"],setup(L){return(E,m)=>(i(),le(ke,{to:"body"},[L.show?(i(),u("div",jt,[e("div",St,[e("div",Mt,[m[2]||(m[2]=e("div",{class:"w-12 h-12 bg-gradient-to-br from-yellow-400 to-yellow-500 rounded-full flex items-center justify-center flex-shrink-0"},[e("i",{class:"fas fa-exclamation text-white text-xl"})],-1)),e("div",Kt,[e("h3",Pt,U(L.title),1),e("p",Rt,U(L.message),1)])]),e("div",Gt,[e("button",{class:"flex-1 px-4 py-2.5 bg-gray-100 text-gray-700 rounded-xl font-medium hover:bg-gray-200 transition-colors",onClick:m[0]||(m[0]=g=>E.$emit("cancel"))},U(L.cancelText),1),e("button",{class:"flex-1 px-4 py-2.5 bg-gradient-to-r from-yellow-500 to-orange-500 text-white rounded-xl font-medium hover:from-yellow-600 hover:to-orange-600 transition-colors shadow-sm",onClick:m[1]||(m[1]=g=>E.$emit("confirm"))},U(L.confirmText),1)])])])):$("",!0)]))}},Lt={key:0,class:"fixed inset-0 modal z-50 flex items-center justify-center p-4"},Dt={class:"modal-content w-full max-w-2xl p-8 mx-auto max-h-[90vh] overflow-y-auto custom-scrollbar"},Ot={class:"flex items-center justify-between mb-6"},Et={class:"flex items-center gap-3"},zt={class:"text-xl font-bold text-gray-900"},Wt={key:0,class:"flex items-center justify-center mb-8"},qt={class:"flex items-center space-x-4"},Bt={class:"flex items-center"},Nt={class:"flex items-center"},Ft={key:1},Ht={class:"space-y-6"},_t={key:0},Jt={class:"flex gap-4"},Yt={class:"flex items-center cursor-pointer"},Qt={class:"flex items-center cursor-pointer"},Xt={class:"flex items-center cursor-pointer"},Zt={key:1},es={class:"flex gap-4"},ts={class:"flex items-center cursor-pointer"},ss={class:"flex items-center cursor-pointer"},ls={key:0,class:"text-red-500 text-xs mt-1"},as={class:"flex gap-4"},os={class:"flex items-center cursor-pointer"},ns={class:"flex items-center cursor-pointer"},rs={key:2},is={key:3,class:"space-y-4"},us={key:0,class:"text-red-500 text-xs mt-1"},ds={key:0,class:"text-red-500 text-xs mt-1"},ps={class:"mb-2 flex gap-2"},cs={key:4},ms={key:5,class:"space-y-4 bg-blue-50 p-4 rounded-lg border border-blue-200"},fs={class:"flex items-start gap-3 mb-4"},xs={key:0,class:"text-sm text-blue-800 mb-2"},vs={key:1,class:"text-sm text-blue-800 mb-2"},ys={class:"bg-white/80 rounded-lg p-3 mt-2 mb-2 border border-blue-300"},gs={key:0,class:"text-xs text-blue-800"},bs={key:1,class:"text-xs text-blue-800"},ws={key:0,class:"text-red-500 text-xs mt-1"},ks={class:"flex gap-3 pt-4"},hs=["disabled"],$s=["disabled"],Cs={key:0,class:"loading-spinner mr-2"},Ts={key:3,class:"space-y-6"},As={class:"flex gap-4"},Us={class:"flex items-center cursor-pointer"},Vs={class:"flex items-center cursor-pointer"},Is={key:0},js={key:1},Ss={key:2,class:"space-y-4"},Ms={class:"mb-2 flex gap-2"},Ks={key:3,class:"bg-amber-50 p-4 rounded-lg border border-amber-200"},Ps={class:"space-y-4"},Rs={class:"flex gap-3 pt-4"},Gs=["disabled"],Ls={key:0,class:"loading-spinner mr-2"},be={__name:"AccountForm",props:{account:{type:Object,default:null}},emits:["close","success"],setup(L,{emit:E}){var X,Z,ee,x,c,b,q,ae,p,l,o,k;const m=L,g=E,d=$e(),{showConfirmModal:S,confirmOptions:I,showConfirm:C,handleConfirm:A,handleCancel:y}=he(),f=se(()=>!!m.account),M=T(!0),D=T(1),P=T(!1),_=()=>{var n;return(n=m.account)!=null&&n.proxy&&m.account.proxy.host&&m.account.proxy.port?{enabled:!0,type:m.account.proxy.type||"socks5",host:m.account.proxy.host,port:m.account.proxy.port,username:m.account.proxy.username||"",password:m.account.proxy.password||""}:{enabled:!1,type:"socks5",host:"",port:"",username:"",password:""}},s=T({platform:((X=m.account)==null?void 0:X.platform)||"claude",addType:"oauth",name:((Z=m.account)==null?void 0:Z.name)||"",description:((ee=m.account)==null?void 0:ee.description)||"",accountType:((x=m.account)==null?void 0:x.accountType)||"shared",projectId:((c=m.account)==null?void 0:c.projectId)||"",accessToken:"",refreshToken:"",proxy:_(),apiUrl:((b=m.account)==null?void 0:b.apiUrl)||"",apiKey:((q=m.account)==null?void 0:q.apiKey)||"",priority:((ae=m.account)==null?void 0:ae.priority)||50,supportedModels:((l=(p=m.account)==null?void 0:p.supportedModels)==null?void 0:l.join(`
+import{r as T,aR as Te,o as O,V as Ae,x as u,y as i,z as e,L as $,K as w,al as xe,aY as te,aX as we,aq as j,aZ as Ue,C as G,O as h,c as se,P as U,I as le,a5 as ke,R as ne,an as H,u as W,q as Ve,Y as Ie,Q as je,ac as Se,B as ve}from"./vue-vendor-CKToUHZx.js";import{s as V}from"./toast-BvwA7Mwb.js";import{a as K,_ as Me}from"./index-HYE9xPuR.js";import"./element-plus-B8Fs_0jW.js";import"./vendor-BDiMbLwQ.js";const oe=T(!1),ye=T({title:"",message:"",confirmText:"继续",cancelText:"取消"}),J=T(null);function he(){return{showConfirmModal:oe,confirmOptions:ye,showConfirm:(g,d,S="继续",I="取消")=>new Promise(C=>{ye.value={title:g,message:d,confirmText:S,cancelText:I},J.value=C,oe.value=!0}),handleConfirm:()=>{oe.value=!1,J.value&&(J.value(!0),J.value=null)},handleCancel:()=>{oe.value=!1,J.value&&(J.value(!1),J.value=null)}}}const $e=Te("accounts",()=>{const L=T([]),E=T([]),m=T([]),g=T(!1),d=T(null),S=T(""),I=T("asc"),C=async()=>{g.value=!0,d.value=null;try{const x=await K.get("/admin/claude-accounts");if(x.success)L.value=x.data||[];else throw new Error(x.message||"获取Claude账户失败")}catch(x){throw d.value=x.message,x}finally{g.value=!1}},A=async()=>{g.value=!0,d.value=null;try{const x=await K.get("/admin/claude-console-accounts");if(x.success)E.value=x.data||[];else throw new Error(x.message||"获取Claude Console账户失败")}catch(x){throw d.value=x.message,x}finally{g.value=!1}},y=async()=>{g.value=!0,d.value=null;try{const x=await K.get("/admin/gemini-accounts");if(x.success)m.value=x.data||[];else throw new Error(x.message||"获取Gemini账户失败")}catch(x){throw d.value=x.message,x}finally{g.value=!1}};return{claudeAccounts:L,claudeConsoleAccounts:E,geminiAccounts:m,loading:g,error:d,sortBy:S,sortOrder:I,fetchClaudeAccounts:C,fetchClaudeConsoleAccounts:A,fetchGeminiAccounts:y,fetchAllAccounts:async()=>{g.value=!0,d.value=null;try{await Promise.all([C(),A(),y()])}catch(x){throw d.value=x.message,x}finally{g.value=!1}},createClaudeAccount:async x=>{g.value=!0,d.value=null;try{const c=await K.post("/admin/claude-accounts",x);if(c.success)return await C(),c.data;throw new Error(c.message||"创建Claude账户失败")}catch(c){throw d.value=c.message,c}finally{g.value=!1}},createClaudeConsoleAccount:async x=>{g.value=!0,d.value=null;try{const c=await K.post("/admin/claude-console-accounts",x);if(c.success)return await A(),c.data;throw new Error(c.message||"创建Claude Console账户失败")}catch(c){throw d.value=c.message,c}finally{g.value=!1}},createGeminiAccount:async x=>{g.value=!0,d.value=null;try{const c=await K.post("/admin/gemini-accounts",x);if(c.success)return await y(),c.data;throw new Error(c.message||"创建Gemini账户失败")}catch(c){throw d.value=c.message,c}finally{g.value=!1}},updateClaudeAccount:async(x,c)=>{g.value=!0,d.value=null;try{const b=await K.put(`/admin/claude-accounts/${x}`,c);if(b.success)return await C(),b;throw new Error(b.message||"更新Claude账户失败")}catch(b){throw d.value=b.message,b}finally{g.value=!1}},updateClaudeConsoleAccount:async(x,c)=>{g.value=!0,d.value=null;try{const b=await K.put(`/admin/claude-console-accounts/${x}`,c);if(b.success)return await A(),b;throw new Error(b.message||"更新Claude Console账户失败")}catch(b){throw d.value=b.message,b}finally{g.value=!1}},updateGeminiAccount:async(x,c)=>{g.value=!0,d.value=null;try{const b=await K.put(`/admin/gemini-accounts/${x}`,c);if(b.success)return await y(),b;throw new Error(b.message||"更新Gemini账户失败")}catch(b){throw d.value=b.message,b}finally{g.value=!1}},toggleAccount:async(x,c)=>{g.value=!0,d.value=null;try{let b;x==="claude"?b=`/admin/claude-accounts/${c}/toggle`:x==="claude-console"?b=`/admin/claude-console-accounts/${c}/toggle`:b=`/admin/gemini-accounts/${c}/toggle`;const q=await K.put(b);if(q.success)return x==="claude"?await C():x==="claude-console"?await A():await y(),q;throw new Error(q.message||"切换状态失败")}catch(b){throw d.value=b.message,b}finally{g.value=!1}},deleteAccount:async(x,c)=>{g.value=!0,d.value=null;try{let b;x==="claude"?b=`/admin/claude-accounts/${c}`:x==="claude-console"?b=`/admin/claude-console-accounts/${c}`:b=`/admin/gemini-accounts/${c}`;const q=await K.delete(b);if(q.success)return x==="claude"?await C():x==="claude-console"?await A():await y(),q;throw new Error(q.message||"删除失败")}catch(b){throw d.value=b.message,b}finally{g.value=!1}},refreshClaudeToken:async x=>{g.value=!0,d.value=null;try{const c=await K.post(`/admin/claude-accounts/${x}/refresh`);if(c.success)return await C(),c;throw new Error(c.message||"Token刷新失败")}catch(c){throw d.value=c.message,c}finally{g.value=!1}},generateClaudeAuthUrl:async x=>{try{const c=await K.post("/admin/claude-accounts/generate-auth-url",x);if(c.success)return c.data;throw new Error(c.message||"生成授权URL失败")}catch(c){throw d.value=c.message,c}},exchangeClaudeCode:async x=>{try{const c=await K.post("/admin/claude-accounts/exchange-code",x);if(c.success)return c.data;throw new Error(c.message||"交换授权码失败")}catch(c){throw d.value=c.message,c}},generateGeminiAuthUrl:async x=>{try{const c=await K.post("/admin/gemini-accounts/generate-auth-url",x);if(c.success)return c.data;throw new Error(c.message||"生成授权URL失败")}catch(c){throw d.value=c.message,c}},exchangeGeminiCode:async x=>{try{const c=await K.post("/admin/gemini-accounts/exchange-code",x);if(c.success)return c.data;throw new Error(c.message||"交换授权码失败")}catch(c){throw d.value=c.message,c}},sortAccounts:x=>{S.value===x?I.value=I.value==="asc"?"desc":"asc":(S.value=x,I.value="asc")},reset:()=>{L.value=[],E.value=[],m.value=[],g.value=!1,d.value=null,S.value="",I.value="asc"}}}),Ke={class:"space-y-4"},Pe={class:"flex items-center justify-between"},Re={class:"flex items-center cursor-pointer"},Ge={key:0,class:"bg-gray-50 p-4 rounded-lg border border-gray-200 space-y-4"},Le={class:"grid grid-cols-2 gap-4"},De={class:"space-y-4"},Oe={class:"flex items-center"},Ee={key:0,class:"grid grid-cols-2 gap-4"},ze={class:"relative"},We=["type"],ge={__name:"ProxyConfig",props:{modelValue:{type:Object,default:()=>({enabled:!1,type:"socks5",host:"",port:"",username:"",password:""})}},emits:["update:modelValue"],setup(L,{emit:E}){const m=L,g=E,d=T({...m.modelValue}),S=T(!!(d.value.username||d.value.password)),I=T(!1);O(()=>m.modelValue,y=>{JSON.stringify(y)!==JSON.stringify(d.value)&&(d.value={...y},S.value=!!(y.username||y.password))},{deep:!0}),O(()=>d.value.enabled,y=>{A()}),O(()=>d.value.type,y=>{A()}),O(()=>d.value.host,y=>{A()}),O(()=>d.value.port,y=>{A()}),O(()=>d.value.username,y=>{A()}),O(()=>d.value.password,y=>{A()}),O(S,y=>{y||(d.value.username="",d.value.password="",A())});let C=null;function A(){C&&clearTimeout(C),C=setTimeout(()=>{const y={...d.value};S.value||(y.username="",y.password=""),g("update:modelValue",y)},100)}return Ae(()=>{C&&clearTimeout(C)}),(y,f)=>(i(),u("div",Ke,[e("div",Pe,[f[9]||(f[9]=e("h4",{class:"text-sm font-semibold text-gray-700"}," 代理设置 (可选) ",-1)),e("label",Re,[w(e("input",{"onUpdate:modelValue":f[0]||(f[0]=M=>d.value.enabled=M),type:"checkbox",class:"w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500"},null,512),[[xe,d.value.enabled]]),f[8]||(f[8]=e("span",{class:"ml-2 text-sm text-gray-700"},"启用代理",-1))])]),d.value.enabled?(i(),u("div",Ge,[f[17]||(f[17]=te('
配置代理以访问受限的网络资源。支持 SOCKS5 和 HTTP 代理。
请确保代理服务器稳定可用,否则会影响账户的正常使用。
',1)),e("div",null,[f[11]||(f[11]=e("label",{class:"block text-sm font-medium text-gray-700 mb-2"},"代理类型",-1)),w(e("select",{"onUpdate:modelValue":f[1]||(f[1]=M=>d.value.type=M),class:"form-input w-full"},f[10]||(f[10]=[e("option",{value:"socks5"}," SOCKS5 ",-1),e("option",{value:"http"}," HTTP ",-1),e("option",{value:"https"}," HTTPS ",-1)]),512),[[we,d.value.type]])]),e("div",Le,[e("div",null,[f[12]||(f[12]=e("label",{class:"block text-sm font-medium text-gray-700 mb-2"},"主机地址",-1)),w(e("input",{"onUpdate:modelValue":f[2]||(f[2]=M=>d.value.host=M),type:"text",placeholder:"例如: 192.168.1.100",class:"form-input w-full"},null,512),[[j,d.value.host]])]),e("div",null,[f[13]||(f[13]=e("label",{class:"block text-sm font-medium text-gray-700 mb-2"},"端口",-1)),w(e("input",{"onUpdate:modelValue":f[3]||(f[3]=M=>d.value.port=M),type:"number",placeholder:"例如: 1080",class:"form-input w-full"},null,512),[[j,d.value.port]])])]),e("div",De,[e("div",Oe,[w(e("input",{id:"proxyAuth","onUpdate:modelValue":f[4]||(f[4]=M=>S.value=M),type:"checkbox",class:"w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500"},null,512),[[xe,S.value]]),f[14]||(f[14]=e("label",{for:"proxyAuth",class:"ml-2 text-sm text-gray-700 cursor-pointer"}," 需要身份验证 ",-1))]),S.value?(i(),u("div",Ee,[e("div",null,[f[15]||(f[15]=e("label",{class:"block text-sm font-medium text-gray-700 mb-2"},"用户名",-1)),w(e("input",{"onUpdate:modelValue":f[5]||(f[5]=M=>d.value.username=M),type:"text",placeholder:"代理用户名",class:"form-input w-full"},null,512),[[j,d.value.username]])]),e("div",null,[f[16]||(f[16]=e("label",{class:"block text-sm font-medium text-gray-700 mb-2"},"密码",-1)),e("div",ze,[w(e("input",{"onUpdate:modelValue":f[6]||(f[6]=M=>d.value.password=M),type:I.value?"text":"password",placeholder:"代理密码",class:"form-input w-full pr-10"},null,8,We),[[Ue,d.value.password]]),e("button",{type:"button",class:"absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-gray-600",onClick:f[7]||(f[7]=M=>I.value=!I.value)},[e("i",{class:G(I.value?"fas fa-eye-slash":"fas fa-eye")},null,2)])])])])):$("",!0)]),f[18]||(f[18]=e("div",{class:"bg-blue-50 p-3 rounded-lg border border-blue-200"},[e("p",{class:"text-xs text-blue-700"},[e("i",{class:"fas fa-info-circle mr-1"}),e("strong",null,"提示:"),h("代理设置将用于所有与此账户相关的API请求。请确保代理服务器支持HTTPS流量转发。 ")])],-1))])):$("",!0)]))}},qe={class:"space-y-6"},Be={key:0},Ne={class:"bg-blue-50 p-6 rounded-lg border border-blue-200"},Fe={class:"flex items-start gap-4"},He={class:"flex-1"},_e={class:"space-y-4"},Je={class:"bg-white/80 rounded-lg p-4 border border-blue-300"},Ye={class:"flex items-start gap-3"},Qe={class:"flex-1"},Xe=["disabled"],Ze={key:0,class:"fas fa-link mr-2"},et={key:1,class:"loading-spinner mr-2"},tt={key:1,class:"space-y-3"},st={class:"flex items-center gap-2"},lt=["value"],at={class:"bg-white/80 rounded-lg p-4 border border-blue-300"},ot={class:"flex items-start gap-3"},nt={class:"flex-1"},rt={class:"space-y-3"},it={key:1},ut={class:"bg-green-50 p-6 rounded-lg border border-green-200"},dt={class:"flex items-start gap-4"},pt={class:"flex-1"},ct={class:"space-y-4"},mt={class:"bg-white/80 rounded-lg p-4 border border-green-300"},ft={class:"flex items-start gap-3"},xt={class:"flex-1"},vt=["disabled"],yt={key:0,class:"fas fa-link mr-2"},gt={key:1,class:"loading-spinner mr-2"},bt={key:1,class:"space-y-3"},wt={class:"flex items-center gap-2"},kt=["value"],ht={class:"bg-white/80 rounded-lg p-4 border border-green-300"},$t={class:"flex items-start gap-3"},Ct={class:"flex-1"},Tt={class:"space-y-3"},At={class:"flex gap-3 pt-4"},Ut=["disabled"],Vt={key:0,class:"loading-spinner mr-2"},It={__name:"OAuthFlow",props:{platform:{type:String,required:!0},proxy:{type:Object,default:null}},emits:["success","back"],setup(L,{emit:E}){const m=L,g=E,d=$e(),S=T(!1),I=T(!1),C=T(""),A=T(""),y=T(!1),f=T(""),M=se(()=>C.value&&A.value.trim());O(A,v=>{if(!v||typeof v!="string")return;const r=v.trim();if(!r)return;if(r.startsWith("http://")||r.startsWith("https://"))if(r.startsWith("http://localhost:45462"))try{const B=new URL(r).searchParams.get("code");B?(A.value=B,V("成功提取授权码!","success"),console.log("Successfully extracted authorization code from URL")):V("URL 中未找到授权码参数,请检查链接是否正确","error")}catch(N){console.error("Failed to parse URL:",N),V("链接格式错误,请检查是否为完整的 URL","error")}else if(m.platform==="gemini")try{const B=new URL(r).searchParams.get("code");B&&(A.value=B,V("成功提取授权码!","success"))}catch{}else V("请粘贴以 http://localhost:45462 开头的链接","error")});const D=async()=>{var v;S.value=!0;try{const r=(v=m.proxy)!=null&&v.enabled?{proxy:{type:m.proxy.type,host:m.proxy.host,port:parseInt(m.proxy.port),username:m.proxy.username||null,password:m.proxy.password||null}}:{};if(m.platform==="claude"){const R=await d.generateClaudeAuthUrl(r);C.value=R.authUrl,f.value=R.sessionId}else if(m.platform==="gemini"){const R=await d.generateGeminiAuthUrl(r);C.value=R.authUrl,f.value=R.sessionId}}catch(r){V(r.message||"生成授权链接失败","error")}finally{S.value=!1}},P=()=>{C.value="",A.value="",D()},_=async()=>{try{await navigator.clipboard.writeText(C.value),y.value=!0,V("链接已复制","success"),setTimeout(()=>{y.value=!1},2e3)}catch{const r=document.createElement("input");r.value=C.value,document.body.appendChild(r),r.select(),document.execCommand("copy"),document.body.removeChild(r),y.value=!0,V("链接已复制","success"),setTimeout(()=>{y.value=!1},2e3)}},s=async()=>{var v;if(M.value){I.value=!0;try{let r={};m.platform==="claude"?r={sessionId:f.value,callbackUrl:A.value.trim()}:m.platform==="gemini"&&(r={code:A.value.trim(),sessionId:f.value}),(v=m.proxy)!=null&&v.enabled&&(r.proxy={type:m.proxy.type,host:m.proxy.host,port:parseInt(m.proxy.port),username:m.proxy.username||null,password:m.proxy.password||null});let R;m.platform==="claude"?R=await d.exchangeClaudeCode(r):m.platform==="gemini"&&(R=await d.exchangeGeminiCode(r)),g("success",R)}catch(r){V(r.message||"授权失败,请检查授权码是否正确","error")}finally{I.value=!1}}};return(v,r)=>(i(),u("div",qe,[L.platform==="claude"?(i(),u("div",Be,[e("div",Ne,[e("div",Fe,[r[14]||(r[14]=e("div",{class:"w-10 h-10 bg-blue-500 rounded-lg flex items-center justify-center flex-shrink-0"},[e("i",{class:"fas fa-link text-white"})],-1)),e("div",He,[r[12]||(r[12]=e("h4",{class:"font-semibold text-blue-900 mb-3"}," Claude 账户授权 ",-1)),r[13]||(r[13]=e("p",{class:"text-sm text-blue-800 mb-4"}," 请按照以下步骤完成 Claude 账户的授权: ",-1)),e("div",_e,[e("div",Je,[e("div",Ye,[r[5]||(r[5]=e("div",{class:"w-6 h-6 bg-blue-600 text-white rounded-full flex items-center justify-center text-xs font-bold flex-shrink-0"}," 1 ",-1)),e("div",Qe,[r[4]||(r[4]=e("p",{class:"font-medium text-blue-900 mb-2"}," 点击下方按钮生成授权链接 ",-1)),C.value?(i(),u("div",tt,[e("div",st,[e("input",{type:"text",value:C.value,readonly:"",class:"form-input flex-1 text-xs font-mono bg-gray-50"},null,8,lt),e("button",{class:"px-3 py-2 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors",title:"复制链接",onClick:_},[e("i",{class:G(y.value?"fas fa-check text-green-500":"fas fa-copy")},null,2)])]),e("button",{class:"text-xs text-blue-600 hover:text-blue-700",onClick:P},r[3]||(r[3]=[e("i",{class:"fas fa-sync-alt mr-1"},null,-1),h("重新生成 ",-1)]))])):(i(),u("button",{key:0,disabled:S.value,class:"btn btn-primary px-4 py-2 text-sm",onClick:D},[S.value?(i(),u("div",et)):(i(),u("i",Ze)),h(" "+U(S.value?"生成中...":"生成授权链接"),1)],8,Xe))])])]),r[11]||(r[11]=te(' 2
在浏览器中打开链接并完成授权
请在新标签页中打开授权链接,登录您的 Claude 账户并授权。
注意:如果您设置了代理,请确保浏览器也使用相同的代理访问授权页面。
',1)),e("div",at,[e("div",ot,[r[10]||(r[10]=e("div",{class:"w-6 h-6 bg-blue-600 text-white rounded-full flex items-center justify-center text-xs font-bold flex-shrink-0"}," 3 ",-1)),e("div",nt,[r[8]||(r[8]=e("p",{class:"font-medium text-blue-900 mb-2"}," 输入 Authorization Code ",-1)),r[9]||(r[9]=e("p",{class:"text-sm text-blue-700 mb-3"},[h(" 授权完成后,页面会显示一个 "),e("strong",null,"Authorization Code"),h(",请将其复制并粘贴到下方输入框: ")],-1)),e("div",rt,[e("div",null,[r[6]||(r[6]=e("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},[e("i",{class:"fas fa-key text-blue-500 mr-2"}),h("Authorization Code ")],-1)),w(e("textarea",{"onUpdate:modelValue":r[0]||(r[0]=R=>A.value=R),rows:"3",class:"form-input w-full resize-none font-mono text-sm",placeholder:"粘贴从Claude页面获取的Authorization Code..."},null,512),[[j,A.value]])]),r[7]||(r[7]=e("p",{class:"text-xs text-gray-500 mt-2"},[e("i",{class:"fas fa-info-circle mr-1"}),h(" 请粘贴从Claude页面复制的Authorization Code ")],-1))])])])])])])])])])):L.platform==="gemini"?(i(),u("div",it,[e("div",ut,[e("div",dt,[r[26]||(r[26]=e("div",{class:"w-10 h-10 bg-green-500 rounded-lg flex items-center justify-center flex-shrink-0"},[e("i",{class:"fas fa-robot text-white"})],-1)),e("div",pt,[r[24]||(r[24]=e("h4",{class:"font-semibold text-green-900 mb-3"}," Gemini 账户授权 ",-1)),r[25]||(r[25]=e("p",{class:"text-sm text-green-800 mb-4"}," 请按照以下步骤完成 Gemini 账户的授权: ",-1)),e("div",ct,[e("div",mt,[e("div",ft,[r[17]||(r[17]=e("div",{class:"w-6 h-6 bg-green-600 text-white rounded-full flex items-center justify-center text-xs font-bold flex-shrink-0"}," 1 ",-1)),e("div",xt,[r[16]||(r[16]=e("p",{class:"font-medium text-green-900 mb-2"}," 点击下方按钮生成授权链接 ",-1)),C.value?(i(),u("div",bt,[e("div",wt,[e("input",{type:"text",value:C.value,readonly:"",class:"form-input flex-1 text-xs font-mono bg-gray-50"},null,8,kt),e("button",{class:"px-3 py-2 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors",title:"复制链接",onClick:_},[e("i",{class:G(y.value?"fas fa-check text-green-500":"fas fa-copy")},null,2)])]),e("button",{class:"text-xs text-green-600 hover:text-green-700",onClick:P},r[15]||(r[15]=[e("i",{class:"fas fa-sync-alt mr-1"},null,-1),h("重新生成 ",-1)]))])):(i(),u("button",{key:0,disabled:S.value,class:"btn btn-primary px-4 py-2 text-sm",onClick:D},[S.value?(i(),u("div",gt)):(i(),u("i",yt)),h(" "+U(S.value?"生成中...":"生成授权链接"),1)],8,vt))])])]),r[23]||(r[23]=te(' 2
在浏览器中打开链接并完成授权
- 点击上方的授权链接,在新页面中完成Google账号登录
- 点击“登录”按钮后可能会加载很慢(这是正常的)
- 如果超过1分钟还在加载,请按 F5 刷新页面
- 授权完成后会跳转到 http://localhost:45462 (可能显示无法访问)
提示:如果页面一直无法跳转,可以打开浏览器开发者工具(F12),F5刷新一下授权页再点击页面的登录按钮,在“网络”标签中找到以 localhost:45462 开头的请求,复制其完整URL。
',1)),e("div",ht,[e("div",$t,[r[22]||(r[22]=e("div",{class:"w-6 h-6 bg-green-600 text-white rounded-full flex items-center justify-center text-xs font-bold flex-shrink-0"}," 3 ",-1)),e("div",Ct,[r[20]||(r[20]=e("p",{class:"font-medium text-green-900 mb-2"}," 复制oauth后的链接 ",-1)),r[21]||(r[21]=e("p",{class:"text-sm text-green-700 mb-3"}," 复制浏览器地址栏的完整链接并粘贴到下方输入框: ",-1)),e("div",Tt,[e("div",null,[r[18]||(r[18]=e("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},[e("i",{class:"fas fa-key text-green-500 mr-2"}),h("复制oauth后的链接 ")],-1)),w(e("textarea",{"onUpdate:modelValue":r[1]||(r[1]=R=>A.value=R),rows:"3",class:"form-input w-full resize-none font-mono text-sm",placeholder:"粘贴以 http://localhost:45462 开头的完整链接..."},null,512),[[j,A.value]])]),r[19]||(r[19]=te(' 支持粘贴完整链接,系统会自动提取授权码
也可以直接粘贴授权码(code参数的值)
',1))])])])])])])])])])):$("",!0),e("div",At,[e("button",{type:"button",class:"flex-1 px-6 py-3 bg-gray-100 text-gray-700 rounded-xl font-semibold hover:bg-gray-200 transition-colors",onClick:r[2]||(r[2]=R=>v.$emit("back"))}," 上一步 "),e("button",{type:"button",disabled:!M.value||I.value,class:"btn btn-primary flex-1 py-3 px-6 font-semibold",onClick:s},[I.value?(i(),u("div",Vt)):$("",!0),h(" "+U(I.value?"验证中...":"完成授权"),1)],8,Ut)])]))}},jt={key:0,class:"fixed inset-0 modal z-50 flex items-center justify-center p-4"},St={class:"modal-content w-full max-w-md p-6 mx-auto"},Mt={class:"flex items-start gap-4 mb-6"},Kt={class:"flex-1"},Pt={class:"text-lg font-bold text-gray-900 mb-2"},Rt={class:"text-gray-600 text-sm leading-relaxed whitespace-pre-line"},Gt={class:"flex gap-3"},Ce={__name:"ConfirmModal",props:{show:{type:Boolean,required:!0},title:{type:String,default:""},message:{type:String,default:""},confirmText:{type:String,default:"继续"},cancelText:{type:String,default:"取消"}},emits:["confirm","cancel"],setup(L){return(E,m)=>(i(),le(ke,{to:"body"},[L.show?(i(),u("div",jt,[e("div",St,[e("div",Mt,[m[2]||(m[2]=e("div",{class:"w-12 h-12 bg-gradient-to-br from-yellow-400 to-yellow-500 rounded-full flex items-center justify-center flex-shrink-0"},[e("i",{class:"fas fa-exclamation text-white text-xl"})],-1)),e("div",Kt,[e("h3",Pt,U(L.title),1),e("p",Rt,U(L.message),1)])]),e("div",Gt,[e("button",{class:"flex-1 px-4 py-2.5 bg-gray-100 text-gray-700 rounded-xl font-medium hover:bg-gray-200 transition-colors",onClick:m[0]||(m[0]=g=>E.$emit("cancel"))},U(L.cancelText),1),e("button",{class:"flex-1 px-4 py-2.5 bg-gradient-to-r from-yellow-500 to-orange-500 text-white rounded-xl font-medium hover:from-yellow-600 hover:to-orange-600 transition-colors shadow-sm",onClick:m[1]||(m[1]=g=>E.$emit("confirm"))},U(L.confirmText),1)])])])):$("",!0)]))}},Lt={key:0,class:"fixed inset-0 modal z-50 flex items-center justify-center p-4"},Dt={class:"modal-content w-full max-w-2xl p-8 mx-auto max-h-[90vh] overflow-y-auto custom-scrollbar"},Ot={class:"flex items-center justify-between mb-6"},Et={class:"flex items-center gap-3"},zt={class:"text-xl font-bold text-gray-900"},Wt={key:0,class:"flex items-center justify-center mb-8"},qt={class:"flex items-center space-x-4"},Bt={class:"flex items-center"},Nt={class:"flex items-center"},Ft={key:1},Ht={class:"space-y-6"},_t={key:0},Jt={class:"flex gap-4"},Yt={class:"flex items-center cursor-pointer"},Qt={class:"flex items-center cursor-pointer"},Xt={class:"flex items-center cursor-pointer"},Zt={key:1},es={class:"flex gap-4"},ts={class:"flex items-center cursor-pointer"},ss={class:"flex items-center cursor-pointer"},ls={key:0,class:"text-red-500 text-xs mt-1"},as={class:"flex gap-4"},os={class:"flex items-center cursor-pointer"},ns={class:"flex items-center cursor-pointer"},rs={key:2},is={key:3,class:"space-y-4"},us={key:0,class:"text-red-500 text-xs mt-1"},ds={key:0,class:"text-red-500 text-xs mt-1"},ps={class:"mb-2 flex gap-2"},cs={key:4},ms={key:5,class:"space-y-4 bg-blue-50 p-4 rounded-lg border border-blue-200"},fs={class:"flex items-start gap-3 mb-4"},xs={key:0,class:"text-sm text-blue-800 mb-2"},vs={key:1,class:"text-sm text-blue-800 mb-2"},ys={class:"bg-white/80 rounded-lg p-3 mt-2 mb-2 border border-blue-300"},gs={key:0,class:"text-xs text-blue-800"},bs={key:1,class:"text-xs text-blue-800"},ws={key:0,class:"text-red-500 text-xs mt-1"},ks={class:"flex gap-3 pt-4"},hs=["disabled"],$s=["disabled"],Cs={key:0,class:"loading-spinner mr-2"},Ts={key:3,class:"space-y-6"},As={class:"flex gap-4"},Us={class:"flex items-center cursor-pointer"},Vs={class:"flex items-center cursor-pointer"},Is={key:0},js={key:1},Ss={key:2,class:"space-y-4"},Ms={class:"mb-2 flex gap-2"},Ks={key:3,class:"bg-amber-50 p-4 rounded-lg border border-amber-200"},Ps={class:"space-y-4"},Rs={class:"flex gap-3 pt-4"},Gs=["disabled"],Ls={key:0,class:"loading-spinner mr-2"},be={__name:"AccountForm",props:{account:{type:Object,default:null}},emits:["close","success"],setup(L,{emit:E}){var X,Z,ee,x,c,b,q,ae,p,l,o,k;const m=L,g=E,d=$e(),{showConfirmModal:S,confirmOptions:I,showConfirm:C,handleConfirm:A,handleCancel:y}=he(),f=se(()=>!!m.account),M=T(!0),D=T(1),P=T(!1),_=()=>{var n;return(n=m.account)!=null&&n.proxy&&m.account.proxy.host&&m.account.proxy.port?{enabled:!0,type:m.account.proxy.type||"socks5",host:m.account.proxy.host,port:m.account.proxy.port,username:m.account.proxy.username||"",password:m.account.proxy.password||""}:{enabled:!1,type:"socks5",host:"",port:"",username:"",password:""}},s=T({platform:((X=m.account)==null?void 0:X.platform)||"claude",addType:"oauth",name:((Z=m.account)==null?void 0:Z.name)||"",description:((ee=m.account)==null?void 0:ee.description)||"",accountType:((x=m.account)==null?void 0:x.accountType)||"shared",projectId:((c=m.account)==null?void 0:c.projectId)||"",accessToken:"",refreshToken:"",proxy:_(),apiUrl:((b=m.account)==null?void 0:b.apiUrl)||"",apiKey:((q=m.account)==null?void 0:q.apiKey)||"",priority:((ae=m.account)==null?void 0:ae.priority)||50,supportedModels:((l=(p=m.account)==null?void 0:p.supportedModels)==null?void 0:l.join(`
`))||"",userAgent:((o=m.account)==null?void 0:o.userAgent)||"",rateLimitDuration:((k=m.account)==null?void 0:k.rateLimitDuration)||60}),v=T({name:"",accessToken:"",apiUrl:"",apiKey:""}),r=se(()=>{var n;return((n=s.value.name)==null?void 0:n.trim())&&s.value.platform});se(()=>{var n,t,a;return s.value.addType==="manual"?((n=s.value.name)==null?void 0:n.trim())&&((t=s.value.accessToken)==null?void 0:t.trim()):(a=s.value.name)==null?void 0:a.trim()});const R=async()=>{if(v.value.name="",!r.value){(!s.value.name||s.value.name.trim()==="")&&(v.value.name="请填写账户名称");return}s.value.platform==="gemini"&&D.value===1&&s.value.addType==="oauth"&&(!s.value.projectId||s.value.projectId.trim()==="")&&!await C("项目编号未填写",`您尚未填写项目编号。
如果您的Google账号绑定了Google Cloud或被识别为Workspace账号,需要提供项目编号。
diff --git a/web/admin-spa/dist/assets/ApiKeysView-DagFDYhj.js b/web/admin-spa/dist/assets/ApiKeysView-BwqhkYtq.js
similarity index 62%
rename from web/admin-spa/dist/assets/ApiKeysView-DagFDYhj.js
rename to web/admin-spa/dist/assets/ApiKeysView-BwqhkYtq.js
index 8e52ad61..6ab2123a 100644
--- a/web/admin-spa/dist/assets/ApiKeysView-DagFDYhj.js
+++ b/web/admin-spa/dist/assets/ApiKeysView-BwqhkYtq.js
@@ -1,4 +1,4 @@
-import{E as St}from"./element-plus-B8Fs_0jW.js";import{aR as ft,r as A,c as tt,_ as rt,q as dt,I as B,y as i,z as t,Y as Q,K as $,x as a,L as K,O as f,aq as E,C as F,P as u,Q as V,ac as q,aa as nt,aX as H,an as J,al as Z,a5 as ot,R as Tt,B as _t}from"./vue-vendor-CKToUHZx.js";import{s as S}from"./toast-BvwA7Mwb.js";import{a as U,_ as et,u as ut}from"./index-D7YURYF2.js";import"./vendor-BDiMbLwQ.js";const mt=ft("clients",{state:()=>({supportedClients:[],loading:!1,error:null}),actions:{async loadSupportedClients(){if(this.supportedClients.length>0)return this.supportedClients;this.loading=!0,this.error=null;try{const L=await U.get("/admin/supported-clients");return L.success?this.supportedClients=L.data||[]:(this.error=L.message||"加载支持的客户端失败",console.error("Failed to load supported clients:",this.error)),this.supportedClients}catch(L){return this.error=L.message||"加载支持的客户端失败",console.error("Error loading supported clients:",L),[]}finally{this.loading=!1}}}}),bt=ft("apiKeys",()=>{const L=A([]),R=A(!1),c=A(null),_=A("all"),M=A(""),y=A("asc"),k=async()=>{R.value=!0,c.value=null;try{const b=await U.get("/admin/api-keys");if(b.success)L.value=b.data||[];else throw new Error(b.message||"获取API Keys失败")}catch(b){throw c.value=b.message,b}finally{R.value=!1}};return{apiKeys:L,loading:R,error:c,statsTimeRange:_,sortBy:M,sortOrder:y,fetchApiKeys:k,createApiKey:async b=>{R.value=!0,c.value=null;try{const h=await U.post("/admin/api-keys",b);if(h.success)return await k(),h.data;throw new Error(h.message||"创建API Key失败")}catch(h){throw c.value=h.message,h}finally{R.value=!1}},updateApiKey:async(b,h)=>{R.value=!0,c.value=null;try{const g=await U.put(`/admin/api-keys/${b}`,h);if(g.success)return await k(),g;throw new Error(g.message||"更新API Key失败")}catch(g){throw c.value=g.message,g}finally{R.value=!1}},toggleApiKey:async b=>{R.value=!0,c.value=null;try{const h=await U.put(`/admin/api-keys/${b}/toggle`);if(h.success)return await k(),h;throw new Error(h.message||"切换状态失败")}catch(h){throw c.value=h.message,h}finally{R.value=!1}},renewApiKey:async(b,h)=>{R.value=!0,c.value=null;try{const g=await U.put(`/admin/api-keys/${b}/renew`,h);if(g.success)return await k(),g;throw new Error(g.message||"续期失败")}catch(g){throw c.value=g.message,g}finally{R.value=!1}},deleteApiKey:async b=>{R.value=!0,c.value=null;try{const h=await U.delete(`/admin/api-keys/${b}`);if(h.success)return await k(),h;throw new Error(h.message||"删除失败")}catch(h){throw c.value=h.message,h}finally{R.value=!1}},fetchApiKeyStats:async(b,h="all")=>{try{const g=await U.get(`/admin/api-keys/${b}/stats`,{params:{timeRange:h}});if(g.success)return g.stats;throw new Error(g.message||"获取统计失败")}catch(g){return console.error("获取API Key统计失败:",g),null}},fetchTags:async()=>{try{const b=await U.get("/admin/api-keys/tags");if(b.success)return b.data||[];throw new Error(b.message||"获取标签失败")}catch(b){return console.error("获取标签失败:",b),[]}},sortApiKeys:b=>{M.value===b?y.value=y.value==="asc"?"desc":"asc":(M.value=b,y.value="asc")},reset:()=>{L.value=[],R.value=!1,c.value=null,_.value="all",M.value="",y.value="asc"}}}),Pt={class:"fixed inset-0 modal z-50 flex items-center justify-center p-4"},Et={class:"modal-content w-full max-w-4xl p-6 mx-auto max-h-[90vh] flex flex-col"},Vt={class:"flex items-center justify-between mb-4"},jt={key:0,class:"text-red-500 text-xs mt-1"},Ut={class:"space-y-4"},qt={key:0},Ot={class:"flex flex-wrap gap-2"},Ft=["onClick"],Wt={key:1},Yt={class:"flex flex-wrap gap-2"},zt=["onClick"],Nt={class:"flex gap-2"},Bt=["onKeypress"],Ht={class:"bg-blue-50 border border-blue-200 rounded-lg p-3"},Gt={class:"space-y-2"},Qt={class:"grid grid-cols-1 lg:grid-cols-3 gap-2"},Xt={class:"space-y-2"},Jt={class:"flex gap-2"},Zt={key:0,class:"mt-3"},te=["min"],ee={key:1,class:"text-xs text-gray-500 mt-2"},se={class:"flex gap-4"},le={class:"flex items-center cursor-pointer"},ne={class:"flex items-center cursor-pointer"},oe={class:"flex items-center cursor-pointer"},ie={class:"grid grid-cols-1 gap-3"},ae=["disabled"],re=["value"],de=["disabled"],ue=["value"],me={class:"flex items-center mb-2"},pe={key:0,class:"space-y-2 bg-red-50 border border-red-200 rounded-lg p-3"},ce={class:"flex flex-wrap gap-1 mb-2 min-h-[24px]"},xe=["onClick"],ye={key:0,class:"text-gray-400 text-xs"},ge={class:"flex gap-2"},fe=["onKeydown"],be={class:"flex items-center mb-2"},ve={key:0,class:"bg-green-50 border border-green-200 rounded-lg p-3"},we={class:"space-y-1"},$e=["id","value"],Ae=["for"],Ce={class:"text-sm font-medium text-gray-700"},Ke={class:"text-xs text-gray-500 block"},ke={class:"flex gap-3 pt-2"},he=["disabled"],Le={key:0,class:"loading-spinner mr-2"},Ie={key:1,class:"fas fa-plus mr-2"},De={__name:"CreateApiKeyModal",props:{accounts:{type:Object,default:()=>({claude:[],gemini:[]})}},emits:["close","success"],setup(L,{emit:R}){const c=R;ut();const _=mt(),M=bt(),y=A(!1),k=A({name:""}),T=A(""),C=A([]),O=tt(()=>C.value.filter(w=>!e.tags.includes(w))),I=A([]),e=rt({name:"",description:"",tokenLimit:"",rateLimitWindow:"",rateLimitRequests:"",concurrencyLimit:"",dailyCostLimit:"",expireDuration:"",customExpireDate:"",expiresAt:null,permissions:"all",claudeAccountId:"",geminiAccountId:"",enableModelRestriction:!1,restrictedModels:[],modelInput:"",enableClientRestriction:!1,allowedClients:[],tags:[]});dt(async()=>{I.value=await _.loadSupportedClients(),C.value=await M.fetchTags()});const v=tt(()=>{const w=new Date;return w.setMinutes(w.getMinutes()+1),w.toISOString().slice(0,16)}),j=()=>{if(!e.expireDuration){e.expiresAt=null;return}if(e.expireDuration==="custom")return;const w=new Date,d=e.expireDuration.match(/(\d+)([dhmy])/);if(d){const[,D,G]=d,X=parseInt(D);switch(G){case"d":w.setDate(w.getDate()+X);break;case"h":w.setHours(w.getHours()+X);break;case"m":w.setMonth(w.getMonth()+X);break;case"y":w.setFullYear(w.getFullYear()+X);break}e.expiresAt=w.toISOString()}},W=()=>{e.customExpireDate&&(e.expiresAt=new Date(e.customExpireDate).toISOString())},z=w=>new Date(w).toLocaleString("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"}),b=()=>{e.modelInput&&!e.restrictedModels.includes(e.modelInput)&&(e.restrictedModels.push(e.modelInput),e.modelInput="")},h=w=>{e.restrictedModels.splice(w,1)},g=()=>{if(T.value&&T.value.trim()){const w=T.value.trim();e.tags.includes(w)||e.tags.push(w),T.value=""}},o=w=>{e.tags.includes(w)||e.tags.push(w)},m=w=>{e.tags.splice(w,1)},Y=async()=>{if(k.value.name="",!e.name||!e.name.trim()){k.value.name="请输入API Key名称";return}y.value=!0;try{const w={name:e.name,description:e.description||void 0,tokenLimit:e.tokenLimit!==""&&e.tokenLimit!==null?parseInt(e.tokenLimit):null,rateLimitWindow:e.rateLimitWindow!==""&&e.rateLimitWindow!==null?parseInt(e.rateLimitWindow):null,rateLimitRequests:e.rateLimitRequests!==""&&e.rateLimitRequests!==null?parseInt(e.rateLimitRequests):null,concurrencyLimit:e.concurrencyLimit!==""&&e.concurrencyLimit!==null?parseInt(e.concurrencyLimit):0,dailyCostLimit:e.dailyCostLimit!==""&&e.dailyCostLimit!==null?parseFloat(e.dailyCostLimit):0,expiresAt:e.expiresAt||void 0,permissions:e.permissions,claudeAccountId:e.claudeAccountId||void 0,geminiAccountId:e.geminiAccountId||void 0,tags:e.tags.length>0?e.tags:void 0};w.enableModelRestriction=e.enableModelRestriction,w.restrictedModels=e.restrictedModels,w.enableClientRestriction=e.enableClientRestriction,w.allowedClients=e.allowedClients;const n=await U.post("/admin/api-keys",w);n.success?(S("API Key 创建成功","success"),c("success",n.data),c("close")):S(n.message||"创建失败","error")}catch{S("创建失败","error")}finally{y.value=!1}};return(w,n)=>(i(),B(ot,{to:"body"},[t("div",Pt,[t("div",Et,[t("div",Vt,[n[27]||(n[27]=t("div",{class:"flex items-center gap-3"},[t("div",{class:"w-10 h-10 bg-gradient-to-br from-blue-500 to-blue-600 rounded-xl flex items-center justify-center"},[t("i",{class:"fas fa-key text-white"})]),t("h3",{class:"text-xl font-bold text-gray-900"}," 创建新的 API Key ")],-1)),t("button",{class:"text-gray-400 hover:text-gray-600 transition-colors",onClick:n[0]||(n[0]=d=>w.$emit("close"))},n[26]||(n[26]=[t("i",{class:"fas fa-times text-xl"},null,-1)]))]),t("form",{class:"space-y-4 modal-scroll-content custom-scrollbar flex-1",onSubmit:Q(Y,["prevent"])},[t("div",null,[n[28]||(n[28]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},[f("名称 "),t("span",{class:"text-red-500"},"*")],-1)),$(t("input",{"onUpdate:modelValue":n[1]||(n[1]=d=>e.name=d),type:"text",required:"",class:F(["form-input w-full",{"border-red-500":k.value.name}]),placeholder:"为您的 API Key 取一个名称",onInput:n[2]||(n[2]=d=>k.value.name="")},null,34),[[E,e.name]]),k.value.name?(i(),a("p",jt,u(k.value.name),1)):K("",!0)]),t("div",null,[n[36]||(n[36]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},"标签",-1)),t("div",Ut,[e.tags.length>0?(i(),a("div",qt,[n[30]||(n[30]=t("div",{class:"text-xs font-medium text-gray-600 mb-2"}," 已选择的标签: ",-1)),t("div",Ot,[(i(!0),a(V,null,q(e.tags,(d,D)=>(i(),a("span",{key:"selected-"+D,class:"inline-flex items-center gap-1 px-3 py-1 bg-blue-100 text-blue-800 text-sm rounded-full"},[f(u(d)+" ",1),t("button",{type:"button",class:"ml-1 hover:text-blue-900",onClick:G=>m(D)},n[29]||(n[29]=[t("i",{class:"fas fa-times text-xs"},null,-1)]),8,Ft)]))),128))])])):K("",!0),O.value.length>0?(i(),a("div",Wt,[n[32]||(n[32]=t("div",{class:"text-xs font-medium text-gray-600 mb-2"}," 点击选择已有标签: ",-1)),t("div",Yt,[(i(!0),a(V,null,q(O.value,d=>(i(),a("button",{key:"available-"+d,type:"button",class:"inline-flex items-center gap-1 px-3 py-1 bg-gray-100 text-gray-700 text-sm rounded-full hover:bg-blue-100 hover:text-blue-700 transition-colors",onClick:D=>o(d)},[n[31]||(n[31]=t("i",{class:"fas fa-tag text-gray-500 text-xs"},null,-1)),f(" "+u(d),1)],8,zt))),128))])])):K("",!0),t("div",null,[n[34]||(n[34]=t("div",{class:"text-xs font-medium text-gray-600 mb-2"}," 创建新标签: ",-1)),t("div",Nt,[$(t("input",{"onUpdate:modelValue":n[3]||(n[3]=d=>T.value=d),type:"text",class:"form-input flex-1",placeholder:"输入新标签名称",onKeypress:nt(Q(g,["prevent"]),["enter"])},null,40,Bt),[[E,T.value]]),t("button",{type:"button",class:"px-4 py-2 bg-green-500 text-white rounded-lg hover:bg-green-600 transition-colors",onClick:g},n[33]||(n[33]=[t("i",{class:"fas fa-plus"},null,-1)]))])]),n[35]||(n[35]=t("p",{class:"text-xs text-gray-500"}," 用于标记不同团队或用途,方便筛选管理 ",-1))])]),t("div",Ht,[n[44]||(n[44]=t("div",{class:"flex items-center gap-2 mb-2"},[t("div",{class:"w-6 h-6 bg-blue-500 rounded flex items-center justify-center flex-shrink-0"},[t("i",{class:"fas fa-tachometer-alt text-white text-xs"})]),t("h4",{class:"font-semibold text-gray-800 text-sm"}," 速率限制设置 (可选) ")],-1)),t("div",Gt,[t("div",Qt,[t("div",null,[n[37]||(n[37]=t("label",{class:"block text-xs font-medium text-gray-700 mb-1"},"时间窗口 (分钟)",-1)),$(t("input",{"onUpdate:modelValue":n[4]||(n[4]=d=>e.rateLimitWindow=d),type:"number",min:"1",placeholder:"无限制",class:"form-input w-full text-sm"},null,512),[[E,e.rateLimitWindow]]),n[38]||(n[38]=t("p",{class:"text-xs text-gray-500 mt-0.5 ml-2"}," 时间段单位 ",-1))]),t("div",null,[n[39]||(n[39]=t("label",{class:"block text-xs font-medium text-gray-700 mb-1"},"请求次数限制",-1)),$(t("input",{"onUpdate:modelValue":n[5]||(n[5]=d=>e.rateLimitRequests=d),type:"number",min:"1",placeholder:"无限制",class:"form-input w-full text-sm"},null,512),[[E,e.rateLimitRequests]]),n[40]||(n[40]=t("p",{class:"text-xs text-gray-500 mt-0.5 ml-2"}," 窗口内最大请求 ",-1))]),t("div",null,[n[41]||(n[41]=t("label",{class:"block text-xs font-medium text-gray-700 mb-1"},"Token 限制",-1)),$(t("input",{"onUpdate:modelValue":n[6]||(n[6]=d=>e.tokenLimit=d),type:"number",placeholder:"无限制",class:"form-input w-full text-sm"},null,512),[[E,e.tokenLimit]]),n[42]||(n[42]=t("p",{class:"text-xs text-gray-500 mt-0.5 ml-2"}," 窗口内最大Token ",-1))])]),n[43]||(n[43]=t("div",{class:"bg-blue-100 rounded-lg p-2"},[t("h5",{class:"text-xs font-semibold text-blue-800 mb-1"}," 💡 使用示例 "),t("div",{class:"text-xs text-blue-700 space-y-0.5"},[t("div",null,[t("strong",null,"示例1:"),f(" 时间窗口=60,请求次数=1000 → 每60分钟最多1000次请求")]),t("div",null,[t("strong",null,"示例2:"),f(" 时间窗口=1,Token=10000 → 每分钟最多10,000个Token")]),t("div",null,[t("strong",null,"示例3:"),f(" 窗口=30,请求=50,Token=100000 → 每30分钟50次请求且不超10万Token")])])],-1))])]),t("div",null,[n[46]||(n[46]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},"每日费用限制 (美元)",-1)),t("div",Xt,[t("div",Jt,[t("button",{type:"button",class:"px-2 py-1 bg-gray-100 hover:bg-gray-200 rounded text-xs font-medium",onClick:n[7]||(n[7]=d=>e.dailyCostLimit="50")}," $50 "),t("button",{type:"button",class:"px-2 py-1 bg-gray-100 hover:bg-gray-200 rounded text-xs font-medium",onClick:n[8]||(n[8]=d=>e.dailyCostLimit="100")}," $100 "),t("button",{type:"button",class:"px-2 py-1 bg-gray-100 hover:bg-gray-200 rounded text-xs font-medium",onClick:n[9]||(n[9]=d=>e.dailyCostLimit="200")}," $200 "),t("button",{type:"button",class:"px-2 py-1 bg-gray-100 hover:bg-gray-200 rounded text-xs font-medium",onClick:n[10]||(n[10]=d=>e.dailyCostLimit="")}," 自定义 ")]),$(t("input",{"onUpdate:modelValue":n[11]||(n[11]=d=>e.dailyCostLimit=d),type:"number",min:"0",step:"0.01",placeholder:"0 表示无限制",class:"form-input w-full"},null,512),[[E,e.dailyCostLimit]]),n[45]||(n[45]=t("p",{class:"text-xs text-gray-500"}," 设置此 API Key 每日的费用限制,超过限制将拒绝请求,0 或留空表示无限制 ",-1))])]),t("div",null,[n[47]||(n[47]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},"并发限制 (可选)",-1)),$(t("input",{"onUpdate:modelValue":n[12]||(n[12]=d=>e.concurrencyLimit=d),type:"number",min:"0",placeholder:"0 表示无限制",class:"form-input w-full"},null,512),[[E,e.concurrencyLimit]]),n[48]||(n[48]=t("p",{class:"text-xs text-gray-500 mt-2"}," 设置此 API Key 可同时处理的最大请求数,0 或留空表示无限制 ",-1))]),t("div",null,[n[49]||(n[49]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},"备注 (可选)",-1)),$(t("textarea",{"onUpdate:modelValue":n[13]||(n[13]=d=>e.description=d),rows:"2",class:"form-input w-full resize-none text-sm",placeholder:"描述此 API Key 的用途..."},null,512),[[E,e.description]])]),t("div",null,[n[51]||(n[51]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},"有效期限",-1)),$(t("select",{"onUpdate:modelValue":n[14]||(n[14]=d=>e.expireDuration=d),class:"form-input w-full",onChange:j},n[50]||(n[50]=[t("option",{value:""}," 永不过期 ",-1),t("option",{value:"1d"}," 1 天 ",-1),t("option",{value:"7d"}," 7 天 ",-1),t("option",{value:"30d"}," 30 天 ",-1),t("option",{value:"90d"}," 90 天 ",-1),t("option",{value:"180d"}," 180 天 ",-1),t("option",{value:"365d"}," 365 天 ",-1),t("option",{value:"custom"}," 自定义日期 ",-1)]),544),[[H,e.expireDuration]]),e.expireDuration==="custom"?(i(),a("div",Zt,[$(t("input",{"onUpdate:modelValue":n[15]||(n[15]=d=>e.customExpireDate=d),type:"datetime-local",class:"form-input w-full",min:v.value,onChange:W},null,40,te),[[E,e.customExpireDate]])])):K("",!0),e.expiresAt?(i(),a("p",ee," 将于 "+u(z(e.expiresAt))+" 过期 ",1)):K("",!0)]),t("div",null,[n[55]||(n[55]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},"服务权限",-1)),t("div",se,[t("label",le,[$(t("input",{"onUpdate:modelValue":n[16]||(n[16]=d=>e.permissions=d),type:"radio",value:"all",class:"mr-2"},null,512),[[J,e.permissions]]),n[52]||(n[52]=t("span",{class:"text-sm text-gray-700"},"全部服务",-1))]),t("label",ne,[$(t("input",{"onUpdate:modelValue":n[17]||(n[17]=d=>e.permissions=d),type:"radio",value:"claude",class:"mr-2"},null,512),[[J,e.permissions]]),n[53]||(n[53]=t("span",{class:"text-sm text-gray-700"},"仅 Claude",-1))]),t("label",oe,[$(t("input",{"onUpdate:modelValue":n[18]||(n[18]=d=>e.permissions=d),type:"radio",value:"gemini",class:"mr-2"},null,512),[[J,e.permissions]]),n[54]||(n[54]=t("span",{class:"text-sm text-gray-700"},"仅 Gemini",-1))])]),n[56]||(n[56]=t("p",{class:"text-xs text-gray-500 mt-2"}," 控制此 API Key 可以访问哪些服务 ",-1))]),t("div",null,[n[61]||(n[61]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},"专属账号绑定 (可选)",-1)),t("div",ie,[t("div",null,[n[58]||(n[58]=t("label",{class:"block text-sm font-medium text-gray-600 mb-1"},"Claude 专属账号",-1)),$(t("select",{"onUpdate:modelValue":n[19]||(n[19]=d=>e.claudeAccountId=d),class:"form-input w-full",disabled:e.permissions==="gemini"},[n[57]||(n[57]=t("option",{value:""}," 使用共享账号池 ",-1)),(i(!0),a(V,null,q(L.accounts.claude.filter(d=>d.isDedicated),d=>(i(),a("option",{key:d.id,value:d.id},u(d.name)+" ("+u(d.status==="active"?"正常":"异常")+") ",9,re))),128))],8,ae),[[H,e.claudeAccountId]])]),t("div",null,[n[60]||(n[60]=t("label",{class:"block text-sm font-medium text-gray-600 mb-1"},"Gemini 专属账号",-1)),$(t("select",{"onUpdate:modelValue":n[20]||(n[20]=d=>e.geminiAccountId=d),class:"form-input w-full",disabled:e.permissions==="claude"},[n[59]||(n[59]=t("option",{value:""}," 使用共享账号池 ",-1)),(i(!0),a(V,null,q(L.accounts.gemini.filter(d=>d.isDedicated),d=>(i(),a("option",{key:d.id,value:d.id},u(d.name)+" ("+u(d.status==="active"?"正常":"异常")+") ",9,ue))),128))],8,de),[[H,e.geminiAccountId]])])]),n[62]||(n[62]=t("p",{class:"text-xs text-gray-500 mt-2"}," 选择专属账号后,此API Key将只使用该账号,不选择则使用共享账号池 ",-1))]),t("div",null,[t("div",me,[$(t("input",{id:"enableModelRestriction","onUpdate:modelValue":n[21]||(n[21]=d=>e.enableModelRestriction=d),type:"checkbox",class:"w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500"},null,512),[[Z,e.enableModelRestriction]]),n[63]||(n[63]=t("label",{for:"enableModelRestriction",class:"ml-2 text-sm font-semibold text-gray-700 cursor-pointer"}," 启用模型限制 ",-1))]),e.enableModelRestriction?(i(),a("div",pe,[t("div",null,[n[66]||(n[66]=t("label",{class:"block text-xs font-medium text-gray-700 mb-1"},"限制的模型列表",-1)),t("div",ce,[(i(!0),a(V,null,q(e.restrictedModels,(d,D)=>(i(),a("span",{key:D,class:"inline-flex items-center px-2 py-1 rounded-full text-xs bg-red-100 text-red-800"},[f(u(d)+" ",1),t("button",{type:"button",class:"ml-1 text-red-600 hover:text-red-800",onClick:G=>h(D)},n[64]||(n[64]=[t("i",{class:"fas fa-times text-xs"},null,-1)]),8,xe)]))),128)),e.restrictedModels.length===0?(i(),a("span",ye," 暂无限制的模型 ")):K("",!0)]),t("div",ge,[$(t("input",{"onUpdate:modelValue":n[22]||(n[22]=d=>e.modelInput=d),type:"text",placeholder:"输入模型名称,按回车添加",class:"form-input flex-1 text-sm",onKeydown:nt(Q(b,["prevent"]),["enter"])},null,40,fe),[[E,e.modelInput]]),t("button",{type:"button",class:"px-3 py-1.5 bg-red-500 text-white rounded-lg hover:bg-red-600 transition-colors text-sm",onClick:b},n[65]||(n[65]=[t("i",{class:"fas fa-plus"},null,-1)]))]),n[67]||(n[67]=t("p",{class:"text-xs text-gray-500 mt-1"}," 例如:claude-opus-4-20250514 ",-1))])])):K("",!0)]),t("div",null,[t("div",be,[$(t("input",{id:"enableClientRestriction","onUpdate:modelValue":n[23]||(n[23]=d=>e.enableClientRestriction=d),type:"checkbox",class:"w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500"},null,512),[[Z,e.enableClientRestriction]]),n[68]||(n[68]=t("label",{for:"enableClientRestriction",class:"ml-2 text-sm font-semibold text-gray-700 cursor-pointer"}," 启用客户端限制 ",-1))]),e.enableClientRestriction?(i(),a("div",ve,[t("div",null,[n[69]||(n[69]=t("label",{class:"block text-xs font-medium text-gray-700 mb-2"},"允许的客户端",-1)),t("div",we,[(i(!0),a(V,null,q(I.value,d=>(i(),a("div",{key:d.id,class:"flex items-start"},[$(t("input",{id:`client_${d.id}`,"onUpdate:modelValue":n[24]||(n[24]=D=>e.allowedClients=D),type:"checkbox",value:d.id,class:"w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 mt-0.5"},null,8,$e),[[Z,e.allowedClients]]),t("label",{for:`client_${d.id}`,class:"ml-2 flex-1 cursor-pointer"},[t("span",Ce,u(d.name),1),t("span",Ke,u(d.description),1)],8,Ae)]))),128))])])])):K("",!0)]),t("div",ke,[t("button",{type:"button",class:"flex-1 px-4 py-2.5 bg-gray-100 text-gray-700 rounded-lg font-semibold hover:bg-gray-200 transition-colors text-sm",onClick:n[25]||(n[25]=d=>w.$emit("close"))}," 取消 "),t("button",{type:"submit",disabled:y.value,class:"btn btn-primary flex-1 py-2.5 px-4 font-semibold text-sm"},[y.value?(i(),a("div",Le)):(i(),a("i",Ie)),f(" "+u(y.value?"创建中...":"创建"),1)],8,he)])],32)])])]))}},Re=et(De,[["__scopeId","data-v-3fb23c54"]]),Me={class:"fixed inset-0 modal z-50 flex items-center justify-center p-4"},Se={class:"modal-content w-full max-w-4xl p-8 mx-auto max-h-[90vh] flex flex-col"},Te={class:"flex items-center justify-between mb-6"},_e=["value"],Pe={class:"space-y-4"},Ee={key:0},Ve={class:"flex flex-wrap gap-2"},je=["onClick"],Ue={key:1},qe={class:"flex flex-wrap gap-2"},Oe=["onClick"],Fe={class:"flex gap-2"},We=["onKeypress"],Ye={class:"bg-blue-50 border border-blue-200 rounded-lg p-3"},ze={class:"space-y-2"},Ne={class:"grid grid-cols-1 lg:grid-cols-3 gap-2"},Be={class:"space-y-3"},He={class:"flex gap-2"},Ge={class:"flex gap-4"},Qe={class:"flex items-center cursor-pointer"},Xe={class:"flex items-center cursor-pointer"},Je={class:"flex items-center cursor-pointer"},Ze={class:"grid grid-cols-1 gap-3"},ts=["disabled"],es=["value"],ss=["disabled"],ls=["value"],ns={class:"flex items-center mb-3"},os={key:0,class:"space-y-3"},is={class:"flex flex-wrap gap-2 mb-3 min-h-[32px] p-2 bg-gray-50 rounded-lg border border-gray-200"},as=["onClick"],rs={key:0,class:"text-gray-400 text-sm"},ds={class:"flex gap-2"},us=["onKeydown"],ms={class:"flex items-center mb-3"},ps={key:0,class:"space-y-3"},cs={class:"space-y-2"},xs=["id","value"],ys=["for"],gs={class:"text-sm font-medium text-gray-700"},fs={class:"text-xs text-gray-500 block"},bs={class:"flex gap-3 pt-4"},vs=["disabled"],ws={key:0,class:"loading-spinner mr-2"},$s={key:1,class:"fas fa-save mr-2"},As={__name:"EditApiKeyModal",props:{apiKey:{type:Object,required:!0},accounts:{type:Object,default:()=>({claude:[],gemini:[]})}},emits:["close","success"],setup(L,{emit:R}){const c=L,_=R;ut();const M=mt(),y=bt(),k=A(!1),T=A([]),C=A(""),O=A([]),I=tt(()=>O.value.filter(g=>!e.tags.includes(g))),e=rt({name:"",tokenLimit:"",rateLimitWindow:"",rateLimitRequests:"",concurrencyLimit:"",dailyCostLimit:"",permissions:"all",claudeAccountId:"",geminiAccountId:"",enableModelRestriction:!1,restrictedModels:[],modelInput:"",enableClientRestriction:!1,allowedClients:[],tags:[]}),v=()=>{e.modelInput&&!e.restrictedModels.includes(e.modelInput)&&(e.restrictedModels.push(e.modelInput),e.modelInput="")},j=g=>{e.restrictedModels.splice(g,1)},W=()=>{if(C.value&&C.value.trim()){const g=C.value.trim();e.tags.includes(g)||e.tags.push(g),C.value=""}},z=g=>{e.tags.includes(g)||e.tags.push(g)},b=g=>{e.tags.splice(g,1)},h=async()=>{k.value=!0;try{const g={tokenLimit:e.tokenLimit!==""&&e.tokenLimit!==null?parseInt(e.tokenLimit):0,rateLimitWindow:e.rateLimitWindow!==""&&e.rateLimitWindow!==null?parseInt(e.rateLimitWindow):0,rateLimitRequests:e.rateLimitRequests!==""&&e.rateLimitRequests!==null?parseInt(e.rateLimitRequests):0,concurrencyLimit:e.concurrencyLimit!==""&&e.concurrencyLimit!==null?parseInt(e.concurrencyLimit):0,dailyCostLimit:e.dailyCostLimit!==""&&e.dailyCostLimit!==null?parseFloat(e.dailyCostLimit):0,permissions:e.permissions,claudeAccountId:e.claudeAccountId||null,geminiAccountId:e.geminiAccountId||null,tags:e.tags};g.enableModelRestriction=e.enableModelRestriction,g.restrictedModels=e.restrictedModels,g.enableClientRestriction=e.enableClientRestriction,g.allowedClients=e.allowedClients;const o=await U.put(`/admin/api-keys/${c.apiKey.id}`,g);o.success?(_("success"),_("close")):S(o.message||"更新失败","error")}catch{S("更新失败","error")}finally{k.value=!1}};return dt(async()=>{T.value=await M.loadSupportedClients(),O.value=await y.fetchTags(),e.name=c.apiKey.name,e.tokenLimit=c.apiKey.tokenLimit||"",e.rateLimitWindow=c.apiKey.rateLimitWindow||"",e.rateLimitRequests=c.apiKey.rateLimitRequests||"",e.concurrencyLimit=c.apiKey.concurrencyLimit||"",e.dailyCostLimit=c.apiKey.dailyCostLimit||"",e.permissions=c.apiKey.permissions||"all",e.claudeAccountId=c.apiKey.claudeAccountId||"",e.geminiAccountId=c.apiKey.geminiAccountId||"",e.restrictedModels=c.apiKey.restrictedModels||[],e.allowedClients=c.apiKey.allowedClients||[],e.tags=c.apiKey.tags||[],e.enableModelRestriction=c.apiKey.enableModelRestriction||!1,e.enableClientRestriction=c.apiKey.enableClientRestriction||!1}),(g,o)=>(i(),B(ot,{to:"body"},[t("div",Me,[t("div",Se,[t("div",Te,[o[22]||(o[22]=t("div",{class:"flex items-center gap-3"},[t("div",{class:"w-10 h-10 bg-gradient-to-br from-blue-500 to-blue-600 rounded-xl flex items-center justify-center"},[t("i",{class:"fas fa-edit text-white"})]),t("h3",{class:"text-xl font-bold text-gray-900"}," 编辑 API Key ")],-1)),t("button",{class:"text-gray-400 hover:text-gray-600 transition-colors",onClick:o[0]||(o[0]=m=>g.$emit("close"))},o[21]||(o[21]=[t("i",{class:"fas fa-times text-xl"},null,-1)]))]),t("form",{class:"space-y-6 modal-scroll-content custom-scrollbar flex-1",onSubmit:Q(h,["prevent"])},[t("div",null,[o[23]||(o[23]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"名称",-1)),t("input",{value:e.name,type:"text",disabled:"",class:"form-input w-full bg-gray-100 cursor-not-allowed"},null,8,_e),o[24]||(o[24]=t("p",{class:"text-xs text-gray-500 mt-2"}," 名称不可修改 ",-1))]),t("div",null,[o[32]||(o[32]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"标签",-1)),t("div",Pe,[e.tags.length>0?(i(),a("div",Ee,[o[26]||(o[26]=t("div",{class:"text-xs font-medium text-gray-600 mb-2"}," 已选择的标签: ",-1)),t("div",Ve,[(i(!0),a(V,null,q(e.tags,(m,Y)=>(i(),a("span",{key:"selected-"+Y,class:"inline-flex items-center gap-1 px-3 py-1 bg-blue-100 text-blue-800 text-sm rounded-full"},[f(u(m)+" ",1),t("button",{type:"button",class:"ml-1 hover:text-blue-900",onClick:w=>b(Y)},o[25]||(o[25]=[t("i",{class:"fas fa-times text-xs"},null,-1)]),8,je)]))),128))])])):K("",!0),I.value.length>0?(i(),a("div",Ue,[o[28]||(o[28]=t("div",{class:"text-xs font-medium text-gray-600 mb-2"}," 点击选择已有标签: ",-1)),t("div",qe,[(i(!0),a(V,null,q(I.value,m=>(i(),a("button",{key:"available-"+m,type:"button",class:"inline-flex items-center gap-1 px-3 py-1 bg-gray-100 text-gray-700 text-sm rounded-full hover:bg-blue-100 hover:text-blue-700 transition-colors",onClick:Y=>z(m)},[o[27]||(o[27]=t("i",{class:"fas fa-tag text-gray-500 text-xs"},null,-1)),f(" "+u(m),1)],8,Oe))),128))])])):K("",!0),t("div",null,[o[30]||(o[30]=t("div",{class:"text-xs font-medium text-gray-600 mb-2"}," 创建新标签: ",-1)),t("div",Fe,[$(t("input",{"onUpdate:modelValue":o[1]||(o[1]=m=>C.value=m),type:"text",class:"form-input flex-1",placeholder:"输入新标签名称",onKeypress:nt(Q(W,["prevent"]),["enter"])},null,40,We),[[E,C.value]]),t("button",{type:"button",class:"px-4 py-2 bg-green-500 text-white rounded-lg hover:bg-green-600 transition-colors",onClick:W},o[29]||(o[29]=[t("i",{class:"fas fa-plus"},null,-1)]))])]),o[31]||(o[31]=t("p",{class:"text-xs text-gray-500"}," 用于标记不同团队或用途,方便筛选管理 ",-1))])]),t("div",Ye,[o[40]||(o[40]=t("div",{class:"flex items-center gap-2 mb-2"},[t("div",{class:"w-6 h-6 bg-blue-500 rounded flex items-center justify-center flex-shrink-0"},[t("i",{class:"fas fa-tachometer-alt text-white text-xs"})]),t("h4",{class:"font-semibold text-gray-800 text-sm"}," 速率限制设置 (可选) ")],-1)),t("div",ze,[t("div",Ne,[t("div",null,[o[33]||(o[33]=t("label",{class:"block text-xs font-medium text-gray-700 mb-1"},"时间窗口 (分钟)",-1)),$(t("input",{"onUpdate:modelValue":o[2]||(o[2]=m=>e.rateLimitWindow=m),type:"number",min:"1",placeholder:"无限制",class:"form-input w-full text-sm"},null,512),[[E,e.rateLimitWindow]]),o[34]||(o[34]=t("p",{class:"text-xs text-gray-500 mt-0.5 ml-2"}," 时间段单位 ",-1))]),t("div",null,[o[35]||(o[35]=t("label",{class:"block text-xs font-medium text-gray-700 mb-1"},"请求次数限制",-1)),$(t("input",{"onUpdate:modelValue":o[3]||(o[3]=m=>e.rateLimitRequests=m),type:"number",min:"1",placeholder:"无限制",class:"form-input w-full text-sm"},null,512),[[E,e.rateLimitRequests]]),o[36]||(o[36]=t("p",{class:"text-xs text-gray-500 mt-0.5 ml-2"}," 窗口内最大请求 ",-1))]),t("div",null,[o[37]||(o[37]=t("label",{class:"block text-xs font-medium text-gray-700 mb-1"},"Token 限制",-1)),$(t("input",{"onUpdate:modelValue":o[4]||(o[4]=m=>e.tokenLimit=m),type:"number",placeholder:"无限制",class:"form-input w-full text-sm"},null,512),[[E,e.tokenLimit]]),o[38]||(o[38]=t("p",{class:"text-xs text-gray-500 mt-0.5 ml-2"}," 窗口内最大Token ",-1))])]),o[39]||(o[39]=t("div",{class:"bg-blue-100 rounded-lg p-2"},[t("h5",{class:"text-xs font-semibold text-blue-800 mb-1"}," 💡 使用示例 "),t("div",{class:"text-xs text-blue-700 space-y-0.5"},[t("div",null,[t("strong",null,"示例1:"),f(" 时间窗口=60,请求次数=1000 → 每60分钟最多1000次请求")]),t("div",null,[t("strong",null,"示例2:"),f(" 时间窗口=1,Token=10000 → 每分钟最多10,000个Token")]),t("div",null,[t("strong",null,"示例3:"),f(" 窗口=30,请求=50,Token=100000 → 每30分钟50次请求且不超10万Token")])])],-1))])]),t("div",null,[o[42]||(o[42]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"每日费用限制 (美元)",-1)),t("div",Be,[t("div",He,[t("button",{type:"button",class:"px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded-lg text-sm font-medium",onClick:o[5]||(o[5]=m=>e.dailyCostLimit="50")}," $50 "),t("button",{type:"button",class:"px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded-lg text-sm font-medium",onClick:o[6]||(o[6]=m=>e.dailyCostLimit="100")}," $100 "),t("button",{type:"button",class:"px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded-lg text-sm font-medium",onClick:o[7]||(o[7]=m=>e.dailyCostLimit="200")}," $200 "),t("button",{type:"button",class:"px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded-lg text-sm font-medium",onClick:o[8]||(o[8]=m=>e.dailyCostLimit="")}," 自定义 ")]),$(t("input",{"onUpdate:modelValue":o[9]||(o[9]=m=>e.dailyCostLimit=m),type:"number",min:"0",step:"0.01",placeholder:"0 表示无限制",class:"form-input w-full"},null,512),[[E,e.dailyCostLimit]]),o[41]||(o[41]=t("p",{class:"text-xs text-gray-500"}," 设置此 API Key 每日的费用限制,超过限制将拒绝请求,0 或留空表示无限制 ",-1))])]),t("div",null,[o[43]||(o[43]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"并发限制",-1)),$(t("input",{"onUpdate:modelValue":o[10]||(o[10]=m=>e.concurrencyLimit=m),type:"number",min:"0",placeholder:"0 表示无限制",class:"form-input w-full"},null,512),[[E,e.concurrencyLimit]]),o[44]||(o[44]=t("p",{class:"text-xs text-gray-500 mt-2"}," 设置此 API Key 可同时处理的最大请求数 ",-1))]),t("div",null,[o[48]||(o[48]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"服务权限",-1)),t("div",Ge,[t("label",Qe,[$(t("input",{"onUpdate:modelValue":o[11]||(o[11]=m=>e.permissions=m),type:"radio",value:"all",class:"mr-2"},null,512),[[J,e.permissions]]),o[45]||(o[45]=t("span",{class:"text-sm text-gray-700"},"全部服务",-1))]),t("label",Xe,[$(t("input",{"onUpdate:modelValue":o[12]||(o[12]=m=>e.permissions=m),type:"radio",value:"claude",class:"mr-2"},null,512),[[J,e.permissions]]),o[46]||(o[46]=t("span",{class:"text-sm text-gray-700"},"仅 Claude",-1))]),t("label",Je,[$(t("input",{"onUpdate:modelValue":o[13]||(o[13]=m=>e.permissions=m),type:"radio",value:"gemini",class:"mr-2"},null,512),[[J,e.permissions]]),o[47]||(o[47]=t("span",{class:"text-sm text-gray-700"},"仅 Gemini",-1))])]),o[49]||(o[49]=t("p",{class:"text-xs text-gray-500 mt-2"}," 控制此 API Key 可以访问哪些服务 ",-1))]),t("div",null,[o[54]||(o[54]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"专属账号绑定",-1)),t("div",Ze,[t("div",null,[o[51]||(o[51]=t("label",{class:"block text-sm font-medium text-gray-600 mb-1"},"Claude 专属账号",-1)),$(t("select",{"onUpdate:modelValue":o[14]||(o[14]=m=>e.claudeAccountId=m),class:"form-input w-full",disabled:e.permissions==="gemini"},[o[50]||(o[50]=t("option",{value:""}," 使用共享账号池 ",-1)),(i(!0),a(V,null,q(L.accounts.claude,m=>(i(),a("option",{key:m.id,value:m.id},u(m.name)+" ("+u(m.status==="active"?"正常":"异常")+") ",9,es))),128))],8,ts),[[H,e.claudeAccountId]])]),t("div",null,[o[53]||(o[53]=t("label",{class:"block text-sm font-medium text-gray-600 mb-1"},"Gemini 专属账号",-1)),$(t("select",{"onUpdate:modelValue":o[15]||(o[15]=m=>e.geminiAccountId=m),class:"form-input w-full",disabled:e.permissions==="claude"},[o[52]||(o[52]=t("option",{value:""}," 使用共享账号池 ",-1)),(i(!0),a(V,null,q(L.accounts.gemini,m=>(i(),a("option",{key:m.id,value:m.id},u(m.name)+" ("+u(m.status==="active"?"正常":"异常")+") ",9,ls))),128))],8,ss),[[H,e.geminiAccountId]])])]),o[55]||(o[55]=t("p",{class:"text-xs text-gray-500 mt-2"}," 修改绑定账号将影响此API Key的请求路由 ",-1))]),t("div",null,[t("div",ns,[$(t("input",{id:"editEnableModelRestriction","onUpdate:modelValue":o[16]||(o[16]=m=>e.enableModelRestriction=m),type:"checkbox",class:"w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500"},null,512),[[Z,e.enableModelRestriction]]),o[56]||(o[56]=t("label",{for:"editEnableModelRestriction",class:"ml-2 text-sm font-semibold text-gray-700 cursor-pointer"}," 启用模型限制 ",-1))]),e.enableModelRestriction?(i(),a("div",os,[t("div",null,[o[59]||(o[59]=t("label",{class:"block text-sm font-medium text-gray-600 mb-2"},"限制的模型列表",-1)),t("div",is,[(i(!0),a(V,null,q(e.restrictedModels,(m,Y)=>(i(),a("span",{key:Y,class:"inline-flex items-center px-3 py-1 rounded-full text-sm bg-red-100 text-red-800"},[f(u(m)+" ",1),t("button",{type:"button",class:"ml-2 text-red-600 hover:text-red-800",onClick:w=>j(Y)},o[57]||(o[57]=[t("i",{class:"fas fa-times text-xs"},null,-1)]),8,as)]))),128)),e.restrictedModels.length===0?(i(),a("span",rs," 暂无限制的模型 ")):K("",!0)]),t("div",ds,[$(t("input",{"onUpdate:modelValue":o[17]||(o[17]=m=>e.modelInput=m),type:"text",placeholder:"输入模型名称,按回车添加",class:"form-input flex-1",onKeydown:nt(Q(v,["prevent"]),["enter"])},null,40,us),[[E,e.modelInput]]),t("button",{type:"button",class:"px-4 py-2 bg-red-500 text-white rounded-lg hover:bg-red-600 transition-colors",onClick:v},o[58]||(o[58]=[t("i",{class:"fas fa-plus"},null,-1)]))]),o[60]||(o[60]=t("p",{class:"text-xs text-gray-500 mt-2"}," 设置此API Key无法访问的模型,例如:claude-opus-4-20250514 ",-1))])])):K("",!0)]),t("div",null,[t("div",ms,[$(t("input",{id:"editEnableClientRestriction","onUpdate:modelValue":o[18]||(o[18]=m=>e.enableClientRestriction=m),type:"checkbox",class:"w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500"},null,512),[[Z,e.enableClientRestriction]]),o[61]||(o[61]=t("label",{for:"editEnableClientRestriction",class:"ml-2 text-sm font-semibold text-gray-700 cursor-pointer"}," 启用客户端限制 ",-1))]),e.enableClientRestriction?(i(),a("div",ps,[t("div",null,[o[62]||(o[62]=t("label",{class:"block text-sm font-medium text-gray-600 mb-2"},"允许的客户端",-1)),o[63]||(o[63]=t("p",{class:"text-xs text-gray-500 mb-3"}," 勾选允许使用此API Key的客户端 ",-1)),t("div",cs,[(i(!0),a(V,null,q(T.value,m=>(i(),a("div",{key:m.id,class:"flex items-start"},[$(t("input",{id:`edit_client_${m.id}`,"onUpdate:modelValue":o[19]||(o[19]=Y=>e.allowedClients=Y),type:"checkbox",value:m.id,class:"w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 mt-0.5"},null,8,xs),[[Z,e.allowedClients]]),t("label",{for:`edit_client_${m.id}`,class:"ml-2 flex-1 cursor-pointer"},[t("span",gs,u(m.name),1),t("span",fs,u(m.description),1)],8,ys)]))),128))])])])):K("",!0)]),t("div",bs,[t("button",{type:"button",class:"flex-1 px-6 py-3 bg-gray-100 text-gray-700 rounded-xl font-semibold hover:bg-gray-200 transition-colors",onClick:o[20]||(o[20]=m=>g.$emit("close"))}," 取消 "),t("button",{type:"submit",disabled:k.value,class:"btn btn-primary flex-1 py-3 px-6 font-semibold"},[k.value?(i(),a("div",ws)):(i(),a("i",$s)),f(" "+u(k.value?"保存中...":"保存修改"),1)],8,vs)])],32)])])]))}},Cs=et(As,[["__scopeId","data-v-f70072fe"]]),Ks={class:"fixed inset-0 modal z-50 flex items-center justify-center p-4"},ks={class:"modal-content w-full max-w-md p-8 mx-auto max-h-[90vh] flex flex-col"},hs={class:"flex items-center justify-between mb-6"},Ls={class:"space-y-6 modal-scroll-content custom-scrollbar flex-1"},Is={class:"bg-blue-50 border border-blue-200 rounded-lg p-4"},Ds={class:"flex items-start gap-3"},Rs={class:"text-sm text-gray-700"},Ms={class:"text-xs text-gray-600 mt-1"},Ss={key:0,class:"mt-3"},Ts=["min"],_s={key:1,class:"text-xs text-gray-500 mt-2"},Ps={class:"flex gap-3 pt-4"},Es=["disabled"],Vs={key:0,class:"loading-spinner mr-2"},js={key:1,class:"fas fa-clock mr-2"},Us={__name:"RenewApiKeyModal",props:{apiKey:{type:Object,required:!0}},emits:["close","success"],setup(L,{emit:R}){const c=L,_=R;ut();const M=A(!1),y=rt({renewDuration:"30d",customExpireDate:"",newExpiresAt:null}),k=tt(()=>{const e=new Date;return c.apiKey.expiresAt&&new Date(c.apiKey.expiresAt)>e?new Date(c.apiKey.expiresAt).toISOString().slice(0,16):(e.setMinutes(e.getMinutes()+1),e.toISOString().slice(0,16))}),T=e=>new Date(e).toLocaleString("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"}),C=()=>{if(!y.renewDuration){y.newExpiresAt=null;return}if(y.renewDuration==="permanent"){y.newExpiresAt=null;return}if(y.renewDuration==="custom")return;const e=c.apiKey.expiresAt&&new Date(c.apiKey.expiresAt)>new Date?new Date(c.apiKey.expiresAt):new Date,j=y.renewDuration.match(/(\d+)([dhmy])/);if(j){const[,W,z]=j,b=parseInt(W);switch(z){case"d":e.setDate(e.getDate()+b);break;case"h":e.setHours(e.getHours()+b);break;case"m":e.setMonth(e.getMonth()+b);break;case"y":e.setFullYear(e.getFullYear()+b);break}y.newExpiresAt=e.toISOString()}},O=()=>{y.customExpireDate&&(y.newExpiresAt=new Date(y.customExpireDate).toISOString())},I=async()=>{M.value=!0;try{const e={expiresAt:y.renewDuration==="permanent"?null:y.newExpiresAt},v=await U.put(`/admin/api-keys/${c.apiKey.id}/renew`,e);v.success?(S("API Key 续期成功","success"),_("success"),_("close")):S(v.message||"续期失败","error")}catch{S("续期失败","error")}finally{M.value=!1}};return C(),(e,v)=>(i(),B(ot,{to:"body"},[t("div",Ks,[t("div",ks,[t("div",hs,[v[5]||(v[5]=t("div",{class:"flex items-center gap-3"},[t("div",{class:"w-10 h-10 bg-gradient-to-br from-green-500 to-green-600 rounded-xl flex items-center justify-center"},[t("i",{class:"fas fa-clock text-white"})]),t("h3",{class:"text-xl font-bold text-gray-900"}," 续期 API Key ")],-1)),t("button",{class:"text-gray-400 hover:text-gray-600 transition-colors",onClick:v[0]||(v[0]=j=>e.$emit("close"))},v[4]||(v[4]=[t("i",{class:"fas fa-times text-xl"},null,-1)]))]),t("div",Ls,[t("div",Is,[t("div",Ds,[v[7]||(v[7]=t("div",{class:"w-8 h-8 bg-blue-500 rounded-lg flex items-center justify-center flex-shrink-0"},[t("i",{class:"fas fa-info text-white text-sm"})],-1)),t("div",null,[v[6]||(v[6]=t("h4",{class:"font-semibold text-gray-800 mb-1"}," API Key 信息 ",-1)),t("p",Rs,u(L.apiKey.name),1),t("p",Ms," 当前过期时间:"+u(L.apiKey.expiresAt?T(L.apiKey.expiresAt):"永不过期"),1)])])]),t("div",null,[v[9]||(v[9]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"续期时长",-1)),$(t("select",{"onUpdate:modelValue":v[1]||(v[1]=j=>y.renewDuration=j),class:"form-input w-full",onChange:C},v[8]||(v[8]=[t("option",{value:"7d"}," 延长 7 天 ",-1),t("option",{value:"30d"}," 延长 30 天 ",-1),t("option",{value:"90d"}," 延长 90 天 ",-1),t("option",{value:"180d"}," 延长 180 天 ",-1),t("option",{value:"365d"}," 延长 365 天 ",-1),t("option",{value:"custom"}," 自定义日期 ",-1),t("option",{value:"permanent"}," 设为永不过期 ",-1)]),544),[[H,y.renewDuration]]),y.renewDuration==="custom"?(i(),a("div",Ss,[$(t("input",{"onUpdate:modelValue":v[2]||(v[2]=j=>y.customExpireDate=j),type:"datetime-local",class:"form-input w-full",min:k.value,onChange:O},null,40,Ts),[[E,y.customExpireDate]])])):K("",!0),y.newExpiresAt?(i(),a("p",_s," 新的过期时间:"+u(T(y.newExpiresAt)),1)):K("",!0)])]),t("div",Ps,[t("button",{type:"button",class:"flex-1 px-6 py-3 bg-gray-100 text-gray-700 rounded-xl font-semibold hover:bg-gray-200 transition-colors",onClick:v[3]||(v[3]=j=>e.$emit("close"))}," 取消 "),t("button",{type:"button",disabled:M.value||!y.renewDuration,class:"btn btn-primary flex-1 py-3 px-6 font-semibold",onClick:I},[M.value?(i(),a("div",Vs)):(i(),a("i",js)),f(" "+u(M.value?"续期中...":"确认续期"),1)],8,Es)])])])]))}},qs=et(Us,[["__scopeId","data-v-0c3b1b3f"]]),Os={class:"fixed inset-0 modal z-50 flex items-center justify-center p-4"},Fs={class:"modal-content w-full max-w-lg p-8 mx-auto max-h-[90vh] overflow-y-auto custom-scrollbar"},Ws={class:"space-y-4 mb-6"},Ys={class:"p-3 bg-gray-50 rounded-lg border"},zs={class:"text-gray-900 font-medium"},Ns={key:0},Bs={class:"p-3 bg-gray-50 rounded-lg border"},Hs={class:"text-gray-700"},Gs={class:"relative"},Qs={class:"p-4 pr-14 bg-gray-900 rounded-lg border font-mono text-sm text-white break-all min-h-[60px] flex items-center"},Xs={class:"absolute top-3 right-3"},Js=["title"],Zs={__name:"NewApiKeyModal",props:{apiKey:{type:Object,required:!0}},emits:["close"],setup(L,{emit:R}){const c=L,_=R,M=A(!1),y=()=>{M.value=!M.value},k=()=>{const I=c.apiKey.apiKey||c.apiKey.key||"";return I?M.value||I.length<=12?I:I.substring(0,8)+"●".repeat(Math.max(0,I.length-12))+I.substring(I.length-4):""},T=async()=>{const I=c.apiKey.apiKey||c.apiKey.key||"";if(!I){S("API Key 不存在","error");return}try{await navigator.clipboard.writeText(I),S("API Key 已复制到剪贴板","success")}catch(e){console.error("Failed to copy:",e);const v=document.createElement("textarea");v.value=I,document.body.appendChild(v),v.select();try{document.execCommand("copy"),S("API Key 已复制到剪贴板","success")}catch{S("复制失败,请手动复制","error")}finally{document.body.removeChild(v)}}},C=async()=>{window.showConfirm?await window.showConfirm("关闭提醒",`关闭后将无法再次查看完整的API Key,请确保已经妥善保存。
+import{E as St}from"./element-plus-B8Fs_0jW.js";import{aR as ft,r as A,c as tt,_ as rt,q as dt,I as B,y as i,z as t,Y as Q,K as $,x as a,L as K,O as f,aq as E,C as F,P as u,Q as V,ac as q,aa as nt,aX as H,an as J,al as Z,a5 as ot,R as Tt,B as _t}from"./vue-vendor-CKToUHZx.js";import{s as S}from"./toast-BvwA7Mwb.js";import{a as U,_ as et,u as ut}from"./index-HYE9xPuR.js";import"./vendor-BDiMbLwQ.js";const mt=ft("clients",{state:()=>({supportedClients:[],loading:!1,error:null}),actions:{async loadSupportedClients(){if(this.supportedClients.length>0)return this.supportedClients;this.loading=!0,this.error=null;try{const L=await U.get("/admin/supported-clients");return L.success?this.supportedClients=L.data||[]:(this.error=L.message||"加载支持的客户端失败",console.error("Failed to load supported clients:",this.error)),this.supportedClients}catch(L){return this.error=L.message||"加载支持的客户端失败",console.error("Error loading supported clients:",L),[]}finally{this.loading=!1}}}}),bt=ft("apiKeys",()=>{const L=A([]),R=A(!1),c=A(null),_=A("all"),M=A(""),y=A("asc"),k=async()=>{R.value=!0,c.value=null;try{const b=await U.get("/admin/api-keys");if(b.success)L.value=b.data||[];else throw new Error(b.message||"获取API Keys失败")}catch(b){throw c.value=b.message,b}finally{R.value=!1}};return{apiKeys:L,loading:R,error:c,statsTimeRange:_,sortBy:M,sortOrder:y,fetchApiKeys:k,createApiKey:async b=>{R.value=!0,c.value=null;try{const h=await U.post("/admin/api-keys",b);if(h.success)return await k(),h.data;throw new Error(h.message||"创建API Key失败")}catch(h){throw c.value=h.message,h}finally{R.value=!1}},updateApiKey:async(b,h)=>{R.value=!0,c.value=null;try{const g=await U.put(`/admin/api-keys/${b}`,h);if(g.success)return await k(),g;throw new Error(g.message||"更新API Key失败")}catch(g){throw c.value=g.message,g}finally{R.value=!1}},toggleApiKey:async b=>{R.value=!0,c.value=null;try{const h=await U.put(`/admin/api-keys/${b}/toggle`);if(h.success)return await k(),h;throw new Error(h.message||"切换状态失败")}catch(h){throw c.value=h.message,h}finally{R.value=!1}},renewApiKey:async(b,h)=>{R.value=!0,c.value=null;try{const g=await U.put(`/admin/api-keys/${b}/renew`,h);if(g.success)return await k(),g;throw new Error(g.message||"续期失败")}catch(g){throw c.value=g.message,g}finally{R.value=!1}},deleteApiKey:async b=>{R.value=!0,c.value=null;try{const h=await U.delete(`/admin/api-keys/${b}`);if(h.success)return await k(),h;throw new Error(h.message||"删除失败")}catch(h){throw c.value=h.message,h}finally{R.value=!1}},fetchApiKeyStats:async(b,h="all")=>{try{const g=await U.get(`/admin/api-keys/${b}/stats`,{params:{timeRange:h}});if(g.success)return g.stats;throw new Error(g.message||"获取统计失败")}catch(g){return console.error("获取API Key统计失败:",g),null}},fetchTags:async()=>{try{const b=await U.get("/admin/api-keys/tags");if(b.success)return b.data||[];throw new Error(b.message||"获取标签失败")}catch(b){return console.error("获取标签失败:",b),[]}},sortApiKeys:b=>{M.value===b?y.value=y.value==="asc"?"desc":"asc":(M.value=b,y.value="asc")},reset:()=>{L.value=[],R.value=!1,c.value=null,_.value="all",M.value="",y.value="asc"}}}),Pt={class:"fixed inset-0 modal z-50 flex items-center justify-center p-4"},Et={class:"modal-content w-full max-w-4xl p-6 mx-auto max-h-[90vh] flex flex-col"},Vt={class:"flex items-center justify-between mb-4"},jt={key:0,class:"text-red-500 text-xs mt-1"},Ut={class:"space-y-4"},qt={key:0},Ot={class:"flex flex-wrap gap-2"},Ft=["onClick"],Wt={key:1},Yt={class:"flex flex-wrap gap-2"},zt=["onClick"],Nt={class:"flex gap-2"},Bt=["onKeypress"],Ht={class:"bg-blue-50 border border-blue-200 rounded-lg p-3"},Gt={class:"space-y-2"},Qt={class:"grid grid-cols-1 lg:grid-cols-3 gap-2"},Xt={class:"space-y-2"},Jt={class:"flex gap-2"},Zt={key:0,class:"mt-3"},te=["min"],ee={key:1,class:"text-xs text-gray-500 mt-2"},se={class:"flex gap-4"},le={class:"flex items-center cursor-pointer"},ne={class:"flex items-center cursor-pointer"},oe={class:"flex items-center cursor-pointer"},ie={class:"grid grid-cols-1 gap-3"},ae=["disabled"],re=["value"],de=["disabled"],ue=["value"],me={class:"flex items-center mb-2"},pe={key:0,class:"space-y-2 bg-red-50 border border-red-200 rounded-lg p-3"},ce={class:"flex flex-wrap gap-1 mb-2 min-h-[24px]"},xe=["onClick"],ye={key:0,class:"text-gray-400 text-xs"},ge={class:"flex gap-2"},fe=["onKeydown"],be={class:"flex items-center mb-2"},ve={key:0,class:"bg-green-50 border border-green-200 rounded-lg p-3"},we={class:"space-y-1"},$e=["id","value"],Ae=["for"],Ce={class:"text-sm font-medium text-gray-700"},Ke={class:"text-xs text-gray-500 block"},ke={class:"flex gap-3 pt-2"},he=["disabled"],Le={key:0,class:"loading-spinner mr-2"},Ie={key:1,class:"fas fa-plus mr-2"},De={__name:"CreateApiKeyModal",props:{accounts:{type:Object,default:()=>({claude:[],gemini:[]})}},emits:["close","success"],setup(L,{emit:R}){const c=R;ut();const _=mt(),M=bt(),y=A(!1),k=A({name:""}),T=A(""),C=A([]),O=tt(()=>C.value.filter(w=>!e.tags.includes(w))),I=A([]),e=rt({name:"",description:"",tokenLimit:"",rateLimitWindow:"",rateLimitRequests:"",concurrencyLimit:"",dailyCostLimit:"",expireDuration:"",customExpireDate:"",expiresAt:null,permissions:"all",claudeAccountId:"",geminiAccountId:"",enableModelRestriction:!1,restrictedModels:[],modelInput:"",enableClientRestriction:!1,allowedClients:[],tags:[]});dt(async()=>{I.value=await _.loadSupportedClients(),C.value=await M.fetchTags()});const v=tt(()=>{const w=new Date;return w.setMinutes(w.getMinutes()+1),w.toISOString().slice(0,16)}),j=()=>{if(!e.expireDuration){e.expiresAt=null;return}if(e.expireDuration==="custom")return;const w=new Date,d=e.expireDuration.match(/(\d+)([dhmy])/);if(d){const[,D,G]=d,X=parseInt(D);switch(G){case"d":w.setDate(w.getDate()+X);break;case"h":w.setHours(w.getHours()+X);break;case"m":w.setMonth(w.getMonth()+X);break;case"y":w.setFullYear(w.getFullYear()+X);break}e.expiresAt=w.toISOString()}},W=()=>{e.customExpireDate&&(e.expiresAt=new Date(e.customExpireDate).toISOString())},z=w=>new Date(w).toLocaleString("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"}),b=()=>{e.modelInput&&!e.restrictedModels.includes(e.modelInput)&&(e.restrictedModels.push(e.modelInput),e.modelInput="")},h=w=>{e.restrictedModels.splice(w,1)},g=()=>{if(T.value&&T.value.trim()){const w=T.value.trim();e.tags.includes(w)||e.tags.push(w),T.value=""}},o=w=>{e.tags.includes(w)||e.tags.push(w)},m=w=>{e.tags.splice(w,1)},Y=async()=>{if(k.value.name="",!e.name||!e.name.trim()){k.value.name="请输入API Key名称";return}y.value=!0;try{const w={name:e.name,description:e.description||void 0,tokenLimit:e.tokenLimit!==""&&e.tokenLimit!==null?parseInt(e.tokenLimit):null,rateLimitWindow:e.rateLimitWindow!==""&&e.rateLimitWindow!==null?parseInt(e.rateLimitWindow):null,rateLimitRequests:e.rateLimitRequests!==""&&e.rateLimitRequests!==null?parseInt(e.rateLimitRequests):null,concurrencyLimit:e.concurrencyLimit!==""&&e.concurrencyLimit!==null?parseInt(e.concurrencyLimit):0,dailyCostLimit:e.dailyCostLimit!==""&&e.dailyCostLimit!==null?parseFloat(e.dailyCostLimit):0,expiresAt:e.expiresAt||void 0,permissions:e.permissions,claudeAccountId:e.claudeAccountId||void 0,geminiAccountId:e.geminiAccountId||void 0,tags:e.tags.length>0?e.tags:void 0};w.enableModelRestriction=e.enableModelRestriction,w.restrictedModels=e.restrictedModels,w.enableClientRestriction=e.enableClientRestriction,w.allowedClients=e.allowedClients;const n=await U.post("/admin/api-keys",w);n.success?(S("API Key 创建成功","success"),c("success",n.data),c("close")):S(n.message||"创建失败","error")}catch{S("创建失败","error")}finally{y.value=!1}};return(w,n)=>(i(),B(ot,{to:"body"},[t("div",Pt,[t("div",Et,[t("div",Vt,[n[27]||(n[27]=t("div",{class:"flex items-center gap-3"},[t("div",{class:"w-10 h-10 bg-gradient-to-br from-blue-500 to-blue-600 rounded-xl flex items-center justify-center"},[t("i",{class:"fas fa-key text-white"})]),t("h3",{class:"text-xl font-bold text-gray-900"}," 创建新的 API Key ")],-1)),t("button",{class:"text-gray-400 hover:text-gray-600 transition-colors",onClick:n[0]||(n[0]=d=>w.$emit("close"))},n[26]||(n[26]=[t("i",{class:"fas fa-times text-xl"},null,-1)]))]),t("form",{class:"space-y-4 modal-scroll-content custom-scrollbar flex-1",onSubmit:Q(Y,["prevent"])},[t("div",null,[n[28]||(n[28]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},[f("名称 "),t("span",{class:"text-red-500"},"*")],-1)),$(t("input",{"onUpdate:modelValue":n[1]||(n[1]=d=>e.name=d),type:"text",required:"",class:F(["form-input w-full",{"border-red-500":k.value.name}]),placeholder:"为您的 API Key 取一个名称",onInput:n[2]||(n[2]=d=>k.value.name="")},null,34),[[E,e.name]]),k.value.name?(i(),a("p",jt,u(k.value.name),1)):K("",!0)]),t("div",null,[n[36]||(n[36]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},"标签",-1)),t("div",Ut,[e.tags.length>0?(i(),a("div",qt,[n[30]||(n[30]=t("div",{class:"text-xs font-medium text-gray-600 mb-2"}," 已选择的标签: ",-1)),t("div",Ot,[(i(!0),a(V,null,q(e.tags,(d,D)=>(i(),a("span",{key:"selected-"+D,class:"inline-flex items-center gap-1 px-3 py-1 bg-blue-100 text-blue-800 text-sm rounded-full"},[f(u(d)+" ",1),t("button",{type:"button",class:"ml-1 hover:text-blue-900",onClick:G=>m(D)},n[29]||(n[29]=[t("i",{class:"fas fa-times text-xs"},null,-1)]),8,Ft)]))),128))])])):K("",!0),O.value.length>0?(i(),a("div",Wt,[n[32]||(n[32]=t("div",{class:"text-xs font-medium text-gray-600 mb-2"}," 点击选择已有标签: ",-1)),t("div",Yt,[(i(!0),a(V,null,q(O.value,d=>(i(),a("button",{key:"available-"+d,type:"button",class:"inline-flex items-center gap-1 px-3 py-1 bg-gray-100 text-gray-700 text-sm rounded-full hover:bg-blue-100 hover:text-blue-700 transition-colors",onClick:D=>o(d)},[n[31]||(n[31]=t("i",{class:"fas fa-tag text-gray-500 text-xs"},null,-1)),f(" "+u(d),1)],8,zt))),128))])])):K("",!0),t("div",null,[n[34]||(n[34]=t("div",{class:"text-xs font-medium text-gray-600 mb-2"}," 创建新标签: ",-1)),t("div",Nt,[$(t("input",{"onUpdate:modelValue":n[3]||(n[3]=d=>T.value=d),type:"text",class:"form-input flex-1",placeholder:"输入新标签名称",onKeypress:nt(Q(g,["prevent"]),["enter"])},null,40,Bt),[[E,T.value]]),t("button",{type:"button",class:"px-4 py-2 bg-green-500 text-white rounded-lg hover:bg-green-600 transition-colors",onClick:g},n[33]||(n[33]=[t("i",{class:"fas fa-plus"},null,-1)]))])]),n[35]||(n[35]=t("p",{class:"text-xs text-gray-500"}," 用于标记不同团队或用途,方便筛选管理 ",-1))])]),t("div",Ht,[n[44]||(n[44]=t("div",{class:"flex items-center gap-2 mb-2"},[t("div",{class:"w-6 h-6 bg-blue-500 rounded flex items-center justify-center flex-shrink-0"},[t("i",{class:"fas fa-tachometer-alt text-white text-xs"})]),t("h4",{class:"font-semibold text-gray-800 text-sm"}," 速率限制设置 (可选) ")],-1)),t("div",Gt,[t("div",Qt,[t("div",null,[n[37]||(n[37]=t("label",{class:"block text-xs font-medium text-gray-700 mb-1"},"时间窗口 (分钟)",-1)),$(t("input",{"onUpdate:modelValue":n[4]||(n[4]=d=>e.rateLimitWindow=d),type:"number",min:"1",placeholder:"无限制",class:"form-input w-full text-sm"},null,512),[[E,e.rateLimitWindow]]),n[38]||(n[38]=t("p",{class:"text-xs text-gray-500 mt-0.5 ml-2"}," 时间段单位 ",-1))]),t("div",null,[n[39]||(n[39]=t("label",{class:"block text-xs font-medium text-gray-700 mb-1"},"请求次数限制",-1)),$(t("input",{"onUpdate:modelValue":n[5]||(n[5]=d=>e.rateLimitRequests=d),type:"number",min:"1",placeholder:"无限制",class:"form-input w-full text-sm"},null,512),[[E,e.rateLimitRequests]]),n[40]||(n[40]=t("p",{class:"text-xs text-gray-500 mt-0.5 ml-2"}," 窗口内最大请求 ",-1))]),t("div",null,[n[41]||(n[41]=t("label",{class:"block text-xs font-medium text-gray-700 mb-1"},"Token 限制",-1)),$(t("input",{"onUpdate:modelValue":n[6]||(n[6]=d=>e.tokenLimit=d),type:"number",placeholder:"无限制",class:"form-input w-full text-sm"},null,512),[[E,e.tokenLimit]]),n[42]||(n[42]=t("p",{class:"text-xs text-gray-500 mt-0.5 ml-2"}," 窗口内最大Token ",-1))])]),n[43]||(n[43]=t("div",{class:"bg-blue-100 rounded-lg p-2"},[t("h5",{class:"text-xs font-semibold text-blue-800 mb-1"}," 💡 使用示例 "),t("div",{class:"text-xs text-blue-700 space-y-0.5"},[t("div",null,[t("strong",null,"示例1:"),f(" 时间窗口=60,请求次数=1000 → 每60分钟最多1000次请求")]),t("div",null,[t("strong",null,"示例2:"),f(" 时间窗口=1,Token=10000 → 每分钟最多10,000个Token")]),t("div",null,[t("strong",null,"示例3:"),f(" 窗口=30,请求=50,Token=100000 → 每30分钟50次请求且不超10万Token")])])],-1))])]),t("div",null,[n[46]||(n[46]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},"每日费用限制 (美元)",-1)),t("div",Xt,[t("div",Jt,[t("button",{type:"button",class:"px-2 py-1 bg-gray-100 hover:bg-gray-200 rounded text-xs font-medium",onClick:n[7]||(n[7]=d=>e.dailyCostLimit="50")}," $50 "),t("button",{type:"button",class:"px-2 py-1 bg-gray-100 hover:bg-gray-200 rounded text-xs font-medium",onClick:n[8]||(n[8]=d=>e.dailyCostLimit="100")}," $100 "),t("button",{type:"button",class:"px-2 py-1 bg-gray-100 hover:bg-gray-200 rounded text-xs font-medium",onClick:n[9]||(n[9]=d=>e.dailyCostLimit="200")}," $200 "),t("button",{type:"button",class:"px-2 py-1 bg-gray-100 hover:bg-gray-200 rounded text-xs font-medium",onClick:n[10]||(n[10]=d=>e.dailyCostLimit="")}," 自定义 ")]),$(t("input",{"onUpdate:modelValue":n[11]||(n[11]=d=>e.dailyCostLimit=d),type:"number",min:"0",step:"0.01",placeholder:"0 表示无限制",class:"form-input w-full"},null,512),[[E,e.dailyCostLimit]]),n[45]||(n[45]=t("p",{class:"text-xs text-gray-500"}," 设置此 API Key 每日的费用限制,超过限制将拒绝请求,0 或留空表示无限制 ",-1))])]),t("div",null,[n[47]||(n[47]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},"并发限制 (可选)",-1)),$(t("input",{"onUpdate:modelValue":n[12]||(n[12]=d=>e.concurrencyLimit=d),type:"number",min:"0",placeholder:"0 表示无限制",class:"form-input w-full"},null,512),[[E,e.concurrencyLimit]]),n[48]||(n[48]=t("p",{class:"text-xs text-gray-500 mt-2"}," 设置此 API Key 可同时处理的最大请求数,0 或留空表示无限制 ",-1))]),t("div",null,[n[49]||(n[49]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},"备注 (可选)",-1)),$(t("textarea",{"onUpdate:modelValue":n[13]||(n[13]=d=>e.description=d),rows:"2",class:"form-input w-full resize-none text-sm",placeholder:"描述此 API Key 的用途..."},null,512),[[E,e.description]])]),t("div",null,[n[51]||(n[51]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},"有效期限",-1)),$(t("select",{"onUpdate:modelValue":n[14]||(n[14]=d=>e.expireDuration=d),class:"form-input w-full",onChange:j},n[50]||(n[50]=[t("option",{value:""}," 永不过期 ",-1),t("option",{value:"1d"}," 1 天 ",-1),t("option",{value:"7d"}," 7 天 ",-1),t("option",{value:"30d"}," 30 天 ",-1),t("option",{value:"90d"}," 90 天 ",-1),t("option",{value:"180d"}," 180 天 ",-1),t("option",{value:"365d"}," 365 天 ",-1),t("option",{value:"custom"}," 自定义日期 ",-1)]),544),[[H,e.expireDuration]]),e.expireDuration==="custom"?(i(),a("div",Zt,[$(t("input",{"onUpdate:modelValue":n[15]||(n[15]=d=>e.customExpireDate=d),type:"datetime-local",class:"form-input w-full",min:v.value,onChange:W},null,40,te),[[E,e.customExpireDate]])])):K("",!0),e.expiresAt?(i(),a("p",ee," 将于 "+u(z(e.expiresAt))+" 过期 ",1)):K("",!0)]),t("div",null,[n[55]||(n[55]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},"服务权限",-1)),t("div",se,[t("label",le,[$(t("input",{"onUpdate:modelValue":n[16]||(n[16]=d=>e.permissions=d),type:"radio",value:"all",class:"mr-2"},null,512),[[J,e.permissions]]),n[52]||(n[52]=t("span",{class:"text-sm text-gray-700"},"全部服务",-1))]),t("label",ne,[$(t("input",{"onUpdate:modelValue":n[17]||(n[17]=d=>e.permissions=d),type:"radio",value:"claude",class:"mr-2"},null,512),[[J,e.permissions]]),n[53]||(n[53]=t("span",{class:"text-sm text-gray-700"},"仅 Claude",-1))]),t("label",oe,[$(t("input",{"onUpdate:modelValue":n[18]||(n[18]=d=>e.permissions=d),type:"radio",value:"gemini",class:"mr-2"},null,512),[[J,e.permissions]]),n[54]||(n[54]=t("span",{class:"text-sm text-gray-700"},"仅 Gemini",-1))])]),n[56]||(n[56]=t("p",{class:"text-xs text-gray-500 mt-2"}," 控制此 API Key 可以访问哪些服务 ",-1))]),t("div",null,[n[61]||(n[61]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},"专属账号绑定 (可选)",-1)),t("div",ie,[t("div",null,[n[58]||(n[58]=t("label",{class:"block text-sm font-medium text-gray-600 mb-1"},"Claude 专属账号",-1)),$(t("select",{"onUpdate:modelValue":n[19]||(n[19]=d=>e.claudeAccountId=d),class:"form-input w-full",disabled:e.permissions==="gemini"},[n[57]||(n[57]=t("option",{value:""}," 使用共享账号池 ",-1)),(i(!0),a(V,null,q(L.accounts.claude.filter(d=>d.accountType==="dedicated"),d=>(i(),a("option",{key:d.id,value:d.id},u(d.name)+" ("+u(d.status==="active"?"正常":"异常")+") ",9,re))),128))],8,ae),[[H,e.claudeAccountId]])]),t("div",null,[n[60]||(n[60]=t("label",{class:"block text-sm font-medium text-gray-600 mb-1"},"Gemini 专属账号",-1)),$(t("select",{"onUpdate:modelValue":n[20]||(n[20]=d=>e.geminiAccountId=d),class:"form-input w-full",disabled:e.permissions==="claude"},[n[59]||(n[59]=t("option",{value:""}," 使用共享账号池 ",-1)),(i(!0),a(V,null,q(L.accounts.gemini.filter(d=>d.accountType==="dedicated"),d=>(i(),a("option",{key:d.id,value:d.id},u(d.name)+" ("+u(d.status==="active"?"正常":"异常")+") ",9,ue))),128))],8,de),[[H,e.geminiAccountId]])])]),n[62]||(n[62]=t("p",{class:"text-xs text-gray-500 mt-2"}," 选择专属账号后,此API Key将只使用该账号,不选择则使用共享账号池 ",-1))]),t("div",null,[t("div",me,[$(t("input",{id:"enableModelRestriction","onUpdate:modelValue":n[21]||(n[21]=d=>e.enableModelRestriction=d),type:"checkbox",class:"w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500"},null,512),[[Z,e.enableModelRestriction]]),n[63]||(n[63]=t("label",{for:"enableModelRestriction",class:"ml-2 text-sm font-semibold text-gray-700 cursor-pointer"}," 启用模型限制 ",-1))]),e.enableModelRestriction?(i(),a("div",pe,[t("div",null,[n[66]||(n[66]=t("label",{class:"block text-xs font-medium text-gray-700 mb-1"},"限制的模型列表",-1)),t("div",ce,[(i(!0),a(V,null,q(e.restrictedModels,(d,D)=>(i(),a("span",{key:D,class:"inline-flex items-center px-2 py-1 rounded-full text-xs bg-red-100 text-red-800"},[f(u(d)+" ",1),t("button",{type:"button",class:"ml-1 text-red-600 hover:text-red-800",onClick:G=>h(D)},n[64]||(n[64]=[t("i",{class:"fas fa-times text-xs"},null,-1)]),8,xe)]))),128)),e.restrictedModels.length===0?(i(),a("span",ye," 暂无限制的模型 ")):K("",!0)]),t("div",ge,[$(t("input",{"onUpdate:modelValue":n[22]||(n[22]=d=>e.modelInput=d),type:"text",placeholder:"输入模型名称,按回车添加",class:"form-input flex-1 text-sm",onKeydown:nt(Q(b,["prevent"]),["enter"])},null,40,fe),[[E,e.modelInput]]),t("button",{type:"button",class:"px-3 py-1.5 bg-red-500 text-white rounded-lg hover:bg-red-600 transition-colors text-sm",onClick:b},n[65]||(n[65]=[t("i",{class:"fas fa-plus"},null,-1)]))]),n[67]||(n[67]=t("p",{class:"text-xs text-gray-500 mt-1"}," 例如:claude-opus-4-20250514 ",-1))])])):K("",!0)]),t("div",null,[t("div",be,[$(t("input",{id:"enableClientRestriction","onUpdate:modelValue":n[23]||(n[23]=d=>e.enableClientRestriction=d),type:"checkbox",class:"w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500"},null,512),[[Z,e.enableClientRestriction]]),n[68]||(n[68]=t("label",{for:"enableClientRestriction",class:"ml-2 text-sm font-semibold text-gray-700 cursor-pointer"}," 启用客户端限制 ",-1))]),e.enableClientRestriction?(i(),a("div",ve,[t("div",null,[n[69]||(n[69]=t("label",{class:"block text-xs font-medium text-gray-700 mb-2"},"允许的客户端",-1)),t("div",we,[(i(!0),a(V,null,q(I.value,d=>(i(),a("div",{key:d.id,class:"flex items-start"},[$(t("input",{id:`client_${d.id}`,"onUpdate:modelValue":n[24]||(n[24]=D=>e.allowedClients=D),type:"checkbox",value:d.id,class:"w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 mt-0.5"},null,8,$e),[[Z,e.allowedClients]]),t("label",{for:`client_${d.id}`,class:"ml-2 flex-1 cursor-pointer"},[t("span",Ce,u(d.name),1),t("span",Ke,u(d.description),1)],8,Ae)]))),128))])])])):K("",!0)]),t("div",ke,[t("button",{type:"button",class:"flex-1 px-4 py-2.5 bg-gray-100 text-gray-700 rounded-lg font-semibold hover:bg-gray-200 transition-colors text-sm",onClick:n[25]||(n[25]=d=>w.$emit("close"))}," 取消 "),t("button",{type:"submit",disabled:y.value,class:"btn btn-primary flex-1 py-2.5 px-4 font-semibold text-sm"},[y.value?(i(),a("div",Le)):(i(),a("i",Ie)),f(" "+u(y.value?"创建中...":"创建"),1)],8,he)])],32)])])]))}},Re=et(De,[["__scopeId","data-v-675bffce"]]),Me={class:"fixed inset-0 modal z-50 flex items-center justify-center p-4"},Se={class:"modal-content w-full max-w-4xl p-8 mx-auto max-h-[90vh] flex flex-col"},Te={class:"flex items-center justify-between mb-6"},_e=["value"],Pe={class:"space-y-4"},Ee={key:0},Ve={class:"flex flex-wrap gap-2"},je=["onClick"],Ue={key:1},qe={class:"flex flex-wrap gap-2"},Oe=["onClick"],Fe={class:"flex gap-2"},We=["onKeypress"],Ye={class:"bg-blue-50 border border-blue-200 rounded-lg p-3"},ze={class:"space-y-2"},Ne={class:"grid grid-cols-1 lg:grid-cols-3 gap-2"},Be={class:"space-y-3"},He={class:"flex gap-2"},Ge={class:"flex gap-4"},Qe={class:"flex items-center cursor-pointer"},Xe={class:"flex items-center cursor-pointer"},Je={class:"flex items-center cursor-pointer"},Ze={class:"grid grid-cols-1 gap-3"},ts=["disabled"],es=["value"],ss=["disabled"],ls=["value"],ns={class:"flex items-center mb-3"},os={key:0,class:"space-y-3"},is={class:"flex flex-wrap gap-2 mb-3 min-h-[32px] p-2 bg-gray-50 rounded-lg border border-gray-200"},as=["onClick"],rs={key:0,class:"text-gray-400 text-sm"},ds={class:"flex gap-2"},us=["onKeydown"],ms={class:"flex items-center mb-3"},ps={key:0,class:"space-y-3"},cs={class:"space-y-2"},xs=["id","value"],ys=["for"],gs={class:"text-sm font-medium text-gray-700"},fs={class:"text-xs text-gray-500 block"},bs={class:"flex gap-3 pt-4"},vs=["disabled"],ws={key:0,class:"loading-spinner mr-2"},$s={key:1,class:"fas fa-save mr-2"},As={__name:"EditApiKeyModal",props:{apiKey:{type:Object,required:!0},accounts:{type:Object,default:()=>({claude:[],gemini:[]})}},emits:["close","success"],setup(L,{emit:R}){const c=L,_=R;ut();const M=mt(),y=bt(),k=A(!1),T=A([]),C=A(""),O=A([]),I=tt(()=>O.value.filter(g=>!e.tags.includes(g))),e=rt({name:"",tokenLimit:"",rateLimitWindow:"",rateLimitRequests:"",concurrencyLimit:"",dailyCostLimit:"",permissions:"all",claudeAccountId:"",geminiAccountId:"",enableModelRestriction:!1,restrictedModels:[],modelInput:"",enableClientRestriction:!1,allowedClients:[],tags:[]}),v=()=>{e.modelInput&&!e.restrictedModels.includes(e.modelInput)&&(e.restrictedModels.push(e.modelInput),e.modelInput="")},j=g=>{e.restrictedModels.splice(g,1)},W=()=>{if(C.value&&C.value.trim()){const g=C.value.trim();e.tags.includes(g)||e.tags.push(g),C.value=""}},z=g=>{e.tags.includes(g)||e.tags.push(g)},b=g=>{e.tags.splice(g,1)},h=async()=>{k.value=!0;try{const g={tokenLimit:e.tokenLimit!==""&&e.tokenLimit!==null?parseInt(e.tokenLimit):0,rateLimitWindow:e.rateLimitWindow!==""&&e.rateLimitWindow!==null?parseInt(e.rateLimitWindow):0,rateLimitRequests:e.rateLimitRequests!==""&&e.rateLimitRequests!==null?parseInt(e.rateLimitRequests):0,concurrencyLimit:e.concurrencyLimit!==""&&e.concurrencyLimit!==null?parseInt(e.concurrencyLimit):0,dailyCostLimit:e.dailyCostLimit!==""&&e.dailyCostLimit!==null?parseFloat(e.dailyCostLimit):0,permissions:e.permissions,claudeAccountId:e.claudeAccountId||null,geminiAccountId:e.geminiAccountId||null,tags:e.tags};g.enableModelRestriction=e.enableModelRestriction,g.restrictedModels=e.restrictedModels,g.enableClientRestriction=e.enableClientRestriction,g.allowedClients=e.allowedClients;const o=await U.put(`/admin/api-keys/${c.apiKey.id}`,g);o.success?(_("success"),_("close")):S(o.message||"更新失败","error")}catch{S("更新失败","error")}finally{k.value=!1}};return dt(async()=>{T.value=await M.loadSupportedClients(),O.value=await y.fetchTags(),e.name=c.apiKey.name,e.tokenLimit=c.apiKey.tokenLimit||"",e.rateLimitWindow=c.apiKey.rateLimitWindow||"",e.rateLimitRequests=c.apiKey.rateLimitRequests||"",e.concurrencyLimit=c.apiKey.concurrencyLimit||"",e.dailyCostLimit=c.apiKey.dailyCostLimit||"",e.permissions=c.apiKey.permissions||"all",e.claudeAccountId=c.apiKey.claudeAccountId||"",e.geminiAccountId=c.apiKey.geminiAccountId||"",e.restrictedModels=c.apiKey.restrictedModels||[],e.allowedClients=c.apiKey.allowedClients||[],e.tags=c.apiKey.tags||[],e.enableModelRestriction=c.apiKey.enableModelRestriction||!1,e.enableClientRestriction=c.apiKey.enableClientRestriction||!1}),(g,o)=>(i(),B(ot,{to:"body"},[t("div",Me,[t("div",Se,[t("div",Te,[o[22]||(o[22]=t("div",{class:"flex items-center gap-3"},[t("div",{class:"w-10 h-10 bg-gradient-to-br from-blue-500 to-blue-600 rounded-xl flex items-center justify-center"},[t("i",{class:"fas fa-edit text-white"})]),t("h3",{class:"text-xl font-bold text-gray-900"}," 编辑 API Key ")],-1)),t("button",{class:"text-gray-400 hover:text-gray-600 transition-colors",onClick:o[0]||(o[0]=m=>g.$emit("close"))},o[21]||(o[21]=[t("i",{class:"fas fa-times text-xl"},null,-1)]))]),t("form",{class:"space-y-6 modal-scroll-content custom-scrollbar flex-1",onSubmit:Q(h,["prevent"])},[t("div",null,[o[23]||(o[23]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"名称",-1)),t("input",{value:e.name,type:"text",disabled:"",class:"form-input w-full bg-gray-100 cursor-not-allowed"},null,8,_e),o[24]||(o[24]=t("p",{class:"text-xs text-gray-500 mt-2"}," 名称不可修改 ",-1))]),t("div",null,[o[32]||(o[32]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"标签",-1)),t("div",Pe,[e.tags.length>0?(i(),a("div",Ee,[o[26]||(o[26]=t("div",{class:"text-xs font-medium text-gray-600 mb-2"}," 已选择的标签: ",-1)),t("div",Ve,[(i(!0),a(V,null,q(e.tags,(m,Y)=>(i(),a("span",{key:"selected-"+Y,class:"inline-flex items-center gap-1 px-3 py-1 bg-blue-100 text-blue-800 text-sm rounded-full"},[f(u(m)+" ",1),t("button",{type:"button",class:"ml-1 hover:text-blue-900",onClick:w=>b(Y)},o[25]||(o[25]=[t("i",{class:"fas fa-times text-xs"},null,-1)]),8,je)]))),128))])])):K("",!0),I.value.length>0?(i(),a("div",Ue,[o[28]||(o[28]=t("div",{class:"text-xs font-medium text-gray-600 mb-2"}," 点击选择已有标签: ",-1)),t("div",qe,[(i(!0),a(V,null,q(I.value,m=>(i(),a("button",{key:"available-"+m,type:"button",class:"inline-flex items-center gap-1 px-3 py-1 bg-gray-100 text-gray-700 text-sm rounded-full hover:bg-blue-100 hover:text-blue-700 transition-colors",onClick:Y=>z(m)},[o[27]||(o[27]=t("i",{class:"fas fa-tag text-gray-500 text-xs"},null,-1)),f(" "+u(m),1)],8,Oe))),128))])])):K("",!0),t("div",null,[o[30]||(o[30]=t("div",{class:"text-xs font-medium text-gray-600 mb-2"}," 创建新标签: ",-1)),t("div",Fe,[$(t("input",{"onUpdate:modelValue":o[1]||(o[1]=m=>C.value=m),type:"text",class:"form-input flex-1",placeholder:"输入新标签名称",onKeypress:nt(Q(W,["prevent"]),["enter"])},null,40,We),[[E,C.value]]),t("button",{type:"button",class:"px-4 py-2 bg-green-500 text-white rounded-lg hover:bg-green-600 transition-colors",onClick:W},o[29]||(o[29]=[t("i",{class:"fas fa-plus"},null,-1)]))])]),o[31]||(o[31]=t("p",{class:"text-xs text-gray-500"}," 用于标记不同团队或用途,方便筛选管理 ",-1))])]),t("div",Ye,[o[40]||(o[40]=t("div",{class:"flex items-center gap-2 mb-2"},[t("div",{class:"w-6 h-6 bg-blue-500 rounded flex items-center justify-center flex-shrink-0"},[t("i",{class:"fas fa-tachometer-alt text-white text-xs"})]),t("h4",{class:"font-semibold text-gray-800 text-sm"}," 速率限制设置 (可选) ")],-1)),t("div",ze,[t("div",Ne,[t("div",null,[o[33]||(o[33]=t("label",{class:"block text-xs font-medium text-gray-700 mb-1"},"时间窗口 (分钟)",-1)),$(t("input",{"onUpdate:modelValue":o[2]||(o[2]=m=>e.rateLimitWindow=m),type:"number",min:"1",placeholder:"无限制",class:"form-input w-full text-sm"},null,512),[[E,e.rateLimitWindow]]),o[34]||(o[34]=t("p",{class:"text-xs text-gray-500 mt-0.5 ml-2"}," 时间段单位 ",-1))]),t("div",null,[o[35]||(o[35]=t("label",{class:"block text-xs font-medium text-gray-700 mb-1"},"请求次数限制",-1)),$(t("input",{"onUpdate:modelValue":o[3]||(o[3]=m=>e.rateLimitRequests=m),type:"number",min:"1",placeholder:"无限制",class:"form-input w-full text-sm"},null,512),[[E,e.rateLimitRequests]]),o[36]||(o[36]=t("p",{class:"text-xs text-gray-500 mt-0.5 ml-2"}," 窗口内最大请求 ",-1))]),t("div",null,[o[37]||(o[37]=t("label",{class:"block text-xs font-medium text-gray-700 mb-1"},"Token 限制",-1)),$(t("input",{"onUpdate:modelValue":o[4]||(o[4]=m=>e.tokenLimit=m),type:"number",placeholder:"无限制",class:"form-input w-full text-sm"},null,512),[[E,e.tokenLimit]]),o[38]||(o[38]=t("p",{class:"text-xs text-gray-500 mt-0.5 ml-2"}," 窗口内最大Token ",-1))])]),o[39]||(o[39]=t("div",{class:"bg-blue-100 rounded-lg p-2"},[t("h5",{class:"text-xs font-semibold text-blue-800 mb-1"}," 💡 使用示例 "),t("div",{class:"text-xs text-blue-700 space-y-0.5"},[t("div",null,[t("strong",null,"示例1:"),f(" 时间窗口=60,请求次数=1000 → 每60分钟最多1000次请求")]),t("div",null,[t("strong",null,"示例2:"),f(" 时间窗口=1,Token=10000 → 每分钟最多10,000个Token")]),t("div",null,[t("strong",null,"示例3:"),f(" 窗口=30,请求=50,Token=100000 → 每30分钟50次请求且不超10万Token")])])],-1))])]),t("div",null,[o[42]||(o[42]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"每日费用限制 (美元)",-1)),t("div",Be,[t("div",He,[t("button",{type:"button",class:"px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded-lg text-sm font-medium",onClick:o[5]||(o[5]=m=>e.dailyCostLimit="50")}," $50 "),t("button",{type:"button",class:"px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded-lg text-sm font-medium",onClick:o[6]||(o[6]=m=>e.dailyCostLimit="100")}," $100 "),t("button",{type:"button",class:"px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded-lg text-sm font-medium",onClick:o[7]||(o[7]=m=>e.dailyCostLimit="200")}," $200 "),t("button",{type:"button",class:"px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded-lg text-sm font-medium",onClick:o[8]||(o[8]=m=>e.dailyCostLimit="")}," 自定义 ")]),$(t("input",{"onUpdate:modelValue":o[9]||(o[9]=m=>e.dailyCostLimit=m),type:"number",min:"0",step:"0.01",placeholder:"0 表示无限制",class:"form-input w-full"},null,512),[[E,e.dailyCostLimit]]),o[41]||(o[41]=t("p",{class:"text-xs text-gray-500"}," 设置此 API Key 每日的费用限制,超过限制将拒绝请求,0 或留空表示无限制 ",-1))])]),t("div",null,[o[43]||(o[43]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"并发限制",-1)),$(t("input",{"onUpdate:modelValue":o[10]||(o[10]=m=>e.concurrencyLimit=m),type:"number",min:"0",placeholder:"0 表示无限制",class:"form-input w-full"},null,512),[[E,e.concurrencyLimit]]),o[44]||(o[44]=t("p",{class:"text-xs text-gray-500 mt-2"}," 设置此 API Key 可同时处理的最大请求数 ",-1))]),t("div",null,[o[48]||(o[48]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"服务权限",-1)),t("div",Ge,[t("label",Qe,[$(t("input",{"onUpdate:modelValue":o[11]||(o[11]=m=>e.permissions=m),type:"radio",value:"all",class:"mr-2"},null,512),[[J,e.permissions]]),o[45]||(o[45]=t("span",{class:"text-sm text-gray-700"},"全部服务",-1))]),t("label",Xe,[$(t("input",{"onUpdate:modelValue":o[12]||(o[12]=m=>e.permissions=m),type:"radio",value:"claude",class:"mr-2"},null,512),[[J,e.permissions]]),o[46]||(o[46]=t("span",{class:"text-sm text-gray-700"},"仅 Claude",-1))]),t("label",Je,[$(t("input",{"onUpdate:modelValue":o[13]||(o[13]=m=>e.permissions=m),type:"radio",value:"gemini",class:"mr-2"},null,512),[[J,e.permissions]]),o[47]||(o[47]=t("span",{class:"text-sm text-gray-700"},"仅 Gemini",-1))])]),o[49]||(o[49]=t("p",{class:"text-xs text-gray-500 mt-2"}," 控制此 API Key 可以访问哪些服务 ",-1))]),t("div",null,[o[54]||(o[54]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"专属账号绑定",-1)),t("div",Ze,[t("div",null,[o[51]||(o[51]=t("label",{class:"block text-sm font-medium text-gray-600 mb-1"},"Claude 专属账号",-1)),$(t("select",{"onUpdate:modelValue":o[14]||(o[14]=m=>e.claudeAccountId=m),class:"form-input w-full",disabled:e.permissions==="gemini"},[o[50]||(o[50]=t("option",{value:""}," 使用共享账号池 ",-1)),(i(!0),a(V,null,q(L.accounts.claude,m=>(i(),a("option",{key:m.id,value:m.id},u(m.name)+" ("+u(m.status==="active"?"正常":"异常")+") ",9,es))),128))],8,ts),[[H,e.claudeAccountId]])]),t("div",null,[o[53]||(o[53]=t("label",{class:"block text-sm font-medium text-gray-600 mb-1"},"Gemini 专属账号",-1)),$(t("select",{"onUpdate:modelValue":o[15]||(o[15]=m=>e.geminiAccountId=m),class:"form-input w-full",disabled:e.permissions==="claude"},[o[52]||(o[52]=t("option",{value:""}," 使用共享账号池 ",-1)),(i(!0),a(V,null,q(L.accounts.gemini,m=>(i(),a("option",{key:m.id,value:m.id},u(m.name)+" ("+u(m.status==="active"?"正常":"异常")+") ",9,ls))),128))],8,ss),[[H,e.geminiAccountId]])])]),o[55]||(o[55]=t("p",{class:"text-xs text-gray-500 mt-2"}," 修改绑定账号将影响此API Key的请求路由 ",-1))]),t("div",null,[t("div",ns,[$(t("input",{id:"editEnableModelRestriction","onUpdate:modelValue":o[16]||(o[16]=m=>e.enableModelRestriction=m),type:"checkbox",class:"w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500"},null,512),[[Z,e.enableModelRestriction]]),o[56]||(o[56]=t("label",{for:"editEnableModelRestriction",class:"ml-2 text-sm font-semibold text-gray-700 cursor-pointer"}," 启用模型限制 ",-1))]),e.enableModelRestriction?(i(),a("div",os,[t("div",null,[o[59]||(o[59]=t("label",{class:"block text-sm font-medium text-gray-600 mb-2"},"限制的模型列表",-1)),t("div",is,[(i(!0),a(V,null,q(e.restrictedModels,(m,Y)=>(i(),a("span",{key:Y,class:"inline-flex items-center px-3 py-1 rounded-full text-sm bg-red-100 text-red-800"},[f(u(m)+" ",1),t("button",{type:"button",class:"ml-2 text-red-600 hover:text-red-800",onClick:w=>j(Y)},o[57]||(o[57]=[t("i",{class:"fas fa-times text-xs"},null,-1)]),8,as)]))),128)),e.restrictedModels.length===0?(i(),a("span",rs," 暂无限制的模型 ")):K("",!0)]),t("div",ds,[$(t("input",{"onUpdate:modelValue":o[17]||(o[17]=m=>e.modelInput=m),type:"text",placeholder:"输入模型名称,按回车添加",class:"form-input flex-1",onKeydown:nt(Q(v,["prevent"]),["enter"])},null,40,us),[[E,e.modelInput]]),t("button",{type:"button",class:"px-4 py-2 bg-red-500 text-white rounded-lg hover:bg-red-600 transition-colors",onClick:v},o[58]||(o[58]=[t("i",{class:"fas fa-plus"},null,-1)]))]),o[60]||(o[60]=t("p",{class:"text-xs text-gray-500 mt-2"}," 设置此API Key无法访问的模型,例如:claude-opus-4-20250514 ",-1))])])):K("",!0)]),t("div",null,[t("div",ms,[$(t("input",{id:"editEnableClientRestriction","onUpdate:modelValue":o[18]||(o[18]=m=>e.enableClientRestriction=m),type:"checkbox",class:"w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500"},null,512),[[Z,e.enableClientRestriction]]),o[61]||(o[61]=t("label",{for:"editEnableClientRestriction",class:"ml-2 text-sm font-semibold text-gray-700 cursor-pointer"}," 启用客户端限制 ",-1))]),e.enableClientRestriction?(i(),a("div",ps,[t("div",null,[o[62]||(o[62]=t("label",{class:"block text-sm font-medium text-gray-600 mb-2"},"允许的客户端",-1)),o[63]||(o[63]=t("p",{class:"text-xs text-gray-500 mb-3"}," 勾选允许使用此API Key的客户端 ",-1)),t("div",cs,[(i(!0),a(V,null,q(T.value,m=>(i(),a("div",{key:m.id,class:"flex items-start"},[$(t("input",{id:`edit_client_${m.id}`,"onUpdate:modelValue":o[19]||(o[19]=Y=>e.allowedClients=Y),type:"checkbox",value:m.id,class:"w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 mt-0.5"},null,8,xs),[[Z,e.allowedClients]]),t("label",{for:`edit_client_${m.id}`,class:"ml-2 flex-1 cursor-pointer"},[t("span",gs,u(m.name),1),t("span",fs,u(m.description),1)],8,ys)]))),128))])])])):K("",!0)]),t("div",bs,[t("button",{type:"button",class:"flex-1 px-6 py-3 bg-gray-100 text-gray-700 rounded-xl font-semibold hover:bg-gray-200 transition-colors",onClick:o[20]||(o[20]=m=>g.$emit("close"))}," 取消 "),t("button",{type:"submit",disabled:k.value,class:"btn btn-primary flex-1 py-3 px-6 font-semibold"},[k.value?(i(),a("div",ws)):(i(),a("i",$s)),f(" "+u(k.value?"保存中...":"保存修改"),1)],8,vs)])],32)])])]))}},Cs=et(As,[["__scopeId","data-v-f70072fe"]]),Ks={class:"fixed inset-0 modal z-50 flex items-center justify-center p-4"},ks={class:"modal-content w-full max-w-md p-8 mx-auto max-h-[90vh] flex flex-col"},hs={class:"flex items-center justify-between mb-6"},Ls={class:"space-y-6 modal-scroll-content custom-scrollbar flex-1"},Is={class:"bg-blue-50 border border-blue-200 rounded-lg p-4"},Ds={class:"flex items-start gap-3"},Rs={class:"text-sm text-gray-700"},Ms={class:"text-xs text-gray-600 mt-1"},Ss={key:0,class:"mt-3"},Ts=["min"],_s={key:1,class:"text-xs text-gray-500 mt-2"},Ps={class:"flex gap-3 pt-4"},Es=["disabled"],Vs={key:0,class:"loading-spinner mr-2"},js={key:1,class:"fas fa-clock mr-2"},Us={__name:"RenewApiKeyModal",props:{apiKey:{type:Object,required:!0}},emits:["close","success"],setup(L,{emit:R}){const c=L,_=R;ut();const M=A(!1),y=rt({renewDuration:"30d",customExpireDate:"",newExpiresAt:null}),k=tt(()=>{const e=new Date;return c.apiKey.expiresAt&&new Date(c.apiKey.expiresAt)>e?new Date(c.apiKey.expiresAt).toISOString().slice(0,16):(e.setMinutes(e.getMinutes()+1),e.toISOString().slice(0,16))}),T=e=>new Date(e).toLocaleString("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"}),C=()=>{if(!y.renewDuration){y.newExpiresAt=null;return}if(y.renewDuration==="permanent"){y.newExpiresAt=null;return}if(y.renewDuration==="custom")return;const e=c.apiKey.expiresAt&&new Date(c.apiKey.expiresAt)>new Date?new Date(c.apiKey.expiresAt):new Date,j=y.renewDuration.match(/(\d+)([dhmy])/);if(j){const[,W,z]=j,b=parseInt(W);switch(z){case"d":e.setDate(e.getDate()+b);break;case"h":e.setHours(e.getHours()+b);break;case"m":e.setMonth(e.getMonth()+b);break;case"y":e.setFullYear(e.getFullYear()+b);break}y.newExpiresAt=e.toISOString()}},O=()=>{y.customExpireDate&&(y.newExpiresAt=new Date(y.customExpireDate).toISOString())},I=async()=>{M.value=!0;try{const e={expiresAt:y.renewDuration==="permanent"?null:y.newExpiresAt},v=await U.put(`/admin/api-keys/${c.apiKey.id}/renew`,e);v.success?(S("API Key 续期成功","success"),_("success"),_("close")):S(v.message||"续期失败","error")}catch{S("续期失败","error")}finally{M.value=!1}};return C(),(e,v)=>(i(),B(ot,{to:"body"},[t("div",Ks,[t("div",ks,[t("div",hs,[v[5]||(v[5]=t("div",{class:"flex items-center gap-3"},[t("div",{class:"w-10 h-10 bg-gradient-to-br from-green-500 to-green-600 rounded-xl flex items-center justify-center"},[t("i",{class:"fas fa-clock text-white"})]),t("h3",{class:"text-xl font-bold text-gray-900"}," 续期 API Key ")],-1)),t("button",{class:"text-gray-400 hover:text-gray-600 transition-colors",onClick:v[0]||(v[0]=j=>e.$emit("close"))},v[4]||(v[4]=[t("i",{class:"fas fa-times text-xl"},null,-1)]))]),t("div",Ls,[t("div",Is,[t("div",Ds,[v[7]||(v[7]=t("div",{class:"w-8 h-8 bg-blue-500 rounded-lg flex items-center justify-center flex-shrink-0"},[t("i",{class:"fas fa-info text-white text-sm"})],-1)),t("div",null,[v[6]||(v[6]=t("h4",{class:"font-semibold text-gray-800 mb-1"}," API Key 信息 ",-1)),t("p",Rs,u(L.apiKey.name),1),t("p",Ms," 当前过期时间:"+u(L.apiKey.expiresAt?T(L.apiKey.expiresAt):"永不过期"),1)])])]),t("div",null,[v[9]||(v[9]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"续期时长",-1)),$(t("select",{"onUpdate:modelValue":v[1]||(v[1]=j=>y.renewDuration=j),class:"form-input w-full",onChange:C},v[8]||(v[8]=[t("option",{value:"7d"}," 延长 7 天 ",-1),t("option",{value:"30d"}," 延长 30 天 ",-1),t("option",{value:"90d"}," 延长 90 天 ",-1),t("option",{value:"180d"}," 延长 180 天 ",-1),t("option",{value:"365d"}," 延长 365 天 ",-1),t("option",{value:"custom"}," 自定义日期 ",-1),t("option",{value:"permanent"}," 设为永不过期 ",-1)]),544),[[H,y.renewDuration]]),y.renewDuration==="custom"?(i(),a("div",Ss,[$(t("input",{"onUpdate:modelValue":v[2]||(v[2]=j=>y.customExpireDate=j),type:"datetime-local",class:"form-input w-full",min:k.value,onChange:O},null,40,Ts),[[E,y.customExpireDate]])])):K("",!0),y.newExpiresAt?(i(),a("p",_s," 新的过期时间:"+u(T(y.newExpiresAt)),1)):K("",!0)])]),t("div",Ps,[t("button",{type:"button",class:"flex-1 px-6 py-3 bg-gray-100 text-gray-700 rounded-xl font-semibold hover:bg-gray-200 transition-colors",onClick:v[3]||(v[3]=j=>e.$emit("close"))}," 取消 "),t("button",{type:"button",disabled:M.value||!y.renewDuration,class:"btn btn-primary flex-1 py-3 px-6 font-semibold",onClick:I},[M.value?(i(),a("div",Vs)):(i(),a("i",js)),f(" "+u(M.value?"续期中...":"确认续期"),1)],8,Es)])])])]))}},qs=et(Us,[["__scopeId","data-v-0c3b1b3f"]]),Os={class:"fixed inset-0 modal z-50 flex items-center justify-center p-4"},Fs={class:"modal-content w-full max-w-lg p-8 mx-auto max-h-[90vh] overflow-y-auto custom-scrollbar"},Ws={class:"space-y-4 mb-6"},Ys={class:"p-3 bg-gray-50 rounded-lg border"},zs={class:"text-gray-900 font-medium"},Ns={key:0},Bs={class:"p-3 bg-gray-50 rounded-lg border"},Hs={class:"text-gray-700"},Gs={class:"relative"},Qs={class:"p-4 pr-14 bg-gray-900 rounded-lg border font-mono text-sm text-white break-all min-h-[60px] flex items-center"},Xs={class:"absolute top-3 right-3"},Js=["title"],Zs={__name:"NewApiKeyModal",props:{apiKey:{type:Object,required:!0}},emits:["close"],setup(L,{emit:R}){const c=L,_=R,M=A(!1),y=()=>{M.value=!M.value},k=()=>{const I=c.apiKey.apiKey||c.apiKey.key||"";return I?M.value||I.length<=12?I:I.substring(0,8)+"●".repeat(Math.max(0,I.length-12))+I.substring(I.length-4):""},T=async()=>{const I=c.apiKey.apiKey||c.apiKey.key||"";if(!I){S("API Key 不存在","error");return}try{await navigator.clipboard.writeText(I),S("API Key 已复制到剪贴板","success")}catch(e){console.error("Failed to copy:",e);const v=document.createElement("textarea");v.value=I,document.body.appendChild(v),v.select();try{document.execCommand("copy"),S("API Key 已复制到剪贴板","success")}catch{S("复制失败,请手动复制","error")}finally{document.body.removeChild(v)}}},C=async()=>{window.showConfirm?await window.showConfirm("关闭提醒",`关闭后将无法再次查看完整的API Key,请确保已经妥善保存。
确定要关闭吗?`,"确定关闭","取消")&&_("close"):confirm(`关闭后将无法再次查看完整的API Key,请确保已经妥善保存。
diff --git a/web/admin-spa/dist/assets/ApiStatsView-D9E2vriK.js b/web/admin-spa/dist/assets/ApiStatsView-CUnItdoW.js
similarity index 99%
rename from web/admin-spa/dist/assets/ApiStatsView-D9E2vriK.js
rename to web/admin-spa/dist/assets/ApiStatsView-CUnItdoW.js
index 6e7e8606..a08fbb41 100644
--- a/web/admin-spa/dist/assets/ApiStatsView-D9E2vriK.js
+++ b/web/admin-spa/dist/assets/ApiStatsView-CUnItdoW.js
@@ -1 +1 @@
-import{aR as B,r as $,c as J,aW as A,x as f,y as m,z as t,O as y,K as H,aq as Q,u as s,aa as G,f as X,P as r,C as P,L as C,Q as O,ac as F,q as Z,aU as tt,V as st,o as et,R as S,J as at,av as it}from"./vue-vendor-CKToUHZx.js";import{L as ot}from"./LogoTitle-Bg7KLvUv.js";import{_ as K}from"./index-D7YURYF2.js";import{b as nt}from"./vendor-BDiMbLwQ.js";import lt from"./TutorialView-BPaY-imZ.js";/* empty css */import"./element-plus-B8Fs_0jW.js";class rt{constructor(){this.baseURL=window.location.origin,this.isDev=!1}async request(n,a={}){try{this.isDev&&n.startsWith("/admin")&&(n="/webapi"+n);const l=await fetch(`${this.baseURL}${n}`,{headers:{"Content-Type":"application/json",...a.headers},...a}),c=await l.json();if(!l.ok)throw new Error(c.message||`请求失败: ${l.status}`);return c}catch(l){throw console.error("API Stats request error:",l),l}}async getKeyId(n){return this.request("/apiStats/api/get-key-id",{method:"POST",body:JSON.stringify({apiKey:n})})}async getUserStats(n){return this.request("/apiStats/api/user-stats",{method:"POST",body:JSON.stringify({apiId:n})})}async getUserModelStats(n,a="daily"){return this.request("/apiStats/api/user-model-stats",{method:"POST",body:JSON.stringify({apiId:n,period:a})})}async getOemSettings(){try{return await this.request("/admin/oem-settings")}catch(n){return console.error("Failed to load OEM settings:",n),{success:!0,data:{siteName:"Claude Relay Service",siteIcon:"",siteIconData:""}}}}}const D=new rt,M=B("apistats",()=>{const w=$(""),n=$(null),a=$(!1),l=$(!1),c=$(!0),e=$(""),i=$("daily"),d=$(null),v=$([]),_=$(null),h=$(null),x=$({siteName:"",siteIcon:"",siteIconData:""}),u=J(()=>{const o={requests:0,inputTokens:0,outputTokens:0,cacheCreateTokens:0,cacheReadTokens:0,allTokens:0,cost:0,formattedCost:"$0.000000"};return i.value==="daily"?_.value||o:h.value||o}),U=J(()=>{if(!d.value||!u.value)return{tokenUsage:0,costUsage:0,requestUsage:0};const o=u.value,g=d.value.limits;return{tokenUsage:g.tokenLimit>0?Math.min(o.allTokens/g.tokenLimit*100,100):0,costUsage:g.dailyCostLimit>0?Math.min(o.cost/g.dailyCostLimit*100,100):0,requestUsage:g.rateLimitRequests>0?Math.min(o.requests/g.rateLimitRequests*100,100):0}});async function T(){if(!w.value.trim()){e.value="请输入 API Key";return}a.value=!0,e.value="",d.value=null,v.value=[],n.value=null;try{const o=await D.getKeyId(w.value);if(o.success){n.value=o.data.id;const g=await D.getUserStats(n.value);if(g.success)d.value=g.data,await R(),e.value="",j();else throw new Error(g.message||"查询失败")}else throw new Error(o.message||"获取 API Key ID 失败")}catch(o){console.error("Query stats error:",o),e.value=o.message||"查询统计数据失败,请检查您的 API Key 是否正确",d.value=null,v.value=[],n.value=null}finally{a.value=!1}}async function R(){n.value&&(await Promise.all([L("daily"),L("monthly")]),await q(i.value))}async function L(o){try{const g=await D.getUserModelStats(n.value,o);if(g.success){const z=g.data||[],k={requests:0,inputTokens:0,outputTokens:0,cacheCreateTokens:0,cacheReadTokens:0,allTokens:0,cost:0,formattedCost:"$0.000000"};z.forEach(I=>{var W;k.requests+=I.requests||0,k.inputTokens+=I.inputTokens||0,k.outputTokens+=I.outputTokens||0,k.cacheCreateTokens+=I.cacheCreateTokens||0,k.cacheReadTokens+=I.cacheReadTokens||0,k.allTokens+=I.allTokens||0,k.cost+=((W=I.costs)==null?void 0:W.total)||0}),k.formattedCost=N(k.cost),o==="daily"?_.value=k:h.value=k}else console.warn(`Failed to load ${o} stats:`,g.message)}catch(g){console.error(`Load ${o} stats error:`,g)}}async function q(o="daily"){if(n.value){l.value=!0;try{const g=await D.getUserModelStats(n.value,o);if(g.success)v.value=g.data||[];else throw new Error(g.message||"加载模型统计失败")}catch(g){console.error("Load model stats error:",g),v.value=[]}finally{l.value=!1}}}async function E(o){i.value===o||l.value||(i.value=o,(o==="daily"&&!_.value||o==="monthly"&&!h.value)&&await L(o),await q(o))}async function b(){if(n.value){a.value=!0,e.value="",d.value=null,v.value=[];try{const o=await D.getUserStats(n.value);if(o.success)d.value=o.data,await R(),e.value="";else throw new Error(o.message||"查询失败")}catch(o){console.error("Load stats with apiId error:",o),e.value=o.message||"查询统计数据失败",d.value=null,v.value=[]}finally{a.value=!1}}}async function p(){c.value=!0;try{const o=await D.getOemSettings();o&&o.success&&o.data&&(x.value={...x.value,...o.data})}catch(o){console.error("Error loading OEM settings:",o),x.value={siteName:"Claude Relay Service",siteIcon:"",siteIconData:""}}finally{c.value=!1}}function N(o){return typeof o!="number"||o===0?"$0.000000":o>=1?"$"+o.toFixed(2):o>=.01?"$"+o.toFixed(4):"$"+o.toFixed(6)}function j(){if(n.value){const o=new URL(window.location);o.searchParams.set("apiId",n.value),window.history.pushState({},"",o)}}function V(){d.value=null,v.value=[],_.value=null,h.value=null,e.value="",i.value="daily",n.value=null}function Y(){w.value="",V()}return{apiKey:w,apiId:n,loading:a,modelStatsLoading:l,oemLoading:c,error:e,statsPeriod:i,statsData:d,modelStats:v,dailyStats:_,monthlyStats:h,oemSettings:x,currentPeriodData:u,usagePercentages:U,queryStats:T,loadAllPeriodStats:R,loadPeriodStats:L,loadModelStats:q,switchPeriod:E,loadStatsWithApiId:b,loadOemSettings:p,clearData:V,reset:Y}}),dt={class:"api-input-wide-card glass-strong rounded-3xl p-6 mb-8 shadow-xl"},ct={class:"max-w-4xl mx-auto"},ut={class:"api-input-grid grid grid-cols-1 lg:grid-cols-4"},ft={class:"lg:col-span-3"},mt=["disabled"],xt={class:"lg:col-span-1"},yt=["disabled"],pt={key:0,class:"fas fa-spinner loading-spinner"},gt={key:1,class:"fas fa-search"},vt={__name:"ApiKeyInput",setup(w){const n=M(),{apiKey:a,loading:l}=A(n),{queryStats:c}=n;return(e,i)=>(m(),f("div",dt,[i[6]||(i[6]=t("div",{class:"wide-card-title text-center mb-6"},[t("h2",{class:"text-2xl font-bold mb-2"},[t("i",{class:"fas fa-chart-line mr-3"}),y(" 使用统计查询 ")]),t("p",{class:"text-base text-gray-600"}," 查询您的 API Key 使用情况和统计数据 ")],-1)),t("div",ct,[t("div",ut,[t("div",ft,[i[3]||(i[3]=t("label",{class:"block text-sm font-medium mb-2 text-gray-700"},[t("i",{class:"fas fa-key mr-2"}),y(" 输入您的 API Key ")],-1)),H(t("input",{"onUpdate:modelValue":i[0]||(i[0]=d=>X(a)?a.value=d:null),type:"password",placeholder:"请输入您的 API Key (cr_...)",class:"wide-card-input w-full",disabled:s(l),onKeyup:i[1]||(i[1]=G((...d)=>s(c)&&s(c)(...d),["enter"]))},null,40,mt),[[Q,s(a)]])]),t("div",xt,[i[4]||(i[4]=t("label",{class:"hidden lg:block text-sm font-medium mb-2 text-gray-700"}," ",-1)),t("button",{disabled:s(l)||!s(a).trim(),class:"btn btn-primary btn-query w-full h-full flex items-center justify-center gap-2",onClick:i[2]||(i[2]=(...d)=>s(c)&&s(c)(...d))},[s(l)?(m(),f("i",pt)):(m(),f("i",gt)),y(" "+r(s(l)?"查询中...":"查询统计"),1)],8,yt)])]),i[5]||(i[5]=t("div",{class:"security-notice mt-4"},[t("i",{class:"fas fa-shield-alt mr-2"}),y(" 您的 API Key 仅用于查询自己的统计数据,不会被存储或用于其他用途 ")],-1))])]))}},_t=K(vt,[["__scopeId","data-v-d80546e3"]]),bt={class:"grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8"},ht={class:"card p-6"},$t={class:"space-y-3"},wt={class:"flex justify-between items-center"},kt={class:"font-medium text-gray-900"},St={class:"flex justify-between items-center"},Tt={class:"flex justify-between items-center"},It={class:"font-medium text-gray-900"},Ct={class:"flex justify-between items-center"},Lt={class:"font-medium text-gray-900"},Dt={class:"flex justify-between items-center"},Pt={key:0},At={key:0,class:"text-red-600 font-medium"},Kt={key:1,class:"text-orange-600 font-medium"},Mt={key:2,class:"text-gray-900 font-medium"},Rt={key:1,class:"text-gray-400 font-medium"},qt={class:"card p-6"},jt={class:"text-xl font-bold mb-4 flex items-center text-gray-900"},Ut={class:"text-sm font-normal text-gray-600 ml-2"},Et={class:"grid grid-cols-2 gap-4"},Nt={class:"stat-card text-center"},Ot={class:"text-3xl font-bold text-green-600"},Ft={class:"text-sm text-gray-600"},Vt={class:"stat-card text-center"},Wt={class:"text-3xl font-bold text-blue-600"},Jt={class:"text-sm text-gray-600"},Yt={class:"stat-card text-center"},zt={class:"text-3xl font-bold text-purple-600"},Bt={class:"text-sm text-gray-600"},Ht={class:"stat-card text-center"},Qt={class:"text-3xl font-bold text-yellow-600"},Gt={class:"text-sm text-gray-600"},Xt={__name:"StatsOverview",setup(w){const n=M(),{statsData:a,statsPeriod:l,currentPeriodData:c}=A(n),e=x=>{if(!x)return"无";try{return nt(x).format("YYYY年MM月DD日 HH:mm")}catch{return"格式错误"}},i=x=>x?new Date(x).toLocaleString("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"}):"",d=x=>x?new Date(x){if(!x)return!1;const T=(new Date(x)-new Date)/(1e3*60*60*24);return T>0&&T<=7},_=x=>(typeof x!="number"&&(x=parseInt(x)||0),x===0?"0":x>=1e6?(x/1e6).toFixed(1)+"M":x>=1e3?(x/1e3).toFixed(1)+"K":x.toLocaleString()),h=x=>({claude:"Claude",gemini:"Gemini",all:"全部模型"})[x]||x||"未知";return(x,u)=>(m(),f("div",bt,[t("div",ht,[u[8]||(u[8]=t("h3",{class:"text-xl font-bold mb-4 flex items-center text-gray-900"},[t("i",{class:"fas fa-info-circle mr-3 text-blue-500"}),y(" API Key 信息 ")],-1)),t("div",$t,[t("div",wt,[u[0]||(u[0]=t("span",{class:"text-gray-600"},"名称",-1)),t("span",kt,r(s(a).name),1)]),t("div",St,[u[1]||(u[1]=t("span",{class:"text-gray-600"},"状态",-1)),t("span",{class:P([s(a).isActive?"text-green-600":"text-red-600","font-medium"])},[t("i",{class:P([s(a).isActive?"fas fa-check-circle":"fas fa-times-circle","mr-1"])},null,2),y(" "+r(s(a).isActive?"活跃":"已停用"),1)],2)]),t("div",Tt,[u[2]||(u[2]=t("span",{class:"text-gray-600"},"权限",-1)),t("span",It,r(h(s(a).permissions)),1)]),t("div",Ct,[u[3]||(u[3]=t("span",{class:"text-gray-600"},"创建时间",-1)),t("span",Lt,r(e(s(a).createdAt)),1)]),t("div",Dt,[u[7]||(u[7]=t("span",{class:"text-gray-600"},"过期时间",-1)),s(a).expiresAt?(m(),f("div",Pt,[d(s(a).expiresAt)?(m(),f("div",At,u[4]||(u[4]=[t("i",{class:"fas fa-exclamation-circle mr-1"},null,-1),y(" 已过期 ",-1)]))):v(s(a).expiresAt)?(m(),f("div",Kt,[u[5]||(u[5]=t("i",{class:"fas fa-clock mr-1"},null,-1)),y(" "+r(i(s(a).expiresAt)),1)])):(m(),f("div",Mt,r(i(s(a).expiresAt)),1))])):(m(),f("div",Rt,u[6]||(u[6]=[t("i",{class:"fas fa-infinity mr-1"},null,-1),y(" 永不过期 ",-1)])))])])]),t("div",qt,[t("h3",jt,[u[9]||(u[9]=t("i",{class:"fas fa-chart-bar mr-3 text-green-500"},null,-1)),u[10]||(u[10]=y(" 使用统计概览 ",-1)),t("span",Ut,"("+r(s(l)==="daily"?"今日":"本月")+")",1)]),t("div",Et,[t("div",Nt,[t("div",Ot,r(_(s(c).requests)),1),t("div",Ft,r(s(l)==="daily"?"今日":"本月")+"请求数 ",1)]),t("div",Vt,[t("div",Wt,r(_(s(c).allTokens)),1),t("div",Jt,r(s(l)==="daily"?"今日":"本月")+"Token数 ",1)]),t("div",Yt,[t("div",zt,r(s(c).formattedCost||"$0.000000"),1),t("div",Bt,r(s(l)==="daily"?"今日":"本月")+"费用 ",1)]),t("div",Ht,[t("div",Qt,r(_(s(c).inputTokens)),1),t("div",Gt,r(s(l)==="daily"?"今日":"本月")+"输入Token ",1)])])])]))}},Zt=K(Xt,[["__scopeId","data-v-e7abc110"]]),ts={class:"card p-6"},ss={class:"text-xl font-bold mb-4 flex items-center text-gray-900"},es={class:"text-sm font-normal text-gray-600 ml-2"},as={class:"space-y-3"},is={class:"flex justify-between items-center"},os={class:"font-medium text-gray-900"},ns={class:"flex justify-between items-center"},ls={class:"font-medium text-gray-900"},rs={class:"flex justify-between items-center"},ds={class:"font-medium text-gray-900"},cs={class:"flex justify-between items-center"},us={class:"font-medium text-gray-900"},fs={class:"mt-4 pt-4 border-t border-gray-200"},ms={class:"flex justify-between items-center font-bold text-gray-900"},xs={class:"text-xl"},ys={__name:"TokenDistribution",setup(w){const n=M(),{statsPeriod:a,currentPeriodData:l}=A(n),c=e=>(typeof e!="number"&&(e=parseInt(e)||0),e===0?"0":e>=1e6?(e/1e6).toFixed(1)+"M":e>=1e3?(e/1e3).toFixed(1)+"K":e.toLocaleString());return(e,i)=>(m(),f("div",ts,[t("h3",ss,[i[0]||(i[0]=t("i",{class:"fas fa-coins mr-3 text-yellow-500"},null,-1)),i[1]||(i[1]=y(" Token 使用分布 ",-1)),t("span",es,"("+r(s(a)==="daily"?"今日":"本月")+")",1)]),t("div",as,[t("div",is,[i[2]||(i[2]=t("span",{class:"text-gray-600 flex items-center"},[t("i",{class:"fas fa-arrow-right mr-2 text-green-500"}),y(" 输入 Token ")],-1)),t("span",os,r(c(s(l).inputTokens)),1)]),t("div",ns,[i[3]||(i[3]=t("span",{class:"text-gray-600 flex items-center"},[t("i",{class:"fas fa-arrow-left mr-2 text-blue-500"}),y(" 输出 Token ")],-1)),t("span",ls,r(c(s(l).outputTokens)),1)]),t("div",rs,[i[4]||(i[4]=t("span",{class:"text-gray-600 flex items-center"},[t("i",{class:"fas fa-save mr-2 text-purple-500"}),y(" 缓存创建 Token ")],-1)),t("span",ds,r(c(s(l).cacheCreateTokens)),1)]),t("div",cs,[i[5]||(i[5]=t("span",{class:"text-gray-600 flex items-center"},[t("i",{class:"fas fa-download mr-2 text-orange-500"}),y(" 缓存读取 Token ")],-1)),t("span",us,r(c(s(l).cacheReadTokens)),1)])]),t("div",fs,[t("div",ms,[t("span",null,r(s(a)==="daily"?"今日":"本月")+"总计",1),t("span",xs,r(c(s(l).allTokens)),1)])])]))}},ps=K(ys,[["__scopeId","data-v-ff744b2f"]]),gs={class:"card p-6"},vs={class:"space-y-3"},_s={class:"flex justify-between items-center"},bs={class:"font-medium text-gray-900"},hs={class:"flex justify-between items-center"},$s={class:"font-medium text-gray-900"},ws={class:"flex justify-between items-center"},ks={class:"font-medium text-gray-900"},Ss={class:"flex justify-between items-center"},Ts={class:"font-medium text-gray-900"},Is={class:"flex justify-between items-center"},Cs={class:"font-medium text-gray-900"},Ls={key:0,class:"text-orange-600"},Ds={key:1,class:"text-green-600"},Ps={class:"flex justify-between items-center"},As={class:"font-medium text-gray-900"},Ks={key:0,class:"text-orange-600"},Ms={key:1,class:"text-green-600"},Rs={key:0,class:"card p-6 mt-6"},qs={class:"grid grid-cols-1 lg:grid-cols-2 gap-6"},js={key:0,class:"bg-amber-50 border border-amber-200 rounded-lg p-4"},Us={class:"space-y-2"},Es={class:"text-gray-800"},Ns={key:1,class:"bg-blue-50 border border-blue-200 rounded-lg p-4"},Os={class:"space-y-2"},Fs={class:"text-gray-800"},Vs={__name:"LimitConfig",setup(w){const n=M(),{statsData:a}=A(n),l=c=>(typeof c!="number"&&(c=parseInt(c)||0),c===0?"0":c>=1e6?(c/1e6).toFixed(1)+"M":c>=1e3?(c/1e3).toFixed(1)+"K":c.toLocaleString());return(c,e)=>(m(),f("div",null,[t("div",gs,[e[10]||(e[10]=t("h3",{class:"text-xl font-bold mb-4 flex items-center text-gray-900"},[t("i",{class:"fas fa-shield-alt mr-3 text-red-500"}),y(" 限制配置 ")],-1)),t("div",vs,[t("div",_s,[e[0]||(e[0]=t("span",{class:"text-gray-600"},"Token 限制",-1)),t("span",bs,r(s(a).limits.tokenLimit>0?l(s(a).limits.tokenLimit):"无限制"),1)]),t("div",hs,[e[1]||(e[1]=t("span",{class:"text-gray-600"},"并发限制",-1)),t("span",$s,r(s(a).limits.concurrencyLimit>0?s(a).limits.concurrencyLimit:"无限制"),1)]),t("div",ws,[e[2]||(e[2]=t("span",{class:"text-gray-600"},"速率限制",-1)),t("span",ks,r(s(a).limits.rateLimitRequests>0&&s(a).limits.rateLimitWindow>0?`${s(a).limits.rateLimitRequests}次/${s(a).limits.rateLimitWindow}分钟`:"无限制"),1)]),t("div",Ss,[e[3]||(e[3]=t("span",{class:"text-gray-600"},"每日费用限制",-1)),t("span",Ts,r(s(a).limits.dailyCostLimit>0?"$"+s(a).limits.dailyCostLimit:"无限制"),1)]),t("div",Is,[e[6]||(e[6]=t("span",{class:"text-gray-600"},"模型限制",-1)),t("span",Cs,[s(a).restrictions.enableModelRestriction&&s(a).restrictions.restrictedModels.length>0?(m(),f("span",Ls,[e[4]||(e[4]=t("i",{class:"fas fa-exclamation-triangle mr-1"},null,-1)),y(" 限制 "+r(s(a).restrictions.restrictedModels.length)+" 个模型 ",1)])):(m(),f("span",Ds,e[5]||(e[5]=[t("i",{class:"fas fa-check-circle mr-1"},null,-1),y(" 允许所有模型 ",-1)])))])]),t("div",Ps,[e[9]||(e[9]=t("span",{class:"text-gray-600"},"客户端限制",-1)),t("span",As,[s(a).restrictions.enableClientRestriction&&s(a).restrictions.allowedClients.length>0?(m(),f("span",Ks,[e[7]||(e[7]=t("i",{class:"fas fa-exclamation-triangle mr-1"},null,-1)),y(" 限制 "+r(s(a).restrictions.allowedClients.length)+" 个客户端 ",1)])):(m(),f("span",Ms,e[8]||(e[8]=[t("i",{class:"fas fa-check-circle mr-1"},null,-1),y(" 允许所有客户端 ",-1)])))])])])]),s(a).restrictions.enableModelRestriction&&s(a).restrictions.restrictedModels.length>0||s(a).restrictions.enableClientRestriction&&s(a).restrictions.allowedClients.length>0?(m(),f("div",Rs,[e[17]||(e[17]=t("h3",{class:"text-xl font-bold mb-4 flex items-center text-gray-900"},[t("i",{class:"fas fa-list-alt mr-3 text-amber-500"}),y(" 详细限制信息 ")],-1)),t("div",qs,[s(a).restrictions.enableModelRestriction&&s(a).restrictions.restrictedModels.length>0?(m(),f("div",js,[e[12]||(e[12]=t("h4",{class:"font-bold text-amber-800 mb-3 flex items-center"},[t("i",{class:"fas fa-robot mr-2"}),y(" 受限模型列表 ")],-1)),t("div",Us,[(m(!0),f(O,null,F(s(a).restrictions.restrictedModels,i=>(m(),f("div",{key:i,class:"bg-white rounded px-3 py-2 text-sm border border-amber-200"},[e[11]||(e[11]=t("i",{class:"fas fa-ban mr-2 text-red-500"},null,-1)),t("span",Es,r(i),1)]))),128))]),e[13]||(e[13]=t("p",{class:"text-xs text-amber-700 mt-3"},[t("i",{class:"fas fa-info-circle mr-1"}),y(" 此 API Key 不能访问以上列出的模型 ")],-1))])):C("",!0),s(a).restrictions.enableClientRestriction&&s(a).restrictions.allowedClients.length>0?(m(),f("div",Ns,[e[15]||(e[15]=t("h4",{class:"font-bold text-blue-800 mb-3 flex items-center"},[t("i",{class:"fas fa-desktop mr-2"}),y(" 允许的客户端 ")],-1)),t("div",Os,[(m(!0),f(O,null,F(s(a).restrictions.allowedClients,i=>(m(),f("div",{key:i,class:"bg-white rounded px-3 py-2 text-sm border border-blue-200"},[e[14]||(e[14]=t("i",{class:"fas fa-check mr-2 text-green-500"},null,-1)),t("span",Fs,r(i),1)]))),128))]),e[16]||(e[16]=t("p",{class:"text-xs text-blue-700 mt-3"},[t("i",{class:"fas fa-info-circle mr-1"}),y(" 此 API Key 只能被以上列出的客户端使用 ")],-1))])):C("",!0)])])):C("",!0)]))}},Ws=K(Vs,[["__scopeId","data-v-f97c29cf"]]),Js={class:"card p-6"},Ys={class:"mb-6"},zs={class:"text-xl font-bold flex items-center text-gray-900"},Bs={class:"text-sm font-normal text-gray-600 ml-2"},Hs={key:0,class:"text-center py-8"},Qs={key:1,class:"space-y-4"},Gs={class:"flex justify-between items-start mb-3"},Xs={class:"font-bold text-lg text-gray-900"},Zs={class:"text-gray-600 text-sm"},te={class:"text-right"},se={class:"text-lg font-bold text-green-600"},ee={class:"grid grid-cols-2 md:grid-cols-4 gap-3 text-sm"},ae={class:"bg-gray-50 rounded p-2"},ie={class:"font-medium text-gray-900"},oe={class:"bg-gray-50 rounded p-2"},ne={class:"font-medium text-gray-900"},le={class:"bg-gray-50 rounded p-2"},re={class:"font-medium text-gray-900"},de={class:"bg-gray-50 rounded p-2"},ce={class:"font-medium text-gray-900"},ue={key:2,class:"text-center py-8 text-gray-500"},fe={__name:"ModelUsageStats",setup(w){const n=M(),{statsPeriod:a,modelStats:l,modelStatsLoading:c}=A(n),e=i=>(typeof i!="number"&&(i=parseInt(i)||0),i===0?"0":i>=1e6?(i/1e6).toFixed(1)+"M":i>=1e3?(i/1e3).toFixed(1)+"K":i.toLocaleString());return(i,d)=>(m(),f("div",Js,[t("div",Ys,[t("h3",zs,[d[0]||(d[0]=t("i",{class:"fas fa-robot mr-3 text-indigo-500"},null,-1)),d[1]||(d[1]=y(" 模型使用统计 ",-1)),t("span",Bs,"("+r(s(a)==="daily"?"今日":"本月")+")",1)])]),s(c)?(m(),f("div",Hs,d[2]||(d[2]=[t("i",{class:"fas fa-spinner loading-spinner text-2xl mb-2 text-gray-600"},null,-1),t("p",{class:"text-gray-600"}," 加载模型统计数据中... ",-1)]))):s(l).length>0?(m(),f("div",Qs,[(m(!0),f(O,null,F(s(l),(v,_)=>{var h;return m(),f("div",{key:_,class:"model-usage-item"},[t("div",Gs,[t("div",null,[t("h4",Xs,r(v.model),1),t("p",Zs,r(v.requests)+" 次请求 ",1)]),t("div",te,[t("div",se,r(((h=v.formatted)==null?void 0:h.total)||"$0.000000"),1),d[3]||(d[3]=t("div",{class:"text-sm text-gray-600"}," 总费用 ",-1))])]),t("div",ee,[t("div",ae,[d[4]||(d[4]=t("div",{class:"text-gray-600"}," 输入 Token ",-1)),t("div",ie,r(e(v.inputTokens)),1)]),t("div",oe,[d[5]||(d[5]=t("div",{class:"text-gray-600"}," 输出 Token ",-1)),t("div",ne,r(e(v.outputTokens)),1)]),t("div",le,[d[6]||(d[6]=t("div",{class:"text-gray-600"}," 缓存创建 ",-1)),t("div",re,r(e(v.cacheCreateTokens)),1)]),t("div",de,[d[7]||(d[7]=t("div",{class:"text-gray-600"}," 缓存读取 ",-1)),t("div",ce,r(e(v.cacheReadTokens)),1)])])])}),128))])):(m(),f("div",ue,[d[8]||(d[8]=t("i",{class:"fas fa-chart-pie text-3xl mb-3"},null,-1)),t("p",null,"暂无"+r(s(a)==="daily"?"今日":"本月")+"模型使用数据",1)]))]))}},me=K(fe,[["__scopeId","data-v-ccf97793"]]),xe={class:"min-h-screen gradient-bg p-6"},ye={class:"glass-strong rounded-3xl p-6 mb-8 shadow-xl"},pe={class:"flex flex-col md:flex-row justify-between items-center gap-4"},ge={class:"flex items-center gap-3"},ve={class:"mb-8"},_e={class:"flex justify-center"},be={class:"inline-flex bg-white/10 backdrop-blur-xl rounded-full p-1 shadow-lg border border-white/20"},he={key:0,class:"tab-content"},$e={key:0,class:"mb-8"},we={class:"bg-red-500/20 border border-red-500/30 rounded-xl p-4 text-red-800 backdrop-blur-sm"},ke={key:1,class:"fade-in"},Se={class:"glass-strong rounded-3xl p-6 shadow-xl"},Te={class:"mb-6 pb-6 border-b border-gray-200"},Ie={class:"flex flex-col md:flex-row items-start md:items-center justify-between gap-4"},Ce={class:"flex gap-2"},Le=["disabled"],De=["disabled"],Pe={class:"grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8"},Ae={key:1,class:"tab-content"},Ke={class:"glass-strong rounded-3xl shadow-xl"},Me={__name:"ApiStatsView",setup(w){const n=tt(),a=M(),l=$("stats"),{apiKey:c,apiId:e,loading:i,modelStatsLoading:d,oemLoading:v,error:_,statsPeriod:h,statsData:x,oemSettings:u}=A(a),{queryStats:U,switchPeriod:T,loadStatsWithApiId:R,loadOemSettings:L,reset:q}=a,E=b=>{(b.ctrlKey||b.metaKey)&&b.key==="Enter"&&(!i.value&&c.value.trim()&&U(),b.preventDefault()),b.key==="Escape"&&q()};return Z(()=>{console.log("API Stats Page loaded"),L();const b=n.query.apiId,p=n.query.apiKey;b&&b.match(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i)?(e.value=b,R()):p&&p.length>10&&(c.value=p),document.addEventListener("keydown",E)}),st(()=>{document.removeEventListener("keydown",E)}),et(c,b=>{b||a.clearData()}),(b,p)=>{const N=it("router-link");return m(),f("div",xe,[t("div",ye,[t("div",pe,[S(ot,{loading:s(v),title:s(u).siteName,subtitle:l.value==="stats"?"API Key 使用统计":"使用教程","logo-src":s(u).siteIconData||s(u).siteIcon},null,8,["loading","title","subtitle","logo-src"]),t("div",ge,[S(N,{to:"/dashboard",class:"admin-button rounded-xl px-4 py-2 text-white transition-all duration-300 flex items-center gap-2"},{default:at(()=>p[4]||(p[4]=[t("i",{class:"fas fa-cog text-sm"},null,-1),t("span",{class:"text-sm font-medium"},"管理后台",-1)])),_:1,__:[4]})])])]),t("div",ve,[t("div",_e,[t("div",be,[t("button",{class:P(["tab-pill-button",l.value==="stats"?"active":""]),onClick:p[0]||(p[0]=j=>l.value="stats")},p[5]||(p[5]=[t("i",{class:"fas fa-chart-line mr-2"},null,-1),t("span",null,"统计查询",-1)]),2),t("button",{class:P(["tab-pill-button",l.value==="tutorial"?"active":""]),onClick:p[1]||(p[1]=j=>l.value="tutorial")},p[6]||(p[6]=[t("i",{class:"fas fa-graduation-cap mr-2"},null,-1),t("span",null,"使用教程",-1)]),2)])])]),l.value==="stats"?(m(),f("div",he,[S(_t),s(_)?(m(),f("div",$e,[t("div",we,[p[7]||(p[7]=t("i",{class:"fas fa-exclamation-triangle mr-2"},null,-1)),y(" "+r(s(_)),1)])])):C("",!0),s(x)?(m(),f("div",ke,[t("div",Se,[t("div",Te,[t("div",Ie,[p[10]||(p[10]=t("div",{class:"flex items-center gap-3"},[t("i",{class:"fas fa-clock text-blue-500 text-lg"}),t("span",{class:"text-lg font-medium text-gray-700"},"统计时间范围")],-1)),t("div",Ce,[t("button",{class:P([["period-btn",{active:s(h)==="daily"}],"px-6 py-2 text-sm font-medium flex items-center gap-2"]),disabled:s(i)||s(d),onClick:p[2]||(p[2]=j=>s(T)("daily"))},p[8]||(p[8]=[t("i",{class:"fas fa-calendar-day"},null,-1),y(" 今日 ",-1)]),10,Le),t("button",{class:P([["period-btn",{active:s(h)==="monthly"}],"px-6 py-2 text-sm font-medium flex items-center gap-2"]),disabled:s(i)||s(d),onClick:p[3]||(p[3]=j=>s(T)("monthly"))},p[9]||(p[9]=[t("i",{class:"fas fa-calendar-alt"},null,-1),y(" 本月 ",-1)]),10,De)])])]),S(Zt),t("div",Pe,[S(ps),S(Ws)]),S(me)])])):C("",!0)])):C("",!0),l.value==="tutorial"?(m(),f("div",Ae,[t("div",Ke,[S(lt)])])):C("",!0)])}}},Fe=K(Me,[["__scopeId","data-v-38cbdfe3"]]);export{Fe as default};
+import{aR as B,r as $,c as J,aW as A,x as f,y as m,z as t,O as y,K as H,aq as Q,u as s,aa as G,f as X,P as r,C as P,L as C,Q as O,ac as F,q as Z,aU as tt,V as st,o as et,R as S,J as at,av as it}from"./vue-vendor-CKToUHZx.js";import{L as ot}from"./LogoTitle-DHj-MjwS.js";import{_ as K}from"./index-HYE9xPuR.js";import{b as nt}from"./vendor-BDiMbLwQ.js";import lt from"./TutorialView-DqKyDtQV.js";/* empty css */import"./element-plus-B8Fs_0jW.js";class rt{constructor(){this.baseURL=window.location.origin,this.isDev=!1}async request(n,a={}){try{this.isDev&&n.startsWith("/admin")&&(n="/webapi"+n);const l=await fetch(`${this.baseURL}${n}`,{headers:{"Content-Type":"application/json",...a.headers},...a}),c=await l.json();if(!l.ok)throw new Error(c.message||`请求失败: ${l.status}`);return c}catch(l){throw console.error("API Stats request error:",l),l}}async getKeyId(n){return this.request("/apiStats/api/get-key-id",{method:"POST",body:JSON.stringify({apiKey:n})})}async getUserStats(n){return this.request("/apiStats/api/user-stats",{method:"POST",body:JSON.stringify({apiId:n})})}async getUserModelStats(n,a="daily"){return this.request("/apiStats/api/user-model-stats",{method:"POST",body:JSON.stringify({apiId:n,period:a})})}async getOemSettings(){try{return await this.request("/admin/oem-settings")}catch(n){return console.error("Failed to load OEM settings:",n),{success:!0,data:{siteName:"Claude Relay Service",siteIcon:"",siteIconData:""}}}}}const D=new rt,M=B("apistats",()=>{const w=$(""),n=$(null),a=$(!1),l=$(!1),c=$(!0),e=$(""),i=$("daily"),d=$(null),v=$([]),_=$(null),h=$(null),x=$({siteName:"",siteIcon:"",siteIconData:""}),u=J(()=>{const o={requests:0,inputTokens:0,outputTokens:0,cacheCreateTokens:0,cacheReadTokens:0,allTokens:0,cost:0,formattedCost:"$0.000000"};return i.value==="daily"?_.value||o:h.value||o}),U=J(()=>{if(!d.value||!u.value)return{tokenUsage:0,costUsage:0,requestUsage:0};const o=u.value,g=d.value.limits;return{tokenUsage:g.tokenLimit>0?Math.min(o.allTokens/g.tokenLimit*100,100):0,costUsage:g.dailyCostLimit>0?Math.min(o.cost/g.dailyCostLimit*100,100):0,requestUsage:g.rateLimitRequests>0?Math.min(o.requests/g.rateLimitRequests*100,100):0}});async function T(){if(!w.value.trim()){e.value="请输入 API Key";return}a.value=!0,e.value="",d.value=null,v.value=[],n.value=null;try{const o=await D.getKeyId(w.value);if(o.success){n.value=o.data.id;const g=await D.getUserStats(n.value);if(g.success)d.value=g.data,await R(),e.value="",j();else throw new Error(g.message||"查询失败")}else throw new Error(o.message||"获取 API Key ID 失败")}catch(o){console.error("Query stats error:",o),e.value=o.message||"查询统计数据失败,请检查您的 API Key 是否正确",d.value=null,v.value=[],n.value=null}finally{a.value=!1}}async function R(){n.value&&(await Promise.all([L("daily"),L("monthly")]),await q(i.value))}async function L(o){try{const g=await D.getUserModelStats(n.value,o);if(g.success){const z=g.data||[],k={requests:0,inputTokens:0,outputTokens:0,cacheCreateTokens:0,cacheReadTokens:0,allTokens:0,cost:0,formattedCost:"$0.000000"};z.forEach(I=>{var W;k.requests+=I.requests||0,k.inputTokens+=I.inputTokens||0,k.outputTokens+=I.outputTokens||0,k.cacheCreateTokens+=I.cacheCreateTokens||0,k.cacheReadTokens+=I.cacheReadTokens||0,k.allTokens+=I.allTokens||0,k.cost+=((W=I.costs)==null?void 0:W.total)||0}),k.formattedCost=N(k.cost),o==="daily"?_.value=k:h.value=k}else console.warn(`Failed to load ${o} stats:`,g.message)}catch(g){console.error(`Load ${o} stats error:`,g)}}async function q(o="daily"){if(n.value){l.value=!0;try{const g=await D.getUserModelStats(n.value,o);if(g.success)v.value=g.data||[];else throw new Error(g.message||"加载模型统计失败")}catch(g){console.error("Load model stats error:",g),v.value=[]}finally{l.value=!1}}}async function E(o){i.value===o||l.value||(i.value=o,(o==="daily"&&!_.value||o==="monthly"&&!h.value)&&await L(o),await q(o))}async function b(){if(n.value){a.value=!0,e.value="",d.value=null,v.value=[];try{const o=await D.getUserStats(n.value);if(o.success)d.value=o.data,await R(),e.value="";else throw new Error(o.message||"查询失败")}catch(o){console.error("Load stats with apiId error:",o),e.value=o.message||"查询统计数据失败",d.value=null,v.value=[]}finally{a.value=!1}}}async function p(){c.value=!0;try{const o=await D.getOemSettings();o&&o.success&&o.data&&(x.value={...x.value,...o.data})}catch(o){console.error("Error loading OEM settings:",o),x.value={siteName:"Claude Relay Service",siteIcon:"",siteIconData:""}}finally{c.value=!1}}function N(o){return typeof o!="number"||o===0?"$0.000000":o>=1?"$"+o.toFixed(2):o>=.01?"$"+o.toFixed(4):"$"+o.toFixed(6)}function j(){if(n.value){const o=new URL(window.location);o.searchParams.set("apiId",n.value),window.history.pushState({},"",o)}}function V(){d.value=null,v.value=[],_.value=null,h.value=null,e.value="",i.value="daily",n.value=null}function Y(){w.value="",V()}return{apiKey:w,apiId:n,loading:a,modelStatsLoading:l,oemLoading:c,error:e,statsPeriod:i,statsData:d,modelStats:v,dailyStats:_,monthlyStats:h,oemSettings:x,currentPeriodData:u,usagePercentages:U,queryStats:T,loadAllPeriodStats:R,loadPeriodStats:L,loadModelStats:q,switchPeriod:E,loadStatsWithApiId:b,loadOemSettings:p,clearData:V,reset:Y}}),dt={class:"api-input-wide-card glass-strong rounded-3xl p-6 mb-8 shadow-xl"},ct={class:"max-w-4xl mx-auto"},ut={class:"api-input-grid grid grid-cols-1 lg:grid-cols-4"},ft={class:"lg:col-span-3"},mt=["disabled"],xt={class:"lg:col-span-1"},yt=["disabled"],pt={key:0,class:"fas fa-spinner loading-spinner"},gt={key:1,class:"fas fa-search"},vt={__name:"ApiKeyInput",setup(w){const n=M(),{apiKey:a,loading:l}=A(n),{queryStats:c}=n;return(e,i)=>(m(),f("div",dt,[i[6]||(i[6]=t("div",{class:"wide-card-title text-center mb-6"},[t("h2",{class:"text-2xl font-bold mb-2"},[t("i",{class:"fas fa-chart-line mr-3"}),y(" 使用统计查询 ")]),t("p",{class:"text-base text-gray-600"}," 查询您的 API Key 使用情况和统计数据 ")],-1)),t("div",ct,[t("div",ut,[t("div",ft,[i[3]||(i[3]=t("label",{class:"block text-sm font-medium mb-2 text-gray-700"},[t("i",{class:"fas fa-key mr-2"}),y(" 输入您的 API Key ")],-1)),H(t("input",{"onUpdate:modelValue":i[0]||(i[0]=d=>X(a)?a.value=d:null),type:"password",placeholder:"请输入您的 API Key (cr_...)",class:"wide-card-input w-full",disabled:s(l),onKeyup:i[1]||(i[1]=G((...d)=>s(c)&&s(c)(...d),["enter"]))},null,40,mt),[[Q,s(a)]])]),t("div",xt,[i[4]||(i[4]=t("label",{class:"hidden lg:block text-sm font-medium mb-2 text-gray-700"}," ",-1)),t("button",{disabled:s(l)||!s(a).trim(),class:"btn btn-primary btn-query w-full h-full flex items-center justify-center gap-2",onClick:i[2]||(i[2]=(...d)=>s(c)&&s(c)(...d))},[s(l)?(m(),f("i",pt)):(m(),f("i",gt)),y(" "+r(s(l)?"查询中...":"查询统计"),1)],8,yt)])]),i[5]||(i[5]=t("div",{class:"security-notice mt-4"},[t("i",{class:"fas fa-shield-alt mr-2"}),y(" 您的 API Key 仅用于查询自己的统计数据,不会被存储或用于其他用途 ")],-1))])]))}},_t=K(vt,[["__scopeId","data-v-d80546e3"]]),bt={class:"grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8"},ht={class:"card p-6"},$t={class:"space-y-3"},wt={class:"flex justify-between items-center"},kt={class:"font-medium text-gray-900"},St={class:"flex justify-between items-center"},Tt={class:"flex justify-between items-center"},It={class:"font-medium text-gray-900"},Ct={class:"flex justify-between items-center"},Lt={class:"font-medium text-gray-900"},Dt={class:"flex justify-between items-center"},Pt={key:0},At={key:0,class:"text-red-600 font-medium"},Kt={key:1,class:"text-orange-600 font-medium"},Mt={key:2,class:"text-gray-900 font-medium"},Rt={key:1,class:"text-gray-400 font-medium"},qt={class:"card p-6"},jt={class:"text-xl font-bold mb-4 flex items-center text-gray-900"},Ut={class:"text-sm font-normal text-gray-600 ml-2"},Et={class:"grid grid-cols-2 gap-4"},Nt={class:"stat-card text-center"},Ot={class:"text-3xl font-bold text-green-600"},Ft={class:"text-sm text-gray-600"},Vt={class:"stat-card text-center"},Wt={class:"text-3xl font-bold text-blue-600"},Jt={class:"text-sm text-gray-600"},Yt={class:"stat-card text-center"},zt={class:"text-3xl font-bold text-purple-600"},Bt={class:"text-sm text-gray-600"},Ht={class:"stat-card text-center"},Qt={class:"text-3xl font-bold text-yellow-600"},Gt={class:"text-sm text-gray-600"},Xt={__name:"StatsOverview",setup(w){const n=M(),{statsData:a,statsPeriod:l,currentPeriodData:c}=A(n),e=x=>{if(!x)return"无";try{return nt(x).format("YYYY年MM月DD日 HH:mm")}catch{return"格式错误"}},i=x=>x?new Date(x).toLocaleString("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"}):"",d=x=>x?new Date(x){if(!x)return!1;const T=(new Date(x)-new Date)/(1e3*60*60*24);return T>0&&T<=7},_=x=>(typeof x!="number"&&(x=parseInt(x)||0),x===0?"0":x>=1e6?(x/1e6).toFixed(1)+"M":x>=1e3?(x/1e3).toFixed(1)+"K":x.toLocaleString()),h=x=>({claude:"Claude",gemini:"Gemini",all:"全部模型"})[x]||x||"未知";return(x,u)=>(m(),f("div",bt,[t("div",ht,[u[8]||(u[8]=t("h3",{class:"text-xl font-bold mb-4 flex items-center text-gray-900"},[t("i",{class:"fas fa-info-circle mr-3 text-blue-500"}),y(" API Key 信息 ")],-1)),t("div",$t,[t("div",wt,[u[0]||(u[0]=t("span",{class:"text-gray-600"},"名称",-1)),t("span",kt,r(s(a).name),1)]),t("div",St,[u[1]||(u[1]=t("span",{class:"text-gray-600"},"状态",-1)),t("span",{class:P([s(a).isActive?"text-green-600":"text-red-600","font-medium"])},[t("i",{class:P([s(a).isActive?"fas fa-check-circle":"fas fa-times-circle","mr-1"])},null,2),y(" "+r(s(a).isActive?"活跃":"已停用"),1)],2)]),t("div",Tt,[u[2]||(u[2]=t("span",{class:"text-gray-600"},"权限",-1)),t("span",It,r(h(s(a).permissions)),1)]),t("div",Ct,[u[3]||(u[3]=t("span",{class:"text-gray-600"},"创建时间",-1)),t("span",Lt,r(e(s(a).createdAt)),1)]),t("div",Dt,[u[7]||(u[7]=t("span",{class:"text-gray-600"},"过期时间",-1)),s(a).expiresAt?(m(),f("div",Pt,[d(s(a).expiresAt)?(m(),f("div",At,u[4]||(u[4]=[t("i",{class:"fas fa-exclamation-circle mr-1"},null,-1),y(" 已过期 ",-1)]))):v(s(a).expiresAt)?(m(),f("div",Kt,[u[5]||(u[5]=t("i",{class:"fas fa-clock mr-1"},null,-1)),y(" "+r(i(s(a).expiresAt)),1)])):(m(),f("div",Mt,r(i(s(a).expiresAt)),1))])):(m(),f("div",Rt,u[6]||(u[6]=[t("i",{class:"fas fa-infinity mr-1"},null,-1),y(" 永不过期 ",-1)])))])])]),t("div",qt,[t("h3",jt,[u[9]||(u[9]=t("i",{class:"fas fa-chart-bar mr-3 text-green-500"},null,-1)),u[10]||(u[10]=y(" 使用统计概览 ",-1)),t("span",Ut,"("+r(s(l)==="daily"?"今日":"本月")+")",1)]),t("div",Et,[t("div",Nt,[t("div",Ot,r(_(s(c).requests)),1),t("div",Ft,r(s(l)==="daily"?"今日":"本月")+"请求数 ",1)]),t("div",Vt,[t("div",Wt,r(_(s(c).allTokens)),1),t("div",Jt,r(s(l)==="daily"?"今日":"本月")+"Token数 ",1)]),t("div",Yt,[t("div",zt,r(s(c).formattedCost||"$0.000000"),1),t("div",Bt,r(s(l)==="daily"?"今日":"本月")+"费用 ",1)]),t("div",Ht,[t("div",Qt,r(_(s(c).inputTokens)),1),t("div",Gt,r(s(l)==="daily"?"今日":"本月")+"输入Token ",1)])])])]))}},Zt=K(Xt,[["__scopeId","data-v-e7abc110"]]),ts={class:"card p-6"},ss={class:"text-xl font-bold mb-4 flex items-center text-gray-900"},es={class:"text-sm font-normal text-gray-600 ml-2"},as={class:"space-y-3"},is={class:"flex justify-between items-center"},os={class:"font-medium text-gray-900"},ns={class:"flex justify-between items-center"},ls={class:"font-medium text-gray-900"},rs={class:"flex justify-between items-center"},ds={class:"font-medium text-gray-900"},cs={class:"flex justify-between items-center"},us={class:"font-medium text-gray-900"},fs={class:"mt-4 pt-4 border-t border-gray-200"},ms={class:"flex justify-between items-center font-bold text-gray-900"},xs={class:"text-xl"},ys={__name:"TokenDistribution",setup(w){const n=M(),{statsPeriod:a,currentPeriodData:l}=A(n),c=e=>(typeof e!="number"&&(e=parseInt(e)||0),e===0?"0":e>=1e6?(e/1e6).toFixed(1)+"M":e>=1e3?(e/1e3).toFixed(1)+"K":e.toLocaleString());return(e,i)=>(m(),f("div",ts,[t("h3",ss,[i[0]||(i[0]=t("i",{class:"fas fa-coins mr-3 text-yellow-500"},null,-1)),i[1]||(i[1]=y(" Token 使用分布 ",-1)),t("span",es,"("+r(s(a)==="daily"?"今日":"本月")+")",1)]),t("div",as,[t("div",is,[i[2]||(i[2]=t("span",{class:"text-gray-600 flex items-center"},[t("i",{class:"fas fa-arrow-right mr-2 text-green-500"}),y(" 输入 Token ")],-1)),t("span",os,r(c(s(l).inputTokens)),1)]),t("div",ns,[i[3]||(i[3]=t("span",{class:"text-gray-600 flex items-center"},[t("i",{class:"fas fa-arrow-left mr-2 text-blue-500"}),y(" 输出 Token ")],-1)),t("span",ls,r(c(s(l).outputTokens)),1)]),t("div",rs,[i[4]||(i[4]=t("span",{class:"text-gray-600 flex items-center"},[t("i",{class:"fas fa-save mr-2 text-purple-500"}),y(" 缓存创建 Token ")],-1)),t("span",ds,r(c(s(l).cacheCreateTokens)),1)]),t("div",cs,[i[5]||(i[5]=t("span",{class:"text-gray-600 flex items-center"},[t("i",{class:"fas fa-download mr-2 text-orange-500"}),y(" 缓存读取 Token ")],-1)),t("span",us,r(c(s(l).cacheReadTokens)),1)])]),t("div",fs,[t("div",ms,[t("span",null,r(s(a)==="daily"?"今日":"本月")+"总计",1),t("span",xs,r(c(s(l).allTokens)),1)])])]))}},ps=K(ys,[["__scopeId","data-v-ff744b2f"]]),gs={class:"card p-6"},vs={class:"space-y-3"},_s={class:"flex justify-between items-center"},bs={class:"font-medium text-gray-900"},hs={class:"flex justify-between items-center"},$s={class:"font-medium text-gray-900"},ws={class:"flex justify-between items-center"},ks={class:"font-medium text-gray-900"},Ss={class:"flex justify-between items-center"},Ts={class:"font-medium text-gray-900"},Is={class:"flex justify-between items-center"},Cs={class:"font-medium text-gray-900"},Ls={key:0,class:"text-orange-600"},Ds={key:1,class:"text-green-600"},Ps={class:"flex justify-between items-center"},As={class:"font-medium text-gray-900"},Ks={key:0,class:"text-orange-600"},Ms={key:1,class:"text-green-600"},Rs={key:0,class:"card p-6 mt-6"},qs={class:"grid grid-cols-1 lg:grid-cols-2 gap-6"},js={key:0,class:"bg-amber-50 border border-amber-200 rounded-lg p-4"},Us={class:"space-y-2"},Es={class:"text-gray-800"},Ns={key:1,class:"bg-blue-50 border border-blue-200 rounded-lg p-4"},Os={class:"space-y-2"},Fs={class:"text-gray-800"},Vs={__name:"LimitConfig",setup(w){const n=M(),{statsData:a}=A(n),l=c=>(typeof c!="number"&&(c=parseInt(c)||0),c===0?"0":c>=1e6?(c/1e6).toFixed(1)+"M":c>=1e3?(c/1e3).toFixed(1)+"K":c.toLocaleString());return(c,e)=>(m(),f("div",null,[t("div",gs,[e[10]||(e[10]=t("h3",{class:"text-xl font-bold mb-4 flex items-center text-gray-900"},[t("i",{class:"fas fa-shield-alt mr-3 text-red-500"}),y(" 限制配置 ")],-1)),t("div",vs,[t("div",_s,[e[0]||(e[0]=t("span",{class:"text-gray-600"},"Token 限制",-1)),t("span",bs,r(s(a).limits.tokenLimit>0?l(s(a).limits.tokenLimit):"无限制"),1)]),t("div",hs,[e[1]||(e[1]=t("span",{class:"text-gray-600"},"并发限制",-1)),t("span",$s,r(s(a).limits.concurrencyLimit>0?s(a).limits.concurrencyLimit:"无限制"),1)]),t("div",ws,[e[2]||(e[2]=t("span",{class:"text-gray-600"},"速率限制",-1)),t("span",ks,r(s(a).limits.rateLimitRequests>0&&s(a).limits.rateLimitWindow>0?`${s(a).limits.rateLimitRequests}次/${s(a).limits.rateLimitWindow}分钟`:"无限制"),1)]),t("div",Ss,[e[3]||(e[3]=t("span",{class:"text-gray-600"},"每日费用限制",-1)),t("span",Ts,r(s(a).limits.dailyCostLimit>0?"$"+s(a).limits.dailyCostLimit:"无限制"),1)]),t("div",Is,[e[6]||(e[6]=t("span",{class:"text-gray-600"},"模型限制",-1)),t("span",Cs,[s(a).restrictions.enableModelRestriction&&s(a).restrictions.restrictedModels.length>0?(m(),f("span",Ls,[e[4]||(e[4]=t("i",{class:"fas fa-exclamation-triangle mr-1"},null,-1)),y(" 限制 "+r(s(a).restrictions.restrictedModels.length)+" 个模型 ",1)])):(m(),f("span",Ds,e[5]||(e[5]=[t("i",{class:"fas fa-check-circle mr-1"},null,-1),y(" 允许所有模型 ",-1)])))])]),t("div",Ps,[e[9]||(e[9]=t("span",{class:"text-gray-600"},"客户端限制",-1)),t("span",As,[s(a).restrictions.enableClientRestriction&&s(a).restrictions.allowedClients.length>0?(m(),f("span",Ks,[e[7]||(e[7]=t("i",{class:"fas fa-exclamation-triangle mr-1"},null,-1)),y(" 限制 "+r(s(a).restrictions.allowedClients.length)+" 个客户端 ",1)])):(m(),f("span",Ms,e[8]||(e[8]=[t("i",{class:"fas fa-check-circle mr-1"},null,-1),y(" 允许所有客户端 ",-1)])))])])])]),s(a).restrictions.enableModelRestriction&&s(a).restrictions.restrictedModels.length>0||s(a).restrictions.enableClientRestriction&&s(a).restrictions.allowedClients.length>0?(m(),f("div",Rs,[e[17]||(e[17]=t("h3",{class:"text-xl font-bold mb-4 flex items-center text-gray-900"},[t("i",{class:"fas fa-list-alt mr-3 text-amber-500"}),y(" 详细限制信息 ")],-1)),t("div",qs,[s(a).restrictions.enableModelRestriction&&s(a).restrictions.restrictedModels.length>0?(m(),f("div",js,[e[12]||(e[12]=t("h4",{class:"font-bold text-amber-800 mb-3 flex items-center"},[t("i",{class:"fas fa-robot mr-2"}),y(" 受限模型列表 ")],-1)),t("div",Us,[(m(!0),f(O,null,F(s(a).restrictions.restrictedModels,i=>(m(),f("div",{key:i,class:"bg-white rounded px-3 py-2 text-sm border border-amber-200"},[e[11]||(e[11]=t("i",{class:"fas fa-ban mr-2 text-red-500"},null,-1)),t("span",Es,r(i),1)]))),128))]),e[13]||(e[13]=t("p",{class:"text-xs text-amber-700 mt-3"},[t("i",{class:"fas fa-info-circle mr-1"}),y(" 此 API Key 不能访问以上列出的模型 ")],-1))])):C("",!0),s(a).restrictions.enableClientRestriction&&s(a).restrictions.allowedClients.length>0?(m(),f("div",Ns,[e[15]||(e[15]=t("h4",{class:"font-bold text-blue-800 mb-3 flex items-center"},[t("i",{class:"fas fa-desktop mr-2"}),y(" 允许的客户端 ")],-1)),t("div",Os,[(m(!0),f(O,null,F(s(a).restrictions.allowedClients,i=>(m(),f("div",{key:i,class:"bg-white rounded px-3 py-2 text-sm border border-blue-200"},[e[14]||(e[14]=t("i",{class:"fas fa-check mr-2 text-green-500"},null,-1)),t("span",Fs,r(i),1)]))),128))]),e[16]||(e[16]=t("p",{class:"text-xs text-blue-700 mt-3"},[t("i",{class:"fas fa-info-circle mr-1"}),y(" 此 API Key 只能被以上列出的客户端使用 ")],-1))])):C("",!0)])])):C("",!0)]))}},Ws=K(Vs,[["__scopeId","data-v-f97c29cf"]]),Js={class:"card p-6"},Ys={class:"mb-6"},zs={class:"text-xl font-bold flex items-center text-gray-900"},Bs={class:"text-sm font-normal text-gray-600 ml-2"},Hs={key:0,class:"text-center py-8"},Qs={key:1,class:"space-y-4"},Gs={class:"flex justify-between items-start mb-3"},Xs={class:"font-bold text-lg text-gray-900"},Zs={class:"text-gray-600 text-sm"},te={class:"text-right"},se={class:"text-lg font-bold text-green-600"},ee={class:"grid grid-cols-2 md:grid-cols-4 gap-3 text-sm"},ae={class:"bg-gray-50 rounded p-2"},ie={class:"font-medium text-gray-900"},oe={class:"bg-gray-50 rounded p-2"},ne={class:"font-medium text-gray-900"},le={class:"bg-gray-50 rounded p-2"},re={class:"font-medium text-gray-900"},de={class:"bg-gray-50 rounded p-2"},ce={class:"font-medium text-gray-900"},ue={key:2,class:"text-center py-8 text-gray-500"},fe={__name:"ModelUsageStats",setup(w){const n=M(),{statsPeriod:a,modelStats:l,modelStatsLoading:c}=A(n),e=i=>(typeof i!="number"&&(i=parseInt(i)||0),i===0?"0":i>=1e6?(i/1e6).toFixed(1)+"M":i>=1e3?(i/1e3).toFixed(1)+"K":i.toLocaleString());return(i,d)=>(m(),f("div",Js,[t("div",Ys,[t("h3",zs,[d[0]||(d[0]=t("i",{class:"fas fa-robot mr-3 text-indigo-500"},null,-1)),d[1]||(d[1]=y(" 模型使用统计 ",-1)),t("span",Bs,"("+r(s(a)==="daily"?"今日":"本月")+")",1)])]),s(c)?(m(),f("div",Hs,d[2]||(d[2]=[t("i",{class:"fas fa-spinner loading-spinner text-2xl mb-2 text-gray-600"},null,-1),t("p",{class:"text-gray-600"}," 加载模型统计数据中... ",-1)]))):s(l).length>0?(m(),f("div",Qs,[(m(!0),f(O,null,F(s(l),(v,_)=>{var h;return m(),f("div",{key:_,class:"model-usage-item"},[t("div",Gs,[t("div",null,[t("h4",Xs,r(v.model),1),t("p",Zs,r(v.requests)+" 次请求 ",1)]),t("div",te,[t("div",se,r(((h=v.formatted)==null?void 0:h.total)||"$0.000000"),1),d[3]||(d[3]=t("div",{class:"text-sm text-gray-600"}," 总费用 ",-1))])]),t("div",ee,[t("div",ae,[d[4]||(d[4]=t("div",{class:"text-gray-600"}," 输入 Token ",-1)),t("div",ie,r(e(v.inputTokens)),1)]),t("div",oe,[d[5]||(d[5]=t("div",{class:"text-gray-600"}," 输出 Token ",-1)),t("div",ne,r(e(v.outputTokens)),1)]),t("div",le,[d[6]||(d[6]=t("div",{class:"text-gray-600"}," 缓存创建 ",-1)),t("div",re,r(e(v.cacheCreateTokens)),1)]),t("div",de,[d[7]||(d[7]=t("div",{class:"text-gray-600"}," 缓存读取 ",-1)),t("div",ce,r(e(v.cacheReadTokens)),1)])])])}),128))])):(m(),f("div",ue,[d[8]||(d[8]=t("i",{class:"fas fa-chart-pie text-3xl mb-3"},null,-1)),t("p",null,"暂无"+r(s(a)==="daily"?"今日":"本月")+"模型使用数据",1)]))]))}},me=K(fe,[["__scopeId","data-v-ccf97793"]]),xe={class:"min-h-screen gradient-bg p-6"},ye={class:"glass-strong rounded-3xl p-6 mb-8 shadow-xl"},pe={class:"flex flex-col md:flex-row justify-between items-center gap-4"},ge={class:"flex items-center gap-3"},ve={class:"mb-8"},_e={class:"flex justify-center"},be={class:"inline-flex bg-white/10 backdrop-blur-xl rounded-full p-1 shadow-lg border border-white/20"},he={key:0,class:"tab-content"},$e={key:0,class:"mb-8"},we={class:"bg-red-500/20 border border-red-500/30 rounded-xl p-4 text-red-800 backdrop-blur-sm"},ke={key:1,class:"fade-in"},Se={class:"glass-strong rounded-3xl p-6 shadow-xl"},Te={class:"mb-6 pb-6 border-b border-gray-200"},Ie={class:"flex flex-col md:flex-row items-start md:items-center justify-between gap-4"},Ce={class:"flex gap-2"},Le=["disabled"],De=["disabled"],Pe={class:"grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8"},Ae={key:1,class:"tab-content"},Ke={class:"glass-strong rounded-3xl shadow-xl"},Me={__name:"ApiStatsView",setup(w){const n=tt(),a=M(),l=$("stats"),{apiKey:c,apiId:e,loading:i,modelStatsLoading:d,oemLoading:v,error:_,statsPeriod:h,statsData:x,oemSettings:u}=A(a),{queryStats:U,switchPeriod:T,loadStatsWithApiId:R,loadOemSettings:L,reset:q}=a,E=b=>{(b.ctrlKey||b.metaKey)&&b.key==="Enter"&&(!i.value&&c.value.trim()&&U(),b.preventDefault()),b.key==="Escape"&&q()};return Z(()=>{console.log("API Stats Page loaded"),L();const b=n.query.apiId,p=n.query.apiKey;b&&b.match(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i)?(e.value=b,R()):p&&p.length>10&&(c.value=p),document.addEventListener("keydown",E)}),st(()=>{document.removeEventListener("keydown",E)}),et(c,b=>{b||a.clearData()}),(b,p)=>{const N=it("router-link");return m(),f("div",xe,[t("div",ye,[t("div",pe,[S(ot,{loading:s(v),title:s(u).siteName,subtitle:l.value==="stats"?"API Key 使用统计":"使用教程","logo-src":s(u).siteIconData||s(u).siteIcon},null,8,["loading","title","subtitle","logo-src"]),t("div",ge,[S(N,{to:"/dashboard",class:"admin-button rounded-xl px-4 py-2 text-white transition-all duration-300 flex items-center gap-2"},{default:at(()=>p[4]||(p[4]=[t("i",{class:"fas fa-cog text-sm"},null,-1),t("span",{class:"text-sm font-medium"},"管理后台",-1)])),_:1,__:[4]})])])]),t("div",ve,[t("div",_e,[t("div",be,[t("button",{class:P(["tab-pill-button",l.value==="stats"?"active":""]),onClick:p[0]||(p[0]=j=>l.value="stats")},p[5]||(p[5]=[t("i",{class:"fas fa-chart-line mr-2"},null,-1),t("span",null,"统计查询",-1)]),2),t("button",{class:P(["tab-pill-button",l.value==="tutorial"?"active":""]),onClick:p[1]||(p[1]=j=>l.value="tutorial")},p[6]||(p[6]=[t("i",{class:"fas fa-graduation-cap mr-2"},null,-1),t("span",null,"使用教程",-1)]),2)])])]),l.value==="stats"?(m(),f("div",he,[S(_t),s(_)?(m(),f("div",$e,[t("div",we,[p[7]||(p[7]=t("i",{class:"fas fa-exclamation-triangle mr-2"},null,-1)),y(" "+r(s(_)),1)])])):C("",!0),s(x)?(m(),f("div",ke,[t("div",Se,[t("div",Te,[t("div",Ie,[p[10]||(p[10]=t("div",{class:"flex items-center gap-3"},[t("i",{class:"fas fa-clock text-blue-500 text-lg"}),t("span",{class:"text-lg font-medium text-gray-700"},"统计时间范围")],-1)),t("div",Ce,[t("button",{class:P([["period-btn",{active:s(h)==="daily"}],"px-6 py-2 text-sm font-medium flex items-center gap-2"]),disabled:s(i)||s(d),onClick:p[2]||(p[2]=j=>s(T)("daily"))},p[8]||(p[8]=[t("i",{class:"fas fa-calendar-day"},null,-1),y(" 今日 ",-1)]),10,Le),t("button",{class:P([["period-btn",{active:s(h)==="monthly"}],"px-6 py-2 text-sm font-medium flex items-center gap-2"]),disabled:s(i)||s(d),onClick:p[3]||(p[3]=j=>s(T)("monthly"))},p[9]||(p[9]=[t("i",{class:"fas fa-calendar-alt"},null,-1),y(" 本月 ",-1)]),10,De)])])]),S(Zt),t("div",Pe,[S(ps),S(Ws)]),S(me)])])):C("",!0)])):C("",!0),l.value==="tutorial"?(m(),f("div",Ae,[t("div",Ke,[S(lt)])])):C("",!0)])}}},Fe=K(Me,[["__scopeId","data-v-38cbdfe3"]]);export{Fe as default};
diff --git a/web/admin-spa/dist/assets/DashboardView-QB8MFvLZ.js b/web/admin-spa/dist/assets/DashboardView-B_FI7Rf0.js
similarity index 99%
rename from web/admin-spa/dist/assets/DashboardView-QB8MFvLZ.js
rename to web/admin-spa/dist/assets/DashboardView-B_FI7Rf0.js
index ca135450..1d8167b4 100644
--- a/web/admin-spa/dist/assets/DashboardView-QB8MFvLZ.js
+++ b/web/admin-spa/dist/assets/DashboardView-B_FI7Rf0.js
@@ -1 +1 @@
-import{E as Dt}from"./element-plus-B8Fs_0jW.js";import{aR as wt,r as T,c as Tt,aW as _t,o as mt,q as St,D as ot,V as Rt,x as w,z as t,P as p,u as a,O as k,L as z,Q as bt,ac as kt,C as G,R as $t,K as At,al as Mt,y as _}from"./vue-vendor-CKToUHZx.js";import{a as J,_ as Ut}from"./index-D7YURYF2.js";import{s as xt}from"./toast-BvwA7Mwb.js";import{C as vt}from"./chart-Cor9iTVD.js";import"./vendor-BDiMbLwQ.js";const Kt=wt("dashboard",()=>{const nt=T(!1),N=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}),c=T({todayCosts:{totalCost:0,formatted:{totalCost:"$0.000000"}},totalCosts:{totalCost:0,formatted:{totalCost:"$0.000000"}}}),lt=T([]),H=T([]),X=T([]),M=T({data:[],topApiKeys:[],totalApiKeys:0}),n=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}]}),S=T("day"),q=T("requests"),I=T([new Date(2e3,1,1,0,0,0),new Date(2e3,2,1,23,59,59)]),pt=Tt(()=>{const s=N.value.uptime,r=Math.floor(s/86400),l=Math.floor(s%86400/3600),i=Math.floor(s%3600/60);return r>0?`${r}天 ${l}小时`:l>0?`${l}小时 ${i}分钟`:`${i}分钟`});function A(s,r=!0){const l=s.getFullYear(),i=s.getMonth(),o=s.getDate();return r?new Date(Date.UTC(l,i,o-1,16,0,0,0)):new Date(Date.UTC(l,i,o,15,59,59,999))}async function yt(){nt.value=!0;try{const[s,r,l]=await Promise.all([J.get("/admin/dashboard"),J.get("/admin/usage-costs?period=today"),J.get("/admin/usage-costs?period=all")]);if(s.success){const i=s.data.overview||{},o=s.data.recentActivity||{},d=s.data.systemAverages||{},u=s.data.realtimeMetrics||{},f=s.data.systemHealth||{};N.value={totalApiKeys:i.totalApiKeys||0,activeApiKeys:i.activeApiKeys||0,totalAccounts:i.totalClaudeAccounts||0,activeAccounts:i.activeClaudeAccounts||0,rateLimitedAccounts:i.rateLimitedClaudeAccounts||0,todayRequests:o.requestsToday||0,totalRequests:i.totalRequestsUsed||0,todayTokens:o.tokensToday||0,todayInputTokens:o.inputTokensToday||0,todayOutputTokens:o.outputTokensToday||0,totalTokens:i.totalTokensUsed||0,totalInputTokens:i.totalInputTokensUsed||0,totalOutputTokens:i.totalOutputTokensUsed||0,totalCacheCreateTokens:i.totalCacheCreateTokensUsed||0,totalCacheReadTokens:i.totalCacheReadTokensUsed||0,todayCacheCreateTokens:o.cacheCreateTokensToday||0,todayCacheReadTokens:o.cacheReadTokensToday||0,systemRPM:d.rpm||0,systemTPM:d.tpm||0,realtimeRPM:u.rpm||0,realtimeTPM:u.tpm||0,metricsWindow:u.windowMinutes||5,isHistoricalMetrics:u.isHistorical||!1,systemStatus:f.redisConnected?"正常":"异常",uptime:f.uptime||0,systemTimezone:s.data.systemTimezone||8}}r.success&&l.success&&(c.value={todayCosts:r.data.totalCosts||{totalCost:0,formatted:{totalCost:"$0.000000"}},totalCosts:l.data.totalCosts||{totalCost:0,formatted:{totalCost:"$0.000000"}}})}catch(s){console.error("加载仪表板数据失败:",s)}finally{nt.value=!1}}async function rt(s=7,r="day"){try{let l="/admin/usage-trend?";if(r==="hour")if(l+="granularity=hour",n.value.customRange&&n.value.customRange.length===2){const o=d=>{const[f,m]=d.split(" "),[$,P,F]=f.split("-").map(Number),[K,L,B]=m.split(":").map(Number);return new Date(Date.UTC($,P-1,F,K-8,L,B)).toISOString()};l+=`&startDate=${encodeURIComponent(o(n.value.customRange[0]))}`,l+=`&endDate=${encodeURIComponent(o(n.value.customRange[1]))}`}else{const o=new Date;let d,u;if(n.value.type==="preset")switch(n.value.preset){case"last24h":u=new Date(o),d=new Date(o.getTime()-24*60*60*1e3);break;case"yesterday":const f=new Date;f.setDate(f.getDate()-1),d=A(f,!0),u=A(f,!1);break;case"dayBefore":const m=new Date;m.setDate(m.getDate()-2),d=A(m,!0),u=A(m,!1);break;default:d=new Date(o.getTime()-24*60*60*1e3),u=o}else d=new Date(o.getTime()-s*24*60*60*1e3),u=o;l+=`&startDate=${encodeURIComponent(d.toISOString())}`,l+=`&endDate=${encodeURIComponent(u.toISOString())}`}else l+=`granularity=day&days=${s}`;const i=await J.get(l);i.success&&(H.value=i.data)}catch(l){console.error("加载使用趋势失败:",l)}}async function it(s="daily"){try{const r=await J.get(`/admin/model-stats?period=${s}`);r.success&&(X.value=r.data)}catch(r){console.error("加载模型统计失败:",r)}}async function tt(s="requests"){try{let r="/admin/api-keys-usage-trend?",l=7;if(S.value==="hour")if(r+="granularity=hour",n.value.customRange&&n.value.customRange.length===2){const o=d=>{const[f,m]=d.split(" "),[$,P,F]=f.split("-").map(Number),[K,L,B]=m.split(":").map(Number);return new Date(Date.UTC($,P-1,F,K-8,L,B)).toISOString()};r+=`&startDate=${encodeURIComponent(o(n.value.customRange[0]))}`,r+=`&endDate=${encodeURIComponent(o(n.value.customRange[1]))}`}else{const o=new Date;let d,u;if(n.value.type==="preset")switch(n.value.preset){case"last24h":u=new Date(o),d=new Date(o.getTime()-24*60*60*1e3);break;case"yesterday":const f=new Date;f.setDate(f.getDate()-1),d=A(f,!0),u=A(f,!1);break;case"dayBefore":const m=new Date;m.setDate(m.getDate()-2),d=A(m,!0),u=A(m,!1);break;default:d=new Date(o.getTime()-24*60*60*1e3),u=o}else d=new Date(o.getTime()-24*60*60*1e3),u=o;r+=`&startDate=${encodeURIComponent(d.toISOString())}`,r+=`&endDate=${encodeURIComponent(u.toISOString())}`}else l=n.value.type==="preset"?n.value.preset==="today"?1:n.value.preset==="7days"?7:30:Q(n.value.customStart,n.value.customEnd),r+=`granularity=day&days=${l}`;r+=`&metric=${s}`;const i=await J.get(r);i.success&&(M.value={data:i.data||[],topApiKeys:i.topApiKeys||[],totalApiKeys:i.totalApiKeys||0})}catch(r){console.error("加载API Keys趋势失败:",r)}}function j(s){n.value.type="preset",n.value.preset=s;const r=n.value.presetOptions.find(l=>l.value===s);if(r){const l=new Date;let i,o;if(S.value==="hour")switch(s){case"last24h":o=new Date(l),i=new Date(l.getTime()-24*60*60*1e3);break;case"yesterday":const d=new Date;d.setDate(d.getDate()-1),i=A(d,!0),o=A(d,!1);break;case"dayBefore":const u=new Date;u.setDate(u.getDate()-2),i=A(u,!0),o=A(u,!1);break}else i=new Date(l),o=new Date(l),s==="today"?(i.setHours(0,0,0,0),o.setHours(23,59,59,999)):(i.setDate(l.getDate()-(r.days-1)),i.setHours(0,0,0,0),o.setHours(23,59,59,999));if(n.value.customStart=i.toISOString().split("T")[0],n.value.customEnd=o.toISOString().split("T")[0],S.value==="hour"&&(s==="yesterday"||s==="dayBefore")){const d=new Date;s==="yesterday"?d.setDate(d.getDate()-1):d.setDate(d.getDate()-2);const u=d.getFullYear(),f=String(d.getMonth()+1).padStart(2,"0"),m=String(d.getDate()).padStart(2,"0");n.value.customRange=[`${u}-${f}-${m} 00:00:00`,`${u}-${f}-${m} 23:59:59`]}else{const d=u=>{const $=new Date(u.getTime()+288e5),P=$.getUTCFullYear(),F=String($.getUTCMonth()+1).padStart(2,"0"),K=String($.getUTCDate()).padStart(2,"0"),L=String($.getUTCHours()).padStart(2,"0"),B=String($.getUTCMinutes()).padStart(2,"0"),Z=String($.getUTCSeconds()).padStart(2,"0");return`${P}-${F}-${K} ${L}:${B}:${Z}`};n.value.customRange=[d(i),d(o)]}}E()}function ft(s){if(s&&s.length===2){n.value.type="custom",n.value.preset="",n.value.customRange=s,n.value.customStart=s[0].split(" ")[0],n.value.customEnd=s[1].split(" ")[0],N.value.systemTimezone;const r=o=>{const[d,u]=o.split(" "),[f,m,$]=d.split("-").map(Number),[P,F,K]=u.split(":").map(Number);return new Date(f,m-1,$,P,F,K)},l=r(s[0]),i=r(s[1]);if(S.value==="hour"){if((i-l)/36e5>24){xt("小时粒度下日期范围不能超过24小时","warning");return}}else if(Math.ceil((i-l)/864e5)+1>31){xt("日期范围不能超过 31 天","warning");return}E()}else s===null&&j(S.value==="hour"?"last24h":"7days")}function et(s){if(S.value=s,s==="hour"){if(n.value.presetOptions=[{value:"last24h",label:"近24小时",hours:24},{value:"yesterday",label:"昨天",hours:24},{value:"dayBefore",label:"前天",hours:24}],n.value.type==="custom"&&n.value.customRange&&n.value.customRange.length===2){const r=new Date(n.value.customRange[0]);if((new Date(n.value.customRange[1])-r)/(1e3*60*60)>24){xt("小时粒度下日期范围不能超过24小时,已切换到近24小时","warning"),j("last24h");return}}if(["today","7days","30days"].includes(n.value.preset)){j("last24h");return}}else if(n.value.presetOptions=[{value:"today",label:"今日",days:1},{value:"7days",label:"7天",days:7},{value:"30days",label:"30天",days:30}],["last24h","yesterday","dayBefore"].includes(n.value.preset)){j("7days");return}E()}async function E(){let s,r="monthly";if(n.value.type==="preset"){const l=n.value.presetOptions.find(i=>i.value===n.value.preset);S.value==="hour"?(s=1,r="daily"):(s=l?l.days:7,n.value.preset==="today"?r="daily":r="monthly")}else{if(S.value==="hour"){const l=new Date(n.value.customRange[0]),i=new Date(n.value.customRange[1]),o=Math.ceil((i-l)/(1e3*60*60));s=Math.ceil(o/24)||1}else s=Q(n.value.customStart,n.value.customEnd);r="daily"}await Promise.all([rt(s,S.value),it(r),tt(q.value)])}function Q(s,r){if(!s||!r)return 7;const l=new Date(s),i=new Date(r),o=Math.abs(i-l);return Math.ceil(o/(1e3*60*60*24))||7}function Y(s){return s>new Date}return{loading:nt,dashboardData:N,costsData:c,modelStats:lt,trendData:H,dashboardModelStats:X,apiKeysTrendData:M,dateFilter:n,trendGranularity:S,apiKeysTrendMetric:q,defaultTime:I,formattedUptime:pt,loadDashboardData:yt,loadUsageTrend:rt,loadModelStats:it,loadApiKeysTrend:tt,setDateFilterPreset:j,onCustomDateRangeChange:ft,setTrendGranularity:et,refreshChartsData:E,disabledDate:Y}}),It={class:"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6 mb-8"},Pt={class:"stat-card"},Ft={class:"flex items-center justify-between"},Ot={class:"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-3xl font-bold text-gray-900"},Et={class:"text-xs text-gray-500 mt-1"},Lt={key:0,class:"text-yellow-600"},Vt={class:"stat-card"},Nt={class:"flex items-center justify-between"},jt={class:"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-3xl font-bold text-green-600"},Zt={class:"text-xs text-gray-500 mt-1"},Jt={class:"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6 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-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-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"},ke={class:"font-medium"},Te={class:"font-medium"},Ce={key:0,class:"text-purple-600"},De={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-sm font-semibold text-gray-600 mb-1"},Ae={class:"text-xs text-gray-400"},Me={class:"text-3xl font-bold text-orange-600"},Ue={class:"text-xs text-gray-500 mt-1"},Ke={key:0,class:"text-yellow-600"},Ie={class:"stat-card"},Pe={class:"flex items-center justify-between"},Fe={class:"text-sm font-semibold text-gray-600 mb-1"},Oe={class:"text-xs text-gray-400"},Be={class:"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 lg:flex-row lg:items-center lg:justify-between gap-4 mb-6"},Le={class:"flex flex-wrap gap-2 items-center"},Ve={class:"flex gap-1 bg-gray-100 rounded-lg p-1"},Ne=["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:"grid grid-cols-1 lg:grid-cols-2 gap-6"},es={class:"card p-6"},ss={class:"relative",style:{height:"300px"}},as={class:"card p-6"},os={key:0,class:"text-center py-8"},ns={key:1,class:"overflow-auto max-h-[300px]"},ls={class:"min-w-full"},rs={class:"divide-y divide-gray-200"},is={class:"px-4 py-2 text-sm text-gray-900"},ds={class:"px-4 py-2 text-sm text-gray-600 text-right"},us={class:"px-4 py-2 text-sm text-gray-600 text-right"},cs={class:"px-4 py-2 text-sm text-green-600 text-right font-medium"},ms={class:"px-4 py-2 text-sm font-medium text-right"},ps={class:"inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-blue-100 text-blue-800"},ys={class:"mb-8"},fs={class:"card p-6"},gs={style:{height:"300px"}},xs={class:"mb-8"},vs={class:"card p-6"},hs={class:"flex items-center justify-between mb-4"},bs={class:"flex gap-1 bg-gray-100 rounded-lg p-1"},ks={class:"mb-4 text-sm text-gray-600"},Ts={key:0},Cs={key:1},Ds={style:{height:"350px"}},ws={__name:"DashboardView",setup(nt){const N=Kt(),{dashboardData:c,costsData:lt,dashboardModelStats:H,trendData:X,apiKeysTrendData:M,formattedUptime:n,dateFilter:S,trendGranularity:q,apiKeysTrendMetric:I,defaultTime:pt}=_t(N),{loadDashboardData:A,loadApiKeysTrend:yt,setDateFilterPreset:rt,onCustomDateRangeChange:it,setTrendGranularity:tt,refreshChartsData:j,disabledDate:ft}=N,et=T(null),E=T(null),Q=T(null);let Y=null,s=null,r=null;const l=T(!1),i=T(30),o=T(null),d=T(0),u=T(null),f=T(!1);Tt(()=>!l.value||d.value<=0?"":`${d.value}秒后刷新`);function m(v){return v>=1e6?(v/1e6).toFixed(2)+"M":v>=1e3?(v/1e3).toFixed(2)+"K":v.toString()}function $(v,e){if(!e||e.length===0)return 0;const C=e.reduce((g,V)=>g+V.allTokens,0);return C===0?0:(v/C*100).toFixed(1)}function P(){if(!et.value)return;Y&&Y.destroy();const v=H.value||[],e={labels:v.map(C=>C.model),datasets:[{data:v.map(C=>C.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(C){const g=C.label||"",V=m(C.parsed),st=$(C.parsed,v);return`${g}: ${V} (${st}%)`}}}}}})}function F(){var D;if(!E.value)return;s&&s.destroy();const v=X.value||[],e=v.map(y=>y.inputTokens||0),C=v.map(y=>y.outputTokens||0),g=v.map(y=>y.cacheCreateTokens||0),V=v.map(y=>y.cacheReadTokens||0),st=v.map(y=>y.requests||0),dt=v.map(y=>y.cost||0),ut=(D=v[0])!=null&&D.date?"date":"hour",U={labels:v.map(y=>{if(y.label)return y.label;if(ut==="hour"){const x=new Date(y.hour),R=String(x.getMonth()+1).padStart(2,"0"),W=String(x.getDate()).padStart(2,"0"),ct=String(x.getHours()).padStart(2,"0");return`${R}/${W} ${ct}:00`}const b=y.date;if(b&&b.includes("-")){const x=b.split("-");if(x.length>=3)return`${x[1]}/${x[2]}`}return y.date}),datasets:[{label:"输入Token",data:e,borderColor:"rgb(102, 126, 234)",backgroundColor:"rgba(102, 126, 234, 0.1)",tension:.3},{label:"输出Token",data:C,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:V,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"}]};s=new vt(E.value,{type:"line",data:U,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(y,b){const x=y.dataset.label||"",R=b.dataset.label||"";return x==="费用 (USD)"||R==="费用 (USD)"?x==="费用 (USD)"?-1:1:x==="请求数"||R==="请求数"?x==="请求数"?1:-1:b.parsed.y-y.parsed.y},callbacks:{label:function(y){const b=y.dataset.label||"";let x=y.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:q.value==="hour"?"时间":"日期"}},y:{type:"linear",display:!0,position:"left",title:{display:!0,text:"Token数量"},ticks:{callback:function(y){return m(y)}}},y1:{type:"linear",display:!0,position:"right",title:{display:!0,text:"请求数"},grid:{drawOnChartArea:!1},ticks:{callback:function(y){return y.toLocaleString()}}},y2:{type:"linear",display:!1,position:"right"}}}})}function K(){var dt,ut;if(!Q.value)return;r&&r.destroy();const v=M.value.data||[],e=I.value,C=["#3B82F6","#10B981","#F59E0B","#EF4444","#8B5CF6","#EC4899","#14B8A6","#F97316","#6366F1","#84CC16"],g=((dt=M.value.topApiKeys)==null?void 0:dt.map((h,U)=>{var b,x;const D=M.value.data.map(R=>!R.apiKeys||!R.apiKeys[h]?0:e==="tokens"?R.apiKeys[h].tokens:R.apiKeys[h].requests||0);return{label:((x=(b=M.value.data.find(R=>R.apiKeys&&R.apiKeys[h]))==null?void 0:b.apiKeys[h])==null?void 0:x.name)||`API Key ${h}`,data:D,borderColor:C[U%C.length],backgroundColor:C[U%C.length]+"20",tension:.4,fill:!1}}))||[],V=(ut=v[0])!=null&&ut.date?"date":"hour",st={labels:v.map(h=>{if(h.label)return h.label;if(V==="hour"){const D=new Date(h.hour),y=String(D.getMonth()+1).padStart(2,"0"),b=String(D.getDate()).padStart(2,"0"),x=String(D.getHours()).padStart(2,"0");return`${y}/${b} ${x}:00`}const U=h.date;if(U&&U.includes("-")){const D=U.split("-");if(D.length>=3)return`${D[1]}/${D[2]}`}return h.date}),datasets:g};r=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,U){return U.parsed.y-h.parsed.y},callbacks:{label:function(h){var ct;const U=h.dataset.label||"",D=h.parsed.y,y=h.dataIndex,b=M.value.data[y],R=h.chart.data.datasets.map((O,at)=>({value:O.data[y]||0,index:at})).sort((O,at)=>at.value-O.value).findIndex(O=>O.index===h.datasetIndex)+1;let W="";if(R===1?W="🥇 ":R===2?W="🥈 ":R===3&&(W="🥉 "),I.value==="tokens"){let O="";D>=1e6?O=(D/1e6).toFixed(2)+"M":D>=1e3?O=(D/1e3).toFixed(2)+"K":O=D.toLocaleString();const at=M.value.topApiKeys[h.datasetIndex],gt=(ct=b==null?void 0:b.apiKeys)==null?void 0:ct[at],Ct=(gt==null?void 0:gt.formattedCost)||"$0.00";return`${W}${U}: ${O} tokens (${Ct})`}else return`${W}${U}: ${D.toLocaleString()} 次`}}}},scales:{x:{type:"category",display:!0,title:{display:!0,text:q.value==="hour"?"时间":"日期"}},y:{beginAtZero:!0,title:{display:!0,text:I.value==="tokens"?"Token 数量":"请求次数"},ticks:{callback:function(h){return m(h)}}}}}})}async function L(){await yt(I.value),await ot(),K()}mt(H,()=>{ot(()=>P())}),mt(X,()=>{ot(()=>F())}),mt(M,()=>{ot(()=>K())});async function B(){if(!f.value){f.value=!0;try{await Promise.all([A(),j()])}finally{f.value=!1}}}function Z(){l.value&&(d.value=i.value,u.value&&clearInterval(u.value),o.value&&clearTimeout(o.value),u.value=setInterval(()=>{d.value--,d.value<=0&&clearInterval(u.value)},1e3),o.value=setTimeout(async()=>{await B(),l.value&&Z()},i.value*1e3))}function ht(){u.value&&(clearInterval(u.value),u.value=null),o.value&&(clearTimeout(o.value),o.value=null),d.value=0}return mt(l,v=>{v?Z():ht()}),St(async()=>{await B(),await ot(),P(),F(),K()}),Rt(()=>{ht(),Y&&Y.destroy(),s&&s.destroy(),r&&r.destroy()}),(v,e)=>{const C=Dt;return _(),w("div",null,[t("div",It,[t("div",Pt,[t("div",Ft,[t("div",null,[e[7]||(e[7]=t("p",{class:"text-sm font-semibold text-gray-600 mb-1"}," 总API Keys ",-1)),t("p",Ot,p(a(c).totalApiKeys),1),t("p",Bt," 活跃: "+p(a(c).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-sm font-semibold text-gray-600 mb-1"}," 服务账户 ",-1)),t("p",qt,p(a(c).totalAccounts),1),t("p",Et,[k(" 活跃: "+p(a(c).activeAccounts||0)+" ",1),a(c).rateLimitedAccounts>0?(_(),w("span",Lt," | 限流: "+p(a(c).rateLimitedAccounts),1)):z("",!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",Vt,[t("div",Nt,[t("div",null,[e[11]||(e[11]=t("p",{class:"text-sm font-semibold text-gray-600 mb-1"}," 今日请求 ",-1)),t("p",jt,p(a(c).todayRequests),1),t("p",Yt," 总请求: "+p(m(a(c).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-sm font-semibold text-gray-600 mb-1"}," 系统状态 ",-1)),t("p",Qt,p(a(c).systemStatus),1),t("p",Zt," 运行时间: "+p(a(n)),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-sm font-semibold text-gray-600 mb-1"}," 今日Token ",-1)),t("div",se,[t("p",ae,p(m((a(c).todayInputTokens||0)+(a(c).todayOutputTokens||0)+(a(c).todayCacheCreateTokens||0)+(a(c).todayCacheReadTokens||0))),1),t("span",oe,"/ "+p(a(lt).todayCosts.formatted.totalCost),1)]),t("div",ne,[t("div",le,[t("span",null,[e[15]||(e[15]=k("输入: ",-1)),t("span",re,p(m(a(c).todayInputTokens||0)),1)]),t("span",null,[e[16]||(e[16]=k("输出: ",-1)),t("span",ie,p(m(a(c).todayOutputTokens||0)),1)]),(a(c).todayCacheCreateTokens||0)>0?(_(),w("span",de,[e[17]||(e[17]=k("缓存创建: ",-1)),t("span",ue,p(m(a(c).todayCacheCreateTokens||0)),1)])):z("",!0),(a(c).todayCacheReadTokens||0)>0?(_(),w("span",ce,[e[18]||(e[18]=k("缓存读取: ",-1)),t("span",me,p(m(a(c).todayCacheReadTokens||0)),1)])):z("",!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-sm font-semibold text-gray-600 mb-1"}," 总Token消耗 ",-1)),t("div",ge,[t("p",xe,p(m((a(c).totalInputTokens||0)+(a(c).totalOutputTokens||0)+(a(c).totalCacheCreateTokens||0)+(a(c).totalCacheReadTokens||0))),1),t("span",ve,"/ "+p(a(lt).totalCosts.formatted.totalCost),1)]),t("div",he,[t("div",be,[t("span",null,[e[21]||(e[21]=k("输入: ",-1)),t("span",ke,p(m(a(c).totalInputTokens||0)),1)]),t("span",null,[e[22]||(e[22]=k("输出: ",-1)),t("span",Te,p(m(a(c).totalOutputTokens||0)),1)]),(a(c).totalCacheCreateTokens||0)>0?(_(),w("span",Ce,[e[23]||(e[23]=k("缓存创建: ",-1)),t("span",De,p(m(a(c).totalCacheCreateTokens||0)),1)])):z("",!0),(a(c).totalCacheReadTokens||0)>0?(_(),w("span",we,[e[24]||(e[24]=k("缓存读取: ",-1)),t("span",_e,p(m(a(c).totalCacheReadTokens||0)),1)])):z("",!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]=k(" 实时RPM ",-1)),t("span",Ae,"("+p(a(c).metricsWindow)+"分钟)",1)]),t("p",Me,p(a(c).realtimeRPM||0),1),t("p",Ue,[e[29]||(e[29]=k(" 每分钟请求数 ",-1)),a(c).isHistoricalMetrics?(_(),w("span",Ke,e[28]||(e[28]=[t("i",{class:"fas fa-exclamation-circle"},null,-1),k(" 历史数据 ",-1)]))):z("",!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",Ie,[t("div",Pe,[t("div",null,[t("p",Fe,[e[31]||(e[31]=k(" 实时TPM ",-1)),t("span",Oe,"("+p(a(c).metricsWindow)+"分钟)",1)]),t("p",Be,p(m(a(c).realtimeTPM||0)),1),t("p",ze,[e[33]||(e[33]=k(" 每分钟Token数 ",-1)),a(c).isHistoricalMetrics?(_(),w("span",He,e[32]||(e[32]=[t("i",{class:"fas fa-exclamation-circle"},null,-1),k(" 历史数据 ",-1)]))):z("",!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-xl font-bold text-gray-900"}," 模型使用分布与Token使用趋势 ",-1)),t("div",Le,[t("div",Ve,[(_(!0),w(bt,null,kt(a(S).presetOptions,g=>(_(),w("button",{key:g.value,class:G(["px-3 py-1 rounded-md text-sm font-medium transition-colors",a(S).preset===g.value&&a(S).type==="preset"?"bg-white text-blue-600 shadow-sm":"text-gray-600 hover:text-gray-900"]),onClick:V=>a(rt)(g.value)},p(g.label),11,Ne))),128))]),t("div",je,[t("button",{class:G(["px-3 py-1 rounded-md text-sm font-medium transition-colors",a(q)==="day"?"bg-white text-blue-600 shadow-sm":"text-gray-600 hover:text-gray-900"]),onClick:e[0]||(e[0]=g=>a(tt)("day"))},e[35]||(e[35]=[t("i",{class:"fas fa-calendar-day mr-1"},null,-1),k("按天 ",-1)]),2),t("button",{class:G(["px-3 py-1 rounded-md text-sm font-medium transition-colors",a(q)==="hour"?"bg-white text-blue-600 shadow-sm":"text-gray-600 hover:text-gray-900"]),onClick:e[1]||(e[1]=g=>a(tt)("hour"))},e[36]||(e[36]=[t("i",{class:"fas fa-clock mr-1"},null,-1),k("按小时 ",-1)]),2)]),t("div",Ye,[$t(C,{modelValue:a(S).customRange,"onUpdate:modelValue":e[2]||(e[2]=g=>a(S).customRange=g),"default-time":a(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":a(ft),size:"default",style:{width:"400px"},class:"custom-date-picker",onChange:a(it)},null,8,["modelValue","default-time","disabled-date","onChange"]),a(q)==="hour"?(_(),w("span",We,e[37]||(e[37]=[t("i",{class:"fas fa-info-circle"},null,-1),k(" 最多24小时 ",-1)]))):z("",!0)]),t("div",Ge,[t("div",Qe,[t("label",Ze,[At(t("input",{"onUpdate:modelValue":e[3]||(e[3]=g=>l.value=g),type:"checkbox",class:"sr-only peer"},null,512),[[Mt,l.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)),l.value?(_(),w("span",{key:0,class:G(["ml-1 text-xs text-blue-600 font-mono transition-opacity",d.value>0?"opacity-100":"opacity-0"])},p(d.value)+"s ",3)):z("",!0)])])]),t("button",{disabled:f.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-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":f.value}])},null,2),t("span",null,p(f.value?"刷新中":"刷新"),1)],8,Xe)])])]),t("div",ts,[t("div",es,[e[42]||(e[42]=t("h4",{class:"text-lg font-semibold text-gray-800 mb-4"}," Token使用分布 ",-1)),t("div",ss,[t("canvas",{ref_key:"modelUsageChart",ref:et},null,512)])]),t("div",as,[e[45]||(e[45]=t("h4",{class:"text-lg font-semibold text-gray-800 mb-4"}," 详细统计数据 ",-1)),a(H).length===0?(_(),w("div",os,e[43]||(e[43]=[t("p",{class:"text-gray-500"}," 暂无模型使用数据 ",-1)]))):(_(),w("div",ns,[t("table",ls,[e[44]||(e[44]=t("thead",{class:"bg-gray-50 sticky top-0"},[t("tr",null,[t("th",{class:"px-4 py-2 text-left text-xs font-medium text-gray-700"}," 模型 "),t("th",{class:"px-4 py-2 text-right text-xs font-medium text-gray-700"}," 请求数 "),t("th",{class:"px-4 py-2 text-right text-xs font-medium text-gray-700"}," 总Token "),t("th",{class:"px-4 py-2 text-right text-xs font-medium text-gray-700"}," 费用 "),t("th",{class:"px-4 py-2 text-right text-xs font-medium text-gray-700"}," 占比 ")])],-1)),t("tbody",rs,[(_(!0),w(bt,null,kt(a(H),g=>(_(),w("tr",{key:g.model,class:"hover:bg-gray-50"},[t("td",is,p(g.model),1),t("td",ds,p(m(g.requests)),1),t("td",us,p(m(g.allTokens)),1),t("td",cs,p(g.formatted?g.formatted.total:"$0.000000"),1),t("td",ms,[t("span",ps,p($(g.allTokens,a(H)))+"% ",1)])]))),128))])])]))])])]),t("div",ys,[t("div",fs,[t("div",gs,[t("canvas",{ref_key:"usageTrendChart",ref:E},null,512)])])]),t("div",xs,[t("div",vs,[t("div",hs,[e[48]||(e[48]=t("h3",{class:"text-lg font-semibold text-gray-900"}," API Keys 使用趋势 ",-1)),t("div",bs,[t("button",{class:G(["px-3 py-1 rounded-md text-sm font-medium transition-colors",a(I)==="requests"?"bg-white text-blue-600 shadow-sm":"text-gray-600 hover:text-gray-900"]),onClick:e[5]||(e[5]=g=>{I.value="requests",L()})},e[46]||(e[46]=[t("i",{class:"fas fa-exchange-alt mr-1"},null,-1),k("请求次数 ",-1)]),2),t("button",{class:G(["px-3 py-1 rounded-md text-sm font-medium transition-colors",a(I)==="tokens"?"bg-white text-blue-600 shadow-sm":"text-gray-600 hover:text-gray-900"]),onClick:e[6]||(e[6]=g=>{I.value="tokens",L()})},e[47]||(e[47]=[t("i",{class:"fas fa-coins mr-1"},null,-1),k("Token 数量 ",-1)]),2)])]),t("div",ks,[a(M).totalApiKeys>10?(_(),w("span",Ts," 共 "+p(a(M).totalApiKeys)+" 个 API Key,显示使用量前 10 个 ",1)):(_(),w("span",Cs," 共 "+p(a(M).totalApiKeys)+" 个 API Key ",1))]),t("div",Ds,[t("canvas",{ref_key:"apiKeysUsageTrendChart",ref:Q},null,512)])])])])}}},Us=Ut(ws,[["__scopeId","data-v-e2cbd0e3"]]);export{Us as default};
+import{E as Dt}from"./element-plus-B8Fs_0jW.js";import{aR as wt,r as T,c as Tt,aW as _t,o as mt,q as St,D as ot,V as Rt,x as w,z as t,P as p,u as a,O as k,L as z,Q as bt,ac as kt,C as G,R as $t,K as At,al as Mt,y as _}from"./vue-vendor-CKToUHZx.js";import{a as J,_ as Ut}from"./index-HYE9xPuR.js";import{s as xt}from"./toast-BvwA7Mwb.js";import{C as vt}from"./chart-Cor9iTVD.js";import"./vendor-BDiMbLwQ.js";const Kt=wt("dashboard",()=>{const nt=T(!1),N=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}),c=T({todayCosts:{totalCost:0,formatted:{totalCost:"$0.000000"}},totalCosts:{totalCost:0,formatted:{totalCost:"$0.000000"}}}),lt=T([]),H=T([]),X=T([]),M=T({data:[],topApiKeys:[],totalApiKeys:0}),n=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}]}),S=T("day"),q=T("requests"),I=T([new Date(2e3,1,1,0,0,0),new Date(2e3,2,1,23,59,59)]),pt=Tt(()=>{const s=N.value.uptime,r=Math.floor(s/86400),l=Math.floor(s%86400/3600),i=Math.floor(s%3600/60);return r>0?`${r}天 ${l}小时`:l>0?`${l}小时 ${i}分钟`:`${i}分钟`});function A(s,r=!0){const l=s.getFullYear(),i=s.getMonth(),o=s.getDate();return r?new Date(Date.UTC(l,i,o-1,16,0,0,0)):new Date(Date.UTC(l,i,o,15,59,59,999))}async function yt(){nt.value=!0;try{const[s,r,l]=await Promise.all([J.get("/admin/dashboard"),J.get("/admin/usage-costs?period=today"),J.get("/admin/usage-costs?period=all")]);if(s.success){const i=s.data.overview||{},o=s.data.recentActivity||{},d=s.data.systemAverages||{},u=s.data.realtimeMetrics||{},f=s.data.systemHealth||{};N.value={totalApiKeys:i.totalApiKeys||0,activeApiKeys:i.activeApiKeys||0,totalAccounts:i.totalClaudeAccounts||0,activeAccounts:i.activeClaudeAccounts||0,rateLimitedAccounts:i.rateLimitedClaudeAccounts||0,todayRequests:o.requestsToday||0,totalRequests:i.totalRequestsUsed||0,todayTokens:o.tokensToday||0,todayInputTokens:o.inputTokensToday||0,todayOutputTokens:o.outputTokensToday||0,totalTokens:i.totalTokensUsed||0,totalInputTokens:i.totalInputTokensUsed||0,totalOutputTokens:i.totalOutputTokensUsed||0,totalCacheCreateTokens:i.totalCacheCreateTokensUsed||0,totalCacheReadTokens:i.totalCacheReadTokensUsed||0,todayCacheCreateTokens:o.cacheCreateTokensToday||0,todayCacheReadTokens:o.cacheReadTokensToday||0,systemRPM:d.rpm||0,systemTPM:d.tpm||0,realtimeRPM:u.rpm||0,realtimeTPM:u.tpm||0,metricsWindow:u.windowMinutes||5,isHistoricalMetrics:u.isHistorical||!1,systemStatus:f.redisConnected?"正常":"异常",uptime:f.uptime||0,systemTimezone:s.data.systemTimezone||8}}r.success&&l.success&&(c.value={todayCosts:r.data.totalCosts||{totalCost:0,formatted:{totalCost:"$0.000000"}},totalCosts:l.data.totalCosts||{totalCost:0,formatted:{totalCost:"$0.000000"}}})}catch(s){console.error("加载仪表板数据失败:",s)}finally{nt.value=!1}}async function rt(s=7,r="day"){try{let l="/admin/usage-trend?";if(r==="hour")if(l+="granularity=hour",n.value.customRange&&n.value.customRange.length===2){const o=d=>{const[f,m]=d.split(" "),[$,P,F]=f.split("-").map(Number),[K,L,B]=m.split(":").map(Number);return new Date(Date.UTC($,P-1,F,K-8,L,B)).toISOString()};l+=`&startDate=${encodeURIComponent(o(n.value.customRange[0]))}`,l+=`&endDate=${encodeURIComponent(o(n.value.customRange[1]))}`}else{const o=new Date;let d,u;if(n.value.type==="preset")switch(n.value.preset){case"last24h":u=new Date(o),d=new Date(o.getTime()-24*60*60*1e3);break;case"yesterday":const f=new Date;f.setDate(f.getDate()-1),d=A(f,!0),u=A(f,!1);break;case"dayBefore":const m=new Date;m.setDate(m.getDate()-2),d=A(m,!0),u=A(m,!1);break;default:d=new Date(o.getTime()-24*60*60*1e3),u=o}else d=new Date(o.getTime()-s*24*60*60*1e3),u=o;l+=`&startDate=${encodeURIComponent(d.toISOString())}`,l+=`&endDate=${encodeURIComponent(u.toISOString())}`}else l+=`granularity=day&days=${s}`;const i=await J.get(l);i.success&&(H.value=i.data)}catch(l){console.error("加载使用趋势失败:",l)}}async function it(s="daily"){try{const r=await J.get(`/admin/model-stats?period=${s}`);r.success&&(X.value=r.data)}catch(r){console.error("加载模型统计失败:",r)}}async function tt(s="requests"){try{let r="/admin/api-keys-usage-trend?",l=7;if(S.value==="hour")if(r+="granularity=hour",n.value.customRange&&n.value.customRange.length===2){const o=d=>{const[f,m]=d.split(" "),[$,P,F]=f.split("-").map(Number),[K,L,B]=m.split(":").map(Number);return new Date(Date.UTC($,P-1,F,K-8,L,B)).toISOString()};r+=`&startDate=${encodeURIComponent(o(n.value.customRange[0]))}`,r+=`&endDate=${encodeURIComponent(o(n.value.customRange[1]))}`}else{const o=new Date;let d,u;if(n.value.type==="preset")switch(n.value.preset){case"last24h":u=new Date(o),d=new Date(o.getTime()-24*60*60*1e3);break;case"yesterday":const f=new Date;f.setDate(f.getDate()-1),d=A(f,!0),u=A(f,!1);break;case"dayBefore":const m=new Date;m.setDate(m.getDate()-2),d=A(m,!0),u=A(m,!1);break;default:d=new Date(o.getTime()-24*60*60*1e3),u=o}else d=new Date(o.getTime()-24*60*60*1e3),u=o;r+=`&startDate=${encodeURIComponent(d.toISOString())}`,r+=`&endDate=${encodeURIComponent(u.toISOString())}`}else l=n.value.type==="preset"?n.value.preset==="today"?1:n.value.preset==="7days"?7:30:Q(n.value.customStart,n.value.customEnd),r+=`granularity=day&days=${l}`;r+=`&metric=${s}`;const i=await J.get(r);i.success&&(M.value={data:i.data||[],topApiKeys:i.topApiKeys||[],totalApiKeys:i.totalApiKeys||0})}catch(r){console.error("加载API Keys趋势失败:",r)}}function j(s){n.value.type="preset",n.value.preset=s;const r=n.value.presetOptions.find(l=>l.value===s);if(r){const l=new Date;let i,o;if(S.value==="hour")switch(s){case"last24h":o=new Date(l),i=new Date(l.getTime()-24*60*60*1e3);break;case"yesterday":const d=new Date;d.setDate(d.getDate()-1),i=A(d,!0),o=A(d,!1);break;case"dayBefore":const u=new Date;u.setDate(u.getDate()-2),i=A(u,!0),o=A(u,!1);break}else i=new Date(l),o=new Date(l),s==="today"?(i.setHours(0,0,0,0),o.setHours(23,59,59,999)):(i.setDate(l.getDate()-(r.days-1)),i.setHours(0,0,0,0),o.setHours(23,59,59,999));if(n.value.customStart=i.toISOString().split("T")[0],n.value.customEnd=o.toISOString().split("T")[0],S.value==="hour"&&(s==="yesterday"||s==="dayBefore")){const d=new Date;s==="yesterday"?d.setDate(d.getDate()-1):d.setDate(d.getDate()-2);const u=d.getFullYear(),f=String(d.getMonth()+1).padStart(2,"0"),m=String(d.getDate()).padStart(2,"0");n.value.customRange=[`${u}-${f}-${m} 00:00:00`,`${u}-${f}-${m} 23:59:59`]}else{const d=u=>{const $=new Date(u.getTime()+288e5),P=$.getUTCFullYear(),F=String($.getUTCMonth()+1).padStart(2,"0"),K=String($.getUTCDate()).padStart(2,"0"),L=String($.getUTCHours()).padStart(2,"0"),B=String($.getUTCMinutes()).padStart(2,"0"),Z=String($.getUTCSeconds()).padStart(2,"0");return`${P}-${F}-${K} ${L}:${B}:${Z}`};n.value.customRange=[d(i),d(o)]}}E()}function ft(s){if(s&&s.length===2){n.value.type="custom",n.value.preset="",n.value.customRange=s,n.value.customStart=s[0].split(" ")[0],n.value.customEnd=s[1].split(" ")[0],N.value.systemTimezone;const r=o=>{const[d,u]=o.split(" "),[f,m,$]=d.split("-").map(Number),[P,F,K]=u.split(":").map(Number);return new Date(f,m-1,$,P,F,K)},l=r(s[0]),i=r(s[1]);if(S.value==="hour"){if((i-l)/36e5>24){xt("小时粒度下日期范围不能超过24小时","warning");return}}else if(Math.ceil((i-l)/864e5)+1>31){xt("日期范围不能超过 31 天","warning");return}E()}else s===null&&j(S.value==="hour"?"last24h":"7days")}function et(s){if(S.value=s,s==="hour"){if(n.value.presetOptions=[{value:"last24h",label:"近24小时",hours:24},{value:"yesterday",label:"昨天",hours:24},{value:"dayBefore",label:"前天",hours:24}],n.value.type==="custom"&&n.value.customRange&&n.value.customRange.length===2){const r=new Date(n.value.customRange[0]);if((new Date(n.value.customRange[1])-r)/(1e3*60*60)>24){xt("小时粒度下日期范围不能超过24小时,已切换到近24小时","warning"),j("last24h");return}}if(["today","7days","30days"].includes(n.value.preset)){j("last24h");return}}else if(n.value.presetOptions=[{value:"today",label:"今日",days:1},{value:"7days",label:"7天",days:7},{value:"30days",label:"30天",days:30}],["last24h","yesterday","dayBefore"].includes(n.value.preset)){j("7days");return}E()}async function E(){let s,r="monthly";if(n.value.type==="preset"){const l=n.value.presetOptions.find(i=>i.value===n.value.preset);S.value==="hour"?(s=1,r="daily"):(s=l?l.days:7,n.value.preset==="today"?r="daily":r="monthly")}else{if(S.value==="hour"){const l=new Date(n.value.customRange[0]),i=new Date(n.value.customRange[1]),o=Math.ceil((i-l)/(1e3*60*60));s=Math.ceil(o/24)||1}else s=Q(n.value.customStart,n.value.customEnd);r="daily"}await Promise.all([rt(s,S.value),it(r),tt(q.value)])}function Q(s,r){if(!s||!r)return 7;const l=new Date(s),i=new Date(r),o=Math.abs(i-l);return Math.ceil(o/(1e3*60*60*24))||7}function Y(s){return s>new Date}return{loading:nt,dashboardData:N,costsData:c,modelStats:lt,trendData:H,dashboardModelStats:X,apiKeysTrendData:M,dateFilter:n,trendGranularity:S,apiKeysTrendMetric:q,defaultTime:I,formattedUptime:pt,loadDashboardData:yt,loadUsageTrend:rt,loadModelStats:it,loadApiKeysTrend:tt,setDateFilterPreset:j,onCustomDateRangeChange:ft,setTrendGranularity:et,refreshChartsData:E,disabledDate:Y}}),It={class:"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6 mb-8"},Pt={class:"stat-card"},Ft={class:"flex items-center justify-between"},Ot={class:"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-3xl font-bold text-gray-900"},Et={class:"text-xs text-gray-500 mt-1"},Lt={key:0,class:"text-yellow-600"},Vt={class:"stat-card"},Nt={class:"flex items-center justify-between"},jt={class:"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-3xl font-bold text-green-600"},Zt={class:"text-xs text-gray-500 mt-1"},Jt={class:"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6 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-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-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"},ke={class:"font-medium"},Te={class:"font-medium"},Ce={key:0,class:"text-purple-600"},De={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-sm font-semibold text-gray-600 mb-1"},Ae={class:"text-xs text-gray-400"},Me={class:"text-3xl font-bold text-orange-600"},Ue={class:"text-xs text-gray-500 mt-1"},Ke={key:0,class:"text-yellow-600"},Ie={class:"stat-card"},Pe={class:"flex items-center justify-between"},Fe={class:"text-sm font-semibold text-gray-600 mb-1"},Oe={class:"text-xs text-gray-400"},Be={class:"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 lg:flex-row lg:items-center lg:justify-between gap-4 mb-6"},Le={class:"flex flex-wrap gap-2 items-center"},Ve={class:"flex gap-1 bg-gray-100 rounded-lg p-1"},Ne=["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:"grid grid-cols-1 lg:grid-cols-2 gap-6"},es={class:"card p-6"},ss={class:"relative",style:{height:"300px"}},as={class:"card p-6"},os={key:0,class:"text-center py-8"},ns={key:1,class:"overflow-auto max-h-[300px]"},ls={class:"min-w-full"},rs={class:"divide-y divide-gray-200"},is={class:"px-4 py-2 text-sm text-gray-900"},ds={class:"px-4 py-2 text-sm text-gray-600 text-right"},us={class:"px-4 py-2 text-sm text-gray-600 text-right"},cs={class:"px-4 py-2 text-sm text-green-600 text-right font-medium"},ms={class:"px-4 py-2 text-sm font-medium text-right"},ps={class:"inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-blue-100 text-blue-800"},ys={class:"mb-8"},fs={class:"card p-6"},gs={style:{height:"300px"}},xs={class:"mb-8"},vs={class:"card p-6"},hs={class:"flex items-center justify-between mb-4"},bs={class:"flex gap-1 bg-gray-100 rounded-lg p-1"},ks={class:"mb-4 text-sm text-gray-600"},Ts={key:0},Cs={key:1},Ds={style:{height:"350px"}},ws={__name:"DashboardView",setup(nt){const N=Kt(),{dashboardData:c,costsData:lt,dashboardModelStats:H,trendData:X,apiKeysTrendData:M,formattedUptime:n,dateFilter:S,trendGranularity:q,apiKeysTrendMetric:I,defaultTime:pt}=_t(N),{loadDashboardData:A,loadApiKeysTrend:yt,setDateFilterPreset:rt,onCustomDateRangeChange:it,setTrendGranularity:tt,refreshChartsData:j,disabledDate:ft}=N,et=T(null),E=T(null),Q=T(null);let Y=null,s=null,r=null;const l=T(!1),i=T(30),o=T(null),d=T(0),u=T(null),f=T(!1);Tt(()=>!l.value||d.value<=0?"":`${d.value}秒后刷新`);function m(v){return v>=1e6?(v/1e6).toFixed(2)+"M":v>=1e3?(v/1e3).toFixed(2)+"K":v.toString()}function $(v,e){if(!e||e.length===0)return 0;const C=e.reduce((g,V)=>g+V.allTokens,0);return C===0?0:(v/C*100).toFixed(1)}function P(){if(!et.value)return;Y&&Y.destroy();const v=H.value||[],e={labels:v.map(C=>C.model),datasets:[{data:v.map(C=>C.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(C){const g=C.label||"",V=m(C.parsed),st=$(C.parsed,v);return`${g}: ${V} (${st}%)`}}}}}})}function F(){var D;if(!E.value)return;s&&s.destroy();const v=X.value||[],e=v.map(y=>y.inputTokens||0),C=v.map(y=>y.outputTokens||0),g=v.map(y=>y.cacheCreateTokens||0),V=v.map(y=>y.cacheReadTokens||0),st=v.map(y=>y.requests||0),dt=v.map(y=>y.cost||0),ut=(D=v[0])!=null&&D.date?"date":"hour",U={labels:v.map(y=>{if(y.label)return y.label;if(ut==="hour"){const x=new Date(y.hour),R=String(x.getMonth()+1).padStart(2,"0"),W=String(x.getDate()).padStart(2,"0"),ct=String(x.getHours()).padStart(2,"0");return`${R}/${W} ${ct}:00`}const b=y.date;if(b&&b.includes("-")){const x=b.split("-");if(x.length>=3)return`${x[1]}/${x[2]}`}return y.date}),datasets:[{label:"输入Token",data:e,borderColor:"rgb(102, 126, 234)",backgroundColor:"rgba(102, 126, 234, 0.1)",tension:.3},{label:"输出Token",data:C,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:V,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"}]};s=new vt(E.value,{type:"line",data:U,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(y,b){const x=y.dataset.label||"",R=b.dataset.label||"";return x==="费用 (USD)"||R==="费用 (USD)"?x==="费用 (USD)"?-1:1:x==="请求数"||R==="请求数"?x==="请求数"?1:-1:b.parsed.y-y.parsed.y},callbacks:{label:function(y){const b=y.dataset.label||"";let x=y.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:q.value==="hour"?"时间":"日期"}},y:{type:"linear",display:!0,position:"left",title:{display:!0,text:"Token数量"},ticks:{callback:function(y){return m(y)}}},y1:{type:"linear",display:!0,position:"right",title:{display:!0,text:"请求数"},grid:{drawOnChartArea:!1},ticks:{callback:function(y){return y.toLocaleString()}}},y2:{type:"linear",display:!1,position:"right"}}}})}function K(){var dt,ut;if(!Q.value)return;r&&r.destroy();const v=M.value.data||[],e=I.value,C=["#3B82F6","#10B981","#F59E0B","#EF4444","#8B5CF6","#EC4899","#14B8A6","#F97316","#6366F1","#84CC16"],g=((dt=M.value.topApiKeys)==null?void 0:dt.map((h,U)=>{var b,x;const D=M.value.data.map(R=>!R.apiKeys||!R.apiKeys[h]?0:e==="tokens"?R.apiKeys[h].tokens:R.apiKeys[h].requests||0);return{label:((x=(b=M.value.data.find(R=>R.apiKeys&&R.apiKeys[h]))==null?void 0:b.apiKeys[h])==null?void 0:x.name)||`API Key ${h}`,data:D,borderColor:C[U%C.length],backgroundColor:C[U%C.length]+"20",tension:.4,fill:!1}}))||[],V=(ut=v[0])!=null&&ut.date?"date":"hour",st={labels:v.map(h=>{if(h.label)return h.label;if(V==="hour"){const D=new Date(h.hour),y=String(D.getMonth()+1).padStart(2,"0"),b=String(D.getDate()).padStart(2,"0"),x=String(D.getHours()).padStart(2,"0");return`${y}/${b} ${x}:00`}const U=h.date;if(U&&U.includes("-")){const D=U.split("-");if(D.length>=3)return`${D[1]}/${D[2]}`}return h.date}),datasets:g};r=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,U){return U.parsed.y-h.parsed.y},callbacks:{label:function(h){var ct;const U=h.dataset.label||"",D=h.parsed.y,y=h.dataIndex,b=M.value.data[y],R=h.chart.data.datasets.map((O,at)=>({value:O.data[y]||0,index:at})).sort((O,at)=>at.value-O.value).findIndex(O=>O.index===h.datasetIndex)+1;let W="";if(R===1?W="🥇 ":R===2?W="🥈 ":R===3&&(W="🥉 "),I.value==="tokens"){let O="";D>=1e6?O=(D/1e6).toFixed(2)+"M":D>=1e3?O=(D/1e3).toFixed(2)+"K":O=D.toLocaleString();const at=M.value.topApiKeys[h.datasetIndex],gt=(ct=b==null?void 0:b.apiKeys)==null?void 0:ct[at],Ct=(gt==null?void 0:gt.formattedCost)||"$0.00";return`${W}${U}: ${O} tokens (${Ct})`}else return`${W}${U}: ${D.toLocaleString()} 次`}}}},scales:{x:{type:"category",display:!0,title:{display:!0,text:q.value==="hour"?"时间":"日期"}},y:{beginAtZero:!0,title:{display:!0,text:I.value==="tokens"?"Token 数量":"请求次数"},ticks:{callback:function(h){return m(h)}}}}}})}async function L(){await yt(I.value),await ot(),K()}mt(H,()=>{ot(()=>P())}),mt(X,()=>{ot(()=>F())}),mt(M,()=>{ot(()=>K())});async function B(){if(!f.value){f.value=!0;try{await Promise.all([A(),j()])}finally{f.value=!1}}}function Z(){l.value&&(d.value=i.value,u.value&&clearInterval(u.value),o.value&&clearTimeout(o.value),u.value=setInterval(()=>{d.value--,d.value<=0&&clearInterval(u.value)},1e3),o.value=setTimeout(async()=>{await B(),l.value&&Z()},i.value*1e3))}function ht(){u.value&&(clearInterval(u.value),u.value=null),o.value&&(clearTimeout(o.value),o.value=null),d.value=0}return mt(l,v=>{v?Z():ht()}),St(async()=>{await B(),await ot(),P(),F(),K()}),Rt(()=>{ht(),Y&&Y.destroy(),s&&s.destroy(),r&&r.destroy()}),(v,e)=>{const C=Dt;return _(),w("div",null,[t("div",It,[t("div",Pt,[t("div",Ft,[t("div",null,[e[7]||(e[7]=t("p",{class:"text-sm font-semibold text-gray-600 mb-1"}," 总API Keys ",-1)),t("p",Ot,p(a(c).totalApiKeys),1),t("p",Bt," 活跃: "+p(a(c).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-sm font-semibold text-gray-600 mb-1"}," 服务账户 ",-1)),t("p",qt,p(a(c).totalAccounts),1),t("p",Et,[k(" 活跃: "+p(a(c).activeAccounts||0)+" ",1),a(c).rateLimitedAccounts>0?(_(),w("span",Lt," | 限流: "+p(a(c).rateLimitedAccounts),1)):z("",!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",Vt,[t("div",Nt,[t("div",null,[e[11]||(e[11]=t("p",{class:"text-sm font-semibold text-gray-600 mb-1"}," 今日请求 ",-1)),t("p",jt,p(a(c).todayRequests),1),t("p",Yt," 总请求: "+p(m(a(c).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-sm font-semibold text-gray-600 mb-1"}," 系统状态 ",-1)),t("p",Qt,p(a(c).systemStatus),1),t("p",Zt," 运行时间: "+p(a(n)),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-sm font-semibold text-gray-600 mb-1"}," 今日Token ",-1)),t("div",se,[t("p",ae,p(m((a(c).todayInputTokens||0)+(a(c).todayOutputTokens||0)+(a(c).todayCacheCreateTokens||0)+(a(c).todayCacheReadTokens||0))),1),t("span",oe,"/ "+p(a(lt).todayCosts.formatted.totalCost),1)]),t("div",ne,[t("div",le,[t("span",null,[e[15]||(e[15]=k("输入: ",-1)),t("span",re,p(m(a(c).todayInputTokens||0)),1)]),t("span",null,[e[16]||(e[16]=k("输出: ",-1)),t("span",ie,p(m(a(c).todayOutputTokens||0)),1)]),(a(c).todayCacheCreateTokens||0)>0?(_(),w("span",de,[e[17]||(e[17]=k("缓存创建: ",-1)),t("span",ue,p(m(a(c).todayCacheCreateTokens||0)),1)])):z("",!0),(a(c).todayCacheReadTokens||0)>0?(_(),w("span",ce,[e[18]||(e[18]=k("缓存读取: ",-1)),t("span",me,p(m(a(c).todayCacheReadTokens||0)),1)])):z("",!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-sm font-semibold text-gray-600 mb-1"}," 总Token消耗 ",-1)),t("div",ge,[t("p",xe,p(m((a(c).totalInputTokens||0)+(a(c).totalOutputTokens||0)+(a(c).totalCacheCreateTokens||0)+(a(c).totalCacheReadTokens||0))),1),t("span",ve,"/ "+p(a(lt).totalCosts.formatted.totalCost),1)]),t("div",he,[t("div",be,[t("span",null,[e[21]||(e[21]=k("输入: ",-1)),t("span",ke,p(m(a(c).totalInputTokens||0)),1)]),t("span",null,[e[22]||(e[22]=k("输出: ",-1)),t("span",Te,p(m(a(c).totalOutputTokens||0)),1)]),(a(c).totalCacheCreateTokens||0)>0?(_(),w("span",Ce,[e[23]||(e[23]=k("缓存创建: ",-1)),t("span",De,p(m(a(c).totalCacheCreateTokens||0)),1)])):z("",!0),(a(c).totalCacheReadTokens||0)>0?(_(),w("span",we,[e[24]||(e[24]=k("缓存读取: ",-1)),t("span",_e,p(m(a(c).totalCacheReadTokens||0)),1)])):z("",!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]=k(" 实时RPM ",-1)),t("span",Ae,"("+p(a(c).metricsWindow)+"分钟)",1)]),t("p",Me,p(a(c).realtimeRPM||0),1),t("p",Ue,[e[29]||(e[29]=k(" 每分钟请求数 ",-1)),a(c).isHistoricalMetrics?(_(),w("span",Ke,e[28]||(e[28]=[t("i",{class:"fas fa-exclamation-circle"},null,-1),k(" 历史数据 ",-1)]))):z("",!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",Ie,[t("div",Pe,[t("div",null,[t("p",Fe,[e[31]||(e[31]=k(" 实时TPM ",-1)),t("span",Oe,"("+p(a(c).metricsWindow)+"分钟)",1)]),t("p",Be,p(m(a(c).realtimeTPM||0)),1),t("p",ze,[e[33]||(e[33]=k(" 每分钟Token数 ",-1)),a(c).isHistoricalMetrics?(_(),w("span",He,e[32]||(e[32]=[t("i",{class:"fas fa-exclamation-circle"},null,-1),k(" 历史数据 ",-1)]))):z("",!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-xl font-bold text-gray-900"}," 模型使用分布与Token使用趋势 ",-1)),t("div",Le,[t("div",Ve,[(_(!0),w(bt,null,kt(a(S).presetOptions,g=>(_(),w("button",{key:g.value,class:G(["px-3 py-1 rounded-md text-sm font-medium transition-colors",a(S).preset===g.value&&a(S).type==="preset"?"bg-white text-blue-600 shadow-sm":"text-gray-600 hover:text-gray-900"]),onClick:V=>a(rt)(g.value)},p(g.label),11,Ne))),128))]),t("div",je,[t("button",{class:G(["px-3 py-1 rounded-md text-sm font-medium transition-colors",a(q)==="day"?"bg-white text-blue-600 shadow-sm":"text-gray-600 hover:text-gray-900"]),onClick:e[0]||(e[0]=g=>a(tt)("day"))},e[35]||(e[35]=[t("i",{class:"fas fa-calendar-day mr-1"},null,-1),k("按天 ",-1)]),2),t("button",{class:G(["px-3 py-1 rounded-md text-sm font-medium transition-colors",a(q)==="hour"?"bg-white text-blue-600 shadow-sm":"text-gray-600 hover:text-gray-900"]),onClick:e[1]||(e[1]=g=>a(tt)("hour"))},e[36]||(e[36]=[t("i",{class:"fas fa-clock mr-1"},null,-1),k("按小时 ",-1)]),2)]),t("div",Ye,[$t(C,{modelValue:a(S).customRange,"onUpdate:modelValue":e[2]||(e[2]=g=>a(S).customRange=g),"default-time":a(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":a(ft),size:"default",style:{width:"400px"},class:"custom-date-picker",onChange:a(it)},null,8,["modelValue","default-time","disabled-date","onChange"]),a(q)==="hour"?(_(),w("span",We,e[37]||(e[37]=[t("i",{class:"fas fa-info-circle"},null,-1),k(" 最多24小时 ",-1)]))):z("",!0)]),t("div",Ge,[t("div",Qe,[t("label",Ze,[At(t("input",{"onUpdate:modelValue":e[3]||(e[3]=g=>l.value=g),type:"checkbox",class:"sr-only peer"},null,512),[[Mt,l.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)),l.value?(_(),w("span",{key:0,class:G(["ml-1 text-xs text-blue-600 font-mono transition-opacity",d.value>0?"opacity-100":"opacity-0"])},p(d.value)+"s ",3)):z("",!0)])])]),t("button",{disabled:f.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-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":f.value}])},null,2),t("span",null,p(f.value?"刷新中":"刷新"),1)],8,Xe)])])]),t("div",ts,[t("div",es,[e[42]||(e[42]=t("h4",{class:"text-lg font-semibold text-gray-800 mb-4"}," Token使用分布 ",-1)),t("div",ss,[t("canvas",{ref_key:"modelUsageChart",ref:et},null,512)])]),t("div",as,[e[45]||(e[45]=t("h4",{class:"text-lg font-semibold text-gray-800 mb-4"}," 详细统计数据 ",-1)),a(H).length===0?(_(),w("div",os,e[43]||(e[43]=[t("p",{class:"text-gray-500"}," 暂无模型使用数据 ",-1)]))):(_(),w("div",ns,[t("table",ls,[e[44]||(e[44]=t("thead",{class:"bg-gray-50 sticky top-0"},[t("tr",null,[t("th",{class:"px-4 py-2 text-left text-xs font-medium text-gray-700"}," 模型 "),t("th",{class:"px-4 py-2 text-right text-xs font-medium text-gray-700"}," 请求数 "),t("th",{class:"px-4 py-2 text-right text-xs font-medium text-gray-700"}," 总Token "),t("th",{class:"px-4 py-2 text-right text-xs font-medium text-gray-700"}," 费用 "),t("th",{class:"px-4 py-2 text-right text-xs font-medium text-gray-700"}," 占比 ")])],-1)),t("tbody",rs,[(_(!0),w(bt,null,kt(a(H),g=>(_(),w("tr",{key:g.model,class:"hover:bg-gray-50"},[t("td",is,p(g.model),1),t("td",ds,p(m(g.requests)),1),t("td",us,p(m(g.allTokens)),1),t("td",cs,p(g.formatted?g.formatted.total:"$0.000000"),1),t("td",ms,[t("span",ps,p($(g.allTokens,a(H)))+"% ",1)])]))),128))])])]))])])]),t("div",ys,[t("div",fs,[t("div",gs,[t("canvas",{ref_key:"usageTrendChart",ref:E},null,512)])])]),t("div",xs,[t("div",vs,[t("div",hs,[e[48]||(e[48]=t("h3",{class:"text-lg font-semibold text-gray-900"}," API Keys 使用趋势 ",-1)),t("div",bs,[t("button",{class:G(["px-3 py-1 rounded-md text-sm font-medium transition-colors",a(I)==="requests"?"bg-white text-blue-600 shadow-sm":"text-gray-600 hover:text-gray-900"]),onClick:e[5]||(e[5]=g=>{I.value="requests",L()})},e[46]||(e[46]=[t("i",{class:"fas fa-exchange-alt mr-1"},null,-1),k("请求次数 ",-1)]),2),t("button",{class:G(["px-3 py-1 rounded-md text-sm font-medium transition-colors",a(I)==="tokens"?"bg-white text-blue-600 shadow-sm":"text-gray-600 hover:text-gray-900"]),onClick:e[6]||(e[6]=g=>{I.value="tokens",L()})},e[47]||(e[47]=[t("i",{class:"fas fa-coins mr-1"},null,-1),k("Token 数量 ",-1)]),2)])]),t("div",ks,[a(M).totalApiKeys>10?(_(),w("span",Ts," 共 "+p(a(M).totalApiKeys)+" 个 API Key,显示使用量前 10 个 ",1)):(_(),w("span",Cs," 共 "+p(a(M).totalApiKeys)+" 个 API Key ",1))]),t("div",Ds,[t("canvas",{ref_key:"apiKeysUsageTrendChart",ref:Q},null,512)])])])])}}},Us=Ut(ws,[["__scopeId","data-v-e2cbd0e3"]]);export{Us as default};
diff --git a/web/admin-spa/dist/assets/LoginView-D5DsB4oB.js b/web/admin-spa/dist/assets/LoginView-BJ0LLv16.js
similarity index 97%
rename from web/admin-spa/dist/assets/LoginView-D5DsB4oB.js
rename to web/admin-spa/dist/assets/LoginView-BJ0LLv16.js
index 6cfc00bf..05dd59b3 100644
--- a/web/admin-spa/dist/assets/LoginView-D5DsB4oB.js
+++ b/web/admin-spa/dist/assets/LoginView-BJ0LLv16.js
@@ -1 +1 @@
-import{c as b,r as x,q as f,x as a,z as s,L as i,Q as y,u as o,P as m,Y as _,K as u,aq as c,O as g,y as n}from"./vue-vendor-CKToUHZx.js";import{_ as v,u as w}from"./index-D7YURYF2.js";/* empty css */import"./element-plus-B8Fs_0jW.js";import"./vendor-BDiMbLwQ.js";const h={class:"flex items-center justify-center min-h-screen p-6"},k={class:"glass-strong rounded-3xl p-10 w-full max-w-md shadow-2xl"},L={class:"text-center mb-8"},S={class:"w-20 h-20 mx-auto mb-6 bg-gradient-to-br from-blue-500/20 to-purple-500/20 border border-gray-300/30 rounded-2xl flex items-center justify-center backdrop-blur-sm overflow-hidden"},V=["src"],I={key:1,class:"fas fa-cloud text-3xl text-gray-700"},N={key:1,class:"w-12 h-12 bg-gray-300/50 rounded animate-pulse"},q={key:0,class:"text-3xl font-bold text-white mb-2 header-title"},D={key:1,class:"h-9 w-64 bg-gray-300/50 rounded animate-pulse mx-auto mb-2"},E=["disabled"],j={key:0,class:"fas fa-sign-in-alt mr-2"},B={key:1,class:"loading-spinner mr-2"},M={key:0,class:"mt-6 p-4 bg-red-500/20 border border-red-500/30 rounded-xl text-red-800 text-sm text-center backdrop-blur-sm"},F={__name:"LoginView",setup(O){const e=w(),d=b(()=>e.oemLoading),l=x({username:"",password:""});f(()=>{e.loadOemSettings()});const p=async()=>{await e.login(l.value)};return(T,t)=>(n(),a("div",h,[s("div",k,[s("div",L,[s("div",S,[d.value?(n(),a("div",N)):(n(),a(y,{key:0},[o(e).oemSettings.siteIconData||o(e).oemSettings.siteIcon?(n(),a("img",{key:0,src:o(e).oemSettings.siteIconData||o(e).oemSettings.siteIcon,alt:"Logo",class:"w-12 h-12 object-contain",onError:t[0]||(t[0]=r=>r.target.style.display="none")},null,40,V)):(n(),a("i",I))],64))]),!d.value&&o(e).oemSettings.siteName?(n(),a("h1",q,m(o(e).oemSettings.siteName),1)):d.value?(n(),a("div",D)):i("",!0),t[3]||(t[3]=s("p",{class:"text-gray-600 text-lg"}," 管理后台 ",-1))]),s("form",{class:"space-y-6",onSubmit:_(p,["prevent"])},[s("div",null,[t[4]||(t[4]=s("label",{class:"block text-sm font-semibold text-gray-900 mb-3"},"用户名",-1)),u(s("input",{"onUpdate:modelValue":t[1]||(t[1]=r=>l.value.username=r),type:"text",required:"",class:"form-input w-full",placeholder:"请输入用户名"},null,512),[[c,l.value.username]])]),s("div",null,[t[5]||(t[5]=s("label",{class:"block text-sm font-semibold text-gray-900 mb-3"},"密码",-1)),u(s("input",{"onUpdate:modelValue":t[2]||(t[2]=r=>l.value.password=r),type:"password",required:"",class:"form-input w-full",placeholder:"请输入密码"},null,512),[[c,l.value.password]])]),s("button",{type:"submit",disabled:o(e).loginLoading,class:"btn btn-primary w-full py-4 px-6 text-lg font-semibold"},[o(e).loginLoading?i("",!0):(n(),a("i",j)),o(e).loginLoading?(n(),a("div",B)):i("",!0),g(" "+m(o(e).loginLoading?"登录中...":"登录"),1)],8,E)],32),o(e).loginError?(n(),a("div",M,[t[6]||(t[6]=s("i",{class:"fas fa-exclamation-triangle mr-2"},null,-1)),g(m(o(e).loginError),1)])):i("",!0)])]))}},P=v(F,[["__scopeId","data-v-82195a01"]]);export{P as default};
+import{c as b,r as x,q as f,x as a,z as s,L as i,Q as y,u as o,P as m,Y as _,K as u,aq as c,O as g,y as n}from"./vue-vendor-CKToUHZx.js";import{_ as v,u as w}from"./index-HYE9xPuR.js";/* empty css */import"./element-plus-B8Fs_0jW.js";import"./vendor-BDiMbLwQ.js";const h={class:"flex items-center justify-center min-h-screen p-6"},k={class:"glass-strong rounded-3xl p-10 w-full max-w-md shadow-2xl"},L={class:"text-center mb-8"},S={class:"w-20 h-20 mx-auto mb-6 bg-gradient-to-br from-blue-500/20 to-purple-500/20 border border-gray-300/30 rounded-2xl flex items-center justify-center backdrop-blur-sm overflow-hidden"},V=["src"],I={key:1,class:"fas fa-cloud text-3xl text-gray-700"},N={key:1,class:"w-12 h-12 bg-gray-300/50 rounded animate-pulse"},q={key:0,class:"text-3xl font-bold text-white mb-2 header-title"},D={key:1,class:"h-9 w-64 bg-gray-300/50 rounded animate-pulse mx-auto mb-2"},E=["disabled"],j={key:0,class:"fas fa-sign-in-alt mr-2"},B={key:1,class:"loading-spinner mr-2"},M={key:0,class:"mt-6 p-4 bg-red-500/20 border border-red-500/30 rounded-xl text-red-800 text-sm text-center backdrop-blur-sm"},F={__name:"LoginView",setup(O){const e=w(),d=b(()=>e.oemLoading),l=x({username:"",password:""});f(()=>{e.loadOemSettings()});const p=async()=>{await e.login(l.value)};return(T,t)=>(n(),a("div",h,[s("div",k,[s("div",L,[s("div",S,[d.value?(n(),a("div",N)):(n(),a(y,{key:0},[o(e).oemSettings.siteIconData||o(e).oemSettings.siteIcon?(n(),a("img",{key:0,src:o(e).oemSettings.siteIconData||o(e).oemSettings.siteIcon,alt:"Logo",class:"w-12 h-12 object-contain",onError:t[0]||(t[0]=r=>r.target.style.display="none")},null,40,V)):(n(),a("i",I))],64))]),!d.value&&o(e).oemSettings.siteName?(n(),a("h1",q,m(o(e).oemSettings.siteName),1)):d.value?(n(),a("div",D)):i("",!0),t[3]||(t[3]=s("p",{class:"text-gray-600 text-lg"}," 管理后台 ",-1))]),s("form",{class:"space-y-6",onSubmit:_(p,["prevent"])},[s("div",null,[t[4]||(t[4]=s("label",{class:"block text-sm font-semibold text-gray-900 mb-3"},"用户名",-1)),u(s("input",{"onUpdate:modelValue":t[1]||(t[1]=r=>l.value.username=r),type:"text",required:"",class:"form-input w-full",placeholder:"请输入用户名"},null,512),[[c,l.value.username]])]),s("div",null,[t[5]||(t[5]=s("label",{class:"block text-sm font-semibold text-gray-900 mb-3"},"密码",-1)),u(s("input",{"onUpdate:modelValue":t[2]||(t[2]=r=>l.value.password=r),type:"password",required:"",class:"form-input w-full",placeholder:"请输入密码"},null,512),[[c,l.value.password]])]),s("button",{type:"submit",disabled:o(e).loginLoading,class:"btn btn-primary w-full py-4 px-6 text-lg font-semibold"},[o(e).loginLoading?i("",!0):(n(),a("i",j)),o(e).loginLoading?(n(),a("div",B)):i("",!0),g(" "+m(o(e).loginLoading?"登录中...":"登录"),1)],8,E)],32),o(e).loginError?(n(),a("div",M,[t[6]||(t[6]=s("i",{class:"fas fa-exclamation-triangle mr-2"},null,-1)),g(m(o(e).loginError),1)])):i("",!0)])]))}},P=v(F,[["__scopeId","data-v-82195a01"]]);export{P as default};
diff --git a/web/admin-spa/dist/assets/LogoTitle-Bg7KLvUv.js b/web/admin-spa/dist/assets/LogoTitle-DHj-MjwS.js
similarity index 96%
rename from web/admin-spa/dist/assets/LogoTitle-Bg7KLvUv.js
rename to web/admin-spa/dist/assets/LogoTitle-DHj-MjwS.js
index f6510d61..1bbdd4af 100644
--- a/web/admin-spa/dist/assets/LogoTitle-Bg7KLvUv.js
+++ b/web/admin-spa/dist/assets/LogoTitle-DHj-MjwS.js
@@ -1 +1 @@
-/* empty css */import{_ as r}from"./index-D7YURYF2.js";import{x as t,y as s,z as o,Q as d,L as a,A as c,C as g,P as i}from"./vue-vendor-CKToUHZx.js";const u={class:"flex items-center gap-4"},f={class:"w-12 h-12 bg-gradient-to-br from-blue-500/20 to-purple-500/20 border border-gray-300/30 rounded-xl flex items-center justify-center backdrop-blur-sm flex-shrink-0 overflow-hidden"},y=["src"],m={key:1,class:"fas fa-cloud text-xl text-gray-700"},h={key:1,class:"w-8 h-8 bg-gray-300/50 rounded animate-pulse"},x={class:"flex flex-col justify-center min-h-[48px]"},b={class:"flex items-center gap-3"},k={key:1,class:"h-8 w-64 bg-gray-300/50 rounded animate-pulse"},_={key:0,class:"text-gray-600 text-sm leading-tight mt-0.5"},S={__name:"LogoTitle",props:{loading:{type:Boolean,default:!1},title:{type:String,default:""},subtitle:{type:String,default:""},logoSrc:{type:String,default:""},titleClass:{type:String,default:"text-gray-900"}},setup(e){const n=l=>{l.target.style.display="none"};return(l,p)=>(s(),t("div",u,[o("div",f,[e.loading?(s(),t("div",h)):(s(),t(d,{key:0},[e.logoSrc?(s(),t("img",{key:0,src:e.logoSrc,alt:"Logo",class:"w-8 h-8 object-contain",onError:n},null,40,y)):(s(),t("i",m))],64))]),o("div",x,[o("div",b,[!e.loading&&e.title?(s(),t("h1",{key:0,class:g(["text-2xl font-bold header-title leading-tight",e.titleClass])},i(e.title),3)):e.loading?(s(),t("div",k)):a("",!0),c(l.$slots,"after-title",{},void 0,!0)]),e.subtitle?(s(),t("p",_,i(e.subtitle),1)):a("",!0)])]))}},C=r(S,[["__scopeId","data-v-718feedc"]]);export{C as L};
+/* empty css */import{_ as r}from"./index-HYE9xPuR.js";import{x as t,y as s,z as o,Q as d,L as a,A as c,C as g,P as i}from"./vue-vendor-CKToUHZx.js";const u={class:"flex items-center gap-4"},f={class:"w-12 h-12 bg-gradient-to-br from-blue-500/20 to-purple-500/20 border border-gray-300/30 rounded-xl flex items-center justify-center backdrop-blur-sm flex-shrink-0 overflow-hidden"},y=["src"],m={key:1,class:"fas fa-cloud text-xl text-gray-700"},h={key:1,class:"w-8 h-8 bg-gray-300/50 rounded animate-pulse"},x={class:"flex flex-col justify-center min-h-[48px]"},b={class:"flex items-center gap-3"},k={key:1,class:"h-8 w-64 bg-gray-300/50 rounded animate-pulse"},_={key:0,class:"text-gray-600 text-sm leading-tight mt-0.5"},S={__name:"LogoTitle",props:{loading:{type:Boolean,default:!1},title:{type:String,default:""},subtitle:{type:String,default:""},logoSrc:{type:String,default:""},titleClass:{type:String,default:"text-gray-900"}},setup(e){const n=l=>{l.target.style.display="none"};return(l,p)=>(s(),t("div",u,[o("div",f,[e.loading?(s(),t("div",h)):(s(),t(d,{key:0},[e.logoSrc?(s(),t("img",{key:0,src:e.logoSrc,alt:"Logo",class:"w-8 h-8 object-contain",onError:n},null,40,y)):(s(),t("i",m))],64))]),o("div",x,[o("div",b,[!e.loading&&e.title?(s(),t("h1",{key:0,class:g(["text-2xl font-bold header-title leading-tight",e.titleClass])},i(e.title),3)):e.loading?(s(),t("div",k)):a("",!0),c(l.$slots,"after-title",{},void 0,!0)]),e.subtitle?(s(),t("p",_,i(e.subtitle),1)):a("",!0)])]))}},C=r(S,[["__scopeId","data-v-718feedc"]]);export{C as L};
diff --git a/web/admin-spa/dist/assets/MainLayout-BDUoBMsO.js b/web/admin-spa/dist/assets/MainLayout-CLydIeqJ.js
similarity index 98%
rename from web/admin-spa/dist/assets/MainLayout-BDUoBMsO.js
rename to web/admin-spa/dist/assets/MainLayout-CLydIeqJ.js
index 9ddd71af..17e79158 100644
--- a/web/admin-spa/dist/assets/MainLayout-BDUoBMsO.js
+++ b/web/admin-spa/dist/assets/MainLayout-CLydIeqJ.js
@@ -1 +1 @@
-import{c as M,r as w,_ as O,q as E,V as R,x as o,y as n,z as t,L as T,R as y,J as U,P as b,C as V,Y as $,O as v,T as D,K as k,aq as _,Q as N,aT as q,ac as F,o as J,av as H,aU as Q,I as A,aV as Y,M as G}from"./vue-vendor-CKToUHZx.js";import{_ as L,u as W,a as j}from"./index-D7YURYF2.js";import{s as g}from"./toast-BvwA7Mwb.js";import{L as X}from"./LogoTitle-Bg7KLvUv.js";import"./element-plus-B8Fs_0jW.js";import"./vendor-BDiMbLwQ.js";/* empty css */const Z={class:"glass-strong rounded-3xl p-6 mb-8 shadow-xl",style:{"z-index":"10",position:"relative"}},ee={class:"flex flex-col md:flex-row justify-between items-center gap-4"},te={class:"flex items-center gap-4"},se={class:"flex items-center gap-2"},ae={class:"text-sm text-gray-400 font-mono"},ne=["href"],oe={class:"relative user-menu-container"},le={class:"px-4 py-3 border-b border-gray-100"},re={class:"flex items-center justify-between text-sm"},ie={class:"font-mono text-gray-700"},ue={key:0,class:"mt-2"},de={class:"flex items-center justify-between text-sm mb-2"},ce={class:"font-mono text-green-600"},me=["href"],fe={key:1,class:"mt-2 text-center text-xs text-gray-500"},pe={key:2,class:"mt-2 text-center"},ve={key:"message",class:"px-3 py-1.5 bg-green-100 border border-green-200 rounded-lg inline-block"},xe={key:0,class:"fixed inset-0 modal z-50 flex items-center justify-center p-4"},ge={class:"modal-content w-full max-w-md p-8 mx-auto max-h-[90vh] flex flex-col"},be=["value"],ye={class:"flex gap-3 pt-4"},we=["disabled"],he={key:0,class:"loading-spinner mr-2"},ke={key:1,class:"fas fa-save mr-2"},_e={__name:"AppHeader",setup(C){const x=q(),d=W(),m=M(()=>d.user||{username:"Admin"}),l=M(()=>d.oemSettings||{}),h=M(()=>d.oemLoading),s=w({current:"...",latest:"",hasUpdate:!1,checkingUpdate:!1,lastChecked:null,releaseInfo:null,noUpdateMessage:!1}),r=w(!1),f=w(!1),p=w(!1),a=O({currentPassword:"",newPassword:"",confirmPassword:"",newUsername:""}),P=async()=>{if(!s.value.checkingUpdate){s.value.checkingUpdate=!0;try{const u=await j.get("/admin/check-updates");if(u.success){const e=u.data;s.value.current=e.current,s.value.latest=e.latest,s.value.hasUpdate=e.hasUpdate,s.value.releaseInfo=e.releaseInfo,s.value.lastChecked=new Date,localStorage.setItem("versionInfo",JSON.stringify({current:e.current,latest:e.latest,lastChecked:s.value.lastChecked,hasUpdate:e.hasUpdate,releaseInfo:e.releaseInfo})),e.hasUpdate||(s.value.noUpdateMessage=!0,setTimeout(()=>{s.value.noUpdateMessage=!1},3e3))}}catch(u){console.error("Error checking for updates:",u);const e=localStorage.getItem("versionInfo");if(e){const c=JSON.parse(e);s.value.current=c.current||s.value.current,s.value.latest=c.latest,s.value.hasUpdate=c.hasUpdate,s.value.releaseInfo=c.releaseInfo,s.value.lastChecked=new Date(c.lastChecked)}}finally{s.value.checkingUpdate=!1}}},z=()=>{a.currentPassword="",a.newPassword="",a.confirmPassword="",a.newUsername="",f.value=!0,r.value=!1},I=()=>{f.value=!1},B=async()=>{if(a.newPassword!==a.confirmPassword){g("两次输入的密码不一致","error");return}if(a.newPassword.length<8){g("新密码长度至少8位","error");return}p.value=!0;try{const u=await j.post("/admin/change-password",{currentPassword:a.currentPassword,newPassword:a.newPassword,newUsername:a.newUsername||void 0});if(u.success){const e=a.newUsername?"账户信息修改成功,请重新登录":"密码修改成功,请重新登录";g(e,"success"),I(),setTimeout(()=>{d.logout(),x.push("/login")},1500)}else g(u.message||"修改失败","error")}catch{g("修改密码失败","error")}finally{p.value=!1}},K=()=>{confirm("确定要退出登录吗?")&&(d.logout(),x.push("/login"),g("已安全退出","success")),r.value=!1},S=u=>{!u.target.closest(".user-menu-container")&&r.value&&(r.value=!1)};return E(()=>{P(),setInterval(()=>{P()},36e5),document.addEventListener("click",S)}),R(()=>{document.removeEventListener("click",S)}),(u,e)=>{var c;return n(),o(N,null,[t("div",Z,[t("div",ee,[t("div",te,[y(X,{loading:h.value,title:l.value.siteName,subtitle:"管理后台","logo-src":l.value.siteIconData||l.value.siteIcon,"title-class":"text-white"},{"after-title":U(()=>{var i;return[t("div",se,[t("span",ae,"v"+b(s.value.current||"..."),1),s.value.hasUpdate?(n(),o("a",{key:0,href:((i=s.value.releaseInfo)==null?void 0:i.htmlUrl)||"#",target:"_blank",class:"inline-flex items-center gap-1 px-2 py-0.5 bg-green-500 border border-green-600 rounded-full text-xs text-white hover:bg-green-600 transition-colors animate-pulse",title:"有新版本可用"},e[7]||(e[7]=[t("i",{class:"fas fa-arrow-up text-[10px]"},null,-1),t("span",null,"新版本",-1)]),8,ne)):T("",!0)])]}),_:1},8,["loading","title","logo-src"])]),t("div",oe,[t("button",{class:"btn btn-primary px-4 py-3 flex items-center gap-2 relative",onClick:e[0]||(e[0]=i=>r.value=!r.value)},[e[8]||(e[8]=t("i",{class:"fas fa-user-circle"},null,-1)),t("span",null,b(m.value.username||"Admin"),1),t("i",{class:V(["fas fa-chevron-down text-xs transition-transform duration-200",{"rotate-180":r.value}])},null,2)]),r.value?(n(),o("div",{key:0,class:"absolute right-0 top-full mt-2 w-56 bg-white rounded-xl shadow-xl border border-gray-200 py-2 user-menu-dropdown",style:{"z-index":"999999"},onClick:e[2]||(e[2]=$(()=>{},["stop"]))},[t("div",le,[t("div",re,[e[9]||(e[9]=t("span",{class:"text-gray-500"},"当前版本",-1)),t("span",ie,"v"+b(s.value.current||"..."),1)]),s.value.hasUpdate?(n(),o("div",ue,[t("div",de,[e[10]||(e[10]=t("span",{class:"text-green-600 font-medium"},[t("i",{class:"fas fa-arrow-up mr-1"}),v("有新版本 ")],-1)),t("span",ce,"v"+b(s.value.latest),1)]),t("a",{href:((c=s.value.releaseInfo)==null?void 0:c.htmlUrl)||"#",target:"_blank",class:"block w-full text-center px-3 py-1.5 bg-green-500 text-white text-sm rounded-lg hover:bg-green-600 transition-colors"},e[11]||(e[11]=[t("i",{class:"fas fa-external-link-alt mr-1"},null,-1),v("查看更新 ",-1)]),8,me)])):s.value.checkingUpdate?(n(),o("div",fe,e[12]||(e[12]=[t("i",{class:"fas fa-spinner fa-spin mr-1"},null,-1),v("检查更新中... ",-1)]))):(n(),o("div",pe,[y(D,{name:"fade",mode:"out-in"},{default:U(()=>[s.value.noUpdateMessage?(n(),o("div",ve,e[13]||(e[13]=[t("p",{class:"text-xs text-green-700 font-medium"},[t("i",{class:"fas fa-check-circle mr-1"}),v("当前已是最新版本 ")],-1)]))):(n(),o("button",{key:"button",class:"text-xs text-blue-500 hover:text-blue-700 transition-colors",onClick:e[1]||(e[1]=i=>P())},e[14]||(e[14]=[t("i",{class:"fas fa-sync-alt mr-1"},null,-1),v("检查更新 ",-1)])))]),_:1})]))]),t("button",{class:"w-full px-4 py-3 text-left text-gray-700 hover:bg-gray-50 transition-colors flex items-center gap-3",onClick:z},e[15]||(e[15]=[t("i",{class:"fas fa-key text-blue-500"},null,-1),t("span",null,"修改账户信息",-1)])),e[17]||(e[17]=t("hr",{class:"my-2 border-gray-200"},null,-1)),t("button",{class:"w-full px-4 py-3 text-left text-gray-700 hover:bg-gray-50 transition-colors flex items-center gap-3",onClick:K},e[16]||(e[16]=[t("i",{class:"fas fa-sign-out-alt text-red-500"},null,-1),t("span",null,"退出登录",-1)]))])):T("",!0)])])]),f.value?(n(),o("div",xe,[t("div",ge,[t("div",{class:"flex items-center justify-between mb-6"},[e[19]||(e[19]=t("div",{class:"flex items-center gap-3"},[t("div",{class:"w-10 h-10 bg-gradient-to-br from-blue-500 to-blue-600 rounded-xl flex items-center justify-center"},[t("i",{class:"fas fa-key text-white"})]),t("h3",{class:"text-xl font-bold text-gray-900"}," 修改账户信息 ")],-1)),t("button",{class:"text-gray-400 hover:text-gray-600 transition-colors",onClick:I},e[18]||(e[18]=[t("i",{class:"fas fa-times text-xl"},null,-1)]))]),t("form",{class:"space-y-6 modal-scroll-content custom-scrollbar flex-1",onSubmit:$(B,["prevent"])},[t("div",null,[e[20]||(e[20]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"当前用户名",-1)),t("input",{value:m.value.username||"Admin",type:"text",disabled:"",class:"form-input w-full bg-gray-100 cursor-not-allowed"},null,8,be),e[21]||(e[21]=t("p",{class:"text-xs text-gray-500 mt-2"}," 当前用户名,输入新用户名以修改 ",-1))]),t("div",null,[e[22]||(e[22]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"新用户名",-1)),k(t("input",{"onUpdate:modelValue":e[3]||(e[3]=i=>a.newUsername=i),type:"text",class:"form-input w-full",placeholder:"输入新用户名(留空保持不变)"},null,512),[[_,a.newUsername]]),e[23]||(e[23]=t("p",{class:"text-xs text-gray-500 mt-2"}," 留空表示不修改用户名 ",-1))]),t("div",null,[e[24]||(e[24]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"当前密码",-1)),k(t("input",{"onUpdate:modelValue":e[4]||(e[4]=i=>a.currentPassword=i),type:"password",required:"",class:"form-input w-full",placeholder:"请输入当前密码"},null,512),[[_,a.currentPassword]])]),t("div",null,[e[25]||(e[25]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"新密码",-1)),k(t("input",{"onUpdate:modelValue":e[5]||(e[5]=i=>a.newPassword=i),type:"password",required:"",class:"form-input w-full",placeholder:"请输入新密码"},null,512),[[_,a.newPassword]]),e[26]||(e[26]=t("p",{class:"text-xs text-gray-500 mt-2"}," 密码长度至少8位 ",-1))]),t("div",null,[e[27]||(e[27]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"确认新密码",-1)),k(t("input",{"onUpdate:modelValue":e[6]||(e[6]=i=>a.confirmPassword=i),type:"password",required:"",class:"form-input w-full",placeholder:"请再次输入新密码"},null,512),[[_,a.confirmPassword]])]),t("div",ye,[t("button",{type:"button",class:"flex-1 px-6 py-3 bg-gray-100 text-gray-700 rounded-xl font-semibold hover:bg-gray-200 transition-colors",onClick:I}," 取消 "),t("button",{type:"submit",disabled:p.value,class:"btn btn-primary flex-1 py-3 px-6 font-semibold"},[p.value?(n(),o("div",he)):(n(),o("i",ke)),v(" "+b(p.value?"保存中...":"保存修改"),1)],8,we)])],32)])])):T("",!0)],64)}}},Ue=L(_e,[["__scopeId","data-v-590374fc"]]),Ce={class:"flex flex-wrap gap-2 mb-6 bg-white/10 rounded-2xl p-2 backdrop-blur-sm"},Pe=["onClick"],Ie={__name:"TabBar",props:{activeTab:{type:String,required:!0}},emits:["tab-change"],setup(C){const x=[{key:"dashboard",name:"仪表板",icon:"fas fa-tachometer-alt"},{key:"apiKeys",name:"API Keys",icon:"fas fa-key"},{key:"accounts",name:"账户管理",icon:"fas fa-user-circle"},{key:"tutorial",name:"使用教程",icon:"fas fa-graduation-cap"},{key:"settings",name:"其他设置",icon:"fas fa-cogs"}];return(d,m)=>(n(),o("div",Ce,[(n(),o(N,null,F(x,l=>t("button",{key:l.key,class:V(["tab-btn flex-1 py-3 px-6 text-sm font-semibold transition-all duration-300",C.activeTab===l.key?"active":"text-gray-700 hover:bg-white/10 hover:text-gray-900"]),onClick:h=>d.$emit("tab-change",l.key)},[t("i",{class:V(l.icon+" mr-2")},null,2),v(b(l.name),1)],10,Pe)),64))]))}},Me=L(Ie,[["__scopeId","data-v-aabb6896"]]),Te={class:"min-h-screen p-6"},Ve={class:"glass-strong rounded-3xl p-6 shadow-xl",style:{"z-index":"1","min-height":"calc(100vh - 240px)"}},Le={class:"tab-content"},Se={__name:"MainLayout",setup(C){const x=Q(),d=q(),m=w("dashboard"),l={dashboard:"/dashboard",apiKeys:"/api-keys",accounts:"/accounts",tutorial:"/tutorial",settings:"/settings"};J(()=>x.path,s=>{const r=Object.keys(l).find(f=>l[f]===s);r&&(m.value=r)},{immediate:!0});const h=s=>{m.value=s,d.push(l[s])};return(s,r)=>{const f=H("router-view");return n(),o("div",Te,[y(Ue),t("div",Ve,[y(Me,{"active-tab":m.value,onTabChange:h},null,8,["active-tab"]),t("div",Le,[y(f,null,{default:U(({Component:p})=>[y(D,{name:"slide-up",mode:"out-in"},{default:U(()=>[(n(),A(Y,{include:["DashboardView","ApiKeysView"]},[(n(),A(G(p)))],1024))]),_:2},1024)]),_:1})])])])}}},Be=L(Se,[["__scopeId","data-v-59f33a38"]]);export{Be as default};
+import{c as M,r as w,_ as O,q as E,V as R,x as o,y as n,z as t,L as T,R as y,J as U,P as b,C as V,Y as $,O as v,T as D,K as k,aq as _,Q as N,aT as q,ac as F,o as J,av as H,aU as Q,I as A,aV as Y,M as G}from"./vue-vendor-CKToUHZx.js";import{_ as L,u as W,a as j}from"./index-HYE9xPuR.js";import{s as g}from"./toast-BvwA7Mwb.js";import{L as X}from"./LogoTitle-DHj-MjwS.js";import"./element-plus-B8Fs_0jW.js";import"./vendor-BDiMbLwQ.js";/* empty css */const Z={class:"glass-strong rounded-3xl p-6 mb-8 shadow-xl",style:{"z-index":"10",position:"relative"}},ee={class:"flex flex-col md:flex-row justify-between items-center gap-4"},te={class:"flex items-center gap-4"},se={class:"flex items-center gap-2"},ae={class:"text-sm text-gray-400 font-mono"},ne=["href"],oe={class:"relative user-menu-container"},le={class:"px-4 py-3 border-b border-gray-100"},re={class:"flex items-center justify-between text-sm"},ie={class:"font-mono text-gray-700"},ue={key:0,class:"mt-2"},de={class:"flex items-center justify-between text-sm mb-2"},ce={class:"font-mono text-green-600"},me=["href"],fe={key:1,class:"mt-2 text-center text-xs text-gray-500"},pe={key:2,class:"mt-2 text-center"},ve={key:"message",class:"px-3 py-1.5 bg-green-100 border border-green-200 rounded-lg inline-block"},xe={key:0,class:"fixed inset-0 modal z-50 flex items-center justify-center p-4"},ge={class:"modal-content w-full max-w-md p-8 mx-auto max-h-[90vh] flex flex-col"},be=["value"],ye={class:"flex gap-3 pt-4"},we=["disabled"],he={key:0,class:"loading-spinner mr-2"},ke={key:1,class:"fas fa-save mr-2"},_e={__name:"AppHeader",setup(C){const x=q(),d=W(),m=M(()=>d.user||{username:"Admin"}),l=M(()=>d.oemSettings||{}),h=M(()=>d.oemLoading),s=w({current:"...",latest:"",hasUpdate:!1,checkingUpdate:!1,lastChecked:null,releaseInfo:null,noUpdateMessage:!1}),r=w(!1),f=w(!1),p=w(!1),a=O({currentPassword:"",newPassword:"",confirmPassword:"",newUsername:""}),P=async()=>{if(!s.value.checkingUpdate){s.value.checkingUpdate=!0;try{const u=await j.get("/admin/check-updates");if(u.success){const e=u.data;s.value.current=e.current,s.value.latest=e.latest,s.value.hasUpdate=e.hasUpdate,s.value.releaseInfo=e.releaseInfo,s.value.lastChecked=new Date,localStorage.setItem("versionInfo",JSON.stringify({current:e.current,latest:e.latest,lastChecked:s.value.lastChecked,hasUpdate:e.hasUpdate,releaseInfo:e.releaseInfo})),e.hasUpdate||(s.value.noUpdateMessage=!0,setTimeout(()=>{s.value.noUpdateMessage=!1},3e3))}}catch(u){console.error("Error checking for updates:",u);const e=localStorage.getItem("versionInfo");if(e){const c=JSON.parse(e);s.value.current=c.current||s.value.current,s.value.latest=c.latest,s.value.hasUpdate=c.hasUpdate,s.value.releaseInfo=c.releaseInfo,s.value.lastChecked=new Date(c.lastChecked)}}finally{s.value.checkingUpdate=!1}}},z=()=>{a.currentPassword="",a.newPassword="",a.confirmPassword="",a.newUsername="",f.value=!0,r.value=!1},I=()=>{f.value=!1},B=async()=>{if(a.newPassword!==a.confirmPassword){g("两次输入的密码不一致","error");return}if(a.newPassword.length<8){g("新密码长度至少8位","error");return}p.value=!0;try{const u=await j.post("/admin/change-password",{currentPassword:a.currentPassword,newPassword:a.newPassword,newUsername:a.newUsername||void 0});if(u.success){const e=a.newUsername?"账户信息修改成功,请重新登录":"密码修改成功,请重新登录";g(e,"success"),I(),setTimeout(()=>{d.logout(),x.push("/login")},1500)}else g(u.message||"修改失败","error")}catch{g("修改密码失败","error")}finally{p.value=!1}},K=()=>{confirm("确定要退出登录吗?")&&(d.logout(),x.push("/login"),g("已安全退出","success")),r.value=!1},S=u=>{!u.target.closest(".user-menu-container")&&r.value&&(r.value=!1)};return E(()=>{P(),setInterval(()=>{P()},36e5),document.addEventListener("click",S)}),R(()=>{document.removeEventListener("click",S)}),(u,e)=>{var c;return n(),o(N,null,[t("div",Z,[t("div",ee,[t("div",te,[y(X,{loading:h.value,title:l.value.siteName,subtitle:"管理后台","logo-src":l.value.siteIconData||l.value.siteIcon,"title-class":"text-white"},{"after-title":U(()=>{var i;return[t("div",se,[t("span",ae,"v"+b(s.value.current||"..."),1),s.value.hasUpdate?(n(),o("a",{key:0,href:((i=s.value.releaseInfo)==null?void 0:i.htmlUrl)||"#",target:"_blank",class:"inline-flex items-center gap-1 px-2 py-0.5 bg-green-500 border border-green-600 rounded-full text-xs text-white hover:bg-green-600 transition-colors animate-pulse",title:"有新版本可用"},e[7]||(e[7]=[t("i",{class:"fas fa-arrow-up text-[10px]"},null,-1),t("span",null,"新版本",-1)]),8,ne)):T("",!0)])]}),_:1},8,["loading","title","logo-src"])]),t("div",oe,[t("button",{class:"btn btn-primary px-4 py-3 flex items-center gap-2 relative",onClick:e[0]||(e[0]=i=>r.value=!r.value)},[e[8]||(e[8]=t("i",{class:"fas fa-user-circle"},null,-1)),t("span",null,b(m.value.username||"Admin"),1),t("i",{class:V(["fas fa-chevron-down text-xs transition-transform duration-200",{"rotate-180":r.value}])},null,2)]),r.value?(n(),o("div",{key:0,class:"absolute right-0 top-full mt-2 w-56 bg-white rounded-xl shadow-xl border border-gray-200 py-2 user-menu-dropdown",style:{"z-index":"999999"},onClick:e[2]||(e[2]=$(()=>{},["stop"]))},[t("div",le,[t("div",re,[e[9]||(e[9]=t("span",{class:"text-gray-500"},"当前版本",-1)),t("span",ie,"v"+b(s.value.current||"..."),1)]),s.value.hasUpdate?(n(),o("div",ue,[t("div",de,[e[10]||(e[10]=t("span",{class:"text-green-600 font-medium"},[t("i",{class:"fas fa-arrow-up mr-1"}),v("有新版本 ")],-1)),t("span",ce,"v"+b(s.value.latest),1)]),t("a",{href:((c=s.value.releaseInfo)==null?void 0:c.htmlUrl)||"#",target:"_blank",class:"block w-full text-center px-3 py-1.5 bg-green-500 text-white text-sm rounded-lg hover:bg-green-600 transition-colors"},e[11]||(e[11]=[t("i",{class:"fas fa-external-link-alt mr-1"},null,-1),v("查看更新 ",-1)]),8,me)])):s.value.checkingUpdate?(n(),o("div",fe,e[12]||(e[12]=[t("i",{class:"fas fa-spinner fa-spin mr-1"},null,-1),v("检查更新中... ",-1)]))):(n(),o("div",pe,[y(D,{name:"fade",mode:"out-in"},{default:U(()=>[s.value.noUpdateMessage?(n(),o("div",ve,e[13]||(e[13]=[t("p",{class:"text-xs text-green-700 font-medium"},[t("i",{class:"fas fa-check-circle mr-1"}),v("当前已是最新版本 ")],-1)]))):(n(),o("button",{key:"button",class:"text-xs text-blue-500 hover:text-blue-700 transition-colors",onClick:e[1]||(e[1]=i=>P())},e[14]||(e[14]=[t("i",{class:"fas fa-sync-alt mr-1"},null,-1),v("检查更新 ",-1)])))]),_:1})]))]),t("button",{class:"w-full px-4 py-3 text-left text-gray-700 hover:bg-gray-50 transition-colors flex items-center gap-3",onClick:z},e[15]||(e[15]=[t("i",{class:"fas fa-key text-blue-500"},null,-1),t("span",null,"修改账户信息",-1)])),e[17]||(e[17]=t("hr",{class:"my-2 border-gray-200"},null,-1)),t("button",{class:"w-full px-4 py-3 text-left text-gray-700 hover:bg-gray-50 transition-colors flex items-center gap-3",onClick:K},e[16]||(e[16]=[t("i",{class:"fas fa-sign-out-alt text-red-500"},null,-1),t("span",null,"退出登录",-1)]))])):T("",!0)])])]),f.value?(n(),o("div",xe,[t("div",ge,[t("div",{class:"flex items-center justify-between mb-6"},[e[19]||(e[19]=t("div",{class:"flex items-center gap-3"},[t("div",{class:"w-10 h-10 bg-gradient-to-br from-blue-500 to-blue-600 rounded-xl flex items-center justify-center"},[t("i",{class:"fas fa-key text-white"})]),t("h3",{class:"text-xl font-bold text-gray-900"}," 修改账户信息 ")],-1)),t("button",{class:"text-gray-400 hover:text-gray-600 transition-colors",onClick:I},e[18]||(e[18]=[t("i",{class:"fas fa-times text-xl"},null,-1)]))]),t("form",{class:"space-y-6 modal-scroll-content custom-scrollbar flex-1",onSubmit:$(B,["prevent"])},[t("div",null,[e[20]||(e[20]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"当前用户名",-1)),t("input",{value:m.value.username||"Admin",type:"text",disabled:"",class:"form-input w-full bg-gray-100 cursor-not-allowed"},null,8,be),e[21]||(e[21]=t("p",{class:"text-xs text-gray-500 mt-2"}," 当前用户名,输入新用户名以修改 ",-1))]),t("div",null,[e[22]||(e[22]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"新用户名",-1)),k(t("input",{"onUpdate:modelValue":e[3]||(e[3]=i=>a.newUsername=i),type:"text",class:"form-input w-full",placeholder:"输入新用户名(留空保持不变)"},null,512),[[_,a.newUsername]]),e[23]||(e[23]=t("p",{class:"text-xs text-gray-500 mt-2"}," 留空表示不修改用户名 ",-1))]),t("div",null,[e[24]||(e[24]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"当前密码",-1)),k(t("input",{"onUpdate:modelValue":e[4]||(e[4]=i=>a.currentPassword=i),type:"password",required:"",class:"form-input w-full",placeholder:"请输入当前密码"},null,512),[[_,a.currentPassword]])]),t("div",null,[e[25]||(e[25]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"新密码",-1)),k(t("input",{"onUpdate:modelValue":e[5]||(e[5]=i=>a.newPassword=i),type:"password",required:"",class:"form-input w-full",placeholder:"请输入新密码"},null,512),[[_,a.newPassword]]),e[26]||(e[26]=t("p",{class:"text-xs text-gray-500 mt-2"}," 密码长度至少8位 ",-1))]),t("div",null,[e[27]||(e[27]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"确认新密码",-1)),k(t("input",{"onUpdate:modelValue":e[6]||(e[6]=i=>a.confirmPassword=i),type:"password",required:"",class:"form-input w-full",placeholder:"请再次输入新密码"},null,512),[[_,a.confirmPassword]])]),t("div",ye,[t("button",{type:"button",class:"flex-1 px-6 py-3 bg-gray-100 text-gray-700 rounded-xl font-semibold hover:bg-gray-200 transition-colors",onClick:I}," 取消 "),t("button",{type:"submit",disabled:p.value,class:"btn btn-primary flex-1 py-3 px-6 font-semibold"},[p.value?(n(),o("div",he)):(n(),o("i",ke)),v(" "+b(p.value?"保存中...":"保存修改"),1)],8,we)])],32)])])):T("",!0)],64)}}},Ue=L(_e,[["__scopeId","data-v-590374fc"]]),Ce={class:"flex flex-wrap gap-2 mb-6 bg-white/10 rounded-2xl p-2 backdrop-blur-sm"},Pe=["onClick"],Ie={__name:"TabBar",props:{activeTab:{type:String,required:!0}},emits:["tab-change"],setup(C){const x=[{key:"dashboard",name:"仪表板",icon:"fas fa-tachometer-alt"},{key:"apiKeys",name:"API Keys",icon:"fas fa-key"},{key:"accounts",name:"账户管理",icon:"fas fa-user-circle"},{key:"tutorial",name:"使用教程",icon:"fas fa-graduation-cap"},{key:"settings",name:"其他设置",icon:"fas fa-cogs"}];return(d,m)=>(n(),o("div",Ce,[(n(),o(N,null,F(x,l=>t("button",{key:l.key,class:V(["tab-btn flex-1 py-3 px-6 text-sm font-semibold transition-all duration-300",C.activeTab===l.key?"active":"text-gray-700 hover:bg-white/10 hover:text-gray-900"]),onClick:h=>d.$emit("tab-change",l.key)},[t("i",{class:V(l.icon+" mr-2")},null,2),v(b(l.name),1)],10,Pe)),64))]))}},Me=L(Ie,[["__scopeId","data-v-aabb6896"]]),Te={class:"min-h-screen p-6"},Ve={class:"glass-strong rounded-3xl p-6 shadow-xl",style:{"z-index":"1","min-height":"calc(100vh - 240px)"}},Le={class:"tab-content"},Se={__name:"MainLayout",setup(C){const x=Q(),d=q(),m=w("dashboard"),l={dashboard:"/dashboard",apiKeys:"/api-keys",accounts:"/accounts",tutorial:"/tutorial",settings:"/settings"};J(()=>x.path,s=>{const r=Object.keys(l).find(f=>l[f]===s);r&&(m.value=r)},{immediate:!0});const h=s=>{m.value=s,d.push(l[s])};return(s,r)=>{const f=H("router-view");return n(),o("div",Te,[y(Ue),t("div",Ve,[y(Me,{"active-tab":m.value,onTabChange:h},null,8,["active-tab"]),t("div",Le,[y(f,null,{default:U(({Component:p})=>[y(D,{name:"slide-up",mode:"out-in"},{default:U(()=>[(n(),A(Y,{include:["DashboardView","ApiKeysView"]},[(n(),A(G(p)))],1024))]),_:2},1024)]),_:1})])])])}}},Be=L(Se,[["__scopeId","data-v-59f33a38"]]);export{Be as default};
diff --git a/web/admin-spa/dist/assets/SettingsView-Dubxv8iH.js b/web/admin-spa/dist/assets/SettingsView-DicW12bL.js
similarity index 99%
rename from web/admin-spa/dist/assets/SettingsView-Dubxv8iH.js
rename to web/admin-spa/dist/assets/SettingsView-DicW12bL.js
index 6c81c63f..f5392027 100644
--- a/web/admin-spa/dist/assets/SettingsView-Dubxv8iH.js
+++ b/web/admin-spa/dist/assets/SettingsView-DicW12bL.js
@@ -1,3 +1,3 @@
-import{aR as k,r as x,aW as C,q as O,x as m,z as e,u as i,K as T,aq as N,L as _,O as v,C as j,P as S,y as g}from"./vue-vendor-CKToUHZx.js";import{s as c}from"./toast-BvwA7Mwb.js";import{a as D,_ as F}from"./index-D7YURYF2.js";import"./element-plus-B8Fs_0jW.js";import"./vendor-BDiMbLwQ.js";const E=k("settings",()=>{const l=x({siteName:"Claude Relay Service",siteIcon:"",siteIconData:"",updatedAt:null}),r=x(!1),p=x(!1),d=async()=>{r.value=!0;try{const s=await D.get("/admin/oem-settings");return s&&s.success&&(l.value={...l.value,...s.data},f()),s}catch(s){throw console.error("Failed to load OEM settings:",s),s}finally{r.value=!1}},a=async s=>{p.value=!0;try{const o=await D.put("/admin/oem-settings",s);return o&&o.success&&(l.value={...l.value,...o.data},f()),o}catch(o){throw console.error("Failed to save OEM settings:",o),o}finally{p.value=!1}},w=async()=>{const s={siteName:"Claude Relay Service",siteIcon:"",siteIconData:"",updatedAt:null};return l.value={...s},await a(s)},f=()=>{if(l.value.siteName&&(document.title=`${l.value.siteName} - 管理后台`),l.value.siteIconData||l.value.siteIcon){const s=document.querySelector('link[rel="icon"]')||document.createElement("link");s.rel="icon",s.href=l.value.siteIconData||l.value.siteIcon,document.querySelector('link[rel="icon"]')||document.head.appendChild(s)}};return{oemSettings:l,loading:r,saving:p,loadOemSettings:d,saveOemSettings:a,resetOemSettings:w,applyOemSettings:f,formatDateTime:s=>s?new Date(s).toLocaleString("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"}):"",validateIconFile:s=>{const o=[];return s.size>350*1024&&o.push("图标文件大小不能超过 350KB"),["image/x-icon","image/png","image/jpeg","image/jpg","image/svg+xml"].includes(s.type)||o.push("不支持的文件类型,请选择 .ico, .png, .jpg 或 .svg 文件"),{isValid:o.length===0,errors:o}},fileToBase64:s=>new Promise((o,n)=>{const t=new FileReader;t.onload=u=>o(u.target.result),t.onerror=n,t.readAsDataURL(s)})}}),B={class:"settings-container"},V={class:"card p-6"},R={key:0,class:"text-center py-12"},M={key:1,class:"table-container"},A={class:"min-w-full"},q={class:"divide-y divide-gray-200/50"},z={class:"table-row"},K={class:"px-6 py-4"},L={class:"table-row"},U={class:"px-6 py-4"},$={class:"space-y-3"},P={key:0,class:"inline-flex items-center gap-3 p-3 bg-gray-50 rounded-lg"},W=["src"],G={class:"px-6 py-6",colspan:"2"},H={class:"flex items-center justify-between"},J={class:"flex gap-3"},Q=["disabled"],X={key:0,class:"loading-spinner mr-2"},Y={key:1,class:"fas fa-save mr-2"},Z=["disabled"],ee={key:0,class:"text-sm text-gray-500"},te={__name:"SettingsView",setup(l){const r=E(),{loading:p,saving:d,oemSettings:a}=C(r),w=x();O(async()=>{try{await r.loadOemSettings()}catch{c("加载设置失败","error")}});const f=async()=>{try{const n={siteName:a.value.siteName,siteIcon:a.value.siteIcon,siteIconData:a.value.siteIconData},t=await r.saveOemSettings(n);t&&t.success?c("OEM设置保存成功","success"):c((t==null?void 0:t.message)||"保存失败","error")}catch{c("保存OEM设置失败","error")}},b=async()=>{if(confirm(`确定要重置为默认设置吗?
+import{aR as k,r as x,aW as C,q as O,x as m,z as e,u as i,K as T,aq as N,L as _,O as v,C as j,P as S,y as g}from"./vue-vendor-CKToUHZx.js";import{s as c}from"./toast-BvwA7Mwb.js";import{a as D,_ as F}from"./index-HYE9xPuR.js";import"./element-plus-B8Fs_0jW.js";import"./vendor-BDiMbLwQ.js";const E=k("settings",()=>{const l=x({siteName:"Claude Relay Service",siteIcon:"",siteIconData:"",updatedAt:null}),r=x(!1),p=x(!1),d=async()=>{r.value=!0;try{const s=await D.get("/admin/oem-settings");return s&&s.success&&(l.value={...l.value,...s.data},f()),s}catch(s){throw console.error("Failed to load OEM settings:",s),s}finally{r.value=!1}},a=async s=>{p.value=!0;try{const o=await D.put("/admin/oem-settings",s);return o&&o.success&&(l.value={...l.value,...o.data},f()),o}catch(o){throw console.error("Failed to save OEM settings:",o),o}finally{p.value=!1}},w=async()=>{const s={siteName:"Claude Relay Service",siteIcon:"",siteIconData:"",updatedAt:null};return l.value={...s},await a(s)},f=()=>{if(l.value.siteName&&(document.title=`${l.value.siteName} - 管理后台`),l.value.siteIconData||l.value.siteIcon){const s=document.querySelector('link[rel="icon"]')||document.createElement("link");s.rel="icon",s.href=l.value.siteIconData||l.value.siteIcon,document.querySelector('link[rel="icon"]')||document.head.appendChild(s)}};return{oemSettings:l,loading:r,saving:p,loadOemSettings:d,saveOemSettings:a,resetOemSettings:w,applyOemSettings:f,formatDateTime:s=>s?new Date(s).toLocaleString("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"}):"",validateIconFile:s=>{const o=[];return s.size>350*1024&&o.push("图标文件大小不能超过 350KB"),["image/x-icon","image/png","image/jpeg","image/jpg","image/svg+xml"].includes(s.type)||o.push("不支持的文件类型,请选择 .ico, .png, .jpg 或 .svg 文件"),{isValid:o.length===0,errors:o}},fileToBase64:s=>new Promise((o,n)=>{const t=new FileReader;t.onload=u=>o(u.target.result),t.onerror=n,t.readAsDataURL(s)})}}),B={class:"settings-container"},V={class:"card p-6"},R={key:0,class:"text-center py-12"},M={key:1,class:"table-container"},A={class:"min-w-full"},q={class:"divide-y divide-gray-200/50"},z={class:"table-row"},K={class:"px-6 py-4"},L={class:"table-row"},U={class:"px-6 py-4"},$={class:"space-y-3"},P={key:0,class:"inline-flex items-center gap-3 p-3 bg-gray-50 rounded-lg"},W=["src"],G={class:"px-6 py-6",colspan:"2"},H={class:"flex items-center justify-between"},J={class:"flex gap-3"},Q=["disabled"],X={key:0,class:"loading-spinner mr-2"},Y={key:1,class:"fas fa-save mr-2"},Z=["disabled"],ee={key:0,class:"text-sm text-gray-500"},te={__name:"SettingsView",setup(l){const r=E(),{loading:p,saving:d,oemSettings:a}=C(r),w=x();O(async()=>{try{await r.loadOemSettings()}catch{c("加载设置失败","error")}});const f=async()=>{try{const n={siteName:a.value.siteName,siteIcon:a.value.siteIcon,siteIconData:a.value.siteIconData},t=await r.saveOemSettings(n);t&&t.success?c("OEM设置保存成功","success"):c((t==null?void 0:t.message)||"保存失败","error")}catch{c("保存OEM设置失败","error")}},b=async()=>{if(confirm(`确定要重置为默认设置吗?
这将清除所有自定义的网站名称和图标设置。`))try{const n=await r.resetOemSettings();n&&n.success?c("已重置为默认设置","success"):c("重置失败","error")}catch{c("重置失败","error")}},h=async n=>{const t=n.target.files[0];if(!t)return;const u=r.validateIconFile(t);if(!u.isValid){u.errors.forEach(y=>c(y,"error"));return}try{const y=await r.fileToBase64(t);a.value.siteIconData=y}catch{c("文件读取失败","error")}n.target.value=""},I=()=>{a.value.siteIcon="",a.value.siteIconData=""},s=()=>{console.warn("Icon failed to load")},o=r.formatDateTime;return(n,t)=>(g(),m("div",B,[e("div",V,[t[12]||(t[12]=e("div",{class:"flex flex-col md:flex-row justify-between items-center gap-4 mb-6"},[e("div",null,[e("h3",{class:"text-xl font-bold text-gray-900 mb-2"}," 其他设置 "),e("p",{class:"text-gray-600"}," 自定义网站名称和图标 ")])],-1)),i(p)?(g(),m("div",R,t[2]||(t[2]=[e("div",{class:"loading-spinner mx-auto mb-4"},null,-1),e("p",{class:"text-gray-500"}," 正在加载设置... ",-1)]))):(g(),m("div",M,[e("table",A,[e("tbody",q,[e("tr",z,[t[4]||(t[4]=e("td",{class:"px-6 py-4 whitespace-nowrap w-48"},[e("div",{class:"flex items-center"},[e("div",{class:"w-8 h-8 bg-gradient-to-br from-blue-500 to-blue-600 rounded-lg flex items-center justify-center mr-3"},[e("i",{class:"fas fa-font text-white text-xs"})]),e("div",null,[e("div",{class:"text-sm font-semibold text-gray-900"}," 网站名称 "),e("div",{class:"text-xs text-gray-500"}," 品牌标识 ")])])],-1)),e("td",K,[T(e("input",{"onUpdate:modelValue":t[0]||(t[0]=u=>i(a).siteName=u),type:"text",class:"form-input w-full max-w-md",placeholder:"Claude Relay Service",maxlength:"100"},null,512),[[N,i(a).siteName]]),t[3]||(t[3]=e("p",{class:"text-xs text-gray-500 mt-1"}," 将显示在浏览器标题和页面头部 ",-1))])]),e("tr",L,[t[9]||(t[9]=e("td",{class:"px-6 py-4 whitespace-nowrap w-48"},[e("div",{class:"flex items-center"},[e("div",{class:"w-8 h-8 bg-gradient-to-br from-purple-500 to-purple-600 rounded-lg flex items-center justify-center mr-3"},[e("i",{class:"fas fa-image text-white text-xs"})]),e("div",null,[e("div",{class:"text-sm font-semibold text-gray-900"}," 网站图标 "),e("div",{class:"text-xs text-gray-500"}," Favicon ")])])],-1)),e("td",U,[e("div",$,[i(a).siteIconData||i(a).siteIcon?(g(),m("div",P,[e("img",{src:i(a).siteIconData||i(a).siteIcon,alt:"图标预览",class:"w-8 h-8",onError:s},null,40,W),t[6]||(t[6]=e("span",{class:"text-sm text-gray-600"},"当前图标",-1)),e("button",{class:"text-red-600 hover:text-red-900 font-medium hover:bg-red-50 px-3 py-1 rounded-lg transition-colors",onClick:I},t[5]||(t[5]=[e("i",{class:"fas fa-trash mr-1"},null,-1),v("删除 ",-1)]))])):_("",!0),e("div",null,[e("input",{ref_key:"iconFileInput",ref:w,type:"file",accept:".ico,.png,.jpg,.jpeg,.svg",class:"hidden",onChange:h},null,544),e("button",{class:"btn btn-success px-4 py-2",onClick:t[1]||(t[1]=u=>n.$refs.iconFileInput.click())},t[7]||(t[7]=[e("i",{class:"fas fa-upload mr-2"},null,-1),v(" 上传图标 ",-1)])),t[8]||(t[8]=e("span",{class:"text-xs text-gray-500 ml-3"},"支持 .ico, .png, .jpg, .svg 格式,最大 350KB",-1))])])])]),e("tr",null,[e("td",G,[e("div",H,[e("div",J,[e("button",{disabled:i(d),class:j(["btn btn-primary px-6 py-3",{"opacity-50 cursor-not-allowed":i(d)}]),onClick:f},[i(d)?(g(),m("div",X)):(g(),m("i",Y)),v(" "+S(i(d)?"保存中...":"保存设置"),1)],10,Q),e("button",{class:"btn bg-gray-100 text-gray-700 hover:bg-gray-200 px-6 py-3",disabled:i(d),onClick:b},t[10]||(t[10]=[e("i",{class:"fas fa-undo mr-2"},null,-1),v(" 重置为默认 ",-1)]),8,Z)]),i(a).updatedAt?(g(),m("div",ee,[t[11]||(t[11]=e("i",{class:"fas fa-clock mr-1"},null,-1)),v(" 最后更新:"+S(i(o)(i(a).updatedAt)),1)])):_("",!0)])])])])])]))])]))}},le=F(te,[["__scopeId","data-v-d29d5f49"]]);export{le as default};
diff --git a/web/admin-spa/dist/assets/TutorialView-BPaY-imZ.js b/web/admin-spa/dist/assets/TutorialView-DqKyDtQV.js
similarity index 99%
rename from web/admin-spa/dist/assets/TutorialView-BPaY-imZ.js
rename to web/admin-spa/dist/assets/TutorialView-DqKyDtQV.js
index 579efada..fe1669a4 100644
--- a/web/admin-spa/dist/assets/TutorialView-BPaY-imZ.js
+++ b/web/admin-spa/dist/assets/TutorialView-DqKyDtQV.js
@@ -1 +1 @@
-import{_ as m}from"./index-D7YURYF2.js";import{r as g,c as x,x as i,z as a,L as b,O as e,Q as u,ac as p,aY as l,P as d,y as c,C as v}from"./vue-vendor-CKToUHZx.js";import"./element-plus-B8Fs_0jW.js";import"./vendor-BDiMbLwQ.js";const y={class:"card p-6"},f={class:"mb-8"},h={class:"flex flex-wrap gap-2 p-2 bg-gray-100 rounded-xl"},C=["onClick"],w={key:0,class:"tutorial-content"},A={class:"mb-10"},T={class:"bg-gradient-to-r from-orange-50 to-yellow-50 rounded-xl p-6 border border-orange-100 mb-6"},P={class:"space-y-4"},N={class:"bg-white rounded-lg p-4 border border-orange-200"},S={class:"bg-gray-900 text-green-400 p-3 rounded font-mono text-sm"},H={class:"text-gray-300"},O={class:"bg-white rounded-lg p-4 border border-orange-200"},I={class:"mt-3 space-y-2"},R={class:"bg-gray-100 p-2 rounded text-sm"},B={class:"font-mono"},U={class:"bg-blue-50 border border-blue-200 rounded-lg p-4 mt-6"},j={class:"mt-3 space-y-2"},E={class:"bg-gray-100 p-2 rounded text-sm font-mono"},L={key:1,class:"tutorial-content"},_={class:"mb-10"},q={class:"bg-gradient-to-r from-orange-50 to-yellow-50 rounded-xl p-6 border border-orange-100 mb-6"},k={class:"space-y-4"},G={class:"bg-white rounded-lg p-4 border border-orange-200"},K={class:"bg-gray-900 text-green-400 p-3 rounded font-mono text-sm"},z={class:"text-gray-300"},D={class:"bg-white rounded-lg p-4 border border-orange-200"},W={class:"bg-gray-900 text-green-400 p-3 rounded font-mono text-sm mb-3"},$={class:"text-gray-300"},M={class:"bg-gray-900 text-green-400 p-3 rounded font-mono text-sm"},V={class:"text-gray-300"},F={key:2,class:"tutorial-content"},Q={class:"mb-10"},Y={class:"bg-gradient-to-r from-orange-50 to-yellow-50 rounded-xl p-6 border border-orange-100 mb-6"},J={class:"space-y-4"},X={class:"bg-white rounded-lg p-4 border border-orange-200"},Z={class:"bg-gray-900 text-green-400 p-3 rounded font-mono text-sm"},tt={class:"text-gray-300"},at={class:"bg-white rounded-lg p-4 border border-orange-200"},et={class:"bg-gray-900 text-green-400 p-3 rounded font-mono text-sm mb-3"},dt={class:"text-gray-300"},st={class:"bg-gray-900 text-green-400 p-3 rounded font-mono text-sm"},lt={class:"text-gray-300"},rt={__name:"TutorialView",setup(ot){const r=g("windows"),n=[{key:"windows",name:"Windows",icon:"fab fa-windows"},{key:"macos",name:"macOS",icon:"fab fa-apple"},{key:"linux",name:"Linux / WSL2",icon:"fab fa-linux"}];return x(()=>window.location.origin),(s,t)=>(c(),i("div",y,[t[55]||(t[55]=a("div",{class:"mb-8"},[a("h3",{class:"text-2xl font-bold text-gray-900 mb-4 flex items-center"},[a("i",{class:"fas fa-graduation-cap text-blue-600 mr-3"}),e(" Claude Code 使用教程 ")]),a("p",{class:"text-gray-600 text-lg"}," 跟着这个教程,你可以轻松在自己的电脑上安装并使用 Claude Code。 ")],-1)),a("div",f,[a("div",h,[(c(),i(u,null,p(n,o=>a("button",{key:o.key,class:v(["flex-1 py-3 px-6 text-sm font-semibold rounded-lg transition-all duration-300 flex items-center justify-center gap-2",r.value===o.key?"bg-white text-blue-600 shadow-sm":"text-gray-600 hover:bg-white/50 hover:text-gray-900"]),onClick:it=>r.value=o.key},[a("i",{class:v(o.icon)},null,2),e(" "+d(o.name),1)],10,C)),64))])]),r.value==="windows"?(c(),i("div",w,[t[19]||(t[19]=l('1 安装 Node.js 环境
Claude Code 需要 Node.js 环境才能运行。
Windows 安装方法
方法一:官网下载(推荐)
- 打开浏览器访问
https://nodejs.org/ - 点击 "LTS" 版本进行下载(推荐长期支持版本)
- 下载完成后双击
.msi 文件 - 按照安装向导完成安装,保持默认设置即可
方法二:使用包管理器
如果你安装了 Chocolatey 或 Scoop,可以使用命令行安装:
# 使用 Chocolatey
choco install nodejs
# 或使用 Scoop
scoop install nodejs
Windows 注意事项
- • 建议使用 PowerShell 而不是 CMD
- • 如果遇到权限问题,尝试以管理员身份运行
- • 某些杀毒软件可能会误报,需要添加白名单
验证安装是否成功
安装完成后,打开 PowerShell 或 CMD,输入以下命令:
node --version
npm --version
如果显示版本号,说明安装成功了!
2 安装 Git Bash
Windows 环境下需要使用 Git Bash 安装Claude code。安装完成后,环境变量设置和使用 Claude Code 仍然在普通的 PowerShell 或 CMD 中进行。
下载并安装 Git for Windows
- 访问
https://git-scm.com/downloads/win - 点击 "Download for Windows" 下载安装包
- 运行下载的
.exe 安装文件 - 在安装过程中保持默认设置,直接点击 "Next" 完成安装
安装完成后
- • 在任意文件夹右键可以看到 "Git Bash Here" 选项
- • 也可以从开始菜单启动 "Git Bash"
- • 只需要在 Git Bash 中运行 npm install 命令
- • 后续的环境变量设置和使用都在 PowerShell/CMD 中
验证 Git Bash 安装
打开 Git Bash,输入以下命令验证:
如果显示 Git 版本号,说明安装成功!
3 安装 Claude Code
安装 Claude Code
打开 Git Bash(重要:不要使用 PowerShell),运行以下命令:
# 在 Git Bash 中全局安装 Claude Code
npm install -g @anthropic-ai/claude-code
这个命令会从 npm 官方仓库下载并安装最新版本的 Claude Code。
重要提醒
- • 必须在 Git Bash 中运行,不要在 PowerShell 中运行
- • 如果遇到权限问题,可以尝试在 Git Bash 中使用 sudo 命令
验证 Claude Code 安装
安装完成后,输入以下命令检查是否安装成功:
如果显示版本号,恭喜你!Claude Code 已经成功安装了。
',3)),a("div",A,[t[18]||(t[18]=a("h4",{class:"text-xl font-semibold text-gray-800 mb-4 flex items-center"},[a("span",{class:"w-8 h-8 bg-orange-500 text-white rounded-full flex items-center justify-center text-sm font-bold mr-3"},"4"),e(" 设置环境变量 ")],-1)),a("div",T,[t[12]||(t[12]=a("h5",{class:"text-lg font-semibold text-gray-800 mb-3 flex items-center"},[a("i",{class:"fas fa-cog text-orange-600 mr-2"}),e(" 配置 Claude Code 环境变量 ")],-1)),t[13]||(t[13]=a("p",{class:"text-gray-700 mb-4"}," 为了让 Claude Code 连接到你的中转服务,需要设置两个环境变量: ",-1)),a("div",P,[a("div",N,[t[1]||(t[1]=a("h6",{class:"font-medium text-gray-800 mb-2"}," 方法一:PowerShell 临时设置(推荐) ",-1)),t[2]||(t[2]=a("p",{class:"text-gray-600 text-sm mb-3"}," 在 PowerShell 中运行以下命令: ",-1)),a("div",S,[a("div",H,' $env:ANTHROPIC_BASE_URL = "'+d(s.currentBaseUrl)+'" ',1),t[0]||(t[0]=a("div",{class:"text-gray-300"},' $env:ANTHROPIC_AUTH_TOKEN = "你的API密钥" ',-1))]),t[3]||(t[3]=a("p",{class:"text-yellow-700 text-xs mt-2"},' 💡 记得将 "你的API密钥" 替换为在上方 "API Keys" 标签页中创建的实际密钥。 ',-1))]),a("div",O,[t[10]||(t[10]=a("h6",{class:"font-medium text-gray-800 mb-2"}," 方法二:系统环境变量(永久设置) ",-1)),t[11]||(t[11]=a("ol",{class:"text-gray-600 text-sm space-y-1 list-decimal list-inside"},[a("li",null,'右键"此电脑" → "属性" → "高级系统设置"'),a("li",null,'点击"环境变量"按钮'),a("li",null,'在"用户变量"或"系统变量"中点击"新建"'),a("li",null,"添加以下两个变量:")],-1)),a("div",I,[a("div",R,[t[4]||(t[4]=a("strong",null,"变量名:",-1)),t[5]||(t[5]=e(" ANTHROPIC_BASE_URL",-1)),t[6]||(t[6]=a("br",null,null,-1)),t[7]||(t[7]=a("strong",null,"变量值:",-1)),t[8]||(t[8]=e()),a("span",B,d(s.currentBaseUrl),1)]),t[9]||(t[9]=a("div",{class:"bg-gray-100 p-2 rounded text-sm"},[a("strong",null,"变量名:"),e(" ANTHROPIC_AUTH_TOKEN"),a("br"),a("strong",null,"变量值:"),e(),a("span",{class:"font-mono"},"你的API密钥")],-1))])])])]),a("div",U,[t[17]||(t[17]=l(' 验证环境变量设置
设置完环境变量后,可以通过以下命令验证是否设置成功:
在 PowerShell 中验证:
echo $env:ANTHROPIC_BASE_URL
echo $env:ANTHROPIC_AUTH_TOKEN
在 CMD 中验证:
echo %ANTHROPIC_BASE_URL%
echo %ANTHROPIC_AUTH_TOKEN%
',3)),a("div",j,[t[15]||(t[15]=a("p",{class:"text-blue-700 text-sm"},[a("strong",null,"预期输出示例:")],-1)),a("div",E,[a("div",null,d(s.currentBaseUrl),1),t[14]||(t[14]=a("div",null,"cr_xxxxxxxxxxxxxxxxxx",-1))]),t[16]||(t[16]=a("p",{class:"text-blue-700 text-xs"}," 💡 如果输出为空或显示变量名本身,说明环境变量设置失败,请重新设置。 ",-1))])])]),t[20]||(t[20]=l('5 开始使用 Claude Code
现在你可以开始使用 Claude Code 了!
在特定项目中使用
# 进入你的项目目录
cd C:\\path\\to\\your\\project
# 启动 Claude Code
claude
Windows 常见问题解决
安装时提示 "permission denied" 错误
这通常是权限问题,尝试以下解决方法:
- 以管理员身份运行 PowerShell
- 或者配置 npm 使用用户目录:
npm config set prefix %APPDATA%\\npm
PowerShell 执行策略错误
如果遇到执行策略限制,运行:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
环境变量设置后不生效
设置永久环境变量后需要:
- 重新启动 PowerShell 或 CMD
- 或者注销并重新登录 Windows
- 验证设置:
echo $env:ANTHROPIC_BASE_URL
',2))])):r.value==="macos"?(c(),i("div",L,[t[36]||(t[36]=l('1 安装 Node.js 环境
Claude Code 需要 Node.js 环境才能运行。
macOS 安装方法
方法一:使用 Homebrew(推荐)
如果你已经安装了 Homebrew,使用它安装 Node.js 会更方便:
# 更新 Homebrew
brew update
# 安装 Node.js
brew install node
方法二:官网下载
- 访问
https://nodejs.org/ - 下载适合 macOS 的 LTS 版本
- 打开下载的
.pkg 文件 - 按照安装程序指引完成安装
macOS 注意事项
- • 如果遇到权限问题,可能需要使用
sudo - • 首次运行可能需要在系统偏好设置中允许
- • 建议使用 Terminal 或 iTerm2
验证安装是否成功
安装完成后,打开 Terminal,输入以下命令:
node --version
npm --version
如果显示版本号,说明安装成功了!
2 安装 Claude Code
安装 Claude Code
打开 Terminal,运行以下命令:
# 全局安装 Claude Code
npm install -g @anthropic-ai/claude-code
如果遇到权限问题,可以使用 sudo:
sudo npm install -g @anthropic-ai/claude-code
验证 Claude Code 安装
安装完成后,输入以下命令检查是否安装成功:
如果显示版本号,恭喜你!Claude Code 已经成功安装了。
',2)),a("div",_,[t[35]||(t[35]=a("h4",{class:"text-xl font-semibold text-gray-800 mb-4 flex items-center"},[a("span",{class:"w-8 h-8 bg-orange-500 text-white rounded-full flex items-center justify-center text-sm font-bold mr-3"},"3"),e(" 设置环境变量 ")],-1)),a("div",q,[t[33]||(t[33]=a("h5",{class:"text-lg font-semibold text-gray-800 mb-3 flex items-center"},[a("i",{class:"fas fa-cog text-orange-600 mr-2"}),e(" 配置 Claude Code 环境变量 ")],-1)),t[34]||(t[34]=a("p",{class:"text-gray-700 mb-4"}," 为了让 Claude Code 连接到你的中转服务,需要设置两个环境变量: ",-1)),a("div",k,[a("div",G,[t[22]||(t[22]=a("h6",{class:"font-medium text-gray-800 mb-2"}," 方法一:临时设置(当前会话) ",-1)),t[23]||(t[23]=a("p",{class:"text-gray-600 text-sm mb-3"}," 在 Terminal 中运行以下命令: ",-1)),a("div",K,[a("div",z,' export ANTHROPIC_BASE_URL="'+d(s.currentBaseUrl)+'" ',1),t[21]||(t[21]=a("div",{class:"text-gray-300"},' export ANTHROPIC_AUTH_TOKEN="你的API密钥" ',-1))]),t[24]||(t[24]=a("p",{class:"text-yellow-700 text-xs mt-2"},' 💡 记得将 "你的API密钥" 替换为在上方 "API Keys" 标签页中创建的实际密钥。 ',-1))]),a("div",D,[t[31]||(t[31]=a("h6",{class:"font-medium text-gray-800 mb-2"}," 方法二:永久设置 ",-1)),t[32]||(t[32]=a("p",{class:"text-gray-600 text-sm mb-3"}," 编辑你的 shell 配置文件(根据你使用的 shell): ",-1)),a("div",W,[t[25]||(t[25]=a("div",{class:"mb-2"}," # 对于 zsh (默认) ",-1)),a("div",$,` echo 'export ANTHROPIC_BASE_URL="`+d(s.currentBaseUrl)+`"' >> ~/.zshrc `,1),t[26]||(t[26]=a("div",{class:"text-gray-300"},` echo 'export ANTHROPIC_AUTH_TOKEN="你的API密钥"' >> ~/.zshrc `,-1)),t[27]||(t[27]=a("div",{class:"text-gray-300"}," source ~/.zshrc ",-1))]),a("div",M,[t[28]||(t[28]=a("div",{class:"mb-2"}," # 对于 bash ",-1)),a("div",V,` echo 'export ANTHROPIC_BASE_URL="`+d(s.currentBaseUrl)+`"' >> ~/.bash_profile `,1),t[29]||(t[29]=a("div",{class:"text-gray-300"},` echo 'export ANTHROPIC_AUTH_TOKEN="你的API密钥"' >> ~/.bash_profile `,-1)),t[30]||(t[30]=a("div",{class:"text-gray-300"}," source ~/.bash_profile ",-1))])])])])]),t[37]||(t[37]=l('4 开始使用 Claude Code
现在你可以开始使用 Claude Code 了!
在特定项目中使用
# 进入你的项目目录
cd /path/to/your/project
# 启动 Claude Code
claude
macOS 常见问题解决
安装时提示权限错误
尝试以下解决方法:
- 使用 sudo 安装:
sudo npm install -g @anthropic-ai/claude-code - 或者配置 npm 使用用户目录:
npm config set prefix ~/.npm-global
macOS 安全设置阻止运行
如果系统阻止运行 Claude Code:
- 打开"系统偏好设置" → "安全性与隐私"
- 点击"仍要打开"或"允许"
- 或者在 Terminal 中运行:
sudo spctl --master-disable
环境变量不生效
检查以下几点:
- 确认修改了正确的配置文件(.zshrc 或 .bash_profile)
- 重新启动 Terminal
- 验证设置:
echo $ANTHROPIC_BASE_URL
',2))])):r.value==="linux"?(c(),i("div",F,[t[53]||(t[53]=l('1 安装 Node.js 环境
Claude Code 需要 Node.js 环境才能运行。
Linux 安装方法
方法一:使用官方仓库(推荐)
# 添加 NodeSource 仓库
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
# 安装 Node.js
sudo apt-get install -y nodejs
方法二:使用系统包管理器
虽然版本可能不是最新的,但对于基本使用已经足够:
# Ubuntu/Debian
sudo apt update
sudo apt install nodejs npm
# CentOS/RHEL/Fedora
sudo dnf install nodejs npm
Linux 注意事项
- • 某些发行版可能需要安装额外的依赖
- • 如果遇到权限问题,使用
sudo - • 确保你的用户在 npm 的全局目录有写权限
验证安装是否成功
安装完成后,打开终端,输入以下命令:
node --version
npm --version
如果显示版本号,说明安装成功了!
2 安装 Claude Code
安装 Claude Code
打开终端,运行以下命令:
# 全局安装 Claude Code
npm install -g @anthropic-ai/claude-code
如果遇到权限问题,可以使用 sudo:
sudo npm install -g @anthropic-ai/claude-code
验证 Claude Code 安装
安装完成后,输入以下命令检查是否安装成功:
如果显示版本号,恭喜你!Claude Code 已经成功安装了。
',2)),a("div",Q,[t[52]||(t[52]=a("h4",{class:"text-xl font-semibold text-gray-800 mb-4 flex items-center"},[a("span",{class:"w-8 h-8 bg-orange-500 text-white rounded-full flex items-center justify-center text-sm font-bold mr-3"},"3"),e(" 设置环境变量 ")],-1)),a("div",Y,[t[50]||(t[50]=a("h5",{class:"text-lg font-semibold text-gray-800 mb-3 flex items-center"},[a("i",{class:"fas fa-cog text-orange-600 mr-2"}),e(" 配置 Claude Code 环境变量 ")],-1)),t[51]||(t[51]=a("p",{class:"text-gray-700 mb-4"}," 为了让 Claude Code 连接到你的中转服务,需要设置两个环境变量: ",-1)),a("div",J,[a("div",X,[t[39]||(t[39]=a("h6",{class:"font-medium text-gray-800 mb-2"}," 方法一:临时设置(当前会话) ",-1)),t[40]||(t[40]=a("p",{class:"text-gray-600 text-sm mb-3"}," 在终端中运行以下命令: ",-1)),a("div",Z,[a("div",tt,' export ANTHROPIC_BASE_URL="'+d(s.currentBaseUrl)+'" ',1),t[38]||(t[38]=a("div",{class:"text-gray-300"},' export ANTHROPIC_AUTH_TOKEN="你的API密钥" ',-1))]),t[41]||(t[41]=a("p",{class:"text-yellow-700 text-xs mt-2"},' 💡 记得将 "你的API密钥" 替换为在上方 "API Keys" 标签页中创建的实际密钥。 ',-1))]),a("div",at,[t[48]||(t[48]=a("h6",{class:"font-medium text-gray-800 mb-2"}," 方法二:永久设置 ",-1)),t[49]||(t[49]=a("p",{class:"text-gray-600 text-sm mb-3"}," 编辑你的 shell 配置文件: ",-1)),a("div",et,[t[42]||(t[42]=a("div",{class:"mb-2"}," # 对于 bash (默认) ",-1)),a("div",dt,` echo 'export ANTHROPIC_BASE_URL="`+d(s.currentBaseUrl)+`"' >> ~/.bashrc `,1),t[43]||(t[43]=a("div",{class:"text-gray-300"},` echo 'export ANTHROPIC_AUTH_TOKEN="你的API密钥"' >> ~/.bashrc `,-1)),t[44]||(t[44]=a("div",{class:"text-gray-300"}," source ~/.bashrc ",-1))]),a("div",st,[t[45]||(t[45]=a("div",{class:"mb-2"}," # 对于 zsh ",-1)),a("div",lt,` echo 'export ANTHROPIC_BASE_URL="`+d(s.currentBaseUrl)+`"' >> ~/.zshrc `,1),t[46]||(t[46]=a("div",{class:"text-gray-300"},` echo 'export ANTHROPIC_AUTH_TOKEN="你的API密钥"' >> ~/.zshrc `,-1)),t[47]||(t[47]=a("div",{class:"text-gray-300"}," source ~/.zshrc ",-1))])])])])]),t[54]||(t[54]=l('4 开始使用 Claude Code
现在你可以开始使用 Claude Code 了!
在特定项目中使用
# 进入你的项目目录
cd /path/to/your/project
# 启动 Claude Code
claude
Linux 常见问题解决
安装时提示权限错误
尝试以下解决方法:
- 使用 sudo 安装:
sudo npm install -g @anthropic-ai/claude-code - 或者配置 npm 使用用户目录:
npm config set prefix ~/.npm-global - 然后添加到 PATH:
export PATH=~/.npm-global/bin:$PATH
缺少依赖库
某些 Linux 发行版需要安装额外依赖:
# Ubuntu/Debian
sudo apt install build-essential
# CentOS/RHEL
sudo dnf groupinstall "Development Tools"
环境变量不生效
检查以下几点:
- 确认修改了正确的配置文件(.bashrc 或 .zshrc)
- 重新启动终端或运行
source ~/.bashrc - 验证设置:
echo $ANTHROPIC_BASE_URL
',2))])):b("",!0),t[56]||(t[56]=a("div",{class:"bg-gradient-to-r from-blue-500 to-purple-600 text-white rounded-xl p-6 text-center"},[a("h5",{class:"text-xl font-semibold mb-2"}," 🎉 恭喜你! "),a("p",{class:"text-blue-100 mb-4"}," 你已经成功安装并配置了 Claude Code,现在可以开始享受 AI 编程助手带来的便利了。 "),a("p",{class:"text-sm text-blue-200"}," 如果在使用过程中遇到任何问题,可以查看官方文档或社区讨论获取帮助。 ")],-1))]))}},gt=m(rt,[["__scopeId","data-v-508c8654"]]);export{gt as default};
+import{_ as m}from"./index-HYE9xPuR.js";import{r as g,c as x,x as i,z as a,L as b,O as e,Q as u,ac as p,aY as l,P as d,y as c,C as v}from"./vue-vendor-CKToUHZx.js";import"./element-plus-B8Fs_0jW.js";import"./vendor-BDiMbLwQ.js";const y={class:"card p-6"},f={class:"mb-8"},h={class:"flex flex-wrap gap-2 p-2 bg-gray-100 rounded-xl"},C=["onClick"],w={key:0,class:"tutorial-content"},A={class:"mb-10"},T={class:"bg-gradient-to-r from-orange-50 to-yellow-50 rounded-xl p-6 border border-orange-100 mb-6"},P={class:"space-y-4"},N={class:"bg-white rounded-lg p-4 border border-orange-200"},S={class:"bg-gray-900 text-green-400 p-3 rounded font-mono text-sm"},H={class:"text-gray-300"},O={class:"bg-white rounded-lg p-4 border border-orange-200"},I={class:"mt-3 space-y-2"},R={class:"bg-gray-100 p-2 rounded text-sm"},B={class:"font-mono"},U={class:"bg-blue-50 border border-blue-200 rounded-lg p-4 mt-6"},j={class:"mt-3 space-y-2"},E={class:"bg-gray-100 p-2 rounded text-sm font-mono"},L={key:1,class:"tutorial-content"},_={class:"mb-10"},q={class:"bg-gradient-to-r from-orange-50 to-yellow-50 rounded-xl p-6 border border-orange-100 mb-6"},k={class:"space-y-4"},G={class:"bg-white rounded-lg p-4 border border-orange-200"},K={class:"bg-gray-900 text-green-400 p-3 rounded font-mono text-sm"},z={class:"text-gray-300"},D={class:"bg-white rounded-lg p-4 border border-orange-200"},W={class:"bg-gray-900 text-green-400 p-3 rounded font-mono text-sm mb-3"},$={class:"text-gray-300"},M={class:"bg-gray-900 text-green-400 p-3 rounded font-mono text-sm"},V={class:"text-gray-300"},F={key:2,class:"tutorial-content"},Q={class:"mb-10"},Y={class:"bg-gradient-to-r from-orange-50 to-yellow-50 rounded-xl p-6 border border-orange-100 mb-6"},J={class:"space-y-4"},X={class:"bg-white rounded-lg p-4 border border-orange-200"},Z={class:"bg-gray-900 text-green-400 p-3 rounded font-mono text-sm"},tt={class:"text-gray-300"},at={class:"bg-white rounded-lg p-4 border border-orange-200"},et={class:"bg-gray-900 text-green-400 p-3 rounded font-mono text-sm mb-3"},dt={class:"text-gray-300"},st={class:"bg-gray-900 text-green-400 p-3 rounded font-mono text-sm"},lt={class:"text-gray-300"},rt={__name:"TutorialView",setup(ot){const r=g("windows"),n=[{key:"windows",name:"Windows",icon:"fab fa-windows"},{key:"macos",name:"macOS",icon:"fab fa-apple"},{key:"linux",name:"Linux / WSL2",icon:"fab fa-linux"}];return x(()=>window.location.origin),(s,t)=>(c(),i("div",y,[t[55]||(t[55]=a("div",{class:"mb-8"},[a("h3",{class:"text-2xl font-bold text-gray-900 mb-4 flex items-center"},[a("i",{class:"fas fa-graduation-cap text-blue-600 mr-3"}),e(" Claude Code 使用教程 ")]),a("p",{class:"text-gray-600 text-lg"}," 跟着这个教程,你可以轻松在自己的电脑上安装并使用 Claude Code。 ")],-1)),a("div",f,[a("div",h,[(c(),i(u,null,p(n,o=>a("button",{key:o.key,class:v(["flex-1 py-3 px-6 text-sm font-semibold rounded-lg transition-all duration-300 flex items-center justify-center gap-2",r.value===o.key?"bg-white text-blue-600 shadow-sm":"text-gray-600 hover:bg-white/50 hover:text-gray-900"]),onClick:it=>r.value=o.key},[a("i",{class:v(o.icon)},null,2),e(" "+d(o.name),1)],10,C)),64))])]),r.value==="windows"?(c(),i("div",w,[t[19]||(t[19]=l('1 安装 Node.js 环境
Claude Code 需要 Node.js 环境才能运行。
Windows 安装方法
方法一:官网下载(推荐)
- 打开浏览器访问
https://nodejs.org/ - 点击 "LTS" 版本进行下载(推荐长期支持版本)
- 下载完成后双击
.msi 文件 - 按照安装向导完成安装,保持默认设置即可
方法二:使用包管理器
如果你安装了 Chocolatey 或 Scoop,可以使用命令行安装:
# 使用 Chocolatey
choco install nodejs
# 或使用 Scoop
scoop install nodejs
Windows 注意事项
- • 建议使用 PowerShell 而不是 CMD
- • 如果遇到权限问题,尝试以管理员身份运行
- • 某些杀毒软件可能会误报,需要添加白名单
验证安装是否成功
安装完成后,打开 PowerShell 或 CMD,输入以下命令:
node --version
npm --version
如果显示版本号,说明安装成功了!
2 安装 Git Bash
Windows 环境下需要使用 Git Bash 安装Claude code。安装完成后,环境变量设置和使用 Claude Code 仍然在普通的 PowerShell 或 CMD 中进行。
下载并安装 Git for Windows
- 访问
https://git-scm.com/downloads/win - 点击 "Download for Windows" 下载安装包
- 运行下载的
.exe 安装文件 - 在安装过程中保持默认设置,直接点击 "Next" 完成安装
安装完成后
- • 在任意文件夹右键可以看到 "Git Bash Here" 选项
- • 也可以从开始菜单启动 "Git Bash"
- • 只需要在 Git Bash 中运行 npm install 命令
- • 后续的环境变量设置和使用都在 PowerShell/CMD 中
验证 Git Bash 安装
打开 Git Bash,输入以下命令验证:
如果显示 Git 版本号,说明安装成功!
3 安装 Claude Code
安装 Claude Code
打开 Git Bash(重要:不要使用 PowerShell),运行以下命令:
# 在 Git Bash 中全局安装 Claude Code
npm install -g @anthropic-ai/claude-code
这个命令会从 npm 官方仓库下载并安装最新版本的 Claude Code。
重要提醒
- • 必须在 Git Bash 中运行,不要在 PowerShell 中运行
- • 如果遇到权限问题,可以尝试在 Git Bash 中使用 sudo 命令
验证 Claude Code 安装
安装完成后,输入以下命令检查是否安装成功:
如果显示版本号,恭喜你!Claude Code 已经成功安装了。
',3)),a("div",A,[t[18]||(t[18]=a("h4",{class:"text-xl font-semibold text-gray-800 mb-4 flex items-center"},[a("span",{class:"w-8 h-8 bg-orange-500 text-white rounded-full flex items-center justify-center text-sm font-bold mr-3"},"4"),e(" 设置环境变量 ")],-1)),a("div",T,[t[12]||(t[12]=a("h5",{class:"text-lg font-semibold text-gray-800 mb-3 flex items-center"},[a("i",{class:"fas fa-cog text-orange-600 mr-2"}),e(" 配置 Claude Code 环境变量 ")],-1)),t[13]||(t[13]=a("p",{class:"text-gray-700 mb-4"}," 为了让 Claude Code 连接到你的中转服务,需要设置两个环境变量: ",-1)),a("div",P,[a("div",N,[t[1]||(t[1]=a("h6",{class:"font-medium text-gray-800 mb-2"}," 方法一:PowerShell 临时设置(推荐) ",-1)),t[2]||(t[2]=a("p",{class:"text-gray-600 text-sm mb-3"}," 在 PowerShell 中运行以下命令: ",-1)),a("div",S,[a("div",H,' $env:ANTHROPIC_BASE_URL = "'+d(s.currentBaseUrl)+'" ',1),t[0]||(t[0]=a("div",{class:"text-gray-300"},' $env:ANTHROPIC_AUTH_TOKEN = "你的API密钥" ',-1))]),t[3]||(t[3]=a("p",{class:"text-yellow-700 text-xs mt-2"},' 💡 记得将 "你的API密钥" 替换为在上方 "API Keys" 标签页中创建的实际密钥。 ',-1))]),a("div",O,[t[10]||(t[10]=a("h6",{class:"font-medium text-gray-800 mb-2"}," 方法二:系统环境变量(永久设置) ",-1)),t[11]||(t[11]=a("ol",{class:"text-gray-600 text-sm space-y-1 list-decimal list-inside"},[a("li",null,'右键"此电脑" → "属性" → "高级系统设置"'),a("li",null,'点击"环境变量"按钮'),a("li",null,'在"用户变量"或"系统变量"中点击"新建"'),a("li",null,"添加以下两个变量:")],-1)),a("div",I,[a("div",R,[t[4]||(t[4]=a("strong",null,"变量名:",-1)),t[5]||(t[5]=e(" ANTHROPIC_BASE_URL",-1)),t[6]||(t[6]=a("br",null,null,-1)),t[7]||(t[7]=a("strong",null,"变量值:",-1)),t[8]||(t[8]=e()),a("span",B,d(s.currentBaseUrl),1)]),t[9]||(t[9]=a("div",{class:"bg-gray-100 p-2 rounded text-sm"},[a("strong",null,"变量名:"),e(" ANTHROPIC_AUTH_TOKEN"),a("br"),a("strong",null,"变量值:"),e(),a("span",{class:"font-mono"},"你的API密钥")],-1))])])])]),a("div",U,[t[17]||(t[17]=l(' 验证环境变量设置
设置完环境变量后,可以通过以下命令验证是否设置成功:
在 PowerShell 中验证:
echo $env:ANTHROPIC_BASE_URL
echo $env:ANTHROPIC_AUTH_TOKEN
在 CMD 中验证:
echo %ANTHROPIC_BASE_URL%
echo %ANTHROPIC_AUTH_TOKEN%
',3)),a("div",j,[t[15]||(t[15]=a("p",{class:"text-blue-700 text-sm"},[a("strong",null,"预期输出示例:")],-1)),a("div",E,[a("div",null,d(s.currentBaseUrl),1),t[14]||(t[14]=a("div",null,"cr_xxxxxxxxxxxxxxxxxx",-1))]),t[16]||(t[16]=a("p",{class:"text-blue-700 text-xs"}," 💡 如果输出为空或显示变量名本身,说明环境变量设置失败,请重新设置。 ",-1))])])]),t[20]||(t[20]=l('5 开始使用 Claude Code
现在你可以开始使用 Claude Code 了!
在特定项目中使用
# 进入你的项目目录
cd C:\\path\\to\\your\\project
# 启动 Claude Code
claude
Windows 常见问题解决
安装时提示 "permission denied" 错误
这通常是权限问题,尝试以下解决方法:
- 以管理员身份运行 PowerShell
- 或者配置 npm 使用用户目录:
npm config set prefix %APPDATA%\\npm
PowerShell 执行策略错误
如果遇到执行策略限制,运行:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
环境变量设置后不生效
设置永久环境变量后需要:
- 重新启动 PowerShell 或 CMD
- 或者注销并重新登录 Windows
- 验证设置:
echo $env:ANTHROPIC_BASE_URL
',2))])):r.value==="macos"?(c(),i("div",L,[t[36]||(t[36]=l('1 安装 Node.js 环境
Claude Code 需要 Node.js 环境才能运行。
macOS 安装方法
方法一:使用 Homebrew(推荐)
如果你已经安装了 Homebrew,使用它安装 Node.js 会更方便:
# 更新 Homebrew
brew update
# 安装 Node.js
brew install node
方法二:官网下载
- 访问
https://nodejs.org/ - 下载适合 macOS 的 LTS 版本
- 打开下载的
.pkg 文件 - 按照安装程序指引完成安装
macOS 注意事项
- • 如果遇到权限问题,可能需要使用
sudo - • 首次运行可能需要在系统偏好设置中允许
- • 建议使用 Terminal 或 iTerm2
验证安装是否成功
安装完成后,打开 Terminal,输入以下命令:
node --version
npm --version
如果显示版本号,说明安装成功了!
2 安装 Claude Code
安装 Claude Code
打开 Terminal,运行以下命令:
# 全局安装 Claude Code
npm install -g @anthropic-ai/claude-code
如果遇到权限问题,可以使用 sudo:
sudo npm install -g @anthropic-ai/claude-code
验证 Claude Code 安装
安装完成后,输入以下命令检查是否安装成功:
如果显示版本号,恭喜你!Claude Code 已经成功安装了。
',2)),a("div",_,[t[35]||(t[35]=a("h4",{class:"text-xl font-semibold text-gray-800 mb-4 flex items-center"},[a("span",{class:"w-8 h-8 bg-orange-500 text-white rounded-full flex items-center justify-center text-sm font-bold mr-3"},"3"),e(" 设置环境变量 ")],-1)),a("div",q,[t[33]||(t[33]=a("h5",{class:"text-lg font-semibold text-gray-800 mb-3 flex items-center"},[a("i",{class:"fas fa-cog text-orange-600 mr-2"}),e(" 配置 Claude Code 环境变量 ")],-1)),t[34]||(t[34]=a("p",{class:"text-gray-700 mb-4"}," 为了让 Claude Code 连接到你的中转服务,需要设置两个环境变量: ",-1)),a("div",k,[a("div",G,[t[22]||(t[22]=a("h6",{class:"font-medium text-gray-800 mb-2"}," 方法一:临时设置(当前会话) ",-1)),t[23]||(t[23]=a("p",{class:"text-gray-600 text-sm mb-3"}," 在 Terminal 中运行以下命令: ",-1)),a("div",K,[a("div",z,' export ANTHROPIC_BASE_URL="'+d(s.currentBaseUrl)+'" ',1),t[21]||(t[21]=a("div",{class:"text-gray-300"},' export ANTHROPIC_AUTH_TOKEN="你的API密钥" ',-1))]),t[24]||(t[24]=a("p",{class:"text-yellow-700 text-xs mt-2"},' 💡 记得将 "你的API密钥" 替换为在上方 "API Keys" 标签页中创建的实际密钥。 ',-1))]),a("div",D,[t[31]||(t[31]=a("h6",{class:"font-medium text-gray-800 mb-2"}," 方法二:永久设置 ",-1)),t[32]||(t[32]=a("p",{class:"text-gray-600 text-sm mb-3"}," 编辑你的 shell 配置文件(根据你使用的 shell): ",-1)),a("div",W,[t[25]||(t[25]=a("div",{class:"mb-2"}," # 对于 zsh (默认) ",-1)),a("div",$,` echo 'export ANTHROPIC_BASE_URL="`+d(s.currentBaseUrl)+`"' >> ~/.zshrc `,1),t[26]||(t[26]=a("div",{class:"text-gray-300"},` echo 'export ANTHROPIC_AUTH_TOKEN="你的API密钥"' >> ~/.zshrc `,-1)),t[27]||(t[27]=a("div",{class:"text-gray-300"}," source ~/.zshrc ",-1))]),a("div",M,[t[28]||(t[28]=a("div",{class:"mb-2"}," # 对于 bash ",-1)),a("div",V,` echo 'export ANTHROPIC_BASE_URL="`+d(s.currentBaseUrl)+`"' >> ~/.bash_profile `,1),t[29]||(t[29]=a("div",{class:"text-gray-300"},` echo 'export ANTHROPIC_AUTH_TOKEN="你的API密钥"' >> ~/.bash_profile `,-1)),t[30]||(t[30]=a("div",{class:"text-gray-300"}," source ~/.bash_profile ",-1))])])])])]),t[37]||(t[37]=l('4 开始使用 Claude Code
现在你可以开始使用 Claude Code 了!
在特定项目中使用
# 进入你的项目目录
cd /path/to/your/project
# 启动 Claude Code
claude
macOS 常见问题解决
安装时提示权限错误
尝试以下解决方法:
- 使用 sudo 安装:
sudo npm install -g @anthropic-ai/claude-code - 或者配置 npm 使用用户目录:
npm config set prefix ~/.npm-global
macOS 安全设置阻止运行
如果系统阻止运行 Claude Code:
- 打开"系统偏好设置" → "安全性与隐私"
- 点击"仍要打开"或"允许"
- 或者在 Terminal 中运行:
sudo spctl --master-disable
环境变量不生效
检查以下几点:
- 确认修改了正确的配置文件(.zshrc 或 .bash_profile)
- 重新启动 Terminal
- 验证设置:
echo $ANTHROPIC_BASE_URL
',2))])):r.value==="linux"?(c(),i("div",F,[t[53]||(t[53]=l('1 安装 Node.js 环境
Claude Code 需要 Node.js 环境才能运行。
Linux 安装方法
方法一:使用官方仓库(推荐)
# 添加 NodeSource 仓库
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
# 安装 Node.js
sudo apt-get install -y nodejs
方法二:使用系统包管理器
虽然版本可能不是最新的,但对于基本使用已经足够:
# Ubuntu/Debian
sudo apt update
sudo apt install nodejs npm
# CentOS/RHEL/Fedora
sudo dnf install nodejs npm
Linux 注意事项
- • 某些发行版可能需要安装额外的依赖
- • 如果遇到权限问题,使用
sudo - • 确保你的用户在 npm 的全局目录有写权限
验证安装是否成功
安装完成后,打开终端,输入以下命令:
node --version
npm --version
如果显示版本号,说明安装成功了!
2 安装 Claude Code
安装 Claude Code
打开终端,运行以下命令:
# 全局安装 Claude Code
npm install -g @anthropic-ai/claude-code
如果遇到权限问题,可以使用 sudo:
sudo npm install -g @anthropic-ai/claude-code
验证 Claude Code 安装
安装完成后,输入以下命令检查是否安装成功:
如果显示版本号,恭喜你!Claude Code 已经成功安装了。
',2)),a("div",Q,[t[52]||(t[52]=a("h4",{class:"text-xl font-semibold text-gray-800 mb-4 flex items-center"},[a("span",{class:"w-8 h-8 bg-orange-500 text-white rounded-full flex items-center justify-center text-sm font-bold mr-3"},"3"),e(" 设置环境变量 ")],-1)),a("div",Y,[t[50]||(t[50]=a("h5",{class:"text-lg font-semibold text-gray-800 mb-3 flex items-center"},[a("i",{class:"fas fa-cog text-orange-600 mr-2"}),e(" 配置 Claude Code 环境变量 ")],-1)),t[51]||(t[51]=a("p",{class:"text-gray-700 mb-4"}," 为了让 Claude Code 连接到你的中转服务,需要设置两个环境变量: ",-1)),a("div",J,[a("div",X,[t[39]||(t[39]=a("h6",{class:"font-medium text-gray-800 mb-2"}," 方法一:临时设置(当前会话) ",-1)),t[40]||(t[40]=a("p",{class:"text-gray-600 text-sm mb-3"}," 在终端中运行以下命令: ",-1)),a("div",Z,[a("div",tt,' export ANTHROPIC_BASE_URL="'+d(s.currentBaseUrl)+'" ',1),t[38]||(t[38]=a("div",{class:"text-gray-300"},' export ANTHROPIC_AUTH_TOKEN="你的API密钥" ',-1))]),t[41]||(t[41]=a("p",{class:"text-yellow-700 text-xs mt-2"},' 💡 记得将 "你的API密钥" 替换为在上方 "API Keys" 标签页中创建的实际密钥。 ',-1))]),a("div",at,[t[48]||(t[48]=a("h6",{class:"font-medium text-gray-800 mb-2"}," 方法二:永久设置 ",-1)),t[49]||(t[49]=a("p",{class:"text-gray-600 text-sm mb-3"}," 编辑你的 shell 配置文件: ",-1)),a("div",et,[t[42]||(t[42]=a("div",{class:"mb-2"}," # 对于 bash (默认) ",-1)),a("div",dt,` echo 'export ANTHROPIC_BASE_URL="`+d(s.currentBaseUrl)+`"' >> ~/.bashrc `,1),t[43]||(t[43]=a("div",{class:"text-gray-300"},` echo 'export ANTHROPIC_AUTH_TOKEN="你的API密钥"' >> ~/.bashrc `,-1)),t[44]||(t[44]=a("div",{class:"text-gray-300"}," source ~/.bashrc ",-1))]),a("div",st,[t[45]||(t[45]=a("div",{class:"mb-2"}," # 对于 zsh ",-1)),a("div",lt,` echo 'export ANTHROPIC_BASE_URL="`+d(s.currentBaseUrl)+`"' >> ~/.zshrc `,1),t[46]||(t[46]=a("div",{class:"text-gray-300"},` echo 'export ANTHROPIC_AUTH_TOKEN="你的API密钥"' >> ~/.zshrc `,-1)),t[47]||(t[47]=a("div",{class:"text-gray-300"}," source ~/.zshrc ",-1))])])])])]),t[54]||(t[54]=l('4 开始使用 Claude Code
现在你可以开始使用 Claude Code 了!
在特定项目中使用
# 进入你的项目目录
cd /path/to/your/project
# 启动 Claude Code
claude
Linux 常见问题解决
安装时提示权限错误
尝试以下解决方法:
- 使用 sudo 安装:
sudo npm install -g @anthropic-ai/claude-code - 或者配置 npm 使用用户目录:
npm config set prefix ~/.npm-global - 然后添加到 PATH:
export PATH=~/.npm-global/bin:$PATH
缺少依赖库
某些 Linux 发行版需要安装额外依赖:
# Ubuntu/Debian
sudo apt install build-essential
# CentOS/RHEL
sudo dnf groupinstall "Development Tools"
环境变量不生效
检查以下几点:
- 确认修改了正确的配置文件(.bashrc 或 .zshrc)
- 重新启动终端或运行
source ~/.bashrc - 验证设置:
echo $ANTHROPIC_BASE_URL
',2))])):b("",!0),t[56]||(t[56]=a("div",{class:"bg-gradient-to-r from-blue-500 to-purple-600 text-white rounded-xl p-6 text-center"},[a("h5",{class:"text-xl font-semibold mb-2"}," 🎉 恭喜你! "),a("p",{class:"text-blue-100 mb-4"}," 你已经成功安装并配置了 Claude Code,现在可以开始享受 AI 编程助手带来的便利了。 "),a("p",{class:"text-sm text-blue-200"}," 如果在使用过程中遇到任何问题,可以查看官方文档或社区讨论获取帮助。 ")],-1))]))}},gt=m(rt,[["__scopeId","data-v-508c8654"]]);export{gt as default};
diff --git a/web/admin-spa/dist/assets/index-D7YURYF2.js b/web/admin-spa/dist/assets/index-HYE9xPuR.js
similarity index 91%
rename from web/admin-spa/dist/assets/index-D7YURYF2.js
rename to web/admin-spa/dist/assets/index-HYE9xPuR.js
index 8fdf630e..73f5189c 100644
--- a/web/admin-spa/dist/assets/index-D7YURYF2.js
+++ b/web/admin-spa/dist/assets/index-HYE9xPuR.js
@@ -1,2 +1,2 @@
-const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/LoginView-D5DsB4oB.js","assets/vue-vendor-CKToUHZx.js","assets/element-plus-B8Fs_0jW.js","assets/vendor-BDiMbLwQ.js","assets/element-plus-CPnoEkWW.css","assets/LoginView-tn0RQdqM.css","assets/LogoTitle-BiOf3Vkp.css","assets/MainLayout-BDUoBMsO.js","assets/toast-BvwA7Mwb.js","assets/LogoTitle-Bg7KLvUv.js","assets/MainLayout-tWrOHYRR.css","assets/DashboardView-QB8MFvLZ.js","assets/chart-Cor9iTVD.js","assets/DashboardView-B39lq_zZ.css","assets/ApiKeysView-DagFDYhj.js","assets/ApiKeysView-DYiCSByq.css","assets/AccountsView-CGu30Mq0.js","assets/AccountsView-CZl79P8u.css","assets/TutorialView-BPaY-imZ.js","assets/TutorialView-BM6fz9TT.css","assets/SettingsView-Dubxv8iH.js","assets/SettingsView-D9bl7XvV.css","assets/ApiStatsView-D9E2vriK.js","assets/ApiStatsView-C5BOZdu2.css"])))=>i.map(i=>d[i]);
-import{aP as K,aQ as W,aR as F,r as _,c as L,q as R,V as D,I as q,z as h,x as b,ac as M,Q as G,a5 as N,y,C as S,L as x,P as T,Y as U,B as H,R as P,J,T as Q,O as X,av as Y,aM as Z,aS as ee}from"./vue-vendor-CKToUHZx.js";import{i as te,z as oe}from"./element-plus-B8Fs_0jW.js";import"./vendor-BDiMbLwQ.js";(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))o(s);new MutationObserver(s=>{for(const a of s)if(a.type==="childList")for(const n of a.addedNodes)n.tagName==="LINK"&&n.rel==="modulepreload"&&o(n)}).observe(document,{childList:!0,subtree:!0});function e(s){const a={};return s.integrity&&(a.integrity=s.integrity),s.referrerPolicy&&(a.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?a.credentials="include":s.crossOrigin==="anonymous"?a.credentials="omit":a.credentials="same-origin",a}function o(s){if(s.ep)return;s.ep=!0;const a=e(s);fetch(s.href,a)}})();const se="modulepreload",ne=function(r){return"/admin-next/"+r},$={},w=function(t,e,o){let s=Promise.resolve();if(e&&e.length>0){document.getElementsByTagName("link");const n=document.querySelector("meta[property=csp-nonce]"),p=(n==null?void 0:n.nonce)||(n==null?void 0:n.getAttribute("nonce"));s=Promise.allSettled(e.map(c=>{if(c=ne(c),c in $)return;$[c]=!0;const l=c.endsWith(".css"),d=l?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${c}"]${d}`))return;const i=document.createElement("link");if(i.rel=l?"stylesheet":se,l||(i.as="script"),i.crossOrigin="",i.href=c,p&&i.setAttribute("nonce",p),document.head.appendChild(i),l)return new Promise((m,f)=>{i.addEventListener("load",m),i.addEventListener("error",()=>f(new Error(`Unable to preload CSS for ${c}`)))})}))}function a(n){const p=new Event("vite:preloadError",{cancelable:!0});if(p.payload=n,window.dispatchEvent(p),!p.defaultPrevented)throw n}return s.then(n=>{for(const p of n||[])p.status==="rejected"&&a(p.reason);return t().catch(a)})},V={basePath:"/admin-next/",apiPrefix:""};function ae(r=""){return r&&!r.startsWith("/")&&(r="/"+r),V.basePath+(r.startsWith("#")?r:"#"+r)}function re(){return ae("/login")}const ie=()=>w(()=>import("./LoginView-D5DsB4oB.js"),__vite__mapDeps([0,1,2,3,4,5,6])),E=()=>w(()=>import("./MainLayout-BDUoBMsO.js"),__vite__mapDeps([7,1,8,9,6,2,3,4,10])),ce=()=>w(()=>import("./DashboardView-QB8MFvLZ.js"),__vite__mapDeps([11,2,1,3,4,8,12,13])),le=()=>w(()=>import("./ApiKeysView-DagFDYhj.js"),__vite__mapDeps([14,2,1,3,4,8,15])),ue=()=>w(()=>import("./AccountsView-CGu30Mq0.js"),__vite__mapDeps([16,1,8,2,3,4,17])),de=()=>w(()=>import("./TutorialView-BPaY-imZ.js"),__vite__mapDeps([18,1,2,3,4,19])),fe=()=>w(()=>import("./SettingsView-Dubxv8iH.js"),__vite__mapDeps([20,1,8,2,3,4,21])),he=()=>w(()=>import("./ApiStatsView-D9E2vriK.js"),__vite__mapDeps([22,1,9,6,3,18,2,4,19,23])),me=[{path:"/",redirect:"/api-stats"},{path:"/login",name:"Login",component:ie,meta:{requiresAuth:!1}},{path:"/api-stats",name:"ApiStats",component:he,meta:{requiresAuth:!1}},{path:"/dashboard",component:E,meta:{requiresAuth:!0},children:[{path:"",name:"Dashboard",component:ce}]},{path:"/api-keys",component:E,meta:{requiresAuth:!0},children:[{path:"",name:"ApiKeys",component:le}]},{path:"/accounts",component:E,meta:{requiresAuth:!0},children:[{path:"",name:"Accounts",component:ue}]},{path:"/tutorial",component:E,meta:{requiresAuth:!0},children:[{path:"",name:"Tutorial",component:de}]},{path:"/settings",component:E,meta:{requiresAuth:!0},children:[{path:"",name:"Settings",component:fe}]}],C=K({history:W(V.basePath),routes:me});C.beforeEach((r,t,e)=>{const o=B();console.log("路由导航:",{to:r.path,from:t.path,requiresAuth:r.meta.requiresAuth,isAuthenticated:o.isAuthenticated}),r.path==="/api-stats"||r.path.startsWith("/api-stats")?e():r.meta.requiresAuth&&!o.isAuthenticated?e("/login"):r.path==="/login"&&o.isAuthenticated?e("/dashboard"):e()});const z=V.apiPrefix;function A(r){return r.startsWith("/")||(r="/"+r),z+r}class pe{constructor(){this.baseURL=z}getAuthToken(){return localStorage.getItem("authToken")||null}buildConfig(t={}){const e={headers:{"Content-Type":"application/json",...t.headers},...t},o=this.getAuthToken();return o&&(e.headers.Authorization=`Bearer ${o}`),e}async handleResponse(t){if(t.status===401){const o=window.location.pathname+window.location.hash;throw o.includes("/login")||o.endsWith("/")||(localStorage.removeItem("authToken"),window.location.href=re()),new Error("Unauthorized")}const e=t.headers.get("content-type");if(e&&e.includes("application/json")){const o=await t.json();if(!t.ok)throw new Error(o.message||`HTTP ${t.status}`);return o}if(!t.ok)throw new Error(`HTTP ${t.status}: ${t.statusText}`);return t}async get(t,e={}){const o=A(t),s=this.buildConfig({...e,method:"GET"});try{const a=await fetch(o,s);return await this.handleResponse(a)}catch(a){throw console.error("API GET Error:",a),a}}async post(t,e=null,o={}){const s=A(t),a=this.buildConfig({...o,method:"POST",body:e?JSON.stringify(e):void 0});try{const n=await fetch(s,a);return await this.handleResponse(n)}catch(n){throw console.error("API POST Error:",n),n}}async put(t,e=null,o={}){const s=A(t),a=this.buildConfig({...o,method:"PUT",body:e?JSON.stringify(e):void 0});try{const n=await fetch(s,a);return await this.handleResponse(n)}catch(n){throw console.error("API PUT Error:",n),n}}async delete(t,e={}){const o=A(t),s=this.buildConfig({...e,method:"DELETE"});try{const a=await fetch(o,s);return await this.handleResponse(a)}catch(a){throw console.error("API DELETE Error:",a),a}}}const k=new pe,B=F("auth",()=>{const r=_(!1),t=_(localStorage.getItem("authToken")||""),e=_(""),o=_(""),s=_(!1),a=_({siteName:"Claude Relay Service",siteIcon:"",siteIconData:"",faviconData:""}),n=_(!0),p=L(()=>!!t.value&&r.value),c=L(()=>t.value),l=L(()=>({username:e.value}));async function d(u){s.value=!0,o.value="";try{const g=await k.post("/web/auth/login",u);g.success?(t.value=g.token,e.value=g.username||u.username,r.value=!0,localStorage.setItem("authToken",g.token),await C.push("/dashboard")):o.value=g.message||"登录失败"}catch(g){o.value=g.message||"登录失败,请检查用户名和密码"}finally{s.value=!1}}function i(){r.value=!1,t.value="",e.value="",localStorage.removeItem("authToken"),C.push("/login")}function m(){t.value&&(r.value=!0,f())}async function f(){try{const u=await k.get("/web/auth/user");u.success&&u.user&&(e.value=u.user.username),(await k.get("/admin/dashboard")).success||i()}catch{i()}}async function v(){n.value=!0;try{const u=await k.get("/admin/oem-settings");if(u.success&&u.data){if(a.value={...a.value,...u.data},u.data.siteIconData||u.data.siteIcon){const g=document.querySelector("link[rel*='icon']")||document.createElement("link");g.type="image/x-icon",g.rel="shortcut icon",g.href=u.data.siteIconData||u.data.siteIcon,document.getElementsByTagName("head")[0].appendChild(g)}u.data.siteName&&(document.title=`${u.data.siteName} - 管理后台`)}}catch(u){console.error("加载OEM设置失败:",u)}finally{n.value=!1}}return{isLoggedIn:r,authToken:t,username:e,loginError:o,loginLoading:s,oemSettings:a,oemLoading:n,isAuthenticated:p,token:c,user:l,login:d,logout:i,checkAuth:m,loadOemSettings:v}}),O=(r,t)=>{const e=r.__vccOpts||r;for(const[o,s]of t)e[o]=s;return e},_e={class:"toast-container"},ge=["onClick"],ve={class:"toast-content"},ye={class:"toast-icon"},we={class:"toast-body"},be={key:0,class:"toast-title"},Te={class:"toast-message"},Ee=["onClick"],Ae={__name:"ToastNotification",setup(r,{expose:t}){const e=_([]);let o=0;const s=l=>{const d={success:"fas fa-check-circle",error:"fas fa-exclamation-circle",warning:"fas fa-exclamation-triangle",info:"fas fa-info-circle"};return d[l]||d.info},a=(l,d="info",i=null,m=5e3)=>{const f=++o,v={id:f,message:l,type:d,title:i,duration:m,isVisible:!1};return e.value.push(v),setTimeout(()=>{v.isVisible=!0},10),m>0&&setTimeout(()=>{n(f)},m),f},n=l=>{const d=e.value.findIndex(i=>i.id===l);if(d>-1){const i=e.value[d];i.isVisible=!1,setTimeout(()=>{const m=e.value.findIndex(f=>f.id===l);m>-1&&e.value.splice(m,1)},300)}},p=()=>{e.value.forEach(l=>{l.isVisible=!1}),setTimeout(()=>{e.value.length=0},300)},c=(l,d="info",i=null,m=5e3)=>a(l,d,i,m);return R(()=>{window.showToast=c}),D(()=>{window.showToast===c&&delete window.showToast}),t({showToast:c,removeToast:n,clearAllToasts:p}),(l,d)=>(y(),q(N,{to:"body"},[h("div",_e,[(y(!0),b(G,null,M(e.value,i=>(y(),b("div",{key:i.id,class:S(["toast",`toast-${i.type}`,i.isVisible?"toast-show":"toast-hide"]),onClick:m=>n(i.id)},[h("div",ve,[h("div",ye,[h("i",{class:S(s(i.type))},null,2)]),h("div",we,[i.title?(y(),b("div",be,T(i.title),1)):x("",!0),h("div",Te,T(i.message),1)]),h("button",{class:"toast-close",onClick:U(m=>n(i.id),["stop"])},d[0]||(d[0]=[h("i",{class:"fas fa-times"},null,-1)]),8,Ee)]),i.duration>0?(y(),b("div",{key:0,class:"toast-progress",style:H({animationDuration:`${i.duration}ms`})},null,4)):x("",!0)],10,ge))),128))])]))}},ke=O(Ae,[["__scopeId","data-v-1a3ab19b"]]),Pe={class:"modal-content w-full max-w-md p-6 mx-auto"},xe={class:"flex items-start gap-4 mb-6"},Ce={class:"flex-1"},Ie={class:"text-lg font-semibold text-gray-900 mb-2"},Le={class:"text-gray-600 leading-relaxed whitespace-pre-line"},Se={class:"flex items-center justify-end gap-3"},Re=["disabled"],Ve=["disabled"],Oe={key:0,class:"loading-spinner mr-2"},$e={__name:"ConfirmDialog",setup(r,{expose:t}){const e=_(!1),o=_(!1),s=_(""),a=_(""),n=_("确认"),p=_("取消");let c=null;const l=(f,v,u="确认",g="取消")=>new Promise(j=>{s.value=f,a.value=v,n.value=u,p.value=g,e.value=!0,o.value=!1,c=j}),d=()=>{o.value||(o.value=!0,setTimeout(()=>{e.value=!1,o.value=!1,c&&(c(!0),c=null)},200))},i=()=>{o.value||(e.value=!1,c&&(c(!1),c=null))},m=f=>{e.value&&(f.key==="Escape"?i():f.key==="Enter"&&!f.shiftKey&&!f.ctrlKey&&!f.altKey&&d())};return R(()=>{window.showConfirm=l,document.addEventListener("keydown",m)}),D(()=>{window.showConfirm===l&&delete window.showConfirm,document.removeEventListener("keydown",m)}),t({showConfirm:l}),(f,v)=>(y(),q(N,{to:"body"},[P(Q,{name:"modal",appear:""},{default:J(()=>[e.value?(y(),b("div",{key:0,class:"fixed inset-0 modal z-[100] flex items-center justify-center p-4",onClick:U(i,["self"])},[h("div",Pe,[h("div",xe,[v[0]||(v[0]=h("div",{class:"flex-shrink-0 w-12 h-12 bg-gradient-to-br from-amber-500 to-amber-600 rounded-xl flex items-center justify-center"},[h("i",{class:"fas fa-exclamation-triangle text-white text-lg"})],-1)),h("div",Ce,[h("h3",Ie,T(s.value),1),h("div",Le,T(a.value),1)])]),h("div",Se,[h("button",{class:"btn bg-gray-100 text-gray-700 hover:bg-gray-200 px-6 py-3",disabled:o.value,onClick:i},T(p.value),9,Re),h("button",{class:S(["btn btn-warning px-6 py-3",{"opacity-50 cursor-not-allowed":o.value}]),disabled:o.value,onClick:d},[o.value?(y(),b("div",Oe)):x("",!0),X(" "+T(n.value),1)],10,Ve)])])])):x("",!0)]),_:1})]))}},De=O($e,[["__scopeId","data-v-bdb20ffd"]]),qe={id:"app"},Ne={__name:"App",setup(r){const t=B(),e=_(),o=_();return R(()=>{t.checkAuth(),t.loadOemSettings()}),(s,a)=>{const n=Y("router-view");return y(),b("div",qe,[P(n),P(ke,{ref_key:"toastRef",ref:e},null,512),P(De,{ref_key:"confirmRef",ref:o},null,512)])}}},Ue=O(Ne,[["__scopeId","data-v-5cba45f5"]]),I=Z(Ue),ze=ee();I.use(ze);I.use(C);I.use(te,{locale:oe});I.mount("#app");export{O as _,k as a,B as u};
+const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/LoginView-BJ0LLv16.js","assets/vue-vendor-CKToUHZx.js","assets/element-plus-B8Fs_0jW.js","assets/vendor-BDiMbLwQ.js","assets/element-plus-CPnoEkWW.css","assets/LoginView-tn0RQdqM.css","assets/LogoTitle-BiOf3Vkp.css","assets/MainLayout-CLydIeqJ.js","assets/toast-BvwA7Mwb.js","assets/LogoTitle-DHj-MjwS.js","assets/MainLayout-tWrOHYRR.css","assets/DashboardView-B_FI7Rf0.js","assets/chart-Cor9iTVD.js","assets/DashboardView-B39lq_zZ.css","assets/ApiKeysView-BwqhkYtq.js","assets/ApiKeysView-DYiCSByq.css","assets/AccountsView-z89aebep.js","assets/AccountsView-CZl79P8u.css","assets/TutorialView-DqKyDtQV.js","assets/TutorialView-BM6fz9TT.css","assets/SettingsView-DicW12bL.js","assets/SettingsView-D9bl7XvV.css","assets/ApiStatsView-CUnItdoW.js","assets/ApiStatsView-C5BOZdu2.css"])))=>i.map(i=>d[i]);
+import{aP as K,aQ as W,aR as F,r as _,c as L,q as R,V as D,I as q,z as h,x as b,ac as M,Q as G,a5 as N,y,C as S,L as x,P as T,Y as U,B as H,R as P,J,T as Q,O as X,av as Y,aM as Z,aS as ee}from"./vue-vendor-CKToUHZx.js";import{i as te,z as oe}from"./element-plus-B8Fs_0jW.js";import"./vendor-BDiMbLwQ.js";(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))o(s);new MutationObserver(s=>{for(const a of s)if(a.type==="childList")for(const n of a.addedNodes)n.tagName==="LINK"&&n.rel==="modulepreload"&&o(n)}).observe(document,{childList:!0,subtree:!0});function e(s){const a={};return s.integrity&&(a.integrity=s.integrity),s.referrerPolicy&&(a.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?a.credentials="include":s.crossOrigin==="anonymous"?a.credentials="omit":a.credentials="same-origin",a}function o(s){if(s.ep)return;s.ep=!0;const a=e(s);fetch(s.href,a)}})();const se="modulepreload",ne=function(r){return"/admin-next/"+r},$={},w=function(t,e,o){let s=Promise.resolve();if(e&&e.length>0){document.getElementsByTagName("link");const n=document.querySelector("meta[property=csp-nonce]"),p=(n==null?void 0:n.nonce)||(n==null?void 0:n.getAttribute("nonce"));s=Promise.allSettled(e.map(c=>{if(c=ne(c),c in $)return;$[c]=!0;const l=c.endsWith(".css"),d=l?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${c}"]${d}`))return;const i=document.createElement("link");if(i.rel=l?"stylesheet":se,l||(i.as="script"),i.crossOrigin="",i.href=c,p&&i.setAttribute("nonce",p),document.head.appendChild(i),l)return new Promise((m,f)=>{i.addEventListener("load",m),i.addEventListener("error",()=>f(new Error(`Unable to preload CSS for ${c}`)))})}))}function a(n){const p=new Event("vite:preloadError",{cancelable:!0});if(p.payload=n,window.dispatchEvent(p),!p.defaultPrevented)throw n}return s.then(n=>{for(const p of n||[])p.status==="rejected"&&a(p.reason);return t().catch(a)})},V={basePath:"/admin-next/",apiPrefix:""};function ae(r=""){return r&&!r.startsWith("/")&&(r="/"+r),V.basePath+(r.startsWith("#")?r:"#"+r)}function re(){return ae("/login")}const ie=()=>w(()=>import("./LoginView-BJ0LLv16.js"),__vite__mapDeps([0,1,2,3,4,5,6])),E=()=>w(()=>import("./MainLayout-CLydIeqJ.js"),__vite__mapDeps([7,1,8,9,6,2,3,4,10])),ce=()=>w(()=>import("./DashboardView-B_FI7Rf0.js"),__vite__mapDeps([11,2,1,3,4,8,12,13])),le=()=>w(()=>import("./ApiKeysView-BwqhkYtq.js"),__vite__mapDeps([14,2,1,3,4,8,15])),ue=()=>w(()=>import("./AccountsView-z89aebep.js"),__vite__mapDeps([16,1,8,2,3,4,17])),de=()=>w(()=>import("./TutorialView-DqKyDtQV.js"),__vite__mapDeps([18,1,2,3,4,19])),fe=()=>w(()=>import("./SettingsView-DicW12bL.js"),__vite__mapDeps([20,1,8,2,3,4,21])),he=()=>w(()=>import("./ApiStatsView-CUnItdoW.js"),__vite__mapDeps([22,1,9,6,3,18,2,4,19,23])),me=[{path:"/",redirect:"/api-stats"},{path:"/login",name:"Login",component:ie,meta:{requiresAuth:!1}},{path:"/api-stats",name:"ApiStats",component:he,meta:{requiresAuth:!1}},{path:"/dashboard",component:E,meta:{requiresAuth:!0},children:[{path:"",name:"Dashboard",component:ce}]},{path:"/api-keys",component:E,meta:{requiresAuth:!0},children:[{path:"",name:"ApiKeys",component:le}]},{path:"/accounts",component:E,meta:{requiresAuth:!0},children:[{path:"",name:"Accounts",component:ue}]},{path:"/tutorial",component:E,meta:{requiresAuth:!0},children:[{path:"",name:"Tutorial",component:de}]},{path:"/settings",component:E,meta:{requiresAuth:!0},children:[{path:"",name:"Settings",component:fe}]}],C=K({history:W(V.basePath),routes:me});C.beforeEach((r,t,e)=>{const o=B();console.log("路由导航:",{to:r.path,from:t.path,requiresAuth:r.meta.requiresAuth,isAuthenticated:o.isAuthenticated}),r.path==="/api-stats"||r.path.startsWith("/api-stats")?e():r.meta.requiresAuth&&!o.isAuthenticated?e("/login"):r.path==="/login"&&o.isAuthenticated?e("/dashboard"):e()});const z=V.apiPrefix;function A(r){return r.startsWith("/")||(r="/"+r),z+r}class pe{constructor(){this.baseURL=z}getAuthToken(){return localStorage.getItem("authToken")||null}buildConfig(t={}){const e={headers:{"Content-Type":"application/json",...t.headers},...t},o=this.getAuthToken();return o&&(e.headers.Authorization=`Bearer ${o}`),e}async handleResponse(t){if(t.status===401){const o=window.location.pathname+window.location.hash;throw o.includes("/login")||o.endsWith("/")||(localStorage.removeItem("authToken"),window.location.href=re()),new Error("Unauthorized")}const e=t.headers.get("content-type");if(e&&e.includes("application/json")){const o=await t.json();if(!t.ok)throw new Error(o.message||`HTTP ${t.status}`);return o}if(!t.ok)throw new Error(`HTTP ${t.status}: ${t.statusText}`);return t}async get(t,e={}){const o=A(t),s=this.buildConfig({...e,method:"GET"});try{const a=await fetch(o,s);return await this.handleResponse(a)}catch(a){throw console.error("API GET Error:",a),a}}async post(t,e=null,o={}){const s=A(t),a=this.buildConfig({...o,method:"POST",body:e?JSON.stringify(e):void 0});try{const n=await fetch(s,a);return await this.handleResponse(n)}catch(n){throw console.error("API POST Error:",n),n}}async put(t,e=null,o={}){const s=A(t),a=this.buildConfig({...o,method:"PUT",body:e?JSON.stringify(e):void 0});try{const n=await fetch(s,a);return await this.handleResponse(n)}catch(n){throw console.error("API PUT Error:",n),n}}async delete(t,e={}){const o=A(t),s=this.buildConfig({...e,method:"DELETE"});try{const a=await fetch(o,s);return await this.handleResponse(a)}catch(a){throw console.error("API DELETE Error:",a),a}}}const k=new pe,B=F("auth",()=>{const r=_(!1),t=_(localStorage.getItem("authToken")||""),e=_(""),o=_(""),s=_(!1),a=_({siteName:"Claude Relay Service",siteIcon:"",siteIconData:"",faviconData:""}),n=_(!0),p=L(()=>!!t.value&&r.value),c=L(()=>t.value),l=L(()=>({username:e.value}));async function d(u){s.value=!0,o.value="";try{const g=await k.post("/web/auth/login",u);g.success?(t.value=g.token,e.value=g.username||u.username,r.value=!0,localStorage.setItem("authToken",g.token),await C.push("/dashboard")):o.value=g.message||"登录失败"}catch(g){o.value=g.message||"登录失败,请检查用户名和密码"}finally{s.value=!1}}function i(){r.value=!1,t.value="",e.value="",localStorage.removeItem("authToken"),C.push("/login")}function m(){t.value&&(r.value=!0,f())}async function f(){try{const u=await k.get("/web/auth/user");u.success&&u.user&&(e.value=u.user.username),(await k.get("/admin/dashboard")).success||i()}catch{i()}}async function v(){n.value=!0;try{const u=await k.get("/admin/oem-settings");if(u.success&&u.data){if(a.value={...a.value,...u.data},u.data.siteIconData||u.data.siteIcon){const g=document.querySelector("link[rel*='icon']")||document.createElement("link");g.type="image/x-icon",g.rel="shortcut icon",g.href=u.data.siteIconData||u.data.siteIcon,document.getElementsByTagName("head")[0].appendChild(g)}u.data.siteName&&(document.title=`${u.data.siteName} - 管理后台`)}}catch(u){console.error("加载OEM设置失败:",u)}finally{n.value=!1}}return{isLoggedIn:r,authToken:t,username:e,loginError:o,loginLoading:s,oemSettings:a,oemLoading:n,isAuthenticated:p,token:c,user:l,login:d,logout:i,checkAuth:m,loadOemSettings:v}}),O=(r,t)=>{const e=r.__vccOpts||r;for(const[o,s]of t)e[o]=s;return e},_e={class:"toast-container"},ge=["onClick"],ve={class:"toast-content"},ye={class:"toast-icon"},we={class:"toast-body"},be={key:0,class:"toast-title"},Te={class:"toast-message"},Ee=["onClick"],Ae={__name:"ToastNotification",setup(r,{expose:t}){const e=_([]);let o=0;const s=l=>{const d={success:"fas fa-check-circle",error:"fas fa-exclamation-circle",warning:"fas fa-exclamation-triangle",info:"fas fa-info-circle"};return d[l]||d.info},a=(l,d="info",i=null,m=5e3)=>{const f=++o,v={id:f,message:l,type:d,title:i,duration:m,isVisible:!1};return e.value.push(v),setTimeout(()=>{v.isVisible=!0},10),m>0&&setTimeout(()=>{n(f)},m),f},n=l=>{const d=e.value.findIndex(i=>i.id===l);if(d>-1){const i=e.value[d];i.isVisible=!1,setTimeout(()=>{const m=e.value.findIndex(f=>f.id===l);m>-1&&e.value.splice(m,1)},300)}},p=()=>{e.value.forEach(l=>{l.isVisible=!1}),setTimeout(()=>{e.value.length=0},300)},c=(l,d="info",i=null,m=5e3)=>a(l,d,i,m);return R(()=>{window.showToast=c}),D(()=>{window.showToast===c&&delete window.showToast}),t({showToast:c,removeToast:n,clearAllToasts:p}),(l,d)=>(y(),q(N,{to:"body"},[h("div",_e,[(y(!0),b(G,null,M(e.value,i=>(y(),b("div",{key:i.id,class:S(["toast",`toast-${i.type}`,i.isVisible?"toast-show":"toast-hide"]),onClick:m=>n(i.id)},[h("div",ve,[h("div",ye,[h("i",{class:S(s(i.type))},null,2)]),h("div",we,[i.title?(y(),b("div",be,T(i.title),1)):x("",!0),h("div",Te,T(i.message),1)]),h("button",{class:"toast-close",onClick:U(m=>n(i.id),["stop"])},d[0]||(d[0]=[h("i",{class:"fas fa-times"},null,-1)]),8,Ee)]),i.duration>0?(y(),b("div",{key:0,class:"toast-progress",style:H({animationDuration:`${i.duration}ms`})},null,4)):x("",!0)],10,ge))),128))])]))}},ke=O(Ae,[["__scopeId","data-v-1a3ab19b"]]),Pe={class:"modal-content w-full max-w-md p-6 mx-auto"},xe={class:"flex items-start gap-4 mb-6"},Ce={class:"flex-1"},Ie={class:"text-lg font-semibold text-gray-900 mb-2"},Le={class:"text-gray-600 leading-relaxed whitespace-pre-line"},Se={class:"flex items-center justify-end gap-3"},Re=["disabled"],Ve=["disabled"],Oe={key:0,class:"loading-spinner mr-2"},$e={__name:"ConfirmDialog",setup(r,{expose:t}){const e=_(!1),o=_(!1),s=_(""),a=_(""),n=_("确认"),p=_("取消");let c=null;const l=(f,v,u="确认",g="取消")=>new Promise(j=>{s.value=f,a.value=v,n.value=u,p.value=g,e.value=!0,o.value=!1,c=j}),d=()=>{o.value||(o.value=!0,setTimeout(()=>{e.value=!1,o.value=!1,c&&(c(!0),c=null)},200))},i=()=>{o.value||(e.value=!1,c&&(c(!1),c=null))},m=f=>{e.value&&(f.key==="Escape"?i():f.key==="Enter"&&!f.shiftKey&&!f.ctrlKey&&!f.altKey&&d())};return R(()=>{window.showConfirm=l,document.addEventListener("keydown",m)}),D(()=>{window.showConfirm===l&&delete window.showConfirm,document.removeEventListener("keydown",m)}),t({showConfirm:l}),(f,v)=>(y(),q(N,{to:"body"},[P(Q,{name:"modal",appear:""},{default:J(()=>[e.value?(y(),b("div",{key:0,class:"fixed inset-0 modal z-[100] flex items-center justify-center p-4",onClick:U(i,["self"])},[h("div",Pe,[h("div",xe,[v[0]||(v[0]=h("div",{class:"flex-shrink-0 w-12 h-12 bg-gradient-to-br from-amber-500 to-amber-600 rounded-xl flex items-center justify-center"},[h("i",{class:"fas fa-exclamation-triangle text-white text-lg"})],-1)),h("div",Ce,[h("h3",Ie,T(s.value),1),h("div",Le,T(a.value),1)])]),h("div",Se,[h("button",{class:"btn bg-gray-100 text-gray-700 hover:bg-gray-200 px-6 py-3",disabled:o.value,onClick:i},T(p.value),9,Re),h("button",{class:S(["btn btn-warning px-6 py-3",{"opacity-50 cursor-not-allowed":o.value}]),disabled:o.value,onClick:d},[o.value?(y(),b("div",Oe)):x("",!0),X(" "+T(n.value),1)],10,Ve)])])])):x("",!0)]),_:1})]))}},De=O($e,[["__scopeId","data-v-bdb20ffd"]]),qe={id:"app"},Ne={__name:"App",setup(r){const t=B(),e=_(),o=_();return R(()=>{t.checkAuth(),t.loadOemSettings()}),(s,a)=>{const n=Y("router-view");return y(),b("div",qe,[P(n),P(ke,{ref_key:"toastRef",ref:e},null,512),P(De,{ref_key:"confirmRef",ref:o},null,512)])}}},Ue=O(Ne,[["__scopeId","data-v-5cba45f5"]]),I=Z(Ue),ze=ee();I.use(ze);I.use(C);I.use(te,{locale:oe});I.mount("#app");export{O as _,k as a,B as u};
diff --git a/web/admin-spa/dist/index.html b/web/admin-spa/dist/index.html
index fb16d27d..2df537fc 100644
--- a/web/admin-spa/dist/index.html
+++ b/web/admin-spa/dist/index.html
@@ -18,7 +18,7 @@
-
+