waygate-open 1.6.14 → 1.6.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/README.md +3 -3
  2. package/package.json +1 -1
  3. package/server/dist/api/overview.service.js +9 -0
  4. package/server/dist/proxy/quota/quota-parse.js +9 -4
  5. package/server/dist/version.js +1 -1
  6. package/server/package.json +1 -1
  7. package/web/dist/assets/{ApiKeysPage-LOAdUyHT.js → ApiKeysPage-Ck0Gry6E.js} +3 -3
  8. package/web/dist/assets/{ClientMetricTip-D-pXFJpS.js → ClientMetricTip-C2VuiT4-.js} +1 -1
  9. package/web/dist/assets/ClientsPage-Dy68uQDl.js +1 -0
  10. package/web/dist/assets/LandingPage-B2hMgbmZ.css +1 -0
  11. package/web/dist/assets/LandingPage-P2QNDFaP.js +15 -0
  12. package/web/dist/assets/OverviewPage-BgBo_XhF.js +1 -0
  13. package/web/dist/assets/RequestsPage-CVB0wpCH.js +5 -0
  14. package/web/dist/assets/{Select-BxZGnteq.js → Select-G6AhT0TA.js} +1 -1
  15. package/web/dist/assets/SettingsPage-B4Mew-7b.js +5 -0
  16. package/web/dist/assets/UsagePage-cxZ-GnpO.js +1 -0
  17. package/web/dist/assets/index-CEoe20BF.css +1 -0
  18. package/web/dist/assets/index-nQeRK3kW.js +2 -0
  19. package/web/dist/assets/sharedWindow-FDfq75PI.js +1 -0
  20. package/web/dist/index.html +2 -2
  21. package/web/dist/assets/ClientsPage-D3z8xy1H.js +0 -1
  22. package/web/dist/assets/LandingPage-BXVLs2Ni.js +0 -15
  23. package/web/dist/assets/LandingPage-DIP_XFhP.css +0 -1
  24. package/web/dist/assets/OverviewPage-xTsnlyEP.js +0 -1
  25. package/web/dist/assets/RequestsPage-B2ThbdoO.js +0 -5
  26. package/web/dist/assets/SettingsPage-CfuPWZ4_.js +0 -3
  27. package/web/dist/assets/UsagePage-UatftkHb.js +0 -1
  28. package/web/dist/assets/index-BtuqaoxX.css +0 -1
  29. package/web/dist/assets/index-VH6Gc3-s.js +0 -2
