diff --git a/.gitignore b/.gitignore
index 3bc0b5c..6887075 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
*.dll
*.so
*.dylib
+/JoyCode2Api
/JoyCodeProxy
# Go build cache
@@ -17,7 +18,8 @@ dist/
out/
joycode_proxy_bin
joycode_proxy_bin.bak
-cmd/JoyCodeProxy/JoyCodeProxy
+cmd/JoyCode2Api/JoyCode2Api
+cmd/JoyCode2Api/JoyCodeProxy
joycode_proxy_darwin_*
joycode_proxy_linux_*
joycode-proxy
diff --git a/Dockerfile b/Dockerfile
index b5c8cbf..7c7e7f1 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -15,7 +15,7 @@ COPY go.mod go.sum ./
RUN go mod download
COPY . .
-RUN CGO_ENABLED=1 go build -ldflags "-s -w" -o /JoyCodeProxy ./cmd/JoyCodeProxy
+RUN CGO_ENABLED=1 go build -ldflags "-s -w" -o /JoyCode2Api ./cmd/JoyCode2Api
FROM alpine:3.19
@@ -23,12 +23,12 @@ ARG ALPINE_MIRROR
RUN sed -i "s|https://dl-cdn.alpinelinux.org/alpine|${ALPINE_MIRROR}|g" /etc/apk/repositories \
&& apk add --no-cache ca-certificates
-COPY --from=builder /JoyCodeProxy /usr/local/bin/JoyCodeProxy
+COPY --from=builder /JoyCode2Api /usr/local/bin/JoyCode2Api
EXPOSE 34891
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
CMD wget -qO- http://localhost:34891/health || exit 1
-ENTRYPOINT ["JoyCodeProxy"]
+ENTRYPOINT ["JoyCode2Api"]
CMD ["serve"]
diff --git a/README.md b/README.md
index 4a4a1d7..9711c41 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-# JoyCodeProxy
+# JoyCode2Api
**一个不太正经的协议翻译器**
@@ -24,10 +24,10 @@ JoyAI-Code · GLM-5.1 · Kimi-K2.6 · MiniMax-M2.7 · Doubao-Seed-2.0-pro
事情是这样的:JoyCode(京东的 AI 编程助手)里面有一些不错的模型,GLM、Kimi、MiniMax、Doubao 这些都有。但它的 API 协议跟 Anthropic 和 OpenAI 的不一样,所以 Claude Code、Cursor 这些主流编程工具接不上。
-JoyCodeProxy 就是在中间做了一个翻译层,把协议对齐了。改两个环境变量,Claude Code 就能直接用 JoyCode 的模型了。
+JoyCode2Api 就是在中间做了一个翻译层,把协议对齐了。改两个环境变量,Claude Code 就能直接用 JoyCode 的模型了。
```
-Claude Code / Cursor / Windsurf → JoyCodeProxy → JoyCode API
+Claude Code / Cursor / Windsurf → JoyCode2Api → JoyCode API
(协议翻译)
```
@@ -78,7 +78,7 @@ Claude Code / Cursor / Windsurf → JoyCodeProxy → JoyCode API
cd web && npm install && npm run build && cd ..
# 再构建后端(前端会自动嵌入)
-go build -o joycode_proxy_bin ./cmd/JoyCodeProxy/
+go build -o JoyCode2Api ./cmd/JoyCode2Api/
```
或者用 Docker:
@@ -101,7 +101,7 @@ docker run -p 34891:34891 joycode-proxy
### 启动
```bash
-./joycode_proxy_bin serve
+./JoyCode2Api serve
```
默认监听 `0.0.0.0:34891`。macOS 首次启动会自动从本地 JoyCode 客户端读取凭据,不需要手动配。
@@ -159,7 +159,7 @@ claude
## 项目结构
```
-cmd/JoyCodeProxy/ 入口,HTTP 服务器
+cmd/JoyCode2Api/ 入口,HTTP 服务器
pkg/anthropic/ Anthropic 协议翻译(请求、响应、SSE 流式)
pkg/openai/ OpenAI 协议翻译
pkg/joycode/ JoyCode API 客户端
diff --git a/cmd/JoyCodeProxy/anthropic_image_test.go b/cmd/JoyCode2Api/anthropic_image_test.go
similarity index 96%
rename from cmd/JoyCodeProxy/anthropic_image_test.go
rename to cmd/JoyCode2Api/anthropic_image_test.go
index 44bf66a..79579ef 100644
--- a/cmd/JoyCodeProxy/anthropic_image_test.go
+++ b/cmd/JoyCode2Api/anthropic_image_test.go
@@ -8,8 +8,8 @@ import (
"strings"
"testing"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/anthropic"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/joycode"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/anthropic"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/joycode"
)
// Regression for issue #4 (vision sub-bug): the Anthropic /v1/messages path
diff --git a/cmd/JoyCodeProxy/chat.go b/cmd/JoyCode2Api/chat.go
similarity index 97%
rename from cmd/JoyCodeProxy/chat.go
rename to cmd/JoyCode2Api/chat.go
index e7807cd..05d5874 100644
--- a/cmd/JoyCodeProxy/chat.go
+++ b/cmd/JoyCode2Api/chat.go
@@ -4,7 +4,7 @@ import (
"fmt"
"github.com/spf13/cobra"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/joycode"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/joycode"
)
var (
diff --git a/cmd/JoyCodeProxy/check.go b/cmd/JoyCode2Api/check.go
similarity index 100%
rename from cmd/JoyCodeProxy/check.go
rename to cmd/JoyCode2Api/check.go
diff --git a/cmd/JoyCodeProxy/config.go b/cmd/JoyCode2Api/config.go
similarity index 95%
rename from cmd/JoyCodeProxy/config.go
rename to cmd/JoyCode2Api/config.go
index 83513a0..e66e3c0 100644
--- a/cmd/JoyCodeProxy/config.go
+++ b/cmd/JoyCode2Api/config.go
@@ -6,8 +6,8 @@ import (
"path/filepath"
"github.com/spf13/cobra"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/auth"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/joycode"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/auth"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/joycode"
)
var configCmd = &cobra.Command{
diff --git a/cmd/JoyCodeProxy/daemon.go b/cmd/JoyCode2Api/daemon.go
similarity index 99%
rename from cmd/JoyCodeProxy/daemon.go
rename to cmd/JoyCode2Api/daemon.go
index 1d94f0b..e6f6d02 100644
--- a/cmd/JoyCodeProxy/daemon.go
+++ b/cmd/JoyCode2Api/daemon.go
@@ -16,7 +16,7 @@ import (
"time"
"github.com/spf13/cobra"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/logrot"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/logrot"
)
const (
diff --git a/cmd/JoyCodeProxy/daemon_test.go b/cmd/JoyCode2Api/daemon_test.go
similarity index 100%
rename from cmd/JoyCodeProxy/daemon_test.go
rename to cmd/JoyCode2Api/daemon_test.go
diff --git a/cmd/JoyCodeProxy/dashboard_test.go b/cmd/JoyCode2Api/dashboard_test.go
similarity index 100%
rename from cmd/JoyCodeProxy/dashboard_test.go
rename to cmd/JoyCode2Api/dashboard_test.go
diff --git a/cmd/JoyCodeProxy/dual_listener.go b/cmd/JoyCode2Api/dual_listener.go
similarity index 100%
rename from cmd/JoyCodeProxy/dual_listener.go
rename to cmd/JoyCode2Api/dual_listener.go
diff --git a/cmd/JoyCodeProxy/embed.go b/cmd/JoyCode2Api/embed.go
similarity index 100%
rename from cmd/JoyCodeProxy/embed.go
rename to cmd/JoyCode2Api/embed.go
diff --git a/cmd/JoyCodeProxy/integration_test.go b/cmd/JoyCode2Api/integration_test.go
similarity index 100%
rename from cmd/JoyCodeProxy/integration_test.go
rename to cmd/JoyCode2Api/integration_test.go
diff --git a/cmd/JoyCodeProxy/main.go b/cmd/JoyCode2Api/main.go
similarity index 100%
rename from cmd/JoyCodeProxy/main.go
rename to cmd/JoyCode2Api/main.go
diff --git a/cmd/JoyCodeProxy/models.go b/cmd/JoyCode2Api/models.go
similarity index 92%
rename from cmd/JoyCodeProxy/models.go
rename to cmd/JoyCode2Api/models.go
index 6f61ee4..5d49e88 100644
--- a/cmd/JoyCodeProxy/models.go
+++ b/cmd/JoyCode2Api/models.go
@@ -4,7 +4,7 @@ import (
"fmt"
"github.com/spf13/cobra"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/joycode"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/joycode"
)
var modelsCmd = &cobra.Command{
diff --git a/cmd/JoyCodeProxy/reset_password.go b/cmd/JoyCode2Api/reset_password.go
similarity index 93%
rename from cmd/JoyCodeProxy/reset_password.go
rename to cmd/JoyCode2Api/reset_password.go
index 6c07fac..6845c03 100644
--- a/cmd/JoyCodeProxy/reset_password.go
+++ b/cmd/JoyCode2Api/reset_password.go
@@ -6,8 +6,8 @@ import (
"fmt"
"github.com/spf13/cobra"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/auth"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/store"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/auth"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/store"
)
var resetPasswordCmd = &cobra.Command{
diff --git a/cmd/JoyCodeProxy/root.go b/cmd/JoyCode2Api/root.go
similarity index 96%
rename from cmd/JoyCodeProxy/root.go
rename to cmd/JoyCode2Api/root.go
index 28a8fc3..40aaea9 100644
--- a/cmd/JoyCodeProxy/root.go
+++ b/cmd/JoyCode2Api/root.go
@@ -5,8 +5,8 @@ import (
"log"
"github.com/spf13/cobra"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/auth"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/joycode"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/auth"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/joycode"
)
var (
diff --git a/cmd/JoyCodeProxy/search.go b/cmd/JoyCode2Api/search.go
similarity index 100%
rename from cmd/JoyCodeProxy/search.go
rename to cmd/JoyCode2Api/search.go
diff --git a/cmd/JoyCodeProxy/serve.go b/cmd/JoyCode2Api/serve.go
similarity index 96%
rename from cmd/JoyCodeProxy/serve.go
rename to cmd/JoyCode2Api/serve.go
index 513c70b..d45f043 100644
--- a/cmd/JoyCodeProxy/serve.go
+++ b/cmd/JoyCode2Api/serve.go
@@ -21,15 +21,15 @@ import (
"time"
"github.com/spf13/cobra"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/anthropic"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/auth"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/dashboard"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/joycode"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/keepalive"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/logrot"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/openai"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/proxy"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/store"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/anthropic"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/auth"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/dashboard"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/joycode"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/keepalive"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/logrot"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/openai"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/proxy"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/store"
)
var (
diff --git a/cmd/JoyCodeProxy/service.go b/cmd/JoyCode2Api/service.go
similarity index 100%
rename from cmd/JoyCodeProxy/service.go
rename to cmd/JoyCode2Api/service.go
diff --git a/cmd/JoyCodeProxy/service_darwin.go b/cmd/JoyCode2Api/service_darwin.go
similarity index 100%
rename from cmd/JoyCodeProxy/service_darwin.go
rename to cmd/JoyCode2Api/service_darwin.go
diff --git a/cmd/JoyCodeProxy/service_linux.go b/cmd/JoyCode2Api/service_linux.go
similarity index 100%
rename from cmd/JoyCodeProxy/service_linux.go
rename to cmd/JoyCode2Api/service_linux.go
diff --git a/cmd/JoyCodeProxy/static/assets/AccountDetail-C8Op2jDh.js b/cmd/JoyCode2Api/static/assets/AccountDetail-CKlxfyqh.js
similarity index 99%
rename from cmd/JoyCodeProxy/static/assets/AccountDetail-C8Op2jDh.js
rename to cmd/JoyCode2Api/static/assets/AccountDetail-CKlxfyqh.js
index 9ac787e..8f3765e 100644
--- a/cmd/JoyCodeProxy/static/assets/AccountDetail-C8Op2jDh.js
+++ b/cmd/JoyCode2Api/static/assets/AccountDetail-CKlxfyqh.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-Dlk94Fmh.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-DvS7W_Go.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-DLaCRU82.js b/cmd/JoyCode2Api/static/assets/Accounts-TPawoPaO.js
similarity index 99%
rename from cmd/JoyCodeProxy/static/assets/Accounts-DLaCRU82.js
rename to cmd/JoyCode2Api/static/assets/Accounts-TPawoPaO.js
index f36d568..5c82bea 100644
--- a/cmd/JoyCodeProxy/static/assets/Accounts-DLaCRU82.js
+++ b/cmd/JoyCode2Api/static/assets/Accounts-TPawoPaO.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-Dlk94Fmh.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 L(e){return`nodeType`in e}function R(e){return e?I(e)?e:L(e)?e.ownerDocument?.defaultView??window:window:window}function z(e){let{Document:t}=R(e);return e instanceof t}function B(e){return I(e)?!1:e instanceof R(e).HTMLElement}function V(e){return e instanceof R(e).SVGElement}function H(e){return e?I(e)?e.document:L(e)?z(e)?e:B(e)||V(e)?e.ownerDocument:document:document:document}var U=se?P.useLayoutEffect:P.useEffect;function ce(e){let t=(0,P.useRef)(e);return U(()=>{t.current=e}),(0,P.useCallback)(function(){var e=[...arguments];return t.current==null?void 0:t.current(...e)},[])}function le(){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 ue(e,t){t===void 0&&(t=[e]);let n=(0,P.useRef)(e);return U(()=>{n.current!==e&&(n.current=e)},t),n}function W(e,t){let n=(0,P.useRef)();return(0,P.useMemo)(()=>{let t=e(n.current);return n.current=t,t},[...t])}function de(e){let t=ce(e),n=(0,P.useRef)(null);return[n,(0,P.useCallback)(e=>{e!==n.current&&t?.(e,n.current),n.current=e},[])]}function fe(e){let t=(0,P.useRef)();return(0,P.useEffect)(()=>{t.current=e},[e]),t.current}var pe={};function me(e,t){return(0,P.useMemo)(()=>{if(t)return t;let n=pe[e]==null?0:pe[e]+1;return pe[e]=n,e+`-`+n},[e,t])}function he(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 ge=he(1),_e=he(-1);function ve(e){return`clientX`in e&&`clientY`in e}function G(e){if(!e)return!1;let{KeyboardEvent:t}=R(e.target);return t&&e instanceof t}function ye(e){if(!e)return!1;let{TouchEvent:t}=R(e.target);return t&&e instanceof t}function be(e){if(ye(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 ve(e)?{x:e.clientX,y:e.clientY}:null}var K=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[K.Translate.toString(e),K.Scale.toString(e)].join(` `)}},Transition:{toString(e){let{property:t,duration:n,easing:r}=e;return t+` `+n+`ms `+r}}}),q=`a,frame,iframe,input:not([type=hidden]):not(:disabled),select:not(:disabled),textarea:not(:disabled),button:not(:disabled),*[tabindex]`;function xe(e){return e.matches(q)?e:e.querySelector(q)}var Se={display:`none`};function J(e){let{id:t,value:n}=e;return P.createElement(`div`,{id:t,style:Se},n)}function Ce(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-DvS7W_Go.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 L(e){return`nodeType`in e}function R(e){return e?I(e)?e:L(e)?e.ownerDocument?.defaultView??window:window:window}function z(e){let{Document:t}=R(e);return e instanceof t}function B(e){return I(e)?!1:e instanceof R(e).HTMLElement}function V(e){return e instanceof R(e).SVGElement}function H(e){return e?I(e)?e.document:L(e)?z(e)?e:B(e)||V(e)?e.ownerDocument:document:document:document}var U=se?P.useLayoutEffect:P.useEffect;function ce(e){let t=(0,P.useRef)(e);return U(()=>{t.current=e}),(0,P.useCallback)(function(){var e=[...arguments];return t.current==null?void 0:t.current(...e)},[])}function le(){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 ue(e,t){t===void 0&&(t=[e]);let n=(0,P.useRef)(e);return U(()=>{n.current!==e&&(n.current=e)},t),n}function W(e,t){let n=(0,P.useRef)();return(0,P.useMemo)(()=>{let t=e(n.current);return n.current=t,t},[...t])}function de(e){let t=ce(e),n=(0,P.useRef)(null);return[n,(0,P.useCallback)(e=>{e!==n.current&&t?.(e,n.current),n.current=e},[])]}function fe(e){let t=(0,P.useRef)();return(0,P.useEffect)(()=>{t.current=e},[e]),t.current}var pe={};function me(e,t){return(0,P.useMemo)(()=>{if(t)return t;let n=pe[e]==null?0:pe[e]+1;return pe[e]=n,e+`-`+n},[e,t])}function he(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 ge=he(1),_e=he(-1);function ve(e){return`clientX`in e&&`clientY`in e}function G(e){if(!e)return!1;let{KeyboardEvent:t}=R(e.target);return t&&e instanceof t}function ye(e){if(!e)return!1;let{TouchEvent:t}=R(e.target);return t&&e instanceof t}function be(e){if(ye(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 ve(e)?{x:e.clientX,y:e.clientY}:null}var K=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[K.Translate.toString(e),K.Scale.toString(e)].join(` `)}},Transition:{toString(e){let{property:t,duration:n,easing:r}=e;return t+` `+n+`ms `+r}}}),q=`a,frame,iframe,input:not([type=hidden]):not(:disabled),select:not(:disabled),textarea:not(:disabled),button:not(:disabled),*[tabindex]`;function xe(e){return e.matches(q)?e:e.querySelector(q)}var Se={display:`none`};function J(e){let{id:t,value:n}=e;return P.createElement(`div`,{id:t,style:Se},n)}function Ce(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/CommandTooltip-Cw9Jxov1.js b/cmd/JoyCode2Api/static/assets/CommandTooltip-Cw9Jxov1.js
similarity index 100%
rename from cmd/JoyCodeProxy/static/assets/CommandTooltip-Cw9Jxov1.js
rename to cmd/JoyCode2Api/static/assets/CommandTooltip-Cw9Jxov1.js
diff --git a/cmd/JoyCodeProxy/static/assets/Dashboard-BE0h6Vkl.js b/cmd/JoyCode2Api/static/assets/Dashboard-C-E-xot8.js
similarity index 99%
rename from cmd/JoyCodeProxy/static/assets/Dashboard-BE0h6Vkl.js
rename to cmd/JoyCode2Api/static/assets/Dashboard-C-E-xot8.js
index c81289f..56dd30c 100644
--- a/cmd/JoyCodeProxy/static/assets/Dashboard-BE0h6Vkl.js
+++ b/cmd/JoyCode2Api/static/assets/Dashboard-C-E-xot8.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-Dlk94Fmh.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-DvS7W_Go.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-BGbLU_nd.js b/cmd/JoyCode2Api/static/assets/Settings-CMvCPBeH.js
similarity index 99%
rename from cmd/JoyCodeProxy/static/assets/Settings-BGbLU_nd.js
rename to cmd/JoyCode2Api/static/assets/Settings-CMvCPBeH.js
index 2bca134..9d53fa4 100644
--- a/cmd/JoyCodeProxy/static/assets/Settings-BGbLU_nd.js
+++ b/cmd/JoyCode2Api/static/assets/Settings-CMvCPBeH.js
@@ -1 +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-Dlk94Fmh.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(),t=[];for(let e of M)for(let n of e.fields)n.type===`switch`&&t.push(n.key);let n={...e};for(let r of t)n[r]=e[r]!==`false`;F.setFieldsValue(n)}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,t==null?``: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
+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-DvS7W_Go.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(),t=[];for(let e of M)for(let n of e.fields)n.type===`switch`&&t.push(n.key);let n={...e};for(let r of t)n[r]=e[r]!==`false`;F.setFieldsValue(n)}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,t==null?``: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/antd-BIDKISxA.js b/cmd/JoyCode2Api/static/assets/antd-BIDKISxA.js
similarity index 100%
rename from cmd/JoyCodeProxy/static/assets/antd-BIDKISxA.js
rename to cmd/JoyCode2Api/static/assets/antd-BIDKISxA.js
diff --git a/cmd/JoyCodeProxy/static/assets/index-Ca5oEz-R.css b/cmd/JoyCode2Api/static/assets/index-Ca5oEz-R.css
similarity index 100%
rename from cmd/JoyCodeProxy/static/assets/index-Ca5oEz-R.css
rename to cmd/JoyCode2Api/static/assets/index-Ca5oEz-R.css
diff --git a/cmd/JoyCode2Api/static/assets/index-DvS7W_Go.js b/cmd/JoyCode2Api/static/assets/index-DvS7W_Go.js
new file mode 100644
index 0000000..fc8d5cc
--- /dev/null
+++ b/cmd/JoyCode2Api/static/assets/index-DvS7W_Go.js
@@ -0,0 +1,2 @@
+const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/Dashboard-C-E-xot8.js","assets/rolldown-runtime-S-ySWqyJ.js","assets/vendor-C3SDdTD0.js","assets/antd-BIDKISxA.js","assets/recharts-abRO4Y-P.js","assets/Accounts-TPawoPaO.js","assets/CommandTooltip-Cw9Jxov1.js","assets/AccountDetail-CKlxfyqh.js","assets/Settings-CMvCPBeH.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/JoyCode2Api`,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/JoyCode2Api`,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)(`./JoyCode2Api`);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-C-E-xot8.js`),__vite__mapDeps([0,1,2,3,4]))),Fe=(0,P.lazy)(()=>k(()=>import(`./Accounts-TPawoPaO.js`),__vite__mapDeps([5,1,2,3,6]))),Ie=(0,P.lazy)(()=>k(()=>import(`./AccountDetail-CKlxfyqh.js`),__vite__mapDeps([7,1,2,3,4,6]))),Le=(0,P.lazy)(()=>k(()=>import(`./Settings-CMvCPBeH.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/assets/recharts-abRO4Y-P.js b/cmd/JoyCode2Api/static/assets/recharts-abRO4Y-P.js
similarity index 100%
rename from cmd/JoyCodeProxy/static/assets/recharts-abRO4Y-P.js
rename to cmd/JoyCode2Api/static/assets/recharts-abRO4Y-P.js
diff --git a/cmd/JoyCodeProxy/static/assets/rolldown-runtime-S-ySWqyJ.js b/cmd/JoyCode2Api/static/assets/rolldown-runtime-S-ySWqyJ.js
similarity index 100%
rename from cmd/JoyCodeProxy/static/assets/rolldown-runtime-S-ySWqyJ.js
rename to cmd/JoyCode2Api/static/assets/rolldown-runtime-S-ySWqyJ.js
diff --git a/cmd/JoyCodeProxy/static/assets/vendor-C3SDdTD0.js b/cmd/JoyCode2Api/static/assets/vendor-C3SDdTD0.js
similarity index 100%
rename from cmd/JoyCodeProxy/static/assets/vendor-C3SDdTD0.js
rename to cmd/JoyCode2Api/static/assets/vendor-C3SDdTD0.js
diff --git a/cmd/JoyCodeProxy/static/favicon.ico b/cmd/JoyCode2Api/static/favicon.ico
similarity index 100%
rename from cmd/JoyCodeProxy/static/favicon.ico
rename to cmd/JoyCode2Api/static/favicon.ico
diff --git a/cmd/JoyCodeProxy/static/favicon.svg b/cmd/JoyCode2Api/static/favicon.svg
similarity index 100%
rename from cmd/JoyCodeProxy/static/favicon.svg
rename to cmd/JoyCode2Api/static/favicon.svg
diff --git a/cmd/JoyCodeProxy/static/index.html b/cmd/JoyCode2Api/static/index.html
similarity index 88%
rename from cmd/JoyCodeProxy/static/index.html
rename to cmd/JoyCode2Api/static/index.html
index 6b8c1a8..423c7bf 100644
--- a/cmd/JoyCodeProxy/static/index.html
+++ b/cmd/JoyCode2Api/static/index.html
@@ -5,7 +5,7 @@
JoyCode 代理
-
+
diff --git a/cmd/JoyCodeProxy/tls.go b/cmd/JoyCode2Api/tls.go
similarity index 100%
rename from cmd/JoyCodeProxy/tls.go
rename to cmd/JoyCode2Api/tls.go
diff --git a/cmd/JoyCodeProxy/version.go b/cmd/JoyCode2Api/version.go
similarity index 89%
rename from cmd/JoyCodeProxy/version.go
rename to cmd/JoyCode2Api/version.go
index 93dc994..48c9eb3 100644
--- a/cmd/JoyCodeProxy/version.go
+++ b/cmd/JoyCode2Api/version.go
@@ -5,7 +5,7 @@ import (
"runtime"
"github.com/spf13/cobra"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/joycode"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/joycode"
)
var Version = "0.5.0"
diff --git a/cmd/JoyCodeProxy/whoami.go b/cmd/JoyCode2Api/whoami.go
similarity index 100%
rename from cmd/JoyCodeProxy/whoami.go
rename to cmd/JoyCode2Api/whoami.go
diff --git a/cmd/JoyCodeProxy/static/assets/index-Dlk94Fmh.js b/cmd/JoyCodeProxy/static/assets/index-Dlk94Fmh.js
deleted file mode 100644
index ac45f03..0000000
--- a/cmd/JoyCodeProxy/static/assets/index-Dlk94Fmh.js
+++ /dev/null
@@ -1,2 +0,0 @@
-const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/Dashboard-BE0h6Vkl.js","assets/rolldown-runtime-S-ySWqyJ.js","assets/vendor-C3SDdTD0.js","assets/antd-BIDKISxA.js","assets/recharts-abRO4Y-P.js","assets/Accounts-DLaCRU82.js","assets/CommandTooltip-Cw9Jxov1.js","assets/AccountDetail-C8Op2jDh.js","assets/Settings-BGbLU_nd.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-BE0h6Vkl.js`),__vite__mapDeps([0,1,2,3,4]))),Fe=(0,P.lazy)(()=>k(()=>import(`./Accounts-DLaCRU82.js`),__vite__mapDeps([5,1,2,3,6]))),Ie=(0,P.lazy)(()=>k(()=>import(`./AccountDetail-C8Op2jDh.js`),__vite__mapDeps([7,1,2,3,4,6]))),Le=(0,P.lazy)(()=>k(()=>import(`./Settings-BGbLU_nd.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/go.mod b/go.mod
index eea8f07..19a2238 100644
--- a/go.mod
+++ b/go.mod
@@ -1,4 +1,4 @@
-module github.com/vibe-coding-labs/JoyCodeProxy
+module github.com/vibe-coding-labs/JoyCode2Api
go 1.25.0
diff --git a/package-lock.json b/package-lock.json
index a25d438..0635d94 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,5 +1,5 @@
{
- "name": "JoyCodeProxy",
+ "name": "JoyCode2Api",
"lockfileVersion": 3,
"requires": true,
"packages": {}
diff --git a/pkg/anthropic/anthropic_test.go b/pkg/anthropic/anthropic_test.go
index 4bef57d..0018331 100644
--- a/pkg/anthropic/anthropic_test.go
+++ b/pkg/anthropic/anthropic_test.go
@@ -6,7 +6,7 @@ import (
"strings"
"testing"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/joycode"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/joycode"
)
func TestResolveModel(t *testing.T) {
diff --git a/pkg/anthropic/handler.go b/pkg/anthropic/handler.go
index 30afda5..5714c37 100644
--- a/pkg/anthropic/handler.go
+++ b/pkg/anthropic/handler.go
@@ -10,8 +10,8 @@ import (
"strings"
"time"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/joycode"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/store"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/joycode"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/store"
)
const chatEndpoint = "/api/saas/openai/v1/chat/completions"
diff --git a/pkg/anthropic/stream_truncation_test.go b/pkg/anthropic/stream_truncation_test.go
index a1d17ce..8493db3 100644
--- a/pkg/anthropic/stream_truncation_test.go
+++ b/pkg/anthropic/stream_truncation_test.go
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/joycode"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/joycode"
)
// Regression tests for issue #2 ("模型自动断开"): a stream that starts but ends
diff --git a/pkg/anthropic/translate.go b/pkg/anthropic/translate.go
index 4abc627..f068dbb 100644
--- a/pkg/anthropic/translate.go
+++ b/pkg/anthropic/translate.go
@@ -7,8 +7,8 @@ import (
"fmt"
"strings"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/joycode"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/store"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/joycode"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/store"
)
// TranslateRequest converts an Anthropic MessageRequest to a JoyCode API body.
diff --git a/pkg/anthropic/translate_extended_test.go b/pkg/anthropic/translate_extended_test.go
index ba49675..9cb9e09 100644
--- a/pkg/anthropic/translate_extended_test.go
+++ b/pkg/anthropic/translate_extended_test.go
@@ -6,7 +6,7 @@ import (
"strings"
"testing"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/joycode"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/joycode"
)
// ---------------------------------------------------------------------------
diff --git a/pkg/auth/jdlogin.go b/pkg/auth/jdlogin.go
index fe798f0..f7d56dd 100644
--- a/pkg/auth/jdlogin.go
+++ b/pkg/auth/jdlogin.go
@@ -13,7 +13,7 @@ import (
"sync"
"time"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/joycode"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/joycode"
)
func minInt(a, b int) int {
diff --git a/pkg/dashboard/handler.go b/pkg/dashboard/handler.go
index fc68f9e..48b75cc 100644
--- a/pkg/dashboard/handler.go
+++ b/pkg/dashboard/handler.go
@@ -21,11 +21,11 @@ import (
"time"
_ "github.com/mattn/go-sqlite3"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/auth"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/joycode"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/keepalive"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/proxy"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/store"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/auth"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/joycode"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/keepalive"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/proxy"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/store"
)
type Handler struct {
@@ -83,7 +83,7 @@ var (
)
const ghStarsCacheTTL = 1 * time.Hour
-const ghRepo = "vibe-coding-labs/JoyCodeProxy"
+const ghRepo = "vibe-coding-labs/JoyCode2Api"
func (h *Handler) handleGitHubStars(w http.ResponseWriter, r *http.Request) {
setCors(w)
@@ -205,7 +205,7 @@ func (h *Handler) ServeStatic(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusNotFound, map[string]interface{}{
"error": map[string]string{
"type": "invalid_request_error",
- "message": fmt.Sprintf("%s %s not found. JoyCodeProxy serves the API under /v1/. Set base_url to http://:/v1", r.Method, path),
+ "message": fmt.Sprintf("%s %s not found. JoyCode2Api serves the API under /v1/. Set base_url to http://:/v1", r.Method, path),
},
})
return
diff --git a/pkg/dashboard/handler_test.go b/pkg/dashboard/handler_test.go
index 95f004d..b1016eb 100644
--- a/pkg/dashboard/handler_test.go
+++ b/pkg/dashboard/handler_test.go
@@ -11,8 +11,8 @@ import (
"time"
"testing"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/keepalive"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/store"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/keepalive"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/store"
)
func setupTestHandler(t *testing.T) (*Handler, *store.Store) {
diff --git a/pkg/keepalive/keepalive.go b/pkg/keepalive/keepalive.go
index 46c4e56..2f3e4e5 100644
--- a/pkg/keepalive/keepalive.go
+++ b/pkg/keepalive/keepalive.go
@@ -6,8 +6,8 @@ import (
"sync"
"time"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/joycode"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/store"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/joycode"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/store"
)
// CredentialStatus represents the health of an account's credentials.
diff --git a/pkg/openai/chat.go b/pkg/openai/chat.go
index 01e2ea3..0908b30 100644
--- a/pkg/openai/chat.go
+++ b/pkg/openai/chat.go
@@ -7,8 +7,8 @@ import (
"net/http"
"strings"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/joycode"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/store"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/joycode"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/store"
)
func (s *Server) handleChat(w http.ResponseWriter, r *http.Request) {
diff --git a/pkg/openai/handler.go b/pkg/openai/handler.go
index 20245aa..a86abd4 100644
--- a/pkg/openai/handler.go
+++ b/pkg/openai/handler.go
@@ -5,8 +5,8 @@ import (
"log/slog"
"net/http"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/joycode"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/store"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/joycode"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/store"
)
// ClientResolver returns the appropriate joycode.Client for a request.
diff --git a/pkg/openai/handler_test.go b/pkg/openai/handler_test.go
index da390f8..1590e53 100644
--- a/pkg/openai/handler_test.go
+++ b/pkg/openai/handler_test.go
@@ -11,8 +11,8 @@ import (
"testing"
"time"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/joycode"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/store"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/joycode"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/store"
)
// --- Mock infrastructure ---
diff --git a/pkg/openai/translate.go b/pkg/openai/translate.go
index 8b4c3a0..56ab035 100644
--- a/pkg/openai/translate.go
+++ b/pkg/openai/translate.go
@@ -5,7 +5,7 @@ import (
"fmt"
"time"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/joycode"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/joycode"
)
// TranslateRequest converts an OpenAI ChatRequest to JoyCode API body.
diff --git a/pkg/openai/translate_test.go b/pkg/openai/translate_test.go
index 2632317..d61cb17 100644
--- a/pkg/openai/translate_test.go
+++ b/pkg/openai/translate_test.go
@@ -5,7 +5,7 @@ import (
"strings"
"testing"
- "github.com/vibe-coding-labs/JoyCodeProxy/pkg/joycode"
+ "github.com/vibe-coding-labs/JoyCode2Api/pkg/joycode"
)
// --- TranslateRequest tests ---
diff --git a/scripts/release.sh b/scripts/release.sh
index 568ec3d..c13c16b 100755
--- a/scripts/release.sh
+++ b/scripts/release.sh
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
-# ── JoyCodeProxy Release Script ──────────────────────────────────────
+# ── JoyCode2Api Release Script ──────────────────────────────────────
# Usage: ./scripts/release.sh
# Example: ./scripts/release.sh v0.3.0
#
@@ -20,8 +20,8 @@ set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
DIST_DIR="$ROOT_DIR/dist"
-VERSION_FILE="$ROOT_DIR/cmd/JoyCodeProxy/version.go"
-BINARY_NAME="JoyCodeProxy"
+VERSION_FILE="$ROOT_DIR/cmd/JoyCode2Api/version.go"
+BINARY_NAME="JoyCode2Api"
# ── Validate input ───────────────────────────────────────────────────
@@ -36,7 +36,7 @@ fi
VERSION_NUM="${VERSION#v}"
echo "=========================================="
-echo " JoyCodeProxy Release: $VERSION"
+echo " JoyCode2Api Release: $VERSION"
echo "=========================================="
# ── Step 1: Build frontend ───────────────────────────────────────────
@@ -47,7 +47,7 @@ cd "$ROOT_DIR/web"
npm install --silent
npm run build
-if [[ ! -f "$ROOT_DIR/cmd/JoyCodeProxy/static/index.html" ]]; then
+if [[ ! -f "$ROOT_DIR/cmd/JoyCode2Api/static/index.html" ]]; then
echo "ERROR: Frontend build failed - index.html not found"
exit 1
fi
@@ -84,7 +84,7 @@ cd "$ROOT_DIR"
CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 \
go build -trimpath -ldflags "-s -w" \
-o "$DIST_DIR/${BINARY_NAME}-darwin-arm64" \
- ./cmd/JoyCodeProxy/
+ ./cmd/JoyCode2Api/
echo " Built: ${BINARY_NAME}-darwin-arm64 ($(du -h "$DIST_DIR/${BINARY_NAME}-darwin-arm64" | cut -f1))"
@@ -111,10 +111,10 @@ COPY . .
ARG VERSION=dev
RUN CGO_ENABLED=1 go build -trimpath -ldflags "-s -w -X main.Version=${VERSION}" \
- -o /JoyCodeProxy ./cmd/JoyCodeProxy/
+ -o /JoyCode2Api ./cmd/JoyCode2Api/
FROM alpine:3.21
-COPY --from=builder /JoyCodeProxy /JoyCodeProxy
+COPY --from=builder /JoyCode2Api /JoyCode2Api
DOCKERFILE
docker build --platform linux/amd64 \
@@ -125,7 +125,7 @@ docker build --platform linux/amd64 \
# Extract binary from Docker image
CONTAINER_ID=$(docker create "joycode-build:$VERSION_NUM")
-docker cp "$CONTAINER_ID:/JoyCodeProxy" "$DIST_DIR/${BINARY_NAME}-linux-amd64"
+docker cp "$CONTAINER_ID:/JoyCode2Api" "$DIST_DIR/${BINARY_NAME}-linux-amd64"
docker rm "$CONTAINER_ID" > /dev/null
# Clean up
@@ -142,7 +142,7 @@ echo ""
echo "[6/6] Creating GitHub Release..."
# Commit version change
-git add "$VERSION_FILE" "$ROOT_DIR/Dockerfile" "$ROOT_DIR/cmd/JoyCodeProxy/static/"
+git add "$VERSION_FILE" "$ROOT_DIR/Dockerfile" "$ROOT_DIR/cmd/JoyCode2Api/static/"
git commit -m "release: $VERSION" || echo " Nothing new to commit"
# Create git tag
@@ -162,22 +162,22 @@ gh release create "$VERSION" \
"$DIST_DIR/${BINARY_NAME}-darwin-arm64" \
"$DIST_DIR/${BINARY_NAME}-linux-amd64" \
"$DIST_DIR/checksums-sha256.txt" \
- --title "JoyCodeProxy $VERSION" \
- --notes "## JoyCodeProxy $VERSION
+ --title "JoyCode2Api $VERSION" \
+ --notes "## JoyCode2Api $VERSION
### Downloads
-- \`JoyCodeProxy-darwin-arm64\` — macOS (Apple Silicon)
-- \`JoyCodeProxy-linux-amd64\` — Linux (x86_64)
+- \`JoyCode2Api-darwin-arm64\` — macOS (Apple Silicon)
+- \`JoyCode2Api-linux-amd64\` — Linux (x86_64)
### Quick Start
\`\`\`bash
# macOS
-chmod +x JoyCodeProxy-darwin-arm64
-./JoyCodeProxy-darwin-arm64 serve
+chmod +x JoyCode2Api-darwin-arm64
+./JoyCode2Api-darwin-arm64 serve
# Linux
-chmod +x JoyCodeProxy-linux-amd64
-./JoyCodeProxy-linux-amd64 serve
+chmod +x JoyCode2Api-linux-amd64
+./JoyCode2Api-linux-amd64 serve
\`\`\`
### Verify checksum
diff --git a/web/src/layouts/MainLayout.tsx b/web/src/layouts/MainLayout.tsx
index c3e90ed..5626b69 100644
--- a/web/src/layouts/MainLayout.tsx
+++ b/web/src/layouts/MainLayout.tsx
@@ -102,7 +102,7 @@ const MainLayout: React.FC = () => {
{
- const [exePath, setExePath] = useState('./joycode_proxy_bin');
+ const [exePath, setExePath] = useState('./JoyCode2Api');
useEffect(() => {
authApi.status().then((res) => {
diff --git a/web/src/pages/Login.tsx b/web/src/pages/Login.tsx
index 97067f7..134fbe8 100644
--- a/web/src/pages/Login.tsx
+++ b/web/src/pages/Login.tsx
@@ -40,7 +40,7 @@ const LoginPage: React.FC = () => {
}}>