mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-22 16:43:35 +00:00
10 lines
70 KiB
JavaScript
10 lines
70 KiB
JavaScript
import{E as St}from"./element-plus-B8Fs_0jW.js";import{aR as gt,r as C,c as et,_ as rt,q as dt,I as H,y as i,z as t,Y as X,K as $,x as a,L as A,O as y,aq as j,C as W,P as c,Q as E,ac as V,aa as ot,aX as G,an as Z,al as tt,a5 as nt,R as Tt,B as _t}from"./vue-vendor-CKToUHZx.js";import{s as T}from"./toast-BvwA7Mwb.js";import{a as U,_ as st,u as yt}from"./index-Ch5822Og.js";import"./vendor-BDiMbLwQ.js";const ut=gt("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 k=await U.get("/admin/supported-clients");return k.success?this.supportedClients=k.data||[]:(this.error=k.message||"加载支持的客户端失败",console.error("Failed to load supported clients:",this.error)),this.supportedClients}catch(k){return this.error=k.message||"加载支持的客户端失败",console.error("Error loading supported clients:",k),[]}finally{this.loading=!1}}}}),bt=gt("apiKeys",()=>{const k=C([]),R=C(!1),x=C(null),P=C("all"),M=C(""),g=C("asc"),h=async()=>{R.value=!0,x.value=null;try{const v=await U.get("/admin/api-keys");if(v.success)k.value=v.data||[];else throw new Error(v.message||"获取API Keys失败")}catch(v){throw x.value=v.message,v}finally{R.value=!1}};return{apiKeys:k,loading:R,error:x,statsTimeRange:P,sortBy:M,sortOrder:g,fetchApiKeys:h,createApiKey:async v=>{R.value=!0,x.value=null;try{const I=await U.post("/admin/api-keys",v);if(I.success)return await h(),I.data;throw new Error(I.message||"创建API Key失败")}catch(I){throw x.value=I.message,I}finally{R.value=!1}},updateApiKey:async(v,I)=>{R.value=!0,x.value=null;try{const f=await U.put(`/admin/api-keys/${v}`,I);if(f.success)return await h(),f;throw new Error(f.message||"更新API Key失败")}catch(f){throw x.value=f.message,f}finally{R.value=!1}},toggleApiKey:async v=>{R.value=!0,x.value=null;try{const I=await U.put(`/admin/api-keys/${v}/toggle`);if(I.success)return await h(),I;throw new Error(I.message||"切换状态失败")}catch(I){throw x.value=I.message,I}finally{R.value=!1}},renewApiKey:async(v,I)=>{R.value=!0,x.value=null;try{const f=await U.put(`/admin/api-keys/${v}/renew`,I);if(f.success)return await h(),f;throw new Error(f.message||"续期失败")}catch(f){throw x.value=f.message,f}finally{R.value=!1}},deleteApiKey:async v=>{R.value=!0,x.value=null;try{const I=await U.delete(`/admin/api-keys/${v}`);if(I.success)return await h(),I;throw new Error(I.message||"删除失败")}catch(I){throw x.value=I.message,I}finally{R.value=!1}},fetchApiKeyStats:async(v,I="all")=>{try{const f=await U.get(`/admin/api-keys/${v}/stats`,{params:{timeRange:I}});if(f.success)return f.stats;throw new Error(f.message||"获取统计失败")}catch(f){return console.error("获取API Key统计失败:",f),null}},fetchTags:async()=>{try{const v=await U.get("/admin/api-keys/tags");if(v.success)return v.data||[];throw new Error(v.message||"获取标签失败")}catch(v){return console.error("获取标签失败:",v),[]}},sortApiKeys:v=>{M.value===v?g.value=g.value==="asc"?"desc":"asc":(M.value=v,g.value="asc")},reset:()=>{k.value=[],R.value=!1,x.value=null,P.value="all",M.value="",g.value="asc"}}}),Et={class:"fixed inset-0 modal z-50 flex items-center justify-center p-4"},Pt={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"},oe={class:"flex items-center cursor-pointer"},ne={class:"flex items-center cursor-pointer"},ie={class:"grid grid-cols-1 gap-3"},ae=["disabled"],re={key:0,label:"Claude OAuth 账号"},de=["value"],ue={key:1,label:"Claude Console 账号"},ce=["value"],me=["disabled"],pe=["value"],xe={class:"flex items-center mb-2"},fe={key:0,class:"space-y-2 bg-red-50 border border-red-200 rounded-lg p-3"},ge={class:"flex flex-wrap gap-1 mb-2 min-h-[24px]"},ye=["onClick"],be={key:0,class:"text-gray-400 text-xs"},ve={class:"flex gap-2"},we=["onKeydown"],Ae={class:"flex items-center mb-2"},$e={key:0,class:"bg-green-50 border border-green-200 rounded-lg p-3"},Ce={class:"space-y-1"},Ke=["id","value"],ke=["for"],he={class:"text-sm font-medium text-gray-700"},Ie={class:"text-xs text-gray-500 block"},De={class:"flex gap-3 pt-2"},Le=["disabled"],Re={key:0,class:"loading-spinner mr-2"},Me={key:1,class:"fas fa-plus mr-2"},Se={__name:"CreateApiKeyModal",props:{accounts:{type:Object,default:()=>({claude:[],gemini:[]})}},emits:["close","success"],setup(k,{emit:R}){const x=R;yt();const P=ut(),M=bt(),g=C(!1),h=C({name:""}),_=C(""),K=C([]),O=et(()=>K.value.filter(b=>!e.tags.includes(b))),D=C([]),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()=>{D.value=await P.loadSupportedClients(),K.value=await M.fetchTags()});const w=et(()=>{const b=new Date;return b.setMinutes(b.getMinutes()+1),b.toISOString().slice(0,16)}),q=()=>{if(!e.expireDuration){e.expiresAt=null;return}if(e.expireDuration==="custom")return;const b=new Date,r=e.expireDuration.match(/(\d+)([dhmy])/);if(r){const[,L,Q]=r,J=parseInt(L);switch(Q){case"d":b.setDate(b.getDate()+J);break;case"h":b.setHours(b.getHours()+J);break;case"m":b.setMonth(b.getMonth()+J);break;case"y":b.setFullYear(b.getFullYear()+J);break}e.expiresAt=b.toISOString()}},Y=()=>{e.customExpireDate&&(e.expiresAt=new Date(e.customExpireDate).toISOString())},N=b=>new Date(b).toLocaleString("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"}),v=()=>{e.modelInput&&!e.restrictedModels.includes(e.modelInput)&&(e.restrictedModels.push(e.modelInput),e.modelInput="")},I=b=>{e.restrictedModels.splice(b,1)},f=()=>{if(_.value&&_.value.trim()){const b=_.value.trim();e.tags.includes(b)||e.tags.push(b),_.value=""}},n=b=>{e.tags.includes(b)||e.tags.push(b)},u=b=>{e.tags.splice(b,1)},z=async()=>{if(h.value.name="",!e.name||!e.name.trim()){h.value.name="请输入API Key名称";return}g.value=!0;try{const b={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,tags:e.tags.length>0?e.tags:void 0};e.claudeAccountId&&(e.claudeAccountId.startsWith("console:")?b.claudeConsoleAccountId=e.claudeAccountId.substring(8):b.claudeAccountId=e.claudeAccountId),e.geminiAccountId&&(b.geminiAccountId=e.geminiAccountId),b.enableModelRestriction=e.enableModelRestriction,b.restrictedModels=e.restrictedModels,b.enableClientRestriction=e.enableClientRestriction,b.allowedClients=e.allowedClients;const o=await U.post("/admin/api-keys",b);o.success?(T("API Key 创建成功","success"),x("success",o.data),x("close")):T(o.message||"创建失败","error")}catch{T("创建失败","error")}finally{g.value=!1}};return(b,o)=>(i(),H(nt,{to:"body"},[t("div",Et,[t("div",Pt,[t("div",Vt,[o[27]||(o[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:o[0]||(o[0]=r=>b.$emit("close"))},o[26]||(o[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:X(z,["prevent"])},[t("div",null,[o[28]||(o[28]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},[y("名称 "),t("span",{class:"text-red-500"},"*")],-1)),$(t("input",{"onUpdate:modelValue":o[1]||(o[1]=r=>e.name=r),type:"text",required:"",class:W(["form-input w-full",{"border-red-500":h.value.name}]),placeholder:"为您的 API Key 取一个名称",onInput:o[2]||(o[2]=r=>h.value.name="")},null,34),[[j,e.name]]),h.value.name?(i(),a("p",jt,c(h.value.name),1)):A("",!0)]),t("div",null,[o[36]||(o[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,[o[30]||(o[30]=t("div",{class:"text-xs font-medium text-gray-600 mb-2"}," 已选择的标签: ",-1)),t("div",Ot,[(i(!0),a(E,null,V(e.tags,(r,L)=>(i(),a("span",{key:"selected-"+L,class:"inline-flex items-center gap-1 px-3 py-1 bg-blue-100 text-blue-800 text-sm rounded-full"},[y(c(r)+" ",1),t("button",{type:"button",class:"ml-1 hover:text-blue-900",onClick:Q=>u(L)},o[29]||(o[29]=[t("i",{class:"fas fa-times text-xs"},null,-1)]),8,Ft)]))),128))])])):A("",!0),O.value.length>0?(i(),a("div",Wt,[o[32]||(o[32]=t("div",{class:"text-xs font-medium text-gray-600 mb-2"}," 点击选择已有标签: ",-1)),t("div",Yt,[(i(!0),a(E,null,V(O.value,r=>(i(),a("button",{key:"available-"+r,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:L=>n(r)},[o[31]||(o[31]=t("i",{class:"fas fa-tag text-gray-500 text-xs"},null,-1)),y(" "+c(r),1)],8,zt))),128))])])):A("",!0),t("div",null,[o[34]||(o[34]=t("div",{class:"text-xs font-medium text-gray-600 mb-2"}," 创建新标签: ",-1)),t("div",Nt,[$(t("input",{"onUpdate:modelValue":o[3]||(o[3]=r=>_.value=r),type:"text",class:"form-input flex-1",placeholder:"输入新标签名称",onKeypress:ot(X(f,["prevent"]),["enter"])},null,40,Bt),[[j,_.value]]),t("button",{type:"button",class:"px-4 py-2 bg-green-500 text-white rounded-lg hover:bg-green-600 transition-colors",onClick:f},o[33]||(o[33]=[t("i",{class:"fas fa-plus"},null,-1)]))])]),o[35]||(o[35]=t("p",{class:"text-xs text-gray-500"}," 用于标记不同团队或用途,方便筛选管理 ",-1))])]),t("div",Ht,[o[44]||(o[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,[o[37]||(o[37]=t("label",{class:"block text-xs font-medium text-gray-700 mb-1"},"时间窗口 (分钟)",-1)),$(t("input",{"onUpdate:modelValue":o[4]||(o[4]=r=>e.rateLimitWindow=r),type:"number",min:"1",placeholder:"无限制",class:"form-input w-full text-sm"},null,512),[[j,e.rateLimitWindow]]),o[38]||(o[38]=t("p",{class:"text-xs text-gray-500 mt-0.5 ml-2"}," 时间段单位 ",-1))]),t("div",null,[o[39]||(o[39]=t("label",{class:"block text-xs font-medium text-gray-700 mb-1"},"请求次数限制",-1)),$(t("input",{"onUpdate:modelValue":o[5]||(o[5]=r=>e.rateLimitRequests=r),type:"number",min:"1",placeholder:"无限制",class:"form-input w-full text-sm"},null,512),[[j,e.rateLimitRequests]]),o[40]||(o[40]=t("p",{class:"text-xs text-gray-500 mt-0.5 ml-2"}," 窗口内最大请求 ",-1))]),t("div",null,[o[41]||(o[41]=t("label",{class:"block text-xs font-medium text-gray-700 mb-1"},"Token 限制",-1)),$(t("input",{"onUpdate:modelValue":o[6]||(o[6]=r=>e.tokenLimit=r),type:"number",placeholder:"无限制",class:"form-input w-full text-sm"},null,512),[[j,e.tokenLimit]]),o[42]||(o[42]=t("p",{class:"text-xs text-gray-500 mt-0.5 ml-2"}," 窗口内最大Token ",-1))])]),o[43]||(o[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:"),y(" 时间窗口=60,请求次数=1000 → 每60分钟最多1000次请求")]),t("div",null,[t("strong",null,"示例2:"),y(" 时间窗口=1,Token=10000 → 每分钟最多10,000个Token")]),t("div",null,[t("strong",null,"示例3:"),y(" 窗口=30,请求=50,Token=100000 → 每30分钟50次请求且不超10万Token")])])],-1))])]),t("div",null,[o[46]||(o[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:o[7]||(o[7]=r=>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:o[8]||(o[8]=r=>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:o[9]||(o[9]=r=>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:o[10]||(o[10]=r=>e.dailyCostLimit="")}," 自定义 ")]),$(t("input",{"onUpdate:modelValue":o[11]||(o[11]=r=>e.dailyCostLimit=r),type:"number",min:"0",step:"0.01",placeholder:"0 表示无限制",class:"form-input w-full"},null,512),[[j,e.dailyCostLimit]]),o[45]||(o[45]=t("p",{class:"text-xs text-gray-500"}," 设置此 API Key 每日的费用限制,超过限制将拒绝请求,0 或留空表示无限制 ",-1))])]),t("div",null,[o[47]||(o[47]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},"并发限制 (可选)",-1)),$(t("input",{"onUpdate:modelValue":o[12]||(o[12]=r=>e.concurrencyLimit=r),type:"number",min:"0",placeholder:"0 表示无限制",class:"form-input w-full"},null,512),[[j,e.concurrencyLimit]]),o[48]||(o[48]=t("p",{class:"text-xs text-gray-500 mt-2"}," 设置此 API Key 可同时处理的最大请求数,0 或留空表示无限制 ",-1))]),t("div",null,[o[49]||(o[49]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},"备注 (可选)",-1)),$(t("textarea",{"onUpdate:modelValue":o[13]||(o[13]=r=>e.description=r),rows:"2",class:"form-input w-full resize-none text-sm",placeholder:"描述此 API Key 的用途..."},null,512),[[j,e.description]])]),t("div",null,[o[51]||(o[51]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},"有效期限",-1)),$(t("select",{"onUpdate:modelValue":o[14]||(o[14]=r=>e.expireDuration=r),class:"form-input w-full",onChange:q},o[50]||(o[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),[[G,e.expireDuration]]),e.expireDuration==="custom"?(i(),a("div",Zt,[$(t("input",{"onUpdate:modelValue":o[15]||(o[15]=r=>e.customExpireDate=r),type:"datetime-local",class:"form-input w-full",min:w.value,onChange:Y},null,40,te),[[j,e.customExpireDate]])])):A("",!0),e.expiresAt?(i(),a("p",ee," 将于 "+c(N(e.expiresAt))+" 过期 ",1)):A("",!0)]),t("div",null,[o[55]||(o[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":o[16]||(o[16]=r=>e.permissions=r),type:"radio",value:"all",class:"mr-2"},null,512),[[Z,e.permissions]]),o[52]||(o[52]=t("span",{class:"text-sm text-gray-700"},"全部服务",-1))]),t("label",oe,[$(t("input",{"onUpdate:modelValue":o[17]||(o[17]=r=>e.permissions=r),type:"radio",value:"claude",class:"mr-2"},null,512),[[Z,e.permissions]]),o[53]||(o[53]=t("span",{class:"text-sm text-gray-700"},"仅 Claude",-1))]),t("label",ne,[$(t("input",{"onUpdate:modelValue":o[18]||(o[18]=r=>e.permissions=r),type:"radio",value:"gemini",class:"mr-2"},null,512),[[Z,e.permissions]]),o[54]||(o[54]=t("span",{class:"text-sm text-gray-700"},"仅 Gemini",-1))])]),o[56]||(o[56]=t("p",{class:"text-xs text-gray-500 mt-2"}," 控制此 API Key 可以访问哪些服务 ",-1))]),t("div",null,[o[61]||(o[61]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},"专属账号绑定 (可选)",-1)),t("div",ie,[t("div",null,[o[58]||(o[58]=t("label",{class:"block text-sm font-medium text-gray-600 mb-1"},"Claude 专属账号",-1)),$(t("select",{"onUpdate:modelValue":o[19]||(o[19]=r=>e.claudeAccountId=r),class:"form-input w-full",disabled:e.permissions==="gemini"},[o[57]||(o[57]=t("option",{value:""}," 使用共享账号池 ",-1)),k.accounts.claude.filter(r=>r.isDedicated&&r.platform==="claude-oauth").length>0?(i(),a("optgroup",re,[(i(!0),a(E,null,V(k.accounts.claude.filter(r=>r.isDedicated&&r.platform==="claude-oauth"),r=>(i(),a("option",{key:r.id,value:r.id},c(r.name)+" ("+c(r.status==="active"?"正常":"异常")+") ",9,de))),128))])):A("",!0),k.accounts.claude.filter(r=>r.isDedicated&&r.platform==="claude-console").length>0?(i(),a("optgroup",ue,[(i(!0),a(E,null,V(k.accounts.claude.filter(r=>r.isDedicated&&r.platform==="claude-console"),r=>(i(),a("option",{key:r.id,value:`console:${r.id}`},c(r.name)+" ("+c(r.status==="active"?"正常":"异常")+") ",9,ce))),128))])):A("",!0)],8,ae),[[G,e.claudeAccountId]])]),t("div",null,[o[60]||(o[60]=t("label",{class:"block text-sm font-medium text-gray-600 mb-1"},"Gemini 专属账号",-1)),$(t("select",{"onUpdate:modelValue":o[20]||(o[20]=r=>e.geminiAccountId=r),class:"form-input w-full",disabled:e.permissions==="claude"},[o[59]||(o[59]=t("option",{value:""}," 使用共享账号池 ",-1)),(i(!0),a(E,null,V(k.accounts.gemini.filter(r=>r.isDedicated),r=>(i(),a("option",{key:r.id,value:r.id},c(r.name)+" ("+c(r.status==="active"?"正常":"异常")+") ",9,pe))),128))],8,me),[[G,e.geminiAccountId]])])]),o[62]||(o[62]=t("p",{class:"text-xs text-gray-500 mt-2"}," 选择专属账号后,此API Key将只使用该账号,不选择则使用共享账号池 ",-1))]),t("div",null,[t("div",xe,[$(t("input",{id:"enableModelRestriction","onUpdate:modelValue":o[21]||(o[21]=r=>e.enableModelRestriction=r),type:"checkbox",class:"w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500"},null,512),[[tt,e.enableModelRestriction]]),o[63]||(o[63]=t("label",{for:"enableModelRestriction",class:"ml-2 text-sm font-semibold text-gray-700 cursor-pointer"}," 启用模型限制 ",-1))]),e.enableModelRestriction?(i(),a("div",fe,[t("div",null,[o[66]||(o[66]=t("label",{class:"block text-xs font-medium text-gray-700 mb-1"},"限制的模型列表",-1)),t("div",ge,[(i(!0),a(E,null,V(e.restrictedModels,(r,L)=>(i(),a("span",{key:L,class:"inline-flex items-center px-2 py-1 rounded-full text-xs bg-red-100 text-red-800"},[y(c(r)+" ",1),t("button",{type:"button",class:"ml-1 text-red-600 hover:text-red-800",onClick:Q=>I(L)},o[64]||(o[64]=[t("i",{class:"fas fa-times text-xs"},null,-1)]),8,ye)]))),128)),e.restrictedModels.length===0?(i(),a("span",be," 暂无限制的模型 ")):A("",!0)]),t("div",ve,[$(t("input",{"onUpdate:modelValue":o[22]||(o[22]=r=>e.modelInput=r),type:"text",placeholder:"输入模型名称,按回车添加",class:"form-input flex-1 text-sm",onKeydown:ot(X(v,["prevent"]),["enter"])},null,40,we),[[j,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:v},o[65]||(o[65]=[t("i",{class:"fas fa-plus"},null,-1)]))]),o[67]||(o[67]=t("p",{class:"text-xs text-gray-500 mt-1"}," 例如:claude-opus-4-20250514 ",-1))])])):A("",!0)]),t("div",null,[t("div",Ae,[$(t("input",{id:"enableClientRestriction","onUpdate:modelValue":o[23]||(o[23]=r=>e.enableClientRestriction=r),type:"checkbox",class:"w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500"},null,512),[[tt,e.enableClientRestriction]]),o[68]||(o[68]=t("label",{for:"enableClientRestriction",class:"ml-2 text-sm font-semibold text-gray-700 cursor-pointer"}," 启用客户端限制 ",-1))]),e.enableClientRestriction?(i(),a("div",$e,[t("div",null,[o[69]||(o[69]=t("label",{class:"block text-xs font-medium text-gray-700 mb-2"},"允许的客户端",-1)),t("div",Ce,[(i(!0),a(E,null,V(D.value,r=>(i(),a("div",{key:r.id,class:"flex items-start"},[$(t("input",{id:`client_${r.id}`,"onUpdate:modelValue":o[24]||(o[24]=L=>e.allowedClients=L),type:"checkbox",value:r.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,Ke),[[tt,e.allowedClients]]),t("label",{for:`client_${r.id}`,class:"ml-2 flex-1 cursor-pointer"},[t("span",he,c(r.name),1),t("span",Ie,c(r.description),1)],8,ke)]))),128))])])])):A("",!0)]),t("div",De,[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:o[25]||(o[25]=r=>b.$emit("close"))}," 取消 "),t("button",{type:"submit",disabled:g.value,class:"btn btn-primary flex-1 py-2.5 px-4 font-semibold text-sm"},[g.value?(i(),a("div",Re)):(i(),a("i",Me)),y(" "+c(g.value?"创建中...":"创建"),1)],8,Le)])],32)])])]))}},Te=st(Se,[["__scopeId","data-v-6f63995d"]]),_e={class:"fixed inset-0 modal z-50 flex items-center justify-center p-4"},Ee={class:"modal-content w-full max-w-4xl p-8 mx-auto max-h-[90vh] flex flex-col"},Pe={class:"flex items-center justify-between mb-6"},Ve=["value"],je={class:"space-y-4"},Ue={key:0},qe={class:"flex flex-wrap gap-2"},Oe=["onClick"],Fe={key:1},We={class:"flex flex-wrap gap-2"},Ye=["onClick"],ze={class:"flex gap-2"},Ne=["onKeypress"],Be={class:"bg-blue-50 border border-blue-200 rounded-lg p-3"},He={class:"space-y-2"},Ge={class:"grid grid-cols-1 lg:grid-cols-3 gap-2"},Qe={class:"space-y-3"},Xe={class:"flex gap-2"},Je={class:"flex gap-4"},Ze={class:"flex items-center cursor-pointer"},ts={class:"flex items-center cursor-pointer"},es={class:"flex items-center cursor-pointer"},ss={class:"grid grid-cols-1 gap-3"},ls=["disabled"],os={key:0,label:"Claude OAuth 账号"},ns=["value"],is={key:1,label:"Claude Console 账号"},as=["value"],rs=["disabled"],ds=["value"],us={class:"flex items-center mb-3"},cs={key:0,class:"space-y-3"},ms={class:"flex flex-wrap gap-2 mb-3 min-h-[32px] p-2 bg-gray-50 rounded-lg border border-gray-200"},ps=["onClick"],xs={key:0,class:"text-gray-400 text-sm"},fs={class:"flex gap-2"},gs=["onKeydown"],ys={class:"flex items-center mb-3"},bs={key:0,class:"space-y-3"},vs={class:"space-y-2"},ws=["id","value"],As=["for"],$s={class:"text-sm font-medium text-gray-700"},Cs={class:"text-xs text-gray-500 block"},Ks={class:"flex gap-3 pt-4"},ks=["disabled"],hs={key:0,class:"loading-spinner mr-2"},Is={key:1,class:"fas fa-save mr-2"},Ds={__name:"EditApiKeyModal",props:{apiKey:{type:Object,required:!0},accounts:{type:Object,default:()=>({claude:[],gemini:[]})}},emits:["close","success"],setup(k,{emit:R}){const x=k,P=R,M=ut(),g=bt(),h=C(!1),_=C([]),K=C(""),O=C([]),D=et(()=>O.value.filter(f=>!e.tags.includes(f))),e=rt({name:"",tokenLimit:"",rateLimitWindow:"",rateLimitRequests:"",concurrencyLimit:"",dailyCostLimit:"",permissions:"all",claudeAccountId:"",geminiAccountId:"",enableModelRestriction:!1,restrictedModels:[],modelInput:"",enableClientRestriction:!1,allowedClients:[],tags:[]}),w=()=>{e.modelInput&&!e.restrictedModels.includes(e.modelInput)&&(e.restrictedModels.push(e.modelInput),e.modelInput="")},q=f=>{e.restrictedModels.splice(f,1)},Y=()=>{if(K.value&&K.value.trim()){const f=K.value.trim();e.tags.includes(f)||e.tags.push(f),K.value=""}},N=f=>{e.tags.includes(f)||e.tags.push(f)},v=f=>{e.tags.splice(f,1)},I=async()=>{h.value=!0;try{const f={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,tags:e.tags};f.enableModelRestriction=e.enableModelRestriction,f.restrictedModels=e.restrictedModels,f.enableClientRestriction=e.enableClientRestriction,f.allowedClients=e.allowedClients,e.claudeAccountId?e.claudeAccountId.startsWith("console:")?(f.claudeConsoleAccountId=e.claudeAccountId.substring(8),f.claudeAccountId=null):(f.claudeAccountId=e.claudeAccountId,f.claudeConsoleAccountId=null):(f.claudeAccountId=null,f.claudeConsoleAccountId=null),f.geminiAccountId=e.geminiAccountId||null;const n=await U.put(`/admin/api-keys/${x.apiKey.id}`,f);n.success?(P("success"),P("close")):T(n.message||"更新失败","error")}catch{T("更新失败","error")}finally{h.value=!1}};return dt(async()=>{_.value=await M.loadSupportedClients(),O.value=await g.fetchTags(),e.name=x.apiKey.name,e.tokenLimit=x.apiKey.tokenLimit||"",e.rateLimitWindow=x.apiKey.rateLimitWindow||"",e.rateLimitRequests=x.apiKey.rateLimitRequests||"",e.concurrencyLimit=x.apiKey.concurrencyLimit||"",e.dailyCostLimit=x.apiKey.dailyCostLimit||"",e.permissions=x.apiKey.permissions||"all",x.apiKey.claudeAccountId?e.claudeAccountId=x.apiKey.claudeAccountId:x.apiKey.claudeConsoleAccountId?e.claudeAccountId=`console:${x.apiKey.claudeConsoleAccountId}`:e.claudeAccountId="",e.geminiAccountId=x.apiKey.geminiAccountId||"",e.restrictedModels=x.apiKey.restrictedModels||[],e.allowedClients=x.apiKey.allowedClients||[],e.tags=x.apiKey.tags||[],e.enableModelRestriction=x.apiKey.enableModelRestriction||!1,e.enableClientRestriction=x.apiKey.enableClientRestriction||!1}),(f,n)=>(i(),H(nt,{to:"body"},[t("div",_e,[t("div",Ee,[t("div",Pe,[n[22]||(n[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:n[0]||(n[0]=u=>f.$emit("close"))},n[21]||(n[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:X(I,["prevent"])},[t("div",null,[n[23]||(n[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,Ve),n[24]||(n[24]=t("p",{class:"text-xs text-gray-500 mt-2"}," 名称不可修改 ",-1))]),t("div",null,[n[32]||(n[32]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"标签",-1)),t("div",je,[e.tags.length>0?(i(),a("div",Ue,[n[26]||(n[26]=t("div",{class:"text-xs font-medium text-gray-600 mb-2"}," 已选择的标签: ",-1)),t("div",qe,[(i(!0),a(E,null,V(e.tags,(u,z)=>(i(),a("span",{key:"selected-"+z,class:"inline-flex items-center gap-1 px-3 py-1 bg-blue-100 text-blue-800 text-sm rounded-full"},[y(c(u)+" ",1),t("button",{type:"button",class:"ml-1 hover:text-blue-900",onClick:b=>v(z)},n[25]||(n[25]=[t("i",{class:"fas fa-times text-xs"},null,-1)]),8,Oe)]))),128))])])):A("",!0),D.value.length>0?(i(),a("div",Fe,[n[28]||(n[28]=t("div",{class:"text-xs font-medium text-gray-600 mb-2"}," 点击选择已有标签: ",-1)),t("div",We,[(i(!0),a(E,null,V(D.value,u=>(i(),a("button",{key:"available-"+u,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:z=>N(u)},[n[27]||(n[27]=t("i",{class:"fas fa-tag text-gray-500 text-xs"},null,-1)),y(" "+c(u),1)],8,Ye))),128))])])):A("",!0),t("div",null,[n[30]||(n[30]=t("div",{class:"text-xs font-medium text-gray-600 mb-2"}," 创建新标签: ",-1)),t("div",ze,[$(t("input",{"onUpdate:modelValue":n[1]||(n[1]=u=>K.value=u),type:"text",class:"form-input flex-1",placeholder:"输入新标签名称",onKeypress:ot(X(Y,["prevent"]),["enter"])},null,40,Ne),[[j,K.value]]),t("button",{type:"button",class:"px-4 py-2 bg-green-500 text-white rounded-lg hover:bg-green-600 transition-colors",onClick:Y},n[29]||(n[29]=[t("i",{class:"fas fa-plus"},null,-1)]))])]),n[31]||(n[31]=t("p",{class:"text-xs text-gray-500"}," 用于标记不同团队或用途,方便筛选管理 ",-1))])]),t("div",Be,[n[40]||(n[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",He,[t("div",Ge,[t("div",null,[n[33]||(n[33]=t("label",{class:"block text-xs font-medium text-gray-700 mb-1"},"时间窗口 (分钟)",-1)),$(t("input",{"onUpdate:modelValue":n[2]||(n[2]=u=>e.rateLimitWindow=u),type:"number",min:"1",placeholder:"无限制",class:"form-input w-full text-sm"},null,512),[[j,e.rateLimitWindow]]),n[34]||(n[34]=t("p",{class:"text-xs text-gray-500 mt-0.5 ml-2"}," 时间段单位 ",-1))]),t("div",null,[n[35]||(n[35]=t("label",{class:"block text-xs font-medium text-gray-700 mb-1"},"请求次数限制",-1)),$(t("input",{"onUpdate:modelValue":n[3]||(n[3]=u=>e.rateLimitRequests=u),type:"number",min:"1",placeholder:"无限制",class:"form-input w-full text-sm"},null,512),[[j,e.rateLimitRequests]]),n[36]||(n[36]=t("p",{class:"text-xs text-gray-500 mt-0.5 ml-2"}," 窗口内最大请求 ",-1))]),t("div",null,[n[37]||(n[37]=t("label",{class:"block text-xs font-medium text-gray-700 mb-1"},"Token 限制",-1)),$(t("input",{"onUpdate:modelValue":n[4]||(n[4]=u=>e.tokenLimit=u),type:"number",placeholder:"无限制",class:"form-input w-full text-sm"},null,512),[[j,e.tokenLimit]]),n[38]||(n[38]=t("p",{class:"text-xs text-gray-500 mt-0.5 ml-2"}," 窗口内最大Token ",-1))])]),n[39]||(n[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:"),y(" 时间窗口=60,请求次数=1000 → 每60分钟最多1000次请求")]),t("div",null,[t("strong",null,"示例2:"),y(" 时间窗口=1,Token=10000 → 每分钟最多10,000个Token")]),t("div",null,[t("strong",null,"示例3:"),y(" 窗口=30,请求=50,Token=100000 → 每30分钟50次请求且不超10万Token")])])],-1))])]),t("div",null,[n[42]||(n[42]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"每日费用限制 (美元)",-1)),t("div",Qe,[t("div",Xe,[t("button",{type:"button",class:"px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded-lg text-sm font-medium",onClick:n[5]||(n[5]=u=>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:n[6]||(n[6]=u=>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:n[7]||(n[7]=u=>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:n[8]||(n[8]=u=>e.dailyCostLimit="")}," 自定义 ")]),$(t("input",{"onUpdate:modelValue":n[9]||(n[9]=u=>e.dailyCostLimit=u),type:"number",min:"0",step:"0.01",placeholder:"0 表示无限制",class:"form-input w-full"},null,512),[[j,e.dailyCostLimit]]),n[41]||(n[41]=t("p",{class:"text-xs text-gray-500"}," 设置此 API Key 每日的费用限制,超过限制将拒绝请求,0 或留空表示无限制 ",-1))])]),t("div",null,[n[43]||(n[43]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"并发限制",-1)),$(t("input",{"onUpdate:modelValue":n[10]||(n[10]=u=>e.concurrencyLimit=u),type:"number",min:"0",placeholder:"0 表示无限制",class:"form-input w-full"},null,512),[[j,e.concurrencyLimit]]),n[44]||(n[44]=t("p",{class:"text-xs text-gray-500 mt-2"}," 设置此 API Key 可同时处理的最大请求数 ",-1))]),t("div",null,[n[48]||(n[48]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"服务权限",-1)),t("div",Je,[t("label",Ze,[$(t("input",{"onUpdate:modelValue":n[11]||(n[11]=u=>e.permissions=u),type:"radio",value:"all",class:"mr-2"},null,512),[[Z,e.permissions]]),n[45]||(n[45]=t("span",{class:"text-sm text-gray-700"},"全部服务",-1))]),t("label",ts,[$(t("input",{"onUpdate:modelValue":n[12]||(n[12]=u=>e.permissions=u),type:"radio",value:"claude",class:"mr-2"},null,512),[[Z,e.permissions]]),n[46]||(n[46]=t("span",{class:"text-sm text-gray-700"},"仅 Claude",-1))]),t("label",es,[$(t("input",{"onUpdate:modelValue":n[13]||(n[13]=u=>e.permissions=u),type:"radio",value:"gemini",class:"mr-2"},null,512),[[Z,e.permissions]]),n[47]||(n[47]=t("span",{class:"text-sm text-gray-700"},"仅 Gemini",-1))])]),n[49]||(n[49]=t("p",{class:"text-xs text-gray-500 mt-2"}," 控制此 API Key 可以访问哪些服务 ",-1))]),t("div",null,[n[54]||(n[54]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"专属账号绑定",-1)),t("div",ss,[t("div",null,[n[51]||(n[51]=t("label",{class:"block text-sm font-medium text-gray-600 mb-1"},"Claude 专属账号",-1)),$(t("select",{"onUpdate:modelValue":n[14]||(n[14]=u=>e.claudeAccountId=u),class:"form-input w-full",disabled:e.permissions==="gemini"},[n[50]||(n[50]=t("option",{value:""}," 使用共享账号池 ",-1)),k.accounts.claude.filter(u=>u.isDedicated&&u.platform==="claude-oauth").length>0?(i(),a("optgroup",os,[(i(!0),a(E,null,V(k.accounts.claude.filter(u=>u.isDedicated&&u.platform==="claude-oauth"),u=>(i(),a("option",{key:u.id,value:u.id},c(u.name)+" ("+c(u.status==="active"?"正常":"异常")+") ",9,ns))),128))])):A("",!0),k.accounts.claude.filter(u=>u.isDedicated&&u.platform==="claude-console").length>0?(i(),a("optgroup",is,[(i(!0),a(E,null,V(k.accounts.claude.filter(u=>u.isDedicated&&u.platform==="claude-console"),u=>(i(),a("option",{key:u.id,value:`console:${u.id}`},c(u.name)+" ("+c(u.status==="active"?"正常":"异常")+") ",9,as))),128))])):A("",!0)],8,ls),[[G,e.claudeAccountId]])]),t("div",null,[n[53]||(n[53]=t("label",{class:"block text-sm font-medium text-gray-600 mb-1"},"Gemini 专属账号",-1)),$(t("select",{"onUpdate:modelValue":n[15]||(n[15]=u=>e.geminiAccountId=u),class:"form-input w-full",disabled:e.permissions==="claude"},[n[52]||(n[52]=t("option",{value:""}," 使用共享账号池 ",-1)),(i(!0),a(E,null,V(k.accounts.gemini,u=>(i(),a("option",{key:u.id,value:u.id},c(u.name)+" ("+c(u.status==="active"?"正常":"异常")+") ",9,ds))),128))],8,rs),[[G,e.geminiAccountId]])])]),n[55]||(n[55]=t("p",{class:"text-xs text-gray-500 mt-2"}," 修改绑定账号将影响此API Key的请求路由 ",-1))]),t("div",null,[t("div",us,[$(t("input",{id:"editEnableModelRestriction","onUpdate:modelValue":n[16]||(n[16]=u=>e.enableModelRestriction=u),type:"checkbox",class:"w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500"},null,512),[[tt,e.enableModelRestriction]]),n[56]||(n[56]=t("label",{for:"editEnableModelRestriction",class:"ml-2 text-sm font-semibold text-gray-700 cursor-pointer"}," 启用模型限制 ",-1))]),e.enableModelRestriction?(i(),a("div",cs,[t("div",null,[n[59]||(n[59]=t("label",{class:"block text-sm font-medium text-gray-600 mb-2"},"限制的模型列表",-1)),t("div",ms,[(i(!0),a(E,null,V(e.restrictedModels,(u,z)=>(i(),a("span",{key:z,class:"inline-flex items-center px-3 py-1 rounded-full text-sm bg-red-100 text-red-800"},[y(c(u)+" ",1),t("button",{type:"button",class:"ml-2 text-red-600 hover:text-red-800",onClick:b=>q(z)},n[57]||(n[57]=[t("i",{class:"fas fa-times text-xs"},null,-1)]),8,ps)]))),128)),e.restrictedModels.length===0?(i(),a("span",xs," 暂无限制的模型 ")):A("",!0)]),t("div",fs,[$(t("input",{"onUpdate:modelValue":n[17]||(n[17]=u=>e.modelInput=u),type:"text",placeholder:"输入模型名称,按回车添加",class:"form-input flex-1",onKeydown:ot(X(w,["prevent"]),["enter"])},null,40,gs),[[j,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:w},n[58]||(n[58]=[t("i",{class:"fas fa-plus"},null,-1)]))]),n[60]||(n[60]=t("p",{class:"text-xs text-gray-500 mt-2"}," 设置此API Key无法访问的模型,例如:claude-opus-4-20250514 ",-1))])])):A("",!0)]),t("div",null,[t("div",ys,[$(t("input",{id:"editEnableClientRestriction","onUpdate:modelValue":n[18]||(n[18]=u=>e.enableClientRestriction=u),type:"checkbox",class:"w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500"},null,512),[[tt,e.enableClientRestriction]]),n[61]||(n[61]=t("label",{for:"editEnableClientRestriction",class:"ml-2 text-sm font-semibold text-gray-700 cursor-pointer"}," 启用客户端限制 ",-1))]),e.enableClientRestriction?(i(),a("div",bs,[t("div",null,[n[62]||(n[62]=t("label",{class:"block text-sm font-medium text-gray-600 mb-2"},"允许的客户端",-1)),n[63]||(n[63]=t("p",{class:"text-xs text-gray-500 mb-3"}," 勾选允许使用此API Key的客户端 ",-1)),t("div",vs,[(i(!0),a(E,null,V(_.value,u=>(i(),a("div",{key:u.id,class:"flex items-start"},[$(t("input",{id:`edit_client_${u.id}`,"onUpdate:modelValue":n[19]||(n[19]=z=>e.allowedClients=z),type:"checkbox",value:u.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,ws),[[tt,e.allowedClients]]),t("label",{for:`edit_client_${u.id}`,class:"ml-2 flex-1 cursor-pointer"},[t("span",$s,c(u.name),1),t("span",Cs,c(u.description),1)],8,As)]))),128))])])])):A("",!0)]),t("div",Ks,[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:n[20]||(n[20]=u=>f.$emit("close"))}," 取消 "),t("button",{type:"submit",disabled:h.value,class:"btn btn-primary flex-1 py-3 px-6 font-semibold"},[h.value?(i(),a("div",hs)):(i(),a("i",Is)),y(" "+c(h.value?"保存中...":"保存修改"),1)],8,ks)])],32)])])]))}},Ls=st(Ds,[["__scopeId","data-v-dd9249b5"]]),Rs={class:"fixed inset-0 modal z-50 flex items-center justify-center p-4"},Ms={class:"modal-content w-full max-w-md p-8 mx-auto max-h-[90vh] flex flex-col"},Ss={class:"flex items-center justify-between mb-6"},Ts={class:"space-y-6 modal-scroll-content custom-scrollbar flex-1"},_s={class:"bg-blue-50 border border-blue-200 rounded-lg p-4"},Es={class:"flex items-start gap-3"},Ps={class:"text-sm text-gray-700"},Vs={class:"text-xs text-gray-600 mt-1"},js={key:0,class:"mt-3"},Us=["min"],qs={key:1,class:"text-xs text-gray-500 mt-2"},Os={class:"flex gap-3 pt-4"},Fs=["disabled"],Ws={key:0,class:"loading-spinner mr-2"},Ys={key:1,class:"fas fa-clock mr-2"},zs={__name:"RenewApiKeyModal",props:{apiKey:{type:Object,required:!0}},emits:["close","success"],setup(k,{emit:R}){const x=k,P=R;yt();const M=C(!1),g=rt({renewDuration:"30d",customExpireDate:"",newExpiresAt:null}),h=et(()=>{const e=new Date;return x.apiKey.expiresAt&&new Date(x.apiKey.expiresAt)>e?new Date(x.apiKey.expiresAt).toISOString().slice(0,16):(e.setMinutes(e.getMinutes()+1),e.toISOString().slice(0,16))}),_=e=>new Date(e).toLocaleString("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"}),K=()=>{if(!g.renewDuration){g.newExpiresAt=null;return}if(g.renewDuration==="permanent"){g.newExpiresAt=null;return}if(g.renewDuration==="custom")return;const e=x.apiKey.expiresAt&&new Date(x.apiKey.expiresAt)>new Date?new Date(x.apiKey.expiresAt):new Date,q=g.renewDuration.match(/(\d+)([dhmy])/);if(q){const[,Y,N]=q,v=parseInt(Y);switch(N){case"d":e.setDate(e.getDate()+v);break;case"h":e.setHours(e.getHours()+v);break;case"m":e.setMonth(e.getMonth()+v);break;case"y":e.setFullYear(e.getFullYear()+v);break}g.newExpiresAt=e.toISOString()}},O=()=>{g.customExpireDate&&(g.newExpiresAt=new Date(g.customExpireDate).toISOString())},D=async()=>{M.value=!0;try{const e={expiresAt:g.renewDuration==="permanent"?null:g.newExpiresAt},w=await U.put(`/admin/api-keys/${x.apiKey.id}/renew`,e);w.success?(T("API Key 续期成功","success"),P("success"),P("close")):T(w.message||"续期失败","error")}catch{T("续期失败","error")}finally{M.value=!1}};return K(),(e,w)=>(i(),H(nt,{to:"body"},[t("div",Rs,[t("div",Ms,[t("div",Ss,[w[5]||(w[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:w[0]||(w[0]=q=>e.$emit("close"))},w[4]||(w[4]=[t("i",{class:"fas fa-times text-xl"},null,-1)]))]),t("div",Ts,[t("div",_s,[t("div",Es,[w[7]||(w[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,[w[6]||(w[6]=t("h4",{class:"font-semibold text-gray-800 mb-1"}," API Key 信息 ",-1)),t("p",Ps,c(k.apiKey.name),1),t("p",Vs," 当前过期时间:"+c(k.apiKey.expiresAt?_(k.apiKey.expiresAt):"永不过期"),1)])])]),t("div",null,[w[9]||(w[9]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-3"},"续期时长",-1)),$(t("select",{"onUpdate:modelValue":w[1]||(w[1]=q=>g.renewDuration=q),class:"form-input w-full",onChange:K},w[8]||(w[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),[[G,g.renewDuration]]),g.renewDuration==="custom"?(i(),a("div",js,[$(t("input",{"onUpdate:modelValue":w[2]||(w[2]=q=>g.customExpireDate=q),type:"datetime-local",class:"form-input w-full",min:h.value,onChange:O},null,40,Us),[[j,g.customExpireDate]])])):A("",!0),g.newExpiresAt?(i(),a("p",qs," 新的过期时间:"+c(_(g.newExpiresAt)),1)):A("",!0)])]),t("div",Os,[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:w[3]||(w[3]=q=>e.$emit("close"))}," 取消 "),t("button",{type:"button",disabled:M.value||!g.renewDuration,class:"btn btn-primary flex-1 py-3 px-6 font-semibold",onClick:D},[M.value?(i(),a("div",Ws)):(i(),a("i",Ys)),y(" "+c(M.value?"续期中...":"确认续期"),1)],8,Fs)])])])]))}},Ns=st(zs,[["__scopeId","data-v-0c3b1b3f"]]),Bs={class:"fixed inset-0 modal z-50 flex items-center justify-center p-4"},Hs={class:"modal-content w-full max-w-lg p-8 mx-auto max-h-[90vh] overflow-y-auto custom-scrollbar"},Gs={class:"space-y-4 mb-6"},Qs={class:"p-3 bg-gray-50 rounded-lg border"},Xs={class:"text-gray-900 font-medium"},Js={key:0},Zs={class:"p-3 bg-gray-50 rounded-lg border"},tl={class:"text-gray-700"},el={class:"relative"},sl={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"},ll={class:"absolute top-3 right-3"},ol=["title"],nl={__name:"NewApiKeyModal",props:{apiKey:{type:Object,required:!0}},emits:["close"],setup(k,{emit:R}){const x=k,P=R,M=C(!1),g=()=>{M.value=!M.value},h=()=>{const D=x.apiKey.apiKey||x.apiKey.key||"";return D?M.value||D.length<=12?D:D.substring(0,8)+"●".repeat(Math.max(0,D.length-12))+D.substring(D.length-4):""},_=async()=>{const D=x.apiKey.apiKey||x.apiKey.key||"";if(!D){T("API Key 不存在","error");return}try{await navigator.clipboard.writeText(D),T("API Key 已复制到剪贴板","success")}catch(e){console.error("Failed to copy:",e);const w=document.createElement("textarea");w.value=D,document.body.appendChild(w),w.select();try{document.execCommand("copy"),T("API Key 已复制到剪贴板","success")}catch{T("复制失败,请手动复制","error")}finally{document.body.removeChild(w)}}},K=async()=>{window.showConfirm?await window.showConfirm("关闭提醒",`关闭后将无法再次查看完整的API Key,请确保已经妥善保存。
|
||
|
||
确定要关闭吗?`,"确定关闭","取消")&&P("close"):confirm(`关闭后将无法再次查看完整的API Key,请确保已经妥善保存。
|
||
|
||
确定要关闭吗?`)&&P("close")},O=async()=>{window.showConfirm?await window.showConfirm("确定要关闭吗?",`您还没有保存API Key,关闭后将无法再次查看。
|
||
|
||
建议您先复制API Key再关闭。`,"仍然关闭","返回复制")&&P("close"):confirm(`您还没有保存API Key,关闭后将无法再次查看。
|
||
|
||
确定要关闭吗?`)&&P("close")};return(D,e)=>(i(),H(nt,{to:"body"},[t("div",Bs,[t("div",Hs,[t("div",{class:"flex items-center justify-between mb-6"},[e[1]||(e[1]=t("div",{class:"flex items-center gap-3"},[t("div",{class:"w-12 h-12 bg-gradient-to-br from-green-500 to-green-600 rounded-xl flex items-center justify-center"},[t("i",{class:"fas fa-check text-white text-lg"})]),t("div",null,[t("h3",{class:"text-xl font-bold text-gray-900"}," API Key 创建成功 "),t("p",{class:"text-sm text-gray-600"}," 请妥善保存您的 API Key ")])],-1)),t("button",{class:"text-gray-400 hover:text-gray-600 transition-colors",title:"直接关闭(不推荐)",onClick:O},e[0]||(e[0]=[t("i",{class:"fas fa-times text-xl"},null,-1)]))]),e[7]||(e[7]=t("div",{class:"bg-amber-50 border-l-4 border-amber-400 p-4 mb-6"},[t("div",{class:"flex items-start"},[t("div",{class:"w-6 h-6 bg-amber-400 rounded-lg flex items-center justify-center flex-shrink-0 mt-0.5"},[t("i",{class:"fas fa-exclamation-triangle text-white text-sm"})]),t("div",{class:"ml-3"},[t("h5",{class:"font-semibold text-amber-900 mb-1"}," 重要提醒 "),t("p",{class:"text-sm text-amber-800"}," 这是您唯一能看到完整 API Key 的机会。关闭此窗口后,系统将不再显示完整的 API Key。请立即复制并妥善保存。 ")])])],-1)),t("div",Gs,[t("div",null,[e[2]||(e[2]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},"API Key 名称",-1)),t("div",Qs,[t("span",Xs,c(k.apiKey.name),1)])]),k.apiKey.description?(i(),a("div",Js,[e[3]||(e[3]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},"备注",-1)),t("div",Zs,[t("span",tl,c(k.apiKey.description||"无描述"),1)])])):A("",!0),t("div",null,[e[4]||(e[4]=t("label",{class:"block text-sm font-semibold text-gray-700 mb-2"},"API Key",-1)),t("div",el,[t("div",sl,c(h()),1),t("div",ll,[t("button",{type:"button",class:"btn-icon-sm hover:bg-gray-800 bg-gray-700",title:M.value?"隐藏API Key":"显示完整API Key",onClick:g},[t("i",{class:W(["fas",M.value?"fa-eye-slash":"fa-eye","text-gray-300"])},null,2)],8,ol)])]),e[5]||(e[5]=t("p",{class:"text-xs text-gray-500 mt-2"}," 点击眼睛图标切换显示模式,使用下方按钮复制完整 API Key ",-1))])]),t("div",{class:"flex gap-3"},[t("button",{class:"flex-1 btn btn-primary py-3 px-6 font-semibold flex items-center justify-center gap-2",onClick:_},e[6]||(e[6]=[t("i",{class:"fas fa-copy"},null,-1),y(" 复制 API Key ",-1)])),t("button",{class:"px-6 py-3 bg-gray-200 text-gray-800 rounded-xl font-semibold hover:bg-gray-300 transition-colors border border-gray-300",onClick:K}," 我已保存 ")])])])]))}},il=st(nl,[["__scopeId","data-v-2c02f1f7"]]),al={class:"tab-content"},rl={class:"card p-6"},dl={class:"flex flex-col md:flex-row justify-between items-center gap-4 mb-6"},ul={class:"flex items-center gap-3"},cl=["value"],ml={key:0,class:"text-center py-12"},pl={key:1,class:"text-center py-12"},xl={key:2,class:"table-container"},fl={class:"min-w-full"},gl={class:"bg-gray-50/80 backdrop-blur-sm"},yl={key:1,class:"fas fa-sort ml-1 text-gray-400"},bl={key:1,class:"fas fa-sort ml-1 text-gray-400"},vl={class:"px-6 py-4 text-left text-xs font-bold text-gray-700 uppercase tracking-wider"},wl={key:1,class:"fas fa-sort ml-1 text-gray-400"},Al={key:1,class:"fas fa-sort ml-1 text-gray-400"},$l={key:1,class:"fas fa-sort ml-1 text-gray-400"},Cl={class:"divide-y divide-gray-200/50"},Kl={class:"table-row"},kl={class:"px-6 py-4 whitespace-nowrap"},hl={class:"flex items-center"},Il={class:"text-sm font-semibold text-gray-900"},Dl={class:"text-xs text-gray-500"},Ll={class:"text-xs text-gray-500 mt-1"},Rl={key:0},Ml={key:1},Sl={class:"px-6 py-4"},Tl={class:"flex flex-wrap gap-1"},_l={key:0,class:"text-xs text-gray-400"},El={class:"px-6 py-4 whitespace-nowrap"},Pl={class:"text-sm font-mono text-gray-600 bg-gray-50 px-3 py-1 rounded-lg"},Vl={class:"px-6 py-4 whitespace-nowrap"},jl={class:"px-6 py-4"},Ul={class:"space-y-1"},ql={class:"flex justify-between text-sm"},Ol={class:"font-medium text-gray-900"},Fl={class:"flex justify-between text-sm"},Wl={class:"font-medium text-gray-900"},Yl={class:"flex justify-between text-sm"},zl={class:"font-medium text-green-600"},Nl={key:0,class:"flex justify-between text-sm"},Bl={class:"flex justify-between text-sm"},Hl={class:"font-medium text-purple-600"},Gl={class:"flex justify-between text-sm"},Ql={key:0,class:"text-xs text-gray-500"},Xl={key:1,class:"flex justify-between text-sm"},Jl={class:"font-medium text-indigo-600"},Zl={key:2,class:"flex justify-between text-sm"},to={class:"font-medium text-indigo-600"},eo={class:"flex justify-between text-xs text-gray-500"},so={key:3,class:"flex justify-between text-xs text-orange-500"},lo={class:"flex justify-between text-xs text-blue-600"},oo={class:"pt-1 border-t border-gray-100"},no={class:"flex justify-between text-xs text-green-600"},io={class:"pt-2"},ao=["onClick"],ro={class:"px-6 py-4 whitespace-nowrap text-sm text-gray-500"},uo={class:"px-6 py-4 whitespace-nowrap text-sm"},co={key:0},mo={key:0,class:"text-red-600"},po={key:1,class:"text-orange-600"},xo={key:2,class:"text-gray-600"},fo={key:1,class:"text-gray-400"},go={class:"px-6 py-4 whitespace-nowrap text-sm"},yo={class:"flex gap-2"},bo=["onClick"],vo=["onClick"],wo=["onClick"],Ao=["onClick"],$o={key:0},Co={colspan:"7",class:"px-6 py-4 bg-gray-50"},Ko={key:0,class:"text-center py-4"},ko={class:"space-y-4"},ho={class:"flex items-center justify-between mb-4"},Io={class:"flex items-center gap-2"},Do={key:0,class:"text-xs text-gray-500 bg-gray-100 px-2 py-1 rounded-full"},Lo={class:"flex gap-1 items-center"},Ro={class:"flex gap-1 bg-gray-100 rounded p-1"},Mo=["onClick"],So={key:0,class:"text-center py-8"},To={class:"flex items-center justify-center gap-2 mb-3"},_o=["onClick"],Eo={key:1,class:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"},Po={class:"flex justify-between items-start mb-3"},Vo={class:"flex-1"},jo={class:"text-sm font-semibold text-gray-800 block mb-1"},Uo={class:"text-xs text-gray-500 bg-blue-50 px-2 py-1 rounded-full"},qo={class:"space-y-2 mb-3"},Oo={class:"flex justify-between items-center text-sm"},Fo={class:"font-semibold text-gray-900"},Wo={class:"flex justify-between items-center text-sm"},Yo={class:"font-semibold text-green-600"},zo={class:"pt-2 mt-2 border-t border-gray-100"},No={class:"flex justify-between items-center text-xs text-gray-500"},Bo={class:"font-medium"},Ho={class:"flex justify-between items-center text-xs text-gray-500"},Go={class:"font-medium"},Qo={key:0,class:"flex justify-between items-center text-xs text-purple-600"},Xo={class:"font-medium"},Jo={key:1,class:"flex justify-between items-center text-xs text-purple-600"},Zo={class:"font-medium"},tn={class:"w-full bg-gray-200 rounded-full h-2 mt-3"},en={class:"text-right mt-1"},sn={class:"text-xs font-medium text-indigo-600"},ln={key:2,class:"mt-4 p-3 bg-gradient-to-r from-indigo-50 to-purple-50 rounded-lg border border-indigo-100"},on={class:"flex items-center justify-between text-sm"},nn={class:"flex gap-4 text-xs"},an={class:"text-gray-600"},rn={class:"font-semibold text-gray-800"},dn={class:"text-gray-600"},un={class:"font-semibold text-gray-800"},cn={__name:"ApiKeysView",setup(k){const R=ut(),x=C([]),P=C(!1),M=C("today"),g=C(""),h=C("asc"),_=C({}),K=C({}),O=C({}),D=C([new Date(2e3,1,1,0,0,0),new Date(2e3,2,1,23,59,59)]),e=C({claude:[],gemini:[]}),w=C(""),q=C([]),Y=C(!1),N=C(!1),v=C(!1),I=C(!1),f=C(null),n=C(null),u=C(null),z=et(()=>{let d=x.value;return w.value&&(d=x.value.filter(p=>p.tags&&p.tags.includes(w.value))),g.value?[...d].sort((p,l)=>{let m=p[g.value],S=l[g.value];return g.value==="status"?(m=p.isActive?1:0,S=l.isActive?1:0):g.value==="cost"?(m=parseFloat(Q(p.usage).replace("$","")),S=parseFloat(Q(l.usage).replace("$",""))):(g.value==="createdAt"||g.value==="expiresAt")&&(m=m?new Date(m).getTime():0,S=S?new Date(S).getTime():0),m<S?h.value==="asc"?-1:1:m>S?h.value==="asc"?1:-1:0}):d}),b=async()=>{var d,s;try{const[p,l,m]=await Promise.all([U.get("/admin/claude-accounts"),U.get("/admin/claude-console-accounts"),U.get("/admin/gemini-accounts")]),S=[];p.success&&((d=p.data)==null||d.forEach(F=>{S.push({...F,platform:"claude-oauth",isDedicated:F.accountType==="dedicated"})})),l.success&&((s=l.data)==null||s.forEach(F=>{S.push({...F,platform:"claude-console",isDedicated:F.accountType==="dedicated"})})),e.value.claude=S,m.success&&(e.value.gemini=(m.data||[]).map(F=>({...F,isDedicated:F.accountType==="dedicated"})))}catch(p){console.error("加载账户列表失败:",p)}},o=async()=>{P.value=!0;try{const d=await U.get(`/admin/api-keys?timeRange=${M.value}`);if(d.success){x.value=d.data||[];const s=new Set;x.value.forEach(p=>{p.tags&&Array.isArray(p.tags)&&p.tags.forEach(l=>s.add(l))}),q.value=Array.from(s).sort()}}catch{T("加载 API Keys 失败","error")}finally{P.value=!1}},r=d=>{g.value===d?h.value=h.value==="asc"?"desc":"asc":(g.value=d,h.value="asc")},L=d=>!d&&d!==0?"0":d.toLocaleString("zh-CN"),Q=d=>!d||!d.total?"$0.0000":`$${(d.total.cost||0).toFixed(4)}`,J=(d,s)=>{if(d){const p=e.value.claude.find(l=>l.id===d);return p?p.name:`账户-${d.substring(0,8)}`}if(s){const p=e.value.claude.find(l=>l.id===s);return p?`${p.name} (Console)`:`Console-${s.substring(0,8)}`}return"未知账户"},it=d=>d?new Date(d)<new Date:!1,ct=d=>!d||it(d)?!1:(new Date(d)-new Date)/(1e3*60*60*24)<=7,mt=d=>d?new Date(d).toLocaleDateString("zh-CN"):"",vt=async d=>{_.value[d]?_.value[d]=!1:(_.value[d]=!0,O.value[d]||xt(d),await lt(d,!0))},lt=async(d,s=!1)=>{if(!s&&K.value[d]&&K.value[d].length>0)return;const p=B(d);try{let l=`/admin/api-keys/${d}/model-stats`;const m=new URLSearchParams;if(p.customStart&&p.customEnd)m.append("startDate",p.customStart),m.append("endDate",p.customEnd),m.append("period","custom");else{const F=p.preset==="today"?"daily":"monthly";m.append("period",F)}l+="?"+m.toString();const S=await U.get(l);S.success&&(K.value[d]=S.data||[])}catch{T("加载模型统计失败","error"),K.value[d]=[]}},pt=(d,s)=>{const p=s.reduce((l,m)=>l+(m.allTokens||0),0);return p===0?0:Math.round(d/p*100)},wt=d=>d.formatted&&d.formatted.total?d.formatted.total:d.cost!==void 0?`$${d.cost.toFixed(6)}`:"$0.000000",xt=d=>{const s=new Date,p=new Date(s);p.setDate(s.getDate()-6),O.value[d]={type:"preset",preset:"7days",customStart:p.toISOString().split("T")[0],customEnd:s.toISOString().split("T")[0],customRange:null,presetOptions:[{value:"today",label:"今日",days:1},{value:"7days",label:"7天",days:7},{value:"30days",label:"30天",days:30}]}},B=d=>(O.value[d]||xt(d),O.value[d]),ft=(d,s)=>{const p=B(s);p.type="preset",p.preset=d;const l=p.presetOptions.find(m=>m.value===d);if(l){const m=new Date,S=new Date(m);S.setDate(m.getDate()-(l.days-1)),p.customStart=S.toISOString().split("T")[0],p.customEnd=m.toISOString().split("T")[0];const F=at=>at.getFullYear()+"-"+String(at.getMonth()+1).padStart(2,"0")+"-"+String(at.getDate()).padStart(2,"0")+" 00:00:00";p.customRange=[F(S),F(m)]}lt(s,!0)},At=(d,s)=>{const p=B(d);s&&s.length===2?(p.type="custom",p.preset="",p.customRange=s,p.customStart=s[0].split(" ")[0],p.customEnd=s[1].split(" ")[0],lt(d,!0)):s===null&&ft("7days",d)},$t=d=>d>new Date,Ct=d=>{const s=B(d);s.type="preset",s.preset="7days";const p=new Date,l=new Date(p);l.setDate(p.getDate()-6),s.customStart=l.toISOString().split("T")[0],s.customEnd=p.toISOString().split("T")[0],s.customRange=null,lt(d,!0),T("已重置筛选条件并刷新数据","info")},Kt=()=>{Y.value=!0},kt=d=>{f.value=d,N.value=!0},ht=d=>{n.value=d,v.value=!0},It=d=>{Y.value=!1,u.value=d,I.value=!0,o()},Dt=()=>{N.value=!1,T("API Key 更新成功","success"),o()},Lt=()=>{v.value=!1,T("API Key 续期成功","success"),o()},Rt=async d=>{let s=!1;if(window.showConfirm?s=await window.showConfirm("删除 API Key","确定要删除这个 API Key 吗?此操作不可恢复。","确定删除","取消"):s=confirm("确定要删除这个 API Key 吗?此操作不可恢复。"),!!s)try{const p=await U.delete(`/admin/api-keys/${d}`);p.success?(T("API Key 已删除","success"),o()):T(p.message||"删除失败","error")}catch{T("删除失败","error")}},Mt=d=>{const p=`${window.location.origin}/admin/api-stats?apiId=${d.id}`,l=document.createElement("textarea");l.value=p,l.style.position="fixed",l.style.opacity="0",l.style.left="-9999px",document.body.appendChild(l),l.select(),l.setSelectionRange(0,99999);try{document.execCommand("copy")?T("已复制统计页面链接","success"):(T("复制失败,请手动复制","error"),console.log("统计页面链接:",p))}catch(m){T("复制失败,请手动复制","error"),console.error("复制错误:",m),console.log("统计页面链接:",p)}finally{document.body.removeChild(l)}};return dt(async()=>{await Promise.all([R.loadSupportedClients(),b(),o()])}),(d,s)=>{const p=St;return i(),a("div",al,[t("div",rl,[t("div",dl,[s[15]||(s[15]=t("div",null,[t("h3",{class:"text-xl font-bold text-gray-900 mb-2"}," API Keys 管理 "),t("p",{class:"text-gray-600"}," 管理和监控您的 API 密钥 ")],-1)),t("div",ul,[$(t("select",{"onUpdate:modelValue":s[0]||(s[0]=l=>M.value=l),class:"form-input px-3 py-2 text-sm",onChange:s[1]||(s[1]=l=>o())},s[12]||(s[12]=[t("option",{value:"today"}," 今日 ",-1),t("option",{value:"7days"}," 最近7天 ",-1),t("option",{value:"monthly"}," 本月 ",-1),t("option",{value:"all"}," 全部时间 ",-1)]),544),[[G,M.value]]),$(t("select",{"onUpdate:modelValue":s[2]||(s[2]=l=>w.value=l),class:"form-input px-3 py-2 text-sm"},[s[13]||(s[13]=t("option",{value:""}," 所有标签 ",-1)),(i(!0),a(E,null,V(q.value,l=>(i(),a("option",{key:l,value:l},c(l),9,cl))),128))],512),[[G,w.value]]),t("button",{class:"btn btn-primary px-6 py-3 flex items-center gap-2",onClick:X(Kt,["stop"])},s[14]||(s[14]=[t("i",{class:"fas fa-plus"},null,-1),y("创建新 Key ",-1)]))])]),P.value?(i(),a("div",ml,s[16]||(s[16]=[t("div",{class:"loading-spinner mx-auto mb-4"},null,-1),t("p",{class:"text-gray-500"}," 正在加载 API Keys... ",-1)]))):x.value.length===0?(i(),a("div",pl,s[17]||(s[17]=[t("div",{class:"w-16 h-16 mx-auto mb-4 bg-gray-100 rounded-full flex items-center justify-center"},[t("i",{class:"fas fa-key text-gray-400 text-xl"})],-1),t("p",{class:"text-gray-500 text-lg"}," 暂无 API Keys ",-1),t("p",{class:"text-gray-400 text-sm mt-2"}," 点击上方按钮创建您的第一个 API Key ",-1)]))):(i(),a("div",xl,[t("table",fl,[t("thead",gl,[t("tr",null,[t("th",{class:"px-6 py-4 text-left text-xs font-bold text-gray-700 uppercase tracking-wider cursor-pointer hover:bg-gray-100",onClick:s[3]||(s[3]=l=>r("name"))},[s[18]||(s[18]=y(" 名称 ",-1)),g.value==="name"?(i(),a("i",{key:0,class:W(["fas",h.value==="asc"?"fa-sort-up":"fa-sort-down","ml-1"])},null,2)):(i(),a("i",yl))]),s[25]||(s[25]=t("th",{class:"px-6 py-4 text-left text-xs font-bold text-gray-700 uppercase tracking-wider"}," 标签 ",-1)),s[26]||(s[26]=t("th",{class:"px-6 py-4 text-left text-xs font-bold text-gray-700 uppercase tracking-wider"}," API Key ",-1)),t("th",{class:"px-6 py-4 text-left text-xs font-bold text-gray-700 uppercase tracking-wider cursor-pointer hover:bg-gray-100",onClick:s[4]||(s[4]=l=>r("status"))},[s[19]||(s[19]=y(" 状态 ",-1)),g.value==="status"?(i(),a("i",{key:0,class:W(["fas",h.value==="asc"?"fa-sort-up":"fa-sort-down","ml-1"])},null,2)):(i(),a("i",bl))]),t("th",vl,[s[22]||(s[22]=y(" 使用统计 ",-1)),t("span",{class:"cursor-pointer hover:bg-gray-100 px-2 py-1 rounded",onClick:s[5]||(s[5]=l=>r("cost"))},[s[20]||(s[20]=y(" (费用 ",-1)),g.value==="cost"?(i(),a("i",{key:0,class:W(["fas",h.value==="asc"?"fa-sort-up":"fa-sort-down","ml-1"])},null,2)):(i(),a("i",wl)),s[21]||(s[21]=y(") ",-1))])]),t("th",{class:"px-6 py-4 text-left text-xs font-bold text-gray-700 uppercase tracking-wider cursor-pointer hover:bg-gray-100",onClick:s[6]||(s[6]=l=>r("createdAt"))},[s[23]||(s[23]=y(" 创建时间 ",-1)),g.value==="createdAt"?(i(),a("i",{key:0,class:W(["fas",h.value==="asc"?"fa-sort-up":"fa-sort-down","ml-1"])},null,2)):(i(),a("i",Al))]),t("th",{class:"px-6 py-4 text-left text-xs font-bold text-gray-700 uppercase tracking-wider cursor-pointer hover:bg-gray-100",onClick:s[7]||(s[7]=l=>r("expiresAt"))},[s[24]||(s[24]=y(" 过期时间 ",-1)),g.value==="expiresAt"?(i(),a("i",{key:0,class:W(["fas",h.value==="asc"?"fa-sort-up":"fa-sort-down","ml-1"])},null,2)):(i(),a("i",$l))]),s[27]||(s[27]=t("th",{class:"px-6 py-4 text-left text-xs font-bold text-gray-700 uppercase tracking-wider"}," 操作 ",-1))])]),t("tbody",Cl,[(i(!0),a(E,null,V(z.value,l=>(i(),a(E,{key:l.id},[t("tr",Kl,[t("td",kl,[t("div",hl,[s[30]||(s[30]=t("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"},[t("i",{class:"fas fa-key text-white text-xs"})],-1)),t("div",null,[t("div",Il,c(l.name),1),t("div",Dl,c(l.id),1),t("div",Ll,[l.claudeAccountId||l.claudeConsoleAccountId?(i(),a("span",Rl,[s[28]||(s[28]=t("i",{class:"fas fa-link mr-1"},null,-1)),y(" 绑定: "+c(J(l.claudeAccountId,l.claudeConsoleAccountId)),1)])):(i(),a("span",Ml,s[29]||(s[29]=[t("i",{class:"fas fa-share-alt mr-1"},null,-1),y(" 使用共享池 ",-1)])))])])])]),t("td",Sl,[t("div",Tl,[(i(!0),a(E,null,V(l.tags||[],m=>(i(),a("span",{key:m,class:"inline-flex items-center px-2 py-0.5 bg-blue-100 text-blue-800 text-xs rounded-full"},c(m),1))),128)),!l.tags||l.tags.length===0?(i(),a("span",_l,"无标签")):A("",!0)])]),t("td",El,[t("div",Pl,c((l.apiKey||"").substring(0,20))+"... ",1)]),t("td",Vl,[t("span",{class:W(["inline-flex items-center px-3 py-1 rounded-full text-xs font-semibold",l.isActive?"bg-green-100 text-green-800":"bg-red-100 text-red-800"])},[t("div",{class:W(["w-2 h-2 rounded-full mr-2",l.isActive?"bg-green-500":"bg-red-500"])},null,2),y(" "+c(l.isActive?"活跃":"禁用"),1)],2)]),t("td",jl,[t("div",Ul,[t("div",ql,[s[31]||(s[31]=t("span",{class:"text-gray-600"},"请求数:",-1)),t("span",Ol,c(L(l.usage&&l.usage.total&&l.usage.total.requests||0)),1)]),t("div",Fl,[s[32]||(s[32]=t("span",{class:"text-gray-600"},"Token:",-1)),t("span",Wl,c(L(l.usage&&l.usage.total&&l.usage.total.tokens||0)),1)]),t("div",Yl,[s[33]||(s[33]=t("span",{class:"text-gray-600"},"费用:",-1)),t("span",zl,c(Q(l.usage)),1)]),l.dailyCostLimit>0?(i(),a("div",Nl,[s[34]||(s[34]=t("span",{class:"text-gray-600"},"今日费用:",-1)),t("span",{class:W(["font-medium",(l.dailyCost||0)>=l.dailyCostLimit?"text-red-600":"text-blue-600"])}," $"+c((l.dailyCost||0).toFixed(2))+" / $"+c(l.dailyCostLimit.toFixed(2)),3)])):A("",!0),t("div",Bl,[s[35]||(s[35]=t("span",{class:"text-gray-600"},"并发限制:",-1)),t("span",Hl,c(l.concurrencyLimit>0?l.concurrencyLimit:"无限制"),1)]),t("div",Gl,[s[36]||(s[36]=t("span",{class:"text-gray-600"},"当前并发:",-1)),t("span",{class:W(["font-medium",l.currentConcurrency>0?"text-orange-600":"text-gray-600"])},[y(c(l.currentConcurrency||0)+" ",1),l.concurrencyLimit>0?(i(),a("span",Ql,"/ "+c(l.concurrencyLimit),1)):A("",!0)],2)]),l.rateLimitWindow>0?(i(),a("div",Xl,[s[37]||(s[37]=t("span",{class:"text-gray-600"},"时间窗口:",-1)),t("span",Jl,c(l.rateLimitWindow)+" 分钟",1)])):A("",!0),l.rateLimitRequests>0?(i(),a("div",Zl,[s[38]||(s[38]=t("span",{class:"text-gray-600"},"请求限制:",-1)),t("span",to,c(l.rateLimitRequests)+" 次/窗口",1)])):A("",!0),t("div",eo,[t("span",null,"输入: "+c(L(l.usage&&l.usage.total&&l.usage.total.inputTokens||0)),1),t("span",null,"输出: "+c(L(l.usage&&l.usage.total&&l.usage.total.outputTokens||0)),1)]),(l.usage&&l.usage.total&&l.usage.total.cacheCreateTokens||0)>0||(l.usage&&l.usage.total&&l.usage.total.cacheReadTokens||0)>0?(i(),a("div",so,[t("span",null,"缓存创建: "+c(L(l.usage&&l.usage.total&&l.usage.total.cacheCreateTokens||0)),1),t("span",null,"缓存读取: "+c(L(l.usage&&l.usage.total&&l.usage.total.cacheReadTokens||0)),1)])):A("",!0),t("div",lo,[t("span",null,"RPM: "+c(l.usage&&l.usage.averages&&l.usage.averages.rpm||0),1),t("span",null,"TPM: "+c(l.usage&&l.usage.averages&&l.usage.averages.tpm||0),1)]),t("div",oo,[t("div",no,[t("span",null,"今日: "+c(L(l.usage&&l.usage.daily&&l.usage.daily.requests||0))+"次",1),t("span",null,c(L(l.usage&&l.usage.daily&&l.usage.daily.tokens||0))+"T",1)])]),t("div",io,[l&&l.id?(i(),a("button",{key:0,class:"text-xs text-indigo-600 hover:text-indigo-800 font-medium",onClick:m=>vt(l.id)},[t("i",{class:W(["fas",_.value[l.id]?"fa-chevron-up":"fa-chevron-down","mr-1"])},null,2),s[39]||(s[39]=y(" 模型使用分布 ",-1))],8,ao)):A("",!0)])])]),t("td",ro,c(new Date(l.createdAt).toLocaleDateString()),1),t("td",uo,[l.expiresAt?(i(),a("div",co,[it(l.expiresAt)?(i(),a("div",mo,s[40]||(s[40]=[t("i",{class:"fas fa-exclamation-circle mr-1"},null,-1),y(" 已过期 ",-1)]))):ct(l.expiresAt)?(i(),a("div",po,[s[41]||(s[41]=t("i",{class:"fas fa-clock mr-1"},null,-1)),y(" "+c(mt(l.expiresAt)),1)])):(i(),a("div",xo,c(mt(l.expiresAt)),1))])):(i(),a("div",fo,s[42]||(s[42]=[t("i",{class:"fas fa-infinity mr-1"},null,-1),y(" 永不过期 ",-1)])))]),t("td",go,[t("div",yo,[t("button",{class:"text-purple-600 hover:text-purple-900 font-medium hover:bg-purple-50 px-3 py-1 rounded-lg transition-colors",title:"复制统计页面链接",onClick:m=>Mt(l)},s[43]||(s[43]=[t("i",{class:"fas fa-chart-bar mr-1"},null,-1),y("统计 ",-1)]),8,bo),t("button",{class:"text-blue-600 hover:text-blue-900 font-medium hover:bg-blue-50 px-3 py-1 rounded-lg transition-colors",onClick:m=>kt(l)},s[44]||(s[44]=[t("i",{class:"fas fa-edit mr-1"},null,-1),y("编辑 ",-1)]),8,vo),l.expiresAt&&(it(l.expiresAt)||ct(l.expiresAt))?(i(),a("button",{key:0,class:"text-green-600 hover:text-green-900 font-medium hover:bg-green-50 px-3 py-1 rounded-lg transition-colors",onClick:m=>ht(l)},s[45]||(s[45]=[t("i",{class:"fas fa-clock mr-1"},null,-1),y("续期 ",-1)]),8,wo)):A("",!0),t("button",{class:"text-red-600 hover:text-red-900 font-medium hover:bg-red-50 px-3 py-1 rounded-lg transition-colors",onClick:m=>Rt(l.id)},s[46]||(s[46]=[t("i",{class:"fas fa-trash mr-1"},null,-1),y("删除 ",-1)]),8,Ao)])])]),l&&l.id&&_.value[l.id]?(i(),a("tr",$o,[t("td",Co,[K.value[l.id]?A("",!0):(i(),a("div",Ko,s[47]||(s[47]=[t("div",{class:"loading-spinner mx-auto"},null,-1),t("p",{class:"text-sm text-gray-500 mt-2"}," 加载模型统计... ",-1)]))),t("div",ko,[t("div",ho,[s[48]||(s[48]=t("h5",{class:"text-sm font-semibold text-gray-700 flex items-center"},[t("i",{class:"fas fa-chart-pie text-indigo-500 mr-2"}),y(" 模型使用分布 ")],-1)),t("div",Io,[K.value[l.id]&&K.value[l.id].length>0?(i(),a("span",Do,c(K.value[l.id].length)+" 个模型 ",1)):A("",!0),t("div",Lo,[t("div",Ro,[(i(!0),a(E,null,V(B(l.id).presetOptions,m=>(i(),a("button",{key:m.value,class:W(["px-2 py-1 rounded text-xs font-medium transition-colors",B(l.id).preset===m.value&&B(l.id).type==="preset"?"bg-white text-blue-600 shadow-sm":"text-gray-600 hover:text-gray-900"]),onClick:S=>ft(m.value,l.id)},c(m.label),11,Mo))),128))]),Tt(p,{"model-value":B(l.id).customRange,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":$t,"default-time":D.value,size:"small",style:{width:"280px"},"onUpdate:modelValue":m=>At(l.id,m),class:"api-key-date-picker",clearable:!0,"unlink-panels":!1},null,8,["model-value","default-time","onUpdate:modelValue"])])])]),K.value[l.id]&&K.value[l.id].length===0?(i(),a("div",So,[t("div",To,[s[50]||(s[50]=t("i",{class:"fas fa-chart-line text-gray-400 text-lg"},null,-1)),s[51]||(s[51]=t("p",{class:"text-sm text-gray-500"}," 暂无模型使用数据 ",-1)),t("button",{class:"text-blue-500 hover:text-blue-700 text-sm ml-2 flex items-center gap-1 transition-colors",title:"重置筛选条件并刷新",onClick:m=>Ct(l.id)},s[49]||(s[49]=[t("i",{class:"fas fa-sync-alt text-xs"},null,-1),t("span",{class:"text-xs"},"刷新",-1)]),8,_o)]),s[52]||(s[52]=t("p",{class:"text-xs text-gray-400"}," 尝试调整时间范围或点击刷新重新加载数据 ",-1))])):K.value[l.id]&&K.value[l.id].length>0?(i(),a("div",Eo,[(i(!0),a(E,null,V(K.value[l.id],m=>(i(),a("div",{key:m.model,class:"bg-gradient-to-br from-white to-gray-50 rounded-xl p-4 border border-gray-200 hover:border-indigo-300 hover:shadow-lg transition-all duration-200"},[t("div",Po,[t("div",Vo,[t("span",jo,c(m.model),1),t("span",Uo,c(m.requests)+" 次请求",1)])]),t("div",qo,[t("div",Oo,[s[53]||(s[53]=t("span",{class:"text-gray-600 flex items-center"},[t("i",{class:"fas fa-coins text-yellow-500 mr-1 text-xs"}),y(" 总Token: ")],-1)),t("span",Fo,c(L(m.allTokens)),1)]),t("div",Wo,[s[54]||(s[54]=t("span",{class:"text-gray-600 flex items-center"},[t("i",{class:"fas fa-dollar-sign text-green-500 mr-1 text-xs"}),y(" 费用: ")],-1)),t("span",Yo,c(wt(m)),1)]),t("div",zo,[t("div",No,[s[55]||(s[55]=t("span",{class:"flex items-center"},[t("i",{class:"fas fa-arrow-down text-green-500 mr-1"}),y(" 输入: ")],-1)),t("span",Bo,c(L(m.inputTokens)),1)]),t("div",Ho,[s[56]||(s[56]=t("span",{class:"flex items-center"},[t("i",{class:"fas fa-arrow-up text-blue-500 mr-1"}),y(" 输出: ")],-1)),t("span",Go,c(L(m.outputTokens)),1)]),m.cacheCreateTokens>0?(i(),a("div",Qo,[s[57]||(s[57]=t("span",{class:"flex items-center"},[t("i",{class:"fas fa-save mr-1"}),y(" 缓存创建: ")],-1)),t("span",Xo,c(L(m.cacheCreateTokens)),1)])):A("",!0),m.cacheReadTokens>0?(i(),a("div",Jo,[s[58]||(s[58]=t("span",{class:"flex items-center"},[t("i",{class:"fas fa-download mr-1"}),y(" 缓存读取: ")],-1)),t("span",Zo,c(L(m.cacheReadTokens)),1)])):A("",!0)])]),t("div",tn,[t("div",{class:"bg-gradient-to-r from-indigo-500 to-purple-600 h-2 rounded-full transition-all duration-500",style:_t({width:pt(m.allTokens,K.value[l.id])+"%"})},null,4)]),t("div",en,[t("span",sn,c(pt(m.allTokens,K.value[l.id]))+"% ",1)])]))),128))])):A("",!0),K.value[l.id]&&K.value[l.id].length>0?(i(),a("div",ln,[t("div",on,[s[61]||(s[61]=t("span",{class:"font-semibold text-gray-700 flex items-center"},[t("i",{class:"fas fa-calculator text-indigo-500 mr-2"}),y(" 总计统计 ")],-1)),t("div",nn,[t("span",an,[s[59]||(s[59]=y(" 总请求: ",-1)),t("span",rn,c(K.value[l.id].reduce((m,S)=>m+S.requests,0)),1)]),t("span",dn,[s[60]||(s[60]=y(" 总Token: ",-1)),t("span",un,c(L(K.value[l.id].reduce((m,S)=>m+S.allTokens,0))),1)])])])])):A("",!0)])])])):A("",!0)],64))),128))])])]))]),Y.value?(i(),H(Te,{key:0,accounts:e.value,onClose:s[8]||(s[8]=l=>Y.value=!1),onSuccess:It},null,8,["accounts"])):A("",!0),N.value?(i(),H(Ls,{key:1,"api-key":f.value,accounts:e.value,onClose:s[9]||(s[9]=l=>N.value=!1),onSuccess:Dt},null,8,["api-key","accounts"])):A("",!0),v.value?(i(),H(Ns,{key:2,"api-key":n.value,onClose:s[10]||(s[10]=l=>v.value=!1),onSuccess:Lt},null,8,["api-key"])):A("",!0),I.value?(i(),H(il,{key:3,"api-key":u.value,onClose:s[11]||(s[11]=l=>I.value=!1)},null,8,["api-key"])):A("",!0)])}}},yn=st(cn,[["__scopeId","data-v-61e76aa7"]]);export{yn as default};
|