@@ -1 +1 @@
1
- import{J as e,S as t,it as n,k as r,m as i,q as a,r as o,rt as s,tt as c}from"./vendor-befEYGHM.js";import{i as l}from"./index-VH6Gc3-s.js";var u=c();function d({tone:e=`ghost`,dot:t=!1,children:n}){return(0,u.jsxs)(`span`,{className:`pill pill-${e}`,children:[t?(0,u.jsx)(`span`,{className:`dot dot-live`}):null,n]})}function f({tone:e=`off`,children:t}){return(0,u.jsx)(`span`,{className:`tag tag-${e}`,children:t})}function p({title:e,status:t,actions:n}){return(0,u.jsxs)(`div`,{className:`topbar`,children:[(0,u.jsxs)(`div`,{className:`topbar-left`,children:[(0,u.jsx)(`h1`,{children:e}),t]}),n?(0,u.jsx)(`div`,{className:`topbar-right`,children:n}):null]})}function m({title:e,aside:t,children:n,className:r=``,padded:i=!0}){return(0,u.jsxs)(`div`,{className:`card${i?` panel`:``} ${r}`.trim(),children:[e?(0,u.jsxs)(`div`,{className:`panel-head`,style:i?void 0:{padding:`18px 20px 0`,marginBottom:12},children:[(0,u.jsx)(`h3`,{children:e}),t]}):null,n]})}function h({items:e}){return(0,u.jsx)(`div`,{className:`statbar`,"data-count":e.length,children:e.map(e=>(0,u.jsxs)(`div`,{children:[(0,u.jsxs)(`div`,{className:`sb-top`,children:[(0,u.jsx)(`span`,{className:`lb`,children:e.label}),e.detail?(0,u.jsx)(`span`,{className:`sdl`,children:e.detail}):null]}),e.tip?(0,u.jsx)(l,{content:e.tip,placement:e.tipPos===`down`?`below`:`auto`,className:`tooltip-value-anchor`,children:(0,u.jsx)(`div`,{className:`vl`,style:e.tone===`live`?{color:`var(--signal-live)`}:e.tone===`amber`?{color:`var(--warn-amber)`}:void 0,children:e.value})}):(0,u.jsx)(`div`,{className:`vl`,style:e.tone===`live`?{color:`var(--signal-live)`}:e.tone===`amber`?{color:`var(--warn-amber)`}:void 0,children:e.value})]},e.label))})}function g({label:e,value:t,detail:n,tone:r,icon:i,tip:a,tipPos:o}){let s=r===`cyan`||r===`violet`||r===`green`||r===`amber`||r===`blue`||r===`rose`?` m-${r}`:``;return(0,u.jsxs)(`div`,{className:`card metric`,children:[(0,u.jsxs)(`div`,{className:`m-top`,children:[i?(0,u.jsx)(`span`,{className:`m-ico${s}`,"aria-hidden":`true`,children:i}):null,(0,u.jsx)(`span`,{className:`lb`,children:e})]}),a?(0,u.jsx)(l,{content:a,placement:o===`down`?`below`:`auto`,className:`tooltip-value-anchor`,children:(0,u.jsx)(`div`,{className:`vl`,children:t})}):(0,u.jsx)(`div`,{className:`vl`,children:t}),n?(0,u.jsx)(`div`,{className:`dl${r===`up`?` up`:r===`warn`?` warn`:``}`,children:n}):null]})}function _({kind:e,title:n,detail:a,onRetry:s,children:c}){return e===`loading`?(0,u.jsxs)(`div`,{className:`state-block`,role:`status`,"aria-live":`polite`,"aria-busy":`true`,children:[(0,u.jsx)(t,{size:22,className:`spin`,style:{animation:`spin 1s linear infinite`}}),(0,u.jsx)(`div`,{className:`t`,children:n??`加载中…`})]}):e===`empty`?(0,u.jsxs)(`div`,{className:`state-block`,role:`status`,"aria-live":`polite`,children:[(0,u.jsx)(r,{size:26}),(0,u.jsx)(`div`,{className:`t`,children:n??`暂无数据`}),a?(0,u.jsx)(`div`,{className:`d`,children:a}):null,c]}):(0,u.jsxs)(`div`,{className:`state-block`,role:`alert`,"aria-live":`assertive`,children:[(0,u.jsx)(o,{size:26}),(0,u.jsx)(`div`,{className:`t`,children:n??`加载失败`}),a?(0,u.jsx)(`div`,{className:`d`,children:a}):null,s?(0,u.jsxs)(`button`,{type:`button`,className:`btn btn-quiet btn-sm`,onClick:s,children:[(0,u.jsx)(i,{size:14}),`重试`]}):null]})}function v(e){if(!e)return``;let t={40001:`有字段没通过校验,回退一步检查刚填的内容。`,40002:`确认文字不匹配 —— 这是刻意设计的门槛。`,40101:`管理口令不正确,注意区分大小写。`,40102:`会话已过期,登录后继续。`,40290:`登录失败次数过多,请 ${e.retryAfterSeconds?Math.ceil(e.retryAfterSeconds/60):10} 分钟后重试。`,40301:`请求来源校验失败(CSRF 防护),刷新页面重试。`,40401:`这条记录已不存在,可能刚被删掉了。`,40901:`同名密钥已存在,换一个名字。`,50001:`服务端未分类异常,可稍后重试或查看服务日志。`,50301:`数据库暂时不可用,确认后端进程是否在运行。`};return(e.code===40001||e.code===50001)&&/[\u4e00-\u9fa5]/.test(e.message)?e.message:t[e.code]?t[e.code]:e.status===0?e.message:e.message||`请求失败(HTTP ${e.status})`}var y=n(),b=s();function x({value:t,options:n,onChange:r,width:i,disabled:o,size:s=`md`,ariaLabel:c}){let[l,d]=(0,y.useState)(!1),[f,p]=(0,y.useState)(0),[m,h]=(0,y.useState)(null),[g,_]=(0,y.useState)(!1),v=(0,y.useRef)(null),x=(0,y.useRef)(null),S=(0,y.useRef)({buf:``,at:0}),C=(0,y.useId)(),w=`${C}list`,T=e=>`${C}opt${e}`,E=Math.max(0,n.findIndex(e=>e.value===t)),D=(0,y.useCallback)(()=>{let e=v.current;if(!e)return;let t=e.getBoundingClientRect();h({left:t.left,top:t.top,bottom:t.bottom,width:t.width})},[]),O=(0,y.useCallback)(()=>{o||n.length===0||(S.current={buf:``,at:0},p(E),D(),d(!0))},[o,D,n.length,E]),k=(0,y.useCallback)(e=>{let t=n[e];t&&r(t.value),d(!1),v.current?.focus()},[r,n]);(0,y.useLayoutEffect)(()=>{l&&x.current?.focus()},[l]),(0,y.useLayoutEffect)(()=>{if(!l||!m)return;let e=x.current;if(!e)return;let t=window.innerHeight-m.bottom;_(t<e.offsetHeight+12&&m.top>t)},[l,m,n.length]),(0,y.useEffect)(()=>{l&&x.current?.querySelector(`[data-opt="${f}"]`)?.scrollIntoView({block:`nearest`})},[f,l]),(0,y.useEffect)(()=>{if(!l)return;let e=()=>D(),t=e=>{let t=e.target;t&&(v.current?.contains(t)||x.current?.contains(t))||d(!1)};return window.addEventListener(`scroll`,e,!0),window.addEventListener(`resize`,e),document.addEventListener(`pointerdown`,t,!0),()=>{window.removeEventListener(`scroll`,e,!0),window.removeEventListener(`resize`,e),document.removeEventListener(`pointerdown`,t,!0)}},[l,D]);let A=(0,y.useCallback)((e,t)=>{let r=Date.now(),i=(r-S.current.at>700?``:S.current.buf)+e;S.current={buf:i,at:r};let a=i.toLowerCase(),o=n.length,s=i.length===1?(t+1)%o:0;for(let e=0;e<o;e+=1){let t=(s+e)%o;if(n[t].label.toLowerCase().startsWith(a)){p(t);return}}},[n]),j=e=>e.key.length===1&&!e.ctrlKey&&!e.metaKey&&!e.altKey&&/\S/.test(e.key),M=e=>{if(!(o||l)){if(e.key===`ArrowDown`||e.key===`ArrowUp`||e.key===`Enter`||e.key===` `){e.preventDefault(),O();return}j(e)&&(e.preventDefault(),O(),A(e.key,E))}},N=e=>{let t=n.length;switch(e.key){case`ArrowDown`:e.preventDefault(),p(e=>(e+1)%t);break;case`ArrowUp`:e.preventDefault(),p(e=>(e-1+t)%t);break;case`Home`:e.preventDefault(),p(0);break;case`End`:e.preventDefault(),p(t-1);break;case`Enter`:case` `:e.preventDefault(),k(f);break;case`Escape`:e.preventDefault(),e.stopPropagation(),d(!1),v.current?.focus();break;case`Tab`:d(!1),v.current?.focus();break;default:j(e)&&A(e.key,f)}},P=n[E]?.label??``;return(0,u.jsxs)(`div`,{className:`sel-field`,style:i?{width:i}:void 0,children:[(0,u.jsxs)(`button`,{type:`button`,ref:v,className:s===`sm`?`sel sm`:`sel`,"aria-haspopup":`listbox`,"aria-expanded":l,"aria-controls":l?w:void 0,"aria-label":c,"data-value":t,disabled:o,onClick:()=>l?d(!1):O(),onKeyDown:M,children:[(0,u.jsx)(`span`,{className:`sel-val`,children:P}),(0,u.jsx)(a,{size:s===`sm`?12:13,className:`ic caret-glyph`,"aria-hidden":!0})]}),l&&m?(0,b.createPortal)((0,u.jsx)(`div`,{ref:x,id:w,role:`listbox`,tabIndex:-1,"aria-activedescendant":n.length?T(f):void 0,className:s===`sm`?`sel-pop sm`:`sel-pop`,onKeyDown:N,style:{left:Math.max(8,Math.min(m.left,window.innerWidth-Math.max(m.width,168)-8)),top:g?void 0:m.bottom+6,bottom:g?window.innerHeight-m.top+6:void 0,minWidth:m.width},children:n.map((n,r)=>(0,u.jsxs)(`div`,{id:T(r),"data-opt":r,"data-value":n.value,role:`option`,"aria-selected":n.value===t,className:`sel-opt${r===f?` on`:``}${n.value===t?` picked`:``}`,onMouseEnter:()=>p(r),onPointerDown:e=>e.preventDefault(),onClick:()=>k(r),children:[(0,u.jsx)(`span`,{className:`sel-opt-lb`,children:n.label}),n.value===t?(0,u.jsx)(e,{size:13,className:`ic`,"aria-hidden":!0}):null]},n.value))}),document.body):null]})}export{m as a,d as c,g as i,f as l,_ as n,h as o,v as r,p as s,x as t};
1
+ import{J as e,S as t,it as n,k as r,m as i,q as a,r as o,rt as s,tt as c}from"./vendor-befEYGHM.js";import{a as l}from"./index-nQeRK3kW.js";var u=c();function d({tone:e=`ghost`,dot:t=!1,children:n}){return(0,u.jsxs)(`span`,{className:`pill pill-${e}`,children:[t?(0,u.jsx)(`span`,{className:`dot dot-live`}):null,n]})}function f({tone:e=`off`,children:t}){return(0,u.jsx)(`span`,{className:`tag tag-${e}`,children:t})}function p({title:e,status:t,actions:n}){return(0,u.jsxs)(`div`,{className:`topbar`,children:[(0,u.jsxs)(`div`,{className:`topbar-left`,children:[(0,u.jsx)(`h1`,{children:e}),t]}),n?(0,u.jsx)(`div`,{className:`topbar-right`,children:n}):null]})}function m({title:e,aside:t,children:n,className:r=``,padded:i=!0}){return(0,u.jsxs)(`div`,{className:`card${i?` panel`:``} ${r}`.trim(),children:[e?(0,u.jsxs)(`div`,{className:`panel-head`,style:i?void 0:{padding:`18px 20px 0`,marginBottom:12},children:[(0,u.jsx)(`h3`,{children:e}),t]}):null,n]})}function h({items:e}){return(0,u.jsx)(`div`,{className:`statbar`,"data-count":e.length,children:e.map(e=>(0,u.jsxs)(`div`,{children:[(0,u.jsxs)(`div`,{className:`sb-top`,children:[(0,u.jsx)(`span`,{className:`lb`,children:e.label}),e.detail?(0,u.jsx)(`span`,{className:`sdl`,children:e.detail}):null]}),e.tip?(0,u.jsx)(l,{content:e.tip,placement:e.tipPos===`down`?`below`:`auto`,className:`tooltip-value-anchor`,children:(0,u.jsx)(`div`,{className:`vl`,style:e.tone===`live`?{color:`var(--signal-live)`}:e.tone===`amber`?{color:`var(--warn-amber)`}:void 0,children:e.value})}):(0,u.jsx)(`div`,{className:`vl`,style:e.tone===`live`?{color:`var(--signal-live)`}:e.tone===`amber`?{color:`var(--warn-amber)`}:void 0,children:e.value})]},e.label))})}function g({label:e,value:t,detail:n,tone:r,icon:i,tip:a,tipPos:o}){let s=r===`cyan`||r===`violet`||r===`green`||r===`amber`||r===`blue`||r===`rose`?` m-${r}`:``;return(0,u.jsxs)(`div`,{className:`card metric`,children:[(0,u.jsxs)(`div`,{className:`m-top`,children:[i?(0,u.jsx)(`span`,{className:`m-ico${s}`,"aria-hidden":`true`,children:i}):null,(0,u.jsx)(`span`,{className:`lb`,children:e})]}),a?(0,u.jsx)(l,{content:a,placement:o===`down`?`below`:`auto`,className:`tooltip-value-anchor`,children:(0,u.jsx)(`div`,{className:`vl`,children:t})}):(0,u.jsx)(`div`,{className:`vl`,children:t}),n?(0,u.jsx)(`div`,{className:`dl${r===`up`?` up`:r===`warn`?` warn`:``}`,children:n}):null]})}function _({kind:e,title:n,detail:a,onRetry:s,children:c}){return e===`loading`?(0,u.jsxs)(`div`,{className:`state-block`,role:`status`,"aria-live":`polite`,"aria-busy":`true`,children:[(0,u.jsx)(t,{size:22,className:`spin`,style:{animation:`spin 1s linear infinite`}}),(0,u.jsx)(`div`,{className:`t`,children:n??`加载中…`})]}):e===`empty`?(0,u.jsxs)(`div`,{className:`state-block`,role:`status`,"aria-live":`polite`,children:[(0,u.jsx)(r,{size:26}),(0,u.jsx)(`div`,{className:`t`,children:n??`暂无数据`}),a?(0,u.jsx)(`div`,{className:`d`,children:a}):null,c]}):(0,u.jsxs)(`div`,{className:`state-block`,role:`alert`,"aria-live":`assertive`,children:[(0,u.jsx)(o,{size:26}),(0,u.jsx)(`div`,{className:`t`,children:n??`加载失败`}),a?(0,u.jsx)(`div`,{className:`d`,children:a}):null,s?(0,u.jsxs)(`button`,{type:`button`,className:`btn btn-quiet btn-sm`,onClick:s,children:[(0,u.jsx)(i,{size:14}),`重试`]}):null]})}function v(e){if(!e)return``;let t={40001:`有字段没通过校验,回退一步检查刚填的内容。`,40002:`确认文字不匹配 —— 这是刻意设计的门槛。`,40101:`管理口令不正确,注意区分大小写。`,40102:`会话已过期,登录后继续。`,40290:`登录失败次数过多,请 ${e.retryAfterSeconds?Math.ceil(e.retryAfterSeconds/60):10} 分钟后重试。`,40301:`请求来源校验失败(CSRF 防护),刷新页面重试。`,40401:`这条记录已不存在,可能刚被删掉了。`,40901:`同名密钥已存在,换一个名字。`,50001:`服务端未分类异常,可稍后重试或查看服务日志。`,50301:`数据库暂时不可用,确认后端进程是否在运行。`};return(e.code===40001||e.code===50001)&&/[\u4e00-\u9fa5]/.test(e.message)?e.message:t[e.code]?t[e.code]:e.status===0?e.message:e.message||`请求失败(HTTP ${e.status})`}var y=n(),b=s();function x({value:t,options:n,onChange:r,width:i,disabled:o,size:s=`md`,ariaLabel:c}){let[l,d]=(0,y.useState)(!1),[f,p]=(0,y.useState)(0),[m,h]=(0,y.useState)(null),[g,_]=(0,y.useState)(!1),v=(0,y.useRef)(null),x=(0,y.useRef)(null),S=(0,y.useRef)({buf:``,at:0}),C=(0,y.useId)(),w=`${C}list`,T=e=>`${C}opt${e}`,E=Math.max(0,n.findIndex(e=>e.value===t)),D=(0,y.useCallback)(()=>{let e=v.current;if(!e)return;let t=e.getBoundingClientRect();h({left:t.left,top:t.top,bottom:t.bottom,width:t.width})},[]),O=(0,y.useCallback)(()=>{o||n.length===0||(S.current={buf:``,at:0},p(E),D(),d(!0))},[o,D,n.length,E]),k=(0,y.useCallback)(e=>{let t=n[e];t&&r(t.value),d(!1),v.current?.focus()},[r,n]);(0,y.useLayoutEffect)(()=>{l&&x.current?.focus()},[l]),(0,y.useLayoutEffect)(()=>{if(!l||!m)return;let e=x.current;if(!e)return;let t=window.innerHeight-m.bottom;_(t<e.offsetHeight+12&&m.top>t)},[l,m,n.length]),(0,y.useEffect)(()=>{l&&x.current?.querySelector(`[data-opt="${f}"]`)?.scrollIntoView({block:`nearest`})},[f,l]),(0,y.useEffect)(()=>{if(!l)return;let e=()=>D(),t=e=>{let t=e.target;t&&(v.current?.contains(t)||x.current?.contains(t))||d(!1)};return window.addEventListener(`scroll`,e,!0),window.addEventListener(`resize`,e),document.addEventListener(`pointerdown`,t,!0),()=>{window.removeEventListener(`scroll`,e,!0),window.removeEventListener(`resize`,e),document.removeEventListener(`pointerdown`,t,!0)}},[l,D]);let A=(0,y.useCallback)((e,t)=>{let r=Date.now(),i=(r-S.current.at>700?``:S.current.buf)+e;S.current={buf:i,at:r};let a=i.toLowerCase(),o=n.length,s=i.length===1?(t+1)%o:0;for(let e=0;e<o;e+=1){let t=(s+e)%o;if(n[t].label.toLowerCase().startsWith(a)){p(t);return}}},[n]),j=e=>e.key.length===1&&!e.ctrlKey&&!e.metaKey&&!e.altKey&&/\S/.test(e.key),M=e=>{if(!(o||l)){if(e.key===`ArrowDown`||e.key===`ArrowUp`||e.key===`Enter`||e.key===` `){e.preventDefault(),O();return}j(e)&&(e.preventDefault(),O(),A(e.key,E))}},N=e=>{let t=n.length;switch(e.key){case`ArrowDown`:e.preventDefault(),p(e=>(e+1)%t);break;case`ArrowUp`:e.preventDefault(),p(e=>(e-1+t)%t);break;case`Home`:e.preventDefault(),p(0);break;case`End`:e.preventDefault(),p(t-1);break;case`Enter`:case` `:e.preventDefault(),k(f);break;case`Escape`:e.preventDefault(),e.stopPropagation(),d(!1),v.current?.focus();break;case`Tab`:d(!1),v.current?.focus();break;default:j(e)&&A(e.key,f)}},P=n[E]?.label??``;return(0,u.jsxs)(`div`,{className:`sel-field`,style:i?{width:i}:void 0,children:[(0,u.jsxs)(`button`,{type:`button`,ref:v,className:s===`sm`?`sel sm`:`sel`,"aria-haspopup":`listbox`,"aria-expanded":l,"aria-controls":l?w:void 0,"aria-label":c,"data-value":t,disabled:o,onClick:()=>l?d(!1):O(),onKeyDown:M,children:[(0,u.jsx)(`span`,{className:`sel-val`,children:P}),(0,u.jsx)(a,{size:s===`sm`?12:13,className:`ic caret-glyph`,"aria-hidden":!0})]}),l&&m?(0,b.createPortal)((0,u.jsx)(`div`,{ref:x,id:w,role:`listbox`,tabIndex:-1,"aria-activedescendant":n.length?T(f):void 0,className:s===`sm`?`sel-pop sm`:`sel-pop`,onKeyDown:N,style:{left:Math.max(8,Math.min(m.left,window.innerWidth-Math.max(m.width,168)-8)),top:g?void 0:m.bottom+6,bottom:g?window.innerHeight-m.top+6:void 0,minWidth:m.width},children:n.map((n,r)=>(0,u.jsxs)(`div`,{id:T(r),"data-opt":r,"data-value":n.value,role:`option`,"aria-selected":n.value===t,className:`sel-opt${r===f?` on`:``}${n.value===t?` picked`:``}`,onMouseEnter:()=>p(r),onPointerDown:e=>e.preventDefault(),onClick:()=>k(r),children:[(0,u.jsx)(`span`,{className:`sel-opt-lb`,children:n.label}),n.value===t?(0,u.jsx)(e,{size:13,className:`ic`,"aria-hidden":!0}):null]},n.value))}),document.body):null]})}export{m as a,d as c,g as i,f as l,_ as n,h as o,v as r,p as s,x as t};
@@ -0,0 +1,5 @@
1
+ import{D as e,J as t,S as n,f as r,it as i,l as a,p as o,tt as s,w as c,z as l}from"./vendor-befEYGHM.js";import{M as u,a as d,c as f,g as p,j as m,p as h,r as g}from"./index-nQeRK3kW.js";import{t as _}from"./accessUrl-DbL5DLDz.js";import{a as v,c as y,l as b,n as x,r as S,s as C,t as w}from"./Select-G6AhT0TA.js";import{t as T}from"./Modal-B-rIrvXS.js";import{t as E}from"./Drawer-CleQGhRU.js";import{t as D}from"./Switch-0KA1AbiV.js";var O=i(),k=s();function A({item:e,value:t,disabled:n,onChange:r}){if(e.type===`switch`)return(0,k.jsx)(D,{checked:!!t,disabled:n||e.readonly,label:e.label,onChange:e=>r(e)});if(e.type===`badge`)return(0,k.jsx)(b,{tone:`live`,children:String(t)});if(e.type===`select`){let i=(e.options??[]).map(e=>({value:e.value,label:e.label}));return(0,k.jsx)(w,{value:String(t),options:i,disabled:n||e.readonly,onChange:e=>r(e),width:188})}return e.type===`number`?(0,k.jsx)(`input`,{className:`field-input num`,type:`number`,value:t==null?``:String(t),disabled:n||e.readonly,onChange:e=>r(e.target.value===``?``:Number(e.target.value)),"aria-label":e.label}):e.type===`mapping`?null:(0,k.jsx)(`input`,{className:`field-input text`,value:t==null?``:String(t),disabled:n||e.readonly,onChange:e=>r(e.target.value),"aria-label":e.label})}function j(){let e=_(),[n,r]=(0,O.useState)(!1),i=async()=>{try{await navigator.clipboard.writeText(e),r(!0),window.setTimeout(()=>r(!1),1200)}catch{}};return(0,k.jsxs)(`div`,{className:`card access-card`,children:[(0,k.jsxs)(`div`,{className:`access-head`,children:[(0,k.jsxs)(`span`,{className:`access-title`,children:[(0,k.jsx)(c,{size:13,"aria-hidden":!0}),`接入地址`]}),(0,k.jsx)(`span`,{className:`access-sub`,children:`客户端与 API 同源 —— 这就是你当前访问控制台的地址`})]}),(0,k.jsxs)(`div`,{className:`key-plain access-url`,children:[(0,k.jsx)(`code`,{children:e}),(0,k.jsxs)(`button`,{type:`button`,className:`copy`,"aria-label":n?`已复制接入地址`:`复制接入地址`,onClick:()=>void i(),children:[n?(0,k.jsx)(t,{size:13}):(0,k.jsx)(l,{size:13}),n?`已复制`:`复制`]})]}),(0,k.jsxs)(`p`,{className:`chain-note`,children:[`客户端里要填两组值:`,(0,k.jsx)(`b`,{children:`base_url`}),` 就是上面这串;`,(0,k.jsx)(`b`,{children:`API Key`}),` 用你在本页`,(0,k.jsx)(`b`,{children:`新建的那把`}),(0,k.jsx)(`span`,{className:`code-chip`,children:`sk-waygate-…`}),`(明文只在创建时显示一次,丢了只能删掉重建)。`]}),(0,k.jsxs)(`div`,{className:`cred-note access-cert`,children:[(0,k.jsx)(a,{size:14,"aria-hidden":!0}),(0,k.jsxs)(`span`,{children:[`本服务的 TLS 是`,(0,k.jsx)(`b`,{children:`自签证书`}),`:客户端得先信任它的根证书,否则会以「证书错误」失败 —— 那`,(0,k.jsx)(`b`,{children:`不是`}),`地址填错。把根证书装进系统信任库,或让客户端通过`,(0,k.jsx)(`span`,{className:`code-chip`,children:`NODE_EXTRA_CA_CERTS`}),` /`,(0,k.jsx)(`span`,{className:`code-chip`,children:`SSL_CERT_FILE`}),`指向随部署产出的`,(0,k.jsx)(`span`,{className:`code-chip`,children:`relay-ca.crt`}),`。`]})]})]})}var M=8,N=128;function P({onClose:r,onDone:i}){let[o,s]=(0,O.useState)(`reset`),[c,d]=(0,O.useState)(`warn`),[p,m]=(0,O.useState)(``),[h,_]=(0,O.useState)(!1),[v,y]=(0,O.useState)(null),[b,x]=(0,O.useState)(null),[C,w]=(0,O.useState)(!1),[E,D]=(0,O.useState)(``),[A,j]=(0,O.useState)(``),[P,I]=(0,O.useState)(null),L=p===`确认`,R=async()=>{if(L&&!h){_(!0),y(null);try{let e=await f.resetAdminPassword();x(e),d(`result`)}catch(e){y(e instanceof u?S(e):String(e))}finally{_(!1)}}},z=async()=>{if(b)try{await navigator.clipboard.writeText(b.password),w(!0),window.setTimeout(()=>w(!1),2e3)}catch{y(`浏览器拒绝了剪贴板访问,请手动选中口令复制。`)}},B=()=>{x(null),D(``),j(``),i?.(),r()},V=async()=>{if(h)return;let e=E.trim();if(e.length===0){y(`管理口令不能为空或纯空白。`);return}if(e.length<M){y(`管理口令至少 ${M} 个字符,当前 ${e.length} 个。`);return}if(E.length>N){y(`管理口令最多 ${N} 个字符,当前 ${E.length} 个。`);return}if(E!==A){y(`两次输入不一致,请重新确认。`);return}_(!0),y(null);try{let e=await f.setAdminPassword(E);D(``),j(``),I(e.persisted?`已生效,下次登录用新口令。当前会话不受影响。`:`已生效(仅内存),下次登录用新口令 —— 但服务端数据库不可写,重启后会回到上一个口令。`)}catch(e){y(e instanceof u?S(e):String(e))}finally{_(!1)}};if(o===`manual`&&P)return(0,k.jsxs)(T,{title:`管理口令已更新`,onClose:B,footer:(0,k.jsx)(`button`,{type:`button`,className:`btn btn-primary btn-sm`,onClick:B,children:`知道了`}),children:[(0,k.jsx)(`div`,{className:`pw-note`,children:P}),(0,k.jsxs)(`p`,{className:`ov-sub`,style:{marginTop:12},children:[`服务端只存了口令的 scrypt 哈希,`,(0,k.jsx)(`b`,{children:`回不出明文`}),`。请确保你已经记住了刚才输入的口令。`]})]});if(o===`manual`){let t=E.trim().length>0&&E.trim().length<M,i=A.length>0&&E!==A;return(0,k.jsxs)(T,{title:`手动设定管理口令`,onClose:r,footer:(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(`button`,{type:`button`,className:`btn btn-quiet btn-sm`,onClick:r,children:`取消`}),(0,k.jsxs)(`button`,{type:`button`,className:`btn btn-primary btn-sm`,disabled:h||t||i||E.trim().length===0,onClick:()=>void V(),children:[h?(0,k.jsx)(n,{size:14}):(0,k.jsx)(e,{size:14}),h?`保存中…`:`保存并生效`]})]}),children:[(0,k.jsxs)(`p`,{className:`ov-sub`,children:[`设定一个你自己方便记忆的管理口令(至少 `,M,` 个字符)。 保存后`,(0,k.jsx)(`b`,{children:`立即生效、无需重启`}),`,当前会话不会被打断。`]}),(0,k.jsxs)(`div`,{className:`ov-field`,children:[(0,k.jsx)(`label`,{htmlFor:`pw-new`,children:`新管理口令`}),(0,k.jsx)(`input`,{id:`pw-new`,type:`password`,className:`field-input text`,style:{width:`100%`},value:E,autoFocus:!0,autoComplete:`new-password`,placeholder:`至少 ${M} 个字符`,onChange:e=>{D(e.target.value),y(null)}}),t?(0,k.jsxs)(`div`,{className:`ov-hint`,style:{color:`var(--warn-amber)`},children:[`至少 `,M,` 个字符,当前 `,E.trim().length,` 个。`]}):null]}),(0,k.jsxs)(`div`,{className:`ov-field`,children:[(0,k.jsx)(`label`,{htmlFor:`pw-new-confirm`,children:`再次输入`}),(0,k.jsx)(`input`,{id:`pw-new-confirm`,type:`password`,className:`field-input text`,style:{width:`100%`},value:A,autoComplete:`new-password`,placeholder:`重复上面输入的口令`,onChange:e=>{j(e.target.value),y(null)}}),i?(0,k.jsx)(`div`,{className:`ov-hint`,style:{color:`var(--warn-amber)`},children:`两次输入不一致。`}):null]}),(0,k.jsxs)(`div`,{className:`ov-lose`,children:[(0,k.jsx)(`b`,{children:`请记住它:`}),`设定后旧口令立即失效,且本产品没有「忘记口令」的找回通道。 口令明文不会保存在浏览器任何位置,也不会被回显。`]}),v?(0,k.jsx)(g,{tone:`error`,children:(0,k.jsx)(`span`,{style:{display:`block`,marginTop:14},children:v})}):null]})}return c===`result`&&b?(0,k.jsxs)(T,{title:`新管理口令`,onClose:B,footer:(0,k.jsx)(`button`,{type:`button`,className:`btn btn-primary btn-sm`,onClick:B,children:`我已保存,关闭`}),children:[(0,k.jsxs)(`div`,{className:`pw-once`,children:[(0,k.jsxs)(`div`,{className:`pw-once-head`,children:[(0,k.jsx)(a,{size:16}),(0,k.jsx)(`b`,{children:`这是唯一一次显示`})]}),(0,k.jsx)(`div`,{className:`pw-once-body`,children:`关闭这个窗口后,服务端也回不出这份明文 —— 库里只存了它的 scrypt 哈希。 请现在就复制并保存到你的密码管理器里。`})]}),(0,k.jsxs)(`div`,{className:`pw-plain`,children:[(0,k.jsx)(`code`,{children:b.password}),(0,k.jsxs)(`button`,{type:`button`,className:`btn btn-quiet btn-sm`,onClick:()=>void z(),children:[C?(0,k.jsx)(t,{size:14}):(0,k.jsx)(l,{size:14}),C?`已复制`:`复制`]})]}),b.persisted?(0,k.jsxs)(`div`,{className:`pw-note`,children:[`已写入服务端数据库,`,(0,k.jsx)(`b`,{children:`立即生效、无需重启`}),`,并会随每日备份一起保存。 下次登录请使用新口令。`]}):(0,k.jsx)(g,{tone:`warn`,children:(0,k.jsxs)(`span`,{style:{display:`block`,marginTop:14},children:[`服务端数据库不可写,新口令`,(0,k.jsx)(`b`,{children:`仅本次运行有效`}),`:重启后会回到旧口令。 请先修好数据目录权限,再重置一次。`]})}),v?(0,k.jsx)(g,{tone:`error`,children:(0,k.jsx)(`span`,{style:{display:`block`,marginTop:14},children:v})}):null]}):c===`confirm`?(0,k.jsxs)(T,{title:`确认重置管理口令?`,onClose:r,footer:(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(`button`,{type:`button`,className:`btn btn-primary btn-sm`,onClick:r,children:`取消(保持现状)`}),(0,k.jsxs)(`button`,{type:`button`,className:`btn btn-danger btn-sm`,disabled:!L||h,onClick:()=>void R(),children:[h?(0,k.jsx)(n,{size:14}):null,h?`重置中…`:`确认重置`]})]}),children:[(0,k.jsxs)(`p`,{className:`ov-sub`,children:[`重置后,`,(0,k.jsx)(`b`,{children:`当前口令立即失效`}),`。你正在使用的这个会话不会被打断,但下次登录必须用新口令。`]}),(0,k.jsxs)(`div`,{className:`ov-lose`,children:[(0,k.jsx)(`b`,{children:`会失去什么:`}),`旧口令的所有副本(笔记、密码管理器里的旧条目)都会变成无效值。本产品没有「忘记口令」的找回通道。`]}),(0,k.jsxs)(`div`,{className:`ov-field`,children:[(0,k.jsxs)(`label`,{htmlFor:`pw-confirm`,children:[`输入 `,(0,k.jsx)(`b`,{style:{color:`var(--text-secondary)`,fontWeight:500},children:`确认`}),` 以继续`]}),(0,k.jsx)(`input`,{id:`pw-confirm`,className:`field-input text`,style:{width:`100%`,fontFamily:`var(--font-mono)`},value:p,autoFocus:!0,placeholder:`确认`,onChange:e=>m(e.target.value)}),(0,k.jsx)(`div`,{className:`ov-hint`,children:`打错一个字就没法继续。重置入口凭证值得这一步。`})]}),v?(0,k.jsx)(g,{tone:`error`,children:v}):null]}):(0,k.jsxs)(T,{title:`重置管理口令`,onClose:r,footer:(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(`button`,{type:`button`,className:`btn btn-quiet btn-sm`,onClick:r,children:`取消`}),(0,k.jsxs)(`button`,{type:`button`,className:`btn btn-danger btn-sm`,onClick:()=>d(`confirm`),children:[(0,k.jsx)(e,{size:14}),`我明白,继续`]})]}),children:[(0,k.jsx)(F,{mode:o,onChange:e=>{s(e),y(null)}}),(0,k.jsxs)(`p`,{className:`ov-sub`,children:[`服务端会生成一个新的 16 位随机口令。`,(0,k.jsx)(`b`,{children:`新口令只显示一次`}),`,请准备好记录工具。`]}),(0,k.jsxs)(`div`,{className:`pw-warn-list`,children:[(0,k.jsxs)(`div`,{children:[(0,k.jsx)(`span`,{className:`pw-dot`}),(0,k.jsxs)(`span`,{children:[(0,k.jsx)(`b`,{children:`当前口令立即失效`}),` —— 但已登录的会话`,(0,k.jsx)(`b`,{children:`不受影响`}),`:会话由独立密钥 (RELAY_SECRET)签名,与口令本身无关。包括其它浏览器标签页在内的登录态, 都会保持有效直到各自过期。本版本未提供「改密强制所有会话下线」。`]})]}),(0,k.jsxs)(`div`,{children:[(0,k.jsx)(`span`,{className:`pw-dot`}),(0,k.jsxs)(`span`,{children:[(0,k.jsx)(`b`,{children:`没有找回通道`}),` —— 忘记新口令后,只能上服务器删除数据结构后重新引导。`]})]}),(0,k.jsxs)(`div`,{children:[(0,k.jsx)(`span`,{className:`pw-dot`}),(0,k.jsxs)(`span`,{children:[(0,k.jsx)(`b`,{children:`立即生效、无需重启`}),` —— 哈希写进数据库后立刻对后续登录起作用。`]})]})]}),(0,k.jsx)(`div`,{className:`ov-hint`,style:{marginTop:12},children:`想用自己的口令?切到上方「手动设定」—— 随机口令更安全,手动口令更好记,按需选择。`})]})}function F({mode:e,onChange:t}){return(0,k.jsxs)(`span`,{className:`seg-tabs`,role:`group`,"aria-label":`口令变更方式`,style:{marginBottom:14},children:[(0,k.jsx)(`button`,{type:`button`,className:e===`reset`?`on`:``,"aria-pressed":e===`reset`,onClick:()=>t(`reset`),children:`随机重置`}),(0,k.jsx)(`button`,{type:`button`,className:e===`manual`?`on`:``,"aria-pressed":e===`manual`,onClick:()=>t(`manual`),children:`手动设定`})]})}function I({spec:e,onClose:t,onDone:r}){let[i,a]=(0,O.useState)(``),[o,s]=(0,O.useState)(!1),[c,l]=(0,O.useState)(null),d=i===`确认`,p=async()=>{if(d&&!o){s(!0),l(null);try{r(await f.danger(e.action,i))}catch(e){l(e instanceof u?e:new u(String(e),0,0)),s(!1)}}};return(0,k.jsxs)(T,{title:e.title,onClose:t,footer:(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(`button`,{type:`button`,className:`btn btn-primary btn-sm`,onClick:t,children:`取消(保持现状)`}),(0,k.jsxs)(`button`,{type:`button`,className:`btn btn-danger btn-sm`,disabled:!d||o,onClick:()=>void p(),children:[o?(0,k.jsx)(n,{size:14}):null,o?`执行中…`:e.ok]})]}),children:[(0,k.jsx)(`p`,{className:`ov-sub`,children:e.body}),(0,k.jsxs)(`div`,{className:`ov-lose`,children:[(0,k.jsx)(`b`,{children:`会失去什么:`}),e.lose]}),(0,k.jsxs)(`div`,{className:`ov-field`,children:[(0,k.jsxs)(`label`,{htmlFor:`danger-confirm`,children:[`输入 `,(0,k.jsx)(`b`,{style:{color:`var(--text-secondary)`,fontWeight:500},children:`确认`}),` 以继续`]}),(0,k.jsx)(`input`,{id:`danger-confirm`,className:`field-input text`,style:{width:`100%`,fontFamily:`var(--font-mono)`},value:i,autoFocus:!0,placeholder:`确认`,onChange:e=>a(e.target.value)}),(0,k.jsx)(`div`,{className:`ov-hint`,children:`打错一个字就没法继续。破坏性操作值得这一步。`})]}),c?(0,k.jsx)(g,{tone:`error`,children:S(c)}):null]})}var L={"danger.clearLogs":{action:`clearLogs`,title:`清空全部日志?`,body:`删除后「按模型 / 按客户端」明细会一并归零。剩余积分不受影响,服务也不中断。`,lose:`将删除本机全部请求日志,覆盖保留天数内的所有记录,没有备份入口。`,ok:`确认清空`},"danger.resetKeys":{action:`resetKeys`,title:`重置全部密钥?`,body:`所有密钥会立即失效,每个客户端都要重新填一次。已消耗的积分不受影响。`,lose:`将失效全部 sk-waygate- 密钥,正在使用它们的客户端会立刻收到 401。`,ok:`确认重置`},"danger.restoreDefaults":{action:`restoreDefaults`,title:`恢复默认配置?`,body:`会用默认值覆盖 ~/.relay/config.yml。你改过的端口、并发、日志保留天数都会回到出厂值。`,lose:`将覆盖所有自定义配置,服务重启后生效。`,ok:`确认恢复`}},R={openai:`OpenAI 方言`,anthropic:`Anthropic 方言`,qoder:`COSY 协议`};function z(){let e=m(()=>f.providers(),[],{cacheKey:`providers`}),t=e.data?.items??[],[n,r]=(0,O.useState)(null),i=m(()=>f.providerGrowthPanel(n.id),[n?.id],{enabled:n!==null});return(0,k.jsxs)(v,{title:`提供商健康`,aside:(0,k.jsxs)(y,{children:[t.length,` 家 · 只读总览`]}),children:[e.initial&&e.loading?(0,k.jsx)(`div`,{className:`empty-note`,style:{padding:`8px 0`},children:`正在读取提供商…`}):e.error?(0,k.jsx)(`div`,{className:`empty-note`,style:{padding:`8px 0`},children:`提供商列表没取到,稍后重试。`}):t.length===0?(0,k.jsx)(`div`,{className:`empty-note`,style:{padding:`8px 0`},children:`还没有登记任何提供商 —— 到「提供商管理 → 提供商」新增。`}):(0,k.jsx)(`div`,{className:`tbl-scroll`,children:(0,k.jsxs)(`table`,{className:`tbl`,children:[(0,k.jsx)(`caption`,{className:`sr-only`,children:`各提供商的健康状态`}),(0,k.jsx)(`thead`,{children:(0,k.jsxs)(`tr`,{children:[(0,k.jsx)(`th`,{scope:`col`,children:`提供商`}),(0,k.jsx)(`th`,{scope:`col`,children:`协议`}),(0,k.jsx)(`th`,{scope:`col`,children:`凭证`}),(0,k.jsx)(`th`,{scope:`col`,children:`状态`}),(0,k.jsx)(`th`,{scope:`col`,className:`r`,children:`模型数`}),(0,k.jsx)(`th`,{scope:`col`,children:`积分 / 签到`})]})}),(0,k.jsx)(`tbody`,{children:t.map(e=>(0,k.jsxs)(`tr`,{children:[(0,k.jsx)(`td`,{className:`td-strong`,children:e.name}),(0,k.jsx)(`td`,{className:`td-sub`,children:R[e.protocol]??e.protocol}),(0,k.jsx)(`td`,{children:(0,k.jsx)(`span`,{className:`up-badge${e.configured?``:` warn`}`,children:e.configured?`有效`:`未配置`})}),(0,k.jsx)(`td`,{children:e.active?(0,k.jsx)(y,{tone:`live`,children:`已启用`}):(0,k.jsx)(y,{tone:`ghost`,children:`未启用`})}),(0,k.jsx)(`td`,{className:`r td-mono`,children:p(e.modelCount??0)}),(0,k.jsx)(`td`,{className:`td-sub td-mono`,children:e.credits?.available?(0,k.jsxs)(k.Fragment,{children:[`剩余 `,h(e.credits.remaining??0),e.credits.consumed===null?null:(0,k.jsxs)(k.Fragment,{children:[` `,(0,k.jsx)(d,{content:`已消耗 / 累计发放 —— 账户级全部历史(含官方客户端直连的用量)。
2
+ 不是本服务转发的那部分,与剩余不是同一种量。`,children:(0,k.jsxs)(`span`,{className:`credit-aside`,children:[`已消耗 `,h(e.credits.consumed),e.credits.granted===null?``:` / 发放 ${h(e.credits.granted)}`]})})]}),e.credits.stale?`(偏旧)`:``]}):e.qoderCredits?(0,k.jsxs)(k.Fragment,{children:[e.qoderCredits.remaining===null?`余额未知`:`剩余 ${h(e.qoderCredits.remaining)}`,e.qoderCredits.lifetimeConsumed!==null&&e.qoderCredits.lifetimeConsumed!==void 0?(0,k.jsxs)(k.Fragment,{children:[` `,(0,k.jsx)(d,{content:`累计消耗 —— 这个账号近一年在该平台消耗掉的 credits 总量(账号级)。
3
+ 它不是当前余额,也不是本服务转发的那部分:含官方客户端直连的用量。
4
+ 数值等于每日消耗热力图近 371 天之和。`,children:(0,k.jsxs)(`span`,{className:`credit-aside`,children:[`累计消耗 `,h(e.qoderCredits.lifetimeConsumed),e.qoderCredits.granted===null?``:` / 发放 ${h(e.qoderCredits.granted)}`]})})]}):null,e.qoderCredits.stale?`(偏旧)`:``,e.signin?.streak?`(连续活跃 ${p(e.signin.streak)} 天)`:``]}):e.wbCredits?(0,k.jsxs)(k.Fragment,{children:[`剩余 `,h(e.wbCredits.remaining??0),e.wbCredits.consumed===null?null:(0,k.jsxs)(k.Fragment,{children:[` `,(0,k.jsx)(d,{content:`已消耗 / 累计发放 —— 账户全部资源包的历史合计(含已过期包、
5
+ 含官方客户端直连的用量)。剩余只统计未过期包,两者口径不同。`,children:(0,k.jsxs)(`span`,{className:`credit-aside`,children:[`已消耗 `,h(e.wbCredits.consumed),e.wbCredits.granted===null?``:` / 发放 ${h(e.wbCredits.granted)}`]})})]}),e.wbSignin?.streak?`(连签 ${p(e.wbSignin.streak)} 天)`:``]}):e.signin?.checkedOn?(0,k.jsxs)(k.Fragment,{children:[`今日已签到`,e.signin.lastPoints?` +${p(e.signin.lastPoints)}`:``]}):e.wbSignin?.checkedOn?(0,k.jsxs)(k.Fragment,{children:[`今日已签到`,e.wbSignin.lastPoints?` +${p(e.wbSignin.lastPoints)}`:``]}):`—`}),(0,k.jsx)(`td`,{children:e.protocol===`openai`&&e.wbOAuth?.configured?(0,k.jsx)(d,{content:`查看成长任务的完成情况(进度/奖励/状态,只读)`,children:(0,k.jsx)(`button`,{type:`button`,className:`mini-pill`,onClick:()=>r(e),children:`任务`})}):(0,k.jsx)(`span`,{className:`td-sub`,children:`—`})})]},e.id))})]})}),(0,k.jsxs)(`ul`,{className:`ph-notes`,children:[(0,k.jsxs)(`li`,{children:[(0,k.jsx)(`b`,{children:`积分口径(三家各不同)`}),`:本表「积分」列都取`,(0,k.jsx)(`b`,{children:`上游真实余额`}),`,非本地推算。 MiniMax Code 来自 `,(0,k.jsx)(`span`,{className:`code-chip`,children:`credit/details`}),`(余额/已用/累计发放齐全,精确到 0.01); WorkBuddy 来自资源包聚合 `,(0,k.jsx)(`span`,{className:`code-chip`,children:`get-user-resource`}),`(剩余/发放为包级真实数); Qoder CN 来自 `,(0,k.jsx)(`span`,{className:`code-chip`,children:`v2/me/usage`}),`(套餐内 + 资源包合计 —— 签到赠送的 Credits 进资源包,故签完此处会上涨)。`,(0,k.jsx)(`b`,{children:`到期时刻仅 Qoder 不提供`}),`(上游无此字段), 概览「积分账本」对应列显示 `,(0,k.jsx)(`span`,{className:`code-chip`,children:`—`}),`。 另一种「累计消耗」是`,(0,k.jsx)(`b`,{children:`账号级近一年消耗总量`}),`(含官方客户端直连),与余额不是一回事, 两者不混算。`]}),(0,k.jsxs)(`li`,{children:[(0,k.jsx)(`b`,{children:`每日签到`}),`:MiniMax Code 由本服务每天 08:05 后自动代签(OAuth 链)。WorkBuddy 分两档: 已导入桌面端 OAuth 凭证的(提供商管理 → 提供商 → 导入OAuth)每天 08:05 `,(0,k.jsx)(`b`,{children:`自动代领`}),`签到 + 成长任务 + 连登兑换;未导入的只做状态同步(上游不允许 API 密钥代领,403 实证)。 OAuth 与转发用的 API 密钥互不影响(实验实证多会话共存,桌面端不受干扰)。成长任务的 完成情况点本表「任务」查看(未完成的需在官方客户端真实使用后才能领)。`]}),(0,k.jsxs)(`li`,{children:[(0,k.jsx)(`b`,{children:`凭证口径(两家不同)`}),`:`,(0,k.jsx)(`b`,{children:`MiniMax Code 是真互斥`}),` —— refresh token 一次性,且「同一账号同时只有一个有效会话」, 桌面客户端登录会把本服务顶下线,反之亦然;`,(0,k.jsx)(`b`,{children:`建议给本服务用专用账号`}),`。`,(0,k.jsx)(`b`,{children:`Qoder CN 不互斥`}),` —— 支持多会话并存,本服务与桌面客户端可同时用同一账号(实测 2026-10-16),`,(0,k.jsx)(`b`,{children:`无需`}),`专用账号。任一凭证失效时到「提供商管理 → 提供商」重新导入。`]}),(0,k.jsxs)(`li`,{children:[(0,k.jsx)(`b`,{children:`Qoder 零内容断流自动重试`}),`:Qoder 网关在大上下文时偶发「返回 200 但零字节即断开」, 本服务会自动重发一次(最多 1 次,对客户端无感 —— 重试发生在响应提交之前)。 请求日志里记 `,(0,k.jsx)(`span`,{className:`code-chip`,children:`retry_count`}),` 与 `,(0,k.jsx)(`span`,{className:`code-chip`,children:`retried`}),`。`]}),(0,k.jsxs)(`li`,{children:[(0,k.jsx)(`b`,{children:`提供商归属的已知限制`}),`:请求表不记录「这条走的是哪家」,提供商归属按`,(0,k.jsx)(`b`,{children:`模型 id → 目录`}),`推断。因此同名的模型 id 分属两家时归属可能不准; 请求日志的「提供商」列也是用同一推断口径。`]})]}),n?(0,k.jsx)(E,{title:`成长任务 · ${n.name}`,subtitle:`完成态与奖励(上游实时只读;未完成的需在官方客户端真实使用后才能领)`,onClose:()=>r(null),children:(0,k.jsxs)(`div`,{className:`drawer-body`,children:[i.initial&&i.loading?(0,k.jsx)(`div`,{className:`empty-note`,children:`正在读取任务面板…`}):i.error||!i.data?.ok?(0,k.jsx)(`div`,{className:`empty-note`,children:i.error?.message??i.data?.message??`任务面板没取到,稍后重试。`}):(0,k.jsx)(`div`,{style:{maxHeight:`min(68vh, 640px)`,overflow:`auto`},children:(0,k.jsxs)(`table`,{className:`tbl`,style:{minWidth:480},children:[(0,k.jsx)(`caption`,{className:`sr-only`,children:`成长任务完成情况`}),(0,k.jsx)(`thead`,{children:(0,k.jsxs)(`tr`,{children:[(0,k.jsx)(`th`,{scope:`col`,children:`任务`}),(0,k.jsx)(`th`,{scope:`col`,style:{width:56},children:`进度`}),(0,k.jsx)(`th`,{scope:`col`,className:`r`,style:{width:84},children:`奖励`}),(0,k.jsx)(`th`,{scope:`col`,style:{width:72},children:`状态`})]})}),(0,k.jsx)(`tbody`,{children:i.data.tasks.map(e=>(0,k.jsxs)(`tr`,{children:[(0,k.jsx)(`td`,{style:{maxWidth:104},children:(0,k.jsx)(d,{content:e.desc?`${e.title??e.code} —— ${e.desc}`:e.title??e.code,children:(0,k.jsx)(`span`,{className:`td-strong`,style:{display:`inline-block`,maxWidth:`100%`,whiteSpace:`nowrap`,overflow:`hidden`,textOverflow:`ellipsis`,verticalAlign:`bottom`},children:e.title??e.code})})}),(0,k.jsx)(`td`,{className:`td-mono`,children:e.progress?`${e.progress.current}/${e.progress.target}`:`—`}),(0,k.jsx)(`td`,{className:`r td-mono`,children:e.rewardCredit?`${e.rewardCredit} 积分`:`—`}),(0,k.jsx)(`td`,{children:e.status===`claimed`?(0,k.jsx)(y,{tone:`live`,children:`已领取`}):e.status===`in_progress`?(0,k.jsx)(y,{tone:`amber`,children:`进行中`}):e.locked?(0,k.jsx)(y,{tone:`ghost`,children:`未解锁`}):(0,k.jsx)(y,{tone:`ghost`,children:`待完成`})})]},e.code))})]})}),(0,k.jsx)(`div`,{className:`footer-note`,children:`每天 08:05 自动代领一轮(签到 + 已完成的任务 + 连登兑换);这里的数据来自上游任务面板,实时只读。`})]})}):null]})}var B=new Set([`credential.source`,`credential.status`]),V={service:`ghost`,credential:`cyan`,quota:`amber`,limits:`rose`,logs:`ghost`,password:`amber`,danger:`amber`,mapping:`cyan`};function H(){let t=m(()=>f.settings(),[],{cacheKey:`settings`}),[n,i]=(0,O.useState)({}),[a,s]=(0,O.useState)(!1),[c,l]=(0,O.useState)(null),[d,p]=(0,O.useState)(null),[h,_]=(0,O.useState)(null),[b,w]=(0,O.useState)(null),[T,E]=(0,O.useState)(!1),[D,A]=(0,O.useState)(null),[M,N]=(0,O.useState)(`access`),F=t.data?.groups??[],R=(0,O.useMemo)(()=>{let e=[{id:`access`,label:`接入地址`,tone:`cyan`}];for(let t of F)t.id!==`mapping`&&e.push({id:t.id,label:t.label,tone:V[t.id]??`ghost`});return e.push({id:`password`,label:`管理口令`,tone:`amber`}),e.push({id:`mapping`,label:`键位映射`,tone:`cyan`}),e},[F]),H=(0,O.useMemo)(()=>{let e={};for(let t of F){let r=0;for(let e of t.items)B.has(e.key)||e.readonly||e.type===`action`||e.type===`mapping`||e.key in n&&n[e.key]!==e.value&&(r+=1);r>0&&(e[t.id]=r)}return e},[F,n]),W=(e,t)=>e in n?n[e]:t,G=(0,O.useMemo)(()=>{if(!t.data)return[];let e=[];return t.data.groups.forEach(t=>t.items.forEach(t=>{B.has(t.key)||t.readonly||t.type===`action`||t.type===`mapping`||t.key in n&&n[t.key]!==t.value&&e.push({key:t.key,value:n[t.key]})})),e},[t.data,n]),K=async()=>{if(!(G.length===0||a)){s(!0),l(null),p(null);try{let e=await f.putSettings(G);i({}),p(e.requiresRestart?`已应用 ${e.applied} 项,配置版本 → v${e.version}。其中含需重启才生效的项。`:`已应用 ${e.applied} 项,配置版本 → v${e.version}。`),setTimeout(()=>p(null),4e3),t.reload()}catch(e){l(e instanceof u?e:new u(String(e),0,0))}finally{s(!1)}}},q=e=>{let n=e.affected.logs??e.affected.keys??0;w(`操作已完成,影响 ${n} 条记录。`),setTimeout(()=>w(null),4e3),_(null),t.reload()},J=F.find(e=>e.id===`mapping`)?.items[0],Y=F.find(e=>e.id===M),X=F.find(e=>e.id===`danger`)?.items??[];return(0,k.jsxs)(`div`,{className:`view on`,children:[(0,k.jsx)(C,{title:`设置`,status:t.data?(0,k.jsx)(y,{tone:G.length?`amber`:`ghost`,dot:G.length>0,children:G.length?`${G.length} 项待保存`:`配置版本 v${t.data.version}`}):null,actions:(0,k.jsxs)(k.Fragment,{children:[G.length?(0,k.jsxs)(`button`,{type:`button`,className:`btn btn-quiet btn-sm`,onClick:()=>i({}),children:[(0,k.jsx)(o,{size:14}),`放弃改动`]}):null,(0,k.jsxs)(`button`,{type:`button`,className:`btn btn-primary btn-sm`,disabled:G.length===0||a,onClick:()=>void K(),children:[(0,k.jsx)(r,{size:14}),a?`保存中…`:`保存`]})]})}),(0,k.jsxs)(`div`,{className:`view-body stack`,children:[c?(0,k.jsx)(g,{tone:`error`,children:S(c)}):null,d?(0,k.jsx)(g,{tone:`success`,children:d}):null,b?(0,k.jsx)(g,{tone:`success`,children:b}):null,D?(0,k.jsx)(g,{tone:`success`,children:D}):null,(0,k.jsxs)(`div`,{className:`settings-split`,children:[(0,k.jsx)(`nav`,{className:`settings-nav`,"aria-label":`设置分组`,children:R.map(e=>{let t=H[e.id]??0;return(0,k.jsxs)(`button`,{type:`button`,className:`settings-nav-i${M===e.id?` on`:``}`,"aria-current":M===e.id?`page`:void 0,onClick:()=>N(e.id),children:[(0,k.jsx)(`span`,{className:`settings-nav-label`,children:e.label}),t>0?(0,k.jsx)(`span`,{className:`settings-nav-dirty`,children:t}):null]},e.id)})}),(0,k.jsx)(`div`,{className:`settings-content`,children:t.initial&&t.loading?(0,k.jsx)(v,{children:(0,k.jsx)(x,{kind:`loading`,title:`正在读取配置…`})}):t.error?(0,k.jsx)(v,{children:(0,k.jsx)(x,{kind:`error`,title:`配置没取到`,detail:S(t.error),onRetry:t.reload})}):(0,k.jsxs)(k.Fragment,{children:[M===`access`?(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(j,{}),(0,k.jsx)(z,{})]}):null,M===`password`?(0,k.jsxs)(`div`,{className:`card`,children:[(0,k.jsxs)(`div`,{className:`group-head`,children:[(0,k.jsxs)(`h3`,{children:[(0,k.jsx)(e,{size:14,style:{verticalAlign:-2,marginRight:6}}),`管理口令`]}),(0,k.jsx)(`p`,{children:`控制台的唯一入口凭证`})]}),(0,k.jsxs)(`div`,{className:`set-row`,children:[(0,k.jsxs)(`div`,{className:`info`,children:[(0,k.jsx)(`b`,{children:`管理口令`}),(0,k.jsxs)(`span`,{children:[`两种改法:`,(0,k.jsx)(`b`,{children:`随机重置`}),`由服务端生成 16 位新口令(更强,但需当场保存);`,(0,k.jsx)(`b`,{children:`手动设定`}),`由你输入一个方便记忆的口令(至少 8 个字符)。 两种都立即生效、无需重启;新口令不回显、不落浏览器任何位置。`]})]}),(0,k.jsx)(`div`,{className:`ctl`,children:(0,k.jsxs)(`button`,{type:`button`,className:`btn btn-quiet btn-sm`,disabled:a,onClick:()=>E(!0),children:[(0,k.jsx)(e,{size:13}),`修改`]})})]})]}):null,M===`danger`?(0,k.jsxs)(`div`,{className:`card danger-zone`,children:[(0,k.jsxs)(`div`,{className:`group-head`,children:[(0,k.jsx)(`h3`,{style:{color:`var(--warn-amber)`},children:`危险操作`}),(0,k.jsx)(`p`,{children:`不可撤销,需二次确认`})]}),X.map(e=>(0,k.jsxs)(`div`,{className:`set-row`,children:[(0,k.jsxs)(`div`,{className:`info`,children:[(0,k.jsx)(`b`,{children:e.label}),(0,k.jsx)(`span`,{children:e.why})]}),(0,k.jsx)(`div`,{className:`ctl`,children:(0,k.jsx)(`button`,{type:`button`,className:`mini-pill danger`,disabled:a,onClick:()=>_(L[e.key]??null),children:e.label})})]},e.key))]}):null,M===`mapping`&&J?.type===`mapping`?(0,k.jsxs)(v,{title:J.label,aside:(0,k.jsx)(y,{children:`config.yml`}),children:[(0,k.jsx)(`div`,{className:`code`,style:{fontSize:12},children:Object.entries(J.value??{}).map(([e,t])=>(0,k.jsxs)(`div`,{children:[(0,k.jsx)(`span`,{className:`k`,children:e}),` → `,(0,k.jsx)(`span`,{className:`st`,children:t})]},e))}),(0,k.jsx)(`div`,{className:`footer-note`,children:J.why})]}):null,Y&&Y.id!==`danger`&&Y.id!==`mapping`?(0,k.jsx)(U,{group:Y,saving:a,valueOf:W,onChange:(e,t)=>i(n=>({...n,[e]:t}))}):null]})})]})]}),h?(0,k.jsx)(I,{spec:h,onClose:()=>_(null),onDone:q}):null,T?(0,k.jsx)(P,{onClose:()=>E(!1),onDone:()=>{A(`管理口令已更新并立即生效。下次登录请使用新口令。`),setTimeout(()=>A(null),4e3),t.reload()}}):null]})}function U({group:e,saving:t,valueOf:n,onChange:r}){let i=e.items.filter(e=>!B.has(e.key));if(i.length===0)return null;let a=i.filter(e=>!e.noop),o=i.filter(e=>e.noop);return(0,k.jsxs)(`div`,{className:`card`,children:[(0,k.jsxs)(`div`,{className:`group-head`,children:[(0,k.jsx)(`h3`,{children:e.label}),(0,k.jsx)(`p`,{children:W(e.id)})]}),a.map(e=>(0,k.jsx)(G,{item:e,value:n(e.key,e.value),saving:t,onChange:t=>r(e.key,t)},e.key)),o.length>0?(0,k.jsxs)(`details`,{className:`dormant`,children:[(0,k.jsxs)(`summary`,{children:[o.length,` 项暂未生效`,(0,k.jsx)(`span`,{children:`改了不会有任何变化 —— 依赖的功能未实现或上游未供货`})]}),o.map(e=>(0,k.jsx)(G,{item:e,value:n(e.key,e.value),saving:t,onChange:t=>r(e.key,t)},e.key))]}):null]})}function W(e){return{service:`进程监听与启动方式`,credential:`跨提供商的全局策略(部分项仅对 WorkBuddy 生效)`,quota:`积分口径与额度轮询(仅 WorkBuddy;MiniMax 走独立账本,Qoder 无端点)`,signin:`每日 08:05 自动签到(WorkBuddy 可关;MiniMax 恒开,Qoder 无签到)`,limits:`自用场景的保护,而非配额限制`,logs:`留在本机,不参与同步`}[e]??``}function G({item:e,value:t,saving:n,onChange:r}){return(0,k.jsxs)(`div`,{className:`set-row`,children:[(0,k.jsxs)(`div`,{className:`info`,children:[(0,k.jsxs)(`b`,{children:[e.label,e.requiresRestart?(0,k.jsx)(`span`,{style:{marginLeft:8,fontSize:10.5,color:`var(--warn-amber)`},children:`需重启`}):null]}),(0,k.jsx)(`span`,{children:e.why})]}),(0,k.jsx)(`div`,{className:`ctl`,children:(0,k.jsx)(A,{item:e,value:t,disabled:n,onChange:r})})]})}export{H as SettingsPage};
@@ -0,0 +1 @@
1
+ import{A as e,E as t,it as n,r,tt as i}from"./vendor-befEYGHM.js";import{O as a,_ as o,a as s,c,g as l,j as u,k as d,p as f,u as p,v as m,x as h}from"./index-nQeRK3kW.js";import{a as g,c as _,n as v,o as y,r as b,s as x,t as S}from"./Select-G6AhT0TA.js";import{a as C}from"./PageSkeleton-DG-Dj4_9.js";import{n as w,t as T}from"./sharedWindow-FDfq75PI.js";import{t as E}from"./useFx-xcrp_LHB.js";import{n as D,r as O,t as k}from"./ClientMetricTip-C2VuiT4-.js";var A=n(),j=i(),M={tokens:`消耗 tokens`,requests:`请求次数`};function N({points:e,metric:t,avg:n}){let[r,i]=(0,A.useState)(null),[a,o]=(0,A.useState)(null),s=(0,A.useRef)(null),c=(0,A.useRef)(null),[u,d]=(0,A.useState)(null);(0,A.useLayoutEffect)(()=>{let t=c.current,n=s.current;if(!t||!n||r===null||e.length===0){d(null);return}let i=()=>{let i=(r+.5)/e.length*n.clientWidth,a=n.getBoundingClientRect(),o=t.getBoundingClientRect(),s=i-(o.left-a.left);d(Math.max(12,Math.min(s,o.width-12)))};return i(),window.addEventListener(`resize`,i),()=>window.removeEventListener(`resize`,i)},[r,t,e.length]);let f=(0,A.useMemo)(()=>e.map((n,r)=>{let i=r>0?e[r-1]:null,a=i?t===`tokens`?n.tokens-i.tokens:n.requests-i.requests:null,o=/T\d{2}$/.test(n.bucket),s=(n.models??[]).slice(0,5).map(e=>`${e.model} ${h(e.tokens)} tokens`).join(`、`),c=a===null?``:` · 较${o?`上一小时`:`昨日`} ${a>0?`增加`:a<0?`减少`:`持平`}${a===0?``:` ${l(Math.abs(a))}`}`;return`${p(n.bucket)} · ${l(n.requests)} 次请求 · ${h(n.tokens)} tokens`+(n.errors>0?` · ${l(n.errors)} 次失败`:``)+(s?` · 模型:${s}`:``)+c}),[e,t]);if(e.length===0)return(0,j.jsx)(`div`,{className:`empty-note`,style:{padding:`24px 0`},children:`该窗口内没有请求记录。`});let m=e.map(e=>t===`tokens`?e.tokens:e.requests),g=Math.max(1,...m),_=l,v=n===null?null:Math.round(Math.min(1,Math.max(0,n/g))*1e4)/1e4,y=Math.ceil(e.length/5),b=a??e.length-1,x=t=>{let n=e.length-1,r;if(t.key===`ArrowRight`)r=Math.min(n,b+1);else if(t.key===`ArrowLeft`)r=Math.max(0,b-1);else if(t.key===`Home`)r=0;else if(t.key===`End`)r=n;else return;t.preventDefault(),o(r),i(r),(s.current?.querySelector(`[data-idx="${r}"]`)??void 0)?.focus()},S=r===null?null:e[r],C=S?/T\d{2}$/.test(S.bucket):!1,w=S&&r!==null&&r>0?e[r-1]:null,T=S&&w?t===`tokens`?S.tokens-w.tokens:S.requests-w.requests:null;return(0,j.jsxs)(j.Fragment,{children:[(0,j.jsxs)(`div`,{className:`avgline`,style:{"--avg":v??0},children:[v===null?null:(0,j.jsxs)(`span`,{className:`avg-row`,children:[(0,j.jsxs)(`span`,{className:`avg-tag`,children:[`日均 `,_(n)]}),(0,j.jsx)(`i`,{className:`avg-rule`})]}),(0,j.jsxs)(`div`,{className:`bars30 js-grow`,ref:s,onKeyDown:x,onMouseLeave:()=>i(null),children:[(0,j.jsxs)(`span`,{className:`grid`,"aria-hidden":`true`,children:[(0,j.jsx)(`i`,{className:`base`}),(0,j.jsx)(`i`,{className:`mid`}),(0,j.jsx)(`i`,{className:`q1`})]}),e.map((n,a)=>{let o=t===`tokens`?n.tokens:n.requests,s=a===e.length-1?`today`:o>=g?`peak`:``,c=n.errors>0,l=f[a];return(0,j.jsx)(`div`,{"data-idx":a,className:`bcol${a===r?` on`:``}`,role:`img`,"aria-label":l,tabIndex:a===b?0:-1,onMouseEnter:()=>i(a),onFocus:()=>i(a),onBlur:()=>i(e=>e===a?null:e),children:(0,j.jsx)(`div`,{className:`b ${s}`.trim()+(c?` err`:``),style:{height:`${Math.max(2,Math.round(o/g*100))}%`},children:c?(0,j.jsx)(`span`,{className:`err-dot`,"aria-hidden":`true`}):null})},n.bucket)}),S?(()=>{let n=r!==null&&e.length>0?(r+.5)/e.length*100:50;return(0,j.jsxs)(`div`,{ref:c,className:`bar-tip${n<12?` tip-left`:n>88?` tip-right`:``}`,style:{"--tip-x":`${n}%`,"--tip-arrow":u===null?void 0:`${u}px`},"aria-hidden":`true`,children:[(0,j.jsxs)(`div`,{className:`bt-head`,children:[(0,j.jsx)(`b`,{children:p(S.bucket)}),r===e.length-1?(0,j.jsx)(`span`,{className:`bt-tag`,children:`最新`}):null]}),(0,j.jsxs)(`div`,{className:`bt-row${t===`tokens`?` hot`:``}`,children:[(0,j.jsx)(`span`,{children:`消耗 tokens`}),(0,j.jsx)(`i`,{children:h(S.tokens)})]}),(S.models??[]).length>0?(0,j.jsx)(`div`,{className:`bt-models`,children:(S.models??[]).map(e=>(0,j.jsxs)(`div`,{className:`bt-model`,children:[(0,j.jsx)(`span`,{className:`bt-model-name`,children:e.model}),(0,j.jsxs)(`i`,{children:[h(e.tokens),(0,j.jsx)(`em`,{children:` · ${S.tokens>0?Math.round(e.tokens/S.tokens*100):0}%`})]})]},e.model))}):null,(0,j.jsxs)(`div`,{className:`bt-row${t===`requests`?` hot`:``}`,children:[(0,j.jsx)(`span`,{children:`请求次数`}),(0,j.jsx)(`i`,{children:l(S.requests)})]}),S.errors>0?(0,j.jsxs)(`div`,{className:`bt-row bt-err`,children:[(0,j.jsx)(`span`,{children:`失败`}),(0,j.jsxs)(`i`,{children:[l(S.errors),(0,j.jsxs)(`em`,{children:[` `,`(`,l(S.requests)===`--`||S.requests===0?`—`:`${(S.errors/S.requests*100).toFixed(1)}%`,`)`]})]})]}):null,T===null?null:(0,j.jsxs)(`div`,{className:`bt-delta${T>0?` up`:T<0?` down`:` flat`}`,children:[`较`,C?`上一小时`:`昨日`,T>0?` ▲`:T<0?` ▼`:` — `,T>0||T<0?l(Math.abs(T)):`持平`]})]})})():null]})]}),(0,j.jsx)(`div`,{className:`axis`,children:e.map((t,n)=>(0,j.jsx)(`span`,{children:n%y===0||n===e.length-1?p(t.bucket):``},t.bucket))})]})}function P({items:e,windowLabel:t}){if(e.length===0)return(0,j.jsxs)(`div`,{className:`empty-note`,children:[t,`没有可拆分的请求。`]});let n=Math.max(1,...e.map(e=>e.value)),r=e=>e?void 0:{fontFamily:`var(--font-body)`};return(0,j.jsx)(`div`,{className:`dist js-stagger js-grow`,children:e.map(e=>(0,j.jsxs)(`div`,{className:`d-row`,children:[e.tip?(0,j.jsx)(s,{content:e.tip,children:(0,j.jsx)(`span`,{className:`d-name`,style:r(e.mono),children:e.label})}):(0,j.jsx)(`span`,{className:`d-name`,style:r(e.mono),children:e.label}),(0,j.jsxs)(`span`,{className:`d-val`,children:[e.format===`credits`?f(e.value):l(e.value),` · `,e.trailing]}),(0,j.jsx)(`span`,{className:`d-track`,children:(0,j.jsx)(`i`,{style:{width:`${Math.max(2,Math.round(e.value/n*100))}%`}})})]},e.key))})}function F({items:e,windowLabel:t}){return e.length===0?(0,j.jsxs)(`div`,{className:`empty-note`,style:{padding:`8px 0`},children:[t,`没有按模型的消耗记录。`]}):(0,j.jsxs)(j.Fragment,{children:[(0,j.jsx)(`div`,{className:`tbl-scroll`,children:(0,j.jsxs)(`table`,{className:`tbl`,children:[(0,j.jsxs)(`caption`,{className:`sr-only`,children:[`按模型的 token 消耗明细,共 `,e.length,` 个模型`]}),(0,j.jsx)(`thead`,{children:(0,j.jsxs)(`tr`,{children:[(0,j.jsx)(`th`,{scope:`col`,children:`模型`}),(0,j.jsx)(`th`,{scope:`col`,className:`r`,children:`请求次数`}),(0,j.jsx)(`th`,{scope:`col`,className:`r`,children:`Token 消耗`}),(0,j.jsx)(`th`,{scope:`col`,className:`r`,children:`Token 占比`}),(0,j.jsx)(`th`,{scope:`col`,className:`r`,children:`消耗积分`}),(0,j.jsx)(`th`,{scope:`col`,className:`r`,children:`平均单次 Token`})]})}),(0,j.jsx)(`tbody`,{children:e.map(e=>{let t=e.displayName??e.model??`未知模型`;return(0,j.jsxs)(`tr`,{children:[(0,j.jsxs)(`td`,{className:`td-strong`,children:[t,e.tag?(0,j.jsx)(`span`,{className:`mu-tag`,children:e.tag}):null,e.multiplier==null?(0,j.jsx)(s,{content:`接口与本地快照都缺此模型倍率 —— 该行积分按中性倍率估算,不是上游真实计费`,children:(0,j.jsx)(`span`,{className:`mu-unknown`,children:`倍率未知`})}):null]}),(0,j.jsx)(`td`,{className:`r td-mono`,children:l(e.requests)}),(0,j.jsx)(`td`,{className:`r td-mono`,children:h(e.tokens??0)}),(0,j.jsx)(`td`,{className:`r td-mono`,children:o(e.share)}),(0,j.jsx)(`td`,{className:`r td-mono`,children:e.credits===null?(0,j.jsx)(s,{content:e.creditsUnknownCount?`本窗口 ${l(e.creditsUnknownCount)} 条请求上游均未回报单次费用(该上游只在账本给累计值)。真实消耗见上方「积分账本」。`:`上游未回报单次费用。真实消耗见上方「积分账本」。`,children:(0,j.jsx)(`span`,{className:`cred-unknown`,children:`--`})}):f(e.credits)}),(0,j.jsx)(`td`,{className:`r td-mono`,children:e.requests>0?h(Math.round((e.tokens??0)/e.requests)):`--`})]},e.model??t)})})]})}),(0,j.jsxs)(`div`,{className:`footer-note`,children:[`平均单次 = Token 消耗 ÷ 请求次数。接口不提供按模型的耗时,「较昨日」与「本计费周期」也无对应字段 —— 这三样一律留空而不是补一个看着合理的数。`,(0,j.jsx)(`br`,{}),`标着`,(0,j.jsx)(`b`,{children:`「倍率未知」`}),`的行,是 /v3/config 接口与本地快照都没有的模型:`,(0,j.jsx)(`b`,{children:`该行积分是按中性倍率估算的,不是上游真实计费`}),`。`]})]})}var I={ok:`额度接口正常`,quota_endpoint_not_configured:`未配置额度端点`,quota_endpoint_error:`额度端点拉取失败`};function L({quota:n,provenance:i,windowLabel:a}){let o=n.available&&n.remain!==null;return(0,j.jsxs)(g,{title:`配额数据来源`,aside:(0,j.jsx)(_,{tone:n.available?`live`:`amber`,dot:!0,children:I[n.reason]}),children:[(0,j.jsxs)(`div`,{className:`src-grid`,children:[(0,j.jsxs)(`div`,{className:`src-col`,children:[(0,j.jsxs)(`div`,{className:`src-head`,children:[(0,j.jsx)(t,{size:13,"aria-hidden":!0}),`来自上游额度接口`,(0,j.jsx)(`span`,{className:`tag tag-live`,children:`官方口径`})]}),(0,j.jsxs)(`ul`,{children:[(0,j.jsxs)(`li`,{children:[(0,j.jsx)(`b`,{children:`剩余积分`}),(0,j.jsx)(`i`,{children:`quota.remain`})]}),(0,j.jsxs)(`li`,{children:[(0,j.jsx)(`b`,{children:`总量`}),(0,j.jsx)(`i`,{children:`quota.total`})]}),(0,j.jsxs)(`li`,{children:[(0,j.jsx)(`b`,{children:`重置时间`}),(0,j.jsx)(`i`,{children:`quota.resetAt`})]})]}),(0,j.jsx)(`div`,{className:`src-state`,children:o?n.stale?(0,j.jsxs)(j.Fragment,{children:[(0,j.jsx)(r,{size:13,"aria-hidden":!0}),`上次拉取失败,当前显示的是上一次成功值(不会清空)。`]}):`已接入,随配额端点轮询刷新。`:(0,j.jsxs)(j.Fragment,{children:[`未接入 —— 上面三项显示 `,(0,j.jsx)(`i`,{children:`--`}),`。服务端不做估算,前端更不会替它编一个。`]})})]}),(0,j.jsxs)(`div`,{className:`src-col`,children:[(0,j.jsxs)(`div`,{className:`src-head`,children:[(0,j.jsx)(e,{size:13,"aria-hidden":!0}),`本机按请求累计`,(0,j.jsx)(`span`,{className:`tag tag-off`,children:`非官方口径`})]}),(0,j.jsxs)(`ul`,{children:[(0,j.jsxs)(`li`,{children:[(0,j.jsx)(`b`,{children:`已消耗积分`}),(0,j.jsx)(`i`,{children:`仅统计经本服务转发的请求,按上游实扣累加(官方客户端直连不计入)`})]}),(0,j.jsxs)(`li`,{children:[(0,j.jsxs)(`b`,{children:[a,`趋势`]}),(0,j.jsx)(`i`,{children:`本机日志按天聚合`})]}),(0,j.jsxs)(`li`,{children:[(0,j.jsx)(`b`,{children:`按模型 / 按提供商消耗`}),(0,j.jsx)(`i`,{children:`同一次聚合的一体两面`})]})]}),(0,j.jsx)(`div`,{className:`src-state`,children:`这些数即时产生,不等额度接口 —— 也正是它和「剩余积分」会对不齐的原因。`})]})]}),n.message?(0,j.jsx)(`div`,{className:`footer-note`,children:n.message}):null,(0,j.jsx)(`div`,{className:`footer-note`,children:i.note}),(0,j.jsxs)(`div`,{className:`footer-note`,children:[`官方额度接口按 `,(0,j.jsx)(`span`,{className:`code-chip`,children:`quota.pollSeconds`}),`(默认 `,(0,j.jsx)(`b`,{children:`30 秒`}),`)轮询, 所以「剩余积分」最多滞后 30 秒;本机累计的消耗是即时的。 两者最多相差 `,(0,j.jsx)(`b`,{children:`30 秒内的消耗量`}),` —— 这是取样时刻不同,不是账对不上。 来源标记:已消耗积分 `,(0,j.jsx)(`span`,{className:`code-chip`,children:i.creditsUsed}),` · `,`剩余积分 `,(0,j.jsx)(`span`,{className:`code-chip`,children:i.quotaRemain}),`。`]})]})}var R=`today`,z={today:null,"1h":null,"24h":null,"7d":7,"30d":30};function B(){let[e,t]=(0,A.useState)(()=>T()??R),n=u(()=>c.overview(e),[e],{cacheKey:`overview:${e}`});E(`usage-${e}-${n.data?`ready`:`pending`}`);let[r,i]=(0,A.useState)(`tokens`),s=n.data,p=z[e],I=s&&p?s.metrics.creditsUsed/p:null,B=s&&p?s.metrics.requests/p:null,V=s&&p?s.metrics.totalTokens/p:null,H=s?[...s.byModel].sort((e,t)=>(t.tokens??0)-(e.tokens??0)):[],U=s?[...s.byClient].sort((e,t)=>(t.tokens??0)-(e.tokens??0)):[],W=s&&s.quota.available&&s.quota.remain!==null&&I!==null&&I>0?Math.floor(s.quota.remain/I):null,G=s?s.quota.available?I===null||I<=0?`${a[s.window]}无消耗记录`:`按日均 ${f(I)} 积分估算`:`需要额度接口`:void 0,K=e=>{if(!s||s.byClient.length===0)return;let t=[...s.byClient].sort((t,n)=>(n[e]??0)-(t[e]??0));return(0,j.jsx)(k,{rows:t,metric:e,windowLabel:a[s.window],total:e===`credits`?s.metrics.creditsUsed:e===`tokens`?s.metrics.totalTokens:s.metrics.requests,totalCount:t.length})};return(0,j.jsxs)(`div`,{className:`view on`,children:[(0,j.jsx)(x,{title:`积分与用量`,status:s?(0,j.jsxs)(_,{tone:`live`,dot:!0,children:[a[s.window],` · `,m(s.generatedAt)]}):null,actions:(0,j.jsx)(S,{value:e,options:d,onChange:e=>{w(e),t(e)},width:148})}),(0,j.jsx)(`div`,{className:`view-body stack`,children:n.initial&&n.loading?(0,j.jsx)(C,{}):n.error?(0,j.jsx)(g,{children:(0,j.jsx)(v,{kind:`error`,title:`用量数据没取到`,detail:b(n.error),onRetry:n.reload})}):s?(0,j.jsxs)(j.Fragment,{children:[(0,j.jsx)(O,{metrics:s.metrics}),(0,j.jsx)(y,{items:[{label:`${a[s.window]}消耗`,value:f(s.metrics.creditsUsed),detail:`经本服务转发 · 上游实扣累计`,tip:K(`credits`),tipPos:`down`},{label:`${a[s.window]}请求`,value:l(s.metrics.requests),detail:`${l(s.metrics.activeClients)} 个密钥活跃`,tip:K(`requests`),tipPos:`down`},...I===null?[{label:`本窗口总 tokens`,value:h(s.metrics.totalTokens),detail:`输入 ${h(s.metrics.promptTokens)} · 输出 ${h(s.metrics.completionTokens)}`,tip:K(`tokens`),tipPos:`down`}]:[{label:`日均消耗`,value:f(I),detail:`${a[s.window]}消耗 ÷ ${p} 天`,tip:K(`credits`),tipPos:`down`},{label:`按当前速度可用天数`,value:W===null?`—`:l(W),detail:G,tone:s.quota.available?void 0:`amber`}]]}),(0,j.jsx)(g,{title:`${a[s.window]}趋势`,aside:(0,j.jsxs)(`span`,{className:`panel-aside-row`,children:[(0,j.jsx)(`span`,{className:`seg-tabs`,role:`group`,"aria-label":`趋势口径`,children:[`tokens`,`requests`].map(e=>(0,j.jsx)(`button`,{type:`button`,className:r===e?`on`:``,"aria-pressed":r===e,onClick:()=>i(e),children:e===`tokens`?`Token`:`请求数`},e))}),(0,j.jsxs)(_,{children:[`单位:`,M[r],` `,e===`1h`||e===`24h`||e===`today`?`/ 小时`:`/ 天`]})]}),padded:!1,children:(0,j.jsx)(`div`,{style:{padding:`0 20px 18px`},children:(0,j.jsx)(N,{points:s.trend,metric:r,avg:r===`tokens`?V:B})})}),(0,j.jsx)(g,{title:`按模型消耗明细`,aside:(0,j.jsx)(_,{children:`按 Token 排序`}),padded:!1,children:(0,j.jsx)(`div`,{style:{padding:`0 20px 18px`},children:(0,j.jsx)(F,{items:H,windowLabel:a[s.window]})})}),(0,j.jsxs)(g,{title:`按提供商消耗`,aside:(0,j.jsx)(_,{children:`按 Token 排序`}),children:[(0,j.jsx)(P,{windowLabel:a[s.window],items:U.map(e=>({key:e.clientId??`—`,label:e.client??`未识别`,value:e.tokens??0,format:`int`,trailing:`${o(e.share)} · ${f(e.credits)} 积分 · ${l(e.requests)} 次`,tip:(0,j.jsx)(D,{row:e})}))}),(0,j.jsx)(`div`,{className:`footer-note`,children:`「未识别」是正常的识别分支,不是错误 —— 没绑定密钥又没匹配到特征时归到这里。`})]}),(0,j.jsx)(L,{quota:s.quota,provenance:s.provenance,windowLabel:a[s.window]})]}):null})]})}export{B as UsagePage};