ezllm 0.0.4 → 0.0.26
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/README.md +2 -2
- package/bin/ellm-proxy.js +1 -1
- package/dist/cli.js +57 -88
- package/dist/server.js +196 -280
- package/dist/web-ui/assets/DashboardView-CAv7TPGt.css +1 -0
- package/dist/web-ui/assets/DashboardView-CjEo1VeN.js +1 -0
- package/dist/web-ui/assets/LayoutView-CZWTEtiI.js +1 -0
- package/dist/web-ui/assets/{LayoutView-kZ2yGen8.css → LayoutView-DMNmIelM.css} +1 -1
- package/dist/web-ui/assets/LoginView-BZnxf_XD.css +1 -0
- package/dist/web-ui/assets/LoginView-Crwq9D2r.js +1 -0
- package/dist/web-ui/assets/LogsView-CVnmnD7w.js +9 -0
- package/dist/web-ui/assets/LogsView-D7xJOKSv.css +1 -0
- package/dist/web-ui/assets/ProvidersView-BOLgh-Q7.js +14 -0
- package/dist/web-ui/assets/ProvidersView-Bi_ojHNQ.css +1 -0
- package/dist/web-ui/assets/ServiceStatusView-DXbn--55.css +1 -0
- package/dist/web-ui/assets/ServiceStatusView-DnJ_x40Z.js +2 -0
- package/dist/web-ui/assets/SettingsView-BY2QIyXL.css +1 -0
- package/dist/web-ui/assets/SettingsView-DFGf2qGB.js +1 -0
- package/dist/web-ui/assets/SetupView-B3SahEFi.css +1 -0
- package/dist/web-ui/assets/SetupView-DPfeIQ8u.js +1 -0
- package/dist/web-ui/assets/clipboard-CorU9X8e.js +1 -0
- package/dist/web-ui/assets/config-BLeVzAng.js +1 -0
- package/dist/web-ui/assets/format-DrbP4_cY.js +1 -0
- package/dist/web-ui/assets/index-BNieAChJ.css +1 -0
- package/dist/web-ui/assets/index-D8q_jlRU.js +49 -0
- package/dist/web-ui/assets/latestRequest-Dk21IcrH.js +1 -0
- package/dist/web-ui/assets/message-CPl1jEnd.js +2 -0
- package/dist/web-ui/assets/providers-CrgmFKCl.js +1 -0
- package/dist/web-ui/assets/quota-pWFONauN.js +1 -0
- package/dist/web-ui/assets/router-CjERSWL9.js +6 -0
- package/dist/web-ui/assets/useLoadError-CKk_ZYc1.js +1 -0
- package/dist/web-ui/assets/useManagerApi-BKQpMU8c.js +1 -0
- package/dist/web-ui/assets/useToast-BrWn2CV2.js +1 -0
- package/dist/web-ui/assets/version-quqH5oMc.js +1 -0
- package/dist/web-ui/config.js +4 -2
- package/dist/web-ui/index.html +4 -2
- package/docs/DESIGN.md +25 -17
- package/package.json +8 -6
- package/dist/web-ui/assets/DashboardView-DwlQExQv.css +0 -1
- package/dist/web-ui/assets/DashboardView-fRDkGq0g.js +0 -1
- package/dist/web-ui/assets/LayoutView-CK_MaWN7.js +0 -1
- package/dist/web-ui/assets/LoginView-B1naaT8E.js +0 -1
- package/dist/web-ui/assets/LoginView-CSfb59pE.css +0 -1
- package/dist/web-ui/assets/LogsView-CCjJTjvZ.css +0 -1
- package/dist/web-ui/assets/LogsView-YtH8gJPU.js +0 -9
- package/dist/web-ui/assets/ProvidersView-Caqpg_0F.css +0 -1
- package/dist/web-ui/assets/ProvidersView-DWtS_e7t.js +0 -31
- package/dist/web-ui/assets/ServiceStatusView-D3ybS2T-.js +0 -39
- package/dist/web-ui/assets/ServiceStatusView-DrPoYMN-.css +0 -1
- package/dist/web-ui/assets/SettingsView-D1kbH5Ev.css +0 -1
- package/dist/web-ui/assets/SettingsView-DepOaZYg.js +0 -1
- package/dist/web-ui/assets/SetupView-BwDwokAd.js +0 -1
- package/dist/web-ui/assets/SetupView-pS9nSnLg.css +0 -1
- package/dist/web-ui/assets/clipboard-aCBIMfw7.js +0 -1
- package/dist/web-ui/assets/config-CdOq1p3C.js +0 -1
- package/dist/web-ui/assets/format-kTdM4RVv.js +0 -1
- package/dist/web-ui/assets/index-BecfPmag.css +0 -1
- package/dist/web-ui/assets/index-CgzCvxTY.js +0 -96
- package/dist/web-ui/assets/providers-i7t_wEzk.js +0 -1
- package/dist/web-ui/assets/useLoadError-UA3r7sR9.js +0 -1
- package/dist/web-ui/assets/useManagerApi-CBQNomtR.js +0 -1
- package/dist/web-ui/assets/useToast-DNMhOOeI.js +0 -1
- package/dist/web-ui/assets/version-BKHjE_LF.js +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.service-status-page[data-v-0be6fcd8]{flex-direction:column;height:calc(100vh - 124px);display:flex;overflow:hidden}.main-card[data-v-0be6fcd8]{flex-direction:column;flex:1;min-height:0;display:flex;overflow:hidden}.main-card[data-v-0be6fcd8] .el-card__body{flex-direction:column;height:100%;display:flex;overflow:hidden}.legend[data-v-0be6fcd8]{color:#606266;flex-shrink:0;align-items:center;gap:6px;margin-bottom:8px;font-size:12px;display:flex}.legend-gradient[data-v-0be6fcd8]{background:linear-gradient(90deg,#67c23a,#e6a23c,#f56c6c);border-radius:2px;width:96px;height:10px}.legend-swatch[data-v-0be6fcd8]{border-radius:2px;width:14px;height:10px;margin-left:10px}.legend-swatch--down[data-v-0be6fcd8]{background-color:#909399}.legend-swatch--empty[data-v-0be6fcd8]{background-color:#f2f3f5;border:1px solid #ebeef5}.hint[data-v-0be6fcd8]{flex-shrink:0;margin-bottom:12px}.gantt-wrap[data-v-0be6fcd8]{flex-direction:column;flex:1;min-height:0;display:flex;overflow:hidden}.gantt[data-v-0be6fcd8]{flex:1;min-height:0;overflow:hidden auto}.gantt-row[data-v-0be6fcd8]{border-bottom:1px solid #f2f6fc;align-items:center;height:32px;display:flex}.gantt-row[data-v-0be6fcd8]:hover{background-color:#fafcff}.gantt-head[data-v-0be6fcd8]{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-0be6fcd8]{flex:0 0 240px;width:240px;padding-right:12px;font-size:13px}.col-status[data-v-0be6fcd8]{color:#606266;flex:0 0 100px;width:100px;padding-right:12px;font-size:13px}.col-cells[data-v-0be6fcd8]{flex:1;min-width:0;display:flex}.cell[data-v-0be6fcd8]{flex:1 1 0;min-width:0;height:20px;box-shadow:inset -1px 0 #fff}.cell[data-v-0be6fcd8]:last-child{box-shadow:none}.cell--head[data-v-0be6fcd8]{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-0be6fcd8]{color:#c0c4cc;font-size:9px}.cell--empty[data-v-0be6fcd8]{background-color:#f2f3f5}.gantt-empty[data-v-0be6fcd8]{color:#909399;flex:1;justify-content:center;align-items:center;font-size:13px;display:flex}.copy-text[data-v-0be6fcd8]{color:#409eff;cursor:pointer}.copy-text[data-v-0be6fcd8]:hover{text-decoration:underline}.model-name[data-v-0be6fcd8]{white-space:nowrap;text-overflow:ellipsis;display:block;overflow:hidden}
|
|
@@ -0,0 +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 g,ht as _,j as v,k as y,ot as b,pn as x,rt as S,tt as C,un as w,yt as T}from"./router-CjERSWL9.js";import{t as E}from"./useToast-BrWn2CV2.js";import{t as D}from"./useLoadError-CKk_ZYc1.js";import{t as te}from"./clipboard-CorU9X8e.js";import{c as ne,i as O}from"./format-DrbP4_cY.js";o(),T(),a();var re={class:`service-status-page`},ie={class:`flex-between`},ae={class:`flex-gap-8`},oe={class:`flex-gap-8`},se={class:`gantt-wrap`},ce={key:0,class:`gantt`},le={class:`gantt-row gantt-head`},ue={class:`col-cells`},de=[`title`],fe={class:`cell-head-date`},pe={class:`col-name`},k=[`title`,`onClick`],A=[`title`],j={class:`col-cells`},M=[`title`],N={key:1,class:`gantt-empty`},P=36e5,F=24,I=`#909399`,L=h(c({__name:`ServiceStatusView`,setup(a){let{toast:o}=E(),{loadError:c,run:h}=D(`延迟数据加载失败,请重试`),T=n([]),L=n(!0),R=n(!1),z=n(null),B=n(!1),V=n(!1),H,U,W=n(K()),G=n(new Map);function K(){let e=new Date,t=new Date(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours()).getTime();return Array.from({length:F},(e,n)=>t-(23-n)*P)}let q=e=>{let t=new Date(e);if(Number.isNaN(t.getTime()))return`-`;let n=e=>String(e).padStart(2,`0`);return`${t.getFullYear()}-${n(t.getMonth()+1)}-${n(t.getDate())} ${n(t.getHours())}:00`},me=y(()=>W.value.map(e=>{let t=new Date(e),n=e=>String(e).padStart(2,`0`),r=n(t.getHours());return{start:e,dateLabel:`${n(t.getMonth()+1)}-${n(t.getDate())}`,hourLabel:r,fullLabel:`${q(e)} - ${r}:59`}})),he=[103,194,58],J=[230,162,60],ge=[245,108,108],_e=y(()=>{let e=[];for(let t of G.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}}),Y=e=>{let{min:t,max:n}=_e.value,r=n===t?0:(e-t)/(n-t),[i,a]=r<=.5?[he,J]:[J,ge],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=`${q(t)} - ${String(new Date(t+P).getHours()).padStart(2,`0`)}:00`;return e===void 0||e.total===0?`${n}\n无探测数据`:`${n}\n平均延迟 ${O(e.avgLatencyMs)}\n成功 ${String(e.success)} / 失败 ${String(e.failed)}`},Z=y(()=>ye.value.map(e=>{let t=G.value.get(e.model),n=W.value.map(e=>{let n=t?.get(e);return n!==void 0&&n.failed>0?{start:e,className:`cell--down`,style:{backgroundColor:I},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:Y(n.avgLatencyMs)},title:X(n,e)}});return{model:e.model,avg24h:e.avg24h,statusTitle:[e.avg24h===null?`最近 24 小时无成功探测记录`:`最近 24 小时成功探测平均延迟 ${O(e.avg24h)}`,e.lastLatencyMs==null?`最近一次探测:无成功延迟记录`:`最近一次探测延迟 ${O(e.lastLatencyMs)}`].join(`
|
|
2
|
+
`),cells:n}})),ve=(e,t)=>e===null&&t===null?0:e===null?1:t===null?-1:e-t,ye=y(()=>[...T.value].sort((e,t)=>{let n=e.lastOk===!1;if(n!==(t.lastOk===!1))return n?1:-1;let r=ve(e.avg24h,t.avg24h);return r===0?e.model.localeCompare(t.model):r})),Q=async e=>{if(e.length===0){G.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]}}));G.value=new Map(t)},$=()=>h(async()=>{try{let e=await p.get(`/api/latency/history`);T.value=e.models??[],R.value=e.running,z.value=e.lastRunAt,W.value=K(),await Q(T.value.map(e=>e.model))}finally{L.value=!1}}),be=()=>$(),xe=()=>{V.value?H=window.setInterval(()=>void $(),5e3):H!==void 0&&(window.clearInterval(H),H=void 0)},Se=async()=>{B.value=!0;try{await p.post(`/api/latency/run`)}catch(e){o(e.message,`error`),B.value=!1;return}U=window.setInterval(async()=>{try{let e=await p.get(`/api/latency/history`);T.value=e.models??[],R.value=e.running,z.value=e.lastRunAt,e.running||(window.clearInterval(U),U=void 0,B.value=!1,W.value=K(),await Q(T.value.map(e=>e.model)))}catch{}},2e3)},Ce=async e=>{await te(e)?o(`已复制到剪贴板`,`success`):o(`复制失败`,`error`)};return d(()=>{$()}),e(()=>{H!==void 0&&window.clearInterval(H),U!==void 0&&window.clearInterval(U)}),(e,n)=>{let a=m(`el-button`),o=m(`el-alert`),d=m(`el-tag`),p=m(`el-checkbox`),h=m(`el-card`),y=b(`loading`);return C(),u(`div`,re,[i(c)?(C(),v(o,{key:0,title:i(c),type:`error`,"show-icon":``,closable:!1,class:`mb-16`},{default:_(()=>[s(a,{size:`small`,onClick:be},{default:_(()=>[...n[1]||=[r(`重试`,-1)]]),_:1})]),_:1},8,[`title`])):l(``,!0),s(h,{shadow:`never`,class:`main-card`},{header:_(()=>[t(`div`,ie,[t(`div`,ae,[n[3]||=t(`span`,{class:`fw-600`},`服务状态`,-1),R.value?(C(),v(d,{key:0,type:`warning`,size:`small`},{default:_(()=>[...n[2]||=[r(`测试进行中`,-1)]]),_:1})):z.value?(C(),v(d,{key:1,type:`info`,size:`small`},{default:_(()=>[r(` 上次测试 `+x(i(ne)(z.value)),1)]),_:1})):l(``,!0)]),t(`div`,oe,[s(p,{modelValue:V.value,"onUpdate:modelValue":n[0]||=e=>V.value=e,onChange:xe},{default:_(()=>[...n[4]||=[r(` 自动刷新(5s) `,-1)]]),_:1},8,[`modelValue`]),s(a,{loading:B.value,onClick:Se},{default:_(()=>[...n[5]||=[r(` 延迟测试 `,-1)]]),_:1},8,[`loading`])])])]),default:_(()=>[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),g((C(),u(`div`,se,[n[8]||=t(`div`,{class:`muted-sm hint`},` 右侧 24 格为最近 24 小时(每格 1 小时,本地整点对齐,最右格为当前小时)。 格子底色为当小时成功探测的平均延迟,全表统一色标(本期最快→最慢 绿→红); 当小时存在失败探测即视为不可用,显示灰色。 行按 24h 平均延迟升序,最近一次探测失败的模型沉底。 `,-1),Z.value.length>0?(C(),u(`div`,ce,[t(`div`,le,[n[6]||=t(`div`,{class:`col-name`},`模型名称`,-1),n[7]||=t(`div`,{class:`col-status`},`状态`,-1),t(`div`,ue,[(C(!0),u(f,null,S(me.value,e=>(C(),u(`div`,{key:e.start,class:`cell cell--head`,title:e.fullLabel},[t(`span`,fe,x(e.dateLabel),1),t(`span`,null,x(e.hourLabel),1)],8,de))),128))])]),(C(!0),u(f,null,S(Z.value,e=>(C(),u(`div`,{key:e.model,class:`gantt-row`},[t(`div`,pe,[t(`span`,{class:`copy-text model-name`,title:e.model,onClick:t=>Ce(e.model)},x(e.model),9,k)]),t(`div`,{class:`col-status`,title:e.statusTitle},x(i(O)(e.avg24h)),9,A),t(`div`,j,[(C(!0),u(f,null,S(e.cells,e=>(C(),u(`div`,{key:e.start,class:ee([`cell`,e.className]),style:w(e.style),title:e.title},null,14,M))),128))])]))),128))])):(C(),u(`div`,N,`暂无延迟数据,点击「延迟测试」开始`))])),[[y,L.value]])]),_:1})])}}}),[[`__scopeId`,`data-v-0be6fcd8`]]);export{L as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.switch-row[data-v-5084d579]{justify-content:space-between;align-items:center;gap:24px;padding:4px 0;display:flex}.switch-title[data-v-5084d579]{align-items:center;gap:8px;margin-bottom:4px;font-weight:600;display:flex}.switch-desc[data-v-5084d579]{color:var(--el-text-color-secondary);font-size:13px;line-height:1.6}.switch-desc code[data-v-5084d579]{background:var(--el-fill-color-light);border-radius:4px;padding:1px 6px;font-size:12px}.switch-divider[data-v-5084d579]{margin:16px 0}.mb-16[data-v-d51cfdf5]{margin-bottom:16px}.mt-8[data-v-d51cfdf5]{margin-top:8px}.switch-row[data-v-d51cfdf5]{justify-content:space-between;align-items:center;gap:24px;padding:4px 0;display:flex}.switch-title[data-v-d51cfdf5]{align-items:center;gap:8px;margin-bottom:4px;font-weight:600;display:flex}.switch-desc[data-v-d51cfdf5]{color:var(--el-text-color-secondary);font-size:13px;line-height:1.6}.switch-desc code[data-v-d51cfdf5]{background:var(--el-fill-color-light);border-radius:4px;padding:1px 6px;font-size:12px}.version-row[data-v-d51cfdf5]{align-items:center;gap:8px;margin-bottom:8px;display:flex}.version-label[data-v-d51cfdf5]{color:var(--el-text-color-secondary);font-size:13px}.version-actions[data-v-d51cfdf5]{gap:8px;margin-top:12px;display:flex}.settings-tabs[data-v-e1ea3ddd] .el-tabs__content{overflow:visible}.save-bar[data-v-e1ea3ddd]{justify-content:center;padding:8px 0;display:flex;position:sticky;bottom:0}.login-row[data-v-e1ea3ddd]{flex-wrap:wrap;gap:8px;display:flex}.monitor-row[data-v-e1ea3ddd]{justify-content:space-between;align-items:center;gap:24px;display:flex}.monitor-title[data-v-e1ea3ddd]{margin-bottom:4px;font-weight:600}
|
|
@@ -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,a as p,at as m,d as h,gt as g,ht as _,j as v,k as y,n as b,ot as x,pn as S,rt as C,tt as w,yt as T}from"./router-CjERSWL9.js";import{t as E}from"./index-D8q_jlRU.js";import{n as D,t as O}from"./useManagerApi-BKQpMU8c.js";import{t as k}from"./config-BLeVzAng.js";import{t as A}from"./useToast-BrWn2CV2.js";import{t as j}from"./useLoadError-CKk_ZYc1.js";import{t as M}from"./clipboard-CorU9X8e.js";import{n as N,t as P}from"./version-quqH5oMc.js";o(),a(),T();var F={class:`flex-between`},I={class:`muted-sm mb-8`},L={class:`switch-row`},R={class:`switch-info`},z={class:`switch-title`},B={class:`switch-row`},V={class:`switch-info`},H={class:`switch-title`},U={class:`switch-row`},W={class:`switch-info`},G={class:`switch-title`},K=h(c({__name:`HarnessSwitches`,setup(e){let{toast:i}=A(),a=n(!0),o=n(!1),c=n(null),p=n(null),h=n(null),y=n(null),b=n(`success`),C=async e=>{e||(c.value?o.value=!0:a.value=!0);try{c.value=await O.harness(),p.value=null}catch(t){e||(p.value=t.message)}finally{e||(a.value=!1,o.value=!1)}};d(()=>C(!1));let T={claudeCode:{label:`Claude Code`,file:`~/.claude/settings.json`,toggle:O.setClaudeCode},codex:{label:`Codex CLI`,file:`~/.codex/config.toml`,toggle:O.setCodex},dsh:{label:`DeepSeek Harness`,file:`~/.dsh/settings.yaml`,toggle:O.setDsh}},D=async(e,t)=>{if(!c.value||h.value)return;let n=T[e],r=t?`确定开启 ${n.label} 代理?将改写 ${n.file}(开启前自动备份,关闭时从备份还原)。`:`确定关闭 ${n.label} 代理?将从备份还原 ${n.file}(无备份时移除代理相关配置)。`;try{await E.confirm(r,t?`开启确认`:`关闭确认`,{confirmButtonText:t?`开启`:`关闭`,cancelButtonText:`取消`,type:`warning`})}catch{return}h.value=e;try{let e=await n.toggle(t);y.value=e.note??null,b.value=t?`success`:`info`,i(t?`已开启代理`:`已关闭代理`,`success`)}catch(e){i(e.message||`操作失败`,`error`)}finally{h.value=null,await C(!0)}};return(e,n)=>{let i=m(`el-button`),d=m(`el-alert`),T=m(`el-tag`),E=m(`el-switch`),O=m(`el-divider`),k=m(`el-empty`),A=m(`el-card`),j=x(`loading`);return g((w(),v(A,{shadow:`never`},{header:_(()=>[t(`div`,F,[n[7]||=t(`span`,{class:`fw-600`},`代理开关`,-1),s(i,{loading:o.value,onClick:n[0]||=e=>C(!1)},{default:_(()=>[...n[6]||=[r(`刷新`,-1)]]),_:1},8,[`loading`])])]),default:_(()=>[c.value?(w(),u(f,{key:0},[t(`div`,I,` 将本机 CLI 工具的流量一键指向本机网关(`+S(c.value.gatewayBase)+`)。 开启前自动备份原配置为 *.ellm-bak(保留最早的原始备份),关闭时从备份还原。 `,1),y.value?(w(),v(d,{key:0,title:y.value,type:b.value,"show-icon":``,class:`mb-8`,onClose:n[1]||=e=>y.value=null},null,8,[`title`,`type`])):l(``,!0),t(`div`,L,[t(`div`,R,[t(`div`,z,[n[8]||=r(` Claude Code `,-1),s(T,{type:c.value.claudeCode?`success`:`info`,size:`small`,"disable-transitions":``},{default:_(()=>[r(S(c.value.claudeCode?`已开启`:`未开启`),1)]),_:1},8,[`type`])]),n[9]||=t(`div`,{class:`switch-desc`},[r(` 写入 `),t(`code`,null,`~/.claude/settings.json`),r(` 的 env.ANTHROPIC_BASE_URL / ANTHROPIC_AUTH_TOKEN, 鉴权取网关配置的 masterKey(未设置将开启失败);其余字段原样保留,重启 Claude Code 会话后生效。 `)],-1)]),s(E,{"model-value":c.value.claudeCode,loading:h.value===`claudeCode`,onChange:n[2]||=e=>D(`claudeCode`,!!e)},null,8,[`model-value`,`loading`])]),s(O,{class:`switch-divider`}),t(`div`,B,[t(`div`,V,[t(`div`,H,[n[10]||=r(` Codex CLI `,-1),s(T,{type:c.value.codex?`success`:`info`,size:`small`,"disable-transitions":``},{default:_(()=>[r(S(c.value.codex?`已开启`:`未开启`),1)]),_:1},8,[`type`])]),n[11]||=t(`div`,{class:`switch-desc`},[r(` 写入 `),t(`code`,null,`~/.codex/config.toml`),r(` 的 model_provider 与 [model_providers.ellm-proxy] 段 (保留用户注释与排版);开启后需按提示设置环境变量 ELLM_PROXY_API_KEY 供 Codex 鉴权。 `)],-1)]),s(E,{"model-value":c.value.codex,loading:h.value===`codex`,onChange:n[3]||=e=>D(`codex`,!!e)},null,8,[`model-value`,`loading`])]),s(O,{class:`switch-divider`}),t(`div`,U,[t(`div`,W,[t(`div`,G,[n[12]||=r(` DeepSeek Harness `,-1),s(T,{type:c.value.dsh?`success`:`info`,size:`small`,"disable-transitions":``},{default:_(()=>[r(S(c.value.dsh?`已开启`:`未开启`),1)]),_:1},8,[`type`])]),n[13]||=t(`div`,{class:`switch-desc`},[r(` 写入 `),t(`code`,null,`~/.dsh/settings.yaml`),r(` 的 llm-deepseek.baseURL 与 `),t(`code`,null,`~/.dsh/.credentials.yaml`),r(` 的 DEEPSEEK_API_KEY(取网关 masterKey,未设置则写占位值);模型请在 dsh 内选择与网关部署名一致的模型。 dsh 为 developer preview,配置格式可能随版本变化。 `)],-1)]),s(E,{"model-value":c.value.dsh,loading:h.value===`dsh`,onChange:n[4]||=e=>D(`dsh`,!!e)},null,8,[`model-value`,`loading`])])],64)):(w(),v(k,{key:1,description:p.value||`暂无开关状态`},{default:_(()=>[s(i,{type:`primary`,onClick:n[5]||=e=>C(!1)},{default:_(()=>[...n[14]||=[r(`重试`,-1)]]),_:1})]),_:1},8,[`description`]))]),_:1})),[[j,a.value]])}}}),[[`__scopeId`,`data-v-5084d579`]]);o(),a(),T();var q={class:`service-settings`},J={class:`flex-between`},Y={key:0,class:`switch-row`},X={class:`switch-info`},Z={class:`switch-title`},Q={key:0,class:`switch-row`},ee={class:`switch-info`},te={class:`switch-title`},ne={class:`switch-desc`},re={key:0,class:`version-block`},ie={class:`version-row`},ae={class:`muted-sm`},oe={key:0,class:`muted-sm`},se={key:1,class:`muted-sm`},ce={class:`muted-sm`},le={class:`version-actions`},$=h(c({__name:`ServiceUpdateSettings`,setup(i){let{toast:a}=A(),o=n(!0),c=n(!1),p=n(null),h=n(null),b=n(null),C=n(null),T=n(null),k=n(!1),j=n(!1),M=n(null),F=null;e(()=>F?.abort());let I=async e=>{if(!e){if(c.value)return;c.value=!0}try{let[e,t]=await Promise.allSettled([O.autostart(),O.update()]);p.value=e.status===`fulfilled`?e.value:null,h.value=e.status===`rejected`?e.reason?.message:null,b.value=t.status===`fulfilled`?t.value:null,C.value=t.status===`rejected`?t.reason?.message:null}finally{o.value=!1,c.value=!1}};d(()=>I(!1));let L=y(()=>b.value?.lastCheck?.currentVersion??null),R=y(()=>P(L.value)),z=y(()=>b.value?.lastCheck?.latestVersion??null),B=y(()=>b.value?.lastCheck?.hasUpdate===!0),V=y(()=>{let e=b.value?.lastCheck?.checkedAt;return e?new Date(e).toLocaleString():null}),H=y(()=>{let e=b.value?.lastApply;if(!e)return null;let t=e.appliedAt?new Date(e.appliedAt).toLocaleString():``;return`${e.fromVersion} → ${e.toVersion}${t?`(${t})`:``}`}),U=e=>e?new Date(e).toLocaleString():``,W=async e=>{if(!p.value||T.value)return;let t=e?`确定开启开机自启?将注册登录触发的自启项(登录时自动恢复服务)。`:`确定关闭开机自启?将移除自启项,且此后首次启动不再自动注册。`;try{await E.confirm(t,e?`开启确认`:`关闭确认`,{confirmButtonText:e?`开启`:`关闭`,cancelButtonText:`取消`,type:`warning`})}catch{return}T.value=`autostart`;try{let t=await O.setAutostart(e);t.note?a(t.note,`success`):a(e?`开机自启已开启`:`开机自启已关闭`,`success`)}catch(e){a(e.message||`操作失败`,`error`)}finally{T.value=null,await I(!0)}},G=async e=>{if(!b.value||T.value)return;let t=e?`确定开启自动更新?将每小时检查 npm 源,发现新版本自动安装并重启服务。`:`确定关闭自动更新?不再自动检查(手动检查更新不受影响)。`;try{await E.confirm(t,e?`开启确认`:`关闭确认`,{confirmButtonText:e?`开启`:`关闭`,cancelButtonText:`取消`,type:`warning`})}catch{return}T.value=`updateEnabled`;try{let t=await O.setUpdateEnabled(e);t.note&&a(t.note,`success`)}catch(e){a(e.message||`操作失败`,`error`)}finally{T.value=null,await I(!0)}},K=async()=>{k.value=!0;try{let e=await O.checkUpdate();M.value=e.hasUpdate?`发现新版本 ${e.latestVersion}(当前 ${e.currentVersion}):点击「立即更新」即可安装(服务自动重启,期间管理台短暂不可访问)`:`已是最新版本 ${e.currentVersion}(检查于 ${U(e.checkedAt)})`,await I(!0)}catch(e){a(e.message||`检查更新失败`,`error`)}finally{k.value=!1}},$=async()=>{try{await E.confirm(`确定更新到 ${z.value}?服务会自动重启并在启动时安装新版本:重启期间管理台短暂不可访问(预计 1~3 分钟),更新完成后自动恢复。`,`更新确认`,{confirmButtonText:`立即更新`,cancelButtonText:`取消`,type:`warning`})}catch{return}j.value=!0;let e=new AbortController;F=e;try{let t=await O.update(),n=await O.applyUpdate();if(!n.updated){M.value=`已是最新版本 ${n.toVersion}`;return}M.value=`正在重启服务并安装 ${n.toVersion}(预计 1~3 分钟):重启期间管理台短暂不可访问,完成后这里会自动显示结果。`;let r=await D({targetVersion:n.toVersion,sinceAppliedAt:t.lastApply?.appliedAt??null,signal:e.signal});if(e.signal.aborted)return;r&&!r.error?(a(`已更新到 ${r.toVersion}`,`success`),M.value=`已更新 ${r.fromVersion} → ${r.toVersion},服务已在新版本上运行。`):r?.error?(a(`更新失败:${r.error}`,`error`),M.value=N(r.error)):M.value=`更新仍在进行(安装耗时较长):稍后刷新页面查看最新状态。`}catch(e){a(e.message||`更新失败`,`error`)}finally{j.value=!1,F===e&&(F=null),e.signal.aborted||await I(!0)}};return(e,n)=>{let i=m(`el-button`),a=m(`el-tag`),d=m(`el-switch`),y=m(`el-empty`),E=m(`el-card`),D=m(`el-link`),O=m(`el-alert`),A=x(`loading`);return g((w(),u(`div`,q,[s(E,{shadow:`never`,class:`mb-16`},{header:_(()=>[t(`div`,J,[n[7]||=t(`span`,{class:`fw-600`},`开机自启`,-1),s(i,{loading:c.value,onClick:n[0]||=e=>I(!1)},{default:_(()=>[...n[6]||=[r(`刷新`,-1)]]),_:1},8,[`loading`])])]),default:_(()=>[p.value?(w(),u(`div`,Y,[t(`div`,X,[t(`div`,Z,[n[8]||=r(` 登录时自动启动服务 `,-1),s(a,{type:p.value.enabled?`success`:`info`,size:`small`,"disable-transitions":``},{default:_(()=>[r(S(p.value.enabled?`已开启`:`未开启`),1)]),_:1},8,[`type`])]),n[9]||=t(`div`,{class:`switch-desc`},[r(` 登录操作系统时自动启动服务(无需管理员权限)。 关闭后首次启动 `),t(`code`,null,`ezllm`),r(` 也不会再自动注册,重新开启即可解除。 `)],-1)]),s(d,{"model-value":p.value.enabled,loading:T.value===`autostart`,onChange:n[1]||=e=>W(!!e)},null,8,[`model-value`,`loading`])])):(w(),v(y,{key:1,description:h.value||`暂无自启状态`},{default:_(()=>[s(i,{type:`primary`,onClick:n[2]||=e=>I(!1)},{default:_(()=>[...n[10]||=[r(`重试`,-1)]]),_:1})]),_:1},8,[`description`]))]),_:1}),s(E,{shadow:`never`,class:`mb-16`},{header:_(()=>[...n[11]||=[t(`div`,{class:`flex-between`},[t(`span`,{class:`fw-600`},`自动更新`)],-1)]]),default:_(()=>[b.value?(w(),u(`div`,Q,[t(`div`,ee,[t(`div`,te,[n[12]||=r(` 自动检查并安装新版本 `,-1),s(a,{type:b.value.enabled?`success`:`info`,size:`small`,"disable-transitions":``},{default:_(()=>[r(S(b.value.enabled?`已开启`:`未开启`),1)]),_:1},8,[`type`])]),t(`div`,ne,[b.value.supported?(w(),u(f,{key:1},[r(` 每小时检查 npm 源,发现新版本自动重启服务并在启动时安装(更新期间服务短暂中断); 关闭后仍可在下方手动检查与更新。 `)],64)):(w(),u(f,{key:0},[r(` 当前为源码运行模式,更新功能不可用(仅 npm 全局安装的包支持自动更新)。 `)],64))])]),b.value.supported?(w(),v(d,{key:0,"model-value":b.value.enabled,loading:T.value===`updateEnabled`,onChange:n[3]||=e=>G(!!e)},null,8,[`model-value`,`loading`])):l(``,!0)])):(w(),v(y,{key:1,description:C.value||`暂无更新状态`},{default:_(()=>[s(i,{type:`primary`,onClick:n[4]||=e=>I(!1)},{default:_(()=>[...n[13]||=[r(`重试`,-1)]]),_:1})]),_:1},8,[`description`]))]),_:1}),s(E,{shadow:`never`},{header:_(()=>[...n[14]||=[t(`div`,{class:`flex-between`},[t(`span`,{class:`fw-600`},`版本信息`)],-1)]]),default:_(()=>[b.value?(w(),u(`div`,re,[t(`div`,ie,[n[18]||=t(`span`,{class:`version-label`},`当前版本`,-1),s(a,{size:`small`},{default:_(()=>[r(S(L.value||`未知`),1)]),_:1}),R.value?(w(),v(a,{key:0,type:`warning`,size:`small`,"disable-transitions":``},{default:_(()=>[...n[15]||=[r(`本地构建`,-1)]]),_:1})):l(``,!0),z.value?(w(),u(f,{key:1},[n[17]||=t(`span`,{class:`version-label`},`最新版本`,-1),s(a,{type:B.value?`warning`:`success`,size:`small`,"disable-transitions":``},{default:_(()=>[r(S(z.value),1)]),_:1},8,[`type`]),B.value?(w(),v(a,{key:0,type:`warning`,size:`small`,"disable-transitions":``},{default:_(()=>[...n[16]||=[r(`发现新版本`,-1)]]),_:1})):l(``,!0)],64)):l(``,!0)]),t(`div`,ae,[r(` 上次检查:`+S(V.value||`尚未检查`)+` `,1),b.value.updating?(w(),u(f,{key:0},[r(` · 更新执行中...`)],64)):l(``,!0)]),b.value.supported?l(``,!0):(w(),u(`div`,oe,` 源码运行模式:手动检查与更新不可用。 `)),H.value?(w(),u(`div`,se,` 上次更新:`+S(H.value),1)):l(``,!0),t(`div`,ce,[n[20]||=r(` npm 包主页:`,-1),s(D,{type:`primary`,href:`https://www.npmjs.com/package/ezllm`,target:`_blank`},{default:_(()=>[...n[19]||=[r(`npmjs.com/package/ezllm`,-1)]]),_:1})]),t(`div`,le,[s(i,{loading:k.value,disabled:!b.value.supported||b.value.updating,onClick:K},{default:_(()=>[r(S(k.value?`检查中...`:`检查更新`),1)]),_:1},8,[`loading`,`disabled`]),B.value&&b.value.supported?(w(),v(i,{key:0,type:`primary`,loading:j.value,disabled:b.value.updating,onClick:$},{default:_(()=>[r(S(j.value?`更新中...`:`立即更新到 ${z.value}`),1)]),_:1},8,[`loading`,`disabled`])):l(``,!0)]),M.value?(w(),v(O,{key:2,title:M.value,type:`info`,"show-icon":``,class:`mt-8`,onClose:n[5]||=e=>M.value=null},null,8,[`title`])):l(``,!0)])):(w(),v(y,{key:1,description:`更新状态不可用`}))]),_:1})])),[[A,o.value]])}}}),[[`__scopeId`,`data-v-d51cfdf5`]]);o(),T(),a();var ue={class:`flex-col-gap`},de={class:`flex-between`},fe={class:`muted-sm`},pe={class:`login-row`},me={class:`muted-sm`},he={class:`flex-between`},ge={class:`monitor-row`},_e={class:`save-bar`},ve=h(c({__name:`SettingsView`,setup(e){let{toast:a}=A(),o=k(),c=n(`basic`),h=n(!0),T=n(!1),E=n(``),D=async()=>{E.value&&(await M(E.value)?a(`已复制到剪贴板`,`success`):a(`复制失败`,`error`))},O=n(29770),N=n(null),P=n(!0),F=n(null),I=n(null),L=n(``),R=n(``),z=y(()=>E.value.trim()!==``||L.value!==``&&R.value!==``),B=n(!1),V=n(60),H=[{label:`10分钟`,value:10},{label:`30分钟`,value:30},{label:`1小时`,value:60},{label:`2小时`,value:120},{label:`5小时`,value:300},{label:`8小时`,value:480},{label:`12小时`,value:720},{label:`24小时`,value:1440}],{loadError:U,run:W}=j(`设置加载失败,请重试`),G=()=>W(async()=>{try{await o.load(),E.value=o.config.masterKey||``,O.value=o.config.port??29770;let e=o.config[`web-ui`]?.[`login-account`];L.value=e?.username||``,R.value=e?.password||``,P.value=o.config.allowLan!==!1;let t=o.config.latencyTest;B.value=t?.enabled===!0,V.value=t?.intervalMinutes??60;try{let e=await p.get(`/api/status`);N.value=e.listenPort,F.value=e.listenHost??null,I.value=e.listenSource??null}catch{N.value=null,F.value=null,I.value=null}}finally{h.value=!1}}),q=async()=>{if(L.value.trim()!==``||R.value!==``){if(L.value.trim()===``||R.value===``){a(`用户名和密码需同时填写`,`error`);return}if(R.value.length<6){a(`密码至少 6 位`,`error`);return}}T.value=!0;let e=B.value&&o.config.latencyTest?.enabled!==!0;try{let t=await o.update(e=>{e.masterKey=E.value.trim(),e.port=O.value,e.allowLan=P.value,e.latencyTest={enabled:B.value,intervalMinutes:V.value},e[`web-ui`]??={},e[`web-ui`][`login-account`]??={},e[`web-ui`][`login-account`].username=L.value.trim(),e[`web-ui`][`login-account`].password=R.value});await b(!0),a(`设置已保存并生效`,`success`),e&&a(`已开启自动测试:服务将定期直连所有上游发送探测请求,有少量 token 消耗`,`warning`),t.restartHint&&a(t.restartHint,`warning`)}catch(e){a(e.message,`error`)}finally{T.value=!1}};return d(G),(e,n)=>{let a=m(`el-button`),o=m(`el-alert`),d=m(`el-tag`),p=m(`el-input`),y=m(`el-form-item`),b=m(`el-input-number`),k=m(`el-form`),A=m(`el-card`),j=m(`el-switch`),M=m(`el-divider`),W=m(`el-option`),J=m(`el-select`),Y=m(`el-tab-pane`),X=m(`el-tabs`),Z=x(`loading`);return w(),v(X,{modelValue:c.value,"onUpdate:modelValue":n[7]||=e=>c.value=e,class:`settings-tabs`},{default:_(()=>[s(Y,{label:`基本设置`,name:`basic`},{default:_(()=>[g((w(),u(`div`,ue,[i(U)?(w(),v(o,{key:0,title:i(U),type:`error`,"show-icon":``,closable:!1},{default:_(()=>[s(a,{size:`small`,onClick:G},{default:_(()=>[...n[8]||=[r(`重试`,-1)]]),_:1})]),_:1},8,[`title`])):l(``,!0),s(A,{shadow:`never`},{header:_(()=>[t(`div`,de,[n[10]||=t(`span`,{class:`fw-600`},`网关访问`,-1),s(d,{type:`success`},{default:_(()=>[...n[9]||=[r(`运行中`,-1)]]),_:1})])]),default:_(()=>[s(k,{"label-position":`top`},{default:_(()=>[s(y,{label:`API 密钥 (masterKey)`},{default:_(()=>[s(p,{modelValue:E.value,"onUpdate:modelValue":n[0]||=e=>E.value=e,placeholder:`sk-1234`,clearable:``},{append:_(()=>[s(a,{onClick:D},{default:_(()=>[...n[11]||=[r(`复制`,-1)]]),_:1})]),_:1},8,[`modelValue`]),n[12]||=t(`div`,{class:`muted-sm`},` 客户端请求 /v1/* 时的认证密钥(Bearer <masterKey>;留空 = 本地放行) `,-1)]),_:1}),s(y,{label:`监听端口 (port)`},{default:_(()=>[s(b,{modelValue:O.value,"onUpdate:modelValue":n[1]||=e=>O.value=e,min:1,max:65535,step:1,style:{width:`220px`}},null,8,[`modelValue`]),t(`div`,fe,[n[14]||=r(` 网关与管理台 API 的监听端口,保存后重启生效 `,-1),N.value===null?l(``,!0):(w(),u(f,{key:0},[n[13]||=r(` ;服务上报的端口 `,-1),t(`b`,null,S(N.value),1),I.value===`env`?(w(),u(f,{key:0},[r(`(监听配置由环境变量覆盖,此配置值不生效)`)],64)):l(``,!0)],64))])]),_:1})]),_:1})]),_:1}),s(A,{shadow:`never`},{header:_(()=>[...n[15]||=[t(`span`,{class:`fw-600`},`安全与登录`,-1)]]),default:_(()=>[s(k,{"label-position":`top`},{default:_(()=>[s(y,{label:`管理台登录账号`},{default:_(()=>[t(`div`,pe,[s(p,{modelValue:L.value,"onUpdate:modelValue":n[2]||=e=>L.value=e,placeholder:`用户名`,style:{width:`200px`}},null,8,[`modelValue`]),s(p,{modelValue:R.value,"onUpdate:modelValue":n[3]||=e=>R.value=e,type:`password`,placeholder:`密码(至少 6 位)`,"show-password":``,style:{width:`200px`}},null,8,[`modelValue`])]),n[16]||=t(`div`,{class:`muted-sm`},` 管理台登录凭证;留空 = 免登录直接访问(仅本机使用时推荐)。 修改后立即生效,需用新账号重新登录 `,-1)]),_:1}),s(y,{label:`允许局域网访问 (allowLan)`},{default:_(()=>[s(j,{modelValue:P.value,"onUpdate:modelValue":n[4]||=e=>P.value=e},null,8,[`modelValue`]),t(`div`,me,[n[19]||=r(` 开启 = 绑定全部网卡,局域网内设备可访问;关闭 = 仅本机 127.0.0.1。保存后需重启生效 `,-1),I.value===`env`?(w(),u(f,{key:0},[n[17]||=r(` ;当前实际监听 `,-1),t(`b`,null,S(F.value),1),n[18]||=r(`(由 HOST 环境变量覆盖,此开关不生效) `,-1)],64)):z.value?l(``,!0):(w(),u(f,{key:1},[r(` ;未设置任何凭据(密钥与登录账号皆无)时始终仅绑本机 `)],64))])]),_:1})]),_:1})]),_:1}),s(A,{shadow:`never`},{header:_(()=>[t(`div`,he,[n[20]||=t(`span`,{class:`fw-600`},`模型服务监控`,-1),s(d,{type:B.value?`success`:`info`,size:`small`,"disable-transitions":``},{default:_(()=>[r(S(B.value?`已开启`:`未开启`),1)]),_:1},8,[`type`])])]),default:_(()=>[t(`div`,ge,[n[21]||=t(`div`,{class:`monitor-info`},[t(`div`,{class:`monitor-title`},`自动测试模型服务状态`),t(`div`,{class:`muted-sm`},` 按设定间隔自动直连所有上游模型发送极小探测请求(max_tokens: 1,有少量 token 消耗); 测试结果展示在「服务状态」页面 `)],-1),s(j,{modelValue:B.value,"onUpdate:modelValue":n[5]||=e=>B.value=e},null,8,[`modelValue`])]),B.value?(w(),u(f,{key:0},[s(M,{style:{margin:`12px 0`}}),s(k,{"label-position":`top`},{default:_(()=>[s(y,{label:`测试间隔`,style:{"margin-bottom":`0`}},{default:_(()=>[s(J,{modelValue:V.value,"onUpdate:modelValue":n[6]||=e=>V.value=e,style:{width:`220px`}},{default:_(()=>[(w(),u(f,null,C(H,e=>s(W,{key:e.value,label:e.label,value:e.value},null,8,[`label`,`value`])),64))]),_:1},8,[`modelValue`]),n[22]||=t(`div`,{class:`muted-sm`},` 自动测试的执行间隔,保存后即时生效(无需重启) `,-1)]),_:1})]),_:1})],64)):l(``,!0)]),_:1}),t(`div`,_e,[s(a,{type:`primary`,size:`large`,loading:T.value,disabled:T.value||i(U)!==null,onClick:q},{default:_(()=>[r(S(T.value?`保存中...`:`保存设置`),1)]),_:1},8,[`loading`,`disabled`])])])),[[Z,h.value]])]),_:1}),s(Y,{label:`代理开关`,name:`harness`,lazy:``},{default:_(()=>[s(K)]),_:1}),s(Y,{label:`服务与更新`,name:`service`,lazy:``},{default:_(()=>[s($)]),_:1})]),_:1},8,[`modelValue`])}}}),[[`__scopeId`,`data-v-e1ea3ddd`]]);export{ve as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.setup-wrap[data-v-52af652f]{background:#f5f7fa;justify-content:center;align-items:center;min-height:100vh;display:flex}.setup-card[data-v-52af652f]{width:520px;max-width:92vw}.setup-title[data-v-52af652f]{text-align:center;color:#3b82f6;margin-bottom:20px}.account-row[data-v-52af652f]{gap:12px;width:100%;display:flex}.label-hint[data-v-52af652f]{color:#909399;font-size:12px;font-weight:400;line-height:1.4;display:block}.full-width[data-v-52af652f]{width:100%}.mb-16[data-v-52af652f]{margin-bottom:16px}
|
|
@@ -0,0 +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,Q as l,a as u,at as d,d as f,h as p,ht as m,j as h,n as g,pt as _,r as v,tt as y,u as b,yt as x}from"./router-CjERSWL9.js";import{t as S}from"./message-CPl1jEnd.js";import{t as C}from"./clipboard-CorU9X8e.js";i(),p(),x();var w={class:`setup-wrap`},T={class:`account-row`},E=f(o({__name:`SetupView`,setup(i){let o=b(),f=n(!1),p=n(``),x=!1,E=n(``),D=n(``),O=n(!1),k=n(``);l(async()=>{!(await g()).masterKeySet&&f.value&&A()});function A(){p.value=j(),x=!0}_(f,e=>{e?p.value.trim()===``&&A():x&&=(p.value=``,!1)});function j(){let e=new Uint8Array(32);crypto.getRandomValues(e);let t=``;for(let n of e)t+=String.fromCharCode(n);return btoa(t).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/,``)}async function M(){await C(p.value)?S.success(`已复制到剪贴板`):S.error(`复制失败,请手动选择复制`)}async function N(){k.value=``;let e=f.value?`server`:`local`,t=p.value.trim(),n=E.value.trim()!==``||D.value!==``;if(f.value&&t===``){k.value=`服务器部署必须设置主密钥,防止 /v1 网关被他人盗用`;return}if(f.value&&!n){k.value=`服务器部署必须设置登录账号密码,防止管理台被陌生人登录`;return}if(n){if(E.value.trim()===``||D.value===``){k.value=`用户名和密码需同时填写`;return}if(D.value.length<6){k.value=`密码至少 6 位`;return}}O.value=!0;try{let r=t===``?null:await u.post(`/api/setup/master-key`,{mode:`custom`,masterKey:t}),i=await u.post(`/api/setup/finish`,{deployment:e,...n?{username:E.value.trim(),password:D.value}:{}});v(e,n),S.success(n?`初始化完成,请使用新账号登录`:`初始化完成,免登录进入管理台`);let a=r?.restartHint??i.restartHint;a&&S({message:a,type:`warning`,duration:8e3}),await o.push(n?`/login`:`/`)}catch(e){k.value=e.message||`保存失败`}finally{O.value=!1}}return(n,i)=>{let o=d(`el-checkbox`),l=d(`el-alert`),u=d(`el-button`),g=d(`el-input`),_=d(`el-form-item`),v=d(`el-form`),b=d(`el-card`);return y(),c(`div`,w,[a(b,{shadow:`hover`,class:`setup-card`},{default:m(()=>[i[10]||=e(`h2`,{class:`setup-title`},`初始化 EZLLM`,-1),a(o,{modelValue:f.value,"onUpdate:modelValue":i[0]||=e=>f.value=e,class:`mb-16`},{default:m(()=>[...i[4]||=[r(` 允许其他设备访问本服务(局域网 / 公网部署) `,-1)]]),_:1},8,[`modelValue`]),f.value?(y(),h(l,{key:0,type:`warning`,"show-icon":``,closable:!1,title:`服务将对网络中的其他设备可见,请务必保留主密钥并修改默认账号`,class:`mb-16`})):s(``,!0),a(v,{"label-position":`top`,onSubmit:t(N,[`prevent`])},{default:m(()=>[a(_,null,{label:m(()=>[...i[5]||=[r(` API 主密钥(本地部署可留空) `,-1),e(`span`,{class:`label-hint`},`调用 /v1/* 时的 Bearer Token;留空 = 不启用鉴权,且未设登录账号时服务仅本机可访问`,-1)]]),default:m(()=>[a(g,{modelValue:p.value,"onUpdate:modelValue":i[1]||=e=>p.value=e,placeholder:`已设置主密钥,留空保持不变`,clearable:``},{append:m(()=>[a(u,{onClick:A},{default:m(()=>[...i[6]||=[r(`生成`,-1)]]),_:1}),a(u,{disabled:!p.value,onClick:M},{default:m(()=>[...i[7]||=[r(`复制`,-1)]]),_:1},8,[`disabled`])]),_:1},8,[`modelValue`])]),_:1}),a(_,null,{label:m(()=>[...i[8]||=[r(` 管理台登录(可选) `,-1),e(`span`,{class:`label-hint`},`不填 = 免登录直接进管理台(纯本机使用);勾选上方后必须填写`,-1)]]),default:m(()=>[e(`div`,T,[a(g,{modelValue:E.value,"onUpdate:modelValue":i[2]||=e=>E.value=e,placeholder:`用户名`,clearable:``},null,8,[`modelValue`]),a(g,{modelValue:D.value,"onUpdate:modelValue":i[3]||=e=>D.value=e,type:`password`,"show-password":``,placeholder:`密码(至少 6 位)`},null,8,[`modelValue`])])]),_:1}),k.value?(y(),h(l,{key:0,title:k.value,type:`error`,"show-icon":``,closable:!1,class:`mb-16`},null,8,[`title`])):s(``,!0),a(u,{type:`primary`,class:`full-width`,loading:O.value,onClick:N},{default:m(()=>[...i[9]||=[r(` 完成初始化 `,-1)]]),_:1},8,[`loading`])]),_:1})]),_:1})])}}}),[[`__scopeId`,`data-v-52af652f`]]);export{E as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
async function e(e){try{if(navigator.clipboard&&window.isSecureContext)return await navigator.clipboard.writeText(e),!0}catch{}try{let t=document.createElement(`textarea`);t.value=e,t.style.position=`fixed`,t.style.opacity=`0`,document.body.appendChild(t),t.select();let n=document.execCommand(`copy`);return document.body.removeChild(t),n}catch{return!1}}export{e as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Et as e,H as t,a as n,k as r,yt as i}from"./router-CjERSWL9.js";import{n as a}from"./index-D8q_jlRU.js";i(),t();var o=a(`config`,()=>{let t=e({}),i=e(!1),a=r(()=>Array.isArray(t.value.providers)?t.value.providers:[]),o=r(()=>a.value.length),s=r(()=>a.value.reduce((e,t)=>e+(t.models?.length??0),0));async function c(){i.value=!0;try{t.value=await n.get(`/api/config`)}finally{i.value=!1}}async function l(){return await n.put(`/api/config`,t.value)}async function u(e){return e(t.value),await l()}return{config:t,loading:i,providers:a,providerCount:o,totalModelCount:s,load:c,save:l,update:u}});export{o as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=e=>{if(!e)return`-`;let t=new Date(e);if(Number.isNaN(t.getTime()))return`-`;let n=e=>String(e).padStart(2,`0`);return`${t.getFullYear()}-${n(t.getMonth()+1)}-${n(t.getDate())} ${n(t.getHours())}:${n(t.getMinutes())}:${n(t.getSeconds())}`},t=e=>e?typeof e==`string`?e:JSON.stringify(e,null,2):`-`,n=e=>{if(!e)return`-`;try{return JSON.stringify(JSON.parse(e),null,2)}catch{return e}},r=e=>(e??0).toLocaleString(),i=e=>e?e>=1024**3?(e/1024**3).toFixed(1)+`G`:e>=1024**2?(e/1024**2).toFixed(1)+`M`:e>=1024?(e/1024).toFixed(1)+`K`:`${e}B`:`-`,a=({protocol:e,hostname:t,port:n})=>`${e===`https:`?`https:`:`http:`}//${t}${n?`:${n}`:``}`,o=e=>e==null||e<=0?`-`:e>=1e3?(e/1e3).toFixed(2)+`s`:Math.round(e)+`ms`,s=e=>e==null?`-`:e<1e3?`${String(e)}ms`:`${(e/1e3).toFixed(1)}s`,c=e=>{let t=e.input_tokens||0,n=e.cache_read_tokens||0;return t<=0?`-`:(n/t*100).toFixed(1)+`%`};export{i as a,e as c,s as i,n as l,c as n,r as o,o as r,t as s,a as t};
|