diff --git a/cmd/capi/antigravity.go b/cmd/capi/antigravity.go index 6ae251d..abd848e 100644 --- a/cmd/capi/antigravity.go +++ b/cmd/capi/antigravity.go @@ -28,6 +28,14 @@ const ( antigravityOAuthClientID = "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com" antigravityTokenEndpoint = "https://oauth2.googleapis.com/token" + // Local-authorization (loopback) OAuth. The admin opens the Google consent + // page, logs in, and pastes the localhost callback URL back — the same + // copy-paste flow codex uses. The Antigravity client is a Google "Desktop + // app" OAuth client, so Google accepts any http://localhost redirect. + antigravityOAuthAuthorizeEndpoint = "https://accounts.google.com/o/oauth2/v2/auth" + antigravityOAuthRedirectURI = "http://localhost:8788/oauth2callback" + antigravityOAuthScope = "openid https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/cloud-platform" + // Consumer credentials default to the daily host for generateContent while // project discovery (loadCodeAssist) goes to the production host. antigravityBaseURLDaily = "https://daily-cloudcode-pa.googleapis.com" @@ -245,6 +253,81 @@ func (s *Server) refreshAntigravityAccount(refreshToken string) (OpenAIRefreshRe return result, nil } +// antigravityAuthorizeURL builds the Google OAuth consent URL for the local +// authorization flow. access_type=offline + prompt=consent force Google to +// return a refresh_token even when the account has consented before. +func antigravityAuthorizeURL(challenge, state string) string { + params := url.Values{} + params.Set("response_type", "code") + params.Set("client_id", antigravityOAuthClientID) + params.Set("redirect_uri", antigravityOAuthRedirectURI) + params.Set("scope", antigravityOAuthScope) + params.Set("code_challenge", challenge) + params.Set("code_challenge_method", "S256") + params.Set("access_type", "offline") + params.Set("prompt", "consent") + params.Set("state", state) + return antigravityOAuthAuthorizeEndpoint + "?" + params.Encode() +} + +// exchangeAntigravityOAuthCode exchanges a Google authorization code + PKCE +// verifier for Antigravity (Cloud Code) tokens, mirroring the refresh call but +// with grant_type=authorization_code. +func (s *Server) exchangeAntigravityOAuthCode(code, verifier string) (OpenAIRefreshResult, error) { + form := url.Values{} + form.Set("grant_type", "authorization_code") + form.Set("client_id", antigravityOAuthClientID) + form.Set("client_secret", antigravityOAuthClientSecret) + form.Set("code", code) + form.Set("redirect_uri", antigravityOAuthRedirectURI) + form.Set("code_verifier", verifier) + + request, err := http.NewRequest(http.MethodPost, antigravityTokenEndpoint, strings.NewReader(form.Encode())) + if err != nil { + return OpenAIRefreshResult{}, err + } + request.Header.Set("Content-Type", "application/x-www-form-urlencoded") + request.Header.Set("Accept", "application/json") + + response, err := s.httpClient.Do(request) + if err != nil { + return OpenAIRefreshResult{}, err + } + defer response.Body.Close() + + content, err := io.ReadAll(io.LimitReader(response.Body, 1<<20)) + if err != nil { + return OpenAIRefreshResult{}, err + } + if response.StatusCode < 200 || response.StatusCode >= 300 { + providerErr := providerErrorFromUpstream(response.StatusCode, content) + return OpenAIRefreshResult{}, fmt.Errorf("%s", providerErr.Message) + } + + var body struct { + AccessToken string `json:"access_token"` + RefreshToken string `json:"refresh_token"` + IDToken string `json:"id_token"` + ExpiresIn int `json:"expires_in"` + TokenType string `json:"token_type"` + } + if err := json.Unmarshal(content, &body); err != nil { + return OpenAIRefreshResult{}, err + } + if strings.TrimSpace(body.AccessToken) == "" { + return OpenAIRefreshResult{}, fmt.Errorf("授权响应缺少 access_token") + } + result := OpenAIRefreshResult{ + AccessToken: strings.TrimSpace(body.AccessToken), + RefreshToken: strings.TrimSpace(body.RefreshToken), + IDToken: strings.TrimSpace(body.IDToken), + } + if body.ExpiresIn > 0 { + result.ExpiresAt = time.Now().Add(time.Duration(body.ExpiresIn) * time.Second).UTC().Format(time.RFC3339Nano) + } + return result, nil +} + // resolveAntigravityProject discovers the GCP project bound to the account via // loadCodeAssist. The project is required on every generateContent request. func (s *Server) resolveAntigravityProject(account OpenAIAccount, accessToken string) (string, error) { diff --git a/cmd/capi/antigravity_test.go b/cmd/capi/antigravity_test.go index 28d497c..98d4d70 100644 --- a/cmd/capi/antigravity_test.go +++ b/cmd/capi/antigravity_test.go @@ -2,6 +2,7 @@ package main import ( "encoding/json" + "net/url" "strings" "testing" @@ -179,3 +180,35 @@ func TestAntigravityClientSecretDecodes(t *testing.T) { t.Fatalf("client secret decoded to garbage") } } + +func TestAntigravityAuthorizeURL(t *testing.T) { + raw := antigravityAuthorizeURL("chal-123", "state-abc") + parsed, err := url.Parse(raw) + if err != nil { + t.Fatalf("authorize URL does not parse: %v", err) + } + if got := parsed.Scheme + "://" + parsed.Host + parsed.Path; got != antigravityOAuthAuthorizeEndpoint { + t.Fatalf("authorize endpoint = %q, want %q", got, antigravityOAuthAuthorizeEndpoint) + } + query := parsed.Query() + checks := map[string]string{ + "response_type": "code", + "client_id": antigravityOAuthClientID, + "redirect_uri": antigravityOAuthRedirectURI, + "scope": antigravityOAuthScope, + "code_challenge": "chal-123", + "code_challenge_method": "S256", + "access_type": "offline", + "prompt": "consent", + "state": "state-abc", + } + for key, want := range checks { + if got := query.Get(key); got != want { + t.Fatalf("authorize param %q = %q, want %q", key, got, want) + } + } + // A refresh token is only issued when cloud-platform scope is granted. + if !strings.Contains(query.Get("scope"), "cloud-platform") { + t.Fatalf("scope must request cloud-platform, got %q", query.Get("scope")) + } +} diff --git a/cmd/capi/main.go b/cmd/capi/main.go index a3e23fd..6638275 100644 --- a/cmd/capi/main.go +++ b/cmd/capi/main.go @@ -957,6 +957,8 @@ func (s *Server) registerRoutes(router *gin.Engine) { admin.POST("/channels/:id/import-openai-accounts", s.importOpenAIAccounts) admin.POST("/channels/:id/openai-oauth/start", s.startOpenAIOAuth) admin.POST("/channels/:id/openai-oauth/complete", s.completeOpenAIOAuth) + admin.POST("/channels/:id/antigravity-oauth/start", s.startAntigravityOAuth) + admin.POST("/channels/:id/antigravity-oauth/complete", s.completeAntigravityOAuth) admin.POST("/channels/:id/openai-accounts/check", s.checkOpenAIAccounts) admin.POST("/channels/:id/openai-accounts/deduplicate", s.deduplicateOpenAIAccounts) admin.DELETE("/channels/:id/openai-accounts/:accountId", s.deleteOpenAIAccount) @@ -3506,6 +3508,142 @@ func (s *Server) completeOpenAIOAuth(c *gin.Context) { }) } +// startAntigravityOAuth begins a Google OAuth (PKCE) local authorization for an +// Antigravity channel. It mirrors startOpenAIOAuth but targets Google's consent +// endpoint; the resulting account carries a Google refresh token. +func (s *Server) startAntigravityOAuth(c *gin.Context) { + s.mu.Lock() + channel := s.findChannel(c.Param("id")) + if channel == nil { + s.mu.Unlock() + c.JSON(http.StatusNotFound, gin.H{"error": gin.H{"message": "Channel not found"}}) + return + } + s.mu.Unlock() + + verifier, challenge, err := newPKCEPair() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": gin.H{"message": "Failed to create PKCE challenge"}}) + return + } + state := randomHex(24) + + s.mu.Lock() + s.pruneOpenAIOAuthFlowsLocked() + s.openAIOAuthFlows[state] = openAIOAuthFlow{CodeVerifier: verifier, CreatedAt: time.Now().UTC()} + s.mu.Unlock() + + c.JSON(http.StatusOK, gin.H{ + "authorizeUrl": antigravityAuthorizeURL(challenge, state), + "state": state, + "redirectUri": antigravityOAuthRedirectURI, + }) +} + +// completeAntigravityOAuth finishes the Google OAuth flow: it verifies the state, +// exchanges the code with the stored PKCE verifier, and stores the resulting +// Antigravity account (with its Google refresh token) in the channel's pool. +func (s *Server) completeAntigravityOAuth(c *gin.Context) { + var body struct { + CallbackURL string `json:"callbackUrl"` + Code string `json:"code"` + State string `json:"state"` + } + _ = c.ShouldBindJSON(&body) + + code := strings.TrimSpace(body.Code) + state := strings.TrimSpace(body.State) + if raw := strings.TrimSpace(body.CallbackURL); raw != "" { + if parsed, err := url.Parse(raw); err == nil { + query := parsed.Query() + if v := strings.TrimSpace(query.Get("code")); v != "" { + code = v + } + if v := strings.TrimSpace(query.Get("state")); v != "" { + state = v + } + } + } + if code == "" { + validationError(c, "缺少授权 code,请粘贴完整回调地址") + return + } + + s.mu.Lock() + channel := s.findChannel(c.Param("id")) + if channel == nil { + s.mu.Unlock() + c.JSON(http.StatusNotFound, gin.H{"error": gin.H{"message": "Channel not found"}}) + return + } + flow, ok := s.openAIOAuthFlows[state] + if ok { + delete(s.openAIOAuthFlows, state) + } + s.mu.Unlock() + if !ok { + validationError(c, "授权状态已失效,请重新发起授权") + return + } + + tokens, err := s.exchangeAntigravityOAuthCode(code, flow.CodeVerifier) + if err != nil { + s.openAIError(c, http.StatusBadGateway, "oauth_exchange_failed", err.Error(), "api_error", nil) + return + } + + email, name := jwtEmailName(tokens.IDToken) + + s.mu.Lock() + defer s.mu.Unlock() + channel = s.findChannel(c.Param("id")) + if channel == nil { + c.JSON(http.StatusNotFound, gin.H{"error": gin.H{"message": "Channel not found"}}) + return + } + s.ensureAntigravityChannelLocked(channel) + + protectedAccess, err := s.protectSecret(tokens.AccessToken) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": gin.H{"message": "Failed to protect access token"}}) + return + } + protectedRefresh := "" + if strings.TrimSpace(tokens.RefreshToken) != "" { + if protectedRefresh, err = s.protectSecret(tokens.RefreshToken); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": gin.H{"message": "Failed to protect refresh token"}}) + return + } + } + protectedID := "" + if strings.TrimSpace(tokens.IDToken) != "" { + if protectedID, err = s.protectSecret(tokens.IDToken); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": gin.H{"message": "Failed to protect id token"}}) + return + } + } + stored := OpenAIAccount{ + ID: newID("oaiacc"), + Name: firstNonEmptyString(name, email), + Email: email, + AccessToken: protectedAccess, + RefreshToken: protectedRefresh, + IDToken: protectedID, + ExpiresAt: tokens.ExpiresAt, + LastRefresh: now(), + Source: "antigravity", + ImportedAt: time.Now().UTC().Format(time.RFC3339), + Status: "unchecked", + } + channel.OpenAIAccounts = append(channel.OpenAIAccounts, stored) + s.saveStateLocked() + + c.JSON(http.StatusCreated, gin.H{ + "account": publicOpenAIAccount(stored), + "channel": publicChannel(*channel), + }) +} + // exchangeOpenAIOAuthCode exchanges an authorization code + PKCE verifier for // ChatGPT tokens. func (s *Server) exchangeOpenAIOAuthCode(code, verifier string) (OpenAIRefreshResult, error) { diff --git a/dist/assets/index-B276P45A.js b/dist/assets/index-B276P45A.js deleted file mode 100644 index 6fecadf..0000000 --- a/dist/assets/index-B276P45A.js +++ /dev/null @@ -1,43 +0,0 @@ -(function(){const f=document.createElement("link").relList;if(f&&f.supports&&f.supports("modulepreload"))return;for(const A of document.querySelectorAll('link[rel="modulepreload"]'))r(A);new MutationObserver(A=>{for(const T of A)if(T.type==="childList")for(const L of T.addedNodes)L.tagName==="LINK"&&L.rel==="modulepreload"&&r(L)}).observe(document,{childList:!0,subtree:!0});function p(A){const T={};return A.integrity&&(T.integrity=A.integrity),A.referrerPolicy&&(T.referrerPolicy=A.referrerPolicy),A.crossOrigin==="use-credentials"?T.credentials="include":A.crossOrigin==="anonymous"?T.credentials="omit":T.credentials="same-origin",T}function r(A){if(A.ep)return;A.ep=!0;const T=p(A);fetch(A.href,T)}})();function q0(u){return u&&u.__esModule&&Object.prototype.hasOwnProperty.call(u,"default")?u.default:u}var Qc={exports:{}},is={};var tm;function G0(){if(tm)return is;tm=1;var u=Symbol.for("react.transitional.element"),f=Symbol.for("react.fragment");function p(r,A,T){var L=null;if(T!==void 0&&(L=""+T),A.key!==void 0&&(L=""+A.key),"key"in A){T={};for(var $ in A)$!=="key"&&(T[$]=A[$])}else T=A;return A=T.ref,{$$typeof:u,type:r,key:L,ref:A!==void 0?A:null,props:T}}return is.Fragment=f,is.jsx=p,is.jsxs=p,is}var lm;function Y0(){return lm||(lm=1,Qc.exports=G0()),Qc.exports}var n=Y0(),Xc={exports:{}},Ae={};var am;function L0(){if(am)return Ae;am=1;var u=Symbol.for("react.transitional.element"),f=Symbol.for("react.portal"),p=Symbol.for("react.fragment"),r=Symbol.for("react.strict_mode"),A=Symbol.for("react.profiler"),T=Symbol.for("react.consumer"),L=Symbol.for("react.context"),$=Symbol.for("react.forward_ref"),C=Symbol.for("react.suspense"),g=Symbol.for("react.memo"),G=Symbol.for("react.lazy"),z=Symbol.for("react.activity"),V=Symbol.iterator;function W(m){return m===null||typeof m!="object"?null:(m=V&&m[V]||m["@@iterator"],typeof m=="function"?m:null)}var fe={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},te=Object.assign,ae={};function ie(m,h,M){this.props=m,this.context=h,this.refs=ae,this.updater=M||fe}ie.prototype.isReactComponent={},ie.prototype.setState=function(m,h){if(typeof m!="object"&&typeof m!="function"&&m!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,m,h,"setState")},ie.prototype.forceUpdate=function(m){this.updater.enqueueForceUpdate(this,m,"forceUpdate")};function be(){}be.prototype=ie.prototype;function Y(m,h,M){this.props=m,this.context=h,this.refs=ae,this.updater=M||fe}var xe=Y.prototype=new be;xe.constructor=Y,te(xe,ie.prototype),xe.isPureReactComponent=!0;var P=Array.isArray;function he(){}var _={H:null,A:null,T:null,S:null},ne=Object.prototype.hasOwnProperty;function me(m,h,M){var Q=M.ref;return{$$typeof:u,type:m,key:h,ref:Q!==void 0?Q:null,props:M}}function Ce(m,h){return me(m.type,h,m.props)}function Me(m){return typeof m=="object"&&m!==null&&m.$$typeof===u}function ue(m){var h={"=":"=0",":":"=2"};return"$"+m.replace(/[=:]/g,function(M){return h[M]})}var K=/\/+/g;function de(m,h){return typeof m=="object"&&m!==null&&m.key!=null?ue(""+m.key):h.toString(36)}function J(m){switch(m.status){case"fulfilled":return m.value;case"rejected":throw m.reason;default:switch(typeof m.status=="string"?m.then(he,he):(m.status="pending",m.then(function(h){m.status==="pending"&&(m.status="fulfilled",m.value=h)},function(h){m.status==="pending"&&(m.status="rejected",m.reason=h)})),m.status){case"fulfilled":return m.value;case"rejected":throw m.reason}}throw m}function N(m,h,M,Q,ee){var Ne=typeof m;(Ne==="undefined"||Ne==="boolean")&&(m=null);var O=!1;if(m===null)O=!0;else switch(Ne){case"bigint":case"string":case"number":O=!0;break;case"object":switch(m.$$typeof){case u:case f:O=!0;break;case G:return O=m._init,N(O(m._payload),h,M,Q,ee)}}if(O)return ee=ee(m),O=Q===""?"."+de(m,0):Q,P(ee)?(M="",O!=null&&(M=O.replace(K,"$&/")+"/"),N(ee,h,M,"",function(St){return St})):ee!=null&&(Me(ee)&&(ee=Ce(ee,M+(ee.key==null||m&&m.key===ee.key?"":(""+ee.key).replace(K,"$&/")+"/")+O)),h.push(ee)),1;O=0;var ye=Q===""?".":Q+":";if(P(m))for(var ce=0;ce>>1,se=N[X];if(0>>1;XA(M,H))QA(ee,M)?(N[X]=ee,N[Q]=H,X=Q):(N[X]=M,N[h]=H,X=h);else if(QA(ee,H))N[X]=ee,N[Q]=H,X=Q;else break e}}return k}function A(N,k){var H=N.sortIndex-k.sortIndex;return H!==0?H:N.id-k.id}if(u.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var T=performance;u.unstable_now=function(){return T.now()}}else{var L=Date,$=L.now();u.unstable_now=function(){return L.now()-$}}var C=[],g=[],G=1,z=null,V=3,W=!1,fe=!1,te=!1,ae=!1,ie=typeof setTimeout=="function"?setTimeout:null,be=typeof clearTimeout=="function"?clearTimeout:null,Y=typeof setImmediate<"u"?setImmediate:null;function xe(N){for(var k=p(g);k!==null;){if(k.callback===null)r(g);else if(k.startTime<=N)r(g),k.sortIndex=k.expirationTime,f(C,k);else break;k=p(g)}}function P(N){if(te=!1,xe(N),!fe)if(p(C)!==null)fe=!0,he||(he=!0,ue());else{var k=p(g);k!==null&&J(P,k.startTime-N)}}var he=!1,_=-1,ne=5,me=-1;function Ce(){return ae?!0:!(u.unstable_now()-meN&&Ce());){var X=z.callback;if(typeof X=="function"){z.callback=null,V=z.priorityLevel;var se=X(z.expirationTime<=N);if(N=u.unstable_now(),typeof se=="function"){z.callback=se,xe(N),k=!0;break t}z===p(C)&&r(C),xe(N)}else r(C);z=p(C)}if(z!==null)k=!0;else{var m=p(g);m!==null&&J(P,m.startTime-N),k=!1}}break e}finally{z=null,V=H,W=!1}k=void 0}}finally{k?ue():he=!1}}}var ue;if(typeof Y=="function")ue=function(){Y(Me)};else if(typeof MessageChannel<"u"){var K=new MessageChannel,de=K.port2;K.port1.onmessage=Me,ue=function(){de.postMessage(null)}}else ue=function(){ie(Me,0)};function J(N,k){_=ie(function(){N(u.unstable_now())},k)}u.unstable_IdlePriority=5,u.unstable_ImmediatePriority=1,u.unstable_LowPriority=4,u.unstable_NormalPriority=3,u.unstable_Profiling=null,u.unstable_UserBlockingPriority=2,u.unstable_cancelCallback=function(N){N.callback=null},u.unstable_forceFrameRate=function(N){0>N||125X?(N.sortIndex=H,f(g,N),p(C)===null&&N===p(g)&&(te?(be(_),_=-1):te=!0,J(P,H-X))):(N.sortIndex=se,f(C,N),fe||W||(fe=!0,he||(he=!0,ue()))),N},u.unstable_shouldYield=Ce,u.unstable_wrapCallback=function(N){var k=V;return function(){var H=V;V=k;try{return N.apply(this,arguments)}finally{V=H}}}})(Vc)),Vc}var im;function X0(){return im||(im=1,Zc.exports=Q0()),Zc.exports}var Jc={exports:{}},gt={};var um;function K0(){if(um)return gt;um=1;var u=eo();function f(C){var g="https://react.dev/errors/"+C;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(u)}catch(f){console.error(f)}}return u(),Jc.exports=K0(),Jc.exports}var om;function V0(){if(om)return us;om=1;var u=X0(),f=eo(),p=Z0();function r(e){var t="https://react.dev/errors/"+e;if(1se||(e.current=X[se],X[se]=null,se--)}function M(e,t){se++,X[se]=e.current,e.current=t}var Q=m(null),ee=m(null),Ne=m(null),O=m(null);function ye(e,t){switch(M(Ne,t),M(ee,e),M(Q,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?Af(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=Af(t),e=Cf(t,e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}h(Q),M(Q,e)}function ce(){h(Q),h(ee),h(Ne)}function St(e){e.memoizedState!==null&&M(O,e);var t=Q.current,l=Cf(t,e.type);t!==l&&(M(ee,e),M(Q,l))}function F(e){ee.current===e&&(h(Q),h(ee)),O.current===e&&(h(O),ls._currentValue=H)}var $e,rt;function We(e){if($e===void 0)try{throw Error()}catch(l){var t=l.stack.trim().match(/\n( *(at )?)/);$e=t&&t[1]||"",rt=-1)":-1s||d[a]!==j[s]){var D=` -`+d[a].replace(" at new "," at ");return e.displayName&&D.includes("")&&(D=D.replace("",e.displayName)),D}while(1<=a&&0<=s);break}}}finally{bt=!1,Error.prepareStackTrace=l}return(l=e?e.displayName||e.name:"")?We(l):""}function tl(e,t){switch(e.tag){case 26:case 27:case 5:return We(e.type);case 16:return We("Lazy");case 13:return e.child!==t&&t!==null?We("Suspense Fallback"):We("Suspense");case 19:return We("SuspenseList");case 0:case 15:return Ut(e.type,!1);case 11:return Ut(e.type.render,!1);case 1:return Ut(e.type,!0);case 31:return We("Activity");default:return""}}function ll(e){try{var t="",l=null;do t+=tl(e,l),l=e,e=e.return;while(e);return t}catch(a){return` -Error generating stack: `+a.message+` -`+a.stack}}var U=Object.prototype.hasOwnProperty,B=u.unstable_scheduleCallback,Be=u.unstable_cancelCallback,Fe=u.unstable_shouldYield,nt=u.unstable_requestPaint,et=u.unstable_now,zi=u.unstable_getCurrentPriorityLevel,hn=u.unstable_ImmediatePriority,ia=u.unstable_UserBlockingPriority,ua=u.unstable_NormalPriority,Oi=u.unstable_LowPriority,R=u.unstable_IdlePriority,Z=u.log,le=u.unstable_setDisableYieldValue,I=null,ge=null;function qe(e){if(typeof Z=="function"&&le(e),ge&&typeof ge.setStrictMode=="function")try{ge.setStrictMode(I,e)}catch{}}var Ke=Math.clz32?Math.clz32:ca,Rt=Math.log,Rl=Math.LN2;function ca(e){return e>>>=0,e===0?32:31-(Rt(e)/Rl|0)|0}var Ea=256,Ma=262144,wl=4194304;function hl(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function os(e,t,l){var a=e.pendingLanes;if(a===0)return 0;var s=0,i=e.suspendedLanes,c=e.pingedLanes;e=e.warmLanes;var o=a&134217727;return o!==0?(a=o&~i,a!==0?s=hl(a):(c&=o,c!==0?s=hl(c):l||(l=o&~e,l!==0&&(s=hl(l))))):(o=a&~i,o!==0?s=hl(o):c!==0?s=hl(c):l||(l=a&~e,l!==0&&(s=hl(l)))),s===0?0:t!==0&&t!==s&&(t&i)===0&&(i=s&-s,l=t&-t,i>=l||i===32&&(l&4194048)!==0)?t:s}function pn(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Cm(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function ao(){var e=wl;return wl<<=1,(wl&62914560)===0&&(wl=4194304),e}function _i(e){for(var t=[],l=0;31>l;l++)t.push(e);return t}function vn(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function Tm(e,t,l,a,s,i){var c=e.pendingLanes;e.pendingLanes=l,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=l,e.entangledLanes&=l,e.errorRecoveryDisabledLanes&=l,e.shellSuspendCounter=0;var o=e.entanglements,d=e.expirationTimes,j=e.hiddenUpdates;for(l=c&~l;0"u")return null;try{return e.activeElement||e.body}catch{return e.body}}var Dm=/[\n"\\]/g;function Xt(e){return e.replace(Dm,function(t){return"\\"+t.charCodeAt(0).toString(16)+" "})}function Bi(e,t,l,a,s,i,c,o){e.name="",c!=null&&typeof c!="function"&&typeof c!="symbol"&&typeof c!="boolean"?e.type=c:e.removeAttribute("type"),t!=null?c==="number"?(t===0&&e.value===""||e.value!=t)&&(e.value=""+Qt(t)):e.value!==""+Qt(t)&&(e.value=""+Qt(t)):c!=="submit"&&c!=="reset"||e.removeAttribute("value"),t!=null?qi(e,c,Qt(t)):l!=null?qi(e,c,Qt(l)):a!=null&&e.removeAttribute("value"),s==null&&i!=null&&(e.defaultChecked=!!i),s!=null&&(e.checked=s&&typeof s!="function"&&typeof s!="symbol"),o!=null&&typeof o!="function"&&typeof o!="symbol"&&typeof o!="boolean"?e.name=""+Qt(o):e.removeAttribute("name")}function yo(e,t,l,a,s,i,c,o){if(i!=null&&typeof i!="function"&&typeof i!="symbol"&&typeof i!="boolean"&&(e.type=i),t!=null||l!=null){if(!(i!=="submit"&&i!=="reset"||t!=null)){Hi(e);return}l=l!=null?""+Qt(l):"",t=t!=null?""+Qt(t):l,o||t===e.value||(e.value=t),e.defaultValue=t}a=a??s,a=typeof a!="function"&&typeof a!="symbol"&&!!a,e.checked=o?e.checked:!!a,e.defaultChecked=!!a,c!=null&&typeof c!="function"&&typeof c!="symbol"&&typeof c!="boolean"&&(e.name=c),Hi(e)}function qi(e,t,l){t==="number"&&fs(e.ownerDocument)===e||e.defaultValue===""+l||(e.defaultValue=""+l)}function Ra(e,t,l,a){if(e=e.options,t){t={};for(var s=0;s"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Qi=!1;if(yl)try{var xn={};Object.defineProperty(xn,"passive",{get:function(){Qi=!0}}),window.addEventListener("test",xn,xn),window.removeEventListener("test",xn,xn)}catch{Qi=!1}var Bl=null,Xi=null,hs=null;function Ao(){if(hs)return hs;var e,t=Xi,l=t.length,a,s="value"in Bl?Bl.value:Bl.textContent,i=s.length;for(e=0;e=Nn),Oo=" ",_o=!1;function Do(e,t){switch(e){case"keyup":return ih.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Uo(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var qa=!1;function ch(e,t){switch(e){case"compositionend":return Uo(t);case"keypress":return t.which!==32?null:(_o=!0,Oo);case"textInput":return e=t.data,e===Oo&&_o?null:e;default:return null}}function oh(e,t){if(qa)return e==="compositionend"||!$i&&Do(e,t)?(e=Ao(),hs=Xi=Bl=null,qa=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:l,offset:t-e};e=a}e:{for(;l;){if(l.nextSibling){l=l.nextSibling;break e}l=l.parentNode}l=void 0}l=Lo(l)}}function Qo(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Qo(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Xo(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=fs(e.document);t instanceof e.HTMLIFrameElement;){try{var l=typeof t.contentWindow.location.href=="string"}catch{l=!1}if(l)e=t.contentWindow;else break;t=fs(e.document)}return t}function Ii(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}var yh=yl&&"documentMode"in document&&11>=document.documentMode,Ga=null,Pi=null,En=null,eu=!1;function Ko(e,t,l){var a=l.window===l?l.document:l.nodeType===9?l:l.ownerDocument;eu||Ga==null||Ga!==fs(a)||(a=Ga,"selectionStart"in a&&Ii(a)?a={start:a.selectionStart,end:a.selectionEnd}:(a=(a.ownerDocument&&a.ownerDocument.defaultView||window).getSelection(),a={anchorNode:a.anchorNode,anchorOffset:a.anchorOffset,focusNode:a.focusNode,focusOffset:a.focusOffset}),En&&Tn(En,a)||(En=a,a=ui(Pi,"onSelect"),0>=c,s-=c,ol=1<<32-Ke(t)+s|l<Ee?(De=re,re=null):De=re.sibling;var we=S(y,re,x[Ee],w);if(we===null){re===null&&(re=De);break}e&&re&&we.alternate===null&&t(y,re),v=i(we,v,Ee),Re===null?pe=we:Re.sibling=we,Re=we,re=De}if(Ee===x.length)return l(y,re),Ue&&bl(y,Ee),pe;if(re===null){for(;EeEe?(De=re,re=null):De=re.sibling;var sa=S(y,re,we.value,w);if(sa===null){re===null&&(re=De);break}e&&re&&sa.alternate===null&&t(y,re),v=i(sa,v,Ee),Re===null?pe=sa:Re.sibling=sa,Re=sa,re=De}if(we.done)return l(y,re),Ue&&bl(y,Ee),pe;if(re===null){for(;!we.done;Ee++,we=x.next())we=q(y,we.value,w),we!==null&&(v=i(we,v,Ee),Re===null?pe=we:Re.sibling=we,Re=we);return Ue&&bl(y,Ee),pe}for(re=a(re);!we.done;Ee++,we=x.next())we=E(re,y,Ee,we.value,w),we!==null&&(e&&we.alternate!==null&&re.delete(we.key===null?Ee:we.key),v=i(we,v,Ee),Re===null?pe=we:Re.sibling=we,Re=we);return e&&re.forEach(function(B0){return t(y,B0)}),Ue&&bl(y,Ee),pe}function Qe(y,v,x,w){if(typeof x=="object"&&x!==null&&x.type===te&&x.key===null&&(x=x.props.children),typeof x=="object"&&x!==null){switch(x.$$typeof){case W:e:{for(var pe=x.key;v!==null;){if(v.key===pe){if(pe=x.type,pe===te){if(v.tag===7){l(y,v.sibling),w=s(v,x.props.children),w.return=y,y=w;break e}}else if(v.elementType===pe||typeof pe=="object"&&pe!==null&&pe.$$typeof===ne&&ba(pe)===v.type){l(y,v.sibling),w=s(v,x.props),Un(w,x),w.return=y,y=w;break e}l(y,v);break}else t(y,v);v=v.sibling}x.type===te?(w=ha(x.props.children,y.mode,w,x.key),w.return=y,y=w):(w=As(x.type,x.key,x.props,null,y.mode,w),Un(w,x),w.return=y,y=w)}return c(y);case fe:e:{for(pe=x.key;v!==null;){if(v.key===pe)if(v.tag===4&&v.stateNode.containerInfo===x.containerInfo&&v.stateNode.implementation===x.implementation){l(y,v.sibling),w=s(v,x.children||[]),w.return=y,y=w;break e}else{l(y,v);break}else t(y,v);v=v.sibling}w=uu(x,y.mode,w),w.return=y,y=w}return c(y);case ne:return x=ba(x),Qe(y,v,x,w)}if(J(x))return oe(y,v,x,w);if(ue(x)){if(pe=ue(x),typeof pe!="function")throw Error(r(150));return x=pe.call(x),Se(y,v,x,w)}if(typeof x.then=="function")return Qe(y,v,_s(x),w);if(x.$$typeof===Y)return Qe(y,v,Es(y,x),w);Ds(y,x)}return typeof x=="string"&&x!==""||typeof x=="number"||typeof x=="bigint"?(x=""+x,v!==null&&v.tag===6?(l(y,v.sibling),w=s(v,x),w.return=y,y=w):(l(y,v),w=iu(x,y.mode,w),w.return=y,y=w),c(y)):l(y,v)}return function(y,v,x,w){try{Dn=0;var pe=Qe(y,v,x,w);return Wa=null,pe}catch(re){if(re===$a||re===zs)throw re;var Re=Ht(29,re,null,y.mode);return Re.lanes=w,Re.return=y,Re}}}var ja=hr(!0),pr=hr(!1),kl=!1;function bu(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function xu(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function Ql(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function Xl(e,t,l){var a=e.updateQueue;if(a===null)return null;if(a=a.shared,(He&2)!==0){var s=a.pending;return s===null?t.next=t:(t.next=s.next,s.next=t),a.pending=t,t=Ns(e),Io(e,null,l),t}return Ss(e,a,t,l),Ns(e)}function Rn(e,t,l){if(t=t.updateQueue,t!==null&&(t=t.shared,(l&4194048)!==0)){var a=t.lanes;a&=e.pendingLanes,l|=a,t.lanes=l,so(e,l)}}function ju(e,t){var l=e.updateQueue,a=e.alternate;if(a!==null&&(a=a.updateQueue,l===a)){var s=null,i=null;if(l=l.firstBaseUpdate,l!==null){do{var c={lane:l.lane,tag:l.tag,payload:l.payload,callback:null,next:null};i===null?s=i=c:i=i.next=c,l=l.next}while(l!==null);i===null?s=i=t:i=i.next=t}else s=i=t;l={baseState:a.baseState,firstBaseUpdate:s,lastBaseUpdate:i,shared:a.shared,callbacks:a.callbacks},e.updateQueue=l;return}e=l.lastBaseUpdate,e===null?l.firstBaseUpdate=t:e.next=t,l.lastBaseUpdate=t}var Su=!1;function wn(){if(Su){var e=Ja;if(e!==null)throw e}}function Hn(e,t,l,a){Su=!1;var s=e.updateQueue;kl=!1;var i=s.firstBaseUpdate,c=s.lastBaseUpdate,o=s.shared.pending;if(o!==null){s.shared.pending=null;var d=o,j=d.next;d.next=null,c===null?i=j:c.next=j,c=d;var D=e.alternate;D!==null&&(D=D.updateQueue,o=D.lastBaseUpdate,o!==c&&(o===null?D.firstBaseUpdate=j:o.next=j,D.lastBaseUpdate=d))}if(i!==null){var q=s.baseState;c=0,D=j=d=null,o=i;do{var S=o.lane&-536870913,E=S!==o.lane;if(E?(_e&S)===S:(a&S)===S){S!==0&&S===Va&&(Su=!0),D!==null&&(D=D.next={lane:0,tag:o.tag,payload:o.payload,callback:null,next:null});e:{var oe=e,Se=o;S=t;var Qe=l;switch(Se.tag){case 1:if(oe=Se.payload,typeof oe=="function"){q=oe.call(Qe,q,S);break e}q=oe;break e;case 3:oe.flags=oe.flags&-65537|128;case 0:if(oe=Se.payload,S=typeof oe=="function"?oe.call(Qe,q,S):oe,S==null)break e;q=z({},q,S);break e;case 2:kl=!0}}S=o.callback,S!==null&&(e.flags|=64,E&&(e.flags|=8192),E=s.callbacks,E===null?s.callbacks=[S]:E.push(S))}else E={lane:S,tag:o.tag,payload:o.payload,callback:o.callback,next:null},D===null?(j=D=E,d=q):D=D.next=E,c|=S;if(o=o.next,o===null){if(o=s.shared.pending,o===null)break;E=o,o=E.next,E.next=null,s.lastBaseUpdate=E,s.shared.pending=null}}while(!0);D===null&&(d=q),s.baseState=d,s.firstBaseUpdate=j,s.lastBaseUpdate=D,i===null&&(s.shared.lanes=0),$l|=c,e.lanes=c,e.memoizedState=q}}function vr(e,t){if(typeof e!="function")throw Error(r(191,e));e.call(t)}function yr(e,t){var l=e.callbacks;if(l!==null)for(e.callbacks=null,e=0;ei?i:8;var c=N.T,o={};N.T=o,Lu(e,!1,t,l);try{var d=s(),j=N.S;if(j!==null&&j(o,d),d!==null&&typeof d=="object"&&typeof d.then=="function"){var D=Th(d,a);Gn(e,t,D,Lt(e))}else Gn(e,t,a,Lt(e))}catch(q){Gn(e,t,{then:function(){},status:"rejected",reason:q},Lt())}finally{k.p=i,c!==null&&o.types!==null&&(c.types=o.types),N.T=c}}function Dh(){}function Gu(e,t,l,a){if(e.tag!==5)throw Error(r(476));var s=$r(e).queue;Jr(e,s,t,H,l===null?Dh:function(){return Wr(e),l(a)})}function $r(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:H,baseState:H,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Nl,lastRenderedState:H},next:null};var l={};return t.next={memoizedState:l,baseState:l,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Nl,lastRenderedState:l},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function Wr(e){var t=$r(e);t.next===null&&(t=e.alternate.memoizedState),Gn(e,t.next.queue,{},Lt())}function Yu(){return pt(ls)}function Fr(){return lt().memoizedState}function Ir(){return lt().memoizedState}function Uh(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var l=Lt();e=Ql(l);var a=Xl(t,e,l);a!==null&&(zt(a,t,l),Rn(a,t,l)),t={cache:pu()},e.payload=t;return}t=t.return}}function Rh(e,t,l){var a=Lt();l={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null},ks(e)?ed(t,l):(l=nu(e,t,l,a),l!==null&&(zt(l,e,a),td(l,t,a)))}function Pr(e,t,l){var a=Lt();Gn(e,t,l,a)}function Gn(e,t,l,a){var s={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null};if(ks(e))ed(t,s);else{var i=e.alternate;if(e.lanes===0&&(i===null||i.lanes===0)&&(i=t.lastRenderedReducer,i!==null))try{var c=t.lastRenderedState,o=i(c,l);if(s.hasEagerState=!0,s.eagerState=o,wt(o,c))return Ss(e,t,s,0),Xe===null&&js(),!1}catch{}if(l=nu(e,t,s,a),l!==null)return zt(l,e,a),td(l,t,a),!0}return!1}function Lu(e,t,l,a){if(a={lane:2,revertLane:bc(),gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null},ks(e)){if(t)throw Error(r(479))}else t=nu(e,l,a,2),t!==null&&zt(t,e,2)}function ks(e){var t=e.alternate;return e===Te||t!==null&&t===Te}function ed(e,t){Ia=ws=!0;var l=e.pending;l===null?t.next=t:(t.next=l.next,l.next=t),e.pending=t}function td(e,t,l){if((l&4194048)!==0){var a=t.lanes;a&=e.pendingLanes,l|=a,t.lanes=l,so(e,l)}}var Yn={readContext:pt,use:qs,useCallback:Ie,useContext:Ie,useEffect:Ie,useImperativeHandle:Ie,useLayoutEffect:Ie,useInsertionEffect:Ie,useMemo:Ie,useReducer:Ie,useRef:Ie,useState:Ie,useDebugValue:Ie,useDeferredValue:Ie,useTransition:Ie,useSyncExternalStore:Ie,useId:Ie,useHostTransitionStatus:Ie,useFormState:Ie,useActionState:Ie,useOptimistic:Ie,useMemoCache:Ie,useCacheRefresh:Ie};Yn.useEffectEvent=Ie;var ld={readContext:pt,use:qs,useCallback:function(e,t){return xt().memoizedState=[e,t===void 0?null:t],e},useContext:pt,useEffect:Gr,useImperativeHandle:function(e,t,l){l=l!=null?l.concat([e]):null,Ys(4194308,4,Qr.bind(null,t,e),l)},useLayoutEffect:function(e,t){return Ys(4194308,4,e,t)},useInsertionEffect:function(e,t){Ys(4,2,e,t)},useMemo:function(e,t){var l=xt();t=t===void 0?null:t;var a=e();if(Sa){qe(!0);try{e()}finally{qe(!1)}}return l.memoizedState=[a,t],a},useReducer:function(e,t,l){var a=xt();if(l!==void 0){var s=l(t);if(Sa){qe(!0);try{l(t)}finally{qe(!1)}}}else s=t;return a.memoizedState=a.baseState=s,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:s},a.queue=e,e=e.dispatch=Rh.bind(null,Te,e),[a.memoizedState,e]},useRef:function(e){var t=xt();return e={current:e},t.memoizedState=e},useState:function(e){e=Ru(e);var t=e.queue,l=Pr.bind(null,Te,t);return t.dispatch=l,[e.memoizedState,l]},useDebugValue:Bu,useDeferredValue:function(e,t){var l=xt();return qu(l,e,t)},useTransition:function(){var e=Ru(!1);return e=Jr.bind(null,Te,e.queue,!0,!1),xt().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,l){var a=Te,s=xt();if(Ue){if(l===void 0)throw Error(r(407));l=l()}else{if(l=t(),Xe===null)throw Error(r(349));(_e&127)!==0||Nr(a,t,l)}s.memoizedState=l;var i={value:l,getSnapshot:t};return s.queue=i,Gr(Cr.bind(null,a,i,e),[e]),a.flags|=2048,en(9,{destroy:void 0},Ar.bind(null,a,i,l,t),null),l},useId:function(){var e=xt(),t=Xe.identifierPrefix;if(Ue){var l=rl,a=ol;l=(a&~(1<<32-Ke(a)-1)).toString(32)+l,t="_"+t+"R_"+l,l=Hs++,0<\/script>",i=i.removeChild(i.firstChild);break;case"select":i=typeof a.is=="string"?c.createElement("select",{is:a.is}):c.createElement("select"),a.multiple?i.multiple=!0:a.size&&(i.size=a.size);break;default:i=typeof a.is=="string"?c.createElement(s,{is:a.is}):c.createElement(s)}}i[mt]=t,i[Nt]=a;e:for(c=t.child;c!==null;){if(c.tag===5||c.tag===6)i.appendChild(c.stateNode);else if(c.tag!==4&&c.tag!==27&&c.child!==null){c.child.return=c,c=c.child;continue}if(c===t)break e;for(;c.sibling===null;){if(c.return===null||c.return===t)break e;c=c.return}c.sibling.return=c.return,c=c.sibling}t.stateNode=i;e:switch(yt(i,s,a),s){case"button":case"input":case"select":case"textarea":a=!!a.autoFocus;break e;case"img":a=!0;break e;default:a=!1}a&&Cl(t)}}return Ve(t),tc(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,l),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==a&&Cl(t);else{if(typeof a!="string"&&t.stateNode===null)throw Error(r(166));if(e=Ne.current,Ka(t)){if(e=t.stateNode,l=t.memoizedProps,a=null,s=ht,s!==null)switch(s.tag){case 27:case 5:a=s.memoizedProps}e[mt]=t,e=!!(e.nodeValue===l||a!==null&&a.suppressHydrationWarning===!0||Sf(e.nodeValue,l)),e||Yl(t,!0)}else e=ci(e).createTextNode(a),e[mt]=t,t.stateNode=e}return Ve(t),null;case 31:if(l=t.memoizedState,e===null||e.memoizedState!==null){if(a=Ka(t),l!==null){if(e===null){if(!a)throw Error(r(318));if(e=t.memoizedState,e=e!==null?e.dehydrated:null,!e)throw Error(r(557));e[mt]=t}else pa(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;Ve(t),e=!1}else l=du(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=l),e=!0;if(!e)return t.flags&256?(qt(t),t):(qt(t),null);if((t.flags&128)!==0)throw Error(r(558))}return Ve(t),null;case 13:if(a=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(s=Ka(t),a!==null&&a.dehydrated!==null){if(e===null){if(!s)throw Error(r(318));if(s=t.memoizedState,s=s!==null?s.dehydrated:null,!s)throw Error(r(317));s[mt]=t}else pa(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;Ve(t),s=!1}else s=du(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=s),s=!0;if(!s)return t.flags&256?(qt(t),t):(qt(t),null)}return qt(t),(t.flags&128)!==0?(t.lanes=l,t):(l=a!==null,e=e!==null&&e.memoizedState!==null,l&&(a=t.child,s=null,a.alternate!==null&&a.alternate.memoizedState!==null&&a.alternate.memoizedState.cachePool!==null&&(s=a.alternate.memoizedState.cachePool.pool),i=null,a.memoizedState!==null&&a.memoizedState.cachePool!==null&&(i=a.memoizedState.cachePool.pool),i!==s&&(a.flags|=2048)),l!==e&&l&&(t.child.flags|=8192),Vs(t,t.updateQueue),Ve(t),null);case 4:return ce(),e===null&&Nc(t.stateNode.containerInfo),Ve(t),null;case 10:return jl(t.type),Ve(t),null;case 19:if(h(tt),a=t.memoizedState,a===null)return Ve(t),null;if(s=(t.flags&128)!==0,i=a.rendering,i===null)if(s)kn(a,!1);else{if(Pe!==0||e!==null&&(e.flags&128)!==0)for(e=t.child;e!==null;){if(i=Rs(e),i!==null){for(t.flags|=128,kn(a,!1),e=i.updateQueue,t.updateQueue=e,Vs(t,e),t.subtreeFlags=0,e=l,l=t.child;l!==null;)Po(l,e),l=l.sibling;return M(tt,tt.current&1|2),Ue&&bl(t,a.treeForkCount),t.child}e=e.sibling}a.tail!==null&&et()>Is&&(t.flags|=128,s=!0,kn(a,!1),t.lanes=4194304)}else{if(!s)if(e=Rs(i),e!==null){if(t.flags|=128,s=!0,e=e.updateQueue,t.updateQueue=e,Vs(t,e),kn(a,!0),a.tail===null&&a.tailMode==="hidden"&&!i.alternate&&!Ue)return Ve(t),null}else 2*et()-a.renderingStartTime>Is&&l!==536870912&&(t.flags|=128,s=!0,kn(a,!1),t.lanes=4194304);a.isBackwards?(i.sibling=t.child,t.child=i):(e=a.last,e!==null?e.sibling=i:t.child=i,a.last=i)}return a.tail!==null?(e=a.tail,a.rendering=e,a.tail=e.sibling,a.renderingStartTime=et(),e.sibling=null,l=tt.current,M(tt,s?l&1|2:l&1),Ue&&bl(t,a.treeForkCount),e):(Ve(t),null);case 22:case 23:return qt(t),Au(),a=t.memoizedState!==null,e!==null?e.memoizedState!==null!==a&&(t.flags|=8192):a&&(t.flags|=8192),a?(l&536870912)!==0&&(t.flags&128)===0&&(Ve(t),t.subtreeFlags&6&&(t.flags|=8192)):Ve(t),l=t.updateQueue,l!==null&&Vs(t,l.retryQueue),l=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(l=e.memoizedState.cachePool.pool),a=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(a=t.memoizedState.cachePool.pool),a!==l&&(t.flags|=2048),e!==null&&h(ga),null;case 24:return l=null,e!==null&&(l=e.memoizedState.cache),t.memoizedState.cache!==l&&(t.flags|=2048),jl(st),Ve(t),null;case 25:return null;case 30:return null}throw Error(r(156,t.tag))}function Gh(e,t){switch(ou(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return jl(st),ce(),e=t.flags,(e&65536)!==0&&(e&128)===0?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return F(t),null;case 31:if(t.memoizedState!==null){if(qt(t),t.alternate===null)throw Error(r(340));pa()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(qt(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(r(340));pa()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return h(tt),null;case 4:return ce(),null;case 10:return jl(t.type),null;case 22:case 23:return qt(t),Au(),e!==null&&h(ga),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return jl(st),null;case 25:return null;default:return null}}function Td(e,t){switch(ou(t),t.tag){case 3:jl(st),ce();break;case 26:case 27:case 5:F(t);break;case 4:ce();break;case 31:t.memoizedState!==null&&qt(t);break;case 13:qt(t);break;case 19:h(tt);break;case 10:jl(t.type);break;case 22:case 23:qt(t),Au(),e!==null&&h(ga);break;case 24:jl(st)}}function Qn(e,t){try{var l=t.updateQueue,a=l!==null?l.lastEffect:null;if(a!==null){var s=a.next;l=s;do{if((l.tag&e)===e){a=void 0;var i=l.create,c=l.inst;a=i(),c.destroy=a}l=l.next}while(l!==s)}}catch(o){Ye(t,t.return,o)}}function Vl(e,t,l){try{var a=t.updateQueue,s=a!==null?a.lastEffect:null;if(s!==null){var i=s.next;a=i;do{if((a.tag&e)===e){var c=a.inst,o=c.destroy;if(o!==void 0){c.destroy=void 0,s=t;var d=l,j=o;try{j()}catch(D){Ye(s,d,D)}}}a=a.next}while(a!==i)}}catch(D){Ye(t,t.return,D)}}function Ed(e){var t=e.updateQueue;if(t!==null){var l=e.stateNode;try{yr(t,l)}catch(a){Ye(e,e.return,a)}}}function Md(e,t,l){l.props=Na(e.type,e.memoizedProps),l.state=e.memoizedState;try{l.componentWillUnmount()}catch(a){Ye(e,t,a)}}function Xn(e,t){try{var l=e.ref;if(l!==null){switch(e.tag){case 26:case 27:case 5:var a=e.stateNode;break;case 30:a=e.stateNode;break;default:a=e.stateNode}typeof l=="function"?e.refCleanup=l(a):l.current=a}}catch(s){Ye(e,t,s)}}function dl(e,t){var l=e.ref,a=e.refCleanup;if(l!==null)if(typeof a=="function")try{a()}catch(s){Ye(e,t,s)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof l=="function")try{l(null)}catch(s){Ye(e,t,s)}else l.current=null}function zd(e){var t=e.type,l=e.memoizedProps,a=e.stateNode;try{e:switch(t){case"button":case"input":case"select":case"textarea":l.autoFocus&&a.focus();break e;case"img":l.src?a.src=l.src:l.srcSet&&(a.srcset=l.srcSet)}}catch(s){Ye(e,e.return,s)}}function lc(e,t,l){try{var a=e.stateNode;u0(a,e.type,l,t),a[Nt]=t}catch(s){Ye(e,e.return,s)}}function Od(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&ea(e.type)||e.tag===4}function ac(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Od(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&ea(e.type)||e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function nc(e,t,l){var a=e.tag;if(a===5||a===6)e=e.stateNode,t?(l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l).insertBefore(e,t):(t=l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l,t.appendChild(e),l=l._reactRootContainer,l!=null||t.onclick!==null||(t.onclick=vl));else if(a!==4&&(a===27&&ea(e.type)&&(l=e.stateNode,t=null),e=e.child,e!==null))for(nc(e,t,l),e=e.sibling;e!==null;)nc(e,t,l),e=e.sibling}function Js(e,t,l){var a=e.tag;if(a===5||a===6)e=e.stateNode,t?l.insertBefore(e,t):l.appendChild(e);else if(a!==4&&(a===27&&ea(e.type)&&(l=e.stateNode),e=e.child,e!==null))for(Js(e,t,l),e=e.sibling;e!==null;)Js(e,t,l),e=e.sibling}function _d(e){var t=e.stateNode,l=e.memoizedProps;try{for(var a=e.type,s=t.attributes;s.length;)t.removeAttributeNode(s[0]);yt(t,a,l),t[mt]=e,t[Nt]=l}catch(i){Ye(e,e.return,i)}}var Tl=!1,ct=!1,sc=!1,Dd=typeof WeakSet=="function"?WeakSet:Set,ft=null;function Yh(e,t){if(e=e.containerInfo,Tc=pi,e=Xo(e),Ii(e)){if("selectionStart"in e)var l={start:e.selectionStart,end:e.selectionEnd};else e:{l=(l=e.ownerDocument)&&l.defaultView||window;var a=l.getSelection&&l.getSelection();if(a&&a.rangeCount!==0){l=a.anchorNode;var s=a.anchorOffset,i=a.focusNode;a=a.focusOffset;try{l.nodeType,i.nodeType}catch{l=null;break e}var c=0,o=-1,d=-1,j=0,D=0,q=e,S=null;t:for(;;){for(var E;q!==l||s!==0&&q.nodeType!==3||(o=c+s),q!==i||a!==0&&q.nodeType!==3||(d=c+a),q.nodeType===3&&(c+=q.nodeValue.length),(E=q.firstChild)!==null;)S=q,q=E;for(;;){if(q===e)break t;if(S===l&&++j===s&&(o=c),S===i&&++D===a&&(d=c),(E=q.nextSibling)!==null)break;q=S,S=q.parentNode}q=E}l=o===-1||d===-1?null:{start:o,end:d}}else l=null}l=l||{start:0,end:0}}else l=null;for(Ec={focusedElem:e,selectionRange:l},pi=!1,ft=t;ft!==null;)if(t=ft,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,ft=e;else for(;ft!==null;){switch(t=ft,i=t.alternate,e=t.flags,t.tag){case 0:if((e&4)!==0&&(e=t.updateQueue,e=e!==null?e.events:null,e!==null))for(l=0;l title"))),yt(i,a,l),i[mt]=e,dt(i),a=i;break e;case"link":var c=Gf("link","href",s).get(a+(l.href||""));if(c){for(var o=0;oQe&&(c=Qe,Qe=Se,Se=c);var y=ko(o,Se),v=ko(o,Qe);if(y&&v&&(E.rangeCount!==1||E.anchorNode!==y.node||E.anchorOffset!==y.offset||E.focusNode!==v.node||E.focusOffset!==v.offset)){var x=q.createRange();x.setStart(y.node,y.offset),E.removeAllRanges(),Se>Qe?(E.addRange(x),E.extend(v.node,v.offset)):(x.setEnd(v.node,v.offset),E.addRange(x))}}}}for(q=[],E=o;E=E.parentNode;)E.nodeType===1&&q.push({element:E,left:E.scrollLeft,top:E.scrollTop});for(typeof o.focus=="function"&&o.focus(),o=0;ol?32:l,N.T=null,l=fc,fc=null;var i=Fl,c=_l;if(ot=0,sn=Fl=null,_l=0,(He&6)!==0)throw Error(r(331));var o=He;if(He|=4,Qd(i.current),Yd(i,i.current,c,l),He=o,Wn(0,!1),ge&&typeof ge.onPostCommitFiberRoot=="function")try{ge.onPostCommitFiberRoot(I,i)}catch{}return!0}finally{k.p=s,N.T=a,cf(e,t)}}function rf(e,t,l){t=Zt(l,t),t=Ku(e.stateNode,t,2),e=Xl(e,t,2),e!==null&&(vn(e,2),fl(e))}function Ye(e,t,l){if(e.tag===3)rf(e,e,l);else for(;t!==null;){if(t.tag===3){rf(t,e,l);break}else if(t.tag===1){var a=t.stateNode;if(typeof t.type.getDerivedStateFromError=="function"||typeof a.componentDidCatch=="function"&&(Wl===null||!Wl.has(a))){e=Zt(l,e),l=rd(2),a=Xl(t,l,2),a!==null&&(dd(l,a,t,e),vn(a,2),fl(a));break}}t=t.return}}function vc(e,t,l){var a=e.pingCache;if(a===null){a=e.pingCache=new Qh;var s=new Set;a.set(t,s)}else s=a.get(t),s===void 0&&(s=new Set,a.set(t,s));s.has(l)||(cc=!0,s.add(l),e=Jh.bind(null,e,t,l),t.then(e,e))}function Jh(e,t,l){var a=e.pingCache;a!==null&&a.delete(t),e.pingedLanes|=e.suspendedLanes&l,e.warmLanes&=~l,Xe===e&&(_e&l)===l&&(Pe===4||Pe===3&&(_e&62914560)===_e&&300>et()-Fs?(He&2)===0&&un(e,0):oc|=l,nn===_e&&(nn=0)),fl(e)}function df(e,t){t===0&&(t=ao()),e=ma(e,t),e!==null&&(vn(e,t),fl(e))}function $h(e){var t=e.memoizedState,l=0;t!==null&&(l=t.retryLane),df(e,l)}function Wh(e,t){var l=0;switch(e.tag){case 31:case 13:var a=e.stateNode,s=e.memoizedState;s!==null&&(l=s.retryLane);break;case 19:a=e.stateNode;break;case 22:a=e.stateNode._retryCache;break;default:throw Error(r(314))}a!==null&&a.delete(t),df(e,l)}function Fh(e,t){return B(e,t)}var ni=null,on=null,yc=!1,si=!1,gc=!1,Pl=0;function fl(e){e!==on&&e.next===null&&(on===null?ni=on=e:on=on.next=e),si=!0,yc||(yc=!0,Ph())}function Wn(e,t){if(!gc&&si){gc=!0;do for(var l=!1,a=ni;a!==null;){if(e!==0){var s=a.pendingLanes;if(s===0)var i=0;else{var c=a.suspendedLanes,o=a.pingedLanes;i=(1<<31-Ke(42|e)+1)-1,i&=s&~(c&~o),i=i&201326741?i&201326741|1:i?i|2:0}i!==0&&(l=!0,pf(a,i))}else i=_e,i=os(a,a===Xe?i:0,a.cancelPendingCommit!==null||a.timeoutHandle!==-1),(i&3)===0||pn(a,i)||(l=!0,pf(a,i));a=a.next}while(l);gc=!1}}function Ih(){ff()}function ff(){si=yc=!1;var e=0;Pl!==0&&o0()&&(e=Pl);for(var t=et(),l=null,a=ni;a!==null;){var s=a.next,i=mf(a,t);i===0?(a.next=null,l===null?ni=s:l.next=s,s===null&&(on=l)):(l=a,(e!==0||(i&3)!==0)&&(si=!0)),a=s}ot!==0&&ot!==5||Wn(e),Pl!==0&&(Pl=0)}function mf(e,t){for(var l=e.suspendedLanes,a=e.pingedLanes,s=e.expirationTimes,i=e.pendingLanes&-62914561;0o)break;var D=d.transferSize,q=d.initiatorType;D&&Nf(q)&&(d=d.responseEnd,c+=D*(d"u"?null:document;function wf(e,t,l){var a=rn;if(a&&typeof t=="string"&&t){var s=Xt(t);s='link[rel="'+e+'"][href="'+s+'"]',typeof l=="string"&&(s+='[crossorigin="'+l+'"]'),Rf.has(s)||(Rf.add(s),e={rel:e,crossOrigin:l,href:t},a.querySelector(s)===null&&(t=a.createElement("link"),yt(t,"link",e),dt(t),a.head.appendChild(t)))}}function g0(e){Dl.D(e),wf("dns-prefetch",e,null)}function b0(e,t){Dl.C(e,t),wf("preconnect",e,t)}function x0(e,t,l){Dl.L(e,t,l);var a=rn;if(a&&e&&t){var s='link[rel="preload"][as="'+Xt(t)+'"]';t==="image"&&l&&l.imageSrcSet?(s+='[imagesrcset="'+Xt(l.imageSrcSet)+'"]',typeof l.imageSizes=="string"&&(s+='[imagesizes="'+Xt(l.imageSizes)+'"]')):s+='[href="'+Xt(e)+'"]';var i=s;switch(t){case"style":i=dn(e);break;case"script":i=fn(e)}It.has(i)||(e=z({rel:"preload",href:t==="image"&&l&&l.imageSrcSet?void 0:e,as:t},l),It.set(i,e),a.querySelector(s)!==null||t==="style"&&a.querySelector(es(i))||t==="script"&&a.querySelector(ts(i))||(t=a.createElement("link"),yt(t,"link",e),dt(t),a.head.appendChild(t)))}}function j0(e,t){Dl.m(e,t);var l=rn;if(l&&e){var a=t&&typeof t.as=="string"?t.as:"script",s='link[rel="modulepreload"][as="'+Xt(a)+'"][href="'+Xt(e)+'"]',i=s;switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":i=fn(e)}if(!It.has(i)&&(e=z({rel:"modulepreload",href:e},t),It.set(i,e),l.querySelector(s)===null)){switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(l.querySelector(ts(i)))return}a=l.createElement("link"),yt(a,"link",e),dt(a),l.head.appendChild(a)}}}function S0(e,t,l){Dl.S(e,t,l);var a=rn;if(a&&e){var s=Da(a).hoistableStyles,i=dn(e);t=t||"default";var c=s.get(i);if(!c){var o={loading:0,preload:null};if(c=a.querySelector(es(i)))o.loading=5;else{e=z({rel:"stylesheet",href:e,"data-precedence":t},l),(l=It.get(i))&&Rc(e,l);var d=c=a.createElement("link");dt(d),yt(d,"link",e),d._p=new Promise(function(j,D){d.onload=j,d.onerror=D}),d.addEventListener("load",function(){o.loading|=1}),d.addEventListener("error",function(){o.loading|=2}),o.loading|=4,ri(c,t,a)}c={type:"stylesheet",instance:c,count:1,state:o},s.set(i,c)}}}function N0(e,t){Dl.X(e,t);var l=rn;if(l&&e){var a=Da(l).hoistableScripts,s=fn(e),i=a.get(s);i||(i=l.querySelector(ts(s)),i||(e=z({src:e,async:!0},t),(t=It.get(s))&&wc(e,t),i=l.createElement("script"),dt(i),yt(i,"link",e),l.head.appendChild(i)),i={type:"script",instance:i,count:1,state:null},a.set(s,i))}}function A0(e,t){Dl.M(e,t);var l=rn;if(l&&e){var a=Da(l).hoistableScripts,s=fn(e),i=a.get(s);i||(i=l.querySelector(ts(s)),i||(e=z({src:e,async:!0,type:"module"},t),(t=It.get(s))&&wc(e,t),i=l.createElement("script"),dt(i),yt(i,"link",e),l.head.appendChild(i)),i={type:"script",instance:i,count:1,state:null},a.set(s,i))}}function Hf(e,t,l,a){var s=(s=Ne.current)?oi(s):null;if(!s)throw Error(r(446));switch(e){case"meta":case"title":return null;case"style":return typeof l.precedence=="string"&&typeof l.href=="string"?(t=dn(l.href),l=Da(s).hoistableStyles,a=l.get(t),a||(a={type:"style",instance:null,count:0,state:null},l.set(t,a)),a):{type:"void",instance:null,count:0,state:null};case"link":if(l.rel==="stylesheet"&&typeof l.href=="string"&&typeof l.precedence=="string"){e=dn(l.href);var i=Da(s).hoistableStyles,c=i.get(e);if(c||(s=s.ownerDocument||s,c={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},i.set(e,c),(i=s.querySelector(es(e)))&&!i._p&&(c.instance=i,c.state.loading=5),It.has(e)||(l={rel:"preload",as:"style",href:l.href,crossOrigin:l.crossOrigin,integrity:l.integrity,media:l.media,hrefLang:l.hrefLang,referrerPolicy:l.referrerPolicy},It.set(e,l),i||C0(s,e,l,c.state))),t&&a===null)throw Error(r(528,""));return c}if(t&&a!==null)throw Error(r(529,""));return null;case"script":return t=l.async,l=l.src,typeof l=="string"&&t&&typeof t!="function"&&typeof t!="symbol"?(t=fn(l),l=Da(s).hoistableScripts,a=l.get(t),a||(a={type:"script",instance:null,count:0,state:null},l.set(t,a)),a):{type:"void",instance:null,count:0,state:null};default:throw Error(r(444,e))}}function dn(e){return'href="'+Xt(e)+'"'}function es(e){return'link[rel="stylesheet"]['+e+"]"}function Bf(e){return z({},e,{"data-precedence":e.precedence,precedence:null})}function C0(e,t,l,a){e.querySelector('link[rel="preload"][as="style"]['+t+"]")?a.loading=1:(t=e.createElement("link"),a.preload=t,t.addEventListener("load",function(){return a.loading|=1}),t.addEventListener("error",function(){return a.loading|=2}),yt(t,"link",l),dt(t),e.head.appendChild(t))}function fn(e){return'[src="'+Xt(e)+'"]'}function ts(e){return"script[async]"+e}function qf(e,t,l){if(t.count++,t.instance===null)switch(t.type){case"style":var a=e.querySelector('style[data-href~="'+Xt(l.href)+'"]');if(a)return t.instance=a,dt(a),a;var s=z({},l,{"data-href":l.href,"data-precedence":l.precedence,href:null,precedence:null});return a=(e.ownerDocument||e).createElement("style"),dt(a),yt(a,"style",s),ri(a,l.precedence,e),t.instance=a;case"stylesheet":s=dn(l.href);var i=e.querySelector(es(s));if(i)return t.state.loading|=4,t.instance=i,dt(i),i;a=Bf(l),(s=It.get(s))&&Rc(a,s),i=(e.ownerDocument||e).createElement("link"),dt(i);var c=i;return c._p=new Promise(function(o,d){c.onload=o,c.onerror=d}),yt(i,"link",a),t.state.loading|=4,ri(i,l.precedence,e),t.instance=i;case"script":return i=fn(l.src),(s=e.querySelector(ts(i)))?(t.instance=s,dt(s),s):(a=l,(s=It.get(i))&&(a=z({},l),wc(a,s)),e=e.ownerDocument||e,s=e.createElement("script"),dt(s),yt(s,"link",a),e.head.appendChild(s),t.instance=s);case"void":return null;default:throw Error(r(443,t.type))}else t.type==="stylesheet"&&(t.state.loading&4)===0&&(a=t.instance,t.state.loading|=4,ri(a,l.precedence,e));return t.instance}function ri(e,t,l){for(var a=l.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),s=a.length?a[a.length-1]:null,i=s,c=0;c title"):null)}function T0(e,t,l){if(l===1||t.itemProp!=null)return!1;switch(e){case"meta":case"title":return!0;case"style":if(typeof t.precedence!="string"||typeof t.href!="string"||t.href==="")break;return!0;case"link":if(typeof t.rel!="string"||typeof t.href!="string"||t.href===""||t.onLoad||t.onError)break;return t.rel==="stylesheet"?(e=t.disabled,typeof t.precedence=="string"&&e==null):!0;case"script":if(t.async&&typeof t.async!="function"&&typeof t.async!="symbol"&&!t.onLoad&&!t.onError&&t.src&&typeof t.src=="string")return!0}return!1}function Lf(e){return!(e.type==="stylesheet"&&(e.state.loading&3)===0)}function E0(e,t,l,a){if(l.type==="stylesheet"&&(typeof a.media!="string"||matchMedia(a.media).matches!==!1)&&(l.state.loading&4)===0){if(l.instance===null){var s=dn(a.href),i=t.querySelector(es(s));if(i){t=i._p,t!==null&&typeof t=="object"&&typeof t.then=="function"&&(e.count++,e=fi.bind(e),t.then(e,e)),l.state.loading|=4,l.instance=i,dt(i);return}i=t.ownerDocument||t,a=Bf(a),(s=It.get(s))&&Rc(a,s),i=i.createElement("link"),dt(i);var c=i;c._p=new Promise(function(o,d){c.onload=o,c.onerror=d}),yt(i,"link",a),l.instance=i}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(l,t),(t=l.state.preload)&&(l.state.loading&3)===0&&(e.count++,l=fi.bind(e),t.addEventListener("load",l),t.addEventListener("error",l))}}var Hc=0;function M0(e,t){return e.stylesheets&&e.count===0&&hi(e,e.stylesheets),0Hc?50:800)+t);return e.unsuspend=l,function(){e.unsuspend=null,clearTimeout(a),clearTimeout(s)}}:null}function fi(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)hi(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var mi=null;function hi(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,mi=new Map,t.forEach(z0,e),mi=null,fi.call(e))}function z0(e,t){if(!(t.state.loading&4)){var l=mi.get(e);if(l)var a=l.get(null);else{l=new Map,mi.set(e,l);for(var s=e.querySelectorAll("link[data-precedence],style[data-precedence]"),i=0;i"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(u)}catch(f){console.error(f)}}return u(),Kc.exports=V0(),Kc.exports}var $0=J0();function je(u){return Array.isArray(u)?u:[]}function ym(u){const f=new Set;return u.map(p=>p.trim()).filter(p=>{const r=p.toLowerCase();return!p||f.has(r)?!1:(f.add(r),!0)})}function il(u){const f=Ni.some(p=>p.value===u.streamMode)?u.streamMode:"auto";return{...u,streamMode:f,models:je(u.models),allowedGroupIds:je(u.allowedGroupIds),openaiAccounts:je(u.openaiAccounts),kiroAccounts:je(u.kiroAccounts)}}function cs(u){return{...u,aliases:je(u.aliases)}}function W0(u){return{...u,apiKeys:je(u.apiKeys),logs:je(u.logs)}}class Ci extends Error{status;payload;constructor(f,p,r){super(p),this.status=f,this.payload=r}}const F0={home:"M3 10.5 12 3l9 7.5V21a1 1 0 0 1-1 1h-5v-7H9v7H4a1 1 0 0 1-1-1z",users:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8M22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75",key:"M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.78 7.78 5.5 5.5 0 0 1 7.78-7.78ZM14 8l7-7M21 8h-5V3",models:"M12 2 4 6v12l8 4 8-4V6zM4 6l8 4 8-4M12 10v12",image:"M21 19V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2ZM8.5 11a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5ZM21 16l-5-5L5 21",route:"M4 19a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM20 11a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM7 16h3a4 4 0 0 0 4-4V8h3",logs:"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8zM14 2v6h6M8 13h8M8 17h6",orbit:"M12 7a5 5 0 1 0 0 10 5 5 0 0 0 0-10ZM3 12a9 3 0 1 0 18 0 9 3 0 1 0-18 0Z",settings:"M12 15.5a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7ZM19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.6 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 8.92 4a1.65 1.65 0 0 0 1-1.51V2a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9c.14.31.39.57.71.71.23.1.49.18.8.2H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1Z",search:"M21 21l-4.35-4.35M10.5 18a7.5 7.5 0 1 1 0-15 7.5 7.5 0 0 1 0 15Z",copy:"M8 8h11a1 1 0 0 1 1 1v11a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1ZM4 16H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h11a1 1 0 0 1 1 1v1",ban:"M4.93 4.93 19.07 19.07M22 12A10 10 0 1 1 2 12a10 10 0 0 1 20 0Z",check:"M20 6 9 17l-5-5",moon:"M21 12.8A8.5 8.5 0 1 1 11.2 3 6.5 6.5 0 0 0 21 12.8Z",sun:"M12 4V2M12 22v-2M4.93 4.93 3.52 3.52M20.48 20.48l-1.41-1.41M4 12H2M22 12h-2M4.93 19.07l-1.41 1.41M20.48 3.52l-1.41 1.41M16 12a4 4 0 1 1-8 0 4 4 0 0 1 8 0Z",plus:"M12 5v14M5 12h14"};function Ot({name:u}){return n.jsx("svg",{viewBox:"0 0 24 24","aria-hidden":"true",className:"icon",children:n.jsx("path",{d:F0[u]})})}async function ve(u,f){const p=new Headers(f?.headers);p.set("Content-Type","application/json");const r=window.sessionStorage.getItem("capi-admin-token");r&&p.set("Authorization",`Bearer ${r}`);const A=await fetch(u,{credentials:"include",...f,headers:p});if(!A.ok){const T=await A.json().catch(()=>null);throw new Ci(A.status,T?.error?.message||`Request failed: ${A.status}`,T)}return A.json()}async function I0(u,f){const p=new Headers,r=window.sessionStorage.getItem("capi-admin-token");r&&p.set("Authorization",`Bearer ${r}`);const A=await fetch(u,{credentials:"include",method:"POST",headers:p,body:f});if(!A.ok){const T=await A.json().catch(()=>null);throw new Ci(A.status,T?.error?.message||`Request failed: ${A.status}`,T)}return A.json()}const dm=[{id:"overview",label:"概览",icon:"home"},{id:"users",label:"用户",icon:"users"},{id:"groups",label:"分组",icon:"users"},{id:"keys",label:"密钥",icon:"key"},{id:"models",label:"模型",icon:"models"},{id:"drawing",label:"绘图",icon:"image"},{id:"antigravity",label:"Antigravity",icon:"orbit"},{id:"channels",label:"渠道",icon:"route"},{id:"logs",label:"日志",icon:"logs"},{id:"settings",label:"设置",icon:"settings"}],to=[{value:"kiro",label:"Kiro / Amazon Q"},{value:"codex",label:"Codex / ChatGPT OAuth"},{value:"antigravity",label:"Antigravity / Google"},{value:"cpa",label:"CPA / CLIProxyAPI"},{value:"openai",label:"OpenAI"},{value:"anthropic",label:"Anthropic / Claude"},{value:"google",label:"Google Gemini"},{value:"deepseek",label:"DeepSeek"},{value:"openrouter",label:"OpenRouter"},{value:"groq",label:"Groq"},{value:"siliconflow",label:"SiliconFlow"},{value:"moonshot",label:"Moonshot"},{value:"compatible",label:"OpenAI 兼容接口"}],gm="https://api.openai.com/v1",Ti="https://chatgpt.com/backend-api",bm="http://localhost:8317/v1",xm="https://codewhisperer.us-east-1.amazonaws.com",jm="gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, gpt-image-2, gpt-image-1",P0="gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, gpt-image-2",ep="gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, claude-sonnet-4, gemini-3.1-pro",tp="claude-sonnet-4.5, claude-sonnet-4, claude-haiku-4.5, claude-opus-4.5",Sm="https://daily-cloudcode-pa.googleapis.com",lp="claude-opus-4-6-thinking, claude-sonnet-4-6, gemini-3.8-flash-high, gemini-3.7-flash-high, gemini-3.6-flash-high, gemini-3-flash, gemini-pro-agent, gemini-3.1-pro-low, gpt-oss-120b-medium, gemini-3.1-flash-lite, gemini-3.5-flash-lite, gemini-3.1-flash-image",Fc=[{provider:"kiro",label:"Kiro / Amazon Q",name:"Kiro 账号池",baseUrl:xm,models:tp.split(",").map(u=>u.trim())},{provider:"openai",label:"OpenAI",name:"OpenAI 主线路",baseUrl:gm,models:P0.split(",").map(u=>u.trim())},{provider:"codex",label:"Codex 账号池",name:"Codex 账号池",baseUrl:Ti,models:jm.split(",").map(u=>u.trim())},{provider:"antigravity",label:"Antigravity 账号池",name:"Antigravity 账号池",baseUrl:Sm,models:lp.split(",").map(u=>u.trim())},{provider:"cpa",label:"CPA / CLIProxyAPI",name:"CPA 本地代理",baseUrl:bm,models:ep.split(",").map(u=>u.trim())},{provider:"compatible",label:"OpenAI 兼容接口",name:"兼容渠道",baseUrl:"",models:[]},{provider:"openrouter",label:"OpenRouter",name:"OpenRouter",baseUrl:"https://openrouter.ai/api/v1",models:[]},{provider:"google",label:"Google Gemini",name:"Gemini",baseUrl:"",models:[]},{provider:"anthropic",label:"Anthropic / Claude",name:"Claude",baseUrl:"",models:[]}];function Ta(u){return Fc.find(f=>f.provider===u)||Fc[2]}function Ic(u){const f=Ta(u);return{name:f.name,provider:f.provider,baseUrl:f.baseUrl,models:[...f.models],streamMode:"auto"}}function ap(u){const f=u?.trim().toLowerCase();return f&&({free:"Free",plus:"Plus",pro:"Pro",team:"Team",enterprise:"Enterprise"}[f]||u)||"套餐未知"}function fm(u){return u?{upstream_token_invalidated:"Token 已失效",upstream_invalid_api_key:"API Key 无效",upstream_account_error:"账号错误",upstream_accounts_unavailable:"账号池不可用",upstream_error:"上游错误"}[u]||u:""}function Ei(u){return u==="openai"?gm:u==="codex"?Ti:u==="antigravity"?Sm:u==="cpa"||u==="cliproxyapi"?bm:u==="kiro"?xm:""}function Pc(u){return ym(u.split(/[\s,;,;]+/))}function np(u){return ym(u.split(/[\n,;,;]+/).map(f=>f.trim()))}function Nm(u){const f=np(u);return f.length===0?{}:f.length===1?{upstreamApiKey:f[0]}:{upstreamApiKeys:f}}const Ni=[{value:"auto",label:"自动",description:"按请求参数处理"},{value:"real",label:"真流",description:"直连上游 SSE"},{value:"fake",label:"假流",description:"非流转 SSE"},{value:"disabled",label:"禁用流",description:"流式请求跳过"}];function el(u){if(!u)return"未使用";const f=new Date(u);return Number.isNaN(f.getTime())?"-":new Intl.DateTimeFormat("zh-CN",{month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"}).format(f)}function mm(u){if(!u)return"";const f=new Date(u);if(Number.isNaN(f.getTime()))return"";const p=f.getTimezoneOffset()*6e4;return new Date(f.getTime()-p).toISOString().slice(0,16)}function sp(u){if(!u)return"";const f=new Date(u);return Number.isNaN(f.getTime())?"":f.toISOString()}function ip(u){if(!u)return"-";const f=new Date(u);return Number.isNaN(f.getTime())?"-":new Intl.DateTimeFormat("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"}).format(f)}function _t(u){return{active:"正常",disabled:"禁用",limited:"受限",overdue:"欠费",healthy:"正常",standby:"备用",available:"Available",success:"成功",failed:"失败"}[u]||u}function jt(u,f=2){const p=Number(u||0);return new Intl.NumberFormat("zh-CN",{minimumFractionDigits:f,maximumFractionDigits:f}).format(p)}function ml(u){return new Intl.NumberFormat("zh-CN").format(Math.max(0,Math.round(Number(u||0))))}function lo(u){return u.model?u.model:u.errorCode==="invalid_api_key"?"密钥无效":u.errorCode==="model_not_available"?"模型不可用":u.errorCode==="insufficient_quota"?"额度不足":u.errorCode==="rate_limit_exceeded"?"请求过快":u.errorCode||"请求失败"}function up(u){return u.model||(u.errorCode?`错误:${u.errorCode}`:"-")}function cp(u){return u.channel||(u.apiKeyPrefix?`Key ${u.apiKeyPrefix}`:"-")}function op(u){const f=je(u);if(f.length===0)return"未绑定模型";const p=f.slice(0,2).join(", ");return f.length>2?`${p} · 其余 ${f.length-2} 个`:p}function ul(u){return u==="cliproxyapi"||u==="cli-proxy-api"?"CPA / CLIProxyAPI":to.find(f=>f.value===u)?.label||u||"Custom"}function $c(u){const f=`${u.vendor} ${u.id} ${u.name}`.toLowerCase();return f.includes("cliproxyapi")||/\bcpa\b/.test(f)?"cpa":f.includes("openai")||/\bgpt[-_/]/.test(f)||f.includes("o1-")||f.includes("o3-")?"openai":f.includes("anthropic")||f.includes("claude")?"anthropic":f.includes("google")||f.includes("gemini")||f.includes("gcli-")?"google":f.includes("deepseek")?"deepseek":f.includes("openrouter")?"openrouter":f.includes("groq")?"groq":f.includes("siliconflow")?"siliconflow":f.includes("moonshot")||f.includes("kimi")?"moonshot":u.vendor&&u.vendor.toLowerCase()!=="custom"?u.vendor.toLowerCase():"compatible"}function hm({provider:u}){if(u==="deepseek")return n.jsx("span",{className:"provider-icon provider-icon-deepseek","aria-hidden":"true",children:n.jsxs("svg",{viewBox:"0 0 32 32",role:"img",children:[n.jsx("rect",{x:"1",y:"1",width:"30",height:"30",rx:"8"}),n.jsx("path",{transform:"translate(2.4 4.4)",d:"M26.517 3.395c-.282-.138-.403.125-.568.258-.057.044-.105.1-.152.152-.413.44-.895.73-1.524.695-.92-.052-1.705.237-2.4.941-.147-.868-.638-1.386-1.384-1.718-.39-.173-.786-.346-1.06-.721-.19-.268-.243-.566-.338-.86-.061-.176-.121-.357-.325-.388-.222-.034-.309.151-.396.307-.347.635-.481 1.334-.468 2.042.03 1.594.703 2.863 2.04 3.765.152.104.191.207.143.359-.091.31-.2.613-.295.924-.06.198-.151.242-.364.155-.734-.306-1.367-.76-1.927-1.308-.951-.92-1.81-1.934-2.882-2.729-.252-.185-.504-.358-.764-.522-1.094-1.062.143-1.935.43-2.038.3-.108.104-.48-.864-.475-.968.004-1.853.328-2.982.76-.165.065-.339.112-.516.151-1.024-.194-2.088-.237-3.199-.112-2.092.233-3.763 1.222-4.991 2.91C.254 7.972-.093 10.278.332 12.682c.446 2.535 1.74 4.633 3.728 6.274 2.062 1.7 4.436 2.534 7.145 2.375 1.645-.095 3.476-.316 5.542-2.064.521.259 1.068.363 1.975.44.699.065 1.371-.034 1.892-.142.816-.173.76-.929.465-1.067-2.392-1.114-1.866-.661-2.344-1.027 1.215-1.438 3.071-3.993 3.644-7.473.056-.384.128-.925.12-1.236-.005-.19.038-.263.255-.285.6-.069 1.18-.233 1.715-.527 1.55-.846 2.175-2.237 2.322-3.903.022-.255-.005-.518-.274-.652ZM13.014 18.395c-2.318-1.823-3.442-2.423-3.906-2.397-.434.026-.356.523-.26.847.1.32.23.54.412.82.126.186.213.462-.126.67-.746.461-2.044-.156-2.105-.186-1.51-.89-2.773-2.064-3.664-3.67-.86-1.545-1.358-3.204-1.44-4.974-.022-.427.104-.578.529-.656.56-.103 1.137-.125 1.697-.043 2.366.346 4.379 1.403 6.068 3.079.963.954 1.692 2.094 2.443 3.208.799 1.183 1.658 2.31 2.752 3.234.387.324.695.57.99.751-.89.1-2.374.121-3.39-.683Zm1.111-7.146c0-.19.152-.341.343-.341.043 0 .082.009.117.021.048.018.092.044.126.083.061.06.096.146.096.237a.341.341 0 0 1-.343.341.34.34 0 0 1-.339-.341Zm3.451 1.77c-.222.09-.443.168-.656.177-.33.017-.69-.117-.885-.281-.304-.255-.521-.397-.612-.842-.039-.19-.017-.483.017-.652.078-.362-.009-.595-.265-.807-.208-.172-.473-.22-.764-.22-.108 0-.208-.048-.282-.086-.121-.061-.221-.212-.126-.398.031-.06.178-.207.213-.233.395-.225.85-.151 1.272.018.39.16.686.453 1.111.867.434.501.512.639.759 1.015.196.294.373.596.495.942.073.215-.022.392-.277.5Z"})]})});if(u==="openai")return n.jsx("span",{className:"provider-icon provider-icon-openai","aria-hidden":"true",children:n.jsxs("svg",{viewBox:"0 0 32 32",role:"img",children:[n.jsx("rect",{x:"1",y:"1",width:"30",height:"30",rx:"8"}),n.jsx("g",{transform:"translate(7 7.5) scale(0.065)",fill:"currentColor",stroke:"none",children:n.jsx("path",{d:"M267.06 111.34a71.78 71.78 0 0 0-6.17-58.91c-14.5-25.15-43.55-38.09-71.9-32.03A71.78 71.78 0 0 0 135.1.5C106 .43 80.21 19.16 71.29 46.85a71.79 71.79 0 0 0-47.98 34.8c-14.6 25.1-11.28 56.75 8.22 78.3a71.78 71.78 0 0 0 6.16 58.9c14.5 25.16 43.56 38.1 71.91 32.04a71.76 71.76 0 0 0 53.89 24.02c29.12.02 54.92-18.72 63.84-46.44a71.79 71.79 0 0 0 47.98-34.8c14.58-25.1 11.25-56.72-8.24-78.27zm-107.9 150.77a53.15 53.15 0 0 1-34.15-12.35c.43-.24 1.2-.66 1.7-.96l56.68-32.73a9.22 9.22 0 0 0 4.66-8.06v-79.9l23.95 13.83a.85.85 0 0 1 .47.66v66.16a53.42 53.42 0 0 1-53.3 53.35zM44.6 213.16a53.13 53.13 0 0 1-6.36-35.75c.42.25 1.15.7 1.68 1l56.68 32.73a9.24 9.24 0 0 0 9.31 0l69.2-39.95v27.66a.87.87 0 0 1-.34.74l-57.29 33.07a53.42 53.42 0 0 1-72.88-19.5zM29.7 90.05a53.1 53.1 0 0 1 27.76-23.36c0 .49-.03 1.36-.03 1.96v65.46a9.22 9.22 0 0 0 4.65 8.05l69.2 39.95-23.95 13.83a.86.86 0 0 1-.81.07L49.2 162.9A53.42 53.42 0 0 1 29.7 90.05zm196.8 45.8L157.3 95.9l23.95-13.82a.86.86 0 0 1 .81-.07l57.3 33.08a53.37 53.37 0 0 1-8.24 96.29v-65.46a9.2 9.2 0 0 0-4.62-8.06zm23.84-35.89c-.42-.26-1.15-.7-1.68-1.01l-56.68-32.73a9.25 9.25 0 0 0-9.31 0l-69.2 39.95V78.5a.87.87 0 0 1 .35-.74l57.28-33.05a53.35 53.35 0 0 1 79.24 55.25zM100.11 149.24l-23.96-13.83a.85.85 0 0 1-.46-.66V68.6a53.37 53.37 0 0 1 87.52-40.95c-.42.24-1.19.66-1.7.96l-56.68 32.73a9.22 9.22 0 0 0-4.66 8.06l-.04 79.85zm13.01-28.05L144 103.3l30.88 17.83v35.68L144 174.63l-30.88-17.82v-35.62z"})})]})});const f=u==="codex"?"C":u==="antigravity"?"G":u==="cpa"||u==="cliproxyapi"?"CPA":u==="anthropic"?"A":u==="google"?"✦":u==="openrouter"?"↗":u==="groq"?"G":u==="siliconflow"?"S":u==="moonshot"?"M":"◇";return n.jsx("span",{className:`provider-icon provider-icon-${u}`,"aria-hidden":"true",children:n.jsxs("svg",{viewBox:"0 0 32 32",role:"img",children:[n.jsx("rect",{x:"1",y:"1",width:"30",height:"30",rx:"8"}),n.jsx("text",{x:"16",y:"21",textAnchor:"middle",children:f})]})})}async function Ai(u){if(navigator.clipboard?.writeText){await navigator.clipboard.writeText(u);return}const f=document.createElement("textarea");f.value=u,f.setAttribute("readonly","true"),f.style.position="fixed",f.style.opacity="0",document.body.appendChild(f),f.select(),document.execCommand("copy"),document.body.removeChild(f)}function Ul(){return window.location.origin}function rp(){return`${Ul()}/api/auth/discord/callback`}function dp(){return`${Ul()}/`}function Wc(u){return{...u,redirectUri:u.redirectUri&&!u.redirectUri.includes("localhost")?u.redirectUri:rp(),authSuccessUrl:u.authSuccessUrl&&!u.authSuccessUrl.includes("localhost")?u.authSuccessUrl:dp(),blockedGuildIds:je(u.blockedGuildIds),sessionTtlHours:u.sessionTtlHours||168}}function Mi(u){return u==="email"||u==="discord"?u:"username"}function fp(u){const p=(u.split("@")[0]||"user").toLowerCase().replace(/[^a-z0-9_-]+/g,"-").replace(/^[-_]+|[-_]+$/g,"");return(p.length>=3?p:"user").slice(0,24)}function mp(){const[u,f]=b.useState("home"),[p,r]=b.useState("login"),[A,T]=b.useState(null),[L,$]=b.useState("overview"),[C,g]=b.useState(()=>{const R=window.localStorage.getItem("capi-theme");return R==="light"||R==="dark"?R:window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}),[G,z]=b.useState("comfortable"),[V,W]=b.useState(null),[fe,te]=b.useState([]),[ae,ie]=b.useState([]),[be,Y]=b.useState([]),[xe,P]=b.useState([]),[he,_]=b.useState([]),[ne,me]=b.useState(""),[Ce,Me]=b.useState(""),[ue,K]=b.useState(null),[de,J]=b.useState(""),[N,k]=b.useState(""),[H,X]=b.useState(!1),se=b.useMemo(()=>{const R=ne.trim().toLowerCase();return R?fe.filter(Z=>`${Z.id} ${Z.name} ${Z.email}`.toLowerCase().includes(R)):fe},[ne,fe]);async function m(){const R=new Date().getTimezoneOffset(),[Z,le,I,ge,qe,Ke]=await Promise.all([ve(`/api/overview?timezoneOffset=${R}`),ve("/api/users"),ve("/api/channels"),ve("/api/models"),ve("/api/logs"),ve("/api/groups")]),Rt=je(le.users),Rl=je(I.channels).map(il),ca=je(ge.models).map(cs),Ea=je(qe.logs),Ma=je(Ke.groups);W(Z),te(Rt),ie(Rl),Y(Ma),P(ca),_(Ea),Me(wl=>wl&&Rt.some(hl=>hl.id===wl)?wl:Rt[0]?.id||""),Rt.length===0&&K(null),X(!0)}async function h(R){const Z=await ve(`/api/users/${R}`);K(W0(Z))}async function M(R,Z){const le=await ve(`/api/users/${R}`,{method:"PATCH",body:JSON.stringify(Z)});te(I=>I.map(ge=>ge.id===R?le.user:ge)),K(I=>I?.user.id===R?{...I,user:le.user}:I),J("已更新用户"),window.setTimeout(()=>J(""),1800)}async function Q(R,Z,le={}){const I=await ve("/api/users/bulk",{method:"POST",body:JSON.stringify({userIds:R,action:Z,...le})}),ge=new Map(je(I.users).map(qe=>[qe.id,qe]));te(qe=>qe.map(Ke=>ge.get(Ke.id)||Ke)),K(qe=>{if(!qe)return qe;const Ke=ge.get(qe.user.id);return Ke?{...qe,user:Ke}:qe}),J(`已处理 ${I.updated} 个用户`),window.setTimeout(()=>J(""),1800)}async function ee(R){const Z=await ve(`/api/users/${R}/api-keys`,{method:"POST",body:JSON.stringify({name:"Console Key"})});ue?.user.id===R&&K({...ue,apiKeys:[...ue.apiKeys,Z.apiKey]}),k(Z.secret),await Ai(Z.secret),J("新 Key 已创建并复制,请立即保存"),window.setTimeout(()=>J(""),2400)}async function Ne(R){window.confirm("删除这个 Key?删除后使用它的请求会立即失效。")&&(await ve(`/api/api-keys/${R}`,{method:"DELETE"}),K(Z=>Z&&{...Z,apiKeys:Z.apiKeys.filter(le=>le.id!==R)}),J("Key 已删除"),window.setTimeout(()=>J(""),1800))}async function O(R,Z){const le=await ve(`/api/api-keys/${R}`,{method:"PATCH",body:JSON.stringify(Z)});K(I=>I&&{...I,apiKeys:I.apiKeys.map(ge=>ge.id===R?le.apiKey:ge)}),J("Key 已更新"),window.setTimeout(()=>J(""),1800)}async function ye(R,Z){const le=await ve(`/api/channels/${R}`,{method:"PATCH",body:JSON.stringify(Z)});ie(I=>I.map(ge=>ge.id===R?il(le.channel):ge)),We(le.removedModels),J("渠道已更新"),window.setTimeout(()=>J(""),1800)}async function ce(R){const Z=ae.find(I=>I.id===R);if(!window.confirm(`删除渠道「${Z?.name||R}」?`))return;const le=await ve(`/api/channels/${R}`,{method:"DELETE"});ie(I=>I.filter(ge=>ge.id!==R)),We(le.removedModels),J("渠道已删除"),window.setTimeout(()=>J(""),1800)}async function St(R){const Z=await ve("/api/groups",{method:"POST",body:JSON.stringify(R)});Y(le=>[...le,Z.group]),J("分组已创建"),window.setTimeout(()=>J(""),1800)}async function F(R,Z){const le=await ve(`/api/groups/${R}`,{method:"PATCH",body:JSON.stringify(Z)});Y(I=>I.map(ge=>ge.id===R?le.group:ge)),J("分组已更新"),window.setTimeout(()=>J(""),1800)}async function $e(R){const Z=be.find(le=>le.id===R);window.confirm(`删除分组「${Z?.name||R}」?删除后渠道的可见范围会移除该分组。`)&&(await ve(`/api/groups/${R}`,{method:"DELETE"}),Y(le=>le.filter(I=>I.id!==R)),ie(le=>le.map(I=>({...I,allowedGroupIds:I.allowedGroupIds.filter(ge=>ge!==R)}))),J("分组已删除"),window.setTimeout(()=>J(""),1800))}async function rt(R,Z){const le=je(Z).map(Rt=>Rt.trim()).filter(Boolean),I=await ve(`/api/channels/${R}/sync-models`,{method:"POST",body:JSON.stringify(le.length?{models:le}:{})}),ge=il(I.channel),qe=je(I.addedModels).map(cs),Ke=je(I.models);ie(Rt=>Rt.map(Rl=>Rl.id===R?ge:Rl)),qe.length>0&&P(Rt=>{const Rl=new Set(Rt.map(ca=>ca.id.toLowerCase()));return[...Rt,...qe.filter(ca=>!Rl.has(ca.id.toLowerCase()))]}),We(I.removedModels),J(le.length?`已保存 ${Ke.length} 个模型`:Ke.length?`已拉取 ${Ke.length} 个模型`:"上游没有返回模型"),window.setTimeout(()=>J(""),2200)}function We(R){const Z=new Set(je(R).map(le=>le.toLowerCase()));Z.size!==0&&(P(le=>le.filter(I=>!Z.has(I.id.toLowerCase()))),K(le=>le&&{...le,apiKeys:le.apiKeys.map(I=>({...I,allowedModels:I.allowedModels.filter(ge=>!Z.has(ge.toLowerCase()))}))}))}async function bt(R){try{const Z=await ve(`/api/channels/${R}/check`,{method:"POST",body:JSON.stringify({})});ie(le=>le.map(I=>I.id===R?il(Z.channel):I)),J(Z.ok?`渠道可用,检测到 ${je(Z.models).length} 个模型`:"渠道检测失败")}catch(Z){const le=Z instanceof Ci?Z.payload?.channel:null;le&&ie(I=>I.map(ge=>ge.id===R?il(le):ge)),J(Z instanceof Error?Z.message:"渠道检测失败")}window.setTimeout(()=>J(""),2400)}async function Ut(R=Ic("codex")){const Z=await ve("/api/channels",{method:"POST",body:JSON.stringify(R)});ie(le=>[...le,il(Z.channel)]),J("渠道已创建,可继续拉取模型或检测渠道"),window.setTimeout(()=>J(""),2400)}async function tl(R,Z){const le=new FormData;le.append("file",Z);const I=await I0(`/api/channels/${encodeURIComponent(R)}/import-openai-accounts`,le);ie(ge=>ge.map(qe=>qe.id===I.channel.id?il(I.channel):qe)),J(`新增 ${I.created??I.imported} 个账号${I.updated?`,更新 ${I.updated} 个已有账号`:""}${I.skipped?`,跳过 ${I.skipped} 个`:""}`),window.setTimeout(()=>J(""),2600)}async function ll(R,Z=!1,le=""){const I=await ve(`/api/channels/${encodeURIComponent(R)}/openai-accounts/check`,{method:"POST",body:JSON.stringify({onlyInvalid:Z,accountId:le})});ie(ge=>ge.map(qe=>qe.id===I.channel.id?il(I.channel):qe)),J(`${Z?"无效账号复检":"账号测活"}完成:${I.healthy}/${I.checked} 可用${I.failed?`,无效 ${I.failed}`:""}`),window.setTimeout(()=>J(""),3e3)}async function U(R){const Z=await ve(`/api/channels/${encodeURIComponent(R)}/openai-accounts/deduplicate`,{method:"POST",body:JSON.stringify({})});ie(le=>le.map(I=>I.id===Z.channel.id?il(Z.channel):I)),J(Z.removed?`已合并 ${Z.removed} 个重复账号`:"未发现可识别的重复账号"),window.setTimeout(()=>J(""),2600)}async function B(R,Z){const le=await ve(`/api/channels/${encodeURIComponent(R)}/openai-accounts/${encodeURIComponent(Z)}`,{method:"DELETE"});ie(I=>I.map(ge=>ge.id===le.channel.id?il(le.channel):ge)),J("账号已删除"),window.setTimeout(()=>J(""),1800)}async function Be(R){return ve(`/api/channels/${encodeURIComponent(R)}/openai-oauth/start`,{method:"POST",body:JSON.stringify({})})}async function Fe(R,Z){const le=await ve(`/api/channels/${encodeURIComponent(R)}/openai-oauth/complete`,{method:"POST",body:JSON.stringify(Z)});return ie(I=>I.map(ge=>ge.id===le.channel.id?il(le.channel):ge)),J("已通过 OAuth 添加账号"),window.setTimeout(()=>J(""),2400),le}async function nt(R){const Z=await ve("/api/models",{method:"POST",body:JSON.stringify(R)});P(le=>[...le,cs(Z.model)]),J("模型已添加"),window.setTimeout(()=>J(""),1800)}async function et(R,Z){const le=await ve(`/api/models/${encodeURIComponent(R)}`,{method:"PATCH",body:JSON.stringify(Z)});P(I=>I.map(ge=>ge.id===R?cs(le.model):ge)),J("模型已更新"),window.setTimeout(()=>J(""),1600)}async function zi(R){window.confirm(`删除模型 ${R}?渠道和 Key 中的引用也会一起清理。`)&&(await ve(`/api/models/${encodeURIComponent(R)}`,{method:"DELETE"}),P(Z=>Z.filter(le=>le.id!==R)),ie(Z=>Z.map(le=>({...le,models:le.models.filter(I=>I!==R)}))),K(Z=>Z&&{...Z,apiKeys:Z.apiKeys.map(le=>({...le,allowedModels:le.allowedModels.filter(I=>I!==R)}))}),J("模型已删除"),window.setTimeout(()=>J(""),1800))}async function hn(R,Z="已复制"){await Ai(R),J(Z),window.setTimeout(()=>J(""),1600)}function ia(R,Z){if(R instanceof Ci&&R.status===401){X(!1),r("login"),f("auth");return}J(Z)}async function ua(){try{const R=await ve("/api/auth/status");if(T(R),!R.initialized){r("setup"),f("auth");return}if(!R.authenticated){r("login"),f("auth");return}f(R.session?.role==="admin"?"console":"account")}catch(R){ia(R,"认证状态加载失败")}}async function Oi(){await ve("/api/auth/logout",{method:"POST"}),window.sessionStorage.removeItem("capi-admin-token"),T(null),f("home")}return b.useEffect(()=>{let R=!1;return ve("/api/auth/status").then(Z=>{R||(T(Z),Z.authenticated&&Z.session&&f(Z.session.role==="admin"?"console":"account"))}).catch(()=>{}),()=>{R=!0}},[]),b.useEffect(()=>{u==="console"&&(X(!1),m().catch(R=>ia(R,"加载数据失败")))},[u]),b.useEffect(()=>{u!=="console"||!H||h(Ce).catch(R=>ia(R,"加载用户详情失败"))},[Ce,u,H]),b.useEffect(()=>{window.localStorage.setItem("capi-theme",C)},[C]),b.useEffect(()=>{window.scrollTo({top:0,left:0})},[u,L]),u==="home"?n.jsx(xp,{theme:C,setTheme:g,enterConsole:ua}):u==="auth"?n.jsx(hp,{theme:C,mode:p,status:A,setTheme:g,setMode:r,goHome:()=>f("home"),onAuthenticated:R=>{T(Z=>Z?{...Z,authenticated:!0,initialized:!0,session:R}:null),f(R.role==="admin"?"console":"account")}}):u==="account"?n.jsx(bp,{theme:C,setTheme:g,goHome:()=>f("home"),openLogin:ua}):n.jsxs("div",{className:"app-shell","data-theme":C,"data-density":G,children:[n.jsxs("aside",{className:"sidebar",children:[n.jsxs("div",{className:"ios-window-dots","aria-hidden":"true",children:[n.jsx("span",{}),n.jsx("span",{}),n.jsx("span",{})]}),n.jsxs("div",{className:"brand",children:[n.jsx("div",{className:"brand-mark",children:"C"}),n.jsxs("div",{children:[n.jsx("strong",{children:"CAPI"}),n.jsx("span",{children:"聚合网关"})]})]}),n.jsx("nav",{children:dm.map(R=>n.jsxs("button",{className:L===R.id?"nav-item active":"nav-item",onClick:()=>$(R.id),children:[n.jsx(Ot,{name:R.icon}),n.jsx("span",{className:"nav-label",children:R.label})]},R.id))}),n.jsxs("div",{className:"sidebar-footer",children:[n.jsx("span",{children:"Gateway"}),n.jsxs("strong",{children:[n.jsx("span",{className:"pulse-dot"}),"Online"]})]})]}),n.jsxs("main",{className:"content",children:[n.jsxs("header",{className:"topbar",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"Admin Console"}),n.jsx("h1",{children:dm.find(R=>R.id===L)?.label})]}),n.jsxs("div",{className:"topbar-actions",children:[n.jsx(Vp,{value:G,options:[{value:"comfortable",label:"舒适"},{value:"compact",label:"紧凑"}],onChange:R=>z(R)}),n.jsxs("button",{className:"theme-toggle","aria-label":"切换暗色模式",onClick:()=>g(C==="dark"?"light":"dark"),children:[n.jsx(Ot,{name:C==="dark"?"sun":"moon"}),n.jsx("span",{children:C==="dark"?"浅色":"暗色"})]}),n.jsx("button",{className:"primary-button",onClick:()=>m().catch(R=>ia(R,"刷新失败")),children:"刷新"}),n.jsx("button",{className:"secondary-button home-link",onClick:()=>f("home"),children:"首页"}),n.jsx("button",{className:"secondary-button",onClick:Oi,children:"退出"})]})]}),L==="overview"&&n.jsx(jp,{overview:V,channels:ae,logs:he,onNavigate:R=>{$(R),R==="channels"&&ae.length===0&&J("渠道页可以创建第一个上游"),R==="logs"&&he.length===0&&J("暂无异常日志"),window.setTimeout(()=>J(""),1800)}}),L==="users"&&n.jsx(Np,{users:se,query:ne,selectedUser:ue,onQuery:me,onSelect:Me,onUpdate:M,onBulkUpdate:Q,onCreateKey:ee,groups:be,onOpenRegistration:()=>{$("settings"),J("在账号与注册里开放注册,用户即可自助创建账号"),window.setTimeout(()=>J(""),2400)}}),L==="groups"&&n.jsx(Kp,{groups:be,onCreate:St,onUpdate:F,onDelete:$e}),L==="keys"&&n.jsx(Ap,{selectedUser:ue,onCreateKey:ee,onUpdateKey:O,onDeleteKey:Ne}),L==="models"&&n.jsx(Tp,{models:xe,onCopy:hn,onCreate:nt,onUpdate:et,onDelete:zi}),L==="drawing"&&n.jsx(vm,{variant:"drawing",channels:ae,onCreate:Ut,onImport:tl,onCheckAccounts:ll,onDeduplicateAccounts:U,onDeleteAccount:B,onUpdate:ye,onStartOAuth:Be,onCompleteOAuth:Fe}),L==="antigravity"&&n.jsx(vm,{variant:"antigravity",channels:ae,onCreate:Ut,onImport:tl,onCheckAccounts:ll,onDeduplicateAccounts:U,onDeleteAccount:B,onUpdate:ye,onStartOAuth:Be,onCompleteOAuth:Fe}),L==="channels"&&n.jsx(Yp,{channels:ae,groups:be,onUpdate:ye,onCreate:Ut,onImport:tl,onDelete:ce,onSyncModels:rt,onCheck:bt}),L==="logs"&&n.jsx(kp,{logs:he,onCopy:hn}),L==="settings"&&n.jsx(Xp,{models:xe,channels:ae,groups:be})]}),N&&n.jsx("div",{className:"secret-dialog-backdrop",role:"presentation",children:n.jsxs("section",{className:"secret-dialog",role:"dialog","aria-modal":"true","aria-labelledby":"secret-dialog-title",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"One-time secret"}),n.jsx("h2",{id:"secret-dialog-title",children:"完整 API Key"})]}),n.jsx("p",{children:"完整密钥只显示这一次。列表中的星号内容只是识别前缀,不能用于 API 调用。"}),n.jsx("code",{children:N}),n.jsxs("div",{className:"secret-dialog-actions",children:[n.jsx("button",{className:"secondary-button",onClick:()=>{Ai(N),J("完整 Key 已复制"),window.setTimeout(()=>J(""),1800)},children:"复制"}),n.jsx("button",{className:"primary-button",onClick:()=>k(""),children:"完成"})]})]})}),de&&n.jsx("div",{className:"toast",children:de})]})}function hp({theme:u,mode:f,status:p,setTheme:r,setMode:A,goHome:T,onAuthenticated:L}){const[$,C]=b.useState(""),[g,G]=b.useState(""),[z,V]=b.useState(""),[W,fe]=b.useState(""),[te,ae]=b.useState(""),[ie,be]=b.useState(""),[Y,xe]=b.useState(!1),[P,he]=b.useState("username"),[_,ne]=b.useState("0"),[me,Ce]=b.useState(""),[Me,ue]=b.useState(!1),K=f==="setup",de=f==="register",J=Mi(p?.registrationMode),N=de&&J==="email",k=de&&J==="discord";async function H(){if(!k){if((K||de)&&te!==ie){Ce("两次输入的密码不一致");return}ue(!0),Ce("");try{const X=K?"/api/auth/setup":de?"/api/auth/register":"/api/auth/login",se=N?fp(z):$,m=f==="login"?{identifier:$,password:te}:{username:se,password:te,displayName:g,email:z,discordUserId:K?W:"",registrationEnabled:K?Y:void 0,registrationMode:K?P:void 0,defaultBalance:K?Number(_||0):void 0},h=await ve(X,{method:"POST",body:JSON.stringify(m)});L(h.session)}catch(X){Ce(X instanceof Error?X.message:"操作失败")}finally{ue(!1)}}}return n.jsxs("main",{className:"auth-page","data-theme":u,children:[n.jsxs("header",{className:"auth-topbar",children:[n.jsxs("button",{className:"auth-brand",onClick:T,children:[n.jsx("span",{className:"brand-mark",children:"C"}),n.jsx("strong",{children:"CAPI"})]}),n.jsxs("button",{className:"theme-toggle","aria-label":"切换暗色模式",onClick:()=>r(u==="dark"?"light":"dark"),children:[n.jsx(Ot,{name:u==="dark"?"sun":"moon"}),n.jsx("span",{children:u==="dark"?"浅色":"暗色"})]})]}),n.jsxs("section",{className:"auth-stage",children:[n.jsxs("div",{className:"auth-intro",children:[n.jsx("span",{children:K?"First Run":"Welcome Back"}),n.jsx("h1",{children:K?"初始化 CAPI":de?"创建账号":"登录"}),n.jsx("p",{children:K?"创建第一个管理员账号,完成后即可进入控制台。":"使用你的 CAPI 账号继续。"})]}),n.jsxs("form",{className:"auth-form",onSubmit:X=>{X.preventDefault(),H()},children:[k?n.jsxs("div",{className:"auth-discord-register",children:[n.jsx("strong",{children:"使用 Discord 创建账号"}),n.jsx("span",{children:"继续后会按站点设置校验服务器和身份组。"}),p?.discordEnabled?n.jsx("a",{className:"discord-login-button",href:"/api/auth/discord/start",children:"继续使用 Discord"}):n.jsx("div",{className:"auth-message",children:"管理员还没有启用 Discord 登录"})]}):n.jsxs(n.Fragment,{children:[f!=="login"&&n.jsxs("label",{children:[n.jsx("span",{children:"显示名称"}),n.jsx("input",{value:g,onChange:X=>G(X.target.value),autoComplete:"name",placeholder:"CAPI"})]}),!N&&n.jsxs("label",{children:[n.jsx("span",{children:f==="login"?"账号或邮箱":"账号"}),n.jsx("input",{value:$,onChange:X=>C(X.target.value),autoComplete:"username",placeholder:f==="login"?"输入账号或邮箱":"3-32 位字母、数字、_ 或 -"})]}),(K||N)&&n.jsxs("label",{children:[n.jsx("span",{children:N?"邮箱":"邮箱(可选)"}),n.jsx("input",{type:"email",value:z,onChange:X=>V(X.target.value),autoComplete:"email",placeholder:"name@example.com"})]}),K&&n.jsxs(n.Fragment,{children:[n.jsxs("label",{children:[n.jsx("span",{children:"Discord 用户 ID(可选)"}),n.jsx("input",{inputMode:"numeric",autoComplete:"off",value:W,onChange:X=>fe(X.target.value),placeholder:"绑定管理员 Discord 账号"})]}),n.jsxs("div",{className:"setup-options",children:[n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"开放注册"}),n.jsx("button",{type:"button",className:Y?"ios-switch is-on":"ios-switch","aria-pressed":Y,onClick:()=>xe(X=>!X),children:n.jsx("span",{})})]}),n.jsxs("label",{children:[n.jsx("span",{children:"注册方式"}),n.jsxs("select",{value:P,onChange:X=>he(Mi(X.target.value)),children:[n.jsx("option",{value:"username",children:"账号密码"}),n.jsx("option",{value:"email",children:"邮箱"}),n.jsx("option",{value:"discord",children:"Discord"})]})]}),n.jsxs("label",{children:[n.jsx("span",{children:"新用户初始额度"}),n.jsx("input",{type:"number",min:"0",step:"0.01",value:_,onChange:X=>ne(X.target.value)})]})]})]}),n.jsxs("label",{children:[n.jsx("span",{children:"密码"}),n.jsx("input",{type:"password",value:te,onChange:X=>ae(X.target.value),autoComplete:f==="login"?"current-password":"new-password",placeholder:"至少 8 个字符"})]}),f!=="login"&&n.jsxs("label",{children:[n.jsx("span",{children:"确认密码"}),n.jsx("input",{type:"password",value:ie,onChange:X=>be(X.target.value),autoComplete:"new-password",placeholder:"再次输入密码"})]}),n.jsx("div",{className:"auth-message",role:"status",children:me}),n.jsx("button",{className:"primary-button auth-submit",type:"submit",disabled:Me,children:Me?"请稍候":K?"创建管理员":de?"注册":"登录"})]}),!K&&!k&&p?.discordEnabled&&n.jsx("a",{className:"discord-login-button",href:"/api/auth/discord/start",children:"使用 Discord 登录"}),!K&&n.jsx("div",{className:"auth-switch",children:f==="login"&&p?.registrationEnabled?n.jsx("button",{type:"button",onClick:()=>A("register"),children:"创建账号"}):n.jsx("button",{type:"button",onClick:()=>A("login"),children:"返回登录"})})]})]})]})}const pp=[1,1.5,2,2.5,3,4,5,6,8,10];function vp(u){if(!(u>0))return 1;const f=Math.floor(Math.log10(u)),p=Math.pow(10,f),r=u/p;return(pp.find(T=>r<=T)??10)*p}const pm=88;function yp(u){const f=u.split("-");return f.length===3?`${f[1]}/${f[2]}`:u}function gp(){const[u,f]=b.useState(14),[p,r]=b.useState(null),[A,T]=b.useState(!0),[L,$]=b.useState(!1),[C,g]=b.useState("");b.useEffect(()=>{let Y=!1;return T(!0),ve(`/api/account/usage?days=${u}&timezoneOffset=${new Date().getTimezoneOffset()}`).then(xe=>{Y||(r({...xe.usage,daily:je(xe.usage?.daily),models:je(xe.usage?.models)}),$(!1))}).catch(()=>{Y||$(!0)}).finally(()=>{Y||T(!1)}),()=>{Y=!0}},[u]);const G=p?.daily??[],z=p?.models??[],V=vp(Math.max(0,...G.map(Y=>Y.cost))),W=Math.max(0,...z.map(Y=>Y.cost)),fe=G.reduce((Y,xe)=>!Y||xe.cost>Y.cost?xe:Y,null),te=Math.max(1,Math.ceil(G.length/5)),ae=G.find(Y=>Y.day===C)||null,ie=ae?G.indexOf(ae):-1,be=p?p.today.cost-p.yesterday.cost:0;return n.jsxs("section",{className:"account-section usage-section",children:[n.jsx("div",{className:"account-section-title",children:n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"Usage"}),n.jsx("h2",{children:"用量概览"})]})}),!p&&A&&n.jsx("p",{className:"usage-placeholder",children:"正在统计用量…"}),!p&&!A&&L&&n.jsx("p",{className:"usage-placeholder",children:"用量加载失败,请稍后重试"}),p&&n.jsxs("div",{className:A?"usage-body is-refreshing":"usage-body",children:[n.jsxs("div",{className:"usage-kpi",children:[n.jsxs("div",{className:"usage-tile",children:[n.jsx("span",{children:"今日消费"}),n.jsx("strong",{children:jt(p.today.cost)}),n.jsxs("small",{children:["较昨日 ",be>=0?"+":"−",jt(Math.abs(be))]})]}),n.jsxs("div",{className:"usage-tile",children:[n.jsx("span",{children:"本月消费"}),n.jsx("strong",{children:jt(p.month.cost)}),n.jsxs("small",{children:[ml(p.month.requests)," 次请求"]})]}),n.jsxs("div",{className:"usage-tile",children:[n.jsx("span",{children:"今日请求"}),n.jsx("strong",{children:ml(p.today.requests)}),n.jsxs("small",{children:["成功率 ",p.today.successRate,"%"]})]}),n.jsxs("div",{className:"usage-tile",children:[n.jsx("span",{children:"累计消费"}),n.jsx("strong",{children:jt(p.total.cost)}),n.jsxs("small",{children:[ml(p.total.requests)," 次请求"]})]})]}),n.jsx("div",{className:"usage-range",role:"group","aria-label":"统计范围",children:[7,14,30].map(Y=>n.jsxs("button",{type:"button",className:u===Y?"selected":"","aria-pressed":u===Y,onClick:()=>f(Y),children:["近 ",Y," 天"]},Y))}),n.jsxs("div",{className:"usage-block",children:[n.jsxs("div",{className:"usage-block-head",children:[n.jsx("strong",{children:"每日消费"}),n.jsxs("span",{children:["近 ",p.rangeDays," 天"]})]}),G.length===0||V<=0?n.jsx("p",{className:"usage-placeholder",children:"这段时间还没有消费记录"}):n.jsxs(n.Fragment,{children:[n.jsxs("div",{className:"usage-plot",children:[n.jsx("div",{className:"usage-grid","aria-hidden":"true",children:[1,.5,0].map(Y=>n.jsx("div",{className:"usage-gridline",style:{bottom:`${Y*pm}%`},children:n.jsx("span",{children:jt(V*Y)})},Y))}),n.jsxs("div",{className:"usage-columns",children:[G.map((Y,xe)=>{const P=V>0?Y.cost/V*pm:0,he=Y.cost>0,_=he&&fe!==null&&Y.day===fe.day,ne=xe%te===0||xe===G.length-1;return n.jsxs("div",{className:"usage-column",children:[n.jsxs("button",{type:"button",className:C===Y.day?"usage-column-hit is-hovered":"usage-column-hit",onMouseEnter:()=>g(Y.day),onMouseLeave:()=>g(""),onFocus:()=>g(Y.day),onBlur:()=>g(""),"aria-label":`${Y.day} 消费 ${jt(Y.cost)},${Y.requests} 次请求`,children:[he&&n.jsx("span",{className:"usage-column-bar",style:{height:`${P}%`}}),_&&n.jsx("span",{className:"usage-column-peak",style:{bottom:`calc(${P}% + 6px)`},children:jt(Y.cost)})]}),n.jsx("span",{className:"usage-column-tick",children:ne?yp(Y.day):""})]},Y.day)}),ae&&n.jsxs("div",{className:"usage-tooltip",style:{left:`${(ie+.5)/G.length*100}%`},role:"status",children:[n.jsx("strong",{children:jt(ae.cost)}),n.jsx("span",{children:ae.day}),n.jsxs("span",{children:[ae.requests," 次请求"]})]})]})]}),n.jsxs("details",{className:"usage-table-toggle",children:[n.jsx("summary",{children:"查看数据表"}),n.jsxs("div",{className:"usage-table",children:[n.jsxs("div",{className:"usage-table-head",children:[n.jsx("span",{children:"日期"}),n.jsx("span",{children:"请求"}),n.jsx("span",{children:"消费"})]}),G.slice().reverse().map(Y=>n.jsxs("div",{className:"usage-table-row",children:[n.jsx("span",{children:Y.day}),n.jsx("span",{children:Y.requests}),n.jsx("span",{children:jt(Y.cost)})]},Y.day))]})]})]})]}),n.jsxs("div",{className:"usage-block",children:[n.jsxs("div",{className:"usage-block-head",children:[n.jsx("strong",{children:"按模型拆分"}),n.jsxs("span",{children:["近 ",p.rangeDays," 天消费"]})]}),z.length===0?n.jsx("p",{className:"usage-placeholder",children:"这段时间还没有调用记录"}):n.jsx("div",{className:"usage-models",children:z.map(Y=>n.jsxs("div",{className:"usage-model-row",children:[n.jsx("span",{className:"usage-model-name",title:Y.model,children:Y.model}),n.jsx("span",{className:"usage-model-track",children:n.jsx("span",{className:"usage-model-bar",style:{width:`${W>0?Y.cost/W*100:0}%`}})}),n.jsx("span",{className:"usage-model-value",children:jt(Y.cost)})]},Y.model))})]})]})]})}function bp({theme:u,setTheme:f,goHome:p,openLogin:r}){const[A,T]=b.useState(null),[L,$]=b.useState([]),[C,g]=b.useState(null),[G,z]=b.useState(!1),[V,W]=b.useState(""),[fe,te]=b.useState(""),[ae,ie]=b.useState("");async function be(){try{const[_,ne,me]=await Promise.all([ve("/api/account/me"),ve("/api/catalog/models"),ve("/api/account/check-in")]);T({..._,apiKeys:je(_.apiKeys)}),$(je(ne.models).map(cs)),g(me.checkIn)}catch{r()}}b.useEffect(()=>{be()},[]);async function Y(){if(!(!C?.enabled||C.claimed||G)){z(!0),W("");try{const _=await ve("/api/account/check-in",{method:"POST",body:JSON.stringify({})});T(ne=>ne&&{...ne,user:_.user}),g(_.checkIn),W(`签到成功,获得 ${_.reward.toFixed(2)} 额度`)}catch(_){W(_ instanceof Error?_.message:"签到失败,请稍后重试")}finally{z(!1)}}}async function xe(){try{const _=await ve("/api/account/api-keys",{method:"POST",body:JSON.stringify({name:"My API Key"})});te(_.secret),ie("新密钥只显示这一次"),await be()}catch(_){ie(_ instanceof Error?_.message:"创建密钥失败")}}async function P(_){if(window.confirm("删除这个 API Key?使用它的请求会立即失效。"))try{await ve(`/api/account/api-keys/${_}`,{method:"DELETE"}),T(ne=>ne&&{...ne,apiKeys:ne.apiKeys.filter(me=>me.id!==_)}),ie("密钥已删除")}catch(ne){ie(ne instanceof Error?ne.message:"删除密钥失败")}}async function he(){await ve("/api/auth/logout",{method:"POST"}),p()}return n.jsxs("main",{className:"account-page","data-theme":u,children:[n.jsxs("header",{className:"account-topbar",children:[n.jsxs("button",{className:"auth-brand",onClick:p,children:[n.jsx("span",{className:"brand-mark",children:"C"}),n.jsx("strong",{children:"CAPI"})]}),n.jsxs("div",{className:"account-actions",children:[n.jsx("button",{className:"theme-toggle","aria-label":"切换暗色模式",onClick:()=>f(u==="dark"?"light":"dark"),children:n.jsx(Ot,{name:u==="dark"?"sun":"moon"})}),n.jsx("button",{className:"secondary-button",onClick:he,children:"退出"})]})]}),n.jsxs("section",{className:"account-content",children:[n.jsxs("div",{className:"account-heading",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"My CAPI"}),n.jsx("h1",{children:A?.user.name||"账户"})]}),n.jsxs("div",{className:"account-balance",children:[n.jsx("span",{children:"余额"}),n.jsx("strong",{children:A?A.user.balance.toFixed(2):"-"})]})]}),n.jsx(gp,{}),n.jsxs("section",{className:"account-section check-in-section",children:[n.jsxs("div",{className:"account-section-title",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"Daily Reward"}),n.jsx("h2",{children:"每日签到"})]}),n.jsx("button",{className:"primary-button",disabled:!C?.enabled||!!C?.claimed||G,onClick:Y,children:G?"领取中":C?.claimed?"今日已签到":C?.enabled?"签到领额度":"暂未开放"})]}),n.jsxs("div",{className:"check-in-summary",children:[n.jsxs("div",{children:[n.jsx("span",{children:"今日状态"}),n.jsx("strong",{children:C?.claimed?`已领取 ${C.reward.toFixed(2)}`:C?.enabled?"等待签到":"活动关闭"})]}),n.jsxs("div",{children:[n.jsx("span",{children:"随机奖励"}),n.jsx("strong",{children:C?`${C.minReward.toFixed(2)} - ${C.maxReward.toFixed(2)}`:"-"})]}),n.jsxs("div",{children:[n.jsx("span",{children:"结算日期"}),n.jsx("strong",{children:C?.day||"北京时间"})]})]}),n.jsx("p",{className:"check-in-note",children:"每天按北京时间 00:00 刷新,奖励领取后直接计入账户余额。"}),V&&n.jsx("p",{className:"account-message check-in-message",role:"status",children:V})]}),n.jsxs("section",{className:"account-section",children:[n.jsxs("div",{className:"account-section-title",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"API Keys"}),n.jsx("h2",{children:"API 密钥"})]}),n.jsx("button",{className:"primary-button",onClick:xe,children:"创建密钥"})]}),fe&&n.jsx("code",{className:"one-time-secret",children:fe}),ae&&n.jsx("p",{className:"account-message",children:ae}),n.jsxs("div",{className:"account-key-list",children:[A?.apiKeys?.map(_=>n.jsxs("div",{className:"account-key-item",children:[n.jsx("span",{className:"account-key-mark","aria-hidden":"true",children:n.jsx(Ot,{name:"key"})}),n.jsxs("div",{className:"account-key-info",children:[n.jsx("strong",{children:_.name}),n.jsxs("code",{children:[_.prefix,"…"]})]}),n.jsx(Dt,{tone:_.status,children:_t(_.status)}),n.jsx("button",{className:"icon-button","aria-label":`删除 ${_.name}`,title:"删除密钥",onClick:()=>P(_.id),children:n.jsx(Ot,{name:"ban"})})]},_.id)),je(A?.apiKeys).length===0&&n.jsx("div",{className:"empty",children:"还没有 API 密钥"})]})]}),n.jsxs("section",{className:"account-section",children:[n.jsx("div",{className:"account-section-title",children:n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"Models"}),n.jsx("h2",{children:"可用模型"})]})}),n.jsxs("div",{className:"account-model-grid",children:[L.map(_=>n.jsxs("article",{children:[n.jsx("span",{children:_.vendor}),n.jsx("strong",{children:_.name}),n.jsx("p",{children:_.description}),n.jsx("code",{children:_.id})]},_.id)),L.length===0&&n.jsx("div",{className:"account-model-empty",children:"暂无可用模型,管理员配置渠道后将在此展示"})]})]})]})]})}function xp({theme:u,setTheme:f,enterConsole:p}){return n.jsxs("main",{className:"public-home","data-theme":u,children:[n.jsxs("header",{className:"home-topbar",children:[n.jsxs("div",{className:"home-brand",children:[n.jsx("div",{className:"brand-mark",children:"C"}),n.jsxs("div",{children:[n.jsx("strong",{children:"CAPI"}),n.jsx("span",{children:"AI 聚合网关"})]})]}),n.jsxs("div",{className:"home-actions",children:[n.jsxs("button",{className:"theme-toggle","aria-label":"切换暗色模式",onClick:()=>f(u==="dark"?"light":"dark"),children:[n.jsx(Ot,{name:u==="dark"?"sun":"moon"}),n.jsx("span",{children:u==="dark"?"浅色":"暗色"})]}),n.jsx("button",{className:"primary-button",onClick:p,children:"控制台"})]})]}),n.jsxs("section",{className:"home-hero",children:[n.jsxs("div",{className:"home-copy",children:[n.jsx("span",{className:"home-kicker",children:"兼容 OpenAI 格式的网关"}),n.jsxs("h1",{children:["CAPI",n.jsx("span",{children:"轻量 AI 聚合网关"})]}),n.jsx("p",{children:"面向个人用户和团队的模型接入层。把 API Key、额度、模型渠道和调用日志放在一个清爽控制台里,保持轻量,也便于排障。"}),n.jsx("div",{className:"home-cta",children:n.jsx("button",{className:"primary-button",onClick:p,children:"进入控制台"})}),n.jsxs("div",{className:"integration-row","aria-label":"网关能力概览",children:[n.jsx("span",{children:"网关能力"}),n.jsxs("div",{children:[n.jsx("span",{children:"OpenAI 兼容接口"}),n.jsx("span",{children:"额度控制"}),n.jsx("span",{children:"调用审计"})]})]})]}),n.jsxs("div",{className:"gateway-terminal","aria-label":"CAPI 终端请求示意",children:[n.jsxs("div",{className:"terminal-titlebar",children:[n.jsxs("div",{className:"terminal-dots","aria-hidden":"true",children:[n.jsx("span",{}),n.jsx("span",{}),n.jsx("span",{})]}),n.jsx("strong",{children:"CAPI Terminal"}),n.jsxs("div",{className:"terminal-status",children:[n.jsx("span",{className:"pulse-dot"}),n.jsx("strong",{children:"Online"})]})]}),n.jsxs("div",{className:"terminal-endpoint",children:[n.jsx("span",{children:"POST"}),n.jsx("strong",{children:"/v1/chat/completions"})]}),n.jsxs("div",{className:"terminal-body",children:[n.jsxs("div",{className:"terminal-block",children:[n.jsx("span",{children:"REQUEST"}),n.jsx("pre",{children:`curl https://api.capi.local/v1/chat/completions \\ - -H "Authorization: Bearer cat_..." \\ - -d '{ - "model": "capi-fast", - "messages": [{ "role": "user", "content": "ping" }] - }'`})]}),n.jsxs("div",{className:"terminal-route",children:[n.jsxs("div",{children:[n.jsx("span",{children:"auth"}),n.jsx("strong",{children:"pass"})]}),n.jsxs("div",{children:[n.jsx("span",{children:"quota"}),n.jsx("strong",{children:"ok"})]}),n.jsxs("div",{children:[n.jsx("span",{children:"route"}),n.jsx("strong",{children:"capi-fast"})]}),n.jsxs("div",{children:[n.jsx("span",{children:"latency"}),n.jsx("strong",{children:"186ms"})]})]}),n.jsxs("div",{className:"terminal-block response",children:[n.jsx("span",{children:"RESPONSE"}),n.jsxs("pre",{children:[`{ - "status": 200, - "model": "capi-fast", - "usage": { "total_tokens": 27 }, - "message": "request routed" -}`,n.jsx("span",{className:"terminal-caret","aria-hidden":"true"})]})]})]})]})]})]})}function jp({overview:u,channels:f,logs:p,onNavigate:r}){const A=p.filter(T=>T.status!=="success");return n.jsxs("section",{className:"page-stack",children:[n.jsxs("div",{className:"hero-strip",children:[n.jsxs("div",{children:[n.jsx("span",{children:"Live Gateway"}),n.jsxs("strong",{children:["CAPI 网关正在服务 ",u?.activeUsers??"-"," 个活跃用户"]}),n.jsx("p",{children:"请求进入 CAPI 后,会按额度、模型和渠道状态自动选择最合适的上游。"})]}),n.jsxs("div",{className:"live-island",children:[n.jsx("div",{className:"pulse-dot"}),n.jsx("span",{children:"在线"})]})]}),n.jsxs("div",{className:"quick-actions","aria-label":"快捷操作",children:[n.jsx(Si,{icon:"key",label:"创建 Key",onClick:()=>r("keys")}),n.jsx(Si,{icon:"route",label:"配置渠道",onClick:()=>r("channels")}),n.jsx(Si,{icon:"users",label:"调整额度",onClick:()=>r("users")}),n.jsx(Si,{icon:"logs",label:"查看异常",onClick:()=>r("logs")})]}),n.jsxs("div",{className:"metrics-grid",children:[n.jsx(cl,{label:"活跃用户",value:u?ml(u.activeUsers):"-"}),n.jsx(cl,{label:"今日请求",value:u?ml(u.requestsToday):"-"}),n.jsx(cl,{label:"今日输入",value:u?ml(u.todayInputTokens):"-"}),n.jsx(cl,{label:"今日输出",value:u?ml(u.todayOutputTokens):"-"}),n.jsx(cl,{label:"今日扣费",value:u?jt(u.todayCost,4):"-"}),n.jsx(cl,{label:"账户余额",value:u?jt(u.totalBalance):"-"}),n.jsx(cl,{label:"成功率",value:u?`${u.successRate}%`:"-"})]}),n.jsx(Sp,{}),n.jsxs("div",{className:"split-grid",children:[n.jsx(at,{title:"渠道状态",children:f.length?f.map(T=>n.jsxs("div",{className:"list-row overview-channel-row",children:[n.jsxs("div",{children:[n.jsx("strong",{children:T.name}),n.jsx("span",{title:je(T.models).join(", "),children:op(T.models)})]}),n.jsx(Dt,{tone:T.status,children:_t(T.status)})]},T.id)):n.jsx(kt,{text:"暂无渠道"})}),n.jsx(at,{title:"最近请求",children:p.length?p.slice(0,4).map(T=>n.jsxs("div",{className:"list-row",children:[n.jsxs("div",{children:[n.jsx("strong",{children:lo(T)}),n.jsxs("span",{children:[T.id," · ",T.errorCode||el(T.createdAt)]})]}),n.jsx(Dt,{tone:T.status,children:_t(T.status)})]},T.id)):n.jsx(kt,{text:A.length?"暂无最近请求":"暂无请求"})})]})]})}function Si({icon:u,label:f,onClick:p}){return n.jsxs("button",{className:"quick-action",onClick:p,children:[n.jsx(Ot,{name:u}),n.jsx("span",{children:f})]})}function Sp(){const u=[{label:"认证",detail:"校验 API Key"},{label:"额度",detail:"检查余额"},{label:"路由",detail:"选择渠道"},{label:"响应",detail:"返回结果"}];return n.jsxs("section",{className:"flow-panel","aria-label":"网关流转",children:[n.jsxs("div",{className:"flow-copy",children:[n.jsx("span",{children:"Request Flow"}),n.jsx("strong",{children:"请求处理流程"})]}),n.jsx("div",{className:"flow-steps",children:u.map((f,p)=>n.jsxs("div",{className:"flow-step",children:[n.jsx("div",{className:"flow-index",children:p+1}),n.jsx("strong",{children:f.label}),n.jsx("span",{children:f.detail})]},f.label))})]})}function Np({users:u,query:f,selectedUser:p,onQuery:r,onSelect:A,onUpdate:T,onBulkUpdate:L,onCreateKey:$,groups:C,onOpenRegistration:g}){const[z,V]=b.useState(1),[W,fe]=b.useState("all"),[te,ae]=b.useState(new Set),[ie,be]=b.useState("10"),[Y,xe]=b.useState(""),[P,he]=b.useState(""),[_,ne]=b.useState(!1),[me,Ce]=b.useState("10"),[Me,ue]=b.useState(""),[K,de]=b.useState(""),[J,N]=b.useState(!1),k=W==="all"?u:u.filter(O=>O.status===W),H=k.filter(O=>O.role!=="admin"),X=Math.max(1,Math.ceil(k.length/25)),se=Math.min(z,X),m=k.slice((se-1)*25,se*25),h=H.length>0&&H.every(O=>te.has(O.id));b.useEffect(()=>{V(1)},[f,W]),b.useEffect(()=>{const O=new Set(u.map(ye=>ye.id));ae(ye=>new Set([...ye].filter(ce=>O.has(ce))))},[u]),b.useEffect(()=>{Ce("10"),ue(""),de("")},[p?.user.id]);function M(O){ae(ye=>{const ce=new Set(ye);return ce.has(O)?ce.delete(O):ce.add(O),ce})}function Q(){ae(O=>{const ye=new Set(O);return h?H.forEach(ce=>ye.delete(ce.id)):H.forEach(ce=>ye.add(ce.id)),ye})}async function ee(O,ye){if(te.size!==0){ne(!0);try{await L([...te],O,ye),ae(new Set),xe("")}finally{ne(!1)}}}async function Ne(O){if(!p)return;const ye=Math.abs(Number(me));if(!Number.isFinite(ye)||ye<=0){de("请输入大于 0 的金额");return}N(!0),de("");try{await L([p.user.id],"adjust_balance",{amount:Number((ye*O).toFixed(4)),reason:Me.trim()||(O>0?"管理员增加额度":"管理员扣减额度")}),de(O>0?"额度已增加":"额度已扣减"),ue("")}catch(ce){de(ce instanceof Error?ce.message:"额度调整失败")}finally{N(!1)}}return n.jsxs("section",{className:"users-layout",children:[n.jsxs(at,{title:"用户管理",children:[n.jsxs("div",{className:"panel-toolbar",children:[n.jsxs("div",{className:"search-box",children:[n.jsx(Ot,{name:"search"}),n.jsx("input",{value:f,onChange:O=>r(O.target.value),placeholder:"搜索 ID、姓名或邮箱"})]}),n.jsx("button",{className:"icon-button",title:"开放注册",onClick:g,children:n.jsx(Ot,{name:"plus"})})]}),n.jsxs("div",{className:"user-summary-strip",children:[n.jsxs("span",{children:[n.jsx("strong",{children:u.length})," 匹配用户"]}),n.jsxs("span",{children:[n.jsx("strong",{children:u.filter(O=>O.status==="active").length})," 正常"]}),n.jsxs("span",{children:[n.jsx("strong",{children:u.filter(O=>O.status==="disabled").length})," 禁用"]}),n.jsxs("span",{children:[n.jsx("strong",{children:u.reduce((O,ye)=>O+ye.requestsToday,0)})," 今日请求"]})]}),n.jsx("div",{className:"user-filter-row",role:"group","aria-label":"用户状态筛选",children:[{value:"all",label:"全部"},{value:"active",label:"正常"},{value:"limited",label:"受限"},{value:"disabled",label:"禁用"}].map(O=>n.jsx("button",{type:"button",className:W===O.value?"selected":"",onClick:()=>fe(O.value),children:O.label},O.value))}),n.jsx("button",{type:"button",className:"secondary-button mobile-bulk-select",onClick:Q,children:h?"取消全选":`全选结果(${H.length})`}),te.size>0&&n.jsxs("div",{className:"bulk-action-bar",children:[n.jsxs("strong",{children:["已选 ",te.size," 人"]}),n.jsx("input",{type:"number",step:"0.01",value:ie,onChange:O=>be(O.target.value),"aria-label":"额度调整值"}),n.jsx("input",{value:Y,onChange:O=>xe(O.target.value),placeholder:"原因,例如:活动赠送","aria-label":"调整原因"}),n.jsx("button",{type:"button",className:"secondary-button",disabled:_||!Number(ie),onClick:()=>ee("adjust_balance",{amount:Number(ie),reason:Y}),children:"调整额度"}),n.jsx("button",{type:"button",className:"secondary-button",disabled:_,onClick:()=>ee("set_status",{value:"active"}),children:"启用"}),n.jsx("button",{type:"button",className:"danger-button",disabled:_,onClick:()=>ee("set_status",{value:"disabled"}),children:"禁用"}),n.jsxs("select",{className:"bulk-group-select",value:P,disabled:_,"aria-label":"批量设置分组",onChange:O=>he(O.target.value),children:[n.jsx("option",{value:"",children:"未分组"}),C.map(O=>n.jsx("option",{value:O.id,children:O.name},O.id))]}),n.jsx("button",{type:"button",className:"secondary-button",disabled:_,onClick:()=>ee("set_group",{value:P}),children:"设为分组"})]}),n.jsxs("div",{className:"table",children:[n.jsxs("div",{className:"table-head users-table",children:[n.jsx("input",{type:"checkbox",checked:h,onChange:Q,"aria-label":"选择当前筛选结果"}),n.jsx("span",{children:"用户"}),n.jsx("span",{children:"状态"}),n.jsx("span",{children:"余额"}),n.jsx("span",{children:"今日"})]}),m.map(O=>n.jsxs("div",{className:p?.user.id===O.id?"table-row users-table selected":"table-row users-table",role:"button",tabIndex:0,onClick:()=>A(O.id),onKeyDown:ye=>{(ye.key==="Enter"||ye.key===" ")&&A(O.id)},children:[n.jsx("input",{type:"checkbox",checked:te.has(O.id),disabled:O.role==="admin",onChange:()=>M(O.id),onClick:ye=>ye.stopPropagation(),"aria-label":O.role==="admin"?`${O.name} 是管理员,不参与批量操作`:`选择 ${O.name}`}),n.jsxs("span",{children:[n.jsx("strong",{children:O.name}),n.jsxs("small",{children:[O.id," · ",O.email||"未绑定邮箱"]})]}),n.jsx(Dt,{tone:O.status,children:_t(O.status)}),n.jsx("span",{children:jt(O.balance)}),n.jsx("span",{children:O.requestsToday})]},O.id)),k.length===0&&n.jsx(kt,{text:"暂无匹配用户"})]}),k.length>25&&n.jsxs("div",{className:"pagination-bar",children:[n.jsx("button",{className:"secondary-button",disabled:se<=1,onClick:()=>V(O=>Math.max(1,O-1)),children:"上一页"}),n.jsxs("span",{children:[se," / ",X]}),n.jsx("button",{className:"secondary-button",disabled:se>=X,onClick:()=>V(O=>Math.min(X,O+1)),children:"下一页"})]})]}),n.jsx(at,{title:"用户详情",children:p?n.jsxs("div",{className:"detail-stack",children:[n.jsxs("div",{className:"user-hero",children:[n.jsx("div",{className:"avatar",children:p.user.name.slice(0,1)}),n.jsxs("div",{children:[n.jsx("h2",{children:p.user.name}),n.jsx("p",{children:p.user.email})]}),n.jsx(Dt,{tone:p.user.status,children:_t(p.user.status)})]}),n.jsxs("div",{className:"settings-group",children:[n.jsx(Pt,{label:"角色",value:p.user.role==="admin"?"管理员":"用户"}),n.jsx(Pt,{label:"余额",value:jt(p.user.balance)}),n.jsx(Pt,{label:"总请求",value:String(p.user.totalRequests)}),n.jsx(Pt,{label:"最后登录",value:el(p.user.lastLoginAt)}),n.jsx(Pt,{label:"API 调用",value:p.user.status==="disabled"?"关闭":"允许",switchOn:p.user.status!=="disabled"})]}),n.jsxs("div",{className:"group-assign-row",children:[n.jsxs("label",{children:[n.jsx("span",{children:"所属分组"}),n.jsxs("select",{value:p.user.groupId||"",onChange:O=>T(p.user.id,{groupId:O.target.value}),children:[n.jsx("option",{value:"",children:"未分组"}),C.map(O=>n.jsx("option",{value:O.id,children:O.name},O.id))]})]}),n.jsx("small",{children:"分组决定该用户可路由到哪些渠道;未分组用户只能使用未限制分组的渠道。"})]}),n.jsxs("div",{className:"balance-adjuster",children:[n.jsxs("div",{className:"balance-adjuster-title",children:[n.jsx("strong",{children:"调整余额"}),n.jsxs("span",{children:["当前 ",jt(p.user.balance)]})]}),n.jsxs("div",{className:"balance-adjuster-fields",children:[n.jsxs("label",{children:[n.jsx("span",{children:"金额"}),n.jsx("input",{type:"number",min:"0.0001",step:"0.01",value:me,onChange:O=>Ce(O.target.value)})]}),n.jsxs("label",{children:[n.jsx("span",{children:"备注"}),n.jsx("input",{value:Me,onChange:O=>ue(O.target.value),placeholder:"可选,会记录到流水"})]})]}),n.jsxs("div",{className:"balance-adjuster-actions",children:[n.jsx("button",{className:"secondary-button",disabled:J,onClick:()=>Ne(1),children:"增加"}),n.jsx("button",{className:"danger-button",disabled:J,onClick:()=>Ne(-1),children:"扣减"}),n.jsx("span",{role:"status",children:K})]})]}),n.jsxs("div",{className:"action-row",children:[n.jsx("button",{className:"secondary-button",onClick:()=>$(p.user.id),children:"创建 Key"}),n.jsx("button",{className:"secondary-button",disabled:p.user.role==="admin",onClick:()=>T(p.user.id,{status:p.user.status==="disabled"?"active":"disabled"}),children:p.user.role==="admin"?"管理员保护":p.user.status==="disabled"?"解封":"禁用"})]}),n.jsxs("div",{children:[n.jsx("h3",{children:"API Key"}),p.apiKeys.map(O=>n.jsxs("div",{className:"list-row",children:[n.jsxs("div",{children:[n.jsx("strong",{children:O.name}),n.jsxs("span",{children:[O.prefix,"*** · ",O.requestCount," 次"]})]}),n.jsx(Dt,{tone:O.status,children:_t(O.status)})]},O.id)),p.apiKeys.length===0&&n.jsx(kt,{text:"暂无 API Key"})]})]}):n.jsx(kt,{text:"请选择一个用户"})})]})}function Ap({selectedUser:u,onCreateKey:f,onUpdateKey:p,onDeleteKey:r}){return n.jsx(at,{title:"密钥管理",children:u?n.jsxs(n.Fragment,{children:[n.jsxs("div",{className:"panel-toolbar",children:[n.jsxs("span",{className:"muted-inline",children:[u.user.name," · 完整 Key 只在创建时显示,丢失请重新创建"]}),n.jsx("button",{className:"primary-button",onClick:()=>f(u.user.id),children:"创建 Key"})]}),u.apiKeys.length?u.apiKeys.map(A=>n.jsx(Cp,{apiKey:A,onSave:p,onDelete:r},A.id)):n.jsx(kt,{text:"暂无密钥"})]}):n.jsx(kt,{text:"请选择一个用户"})})}function Cp({apiKey:u,onSave:f,onDelete:p}){const[r,A]=b.useState(u.name),[T,L]=b.useState(je(u.allowedModels).join(", ")),[$,C]=b.useState(mm(u.expiresAt||"")),[g,G]=b.useState(String(u.rateLimitPerMinute||"")),[z,V]=b.useState(!1),W=je(u.allowedModels).length?je(u.allowedModels).join(", "):"全部模型";b.useEffect(()=>{A(u.name),L(je(u.allowedModels).join(", ")),C(mm(u.expiresAt||"")),G(String(u.rateLimitPerMinute||""))},[u]);async function fe(){V(!0);try{await f(u.id,{name:r.trim()||"API Key",allowedModels:Pc(T),expiresAt:sp($),rateLimitPerMinute:Number(g||0)})}finally{V(!1)}}return n.jsxs("details",{className:"key-editor key-editor-collapsible",children:[n.jsxs("summary",{className:"key-editor-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:u.name}),n.jsxs("span",{children:[u.prefix,"*** · ",W," · 最后使用 ",el(u.lastUsedAt)]})]}),n.jsxs("div",{className:"row-actions",children:[n.jsx(Dt,{tone:u.status,children:_t(u.status)}),n.jsx("span",{className:"key-expand-hint",children:"管理"})]})]}),n.jsxs("div",{className:"key-editor-body",children:[n.jsxs("div",{className:"key-editor-grid",children:[n.jsxs("label",{children:["名称",n.jsx("input",{value:r,onChange:te=>A(te.target.value)})]}),n.jsxs("label",{children:["允许模型",n.jsx("input",{value:T,onChange:te=>L(te.target.value),placeholder:"留空表示全部模型,多个用逗号分隔"})]}),n.jsxs("label",{children:["过期时间",n.jsx("input",{type:"datetime-local",value:$,onChange:te=>C(te.target.value)})]}),n.jsxs("label",{children:["每分钟限制",n.jsx("input",{type:"number",min:"0",value:g,onChange:te=>G(te.target.value),placeholder:"0 使用全局限制"})]})]}),n.jsxs("div",{className:"key-editor-actions",children:[n.jsx("button",{className:"secondary-button",onClick:()=>f(u.id,{status:u.status==="active"?"disabled":"active"}),children:u.status==="active"?"停用密钥":"启用密钥"}),n.jsx("button",{className:"danger-button",onClick:()=>p(u.id),children:"删除密钥"}),n.jsx("button",{className:"primary-button",disabled:z,onClick:fe,children:z?"保存中":"保存设置"})]})]})]})}function Tp({models:u,onCopy:f,onCreate:p,onUpdate:r,onDelete:A}){const T=u.filter(H=>H.recommended),[L,$]=b.useState(""),[C,g]=b.useState("all"),[G,z]=b.useState("all"),[V,W]=b.useState(1),[fe,te]=b.useState(""),[ae,ie]=b.useState(""),[be,Y]=b.useState(""),[xe,P]=b.useState(""),[he,_]=b.useState(""),[ne,me]=b.useState(""),Ce=60,Me=b.useMemo(()=>{const H=new Map;return u.forEach(X=>{const se=$c(X);H.set(se,(H.get(se)||0)+1)}),Array.from(H.entries()).sort((X,se)=>se[1]-X[1]||ul(X[0]).localeCompare(ul(se[0]))).map(([X,se])=>({provider:X,count:se}))},[u]),ue=b.useMemo(()=>{const H=L.trim().toLowerCase();return u.filter(X=>C!=="all"&&$c(X)!==C||G!=="all"&&X.status!==G?!1:H?[X.id,X.name,X.vendor,X.category,X.description,...je(X.aliases)].join(" ").toLowerCase().includes(H):!0)},[u,L,C,G]),K=b.useMemo(()=>{const H=new Map;ue.forEach(M=>{const Q=$c(M);H.set(Q,[...H.get(Q)||[],M])});const X=[];let se=[],m=0;const h=Array.from(H.entries()).sort((M,Q)=>ul(M[0]).localeCompare(ul(Q[0])));for(const M of h)se.length>0&&m+M[1].length>Ce&&(X.push(se),se=[],m=0),se.push(M),m+=M[1].length;return se.length>0&&X.push(se),X},[ue]),de=Math.max(1,K.length),J=Math.min(V,de),N=K[J-1]||[];b.useEffect(()=>{W(1)},[L,C,G,u.length]);async function k(H){H.preventDefault();const X=fe.trim();if(X){me("");try{await p({id:X,name:ae.trim()||X,vendor:be.trim()||"Custom",aliases:xe.split(",").map(se=>se.trim()).filter(Boolean),category:"通用",description:he.trim(),price:"自定义",context:"未配置上下文"}),te(""),ie(""),Y(""),P(""),_("")}catch(se){me(se instanceof Error?se.message:"模型添加失败")}}}return n.jsxs("section",{className:"models-page",children:[n.jsx("div",{className:"model-hero",children:n.jsxs("div",{children:[n.jsx("span",{children:"Model Catalog"}),n.jsx("strong",{children:"Models"})]})}),n.jsx(at,{title:"新增模型",children:n.jsxs("form",{className:"model-create-form",onSubmit:k,children:[n.jsx("input",{value:fe,onChange:H=>te(H.target.value),placeholder:"模型 ID,例如 openai/gpt-4.1"}),n.jsx("input",{value:ae,onChange:H=>ie(H.target.value),placeholder:"显示名称(可选)"}),n.jsx("input",{value:be,onChange:H=>Y(H.target.value),placeholder:"供应商(可选)"}),n.jsx("input",{value:xe,onChange:H=>P(H.target.value),placeholder:"代称,多个用逗号分隔(可选)"}),n.jsx("input",{className:"model-create-wide",value:he,onChange:H=>_(H.target.value),placeholder:"描述(可选)"}),n.jsx("button",{className:"primary-button",type:"submit",children:"新增模型"}),n.jsx("div",{className:"model-create-message",role:"status",children:ne})]})}),T.length>0&&n.jsx(at,{title:"推荐模型",children:n.jsx("div",{className:"model-grid",children:T.map(H=>n.jsx(Mp,{model:H,featured:!0,onCopy:f,onUpdate:r},H.id))})}),n.jsxs(at,{title:"全部模型",children:[n.jsxs("div",{className:"panel-toolbar model-list-toolbar",children:[n.jsx("input",{value:L,onChange:H=>$(H.target.value),placeholder:"搜索模型 ID、名称、供应商或代称"}),n.jsx("div",{className:"model-filter-actions",children:[{value:"all",label:"全部"},{value:"available",label:"可用"},{value:"disabled",label:"禁用"}].map(H=>n.jsx("button",{type:"button",className:G===H.value?"selected":"",onClick:()=>z(H.value),children:H.label},H.value))})]}),n.jsxs("div",{className:"model-provider-filter","aria-label":"按供应商筛选模型",children:[n.jsxs("button",{type:"button",className:C==="all"?"selected":"",onClick:()=>g("all"),children:[n.jsx("span",{className:"provider-icon provider-icon-all","aria-hidden":"true",children:"All"}),n.jsx("strong",{children:"全部"}),n.jsx("small",{children:u.length})]}),Me.map(H=>n.jsxs("button",{type:"button",className:C===H.provider?"selected":"",onClick:()=>g(H.provider),children:[n.jsx(hm,{provider:H.provider}),n.jsx("strong",{children:ul(H.provider)}),n.jsx("small",{children:H.count})]},H.provider))]}),n.jsxs("div",{className:"model-list-summary",children:[n.jsx("span",{children:C==="all"?"全部供应商":ul(C)}),n.jsx("strong",{children:ue.length}),n.jsx("span",{children:"个模型"})]}),ue.length>0?n.jsxs(n.Fragment,{children:[n.jsx("div",{className:"model-provider-groups",children:N.map(([H,X])=>n.jsxs("section",{className:"model-provider-group",children:[n.jsxs("header",{children:[n.jsx(hm,{provider:H}),n.jsxs("div",{children:[n.jsx("strong",{children:ul(H)}),n.jsxs("span",{children:[X.length," 个模型"]})]})]}),n.jsx("div",{className:"model-compact-grid",children:X.map(se=>n.jsx(Ep,{model:se,onCopy:f,onUpdate:r,onDelete:A},se.id))})]},H))}),de>1&&n.jsxs("div",{className:"pager",children:[n.jsx("button",{className:"secondary-button compact-button",onClick:()=>W(H=>Math.max(1,H-1)),disabled:J<=1,children:"上一页"}),n.jsxs("span",{children:[J," / ",de]}),n.jsx("button",{className:"secondary-button compact-button",onClick:()=>W(H=>Math.min(de,H+1)),disabled:J>=de,children:"下一页"})]})]}):n.jsx(kt,{text:u.length?"没有匹配的模型":"暂无模型,请先添加你要开放给用户调用的模型 ID"})]})]})}function Ep({model:u,onCopy:f,onUpdate:p,onDelete:r}){const A=je(u.aliases).slice(0,3),T=u.status==="disabled";return n.jsxs("article",{className:"model-compact-row",children:[n.jsxs("div",{className:"model-compact-main",children:[n.jsx("strong",{children:u.name}),n.jsx("small",{children:u.id}),A.length>0&&n.jsx("span",{children:A.map(L=>n.jsx("em",{children:L},L))})]}),n.jsxs("div",{className:"model-row-actions",children:[n.jsx(Dt,{tone:u.status,children:_t(u.status)}),u.recommended&&n.jsx("span",{className:"model-recommended-mark",children:"推荐"}),n.jsx("button",{className:"icon-button",title:"复制模型 ID",onClick:()=>f(u.id,"模型 ID 已复制"),children:n.jsx(Ot,{name:"copy"})}),n.jsxs("details",{className:"model-row-menu",children:[n.jsx("summary",{"aria-label":"模型操作",children:"•••"}),n.jsxs("div",{children:[n.jsx("button",{type:"button",onClick:()=>p(u.id,{recommended:!u.recommended}),children:u.recommended?"取消推荐":"设为推荐"}),n.jsx("button",{type:"button",onClick:()=>p(u.id,{status:T?"available":"disabled"}),children:T?"启用模型":"停用模型"}),n.jsx("button",{className:"is-danger",type:"button",onClick:()=>r(u.id),children:"删除模型"})]})]})]})]})}function Mp({model:u,featured:f=!1,onCopy:p,onUpdate:r}){return n.jsxs("article",{className:f?"model-card featured":"model-card",children:[n.jsxs("div",{className:"model-card-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:u.name}),n.jsxs("span",{children:[u.vendor," · ",u.category]})]}),n.jsx(Dt,{tone:u.status,children:_t(u.status)})]}),n.jsx("p",{children:u.description}),n.jsx("div",{className:"alias-row",children:je(u.aliases).map(A=>n.jsx("span",{children:A},A))}),n.jsxs("div",{className:"model-meta",children:[n.jsxs("span",{children:["价格:",u.price]}),n.jsx("span",{children:u.context})]}),n.jsxs("div",{className:"model-id",children:[n.jsx("code",{children:u.id}),n.jsx("button",{className:"icon-button",title:"复制模型 ID",onClick:()=>p(u.id,"模型 ID 已复制"),children:n.jsx(Ot,{name:"copy"})})]}),r&&n.jsxs("div",{className:"model-card-actions",children:[n.jsx("button",{className:"secondary-button compact-button",type:"button",onClick:()=>r(u.id,{recommended:!1}),children:"取消推荐"}),n.jsx("button",{className:"secondary-button compact-button",type:"button",onClick:()=>r(u.id,{status:u.status==="disabled"?"available":"disabled"}),children:u.status==="disabled"?"启用":"停用"})]})]})}function vm({channels:u,onCreate:f,onImport:p,onCheckAccounts:r,onDeduplicateAccounts:A,onDeleteAccount:T,onUpdate:L,onStartOAuth:$,onCompleteOAuth:C,variant:g="drawing"}){const G=g==="antigravity",z=u.filter(h=>G?h.provider==="antigravity":h.provider!=="antigravity"&&(h.provider==="codex"||h.provider==="openai"||je(h.models).some(M=>M.includes("image")))),[V,W]=b.useState(""),[fe,te]=b.useState({}),[ae,ie]=b.useState({}),[be,Y]=b.useState({}),[xe,P]=b.useState({}),[he,_]=b.useState(""),[ne,me]=b.useState(""),[Ce,Me]=b.useState(""),[ue,K]=b.useState(""),de=24,J=48;async function N(h,M){W(`import:${h}`);try{await p(h,M)}finally{W("")}}async function k(h,M=!1,Q=""){W(Q?`check-account:${Q}`:`${M?"retry":"check"}:${h}`);try{await r(h,M,Q)}finally{W("")}}async function H(h){W(`dedupe:${h}`);try{await A(h)}finally{W("")}}function X(h){const M=je(h.openaiAccounts).map(ce=>[ce.email||ce.name||ce.accountId||ce.id,ce.accountId||"",ce.status||"unchecked",ce.credentialMode||"access-token",ce.planType||"",ce.expiresAt||"",ce.lastCheckedAt||"",ce.lastUsedAt||"",String(ce.requestCount||0),ce.lastErrorCode||"",ce.lastError||""]),Q=ce=>`"${ce.replace(/"/g,'""')}"`,ee=[["账号","Account ID","状态","凭据方式","套餐","到期时间","最近检测","最近调用","调用次数","错误码","最后错误"],...M].map(ce=>ce.map(Q).join(",")).join(`\r -`),Ne=new Blob(["\uFEFF"+ee],{type:"text/csv;charset=utf-8"}),O=URL.createObjectURL(Ne),ye=document.createElement("a");ye.href=O,ye.download=`${h.name||"account-pool"}-health-report.csv`,ye.click(),URL.revokeObjectURL(O)}async function se(h){W(`status:${h.id}`);try{await L(h.id,{status:h.status==="disabled"?"healthy":"disabled",baseUrl:h.baseUrl||Ei(h.provider)||Ti,provider:h.provider||"codex",models:je(h.models).length?h.models:jm.split(",").map(M=>M.trim())})}finally{W("")}}async function m(h,M){const Q=M.email||M.name||M.accountId||M.id;if(window.confirm(`删除账号「${Q}」?`)){W(`delete-account:${M.id}`);try{await T(h.id,M.id)}finally{W("")}}}return n.jsxs(at,{title:G?"Antigravity 账号池":"账号池",children:[n.jsxs("div",{className:"panel-toolbar",children:[n.jsx("span",{className:"muted-inline",children:G?"导入 Google OAuth JSON 或 refresh token 即可入池。":"账号有两种来源,任选其一即可。"}),G?n.jsx("button",{className:"primary-button",onClick:()=>f(Ic("antigravity")),children:"新增 Antigravity 账号池"}):n.jsx("button",{className:"primary-button",onClick:()=>f(Ic("codex")),children:"新增账号池渠道"})]}),n.jsx("div",{className:"source-guide",children:G?n.jsxs(n.Fragment,{children:[n.jsxs("div",{className:"source-guide-item",children:[n.jsx("strong",{children:"Antigravity 导入(推荐)"}),n.jsx("span",{children:"粘贴 Google OAuth 凭据 JSON 或 refresh token,调用前自动换取 accessToken。"})]}),n.jsxs("div",{className:"source-guide-item",children:[n.jsx("strong",{children:"批量导入"}),n.jsx("span",{children:"支持 JSON、ZIP、TXT;TXT 可使用 JSONL 或每行一个 refresh token。"})]})]}):n.jsxs(n.Fragment,{children:[n.jsxs("div",{className:"source-guide-item",children:[n.jsx("strong",{children:"网页会话(推荐)"}),n.jsx("span",{children:"支持完整 auth/session JSON 或浏览器 Session Cookie,并在调用前重新获取 accessToken。"})]}),n.jsxs("div",{className:"source-guide-item",children:[n.jsx("strong",{children:"批量导入"}),n.jsx("span",{children:"支持 JSON、ZIP、TXT;TXT 可使用 JSONL 或每行一个 access token。"})]})]})}),n.jsxs("div",{className:"channels-stack",children:[z.map(h=>{const M=je(h.openaiAccounts),Q=M.filter(B=>B.status==="healthy").length,ee=M.filter(B=>B.status==="invalid").length,Ne=M.filter(B=>!!B.lastErrorCode).length,O=Math.max(0,M.length-Q-ee),ye=M.filter(B=>B.credentialMode==="refreshable").length,ce=M.filter(B=>B.credentialMode==="browser-session").length,St=Math.max(0,M.length-ye-ce),F=ae[h.id]||"all",$e=(be[h.id]||"").trim().toLowerCase(),rt=M.filter(B=>{const Be=F==="all"||F==="attention"&&Gp(B)||F==="invalid"&&B.status==="invalid"||F==="error"&&!!B.lastErrorCode||F==="refreshable"&&B.credentialMode==="refreshable",Fe=`${B.email||""} ${B.name||""} ${B.accountId||""} ${B.userId||""} ${B.lastError||""}`.toLowerCase();return Be&&(!$e||Fe.includes($e))}),We=xe[h.id]||"pool",bt=[...rt].sort((B,Be)=>{if(We==="pool")return 0;const Fe=We==="expiry"?B.expiresAt||"9999-12-31":B.lastUsedAt||"",nt=We==="expiry"?Be.expiresAt||"9999-12-31":Be.lastUsedAt||"";return We==="recent"?nt.localeCompare(Fe):Fe.localeCompare(nt)}),Ut=Math.min(bt.length,fe[h.id]||de),tl=bt.slice(0,Ut),ll=Math.max(0,bt.length-tl.length),U=ll===0;return n.jsxs("div",{className:"channel-card",children:[n.jsxs("div",{className:"channel-card-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:h.name}),n.jsx("span",{children:h.baseUrl||Ei(h.provider)||Ti}),n.jsxs("small",{children:["账号 ",M.length," 个,可用 ",Q,",无效 ",ee,",未验证 ",O]}),n.jsxs("small",{children:["可续期 ",ye," · 网页会话 ",ce," · 仅 Token ",St]}),n.jsxs("small",{children:["自动检测 ",h.lastCheckedAt?el(h.lastCheckedAt):"等待首次检测"]})]}),n.jsxs("div",{className:"channel-card-head-actions",children:[n.jsx(Dt,{tone:h.status,children:_t(h.status)}),n.jsx("button",{className:"primary-button compact-button",onClick:()=>K(h.id),disabled:V!=="",children:"添加账号"}),n.jsx("button",{className:"secondary-button compact-button",onClick:()=>k(h.id),disabled:V!==""||M.length===0,children:V===`check:${h.id}`?"检测中":"批量检测"}),ee>0&&n.jsx("button",{className:"secondary-button compact-button",onClick:()=>k(h.id,!0),disabled:V!=="",children:V===`retry:${h.id}`?"复检中":`复检无效 ${ee}`}),M.length>1&&n.jsx("button",{className:"secondary-button compact-button",onClick:()=>H(h.id),disabled:V!=="",children:V===`dedupe:${h.id}`?"去重中":"账号去重"}),M.length>0&&n.jsx("button",{className:"secondary-button compact-button",onClick:()=>X(h),disabled:V!=="",children:"导出报告"}),n.jsx("button",{className:"secondary-button compact-button",onClick:()=>se(h),disabled:V!=="",children:h.status==="disabled"?"启用渠道":"停用渠道"})]})]}),n.jsxs("div",{className:"account-filter-bar",role:"group","aria-label":"账号筛选",children:[n.jsx("input",{value:be[h.id]||"",onChange:B=>Y(Be=>({...Be,[h.id]:B.target.value})),placeholder:"搜索账号或错误","aria-label":"搜索账号"}),n.jsxs("select",{value:We,onChange:B=>P(Be=>({...Be,[h.id]:B.target.value})),"aria-label":"账号排序",children:[n.jsx("option",{value:"pool",children:"账号池顺序"}),n.jsx("option",{value:"oldest",children:"最久未用优先"}),n.jsx("option",{value:"recent",children:"最近使用优先"}),n.jsx("option",{value:"expiry",children:"最早到期优先"})]}),[["all",`全部 ${M.length}`],["attention","需关注"],["invalid",`无效 ${ee}`],["error",`有错误 ${Ne}`],["refreshable",`可续期 ${ye}`]].map(([B,Be])=>n.jsx("button",{type:"button",className:F===B?"selected":"",onClick:()=>ie(Fe=>({...Fe,[h.id]:B})),children:Be},B))]}),n.jsxs("div",{className:"metrics-grid",children:[n.jsx(cl,{label:"账号总数",value:M.length}),n.jsx(cl,{label:"可用账号",value:Q}),n.jsx(cl,{label:"无效账号",value:ee}),n.jsx(cl,{label:"未验证账号",value:O})]}),n.jsx("div",{className:"drawing-channel-models",children:je(h.models).length?je(h.models).map(B=>n.jsx("span",{children:B},B)):n.jsx("span",{children:"未绑定绘图模型"})}),M.length>0&&n.jsxs("div",{className:"account-pool-list",children:[tl.map(B=>n.jsxs("div",{className:"account-pool-row",children:[n.jsxs("div",{className:"account-pool-main",children:[n.jsxs("div",{children:[n.jsxs("div",{className:"account-pool-title",children:[n.jsx("strong",{title:B.email||B.name||B.accountId||B.id,children:B.email||B.name||B.accountId||B.id}),n.jsx("span",{className:`source-tag source-tag-${B.source==="web-login"?"web":"manual"}`,children:B.source==="web-login"?"网页登录":B.source==="web-oauth"?"网页 OAuth":B.source==="oauth"?"Codex OAuth":B.source==="antigravity"||B.source==="agy"||B.source==="google-antigravity"?"Antigravity":"导入"})]}),n.jsx("span",{children:B.lastError?`${fm(B.lastErrorCode)}${fm(B.lastErrorCode)?" · ":""}${B.lastError}`:B.lastCheckedAt?`上次检测 ${el(B.lastCheckedAt)}`:"未检测"}),n.jsxs("span",{children:[B.credentialMode==="refreshable"?"可自动续期":B.credentialMode==="browser-session"?"依赖网页会话":"仅 access token",B.expiresAt?` · 到期 ${el(B.expiresAt)}`:""]}),n.jsxs("span",{children:["套餐 ",ap(B.planType)]}),B.lastUsedAt&&n.jsxs("span",{children:["最近调用 ",el(B.lastUsedAt)," · ",B.requestCount||0," 次"]})]}),n.jsx(wp,{limits:B.quotaLimits})]}),n.jsxs("div",{className:"account-pool-meta",children:[n.jsx(Dt,{tone:B.status==="healthy"?"healthy":B.status==="invalid"?"disabled":"standby",children:B.status==="healthy"?"可用":B.status==="invalid"?"无效":"未验证"}),n.jsx("button",{type:"button",className:"secondary-button compact-button",disabled:V!=="",onClick:()=>k(h.id,!1,B.id),children:V===`check-account:${B.id}`?"检测中":"检测"}),n.jsx("button",{type:"button",className:"danger-button compact-button",disabled:V!=="",onClick:()=>m(h,B),children:V===`delete-account:${B.id}`?"删除中":"删除"})]})]},B.id)),rt.length===0&&n.jsx(kt,{text:"没有匹配的账号"}),bt.length>de&&n.jsxs("div",{className:"account-pool-more",children:[n.jsx("span",{className:"muted-inline",children:U?`已显示全部 ${bt.length} 个账号`:`已显示 ${tl.length} 个,还有 ${ll} 个`}),n.jsxs("div",{className:"account-pool-more-actions",children:[!U&&n.jsxs("button",{type:"button",className:"secondary-button compact-button",onClick:()=>te(B=>({...B,[h.id]:Math.min(bt.length,Ut+J)})),children:["再显示 ",Math.min(J,ll)," 个"]}),!U&&n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:()=>te(B=>({...B,[h.id]:bt.length})),children:"全部显示"}),Ut>de&&n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:()=>te(B=>({...B,[h.id]:de})),children:"收起"})]})]})]})]},h.id)}),z.length===0&&n.jsx(kt,{text:G?"暂无 Antigravity 渠道,先新增一个 Antigravity 账号池":"暂无绘图渠道,先新增一个 OpenAI 账号池渠道"})]}),he&&n.jsx(Rp,{channelId:he,onStart:$,onComplete:C,onClose:()=>_("")}),ue&&n.jsx(zp,{busy:V!=="",onAuthSession:()=>{me(ue),K("")},onAntigravity:()=>{Me(ue),K("")},onImport:async h=>{await N(ue,h),K("")},onClose:()=>K("")}),ne&&n.jsx(_p,{onImport:async h=>{await N(ne,new File([JSON.stringify(Op(h))],"authsession.json",{type:"application/json"}))},onClose:()=>me("")}),Ce&&n.jsx(Up,{onImport:async h=>{await N(Ce,new File([JSON.stringify(Dp(h))],"antigravity.json",{type:"application/json"}))},onClose:()=>Me("")})]})}function zp({busy:u,onAuthSession:f,onAntigravity:p,onImport:r,onClose:A}){return n.jsx("div",{className:"modal-backdrop",onClick:A,children:n.jsxs("div",{className:"modal-card account-add-modal",onClick:T=>T.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:"添加账号"}),n.jsx("span",{children:"选择一种账号接入方式"})]}),n.jsx("button",{type:"button",className:"icon-button",onClick:A,children:"×"})]}),n.jsxs("div",{className:"account-add-options",children:[n.jsxs("button",{type:"button",className:"account-add-option recommended",onClick:f,disabled:u,children:[n.jsx("span",{className:"account-add-icon",children:"A"}),n.jsx("strong",{children:"导入网页会话"}),n.jsx("small",{children:"粘贴完整 authsession JSON,保留 sessionToken"})]}),n.jsxs("button",{type:"button",className:"account-add-option",onClick:p,disabled:u,children:[n.jsx("span",{className:"account-add-icon",children:"G"}),n.jsx("strong",{children:"导入 Antigravity"}),n.jsx("small",{children:"粘贴 Google OAuth JSON 或 refresh token"})]}),n.jsxs("label",{className:`account-add-option${u?" disabled":""}`,children:[n.jsx("span",{className:"account-add-icon",children:"J"}),n.jsx("strong",{children:u?"导入中":"导入 JSON / ZIP / TXT"}),n.jsx("small",{children:"批量导入已有账号文件"}),n.jsx("input",{type:"file",accept:"application/json,application/zip,text/plain,.json,.zip,.txt",disabled:u,onChange:T=>{const L=T.target.files?.[0];L&&r(L),T.target.value=""}})]})]}),n.jsx("div",{className:"modal-actions",children:n.jsx("button",{type:"button",className:"secondary-button",onClick:A,children:"取消"})})]})})}function Op(u){const f=u.trim(),p=f.match(/(?:^|[;\s])(__Secure-(?:next-auth|authjs)\.session-token)=([^;\s]+)/);if(p)return{sessionToken:p[2],source:"web-login"};try{const r=JSON.parse(f),A=r.tokens&&typeof r.tokens=="object"?r.tokens:{},T=G=>typeof r[G]=="string"?r[G]:typeof A[G]=="string"?A[G]:"",L=T("accessToken")||T("access_token"),$=T("refreshToken")||T("refresh_token"),C=T("sessionToken")||T("session_token"),g=r.user&&typeof r.user=="object"?r.user:{};if(L||$||C)return{accessToken:L||void 0,refreshToken:$||void 0,sessionToken:C||void 0,email:typeof g.email=="string"?g.email:void 0,name:typeof g.name=="string"?g.name:void 0,source:"web-login"}}catch{}return{sessionToken:f,source:"web-login"}}function _p({onImport:u,onClose:f}){const[p,r]=b.useState(""),[A,T]=b.useState(!1),[L,$]=b.useState(""),[C,g]=b.useState("");async function G(){if(!p.trim()){$("请粘贴 authsession");return}T(!0),$(""),g("");try{await u(p.trim()),r(""),g("已导入,继续粘贴下一条即可")}catch(z){$(z instanceof Error?z.message:"导入失败")}finally{T(!1)}}return n.jsx("div",{className:"modal-backdrop",onClick:f,children:n.jsxs("div",{className:"modal-card",onClick:z=>z.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsx("strong",{children:"添加网页会话"}),n.jsx("button",{type:"button",className:"icon-button",onClick:f,children:"×"})]}),n.jsxs("p",{className:"muted-inline",children:["可直接粘贴 chatgpt.com/api/auth/session 的完整 JSON;也支持浏览器 ",n.jsx("code",{children:"__Secure-next-auth.session-token"})," 的值或完整 Cookie 字符串。"]}),n.jsxs("label",{className:"authsession-field",children:[n.jsx("span",{children:"authsession"}),n.jsx("textarea",{autoFocus:!0,value:p,onChange:z=>r(z.target.value),placeholder:"eyJhbGci..."})]}),L&&n.jsx("div",{className:"form-error",children:L}),C&&n.jsx("div",{className:"form-success",children:C}),n.jsxs("div",{className:"modal-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",onClick:f,children:"取消"}),n.jsx("button",{type:"button",className:"primary-button",disabled:A,onClick:G,children:A?"导入中":"导入账号"})]})]})})}function Dp(u){const f=u.trim();try{const p=JSON.parse(f),r=p.tokens&&typeof p.tokens=="object"?p.tokens:{},A=(...g)=>{for(const G of g){if(typeof p[G]=="string"&&p[G])return p[G];if(typeof r[G]=="string"&&r[G])return r[G]}return""},T=A("access_token","accessToken"),L=A("refresh_token","refreshToken"),$=A("email"),C=A("expired","expires_at","expiresAt","expiry");if(T||L)return{accessToken:T||void 0,refreshToken:L||void 0,email:$||void 0,expired:C||void 0,source:"antigravity"}}catch{}return{refreshToken:f,source:"antigravity"}}function Up({onImport:u,onClose:f}){const[p,r]=b.useState(""),[A,T]=b.useState(!1),[L,$]=b.useState(""),[C,g]=b.useState("");async function G(){if(!p.trim()){$("请粘贴 Antigravity OAuth JSON 或 refresh token");return}T(!0),$(""),g("");try{await u(p.trim()),r(""),g("已导入,继续粘贴下一条即可")}catch(z){$(z instanceof Error?z.message:"导入失败")}finally{T(!1)}}return n.jsx("div",{className:"modal-backdrop",onClick:f,children:n.jsxs("div",{className:"modal-card",onClick:z=>z.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsx("strong",{children:"导入 Antigravity 账号"}),n.jsx("button",{type:"button",className:"icon-button",onClick:f,children:"×"})]}),n.jsxs("p",{className:"muted-inline",children:["粘贴 Antigravity 的 Google OAuth 凭证 JSON(含 ",n.jsx("code",{children:"access_token"})," / ",n.jsx("code",{children:"refresh_token"}),"),或直接粘贴 refresh token。导入后会自动刷新并加入账号池。"]}),n.jsxs("label",{className:"authsession-field",children:[n.jsx("span",{children:"OAuth JSON / refresh token"}),n.jsx("textarea",{autoFocus:!0,value:p,onChange:z=>r(z.target.value),placeholder:'{"access_token":"ya29...","refresh_token":"1//..."}'})]}),L&&n.jsx("div",{className:"form-error",children:L}),C&&n.jsx("div",{className:"form-success",children:C}),n.jsxs("div",{className:"modal-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",onClick:f,children:"取消"}),n.jsx("button",{type:"button",className:"primary-button",disabled:A,onClick:G,children:A?"导入中":"导入账号"})]})]})})}function Rp({channelId:u,onStart:f,onComplete:p,onClose:r}){const[A,T]=b.useState(""),[L,$]=b.useState(""),[C,g]=b.useState(""),[G,z]=b.useState(!1),[V,W]=b.useState("");async function fe(){z(!0),W("");try{const ae=await f(u);T(ae.authorizeUrl),$(ae.state),window.open(ae.authorizeUrl,"_blank","noopener")}catch(ae){W(ae instanceof Error?ae.message:"发起授权失败")}finally{z(!1)}}async function te(){if(!C.trim()){W("请粘贴授权完成后浏览器跳转的回调地址");return}z(!0),W("");try{await p(u,{callbackUrl:C.trim(),state:L}),r()}catch(ae){W(ae instanceof Error?ae.message:"完成授权失败")}finally{z(!1)}}return n.jsx("div",{className:"modal-backdrop",onClick:r,children:n.jsxs("div",{className:"modal-card",onClick:ae=>ae.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsx("strong",{children:"OAuth 授权添加网页账号"}),n.jsx("button",{type:"button",className:"icon-button",onClick:r,children:"×"})]}),n.jsx("p",{className:"muted-inline",children:"使用 ChatGPT 网页兼容的 OAuth 客户端获取 refresh_token,只调用网页 backend-api,不会走 Codex 接口。"}),n.jsxs("ol",{className:"oauth-steps",children:[n.jsxs("li",{children:[n.jsx("button",{type:"button",className:"primary-button",onClick:fe,disabled:G,children:A?"重新生成授权链接":"① 生成授权链接并打开"}),A&&n.jsxs("div",{className:"oauth-link",children:[n.jsx("input",{readOnly:!0,value:A,onFocus:ae=>ae.target.select()}),n.jsx("span",{className:"muted-inline",children:"若未自动打开,复制到浏览器手动访问,用要添加的 ChatGPT 账号登录授权。"})]})]}),n.jsxs("li",{children:[n.jsx("label",{children:"② 粘贴授权后浏览器跳转的完整回调地址"}),n.jsx("input",{value:C,placeholder:"https://platform.openai.com/auth/callback?code=...&state=...",onChange:ae=>g(ae.target.value),disabled:!A||G})]})]}),V&&n.jsx("p",{className:"form-error",children:V}),n.jsxs("div",{className:"modal-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",onClick:r,disabled:G,children:"取消"}),n.jsx("button",{type:"button",className:"primary-button",onClick:te,disabled:!A||G,children:G?"处理中":"完成授权"})]})]})})}function wp({limits:u}){const f=je(u).filter(p=>p.label||p.name).slice(0,3);return f.length?n.jsx("div",{className:"quota-bars",children:f.map(p=>{const r=Hp(p);return n.jsxs("div",{className:"quota-bar",children:[n.jsxs("div",{className:"quota-bar-label",children:[n.jsx("strong",{children:p.label||p.name}),n.jsx("span",{children:Bp(p,r)})]}),n.jsx("div",{className:"quota-bar-track",children:n.jsx("span",{style:{width:`${r}%`}})})]},`${p.label||p.name}-${p.resetAt||""}`)})}):null}function Hp(u){return typeof u.percentRemaining=="number"&&Number.isFinite(u.percentRemaining)?Math.max(0,Math.min(100,u.percentRemaining)):typeof u.remaining=="number"&&typeof u.limit=="number"&&u.limit>0?Math.max(0,Math.min(100,u.remaining/u.limit*100)):typeof u.used=="number"&&typeof u.limit=="number"&&u.limit>0?Math.max(0,Math.min(100,(u.limit-u.used)/u.limit*100)):0}function Bp(u,f){const p=u.resetAt?` · ${el(u.resetAt)}`:"";return typeof u.remaining=="number"?`${Math.round(f)}% 剩余${p}`:`${Math.round(f)}%${p}`}function qp(u){const f=je(u.models).join(" ").toLowerCase(),p=["对话"];u.streamMode!=="disabled"&&p.push("流式"),/(image|dall-e|gpt-image)/.test(f)&&p.push("图片"),(u.openaiAccountCount??u.openaiAccounts?.length??0)>0&&p.push("账号池");const r=u.upstreamKeyCount??0;return r>1&&p.push(`${r} Key 轮询`),p}function Gp(u){if(u.status==="invalid"||u.credentialMode==="browser-session")return!0;if(!u.expiresAt)return!1;const f=new Date(u.expiresAt).getTime();return Number.isFinite(f)&&f-Date.now()<=1440*60*1e3}function Yp({channels:u,groups:f,onUpdate:p,onCreate:r,onImport:A,onDelete:T,onSyncModels:L,onCheck:$}){const C=Ta("openai"),[g,G]=b.useState(!1),[z,V]=b.useState(C.provider),[W,fe]=b.useState(C.name),[te,ae]=b.useState(C.baseUrl),[ie,be]=b.useState(C.models.join(", ")),[Y,xe]=b.useState(""),[P,he]=b.useState(""),[_,ne]=b.useState(!1),[me,Ce]=b.useState(!1);function Me(K){const de=Ta(K);V(de.provider),fe(de.name),ae(de.baseUrl),be(de.models.join(", ")),he("")}async function ue(K){K.preventDefault(),ne(!0),he("");try{await r({name:W.trim()||Ta(z).name,provider:z,baseUrl:te.trim(),...Nm(Y),models:Pc(ie),streamMode:"auto"}),G(!1),xe(""),Me(z)}catch(de){he(de instanceof Error?de.message:"渠道创建失败")}finally{ne(!1)}}return n.jsxs(at,{title:"渠道",children:[n.jsxs("div",{className:"channel-page-intro",children:[n.jsxs("div",{children:[n.jsx("strong",{children:"管理上游服务"}),n.jsx("span",{children:"每个渠道对应一个 API 上游。先添加渠道,再检测连通性并同步可用模型。"})]}),n.jsxs("div",{className:"channel-page-summary",children:[n.jsxs("span",{children:[n.jsx("b",{children:u.length})," 个渠道"]}),n.jsxs("span",{children:[n.jsx("b",{children:u.filter(K=>K.status!=="disabled").length})," 个已启用"]})]})]}),n.jsxs("div",{className:"panel-toolbar channel-toolbar",children:[n.jsx("span",{className:"muted-inline",children:"列表显示当前状态;点击任一渠道可修改连接、模型和计费设置。"}),n.jsx("button",{className:"primary-button",onClick:()=>G(K=>!K),children:g?"取消新增":"+ 新增渠道"})]}),g&&n.jsxs("form",{className:"channel-card channel-create-form",onSubmit:ue,children:[n.jsxs("label",{className:"channel-select-field",children:[n.jsx("span",{children:"选择渠道类型"}),n.jsxs("details",{className:"channel-choice-menu",children:[n.jsxs("summary",{children:[n.jsx("span",{children:Ta(z).label}),n.jsx("small",{children:"选择后自动填入建议配置"})]}),n.jsx("div",{role:"listbox","aria-label":"选择渠道类型",children:Fc.map(K=>n.jsxs("button",{type:"button",className:z===K.provider?"selected":"",onClick:de=>{Me(K.provider),de.currentTarget.closest("details")?.removeAttribute("open")},children:[n.jsx("strong",{children:K.label}),n.jsx("span",{children:"使用推荐的名称和地址"})]},K.provider))})]})]}),n.jsxs("div",{className:"channel-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"渠道名称"}),n.jsx("input",{value:W,onChange:K=>fe(K.target.value),placeholder:"例如 OpenAI 主线路"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"供应商"}),n.jsx("input",{value:ul(z),readOnly:!0})]}),n.jsxs("label",{className:"channel-form-wide",children:[n.jsx("span",{children:"Base URL"}),n.jsx("input",{value:te,onChange:K=>ae(K.target.value),placeholder:"https://provider.example/v1"})]}),n.jsxs("label",{className:"channel-form-wide",children:[n.jsx("span",{children:"上游 Key"}),n.jsx("textarea",{className:"channel-key-input",value:Y,onChange:K=>xe(K.target.value),placeholder:z==="codex"?"账号池导入后使用":z==="cpa"?"填写 CPA 的 API key,多个每行一个":"每行一个 Key;填多个会自动轮询分发",autoComplete:"off",rows:3})]}),n.jsxs("div",{className:"channel-form-wide channel-model-field",children:[n.jsxs("div",{className:"field-label-row",children:[n.jsx("span",{children:"模型"}),n.jsx("button",{type:"button",className:"model-pull-button",onClick:()=>{if(z!=="codex"&&!te.trim()){he("请先填写 Base URL 再获取模型");return}he(""),Ce(!0)},children:"从上游获取模型"})]}),n.jsx("textarea",{value:ie,onChange:K=>be(K.target.value),placeholder:"多个模型用逗号分隔,或点上方『从上游获取模型』拉取后多选"})]})]}),n.jsxs("div",{className:"channel-card-actions",children:[n.jsx("span",{className:"model-create-message",role:"status",children:P}),n.jsx("button",{className:"secondary-button",type:"button",onClick:()=>Me(z),disabled:_,children:"填入模板"}),n.jsx("button",{className:"primary-button",type:"submit",disabled:_,children:_?"创建中":"创建渠道"})]})]}),g&&me&&n.jsx(Am,{subtitle:`${W.trim()||Ta(z).name} · 勾选需要接入的模型`,current:Pc(ie),loadModels:async()=>{const K=await ve("/api/channel-model-preview",{method:"POST",body:JSON.stringify({provider:z,baseUrl:te.trim(),upstreamApiKey:Y})});return je(K.models)},onConfirm:async K=>{be(K.join(", "))},onClose:()=>Ce(!1)}),n.jsxs("div",{className:"channels-stack",children:[u.map(K=>n.jsx(Lp,{channel:K,groups:f,onUpdate:p,onImport:A,onDelete:T,onSyncModels:L,onCheck:$},K.id)),u.length===0&&n.jsx(kt,{text:"暂无渠道,先在后端添加渠道接口或导入配置"})]})]})}function Lp({channel:u,groups:f,onUpdate:p,onImport:r,onDelete:A,onSyncModels:T,onCheck:L}){const[$,C]=b.useState(u.name),[g,G]=b.useState(u.provider),[z,V]=b.useState(u.streamMode||"auto"),[W,fe]=b.useState(u.baseUrl),[te,ae]=b.useState(je(u.allowedGroupIds)),[ie,be]=b.useState(je(u.models).join(", ")),[Y,xe]=b.useState("saved"),[P,he]=b.useState(String(u.inputPricePer1K||0)),[_,ne]=b.useState(String(u.outputPricePer1K||0)),[me,Ce]=b.useState(!!u.webEndpoint),[Me,ue]=b.useState(""),[K,de]=b.useState(""),[J,N]=b.useState(!1),k=u.openaiAccountCount??u.openaiAccounts?.length??0,H=je(u.models).length,X=qp(u),se=u.status==="disabled",m={saved:"已保存",template:"模板",manual:"手动",synced:"上游同步"}[Y],h=Ni.find(F=>F.value===z)||Ni[0],M={auto:"自动处理(推荐)",real:"强制流式",fake:"兼容流式",disabled:"关闭流式"};b.useEffect(()=>{C(u.name),G(u.provider),V(u.streamMode||"auto"),fe(u.baseUrl),ae(je(u.allowedGroupIds)),be(je(u.models).join(", ")),xe("saved"),he(String(u.inputPricePer1K||0)),ne(String(u.outputPricePer1K||0)),Ce(!!u.webEndpoint),ue("")},[u.id,u.name,u.provider,u.streamMode,u.baseUrl,u.models,u.inputPricePer1K,u.outputPricePer1K,u.webEndpoint]);async function Q(){const F=ee();de("save");try{await p(u.id,F),ue("")}finally{de("")}}function ee(){const F=Ei(g),$e=!/^https?:\/\//i.test(W.trim())&&F?F:W,rt={name:$.trim()||u.name,provider:g,streamMode:z,baseUrl:$e,inputPricePer1K:Number(P)||0,outputPricePer1K:Number(_)||0,webEndpoint:me,models:ie.split(",").map(We=>We.trim()).filter(Boolean),allowedGroupIds:te};return Object.assign(rt,Nm(Me)),rt}async function Ne(){const F=u.status==="disabled"?"healthy":"disabled";de("status");try{await p(u.id,{...ee(),status:F}),ue("")}finally{de("")}}async function O(){de("sync");try{await p(u.id,ee()),ue(""),N(!0)}finally{de("")}}function ye(){const F=Ta(g);be(F.models.join(", ")),xe("template"),F.baseUrl&&!/^https?:\/\//i.test(W.trim())&&fe(F.baseUrl)}async function ce(){de("check");try{await Q(),await L(u.id)}finally{de("")}}async function St(F){de("import");try{await r(u.id,F)}finally{de("")}}return n.jsxs(n.Fragment,{children:[n.jsxs("details",{className:"channel-card channel-card-collapsible",children:[n.jsxs("summary",{className:"channel-card-head channel-list-row",children:[n.jsxs("div",{className:"channel-identity",children:[n.jsx("strong",{children:u.name}),n.jsx("span",{children:ul(g)}),n.jsx("small",{children:u.baseUrl||"尚未配置上游地址"}),n.jsx("div",{className:"channel-capability-tags",children:X.map(F=>n.jsx("span",{children:F},F))})]}),n.jsxs("div",{className:"channel-list-meta",children:[n.jsxs("span",{children:[n.jsx("b",{children:H})," 个模型"]}),k>0&&n.jsxs("span",{children:[n.jsx("b",{children:k})," 个账号"]})]}),n.jsxs("div",{className:"channel-check-result",children:[n.jsx("span",{children:"连通性"}),n.jsx("b",{className:u.lastError?"is-error":u.lastCheckedAt?"is-ok":"",children:u.lastError?"检测失败":u.lastCheckedAt?`已检测 ${el(u.lastCheckedAt)}`:"尚未检测"})]}),n.jsxs("div",{className:"channel-list-status",children:[n.jsx(Dt,{tone:u.status,children:se?"已停用":_t(u.status)}),n.jsx("span",{className:"channel-expand-hint",children:"配置"})]})]}),n.jsxs("div",{className:"channel-editor-controls",children:[n.jsxs("label",{className:"channel-select-field",children:[n.jsx("span",{children:"供应商"}),n.jsxs("details",{className:"channel-choice-menu",children:[n.jsxs("summary",{children:[n.jsx("span",{children:ul(g)}),n.jsx("small",{children:"修改上游协议类型"})]}),n.jsx("div",{role:"listbox","aria-label":"供应商",children:to.map(F=>n.jsxs("button",{type:"button",className:g===F.value?"selected":"",onClick:$e=>{G(F.value);const rt=Ei(F.value);rt&&!/^https?:\/\//i.test(W.trim())&&fe(rt),$e.currentTarget.closest("details")?.removeAttribute("open")},children:[n.jsx("strong",{children:F.label}),n.jsx("span",{children:F.value==="compatible"?"适用于兼容 OpenAI 格式的服务":"选择对应的上游协议"})]},F.value))})]})]}),n.jsxs("label",{className:"channel-select-field",children:[n.jsx("span",{children:"响应方式"}),n.jsxs("details",{className:"channel-choice-menu",children:[n.jsxs("summary",{children:[n.jsx("span",{children:M[h.value]}),n.jsx("small",{children:h.description})]}),n.jsx("div",{role:"listbox","aria-label":"响应方式",children:Ni.map(F=>n.jsxs("button",{type:"button",className:z===F.value?"selected":"",onClick:$e=>{V(F.value),$e.currentTarget.closest("details")?.removeAttribute("open")},children:[n.jsx("strong",{children:M[F.value]}),n.jsx("span",{children:F.description})]},F.value))})]})]})]}),(g==="codex"||k>0)&&n.jsxs("div",{className:"setting",children:[n.jsxs("div",{children:[n.jsx("span",{children:"网页对话接口"}),n.jsx("small",{children:"开启后走 ChatGPT 网页对话接口,把 Plus 订阅账号包装成 API"})]}),n.jsx("div",{className:"setting-value",children:n.jsx("button",{type:"button",className:me?"ios-switch is-on":"ios-switch","aria-label":me?"关闭网页对话接口":"开启网页对话接口","aria-pressed":me,onClick:()=>Ce(F=>!F),children:n.jsx("span",{})})})]}),n.jsxs("div",{className:"channel-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"渠道名称"}),n.jsx("input",{value:$,onChange:F=>C(F.target.value),placeholder:"例如 Gemini 主线路"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"供应商"}),n.jsx("input",{value:ul(g),readOnly:!0})]}),n.jsxs("label",{className:"channel-form-wide",children:[n.jsx("span",{children:"Base URL"}),n.jsx("input",{value:W,onChange:F=>fe(F.target.value),placeholder:"https://provider.example/v1"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"优先级"}),n.jsx("input",{value:u.priority,readOnly:!0})]}),n.jsxs("div",{className:"channel-form-wide channel-model-field",children:[n.jsxs("div",{className:"field-label-row",children:[n.jsx("span",{children:"模型"}),n.jsxs("small",{children:["来源:",m]})]}),n.jsx("textarea",{value:ie,onChange:F=>{be(F.target.value),xe("manual")},placeholder:"优先拉取上游模型,也可以手动补充,多个用逗号分隔"}),n.jsxs("div",{className:"channel-model-actions",children:[n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:ye,disabled:K!=="",children:"填入模板"}),n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:O,disabled:K!=="",children:K==="sync"?"拉取中":"获取上游模型"})]})]}),n.jsxs("label",{className:"channel-form-wide",children:[n.jsxs("span",{children:["上游 Key",(u.upstreamKeyCount??0)>0?` (已配置 ${u.upstreamKeyCount} 个)`:u.upstreamKeySet?" (已配置)":""]}),n.jsx("textarea",{className:"channel-key-input",value:Me,onChange:F=>ue(F.target.value),placeholder:g==="codex"?"Codex 账号池不需要上游 Key":g==="cpa"?"填写 CPA 的 API key,多个每行一个":"每行一个 Key;填多个会自动轮询分发;留空不修改",autoComplete:"off",rows:3})]}),n.jsxs("label",{children:[n.jsx("span",{children:"输入单价 / 1K Token"}),n.jsx("input",{type:"number",min:"0",step:"0.0001",value:P,onChange:F=>he(F.target.value)})]}),n.jsxs("label",{children:[n.jsx("span",{children:"输出单价 / 1K Token"}),n.jsx("input",{type:"number",min:"0",step:"0.0001",value:_,onChange:F=>ne(F.target.value)})]}),n.jsx("span",{className:"channel-billing-note",children:"定价可先留空;接入是否可用优先看渠道检测和模型同步结果。"})]}),n.jsxs("div",{className:"channel-group-field",children:[n.jsxs("div",{className:"field-label-row",children:[n.jsx("span",{children:"可见分组"}),n.jsx("small",{children:te.length?`已选择 ${te.length} 个分组`:"全部用户可用"})]}),f.length===0?n.jsx("p",{className:"channel-group-empty",children:"还没有用户分组。去「分组」页创建后,可在这里把渠道限制为只对特定分组开放。"}):n.jsx("div",{className:"channel-group-options",children:f.map(F=>{const $e=te.includes(F.id);return n.jsxs("button",{type:"button",className:$e?"selected":"","aria-pressed":$e,onClick:()=>ae(rt=>$e?rt.filter(We=>We!==F.id):[...rt,F.id]),children:[n.jsx("span",{children:F.name}),F.description&&n.jsx("small",{children:F.description})]},F.id)})})]}),n.jsxs("div",{className:"channel-card-actions",children:[n.jsx("button",{className:"secondary-button",onClick:ce,disabled:K!=="",children:K==="check"?"检测中":"检测渠道"}),n.jsx("button",{className:"primary-button",onClick:Q,disabled:K!=="",children:K==="save"?"保存中":"保存"}),n.jsxs("details",{className:"channel-more-actions",children:[n.jsx("summary",{children:"更多操作"}),n.jsxs("div",{children:[n.jsxs("label",{className:"secondary-button",children:[K==="import"?"导入中":"导入账号 JSON",n.jsx("input",{type:"file",accept:"application/json,application/zip,text/plain,.json,.zip,.txt",disabled:K!=="",onChange:F=>{const $e=F.target.files?.[0];$e&&St($e),F.target.value=""}})]}),n.jsx("button",{className:"secondary-button",onClick:Ne,disabled:K!=="",children:u.status==="disabled"?"启用渠道":"停用渠道"}),n.jsx("button",{className:"danger-button",onClick:()=>A(u.id),disabled:K!=="",children:"删除渠道"})]})]})]})]}),J&&n.jsx(Am,{subtitle:`${u.name} · 勾选需要接入的模型`,current:ie.split(",").map(F=>F.trim()).filter(Boolean),loadModels:async()=>{const F=await ve(`/api/channels/${u.id}/upstream-models`,{method:"POST",body:JSON.stringify({})});return je(F.models)},onConfirm:async F=>{await T(u.id,F)},onClose:()=>N(!1)})]})}function Am({subtitle:u,current:f,loadModels:p,onConfirm:r,onClose:A}){const[T,L]=b.useState(!0),[$,C]=b.useState(""),[g,G]=b.useState([]),[z,V]=b.useState(new Set),[W,fe]=b.useState(""),[te,ae]=b.useState(!1);b.useEffect(()=>{let _=!1;return(async()=>{L(!0),C("");try{const ne=await p();if(_)return;const me=new Set,Ce=je(ne).map(ue=>ue.trim()).filter(ue=>{if(!ue)return!1;const K=ue.toLowerCase();return me.has(K)?!1:(me.add(K),!0)}),Me=new Set(f.map(ue=>ue.toLowerCase()));G(Ce),V(new Set(Ce.filter(ue=>Me.has(ue.toLowerCase()))))}catch(ne){_||C(ne instanceof Error?ne.message:"获取上游模型失败")}finally{_||L(!1)}})(),()=>{_=!0}},[]);const ie=W.trim().toLowerCase(),be=ie?g.filter(_=>_.toLowerCase().includes(ie)):g,Y=be.length>0&&be.every(_=>z.has(_));function xe(_){V(ne=>{const me=new Set(ne);return me.has(_)?me.delete(_):me.add(_),me})}function P(){V(_=>{const ne=new Set(_);return Y?be.forEach(me=>ne.delete(me)):be.forEach(me=>ne.add(me)),ne})}async function he(){const _=new Set(g.map(ue=>ue.toLowerCase())),ne=f.filter(ue=>!_.has(ue.toLowerCase())),me=g.filter(ue=>z.has(ue)),Ce=new Set,Me=[...ne,...me].filter(ue=>{const K=ue.toLowerCase();return Ce.has(K)?!1:(Ce.add(K),!0)});ae(!0);try{await r(Me),A()}catch{ae(!1)}}return n.jsx("div",{className:"modal-backdrop",onClick:A,children:n.jsxs("div",{className:"modal-card model-picker-modal",onClick:_=>_.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:"选择上游模型"}),n.jsx("span",{children:u})]}),n.jsx("button",{type:"button",className:"icon-button",onClick:A,children:"×"})]}),T?n.jsx("div",{className:"model-picker-status",children:"正在获取上游模型…"}):$?n.jsx("div",{className:"model-picker-status model-picker-error",children:$}):n.jsxs(n.Fragment,{children:[n.jsxs("div",{className:"model-picker-toolbar",children:[n.jsx("input",{className:"model-picker-search",value:W,onChange:_=>fe(_.target.value),placeholder:"搜索模型名称",autoFocus:!0}),n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:P,disabled:be.length===0,children:Y?"取消全选":"全选"})]}),n.jsxs("div",{className:"model-picker-count",children:["共 ",g.length," 个 · 已选 ",z.size," 个",ie?` · 匹配 ${be.length} 个`:""]}),n.jsxs("div",{className:"model-picker-list",children:[be.map(_=>{const ne=z.has(_),me=f.some(Ce=>Ce.toLowerCase()===_.toLowerCase());return n.jsxs("label",{className:`model-picker-row${ne?" checked":""}`,children:[n.jsx("input",{type:"checkbox",checked:ne,onChange:()=>xe(_)}),n.jsx("span",{className:"model-picker-name",children:_}),me&&n.jsx("span",{className:"model-picker-tag",children:"已接入"})]},_)}),be.length===0&&n.jsx("div",{className:"model-picker-status",children:"没有匹配的模型"})]})]}),n.jsxs("div",{className:"modal-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",onClick:A,children:"取消"}),n.jsx("button",{type:"button",className:"primary-button",disabled:T||!!$||te,onClick:he,children:te?"保存中":`导入所选 (${z.size})`})]})]})})}function kp({logs:u,onCopy:f}){const[p,r]=b.useState(u),[A,T]=b.useState(u.length),[L,$]=b.useState(1),[C,g]=b.useState(""),[G,z]=b.useState("all"),[V,W]=b.useState(null),[fe,te]=b.useState(!1),[ae,ie]=b.useState(!1),be=25,Y=Math.max(1,Math.ceil(A/be));b.useEffect(()=>{$(1)},[C,G]),b.useEffect(()=>{L>Y&&$(Y)},[L,Y]),b.useEffect(()=>{const P=new AbortController,he=window.setTimeout(async()=>{te(!0);try{const _=new URLSearchParams({page:String(L),pageSize:String(be),status:G,q:C.trim()}),ne=await ve(`/api/logs?${_}`,{signal:P.signal}),me=je(ne.logs);r(me),T(ne.total||0),W(Ce=>Ce&&me.some(Me=>Me.id===Ce.id)?Ce:null)}catch(_){_ instanceof DOMException&&_.name==="AbortError"||(r([]),T(0))}finally{P.signal.aborted||te(!1)}},C?250:0);return()=>{window.clearTimeout(he),P.abort()}},[L,C,G]);async function xe(P){if(V?.id===P.id){W(null);return}W(P),ie(!0);try{const he=await ve(`/api/logs/${encodeURIComponent(P.id)}`);W(he.log)}catch{W(P)}finally{ie(!1)}}return n.jsxs(at,{title:"调用日志",children:[n.jsxs("div",{className:"logs-toolbar",children:[n.jsxs("div",{className:"search-box",children:[n.jsx(Ot,{name:"search"}),n.jsx("input",{value:C,onChange:P=>g(P.target.value),placeholder:"搜索请求 ID、用户、Key、模型、渠道或错误码"})]}),n.jsx("div",{className:"log-status-filter",role:"group","aria-label":"日志状态筛选",children:[{value:"all",label:"全部"},{value:"success",label:"成功"},{value:"failed",label:"失败"}].map(P=>n.jsx("button",{type:"button",className:G===P.value?"selected":"",onClick:()=>z(P.value),children:P.label},P.value))}),n.jsx("span",{className:"muted-inline",children:fe?"加载中":`共 ${A} 条`})]}),n.jsxs("div",{className:V?"logs-layout has-detail":"logs-layout",children:[n.jsxs("div",{className:"table",children:[n.jsxs("div",{className:"table-head logs-table",children:[n.jsx("span",{children:"请求"}),n.jsx("span",{children:"模型"}),n.jsx("span",{children:"渠道"}),n.jsx("span",{children:"状态"})]}),p.map(P=>n.jsx("div",{className:"log-entry",children:n.jsxs("div",{className:V?.id===P.id?"table-row logs-table selected":"table-row logs-table",role:"button",tabIndex:0,onClick:()=>xe(P),onKeyDown:he=>{(he.key==="Enter"||he.key===" ")&&xe(P)},children:[n.jsxs("span",{children:[n.jsx("strong",{children:lo(P)}),n.jsxs("small",{children:[P.id," · ",el(P.createdAt)," · ",P.latencyMs,"ms"]})]}),n.jsx("span",{children:up(P)}),n.jsx("span",{children:cp(P)}),n.jsx(Dt,{tone:P.status,children:_t(P.status)})]})},P.id)),!fe&&p.length===0&&n.jsx(kt,{text:C||G!=="all"?"没有匹配的日志":"暂无调用日志"})]}),V&&n.jsx(Qp,{log:V,loading:ae,onCopy:f})]}),Y>1&&n.jsxs("div",{className:"pagination-bar",children:[n.jsx("button",{className:"secondary-button",disabled:L<=1||fe,onClick:()=>$(P=>Math.max(1,P-1)),children:"上一页"}),n.jsxs("span",{children:[L," / ",Y]}),n.jsx("button",{className:"secondary-button",disabled:L>=Y||fe,onClick:()=>$(P=>Math.min(Y,P+1)),children:"下一页"})]})]})}function Qp({log:u,loading:f,onCopy:p}){if(!u)return n.jsx("aside",{className:"log-inspector empty-inspector",children:n.jsx("span",{children:"选择一条日志查看详情"})});const r=Number(u.inputTokens||0),A=Number(u.outputTokens||0),T=typeof u.attempts=="number"?Math.max(0,u.attempts):null,L=[["请求 ID",u.id],["状态",_t(u.status)],["时间",ip(u.createdAt)],["用户 ID",u.userId||"未识别"],["API Key",u.apiKeyPrefix?`${u.apiKeyPrefix}***`:"未识别"],["模型",u.model||"未提供"],["渠道",u.channel||"未选择"],["实际账号",u.account||"未记录"],["响应耗时",`${u.latencyMs} ms`],["尝试次数",T===null?"未记录":String(T)],["是否重试",T===null?"未记录":T>1?"是":"否"],["输入 Tokens",ml(r)],["输出 Tokens",ml(A)],["总 Tokens",ml(r+A)],["扣费",u.cost.toFixed(4)],["错误码",u.errorCode||"无"]];return n.jsxs("aside",{className:"log-inspector",children:[n.jsxs("header",{children:[n.jsxs("div",{children:[n.jsx("span",{children:f?"加载中":"日志详情"}),n.jsx("strong",{children:lo(u)})]}),n.jsx(Dt,{tone:u.status,children:_t(u.status)})]}),n.jsx("div",{className:"log-detail",children:L.map(([$,C])=>n.jsxs("div",{children:[n.jsx("span",{children:$}),n.jsx("strong",{title:C,children:C})]},$))}),n.jsxs("div",{className:"log-actions",children:[n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:()=>p(u.id,"请求 ID 已复制"),children:"复制请求 ID"}),u.errorCode&&n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:()=>p(u.errorCode||"","错误码已复制"),children:"复制错误码"})]})]})}function Xp({models:u,channels:f,groups:p}){const[r,A]=b.useState(null),[T,L]=b.useState(null),[$,C]=b.useState("username"),[g,G]=b.useState("0"),[z,V]=b.useState(""),[W,fe]=b.useState({enabled:!0,minReward:.1,maxReward:1}),[te,ae]=b.useState({logRetentionDays:30,maxLogs:1e4,maxQuotaEntries:2e4}),[ie,be]=b.useState(null),[Y,xe]=b.useState(null),[P,he]=b.useState(""),[_,ne]=b.useState(""),[me,Ce]=b.useState(""),[Me,ue]=b.useState(""),[K,de]=b.useState(""),[J,N]=b.useState(""),[k,H]=b.useState(""),[X,se]=b.useState(""),[m,h]=b.useState(""),[M,Q]=b.useState(!1),[ee,Ne]=b.useState("system"),O=u.find(U=>U.recommended&&U.status==="available")?.id||u.find(U=>U.status==="available")?.id||"未配置",ye=f.filter(U=>U.status!=="disabled").length,ce=[{value:"system",label:"系统",description:"运行概况"},{value:"cli",label:"CLI 接入",description:"一键配置"},{value:"auth",label:"注册",description:"开放方式"},{value:"check-in",label:"签到",description:"奖励范围"},{value:"admin",label:"管理员",description:"账号绑定"},{value:"discord",label:"Discord",description:"登录限制"},{value:"maintenance",label:"维护",description:"日志保留"},{value:"backup",label:"备份",description:"导出恢复"}],St=ce.find(U=>U.value===ee)||ce[0];b.useEffect(()=>{Promise.all([ve("/api/settings/discord"),ve("/api/settings/auth"),ve("/api/settings/check-in"),ve("/api/account/me"),ve("/api/settings/maintenance"),ve("/api/health")]).then(([U,B,Be,Fe,nt,et])=>{A(Wc(U.discord)),se(je(U.discord.blockedGuildIds).join(` -`)),L(B.auth.registrationEnabled),C(Mi(B.auth.registrationMode)),G(String(B.auth.defaultBalance||0)),V(B.auth.defaultGroupId||""),fe(Be.checkIn),xe(Fe.account),he(Fe.account?.username||""),ne(Fe.user.name||""),Ce(Fe.account?.email||""),ue(Fe.account?.discordUserId||""),ae(nt.maintenance),be(et)}).catch(()=>h("设置加载失败"))},[]);async function F(U=T,B=$,Be=Number(g),Fe=z){if(U!==null)try{const nt=await ve("/api/settings/auth",{method:"PATCH",body:JSON.stringify({registrationEnabled:U,registrationMode:B,defaultBalance:Be,defaultGroupId:Fe})});L(nt.auth.registrationEnabled),C(Mi(nt.auth.registrationMode)),G(String(nt.auth.defaultBalance||0)),V(nt.auth.defaultGroupId||""),h(nt.auth.registrationEnabled?"注册设置已保存":"已关闭用户注册")}catch(nt){h(nt instanceof Error?nt.message:"注册设置保存失败")}}async function $e(){T!==null&&F(!T,$)}async function rt(){Q(!0),h("");try{const U=await ve("/api/settings/check-in",{method:"PATCH",body:JSON.stringify(W)});fe(U.checkIn),h(U.checkIn.enabled?"签到奖励设置已保存":"已关闭每日签到")}catch(U){h(U instanceof Error?U.message:"签到设置保存失败")}finally{Q(!1)}}async function We(){if(r){Q(!0),h("");try{const U=Wc(r),B=X.split(/[\s,]+/).map(Fe=>Fe.trim()).filter(Boolean),Be=await ve("/api/settings/discord",{method:"PATCH",body:JSON.stringify({...U,blockedGuildIds:B,clientSecret:k})});A(Wc(Be.discord)),se(je(Be.discord.blockedGuildIds).join(` -`)),H(""),h("Discord 配置已保存")}catch(U){h(U instanceof Error?U.message:"保存失败,请检查填写内容")}finally{Q(!1)}}}async function bt(){try{const U=await ve("/api/account/profile",{method:"PATCH",body:JSON.stringify({username:P,displayName:_,email:me,discordUserId:Me,currentPassword:K,newPassword:J})});xe(U.account),he(U.account.username),Ce(U.account.email||""),ue(U.account.discordUserId||""),de(""),N(""),h("管理员账号已保存")}catch(U){h(U instanceof Error?U.message:"账号设置保存失败")}}async function Ut(){Q(!0),h("");try{const U=await ve("/api/settings/maintenance",{method:"PATCH",body:JSON.stringify(te)});ae(U.maintenance),h("维护设置已保存,历史数据已按新规则清理")}catch(U){h(U instanceof Error?U.message:"维护设置保存失败")}finally{Q(!1)}}async function tl(){Q(!0),h("");try{const U=await fetch("/api/backup",{credentials:"include"});if(!U.ok)throw new Error("备份导出失败");const B=await U.blob(),Fe=(U.headers.get("Content-Disposition")||"").match(/filename="([^"]+)"/)?.[1]||"capi-backup.json",nt=URL.createObjectURL(B),et=document.createElement("a");et.href=nt,et.download=Fe,et.click(),URL.revokeObjectURL(nt),h("备份已导出,请妥善保管")}catch(U){h(U instanceof Error?U.message:"备份导出失败")}finally{Q(!1)}}async function ll(U){if(window.confirm("恢复会覆盖当前全部数据,并退出现有登录会话。确定继续?")){Q(!0),h("");try{const B=await fetch("/api/restore",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:U}),Be=await B.json().catch(()=>null);if(!B.ok)throw new Error(Be?.error?.message||"备份恢复失败");h(`已恢复 ${Be.users} 个用户、${Be.channels} 条渠道和 ${Be.models} 个模型,请重新登录`)}catch(B){h(B instanceof Error?B.message:"备份恢复失败")}finally{Q(!1)}}}return n.jsxs("div",{className:"settings-layout",children:[n.jsx("div",{className:"settings-tabs",children:ce.map(U=>n.jsxs("button",{type:"button",className:ee===U.value?"selected":"",onClick:()=>Ne(U.value),children:[n.jsx("strong",{children:U.label}),n.jsx("small",{children:U.description})]},U.value))}),n.jsxs("div",{className:"settings-tab-note",children:[n.jsx("strong",{children:St.label}),n.jsx("span",{children:St.description})]}),ee==="system"&&n.jsx(at,{title:"系统设置",children:n.jsxs("div",{className:"settings-group",children:[n.jsx(Pt,{label:"接口兼容",value:"OpenAI API"}),n.jsx(Pt,{label:"当前默认模型",value:O}),n.jsx(Pt,{label:"已配置渠道",value:`${f.length} 个,${ye} 个启用`}),n.jsx(Pt,{label:"可选供应商",value:`${to.length} 种`}),n.jsx(Pt,{label:"运行版本",value:`${ie?.version||"未知"} · ${ie?.commit||"未知"}`}),n.jsx(Pt,{label:"构建时间",value:ie?.buildTime?el(ie.buildTime):"本地构建"}),n.jsx(Pt,{label:"账号自动检测",value:"每 15 分钟自动检测一次"})]})}),ee==="cli"&&n.jsxs(at,{title:"CLI 工具接入",children:[n.jsx("p",{className:"cli-intro",children:"CAPI 兼容 OpenAI 和 Anthropic 协议,常见 AI 命令行工具可直接接入。"}),n.jsxs("div",{className:"cli-credentials",children:[n.jsxs("div",{className:"cli-credential",children:[n.jsx("span",{children:"Base URL"}),n.jsx("code",{children:Ul()}),n.jsx("button",{type:"button",className:"copy-button","aria-label":"复制",onClick:()=>{Ai(Ul()),h("已复制 Base URL")},children:n.jsx(Ot,{name:"copy"})})]}),n.jsxs("div",{className:"cli-credential",children:[n.jsx("span",{children:"API Key"}),n.jsx("code",{children:"cat_你的_api_key"})]})]}),n.jsxs("div",{className:"cli-tools",children:[n.jsxs("details",{className:"cli-tool",open:!0,children:[n.jsxs("summary",{children:[n.jsx("strong",{children:"Claude Code"}),n.jsx("span",{children:"Anthropic Messages 协议"})]}),n.jsx("pre",{children:`export ANTHROPIC_BASE_URL="${Ul()}" -export ANTHROPIC_AUTH_TOKEN="cat_你的_api_key" -export ANTHROPIC_MODEL="${O}" -claude`})]}),n.jsxs("details",{className:"cli-tool",children:[n.jsxs("summary",{children:[n.jsx("strong",{children:"Codex CLI"}),n.jsx("span",{children:"OpenAI Chat 协议"})]}),n.jsxs("p",{children:["编辑 ",n.jsx("code",{children:"~/.codex/config.toml"}),":"]}),n.jsx("pre",{children:`model = "${O}" -model_provider = "capi" - -[model_providers.capi] -name = "CAPI" -base_url = "${Ul()}/v1" -env_key = "CAPI_KEY" -wire_api = "chat"`}),n.jsx("p",{children:"然后设置环境变量并运行:"}),n.jsx("pre",{children:`export CAPI_KEY="cat_你的_api_key" -codex`})]}),n.jsxs("details",{className:"cli-tool",children:[n.jsxs("summary",{children:[n.jsx("strong",{children:"Aider"}),n.jsx("span",{children:"OpenAI 兼容"})]}),n.jsx("pre",{children:`export OPENAI_API_BASE="${Ul()}" -export OPENAI_API_KEY="cat_你的_api_key" -aider --model openai/${O}`})]}),n.jsxs("details",{className:"cli-tool",children:[n.jsxs("summary",{children:[n.jsx("strong",{children:"Cline / Roo Code / Kilo Code"}),n.jsx("span",{children:"VS Code 插件"})]}),n.jsxs("p",{children:["在插件设置中选择 ",n.jsx("strong",{children:"OpenAI Compatible"}),":"]}),n.jsx("pre",{children:`Base URL: ${Ul()}/v1 -API Key: cat_你的_api_key -Model ID: ${O}`})]}),n.jsxs("details",{className:"cli-tool",children:[n.jsxs("summary",{children:[n.jsx("strong",{children:"通用 OpenAI SDK"}),n.jsx("span",{children:"Python / Node.js"})]}),n.jsx("pre",{children:`export OPENAI_BASE_URL="${Ul()}" -export OPENAI_API_KEY="cat_你的_api_key"`}),n.jsx("pre",{children:`from openai import OpenAI -client = OpenAI() -response = client.chat.completions.create( - model="${O}", - messages=[{"role": "user", "content": "hello"}] -)`})]})]}),m&&n.jsx("p",{className:"cli-message",role:"status",children:m})]}),ee==="maintenance"&&n.jsx(at,{title:"维护设置",children:n.jsxs("div",{className:"settings-group",children:[n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"日志保留天数"}),n.jsx("div",{className:"setting-value maintenance-control",children:n.jsx("input",{type:"number",min:"1",max:"3650",value:te.logRetentionDays,onChange:U=>ae(B=>({...B,logRetentionDays:Number(U.target.value)}))})})]}),n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"日志最大条数"}),n.jsx("div",{className:"setting-value maintenance-control",children:n.jsx("input",{type:"number",min:"100",max:"1000000",step:"100",value:te.maxLogs,onChange:U=>ae(B=>({...B,maxLogs:Number(U.target.value)}))})})]}),n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"额度流水最大条数"}),n.jsx("div",{className:"setting-value maintenance-control",children:n.jsx("input",{type:"number",min:"100",max:"2000000",step:"100",value:te.maxQuotaEntries,onChange:U=>ae(B=>({...B,maxQuotaEntries:Number(U.target.value)}))})})]}),n.jsxs("div",{className:"settings-save-row",children:[n.jsx("span",{role:"status",children:m}),n.jsx("button",{type:"button",className:"primary-button",disabled:M,onClick:Ut,children:M?"保存中":"保存维护设置"})]})]})}),ee==="backup"&&n.jsx(at,{title:"备份与恢复",children:n.jsx("div",{className:"settings-group",children:n.jsxs("div",{className:"setting",children:[n.jsxs("span",{children:["备份与恢复",n.jsx("small",{children:"包含账号哈希和加密后的上游密钥,恢复时需要相同的 SECRET_KEY"})]}),n.jsxs("div",{className:"setting-value backup-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",disabled:M,onClick:tl,children:"导出备份"}),n.jsxs("label",{className:"secondary-button",children:["恢复备份",n.jsx("input",{type:"file",accept:"application/json,.json",disabled:M,onChange:U=>{const B=U.target.files?.[0];B&&ll(B),U.target.value=""}})]})]})]})})}),ee==="auth"&&n.jsx(at,{title:"账号与注册",children:n.jsxs("div",{className:"settings-group",children:[n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"开放用户注册"}),n.jsxs("div",{className:"setting-value",children:[n.jsx("strong",{children:T?"启用":"关闭"}),n.jsx("button",{type:"button",className:T?"ios-switch is-on":"ios-switch","aria-label":T?"关闭用户注册":"开放用户注册","aria-pressed":!!T,onClick:$e,children:n.jsx("span",{})})]})]}),n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"注册方式"}),n.jsx("div",{className:"registration-mode-control",role:"group","aria-label":"注册方式",children:[{value:"username",label:"账号密码"},{value:"email",label:"邮箱"},{value:"discord",label:"Discord"}].map(U=>n.jsx("button",{type:"button",className:$===U.value?"selected":"",onClick:()=>F(T??!0,U.value),children:U.label},U.value))})]}),n.jsxs("div",{className:"setting",children:[n.jsxs("span",{children:["新用户初始额度",n.jsx("small",{children:"注册完成后自动发放,仅影响之后的新用户"})]}),n.jsxs("div",{className:"setting-value auth-default-balance",children:[n.jsx("input",{type:"number",min:"0",step:"0.01",value:g,onChange:U=>G(U.target.value),"aria-label":"新用户初始额度"}),n.jsx("button",{type:"button",className:"secondary-button",onClick:()=>F(T,$,Number(g)),children:"保存"})]})]}),n.jsxs("div",{className:"setting",children:[n.jsxs("span",{children:["默认注册分组",n.jsx("small",{children:"新注册用户自动归入该分组,决定他们能用哪些渠道"})]}),n.jsxs("div",{className:"setting-value auth-default-balance",children:[n.jsxs("select",{value:z,onChange:U=>V(U.target.value),"aria-label":"默认注册分组",children:[p.map(U=>n.jsx("option",{value:U.id,children:U.name},U.id)),p.length===0&&n.jsx("option",{value:"",children:"暂无分组"})]}),n.jsx("button",{type:"button",className:"secondary-button",disabled:p.length===0,onClick:()=>F(T,$,Number(g),z),children:"保存"})]})]})]})}),ee==="check-in"&&n.jsx(at,{title:"每日签到奖励",children:n.jsxs("div",{className:"settings-group",children:[n.jsxs("div",{className:"setting",children:[n.jsxs("span",{children:["开放每日签到",n.jsx("small",{children:"用户每天可领取一次随机额度,按北京时间刷新"})]}),n.jsxs("div",{className:"setting-value",children:[n.jsx("strong",{children:W.enabled?"启用":"关闭"}),n.jsx("button",{type:"button",className:W.enabled?"ios-switch is-on":"ios-switch","aria-label":W.enabled?"关闭每日签到":"开放每日签到","aria-pressed":W.enabled,onClick:()=>fe(U=>({...U,enabled:!U.enabled})),children:n.jsx("span",{})})]})]}),n.jsxs("div",{className:"setting check-in-settings-row",children:[n.jsxs("span",{children:["随机奖励范围",n.jsx("small",{children:"领取金额精确到 0.01,直接计入用户余额和额度流水"})]}),n.jsxs("div",{className:"check-in-reward-inputs",children:[n.jsxs("label",{children:[n.jsx("span",{children:"最低"}),n.jsx("input",{type:"number",min:"0.01",max:"1000000",step:"0.01",value:W.minReward,onChange:U=>fe(B=>({...B,minReward:Number(U.target.value)}))})]}),n.jsxs("label",{children:[n.jsx("span",{children:"最高"}),n.jsx("input",{type:"number",min:"0.01",max:"1000000",step:"0.01",value:W.maxReward,onChange:U=>fe(B=>({...B,maxReward:Number(U.target.value)}))})]})]})]}),n.jsxs("div",{className:"settings-save-row",children:[n.jsx("span",{role:"status",children:m}),n.jsx("button",{type:"button",className:"primary-button",disabled:M,onClick:rt,children:M?"保存中":"保存签到设置"})]})]})}),ee==="admin"&&n.jsx(at,{title:"管理员账号",children:n.jsxs("form",{className:"discord-settings",onSubmit:U=>{U.preventDefault(),bt()},children:[n.jsxs("div",{className:"settings-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"登录账号"}),n.jsx("input",{value:P,onChange:U=>he(U.target.value),autoComplete:"username"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"显示名称"}),n.jsx("input",{value:_,onChange:U=>ne(U.target.value),autoComplete:"name"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"邮箱"}),n.jsx("input",{type:"email",value:me,onChange:U=>Ce(U.target.value),autoComplete:"email"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"Discord 用户 ID(可选)"}),n.jsx("input",{inputMode:"numeric",autoComplete:"off",value:Me,onChange:U=>ue(U.target.value),placeholder:Y?.discordUserId?"已绑定":"输入管理员的 Discord 用户 ID"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"当前密码"}),n.jsx("input",{type:"password",value:K,onChange:U=>de(U.target.value),autoComplete:"current-password",placeholder:"修改密码时填写"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"新密码"}),n.jsx("input",{type:"password",value:J,onChange:U=>N(U.target.value),autoComplete:"new-password",placeholder:"留空表示不修改"})]})]}),n.jsxs("div",{className:"settings-save-row",children:[n.jsx("span",{role:"status",children:m}),n.jsx("button",{className:"primary-button",type:"submit",children:"保存账号"})]})]})}),ee==="discord"&&n.jsx(at,{title:"Discord 登录",children:r?n.jsxs("form",{className:"discord-settings",autoComplete:"off",onSubmit:U=>{U.preventDefault(),We()},children:[n.jsxs("div",{className:"discord-toggle-row",children:[n.jsxs("div",{children:[n.jsx("strong",{children:"Discord 登录"}),n.jsx("span",{children:r.enabled?"已启用":"未启用"})]}),n.jsx("button",{type:"button",className:r.enabled?"ios-switch is-on":"ios-switch","aria-label":r.enabled?"停用 Discord 登录":"启用 Discord 登录","aria-pressed":r.enabled,onClick:()=>A({...r,enabled:!r.enabled}),children:n.jsx("span",{})})]}),n.jsxs("div",{className:"settings-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"Client ID"}),n.jsx("input",{inputMode:"numeric",autoComplete:"off",value:r.clientId,onChange:U=>A({...r,clientId:U.target.value}),placeholder:"100000000000000001"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"Client Secret"}),n.jsx("input",{type:"password",autoComplete:"new-password",value:k,onChange:U=>H(U.target.value),placeholder:r.clientSecretSet?"已设置,留空表示不修改":"粘贴 Discord Client Secret"})]}),n.jsxs("label",{className:"settings-form-wide",children:[n.jsx("span",{children:"回调地址"}),n.jsx("input",{type:"url",value:r.redirectUri,onChange:U=>A({...r,redirectUri:U.target.value}),placeholder:"https://你的域名/api/auth/discord/callback"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"服务器 ID"}),n.jsx("input",{inputMode:"numeric",value:r.allowedGuildId,onChange:U=>A({...r,allowedGuildId:U.target.value}),placeholder:"允许登录的服务器 ID"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"身份组 ID"}),n.jsx("input",{inputMode:"numeric",value:r.allowedRoleId,onChange:U=>A({...r,allowedRoleId:U.target.value}),placeholder:"允许登录的身份组 ID"})]}),n.jsxs("label",{className:"settings-form-wide",children:[n.jsx("span",{children:"拉黑服务器 ID"}),n.jsx("textarea",{value:X,onChange:U=>se(U.target.value),placeholder:"每行一个服务器 ID;命中的用户禁止注册 / 登录",rows:3}),n.jsx("small",{children:"用户若加入了这些 Discord 服务器中的任意一个,将无法注册或登录(优先于上面的允许规则)。"})]}),n.jsxs("label",{className:"settings-form-wide",children:[n.jsx("span",{children:"登录成功跳转地址"}),n.jsx("input",{type:"url",value:r.authSuccessUrl,onChange:U=>A({...r,authSuccessUrl:U.target.value}),placeholder:"https://你的域名/"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"登录有效期(小时)"}),n.jsx("input",{type:"number",min:"1",max:"8760",value:r.sessionTtlHours,onChange:U=>A({...r,sessionTtlHours:Number(U.target.value)})})]})]}),n.jsxs("div",{className:"settings-save-row",children:[n.jsx("span",{role:"status",children:m}),n.jsx("button",{className:"primary-button",type:"submit",disabled:M,children:M?"保存中":"保存配置"})]})]}):n.jsx("div",{className:"empty",children:"正在读取配置"})})]})}function cl({label:u,value:f}){return n.jsxs("div",{className:"metric",children:[n.jsx("span",{children:u}),n.jsx("strong",{children:f})]})}function Kp({groups:u,onCreate:f,onUpdate:p,onDelete:r}){const[A,T]=b.useState(""),[L,$]=b.useState(""),[C,g]=b.useState(!1);async function G(z){if(z.preventDefault(),!!A.trim()){g(!0);try{await f({name:A.trim(),description:L.trim()}),T(""),$("")}finally{g(!1)}}}return n.jsxs("section",{className:"models-page",children:[n.jsxs(at,{title:"用户分组",children:[n.jsxs("form",{className:"channel-create-form",onSubmit:G,children:[n.jsxs("div",{className:"channel-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"分组名称"}),n.jsx("input",{value:A,onChange:z=>T(z.target.value),placeholder:"例如 尊享用户 / 试用用户"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"说明"}),n.jsx("input",{value:L,onChange:z=>$(z.target.value),placeholder:"可选"})]})]}),n.jsx("div",{className:"channel-card-actions",children:n.jsx("button",{className:"primary-button",type:"submit",disabled:C||!A.trim(),children:C?"创建中":"创建分组"})})]}),n.jsx("p",{className:"muted-inline",children:"分组用于控制渠道对用户的可见范围:把用户归入分组,并在渠道上勾选「可见分组」即可限制访问。未分组的用户只能使用未限制分组的渠道。"})]}),n.jsx(at,{title:"全部分组",children:u.length===0?n.jsx(kt,{text:"还没有分组"}):n.jsx("div",{className:"channels-stack",children:u.map(z=>n.jsx(Zp,{group:z,onUpdate:p,onDelete:r},z.id))})})]})}function Zp({group:u,onUpdate:f,onDelete:p}){const[r,A]=b.useState(!1),[T,L]=b.useState(u.name),[$,C]=b.useState(u.description),[g,G]=b.useState(!1);async function z(){G(!0);try{await f(u.id,{name:T.trim(),description:$.trim()}),A(!1)}finally{G(!1)}}return n.jsx("div",{className:"channel-card",children:n.jsxs("div",{className:"channel-card-head",children:[n.jsx("div",{children:r?n.jsxs("div",{className:"group-edit-fields",children:[n.jsx("input",{value:T,onChange:V=>L(V.target.value),placeholder:"分组名称"}),n.jsx("input",{value:$,onChange:V=>C(V.target.value),placeholder:"说明"})]}):n.jsxs(n.Fragment,{children:[n.jsx("strong",{children:u.name}),u.description&&n.jsx("span",{children:u.description}),n.jsxs("small",{children:["创建于 ",el(u.createdAt)]})]})}),n.jsx("div",{className:"channel-card-head-actions",children:r?n.jsxs(n.Fragment,{children:[n.jsx("button",{className:"primary-button compact-button",onClick:z,disabled:g||!T.trim(),children:g?"保存中":"保存"}),n.jsx("button",{className:"secondary-button compact-button",onClick:()=>{L(u.name),C(u.description),A(!1)},children:"取消"})]}):n.jsxs(n.Fragment,{children:[n.jsx("button",{className:"secondary-button compact-button",onClick:()=>A(!0),children:"重命名"}),n.jsx("button",{className:"danger-button compact-button",onClick:()=>p(u.id),children:"删除"})]})})]})})}function at({title:u,children:f}){return n.jsxs("section",{className:"panel",children:[n.jsx("div",{className:"panel-title",children:n.jsx("h2",{children:u})}),f]})}function Dt({tone:u,children:f}){return n.jsx("span",{className:`badge tone-${u}`,children:f})}function Pt({label:u,value:f,switchOn:p}){return n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:u}),n.jsxs("div",{className:"setting-value",children:[n.jsx("strong",{children:f}),typeof p=="boolean"&&n.jsx("div",{className:p?"ios-switch is-on":"ios-switch","aria-hidden":"true",children:n.jsx("span",{})})]})]})}function Vp({value:u,options:f,onChange:p}){return n.jsx("div",{className:"segmented-control",children:f.map(r=>n.jsx("button",{className:u===r.value?"selected":"",onClick:()=>p(r.value),children:r.label},r.value))})}function kt({text:u}){return n.jsx("div",{className:"empty",children:u})}$0.createRoot(document.getElementById("root")).render(n.jsx(k0.StrictMode,{children:n.jsx(mp,{})})); diff --git a/dist/assets/index-BBl9ztAh.js b/dist/assets/index-BBl9ztAh.js new file mode 100644 index 0000000..972843f --- /dev/null +++ b/dist/assets/index-BBl9ztAh.js @@ -0,0 +1,43 @@ +(function(){const f=document.createElement("link").relList;if(f&&f.supports&&f.supports("modulepreload"))return;for(const C of document.querySelectorAll('link[rel="modulepreload"]'))r(C);new MutationObserver(C=>{for(const T of C)if(T.type==="childList")for(const k of T.addedNodes)k.tagName==="LINK"&&k.rel==="modulepreload"&&r(k)}).observe(document,{childList:!0,subtree:!0});function p(C){const T={};return C.integrity&&(T.integrity=C.integrity),C.referrerPolicy&&(T.referrerPolicy=C.referrerPolicy),C.crossOrigin==="use-credentials"?T.credentials="include":C.crossOrigin==="anonymous"?T.credentials="omit":T.credentials="same-origin",T}function r(C){if(C.ep)return;C.ep=!0;const T=p(C);fetch(C.href,T)}})();function q0(u){return u&&u.__esModule&&Object.prototype.hasOwnProperty.call(u,"default")?u.default:u}var Qc={exports:{}},ss={};var tm;function G0(){if(tm)return ss;tm=1;var u=Symbol.for("react.transitional.element"),f=Symbol.for("react.fragment");function p(r,C,T){var k=null;if(T!==void 0&&(k=""+T),C.key!==void 0&&(k=""+C.key),"key"in C){T={};for(var W in C)W!=="key"&&(T[W]=C[W])}else T=C;return C=T.ref,{$$typeof:u,type:r,key:k,ref:C!==void 0?C:null,props:T}}return ss.Fragment=f,ss.jsx=p,ss.jsxs=p,ss}var lm;function k0(){return lm||(lm=1,Qc.exports=G0()),Qc.exports}var n=k0(),Xc={exports:{}},Ae={};var am;function Y0(){if(am)return Ae;am=1;var u=Symbol.for("react.transitional.element"),f=Symbol.for("react.portal"),p=Symbol.for("react.fragment"),r=Symbol.for("react.strict_mode"),C=Symbol.for("react.profiler"),T=Symbol.for("react.consumer"),k=Symbol.for("react.context"),W=Symbol.for("react.forward_ref"),N=Symbol.for("react.suspense"),y=Symbol.for("react.memo"),G=Symbol.for("react.lazy"),_=Symbol.for("react.activity"),V=Symbol.iterator;function P(m){return m===null||typeof m!="object"?null:(m=V&&m[V]||m["@@iterator"],typeof m=="function"?m:null)}var fe={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},ee=Object.assign,me={};function ne(m,h,M){this.props=m,this.context=h,this.refs=me,this.updater=M||fe}ne.prototype.isReactComponent={},ne.prototype.setState=function(m,h){if(typeof m!="object"&&typeof m!="function"&&m!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,m,h,"setState")},ne.prototype.forceUpdate=function(m){this.updater.enqueueForceUpdate(this,m,"forceUpdate")};function se(){}se.prototype=ne.prototype;function Y(m,h,M){this.props=m,this.context=h,this.refs=me,this.updater=M||fe}var xe=Y.prototype=new se;xe.constructor=Y,ee(xe,ne.prototype),xe.isPureReactComponent=!0;var te=Array.isArray;function ye(){}var O={H:null,A:null,T:null,S:null},ae=Object.prototype.hasOwnProperty;function ve(m,h,M){var Q=M.ref;return{$$typeof:u,type:m,key:h,ref:Q!==void 0?Q:null,props:M}}function Ce(m,h){return ve(m.type,h,m.props)}function Me(m){return typeof m=="object"&&m!==null&&m.$$typeof===u}function ue(m){var h={"=":"=0",":":"=2"};return"$"+m.replace(/[=:]/g,function(M){return h[M]})}var Z=/\/+/g;function de(m,h){return typeof m=="object"&&m!==null&&m.key!=null?ue(""+m.key):h.toString(36)}function $(m){switch(m.status){case"fulfilled":return m.value;case"rejected":throw m.reason;default:switch(typeof m.status=="string"?m.then(ye,ye):(m.status="pending",m.then(function(h){m.status==="pending"&&(m.status="fulfilled",m.value=h)},function(h){m.status==="pending"&&(m.status="rejected",m.reason=h)})),m.status){case"fulfilled":return m.value;case"rejected":throw m.reason}}throw m}function A(m,h,M,Q,le){var Ne=typeof m;(Ne==="undefined"||Ne==="boolean")&&(m=null);var z=!1;if(m===null)z=!0;else switch(Ne){case"bigint":case"string":case"number":z=!0;break;case"object":switch(m.$$typeof){case u:case f:z=!0;break;case G:return z=m._init,A(z(m._payload),h,M,Q,le)}}if(z)return le=le(m),z=Q===""?"."+de(m,0):Q,te(le)?(M="",z!=null&&(M=z.replace(Z,"$&/")+"/"),A(le,h,M,"",function(jt){return jt})):le!=null&&(Me(le)&&(le=Ce(le,M+(le.key==null||m&&m.key===le.key?"":(""+le.key).replace(Z,"$&/")+"/")+z)),h.push(le)),1;z=0;var be=Q===""?".":Q+":";if(te(m))for(var ce=0;ce>>1,ie=A[X];if(0>>1;XC(M,H))QC(le,M)?(A[X]=le,A[Q]=H,X=Q):(A[X]=M,A[h]=H,X=h);else if(QC(le,H))A[X]=le,A[Q]=H,X=Q;else break e}}return L}function C(A,L){var H=A.sortIndex-L.sortIndex;return H!==0?H:A.id-L.id}if(u.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var T=performance;u.unstable_now=function(){return T.now()}}else{var k=Date,W=k.now();u.unstable_now=function(){return k.now()-W}}var N=[],y=[],G=1,_=null,V=3,P=!1,fe=!1,ee=!1,me=!1,ne=typeof setTimeout=="function"?setTimeout:null,se=typeof clearTimeout=="function"?clearTimeout:null,Y=typeof setImmediate<"u"?setImmediate:null;function xe(A){for(var L=p(y);L!==null;){if(L.callback===null)r(y);else if(L.startTime<=A)r(y),L.sortIndex=L.expirationTime,f(N,L);else break;L=p(y)}}function te(A){if(ee=!1,xe(A),!fe)if(p(N)!==null)fe=!0,ye||(ye=!0,ue());else{var L=p(y);L!==null&&$(te,L.startTime-A)}}var ye=!1,O=-1,ae=5,ve=-1;function Ce(){return me?!0:!(u.unstable_now()-veA&&Ce());){var X=_.callback;if(typeof X=="function"){_.callback=null,V=_.priorityLevel;var ie=X(_.expirationTime<=A);if(A=u.unstable_now(),typeof ie=="function"){_.callback=ie,xe(A),L=!0;break t}_===p(N)&&r(N),xe(A)}else r(N);_=p(N)}if(_!==null)L=!0;else{var m=p(y);m!==null&&$(te,m.startTime-A),L=!1}}break e}finally{_=null,V=H,P=!1}L=void 0}}finally{L?ue():ye=!1}}}var ue;if(typeof Y=="function")ue=function(){Y(Me)};else if(typeof MessageChannel<"u"){var Z=new MessageChannel,de=Z.port2;Z.port1.onmessage=Me,ue=function(){de.postMessage(null)}}else ue=function(){ne(Me,0)};function $(A,L){O=ne(function(){A(u.unstable_now())},L)}u.unstable_IdlePriority=5,u.unstable_ImmediatePriority=1,u.unstable_LowPriority=4,u.unstable_NormalPriority=3,u.unstable_Profiling=null,u.unstable_UserBlockingPriority=2,u.unstable_cancelCallback=function(A){A.callback=null},u.unstable_forceFrameRate=function(A){0>A||125X?(A.sortIndex=H,f(y,A),p(N)===null&&A===p(y)&&(ee?(se(O),O=-1):ee=!0,$(te,H-X))):(A.sortIndex=ie,f(N,A),fe||P||(fe=!0,ye||(ye=!0,ue()))),A},u.unstable_shouldYield=Ce,u.unstable_wrapCallback=function(A){var L=V;return function(){var H=V;V=L;try{return A.apply(this,arguments)}finally{V=H}}}})(Vc)),Vc}var im;function X0(){return im||(im=1,Zc.exports=Q0()),Zc.exports}var Jc={exports:{}},yt={};var um;function K0(){if(um)return yt;um=1;var u=eo();function f(N){var y="https://react.dev/errors/"+N;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(u)}catch(f){console.error(f)}}return u(),Jc.exports=K0(),Jc.exports}var om;function V0(){if(om)return is;om=1;var u=X0(),f=eo(),p=Z0();function r(e){var t="https://react.dev/errors/"+e;if(1ie||(e.current=X[ie],X[ie]=null,ie--)}function M(e,t){ie++,X[ie]=e.current,e.current=t}var Q=m(null),le=m(null),Ne=m(null),z=m(null);function be(e,t){switch(M(Ne,t),M(le,e),M(Q,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?Af(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=Af(t),e=Cf(t,e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}h(Q),M(Q,e)}function ce(){h(Q),h(le),h(Ne)}function jt(e){e.memoizedState!==null&&M(z,e);var t=Q.current,l=Cf(t,e.type);t!==l&&(M(le,e),M(Q,l))}function I(e){le.current===e&&(h(Q),h(le)),z.current===e&&(h(z),ts._currentValue=H)}var Ve,ot;function Je(e){if(Ve===void 0)try{throw Error()}catch(l){var t=l.stack.trim().match(/\n( *(at )?)/);Ve=t&&t[1]||"",ot=-1)":-1s||d[a]!==j[s]){var D=` +`+d[a].replace(" at new "," at ");return e.displayName&&D.includes("")&&(D=D.replace("",e.displayName)),D}while(1<=a&&0<=s);break}}}finally{gt=!1,Error.prepareStackTrace=l}return(l=e?e.displayName||e.name:"")?Je(l):""}function ll(e,t){switch(e.tag){case 26:case 27:case 5:return Je(e.type);case 16:return Je("Lazy");case 13:return e.child!==t&&t!==null?Je("Suspense Fallback"):Je("Suspense");case 19:return Je("SuspenseList");case 0:case 15:return Dt(e.type,!1);case 11:return Dt(e.type.render,!1);case 1:return Dt(e.type,!0);case 31:return Je("Activity");default:return""}}function al(e){try{var t="",l=null;do t+=ll(e,l),l=e,e=e.return;while(e);return t}catch(a){return` +Error generating stack: `+a.message+` +`+a.stack}}var U=Object.prototype.hasOwnProperty,B=u.unstable_scheduleCallback,Be=u.unstable_cancelCallback,We=u.unstable_shouldYield,at=u.unstable_requestPaint,Pe=u.unstable_now,zi=u.unstable_getCurrentPriorityLevel,cs=u.unstable_ImmediatePriority,os=u.unstable_UserBlockingPriority,ua=u.unstable_NormalPriority,Ea=u.unstable_LowPriority,hn=u.unstable_IdlePriority,Oi=u.log,R=u.unstable_setDisableYieldValue,K=null,J=null;function F(e){if(typeof Oi=="function"&&R(e),J&&typeof J.setStrictMode=="function")try{J.setStrictMode(K,e)}catch{}}var he=Math.clz32?Math.clz32:Rt,$e=Math.log,Ut=Math.LN2;function Rt(e){return e>>>=0,e===0?32:31-($e(e)/Ut|0)|0}var nl=256,rl=262144,Ma=4194304;function vl(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Hl(e,t,l){var a=e.pendingLanes;if(a===0)return 0;var s=0,i=e.suspendedLanes,c=e.pingedLanes;e=e.warmLanes;var o=a&134217727;return o!==0?(a=o&~i,a!==0?s=vl(a):(c&=o,c!==0?s=vl(c):l||(l=o&~e,l!==0&&(s=vl(l))))):(o=a&~i,o!==0?s=vl(o):c!==0?s=vl(c):l||(l=a&~e,l!==0&&(s=vl(l)))),s===0?0:t!==0&&t!==s&&(t&i)===0&&(i=s&-s,l=t&-t,i>=l||i===32&&(l&4194048)!==0)?t:s}function ca(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Cm(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function ao(){var e=Ma;return Ma<<=1,(Ma&62914560)===0&&(Ma=4194304),e}function _i(e){for(var t=[],l=0;31>l;l++)t.push(e);return t}function pn(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function Tm(e,t,l,a,s,i){var c=e.pendingLanes;e.pendingLanes=l,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=l,e.entangledLanes&=l,e.errorRecoveryDisabledLanes&=l,e.shellSuspendCounter=0;var o=e.entanglements,d=e.expirationTimes,j=e.hiddenUpdates;for(l=c&~l;0"u")return null;try{return e.activeElement||e.body}catch{return e.body}}var Dm=/[\n"\\]/g;function Xt(e){return e.replace(Dm,function(t){return"\\"+t.charCodeAt(0).toString(16)+" "})}function Bi(e,t,l,a,s,i,c,o){e.name="",c!=null&&typeof c!="function"&&typeof c!="symbol"&&typeof c!="boolean"?e.type=c:e.removeAttribute("type"),t!=null?c==="number"?(t===0&&e.value===""||e.value!=t)&&(e.value=""+Qt(t)):e.value!==""+Qt(t)&&(e.value=""+Qt(t)):c!=="submit"&&c!=="reset"||e.removeAttribute("value"),t!=null?qi(e,c,Qt(t)):l!=null?qi(e,c,Qt(l)):a!=null&&e.removeAttribute("value"),s==null&&i!=null&&(e.defaultChecked=!!i),s!=null&&(e.checked=s&&typeof s!="function"&&typeof s!="symbol"),o!=null&&typeof o!="function"&&typeof o!="symbol"&&typeof o!="boolean"?e.name=""+Qt(o):e.removeAttribute("name")}function yo(e,t,l,a,s,i,c,o){if(i!=null&&typeof i!="function"&&typeof i!="symbol"&&typeof i!="boolean"&&(e.type=i),t!=null||l!=null){if(!(i!=="submit"&&i!=="reset"||t!=null)){Hi(e);return}l=l!=null?""+Qt(l):"",t=t!=null?""+Qt(t):l,o||t===e.value||(e.value=t),e.defaultValue=t}a=a??s,a=typeof a!="function"&&typeof a!="symbol"&&!!a,e.checked=o?e.checked:!!a,e.defaultChecked=!!a,c!=null&&typeof c!="function"&&typeof c!="symbol"&&typeof c!="boolean"&&(e.name=c),Hi(e)}function qi(e,t,l){t==="number"&&fs(e.ownerDocument)===e||e.defaultValue===""+l||(e.defaultValue=""+l)}function Ra(e,t,l,a){if(e=e.options,t){t={};for(var s=0;s"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Qi=!1;if(bl)try{var bn={};Object.defineProperty(bn,"passive",{get:function(){Qi=!0}}),window.addEventListener("test",bn,bn),window.removeEventListener("test",bn,bn)}catch{Qi=!1}var ql=null,Xi=null,hs=null;function Ao(){if(hs)return hs;var e,t=Xi,l=t.length,a,s="value"in ql?ql.value:ql.textContent,i=s.length;for(e=0;e=Sn),Oo=" ",_o=!1;function Do(e,t){switch(e){case"keyup":return ih.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Uo(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var qa=!1;function ch(e,t){switch(e){case"compositionend":return Uo(t);case"keypress":return t.which!==32?null:(_o=!0,Oo);case"textInput":return e=t.data,e===Oo&&_o?null:e;default:return null}}function oh(e,t){if(qa)return e==="compositionend"||!$i&&Do(e,t)?(e=Ao(),hs=Xi=ql=null,qa=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:l,offset:t-e};e=a}e:{for(;l;){if(l.nextSibling){l=l.nextSibling;break e}l=l.parentNode}l=void 0}l=Yo(l)}}function Qo(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Qo(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Xo(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=fs(e.document);t instanceof e.HTMLIFrameElement;){try{var l=typeof t.contentWindow.location.href=="string"}catch{l=!1}if(l)e=t.contentWindow;else break;t=fs(e.document)}return t}function Ii(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}var yh=bl&&"documentMode"in document&&11>=document.documentMode,Ga=null,Pi=null,Tn=null,eu=!1;function Ko(e,t,l){var a=l.window===l?l.document:l.nodeType===9?l:l.ownerDocument;eu||Ga==null||Ga!==fs(a)||(a=Ga,"selectionStart"in a&&Ii(a)?a={start:a.selectionStart,end:a.selectionEnd}:(a=(a.ownerDocument&&a.ownerDocument.defaultView||window).getSelection(),a={anchorNode:a.anchorNode,anchorOffset:a.anchorOffset,focusNode:a.focusNode,focusOffset:a.focusOffset}),Tn&&Cn(Tn,a)||(Tn=a,a=ui(Pi,"onSelect"),0>=c,s-=c,dl=1<<32-he(t)+s|l<Ee?(De=re,re=null):De=re.sibling;var we=S(g,re,x[Ee],w);if(we===null){re===null&&(re=De);break}e&&re&&we.alternate===null&&t(g,re),v=i(we,v,Ee),Re===null?ge=we:Re.sibling=we,Re=we,re=De}if(Ee===x.length)return l(g,re),Ue&&jl(g,Ee),ge;if(re===null){for(;EeEe?(De=re,re=null):De=re.sibling;var ia=S(g,re,we.value,w);if(ia===null){re===null&&(re=De);break}e&&re&&ia.alternate===null&&t(g,re),v=i(ia,v,Ee),Re===null?ge=ia:Re.sibling=ia,Re=ia,re=De}if(we.done)return l(g,re),Ue&&jl(g,Ee),ge;if(re===null){for(;!we.done;Ee++,we=x.next())we=q(g,we.value,w),we!==null&&(v=i(we,v,Ee),Re===null?ge=we:Re.sibling=we,Re=we);return Ue&&jl(g,Ee),ge}for(re=a(re);!we.done;Ee++,we=x.next())we=E(re,g,Ee,we.value,w),we!==null&&(e&&we.alternate!==null&&re.delete(we.key===null?Ee:we.key),v=i(we,v,Ee),Re===null?ge=we:Re.sibling=we,Re=we);return e&&re.forEach(function(B0){return t(g,B0)}),Ue&&jl(g,Ee),ge}function Le(g,v,x,w){if(typeof x=="object"&&x!==null&&x.type===ee&&x.key===null&&(x=x.props.children),typeof x=="object"&&x!==null){switch(x.$$typeof){case P:e:{for(var ge=x.key;v!==null;){if(v.key===ge){if(ge=x.type,ge===ee){if(v.tag===7){l(g,v.sibling),w=s(v,x.props.children),w.return=g,g=w;break e}}else if(v.elementType===ge||typeof ge=="object"&&ge!==null&&ge.$$typeof===ae&&ba(ge)===v.type){l(g,v.sibling),w=s(v,x.props),Dn(w,x),w.return=g,g=w;break e}l(g,v);break}else t(g,v);v=v.sibling}x.type===ee?(w=ha(x.props.children,g.mode,w,x.key),w.return=g,g=w):(w=As(x.type,x.key,x.props,null,g.mode,w),Dn(w,x),w.return=g,g=w)}return c(g);case fe:e:{for(ge=x.key;v!==null;){if(v.key===ge)if(v.tag===4&&v.stateNode.containerInfo===x.containerInfo&&v.stateNode.implementation===x.implementation){l(g,v.sibling),w=s(v,x.children||[]),w.return=g,g=w;break e}else{l(g,v);break}else t(g,v);v=v.sibling}w=uu(x,g.mode,w),w.return=g,g=w}return c(g);case ae:return x=ba(x),Le(g,v,x,w)}if($(x))return oe(g,v,x,w);if(ue(x)){if(ge=ue(x),typeof ge!="function")throw Error(r(150));return x=ge.call(x),Se(g,v,x,w)}if(typeof x.then=="function")return Le(g,v,_s(x),w);if(x.$$typeof===Y)return Le(g,v,Es(g,x),w);Ds(g,x)}return typeof x=="string"&&x!==""||typeof x=="number"||typeof x=="bigint"?(x=""+x,v!==null&&v.tag===6?(l(g,v.sibling),w=s(v,x),w.return=g,g=w):(l(g,v),w=iu(x,g.mode,w),w.return=g,g=w),c(g)):l(g,v)}return function(g,v,x,w){try{_n=0;var ge=Le(g,v,x,w);return Wa=null,ge}catch(re){if(re===$a||re===zs)throw re;var Re=Ht(29,re,null,g.mode);return Re.lanes=w,Re.return=g,Re}}}var ja=hr(!0),pr=hr(!1),Ql=!1;function bu(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function xu(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function Xl(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function Kl(e,t,l){var a=e.updateQueue;if(a===null)return null;if(a=a.shared,(He&2)!==0){var s=a.pending;return s===null?t.next=t:(t.next=s.next,s.next=t),a.pending=t,t=Ns(e),Io(e,null,l),t}return Ss(e,a,t,l),Ns(e)}function Un(e,t,l){if(t=t.updateQueue,t!==null&&(t=t.shared,(l&4194048)!==0)){var a=t.lanes;a&=e.pendingLanes,l|=a,t.lanes=l,so(e,l)}}function ju(e,t){var l=e.updateQueue,a=e.alternate;if(a!==null&&(a=a.updateQueue,l===a)){var s=null,i=null;if(l=l.firstBaseUpdate,l!==null){do{var c={lane:l.lane,tag:l.tag,payload:l.payload,callback:null,next:null};i===null?s=i=c:i=i.next=c,l=l.next}while(l!==null);i===null?s=i=t:i=i.next=t}else s=i=t;l={baseState:a.baseState,firstBaseUpdate:s,lastBaseUpdate:i,shared:a.shared,callbacks:a.callbacks},e.updateQueue=l;return}e=l.lastBaseUpdate,e===null?l.firstBaseUpdate=t:e.next=t,l.lastBaseUpdate=t}var Su=!1;function Rn(){if(Su){var e=Ja;if(e!==null)throw e}}function wn(e,t,l,a){Su=!1;var s=e.updateQueue;Ql=!1;var i=s.firstBaseUpdate,c=s.lastBaseUpdate,o=s.shared.pending;if(o!==null){s.shared.pending=null;var d=o,j=d.next;d.next=null,c===null?i=j:c.next=j,c=d;var D=e.alternate;D!==null&&(D=D.updateQueue,o=D.lastBaseUpdate,o!==c&&(o===null?D.firstBaseUpdate=j:o.next=j,D.lastBaseUpdate=d))}if(i!==null){var q=s.baseState;c=0,D=j=d=null,o=i;do{var S=o.lane&-536870913,E=S!==o.lane;if(E?(_e&S)===S:(a&S)===S){S!==0&&S===Va&&(Su=!0),D!==null&&(D=D.next={lane:0,tag:o.tag,payload:o.payload,callback:null,next:null});e:{var oe=e,Se=o;S=t;var Le=l;switch(Se.tag){case 1:if(oe=Se.payload,typeof oe=="function"){q=oe.call(Le,q,S);break e}q=oe;break e;case 3:oe.flags=oe.flags&-65537|128;case 0:if(oe=Se.payload,S=typeof oe=="function"?oe.call(Le,q,S):oe,S==null)break e;q=_({},q,S);break e;case 2:Ql=!0}}S=o.callback,S!==null&&(e.flags|=64,E&&(e.flags|=8192),E=s.callbacks,E===null?s.callbacks=[S]:E.push(S))}else E={lane:S,tag:o.tag,payload:o.payload,callback:o.callback,next:null},D===null?(j=D=E,d=q):D=D.next=E,c|=S;if(o=o.next,o===null){if(o=s.shared.pending,o===null)break;E=o,o=E.next,E.next=null,s.lastBaseUpdate=E,s.shared.pending=null}}while(!0);D===null&&(d=q),s.baseState=d,s.firstBaseUpdate=j,s.lastBaseUpdate=D,i===null&&(s.shared.lanes=0),Wl|=c,e.lanes=c,e.memoizedState=q}}function vr(e,t){if(typeof e!="function")throw Error(r(191,e));e.call(t)}function yr(e,t){var l=e.callbacks;if(l!==null)for(e.callbacks=null,e=0;ei?i:8;var c=A.T,o={};A.T=o,Yu(e,!1,t,l);try{var d=s(),j=A.S;if(j!==null&&j(o,d),d!==null&&typeof d=="object"&&typeof d.then=="function"){var D=Th(d,a);qn(e,t,D,Yt(e))}else qn(e,t,a,Yt(e))}catch(q){qn(e,t,{then:function(){},status:"rejected",reason:q},Yt())}finally{L.p=i,c!==null&&o.types!==null&&(c.types=o.types),A.T=c}}function Dh(){}function Gu(e,t,l,a){if(e.tag!==5)throw Error(r(476));var s=$r(e).queue;Jr(e,s,t,H,l===null?Dh:function(){return Wr(e),l(a)})}function $r(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:H,baseState:H,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Cl,lastRenderedState:H},next:null};var l={};return t.next={memoizedState:l,baseState:l,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Cl,lastRenderedState:l},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function Wr(e){var t=$r(e);t.next===null&&(t=e.alternate.memoizedState),qn(e,t.next.queue,{},Yt())}function ku(){return ht(ts)}function Fr(){return tt().memoizedState}function Ir(){return tt().memoizedState}function Uh(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var l=Yt();e=Xl(l);var a=Kl(t,e,l);a!==null&&(Mt(a,t,l),Un(a,t,l)),t={cache:pu()},e.payload=t;return}t=t.return}}function Rh(e,t,l){var a=Yt();l={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null},Ls(e)?ed(t,l):(l=nu(e,t,l,a),l!==null&&(Mt(l,e,a),td(l,t,a)))}function Pr(e,t,l){var a=Yt();qn(e,t,l,a)}function qn(e,t,l,a){var s={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null};if(Ls(e))ed(t,s);else{var i=e.alternate;if(e.lanes===0&&(i===null||i.lanes===0)&&(i=t.lastRenderedReducer,i!==null))try{var c=t.lastRenderedState,o=i(c,l);if(s.hasEagerState=!0,s.eagerState=o,wt(o,c))return Ss(e,t,s,0),Qe===null&&js(),!1}catch{}if(l=nu(e,t,s,a),l!==null)return Mt(l,e,a),td(l,t,a),!0}return!1}function Yu(e,t,l,a){if(a={lane:2,revertLane:bc(),gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null},Ls(e)){if(t)throw Error(r(479))}else t=nu(e,l,a,2),t!==null&&Mt(t,e,2)}function Ls(e){var t=e.alternate;return e===Te||t!==null&&t===Te}function ed(e,t){Ia=ws=!0;var l=e.pending;l===null?t.next=t:(t.next=l.next,l.next=t),e.pending=t}function td(e,t,l){if((l&4194048)!==0){var a=t.lanes;a&=e.pendingLanes,l|=a,t.lanes=l,so(e,l)}}var Gn={readContext:ht,use:qs,useCallback:Fe,useContext:Fe,useEffect:Fe,useImperativeHandle:Fe,useLayoutEffect:Fe,useInsertionEffect:Fe,useMemo:Fe,useReducer:Fe,useRef:Fe,useState:Fe,useDebugValue:Fe,useDeferredValue:Fe,useTransition:Fe,useSyncExternalStore:Fe,useId:Fe,useHostTransitionStatus:Fe,useFormState:Fe,useActionState:Fe,useOptimistic:Fe,useMemoCache:Fe,useCacheRefresh:Fe};Gn.useEffectEvent=Fe;var ld={readContext:ht,use:qs,useCallback:function(e,t){return bt().memoizedState=[e,t===void 0?null:t],e},useContext:ht,useEffect:Gr,useImperativeHandle:function(e,t,l){l=l!=null?l.concat([e]):null,ks(4194308,4,Qr.bind(null,t,e),l)},useLayoutEffect:function(e,t){return ks(4194308,4,e,t)},useInsertionEffect:function(e,t){ks(4,2,e,t)},useMemo:function(e,t){var l=bt();t=t===void 0?null:t;var a=e();if(Sa){F(!0);try{e()}finally{F(!1)}}return l.memoizedState=[a,t],a},useReducer:function(e,t,l){var a=bt();if(l!==void 0){var s=l(t);if(Sa){F(!0);try{l(t)}finally{F(!1)}}}else s=t;return a.memoizedState=a.baseState=s,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:s},a.queue=e,e=e.dispatch=Rh.bind(null,Te,e),[a.memoizedState,e]},useRef:function(e){var t=bt();return e={current:e},t.memoizedState=e},useState:function(e){e=Ru(e);var t=e.queue,l=Pr.bind(null,Te,t);return t.dispatch=l,[e.memoizedState,l]},useDebugValue:Bu,useDeferredValue:function(e,t){var l=bt();return qu(l,e,t)},useTransition:function(){var e=Ru(!1);return e=Jr.bind(null,Te,e.queue,!0,!1),bt().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,l){var a=Te,s=bt();if(Ue){if(l===void 0)throw Error(r(407));l=l()}else{if(l=t(),Qe===null)throw Error(r(349));(_e&127)!==0||Nr(a,t,l)}s.memoizedState=l;var i={value:l,getSnapshot:t};return s.queue=i,Gr(Cr.bind(null,a,i,e),[e]),a.flags|=2048,en(9,{destroy:void 0},Ar.bind(null,a,i,l,t),null),l},useId:function(){var e=bt(),t=Qe.identifierPrefix;if(Ue){var l=fl,a=dl;l=(a&~(1<<32-he(a)-1)).toString(32)+l,t="_"+t+"R_"+l,l=Hs++,0<\/script>",i=i.removeChild(i.firstChild);break;case"select":i=typeof a.is=="string"?c.createElement("select",{is:a.is}):c.createElement("select"),a.multiple?i.multiple=!0:a.size&&(i.size=a.size);break;default:i=typeof a.is=="string"?c.createElement(s,{is:a.is}):c.createElement(s)}}i[ft]=t,i[St]=a;e:for(c=t.child;c!==null;){if(c.tag===5||c.tag===6)i.appendChild(c.stateNode);else if(c.tag!==4&&c.tag!==27&&c.child!==null){c.child.return=c,c=c.child;continue}if(c===t)break e;for(;c.sibling===null;){if(c.return===null||c.return===t)break e;c=c.return}c.sibling.return=c.return,c=c.sibling}t.stateNode=i;e:switch(vt(i,s,a),s){case"button":case"input":case"select":case"textarea":a=!!a.autoFocus;break e;case"img":a=!0;break e;default:a=!1}a&&El(t)}}return Ke(t),tc(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,l),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==a&&El(t);else{if(typeof a!="string"&&t.stateNode===null)throw Error(r(166));if(e=Ne.current,Ka(t)){if(e=t.stateNode,l=t.memoizedProps,a=null,s=mt,s!==null)switch(s.tag){case 27:case 5:a=s.memoizedProps}e[ft]=t,e=!!(e.nodeValue===l||a!==null&&a.suppressHydrationWarning===!0||Sf(e.nodeValue,l)),e||Yl(t,!0)}else e=ci(e).createTextNode(a),e[ft]=t,t.stateNode=e}return Ke(t),null;case 31:if(l=t.memoizedState,e===null||e.memoizedState!==null){if(a=Ka(t),l!==null){if(e===null){if(!a)throw Error(r(318));if(e=t.memoizedState,e=e!==null?e.dehydrated:null,!e)throw Error(r(557));e[ft]=t}else pa(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;Ke(t),e=!1}else l=du(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=l),e=!0;if(!e)return t.flags&256?(qt(t),t):(qt(t),null);if((t.flags&128)!==0)throw Error(r(558))}return Ke(t),null;case 13:if(a=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(s=Ka(t),a!==null&&a.dehydrated!==null){if(e===null){if(!s)throw Error(r(318));if(s=t.memoizedState,s=s!==null?s.dehydrated:null,!s)throw Error(r(317));s[ft]=t}else pa(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;Ke(t),s=!1}else s=du(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=s),s=!0;if(!s)return t.flags&256?(qt(t),t):(qt(t),null)}return qt(t),(t.flags&128)!==0?(t.lanes=l,t):(l=a!==null,e=e!==null&&e.memoizedState!==null,l&&(a=t.child,s=null,a.alternate!==null&&a.alternate.memoizedState!==null&&a.alternate.memoizedState.cachePool!==null&&(s=a.alternate.memoizedState.cachePool.pool),i=null,a.memoizedState!==null&&a.memoizedState.cachePool!==null&&(i=a.memoizedState.cachePool.pool),i!==s&&(a.flags|=2048)),l!==e&&l&&(t.child.flags|=8192),Vs(t,t.updateQueue),Ke(t),null);case 4:return ce(),e===null&&Nc(t.stateNode.containerInfo),Ke(t),null;case 10:return Nl(t.type),Ke(t),null;case 19:if(h(et),a=t.memoizedState,a===null)return Ke(t),null;if(s=(t.flags&128)!==0,i=a.rendering,i===null)if(s)Yn(a,!1);else{if(Ie!==0||e!==null&&(e.flags&128)!==0)for(e=t.child;e!==null;){if(i=Rs(e),i!==null){for(t.flags|=128,Yn(a,!1),e=i.updateQueue,t.updateQueue=e,Vs(t,e),t.subtreeFlags=0,e=l,l=t.child;l!==null;)Po(l,e),l=l.sibling;return M(et,et.current&1|2),Ue&&jl(t,a.treeForkCount),t.child}e=e.sibling}a.tail!==null&&Pe()>Is&&(t.flags|=128,s=!0,Yn(a,!1),t.lanes=4194304)}else{if(!s)if(e=Rs(i),e!==null){if(t.flags|=128,s=!0,e=e.updateQueue,t.updateQueue=e,Vs(t,e),Yn(a,!0),a.tail===null&&a.tailMode==="hidden"&&!i.alternate&&!Ue)return Ke(t),null}else 2*Pe()-a.renderingStartTime>Is&&l!==536870912&&(t.flags|=128,s=!0,Yn(a,!1),t.lanes=4194304);a.isBackwards?(i.sibling=t.child,t.child=i):(e=a.last,e!==null?e.sibling=i:t.child=i,a.last=i)}return a.tail!==null?(e=a.tail,a.rendering=e,a.tail=e.sibling,a.renderingStartTime=Pe(),e.sibling=null,l=et.current,M(et,s?l&1|2:l&1),Ue&&jl(t,a.treeForkCount),e):(Ke(t),null);case 22:case 23:return qt(t),Au(),a=t.memoizedState!==null,e!==null?e.memoizedState!==null!==a&&(t.flags|=8192):a&&(t.flags|=8192),a?(l&536870912)!==0&&(t.flags&128)===0&&(Ke(t),t.subtreeFlags&6&&(t.flags|=8192)):Ke(t),l=t.updateQueue,l!==null&&Vs(t,l.retryQueue),l=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(l=e.memoizedState.cachePool.pool),a=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(a=t.memoizedState.cachePool.pool),a!==l&&(t.flags|=2048),e!==null&&h(ga),null;case 24:return l=null,e!==null&&(l=e.memoizedState.cache),t.memoizedState.cache!==l&&(t.flags|=2048),Nl(nt),Ke(t),null;case 25:return null;case 30:return null}throw Error(r(156,t.tag))}function Gh(e,t){switch(ou(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Nl(nt),ce(),e=t.flags,(e&65536)!==0&&(e&128)===0?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return I(t),null;case 31:if(t.memoizedState!==null){if(qt(t),t.alternate===null)throw Error(r(340));pa()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(qt(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(r(340));pa()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return h(et),null;case 4:return ce(),null;case 10:return Nl(t.type),null;case 22:case 23:return qt(t),Au(),e!==null&&h(ga),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return Nl(nt),null;case 25:return null;default:return null}}function Td(e,t){switch(ou(t),t.tag){case 3:Nl(nt),ce();break;case 26:case 27:case 5:I(t);break;case 4:ce();break;case 31:t.memoizedState!==null&&qt(t);break;case 13:qt(t);break;case 19:h(et);break;case 10:Nl(t.type);break;case 22:case 23:qt(t),Au(),e!==null&&h(ga);break;case 24:Nl(nt)}}function Ln(e,t){try{var l=t.updateQueue,a=l!==null?l.lastEffect:null;if(a!==null){var s=a.next;l=s;do{if((l.tag&e)===e){a=void 0;var i=l.create,c=l.inst;a=i(),c.destroy=a}l=l.next}while(l!==s)}}catch(o){Ge(t,t.return,o)}}function Jl(e,t,l){try{var a=t.updateQueue,s=a!==null?a.lastEffect:null;if(s!==null){var i=s.next;a=i;do{if((a.tag&e)===e){var c=a.inst,o=c.destroy;if(o!==void 0){c.destroy=void 0,s=t;var d=l,j=o;try{j()}catch(D){Ge(s,d,D)}}}a=a.next}while(a!==i)}}catch(D){Ge(t,t.return,D)}}function Ed(e){var t=e.updateQueue;if(t!==null){var l=e.stateNode;try{yr(t,l)}catch(a){Ge(e,e.return,a)}}}function Md(e,t,l){l.props=Na(e.type,e.memoizedProps),l.state=e.memoizedState;try{l.componentWillUnmount()}catch(a){Ge(e,t,a)}}function Qn(e,t){try{var l=e.ref;if(l!==null){switch(e.tag){case 26:case 27:case 5:var a=e.stateNode;break;case 30:a=e.stateNode;break;default:a=e.stateNode}typeof l=="function"?e.refCleanup=l(a):l.current=a}}catch(s){Ge(e,t,s)}}function ml(e,t){var l=e.ref,a=e.refCleanup;if(l!==null)if(typeof a=="function")try{a()}catch(s){Ge(e,t,s)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof l=="function")try{l(null)}catch(s){Ge(e,t,s)}else l.current=null}function zd(e){var t=e.type,l=e.memoizedProps,a=e.stateNode;try{e:switch(t){case"button":case"input":case"select":case"textarea":l.autoFocus&&a.focus();break e;case"img":l.src?a.src=l.src:l.srcSet&&(a.srcset=l.srcSet)}}catch(s){Ge(e,e.return,s)}}function lc(e,t,l){try{var a=e.stateNode;u0(a,e.type,l,t),a[St]=t}catch(s){Ge(e,e.return,s)}}function Od(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&ta(e.type)||e.tag===4}function ac(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Od(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&ta(e.type)||e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function nc(e,t,l){var a=e.tag;if(a===5||a===6)e=e.stateNode,t?(l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l).insertBefore(e,t):(t=l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l,t.appendChild(e),l=l._reactRootContainer,l!=null||t.onclick!==null||(t.onclick=gl));else if(a!==4&&(a===27&&ta(e.type)&&(l=e.stateNode,t=null),e=e.child,e!==null))for(nc(e,t,l),e=e.sibling;e!==null;)nc(e,t,l),e=e.sibling}function Js(e,t,l){var a=e.tag;if(a===5||a===6)e=e.stateNode,t?l.insertBefore(e,t):l.appendChild(e);else if(a!==4&&(a===27&&ta(e.type)&&(l=e.stateNode),e=e.child,e!==null))for(Js(e,t,l),e=e.sibling;e!==null;)Js(e,t,l),e=e.sibling}function _d(e){var t=e.stateNode,l=e.memoizedProps;try{for(var a=e.type,s=t.attributes;s.length;)t.removeAttributeNode(s[0]);vt(t,a,l),t[ft]=e,t[St]=l}catch(i){Ge(e,e.return,i)}}var Ml=!1,ut=!1,sc=!1,Dd=typeof WeakSet=="function"?WeakSet:Set,dt=null;function kh(e,t){if(e=e.containerInfo,Tc=pi,e=Xo(e),Ii(e)){if("selectionStart"in e)var l={start:e.selectionStart,end:e.selectionEnd};else e:{l=(l=e.ownerDocument)&&l.defaultView||window;var a=l.getSelection&&l.getSelection();if(a&&a.rangeCount!==0){l=a.anchorNode;var s=a.anchorOffset,i=a.focusNode;a=a.focusOffset;try{l.nodeType,i.nodeType}catch{l=null;break e}var c=0,o=-1,d=-1,j=0,D=0,q=e,S=null;t:for(;;){for(var E;q!==l||s!==0&&q.nodeType!==3||(o=c+s),q!==i||a!==0&&q.nodeType!==3||(d=c+a),q.nodeType===3&&(c+=q.nodeValue.length),(E=q.firstChild)!==null;)S=q,q=E;for(;;){if(q===e)break t;if(S===l&&++j===s&&(o=c),S===i&&++D===a&&(d=c),(E=q.nextSibling)!==null)break;q=S,S=q.parentNode}q=E}l=o===-1||d===-1?null:{start:o,end:d}}else l=null}l=l||{start:0,end:0}}else l=null;for(Ec={focusedElem:e,selectionRange:l},pi=!1,dt=t;dt!==null;)if(t=dt,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,dt=e;else for(;dt!==null;){switch(t=dt,i=t.alternate,e=t.flags,t.tag){case 0:if((e&4)!==0&&(e=t.updateQueue,e=e!==null?e.events:null,e!==null))for(l=0;l title"))),vt(i,a,l),i[ft]=e,rt(i),a=i;break e;case"link":var c=Gf("link","href",s).get(a+(l.href||""));if(c){for(var o=0;oLe&&(c=Le,Le=Se,Se=c);var g=Lo(o,Se),v=Lo(o,Le);if(g&&v&&(E.rangeCount!==1||E.anchorNode!==g.node||E.anchorOffset!==g.offset||E.focusNode!==v.node||E.focusOffset!==v.offset)){var x=q.createRange();x.setStart(g.node,g.offset),E.removeAllRanges(),Se>Le?(E.addRange(x),E.extend(v.node,v.offset)):(x.setEnd(v.node,v.offset),E.addRange(x))}}}}for(q=[],E=o;E=E.parentNode;)E.nodeType===1&&q.push({element:E,left:E.scrollLeft,top:E.scrollTop});for(typeof o.focus=="function"&&o.focus(),o=0;ol?32:l,A.T=null,l=fc,fc=null;var i=Il,c=Ul;if(ct=0,sn=Il=null,Ul=0,(He&6)!==0)throw Error(r(331));var o=He;if(He|=4,Qd(i.current),kd(i,i.current,c,l),He=o,$n(0,!1),J&&typeof J.onPostCommitFiberRoot=="function")try{J.onPostCommitFiberRoot(K,i)}catch{}return!0}finally{L.p=s,A.T=a,cf(e,t)}}function rf(e,t,l){t=Zt(l,t),t=Ku(e.stateNode,t,2),e=Kl(e,t,2),e!==null&&(pn(e,2),hl(e))}function Ge(e,t,l){if(e.tag===3)rf(e,e,l);else for(;t!==null;){if(t.tag===3){rf(t,e,l);break}else if(t.tag===1){var a=t.stateNode;if(typeof t.type.getDerivedStateFromError=="function"||typeof a.componentDidCatch=="function"&&(Fl===null||!Fl.has(a))){e=Zt(l,e),l=rd(2),a=Kl(t,l,2),a!==null&&(dd(l,a,t,e),pn(a,2),hl(a));break}}t=t.return}}function vc(e,t,l){var a=e.pingCache;if(a===null){a=e.pingCache=new Qh;var s=new Set;a.set(t,s)}else s=a.get(t),s===void 0&&(s=new Set,a.set(t,s));s.has(l)||(cc=!0,s.add(l),e=Jh.bind(null,e,t,l),t.then(e,e))}function Jh(e,t,l){var a=e.pingCache;a!==null&&a.delete(t),e.pingedLanes|=e.suspendedLanes&l,e.warmLanes&=~l,Qe===e&&(_e&l)===l&&(Ie===4||Ie===3&&(_e&62914560)===_e&&300>Pe()-Fs?(He&2)===0&&un(e,0):oc|=l,nn===_e&&(nn=0)),hl(e)}function df(e,t){t===0&&(t=ao()),e=ma(e,t),e!==null&&(pn(e,t),hl(e))}function $h(e){var t=e.memoizedState,l=0;t!==null&&(l=t.retryLane),df(e,l)}function Wh(e,t){var l=0;switch(e.tag){case 31:case 13:var a=e.stateNode,s=e.memoizedState;s!==null&&(l=s.retryLane);break;case 19:a=e.stateNode;break;case 22:a=e.stateNode._retryCache;break;default:throw Error(r(314))}a!==null&&a.delete(t),df(e,l)}function Fh(e,t){return B(e,t)}var ni=null,on=null,yc=!1,si=!1,gc=!1,ea=0;function hl(e){e!==on&&e.next===null&&(on===null?ni=on=e:on=on.next=e),si=!0,yc||(yc=!0,Ph())}function $n(e,t){if(!gc&&si){gc=!0;do for(var l=!1,a=ni;a!==null;){if(e!==0){var s=a.pendingLanes;if(s===0)var i=0;else{var c=a.suspendedLanes,o=a.pingedLanes;i=(1<<31-he(42|e)+1)-1,i&=s&~(c&~o),i=i&201326741?i&201326741|1:i?i|2:0}i!==0&&(l=!0,pf(a,i))}else i=_e,i=Hl(a,a===Qe?i:0,a.cancelPendingCommit!==null||a.timeoutHandle!==-1),(i&3)===0||ca(a,i)||(l=!0,pf(a,i));a=a.next}while(l);gc=!1}}function Ih(){ff()}function ff(){si=yc=!1;var e=0;ea!==0&&o0()&&(e=ea);for(var t=Pe(),l=null,a=ni;a!==null;){var s=a.next,i=mf(a,t);i===0?(a.next=null,l===null?ni=s:l.next=s,s===null&&(on=l)):(l=a,(e!==0||(i&3)!==0)&&(si=!0)),a=s}ct!==0&&ct!==5||$n(e),ea!==0&&(ea=0)}function mf(e,t){for(var l=e.suspendedLanes,a=e.pingedLanes,s=e.expirationTimes,i=e.pendingLanes&-62914561;0o)break;var D=d.transferSize,q=d.initiatorType;D&&Nf(q)&&(d=d.responseEnd,c+=D*(d"u"?null:document;function wf(e,t,l){var a=rn;if(a&&typeof t=="string"&&t){var s=Xt(t);s='link[rel="'+e+'"][href="'+s+'"]',typeof l=="string"&&(s+='[crossorigin="'+l+'"]'),Rf.has(s)||(Rf.add(s),e={rel:e,crossOrigin:l,href:t},a.querySelector(s)===null&&(t=a.createElement("link"),vt(t,"link",e),rt(t),a.head.appendChild(t)))}}function g0(e){Rl.D(e),wf("dns-prefetch",e,null)}function b0(e,t){Rl.C(e,t),wf("preconnect",e,t)}function x0(e,t,l){Rl.L(e,t,l);var a=rn;if(a&&e&&t){var s='link[rel="preload"][as="'+Xt(t)+'"]';t==="image"&&l&&l.imageSrcSet?(s+='[imagesrcset="'+Xt(l.imageSrcSet)+'"]',typeof l.imageSizes=="string"&&(s+='[imagesizes="'+Xt(l.imageSizes)+'"]')):s+='[href="'+Xt(e)+'"]';var i=s;switch(t){case"style":i=dn(e);break;case"script":i=fn(e)}It.has(i)||(e=_({rel:"preload",href:t==="image"&&l&&l.imageSrcSet?void 0:e,as:t},l),It.set(i,e),a.querySelector(s)!==null||t==="style"&&a.querySelector(Pn(i))||t==="script"&&a.querySelector(es(i))||(t=a.createElement("link"),vt(t,"link",e),rt(t),a.head.appendChild(t)))}}function j0(e,t){Rl.m(e,t);var l=rn;if(l&&e){var a=t&&typeof t.as=="string"?t.as:"script",s='link[rel="modulepreload"][as="'+Xt(a)+'"][href="'+Xt(e)+'"]',i=s;switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":i=fn(e)}if(!It.has(i)&&(e=_({rel:"modulepreload",href:e},t),It.set(i,e),l.querySelector(s)===null)){switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(l.querySelector(es(i)))return}a=l.createElement("link"),vt(a,"link",e),rt(a),l.head.appendChild(a)}}}function S0(e,t,l){Rl.S(e,t,l);var a=rn;if(a&&e){var s=Da(a).hoistableStyles,i=dn(e);t=t||"default";var c=s.get(i);if(!c){var o={loading:0,preload:null};if(c=a.querySelector(Pn(i)))o.loading=5;else{e=_({rel:"stylesheet",href:e,"data-precedence":t},l),(l=It.get(i))&&Rc(e,l);var d=c=a.createElement("link");rt(d),vt(d,"link",e),d._p=new Promise(function(j,D){d.onload=j,d.onerror=D}),d.addEventListener("load",function(){o.loading|=1}),d.addEventListener("error",function(){o.loading|=2}),o.loading|=4,ri(c,t,a)}c={type:"stylesheet",instance:c,count:1,state:o},s.set(i,c)}}}function N0(e,t){Rl.X(e,t);var l=rn;if(l&&e){var a=Da(l).hoistableScripts,s=fn(e),i=a.get(s);i||(i=l.querySelector(es(s)),i||(e=_({src:e,async:!0},t),(t=It.get(s))&&wc(e,t),i=l.createElement("script"),rt(i),vt(i,"link",e),l.head.appendChild(i)),i={type:"script",instance:i,count:1,state:null},a.set(s,i))}}function A0(e,t){Rl.M(e,t);var l=rn;if(l&&e){var a=Da(l).hoistableScripts,s=fn(e),i=a.get(s);i||(i=l.querySelector(es(s)),i||(e=_({src:e,async:!0,type:"module"},t),(t=It.get(s))&&wc(e,t),i=l.createElement("script"),rt(i),vt(i,"link",e),l.head.appendChild(i)),i={type:"script",instance:i,count:1,state:null},a.set(s,i))}}function Hf(e,t,l,a){var s=(s=Ne.current)?oi(s):null;if(!s)throw Error(r(446));switch(e){case"meta":case"title":return null;case"style":return typeof l.precedence=="string"&&typeof l.href=="string"?(t=dn(l.href),l=Da(s).hoistableStyles,a=l.get(t),a||(a={type:"style",instance:null,count:0,state:null},l.set(t,a)),a):{type:"void",instance:null,count:0,state:null};case"link":if(l.rel==="stylesheet"&&typeof l.href=="string"&&typeof l.precedence=="string"){e=dn(l.href);var i=Da(s).hoistableStyles,c=i.get(e);if(c||(s=s.ownerDocument||s,c={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},i.set(e,c),(i=s.querySelector(Pn(e)))&&!i._p&&(c.instance=i,c.state.loading=5),It.has(e)||(l={rel:"preload",as:"style",href:l.href,crossOrigin:l.crossOrigin,integrity:l.integrity,media:l.media,hrefLang:l.hrefLang,referrerPolicy:l.referrerPolicy},It.set(e,l),i||C0(s,e,l,c.state))),t&&a===null)throw Error(r(528,""));return c}if(t&&a!==null)throw Error(r(529,""));return null;case"script":return t=l.async,l=l.src,typeof l=="string"&&t&&typeof t!="function"&&typeof t!="symbol"?(t=fn(l),l=Da(s).hoistableScripts,a=l.get(t),a||(a={type:"script",instance:null,count:0,state:null},l.set(t,a)),a):{type:"void",instance:null,count:0,state:null};default:throw Error(r(444,e))}}function dn(e){return'href="'+Xt(e)+'"'}function Pn(e){return'link[rel="stylesheet"]['+e+"]"}function Bf(e){return _({},e,{"data-precedence":e.precedence,precedence:null})}function C0(e,t,l,a){e.querySelector('link[rel="preload"][as="style"]['+t+"]")?a.loading=1:(t=e.createElement("link"),a.preload=t,t.addEventListener("load",function(){return a.loading|=1}),t.addEventListener("error",function(){return a.loading|=2}),vt(t,"link",l),rt(t),e.head.appendChild(t))}function fn(e){return'[src="'+Xt(e)+'"]'}function es(e){return"script[async]"+e}function qf(e,t,l){if(t.count++,t.instance===null)switch(t.type){case"style":var a=e.querySelector('style[data-href~="'+Xt(l.href)+'"]');if(a)return t.instance=a,rt(a),a;var s=_({},l,{"data-href":l.href,"data-precedence":l.precedence,href:null,precedence:null});return a=(e.ownerDocument||e).createElement("style"),rt(a),vt(a,"style",s),ri(a,l.precedence,e),t.instance=a;case"stylesheet":s=dn(l.href);var i=e.querySelector(Pn(s));if(i)return t.state.loading|=4,t.instance=i,rt(i),i;a=Bf(l),(s=It.get(s))&&Rc(a,s),i=(e.ownerDocument||e).createElement("link"),rt(i);var c=i;return c._p=new Promise(function(o,d){c.onload=o,c.onerror=d}),vt(i,"link",a),t.state.loading|=4,ri(i,l.precedence,e),t.instance=i;case"script":return i=fn(l.src),(s=e.querySelector(es(i)))?(t.instance=s,rt(s),s):(a=l,(s=It.get(i))&&(a=_({},l),wc(a,s)),e=e.ownerDocument||e,s=e.createElement("script"),rt(s),vt(s,"link",a),e.head.appendChild(s),t.instance=s);case"void":return null;default:throw Error(r(443,t.type))}else t.type==="stylesheet"&&(t.state.loading&4)===0&&(a=t.instance,t.state.loading|=4,ri(a,l.precedence,e));return t.instance}function ri(e,t,l){for(var a=l.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),s=a.length?a[a.length-1]:null,i=s,c=0;c title"):null)}function T0(e,t,l){if(l===1||t.itemProp!=null)return!1;switch(e){case"meta":case"title":return!0;case"style":if(typeof t.precedence!="string"||typeof t.href!="string"||t.href==="")break;return!0;case"link":if(typeof t.rel!="string"||typeof t.href!="string"||t.href===""||t.onLoad||t.onError)break;return t.rel==="stylesheet"?(e=t.disabled,typeof t.precedence=="string"&&e==null):!0;case"script":if(t.async&&typeof t.async!="function"&&typeof t.async!="symbol"&&!t.onLoad&&!t.onError&&t.src&&typeof t.src=="string")return!0}return!1}function Yf(e){return!(e.type==="stylesheet"&&(e.state.loading&3)===0)}function E0(e,t,l,a){if(l.type==="stylesheet"&&(typeof a.media!="string"||matchMedia(a.media).matches!==!1)&&(l.state.loading&4)===0){if(l.instance===null){var s=dn(a.href),i=t.querySelector(Pn(s));if(i){t=i._p,t!==null&&typeof t=="object"&&typeof t.then=="function"&&(e.count++,e=fi.bind(e),t.then(e,e)),l.state.loading|=4,l.instance=i,rt(i);return}i=t.ownerDocument||t,a=Bf(a),(s=It.get(s))&&Rc(a,s),i=i.createElement("link"),rt(i);var c=i;c._p=new Promise(function(o,d){c.onload=o,c.onerror=d}),vt(i,"link",a),l.instance=i}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(l,t),(t=l.state.preload)&&(l.state.loading&3)===0&&(e.count++,l=fi.bind(e),t.addEventListener("load",l),t.addEventListener("error",l))}}var Hc=0;function M0(e,t){return e.stylesheets&&e.count===0&&hi(e,e.stylesheets),0Hc?50:800)+t);return e.unsuspend=l,function(){e.unsuspend=null,clearTimeout(a),clearTimeout(s)}}:null}function fi(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)hi(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var mi=null;function hi(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,mi=new Map,t.forEach(z0,e),mi=null,fi.call(e))}function z0(e,t){if(!(t.state.loading&4)){var l=mi.get(e);if(l)var a=l.get(null);else{l=new Map,mi.set(e,l);for(var s=e.querySelectorAll("link[data-precedence],style[data-precedence]"),i=0;i"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(u)}catch(f){console.error(f)}}return u(),Kc.exports=V0(),Kc.exports}var $0=J0();function je(u){return Array.isArray(u)?u:[]}function ym(u){const f=new Set;return u.map(p=>p.trim()).filter(p=>{const r=p.toLowerCase();return!p||f.has(r)?!1:(f.add(r),!0)})}function Pt(u){const f=Ni.some(p=>p.value===u.streamMode)?u.streamMode:"auto";return{...u,streamMode:f,models:je(u.models),allowedGroupIds:je(u.allowedGroupIds),openaiAccounts:je(u.openaiAccounts),kiroAccounts:je(u.kiroAccounts)}}function us(u){return{...u,aliases:je(u.aliases)}}function W0(u){return{...u,apiKeys:je(u.apiKeys),logs:je(u.logs)}}class Ci extends Error{status;payload;constructor(f,p,r){super(p),this.status=f,this.payload=r}}const F0={home:"M3 10.5 12 3l9 7.5V21a1 1 0 0 1-1 1h-5v-7H9v7H4a1 1 0 0 1-1-1z",users:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8M22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75",key:"M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.78 7.78 5.5 5.5 0 0 1 7.78-7.78ZM14 8l7-7M21 8h-5V3",models:"M12 2 4 6v12l8 4 8-4V6zM4 6l8 4 8-4M12 10v12",image:"M21 19V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2ZM8.5 11a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5ZM21 16l-5-5L5 21",route:"M4 19a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM20 11a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM7 16h3a4 4 0 0 0 4-4V8h3",logs:"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8zM14 2v6h6M8 13h8M8 17h6",orbit:"M12 7a5 5 0 1 0 0 10 5 5 0 0 0 0-10ZM3 12a9 3 0 1 0 18 0 9 3 0 1 0-18 0Z",settings:"M12 15.5a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7ZM19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.6 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 8.92 4a1.65 1.65 0 0 0 1-1.51V2a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9c.14.31.39.57.71.71.23.1.49.18.8.2H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1Z",search:"M21 21l-4.35-4.35M10.5 18a7.5 7.5 0 1 1 0-15 7.5 7.5 0 0 1 0 15Z",copy:"M8 8h11a1 1 0 0 1 1 1v11a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1ZM4 16H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h11a1 1 0 0 1 1 1v1",ban:"M4.93 4.93 19.07 19.07M22 12A10 10 0 1 1 2 12a10 10 0 0 1 20 0Z",check:"M20 6 9 17l-5-5",moon:"M21 12.8A8.5 8.5 0 1 1 11.2 3 6.5 6.5 0 0 0 21 12.8Z",sun:"M12 4V2M12 22v-2M4.93 4.93 3.52 3.52M20.48 20.48l-1.41-1.41M4 12H2M22 12h-2M4.93 19.07l-1.41 1.41M20.48 3.52l-1.41 1.41M16 12a4 4 0 1 1-8 0 4 4 0 0 1 8 0Z",plus:"M12 5v14M5 12h14"};function zt({name:u}){return n.jsx("svg",{viewBox:"0 0 24 24","aria-hidden":"true",className:"icon",children:n.jsx("path",{d:F0[u]})})}async function pe(u,f){const p=new Headers(f?.headers);p.set("Content-Type","application/json");const r=window.sessionStorage.getItem("capi-admin-token");r&&p.set("Authorization",`Bearer ${r}`);const C=await fetch(u,{credentials:"include",...f,headers:p});if(!C.ok){const T=await C.json().catch(()=>null);throw new Ci(C.status,T?.error?.message||`Request failed: ${C.status}`,T)}return C.json()}async function I0(u,f){const p=new Headers,r=window.sessionStorage.getItem("capi-admin-token");r&&p.set("Authorization",`Bearer ${r}`);const C=await fetch(u,{credentials:"include",method:"POST",headers:p,body:f});if(!C.ok){const T=await C.json().catch(()=>null);throw new Ci(C.status,T?.error?.message||`Request failed: ${C.status}`,T)}return C.json()}const dm=[{id:"overview",label:"概览",icon:"home"},{id:"users",label:"用户",icon:"users"},{id:"groups",label:"分组",icon:"users"},{id:"keys",label:"密钥",icon:"key"},{id:"models",label:"模型",icon:"models"},{id:"drawing",label:"绘图",icon:"image"},{id:"antigravity",label:"Antigravity",icon:"orbit"},{id:"channels",label:"渠道",icon:"route"},{id:"logs",label:"日志",icon:"logs"},{id:"settings",label:"设置",icon:"settings"}],to=[{value:"kiro",label:"Kiro / Amazon Q"},{value:"codex",label:"Codex / ChatGPT OAuth"},{value:"antigravity",label:"Antigravity / Google"},{value:"cpa",label:"CPA / CLIProxyAPI"},{value:"openai",label:"OpenAI"},{value:"anthropic",label:"Anthropic / Claude"},{value:"google",label:"Google Gemini"},{value:"deepseek",label:"DeepSeek"},{value:"openrouter",label:"OpenRouter"},{value:"groq",label:"Groq"},{value:"siliconflow",label:"SiliconFlow"},{value:"moonshot",label:"Moonshot"},{value:"compatible",label:"OpenAI 兼容接口"}],gm="https://api.openai.com/v1",Ti="https://chatgpt.com/backend-api",bm="http://localhost:8317/v1",xm="https://codewhisperer.us-east-1.amazonaws.com",jm="gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, gpt-image-2, gpt-image-1",P0="gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, gpt-image-2",ep="gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, claude-sonnet-4, gemini-3.1-pro",tp="claude-sonnet-4.5, claude-sonnet-4, claude-haiku-4.5, claude-opus-4.5",Sm="https://daily-cloudcode-pa.googleapis.com",lp="claude-opus-4-6-thinking, claude-sonnet-4-6, gemini-3.8-flash-high, gemini-3.7-flash-high, gemini-3.6-flash-high, gemini-3-flash, gemini-pro-agent, gemini-3.1-pro-low, gpt-oss-120b-medium, gemini-3.1-flash-lite, gemini-3.5-flash-lite, gemini-3.1-flash-image",Fc=[{provider:"kiro",label:"Kiro / Amazon Q",name:"Kiro 账号池",baseUrl:xm,models:tp.split(",").map(u=>u.trim())},{provider:"openai",label:"OpenAI",name:"OpenAI 主线路",baseUrl:gm,models:P0.split(",").map(u=>u.trim())},{provider:"codex",label:"Codex 账号池",name:"Codex 账号池",baseUrl:Ti,models:jm.split(",").map(u=>u.trim())},{provider:"antigravity",label:"Antigravity 账号池",name:"Antigravity 账号池",baseUrl:Sm,models:lp.split(",").map(u=>u.trim())},{provider:"cpa",label:"CPA / CLIProxyAPI",name:"CPA 本地代理",baseUrl:bm,models:ep.split(",").map(u=>u.trim())},{provider:"compatible",label:"OpenAI 兼容接口",name:"兼容渠道",baseUrl:"",models:[]},{provider:"openrouter",label:"OpenRouter",name:"OpenRouter",baseUrl:"https://openrouter.ai/api/v1",models:[]},{provider:"google",label:"Google Gemini",name:"Gemini",baseUrl:"",models:[]},{provider:"anthropic",label:"Anthropic / Claude",name:"Claude",baseUrl:"",models:[]}];function Ta(u){return Fc.find(f=>f.provider===u)||Fc[2]}function Ic(u){const f=Ta(u);return{name:f.name,provider:f.provider,baseUrl:f.baseUrl,models:[...f.models],streamMode:"auto"}}function ap(u){const f=u?.trim().toLowerCase();return f&&({free:"Free",plus:"Plus",pro:"Pro",team:"Team",enterprise:"Enterprise"}[f]||u)||"套餐未知"}function fm(u){return u?{upstream_token_invalidated:"Token 已失效",upstream_invalid_api_key:"API Key 无效",upstream_account_error:"账号错误",upstream_accounts_unavailable:"账号池不可用",upstream_error:"上游错误"}[u]||u:""}function Ei(u){return u==="openai"?gm:u==="codex"?Ti:u==="antigravity"?Sm:u==="cpa"||u==="cliproxyapi"?bm:u==="kiro"?xm:""}function Pc(u){return ym(u.split(/[\s,;,;]+/))}function np(u){return ym(u.split(/[\n,;,;]+/).map(f=>f.trim()))}function Nm(u){const f=np(u);return f.length===0?{}:f.length===1?{upstreamApiKey:f[0]}:{upstreamApiKeys:f}}const Ni=[{value:"auto",label:"自动",description:"按请求参数处理"},{value:"real",label:"真流",description:"直连上游 SSE"},{value:"fake",label:"假流",description:"非流转 SSE"},{value:"disabled",label:"禁用流",description:"流式请求跳过"}];function tl(u){if(!u)return"未使用";const f=new Date(u);return Number.isNaN(f.getTime())?"-":new Intl.DateTimeFormat("zh-CN",{month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"}).format(f)}function mm(u){if(!u)return"";const f=new Date(u);if(Number.isNaN(f.getTime()))return"";const p=f.getTimezoneOffset()*6e4;return new Date(f.getTime()-p).toISOString().slice(0,16)}function sp(u){if(!u)return"";const f=new Date(u);return Number.isNaN(f.getTime())?"":f.toISOString()}function ip(u){if(!u)return"-";const f=new Date(u);return Number.isNaN(f.getTime())?"-":new Intl.DateTimeFormat("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"}).format(f)}function Ot(u){return{active:"正常",disabled:"禁用",limited:"受限",overdue:"欠费",healthy:"正常",standby:"备用",available:"Available",success:"成功",failed:"失败"}[u]||u}function xt(u,f=2){const p=Number(u||0);return new Intl.NumberFormat("zh-CN",{minimumFractionDigits:f,maximumFractionDigits:f}).format(p)}function pl(u){return new Intl.NumberFormat("zh-CN").format(Math.max(0,Math.round(Number(u||0))))}function lo(u){return u.model?u.model:u.errorCode==="invalid_api_key"?"密钥无效":u.errorCode==="model_not_available"?"模型不可用":u.errorCode==="insufficient_quota"?"额度不足":u.errorCode==="rate_limit_exceeded"?"请求过快":u.errorCode||"请求失败"}function up(u){return u.model||(u.errorCode?`错误:${u.errorCode}`:"-")}function cp(u){return u.channel||(u.apiKeyPrefix?`Key ${u.apiKeyPrefix}`:"-")}function op(u){const f=je(u);if(f.length===0)return"未绑定模型";const p=f.slice(0,2).join(", ");return f.length>2?`${p} · 其余 ${f.length-2} 个`:p}function cl(u){return u==="cliproxyapi"||u==="cli-proxy-api"?"CPA / CLIProxyAPI":to.find(f=>f.value===u)?.label||u||"Custom"}function $c(u){const f=`${u.vendor} ${u.id} ${u.name}`.toLowerCase();return f.includes("cliproxyapi")||/\bcpa\b/.test(f)?"cpa":f.includes("openai")||/\bgpt[-_/]/.test(f)||f.includes("o1-")||f.includes("o3-")?"openai":f.includes("anthropic")||f.includes("claude")?"anthropic":f.includes("google")||f.includes("gemini")||f.includes("gcli-")?"google":f.includes("deepseek")?"deepseek":f.includes("openrouter")?"openrouter":f.includes("groq")?"groq":f.includes("siliconflow")?"siliconflow":f.includes("moonshot")||f.includes("kimi")?"moonshot":u.vendor&&u.vendor.toLowerCase()!=="custom"?u.vendor.toLowerCase():"compatible"}function hm({provider:u}){if(u==="deepseek")return n.jsx("span",{className:"provider-icon provider-icon-deepseek","aria-hidden":"true",children:n.jsxs("svg",{viewBox:"0 0 32 32",role:"img",children:[n.jsx("rect",{x:"1",y:"1",width:"30",height:"30",rx:"8"}),n.jsx("path",{transform:"translate(2.4 4.4)",d:"M26.517 3.395c-.282-.138-.403.125-.568.258-.057.044-.105.1-.152.152-.413.44-.895.73-1.524.695-.92-.052-1.705.237-2.4.941-.147-.868-.638-1.386-1.384-1.718-.39-.173-.786-.346-1.06-.721-.19-.268-.243-.566-.338-.86-.061-.176-.121-.357-.325-.388-.222-.034-.309.151-.396.307-.347.635-.481 1.334-.468 2.042.03 1.594.703 2.863 2.04 3.765.152.104.191.207.143.359-.091.31-.2.613-.295.924-.06.198-.151.242-.364.155-.734-.306-1.367-.76-1.927-1.308-.951-.92-1.81-1.934-2.882-2.729-.252-.185-.504-.358-.764-.522-1.094-1.062.143-1.935.43-2.038.3-.108.104-.48-.864-.475-.968.004-1.853.328-2.982.76-.165.065-.339.112-.516.151-1.024-.194-2.088-.237-3.199-.112-2.092.233-3.763 1.222-4.991 2.91C.254 7.972-.093 10.278.332 12.682c.446 2.535 1.74 4.633 3.728 6.274 2.062 1.7 4.436 2.534 7.145 2.375 1.645-.095 3.476-.316 5.542-2.064.521.259 1.068.363 1.975.44.699.065 1.371-.034 1.892-.142.816-.173.76-.929.465-1.067-2.392-1.114-1.866-.661-2.344-1.027 1.215-1.438 3.071-3.993 3.644-7.473.056-.384.128-.925.12-1.236-.005-.19.038-.263.255-.285.6-.069 1.18-.233 1.715-.527 1.55-.846 2.175-2.237 2.322-3.903.022-.255-.005-.518-.274-.652ZM13.014 18.395c-2.318-1.823-3.442-2.423-3.906-2.397-.434.026-.356.523-.26.847.1.32.23.54.412.82.126.186.213.462-.126.67-.746.461-2.044-.156-2.105-.186-1.51-.89-2.773-2.064-3.664-3.67-.86-1.545-1.358-3.204-1.44-4.974-.022-.427.104-.578.529-.656.56-.103 1.137-.125 1.697-.043 2.366.346 4.379 1.403 6.068 3.079.963.954 1.692 2.094 2.443 3.208.799 1.183 1.658 2.31 2.752 3.234.387.324.695.57.99.751-.89.1-2.374.121-3.39-.683Zm1.111-7.146c0-.19.152-.341.343-.341.043 0 .082.009.117.021.048.018.092.044.126.083.061.06.096.146.096.237a.341.341 0 0 1-.343.341.34.34 0 0 1-.339-.341Zm3.451 1.77c-.222.09-.443.168-.656.177-.33.017-.69-.117-.885-.281-.304-.255-.521-.397-.612-.842-.039-.19-.017-.483.017-.652.078-.362-.009-.595-.265-.807-.208-.172-.473-.22-.764-.22-.108 0-.208-.048-.282-.086-.121-.061-.221-.212-.126-.398.031-.06.178-.207.213-.233.395-.225.85-.151 1.272.018.39.16.686.453 1.111.867.434.501.512.639.759 1.015.196.294.373.596.495.942.073.215-.022.392-.277.5Z"})]})});if(u==="openai")return n.jsx("span",{className:"provider-icon provider-icon-openai","aria-hidden":"true",children:n.jsxs("svg",{viewBox:"0 0 32 32",role:"img",children:[n.jsx("rect",{x:"1",y:"1",width:"30",height:"30",rx:"8"}),n.jsx("g",{transform:"translate(7 7.5) scale(0.065)",fill:"currentColor",stroke:"none",children:n.jsx("path",{d:"M267.06 111.34a71.78 71.78 0 0 0-6.17-58.91c-14.5-25.15-43.55-38.09-71.9-32.03A71.78 71.78 0 0 0 135.1.5C106 .43 80.21 19.16 71.29 46.85a71.79 71.79 0 0 0-47.98 34.8c-14.6 25.1-11.28 56.75 8.22 78.3a71.78 71.78 0 0 0 6.16 58.9c14.5 25.16 43.56 38.1 71.91 32.04a71.76 71.76 0 0 0 53.89 24.02c29.12.02 54.92-18.72 63.84-46.44a71.79 71.79 0 0 0 47.98-34.8c14.58-25.1 11.25-56.72-8.24-78.27zm-107.9 150.77a53.15 53.15 0 0 1-34.15-12.35c.43-.24 1.2-.66 1.7-.96l56.68-32.73a9.22 9.22 0 0 0 4.66-8.06v-79.9l23.95 13.83a.85.85 0 0 1 .47.66v66.16a53.42 53.42 0 0 1-53.3 53.35zM44.6 213.16a53.13 53.13 0 0 1-6.36-35.75c.42.25 1.15.7 1.68 1l56.68 32.73a9.24 9.24 0 0 0 9.31 0l69.2-39.95v27.66a.87.87 0 0 1-.34.74l-57.29 33.07a53.42 53.42 0 0 1-72.88-19.5zM29.7 90.05a53.1 53.1 0 0 1 27.76-23.36c0 .49-.03 1.36-.03 1.96v65.46a9.22 9.22 0 0 0 4.65 8.05l69.2 39.95-23.95 13.83a.86.86 0 0 1-.81.07L49.2 162.9A53.42 53.42 0 0 1 29.7 90.05zm196.8 45.8L157.3 95.9l23.95-13.82a.86.86 0 0 1 .81-.07l57.3 33.08a53.37 53.37 0 0 1-8.24 96.29v-65.46a9.2 9.2 0 0 0-4.62-8.06zm23.84-35.89c-.42-.26-1.15-.7-1.68-1.01l-56.68-32.73a9.25 9.25 0 0 0-9.31 0l-69.2 39.95V78.5a.87.87 0 0 1 .35-.74l57.28-33.05a53.35 53.35 0 0 1 79.24 55.25zM100.11 149.24l-23.96-13.83a.85.85 0 0 1-.46-.66V68.6a53.37 53.37 0 0 1 87.52-40.95c-.42.24-1.19.66-1.7.96l-56.68 32.73a9.22 9.22 0 0 0-4.66 8.06l-.04 79.85zm13.01-28.05L144 103.3l30.88 17.83v35.68L144 174.63l-30.88-17.82v-35.62z"})})]})});const f=u==="codex"?"C":u==="antigravity"?"G":u==="cpa"||u==="cliproxyapi"?"CPA":u==="anthropic"?"A":u==="google"?"✦":u==="openrouter"?"↗":u==="groq"?"G":u==="siliconflow"?"S":u==="moonshot"?"M":"◇";return n.jsx("span",{className:`provider-icon provider-icon-${u}`,"aria-hidden":"true",children:n.jsxs("svg",{viewBox:"0 0 32 32",role:"img",children:[n.jsx("rect",{x:"1",y:"1",width:"30",height:"30",rx:"8"}),n.jsx("text",{x:"16",y:"21",textAnchor:"middle",children:f})]})})}async function Ai(u){if(navigator.clipboard?.writeText){await navigator.clipboard.writeText(u);return}const f=document.createElement("textarea");f.value=u,f.setAttribute("readonly","true"),f.style.position="fixed",f.style.opacity="0",document.body.appendChild(f),f.select(),document.execCommand("copy"),document.body.removeChild(f)}function wl(){return window.location.origin}function rp(){return`${wl()}/api/auth/discord/callback`}function dp(){return`${wl()}/`}function Wc(u){return{...u,redirectUri:u.redirectUri&&!u.redirectUri.includes("localhost")?u.redirectUri:rp(),authSuccessUrl:u.authSuccessUrl&&!u.authSuccessUrl.includes("localhost")?u.authSuccessUrl:dp(),blockedGuildIds:je(u.blockedGuildIds),sessionTtlHours:u.sessionTtlHours||168}}function Mi(u){return u==="email"||u==="discord"?u:"username"}function fp(u){const p=(u.split("@")[0]||"user").toLowerCase().replace(/[^a-z0-9_-]+/g,"-").replace(/^[-_]+|[-_]+$/g,"");return(p.length>=3?p:"user").slice(0,24)}function mp(){const[u,f]=b.useState("home"),[p,r]=b.useState("login"),[C,T]=b.useState(null),[k,W]=b.useState("overview"),[N,y]=b.useState(()=>{const R=window.localStorage.getItem("capi-theme");return R==="light"||R==="dark"?R:window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}),[G,_]=b.useState("comfortable"),[V,P]=b.useState(null),[fe,ee]=b.useState([]),[me,ne]=b.useState([]),[se,Y]=b.useState([]),[xe,te]=b.useState([]),[ye,O]=b.useState([]),[ae,ve]=b.useState(""),[Ce,Me]=b.useState(""),[ue,Z]=b.useState(null),[de,$]=b.useState(""),[A,L]=b.useState(""),[H,X]=b.useState(!1),ie=b.useMemo(()=>{const R=ae.trim().toLowerCase();return R?fe.filter(K=>`${K.id} ${K.name} ${K.email}`.toLowerCase().includes(R)):fe},[ae,fe]);async function m(){const R=new Date().getTimezoneOffset(),[K,J,F,he,$e,Ut]=await Promise.all([pe(`/api/overview?timezoneOffset=${R}`),pe("/api/users"),pe("/api/channels"),pe("/api/models"),pe("/api/logs"),pe("/api/groups")]),Rt=je(J.users),nl=je(F.channels).map(Pt),rl=je(he.models).map(us),Ma=je($e.logs),vl=je(Ut.groups);P(K),ee(Rt),ne(nl),Y(vl),te(rl),O(Ma),Me(Hl=>Hl&&Rt.some(ca=>ca.id===Hl)?Hl:Rt[0]?.id||""),Rt.length===0&&Z(null),X(!0)}async function h(R){const K=await pe(`/api/users/${R}`);Z(W0(K))}async function M(R,K){const J=await pe(`/api/users/${R}`,{method:"PATCH",body:JSON.stringify(K)});ee(F=>F.map(he=>he.id===R?J.user:he)),Z(F=>F?.user.id===R?{...F,user:J.user}:F),$("已更新用户"),window.setTimeout(()=>$(""),1800)}async function Q(R,K,J={}){const F=await pe("/api/users/bulk",{method:"POST",body:JSON.stringify({userIds:R,action:K,...J})}),he=new Map(je(F.users).map($e=>[$e.id,$e]));ee($e=>$e.map(Ut=>he.get(Ut.id)||Ut)),Z($e=>{if(!$e)return $e;const Ut=he.get($e.user.id);return Ut?{...$e,user:Ut}:$e}),$(`已处理 ${F.updated} 个用户`),window.setTimeout(()=>$(""),1800)}async function le(R){const K=await pe(`/api/users/${R}/api-keys`,{method:"POST",body:JSON.stringify({name:"Console Key"})});ue?.user.id===R&&Z({...ue,apiKeys:[...ue.apiKeys,K.apiKey]}),L(K.secret),await Ai(K.secret),$("新 Key 已创建并复制,请立即保存"),window.setTimeout(()=>$(""),2400)}async function Ne(R){window.confirm("删除这个 Key?删除后使用它的请求会立即失效。")&&(await pe(`/api/api-keys/${R}`,{method:"DELETE"}),Z(K=>K&&{...K,apiKeys:K.apiKeys.filter(J=>J.id!==R)}),$("Key 已删除"),window.setTimeout(()=>$(""),1800))}async function z(R,K){const J=await pe(`/api/api-keys/${R}`,{method:"PATCH",body:JSON.stringify(K)});Z(F=>F&&{...F,apiKeys:F.apiKeys.map(he=>he.id===R?J.apiKey:he)}),$("Key 已更新"),window.setTimeout(()=>$(""),1800)}async function be(R,K){const J=await pe(`/api/channels/${R}`,{method:"PATCH",body:JSON.stringify(K)});ne(F=>F.map(he=>he.id===R?Pt(J.channel):he)),Je(J.removedModels),$("渠道已更新"),window.setTimeout(()=>$(""),1800)}async function ce(R){const K=me.find(F=>F.id===R);if(!window.confirm(`删除渠道「${K?.name||R}」?`))return;const J=await pe(`/api/channels/${R}`,{method:"DELETE"});ne(F=>F.filter(he=>he.id!==R)),Je(J.removedModels),$("渠道已删除"),window.setTimeout(()=>$(""),1800)}async function jt(R){const K=await pe("/api/groups",{method:"POST",body:JSON.stringify(R)});Y(J=>[...J,K.group]),$("分组已创建"),window.setTimeout(()=>$(""),1800)}async function I(R,K){const J=await pe(`/api/groups/${R}`,{method:"PATCH",body:JSON.stringify(K)});Y(F=>F.map(he=>he.id===R?J.group:he)),$("分组已更新"),window.setTimeout(()=>$(""),1800)}async function Ve(R){const K=se.find(J=>J.id===R);window.confirm(`删除分组「${K?.name||R}」?删除后渠道的可见范围会移除该分组。`)&&(await pe(`/api/groups/${R}`,{method:"DELETE"}),Y(J=>J.filter(F=>F.id!==R)),ne(J=>J.map(F=>({...F,allowedGroupIds:F.allowedGroupIds.filter(he=>he!==R)}))),$("分组已删除"),window.setTimeout(()=>$(""),1800))}async function ot(R,K){const J=je(K).map(Rt=>Rt.trim()).filter(Boolean),F=await pe(`/api/channels/${R}/sync-models`,{method:"POST",body:JSON.stringify(J.length?{models:J}:{})}),he=Pt(F.channel),$e=je(F.addedModels).map(us),Ut=je(F.models);ne(Rt=>Rt.map(nl=>nl.id===R?he:nl)),$e.length>0&&te(Rt=>{const nl=new Set(Rt.map(rl=>rl.id.toLowerCase()));return[...Rt,...$e.filter(rl=>!nl.has(rl.id.toLowerCase()))]}),Je(F.removedModels),$(J.length?`已保存 ${Ut.length} 个模型`:Ut.length?`已拉取 ${Ut.length} 个模型`:"上游没有返回模型"),window.setTimeout(()=>$(""),2200)}function Je(R){const K=new Set(je(R).map(J=>J.toLowerCase()));K.size!==0&&(te(J=>J.filter(F=>!K.has(F.id.toLowerCase()))),Z(J=>J&&{...J,apiKeys:J.apiKeys.map(F=>({...F,allowedModels:F.allowedModels.filter(he=>!K.has(he.toLowerCase()))}))}))}async function gt(R){try{const K=await pe(`/api/channels/${R}/check`,{method:"POST",body:JSON.stringify({})});ne(J=>J.map(F=>F.id===R?Pt(K.channel):F)),$(K.ok?`渠道可用,检测到 ${je(K.models).length} 个模型`:"渠道检测失败")}catch(K){const J=K instanceof Ci?K.payload?.channel:null;J&&ne(F=>F.map(he=>he.id===R?Pt(J):he)),$(K instanceof Error?K.message:"渠道检测失败")}window.setTimeout(()=>$(""),2400)}async function Dt(R=Ic("codex")){const K=await pe("/api/channels",{method:"POST",body:JSON.stringify(R)});ne(J=>[...J,Pt(K.channel)]),$("渠道已创建,可继续拉取模型或检测渠道"),window.setTimeout(()=>$(""),2400)}async function ll(R,K){const J=new FormData;J.append("file",K);const F=await I0(`/api/channels/${encodeURIComponent(R)}/import-openai-accounts`,J);ne(he=>he.map($e=>$e.id===F.channel.id?Pt(F.channel):$e)),$(`新增 ${F.created??F.imported} 个账号${F.updated?`,更新 ${F.updated} 个已有账号`:""}${F.skipped?`,跳过 ${F.skipped} 个`:""}`),window.setTimeout(()=>$(""),2600)}async function al(R,K=!1,J=""){const F=await pe(`/api/channels/${encodeURIComponent(R)}/openai-accounts/check`,{method:"POST",body:JSON.stringify({onlyInvalid:K,accountId:J})});ne(he=>he.map($e=>$e.id===F.channel.id?Pt(F.channel):$e)),$(`${K?"无效账号复检":"账号测活"}完成:${F.healthy}/${F.checked} 可用${F.failed?`,无效 ${F.failed}`:""}`),window.setTimeout(()=>$(""),3e3)}async function U(R){const K=await pe(`/api/channels/${encodeURIComponent(R)}/openai-accounts/deduplicate`,{method:"POST",body:JSON.stringify({})});ne(J=>J.map(F=>F.id===K.channel.id?Pt(K.channel):F)),$(K.removed?`已合并 ${K.removed} 个重复账号`:"未发现可识别的重复账号"),window.setTimeout(()=>$(""),2600)}async function B(R,K){const J=await pe(`/api/channels/${encodeURIComponent(R)}/openai-accounts/${encodeURIComponent(K)}`,{method:"DELETE"});ne(F=>F.map(he=>he.id===J.channel.id?Pt(J.channel):he)),$("账号已删除"),window.setTimeout(()=>$(""),1800)}async function Be(R){return pe(`/api/channels/${encodeURIComponent(R)}/openai-oauth/start`,{method:"POST",body:JSON.stringify({})})}async function We(R,K){const J=await pe(`/api/channels/${encodeURIComponent(R)}/openai-oauth/complete`,{method:"POST",body:JSON.stringify(K)});return ne(F=>F.map(he=>he.id===J.channel.id?Pt(J.channel):he)),$("已通过 OAuth 添加账号"),window.setTimeout(()=>$(""),2400),J}async function at(R){return pe(`/api/channels/${encodeURIComponent(R)}/antigravity-oauth/start`,{method:"POST",body:JSON.stringify({})})}async function Pe(R,K){const J=await pe(`/api/channels/${encodeURIComponent(R)}/antigravity-oauth/complete`,{method:"POST",body:JSON.stringify(K)});return ne(F=>F.map(he=>he.id===J.channel.id?Pt(J.channel):he)),$("已通过 Google 授权添加账号"),window.setTimeout(()=>$(""),2400),J}async function zi(R){const K=await pe("/api/models",{method:"POST",body:JSON.stringify(R)});te(J=>[...J,us(K.model)]),$("模型已添加"),window.setTimeout(()=>$(""),1800)}async function cs(R,K){const J=await pe(`/api/models/${encodeURIComponent(R)}`,{method:"PATCH",body:JSON.stringify(K)});te(F=>F.map(he=>he.id===R?us(J.model):he)),$("模型已更新"),window.setTimeout(()=>$(""),1600)}async function os(R){window.confirm(`删除模型 ${R}?渠道和 Key 中的引用也会一起清理。`)&&(await pe(`/api/models/${encodeURIComponent(R)}`,{method:"DELETE"}),te(K=>K.filter(J=>J.id!==R)),ne(K=>K.map(J=>({...J,models:J.models.filter(F=>F!==R)}))),Z(K=>K&&{...K,apiKeys:K.apiKeys.map(J=>({...J,allowedModels:J.allowedModels.filter(F=>F!==R)}))}),$("模型已删除"),window.setTimeout(()=>$(""),1800))}async function ua(R,K="已复制"){await Ai(R),$(K),window.setTimeout(()=>$(""),1600)}function Ea(R,K){if(R instanceof Ci&&R.status===401){X(!1),r("login"),f("auth");return}$(K)}async function hn(){try{const R=await pe("/api/auth/status");if(T(R),!R.initialized){r("setup"),f("auth");return}if(!R.authenticated){r("login"),f("auth");return}f(R.session?.role==="admin"?"console":"account")}catch(R){Ea(R,"认证状态加载失败")}}async function Oi(){await pe("/api/auth/logout",{method:"POST"}),window.sessionStorage.removeItem("capi-admin-token"),T(null),f("home")}return b.useEffect(()=>{let R=!1;return pe("/api/auth/status").then(K=>{R||(T(K),K.authenticated&&K.session&&f(K.session.role==="admin"?"console":"account"))}).catch(()=>{}),()=>{R=!0}},[]),b.useEffect(()=>{u==="console"&&(X(!1),m().catch(R=>Ea(R,"加载数据失败")))},[u]),b.useEffect(()=>{u!=="console"||!H||h(Ce).catch(R=>Ea(R,"加载用户详情失败"))},[Ce,u,H]),b.useEffect(()=>{window.localStorage.setItem("capi-theme",N)},[N]),b.useEffect(()=>{window.scrollTo({top:0,left:0})},[u,k]),u==="home"?n.jsx(xp,{theme:N,setTheme:y,enterConsole:hn}):u==="auth"?n.jsx(hp,{theme:N,mode:p,status:C,setTheme:y,setMode:r,goHome:()=>f("home"),onAuthenticated:R=>{T(K=>K?{...K,authenticated:!0,initialized:!0,session:R}:null),f(R.role==="admin"?"console":"account")}}):u==="account"?n.jsx(bp,{theme:N,setTheme:y,goHome:()=>f("home"),openLogin:hn}):n.jsxs("div",{className:"app-shell","data-theme":N,"data-density":G,children:[n.jsxs("aside",{className:"sidebar",children:[n.jsxs("div",{className:"ios-window-dots","aria-hidden":"true",children:[n.jsx("span",{}),n.jsx("span",{}),n.jsx("span",{})]}),n.jsxs("div",{className:"brand",children:[n.jsx("div",{className:"brand-mark",children:"C"}),n.jsxs("div",{children:[n.jsx("strong",{children:"CAPI"}),n.jsx("span",{children:"聚合网关"})]})]}),n.jsx("nav",{children:dm.map(R=>n.jsxs("button",{className:k===R.id?"nav-item active":"nav-item",onClick:()=>W(R.id),children:[n.jsx(zt,{name:R.icon}),n.jsx("span",{className:"nav-label",children:R.label})]},R.id))}),n.jsxs("div",{className:"sidebar-footer",children:[n.jsx("span",{children:"Gateway"}),n.jsxs("strong",{children:[n.jsx("span",{className:"pulse-dot"}),"Online"]})]})]}),n.jsxs("main",{className:"content",children:[n.jsxs("header",{className:"topbar",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"Admin Console"}),n.jsx("h1",{children:dm.find(R=>R.id===k)?.label})]}),n.jsxs("div",{className:"topbar-actions",children:[n.jsx(Vp,{value:G,options:[{value:"comfortable",label:"舒适"},{value:"compact",label:"紧凑"}],onChange:R=>_(R)}),n.jsxs("button",{className:"theme-toggle","aria-label":"切换暗色模式",onClick:()=>y(N==="dark"?"light":"dark"),children:[n.jsx(zt,{name:N==="dark"?"sun":"moon"}),n.jsx("span",{children:N==="dark"?"浅色":"暗色"})]}),n.jsx("button",{className:"primary-button",onClick:()=>m().catch(R=>Ea(R,"刷新失败")),children:"刷新"}),n.jsx("button",{className:"secondary-button home-link",onClick:()=>f("home"),children:"首页"}),n.jsx("button",{className:"secondary-button",onClick:Oi,children:"退出"})]})]}),k==="overview"&&n.jsx(jp,{overview:V,channels:me,logs:ye,onNavigate:R=>{W(R),R==="channels"&&me.length===0&&$("渠道页可以创建第一个上游"),R==="logs"&&ye.length===0&&$("暂无异常日志"),window.setTimeout(()=>$(""),1800)}}),k==="users"&&n.jsx(Np,{users:ie,query:ae,selectedUser:ue,onQuery:ve,onSelect:Me,onUpdate:M,onBulkUpdate:Q,onCreateKey:le,groups:se,onOpenRegistration:()=>{W("settings"),$("在账号与注册里开放注册,用户即可自助创建账号"),window.setTimeout(()=>$(""),2400)}}),k==="groups"&&n.jsx(Kp,{groups:se,onCreate:jt,onUpdate:I,onDelete:Ve}),k==="keys"&&n.jsx(Ap,{selectedUser:ue,onCreateKey:le,onUpdateKey:z,onDeleteKey:Ne}),k==="models"&&n.jsx(Tp,{models:xe,onCopy:ua,onCreate:zi,onUpdate:cs,onDelete:os}),k==="drawing"&&n.jsx(vm,{variant:"drawing",channels:me,onCreate:Dt,onImport:ll,onCheckAccounts:al,onDeduplicateAccounts:U,onDeleteAccount:B,onUpdate:be,onStartOAuth:Be,onCompleteOAuth:We}),k==="antigravity"&&n.jsx(vm,{variant:"antigravity",channels:me,onCreate:Dt,onImport:ll,onCheckAccounts:al,onDeduplicateAccounts:U,onDeleteAccount:B,onUpdate:be,onStartOAuth:at,onCompleteOAuth:Pe}),k==="channels"&&n.jsx(kp,{channels:me,groups:se,onUpdate:be,onCreate:Dt,onImport:ll,onDelete:ce,onSyncModels:ot,onCheck:gt}),k==="logs"&&n.jsx(Lp,{logs:ye,onCopy:ua}),k==="settings"&&n.jsx(Xp,{models:xe,channels:me,groups:se})]}),A&&n.jsx("div",{className:"secret-dialog-backdrop",role:"presentation",children:n.jsxs("section",{className:"secret-dialog",role:"dialog","aria-modal":"true","aria-labelledby":"secret-dialog-title",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"One-time secret"}),n.jsx("h2",{id:"secret-dialog-title",children:"完整 API Key"})]}),n.jsx("p",{children:"完整密钥只显示这一次。列表中的星号内容只是识别前缀,不能用于 API 调用。"}),n.jsx("code",{children:A}),n.jsxs("div",{className:"secret-dialog-actions",children:[n.jsx("button",{className:"secondary-button",onClick:()=>{Ai(A),$("完整 Key 已复制"),window.setTimeout(()=>$(""),1800)},children:"复制"}),n.jsx("button",{className:"primary-button",onClick:()=>L(""),children:"完成"})]})]})}),de&&n.jsx("div",{className:"toast",children:de})]})}function hp({theme:u,mode:f,status:p,setTheme:r,setMode:C,goHome:T,onAuthenticated:k}){const[W,N]=b.useState(""),[y,G]=b.useState(""),[_,V]=b.useState(""),[P,fe]=b.useState(""),[ee,me]=b.useState(""),[ne,se]=b.useState(""),[Y,xe]=b.useState(!1),[te,ye]=b.useState("username"),[O,ae]=b.useState("0"),[ve,Ce]=b.useState(""),[Me,ue]=b.useState(!1),Z=f==="setup",de=f==="register",$=Mi(p?.registrationMode),A=de&&$==="email",L=de&&$==="discord";async function H(){if(!L){if((Z||de)&&ee!==ne){Ce("两次输入的密码不一致");return}ue(!0),Ce("");try{const X=Z?"/api/auth/setup":de?"/api/auth/register":"/api/auth/login",ie=A?fp(_):W,m=f==="login"?{identifier:W,password:ee}:{username:ie,password:ee,displayName:y,email:_,discordUserId:Z?P:"",registrationEnabled:Z?Y:void 0,registrationMode:Z?te:void 0,defaultBalance:Z?Number(O||0):void 0},h=await pe(X,{method:"POST",body:JSON.stringify(m)});k(h.session)}catch(X){Ce(X instanceof Error?X.message:"操作失败")}finally{ue(!1)}}}return n.jsxs("main",{className:"auth-page","data-theme":u,children:[n.jsxs("header",{className:"auth-topbar",children:[n.jsxs("button",{className:"auth-brand",onClick:T,children:[n.jsx("span",{className:"brand-mark",children:"C"}),n.jsx("strong",{children:"CAPI"})]}),n.jsxs("button",{className:"theme-toggle","aria-label":"切换暗色模式",onClick:()=>r(u==="dark"?"light":"dark"),children:[n.jsx(zt,{name:u==="dark"?"sun":"moon"}),n.jsx("span",{children:u==="dark"?"浅色":"暗色"})]})]}),n.jsxs("section",{className:"auth-stage",children:[n.jsxs("div",{className:"auth-intro",children:[n.jsx("span",{children:Z?"First Run":"Welcome Back"}),n.jsx("h1",{children:Z?"初始化 CAPI":de?"创建账号":"登录"}),n.jsx("p",{children:Z?"创建第一个管理员账号,完成后即可进入控制台。":"使用你的 CAPI 账号继续。"})]}),n.jsxs("form",{className:"auth-form",onSubmit:X=>{X.preventDefault(),H()},children:[L?n.jsxs("div",{className:"auth-discord-register",children:[n.jsx("strong",{children:"使用 Discord 创建账号"}),n.jsx("span",{children:"继续后会按站点设置校验服务器和身份组。"}),p?.discordEnabled?n.jsx("a",{className:"discord-login-button",href:"/api/auth/discord/start",children:"继续使用 Discord"}):n.jsx("div",{className:"auth-message",children:"管理员还没有启用 Discord 登录"})]}):n.jsxs(n.Fragment,{children:[f!=="login"&&n.jsxs("label",{children:[n.jsx("span",{children:"显示名称"}),n.jsx("input",{value:y,onChange:X=>G(X.target.value),autoComplete:"name",placeholder:"CAPI"})]}),!A&&n.jsxs("label",{children:[n.jsx("span",{children:f==="login"?"账号或邮箱":"账号"}),n.jsx("input",{value:W,onChange:X=>N(X.target.value),autoComplete:"username",placeholder:f==="login"?"输入账号或邮箱":"3-32 位字母、数字、_ 或 -"})]}),(Z||A)&&n.jsxs("label",{children:[n.jsx("span",{children:A?"邮箱":"邮箱(可选)"}),n.jsx("input",{type:"email",value:_,onChange:X=>V(X.target.value),autoComplete:"email",placeholder:"name@example.com"})]}),Z&&n.jsxs(n.Fragment,{children:[n.jsxs("label",{children:[n.jsx("span",{children:"Discord 用户 ID(可选)"}),n.jsx("input",{inputMode:"numeric",autoComplete:"off",value:P,onChange:X=>fe(X.target.value),placeholder:"绑定管理员 Discord 账号"})]}),n.jsxs("div",{className:"setup-options",children:[n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"开放注册"}),n.jsx("button",{type:"button",className:Y?"ios-switch is-on":"ios-switch","aria-pressed":Y,onClick:()=>xe(X=>!X),children:n.jsx("span",{})})]}),n.jsxs("label",{children:[n.jsx("span",{children:"注册方式"}),n.jsxs("select",{value:te,onChange:X=>ye(Mi(X.target.value)),children:[n.jsx("option",{value:"username",children:"账号密码"}),n.jsx("option",{value:"email",children:"邮箱"}),n.jsx("option",{value:"discord",children:"Discord"})]})]}),n.jsxs("label",{children:[n.jsx("span",{children:"新用户初始额度"}),n.jsx("input",{type:"number",min:"0",step:"0.01",value:O,onChange:X=>ae(X.target.value)})]})]})]}),n.jsxs("label",{children:[n.jsx("span",{children:"密码"}),n.jsx("input",{type:"password",value:ee,onChange:X=>me(X.target.value),autoComplete:f==="login"?"current-password":"new-password",placeholder:"至少 8 个字符"})]}),f!=="login"&&n.jsxs("label",{children:[n.jsx("span",{children:"确认密码"}),n.jsx("input",{type:"password",value:ne,onChange:X=>se(X.target.value),autoComplete:"new-password",placeholder:"再次输入密码"})]}),n.jsx("div",{className:"auth-message",role:"status",children:ve}),n.jsx("button",{className:"primary-button auth-submit",type:"submit",disabled:Me,children:Me?"请稍候":Z?"创建管理员":de?"注册":"登录"})]}),!Z&&!L&&p?.discordEnabled&&n.jsx("a",{className:"discord-login-button",href:"/api/auth/discord/start",children:"使用 Discord 登录"}),!Z&&n.jsx("div",{className:"auth-switch",children:f==="login"&&p?.registrationEnabled?n.jsx("button",{type:"button",onClick:()=>C("register"),children:"创建账号"}):n.jsx("button",{type:"button",onClick:()=>C("login"),children:"返回登录"})})]})]})]})}const pp=[1,1.5,2,2.5,3,4,5,6,8,10];function vp(u){if(!(u>0))return 1;const f=Math.floor(Math.log10(u)),p=Math.pow(10,f),r=u/p;return(pp.find(T=>r<=T)??10)*p}const pm=88;function yp(u){const f=u.split("-");return f.length===3?`${f[1]}/${f[2]}`:u}function gp(){const[u,f]=b.useState(14),[p,r]=b.useState(null),[C,T]=b.useState(!0),[k,W]=b.useState(!1),[N,y]=b.useState("");b.useEffect(()=>{let Y=!1;return T(!0),pe(`/api/account/usage?days=${u}&timezoneOffset=${new Date().getTimezoneOffset()}`).then(xe=>{Y||(r({...xe.usage,daily:je(xe.usage?.daily),models:je(xe.usage?.models)}),W(!1))}).catch(()=>{Y||W(!0)}).finally(()=>{Y||T(!1)}),()=>{Y=!0}},[u]);const G=p?.daily??[],_=p?.models??[],V=vp(Math.max(0,...G.map(Y=>Y.cost))),P=Math.max(0,..._.map(Y=>Y.cost)),fe=G.reduce((Y,xe)=>!Y||xe.cost>Y.cost?xe:Y,null),ee=Math.max(1,Math.ceil(G.length/5)),me=G.find(Y=>Y.day===N)||null,ne=me?G.indexOf(me):-1,se=p?p.today.cost-p.yesterday.cost:0;return n.jsxs("section",{className:"account-section usage-section",children:[n.jsx("div",{className:"account-section-title",children:n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"Usage"}),n.jsx("h2",{children:"用量概览"})]})}),!p&&C&&n.jsx("p",{className:"usage-placeholder",children:"正在统计用量…"}),!p&&!C&&k&&n.jsx("p",{className:"usage-placeholder",children:"用量加载失败,请稍后重试"}),p&&n.jsxs("div",{className:C?"usage-body is-refreshing":"usage-body",children:[n.jsxs("div",{className:"usage-kpi",children:[n.jsxs("div",{className:"usage-tile",children:[n.jsx("span",{children:"今日消费"}),n.jsx("strong",{children:xt(p.today.cost)}),n.jsxs("small",{children:["较昨日 ",se>=0?"+":"−",xt(Math.abs(se))]})]}),n.jsxs("div",{className:"usage-tile",children:[n.jsx("span",{children:"本月消费"}),n.jsx("strong",{children:xt(p.month.cost)}),n.jsxs("small",{children:[pl(p.month.requests)," 次请求"]})]}),n.jsxs("div",{className:"usage-tile",children:[n.jsx("span",{children:"今日请求"}),n.jsx("strong",{children:pl(p.today.requests)}),n.jsxs("small",{children:["成功率 ",p.today.successRate,"%"]})]}),n.jsxs("div",{className:"usage-tile",children:[n.jsx("span",{children:"累计消费"}),n.jsx("strong",{children:xt(p.total.cost)}),n.jsxs("small",{children:[pl(p.total.requests)," 次请求"]})]})]}),n.jsx("div",{className:"usage-range",role:"group","aria-label":"统计范围",children:[7,14,30].map(Y=>n.jsxs("button",{type:"button",className:u===Y?"selected":"","aria-pressed":u===Y,onClick:()=>f(Y),children:["近 ",Y," 天"]},Y))}),n.jsxs("div",{className:"usage-block",children:[n.jsxs("div",{className:"usage-block-head",children:[n.jsx("strong",{children:"每日消费"}),n.jsxs("span",{children:["近 ",p.rangeDays," 天"]})]}),G.length===0||V<=0?n.jsx("p",{className:"usage-placeholder",children:"这段时间还没有消费记录"}):n.jsxs(n.Fragment,{children:[n.jsxs("div",{className:"usage-plot",children:[n.jsx("div",{className:"usage-grid","aria-hidden":"true",children:[1,.5,0].map(Y=>n.jsx("div",{className:"usage-gridline",style:{bottom:`${Y*pm}%`},children:n.jsx("span",{children:xt(V*Y)})},Y))}),n.jsxs("div",{className:"usage-columns",children:[G.map((Y,xe)=>{const te=V>0?Y.cost/V*pm:0,ye=Y.cost>0,O=ye&&fe!==null&&Y.day===fe.day,ae=xe%ee===0||xe===G.length-1;return n.jsxs("div",{className:"usage-column",children:[n.jsxs("button",{type:"button",className:N===Y.day?"usage-column-hit is-hovered":"usage-column-hit",onMouseEnter:()=>y(Y.day),onMouseLeave:()=>y(""),onFocus:()=>y(Y.day),onBlur:()=>y(""),"aria-label":`${Y.day} 消费 ${xt(Y.cost)},${Y.requests} 次请求`,children:[ye&&n.jsx("span",{className:"usage-column-bar",style:{height:`${te}%`}}),O&&n.jsx("span",{className:"usage-column-peak",style:{bottom:`calc(${te}% + 6px)`},children:xt(Y.cost)})]}),n.jsx("span",{className:"usage-column-tick",children:ae?yp(Y.day):""})]},Y.day)}),me&&n.jsxs("div",{className:"usage-tooltip",style:{left:`${(ne+.5)/G.length*100}%`},role:"status",children:[n.jsx("strong",{children:xt(me.cost)}),n.jsx("span",{children:me.day}),n.jsxs("span",{children:[me.requests," 次请求"]})]})]})]}),n.jsxs("details",{className:"usage-table-toggle",children:[n.jsx("summary",{children:"查看数据表"}),n.jsxs("div",{className:"usage-table",children:[n.jsxs("div",{className:"usage-table-head",children:[n.jsx("span",{children:"日期"}),n.jsx("span",{children:"请求"}),n.jsx("span",{children:"消费"})]}),G.slice().reverse().map(Y=>n.jsxs("div",{className:"usage-table-row",children:[n.jsx("span",{children:Y.day}),n.jsx("span",{children:Y.requests}),n.jsx("span",{children:xt(Y.cost)})]},Y.day))]})]})]})]}),n.jsxs("div",{className:"usage-block",children:[n.jsxs("div",{className:"usage-block-head",children:[n.jsx("strong",{children:"按模型拆分"}),n.jsxs("span",{children:["近 ",p.rangeDays," 天消费"]})]}),_.length===0?n.jsx("p",{className:"usage-placeholder",children:"这段时间还没有调用记录"}):n.jsx("div",{className:"usage-models",children:_.map(Y=>n.jsxs("div",{className:"usage-model-row",children:[n.jsx("span",{className:"usage-model-name",title:Y.model,children:Y.model}),n.jsx("span",{className:"usage-model-track",children:n.jsx("span",{className:"usage-model-bar",style:{width:`${P>0?Y.cost/P*100:0}%`}})}),n.jsx("span",{className:"usage-model-value",children:xt(Y.cost)})]},Y.model))})]})]})]})}function bp({theme:u,setTheme:f,goHome:p,openLogin:r}){const[C,T]=b.useState(null),[k,W]=b.useState([]),[N,y]=b.useState(null),[G,_]=b.useState(!1),[V,P]=b.useState(""),[fe,ee]=b.useState(""),[me,ne]=b.useState("");async function se(){try{const[O,ae,ve]=await Promise.all([pe("/api/account/me"),pe("/api/catalog/models"),pe("/api/account/check-in")]);T({...O,apiKeys:je(O.apiKeys)}),W(je(ae.models).map(us)),y(ve.checkIn)}catch{r()}}b.useEffect(()=>{se()},[]);async function Y(){if(!(!N?.enabled||N.claimed||G)){_(!0),P("");try{const O=await pe("/api/account/check-in",{method:"POST",body:JSON.stringify({})});T(ae=>ae&&{...ae,user:O.user}),y(O.checkIn),P(`签到成功,获得 ${O.reward.toFixed(2)} 额度`)}catch(O){P(O instanceof Error?O.message:"签到失败,请稍后重试")}finally{_(!1)}}}async function xe(){try{const O=await pe("/api/account/api-keys",{method:"POST",body:JSON.stringify({name:"My API Key"})});ee(O.secret),ne("新密钥只显示这一次"),await se()}catch(O){ne(O instanceof Error?O.message:"创建密钥失败")}}async function te(O){if(window.confirm("删除这个 API Key?使用它的请求会立即失效。"))try{await pe(`/api/account/api-keys/${O}`,{method:"DELETE"}),T(ae=>ae&&{...ae,apiKeys:ae.apiKeys.filter(ve=>ve.id!==O)}),ne("密钥已删除")}catch(ae){ne(ae instanceof Error?ae.message:"删除密钥失败")}}async function ye(){await pe("/api/auth/logout",{method:"POST"}),p()}return n.jsxs("main",{className:"account-page","data-theme":u,children:[n.jsxs("header",{className:"account-topbar",children:[n.jsxs("button",{className:"auth-brand",onClick:p,children:[n.jsx("span",{className:"brand-mark",children:"C"}),n.jsx("strong",{children:"CAPI"})]}),n.jsxs("div",{className:"account-actions",children:[n.jsx("button",{className:"theme-toggle","aria-label":"切换暗色模式",onClick:()=>f(u==="dark"?"light":"dark"),children:n.jsx(zt,{name:u==="dark"?"sun":"moon"})}),n.jsx("button",{className:"secondary-button",onClick:ye,children:"退出"})]})]}),n.jsxs("section",{className:"account-content",children:[n.jsxs("div",{className:"account-heading",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"My CAPI"}),n.jsx("h1",{children:C?.user.name||"账户"})]}),n.jsxs("div",{className:"account-balance",children:[n.jsx("span",{children:"余额"}),n.jsx("strong",{children:C?C.user.balance.toFixed(2):"-"})]})]}),n.jsx(gp,{}),n.jsxs("section",{className:"account-section check-in-section",children:[n.jsxs("div",{className:"account-section-title",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"Daily Reward"}),n.jsx("h2",{children:"每日签到"})]}),n.jsx("button",{className:"primary-button",disabled:!N?.enabled||!!N?.claimed||G,onClick:Y,children:G?"领取中":N?.claimed?"今日已签到":N?.enabled?"签到领额度":"暂未开放"})]}),n.jsxs("div",{className:"check-in-summary",children:[n.jsxs("div",{children:[n.jsx("span",{children:"今日状态"}),n.jsx("strong",{children:N?.claimed?`已领取 ${N.reward.toFixed(2)}`:N?.enabled?"等待签到":"活动关闭"})]}),n.jsxs("div",{children:[n.jsx("span",{children:"随机奖励"}),n.jsx("strong",{children:N?`${N.minReward.toFixed(2)} - ${N.maxReward.toFixed(2)}`:"-"})]}),n.jsxs("div",{children:[n.jsx("span",{children:"结算日期"}),n.jsx("strong",{children:N?.day||"北京时间"})]})]}),n.jsx("p",{className:"check-in-note",children:"每天按北京时间 00:00 刷新,奖励领取后直接计入账户余额。"}),V&&n.jsx("p",{className:"account-message check-in-message",role:"status",children:V})]}),n.jsxs("section",{className:"account-section",children:[n.jsxs("div",{className:"account-section-title",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"API Keys"}),n.jsx("h2",{children:"API 密钥"})]}),n.jsx("button",{className:"primary-button",onClick:xe,children:"创建密钥"})]}),fe&&n.jsx("code",{className:"one-time-secret",children:fe}),me&&n.jsx("p",{className:"account-message",children:me}),n.jsxs("div",{className:"account-key-list",children:[C?.apiKeys?.map(O=>n.jsxs("div",{className:"account-key-item",children:[n.jsx("span",{className:"account-key-mark","aria-hidden":"true",children:n.jsx(zt,{name:"key"})}),n.jsxs("div",{className:"account-key-info",children:[n.jsx("strong",{children:O.name}),n.jsxs("code",{children:[O.prefix,"…"]})]}),n.jsx(_t,{tone:O.status,children:Ot(O.status)}),n.jsx("button",{className:"icon-button","aria-label":`删除 ${O.name}`,title:"删除密钥",onClick:()=>te(O.id),children:n.jsx(zt,{name:"ban"})})]},O.id)),je(C?.apiKeys).length===0&&n.jsx("div",{className:"empty",children:"还没有 API 密钥"})]})]}),n.jsxs("section",{className:"account-section",children:[n.jsx("div",{className:"account-section-title",children:n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"Models"}),n.jsx("h2",{children:"可用模型"})]})}),n.jsxs("div",{className:"account-model-grid",children:[k.map(O=>n.jsxs("article",{children:[n.jsx("span",{children:O.vendor}),n.jsx("strong",{children:O.name}),n.jsx("p",{children:O.description}),n.jsx("code",{children:O.id})]},O.id)),k.length===0&&n.jsx("div",{className:"account-model-empty",children:"暂无可用模型,管理员配置渠道后将在此展示"})]})]})]})]})}function xp({theme:u,setTheme:f,enterConsole:p}){return n.jsxs("main",{className:"public-home","data-theme":u,children:[n.jsxs("header",{className:"home-topbar",children:[n.jsxs("div",{className:"home-brand",children:[n.jsx("div",{className:"brand-mark",children:"C"}),n.jsxs("div",{children:[n.jsx("strong",{children:"CAPI"}),n.jsx("span",{children:"AI 聚合网关"})]})]}),n.jsxs("div",{className:"home-actions",children:[n.jsxs("button",{className:"theme-toggle","aria-label":"切换暗色模式",onClick:()=>f(u==="dark"?"light":"dark"),children:[n.jsx(zt,{name:u==="dark"?"sun":"moon"}),n.jsx("span",{children:u==="dark"?"浅色":"暗色"})]}),n.jsx("button",{className:"primary-button",onClick:p,children:"控制台"})]})]}),n.jsxs("section",{className:"home-hero",children:[n.jsxs("div",{className:"home-copy",children:[n.jsx("span",{className:"home-kicker",children:"兼容 OpenAI 格式的网关"}),n.jsxs("h1",{children:["CAPI",n.jsx("span",{children:"轻量 AI 聚合网关"})]}),n.jsx("p",{children:"面向个人用户和团队的模型接入层。把 API Key、额度、模型渠道和调用日志放在一个清爽控制台里,保持轻量,也便于排障。"}),n.jsx("div",{className:"home-cta",children:n.jsx("button",{className:"primary-button",onClick:p,children:"进入控制台"})}),n.jsxs("div",{className:"integration-row","aria-label":"网关能力概览",children:[n.jsx("span",{children:"网关能力"}),n.jsxs("div",{children:[n.jsx("span",{children:"OpenAI 兼容接口"}),n.jsx("span",{children:"额度控制"}),n.jsx("span",{children:"调用审计"})]})]})]}),n.jsxs("div",{className:"gateway-terminal","aria-label":"CAPI 终端请求示意",children:[n.jsxs("div",{className:"terminal-titlebar",children:[n.jsxs("div",{className:"terminal-dots","aria-hidden":"true",children:[n.jsx("span",{}),n.jsx("span",{}),n.jsx("span",{})]}),n.jsx("strong",{children:"CAPI Terminal"}),n.jsxs("div",{className:"terminal-status",children:[n.jsx("span",{className:"pulse-dot"}),n.jsx("strong",{children:"Online"})]})]}),n.jsxs("div",{className:"terminal-endpoint",children:[n.jsx("span",{children:"POST"}),n.jsx("strong",{children:"/v1/chat/completions"})]}),n.jsxs("div",{className:"terminal-body",children:[n.jsxs("div",{className:"terminal-block",children:[n.jsx("span",{children:"REQUEST"}),n.jsx("pre",{children:`curl https://api.capi.local/v1/chat/completions \\ + -H "Authorization: Bearer cat_..." \\ + -d '{ + "model": "capi-fast", + "messages": [{ "role": "user", "content": "ping" }] + }'`})]}),n.jsxs("div",{className:"terminal-route",children:[n.jsxs("div",{children:[n.jsx("span",{children:"auth"}),n.jsx("strong",{children:"pass"})]}),n.jsxs("div",{children:[n.jsx("span",{children:"quota"}),n.jsx("strong",{children:"ok"})]}),n.jsxs("div",{children:[n.jsx("span",{children:"route"}),n.jsx("strong",{children:"capi-fast"})]}),n.jsxs("div",{children:[n.jsx("span",{children:"latency"}),n.jsx("strong",{children:"186ms"})]})]}),n.jsxs("div",{className:"terminal-block response",children:[n.jsx("span",{children:"RESPONSE"}),n.jsxs("pre",{children:[`{ + "status": 200, + "model": "capi-fast", + "usage": { "total_tokens": 27 }, + "message": "request routed" +}`,n.jsx("span",{className:"terminal-caret","aria-hidden":"true"})]})]})]})]})]})]})}function jp({overview:u,channels:f,logs:p,onNavigate:r}){const C=p.filter(T=>T.status!=="success");return n.jsxs("section",{className:"page-stack",children:[n.jsxs("div",{className:"hero-strip",children:[n.jsxs("div",{children:[n.jsx("span",{children:"Live Gateway"}),n.jsxs("strong",{children:["CAPI 网关正在服务 ",u?.activeUsers??"-"," 个活跃用户"]}),n.jsx("p",{children:"请求进入 CAPI 后,会按额度、模型和渠道状态自动选择最合适的上游。"})]}),n.jsxs("div",{className:"live-island",children:[n.jsx("div",{className:"pulse-dot"}),n.jsx("span",{children:"在线"})]})]}),n.jsxs("div",{className:"quick-actions","aria-label":"快捷操作",children:[n.jsx(Si,{icon:"key",label:"创建 Key",onClick:()=>r("keys")}),n.jsx(Si,{icon:"route",label:"配置渠道",onClick:()=>r("channels")}),n.jsx(Si,{icon:"users",label:"调整额度",onClick:()=>r("users")}),n.jsx(Si,{icon:"logs",label:"查看异常",onClick:()=>r("logs")})]}),n.jsxs("div",{className:"metrics-grid",children:[n.jsx(ol,{label:"活跃用户",value:u?pl(u.activeUsers):"-"}),n.jsx(ol,{label:"今日请求",value:u?pl(u.requestsToday):"-"}),n.jsx(ol,{label:"今日输入",value:u?pl(u.todayInputTokens):"-"}),n.jsx(ol,{label:"今日输出",value:u?pl(u.todayOutputTokens):"-"}),n.jsx(ol,{label:"今日扣费",value:u?xt(u.todayCost,4):"-"}),n.jsx(ol,{label:"账户余额",value:u?xt(u.totalBalance):"-"}),n.jsx(ol,{label:"成功率",value:u?`${u.successRate}%`:"-"})]}),n.jsx(Sp,{}),n.jsxs("div",{className:"split-grid",children:[n.jsx(lt,{title:"渠道状态",children:f.length?f.map(T=>n.jsxs("div",{className:"list-row overview-channel-row",children:[n.jsxs("div",{children:[n.jsx("strong",{children:T.name}),n.jsx("span",{title:je(T.models).join(", "),children:op(T.models)})]}),n.jsx(_t,{tone:T.status,children:Ot(T.status)})]},T.id)):n.jsx(Lt,{text:"暂无渠道"})}),n.jsx(lt,{title:"最近请求",children:p.length?p.slice(0,4).map(T=>n.jsxs("div",{className:"list-row",children:[n.jsxs("div",{children:[n.jsx("strong",{children:lo(T)}),n.jsxs("span",{children:[T.id," · ",T.errorCode||tl(T.createdAt)]})]}),n.jsx(_t,{tone:T.status,children:Ot(T.status)})]},T.id)):n.jsx(Lt,{text:C.length?"暂无最近请求":"暂无请求"})})]})]})}function Si({icon:u,label:f,onClick:p}){return n.jsxs("button",{className:"quick-action",onClick:p,children:[n.jsx(zt,{name:u}),n.jsx("span",{children:f})]})}function Sp(){const u=[{label:"认证",detail:"校验 API Key"},{label:"额度",detail:"检查余额"},{label:"路由",detail:"选择渠道"},{label:"响应",detail:"返回结果"}];return n.jsxs("section",{className:"flow-panel","aria-label":"网关流转",children:[n.jsxs("div",{className:"flow-copy",children:[n.jsx("span",{children:"Request Flow"}),n.jsx("strong",{children:"请求处理流程"})]}),n.jsx("div",{className:"flow-steps",children:u.map((f,p)=>n.jsxs("div",{className:"flow-step",children:[n.jsx("div",{className:"flow-index",children:p+1}),n.jsx("strong",{children:f.label}),n.jsx("span",{children:f.detail})]},f.label))})]})}function Np({users:u,query:f,selectedUser:p,onQuery:r,onSelect:C,onUpdate:T,onBulkUpdate:k,onCreateKey:W,groups:N,onOpenRegistration:y}){const[_,V]=b.useState(1),[P,fe]=b.useState("all"),[ee,me]=b.useState(new Set),[ne,se]=b.useState("10"),[Y,xe]=b.useState(""),[te,ye]=b.useState(""),[O,ae]=b.useState(!1),[ve,Ce]=b.useState("10"),[Me,ue]=b.useState(""),[Z,de]=b.useState(""),[$,A]=b.useState(!1),L=P==="all"?u:u.filter(z=>z.status===P),H=L.filter(z=>z.role!=="admin"),X=Math.max(1,Math.ceil(L.length/25)),ie=Math.min(_,X),m=L.slice((ie-1)*25,ie*25),h=H.length>0&&H.every(z=>ee.has(z.id));b.useEffect(()=>{V(1)},[f,P]),b.useEffect(()=>{const z=new Set(u.map(be=>be.id));me(be=>new Set([...be].filter(ce=>z.has(ce))))},[u]),b.useEffect(()=>{Ce("10"),ue(""),de("")},[p?.user.id]);function M(z){me(be=>{const ce=new Set(be);return ce.has(z)?ce.delete(z):ce.add(z),ce})}function Q(){me(z=>{const be=new Set(z);return h?H.forEach(ce=>be.delete(ce.id)):H.forEach(ce=>be.add(ce.id)),be})}async function le(z,be){if(ee.size!==0){ae(!0);try{await k([...ee],z,be),me(new Set),xe("")}finally{ae(!1)}}}async function Ne(z){if(!p)return;const be=Math.abs(Number(ve));if(!Number.isFinite(be)||be<=0){de("请输入大于 0 的金额");return}A(!0),de("");try{await k([p.user.id],"adjust_balance",{amount:Number((be*z).toFixed(4)),reason:Me.trim()||(z>0?"管理员增加额度":"管理员扣减额度")}),de(z>0?"额度已增加":"额度已扣减"),ue("")}catch(ce){de(ce instanceof Error?ce.message:"额度调整失败")}finally{A(!1)}}return n.jsxs("section",{className:"users-layout",children:[n.jsxs(lt,{title:"用户管理",children:[n.jsxs("div",{className:"panel-toolbar",children:[n.jsxs("div",{className:"search-box",children:[n.jsx(zt,{name:"search"}),n.jsx("input",{value:f,onChange:z=>r(z.target.value),placeholder:"搜索 ID、姓名或邮箱"})]}),n.jsx("button",{className:"icon-button",title:"开放注册",onClick:y,children:n.jsx(zt,{name:"plus"})})]}),n.jsxs("div",{className:"user-summary-strip",children:[n.jsxs("span",{children:[n.jsx("strong",{children:u.length})," 匹配用户"]}),n.jsxs("span",{children:[n.jsx("strong",{children:u.filter(z=>z.status==="active").length})," 正常"]}),n.jsxs("span",{children:[n.jsx("strong",{children:u.filter(z=>z.status==="disabled").length})," 禁用"]}),n.jsxs("span",{children:[n.jsx("strong",{children:u.reduce((z,be)=>z+be.requestsToday,0)})," 今日请求"]})]}),n.jsx("div",{className:"user-filter-row",role:"group","aria-label":"用户状态筛选",children:[{value:"all",label:"全部"},{value:"active",label:"正常"},{value:"limited",label:"受限"},{value:"disabled",label:"禁用"}].map(z=>n.jsx("button",{type:"button",className:P===z.value?"selected":"",onClick:()=>fe(z.value),children:z.label},z.value))}),n.jsx("button",{type:"button",className:"secondary-button mobile-bulk-select",onClick:Q,children:h?"取消全选":`全选结果(${H.length})`}),ee.size>0&&n.jsxs("div",{className:"bulk-action-bar",children:[n.jsxs("strong",{children:["已选 ",ee.size," 人"]}),n.jsx("input",{type:"number",step:"0.01",value:ne,onChange:z=>se(z.target.value),"aria-label":"额度调整值"}),n.jsx("input",{value:Y,onChange:z=>xe(z.target.value),placeholder:"原因,例如:活动赠送","aria-label":"调整原因"}),n.jsx("button",{type:"button",className:"secondary-button",disabled:O||!Number(ne),onClick:()=>le("adjust_balance",{amount:Number(ne),reason:Y}),children:"调整额度"}),n.jsx("button",{type:"button",className:"secondary-button",disabled:O,onClick:()=>le("set_status",{value:"active"}),children:"启用"}),n.jsx("button",{type:"button",className:"danger-button",disabled:O,onClick:()=>le("set_status",{value:"disabled"}),children:"禁用"}),n.jsxs("select",{className:"bulk-group-select",value:te,disabled:O,"aria-label":"批量设置分组",onChange:z=>ye(z.target.value),children:[n.jsx("option",{value:"",children:"未分组"}),N.map(z=>n.jsx("option",{value:z.id,children:z.name},z.id))]}),n.jsx("button",{type:"button",className:"secondary-button",disabled:O,onClick:()=>le("set_group",{value:te}),children:"设为分组"})]}),n.jsxs("div",{className:"table",children:[n.jsxs("div",{className:"table-head users-table",children:[n.jsx("input",{type:"checkbox",checked:h,onChange:Q,"aria-label":"选择当前筛选结果"}),n.jsx("span",{children:"用户"}),n.jsx("span",{children:"状态"}),n.jsx("span",{children:"余额"}),n.jsx("span",{children:"今日"})]}),m.map(z=>n.jsxs("div",{className:p?.user.id===z.id?"table-row users-table selected":"table-row users-table",role:"button",tabIndex:0,onClick:()=>C(z.id),onKeyDown:be=>{(be.key==="Enter"||be.key===" ")&&C(z.id)},children:[n.jsx("input",{type:"checkbox",checked:ee.has(z.id),disabled:z.role==="admin",onChange:()=>M(z.id),onClick:be=>be.stopPropagation(),"aria-label":z.role==="admin"?`${z.name} 是管理员,不参与批量操作`:`选择 ${z.name}`}),n.jsxs("span",{children:[n.jsx("strong",{children:z.name}),n.jsxs("small",{children:[z.id," · ",z.email||"未绑定邮箱"]})]}),n.jsx(_t,{tone:z.status,children:Ot(z.status)}),n.jsx("span",{children:xt(z.balance)}),n.jsx("span",{children:z.requestsToday})]},z.id)),L.length===0&&n.jsx(Lt,{text:"暂无匹配用户"})]}),L.length>25&&n.jsxs("div",{className:"pagination-bar",children:[n.jsx("button",{className:"secondary-button",disabled:ie<=1,onClick:()=>V(z=>Math.max(1,z-1)),children:"上一页"}),n.jsxs("span",{children:[ie," / ",X]}),n.jsx("button",{className:"secondary-button",disabled:ie>=X,onClick:()=>V(z=>Math.min(X,z+1)),children:"下一页"})]})]}),n.jsx(lt,{title:"用户详情",children:p?n.jsxs("div",{className:"detail-stack",children:[n.jsxs("div",{className:"user-hero",children:[n.jsx("div",{className:"avatar",children:p.user.name.slice(0,1)}),n.jsxs("div",{children:[n.jsx("h2",{children:p.user.name}),n.jsx("p",{children:p.user.email})]}),n.jsx(_t,{tone:p.user.status,children:Ot(p.user.status)})]}),n.jsxs("div",{className:"settings-group",children:[n.jsx(el,{label:"角色",value:p.user.role==="admin"?"管理员":"用户"}),n.jsx(el,{label:"余额",value:xt(p.user.balance)}),n.jsx(el,{label:"总请求",value:String(p.user.totalRequests)}),n.jsx(el,{label:"最后登录",value:tl(p.user.lastLoginAt)}),n.jsx(el,{label:"API 调用",value:p.user.status==="disabled"?"关闭":"允许",switchOn:p.user.status!=="disabled"})]}),n.jsxs("div",{className:"group-assign-row",children:[n.jsxs("label",{children:[n.jsx("span",{children:"所属分组"}),n.jsxs("select",{value:p.user.groupId||"",onChange:z=>T(p.user.id,{groupId:z.target.value}),children:[n.jsx("option",{value:"",children:"未分组"}),N.map(z=>n.jsx("option",{value:z.id,children:z.name},z.id))]})]}),n.jsx("small",{children:"分组决定该用户可路由到哪些渠道;未分组用户只能使用未限制分组的渠道。"})]}),n.jsxs("div",{className:"balance-adjuster",children:[n.jsxs("div",{className:"balance-adjuster-title",children:[n.jsx("strong",{children:"调整余额"}),n.jsxs("span",{children:["当前 ",xt(p.user.balance)]})]}),n.jsxs("div",{className:"balance-adjuster-fields",children:[n.jsxs("label",{children:[n.jsx("span",{children:"金额"}),n.jsx("input",{type:"number",min:"0.0001",step:"0.01",value:ve,onChange:z=>Ce(z.target.value)})]}),n.jsxs("label",{children:[n.jsx("span",{children:"备注"}),n.jsx("input",{value:Me,onChange:z=>ue(z.target.value),placeholder:"可选,会记录到流水"})]})]}),n.jsxs("div",{className:"balance-adjuster-actions",children:[n.jsx("button",{className:"secondary-button",disabled:$,onClick:()=>Ne(1),children:"增加"}),n.jsx("button",{className:"danger-button",disabled:$,onClick:()=>Ne(-1),children:"扣减"}),n.jsx("span",{role:"status",children:Z})]})]}),n.jsxs("div",{className:"action-row",children:[n.jsx("button",{className:"secondary-button",onClick:()=>W(p.user.id),children:"创建 Key"}),n.jsx("button",{className:"secondary-button",disabled:p.user.role==="admin",onClick:()=>T(p.user.id,{status:p.user.status==="disabled"?"active":"disabled"}),children:p.user.role==="admin"?"管理员保护":p.user.status==="disabled"?"解封":"禁用"})]}),n.jsxs("div",{children:[n.jsx("h3",{children:"API Key"}),p.apiKeys.map(z=>n.jsxs("div",{className:"list-row",children:[n.jsxs("div",{children:[n.jsx("strong",{children:z.name}),n.jsxs("span",{children:[z.prefix,"*** · ",z.requestCount," 次"]})]}),n.jsx(_t,{tone:z.status,children:Ot(z.status)})]},z.id)),p.apiKeys.length===0&&n.jsx(Lt,{text:"暂无 API Key"})]})]}):n.jsx(Lt,{text:"请选择一个用户"})})]})}function Ap({selectedUser:u,onCreateKey:f,onUpdateKey:p,onDeleteKey:r}){return n.jsx(lt,{title:"密钥管理",children:u?n.jsxs(n.Fragment,{children:[n.jsxs("div",{className:"panel-toolbar",children:[n.jsxs("span",{className:"muted-inline",children:[u.user.name," · 完整 Key 只在创建时显示,丢失请重新创建"]}),n.jsx("button",{className:"primary-button",onClick:()=>f(u.user.id),children:"创建 Key"})]}),u.apiKeys.length?u.apiKeys.map(C=>n.jsx(Cp,{apiKey:C,onSave:p,onDelete:r},C.id)):n.jsx(Lt,{text:"暂无密钥"})]}):n.jsx(Lt,{text:"请选择一个用户"})})}function Cp({apiKey:u,onSave:f,onDelete:p}){const[r,C]=b.useState(u.name),[T,k]=b.useState(je(u.allowedModels).join(", ")),[W,N]=b.useState(mm(u.expiresAt||"")),[y,G]=b.useState(String(u.rateLimitPerMinute||"")),[_,V]=b.useState(!1),P=je(u.allowedModels).length?je(u.allowedModels).join(", "):"全部模型";b.useEffect(()=>{C(u.name),k(je(u.allowedModels).join(", ")),N(mm(u.expiresAt||"")),G(String(u.rateLimitPerMinute||""))},[u]);async function fe(){V(!0);try{await f(u.id,{name:r.trim()||"API Key",allowedModels:Pc(T),expiresAt:sp(W),rateLimitPerMinute:Number(y||0)})}finally{V(!1)}}return n.jsxs("details",{className:"key-editor key-editor-collapsible",children:[n.jsxs("summary",{className:"key-editor-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:u.name}),n.jsxs("span",{children:[u.prefix,"*** · ",P," · 最后使用 ",tl(u.lastUsedAt)]})]}),n.jsxs("div",{className:"row-actions",children:[n.jsx(_t,{tone:u.status,children:Ot(u.status)}),n.jsx("span",{className:"key-expand-hint",children:"管理"})]})]}),n.jsxs("div",{className:"key-editor-body",children:[n.jsxs("div",{className:"key-editor-grid",children:[n.jsxs("label",{children:["名称",n.jsx("input",{value:r,onChange:ee=>C(ee.target.value)})]}),n.jsxs("label",{children:["允许模型",n.jsx("input",{value:T,onChange:ee=>k(ee.target.value),placeholder:"留空表示全部模型,多个用逗号分隔"})]}),n.jsxs("label",{children:["过期时间",n.jsx("input",{type:"datetime-local",value:W,onChange:ee=>N(ee.target.value)})]}),n.jsxs("label",{children:["每分钟限制",n.jsx("input",{type:"number",min:"0",value:y,onChange:ee=>G(ee.target.value),placeholder:"0 使用全局限制"})]})]}),n.jsxs("div",{className:"key-editor-actions",children:[n.jsx("button",{className:"secondary-button",onClick:()=>f(u.id,{status:u.status==="active"?"disabled":"active"}),children:u.status==="active"?"停用密钥":"启用密钥"}),n.jsx("button",{className:"danger-button",onClick:()=>p(u.id),children:"删除密钥"}),n.jsx("button",{className:"primary-button",disabled:_,onClick:fe,children:_?"保存中":"保存设置"})]})]})]})}function Tp({models:u,onCopy:f,onCreate:p,onUpdate:r,onDelete:C}){const T=u.filter(H=>H.recommended),[k,W]=b.useState(""),[N,y]=b.useState("all"),[G,_]=b.useState("all"),[V,P]=b.useState(1),[fe,ee]=b.useState(""),[me,ne]=b.useState(""),[se,Y]=b.useState(""),[xe,te]=b.useState(""),[ye,O]=b.useState(""),[ae,ve]=b.useState(""),Ce=60,Me=b.useMemo(()=>{const H=new Map;return u.forEach(X=>{const ie=$c(X);H.set(ie,(H.get(ie)||0)+1)}),Array.from(H.entries()).sort((X,ie)=>ie[1]-X[1]||cl(X[0]).localeCompare(cl(ie[0]))).map(([X,ie])=>({provider:X,count:ie}))},[u]),ue=b.useMemo(()=>{const H=k.trim().toLowerCase();return u.filter(X=>N!=="all"&&$c(X)!==N||G!=="all"&&X.status!==G?!1:H?[X.id,X.name,X.vendor,X.category,X.description,...je(X.aliases)].join(" ").toLowerCase().includes(H):!0)},[u,k,N,G]),Z=b.useMemo(()=>{const H=new Map;ue.forEach(M=>{const Q=$c(M);H.set(Q,[...H.get(Q)||[],M])});const X=[];let ie=[],m=0;const h=Array.from(H.entries()).sort((M,Q)=>cl(M[0]).localeCompare(cl(Q[0])));for(const M of h)ie.length>0&&m+M[1].length>Ce&&(X.push(ie),ie=[],m=0),ie.push(M),m+=M[1].length;return ie.length>0&&X.push(ie),X},[ue]),de=Math.max(1,Z.length),$=Math.min(V,de),A=Z[$-1]||[];b.useEffect(()=>{P(1)},[k,N,G,u.length]);async function L(H){H.preventDefault();const X=fe.trim();if(X){ve("");try{await p({id:X,name:me.trim()||X,vendor:se.trim()||"Custom",aliases:xe.split(",").map(ie=>ie.trim()).filter(Boolean),category:"通用",description:ye.trim(),price:"自定义",context:"未配置上下文"}),ee(""),ne(""),Y(""),te(""),O("")}catch(ie){ve(ie instanceof Error?ie.message:"模型添加失败")}}}return n.jsxs("section",{className:"models-page",children:[n.jsx("div",{className:"model-hero",children:n.jsxs("div",{children:[n.jsx("span",{children:"Model Catalog"}),n.jsx("strong",{children:"Models"})]})}),n.jsx(lt,{title:"新增模型",children:n.jsxs("form",{className:"model-create-form",onSubmit:L,children:[n.jsx("input",{value:fe,onChange:H=>ee(H.target.value),placeholder:"模型 ID,例如 openai/gpt-4.1"}),n.jsx("input",{value:me,onChange:H=>ne(H.target.value),placeholder:"显示名称(可选)"}),n.jsx("input",{value:se,onChange:H=>Y(H.target.value),placeholder:"供应商(可选)"}),n.jsx("input",{value:xe,onChange:H=>te(H.target.value),placeholder:"代称,多个用逗号分隔(可选)"}),n.jsx("input",{className:"model-create-wide",value:ye,onChange:H=>O(H.target.value),placeholder:"描述(可选)"}),n.jsx("button",{className:"primary-button",type:"submit",children:"新增模型"}),n.jsx("div",{className:"model-create-message",role:"status",children:ae})]})}),T.length>0&&n.jsx(lt,{title:"推荐模型",children:n.jsx("div",{className:"model-grid",children:T.map(H=>n.jsx(Mp,{model:H,featured:!0,onCopy:f,onUpdate:r},H.id))})}),n.jsxs(lt,{title:"全部模型",children:[n.jsxs("div",{className:"panel-toolbar model-list-toolbar",children:[n.jsx("input",{value:k,onChange:H=>W(H.target.value),placeholder:"搜索模型 ID、名称、供应商或代称"}),n.jsx("div",{className:"model-filter-actions",children:[{value:"all",label:"全部"},{value:"available",label:"可用"},{value:"disabled",label:"禁用"}].map(H=>n.jsx("button",{type:"button",className:G===H.value?"selected":"",onClick:()=>_(H.value),children:H.label},H.value))})]}),n.jsxs("div",{className:"model-provider-filter","aria-label":"按供应商筛选模型",children:[n.jsxs("button",{type:"button",className:N==="all"?"selected":"",onClick:()=>y("all"),children:[n.jsx("span",{className:"provider-icon provider-icon-all","aria-hidden":"true",children:"All"}),n.jsx("strong",{children:"全部"}),n.jsx("small",{children:u.length})]}),Me.map(H=>n.jsxs("button",{type:"button",className:N===H.provider?"selected":"",onClick:()=>y(H.provider),children:[n.jsx(hm,{provider:H.provider}),n.jsx("strong",{children:cl(H.provider)}),n.jsx("small",{children:H.count})]},H.provider))]}),n.jsxs("div",{className:"model-list-summary",children:[n.jsx("span",{children:N==="all"?"全部供应商":cl(N)}),n.jsx("strong",{children:ue.length}),n.jsx("span",{children:"个模型"})]}),ue.length>0?n.jsxs(n.Fragment,{children:[n.jsx("div",{className:"model-provider-groups",children:A.map(([H,X])=>n.jsxs("section",{className:"model-provider-group",children:[n.jsxs("header",{children:[n.jsx(hm,{provider:H}),n.jsxs("div",{children:[n.jsx("strong",{children:cl(H)}),n.jsxs("span",{children:[X.length," 个模型"]})]})]}),n.jsx("div",{className:"model-compact-grid",children:X.map(ie=>n.jsx(Ep,{model:ie,onCopy:f,onUpdate:r,onDelete:C},ie.id))})]},H))}),de>1&&n.jsxs("div",{className:"pager",children:[n.jsx("button",{className:"secondary-button compact-button",onClick:()=>P(H=>Math.max(1,H-1)),disabled:$<=1,children:"上一页"}),n.jsxs("span",{children:[$," / ",de]}),n.jsx("button",{className:"secondary-button compact-button",onClick:()=>P(H=>Math.min(de,H+1)),disabled:$>=de,children:"下一页"})]})]}):n.jsx(Lt,{text:u.length?"没有匹配的模型":"暂无模型,请先添加你要开放给用户调用的模型 ID"})]})]})}function Ep({model:u,onCopy:f,onUpdate:p,onDelete:r}){const C=je(u.aliases).slice(0,3),T=u.status==="disabled";return n.jsxs("article",{className:"model-compact-row",children:[n.jsxs("div",{className:"model-compact-main",children:[n.jsx("strong",{children:u.name}),n.jsx("small",{children:u.id}),C.length>0&&n.jsx("span",{children:C.map(k=>n.jsx("em",{children:k},k))})]}),n.jsxs("div",{className:"model-row-actions",children:[n.jsx(_t,{tone:u.status,children:Ot(u.status)}),u.recommended&&n.jsx("span",{className:"model-recommended-mark",children:"推荐"}),n.jsx("button",{className:"icon-button",title:"复制模型 ID",onClick:()=>f(u.id,"模型 ID 已复制"),children:n.jsx(zt,{name:"copy"})}),n.jsxs("details",{className:"model-row-menu",children:[n.jsx("summary",{"aria-label":"模型操作",children:"•••"}),n.jsxs("div",{children:[n.jsx("button",{type:"button",onClick:()=>p(u.id,{recommended:!u.recommended}),children:u.recommended?"取消推荐":"设为推荐"}),n.jsx("button",{type:"button",onClick:()=>p(u.id,{status:T?"available":"disabled"}),children:T?"启用模型":"停用模型"}),n.jsx("button",{className:"is-danger",type:"button",onClick:()=>r(u.id),children:"删除模型"})]})]})]})]})}function Mp({model:u,featured:f=!1,onCopy:p,onUpdate:r}){return n.jsxs("article",{className:f?"model-card featured":"model-card",children:[n.jsxs("div",{className:"model-card-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:u.name}),n.jsxs("span",{children:[u.vendor," · ",u.category]})]}),n.jsx(_t,{tone:u.status,children:Ot(u.status)})]}),n.jsx("p",{children:u.description}),n.jsx("div",{className:"alias-row",children:je(u.aliases).map(C=>n.jsx("span",{children:C},C))}),n.jsxs("div",{className:"model-meta",children:[n.jsxs("span",{children:["价格:",u.price]}),n.jsx("span",{children:u.context})]}),n.jsxs("div",{className:"model-id",children:[n.jsx("code",{children:u.id}),n.jsx("button",{className:"icon-button",title:"复制模型 ID",onClick:()=>p(u.id,"模型 ID 已复制"),children:n.jsx(zt,{name:"copy"})})]}),r&&n.jsxs("div",{className:"model-card-actions",children:[n.jsx("button",{className:"secondary-button compact-button",type:"button",onClick:()=>r(u.id,{recommended:!1}),children:"取消推荐"}),n.jsx("button",{className:"secondary-button compact-button",type:"button",onClick:()=>r(u.id,{status:u.status==="disabled"?"available":"disabled"}),children:u.status==="disabled"?"启用":"停用"})]})]})}function vm({channels:u,onCreate:f,onImport:p,onCheckAccounts:r,onDeduplicateAccounts:C,onDeleteAccount:T,onUpdate:k,onStartOAuth:W,onCompleteOAuth:N,variant:y="drawing"}){const G=y==="antigravity",_=u.filter(h=>G?h.provider==="antigravity":h.provider!=="antigravity"&&(h.provider==="codex"||h.provider==="openai"||je(h.models).some(M=>M.includes("image")))),[V,P]=b.useState(""),[fe,ee]=b.useState({}),[me,ne]=b.useState({}),[se,Y]=b.useState({}),[xe,te]=b.useState({}),[ye,O]=b.useState(""),[ae,ve]=b.useState(""),[Ce,Me]=b.useState(""),[ue,Z]=b.useState(""),de=24,$=48;async function A(h,M){P(`import:${h}`);try{await p(h,M)}finally{P("")}}async function L(h,M=!1,Q=""){P(Q?`check-account:${Q}`:`${M?"retry":"check"}:${h}`);try{await r(h,M,Q)}finally{P("")}}async function H(h){P(`dedupe:${h}`);try{await C(h)}finally{P("")}}function X(h){const M=je(h.openaiAccounts).map(ce=>[ce.email||ce.name||ce.accountId||ce.id,ce.accountId||"",ce.status||"unchecked",ce.credentialMode||"access-token",ce.planType||"",ce.expiresAt||"",ce.lastCheckedAt||"",ce.lastUsedAt||"",String(ce.requestCount||0),ce.lastErrorCode||"",ce.lastError||""]),Q=ce=>`"${ce.replace(/"/g,'""')}"`,le=[["账号","Account ID","状态","凭据方式","套餐","到期时间","最近检测","最近调用","调用次数","错误码","最后错误"],...M].map(ce=>ce.map(Q).join(",")).join(`\r +`),Ne=new Blob(["\uFEFF"+le],{type:"text/csv;charset=utf-8"}),z=URL.createObjectURL(Ne),be=document.createElement("a");be.href=z,be.download=`${h.name||"account-pool"}-health-report.csv`,be.click(),URL.revokeObjectURL(z)}async function ie(h){P(`status:${h.id}`);try{await k(h.id,{status:h.status==="disabled"?"healthy":"disabled",baseUrl:h.baseUrl||Ei(h.provider)||Ti,provider:h.provider||"codex",models:je(h.models).length?h.models:jm.split(",").map(M=>M.trim())})}finally{P("")}}async function m(h,M){const Q=M.email||M.name||M.accountId||M.id;if(window.confirm(`删除账号「${Q}」?`)){P(`delete-account:${M.id}`);try{await T(h.id,M.id)}finally{P("")}}}return n.jsxs(lt,{title:G?"Antigravity 账号池":"账号池",children:[n.jsxs("div",{className:"panel-toolbar",children:[n.jsx("span",{className:"muted-inline",children:G?"导入 Google OAuth JSON 或 refresh token 即可入池。":"账号有两种来源,任选其一即可。"}),G?n.jsx("button",{className:"primary-button",onClick:()=>f(Ic("antigravity")),children:"新增 Antigravity 账号池"}):n.jsx("button",{className:"primary-button",onClick:()=>f(Ic("codex")),children:"新增账号池渠道"})]}),n.jsx("div",{className:"source-guide",children:G?n.jsxs(n.Fragment,{children:[n.jsxs("div",{className:"source-guide-item",children:[n.jsx("strong",{children:"Antigravity 导入(推荐)"}),n.jsx("span",{children:"粘贴 Google OAuth 凭据 JSON 或 refresh token,调用前自动换取 accessToken。"})]}),n.jsxs("div",{className:"source-guide-item",children:[n.jsx("strong",{children:"批量导入"}),n.jsx("span",{children:"支持 JSON、ZIP、TXT;TXT 可使用 JSONL 或每行一个 refresh token。"})]})]}):n.jsxs(n.Fragment,{children:[n.jsxs("div",{className:"source-guide-item",children:[n.jsx("strong",{children:"网页会话(推荐)"}),n.jsx("span",{children:"支持完整 auth/session JSON 或浏览器 Session Cookie,并在调用前重新获取 accessToken。"})]}),n.jsxs("div",{className:"source-guide-item",children:[n.jsx("strong",{children:"批量导入"}),n.jsx("span",{children:"支持 JSON、ZIP、TXT;TXT 可使用 JSONL 或每行一个 access token。"})]})]})}),n.jsxs("div",{className:"channels-stack",children:[_.map(h=>{const M=je(h.openaiAccounts),Q=M.filter(B=>B.status==="healthy").length,le=M.filter(B=>B.status==="invalid").length,Ne=M.filter(B=>!!B.lastErrorCode).length,z=Math.max(0,M.length-Q-le),be=M.filter(B=>B.credentialMode==="refreshable").length,ce=M.filter(B=>B.credentialMode==="browser-session").length,jt=Math.max(0,M.length-be-ce),I=me[h.id]||"all",Ve=(se[h.id]||"").trim().toLowerCase(),ot=M.filter(B=>{const Be=I==="all"||I==="attention"&&Gp(B)||I==="invalid"&&B.status==="invalid"||I==="error"&&!!B.lastErrorCode||I==="refreshable"&&B.credentialMode==="refreshable",We=`${B.email||""} ${B.name||""} ${B.accountId||""} ${B.userId||""} ${B.lastError||""}`.toLowerCase();return Be&&(!Ve||We.includes(Ve))}),Je=xe[h.id]||"pool",gt=[...ot].sort((B,Be)=>{if(Je==="pool")return 0;const We=Je==="expiry"?B.expiresAt||"9999-12-31":B.lastUsedAt||"",at=Je==="expiry"?Be.expiresAt||"9999-12-31":Be.lastUsedAt||"";return Je==="recent"?at.localeCompare(We):We.localeCompare(at)}),Dt=Math.min(gt.length,fe[h.id]||de),ll=gt.slice(0,Dt),al=Math.max(0,gt.length-ll.length),U=al===0;return n.jsxs("div",{className:"channel-card",children:[n.jsxs("div",{className:"channel-card-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:h.name}),n.jsx("span",{children:h.baseUrl||Ei(h.provider)||Ti}),n.jsxs("small",{children:["账号 ",M.length," 个,可用 ",Q,",无效 ",le,",未验证 ",z]}),n.jsxs("small",{children:["可续期 ",be," · 网页会话 ",ce," · 仅 Token ",jt]}),n.jsxs("small",{children:["自动检测 ",h.lastCheckedAt?tl(h.lastCheckedAt):"等待首次检测"]})]}),n.jsxs("div",{className:"channel-card-head-actions",children:[n.jsx(_t,{tone:h.status,children:Ot(h.status)}),n.jsx("button",{className:"primary-button compact-button",onClick:()=>Z(h.id),disabled:V!=="",children:"添加账号"}),n.jsx("button",{className:"secondary-button compact-button",onClick:()=>L(h.id),disabled:V!==""||M.length===0,children:V===`check:${h.id}`?"检测中":"批量检测"}),le>0&&n.jsx("button",{className:"secondary-button compact-button",onClick:()=>L(h.id,!0),disabled:V!=="",children:V===`retry:${h.id}`?"复检中":`复检无效 ${le}`}),M.length>1&&n.jsx("button",{className:"secondary-button compact-button",onClick:()=>H(h.id),disabled:V!=="",children:V===`dedupe:${h.id}`?"去重中":"账号去重"}),M.length>0&&n.jsx("button",{className:"secondary-button compact-button",onClick:()=>X(h),disabled:V!=="",children:"导出报告"}),n.jsx("button",{className:"secondary-button compact-button",onClick:()=>ie(h),disabled:V!=="",children:h.status==="disabled"?"启用渠道":"停用渠道"})]})]}),n.jsxs("div",{className:"account-filter-bar",role:"group","aria-label":"账号筛选",children:[n.jsx("input",{value:se[h.id]||"",onChange:B=>Y(Be=>({...Be,[h.id]:B.target.value})),placeholder:"搜索账号或错误","aria-label":"搜索账号"}),n.jsxs("select",{value:Je,onChange:B=>te(Be=>({...Be,[h.id]:B.target.value})),"aria-label":"账号排序",children:[n.jsx("option",{value:"pool",children:"账号池顺序"}),n.jsx("option",{value:"oldest",children:"最久未用优先"}),n.jsx("option",{value:"recent",children:"最近使用优先"}),n.jsx("option",{value:"expiry",children:"最早到期优先"})]}),[["all",`全部 ${M.length}`],["attention","需关注"],["invalid",`无效 ${le}`],["error",`有错误 ${Ne}`],["refreshable",`可续期 ${be}`]].map(([B,Be])=>n.jsx("button",{type:"button",className:I===B?"selected":"",onClick:()=>ne(We=>({...We,[h.id]:B})),children:Be},B))]}),n.jsxs("div",{className:"metrics-grid",children:[n.jsx(ol,{label:"账号总数",value:M.length}),n.jsx(ol,{label:"可用账号",value:Q}),n.jsx(ol,{label:"无效账号",value:le}),n.jsx(ol,{label:"未验证账号",value:z})]}),n.jsx("div",{className:"drawing-channel-models",children:je(h.models).length?je(h.models).map(B=>n.jsx("span",{children:B},B)):n.jsx("span",{children:"未绑定绘图模型"})}),M.length>0&&n.jsxs("div",{className:"account-pool-list",children:[ll.map(B=>n.jsxs("div",{className:"account-pool-row",children:[n.jsxs("div",{className:"account-pool-main",children:[n.jsxs("div",{children:[n.jsxs("div",{className:"account-pool-title",children:[n.jsx("strong",{title:B.email||B.name||B.accountId||B.id,children:B.email||B.name||B.accountId||B.id}),n.jsx("span",{className:`source-tag source-tag-${B.source==="web-login"?"web":"manual"}`,children:B.source==="web-login"?"网页登录":B.source==="web-oauth"?"网页 OAuth":B.source==="oauth"?"Codex OAuth":B.source==="antigravity"||B.source==="agy"||B.source==="google-antigravity"?"Antigravity":"导入"})]}),n.jsx("span",{children:B.lastError?`${fm(B.lastErrorCode)}${fm(B.lastErrorCode)?" · ":""}${B.lastError}`:B.lastCheckedAt?`上次检测 ${tl(B.lastCheckedAt)}`:"未检测"}),n.jsxs("span",{children:[B.credentialMode==="refreshable"?"可自动续期":B.credentialMode==="browser-session"?"依赖网页会话":"仅 access token",B.expiresAt?` · 到期 ${tl(B.expiresAt)}`:""]}),n.jsxs("span",{children:["套餐 ",ap(B.planType)]}),B.lastUsedAt&&n.jsxs("span",{children:["最近调用 ",tl(B.lastUsedAt)," · ",B.requestCount||0," 次"]})]}),n.jsx(wp,{limits:B.quotaLimits})]}),n.jsxs("div",{className:"account-pool-meta",children:[n.jsx(_t,{tone:B.status==="healthy"?"healthy":B.status==="invalid"?"disabled":"standby",children:B.status==="healthy"?"可用":B.status==="invalid"?"无效":"未验证"}),n.jsx("button",{type:"button",className:"secondary-button compact-button",disabled:V!=="",onClick:()=>L(h.id,!1,B.id),children:V===`check-account:${B.id}`?"检测中":"检测"}),n.jsx("button",{type:"button",className:"danger-button compact-button",disabled:V!=="",onClick:()=>m(h,B),children:V===`delete-account:${B.id}`?"删除中":"删除"})]})]},B.id)),ot.length===0&&n.jsx(Lt,{text:"没有匹配的账号"}),gt.length>de&&n.jsxs("div",{className:"account-pool-more",children:[n.jsx("span",{className:"muted-inline",children:U?`已显示全部 ${gt.length} 个账号`:`已显示 ${ll.length} 个,还有 ${al} 个`}),n.jsxs("div",{className:"account-pool-more-actions",children:[!U&&n.jsxs("button",{type:"button",className:"secondary-button compact-button",onClick:()=>ee(B=>({...B,[h.id]:Math.min(gt.length,Dt+$)})),children:["再显示 ",Math.min($,al)," 个"]}),!U&&n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:()=>ee(B=>({...B,[h.id]:gt.length})),children:"全部显示"}),Dt>de&&n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:()=>ee(B=>({...B,[h.id]:de})),children:"收起"})]})]})]})]},h.id)}),_.length===0&&n.jsx(Lt,{text:G?"暂无 Antigravity 渠道,先新增一个 Antigravity 账号池":"暂无绘图渠道,先新增一个 OpenAI 账号池渠道"})]}),ye&&n.jsx(Rp,{channelId:ye,variant:G?"antigravity":"openai",onStart:W,onComplete:N,onClose:()=>O("")}),ue&&n.jsx(zp,{busy:V!=="",variant:y,onAuthSession:()=>{ve(ue),Z("")},onAntigravity:()=>{Me(ue),Z("")},onOAuth:()=>{O(ue),Z("")},onImport:async h=>{await A(ue,h),Z("")},onClose:()=>Z("")}),ae&&n.jsx(_p,{onImport:async h=>{await A(ae,new File([JSON.stringify(Op(h))],"authsession.json",{type:"application/json"}))},onClose:()=>ve("")}),Ce&&n.jsx(Up,{onImport:async h=>{await A(Ce,new File([JSON.stringify(Dp(h))],"antigravity.json",{type:"application/json"}))},onClose:()=>Me("")})]})}function zp({busy:u,variant:f="drawing",onAuthSession:p,onAntigravity:r,onOAuth:C,onImport:T,onClose:k}){const W=f==="antigravity";return n.jsx("div",{className:"modal-backdrop",onClick:k,children:n.jsxs("div",{className:"modal-card account-add-modal",onClick:N=>N.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:"添加账号"}),n.jsx("span",{children:"选择一种账号接入方式"})]}),n.jsx("button",{type:"button",className:"icon-button",onClick:k,children:"×"})]}),n.jsxs("div",{className:"account-add-options",children:[W?n.jsxs(n.Fragment,{children:[n.jsxs("button",{type:"button",className:"account-add-option recommended",onClick:C,disabled:u,children:[n.jsx("span",{className:"account-add-icon",children:"G"}),n.jsx("strong",{children:"本地授权登录"}),n.jsx("small",{children:"用 Google 账号登录授权,自动获取 refresh token"})]}),n.jsxs("button",{type:"button",className:"account-add-option",onClick:r,disabled:u,children:[n.jsx("span",{className:"account-add-icon",children:"T"}),n.jsx("strong",{children:"导入 Antigravity 凭据"}),n.jsx("small",{children:"已有 Google OAuth JSON 或 refresh token 时粘贴"})]})]}):n.jsxs("button",{type:"button",className:"account-add-option recommended",onClick:p,disabled:u,children:[n.jsx("span",{className:"account-add-icon",children:"A"}),n.jsx("strong",{children:"导入网页会话"}),n.jsx("small",{children:"粘贴完整 authsession JSON,保留 sessionToken"})]}),n.jsxs("label",{className:`account-add-option${u?" disabled":""}`,children:[n.jsx("span",{className:"account-add-icon",children:"J"}),n.jsx("strong",{children:u?"导入中":"导入 JSON / ZIP / TXT"}),n.jsx("small",{children:"批量导入已有账号文件"}),n.jsx("input",{type:"file",accept:"application/json,application/zip,text/plain,.json,.zip,.txt",disabled:u,onChange:N=>{const y=N.target.files?.[0];y&&T(y),N.target.value=""}})]})]}),n.jsx("div",{className:"modal-actions",children:n.jsx("button",{type:"button",className:"secondary-button",onClick:k,children:"取消"})})]})})}function Op(u){const f=u.trim(),p=f.match(/(?:^|[;\s])(__Secure-(?:next-auth|authjs)\.session-token)=([^;\s]+)/);if(p)return{sessionToken:p[2],source:"web-login"};try{const r=JSON.parse(f),C=r.tokens&&typeof r.tokens=="object"?r.tokens:{},T=G=>typeof r[G]=="string"?r[G]:typeof C[G]=="string"?C[G]:"",k=T("accessToken")||T("access_token"),W=T("refreshToken")||T("refresh_token"),N=T("sessionToken")||T("session_token"),y=r.user&&typeof r.user=="object"?r.user:{};if(k||W||N)return{accessToken:k||void 0,refreshToken:W||void 0,sessionToken:N||void 0,email:typeof y.email=="string"?y.email:void 0,name:typeof y.name=="string"?y.name:void 0,source:"web-login"}}catch{}return{sessionToken:f,source:"web-login"}}function _p({onImport:u,onClose:f}){const[p,r]=b.useState(""),[C,T]=b.useState(!1),[k,W]=b.useState(""),[N,y]=b.useState("");async function G(){if(!p.trim()){W("请粘贴 authsession");return}T(!0),W(""),y("");try{await u(p.trim()),r(""),y("已导入,继续粘贴下一条即可")}catch(_){W(_ instanceof Error?_.message:"导入失败")}finally{T(!1)}}return n.jsx("div",{className:"modal-backdrop",onClick:f,children:n.jsxs("div",{className:"modal-card",onClick:_=>_.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsx("strong",{children:"添加网页会话"}),n.jsx("button",{type:"button",className:"icon-button",onClick:f,children:"×"})]}),n.jsxs("p",{className:"muted-inline",children:["可直接粘贴 chatgpt.com/api/auth/session 的完整 JSON;也支持浏览器 ",n.jsx("code",{children:"__Secure-next-auth.session-token"})," 的值或完整 Cookie 字符串。"]}),n.jsxs("label",{className:"authsession-field",children:[n.jsx("span",{children:"authsession"}),n.jsx("textarea",{autoFocus:!0,value:p,onChange:_=>r(_.target.value),placeholder:"eyJhbGci..."})]}),k&&n.jsx("div",{className:"form-error",children:k}),N&&n.jsx("div",{className:"form-success",children:N}),n.jsxs("div",{className:"modal-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",onClick:f,children:"取消"}),n.jsx("button",{type:"button",className:"primary-button",disabled:C,onClick:G,children:C?"导入中":"导入账号"})]})]})})}function Dp(u){const f=u.trim();try{const p=JSON.parse(f),r=p.tokens&&typeof p.tokens=="object"?p.tokens:{},C=(...y)=>{for(const G of y){if(typeof p[G]=="string"&&p[G])return p[G];if(typeof r[G]=="string"&&r[G])return r[G]}return""},T=C("access_token","accessToken"),k=C("refresh_token","refreshToken"),W=C("email"),N=C("expired","expires_at","expiresAt","expiry");if(T||k)return{accessToken:T||void 0,refreshToken:k||void 0,email:W||void 0,expired:N||void 0,source:"antigravity"}}catch{}return{refreshToken:f,source:"antigravity"}}function Up({onImport:u,onClose:f}){const[p,r]=b.useState(""),[C,T]=b.useState(!1),[k,W]=b.useState(""),[N,y]=b.useState("");async function G(){if(!p.trim()){W("请粘贴 Antigravity OAuth JSON 或 refresh token");return}T(!0),W(""),y("");try{await u(p.trim()),r(""),y("已导入,继续粘贴下一条即可")}catch(_){W(_ instanceof Error?_.message:"导入失败")}finally{T(!1)}}return n.jsx("div",{className:"modal-backdrop",onClick:f,children:n.jsxs("div",{className:"modal-card",onClick:_=>_.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsx("strong",{children:"导入 Antigravity 账号"}),n.jsx("button",{type:"button",className:"icon-button",onClick:f,children:"×"})]}),n.jsxs("p",{className:"muted-inline",children:["粘贴 Antigravity 的 Google OAuth 凭证 JSON(含 ",n.jsx("code",{children:"access_token"})," / ",n.jsx("code",{children:"refresh_token"}),"),或直接粘贴 refresh token。导入后会自动刷新并加入账号池。"]}),n.jsxs("label",{className:"authsession-field",children:[n.jsx("span",{children:"OAuth JSON / refresh token"}),n.jsx("textarea",{autoFocus:!0,value:p,onChange:_=>r(_.target.value),placeholder:'{"access_token":"ya29...","refresh_token":"1//..."}'})]}),k&&n.jsx("div",{className:"form-error",children:k}),N&&n.jsx("div",{className:"form-success",children:N}),n.jsxs("div",{className:"modal-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",onClick:f,children:"取消"}),n.jsx("button",{type:"button",className:"primary-button",disabled:C,onClick:G,children:C?"导入中":"导入账号"})]})]})})}function Rp({channelId:u,variant:f="openai",onStart:p,onComplete:r,onClose:C}){const T=f==="antigravity",[k,W]=b.useState(""),[N,y]=b.useState(""),[G,_]=b.useState(""),[V,P]=b.useState(!1),[fe,ee]=b.useState("");async function me(){P(!0),ee("");try{const se=await p(u);W(se.authorizeUrl),y(se.state),window.open(se.authorizeUrl,"_blank","noopener")}catch(se){ee(se instanceof Error?se.message:"发起授权失败")}finally{P(!1)}}async function ne(){if(!G.trim()){ee("请粘贴授权完成后浏览器跳转的回调地址");return}P(!0),ee("");try{await r(u,{callbackUrl:G.trim(),state:N}),C()}catch(se){ee(se instanceof Error?se.message:"完成授权失败")}finally{P(!1)}}return n.jsx("div",{className:"modal-backdrop",onClick:C,children:n.jsxs("div",{className:"modal-card",onClick:se=>se.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsx("strong",{children:T?"本地授权添加 Antigravity 账号":"OAuth 授权添加网页账号"}),n.jsx("button",{type:"button",className:"icon-button",onClick:C,children:"×"})]}),n.jsx("p",{className:"muted-inline",children:T?"用 Google 账号登录授权 Antigravity 客户端,服务端换取 refresh_token 后加入账号池,凭据只保存在本服务。":"使用 ChatGPT 网页兼容的 OAuth 客户端获取 refresh_token,只调用网页 backend-api,不会走 Codex 接口。"}),n.jsxs("ol",{className:"oauth-steps",children:[n.jsxs("li",{children:[n.jsx("button",{type:"button",className:"primary-button",onClick:me,disabled:V,children:k?"重新生成授权链接":"① 生成授权链接并打开"}),k&&n.jsxs("div",{className:"oauth-link",children:[n.jsx("input",{readOnly:!0,value:k,onFocus:se=>se.target.select()}),n.jsx("span",{className:"muted-inline",children:T?"若未自动打开,复制到浏览器手动访问,用要添加的 Google 账号登录授权。":"若未自动打开,复制到浏览器手动访问,用要添加的 ChatGPT 账号登录授权。"})]})]}),n.jsxs("li",{children:[n.jsx("label",{children:"② 粘贴授权后浏览器跳转的完整回调地址"}),n.jsx("input",{value:G,placeholder:T?"http://localhost:8788/oauth2callback?code=...&state=...":"https://platform.openai.com/auth/callback?code=...&state=...",onChange:se=>_(se.target.value),disabled:!k||V})]})]}),fe&&n.jsx("p",{className:"form-error",children:fe}),n.jsxs("div",{className:"modal-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",onClick:C,disabled:V,children:"取消"}),n.jsx("button",{type:"button",className:"primary-button",onClick:ne,disabled:!k||V,children:V?"处理中":"完成授权"})]})]})})}function wp({limits:u}){const f=je(u).filter(p=>p.label||p.name).slice(0,3);return f.length?n.jsx("div",{className:"quota-bars",children:f.map(p=>{const r=Hp(p);return n.jsxs("div",{className:"quota-bar",children:[n.jsxs("div",{className:"quota-bar-label",children:[n.jsx("strong",{children:p.label||p.name}),n.jsx("span",{children:Bp(p,r)})]}),n.jsx("div",{className:"quota-bar-track",children:n.jsx("span",{style:{width:`${r}%`}})})]},`${p.label||p.name}-${p.resetAt||""}`)})}):null}function Hp(u){return typeof u.percentRemaining=="number"&&Number.isFinite(u.percentRemaining)?Math.max(0,Math.min(100,u.percentRemaining)):typeof u.remaining=="number"&&typeof u.limit=="number"&&u.limit>0?Math.max(0,Math.min(100,u.remaining/u.limit*100)):typeof u.used=="number"&&typeof u.limit=="number"&&u.limit>0?Math.max(0,Math.min(100,(u.limit-u.used)/u.limit*100)):0}function Bp(u,f){const p=u.resetAt?` · ${tl(u.resetAt)}`:"";return typeof u.remaining=="number"?`${Math.round(f)}% 剩余${p}`:`${Math.round(f)}%${p}`}function qp(u){const f=je(u.models).join(" ").toLowerCase(),p=["对话"];u.streamMode!=="disabled"&&p.push("流式"),/(image|dall-e|gpt-image)/.test(f)&&p.push("图片"),(u.openaiAccountCount??u.openaiAccounts?.length??0)>0&&p.push("账号池");const r=u.upstreamKeyCount??0;return r>1&&p.push(`${r} Key 轮询`),p}function Gp(u){if(u.status==="invalid"||u.credentialMode==="browser-session")return!0;if(!u.expiresAt)return!1;const f=new Date(u.expiresAt).getTime();return Number.isFinite(f)&&f-Date.now()<=1440*60*1e3}function kp({channels:u,groups:f,onUpdate:p,onCreate:r,onImport:C,onDelete:T,onSyncModels:k,onCheck:W}){const N=Ta("openai"),[y,G]=b.useState(!1),[_,V]=b.useState(N.provider),[P,fe]=b.useState(N.name),[ee,me]=b.useState(N.baseUrl),[ne,se]=b.useState(N.models.join(", ")),[Y,xe]=b.useState(""),[te,ye]=b.useState(""),[O,ae]=b.useState(!1),[ve,Ce]=b.useState(!1);function Me(Z){const de=Ta(Z);V(de.provider),fe(de.name),me(de.baseUrl),se(de.models.join(", ")),ye("")}async function ue(Z){Z.preventDefault(),ae(!0),ye("");try{await r({name:P.trim()||Ta(_).name,provider:_,baseUrl:ee.trim(),...Nm(Y),models:Pc(ne),streamMode:"auto"}),G(!1),xe(""),Me(_)}catch(de){ye(de instanceof Error?de.message:"渠道创建失败")}finally{ae(!1)}}return n.jsxs(lt,{title:"渠道",children:[n.jsxs("div",{className:"channel-page-intro",children:[n.jsxs("div",{children:[n.jsx("strong",{children:"管理上游服务"}),n.jsx("span",{children:"每个渠道对应一个 API 上游。先添加渠道,再检测连通性并同步可用模型。"})]}),n.jsxs("div",{className:"channel-page-summary",children:[n.jsxs("span",{children:[n.jsx("b",{children:u.length})," 个渠道"]}),n.jsxs("span",{children:[n.jsx("b",{children:u.filter(Z=>Z.status!=="disabled").length})," 个已启用"]})]})]}),n.jsxs("div",{className:"panel-toolbar channel-toolbar",children:[n.jsx("span",{className:"muted-inline",children:"列表显示当前状态;点击任一渠道可修改连接、模型和计费设置。"}),n.jsx("button",{className:"primary-button",onClick:()=>G(Z=>!Z),children:y?"取消新增":"+ 新增渠道"})]}),y&&n.jsxs("form",{className:"channel-card channel-create-form",onSubmit:ue,children:[n.jsxs("label",{className:"channel-select-field",children:[n.jsx("span",{children:"选择渠道类型"}),n.jsxs("details",{className:"channel-choice-menu",children:[n.jsxs("summary",{children:[n.jsx("span",{children:Ta(_).label}),n.jsx("small",{children:"选择后自动填入建议配置"})]}),n.jsx("div",{role:"listbox","aria-label":"选择渠道类型",children:Fc.map(Z=>n.jsxs("button",{type:"button",className:_===Z.provider?"selected":"",onClick:de=>{Me(Z.provider),de.currentTarget.closest("details")?.removeAttribute("open")},children:[n.jsx("strong",{children:Z.label}),n.jsx("span",{children:"使用推荐的名称和地址"})]},Z.provider))})]})]}),n.jsxs("div",{className:"channel-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"渠道名称"}),n.jsx("input",{value:P,onChange:Z=>fe(Z.target.value),placeholder:"例如 OpenAI 主线路"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"供应商"}),n.jsx("input",{value:cl(_),readOnly:!0})]}),n.jsxs("label",{className:"channel-form-wide",children:[n.jsx("span",{children:"Base URL"}),n.jsx("input",{value:ee,onChange:Z=>me(Z.target.value),placeholder:"https://provider.example/v1"})]}),n.jsxs("label",{className:"channel-form-wide",children:[n.jsx("span",{children:"上游 Key"}),n.jsx("textarea",{className:"channel-key-input",value:Y,onChange:Z=>xe(Z.target.value),placeholder:_==="codex"?"账号池导入后使用":_==="cpa"?"填写 CPA 的 API key,多个每行一个":"每行一个 Key;填多个会自动轮询分发",autoComplete:"off",rows:3})]}),n.jsxs("div",{className:"channel-form-wide channel-model-field",children:[n.jsxs("div",{className:"field-label-row",children:[n.jsx("span",{children:"模型"}),n.jsx("button",{type:"button",className:"model-pull-button",onClick:()=>{if(_!=="codex"&&!ee.trim()){ye("请先填写 Base URL 再获取模型");return}ye(""),Ce(!0)},children:"从上游获取模型"})]}),n.jsx("textarea",{value:ne,onChange:Z=>se(Z.target.value),placeholder:"多个模型用逗号分隔,或点上方『从上游获取模型』拉取后多选"})]})]}),n.jsxs("div",{className:"channel-card-actions",children:[n.jsx("span",{className:"model-create-message",role:"status",children:te}),n.jsx("button",{className:"secondary-button",type:"button",onClick:()=>Me(_),disabled:O,children:"填入模板"}),n.jsx("button",{className:"primary-button",type:"submit",disabled:O,children:O?"创建中":"创建渠道"})]})]}),y&&ve&&n.jsx(Am,{subtitle:`${P.trim()||Ta(_).name} · 勾选需要接入的模型`,current:Pc(ne),loadModels:async()=>{const Z=await pe("/api/channel-model-preview",{method:"POST",body:JSON.stringify({provider:_,baseUrl:ee.trim(),upstreamApiKey:Y})});return je(Z.models)},onConfirm:async Z=>{se(Z.join(", "))},onClose:()=>Ce(!1)}),n.jsxs("div",{className:"channels-stack",children:[u.map(Z=>n.jsx(Yp,{channel:Z,groups:f,onUpdate:p,onImport:C,onDelete:T,onSyncModels:k,onCheck:W},Z.id)),u.length===0&&n.jsx(Lt,{text:"暂无渠道,先在后端添加渠道接口或导入配置"})]})]})}function Yp({channel:u,groups:f,onUpdate:p,onImport:r,onDelete:C,onSyncModels:T,onCheck:k}){const[W,N]=b.useState(u.name),[y,G]=b.useState(u.provider),[_,V]=b.useState(u.streamMode||"auto"),[P,fe]=b.useState(u.baseUrl),[ee,me]=b.useState(je(u.allowedGroupIds)),[ne,se]=b.useState(je(u.models).join(", ")),[Y,xe]=b.useState("saved"),[te,ye]=b.useState(String(u.inputPricePer1K||0)),[O,ae]=b.useState(String(u.outputPricePer1K||0)),[ve,Ce]=b.useState(!!u.webEndpoint),[Me,ue]=b.useState(""),[Z,de]=b.useState(""),[$,A]=b.useState(!1),L=u.openaiAccountCount??u.openaiAccounts?.length??0,H=je(u.models).length,X=qp(u),ie=u.status==="disabled",m={saved:"已保存",template:"模板",manual:"手动",synced:"上游同步"}[Y],h=Ni.find(I=>I.value===_)||Ni[0],M={auto:"自动处理(推荐)",real:"强制流式",fake:"兼容流式",disabled:"关闭流式"};b.useEffect(()=>{N(u.name),G(u.provider),V(u.streamMode||"auto"),fe(u.baseUrl),me(je(u.allowedGroupIds)),se(je(u.models).join(", ")),xe("saved"),ye(String(u.inputPricePer1K||0)),ae(String(u.outputPricePer1K||0)),Ce(!!u.webEndpoint),ue("")},[u.id,u.name,u.provider,u.streamMode,u.baseUrl,u.models,u.inputPricePer1K,u.outputPricePer1K,u.webEndpoint]);async function Q(){const I=le();de("save");try{await p(u.id,I),ue("")}finally{de("")}}function le(){const I=Ei(y),Ve=!/^https?:\/\//i.test(P.trim())&&I?I:P,ot={name:W.trim()||u.name,provider:y,streamMode:_,baseUrl:Ve,inputPricePer1K:Number(te)||0,outputPricePer1K:Number(O)||0,webEndpoint:ve,models:ne.split(",").map(Je=>Je.trim()).filter(Boolean),allowedGroupIds:ee};return Object.assign(ot,Nm(Me)),ot}async function Ne(){const I=u.status==="disabled"?"healthy":"disabled";de("status");try{await p(u.id,{...le(),status:I}),ue("")}finally{de("")}}async function z(){de("sync");try{await p(u.id,le()),ue(""),A(!0)}finally{de("")}}function be(){const I=Ta(y);se(I.models.join(", ")),xe("template"),I.baseUrl&&!/^https?:\/\//i.test(P.trim())&&fe(I.baseUrl)}async function ce(){de("check");try{await Q(),await k(u.id)}finally{de("")}}async function jt(I){de("import");try{await r(u.id,I)}finally{de("")}}return n.jsxs(n.Fragment,{children:[n.jsxs("details",{className:"channel-card channel-card-collapsible",children:[n.jsxs("summary",{className:"channel-card-head channel-list-row",children:[n.jsxs("div",{className:"channel-identity",children:[n.jsx("strong",{children:u.name}),n.jsx("span",{children:cl(y)}),n.jsx("small",{children:u.baseUrl||"尚未配置上游地址"}),n.jsx("div",{className:"channel-capability-tags",children:X.map(I=>n.jsx("span",{children:I},I))})]}),n.jsxs("div",{className:"channel-list-meta",children:[n.jsxs("span",{children:[n.jsx("b",{children:H})," 个模型"]}),L>0&&n.jsxs("span",{children:[n.jsx("b",{children:L})," 个账号"]})]}),n.jsxs("div",{className:"channel-check-result",children:[n.jsx("span",{children:"连通性"}),n.jsx("b",{className:u.lastError?"is-error":u.lastCheckedAt?"is-ok":"",children:u.lastError?"检测失败":u.lastCheckedAt?`已检测 ${tl(u.lastCheckedAt)}`:"尚未检测"})]}),n.jsxs("div",{className:"channel-list-status",children:[n.jsx(_t,{tone:u.status,children:ie?"已停用":Ot(u.status)}),n.jsx("span",{className:"channel-expand-hint",children:"配置"})]})]}),n.jsxs("div",{className:"channel-editor-controls",children:[n.jsxs("label",{className:"channel-select-field",children:[n.jsx("span",{children:"供应商"}),n.jsxs("details",{className:"channel-choice-menu",children:[n.jsxs("summary",{children:[n.jsx("span",{children:cl(y)}),n.jsx("small",{children:"修改上游协议类型"})]}),n.jsx("div",{role:"listbox","aria-label":"供应商",children:to.map(I=>n.jsxs("button",{type:"button",className:y===I.value?"selected":"",onClick:Ve=>{G(I.value);const ot=Ei(I.value);ot&&!/^https?:\/\//i.test(P.trim())&&fe(ot),Ve.currentTarget.closest("details")?.removeAttribute("open")},children:[n.jsx("strong",{children:I.label}),n.jsx("span",{children:I.value==="compatible"?"适用于兼容 OpenAI 格式的服务":"选择对应的上游协议"})]},I.value))})]})]}),n.jsxs("label",{className:"channel-select-field",children:[n.jsx("span",{children:"响应方式"}),n.jsxs("details",{className:"channel-choice-menu",children:[n.jsxs("summary",{children:[n.jsx("span",{children:M[h.value]}),n.jsx("small",{children:h.description})]}),n.jsx("div",{role:"listbox","aria-label":"响应方式",children:Ni.map(I=>n.jsxs("button",{type:"button",className:_===I.value?"selected":"",onClick:Ve=>{V(I.value),Ve.currentTarget.closest("details")?.removeAttribute("open")},children:[n.jsx("strong",{children:M[I.value]}),n.jsx("span",{children:I.description})]},I.value))})]})]})]}),(y==="codex"||L>0)&&n.jsxs("div",{className:"setting",children:[n.jsxs("div",{children:[n.jsx("span",{children:"网页对话接口"}),n.jsx("small",{children:"开启后走 ChatGPT 网页对话接口,把 Plus 订阅账号包装成 API"})]}),n.jsx("div",{className:"setting-value",children:n.jsx("button",{type:"button",className:ve?"ios-switch is-on":"ios-switch","aria-label":ve?"关闭网页对话接口":"开启网页对话接口","aria-pressed":ve,onClick:()=>Ce(I=>!I),children:n.jsx("span",{})})})]}),n.jsxs("div",{className:"channel-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"渠道名称"}),n.jsx("input",{value:W,onChange:I=>N(I.target.value),placeholder:"例如 Gemini 主线路"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"供应商"}),n.jsx("input",{value:cl(y),readOnly:!0})]}),n.jsxs("label",{className:"channel-form-wide",children:[n.jsx("span",{children:"Base URL"}),n.jsx("input",{value:P,onChange:I=>fe(I.target.value),placeholder:"https://provider.example/v1"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"优先级"}),n.jsx("input",{value:u.priority,readOnly:!0})]}),n.jsxs("div",{className:"channel-form-wide channel-model-field",children:[n.jsxs("div",{className:"field-label-row",children:[n.jsx("span",{children:"模型"}),n.jsxs("small",{children:["来源:",m]})]}),n.jsx("textarea",{value:ne,onChange:I=>{se(I.target.value),xe("manual")},placeholder:"优先拉取上游模型,也可以手动补充,多个用逗号分隔"}),n.jsxs("div",{className:"channel-model-actions",children:[n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:be,disabled:Z!=="",children:"填入模板"}),n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:z,disabled:Z!=="",children:Z==="sync"?"拉取中":"获取上游模型"})]})]}),n.jsxs("label",{className:"channel-form-wide",children:[n.jsxs("span",{children:["上游 Key",(u.upstreamKeyCount??0)>0?` (已配置 ${u.upstreamKeyCount} 个)`:u.upstreamKeySet?" (已配置)":""]}),n.jsx("textarea",{className:"channel-key-input",value:Me,onChange:I=>ue(I.target.value),placeholder:y==="codex"?"Codex 账号池不需要上游 Key":y==="cpa"?"填写 CPA 的 API key,多个每行一个":"每行一个 Key;填多个会自动轮询分发;留空不修改",autoComplete:"off",rows:3})]}),n.jsxs("label",{children:[n.jsx("span",{children:"输入单价 / 1K Token"}),n.jsx("input",{type:"number",min:"0",step:"0.0001",value:te,onChange:I=>ye(I.target.value)})]}),n.jsxs("label",{children:[n.jsx("span",{children:"输出单价 / 1K Token"}),n.jsx("input",{type:"number",min:"0",step:"0.0001",value:O,onChange:I=>ae(I.target.value)})]}),n.jsx("span",{className:"channel-billing-note",children:"定价可先留空;接入是否可用优先看渠道检测和模型同步结果。"})]}),n.jsxs("div",{className:"channel-group-field",children:[n.jsxs("div",{className:"field-label-row",children:[n.jsx("span",{children:"可见分组"}),n.jsx("small",{children:ee.length?`已选择 ${ee.length} 个分组`:"全部用户可用"})]}),f.length===0?n.jsx("p",{className:"channel-group-empty",children:"还没有用户分组。去「分组」页创建后,可在这里把渠道限制为只对特定分组开放。"}):n.jsx("div",{className:"channel-group-options",children:f.map(I=>{const Ve=ee.includes(I.id);return n.jsxs("button",{type:"button",className:Ve?"selected":"","aria-pressed":Ve,onClick:()=>me(ot=>Ve?ot.filter(Je=>Je!==I.id):[...ot,I.id]),children:[n.jsx("span",{children:I.name}),I.description&&n.jsx("small",{children:I.description})]},I.id)})})]}),n.jsxs("div",{className:"channel-card-actions",children:[n.jsx("button",{className:"secondary-button",onClick:ce,disabled:Z!=="",children:Z==="check"?"检测中":"检测渠道"}),n.jsx("button",{className:"primary-button",onClick:Q,disabled:Z!=="",children:Z==="save"?"保存中":"保存"}),n.jsxs("details",{className:"channel-more-actions",children:[n.jsx("summary",{children:"更多操作"}),n.jsxs("div",{children:[n.jsxs("label",{className:"secondary-button",children:[Z==="import"?"导入中":"导入账号 JSON",n.jsx("input",{type:"file",accept:"application/json,application/zip,text/plain,.json,.zip,.txt",disabled:Z!=="",onChange:I=>{const Ve=I.target.files?.[0];Ve&&jt(Ve),I.target.value=""}})]}),n.jsx("button",{className:"secondary-button",onClick:Ne,disabled:Z!=="",children:u.status==="disabled"?"启用渠道":"停用渠道"}),n.jsx("button",{className:"danger-button",onClick:()=>C(u.id),disabled:Z!=="",children:"删除渠道"})]})]})]})]}),$&&n.jsx(Am,{subtitle:`${u.name} · 勾选需要接入的模型`,current:ne.split(",").map(I=>I.trim()).filter(Boolean),loadModels:async()=>{const I=await pe(`/api/channels/${u.id}/upstream-models`,{method:"POST",body:JSON.stringify({})});return je(I.models)},onConfirm:async I=>{await T(u.id,I)},onClose:()=>A(!1)})]})}function Am({subtitle:u,current:f,loadModels:p,onConfirm:r,onClose:C}){const[T,k]=b.useState(!0),[W,N]=b.useState(""),[y,G]=b.useState([]),[_,V]=b.useState(new Set),[P,fe]=b.useState(""),[ee,me]=b.useState(!1);b.useEffect(()=>{let O=!1;return(async()=>{k(!0),N("");try{const ae=await p();if(O)return;const ve=new Set,Ce=je(ae).map(ue=>ue.trim()).filter(ue=>{if(!ue)return!1;const Z=ue.toLowerCase();return ve.has(Z)?!1:(ve.add(Z),!0)}),Me=new Set(f.map(ue=>ue.toLowerCase()));G(Ce),V(new Set(Ce.filter(ue=>Me.has(ue.toLowerCase()))))}catch(ae){O||N(ae instanceof Error?ae.message:"获取上游模型失败")}finally{O||k(!1)}})(),()=>{O=!0}},[]);const ne=P.trim().toLowerCase(),se=ne?y.filter(O=>O.toLowerCase().includes(ne)):y,Y=se.length>0&&se.every(O=>_.has(O));function xe(O){V(ae=>{const ve=new Set(ae);return ve.has(O)?ve.delete(O):ve.add(O),ve})}function te(){V(O=>{const ae=new Set(O);return Y?se.forEach(ve=>ae.delete(ve)):se.forEach(ve=>ae.add(ve)),ae})}async function ye(){const O=new Set(y.map(ue=>ue.toLowerCase())),ae=f.filter(ue=>!O.has(ue.toLowerCase())),ve=y.filter(ue=>_.has(ue)),Ce=new Set,Me=[...ae,...ve].filter(ue=>{const Z=ue.toLowerCase();return Ce.has(Z)?!1:(Ce.add(Z),!0)});me(!0);try{await r(Me),C()}catch{me(!1)}}return n.jsx("div",{className:"modal-backdrop",onClick:C,children:n.jsxs("div",{className:"modal-card model-picker-modal",onClick:O=>O.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:"选择上游模型"}),n.jsx("span",{children:u})]}),n.jsx("button",{type:"button",className:"icon-button",onClick:C,children:"×"})]}),T?n.jsx("div",{className:"model-picker-status",children:"正在获取上游模型…"}):W?n.jsx("div",{className:"model-picker-status model-picker-error",children:W}):n.jsxs(n.Fragment,{children:[n.jsxs("div",{className:"model-picker-toolbar",children:[n.jsx("input",{className:"model-picker-search",value:P,onChange:O=>fe(O.target.value),placeholder:"搜索模型名称",autoFocus:!0}),n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:te,disabled:se.length===0,children:Y?"取消全选":"全选"})]}),n.jsxs("div",{className:"model-picker-count",children:["共 ",y.length," 个 · 已选 ",_.size," 个",ne?` · 匹配 ${se.length} 个`:""]}),n.jsxs("div",{className:"model-picker-list",children:[se.map(O=>{const ae=_.has(O),ve=f.some(Ce=>Ce.toLowerCase()===O.toLowerCase());return n.jsxs("label",{className:`model-picker-row${ae?" checked":""}`,children:[n.jsx("input",{type:"checkbox",checked:ae,onChange:()=>xe(O)}),n.jsx("span",{className:"model-picker-name",children:O}),ve&&n.jsx("span",{className:"model-picker-tag",children:"已接入"})]},O)}),se.length===0&&n.jsx("div",{className:"model-picker-status",children:"没有匹配的模型"})]})]}),n.jsxs("div",{className:"modal-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",onClick:C,children:"取消"}),n.jsx("button",{type:"button",className:"primary-button",disabled:T||!!W||ee,onClick:ye,children:ee?"保存中":`导入所选 (${_.size})`})]})]})})}function Lp({logs:u,onCopy:f}){const[p,r]=b.useState(u),[C,T]=b.useState(u.length),[k,W]=b.useState(1),[N,y]=b.useState(""),[G,_]=b.useState("all"),[V,P]=b.useState(null),[fe,ee]=b.useState(!1),[me,ne]=b.useState(!1),se=25,Y=Math.max(1,Math.ceil(C/se));b.useEffect(()=>{W(1)},[N,G]),b.useEffect(()=>{k>Y&&W(Y)},[k,Y]),b.useEffect(()=>{const te=new AbortController,ye=window.setTimeout(async()=>{ee(!0);try{const O=new URLSearchParams({page:String(k),pageSize:String(se),status:G,q:N.trim()}),ae=await pe(`/api/logs?${O}`,{signal:te.signal}),ve=je(ae.logs);r(ve),T(ae.total||0),P(Ce=>Ce&&ve.some(Me=>Me.id===Ce.id)?Ce:null)}catch(O){O instanceof DOMException&&O.name==="AbortError"||(r([]),T(0))}finally{te.signal.aborted||ee(!1)}},N?250:0);return()=>{window.clearTimeout(ye),te.abort()}},[k,N,G]);async function xe(te){if(V?.id===te.id){P(null);return}P(te),ne(!0);try{const ye=await pe(`/api/logs/${encodeURIComponent(te.id)}`);P(ye.log)}catch{P(te)}finally{ne(!1)}}return n.jsxs(lt,{title:"调用日志",children:[n.jsxs("div",{className:"logs-toolbar",children:[n.jsxs("div",{className:"search-box",children:[n.jsx(zt,{name:"search"}),n.jsx("input",{value:N,onChange:te=>y(te.target.value),placeholder:"搜索请求 ID、用户、Key、模型、渠道或错误码"})]}),n.jsx("div",{className:"log-status-filter",role:"group","aria-label":"日志状态筛选",children:[{value:"all",label:"全部"},{value:"success",label:"成功"},{value:"failed",label:"失败"}].map(te=>n.jsx("button",{type:"button",className:G===te.value?"selected":"",onClick:()=>_(te.value),children:te.label},te.value))}),n.jsx("span",{className:"muted-inline",children:fe?"加载中":`共 ${C} 条`})]}),n.jsxs("div",{className:V?"logs-layout has-detail":"logs-layout",children:[n.jsxs("div",{className:"table",children:[n.jsxs("div",{className:"table-head logs-table",children:[n.jsx("span",{children:"请求"}),n.jsx("span",{children:"模型"}),n.jsx("span",{children:"渠道"}),n.jsx("span",{children:"状态"})]}),p.map(te=>n.jsx("div",{className:"log-entry",children:n.jsxs("div",{className:V?.id===te.id?"table-row logs-table selected":"table-row logs-table",role:"button",tabIndex:0,onClick:()=>xe(te),onKeyDown:ye=>{(ye.key==="Enter"||ye.key===" ")&&xe(te)},children:[n.jsxs("span",{children:[n.jsx("strong",{children:lo(te)}),n.jsxs("small",{children:[te.id," · ",tl(te.createdAt)," · ",te.latencyMs,"ms"]})]}),n.jsx("span",{children:up(te)}),n.jsx("span",{children:cp(te)}),n.jsx(_t,{tone:te.status,children:Ot(te.status)})]})},te.id)),!fe&&p.length===0&&n.jsx(Lt,{text:N||G!=="all"?"没有匹配的日志":"暂无调用日志"})]}),V&&n.jsx(Qp,{log:V,loading:me,onCopy:f})]}),Y>1&&n.jsxs("div",{className:"pagination-bar",children:[n.jsx("button",{className:"secondary-button",disabled:k<=1||fe,onClick:()=>W(te=>Math.max(1,te-1)),children:"上一页"}),n.jsxs("span",{children:[k," / ",Y]}),n.jsx("button",{className:"secondary-button",disabled:k>=Y||fe,onClick:()=>W(te=>Math.min(Y,te+1)),children:"下一页"})]})]})}function Qp({log:u,loading:f,onCopy:p}){if(!u)return n.jsx("aside",{className:"log-inspector empty-inspector",children:n.jsx("span",{children:"选择一条日志查看详情"})});const r=Number(u.inputTokens||0),C=Number(u.outputTokens||0),T=typeof u.attempts=="number"?Math.max(0,u.attempts):null,k=[["请求 ID",u.id],["状态",Ot(u.status)],["时间",ip(u.createdAt)],["用户 ID",u.userId||"未识别"],["API Key",u.apiKeyPrefix?`${u.apiKeyPrefix}***`:"未识别"],["模型",u.model||"未提供"],["渠道",u.channel||"未选择"],["实际账号",u.account||"未记录"],["响应耗时",`${u.latencyMs} ms`],["尝试次数",T===null?"未记录":String(T)],["是否重试",T===null?"未记录":T>1?"是":"否"],["输入 Tokens",pl(r)],["输出 Tokens",pl(C)],["总 Tokens",pl(r+C)],["扣费",u.cost.toFixed(4)],["错误码",u.errorCode||"无"]];return n.jsxs("aside",{className:"log-inspector",children:[n.jsxs("header",{children:[n.jsxs("div",{children:[n.jsx("span",{children:f?"加载中":"日志详情"}),n.jsx("strong",{children:lo(u)})]}),n.jsx(_t,{tone:u.status,children:Ot(u.status)})]}),n.jsx("div",{className:"log-detail",children:k.map(([W,N])=>n.jsxs("div",{children:[n.jsx("span",{children:W}),n.jsx("strong",{title:N,children:N})]},W))}),n.jsxs("div",{className:"log-actions",children:[n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:()=>p(u.id,"请求 ID 已复制"),children:"复制请求 ID"}),u.errorCode&&n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:()=>p(u.errorCode||"","错误码已复制"),children:"复制错误码"})]})]})}function Xp({models:u,channels:f,groups:p}){const[r,C]=b.useState(null),[T,k]=b.useState(null),[W,N]=b.useState("username"),[y,G]=b.useState("0"),[_,V]=b.useState(""),[P,fe]=b.useState({enabled:!0,minReward:.1,maxReward:1}),[ee,me]=b.useState({logRetentionDays:30,maxLogs:1e4,maxQuotaEntries:2e4}),[ne,se]=b.useState(null),[Y,xe]=b.useState(null),[te,ye]=b.useState(""),[O,ae]=b.useState(""),[ve,Ce]=b.useState(""),[Me,ue]=b.useState(""),[Z,de]=b.useState(""),[$,A]=b.useState(""),[L,H]=b.useState(""),[X,ie]=b.useState(""),[m,h]=b.useState(""),[M,Q]=b.useState(!1),[le,Ne]=b.useState("system"),z=u.find(U=>U.recommended&&U.status==="available")?.id||u.find(U=>U.status==="available")?.id||"未配置",be=f.filter(U=>U.status!=="disabled").length,ce=[{value:"system",label:"系统",description:"运行概况"},{value:"cli",label:"CLI 接入",description:"一键配置"},{value:"auth",label:"注册",description:"开放方式"},{value:"check-in",label:"签到",description:"奖励范围"},{value:"admin",label:"管理员",description:"账号绑定"},{value:"discord",label:"Discord",description:"登录限制"},{value:"maintenance",label:"维护",description:"日志保留"},{value:"backup",label:"备份",description:"导出恢复"}],jt=ce.find(U=>U.value===le)||ce[0];b.useEffect(()=>{Promise.all([pe("/api/settings/discord"),pe("/api/settings/auth"),pe("/api/settings/check-in"),pe("/api/account/me"),pe("/api/settings/maintenance"),pe("/api/health")]).then(([U,B,Be,We,at,Pe])=>{C(Wc(U.discord)),ie(je(U.discord.blockedGuildIds).join(` +`)),k(B.auth.registrationEnabled),N(Mi(B.auth.registrationMode)),G(String(B.auth.defaultBalance||0)),V(B.auth.defaultGroupId||""),fe(Be.checkIn),xe(We.account),ye(We.account?.username||""),ae(We.user.name||""),Ce(We.account?.email||""),ue(We.account?.discordUserId||""),me(at.maintenance),se(Pe)}).catch(()=>h("设置加载失败"))},[]);async function I(U=T,B=W,Be=Number(y),We=_){if(U!==null)try{const at=await pe("/api/settings/auth",{method:"PATCH",body:JSON.stringify({registrationEnabled:U,registrationMode:B,defaultBalance:Be,defaultGroupId:We})});k(at.auth.registrationEnabled),N(Mi(at.auth.registrationMode)),G(String(at.auth.defaultBalance||0)),V(at.auth.defaultGroupId||""),h(at.auth.registrationEnabled?"注册设置已保存":"已关闭用户注册")}catch(at){h(at instanceof Error?at.message:"注册设置保存失败")}}async function Ve(){T!==null&&I(!T,W)}async function ot(){Q(!0),h("");try{const U=await pe("/api/settings/check-in",{method:"PATCH",body:JSON.stringify(P)});fe(U.checkIn),h(U.checkIn.enabled?"签到奖励设置已保存":"已关闭每日签到")}catch(U){h(U instanceof Error?U.message:"签到设置保存失败")}finally{Q(!1)}}async function Je(){if(r){Q(!0),h("");try{const U=Wc(r),B=X.split(/[\s,]+/).map(We=>We.trim()).filter(Boolean),Be=await pe("/api/settings/discord",{method:"PATCH",body:JSON.stringify({...U,blockedGuildIds:B,clientSecret:L})});C(Wc(Be.discord)),ie(je(Be.discord.blockedGuildIds).join(` +`)),H(""),h("Discord 配置已保存")}catch(U){h(U instanceof Error?U.message:"保存失败,请检查填写内容")}finally{Q(!1)}}}async function gt(){try{const U=await pe("/api/account/profile",{method:"PATCH",body:JSON.stringify({username:te,displayName:O,email:ve,discordUserId:Me,currentPassword:Z,newPassword:$})});xe(U.account),ye(U.account.username),Ce(U.account.email||""),ue(U.account.discordUserId||""),de(""),A(""),h("管理员账号已保存")}catch(U){h(U instanceof Error?U.message:"账号设置保存失败")}}async function Dt(){Q(!0),h("");try{const U=await pe("/api/settings/maintenance",{method:"PATCH",body:JSON.stringify(ee)});me(U.maintenance),h("维护设置已保存,历史数据已按新规则清理")}catch(U){h(U instanceof Error?U.message:"维护设置保存失败")}finally{Q(!1)}}async function ll(){Q(!0),h("");try{const U=await fetch("/api/backup",{credentials:"include"});if(!U.ok)throw new Error("备份导出失败");const B=await U.blob(),We=(U.headers.get("Content-Disposition")||"").match(/filename="([^"]+)"/)?.[1]||"capi-backup.json",at=URL.createObjectURL(B),Pe=document.createElement("a");Pe.href=at,Pe.download=We,Pe.click(),URL.revokeObjectURL(at),h("备份已导出,请妥善保管")}catch(U){h(U instanceof Error?U.message:"备份导出失败")}finally{Q(!1)}}async function al(U){if(window.confirm("恢复会覆盖当前全部数据,并退出现有登录会话。确定继续?")){Q(!0),h("");try{const B=await fetch("/api/restore",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:U}),Be=await B.json().catch(()=>null);if(!B.ok)throw new Error(Be?.error?.message||"备份恢复失败");h(`已恢复 ${Be.users} 个用户、${Be.channels} 条渠道和 ${Be.models} 个模型,请重新登录`)}catch(B){h(B instanceof Error?B.message:"备份恢复失败")}finally{Q(!1)}}}return n.jsxs("div",{className:"settings-layout",children:[n.jsx("div",{className:"settings-tabs",children:ce.map(U=>n.jsxs("button",{type:"button",className:le===U.value?"selected":"",onClick:()=>Ne(U.value),children:[n.jsx("strong",{children:U.label}),n.jsx("small",{children:U.description})]},U.value))}),n.jsxs("div",{className:"settings-tab-note",children:[n.jsx("strong",{children:jt.label}),n.jsx("span",{children:jt.description})]}),le==="system"&&n.jsx(lt,{title:"系统设置",children:n.jsxs("div",{className:"settings-group",children:[n.jsx(el,{label:"接口兼容",value:"OpenAI API"}),n.jsx(el,{label:"当前默认模型",value:z}),n.jsx(el,{label:"已配置渠道",value:`${f.length} 个,${be} 个启用`}),n.jsx(el,{label:"可选供应商",value:`${to.length} 种`}),n.jsx(el,{label:"运行版本",value:`${ne?.version||"未知"} · ${ne?.commit||"未知"}`}),n.jsx(el,{label:"构建时间",value:ne?.buildTime?tl(ne.buildTime):"本地构建"}),n.jsx(el,{label:"账号自动检测",value:"每 15 分钟自动检测一次"})]})}),le==="cli"&&n.jsxs(lt,{title:"CLI 工具接入",children:[n.jsx("p",{className:"cli-intro",children:"CAPI 兼容 OpenAI 和 Anthropic 协议,常见 AI 命令行工具可直接接入。"}),n.jsxs("div",{className:"cli-credentials",children:[n.jsxs("div",{className:"cli-credential",children:[n.jsx("span",{children:"Base URL"}),n.jsx("code",{children:wl()}),n.jsx("button",{type:"button",className:"copy-button","aria-label":"复制",onClick:()=>{Ai(wl()),h("已复制 Base URL")},children:n.jsx(zt,{name:"copy"})})]}),n.jsxs("div",{className:"cli-credential",children:[n.jsx("span",{children:"API Key"}),n.jsx("code",{children:"cat_你的_api_key"})]})]}),n.jsxs("div",{className:"cli-tools",children:[n.jsxs("details",{className:"cli-tool",open:!0,children:[n.jsxs("summary",{children:[n.jsx("strong",{children:"Claude Code"}),n.jsx("span",{children:"Anthropic Messages 协议"})]}),n.jsx("pre",{children:`export ANTHROPIC_BASE_URL="${wl()}" +export ANTHROPIC_AUTH_TOKEN="cat_你的_api_key" +export ANTHROPIC_MODEL="${z}" +claude`})]}),n.jsxs("details",{className:"cli-tool",children:[n.jsxs("summary",{children:[n.jsx("strong",{children:"Codex CLI"}),n.jsx("span",{children:"OpenAI Chat 协议"})]}),n.jsxs("p",{children:["编辑 ",n.jsx("code",{children:"~/.codex/config.toml"}),":"]}),n.jsx("pre",{children:`model = "${z}" +model_provider = "capi" + +[model_providers.capi] +name = "CAPI" +base_url = "${wl()}/v1" +env_key = "CAPI_KEY" +wire_api = "chat"`}),n.jsx("p",{children:"然后设置环境变量并运行:"}),n.jsx("pre",{children:`export CAPI_KEY="cat_你的_api_key" +codex`})]}),n.jsxs("details",{className:"cli-tool",children:[n.jsxs("summary",{children:[n.jsx("strong",{children:"Aider"}),n.jsx("span",{children:"OpenAI 兼容"})]}),n.jsx("pre",{children:`export OPENAI_API_BASE="${wl()}" +export OPENAI_API_KEY="cat_你的_api_key" +aider --model openai/${z}`})]}),n.jsxs("details",{className:"cli-tool",children:[n.jsxs("summary",{children:[n.jsx("strong",{children:"Cline / Roo Code / Kilo Code"}),n.jsx("span",{children:"VS Code 插件"})]}),n.jsxs("p",{children:["在插件设置中选择 ",n.jsx("strong",{children:"OpenAI Compatible"}),":"]}),n.jsx("pre",{children:`Base URL: ${wl()}/v1 +API Key: cat_你的_api_key +Model ID: ${z}`})]}),n.jsxs("details",{className:"cli-tool",children:[n.jsxs("summary",{children:[n.jsx("strong",{children:"通用 OpenAI SDK"}),n.jsx("span",{children:"Python / Node.js"})]}),n.jsx("pre",{children:`export OPENAI_BASE_URL="${wl()}" +export OPENAI_API_KEY="cat_你的_api_key"`}),n.jsx("pre",{children:`from openai import OpenAI +client = OpenAI() +response = client.chat.completions.create( + model="${z}", + messages=[{"role": "user", "content": "hello"}] +)`})]})]}),m&&n.jsx("p",{className:"cli-message",role:"status",children:m})]}),le==="maintenance"&&n.jsx(lt,{title:"维护设置",children:n.jsxs("div",{className:"settings-group",children:[n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"日志保留天数"}),n.jsx("div",{className:"setting-value maintenance-control",children:n.jsx("input",{type:"number",min:"1",max:"3650",value:ee.logRetentionDays,onChange:U=>me(B=>({...B,logRetentionDays:Number(U.target.value)}))})})]}),n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"日志最大条数"}),n.jsx("div",{className:"setting-value maintenance-control",children:n.jsx("input",{type:"number",min:"100",max:"1000000",step:"100",value:ee.maxLogs,onChange:U=>me(B=>({...B,maxLogs:Number(U.target.value)}))})})]}),n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"额度流水最大条数"}),n.jsx("div",{className:"setting-value maintenance-control",children:n.jsx("input",{type:"number",min:"100",max:"2000000",step:"100",value:ee.maxQuotaEntries,onChange:U=>me(B=>({...B,maxQuotaEntries:Number(U.target.value)}))})})]}),n.jsxs("div",{className:"settings-save-row",children:[n.jsx("span",{role:"status",children:m}),n.jsx("button",{type:"button",className:"primary-button",disabled:M,onClick:Dt,children:M?"保存中":"保存维护设置"})]})]})}),le==="backup"&&n.jsx(lt,{title:"备份与恢复",children:n.jsx("div",{className:"settings-group",children:n.jsxs("div",{className:"setting",children:[n.jsxs("span",{children:["备份与恢复",n.jsx("small",{children:"包含账号哈希和加密后的上游密钥,恢复时需要相同的 SECRET_KEY"})]}),n.jsxs("div",{className:"setting-value backup-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",disabled:M,onClick:ll,children:"导出备份"}),n.jsxs("label",{className:"secondary-button",children:["恢复备份",n.jsx("input",{type:"file",accept:"application/json,.json",disabled:M,onChange:U=>{const B=U.target.files?.[0];B&&al(B),U.target.value=""}})]})]})]})})}),le==="auth"&&n.jsx(lt,{title:"账号与注册",children:n.jsxs("div",{className:"settings-group",children:[n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"开放用户注册"}),n.jsxs("div",{className:"setting-value",children:[n.jsx("strong",{children:T?"启用":"关闭"}),n.jsx("button",{type:"button",className:T?"ios-switch is-on":"ios-switch","aria-label":T?"关闭用户注册":"开放用户注册","aria-pressed":!!T,onClick:Ve,children:n.jsx("span",{})})]})]}),n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"注册方式"}),n.jsx("div",{className:"registration-mode-control",role:"group","aria-label":"注册方式",children:[{value:"username",label:"账号密码"},{value:"email",label:"邮箱"},{value:"discord",label:"Discord"}].map(U=>n.jsx("button",{type:"button",className:W===U.value?"selected":"",onClick:()=>I(T??!0,U.value),children:U.label},U.value))})]}),n.jsxs("div",{className:"setting",children:[n.jsxs("span",{children:["新用户初始额度",n.jsx("small",{children:"注册完成后自动发放,仅影响之后的新用户"})]}),n.jsxs("div",{className:"setting-value auth-default-balance",children:[n.jsx("input",{type:"number",min:"0",step:"0.01",value:y,onChange:U=>G(U.target.value),"aria-label":"新用户初始额度"}),n.jsx("button",{type:"button",className:"secondary-button",onClick:()=>I(T,W,Number(y)),children:"保存"})]})]}),n.jsxs("div",{className:"setting",children:[n.jsxs("span",{children:["默认注册分组",n.jsx("small",{children:"新注册用户自动归入该分组,决定他们能用哪些渠道"})]}),n.jsxs("div",{className:"setting-value auth-default-balance",children:[n.jsxs("select",{value:_,onChange:U=>V(U.target.value),"aria-label":"默认注册分组",children:[p.map(U=>n.jsx("option",{value:U.id,children:U.name},U.id)),p.length===0&&n.jsx("option",{value:"",children:"暂无分组"})]}),n.jsx("button",{type:"button",className:"secondary-button",disabled:p.length===0,onClick:()=>I(T,W,Number(y),_),children:"保存"})]})]})]})}),le==="check-in"&&n.jsx(lt,{title:"每日签到奖励",children:n.jsxs("div",{className:"settings-group",children:[n.jsxs("div",{className:"setting",children:[n.jsxs("span",{children:["开放每日签到",n.jsx("small",{children:"用户每天可领取一次随机额度,按北京时间刷新"})]}),n.jsxs("div",{className:"setting-value",children:[n.jsx("strong",{children:P.enabled?"启用":"关闭"}),n.jsx("button",{type:"button",className:P.enabled?"ios-switch is-on":"ios-switch","aria-label":P.enabled?"关闭每日签到":"开放每日签到","aria-pressed":P.enabled,onClick:()=>fe(U=>({...U,enabled:!U.enabled})),children:n.jsx("span",{})})]})]}),n.jsxs("div",{className:"setting check-in-settings-row",children:[n.jsxs("span",{children:["随机奖励范围",n.jsx("small",{children:"领取金额精确到 0.01,直接计入用户余额和额度流水"})]}),n.jsxs("div",{className:"check-in-reward-inputs",children:[n.jsxs("label",{children:[n.jsx("span",{children:"最低"}),n.jsx("input",{type:"number",min:"0.01",max:"1000000",step:"0.01",value:P.minReward,onChange:U=>fe(B=>({...B,minReward:Number(U.target.value)}))})]}),n.jsxs("label",{children:[n.jsx("span",{children:"最高"}),n.jsx("input",{type:"number",min:"0.01",max:"1000000",step:"0.01",value:P.maxReward,onChange:U=>fe(B=>({...B,maxReward:Number(U.target.value)}))})]})]})]}),n.jsxs("div",{className:"settings-save-row",children:[n.jsx("span",{role:"status",children:m}),n.jsx("button",{type:"button",className:"primary-button",disabled:M,onClick:ot,children:M?"保存中":"保存签到设置"})]})]})}),le==="admin"&&n.jsx(lt,{title:"管理员账号",children:n.jsxs("form",{className:"discord-settings",onSubmit:U=>{U.preventDefault(),gt()},children:[n.jsxs("div",{className:"settings-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"登录账号"}),n.jsx("input",{value:te,onChange:U=>ye(U.target.value),autoComplete:"username"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"显示名称"}),n.jsx("input",{value:O,onChange:U=>ae(U.target.value),autoComplete:"name"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"邮箱"}),n.jsx("input",{type:"email",value:ve,onChange:U=>Ce(U.target.value),autoComplete:"email"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"Discord 用户 ID(可选)"}),n.jsx("input",{inputMode:"numeric",autoComplete:"off",value:Me,onChange:U=>ue(U.target.value),placeholder:Y?.discordUserId?"已绑定":"输入管理员的 Discord 用户 ID"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"当前密码"}),n.jsx("input",{type:"password",value:Z,onChange:U=>de(U.target.value),autoComplete:"current-password",placeholder:"修改密码时填写"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"新密码"}),n.jsx("input",{type:"password",value:$,onChange:U=>A(U.target.value),autoComplete:"new-password",placeholder:"留空表示不修改"})]})]}),n.jsxs("div",{className:"settings-save-row",children:[n.jsx("span",{role:"status",children:m}),n.jsx("button",{className:"primary-button",type:"submit",children:"保存账号"})]})]})}),le==="discord"&&n.jsx(lt,{title:"Discord 登录",children:r?n.jsxs("form",{className:"discord-settings",autoComplete:"off",onSubmit:U=>{U.preventDefault(),Je()},children:[n.jsxs("div",{className:"discord-toggle-row",children:[n.jsxs("div",{children:[n.jsx("strong",{children:"Discord 登录"}),n.jsx("span",{children:r.enabled?"已启用":"未启用"})]}),n.jsx("button",{type:"button",className:r.enabled?"ios-switch is-on":"ios-switch","aria-label":r.enabled?"停用 Discord 登录":"启用 Discord 登录","aria-pressed":r.enabled,onClick:()=>C({...r,enabled:!r.enabled}),children:n.jsx("span",{})})]}),n.jsxs("div",{className:"settings-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"Client ID"}),n.jsx("input",{inputMode:"numeric",autoComplete:"off",value:r.clientId,onChange:U=>C({...r,clientId:U.target.value}),placeholder:"100000000000000001"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"Client Secret"}),n.jsx("input",{type:"password",autoComplete:"new-password",value:L,onChange:U=>H(U.target.value),placeholder:r.clientSecretSet?"已设置,留空表示不修改":"粘贴 Discord Client Secret"})]}),n.jsxs("label",{className:"settings-form-wide",children:[n.jsx("span",{children:"回调地址"}),n.jsx("input",{type:"url",value:r.redirectUri,onChange:U=>C({...r,redirectUri:U.target.value}),placeholder:"https://你的域名/api/auth/discord/callback"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"服务器 ID"}),n.jsx("input",{inputMode:"numeric",value:r.allowedGuildId,onChange:U=>C({...r,allowedGuildId:U.target.value}),placeholder:"允许登录的服务器 ID"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"身份组 ID"}),n.jsx("input",{inputMode:"numeric",value:r.allowedRoleId,onChange:U=>C({...r,allowedRoleId:U.target.value}),placeholder:"允许登录的身份组 ID"})]}),n.jsxs("label",{className:"settings-form-wide",children:[n.jsx("span",{children:"拉黑服务器 ID"}),n.jsx("textarea",{value:X,onChange:U=>ie(U.target.value),placeholder:"每行一个服务器 ID;命中的用户禁止注册 / 登录",rows:3}),n.jsx("small",{children:"用户若加入了这些 Discord 服务器中的任意一个,将无法注册或登录(优先于上面的允许规则)。"})]}),n.jsxs("label",{className:"settings-form-wide",children:[n.jsx("span",{children:"登录成功跳转地址"}),n.jsx("input",{type:"url",value:r.authSuccessUrl,onChange:U=>C({...r,authSuccessUrl:U.target.value}),placeholder:"https://你的域名/"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"登录有效期(小时)"}),n.jsx("input",{type:"number",min:"1",max:"8760",value:r.sessionTtlHours,onChange:U=>C({...r,sessionTtlHours:Number(U.target.value)})})]})]}),n.jsxs("div",{className:"settings-save-row",children:[n.jsx("span",{role:"status",children:m}),n.jsx("button",{className:"primary-button",type:"submit",disabled:M,children:M?"保存中":"保存配置"})]})]}):n.jsx("div",{className:"empty",children:"正在读取配置"})})]})}function ol({label:u,value:f}){return n.jsxs("div",{className:"metric",children:[n.jsx("span",{children:u}),n.jsx("strong",{children:f})]})}function Kp({groups:u,onCreate:f,onUpdate:p,onDelete:r}){const[C,T]=b.useState(""),[k,W]=b.useState(""),[N,y]=b.useState(!1);async function G(_){if(_.preventDefault(),!!C.trim()){y(!0);try{await f({name:C.trim(),description:k.trim()}),T(""),W("")}finally{y(!1)}}}return n.jsxs("section",{className:"models-page",children:[n.jsxs(lt,{title:"用户分组",children:[n.jsxs("form",{className:"channel-create-form",onSubmit:G,children:[n.jsxs("div",{className:"channel-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"分组名称"}),n.jsx("input",{value:C,onChange:_=>T(_.target.value),placeholder:"例如 尊享用户 / 试用用户"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"说明"}),n.jsx("input",{value:k,onChange:_=>W(_.target.value),placeholder:"可选"})]})]}),n.jsx("div",{className:"channel-card-actions",children:n.jsx("button",{className:"primary-button",type:"submit",disabled:N||!C.trim(),children:N?"创建中":"创建分组"})})]}),n.jsx("p",{className:"muted-inline",children:"分组用于控制渠道对用户的可见范围:把用户归入分组,并在渠道上勾选「可见分组」即可限制访问。未分组的用户只能使用未限制分组的渠道。"})]}),n.jsx(lt,{title:"全部分组",children:u.length===0?n.jsx(Lt,{text:"还没有分组"}):n.jsx("div",{className:"channels-stack",children:u.map(_=>n.jsx(Zp,{group:_,onUpdate:p,onDelete:r},_.id))})})]})}function Zp({group:u,onUpdate:f,onDelete:p}){const[r,C]=b.useState(!1),[T,k]=b.useState(u.name),[W,N]=b.useState(u.description),[y,G]=b.useState(!1);async function _(){G(!0);try{await f(u.id,{name:T.trim(),description:W.trim()}),C(!1)}finally{G(!1)}}return n.jsx("div",{className:"channel-card",children:n.jsxs("div",{className:"channel-card-head",children:[n.jsx("div",{children:r?n.jsxs("div",{className:"group-edit-fields",children:[n.jsx("input",{value:T,onChange:V=>k(V.target.value),placeholder:"分组名称"}),n.jsx("input",{value:W,onChange:V=>N(V.target.value),placeholder:"说明"})]}):n.jsxs(n.Fragment,{children:[n.jsx("strong",{children:u.name}),u.description&&n.jsx("span",{children:u.description}),n.jsxs("small",{children:["创建于 ",tl(u.createdAt)]})]})}),n.jsx("div",{className:"channel-card-head-actions",children:r?n.jsxs(n.Fragment,{children:[n.jsx("button",{className:"primary-button compact-button",onClick:_,disabled:y||!T.trim(),children:y?"保存中":"保存"}),n.jsx("button",{className:"secondary-button compact-button",onClick:()=>{k(u.name),N(u.description),C(!1)},children:"取消"})]}):n.jsxs(n.Fragment,{children:[n.jsx("button",{className:"secondary-button compact-button",onClick:()=>C(!0),children:"重命名"}),n.jsx("button",{className:"danger-button compact-button",onClick:()=>p(u.id),children:"删除"})]})})]})})}function lt({title:u,children:f}){return n.jsxs("section",{className:"panel",children:[n.jsx("div",{className:"panel-title",children:n.jsx("h2",{children:u})}),f]})}function _t({tone:u,children:f}){return n.jsx("span",{className:`badge tone-${u}`,children:f})}function el({label:u,value:f,switchOn:p}){return n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:u}),n.jsxs("div",{className:"setting-value",children:[n.jsx("strong",{children:f}),typeof p=="boolean"&&n.jsx("div",{className:p?"ios-switch is-on":"ios-switch","aria-hidden":"true",children:n.jsx("span",{})})]})]})}function Vp({value:u,options:f,onChange:p}){return n.jsx("div",{className:"segmented-control",children:f.map(r=>n.jsx("button",{className:u===r.value?"selected":"",onClick:()=>p(r.value),children:r.label},r.value))})}function Lt({text:u}){return n.jsx("div",{className:"empty",children:u})}$0.createRoot(document.getElementById("root")).render(n.jsx(L0.StrictMode,{children:n.jsx(mp,{})})); diff --git a/dist/index.html b/dist/index.html index 05a0788..6b2db7f 100644 --- a/dist/index.html +++ b/dist/index.html @@ -5,7 +5,7 @@ CAPI - + diff --git a/src/App.tsx b/src/App.tsx index 4d850ef..6203eea 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1115,6 +1115,24 @@ function App() { return result; } + async function startAntigravityOAuth(channelId: string) { + return fetchJson<{ authorizeUrl: string; state: string; redirectUri: string }>( + `/api/channels/${encodeURIComponent(channelId)}/antigravity-oauth/start`, + { method: "POST", body: JSON.stringify({}) } + ); + } + + async function completeAntigravityOAuth(channelId: string, payload: { callbackUrl?: string; code?: string; state?: string }) { + const result = await fetchJson<{ account: OpenAIAccount; channel: Channel }>( + `/api/channels/${encodeURIComponent(channelId)}/antigravity-oauth/complete`, + { method: "POST", body: JSON.stringify(payload) } + ); + setChannels((current) => current.map((channel) => (channel.id === result.channel.id ? normalizeChannel(result.channel) : channel))); + setToast("已通过 Google 授权添加账号"); + window.setTimeout(() => setToast(""), 2400); + return result; + } + async function createModel(model: ModelCreate) { const data = await fetchJson<{ model: ModelItem }>("/api/models", { method: "POST", @@ -1346,7 +1364,7 @@ function App() { {active === "keys" && } {active === "models" && } {active === "drawing" && } - {active === "antigravity" && } + {active === "antigravity" && } {active === "channels" && } {active === "logs" && } {active === "settings" && } @@ -3379,6 +3397,7 @@ function DrawingView({ {oauthChannelId && ( setOAuthChannelId("")} @@ -3387,6 +3406,7 @@ function DrawingView({ {addAccountChannelId && ( { setAuthSessionChannelId(addAccountChannelId); setAddAccountChannelId(""); @@ -3395,6 +3415,10 @@ function DrawingView({ setAntigravityChannelId(addAccountChannelId); setAddAccountChannelId(""); }} + onOAuth={() => { + setOAuthChannelId(addAccountChannelId); + setAddAccountChannelId(""); + }} onImport={async (file) => { await importFile(addAccountChannelId, file); setAddAccountChannelId(""); @@ -3424,17 +3448,22 @@ function DrawingView({ function AccountAddModal({ busy, + variant = "drawing", onAuthSession, onAntigravity, + onOAuth, onImport, onClose }: { busy: boolean; + variant?: "drawing" | "antigravity"; onAuthSession: () => void; onAntigravity: () => void; + onOAuth: () => void; onImport: (file: File) => Promise; onClose: () => void; }) { + const isAntigravity = variant === "antigravity"; return (
event.stopPropagation()}> @@ -3446,16 +3475,26 @@ function AccountAddModal({
- - + {isAntigravity ? ( + <> + + + + ) : ( + + )}