ezllm 0.0.41 → 0.0.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/cli.js +5 -5
  2. package/dist/server.js +56 -56
  3. package/dist/web-ui/assets/{DashboardView-DRckeG7f.js → DashboardView-WtDwRkVw.js} +1 -1
  4. package/dist/web-ui/assets/{LayoutView-4x7mM1Nd.js → LayoutView-Bxe9Zpzg.js} +1 -1
  5. package/dist/web-ui/assets/{LoginView-D55GMnh2.js → LoginView-oHqStvWg.js} +1 -1
  6. package/dist/web-ui/assets/LogsView-C1rYzWM5.js +5 -0
  7. package/dist/web-ui/assets/{LogsView-u-0B5Xpc.css → LogsView-CXFJ_22b.css} +1 -1
  8. package/dist/web-ui/assets/{ManagedServicesView-aU7KD-uK.js → ManagedServicesView-Roep2c1v.js} +1 -1
  9. package/dist/web-ui/assets/PluginsView-Ar17i6aK.css +1 -0
  10. package/dist/web-ui/assets/PluginsView-xy5NajWq.js +2 -0
  11. package/dist/web-ui/assets/{ProvidersView-BuCzzvhA.js → ProvidersView-M_MSab-K.js} +1 -1
  12. package/dist/web-ui/assets/{ServiceStatusView-BfEtiG3k.js → ServiceStatusView-Dsrz87_B.js} +2 -2
  13. package/dist/web-ui/assets/{SettingsView-C3lfSDLN.js → SettingsView-CwdCfurj.js} +1 -1
  14. package/dist/web-ui/assets/{SetupView-BB5YHhmw.js → SetupView-8ajUBY2H.js} +1 -1
  15. package/dist/web-ui/assets/{config-B3YP6GMt.js → config-_F8xCbJI.js} +1 -1
  16. package/dist/web-ui/assets/format-CPPf8IfM.js +1 -0
  17. package/dist/web-ui/assets/{index-DVkpGX_l.js → index-W7WdLt_5.js} +1 -1
  18. package/dist/web-ui/assets/{message-JXw_u_ps.js → message-DpifAOwJ.js} +1 -1
  19. package/dist/web-ui/assets/providers-CkMtur-C.js +1 -0
  20. package/dist/web-ui/assets/{router-DxY62FPf.js → router-BgTNV93P.js} +2 -2
  21. package/dist/web-ui/assets/{useCopyToast-W6vLjLdg.js → useCopyToast-B_Qvf_Pf.js} +1 -1
  22. package/dist/web-ui/assets/{useManagerApi-7t9qNB2C.js → useManagerApi-USNyi1JZ.js} +1 -1
  23. package/dist/web-ui/assets/{useQuickRangeFilter-BWtDACYs.js → useQuickRangeFilter-DNSnrkx7.js} +1 -1
  24. package/dist/web-ui/assets/useToast-X_JkPDpr.js +1 -0
  25. package/dist/web-ui/index.html +3 -3
  26. package/package.json +1 -1
  27. package/dist/web-ui/assets/LogsView-Ck8cUn2K.js +0 -5
  28. package/dist/web-ui/assets/PluginsView-XtlAtfkK.js +0 -2
  29. package/dist/web-ui/assets/PluginsView-ggYmqCJ8.css +0 -1
  30. package/dist/web-ui/assets/format-7jzqzMS_.js +0 -1
  31. package/dist/web-ui/assets/providers-CbsDigh3.js +0 -1
  32. package/dist/web-ui/assets/src-DLq1gsLr.js +0 -1
  33. package/dist/web-ui/assets/useToast-DgnKZwIF.js +0 -1
