diff --git a/cmd/JoyCodeProxy/static/assets/AccountDetail-DEkC2vuX.js b/cmd/JoyCodeProxy/static/assets/AccountDetail-qwdKolAO.js similarity index 99% rename from cmd/JoyCodeProxy/static/assets/AccountDetail-DEkC2vuX.js rename to cmd/JoyCodeProxy/static/assets/AccountDetail-qwdKolAO.js index 48722a2..ea2cb29 100644 --- a/cmd/JoyCodeProxy/static/assets/AccountDetail-DEkC2vuX.js +++ b/cmd/JoyCodeProxy/static/assets/AccountDetail-qwdKolAO.js @@ -1,3 +1,3 @@ -import{r as e}from"./rolldown-runtime-S-ySWqyJ.js";import{$ as t,B as n,C as r,D as i,E as a,F as o,H as s,I as c,J as ee,K as te,M as ne,Q as re,R as ie,S as ae,U as oe,X as se,Y as ce,_ as l,at as u,b as le,et as d,h as ue,j as f,k as de,mt as p,ot as m,p as h,r as fe,rt as g,st as pe,tt as _,ut as me,w as v}from"./antd-BIDKISxA.js";import{l as he,t as y,u as ge}from"./vendor-C3SDdTD0.js";import{n as b,t as x}from"./index-C0OoGTlz.js";import{a as S,c as C,d as w,f as T,i as E,l as _e,n as ve,o as ye,r as be,s as D,t as O,u as xe}from"./recharts-abRO4Y-P.js";import{n as Se,r as Ce,t as k}from"./CommandTooltip-Cw9Jxov1.js";var A=e(p(),1),j=y(),M=[{label:`JoyAI-Code(推荐)`,value:`JoyAI-Code`},{label:`Claude-Opus-4.7`,value:`Claude-Opus-4.7`},{label:`GLM-5.1`,value:`GLM-5.1`},{label:`GLM-5`,value:`GLM-5`},{label:`GLM-4.7`,value:`GLM-4.7`},{label:`Kimi-K2.6`,value:`Kimi-K2.6`},{label:`Kimi-K2.5`,value:`Kimi-K2.5`},{label:`MiniMax-M2.7`,value:`MiniMax-M2.7`},{label:`Doubao-Seed-2.0-pro`,value:`Doubao-Seed-2.0-pro`}],N=e=>e===`Claude-Opus-4.7`,P=[`#00b578`,`#36cfc9`,`#73d13d`,`#95de64`,`#1890ff`,`#13c2c2`,`#eb2f96`,`#fa8c16`],we=e=>e<500?`#52c41a`:e<1500?`#faad14`:`#ff4d4f`,F=e=>e>=1e6?(e/1e6).toFixed(2)+`M`:e>=1e3?(e/1e3).toFixed(1)+`K`:e.toLocaleString(),Te=e=>e>=200&&e<300?(0,j.jsx)(f,{color:`success`,children:e}):e>=400&&e<500?(0,j.jsx)(f,{color:`warning`,children:e}):(0,j.jsx)(f,{color:`error`,children:e}),I=e=>{if(!e)return`-`;let t=new Date(e+(e.includes(`Z`)||e.includes(`+`)?``:`Z`));if(isNaN(t.getTime()))return e;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())}`},L=e=>{if(e<1e3)return`${e}ms`;let t=Math.floor(e/1e3),n=e%1e3;if(t<60)return`${t}s${n>0?` ${n}ms`:``}`;let r=Math.floor(t/60),i=t%60;return`${r}m${i>0?` ${i}s`:``}`},R=()=>`${window.location.protocol}//${window.location.host}`,z=(e,t=`GLM-5.1`)=>[`API_TIMEOUT_MS=6000000 \\`,`CLAUDE_CODE_MAX_RETRIES=3 \\`,`NODE_TLS_REJECT_UNAUTHORIZED=0 \\`,`ANTHROPIC_BASE_URL=${R()} \\`,`ANTHROPIC_API_KEY="${e}" \\`,`CLAUDE_CODE_MAX_OUTPUT_TOKENS=6553655 \\`,`ANTHROPIC_MODEL=${t} \\`,`claude --dangerously-skip-permissions`].join(` +import{r as e}from"./rolldown-runtime-S-ySWqyJ.js";import{$ as t,B as n,C as r,D as i,E as a,F as o,H as s,I as c,J as ee,K as te,M as ne,Q as re,R as ie,S as ae,U as oe,X as se,Y as ce,_ as l,at as u,b as le,et as d,h as ue,j as f,k as de,mt as p,ot as m,p as h,r as fe,rt as g,st as pe,tt as _,ut as me,w as v}from"./antd-BIDKISxA.js";import{l as he,t as y,u as ge}from"./vendor-C3SDdTD0.js";import{n as b,t as x}from"./index-62d9Y_mr.js";import{a as S,c as C,d as w,f as T,i as E,l as _e,n as ve,o as ye,r as be,s as D,t as O,u as xe}from"./recharts-abRO4Y-P.js";import{n as Se,r as Ce,t as k}from"./CommandTooltip-Cw9Jxov1.js";var A=e(p(),1),j=y(),M=[{label:`JoyAI-Code(推荐)`,value:`JoyAI-Code`},{label:`Claude-Opus-4.7`,value:`Claude-Opus-4.7`},{label:`GLM-5.1`,value:`GLM-5.1`},{label:`GLM-5`,value:`GLM-5`},{label:`GLM-4.7`,value:`GLM-4.7`},{label:`Kimi-K2.6`,value:`Kimi-K2.6`},{label:`Kimi-K2.5`,value:`Kimi-K2.5`},{label:`MiniMax-M2.7`,value:`MiniMax-M2.7`},{label:`Doubao-Seed-2.0-pro`,value:`Doubao-Seed-2.0-pro`}],N=e=>e===`Claude-Opus-4.7`,P=[`#00b578`,`#36cfc9`,`#73d13d`,`#95de64`,`#1890ff`,`#13c2c2`,`#eb2f96`,`#fa8c16`],we=e=>e<500?`#52c41a`:e<1500?`#faad14`:`#ff4d4f`,F=e=>e>=1e6?(e/1e6).toFixed(2)+`M`:e>=1e3?(e/1e3).toFixed(1)+`K`:e.toLocaleString(),Te=e=>e>=200&&e<300?(0,j.jsx)(f,{color:`success`,children:e}):e>=400&&e<500?(0,j.jsx)(f,{color:`warning`,children:e}):(0,j.jsx)(f,{color:`error`,children:e}),I=e=>{if(!e)return`-`;let t=new Date(e+(e.includes(`Z`)||e.includes(`+`)?``:`Z`));if(isNaN(t.getTime()))return e;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())}`},L=e=>{if(e<1e3)return`${e}ms`;let t=Math.floor(e/1e3),n=e%1e3;if(t<60)return`${t}s${n>0?` ${n}ms`:``}`;let r=Math.floor(t/60),i=t%60;return`${r}m${i>0?` ${i}s`:``}`},R=()=>`${window.location.protocol}//${window.location.host}`,z=(e,t=`GLM-5.1`)=>[`API_TIMEOUT_MS=6000000 \\`,`CLAUDE_CODE_MAX_RETRIES=3 \\`,`NODE_TLS_REJECT_UNAUTHORIZED=0 \\`,`ANTHROPIC_BASE_URL=${R()} \\`,`ANTHROPIC_API_KEY="${e}" \\`,`CLAUDE_CODE_MAX_OUTPUT_TOKENS=6553655 \\`,`ANTHROPIC_MODEL=${t} \\`,`claude --dangerously-skip-permissions`].join(` `),B=(e,t=`GLM-5.1`)=>[`OPENAI_BASE_URL=${R()}/v1 \\`,`OPENAI_API_KEY="${e}" \\`,`OPENAI_MODEL=${t} \\`,`codex`].join(` `),V=async(e,t)=>{try{if(navigator.clipboard?.writeText)await navigator.clipboard.writeText(e);else{let t=document.createElement(`textarea`);t.value=e,t.style.cssText=`position:fixed;left:-9999px`,document.body.appendChild(t),t.select(),document.execCommand(`copy`),document.body.removeChild(t)}s.success(`${t} 命令已复制到剪贴板`)}catch{s.error(`复制失败`)}},H=()=>{let{userId:e}=ge(),p=he(),[y,R]=(0,A.useState)(null),[H,Ee]=(0,A.useState)(null),[U,De]=(0,A.useState)([]),[Oe,ke]=(0,A.useState)([]),[Ae,W]=(0,A.useState)(!0),[je,G]=(0,A.useState)(!1),[Me,K]=(0,A.useState)(!1),[q,J]=(0,A.useState)(`all`),[Y,Ne]=(0,A.useState)(0),X=e?decodeURIComponent(e):``,Z=async()=>{W(!0);try{let[e,t,n]=await Promise.all([b.listAccounts(),b.getAccountStats(X),b.getAccountLogs(X,500)]);R(e.find(e=>e.user_id===X)||null),Ee(t),De(n.logs||[])}catch(e){s.error(e instanceof Error?e.message:`加载失败`)}finally{W(!1)}},Q=async()=>{G(!0);try{ke(await b.listAccountModels(X))}catch{}finally{G(!1)}};(0,A.useEffect)(()=>{Z()},[X]),(0,A.useEffect)(()=>{Q()},[X]),(0,A.useEffect)(()=>{let e=async()=>{try{let e=(await b.listAccounts()).find(e=>e.user_id===X);e&&Ne(e.active_sessions)}catch{}};e();let t=setInterval(e,5e3);return()=>clearInterval(t)},[X]);let Pe=async e=>{K(!0);try{await b.updateAccountModel(X,e),s.success(`默认模型已更新为「${e||`未设置`}」`),Z()}catch(e){s.error(e instanceof Error?e.message:`更新失败`)}finally{K(!1)}};if(Ae)return(0,j.jsx)(oe,{size:`large`,style:{display:`block`,margin:`100px auto`}});if(!y)return(0,j.jsx)(`div`,{style:{textAlign:`center`,padding:100},children:`账号不存在`});let Fe=[...M,...Oe.filter(e=>!M.some(t=>t.value===e.id)).map(e=>({label:e.name||e.id,value:e.id}))],Ie=q===`all`?U:q===`errors`?U.filter(e=>e.status_code>=400):U.filter(e=>e.stream),$=H?.by_endpoint.map(e=>({name:e.endpoint.replace(`/v1/`,``),value:e.count}))||[];return(0,j.jsxs)(`div`,{children:[(0,j.jsxs)(`div`,{style:{marginBottom:20,display:`flex`,alignItems:`center`,gap:12,borderBottom:`1px solid #f0f0f0`,paddingBottom:16},children:[(0,j.jsx)(g,{icon:(0,j.jsx)(r,{}),onClick:()=>p(`/accounts`),type:`text`}),(0,j.jsxs)(`div`,{style:{flex:1},children:[(0,j.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:8},children:[(0,j.jsx)(a.Title,{level:4,style:{margin:0},children:x(y)}),y.is_default&&(0,j.jsx)(f,{color:`blue`,children:`默认`})]}),(0,j.jsxs)(a.Text,{type:`secondary`,style:{fontSize:12},children:[y.user_id,` · 创建于 `,y.created_at?.slice(0,10)||`-`]}),(0,j.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:6,marginTop:4},children:[(0,j.jsx)(a.Text,{type:`secondary`,style:{fontSize:12},children:`Token:`}),(0,j.jsx)(a.Text,{code:!0,copyable:!0,style:{fontSize:11},children:y.api_token})]}),(0,j.jsx)(`div`,{style:{marginTop:6},children:Y>0?(0,j.jsx)(u,{status:`processing`,color:`blue`,text:(0,j.jsxs)(a.Text,{style:{fontSize:12,color:`#1890ff`},children:[Y,` 个活跃会话`]})}):(0,j.jsx)(u,{status:`default`,text:(0,j.jsx)(a.Text,{type:`secondary`,style:{fontSize:12},children:`无活跃会话`})})})]}),(0,j.jsxs)(ce,{children:[(0,j.jsx)(m,{title:`此模型的用途仅限生成下方的快速启动命令。实际请求中的模型由客户端指定(如 ANTHROPIC_MODEL 环境变量),始终优先于本设置。模型列表来自 JoyCode API 支持的模型 + 服务器动态获取的扩展模型。`,children:(0,j.jsx)(ee,{style:{color:`#999`,cursor:`help`}})}),(0,j.jsx)(pe,{style:{width:220},value:y.default_model||void 0,placeholder:`默认模型`,options:Fe,allowClear:!0,loading:je,onChange:Pe,disabled:Me,size:`small`}),N(y.default_model)&&(0,j.jsx)(m,{title:`Claude 模型需要本机登录 JoyCode IDE`,children:(0,j.jsx)(h,{style:{color:`#faad14`}})}),(0,j.jsx)(g,{size:`small`,onClick:async()=>{try{await b.renewToken(X),s.success(`API Token 已更新`),Z()}catch(e){s.error(e instanceof Error?e.message:`更新失败`)}},children:`重置 Token`}),(0,j.jsx)(g,{size:`small`,icon:(0,j.jsx)(ie,{}),onClick:()=>{Z(),Q()},children:`刷新`}),(0,j.jsx)(n,{title:`确定要删除账号「${x(y)}」吗?`,description:`删除后使用该密钥的客户端将无法访问`,onConfirm:async()=>{try{await b.removeAccount(X),s.success(`账号「${x(y)}」已删除`),p(`/accounts`)}catch(e){s.error(e instanceof Error?e.message:`删除账号失败`)}},children:(0,j.jsx)(g,{size:`small`,danger:!0,icon:(0,j.jsx)(de,{}),children:`删除`})})]})]}),N(y.default_model)&&(0,j.jsx)(me,{type:`warning`,showIcon:!0,message:`Claude 模型需要 JoyCode IDE 登录态`,description:`请确保本机 JoyCode IDE 已登录,否则 Claude 模型无法使用。`,style:{marginBottom:16}}),(0,j.jsxs)(_,{size:`small`,style:{marginBottom:16},children:[(0,j.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,justifyContent:`space-between`,marginBottom:10},children:[(0,j.jsx)(a.Text,{strong:!0,style:{fontSize:13},children:`快速启动命令`}),(0,j.jsx)(m,{title:`模型优先级:客户端指定的模型(如启动命令中的 ANTHROPIC_MODEL)始终优先。上方设置的「默认模型」仅用于生成这些命令中的模型参数。如果你手动修改了启动命令中的模型,以你手动指定的为准。`,children:(0,j.jsxs)(a.Text,{style:{fontSize:12,color:`#999`,cursor:`help`},children:[(0,j.jsx)(h,{}),` 模型优先级说明`]})})]}),(0,j.jsxs)(c,{gutter:[16,12],children:[(0,j.jsx)(d,{xs:24,md:12,children:(0,j.jsxs)(`div`,{style:{background:`#f6f5f0`,borderRadius:6,padding:`10px 14px`},children:[(0,j.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,justifyContent:`space-between`,marginBottom:6},children:[(0,j.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:6},children:[(0,j.jsx)(Ce,{}),(0,j.jsx)(a.Text,{strong:!0,style:{fontSize:13},children:`Claude Code`})]}),(0,j.jsx)(k,{command:z(y.api_token,y.default_model||void 0),label:`Claude Code`,children:(0,j.jsx)(g,{type:`text`,size:`small`,icon:(0,j.jsx)(i,{}),onClick:()=>V(z(y.api_token,y.default_model||void 0),`Claude Code`)})})]}),(0,j.jsx)(`pre`,{style:{margin:0,fontFamily:`monospace`,fontSize:11,lineHeight:1.6,whiteSpace:`pre-wrap`,color:`#333`},children:z(y.api_token,y.default_model||void 0)})]})}),(0,j.jsx)(d,{xs:24,md:12,children:(0,j.jsxs)(`div`,{style:{background:`#f0faf5`,borderRadius:6,padding:`10px 14px`},children:[(0,j.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,justifyContent:`space-between`,marginBottom:6},children:[(0,j.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:6},children:[(0,j.jsx)(Se,{}),(0,j.jsx)(a.Text,{strong:!0,style:{fontSize:13},children:`Codex`})]}),(0,j.jsx)(k,{command:B(y.api_token,y.default_model||void 0),label:`Codex`,children:(0,j.jsx)(g,{type:`text`,size:`small`,icon:(0,j.jsx)(i,{}),onClick:()=>V(B(y.api_token,y.default_model||void 0),`Codex`)})})]}),(0,j.jsx)(`pre`,{style:{margin:0,fontFamily:`monospace`,fontSize:11,lineHeight:1.6,whiteSpace:`pre-wrap`,color:`#333`},children:B(y.api_token,y.default_model||void 0)})]})})]})]}),(0,j.jsx)(_,{size:`small`,style:{marginBottom:16,borderRadius:8,background:Y>0?`#f6ffed`:`#fafafa`,border:Y>0?`1px solid #b7eb8f`:void 0},children:(0,j.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:12},children:[(0,j.jsx)(u,{status:Y>0?`processing`:`default`}),(0,j.jsx)(a.Text,{strong:!0,style:{fontSize:13},children:`实时状态`}),(0,j.jsxs)(a.Text,{style:{fontSize:13},children:[`当前有 `,(0,j.jsx)(a.Text,{strong:!0,style:{fontSize:16,color:Y>0?`#1890ff`:void 0},children:Y}),` 个活跃连接`]}),Y>0&&(0,j.jsx)(f,{color:`blue`,children:`请求处理中`}),(0,j.jsx)(a.Text,{type:`secondary`,style:{fontSize:11,marginLeft:`auto`},children:`每 5 秒自动刷新`})]})}),H&&(0,j.jsxs)(c,{gutter:[16,16],style:{marginBottom:20},children:[(0,j.jsx)(d,{xs:24,md:12,children:(0,j.jsx)(_,{title:(0,j.jsxs)(`span`,{children:[(0,j.jsx)(v,{style:{marginRight:6}}),`请求统计`]}),size:`small`,style:{borderRadius:8,height:`100%`},children:(0,j.jsxs)(c,{gutter:[8,12],children:[(0,j.jsx)(d,{span:12,children:(0,j.jsx)(o,{title:`今日请求`,value:H.total_requests,valueStyle:{fontSize:20,color:`#00b578`},prefix:(0,j.jsx)(v,{})})}),(0,j.jsx)(d,{span:12,children:(0,j.jsx)(o,{title:`累计请求`,value:H.all_time?.total_requests??0,valueStyle:{fontSize:20}})}),(0,j.jsxs)(d,{span:12,children:[(0,j.jsx)(o,{title:`今日成功`,value:H.success_count,prefix:(0,j.jsx)(ae,{}),valueStyle:{fontSize:18,color:`#52c41a`}}),(0,j.jsxs)(a.Text,{type:`secondary`,style:{fontSize:11},children:[`占比 `,H.total_requests>0?Math.round(H.success_count/H.total_requests*100):100,`%`]})]}),(0,j.jsxs)(d,{span:12,children:[(0,j.jsx)(o,{title:`今日失败`,value:H.error_count,prefix:(0,j.jsx)(le,{}),valueStyle:{fontSize:18,color:H.error_count>0?`#ff4d4f`:`#52c41a`}}),(0,j.jsxs)(a.Text,{type:`secondary`,style:{fontSize:11},children:[`占比 `,H.total_requests>0?Math.round(H.error_count/H.total_requests*100):0,`%`]})]}),(0,j.jsxs)(d,{span:24,children:[(0,j.jsx)(t,{style:{margin:`4px 0 8px`}}),(0,j.jsxs)(c,{gutter:8,children:[(0,j.jsxs)(d,{span:12,children:[(0,j.jsx)(o,{title:`流式请求`,value:H.stream_count,prefix:(0,j.jsx)(te,{}),valueStyle:{fontSize:16}}),(0,j.jsxs)(f,{color:`blue`,style:{marginTop:2},children:[H.total_requests>0?Math.round(H.stream_count/H.total_requests*100):0,`%`]})]}),(0,j.jsx)(d,{span:12,children:(0,j.jsx)(o,{title:`平均延迟`,value:Math.round(H.avg_latency_ms),suffix:`ms`,prefix:(0,j.jsx)(fe,{}),valueStyle:{fontSize:16,color:H.avg_latency_ms<500?`#52c41a`:H.avg_latency_ms<1500?`#faad14`:`#ff4d4f`}})})]})]})]})})}),(0,j.jsx)(d,{xs:24,md:12,children:(0,j.jsx)(_,{title:(0,j.jsxs)(`span`,{children:[(0,j.jsx)(l,{style:{marginRight:6}}),`Token 消费`]}),size:`small`,style:{borderRadius:8,height:`100%`},children:(0,j.jsxs)(c,{gutter:[8,12],children:[(0,j.jsx)(d,{span:12,children:(0,j.jsx)(o,{title:`今日 Token`,value:F(H.total_input_tokens+H.total_output_tokens),valueStyle:{fontSize:20,color:`#389e0d`}})}),(0,j.jsx)(d,{span:12,children:(0,j.jsx)(o,{title:`累计 Token`,value:F((H.all_time?.total_input_tokens??0)+(H.all_time?.total_output_tokens??0)),valueStyle:{fontSize:20}})}),(0,j.jsx)(d,{span:12,children:(0,j.jsx)(o,{title:`今日输入`,value:F(H.total_input_tokens),valueStyle:{fontSize:16}})}),(0,j.jsx)(d,{span:12,children:(0,j.jsx)(o,{title:`今日输出`,value:F(H.total_output_tokens),valueStyle:{fontSize:16}})}),(0,j.jsxs)(d,{span:24,children:[(0,j.jsx)(t,{style:{margin:`4px 0 8px`}}),(0,j.jsxs)(c,{gutter:8,children:[(0,j.jsx)(d,{span:12,children:(0,j.jsx)(o,{title:`平均每请求`,value:H.total_requests>0?F(Math.round((H.total_input_tokens+H.total_output_tokens)/H.total_requests)):`-`,suffix:H.total_requests>0?`tokens`:``,valueStyle:{fontSize:15}})}),(0,j.jsx)(d,{span:12,children:(0,j.jsx)(o,{title:`输入/输出比`,value:H.total_output_tokens>0?(H.total_input_tokens/H.total_output_tokens).toFixed(1):`-`,suffix:H.total_output_tokens>0?`:1`:``,valueStyle:{fontSize:15}})})]})]})]})})})]}),H&&H.hourly&&H.hourly.length>0&&(()=>{let e=new Map;for(let t of H.hourly)e.set(t.hour,t);let t=new Date,n=[];for(let r=23;r>=0;r--){let i=new Date(t.getTime()-r*36e5),a=`${String(i.getMonth()+1).padStart(2,`0`)}-${String(i.getDate()).padStart(2,`0`)} ${String(i.getHours()).padStart(2,`0`)}`,o=e.get(a);n.push({label:`${String(i.getHours()).padStart(2,`0`)}:00`,count:o?.count??0,input_tokens:o?.input_tokens??0,output_tokens:o?.output_tokens??0,errors:o?.errors??0})}return(0,j.jsxs)(c,{gutter:[16,16],style:{marginBottom:20},children:[(0,j.jsx)(d,{xs:24,lg:12,children:(0,j.jsx)(_,{title:`24 小时请求趋势`,size:`small`,children:(0,j.jsx)(T,{width:`100%`,height:200,children:(0,j.jsxs)(O,{data:n,margin:{left:-10},children:[(0,j.jsx)(C,{strokeDasharray:`3 3`}),(0,j.jsx)(S,{dataKey:`label`,tick:{fontSize:11},interval:2}),(0,j.jsx)(E,{tick:{fontSize:11}}),(0,j.jsx)(w,{}),(0,j.jsx)(D,{type:`monotone`,dataKey:`count`,name:`请求数`,stroke:`#00b578`,fill:`#00b578`,fillOpacity:.15}),(0,j.jsx)(D,{type:`monotone`,dataKey:`errors`,name:`错误数`,stroke:`#ff4d4f`,fill:`#ff4d4f`,fillOpacity:.15})]})})})}),(0,j.jsx)(d,{xs:24,lg:12,children:(0,j.jsx)(_,{title:`24 小时 Token 消耗趋势`,size:`small`,children:(0,j.jsx)(T,{width:`100%`,height:200,children:(0,j.jsxs)(O,{data:n,margin:{left:-10},children:[(0,j.jsx)(C,{strokeDasharray:`3 3`}),(0,j.jsx)(S,{dataKey:`label`,tick:{fontSize:11},interval:2}),(0,j.jsx)(E,{tick:{fontSize:11}}),(0,j.jsx)(w,{}),(0,j.jsx)(D,{type:`monotone`,dataKey:`input_tokens`,name:`输入 Token`,stroke:`#1890ff`,fill:`#1890ff`,fillOpacity:.15}),(0,j.jsx)(D,{type:`monotone`,dataKey:`output_tokens`,name:`输出 Token`,stroke:`#73d13d`,fill:`#73d13d`,fillOpacity:.15})]})})})})]})})(),H&&(H.by_model.length>0||$.length>0)&&(0,j.jsxs)(c,{gutter:[16,16],style:{marginBottom:20},children:[H.by_model.length>0&&(0,j.jsx)(d,{xs:24,lg:14,children:(0,j.jsx)(_,{title:(0,j.jsxs)(j.Fragment,{children:[(0,j.jsx)(l,{}),` 模型使用分布`]}),size:`small`,children:(0,j.jsx)(T,{width:`100%`,height:200,children:(0,j.jsxs)(be,{data:H.by_model,layout:`vertical`,margin:{left:10},children:[(0,j.jsx)(C,{strokeDasharray:`3 3`}),(0,j.jsx)(S,{type:`number`}),(0,j.jsx)(E,{dataKey:`model`,type:`category`,width:100,tick:{fontSize:11}}),(0,j.jsx)(w,{}),(0,j.jsx)(ye,{dataKey:`count`,name:`请求数`,fill:`#00b578`,radius:[0,4,4,0]})]})})})}),$.length>0&&(0,j.jsx)(d,{xs:24,lg:10,children:(0,j.jsx)(_,{title:(0,j.jsxs)(j.Fragment,{children:[(0,j.jsx)(ue,{}),` 端点调用分布`]}),size:`small`,children:(0,j.jsx)(T,{width:`100%`,height:200,children:(0,j.jsxs)(ve,{children:[(0,j.jsx)(_e,{data:$,dataKey:`value`,nameKey:`name`,cx:`50%`,cy:`50%`,outerRadius:70,label:({name:e,percent:t})=>`${e||``} ${((t||0)*100).toFixed(0)}%`,labelLine:{strokeWidth:1},children:$.map((e,t)=>(0,j.jsx)(xe,{fill:P[t%P.length]},t))}),(0,j.jsx)(w,{})]})})})})]}),(0,j.jsx)(_,{title:(0,j.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:8},children:[(0,j.jsx)(se,{}),(0,j.jsx)(`span`,{children:`请求日志`}),(0,j.jsxs)(f,{children:[U.length,` 条`]})]}),size:`small`,extra:(0,j.jsx)(re,{size:`small`,value:q,onChange:e=>J(e),options:[{label:`全部`,value:`all`},{label:`流式`,value:`stream`},{label:`错误`,value:`errors`}]}),children:(0,j.jsx)(ne,{dataSource:Ie,columns:[{title:`时间`,dataIndex:`created_at`,key:`time`,width:170,render:e=>(0,j.jsx)(a.Text,{style:{fontSize:12,fontFamily:`monospace`},children:I(e)})},{title:`端点`,dataIndex:`endpoint`,key:`endpoint`,width:200,render:e=>(0,j.jsx)(a.Text,{code:!0,style:{fontSize:12},children:e})},{title:`模型`,dataIndex:`model`,key:`model`,width:140,ellipsis:!0,render:e=>e||(0,j.jsx)(a.Text,{type:`secondary`,children:`-`})},{title:`流式`,dataIndex:`stream`,key:`stream`,width:60,render:e=>e?(0,j.jsx)(u,{status:`processing`,text:``}):(0,j.jsx)(u,{status:`default`,text:``})},{title:`状态`,dataIndex:`status_code`,key:`status`,width:70,render:e=>Te(e)},{title:`输入`,dataIndex:`input_tokens`,key:`input`,width:80,sorter:(e,t)=>e.input_tokens-t.input_tokens,render:e=>(0,j.jsx)(a.Text,{style:{fontSize:12,fontFamily:`monospace`},children:e>0?F(e):`-`})},{title:`输出`,dataIndex:`output_tokens`,key:`output`,width:80,sorter:(e,t)=>e.output_tokens-t.output_tokens,render:e=>(0,j.jsx)(a.Text,{style:{fontSize:12,fontFamily:`monospace`},children:e>0?F(e):`-`})},{title:`延迟`,dataIndex:`latency_ms`,key:`latency`,width:100,sorter:(e,t)=>e.latency_ms-t.latency_ms,render:e=>(0,j.jsx)(a.Text,{style:{color:we(e),fontFamily:`monospace`,fontWeight:500},children:L(e)})}],rowKey:`id`,size:`small`,pagination:{pageSize:20,showSizeChanger:!1,showTotal:e=>`共 ${e} 条`},scroll:{x:980},locale:{emptyText:`暂无请求记录`},expandable:{expandedRowRender:e=>(0,j.jsxs)(`div`,{style:{padding:`8px 0 8px 12px`},children:[e.status_code>=400&&(0,j.jsxs)(`div`,{style:{marginBottom:10,padding:`10px 12px`,border:`1px solid #ffccc7`,borderRadius:6,background:`#fff2f0`},children:[(0,j.jsx)(a.Text,{strong:!0,style:{display:`block`,marginBottom:6,color:`#cf1322`},children:`错误详情`}),(0,j.jsx)(`pre`,{style:{margin:0,whiteSpace:`pre-wrap`,wordBreak:`break-word`,fontSize:12,lineHeight:1.6,color:`#cf1322`,fontFamily:`monospace`},children:e.error_message||`HTTP ${e.status_code}`})]}),(0,j.jsxs)(`div`,{style:{display:`grid`,gridTemplateColumns:`120px minmax(0, 1fr)`,gap:`6px 12px`,fontSize:12},children:[(0,j.jsx)(a.Text,{type:`secondary`,children:`请求 ID`}),(0,j.jsx)(a.Text,{code:!0,children:e.id}),(0,j.jsx)(a.Text,{type:`secondary`,children:`时间`}),(0,j.jsx)(a.Text,{children:I(e.created_at)}),(0,j.jsx)(a.Text,{type:`secondary`,children:`端点`}),(0,j.jsx)(a.Text,{code:!0,children:e.endpoint}),(0,j.jsx)(a.Text,{type:`secondary`,children:`模型`}),(0,j.jsx)(a.Text,{children:e.model||`-`}),(0,j.jsx)(a.Text,{type:`secondary`,children:`流式`}),(0,j.jsx)(a.Text,{children:e.stream?`是`:`否`}),(0,j.jsx)(a.Text,{type:`secondary`,children:`状态`}),(0,j.jsx)(a.Text,{children:e.status_code}),(0,j.jsx)(a.Text,{type:`secondary`,children:`输入 / 输出 Token`}),(0,j.jsxs)(a.Text,{children:[e.input_tokens||0,` / `,e.output_tokens||0]}),(0,j.jsx)(a.Text,{type:`secondary`,children:`延迟`}),(0,j.jsx)(a.Text,{children:L(e.latency_ms)})]})]})}})})]})};export{H as default}; \ No newline at end of file diff --git a/cmd/JoyCodeProxy/static/assets/Accounts-DymrWPU2.js b/cmd/JoyCodeProxy/static/assets/Accounts-teu0Jh5t.js similarity index 99% rename from cmd/JoyCodeProxy/static/assets/Accounts-DymrWPU2.js rename to cmd/JoyCodeProxy/static/assets/Accounts-teu0Jh5t.js index ffc322b..f794950 100644 --- a/cmd/JoyCodeProxy/static/assets/Accounts-DymrWPU2.js +++ b/cmd/JoyCodeProxy/static/assets/Accounts-teu0Jh5t.js @@ -1,4 +1,4 @@ -import{r as e}from"./rolldown-runtime-S-ySWqyJ.js";import{B as t,E as n,G as r,H as i,J as a,M as o,N as s,O as c,P as l,R as u,S as d,U as f,V as p,X as m,Y as h,a as g,b as _,c as v,d as y,j as b,k as x,mt as ee,n as S,nt as C,ot as w,pt as T,q as E,rt as D,st as O,ut as k,v as te,x as A}from"./antd-BIDKISxA.js";import{l as j,t as ne}from"./vendor-C3SDdTD0.js";import{n as M,t as N}from"./index-C0OoGTlz.js";import{n as re,r as ie,t as ae}from"./CommandTooltip-Cw9Jxov1.js";var oe=e(T()),P=e(ee());function F(){var e=[...arguments];return(0,P.useMemo)(()=>t=>{e.forEach(e=>e(t))},e)}var se=typeof window<`u`&&window.document!==void 0&&window.document.createElement!==void 0;function I(e){let t=Object.prototype.toString.call(e);return t===`[object Window]`||t===`[object global]`}function ce(e){return`nodeType`in e}function L(e){return e?I(e)?e:ce(e)?e.ownerDocument?.defaultView??window:window:window}function R(e){let{Document:t}=L(e);return e instanceof t}function z(e){return I(e)?!1:e instanceof L(e).HTMLElement}function B(e){return e instanceof L(e).SVGElement}function V(e){return e?I(e)?e.document:ce(e)?R(e)?e:z(e)||B(e)?e.ownerDocument:document:document:document}var H=se?P.useLayoutEffect:P.useEffect;function le(e){let t=(0,P.useRef)(e);return H(()=>{t.current=e}),(0,P.useCallback)(function(){var e=[...arguments];return t.current==null?void 0:t.current(...e)},[])}function ue(){let e=(0,P.useRef)(null);return[(0,P.useCallback)((t,n)=>{e.current=setInterval(t,n)},[]),(0,P.useCallback)(()=>{e.current!==null&&(clearInterval(e.current),e.current=null)},[])]}function de(e,t){t===void 0&&(t=[e]);let n=(0,P.useRef)(e);return H(()=>{n.current!==e&&(n.current=e)},t),n}function U(e,t){let n=(0,P.useRef)();return(0,P.useMemo)(()=>{let t=e(n.current);return n.current=t,t},[...t])}function fe(e){let t=le(e),n=(0,P.useRef)(null);return[n,(0,P.useCallback)(e=>{e!==n.current&&t?.(e,n.current),n.current=e},[])]}function pe(e){let t=(0,P.useRef)();return(0,P.useEffect)(()=>{t.current=e},[e]),t.current}var me={};function he(e,t){return(0,P.useMemo)(()=>{if(t)return t;let n=me[e]==null?0:me[e]+1;return me[e]=n,e+`-`+n},[e,t])}function ge(e){return function(t){return[...arguments].slice(1).reduce((t,n)=>{let r=Object.entries(n);for(let[n,i]of r){let r=t[n];r!=null&&(t[n]=r+e*i)}return t},{...t})}}var _e=ge(1),ve=ge(-1);function ye(e){return`clientX`in e&&`clientY`in e}function W(e){if(!e)return!1;let{KeyboardEvent:t}=L(e.target);return t&&e instanceof t}function be(e){if(!e)return!1;let{TouchEvent:t}=L(e.target);return t&&e instanceof t}function xe(e){if(be(e)){if(e.touches&&e.touches.length){let{clientX:t,clientY:n}=e.touches[0];return{x:t,y:n}}else if(e.changedTouches&&e.changedTouches.length){let{clientX:t,clientY:n}=e.changedTouches[0];return{x:t,y:n}}}return ye(e)?{x:e.clientX,y:e.clientY}:null}var G=Object.freeze({Translate:{toString(e){if(!e)return;let{x:t,y:n}=e;return`translate3d(`+(t?Math.round(t):0)+`px, `+(n?Math.round(n):0)+`px, 0)`}},Scale:{toString(e){if(!e)return;let{scaleX:t,scaleY:n}=e;return`scaleX(`+t+`) scaleY(`+n+`)`}},Transform:{toString(e){if(e)return[G.Translate.toString(e),G.Scale.toString(e)].join(` `)}},Transition:{toString(e){let{property:t,duration:n,easing:r}=e;return t+` `+n+`ms `+r}}}),K=`a,frame,iframe,input:not([type=hidden]):not(:disabled),select:not(:disabled),textarea:not(:disabled),button:not(:disabled),*[tabindex]`;function q(e){return e.matches(K)?e:e.querySelector(K)}var Se={display:`none`};function Ce(e){let{id:t,value:n}=e;return P.createElement(`div`,{id:t,style:Se},n)}function J(e){let{id:t,announcement:n,ariaLiveType:r=`assertive`}=e;return P.createElement(`div`,{id:t,style:{position:`fixed`,top:0,left:0,width:1,height:1,margin:-1,border:0,padding:0,overflow:`hidden`,clip:`rect(0 0 0 0)`,clipPath:`inset(100%)`,whiteSpace:`nowrap`},role:`status`,"aria-live":r,"aria-atomic":!0},n)}function we(){let[e,t]=(0,P.useState)(``);return{announce:(0,P.useCallback)(e=>{e!=null&&t(e)},[]),announcement:e}}var Te=(0,P.createContext)(null);function Ee(e){let t=(0,P.useContext)(Te);(0,P.useEffect)(()=>{if(!t)throw Error(`useDndMonitor must be used within a children of `);return t(e)},[e,t])}function De(){let[e]=(0,P.useState)(()=>new Set),t=(0,P.useCallback)(t=>(e.add(t),()=>e.delete(t)),[e]);return[(0,P.useCallback)(t=>{let{type:n,event:r}=t;e.forEach(e=>e[n]?.call(e,r))},[e]),t]}var Oe={draggable:` +import{r as e}from"./rolldown-runtime-S-ySWqyJ.js";import{B as t,E as n,G as r,H as i,J as a,M as o,N as s,O as c,P as l,R as u,S as d,U as f,V as p,X as m,Y as h,a as g,b as _,c as v,d as y,j as b,k as x,mt as ee,n as S,nt as C,ot as w,pt as T,q as E,rt as D,st as O,ut as k,v as te,x as A}from"./antd-BIDKISxA.js";import{l as j,t as ne}from"./vendor-C3SDdTD0.js";import{n as M,t as N}from"./index-62d9Y_mr.js";import{n as re,r as ie,t as ae}from"./CommandTooltip-Cw9Jxov1.js";var oe=e(T()),P=e(ee());function F(){var e=[...arguments];return(0,P.useMemo)(()=>t=>{e.forEach(e=>e(t))},e)}var se=typeof window<`u`&&window.document!==void 0&&window.document.createElement!==void 0;function I(e){let t=Object.prototype.toString.call(e);return t===`[object Window]`||t===`[object global]`}function ce(e){return`nodeType`in e}function L(e){return e?I(e)?e:ce(e)?e.ownerDocument?.defaultView??window:window:window}function R(e){let{Document:t}=L(e);return e instanceof t}function z(e){return I(e)?!1:e instanceof L(e).HTMLElement}function B(e){return e instanceof L(e).SVGElement}function V(e){return e?I(e)?e.document:ce(e)?R(e)?e:z(e)||B(e)?e.ownerDocument:document:document:document}var H=se?P.useLayoutEffect:P.useEffect;function le(e){let t=(0,P.useRef)(e);return H(()=>{t.current=e}),(0,P.useCallback)(function(){var e=[...arguments];return t.current==null?void 0:t.current(...e)},[])}function ue(){let e=(0,P.useRef)(null);return[(0,P.useCallback)((t,n)=>{e.current=setInterval(t,n)},[]),(0,P.useCallback)(()=>{e.current!==null&&(clearInterval(e.current),e.current=null)},[])]}function de(e,t){t===void 0&&(t=[e]);let n=(0,P.useRef)(e);return H(()=>{n.current!==e&&(n.current=e)},t),n}function U(e,t){let n=(0,P.useRef)();return(0,P.useMemo)(()=>{let t=e(n.current);return n.current=t,t},[...t])}function fe(e){let t=le(e),n=(0,P.useRef)(null);return[n,(0,P.useCallback)(e=>{e!==n.current&&t?.(e,n.current),n.current=e},[])]}function pe(e){let t=(0,P.useRef)();return(0,P.useEffect)(()=>{t.current=e},[e]),t.current}var me={};function he(e,t){return(0,P.useMemo)(()=>{if(t)return t;let n=me[e]==null?0:me[e]+1;return me[e]=n,e+`-`+n},[e,t])}function ge(e){return function(t){return[...arguments].slice(1).reduce((t,n)=>{let r=Object.entries(n);for(let[n,i]of r){let r=t[n];r!=null&&(t[n]=r+e*i)}return t},{...t})}}var _e=ge(1),ve=ge(-1);function ye(e){return`clientX`in e&&`clientY`in e}function W(e){if(!e)return!1;let{KeyboardEvent:t}=L(e.target);return t&&e instanceof t}function be(e){if(!e)return!1;let{TouchEvent:t}=L(e.target);return t&&e instanceof t}function xe(e){if(be(e)){if(e.touches&&e.touches.length){let{clientX:t,clientY:n}=e.touches[0];return{x:t,y:n}}else if(e.changedTouches&&e.changedTouches.length){let{clientX:t,clientY:n}=e.changedTouches[0];return{x:t,y:n}}}return ye(e)?{x:e.clientX,y:e.clientY}:null}var G=Object.freeze({Translate:{toString(e){if(!e)return;let{x:t,y:n}=e;return`translate3d(`+(t?Math.round(t):0)+`px, `+(n?Math.round(n):0)+`px, 0)`}},Scale:{toString(e){if(!e)return;let{scaleX:t,scaleY:n}=e;return`scaleX(`+t+`) scaleY(`+n+`)`}},Transform:{toString(e){if(e)return[G.Translate.toString(e),G.Scale.toString(e)].join(` `)}},Transition:{toString(e){let{property:t,duration:n,easing:r}=e;return t+` `+n+`ms `+r}}}),K=`a,frame,iframe,input:not([type=hidden]):not(:disabled),select:not(:disabled),textarea:not(:disabled),button:not(:disabled),*[tabindex]`;function q(e){return e.matches(K)?e:e.querySelector(K)}var Se={display:`none`};function Ce(e){let{id:t,value:n}=e;return P.createElement(`div`,{id:t,style:Se},n)}function J(e){let{id:t,announcement:n,ariaLiveType:r=`assertive`}=e;return P.createElement(`div`,{id:t,style:{position:`fixed`,top:0,left:0,width:1,height:1,margin:-1,border:0,padding:0,overflow:`hidden`,clip:`rect(0 0 0 0)`,clipPath:`inset(100%)`,whiteSpace:`nowrap`},role:`status`,"aria-live":r,"aria-atomic":!0},n)}function we(){let[e,t]=(0,P.useState)(``);return{announce:(0,P.useCallback)(e=>{e!=null&&t(e)},[]),announcement:e}}var Te=(0,P.createContext)(null);function Ee(e){let t=(0,P.useContext)(Te);(0,P.useEffect)(()=>{if(!t)throw Error(`useDndMonitor must be used within a children of `);return t(e)},[e,t])}function De(){let[e]=(0,P.useState)(()=>new Set),t=(0,P.useCallback)(t=>(e.add(t),()=>e.delete(t)),[e]);return[(0,P.useCallback)(t=>{let{type:n,event:r}=t;e.forEach(e=>e[n]?.call(e,r))},[e]),t]}var Oe={draggable:` To pick up a draggable item, press the space bar. While dragging, use the arrow keys to move the item. Press space again to drop the item in its new position, or press escape to cancel. diff --git a/cmd/JoyCodeProxy/static/assets/Dashboard-B_CPt8DM.js b/cmd/JoyCodeProxy/static/assets/Dashboard-DLytBGNF.js similarity index 99% rename from cmd/JoyCodeProxy/static/assets/Dashboard-B_CPt8DM.js rename to cmd/JoyCodeProxy/static/assets/Dashboard-DLytBGNF.js index 13f29a0..8aace99 100644 --- a/cmd/JoyCodeProxy/static/assets/Dashboard-B_CPt8DM.js +++ b/cmd/JoyCodeProxy/static/assets/Dashboard-DLytBGNF.js @@ -1 +1 @@ -import{r as e}from"./rolldown-runtime-S-ySWqyJ.js";import{$ as t,E as n,F as r,I as i,K as a,M as o,S as s,U as c,_ as l,b as u,ct as d,et as f,i as p,j as m,l as h,mt as g,r as _,tt as v,w as y,y as b}from"./antd-BIDKISxA.js";import{t as x}from"./vendor-C3SDdTD0.js";import{n as S,t as C}from"./index-C0OoGTlz.js";import{a as w,c as T,d as E,f as D,i as O,o as k,r as A,s as j,t as M}from"./recharts-abRO4Y-P.js";var N=e(g(),1),P=x(),F=[`#00b578`,`#36cfc9`,`#73d13d`,`#95de64`,`#1890ff`,`#722ed1`,`#13c2c2`,`#fa8c16`],I=e=>e>=1e6?(e/1e6).toFixed(2)+`M`:e>=1e3?(e/1e3).toFixed(1)+`K`:e.toLocaleString(),L=e=>{if(e<1e3)return`${e}ms`;let t=Math.floor(e/1e3);if(t<60)return`${t}s`;let n=Math.floor(t/60),r=t%60;return`${n}m${r>0?` ${r}s`:``}`},R=()=>{let[e,g]=(0,N.useState)(null),[x,R]=(0,N.useState)([]),[z,B]=(0,N.useState)(!0),V=async()=>{B(!0);try{let[e,t]=await Promise.all([S.getStats(),S.listAccounts()]);g(e),R(t)}catch(e){console.error(e)}finally{B(!1)}};if((0,N.useEffect)(()=>{V()},[]),z)return(0,P.jsx)(c,{size:`large`,style:{display:`block`,margin:`100px auto`}});if(!e)return(0,P.jsx)(d,{description:`无法加载统计数据`});let H=e.total_requests>0?Math.round(e.success_count/e.total_requests*100):100,U=e.total_requests>0?Math.round(e.error_count/e.total_requests*100):0,W=e.total_requests>0?Math.round(e.stream_count/e.total_requests*100):0,G=e.total_input_tokens+e.total_output_tokens,K=(e.all_time?.total_input_tokens??0)+(e.all_time?.total_output_tokens??0),q=e.total_requests>0?Math.round(G/e.total_requests):0,J=Math.round(e.avg_latency_ms),Y=e.by_model.map(t=>({name:t.model,value:t.count,pct:e.total_requests>0?Math.round(t.count/e.total_requests*100):0})),X=e.by_account.map(t=>({name:C(t),value:t.count,pct:e.total_requests>0?Math.round(t.count/e.total_requests*100):0})),Z=new Map;for(let t of e.hourly??[])Z.set(t.hour,{count:t.count,tokens:t.input_tokens+t.output_tokens,errors:t.errors});let Q=new Date,$=[];for(let e=23;e>=0;e--){let t=new Date(Q.getTime()-e*36e5),n=`${String(t.getMonth()+1).padStart(2,`0`)}-${String(t.getDate()).padStart(2,`0`)} ${String(t.getHours()).padStart(2,`0`)}`,r=`${String(t.getHours()).padStart(2,`0`)}:00`,i=Z.get(n);$.push({hour:n,label:r,requests:i?.count??0,tokens:i?.tokens??0,errors:i?.errors??0})}return(0,P.jsxs)(`div`,{children:[(0,P.jsx)(v,{style:{marginBottom:16,background:`linear-gradient(135deg, #00b578 0%, #009a63 100%)`,border:`none`,borderRadius:12},bodyStyle:{padding:`20px 24px`},children:(0,P.jsxs)(i,{align:`middle`,justify:`space-between`,children:[(0,P.jsxs)(f,{children:[(0,P.jsx)(n.Text,{style:{color:`rgba(255,255,255,0.85)`,fontSize:13},children:`JoyCode API 代理服务 · 数据概览`}),(0,P.jsx)(n.Title,{level:3,style:{color:`#fff`,margin:`4px 0 0`},children:`系统运行状态`})]}),(0,P.jsx)(f,{children:(0,P.jsxs)(i,{gutter:32,children:[(0,P.jsxs)(f,{style:{textAlign:`center`},children:[(0,P.jsx)(`div`,{style:{color:`rgba(255,255,255,0.7)`,fontSize:12},children:`今日请求`}),(0,P.jsx)(`div`,{style:{color:`#fff`,fontSize:26,fontWeight:700},children:e.total_requests.toLocaleString()})]}),(0,P.jsxs)(f,{style:{textAlign:`center`},children:[(0,P.jsx)(`div`,{style:{color:`rgba(255,255,255,0.7)`,fontSize:12},children:`今日 Token`}),(0,P.jsx)(`div`,{style:{color:`#fff`,fontSize:26,fontWeight:700},children:I(G)})]}),(0,P.jsxs)(f,{style:{textAlign:`center`},children:[(0,P.jsx)(`div`,{style:{color:`rgba(255,255,255,0.7)`,fontSize:12},children:`累计请求`}),(0,P.jsx)(`div`,{style:{color:`#fff`,fontSize:22,fontWeight:600},children:(e.all_time?.total_requests??0).toLocaleString()})]}),(0,P.jsxs)(f,{style:{textAlign:`center`},children:[(0,P.jsx)(`div`,{style:{color:`rgba(255,255,255,0.7)`,fontSize:12},children:`累计 Token`}),(0,P.jsx)(`div`,{style:{color:`#fff`,fontSize:22,fontWeight:600},children:I(K)})]}),(0,P.jsxs)(f,{style:{textAlign:`center`},children:[(0,P.jsx)(`div`,{style:{color:`rgba(255,255,255,0.7)`,fontSize:12},children:`账号数`}),(0,P.jsx)(`div`,{style:{color:`#fff`,fontSize:26,fontWeight:700},children:e.accounts_count})]}),(0,P.jsxs)(f,{style:{textAlign:`center`},children:[(0,P.jsx)(`div`,{style:{color:`rgba(255,255,255,0.7)`,fontSize:12},children:`成功率`}),(0,P.jsxs)(`div`,{style:{color:`#fff`,fontSize:26,fontWeight:700},children:[H,`%`]})]})]})})]})}),(0,P.jsxs)(i,{gutter:[16,16],children:[(0,P.jsx)(f,{xs:24,lg:12,children:(0,P.jsx)(v,{title:(0,P.jsxs)(`span`,{children:[(0,P.jsx)(y,{style:{marginRight:6}}),`24 小时请求趋势`]}),size:`small`,style:{borderRadius:8},children:(0,P.jsx)(D,{width:`100%`,height:200,children:(0,P.jsxs)(M,{data:$,margin:{top:5,right:10,left:0,bottom:0},children:[(0,P.jsx)(T,{strokeDasharray:`3 3`}),(0,P.jsx)(w,{dataKey:`label`,tick:{fontSize:10},interval:2}),(0,P.jsx)(O,{tick:{fontSize:11}}),(0,P.jsx)(E,{formatter:e=>[Number(e).toLocaleString(),`请求数`]}),(0,P.jsx)(j,{type:`monotone`,dataKey:`requests`,name:`requests`,stroke:`#00b578`,fill:`#00b578`,fillOpacity:.15,strokeWidth:2}),(0,P.jsx)(j,{type:`monotone`,dataKey:`errors`,name:`errors`,stroke:`#ff4d4f`,fill:`#ff4d4f`,fillOpacity:.1,strokeWidth:1.5})]})})})}),(0,P.jsx)(f,{xs:24,lg:12,children:(0,P.jsx)(v,{title:(0,P.jsxs)(`span`,{children:[(0,P.jsx)(l,{style:{marginRight:6}}),`24 小时 Token 消耗趋势`]}),size:`small`,style:{borderRadius:8},children:(0,P.jsx)(D,{width:`100%`,height:200,children:(0,P.jsxs)(M,{data:$,margin:{top:5,right:10,left:0,bottom:0},children:[(0,P.jsx)(T,{strokeDasharray:`3 3`}),(0,P.jsx)(w,{dataKey:`label`,tick:{fontSize:10},interval:2}),(0,P.jsx)(O,{tick:{fontSize:11},tickFormatter:e=>I(e)}),(0,P.jsx)(E,{formatter:e=>[I(Number(e)),`Token 用量`]}),(0,P.jsx)(j,{type:`monotone`,dataKey:`tokens`,stroke:`#389e0d`,fill:`#389e0d`,fillOpacity:.15,strokeWidth:2})]})})})})]}),(0,P.jsxs)(i,{gutter:[16,16],style:{marginTop:16},children:[(0,P.jsx)(f,{xs:24,md:8,children:(0,P.jsx)(v,{title:(0,P.jsxs)(`span`,{children:[(0,P.jsx)(y,{style:{marginRight:6}}),`请求统计`]}),size:`small`,style:{borderRadius:8,height:`100%`},children:(0,P.jsxs)(i,{gutter:[8,12],children:[(0,P.jsx)(f,{span:12,children:(0,P.jsx)(r,{title:`今日请求`,value:e.total_requests,valueStyle:{fontSize:20,color:`#00b578`}})}),(0,P.jsx)(f,{span:12,children:(0,P.jsx)(r,{title:`累计请求`,value:e.all_time?.total_requests??0,valueStyle:{fontSize:20}})}),(0,P.jsxs)(f,{span:12,children:[(0,P.jsx)(r,{title:`今日成功`,value:e.success_count,prefix:(0,P.jsx)(s,{}),valueStyle:{fontSize:18,color:`#52c41a`}}),(0,P.jsxs)(n.Text,{type:`secondary`,style:{fontSize:11},children:[`占比 `,H,`%`]})]}),(0,P.jsxs)(f,{span:12,children:[(0,P.jsx)(r,{title:`今日失败`,value:e.error_count,prefix:(0,P.jsx)(u,{}),valueStyle:{fontSize:18,color:e.error_count>0?`#ff4d4f`:`#52c41a`}}),(0,P.jsxs)(n.Text,{type:`secondary`,style:{fontSize:11},children:[`占比 `,U,`%`]})]}),(0,P.jsxs)(f,{span:24,children:[(0,P.jsx)(t,{style:{margin:`4px 0 8px`}}),(0,P.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`},children:[(0,P.jsx)(r,{title:`流式请求`,value:e.stream_count,valueStyle:{fontSize:16},prefix:(0,P.jsx)(a,{})}),(0,P.jsxs)(m,{color:`blue`,style:{height:`fit-content`,marginTop:20},children:[W,`%`]})]})]})]})})}),(0,P.jsx)(f,{xs:24,md:8,children:(0,P.jsx)(v,{title:(0,P.jsxs)(`span`,{children:[(0,P.jsx)(l,{style:{marginRight:6}}),`Token 消费`]}),size:`small`,style:{borderRadius:8,height:`100%`},children:(0,P.jsxs)(i,{gutter:[8,12],children:[(0,P.jsx)(f,{span:12,children:(0,P.jsx)(r,{title:`今日 Token`,value:I(G),valueStyle:{fontSize:20,color:`#389e0d`}})}),(0,P.jsx)(f,{span:12,children:(0,P.jsx)(r,{title:`累计 Token`,value:I(K),valueStyle:{fontSize:20}})}),(0,P.jsx)(f,{span:12,children:(0,P.jsx)(r,{title:`今日输入`,value:I(e.total_input_tokens),valueStyle:{fontSize:16}})}),(0,P.jsx)(f,{span:12,children:(0,P.jsx)(r,{title:`今日输出`,value:I(e.total_output_tokens),valueStyle:{fontSize:16}})}),(0,P.jsxs)(f,{span:24,children:[(0,P.jsx)(t,{style:{margin:`4px 0 8px`}}),(0,P.jsxs)(i,{gutter:8,children:[(0,P.jsx)(f,{span:12,children:(0,P.jsx)(r,{title:`平均每请求`,value:q.toLocaleString(),suffix:`tokens`,valueStyle:{fontSize:15}})}),(0,P.jsx)(f,{span:12,children:(0,P.jsx)(r,{title:`输入/输出比`,value:e.total_output_tokens>0?(e.total_input_tokens/e.total_output_tokens).toFixed(1):`-`,suffix:e.total_output_tokens>0?`:1`:``,valueStyle:{fontSize:15}})})]})]})]})})}),(0,P.jsx)(f,{xs:24,md:8,children:(0,P.jsx)(v,{title:(0,P.jsxs)(`span`,{children:[(0,P.jsx)(b,{style:{marginRight:6}}),`响应质量`]}),size:`small`,style:{borderRadius:8,height:`100%`},children:(0,P.jsxs)(i,{gutter:[8,12],children:[(0,P.jsx)(f,{span:12,children:(0,P.jsx)(r,{title:`平均延迟`,value:L(J),prefix:(0,P.jsx)(_,{}),valueStyle:{fontSize:20,color:J<5e3?`#52c41a`:J<15e3?`#faad14`:`#ff4d4f`}})}),(0,P.jsx)(f,{span:12,children:(0,P.jsx)(r,{title:`成功率`,value:H,suffix:`%`,prefix:(0,P.jsx)(s,{}),valueStyle:{fontSize:20,color:H>=95?`#52c41a`:H>=80?`#faad14`:`#ff4d4f`}})}),(0,P.jsxs)(f,{span:24,children:[(0,P.jsx)(t,{style:{margin:`4px 0 8px`}}),(0,P.jsx)(r,{title:`流式占比`,value:W,suffix:`%`,prefix:(0,P.jsx)(a,{}),valueStyle:{fontSize:18}})]}),(0,P.jsx)(f,{span:12,children:(0,P.jsx)(r,{title:`配置账号`,value:e.accounts_count,prefix:(0,P.jsx)(p,{}),valueStyle:{fontSize:16}})}),(0,P.jsx)(f,{span:12,children:(0,P.jsx)(r,{title:`使用模型`,value:e.by_model.length,prefix:(0,P.jsx)(h,{}),valueStyle:{fontSize:16}})})]})})})]}),(0,P.jsxs)(i,{gutter:[16,16],style:{marginTop:16},children:[(0,P.jsx)(f,{xs:24,lg:12,children:(0,P.jsx)(v,{title:(0,P.jsxs)(`span`,{children:[(0,P.jsx)(h,{style:{marginRight:6}}),`模型使用分布`]}),size:`small`,style:{borderRadius:8},children:Y.length>0?(0,P.jsxs)(i,{children:[(0,P.jsx)(f,{xs:24,md:14,children:(0,P.jsx)(D,{width:`100%`,height:220,children:(0,P.jsxs)(A,{data:Y,layout:`vertical`,margin:{left:10},children:[(0,P.jsx)(T,{strokeDasharray:`3 3`}),(0,P.jsx)(w,{type:`number`,tick:{fontSize:11}}),(0,P.jsx)(O,{dataKey:`name`,type:`category`,width:110,tick:{fontSize:11}}),(0,P.jsx)(E,{formatter:e=>[Number(e).toLocaleString(),`请求数`]}),(0,P.jsx)(k,{dataKey:`value`,name:`请求数`,fill:`#00b578`,radius:[0,4,4,0]})]})})}),(0,P.jsx)(f,{xs:24,md:10,children:(0,P.jsx)(`div`,{style:{padding:`4px 0 0 12px`},children:Y.map((e,t)=>(0,P.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,padding:`4px 0`,borderBottom:`1px solid #f5f5f5`},children:[(0,P.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:6},children:[(0,P.jsx)(`div`,{style:{width:8,height:8,borderRadius:`50%`,background:F[t%F.length]}}),(0,P.jsx)(n.Text,{style:{fontSize:12},children:e.name})]}),(0,P.jsxs)(`div`,{children:[(0,P.jsx)(n.Text,{style:{fontSize:12,fontWeight:500},children:e.value.toLocaleString()}),(0,P.jsxs)(n.Text,{type:`secondary`,style:{fontSize:11,marginLeft:4},children:[e.pct,`%`]})]})]},e.name))})})]}):(0,P.jsx)(d,{description:`暂无数据`,image:d.PRESENTED_IMAGE_SIMPLE})})}),(0,P.jsx)(f,{xs:24,lg:12,children:(0,P.jsx)(v,{title:(0,P.jsxs)(`span`,{children:[(0,P.jsx)(p,{style:{marginRight:6}}),`账号请求分布`]}),size:`small`,style:{borderRadius:8},children:X.length>0?(0,P.jsxs)(i,{children:[(0,P.jsx)(f,{xs:24,md:14,children:(0,P.jsx)(D,{width:`100%`,height:220,children:(0,P.jsxs)(A,{data:X,children:[(0,P.jsx)(T,{strokeDasharray:`3 3`}),(0,P.jsx)(w,{dataKey:`name`,tick:{fontSize:11}}),(0,P.jsx)(O,{tick:{fontSize:11}}),(0,P.jsx)(E,{formatter:e=>[Number(e).toLocaleString(),`请求数`]}),(0,P.jsx)(k,{dataKey:`value`,name:`请求数`,fill:`#00b578`,radius:[4,4,0,0]})]})})}),(0,P.jsx)(f,{xs:24,md:10,children:(0,P.jsx)(`div`,{style:{padding:`4px 0 0 12px`},children:X.map((e,t)=>(0,P.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,padding:`4px 0`,borderBottom:`1px solid #f5f5f5`},children:[(0,P.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:6},children:[(0,P.jsx)(`div`,{style:{width:8,height:8,borderRadius:`50%`,background:F[t%F.length]}}),(0,P.jsx)(n.Text,{style:{fontSize:12},children:e.name})]}),(0,P.jsxs)(`div`,{children:[(0,P.jsx)(n.Text,{style:{fontSize:12,fontWeight:500},children:e.value.toLocaleString()}),(0,P.jsxs)(n.Text,{type:`secondary`,style:{fontSize:11,marginLeft:4},children:[e.pct,`%`]})]})]},e.name))})})]}):(0,P.jsx)(d,{description:`暂无数据`,image:d.PRESENTED_IMAGE_SIMPLE})})})]}),x.length>0&&(0,P.jsx)(v,{title:(0,P.jsxs)(`span`,{children:[(0,P.jsx)(p,{style:{marginRight:6}}),`账号概览`]}),size:`small`,style:{marginTop:16,borderRadius:8},extra:(0,P.jsxs)(m,{children:[x.length,` 个账号`]}),children:(0,P.jsx)(o,{dataSource:x,columns:[{title:`账号`,dataIndex:`user_id`,key:`user_id`,render:(e,t)=>(0,P.jsx)(n.Text,{strong:!0,style:{fontSize:13},children:C(t)})},{title:`默认模型`,dataIndex:`default_model`,key:`model`,render:e=>e?(0,P.jsx)(m,{children:e}):(0,P.jsx)(n.Text,{type:`secondary`,children:`-`})},{title:`请求量`,key:`count`,render:(t,r)=>{let i=e.by_account.find(e=>e.user_id===r.user_id);return i?i.count.toLocaleString():(0,P.jsx)(n.Text,{type:`secondary`,children:`0`})}},{title:`状态`,key:`status`,render:()=>(0,P.jsx)(m,{color:`success`,children:`在线`})}],rowKey:`user_id`,size:`small`,pagination:!1})}),e.total_requests===0&&(e.all_time?.total_requests??0)===0&&(0,P.jsx)(v,{style:{marginTop:16,borderRadius:8},children:(0,P.jsx)(d,{description:`暂无请求数据`,children:(0,P.jsx)(n.Text,{type:`secondary`,children:`配置好账号后,使用 Claude Code 或 Codex 连接到本代理即可看到统计数据`})})})]})};export{R as default}; \ No newline at end of file +import{r as e}from"./rolldown-runtime-S-ySWqyJ.js";import{$ as t,E as n,F as r,I as i,K as a,M as o,S as s,U as c,_ as l,b as u,ct as d,et as f,i as p,j as m,l as h,mt as g,r as _,tt as v,w as y,y as b}from"./antd-BIDKISxA.js";import{t as x}from"./vendor-C3SDdTD0.js";import{n as S,t as C}from"./index-62d9Y_mr.js";import{a as w,c as T,d as E,f as D,i as O,o as k,r as A,s as j,t as M}from"./recharts-abRO4Y-P.js";var N=e(g(),1),P=x(),F=[`#00b578`,`#36cfc9`,`#73d13d`,`#95de64`,`#1890ff`,`#722ed1`,`#13c2c2`,`#fa8c16`],I=e=>e>=1e6?(e/1e6).toFixed(2)+`M`:e>=1e3?(e/1e3).toFixed(1)+`K`:e.toLocaleString(),L=e=>{if(e<1e3)return`${e}ms`;let t=Math.floor(e/1e3);if(t<60)return`${t}s`;let n=Math.floor(t/60),r=t%60;return`${n}m${r>0?` ${r}s`:``}`},R=()=>{let[e,g]=(0,N.useState)(null),[x,R]=(0,N.useState)([]),[z,B]=(0,N.useState)(!0),V=async()=>{B(!0);try{let[e,t]=await Promise.all([S.getStats(),S.listAccounts()]);g(e),R(t)}catch(e){console.error(e)}finally{B(!1)}};if((0,N.useEffect)(()=>{V()},[]),z)return(0,P.jsx)(c,{size:`large`,style:{display:`block`,margin:`100px auto`}});if(!e)return(0,P.jsx)(d,{description:`无法加载统计数据`});let H=e.total_requests>0?Math.round(e.success_count/e.total_requests*100):100,U=e.total_requests>0?Math.round(e.error_count/e.total_requests*100):0,W=e.total_requests>0?Math.round(e.stream_count/e.total_requests*100):0,G=e.total_input_tokens+e.total_output_tokens,K=(e.all_time?.total_input_tokens??0)+(e.all_time?.total_output_tokens??0),q=e.total_requests>0?Math.round(G/e.total_requests):0,J=Math.round(e.avg_latency_ms),Y=e.by_model.map(t=>({name:t.model,value:t.count,pct:e.total_requests>0?Math.round(t.count/e.total_requests*100):0})),X=e.by_account.map(t=>({name:C(t),value:t.count,pct:e.total_requests>0?Math.round(t.count/e.total_requests*100):0})),Z=new Map;for(let t of e.hourly??[])Z.set(t.hour,{count:t.count,tokens:t.input_tokens+t.output_tokens,errors:t.errors});let Q=new Date,$=[];for(let e=23;e>=0;e--){let t=new Date(Q.getTime()-e*36e5),n=`${String(t.getMonth()+1).padStart(2,`0`)}-${String(t.getDate()).padStart(2,`0`)} ${String(t.getHours()).padStart(2,`0`)}`,r=`${String(t.getHours()).padStart(2,`0`)}:00`,i=Z.get(n);$.push({hour:n,label:r,requests:i?.count??0,tokens:i?.tokens??0,errors:i?.errors??0})}return(0,P.jsxs)(`div`,{children:[(0,P.jsx)(v,{style:{marginBottom:16,background:`linear-gradient(135deg, #00b578 0%, #009a63 100%)`,border:`none`,borderRadius:12},bodyStyle:{padding:`20px 24px`},children:(0,P.jsxs)(i,{align:`middle`,justify:`space-between`,children:[(0,P.jsxs)(f,{children:[(0,P.jsx)(n.Text,{style:{color:`rgba(255,255,255,0.85)`,fontSize:13},children:`JoyCode API 代理服务 · 数据概览`}),(0,P.jsx)(n.Title,{level:3,style:{color:`#fff`,margin:`4px 0 0`},children:`系统运行状态`})]}),(0,P.jsx)(f,{children:(0,P.jsxs)(i,{gutter:32,children:[(0,P.jsxs)(f,{style:{textAlign:`center`},children:[(0,P.jsx)(`div`,{style:{color:`rgba(255,255,255,0.7)`,fontSize:12},children:`今日请求`}),(0,P.jsx)(`div`,{style:{color:`#fff`,fontSize:26,fontWeight:700},children:e.total_requests.toLocaleString()})]}),(0,P.jsxs)(f,{style:{textAlign:`center`},children:[(0,P.jsx)(`div`,{style:{color:`rgba(255,255,255,0.7)`,fontSize:12},children:`今日 Token`}),(0,P.jsx)(`div`,{style:{color:`#fff`,fontSize:26,fontWeight:700},children:I(G)})]}),(0,P.jsxs)(f,{style:{textAlign:`center`},children:[(0,P.jsx)(`div`,{style:{color:`rgba(255,255,255,0.7)`,fontSize:12},children:`累计请求`}),(0,P.jsx)(`div`,{style:{color:`#fff`,fontSize:22,fontWeight:600},children:(e.all_time?.total_requests??0).toLocaleString()})]}),(0,P.jsxs)(f,{style:{textAlign:`center`},children:[(0,P.jsx)(`div`,{style:{color:`rgba(255,255,255,0.7)`,fontSize:12},children:`累计 Token`}),(0,P.jsx)(`div`,{style:{color:`#fff`,fontSize:22,fontWeight:600},children:I(K)})]}),(0,P.jsxs)(f,{style:{textAlign:`center`},children:[(0,P.jsx)(`div`,{style:{color:`rgba(255,255,255,0.7)`,fontSize:12},children:`账号数`}),(0,P.jsx)(`div`,{style:{color:`#fff`,fontSize:26,fontWeight:700},children:e.accounts_count})]}),(0,P.jsxs)(f,{style:{textAlign:`center`},children:[(0,P.jsx)(`div`,{style:{color:`rgba(255,255,255,0.7)`,fontSize:12},children:`成功率`}),(0,P.jsxs)(`div`,{style:{color:`#fff`,fontSize:26,fontWeight:700},children:[H,`%`]})]})]})})]})}),(0,P.jsxs)(i,{gutter:[16,16],children:[(0,P.jsx)(f,{xs:24,lg:12,children:(0,P.jsx)(v,{title:(0,P.jsxs)(`span`,{children:[(0,P.jsx)(y,{style:{marginRight:6}}),`24 小时请求趋势`]}),size:`small`,style:{borderRadius:8},children:(0,P.jsx)(D,{width:`100%`,height:200,children:(0,P.jsxs)(M,{data:$,margin:{top:5,right:10,left:0,bottom:0},children:[(0,P.jsx)(T,{strokeDasharray:`3 3`}),(0,P.jsx)(w,{dataKey:`label`,tick:{fontSize:10},interval:2}),(0,P.jsx)(O,{tick:{fontSize:11}}),(0,P.jsx)(E,{formatter:e=>[Number(e).toLocaleString(),`请求数`]}),(0,P.jsx)(j,{type:`monotone`,dataKey:`requests`,name:`requests`,stroke:`#00b578`,fill:`#00b578`,fillOpacity:.15,strokeWidth:2}),(0,P.jsx)(j,{type:`monotone`,dataKey:`errors`,name:`errors`,stroke:`#ff4d4f`,fill:`#ff4d4f`,fillOpacity:.1,strokeWidth:1.5})]})})})}),(0,P.jsx)(f,{xs:24,lg:12,children:(0,P.jsx)(v,{title:(0,P.jsxs)(`span`,{children:[(0,P.jsx)(l,{style:{marginRight:6}}),`24 小时 Token 消耗趋势`]}),size:`small`,style:{borderRadius:8},children:(0,P.jsx)(D,{width:`100%`,height:200,children:(0,P.jsxs)(M,{data:$,margin:{top:5,right:10,left:0,bottom:0},children:[(0,P.jsx)(T,{strokeDasharray:`3 3`}),(0,P.jsx)(w,{dataKey:`label`,tick:{fontSize:10},interval:2}),(0,P.jsx)(O,{tick:{fontSize:11},tickFormatter:e=>I(e)}),(0,P.jsx)(E,{formatter:e=>[I(Number(e)),`Token 用量`]}),(0,P.jsx)(j,{type:`monotone`,dataKey:`tokens`,stroke:`#389e0d`,fill:`#389e0d`,fillOpacity:.15,strokeWidth:2})]})})})})]}),(0,P.jsxs)(i,{gutter:[16,16],style:{marginTop:16},children:[(0,P.jsx)(f,{xs:24,md:8,children:(0,P.jsx)(v,{title:(0,P.jsxs)(`span`,{children:[(0,P.jsx)(y,{style:{marginRight:6}}),`请求统计`]}),size:`small`,style:{borderRadius:8,height:`100%`},children:(0,P.jsxs)(i,{gutter:[8,12],children:[(0,P.jsx)(f,{span:12,children:(0,P.jsx)(r,{title:`今日请求`,value:e.total_requests,valueStyle:{fontSize:20,color:`#00b578`}})}),(0,P.jsx)(f,{span:12,children:(0,P.jsx)(r,{title:`累计请求`,value:e.all_time?.total_requests??0,valueStyle:{fontSize:20}})}),(0,P.jsxs)(f,{span:12,children:[(0,P.jsx)(r,{title:`今日成功`,value:e.success_count,prefix:(0,P.jsx)(s,{}),valueStyle:{fontSize:18,color:`#52c41a`}}),(0,P.jsxs)(n.Text,{type:`secondary`,style:{fontSize:11},children:[`占比 `,H,`%`]})]}),(0,P.jsxs)(f,{span:12,children:[(0,P.jsx)(r,{title:`今日失败`,value:e.error_count,prefix:(0,P.jsx)(u,{}),valueStyle:{fontSize:18,color:e.error_count>0?`#ff4d4f`:`#52c41a`}}),(0,P.jsxs)(n.Text,{type:`secondary`,style:{fontSize:11},children:[`占比 `,U,`%`]})]}),(0,P.jsxs)(f,{span:24,children:[(0,P.jsx)(t,{style:{margin:`4px 0 8px`}}),(0,P.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`},children:[(0,P.jsx)(r,{title:`流式请求`,value:e.stream_count,valueStyle:{fontSize:16},prefix:(0,P.jsx)(a,{})}),(0,P.jsxs)(m,{color:`blue`,style:{height:`fit-content`,marginTop:20},children:[W,`%`]})]})]})]})})}),(0,P.jsx)(f,{xs:24,md:8,children:(0,P.jsx)(v,{title:(0,P.jsxs)(`span`,{children:[(0,P.jsx)(l,{style:{marginRight:6}}),`Token 消费`]}),size:`small`,style:{borderRadius:8,height:`100%`},children:(0,P.jsxs)(i,{gutter:[8,12],children:[(0,P.jsx)(f,{span:12,children:(0,P.jsx)(r,{title:`今日 Token`,value:I(G),valueStyle:{fontSize:20,color:`#389e0d`}})}),(0,P.jsx)(f,{span:12,children:(0,P.jsx)(r,{title:`累计 Token`,value:I(K),valueStyle:{fontSize:20}})}),(0,P.jsx)(f,{span:12,children:(0,P.jsx)(r,{title:`今日输入`,value:I(e.total_input_tokens),valueStyle:{fontSize:16}})}),(0,P.jsx)(f,{span:12,children:(0,P.jsx)(r,{title:`今日输出`,value:I(e.total_output_tokens),valueStyle:{fontSize:16}})}),(0,P.jsxs)(f,{span:24,children:[(0,P.jsx)(t,{style:{margin:`4px 0 8px`}}),(0,P.jsxs)(i,{gutter:8,children:[(0,P.jsx)(f,{span:12,children:(0,P.jsx)(r,{title:`平均每请求`,value:q.toLocaleString(),suffix:`tokens`,valueStyle:{fontSize:15}})}),(0,P.jsx)(f,{span:12,children:(0,P.jsx)(r,{title:`输入/输出比`,value:e.total_output_tokens>0?(e.total_input_tokens/e.total_output_tokens).toFixed(1):`-`,suffix:e.total_output_tokens>0?`:1`:``,valueStyle:{fontSize:15}})})]})]})]})})}),(0,P.jsx)(f,{xs:24,md:8,children:(0,P.jsx)(v,{title:(0,P.jsxs)(`span`,{children:[(0,P.jsx)(b,{style:{marginRight:6}}),`响应质量`]}),size:`small`,style:{borderRadius:8,height:`100%`},children:(0,P.jsxs)(i,{gutter:[8,12],children:[(0,P.jsx)(f,{span:12,children:(0,P.jsx)(r,{title:`平均延迟`,value:L(J),prefix:(0,P.jsx)(_,{}),valueStyle:{fontSize:20,color:J<5e3?`#52c41a`:J<15e3?`#faad14`:`#ff4d4f`}})}),(0,P.jsx)(f,{span:12,children:(0,P.jsx)(r,{title:`成功率`,value:H,suffix:`%`,prefix:(0,P.jsx)(s,{}),valueStyle:{fontSize:20,color:H>=95?`#52c41a`:H>=80?`#faad14`:`#ff4d4f`}})}),(0,P.jsxs)(f,{span:24,children:[(0,P.jsx)(t,{style:{margin:`4px 0 8px`}}),(0,P.jsx)(r,{title:`流式占比`,value:W,suffix:`%`,prefix:(0,P.jsx)(a,{}),valueStyle:{fontSize:18}})]}),(0,P.jsx)(f,{span:12,children:(0,P.jsx)(r,{title:`配置账号`,value:e.accounts_count,prefix:(0,P.jsx)(p,{}),valueStyle:{fontSize:16}})}),(0,P.jsx)(f,{span:12,children:(0,P.jsx)(r,{title:`使用模型`,value:e.by_model.length,prefix:(0,P.jsx)(h,{}),valueStyle:{fontSize:16}})})]})})})]}),(0,P.jsxs)(i,{gutter:[16,16],style:{marginTop:16},children:[(0,P.jsx)(f,{xs:24,lg:12,children:(0,P.jsx)(v,{title:(0,P.jsxs)(`span`,{children:[(0,P.jsx)(h,{style:{marginRight:6}}),`模型使用分布`]}),size:`small`,style:{borderRadius:8},children:Y.length>0?(0,P.jsxs)(i,{children:[(0,P.jsx)(f,{xs:24,md:14,children:(0,P.jsx)(D,{width:`100%`,height:220,children:(0,P.jsxs)(A,{data:Y,layout:`vertical`,margin:{left:10},children:[(0,P.jsx)(T,{strokeDasharray:`3 3`}),(0,P.jsx)(w,{type:`number`,tick:{fontSize:11}}),(0,P.jsx)(O,{dataKey:`name`,type:`category`,width:110,tick:{fontSize:11}}),(0,P.jsx)(E,{formatter:e=>[Number(e).toLocaleString(),`请求数`]}),(0,P.jsx)(k,{dataKey:`value`,name:`请求数`,fill:`#00b578`,radius:[0,4,4,0]})]})})}),(0,P.jsx)(f,{xs:24,md:10,children:(0,P.jsx)(`div`,{style:{padding:`4px 0 0 12px`},children:Y.map((e,t)=>(0,P.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,padding:`4px 0`,borderBottom:`1px solid #f5f5f5`},children:[(0,P.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:6},children:[(0,P.jsx)(`div`,{style:{width:8,height:8,borderRadius:`50%`,background:F[t%F.length]}}),(0,P.jsx)(n.Text,{style:{fontSize:12},children:e.name})]}),(0,P.jsxs)(`div`,{children:[(0,P.jsx)(n.Text,{style:{fontSize:12,fontWeight:500},children:e.value.toLocaleString()}),(0,P.jsxs)(n.Text,{type:`secondary`,style:{fontSize:11,marginLeft:4},children:[e.pct,`%`]})]})]},e.name))})})]}):(0,P.jsx)(d,{description:`暂无数据`,image:d.PRESENTED_IMAGE_SIMPLE})})}),(0,P.jsx)(f,{xs:24,lg:12,children:(0,P.jsx)(v,{title:(0,P.jsxs)(`span`,{children:[(0,P.jsx)(p,{style:{marginRight:6}}),`账号请求分布`]}),size:`small`,style:{borderRadius:8},children:X.length>0?(0,P.jsxs)(i,{children:[(0,P.jsx)(f,{xs:24,md:14,children:(0,P.jsx)(D,{width:`100%`,height:220,children:(0,P.jsxs)(A,{data:X,children:[(0,P.jsx)(T,{strokeDasharray:`3 3`}),(0,P.jsx)(w,{dataKey:`name`,tick:{fontSize:11}}),(0,P.jsx)(O,{tick:{fontSize:11}}),(0,P.jsx)(E,{formatter:e=>[Number(e).toLocaleString(),`请求数`]}),(0,P.jsx)(k,{dataKey:`value`,name:`请求数`,fill:`#00b578`,radius:[4,4,0,0]})]})})}),(0,P.jsx)(f,{xs:24,md:10,children:(0,P.jsx)(`div`,{style:{padding:`4px 0 0 12px`},children:X.map((e,t)=>(0,P.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,padding:`4px 0`,borderBottom:`1px solid #f5f5f5`},children:[(0,P.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:6},children:[(0,P.jsx)(`div`,{style:{width:8,height:8,borderRadius:`50%`,background:F[t%F.length]}}),(0,P.jsx)(n.Text,{style:{fontSize:12},children:e.name})]}),(0,P.jsxs)(`div`,{children:[(0,P.jsx)(n.Text,{style:{fontSize:12,fontWeight:500},children:e.value.toLocaleString()}),(0,P.jsxs)(n.Text,{type:`secondary`,style:{fontSize:11,marginLeft:4},children:[e.pct,`%`]})]})]},e.name))})})]}):(0,P.jsx)(d,{description:`暂无数据`,image:d.PRESENTED_IMAGE_SIMPLE})})})]}),x.length>0&&(0,P.jsx)(v,{title:(0,P.jsxs)(`span`,{children:[(0,P.jsx)(p,{style:{marginRight:6}}),`账号概览`]}),size:`small`,style:{marginTop:16,borderRadius:8},extra:(0,P.jsxs)(m,{children:[x.length,` 个账号`]}),children:(0,P.jsx)(o,{dataSource:x,columns:[{title:`账号`,dataIndex:`user_id`,key:`user_id`,render:(e,t)=>(0,P.jsx)(n.Text,{strong:!0,style:{fontSize:13},children:C(t)})},{title:`默认模型`,dataIndex:`default_model`,key:`model`,render:e=>e?(0,P.jsx)(m,{children:e}):(0,P.jsx)(n.Text,{type:`secondary`,children:`-`})},{title:`请求量`,key:`count`,render:(t,r)=>{let i=e.by_account.find(e=>e.user_id===r.user_id);return i?i.count.toLocaleString():(0,P.jsx)(n.Text,{type:`secondary`,children:`0`})}},{title:`状态`,key:`status`,render:()=>(0,P.jsx)(m,{color:`success`,children:`在线`})}],rowKey:`user_id`,size:`small`,pagination:!1})}),e.total_requests===0&&(e.all_time?.total_requests??0)===0&&(0,P.jsx)(v,{style:{marginTop:16,borderRadius:8},children:(0,P.jsx)(d,{description:`暂无请求数据`,children:(0,P.jsx)(n.Text,{type:`secondary`,children:`配置好账号后,使用 Claude Code 或 Codex 连接到本代理即可看到统计数据`})})})]})};export{R as default}; \ No newline at end of file diff --git a/cmd/JoyCodeProxy/static/assets/Settings-BVAc1eo4.js b/cmd/JoyCodeProxy/static/assets/Settings-BVAc1eo4.js new file mode 100644 index 0000000..2e63741 --- /dev/null +++ b/cmd/JoyCodeProxy/static/assets/Settings-BVAc1eo4.js @@ -0,0 +1 @@ +import{r as e}from"./rolldown-runtime-S-ySWqyJ.js";import{E as t,G as n,H as r,I as i,J as a,P as o,R as s,S as c,U as l,V as u,Y as d,Z as f,et as p,f as m,j as h,mt as g,o as _,ot as v,p as y,q as b,rt as x,s as S,st as C,tt as w}from"./antd-BIDKISxA.js";import{t as T}from"./vendor-C3SDdTD0.js";import{i as E,n as D,r as O}from"./index-62d9Y_mr.js";var k=e(g(),1),A=T(),{Text:j}=t,M=[{title:`模型配置`,fields:[{key:`default_model`,label:`默认模型`,tag:`已生效`,tooltip:`当客户端未指定模型,且账号未配置默认模型时使用的 JoyCode 模型`,placeholder:`JoyAI-Code`,type:`select`,options:[{label:`JoyAI-Code — 主力代码模型(推荐)`,value:`JoyAI-Code`},{label:`Claude-Opus-4.7`,value:`Claude-Opus-4.7`},{label:`GLM-5.1 — 智谱 GLM 5.1`,value:`GLM-5.1`},{label:`GLM-5 — 智谱 GLM 5`,value:`GLM-5`},{label:`GLM-4.7 — 智谱 GLM 4.7`,value:`GLM-4.7`},{label:`Kimi-K2.6 — Moonshot Kimi K2.6`,value:`Kimi-K2.6`},{label:`Kimi-K2.5 — Moonshot Kimi K2.5`,value:`Kimi-K2.5`},{label:`MiniMax-M2.7 — MiniMax M2.7`,value:`MiniMax-M2.7`},{label:`Doubao-Seed-2.0-pro — 豆包 Seed 2.0 Pro`,value:`Doubao-Seed-2.0-pro`}]},{key:`default_max_tokens`,label:`默认最大输出 Token`,tooltip:`客户端未指定 max_tokens 时的默认值。更大值允许更长回复,但消耗更多配额`,placeholder:`8192`,type:`number`,tag:`已生效`}]},{title:`连接优化`,fields:[{key:`max_retries`,label:`最大重试次数`,tooltip:`请求失败时的自动重试次数。网络不稳定时可适当增加`,placeholder:`3`,type:`number`,tag:`已生效`},{key:`request_timeout`,label:`请求超时(秒)`,tooltip:`与 JoyCode 后端通信的读取超时时间,低于 60 秒会自动调整为 60 秒`,placeholder:`120`,type:`number`,suffix:`秒`,tag:`已生效`},{key:`max_connections`,label:`最大连接数`,tooltip:`与 JoyCode 后端的最大并发 HTTP 连接数,修改后 10 秒内自动生效`,placeholder:`20`,type:`number`,tag:`已生效`}]},{title:`日志与监控`,fields:[{key:`enable_request_logging`,label:`启用请求日志`,tooltip:`记录每个 API 请求的详细信息(模型、延迟、状态码)。关闭后「数据概览」页面将无数据`,placeholder:`true`,type:`switch`,tag:`已生效`},{key:`log_retention_days`,label:`日志保留天数`,tooltip:`请求日志的自动清理周期。超过此天数的日志将每小时自动清理,0 表示永久保留`,placeholder:`30`,type:`number`,suffix:`天`,tag:`已生效`}]}],N=()=>{let[e,t]=(0,k.useState)(!0),[g,T]=(0,k.useState)(!1),[N,P]=(0,k.useState)(!1),[F]=b.useForm(),[I]=b.useForm(),L=async()=>{t(!0);try{let e=await D.getSettings();F.setFieldsValue(e)}catch(e){r.error(e instanceof Error?e.message:`加载设置失败`)}finally{t(!1)}};(0,k.useEffect)(()=>{L()},[F]);let R=async e=>{T(!0);try{let t=Object.fromEntries(Object.entries(e).map(([e,t])=>[e,String(t)]));await D.updateSettings(t),r.success(`设置已保存`)}catch(e){r.error(e instanceof Error?e.message:`保存设置失败`)}finally{T(!1)}},z=async e=>{u.confirm({title:`确认修改密码`,content:`修改密码后需要重新登录,确定要继续吗?`,okText:`确认修改`,cancelText:`取消`,okButtonProps:{danger:!0},onOk:async()=>{P(!0);try{await O.changePassword(e.old_password,e.new_password),r.success(`密码修改成功,请重新登录`),I.resetFields(),E(),setTimeout(()=>{window.location.href=`/login`},1e3)}catch(e){r.error(e instanceof Error?e.message:`密码修改失败`)}finally{P(!1)}}})};if(e)return(0,A.jsx)(l,{size:`large`,style:{display:`block`,margin:`100px auto`}});let B=e=>{let t=(0,A.jsxs)(d,{size:4,children:[e.label,(0,A.jsx)(v,{title:e.tooltip,children:(0,A.jsx)(a,{style:{color:`#bbb`}})}),e.tag&&(0,A.jsxs)(h,{color:e.tag===`已生效`?`success`:`default`,style:{marginLeft:4,fontSize:11},children:[e.tag===`已生效`?(0,A.jsx)(c,{}):(0,A.jsx)(y,{}),` `,e.tag]})]});switch(e.type){case`number`:return(0,A.jsx)(b.Item,{name:e.key,label:t,children:(0,A.jsx)(f,{style:{width:`100%`},placeholder:e.placeholder,addonAfter:e.suffix,disabled:e.readOnly})},e.key);case`select`:return(0,A.jsx)(b.Item,{name:e.key,label:t,children:(0,A.jsx)(C,{placeholder:e.placeholder,options:e.options,allowClear:!0,disabled:e.readOnly})},e.key);case`switch`:return(0,A.jsx)(b.Item,{name:e.key,valuePropName:`checked`,label:t,children:(0,A.jsx)(o,{})},e.key);default:return(0,A.jsx)(b.Item,{name:e.key,label:t,children:(0,A.jsx)(n,{placeholder:e.placeholder,disabled:e.readOnly})},e.key)}};return(0,A.jsxs)(`div`,{children:[(0,A.jsx)(w,{style:{marginBottom:16,background:`linear-gradient(135deg, #00b578 0%, #009a63 100%)`,border:`none`,borderRadius:12},styles:{body:{padding:`20px 24px`}},children:(0,A.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`},children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(j,{style:{color:`rgba(255,255,255,0.85)`,fontSize:13},children:`JoyCode API 代理服务 · 系统设置`}),(0,A.jsx)(`div`,{style:{color:`#fff`,fontSize:22,fontWeight:700,marginTop:4},children:`代理配置管理`})]}),(0,A.jsx)(`div`,{style:{display:`flex`,gap:8},children:(0,A.jsx)(x,{ghost:!0,style:{color:`#fff`,borderColor:`rgba(255,255,255,0.4)`},icon:(0,A.jsx)(s,{}),onClick:L,children:`刷新`})})]})}),(0,A.jsxs)(b,{form:F,layout:`vertical`,onFinish:R,children:[M.map(e=>(0,A.jsx)(w,{title:(0,A.jsx)(j,{strong:!0,style:{fontSize:15},children:e.title}),style:{marginBottom:16,borderRadius:8,border:`1px solid #f0f0f0`},styles:{body:{padding:`20px 24px`}},extra:(0,A.jsx)(_,{style:{color:`#00b578`}}),children:(0,A.jsx)(i,{gutter:[24,0],children:e.fields.map(e=>(0,A.jsx)(p,{xs:24,md:12,children:B(e)},e.key))})},e.title)),(0,A.jsx)(w,{title:(0,A.jsx)(j,{strong:!0,style:{fontSize:15},children:`安全设置`}),style:{marginBottom:16,borderRadius:8,border:`1px solid #f0f0f0`},styles:{body:{padding:`20px 24px`}},extra:(0,A.jsx)(_,{style:{color:`#00b578`}}),children:(0,A.jsxs)(b,{form:I,layout:`vertical`,onFinish:z,children:[(0,A.jsxs)(i,{gutter:[24,0],children:[(0,A.jsx)(p,{xs:24,md:8,children:(0,A.jsx)(b.Item,{name:`old_password`,label:`当前密码`,rules:[{required:!0,message:`请输入当前密码`}],children:(0,A.jsx)(n.Password,{placeholder:`输入当前密码`})})}),(0,A.jsx)(p,{xs:24,md:8,children:(0,A.jsx)(b.Item,{name:`new_password`,label:`新密码`,rules:[{required:!0,message:`请输入新密码`},{min:6,message:`密码长度不能少于 6 位`}],children:(0,A.jsx)(n.Password,{placeholder:`输入新密码(至少 6 位)`})})}),(0,A.jsx)(p,{xs:24,md:8,children:(0,A.jsx)(b.Item,{label:`确认新密码`,dependencies:[`new_password`],rules:[{required:!0,message:`请确认新密码`},({getFieldValue:e})=>({validator(t,n){return!n||e(`new_password`)===n?Promise.resolve():Promise.reject(Error(`两次输入的密码不一致`))}})],name:`confirm_password`,children:(0,A.jsx)(n.Password,{placeholder:`再次输入新密码`})})})]}),(0,A.jsx)(x,{type:`primary`,htmlType:`submit`,loading:N,icon:(0,A.jsx)(m,{}),style:{borderRadius:6},children:`修改密码`})]})}),(0,A.jsxs)(`div`,{style:{display:`flex`,gap:12,marginTop:8},children:[(0,A.jsx)(x,{type:`primary`,htmlType:`submit`,loading:g,icon:(0,A.jsx)(S,{}),size:`large`,style:{borderRadius:6},children:`保存设置`}),(0,A.jsx)(x,{onClick:L,icon:(0,A.jsx)(s,{}),size:`large`,children:`恢复当前值`})]})]})]})};export{N as default}; \ No newline at end of file diff --git a/cmd/JoyCodeProxy/static/assets/Settings-CuaeIRbW.js b/cmd/JoyCodeProxy/static/assets/Settings-CuaeIRbW.js deleted file mode 100644 index 179efb0..0000000 --- a/cmd/JoyCodeProxy/static/assets/Settings-CuaeIRbW.js +++ /dev/null @@ -1 +0,0 @@ -import{r as e}from"./rolldown-runtime-S-ySWqyJ.js";import{E as t,G as n,H as r,I as i,J as a,P as o,R as s,S as c,U as l,V as u,Y as d,Z as f,et as p,f as m,j as h,mt as g,o as _,ot as v,p as y,q as b,rt as x,s as S,st as C,tt as w}from"./antd-BIDKISxA.js";import{t as T}from"./vendor-C3SDdTD0.js";import{i as E,n as D,r as O}from"./index-C0OoGTlz.js";var k=e(g(),1),A=T(),{Text:j}=t,M=[{title:`模型配置`,fields:[{key:`default_model`,label:`默认模型`,tag:`已生效`,tooltip:`当客户端未指定模型,且账号未配置默认模型时使用的 JoyCode 模型`,placeholder:`JoyAI-Code`,type:`select`,options:[{label:`JoyAI-Code — 主力代码模型(推荐)`,value:`JoyAI-Code`},{label:`Claude-Opus-4.7`,value:`Claude-Opus-4.7`},{label:`GLM-5.1 — 智谱 GLM 5.1`,value:`GLM-5.1`},{label:`GLM-5 — 智谱 GLM 5`,value:`GLM-5`},{label:`GLM-4.7 — 智谱 GLM 4.7`,value:`GLM-4.7`},{label:`Kimi-K2.6 — Moonshot Kimi K2.6`,value:`Kimi-K2.6`},{label:`Kimi-K2.5 — Moonshot Kimi K2.5`,value:`Kimi-K2.5`},{label:`MiniMax-M2.7 — MiniMax M2.7`,value:`MiniMax-M2.7`},{label:`Doubao-Seed-2.0-pro — 豆包 Seed 2.0 Pro`,value:`Doubao-Seed-2.0-pro`}]},{key:`default_max_tokens`,label:`默认最大输出 Token`,tooltip:`客户端未指定 max_tokens 时的默认值。更大值允许更长回复,但消耗更多配额`,placeholder:`8192`,type:`number`,tag:`已生效`}]},{title:`连接优化`,fields:[{key:`max_retries`,label:`最大重试次数`,tooltip:`请求失败时的自动重试次数。网络不稳定时可适当增加`,placeholder:`3`,type:`number`,tag:`已生效`},{key:`request_timeout`,label:`请求超时(秒)`,tooltip:`与 JoyCode 后端通信的读取超时时间,低于 60 秒会自动调整为 60 秒`,placeholder:`120`,type:`number`,suffix:`秒`,tag:`已生效`},{key:`max_connections`,label:`最大连接数`,tooltip:`与 JoyCode 后端的最大并发 HTTP 连接数,修改后 10 秒内自动生效`,placeholder:`20`,type:`number`,tag:`已生效`}]},{title:`日志与监控`,fields:[{key:`enable_request_logging`,label:`启用请求日志`,tooltip:`记录每个 API 请求的详细信息(模型、延迟、状态码)。关闭后「数据概览」页面将无数据`,placeholder:`true`,type:`switch`,tag:`已生效`},{key:`log_retention_days`,label:`日志保留天数`,tooltip:`请求日志的自动清理周期。超过此天数的日志将每小时自动清理,0 表示永久保留`,placeholder:`30`,type:`number`,suffix:`天`,tag:`已生效`}]}],N=()=>{let[e,t]=(0,k.useState)(!0),[g,T]=(0,k.useState)(!1),[N,P]=(0,k.useState)(!1),[F]=b.useForm(),[I]=b.useForm(),L=async()=>{t(!0);try{let e=await D.getSettings();F.setFieldsValue(e)}catch(e){r.error(e instanceof Error?e.message:`加载设置失败`)}finally{t(!1)}};(0,k.useEffect)(()=>{L()},[F]);let R=async e=>{T(!0);try{await D.updateSettings(e),r.success(`设置已保存`)}catch(e){r.error(e instanceof Error?e.message:`保存设置失败`)}finally{T(!1)}},z=async e=>{u.confirm({title:`确认修改密码`,content:`修改密码后需要重新登录,确定要继续吗?`,okText:`确认修改`,cancelText:`取消`,okButtonProps:{danger:!0},onOk:async()=>{P(!0);try{await O.changePassword(e.old_password,e.new_password),r.success(`密码修改成功,请重新登录`),I.resetFields(),E(),setTimeout(()=>{window.location.href=`/login`},1e3)}catch(e){r.error(e instanceof Error?e.message:`密码修改失败`)}finally{P(!1)}}})};if(e)return(0,A.jsx)(l,{size:`large`,style:{display:`block`,margin:`100px auto`}});let B=e=>{let t=(0,A.jsxs)(d,{size:4,children:[e.label,(0,A.jsx)(v,{title:e.tooltip,children:(0,A.jsx)(a,{style:{color:`#bbb`}})}),e.tag&&(0,A.jsxs)(h,{color:e.tag===`已生效`?`success`:`default`,style:{marginLeft:4,fontSize:11},children:[e.tag===`已生效`?(0,A.jsx)(c,{}):(0,A.jsx)(y,{}),` `,e.tag]})]});switch(e.type){case`number`:return(0,A.jsx)(b.Item,{name:e.key,label:t,children:(0,A.jsx)(f,{style:{width:`100%`},placeholder:e.placeholder,addonAfter:e.suffix,disabled:e.readOnly})},e.key);case`select`:return(0,A.jsx)(b.Item,{name:e.key,label:t,children:(0,A.jsx)(C,{placeholder:e.placeholder,options:e.options,allowClear:!0,disabled:e.readOnly})},e.key);case`switch`:return(0,A.jsx)(b.Item,{name:e.key,valuePropName:`checked`,label:t,children:(0,A.jsx)(o,{})},e.key);default:return(0,A.jsx)(b.Item,{name:e.key,label:t,children:(0,A.jsx)(n,{placeholder:e.placeholder,disabled:e.readOnly})},e.key)}};return(0,A.jsxs)(`div`,{children:[(0,A.jsx)(w,{style:{marginBottom:16,background:`linear-gradient(135deg, #00b578 0%, #009a63 100%)`,border:`none`,borderRadius:12},styles:{body:{padding:`20px 24px`}},children:(0,A.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`},children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(j,{style:{color:`rgba(255,255,255,0.85)`,fontSize:13},children:`JoyCode API 代理服务 · 系统设置`}),(0,A.jsx)(`div`,{style:{color:`#fff`,fontSize:22,fontWeight:700,marginTop:4},children:`代理配置管理`})]}),(0,A.jsx)(`div`,{style:{display:`flex`,gap:8},children:(0,A.jsx)(x,{ghost:!0,style:{color:`#fff`,borderColor:`rgba(255,255,255,0.4)`},icon:(0,A.jsx)(s,{}),onClick:L,children:`刷新`})})]})}),(0,A.jsxs)(b,{form:F,layout:`vertical`,onFinish:R,children:[M.map(e=>(0,A.jsx)(w,{title:(0,A.jsx)(j,{strong:!0,style:{fontSize:15},children:e.title}),style:{marginBottom:16,borderRadius:8,border:`1px solid #f0f0f0`},styles:{body:{padding:`20px 24px`}},extra:(0,A.jsx)(_,{style:{color:`#00b578`}}),children:(0,A.jsx)(i,{gutter:[24,0],children:e.fields.map(e=>(0,A.jsx)(p,{xs:24,md:12,children:B(e)},e.key))})},e.title)),(0,A.jsx)(w,{title:(0,A.jsx)(j,{strong:!0,style:{fontSize:15},children:`安全设置`}),style:{marginBottom:16,borderRadius:8,border:`1px solid #f0f0f0`},styles:{body:{padding:`20px 24px`}},extra:(0,A.jsx)(_,{style:{color:`#00b578`}}),children:(0,A.jsxs)(b,{form:I,layout:`vertical`,onFinish:z,children:[(0,A.jsxs)(i,{gutter:[24,0],children:[(0,A.jsx)(p,{xs:24,md:8,children:(0,A.jsx)(b.Item,{name:`old_password`,label:`当前密码`,rules:[{required:!0,message:`请输入当前密码`}],children:(0,A.jsx)(n.Password,{placeholder:`输入当前密码`})})}),(0,A.jsx)(p,{xs:24,md:8,children:(0,A.jsx)(b.Item,{name:`new_password`,label:`新密码`,rules:[{required:!0,message:`请输入新密码`},{min:6,message:`密码长度不能少于 6 位`}],children:(0,A.jsx)(n.Password,{placeholder:`输入新密码(至少 6 位)`})})}),(0,A.jsx)(p,{xs:24,md:8,children:(0,A.jsx)(b.Item,{label:`确认新密码`,dependencies:[`new_password`],rules:[{required:!0,message:`请确认新密码`},({getFieldValue:e})=>({validator(t,n){return!n||e(`new_password`)===n?Promise.resolve():Promise.reject(Error(`两次输入的密码不一致`))}})],name:`confirm_password`,children:(0,A.jsx)(n.Password,{placeholder:`再次输入新密码`})})})]}),(0,A.jsx)(x,{type:`primary`,htmlType:`submit`,loading:N,icon:(0,A.jsx)(m,{}),style:{borderRadius:6},children:`修改密码`})]})}),(0,A.jsxs)(`div`,{style:{display:`flex`,gap:12,marginTop:8},children:[(0,A.jsx)(x,{type:`primary`,htmlType:`submit`,loading:g,icon:(0,A.jsx)(S,{}),size:`large`,style:{borderRadius:6},children:`保存设置`}),(0,A.jsx)(x,{onClick:L,icon:(0,A.jsx)(s,{}),size:`large`,children:`恢复当前值`})]})]})]})};export{N as default}; \ No newline at end of file diff --git a/cmd/JoyCodeProxy/static/assets/index-C0OoGTlz.js b/cmd/JoyCodeProxy/static/assets/index-62d9Y_mr.js similarity index 96% rename from cmd/JoyCodeProxy/static/assets/index-C0OoGTlz.js rename to cmd/JoyCodeProxy/static/assets/index-62d9Y_mr.js index 1c9f741..bc589da 100644 --- a/cmd/JoyCodeProxy/static/assets/index-C0OoGTlz.js +++ b/cmd/JoyCodeProxy/static/assets/index-62d9Y_mr.js @@ -1,2 +1,2 @@ -const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/Dashboard-B_CPt8DM.js","assets/rolldown-runtime-S-ySWqyJ.js","assets/vendor-C3SDdTD0.js","assets/antd-BIDKISxA.js","assets/recharts-abRO4Y-P.js","assets/Accounts-DymrWPU2.js","assets/CommandTooltip-Cw9Jxov1.js","assets/AccountDetail-DEkC2vuX.js","assets/Settings-CuaeIRbW.js"])))=>i.map(i=>d[i]); -import{r as e}from"./rolldown-runtime-S-ySWqyJ.js";import{A as t,C as n,E as r,G as i,H as a,J as o,L as s,S as c,T as l,U as u,W as d,b as f,d as p,f as m,ft as h,g,i as _,it as ee,j as te,lt as ne,m as re,mt as ie,o as v,ot as y,q as b,rt as x,t as ae,tt as S,u as oe,ut as C,y as w,z as T}from"./antd-BIDKISxA.js";import{a as E,c as D,d as O,f as k,i as A,l as j,n as se,o as M,r as N,s as ce,t as le}from"./vendor-C3SDdTD0.js";(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var ue=e(h(),1),de=e(l(),1),P=e(ie(),1),fe={"/":`数据概览 — JoyCode 代理`,"/accounts":`账号管理 — JoyCode 代理`,"/settings":`系统设置 — JoyCode 代理`},F=`JoyCode 代理`,I=()=>{let e=D();(0,P.useEffect)(()=>{if(e.pathname.startsWith(`/accounts/`)){let t=decodeURIComponent(e.pathname.replace(`/accounts/`,``));document.title=`${t} — 账号详情 — JoyCode 代理`}else document.title=fe[e.pathname]||F},[e.pathname])};function L(e){return e.remark?e.remark:e.nickname?e.nickname:e.user_id}var R=`joycode_jwt`;function z(){return localStorage.getItem(R)}function B(e){localStorage.setItem(R,e)}function V(){localStorage.removeItem(R)}function pe(){return!!z()}async function H(e,t){let n={"Content-Type":`application/json`},r=z();r&&(n.Authorization=`Bearer ${r}`);let i=await fetch(e,{headers:n,...t});if(i.status===401)throw V(),window.location.href=`/login`,Error(`Unauthorized`);if(!i.ok){let e=await i.json().catch(()=>({detail:i.statusText}));throw Error(e.detail||`HTTP ${i.status}`)}return i.json()}async function U(e,t){let n=await fetch(e,{headers:{"Content-Type":`application/json`},...t});if(!n.ok){let e=await n.json().catch(()=>({detail:n.statusText}));throw Error(e.detail||`HTTP ${n.status}`)}return n.json()}var W={status:()=>U(`/api/auth/status`),setup:e=>U(`/api/auth/setup`,{method:`POST`,body:JSON.stringify({password:e})}),login:e=>U(`/api/auth/login`,{method:`POST`,body:JSON.stringify({password:e})}),changePassword:(e,t)=>H(`/api/auth/change-password`,{method:`POST`,body:JSON.stringify({old_password:e,new_password:t})})},G={listAccounts:()=>H(`/api/accounts`).then(e=>e.accounts),addAccount:e=>H(`/api/accounts`,{method:`POST`,body:JSON.stringify(e)}),removeAccount:e=>H(`/api/accounts/${encodeURIComponent(e)}`,{method:`DELETE`}),setDefault:e=>H(`/api/accounts/${encodeURIComponent(e)}/default`,{method:`PUT`}),validateAccount:e=>H(`/api/accounts/${encodeURIComponent(e)}/validate`,{method:`POST`}),listModels:()=>H(`/api/models`).then(e=>e.models),listAccountModels:e=>H(`/api/accounts/${encodeURIComponent(e)}/models`).then(e=>e.models),getStats:()=>H(`/api/stats`),getSettings:()=>H(`/api/settings`).then(e=>e.settings),updateSettings:e=>H(`/api/settings`,{method:`PUT`,body:JSON.stringify(e)}),getHealth:()=>H(`/api/health`),updateAccountModel:(e,t)=>H(`/api/accounts/${encodeURIComponent(e)}/model`,{method:`PUT`,body:JSON.stringify({default_model:t})}),getAccountStats:e=>H(`/api/accounts/${encodeURIComponent(e)}/stats`),getAccountLogs:(e,t=200)=>H(`/api/accounts/${encodeURIComponent(e)}/logs?limit=${t}`),renewToken:e=>H(`/api/accounts/${encodeURIComponent(e)}/renew-token`,{method:`POST`}),autoLogin:()=>H(`/api/accounts-auto-login`,{method:`POST`}),qrLoginInit:()=>H(`/api/qr-login/init`,{method:`POST`}),qrLoginStatus:e=>H(`/api/qr-login/status?session=${encodeURIComponent(e)}`),browserLogin:()=>H(`/api/browser-login`,{method:`POST`}),oauthSubmit:e=>H(`/api/oauth-submit`,{method:`POST`,body:JSON.stringify({pt_key:e})}),getRecentErrors:(e=50)=>H(`/api/errors?limit=${e}`),getGitHubStars:()=>H(`/api/github-stars`).then(e=>e.stars),clearAllAccounts:()=>H(`/api/accounts-clear-all`,{method:`POST`}),clearJoyCodeSession:()=>H(`/api/clear-joycode-session`,{method:`POST`}),updateRemark:(e,t)=>H(`/api/accounts/${encodeURIComponent(e)}/remark`,{method:`PUT`,body:JSON.stringify({remark:t})}),reorderAccounts:e=>H(`/api/accounts/reorder`,{method:`PUT`,body:JSON.stringify({user_ids:e})}),exportAccounts:()=>H(`/api/accounts-export`),importAccounts:e=>H(`/api/accounts-import`,{method:`POST`,body:JSON.stringify({accounts:e})})},K=le(),{Header:me,Sider:he,Content:ge}=d,{Text:q}=r,_e=[{key:`/dashboard`,icon:(0,K.jsx)(w,{}),label:`数据概览`},{key:`/accounts`,icon:(0,K.jsx)(_,{}),label:`账号管理`},{key:`/settings`,icon:(0,K.jsx)(v,{}),label:`系统设置`}],J=`joycode_sider_collapsed`,ve=()=>{let[e,n]=(0,P.useState)(()=>localStorage.getItem(J)===`true`),r=j(),i=D(),{token:o}=t.useToken();I();let[l,u]=(0,P.useState)(`ok`),[f,p]=(0,P.useState)(0),[m,h]=(0,P.useState)(null);(0,P.useEffect)(()=>{G.getHealth().then(e=>{u(e.status===`ok`?`ok`:`error`),p(e.accounts)}).catch(()=>u(`error`)),G.getGitHubStars().then(e=>{e>0&&h(e)}).catch(()=>{})},[]);let _=i.pathname.startsWith(`/accounts`)?`/accounts`:i.pathname.startsWith(`/settings`)?`/settings`:`/dashboard`;return(0,K.jsxs)(d,{style:{minHeight:`100vh`},children:[(0,K.jsxs)(he,{collapsible:!0,collapsed:e,onCollapse:e=>{n(e),localStorage.setItem(J,String(e))},style:{background:o.colorBgContainer},children:[(0,K.jsxs)(`div`,{style:{height:48,display:`flex`,alignItems:`center`,justifyContent:`center`,borderBottom:`1px solid ${o.colorBorderSecondary}`},children:[(0,K.jsx)(`img`,{src:`/favicon.ico`,alt:`JoyCode`,style:{width:24,height:24,marginRight:e?0:8}}),!e&&(0,K.jsx)(q,{strong:!0,style:{fontSize:15},children:`JoyCode 代理`})]}),(0,K.jsx)(ee,{mode:`inline`,selectedKeys:[_],items:_e,onClick:({key:e})=>r(e)})]}),(0,K.jsxs)(d,{children:[(0,K.jsxs)(me,{style:{padding:`0 24px`,background:o.colorBgContainer,borderBottom:`1px solid ${o.colorBorderSecondary}`,display:`flex`,alignItems:`center`,justifyContent:`space-between`},children:[(0,K.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:12},children:[(0,K.jsx)(te,{color:l===`ok`?`success`:`error`,icon:(0,K.jsx)(c,{}),children:l===`ok`?`服务正常`:`服务异常`}),(0,K.jsxs)(q,{type:`secondary`,children:[f,` 个账号在线`]})]}),(0,K.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:16},children:[(0,K.jsx)(y,{title:`退出登录`,children:(0,K.jsx)(x,{type:`text`,icon:(0,K.jsx)(oe,{}),onClick:()=>{V(),a.success(`已退出登录`),window.location.href=`/login`},style:{color:o.colorTextSecondary}})}),(0,K.jsx)(y,{title:`去 GitHub Star 支持我们`,children:(0,K.jsxs)(`a`,{href:`https://github.com/vibe-coding-labs/JoyCodeProxy`,target:`_blank`,rel:`noopener noreferrer`,style:{display:`flex`,alignItems:`center`,gap:6,color:o.colorTextSecondary,fontSize:13,textDecoration:`none`},children:[(0,K.jsx)(g,{style:{fontSize:18}}),`GitHub`,m!==null&&(0,K.jsxs)(`span`,{style:{display:`inline-flex`,alignItems:`center`,gap:3,marginLeft:2},children:[(0,K.jsx)(s,{style:{fontSize:13,color:`#faad14`}}),(0,K.jsx)(`span`,{style:{fontSize:12},children:m.toLocaleString()})]})]})})]})]}),(0,K.jsx)(ge,{style:{margin:24},children:(0,K.jsx)(E,{})})]})]})},{Title:ye,Text:be}=r,xe=()=>{let[e,t]=(0,P.useState)(!1),[n,r]=(0,P.useState)(null),c=j();return(0,P.useEffect)(()=>{G.getGitHubStars().then(r).catch(()=>{})},[]),(0,K.jsxs)(`div`,{style:{minHeight:`100vh`,display:`flex`,alignItems:`center`,justifyContent:`center`,background:`linear-gradient(135deg, #00b578 0%, #009a63 100%)`,position:`relative`},children:[(0,K.jsx)(y,{title:`去 GitHub Star 支持我们`,children:(0,K.jsxs)(`a`,{href:`https://github.com/vibe-coding-labs/JoyCodeProxy`,target:`_blank`,rel:`noopener noreferrer`,style:{position:`absolute`,top:20,right:24,display:`flex`,alignItems:`center`,gap:6,color:`rgba(255,255,255,0.85)`,fontSize:13,textDecoration:`none`,transition:`color 0.2s`},onMouseEnter:e=>e.currentTarget.style.color=`#fff`,onMouseLeave:e=>e.currentTarget.style.color=`rgba(255,255,255,0.85)`,children:[(0,K.jsx)(g,{style:{fontSize:18}}),`GitHub`,n!==null&&(0,K.jsxs)(`span`,{style:{display:`inline-flex`,alignItems:`center`,gap:3,marginLeft:2},children:[(0,K.jsx)(s,{style:{fontSize:13,color:`#faad14`}}),(0,K.jsx)(`span`,{style:{fontSize:12},children:n.toLocaleString()})]})]})}),(0,K.jsxs)(S,{style:{width:400,borderRadius:12,boxShadow:`0 8px 24px rgba(0,0,0,0.12)`},styles:{body:{padding:32}},children:[(0,K.jsxs)(`div`,{style:{textAlign:`center`,marginBottom:24},children:[(0,K.jsx)(ye,{level:3,style:{marginBottom:4},children:`JoyCode 代理`}),(0,K.jsx)(be,{type:`secondary`,children:`请输入 root 密码登录`})]}),(0,K.jsxs)(b,{onFinish:async e=>{t(!0);try{B((await W.login(e.password)).token),a.success(`登录成功`),c(`/dashboard`)}catch(e){a.error(e instanceof Error?e.message:`登录失败`)}finally{t(!1)}},size:`large`,children:[(0,K.jsx)(b.Item,{name:`username`,initialValue:`root`,children:(0,K.jsx)(i,{prefix:(0,K.jsx)(ae,{}),disabled:!0})}),(0,K.jsx)(b.Item,{name:`password`,rules:[{required:!0,message:`请输入密码`}],children:(0,K.jsx)(i.Password,{prefix:(0,K.jsx)(m,{}),placeholder:`root 密码`,autoFocus:!0})}),(0,K.jsx)(b.Item,{style:{marginBottom:0},children:(0,K.jsx)(x,{type:`primary`,htmlType:`submit`,loading:e,block:!0,style:{borderRadius:6,height:44},children:`登录`})})]}),(0,K.jsx)(`div`,{style:{textAlign:`center`,marginTop:16},children:(0,K.jsxs)(N,{to:`/forgot-password`,style:{color:`#999`,fontSize:13,display:`inline-flex`,alignItems:`center`,gap:4},children:[(0,K.jsx)(o,{}),`忘记密码?`]})})]})]})},{Title:Se,Text:Ce}=r,we=e=>{if(!e)return 0;let t=0;return e.length>=6&&(t+=25),e.length>=10&&(t+=25),/[A-Z]/.test(e)&&/[a-z]/.test(e)&&(t+=25),/[0-9]/.test(e)&&/[^a-zA-Z0-9]/.test(e)&&(t+=25),t},Te=()=>{let[e,t]=(0,P.useState)(!1),n=j();return(0,K.jsx)(`div`,{style:{minHeight:`100vh`,display:`flex`,alignItems:`center`,justifyContent:`center`,background:`linear-gradient(135deg, #00b578 0%, #009a63 100%)`},children:(0,K.jsxs)(S,{style:{width:440,borderRadius:12,boxShadow:`0 8px 24px rgba(0,0,0,0.12)`},styles:{body:{padding:32}},children:[(0,K.jsxs)(`div`,{style:{textAlign:`center`,marginBottom:24},children:[(0,K.jsx)(c,{style:{fontSize:40,color:`#00b578`,marginBottom:8}}),(0,K.jsx)(Se,{level:3,style:{marginBottom:4},children:`初始化 JoyCode 代理`}),(0,K.jsx)(Ce,{type:`secondary`,children:`首次使用,请设置 root 管理员密码`})]}),(0,K.jsxs)(b,{onFinish:async e=>{t(!0);try{B((await W.setup(e.password)).token),a.success(`密码设置成功`),n(`/dashboard`)}catch(e){a.error(e instanceof Error?e.message:`设置失败`)}finally{t(!1)}},size:`large`,autoComplete:`off`,children:[(0,K.jsx)(b.Item,{shouldUpdate:!0,children:({getFieldValue:e})=>{let t=e(`password`)||``,n=we(t),r=n<=25?`#ff4d4f`:n<=50?`#faad14`:n<=75?`#52c41a`:`#00b578`,i=n<=25?`弱`:n<=50?`中`:n<=75?`强`:`很强`;return t?(0,K.jsx)(`div`,{style:{marginTop:-8,marginBottom:16},children:(0,K.jsx)(T,{percent:n,strokeColor:r,format:()=>i,size:`small`})}):null}}),(0,K.jsx)(b.Item,{name:`password`,rules:[{required:!0,message:`请输入密码`},{min:6,message:`密码长度不能少于 6 位`}],children:(0,K.jsx)(i.Password,{prefix:(0,K.jsx)(m,{}),placeholder:`设置密码(至少 6 位)`,autoFocus:!0})}),(0,K.jsx)(b.Item,{name:`confirm`,dependencies:[`password`],rules:[{required:!0,message:`请确认密码`},({getFieldValue:e})=>({validator(t,n){return!n||e(`password`)===n?Promise.resolve():Promise.reject(Error(`两次输入的密码不一致`))}})],children:(0,K.jsx)(i.Password,{prefix:(0,K.jsx)(m,{}),placeholder:`确认密码`})}),(0,K.jsx)(b.Item,{style:{marginBottom:0},children:(0,K.jsx)(x,{type:`primary`,htmlType:`submit`,loading:e,block:!0,style:{borderRadius:6,height:44},children:`设置密码并登录`})})]})]})})},{Title:Ee,Text:Y,Paragraph:De}=r,X={prompt:`#a6e3a1`,path:`#89b4fa`,subcommand:`#94e2d5`,flag:`#f9e2af`,value:`#fab387`};function Oe(e){let t=[],n=e.split(/\s+/);for(let e=0;e(0,K.jsxs)(P.Fragment,{children:[t>0&&` `,(0,K.jsx)(`span`,{style:{color:X[e.type]},children:e.text})]},t))]})}var Ae=()=>{let[e,t]=(0,P.useState)(`./joycode_proxy_bin`);return(0,P.useEffect)(()=>{W.status().then(e=>{e.exe_path&&t(e.exe_path)}).catch(()=>{})},[]),(0,K.jsx)(`div`,{style:{minHeight:`100vh`,display:`flex`,alignItems:`center`,justifyContent:`center`,background:`linear-gradient(135deg, #00b578 0%, #009a63 100%)`},children:(0,K.jsxs)(S,{style:{width:640,borderRadius:12,boxShadow:`0 8px 24px rgba(0,0,0,0.12)`},styles:{body:{padding:32}},children:[(0,K.jsx)(Ee,{level:3,style:{marginBottom:8},children:`忘记密码`}),(0,K.jsx)(De,{type:`secondary`,style:{marginBottom:24},children:`Dashboard 的 root 密码需要通过服务器命令行重置。`}),(0,K.jsx)(C,{type:`info`,showIcon:!0,style:{marginBottom:20},message:`在服务器终端执行以下命令`}),(0,K.jsx)(Y,{strong:!0,children:`交互式重置(会提示你输入新密码):`}),(0,K.jsx)(Z,{children:`${e} reset-password`}),(0,K.jsx)(Y,{strong:!0,children:`直接指定新密码:`}),(0,K.jsx)(Z,{children:`${e} reset-password -p 你的新密码`}),(0,K.jsx)(C,{type:`warning`,showIcon:!0,style:{marginBottom:24},message:(0,K.jsxs)(`span`,{children:[`密码至少 `,(0,K.jsx)(Y,{strong:!0,children:`6 位`}),`,以 bcrypt 哈希加密存储在 SQLite 数据库中。 重置后所有已登录的会话需要重新登录。`]})}),(0,K.jsx)(N,{to:`/login`,children:(0,K.jsx)(x,{icon:(0,K.jsx)(n,{}),type:`primary`,ghost:!0,style:{borderRadius:6},children:`返回登录`})})]})})},{Title:je,Text:Q,Paragraph:Me}=r,Ne=()=>{let e=j(),[t]=O(),n=t.get(`error`)||`未知错误`;return(0,K.jsx)(`div`,{style:{minHeight:`100vh`,display:`flex`,justifyContent:`center`,alignItems:`center`,background:`#f0f2f5`},children:(0,K.jsxs)(S,{style:{width:480,textAlign:`center`,borderRadius:12},children:[(0,K.jsx)(f,{style:{fontSize:64,color:`#ff4d4f`,marginBottom:16}}),(0,K.jsx)(je,{level:3,children:`OAuth 授权失败`}),(0,K.jsx)(Me,{type:`secondary`,style:{fontSize:14},children:`授权过程中发生错误,账号未能添加成功。`}),(0,K.jsx)(S,{size:`small`,style:{background:`#fff2f0`,border:`1px solid #ffccc7`,marginBottom:24,textAlign:`left`},children:(0,K.jsx)(Q,{type:`danger`,style:{fontSize:13,wordBreak:`break-all`},children:n})}),(0,K.jsxs)(`div`,{style:{display:`flex`,gap:12,justifyContent:`center`},children:[(0,K.jsx)(x,{icon:(0,K.jsx)(p,{}),onClick:()=>e(`/accounts`),children:`返回账号管理`}),(0,K.jsx)(x,{type:`primary`,icon:(0,K.jsx)(re,{}),onClick:()=>e(`/dashboard`),children:`返回首页`})]})]})})},Pe=(0,P.lazy)(()=>k(()=>import(`./Dashboard-B_CPt8DM.js`),__vite__mapDeps([0,1,2,3,4]))),Fe=(0,P.lazy)(()=>k(()=>import(`./Accounts-DymrWPU2.js`),__vite__mapDeps([5,1,2,3,6]))),Ie=(0,P.lazy)(()=>k(()=>import(`./AccountDetail-DEkC2vuX.js`),__vite__mapDeps([7,1,2,3,4,6]))),Le=(0,P.lazy)(()=>k(()=>import(`./Settings-CuaeIRbW.js`),__vite__mapDeps([8,1,2,3]))),$=(0,K.jsx)(u,{size:`large`,style:{display:`block`,margin:`100px auto`}}),Re=()=>{let[e]=O(),t=j();return(0,P.useEffect)(()=>{let n=e.get(`login_success`),r=e.get(`login_error`);if(n){let e=document.cookie.split(`; `).find(e=>e.startsWith(`joycode_auto_jwt=`));if(e){let t=e.split(`=`)[1];t&&B(t),document.cookie=`joycode_auto_jwt=; path=/; max-age=0`}a.success(`登录成功!账号「${n}」已添加`),t(`/accounts`,{replace:!0})}else t(r?`/oauth-error?error=${encodeURIComponent(r)}`:`/dashboard`,{replace:!0})},[e,t]),$},ze=({children:e})=>{let[t,n]=(0,P.useState)(!0),[r,i]=(0,P.useState)(!0),[a,o]=(0,P.useState)(!1);return(0,P.useEffect)(()=>{W.status().then(e=>{i(e.initialized),e.initialized&&o(pe()),n(!1)}).catch(()=>{n(!1)})},[]),t?$:r?a?(0,K.jsx)(K.Fragment,{children:e}):(0,K.jsx)(A,{to:`/login`,replace:!0}):(0,K.jsx)(A,{to:`/setup`,replace:!0})};ue.createRoot(document.getElementById(`root`)).render((0,K.jsx)(P.StrictMode,{children:(0,K.jsx)(()=>(0,K.jsx)(ne,{locale:de.default,theme:{token:{colorPrimary:`#00b578`}},children:(0,K.jsx)(se,{children:(0,K.jsxs)(ce,{children:[(0,K.jsx)(M,{path:`/setup`,element:(0,K.jsx)(Te,{})}),(0,K.jsx)(M,{path:`/login`,element:(0,K.jsx)(xe,{})}),(0,K.jsx)(M,{path:`/forgot-password`,element:(0,K.jsx)(Ae,{})}),(0,K.jsx)(M,{path:`/oauth-error`,element:(0,K.jsx)(Ne,{})}),(0,K.jsxs)(M,{element:(0,K.jsx)(ze,{children:(0,K.jsx)(ve,{})}),children:[(0,K.jsx)(M,{path:`/dashboard`,element:(0,K.jsx)(P.Suspense,{fallback:$,children:(0,K.jsx)(Pe,{})})}),(0,K.jsx)(M,{path:`/accounts`,element:(0,K.jsx)(P.Suspense,{fallback:$,children:(0,K.jsx)(Fe,{})})}),(0,K.jsx)(M,{path:`/accounts/:userId`,element:(0,K.jsx)(P.Suspense,{fallback:$,children:(0,K.jsx)(Ie,{})})}),(0,K.jsx)(M,{path:`/settings`,element:(0,K.jsx)(P.Suspense,{fallback:$,children:(0,K.jsx)(Le,{})})})]}),(0,K.jsx)(M,{path:`/`,element:(0,K.jsx)(Re,{})})]})})}),{})}));export{V as i,G as n,W as r,L as t}; \ No newline at end of file +const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/Dashboard-DLytBGNF.js","assets/rolldown-runtime-S-ySWqyJ.js","assets/vendor-C3SDdTD0.js","assets/antd-BIDKISxA.js","assets/recharts-abRO4Y-P.js","assets/Accounts-teu0Jh5t.js","assets/CommandTooltip-Cw9Jxov1.js","assets/AccountDetail-qwdKolAO.js","assets/Settings-BVAc1eo4.js"])))=>i.map(i=>d[i]); +import{r as e}from"./rolldown-runtime-S-ySWqyJ.js";import{A as t,C as n,E as r,G as i,H as a,J as o,L as s,S as c,T as l,U as u,W as d,b as f,d as p,f as m,ft as h,g,i as _,it as ee,j as te,lt as ne,m as re,mt as ie,o as v,ot as y,q as b,rt as x,t as ae,tt as S,u as oe,ut as C,y as w,z as T}from"./antd-BIDKISxA.js";import{a as E,c as D,d as O,f as k,i as A,l as j,n as se,o as M,r as N,s as ce,t as le}from"./vendor-C3SDdTD0.js";(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var ue=e(h(),1),de=e(l(),1),P=e(ie(),1),fe={"/":`数据概览 — JoyCode 代理`,"/accounts":`账号管理 — JoyCode 代理`,"/settings":`系统设置 — JoyCode 代理`},F=`JoyCode 代理`,I=()=>{let e=D();(0,P.useEffect)(()=>{if(e.pathname.startsWith(`/accounts/`)){let t=decodeURIComponent(e.pathname.replace(`/accounts/`,``));document.title=`${t} — 账号详情 — JoyCode 代理`}else document.title=fe[e.pathname]||F},[e.pathname])};function L(e){return e.remark?e.remark:e.nickname?e.nickname:e.user_id}var R=`joycode_jwt`;function z(){return localStorage.getItem(R)}function B(e){localStorage.setItem(R,e)}function V(){localStorage.removeItem(R)}function pe(){return!!z()}async function H(e,t){let n={"Content-Type":`application/json`},r=z();r&&(n.Authorization=`Bearer ${r}`);let i=await fetch(e,{headers:n,...t});if(i.status===401)throw V(),window.location.href=`/login`,Error(`Unauthorized`);if(!i.ok){let e=await i.json().catch(()=>({detail:i.statusText}));throw Error(e.detail||`HTTP ${i.status}`)}return i.json()}async function U(e,t){let n=await fetch(e,{headers:{"Content-Type":`application/json`},...t});if(!n.ok){let e=await n.json().catch(()=>({detail:n.statusText}));throw Error(e.detail||`HTTP ${n.status}`)}return n.json()}var W={status:()=>U(`/api/auth/status`),setup:e=>U(`/api/auth/setup`,{method:`POST`,body:JSON.stringify({password:e})}),login:e=>U(`/api/auth/login`,{method:`POST`,body:JSON.stringify({password:e})}),changePassword:(e,t)=>H(`/api/auth/change-password`,{method:`POST`,body:JSON.stringify({old_password:e,new_password:t})})},G={listAccounts:()=>H(`/api/accounts`).then(e=>e.accounts),addAccount:e=>H(`/api/accounts`,{method:`POST`,body:JSON.stringify(e)}),removeAccount:e=>H(`/api/accounts/${encodeURIComponent(e)}`,{method:`DELETE`}),setDefault:e=>H(`/api/accounts/${encodeURIComponent(e)}/default`,{method:`PUT`}),validateAccount:e=>H(`/api/accounts/${encodeURIComponent(e)}/validate`,{method:`POST`}),listModels:()=>H(`/api/models`).then(e=>e.models),listAccountModels:e=>H(`/api/accounts/${encodeURIComponent(e)}/models`).then(e=>e.models),getStats:()=>H(`/api/stats`),getSettings:()=>H(`/api/settings`).then(e=>e.settings),updateSettings:e=>H(`/api/settings`,{method:`PUT`,body:JSON.stringify(e)}),getHealth:()=>H(`/api/health`),updateAccountModel:(e,t)=>H(`/api/accounts/${encodeURIComponent(e)}/model`,{method:`PUT`,body:JSON.stringify({default_model:t})}),getAccountStats:e=>H(`/api/accounts/${encodeURIComponent(e)}/stats`),getAccountLogs:(e,t=200)=>H(`/api/accounts/${encodeURIComponent(e)}/logs?limit=${t}`),renewToken:e=>H(`/api/accounts/${encodeURIComponent(e)}/renew-token`,{method:`POST`}),autoLogin:()=>H(`/api/accounts-auto-login`,{method:`POST`}),qrLoginInit:()=>H(`/api/qr-login/init`,{method:`POST`}),qrLoginStatus:e=>H(`/api/qr-login/status?session=${encodeURIComponent(e)}`),browserLogin:()=>H(`/api/browser-login`,{method:`POST`}),oauthSubmit:e=>H(`/api/oauth-submit`,{method:`POST`,body:JSON.stringify({pt_key:e})}),getRecentErrors:(e=50)=>H(`/api/errors?limit=${e}`),getGitHubStars:()=>H(`/api/github-stars`).then(e=>e.stars),clearAllAccounts:()=>H(`/api/accounts-clear-all`,{method:`POST`}),clearJoyCodeSession:()=>H(`/api/clear-joycode-session`,{method:`POST`}),updateRemark:(e,t)=>H(`/api/accounts/${encodeURIComponent(e)}/remark`,{method:`PUT`,body:JSON.stringify({remark:t})}),reorderAccounts:e=>H(`/api/accounts/reorder`,{method:`PUT`,body:JSON.stringify({user_ids:e})}),exportAccounts:()=>H(`/api/accounts-export`),importAccounts:e=>H(`/api/accounts-import`,{method:`POST`,body:JSON.stringify({accounts:e})})},K=le(),{Header:me,Sider:he,Content:ge}=d,{Text:q}=r,_e=[{key:`/dashboard`,icon:(0,K.jsx)(w,{}),label:`数据概览`},{key:`/accounts`,icon:(0,K.jsx)(_,{}),label:`账号管理`},{key:`/settings`,icon:(0,K.jsx)(v,{}),label:`系统设置`}],J=`joycode_sider_collapsed`,ve=()=>{let[e,n]=(0,P.useState)(()=>localStorage.getItem(J)===`true`),r=j(),i=D(),{token:o}=t.useToken();I();let[l,u]=(0,P.useState)(`ok`),[f,p]=(0,P.useState)(0),[m,h]=(0,P.useState)(null);(0,P.useEffect)(()=>{G.getHealth().then(e=>{u(e.status===`ok`?`ok`:`error`),p(e.accounts)}).catch(()=>u(`error`)),G.getGitHubStars().then(e=>{e>0&&h(e)}).catch(()=>{})},[]);let _=i.pathname.startsWith(`/accounts`)?`/accounts`:i.pathname.startsWith(`/settings`)?`/settings`:`/dashboard`;return(0,K.jsxs)(d,{style:{minHeight:`100vh`},children:[(0,K.jsxs)(he,{collapsible:!0,collapsed:e,onCollapse:e=>{n(e),localStorage.setItem(J,String(e))},style:{background:o.colorBgContainer},children:[(0,K.jsxs)(`div`,{style:{height:48,display:`flex`,alignItems:`center`,justifyContent:`center`,borderBottom:`1px solid ${o.colorBorderSecondary}`},children:[(0,K.jsx)(`img`,{src:`/favicon.ico`,alt:`JoyCode`,style:{width:24,height:24,marginRight:e?0:8}}),!e&&(0,K.jsx)(q,{strong:!0,style:{fontSize:15},children:`JoyCode 代理`})]}),(0,K.jsx)(ee,{mode:`inline`,selectedKeys:[_],items:_e,onClick:({key:e})=>r(e)})]}),(0,K.jsxs)(d,{children:[(0,K.jsxs)(me,{style:{padding:`0 24px`,background:o.colorBgContainer,borderBottom:`1px solid ${o.colorBorderSecondary}`,display:`flex`,alignItems:`center`,justifyContent:`space-between`},children:[(0,K.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:12},children:[(0,K.jsx)(te,{color:l===`ok`?`success`:`error`,icon:(0,K.jsx)(c,{}),children:l===`ok`?`服务正常`:`服务异常`}),(0,K.jsxs)(q,{type:`secondary`,children:[f,` 个账号在线`]})]}),(0,K.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:16},children:[(0,K.jsx)(y,{title:`退出登录`,children:(0,K.jsx)(x,{type:`text`,icon:(0,K.jsx)(oe,{}),onClick:()=>{V(),a.success(`已退出登录`),window.location.href=`/login`},style:{color:o.colorTextSecondary}})}),(0,K.jsx)(y,{title:`去 GitHub Star 支持我们`,children:(0,K.jsxs)(`a`,{href:`https://github.com/vibe-coding-labs/JoyCodeProxy`,target:`_blank`,rel:`noopener noreferrer`,style:{display:`flex`,alignItems:`center`,gap:6,color:o.colorTextSecondary,fontSize:13,textDecoration:`none`},children:[(0,K.jsx)(g,{style:{fontSize:18}}),`GitHub`,m!==null&&(0,K.jsxs)(`span`,{style:{display:`inline-flex`,alignItems:`center`,gap:3,marginLeft:2},children:[(0,K.jsx)(s,{style:{fontSize:13,color:`#faad14`}}),(0,K.jsx)(`span`,{style:{fontSize:12},children:m.toLocaleString()})]})]})})]})]}),(0,K.jsx)(ge,{style:{margin:24},children:(0,K.jsx)(E,{})})]})]})},{Title:ye,Text:be}=r,xe=()=>{let[e,t]=(0,P.useState)(!1),[n,r]=(0,P.useState)(null),c=j();return(0,P.useEffect)(()=>{G.getGitHubStars().then(r).catch(()=>{})},[]),(0,K.jsxs)(`div`,{style:{minHeight:`100vh`,display:`flex`,alignItems:`center`,justifyContent:`center`,background:`linear-gradient(135deg, #00b578 0%, #009a63 100%)`,position:`relative`},children:[(0,K.jsx)(y,{title:`去 GitHub Star 支持我们`,children:(0,K.jsxs)(`a`,{href:`https://github.com/vibe-coding-labs/JoyCodeProxy`,target:`_blank`,rel:`noopener noreferrer`,style:{position:`absolute`,top:20,right:24,display:`flex`,alignItems:`center`,gap:6,color:`rgba(255,255,255,0.85)`,fontSize:13,textDecoration:`none`,transition:`color 0.2s`},onMouseEnter:e=>e.currentTarget.style.color=`#fff`,onMouseLeave:e=>e.currentTarget.style.color=`rgba(255,255,255,0.85)`,children:[(0,K.jsx)(g,{style:{fontSize:18}}),`GitHub`,n!==null&&(0,K.jsxs)(`span`,{style:{display:`inline-flex`,alignItems:`center`,gap:3,marginLeft:2},children:[(0,K.jsx)(s,{style:{fontSize:13,color:`#faad14`}}),(0,K.jsx)(`span`,{style:{fontSize:12},children:n.toLocaleString()})]})]})}),(0,K.jsxs)(S,{style:{width:400,borderRadius:12,boxShadow:`0 8px 24px rgba(0,0,0,0.12)`},styles:{body:{padding:32}},children:[(0,K.jsxs)(`div`,{style:{textAlign:`center`,marginBottom:24},children:[(0,K.jsx)(ye,{level:3,style:{marginBottom:4},children:`JoyCode 代理`}),(0,K.jsx)(be,{type:`secondary`,children:`请输入 root 密码登录`})]}),(0,K.jsxs)(b,{onFinish:async e=>{t(!0);try{B((await W.login(e.password)).token),a.success(`登录成功`),c(`/dashboard`)}catch(e){a.error(e instanceof Error?e.message:`登录失败`)}finally{t(!1)}},size:`large`,children:[(0,K.jsx)(b.Item,{name:`username`,initialValue:`root`,children:(0,K.jsx)(i,{prefix:(0,K.jsx)(ae,{}),disabled:!0})}),(0,K.jsx)(b.Item,{name:`password`,rules:[{required:!0,message:`请输入密码`}],children:(0,K.jsx)(i.Password,{prefix:(0,K.jsx)(m,{}),placeholder:`root 密码`,autoFocus:!0})}),(0,K.jsx)(b.Item,{style:{marginBottom:0},children:(0,K.jsx)(x,{type:`primary`,htmlType:`submit`,loading:e,block:!0,style:{borderRadius:6,height:44},children:`登录`})})]}),(0,K.jsx)(`div`,{style:{textAlign:`center`,marginTop:16},children:(0,K.jsxs)(N,{to:`/forgot-password`,style:{color:`#999`,fontSize:13,display:`inline-flex`,alignItems:`center`,gap:4},children:[(0,K.jsx)(o,{}),`忘记密码?`]})})]})]})},{Title:Se,Text:Ce}=r,we=e=>{if(!e)return 0;let t=0;return e.length>=6&&(t+=25),e.length>=10&&(t+=25),/[A-Z]/.test(e)&&/[a-z]/.test(e)&&(t+=25),/[0-9]/.test(e)&&/[^a-zA-Z0-9]/.test(e)&&(t+=25),t},Te=()=>{let[e,t]=(0,P.useState)(!1),n=j();return(0,K.jsx)(`div`,{style:{minHeight:`100vh`,display:`flex`,alignItems:`center`,justifyContent:`center`,background:`linear-gradient(135deg, #00b578 0%, #009a63 100%)`},children:(0,K.jsxs)(S,{style:{width:440,borderRadius:12,boxShadow:`0 8px 24px rgba(0,0,0,0.12)`},styles:{body:{padding:32}},children:[(0,K.jsxs)(`div`,{style:{textAlign:`center`,marginBottom:24},children:[(0,K.jsx)(c,{style:{fontSize:40,color:`#00b578`,marginBottom:8}}),(0,K.jsx)(Se,{level:3,style:{marginBottom:4},children:`初始化 JoyCode 代理`}),(0,K.jsx)(Ce,{type:`secondary`,children:`首次使用,请设置 root 管理员密码`})]}),(0,K.jsxs)(b,{onFinish:async e=>{t(!0);try{B((await W.setup(e.password)).token),a.success(`密码设置成功`),n(`/dashboard`)}catch(e){a.error(e instanceof Error?e.message:`设置失败`)}finally{t(!1)}},size:`large`,autoComplete:`off`,children:[(0,K.jsx)(b.Item,{shouldUpdate:!0,children:({getFieldValue:e})=>{let t=e(`password`)||``,n=we(t),r=n<=25?`#ff4d4f`:n<=50?`#faad14`:n<=75?`#52c41a`:`#00b578`,i=n<=25?`弱`:n<=50?`中`:n<=75?`强`:`很强`;return t?(0,K.jsx)(`div`,{style:{marginTop:-8,marginBottom:16},children:(0,K.jsx)(T,{percent:n,strokeColor:r,format:()=>i,size:`small`})}):null}}),(0,K.jsx)(b.Item,{name:`password`,rules:[{required:!0,message:`请输入密码`},{min:6,message:`密码长度不能少于 6 位`}],children:(0,K.jsx)(i.Password,{prefix:(0,K.jsx)(m,{}),placeholder:`设置密码(至少 6 位)`,autoFocus:!0})}),(0,K.jsx)(b.Item,{name:`confirm`,dependencies:[`password`],rules:[{required:!0,message:`请确认密码`},({getFieldValue:e})=>({validator(t,n){return!n||e(`password`)===n?Promise.resolve():Promise.reject(Error(`两次输入的密码不一致`))}})],children:(0,K.jsx)(i.Password,{prefix:(0,K.jsx)(m,{}),placeholder:`确认密码`})}),(0,K.jsx)(b.Item,{style:{marginBottom:0},children:(0,K.jsx)(x,{type:`primary`,htmlType:`submit`,loading:e,block:!0,style:{borderRadius:6,height:44},children:`设置密码并登录`})})]})]})})},{Title:Ee,Text:Y,Paragraph:De}=r,X={prompt:`#a6e3a1`,path:`#89b4fa`,subcommand:`#94e2d5`,flag:`#f9e2af`,value:`#fab387`};function Oe(e){let t=[],n=e.split(/\s+/);for(let e=0;e(0,K.jsxs)(P.Fragment,{children:[t>0&&` `,(0,K.jsx)(`span`,{style:{color:X[e.type]},children:e.text})]},t))]})}var Ae=()=>{let[e,t]=(0,P.useState)(`./joycode_proxy_bin`);return(0,P.useEffect)(()=>{W.status().then(e=>{e.exe_path&&t(e.exe_path)}).catch(()=>{})},[]),(0,K.jsx)(`div`,{style:{minHeight:`100vh`,display:`flex`,alignItems:`center`,justifyContent:`center`,background:`linear-gradient(135deg, #00b578 0%, #009a63 100%)`},children:(0,K.jsxs)(S,{style:{width:640,borderRadius:12,boxShadow:`0 8px 24px rgba(0,0,0,0.12)`},styles:{body:{padding:32}},children:[(0,K.jsx)(Ee,{level:3,style:{marginBottom:8},children:`忘记密码`}),(0,K.jsx)(De,{type:`secondary`,style:{marginBottom:24},children:`Dashboard 的 root 密码需要通过服务器命令行重置。`}),(0,K.jsx)(C,{type:`info`,showIcon:!0,style:{marginBottom:20},message:`在服务器终端执行以下命令`}),(0,K.jsx)(Y,{strong:!0,children:`交互式重置(会提示你输入新密码):`}),(0,K.jsx)(Z,{children:`${e} reset-password`}),(0,K.jsx)(Y,{strong:!0,children:`直接指定新密码:`}),(0,K.jsx)(Z,{children:`${e} reset-password -p 你的新密码`}),(0,K.jsx)(C,{type:`warning`,showIcon:!0,style:{marginBottom:24},message:(0,K.jsxs)(`span`,{children:[`密码至少 `,(0,K.jsx)(Y,{strong:!0,children:`6 位`}),`,以 bcrypt 哈希加密存储在 SQLite 数据库中。 重置后所有已登录的会话需要重新登录。`]})}),(0,K.jsx)(N,{to:`/login`,children:(0,K.jsx)(x,{icon:(0,K.jsx)(n,{}),type:`primary`,ghost:!0,style:{borderRadius:6},children:`返回登录`})})]})})},{Title:je,Text:Q,Paragraph:Me}=r,Ne=()=>{let e=j(),[t]=O(),n=t.get(`error`)||`未知错误`;return(0,K.jsx)(`div`,{style:{minHeight:`100vh`,display:`flex`,justifyContent:`center`,alignItems:`center`,background:`#f0f2f5`},children:(0,K.jsxs)(S,{style:{width:480,textAlign:`center`,borderRadius:12},children:[(0,K.jsx)(f,{style:{fontSize:64,color:`#ff4d4f`,marginBottom:16}}),(0,K.jsx)(je,{level:3,children:`OAuth 授权失败`}),(0,K.jsx)(Me,{type:`secondary`,style:{fontSize:14},children:`授权过程中发生错误,账号未能添加成功。`}),(0,K.jsx)(S,{size:`small`,style:{background:`#fff2f0`,border:`1px solid #ffccc7`,marginBottom:24,textAlign:`left`},children:(0,K.jsx)(Q,{type:`danger`,style:{fontSize:13,wordBreak:`break-all`},children:n})}),(0,K.jsxs)(`div`,{style:{display:`flex`,gap:12,justifyContent:`center`},children:[(0,K.jsx)(x,{icon:(0,K.jsx)(p,{}),onClick:()=>e(`/accounts`),children:`返回账号管理`}),(0,K.jsx)(x,{type:`primary`,icon:(0,K.jsx)(re,{}),onClick:()=>e(`/dashboard`),children:`返回首页`})]})]})})},Pe=(0,P.lazy)(()=>k(()=>import(`./Dashboard-DLytBGNF.js`),__vite__mapDeps([0,1,2,3,4]))),Fe=(0,P.lazy)(()=>k(()=>import(`./Accounts-teu0Jh5t.js`),__vite__mapDeps([5,1,2,3,6]))),Ie=(0,P.lazy)(()=>k(()=>import(`./AccountDetail-qwdKolAO.js`),__vite__mapDeps([7,1,2,3,4,6]))),Le=(0,P.lazy)(()=>k(()=>import(`./Settings-BVAc1eo4.js`),__vite__mapDeps([8,1,2,3]))),$=(0,K.jsx)(u,{size:`large`,style:{display:`block`,margin:`100px auto`}}),Re=()=>{let[e]=O(),t=j();return(0,P.useEffect)(()=>{let n=e.get(`login_success`),r=e.get(`login_error`);if(n){let e=document.cookie.split(`; `).find(e=>e.startsWith(`joycode_auto_jwt=`));if(e){let t=e.split(`=`)[1];t&&B(t),document.cookie=`joycode_auto_jwt=; path=/; max-age=0`}a.success(`登录成功!账号「${n}」已添加`),t(`/accounts`,{replace:!0})}else t(r?`/oauth-error?error=${encodeURIComponent(r)}`:`/dashboard`,{replace:!0})},[e,t]),$},ze=({children:e})=>{let[t,n]=(0,P.useState)(!0),[r,i]=(0,P.useState)(!0),[a,o]=(0,P.useState)(!1);return(0,P.useEffect)(()=>{W.status().then(e=>{i(e.initialized),e.initialized&&o(pe()),n(!1)}).catch(()=>{n(!1)})},[]),t?$:r?a?(0,K.jsx)(K.Fragment,{children:e}):(0,K.jsx)(A,{to:`/login`,replace:!0}):(0,K.jsx)(A,{to:`/setup`,replace:!0})};ue.createRoot(document.getElementById(`root`)).render((0,K.jsx)(P.StrictMode,{children:(0,K.jsx)(()=>(0,K.jsx)(ne,{locale:de.default,theme:{token:{colorPrimary:`#00b578`}},children:(0,K.jsx)(se,{children:(0,K.jsxs)(ce,{children:[(0,K.jsx)(M,{path:`/setup`,element:(0,K.jsx)(Te,{})}),(0,K.jsx)(M,{path:`/login`,element:(0,K.jsx)(xe,{})}),(0,K.jsx)(M,{path:`/forgot-password`,element:(0,K.jsx)(Ae,{})}),(0,K.jsx)(M,{path:`/oauth-error`,element:(0,K.jsx)(Ne,{})}),(0,K.jsxs)(M,{element:(0,K.jsx)(ze,{children:(0,K.jsx)(ve,{})}),children:[(0,K.jsx)(M,{path:`/dashboard`,element:(0,K.jsx)(P.Suspense,{fallback:$,children:(0,K.jsx)(Pe,{})})}),(0,K.jsx)(M,{path:`/accounts`,element:(0,K.jsx)(P.Suspense,{fallback:$,children:(0,K.jsx)(Fe,{})})}),(0,K.jsx)(M,{path:`/accounts/:userId`,element:(0,K.jsx)(P.Suspense,{fallback:$,children:(0,K.jsx)(Ie,{})})}),(0,K.jsx)(M,{path:`/settings`,element:(0,K.jsx)(P.Suspense,{fallback:$,children:(0,K.jsx)(Le,{})})})]}),(0,K.jsx)(M,{path:`/`,element:(0,K.jsx)(Re,{})})]})})}),{})}));export{V as i,G as n,W as r,L as t}; \ No newline at end of file diff --git a/cmd/JoyCodeProxy/static/index.html b/cmd/JoyCodeProxy/static/index.html index 5708254..f99dca3 100644 --- a/cmd/JoyCodeProxy/static/index.html +++ b/cmd/JoyCodeProxy/static/index.html @@ -1,17 +1,17 @@ - - - - - - - JoyCode 代理 - + + + + + + + JoyCode 代理 + - - -
- - + + +
+ + diff --git a/web/src/pages/Settings.tsx b/web/src/pages/Settings.tsx index efbfd0e..7c05df5 100644 --- a/web/src/pages/Settings.tsx +++ b/web/src/pages/Settings.tsx @@ -135,7 +135,10 @@ const SettingsPage: React.FC = () => { const handleSave = async (values: Settings) => { setSaving(true); try { - await api.updateSettings(values); + const payload = Object.fromEntries( + Object.entries(values).map(([key, value]) => [key, String(value)]) + ); + await api.updateSettings(payload); message.success('设置已保存'); } catch (e: unknown) { message.error(e instanceof Error ? e.message : '保存设置失败');