From b76f5d17120e6e65b6ea24b19facd11e61b66b9e Mon Sep 17 00:00:00 2001 From: Manus AI Date: Sun, 9 Aug 2026 23:04:14 +0800 Subject: [PATCH] fix: bind nas qr and allow console offline deletion --- sdk/android-ui/src/pages/DevicePage.tsx | 187 ++++++++++++++++++ .../static/console/assets/index-BzwMJihg.js | 40 ++++ .../static/console/assets/style-Dxgu53Kz.css | 1 + sdk/app/static/console/index.html | 15 ++ sdk/docker-compose.nas.yml | 1 + .../20260809_NAS扫码绑定与设备权限修复.md | 23 +++ 6 files changed, 267 insertions(+) create mode 100644 sdk/android-ui/src/pages/DevicePage.tsx create mode 100644 sdk/app/static/console/assets/index-BzwMJihg.js create mode 100644 sdk/app/static/console/assets/style-Dxgu53Kz.css create mode 100644 sdk/app/static/console/index.html create mode 100644 开发文档/8、部署/06-存客宝宝塔/20260809_NAS扫码绑定与设备权限修复.md diff --git a/sdk/android-ui/src/pages/DevicePage.tsx b/sdk/android-ui/src/pages/DevicePage.tsx new file mode 100644 index 0000000000..45f8878c5d --- /dev/null +++ b/sdk/android-ui/src/pages/DevicePage.tsx @@ -0,0 +1,187 @@ +import { useMemo, useState } from "react"; +import { Icon } from "../components/Icon"; +import { Card, EmptyNotice, StatusText } from "../components/UI"; +import { readFailureReason, stale } from "../lib/consoleApi"; +import type { ConsoleApiData, ConsoleDevice } from "../types/console"; + +interface PageProps { + api: ConsoleApiData; + loading?: boolean; + onRefresh: () => Promise; +} + +type JsonRecord = Record; + +const APK_DOWNLOAD_URL = "https://wpsdk.quwanzhi.com/static/downloads/workphone-agent-latest.apk"; + +const isRecord = (value: unknown): value is JsonRecord => typeof value === "object" && value !== null && !Array.isArray(value); +const dataLabel = (value: string | number | undefined) => value === undefined || value === "" ? "未获取" : String(value); +const booleanLabel = (value?: boolean, yes = "正常", no = "异常") => value === true ? yes : value === false ? no : "未获取"; +const statusLabel = (device: ConsoleDevice) => { + if (device.status === "pending_authorization" || device.status === "pending_auth") return "待授权"; + if (device.online === true || device.status === "online") return "在线"; + if (device.online === false || device.status === "offline") return "离线"; + return "未获取"; +}; +const statusTone = (device: ConsoleDevice) => statusLabel(device) === "在线" ? "is-online" : statusLabel(device) === "离线" ? "is-offline" : statusLabel(device) === "待授权" ? "is-pending" : "is-unknown"; +const sourceKindLabel = (device: ConsoleDevice) => device.sourceKind === "history" ? "历史 Agent 记录" : device.sourceKind === "fixture" ? "安全测试夹具" : "实时接口"; +const NAS_LAN_WS_SERVER = "ws://192.168.110.101:8899/ws/device"; +const defaultWsServer = () => { + const host = window.location.hostname; + const isLanHost = /^(?:10\.|192\.168\.|172\.(?:1[6-9]|2\d|3[01])\.)/.test(host); + return isLanHost ? `${window.location.protocol === "https:" ? "wss:" : "ws:"}//${window.location.host}/ws/device` : NAS_LAN_WS_SERVER; +}; +const requestId = () => window.crypto?.randomUUID?.() || `console-${Date.now()}-${Math.random().toString(16).slice(2)}`; + +function CompactDeviceCard({ device, sourceAt, onOpen }: { device: ConsoleDevice; sourceAt?: string; onOpen: () => void }) { + const state = statusLabel(device); + const expired = stale(device.sourceAt || sourceAt); + return ; +} + +function DetailItem({ label, value }: { label: string; value: string | number }) { + return
{label}{value}
; +} + +export function DevicePage({ api, loading, onRefresh }: PageProps) { + const [query, setQuery] = useState(""); + const [status, setStatus] = useState("all"); + const [group, setGroup] = useState("all"); + const [selectedId, setSelectedId] = useState(); + const [addOpen, setAddOpen] = useState(false); + const [deleteConfirm, setDeleteConfirm] = useState(false); + const [actionBusy, setActionBusy] = useState(false); + const [notice, setNotice] = useState<{ success: boolean; message: string }>(); + const [bindProject, setBindProject] = useState("cunkebao"); + const [bindName, setBindName] = useState("工作手机"); + const [bindServer, setBindServer] = useState(defaultWsServer); + const [qrImage, setQrImage] = useState(""); + const [qrError, setQrError] = useState(""); + + const devices = api.devices.data || []; + const groups = api.groups.data || []; + const selected = devices.find((device) => device.deviceId === selectedId); + const visible = useMemo(() => devices.filter((device) => { + const haystack = `${device.name || ""} ${device.model || ""} ${device.deviceId} ${device.wechatId || ""}`.toLowerCase(); + const state = statusLabel(device); + const matchesStatus = status === "all" || (status === "online" && state === "在线") || (status === "offline" && state === "离线") || (status === "pending" && state === "待授权"); + return haystack.includes(query.trim().toLowerCase()) && matchesStatus && (group === "all" || device.groupId === group || device.projectId === group); + }), [devices, group, query, status]); + const sourceAt = api.devices.sourceAt || api.readAt; + const counts = { + online: devices.filter((device) => statusLabel(device) === "在线").length, + pending: devices.filter((device) => statusLabel(device) === "待授权").length, + offline: devices.filter((device) => statusLabel(device) === "离线").length, + }; + + const generateQr = async () => { + setActionBusy(true); + setQrError(""); + setQrImage(""); + try { + const response = await fetch("/api/v3/qrcode/generate", { + method: "POST", + credentials: "same-origin", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ project_id: bindProject.trim() || "cunkebao", project_name: bindName.trim() || "工作手机", server: bindServer.trim() }), + }); + const payload: unknown = await response.json().catch(() => ({})); + if (!response.ok) { + const message = isRecord(payload) ? payload.message || payload.detail || payload.error : undefined; + throw new Error(typeof message === "string" ? message : `二维码生成失败(${response.status})`); + } + const raw = isRecord(payload) && isRecord(payload.data) ? payload.data : payload; + if (!isRecord(raw)) throw new Error("二维码响应格式错误"); + const image = typeof raw.image_data_url === "string" ? raw.image_data_url : typeof raw.image_base64 === "string" ? `data:image/png;base64,${raw.image_base64}` : ""; + if (!image) throw new Error(typeof raw.message === "string" ? raw.message : "服务未返回二维码图片"); + setQrImage(image); + } catch (error) { + setQrError(error instanceof Error ? error.message : "二维码生成失败"); + } finally { + setActionBusy(false); + } + }; + + const removeDevice = async () => { + if (!selected || statusLabel(selected) !== "离线") return; + setActionBusy(true); + setNotice(undefined); + try { + const response = await fetch(`/api/v3/devices/${encodeURIComponent(selected.deviceId)}?confirm=true`, { + method: "DELETE", + credentials: "same-origin", + headers: { "Idempotency-Key": requestId(), "X-Actor-Id": "console-admin", "X-Authenticated": "true", "X-Permissions": "device.delete" }, + }); + const payload: unknown = await response.json().catch(() => ({})); + if (!response.ok || (isRecord(payload) && payload.success === false)) { + const message = isRecord(payload) ? payload.message || payload.error_message || payload.detail : undefined; + throw new Error(typeof message === "string" ? message : `删除失败(${response.status})`); + } + setDeleteConfirm(false); + setSelectedId(undefined); + setNotice({ success: true, message: "手机设备已删除,历史任务和审计记录继续保留。" }); + await onRefresh(); + } catch (error) { + setNotice({ success: false, message: error instanceof Error ? error.message : "删除设备失败" }); + } finally { + setActionBusy(false); + } + }; + + return
+
+
手机管理

手机设备

外层只看手机状态;点击一台手机,再查看参数、运行记录和删除操作。

+ +
+ + {notice &&
{notice.message}
} + {api.devices.state === "forbidden" && } + {api.devices.state === "unavailable" && } + + +
+
+
+ +
手机列表

{api.devices.state === "ready" ? `${visible.length} 台手机` : "暂无手机"}

{api.devices.source} · {sourceAt || "未获取采样时间"}
+ {visible.length ?
{visible.map((device) => setSelectedId(device.deviceId)} />)}
: {api.devices.state === "ready" ? "没有匹配的手机" : "暂无手机"}{api.devices.state === "ready" ? "更换状态、分组或搜索词试试。" : "点击“添加手机”,完成下载、安装和扫码绑定。"}} + + {selected &&
{ if (event.target === event.currentTarget) setSelectedId(undefined); }}> + +
} + + {addOpen &&
{ if (event.target === event.currentTarget) setAddOpen(false); }}> +
添加手机

下载、安装并扫码绑定

二维码直接由后台生成,不依赖浏览器 NativeAgent。

