ezllm 0.0.48 → 0.0.50
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.
- package/dist/server.js +62 -61
- package/dist/web-ui/assets/{DashboardView-CJOcLFY-.js → DashboardView-BJ73jw9G.js} +2 -2
- package/dist/web-ui/assets/{DashboardView-CNsnnzad.css → DashboardView-CrDoH6I9.css} +1 -1
- package/dist/web-ui/assets/LayoutView-CuX7RHKs.js +1 -0
- package/dist/web-ui/assets/LayoutView-b0pdxJLS.css +1 -0
- package/dist/web-ui/assets/{LoginView-Cp-a8Nds.js → LoginView-DW5V8P3m.js} +1 -1
- package/dist/web-ui/assets/{LogsView-C1ImQHJ6.js → LogsView-DrG_qFqR.js} +2 -2
- package/dist/web-ui/assets/{ManagedServicesView-DIMY-j18.js → ManagedServicesView-Dajk1OlI.js} +1 -1
- package/dist/web-ui/assets/{PluginsView-CqmYhJ6G.js → PluginsView-Bo7jtP57.js} +1 -1
- package/dist/web-ui/assets/ProvidersView-AoGdeGoV.js +14 -0
- package/dist/web-ui/assets/{ProvidersView-BwX8Y3kP.css → ProvidersView-DZs-NofB.css} +1 -1
- package/dist/web-ui/assets/{SettingsView-BbmPwJ-1.js → SettingsView-Bbn_XBX3.js} +1 -1
- package/dist/web-ui/assets/{SetupView-WCA8Jeug.js → SetupView-Co92DXfg.js} +1 -1
- package/dist/web-ui/assets/{config-BKCqJSgG.js → config-CVy3DdQo.js} +1 -1
- package/dist/web-ui/assets/index-Bpt0yCG7.js +49 -0
- package/dist/web-ui/assets/{message-Bqg-4z7y.js → message-7_77xsCe.js} +2 -2
- package/dist/web-ui/assets/pluginProviders-DFVS7pcs.js +1 -0
- package/dist/web-ui/assets/{providers-DRvT1zLg.js → providers-Dx3XtxJu.js} +1 -1
- package/dist/web-ui/assets/{router-CpkAp9dB.js → router-DOdUMO6P.js} +2 -2
- package/dist/web-ui/assets/{useCopyToast-DwJ3VhPN.js → useCopyToast-Dkb8g4uG.js} +1 -1
- package/dist/web-ui/assets/{useManagerApi-Cf88mNiu.js → useManagerApi-jm_MgzHV.js} +1 -1
- package/dist/web-ui/assets/{useQuickRangeFilter-BsOHHbog.js → useQuickRangeFilter-CC-fmdix.js} +1 -1
- package/dist/web-ui/assets/useToast-BxrPRTvE.js +1 -0
- package/dist/web-ui/index.html +3 -3
- package/package.json +1 -1
- package/dist/web-ui/assets/LayoutView-DH55aSBP.js +0 -1
- package/dist/web-ui/assets/LayoutView-cQeiOjLU.css +0 -1
- package/dist/web-ui/assets/ProvidersView-uCjHMlHd.js +0 -14
- package/dist/web-ui/assets/index-DNgY-btf.js +0 -49
- package/dist/web-ui/assets/pluginProviders-BGmYcLwJ.js +0 -1
- package/dist/web-ui/assets/useToast-IlI6ESuD.js +0 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{$ as e,A as t,Et as n,F as r,Ft as i,Gt as a,H as o,I as s,L as c,M as l,N as u,Q as d,T as f,a as p,at as m,cn as ee,d as h,gt as te,ht as g,j as _,k as v,l as y,ot as ne,pn as b,pt as x,rt as S,tt as C,un as re,xt as w,yt as T}from"./router-
|
|
2
|
-
`),cells:n}})),be=(e,t)=>e===null&&t===null?0:e===null?1:t===null?-1:e-t,xe=v(()=>[...x.value].sort((e,t)=>{let n=e.lastOk===!1;if(n!==(t.lastOk===!1))return n?1:-1;let r=be(e.avg24h,t.avg24h);return r===0?e.model.localeCompare(t.model):r})),Se=async e=>{if(e.length===0){F.value=new Map;return}let t=await Promise.all(e.map(async e=>{try{let t=await p.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]}}));F.value=new Map(t)},Ce=async()=>{let e=await p.get(`/api/latency/history`);return x.value=e.models??[],T.value=e.running,E.value=e.lastRunAt,e},Q=()=>y(async()=>{try{await Ce(),P.value=I(),await Se(x.value.map(e=>e.model))}finally{w.value=!1}}),we=()=>Q(),Te=()=>{k.value?A=window.setInterval(()=>void Q(),5e3):A!==void 0&&(window.clearInterval(A),A=void 0)},Ee=async()=>{D.value=!0;try{await p.post(`/api/latency/run`)}catch(e){o(e.message,`error`),D.value=!1;return}j=window.setInterval(async()=>{try{(await Ce()).running||(window.clearInterval(j),j=void 0,D.value=!1,P.value=I(),await Se(x.value.map(e=>e.model)))}catch{}},2e3)};return d(()=>{Q()}),e(()=>{A!==void 0&&window.clearInterval(A),j!==void 0&&window.clearInterval(j)}),(e,n)=>{let a=m(`el-button`),o=m(`el-alert`),d=m(`el-tag`),p=m(`el-checkbox`),v=m(`el-empty`),y=m(`el-card`),x=ne(`loading`);return C(),u(`div`,z,[i(h)?(C(),_(o,{key:0,title:i(h),type:`error`,"show-icon":``,closable:!1,class:`mb-16`},{default:g(()=>[s(a,{size:`small`,onClick:we},{default:g(()=>[...n[1]||=[r(`重试`,-1)]]),_:1})]),_:1},8,[`title`])):l(``,!0),s(y,{shadow:`never`,class:`service-status-card`},{header:g(()=>[t(`div`,B,[t(`div`,V,[n[3]||=t(`span`,{class:`fw-600`},`服务状态`,-1),T.value?(C(),_(d,{key:0,type:`warning`,size:`small`},{default:g(()=>[...n[2]||=[r(`测试进行中`,-1)]]),_:1})):E.value?(C(),_(d,{key:1,type:`info`,size:`small`},{default:g(()=>[r(` 上次测试 `+b(i(N)(E.value)),1)]),_:1})):l(``,!0)]),t(`div`,ue,[s(p,{modelValue:k.value,"onUpdate:modelValue":n[0]||=e=>k.value=e,onChange:Te},{default:g(()=>[...n[4]||=[r(` 自动刷新(5s) `,-1)]]),_:1},8,[`modelValue`]),s(a,{loading:D.value,onClick:Ee},{default:g(()=>[...n[5]||=[r(` 延迟测试 `,-1)]]),_:1},8,[`loading`])])])]),default:g(()=>[n[9]||=t(`div`,{class:`legend`},[t(`span`,{class:`legend-text`},`延迟`),t(`span`,{class:`legend-text`},`低`),t(`span`,{class:`legend-gradient`}),t(`span`,{class:`legend-text`},`高`),t(`span`,{class:`legend-swatch legend-swatch--down`}),t(`span`,{class:`legend-text`},`该小时有失败探测`),t(`span`,{class:`legend-swatch legend-swatch--empty`}),t(`span`,{class:`legend-text`},`无探测数据`)],-1),te((C(),u(`div`,de,[n[8]||=t(`div`,{class:`muted-sm hint`},` 右侧 24 格为最近 24 小时(每格 1 小时,本地整点对齐,最右格为当前小时)。 格子底色为当小时成功探测的平均延迟,全表统一色标(本期最快→最慢 绿→红); 当小时存在失败探测即视为不可用,显示灰色。 行按 24h 平均延迟升序,最近一次探测失败的模型沉底。 `,-1),Z.value.length>0?(C(),u(`div`,fe,[t(`div`,pe,[n[6]||=t(`div`,{class:`col-name`},`模型名称`,-1),n[7]||=t(`div`,{class:`col-status`},`状态`,-1),t(`div`,H,[(C(!0),u(f,null,S(oe.value,e=>(C(),u(`div`,{key:e.start,class:`cell cell--head`,title:e.fullLabel},[t(`span`,U,b(e.dateLabel),1),t(`span`,null,b(e.hourLabel),1)],8,me))),128))])]),(C(!0),u(f,null,S(Z.value,e=>(C(),u(`div`,{key:e.model,class:`gantt-row`},[t(`div`,he,[t(`span`,{class:`copy-text model-name`,title:e.model,onClick:t=>i(c)(e.model)},b(e.model),9,W)]),t(`div`,{class:`col-status`,title:e.statusTitle},b(i(M)(e.avg24h)),9,G),t(`div`,K,[(C(!0),u(f,null,S(e.cells,e=>(C(),u(`div`,{key:e.start,class:ee([`cell`,e.className]),style:re(e.style),title:e.title},null,14,q))),128))])]))),128))])):(C(),u(`div`,J,[s(v,{description:`暂无延迟数据,点击「延迟测试」开始`,"image-size":80})]))])),[[x,w.value]])]),_:1})])}}}),[[`__scopeId`,`data-v-0f99bcf1`]]);o(),T(),a();var ye={class:`flex-col-gap`},X={class:`kv-grid`},Z={class:`kv-label`},be={class:`kv-value`},xe=[`onClick`],Se={class:`kv-item kv-span-2`},Ce={class:`kv-value`},Q={key:1,class:`kv-unit`},we={class:`kv-item`},Te={class:`kv-value`},Ee={class:`kv-unit`},De={class:`kv-item`},Oe={class:`kv-value`},ke={class:`flex-between card-header-wrap`},Ae={class:`flex-gap-8`},je={class:`usage-grid`},Me={class:`usage-cell`},Ne={class:`usage-num orange`},Pe={class:`usage-cell`},Fe={class:`usage-num blue`},Ie={class:`usage-cell`},Le={class:`usage-num green`},Re={class:`usage-cell`},ze={class:`usage-num purple`},Be={class:`usage-cell`},Ve={class:`usage-num purple`},He={key:0,class:`usage-cell`},Ue={class:`usage-num gray`},We={class:`usage-cell`},Ge={class:`usage-num blue`},Ke={class:`usage-cell`},qe=[`title`],Je={class:`usage-cell`},Ye=[`title`],Xe={key:0},Ze=[`onClick`],Qe=[`title`],$e=h(c({__name:`DashboardView`,setup(a){let o=D(),c=y(),{copyWithToast:h}=ie(),{loadError:re,track:T,retry:O}=le(),ae={local:`本机 API 地址`,lan:`局域网地址`,other:`API 地址`},M=n(null),N=n(!0),R=n(``),z=n(c.query.tab===`status`?`status`:`overview`);x(()=>c.query.tab,e=>{e===`status`&&(z.value=`status`)});let{rangeKey:B,dateRange:V,onRangeChange:ue}=A(()=>H(),`today`),de=()=>{B.value=``,H()},fe=v(()=>{let e=new Set;for(let t of o.suppliers)for(let n of t.models)e.add(n.modelName);if(M.value?.models)for(let t of M.value.models)e.add(t.model);return[...e].sort()}),pe=k(),H=T(async()=>{let e=pe();N.value=!0;try{let t=new URLSearchParams;R.value&&t.set(`model`,R.value),V.value?.length===2&&(t.set(`startDate`,V.value[0]),t.set(`endDate`,V.value[1]));let n=t.toString(),r=await p.get(`/api/usage${n?`?${n}`:``}`);if(!e())return;M.value=r}catch(t){if(!e())return;throw t}finally{e()&&(N.value=!1)}}),me=k(),U=T(async()=>{let e=me();try{await Promise.all([H(),o.loadProviders()])}catch(t){if(!e())return;throw t}finally{e()&&(N.value=!1)}}),he=()=>O(U),W=window.location.hostname,G=Number(window.location.port)||null,K=v(()=>I({protocol:window.location.protocol,hostname:W,port:G})),q=n(null),J=n(null),Y=n(!1),ge=n(!0),_e=n(Date.now()),$e=n(null),et=n([]),tt=v(()=>$e.value??G),nt=e=>I({protocol:`http:`,hostname:e,port:tt.value}),rt=v(()=>W===`127.0.0.1`||W===`::1`||W===`localhost`?`local`:et.value.includes(W)?`lan`:`other`),$=v(()=>tt.value?et.value.map(nt).filter(e=>e!==K.value):[]),it=v(()=>{let e=tt.value?nt(`127.0.0.1`):``;return e!==``&&e!==K.value?e:``}),at=v(()=>{let e=[];return rt.value===`lan`?e.push({label:`局域网地址`,values:[K.value,...$.value]}):(e.push({label:ae[rt.value],values:[K.value]}),$.value.length>0&&e.push({label:`局域网地址`,values:$.value})),it.value!==``&&e.push({label:`本机 API 地址`,values:[it.value]}),e.map((t,n)=>({...t,span2:e.length%2==1&&n===e.length-1}))}),ot=async()=>{let[e,t]=await Promise.allSettled([E.processes(),p.get(`/api/status`)]);if(ge.value=!1,e.status===`fulfilled`&&(q.value=e.value[0]??null),t.status===`rejected`){J.value=null,Y.value=!0;return}let n=t.value?.masterKey;J.value=typeof n==`string`?n:null,Y.value=typeof n!=`string`;let r=t.value?.listenPort;$e.value=typeof r==`number`&&r>0?r:null;let i=t.value?.lanAddresses;et.value=Array.isArray(i)?i.filter(e=>typeof e==`string`):[],_e.value=Date.now()},st=e=>{if(!e.startedAt)return`-`;let t=Math.max(0,Math.floor((_e.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(` `)},ct=v(()=>Y.value?`获取失败,请刷新重试`:J.value===null?`-`:`未设置(/v1 免鉴权)`),lt;return d(()=>{U(),ot(),lt=window.setInterval(ot,1e4)}),e(()=>window.clearInterval(lt)),(e,n)=>{let a=m(`el-button`),o=m(`el-alert`),c=m(`el-card`),d=m(`el-option`),p=m(`el-select`),v=m(`el-date-picker`),y=m(`el-table-column`),x=m(`el-table`),T=m(`el-empty`),E=m(`el-tab-pane`),D=m(`el-tabs`),O=ne(`loading`);return C(),_(D,{modelValue:z.value,"onUpdate:modelValue":n[4]||=e=>z.value=e,class:`dashboard-tabs`},{default:g(()=>[s(E,{label:`概览`,name:`overview`},{default:g(()=>[t(`div`,ye,[i(re)?(C(),_(o,{key:0,title:i(re),type:`error`,"show-icon":``,closable:!1},{default:g(()=>[s(a,{size:`small`,onClick:he},{default:g(()=>[...n[5]||=[r(`重试`,-1)]]),_:1})]),_:1},8,[`title`])):l(``,!0),s(c,{shadow:`never`},{header:g(()=>[...n[6]||=[t(`span`,{class:`fw-600`},`服务信息`,-1)]]),default:g(()=>[te((C(),u(`div`,X,[(C(!0),u(f,null,S(at.value,e=>(C(),u(`div`,{key:e.label+e.values[0],class:ee([`kv-item`,{"kv-span-2":e.span2}])},[t(`div`,Z,b(e.label),1),t(`div`,be,[(C(!0),u(f,null,S(e.values,e=>(C(),u(`div`,{key:e},[t(`span`,{class:`copy-text`,onClick:t=>i(h)(e)},b(e),9,xe)]))),128))])],2))),128)),t(`div`,Se,[n[7]||=t(`div`,{class:`kv-label`},`API 密钥`,-1),t(`div`,Ce,[J.value?(C(),u(`span`,{key:0,class:`copy-text`,onClick:n[0]||=e=>i(h)(J.value)},b(J.value),1)):l(``,!0),J.value?(C(),u(`span`,Q,`(/v1 需 Bearer 认证)`)):(C(),u(f,{key:2},[r(b(ct.value),1)],64))])]),t(`div`,we,[n[10]||=t(`div`,{class:`kv-label`},`运行状态`,-1),t(`div`,Te,[q.value?(C(),u(f,{key:0},[n[8]||=t(`span`,{class:`status-dot running`},null,-1),n[9]||=r(`运行中 `,-1),t(`span`,Ee,`PID `+b(q.value.pid??`-`),1)],64)):(C(),u(f,{key:1},[r(`-`)],64))])]),t(`div`,De,[n[11]||=t(`div`,{class:`kv-label`},`运行时长`,-1),t(`div`,Oe,b(q.value?st(q.value):`-`),1)])])),[[O,N.value||ge.value]])]),_:1}),M.value?(C(),_(c,{key:1,shadow:`never`},{header:g(()=>[t(`div`,ke,[n[13]||=t(`span`,{class:`fw-600`},`用量统计`,-1),t(`div`,Ae,[s(p,{modelValue:R.value,"onUpdate:modelValue":n[1]||=e=>R.value=e,placeholder:`全部模型`,clearable:``,filterable:``,style:{width:`220px`},onChange:i(H)},{default:g(()=>[(C(!0),u(f,null,S(fe.value,e=>(C(),_(d,{key:e,label:e,value:e},null,8,[`label`,`value`]))),128))]),_:1},8,[`modelValue`,`onChange`]),s(p,{modelValue:i(B),"onUpdate:modelValue":n[2]||=e=>w(B)?B.value=e:null,placeholder:`时间范围`,clearable:``,style:{width:`130px`},onChange:i(ue)},{default:g(()=>[s(d,{label:`今天`,value:`today`}),s(d,{label:`昨天`,value:`yesterday`}),s(d,{label:`前天`,value:`beforeYesterday`}),s(d,{label:`近三天`,value:`last3days`}),s(d,{label:`本周`,value:`week`}),s(d,{label:`本月`,value:`month`})]),_:1},8,[`modelValue`,`onChange`]),s(v,{modelValue:i(V),"onUpdate:modelValue":n[3]||=e=>w(V)?V.value=e:null,type:`daterange`,"range-separator":`至`,"start-placeholder":`开始日期`,"end-placeholder":`结束日期`,"value-format":`YYYY-MM-DD`,style:{width:`260px`},onChange:de},null,8,[`modelValue`]),s(a,{loading:N.value,onClick:i(H)},{default:g(()=>[...n[12]||=[r(`刷新`,-1)]]),_:1},8,[`loading`,`onClick`])])])]),default:g(()=>[t(`div`,je,[t(`div`,Me,[t(`div`,Ne,b(i(L)(M.value.total.total_tokens)),1),n[14]||=t(`div`,{class:`usage-label`},`总 Token`,-1)]),t(`div`,Pe,[t(`div`,Fe,b(i(L)(M.value.total.input_tokens)),1),n[15]||=t(`div`,{class:`usage-label`},`输入 Token`,-1)]),t(`div`,Ie,[t(`div`,Le,b(i(L)(M.value.total.output_tokens)),1),n[16]||=t(`div`,{class:`usage-label`},`输出 Token`,-1)]),t(`div`,Re,[t(`div`,ze,b(i(L)(M.value.total.cache_read_tokens)),1),n[17]||=t(`div`,{class:`usage-label`},`缓存读取`,-1)]),t(`div`,Be,[t(`div`,Ve,b(M.value.total.cache_rate==null?`-`:M.value.total.cache_rate+`%`),1),n[18]||=t(`div`,{class:`usage-label`},`缓存命中率`,-1)]),M.value.logStorageMB==null?l(``,!0):(C(),u(`div`,He,[t(`div`,Ue,b(M.value.logStorageMB),1),n[19]||=t(`div`,{class:`usage-label`},`数据目录占用 (MB)`,-1)])),t(`div`,We,[t(`div`,Ge,b(i(j)(M.value.total.avg_duration)),1),n[20]||=t(`div`,{class:`usage-label`},`平均耗时`,-1)]),t(`div`,Ke,[t(`div`,{class:`usage-num blue`,title:i(oe)},b(i(j)(M.value.total.avg_ttft)),9,qe),n[21]||=t(`div`,{class:`usage-label`},`平均首 Token`,-1)]),t(`div`,Je,[t(`div`,{class:`usage-num green`,title:i(F)},b(i(P)(M.value.total.tps)),9,Ye),n[22]||=t(`div`,{class:`usage-label`},`平均生成速度`,-1)])]),M.value.models?.length?(C(),u(`div`,Xe,[n[23]||=t(`div`,{class:`section-title`},`模型用量`,-1),s(x,{data:M.value.models,border:``,class:`full-width`},{default:g(()=>[s(y,{prop:`model`,label:`模型`,"min-width":`200`},{default:g(({row:e})=>[t(`span`,{class:`copy-text`,onClick:t=>i(h)(e.model)},b(e.model),9,Ze)]),_:1}),s(y,{label:`调用次数`,width:`90`,align:`center`},{default:g(({row:e})=>[r(b(e.calls),1)]),_:1}),s(y,{label:`平均耗时`,width:`110`,align:`center`},{default:g(({row:e})=>[r(b(i(j)(e.avg_duration)),1)]),_:1}),s(y,{label:`速度`,width:`140`,align:`center`},{default:g(({row:e})=>[t(`div`,{title:i(se)},b(i(ce)(e.tps,e.avg_ttft)),9,Qe)]),_:1}),s(y,{label:`总 Token`,width:`140`,align:`center`},{default:g(({row:e})=>[r(b(i(L)(e.total_tokens)),1)]),_:1}),s(y,{label:`输入 Token`,width:`140`,align:`center`},{default:g(({row:e})=>[r(b(i(L)(e.input_tokens)),1)]),_:1}),s(y,{label:`输出 Token`,width:`140`,align:`center`},{default:g(({row:e})=>[r(b(i(L)(e.output_tokens)),1)]),_:1}),s(y,{label:`缓存读取`,width:`130`,align:`center`},{default:g(({row:e})=>[r(b(i(L)(e.cache_read_tokens)),1)]),_:1}),s(y,{label:`缓存命中率`,width:`110`,align:`center`},{default:g(({row:e})=>[r(b(e.cache_rate==null?`-`:e.cache_rate+`%`),1)]),_:1})]),_:1},8,[`data`])])):(C(),_(T,{key:1,description:`暂无调用记录`,"image-size":60}))]),_:1})):l(``,!0)])]),_:1}),s(E,{label:`服务状态`,name:`status`,lazy:``,"destroy-on-close":``},{default:g(()=>[s(ve)]),_:1})]),_:1},8,[`modelValue`])}}}),[[`__scopeId`,`data-v-bab222f3`]]);export{$e as default};
|
|
1
|
+
import{$ as e,A as t,Et as n,F as r,Ft as i,Gt as a,H as o,I as s,L as c,M as l,N as u,Q as d,T as f,a as p,at as m,cn as ee,d as h,gt as te,ht as g,j as _,k as v,l as y,ot as ne,pn as b,pt as x,rt as S,tt as C,un as re,xt as w,yt as T}from"./router-DOdUMO6P.js";import{t as E}from"./useManagerApi-jm_MgzHV.js";import{t as D}from"./providers-Dx3XtxJu.js";import{n as O,t as ie}from"./useCopyToast-Dkb8g4uG.js";import{t as ae}from"./useToast-BxrPRTvE.js";import{n as k,t as A}from"./useQuickRangeFilter-CC-fmdix.js";import{d as j,f as M,g as N,m as P,n as F,o as I,p as L,r as oe,t as se,w as ce,y as R}from"./format-Deb1hfjO.js";T();function le(e){let{loadError:t,run:r}=O(e),i=n(null);function a(e){let t=async()=>{let n=await r(e);return n?i.value===t&&(i.value=null):i.value=t,n};return t}function o(e){r(i.value??e)}return{loadError:t,track:a,retry:o}}o(),T(),a();var z={class:`service-status-panel`},B={class:`flex-between`},V={class:`flex-gap-8`},ue={class:`flex-gap-8`},de={class:`gantt-wrap`},fe={key:0,class:`gantt`},pe={class:`gantt-row gantt-head`},H={class:`col-cells`},me=[`title`],U={class:`cell-head-date`},he={class:`col-name`},W=[`title`,`onClick`],G=[`title`],K={class:`col-cells`},q=[`title`],J={key:1,class:`gantt-empty`},Y=36e5,ge=24,_e=`#909399`,ve=h(c({__name:`ServiceStatusPanel`,setup(a){let{toast:o}=ae(),{copyWithToast:c}=ie(),{loadError:h,run:y}=O(`延迟数据加载失败,请重试`),x=n([]),w=n(!0),T=n(!1),E=n(null),D=n(!1),k=n(!1),A,j,P=n(I()),F=n(new Map);function I(){let e=new Date,t=new Date(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours()).getTime();return Array.from({length:ge},(e,n)=>t-(23-n)*Y)}let L=e=>{let t=new Date(e);return Number.isNaN(t.getTime())?`-`:`${t.getFullYear()}-${R(t.getMonth()+1)}-${R(t.getDate())} ${R(t.getHours())}:00`},oe=v(()=>P.value.map(e=>{let t=new Date(e),n=R(t.getHours());return{start:e,dateLabel:`${R(t.getMonth()+1)}-${R(t.getDate())}`,hourLabel:n,fullLabel:`${L(e)} - ${n}:59`}})),se=[103,194,58],ce=[230,162,60],le=[245,108,108],ve=v(()=>{let e=[];for(let t of F.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}}),ye=e=>{let{min:t,max:n}=ve.value,r=n===t?0:(e-t)/(n-t),[i,a]=r<=.5?[se,ce]:[ce,le],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)`},X=(e,t)=>{let n=`${L(t)} - ${R(new Date(t+Y).getHours())}:00`;return e===void 0||e.total===0?`${n}\n无探测数据`:`${n}\n平均延迟 ${M(e.avgLatencyMs)}\n成功 ${String(e.success)} / 失败 ${String(e.failed)}`},Z=v(()=>xe.value.map(e=>{let t=F.value.get(e.model),n=P.value.map(e=>{let n=t?.get(e);return n!==void 0&&n.failed>0?{start:e,className:`cell--down`,style:{backgroundColor:_e},title:X(n,e)}:n===void 0||n.avgLatencyMs===null?{start:e,className:`cell--empty`,style:{},title:X(n,e)}:{start:e,className:``,style:{backgroundColor:ye(n.avgLatencyMs)},title:X(n,e)}});return{model:e.model,avg24h:e.avg24h,statusTitle:[e.avg24h===null?`最近 24 小时无成功探测记录`:`最近 24 小时成功探测平均延迟 ${M(e.avg24h)}`,e.lastLatencyMs==null?`最近一次探测:无成功延迟记录`:`最近一次探测延迟 ${M(e.lastLatencyMs)}`].join(`
|
|
2
|
+
`),cells:n}})),be=(e,t)=>e===null&&t===null?0:e===null?1:t===null?-1:e-t,xe=v(()=>[...x.value].sort((e,t)=>{let n=e.lastOk===!1;if(n!==(t.lastOk===!1))return n?1:-1;let r=be(e.avg24h,t.avg24h);return r===0?e.model.localeCompare(t.model):r})),Se=async e=>{if(e.length===0){F.value=new Map;return}let t=await Promise.all(e.map(async e=>{try{let t=await p.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]}}));F.value=new Map(t)},Ce=async()=>{let e=await p.get(`/api/latency/history`);return x.value=e.models??[],T.value=e.running,E.value=e.lastRunAt,e},Q=()=>y(async()=>{try{await Ce(),P.value=I(),await Se(x.value.map(e=>e.model))}finally{w.value=!1}}),we=()=>Q(),Te=()=>{k.value?A=window.setInterval(()=>void Q(),5e3):A!==void 0&&(window.clearInterval(A),A=void 0)},Ee=async()=>{D.value=!0;try{await p.post(`/api/latency/run`)}catch(e){o(e.message,`error`),D.value=!1;return}j=window.setInterval(async()=>{try{(await Ce()).running||(window.clearInterval(j),j=void 0,D.value=!1,P.value=I(),await Se(x.value.map(e=>e.model)))}catch{}},2e3)};return d(()=>{Q()}),e(()=>{A!==void 0&&window.clearInterval(A),j!==void 0&&window.clearInterval(j)}),(e,n)=>{let a=m(`el-button`),o=m(`el-alert`),d=m(`el-tag`),p=m(`el-checkbox`),v=m(`el-empty`),y=m(`el-card`),x=ne(`loading`);return C(),u(`div`,z,[i(h)?(C(),_(o,{key:0,title:i(h),type:`error`,"show-icon":``,closable:!1,class:`mb-16`},{default:g(()=>[s(a,{size:`small`,onClick:we},{default:g(()=>[...n[1]||=[r(`重试`,-1)]]),_:1})]),_:1},8,[`title`])):l(``,!0),s(y,{shadow:`never`,class:`service-status-card`},{header:g(()=>[t(`div`,B,[t(`div`,V,[n[3]||=t(`span`,{class:`fw-600`},`服务状态`,-1),T.value?(C(),_(d,{key:0,type:`warning`,size:`small`},{default:g(()=>[...n[2]||=[r(`测试进行中`,-1)]]),_:1})):E.value?(C(),_(d,{key:1,type:`info`,size:`small`},{default:g(()=>[r(` 上次测试 `+b(i(N)(E.value)),1)]),_:1})):l(``,!0)]),t(`div`,ue,[s(p,{modelValue:k.value,"onUpdate:modelValue":n[0]||=e=>k.value=e,onChange:Te},{default:g(()=>[...n[4]||=[r(` 自动刷新(5s) `,-1)]]),_:1},8,[`modelValue`]),s(a,{loading:D.value,onClick:Ee},{default:g(()=>[...n[5]||=[r(` 延迟测试 `,-1)]]),_:1},8,[`loading`])])])]),default:g(()=>[n[9]||=t(`div`,{class:`legend`},[t(`span`,{class:`legend-text`},`延迟`),t(`span`,{class:`legend-text`},`低`),t(`span`,{class:`legend-gradient`}),t(`span`,{class:`legend-text`},`高`),t(`span`,{class:`legend-swatch legend-swatch--down`}),t(`span`,{class:`legend-text`},`该小时有失败探测`),t(`span`,{class:`legend-swatch legend-swatch--empty`}),t(`span`,{class:`legend-text`},`无探测数据`)],-1),te((C(),u(`div`,de,[n[8]||=t(`div`,{class:`muted-sm hint`},` 右侧 24 格为最近 24 小时(每格 1 小时,本地整点对齐,最右格为当前小时)。 格子底色为当小时成功探测的平均延迟,全表统一色标(本期最快→最慢 绿→红); 当小时存在失败探测即视为不可用,显示灰色。 行按 24h 平均延迟升序,最近一次探测失败的模型沉底。 `,-1),Z.value.length>0?(C(),u(`div`,fe,[t(`div`,pe,[n[6]||=t(`div`,{class:`col-name`},`模型名称`,-1),n[7]||=t(`div`,{class:`col-status`},`状态`,-1),t(`div`,H,[(C(!0),u(f,null,S(oe.value,e=>(C(),u(`div`,{key:e.start,class:`cell cell--head`,title:e.fullLabel},[t(`span`,U,b(e.dateLabel),1),t(`span`,null,b(e.hourLabel),1)],8,me))),128))])]),(C(!0),u(f,null,S(Z.value,e=>(C(),u(`div`,{key:e.model,class:`gantt-row`},[t(`div`,he,[t(`span`,{class:`copy-text model-name`,title:e.model,onClick:t=>i(c)(e.model)},b(e.model),9,W)]),t(`div`,{class:`col-status`,title:e.statusTitle},b(i(M)(e.avg24h)),9,G),t(`div`,K,[(C(!0),u(f,null,S(e.cells,e=>(C(),u(`div`,{key:e.start,class:ee([`cell`,e.className]),style:re(e.style),title:e.title},null,14,q))),128))])]))),128))])):(C(),u(`div`,J,[s(v,{description:`暂无延迟数据,点击「延迟测试」开始`,"image-size":80})]))])),[[x,w.value]])]),_:1})])}}}),[[`__scopeId`,`data-v-0f99bcf1`]]);o(),T(),a();var ye={class:`flex-col-gap`},X={class:`kv-grid`},Z={class:`kv-label`},be={class:`kv-value`},xe=[`onClick`],Se={class:`kv-item kv-span-2`},Ce={class:`kv-value`},Q={key:1,class:`kv-unit`},we={class:`kv-item`},Te={class:`kv-value`},Ee={class:`kv-unit`},De={class:`kv-item`},Oe={class:`kv-value`},ke={class:`flex-between card-header-wrap`},Ae={class:`flex-gap-8`},je={class:`usage-grid`},Me={class:`usage-cell`},Ne={class:`usage-num orange`},Pe={class:`usage-cell`},Fe={class:`usage-num blue`},Ie={class:`usage-cell`},Le={class:`usage-num green`},Re={class:`usage-cell`},ze={class:`usage-num purple`},Be={class:`usage-cell`},Ve={class:`usage-num purple`},He={key:0,class:`usage-cell`},Ue={class:`usage-num gray`},We={class:`usage-cell`},Ge={class:`usage-num blue`},Ke={class:`usage-cell`},qe=[`title`],Je={class:`usage-cell`},Ye=[`title`],Xe={key:0},Ze=[`onClick`],Qe=[`title`],$e=h(c({__name:`DashboardView`,setup(a){let o=D(),c=y(),{copyWithToast:h}=ie(),{loadError:re,track:T,retry:O}=le(),ae={local:`本机 API 地址`,lan:`局域网地址`,other:`API 地址`},M=n(null),N=n(!0),R=n(``),z=n(c.query.tab===`status`?`status`:`overview`);x(()=>c.query.tab,e=>{e===`status`&&(z.value=`status`)});let{rangeKey:B,dateRange:V,onRangeChange:ue}=A(()=>H(),`today`),de=()=>{B.value=``,H()},fe=v(()=>{let e=new Set;for(let t of o.suppliers)for(let n of t.models)e.add(n.modelName);if(M.value?.models)for(let t of M.value.models)e.add(t.model);return[...e].sort()}),pe=k(),H=T(async()=>{let e=pe();N.value=!0;try{let t=new URLSearchParams;R.value&&t.set(`model`,R.value),V.value?.length===2&&(t.set(`startDate`,V.value[0]),t.set(`endDate`,V.value[1]));let n=t.toString(),r=await p.get(`/api/usage${n?`?${n}`:``}`);if(!e())return;M.value=r}catch(t){if(!e())return;throw t}finally{e()&&(N.value=!1)}}),me=k(),U=T(async()=>{let e=me();try{await Promise.all([H(),o.loadProviders()])}catch(t){if(!e())return;throw t}finally{e()&&(N.value=!1)}}),he=()=>O(U),W=window.location.hostname,G=Number(window.location.port)||null,K=v(()=>I({protocol:window.location.protocol,hostname:W,port:G})),q=n(null),J=n(null),Y=n(!1),ge=n(!0),_e=n(Date.now()),$e=n(null),et=n([]),$=v(()=>$e.value??G),tt=e=>I({protocol:`http:`,hostname:e,port:$.value}),nt=v(()=>W===`127.0.0.1`||W===`::1`||W===`localhost`?`local`:et.value.includes(W)?`lan`:`other`),rt=v(()=>$.value?et.value.map(tt).filter(e=>e!==K.value):[]),it=v(()=>{let e=$.value?tt(`127.0.0.1`):``;return e!==``&&e!==K.value?e:``}),at=v(()=>{let e=[];if(nt.value===`lan`)e.push({label:`局域网地址`,values:[K.value]});else{e.push({label:ae[nt.value],values:[K.value]});let t=rt.value[0];t!==void 0&&e.push({label:`局域网地址`,values:[t]})}return it.value!==``&&e.push({label:`本机 API 地址`,values:[it.value]}),e.map((t,n)=>({...t,span2:e.length%2==1&&n===e.length-1}))}),ot=async()=>{let[e,t]=await Promise.allSettled([E.processes(),p.get(`/api/status`)]);if(ge.value=!1,e.status===`fulfilled`&&(q.value=e.value[0]??null),t.status===`rejected`){J.value=null,Y.value=!0;return}let n=t.value?.masterKey;J.value=typeof n==`string`?n:null,Y.value=typeof n!=`string`;let r=t.value?.listenPort;$e.value=typeof r==`number`&&r>0?r:null;let i=t.value?.lanAddresses;et.value=Array.isArray(i)?i.filter(e=>typeof e==`string`):[],_e.value=Date.now()},st=e=>{if(!e.startedAt)return`-`;let t=Math.max(0,Math.floor((_e.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(` `)},ct=v(()=>Y.value?`获取失败,请刷新重试`:J.value===null?`-`:`未设置(/v1 免鉴权)`),lt;return d(()=>{U(),ot(),lt=window.setInterval(ot,1e4)}),e(()=>window.clearInterval(lt)),(e,n)=>{let a=m(`el-button`),o=m(`el-alert`),c=m(`el-card`),d=m(`el-option`),p=m(`el-select`),v=m(`el-date-picker`),y=m(`el-table-column`),x=m(`el-table`),T=m(`el-empty`),E=m(`el-tab-pane`),D=m(`el-tabs`),O=ne(`loading`);return C(),_(D,{modelValue:z.value,"onUpdate:modelValue":n[4]||=e=>z.value=e,class:`dashboard-tabs`},{default:g(()=>[s(E,{label:`概览`,name:`overview`},{default:g(()=>[t(`div`,ye,[i(re)?(C(),_(o,{key:0,title:i(re),type:`error`,"show-icon":``,closable:!1},{default:g(()=>[s(a,{size:`small`,onClick:he},{default:g(()=>[...n[5]||=[r(`重试`,-1)]]),_:1})]),_:1},8,[`title`])):l(``,!0),s(c,{shadow:`never`},{header:g(()=>[...n[6]||=[t(`span`,{class:`fw-600`},`服务信息`,-1)]]),default:g(()=>[te((C(),u(`div`,X,[(C(!0),u(f,null,S(at.value,e=>(C(),u(`div`,{key:e.label+e.values[0],class:ee([`kv-item`,{"kv-span-2":e.span2}])},[t(`div`,Z,b(e.label),1),t(`div`,be,[(C(!0),u(f,null,S(e.values,e=>(C(),u(`div`,{key:e},[t(`span`,{class:`copy-text`,onClick:t=>i(h)(e)},b(e),9,xe)]))),128))])],2))),128)),t(`div`,Se,[n[7]||=t(`div`,{class:`kv-label`},`API 密钥`,-1),t(`div`,Ce,[J.value?(C(),u(`span`,{key:0,class:`copy-text`,onClick:n[0]||=e=>i(h)(J.value)},b(J.value),1)):l(``,!0),J.value?(C(),u(`span`,Q,`(/v1 需 Bearer 认证)`)):(C(),u(f,{key:2},[r(b(ct.value),1)],64))])]),t(`div`,we,[n[10]||=t(`div`,{class:`kv-label`},`运行状态`,-1),t(`div`,Te,[q.value?(C(),u(f,{key:0},[n[8]||=t(`span`,{class:`status-dot running`},null,-1),n[9]||=r(`运行中 `,-1),t(`span`,Ee,`PID `+b(q.value.pid??`-`),1)],64)):(C(),u(f,{key:1},[r(`-`)],64))])]),t(`div`,De,[n[11]||=t(`div`,{class:`kv-label`},`运行时长`,-1),t(`div`,Oe,b(q.value?st(q.value):`-`),1)])])),[[O,N.value||ge.value]])]),_:1}),M.value?(C(),_(c,{key:1,shadow:`never`},{header:g(()=>[t(`div`,ke,[n[13]||=t(`span`,{class:`fw-600`},`用量统计`,-1),t(`div`,Ae,[s(p,{modelValue:R.value,"onUpdate:modelValue":n[1]||=e=>R.value=e,placeholder:`全部模型`,clearable:``,filterable:``,style:{width:`220px`},onChange:i(H)},{default:g(()=>[(C(!0),u(f,null,S(fe.value,e=>(C(),_(d,{key:e,label:e,value:e},null,8,[`label`,`value`]))),128))]),_:1},8,[`modelValue`,`onChange`]),s(p,{modelValue:i(B),"onUpdate:modelValue":n[2]||=e=>w(B)?B.value=e:null,placeholder:`时间范围`,clearable:``,style:{width:`130px`},onChange:i(ue)},{default:g(()=>[s(d,{label:`今天`,value:`today`}),s(d,{label:`昨天`,value:`yesterday`}),s(d,{label:`前天`,value:`beforeYesterday`}),s(d,{label:`近三天`,value:`last3days`}),s(d,{label:`本周`,value:`week`}),s(d,{label:`本月`,value:`month`})]),_:1},8,[`modelValue`,`onChange`]),s(v,{modelValue:i(V),"onUpdate:modelValue":n[3]||=e=>w(V)?V.value=e:null,type:`daterange`,"range-separator":`至`,"start-placeholder":`开始日期`,"end-placeholder":`结束日期`,"value-format":`YYYY-MM-DD`,style:{width:`260px`},onChange:de},null,8,[`modelValue`]),s(a,{loading:N.value,onClick:i(H)},{default:g(()=>[...n[12]||=[r(`刷新`,-1)]]),_:1},8,[`loading`,`onClick`])])])]),default:g(()=>[t(`div`,je,[t(`div`,Me,[t(`div`,Ne,b(i(L)(M.value.total.total_tokens)),1),n[14]||=t(`div`,{class:`usage-label`},`总 Token`,-1)]),t(`div`,Pe,[t(`div`,Fe,b(i(L)(M.value.total.input_tokens)),1),n[15]||=t(`div`,{class:`usage-label`},`输入 Token`,-1)]),t(`div`,Ie,[t(`div`,Le,b(i(L)(M.value.total.output_tokens)),1),n[16]||=t(`div`,{class:`usage-label`},`输出 Token`,-1)]),t(`div`,Re,[t(`div`,ze,b(i(L)(M.value.total.cache_read_tokens)),1),n[17]||=t(`div`,{class:`usage-label`},`缓存读取`,-1)]),t(`div`,Be,[t(`div`,Ve,b(M.value.total.cache_rate==null?`-`:M.value.total.cache_rate+`%`),1),n[18]||=t(`div`,{class:`usage-label`},`缓存命中率`,-1)]),M.value.logStorageMB==null?l(``,!0):(C(),u(`div`,He,[t(`div`,Ue,b(M.value.logStorageMB),1),n[19]||=t(`div`,{class:`usage-label`},`数据目录占用 (MB)`,-1)])),t(`div`,We,[t(`div`,Ge,b(i(j)(M.value.total.avg_duration)),1),n[20]||=t(`div`,{class:`usage-label`},`平均耗时`,-1)]),t(`div`,Ke,[t(`div`,{class:`usage-num blue`,title:i(oe)},b(i(j)(M.value.total.avg_ttft)),9,qe),n[21]||=t(`div`,{class:`usage-label`},`平均首 Token`,-1)]),t(`div`,Je,[t(`div`,{class:`usage-num green`,title:i(F)},b(i(P)(M.value.total.tps)),9,Ye),n[22]||=t(`div`,{class:`usage-label`},`平均生成速度`,-1)])]),M.value.models?.length?(C(),u(`div`,Xe,[n[23]||=t(`div`,{class:`section-title`},`模型用量`,-1),s(x,{data:M.value.models,border:``,class:`full-width`},{default:g(()=>[s(y,{prop:`model`,label:`模型`,"min-width":`200`},{default:g(({row:e})=>[t(`span`,{class:`copy-text`,onClick:t=>i(h)(e.model)},b(e.model),9,Ze)]),_:1}),s(y,{label:`调用次数`,width:`90`,align:`center`},{default:g(({row:e})=>[r(b(e.calls),1)]),_:1}),s(y,{label:`平均耗时`,width:`110`,align:`center`},{default:g(({row:e})=>[r(b(i(j)(e.avg_duration)),1)]),_:1}),s(y,{label:`速度`,width:`140`,align:`center`},{default:g(({row:e})=>[t(`div`,{title:i(se)},b(i(ce)(e.tps,e.avg_ttft)),9,Qe)]),_:1}),s(y,{label:`总 Token`,width:`140`,align:`center`},{default:g(({row:e})=>[r(b(i(L)(e.total_tokens)),1)]),_:1}),s(y,{label:`输入 Token`,width:`140`,align:`center`},{default:g(({row:e})=>[r(b(i(L)(e.input_tokens)),1)]),_:1}),s(y,{label:`输出 Token`,width:`140`,align:`center`},{default:g(({row:e})=>[r(b(i(L)(e.output_tokens)),1)]),_:1}),s(y,{label:`缓存读取`,width:`130`,align:`center`},{default:g(({row:e})=>[r(b(i(L)(e.cache_read_tokens)),1)]),_:1}),s(y,{label:`缓存命中率`,width:`110`,align:`center`},{default:g(({row:e})=>[r(b(e.cache_rate==null?`-`:e.cache_rate+`%`),1)]),_:1})]),_:1},8,[`data`])])):(C(),_(T,{key:1,description:`暂无调用记录`,"image-size":60}))]),_:1})):l(``,!0)])]),_:1}),s(E,{label:`服务状态`,name:`status`,lazy:``,"destroy-on-close":``},{default:g(()=>[s(ve)]),_:1})]),_:1},8,[`modelValue`])}}}),[[`__scopeId`,`data-v-a3c167a0`]]);export{$e as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.service-status-panel[data-v-0f99bcf1]{min-width:0}.service-status-card[data-v-0f99bcf1] .el-card__body{padding-top:12px}.legend[data-v-0f99bcf1]{color:#606266;flex-shrink:0;align-items:center;gap:6px;margin-bottom:8px;font-size:12px;display:flex}.legend-gradient[data-v-0f99bcf1]{background:linear-gradient(90deg,#67c23a,#e6a23c,#f56c6c);border-radius:2px;width:96px;height:10px}.legend-swatch[data-v-0f99bcf1]{border-radius:2px;width:14px;height:10px;margin-left:10px}.legend-swatch--down[data-v-0f99bcf1]{background-color:#909399}.legend-swatch--empty[data-v-0f99bcf1]{background-color:#f2f3f5;border:1px solid #ebeef5}.hint[data-v-0f99bcf1]{flex-shrink:0;margin-bottom:12px}.gantt-wrap[data-v-0f99bcf1]{min-width:0}.gantt[data-v-0f99bcf1]{max-height:420px;overflow:hidden auto}.gantt-row[data-v-0f99bcf1]{border-bottom:1px solid #f2f6fc;align-items:center;height:32px;display:flex}.gantt-row[data-v-0f99bcf1]:hover{background-color:#fafcff}.gantt-head[data-v-0f99bcf1]{z-index:1;color:#909399;background-color:#fff;border-bottom:1px solid #ebeef5;height:auto;min-height:34px;padding:2px 0;font-size:12px;font-weight:600;position:sticky;top:0}.col-name[data-v-0f99bcf1]{flex:0 0 240px;width:240px;padding-right:12px;font-size:13px}.col-status[data-v-0f99bcf1]{color:#606266;flex:0 0 100px;width:100px;padding-right:12px;font-size:13px}.col-cells[data-v-0f99bcf1]{flex:1;min-width:0;display:flex}.cell[data-v-0f99bcf1]{flex:1 1 0;min-width:0;height:20px;box-shadow:inset -1px 0 #fff}.cell[data-v-0f99bcf1]:last-child{box-shadow:none}.cell--head[data-v-0f99bcf1]{white-space:nowrap;flex-direction:column;align-items:center;height:auto;font-size:10px;font-weight:400;line-height:1.15;display:flex;overflow:hidden}.cell-head-date[data-v-0f99bcf1]{color:#c0c4cc;font-size:9px}.cell--empty[data-v-0f99bcf1]{background-color:#f2f3f5}.gantt-empty[data-v-0f99bcf1]{color:#909399;justify-content:center;align-items:center;min-height:160px;font-size:13px;display:flex}.model-name[data-v-0f99bcf1]{white-space:nowrap;text-overflow:ellipsis;display:block;overflow:hidden}.dashboard-tabs[data-v-
|
|
1
|
+
.service-status-panel[data-v-0f99bcf1]{min-width:0}.service-status-card[data-v-0f99bcf1] .el-card__body{padding-top:12px}.legend[data-v-0f99bcf1]{color:#606266;flex-shrink:0;align-items:center;gap:6px;margin-bottom:8px;font-size:12px;display:flex}.legend-gradient[data-v-0f99bcf1]{background:linear-gradient(90deg,#67c23a,#e6a23c,#f56c6c);border-radius:2px;width:96px;height:10px}.legend-swatch[data-v-0f99bcf1]{border-radius:2px;width:14px;height:10px;margin-left:10px}.legend-swatch--down[data-v-0f99bcf1]{background-color:#909399}.legend-swatch--empty[data-v-0f99bcf1]{background-color:#f2f3f5;border:1px solid #ebeef5}.hint[data-v-0f99bcf1]{flex-shrink:0;margin-bottom:12px}.gantt-wrap[data-v-0f99bcf1]{min-width:0}.gantt[data-v-0f99bcf1]{max-height:420px;overflow:hidden auto}.gantt-row[data-v-0f99bcf1]{border-bottom:1px solid #f2f6fc;align-items:center;height:32px;display:flex}.gantt-row[data-v-0f99bcf1]:hover{background-color:#fafcff}.gantt-head[data-v-0f99bcf1]{z-index:1;color:#909399;background-color:#fff;border-bottom:1px solid #ebeef5;height:auto;min-height:34px;padding:2px 0;font-size:12px;font-weight:600;position:sticky;top:0}.col-name[data-v-0f99bcf1]{flex:0 0 240px;width:240px;padding-right:12px;font-size:13px}.col-status[data-v-0f99bcf1]{color:#606266;flex:0 0 100px;width:100px;padding-right:12px;font-size:13px}.col-cells[data-v-0f99bcf1]{flex:1;min-width:0;display:flex}.cell[data-v-0f99bcf1]{flex:1 1 0;min-width:0;height:20px;box-shadow:inset -1px 0 #fff}.cell[data-v-0f99bcf1]:last-child{box-shadow:none}.cell--head[data-v-0f99bcf1]{white-space:nowrap;flex-direction:column;align-items:center;height:auto;font-size:10px;font-weight:400;line-height:1.15;display:flex;overflow:hidden}.cell-head-date[data-v-0f99bcf1]{color:#c0c4cc;font-size:9px}.cell--empty[data-v-0f99bcf1]{background-color:#f2f3f5}.gantt-empty[data-v-0f99bcf1]{color:#909399;justify-content:center;align-items:center;min-height:160px;font-size:13px;display:flex}.model-name[data-v-0f99bcf1]{white-space:nowrap;text-overflow:ellipsis;display:block;overflow:hidden}.dashboard-tabs[data-v-a3c167a0] .el-tabs__header{margin-bottom:16px}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{$ as e,A as t,Et as n,F as r,Ft as i,Gt as a,H as o,I as s,L as c,M as l,N as u,Q as d,T as f,at as p,d as m,gt as h,ht as g,i as _,j as v,k as y,l as b,n as x,o as S,ot as C,pn as w,tt as T,u as E,ut as D,yt as O}from"./router-DOdUMO6P.js";import{m as k}from"./message-7_77xsCe.js";import{t as A}from"./index-Bpt0yCG7.js";import{n as j,t as M}from"./useManagerApi-jm_MgzHV.js";import{t as N}from"./config-CVy3DdQo.js";import{t as P}from"./useToast-BxrPRTvE.js";import{t as F}from"./navVisibility-CPbwxq3d.js";function I(e){return`更新失败:${e}(更新未生效,服务仍在旧版本运行)`}o(),a(),O();var L={class:`check-body`},R={class:`version-summary`},z={class:`version-item`},B={class:`version-value`},V={class:`version-item version-item--latest`},H={class:`version-value`},U={class:`meta-row`},W={key:0,class:`meta-row meta-row--stack`},ee={key:0,class:`meta-warn`},G={key:1},K={class:`npm-line`},q=`https://www.npmjs.com/package/ezllm`,J=m(c({__name:`UpdateCheckDialog`,props:{modelValue:{type:Boolean,default:!1},modelModifiers:{}},emits:[`update:modelValue`],setup(e){let{toast:i}=P(),a=D(e,`modelValue`),o=n(!1),c=n(!1),d=n(null),m=n(null),b=y(()=>_.value?.buildSource===`local`),x=n(null),S=n(null),E=n(!1),O=()=>window.location.reload(),k=null,N=()=>k?.abort(),F=e=>new Date(e).toLocaleString(),J=y(()=>{let e=d.value?.lastApply;if(!e)return null;let t=e.appliedAt?F(e.appliedAt):``,n=`${e.fromVersion} → ${e.toVersion}${t?`(${t})`:``}`;return e.error?`${n}:${e.error}`:n}),Y=y(()=>{let e=d.value;return e?.updating?e.pendingUpdate?`更新执行中:目标 ${e.pendingUpdate}`:`更新执行中`:null}),X=e=>`https://www.npmjs.com/package/ezllm/v/${e}`,Z=async()=>{m.value=null,x.value=null,S.value=null,E.value=!1,o.value=!0;try{let e=await M.update();if(d.value=e,!e.supported)return;m.value=await M.checkUpdate()}catch(e){x.value=e.message||`检查更新失败`}finally{o.value=!1}},Q=async()=>{if(!m.value)return;let e=m.value.latestVersion;try{await A.confirm(`确定更新到 ${e}?服务会自动重启并在启动时安装新版本:重启期间管理台短暂不可访问(预计 1~3 分钟),完成后自动恢复。`,`立即更新`,{confirmButtonText:`立即更新`,cancelButtonText:`取消`,type:`warning`})}catch{return}c.value=!0,E.value=!1;let t=new AbortController;k=t;try{let e=await M.update(),n=await M.applyUpdate();if(!n.updated){S.value=`已是最新版本 ${n.fromVersion}`,m.value={hasUpdate:!1,currentVersion:n.fromVersion,latestVersion:n.fromVersion,checkedAt:Date.now()};return}S.value=`正在重启服务并安装 ${n.toVersion}(预计 1~3 分钟):重启期间管理台短暂不可访问,完成后这里会自动显示结果。`;let r=await j({targetVersion:n.toVersion,sinceAppliedAt:e.lastApply?.appliedAt??null,signal:t.signal});if(t.signal.aborted)return;r&&!r.error?(i(`已更新到 ${r.toVersion}`,`success`),S.value=`已更新 ${r.fromVersion} → ${r.toVersion},页面即将自动刷新…`,m.value={hasUpdate:!1,currentVersion:r.toVersion,latestVersion:r.toVersion,checkedAt:Date.now()},window.setTimeout(()=>window.location.reload(),1500)):r?.error?(i(`更新失败:${r.error}`,`error`),S.value=I(r.error)):(S.value=`更新仍在进行(安装耗时较长):可稍后刷新页面查看最新状态。`,E.value=!0)}catch(e){i(e.message||`更新失败`,`error`)}finally{if(c.value=!1,k===t&&(k=null),!t.signal.aborted)try{d.value=await M.update()}catch{}}};return(e,n)=>{let i=p(`el-alert`),_=p(`el-tag`),y=p(`el-link`),D=p(`el-button`),k=p(`el-dialog`),A=C(`loading`);return T(),v(k,{modelValue:a.value,"onUpdate:modelValue":n[1]||=e=>a.value=e,title:`检查更新`,width:`480px`,"close-on-click-modal":!c.value,onOpen:Z,onClose:N},{footer:g(()=>[s(D,{onClick:n[0]||=e=>a.value=!1},{default:g(()=>[...n[13]||=[r(`关闭`,-1)]]),_:1}),m.value?.hasUpdate?(T(),v(D,{key:0,type:`primary`,loading:c.value,onClick:Q},{default:g(()=>[r(w(c.value?`更新中...`:`立即更新`),1)]),_:1},8,[`loading`])):l(``,!0)]),default:g(()=>[h((T(),u(`div`,L,[d.value&&!d.value.supported?(T(),v(i,{key:0,title:`当前为源码运行模式,更新功能不可用`,type:`info`,"show-icon":``,closable:!1},{default:g(()=>[...n[2]||=[t(`div`,{class:`alert-hint`},[r(` 仅通过 npx ezllm install 装配的实例支持更新检查。本地开发用仓库里的 `),t(`code`,null,`pnpm upgrade:local`),r(` 更新运行中的服务。 `)],-1)]]),_:1})):m.value?(T(),u(f,{key:1},[t(`div`,R,[t(`div`,z,[n[4]||=t(`span`,{class:`version-label`},`当前版本`,-1),t(`span`,B,w(m.value.currentVersion),1),b.value?(T(),v(_,{key:0,type:`warning`,size:`small`,"disable-transitions":``},{default:g(()=>[...n[3]||=[r(`本地构建`,-1)]]),_:1})):l(``,!0)]),n[6]||=t(`div`,{class:`version-divider`},null,-1),t(`div`,V,[n[5]||=t(`span`,{class:`version-label`},`最新版本`,-1),t(`span`,H,w(m.value.latestVersion),1),s(_,{type:m.value.hasUpdate?`warning`:`success`,size:`small`,"disable-transitions":``},{default:g(()=>[r(w(m.value.hasUpdate?`可更新`:`已是最新`),1)]),_:1},8,[`type`])])]),s(i,{title:m.value.hasUpdate?`发现新版本 ${m.value.latestVersion}(当前 ${m.value.currentVersion})`:`已是最新版本 ${m.value.currentVersion}`,type:m.value.hasUpdate?`warning`:`success`,"show-icon":``,closable:!1},null,8,[`title`,`type`]),t(`div`,U,[t(`span`,null,`检查时间:`+w(F(m.value.checkedAt)),1),m.value.hasUpdate?(T(),v(y,{key:0,type:`primary`,href:X(m.value.latestVersion),target:`_blank`},{default:g(()=>[...n[7]||=[r(`在 npm 查看该版本`,-1)]]),_:1},8,[`href`])):l(``,!0)]),Y.value||J.value?(T(),u(`div`,W,[Y.value?(T(),u(`span`,ee,w(Y.value),1)):l(``,!0),J.value?(T(),u(`span`,G,`上次更新:`+w(J.value),1)):l(``,!0)])):l(``,!0)],64)):!o.value&&x.value?(T(),v(i,{key:2,title:x.value,type:`error`,"show-icon":``,closable:!1},{default:g(()=>[n[9]||=t(`div`,{class:`alert-hint`},`检查需访问 npm 源,可能是网络不可达或版本号解析失败;稍后重试即可。`,-1),s(D,{size:`small`,class:`mt-8`,onClick:Z},{default:g(()=>[...n[8]||=[r(`重试`,-1)]]),_:1})]),_:1},8,[`title`])):l(``,!0),S.value?(T(),v(i,{key:3,title:S.value,type:`info`,"show-icon":``,closable:!1},{default:g(()=>[E.value?(T(),v(D,{key:0,size:`small`,class:`mt-8`,onClick:O},{default:g(()=>[...n[10]||=[r(`刷新页面`,-1)]]),_:1})):l(``,!0)]),_:1},8,[`title`])):l(``,!0),t(`div`,K,[n[12]||=r(` npm 包主页: `,-1),s(y,{type:`primary`,href:q,target:`_blank`},{default:g(()=>[...n[11]||=[r(`npmjs.com/package/ezllm`,-1)]]),_:1})])])),[[A,o.value]])]),_:1},8,[`modelValue`,`close-on-click-modal`])}}}),[[`__scopeId`,`data-v-b75351d9`]]);o(),a(),O();var Y={class:`layout`},X=[`title`],Z={key:0,class:`header-version-tag`},Q={class:`header-nav`},te={class:`header-actions`},ne={class:`user-chip`},$={class:`user-avatar`},re={class:`user-name`},ie={class:`main`},ae={class:`page`},oe=3e4,se=m(c({__name:`LayoutView`,setup(a){let o=b(),c=E(),f=N(),m=n(!1);d(()=>{x(),f.load().catch(()=>{}),C()});let h=null,C=()=>{let e=_.value?.version??``;e!==``&&(h=window.setInterval(async()=>{if(document.visibilityState===`hidden`)return;let t=await x(!0);t.version!==void 0&&t.version!==e&&window.location.reload()},oe))};e(()=>{h!==null&&window.clearInterval(h)});let D=y(()=>F(f.config?.[`web-ui`])),O=y(()=>D.value.plugins),A=y(()=>D.value.managedServices),j=y(()=>_.value?.version||``),M=y(()=>_.value?.buildSource===`local`),P=y(()=>M.value?`本地构建版本(upgrade:local 产物)`:`当前运行版本`),I=y(()=>_.value?.authRequired!==!1),L=y(()=>{if(!I.value)return`免登录`;let e=localStorage.getItem(`webui_token`)||``;try{return atob(e).split(`:`)[0]||`用户`}catch{return`用户`}}),R=y(()=>{let e=o.path;return e===`/`?`/`:e.startsWith(`/providers`)?`/providers`:e.startsWith(`/managed-services`)?`/managed-services`:e.startsWith(`/plugins`)?`/plugins`:e.startsWith(`/settings`)?`/settings`:e.startsWith(`/logs`)?`/logs`:`/`}),z=e=>{e===`logout`&&(S(),c.push(`/login`)),e===`check-update`&&(m.value=!0)};return(e,n)=>{let a=p(`el-menu-item`),o=p(`el-menu`),c=p(`el-icon`),d=p(`el-dropdown-item`),f=p(`el-dropdown-menu`),h=p(`el-dropdown`),_=p(`el-header`),y=p(`router-view`);return T(),u(`div`,Y,[s(_,{class:`header`},{default:g(()=>[n[9]||=t(`div`,{class:`brand`},[t(`span`,{class:`brand-mark`},`EZ`),t(`h1`,null,`LLM`)],-1),j.value?(T(),u(`span`,{key:0,class:`header-version`,title:P.value},[r(` v`+w(j.value),1),M.value?(T(),u(`span`,Z,`本地构建`)):l(``,!0)],8,X)):l(``,!0),t(`nav`,Q,[s(o,{mode:`horizontal`,"default-active":R.value,ellipsis:!1,router:``,class:`header-menu`},{default:g(()=>[s(a,{index:`/`},{default:g(()=>[...n[1]||=[r(`首页`,-1)]]),_:1}),s(a,{index:`/providers`},{default:g(()=>[...n[2]||=[r(`供应商管理`,-1)]]),_:1}),A.value?(T(),v(a,{key:0,index:`/managed-services`},{default:g(()=>[...n[3]||=[r(`托管服务`,-1)]]),_:1})):l(``,!0),O.value?(T(),v(a,{key:1,index:`/plugins`},{default:g(()=>[...n[4]||=[r(`插件`,-1)]]),_:1})):l(``,!0),s(a,{index:`/logs`},{default:g(()=>[...n[5]||=[r(`日志`,-1)]]),_:1}),s(a,{index:`/settings`},{default:g(()=>[...n[6]||=[r(`设置`,-1)]]),_:1})]),_:1},8,[`default-active`])]),t(`div`,te,[s(h,{trigger:`click`,onCommand:z,class:`ml-12`},{dropdown:g(()=>[s(f,null,{default:g(()=>[s(d,{command:`check-update`},{default:g(()=>[...n[7]||=[r(`检查更新`,-1)]]),_:1}),I.value?(T(),v(d,{key:0,command:`logout`,divided:``},{default:g(()=>[...n[8]||=[r(`退出`,-1)]]),_:1})):l(``,!0)]),_:1})]),default:g(()=>[t(`div`,ne,[t(`span`,$,w(L.value.charAt(0).toUpperCase()),1),t(`span`,re,w(L.value),1),s(c,{class:`el-icon--right`},{default:g(()=>[s(i(k))]),_:1})])]),_:1})])]),_:1}),t(`main`,ie,[t(`div`,ae,[s(y)])]),s(J,{modelValue:m.value,"onUpdate:modelValue":n[0]||=e=>m.value=e},null,8,[`modelValue`])])}}}),[[`__scopeId`,`data-v-175b55ec`]]);export{se as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.mt-8[data-v-b75351d9]{margin-top:8px}.check-body[data-v-b75351d9]{flex-direction:column;gap:12px;min-height:96px;display:flex}.alert-hint[data-v-b75351d9]{margin-top:4px;font-size:12px;line-height:1.6}.alert-hint code[data-v-b75351d9]{background:var(--el-fill-color-light);border-radius:4px;padding:1px 6px;font-size:12px}.version-summary[data-v-b75351d9]{background:var(--el-fill-color-lighter);border-radius:8px;grid-template-columns:1fr auto 1fr;align-items:center;padding:12px 16px;display:grid}.version-item[data-v-b75351d9]{flex-direction:column;align-items:flex-start;gap:4px;min-width:0;display:flex}.version-item--latest[data-v-b75351d9]{text-align:right;align-items:flex-end}.version-label[data-v-b75351d9]{color:var(--el-text-color-secondary);font-size:12px}.version-value[data-v-b75351d9]{color:var(--el-text-color-primary);font-variant-numeric:tabular-nums;font-size:18px;font-weight:600;line-height:1.2}.version-divider[data-v-b75351d9]{background:var(--el-border-color-lighter);width:1px;height:36px;margin:0 16px}.meta-row[data-v-b75351d9]{color:var(--el-text-color-secondary);flex-wrap:wrap;justify-content:space-between;align-items:center;gap:12px;font-size:12px;display:flex}.meta-row--stack[data-v-b75351d9]{flex-direction:column;align-items:flex-start;gap:4px}.meta-warn[data-v-b75351d9]{color:var(--el-color-warning)}.npm-line[data-v-b75351d9]{color:var(--el-text-color-secondary);overflow-wrap:anywhere;font-size:12px}.user-chip[data-v-175b55ec]{cursor:pointer;border-radius:999px;outline:none;align-items:center;gap:8px;padding:4px 8px 4px 4px;transition:background .15s;display:flex}.user-chip[data-v-175b55ec]:hover{background:var(--el-fill-color-light)}.user-avatar[data-v-175b55ec]{color:#fff;background:linear-gradient(135deg,#4f8df9 0%,#2563eb 100%);border-radius:50%;flex-shrink:0;justify-content:center;align-items:center;width:28px;height:28px;font-size:13px;font-weight:600;display:inline-flex}.user-name[data-v-175b55ec]{color:var(--el-text-color-primary);text-overflow:ellipsis;white-space:nowrap;max-width:120px;font-size:13px;overflow:hidden}.user-chip .el-icon--right[data-v-175b55ec]{color:var(--el-text-color-secondary);font-size:12px}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{A as e,C as t,Et as n,F as r,H as i,I as a,L as o,M as s,N as c,S as l,a as u,at as d,c as f,d as p,h as m,ht as h,j as g,tt as _,u as v,yt as y}from"./router-
|
|
1
|
+
import{A as e,C as t,Et as n,F as r,H as i,I as a,L as o,M as s,N as c,S as l,a as u,at as d,c as f,d as p,h as m,ht as h,j as g,tt as _,u as v,yt as y}from"./router-DOdUMO6P.js";i(),m(),y();var b={class:`login-wrap`},x=p(o({__name:`LoginView`,setup(i){let o=v(),p=n(``),m=n(``),y=n(``),x=n(!1);async function S(){if(!p.value){y.value=`请输入用户名`;return}if(!m.value){y.value=`请输入密码`;return}x.value=!0,y.value=``;try{let e=await u.post(`/api/auth/login`,{username:p.value.trim(),password:m.value});f(e.token),o.push(`/`)}catch(e){y.value=e.message||`登录失败`}finally{x.value=!1}}return(n,i)=>{let o=d(`el-input`),u=d(`el-form-item`),f=d(`el-alert`),v=d(`el-button`),C=d(`el-form`),w=d(`el-card`);return _(),c(`div`,b,[a(w,{shadow:`never`,class:`login-card`},{default:h(()=>[i[3]||=e(`div`,{class:`login-brand`},[e(`span`,{class:`brand-mark`},`EZ`),e(`span`,{class:`login-title`},`LLM`)],-1),i[4]||=e(`p`,{class:`login-sub`},`本地 LLM 网关 · 管理台登录`,-1),a(C,{"label-position":`top`,onSubmit:t(S,[`prevent`])},{default:h(()=>[a(u,{label:`用户名`},{default:h(()=>[a(o,{modelValue:p.value,"onUpdate:modelValue":i[0]||=e=>p.value=e,placeholder:`请输入用户名`,onKeyup:l(S,[`enter`])},null,8,[`modelValue`])]),_:1}),a(u,{label:`密码`},{default:h(()=>[a(o,{modelValue:m.value,"onUpdate:modelValue":i[1]||=e=>m.value=e,type:`password`,placeholder:`请输入密码`,"show-password":``,onKeyup:l(S,[`enter`])},null,8,[`modelValue`])]),_:1}),y.value?(_(),g(f,{key:0,title:y.value,type:`error`,"show-icon":``,class:`mb-16`},null,8,[`title`])):s(``,!0),a(v,{type:`primary`,class:`full-width`,loading:x.value,onClick:S},{default:h(()=>[...i[2]||=[r(` 登录 `,-1)]]),_:1},8,[`loading`])]),_:1})]),_:1})])}}}),[[`__scopeId`,`data-v-b3e448fa`]]);export{x as default};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{A as e,C as t,Et as n,F as r,Ft as i,Gt as a,H as o,I as s,L as c,M as l,N as u,Q as d,S as f,St as p,T as m,a as h,at as g,d as _,gt as v,h as y,ht as b,j as x,k as S,ot as ee,pn as C,pt as w,rt as T,tt as E,wt as D,xt as O,yt as k}from"./router-
|
|
1
|
+
import{A as e,C as t,Et as n,F as r,Ft as i,Gt as a,H as o,I as s,L as c,M as l,N as u,Q as d,S as f,St as p,T as m,a as h,at as g,d as _,gt as v,h as y,ht as b,j as x,k as S,ot as ee,pn as C,pt as w,rt as T,tt as E,wt as D,xt as O,yt as k}from"./router-DOdUMO6P.js";import{B as te,S as ne}from"./message-7_77xsCe.js";import{t as A}from"./index-Bpt0yCG7.js";import{t as j}from"./providers-Dx3XtxJu.js";import{n as M,t as N}from"./useCopyToast-Dkb8g4uG.js";import{t as P}from"./useToast-BxrPRTvE.js";import{n as F,t as I}from"./useQuickRangeFilter-CC-fmdix.js";import{C as L,S as R,T as z,_ as B,a as re,c as ie,d as V,g as H,h as U,i as ae,l as oe,m as W,n as se,p as G,r as ce,s as le,t as ue,u as K,v as de,w as fe}from"./format-Deb1hfjO.js";o(),k(),a();var pe={class:`detail-content`},q={key:0,class:`ip-link`},me={class:`ip-pop`},J={class:`ip-pop-row`},Y={key:0,class:`ip-pop-row`},X={key:1,class:`ip-pop-error`},he={key:2},ge=[`href`],_e={key:1},ve={key:1},ye=[`title`],be=[`title`],xe={class:`error-text`},Se={class:`pane-bar`},Ce={class:`json-block`},we={class:`pane-bar`},Z={class:`json-block`},Te={class:`pane-bar`},Q={class:`json-block`},Ee={class:`pane-bar`},De={class:`json-block`},Oe={class:`pane-bar`},ke={class:`json-block`},Ae={class:`pane-bar`},$={class:`json-block`},je={class:`pane-bar`},Me={class:`json-block`},Ne={class:`pane-bar`},Pe={class:`json-block`},Fe=_(c({__name:`LogDetailDialog`,setup(t,{expose:a}){let{copyWithToast:o}=N(),{loadError:c,run:d}=M(),f=n(!1),_=n(null),y=n(!1),w=n(`info`),T=n(!1),D=n(null),O=F(),k=e=>{D.value=e,f.value=!0,_.value=null,w.value=`info`;let t=O();y.value=!0,d(async()=>{try{let n=`?id=${String(e.id)}`,r=await h.get(`/api/logs/detail`+n);if(!t())return;if(r&&r.detail){let e={...r.detail,...r.meta};e.response&&=p(e.response),e.request&&=p(e.request),_.value=e}else _.value=r}catch(e){if(!t())return;throw e}finally{t()&&(y.value=!1)}})},te=()=>{D.value&&k(D.value)};a({open:k});let ne=S(()=>U(_.value?.response?.inbound_request)),A=S(()=>U(_.value?.response?.upstream_request)),j=S(()=>B(_.value?.response?.upstream_response_text)),P=S(()=>(_.value?.response?.upstream_stream_frames||[]).join(`
|
|
2
2
|
|
|
3
3
|
`)),I=S(()=>U(_.value?.response?.client_response)),L=S(()=>(_.value?.response?.client_stream_frames||[]).join(`
|
|
4
4
|
|
|
5
|
-
`)),R=S(()=>U(_.value?.request)),re=S(()=>U(_.value?.response)),ie=async e=>{if(!(e._ipInfo||e._ipInfoError)){T.value=!0;try{let t=await h.get(`/api/logs/ipinfo?ip=${encodeURIComponent(e.ip)}`);t.error?e._ipInfoError=t.error:e._ipInfo=t}catch{e._ipInfoError=`查询失败`}finally{T.value=!1}}},ae=e=>[e.country,e.region,e.city].filter(Boolean).join(` · `)||`-`;return(t,n)=>{let a=g(`el-button`),d=g(`el-alert`),p=g(`el-descriptions-item`),h=g(`el-tag`),S=g(`el-divider`),D=g(`el-popover`),O=g(`el-descriptions`),k=g(`el-tab-pane`),M=g(`el-tabs`),N=g(`el-dialog`),F=ee(`loading`);return E(),x(N,{modelValue:f.value,"onUpdate:modelValue":n[11]||=e=>f.value=e,title:`日志详情`,width:`80%`,top:`5vh`,"destroy-on-close":``},{default:b(()=>[i(c)?(E(),x(d,{key:0,title:i(c),type:`error`,"show-icon":``,closable:!1,class:`mb-16`},{default:b(()=>[s(a,{size:`small`,onClick:te},{default:b(()=>[...n[12]||=[r(`重试`,-1)]]),_:1})]),_:1},8,[`title`])):l(``,!0),v((E(),u(`div`,pe,[_.value?(E(),x(M,{key:0,modelValue:w.value,"onUpdate:modelValue":n[10]||=e=>w.value=e},{default:b(()=>[s(k,{lazy:``,label:`基本信息`,name:`info`},{default:b(()=>[s(O,{column:2,border:``},{default:b(()=>[s(p,{label:`时间`},{default:b(()=>[r(C(i(H)(_.value.time)),1)]),_:1}),s(p,{label:`模型`},{default:b(()=>[r(C(_.value.model),1)]),_:1}),s(p,{label:`方法`},{default:b(()=>[r(C(_.value.method),1)]),_:1}),s(p,{label:`路径`},{default:b(()=>[r(C(_.value.path),1)]),_:1}),s(p,{label:`状态码`},{default:b(()=>[r(C(_.value.status),1)]),_:1}),s(p,{label:`流式`},{default:b(()=>[s(h,{type:_.value.stream?`warning`:`info`},{default:b(()=>[r(C(_.value.stream?`是`:`否`),1)]),_:1},8,[`type`])]),_:1}),s(p,{label:`IP`},{default:b(()=>[_.value.ip?(E(),u(`span`,q,[s(D,{placement:`right`,width:`240`,trigger:`click`,onShow:n[0]||=e=>ie(_.value)},{reference:b(()=>[e(`span`,null,C(_.value.ip),1)]),default:b(()=>[v((E(),u(`div`,me,[_.value._ipInfo?(E(),u(m,{key:0},[e(`div`,J,[n[13]||=e(`span`,{class:`ip-pop-label`},`归属地`,-1),e(`span`,null,C(ae(_.value._ipInfo)),1)]),_.value._ipInfo.isp?(E(),u(`div`,Y,[n[14]||=e(`span`,{class:`ip-pop-label`},`运营商`,-1),e(`span`,null,C(_.value._ipInfo.isp),1)])):l(``,!0)],64)):_.value._ipInfoError?(E(),u(`div`,X,C(_.value._ipInfoError),1)):(E(),u(`span`,he,`查询中...`)),s(S,{style:{margin:`8px 0`}}),e(`a`,{class:`ip-pop-link`,href:`https://m.ip138.com/iplookup.php?ip=${encodeURIComponent(_.value.ip)}`,target:`_blank`},`在 ip138 查看`,8,ge)])),[[F,T.value]])]),_:1})])):(E(),u(`span`,_e,`-`))]),_:1}),s(p,{label:`Session`},{default:b(()=>[r(C(_.value.session_id||`-`),1)]),_:1}),s(p,{label:`ID`},{default:b(()=>[_.value._id==null?(E(),u(`span`,ve,`-`)):(E(),u(`span`,{key:0,class:`request-id`,title:`点击复制(日志 id 同时是响应头 x-request-id)`,onClick:n[1]||=e=>i(o)(String(_.value._id))},C(_.value._id),1))]),_:1}),s(p,{label:`输入 Token(含缓存读取)`},{default:b(()=>[r(C(i(G)(_.value.input_tokens??0)),1)]),_:1}),s(p,{label:`输出 Token`},{default:b(()=>[r(C(i(G)(_.value.output_tokens??0)),1)]),_:1}),s(p,{label:`缓存读取`},{default:b(()=>[r(C(i(G)(_.value.cache_read_tokens??0)),1)]),_:1}),s(p,{label:`请求耗时`},{default:b(()=>[r(C(i(V)(_.value.duration)),1)]),_:1}),s(p,{label:`缓存命中率`},{default:b(()=>[r(C(i(le)(_.value)),1)]),_:1}),s(p,{label:`首 Token`},{default:b(()=>[e(`span`,{title:i(ce)},C(i(V)(_.value.ttft)),9,ye)]),_:1}),s(p,{label:`生成速度`},{default:b(()=>[e(`span`,{title:i(se)},C(i(W)(_.value.tps)),9,be)]),_:1}),_.value.error?(E(),x(p,{key:0,label:`错误`,span:2},{default:b(()=>[e(`span`,xe,C(_.value.error),1)]),_:1})):l(``,!0)]),_:1}),_.value.response?.truncated?(E(),x(d,{key:0,class:`mt-16`,type:`warning`,closable:!1,title:`内容超过单请求捕获上限,已截断`})):l(``,!0)]),_:1}),_.value.response?._capture?(E(),u(m,{key:0},[s(k,{lazy:``,label:`客户端请求`,name:`inbound`},{default:b(()=>[e(`div`,Se,[s(a,{size:`small`,class:`copy-btn`,onClick:n[2]||=e=>i(o)(ne.value)},{default:b(()=>[...n[15]||=[r(` 复制 `,-1)]]),_:1})]),e(`pre`,Ce,C(i(z)(ne.value)),1)]),_:1}),s(k,{lazy:``,label:`转发上游的请求`,name:`upstreamReq`},{default:b(()=>[e(`div`,we,[s(a,{size:`small`,class:`copy-btn`,onClick:n[3]||=e=>i(o)(A.value)},{default:b(()=>[...n[16]||=[r(` 复制 `,-1)]]),_:1})]),e(`pre`,Z,C(i(z)(A.value)),1)]),_:1}),_.value.response.upstream_response_text?(E(),x(k,{key:0,lazy:``,label:`上游响应(原始)`,name:`upstreamRes`},{default:b(()=>[e(`div`,Te,[s(a,{size:`small`,class:`copy-btn`,onClick:n[4]||=e=>i(o)(_.value.response.upstream_response_text)},{default:b(()=>[...n[17]||=[r(` 复制 `,-1)]]),_:1})]),e(`pre`,Q,C(i(z)(j.value)),1)]),_:1})):_.value.response.upstream_stream_frames?.length?(E(),x(k,{key:1,lazy:``,label:`上游响应(原始流,${_.value.response.upstream_stream_frames.length} 帧)`,name:`upstreamStream`},{default:b(()=>[e(`div`,Ee,[s(a,{size:`small`,class:`copy-btn`,onClick:n[5]||=e=>i(o)(P.value)},{default:b(()=>[...n[18]||=[r(` 复制 `,-1)]]),_:1})]),e(`pre`,De,C(i(z)(P.value)),1)]),_:1},8,[`label`])):l(``,!0),_.value.response.client_response!==void 0&&_.value.response.client_response!==null?(E(),x(k,{key:2,lazy:``,label:`回写客户端(转换后)`,name:`clientRes`},{default:b(()=>[e(`div`,Oe,[s(a,{size:`small`,class:`copy-btn`,onClick:n[6]||=e=>i(o)(I.value)},{default:b(()=>[...n[19]||=[r(` 复制 `,-1)]]),_:1})]),e(`pre`,ke,C(i(z)(I.value)),1)]),_:1})):_.value.response.client_stream_frames?.length?(E(),x(k,{key:3,lazy:``,label:`回写客户端(${_.value.response.client_stream_frames.length} 帧)`,name:`clientStream`},{default:b(()=>[e(`div`,Ae,[s(a,{size:`small`,class:`copy-btn`,onClick:n[7]||=e=>i(o)(L.value)},{default:b(()=>[...n[20]||=[r(` 复制 `,-1)]]),_:1})]),e(`pre`,$,C(i(z)(L.value)),1)]),_:1},8,[`label`])):l(``,!0)],64)):(E(),u(m,{key:1},[s(k,{lazy:``,label:`请求体`,name:`request`},{default:b(()=>[e(`div`,je,[s(a,{size:`small`,class:`copy-btn`,onClick:n[8]||=e=>i(o)(R.value)},{default:b(()=>[...n[21]||=[r(` 复制 `,-1)]]),_:1})]),e(`pre`,Me,C(i(z)(R.value)),1)]),_:1}),s(k,{lazy:``,label:`响应体`,name:`response`},{default:b(()=>[e(`div`,Ne,[s(a,{size:`small`,class:`copy-btn`,onClick:n[9]||=e=>i(o)(re.value)},{default:b(()=>[...n[22]||=[r(` 复制 `,-1)]]),_:1})]),e(`pre`,Pe,C(i(z)(re.value)),1)]),_:1})],64))]),_:1},8,[`modelValue`])):l(``,!0)])),[[F,y.value]])]),_:1},8,[`modelValue`])}}}),[[`__scopeId`,`data-v-7e1ff197`]]);o(),k(),a(),y();var Ie={class:`session-table`},Le={class:`group-detail`},Re=[`title`],ze={key:0,class:`detail-error`},Be={class:`detail-footer`},Ve={class:`detail-count`},He=[`title`,`onClick`],Ue=`会话平均生成速度:组内有效请求的输出 token 合计 ÷ 生成窗口合计(按窗口加权,不是各请求速度的算术平均);首 = 组内流式且已采集首 token 的请求的平均首 token 延迟(非流式请求无此观测点,不参与)`,We=50,Ge=_(c({__name:`SessionGroupTable`,props:{groups:{},noSession:{},loading:{type:Boolean},filterParams:{}},emits:[`open-detail`],setup(a,{emit:o}){let c=a,d=o,{copyWithToast:f}=N(),p=S(()=>c.noSession?[...c.groups,c.noSession]:c.groups),m=e=>e.session_id||`__no_session__`,_=n(null),y=D(new Map),T={loading:!1,items:[],total:0,nextPage:1,error:null},O=e=>y.get(m(e))??T,k=async(e,t)=>{let n=(e=>(y.has(e)||y.set(e,{loading:!1,items:[],total:0,nextPage:1,error:null}),y.get(e)))(m(e));if(!n.loading){n.loading=!0,n.error=null;try{let r={...c.filterParams,sort:`time`,order:`desc`,page:String(t),pageSize:String(We)};e.session_id?r.sessionId=e.session_id:r.noSession=`1`;let i=await h.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}}},te=(e,t)=>{t.some(t=>m(t)===m(e))&&O(e).items.length===0&&k(e,1)},ne=e=>{let t=O(e);t.loading||t.items.length>=t.total||k(e,t.nextPage)},A=e=>{_.value?.toggleRowExpansion(e)};return w(()=>p.value.map(m),e=>{let t=new Set(e);for(let e of[...y.keys()])t.has(e)||y.delete(e)}),(n,o)=>{let c=g(`el-table-column`),h=g(`el-tag`),y=g(`el-button`),S=g(`el-table`),w=g(`el-empty`),T=ee(`loading`);return E(),u(`div`,Ie,[p.value.length>0||a.loading?v((E(),x(S,{key:0,ref_key:`tableRef`,ref:_,data:p.value,height:`100%`,"row-key":m,border:``,class:`dense-table`,onExpandChange:te,onRowClick:A},{default:b(()=>[s(c,{type:`expand`},{default:b(({row:t})=>[e(`div`,Le,[v((E(),x(S,{data:O(t).items,size:`small`,border:``,class:`dense-table`},{default:b(()=>[s(c,{label:`时间`,width:`136`,align:`center`},{default:b(({row:e})=>[r(C(i(L)(e.time)),1)]),_:1}),s(c,{prop:`model`,label:`模型`,"min-width":`80`,align:`center`,"show-overflow-tooltip":``}),s(c,{label:`客户端`,width:`136`,align:`center`,"show-overflow-tooltip":``},{default:b(({row:e})=>[r(C(i(ie)(e)),1)]),_:1}),s(c,{label:`状态`,width:`60`,align:`center`},{default:b(({row:e})=>[s(h,{size:`small`,type:e.status>=400?`danger`:e.status>=300?`warning`:`success`},{default:b(()=>[r(C(e.status),1)]),_:2},1032,[`type`])]),_:1}),s(c,{label:`输入`,width:`84`,align:`center`},{default:b(({row:e})=>[r(C(i(G)(e.input_tokens??0)),1)]),_:1}),s(c,{label:`输出`,width:`78`,align:`center`},{default:b(({row:e})=>[r(C(i(G)(e.output_tokens??0)),1)]),_:1}),s(c,{label:`缓存读取`,width:`84`,align:`center`},{default:b(({row:e})=>[r(C(i(G)(e.cache_read_tokens??0)),1)]),_:1}),s(c,{label:`缓存命中率`,width:`88`,align:`center`},{default:b(({row:e})=>[r(C(i(le)(e)),1)]),_:1}),s(c,{label:`请求耗时`,width:`74`,align:`center`},{default:b(({row:e})=>[r(C(i(V)(e.duration)),1)]),_:1}),s(c,{label:`速度`,width:`140`,align:`center`},{default:b(({row:t})=>[e(`div`,{title:i(ue)},C(i(fe)(t.tps,t.ttft)),9,Re)]),_:1}),s(c,{label:`详情`,width:`52`,align:`center`},{default:b(({row:e})=>[s(y,{link:``,type:`primary`,onClick:t=>d(`open-detail`,e)},{default:b(()=>[...o[0]||=[r(`查看`,-1)]]),_:1},8,[`onClick`])]),_:1})]),_:1},8,[`data`])),[[T,O(t).loading]]),O(t).error?(E(),u(`div`,ze,[r(C(O(t).error)+` `,1),s(y,{link:``,type:`primary`,size:`small`,onClick:e=>k(t,1)},{default:b(()=>[...o[1]||=[r(`重试`,-1)]]),_:1},8,[`onClick`])])):l(``,!0),e(`div`,Be,[e(`span`,Ve,`已显示 `+C(O(t).items.length)+` / `+C(O(t).total)+` 条`,1),O(t).items.length<O(t).total?(E(),x(y,{key:0,size:`small`,loading:O(t).loading,onClick:e=>ne(t)},{default:b(()=>[...o[2]||=[r(` 加载更多 `,-1)]]),_:1},8,[`loading`,`onClick`])):l(``,!0)])])]),_:1}),s(c,{label:`Session`,width:`100`,align:`center`},{default:b(({row:e})=>[e.session_id?(E(),u(`span`,{key:0,class:`session-id`,title:`${e.session_id}(点击复制)`,onClick:t(t=>i(f)(e.session_id),[`stop`])},C(i(R)(e.session_id)),9,He)):(E(),x(h,{key:1,size:`small`,type:`info`,title:`未携带会话标识的请求(NULL / 空串 session_id)`},{default:b(()=>[...o[3]||=[r(` 无 Session `,-1)]]),_:1}))]),_:1}),s(c,{label:`请求数`,width:`70`,align:`center`},{default:b(({row:e})=>[r(C(i(G)(e.calls)),1)]),_:1}),s(c,{label:`首次请求`,width:`120`,align:`center`},{default:b(({row:e})=>[r(C(i(L)(e.first_time)),1)]),_:1}),s(c,{label:`最后请求`,width:`120`,align:`center`},{default:b(({row:e})=>[r(C(i(L)(e.last_time)),1)]),_:1}),s(c,{label:`模型`,"min-width":`80`,align:`center`,"show-overflow-tooltip":``},{default:b(({row:e})=>[r(C(i(de)(e.models)),1)]),_:1}),s(c,{label:`客户端`,width:`136`,align:`center`,"show-overflow-tooltip":``},{default:b(({row:e})=>[r(C(i(K)(e.clients)),1)]),_:1}),s(c,{label:`输入`,width:`100`,align:`center`},{default:b(({row:e})=>[r(C(i(G)(e.input_tokens)),1)]),_:1}),s(c,{label:`输出`,width:`90`,align:`center`},{default:b(({row:e})=>[r(C(i(G)(e.output_tokens)),1)]),_:1}),s(c,{label:`缓存读取`,width:`100`,align:`center`},{default:b(({row:e})=>[r(C(i(G)(e.cache_read_tokens)),1)]),_:1}),s(c,{label:`速度`,width:`140`,align:`center`},{default:b(({row:t})=>[e(`div`,{title:Ue},C(i(fe)(t.tps,t.avg_ttft)),1)]),_:1})]),_:1},8,[`data`])),[[T,a.loading]]):(E(),x(w,{key:1,description:`当前筛选下没有日志`}))])}}}),[[`__scopeId`,`data-v-37cd2bcc`]]);o(),k(),y(),a();var Ke={class:`logs-page`},qe={class:`filter-bar`},Je={class:`table-wrap`},Ye=[`onClick`],Xe={key:1},Ze=[`title`,`onClick`],Qe={key:1},$e=[`title`,`onClick`],et={key:1},tt=[`title`],nt={class:`pagination-bar`},rt={class:`pagination-left`},it=_(c({__name:`LogsView`,setup(t){let a=j(),{toast:o}=P(),{copyWithToast:c}=N(),{loadError:p,run:_}=M(),{rangeKey:y,dateRange:w,setRange:D,onRangeChange:k}=I(()=>$()),z=n(`2xx`),B=n(``),H=n(``),U=n(``),W=n(`session`),K=n([]),de=n([]),pe=n(null),q=n(0),me=n(0),J=n(1),Y=n(20),X=n(!1),he=n(null),ge=e=>{he.value?.open(e)},_e=S(()=>{let e=new Set;for(let t of a.suppliers)for(let n of t.models)e.add(n.modelName);for(let t of K.value)t.model&&e.add(t.model);return[...e].sort()}),ve=n([]),ye=S(()=>{let e=new Set(ve.value);for(let t of K.value)t.client&&e.add(t.client);return[...e].sort()}),be=async()=>{try{let e=await h.get(`/api/logs/clients`);ve.value=e.clients||[]}catch{ve.value=[]}},xe=e=>{y.value=``,w.value=e||null,$()},Se=()=>{let e={};w.value&&w.value.length===2&&(e.startDate=w.value[0],e.endDate=w.value[1]),z.value&&(e.status=z.value),B.value&&(e.model=B.value),H.value&&(e.client=H.value);let t=U.value.trim();return t&&(e.sessionId=t),e},Ce=S(()=>Se()),we=F(),Z=()=>_(async()=>{let e=we();X.value=!0;try{let t={...Se(),page:String(J.value),pageSize:String(Y.value)};if(W.value===`session`){let n=new URLSearchParams(t).toString(),r=await h.get(`/api/logs/sessions?`+n);if(!e())return;de.value=r.groups||[],pe.value=r.noSession??null,q.value=r.total||0,me.value=r.rowsTotal||0}else{let n=new URLSearchParams({...t,sort:`time`,order:`desc`}).toString(),r=await h.get(`/api/logs?`+n);if(!e())return;K.value=r.items||[],q.value=r.total||0}}catch(t){if(!e())return;throw t}finally{e()&&(X.value=!1)}}),Te=e=>{W.value!==e&&(W.value=e,J.value=1,Y.value=W.value===`session`?20:50,Z())},Q=n(!1),Ee=S(()=>W.value===`session`?me.value:q.value),De=`本页平均:${ce}(仅流式请求参与);${se}——按本页输出 token 合计 ÷ 生成窗口合计加权,不是逐条速度求平均,失败请求、空回复与流式缺首 token 的行不参与`,Oe=S(()=>ae(K.value)),ke=S(()=>re(K.value)),Ae=async()=>{if(Q.value||Ee.value===0)return;let e=W.value===`session`?`(按筛选行数计,含「无 Session」组)`:``;try{await A.confirm(`将永久清理当前筛选条件下的 ${Ee.value} 条日志${e},清理后不可恢复,请谨慎操作!`,`清理确认`,{confirmButtonText:`确认清理`,cancelButtonText:`取消`,type:`warning`})}catch{return}Q.value=!0;try{let e=new URLSearchParams(Se()).toString(),t=await h.post(`/api/logs/clear?`+e,{});o(`已清理 ${t.deleted??0} 条日志`,`success`),J.value>1&&(J.value=1),Z()}catch(e){o(e.message||`清理失败`,`error`)}finally{Q.value=!1}},$=()=>{J.value=1,be(),Z()},je=()=>{y.value=`today`,w.value=null,z.value=`2xx`,B.value=``,H.value=``,U.value=``,J.value=1,Y.value=W.value===`session`?20:50,D(`today`)};return d(()=>{a.loadProviders().catch(()=>{}),be(),D(`today`)}),(t,n)=>{let a=g(`el-button`),o=g(`el-alert`),d=g(`el-option`),h=g(`el-select`),_=g(`el-date-picker`),S=g(`el-input`),D=g(`el-tooltip`),A=g(`el-button-group`),j=g(`el-card`),M=g(`el-table-column`),N=g(`el-tag`),P=g(`el-table`),F=g(`el-pagination`),I=ee(`loading`);return E(),u(`div`,Ke,[i(p)?(E(),x(o,{key:0,title:i(p),type:`error`,"show-icon":``,closable:!1,class:`mb-16`},{default:b(()=>[s(a,{size:`small`,onClick:Z},{default:b(()=>[...n[10]||=[r(`重试`,-1)]]),_:1})]),_:1},8,[`title`])):l(``,!0),s(j,{shadow:`never`},{default:b(()=>[e(`div`,qe,[s(h,{modelValue:i(y),"onUpdate:modelValue":n[0]||=e=>O(y)?y.value=e:null,placeholder:`时间范围`,clearable:``,style:{width:`114px`},onChange:i(k)},{default:b(()=>[s(d,{label:`今天`,value:`today`}),s(d,{label:`昨天`,value:`yesterday`}),s(d,{label:`前天`,value:`beforeYesterday`}),s(d,{label:`近三天`,value:`last3days`}),s(d,{label:`本周`,value:`week`}),s(d,{label:`本月`,value:`month`})]),_:1},8,[`modelValue`,`onChange`]),s(_,{modelValue:i(w),"onUpdate:modelValue":n[1]||=e=>O(w)?w.value=e:null,type:`daterange`,"value-format":`YYYY-MM-DD`,"range-separator":`至`,"start-placeholder":`开始日期`,"end-placeholder":`结束日期`,style:{width:`240px`},onChange:xe},null,8,[`modelValue`]),s(h,{modelValue:z.value,"onUpdate:modelValue":n[2]||=e=>z.value=e,placeholder:`全部状态`,clearable:``,style:{width:`106px`},onChange:$},{default:b(()=>[s(d,{label:`成功 (2xx)`,value:`2xx`}),s(d,{label:`3xx`,value:`3xx`}),s(d,{label:`4xx`,value:`4xx`}),s(d,{label:`5xx`,value:`5xx`}),s(d,{label:`错误 (4xx+)`,value:`err`})]),_:1},8,[`modelValue`]),s(h,{modelValue:B.value,"onUpdate:modelValue":n[3]||=e=>B.value=e,placeholder:`全部模型`,clearable:``,filterable:``,style:{width:`176px`},onChange:$},{default:b(()=>[(E(!0),u(m,null,T(_e.value,e=>(E(),x(d,{key:e,label:e,value:e},null,8,[`label`,`value`]))),128))]),_:1},8,[`modelValue`]),s(h,{modelValue:H.value,"onUpdate:modelValue":n[4]||=e=>H.value=e,placeholder:`全部客户端`,clearable:``,filterable:``,style:{width:`130px`},onChange:$},{default:b(()=>[(E(!0),u(m,null,T(ye.value,e=>(E(),x(d,{key:e,label:e,value:e},null,8,[`label`,`value`]))),128))]),_:1},8,[`modelValue`]),s(S,{modelValue:U.value,"onUpdate:modelValue":n[5]||=e=>U.value=e,class:`session-input`,placeholder:`Session ID(前缀匹配)`,clearable:``,onKeyup:f($,[`enter`])},null,8,[`modelValue`]),s(A,{class:`view-switch push-right`},{default:b(()=>[s(D,{content:`按会话分组`,placement:`top`,"show-after":300},{default:b(()=>[s(a,{type:W.value===`session`?`primary`:`default`,icon:i(te),"aria-label":`按会话分组`,onClick:n[6]||=e=>Te(`session`)},null,8,[`type`,`icon`])]),_:1}),s(D,{content:`列表`,placement:`top`,"show-after":300},{default:b(()=>[s(a,{type:W.value===`list`?`primary`:`default`,icon:i(ne),"aria-label":`列表视图`,onClick:n[7]||=e=>Te(`list`)},null,8,[`type`,`icon`])]),_:1})]),_:1}),s(a,{type:`primary`,onClick:$},{default:b(()=>[...n[11]||=[r(`搜索`,-1)]]),_:1}),s(a,{onClick:je},{default:b(()=>[...n[12]||=[r(`重置`,-1)]]),_:1})])]),_:1}),s(j,{shadow:`never`,class:`mt-16 table-card`},{default:b(()=>[e(`div`,Je,[W.value===`list`?v((E(),x(P,{key:0,data:K.value,border:``,height:`100%`,class:`dense-table`},{default:b(()=>[s(M,{prop:`id`,label:`ID`,width:`66`,align:`center`},{default:b(({row:e})=>[e.id==null?(E(),u(`span`,Xe,`-`)):(E(),u(`span`,{key:0,class:`request-id`,title:`点击复制(日志 id 同时是响应头 x-request-id,可用于关联控制台日志与检索)`,onClick:t=>i(c)(String(e.id))},C(e.id),9,Ye))]),_:1}),s(M,{prop:`time`,label:`时间`,width:`136`,align:`center`},{default:b(({row:e})=>[r(C(i(L)(e.time)),1)]),_:1}),s(M,{prop:`status`,label:`状态`,width:`60`,align:`center`},{default:b(({row:e})=>[s(N,{size:`small`,type:e.status>=400?`danger`:e.status>=300?`warning`:`success`},{default:b(()=>[r(C(e.status),1)]),_:2},1032,[`type`])]),_:1}),s(M,{label:`Session`,width:`88`,align:`center`},{default:b(({row:e})=>[e.session_id?(E(),u(`span`,{key:0,class:`request-id`,title:`${e.session_id}(点击复制)`,onClick:t=>i(c)(e.session_id)},C(i(R)(e.session_id)),9,Ze)):(E(),u(`span`,Qe,`-`))]),_:1}),s(M,{prop:`model`,label:`模型`,"min-width":`80`,align:`center`,"show-overflow-tooltip":``}),s(M,{label:`客户端`,width:`136`,align:`center`},{default:b(({row:e})=>[e.client||e.user_agent?(E(),u(`span`,{key:0,class:`request-id`,title:i(oe)(e),onClick:t=>i(c)(e.user_agent||e.client)},C(i(ie)(e)),9,$e)):(E(),u(`span`,et,`-`))]),_:1}),s(M,{label:`输入`,width:`84`,align:`center`},{default:b(({row:e})=>[r(C(i(G)(e.input_tokens??0)),1)]),_:1}),s(M,{label:`输出`,width:`78`,align:`center`},{default:b(({row:e})=>[r(C(i(G)(e.output_tokens??0)),1)]),_:1}),s(M,{label:`缓存读取`,width:`84`,align:`center`},{default:b(({row:e})=>[r(C(i(G)(e.cache_read_tokens??0)),1)]),_:1}),s(M,{label:`缓存命中率`,width:`88`,align:`center`},{default:b(({row:t})=>[e(`span`,null,C(i(le)(t)),1)]),_:1}),s(M,{label:`请求耗时`,width:`74`,align:`center`},{default:b(({row:e})=>[r(C(i(V)(e.duration)),1)]),_:1}),s(M,{label:`速度`,width:`140`,align:`center`},{default:b(({row:t})=>[e(`div`,{title:i(ue)},C(i(fe)(t.tps,t.ttft)),9,tt)]),_:1}),s(M,{label:`详情`,width:`52`,align:`center`,fixed:`right`},{default:b(({row:e})=>[s(a,{link:``,type:`primary`,onClick:t=>ge(e)},{default:b(()=>[...n[13]||=[r(`查看`,-1)]]),_:1},8,[`onClick`])]),_:1})]),_:1},8,[`data`])),[[I,X.value]]):l(``,!0),W.value===`session`?(E(),x(Ge,{key:1,groups:de.value,"no-session":pe.value,loading:X.value,"filter-params":Ce.value,onOpenDetail:ge},null,8,[`groups`,`no-session`,`loading`,`filter-params`])):l(``,!0)]),e(`div`,nt,[e(`div`,rt,[s(a,{type:`danger`,plain:``,size:`small`,loading:Q.value,disabled:Ee.value===0,onClick:Ae},{default:b(()=>[...n[14]||=[r(`清理已筛选日志`,-1)]]),_:1},8,[`loading`,`disabled`]),W.value===`list`&&K.value.length?(E(),u(`span`,{key:0,class:`muted-sm page-avg-speed`,title:De},C(i(fe)(Oe.value,ke.value)),1)):l(``,!0)]),s(F,{class:`push-right`,"current-page":J.value,"onUpdate:currentPage":n[8]||=e=>J.value=e,"page-size":Y.value,"onUpdate:pageSize":n[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}),s(Fe,{ref_key:`logDetailRef`,ref:he},null,512)])}}}),[[`__scopeId`,`data-v-0ecff344`]]);export{it as default};
|
|
5
|
+
`)),R=S(()=>U(_.value?.request)),re=S(()=>U(_.value?.response)),ie=async e=>{if(!(e._ipInfo||e._ipInfoError)){T.value=!0;try{let t=await h.get(`/api/logs/ipinfo?ip=${encodeURIComponent(e.ip)}`);t.error?e._ipInfoError=t.error:e._ipInfo=t}catch{e._ipInfoError=`查询失败`}finally{T.value=!1}}},ae=e=>[e.country,e.region,e.city].filter(Boolean).join(` · `)||`-`;return(t,n)=>{let a=g(`el-button`),d=g(`el-alert`),p=g(`el-descriptions-item`),h=g(`el-tag`),S=g(`el-divider`),D=g(`el-popover`),O=g(`el-descriptions`),k=g(`el-tab-pane`),M=g(`el-tabs`),N=g(`el-dialog`),F=ee(`loading`);return E(),x(N,{modelValue:f.value,"onUpdate:modelValue":n[11]||=e=>f.value=e,title:`日志详情`,width:`80%`,top:`5vh`,"destroy-on-close":``},{default:b(()=>[i(c)?(E(),x(d,{key:0,title:i(c),type:`error`,"show-icon":``,closable:!1,class:`mb-16`},{default:b(()=>[s(a,{size:`small`,onClick:te},{default:b(()=>[...n[12]||=[r(`重试`,-1)]]),_:1})]),_:1},8,[`title`])):l(``,!0),v((E(),u(`div`,pe,[_.value?(E(),x(M,{key:0,modelValue:w.value,"onUpdate:modelValue":n[10]||=e=>w.value=e},{default:b(()=>[s(k,{lazy:``,label:`基本信息`,name:`info`},{default:b(()=>[s(O,{column:2,border:``},{default:b(()=>[s(p,{label:`时间`},{default:b(()=>[r(C(i(H)(_.value.time)),1)]),_:1}),s(p,{label:`模型`},{default:b(()=>[r(C(_.value.model),1)]),_:1}),s(p,{label:`方法`},{default:b(()=>[r(C(_.value.method),1)]),_:1}),s(p,{label:`路径`},{default:b(()=>[r(C(_.value.path),1)]),_:1}),s(p,{label:`状态码`},{default:b(()=>[r(C(_.value.status),1)]),_:1}),s(p,{label:`流式`},{default:b(()=>[s(h,{type:_.value.stream?`warning`:`info`},{default:b(()=>[r(C(_.value.stream?`是`:`否`),1)]),_:1},8,[`type`])]),_:1}),s(p,{label:`IP`},{default:b(()=>[_.value.ip?(E(),u(`span`,q,[s(D,{placement:`right`,width:`240`,trigger:`click`,onShow:n[0]||=e=>ie(_.value)},{reference:b(()=>[e(`span`,null,C(_.value.ip),1)]),default:b(()=>[v((E(),u(`div`,me,[_.value._ipInfo?(E(),u(m,{key:0},[e(`div`,J,[n[13]||=e(`span`,{class:`ip-pop-label`},`归属地`,-1),e(`span`,null,C(ae(_.value._ipInfo)),1)]),_.value._ipInfo.isp?(E(),u(`div`,Y,[n[14]||=e(`span`,{class:`ip-pop-label`},`运营商`,-1),e(`span`,null,C(_.value._ipInfo.isp),1)])):l(``,!0)],64)):_.value._ipInfoError?(E(),u(`div`,X,C(_.value._ipInfoError),1)):(E(),u(`span`,he,`查询中...`)),s(S,{style:{margin:`8px 0`}}),e(`a`,{class:`ip-pop-link`,href:`https://m.ip138.com/iplookup.php?ip=${encodeURIComponent(_.value.ip)}`,target:`_blank`},`在 ip138 查看`,8,ge)])),[[F,T.value]])]),_:1})])):(E(),u(`span`,_e,`-`))]),_:1}),s(p,{label:`Session`},{default:b(()=>[r(C(_.value.session_id||`-`),1)]),_:1}),s(p,{label:`ID`},{default:b(()=>[_.value._id==null?(E(),u(`span`,ve,`-`)):(E(),u(`span`,{key:0,class:`request-id`,title:`点击复制(日志 id 同时是响应头 x-request-id)`,onClick:n[1]||=e=>i(o)(String(_.value._id))},C(_.value._id),1))]),_:1}),s(p,{label:`输入 Token(含缓存读取)`},{default:b(()=>[r(C(i(G)(_.value.input_tokens??0)),1)]),_:1}),s(p,{label:`输出 Token`},{default:b(()=>[r(C(i(G)(_.value.output_tokens??0)),1)]),_:1}),s(p,{label:`缓存读取`},{default:b(()=>[r(C(i(G)(_.value.cache_read_tokens??0)),1)]),_:1}),s(p,{label:`请求耗时`},{default:b(()=>[r(C(i(V)(_.value.duration)),1)]),_:1}),s(p,{label:`缓存命中率`},{default:b(()=>[r(C(i(le)(_.value)),1)]),_:1}),s(p,{label:`首 Token`},{default:b(()=>[e(`span`,{title:i(ce)},C(i(V)(_.value.ttft)),9,ye)]),_:1}),s(p,{label:`生成速度`},{default:b(()=>[e(`span`,{title:i(se)},C(i(W)(_.value.tps)),9,be)]),_:1}),_.value.error?(E(),x(p,{key:0,label:`错误`,span:2},{default:b(()=>[e(`span`,xe,C(_.value.error),1)]),_:1})):l(``,!0)]),_:1}),_.value.response?.truncated?(E(),x(d,{key:0,class:`mt-16`,type:`warning`,closable:!1,title:`内容超过单请求捕获上限,已截断`})):l(``,!0)]),_:1}),_.value.response?._capture?(E(),u(m,{key:0},[s(k,{lazy:``,label:`客户端请求`,name:`inbound`},{default:b(()=>[e(`div`,Se,[s(a,{size:`small`,class:`copy-btn`,onClick:n[2]||=e=>i(o)(ne.value)},{default:b(()=>[...n[15]||=[r(` 复制 `,-1)]]),_:1})]),e(`pre`,Ce,C(i(z)(ne.value)),1)]),_:1}),s(k,{lazy:``,label:`转发上游的请求`,name:`upstreamReq`},{default:b(()=>[e(`div`,we,[s(a,{size:`small`,class:`copy-btn`,onClick:n[3]||=e=>i(o)(A.value)},{default:b(()=>[...n[16]||=[r(` 复制 `,-1)]]),_:1})]),e(`pre`,Z,C(i(z)(A.value)),1)]),_:1}),_.value.response.upstream_response_text?(E(),x(k,{key:0,lazy:``,label:`上游响应(原始)`,name:`upstreamRes`},{default:b(()=>[e(`div`,Te,[s(a,{size:`small`,class:`copy-btn`,onClick:n[4]||=e=>i(o)(_.value.response.upstream_response_text)},{default:b(()=>[...n[17]||=[r(` 复制 `,-1)]]),_:1})]),e(`pre`,Q,C(i(z)(j.value)),1)]),_:1})):_.value.response.upstream_stream_frames?.length?(E(),x(k,{key:1,lazy:``,label:`上游响应(原始流,${_.value.response.upstream_stream_frames.length} 帧)`,name:`upstreamStream`},{default:b(()=>[e(`div`,Ee,[s(a,{size:`small`,class:`copy-btn`,onClick:n[5]||=e=>i(o)(P.value)},{default:b(()=>[...n[18]||=[r(` 复制 `,-1)]]),_:1})]),e(`pre`,De,C(i(z)(P.value)),1)]),_:1},8,[`label`])):l(``,!0),_.value.response.client_response!==void 0&&_.value.response.client_response!==null?(E(),x(k,{key:2,lazy:``,label:`回写客户端(转换后)`,name:`clientRes`},{default:b(()=>[e(`div`,Oe,[s(a,{size:`small`,class:`copy-btn`,onClick:n[6]||=e=>i(o)(I.value)},{default:b(()=>[...n[19]||=[r(` 复制 `,-1)]]),_:1})]),e(`pre`,ke,C(i(z)(I.value)),1)]),_:1})):_.value.response.client_stream_frames?.length?(E(),x(k,{key:3,lazy:``,label:`回写客户端(${_.value.response.client_stream_frames.length} 帧)`,name:`clientStream`},{default:b(()=>[e(`div`,Ae,[s(a,{size:`small`,class:`copy-btn`,onClick:n[7]||=e=>i(o)(L.value)},{default:b(()=>[...n[20]||=[r(` 复制 `,-1)]]),_:1})]),e(`pre`,$,C(i(z)(L.value)),1)]),_:1},8,[`label`])):l(``,!0)],64)):(E(),u(m,{key:1},[s(k,{lazy:``,label:`请求体`,name:`request`},{default:b(()=>[e(`div`,je,[s(a,{size:`small`,class:`copy-btn`,onClick:n[8]||=e=>i(o)(R.value)},{default:b(()=>[...n[21]||=[r(` 复制 `,-1)]]),_:1})]),e(`pre`,Me,C(i(z)(R.value)),1)]),_:1}),s(k,{lazy:``,label:`响应体`,name:`response`},{default:b(()=>[e(`div`,Ne,[s(a,{size:`small`,class:`copy-btn`,onClick:n[9]||=e=>i(o)(re.value)},{default:b(()=>[...n[22]||=[r(` 复制 `,-1)]]),_:1})]),e(`pre`,Pe,C(i(z)(re.value)),1)]),_:1})],64))]),_:1},8,[`modelValue`])):l(``,!0)])),[[F,y.value]])]),_:1},8,[`modelValue`])}}}),[[`__scopeId`,`data-v-7e1ff197`]]);o(),k(),a(),y();var Ie={class:`session-table`},Le={class:`group-detail`},Re=[`title`],ze={key:0,class:`detail-error`},Be={class:`detail-footer`},Ve={class:`detail-count`},He=[`title`,`onClick`],Ue=`会话平均生成速度:组内有效请求的输出 token 合计 ÷ 生成窗口合计(按窗口加权,不是各请求速度的算术平均);首 = 组内流式且已采集首 token 的请求的平均首 token 延迟(非流式请求无此观测点,不参与)`,We=50,Ge=_(c({__name:`SessionGroupTable`,props:{groups:{},noSession:{},loading:{type:Boolean},filterParams:{}},emits:[`open-detail`],setup(a,{emit:o}){let c=a,d=o,{copyWithToast:f}=N(),p=S(()=>c.noSession?[...c.groups,c.noSession]:c.groups),m=e=>e.session_id||`__no_session__`,_=n(null),y=D(new Map),T={loading:!1,items:[],total:0,nextPage:1,error:null},O=e=>y.get(m(e))??T,k=async(e,t)=>{let n=(e=>(y.has(e)||y.set(e,{loading:!1,items:[],total:0,nextPage:1,error:null}),y.get(e)))(m(e));if(!n.loading){n.loading=!0,n.error=null;try{let r={...c.filterParams,sort:`time`,order:`desc`,page:String(t),pageSize:String(We)};e.session_id?r.sessionId=e.session_id:r.noSession=`1`;let i=await h.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}}},te=(e,t)=>{t.some(t=>m(t)===m(e))&&O(e).items.length===0&&k(e,1)},ne=e=>{let t=O(e);t.loading||t.items.length>=t.total||k(e,t.nextPage)},A=e=>{_.value?.toggleRowExpansion(e)};return w(()=>p.value.map(m),e=>{let t=new Set(e);for(let e of[...y.keys()])t.has(e)||y.delete(e)}),(n,o)=>{let c=g(`el-table-column`),h=g(`el-tag`),y=g(`el-button`),S=g(`el-table`),w=g(`el-empty`),T=ee(`loading`);return E(),u(`div`,Ie,[p.value.length>0||a.loading?v((E(),x(S,{key:0,ref_key:`tableRef`,ref:_,data:p.value,height:`100%`,"row-key":m,border:``,class:`dense-table`,onExpandChange:te,onRowClick:A},{default:b(()=>[s(c,{type:`expand`},{default:b(({row:t})=>[e(`div`,Le,[v((E(),x(S,{data:O(t).items,size:`small`,border:``,class:`dense-table`},{default:b(()=>[s(c,{label:`时间`,width:`136`,align:`center`},{default:b(({row:e})=>[r(C(i(L)(e.time)),1)]),_:1}),s(c,{prop:`model`,label:`模型`,"min-width":`80`,align:`center`,"show-overflow-tooltip":``}),s(c,{label:`客户端`,width:`136`,align:`center`,"show-overflow-tooltip":``},{default:b(({row:e})=>[r(C(i(ie)(e)),1)]),_:1}),s(c,{label:`状态`,width:`60`,align:`center`},{default:b(({row:e})=>[s(h,{size:`small`,type:e.status>=400?`danger`:e.status>=300?`warning`:`success`},{default:b(()=>[r(C(e.status),1)]),_:2},1032,[`type`])]),_:1}),s(c,{label:`输入`,width:`84`,align:`center`},{default:b(({row:e})=>[r(C(i(G)(e.input_tokens??0)),1)]),_:1}),s(c,{label:`输出`,width:`78`,align:`center`},{default:b(({row:e})=>[r(C(i(G)(e.output_tokens??0)),1)]),_:1}),s(c,{label:`缓存读取`,width:`84`,align:`center`},{default:b(({row:e})=>[r(C(i(G)(e.cache_read_tokens??0)),1)]),_:1}),s(c,{label:`缓存命中率`,width:`88`,align:`center`},{default:b(({row:e})=>[r(C(i(le)(e)),1)]),_:1}),s(c,{label:`请求耗时`,width:`74`,align:`center`},{default:b(({row:e})=>[r(C(i(V)(e.duration)),1)]),_:1}),s(c,{label:`速度`,width:`140`,align:`center`},{default:b(({row:t})=>[e(`div`,{title:i(ue)},C(i(fe)(t.tps,t.ttft)),9,Re)]),_:1}),s(c,{label:`详情`,width:`52`,align:`center`},{default:b(({row:e})=>[s(y,{link:``,type:`primary`,onClick:t=>d(`open-detail`,e)},{default:b(()=>[...o[0]||=[r(`查看`,-1)]]),_:1},8,[`onClick`])]),_:1})]),_:1},8,[`data`])),[[T,O(t).loading]]),O(t).error?(E(),u(`div`,ze,[r(C(O(t).error)+` `,1),s(y,{link:``,type:`primary`,size:`small`,onClick:e=>k(t,1)},{default:b(()=>[...o[1]||=[r(`重试`,-1)]]),_:1},8,[`onClick`])])):l(``,!0),e(`div`,Be,[e(`span`,Ve,`已显示 `+C(O(t).items.length)+` / `+C(O(t).total)+` 条`,1),O(t).items.length<O(t).total?(E(),x(y,{key:0,size:`small`,loading:O(t).loading,onClick:e=>ne(t)},{default:b(()=>[...o[2]||=[r(` 加载更多 `,-1)]]),_:1},8,[`loading`,`onClick`])):l(``,!0)])])]),_:1}),s(c,{label:`Session`,width:`100`,align:`center`},{default:b(({row:e})=>[e.session_id?(E(),u(`span`,{key:0,class:`session-id`,title:`${e.session_id}(点击复制)`,onClick:t(t=>i(f)(e.session_id),[`stop`])},C(i(R)(e.session_id)),9,He)):(E(),x(h,{key:1,size:`small`,type:`info`,title:`未携带会话标识的请求(NULL / 空串 session_id)`},{default:b(()=>[...o[3]||=[r(` 无 Session `,-1)]]),_:1}))]),_:1}),s(c,{label:`请求数`,width:`70`,align:`center`},{default:b(({row:e})=>[r(C(i(G)(e.calls)),1)]),_:1}),s(c,{label:`首次请求`,width:`120`,align:`center`},{default:b(({row:e})=>[r(C(i(L)(e.first_time)),1)]),_:1}),s(c,{label:`最后请求`,width:`120`,align:`center`},{default:b(({row:e})=>[r(C(i(L)(e.last_time)),1)]),_:1}),s(c,{label:`模型`,"min-width":`80`,align:`center`,"show-overflow-tooltip":``},{default:b(({row:e})=>[r(C(i(de)(e.models)),1)]),_:1}),s(c,{label:`客户端`,width:`136`,align:`center`,"show-overflow-tooltip":``},{default:b(({row:e})=>[r(C(i(K)(e.clients)),1)]),_:1}),s(c,{label:`输入`,width:`100`,align:`center`},{default:b(({row:e})=>[r(C(i(G)(e.input_tokens)),1)]),_:1}),s(c,{label:`输出`,width:`90`,align:`center`},{default:b(({row:e})=>[r(C(i(G)(e.output_tokens)),1)]),_:1}),s(c,{label:`缓存读取`,width:`100`,align:`center`},{default:b(({row:e})=>[r(C(i(G)(e.cache_read_tokens)),1)]),_:1}),s(c,{label:`速度`,width:`140`,align:`center`},{default:b(({row:t})=>[e(`div`,{title:Ue},C(i(fe)(t.tps,t.avg_ttft)),1)]),_:1})]),_:1},8,[`data`])),[[T,a.loading]]):(E(),x(w,{key:1,description:`当前筛选下没有日志`}))])}}}),[[`__scopeId`,`data-v-37cd2bcc`]]);o(),k(),y(),a();var Ke={class:`logs-page`},qe={class:`filter-bar`},Je={class:`table-wrap`},Ye=[`onClick`],Xe={key:1},Ze=[`title`,`onClick`],Qe={key:1},$e=[`title`,`onClick`],et={key:1},tt=[`title`],nt={class:`pagination-bar`},rt={class:`pagination-left`},it=_(c({__name:`LogsView`,setup(t){let a=j(),{toast:o}=P(),{copyWithToast:c}=N(),{loadError:p,run:_}=M(),{rangeKey:y,dateRange:w,setRange:D,onRangeChange:k}=I(()=>$()),z=n(`2xx`),B=n(``),H=n(``),U=n(``),W=n(`session`),K=n([]),de=n([]),pe=n(null),q=n(0),me=n(0),J=n(1),Y=n(20),X=n(!1),he=n(null),ge=e=>{he.value?.open(e)},_e=S(()=>{let e=new Set;for(let t of a.suppliers)for(let n of t.models)e.add(n.modelName);for(let t of K.value)t.model&&e.add(t.model);return[...e].sort()}),ve=n([]),ye=S(()=>{let e=new Set(ve.value);for(let t of K.value)t.client&&e.add(t.client);return[...e].sort()}),be=async()=>{try{let e=await h.get(`/api/logs/clients`);ve.value=e.clients||[]}catch{ve.value=[]}},xe=e=>{y.value=``,w.value=e||null,$()},Se=()=>{let e={};w.value&&w.value.length===2&&(e.startDate=w.value[0],e.endDate=w.value[1]),z.value&&(e.status=z.value),B.value&&(e.model=B.value),H.value&&(e.client=H.value);let t=U.value.trim();return t&&(e.sessionId=t),e},Ce=S(()=>Se()),we=F(),Z=()=>_(async()=>{let e=we();X.value=!0;try{let t={...Se(),page:String(J.value),pageSize:String(Y.value)};if(W.value===`session`){let n=new URLSearchParams(t).toString(),r=await h.get(`/api/logs/sessions?`+n);if(!e())return;de.value=r.groups||[],pe.value=r.noSession??null,q.value=r.total||0,me.value=r.rowsTotal||0}else{let n=new URLSearchParams({...t,sort:`time`,order:`desc`}).toString(),r=await h.get(`/api/logs?`+n);if(!e())return;K.value=r.items||[],q.value=r.total||0}}catch(t){if(!e())return;throw t}finally{e()&&(X.value=!1)}}),Te=e=>{W.value!==e&&(W.value=e,J.value=1,Y.value=W.value===`session`?20:50,Z())},Q=n(!1),Ee=S(()=>W.value===`session`?me.value:q.value),De=`本页平均:${ce}(仅流式请求参与);${se}——按本页输出 token 合计 ÷ 生成窗口合计加权,不是逐条速度求平均,失败请求、空回复与流式缺首 token 的行不参与`,Oe=S(()=>ae(K.value)),ke=S(()=>re(K.value)),Ae=async()=>{if(Q.value||Ee.value===0)return;let e=W.value===`session`?`(按筛选行数计,含「无 Session」组)`:``;try{await A.confirm(`将永久清理当前筛选条件下的 ${Ee.value} 条日志${e},清理后不可恢复,请谨慎操作!`,`清理确认`,{confirmButtonText:`确认清理`,cancelButtonText:`取消`,type:`warning`})}catch{return}Q.value=!0;try{let e=new URLSearchParams(Se()).toString(),t=await h.post(`/api/logs/clear?`+e,{});o(`已清理 ${t.deleted??0} 条日志`,`success`),J.value>1&&(J.value=1),Z()}catch(e){o(e.message||`清理失败`,`error`)}finally{Q.value=!1}},$=()=>{J.value=1,be(),Z()},je=()=>{y.value=`today`,w.value=null,z.value=`2xx`,B.value=``,H.value=``,U.value=``,J.value=1,Y.value=W.value===`session`?20:50,D(`today`)};return d(()=>{a.loadProviders().catch(()=>{}),be(),D(`today`)}),(t,n)=>{let a=g(`el-button`),o=g(`el-alert`),d=g(`el-option`),h=g(`el-select`),_=g(`el-date-picker`),S=g(`el-input`),D=g(`el-tooltip`),A=g(`el-button-group`),j=g(`el-card`),M=g(`el-table-column`),N=g(`el-tag`),P=g(`el-table`),F=g(`el-pagination`),I=ee(`loading`);return E(),u(`div`,Ke,[i(p)?(E(),x(o,{key:0,title:i(p),type:`error`,"show-icon":``,closable:!1,class:`mb-16`},{default:b(()=>[s(a,{size:`small`,onClick:Z},{default:b(()=>[...n[10]||=[r(`重试`,-1)]]),_:1})]),_:1},8,[`title`])):l(``,!0),s(j,{shadow:`never`},{default:b(()=>[e(`div`,qe,[s(h,{modelValue:i(y),"onUpdate:modelValue":n[0]||=e=>O(y)?y.value=e:null,placeholder:`时间范围`,clearable:``,style:{width:`114px`},onChange:i(k)},{default:b(()=>[s(d,{label:`今天`,value:`today`}),s(d,{label:`昨天`,value:`yesterday`}),s(d,{label:`前天`,value:`beforeYesterday`}),s(d,{label:`近三天`,value:`last3days`}),s(d,{label:`本周`,value:`week`}),s(d,{label:`本月`,value:`month`})]),_:1},8,[`modelValue`,`onChange`]),s(_,{modelValue:i(w),"onUpdate:modelValue":n[1]||=e=>O(w)?w.value=e:null,type:`daterange`,"value-format":`YYYY-MM-DD`,"range-separator":`至`,"start-placeholder":`开始日期`,"end-placeholder":`结束日期`,style:{width:`240px`},onChange:xe},null,8,[`modelValue`]),s(h,{modelValue:z.value,"onUpdate:modelValue":n[2]||=e=>z.value=e,placeholder:`全部状态`,clearable:``,style:{width:`106px`},onChange:$},{default:b(()=>[s(d,{label:`成功 (2xx)`,value:`2xx`}),s(d,{label:`3xx`,value:`3xx`}),s(d,{label:`4xx`,value:`4xx`}),s(d,{label:`5xx`,value:`5xx`}),s(d,{label:`错误 (4xx+)`,value:`err`})]),_:1},8,[`modelValue`]),s(h,{modelValue:B.value,"onUpdate:modelValue":n[3]||=e=>B.value=e,placeholder:`全部模型`,clearable:``,filterable:``,style:{width:`176px`},onChange:$},{default:b(()=>[(E(!0),u(m,null,T(_e.value,e=>(E(),x(d,{key:e,label:e,value:e},null,8,[`label`,`value`]))),128))]),_:1},8,[`modelValue`]),s(h,{modelValue:H.value,"onUpdate:modelValue":n[4]||=e=>H.value=e,placeholder:`全部客户端`,clearable:``,filterable:``,style:{width:`130px`},onChange:$},{default:b(()=>[(E(!0),u(m,null,T(ye.value,e=>(E(),x(d,{key:e,label:e,value:e},null,8,[`label`,`value`]))),128))]),_:1},8,[`modelValue`]),s(S,{modelValue:U.value,"onUpdate:modelValue":n[5]||=e=>U.value=e,class:`session-input`,placeholder:`Session ID(前缀匹配)`,clearable:``,onKeyup:f($,[`enter`])},null,8,[`modelValue`]),s(A,{class:`view-switch push-right`},{default:b(()=>[s(D,{content:`按会话分组`,placement:`top`,"show-after":300},{default:b(()=>[s(a,{type:W.value===`session`?`primary`:`default`,icon:i(ne),"aria-label":`按会话分组`,onClick:n[6]||=e=>Te(`session`)},null,8,[`type`,`icon`])]),_:1}),s(D,{content:`列表`,placement:`top`,"show-after":300},{default:b(()=>[s(a,{type:W.value===`list`?`primary`:`default`,icon:i(te),"aria-label":`列表视图`,onClick:n[7]||=e=>Te(`list`)},null,8,[`type`,`icon`])]),_:1})]),_:1}),s(a,{type:`primary`,onClick:$},{default:b(()=>[...n[11]||=[r(`搜索`,-1)]]),_:1}),s(a,{onClick:je},{default:b(()=>[...n[12]||=[r(`重置`,-1)]]),_:1})])]),_:1}),s(j,{shadow:`never`,class:`mt-16 table-card`},{default:b(()=>[e(`div`,Je,[W.value===`list`?v((E(),x(P,{key:0,data:K.value,border:``,height:`100%`,class:`dense-table`},{default:b(()=>[s(M,{prop:`id`,label:`ID`,width:`66`,align:`center`},{default:b(({row:e})=>[e.id==null?(E(),u(`span`,Xe,`-`)):(E(),u(`span`,{key:0,class:`request-id`,title:`点击复制(日志 id 同时是响应头 x-request-id,可用于关联控制台日志与检索)`,onClick:t=>i(c)(String(e.id))},C(e.id),9,Ye))]),_:1}),s(M,{prop:`time`,label:`时间`,width:`136`,align:`center`},{default:b(({row:e})=>[r(C(i(L)(e.time)),1)]),_:1}),s(M,{prop:`status`,label:`状态`,width:`60`,align:`center`},{default:b(({row:e})=>[s(N,{size:`small`,type:e.status>=400?`danger`:e.status>=300?`warning`:`success`},{default:b(()=>[r(C(e.status),1)]),_:2},1032,[`type`])]),_:1}),s(M,{label:`Session`,width:`88`,align:`center`},{default:b(({row:e})=>[e.session_id?(E(),u(`span`,{key:0,class:`request-id`,title:`${e.session_id}(点击复制)`,onClick:t=>i(c)(e.session_id)},C(i(R)(e.session_id)),9,Ze)):(E(),u(`span`,Qe,`-`))]),_:1}),s(M,{prop:`model`,label:`模型`,"min-width":`80`,align:`center`,"show-overflow-tooltip":``}),s(M,{label:`客户端`,width:`136`,align:`center`},{default:b(({row:e})=>[e.client||e.user_agent?(E(),u(`span`,{key:0,class:`request-id`,title:i(oe)(e),onClick:t=>i(c)(e.user_agent||e.client)},C(i(ie)(e)),9,$e)):(E(),u(`span`,et,`-`))]),_:1}),s(M,{label:`输入`,width:`84`,align:`center`},{default:b(({row:e})=>[r(C(i(G)(e.input_tokens??0)),1)]),_:1}),s(M,{label:`输出`,width:`78`,align:`center`},{default:b(({row:e})=>[r(C(i(G)(e.output_tokens??0)),1)]),_:1}),s(M,{label:`缓存读取`,width:`84`,align:`center`},{default:b(({row:e})=>[r(C(i(G)(e.cache_read_tokens??0)),1)]),_:1}),s(M,{label:`缓存命中率`,width:`88`,align:`center`},{default:b(({row:t})=>[e(`span`,null,C(i(le)(t)),1)]),_:1}),s(M,{label:`请求耗时`,width:`74`,align:`center`},{default:b(({row:e})=>[r(C(i(V)(e.duration)),1)]),_:1}),s(M,{label:`速度`,width:`140`,align:`center`},{default:b(({row:t})=>[e(`div`,{title:i(ue)},C(i(fe)(t.tps,t.ttft)),9,tt)]),_:1}),s(M,{label:`详情`,width:`52`,align:`center`,fixed:`right`},{default:b(({row:e})=>[s(a,{link:``,type:`primary`,onClick:t=>ge(e)},{default:b(()=>[...n[13]||=[r(`查看`,-1)]]),_:1},8,[`onClick`])]),_:1})]),_:1},8,[`data`])),[[I,X.value]]):l(``,!0),W.value===`session`?(E(),x(Ge,{key:1,groups:de.value,"no-session":pe.value,loading:X.value,"filter-params":Ce.value,onOpenDetail:ge},null,8,[`groups`,`no-session`,`loading`,`filter-params`])):l(``,!0)]),e(`div`,nt,[e(`div`,rt,[s(a,{type:`danger`,plain:``,size:`small`,loading:Q.value,disabled:Ee.value===0,onClick:Ae},{default:b(()=>[...n[14]||=[r(`清理已筛选日志`,-1)]]),_:1},8,[`loading`,`disabled`]),W.value===`list`&&K.value.length?(E(),u(`span`,{key:0,class:`muted-sm page-avg-speed`,title:De},C(i(fe)(Oe.value,ke.value)),1)):l(``,!0)]),s(F,{class:`push-right`,"current-page":J.value,"onUpdate:currentPage":n[8]||=e=>J.value=e,"page-size":Y.value,"onUpdate:pageSize":n[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}),s(Fe,{ref_key:`logDetailRef`,ref:he},null,512)])}}}),[[`__scopeId`,`data-v-0ecff344`]]);export{it as default};
|
package/dist/web-ui/assets/{ManagedServicesView-DIMY-j18.js → ManagedServicesView-Dajk1OlI.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{$ as e,A as t,Et as n,F as r,Ft as i,Gt as a,H as o,I as s,L as c,M as l,N as u,Q as d,T as f,at as p,d as m,gt as h,ht as g,j as _,k as v,ot as y,pn as b,tt as x,yt as S}from"./router-
|
|
1
|
+
import{$ as e,A as t,Et as n,F as r,Ft as i,Gt as a,H as o,I as s,L as c,M as l,N as u,Q as d,T as f,at as p,d as m,gt as h,ht as g,j as _,k as v,ot as y,pn as b,tt as x,yt as S}from"./router-DOdUMO6P.js";import{K as C}from"./message-7_77xsCe.js";import{t as w}from"./index-Bpt0yCG7.js";import{t as T}from"./useManagerApi-jm_MgzHV.js";import{n as E,t as D}from"./useCopyToast-Dkb8g4uG.js";import{t as O}from"./useToast-BxrPRTvE.js";import{g as k}from"./format-Deb1hfjO.js";o(),a(),S();var A={class:`form-hint`},j={key:1,class:`form-hint form-hint--block`},M=m(c({__name:`ManagedServiceModal`,props:{editingName:{},service:{}},emits:[`close`,`saved`],setup(e,{emit:i}){let a=e,o=i,{toast:c}=O(),d=n(),m=n(!1),h=n(!0),y=v(()=>a.service?.pid!=null),S=n({name:a.service?.name??``,exec:a.service?.exec??``,cwd:a.service?.cwd??``,autostart:a.service?.autostart??!0}),C=n((a.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)){c(`请补全标红的必填项`,`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};y.value||(t.start=h.value),m.value=!0;try{a.editingName===null?(await T.createManagedService(t),c(t.start?`服务已添加并启动`:`服务已添加`,`success`)):(await T.updateManagedService(a.editingName,t),c(y.value?`已保存,服务正按新配置重启`:`已保存`,`success`)),o(`saved`)}catch(e){c(e.message||`保存失败`,`error`)}finally{m.value=!1}};return(n,i)=>{let a=p(`el-input`),c=p(`el-form-item`),v=p(`el-switch`),T=p(`el-form`),D=p(`el-button`),O=p(`el-dialog`);return x(),_(O,{"model-value":!0,title:e.editingName?`编辑托管服务`:`添加托管服务`,width:`720px`,top:`6vh`,"align-center":``,"close-on-click-modal":!1,onClose:i[7]||=e=>o(`close`)},{footer:g(()=>[s(D,{disabled:m.value,onClick:i[6]||=e=>o(`close`)},{default:g(()=>[...i[13]||=[r(`取消`,-1)]]),_:1},8,[`disabled`]),s(D,{type:`primary`,loading:m.value,onClick:E},{default:g(()=>[r(b(m.value?`保存中...`:e.editingName?`保存`:`添加服务`),1)]),_:1},8,[`loading`])]),default:g(()=>[s(T,{ref_key:`formRef`,ref:d,model:S.value,rules:w,"label-position":`top`},{default:g(()=>[s(c,{label:`服务名`,prop:`name`},{default:g(()=>[s(a,{modelValue:S.value.name,"onUpdate:modelValue":i[0]||=e=>S.value.name=e,disabled:e.editingName!==null,placeholder:`如 codebuddy-cpa(字母数字开头,可用 . _ -)`},null,8,[`modelValue`,`disabled`]),t(`div`,A,[i[8]||=r(` 名称用于日志文件名(logs/out-<名称>.log)与进程标识;`,-1),e.editingName===null?l(``,!0):(x(),u(f,{key:0},[r(`编辑时不可修改(改名请删除后重新添加)。`)],64))])]),_:1}),s(c,{label:`工作目录`,prop:`cwd`},{default:g(()=>[s(a,{modelValue:S.value.cwd,"onUpdate:modelValue":i[1]||=e=>S.value.cwd=e,placeholder:`如 E:\\gitee\\codebuddy-cpa(服务的运行目录)`},null,8,[`modelValue`]),i[9]||=t(`div`,{class:`form-hint`},`服务在此目录下启动;保存时会校验目录是否存在。`,-1)]),_:1}),s(c,{label:`可执行文件`},{default:g(()=>[s(a,{modelValue:S.value.exec,"onUpdate:modelValue":i[2]||=e=>S.value.exec=e,placeholder:`留空 = 使用 ezllm 主进程的 Node;也可填 npm.cmd 或绝对路径`},null,8,[`modelValue`]),i[10]||=t(`div`,{class:`form-hint`},` 留空时用主进程的 Node 直接运行下方参数(第一个参数通常是脚本相对工作目录的路径)。 Windows 上 .cmd / .bat / 无扩展名的命令(如 npm)会自动经 cmd.exe 执行;其他平台直接执行。 `,-1)]),_:1}),s(c,{label:`参数`},{default:g(()=>[s(a,{modelValue:C.value,"onUpdate:modelValue":i[3]||=e=>C.value=e,type:`textarea`,rows:3,placeholder:`每行一个参数,如:
|
|
4
4
|
src/proxy.js
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{A as e,Et as t,F as n,Ft as r,Gt as i,H as a,I as o,L as s,M as c,N as l,Q as u,S as ee,T as d,Y as te,at as f,cn as ne,d as re,h as ie,ht as p,j as m,k as h,pn as g,rt as _,tt as v,yt as y}from"./router-
|
|
1
|
+
import{A as e,Et as t,F as n,Ft as r,Gt as i,H as a,I as o,L as s,M as c,N as l,Q as u,S as ee,T as d,Y as te,at as f,cn as ne,d as re,h as ie,ht as p,j as m,k as h,pn as g,rt as _,tt as v,yt as y}from"./router-DOdUMO6P.js";import{K as ae,W as oe}from"./message-7_77xsCe.js";import{t as se}from"./index-Bpt0yCG7.js";import{t as b}from"./useManagerApi-jm_MgzHV.js";import{n as x,t as ce}from"./providers-Dx3XtxJu.js";import{t as le}from"./useToast-BxrPRTvE.js";import{a as ue,c as de,d as S,f as C,i as fe,l as w,n as pe,o as me,p as T,s as he,u as ge}from"./pluginProviders-DFVS7pcs.js";y();var E=`https://raw.githubusercontent.com/magpie-community/plugins/main/registry.json`,D=[`https://gh-proxy.com/${E}`,`https://ghfast.top/${E}`,E],_e=1e4,ve=`plugin_market_cache`,ye=2,be=216e5,xe=36e5,O=[`provider`];function k(){try{let e=localStorage.getItem(ve);if(e===null)return null;let t=JSON.parse(e);if(t.version!==ye||!Array.isArray(t.entries))return null;let n=t.fetchedAt;return n===void 0||typeof n.at!=`number`?null:{version:ye,entries:t.entries.filter(M),fetchedAt:n}}catch{return null}}function Se(e,t){try{let n={version:ye,entries:e,fetchedAt:t};localStorage.setItem(ve,JSON.stringify(n))}catch{}}function A(e){return typeof e==`string`&&e.trim()!==``?e.trim():null}function Ce(e){if(typeof e!=`object`||!e||Array.isArray(e))return null;let t=e;return A(t.zh)??A(t.en)}function we(e){switch(e){case`provider`:case`middleware`:case`agent`:case`tools`:case`page`:return e;default:return`provider`}}function j(e){return O.includes(e)}function M(e){if(typeof e!=`object`||!e)return!1;let t=e.kind;return typeof t==`string`&&j(t)}function N(e){let t=A(e.package);if(t===null)return null;let n=Array.isArray(e.providers)?e.providers.filter(e=>typeof e==`string`):[];return{package:t,name:A(e.name)??t,icon:A(e.icon),providers:n,community:A(e.community),summary:Ce(e.summary),kind:we(e.kind),replaces:A(e.replaces),version:null,license:null,description:null,homepage:null,weeklyDownloads:null,published:null}}var P=new Map,F=new Map;async function I(e){let t=P.get(e);if(t!==void 0&&Date.now()-t.at<xe)return t.meta;try{let t=await S(`https://registry.npmjs.org/${encodeURIComponent(e)}`),n={version:A(t[`dist-tags`]?.latest),license:A(t.license),description:A(t.description),homepage:A(t.homepage),published:!0};return P.set(e,{at:Date.now(),meta:n}),n}catch(t){let n={version:null,license:null,description:null,homepage:null,published:T(t)!==404&&null};return n.published===!1&&P.set(e,{at:Date.now(),meta:n}),n}}async function Te(e){let t=F.get(e);if(t!==void 0&&Date.now()-t.at<xe)return t.downloads;try{let t=await S(`https://api.npmjs.org/downloads/point/last-week/${encodeURIComponent(e)}`),n=typeof t.downloads==`number`?t.downloads:null;return F.set(e,{at:Date.now(),downloads:n}),n}catch{return null}}async function Ee(){let e=[];for(let t of D)try{let e=await S(t,{timeoutMs:_e});return t!==D[0]&&x(`[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(D.length)} 个源):\n${e.join(`
|
|
2
2
|
`)}`)}async function L(e){let{registry:t,source:n}=await Ee(),r=t.plugins;if(!Array.isArray(r))throw Error(`清单格式不是预期形状(缺 plugins 数组):${E}`);let i=r.map(e=>typeof e==`object`&&e?N(e):null).filter(M).sort((e,t)=>e.package.localeCompare(t.package)),a=0;return await Promise.all(i.map(async t=>{let[n,r]=await Promise.all([I(t.package),Te(t.package)]);Object.assign(t,n,{weeklyDownloads:r}),a+=1,e?.(a,i.length)})),{entries:i,source:n}}var R=t([]),z=t(!1),B=t(null),De=t({loaded:0,total:0}),V=t(null),Oe=t(!1),H=null;function U(e,t){JSON.stringify(e)!==JSON.stringify(R.value)&&(R.value=e),V.value=t,Se(e,t)}async function ke(e={}){let t=e.force===!0,n=R.value.length===0?k():null;n!==null&&(R.value=n.entries,V.value=n.fetchedAt);let r=R.value.length>0,i=V.value,a=i!==null&&Date.now()-i.at<be;if(!(!t&&r&&a)){if(H!==null){if(t)await H;else return}if(t||!r){z.value=!0,Oe.value=!1,De.value={loaded:0,total:0};try{let e=await L((e,t)=>{De.value={loaded:e,total:t}});U(e.entries,{source:e.source,at:Date.now()}),B.value=null}catch(e){B.value=`插件市场清单加载失败:${e instanceof Error?e.message:String(e)}`}finally{z.value=!1}return}Oe.value=!0,H=(async()=>{try{let e=await L();U(e.entries,{source:e.source,at:Date.now()}),B.value=null,Oe.value=!1}catch(e){x(`[plugin-market] 后台刷新失败,继续用缓存:${e instanceof Error?e.message:String(e)}`)}finally{H=null}})()}}function Ae(){return{entries:R,loading:z,marketError:B,progress:De,fetchedAt:V,stale:Oe,loadMarket:ke}}async function je(e){let t=e.timeoutMs??2e4,n=e.intervalMs??400,r=e.now??Date.now,i=e.sleep??(e=>new Promise(t=>setTimeout(t,e))),a=r()+t;for(;;)try{return await e.probe(),!0}catch{if(r()>=a)return!1;await i(n)}}a(),y(),i(),ie();var Me={class:`page-head`},Ne={class:`page-head-actions`},Pe={key:0,class:`tab-count`},Fe={key:1,class:`loading-block`},Ie={key:3},Le={class:`tab-toolbar`},Re={class:`installed-summary`},ze={class:`installed-summary-ok`},Be={class:`tab-actions`},Ve={class:`installed-list`},He={class:`installed-head`},Ue={class:`installed-avatar`},We={class:`installed-identity`},Ge={class:`installed-title`},Ke=[`title`],qe={class:`installed-version`},Je=[`title`],Ye=[`title`],Xe={class:`installed-ops`},Ze={key:0,class:`installed-noprovider`},Qe={key:1,class:`installed-providers`},$e={class:`installed-provider-info`},et=[`title`],tt={class:`installed-provider-models`},nt={class:`installed-provider-actions`},rt={key:0,class:`tab-count`},it={class:`tab-toolbar`},at={class:`muted-sm`},ot={key:0,class:`loading-block`},st={key:2,class:`plugin-grid`},ct={class:`card-top`},lt={class:`plugin-icon`},ut=[`src`,`alt`,`onError`],dt={key:1},ft={class:`plugin-titles`},pt=[`title`],mt={class:`plugin-tags`},ht={class:`plugin-action`},gt=[`title`],_t={class:`plugin-meta`},vt={key:0},yt={key:1,class:`mono`},bt={key:2,class:`muted-disabled`},xt={key:3,class:`muted-disabled`},St={class:`method-list`},Ct={class:`muted-sm`},wt={key:0,class:`muted-sm`},Tt={class:`muted-sm`},Et={class:`muted-sm`},Dt={key:0,class:`mt-8`},Ot=[`href`],kt={key:2,class:`muted-sm mt-8`},At=9e5,jt=9e5,Mt=5e3,Nt=5e3,Pt=re(s({__name:`PluginsView`,setup(i){let{toast:a}=le(),s=ce(),re=t(!0),ie=t(`服务未由 ezllm 主进程托管(源码运行模式);请用 ezllm 启动服务`),y=t(!1),x=t(null),{entries:T,loading:E,marketError:D,progress:_e,fetchedAt:ve,stale:ye,loadMarket:be}=Ae(),xe=t(new Set),O=t([]),k=t(null),Se=t(!1),A=h(()=>{let e=O.value.flatMap(e=>e.providers);return{total:e.length,signedIn:e.filter(e=>e.signedIn).length}}),Ce=e=>T.value.find(t=>t.package===e)?.name??e.replace(/^@[^/]+\//,``),we=e=>{let t=Ce(e).trim();return t===``?`?`:t.charAt(0).toUpperCase()},j=t(null),M=t(!1),N=t(``),P=t(`installed`),F=t(!1),I=t({}),Te=t(!1),Ee=t(!0),L=h(()=>y.value&&x.value!==null),R=e=>O.value.some(t=>t.package===e.package),z=h(()=>T.value.filter(e=>!R(e))),B=e=>e.icon===null||xe.value.has(e.package)?null:/^https?:\/\//i.test(e.icon)?e.icon:null,De=e=>e.icon!==null&&!/^https?:\/\//i.test(e.icon)?e.icon:(e.name.charAt(0)||`?`).toUpperCase(),V=e=>{xe.value=new Set(xe.value).add(e.package)},Oe=e=>e>=1e3?`${(e/1e3).toFixed(e>=1e4?0:1)}k`:String(e),H=async()=>{try{let e=await b.plugins();re.value=!0,y.value=e.running,x.value=e.port}catch(e){if(typeof e?.message==`string`&&e.message.includes(`未由 ezllm 主进程托管`)){re.value=!1,ie.value=e.message,y.value=!1,x.value=null;return}throw e}},U=async()=>{if(!L.value){O.value=[],k.value=null,Se.value=!1;return}let e=x.value;if(e!==null){Se.value=!0;try{let t=await S(w(e,`/packages`));O.value=Array.isArray(t.packages)?t.packages:[],k.value=null}catch(e){O.value=[],k.value=`无法读取已装插件(插件服务可能正在重启):${e?.message??`请求失败`}`}finally{Se.value=!1}}},ke=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()},Pt=h(()=>{if(E.value)return`正在加载 ${String(_e.value.loaded)}/${String(_e.value.total)}…`;let e=ve.value===null?``:ke(ve.value.at),t=e===``?``:` · ${e}更新`,n=ye.value?` · 更新中…`:``;return`清单 ${String(T.value.length)} 个 · 已装 ${String(O.value.length)} 个${t}${n}`}),Ft=async(e=!1)=>{await be({force:e})},It=async()=>{try{await H()}catch{}await Promise.all([U(),Ft(!0)])},Lt=async()=>{try{await H()}catch(e){D.value=e?.message??`插件服务状态加载失败`;return}await U(),await Ft(),W()},Rt=t(!1),zt=async e=>{let t=await S(w(e,`/plugins`));return Array.isArray(t.providers)?t.providers:[]},Bt=async(e,t)=>{try{let n=await S(`${me(t,e)}/v1/models`,{timeoutMs:Mt}),r=(n.data??[]).map(e=>typeof e.id==`string`?e.id.trim():``).filter(e=>e!==``);return{fromHook:n.fromHook===!0,ids:r}}catch{return null}},Vt=async()=>{let e=x.value;if(L.value&&e!==null){Rt.value=!0;try{await s.loadProviders();let t=await zt(e),n=ue(s.suppliers,t,e),r=t.filter(e=>e.protocol!==null&&n.providers.filter(t=>he(t.apiBase)===e.id).some(t=>pe(t,e))),i=new Map;await Promise.all(r.map(async t=>{let n=await Bt(t.id,e);n!==null&&i.set(t.id,n)}));let o=fe(n.providers,t,i);if(n.added.length===0&&n.updated.length===0&&o.refreshed.length===0)return;await s.mutateProviders(n=>{let r=ue(n,t,e);return fe(r.providers,t,i).providers});let c=[];n.added.length>0&&c.push(`新增 ${String(n.added.length)} 个供应商`),n.updated.length>0&&c.push(`修正 ${String(n.updated.length)} 个供应商`),o.refreshed.length>0&&c.push(`刷新 ${String(o.refreshed.length)} 个供应商的模型清单`),a(`已接入网关:${c.join(`、`)}`,`success`)}catch(e){a(e?.message??`供应商配置同步失败`,`error`)}finally{Rt.value=!1}}},Ht=null,W=()=>(Ht===null&&(Ht=Vt().finally(()=>{Ht=null})),Ht),Ut=e=>je({probe:()=>S(w(e,`/health`),{timeoutMs:2e3})}),Wt=async()=>{try{let e=await b.plugins();return{pid:e.pid,startedAt:e.startedAt}}catch{return null}},Gt=(e,t)=>!(e.pid!==null&&t.pid!==null&&e.pid!==t.pid||e.startedAt!==null&&t.startedAt!==null&&e.startedAt!==t.startedAt),Kt=(e,t,n)=>je({timeoutMs:n,probe:async()=>{let n=await b.plugins();if(!n.running||n.port!==e||Gt(t,{pid:n.pid,startedAt:n.startedAt}))throw Error(`宿主尚未完成重启`)}}),qt=async(e,t)=>(t!==null&&await Kt(e,t,Nt),await Ut(e)),Jt=async(e,t)=>await qt(e,t)?(await U(),!0):(k.value=`插件服务未确认完成重启,请稍后点「刷新」或重新打开本页`,!1),Yt=async(e,t)=>{try{let n=e;try{let e=await b.plugins();if(t!==null&&e.running&&!Gt(t,{pid:e.pid,startedAt:e.startedAt}))y.value=e.running,x.value=e.port,n=e.port;else{let e=await b.restartPlugins();y.value=e.running,x.value=e.port,n=e.port}}catch{let e=await b.restartPlugins();y.value=e.running,x.value=e.port,n=e.port}return await Jt(n,t)}catch(e){return k.value=`插件服务重启失败:${e?.message??`请求失败`}`,!1}},Xt=async e=>{await Qt(e.package)},Zt=async()=>{let e=N.value.trim();if(e!==``){F.value=!0;try{await Qt(e),M.value=!1,N.value=``}finally{F.value=!1}}},Qt=async e=>{let t=x.value;if(t===null){a(`插件服务未开启`,`error`);return}j.value=e;try{let n=await Wt(),r=await C(w(t,`/packages`),{package:e},`POST`,{timeoutMs:At}),i=r.restartRequested!==!0||await Yt(t,n);r.restartRequested!==!0&&await U(),r.loaded===!1?a(`${e} 已安装但未加载成功(重启插件服务或查看日志)`,`warning`):i?a(`已安装 ${e}`,`success`):a(`${e} 已安装,但未能确认插件服务已完成重启;稍后刷新即可`,`warning`),i&&await W()}catch(e){a(e?.message??`安装失败`,`error`)}finally{j.value=null}},$t=async e=>{let t=x.value;if(t===null)return;let n=[];try{await s.loadProviders(),n=de(s.suppliers,e.providers.map(e=>e.id))}catch{}let r=n.length===0?``:`网关里对应的供应商(${n.join(`、`)})也会一并移除。`;try{await se.confirm(`确定卸载 ${e.package}?该插件提供的模型将不可用。${r}`,`确认卸载`,{confirmButtonText:`卸载`,cancelButtonText:`取消`,type:`warning`})}catch{return}j.value=e.package;try{let r=await Wt(),i=await ge(w(t,`/packages/${encodeURIComponent(e.package)}`),{timeoutMs:At});n.length>0&&await s.mutateProviders(e=>e.filter(e=>!n.includes(e.name))),a(`已卸载 ${e.package}`,`success`),i.restartRequested===!0?await Yt(t,r)||a(`插件服务未确认完成重启;稍后刷新即可`,`warning`):await U()}catch(e){a(e?.message??`卸载失败`,`error`)}finally{j.value=null}},en=(e,t)=>{e===`uninstall`&&$t(t)},tn=()=>{N.value=``,M.value=!0},nn=h(()=>L.value?Ee.value?`检查已装插件是否有新版本`:`宿主当前无法检查更新`:`插件服务未开启`),rn=e=>{let t=I.value[e];return t&&t.updateAvailable&&t.latest?t.latest:null},an=async(e=!1)=>{let t=x.value;if(t===null){e||a(`插件服务未开启`,`error`);return}Te.value=!0;try{let n=await S(w(t,`/packages/updates`),{timeoutMs:jt}),r=Array.isArray(n.packages)?n.packages:[];Ee.value=n.canCheck;let i={};for(let e of r)i[e.package]=e;if(I.value=i,e)return;if(!n.canCheck){a(`宿主当前无法检查更新`,`warning`);return}if(r.length>0&&r.every(e=>e.latest===null)){a(`检查失败:${String(r.length)} 个插件都未能取到 npm 版本(网络或 npm 源不可达)`,`error`);return}let o=r.filter(e=>e.updateAvailable).length,s=r.filter(e=>e.latest===null).length,c=s>0?`(${String(s)} 个未取到版本,可能网络异常)`:``;a(o>0?`发现 ${String(o)} 个插件有新版本${c}`:`全部插件已是最新${c}`,`success`)}catch(t){e||a(t?.message??`检查更新失败`,`error`)}finally{Te.value=!1}},on=async e=>{let t=x.value,n=I.value[e]?.latest;if(t===null){a(`插件服务未开启`,`error`);return}if(n!=null){j.value=e;try{let r=await Wt();if(await C(w(t,`/packages`),{package:e,version:n},`POST`,{timeoutMs:At}),delete I.value[e],!await Yt(t,r)){a(`已更新到 ${n},但未能确认插件服务已完成重启;稍后刷新即可`,`warning`);return}a(`已更新到 ${n} 并重启插件服务`,`success`),await W(),await an(!0)}catch(e){a(e?.message??`更新失败`,`error`)}finally{j.value=null}}},sn=t(null),cn=t(!1),ln=t(``),un=t([]),G=t(!1),dn=t(``),K=t(``),fn=t(``),q=t(null),J=t(!1),pn=t(``),mn=t(``),hn=t(``),gn=t(``),_n=t(void 0),vn=t({}),Y=t(null),yn=t(!1),X=t(!1),bn=t(``),xn=t([]),Z=t({}),Sn=t(void 0),Q=t(null),Cn=t(!1),$=new Map,wn=!1,Tn=e=>{$.set(e,($.get(e)??0)+1)};te(()=>{wn=!0,$.clear()});let En=(e,t)=>{K.value!==``&&K.value!==e&&Tn(K.value),K.value=e,dn.value=t.url??``,fn.value=t.instructions??``,q.value=null,G.value=!0},Dn=async e=>{let t=x.value;if(t===null)return;let n=($.get(e)??0)+1;$.set(e,n);let r=()=>!wn&&$.get(e)===n,i=Date.now()+18e4;for(;;){if(await new Promise(e=>setTimeout(e,2e3)),!r())return;let n;try{n=await S(w(t,`/login/${encodeURIComponent(e)}`))}catch(t){r()&&K.value===e&&(q.value=t?.message??`查询登录状态失败`);return}if(!r())return;if(n.state===`success`){K.value===e&&(G.value=!1),a(`已登录${n.accountId?`(${n.accountId})`:``}`,`success`),await U(),await W();return}if(n.state===`failed`){K.value===e&&(q.value=n.error??`登录失败`);return}if(Date.now()>i){K.value===e&&(q.value=`等待超时,可关闭后重新点击「登录」`);return}}},On=async(e,t,n,r)=>{let i=x.value;if(i===null){a(`插件服务未开启`,`error`);return}Tn(e);let o={};t!==void 0&&(o.method=t),Object.keys(n).length>0&&(o.inputs=n),r!==void 0&&r!==``&&(o.key=r);let s=await C(w(i,`/login/${encodeURIComponent(e)}`),o);if(s.needMethod===!0){ln.value=e,un.value=s.methods,cn.value=!0;return}if(s.needInputs!==void 0&&s.needInputs.length>0){J.value=!1,bn.value=e,Sn.value=t,xn.value=s.needInputs;let r={...s.inputs??n};for(let e of s.needInputs)r[e.key]=r[e.key]??``;Z.value=r,Q.value=null,X.value=!0;return}if(s.needKey===!0){X.value=!1,pn.value=e,_n.value=t,mn.value=s.label??``,hn.value=s.placeholder??``,vn.value={...s.inputs??n},gn.value=``,Y.value=null,J.value=!0;return}if(s.state===`success`){X.value=!1,J.value=!1,a(`已登录${s.accountId?`(${s.accountId})`:``}`,`success`),await U(),await W();return}if(s.state===`failed`){let e=s.error??`登录失败`;if(J.value){Y.value=e;return}if(X.value){Q.value=e;return}a(e,`error`);return}X.value=!1,J.value=!1,En(e,s),Dn(e)},kn=async(e,t)=>{sn.value=e;try{await On(e,t,{})}catch(e){a(e?.message??`发起登录失败`,`error`)}finally{sn.value=null}},An=t(null),jn=async e=>{let t=x.value;if(t===null){a(`插件服务未开启`,`error`);return}try{await se.confirm(`确定退出 ${e.id} 的登录?本机保存的凭据会被删除,该供应商的模型将立即不可用(插件与网关配置保留)。`,`确认退出登录`,{confirmButtonText:`退出登录`,cancelButtonText:`取消`,type:`warning`})}catch{return}Tn(e.id),K.value===e.id&&(G.value=!1),An.value=e.id;try{await ge(w(t,`/login/${encodeURIComponent(e.id)}`)),a(`已退出 ${e.id} 的登录`,`success`),await U()}catch(e){let t=String(e?.message??``);a(t.includes(`405`)?`当前插件服务版本不支持退出登录,请先升级 ezllm`:e?.message??`退出登录失败`,`error`)}finally{An.value=null}},Mn=async e=>{cn.value=!1,await kn(ln.value,e)},Nn=async()=>{Cn.value=!0;try{await On(bn.value,Sn.value,{...Z.value})}catch(e){Q.value=e?.message??`提交失败`}finally{Cn.value=!1}},Pn=async()=>{if(gn.value.trim()===``){Y.value=`请填写密钥`;return}yn.value=!0,Y.value=null;try{await On(pn.value,_n.value,{...vn.value},gn.value)}catch(e){Y.value=e?.message??`提交失败`}finally{yn.value=!1}};return u(Lt),(t,i)=>{let a=f(`el-icon`),s=f(`el-button`),u=f(`el-alert`),te=f(`el-empty`),h=f(`el-tag`),se=f(`el-dropdown-item`),b=f(`el-dropdown-menu`),x=f(`el-dropdown`),ce=f(`el-tab-pane`),le=f(`el-tabs`),ue=f(`el-input`),de=f(`el-form-item`),S=f(`el-form`),C=f(`el-dialog`),fe=f(`el-option`),w=f(`el-select`);return v(),l(`div`,null,[e(`div`,Me,[i[20]||=e(`div`,null,[e(`div`,{class:`page-head-title`},`插件`),e(`div`,{class:`page-head-sub`},` 订阅社区 OpenCode 插件——把订阅账号(CodeBuddy、智谱 Coding Plan 等)当作供应商接入网关 `)],-1),e(`div`,Ne,[o(s,{disabled:!y.value,onClick:tn},{default:p(()=>[o(a,null,{default:p(()=>[o(r(ae))]),_:1}),i[18]||=n(` 手动安装 `,-1)]),_:1},8,[`disabled`]),o(s,{loading:r(E),onClick:It},{default:p(()=>[...i[19]||=[n(`刷新`,-1)]]),_:1},8,[`loading`])])]),re.value?y.value?c(``,!0):(v(),m(u,{key:1,type:`info`,"show-icon":``,closable:!1,class:`mb-16`,title:`插件服务未运行`},{default:p(()=>[...i[21]||=[e(`div`,{class:`muted-sm`},` 插件服务与设置页「显示插件入口」共用同一配置:开关开启时随服务启动自动拉起。如仍不可用,请查看日志或重启服务。 `,-1)]]),_:1})):(v(),m(u,{key:0,type:`warning`,"show-icon":``,closable:!1,class:`mb-16`,title:`插件服务不可用`},{default:p(()=>[n(g(ie.value),1)]),_:1})),r(D)?(v(),m(u,{key:2,type:`error`,"show-icon":``,closable:!1,class:`mb-16`,title:r(D)},{default:p(()=>[o(s,{size:`small`,onClick:Ft},{default:p(()=>[...i[22]||=[n(`重试`,-1)]]),_:1})]),_:1},8,[`title`])):c(``,!0),o(le,{modelValue:P.value,"onUpdate:modelValue":i[4]||=e=>P.value=e,class:`plugin-tabs`},{default:p(()=>[o(ce,{name:`installed`},{label:p(()=>[i[23]||=n(` 已安装 `,-1),O.value.length>0?(v(),l(`span`,Pe,g(O.value.length),1)):c(``,!0)]),default:p(()=>[k.value?(v(),m(u,{key:0,type:`warning`,"show-icon":``,closable:!1,class:`installed-error`,title:k.value},null,8,[`title`])):c(``,!0),Se.value&&O.value.length===0?(v(),l(`div`,Fe,`正在读取已装插件…`)):O.value.length===0&&!k.value?(v(),m(te,{key:2,description:`尚未安装任何插件`,"image-size":80},{default:p(()=>[o(s,{type:`primary`,onClick:i[0]||=e=>P.value=`market`},{default:p(()=>[n(g(L.value?`去安装插件`:`查看插件清单`),1)]),_:1})]),_:1})):c(``,!0),O.value.length>0?(v(),l(`div`,Ie,[e(`div`,Le,[e(`span`,Re,[n(g(O.value.length)+` 个插件 · `+g(A.value.total)+` 个供应商 · `,1),e(`span`,ze,g(A.value.signedIn)+` 个已登录`,1)]),e(`div`,Be,[o(s,{size:`small`,disabled:!L.value||Rt.value,loading:Rt.value,title:`把宿主已加载的插件供应商补进网关配置:缺的整条新增,已在的只修地址/协议(模型清单保持你的选择)`,onClick:W},{default:p(()=>[...i[24]||=[n(`接入网关`,-1)]]),_:1},8,[`disabled`,`loading`]),o(s,{size:`small`,disabled:!L.value||!Ee.value||j.value!==null,loading:Te.value,title:nn.value,onClick:i[1]||=e=>an()},{default:p(()=>[...i[25]||=[n(`检查更新`,-1)]]),_:1},8,[`disabled`,`loading`,`title`])])]),e(`div`,Ve,[(v(!0),l(d,null,_(O.value,t=>(v(),l(`div`,{key:t.package,class:`installed-card`},[e(`div`,He,[e(`div`,Ue,g(we(t.package)),1),e(`div`,We,[e(`div`,Ge,[e(`span`,{class:`installed-name`,title:t.package},g(Ce(t.package)),9,Ke),e(`span`,qe,`v`+g(t.version||`-`),1),t.loaded?c(``,!0):(v(),m(h,{key:0,type:`danger`,size:`small`,"disable-transitions":``},{default:p(()=>[...i[26]||=[n(`加载失败`,-1)]]),_:1}))]),t.description?(v(),l(`div`,{key:0,class:`installed-desc`,title:t.description},g(t.description),9,Je)):c(``,!0),Ce(t.package)===t.package?c(``,!0):(v(),l(`div`,{key:1,class:`mono installed-pkgname`,title:t.package},g(t.package),9,Ye))]),e(`div`,Xe,[rn(t.package)?(v(),m(s,{key:0,link:``,type:`primary`,size:`small`,disabled:j.value!==null||Te.value,loading:j.value===t.package,onClick:e=>on(t.package)},{default:p(()=>[n(`更新到 `+g(rn(t.package)),1)]),_:2},1032,[`disabled`,`loading`,`onClick`])):c(``,!0),o(x,{trigger:`click`,placement:`bottom-end`,onCommand:e=>en(e,t)},{dropdown:p(()=>[o(b,null,{default:p(()=>[o(se,{command:`uninstall`,disabled:j.value!==null},{default:p(()=>[...i[27]||=[e(`span`,{class:`danger-text`},`卸载插件`,-1)]]),_:1},8,[`disabled`])]),_:1})]),default:p(()=>[o(s,{link:``,size:`small`,class:`card-more`,title:`更多操作`},{default:p(()=>[o(a,null,{default:p(()=>[o(r(oe))]),_:1})]),_:1})]),_:1},8,[`onCommand`])])]),t.providers.length?(v(),l(`div`,Qe,[(v(!0),l(d,null,_(t.providers,t=>(v(),l(`div`,{key:t.id,class:`installed-provider`},[e(`div`,$e,[e(`span`,{class:`mono installed-provider-id`,title:t.id},g(t.id),9,et),e(`span`,tt,g(t.models)+` 个模型`,1)]),e(`div`,nt,[e(`span`,{class:ne([`installed-state`,{"is-on":t.signedIn}])},[e(`span`,{class:ne([`status-dot`,{running:t.signedIn}])},null,2),e(`span`,null,g(t.signedIn?`已登录`:t.needsLogin===!1?`无需登录`:`未登录`),1)],2),t.signedIn?(v(),m(s,{key:0,link:``,size:`small`,loading:An.value===t.id,onClick:e=>jn(t)},{default:p(()=>[...i[28]||=[n(`退出登录`,-1)]]),_:1},8,[`loading`,`onClick`])):t.needsLogin===!1?c(``,!0):(v(),m(s,{key:1,link:``,type:`primary`,size:`small`,loading:sn.value===t.id,onClick:e=>kn(t.id)},{default:p(()=>[...i[29]||=[n(`登录`,-1)]]),_:1},8,[`loading`,`onClick`]))])]))),128))])):(v(),l(`div`,Ze,`未声明可用的供应商`))]))),128))])])):c(``,!0)]),_:1}),o(ce,{name:`market`,lazy:``},{label:p(()=>[i[30]||=n(` 未安装 `,-1),z.value.length>0?(v(),l(`span`,rt,g(z.value.length),1)):c(``,!0)]),default:p(()=>[e(`div`,it,[e(`span`,at,g(Pt.value),1)]),r(E)&&r(T).length===0?(v(),l(`div`,ot,`正在从社区清单加载…`)):z.value.length===0?(v(),m(te,{key:1,description:r(T).length===0?`清单里没有本宿主支持的插件`:`社区清单里的插件都已安装`,"image-size":80},{default:p(()=>[r(T).length===0?(v(),m(s,{key:0,loading:r(E),onClick:i[2]||=e=>Ft(!0)},{default:p(()=>[...i[31]||=[n(`刷新清单`,-1)]]),_:1},8,[`loading`])):(v(),m(s,{key:1,onClick:i[3]||=e=>P.value=`installed`},{default:p(()=>[...i[32]||=[n(`查看已安装`,-1)]]),_:1}))]),_:1},8,[`description`])):(v(),l(`div`,st,[(v(!0),l(d,null,_(z.value,t=>(v(),l(`div`,{key:t.package,class:`plugin-card`},[e(`div`,ct,[e(`div`,lt,[B(t)?(v(),l(`img`,{key:0,src:B(t),alt:t.name,onError:e=>V(t)},null,40,ut)):(v(),l(`span`,dt,g(De(t)),1))]),e(`div`,ft,[e(`div`,{class:`plugin-name`,title:t.name},g(t.name),9,pt),e(`div`,mt,[t.community?(v(),m(h,{key:0,size:`small`,type:`info`,"disable-transitions":``},{default:p(()=>[n(g(t.community),1)]),_:2},1024)):c(``,!0)])]),e(`div`,ht,[o(s,{type:`primary`,size:`small`,disabled:!L.value||j.value===t.package||t.published===!1,loading:j.value===t.package,title:t.published===!1?`该包在 npm 上不存在(可能是清单条目尚未发布)`:void 0,onClick:e=>Xt(t)},{default:p(()=>[...i[33]||=[n(` 安装 `,-1)]]),_:1},8,[`disabled`,`loading`,`title`,`onClick`])])]),e(`div`,{class:`plugin-summary`,title:t.summary??``},g(t.summary??`(清单未提供简介)`),9,gt),e(`div`,_t,[e(`span`,null,`供应商 `+g(t.providers.length),1),t.weeklyDownloads===null?c(``,!0):(v(),l(`span`,vt,g(Oe(t.weeklyDownloads))+`/周`,1)),t.version?(v(),l(`span`,yt,`v`+g(t.version),1)):t.published===!1?(v(),l(`span`,bt,`npm 上不存在`)):(v(),l(`span`,xt,`版本未知`))])]))),128))]))]),_:1})]),_:1},8,[`modelValue`]),o(C,{modelValue:M.value,"onUpdate:modelValue":i[7]||=e=>M.value=e,title:`手动安装插件`,width:`520px`},{footer:p(()=>[o(s,{onClick:i[6]||=e=>M.value=!1},{default:p(()=>[...i[35]||=[n(`取消`,-1)]]),_:1}),o(s,{type:`primary`,loading:F.value,disabled:N.value.trim()===``,onClick:Zt},{default:p(()=>[...i[36]||=[n(` 安装 `,-1)]]),_:1},8,[`loading`,`disabled`])]),default:p(()=>[o(S,{"label-position":`top`},{default:p(()=>[o(de,{label:`npm 包名`},{default:p(()=>[o(ue,{modelValue:N.value,"onUpdate:modelValue":i[5]||=e=>N.value=e,placeholder:`例:@magpie-community/opencode-workbuddy-auth`,clearable:``},null,8,[`modelValue`]),i[34]||=e(`div`,{class:`muted-sm`},[n(`可带版本(`),e(`span`,{class:`mono`},`name@1.2.3`),n(`);清单加载不出来时用这个。`)],-1)]),_:1})]),_:1})]),_:1},8,[`modelValue`]),o(C,{modelValue:cn.value,"onUpdate:modelValue":i[9]||=e=>cn.value=e,title:`选择登录方式`,width:`460px`},{footer:p(()=>[o(s,{onClick:i[8]||=e=>cn.value=!1},{default:p(()=>[...i[37]||=[n(`取消`,-1)]]),_:1})]),default:p(()=>[i[38]||=e(`div`,{class:`muted-sm`},`该插件提供多种登录方式,选一种:`,-1),e(`div`,St,[(v(!0),l(d,null,_(un.value,e=>(v(),m(s,{key:e.label,class:`method-btn`,onClick:t=>Mn(e.label)},{default:p(()=>[n(g(e.label||e.type),1)]),_:2},1032,[`onClick`]))),128))])]),_:1},8,[`modelValue`]),o(C,{modelValue:X.value,"onUpdate:modelValue":i[11]||=e=>X.value=e,title:`登录 ${bn.value}`,width:`480px`},{footer:p(()=>[o(s,{onClick:i[10]||=e=>X.value=!1},{default:p(()=>[...i[39]||=[n(`取消`,-1)]]),_:1}),o(s,{type:`primary`,loading:Cn.value,onClick:Nn},{default:p(()=>[...i[40]||=[n(`确定`,-1)]]),_:1},8,[`loading`])]),default:p(()=>[(v(!0),l(d,null,_(xn.value,t=>(v(),l(`div`,{key:t.key,class:`field-row`},[e(`div`,Ct,g(t.message||t.key),1),t.type===`select`?(v(),m(w,{key:0,modelValue:Z.value[t.key],"onUpdate:modelValue":e=>Z.value[t.key]=e,class:`mt-8`,placeholder:`请选择`,style:{width:`100%`}},{default:p(()=>[(v(!0),l(d,null,_(t.options,t=>(v(),m(fe,{key:t.value,label:t.label??t.value,value:t.value??``},{default:p(()=>[e(`span`,null,g(t.label??t.value),1),t.hint?(v(),l(`span`,wt,`(`+g(t.hint)+`)`,1)):c(``,!0)]),_:2},1032,[`label`,`value`]))),128))]),_:2},1032,[`modelValue`,`onUpdate:modelValue`])):(v(),m(ue,{key:1,modelValue:Z.value[t.key],"onUpdate:modelValue":e=>Z.value[t.key]=e,class:`mt-8`,placeholder:t.placeholder||``,onKeyup:ee(Nn,[`enter`])},null,8,[`modelValue`,`onUpdate:modelValue`,`placeholder`]))]))),128)),Q.value?(v(),m(u,{key:0,type:`error`,"show-icon":``,closable:!1,class:`mt-8`,title:Q.value},null,8,[`title`])):c(``,!0)]),_:1},8,[`modelValue`,`title`]),o(C,{modelValue:J.value,"onUpdate:modelValue":i[14]||=e=>J.value=e,title:`登录 ${pn.value}`,width:`480px`},{footer:p(()=>[o(s,{onClick:i[13]||=e=>J.value=!1},{default:p(()=>[...i[41]||=[n(`取消`,-1)]]),_:1}),o(s,{type:`primary`,loading:yn.value,onClick:Pn},{default:p(()=>[...i[42]||=[n(`确定`,-1)]]),_:1},8,[`loading`])]),default:p(()=>[e(`div`,Tt,g(mn.value||`该登录方式需要一枚密钥`),1),o(ue,{modelValue:gn.value,"onUpdate:modelValue":i[12]||=e=>gn.value=e,class:`mt-8`,placeholder:hn.value||`粘贴密钥`,"show-password":``,onKeyup:ee(Pn,[`enter`])},null,8,[`modelValue`,`placeholder`]),Y.value?(v(),m(u,{key:0,type:`error`,"show-icon":``,closable:!1,class:`mt-8`,title:Y.value},null,8,[`title`])):c(``,!0)]),_:1},8,[`modelValue`,`title`]),o(C,{modelValue:G.value,"onUpdate:modelValue":i[16]||=e=>G.value=e,title:`登录 ${K.value}`,width:`480px`,onClose:i[17]||=e=>Tn(K.value)},{footer:p(()=>[o(s,{onClick:i[15]||=e=>G.value=!1},{default:p(()=>[...i[44]||=[n(`关闭`,-1)]]),_:1})]),default:p(()=>[e(`div`,Et,g(fn.value||`正在读取本机已登录的凭据…`),1),dn.value?(v(),l(`div`,Dt,[e(`a`,{class:`el-button el-button--primary`,href:dn.value,target:`_blank`,rel:`noopener`},` 打开登录页 `,8,Ot),i[43]||=e(`div`,{class:`muted-sm mt-8`},`在打开的页面完成登录即可,本页会自动检测(最长等待几分钟)。`,-1)])):c(``,!0),q.value?(v(),m(u,{key:1,type:`error`,"show-icon":``,closable:!1,class:`mt-8`,title:q.value},null,8,[`title`])):(v(),l(`div`,kt,`等待登录完成…`))]),_:1},8,[`modelValue`,`title`])])}}}),[[`__scopeId`,`data-v-37d2ec6d`]]);export{Pt as default};
|