@@ -1 +1 @@
1
- import{A as e,F as t,I as n,M as r,O as i,P as a,Pt as o,Q as s,Tt as c,V as l,Wt as u,Z as d,a as f,at as ee,bt as p,et as m,fn as h,ht as te,it as g,j as _,k as v,mt as y,nt as b,sn as ne,vt as x,w as S}from"./router-DxY62FPf.js";import{t as C}from"./useManagerApi-7t9qNB2C.js";import{t as w}from"./providers-CbsDigh3.js";import{n as T,t as E}from"./useCopyToast-W6vLjLdg.js";import{n as D,t as re}from"./useQuickRangeFilter-BWtDACYs.js";import{f as O,n as k,p as A,r as j,t as M,u as N}from"./format-7jzqzMS_.js";x();function ie(e){let{loadError:t,run:n}=T(e),r=c(null);function i(e){let t=async()=>{let i=await n(e);return i?r.value===t&&(r.value=null):r.value=t,i};return t}function a(e){n(r.value??e)}return{loadError:t,track:i,retry:a}}l(),x(),u();var ae={class:`flex-col-gap`},oe={class:`kv-grid`},se={class:`kv-label`},ce={class:`kv-value`},le=[`onClick`],ue={class:`kv-item kv-span-2`},de={class:`kv-value`},fe={key:1,class:`kv-unit`},pe={class:`kv-item`},me={class:`kv-value`},he={class:`kv-unit`},ge={class:`kv-item`},_e={class:`kv-value`},ve={class:`flex-between card-header-wrap`},ye={class:`flex-gap-8`},be={class:`usage-grid`},xe={class:`usage-cell`},Se={class:`usage-num orange`},Ce={class:`usage-cell`},we={class:`usage-num blue`},Te={class:`usage-cell`},Ee={class:`usage-num green`},De={class:`usage-cell`},Oe={class:`usage-num purple`},ke={class:`usage-cell`},Ae={class:`usage-num purple`},je={key:0,class:`usage-cell`},Me={class:`usage-num gray`},Ne={class:`usage-cell`},Pe={class:`usage-num blue`},Fe={class:`usage-cell`},Ie=[`title`],Le={class:`usage-cell`},Re=[`title`],ze={key:0},Be=[`onClick`],Ve=[`title`],He=[`title`],P=n({__name:`DashboardView`,setup(n){let l=w(),{copyWithToast:u}=E(),{loadError:x,track:T,retry:P}=ie(),Ue={local:`本机 API 地址`,lan:`局域网地址`,other:`API 地址`},F=c(null),I=c(!0),L=c(``),{rangeKey:R,dateRange:z,onRangeChange:We}=re(()=>B(),`today`),Ge=()=>{R.value=``,B()},Ke=i(()=>{let e=new Set;for(let t of l.suppliers)for(let n of t.models)e.add(n.modelName);if(F.value?.models)for(let t of F.value.models)e.add(t.model);return[...e].sort()}),qe=D(),B=T(async()=>{let e=qe();I.value=!0;try{let t=new URLSearchParams;L.value&&t.set(`model`,L.value),z.value?.length===2&&(t.set(`startDate`,z.value[0]),t.set(`endDate`,z.value[1]));let n=t.toString(),r=await f.get(`/api/usage${n?`?${n}`:``}`);if(!e())return;F.value=r}catch(t){if(!e())return;throw t}finally{e()&&(I.value=!1)}}),Je=D(),V=T(async()=>{let e=Je();try{await Promise.all([B(),l.loadProviders()])}catch(t){if(!e())return;throw t}finally{e()&&(I.value=!1)}}),Ye=()=>P(V),H=window.location.hostname,U=Number(window.location.port)||null,W=i(()=>j({protocol:window.location.protocol,hostname:H,port:U})),G=c(null),K=c(null),q=c(!1),J=c(!0),Y=c(Date.now()),X=c(null),Z=c([]),Q=i(()=>X.value??U),Xe=e=>j({protocol:`http:`,hostname:e,port:Q.value}),Ze=i(()=>H===`127.0.0.1`||H===`::1`||H===`localhost`?`local`:Z.value.includes(H)?`lan`:`other`),$=i(()=>Q.value?Z.value.map(Xe).filter(e=>e!==W.value):[]),Qe=i(()=>{let e=Q.value?Xe(`127.0.0.1`):``;return e!==``&&e!==W.value?e:``}),$e=i(()=>{let e=[];return Ze.value===`lan`?e.push({label:`局域网地址`,values:[W.value,...$.value]}):(e.push({label:Ue[Ze.value],values:[W.value]}),$.value.length>0&&e.push({label:`局域网地址`,values:$.value})),Qe.value!==``&&e.push({label:`本机 API 地址`,values:[Qe.value]}),e.map((t,n)=>({...t,span2:e.length%2==1&&n===e.length-1}))}),et=async()=>{let[e,t]=await Promise.allSettled([C.processes(),f.get(`/api/status`)]);if(J.value=!1,e.status===`fulfilled`&&(G.value=e.value[0]??null),t.status===`rejected`){K.value=null,q.value=!0;return}let n=t.value?.masterKey;K.value=typeof n==`string`?n:null,q.value=typeof n!=`string`;let r=t.value?.listenPort;X.value=typeof r==`number`&&r>0?r:null;let i=t.value?.lanAddresses;Z.value=Array.isArray(i)?i.filter(e=>typeof e==`string`):[],Y.value=Date.now()},tt=e=>{if(!e.startedAt)return`-`;let t=Math.max(0,Math.floor((Y.value-e.startedAt)/1e3)),n=Math.floor(t/86400);t-=n*86400;let r=Math.floor(t/3600);t-=r*3600;let i=Math.floor(t/60);return t-=i*60,[n?`${n}天`:``,r?`${r}时`:``,i?`${i}分`:``,`${t}秒`].filter(Boolean).join(` `)},nt=i(()=>q.value?`获取失败,请刷新重试`:K.value===null?`-`:`未设置(/v1 免鉴权)`),rt;return d(()=>{V(),et(),rt=window.setInterval(et,1e4)}),s(()=>window.clearInterval(rt)),(n,i)=>{let s=g(`el-button`),c=g(`el-alert`),l=g(`el-card`),d=g(`el-option`),f=g(`el-select`),C=g(`el-date-picker`),w=g(`el-table-column`),T=g(`el-table`),E=g(`el-empty`),D=ee(`loading`);return m(),r(`div`,ae,[o(x)?(m(),e(c,{key:0,title:o(x),type:`error`,"show-icon":``,closable:!1},{default:y(()=>[t(s,{size:`small`,onClick:Ye},{default:y(()=>[...i[4]||=[a(`重试`,-1)]]),_:1})]),_:1},8,[`title`])):_(``,!0),t(l,{shadow:`never`},{header:y(()=>[...i[5]||=[v(`span`,{class:`fw-600`},`服务信息`,-1)]]),default:y(()=>[te((m(),r(`div`,oe,[(m(!0),r(S,null,b($e.value,e=>(m(),r(`div`,{key:e.label+e.values[0],class:ne([`kv-item`,{"kv-span-2":e.span2}])},[v(`div`,se,h(e.label),1),v(`div`,ce,[(m(!0),r(S,null,b(e.values,e=>(m(),r(`div`,{key:e},[v(`span`,{class:`copy-text`,onClick:t=>o(u)(e)},h(e),9,le)]))),128))])],2))),128)),v(`div`,ue,[i[6]||=v(`div`,{class:`kv-label`},`API 密钥`,-1),v(`div`,de,[K.value?(m(),r(`span`,{key:0,class:`copy-text`,onClick:i[0]||=e=>o(u)(K.value)},h(K.value),1)):_(``,!0),K.value?(m(),r(`span`,fe,`(/v1 需 Bearer 认证)`)):(m(),r(S,{key:2},[a(h(nt.value),1)],64))])]),v(`div`,pe,[i[9]||=v(`div`,{class:`kv-label`},`运行状态`,-1),v(`div`,me,[G.value?(m(),r(S,{key:0},[i[7]||=v(`span`,{class:`status-dot running`},null,-1),i[8]||=a(`运行中 `,-1),v(`span`,he,`PID `+h(G.value.pid??`-`),1)],64)):(m(),r(S,{key:1},[a(`-`)],64))])]),v(`div`,ge,[i[10]||=v(`div`,{class:`kv-label`},`运行时长`,-1),v(`div`,_e,h(G.value?tt(G.value):`-`),1)])])),[[D,I.value||J.value]])]),_:1}),F.value?(m(),e(l,{key:1,shadow:`never`},{header:y(()=>[v(`div`,ve,[i[12]||=v(`span`,{class:`fw-600`},`用量统计`,-1),v(`div`,ye,[t(f,{modelValue:L.value,"onUpdate:modelValue":i[1]||=e=>L.value=e,placeholder:`全部模型`,clearable:``,filterable:``,style:{width:`220px`},onChange:o(B)},{default:y(()=>[(m(!0),r(S,null,b(Ke.value,t=>(m(),e(d,{key:t,label:t,value:t},null,8,[`label`,`value`]))),128))]),_:1},8,[`modelValue`,`onChange`]),t(f,{modelValue:o(R),"onUpdate:modelValue":i[2]||=e=>p(R)?R.value=e:null,placeholder:`时间范围`,clearable:``,style:{width:`130px`},onChange:o(We)},{default:y(()=>[t(d,{label:`今天`,value:`today`}),t(d,{label:`昨天`,value:`yesterday`}),t(d,{label:`前天`,value:`beforeYesterday`}),t(d,{label:`近三天`,value:`last3days`}),t(d,{label:`本周`,value:`week`}),t(d,{label:`本月`,value:`month`})]),_:1},8,[`modelValue`,`onChange`]),t(C,{modelValue:o(z),"onUpdate:modelValue":i[3]||=e=>p(z)?z.value=e:null,type:`daterange`,"range-separator":`至`,"start-placeholder":`开始日期`,"end-placeholder":`结束日期`,"value-format":`YYYY-MM-DD`,style:{width:`260px`},onChange:Ge},null,8,[`modelValue`]),t(s,{loading:I.value,onClick:o(B)},{default:y(()=>[...i[11]||=[a(`刷新`,-1)]]),_:1},8,[`loading`,`onClick`])])])]),default:y(()=>[v(`div`,be,[v(`div`,xe,[v(`div`,Se,h(o(O)(F.value.total.total_tokens)),1),i[13]||=v(`div`,{class:`usage-label`},`总 Token`,-1)]),v(`div`,Ce,[v(`div`,we,h(o(O)(F.value.total.input_tokens)),1),i[14]||=v(`div`,{class:`usage-label`},`输入 Token`,-1)]),v(`div`,Te,[v(`div`,Ee,h(o(O)(F.value.total.output_tokens)),1),i[15]||=v(`div`,{class:`usage-label`},`输出 Token`,-1)]),v(`div`,De,[v(`div`,Oe,h(o(O)(F.value.total.cache_read_tokens)),1),i[16]||=v(`div`,{class:`usage-label`},`缓存读取`,-1)]),v(`div`,ke,[v(`div`,Ae,h(F.value.total.cache_rate==null?`-`:F.value.total.cache_rate+`%`),1),i[17]||=v(`div`,{class:`usage-label`},`缓存命中率`,-1)]),F.value.logStorageMB==null?_(``,!0):(m(),r(`div`,je,[v(`div`,Me,h(F.value.logStorageMB),1),i[18]||=v(`div`,{class:`usage-label`},`数据目录占用 (MB)`,-1)])),v(`div`,Ne,[v(`div`,Pe,h(o(N)(F.value.total.avg_duration)),1),i[19]||=v(`div`,{class:`usage-label`},`平均耗时`,-1)]),v(`div`,Fe,[v(`div`,{class:`usage-num blue`,title:o(k)},h(o(N)(F.value.total.avg_ttft)),9,Ie),i[20]||=v(`div`,{class:`usage-label`},`平均首 Token`,-1)]),v(`div`,Le,[v(`div`,{class:`usage-num green`,title:o(M)},h(o(A)(F.value.total.tps)),9,Re),i[21]||=v(`div`,{class:`usage-label`},`平均生成速度`,-1)])]),F.value.models?.length?(m(),r(`div`,ze,[i[22]||=v(`div`,{class:`section-title`},`模型用量`,-1),t(T,{data:F.value.models,stripe:``,class:`full-width`},{default:y(()=>[t(w,{prop:`model`,label:`模型`,"min-width":`200`},{default:y(({row:e})=>[v(`span`,{class:`copy-text`,onClick:t=>o(u)(e.model)},h(e.model),9,Be)]),_:1}),t(w,{label:`调用次数`,width:`90`,align:`center`},{default:y(({row:e})=>[a(h(e.calls),1)]),_:1}),t(w,{label:`平均耗时`,width:`110`,align:`center`},{default:y(({row:e})=>[a(h(o(N)(e.avg_duration)),1)]),_:1}),t(w,{label:`速度`,width:`130`,align:`center`},{default:y(({row:e})=>[v(`div`,{title:o(M)},h(o(A)(e.tps)),9,Ve),e.avg_ttft==null?_(``,!0):(m(),r(`div`,{key:0,class:`cell-sub`,title:o(k)},` 首 `+h(o(N)(e.avg_ttft)),9,He))]),_:1}),t(w,{label:`总 Token`,width:`140`,align:`center`},{default:y(({row:e})=>[a(h(o(O)(e.total_tokens)),1)]),_:1}),t(w,{label:`输入 Token`,width:`140`,align:`center`},{default:y(({row:e})=>[a(h(o(O)(e.input_tokens)),1)]),_:1}),t(w,{label:`输出 Token`,width:`140`,align:`center`},{default:y(({row:e})=>[a(h(o(O)(e.output_tokens)),1)]),_:1}),t(w,{label:`缓存读取`,width:`130`,align:`center`},{default:y(({row:e})=>[a(h(o(O)(e.cache_read_tokens)),1)]),_:1}),t(w,{label:`缓存命中率`,width:`110`,align:`center`},{default:y(({row:e})=>[a(h(e.cache_rate==null?`-`:e.cache_rate+`%`),1)]),_:1})]),_:1},8,[`data`])])):(m(),e(E,{key:1,description:`暂无调用记录`,"image-size":60}))]),_:1})):_(``,!0)])}}});export{P as default};
1
+ import{A as e,F as t,I as n,M as r,O as i,P as a,Pt as o,Q as s,Tt as c,V as l,Wt as u,Z as d,a as f,at as ee,bt as p,et as m,fn as h,ht as te,it as g,j as _,k as v,mt as y,nt as b,sn as ne,vt as x,w as S}from"./router-BgTNV93P.js";import{t as C}from"./useManagerApi-USNyi1JZ.js";import{t as w}from"./providers-CkMtur-C.js";import{n as T,t as E}from"./useCopyToast-B_Qvf_Pf.js";import{n as D,t as re}from"./useQuickRangeFilter-DNSnrkx7.js";import{d as O,f as k,i as A,l as j,n as M,r as N}from"./format-CPPf8IfM.js";x();function ie(e){let{loadError:t,run:n}=T(e),r=c(null);function i(e){let t=async()=>{let i=await n(e);return i?r.value===t&&(r.value=null):r.value=t,i};return t}function a(e){n(r.value??e)}return{loadError:t,track:i,retry:a}}l(),x(),u();var ae={class:`flex-col-gap`},oe={class:`kv-grid`},se={class:`kv-label`},ce={class:`kv-value`},le=[`onClick`],ue={class:`kv-item kv-span-2`},de={class:`kv-value`},fe={key:1,class:`kv-unit`},pe={class:`kv-item`},me={class:`kv-value`},he={class:`kv-unit`},ge={class:`kv-item`},_e={class:`kv-value`},ve={class:`flex-between card-header-wrap`},ye={class:`flex-gap-8`},be={class:`usage-grid`},xe={class:`usage-cell`},Se={class:`usage-num orange`},Ce={class:`usage-cell`},we={class:`usage-num blue`},Te={class:`usage-cell`},Ee={class:`usage-num green`},De={class:`usage-cell`},Oe={class:`usage-num purple`},ke={class:`usage-cell`},Ae={class:`usage-num purple`},je={key:0,class:`usage-cell`},Me={class:`usage-num gray`},Ne={class:`usage-cell`},Pe={class:`usage-num blue`},Fe={class:`usage-cell`},Ie=[`title`],Le={class:`usage-cell`},Re=[`title`],ze={key:0},Be=[`onClick`],Ve=[`title`],He=[`title`],P=n({__name:`DashboardView`,setup(n){let l=w(),{copyWithToast:u}=E(),{loadError:x,track:T,retry:P}=ie(),Ue={local:`本机 API 地址`,lan:`局域网地址`,other:`API 地址`},F=c(null),I=c(!0),L=c(``),{rangeKey:R,dateRange:z,onRangeChange:We}=re(()=>B(),`today`),Ge=()=>{R.value=``,B()},Ke=i(()=>{let e=new Set;for(let t of l.suppliers)for(let n of t.models)e.add(n.modelName);if(F.value?.models)for(let t of F.value.models)e.add(t.model);return[...e].sort()}),qe=D(),B=T(async()=>{let e=qe();I.value=!0;try{let t=new URLSearchParams;L.value&&t.set(`model`,L.value),z.value?.length===2&&(t.set(`startDate`,z.value[0]),t.set(`endDate`,z.value[1]));let n=t.toString(),r=await f.get(`/api/usage${n?`?${n}`:``}`);if(!e())return;F.value=r}catch(t){if(!e())return;throw t}finally{e()&&(I.value=!1)}}),Je=D(),V=T(async()=>{let e=Je();try{await Promise.all([B(),l.loadProviders()])}catch(t){if(!e())return;throw t}finally{e()&&(I.value=!1)}}),Ye=()=>P(V),H=window.location.hostname,U=Number(window.location.port)||null,W=i(()=>A({protocol:window.location.protocol,hostname:H,port:U})),G=c(null),K=c(null),q=c(!1),J=c(!0),Y=c(Date.now()),X=c(null),Z=c([]),Q=i(()=>X.value??U),Xe=e=>A({protocol:`http:`,hostname:e,port:Q.value}),Ze=i(()=>H===`127.0.0.1`||H===`::1`||H===`localhost`?`local`:Z.value.includes(H)?`lan`:`other`),$=i(()=>Q.value?Z.value.map(Xe).filter(e=>e!==W.value):[]),Qe=i(()=>{let e=Q.value?Xe(`127.0.0.1`):``;return e!==``&&e!==W.value?e:``}),$e=i(()=>{let e=[];return Ze.value===`lan`?e.push({label:`局域网地址`,values:[W.value,...$.value]}):(e.push({label:Ue[Ze.value],values:[W.value]}),$.value.length>0&&e.push({label:`局域网地址`,values:$.value})),Qe.value!==``&&e.push({label:`本机 API 地址`,values:[Qe.value]}),e.map((t,n)=>({...t,span2:e.length%2==1&&n===e.length-1}))}),et=async()=>{let[e,t]=await Promise.allSettled([C.processes(),f.get(`/api/status`)]);if(J.value=!1,e.status===`fulfilled`&&(G.value=e.value[0]??null),t.status===`rejected`){K.value=null,q.value=!0;return}let n=t.value?.masterKey;K.value=typeof n==`string`?n:null,q.value=typeof n!=`string`;let r=t.value?.listenPort;X.value=typeof r==`number`&&r>0?r:null;let i=t.value?.lanAddresses;Z.value=Array.isArray(i)?i.filter(e=>typeof e==`string`):[],Y.value=Date.now()},tt=e=>{if(!e.startedAt)return`-`;let t=Math.max(0,Math.floor((Y.value-e.startedAt)/1e3)),n=Math.floor(t/86400);t-=n*86400;let r=Math.floor(t/3600);t-=r*3600;let i=Math.floor(t/60);return t-=i*60,[n?`${n}天`:``,r?`${r}时`:``,i?`${i}分`:``,`${t}秒`].filter(Boolean).join(` `)},nt=i(()=>q.value?`获取失败,请刷新重试`:K.value===null?`-`:`未设置(/v1 免鉴权)`),rt;return d(()=>{V(),et(),rt=window.setInterval(et,1e4)}),s(()=>window.clearInterval(rt)),(n,i)=>{let s=g(`el-button`),c=g(`el-alert`),l=g(`el-card`),d=g(`el-option`),f=g(`el-select`),C=g(`el-date-picker`),w=g(`el-table-column`),T=g(`el-table`),E=g(`el-empty`),D=ee(`loading`);return m(),r(`div`,ae,[o(x)?(m(),e(c,{key:0,title:o(x),type:`error`,"show-icon":``,closable:!1},{default:y(()=>[t(s,{size:`small`,onClick:Ye},{default:y(()=>[...i[4]||=[a(`重试`,-1)]]),_:1})]),_:1},8,[`title`])):_(``,!0),t(l,{shadow:`never`},{header:y(()=>[...i[5]||=[v(`span`,{class:`fw-600`},`服务信息`,-1)]]),default:y(()=>[te((m(),r(`div`,oe,[(m(!0),r(S,null,b($e.value,e=>(m(),r(`div`,{key:e.label+e.values[0],class:ne([`kv-item`,{"kv-span-2":e.span2}])},[v(`div`,se,h(e.label),1),v(`div`,ce,[(m(!0),r(S,null,b(e.values,e=>(m(),r(`div`,{key:e},[v(`span`,{class:`copy-text`,onClick:t=>o(u)(e)},h(e),9,le)]))),128))])],2))),128)),v(`div`,ue,[i[6]||=v(`div`,{class:`kv-label`},`API 密钥`,-1),v(`div`,de,[K.value?(m(),r(`span`,{key:0,class:`copy-text`,onClick:i[0]||=e=>o(u)(K.value)},h(K.value),1)):_(``,!0),K.value?(m(),r(`span`,fe,`(/v1 需 Bearer 认证)`)):(m(),r(S,{key:2},[a(h(nt.value),1)],64))])]),v(`div`,pe,[i[9]||=v(`div`,{class:`kv-label`},`运行状态`,-1),v(`div`,me,[G.value?(m(),r(S,{key:0},[i[7]||=v(`span`,{class:`status-dot running`},null,-1),i[8]||=a(`运行中 `,-1),v(`span`,he,`PID `+h(G.value.pid??`-`),1)],64)):(m(),r(S,{key:1},[a(`-`)],64))])]),v(`div`,ge,[i[10]||=v(`div`,{class:`kv-label`},`运行时长`,-1),v(`div`,_e,h(G.value?tt(G.value):`-`),1)])])),[[D,I.value||J.value]])]),_:1}),F.value?(m(),e(l,{key:1,shadow:`never`},{header:y(()=>[v(`div`,ve,[i[12]||=v(`span`,{class:`fw-600`},`用量统计`,-1),v(`div`,ye,[t(f,{modelValue:L.value,"onUpdate:modelValue":i[1]||=e=>L.value=e,placeholder:`全部模型`,clearable:``,filterable:``,style:{width:`220px`},onChange:o(B)},{default:y(()=>[(m(!0),r(S,null,b(Ke.value,t=>(m(),e(d,{key:t,label:t,value:t},null,8,[`label`,`value`]))),128))]),_:1},8,[`modelValue`,`onChange`]),t(f,{modelValue:o(R),"onUpdate:modelValue":i[2]||=e=>p(R)?R.value=e:null,placeholder:`时间范围`,clearable:``,style:{width:`130px`},onChange:o(We)},{default:y(()=>[t(d,{label:`今天`,value:`today`}),t(d,{label:`昨天`,value:`yesterday`}),t(d,{label:`前天`,value:`beforeYesterday`}),t(d,{label:`近三天`,value:`last3days`}),t(d,{label:`本周`,value:`week`}),t(d,{label:`本月`,value:`month`})]),_:1},8,[`modelValue`,`onChange`]),t(C,{modelValue:o(z),"onUpdate:modelValue":i[3]||=e=>p(z)?z.value=e:null,type:`daterange`,"range-separator":`至`,"start-placeholder":`开始日期`,"end-placeholder":`结束日期`,"value-format":`YYYY-MM-DD`,style:{width:`260px`},onChange:Ge},null,8,[`modelValue`]),t(s,{loading:I.value,onClick:o(B)},{default:y(()=>[...i[11]||=[a(`刷新`,-1)]]),_:1},8,[`loading`,`onClick`])])])]),default:y(()=>[v(`div`,be,[v(`div`,xe,[v(`div`,Se,h(o(O)(F.value.total.total_tokens)),1),i[13]||=v(`div`,{class:`usage-label`},`总 Token`,-1)]),v(`div`,Ce,[v(`div`,we,h(o(O)(F.value.total.input_tokens)),1),i[14]||=v(`div`,{class:`usage-label`},`输入 Token`,-1)]),v(`div`,Te,[v(`div`,Ee,h(o(O)(F.value.total.output_tokens)),1),i[15]||=v(`div`,{class:`usage-label`},`输出 Token`,-1)]),v(`div`,De,[v(`div`,Oe,h(o(O)(F.value.total.cache_read_tokens)),1),i[16]||=v(`div`,{class:`usage-label`},`缓存读取`,-1)]),v(`div`,ke,[v(`div`,Ae,h(F.value.total.cache_rate==null?`-`:F.value.total.cache_rate+`%`),1),i[17]||=v(`div`,{class:`usage-label`},`缓存命中率`,-1)]),F.value.logStorageMB==null?_(``,!0):(m(),r(`div`,je,[v(`div`,Me,h(F.value.logStorageMB),1),i[18]||=v(`div`,{class:`usage-label`},`数据目录占用 (MB)`,-1)])),v(`div`,Ne,[v(`div`,Pe,h(o(j)(F.value.total.avg_duration)),1),i[19]||=v(`div`,{class:`usage-label`},`平均耗时`,-1)]),v(`div`,Fe,[v(`div`,{class:`usage-num blue`,title:o(N)},h(o(j)(F.value.total.avg_ttft)),9,Ie),i[20]||=v(`div`,{class:`usage-label`},`平均首 Token`,-1)]),v(`div`,Le,[v(`div`,{class:`usage-num green`,title:o(M)},h(o(k)(F.value.total.tps)),9,Re),i[21]||=v(`div`,{class:`usage-label`},`平均生成速度`,-1)])]),F.value.models?.length?(m(),r(`div`,ze,[i[22]||=v(`div`,{class:`section-title`},`模型用量`,-1),t(T,{data:F.value.models,stripe:``,class:`full-width`},{default:y(()=>[t(w,{prop:`model`,label:`模型`,"min-width":`200`},{default:y(({row:e})=>[v(`span`,{class:`copy-text`,onClick:t=>o(u)(e.model)},h(e.model),9,Be)]),_:1}),t(w,{label:`调用次数`,width:`90`,align:`center`},{default:y(({row:e})=>[a(h(e.calls),1)]),_:1}),t(w,{label:`平均耗时`,width:`110`,align:`center`},{default:y(({row:e})=>[a(h(o(j)(e.avg_duration)),1)]),_:1}),t(w,{label:`速度`,width:`130`,align:`center`},{default:y(({row:e})=>[v(`div`,{title:o(M)},h(o(k)(e.tps)),9,Ve),e.avg_ttft==null?_(``,!0):(m(),r(`div`,{key:0,class:`cell-sub`,title:o(N)},` 首 `+h(o(j)(e.avg_ttft)),9,He))]),_:1}),t(w,{label:`总 Token`,width:`140`,align:`center`},{default:y(({row:e})=>[a(h(o(O)(e.total_tokens)),1)]),_:1}),t(w,{label:`输入 Token`,width:`140`,align:`center`},{default:y(({row:e})=>[a(h(o(O)(e.input_tokens)),1)]),_:1}),t(w,{label:`输出 Token`,width:`140`,align:`center`},{default:y(({row:e})=>[a(h(o(O)(e.output_tokens)),1)]),_:1}),t(w,{label:`缓存读取`,width:`130`,align:`center`},{default:y(({row:e})=>[a(h(o(O)(e.cache_read_tokens)),1)]),_:1}),t(w,{label:`缓存命中率`,width:`110`,align:`center`},{default:y(({row:e})=>[a(h(e.cache_rate==null?`-`:e.cache_rate+`%`),1)]),_:1})]),_:1},8,[`data`])])):(m(),e(E,{key:1,description:`暂无调用记录`,"image-size":60}))]),_:1})):_(``,!0)])}}});export{P as default};
@@ -1 +1 @@
1
- import{A as e,F as t,I as n,M as r,O as i,P as a,Pt as o,Tt as s,V as c,Wt as l,Z as u,at as d,et as f,fn as p,ht as m,i as h,it as g,j as _,k as v,l as y,lt as b,mt as x,n as S,o as C,u as w,vt as T,w as E}from"./router-DxY62FPf.js";import{m as D}from"./message-JXw_u_ps.js";import{n as O,t as k}from"./index-DVkpGX_l.js";import{n as A,t as j}from"./useManagerApi-7t9qNB2C.js";import{t as M}from"./useToast-DgnKZwIF.js";import{t as N}from"./updateNote-CttDt8SZ.js";c(),l(),T();var P={class:`check-body`},F={class:`version-row`},I={class:`version-row`},L={class:`muted-sm`},R=k(n({__name:`UpdateCheckDialog`,props:{modelValue:{type:Boolean,default:!1},modelModifiers:{}},emits:[`update:modelValue`],setup(n){let{toast:o}=M(),c=b(n,`modelValue`),l=s(!1),u=s(!1),y=s(null),S=s(null),C=i(()=>h.value?.buildSource===`local`),w=s(null),T=s(null),D=null,k=()=>D?.abort(),R=e=>new Date(e).toLocaleString(),z=e=>`https://www.npmjs.com/package/ezllm/v/${e}`,B=async()=>{S.value=null,w.value=null,T.value=null,l.value=!0;try{let e=await j.update();if(y.value=e,!e.supported)return;S.value=await j.checkUpdate()}catch(e){w.value=e.message||`检查更新失败`}finally{l.value=!1}},V=async()=>{if(!S.value)return;let e=S.value.latestVersion;try{await O.confirm(`确定更新到 ${e}?服务会自动重启并在启动时安装新版本:重启期间管理台短暂不可访问(预计 1~3 分钟),完成后自动恢复。`,`立即更新`,{confirmButtonText:`立即更新`,cancelButtonText:`取消`,type:`warning`})}catch{return}u.value=!0;let t=new AbortController;D=t;try{let e=await j.update(),n=await j.applyUpdate();if(!n.updated){T.value=`已是最新版本 ${n.fromVersion}`,S.value={hasUpdate:!1,currentVersion:n.fromVersion,latestVersion:n.fromVersion,checkedAt:Date.now()};return}T.value=`正在重启服务并安装 ${n.toVersion}(预计 1~3 分钟):重启期间管理台短暂不可访问,完成后这里会自动显示结果。`;let r=await A({targetVersion:n.toVersion,sinceAppliedAt:e.lastApply?.appliedAt??null,signal:t.signal});if(t.signal.aborted)return;r&&!r.error?(o(`已更新到 ${r.toVersion}`,`success`),T.value=`已更新 ${r.fromVersion} → ${r.toVersion},服务已在新版本上运行。`,S.value={hasUpdate:!1,currentVersion:r.toVersion,latestVersion:r.toVersion,checkedAt:Date.now()}):r?.error?(o(`更新失败:${r.error}`,`error`),T.value=N(r.error)):T.value=`更新仍在进行(安装耗时较长):稍后刷新页面查看最新状态。`}catch(e){o(e.message||`更新失败`,`error`)}finally{u.value=!1,D===t&&(D=null)}};return(n,i)=>{let o=g(`el-alert`),s=g(`el-tag`),h=g(`el-link`),b=g(`el-button`),D=g(`el-dialog`),O=d(`loading`);return f(),e(D,{modelValue:c.value,"onUpdate:modelValue":i[2]||=e=>c.value=e,title:`检查更新`,width:`420px`,"close-on-click-modal":!u.value,onOpen:B,onClose:k},{footer:x(()=>[S.value?.hasUpdate?(f(),e(b,{key:0,type:`primary`,loading:u.value,onClick:V},{default:x(()=>[a(p(u.value?`更新中...`:`立即更新`),1)]),_:1},8,[`loading`])):_(``,!0),t(b,{onClick:i[1]||=e=>c.value=!1},{default:x(()=>[...i[11]||=[a(`关闭`,-1)]]),_:1})]),default:x(()=>[m((f(),r(`div`,P,[y.value&&!y.value.supported?(f(),e(o,{key:0,title:`当前为源码运行模式,更新功能不可用`,type:`info`,"show-icon":``,closable:!1},{default:x(()=>[...i[3]||=[v(`div`,{class:`alert-hint`},[a(` 仅通过 npx ezllm install 装配的实例支持更新检查。本地开发用仓库里的 `),v(`code`,null,`pnpm upgrade:local`),a(` 更新运行中的服务。 `)],-1)]]),_:1})):S.value?(f(),r(E,{key:1},[v(`div`,F,[i[5]||=v(`span`,{class:`version-label`},`当前版本`,-1),t(s,{size:`small`},{default:x(()=>[a(p(S.value.currentVersion),1)]),_:1}),C.value?(f(),e(s,{key:0,type:`warning`,size:`small`,"disable-transitions":``},{default:x(()=>[...i[4]||=[a(`本地构建`,-1)]]),_:1})):_(``,!0)]),v(`div`,I,[i[6]||=v(`span`,{class:`version-label`},`最新版本`,-1),t(s,{type:S.value.hasUpdate?`warning`:`success`,size:`small`,"disable-transitions":``},{default:x(()=>[a(p(S.value.latestVersion),1)]),_:1},8,[`type`])]),t(o,{title:S.value.hasUpdate?`发现新版本 ${S.value.latestVersion}(当前 ${S.value.currentVersion})`:`已是最新版本 ${S.value.currentVersion}`,type:S.value.hasUpdate?`warning`:`success`,"show-icon":``,closable:!1,class:`mt-12`},null,8,[`title`,`type`]),v(`div`,L,[a(` 检查时间:`+p(R(S.value.checkedAt))+` `,1),S.value.hasUpdate?(f(),r(E,{key:0},[i[8]||=a(` · `,-1),t(h,{type:`primary`,href:z(S.value.latestVersion),target:`_blank`},{default:x(()=>[...i[7]||=[a(`在 npm 查看该版本`,-1)]]),_:1},8,[`href`])],64)):_(``,!0)])],64)):!l.value&&w.value?(f(),e(o,{key:2,title:w.value,type:`error`,"show-icon":``,closable:!1},{default:x(()=>[i[10]||=v(`div`,{class:`alert-hint`},` 检查需访问 npm 源,可能是网络不可达或版本号解析失败;稍后重试即可。 `,-1),t(b,{size:`small`,class:`mt-8`,onClick:B},{default:x(()=>[...i[9]||=[a(`重试`,-1)]]),_:1})]),_:1},8,[`title`])):_(``,!0)])),[[O,l.value]]),T.value?(f(),e(o,{key:0,title:T.value,type:`info`,"show-icon":``,class:`mt-12`,onClose:i[0]||=e=>T.value=null},null,8,[`title`])):_(``,!0)]),_:1},8,[`modelValue`,`close-on-click-modal`])}}}),[[`__scopeId`,`data-v-5e671468`]]);c(),l(),T();var z={class:`layout`},B=[`title`],V={key:0,class:`header-version-tag`},H={class:`header-nav`},U={class:`header-actions`},W={class:`user-chip`},G={class:`user-avatar`},K={class:`user-name`},q={class:`main`},J={class:`page`},Y=k(n({__name:`LayoutView`,setup(n){let c=y(),l=w(),d=s(!1);u(()=>{S()});let m=i(()=>h.value?.version||``),b=i(()=>h.value?.buildSource===`local`),T=i(()=>b.value?`本地构建版本(upgrade:local 产物)`:`当前运行版本`),E=i(()=>h.value?.authRequired!==!1),O=i(()=>{if(!E.value)return`免登录`;let e=localStorage.getItem(`webui_token`)||``;try{return atob(e).split(`:`)[0]||`用户`}catch{return`用户`}}),k=i(()=>{let e=c.path;return e===`/`?`/`:e.startsWith(`/providers`)?`/providers`:e.startsWith(`/service-status`)?`/service-status`:e.startsWith(`/managed-services`)?`/managed-services`:e.startsWith(`/settings`)?`/settings`:e.startsWith(`/logs`)?`/logs`:`/`}),A=e=>{e===`logout`&&(C(),l.push(`/login`)),e===`check-update`&&(d.value=!0)};return(n,i)=>{let s=g(`el-menu-item`),c=g(`el-menu`),l=g(`el-icon`),u=g(`el-dropdown-item`),h=g(`el-dropdown-menu`),y=g(`el-dropdown`),S=g(`el-header`),C=g(`router-view`);return f(),r(`div`,z,[t(S,{class:`header`},{default:x(()=>[i[10]||=v(`div`,{class:`brand`},[v(`span`,{class:`brand-mark`},`EZ`),v(`h1`,null,`LLM`)],-1),m.value?(f(),r(`span`,{key:0,class:`header-version`,title:T.value},[a(` v`+p(m.value),1),b.value?(f(),r(`span`,V,`本地构建`)):_(``,!0)],8,B)):_(``,!0),v(`nav`,H,[t(c,{mode:`horizontal`,"default-active":k.value,ellipsis:!1,router:``,class:`header-menu`},{default:x(()=>[t(s,{index:`/`},{default:x(()=>[...i[1]||=[a(`首页`,-1)]]),_:1}),t(s,{index:`/providers`},{default:x(()=>[...i[2]||=[a(`供应商管理`,-1)]]),_:1}),t(s,{index:`/service-status`},{default:x(()=>[...i[3]||=[a(`服务状态`,-1)]]),_:1}),t(s,{index:`/managed-services`},{default:x(()=>[...i[4]||=[a(`托管服务`,-1)]]),_:1}),t(s,{index:`/plugins`},{default:x(()=>[...i[5]||=[a(`插件`,-1)]]),_:1}),t(s,{index:`/logs`},{default:x(()=>[...i[6]||=[a(`日志`,-1)]]),_:1}),t(s,{index:`/settings`},{default:x(()=>[...i[7]||=[a(`设置`,-1)]]),_:1})]),_:1},8,[`default-active`])]),v(`div`,U,[t(y,{trigger:`click`,onCommand:A,class:`ml-12`},{dropdown:x(()=>[t(h,null,{default:x(()=>[t(u,{command:`check-update`},{default:x(()=>[...i[8]||=[a(`检查更新`,-1)]]),_:1}),E.value?(f(),e(u,{key:0,command:`logout`,divided:``},{default:x(()=>[...i[9]||=[a(`退出`,-1)]]),_:1})):_(``,!0)]),_:1})]),default:x(()=>[v(`div`,W,[v(`span`,G,p(O.value.charAt(0).toUpperCase()),1),v(`span`,K,p(O.value),1),t(l,{class:`el-icon--right`},{default:x(()=>[t(o(D))]),_:1})])]),_:1})])]),_:1}),v(`main`,q,[v(`div`,J,[t(C)])]),t(R,{modelValue:d.value,"onUpdate:modelValue":i[0]||=e=>d.value=e},null,8,[`modelValue`])])}}}),[[`__scopeId`,`data-v-4e7e0e0d`]]);export{Y as default};
1
+ import{A as e,F as t,I as n,M as r,O as i,P as a,Pt as o,Tt as s,V as c,Wt as l,Z as u,at as d,et as f,fn as p,ht as m,i as h,it as g,j as _,k as v,l as y,lt as b,mt as x,n as S,o as C,u as w,vt as T,w as E}from"./router-BgTNV93P.js";import{m as D}from"./message-DpifAOwJ.js";import{n as O,t as k}from"./index-W7WdLt_5.js";import{n as A,t as j}from"./useManagerApi-USNyi1JZ.js";import{t as M}from"./useToast-X_JkPDpr.js";import{t as N}from"./updateNote-CttDt8SZ.js";c(),l(),T();var P={class:`check-body`},F={class:`version-row`},I={class:`version-row`},L={class:`muted-sm`},R=k(n({__name:`UpdateCheckDialog`,props:{modelValue:{type:Boolean,default:!1},modelModifiers:{}},emits:[`update:modelValue`],setup(n){let{toast:o}=M(),c=b(n,`modelValue`),l=s(!1),u=s(!1),y=s(null),S=s(null),C=i(()=>h.value?.buildSource===`local`),w=s(null),T=s(null),D=null,k=()=>D?.abort(),R=e=>new Date(e).toLocaleString(),z=e=>`https://www.npmjs.com/package/ezllm/v/${e}`,B=async()=>{S.value=null,w.value=null,T.value=null,l.value=!0;try{let e=await j.update();if(y.value=e,!e.supported)return;S.value=await j.checkUpdate()}catch(e){w.value=e.message||`检查更新失败`}finally{l.value=!1}},V=async()=>{if(!S.value)return;let e=S.value.latestVersion;try{await O.confirm(`确定更新到 ${e}?服务会自动重启并在启动时安装新版本:重启期间管理台短暂不可访问(预计 1~3 分钟),完成后自动恢复。`,`立即更新`,{confirmButtonText:`立即更新`,cancelButtonText:`取消`,type:`warning`})}catch{return}u.value=!0;let t=new AbortController;D=t;try{let e=await j.update(),n=await j.applyUpdate();if(!n.updated){T.value=`已是最新版本 ${n.fromVersion}`,S.value={hasUpdate:!1,currentVersion:n.fromVersion,latestVersion:n.fromVersion,checkedAt:Date.now()};return}T.value=`正在重启服务并安装 ${n.toVersion}(预计 1~3 分钟):重启期间管理台短暂不可访问,完成后这里会自动显示结果。`;let r=await A({targetVersion:n.toVersion,sinceAppliedAt:e.lastApply?.appliedAt??null,signal:t.signal});if(t.signal.aborted)return;r&&!r.error?(o(`已更新到 ${r.toVersion}`,`success`),T.value=`已更新 ${r.fromVersion} → ${r.toVersion},服务已在新版本上运行。`,S.value={hasUpdate:!1,currentVersion:r.toVersion,latestVersion:r.toVersion,checkedAt:Date.now()}):r?.error?(o(`更新失败:${r.error}`,`error`),T.value=N(r.error)):T.value=`更新仍在进行(安装耗时较长):稍后刷新页面查看最新状态。`}catch(e){o(e.message||`更新失败`,`error`)}finally{u.value=!1,D===t&&(D=null)}};return(n,i)=>{let o=g(`el-alert`),s=g(`el-tag`),h=g(`el-link`),b=g(`el-button`),D=g(`el-dialog`),O=d(`loading`);return f(),e(D,{modelValue:c.value,"onUpdate:modelValue":i[2]||=e=>c.value=e,title:`检查更新`,width:`420px`,"close-on-click-modal":!u.value,onOpen:B,onClose:k},{footer:x(()=>[S.value?.hasUpdate?(f(),e(b,{key:0,type:`primary`,loading:u.value,onClick:V},{default:x(()=>[a(p(u.value?`更新中...`:`立即更新`),1)]),_:1},8,[`loading`])):_(``,!0),t(b,{onClick:i[1]||=e=>c.value=!1},{default:x(()=>[...i[11]||=[a(`关闭`,-1)]]),_:1})]),default:x(()=>[m((f(),r(`div`,P,[y.value&&!y.value.supported?(f(),e(o,{key:0,title:`当前为源码运行模式,更新功能不可用`,type:`info`,"show-icon":``,closable:!1},{default:x(()=>[...i[3]||=[v(`div`,{class:`alert-hint`},[a(` 仅通过 npx ezllm install 装配的实例支持更新检查。本地开发用仓库里的 `),v(`code`,null,`pnpm upgrade:local`),a(` 更新运行中的服务。 `)],-1)]]),_:1})):S.value?(f(),r(E,{key:1},[v(`div`,F,[i[5]||=v(`span`,{class:`version-label`},`当前版本`,-1),t(s,{size:`small`},{default:x(()=>[a(p(S.value.currentVersion),1)]),_:1}),C.value?(f(),e(s,{key:0,type:`warning`,size:`small`,"disable-transitions":``},{default:x(()=>[...i[4]||=[a(`本地构建`,-1)]]),_:1})):_(``,!0)]),v(`div`,I,[i[6]||=v(`span`,{class:`version-label`},`最新版本`,-1),t(s,{type:S.value.hasUpdate?`warning`:`success`,size:`small`,"disable-transitions":``},{default:x(()=>[a(p(S.value.latestVersion),1)]),_:1},8,[`type`])]),t(o,{title:S.value.hasUpdate?`发现新版本 ${S.value.latestVersion}(当前 ${S.value.currentVersion})`:`已是最新版本 ${S.value.currentVersion}`,type:S.value.hasUpdate?`warning`:`success`,"show-icon":``,closable:!1,class:`mt-12`},null,8,[`title`,`type`]),v(`div`,L,[a(` 检查时间:`+p(R(S.value.checkedAt))+` `,1),S.value.hasUpdate?(f(),r(E,{key:0},[i[8]||=a(` · `,-1),t(h,{type:`primary`,href:z(S.value.latestVersion),target:`_blank`},{default:x(()=>[...i[7]||=[a(`在 npm 查看该版本`,-1)]]),_:1},8,[`href`])],64)):_(``,!0)])],64)):!l.value&&w.value?(f(),e(o,{key:2,title:w.value,type:`error`,"show-icon":``,closable:!1},{default:x(()=>[i[10]||=v(`div`,{class:`alert-hint`},` 检查需访问 npm 源,可能是网络不可达或版本号解析失败;稍后重试即可。 `,-1),t(b,{size:`small`,class:`mt-8`,onClick:B},{default:x(()=>[...i[9]||=[a(`重试`,-1)]]),_:1})]),_:1},8,[`title`])):_(``,!0)])),[[O,l.value]]),T.value?(f(),e(o,{key:0,title:T.value,type:`info`,"show-icon":``,class:`mt-12`,onClose:i[0]||=e=>T.value=null},null,8,[`title`])):_(``,!0)]),_:1},8,[`modelValue`,`close-on-click-modal`])}}}),[[`__scopeId`,`data-v-5e671468`]]);c(),l(),T();var z={class:`layout`},B=[`title`],V={key:0,class:`header-version-tag`},H={class:`header-nav`},U={class:`header-actions`},W={class:`user-chip`},G={class:`user-avatar`},K={class:`user-name`},q={class:`main`},J={class:`page`},Y=k(n({__name:`LayoutView`,setup(n){let c=y(),l=w(),d=s(!1);u(()=>{S()});let m=i(()=>h.value?.version||``),b=i(()=>h.value?.buildSource===`local`),T=i(()=>b.value?`本地构建版本(upgrade:local 产物)`:`当前运行版本`),E=i(()=>h.value?.authRequired!==!1),O=i(()=>{if(!E.value)return`免登录`;let e=localStorage.getItem(`webui_token`)||``;try{return atob(e).split(`:`)[0]||`用户`}catch{return`用户`}}),k=i(()=>{let e=c.path;return e===`/`?`/`:e.startsWith(`/providers`)?`/providers`:e.startsWith(`/service-status`)?`/service-status`:e.startsWith(`/managed-services`)?`/managed-services`:e.startsWith(`/settings`)?`/settings`:e.startsWith(`/logs`)?`/logs`:`/`}),A=e=>{e===`logout`&&(C(),l.push(`/login`)),e===`check-update`&&(d.value=!0)};return(n,i)=>{let s=g(`el-menu-item`),c=g(`el-menu`),l=g(`el-icon`),u=g(`el-dropdown-item`),h=g(`el-dropdown-menu`),y=g(`el-dropdown`),S=g(`el-header`),C=g(`router-view`);return f(),r(`div`,z,[t(S,{class:`header`},{default:x(()=>[i[10]||=v(`div`,{class:`brand`},[v(`span`,{class:`brand-mark`},`EZ`),v(`h1`,null,`LLM`)],-1),m.value?(f(),r(`span`,{key:0,class:`header-version`,title:T.value},[a(` v`+p(m.value),1),b.value?(f(),r(`span`,V,`本地构建`)):_(``,!0)],8,B)):_(``,!0),v(`nav`,H,[t(c,{mode:`horizontal`,"default-active":k.value,ellipsis:!1,router:``,class:`header-menu`},{default:x(()=>[t(s,{index:`/`},{default:x(()=>[...i[1]||=[a(`首页`,-1)]]),_:1}),t(s,{index:`/providers`},{default:x(()=>[...i[2]||=[a(`供应商管理`,-1)]]),_:1}),t(s,{index:`/service-status`},{default:x(()=>[...i[3]||=[a(`服务状态`,-1)]]),_:1}),t(s,{index:`/managed-services`},{default:x(()=>[...i[4]||=[a(`托管服务`,-1)]]),_:1}),t(s,{index:`/plugins`},{default:x(()=>[...i[5]||=[a(`插件`,-1)]]),_:1}),t(s,{index:`/logs`},{default:x(()=>[...i[6]||=[a(`日志`,-1)]]),_:1}),t(s,{index:`/settings`},{default:x(()=>[...i[7]||=[a(`设置`,-1)]]),_:1})]),_:1},8,[`default-active`])]),v(`div`,U,[t(y,{trigger:`click`,onCommand:A,class:`ml-12`},{dropdown:x(()=>[t(h,null,{default:x(()=>[t(u,{command:`check-update`},{default:x(()=>[...i[8]||=[a(`检查更新`,-1)]]),_:1}),E.value?(f(),e(u,{key:0,command:`logout`,divided:``},{default:x(()=>[...i[9]||=[a(`退出`,-1)]]),_:1})):_(``,!0)]),_:1})]),default:x(()=>[v(`div`,W,[v(`span`,G,p(O.value.charAt(0).toUpperCase()),1),v(`span`,K,p(O.value),1),t(l,{class:`el-icon--right`},{default:x(()=>[t(o(D))]),_:1})])]),_:1})])]),_:1}),v(`main`,q,[v(`div`,J,[t(C)])]),t(R,{modelValue:d.value,"onUpdate:modelValue":i[0]||=e=>d.value=e},null,8,[`modelValue`])])}}}),[[`__scopeId`,`data-v-4e7e0e0d`]]);export{Y as default};
@@ -1 +1 @@
1
- import{A as e,F as t,I as n,M as r,P as i,S as a,Tt as o,V as s,a as c,c as l,et as u,it as d,j as f,k as p,m,mt as h,u as g,vt as _,x as v}from"./router-DxY62FPf.js";import{t as y}from"./index-DVkpGX_l.js";s(),m(),_();var b={class:`login-wrap`},x=y(n({__name:`LoginView`,setup(n){let s=g(),m=o(``),_=o(``),y=o(``),x=o(!1);async function S(){if(!m.value){y.value=`请输入用户名`;return}if(!_.value){y.value=`请输入密码`;return}x.value=!0,y.value=``;try{let e=await c.post(`/api/auth/login`,{username:m.value.trim(),password:_.value});l(e.token),s.push(`/`)}catch(e){y.value=e.message||`登录失败`}finally{x.value=!1}}return(n,o)=>{let s=d(`el-input`),c=d(`el-form-item`),l=d(`el-alert`),g=d(`el-button`),C=d(`el-form`),w=d(`el-card`);return u(),r(`div`,b,[t(w,{shadow:`never`,class:`login-card`},{default:h(()=>[o[3]||=p(`div`,{class:`login-brand`},[p(`span`,{class:`brand-mark`},`EZ`),p(`span`,{class:`login-title`},`LLM`)],-1),o[4]||=p(`p`,{class:`login-sub`},`本地 LLM 网关 · 管理台登录`,-1),t(C,{"label-position":`top`,onSubmit:a(S,[`prevent`])},{default:h(()=>[t(c,{label:`用户名`},{default:h(()=>[t(s,{modelValue:m.value,"onUpdate:modelValue":o[0]||=e=>m.value=e,placeholder:`请输入用户名`,onKeyup:v(S,[`enter`])},null,8,[`modelValue`])]),_:1}),t(c,{label:`密码`},{default:h(()=>[t(s,{modelValue:_.value,"onUpdate:modelValue":o[1]||=e=>_.value=e,type:`password`,placeholder:`请输入密码`,"show-password":``,onKeyup:v(S,[`enter`])},null,8,[`modelValue`])]),_:1}),y.value?(u(),e(l,{key:0,title:y.value,type:`error`,"show-icon":``,class:`mb-16`},null,8,[`title`])):f(``,!0),t(g,{type:`primary`,class:`full-width`,loading:x.value,onClick:S},{default:h(()=>[...o[2]||=[i(` 登录 `,-1)]]),_:1},8,[`loading`])]),_:1})]),_:1})])}}}),[[`__scopeId`,`data-v-b3e448fa`]]);export{x as default};
1
+ import{A as e,F as t,I as n,M as r,P as i,S as a,Tt as o,V as s,a as c,c as l,et as u,it as d,j as f,k as p,m,mt as h,u as g,vt as _,x as v}from"./router-BgTNV93P.js";import{t as y}from"./index-W7WdLt_5.js";s(),m(),_();var b={class:`login-wrap`},x=y(n({__name:`LoginView`,setup(n){let s=g(),m=o(``),_=o(``),y=o(``),x=o(!1);async function S(){if(!m.value){y.value=`请输入用户名`;return}if(!_.value){y.value=`请输入密码`;return}x.value=!0,y.value=``;try{let e=await c.post(`/api/auth/login`,{username:m.value.trim(),password:_.value});l(e.token),s.push(`/`)}catch(e){y.value=e.message||`登录失败`}finally{x.value=!1}}return(n,o)=>{let s=d(`el-input`),c=d(`el-form-item`),l=d(`el-alert`),g=d(`el-button`),C=d(`el-form`),w=d(`el-card`);return u(),r(`div`,b,[t(w,{shadow:`never`,class:`login-card`},{default:h(()=>[o[3]||=p(`div`,{class:`login-brand`},[p(`span`,{class:`brand-mark`},`EZ`),p(`span`,{class:`login-title`},`LLM`)],-1),o[4]||=p(`p`,{class:`login-sub`},`本地 LLM 网关 · 管理台登录`,-1),t(C,{"label-position":`top`,onSubmit:a(S,[`prevent`])},{default:h(()=>[t(c,{label:`用户名`},{default:h(()=>[t(s,{modelValue:m.value,"onUpdate:modelValue":o[0]||=e=>m.value=e,placeholder:`请输入用户名`,onKeyup:v(S,[`enter`])},null,8,[`modelValue`])]),_:1}),t(c,{label:`密码`},{default:h(()=>[t(s,{modelValue:_.value,"onUpdate:modelValue":o[1]||=e=>_.value=e,type:`password`,placeholder:`请输入密码`,"show-password":``,onKeyup:v(S,[`enter`])},null,8,[`modelValue`])]),_:1}),y.value?(u(),e(l,{key:0,title:y.value,type:`error`,"show-icon":``,class:`mb-16`},null,8,[`title`])):f(``,!0),t(g,{type:`primary`,class:`full-width`,loading:x.value,onClick:S},{default:h(()=>[...o[2]||=[i(` 登录 `,-1)]]),_:1},8,[`loading`])]),_:1})]),_:1})])}}}),[[`__scopeId`,`data-v-b3e448fa`]]);export{x as default};
@@ -0,0 +1,5 @@
1
+ import{A as e,Ct as t,F as n,I as r,M as i,O as a,P as o,Pt as s,S as c,Tt as l,V as u,Wt as d,Z as f,a as p,at as ee,bt as m,et as h,fn as g,ft as _,ht as v,it as y,j as b,k as x,m as S,mt as C,nt as w,vt as T,w as E,x as te,xt as D}from"./router-BgTNV93P.js";import{R as O,S as ne}from"./message-DpifAOwJ.js";import{n as k,t as A}from"./index-W7WdLt_5.js";import{t as re}from"./providers-CkMtur-C.js";import{n as j,t as M}from"./useCopyToast-B_Qvf_Pf.js";import{t as N}from"./useToast-X_JkPDpr.js";import{n as P,t as F}from"./useQuickRangeFilter-DNSnrkx7.js";import{C as I,S as L,a as ie,b as R,c as z,d as B,f as V,g as H,h as U,l as W,m as G,n as ae,o as oe,p as K,r as q,s as se,t as ce,x as le}from"./format-CPPf8IfM.js";u(),T(),d();var ue={class:`detail-content`},J={key:0,class:`ip-link`},Y={class:`ip-pop`},X={class:`ip-pop-row`},de={key:0,class:`ip-pop-row`},fe={key:1,class:`ip-pop-error`},pe={key:2},me=[`href`],he={key:1},ge={key:1},_e=[`title`],ve=[`title`],ye={class:`error-text`},be={class:`pane-bar`},Z={class:`json-block`},xe={class:`pane-bar`},Q={class:`json-block`},Se={class:`pane-bar`},Ce={class:`json-block`},$={class:`pane-bar`},we={class:`json-block`},Te={class:`pane-bar`},Ee={class:`json-block`},De={class:`pane-bar`},Oe={class:`json-block`},ke={class:`pane-bar`},Ae={class:`json-block`},je={class:`pane-bar`},Me={class:`json-block`},Ne=A(r({__name:`LogDetailDialog`,setup(t,{expose:r}){let{copyWithToast:c}=M(),{loadError:u,run:d}=j(),f=l(!1),m=l(null),_=l(!1),S=l(`info`),w=l(!1),T=l(null),te=P(),O=e=>{T.value=e,f.value=!0,m.value=null,S.value=`info`;let t=te();_.value=!0,d(async()=>{try{let n=`?id=${String(e.id)}`,r=await p.get(`/api/logs/detail`+n);if(!t())return;if(r&&r.detail){let e={...r.detail,...r.meta};e.response&&=D(e.response),e.request&&=D(e.request),m.value=e}else m.value=r}catch(e){if(!t())return;throw e}finally{t()&&(_.value=!1)}})},ne=()=>{T.value&&O(T.value)};r({open:O});let k=a(()=>K(m.value?.response?.inbound_request)),A=a(()=>K(m.value?.response?.upstream_request)),re=a(()=>U(m.value?.response?.upstream_response_text)),N=a(()=>(m.value?.response?.upstream_stream_frames||[]).join(`
2
+
3
+ `)),F=a(()=>K(m.value?.response?.client_response)),L=a(()=>(m.value?.response?.client_stream_frames||[]).join(`
4
+
5
+ `)),R=a(()=>K(m.value?.request)),z=a(()=>K(m.value?.response)),H=async e=>{if(!(e._ipInfo||e._ipInfoError)){w.value=!0;try{let t=await p.get(`/api/logs/ipinfo?ip=${encodeURIComponent(e.ip)}`);t.error?e._ipInfoError=t.error:e._ipInfo=t}catch{e._ipInfoError=`查询失败`}finally{w.value=!1}}},oe=e=>[e.country,e.region,e.city].filter(Boolean).join(` · `)||`-`;return(t,r)=>{let a=y(`el-button`),l=y(`el-alert`),d=y(`el-descriptions-item`),p=y(`el-tag`),T=y(`el-divider`),te=y(`el-popover`),D=y(`el-descriptions`),O=y(`el-tab-pane`),j=y(`el-tabs`),M=y(`el-dialog`),P=ee(`loading`);return h(),e(M,{modelValue:f.value,"onUpdate:modelValue":r[11]||=e=>f.value=e,title:`日志详情`,width:`80%`,top:`5vh`,"destroy-on-close":``},{default:C(()=>[s(u)?(h(),e(l,{key:0,title:s(u),type:`error`,"show-icon":``,closable:!1,class:`mb-16`},{default:C(()=>[n(a,{size:`small`,onClick:ne},{default:C(()=>[...r[12]||=[o(`重试`,-1)]]),_:1})]),_:1},8,[`title`])):b(``,!0),v((h(),i(`div`,ue,[m.value?(h(),e(j,{key:0,modelValue:S.value,"onUpdate:modelValue":r[10]||=e=>S.value=e},{default:C(()=>[n(O,{lazy:``,label:`基本信息`,name:`info`},{default:C(()=>[n(D,{column:2,border:``},{default:C(()=>[n(d,{label:`时间`},{default:C(()=>[o(g(s(G)(m.value.time)),1)]),_:1}),n(d,{label:`模型`},{default:C(()=>[o(g(m.value.model),1)]),_:1}),n(d,{label:`方法`},{default:C(()=>[o(g(m.value.method),1)]),_:1}),n(d,{label:`路径`},{default:C(()=>[o(g(m.value.path),1)]),_:1}),n(d,{label:`状态码`},{default:C(()=>[o(g(m.value.status),1)]),_:1}),n(d,{label:`流式`},{default:C(()=>[n(p,{type:m.value.stream?`warning`:`info`},{default:C(()=>[o(g(m.value.stream?`是`:`否`),1)]),_:1},8,[`type`])]),_:1}),n(d,{label:`IP`},{default:C(()=>[m.value.ip?(h(),i(`span`,J,[n(te,{placement:`right`,width:`240`,trigger:`click`,onShow:r[0]||=e=>H(m.value)},{reference:C(()=>[x(`span`,null,g(m.value.ip),1)]),default:C(()=>[v((h(),i(`div`,Y,[m.value._ipInfo?(h(),i(E,{key:0},[x(`div`,X,[r[13]||=x(`span`,{class:`ip-pop-label`},`归属地`,-1),x(`span`,null,g(oe(m.value._ipInfo)),1)]),m.value._ipInfo.isp?(h(),i(`div`,de,[r[14]||=x(`span`,{class:`ip-pop-label`},`运营商`,-1),x(`span`,null,g(m.value._ipInfo.isp),1)])):b(``,!0)],64)):m.value._ipInfoError?(h(),i(`div`,fe,g(m.value._ipInfoError),1)):(h(),i(`span`,pe,`查询中...`)),n(T,{style:{margin:`8px 0`}}),x(`a`,{class:`ip-pop-link`,href:`https://m.ip138.com/iplookup.php?ip=${encodeURIComponent(m.value.ip)}`,target:`_blank`},`在 ip138 查看`,8,me)])),[[P,w.value]])]),_:1})])):(h(),i(`span`,he,`-`))]),_:1}),n(d,{label:`Session`},{default:C(()=>[o(g(m.value.session_id||`-`),1)]),_:1}),n(d,{label:`ID`},{default:C(()=>[m.value._id==null?(h(),i(`span`,ge,`-`)):(h(),i(`span`,{key:0,class:`request-id`,title:`点击复制(日志 id 同时是响应头 x-request-id)`,onClick:r[1]||=e=>s(c)(String(m.value._id))},g(m.value._id),1))]),_:1}),n(d,{label:`输入 Token(含缓存读取)`},{default:C(()=>[o(g(s(B)(m.value.input_tokens??0)),1)]),_:1}),n(d,{label:`输出 Token`},{default:C(()=>[o(g(s(B)(m.value.output_tokens??0)),1)]),_:1}),n(d,{label:`缓存读取`},{default:C(()=>[o(g(s(B)(m.value.cache_read_tokens??0)),1)]),_:1}),n(d,{label:`请求耗时`},{default:C(()=>[o(g(s(W)(m.value.duration)),1)]),_:1}),n(d,{label:`缓存命中率`},{default:C(()=>[o(g(s(ie)(m.value)),1)]),_:1}),n(d,{label:`首 Token`},{default:C(()=>[x(`span`,{title:s(q)},g(s(W)(m.value.ttft)),9,_e)]),_:1}),n(d,{label:`生成速度`},{default:C(()=>[x(`span`,{title:s(ae)},g(s(V)(m.value.tps)),9,ve)]),_:1}),m.value.error?(h(),e(d,{key:0,label:`错误`,span:2},{default:C(()=>[x(`span`,ye,g(m.value.error),1)]),_:1})):b(``,!0)]),_:1}),m.value.response?.truncated?(h(),e(l,{key:0,class:`mt-16`,type:`warning`,closable:!1,title:`内容超过单请求捕获上限,已截断`})):b(``,!0)]),_:1}),m.value.response?._capture?(h(),i(E,{key:0},[n(O,{lazy:``,label:`客户端请求`,name:`inbound`},{default:C(()=>[x(`div`,be,[n(a,{size:`small`,class:`copy-btn`,onClick:r[2]||=e=>s(c)(k.value)},{default:C(()=>[...r[15]||=[o(` 复制 `,-1)]]),_:1})]),x(`pre`,Z,g(s(I)(k.value)),1)]),_:1}),n(O,{lazy:``,label:`转发上游的请求`,name:`upstreamReq`},{default:C(()=>[x(`div`,xe,[n(a,{size:`small`,class:`copy-btn`,onClick:r[3]||=e=>s(c)(A.value)},{default:C(()=>[...r[16]||=[o(` 复制 `,-1)]]),_:1})]),x(`pre`,Q,g(s(I)(A.value)),1)]),_:1}),m.value.response.upstream_response_text?(h(),e(O,{key:0,lazy:``,label:`上游响应(原始)`,name:`upstreamRes`},{default:C(()=>[x(`div`,Se,[n(a,{size:`small`,class:`copy-btn`,onClick:r[4]||=e=>s(c)(m.value.response.upstream_response_text)},{default:C(()=>[...r[17]||=[o(` 复制 `,-1)]]),_:1})]),x(`pre`,Ce,g(s(I)(re.value)),1)]),_:1})):m.value.response.upstream_stream_frames?.length?(h(),e(O,{key:1,lazy:``,label:`上游响应(原始流,${m.value.response.upstream_stream_frames.length} 帧)`,name:`upstreamStream`},{default:C(()=>[x(`div`,$,[n(a,{size:`small`,class:`copy-btn`,onClick:r[5]||=e=>s(c)(N.value)},{default:C(()=>[...r[18]||=[o(` 复制 `,-1)]]),_:1})]),x(`pre`,we,g(s(I)(N.value)),1)]),_:1},8,[`label`])):b(``,!0),m.value.response.client_response!==void 0&&m.value.response.client_response!==null?(h(),e(O,{key:2,lazy:``,label:`回写客户端(转换后)`,name:`clientRes`},{default:C(()=>[x(`div`,Te,[n(a,{size:`small`,class:`copy-btn`,onClick:r[6]||=e=>s(c)(F.value)},{default:C(()=>[...r[19]||=[o(` 复制 `,-1)]]),_:1})]),x(`pre`,Ee,g(s(I)(F.value)),1)]),_:1})):m.value.response.client_stream_frames?.length?(h(),e(O,{key:3,lazy:``,label:`回写客户端(${m.value.response.client_stream_frames.length} 帧)`,name:`clientStream`},{default:C(()=>[x(`div`,De,[n(a,{size:`small`,class:`copy-btn`,onClick:r[7]||=e=>s(c)(L.value)},{default:C(()=>[...r[20]||=[o(` 复制 `,-1)]]),_:1})]),x(`pre`,Oe,g(s(I)(L.value)),1)]),_:1},8,[`label`])):b(``,!0)],64)):(h(),i(E,{key:1},[n(O,{lazy:``,label:`请求体`,name:`request`},{default:C(()=>[x(`div`,ke,[n(a,{size:`small`,class:`copy-btn`,onClick:r[8]||=e=>s(c)(R.value)},{default:C(()=>[...r[21]||=[o(` 复制 `,-1)]]),_:1})]),x(`pre`,Ae,g(s(I)(R.value)),1)]),_:1}),n(O,{lazy:``,label:`响应体`,name:`response`},{default:C(()=>[x(`div`,je,[n(a,{size:`small`,class:`copy-btn`,onClick:r[9]||=e=>s(c)(z.value)},{default:C(()=>[...r[22]||=[o(` 复制 `,-1)]]),_:1})]),x(`pre`,Me,g(s(I)(z.value)),1)]),_:1})],64))]),_:1},8,[`modelValue`])):b(``,!0)])),[[P,_.value]])]),_:1},8,[`modelValue`])}}}),[[`__scopeId`,`data-v-7e1ff197`]]);u(),T(),d(),S();var Pe={class:`session-table`},Fe={class:`group-detail`},Ie=[`title`],Le={key:0,class:`detail-error`},Re={class:`detail-footer`},ze={class:`detail-count`},Be=[`title`,`onClick`],Ve=`会话平均生成速度:组内有效请求的输出 token 合计 ÷ 生成窗口合计(按窗口加权,不是各请求速度的算术平均);首 = 组内流式且已采集首 token 的请求的平均首 token 延迟(非流式请求无此观测点,不参与)`,He=50,Ue=A(r({__name:`SessionGroupTable`,props:{groups:{},noSession:{},loading:{type:Boolean},filterParams:{}},emits:[`open-detail`],setup(r,{emit:u}){let d=r,f=u,{copyWithToast:m}=M(),S=a(()=>d.noSession?[...d.groups,d.noSession]:d.groups),w=e=>e.session_id||`__no_session__`,T=l(null),E=t(new Map),te={loading:!1,items:[],total:0,nextPage:1,error:null},D=e=>E.get(w(e))??te,O=async(e,t)=>{let n=(e=>(E.has(e)||E.set(e,{loading:!1,items:[],total:0,nextPage:1,error:null}),E.get(e)))(w(e));if(!n.loading){n.loading=!0,n.error=null;try{let r={...d.filterParams,sort:`time`,order:`desc`,page:String(t),pageSize:String(He)};e.session_id?r.sessionId=e.session_id:r.noSession=`1`;let i=await p.get(`/api/logs?`+new URLSearchParams(r).toString()),a=i.items||[];n.items=t===1?a:[...n.items,...a],n.total=i.total||0,n.nextPage=t+1}catch(e){n.error=e?.message||`加载失败`}finally{n.loading=!1}}},ne=(e,t)=>{t.some(t=>w(t)===w(e))&&D(e).items.length===0&&O(e,1)},k=e=>{let t=D(e);t.loading||t.items.length>=t.total||O(e,t.nextPage)},A=e=>{T.value?.toggleRowExpansion(e)};return _(()=>S.value.map(w),e=>{let t=new Set(e);for(let e of[...E.keys()])t.has(e)||E.delete(e)}),(t,a)=>{let l=y(`el-table-column`),u=y(`el-tag`),d=y(`el-button`),p=y(`el-table`),_=y(`el-empty`),E=ee(`loading`);return h(),i(`div`,Pe,[S.value.length>0||r.loading?v((h(),e(p,{key:0,ref_key:`tableRef`,ref:T,data:S.value,height:`100%`,"row-key":w,stripe:``,class:`dense-table`,onExpandChange:ne,onRowClick:A},{default:C(()=>[n(l,{type:`expand`},{default:C(({row:t})=>[x(`div`,Fe,[v((h(),e(p,{data:D(t).items,size:`small`,stripe:``,class:`dense-table`},{default:C(()=>[n(l,{label:`时间`,width:`136`,align:`center`},{default:C(({row:e})=>[o(g(s(le)(e.time)),1)]),_:1}),n(l,{prop:`model`,label:`模型`,"min-width":`80`,align:`center`,"show-overflow-tooltip":``}),n(l,{label:`客户端`,"min-width":`80`,align:`center`,"show-overflow-tooltip":``},{default:C(({row:e})=>[o(g(s(oe)(e)),1)]),_:1}),n(l,{label:`状态`,width:`60`,align:`center`},{default:C(({row:e})=>[n(u,{size:`small`,type:e.status>=400?`danger`:e.status>=300?`warning`:`success`},{default:C(()=>[o(g(e.status),1)]),_:2},1032,[`type`])]),_:1}),n(l,{label:`输入`,width:`84`,align:`center`},{default:C(({row:e})=>[o(g(s(B)(e.input_tokens??0)),1)]),_:1}),n(l,{label:`输出`,width:`78`,align:`center`},{default:C(({row:e})=>[o(g(s(B)(e.output_tokens??0)),1)]),_:1}),n(l,{label:`缓存读取`,width:`84`,align:`center`},{default:C(({row:e})=>[o(g(s(B)(e.cache_read_tokens??0)),1)]),_:1}),n(l,{label:`缓存命中率`,width:`88`,align:`center`},{default:C(({row:e})=>[o(g(s(ie)(e)),1)]),_:1}),n(l,{label:`请求耗时`,width:`74`,align:`center`},{default:C(({row:e})=>[o(g(s(W)(e.duration)),1)]),_:1}),n(l,{label:`速度`,width:`140`,align:`center`},{default:C(({row:e})=>[x(`div`,{title:s(ce)},g(s(L)(e.tps,e.ttft)),9,Ie)]),_:1}),n(l,{label:`详情`,width:`52`,align:`center`},{default:C(({row:e})=>[n(d,{link:``,type:`primary`,onClick:t=>f(`open-detail`,e)},{default:C(()=>[...a[0]||=[o(`查看`,-1)]]),_:1},8,[`onClick`])]),_:1})]),_:1},8,[`data`])),[[E,D(t).loading]]),D(t).error?(h(),i(`div`,Le,[o(g(D(t).error)+` `,1),n(d,{link:``,type:`primary`,size:`small`,onClick:e=>O(t,1)},{default:C(()=>[...a[1]||=[o(`重试`,-1)]]),_:1},8,[`onClick`])])):b(``,!0),x(`div`,Re,[x(`span`,ze,`已显示 `+g(D(t).items.length)+` / `+g(D(t).total)+` 条`,1),D(t).items.length<D(t).total?(h(),e(d,{key:0,size:`small`,loading:D(t).loading,onClick:e=>k(t)},{default:C(()=>[...a[2]||=[o(` 加载更多 `,-1)]]),_:1},8,[`loading`,`onClick`])):b(``,!0)])])]),_:1}),n(l,{label:`Session`,width:`100`,align:`center`},{default:C(({row:t})=>[t.session_id?(h(),i(`span`,{key:0,class:`session-id`,title:`${t.session_id}(点击复制)`,onClick:c(e=>s(m)(t.session_id),[`stop`])},g(s(R)(t.session_id)),9,Be)):(h(),e(u,{key:1,size:`small`,type:`info`,title:`未携带会话标识的请求(NULL / 空串 session_id)`},{default:C(()=>[...a[3]||=[o(` 无 Session `,-1)]]),_:1}))]),_:1}),n(l,{label:`请求数`,width:`70`,align:`center`},{default:C(({row:e})=>[o(g(s(B)(e.calls)),1)]),_:1}),n(l,{label:`模型`,"min-width":`80`,align:`center`,"show-overflow-tooltip":``},{default:C(({row:e})=>[o(g(s(H)(e.models)),1)]),_:1}),n(l,{label:`客户端`,"min-width":`80`,align:`center`,"show-overflow-tooltip":``},{default:C(({row:e})=>[o(g(s(z)(e.clients)),1)]),_:1}),n(l,{label:`输入`,width:`100`,align:`center`},{default:C(({row:e})=>[o(g(s(B)(e.input_tokens)),1)]),_:1}),n(l,{label:`输出`,width:`90`,align:`center`},{default:C(({row:e})=>[o(g(s(B)(e.output_tokens)),1)]),_:1}),n(l,{label:`缓存读取`,width:`100`,align:`center`},{default:C(({row:e})=>[o(g(s(B)(e.cache_read_tokens)),1)]),_:1}),n(l,{label:`速度`,width:`140`,align:`center`},{default:C(({row:e})=>[x(`div`,{title:Ve},g(s(L)(e.tps,e.avg_ttft)),1)]),_:1}),n(l,{label:`首次请求`,width:`136`,align:`center`},{default:C(({row:e})=>[o(g(s(le)(e.first_time)),1)]),_:1}),n(l,{label:`最后请求`,width:`136`,align:`center`},{default:C(({row:e})=>[o(g(s(le)(e.last_time)),1)]),_:1})]),_:1},8,[`data`])),[[E,r.loading]]):(h(),e(_,{key:1,description:`当前筛选下没有日志`}))])}}}),[[`__scopeId`,`data-v-53b49f30`]]);u(),T(),S(),d();var We={class:`logs-page`},Ge={class:`filter-bar`},Ke={class:`table-wrap`},qe=[`onClick`],Je={key:1},Ye=[`title`,`onClick`],Xe={key:1},Ze=[`title`,`onClick`],Qe={key:1},$e=[`title`],et={class:`pagination-bar`},tt=A(r({__name:`LogsView`,setup(t){let r=re(),{toast:c}=N(),{copyWithToast:u}=M(),{loadError:d,run:_}=j(),{rangeKey:S,dateRange:T,setRange:D,onRangeChange:A}=F(()=>$()),I=l(`2xx`),z=l(``),V=l(``),H=l(``),U=l(`session`),G=l([]),ae=l([]),K=l(null),q=l(0),ue=l(0),J=l(1),Y=l(20),X=l(!1),de=l(null),fe=e=>{de.value?.open(e)},pe=a(()=>{let e=new Set;for(let t of r.suppliers)for(let n of t.models)e.add(n.modelName);for(let t of G.value)t.model&&e.add(t.model);return[...e].sort()}),me=l([]),he=a(()=>{let e=new Set(me.value);for(let t of G.value)t.client&&e.add(t.client);return[...e].sort()}),ge=async()=>{try{let e=await p.get(`/api/logs/clients`);me.value=e.clients||[]}catch{me.value=[]}},_e=e=>{S.value=``,T.value=e||null,$()},ve=()=>{let e={};T.value&&T.value.length===2&&(e.startDate=T.value[0],e.endDate=T.value[1]),I.value&&(e.status=I.value),z.value&&(e.model=z.value),V.value&&(e.client=V.value);let t=H.value.trim();return t&&(e.sessionId=t),e},ye=a(()=>ve()),be=P(),Z=()=>_(async()=>{let e=be();X.value=!0;try{let t={...ve(),page:String(J.value),pageSize:String(Y.value)};if(U.value===`session`){let n=new URLSearchParams(t).toString(),r=await p.get(`/api/logs/sessions?`+n);if(!e())return;ae.value=r.groups||[],K.value=r.noSession??null,q.value=r.total||0,ue.value=r.rowsTotal||0}else{let n=new URLSearchParams({...t,sort:`time`,order:`desc`}).toString(),r=await p.get(`/api/logs?`+n);if(!e())return;G.value=r.items||[],q.value=r.total||0}}catch(t){if(!e())return;throw t}finally{e()&&(X.value=!1)}}),xe=e=>{U.value!==e&&(U.value=e,J.value=1,Y.value=U.value===`session`?20:50,Z())},Q=l(!1),Se=a(()=>U.value===`session`?ue.value:q.value),Ce=async()=>{if(Q.value||Se.value===0)return;let e=U.value===`session`?`(按筛选行数计,含「无 Session」组)`:``;try{await k.confirm(`将永久清理当前筛选条件下的 ${Se.value} 条日志${e},清理后不可恢复,请谨慎操作!`,`清理确认`,{confirmButtonText:`确认清理`,cancelButtonText:`取消`,type:`warning`})}catch{return}Q.value=!0;try{let e=new URLSearchParams(ve()).toString(),t=await p.post(`/api/logs/clear?`+e,{});c(`已清理 ${t.deleted??0} 条日志`,`success`),J.value>1&&(J.value=1),Z()}catch(e){c(e.message||`清理失败`,`error`)}finally{Q.value=!1}},$=()=>{J.value=1,ge(),Z()},we=()=>{S.value=`today`,T.value=null,I.value=`2xx`,z.value=``,V.value=``,H.value=``,J.value=1,Y.value=U.value===`session`?20:50,D(`today`)};return f(()=>{r.loadProviders().catch(()=>{}),ge(),D(`today`)}),(t,r)=>{let a=y(`el-button`),c=y(`el-alert`),l=y(`el-option`),f=y(`el-select`),p=y(`el-date-picker`),_=y(`el-input`),D=y(`el-tooltip`),k=y(`el-button-group`),re=y(`el-card`),j=y(`el-table-column`),M=y(`el-tag`),N=y(`el-table`),P=y(`el-pagination`),F=ee(`loading`);return h(),i(`div`,We,[s(d)?(h(),e(c,{key:0,title:s(d),type:`error`,"show-icon":``,closable:!1,class:`mb-16`},{default:C(()=>[n(a,{size:`small`,onClick:Z},{default:C(()=>[...r[10]||=[o(`重试`,-1)]]),_:1})]),_:1},8,[`title`])):b(``,!0),n(re,{shadow:`never`},{default:C(()=>[x(`div`,Ge,[n(f,{modelValue:s(S),"onUpdate:modelValue":r[0]||=e=>m(S)?S.value=e:null,placeholder:`时间范围`,clearable:``,style:{width:`114px`},onChange:s(A)},{default:C(()=>[n(l,{label:`今天`,value:`today`}),n(l,{label:`昨天`,value:`yesterday`}),n(l,{label:`前天`,value:`beforeYesterday`}),n(l,{label:`近三天`,value:`last3days`}),n(l,{label:`本周`,value:`week`}),n(l,{label:`本月`,value:`month`})]),_:1},8,[`modelValue`,`onChange`]),n(p,{modelValue:s(T),"onUpdate:modelValue":r[1]||=e=>m(T)?T.value=e:null,type:`daterange`,"value-format":`YYYY-MM-DD`,"range-separator":`至`,"start-placeholder":`开始日期`,"end-placeholder":`结束日期`,style:{width:`240px`},onChange:_e},null,8,[`modelValue`]),n(f,{modelValue:I.value,"onUpdate:modelValue":r[2]||=e=>I.value=e,placeholder:`全部状态`,clearable:``,style:{width:`106px`},onChange:$},{default:C(()=>[n(l,{label:`成功 (2xx)`,value:`2xx`}),n(l,{label:`3xx`,value:`3xx`}),n(l,{label:`4xx`,value:`4xx`}),n(l,{label:`5xx`,value:`5xx`}),n(l,{label:`错误 (4xx+)`,value:`err`})]),_:1},8,[`modelValue`]),n(f,{modelValue:z.value,"onUpdate:modelValue":r[3]||=e=>z.value=e,placeholder:`全部模型`,clearable:``,filterable:``,style:{width:`176px`},onChange:$},{default:C(()=>[(h(!0),i(E,null,w(pe.value,t=>(h(),e(l,{key:t,label:t,value:t},null,8,[`label`,`value`]))),128))]),_:1},8,[`modelValue`]),n(f,{modelValue:V.value,"onUpdate:modelValue":r[4]||=e=>V.value=e,placeholder:`全部客户端`,clearable:``,filterable:``,style:{width:`130px`},onChange:$},{default:C(()=>[(h(!0),i(E,null,w(he.value,t=>(h(),e(l,{key:t,label:t,value:t},null,8,[`label`,`value`]))),128))]),_:1},8,[`modelValue`]),n(_,{modelValue:H.value,"onUpdate:modelValue":r[5]||=e=>H.value=e,class:`session-input`,placeholder:`Session ID(前缀匹配)`,clearable:``,onKeyup:te($,[`enter`])},null,8,[`modelValue`]),n(k,{class:`view-switch push-right`},{default:C(()=>[n(D,{content:`按会话分组`,placement:`top`,"show-after":300},{default:C(()=>[n(a,{type:U.value===`session`?`primary`:`default`,icon:s(ne),"aria-label":`按会话分组`,onClick:r[6]||=e=>xe(`session`)},null,8,[`type`,`icon`])]),_:1}),n(D,{content:`列表`,placement:`top`,"show-after":300},{default:C(()=>[n(a,{type:U.value===`list`?`primary`:`default`,icon:s(O),"aria-label":`列表视图`,onClick:r[7]||=e=>xe(`list`)},null,8,[`type`,`icon`])]),_:1})]),_:1}),n(a,{type:`primary`,onClick:$},{default:C(()=>[...r[11]||=[o(`搜索`,-1)]]),_:1}),n(a,{onClick:we},{default:C(()=>[...r[12]||=[o(`重置`,-1)]]),_:1})])]),_:1}),n(re,{shadow:`never`,class:`mt-16 table-card`},{default:C(()=>[x(`div`,Ke,[U.value===`list`?v((h(),e(N,{key:0,data:G.value,stripe:``,height:`100%`,class:`dense-table`},{default:C(()=>[n(j,{prop:`id`,label:`ID`,width:`66`,align:`center`},{default:C(({row:e})=>[e.id==null?(h(),i(`span`,Je,`-`)):(h(),i(`span`,{key:0,class:`request-id`,title:`点击复制(日志 id 同时是响应头 x-request-id,可用于关联控制台日志与检索)`,onClick:t=>s(u)(String(e.id))},g(e.id),9,qe))]),_:1}),n(j,{prop:`time`,label:`时间`,width:`136`,align:`center`},{default:C(({row:e})=>[o(g(s(le)(e.time)),1)]),_:1}),n(j,{prop:`model`,label:`模型`,"min-width":`80`,align:`center`,"show-overflow-tooltip":``}),n(j,{label:`客户端`,"min-width":`80`,align:`center`},{default:C(({row:e})=>[e.client||e.user_agent?(h(),i(`span`,{key:0,class:`request-id`,title:s(se)(e),onClick:t=>s(u)(e.user_agent||e.client)},g(s(oe)(e)),9,Ye)):(h(),i(`span`,Xe,`-`))]),_:1}),n(j,{label:`Session`,width:`88`,align:`center`},{default:C(({row:e})=>[e.session_id?(h(),i(`span`,{key:0,class:`request-id`,title:`${e.session_id}(点击复制)`,onClick:t=>s(u)(e.session_id)},g(s(R)(e.session_id)),9,Ze)):(h(),i(`span`,Qe,`-`))]),_:1}),n(j,{label:`输入`,width:`84`,align:`center`},{default:C(({row:e})=>[o(g(s(B)(e.input_tokens??0)),1)]),_:1}),n(j,{label:`输出`,width:`78`,align:`center`},{default:C(({row:e})=>[o(g(s(B)(e.output_tokens??0)),1)]),_:1}),n(j,{label:`缓存读取`,width:`84`,align:`center`},{default:C(({row:e})=>[o(g(s(B)(e.cache_read_tokens??0)),1)]),_:1}),n(j,{label:`缓存命中率`,width:`88`,align:`center`},{default:C(({row:e})=>[x(`span`,null,g(s(ie)(e)),1)]),_:1}),n(j,{label:`请求耗时`,width:`74`,align:`center`},{default:C(({row:e})=>[o(g(s(W)(e.duration)),1)]),_:1}),n(j,{label:`速度`,width:`140`,align:`center`},{default:C(({row:e})=>[x(`div`,{title:s(ce)},g(s(L)(e.tps,e.ttft)),9,$e)]),_:1}),n(j,{prop:`status`,label:`状态`,width:`60`,align:`center`},{default:C(({row:e})=>[n(M,{size:`small`,type:e.status>=400?`danger`:e.status>=300?`warning`:`success`},{default:C(()=>[o(g(e.status),1)]),_:2},1032,[`type`])]),_:1}),n(j,{label:`详情`,width:`52`,align:`center`,fixed:`right`},{default:C(({row:e})=>[n(a,{link:``,type:`primary`,onClick:t=>fe(e)},{default:C(()=>[...r[13]||=[o(`查看`,-1)]]),_:1},8,[`onClick`])]),_:1})]),_:1},8,[`data`])),[[F,X.value]]):b(``,!0),U.value===`session`?(h(),e(Ue,{key:1,groups:ae.value,"no-session":K.value,loading:X.value,"filter-params":ye.value,onOpenDetail:fe},null,8,[`groups`,`no-session`,`loading`,`filter-params`])):b(``,!0)]),x(`div`,et,[n(a,{type:`danger`,plain:``,size:`small`,loading:Q.value,disabled:Se.value===0,onClick:Ce},{default:C(()=>[...r[14]||=[o(`清理已筛选日志`,-1)]]),_:1},8,[`loading`,`disabled`]),n(P,{class:`push-right`,"current-page":J.value,"onUpdate:currentPage":r[8]||=e=>J.value=e,"page-size":Y.value,"onUpdate:pageSize":r[9]||=e=>Y.value=e,total:q.value,"page-sizes":[20,50,100,200],layout:`total, sizes, prev, pager, next`,onCurrentChange:Z,onSizeChange:Z},null,8,[`current-page`,`page-size`,`total`])])]),_:1}),n(Ne,{ref_key:`logDetailRef`,ref:de},null,512)])}}}),[[`__scopeId`,`data-v-7cb554f8`]]);export{tt as default};
@@ -1 +1 @@
1
- .ip-link[data-v-7e1ff197]{color:#409eff;cursor:pointer}.ip-link[data-v-7e1ff197]:hover{text-decoration:underline}.ip-pop[data-v-7e1ff197]{min-height:20px;font-size:13px}.ip-pop-row[data-v-7e1ff197]{gap:8px;margin-bottom:4px;display:flex}.ip-pop-label[data-v-7e1ff197]{color:#909399;flex-shrink:0}.ip-pop-error[data-v-7e1ff197]{color:#f56c6c}.ip-pop-link[data-v-7e1ff197]{color:#409eff;font-size:13px}.error-text[data-v-7e1ff197]{color:#f56c6c}.pane-bar[data-v-7e1ff197]{flex-shrink:0;justify-content:flex-end;margin-bottom:8px;display:flex}.json-block[data-v-7e1ff197]{white-space:pre-wrap;word-break:break-all;background:#f5f7fa;border:1px solid #e4e7ed;border-radius:4px;flex:1;min-height:0;padding:12px;font-size:13px;line-height:1.5;overflow:auto}.detail-content[data-v-7e1ff197]{flex-direction:column;height:78vh;display:flex;overflow:hidden}.detail-content[data-v-7e1ff197] .el-tabs{flex-direction:column;flex:1;min-height:0;display:flex}.detail-content[data-v-7e1ff197] .el-tabs__content{flex:1;min-height:0}.detail-content[data-v-7e1ff197] .el-tab-pane{flex-direction:column;height:100%;display:flex;overflow:auto}.copy-btn[data-v-7e1ff197]{margin-left:8px;padding:2px 10px;font-size:12px}.session-table[data-v-1a4244ff]{height:100%}.session-id[data-v-1a4244ff]{cursor:pointer;white-space:nowrap;text-overflow:ellipsis;font-family:ui-monospace,Consolas,monospace;display:block;overflow:hidden}.session-id[data-v-1a4244ff]:hover{color:var(--el-color-primary)}.group-detail[data-v-1a4244ff]{padding:4px 16px 8px 48px}.detail-error[data-v-1a4244ff]{color:var(--el-color-danger);margin-top:8px;font-size:12px}.detail-footer[data-v-1a4244ff]{justify-content:flex-end;align-items:center;gap:12px;margin-top:8px;display:flex}.detail-count[data-v-1a4244ff]{color:var(--el-text-color-secondary);font-size:12px}.logs-page[data-v-8caf26b0]{flex-direction:column;height:calc(100vh - 124px);display:flex;overflow:hidden}.request-id[data-v-8caf26b0]{cursor:pointer;white-space:nowrap;text-overflow:ellipsis;font-family:ui-monospace,Consolas,monospace;display:block;overflow:hidden}.request-id[data-v-8caf26b0]:hover{color:var(--el-color-primary)}.filter-bar[data-v-8caf26b0]{flex-wrap:nowrap;align-items:center;gap:12px;display:flex}.filter-bar[data-v-8caf26b0]>*{flex:none}.filter-bar .session-input[data-v-8caf26b0]{flex:160px;min-width:100px}.filter-bar .push-right[data-v-8caf26b0]{margin-left:auto}.filter-bar .view-switch[data-v-8caf26b0]{flex:none}.filter-bar[data-v-8caf26b0] .el-button+.el-button{margin-left:0}@media (width<=900px){.filter-bar[data-v-8caf26b0]{flex-wrap:wrap}.filter-bar .session-input[data-v-8caf26b0]{flex-basis:100%;min-width:0}.filter-bar .push-right[data-v-8caf26b0]{margin-left:auto}}.mt-16[data-v-8caf26b0]{margin-top:16px}.table-card[data-v-8caf26b0]{flex:1;min-height:0;overflow:hidden}.table-card[data-v-8caf26b0] .el-card__body{flex-direction:column;height:100%;display:flex}.table-wrap[data-v-8caf26b0]{flex:1;min-height:0}.pagination-bar[data-v-8caf26b0]{flex-shrink:0;justify-content:space-between;align-items:center;margin-top:16px;display:flex}
1
+ .ip-link[data-v-7e1ff197]{color:#409eff;cursor:pointer}.ip-link[data-v-7e1ff197]:hover{text-decoration:underline}.ip-pop[data-v-7e1ff197]{min-height:20px;font-size:13px}.ip-pop-row[data-v-7e1ff197]{gap:8px;margin-bottom:4px;display:flex}.ip-pop-label[data-v-7e1ff197]{color:#909399;flex-shrink:0}.ip-pop-error[data-v-7e1ff197]{color:#f56c6c}.ip-pop-link[data-v-7e1ff197]{color:#409eff;font-size:13px}.error-text[data-v-7e1ff197]{color:#f56c6c}.pane-bar[data-v-7e1ff197]{flex-shrink:0;justify-content:flex-end;margin-bottom:8px;display:flex}.json-block[data-v-7e1ff197]{white-space:pre-wrap;word-break:break-all;background:#f5f7fa;border:1px solid #e4e7ed;border-radius:4px;flex:1;min-height:0;padding:12px;font-size:13px;line-height:1.5;overflow:auto}.detail-content[data-v-7e1ff197]{flex-direction:column;height:78vh;display:flex;overflow:hidden}.detail-content[data-v-7e1ff197] .el-tabs{flex-direction:column;flex:1;min-height:0;display:flex}.detail-content[data-v-7e1ff197] .el-tabs__content{flex:1;min-height:0}.detail-content[data-v-7e1ff197] .el-tab-pane{flex-direction:column;height:100%;display:flex;overflow:auto}.copy-btn[data-v-7e1ff197]{margin-left:8px;padding:2px 10px;font-size:12px}.session-table[data-v-53b49f30]{height:100%}.session-id[data-v-53b49f30]{cursor:pointer;white-space:nowrap;text-overflow:ellipsis;font-family:ui-monospace,Consolas,monospace;display:block;overflow:hidden}.session-id[data-v-53b49f30]:hover{color:var(--el-color-primary)}.group-detail[data-v-53b49f30]{padding:4px 16px 8px 48px}.detail-error[data-v-53b49f30]{color:var(--el-color-danger);margin-top:8px;font-size:12px}.detail-footer[data-v-53b49f30]{justify-content:flex-end;align-items:center;gap:12px;margin-top:8px;display:flex}.detail-count[data-v-53b49f30]{color:var(--el-text-color-secondary);font-size:12px}.logs-page[data-v-7cb554f8]{flex-direction:column;height:calc(100vh - 124px);display:flex;overflow:hidden}.request-id[data-v-7cb554f8]{cursor:pointer;white-space:nowrap;text-overflow:ellipsis;font-family:ui-monospace,Consolas,monospace;display:block;overflow:hidden}.request-id[data-v-7cb554f8]:hover{color:var(--el-color-primary)}.filter-bar[data-v-7cb554f8]{flex-wrap:nowrap;align-items:center;gap:12px;display:flex}.filter-bar[data-v-7cb554f8]>*{flex:none}.filter-bar .session-input[data-v-7cb554f8]{flex:160px;min-width:100px}.filter-bar .push-right[data-v-7cb554f8]{margin-left:auto}.filter-bar .view-switch[data-v-7cb554f8]{flex:none}.filter-bar[data-v-7cb554f8] .el-button+.el-button{margin-left:0}@media (width<=900px){.filter-bar[data-v-7cb554f8]{flex-wrap:wrap}.filter-bar .session-input[data-v-7cb554f8]{flex-basis:100%;min-width:0}.filter-bar .push-right[data-v-7cb554f8]{margin-left:auto}}.mt-16[data-v-7cb554f8]{margin-top:16px}.table-card[data-v-7cb554f8]{flex:1;min-height:0;overflow:hidden}.table-card[data-v-7cb554f8] .el-card__body{flex-direction:column;height:100%;display:flex}.table-wrap[data-v-7cb554f8]{flex:1;min-height:0}.pagination-bar[data-v-7cb554f8]{flex-shrink:0;justify-content:space-between;align-items:center;margin-top:16px;display:flex}
@@ -1,4 +1,4 @@
1
- import{A as e,F as t,I as n,M as r,O as i,P as a,Pt as o,Q as s,Tt as c,V as l,Wt as u,Z as d,at as f,et as p,fn as m,ht as h,it as g,j as _,k as v,mt as y,vt as b,w as x}from"./router-DxY62FPf.js";import{W as S}from"./message-JXw_u_ps.js";import{n as C,t as w}from"./index-DVkpGX_l.js";import{t as T}from"./useManagerApi-7t9qNB2C.js";import{n as E,t as D}from"./useCopyToast-W6vLjLdg.js";import{t as O}from"./useToast-DgnKZwIF.js";import{h as k}from"./format-7jzqzMS_.js";l(),u(),b();var A={class:`form-hint`},j={key:1,class:`form-hint form-hint--block`},M=w(n({__name:`ManagedServiceModal`,props:{editingName:{},service:{}},emits:[`close`,`saved`],setup(n,{emit:o}){let s=n,l=o,{toast:u}=O(),d=c(),f=c(!1),h=c(!0),b=i(()=>s.service?.pid!=null),S=c({name:s.service?.name??``,exec:s.service?.exec??``,cwd:s.service?.cwd??``,autostart:s.service?.autostart??!0}),C=c((s.service?.args??[]).join(`
1
+ import{A as e,F as t,I as n,M as r,O as i,P as a,Pt as o,Q as s,Tt as c,V as l,Wt as u,Z as d,at as f,et as p,fn as m,ht as h,it as g,j as _,k as v,mt as y,vt as b,w as x}from"./router-BgTNV93P.js";import{W as S}from"./message-DpifAOwJ.js";import{n as C,t as w}from"./index-W7WdLt_5.js";import{t as T}from"./useManagerApi-USNyi1JZ.js";import{n as E,t as D}from"./useCopyToast-B_Qvf_Pf.js";import{t as O}from"./useToast-X_JkPDpr.js";import{m as k}from"./format-CPPf8IfM.js";l(),u(),b();var A={class:`form-hint`},j={key:1,class:`form-hint form-hint--block`},M=w(n({__name:`ManagedServiceModal`,props:{editingName:{},service:{}},emits:[`close`,`saved`],setup(n,{emit:o}){let s=n,l=o,{toast:u}=O(),d=c(),f=c(!1),h=c(!0),b=i(()=>s.service?.pid!=null),S=c({name:s.service?.name??``,exec:s.service?.exec??``,cwd:s.service?.cwd??``,autostart:s.service?.autostart??!0}),C=c((s.service?.args??[]).join(`
2
2
  `)),w={name:[{required:!0,message:`请填写服务名`,trigger:`blur`},{pattern:/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/,message:`只能用字母、数字、点、下划线、短横线(字母或数字开头,不超过 64 个字符)`,trigger:`blur`}],cwd:[{required:!0,message:`请填写工作目录`,trigger:`blur`}]},E=async()=>{let e=e=>e.split(`
3
3
  `).map(e=>e.trim()).filter(e=>e!==``);if(!await d.value?.validate().catch(()=>!1)){u(`请补全标红的必填项`,`error`);return}let t={name:S.value.name.trim(),exec:S.value.exec.trim(),args:e(C.value),cwd:S.value.cwd.trim(),autostart:S.value.autostart};b.value||(t.start=h.value),f.value=!0;try{s.editingName===null?(await T.createManagedService(t),u(t.start?`服务已添加并启动`:`服务已添加`,`success`)):(await T.updateManagedService(s.editingName,t),u(b.value?`已保存,服务正按新配置重启`:`已保存`,`success`)),l(`saved`)}catch(e){u(e.message||`保存失败`,`error`)}finally{f.value=!1}};return(i,o)=>{let s=g(`el-input`),c=g(`el-form-item`),u=g(`el-switch`),T=g(`el-form`),D=g(`el-button`),O=g(`el-dialog`);return p(),e(O,{"model-value":!0,title:n.editingName?`编辑托管服务`:`添加托管服务`,width:`720px`,top:`6vh`,"align-center":``,"close-on-click-modal":!1,onClose:o[7]||=e=>l(`close`)},{footer:y(()=>[t(D,{disabled:f.value,onClick:o[6]||=e=>l(`close`)},{default:y(()=>[...o[13]||=[a(`取消`,-1)]]),_:1},8,[`disabled`]),t(D,{type:`primary`,loading:f.value,onClick:E},{default:y(()=>[a(m(f.value?`保存中...`:n.editingName?`保存`:`添加服务`),1)]),_:1},8,[`loading`])]),default:y(()=>[t(T,{ref_key:`formRef`,ref:d,model:S.value,rules:w,"label-position":`top`},{default:y(()=>[t(c,{label:`服务名`,prop:`name`},{default:y(()=>[t(s,{modelValue:S.value.name,"onUpdate:modelValue":o[0]||=e=>S.value.name=e,disabled:n.editingName!==null,placeholder:`如 codebuddy-cpa(字母数字开头,可用 . _ -)`},null,8,[`modelValue`,`disabled`]),v(`div`,A,[o[8]||=a(` 名称用于日志文件名(logs/out-<名称>.log)与进程标识;`,-1),n.editingName===null?_(``,!0):(p(),r(x,{key:0},[a(`编辑时不可修改(改名请删除后重新添加)。`)],64))])]),_:1}),t(c,{label:`工作目录`,prop:`cwd`},{default:y(()=>[t(s,{modelValue:S.value.cwd,"onUpdate:modelValue":o[1]||=e=>S.value.cwd=e,placeholder:`如 E:\\gitee\\codebuddy-cpa(服务的运行目录)`},null,8,[`modelValue`]),o[9]||=v(`div`,{class:`form-hint`},`服务在此目录下启动;保存时会校验目录是否存在。`,-1)]),_:1}),t(c,{label:`可执行文件`},{default:y(()=>[t(s,{modelValue:S.value.exec,"onUpdate:modelValue":o[2]||=e=>S.value.exec=e,placeholder:`留空 = 使用 ezllm 主进程的 Node;也可填 npm.cmd 或绝对路径`},null,8,[`modelValue`]),o[10]||=v(`div`,{class:`form-hint`},` 留空时用主进程的 Node 直接运行下方参数(第一个参数通常是脚本相对工作目录的路径)。 Windows 上 .cmd / .bat / 无扩展名的命令(如 npm)会自动经 cmd.exe 执行;其他平台直接执行。 `,-1)]),_:1}),t(c,{label:`参数`},{default:y(()=>[t(s,{modelValue:C.value,"onUpdate:modelValue":o[3]||=e=>C.value=e,type:`textarea`,rows:3,placeholder:`每行一个参数,如:
4
4
  src/proxy.js
@@ -0,0 +1 @@
1
+ .plugin-grid[data-v-1245bc25]{grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:16px;display:grid}.plugin-card[data-v-1245bc25]{border:1px solid var(--el-border-color-light);border-radius:8px;flex-direction:column;gap:10px;padding:16px;transition:border-color .15s;display:flex}.plugin-card[data-v-1245bc25]:hover{border-color:var(--el-color-primary-light-5)}.card-top[data-v-1245bc25]{align-items:flex-start;gap:12px;display:flex}.plugin-icon[data-v-1245bc25]{background:var(--el-fill-color-light);border-radius:8px;flex-shrink:0;justify-content:center;align-items:center;width:40px;height:40px;font-size:18px;font-weight:600;display:flex;overflow:hidden}.plugin-icon img[data-v-1245bc25]{object-fit:contain;width:100%;height:100%}.plugin-titles[data-v-1245bc25]{flex:1;min-width:0}.plugin-name[data-v-1245bc25]{text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:600;overflow:hidden}.plugin-tags[data-v-1245bc25]{flex-wrap:wrap;gap:6px;margin-top:4px;display:flex}.plugin-action[data-v-1245bc25]{flex-shrink:0}.plugin-summary[data-v-1245bc25]{color:var(--el-text-color-regular);-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;min-height:39px;font-size:13px;line-height:1.5;display:-webkit-box;overflow:hidden}.plugin-meta[data-v-1245bc25]{color:var(--el-text-color-secondary);border-top:1px solid var(--el-border-color-lighter);flex-wrap:wrap;gap:12px;padding-top:10px;font-size:12px;display:flex}.mono[data-v-1245bc25]{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}.pkg-name[data-v-1245bc25]{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.pkg-desc[data-v-1245bc25]{color:var(--el-text-color-secondary);text-overflow:ellipsis;white-space:nowrap;margin-top:2px;font-size:12px;overflow:hidden}.provider-list[data-v-1245bc25]{grid-template-columns:minmax(0,auto) auto auto;justify-content:start;align-items:center;gap:4px 10px;display:grid}.provider-id[data-v-1245bc25]{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.provider-models[data-v-1245bc25]{color:var(--el-text-color-secondary);white-space:nowrap;font-size:12px}.provider-state[data-v-1245bc25]{align-items:center;gap:6px;display:flex}.version-update[data-v-1245bc25]{justify-content:center;align-items:center;gap:6px;margin-top:2px;display:flex}.method-list[data-v-1245bc25]{flex-direction:column;gap:8px;margin-top:12px;display:flex}.method-btn[data-v-1245bc25]{justify-content:flex-start;margin-left:0}.field-row[data-v-1245bc25]:not(:first-child){margin-top:12px}
@@ -0,0 +1,2 @@
1
+ import{A as e,F as t,I as n,M as r,O as i,P as a,Pt as o,Tt as s,V as c,Wt as l,Z as u,et as d,fn as f,it as p,j as m,k as h,m as g,mt as _,nt as v,s as ee,vt as y,w as b,x as te}from"./router-BgTNV93P.js";import{W as ne}from"./message-DpifAOwJ.js";import{n as x,t as S}from"./index-W7WdLt_5.js";import{t as re}from"./useManagerApi-USNyi1JZ.js";import{n as C,t as ie}from"./providers-CkMtur-C.js";import{t as ae}from"./useToast-X_JkPDpr.js";async function w(e,t={}){return await ee.post(`/api/fetch`,{url:e,...t})}async function T(e,t){if(e.binary)throw Error(`${t} 返回二进制内容(${e.contentType||`无 content-type`}),不是 JSON`);let n=e.body;if(e.status<200||e.status>=300){let t=(n??``).trim().slice(0,300);throw Error(`上游返回 HTTP ${String(e.status)}${t===``?``:`:${t}`}`)}if(n===null||n.trim()===``)throw Error(`上游返回空响应体(HTTP ${String(e.status)},${e.contentType||`无 content-type`})`);try{return JSON.parse(n)}catch{throw Error(`上游响应不是 JSON(HTTP ${String(e.status)},${e.contentType||`无 content-type`}):`+n.trim().slice(0,300))}}function E(e,t){return`http://127.0.0.1:${String(e)}${t.startsWith(`/`)?t:`/${t}`}`}async function D(e,t={}){return await T(await w(e,{method:`GET`,...t}),e)}async function oe(e,t,n=`POST`){return await T(await w(e,{method:n,body:t}),e)}async function se(e){return await T(await w(e,{method:`DELETE`}),e)}y();var O=`https://raw.githubusercontent.com/magpie-community/plugins/main/registry.json`,k=[`https://gh-proxy.com/${O}`,`https://ghfast.top/${O}`,O],ce=1e4,A=`plugin_market_cache`,j=1,le=216e5,ue=36e5,de=[`provider`];function fe(){try{let e=localStorage.getItem(A);if(e===null)return null;let t=JSON.parse(e);if(t.version!==j||!Array.isArray(t.entries))return null;let n=t.fetchedAt;return n===void 0||typeof n.at!=`number`?null:{version:j,entries:t.entries.filter(pe),fetchedAt:n}}catch{return null}}function M(e,t){try{let n={version:j,entries:e,fetchedAt:t};localStorage.setItem(A,JSON.stringify(n))}catch{}}function N(e){return typeof e==`string`&&e.trim()!==``?e.trim():null}function P(e){if(typeof e!=`object`||!e||Array.isArray(e))return null;let t=e;return N(t.zh)??N(t.en)}function F(e){switch(e){case`provider`:case`middleware`:case`agent`:case`tools`:case`page`:return e;default:return`provider`}}function I(e){return de.includes(e)}function pe(e){if(typeof e!=`object`||!e)return!1;let t=e.kind;return typeof t==`string`&&I(t)}function me(e){let t=N(e.package);if(t===null)return null;let n=Array.isArray(e.providers)?e.providers.filter(e=>typeof e==`string`):[];return{package:t,name:N(e.name)??t,icon:N(e.icon),providers:n,community:N(e.community),summary:P(e.summary),kind:F(e.kind),replaces:N(e.replaces),version:null,license:null,description:null,homepage:null,weeklyDownloads:null}}var L=new Map,he=new Map;async function R(e){let t=L.get(e);if(t!==void 0&&Date.now()-t.at<ue)return t.meta;try{let t=await D(`https://registry.npmjs.org/${encodeURIComponent(e)}`),n={version:N(t[`dist-tags`]?.latest),license:N(t.license),description:N(t.description),homepage:N(t.homepage)};return L.set(e,{at:Date.now(),meta:n}),n}catch{return{version:null,license:null,description:null,homepage:null}}}async function ge(e){let t=he.get(e);if(t!==void 0&&Date.now()-t.at<ue)return t.downloads;try{let t=await D(`https://api.npmjs.org/downloads/point/last-week/${encodeURIComponent(e)}`),n=typeof t.downloads==`number`?t.downloads:null;return he.set(e,{at:Date.now(),downloads:n}),n}catch{return null}}async function _e(){let e=[];for(let t of k)try{let e=await D(t,{timeoutMs:ce});return t!==k[0]&&C(`[plugin-market] 清单改由备用源取到:${t}`),{registry:e,source:t}}catch(n){let r=n instanceof Error?n.message:String(n);e.push(`${t} → ${r}`)}throw Error(`插件清单取不到(已试 ${String(k.length)} 个源):\n${e.join(`
2
+ `)}`)}async function ve(e){let{registry:t,source:n}=await _e(),r=t.plugins;if(!Array.isArray(r))throw Error(`清单格式不是预期形状(缺 plugins 数组):${O}`);let i=r.map(e=>typeof e==`object`&&e?me(e):null).filter(pe).sort((e,t)=>e.package.localeCompare(t.package)),a=0;return await Promise.all(i.map(async t=>{let[n,r]=await Promise.all([R(t.package),ge(t.package)]);Object.assign(t,n,{weeklyDownloads:r}),a+=1,e?.(a,i.length)})),{entries:i,source:n}}var z=s([]),ye=s(!1),B=s(null),V=s({loaded:0,total:0}),H=s(null),U=s(!1),W=null;function be(e,t){JSON.stringify(e)!==JSON.stringify(z.value)&&(z.value=e),H.value=t,M(e,t)}async function G(e={}){let t=e.force===!0,n=z.value.length===0?fe():null;n!==null&&(z.value=n.entries,H.value=n.fetchedAt);let r=z.value.length>0,i=H.value,a=i!==null&&Date.now()-i.at<le;if(!(!t&&r&&a)){if(W!==null){if(t)await W;else return}if(t||!r){ye.value=!0,U.value=!1,V.value={loaded:0,total:0};try{let e=await ve((e,t)=>{V.value={loaded:e,total:t}});be(e.entries,{source:e.source,at:Date.now()}),B.value=null}catch(e){B.value=`插件市场清单加载失败:${e instanceof Error?e.message:String(e)}`}finally{ye.value=!1}return}U.value=!0,W=(async()=>{try{let e=await ve();be(e.entries,{source:e.source,at:Date.now()}),B.value=null,U.value=!1}catch(e){C(`[plugin-market] 后台刷新失败,继续用缓存:${e instanceof Error?e.message:String(e)}`)}finally{W=null}})()}}function xe(){return{entries:z,loading:ye,marketError:B,progress:V,fetchedAt:H,stale:U,loadMarket:G}}var Se=[`127.0.0.1`,`localhost`,`[::1]`,`::1`],K=`plugin-host`;function q(e){if(e===void 0||e.trim()===``)return null;let t;try{t=new URL(e.trim())}catch{return null}if(!Se.includes(t.hostname.toLowerCase()))return null;let n=/^\/p\/([^/]+)\/?$/.exec(t.pathname);if(n===null)return null;try{return decodeURIComponent(n[1]??``)||null}catch{return null}}function Ce(e,t){return`http://127.0.0.1:${String(e)}/p/${encodeURIComponent(t)}`}function we(e){let t=e.toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-+|-+$/g,``);return t===``?`plugin`:t}function Te(e,t){if(!t.has(e))return e;for(let n=2;;n+=1){let r=`${e}-${n}`;if(!t.has(r))return r}}function Ee(e){let t=new Set,n=[];for(let r of e.models){let e=r.trim();e===``||t.has(e)||(t.add(e),n.push(e))}return n}function De(e,t,n){let r=[...e],i=[],a=[],o=new Set(r.map(e=>e.name)),s=new Set(r.flatMap(e=>e.alias===void 0?[]:[e.alias])),c=new Set(r.flatMap(e=>(e.models??[]).map(e=>e.modelName)));for(let e of t){if(e.protocol===null)continue;let t=Ce(n,e.id),l=r.findIndex(t=>q(t.apiBase)===e.id);if(l>=0){let n=r[l],i={};if(n.apiBase!==t&&(i.apiBase=t),n.customLlmProvider!==e.protocol&&(i.customLlmProvider=e.protocol),(n.apiKey===void 0||n.apiKey.trim()===``)&&(i.apiKey=K),Object.keys(i).length===0)continue;r[l]={...n,...i},a.push(n.name);continue}let u=Te(we(e.id),s);s.add(u);let d=Te(`${e.name||e.id}(插件)`,o);o.add(d);let f=Ee(e).map(e=>{let t=Te(`${u}/${e}`,c);return c.add(t),{modelName:t,model:e}});r.push({name:d,alias:u,customLlmProvider:e.protocol,apiKey:K,apiBase:t,models:f}),i.push(d)}return{providers:r,added:i,updated:a}}function Oe(e,t){let n=new Set(t);return e.filter(e=>{let t=q(e.apiBase);return t!==null&&n.has(t)}).map(e=>e.name)}c(),y(),l(),g();var ke={class:`page-head`},Ae={class:`page-head-actions`},je={class:`flex-between`},Me={class:`muted-sm`},Ne={key:0,class:`loading-block`},Pe={key:1,class:`loading-block`},Fe={key:2,class:`plugin-grid`},Ie={class:`card-top`},Le={class:`plugin-icon`},Re=[`src`,`alt`,`onError`],ze={key:1},Be={class:`plugin-titles`},Ve=[`title`],He={class:`plugin-tags`},Ue={class:`plugin-action`},We=[`title`],Ge={class:`plugin-meta`},Ke={key:0},qe={key:1,class:`mono`},Je={key:2,class:`muted-disabled`},Ye=[`title`],Xe=[`title`],Ze={key:0,class:`muted-disabled`},Qe={key:1,class:`provider-list`},$e=[`title`],et={class:`provider-models`},tt={class:`provider-state`},nt={class:`mono`},rt={key:0,class:`version-update`},it={class:`mono muted-12`},at={class:`method-list`},ot={class:`muted-sm`},st={key:0,class:`muted-sm`},ct={class:`muted-sm`},lt={class:`muted-sm`},ut={key:0,class:`mt-8`},dt=[`href`],ft={key:2,class:`muted-sm mt-8`},pt=S(n({__name:`PluginsView`,setup(n){let{toast:c}=ae(),l=ie(),g=s(!0),ee=s(`服务未由 ezllm 主进程托管(源码运行模式);请用 ezllm 启动服务`),y=s(!1),S=s(!1),C=s(null),w=s(!1),T=s(!0),O=s(!1),{entries:k,loading:ce,marketError:A,progress:j,fetchedAt:le,stale:ue,loadMarket:de}=xe(),fe=s(new Set),M=s([]),N=s(null),P=s(!1),F=s(``),I=s(!1),pe=s(!1),me=s({}),L=s(!1),he=s(!0),R=i(()=>S.value&&C.value!==null),ge=e=>M.value.some(t=>t.package===e.package),_e=e=>e.icon===null||fe.value.has(e.package)?null:/^https?:\/\//i.test(e.icon)?e.icon:null,ve=e=>e.icon!==null&&!/^https?:\/\//i.test(e.icon)?e.icon:(e.name.charAt(0)||`?`).toUpperCase(),z=e=>{fe.value=new Set(fe.value).add(e.package)},ye=e=>e>=1e3?`${(e/1e3).toFixed(e>=1e4?0:1)}k`:String(e),B=async()=>{try{let e=await re.plugins();g.value=!0,y.value=e.enabled,T.value=e.autoUpdate,S.value=e.running,C.value=e.port}catch(e){if(typeof e?.message==`string`&&e.message.includes(`未由 ezllm 主进程托管`)){g.value=!1,ee.value=e.message,y.value=!1,T.value=!1,S.value=!1,C.value=null;return}throw e}},V=async()=>{if(!R.value){M.value=[];return}let e=C.value;if(e!==null)try{let t=await D(E(e,`/packages`));M.value=Array.isArray(t.packages)?t.packages:[]}catch{M.value=[]}},H=e=>{let t=Math.floor((Date.now()-e)/6e4);if(t<1)return`刚刚`;if(t<60)return`${String(t)} 分钟前`;let n=Math.floor(t/60);return n<24?`${String(n)} 小时前`:new Date(e).toLocaleDateString()},U=i(()=>{if(ce.value)return`正在加载 ${String(j.value.loaded)}/${String(j.value.total)}…`;let e=le.value===null?``:H(le.value.at),t=e===``?``:` · ${e}更新`,n=ue.value?` · 更新中…`:``;return`${String(k.value.length)} 个插件 · 已装 ${String(M.value.length)} 个${t}${n}`}),W=async(e=!1)=>{await de({force:e})},be=async()=>{try{await B()}catch(e){A.value=e?.message??`插件服务状态加载失败`;return}await V(),await W()},G=s(!1),Se=async e=>{let t=await D(E(e,`/plugins`));return Array.isArray(t.providers)?t.providers:[]},K=async()=>{let e=C.value;if(R.value&&e!==null){G.value=!0;try{await l.loadProviders();let t=De(l.suppliers,await Se(e),e);if(t.added.length===0&&t.updated.length===0)return;await l.saveProviders(t.providers);let n=[];t.added.length>0&&n.push(`新增 ${String(t.added.length)} 个`),t.updated.length>0&&n.push(`修正 ${String(t.updated.length)} 个`),c(`已接入网关:${n.join(`、`)}供应商`,`success`)}catch(e){c(e?.message??`供应商配置同步失败`,`error`)}finally{G.value=!1}}},q=async e=>{w.value=!0;try{let t=await re.setPluginEnabled(e);y.value=t.enabled,S.value=t.running,C.value=t.port,c(e?`插件服务已开启`:`插件服务已关闭`,`success`),await V()}catch(e){await B().catch(()=>void 0),c(e?.message??`操作失败`,`error`)}finally{w.value=!1}},Ce=async e=>{if(e){await q(!0);return}try{await x.confirm(`关闭插件服务?已装插件保留,但插件模型的请求将不可用。`,`关闭确认`,{confirmButtonText:`关闭`,cancelButtonText:`取消`,type:`warning`})}catch{await B().catch(()=>void 0);return}await q(!1)},we=async e=>{let t=!!e;O.value=!0;try{let e=await re.setPluginAutoUpdate(t);T.value=e.autoUpdate,c(t?`已开启插件自动更新`:`已关闭插件自动更新`,`success`)}catch(e){await B().catch(()=>void 0),c(e?.message??`操作失败`,`error`)}finally{O.value=!1}},Te=async e=>{await pt(e.package)},Ee=async()=>{let e=F.value.trim();if(e!==``){pe.value=!0;try{await pt(e),P.value=!1,F.value=``}finally{pe.value=!1}}},pt=async e=>{let t=C.value;if(t===null){c(`插件服务未开启`,`error`);return}N.value=e;try{(await oe(E(t,`/packages`),{package:e})).loaded===!1?c(`${e} 已安装但未加载成功(重启插件服务或查看日志)`,`warning`):c(`已安装 ${e}`,`success`),await V(),await K()}catch(e){c(e?.message??`安装失败`,`error`)}finally{N.value=null}},mt=async e=>{let t=C.value;if(t===null)return;let n=[];try{await l.loadProviders(),n=Oe(l.suppliers,e.providers.map(e=>e.id))}catch{}let r=n.length===0?``:`网关里对应的供应商(${n.join(`、`)})也会一并移除。`;try{await x.confirm(`确定卸载 ${e.package}?该插件提供的模型将不可用。${r}`,`确认卸载`,{confirmButtonText:`卸载`,cancelButtonText:`取消`,type:`warning`})}catch{return}N.value=e.package;try{await se(E(t,`/packages/${encodeURIComponent(e.package)}`)),n.length>0&&await l.saveProviders(l.suppliers.filter(e=>!n.includes(e.name))),c(`已卸载 ${e.package}`,`success`),await V()}catch(e){c(e?.message??`卸载失败`,`error`)}finally{N.value=null}},ht=()=>{F.value=``,P.value=!0},gt=async()=>{await V(),I.value=!0},_t=i(()=>R.value?he.value?`检查已装插件是否有新版本`:`宿主当前无法检查更新`:`插件服务未开启`),vt=e=>{let t=me.value[e];return t&&t.updateAvailable&&t.latest?t.latest:null},yt=async(e=!1)=>{let t=C.value;if(t===null){e||c(`插件服务未开启`,`error`);return}L.value=!0;try{let n=await D(E(t,`/packages/updates`)),r=Array.isArray(n.packages)?n.packages:[];he.value=n.canCheck;let i={};for(let e of r)i[e.package]=e;if(me.value=i,e)return;if(!n.canCheck){c(`宿主当前无法检查更新`,`warning`);return}let a=r.filter(e=>e.updateAvailable).length;c(a>0?`发现 ${String(a)} 个插件有新版本`:`全部插件已是最新`,`success`)}catch(t){e||c(t?.message??`检查更新失败`,`error`)}finally{L.value=!1}},bt=async e=>{let t=C.value,n=me.value[e]?.latest;if(t===null){c(`插件服务未开启`,`error`);return}if(n!=null){N.value=e;try{await oe(E(t,`/packages`),{package:e,version:n});let r=await re.restartPlugins();S.value=r.running,C.value=r.port,c(`已更新到 ${n} 并重启插件服务`,`success`),delete me.value[e],await V(),await yt(!0)}catch(e){c(e?.message??`更新失败`,`error`)}finally{N.value=null}}},xt=s(null),St=s(!1),Ct=s(``),wt=s([]),Tt=s(!1),Et=s(``),Dt=s(``),Ot=s(``),J=s(null),Y=s(!1),kt=s(``),At=s(``),jt=s(``),X=s(``),Mt=s(void 0),Nt=s({}),Z=s(null),Pt=s(!1),Q=s(!1),Ft=s(``),It=s([]),$=s({}),Lt=s(void 0),Rt=s(null),zt=s(!1),Bt=(e,t)=>{Dt.value=e,Et.value=t.url??``,Ot.value=t.instructions??``,J.value=null,Tt.value=!0},Vt=async e=>{let t=C.value;if(t===null)return;let n=Date.now()+18e4;for(;;){await new Promise(e=>setTimeout(e,2e3));let r;try{r=await D(E(t,`/login/${encodeURIComponent(e)}`))}catch(e){J.value=e?.message??`查询登录状态失败`;return}if(r.state===`success`){Tt.value=!1,c(`已登录${r.accountId?`(${r.accountId})`:``}`,`success`),await V(),await K();return}if(r.state===`failed`){J.value=r.error??`登录失败`;return}if(Date.now()>n){J.value=`等待超时,可关闭后重新点击「登录」`;return}}},Ht=async(e,t,n,r)=>{let i=C.value;if(i===null){c(`插件服务未开启`,`error`);return}let a={};t!==void 0&&(a.method=t),Object.keys(n).length>0&&(a.inputs=n),r!==void 0&&r!==``&&(a.key=r);let o=await oe(E(i,`/login/${encodeURIComponent(e)}`),a);if(o.needMethod===!0){Ct.value=e,wt.value=o.methods,St.value=!0;return}if(o.needInputs!==void 0&&o.needInputs.length>0){Y.value=!1,Ft.value=e,Lt.value=t,It.value=o.needInputs;let r={...o.inputs??n};for(let e of o.needInputs)r[e.key]=r[e.key]??``;$.value=r,Rt.value=null,Q.value=!0;return}if(o.needKey===!0){Q.value=!1,kt.value=e,Mt.value=t,At.value=o.label??``,jt.value=o.placeholder??``,Nt.value={...o.inputs??n},X.value=``,Z.value=null,Y.value=!0;return}if(o.state===`success`){Q.value=!1,Y.value=!1,c(`已登录${o.accountId?`(${o.accountId})`:``}`,`success`),await V(),await K();return}if(o.state===`failed`){let e=o.error??`登录失败`;if(Y.value){Z.value=e;return}if(Q.value){Rt.value=e;return}c(e,`error`);return}Q.value=!1,Y.value=!1,Bt(e,o),Vt(e)},Ut=async(e,t)=>{xt.value=e;try{await Ht(e,t,{})}catch(e){c(e?.message??`发起登录失败`,`error`)}finally{xt.value=null}},Wt=async e=>{St.value=!1,await Ut(Ct.value,e)},Gt=async()=>{zt.value=!0;try{await Ht(Ft.value,Lt.value,{...$.value})}catch(e){Rt.value=e?.message??`提交失败`}finally{zt.value=!1}},Kt=async()=>{if(X.value.trim()===``){Z.value=`请填写密钥`;return}Pt.value=!0,Z.value=null;try{await Ht(kt.value,Mt.value,{...Nt.value},X.value)}catch(e){Z.value=e?.message??`提交失败`}finally{Pt.value=!1}};return u(be),(n,i)=>{let s=p(`el-switch`),c=p(`el-button`),l=p(`el-icon`),u=p(`el-alert`),x=p(`el-tag`),re=p(`el-card`),C=p(`el-input`),ie=p(`el-form-item`),ae=p(`el-form`),E=p(`el-dialog`),D=p(`el-table-column`),oe=p(`el-table`),se=p(`el-option`),j=p(`el-select`);return d(),r(`div`,null,[h(`div`,ke,[i[22]||=h(`div`,null,[h(`div`,{class:`page-head-title`},`插件`),h(`div`,{class:`page-head-sub`},` 订阅社区 OpenCode 插件——把订阅账号(CodeBuddy、智谱 Coding Plan 等)当作供应商接入网关 `)],-1),h(`div`,Ae,[t(s,{modelValue:y.value,"onUpdate:modelValue":i[0]||=e=>y.value=e,loading:w.value,disabled:!g.value||w.value,"active-text":`插件服务`,"inline-prompt":``,onChange:Ce},null,8,[`modelValue`,`loading`,`disabled`]),t(s,{modelValue:T.value,"onUpdate:modelValue":i[1]||=e=>T.value=e,loading:O.value,disabled:!g.value||O.value,"active-text":`自动更新`,"inline-prompt":``,title:`插件会在后台每小时检查并更新`,onChange:we},null,8,[`modelValue`,`loading`,`disabled`]),t(c,{disabled:!S.value,onClick:gt},{default:_(()=>[...i[19]||=[a(`已装插件`,-1)]]),_:1},8,[`disabled`]),t(c,{disabled:!S.value,onClick:ht},{default:_(()=>[t(l,null,{default:_(()=>[t(o(ne))]),_:1}),i[20]||=a(` 手动安装 `,-1)]),_:1},8,[`disabled`]),t(c,{loading:o(ce),onClick:i[2]||=e=>W(!0)},{default:_(()=>[...i[21]||=[a(`刷新`,-1)]]),_:1},8,[`loading`])])]),g.value?S.value?m(``,!0):(d(),e(u,{key:1,type:`info`,"show-icon":``,closable:!1,class:`mb-16`,title:`插件服务未开启`},{default:_(()=>[i[24]||=h(`div`,{class:`muted-sm`},`开启后即可安装并加载插件;下方清单仍可浏览。`,-1),t(c,{size:`small`,type:`primary`,class:`mt-8`,loading:w.value,onClick:i[3]||=e=>q(!0)},{default:_(()=>[...i[23]||=[a(` 开启插件服务 `,-1)]]),_:1},8,[`loading`])]),_:1})):(d(),e(u,{key:0,type:`warning`,"show-icon":``,closable:!1,class:`mb-16`,title:`插件服务不可用`},{default:_(()=>[a(f(ee.value),1)]),_:1})),o(A)?(d(),e(u,{key:2,type:`error`,"show-icon":``,closable:!1,class:`mb-16`,title:o(A)},{default:_(()=>[t(c,{size:`small`,onClick:W},{default:_(()=>[...i[25]||=[a(`重试`,-1)]]),_:1})]),_:1},8,[`title`])):m(``,!0),t(re,{shadow:`never`},{header:_(()=>[h(`div`,je,[i[26]||=h(`span`,{class:`fw-600`},`社区插件`,-1),h(`span`,Me,f(U.value),1)])]),default:_(()=>[o(ce)&&o(k).length===0?(d(),r(`div`,Ne,`正在从社区清单加载…`)):o(k).length===0?(d(),r(`div`,Pe,` 清单里没有本宿主支持的插件(只收 provider 类),可点右上角「刷新」重试,或用「手动安装」直接按包名安装。 `)):(d(),r(`div`,Fe,[(d(!0),r(b,null,v(o(k),t=>(d(),r(`div`,{key:t.package,class:`plugin-card`},[h(`div`,Ie,[h(`div`,Le,[_e(t)?(d(),r(`img`,{key:0,src:_e(t),alt:t.name,onError:e=>z(t)},null,40,Re)):(d(),r(`span`,ze,f(ve(t)),1))]),h(`div`,Be,[h(`div`,{class:`plugin-name`,title:t.name},f(t.name),9,Ve),h(`div`,He,[t.community?(d(),e(x,{key:0,size:`small`,type:`info`,"disable-transitions":``},{default:_(()=>[a(f(t.community),1)]),_:2},1024)):m(``,!0)])]),h(`div`,Ue,[ge(t)?(d(),e(x,{key:0,type:`success`,size:`small`,"disable-transitions":``},{default:_(()=>[...i[27]||=[a(`已装`,-1)]]),_:1})):(d(),e(c,{key:1,type:`primary`,size:`small`,disabled:!R.value||N.value===t.package,loading:N.value===t.package,onClick:e=>Te(t)},{default:_(()=>[...i[28]||=[a(` 安装 `,-1)]]),_:1},8,[`disabled`,`loading`,`onClick`]))])]),h(`div`,{class:`plugin-summary`,title:t.summary??``},f(t.summary??`(清单未提供简介)`),9,We),h(`div`,Ge,[h(`span`,null,`供应商 `+f(t.providers.length),1),t.weeklyDownloads===null?m(``,!0):(d(),r(`span`,Ke,f(ye(t.weeklyDownloads))+`/周`,1)),t.version?(d(),r(`span`,qe,`v`+f(t.version),1)):(d(),r(`span`,Je,`版本未知`))])]))),128))]))]),_:1}),t(E,{modelValue:P.value,"onUpdate:modelValue":i[6]||=e=>P.value=e,title:`手动安装插件`,width:`520px`},{footer:_(()=>[t(c,{onClick:i[5]||=e=>P.value=!1},{default:_(()=>[...i[30]||=[a(`取消`,-1)]]),_:1}),t(c,{type:`primary`,loading:pe.value,disabled:F.value.trim()===``,onClick:Ee},{default:_(()=>[...i[31]||=[a(` 安装 `,-1)]]),_:1},8,[`loading`,`disabled`])]),default:_(()=>[t(ae,{"label-position":`top`},{default:_(()=>[t(ie,{label:`npm 包名`},{default:_(()=>[t(C,{modelValue:F.value,"onUpdate:modelValue":i[4]||=e=>F.value=e,placeholder:`例:@magpie-community/opencode-workbuddy-auth`,clearable:``},null,8,[`modelValue`]),i[29]||=h(`div`,{class:`muted-sm`},[a(`可带版本(`),h(`span`,{class:`mono`},`name@1.2.3`),a(`);清单加载不出来时用这个。`)],-1)]),_:1})]),_:1})]),_:1},8,[`modelValue`]),t(E,{modelValue:I.value,"onUpdate:modelValue":i[9]||=e=>I.value=e,title:`已装插件`,width:`1100px`,top:`6vh`},{footer:_(()=>[t(c,{disabled:!R.value||G.value,loading:G.value,title:`把宿主已加载的插件供应商补进网关配置:缺的整条新增,已在的只修地址/协议(模型清单保持你的选择)`,onClick:K},{default:_(()=>[...i[39]||=[a(`接入网关`,-1)]]),_:1},8,[`disabled`,`loading`]),t(c,{disabled:!R.value||!he.value||N.value!==null,loading:L.value,title:_t.value,onClick:i[7]||=e=>yt()},{default:_(()=>[...i[40]||=[a(`检查更新`,-1)]]),_:1},8,[`disabled`,`loading`,`title`]),t(c,{onClick:i[8]||=e=>I.value=!1},{default:_(()=>[...i[41]||=[a(`关闭`,-1)]]),_:1})]),default:_(()=>[t(oe,{data:M.value,"empty-text":`尚未安装任何插件`,class:`dense-table`},{default:_(()=>[t(D,{label:`插件包`,"min-width":`320`},{default:_(({row:e})=>[h(`div`,{class:`mono pkg-name`,title:e.package},f(e.package),9,Ye),e.description?(d(),r(`div`,{key:0,class:`pkg-desc`,title:e.description},f(e.description),9,Xe)):m(``,!0)]),_:1}),t(D,{label:`供应商`,"min-width":`280`},{default:_(({row:n})=>[n.providers.length?(d(),r(`div`,Qe,[(d(!0),r(b,null,v(n.providers,n=>(d(),r(b,{key:n.id},[h(`span`,{class:`mono provider-id`,title:n.id},f(n.id),9,$e),h(`span`,et,f(n.models)+` 个模型`,1),h(`span`,tt,[n.signedIn?(d(),e(x,{key:0,type:`success`,size:`small`,"disable-transitions":``},{default:_(()=>[...i[32]||=[a(`已登录`,-1)]]),_:1})):(d(),r(b,{key:1},[t(x,{type:`info`,size:`small`,effect:`plain`,"disable-transitions":``},{default:_(()=>[...i[33]||=[a(`未登录`,-1)]]),_:1}),t(c,{link:``,type:`primary`,size:`small`,loading:xt.value===n.id,onClick:e=>Ut(n.id)},{default:_(()=>[...i[34]||=[a(` 登录 `,-1)]]),_:1},8,[`loading`,`onClick`])],64))])],64))),128))])):(d(),r(`div`,Ze,`-`))]),_:1}),t(D,{label:`版本`,width:`180`,align:`center`},{default:_(({row:e})=>[h(`div`,nt,f(e.version||`-`),1),vt(e.package)?(d(),r(`div`,rt,[h(`span`,it,`→ `+f(vt(e.package)),1),t(c,{link:``,type:`primary`,size:`small`,disabled:N.value!==null||L.value,loading:N.value===e.package,onClick:t=>bt(e.package)},{default:_(()=>[...i[35]||=[a(`更新`,-1)]]),_:1},8,[`disabled`,`loading`,`onClick`])])):m(``,!0)]),_:1}),t(D,{label:`状态`,width:`100`,align:`center`},{default:_(({row:t})=>[t.loaded?(d(),e(x,{key:0,type:`success`,size:`small`,"disable-transitions":``},{default:_(()=>[...i[36]||=[a(`已加载`,-1)]]),_:1})):(d(),e(x,{key:1,type:`danger`,size:`small`,"disable-transitions":``},{default:_(()=>[...i[37]||=[a(`加载失败`,-1)]]),_:1}))]),_:1}),t(D,{label:`操作`,width:`90`,align:`center`},{default:_(({row:e})=>[t(c,{link:``,type:`danger`,loading:N.value===e.package,onClick:t=>mt(e)},{default:_(()=>[...i[38]||=[a(`卸载`,-1)]]),_:1},8,[`loading`,`onClick`])]),_:1})]),_:1},8,[`data`])]),_:1},8,[`modelValue`]),t(E,{modelValue:St.value,"onUpdate:modelValue":i[11]||=e=>St.value=e,title:`选择登录方式`,width:`460px`},{footer:_(()=>[t(c,{onClick:i[10]||=e=>St.value=!1},{default:_(()=>[...i[42]||=[a(`取消`,-1)]]),_:1})]),default:_(()=>[i[43]||=h(`div`,{class:`muted-sm`},`该插件提供多种登录方式,选一种:`,-1),h(`div`,at,[(d(!0),r(b,null,v(wt.value,t=>(d(),e(c,{key:t.label,class:`method-btn`,onClick:e=>Wt(t.label)},{default:_(()=>[a(f(t.label||t.type),1)]),_:2},1032,[`onClick`]))),128))])]),_:1},8,[`modelValue`]),t(E,{modelValue:Q.value,"onUpdate:modelValue":i[13]||=e=>Q.value=e,title:`登录 ${Ft.value}`,width:`480px`},{footer:_(()=>[t(c,{onClick:i[12]||=e=>Q.value=!1},{default:_(()=>[...i[44]||=[a(`取消`,-1)]]),_:1}),t(c,{type:`primary`,loading:zt.value,onClick:Gt},{default:_(()=>[...i[45]||=[a(`确定`,-1)]]),_:1},8,[`loading`])]),default:_(()=>[(d(!0),r(b,null,v(It.value,t=>(d(),r(`div`,{key:t.key,class:`field-row`},[h(`div`,ot,f(t.message||t.key),1),t.type===`select`?(d(),e(j,{key:0,modelValue:$.value[t.key],"onUpdate:modelValue":e=>$.value[t.key]=e,class:`mt-8`,placeholder:`请选择`,style:{width:`100%`}},{default:_(()=>[(d(!0),r(b,null,v(t.options,t=>(d(),e(se,{key:t.value,label:t.label??t.value,value:t.value??``},{default:_(()=>[h(`span`,null,f(t.label??t.value),1),t.hint?(d(),r(`span`,st,`(`+f(t.hint)+`)`,1)):m(``,!0)]),_:2},1032,[`label`,`value`]))),128))]),_:2},1032,[`modelValue`,`onUpdate:modelValue`])):(d(),e(C,{key:1,modelValue:$.value[t.key],"onUpdate:modelValue":e=>$.value[t.key]=e,class:`mt-8`,placeholder:t.placeholder||``,onKeyup:te(Gt,[`enter`])},null,8,[`modelValue`,`onUpdate:modelValue`,`placeholder`]))]))),128)),Rt.value?(d(),e(u,{key:0,type:`error`,"show-icon":``,closable:!1,class:`mt-8`,title:Rt.value},null,8,[`title`])):m(``,!0)]),_:1},8,[`modelValue`,`title`]),t(E,{modelValue:Y.value,"onUpdate:modelValue":i[16]||=e=>Y.value=e,title:`登录 ${kt.value}`,width:`480px`},{footer:_(()=>[t(c,{onClick:i[15]||=e=>Y.value=!1},{default:_(()=>[...i[46]||=[a(`取消`,-1)]]),_:1}),t(c,{type:`primary`,loading:Pt.value,onClick:Kt},{default:_(()=>[...i[47]||=[a(`确定`,-1)]]),_:1},8,[`loading`])]),default:_(()=>[h(`div`,ct,f(At.value||`该登录方式需要一枚密钥`),1),t(C,{modelValue:X.value,"onUpdate:modelValue":i[14]||=e=>X.value=e,class:`mt-8`,placeholder:jt.value||`粘贴密钥`,"show-password":``,onKeyup:te(Kt,[`enter`])},null,8,[`modelValue`,`placeholder`]),Z.value?(d(),e(u,{key:0,type:`error`,"show-icon":``,closable:!1,class:`mt-8`,title:Z.value},null,8,[`title`])):m(``,!0)]),_:1},8,[`modelValue`,`title`]),t(E,{modelValue:Tt.value,"onUpdate:modelValue":i[18]||=e=>Tt.value=e,title:`登录 ${Dt.value}`,width:`480px`},{footer:_(()=>[t(c,{onClick:i[17]||=e=>Tt.value=!1},{default:_(()=>[...i[49]||=[a(`关闭`,-1)]]),_:1})]),default:_(()=>[h(`div`,lt,f(Ot.value||`正在读取本机已登录的凭据…`),1),Et.value?(d(),r(`div`,ut,[h(`a`,{class:`el-button el-button--primary`,href:Et.value,target:`_blank`,rel:`noopener`},` 打开登录页 `,8,dt),i[48]||=h(`div`,{class:`muted-sm mt-8`},`在打开的页面完成登录即可,本页会自动检测(最长等待几分钟)。`,-1)])):m(``,!0),J.value?(d(),e(u,{key:1,type:`error`,"show-icon":``,closable:!1,class:`mt-8`,title:J.value},null,8,[`title`])):(d(),r(`div`,ft,`等待登录完成…`))]),_:1},8,[`modelValue`,`title`])])}}}),[[`__scopeId`,`data-v-1245bc25`]]);export{pt as default};
@@ -1,4 +1,4 @@
1
- import{A as e,Bt as t,Ct as n,F as r,Ft as i,Gt as a,I as o,It as s,Kt as c,Lt as l,M as u,O as d,P as f,Pt as p,Q as m,Qt as h,Rt as g,S as _,Tt as v,V as y,Vt as b,Wt as x,Xt as S,Yt as C,Z as w,Zt as T,_n as E,a as D,an as O,dn as k,et as A,fn as j,ft as M,g as ee,gn as te,hn as ne,in as re,it as N,j as P,k as F,m as ie,mn as ae,mt as I,nn as oe,nt as se,on as ce,pn as le,rn as L,sn as ue,tn as de,un as fe,vn as pe,vt as R,w as me,x as he,zt as ge}from"./router-DxY62FPf.js";import{G as _e,H as ve,K as ye,P as be,W as xe}from"./message-JXw_u_ps.js";import{n as Se,r as Ce,t as we}from"./index-DVkpGX_l.js";import{t as Te}from"./providers-CbsDigh3.js";import{n as Ee,t as De}from"./useCopyToast-W6vLjLdg.js";import{t as Oe}from"./useToast-DgnKZwIF.js";import{d as ke,y as Ae}from"./format-7jzqzMS_.js";function je(e){Object.getOwnPropertySymbols(e).forEach(t=>{ai[t]=e[t]})}function Me(e,t=``){return{type:0,source:t,children:e,helpers:new Set,components:[],directives:[],hoists:[],imports:[],cached:[],temps:0,codegenNode:void 0,loc:ui}}function Ne(e,t,n,r,i,a,o,s=!1,c=!1,l=!1,u=ui){return e&&(s?(e.helper(Tr),e.helper(Xe(e.inSSR,l))):e.helper(Ye(e.inSSR,l)),o&&e.helper(Lr)),{type:13,tag:t,props:n,children:r,patchFlag:i,dynamicProps:a,directives:o,isBlock:s,disableTracking:c,isComponent:l,loc:u}}function Pe(e,t=ui){return{type:17,loc:t,elements:e}}function Fe(e,t=ui){return{type:15,loc:t,properties:e}}function Ie(e,t){return{type:16,loc:ui,key:L(e)?z(e,!0):e,value:t}}function z(e,t=!1,n=ui,r=0){return{type:4,loc:n,content:e,isStatic:t,constType:t?3:r}}function Le(e,t){return{type:5,loc:t,content:L(e)?z(e,!1,t):e}}function Re(e,t=ui){return{type:8,loc:t,children:e}}function ze(e,t=[],n=ui){return{type:14,loc:n,callee:e,arguments:t}}function Be(e,t=void 0,n=!1,r=!1,i=ui){return{type:18,params:e,returns:t,newline:n,isSlot:r,loc:i}}function Ve(e,t,n,r=!0){return{type:19,test:e,consequent:t,alternate:n,newline:r,loc:ui}}function He(e,t,n=!1,r=!1){return{type:20,index:e,value:t,needPauseTracking:n,inVOnce:r,needArraySpread:!1,loc:ui}}function Ue(e){return{type:21,body:e,loc:ui}}function We(e){return{type:22,elements:e,loc:ui}}function Ge(e,t,n){return{type:23,test:e,consequent:t,alternate:n,loc:ui}}function Ke(e,t){return{type:24,left:e,right:t,loc:ui}}function qe(e){return{type:25,expressions:e,loc:ui}}function Je(e){return{type:26,returns:e,loc:ui}}function Ye(e,t){return e||t?Or:kr}function Xe(e,t){return e||t?Er:Dr}function Ze(e,{helper:t,removeHelper:n,inSSR:r}){e.isBlock||(e.isBlock=!0,n(Ye(r,e.isComponent)),t(Tr),t(Xe(r,e.isComponent)))}function Qe(e){return e>=97&&e<=122||e>=65&&e<=90}function $e(e){return e===32||e===10||e===9||e===12||e===13}function et(e){return e===47||e===62||$e(e)}function tt(e){let t=new Uint8Array(e.length);for(let n=0;n<e.length;n++)t[n]=e.charCodeAt(n);return t}function nt(e,{compatConfig:t}){let n=t&&t[e];return e===`MODE`?n||3:n}function rt(e,t){let n=nt(`MODE`,t),r=nt(e,t);return n===3?r===!0:r!==!1}function it(e,t,n,...r){return rt(e,t)}function at(e,t,n,...r){if(nt(e,t)===`suppress-warning`)return;let{message:i,link:a}=gi[e],o=`(deprecation ${e}) ${typeof i==`function`?i(...r):i}${a?`
1
+ import{A as e,Bt as t,Ct as n,F as r,Ft as i,Gt as a,I as o,It as s,Kt as c,Lt as l,M as u,O as d,P as f,Pt as p,Q as m,Qt as h,Rt as g,S as _,Tt as v,V as y,Vt as b,Wt as x,Xt as S,Yt as C,Z as w,Zt as T,_n as E,a as D,an as O,dn as k,et as A,fn as j,ft as M,g as ee,gn as te,hn as ne,in as re,it as N,j as P,k as F,m as ie,mn as ae,mt as I,nn as oe,nt as se,on as ce,pn as le,rn as L,sn as ue,tn as de,un as fe,vn as pe,vt as R,w as me,x as he,zt as ge}from"./router-BgTNV93P.js";import{G as _e,H as ve,K as ye,P as be,W as xe}from"./message-DpifAOwJ.js";import{n as Se,r as Ce,t as we}from"./index-W7WdLt_5.js";import{t as Te}from"./providers-CkMtur-C.js";import{n as Ee,t as De}from"./useCopyToast-B_Qvf_Pf.js";import{t as Oe}from"./useToast-X_JkPDpr.js";import{u as ke,v as Ae}from"./format-CPPf8IfM.js";function je(e){Object.getOwnPropertySymbols(e).forEach(t=>{ai[t]=e[t]})}function Me(e,t=``){return{type:0,source:t,children:e,helpers:new Set,components:[],directives:[],hoists:[],imports:[],cached:[],temps:0,codegenNode:void 0,loc:ui}}function Ne(e,t,n,r,i,a,o,s=!1,c=!1,l=!1,u=ui){return e&&(s?(e.helper(Tr),e.helper(Xe(e.inSSR,l))):e.helper(Ye(e.inSSR,l)),o&&e.helper(Lr)),{type:13,tag:t,props:n,children:r,patchFlag:i,dynamicProps:a,directives:o,isBlock:s,disableTracking:c,isComponent:l,loc:u}}function Pe(e,t=ui){return{type:17,loc:t,elements:e}}function Fe(e,t=ui){return{type:15,loc:t,properties:e}}function Ie(e,t){return{type:16,loc:ui,key:L(e)?z(e,!0):e,value:t}}function z(e,t=!1,n=ui,r=0){return{type:4,loc:n,content:e,isStatic:t,constType:t?3:r}}function Le(e,t){return{type:5,loc:t,content:L(e)?z(e,!1,t):e}}function Re(e,t=ui){return{type:8,loc:t,children:e}}function ze(e,t=[],n=ui){return{type:14,loc:n,callee:e,arguments:t}}function Be(e,t=void 0,n=!1,r=!1,i=ui){return{type:18,params:e,returns:t,newline:n,isSlot:r,loc:i}}function Ve(e,t,n,r=!0){return{type:19,test:e,consequent:t,alternate:n,newline:r,loc:ui}}function He(e,t,n=!1,r=!1){return{type:20,index:e,value:t,needPauseTracking:n,inVOnce:r,needArraySpread:!1,loc:ui}}function Ue(e){return{type:21,body:e,loc:ui}}function We(e){return{type:22,elements:e,loc:ui}}function Ge(e,t,n){return{type:23,test:e,consequent:t,alternate:n,loc:ui}}function Ke(e,t){return{type:24,left:e,right:t,loc:ui}}function qe(e){return{type:25,expressions:e,loc:ui}}function Je(e){return{type:26,returns:e,loc:ui}}function Ye(e,t){return e||t?Or:kr}function Xe(e,t){return e||t?Er:Dr}function Ze(e,{helper:t,removeHelper:n,inSSR:r}){e.isBlock||(e.isBlock=!0,n(Ye(r,e.isComponent)),t(Tr),t(Xe(r,e.isComponent)))}function Qe(e){return e>=97&&e<=122||e>=65&&e<=90}function $e(e){return e===32||e===10||e===9||e===12||e===13}function et(e){return e===47||e===62||$e(e)}function tt(e){let t=new Uint8Array(e.length);for(let n=0;n<e.length;n++)t[n]=e.charCodeAt(n);return t}function nt(e,{compatConfig:t}){let n=t&&t[e];return e===`MODE`?n||3:n}function rt(e,t){let n=nt(`MODE`,t),r=nt(e,t);return n===3?r===!0:r!==!1}function it(e,t,n,...r){return rt(e,t)}function at(e,t,n,...r){if(nt(e,t)===`suppress-warning`)return;let{message:i,link:a}=gi[e],o=`(deprecation ${e}) ${typeof i==`function`?i(...r):i}${a?`
2
2
  Details: ${a}`:``}`,s=SyntaxError(o);s.code=e,n&&(s.loc=n),t.onWarn(s)}function ot(e){throw e}function st(e){}function B(e,t,n,r){let i=`https://vuejs.org/error-reference/#compiler-${e}`,a=SyntaxError(String(i));return a.code=e,a.loc=t,a}function ct(e,t,n=!1,r=[],i=Object.create(null)){}function lt(e,t,n){return!1}function ut(e,t){if(e&&(e.type===`ObjectProperty`||e.type===`ArrayPattern`)){let e=t.length;for(;e--;){let n=t[e];if(n.type===`AssignmentExpression`)return!0;if(n.type!==`ObjectProperty`&&!n.type.endsWith(`Pattern`))break}}return!1}function dt(e){let t=e.length;for(;t--;){let n=e[t];if(n.type===`NewExpression`)return!0;if(n.type!==`MemberExpression`)break}return!1}function ft(e,t){for(let n of e.params)for(let e of _t(n))t(e)}function pt(e,t){let n=e.type===`SwitchCase`?e.consequent:e.body;for(let e of n)if(e.type===`VariableDeclaration`){if(e.declare)continue;for(let n of e.declarations)for(let e of _t(n.id))t(e)}else if(e.type===`FunctionDeclaration`||e.type===`ClassDeclaration`){if(e.declare||!e.id)continue;t(e.id)}else mt(e)?ht(e,!0,t):e.type===`SwitchStatement`&&gt(e,!0,t)}function mt(e){return e.type===`ForOfStatement`||e.type===`ForInStatement`||e.type===`ForStatement`}function ht(e,t,n){let r=e.type===`ForStatement`?e.init:e.left;if(r&&r.type===`VariableDeclaration`&&(r.kind===`var`?t:!t))for(let e of r.declarations)for(let t of _t(e.id))n(t)}function gt(e,t,n){for(let r of e.cases){for(let e of r.consequent)if(e.type===`VariableDeclaration`&&(e.kind===`var`?t:!t))for(let t of e.declarations)for(let e of _t(t.id))n(e);pt(r,n)}}function _t(e,t=[]){switch(e.type){case`Identifier`:t.push(e);break;case`MemberExpression`:let n=e;for(;n.type===`MemberExpression`;)n=n.object;t.push(n);break;case`ObjectPattern`:for(let n of e.properties)n.type===`RestElement`?_t(n.argument,t):_t(n.value,t);break;case`ArrayPattern`:e.elements.forEach(e=>{e&&_t(e,t)});break;case`RestElement`:_t(e.argument,t);break;case`AssignmentPattern`:_t(e.left,t)}return t}function vt(e){return Si.includes(e.type)?vt(e.expression):e}function yt(e){switch(e){case`Teleport`:case`teleport`:return xr;case`Suspense`:case`suspense`:return Sr;case`KeepAlive`:case`keep-alive`:return Cr;case`BaseTransition`:case`base-transition`:return wr}}function bt(e,t,n=t.length){return xt({offset:e.offset,line:e.line,column:e.column},t,n)}function xt(e,t,n=t.length){let r=0,i=-1;for(let e=0;e<n;e++)t.charCodeAt(e)===10&&(r++,i=e);return e.offset+=n,e.line+=r,e.column=i===-1?e.column+n:n-i,e}function St(e,t){if(!e)throw Error(t||`unexpected compiler condition`)}function Ct(e,t,n=!1){for(let r=0;r<e.props.length;r++){let i=e.props[r];if(i.type===7&&(n||i.exp)&&(L(t)?i.name===t:t.test(i.name)))return i}}function wt(e,t,n=!1,r=!1){for(let i=0;i<e.props.length;i++){let a=e.props[i];if(a.type===6){if(n)continue;if(a.name===t&&(a.value||r))return a}else if(a.name===`bind`&&(a.exp||r)&&Tt(a.arg,t))return a}}function Tt(e,t){return!!(e&&Ci(e)&&e.content===t)}function Et(e){return e.props.some(e=>e.type===7&&e.name===`bind`&&(!e.arg||e.arg.type!==4||!e.arg.isStatic))}function Dt(e){return e.type===5||e.type===2}function Ot(e){return e.type===7&&e.name===`pre`}function kt(e){return e.type===7&&e.name===`slot`}function At(e){return e.type===1&&e.tagType===3}function jt(e){return e.type===1&&e.tagType===2}function Mt(e,t=[]){if(e&&!L(e)&&e.type===14){let n=e.callee;if(!L(n)&&Li.has(n))return Mt(e.arguments[0],t.concat(e))}return[e,t]}function Nt(e,t,n){if(e.type!==13&&Pt(e,t))return;let r,i=e.type===13?e.props:e.arguments[2],a=[],o;if(i&&!L(i)&&i.type===14){let e=Mt(i);i=e[0],a=e[1],o=a[a.length-1]}if(i==null||L(i))r=Fe([t]);else if(i.type===14){let e=i.arguments[0];!L(e)&&e.type===15?Ft(t,e)||e.properties.unshift(t):i.callee===qr?r=ze(n.helper(Hr),[Fe([t]),i]):i.arguments.unshift(Fe([t])),!r&&(r=i)}else i.type===15?(Ft(t,i)||i.properties.unshift(t),r=i):(r=ze(n.helper(Hr),[Fe([t]),i]),o&&o.callee===Kr&&(o=a[a.length-2]));e.type===13?o?o.arguments[0]=r:e.props=r:o?o.arguments[0]=r:e.arguments[2]=r}function Pt(e,t){var n,r,i;if(t.key.type!==4||t.key.content!==`key`)return!1;let a=e.arguments[2];if(a&&!L(a)){let[e]=Mt(a);if(e&&!L(e)&&e.type===15&&Ft(t,e))return!0}return(n=e.arguments)[2]||(n[2]=`{}`),(r=e.arguments)[3]||(r[3]=`undefined`),(i=e.arguments)[4]||(i[4]=`undefined`),e.arguments[5]=t.value,!0}function Ft(e,t){let n=!1;if(e.key.type===4){let r=e.key.content;n=t.properties.some(e=>e.key.type===4&&e.key.content===r)}return n}function It(e,t){return`_${t}_${e.replace(/[^\w]/g,(t,n)=>t===`-`?`_`:e.charCodeAt(n).toString())}`}function Lt(e,t){if(!e||Object.keys(t).length===0)return!1;switch(e.type){case 1:for(let n=0;n<e.props.length;n++){let r=e.props[n];if(r.type===7&&(Lt(r.arg,t)||Lt(r.exp,t)))return!0}return e.children.some(e=>Lt(e,t));case 11:return Lt(e.source,t)?!0:e.children.some(e=>Lt(e,t));case 9:return e.branches.some(e=>Lt(e,t));case 10:return Lt(e.condition,t)?!0:e.children.some(e=>Lt(e,t));case 4:return!e.isStatic&&Ti(e.content)&&!!t[e.content];case 8:return e.children.some(e=>T(e)&&Lt(e,t));case 5:case 12:return Lt(e.content,t);case 2:case 3:case 20:return!1;default:return!1}}function Rt(e){return e.type===14&&e.callee===ri?e.arguments[1].returns:e}function zt(e){for(let t=0;t<e.length;t++)if(!$e(e.charCodeAt(t)))return!1;return!0}function Bt(e){return e.type===2&&zt(e.content)||e.type===12&&Bt(e.content)}function Vt(e){return e.type===3||Bt(e)}function Ht(e){let t=e.loc,n=e.content,r=n.match(Ri);if(!r)return;let[,i,a]=r,o=(e,n,r=!1)=>{let i=t.start.offset+n;return sn(e,!1,nn(i,i+e.length),0,+!!r)},s={source:o(a.trim(),n.indexOf(a,i.length)),value:void 0,key:void 0,index:void 0,finalized:!1},c=i.trim().replace(Zi,``).trim(),l=i.indexOf(c),u=c.match(Xi);if(u){c=c.replace(Xi,``).trim();let e=u[1].trim(),t;if(e&&(t=n.indexOf(e,l+c.length),s.key=o(e,t,!0)),u[2]){let r=u[2].trim();r&&(s.index=o(r,n.indexOf(r,s.key?t+e.length:l+c.length),!0))}}return c&&(s.value=o(c,l,!0)),s}function Ut(e,t){return Vi.slice(e,t)}function Wt(e){Yi.inSFCRoot&&(Hi.innerLoc=nn(e+1,e+1)),tn(Hi);let{tag:t,ns:n}=Hi;n===0&&V.isPreTag(t)&&Ki++,V.isVoidTag(t)?Kt(Hi,e):(U.unshift(Hi),(n===1||n===2)&&(Yi.inXML=!0)),Hi=null}function Gt(e,t,n){{let t=U[0]&&U[0].tag;t!==`script`&&t!==`style`&&e.includes(`&`)&&(e=V.decodeEntities(e,!1))}let r=U[0]||Bi,i=r.children[r.children.length-1];i&&i.type===2?(i.content+=e,an(i.loc,n)):r.children.push({type:2,content:e,loc:nn(t,n)})}function Kt(e,n,r=!1){r?an(e.loc,Jt(n,60)):an(e.loc,qt(n,62)+1),Yi.inSFCRoot&&(e.children.length?e.innerLoc.end=t({},e.children[e.children.length-1].loc.end):e.innerLoc.end=t({},e.innerLoc.start),e.innerLoc.source=Ut(e.innerLoc.start.offset,e.innerLoc.end.offset));let{tag:i,ns:a,children:o}=e;if(qi||(i===`slot`?e.tagType=2:Yt(e)?e.tagType=3:Xt(e)&&(e.tagType=1)),Yi.inRCDATA||(e.children=Qt(o)),a===0&&V.isIgnoreNewlineTag(i)){let e=o[0];e&&e.type===2&&(e.content=e.content.replace(/^\r?\n/,``))}a===0&&V.isPreTag(i)&&Ki--,Ji===e&&(qi=Yi.inVPre=!1,Ji=null),Yi.inXML&&(U[0]?U[0].ns:V.ns)===0&&(Yi.inXML=!1);{let t=e.props;if(!Yi.inSFCRoot&&rt(`COMPILER_NATIVE_TEMPLATE`,V)&&e.tag===`template`&&!Yt(e)){let t=U[0]||Bi,n=t.children.indexOf(e);t.children.splice(n,1,...e.children)}let n=t.find(e=>e.type===6&&e.name===`inline-template`);n&&it(`COMPILER_INLINE_TEMPLATE`,V,n.loc)&&e.children.length&&(n.value={type:2,content:Ut(e.children[0].loc.start.offset,e.children[e.children.length-1].loc.end.offset),loc:n.loc})}}function qt(e,t){let n=e;for(;Vi.charCodeAt(n)!==t&&n<Vi.length-1;)n++;return n}function Jt(e,t){let n=e;for(;Vi.charCodeAt(n)!==t&&n>=0;)n--;return n}function Yt({tag:e,props:t}){if(e===`template`){for(let e=0;e<t.length;e++)if(t[e].type===7&&Qi.has(t[e].name))return!0}return!1}function Xt({tag:e,props:t}){if(V.isCustomElement(e))return!1;if(e===`component`||Zt(e.charCodeAt(0))||yt(e)||V.isBuiltInComponent&&V.isBuiltInComponent(e)||V.isNativeTag&&!V.isNativeTag(e))return!0;for(let e=0;e<t.length;e++){let n=t[e];if(n.type===6){if(n.name===`is`&&n.value&&(n.value.content.startsWith(`vue:`)||it(`COMPILER_IS_ON_ELEMENT`,V,n.loc)))return!0}else if(n.name===`bind`&&Tt(n.arg,`is`)&&it(`COMPILER_IS_ON_ELEMENT`,V,n.loc))return!0}return!1}function Zt(e){return e>64&&e<91}function Qt(e){let t=V.whitespace!==`preserve`,n=!1;for(let r=0;r<e.length;r++){let i=e[r];if(i.type===2){if(Ki)i.content=i.content.replace($i,`
3
3
  `);else if(zt(i.content)){let a=e[r-1]&&e[r-1].type,o=e[r+1]&&e[r+1].type;!a||!o||t&&(a===3&&(o===3||o===1)||a===1&&(o===3||o===1&&$t(i.content)))?(n=!0,e[r]=null):i.content=` `}else t&&(i.content=en(i.content))}}return n?e.filter(Boolean):e}function $t(e){for(let t=0;t<e.length;t++){let n=e.charCodeAt(t);if(n===10||n===13)return!0}return!1}function en(e){let t=``,n=!1;for(let r=0;r<e.length;r++)$e(e.charCodeAt(r))?n||=(t+=` `,!0):(t+=e[r],n=!1);return t}function tn(e){(U[0]||Bi).children.push(e)}function nn(e,t){return{start:Yi.getPos(e),end:t==null?t:Yi.getPos(t),source:t==null?t:Ut(e,t)}}function rn(e){return nn(e.start.offset,e.end.offset)}function an(e,t){e.end=Yi.getPos(t),e.source=Ut(e.start.offset,t)}function on(e){let t={type:6,name:e.rawName,nameLoc:nn(e.loc.start.offset,e.loc.start.offset+e.rawName.length),value:void 0,loc:e.loc};if(e.exp){let n=e.exp.loc;n.end.offset<e.loc.end.offset&&(n.start.offset--,n.start.column--,n.end.offset++,n.end.column++),t.value={type:2,content:e.exp.content,loc:n}}return t}function sn(e,t=!1,n,r=0,i=0){return z(e,t,n,r)}function cn(e,t,n){V.onError(B(e,nn(t,t),void 0,n))}function ln(){Yi.reset(),Hi=null,H=null,Ui=``,Wi=-1,Gi=-1,U.length=0}function un(e,n){if(ln(),Vi=e,V=t({},zi),n){let e;for(e in n)n[e]!=null&&(V[e]=n[e])}Yi.mode=V.parseMode===`html`?1:V.parseMode===`sfc`?2:0,Yi.inXML=V.ns===1||V.ns===2;let r=n&&n.delimiters;r&&(Yi.delimiterOpen=tt(r[0]),Yi.delimiterClose=tt(r[1]));let i=Bi=Me([],e);return Yi.parse(Vi),i.loc=nn(0,e.length),i.children=Qt(i.children),Bi=null,i}function dn(e,t){pn(e,void 0,t,!!fn(e))}function fn(e){let t=e.children.filter(e=>e.type!==3);return t.length===1&&t[0].type===1&&!jt(t[0])?t[0]:null}function pn(e,t,n,r=!1,i=!1){let{children:o}=e,s=[];for(let t=0;t<o.length;t++){let a=o[t];if(a.type===1&&a.tagType===0){let e=r?0:mn(a,n);if(e>0){if(e>=2){a.codegenNode.patchFlag=-1,s.push(a);continue}}else{let e=a.codegenNode;if(e.type===13){let t=e.patchFlag;if((t===void 0||t===512||t===1)&&gn(a,n)>=2){let t=_n(a);t&&(e.props=n.hoist(t))}e.dynamicProps&&=n.hoist(e.dynamicProps)}}}else if(a.type===12&&(r?0:mn(a,n))>=2){a.codegenNode.type===14&&a.codegenNode.arguments.length>0&&a.codegenNode.arguments.push(`-1`),s.push(a);continue}if(a.type===1){let t=a.tagType===1;t&&n.scopes.vSlot++,pn(a,e,n,!1,i),t&&n.scopes.vSlot--}else if(a.type===11)pn(a,e,n,a.children.length===1,!0);else if(a.type===9)for(let t=0;t<a.branches.length;t++)pn(a.branches[t],e,n,a.branches[t].children.length===1,i)}let c=!1;if(s.length===o.length&&e.type===1){if(e.tagType===0&&e.codegenNode&&e.codegenNode.type===13&&a(e.codegenNode.children))e.codegenNode.children=l(Pe(e.codegenNode.children)),c=!0;else if(e.tagType===1&&e.codegenNode&&e.codegenNode.type===13&&e.codegenNode.children&&!a(e.codegenNode.children)&&e.codegenNode.children.type===15){let t=u(e.codegenNode,`default`);t&&(t.returns=l(Pe(t.returns)),c=!0)}else if(e.tagType===3&&t&&t.type===1&&t.tagType===1&&t.codegenNode&&t.codegenNode.type===13&&t.codegenNode.children&&!a(t.codegenNode.children)&&t.codegenNode.children.type===15){let n=Ct(e,`slot`,!0),r=n&&n.arg&&u(t.codegenNode,n.arg);r&&(r.returns=l(Pe(r.returns)),c=!0)}}if(!c)for(let e of s)e.codegenNode=n.cache(e.codegenNode);function l(e){let t=n.cache(e);return t.needArraySpread=!0,t}function u(e,t){if(e.children&&!a(e.children)&&e.children.type===15){let n=e.children.properties.find(e=>e.key===t||e.key.content===t);return n&&n.value}}s.length&&n.transformHoist&&n.transformHoist(o,n,e)}function mn(e,t){let{constantCache:n}=t;switch(e.type){case 1:if(e.tagType!==0)return 0;let r=n.get(e);if(r!==void 0)return r;let i=e.codegenNode;if(i.type!==13||i.isBlock&&e.tag!==`svg`&&e.tag!==`foreignObject`&&e.tag!==`math`)return 0;if(i.patchFlag===void 0){let r=3,a=gn(e,t);if(a===0)return n.set(e,0),0;a<r&&(r=a);for(let i=0;i<e.children.length;i++){let a=mn(e.children[i],t);if(a===0)return n.set(e,0),0;a<r&&(r=a)}if(r>1)for(let i=0;i<e.props.length;i++){let a=e.props[i];if(a.type===7&&a.name===`bind`&&a.exp){let i=mn(a.exp,t);if(i===0)return n.set(e,0),0;i<r&&(r=i)}}if(i.isBlock){for(let t=0;t<e.props.length;t++)if(e.props[t].type===7)return n.set(e,0),0;t.removeHelper(Tr),t.removeHelper(Xe(t.inSSR,i.isComponent)),i.isBlock=!1,t.helper(Ye(t.inSSR,i.isComponent))}return n.set(e,r),r}return n.set(e,0),0;case 2:case 3:return 3;case 9:case 11:case 10:return 0;case 5:case 12:return mn(e.content,t);case 4:return e.constType;case 8:let a=3;for(let n=0;n<e.children.length;n++){let r=e.children[n];if(L(r)||re(r))continue;let i=mn(r,t);if(i===0)return 0;i<a&&(a=i)}return a;case 20:return 2;default:return 0}}function hn(e,t){if(e.type===14&&!L(e.callee)&&ea.has(e.callee)){let n=e.arguments[0];if(n.type===4)return mn(n,t);if(n.type===14)return hn(n,t)}return 0}function gn(e,t){let n=3,r=_n(e);if(r&&r.type===15){let{properties:e}=r;for(let r=0;r<e.length;r++){let{key:i,value:a}=e[r],o=mn(i,t);if(o===0)return o;o<n&&(n=o);let s;if(s=a.type===4?mn(a,t):a.type===14?hn(a,t):0,s===0)return s;s<n&&(n=s)}}return n}function _n(e){let t=e.codegenNode;if(t.type===13)return t.props}function vn(e,{filename:t=``,prefixIdentifiers:n=!1,hoistStatic:r=!1,hmr:a=!1,cacheHandlers:o=!1,nodeTransforms:s=[],directiveTransforms:c={},transformHoist:u=null,isBuiltInComponent:d=l,isCustomElement:f=l,expressionPlugins:p=[],scopeId:m=null,slotted:h=!0,ssr:_=!1,inSSR:v=!1,ssrCssVars:y=``,bindingMetadata:b=i,inline:x=!1,isTS:S=!1,onError:C=ot,onWarn:w=st,compatConfig:T}){let E=t.replace(/\?.*$/,``).match(/([^/\\]+)\.\w+$/),D={filename:t,selfName:E&&ge(g(E[1])),prefixIdentifiers:n,hoistStatic:r,hmr:a,cacheHandlers:o,nodeTransforms:s,directiveTransforms:c,transformHoist:u,isBuiltInComponent:d,isCustomElement:f,expressionPlugins:p,scopeId:m,slotted:h,ssr:_,inSSR:v,ssrCssVars:y,bindingMetadata:b,inline:x,isTS:S,onError:C,onWarn:w,compatConfig:T,root:e,helpers:new Map,components:new Set,directives:new Set,hoists:[],imports:[],cached:[],constantCache:new WeakMap,vForMemoKeyedNodes:new WeakSet,temps:0,identifiers:Object.create(null),scopes:{vFor:0,vSlot:0,vPre:0,vOnce:0},parent:null,grandParent:null,currentNode:e,childIndex:0,inVOnce:!1,helper(e){let t=D.helpers.get(e)||0;return D.helpers.set(e,t+1),e},removeHelper(e){let t=D.helpers.get(e);if(t){let n=t-1;n?D.helpers.set(e,n):D.helpers.delete(e)}},helperString(e){return`_${ai[D.helper(e)]}`},replaceNode(e){D.parent.children[D.childIndex]=D.currentNode=e},removeNode(e){let t=D.parent.children,n=e?t.indexOf(e):D.currentNode?D.childIndex:-1;!e||e===D.currentNode?(D.currentNode=null,D.onNodeRemoved()):D.childIndex>n&&(D.childIndex--,D.onNodeRemoved()),D.parent.children.splice(n,1)},onNodeRemoved:l,addIdentifiers(e){},removeIdentifiers(e){},hoist(e){L(e)&&(e=z(e)),D.hoists.push(e);let t=z(`_hoisted_${D.hoists.length}`,!1,e.loc,2);return t.hoisted=e,t},cache(e,t=!1,n=!1){let r=He(D.cached.length,e,t,n);return D.cached.push(r),r}};return D.filters=new Set,D}function yn(e,t){let n=vn(e,t);Sn(e,n),t.hoistStatic&&dn(e,n),t.ssr||bn(e,n),e.helpers=new Set([...n.helpers.keys()]),e.components=[...n.components],e.directives=[...n.directives],e.imports=n.imports,e.hoists=n.hoists,e.temps=n.temps,e.cached=n.cached,e.transformed=!0,e.filters=[...n.filters]}function bn(e,t){let{helper:n}=t,{children:r}=e;if(r.length===1){let n=fn(e);if(n&&n.codegenNode){let r=n.codegenNode;r.type===13&&Ze(r,t),e.codegenNode=r}else e.codegenNode=r[0]}else r.length>1&&(e.codegenNode=Ne(t,n(br),void 0,e.children,64,void 0,void 0,!0,void 0,!1))}function xn(e,t){let n=0,r=()=>{n--};for(;n<e.children.length;n++){let i=e.children[n];L(i)||(t.grandParent=t.parent,t.parent=e,t.childIndex=n,t.onNodeRemoved=r,Sn(i,t))}}function Sn(e,t){t.currentNode=e;let{nodeTransforms:n}=t,r=[];for(let i=0;i<n.length;i++){let o=n[i](e,t);if(o&&(a(o)?r.push(...o):r.push(o)),t.currentNode)e=t.currentNode;else return}switch(e.type){case 3:t.ssr||t.helper(Ar);break;case 5:t.ssr||t.helper(Vr);break;case 9:for(let n=0;n<e.branches.length;n++)Sn(e.branches[n],t);break;case 10:case 11:case 1:case 0:xn(e,t)}t.currentNode=e;let i=r.length;for(;i--;)r[i]()}function Cn(e,t){let n=L(e)?t=>t===e:t=>e.test(t);return(e,r)=>{if(e.type===1){let{props:i}=e;if(e.tagType===3&&i.some(kt))return;let a=[];for(let o=0;o<i.length;o++){let s=i[o];if(s.type===7&&n(s.name)){i.splice(o,1),o--;let n=t(e,s,r);n&&a.push(n)}}return a}}}function wn(e,{mode:t=`function`,prefixIdentifiers:n=t===`module`,sourceMap:r=!1,filename:i=`template.vue.html`,scopeId:a=null,optimizeImports:o=!1,runtimeGlobalName:s=`Vue`,runtimeModuleName:c=`vue`,ssrRuntimeModuleName:l=`vue/server-renderer`,ssr:u=!1,isTS:d=!1,inSSR:f=!1}){let p={mode:t,prefixIdentifiers:n,sourceMap:r,filename:i,scopeId:a,optimizeImports:o,runtimeGlobalName:s,runtimeModuleName:c,ssrRuntimeModuleName:l,ssr:u,isTS:d,inSSR:f,source:e.source,code:``,column:1,line:1,offset:0,indentLevel:0,pure:!1,map:void 0,helper(e){return`_${ai[e]}`},push(e,t=-2,n){p.code+=e},indent(){m(++p.indentLevel)},deindent(e=!1){e?--p.indentLevel:m(--p.indentLevel)},newline(){m(p.indentLevel)}};function m(e){p.push(`
4
4
  `+` `.repeat(e),0)}return p}function Tn(e,t={}){let n=wn(e,t);t.onContextCreated&&t.onContextCreated(n);let{mode:r,push:i,prefixIdentifiers:a,indent:o,deindent:s,newline:c,scopeId:l,ssr:u}=n,d=Array.from(e.helpers),f=d.length>0,p=!a&&r!==`module`;if(En(e,n),i(`function ${u?`ssrRender`:`render`}(${(u?[`_ctx`,`_push`,`_parent`,`_attrs`]:[`_ctx`,`_cache`]).join(`, `)}) {`),o(),p&&(i(`with (_ctx) {`),o(),f&&(i(`const { ${d.map(na).join(`, `)} } = _Vue
@@ -1,2 +1,2 @@
1
- import{A as e,F as t,I as n,M as r,O as i,P as a,Pt as o,Q as s,Tt as c,V as l,Wt as u,Z as d,a as f,at as ee,et as p,fn as m,ht as h,it as g,j as _,k as v,ln as te,mt as y,nt as b,sn as ne,vt as x,w as S}from"./router-DxY62FPf.js";import{t as C}from"./index-DVkpGX_l.js";import{n as w,t as re}from"./useCopyToast-W6vLjLdg.js";import{t as ie}from"./useToast-DgnKZwIF.js";import{d as T,h as ae,v as E}from"./format-7jzqzMS_.js";l(),x(),u();var oe={class:`service-status-page`},se={class:`flex-between`},ce={class:`flex-gap-8`},D={class:`flex-gap-8`},O={class:`gantt-wrap`},k={key:0,class:`gantt`},le={class:`gantt-row gantt-head`},ue={class:`col-cells`},de=[`title`],fe={class:`cell-head-date`},pe={class:`col-name`},me=[`title`,`onClick`],he=[`title`],ge={class:`col-cells`},A=[`title`],j={key:1,class:`gantt-empty`},M=36e5,N=24,P=`#909399`,F=C(n({__name:`ServiceStatusView`,setup(n){let{toast:l}=ie(),{copyWithToast:u}=re(),{loadError:x,run:C}=w(`延迟数据加载失败,请重试`),F=c([]),I=c(!0),L=c(!1),R=c(null),z=c(!1),B=c(!1),V,H,U=c(G()),W=c(new Map);function G(){let e=new Date,t=new Date(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours()).getTime();return Array.from({length:N},(e,n)=>t-(23-n)*M)}let K=e=>{let t=new Date(e);return Number.isNaN(t.getTime())?`-`:`${t.getFullYear()}-${E(t.getMonth()+1)}-${E(t.getDate())} ${E(t.getHours())}:00`},_e=i(()=>U.value.map(e=>{let t=new Date(e),n=E(t.getHours());return{start:e,dateLabel:`${E(t.getMonth()+1)}-${E(t.getDate())}`,hourLabel:n,fullLabel:`${K(e)} - ${n}:59`}})),ve=[103,194,58],q=[230,162,60],ye=[245,108,108],be=i(()=>{let e=[];for(let t of W.value.values())for(let n of t.values())n.avgLatencyMs!==null&&e.push(n.avgLatencyMs);if(e.length===0)return{min:0,max:0};let t=e[0],n=e[0];for(let r of e)r<t&&(t=r),r>n&&(n=r);return{min:t,max:n}}),J=e=>{let{min:t,max:n}=be.value,r=n===t?0:(e-t)/(n-t),[i,a]=r<=.5?[ve,q]:[q,ye],o=r<=.5?r*2:(r-.5)*2,s=i.map((e,t)=>Math.round(e+(a[t]-e)*o));return`rgba(${String(s[0])}, ${String(s[1])}, ${String(s[2])}, 0.9)`},Y=(e,t)=>{let n=`${K(t)} - ${E(new Date(t+M).getHours())}:00`;return e===void 0||e.total===0?`${n}\n无探测数据`:`${n}\n平均延迟 ${T(e.avgLatencyMs)}\n成功 ${String(e.success)} / 失败 ${String(e.failed)}`},X=i(()=>Se.value.map(e=>{let t=W.value.get(e.model),n=U.value.map(e=>{let n=t?.get(e);return n!==void 0&&n.failed>0?{start:e,className:`cell--down`,style:{backgroundColor:P},title:Y(n,e)}:n===void 0||n.avgLatencyMs===null?{start:e,className:`cell--empty`,style:{},title:Y(n,e)}:{start:e,className:``,style:{backgroundColor:J(n.avgLatencyMs)},title:Y(n,e)}});return{model:e.model,avg24h:e.avg24h,statusTitle:[e.avg24h===null?`最近 24 小时无成功探测记录`:`最近 24 小时成功探测平均延迟 ${T(e.avg24h)}`,e.lastLatencyMs==null?`最近一次探测:无成功延迟记录`:`最近一次探测延迟 ${T(e.lastLatencyMs)}`].join(`
2
- `),cells:n}})),xe=(e,t)=>e===null&&t===null?0:e===null?1:t===null?-1:e-t,Se=i(()=>[...F.value].sort((e,t)=>{let n=e.lastOk===!1;if(n!==(t.lastOk===!1))return n?1:-1;let r=xe(e.avg24h,t.avg24h);return r===0?e.model.localeCompare(t.model):r})),Z=async e=>{if(e.length===0){W.value=new Map;return}let t=await Promise.all(e.map(async e=>{try{let t=await f.get(`/api/latency/trend?model=${encodeURIComponent(e)}&granularity=hour`);return[e,new Map((t.buckets??[]).map(e=>[e.bucketStart,e]))]}catch{return[e,new Map]}}));W.value=new Map(t)},Q=async()=>{let e=await f.get(`/api/latency/history`);return F.value=e.models??[],L.value=e.running,R.value=e.lastRunAt,e},$=()=>C(async()=>{try{await Q(),U.value=G(),await Z(F.value.map(e=>e.model))}finally{I.value=!1}}),Ce=()=>$(),we=()=>{B.value?V=window.setInterval(()=>void $(),5e3):V!==void 0&&(window.clearInterval(V),V=void 0)},Te=async()=>{z.value=!0;try{await f.post(`/api/latency/run`)}catch(e){l(e.message,`error`),z.value=!1;return}H=window.setInterval(async()=>{try{(await Q()).running||(window.clearInterval(H),H=void 0,z.value=!1,U.value=G(),await Z(F.value.map(e=>e.model)))}catch{}},2e3)};return d(()=>{$()}),s(()=>{V!==void 0&&window.clearInterval(V),H!==void 0&&window.clearInterval(H)}),(n,i)=>{let s=g(`el-button`),c=g(`el-alert`),l=g(`el-tag`),d=g(`el-checkbox`),f=g(`el-empty`),C=g(`el-card`),w=ee(`loading`);return p(),r(`div`,oe,[o(x)?(p(),e(c,{key:0,title:o(x),type:`error`,"show-icon":``,closable:!1,class:`mb-16`},{default:y(()=>[t(s,{size:`small`,onClick:Ce},{default:y(()=>[...i[1]||=[a(`重试`,-1)]]),_:1})]),_:1},8,[`title`])):_(``,!0),t(C,{shadow:`never`,class:`main-card`},{header:y(()=>[v(`div`,se,[v(`div`,ce,[i[3]||=v(`span`,{class:`fw-600`},`服务状态`,-1),L.value?(p(),e(l,{key:0,type:`warning`,size:`small`},{default:y(()=>[...i[2]||=[a(`测试进行中`,-1)]]),_:1})):R.value?(p(),e(l,{key:1,type:`info`,size:`small`},{default:y(()=>[a(` 上次测试 `+m(o(ae)(R.value)),1)]),_:1})):_(``,!0)]),v(`div`,D,[t(d,{modelValue:B.value,"onUpdate:modelValue":i[0]||=e=>B.value=e,onChange:we},{default:y(()=>[...i[4]||=[a(` 自动刷新(5s) `,-1)]]),_:1},8,[`modelValue`]),t(s,{loading:z.value,onClick:Te},{default:y(()=>[...i[5]||=[a(` 延迟测试 `,-1)]]),_:1},8,[`loading`])])])]),default:y(()=>[i[9]||=v(`div`,{class:`legend`},[v(`span`,{class:`legend-text`},`延迟`),v(`span`,{class:`legend-text`},`低`),v(`span`,{class:`legend-gradient`}),v(`span`,{class:`legend-text`},`高`),v(`span`,{class:`legend-swatch legend-swatch--down`}),v(`span`,{class:`legend-text`},`该小时有失败探测`),v(`span`,{class:`legend-swatch legend-swatch--empty`}),v(`span`,{class:`legend-text`},`无探测数据`)],-1),h((p(),r(`div`,O,[i[8]||=v(`div`,{class:`muted-sm hint`},` 右侧 24 格为最近 24 小时(每格 1 小时,本地整点对齐,最右格为当前小时)。 格子底色为当小时成功探测的平均延迟,全表统一色标(本期最快→最慢 绿→红); 当小时存在失败探测即视为不可用,显示灰色。 行按 24h 平均延迟升序,最近一次探测失败的模型沉底。 `,-1),X.value.length>0?(p(),r(`div`,k,[v(`div`,le,[i[6]||=v(`div`,{class:`col-name`},`模型名称`,-1),i[7]||=v(`div`,{class:`col-status`},`状态`,-1),v(`div`,ue,[(p(!0),r(S,null,b(_e.value,e=>(p(),r(`div`,{key:e.start,class:`cell cell--head`,title:e.fullLabel},[v(`span`,fe,m(e.dateLabel),1),v(`span`,null,m(e.hourLabel),1)],8,de))),128))])]),(p(!0),r(S,null,b(X.value,e=>(p(),r(`div`,{key:e.model,class:`gantt-row`},[v(`div`,pe,[v(`span`,{class:`copy-text model-name`,title:e.model,onClick:t=>o(u)(e.model)},m(e.model),9,me)]),v(`div`,{class:`col-status`,title:e.statusTitle},m(o(T)(e.avg24h)),9,he),v(`div`,ge,[(p(!0),r(S,null,b(e.cells,e=>(p(),r(`div`,{key:e.start,class:ne([`cell`,e.className]),style:te(e.style),title:e.title},null,14,A))),128))])]))),128))])):(p(),r(`div`,j,[t(f,{description:`暂无延迟数据,点击「延迟测试」开始`,"image-size":80})]))])),[[w,I.value]])]),_:1})])}}}),[[`__scopeId`,`data-v-95ae284d`]]);export{F as default};
1
+ import{A as e,F as t,I as n,M as r,O as i,P as a,Pt as o,Q as s,Tt as c,V as l,Wt as u,Z as d,a as f,at as ee,et as p,fn as m,ht as h,it as g,j as _,k as v,ln as te,mt as y,nt as b,sn as ne,vt as x,w as S}from"./router-BgTNV93P.js";import{t as C}from"./index-W7WdLt_5.js";import{n as w,t as re}from"./useCopyToast-B_Qvf_Pf.js";import{t as ie}from"./useToast-X_JkPDpr.js";import{_ as T,m as ae,u as E}from"./format-CPPf8IfM.js";l(),x(),u();var oe={class:`service-status-page`},se={class:`flex-between`},ce={class:`flex-gap-8`},D={class:`flex-gap-8`},O={class:`gantt-wrap`},k={key:0,class:`gantt`},le={class:`gantt-row gantt-head`},ue={class:`col-cells`},de=[`title`],fe={class:`cell-head-date`},pe={class:`col-name`},me=[`title`,`onClick`],he=[`title`],ge={class:`col-cells`},A=[`title`],j={key:1,class:`gantt-empty`},M=36e5,N=24,P=`#909399`,F=C(n({__name:`ServiceStatusView`,setup(n){let{toast:l}=ie(),{copyWithToast:u}=re(),{loadError:x,run:C}=w(`延迟数据加载失败,请重试`),F=c([]),I=c(!0),L=c(!1),R=c(null),z=c(!1),B=c(!1),V,H,U=c(G()),W=c(new Map);function G(){let e=new Date,t=new Date(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours()).getTime();return Array.from({length:N},(e,n)=>t-(23-n)*M)}let K=e=>{let t=new Date(e);return Number.isNaN(t.getTime())?`-`:`${t.getFullYear()}-${T(t.getMonth()+1)}-${T(t.getDate())} ${T(t.getHours())}:00`},_e=i(()=>U.value.map(e=>{let t=new Date(e),n=T(t.getHours());return{start:e,dateLabel:`${T(t.getMonth()+1)}-${T(t.getDate())}`,hourLabel:n,fullLabel:`${K(e)} - ${n}:59`}})),ve=[103,194,58],q=[230,162,60],ye=[245,108,108],be=i(()=>{let e=[];for(let t of W.value.values())for(let n of t.values())n.avgLatencyMs!==null&&e.push(n.avgLatencyMs);if(e.length===0)return{min:0,max:0};let t=e[0],n=e[0];for(let r of e)r<t&&(t=r),r>n&&(n=r);return{min:t,max:n}}),J=e=>{let{min:t,max:n}=be.value,r=n===t?0:(e-t)/(n-t),[i,a]=r<=.5?[ve,q]:[q,ye],o=r<=.5?r*2:(r-.5)*2,s=i.map((e,t)=>Math.round(e+(a[t]-e)*o));return`rgba(${String(s[0])}, ${String(s[1])}, ${String(s[2])}, 0.9)`},Y=(e,t)=>{let n=`${K(t)} - ${T(new Date(t+M).getHours())}:00`;return e===void 0||e.total===0?`${n}\n无探测数据`:`${n}\n平均延迟 ${E(e.avgLatencyMs)}\n成功 ${String(e.success)} / 失败 ${String(e.failed)}`},X=i(()=>Se.value.map(e=>{let t=W.value.get(e.model),n=U.value.map(e=>{let n=t?.get(e);return n!==void 0&&n.failed>0?{start:e,className:`cell--down`,style:{backgroundColor:P},title:Y(n,e)}:n===void 0||n.avgLatencyMs===null?{start:e,className:`cell--empty`,style:{},title:Y(n,e)}:{start:e,className:``,style:{backgroundColor:J(n.avgLatencyMs)},title:Y(n,e)}});return{model:e.model,avg24h:e.avg24h,statusTitle:[e.avg24h===null?`最近 24 小时无成功探测记录`:`最近 24 小时成功探测平均延迟 ${E(e.avg24h)}`,e.lastLatencyMs==null?`最近一次探测:无成功延迟记录`:`最近一次探测延迟 ${E(e.lastLatencyMs)}`].join(`
2
+ `),cells:n}})),xe=(e,t)=>e===null&&t===null?0:e===null?1:t===null?-1:e-t,Se=i(()=>[...F.value].sort((e,t)=>{let n=e.lastOk===!1;if(n!==(t.lastOk===!1))return n?1:-1;let r=xe(e.avg24h,t.avg24h);return r===0?e.model.localeCompare(t.model):r})),Z=async e=>{if(e.length===0){W.value=new Map;return}let t=await Promise.all(e.map(async e=>{try{let t=await f.get(`/api/latency/trend?model=${encodeURIComponent(e)}&granularity=hour`);return[e,new Map((t.buckets??[]).map(e=>[e.bucketStart,e]))]}catch{return[e,new Map]}}));W.value=new Map(t)},Q=async()=>{let e=await f.get(`/api/latency/history`);return F.value=e.models??[],L.value=e.running,R.value=e.lastRunAt,e},$=()=>C(async()=>{try{await Q(),U.value=G(),await Z(F.value.map(e=>e.model))}finally{I.value=!1}}),Ce=()=>$(),we=()=>{B.value?V=window.setInterval(()=>void $(),5e3):V!==void 0&&(window.clearInterval(V),V=void 0)},Te=async()=>{z.value=!0;try{await f.post(`/api/latency/run`)}catch(e){l(e.message,`error`),z.value=!1;return}H=window.setInterval(async()=>{try{(await Q()).running||(window.clearInterval(H),H=void 0,z.value=!1,U.value=G(),await Z(F.value.map(e=>e.model)))}catch{}},2e3)};return d(()=>{$()}),s(()=>{V!==void 0&&window.clearInterval(V),H!==void 0&&window.clearInterval(H)}),(n,i)=>{let s=g(`el-button`),c=g(`el-alert`),l=g(`el-tag`),d=g(`el-checkbox`),f=g(`el-empty`),C=g(`el-card`),w=ee(`loading`);return p(),r(`div`,oe,[o(x)?(p(),e(c,{key:0,title:o(x),type:`error`,"show-icon":``,closable:!1,class:`mb-16`},{default:y(()=>[t(s,{size:`small`,onClick:Ce},{default:y(()=>[...i[1]||=[a(`重试`,-1)]]),_:1})]),_:1},8,[`title`])):_(``,!0),t(C,{shadow:`never`,class:`main-card`},{header:y(()=>[v(`div`,se,[v(`div`,ce,[i[3]||=v(`span`,{class:`fw-600`},`服务状态`,-1),L.value?(p(),e(l,{key:0,type:`warning`,size:`small`},{default:y(()=>[...i[2]||=[a(`测试进行中`,-1)]]),_:1})):R.value?(p(),e(l,{key:1,type:`info`,size:`small`},{default:y(()=>[a(` 上次测试 `+m(o(ae)(R.value)),1)]),_:1})):_(``,!0)]),v(`div`,D,[t(d,{modelValue:B.value,"onUpdate:modelValue":i[0]||=e=>B.value=e,onChange:we},{default:y(()=>[...i[4]||=[a(` 自动刷新(5s) `,-1)]]),_:1},8,[`modelValue`]),t(s,{loading:z.value,onClick:Te},{default:y(()=>[...i[5]||=[a(` 延迟测试 `,-1)]]),_:1},8,[`loading`])])])]),default:y(()=>[i[9]||=v(`div`,{class:`legend`},[v(`span`,{class:`legend-text`},`延迟`),v(`span`,{class:`legend-text`},`低`),v(`span`,{class:`legend-gradient`}),v(`span`,{class:`legend-text`},`高`),v(`span`,{class:`legend-swatch legend-swatch--down`}),v(`span`,{class:`legend-text`},`该小时有失败探测`),v(`span`,{class:`legend-swatch legend-swatch--empty`}),v(`span`,{class:`legend-text`},`无探测数据`)],-1),h((p(),r(`div`,O,[i[8]||=v(`div`,{class:`muted-sm hint`},` 右侧 24 格为最近 24 小时(每格 1 小时,本地整点对齐,最右格为当前小时)。 格子底色为当小时成功探测的平均延迟,全表统一色标(本期最快→最慢 绿→红); 当小时存在失败探测即视为不可用,显示灰色。 行按 24h 平均延迟升序,最近一次探测失败的模型沉底。 `,-1),X.value.length>0?(p(),r(`div`,k,[v(`div`,le,[i[6]||=v(`div`,{class:`col-name`},`模型名称`,-1),i[7]||=v(`div`,{class:`col-status`},`状态`,-1),v(`div`,ue,[(p(!0),r(S,null,b(_e.value,e=>(p(),r(`div`,{key:e.start,class:`cell cell--head`,title:e.fullLabel},[v(`span`,fe,m(e.dateLabel),1),v(`span`,null,m(e.hourLabel),1)],8,de))),128))])]),(p(!0),r(S,null,b(X.value,e=>(p(),r(`div`,{key:e.model,class:`gantt-row`},[v(`div`,pe,[v(`span`,{class:`copy-text model-name`,title:e.model,onClick:t=>o(u)(e.model)},m(e.model),9,me)]),v(`div`,{class:`col-status`,title:e.statusTitle},m(o(E)(e.avg24h)),9,he),v(`div`,ge,[(p(!0),r(S,null,b(e.cells,e=>(p(),r(`div`,{key:e.start,class:ne([`cell`,e.className]),style:te(e.style),title:e.title},null,14,A))),128))])]))),128))])):(p(),r(`div`,j,[t(f,{description:`暂无延迟数据,点击「延迟测试」开始`,"image-size":80})]))])),[[w,I.value]])]),_:1})])}}}),[[`__scopeId`,`data-v-95ae284d`]]);export{F as default};
@@ -1 +1 @@
1
- import{A as e,F as t,I as n,M as r,O as i,P as a,Pt as o,Q as s,Tt as c,V as l,Wt as u,Z as d,a as f,at as p,et as m,fn as h,ht as g,i as _,it as v,j as y,k as b,mt as x,n as S,nt as C,vt as w,w as T}from"./router-DxY62FPf.js";import{n as E,t as D}from"./index-DVkpGX_l.js";import{n as O,t as k}from"./useManagerApi-7t9qNB2C.js";import{t as A}from"./config-B3YP6GMt.js";import{n as j,t as M}from"./useCopyToast-W6vLjLdg.js";import{t as N}from"./useToast-DgnKZwIF.js";import{t as P}from"./updateNote-CttDt8SZ.js";l(),u(),w();var F={class:`flex-between`},I={class:`muted-sm mb-8`},L={class:`switch-row`},R={class:`switch-info`},z={class:`switch-title`},B={class:`switch-row`},V={class:`switch-info`},H={class:`switch-title`},U={class:`switch-row`},W={class:`switch-info`},G={class:`switch-title`},K=D(n({__name:`HarnessSwitches`,setup(n){let{toast:i}=N(),o=c(!0),s=c(!1),l=c(null),u=c(null),f=c(null),_=c(null),S=c(`success`),C=async e=>{e||(l.value?s.value=!0:o.value=!0);try{l.value=await k.harness(),u.value=null}catch(t){e||(u.value=t.message)}finally{e||(o.value=!1,s.value=!1)}};d(()=>C(!1));let w={claudeCode:{label:`Claude Code`,file:`~/.claude/settings.json`,toggle:k.setClaudeCode},codex:{label:`Codex CLI`,file:`~/.codex/config.toml`,toggle:k.setCodex},dsh:{label:`DeepSeek Harness`,file:`~/.dsh/settings.yaml`,toggle:k.setDsh}},D=async(e,t)=>{if(!l.value||f.value)return;let n=w[e],r=t?`确定开启 ${n.label} 代理?将改写 ${n.file}(开启前自动备份,关闭时从备份还原)。`:`确定关闭 ${n.label} 代理?将从备份还原 ${n.file}(无备份时移除代理相关配置)。`;try{await E.confirm(r,t?`开启确认`:`关闭确认`,{confirmButtonText:t?`开启`:`关闭`,cancelButtonText:`取消`,type:`warning`})}catch{return}f.value=e;try{let e=await n.toggle(t);_.value=e.note??null,S.value=t?`success`:`info`,i(t?`已开启代理`:`已关闭代理`,`success`)}catch(e){i(e.message||`操作失败`,`error`)}finally{f.value=null,await C(!0)}};return(n,i)=>{let c=v(`el-button`),d=v(`el-alert`),w=v(`el-tag`),E=v(`el-switch`),O=v(`el-divider`),k=v(`el-empty`),A=v(`el-card`),j=p(`loading`);return g((m(),e(A,{shadow:`never`},{header:x(()=>[b(`div`,F,[i[7]||=b(`span`,{class:`fw-600`},`代理开关`,-1),t(c,{loading:s.value,onClick:i[0]||=e=>C(!1)},{default:x(()=>[...i[6]||=[a(`刷新`,-1)]]),_:1},8,[`loading`])])]),default:x(()=>[l.value?(m(),r(T,{key:0},[b(`div`,I,` 将本机 CLI 工具的流量一键指向本机网关(`+h(l.value.gatewayBase)+`)。 开启前自动备份原配置为 *.ellm-bak(保留最早的原始备份),关闭时从备份还原。 `,1),_.value?(m(),e(d,{key:0,title:_.value,type:S.value,"show-icon":``,class:`mb-8`,onClose:i[1]||=e=>_.value=null},null,8,[`title`,`type`])):y(``,!0),b(`div`,L,[b(`div`,R,[b(`div`,z,[i[8]||=a(` Claude Code `,-1),t(w,{type:l.value.claudeCode?`success`:`info`,size:`small`,"disable-transitions":``},{default:x(()=>[a(h(l.value.claudeCode?`已开启`:`未开启`),1)]),_:1},8,[`type`])]),i[9]||=b(`div`,{class:`switch-desc`},[a(` 写入 `),b(`code`,null,`~/.claude/settings.json`),a(` 的 env.ANTHROPIC_BASE_URL / ANTHROPIC_AUTH_TOKEN, 鉴权取网关配置的 masterKey(未设置将开启失败);其余字段原样保留,重启 Claude Code 会话后生效。 `)],-1)]),t(E,{"model-value":l.value.claudeCode,loading:f.value===`claudeCode`,onChange:i[2]||=e=>D(`claudeCode`,!!e)},null,8,[`model-value`,`loading`])]),t(O,{class:`switch-divider`}),b(`div`,B,[b(`div`,V,[b(`div`,H,[i[10]||=a(` Codex CLI `,-1),t(w,{type:l.value.codex?`success`:`info`,size:`small`,"disable-transitions":``},{default:x(()=>[a(h(l.value.codex?`已开启`:`未开启`),1)]),_:1},8,[`type`])]),i[11]||=b(`div`,{class:`switch-desc`},[a(` 写入 `),b(`code`,null,`~/.codex/config.toml`),a(` 的 model_provider 与 [model_providers.ellm-proxy] 段 (保留用户注释与排版);开启后需按提示设置环境变量 ELLM_PROXY_API_KEY 供 Codex 鉴权。 `)],-1)]),t(E,{"model-value":l.value.codex,loading:f.value===`codex`,onChange:i[3]||=e=>D(`codex`,!!e)},null,8,[`model-value`,`loading`])]),t(O,{class:`switch-divider`}),b(`div`,U,[b(`div`,W,[b(`div`,G,[i[12]||=a(` DeepSeek Harness `,-1),t(w,{type:l.value.dsh?`success`:`info`,size:`small`,"disable-transitions":``},{default:x(()=>[a(h(l.value.dsh?`已开启`:`未开启`),1)]),_:1},8,[`type`])]),i[13]||=b(`div`,{class:`switch-desc`},[a(` 写入 `),b(`code`,null,`~/.dsh/settings.yaml`),a(` 的 llm-deepseek.baseURL 与 `),b(`code`,null,`~/.dsh/.credentials.yaml`),a(` 的 DEEPSEEK_API_KEY(取网关 masterKey,未设置则写占位值);模型请在 dsh 内选择与网关部署名一致的模型。 dsh 为 developer preview,配置格式可能随版本变化。 `)],-1)]),t(E,{"model-value":l.value.dsh,loading:f.value===`dsh`,onChange:i[4]||=e=>D(`dsh`,!!e)},null,8,[`model-value`,`loading`])])],64)):(m(),e(k,{key:1,description:u.value||`暂无开关状态`},{default:x(()=>[t(c,{type:`primary`,onClick:i[5]||=e=>C(!1)},{default:x(()=>[...i[14]||=[a(`重试`,-1)]]),_:1})]),_:1},8,[`description`]))]),_:1})),[[j,o.value]])}}}),[[`__scopeId`,`data-v-fb084a91`]]);l(),u(),w();var q={class:`service-settings`},J={class:`flex-between`},Y={key:0,class:`switch-row`},ee={class:`switch-info`},te={class:`switch-title`},X={key:0,class:`switch-row`},Z={class:`switch-info`},ne={class:`switch-title`},re={class:`switch-desc`},ie={key:0,class:`version-block`},ae={class:`version-row`},oe={class:`muted-sm`},se={key:0,class:`muted-sm`},ce={key:1,class:`muted-sm`},le={class:`muted-sm`},ue={class:`version-actions`},Q=D(n({__name:`ServiceUpdateSettings`,setup(n){let{toast:o}=N(),l=c(!0),u=c(!1),f=c(null),S=c(null),C=c(null),w=c(null),D=c(null),A=c(!1),j=c(!1),M=c(null),F=null;s(()=>F?.abort());let I=async e=>{if(!e){if(u.value)return;u.value=!0}try{let[e,t]=await Promise.allSettled([k.autostart(),k.update()]);f.value=e.status===`fulfilled`?e.value:null,S.value=e.status===`rejected`?e.reason?.message:null,C.value=t.status===`fulfilled`?t.value:null,w.value=t.status===`rejected`?t.reason?.message:null}finally{l.value=!1,u.value=!1}};d(()=>I(!1));let L=e=>e?new Date(e).toLocaleString():``,R=i(()=>C.value?.lastCheck?.currentVersion??null),z=i(()=>_.value?.buildSource===`local`),B=i(()=>C.value?.lastCheck?.latestVersion??null),V=i(()=>C.value?.lastCheck?.hasUpdate===!0),H=i(()=>{let e=C.value?.lastCheck?.checkedAt;return e?new Date(e).toLocaleString():null}),U=i(()=>{let e=C.value?.lastApply;if(!e)return null;let t=L(e.appliedAt);return`${e.fromVersion} → ${e.toVersion}${t?`(${t})`:``}`}),W=async e=>{if(!f.value||D.value)return;let t=e?`确定开启开机自启?将注册登录触发的自启项(登录时自动恢复服务)。`:`确定关闭开机自启?将移除自启项,且此后首次启动不再自动注册。`;try{await E.confirm(t,e?`开启确认`:`关闭确认`,{confirmButtonText:e?`开启`:`关闭`,cancelButtonText:`取消`,type:`warning`})}catch{return}D.value=`autostart`;try{let t=await k.setAutostart(e);t.note?o(t.note,`success`):o(e?`开机自启已开启`:`开机自启已关闭`,`success`)}catch(e){o(e.message||`操作失败`,`error`)}finally{D.value=null,await I(!0)}},G=async e=>{if(!C.value||D.value)return;let t=e?`确定开启自动更新?将每小时检查 npm 源,发现新版本后自动安装并重启服务(过程中管理台短暂不可访问)。`:`确定关闭自动更新?不再自动检查与安装(手动检查与更新不受影响)。`;try{await E.confirm(t,e?`开启确认`:`关闭确认`,{confirmButtonText:e?`开启`:`关闭`,cancelButtonText:`取消`,type:`warning`})}catch{return}D.value=`updateEnabled`;try{let t=await k.setUpdateEnabled(e);t.note&&o(t.note,`success`)}catch(e){o(e.message||`操作失败`,`error`)}finally{D.value=null,await I(!0)}},K=async()=>{A.value=!0;try{let e=await k.checkUpdate();M.value=e.hasUpdate?`发现新版本 ${e.latestVersion}(当前 ${e.currentVersion}):可点击「立即更新」安装`:`已是最新版本 ${e.currentVersion}(检查于 ${L(e.checkedAt)})`,await I(!0)}catch(e){o(e.message||`检查更新失败`,`error`)}finally{A.value=!1}},Q=async()=>{try{await E.confirm(`确定更新到 ${B.value}?服务会自动重启并在启动时安装新版本:重启期间管理台短暂不可访问(预计 1~3 分钟),完成后自动恢复。`,`立即更新`,{confirmButtonText:`立即更新`,cancelButtonText:`取消`,type:`warning`})}catch{return}j.value=!0;let e=new AbortController;F=e;try{let t=await k.update(),n=await k.applyUpdate();if(!n.updated){M.value=`已是最新版本 ${n.fromVersion}`;return}M.value=`正在重启服务并安装 ${n.toVersion}(预计 1~3 分钟):重启期间管理台短暂不可访问,完成后这里会自动显示结果。`;let r=await O({targetVersion:n.toVersion,sinceAppliedAt:t.lastApply?.appliedAt??null,signal:e.signal});if(e.signal.aborted)return;r&&!r.error?(o(`已更新到 ${r.toVersion}`,`success`),M.value=`已更新 ${r.fromVersion} → ${r.toVersion},服务已在新版本上运行。`):r?.error?(o(`更新失败:${r.error}`,`error`),M.value=P(r.error)):M.value=`更新仍在进行(安装耗时较长):稍后刷新页面查看最新状态。`}catch(e){o(e.message||`更新失败`,`error`)}finally{j.value=!1,F===e&&(F=null),e.signal.aborted||await I(!0)}};return(n,i)=>{let o=v(`el-button`),s=v(`el-tag`),c=v(`el-switch`),d=v(`el-empty`),_=v(`el-card`),E=v(`el-link`),O=v(`el-alert`),k=p(`loading`);return g((m(),r(`div`,q,[t(_,{shadow:`never`,class:`mb-16`},{header:x(()=>[b(`div`,J,[i[7]||=b(`span`,{class:`fw-600`},`开机自启`,-1),t(o,{loading:u.value,onClick:i[0]||=e=>I(!1)},{default:x(()=>[...i[6]||=[a(`刷新`,-1)]]),_:1},8,[`loading`])])]),default:x(()=>[f.value?(m(),r(`div`,Y,[b(`div`,ee,[b(`div`,te,[i[8]||=a(` 登录时自动启动服务 `,-1),t(s,{type:f.value.enabled?`success`:`info`,size:`small`,"disable-transitions":``},{default:x(()=>[a(h(f.value.enabled?`已开启`:`未开启`),1)]),_:1},8,[`type`])]),i[9]||=b(`div`,{class:`switch-desc`},[a(` 登录操作系统时自动启动服务(无需管理员权限)。 关闭后首次启动 `),b(`code`,null,`ezllm`),a(` 也不会再自动注册,重新开启即可解除。 `)],-1)]),t(c,{"model-value":f.value.enabled,loading:D.value===`autostart`,onChange:i[1]||=e=>W(!!e)},null,8,[`model-value`,`loading`])])):(m(),e(d,{key:1,description:S.value||`暂无自启状态`},{default:x(()=>[t(o,{type:`primary`,onClick:i[2]||=e=>I(!1)},{default:x(()=>[...i[10]||=[a(`重试`,-1)]]),_:1})]),_:1},8,[`description`]))]),_:1}),t(_,{shadow:`never`,class:`mb-16`},{header:x(()=>[...i[11]||=[b(`div`,{class:`flex-between`},[b(`span`,{class:`fw-600`},`自动更新`)],-1)]]),default:x(()=>[C.value?(m(),r(`div`,X,[b(`div`,Z,[b(`div`,ne,[i[12]||=a(` 自动检查并安装新版本 `,-1),t(s,{type:C.value.enabled?`success`:`info`,size:`small`,"disable-transitions":``},{default:x(()=>[a(h(C.value.enabled?`已开启`:`未开启`),1)]),_:1},8,[`type`])]),b(`div`,re,[C.value.supported?(m(),r(T,{key:1},[a(` 每小时检查 npm 源,发现新版本后自动安装并重启服务(过程中管理台短暂不可访问); 关闭后仍可在下方手动检查与更新。 `)],64)):(m(),r(T,{key:0},[a(` 当前为源码运行模式,更新功能不可用(仅通过 npx ezllm install 装配的实例支持)。 `)],64))])]),C.value.supported?(m(),e(c,{key:0,"model-value":C.value.enabled,loading:D.value===`updateEnabled`,onChange:i[3]||=e=>G(!!e)},null,8,[`model-value`,`loading`])):y(``,!0)])):(m(),e(d,{key:1,description:w.value||`暂无更新状态`},{default:x(()=>[t(o,{type:`primary`,onClick:i[4]||=e=>I(!1)},{default:x(()=>[...i[13]||=[a(`重试`,-1)]]),_:1})]),_:1},8,[`description`]))]),_:1}),t(_,{shadow:`never`},{header:x(()=>[...i[14]||=[b(`div`,{class:`flex-between`},[b(`span`,{class:`fw-600`},`版本信息`)],-1)]]),default:x(()=>[C.value?(m(),r(`div`,ie,[b(`div`,ae,[i[18]||=b(`span`,{class:`version-label`},`当前版本`,-1),t(s,{size:`small`},{default:x(()=>[a(h(R.value||`未知`),1)]),_:1}),z.value?(m(),e(s,{key:0,type:`warning`,size:`small`,"disable-transitions":``},{default:x(()=>[...i[15]||=[a(`本地构建`,-1)]]),_:1})):y(``,!0),B.value?(m(),r(T,{key:1},[i[17]||=b(`span`,{class:`version-label`},`最新版本`,-1),t(s,{type:V.value?`warning`:`success`,size:`small`,"disable-transitions":``},{default:x(()=>[a(h(B.value),1)]),_:1},8,[`type`]),V.value?(m(),e(s,{key:0,type:`warning`,size:`small`,"disable-transitions":``},{default:x(()=>[...i[16]||=[a(`发现新版本`,-1)]]),_:1})):y(``,!0)],64)):y(``,!0)]),b(`div`,oe,[a(` 上次检查:`+h(H.value||`尚未检查`)+` `,1),C.value.updating?(m(),r(T,{key:0},[a(` · 更新执行中...`)],64)):y(``,!0)]),C.value.supported?y(``,!0):(m(),r(`div`,se,`源码运行模式:手动检查与更新不可用。`)),U.value?(m(),r(`div`,ce,`上次更新:`+h(U.value),1)):y(``,!0),b(`div`,le,[i[20]||=a(` npm 包主页:`,-1),t(E,{type:`primary`,href:`https://www.npmjs.com/package/ezllm`,target:`_blank`},{default:x(()=>[...i[19]||=[a(`npmjs.com/package/ezllm`,-1)]]),_:1})]),b(`div`,ue,[t(o,{loading:A.value,disabled:!C.value.supported||C.value.updating,onClick:K},{default:x(()=>[a(h(A.value?`检查中...`:`检查更新`),1)]),_:1},8,[`loading`,`disabled`]),V.value&&C.value.supported?(m(),e(o,{key:0,type:`primary`,loading:j.value,disabled:C.value.updating,onClick:Q},{default:x(()=>[a(h(j.value?`更新中...`:`立即更新到 ${B.value}`),1)]),_:1},8,[`loading`,`disabled`])):y(``,!0)]),M.value?(m(),e(O,{key:2,title:M.value,type:`info`,"show-icon":``,class:`mt-8`,onClose:i[5]||=e=>M.value=null},null,8,[`title`])):y(``,!0)])):(m(),e(d,{key:1,description:`更新状态不可用`}))]),_:1})])),[[k,l.value]])}}}),[[`__scopeId`,`data-v-567dce2c`]]);l(),w(),u();var de={class:`flex-col-gap`},$={class:`flex-between`},fe={class:`muted-sm`},pe={class:`login-row`},me={class:`muted-sm`},he={class:`flex-between`},ge={class:`monitor-row`},_e={class:`save-bar`},ve=D(n({__name:`SettingsView`,setup(n){let{toast:s}=N(),{copyWithToast:l}=M(),u=A(),_=c(`basic`),w=c(!0),E=c(!1),D=c(``),O=async()=>{D.value&&await l(D.value)},k=c(29770),P=c(null),F=c(!0),I=c(``),L=c(``),R=i(()=>D.value.trim()!==``||I.value!==``&&L.value!==``),z=c(!1),B=c(60),V=[{label:`10分钟`,value:10},{label:`30分钟`,value:30},{label:`1小时`,value:60},{label:`2小时`,value:120},{label:`5小时`,value:300},{label:`8小时`,value:480},{label:`12小时`,value:720},{label:`24小时`,value:1440}],{loadError:H,run:U}=j(`设置加载失败,请重试`),W=()=>U(async()=>{try{await u.load(),D.value=u.config.masterKey||``,k.value=u.config.port??29770;let e=u.config[`web-ui`]?.[`login-account`];I.value=e?.username||``,L.value=e?.password||``,F.value=u.config.allowLan!==!1;let t=u.config.latencyTest;z.value=t?.enabled===!0,B.value=t?.intervalMinutes??60;try{let e=await f.get(`/api/status`);P.value=e.listenPort}catch{P.value=null}}finally{w.value=!1}}),G=async()=>{if(I.value.trim()!==``||L.value!==``){if(I.value.trim()===``||L.value===``){s(`用户名和密码需同时填写`,`error`);return}if(L.value.length<6){s(`密码至少 6 位`,`error`);return}}E.value=!0;let e=z.value&&u.config.latencyTest?.enabled!==!0;try{let t=await u.update(e=>{e.masterKey=D.value.trim(),e.port=k.value,e.allowLan=F.value,e.latencyTest={enabled:z.value,intervalMinutes:B.value},e[`web-ui`]??={},e[`web-ui`][`login-account`]??={},e[`web-ui`][`login-account`].username=I.value.trim(),e[`web-ui`][`login-account`].password=L.value});await S(!0),s(`设置已保存并生效`,`success`),e&&s(`已开启自动测试:服务将定期直连所有上游发送探测请求,有少量 token 消耗`,`warning`),t.restartHint&&s(t.restartHint,`warning`)}catch(e){s(e.message,`error`)}finally{E.value=!1}};return d(W),(n,i)=>{let s=v(`el-button`),c=v(`el-alert`),l=v(`el-tag`),u=v(`el-input`),d=v(`el-form-item`),f=v(`el-input-number`),S=v(`el-form`),A=v(`el-card`),j=v(`el-switch`),M=v(`el-divider`),N=v(`el-option`),U=v(`el-select`),q=v(`el-tab-pane`),J=v(`el-tabs`),Y=p(`loading`);return m(),e(J,{modelValue:_.value,"onUpdate:modelValue":i[7]||=e=>_.value=e,class:`settings-tabs`},{default:x(()=>[t(q,{label:`基本设置`,name:`basic`},{default:x(()=>[g((m(),r(`div`,de,[o(H)?(m(),e(c,{key:0,title:o(H),type:`error`,"show-icon":``,closable:!1},{default:x(()=>[t(s,{size:`small`,onClick:W},{default:x(()=>[...i[8]||=[a(`重试`,-1)]]),_:1})]),_:1},8,[`title`])):y(``,!0),t(A,{shadow:`never`},{header:x(()=>[b(`div`,$,[i[10]||=b(`span`,{class:`fw-600`},`网关访问`,-1),t(l,{type:`success`},{default:x(()=>[...i[9]||=[a(`运行中`,-1)]]),_:1})])]),default:x(()=>[t(S,{"label-position":`top`},{default:x(()=>[t(d,{label:`API 密钥 (masterKey)`},{default:x(()=>[t(u,{modelValue:D.value,"onUpdate:modelValue":i[0]||=e=>D.value=e,placeholder:`sk-1234`,clearable:``},{append:x(()=>[t(s,{onClick:O},{default:x(()=>[...i[11]||=[a(`复制`,-1)]]),_:1})]),_:1},8,[`modelValue`]),i[12]||=b(`div`,{class:`muted-sm`},`客户端请求 /v1/* 时的认证密钥(Bearer <masterKey>;留空 = 本地放行)`,-1)]),_:1}),t(d,{label:`监听端口 (port)`},{default:x(()=>[t(f,{modelValue:k.value,"onUpdate:modelValue":i[1]||=e=>k.value=e,min:1,max:65535,step:1,style:{width:`220px`}},null,8,[`modelValue`]),b(`div`,fe,[i[14]||=a(` 网关与管理台 API 的监听端口,保存后重启生效 `,-1),P.value===null?y(``,!0):(m(),r(T,{key:0},[i[13]||=a(` ;服务上报的端口 `,-1),b(`b`,null,h(P.value),1)],64))])]),_:1})]),_:1})]),_:1}),t(A,{shadow:`never`},{header:x(()=>[...i[15]||=[b(`span`,{class:`fw-600`},`安全与登录`,-1)]]),default:x(()=>[t(S,{"label-position":`top`},{default:x(()=>[t(d,{label:`管理台登录账号`},{default:x(()=>[b(`div`,pe,[t(u,{modelValue:I.value,"onUpdate:modelValue":i[2]||=e=>I.value=e,placeholder:`用户名`,style:{width:`200px`}},null,8,[`modelValue`]),t(u,{modelValue:L.value,"onUpdate:modelValue":i[3]||=e=>L.value=e,type:`password`,placeholder:`密码(至少 6 位)`,"show-password":``,style:{width:`200px`}},null,8,[`modelValue`])]),i[16]||=b(`div`,{class:`muted-sm`},` 管理台登录凭证;留空 = 免登录直接访问(仅本机使用时推荐)。 修改后立即生效,需用新账号重新登录 `,-1)]),_:1}),t(d,{label:`允许局域网访问 (allowLan)`},{default:x(()=>[t(j,{modelValue:F.value,"onUpdate:modelValue":i[4]||=e=>F.value=e},null,8,[`modelValue`]),b(`div`,me,[i[17]||=a(` 开启 = 绑定全部网卡,局域网内设备可访问;关闭 = 仅本机 127.0.0.1。保存后需重启生效 `,-1),R.value?y(``,!0):(m(),r(T,{key:0},[a(` ;未设置任何凭据(密钥与登录账号皆无)时始终仅绑本机 `)],64))])]),_:1})]),_:1})]),_:1}),t(A,{shadow:`never`},{header:x(()=>[b(`div`,he,[i[18]||=b(`span`,{class:`fw-600`},`模型服务监控`,-1),t(l,{type:z.value?`success`:`info`,size:`small`,"disable-transitions":``},{default:x(()=>[a(h(z.value?`已开启`:`未开启`),1)]),_:1},8,[`type`])])]),default:x(()=>[b(`div`,ge,[i[19]||=b(`div`,{class:`monitor-info`},[b(`div`,{class:`monitor-title`},`自动测试模型服务状态`),b(`div`,{class:`muted-sm`},` 按设定间隔自动直连所有上游模型发送极小探测请求(max_tokens: 1,有少量 token 消耗); 测试结果展示在「服务状态」页面 `)],-1),t(j,{modelValue:z.value,"onUpdate:modelValue":i[5]||=e=>z.value=e},null,8,[`modelValue`])]),z.value?(m(),r(T,{key:0},[t(M,{style:{margin:`12px 0`}}),t(S,{"label-position":`top`},{default:x(()=>[t(d,{label:`测试间隔`,style:{"margin-bottom":`0`}},{default:x(()=>[t(U,{modelValue:B.value,"onUpdate:modelValue":i[6]||=e=>B.value=e,style:{width:`220px`}},{default:x(()=>[(m(),r(T,null,C(V,e=>t(N,{key:e.value,label:e.label,value:e.value},null,8,[`label`,`value`])),64))]),_:1},8,[`modelValue`]),i[20]||=b(`div`,{class:`muted-sm`},`自动测试的执行间隔,保存后即时生效(无需重启)`,-1)]),_:1})]),_:1})],64)):y(``,!0)]),_:1}),b(`div`,_e,[t(s,{type:`primary`,size:`large`,loading:E.value,disabled:E.value||o(H)!==null,onClick:G},{default:x(()=>[a(h(E.value?`保存中...`:`保存设置`),1)]),_:1},8,[`loading`,`disabled`])])])),[[Y,w.value]])]),_:1}),t(q,{label:`代理开关`,name:`harness`,lazy:``},{default:x(()=>[t(K)]),_:1}),t(q,{label:`服务与更新`,name:`service`,lazy:``},{default:x(()=>[t(Q)]),_:1})]),_:1},8,[`modelValue`])}}}),[[`__scopeId`,`data-v-e5f93ad5`]]);export{ve as default};
1
+ import{A as e,F as t,I as n,M as r,O as i,P as a,Pt as o,Q as s,Tt as c,V as l,Wt as u,Z as d,a as f,at as p,et as m,fn as h,ht as g,i as _,it as v,j as y,k as b,mt as x,n as S,nt as C,vt as w,w as T}from"./router-BgTNV93P.js";import{n as E,t as D}from"./index-W7WdLt_5.js";import{n as O,t as k}from"./useManagerApi-USNyi1JZ.js";import{t as A}from"./config-_F8xCbJI.js";import{n as j,t as M}from"./useCopyToast-B_Qvf_Pf.js";import{t as N}from"./useToast-X_JkPDpr.js";import{t as P}from"./updateNote-CttDt8SZ.js";l(),u(),w();var F={class:`flex-between`},I={class:`muted-sm mb-8`},L={class:`switch-row`},R={class:`switch-info`},z={class:`switch-title`},B={class:`switch-row`},V={class:`switch-info`},H={class:`switch-title`},U={class:`switch-row`},W={class:`switch-info`},G={class:`switch-title`},K=D(n({__name:`HarnessSwitches`,setup(n){let{toast:i}=N(),o=c(!0),s=c(!1),l=c(null),u=c(null),f=c(null),_=c(null),S=c(`success`),C=async e=>{e||(l.value?s.value=!0:o.value=!0);try{l.value=await k.harness(),u.value=null}catch(t){e||(u.value=t.message)}finally{e||(o.value=!1,s.value=!1)}};d(()=>C(!1));let w={claudeCode:{label:`Claude Code`,file:`~/.claude/settings.json`,toggle:k.setClaudeCode},codex:{label:`Codex CLI`,file:`~/.codex/config.toml`,toggle:k.setCodex},dsh:{label:`DeepSeek Harness`,file:`~/.dsh/settings.yaml`,toggle:k.setDsh}},D=async(e,t)=>{if(!l.value||f.value)return;let n=w[e],r=t?`确定开启 ${n.label} 代理?将改写 ${n.file}(开启前自动备份,关闭时从备份还原)。`:`确定关闭 ${n.label} 代理?将从备份还原 ${n.file}(无备份时移除代理相关配置)。`;try{await E.confirm(r,t?`开启确认`:`关闭确认`,{confirmButtonText:t?`开启`:`关闭`,cancelButtonText:`取消`,type:`warning`})}catch{return}f.value=e;try{let e=await n.toggle(t);_.value=e.note??null,S.value=t?`success`:`info`,i(t?`已开启代理`:`已关闭代理`,`success`)}catch(e){i(e.message||`操作失败`,`error`)}finally{f.value=null,await C(!0)}};return(n,i)=>{let c=v(`el-button`),d=v(`el-alert`),w=v(`el-tag`),E=v(`el-switch`),O=v(`el-divider`),k=v(`el-empty`),A=v(`el-card`),j=p(`loading`);return g((m(),e(A,{shadow:`never`},{header:x(()=>[b(`div`,F,[i[7]||=b(`span`,{class:`fw-600`},`代理开关`,-1),t(c,{loading:s.value,onClick:i[0]||=e=>C(!1)},{default:x(()=>[...i[6]||=[a(`刷新`,-1)]]),_:1},8,[`loading`])])]),default:x(()=>[l.value?(m(),r(T,{key:0},[b(`div`,I,` 将本机 CLI 工具的流量一键指向本机网关(`+h(l.value.gatewayBase)+`)。 开启前自动备份原配置为 *.ellm-bak(保留最早的原始备份),关闭时从备份还原。 `,1),_.value?(m(),e(d,{key:0,title:_.value,type:S.value,"show-icon":``,class:`mb-8`,onClose:i[1]||=e=>_.value=null},null,8,[`title`,`type`])):y(``,!0),b(`div`,L,[b(`div`,R,[b(`div`,z,[i[8]||=a(` Claude Code `,-1),t(w,{type:l.value.claudeCode?`success`:`info`,size:`small`,"disable-transitions":``},{default:x(()=>[a(h(l.value.claudeCode?`已开启`:`未开启`),1)]),_:1},8,[`type`])]),i[9]||=b(`div`,{class:`switch-desc`},[a(` 写入 `),b(`code`,null,`~/.claude/settings.json`),a(` 的 env.ANTHROPIC_BASE_URL / ANTHROPIC_AUTH_TOKEN, 鉴权取网关配置的 masterKey(未设置将开启失败);其余字段原样保留,重启 Claude Code 会话后生效。 `)],-1)]),t(E,{"model-value":l.value.claudeCode,loading:f.value===`claudeCode`,onChange:i[2]||=e=>D(`claudeCode`,!!e)},null,8,[`model-value`,`loading`])]),t(O,{class:`switch-divider`}),b(`div`,B,[b(`div`,V,[b(`div`,H,[i[10]||=a(` Codex CLI `,-1),t(w,{type:l.value.codex?`success`:`info`,size:`small`,"disable-transitions":``},{default:x(()=>[a(h(l.value.codex?`已开启`:`未开启`),1)]),_:1},8,[`type`])]),i[11]||=b(`div`,{class:`switch-desc`},[a(` 写入 `),b(`code`,null,`~/.codex/config.toml`),a(` 的 model_provider 与 [model_providers.ellm-proxy] 段 (保留用户注释与排版);开启后需按提示设置环境变量 ELLM_PROXY_API_KEY 供 Codex 鉴权。 `)],-1)]),t(E,{"model-value":l.value.codex,loading:f.value===`codex`,onChange:i[3]||=e=>D(`codex`,!!e)},null,8,[`model-value`,`loading`])]),t(O,{class:`switch-divider`}),b(`div`,U,[b(`div`,W,[b(`div`,G,[i[12]||=a(` DeepSeek Harness `,-1),t(w,{type:l.value.dsh?`success`:`info`,size:`small`,"disable-transitions":``},{default:x(()=>[a(h(l.value.dsh?`已开启`:`未开启`),1)]),_:1},8,[`type`])]),i[13]||=b(`div`,{class:`switch-desc`},[a(` 写入 `),b(`code`,null,`~/.dsh/settings.yaml`),a(` 的 llm-deepseek.baseURL 与 `),b(`code`,null,`~/.dsh/.credentials.yaml`),a(` 的 DEEPSEEK_API_KEY(取网关 masterKey,未设置则写占位值);模型请在 dsh 内选择与网关部署名一致的模型。 dsh 为 developer preview,配置格式可能随版本变化。 `)],-1)]),t(E,{"model-value":l.value.dsh,loading:f.value===`dsh`,onChange:i[4]||=e=>D(`dsh`,!!e)},null,8,[`model-value`,`loading`])])],64)):(m(),e(k,{key:1,description:u.value||`暂无开关状态`},{default:x(()=>[t(c,{type:`primary`,onClick:i[5]||=e=>C(!1)},{default:x(()=>[...i[14]||=[a(`重试`,-1)]]),_:1})]),_:1},8,[`description`]))]),_:1})),[[j,o.value]])}}}),[[`__scopeId`,`data-v-fb084a91`]]);l(),u(),w();var q={class:`service-settings`},J={class:`flex-between`},Y={key:0,class:`switch-row`},ee={class:`switch-info`},te={class:`switch-title`},X={key:0,class:`switch-row`},Z={class:`switch-info`},ne={class:`switch-title`},re={class:`switch-desc`},ie={key:0,class:`version-block`},ae={class:`version-row`},oe={class:`muted-sm`},se={key:0,class:`muted-sm`},ce={key:1,class:`muted-sm`},le={class:`muted-sm`},ue={class:`version-actions`},Q=D(n({__name:`ServiceUpdateSettings`,setup(n){let{toast:o}=N(),l=c(!0),u=c(!1),f=c(null),S=c(null),C=c(null),w=c(null),D=c(null),A=c(!1),j=c(!1),M=c(null),F=null;s(()=>F?.abort());let I=async e=>{if(!e){if(u.value)return;u.value=!0}try{let[e,t]=await Promise.allSettled([k.autostart(),k.update()]);f.value=e.status===`fulfilled`?e.value:null,S.value=e.status===`rejected`?e.reason?.message:null,C.value=t.status===`fulfilled`?t.value:null,w.value=t.status===`rejected`?t.reason?.message:null}finally{l.value=!1,u.value=!1}};d(()=>I(!1));let L=e=>e?new Date(e).toLocaleString():``,R=i(()=>C.value?.lastCheck?.currentVersion??null),z=i(()=>_.value?.buildSource===`local`),B=i(()=>C.value?.lastCheck?.latestVersion??null),V=i(()=>C.value?.lastCheck?.hasUpdate===!0),H=i(()=>{let e=C.value?.lastCheck?.checkedAt;return e?new Date(e).toLocaleString():null}),U=i(()=>{let e=C.value?.lastApply;if(!e)return null;let t=L(e.appliedAt);return`${e.fromVersion} → ${e.toVersion}${t?`(${t})`:``}`}),W=async e=>{if(!f.value||D.value)return;let t=e?`确定开启开机自启?将注册登录触发的自启项(登录时自动恢复服务)。`:`确定关闭开机自启?将移除自启项,且此后首次启动不再自动注册。`;try{await E.confirm(t,e?`开启确认`:`关闭确认`,{confirmButtonText:e?`开启`:`关闭`,cancelButtonText:`取消`,type:`warning`})}catch{return}D.value=`autostart`;try{let t=await k.setAutostart(e);t.note?o(t.note,`success`):o(e?`开机自启已开启`:`开机自启已关闭`,`success`)}catch(e){o(e.message||`操作失败`,`error`)}finally{D.value=null,await I(!0)}},G=async e=>{if(!C.value||D.value)return;let t=e?`确定开启自动更新?将每小时检查 npm 源,发现新版本后自动安装并重启服务(过程中管理台短暂不可访问)。`:`确定关闭自动更新?不再自动检查与安装(手动检查与更新不受影响)。`;try{await E.confirm(t,e?`开启确认`:`关闭确认`,{confirmButtonText:e?`开启`:`关闭`,cancelButtonText:`取消`,type:`warning`})}catch{return}D.value=`updateEnabled`;try{let t=await k.setUpdateEnabled(e);t.note&&o(t.note,`success`)}catch(e){o(e.message||`操作失败`,`error`)}finally{D.value=null,await I(!0)}},K=async()=>{A.value=!0;try{let e=await k.checkUpdate();M.value=e.hasUpdate?`发现新版本 ${e.latestVersion}(当前 ${e.currentVersion}):可点击「立即更新」安装`:`已是最新版本 ${e.currentVersion}(检查于 ${L(e.checkedAt)})`,await I(!0)}catch(e){o(e.message||`检查更新失败`,`error`)}finally{A.value=!1}},Q=async()=>{try{await E.confirm(`确定更新到 ${B.value}?服务会自动重启并在启动时安装新版本:重启期间管理台短暂不可访问(预计 1~3 分钟),完成后自动恢复。`,`立即更新`,{confirmButtonText:`立即更新`,cancelButtonText:`取消`,type:`warning`})}catch{return}j.value=!0;let e=new AbortController;F=e;try{let t=await k.update(),n=await k.applyUpdate();if(!n.updated){M.value=`已是最新版本 ${n.fromVersion}`;return}M.value=`正在重启服务并安装 ${n.toVersion}(预计 1~3 分钟):重启期间管理台短暂不可访问,完成后这里会自动显示结果。`;let r=await O({targetVersion:n.toVersion,sinceAppliedAt:t.lastApply?.appliedAt??null,signal:e.signal});if(e.signal.aborted)return;r&&!r.error?(o(`已更新到 ${r.toVersion}`,`success`),M.value=`已更新 ${r.fromVersion} → ${r.toVersion},服务已在新版本上运行。`):r?.error?(o(`更新失败:${r.error}`,`error`),M.value=P(r.error)):M.value=`更新仍在进行(安装耗时较长):稍后刷新页面查看最新状态。`}catch(e){o(e.message||`更新失败`,`error`)}finally{j.value=!1,F===e&&(F=null),e.signal.aborted||await I(!0)}};return(n,i)=>{let o=v(`el-button`),s=v(`el-tag`),c=v(`el-switch`),d=v(`el-empty`),_=v(`el-card`),E=v(`el-link`),O=v(`el-alert`),k=p(`loading`);return g((m(),r(`div`,q,[t(_,{shadow:`never`,class:`mb-16`},{header:x(()=>[b(`div`,J,[i[7]||=b(`span`,{class:`fw-600`},`开机自启`,-1),t(o,{loading:u.value,onClick:i[0]||=e=>I(!1)},{default:x(()=>[...i[6]||=[a(`刷新`,-1)]]),_:1},8,[`loading`])])]),default:x(()=>[f.value?(m(),r(`div`,Y,[b(`div`,ee,[b(`div`,te,[i[8]||=a(` 登录时自动启动服务 `,-1),t(s,{type:f.value.enabled?`success`:`info`,size:`small`,"disable-transitions":``},{default:x(()=>[a(h(f.value.enabled?`已开启`:`未开启`),1)]),_:1},8,[`type`])]),i[9]||=b(`div`,{class:`switch-desc`},[a(` 登录操作系统时自动启动服务(无需管理员权限)。 关闭后首次启动 `),b(`code`,null,`ezllm`),a(` 也不会再自动注册,重新开启即可解除。 `)],-1)]),t(c,{"model-value":f.value.enabled,loading:D.value===`autostart`,onChange:i[1]||=e=>W(!!e)},null,8,[`model-value`,`loading`])])):(m(),e(d,{key:1,description:S.value||`暂无自启状态`},{default:x(()=>[t(o,{type:`primary`,onClick:i[2]||=e=>I(!1)},{default:x(()=>[...i[10]||=[a(`重试`,-1)]]),_:1})]),_:1},8,[`description`]))]),_:1}),t(_,{shadow:`never`,class:`mb-16`},{header:x(()=>[...i[11]||=[b(`div`,{class:`flex-between`},[b(`span`,{class:`fw-600`},`自动更新`)],-1)]]),default:x(()=>[C.value?(m(),r(`div`,X,[b(`div`,Z,[b(`div`,ne,[i[12]||=a(` 自动检查并安装新版本 `,-1),t(s,{type:C.value.enabled?`success`:`info`,size:`small`,"disable-transitions":``},{default:x(()=>[a(h(C.value.enabled?`已开启`:`未开启`),1)]),_:1},8,[`type`])]),b(`div`,re,[C.value.supported?(m(),r(T,{key:1},[a(` 每小时检查 npm 源,发现新版本后自动安装并重启服务(过程中管理台短暂不可访问); 关闭后仍可在下方手动检查与更新。 `)],64)):(m(),r(T,{key:0},[a(` 当前为源码运行模式,更新功能不可用(仅通过 npx ezllm install 装配的实例支持)。 `)],64))])]),C.value.supported?(m(),e(c,{key:0,"model-value":C.value.enabled,loading:D.value===`updateEnabled`,onChange:i[3]||=e=>G(!!e)},null,8,[`model-value`,`loading`])):y(``,!0)])):(m(),e(d,{key:1,description:w.value||`暂无更新状态`},{default:x(()=>[t(o,{type:`primary`,onClick:i[4]||=e=>I(!1)},{default:x(()=>[...i[13]||=[a(`重试`,-1)]]),_:1})]),_:1},8,[`description`]))]),_:1}),t(_,{shadow:`never`},{header:x(()=>[...i[14]||=[b(`div`,{class:`flex-between`},[b(`span`,{class:`fw-600`},`版本信息`)],-1)]]),default:x(()=>[C.value?(m(),r(`div`,ie,[b(`div`,ae,[i[18]||=b(`span`,{class:`version-label`},`当前版本`,-1),t(s,{size:`small`},{default:x(()=>[a(h(R.value||`未知`),1)]),_:1}),z.value?(m(),e(s,{key:0,type:`warning`,size:`small`,"disable-transitions":``},{default:x(()=>[...i[15]||=[a(`本地构建`,-1)]]),_:1})):y(``,!0),B.value?(m(),r(T,{key:1},[i[17]||=b(`span`,{class:`version-label`},`最新版本`,-1),t(s,{type:V.value?`warning`:`success`,size:`small`,"disable-transitions":``},{default:x(()=>[a(h(B.value),1)]),_:1},8,[`type`]),V.value?(m(),e(s,{key:0,type:`warning`,size:`small`,"disable-transitions":``},{default:x(()=>[...i[16]||=[a(`发现新版本`,-1)]]),_:1})):y(``,!0)],64)):y(``,!0)]),b(`div`,oe,[a(` 上次检查:`+h(H.value||`尚未检查`)+` `,1),C.value.updating?(m(),r(T,{key:0},[a(` · 更新执行中...`)],64)):y(``,!0)]),C.value.supported?y(``,!0):(m(),r(`div`,se,`源码运行模式:手动检查与更新不可用。`)),U.value?(m(),r(`div`,ce,`上次更新:`+h(U.value),1)):y(``,!0),b(`div`,le,[i[20]||=a(` npm 包主页:`,-1),t(E,{type:`primary`,href:`https://www.npmjs.com/package/ezllm`,target:`_blank`},{default:x(()=>[...i[19]||=[a(`npmjs.com/package/ezllm`,-1)]]),_:1})]),b(`div`,ue,[t(o,{loading:A.value,disabled:!C.value.supported||C.value.updating,onClick:K},{default:x(()=>[a(h(A.value?`检查中...`:`检查更新`),1)]),_:1},8,[`loading`,`disabled`]),V.value&&C.value.supported?(m(),e(o,{key:0,type:`primary`,loading:j.value,disabled:C.value.updating,onClick:Q},{default:x(()=>[a(h(j.value?`更新中...`:`立即更新到 ${B.value}`),1)]),_:1},8,[`loading`,`disabled`])):y(``,!0)]),M.value?(m(),e(O,{key:2,title:M.value,type:`info`,"show-icon":``,class:`mt-8`,onClose:i[5]||=e=>M.value=null},null,8,[`title`])):y(``,!0)])):(m(),e(d,{key:1,description:`更新状态不可用`}))]),_:1})])),[[k,l.value]])}}}),[[`__scopeId`,`data-v-567dce2c`]]);l(),w(),u();var de={class:`flex-col-gap`},$={class:`flex-between`},fe={class:`muted-sm`},pe={class:`login-row`},me={class:`muted-sm`},he={class:`flex-between`},ge={class:`monitor-row`},_e={class:`save-bar`},ve=D(n({__name:`SettingsView`,setup(n){let{toast:s}=N(),{copyWithToast:l}=M(),u=A(),_=c(`basic`),w=c(!0),E=c(!1),D=c(``),O=async()=>{D.value&&await l(D.value)},k=c(29770),P=c(null),F=c(!0),I=c(``),L=c(``),R=i(()=>D.value.trim()!==``||I.value!==``&&L.value!==``),z=c(!1),B=c(60),V=[{label:`10分钟`,value:10},{label:`30分钟`,value:30},{label:`1小时`,value:60},{label:`2小时`,value:120},{label:`5小时`,value:300},{label:`8小时`,value:480},{label:`12小时`,value:720},{label:`24小时`,value:1440}],{loadError:H,run:U}=j(`设置加载失败,请重试`),W=()=>U(async()=>{try{await u.load(),D.value=u.config.masterKey||``,k.value=u.config.port??29770;let e=u.config[`web-ui`]?.[`login-account`];I.value=e?.username||``,L.value=e?.password||``,F.value=u.config.allowLan!==!1;let t=u.config.latencyTest;z.value=t?.enabled===!0,B.value=t?.intervalMinutes??60;try{let e=await f.get(`/api/status`);P.value=e.listenPort}catch{P.value=null}}finally{w.value=!1}}),G=async()=>{if(I.value.trim()!==``||L.value!==``){if(I.value.trim()===``||L.value===``){s(`用户名和密码需同时填写`,`error`);return}if(L.value.length<6){s(`密码至少 6 位`,`error`);return}}E.value=!0;let e=z.value&&u.config.latencyTest?.enabled!==!0;try{let t=await u.update(e=>{e.masterKey=D.value.trim(),e.port=k.value,e.allowLan=F.value,e.latencyTest={enabled:z.value,intervalMinutes:B.value},e[`web-ui`]??={},e[`web-ui`][`login-account`]??={},e[`web-ui`][`login-account`].username=I.value.trim(),e[`web-ui`][`login-account`].password=L.value});await S(!0),s(`设置已保存并生效`,`success`),e&&s(`已开启自动测试:服务将定期直连所有上游发送探测请求,有少量 token 消耗`,`warning`),t.restartHint&&s(t.restartHint,`warning`)}catch(e){s(e.message,`error`)}finally{E.value=!1}};return d(W),(n,i)=>{let s=v(`el-button`),c=v(`el-alert`),l=v(`el-tag`),u=v(`el-input`),d=v(`el-form-item`),f=v(`el-input-number`),S=v(`el-form`),A=v(`el-card`),j=v(`el-switch`),M=v(`el-divider`),N=v(`el-option`),U=v(`el-select`),q=v(`el-tab-pane`),J=v(`el-tabs`),Y=p(`loading`);return m(),e(J,{modelValue:_.value,"onUpdate:modelValue":i[7]||=e=>_.value=e,class:`settings-tabs`},{default:x(()=>[t(q,{label:`基本设置`,name:`basic`},{default:x(()=>[g((m(),r(`div`,de,[o(H)?(m(),e(c,{key:0,title:o(H),type:`error`,"show-icon":``,closable:!1},{default:x(()=>[t(s,{size:`small`,onClick:W},{default:x(()=>[...i[8]||=[a(`重试`,-1)]]),_:1})]),_:1},8,[`title`])):y(``,!0),t(A,{shadow:`never`},{header:x(()=>[b(`div`,$,[i[10]||=b(`span`,{class:`fw-600`},`网关访问`,-1),t(l,{type:`success`},{default:x(()=>[...i[9]||=[a(`运行中`,-1)]]),_:1})])]),default:x(()=>[t(S,{"label-position":`top`},{default:x(()=>[t(d,{label:`API 密钥 (masterKey)`},{default:x(()=>[t(u,{modelValue:D.value,"onUpdate:modelValue":i[0]||=e=>D.value=e,placeholder:`sk-1234`,clearable:``},{append:x(()=>[t(s,{onClick:O},{default:x(()=>[...i[11]||=[a(`复制`,-1)]]),_:1})]),_:1},8,[`modelValue`]),i[12]||=b(`div`,{class:`muted-sm`},`客户端请求 /v1/* 时的认证密钥(Bearer <masterKey>;留空 = 本地放行)`,-1)]),_:1}),t(d,{label:`监听端口 (port)`},{default:x(()=>[t(f,{modelValue:k.value,"onUpdate:modelValue":i[1]||=e=>k.value=e,min:1,max:65535,step:1,style:{width:`220px`}},null,8,[`modelValue`]),b(`div`,fe,[i[14]||=a(` 网关与管理台 API 的监听端口,保存后重启生效 `,-1),P.value===null?y(``,!0):(m(),r(T,{key:0},[i[13]||=a(` ;服务上报的端口 `,-1),b(`b`,null,h(P.value),1)],64))])]),_:1})]),_:1})]),_:1}),t(A,{shadow:`never`},{header:x(()=>[...i[15]||=[b(`span`,{class:`fw-600`},`安全与登录`,-1)]]),default:x(()=>[t(S,{"label-position":`top`},{default:x(()=>[t(d,{label:`管理台登录账号`},{default:x(()=>[b(`div`,pe,[t(u,{modelValue:I.value,"onUpdate:modelValue":i[2]||=e=>I.value=e,placeholder:`用户名`,style:{width:`200px`}},null,8,[`modelValue`]),t(u,{modelValue:L.value,"onUpdate:modelValue":i[3]||=e=>L.value=e,type:`password`,placeholder:`密码(至少 6 位)`,"show-password":``,style:{width:`200px`}},null,8,[`modelValue`])]),i[16]||=b(`div`,{class:`muted-sm`},` 管理台登录凭证;留空 = 免登录直接访问(仅本机使用时推荐)。 修改后立即生效,需用新账号重新登录 `,-1)]),_:1}),t(d,{label:`允许局域网访问 (allowLan)`},{default:x(()=>[t(j,{modelValue:F.value,"onUpdate:modelValue":i[4]||=e=>F.value=e},null,8,[`modelValue`]),b(`div`,me,[i[17]||=a(` 开启 = 绑定全部网卡,局域网内设备可访问;关闭 = 仅本机 127.0.0.1。保存后需重启生效 `,-1),R.value?y(``,!0):(m(),r(T,{key:0},[a(` ;未设置任何凭据(密钥与登录账号皆无)时始终仅绑本机 `)],64))])]),_:1})]),_:1})]),_:1}),t(A,{shadow:`never`},{header:x(()=>[b(`div`,he,[i[18]||=b(`span`,{class:`fw-600`},`模型服务监控`,-1),t(l,{type:z.value?`success`:`info`,size:`small`,"disable-transitions":``},{default:x(()=>[a(h(z.value?`已开启`:`未开启`),1)]),_:1},8,[`type`])])]),default:x(()=>[b(`div`,ge,[i[19]||=b(`div`,{class:`monitor-info`},[b(`div`,{class:`monitor-title`},`自动测试模型服务状态`),b(`div`,{class:`muted-sm`},` 按设定间隔自动直连所有上游模型发送极小探测请求(max_tokens: 1,有少量 token 消耗); 测试结果展示在「服务状态」页面 `)],-1),t(j,{modelValue:z.value,"onUpdate:modelValue":i[5]||=e=>z.value=e},null,8,[`modelValue`])]),z.value?(m(),r(T,{key:0},[t(M,{style:{margin:`12px 0`}}),t(S,{"label-position":`top`},{default:x(()=>[t(d,{label:`测试间隔`,style:{"margin-bottom":`0`}},{default:x(()=>[t(U,{modelValue:B.value,"onUpdate:modelValue":i[6]||=e=>B.value=e,style:{width:`220px`}},{default:x(()=>[(m(),r(T,null,C(V,e=>t(N,{key:e.value,label:e.label,value:e.value},null,8,[`label`,`value`])),64))]),_:1},8,[`modelValue`]),i[20]||=b(`div`,{class:`muted-sm`},`自动测试的执行间隔,保存后即时生效(无需重启)`,-1)]),_:1})]),_:1})],64)):y(``,!0)]),_:1}),b(`div`,_e,[t(s,{type:`primary`,size:`large`,loading:E.value,disabled:E.value||o(H)!==null,onClick:G},{default:x(()=>[a(h(E.value?`保存中...`:`保存设置`),1)]),_:1},8,[`loading`,`disabled`])])])),[[Y,w.value]])]),_:1}),t(q,{label:`代理开关`,name:`harness`,lazy:``},{default:x(()=>[t(K)]),_:1}),t(q,{label:`服务与更新`,name:`service`,lazy:``},{default:x(()=>[t(Q)]),_:1})]),_:1},8,[`modelValue`])}}}),[[`__scopeId`,`data-v-e5f93ad5`]]);export{ve as default};
@@ -1 +1 @@
1
- import{A as e,F as t,I as n,M as r,P as i,S as a,Tt as o,V as s,Z as c,a as l,et as u,ft as d,it as f,j as p,k as m,m as h,mt as g,n as _,r as v,u as y,vt as b}from"./router-DxY62FPf.js";import{t as x}from"./message-JXw_u_ps.js";import{t as S}from"./index-DVkpGX_l.js";import{t as C}from"./clipboard-JYWVdyjq.js";s(),h(),b();var w={class:`setup-wrap`},T={class:`account-row`},E=S(n({__name:`SetupView`,setup(n){let s=y(),h=o(!1),b=o(``),S=o(!1),E=!1,D=o(``),O=o(``),k=o(!1),A=o(``);c(async()=>{let e=await _();S.value=e.masterKeySet});function j(){b.value=(()=>{let e=new Uint8Array(32);crypto.getRandomValues(e);let t=``;for(let n of e)t+=String.fromCharCode(n);return btoa(t).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/,``)})(),E=!0}d(h,e=>{A.value=``,e?b.value.trim()===``&&j():E&&=(b.value=``,!1)});async function M(){await C(b.value)?x.success(`已复制到剪贴板`):x.error(`复制失败,请手动选择复制`)}async function N(){A.value=``;let e=h.value?`server`:`local`,t=b.value.trim(),n=D.value.trim()!==``||O.value!==``;if(h.value&&t===``){A.value=`服务器部署必须设置主密钥,防止 /v1 网关被他人盗用`;return}if(h.value&&!n){A.value=`服务器部署必须设置登录账号密码,防止管理台被陌生人登录`;return}if(n){if(D.value.trim()===``||O.value===``){A.value=`用户名和密码需同时填写`;return}if(O.value.length<6){A.value=`密码至少 6 位`;return}}k.value=!0;try{let r=await l.post(`/api/setup/finish`,{deployment:e,...t===``?{}:{masterKey:t},...n?{username:D.value.trim(),password:O.value}:{}});v(e,n),x.success(n?`初始化完成,请使用新账号登录`:`初始化完成,免登录进入管理台`),r.restartHint&&x({message:r.restartHint,type:`warning`,duration:8e3}),await s.push(n?`/login`:`/`)}catch(e){A.value=e.message||`保存失败`}finally{k.value=!1}}return(n,o)=>{let s=f(`el-checkbox`),c=f(`el-alert`),l=f(`el-button`),d=f(`el-input`),_=f(`el-form-item`),v=f(`el-form`),y=f(`el-card`);return u(),r(`div`,w,[t(y,{shadow:`never`,class:`setup-card`},{default:g(()=>[o[10]||=m(`div`,{class:`setup-brand`},[m(`span`,{class:`brand-mark`},`EZ`),m(`span`,{class:`setup-title`},`初始化 EZLLM`)],-1),o[11]||=m(`p`,{class:`setup-sub`},`首次使用前完成部署形态与访问凭据的配置`,-1),t(s,{modelValue:h.value,"onUpdate:modelValue":o[0]||=e=>h.value=e,class:`mb-16`},{default:g(()=>[...o[4]||=[i(` 允许其他设备访问本服务(局域网 / 公网部署) `,-1)]]),_:1},8,[`modelValue`]),h.value?(u(),e(c,{key:0,type:`warning`,"show-icon":``,closable:!1,title:`服务将对网络中的其他设备可见,请务必保留主密钥并修改默认账号`,class:`mb-16`})):p(``,!0),t(v,{"label-position":`top`,onSubmit:a(N,[`prevent`])},{default:g(()=>[t(_,null,{label:g(()=>[...o[5]||=[i(` API 主密钥(本地部署可留空) `,-1),m(`span`,{class:`label-hint`},`调用 /v1/* 时的 Bearer Token;留空 = 不启用鉴权,且未设登录账号时服务仅本机可访问`,-1)]]),default:g(()=>[t(d,{modelValue:b.value,"onUpdate:modelValue":o[1]||=e=>b.value=e,placeholder:S.value?`已设置主密钥,留空保持不变`:`未设置主密钥`,clearable:``},{append:g(()=>[t(l,{onClick:j},{default:g(()=>[...o[6]||=[i(`生成`,-1)]]),_:1}),t(l,{disabled:!b.value,onClick:M},{default:g(()=>[...o[7]||=[i(`复制`,-1)]]),_:1},8,[`disabled`])]),_:1},8,[`modelValue`,`placeholder`])]),_:1}),t(_,null,{label:g(()=>[...o[8]||=[i(` 管理台登录(可选) `,-1),m(`span`,{class:`label-hint`},`不填 = 免登录直接进管理台(纯本机使用);勾选上方后必须填写`,-1)]]),default:g(()=>[m(`div`,T,[t(d,{modelValue:D.value,"onUpdate:modelValue":o[2]||=e=>D.value=e,placeholder:`用户名`,clearable:``},null,8,[`modelValue`]),t(d,{modelValue:O.value,"onUpdate:modelValue":o[3]||=e=>O.value=e,type:`password`,"show-password":``,placeholder:`密码(至少 6 位)`},null,8,[`modelValue`])])]),_:1}),A.value?(u(),e(c,{key:0,title:A.value,type:`error`,"show-icon":``,closable:!1,class:`mb-16`},null,8,[`title`])):p(``,!0),t(l,{type:`primary`,class:`full-width`,loading:k.value,onClick:N},{default:g(()=>[...o[9]||=[i(` 完成初始化 `,-1)]]),_:1},8,[`loading`])]),_:1})]),_:1})])}}}),[[`__scopeId`,`data-v-d62562ab`]]);export{E as default};
1
+ import{A as e,F as t,I as n,M as r,P as i,S as a,Tt as o,V as s,Z as c,a as l,et as u,ft as d,it as f,j as p,k as m,m as h,mt as g,n as _,r as v,u as y,vt as b}from"./router-BgTNV93P.js";import{t as x}from"./message-DpifAOwJ.js";import{t as S}from"./index-W7WdLt_5.js";import{t as C}from"./clipboard-JYWVdyjq.js";s(),h(),b();var w={class:`setup-wrap`},T={class:`account-row`},E=S(n({__name:`SetupView`,setup(n){let s=y(),h=o(!1),b=o(``),S=o(!1),E=!1,D=o(``),O=o(``),k=o(!1),A=o(``);c(async()=>{let e=await _();S.value=e.masterKeySet});function j(){b.value=(()=>{let e=new Uint8Array(32);crypto.getRandomValues(e);let t=``;for(let n of e)t+=String.fromCharCode(n);return btoa(t).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/,``)})(),E=!0}d(h,e=>{A.value=``,e?b.value.trim()===``&&j():E&&=(b.value=``,!1)});async function M(){await C(b.value)?x.success(`已复制到剪贴板`):x.error(`复制失败,请手动选择复制`)}async function N(){A.value=``;let e=h.value?`server`:`local`,t=b.value.trim(),n=D.value.trim()!==``||O.value!==``;if(h.value&&t===``){A.value=`服务器部署必须设置主密钥,防止 /v1 网关被他人盗用`;return}if(h.value&&!n){A.value=`服务器部署必须设置登录账号密码,防止管理台被陌生人登录`;return}if(n){if(D.value.trim()===``||O.value===``){A.value=`用户名和密码需同时填写`;return}if(O.value.length<6){A.value=`密码至少 6 位`;return}}k.value=!0;try{let r=await l.post(`/api/setup/finish`,{deployment:e,...t===``?{}:{masterKey:t},...n?{username:D.value.trim(),password:O.value}:{}});v(e,n),x.success(n?`初始化完成,请使用新账号登录`:`初始化完成,免登录进入管理台`),r.restartHint&&x({message:r.restartHint,type:`warning`,duration:8e3}),await s.push(n?`/login`:`/`)}catch(e){A.value=e.message||`保存失败`}finally{k.value=!1}}return(n,o)=>{let s=f(`el-checkbox`),c=f(`el-alert`),l=f(`el-button`),d=f(`el-input`),_=f(`el-form-item`),v=f(`el-form`),y=f(`el-card`);return u(),r(`div`,w,[t(y,{shadow:`never`,class:`setup-card`},{default:g(()=>[o[10]||=m(`div`,{class:`setup-brand`},[m(`span`,{class:`brand-mark`},`EZ`),m(`span`,{class:`setup-title`},`初始化 EZLLM`)],-1),o[11]||=m(`p`,{class:`setup-sub`},`首次使用前完成部署形态与访问凭据的配置`,-1),t(s,{modelValue:h.value,"onUpdate:modelValue":o[0]||=e=>h.value=e,class:`mb-16`},{default:g(()=>[...o[4]||=[i(` 允许其他设备访问本服务(局域网 / 公网部署) `,-1)]]),_:1},8,[`modelValue`]),h.value?(u(),e(c,{key:0,type:`warning`,"show-icon":``,closable:!1,title:`服务将对网络中的其他设备可见,请务必保留主密钥并修改默认账号`,class:`mb-16`})):p(``,!0),t(v,{"label-position":`top`,onSubmit:a(N,[`prevent`])},{default:g(()=>[t(_,null,{label:g(()=>[...o[5]||=[i(` API 主密钥(本地部署可留空) `,-1),m(`span`,{class:`label-hint`},`调用 /v1/* 时的 Bearer Token;留空 = 不启用鉴权,且未设登录账号时服务仅本机可访问`,-1)]]),default:g(()=>[t(d,{modelValue:b.value,"onUpdate:modelValue":o[1]||=e=>b.value=e,placeholder:S.value?`已设置主密钥,留空保持不变`:`未设置主密钥`,clearable:``},{append:g(()=>[t(l,{onClick:j},{default:g(()=>[...o[6]||=[i(`生成`,-1)]]),_:1}),t(l,{disabled:!b.value,onClick:M},{default:g(()=>[...o[7]||=[i(`复制`,-1)]]),_:1},8,[`disabled`])]),_:1},8,[`modelValue`,`placeholder`])]),_:1}),t(_,null,{label:g(()=>[...o[8]||=[i(` 管理台登录(可选) `,-1),m(`span`,{class:`label-hint`},`不填 = 免登录直接进管理台(纯本机使用);勾选上方后必须填写`,-1)]]),default:g(()=>[m(`div`,T,[t(d,{modelValue:D.value,"onUpdate:modelValue":o[2]||=e=>D.value=e,placeholder:`用户名`,clearable:``},null,8,[`modelValue`]),t(d,{modelValue:O.value,"onUpdate:modelValue":o[3]||=e=>O.value=e,type:`password`,"show-password":``,placeholder:`密码(至少 6 位)`},null,8,[`modelValue`])])]),_:1}),A.value?(u(),e(c,{key:0,title:A.value,type:`error`,"show-icon":``,closable:!1,class:`mb-16`},null,8,[`title`])):p(``,!0),t(l,{type:`primary`,class:`full-width`,loading:k.value,onClick:N},{default:g(()=>[...o[9]||=[i(` 完成初始化 `,-1)]]),_:1},8,[`loading`])]),_:1})]),_:1})])}}}),[[`__scopeId`,`data-v-d62562ab`]]);export{E as default};
@@ -1 +1 @@
1
- import{O as e,Tt as t,V as n,a as r,vt as i}from"./router-DxY62FPf.js";import{r as a}from"./index-DVkpGX_l.js";i(),n();var o=a(`config`,()=>{let n=t({}),i=t(!1),a=e(()=>Array.isArray(n.value.providers)?n.value.providers:[]),o=e(()=>a.value.length),s=e(()=>a.value.reduce((e,t)=>e+(t.models?.length??0),0));async function c(){i.value=!0;try{n.value=await r.get(`/api/config`)}finally{i.value=!1}}async function l(){return await r.put(`/api/config`,n.value)}async function u(e){return e(n.value),await l()}return{config:n,loading:i,providers:a,providerCount:o,totalModelCount:s,load:c,save:l,update:u}});export{o as t};
1
+ import{O as e,Tt as t,V as n,a as r,vt as i}from"./router-BgTNV93P.js";import{r as a}from"./index-W7WdLt_5.js";i(),n();var o=a(`config`,()=>{let n=t({}),i=t(!1),a=e(()=>Array.isArray(n.value.providers)?n.value.providers:[]),o=e(()=>a.value.length),s=e(()=>a.value.reduce((e,t)=>e+(t.models?.length??0),0));async function c(){i.value=!0;try{n.value=await r.get(`/api/config`)}finally{i.value=!1}}async function l(){return await r.put(`/api/config`,n.value)}async function u(e){return e(n.value),await l()}return{config:n,loading:i,providers:a,providerCount:o,totalModelCount:s,load:c,save:l,update:u}});export{o as t};
@@ -0,0 +1 @@
1
+ var e=e=>String(e).padStart(2,`0`),t=t=>{let n=t=>`${t.getFullYear()}-${e(t.getMonth()+1)}-${e(t.getDate())}`,r=new Date,i=new Date(r),a=r;if(t!==`today`){if(t===`yesterday`)i.setDate(r.getDate()-1),a=i;else if(t===`beforeYesterday`)i.setDate(r.getDate()-2),a=i;else if(t===`last3days`)i.setDate(r.getDate()-2);else if(t===`week`)i.setDate(r.getDate()-(r.getDay()+6)%7);else if(t===`month`)i.setDate(1);else return null}return[n(i),n(a)]},n=e=>{if(e.name)return e.name;if(e.alias)return e.alias;let t=e.apiKey||``;if(!t)return`-`;if(t.length<=8)return t;let n=Math.min(6,Math.floor(t.length/4));return`${t.substring(0,n)}...${t.substring(t.length-n)}`},r=e=>{if(!e)return null;let t=new Date(e);return Number.isNaN(t.getTime())?null:t},i=t=>{let n=r(t);return n===null?`-`:`${n.getFullYear()}-${e(n.getMonth()+1)}-${e(n.getDate())} ${e(n.getHours())}:${e(n.getMinutes())}:${e(n.getSeconds())}`},a=t=>{let n=r(t);return n===null?`-`:`${e(n.getMonth()+1)}-${e(n.getDate())} ${e(n.getHours())}:${e(n.getMinutes())}:${e(n.getSeconds())}`},o=e=>e?typeof e==`string`?e:JSON.stringify(e,null,2):`-`,s=e=>{if(!e)return`-`;try{return JSON.stringify(JSON.parse(e),null,2)}catch{return e}},c=e=>{let t=e??0;return(Number.isFinite(t)?t:0).toLocaleString()},l=({protocol:e,hostname:t,port:n})=>`${e===`https:`?`https:`:`http:`}//${t}${n?`:${n}`:``}`,u=e=>e>=1?String(Math.floor(e)):(Math.floor(e*10)/10).toFixed(1),d=e=>e==null||e<=0?`-`:u(e/1e3)+`s`,f=e=>e==null?`-`:e<1e3?`${String(e)}ms`:`${(e/1e3).toFixed(1)}s`,p=e=>typeof e!=`number`||!Number.isFinite(e)||e<=0?`-`:`${u(e)} t/s`,m=`首 token 延迟:请求进入网关 → 上游首个响应数据块到达(仅流式请求有观测点)`,h=`生成速度:输出 token ÷ 生成窗口。流式 = 首 token 后到流结束;非流式无更细观测点,按总耗时近似`,g=`${h};${m}`,_=(e,t)=>{let n=p(e),r=d(t);return r===`-`?n:n===`-`?r:`${r} · ${n}`},v=e=>{let t=e.input_tokens||0,n=e.cache_read_tokens||0;return t<=0?`-`:(n/t*100).toFixed(1)+`%`},y=(e,t=262144)=>{let n=e??``;return n.length<=t?n:`${n.slice(0,t)}\n\n…(已省略 ${(n.length-t).toLocaleString()} 字符以保持流畅,完整内容请点上方「复制」按钮)`},b=e=>{let t=(e||``).trim();return t?t.length>8?`${t.slice(0,8)}…`:t:`-`},x=e=>e.client||e.user_agent||`-`,S=e=>e.user_agent?`${e.user_agent}(点击复制)`:`${e.client??`-`}(点击复制)`,C=e=>{let t=(e||``).split(`,`).map(e=>e.trim()).filter(Boolean).sort();return t.length===0?`-`:t.length<=2?t.join(`, `):`${t.slice(0,2).join(`, `)} +${t.length-2}`},w=e=>C(e),T=e=>C(e);export{y as C,_ as S,e as _,v as a,b,T as c,c as d,p as f,w as g,s as h,l as i,d as l,i as m,h as n,x as o,o as p,m as r,S as s,g as t,f as u,n as v,a as x,t as y};