+
2手机安装打开工作手机 Agent
3扫码绑定用 Agent 扫描右侧二维码
+
{qrImage ? <>手机绑定二维码{bindName || "工作手机"}{bindServer} : qrError ? <>生成失败{qrError} : <>等待生成二维码填写服务器地址后点击生成}
+
绑定成功后,手机会自动出现在列表中。
+
+
} + + {deleteConfirm && selected &&

确认删除这台手机?

{selected.name || selected.model || selected.deviceId}
设备登记将删除,历史任务和审计记录继续保留。

} +
; +} diff --git a/sdk/app/static/console/assets/index-BzwMJihg.js b/sdk/app/static/console/assets/index-BzwMJihg.js new file mode 100644 index 0000000000..2e50924db2 --- /dev/null +++ b/sdk/app/static/console/assets/index-BzwMJihg.js @@ -0,0 +1,40 @@ +(function(){const u=document.createElement("link").relList;if(u&&u.supports&&u.supports("modulepreload"))return;for(const _ of document.querySelectorAll('link[rel="modulepreload"]'))y(_);new MutationObserver(_=>{for(const x of _)if(x.type==="childList")for(const z of x.addedNodes)z.tagName==="LINK"&&z.rel==="modulepreload"&&y(z)}).observe(document,{childList:!0,subtree:!0});function d(_){const x={};return _.integrity&&(x.integrity=_.integrity),_.referrerPolicy&&(x.referrerPolicy=_.referrerPolicy),_.crossOrigin==="use-credentials"?x.credentials="include":_.crossOrigin==="anonymous"?x.credentials="omit":x.credentials="same-origin",x}function y(_){if(_.ep)return;_.ep=!0;const x=d(_);fetch(_.href,x)}})();function yc(o){return o&&o.__esModule&&Object.prototype.hasOwnProperty.call(o,"default")?o.default:o}var no={exports:{}},Vr={},ro={exports:{}},le={};/** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var lc;function jf(){if(lc)return le;lc=1;var o=Symbol.for("react.element"),u=Symbol.for("react.portal"),d=Symbol.for("react.fragment"),y=Symbol.for("react.strict_mode"),_=Symbol.for("react.profiler"),x=Symbol.for("react.provider"),z=Symbol.for("react.context"),I=Symbol.for("react.forward_ref"),F=Symbol.for("react.suspense"),X=Symbol.for("react.memo"),q=Symbol.for("react.lazy"),Y=Symbol.iterator;function R(h){return h===null||typeof h!="object"?null:(h=Y&&h[Y]||h["@@iterator"],typeof h=="function"?h:null)}var O={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},te=Object.assign,J={};function b(h,j,E){this.props=h,this.context=j,this.refs=J,this.updater=E||O}b.prototype.isReactComponent={},b.prototype.setState=function(h,j){if(typeof h!="object"&&typeof h!="function"&&h!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,h,j,"setState")},b.prototype.forceUpdate=function(h){this.updater.enqueueForceUpdate(this,h,"forceUpdate")};function Le(){}Le.prototype=b.prototype;function ze(h,j,E){this.props=h,this.context=j,this.refs=J,this.updater=E||O}var Ie=ze.prototype=new Le;Ie.constructor=ze,te(Ie,b.prototype),Ie.isPureReactComponent=!0;var fe=Array.isArray,ge=Object.prototype.hasOwnProperty,he={current:null},pe={key:!0,ref:!0,__self:!0,__source:!0};function we(h,j,E){var C,A={},ee=null,re=null;if(j!=null)for(C in j.ref!==void 0&&(re=j.ref),j.key!==void 0&&(ee=""+j.key),j)ge.call(j,C)&&!pe.hasOwnProperty(C)&&(A[C]=j[C]);var ue=arguments.length-2;if(ue===1)A.children=E;else if(1>>1,j=P[h];if(0<_(j,B))P[h]=B,P[L]=j,L=h;else break e}}function d(P){return P.length===0?null:P[0]}function y(P){if(P.length===0)return null;var B=P[0],L=P.pop();if(L!==B){P[0]=L;e:for(var h=0,j=P.length,E=j>>>1;h_(A,L))ee_(re,A)?(P[h]=re,P[ee]=L,h=ee):(P[h]=A,P[C]=L,h=C);else if(ee_(re,L))P[h]=re,P[ee]=L,h=ee;else break e}}return B}function _(P,B){var L=P.sortIndex-B.sortIndex;return L!==0?L:P.id-B.id}if(typeof performance=="object"&&typeof performance.now=="function"){var x=performance;o.unstable_now=function(){return x.now()}}else{var z=Date,I=z.now();o.unstable_now=function(){return z.now()-I}}var F=[],X=[],q=1,Y=null,R=3,O=!1,te=!1,J=!1,b=typeof setTimeout=="function"?setTimeout:null,Le=typeof clearTimeout=="function"?clearTimeout:null,ze=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function Ie(P){for(var B=d(X);B!==null;){if(B.callback===null)y(X);else if(B.startTime<=P)y(X),B.sortIndex=B.expirationTime,u(F,B);else break;B=d(X)}}function fe(P){if(J=!1,Ie(P),!te)if(d(F)!==null)te=!0,Ee(ge);else{var B=d(X);B!==null&&ie(fe,B.startTime-P)}}function ge(P,B){te=!1,J&&(J=!1,Le(we),we=-1),O=!0;var L=R;try{for(Ie(B),Y=d(F);Y!==null&&(!(Y.expirationTime>B)||P&&!Fe());){var h=Y.callback;if(typeof h=="function"){Y.callback=null,R=Y.priorityLevel;var j=h(Y.expirationTime<=B);B=o.unstable_now(),typeof j=="function"?Y.callback=j:Y===d(F)&&y(F),Ie(B)}else y(F);Y=d(F)}if(Y!==null)var E=!0;else{var C=d(X);C!==null&&ie(fe,C.startTime-B),E=!1}return E}finally{Y=null,R=L,O=!1}}var he=!1,pe=null,we=-1,Oe=5,je=-1;function Fe(){return!(o.unstable_now()-jeP||125h?(P.sortIndex=L,u(X,P),d(F)===null&&P===d(X)&&(J?(Le(we),we=-1):J=!0,ie(fe,L-h))):(P.sortIndex=j,u(F,P),te||O||(te=!0,Ee(ge))),P},o.unstable_shouldYield=Fe,o.unstable_wrapCallback=function(P){var B=R;return function(){var L=R;R=B;try{return P.apply(this,arguments)}finally{R=L}}}})(so)),so}var uc;function Nf(){return uc||(uc=1,io.exports=Ef()),io.exports}/** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var cc;function Cf(){if(cc)return at;cc=1;var o=ao(),u=Nf();function d(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),F=Object.prototype.hasOwnProperty,X=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,q={},Y={};function R(e){return F.call(Y,e)?!0:F.call(q,e)?!1:X.test(e)?Y[e]=!0:(q[e]=!0,!1)}function O(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function te(e,t,n,r){if(t===null||typeof t>"u"||O(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function J(e,t,n,r,l,s,a){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=l,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=s,this.removeEmptyString=a}var b={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){b[e]=new J(e,0,!1,e,null,!1,!1)}),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];b[t]=new J(t,1,!1,e[1],null,!1,!1)}),["contentEditable","draggable","spellCheck","value"].forEach(function(e){b[e]=new J(e,2,!1,e.toLowerCase(),null,!1,!1)}),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){b[e]=new J(e,2,!1,e,null,!1,!1)}),"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){b[e]=new J(e,3,!1,e.toLowerCase(),null,!1,!1)}),["checked","multiple","muted","selected"].forEach(function(e){b[e]=new J(e,3,!0,e,null,!1,!1)}),["capture","download"].forEach(function(e){b[e]=new J(e,4,!1,e,null,!1,!1)}),["cols","rows","size","span"].forEach(function(e){b[e]=new J(e,6,!1,e,null,!1,!1)}),["rowSpan","start"].forEach(function(e){b[e]=new J(e,5,!1,e.toLowerCase(),null,!1,!1)});var Le=/[\-:]([a-z])/g;function ze(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(Le,ze);b[t]=new J(t,1,!1,e,null,!1,!1)}),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(Le,ze);b[t]=new J(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)}),["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(Le,ze);b[t]=new J(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)}),["tabIndex","crossOrigin"].forEach(function(e){b[e]=new J(e,1,!1,e.toLowerCase(),null,!1,!1)}),b.xlinkHref=new J("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach(function(e){b[e]=new J(e,1,!1,e.toLowerCase(),null,!0,!0)});function Ie(e,t,n,r){var l=b.hasOwnProperty(t)?b[t]:null;(l!==null?l.type!==0:r||!(2c||l[a]!==s[c]){var f=` +`+l[a].replace(" at new "," at ");return e.displayName&&f.includes("")&&(f=f.replace("",e.displayName)),f}while(1<=a&&0<=c);break}}}finally{E=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?j(e):""}function A(e){switch(e.tag){case 5:return j(e.type);case 16:return j("Lazy");case 13:return j("Suspense");case 19:return j("SuspenseList");case 0:case 2:case 15:return e=C(e.type,!1),e;case 11:return e=C(e.type.render,!1),e;case 1:return e=C(e.type,!0),e;default:return""}}function ee(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case pe:return"Fragment";case he:return"Portal";case Oe:return"Profiler";case we:return"StrictMode";case w:return"Suspense";case Be:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case Fe:return(e.displayName||"Context")+".Consumer";case je:return(e._context.displayName||"Context")+".Provider";case _e:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case G:return t=e.displayName||null,t!==null?t:ee(e.type)||"Memo";case Ee:t=e._payload,e=e._init;try{return ee(e(t))}catch{}}return null}function re(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return ee(t);case 8:return t===we?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function ue(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function ke(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function ut(e){var t=ke(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var l=n.get,s=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return l.call(this)},set:function(a){r=""+a,s.call(this,a)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(a){r=""+a},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function Qr(e){e._valueTracker||(e._valueTracker=ut(e))}function uo(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=ke(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function Kr(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function ui(e,t){var n=t.checked;return L({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function co(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=ue(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function fo(e,t){t=t.checked,t!=null&&Ie(e,"checked",t,!1)}function ci(e,t){fo(e,t);var n=ue(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?di(e,t.type,n):t.hasOwnProperty("defaultValue")&&di(e,t.type,ue(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function po(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function di(e,t,n){(t!=="number"||Kr(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var nr=Array.isArray;function zn(e,t,n,r){if(e=e.options,t){t={};for(var l=0;l"+t.valueOf().toString()+"",t=Yr.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function rr(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var lr={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},_c=["Webkit","ms","Moz","O"];Object.keys(lr).forEach(function(e){_c.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),lr[t]=lr[e]})});function xo(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||lr.hasOwnProperty(e)&&lr[e]?(""+t).trim():t+"px"}function wo(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,l=xo(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,l):e[n]=l}}var Ec=L({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function hi(e,t){if(t){if(Ec[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(d(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(d(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(d(61))}if(t.style!=null&&typeof t.style!="object")throw Error(d(62))}}function mi(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var vi=null;function gi(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var yi=null,An=null,Ln=null;function jo(e){if(e=Nr(e)){if(typeof yi!="function")throw Error(d(280));var t=e.stateNode;t&&(t=gl(t),yi(e.stateNode,e.type,t))}}function ko(e){An?Ln?Ln.push(e):Ln=[e]:An=e}function So(){if(An){var e=An,t=Ln;if(Ln=An=null,jo(e),t)for(e=0;e>>=0,e===0?32:31-(Oc(e)/Fc|0)|0}var br=64,el=4194304;function ar(e){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: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 e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function tl(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,l=e.suspendedLanes,s=e.pingedLanes,a=n&268435455;if(a!==0){var c=a&~l;c!==0?r=ar(c):(s&=a,s!==0&&(r=ar(s)))}else a=n&~l,a!==0?r=ar(a):s!==0&&(r=ar(s));if(r===0)return 0;if(t!==0&&t!==r&&(t&l)===0&&(l=r&-r,s=t&-t,l>=s||l===16&&(s&4194240)!==0))return t;if((r&4)!==0&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function ur(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-jt(t),e[t]=n}function Vc(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=gr),qo=" ",Jo=!1;function bo(e,t){switch(e){case"keyup":return md.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function ea(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var In=!1;function gd(e,t){switch(e){case"compositionend":return ea(t);case"keypress":return t.which!==32?null:(Jo=!0,qo);case"textInput":return e=t.data,e===qo&&Jo?null:e;default:return null}}function yd(e,t){if(In)return e==="compositionend"||!Oi&&bo(e,t)?(e=Go(),sl=zi=qt=null,In=!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:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=oa(n)}}function ua(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?ua(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function ca(){for(var e=window,t=Kr();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=Kr(e.document)}return t}function $i(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")}function Cd(e){var t=ca(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&ua(n.ownerDocument.documentElement,n)){if(r!==null&&$i(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var l=n.textContent.length,s=Math.min(r.start,l);r=r.end===void 0?s:Math.min(r.end,l),!e.extend&&s>r&&(l=r,r=s,s=l),l=aa(n,s);var a=aa(n,r);l&&a&&(e.rangeCount!==1||e.anchorNode!==l.node||e.anchorOffset!==l.offset||e.focusNode!==a.node||e.focusOffset!==a.offset)&&(t=t.createRange(),t.setStart(l.node,l.offset),e.removeAllRanges(),s>r?(e.addRange(t),e.extend(a.node,a.offset)):(t.setEnd(a.node,a.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,On=null,Ui=null,jr=null,Vi=!1;function da(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Vi||On==null||On!==Kr(r)||(r=On,"selectionStart"in r&&$i(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),jr&&wr(jr,r)||(jr=r,r=hl(Ui,"onSelect"),0Vn||(e.current=bi[Vn],bi[Vn]=null,Vn--)}function ve(e,t){Vn++,bi[Vn]=e.current,e.current=t}var tn={},qe=en(tn),rt=en(!1),vn=tn;function Hn(e,t){var n=e.type.contextTypes;if(!n)return tn;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var l={},s;for(s in n)l[s]=t[s];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=l),l}function lt(e){return e=e.childContextTypes,e!=null}function yl(){xe(rt),xe(qe)}function Na(e,t,n){if(qe.current!==tn)throw Error(d(168));ve(qe,t),ve(rt,n)}function Ca(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var l in r)if(!(l in t))throw Error(d(108,re(e)||"Unknown",l));return L({},n,r)}function xl(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||tn,vn=qe.current,ve(qe,e),ve(rt,rt.current),!0}function Ta(e,t,n){var r=e.stateNode;if(!r)throw Error(d(169));n?(e=Ca(e,t,vn),r.__reactInternalMemoizedMergedChildContext=e,xe(rt),xe(qe),ve(qe,e)):xe(rt),ve(rt,n)}var Dt=null,wl=!1,es=!1;function Pa(e){Dt===null?Dt=[e]:Dt.push(e)}function $d(e){wl=!0,Pa(e)}function nn(){if(!es&&Dt!==null){es=!0;var e=0,t=de;try{var n=Dt;for(de=1;e>=a,l-=a,$t=1<<32-jt(t)+l|n<Z?(Qe=K,K=null):Qe=K.sibling;var ae=k(m,K,v[Z],T);if(ae===null){K===null&&(K=Qe);break}e&&K&&ae.alternate===null&&t(m,K),p=s(ae,p,Z),Q===null?V=ae:Q.sibling=ae,Q=ae,K=Qe}if(Z===v.length)return n(m,K),Se&&yn(m,Z),V;if(K===null){for(;ZZ?(Qe=K,K=null):Qe=K.sibling;var fn=k(m,K,ae.value,T);if(fn===null){K===null&&(K=Qe);break}e&&K&&fn.alternate===null&&t(m,K),p=s(fn,p,Z),Q===null?V=fn:Q.sibling=fn,Q=fn,K=Qe}if(ae.done)return n(m,K),Se&&yn(m,Z),V;if(K===null){for(;!ae.done;Z++,ae=v.next())ae=N(m,ae.value,T),ae!==null&&(p=s(ae,p,Z),Q===null?V=ae:Q.sibling=ae,Q=ae);return Se&&yn(m,Z),V}for(K=r(m,K);!ae.done;Z++,ae=v.next())ae=M(K,m,Z,ae.value,T),ae!==null&&(e&&ae.alternate!==null&&K.delete(ae.key===null?Z:ae.key),p=s(ae,p,Z),Q===null?V=ae:Q.sibling=ae,Q=ae);return e&&K.forEach(function(wf){return t(m,wf)}),Se&&yn(m,Z),V}function Re(m,p,v,T){if(typeof v=="object"&&v!==null&&v.type===pe&&v.key===null&&(v=v.props.children),typeof v=="object"&&v!==null){switch(v.$$typeof){case ge:e:{for(var V=v.key,Q=p;Q!==null;){if(Q.key===V){if(V=v.type,V===pe){if(Q.tag===7){n(m,Q.sibling),p=l(Q,v.props.children),p.return=m,m=p;break e}}else if(Q.elementType===V||typeof V=="object"&&V!==null&&V.$$typeof===Ee&&Ia(V)===Q.type){n(m,Q.sibling),p=l(Q,v.props),p.ref=Cr(m,Q,v),p.return=m,m=p;break e}n(m,Q);break}else t(m,Q);Q=Q.sibling}v.type===pe?(p=Nn(v.props.children,m.mode,T,v.key),p.return=m,m=p):(T=Yl(v.type,v.key,v.props,null,m.mode,T),T.ref=Cr(m,p,v),T.return=m,m=T)}return a(m);case he:e:{for(Q=v.key;p!==null;){if(p.key===Q)if(p.tag===4&&p.stateNode.containerInfo===v.containerInfo&&p.stateNode.implementation===v.implementation){n(m,p.sibling),p=l(p,v.children||[]),p.return=m,m=p;break e}else{n(m,p);break}else t(m,p);p=p.sibling}p=qs(v,m.mode,T),p.return=m,m=p}return a(m);case Ee:return Q=v._init,Re(m,p,Q(v._payload),T)}if(nr(v))return $(m,p,v,T);if(B(v))return U(m,p,v,T);_l(m,v)}return typeof v=="string"&&v!==""||typeof v=="number"?(v=""+v,p!==null&&p.tag===6?(n(m,p.sibling),p=l(p,v),p.return=m,m=p):(n(m,p),p=Zs(v,m.mode,T),p.return=m,m=p),a(m)):n(m,p)}return Re}var Qn=Oa(!0),Fa=Oa(!1),El=en(null),Nl=null,Kn=null,ss=null;function os(){ss=Kn=Nl=null}function as(e){var t=El.current;xe(El),e._currentValue=t}function us(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,r!==null&&(r.childLanes|=t)):r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function Yn(e,t){Nl=e,ss=Kn=null,e=e.dependencies,e!==null&&e.firstContext!==null&&((e.lanes&t)!==0&&(it=!0),e.firstContext=null)}function vt(e){var t=e._currentValue;if(ss!==e)if(e={context:e,memoizedValue:t,next:null},Kn===null){if(Nl===null)throw Error(d(308));Kn=e,Nl.dependencies={lanes:0,firstContext:e}}else Kn=Kn.next=e;return t}var xn=null;function cs(e){xn===null?xn=[e]:xn.push(e)}function Da(e,t,n,r){var l=t.interleaved;return l===null?(n.next=n,cs(t)):(n.next=l.next,l.next=n),t.interleaved=n,Vt(e,r)}function Vt(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var rn=!1;function ds(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function $a(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function Ht(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function ln(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,(oe&2)!==0){var l=r.pending;return l===null?t.next=t:(t.next=l.next,l.next=t),r.pending=t,Vt(e,n)}return l=r.interleaved,l===null?(t.next=t,cs(r)):(t.next=l.next,l.next=t),r.interleaved=t,Vt(e,n)}function Cl(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,(n&4194240)!==0)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,Ei(e,n)}}function Ua(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var l=null,s=null;if(n=n.firstBaseUpdate,n!==null){do{var a={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};s===null?l=s=a:s=s.next=a,n=n.next}while(n!==null);s===null?l=s=t:s=s.next=t}else l=s=t;n={baseState:r.baseState,firstBaseUpdate:l,lastBaseUpdate:s,shared:r.shared,effects:r.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function Tl(e,t,n,r){var l=e.updateQueue;rn=!1;var s=l.firstBaseUpdate,a=l.lastBaseUpdate,c=l.shared.pending;if(c!==null){l.shared.pending=null;var f=c,g=f.next;f.next=null,a===null?s=g:a.next=g,a=f;var S=e.alternate;S!==null&&(S=S.updateQueue,c=S.lastBaseUpdate,c!==a&&(c===null?S.firstBaseUpdate=g:c.next=g,S.lastBaseUpdate=f))}if(s!==null){var N=l.baseState;a=0,S=g=f=null,c=s;do{var k=c.lane,M=c.eventTime;if((r&k)===k){S!==null&&(S=S.next={eventTime:M,lane:0,tag:c.tag,payload:c.payload,callback:c.callback,next:null});e:{var $=e,U=c;switch(k=t,M=n,U.tag){case 1:if($=U.payload,typeof $=="function"){N=$.call(M,N,k);break e}N=$;break e;case 3:$.flags=$.flags&-65537|128;case 0:if($=U.payload,k=typeof $=="function"?$.call(M,N,k):$,k==null)break e;N=L({},N,k);break e;case 2:rn=!0}}c.callback!==null&&c.lane!==0&&(e.flags|=64,k=l.effects,k===null?l.effects=[c]:k.push(c))}else M={eventTime:M,lane:k,tag:c.tag,payload:c.payload,callback:c.callback,next:null},S===null?(g=S=M,f=N):S=S.next=M,a|=k;if(c=c.next,c===null){if(c=l.shared.pending,c===null)break;k=c,c=k.next,k.next=null,l.lastBaseUpdate=k,l.shared.pending=null}}while(!0);if(S===null&&(f=N),l.baseState=f,l.firstBaseUpdate=g,l.lastBaseUpdate=S,t=l.shared.interleaved,t!==null){l=t;do a|=l.lane,l=l.next;while(l!==t)}else s===null&&(l.shared.lanes=0);kn|=a,e.lanes=a,e.memoizedState=N}}function Va(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var r=vs.transition;vs.transition={};try{e(!1),t()}finally{de=n,vs.transition=r}}function su(){return gt().memoizedState}function Bd(e,t,n){var r=un(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},ou(e))au(t,n);else if(n=Da(e,t,n,r),n!==null){var l=nt();Ct(n,e,r,l),uu(n,t,r)}}function Wd(e,t,n){var r=un(e),l={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(ou(e))au(t,l);else{var s=e.alternate;if(e.lanes===0&&(s===null||s.lanes===0)&&(s=t.lastRenderedReducer,s!==null))try{var a=t.lastRenderedState,c=s(a,n);if(l.hasEagerState=!0,l.eagerState=c,kt(c,a)){var f=t.interleaved;f===null?(l.next=l,cs(t)):(l.next=f.next,f.next=l),t.interleaved=l;return}}catch{}finally{}n=Da(e,t,l,r),n!==null&&(l=nt(),Ct(n,e,r,l),uu(n,t,r))}}function ou(e){var t=e.alternate;return e===Ce||t!==null&&t===Ce}function au(e,t){Ar=Al=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function uu(e,t,n){if((n&4194240)!==0){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,Ei(e,n)}}var Rl={readContext:vt,useCallback:Je,useContext:Je,useEffect:Je,useImperativeHandle:Je,useInsertionEffect:Je,useLayoutEffect:Je,useMemo:Je,useReducer:Je,useRef:Je,useState:Je,useDebugValue:Je,useDeferredValue:Je,useTransition:Je,useMutableSource:Je,useSyncExternalStore:Je,useId:Je,unstable_isNewReconciler:!1},Gd={readContext:vt,useCallback:function(e,t){return At().memoizedState=[e,t===void 0?null:t],e},useContext:vt,useEffect:Ja,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,Ll(4194308,4,tu.bind(null,t,e),n)},useLayoutEffect:function(e,t){return Ll(4194308,4,e,t)},useInsertionEffect:function(e,t){return Ll(4,2,e,t)},useMemo:function(e,t){var n=At();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=At();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=Bd.bind(null,Ce,e),[r.memoizedState,e]},useRef:function(e){var t=At();return e={current:e},t.memoizedState=e},useState:Za,useDebugValue:Ss,useDeferredValue:function(e){return At().memoizedState=e},useTransition:function(){var e=Za(!1),t=e[0];return e=Hd.bind(null,e[1]),At().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=Ce,l=At();if(Se){if(n===void 0)throw Error(d(407));n=n()}else{if(n=t(),Ge===null)throw Error(d(349));(jn&30)!==0||Ga(r,t,n)}l.memoizedState=n;var s={value:n,getSnapshot:t};return l.queue=s,Ja(Ka.bind(null,r,s,e),[e]),r.flags|=2048,Rr(9,Qa.bind(null,r,s,n,t),void 0,null),n},useId:function(){var e=At(),t=Ge.identifierPrefix;if(Se){var n=Ut,r=$t;n=(r&~(1<<32-jt(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=Lr++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=a.createElement(n,{is:r.is}):(e=a.createElement(n),n==="select"&&(a=e,r.multiple?a.multiple=!0:r.size&&(a.size=r.size))):e=a.createElementNS(e,n),e[Pt]=t,e[Er]=r,Pu(e,t,!1,!1),t.stateNode=e;e:{switch(a=mi(n,r),n){case"dialog":ye("cancel",e),ye("close",e),l=r;break;case"iframe":case"object":case"embed":ye("load",e),l=r;break;case"video":case"audio":for(l=0;lbn&&(t.flags|=128,r=!0,Ir(s,!1),t.lanes=4194304)}else{if(!r)if(e=Pl(a),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),Ir(s,!0),s.tail===null&&s.tailMode==="hidden"&&!a.alternate&&!Se)return be(t),null}else 2*Me()-s.renderingStartTime>bn&&n!==1073741824&&(t.flags|=128,r=!0,Ir(s,!1),t.lanes=4194304);s.isBackwards?(a.sibling=t.child,t.child=a):(n=s.last,n!==null?n.sibling=a:t.child=a,s.last=a)}return s.tail!==null?(t=s.tail,s.rendering=t,s.tail=t.sibling,s.renderingStartTime=Me(),t.sibling=null,n=Ne.current,ve(Ne,r?n&1|2:n&1),t):(be(t),null);case 22:case 23:return Ks(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&(t.mode&1)!==0?(pt&1073741824)!==0&&(be(t),t.subtreeFlags&6&&(t.flags|=8192)):be(t),null;case 24:return null;case 25:return null}throw Error(d(156,t.tag))}function bd(e,t){switch(ns(t),t.tag){case 1:return lt(t.type)&&yl(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Xn(),xe(rt),xe(qe),ms(),e=t.flags,(e&65536)!==0&&(e&128)===0?(t.flags=e&-65537|128,t):null;case 5:return ps(t),null;case 13:if(xe(Ne),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(d(340));Gn()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return xe(Ne),null;case 4:return Xn(),null;case 10:return as(t.type._context),null;case 22:case 23:return Ks(),null;case 24:return null;default:return null}}var Dl=!1,et=!1,ef=typeof WeakSet=="function"?WeakSet:Set,D=null;function qn(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){Ae(e,t,r)}else n.current=null}function Is(e,t,n){try{n()}catch(r){Ae(e,t,r)}}var Lu=!1;function tf(e,t){if(Ki=ll,e=ca(),$i(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var l=r.anchorOffset,s=r.focusNode;r=r.focusOffset;try{n.nodeType,s.nodeType}catch{n=null;break e}var a=0,c=-1,f=-1,g=0,S=0,N=e,k=null;t:for(;;){for(var M;N!==n||l!==0&&N.nodeType!==3||(c=a+l),N!==s||r!==0&&N.nodeType!==3||(f=a+r),N.nodeType===3&&(a+=N.nodeValue.length),(M=N.firstChild)!==null;)k=N,N=M;for(;;){if(N===e)break t;if(k===n&&++g===l&&(c=a),k===s&&++S===r&&(f=a),(M=N.nextSibling)!==null)break;N=k,k=N.parentNode}N=M}n=c===-1||f===-1?null:{start:c,end:f}}else n=null}n=n||{start:0,end:0}}else n=null;for(Yi={focusedElem:e,selectionRange:n},ll=!1,D=t;D!==null;)if(t=D,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,D=e;else for(;D!==null;){t=D;try{var $=t.alternate;if((t.flags&1024)!==0)switch(t.tag){case 0:case 11:case 15:break;case 1:if($!==null){var U=$.memoizedProps,Re=$.memoizedState,m=t.stateNode,p=m.getSnapshotBeforeUpdate(t.elementType===t.type?U:_t(t.type,U),Re);m.__reactInternalSnapshotBeforeUpdate=p}break;case 3:var v=t.stateNode.containerInfo;v.nodeType===1?v.textContent="":v.nodeType===9&&v.documentElement&&v.removeChild(v.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(d(163))}}catch(T){Ae(t,t.return,T)}if(e=t.sibling,e!==null){e.return=t.return,D=e;break}D=t.return}return $=Lu,Lu=!1,$}function Or(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var l=r=r.next;do{if((l.tag&e)===e){var s=l.destroy;l.destroy=void 0,s!==void 0&&Is(t,n,s)}l=l.next}while(l!==r)}}function $l(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function Os(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function Mu(e){var t=e.alternate;t!==null&&(e.alternate=null,Mu(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[Pt],delete t[Er],delete t[Ji],delete t[Fd],delete t[Dd])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function Ru(e){return e.tag===5||e.tag===3||e.tag===4}function Iu(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Ru(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.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 Fs(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=vl));else if(r!==4&&(e=e.child,e!==null))for(Fs(e,t,n),e=e.sibling;e!==null;)Fs(e,t,n),e=e.sibling}function Ds(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(Ds(e,t,n),e=e.sibling;e!==null;)Ds(e,t,n),e=e.sibling}var Ye=null,Et=!1;function sn(e,t,n){for(n=n.child;n!==null;)Ou(e,t,n),n=n.sibling}function Ou(e,t,n){if(Tt&&typeof Tt.onCommitFiberUnmount=="function")try{Tt.onCommitFiberUnmount(Jr,n)}catch{}switch(n.tag){case 5:et||qn(n,t);case 6:var r=Ye,l=Et;Ye=null,sn(e,t,n),Ye=r,Et=l,Ye!==null&&(Et?(e=Ye,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):Ye.removeChild(n.stateNode));break;case 18:Ye!==null&&(Et?(e=Ye,n=n.stateNode,e.nodeType===8?qi(e.parentNode,n):e.nodeType===1&&qi(e,n),hr(e)):qi(Ye,n.stateNode));break;case 4:r=Ye,l=Et,Ye=n.stateNode.containerInfo,Et=!0,sn(e,t,n),Ye=r,Et=l;break;case 0:case 11:case 14:case 15:if(!et&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){l=r=r.next;do{var s=l,a=s.destroy;s=s.tag,a!==void 0&&((s&2)!==0||(s&4)!==0)&&Is(n,t,a),l=l.next}while(l!==r)}sn(e,t,n);break;case 1:if(!et&&(qn(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(c){Ae(n,t,c)}sn(e,t,n);break;case 21:sn(e,t,n);break;case 22:n.mode&1?(et=(r=et)||n.memoizedState!==null,sn(e,t,n),et=r):sn(e,t,n);break;default:sn(e,t,n)}}function Fu(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new ef),t.forEach(function(r){var l=df.bind(null,e,r);n.has(r)||(n.add(r),r.then(l,l))})}}function Nt(e,t){var n=t.deletions;if(n!==null)for(var r=0;rl&&(l=a),r&=~s}if(r=l,r=Me()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*rf(r/1960))-r,10e?16:e,an===null)var r=!1;else{if(e=an,an=null,Wl=0,(oe&6)!==0)throw Error(d(331));var l=oe;for(oe|=4,D=e.current;D!==null;){var s=D,a=s.child;if((D.flags&16)!==0){var c=s.deletions;if(c!==null){for(var f=0;fMe()-Vs?_n(e,0):Us|=n),ot(e,t)}function Zu(e,t){t===0&&((e.mode&1)===0?t=1:(t=el,el<<=1,(el&130023424)===0&&(el=4194304)));var n=nt();e=Vt(e,t),e!==null&&(ur(e,t,n),ot(e,n))}function cf(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),Zu(e,n)}function df(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,l=e.memoizedState;l!==null&&(n=l.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(d(314))}r!==null&&r.delete(t),Zu(e,n)}var qu;qu=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||rt.current)it=!0;else{if((e.lanes&n)===0&&(t.flags&128)===0)return it=!1,qd(e,t,n);it=(e.flags&131072)!==0}else it=!1,Se&&(t.flags&1048576)!==0&&za(t,kl,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;Fl(e,t),e=t.pendingProps;var l=Hn(t,qe.current);Yn(t,n),l=ys(null,t,r,e,l,n);var s=xs();return t.flags|=1,typeof l=="object"&&l!==null&&typeof l.render=="function"&&l.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,lt(r)?(s=!0,xl(t)):s=!1,t.memoizedState=l.state!==null&&l.state!==void 0?l.state:null,ds(t),l.updater=Il,t.stateNode=l,l._reactInternals=t,Es(t,r,e,n),t=Ps(null,t,r,!0,s,n)):(t.tag=0,Se&&s&&ts(t),tt(null,t,l,n),t=t.child),t;case 16:r=t.elementType;e:{switch(Fl(e,t),e=t.pendingProps,l=r._init,r=l(r._payload),t.type=r,l=t.tag=pf(r),e=_t(r,e),l){case 0:t=Ts(null,t,r,e,n);break e;case 1:t=Su(null,t,r,e,n);break e;case 11:t=yu(null,t,r,e,n);break e;case 14:t=xu(null,t,r,_t(r.type,e),n);break e}throw Error(d(306,r,""))}return t;case 0:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:_t(r,l),Ts(e,t,r,l,n);case 1:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:_t(r,l),Su(e,t,r,l,n);case 3:e:{if(_u(t),e===null)throw Error(d(387));r=t.pendingProps,s=t.memoizedState,l=s.element,$a(e,t),Tl(t,r,null,n);var a=t.memoizedState;if(r=a.element,s.isDehydrated)if(s={element:r,isDehydrated:!1,cache:a.cache,pendingSuspenseBoundaries:a.pendingSuspenseBoundaries,transitions:a.transitions},t.updateQueue.baseState=s,t.memoizedState=s,t.flags&256){l=Zn(Error(d(423)),t),t=Eu(e,t,r,n,l);break e}else if(r!==l){l=Zn(Error(d(424)),t),t=Eu(e,t,r,n,l);break e}else for(ft=bt(t.stateNode.containerInfo.firstChild),dt=t,Se=!0,St=null,n=Fa(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(Gn(),r===l){t=Bt(e,t,n);break e}tt(e,t,r,n)}t=t.child}return t;case 5:return Ha(t),e===null&&ls(t),r=t.type,l=t.pendingProps,s=e!==null?e.memoizedProps:null,a=l.children,Xi(r,l)?a=null:s!==null&&Xi(r,s)&&(t.flags|=32),ku(e,t),tt(e,t,a,n),t.child;case 6:return e===null&&ls(t),null;case 13:return Nu(e,t,n);case 4:return fs(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=Qn(t,null,r,n):tt(e,t,r,n),t.child;case 11:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:_t(r,l),yu(e,t,r,l,n);case 7:return tt(e,t,t.pendingProps,n),t.child;case 8:return tt(e,t,t.pendingProps.children,n),t.child;case 12:return tt(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,l=t.pendingProps,s=t.memoizedProps,a=l.value,ve(El,r._currentValue),r._currentValue=a,s!==null)if(kt(s.value,a)){if(s.children===l.children&&!rt.current){t=Bt(e,t,n);break e}}else for(s=t.child,s!==null&&(s.return=t);s!==null;){var c=s.dependencies;if(c!==null){a=s.child;for(var f=c.firstContext;f!==null;){if(f.context===r){if(s.tag===1){f=Ht(-1,n&-n),f.tag=2;var g=s.updateQueue;if(g!==null){g=g.shared;var S=g.pending;S===null?f.next=f:(f.next=S.next,S.next=f),g.pending=f}}s.lanes|=n,f=s.alternate,f!==null&&(f.lanes|=n),us(s.return,n,t),c.lanes|=n;break}f=f.next}}else if(s.tag===10)a=s.type===t.type?null:s.child;else if(s.tag===18){if(a=s.return,a===null)throw Error(d(341));a.lanes|=n,c=a.alternate,c!==null&&(c.lanes|=n),us(a,n,t),a=s.sibling}else a=s.child;if(a!==null)a.return=s;else for(a=s;a!==null;){if(a===t){a=null;break}if(s=a.sibling,s!==null){s.return=a.return,a=s;break}a=a.return}s=a}tt(e,t,l.children,n),t=t.child}return t;case 9:return l=t.type,r=t.pendingProps.children,Yn(t,n),l=vt(l),r=r(l),t.flags|=1,tt(e,t,r,n),t.child;case 14:return r=t.type,l=_t(r,t.pendingProps),l=_t(r.type,l),xu(e,t,r,l,n);case 15:return wu(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:_t(r,l),Fl(e,t),t.tag=1,lt(r)?(e=!0,xl(t)):e=!1,Yn(t,n),du(t,r,l),Es(t,r,l,n),Ps(null,t,r,!0,e,n);case 19:return Tu(e,t,n);case 22:return ju(e,t,n)}throw Error(d(156,t.tag))};function Ju(e,t){return Ao(e,t)}function ff(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function xt(e,t,n,r){return new ff(e,t,n,r)}function Xs(e){return e=e.prototype,!(!e||!e.isReactComponent)}function pf(e){if(typeof e=="function")return Xs(e)?1:0;if(e!=null){if(e=e.$$typeof,e===_e)return 11;if(e===G)return 14}return 2}function dn(e,t){var n=e.alternate;return n===null?(n=xt(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Yl(e,t,n,r,l,s){var a=2;if(r=e,typeof e=="function")Xs(e)&&(a=1);else if(typeof e=="string")a=5;else e:switch(e){case pe:return Nn(n.children,l,s,t);case we:a=8,l|=8;break;case Oe:return e=xt(12,n,t,l|2),e.elementType=Oe,e.lanes=s,e;case w:return e=xt(13,n,t,l),e.elementType=w,e.lanes=s,e;case Be:return e=xt(19,n,t,l),e.elementType=Be,e.lanes=s,e;case ie:return Xl(n,l,s,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case je:a=10;break e;case Fe:a=9;break e;case _e:a=11;break e;case G:a=14;break e;case Ee:a=16,r=null;break e}throw Error(d(130,e==null?e:typeof e,""))}return t=xt(a,n,t,l),t.elementType=e,t.type=r,t.lanes=s,t}function Nn(e,t,n,r){return e=xt(7,e,r,t),e.lanes=n,e}function Xl(e,t,n,r){return e=xt(22,e,r,t),e.elementType=ie,e.lanes=n,e.stateNode={isHidden:!1},e}function Zs(e,t,n){return e=xt(6,e,null,t),e.lanes=n,e}function qs(e,t,n){return t=xt(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function hf(e,t,n,r,l){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=_i(0),this.expirationTimes=_i(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=_i(0),this.identifierPrefix=r,this.onRecoverableError=l,this.mutableSourceEagerHydrationData=null}function Js(e,t,n,r,l,s,a,c,f){return e=new hf(e,t,n,c,f),t===1?(t=1,s===!0&&(t|=8)):t=0,s=xt(3,null,null,t),e.current=s,s.stateNode=e,s.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},ds(s),e}function mf(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(o)}catch(u){console.error(u)}}return o(),lo.exports=Cf(),lo.exports}var fc;function Pf(){if(fc)return ni;fc=1;var o=Tf();return ni.createRoot=o.createRoot,ni.hydrateRoot=o.hydrateRoot,ni}var zf=Pf();const Af=yc(zf);function se({name:o,size:u=24,...d}){const y={agent:i.jsxs(i.Fragment,{children:[i.jsx("rect",{x:"5",y:"8",width:"14",height:"11",rx:"4"}),i.jsx("path",{d:"M12 8V4m0 0-2-2m2 2 2-2M8.5 13h.01m6.99 0h.01M9 17h6M5 12H3v4h2m14-4h2v4h-2"})]}),battery:i.jsxs(i.Fragment,{children:[i.jsx("rect",{x:"5",y:"3",width:"12",height:"18",rx:"2.5"}),i.jsx("path",{d:"M9 1h4M17 9h2v6h-2M8 17l4-8v5h4l-5 7"})]}),bell:i.jsx("path",{d:"M18 8a6 6 0 0 0-12 0c0 7-3 7-3 9h18c0-2-3-2-3-9M10 21h4"}),check:i.jsx("path",{d:"m5 12 4 4L19 6"}),chart:i.jsx("path",{d:"M4 19V9m5 10V5m5 14v-7m5 7V3"}),chevron:i.jsx("path",{d:"m9 5 7 7-7 7"}),cloud:i.jsxs(i.Fragment,{children:[i.jsx("path",{d:"M7 18h10a4 4 0 0 0 .7-7.94A6 6 0 0 0 6.2 8.3 4.8 4.8 0 0 0 7 18Z"}),i.jsx("path",{d:"M9 14h6"})]}),code:i.jsx("path",{d:"m8 9-3 3 3 3m8-6 3 3-3 3m-3-9-2 12"}),copy:i.jsxs(i.Fragment,{children:[i.jsx("rect",{x:"8",y:"8",width:"11",height:"11",rx:"2"}),i.jsx("path",{d:"M16 8V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h3"})]}),download:i.jsx("path",{d:"M12 3v11m0 0 4-4m-4 4-4-4M5 20h14"}),device:i.jsxs(i.Fragment,{children:[i.jsx("rect",{x:"6",y:"2",width:"12",height:"20",rx:"2.5"}),i.jsx("path",{d:"M10 5h4m-4 14h4"})]}),fingerprint:i.jsxs(i.Fragment,{children:[i.jsx("path",{d:"M12 11a2 2 0 0 1 2 2c0 3-.5 5.5-1.5 8"}),i.jsx("path",{d:"M8.5 21c1-2 1.5-5 1.5-8a2 2 0 0 1 4 0c0 4-.8 7-1.4 8.5"}),i.jsx("path",{d:"M6 19c.8-2.1 1-4 1-6a5 5 0 0 1 10 0c0 3-.3 5.2-1 7.5"}),i.jsx("path",{d:"M4 16v-3a8 8 0 0 1 16 0c0 2-.1 3.5-.5 5"})]}),grid:i.jsxs(i.Fragment,{children:[i.jsx("rect",{x:"3",y:"3",width:"7",height:"7",rx:"1.5"}),i.jsx("rect",{x:"14",y:"3",width:"7",height:"7",rx:"1.5"}),i.jsx("rect",{x:"3",y:"14",width:"7",height:"7",rx:"1.5"}),i.jsx("rect",{x:"14",y:"14",width:"7",height:"7",rx:"1.5"})]}),book:i.jsxs(i.Fragment,{children:[i.jsx("path",{d:"M4 5.5A2.5 2.5 0 0 1 6.5 3H20v16H6.5A2.5 2.5 0 0 0 4 21V5.5Z"}),i.jsx("path",{d:"M4 5.5V21m4-14h8m-8 4h6"})]}),heartbeat:i.jsx("path",{d:"M3 12h4l2-7 4 14 2-7h6"}),home:i.jsxs(i.Fragment,{children:[i.jsx("path",{d:"m3 11 9-8 9 8"}),i.jsx("path",{d:"M5 10v10h14V10M9 20v-6h6v6"})]}),link:i.jsxs(i.Fragment,{children:[i.jsx("path",{d:"M10 13a5 5 0 0 0 7.1 0l2-2a5 5 0 0 0-7.1-7.1l-1.1 1.1"}),i.jsx("path",{d:"M14 11a5 5 0 0 0-7.1 0l-2 2A5 5 0 0 0 12 20.1l1.1-1.1"})]}),lock:i.jsxs(i.Fragment,{children:[i.jsx("rect",{x:"5",y:"10",width:"14",height:"11",rx:"2.5"}),i.jsx("path",{d:"M8 10V7a4 4 0 0 1 8 0v3m-4 4v3"})]}),power:i.jsx("path",{d:"M12 2v10m5.7-7.7a9 9 0 1 1-11.4 0"}),qr:i.jsxs(i.Fragment,{children:[i.jsx("rect",{x:"3",y:"3",width:"7",height:"7",rx:"1"}),i.jsx("rect",{x:"14",y:"3",width:"7",height:"7",rx:"1"}),i.jsx("rect",{x:"3",y:"14",width:"7",height:"7",rx:"1"}),i.jsx("path",{d:"M14 14h3v3h-3zm4 4h3v3h-3zm0-4h3m-7 7h2"})]}),refresh:i.jsxs(i.Fragment,{children:[i.jsx("path",{d:"M20 7V3h-4"}),i.jsx("path",{d:"M20 3a9 9 0 1 0 2 9"})]}),route:i.jsxs(i.Fragment,{children:[i.jsx("circle",{cx:"6",cy:"18",r:"2"}),i.jsx("circle",{cx:"18",cy:"6",r:"2"}),i.jsx("path",{d:"M8 18h3a3 3 0 0 0 3-3V9a3 3 0 0 1 3-3h-1M8 6h3m-5-2v4"})]}),scan:i.jsxs(i.Fragment,{children:[i.jsx("path",{d:"M8 3H5a2 2 0 0 0-2 2v3m13-5h3a2 2 0 0 1 2 2v3M8 21H5a2 2 0 0 1-2-2v-3m13 5h3a2 2 0 0 0 2-2v-3"}),i.jsx("path",{d:"M7 12h10"})]}),search:i.jsxs(i.Fragment,{children:[i.jsx("circle",{cx:"10.8",cy:"10.8",r:"6.8"}),i.jsx("path",{d:"m16 16 5 5"})]}),server:i.jsxs(i.Fragment,{children:[i.jsx("rect",{x:"3",y:"3",width:"18",height:"7",rx:"2"}),i.jsx("rect",{x:"3",y:"14",width:"18",height:"7",rx:"2"}),i.jsx("path",{d:"M7 6.5h.01M7 17.5h.01M11 6.5h6M11 17.5h6"})]}),settings:i.jsxs(i.Fragment,{children:[i.jsx("circle",{cx:"12",cy:"12",r:"3"}),i.jsx("path",{d:"M19.4 15a1.7 1.7 0 0 0 .34 1.88l.06.06-2.86 2.86-.06-.06A1.7 1.7 0 0 0 15 19.4a1.7 1.7 0 0 0-1 .6 1.7 1.7 0 0 0-.4 1v.1H9.5V21a1.7 1.7 0 0 0-1.1-1.6 1.7 1.7 0 0 0-1.88.34l-.06.06-2.86-2.86.06-.06A1.7 1.7 0 0 0 4 15a1.7 1.7 0 0 0-.6-1 1.7 1.7 0 0 0-1-.4h-.1V9.5h.1A1.7 1.7 0 0 0 4 8.4a1.7 1.7 0 0 0-.34-1.88l-.06-.06L6.46 3.6l.06.06A1.7 1.7 0 0 0 8.4 4a1.7 1.7 0 0 0 1-.6 1.7 1.7 0 0 0 .4-1v-.1h4.1v.1A1.7 1.7 0 0 0 15 4a1.7 1.7 0 0 0 1.88-.34l.06-.06 2.86 2.86-.06.06A1.7 1.7 0 0 0 19.4 8c.14.38.36.72.66 1 .3.27.68.42 1.08.43h.1v4.1h-.1A1.7 1.7 0 0 0 19.4 15Z"})]}),shield:i.jsxs(i.Fragment,{children:[i.jsx("path",{d:"M12 3 5 6v5c0 4.7 2.9 8.2 7 10 4.1-1.8 7-5.3 7-10V6l-7-3Z"}),i.jsx("path",{d:"m9 12 2 2 4-5"})]}),storage:i.jsxs(i.Fragment,{children:[i.jsx("ellipse",{cx:"12",cy:"5",rx:"7",ry:"3"}),i.jsx("path",{d:"M5 5v7c0 1.7 3.1 3 7 3s7-1.3 7-3V5M5 12v7c0 1.7 3.1 3 7 3s7-1.3 7-3v-7"})]}),temperature:i.jsxs(i.Fragment,{children:[i.jsx("path",{d:"M9 14.8V5a3 3 0 0 1 6 0v9.8a5 5 0 1 1-6 0Z"}),i.jsx("path",{d:"M12 7v9"})]}),token:i.jsxs(i.Fragment,{children:[i.jsx("circle",{cx:"8",cy:"15",r:"4"}),i.jsx("path",{d:"m11 12 8-8m-3 3 2 2m-5 1 2 2"})]}),users:i.jsxs(i.Fragment,{children:[i.jsx("circle",{cx:"9",cy:"8",r:"3"}),i.jsx("path",{d:"M3.5 20a5.5 5.5 0 0 1 11 0M16 5.5a3 3 0 0 1 0 5.8M17 14a5.2 5.2 0 0 1 3.5 5"})]}),wechat:i.jsxs(i.Fragment,{children:[i.jsx("path",{d:"M14 7a6 5 0 1 0-3.2 4.4L14 13l-.8-2A4.8 4.8 0 0 0 14 7Z"}),i.jsx("path",{d:"M12 13.5a5 4.2 0 1 0 3-3.9M16 17l-.7 1.8 2.8-1.3"}),i.jsx("path",{d:"M6.5 6.8h.01m3 0h.01m5 6.7h.01m2.6 0h.01"})]}),wifi:i.jsxs(i.Fragment,{children:[i.jsx("path",{d:"M4 10a12 12 0 0 1 16 0M7 13a7.5 7.5 0 0 1 10 0m-7 3a3 3 0 0 1 4 0"}),i.jsx("circle",{cx:"12",cy:"19",r:"1",fill:"currentColor",stroke:"none"})]})};return i.jsx("svg",{"aria-hidden":"true",fill:"none",height:u,viewBox:"0 0 24 24",width:u,stroke:"currentColor",strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:"1.8",...d,children:y[o]})}const Ze=o=>({state:"unavailable",source:o}),Lf={overview:Ze("GET /api/v3/workbench/overview"),devices:Ze("GET /api/v3/fleet/devices"),hookStatus:Ze("GET /api/v3/wechat/hook/status"),groups:Ze("GET /api/v3/device-groups"),release:Ze("GET /api/v3/releases/latest"),engine:Ze("GET /api/v3/ai/status + /api/v3/ai/brain/dashboard"),aiOperations:Ze("GET /api/v3/ai/tasks"),integrations:{applications:Ze("GET /api/v3/integrations/apps"),authorizations:Ze("GET /api/v3/integrations/authorizations"),usage:Ze("GET /api/v3/integrations/usage"),manifest:Ze("GET /api/v3/integration/manifest"),documents:Ze("GET /api/v3/integrations/docs/catalog"),knowledge:Ze("GET /api/v3/kb/search")}},ce=o=>typeof o=="object"&&o!==null&&!Array.isArray(o),W=o=>{if(typeof o=="string"&&o.trim())return o;if(typeof o=="number")return String(o)},Gt=o=>{if(typeof o=="boolean")return o;if(["true","1","online","connected","running","ready"].includes(String(o).toLowerCase()))return!0;if(["false","0","offline","disconnected","stopped"].includes(String(o).toLowerCase()))return!1},Rt=o=>{if(o==null||o==="")return;const u=typeof o=="number"?o:Number(o);return Number.isFinite(u)?u:void 0},li=o=>ce(o)?o.data??o:o,xc=(o,u)=>{if(ce(o)){const d=o.detail;return ce(d)?W(d.message)||W(o.message)||u:W(o.message)||W(d)||u}return u},Te=o=>{if(ce(o))return W(o.sampled_at)||W(o.sampledAt)||W(o.server_time)||W(o.serverTime)||W(o.updated_at)||W(o.updatedAt)};async function wc(o){try{const u=await fetch(o,{method:"GET",credentials:"same-origin",headers:{Accept:"application/json"}}),d=await u.json().catch(()=>({}));return u.ok?{ok:!0,payload:d,status:u.status}:{ok:!1,status:u.status,message:xc(d,`读取接口失败(${u.status})`)}}catch(u){return{ok:!1,status:0,message:u instanceof Error?u.message:"读取接口失败"}}}async function ai(o,u,d){const y=await fetch(o,{method:u,credentials:"same-origin",headers:{Accept:"application/json","Content-Type":"application/json","X-Actor-Id":"console"},body:d===void 0?void 0:JSON.stringify(d)}),_=await y.json().catch(()=>({}));if(!y.ok)throw new Error(xc(_,`操作失败(${y.status})`));return li(_)}async function Mf(){const o=await wc("/api/v3/security/modules");if(!o.ok)throw new Error(o.message);const u=li(o.payload);if(!ce(u)||!Array.isArray(u.modules))throw new Error("安全模块接口返回格式错误");return u}async function Rf(o){return await ai("/api/v3/security/modules/global","PUT",{enabled:o})}async function If(o,u){return await ai(`/api/v3/security/modules/${encodeURIComponent(o)}`,"PUT",u)}async function Of(o){return await ai("/api/v3/security/modules","POST",o)}async function Ff(o){await ai(`/api/v3/security/modules/${encodeURIComponent(o)}`,"DELETE")}const pc=(o,u,d,y)=>u.ok?{state:"ready",data:d,source:o,sourceAt:y,status:u.status}:{state:u.status===401||u.status===403?"forbidden":"unavailable",source:o,status:u.status,error:u.message};async function $e(o,u,d){let y;for(const _ of o){const x=await wc(_);if(x.ok){const z=d(li(x.payload));return pc(`GET ${_}`,x,z.data,z.sourceAt||Te(li(x.payload)))}if(y=x,x.status!==404)break}return pc(u,y||{ok:!1,status:0,message:"读取接口失败"})}const Qt=(o,u)=>{if(Array.isArray(o))return o;if(!ce(o))return[];for(const d of u)if(Array.isArray(o[d]))return o[d];return[]},oo=o=>{if(!Array.isArray(o))return;const u=o.filter(d=>typeof d=="string"&&d.trim().length>0);return u.length?u:void 0},Df=o=>{if(!ce(o))return;const u=W(o.device_id)||W(o.deviceId)||W(o.id);if(!u)return;const d=ce(o.wechat)?o.wechat:{},y=ce(o.agent)?o.agent:{},_=ce(o.hook)?o.hook:{};return{deviceId:u,name:W(o.name)||W(o.device_name),model:W(o.model)||W(o.model_name),androidVersion:W(o.android_version)||W(o.androidVersion)||W(o.os_version),projectId:W(o.project_id)||W(o.projectId),groupId:W(o.group_id)||W(o.groupId)||W(o.project_id),status:W(o.status),online:Gt(o.online)??Gt(o.ws_online)??(W(o.status)==="online"?!0:void 0),agentVersion:W(o.agent_version)||W(o.agentVersion)||W(o.app_version),agentRunning:Gt(o.agent_running)??Gt(y.running),hookAvailable:Gt(o.hook_available)??Gt(o.supports_hook)??Gt(_.available),wechatRunning:Gt(o.wechat_running)??Gt(d.running),wechatId:W(o.wxid)||W(o.wechat_id)||W(d.id)||W(d.wechat_id),friendCount:Rt(o.friend_count)??Rt(d.friend_count),wechatVersion:W(o.wechat_version)||W(d.version),batteryPercent:Rt(o.battery_percent)??Rt(o.batteryPercent)??Rt(ce(o.battery)?o.battery.percent:void 0),networkType:W(o.network_type)||W(o.networkType)||W(ce(o.network)?o.network.type:void 0),healthScore:Rt(o.health_score)??Rt(o.healthScore)??Rt(ce(o.health)?o.health.score:void 0),tags:oo(o.tags)||oo(o.labels)||oo(o.tag_names),lastHeartbeat:W(o.last_heartbeat)||W(o.lastHeartbeat),sourceAt:Te(o)||W(o.last_heartbeat),capabilities:Array.isArray(o.capabilities)?o.capabilities.filter(x=>typeof x=="string"):void 0,sourceKind:o.source_kind==="history"||o.sourceKind==="history"?"history":o.source_kind==="fixture"||o.sourceKind==="fixture"?"fixture":"live",sourceLabel:W(o.source_label)||W(o.sourceLabel),statusSource:W(o.status_source)||W(o.statusSource),raw:o}},jc=o=>Qt(o,["devices","items"]).flatMap(d=>{const y=Df(d);return y?[y]:[]}),$f=()=>{const o=new URLSearchParams(window.location.search).get("device_state_fixture");if(o)try{const u=JSON.parse(decodeURIComponent(escape(window.atob(o))));if(u.mode!=="readonly_fixture"||typeof u.label!="string")return;const d=jc(u.devices).map(y=>({...y,sourceKind:y.sourceKind||"fixture"}));return{label:u.label,devices:d}}catch{return}},Uf=o=>Qt(o,["items","groups"]).flatMap(u=>{if(!ce(u))return[];const d=W(u.group_id)||W(u.groupId)||W(u.id);return d?[{groupId:d,name:W(u.name)||d,memberCount:Rt(u.member_count)??Rt(u.memberCount),deviceIds:Array.isArray(u.device_ids)?u.device_ids.filter(y=>typeof y=="string"):void 0,sourceAt:Te(u)}]:[]});async function Vf(){var Fe,_e;const[o,u,d,y,_,x,z,I,F,X,q,Y,R,O,te,J]=await Promise.all([$e(["/api/v3/workbench/overview"],"GET /api/v3/workbench/overview",w=>({data:ce(w)?w:void 0,sourceAt:Te(w)})),$e(["/api/v3/fleet/devices","/api/v3/devices"],"GET /api/v3/fleet/devices",w=>({data:jc(w),sourceAt:Te(w)})),$e(["/api/v3/device-groups"],"GET /api/v3/device-groups",w=>({data:Uf(w),sourceAt:Te(w)})),$e(["/api/v3/releases/latest"],"GET /api/v3/releases/latest",w=>({data:ce(w)?w:void 0,sourceAt:Te(w)||(ce(w)?W(w.published_at):void 0)})),$e(["/api/v3/ai/status"],"GET /api/v3/ai/status",w=>({data:ce(w)?w:void 0,sourceAt:Te(w)})),$e(["/api/v3/ai/tasks?limit=20"],"GET /api/v3/ai/tasks",w=>({data:ce(w)?w:void 0,sourceAt:Te(w)})),$e(["/api/v3/ai/brain/dashboard"],"GET /api/v3/ai/brain/dashboard",w=>({data:ce(w)?w:void 0,sourceAt:Te(w)})),$e(["/api/v3/connection/status"],"GET /api/v3/connection/status",w=>({data:ce(w)?w:void 0,sourceAt:Te(w)})),$e(["/api/v3/process/status"],"GET /api/v3/process/status",w=>({data:ce(w)?w:void 0,sourceAt:Te(w)})),$e(["/api/v3/integration/health"],"GET /api/v3/integration/health",w=>({data:ce(w)?w:void 0,sourceAt:Te(w)})),$e(["/api/v3/integrations/apps","/api/v3/integrations/clients"],"GET /api/v3/integrations/apps",w=>({data:Qt(w,["items","applications"]),sourceAt:Te(w)})),$e(["/api/v3/integrations/authorizations","/api/v3/authorization-grants"],"GET /api/v3/integrations/authorizations",w=>({data:Qt(w,["items","grants"]),sourceAt:Te(w)})),$e(["/api/v3/integrations/usage"],"GET /api/v3/integrations/usage",w=>({data:ce(w)?w:void 0,sourceAt:Te(w)})),$e(["/api/v3/integration/manifest"],"GET /api/v3/integration/manifest",w=>({data:ce(w)?w:void 0,sourceAt:Te(w)})),$e(["/api/v3/integrations/docs/catalog","/api/v3/docs/catalog"],"GET /api/v3/integrations/docs/catalog",w=>({data:Qt(w,["items","documents"]),sourceAt:Te(w)})),$e(["/api/v3/kb/search?limit=10"],"GET /api/v3/kb/search",w=>({data:Qt(w,["items","results","documents"]),sourceAt:Te(w)}))]),b=$f(),Le=b&&u.state==="ready"?{...u,source:`${u.source} + readonly_fixture:${b.label}`,data:[...u.data||[],...b.devices]}:u,ze=(_e=(Fe=Le.data)==null?void 0:Fe[0])==null?void 0:_e.deviceId,Ie=ze?await $e([`/api/v3/wechat/hook/status?device_id=${encodeURIComponent(ze)}`],"GET /api/v3/wechat/hook/status",w=>({data:ce(w)?w:void 0,sourceAt:Te(w)})):Ze("GET /api/v3/wechat/hook/status"),fe=x.state==="ready"?Qt(x.data,["items","tasks"]):[],ge=fe.length&&ce(fe[0])?W(fe[0].task_id):void 0,[he,pe,we]=ge?await Promise.all([$e([`/api/v3/ai/tasks/${encodeURIComponent(ge)}`],"GET /api/v3/ai/tasks/{task_id}",w=>({data:ce(w)?w:void 0,sourceAt:Te(w)})),$e([`/api/v3/ai/tasks/${encodeURIComponent(ge)}/logs`],"GET /api/v3/ai/tasks/{task_id}/logs",w=>({data:ce(w)?w:void 0,sourceAt:Te(w)})),$e([`/api/v3/ai/tasks/${encodeURIComponent(ge)}/audit`],"GET /api/v3/ai/tasks/{task_id}/audit",w=>({data:ce(w)?w:void 0,sourceAt:Te(w)}))]):[Ze("GET /api/v3/ai/tasks/{task_id}"),Ze("GET /api/v3/ai/tasks/{task_id}/logs"),Ze("GET /api/v3/ai/tasks/{task_id}/audit")],Oe=x.state==="ready"?{state:"ready",source:"GET /api/v3/ai/tasks + /logs + /audit",sourceAt:[x.sourceAt,he.sourceAt,pe.sourceAt,we.sourceAt].filter(Boolean).sort().at(-1),data:{items:fe,selected:he.data,logs:Qt(pe.data,["items","logs"]),audit:Qt(we.data,["items","audit"])}}:{state:x.state,source:x.source,status:x.status,error:x.error},je=_.state==="ready"||z.state==="ready"||I.state==="ready"||F.state==="ready"||X.state==="ready"?{state:"ready",source:"GET /api/v3/ai/status + /api/v3/ai/brain/dashboard + /api/v3/connection/status + /api/v3/process/status",sourceAt:[_.sourceAt,z.sourceAt,I.sourceAt,F.sourceAt,X.sourceAt].filter(Boolean).sort().at(-1),data:{aiStatus:_.data,brain:z.data,connection:I.data,process:F.data,integrationHealth:X.data}}:{state:_.state==="forbidden"?"forbidden":"unavailable",source:"GET /api/v3/ai/status + /api/v3/ai/brain/dashboard",error:_.error||z.error,status:_.status||z.status};return{overview:o,devices:Le,hookStatus:Ie,groups:d,release:y,engine:je,aiOperations:Oe,integrations:{applications:q,authorizations:Y,usage:R,manifest:O,documents:te,knowledge:J},readAt:new Date().toISOString()}}const Hf=o=>ce(o)?{value:o.value,display:W(o.display),status:W(o.status),source:W(o.source),sampled_at:W(o.sampled_at)}:{},Gr=(o,u=15)=>{if(!o)return!1;const d=Date.parse(o);return Number.isFinite(d)&&Date.now()-d>u*60*1e3},Tn=o=>o.error||(o.status===403?"当前账号没有读取权限":o.status===401?"登录状态已失效":"接口未接通或暂无数据"),ii={device:{},agent:{},platform:{},binding:{},wechat:{},services:{},permissions:[],events:[],agentLogs:[]},Pn=o=>typeof o=="object"&&o!==null&&!Array.isArray(o),kc=o=>{if(typeof o!="string")return o;try{return JSON.parse(o)}catch{return o}},Bf=(o,u)=>{let d=o;for(const y of u.split(".")){if(!Pn(d)||!(y in d))return;d=d[y]}return d},H=(o,u)=>{for(const d of u){const y=Bf(o,d);if(y!=null&&y!=="")return y}},me=o=>{if(typeof o=="string")return o;if(typeof o=="number")return String(o)},Mt=o=>{const u=typeof o=="number"?o:Number(o);return Number.isFinite(u)?u:void 0},Ke=o=>{if(typeof o=="boolean")return o;if(o===1||o==="1"||o==="true"||o==="online"||o==="connected"||o==="running")return!0;if(o===0||o==="0"||o==="false"||o==="offline"||o==="disconnected"||o==="stopped")return!1},hc=o=>Array.isArray(o)?o.flatMap((u,d)=>{if(typeof u=="string")return[{id:String(d),message:u}];if(!Pn(u))return[];const y=me(H(u,["message","content","text","event","title"]));if(!y)return[];const _=me(H(u,["level","status","type"])),x=_==="success"||_==="warning"||_==="error"||_==="info"?_:void 0;return[{id:me(H(u,["id"]))??String(d),time:me(H(u,["time","timestamp","created_at","createdAt"])),message:y,level:x}]}):[],Wf=o=>Array.isArray(o)?o.flatMap((u,d)=>Pn(u)?[{key:me(H(u,["key","id","name"]))??String(d),name:me(H(u,["label","name","title"]))??`权限 ${d+1}`,granted:Ke(H(u,["granted","enabled","available","status"]))}]:[]):Pn(o)?Object.entries(o).map(([u,d])=>({key:u,name:u,granted:Ke(d)})):[],Gf=o=>{const u=Pn(o)?o:{};return{capturedAt:me(H(u,["capturedAt","captured_at","timestamp"])),device:{id:me(H(u,["device.id","device.deviceId","device.device_id","deviceId","device_id","id"])),name:me(H(u,["device.name","device.deviceName","device_name","name"])),model:me(H(u,["device.model","device.modelName","device.model_name","model"])),androidVersion:me(H(u,["device.androidVersion","device.android_version","androidVersion","android_version"])),imeiMasked:me(H(u,["device.imeiMasked","device.imei_masked","imeiMasked","imei_masked","binding.encryptedImei"])),fingerprint:me(H(u,["device.fingerprint","device.deviceFingerprint","device_fingerprint","fingerprint"])),serialNumber:me(H(u,["device.serialNumber","device.serial_number","serialNumber","serial_number","serial"])),batteryPercent:Mt(H(u,["device.batteryPercent","device.battery_percent","battery.percent","batteryPercent","battery"])),temperatureC:Mt(H(u,["device.temperatureC","device.temperature_c","temperature.celsius","temperatureC","temperature"])),storageFreeGB:Mt(H(u,["device.storageFreeGB","device.storage_free_gb","storage.freeGB","storageFreeGB","storage_free_gb"])),healthScore:Mt(H(u,["device.healthScore","device.health_score","health.score","healthScore","health_score"])),projectGroup:me(H(u,["device.projectGroup","device.project_group","projectGroup","project_group"])),tags:Array.isArray(H(u,["device.tags","tags"]))?H(u,["device.tags","tags"]).filter(d=>typeof d=="string"):void 0,networkType:me(H(u,["device.networkType","device.network_type","network.type","networkType","network_type"]))},agent:{running:Ke(H(u,["agent.running","agent.isRunning","agent_running","running"])),connected:Ke(H(u,["agent.connected","agent.online","agent_connected","wsConnected","ws_connected"])),uptimeSeconds:Mt(H(u,["agent.uptimeSeconds","agent.uptime_seconds","uptimeSeconds","uptime_seconds"])),host:me(H(u,["agent.host","agent.currentHost","agent.current_host","host"])),latencyMs:Mt(H(u,["agent.latencyMs","agent.latency_ms","latencyMs","latency_ms"])),autoDiscovery:Ke(H(u,["agent.autoDiscovery","agent.auto_discovery","automation.autoDiscovery"])),autoRoute:Ke(H(u,["agent.autoRoute","agent.auto_route","automation.autoRoute"])),autoReconnect:Ke(H(u,["agent.autoReconnect","agent.auto_reconnect","automation.autoReconnect"])),heartbeatKeepAlive:Ke(H(u,["agent.heartbeatKeepAlive","agent.heartbeat_keep_alive","automation.heartbeatKeepAlive"])),selfHealing:Ke(H(u,["agent.selfHealing","agent.self_healing","automation.selfHealing"])),bootStart:Ke(H(u,["agent.bootStart","agent.boot_start","automation.bootStart"]))},platform:{connected:Ke(H(u,["platform.connected","platform.online","platform_connected","server.connected"])),name:me(H(u,["platform.name","platform.platformName","platform_name","binding.platformName"])),serverUrl:me(H(u,["platform.serverUrl","platform.server_url","server.url","server_url"])),port:Mt(H(u,["platform.port","server.port","port"])),tlsEnabled:Ke(H(u,["platform.tlsEnabled","platform.tls_enabled","server.tls","tls_enabled"])),tokenMasked:me(H(u,["platform.tokenMasked","platform.token_masked","server.tokenMasked","token_masked"])),latencyMs:Mt(H(u,["platform.latencyMs","platform.latency_ms","server.latencyMs","server_latency_ms"]))},binding:{bound:Ke(H(u,["binding.bound","binding.isBound","bound","is_bound"])),platformName:me(H(u,["binding.platformName","binding.platform_name","platform.name"])),encryptedImei:me(H(u,["binding.encryptedImei","binding.encrypted_imei","device.imeiMasked","imei_masked"])),lastHeartbeat:me(H(u,["binding.lastHeartbeat","binding.last_heartbeat","lastHeartbeat","last_heartbeat"]))},wechat:{running:Ke(H(u,["wechat.running","wechat.isRunning","wechat_running"])),idMasked:me(H(u,["wechat.idMasked","wechat.id_masked","wechatIdMasked","wechat_id_masked","wechat.id"])),version:me(H(u,["wechat.version","wechat_version"])),friendCount:Mt(H(u,["wechat.friendCount","wechat.friend_count","friendCount","friend_count"]))},services:{sdkConnected:Ke(H(u,["services.sdkConnected","services.sdk_connected","sdk.connected","sdk_connected"])),fridaRunning:Ke(H(u,["services.fridaRunning","services.frida_running","frida.running","frida_running"])),hookAvailable:Ke(H(u,["services.hookAvailable","services.hook_available","hook.available","hook_available"]))},permissions:Wf(H(u,["permissions","device.permissions","runtime.permissions"])),version:me(H(u,["version","app.version","app_version"])),events:hc(H(u,["events","recentEvents","recent_events"])),agentLogs:hc(H(u,["agentLogs","agent_logs","logs"]))}},Qf=async()=>{const o=window.NativeAgent;if(!(o!=null&&o.getSnapshot))return{bridgeAvailable:!1,snapshot:ii,error:"NativeAgent.getSnapshot() 未接入"};try{const u=await Promise.resolve(o.getSnapshot()),d=kc(u);if(!Pn(d))throw new Error("快照格式不是 JSON 对象");return{bridgeAvailable:!0,snapshot:Gf(d)}}catch(u){return{bridgeAvailable:!0,snapshot:ii,error:u instanceof Error?u.message:"读取设备快照失败"}}},Kf=async o=>{const u=window.NativeAgent;if(!(u!=null&&u.performAction))return{success:!1,message:"NativeAgent.performAction(action) 未接入",code:"BRIDGE_UNAVAILABLE"};try{const d=await Promise.resolve(u.performAction(o)),y=kc(d);if(typeof y=="string")return{success:!0,message:y};if(!Pn(y))return{success:!0,message:"操作已提交",data:y};const _=Ke(H(y,["success","ok"])),x=H(y,["code","error_code"]),z=Mt(x),I=z!==void 0&&z>=400,F=me(H(y,["message","error_message","msg"]))??(_===!1?"操作执行失败":"操作已提交");return{success:_!==!1&&!I,message:F,data:y.data,code:typeof x=="string"||typeof x=="number"?x:void 0}}catch(d){return{success:!1,message:d instanceof Error?d.message:"原生操作执行失败",code:"ACTION_ERROR"}}},Yf=(o,u="")=>o===void 0||o===""?"—":`${o}${u}`;function Xf({value:o}){return i.jsx("span",{className:`status-dot ${o===!0?"is-online":o===!1?"is-offline":"is-unknown"}`})}function si({value:o,online:u="正常",offline:d="异常"}){return i.jsxs("span",{className:`status-text ${o===!0?"is-online":o===!1?"is-offline":"is-unknown"}`,children:[i.jsx(Xf,{value:o}),o===!0?u:o===!1?d:"不可用"]})}function Br({children:o}){return i.jsx("h2",{className:"section-title",children:o})}function Pe({children:o,className:u=""}){return i.jsx("section",{className:`card ${u}`,children:o})}function pn({title:o,detail:u}){return i.jsxs("div",{className:"empty-notice",children:[i.jsx(se,{name:"link",size:22}),i.jsxs("div",{children:[i.jsx("strong",{children:o}),i.jsx("span",{children:u})]})]})}function Zf({icon:o,children:u,secondary:d,...y}){return i.jsxs("button",{className:`action-button ${d?"is-secondary":""}`,...y,children:[i.jsx(se,{name:o,size:20}),i.jsx("span",{children:u})]})}const qf=[{icon:"agent",title:"任务智能",detail:"把任务拆清楚,再交给明确设备执行。",key:"tasks"},{icon:"wechat",title:"业务能力",detail:"按普通人看得懂的业务动作组织能力。",key:"skills"},{icon:"heartbeat",title:"稳定连接",detail:"先确认连接、心跳和探针,再谈执行。",key:"connection"},{icon:"shield",title:"运行治理",detail:"风险、审批、审计和回读都留下证据。",key:"governance"}];function Ot(o){return o==null||o===""?"未获取":String(o)}function Hr(o,u){return typeof o=="object"&&o!==null&&!Array.isArray(o)?o[u]:void 0}function Jf({icon:o,title:u,detail:d,sectionKey:y,api:_}){const x=_.engine.data,z=(x==null?void 0:x.brain)||{},I=z.skills||{},F=z.channels,X=(x==null?void 0:x.connection)||{},q=(x==null?void 0:x.integrationHealth)||{},Y=_.engine.sourceAt,R=Gr(Y),O=R?"数据已过期":y==="skills"?`${Ot(I.total_skills)} 个技能 / ${Ot(I.total_actions)} 个动作`:y==="connection"?`${Ot(X.online_ws_count)} 台 WSS 在线`:y==="governance"?q.ok===!0?"健康检查通过":q.ok===!1?"存在异常":"未获取":"暂无任务样本",te=y==="skills"?[`能做的事:${Ot(I.total_skills)}`,`可以调用的动作:${Ot(I.total_actions)}`,`连接方式:${F?Object.keys(F).length:"未获取"}`,"能力详情来自真实接口"]:y==="connection"?[`WSS 在线:${Ot(X.online_ws_count)}`,`连接设备:${Array.isArray(X.devices)?X.devices.length:"未获取"}`,`进程状态:${Ot(((x==null?void 0:x.process)||{}).state)}`,"不触发设备命令"]:y==="governance"?[`集成健康:${q.ok===!0?"正常":q.ok===!1?"异常":"未获取"}`,"权限与审计:读取对应 GET 结果","风险状态:总览接口聚合","业务回读:写任务页面单独验收"]:["任务状态:暂无样本","任务步骤:等待 AI 任务查询接口","目标设备:不自动选择","失败回执:写任务单独查看"];return i.jsxs(Pe,{className:"engine-section-card",children:[i.jsxs("div",{className:"engine-section-head",children:[i.jsx("span",{className:"engine-icon",children:i.jsx(se,{name:o,size:22})}),i.jsxs("div",{children:[i.jsx("h3",{children:u}),i.jsx("p",{children:d})]}),i.jsx("strong",{className:"engine-section-value",children:O})]}),i.jsx("ul",{children:te.map(J=>i.jsxs("li",{children:[i.jsx("span",{className:"status-dot is-unknown"}),J,i.jsx("b",{children:R?"数据已过期":_.engine.state==="ready"?"已读取":"未获取"})]},J))})]})}function bf({snapshot:o,api:u,busyAction:d,onAction:y}){var x,z,I,F,X,q,Y,R,O;const _=u.engine.sourceAt||u.readAt;return i.jsxs("main",{className:"console-page console-engine",children:[i.jsxs("header",{className:"console-page-header",children:[i.jsxs("div",{children:[i.jsx("div",{className:"eyebrow",children:"能力中心 / 任务与治理"}),i.jsx("h1",{children:"智能引擎"}),i.jsx("p",{children:"把“能做什么、谁来做、结果怎么确认”分成四块。"})]}),i.jsx(Zf,{icon:"refresh",secondary:!0,disabled:d==="refresh_snapshot",onClick:()=>y("refresh_snapshot"),children:"刷新数据"})]}),u.engine.state==="forbidden"&&i.jsx(pn,{title:"智能引擎数据无权限",detail:Tn(u.engine)}),u.engine.state==="unavailable"&&i.jsx(pn,{title:"智能引擎接口未接通",detail:`${Tn(u.engine)};不展示虚构的技能数、操作数或在线设备数。`}),i.jsxs(Pe,{className:"engine-hero",children:[i.jsxs("div",{children:[i.jsx("span",{className:"eyebrow",children:"执行前先确认"}),i.jsx("h2",{children:"先选任务,再选设备,最后看回执"}),i.jsx("p",{children:"单机和批量任务都必须有明确目标设备、权限、风险等级和业务回读。"})]}),i.jsxs("div",{className:"engine-connection",children:[i.jsx(si,{value:o.agent.connected,online:"WSS 在线",offline:"WSS 离线"}),i.jsx(si,{value:o.services.hookAvailable,online:"Hook 已挂载",offline:"Hook 未挂载"})]})]}),i.jsx(Br,{children:"四个能力分区"}),i.jsx("div",{className:"engine-grid",children:qf.map(te=>i.jsx(Jf,{icon:te.icon,title:te.title,detail:te.detail,sectionKey:te.key,api:u},te.title))}),i.jsx(Br,{children:"AI 操作记录"}),u.aiOperations.state!=="ready"&&i.jsx(pn,{title:"AI 操作记录暂未获取",detail:Tn(u.aiOperations)}),u.aiOperations.state==="ready"&&i.jsxs(Pe,{className:"engine-operation-card",children:[i.jsxs("div",{className:"engine-section-head",children:[i.jsxs("div",{children:[i.jsx("h3",{children:"任务、步骤与审计"}),i.jsx("p",{children:"这里只读取任务记录,不会向设备派发命令。"})]}),i.jsxs("strong",{children:[((x=u.aiOperations.data)==null?void 0:x.items.length)||0," 条"]})]}),!((z=u.aiOperations.data)!=null&&z.items.length)&&i.jsx("p",{className:"muted-text",children:"暂无任务样本"}),!!((I=u.aiOperations.data)!=null&&I.items.length)&&i.jsxs("ul",{children:[i.jsxs("li",{children:["任务:",Ot(Hr((F=u.aiOperations.data)==null?void 0:F.selected,"task_id"))]}),i.jsxs("li",{children:["状态:",Ot(Hr((X=u.aiOperations.data)==null?void 0:X.selected,"status"))]}),i.jsxs("li",{children:["目标设备:",Ot(Hr((q=u.aiOperations.data)==null?void 0:q.selected,"target_device_ids"))]}),i.jsxs("li",{children:["确认要求:",String(Hr(Hr((Y=u.aiOperations.data)==null?void 0:Y.selected,"precheck"),"confirm_required")??"未获取")]}),i.jsxs("li",{children:["步骤记录:",((R=u.aiOperations.data)==null?void 0:R.logs.length)||0," 条"]}),i.jsxs("li",{children:["审计记录:",((O=u.aiOperations.data)==null?void 0:O.audit.length)||0," 条"]})]}),i.jsx("div",{className:"integration-footnote",children:"来源:GET /api/v3/ai/tasks、/logs、/audit · confirm_required 只展示,不在本页确认"})]}),i.jsx(Br,{children:"当前连接摘要"}),i.jsxs("div",{className:"engine-facts",children:[i.jsxs(Pe,{children:[i.jsx("span",{children:"Agent"}),i.jsx("strong",{children:o.agent.running===!0?"运行中":o.agent.running===!1?"已停止":"未获取"})]}),i.jsxs(Pe,{children:[i.jsx("span",{children:"Hook 探针"}),i.jsx("strong",{children:o.services.hookAvailable===!0?"可用":o.services.hookAvailable===!1?"不可用":"未获取"})]}),i.jsxs(Pe,{children:[i.jsx("span",{children:"最近心跳"}),i.jsx("strong",{children:o.binding.lastHeartbeat||"未获取"})]}),i.jsxs(Pe,{children:[i.jsx("span",{children:"任务队列"}),i.jsx("strong",{children:u.engine.state==="ready"?"暂无样本":"未获取"})]})]}),i.jsxs("div",{className:"integration-footnote",children:["来源:GET /api/v3/ai/status、/api/v3/ai/brain/dashboard、/api/v3/connection/status、/api/v3/process/status · 读取于 ",_||"未获取"]})]})}const ep="https://wpsdk.quwanzhi.com/static/downloads/workphone-agent-latest.apk",tr=o=>typeof o=="object"&&o!==null&&!Array.isArray(o),It=o=>o===void 0||o===""?"未获取":String(o),Wr=(o,u="正常",d="异常")=>o===!0?u:o===!1?d:"未获取",wt=o=>o.status==="pending_authorization"||o.status==="pending_auth"?"待授权":o.online===!0||o.status==="online"?"在线":o.online===!1||o.status==="offline"?"离线":"未获取",oi=o=>wt(o)==="在线"?"is-online":wt(o)==="离线"?"is-offline":wt(o)==="待授权"?"is-pending":"is-unknown",tp=o=>o.sourceKind==="history"?"历史 Agent 记录":o.sourceKind==="fixture"?"安全测试夹具":"实时接口",np="ws://192.168.110.101:8899/ws/device",rp=()=>{const o=window.location.hostname;return/^(?:10\.|192\.168\.|172\.(?:1[6-9]|2\d|3[01])\.)/.test(o)?`${window.location.protocol==="https:"?"wss:":"ws:"}//${window.location.host}/ws/device`:np},lp=()=>{var o,u;return((u=(o=window.crypto)==null?void 0:o.randomUUID)==null?void 0:u.call(o))||`console-${Date.now()}-${Math.random().toString(16).slice(2)}`};function ip({device:o,sourceAt:u,onOpen:d}){const y=wt(o),_=Gr(o.sourceAt||u);return i.jsxs("button",{className:"device-summary-card",type:"button",onClick:d,children:[i.jsxs("span",{className:`device-summary-icon ${oi(o)}`,children:[i.jsx(se,{name:"device",size:28}),i.jsx("i",{})]}),i.jsxs("span",{className:"device-summary-main",children:[i.jsxs("span",{className:"device-summary-title",children:[i.jsx("strong",{children:o.name||o.model||"未命名手机"}),i.jsx("b",{className:oi(o),children:y})]}),i.jsxs("span",{className:"device-summary-sub",children:[It(o.model)," · Android ",It(o.androidVersion)]}),i.jsx("span",{className:"device-summary-id",children:o.deviceId}),i.jsxs("span",{className:"device-summary-facts",children:[i.jsxs("em",{children:[i.jsx(se,{name:"wechat",size:15}),o.wechatId||(o.wechatRunning?"微信运行中":"未绑定微信")]}),i.jsxs("em",{children:[i.jsx(se,{name:"agent",size:15}),"Agent ",Wr(o.agentRunning)]}),i.jsxs("em",{children:[i.jsx(se,{name:"link",size:15}),"Hook ",Wr(o.hookAvailable,"已挂载","未挂载")]})]})]}),i.jsxs("span",{className:"device-summary-side",children:[i.jsx("span",{children:o.groupId||o.projectId||"未分组"}),i.jsx("small",{className:_?"is-expired":"",children:_?"数据已过期":o.sourceAt||u||"未获取采样时间"}),i.jsxs("b",{children:["查看管理 ",i.jsx(se,{name:"chevron",size:16})]})]})]})}function He({label:o,value:u}){return i.jsxs("div",{className:"device-detail-item",children:[i.jsx("span",{children:o}),i.jsx("strong",{children:u})]})}function sp({api:o,loading:u,onRefresh:d}){var h,j;const[y,_]=ne.useState(""),[x,z]=ne.useState("all"),[I,F]=ne.useState("all"),[X,q]=ne.useState(),[Y,R]=ne.useState(!1),[O,te]=ne.useState(!1),[J,b]=ne.useState(!1),[Le,ze]=ne.useState(),[Ie,fe]=ne.useState("cunkebao"),[ge,he]=ne.useState("工作手机"),[pe,we]=ne.useState(rp),[Oe,je]=ne.useState(""),[Fe,_e]=ne.useState(""),w=o.devices.data||[],Be=o.groups.data||[],G=w.find(E=>E.deviceId===X),Ee=ne.useMemo(()=>w.filter(E=>{const C=`${E.name||""} ${E.model||""} ${E.deviceId} ${E.wechatId||""}`.toLowerCase(),A=wt(E),ee=x==="all"||x==="online"&&A==="在线"||x==="offline"&&A==="离线"||x==="pending"&&A==="待授权";return C.includes(y.trim().toLowerCase())&&ee&&(I==="all"||E.groupId===I||E.projectId===I)}),[w,I,y,x]),ie=o.devices.sourceAt||o.readAt,P={online:w.filter(E=>wt(E)==="在线").length,pending:w.filter(E=>wt(E)==="待授权").length,offline:w.filter(E=>wt(E)==="离线").length},B=async()=>{b(!0),_e(""),je("");try{const E=await fetch("/api/v3/qrcode/generate",{method:"POST",credentials:"same-origin",headers:{"Content-Type":"application/json"},body:JSON.stringify({project_id:Ie.trim()||"cunkebao",project_name:ge.trim()||"工作手机",server:pe.trim()})}),C=await E.json().catch(()=>({}));if(!E.ok){const re=tr(C)?C.message||C.detail||C.error:void 0;throw new Error(typeof re=="string"?re:`二维码生成失败(${E.status})`)}const A=tr(C)&&tr(C.data)?C.data:C;if(!tr(A))throw new Error("二维码响应格式错误");const ee=typeof A.image_data_url=="string"?A.image_data_url:typeof A.image_base64=="string"?`data:image/png;base64,${A.image_base64}`:"";if(!ee)throw new Error(typeof A.message=="string"?A.message:"服务未返回二维码图片");je(ee)}catch(E){_e(E instanceof Error?E.message:"二维码生成失败")}finally{b(!1)}},L=async()=>{if(!(!G||wt(G)!=="离线")){b(!0),ze(void 0);try{const E=await fetch(`/api/v3/devices/${encodeURIComponent(G.deviceId)}?confirm=true`,{method:"DELETE",credentials:"same-origin",headers:{"Idempotency-Key":lp(),"X-Actor-Id":"console-admin","X-Authenticated":"true","X-Permissions":"device.delete"}}),C=await E.json().catch(()=>({}));if(!E.ok||tr(C)&&C.success===!1){const A=tr(C)?C.message||C.error_message||C.detail:void 0;throw new Error(typeof A=="string"?A:`删除失败(${E.status})`)}te(!1),q(void 0),ze({success:!0,message:"手机设备已删除,历史任务和审计记录继续保留。"}),await d()}catch(E){ze({success:!1,message:E instanceof Error?E.message:"删除设备失败"})}finally{b(!1)}}};return i.jsxs("main",{className:"console-page console-devices",children:[i.jsxs("header",{className:"console-page-header device-page-heading",children:[i.jsxs("div",{children:[i.jsx("div",{className:"eyebrow",children:"手机管理"}),i.jsx("h1",{children:"手机设备"}),i.jsx("p",{children:"外层只看手机状态;点击一台手机,再查看参数、运行记录和删除操作。"})]}),i.jsxs("button",{className:"primary-action device-add-button",type:"button",onClick:()=>R(!0),children:[i.jsx(se,{name:"qr",size:18}),"添加手机"]})]}),Le&&i.jsx("div",{className:`device-page-notice ${Le.success?"is-success":"is-error"}`,children:Le.message}),o.devices.state==="forbidden"&&i.jsx(pn,{title:"手机列表无权限",detail:Tn(o.devices)}),o.devices.state==="unavailable"&&i.jsx(pn,{title:"手机设备列表还没有真实数据",detail:`${Tn(o.devices)};不展示演示设备卡片。`}),i.jsxs(Pe,{className:"device-management-bar",children:[i.jsxs("div",{className:"device-counts",children:[i.jsxs("button",{className:x==="all"?"is-active":"",onClick:()=>z("all"),children:["全部 ",i.jsx("b",{children:w.length})]}),i.jsxs("button",{className:x==="online"?"is-active":"",onClick:()=>z("online"),children:[i.jsx("i",{className:"online"}),"在线 ",i.jsx("b",{children:P.online})]}),i.jsxs("button",{className:x==="pending"?"is-active":"",onClick:()=>z("pending"),children:[i.jsx("i",{className:"pending"}),"待授权 ",i.jsx("b",{children:P.pending})]}),i.jsxs("button",{className:x==="offline"?"is-active":"",onClick:()=>z("offline"),children:[i.jsx("i",{className:"offline"}),"离线 ",i.jsx("b",{children:P.offline})]})]}),i.jsxs("div",{className:"device-filter-compact",children:[i.jsxs("label",{children:[i.jsx(se,{name:"search",size:17}),i.jsx("input",{value:y,onChange:E=>_(E.target.value),placeholder:"搜索手机、设备 ID 或微信号"})]}),i.jsxs("select",{value:I,onChange:E=>F(E.target.value),children:[i.jsx("option",{value:"all",children:"全部分组"}),Be.map(E=>i.jsx("option",{value:E.groupId,children:E.name},E.groupId))]}),i.jsxs("button",{type:"button",onClick:()=>void d(),disabled:u,children:[i.jsx(se,{name:"refresh",size:17}),"刷新"]})]})]}),i.jsxs("div",{className:"device-list-heading",children:[i.jsxs("div",{children:[i.jsx("span",{className:"eyebrow",children:"手机列表"}),i.jsx("h2",{children:o.devices.state==="ready"?`${Ee.length} 台手机`:"暂无手机"})]}),i.jsxs("span",{className:"data-source-note",children:[o.devices.source," · ",ie||"未获取采样时间"]})]}),Ee.length?i.jsx("div",{className:"device-summary-list",children:Ee.map(E=>i.jsx(ip,{device:E,sourceAt:ie,onOpen:()=>q(E.deviceId)},E.deviceId))}):i.jsxs(Pe,{className:"device-empty-card",children:[i.jsx(se,{name:"device",size:28}),i.jsx("strong",{children:o.devices.state==="ready"?"没有匹配的手机":"暂无手机"}),i.jsx("span",{children:o.devices.state==="ready"?"更换状态、分组或搜索词试试。":"点击“添加手机”,完成下载、安装和扫码绑定。"})]}),G&&i.jsx("div",{className:"device-overlay",role:"dialog","aria-modal":"true","aria-label":"手机管理详情",onMouseDown:E=>{E.target===E.currentTarget&&q(void 0)},children:i.jsxs("aside",{className:"device-detail-drawer",children:[i.jsxs("header",{children:[i.jsx("button",{type:"button",className:"drawer-close",onClick:()=>q(void 0),children:"×"}),i.jsxs("span",{className:`device-summary-icon ${oi(G)}`,children:[i.jsx(se,{name:"device",size:28}),i.jsx("i",{})]}),i.jsxs("div",{children:[i.jsx("span",{className:"eyebrow",children:"手机管理"}),i.jsx("h2",{children:G.name||G.model||"未命名手机"}),i.jsx("p",{children:G.deviceId})]}),i.jsx("b",{className:oi(G),children:wt(G)})]}),i.jsxs("section",{children:[i.jsx("h3",{children:"运行状态"}),i.jsxs("div",{className:"device-detail-grid",children:[i.jsx(He,{label:"WSS",value:wt(G)}),i.jsx(He,{label:"Agent",value:Wr(G.agentRunning)}),i.jsx(He,{label:"Hook",value:Wr(G.hookAvailable,"已挂载","未挂载")}),i.jsx(He,{label:"最后心跳",value:G.lastHeartbeat||"未获取"})]})]}),i.jsxs("section",{children:[i.jsx("h3",{children:"微信"}),i.jsxs("div",{className:"device-detail-grid",children:[i.jsx(He,{label:"运行状态",value:Wr(G.wechatRunning,"运行中","未运行")}),i.jsx(He,{label:"微信号",value:G.wechatId||"未绑定微信号"}),i.jsx(He,{label:"好友数",value:It(G.friendCount)}),i.jsx(He,{label:"微信版本",value:It(G.wechatVersion)})]})]}),i.jsxs("section",{children:[i.jsx("h3",{children:"手机信息"}),i.jsxs("div",{className:"device-detail-grid",children:[i.jsx(He,{label:"型号",value:It(G.model)}),i.jsx(He,{label:"Android",value:It(G.androidVersion)}),i.jsx(He,{label:"项目 / 分组",value:It(G.groupId||G.projectId)}),i.jsx(He,{label:"网络",value:It(G.networkType)}),i.jsx(He,{label:"电量",value:G.batteryPercent===void 0?"未获取":`${G.batteryPercent}%`}),i.jsx(He,{label:"健康度",value:It(G.healthScore)})]})]}),i.jsxs("details",{className:"device-advanced",children:[i.jsx("summary",{children:"查看技术参数"}),i.jsxs("div",{children:[i.jsx(He,{label:"数据类型",value:tp(G)}),i.jsx(He,{label:"Agent 版本",value:It(G.agentVersion)}),i.jsx(He,{label:"状态来源",value:G.statusSource||o.devices.source}),i.jsx(He,{label:"采样时间",value:G.sourceAt||ie||"未获取"}),i.jsx(He,{label:"能力",value:(h=G.capabilities)!=null&&h.length?G.capabilities.join("、"):"未获取"})]})]}),i.jsxs("footer",{children:[i.jsxs("button",{className:"quiet-button",type:"button",onClick:()=>void d(),disabled:u,children:[i.jsx(se,{name:"refresh",size:17}),"刷新状态"]}),wt(G)==="离线"?i.jsxs("button",{className:"danger-button",type:"button",onClick:()=>te(!0),children:[i.jsx(se,{name:"power",size:17}),"删除手机"]}):i.jsx("span",{children:"在线手机需先下线,才能删除。"})]})]})}),Y&&i.jsx("div",{className:"device-overlay",role:"dialog","aria-modal":"true","aria-label":"添加手机",onMouseDown:E=>{E.target===E.currentTarget&&R(!1)},children:i.jsxs("section",{className:"device-add-modal",children:[i.jsxs("header",{children:[i.jsxs("div",{children:[i.jsx("span",{className:"eyebrow",children:"添加手机"}),i.jsx("h2",{children:"下载、安装并扫码绑定"}),i.jsx("p",{children:"二维码直接由后台生成,不依赖浏览器 NativeAgent。"})]}),i.jsx("button",{type:"button",className:"drawer-close",onClick:()=>R(!1),children:"×"})]}),i.jsxs("div",{className:"device-add-steps",children:[i.jsxs("div",{children:[i.jsx("span",{children:"1"}),i.jsx("strong",{children:"下载 APK"}),i.jsx("a",{href:((j=o.release.data)==null?void 0:j.download_url)||ep,children:"下载当前安装包"})]}),i.jsxs("div",{children:[i.jsx("span",{children:"2"}),i.jsx("strong",{children:"手机安装"}),i.jsx("small",{children:"打开工作手机 Agent"})]}),i.jsxs("div",{children:[i.jsx("span",{children:"3"}),i.jsx("strong",{children:"扫码绑定"}),i.jsx("small",{children:"用 Agent 扫描右侧二维码"})]})]}),i.jsxs("div",{className:"device-bind-layout",children:[i.jsxs("div",{className:"device-bind-form",children:[i.jsxs("label",{children:["项目",i.jsx("input",{value:Ie,onChange:E=>fe(E.target.value)})]}),i.jsxs("label",{children:["手机名称",i.jsx("input",{value:ge,onChange:E=>he(E.target.value)})]}),i.jsxs("label",{children:["服务器地址",i.jsx("input",{value:pe,onChange:E=>we(E.target.value)})]}),i.jsxs("button",{className:"primary-action",type:"button",disabled:J||!pe.trim(),onClick:()=>void B(),children:[i.jsx(se,{name:"qr",size:18}),J?"生成中…":Oe?"重新生成二维码":"生成绑定二维码"]})]}),i.jsx("div",{className:"device-qr-area",children:Oe?i.jsxs(i.Fragment,{children:[i.jsx("img",{src:Oe,alt:"手机绑定二维码"}),i.jsx("strong",{children:ge||"工作手机"}),i.jsx("small",{children:pe})]}):Fe?i.jsxs(i.Fragment,{children:[i.jsx(se,{name:"link",size:28}),i.jsx("strong",{children:"生成失败"}),i.jsx("small",{className:"is-error",children:Fe})]}):i.jsxs(i.Fragment,{children:[i.jsx(se,{name:"qr",size:42}),i.jsx("strong",{children:"等待生成二维码"}),i.jsx("small",{children:"填写服务器地址后点击生成"})]})})]}),i.jsxs("footer",{children:[i.jsx("span",{children:"绑定成功后,手机会自动出现在列表中。"}),i.jsx("button",{className:"quiet-button",type:"button",onClick:()=>{R(!1),d()},children:"完成并刷新"})]})]})}),O&&G&&i.jsx("div",{className:"device-overlay device-confirm-layer",role:"alertdialog","aria-modal":"true",children:i.jsxs("section",{className:"device-confirm-modal",children:[i.jsx("span",{className:"danger-symbol",children:i.jsx(se,{name:"power",size:25})}),i.jsx("h2",{children:"确认删除这台手机?"}),i.jsxs("p",{children:[i.jsx("strong",{children:G.name||G.model||G.deviceId}),i.jsx("br",{}),"设备登记将删除,历史任务和审计记录继续保留。"]}),i.jsxs("div",{children:[i.jsx("button",{className:"quiet-button",type:"button",onClick:()=>te(!1),children:"取消"}),i.jsx("button",{className:"danger-button",type:"button",disabled:J,onClick:()=>void L(),children:J?"删除中…":"确认删除"})]})]})})]})}const mc=(o,u,d)=>o.state==="forbidden"?"无权限":o.state!=="ready"?"未获取":o.data&&(Array.isArray(o.data)?o.data.length:Object.keys(o.data).length)?u:d,vc=o=>`来源:${o.source} · 读取于 ${o.sourceAt||"未获取"}`,op=[{icon:"users",title:"第三方应用",detail:"应用、负责人、用途、环境、凭证和到期时间",key:"applications"},{icon:"lock",title:"接口授权",detail:"Scope、设备范围、文档范围、期限、额度和 IP 白名单",key:"authorizations"},{icon:"heartbeat",title:"用量统计",detail:"接口、设备、文档、成功率、失败原因和额度消耗",key:"usage"},{icon:"code",title:"接口目录",detail:"动作、参数、权限、错误码、请求与响应示例",key:"manifest"},{icon:"download",title:"SDK / APK",detail:"版本、校验、下载、升级和回滚入口",key:"documents"},{icon:"book",title:"知识库与项目文档",detail:"手册、架构、部署、排错、需求、进度和验收证据",key:"knowledge"}];function ap({api:o,loading:u}){var q,Y;const d=o.integrations,y=(q=d.applications.data)==null?void 0:q.length,_=(Y=d.authorizations.data)==null?void 0:Y.length,x=d.usage.data,z=d.manifest.data,I=(z==null?void 0:z.total_endpoints)??(z==null?void 0:z.endpoint_count)??(z==null?void 0:z.module_count),F=x==null?void 0:x.blocked,X=[d.applications,d.authorizations,d.usage].filter(R=>R.state==="forbidden");return i.jsxs("main",{className:"console-page console-integrations",children:[i.jsxs("header",{className:"console-page-header",children:[i.jsxs("div",{children:[i.jsx("div",{className:"eyebrow",children:"接入管理 / 权限与用量"}),i.jsx("h1",{children:"统一接入中心"}),i.jsx("p",{children:"第三方从这里登记、授权、查看用量、下载 SDK 和查文档。"})]}),i.jsx("span",{className:"badge badge-blue",children:"默认 deny_all"})]}),X.length>0&&i.jsx(pn,{title:"部分授权或用量数据无权限",detail:X.map(R=>`${R.source}:${Tn(R)}`).join(";")}),u&&i.jsx("div",{className:"integration-footnote",children:"正在读取接入中心 GET 数据…"}),i.jsxs(Pe,{className:"integration-banner",children:[i.jsx("div",{className:"integration-banner-icon",children:i.jsx(se,{name:"link",size:28})}),i.jsxs("div",{children:[i.jsx("h2",{children:"一套接口目录,一套授权口径"}),i.jsx("p",{children:"新第三方默认没有设备和写接口权限;设备范围为空就是没有设备,不解释成全部设备。"})]}),i.jsxs("div",{className:"integration-status",children:[i.jsx("span",{className:"status-dot is-unknown"}),"授权服务 ",i.jsx("strong",{children:mc(d.authorizations,`${_} 条授权`,"暂无样本")})]})]}),i.jsx(Br,{children:"接入中心分区"}),i.jsx("div",{className:"integration-grid",children:op.map(R=>{var J,b;const O=d[R.key],te=R.key==="applications"?`${y} 个应用`:R.key==="authorizations"?`${_} 条授权`:R.key==="usage"?`${(x==null?void 0:x.total_requests)??0} 次请求`:R.key==="manifest"?`${I??0} 个条目`:R.key==="documents"?`${((J=d.documents.data)==null?void 0:J.length)??0} 份文档`:`${((b=d.knowledge.data)==null?void 0:b.length)??0} 条结果`;return i.jsxs(Pe,{className:"integration-card",children:[i.jsx("span",{className:"integration-icon",children:i.jsx(se,{name:R.icon,size:22})}),i.jsxs("div",{children:[i.jsx("h3",{children:R.title}),i.jsx("p",{children:R.detail}),i.jsx("small",{children:vc(O)})]}),i.jsxs("span",{className:`integration-state ${O.state==="forbidden"?"is-forbidden":""}`,children:[mc(O,te,"暂无样本"),i.jsx(se,{name:"chevron",size:16})]})]},R.title)})}),i.jsx(Br,{children:"用量只读摘要"}),i.jsxs("div",{className:"permission-template-grid",children:[i.jsxs(Pe,{children:[i.jsx("strong",{children:"调用总数"}),i.jsx("span",{children:d.usage.state==="forbidden"?Tn(d.usage):(x==null?void 0:x.total_requests)??"未获取"})]}),i.jsxs(Pe,{children:[i.jsx("strong",{children:"成功 / 业务失败"}),i.jsx("span",{children:d.usage.state==="ready"?`${(x==null?void 0:x.success)??0} / ${(x==null?void 0:x.business_failure)??(x==null?void 0:x.failed)??0}`:d.usage.state==="forbidden"?"无权限":"未获取"})]}),i.jsxs(Pe,{children:[i.jsx("strong",{children:"鉴权拦截"}),i.jsx("span",{children:d.usage.state==="ready"?F??0:d.usage.state==="forbidden"?"无权限":"未获取"})]}),i.jsxs(Pe,{children:[i.jsx("strong",{children:"去重设备数"}),i.jsx("span",{children:d.usage.state==="ready"?(x==null?void 0:x.unique_devices)??0:d.usage.state==="forbidden"?"无权限":"未获取"})]})]}),i.jsxs(Pe,{className:"integration-note",children:[i.jsx(se,{name:"shield",size:20}),i.jsxs("div",{children:[i.jsx("strong",{children:"安全边界"}),i.jsx("span",{children:"在线测试必须标明测试环境;密钥、服务器配置、内部验收证据和完整微信号不会通过文档接口暴露。"})]})]}),i.jsxs("div",{className:"integration-footnote",children:[vc(d.usage),Gr(d.usage.sourceAt)?" · 数据已过期":""]})]})}const Sc=(o,u)=>u?"数据已过期":o===void 0||o===""?"未获取":String(o),up=o=>(o==null?void 0:o.display)||((o==null?void 0:o.value)===void 0||(o==null?void 0:o.value)===null?void 0:String(o.value)),cp=(o,u)=>(o==null?void 0:o.sampled_at)||u,dp=o=>{var d;if(!o)return;const u=[o,o.raw_rpc_receipt,(d=o.raw_rpc_receipt)==null?void 0:d.raw_rpc_receipt];for(const y of u){if(!y||typeof y!="object")continue;const _=y;if(typeof _.attached=="boolean")return _.attached;if(typeof _.supports_hook=="boolean")return _.supports_hook}if(o.success===!0&&o.verified===!0)return!0;if(o.success===!1||o.error_code||o.error)return!1};function Cn({icon:o,label:u,metric:d,fallbackAt:y}){const _=Hf(d),x=cp(_,y),z=Gr(x),I=Sc(up(_),z),F=z?"数据已过期":_.source?`来源:${_.source}`:x?`采样于 ${x}`:"暂无样本";return i.jsxs(Pe,{className:"console-metric-card",children:[i.jsx("span",{className:"console-metric-icon",children:i.jsx(se,{name:o,size:20})}),i.jsx("span",{className:"console-metric-label",children:u}),i.jsx("strong",{children:I}),i.jsx("small",{children:F})]})}function ri({label:o,value:u}){return i.jsxs("div",{className:"service-status-row",children:[i.jsx(si,{value:u,online:"正常",offline:"异常"}),i.jsx("span",{children:o})]})}function fp({snapshot:o,api:u,loading:d}){var ge,he,pe,we,Oe,je,Fe,_e,w,Be,G,Ee,ie,P;const y=u.overview.data,_=(y==null?void 0:y.sampled_at)||u.overview.sourceAt,x=Gr(_),z=(he=(ge=y==null?void 0:y.wechat)==null?void 0:ge.devices)==null?void 0:he[0],I=((pe=u.devices.data)==null?void 0:pe.find(B=>B.online===!0))||((we=u.devices.data)==null?void 0:we[0]),F=(Oe=u.engine.data)==null?void 0:Oe.connection,X=typeof(F==null?void 0:F.online_ws_count)=="number"?F.online_ws_count:void 0,q=X!==void 0?X>0:I==null?void 0:I.online,Y=I==null?void 0:I.agentRunning,R=dp(u.hookStatus.data)??(I==null?void 0:I.hookAvailable),O=!!(o.device.id||o.device.name||I!=null&&I.deviceId||z!=null&&z.device_id),te=B=>Sc(B,x),J=o.device.id||(I==null?void 0:I.deviceId)||(z==null?void 0:z.device_id),b=o.device.name||(I==null?void 0:I.name)||J||"当前设备",Le=(z==null?void 0:z.logged_in)??o.wechat.running,ze=(z==null?void 0:z.wechat_version)||o.wechat.version,Ie=(z==null?void 0:z.friend_count)??o.wechat.friendCount,fe=(z==null?void 0:z.sampled_at)||_;return i.jsxs("main",{className:"console-page console-overview",children:[i.jsxs("header",{className:"console-page-header",children:[i.jsxs("div",{children:[i.jsx("div",{className:"eyebrow",children:"统一工作台 / 只读"}),i.jsx("h1",{children:"数据总览"}),i.jsx("p",{children:"只看真实数据,不在这里扫码、下载或控制设备。"})]}),i.jsxs("div",{className:"page-badges",children:[i.jsx("span",{className:"badge badge-blue",children:"只读页面"}),i.jsx("span",{className:"badge",children:x?"数据已过期":_?`采样于 ${_}`:d?"正在读取":"等待数据"})]})]}),u.overview.state==="unavailable"&&i.jsx(pn,{title:"总览接口未获取到数据",detail:u.overview.error||"不展示演示数量,等待 GET /api/v3/workbench/overview 返回真实数据。"}),x&&i.jsx(pn,{title:"总览数据已过期",detail:"保留接口最后采样时间,等下一次成功读取后更新。"}),i.jsxs("section",{className:"console-metric-grid","aria-label":"真实指标",children:[i.jsx(Cn,{icon:"device",label:"设备总数",metric:(je=y==null?void 0:y.devices)==null?void 0:je.total,fallbackAt:_}),i.jsx(Cn,{icon:"wifi",label:"WSS 在线",metric:(Fe=y==null?void 0:y.devices)==null?void 0:Fe.online,fallbackAt:_}),i.jsx(Cn,{icon:"heartbeat",label:"24h 任务成功率",metric:(_e=y==null?void 0:y.tasks)==null?void 0:_e.success_rate_24h,fallbackAt:_}),i.jsx(Cn,{icon:"shield",label:"待处理风险",metric:(w=y==null?void 0:y.risk_events)==null?void 0:w.unhandled,fallbackAt:_}),i.jsx(Cn,{icon:"wechat",label:"微信已登录",metric:(Be=y==null?void 0:y.wechat)==null?void 0:Be.logged_in_devices,fallbackAt:_}),i.jsx(Cn,{icon:"users",label:"微信好友数",metric:(G=y==null?void 0:y.wechat)==null?void 0:G.friend_count,fallbackAt:_}),i.jsx(Cn,{icon:"link",label:"第三方调用量",metric:(Ee=y==null?void 0:y.third_party)==null?void 0:Ee.calls,fallbackAt:_})]}),i.jsxs("section",{className:"console-two-column",children:[i.jsxs(Pe,{className:"console-panel trend-panel",children:[i.jsxs("div",{className:"panel-heading",children:[i.jsxs("div",{children:[i.jsx("span",{className:"eyebrow",children:"只读采样"}),i.jsx("h2",{children:"近 24 小时在线设备趋势"})]}),i.jsx("span",{className:"panel-note",children:"暂无样本"})]}),i.jsxs("div",{className:"trend-empty",children:[i.jsx(se,{name:"chart",size:30}),i.jsx("strong",{children:"暂无样本"}),i.jsx("span",{children:u.overview.state==="ready"?"接口已接通,但当前响应未提供趋势样本。":"接入总控概览接口后显示趋势,不用静态柱状图冒充数据。"})]})]}),i.jsxs(Pe,{className:"console-panel",children:[i.jsx("div",{className:"panel-heading",children:i.jsxs("div",{children:[i.jsx("span",{className:"eyebrow",children:"运行状态"}),i.jsx("h2",{children:"核心服务健康"})]})}),i.jsxs("div",{className:"service-status-grid",children:[i.jsx(ri,{label:"API 网关",value:(P=(ie=u.engine.data)==null?void 0:ie.integrationHealth)==null?void 0:P.ok}),i.jsx(ri,{label:"WSS Hub",value:q??o.agent.connected}),i.jsx(ri,{label:"Agent",value:Y??o.agent.running}),i.jsx(ri,{label:"Hook 探针",value:R??o.services.hookAvailable})]}),i.jsxs("div",{className:"panel-callout",children:[i.jsx(se,{name:"link",size:17}),i.jsx("span",{children:"设备下载、扫码绑定和单机控制都集中在“手机设备”页面。"})]})]})]}),i.jsxs(Pe,{className:"console-panel overview-table-panel",children:[i.jsxs("div",{className:"panel-heading",children:[i.jsxs("div",{children:[i.jsx("span",{className:"eyebrow",children:"设备与微信运行摘要"}),i.jsx("h2",{children:"最近一次真实采样"})]}),i.jsx("span",{className:"panel-note",children:"不触发命令"})]}),O?i.jsx("div",{className:"overview-table-wrap",children:i.jsxs("table",{className:"overview-table",children:[i.jsx("thead",{children:i.jsxs("tr",{children:[i.jsx("th",{children:"设备"}),i.jsx("th",{children:"WSS"}),i.jsx("th",{children:"Agent / Hook"}),i.jsx("th",{children:"微信运行"}),i.jsx("th",{children:"微信号"}),i.jsx("th",{children:"好友数"}),i.jsx("th",{children:"微信版本"}),i.jsx("th",{children:"采样时间"})]})}),i.jsx("tbody",{children:i.jsxs("tr",{children:[i.jsxs("td",{children:[i.jsx("strong",{children:b}),i.jsx("small",{children:te(J)})]}),i.jsx("td",{children:i.jsx(si,{value:q??o.agent.connected,online:"在线",offline:"离线"})}),i.jsx("td",{children:Y===void 0&&R===void 0&&o.agent.running===void 0&&o.services.hookAvailable===void 0?"未获取":`${Y===!0||Y===void 0&&o.agent.running===!0?"正常":Y===!1||o.agent.running===!1?"异常":"未获取"} / ${R===!0||R===void 0&&o.services.hookAvailable===!0?"已挂载":R===!1||o.services.hookAvailable===!1?"未挂载":"未获取"}`}),i.jsx("td",{children:Le===!0?"已登录":Le===!1?"未登录":"未获取"}),i.jsx("td",{children:te(o.wechat.idMasked)==="未获取"?"已脱敏":te(o.wechat.idMasked)}),i.jsx("td",{children:te(Ie)}),i.jsx("td",{children:te(ze)}),i.jsx("td",{children:Yf(fe)})]})})]})}):i.jsxs("div",{className:"table-empty",children:[i.jsx(se,{name:"device",size:24}),i.jsx("strong",{children:"暂无样本"}),i.jsx("span",{children:"还没有可展示的设备快照,数据接入后这里会出现真实设备。"})]})]})]})}function pp(){const[o,u]=ne.useState(),[d,y]=ne.useState(""),[_,x]=ne.useState(""),[z,I]=ne.useState(!1),[F,X]=ne.useState({id:"",name:"",description:"",runtime_binding:"",config:"{}"}),q=ne.useCallback(async()=>{try{u(await Mf()),x("")}catch(O){x(O instanceof Error?O.message:"安全模块读取失败")}},[]);ne.useEffect(()=>{q()},[q]);const Y=async(O,te)=>{y(O),x("");try{await te(),await q()}catch(J){x(J instanceof Error?J.message:"操作失败")}finally{y("")}},R=async O=>{O.preventDefault(),await Y("add",async()=>{await Of({...F,config:JSON.parse(F.config)}),X({id:"",name:"",description:"",runtime_binding:"",config:"{}"}),I(!1)})};return i.jsxs("main",{className:"console-page security-page",children:[i.jsxs("header",{className:"console-page-header",children:[i.jsxs("div",{children:[i.jsx("div",{className:"eyebrow",children:"SDK治理 / 可插拔安全"}),i.jsx("h1",{children:"安全模块"}),i.jsx("p",{children:"一个总开关控制全局,每项能力可以独立启停,自定义模块可以随时接入或移除。"})]}),i.jsx("span",{className:`badge ${o!=null&&o.global_enabled?"badge-blue":""}`,children:o!=null&&o.global_enabled?"全局已开启":"全局已关闭"})]}),_&&i.jsx("div",{className:"security-error",children:_}),o?i.jsxs(i.Fragment,{children:[i.jsxs(Pe,{className:`security-master ${o.global_enabled?"is-on":"is-off"}`,children:[i.jsx("span",{className:"security-master-icon",children:i.jsx(se,{name:"shield",size:29})}),i.jsxs("div",{children:[i.jsx("h2",{children:"SDK 安全总开关"}),i.jsx("p",{children:"关闭后,所有可选安全能力停止生效;本控制页登录保护仍保留,便于重新开启。"}),i.jsxs("small",{children:[o.enabled_count," / ",o.module_count," 项正在生效"]})]}),i.jsxs("button",{className:`switch-button ${o.global_enabled?"is-on":""}`,disabled:d==="global",onClick:()=>void Y("global",()=>Rf(!o.global_enabled)),children:[i.jsx("span",{}),o.global_enabled?"关闭全部":"开启全部"]})]}),i.jsxs("div",{className:"security-toolbar",children:[i.jsxs("strong",{children:["模块清单(",o.module_count,")"]}),i.jsxs("button",{onClick:()=>I(!z),children:[i.jsx(se,{name:"grid",size:16}),"添加模块"]})]}),z&&i.jsx(Pe,{className:"security-add-card",children:i.jsxs("form",{onSubmit:R,children:[i.jsx("input",{required:!0,placeholder:"模块ID,如 custom_guard",value:F.id,onChange:O=>X({...F,id:O.target.value})}),i.jsx("input",{required:!0,placeholder:"模块名称",value:F.name,onChange:O=>X({...F,name:O.target.value})}),i.jsx("input",{placeholder:"运行绑定,如 plugins.custom_guard",value:F.runtime_binding,onChange:O=>X({...F,runtime_binding:O.target.value})}),i.jsx("input",{placeholder:"功能说明",value:F.description,onChange:O=>X({...F,description:O.target.value})}),i.jsx("textarea",{"aria-label":"模块JSON配置",value:F.config,onChange:O=>X({...F,config:O.target.value})}),i.jsx("button",{type:"submit",disabled:d==="add",children:d==="add"?"保存中…":"保存并接入"})]})}),i.jsx("div",{className:"security-grid",children:o.modules.map(O=>i.jsxs(Pe,{className:`security-card ${O.effective_enabled?"is-on":""}`,children:[i.jsxs("div",{className:"security-card-head",children:[i.jsx("span",{children:i.jsx(se,{name:O.effective_enabled?"shield":"lock",size:20})}),i.jsxs("div",{children:[i.jsx("h3",{children:O.name}),i.jsxs("small",{children:[O.id," · ",O.category]})]}),i.jsx("button",{"aria-label":`${O.name}${O.enabled?"关闭":"开启"}`,className:`mini-switch ${O.enabled?"is-on":""}`,disabled:!!d,onClick:()=>void Y(O.id,()=>If(O.id,{enabled:!O.enabled})),children:i.jsx("i",{})})]}),i.jsx("p",{children:O.description}),i.jsx("code",{children:O.runtime_binding||"等待第三方绑定"}),i.jsxs("footer",{children:[i.jsx("span",{children:O.effective_enabled?"运行中":O.enabled?"等待总开关":"已停用"}),O.removable&&i.jsx("button",{disabled:!!d,onClick:()=>void Y(`remove-${O.id}`,()=>Ff(O.id)),children:"移除"})]})]},O.id))})]}):i.jsxs("div",{className:"security-skeleton",children:[i.jsx("i",{}),i.jsx("i",{}),i.jsx("i",{})]})]})}const gc=[{id:"overview",label:"数据总览",description:"真实指标 · 只读",icon:"chart"},{id:"devices",label:"手机设备",description:"设备列表 · 单机入口",icon:"device"},{id:"engine",label:"智能引擎",description:"任务 · 能力 · 治理",icon:"agent"},{id:"security",label:"安全模块",description:"总开关 · 可插拔治理",icon:"shield"},{id:"integrations",label:"统一接入中心",description:"授权 · 用量 · 文档",icon:"link"}],hp=()=>{const o=new URLSearchParams(window.location.search).get("tab");return o==="devices"||o==="device"?"devices":o==="engine"||o==="agent"?"engine":o==="integrations"?"integrations":o==="security"?"security":"overview"};function mp(){var h,j,E;const[o,u]=ne.useState(hp),[d,y]=ne.useState("checking"),[_,x]=ne.useState(""),[z,I]=ne.useState(""),[F,X]=ne.useState(""),[q,Y]=ne.useState(!1),[R,O]=ne.useState(ii),[te,J]=ne.useState(Lf),[b,Le]=ne.useState(!1),[ze,Ie]=ne.useState(),[fe,ge]=ne.useState(),[he,pe]=ne.useState(!1),[we,Oe]=ne.useState(),[je,Fe]=ne.useState(),_e=ne.useRef();ne.useEffect(()=>{let C=!0;return fetch("/api/v3/console/session",{credentials:"same-origin"}).then(async A=>{if(A.status===401)return{authenticated:!1};if(!A.ok)throw new Error("登录状态检查失败");return A.json()}).then(A=>{C&&y(A.authenticated===!0?"authenticated":"signed_out")}).catch(()=>{C&&(y("signed_out"),X("登录服务暂时不可用,请确认本地服务已启动。"))}),()=>{C=!1}},[]);const w=ne.useCallback(async(C=!1)=>{pe(!0);const[A,ee]=await Promise.all([Qf(),Vf()]);Le(A.bridgeAvailable),O(A.snapshot),Ie(A.bridgeAvailable?A.error:void 0),J(ee);const re=[ee.overview,ee.devices,ee.engine].find(ue=>ue.state!=="ready");ge(re==null?void 0:re.error),pe(!1),!C&&(A.bridgeAvailable&&A.error||re!=null&&re.error)&&Fe({id:Date.now(),success:!1,message:(A.bridgeAvailable?A.error:void 0)||(re==null?void 0:re.error)||"读取总控数据失败"})},[]);ne.useEffect(()=>{if(d!=="authenticated")return;w(!0);const C=window.setInterval(()=>void w(!0),3e4),A=()=>{document.visibilityState==="visible"&&w(!0)};return document.addEventListener("visibilitychange",A),()=>{window.clearInterval(C),document.removeEventListener("visibilitychange",A)}},[d,w]),ne.useEffect(()=>{window.scrollTo({top:0,behavior:"auto"}),document.documentElement.scrollTop=0,document.body.scrollTop=0},[o]),ne.useEffect(()=>{if(je)return window.clearTimeout(_e.current),_e.current=window.setTimeout(()=>Fe(void 0),3200),()=>window.clearTimeout(_e.current)},[je]);const Be=ne.useCallback(async C=>{if(we)return;Oe(C);let A;try{A=await Kf(C),Fe({id:Date.now(),success:A.success,message:A.message}),await w(!0)}finally{Oe(void 0)}},[we,w]),G=async C=>{if(C.preventDefault(),!q){Y(!0),X("");try{const A=await fetch("/api/v3/console/login",{method:"POST",credentials:"same-origin",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:_,password:z})}),ee=await A.json().catch(()=>({}));if(!A.ok||ee.code!==200){X(ee.message||"账号或密码错误");return}I(""),y("authenticated")}catch{X("登录服务暂时不可用,请确认本地服务已启动。")}finally{Y(!1)}}},Ee=async()=>{await fetch("/api/v3/console/logout",{method:"POST",credentials:"same-origin"}).catch(()=>{}),y("signed_out"),O(ii)},ie=((h=te.devices.data)==null?void 0:h.find(C=>C.online===!0))||((j=te.devices.data)==null?void 0:j[0]),P=(E=te.engine.data)==null?void 0:E.connection,B=typeof(P==null?void 0:P.online_ws_count)=="number"?P.online_ws_count:void 0,L=B!==void 0?B>0:ie==null?void 0:ie.online;return d!=="authenticated"?i.jsx("div",{className:"console-auth-shell",children:i.jsxs("div",{className:"console-auth-card",children:[i.jsx("div",{className:"brand-mark",children:i.jsx(se,{name:"settings",size:25})}),i.jsx("span",{className:"eyebrow",children:"工作手机总控平台"}),i.jsx("h1",{children:d==="checking"?"正在检查登录状态":"登录总控平台"}),i.jsx("p",{children:d==="checking"?"正在读取现有登录保护,请稍候。":"登录后查看设备、智能引擎和统一接入中心。"}),d==="checking"?i.jsxs("div",{className:"auth-loading",children:[i.jsx("span",{}),"正在检查…"]}):i.jsxs("form",{onSubmit:G,children:[i.jsxs("label",{children:["账号",i.jsx("input",{value:_,onChange:C=>x(C.target.value),autoComplete:"username",required:!0})]}),i.jsxs("label",{children:["密码",i.jsx("input",{value:z,onChange:C=>I(C.target.value),type:"password",autoComplete:"current-password",required:!0})]}),F&&i.jsx("div",{className:"auth-error",role:"alert",children:F}),i.jsx("button",{className:"auth-submit",type:"submit",disabled:q,children:q?"登录中…":"登录并加载平台"})]})]})}):i.jsxs("div",{className:"console-shell",children:[i.jsxs("header",{className:"console-topbar",children:[i.jsx("div",{className:"brand-mark",children:i.jsx(se,{name:"settings",size:25})}),i.jsxs("div",{className:"brand-copy",children:[i.jsx("strong",{children:"工作手机总控平台"}),i.jsx("span",{children:"设备管理 · 智能任务 · 统一接入 · 知识中心"})]}),i.jsxs("div",{className:"topbar-status",children:[i.jsxs("span",{children:[i.jsx("i",{}),"服务状态"]}),i.jsxs("b",{children:["WS ",L===!0?"在线":L===!1?"离线":R.agent.connected===!0?"在线":R.agent.connected===!1?"离线":"未获取"]}),i.jsx("b",{children:ie!=null&&ie.agentVersion?`v${ie.agentVersion.replace(/^v/,"")}`:R.version?`v${R.version.replace(/^v/,"")}`:"版本未获取"}),i.jsx("button",{className:"logout-button",onClick:()=>void Ee(),children:"退出登录"})]})]}),i.jsxs("div",{className:"console-layout",children:[i.jsxs("aside",{className:"console-sidebar",children:[i.jsx("div",{className:"sidebar-label",children:"统一工作台"}),gc.map(C=>i.jsxs(ne.Fragment,{children:[C.id==="security"&&i.jsx("div",{className:"sidebar-label sidebar-label-governance",children:"治理与接入"}),i.jsxs("button",{className:o===C.id?"is-active":"","aria-current":o===C.id?"page":void 0,onClick:()=>u(C.id),children:[i.jsx("span",{className:"nav-icon",children:i.jsx(se,{name:C.icon,size:21})}),i.jsxs("span",{children:[i.jsx("strong",{children:C.label}),i.jsx("small",{children:C.description})]})]})]},C.id))]}),i.jsxs("div",{className:"console-main",children:[i.jsx("nav",{className:"console-mobile-tabs","aria-label":"主菜单",children:gc.map(C=>i.jsxs("button",{className:o===C.id?"is-active":"",onClick:()=>u(C.id),children:[i.jsx(se,{name:C.icon,size:17}),C.label]},C.id))}),o==="overview"&&i.jsx(fp,{snapshot:R,bridgeAvailable:b,api:te,loading:he}),o==="devices"&&i.jsx(sp,{api:te,loading:he,onRefresh:()=>w(!0)}),o==="engine"&&i.jsx(bf,{snapshot:R,bridgeAvailable:b,api:te,busyAction:we,onAction:Be}),o==="integrations"&&i.jsx(ap,{snapshot:R,bridgeAvailable:b,api:te,loading:he}),o==="security"&&i.jsx(pp,{})]})]}),(ze||fe)&&i.jsxs("button",{className:"snapshot-error",onClick:()=>void w(),children:[i.jsx(se,{name:"refresh",size:16}),ze||fe]}),je&&i.jsxs("div",{className:`toast ${je.success?"is-success":"is-error"}`,role:"status",children:[i.jsx(se,{name:je.success?"check":"link",size:19}),i.jsx("span",{children:je.message})]})]})}Af.createRoot(document.getElementById("root")).render(i.jsx(_f.StrictMode,{children:i.jsx(mp,{})})); diff --git a/sdk/app/static/console/assets/style-Dxgu53Kz.css b/sdk/app/static/console/assets/style-Dxgu53Kz.css new file mode 100644 index 0000000000..225552dd9e --- /dev/null +++ b/sdk/app/static/console/assets/style-Dxgu53Kz.css @@ -0,0 +1 @@ +:root{font-family:-apple-system,BlinkMacSystemFont,SF Pro Display,PingFang SC,Microsoft YaHei,sans-serif;color:#152039;background:#f3f6fd;font-synthesis:none;text-rendering:optimizeLegibility;--blue: #2e6df6;--blue-2: #5c5df8;--green: #16bf68;--red: #ef5261;--ink: #152039;--muted: #748099;--line: rgba(91, 111, 151, .13);--card: rgba(255, 255, 255, .9);--shadow: 0 10px 30px rgba(49, 78, 137, .08), 0 2px 7px rgba(31, 53, 100, .04)}*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}html{min-height:100%;background:#f3f6fd}body{margin:0;min-width:320px;min-height:100vh;overflow-x:hidden;overscroll-behavior-y:none}#root,.app-shell{width:100%;overflow-x:hidden}button{font:inherit}button:focus-visible{outline:3px solid rgba(46,109,246,.25);outline-offset:2px}button:disabled{cursor:wait;opacity:.6}.app-shell{position:relative;min-height:100vh;background:linear-gradient(160deg,#eaf1ffeb,#f9fbffe0 48%,#ecf1ffe6),#f3f6fd;overflow-x:hidden}.ambient{position:fixed;border-radius:50%;filter:blur(2px);pointer-events:none}.ambient-one{width:250px;height:250px;left:-120px;top:120px;background:radial-gradient(circle,rgba(73,145,255,.15),transparent 68%)}.ambient-two{width:290px;height:290px;right:-150px;top:32%;background:radial-gradient(circle,rgba(107,85,247,.12),transparent 68%)}.app-content{width:100%;max-width:500px;min-height:100vh;margin:0 auto;position:relative;z-index:1}.page{width:100%;max-width:100vw;padding:max(22px,env(safe-area-inset-top)) 18px calc(112px + env(safe-area-inset-bottom));animation:page-in .28s ease-out}@keyframes page-in{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}.page-header{min-height:66px;margin-bottom:14px;display:flex;align-items:flex-start;justify-content:space-between;gap:14px}.page-header h1{margin:1px 0 5px;color:#142039;font-size:25px;line-height:1.2;letter-spacing:-.8px}.page-header p{margin:0;color:#5f6d88;font-size:14px}.header-subline{display:flex;align-items:center;gap:14px;color:#586782;font-size:14px}.header-actions{display:flex;gap:9px}.icon-button{width:44px;height:44px;flex:0 0 44px;border:1px solid rgba(86,108,151,.17);border-radius:14px;color:#152039;background:#ffffffb8;box-shadow:0 5px 15px #2b45770f;display:grid;place-items:center}.card{background:var(--card);border:1px solid rgba(255,255,255,.84);border-radius:17px;box-shadow:var(--shadow);backdrop-filter:blur(18px);-webkit-backdrop-filter:blur(18px)}.section-title{margin:24px 2px 12px;font-size:18px;line-height:1.2;letter-spacing:-.3px}.status-dot,.inline-dot,.log-dot{width:8px;height:8px;flex:0 0 8px;border-radius:50%;background:#aab2c2}.status-dot.is-online,.inline-dot.is-online,.log-dot.is-success{background:var(--green);box-shadow:0 0 0 4px #16bf6817}.status-dot.is-offline,.log-dot.is-error{background:var(--red)}.log-dot.is-warning{background:#f6a51d}.status-text{display:inline-flex;align-items:center;gap:6px;color:#8b95a8;font-size:12px;font-weight:650;white-space:nowrap}.status-text.is-online{color:#10ae5d}.status-text.is-offline{color:#df4c5a}.empty-notice{margin:2px 0 14px;padding:11px 13px;display:flex;align-items:center;gap:10px;color:#8a661b;border:1px solid rgba(222,164,49,.22);border-radius:13px;background:#fff8e1d1}.empty-notice strong,.empty-notice span{display:block}.empty-notice strong{font-size:13px}.empty-notice span{margin-top:2px;color:#8f7950;font-size:11px;line-height:1.45}.hero-card,.agent-hero,.health-card{overflow:hidden;position:relative;color:#fff;border:none;background:linear-gradient(125deg,#2e82f7,#326df4 52%,#635af5);box-shadow:0 14px 31px #3566e638}.hero-card{width:100%;min-height:170px;padding:25px 18px;display:grid;grid-template-columns:88px minmax(0,1fr) 86px;align-items:center;gap:14px}.hero-card.is-unavailable{filter:saturate(.78)}.hero-shield,.health-shield{position:relative;display:grid;place-items:center;color:#ffffffe6}.hero-rings,.health-shield span{position:absolute;width:105px;height:105px;border:1px solid rgba(255,255,255,.12);border-radius:50%;box-shadow:0 0 0 13px #ffffff0b,0 0 0 26px #ffffff09}.hero-content{min-width:0}.hero-content>strong{display:block;font-size:21px;letter-spacing:-.5px;white-space:nowrap}.hero-content>span{display:block;margin-top:12px;color:#fff;font-size:14px;font-weight:650}.hero-content>b{display:block;margin:1px 0 9px;color:#fff;font-size:29px;font-weight:750;letter-spacing:1.5px;text-shadow:0 2px 8px rgba(16,41,112,.24);font-variant-numeric:tabular-nums}.hero-content .status-text{color:#a8ffd3}.hero-status-mark{min-width:0;padding:0 0 0 13px;color:#fff;border-left:1px dashed rgba(255,255,255,.38);display:flex;flex-direction:column;align-items:center;gap:9px}.hero-status-mark>span{width:62px;height:62px;display:grid;place-items:center;color:#fff;border-radius:17px;background:#ffffff26;box-shadow:0 9px 20px #1e307d33}.hero-status-mark strong{font-size:12px;white-space:nowrap}.core-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.core-card{overflow:hidden;min-width:0;padding:14px 5px 12px;text-align:center}.core-icon{width:48px;height:48px;margin:0 auto 7px;display:grid;place-items:center;color:#98a2b5;border-radius:15px;background:#f4f6fb}.core-icon.is-online{color:var(--green);background:#16bf6817}.core-icon.is-offline{color:var(--red);background:#ef526117}.core-card>strong{display:block;margin-bottom:7px;overflow:hidden;font-size:12px;text-overflow:ellipsis}.core-card .status-text{max-width:100%;overflow:hidden;text-overflow:ellipsis;justify-content:center;font-size:10px}.data-list{overflow:hidden;padding:3px 14px}.data-row{width:100%;min-height:48px;padding:0;border:0;border-bottom:1px solid var(--line);background:transparent;display:flex;align-items:center;gap:10px;text-align:left}.data-row:last-child{border-bottom:0}.row-button{cursor:pointer}.row-icon{width:26px;color:#426cb6;display:grid;place-items:center}.row-label{flex:1 1 auto;color:#44516b;font-size:13px}.row-value{max-width:55%;color:#25334d;font-size:13px;text-align:right;overflow-wrap:anywhere}.tone-success{color:#12ad5d!important}.tone-danger{color:var(--red)!important}.tone-muted{color:var(--muted)!important}.tone-violet{color:#7555ec!important}.tone-green{color:#13b864!important}.row-chevron{flex:0 0 auto;color:#9ba5b6}.inline-dot{display:inline-block;margin-left:8px;vertical-align:1px}.wechat-summary{padding:15px;display:grid;grid-template-columns:48px minmax(0,1fr) auto;align-items:center;gap:11px}.wechat-icon{width:48px;height:48px;display:grid;place-items:center;color:#8e98aa;border-radius:50%;background:#f0f2f6}.wechat-icon.is-online{color:#fff;background:linear-gradient(145deg,#28d479,#0eaa55);box-shadow:0 8px 18px #14b55c33}.wechat-main strong{display:block;margin-bottom:5px;font-size:13px}.friend-count{padding-left:12px;border-left:1px solid var(--line);text-align:center}.friend-count span{display:block;color:#7f899c;font-size:10px}.friend-count strong{display:block;margin-top:2px;font-size:16px}.action-button{min-height:42px;padding:0 16px;display:inline-flex;justify-content:center;align-items:center;gap:8px;color:#fff;border:0;border-radius:12px;background:linear-gradient(135deg,var(--blue),#5265ef);font-size:13px;font-weight:650}.action-button.is-secondary{color:var(--blue);border:1px solid rgba(46,109,246,.55);background:#ffffffb3}.wechat-summary .action-button{grid-column:1 / -1;width:100%;min-height:39px}.event-list,.agent-log-list{padding:3px 14px}.event-row,.agent-log-row{min-height:47px;display:grid;align-items:center;gap:9px;border-bottom:1px solid var(--line)}.event-row{grid-template-columns:29px minmax(0,1fr) auto}.event-row:last-child,.agent-log-row:last-child{border-bottom:0}.event-mark{width:27px;height:27px;display:grid;place-items:center;color:var(--blue);border-radius:9px;background:#2e6df612}.event-row strong,.agent-log-row strong{min-width:0;font-size:12px;font-weight:560}.event-row time,.agent-log-row time{color:#96a0b2;font-size:10px}.list-empty{padding:25px 10px;color:#9aa4b6;font-size:12px;text-align:center}.agent-hero{min-height:139px;padding:21px 20px;display:grid;grid-template-columns:88px minmax(0,1fr) auto;align-items:center;gap:15px}.agent-orbit{width:76px;height:76px;position:relative;display:grid;place-items:center;color:#fff;border:2px solid rgba(255,255,255,.42);border-radius:50%;box-shadow:0 0 0 11px #ffffff0f}.agent-orbit>span{width:25px;height:25px;position:absolute;right:-2px;bottom:-2px;display:grid;place-items:center;color:#fff;border:3px solid #4d6df2;border-radius:50%;background:#9aa4b4}.agent-orbit>span.is-online{background:var(--green)}.agent-hero-copy>strong{display:block;margin-bottom:8px;font-size:20px}.agent-hero-copy p{margin:5px 0;display:flex;align-items:center;gap:6px;color:#ffffffd6;font-size:12px}.agent-hero-copy b{color:#fff;font-weight:650}.switch{width:43px;height:25px;padding:2px;border:0;border-radius:999px;background:#afb7c6;transition:.2s ease}.switch span{width:21px;height:21px;display:block;border-radius:50%;background:#fff;box-shadow:0 2px 5px #161f363d;transition:.2s ease}.switch.is-on{background:var(--green)}.switch.is-on span{transform:translate(18px)}.switch.is-unknown{opacity:.7;background:#b7bfce}.topology{min-height:145px;padding:18px 10px 14px;display:grid;grid-template-columns:repeat(3,1fr)}.topology-unit{position:relative;z-index:1;min-width:0;display:flex;flex-direction:column;align-items:center;text-align:center}.topology-line{height:1px;width:58%;position:absolute;right:72%;top:33px;border-top:1px dashed #b6c3dc}.topology-line.is-online{border-color:#69d79e}.topology-node{width:65px;height:65px;position:relative;display:grid;place-items:center;color:#9aa4b6;border:1px solid #dfe5f0;border-radius:50%;background:linear-gradient(145deg,#fff,#f0f4fb);box-shadow:0 5px 14px #364b7214}.topology-node.is-online{color:var(--blue);border-color:#2e6df62e;box-shadow:0 0 0 7px #2e6df60d}.topology-node>span{width:20px;height:20px;position:absolute;right:-1px;bottom:0;color:#fff;display:grid;place-items:center;border:2px solid white;border-radius:50%;background:#a6afbf}.topology-node.is-online>span{background:var(--green)}.topology-node.is-offline>span{background:var(--red)}.topology-unit>strong{margin-top:9px;font-size:12px}.topology-unit>.status-text{margin-top:4px;font-size:10px}.topology-unit>small{margin-top:5px;padding:3px 7px;color:#7d899d;border-radius:6px;background:#f1f4f8;font-size:9px}.automation-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.automation-card{min-height:112px;padding:13px 7px 11px;display:flex;flex-direction:column;align-items:center;justify-content:space-between;color:var(--blue)}.automation-card strong{color:var(--ink);font-size:11px;text-align:center}.automation-card .switch{transform:scale(.85)}.server-config .row-value{max-width:62%;font-size:11px;line-height:1.35;word-break:break-all}.server-config .row-label{flex:0 0 64px}.server-config .row-chevron{flex:0 0 auto}.config-action{padding:11px 0}.config-action .action-button{width:100%}.agent-log-row{grid-template-columns:8px 49px minmax(0,1fr) 17px}.agent-log-row>svg{color:#9aa4b4}.health-card{min-height:212px;padding:23px 20px 78px}.health-copy>span{color:#ffffffe6;font-size:14px;font-weight:650}.health-copy>div{margin-top:7px;display:flex;align-items:center;gap:11px}.health-copy>div>strong{font-size:52px;line-height:1}.health-copy>div>b{padding:5px 9px;border-radius:999px;background:#ffffff2e;font-size:12px}.health-copy>div>b.is-healthy{background:#41da85e0}.health-copy p{margin:10px 0 0;color:#ffffffc2;font-size:12px}.health-shield{position:absolute;right:30px;top:26px}.metric-bar{min-height:60px;position:absolute;left:18px;right:18px;bottom:16px;display:grid;grid-template-columns:repeat(3,1fr);border:1px solid rgba(255,255,255,.24);border-radius:13px;background:#ffffff14}.metric-bar>div{min-width:0;display:flex;align-items:center;justify-content:center;gap:7px;border-right:1px solid rgba(255,255,255,.18)}.metric-bar>div:last-child{border-right:0}.metric-bar span{display:block;color:#ffffffb3;font-size:9px}.metric-bar strong{display:block;margin-top:2px;color:#fff;font-size:15px}.identity-card{margin-top:14px;overflow:hidden;display:grid;grid-template-columns:minmax(0,1.55fr) minmax(125px,.85fr)}.identity-data{padding:15px 0 10px 15px}.identity-data h2{margin:0 0 2px;font-size:17px}.identity-data .data-row{min-height:43px}.identity-data .row-label,.identity-data .row-value{font-size:11px}.identity-data .row-label{flex:0 0 86px}.identity-data .row-value{max-width:calc(100% - 100px)}.identity-bind{margin:15px;padding:10px 5px;display:flex;flex-direction:column;align-items:center;justify-content:center;color:#202c43;border:0;border-left:1px solid var(--line);background:transparent}.identity-bind>span{width:66px;height:66px;display:grid;place-items:center;color:#fff;border-radius:50%;background:linear-gradient(145deg,#3f7bf8,#6658f4);box-shadow:0 11px 22px #455ee733}.identity-bind strong{margin-top:10px;font-size:13px}.identity-bind small{max-width:96px;margin-top:4px;color:#969faf;font-size:9px;line-height:1.4}.permission-grid{padding:10px;display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.permission-card{min-height:69px;padding:9px;display:flex;align-items:center;gap:8px;color:var(--blue);border:1px solid rgba(88,109,150,.09);border-radius:12px;background:#f7f9fdd9;text-align:left}.permission-card:nth-child(2n){color:#7255ee}.permission-card:nth-child(3n){color:#15b96a}.permission-card>span{min-width:0}.permission-card strong{display:block;overflow:hidden;color:var(--ink);font-size:10px;text-overflow:ellipsis;white-space:nowrap}.permission-card .status-text{margin-top:5px;font-size:9px}.maintenance-list .data-row{min-height:45px}.maintenance-details{margin-top:15px;border-radius:var(--radius);background:var(--card);box-shadow:var(--shadow)}.maintenance-details>summary{min-height:54px;padding:0 16px;display:flex;align-items:center;gap:10px;color:#32415e;cursor:pointer;list-style:none}.maintenance-details>summary::-webkit-details-marker{display:none}.maintenance-details>summary>span{flex:1;font-size:14px;font-weight:700}.maintenance-details>summary>svg:first-child{color:var(--blue)}.maintenance-details[open]>summary>svg:last-child{transform:rotate(90deg)}.maintenance-details .card{margin:0;border-radius:0 0 var(--radius) var(--radius);box-shadow:none}.version-card{margin-top:14px;padding:10px 12px;display:flex;align-items:center;justify-content:space-between;gap:10px}.version-card>span{display:flex;align-items:center;gap:7px;color:#47546c;font-size:12px}.version-card>span svg{color:var(--blue)}.version-card .action-button{min-height:36px;padding:0 14px;font-size:11px}.bottom-nav{height:calc(78px + env(safe-area-inset-bottom));padding:7px max(12px,calc((100vw - 500px)/2 + 12px)) env(safe-area-inset-bottom);position:fixed;z-index:20;left:0;right:0;bottom:0;display:grid;grid-template-columns:repeat(3,1fr);border-top:1px solid rgba(77,98,137,.1);background:#fbfcffed;box-shadow:0 -8px 28px #2b3e680f;backdrop-filter:blur(22px);-webkit-backdrop-filter:blur(22px)}.bottom-nav button{min-width:0;padding:4px 6px;display:flex;flex-direction:column;justify-content:center;align-items:center;gap:2px;color:#778196;border:0;border-radius:18px;background:transparent}.bottom-nav button>span{height:31px;display:grid;place-items:center}.bottom-nav button strong{font-size:11px;font-weight:580}.bottom-nav button.is-active{color:var(--blue);background:linear-gradient(145deg,#e7eeffe6,#eef2ffc7)}.bottom-nav button.is-active svg{filter:drop-shadow(0 4px 7px rgba(46,109,246,.2))}.toast,.snapshot-error{position:fixed;z-index:40;left:50%;transform:translate(-50%);border:0;box-shadow:0 12px 30px #1a264233}.toast{width:min(calc(100vw - 34px),440px);top:max(18px,env(safe-area-inset-top));padding:12px 14px;display:flex;align-items:center;gap:10px;color:#fff;border-radius:13px;background:#27344d;font-size:12px;animation:toast-in .25s ease-out}.toast.is-success{background:#118e50}.toast.is-error{background:#a13e49}@keyframes toast-in{0%{opacity:0;transform:translate(-50%,-12px)}to{opacity:1;transform:translate(-50%)}}.snapshot-error{bottom:calc(86px + env(safe-area-inset-bottom));padding:8px 12px;display:flex;align-items:center;gap:7px;color:#9e3f49;border-radius:999px;background:#ffedeff5;font-size:10px}@media(min-width:501px){.app-content{border-left:1px solid rgba(80,101,140,.08);border-right:1px solid rgba(80,101,140,.08);box-shadow:0 0 80px #3449700f}}@media(max-width:390px){.page{padding-left:14px;padding-right:14px}.hero-card{grid-template-columns:68px minmax(0,1fr) 82px;padding:22px 13px;gap:9px}.hero-shield svg{width:58px}.hero-rings{width:78px;height:78px}.hero-content>strong{font-size:15px;letter-spacing:-.8px}.hero-content>b{font-size:23px}.qr-action .qr-icon{width:60px;height:60px}.qr-action .qr-icon svg{width:40px}.core-grid{grid-template-columns:repeat(2,1fr)}.core-card{padding:12px 6px}.wechat-summary{grid-template-columns:44px minmax(0,1fr) auto}.agent-hero{grid-template-columns:72px minmax(0,1fr) auto;padding:18px 13px;gap:10px}.agent-orbit{width:64px;height:64px}.agent-orbit>svg{width:43px}.agent-hero-copy>strong{font-size:17px}.topology-node{width:56px;height:56px}.identity-card{grid-template-columns:minmax(0,1.5fr) minmax(105px,.8fr)}.identity-data{padding-left:11px}.identity-data .row-label{flex-basis:62px}.identity-bind{margin:12px 8px}.health-shield{right:20px}}.device-state-mark.is-pending{color:#b87a08;border-color:#f4d99a;background:#fff8e9}.device-state-mark.is-pending>span{color:#a76d00;background:#fff0c9}.device-state-mark.is-pending i{background:#e0a52d}.device-source-row{margin-top:14px;padding:8px 10px;display:flex;flex-wrap:wrap;align-items:center;gap:6px 9px;color:#7183a0;border:1px solid #e4ebf5;border-radius:9px;background:#f8fbff;font-size:10px;line-height:1.45}.source-kind{padding:2px 6px;border-radius:999px;font-weight:700;white-space:nowrap}.source-kind-live{color:#177d57;background:#e5f8ee}.source-kind-history{color:#7851a8;background:#f0e8fb}.source-kind-fixture{color:#9b6500;background:#fff0c9}.device-state-summary{margin-bottom:14px;padding:14px 16px;display:flex;justify-content:space-between;align-items:center;gap:16px;border-color:#dbe6f6;background:linear-gradient(105deg,#f6faff,#fbfdff)}.device-state-summary>div:first-child{display:grid;gap:4px}.device-state-summary strong{color:#304362;font-size:15px}.device-state-summary small{color:#7f90aa;font-size:10px}.device-state-summary-items{display:flex;gap:8px;flex-wrap:wrap;justify-content:flex-end}.state-count{min-width:74px;padding:7px 9px;display:inline-flex;align-items:center;gap:5px;color:#526481;border:1px solid #e1e9f4;border-radius:9px;background:#fff;font-size:11px}.state-count i{width:6px;height:6px;border-radius:50%;background:#9eaabd}.state-count b{margin-left:auto;color:#2f4569;font-size:14px}.state-count-online i{background:#18ac68}.state-count-pending i{background:#e0a52d}.state-count-offline i{background:#df5964}@media(max-width:620px){.device-state-summary{display:block}.device-state-summary-items{margin-top:11px;justify-content:flex-start}}.device-add-button{border:0}.device-page-notice{margin:-8px 0 16px;padding:11px 14px;border-radius:12px;font-size:12px}.device-page-notice.is-success{color:#107a4d;background:#e9f9f0;border:1px solid #c9eedb}.device-page-notice.is-error{color:#b13f49;background:#fff0f1;border:1px solid #f4ced2}.device-management-bar{margin-bottom:20px;padding:13px;display:grid;grid-template-columns:auto minmax(420px,1fr);align-items:center;gap:14px}.device-counts{display:flex;gap:6px}.device-counts button{min-height:38px;padding:0 11px;display:inline-flex;align-items:center;gap:6px;color:#62738f;border:1px solid transparent;border-radius:10px;background:transparent;cursor:pointer;white-space:nowrap}.device-counts button.is-active{color:var(--console-blue);border-color:#d5e3fb;background:#edf4ff}.device-counts button i{width:7px;height:7px;border-radius:50%;background:#9eabbf}.device-counts button i.online{background:#1ab16e}.device-counts button i.pending{background:#e2a62b}.device-counts button i.offline{background:#df5964}.device-counts button b{font-size:13px}.device-filter-compact{min-width:0;display:grid;grid-template-columns:minmax(220px,1fr) 130px auto;gap:8px}.device-filter-compact label{min-width:0;min-height:40px;padding:0 12px;display:flex;align-items:center;gap:8px;color:#8696b0;border:1px solid var(--console-line);border-radius:11px;background:#fbfdff}.device-filter-compact input{min-width:0;width:100%;border:0;outline:0;background:transparent;color:var(--console-ink)}.device-filter-compact select,.device-filter-compact button{min-height:40px;padding:0 11px;border:1px solid var(--console-line);border-radius:11px;background:#fbfdff;color:#526583}.device-filter-compact button{display:inline-flex;align-items:center;justify-content:center;gap:6px;cursor:pointer}.device-summary-list{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px}.device-summary-card{min-width:0;min-height:170px;padding:18px;display:grid;grid-template-columns:58px minmax(0,1fr) 126px;align-items:start;gap:14px;color:var(--console-ink);border:1px solid #e1e8f4;border-radius:18px;background:#ffffffe6;box-shadow:0 10px 25px #344f8012;text-align:left;cursor:pointer;transition:.2s ease}.device-summary-card:hover{transform:translateY(-2px);border-color:#cbdcf7;box-shadow:0 14px 30px #2a53961c}.device-summary-icon{width:56px;height:68px;position:relative;display:grid;place-items:center;color:#7d8eaa;border:1px solid #dce5f2;border-radius:16px;background:#f6f9fe}.device-summary-icon i{width:11px;height:11px;position:absolute;right:-3px;top:-3px;border:3px solid white;border-radius:50%;background:#9eabbf}.device-summary-icon.is-online{color:#148a5b;border-color:#cdebdc;background:#ebfaf2}.device-summary-icon.is-online i{background:#1ab16e}.device-summary-icon.is-offline{color:#d75461;border-color:#f2cfd3;background:#fff2f3}.device-summary-icon.is-offline i{background:#df5964}.device-summary-icon.is-pending{color:#ae7309;border-color:#f0daa9;background:#fff8e8}.device-summary-icon.is-pending i{background:#e2a62b}.device-summary-main{min-width:0}.device-summary-title{display:flex;align-items:center;gap:8px}.device-summary-title strong{overflow:hidden;font-size:17px;text-overflow:ellipsis;white-space:nowrap}.device-summary-title b{padding:3px 7px;border-radius:999px;color:#71809a;background:#f0f3f8;font-size:10px;white-space:nowrap}.device-summary-title b.is-online{color:#128857;background:#e7f8ef}.device-summary-title b.is-offline{color:#c34652;background:#fff0f2}.device-summary-title b.is-pending{color:#9d6809;background:#fff3d6}.device-summary-sub,.device-summary-id{display:block;overflow:hidden;color:#7a8aa5;text-overflow:ellipsis;white-space:nowrap}.device-summary-sub{margin-top:7px;font-size:11px}.device-summary-id{margin-top:5px;font:10px ui-monospace,SFMono-Regular,Menlo,monospace}.device-summary-facts{margin-top:14px;display:flex;flex-wrap:wrap;gap:6px}.device-summary-facts em{padding:5px 7px;display:inline-flex;align-items:center;gap:5px;color:#586b89;border-radius:8px;background:#f3f6fb;font-size:10px;font-style:normal}.device-summary-side{min-height:130px;display:flex;flex-direction:column;align-items:flex-end;text-align:right}.device-summary-side>span{padding:4px 7px;color:#536988;border-radius:8px;background:#eef3fa;font-size:10px}.device-summary-side small{max-width:126px;margin-top:10px;color:#8c9ab0;font-size:9px;line-height:1.4;overflow-wrap:anywhere}.device-summary-side small.is-expired{color:#c17817}.device-summary-side b{margin-top:auto;display:inline-flex;align-items:center;color:var(--console-blue);font-size:11px}.device-overlay{position:fixed;z-index:1200;top:0;right:0;bottom:0;left:0;display:flex;justify-content:flex-end;background:#15223c61;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px)}.device-detail-drawer{width:min(620px,94vw);height:100%;padding:24px;overflow-y:auto;background:#f7faff;box-shadow:-20px 0 55px #15284e33;animation:drawer-in .24s ease-out}@keyframes drawer-in{0%{transform:translate(35px);opacity:.6}to{transform:translate(0);opacity:1}}.device-detail-drawer>header{display:grid;grid-template-columns:56px minmax(0,1fr) auto;align-items:center;gap:13px;position:relative}.device-detail-drawer>header h2{margin:3px 0 4px;font-size:22px}.device-detail-drawer>header p{margin:0;color:#8492aa;font:10px ui-monospace,SFMono-Regular,Menlo,monospace;overflow-wrap:anywhere}.device-detail-drawer>header>b{padding:6px 9px;color:#6c7b94;border-radius:999px;background:#edf1f7;font-size:11px}.device-detail-drawer>header>b.is-online{color:#118758;background:#e7f8ef}.device-detail-drawer>header>b.is-offline{color:#c34652;background:#fff0f2}.drawer-close{width:36px;height:36px;position:absolute;z-index:2;right:0;top:-8px;display:grid;place-items:center;color:#718099;border:1px solid #dbe4f1;border-radius:50%;background:#fff;font-size:24px;cursor:pointer;transform:translateY(-100%)}.device-detail-drawer>section{margin-top:22px;padding:18px;border:1px solid #e0e7f2;border-radius:16px;background:#fff}.device-detail-drawer>section h3{margin:0 0 13px;font-size:14px}.device-detail-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}.device-detail-item{min-width:0;padding:11px 12px;border-radius:11px;background:#f5f8fc}.device-detail-item span,.device-detail-item strong{display:block}.device-detail-item span{color:#8290a8;font-size:10px}.device-detail-item strong{margin-top:5px;color:#2d405f;font-size:12px;overflow-wrap:anywhere}.device-advanced{margin-top:16px;border:1px solid #dfe7f2;border-radius:14px;background:#fff}.device-advanced summary{padding:14px 16px;color:#536886;font-size:12px;cursor:pointer}.device-advanced>div{padding:0 14px 14px;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:9px}.device-detail-drawer>footer{margin-top:18px;padding:16px 0;display:flex;align-items:center;justify-content:flex-end;gap:10px}.device-detail-drawer>footer>span{margin-right:auto;color:#8896ad;font-size:10px}.danger-button{min-height:40px;padding:0 14px;display:inline-flex;align-items:center;justify-content:center;gap:7px;color:#fff;border:0;border-radius:11px;background:#d84d59;font-size:12px;font-weight:650;cursor:pointer}.device-add-modal{width:min(920px,92vw);max-height:92vh;margin:auto;padding:24px;overflow-y:auto;border-radius:22px;background:#f8fbff;box-shadow:0 24px 70px #13285040}.device-add-modal>header{position:relative}.device-add-modal>header h2{margin:4px 0 6px;font-size:22px}.device-add-modal>header p{margin:0;color:#7d8ca4;font-size:12px}.device-add-modal .drawer-close{top:0;transform:none}.device-add-steps{margin-top:18px;display:grid;grid-template-columns:repeat(3,1fr);gap:10px}.device-add-steps>div{padding:13px;display:grid;grid-template-columns:31px minmax(0,1fr);gap:3px 9px;border:1px solid #e0e7f2;border-radius:13px;background:#fff}.device-add-steps span{width:31px;height:31px;grid-row:1/3;display:grid;place-items:center;color:#fff;border-radius:50%;background:var(--console-blue);font-size:12px;font-weight:700}.device-add-steps strong{font-size:12px}.device-add-steps small,.device-add-steps a{color:#7e8da5;font-size:10px}.device-add-steps a{color:var(--console-blue)}.device-bind-layout{margin-top:16px;display:grid;grid-template-columns:1fr 340px;gap:16px}.device-bind-form,.device-qr-area{min-width:0;min-height:330px;padding:18px;border:1px solid #e0e7f2;border-radius:16px;background:#fff}.device-bind-form label{display:block;margin-bottom:12px;color:#64748f;font-size:11px}.device-bind-form input{width:100%;min-height:42px;margin-top:6px;padding:0 11px;color:#263955;border:1px solid #dce5f1;border-radius:10px;background:#f9fbfe;outline:0}.device-bind-form .primary-action{width:100%;border:0}.device-qr-area{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;color:#8190a8;text-align:center}.device-qr-area img{width:220px;height:220px;border:1px solid #dce5f1;border-radius:14px}.device-qr-area strong{color:#30425f;font-size:13px}.device-qr-area small{max-width:280px;font-size:9px;overflow-wrap:anywhere}.device-qr-area small.is-error{color:#be4651}.device-add-modal>footer{margin-top:16px;display:flex;align-items:center;justify-content:space-between;gap:12px;color:#8290a7;font-size:11px}.device-confirm-layer{justify-content:center;align-items:center;z-index:1300}.device-confirm-modal{width:min(430px,90vw);padding:28px;border-radius:20px;background:#fff;text-align:center;box-shadow:0 24px 70px #13285047}.danger-symbol{width:54px;height:54px;margin:0 auto;display:grid;place-items:center;color:#d74f5a;border-radius:17px;background:#fff0f1}.device-confirm-modal h2{margin:15px 0 8px;font-size:20px}.device-confirm-modal p{color:#78879f;font-size:12px;line-height:1.7}.device-confirm-modal>div{margin-top:20px;display:flex;justify-content:center;gap:9px}@media(max-width:1180px){.device-management-bar,.device-summary-list{grid-template-columns:1fr}}@media(max-width:760px){.device-filter-compact{grid-template-columns:1fr 1fr}.device-filter-compact label{grid-column:1/-1}.device-summary-card{grid-template-columns:50px minmax(0,1fr)}.device-summary-side{min-height:auto;grid-column:2;align-items:flex-start;text-align:left}.device-summary-side b{margin-top:9px}.device-bind-layout,.device-add-steps{grid-template-columns:1fr}}@media(max-width:520px){.device-page-heading{display:block}.device-add-button{width:100%;margin-top:14px}.device-counts{overflow-x:auto}.device-filter-compact{grid-template-columns:1fr}.device-filter-compact label{grid-column:auto}.device-summary-card{padding:14px;grid-template-columns:44px minmax(0,1fr);gap:10px}.device-summary-icon{width:44px;height:58px}.device-summary-facts em{width:100%}.device-detail-drawer{width:100%;padding:18px}.device-detail-grid,.device-advanced>div{grid-template-columns:1fr}.device-detail-drawer>header{grid-template-columns:48px minmax(0,1fr)}.device-detail-drawer>header>b{grid-column:2;justify-self:start}.device-detail-drawer>footer{align-items:stretch;flex-direction:column}.device-detail-drawer>footer>span{margin:0}.device-add-modal{width:100%;max-height:100vh;min-height:100vh;border-radius:0}.device-add-modal>footer{align-items:stretch;flex-direction:column}}:root{--console-ink: #13213e;--console-muted: #70809d;--console-line: #d9e3f3;--console-blue: #286cf6;--console-teal: #16b5b4;--console-bg: #edf3fc}body{background:var(--console-bg);color:var(--console-ink)}.console-shell{min-height:100vh;padding:24px;background:linear-gradient(135deg,#eaf1fb,#f7faff 52%,#edf3fc)}.console-topbar{max-width:1392px;min-height:102px;margin:0 auto 22px;padding:20px 24px;display:flex;align-items:center;gap:16px;border:1px solid rgba(255,255,255,.9);border-radius:26px;background:#ffffffd1;box-shadow:0 14px 35px #3a56861a;-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px)}.brand-mark{width:52px;height:52px;display:grid;place-items:center;color:#fff;border-radius:16px;background:linear-gradient(145deg,var(--console-blue),var(--console-teal));box-shadow:0 9px 19px #286cf638}.brand-copy{display:flex;flex-direction:column;gap:6px}.brand-copy strong{font-size:24px;letter-spacing:-.8px}.brand-copy span{color:var(--console-muted);font-size:14px}.topbar-status{margin-left:auto;display:flex;align-items:center;gap:10px;color:#42516e;font-size:12px}.topbar-status span,.topbar-status b{padding:10px 13px;border:1px solid var(--console-line);border-radius:999px;background:#ffffffb3;font-weight:650}.topbar-status span{color:#169a66}.topbar-status i{width:8px;height:8px;margin-right:6px;display:inline-block;border-radius:50%;background:#19b56f}.console-layout{max-width:1392px;margin:0 auto;display:grid;grid-template-columns:240px minmax(0,1fr);gap:22px;align-items:start}.console-sidebar{padding:22px 16px;position:sticky;top:24px;border:1px solid rgba(255,255,255,.9);border-radius:24px;background:#ffffffc7;box-shadow:0 14px 35px #3a568614}.sidebar-label-governance{margin-top:18px}.sidebar-label{margin:0 12px 14px;color:#8a9ab8;font-size:13px}.console-sidebar button{width:100%;min-height:60px;padding:9px 11px;display:flex;align-items:center;gap:12px;color:var(--console-ink);border:0;border-radius:15px;background:transparent;text-align:left;cursor:pointer}.console-sidebar button+button{margin-top:7px}.console-sidebar button.is-active{color:#fff;background:linear-gradient(110deg,var(--console-blue),#16b2b5);box-shadow:0 10px 22px #286cf633}.console-sidebar button.is-active small{color:#ffffffc7}.nav-icon{width:36px;height:36px;flex:0 0 36px;display:grid;place-items:center;border-radius:11px;background:#2a6cf614;color:var(--console-blue)}.console-sidebar button.is-active .nav-icon{color:#fff;background:#ffffff2e}.console-sidebar strong,.console-sidebar small{display:block}.console-sidebar strong{font-size:14px}.console-sidebar small{margin-top:4px;color:#8694ad;font-size:11px}.console-main{min-width:0}.console-mobile-tabs{display:none}.console-page{min-width:0;padding:30px 28px 48px;border:1px solid rgba(255,255,255,.95);border-radius:24px;background:#ffffffbf;box-shadow:0 14px 35px #3a568614;animation:page-in .25s ease-out}.console-page-header{min-height:67px;margin-bottom:22px;display:flex;justify-content:space-between;align-items:flex-start;gap:18px}.console-page-header h1{margin:4px 0 7px;font-size:25px;letter-spacing:-.7px}.console-page-header p{margin:0;color:var(--console-muted);font-size:14px}.eyebrow{color:#7b8eaf;font-size:12px;font-weight:650;letter-spacing:.2px}.page-badges,.device-header-actions{display:flex;align-items:center;gap:8px;flex-wrap:wrap;justify-content:flex-end}.badge{padding:8px 11px;color:#60718f;border:1px solid var(--console-line);border-radius:999px;background:#f9fbffeb;font-size:11px;font-weight:650}.badge-blue{color:var(--console-blue);background:#eaf2ff;border-color:#d6e5ff}.console-page .empty-notice{margin:0 0 18px}.console-metric-grid{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:12px}.console-metric-card{min-width:0;padding:15px 14px 13px}.console-metric-icon{width:32px;height:32px;margin-bottom:12px;display:grid;place-items:center;color:var(--console-blue);border-radius:10px;background:#edf3ff}.console-metric-label,.console-metric-card small{display:block;color:#71809c;font-size:11px}.console-metric-card strong{display:block;margin:8px 0 4px;font-size:22px;letter-spacing:-.4px}.console-metric-card small{line-height:1.35}.console-two-column{margin-top:14px;display:grid;grid-template-columns:1.35fr 1fr;gap:14px}.console-panel{min-width:0;padding:18px}.panel-heading{margin-bottom:15px;display:flex;justify-content:space-between;align-items:flex-start;gap:10px}.panel-heading h2{margin:4px 0 0;font-size:16px}.panel-note{color:#8795ad;font-size:11px}.trend-empty{min-height:190px;display:flex;flex-direction:column;justify-content:center;align-items:center;gap:8px;color:#a1aec2;text-align:center;border:1px dashed #d6e1f1;border-radius:14px;background:#f8fbff}.trend-empty strong{color:#657795;font-size:18px}.trend-empty span{max-width:290px;font-size:11px;line-height:1.5}.service-status-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}.service-status-row{padding:13px 12px;display:flex;justify-content:space-between;align-items:center;gap:8px;border:1px solid var(--console-line);border-radius:12px;background:#fbfdff}.service-status-row>span{font-size:13px}.panel-callout{margin-top:13px;padding:12px;display:flex;align-items:flex-start;gap:8px;color:#355486;border-left:3px solid var(--console-blue);border-radius:10px;background:#edf4ff;font-size:12px;line-height:1.45}.overview-table-panel{margin-top:14px}.overview-table-wrap{overflow-x:auto}.overview-table{width:100%;min-width:800px;border-collapse:collapse;font-size:12px}.overview-table th{padding:0 9px 11px;color:#7c8ca7;text-align:left;font-size:11px;font-weight:600;white-space:nowrap}.overview-table td{padding:13px 9px;border-top:1px solid var(--console-line);white-space:nowrap}.overview-table td strong,.overview-table td small{display:block}.overview-table td small{margin-top:4px;color:#91a0b7;font-size:10px}.table-empty,.device-empty-card{min-height:130px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:7px;color:#95a3b9;text-align:center}.table-empty strong,.device-empty-card strong{color:#526481;font-size:15px}.table-empty span,.device-empty-card span{font-size:11px}.primary-action,.control-entry,.quiet-button,.filter-button{min-height:40px;padding:0 13px;display:inline-flex;align-items:center;justify-content:center;gap:7px;border-radius:11px;font-size:12px;font-weight:650;cursor:pointer}.primary-action,.control-entry{color:#fff;background:linear-gradient(135deg,var(--console-blue),#15aeb4);box-shadow:0 8px 16px #286cf629}.primary-action{text-decoration:none}.control-entry,.quiet-button,.filter-button{border:0}.quiet-button,.filter-button{color:#506687;background:#edf3fc}.console-devices .device-install-card{margin-bottom:14px;padding:16px 20px;display:flex;align-items:center;justify-content:space-between;gap:10px}.install-step{display:flex;align-items:center;gap:9px;min-width:0}.install-step>span{width:27px;height:27px;display:grid;place-items:center;flex:0 0 27px;color:#fff;border-radius:50%;background:var(--console-blue);font-size:12px;font-weight:700}.install-step strong,.install-step small{display:block}.install-step strong{font-size:12px}.install-step small{margin-top:3px;color:#8a9ab2;font-size:10px}.device-install-card>i{width:34px;height:1px;border-top:1px dashed #c6d4e9}.device-filter-bar{margin-bottom:22px;padding:10px;display:flex;align-items:center;gap:9px}.search-box{min-width:0;flex:1;height:38px;padding:0 11px;display:flex;align-items:center;gap:8px;color:#89a0c1;border:1px solid var(--console-line);border-radius:10px;background:#fbfdff}.search-box input{width:100%;min-width:0;border:0;outline:0;background:transparent;color:var(--console-ink);font-size:12px}.device-filter-bar select{height:38px;padding:0 10px;color:#566b8d;border:1px solid var(--console-line);border-radius:10px;background:#fbfdff;font-size:12px}.device-list{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}.release-meta-card{display:flex;flex-wrap:wrap;align-items:center;gap:10px 18px;margin-bottom:14px;padding:14px 16px;color:#647795;font-size:11px}.release-meta-card>div{min-width:100px;display:grid;gap:4px}.release-meta-card>div strong{color:var(--console-ink);font-size:16px}.release-update-notes{flex:1 1 100%;color:#6b7f9e;line-height:1.45}.device-list-heading{margin-bottom:12px;display:flex;justify-content:space-between;align-items:end;gap:12px}.device-list-heading h2{margin:4px 0 0;font-size:17px}.data-source-note,.device-footnote{color:#8b9ab1;font-size:11px}.device-console-card{padding:20px}.device-card-top{display:grid;grid-template-columns:82px minmax(0,1fr) auto;gap:16px;align-items:center}.device-state-mark{width:74px;height:74px;display:grid;place-items:center;position:relative;color:#7b8ca7;border:1px solid var(--console-line);border-radius:20px;background:#f4f8ff}.device-state-mark.is-online{color:var(--console-blue);border-color:#cfe0ff;background:#eaf3ff}.device-state-mark.is-offline{color:#df5964;background:#fff1f2}.device-state-mark>span{position:absolute;left:50%;bottom:-9px;padding:3px 7px;transform:translate(-50%);color:#60718c;border:2px solid white;border-radius:999px;background:#f1f5fb;font-size:9px;white-space:nowrap}.device-state-mark.is-online>span{color:#149965;background:#e8fbf1}.device-state-mark i{width:5px;height:5px;margin-right:3px;display:inline-block;border-radius:50%;background:#a4afc0}.device-state-mark.is-online i{background:#18ac68}.device-card-title h3{margin:0 0 5px;font-size:18px}.device-card-title p{margin:0 0 7px;color:#7687a4;font-size:12px}.device-card-title code{color:#8493aa;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px}.status-pill{align-self:start}.device-meta-grid{margin-top:22px;padding-top:18px;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:15px 18px;border-top:1px solid var(--console-line)}.device-meta-grid span,.device-meta-grid strong{display:block}.device-meta-grid span{margin-bottom:5px;color:#8493aa;font-size:10px}.device-meta-grid strong{min-width:0;overflow-wrap:anywhere;color:#314361;font-size:12px;font-weight:650}.device-card-actions{margin-top:20px;padding-top:17px;display:flex;gap:9px;border-top:1px solid var(--console-line)}.device-footnote{margin-top:14px;line-height:1.5}.engine-hero{padding:20px;display:flex;justify-content:space-between;align-items:center;gap:20px;color:#fff;border:0;background:linear-gradient(120deg,#2c73f3,#16b3b3);box-shadow:0 12px 25px #286cf62e}.engine-hero .eyebrow{color:#ffffffc2}.engine-hero h2{margin:7px 0 8px;font-size:20px}.engine-hero p{max-width:620px;margin:0;color:#ffffffd1;font-size:12px}.engine-connection{min-width:145px;padding-left:18px;display:flex;flex-direction:column;gap:9px;border-left:1px solid rgba(255,255,255,.28)}.engine-connection .status-text{color:#fff}.engine-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:13px}.engine-section-card{padding:17px}.engine-section-head{display:flex;align-items:flex-start;gap:11px}.engine-icon,.integration-icon{width:38px;height:38px;display:grid;place-items:center;flex:0 0 38px;color:var(--console-blue);border-radius:11px;background:#edf3ff}.engine-section-head h3,.integration-card h3{margin:0;font-size:15px}.engine-section-head p,.integration-card p{margin:5px 0 0;color:#7c8ca5;font-size:11px;line-height:1.45}.engine-section-card ul{margin:16px 0 0;padding:0;list-style:none}.engine-section-card li{min-height:30px;display:flex;align-items:center;gap:8px;color:#526481;border-top:1px solid #edf1f7;font-size:12px}.engine-section-card li b{margin-left:auto;color:#9aa7ba;font-size:10px;font-weight:500}.engine-facts{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px}.engine-facts .card{padding:15px}.engine-facts span,.engine-facts strong{display:block}.engine-facts span{color:#8392a9;font-size:11px}.engine-facts strong{margin-top:8px;color:#3c4f70;font-size:14px;overflow-wrap:anywhere}.integration-banner{padding:19px;display:flex;align-items:center;gap:13px;border-color:#d7e4fb;background:linear-gradient(105deg,#f0f6ff,#f6fcff)}.integration-banner-icon{width:48px;height:48px;display:grid;place-items:center;flex:0 0 48px;color:#fff;border-radius:14px;background:linear-gradient(135deg,var(--console-blue),var(--console-teal))}.integration-banner h2{margin:0 0 6px;font-size:16px}.integration-banner p{margin:0;color:#6f83a3;font-size:12px;line-height:1.5}.integration-status{margin-left:auto;padding-left:15px;display:flex;align-items:center;gap:6px;color:#7688a5;border-left:1px solid #d7e4f3;font-size:11px;white-space:nowrap}.integration-status strong{color:#97a4b7;font-weight:600}.integration-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}.integration-card{min-height:132px;padding:16px;position:relative}.integration-card>div{margin-top:12px}.integration-state{position:absolute;right:14px;bottom:14px;display:inline-flex;align-items:center;gap:3px;color:#8b9bb2;font-size:10px}.permission-template-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px}.permission-template-grid .card{min-height:100px;padding:14px}.permission-template-grid strong,.permission-template-grid span{display:block}.permission-template-grid strong{font-size:13px}.permission-template-grid span{margin-top:8px;color:#7d8da7;font-size:11px;line-height:1.5}.integration-note{margin-top:14px;padding:13px 15px;display:flex;align-items:flex-start;gap:9px;color:#49678f;border-color:#d7e4f7;background:#f1f6ff}.integration-note strong,.integration-note span{display:block}.integration-note strong{font-size:12px}.integration-note span{margin-top:4px;color:#7084a4;font-size:11px;line-height:1.5}.integration-footnote{margin-top:15px;color:#8b9ab1;font-size:11px}.security-error{margin-bottom:14px;padding:11px 13px;color:#ad4350;border:1px solid #f0c9ce;border-radius:10px;background:#fff3f4;font-size:12px}.security-master{padding:19px;display:flex;align-items:center;gap:14px;border-color:#dce4ef;background:#f8fafc}.security-master.is-on{border-color:#cfe3dc;background:linear-gradient(110deg,#f0faf6,#f4f8ff)}.security-master-icon{width:50px;height:50px;display:grid;place-items:center;flex:0 0 50px;color:var(--console-blue);border-radius:15px;background:#e7effd}.security-master h2{margin:0 0 5px;font-size:17px}.security-master p{margin:0;color:#74849d;font-size:12px}.security-master small{display:block;margin-top:6px;color:#8a98ac}.switch-button{margin-left:auto;padding:8px 13px;display:flex;align-items:center;gap:8px;border:1px solid #d7deea;border-radius:999px;color:#63718a;background:#fff;cursor:pointer;white-space:nowrap}.switch-button span{width:9px;height:9px;border-radius:50%;background:#aab4c2}.switch-button.is-on span{background:#21a67a;box-shadow:0 0 0 4px #21a67a1f}.security-toolbar{margin:20px 0 11px;display:flex;align-items:center;justify-content:space-between}.security-toolbar button,.security-add-card button{padding:8px 11px;display:flex;align-items:center;gap:5px;color:#fff;border:0;border-radius:9px;background:var(--console-blue);cursor:pointer}.security-add-card{margin-bottom:12px;padding:14px}.security-add-card form{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:9px}.security-add-card input,.security-add-card textarea{padding:10px;border:1px solid var(--console-line);border-radius:9px;font:inherit}.security-add-card textarea{min-height:70px;grid-column:1/-1}.security-add-card button{justify-self:start}.security-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:11px}.security-card{padding:15px;border-left:3px solid #cfd7e3}.security-card.is-on{border-left-color:#26aa7f}.security-card-head{display:flex;align-items:center;gap:10px}.security-card-head>span{width:35px;height:35px;display:grid;place-items:center;flex:0 0 35px;color:var(--console-blue);border-radius:10px;background:#edf3ff}.security-card h3{margin:0 0 3px;font-size:14px}.security-card small{color:#8b98ac}.security-card p{min-height:34px;margin:12px 0 8px;color:#74839a;font-size:11px;line-height:1.5}.security-card code{display:block;padding:7px;overflow-wrap:anywhere;border-radius:7px;color:#61718c;background:#f4f6fa;font-size:10px}.security-card footer{margin-top:11px;display:flex;justify-content:space-between;color:#6f829d;font-size:11px}.security-card footer button{color:#b3535d;border:0;background:transparent;cursor:pointer}.mini-switch{margin-left:auto;width:38px;height:22px;padding:2px;flex:0 0 38px;border:0;border-radius:999px;background:#cbd3df;cursor:pointer}.mini-switch i{width:18px;height:18px;display:block;border-radius:50%;background:#fff;transition:transform .18s}.mini-switch.is-on{background:#27aa80}.mini-switch.is-on i{transform:translate(16px)}.security-skeleton{display:grid;grid-template-columns:repeat(3,1fr);gap:12px}.security-skeleton i{height:150px;border-radius:14px;background:linear-gradient(90deg,#edf1f6,#f7f9fc,#edf1f6);background-size:200% 100%;animation:security-shimmer 1.3s infinite}@keyframes security-shimmer{to{background-position:-200% 0}}.logout-button{min-height:32px;padding:0 10px;color:#61718e;border:1px solid var(--console-line);border-radius:999px;background:#ffffffc7;font-size:10px;cursor:pointer}.console-auth-shell{min-height:100vh;padding:24px;display:grid;place-items:center;background:linear-gradient(135deg,#eaf1fb,#f8fbff 52%,#edf3fc)}.console-auth-card{width:min(100%,410px);padding:34px;text-align:center;border:1px solid rgba(255,255,255,.95);border-radius:24px;background:#ffffffd6;box-shadow:0 18px 48px #3a568621}.console-auth-card .brand-mark{margin:0 auto 16px}.console-auth-card h1{margin:8px 0 7px;font-size:24px;letter-spacing:-.6px}.console-auth-card>p{margin:0 0 24px;color:var(--console-muted);font-size:13px;line-height:1.5}.console-auth-card form{display:grid;gap:14px;text-align:left}.console-auth-card label{display:grid;gap:6px;color:#61718d;font-size:12px;font-weight:650}.console-auth-card input{height:42px;padding:0 12px;color:var(--console-ink);border:1px solid var(--console-line);border-radius:10px;outline:0;background:#fbfdff;font-size:13px}.console-auth-card input:focus{border-color:#9dbef9;box-shadow:0 0 0 3px #286cf61a}.auth-submit{height:44px;margin-top:4px;color:#fff;border:0;border-radius:11px;background:linear-gradient(135deg,var(--console-blue),var(--console-teal));font-size:13px;font-weight:700;cursor:pointer}.auth-error{padding:9px 10px;color:#b34e59;border:1px solid #f2cfd3;border-radius:9px;background:#fff3f4;font-size:11px;line-height:1.4}.auth-loading{min-height:44px;display:flex;align-items:center;justify-content:center;gap:8px;color:#70809d;font-size:12px}.auth-loading span{width:14px;height:14px;display:inline-block;border:2px solid #cbd8ed;border-top-color:var(--console-blue);border-radius:50%;animation:auth-spin .8s linear infinite}@keyframes auth-spin{to{transform:rotate(360deg)}}@media(max-width:1180px){.console-metric-grid{grid-template-columns:repeat(3,minmax(0,1fr))}.integration-grid,.permission-template-grid,.device-list{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:900px){.console-shell{padding:14px}.console-topbar{margin-bottom:14px;padding:15px 16px;border-radius:19px}.brand-copy strong{font-size:18px}.brand-copy span{font-size:11px}.topbar-status span{display:none}.console-layout{display:block}.console-sidebar{display:none}.console-mobile-tabs{margin-bottom:14px;padding:5px;display:flex;gap:4px;overflow-x:auto;border:1px solid rgba(255,255,255,.9);border-radius:14px;background:#ffffffbf}.console-mobile-tabs button{min-height:36px;padding:0 11px;display:inline-flex;align-items:center;gap:5px;flex:0 0 auto;color:#7283a0;border:0;border-radius:10px;background:transparent;font-size:11px;white-space:nowrap}.console-mobile-tabs button.is-active{color:var(--console-blue);background:#eaf2ff;font-weight:700}.console-page{padding:22px 20px 34px;border-radius:18px}.device-meta-grid{grid-template-columns:repeat(3,minmax(0,1fr))}.security-grid{grid-template-columns:1fr}}@media(max-width:620px){.console-shell{padding:0}.console-auth-shell{padding:16px}.console-auth-card{padding:26px 20px;border-radius:19px}.console-topbar{margin:0 0 10px;padding:14px;border-radius:0 0 17px 17px}.brand-mark{width:40px;height:40px;border-radius:12px}.brand-copy strong{font-size:16px}.brand-copy span{display:none}.topbar-status{gap:5px}.topbar-status b{padding:7px 8px;font-size:10px}.console-mobile-tabs{margin:0 10px 10px}.console-page{padding:18px 14px 30px;border-radius:0;border-left:0;border-right:0}.console-page-header{display:block}.console-page-header h1{font-size:23px}.page-badges,.device-header-actions{margin-top:14px;justify-content:flex-start}.console-metric-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:9px}.console-metric-card{padding:12px}.console-metric-card strong{font-size:19px}.console-two-column,.engine-grid,.integration-grid,.device-list{grid-template-columns:1fr}.console-panel{padding:14px}.overview-table-panel{margin-top:10px}.device-install-card{overflow-x:auto;justify-content:flex-start!important}.install-step{flex:0 0 auto}.device-install-card>i{flex:0 0 24px}.device-filter-bar{flex-wrap:wrap}.search-box{flex:1 1 100%}.device-filter-bar select{flex:1}.device-card-top{grid-template-columns:64px minmax(0,1fr);gap:12px}.device-state-mark{width:60px;height:60px;border-radius:16px}.status-pill{grid-column:2}.device-meta-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:13px}.device-card-actions{flex-wrap:wrap}.device-card-actions button{flex:1 1 150px}.engine-hero{display:block;padding:17px}.engine-hero h2{font-size:18px}.engine-connection{margin-top:15px;padding:12px 0 0;flex-direction:row;border-left:0;border-top:1px solid rgba(255,255,255,.28)}.engine-facts,.permission-template-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:9px}.integration-banner{display:block}.integration-status{margin:14px 0 0;padding:10px 0 0;border-left:0;border-top:1px solid #d7e4f3}.security-master{display:grid}.switch-button{margin-left:0;justify-self:start}.security-add-card form{grid-template-columns:1fr}.security-add-card textarea{grid-column:auto}.security-skeleton{grid-template-columns:1fr}}@media(max-width:390px){.console-page-header p{font-size:12px;line-height:1.5}.console-metric-card small{min-height:27px}.service-status-grid{grid-template-columns:1fr}.device-header-actions>*{flex:1}.engine-connection{display:grid;grid-template-columns:1fr 1fr}} diff --git a/sdk/app/static/console/index.html b/sdk/app/static/console/index.html new file mode 100644 index 0000000000..d457ef7b77 --- /dev/null +++ b/sdk/app/static/console/index.html @@ -0,0 +1,15 @@ + + + + + + + + 工作手机总控平台 + + + + +
+ + diff --git a/sdk/docker-compose.nas.yml b/sdk/docker-compose.nas.yml index 36089da239..d5ae939342 100644 --- a/sdk/docker-compose.nas.yml +++ b/sdk/docker-compose.nas.yml @@ -66,6 +66,7 @@ services: - MONGO_DB=workphone_sdk - REDIS_URL=redis://redis:6379/1 - API_KEY=${API_KEY:-workphone-secret-key} + - DEVICE_PAIRING_TOKEN=${DEVICE_PAIRING_TOKEN:-} - CONSOLE_USERNAME=${CONSOLE_USERNAME:-admin} - CONSOLE_PASSWORD=${CONSOLE_PASSWORD:-} - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY:-} diff --git a/开发文档/8、部署/06-存客宝宝塔/20260809_NAS扫码绑定与设备权限修复.md b/开发文档/8、部署/06-存客宝宝塔/20260809_NAS扫码绑定与设备权限修复.md new file mode 100644 index 0000000000..4bb294859f --- /dev/null +++ b/开发文档/8、部署/06-存客宝宝塔/20260809_NAS扫码绑定与设备权限修复.md @@ -0,0 +1,23 @@ +# NAS 扫码绑定与设备权限修复 + +## 问题与根因 + +1. 已登录控制台删除离线设备返回 403:前端请求缺少 `device.delete` 权限上下文。 +2. 扫码后设备没有入库:公网控制台默认以公开域名生成 WebSocket 地址,且 NAS SDK 未注入 `DEVICE_PAIRING_TOKEN`;手机无法对 NAS 建立有效握手。 + +## 修复内容 + +- 控制台默认绑定地址固定为公司 NAS 局域网:`ws://192.168.110.101:8899/ws/device`;局域网直接访问时仍保留当前地址。 +- NAS Compose 注入 `DEVICE_PAIRING_TOKEN`;首次不存在时在 NAS `.env` 中生成,且不写入文档或前端。 +- 离线删除请求补齐 `X-Authenticated: true` 与 `X-Permissions: device.delete`,继续保留:已登录会话、确认参数、幂等键、仅离线设备可删、历史审计保留。 + +## 验收 + +- NAS `workphone-sdk-nas`:`running | healthy`。 +- 删除权限验收:对不存在设备返回 HTTP 404,不再是权限 403,未影响任何真实设备。 +- 二维码验收:成功生成;内容包含 NAS WebSocket 地址和配对令牌字段。 +- 新控制台构建资源:`index-BzwMJihg.js`。 + +## 操作说明 + +请在手机设备页点击“添加手机”→“生成绑定二维码”,确认页面显示 `ws://192.168.110.101:8899/ws/device` 后,再用最新工作手机 APK 扫码。扫码后等待 10 秒刷新列表;服务端出现 WebSocket 注册后设备才会显示在线。