chore(hygiene): P3 报告归档 docs/reports + scripts 收敛 + lab 清理 + CSS/README 约定

正式 scripts 仅保留 README 自测清单;根目录报告迁入 docs/reports;
lab 采样 dump 出库;CSS 注明 btn/toast 所有权并 bump ?v=。
This commit is contained in:
cbb
2026-09-21 02:26:42 +08:00
parent 261caf50b7
commit beeae8a382
48 changed files with 170 additions and 6438 deletions
+45 -45
View File
@@ -3,12 +3,12 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ESP32 CAN 通信控制台</title>
<!-- 空 favicon:阻止浏览器自动请求 /favicon.ico(本地静态服务无此文件会 404) -->
<title>ESP32 CAN �帋縑�批��?/title>
<!-- 蝛?favicon嚗𡁻獈甇X�閫�膥�芸𢆡霂瑟� /favicon.ico嚗�𧋦�圈�����⊥�甇斗�隞嗡� 404嚗?-->
<link rel="icon" href="data:,">
<link rel="stylesheet" href="../css/base.css?v=857f83a5">
<link rel="stylesheet" href="../css/layout.css?v=acd17001">
<link rel="stylesheet" href="../css/components.css?v=quiet20260919a">
<link rel="stylesheet" href="../css/layout.css?v=20260924a">
<link rel="stylesheet" href="../css/components.css?v=20260924a">
<link rel="stylesheet" href="../css/can.css?v=c06f5688">
<link rel="stylesheet" href="../css/responsive.css?v=quiet20260919a">
</head>
@@ -25,25 +25,25 @@
</svg>
</span>
<div class="brand-text">
<strong>ESP32 CAN 通信控制台</strong>
<strong>ESP32 CAN �帋縑�批��?/strong>
<span class="brand-sub">DCU 繚 Robot_v2 繚 CAN FD</span>
</div>
</div>
<div class="header-status">
<span class="pill offline" id="canConnPill"><span class="indicator"></span><span id="canConnTxt">未连接</span></span>
<span class="pill offline" id="canConnPill"><span class="indicator"></span><span id="canConnTxt">�芾��?/span></span>
<span class="pill" id="canIpPill">IP --</span>
<span class="pill" id="canRssiPill">RSSI --</span>
<span class="pill" id="canUptimePill">餈鞱� --</span>
<span class="pill" id="canVersionPill">v--</span>
<span class="pill" id="canChannelPill">CH0</span>
<span class="pill" id="dbcSummaryPill">未导入 DBC</span>
<span class="pill" id="dbcSummaryPill">�芸紡�?DBC</span>
<span class="pill" id="messageSummaryPill">0 �交�</span>
<span class="pill" id="fbModePill">璅∪�: --</span>
<span class="pill" id="fbPollStatus">頧株砭: --</span>
</div>
<div class="header-sub can-header-actions">
<a class="pill can-link-pill" href="index.html">返回 OTA 控制台</a>
<a class="pill can-link-pill" href="can_monitor.html" title="独立全屏监控页">监控全屏</a>
<a class="pill can-link-pill" href="index.html">餈𥪜� OTA �批��?/a>
<a class="pill can-link-pill" href="can_monitor.html" title="�祉��典��烐綉憿?>�烐綉�典�</a>
</div>
</header>
@@ -56,7 +56,7 @@
<div class="card-head can-msg-list-head">
<span class="ico">��</span>
<span>�交��𡑒”</span>
<!-- 已导入:合计 + 文件 chip(可逐个移除) -->
<!-- 撌脣紡�伐���恣 + ��辣 chip嚗�虾�𣂷葵蝘駁膄嚗?-->
<div class="dbc-summary-strip dbc-summary-inline" id="dbcFileInfo" hidden>
<span class="dbc-summary-meta">
<span><b id="dbcFileCount">0</b>��辣</span>
@@ -72,7 +72,7 @@
<button class="btn btn-primary btn-sm" id="importDbcBtn" type="button">撖澆� DBC</button>
</div>
</div>
<!-- 通道 / 搜索 / 勾选 / 节点 / 批量 同一工具栏 -->
<!-- �𡁻� / �𦦵揣 / �暸�?/ ��� / �寥� �䔶�撌亙��?-->
<div class="can-msg-toolbar" id="canMsgToolbar">
<label class="can-msg-channel" for="defaultChannel">
<span class="can-msg-channel-label">�𡁻�</span>
@@ -84,43 +84,43 @@
</label>
<div class="can-msg-search-wrap">
<input class="input can-msg-search" type="text" id="dbcSearch"
placeholder="搜索报文名 / ID / 节点 / 信号" autocomplete="off">
placeholder="�𦦵揣�交��?/ ID / ��� / 靽∪噡" autocomplete="off">
</div>
<div class="can-batch-actions">
<span class="pill" id="selectedCountPill">已勾选 0</span>
<span class="pill" id="selectedCountPill">撌脣㗲�?0</span>
<div class="can-node-filter" id="nodeFilterWrap">
<button class="btn btn-outline btn-sm can-node-filter-btn" id="nodeFilterBtn" type="button" aria-haspopup="true" aria-expanded="false">
<span class="can-node-filter-label" id="nodeFilterLabel">�煾����對��券�</span>
<span class="can-node-filter-caret">▾</span>
<span class="can-node-filter-caret">�?/span>
</button>
<div class="can-node-filter-panel" id="nodeFilterPanel" hidden>
<div class="can-node-filter-head">
<input class="input can-node-filter-search" id="nodeFilterSearch" type="text" placeholder="筛选节点名…">
<input class="input can-node-filter-search" id="nodeFilterSearch" type="text" placeholder="蝑偦�㕑��孵��?>
<div class="can-node-filter-actions">
<button class="btn btn-ghost btn-sm" id="nodeFilterAllBtn" type="button">全选</button>
<button class="btn btn-ghost btn-sm" id="nodeFilterAllBtn" type="button">�券�?/button>
<button class="btn btn-ghost btn-sm" id="nodeFilterNoneBtn" type="button">皜�征</button>
</div>
</div>
<div class="can-node-filter-list" id="nodeFilterList">
<div class="status-empty">先导入 DBC。</div>
<div class="status-empty">��紡�?DBC�?/div>
</div>
</div>
</div>
<label class="checkbox-inline can-batch-all-label" title="全选/取消当前过滤的所有报文">
<label class="checkbox-inline can-batch-all-label" title="�券�?�𡝗�敶枏�餈�誘����㗇𥁒�?>
<input type="checkbox" id="selectAllBox">
<span>全选当前过滤</span>
<span>�券�匧��滩�皛?/span>
</label>
<button class="btn btn-outline btn-sm" id="expandAllBtn" type="button">撅訫��券�</button>
<button class="btn btn-outline btn-sm" id="collapseAllBtn" type="button">�嗉絲�券�</button>
<button class="btn btn-primary btn-sm" id="sendCheckedBtn" type="button">批量发送勾选</button>
<button class="btn btn-primary btn-sm" id="sendCheckedBtn" type="button">�寥��煾��㗲�?/button>
</div>
</div>
<div class="card-body can-table-card-body">
<div class="message-list" id="messageList">
<div class="dbc-empty-drop" id="dbcEmptyDrop">
<div class="upload-ico">�𢬢</div>
<h4>导入 DBC 开始编辑报文</h4>
<p>点击此处或拖拽 <code>.dbc</code> 文件到列表区域</p>
<h4>撖澆� DBC 撘�憪讠�颲烐𥁒�?/h4>
<p>�孵稬甇文��𡝗��?<code>.dbc</code> ��辣�啣�銵典躹�?/p>
</div>
</div>
<div class="helper-note" id="dbcHint" hidden></div>
@@ -128,10 +128,10 @@
</section>
<section class="card can-history-card">
<div class="card-head"><span class="ico">🕘</span> 最近发送</div>
<div class="card-head"><span class="ico">��</span> ��餈穃��?/div>
<div class="card-body">
<div class="history-list history-list-compact" id="historyList">
<div class="status-empty">尚未发送任何 CAN 帧。</div>
<div class="status-empty">撠𡁏𧊋�煾��遙雿?CAN 撣扼�?/div>
</div>
</div>
</section>
@@ -139,12 +139,12 @@
<aside class="can-sidepanel">
<section class="card can-preview-card">
<div class="card-head"><span class="ico">🛰️</span> 帧预览</div>
<div class="card-head"><span class="ico">�𤌴儭?/span> 撣折�閫?/div>
<div class="card-body">
<div class="can-frame-panel can-frame-panel-compact">
<div class="can-frame-hex" id="generatedHex">--</div>
<div class="can-byte-strip" id="generatedBytes"></div>
<div class="helper-note" id="encodeHint">选择报文后,信号值会实时编码为 CAN 数据。</div>
<div class="helper-note" id="encodeHint">�㗇𥋘�交��𠬍�靽∪噡�潔�摰墧𧒄蝻𣇉�銝?CAN �唳旿�?/div>
<div class="btn-row can-frame-actions">
<button class="btn btn-outline btn-sm" id="loadPreviewToRawBtn" type="button">頧賢��啣�憪见���躹</button>
<button class="btn btn-primary btn-sm" id="sendSelectedBtn" type="button">�煾����漤�閫�葷</button>
@@ -158,7 +158,7 @@
</section>
<section class="card can-raw-card">
<div class="card-head"><span class="ico">✍️</span> 原始帧发送</div>
<div class="card-head"><span class="ico">�㵪�</span> �笔�撣批��?/div>
<div class="card-body">
<div class="row-2 can-raw-grid">
<div class="form-row" style="margin:0;">
@@ -183,7 +183,7 @@
<input class="input" type="text" id="manualData" value="0102030405060708" placeholder="01020304...">
</div>
<div class="helper-note" id="manualHint">
原始帧模式适合绕过 DBC 直接发 HEX,或发送当前预览帧后二次微调。
�笔�撣扳芋撘誯���蝏閗� DBC �湔𦻖�?HEX嚗峕��煾����漤�閫�葷�𦒘�甈∪凝靚��?
</div>
<div class="btn-row">
<button class="btn btn-primary" id="sendManualBtn" type="button">�煾���憪见葷</button>
@@ -214,22 +214,22 @@
<div class="input-group" style="margin-bottom:12px;flex-wrap:wrap;">
<button class="btn btn-primary btn-sm" id="btnModeAllPass" type="button">�冽𤣰璅∪�</button>
<button class="btn btn-outline btn-sm" id="btnModeFilter" type="button">餈�誘璅∪�</button>
<button class="btn btn-outline btn-sm" id="btnModeBridge" type="button" title="CAN0 收到的每一帧按原帧格式自动转发到 CAN1 与 CAN2">CAN0→1/2 桥接</button>
<button class="btn btn-outline btn-sm" id="btnModeBridge" type="button" title="CAN0 �嗅����銝�撣扳��笔葷�澆��芸𢆡頧砍��?CAN1 銝?CAN2">CAN0�?/2 獢交𦻖</button>
</div>
<div class="helper-note" id="monHelper" style="margin-bottom:14px;">
地址与顶栏一致;1Hz <code>/can/feedback</code>。悬停抽屉保持展开。
�啣�銝𡡞▲�譍��湛�1Hz <code>/can/feedback</code>����𨀣𡂝撅劐����撘��?
</div>
<div class="status-section-title">三路 CAN 通道(1Hz)</div>
<div class="status-section-title">銝㕑楝 CAN �𡁻�嚗?Hz嚗?/div>
<div class="feedback-grid feedback-grid-drawer">
<div class="feedback-channel collapsed" id="fbCh0">
<div class="feedback-ch-head" role="button" tabindex="0" title="�孵稬撅訫�/�睃�霂行�">
<span class="ch-dot ch0"></span> CAN0
<span class="feedback-expand-caret">▾</span>
<span class="feedback-expand-caret">�?/span>
</div>
<div class="feedback-primary">
<div class="feedback-row"><span class="fb-label">状态</span><span class="fb-val" id="fb0State">--</span></div>
<div class="feedback-row"><span class="fb-label">接收数</span><span class="fb-val" id="fb0Rx">--</span></div>
<div class="feedback-row"><span class="fb-label">�嗆�?/span><span class="fb-val" id="fb0State">--</span></div>
<div class="feedback-row"><span class="fb-label">�交𤣰�?/span><span class="fb-val" id="fb0Rx">--</span></div>
<div class="feedback-row"><span class="fb-label">�煾��㺭</span><span class="fb-val" id="fb0Tx">--</span></div>
<div class="feedback-row"><span class="fb-label">銝W葷</span><span class="fb-val" id="fb0Drop">--</span></div>
<div class="feedback-row"><span class="fb-label">�躰秤</span><span class="fb-val" id="fb0Err">--</span></div>
@@ -237,7 +237,7 @@
<div class="feedback-detail">
<div class="feedback-row"><span class="fb-label">TEC</span><span class="fb-val" id="fb0Tec">--</span></div>
<div class="feedback-row"><span class="fb-label">REC</span><span class="fb-val" id="fb0Rec">--</span></div>
<div class="feedback-row"><span class="fb-label">总线状态</span><span class="fb-val" id="fb0Bus">--</span></div>
<div class="feedback-row"><span class="fb-label">�餌瑪�嗆�?/span><span class="fb-val" id="fb0Bus">--</span></div>
<div class="feedback-row"><span class="fb-label">���衰D</span><span class="fb-val mono" id="fb0LastId">--</span></div>
<div class="feedback-row"><span class="fb-label">DLC</span><span class="fb-val" id="fb0Dlc">--</span></div>
<div class="feedback-row"><span class="fb-label">FD/BRS/ESI</span><span class="fb-val" id="fb0Flags">--</span></div>
@@ -250,11 +250,11 @@
<div class="feedback-channel collapsed" id="fbCh1">
<div class="feedback-ch-head" role="button" tabindex="0" title="�孵稬撅訫�/�睃�霂行�">
<span class="ch-dot ch1"></span> CAN1
<span class="feedback-expand-caret">▾</span>
<span class="feedback-expand-caret">�?/span>
</div>
<div class="feedback-primary">
<div class="feedback-row"><span class="fb-label">状态</span><span class="fb-val" id="fb1State">--</span></div>
<div class="feedback-row"><span class="fb-label">接收数</span><span class="fb-val" id="fb1Rx">--</span></div>
<div class="feedback-row"><span class="fb-label">�嗆�?/span><span class="fb-val" id="fb1State">--</span></div>
<div class="feedback-row"><span class="fb-label">�交𤣰�?/span><span class="fb-val" id="fb1Rx">--</span></div>
<div class="feedback-row"><span class="fb-label">�煾��㺭</span><span class="fb-val" id="fb1Tx">--</span></div>
<div class="feedback-row"><span class="fb-label">銝W葷</span><span class="fb-val" id="fb1Drop">--</span></div>
<div class="feedback-row"><span class="fb-label">�躰秤</span><span class="fb-val" id="fb1Err">--</span></div>
@@ -262,7 +262,7 @@
<div class="feedback-detail">
<div class="feedback-row"><span class="fb-label">TEC</span><span class="fb-val" id="fb1Tec">--</span></div>
<div class="feedback-row"><span class="fb-label">REC</span><span class="fb-val" id="fb1Rec">--</span></div>
<div class="feedback-row"><span class="fb-label">总线状态</span><span class="fb-val" id="fb1Bus">--</span></div>
<div class="feedback-row"><span class="fb-label">�餌瑪�嗆�?/span><span class="fb-val" id="fb1Bus">--</span></div>
<div class="feedback-row"><span class="fb-label">���衰D</span><span class="fb-val mono" id="fb1LastId">--</span></div>
<div class="feedback-row"><span class="fb-label">DLC</span><span class="fb-val" id="fb1Dlc">--</span></div>
<div class="feedback-row"><span class="fb-label">FD/BRS/ESI</span><span class="fb-val" id="fb1Flags">--</span></div>
@@ -275,11 +275,11 @@
<div class="feedback-channel collapsed" id="fbCh2">
<div class="feedback-ch-head" role="button" tabindex="0" title="�孵稬撅訫�/�睃�霂行�">
<span class="ch-dot ch2"></span> CAN2
<span class="feedback-expand-caret">▾</span>
<span class="feedback-expand-caret">�?/span>
</div>
<div class="feedback-primary">
<div class="feedback-row"><span class="fb-label">状态</span><span class="fb-val" id="fb2State">--</span></div>
<div class="feedback-row"><span class="fb-label">接收数</span><span class="fb-val" id="fb2Rx">--</span></div>
<div class="feedback-row"><span class="fb-label">�嗆�?/span><span class="fb-val" id="fb2State">--</span></div>
<div class="feedback-row"><span class="fb-label">�交𤣰�?/span><span class="fb-val" id="fb2Rx">--</span></div>
<div class="feedback-row"><span class="fb-label">�煾��㺭</span><span class="fb-val" id="fb2Tx">--</span></div>
<div class="feedback-row"><span class="fb-label">銝W葷</span><span class="fb-val" id="fb2Drop">--</span></div>
<div class="feedback-row"><span class="fb-label">�躰秤</span><span class="fb-val" id="fb2Err">--</span></div>
@@ -287,7 +287,7 @@
<div class="feedback-detail">
<div class="feedback-row"><span class="fb-label">TEC</span><span class="fb-val" id="fb2Tec">--</span></div>
<div class="feedback-row"><span class="fb-label">REC</span><span class="fb-val" id="fb2Rec">--</span></div>
<div class="feedback-row"><span class="fb-label">总线状态</span><span class="fb-val" id="fb2Bus">--</span></div>
<div class="feedback-row"><span class="fb-label">�餌瑪�嗆�?/span><span class="fb-val" id="fb2Bus">--</span></div>
<div class="feedback-row"><span class="fb-label">���衰D</span><span class="fb-val mono" id="fb2LastId">--</span></div>
<div class="feedback-row"><span class="fb-label">DLC</span><span class="fb-val" id="fb2Dlc">--</span></div>
<div class="feedback-row"><span class="fb-label">FD/BRS/ESI</span><span class="fb-val" id="fb2Flags">--</span></div>
@@ -299,7 +299,7 @@
</div>
<div class="status-section-title" style="margin-top:16px;display:flex;align-items:center;gap:10px;flex-wrap:wrap;">
<span>每 ID 快照表</span>
<span>瘥?ID 敹怎�銵?/span>
<select class="input" id="idsnapChannel" style="width:100px;text-transform:none;">
<option value="0">CAN0</option>
<option value="1">CAN1</option>
@@ -325,7 +325,7 @@
</aside>
<div class="toast" id="toast">
<span class="toast-ico" id="toastIco">✓</span>
<span class="toast-ico" id="toastIco">�?/span>
<span id="toastMsg">�滢��𣂼�</span>
</div>
+92 -92
View File
@@ -1,27 +1,27 @@
<!--
index.html - ESP32 OTA 銝剔誧�批��唬蜓憿菟𢒰嚗㇄CU Mission Control 繚 蝢𤾸����
支持 WiFi OTA(ESP32 本机 + GD32 中继)和 BLE OTA 双通道固件升级。
�舀� WiFi OTA嚗𠄌SP32 �祆㦤 + GD32 銝剔誧嚗匧� BLE OTA �屸�𡁻��箔辣��漣�?
�滚��𡁏𧋦嚗惨pp.js (WiFi OTA), ble_ota.js (BLE OTA)
子系统配色:ESP32=青绿 · GD32=琥珀 · BLE=蓝 · CAN=绿 · 内存/调试=紫
摮鞟頂蝏罸��莎�ESP32=�垍遛 繚 GD32=�亦� 繚 BLE=�?繚 CAN=蝏?繚 ���/靚��=蝝?
-->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ESP32 OTA 中继控制台</title>
<!-- 空 favicon:阻止浏览器自动请求 /favicon.ico(本地静态服务无此文件会 404) -->
<title>ESP32 OTA 銝剔誧�批��?/title>
<!-- 蝛?favicon嚗𡁻獈甇X�閫�膥�芸𢆡霂瑟� /favicon.ico嚗�𧋦�圈�����⊥�甇斗�隞嗡� 404嚗?-->
<link rel="icon" href="data:,">
<link rel="stylesheet" href="../css/base.css?v=857f83a5">
<link rel="stylesheet" href="../css/layout.css?v=jumpconsole20260916b">
<link rel="stylesheet" href="../css/components.css?v=quiet20260919a">
<link rel="stylesheet" href="../css/layout.css?v=20260924a">
<link rel="stylesheet" href="../css/components.css?v=20260924a">
<link rel="stylesheet" href="../css/can.css?v=c06f5688">
<link rel="stylesheet" href="../css/responsive.css?v=quiet20260919a">
</head>
<body>
<div class="container">
<!-- ====== HEADER: 命令栏 ====== -->
<!-- ====== HEADER: �賭誘�?====== -->
<header class="header-bar">
<div class="header-brand">
<span class="brand-logo" aria-hidden="true">
@@ -32,19 +32,19 @@
</svg>
</span>
<div class="brand-text">
<strong>ESP32 OTA 中继控制台</strong>
<strong>ESP32 OTA 銝剔誧�批��?/strong>
<span class="brand-sub">DCU 繚 Robot_v2 繚 Relay</span>
</div>
</div>
<div class="header-status">
<span class="pill offline" id="pillConn"><span class="indicator"></span><span id="pillConnTxt">未连接</span></span>
<span class="pill offline" id="pillConn"><span class="indicator"></span><span id="pillConnTxt">�芾��?/span></span>
<span class="pill" id="pillVer">v--</span>
<span class="pill" id="pillIP">--</span>
<span class="pill" id="pillRSSI">--</span>
<span class="pill" id="pillUptime">餈鞱� --</span>
</div>
<div class="header-sub">
<span class="pill">设备名: <b class="pill-val" id="deviceName">-</b></span>
<span class="pill">霈曉��? <b class="pill-val" id="deviceName">-</b></span>
<span class="pill">霈曉�ID: <b class="pill-val" id="deviceId">-</b></span>
</div>
</header>
@@ -69,7 +69,7 @@
<span class="target-tab-txt">BLE �萘�</span>
</button>
<button id="modeEcatBtn" class="btn target-tab-btn btn-outline" data-action="set-console-mode" data-arg="ecat" type="button">
<span class="target-tab-ico" aria-hidden="true">⚡</span>
<span class="target-tab-ico" aria-hidden="true">�?/span>
<span class="target-tab-txt">EtherCAT</span>
</button>
</div>
@@ -82,7 +82,7 @@
</div>
</div>
</div>
<!-- BLE 模式:launch 风格连接按钮(checkbox 驱动:勾选=已连接) -->
<!-- BLE 璅∪�嚗饝aunch 憌擧聢餈墧𦻖�厰僼嚗Ếheckbox 撽勗𢆡嚗𡁜㗲�?撌脰��伐� -->
<div id="bleModeCards" style="display:none;">
<div class="ble-launch-wrap">
<label class="ble-launch-btn" for="bleConnectToggle" data-ble-state="idle">
@@ -120,22 +120,22 @@
</svg>
</div>
<div class="launch">
<div style="--i:1">蓝</div>
<div style="--i:2">牙</div>
<div style="--i:3">连</div>
<div style="--i:4">接</div>
<div style="--i:1">�?/div>
<div style="--i:2">�?/div>
<div style="--i:3">餈?/div>
<div style="--i:4">�?/div>
</div>
<div class="start">
<div class="text1">蝑匧�餈墧𦻖</div>
<div class="text2">
<span style="--n:0">已</span>
<span style="--n:1">连</span>
<span style="--n:2">接</span>
<span style="--n:0">撌?/span>
<span style="--n:1">餈?/span>
<span style="--n:2">�?/span>
<span style="--n:3">.</span>
<span style="--n:4">.</span>
<span style="--n:5">.</span>
</div>
<div class="text3">连接中...</div>
<div class="text3">餈墧𦻖銝?..</div>
</div>
</div>
</div>
@@ -145,29 +145,29 @@
<div class="ble-launch-hint">�孵稬�厰僼餈墧𦻖 / �剖��萘�霈曉�</div>
</div>
</div>
<!-- EtherCAT 模式:APP ↔ BOOT 角色徽章 + 一键切换 -->
<!-- EtherCAT 璅∪�嚗鋫PP �?BOOT 閫坿𠧧敺賜� + 銝��桀��?-->
<div id="ecatModeCards" style="display:none;">
<div class="jump-role-panel">
<div class="jump-role-badge" id="bootEcatRoleBadge" data-role="unknown"
data-action="boot-ecat-probe" role="button" tabindex="0"
title="点击重新探测对端角色(APP / BOOT)">
title="�孵稬�齿鰵�X�撖寧垢閫坿𠧧嚗㇁PP / BOOT嚗?>
<span class="jump-role-label">敶枏�閫坿𠧧 繚 �孵稬�X�</span>
<strong id="bootEcatRoleTxt">未探测</strong>
<span class="jump-role-sw" id="bootEcatRoleSw">—</span>
<strong id="bootEcatRoleTxt">�芣䔝瘚?/strong>
<span class="jump-role-sw" id="bootEcatRoleSw">�?/span>
</div>
<div class="jump-role-meta">
<div><span>设备名 0x1008</span><b id="bootEcatName">—</b></div>
<div><span>软件版本 0x100A</span><b id="bootEcatSw">—</b></div>
<div><span>从站放行</span><b id="bootEcatArm">—</b></div>
<div><span>主站缓存 / 已写 flash</span><b id="bootEcatRecv">—</b></div>
<div><span>霈曉��?0x1008</span><b id="bootEcatName">�?/b></div>
<div><span>頧臭辣��𧋦 0x100A</span><b id="bootEcatSw">�?/b></div>
<div><span>隞𡒊��曇�</span><b id="bootEcatArm">�?/b></div>
<div><span>銝餌�蝻枏� / 撌脣� flash</span><b id="bootEcatRecv">�?/b></div>
</div>
</div>
<button class="btn btn-primary btn-block jump-btn-primary" id="bootEcatRebootBtn"
data-action="boot-ecat-reboot"
title="按对端身份自动选方向:APP→0x2502 进 BOOT;BOOT→0x2503 跳回 APP">让应用回引导程序</button>
title="�匧笆蝡航澈隞質䌊�券�㗇䲮�𡢅�APP�?x2502 餈?BOOT嚗𡰪OOT�?x2503 頝喳� APP">霈拙��典�撘訫紡蝔见�</button>
</div>
<!-- 连接文案只在顶栏 #pillConnTxt 显示,此处不再重复 -->
<!-- 餈墧𦻖����芸銁憿嗆� #pillConnTxt �曄內嚗峕迨憭���漤�憭?-->
</div>
</div>
@@ -177,7 +177,7 @@
<div class="card-body">
<div class="target-tab-row" id="targetTabRow">
<button id="targetGd32Tab" class="btn target-tab-btn btn-outline" data-action="select-flash-target" data-arg="gd32" type="button">
<span class="target-tab-ico" aria-hidden="true">⚙</span>
<span class="target-tab-ico" aria-hidden="true">�?/span>
<span class="target-tab-txt">GD32</span>
</button>
<button id="targetEsp32Tab" class="btn target-tab-btn btn-primary" data-action="select-flash-target" data-arg="esp32" type="button">
@@ -189,7 +189,7 @@
<div id="wifiEsp32UploadPane">
<div class="upload-zone upload-zone-sm" id="uploadZoneEsp32" data-action="pick-shared-firmware" data-arg="esp32">
<div class="upload-ico">�㨩</div>
<h4>点击或拖拽 ESP32 固件</h4>
<h4>�孵稬�𡝗��?ESP32 �箔辣</h4>
</div>
<input type="file" id="fileInputEsp32" accept=".bin" style="display:none;">
<div class="file-info" id="fileInfoEsp32">
@@ -211,8 +211,8 @@
<div id="wifiGd32UploadPane" style="display:none;">
<div class="upload-zone upload-zone-sm" id="uploadZoneGd32" data-action="pick-shared-firmware" data-arg="gd32">
<div class="upload-ico">�㨩</div>
<h4>点击或拖拽 GD32 固件</h4>
<p>支持 .bin 和 .hex(自动转换)</p>
<h4>�孵稬�𡝗��?GD32 �箔辣</h4>
<p>�舀� .bin �?.hex嚗�䌊�刻蓮�g�</p>
</div>
<input type="file" id="fileInputGd32" accept=".hex,.bin" style="display:none;">
<div class="file-info" id="fileInfoGd32">
@@ -235,7 +235,7 @@
<div class="upload-zone upload-zone-sm" id="uploadZone" style="margin-bottom:12px;" data-action="ble-pick-file">
<div class="upload-ico">�㨩</div>
<h4>�孵稬�𡝗��賣�隞嗅�甇文�</h4>
<p>支持 .bin 和 .hex 格式</p>
<p>�舀� .bin �?.hex �澆�</p>
</div>
<input id="firmwareFile" type="file" accept=".bin,.hex,application/octet-stream" style="display:none;">
<div class="file-info" id="fileInfo">
@@ -246,20 +246,20 @@
<div class="file-info-grid">
<div class="file-meta-item"><span>蝐餃�</span><b id="fileType">-</b></div>
<div class="file-meta-item"><span>憭批�</span><b id="fileSize">0 B</b></div>
<div class="file-meta-item"><span>总包数</span><b id="packetCount">0</b></div>
<div class="file-meta-item"><span>已写包</span><b id="sentCount">0</b></div>
<div class="file-meta-item"><span>�餃��?/span><b id="packetCount">0</b></div>
<div class="file-meta-item"><span>撌脣��?/span><b id="sentCount">0</b></div>
</div>
<div class="file-meta-item" style="margin-top:8px;">
<span>SHA-256</span>
<b id="fileSha256" style="font-size:10px;word-break:break-all;font-family:var(--font-mono);">-</b>
</div>
</div>
<div class="footer-note">建议使用 Chrome / Edge。每包 Payload 与触发命令由系统按目标自动设置。</div>
<div class="footer-note">撱箄悅雿輻鍂 Chrome / Edge����?Payload 銝舘圻�穃𦶢隞斤眏蝟餌��厩𤌍��䌊�刻挽蝵柴�?/div>
</div>
<div style="height:12px"></div>
<div id="wifiEsp32ActionPane">
<button class="btn btn-primary btn-block" id="uploadEsp32Btn" data-action="start-upload" data-arg="esp32" disabled>
上传并升级 ESP32
銝𠹺�撟嗅�蝥?ESP32
</button>
</div>
<div id="wifiGd32ActionPane" style="display:none;">
@@ -268,13 +268,13 @@
</button>
</div>
<div class="row-2" id="bleActionPane" style="display:none;">
<button id="autoFlashBtn" class="btn btn-primary" disabled>一键刷写</button>
<button id="autoFlashBtn" class="btn btn-primary" disabled>銝��桀��?/button>
<button id="abortBtn" class="btn btn-danger" disabled>銝剜迫隞餃𦛚</button>
</div>
<!-- EtherCAT 直灌面板:只在「设备连接 = EtherCAT」时显示(applySharedModeUi 控制)。
固件复用同一个 #fileInputGd32 与同一条 processFile 转换/校验,
所以这里不出现第二份 HEX 解析器;"能不能灌"只由 BOOT 里的 ecatArmed()
裁决,前端不复制判据(见 js/ota/boot_ecat.js 头注)。 -->
<!-- EtherCAT �渡��X踎嚗𡁜蘨�具�諹挽憭���?= EtherCAT�齿𧒄�曄內嚗ÒpplySharedModeUi �批�嚗剹�?
�箔辣憭滨鍂�䔶�銝?#fileInputGd32 銝𤾸�銝��?processFile 頧祆揢/�⊿�嚗?
��隞亥��䔶��箇緵蝚砌�隞?HEX 閫���剁�"�賭��賜�"�芰眏 BOOT �𣬚� ecatArmed()
鋆��嚗��蝡臭�憭滚��斗旿嚗�� js/ota/boot_ecat.js 憭湔釣嚗剹�?-->
<div id="bootEcatPane" style="display:none;">
<button class="btn btn-block" id="bootEcatRunBtn" data-action="boot-ecat-run" disabled>EtherCAT �瑕� APP</button>
<button class="btn btn-danger btn-block" id="bootEcatAbortBtn"
@@ -284,15 +284,15 @@
</div>
</div>
<!-- 4. Flash Progress + Stage Flow(WiFi/BLE/EtherCAT 共用同一张进度卡) -->
<!-- 4. Flash Progress + Stage Flow嚗ÁiFi/BLE/EtherCAT �梁鍂�䔶�撘㰘�摨血㨃嚗?-->
<div class="card card--esp32" id="progressCard">
<div class="card-head"><span class="ico">⚡</span> 刷写进度与流程阶段</div>
<div class="card-head"><span class="ico">�?/span> �瑕�餈𥕦漲銝擧�蝔钅𧫴畾?/div>
<div class="card-body">
<!-- Phase step indicators -->
<div class="progress-phase-row">
<div class="pp-step active" id="ppEsp32"><span class="pp-ico">�𣑐</span><span class="pp-txt">ESP32 OTA</span></div>
<div class="pp-step" id="ppGd32Ota"><span class="pp-ico">�㨩</span><span class="pp-txt">GD32 OTA</span></div>
<div class="pp-step" id="ppEcatOta"><span class="pp-ico">⚡</span><span class="pp-txt">EtherCAT</span></div>
<div class="pp-step" id="ppEcatOta"><span class="pp-ico">�?/span><span class="pp-txt">EtherCAT</span></div>
</div>
<!-- Unified progress bar -->
<div class="progress-wrap show" id="progressWrap">
@@ -309,7 +309,7 @@
<div class="stage-node" id="es2"><div class="stage-dot">2</div><div class="stage-label">OTA �坔�</div><div class="stage-detail" id="esd2"></div></div>
<div class="stage-node" id="es3"><div class="stage-dot">3</div><div class="stage-label">SHA-256 �⊿�</div><div class="stage-detail" id="esd3"></div></div>
<div class="stage-node" id="es4"><div class="stage-dot">4</div><div class="stage-label">摨𠉛鍂�箔辣</div><div class="stage-detail" id="esd4"></div></div>
<div class="stage-node" id="es5"><div class="stage-dot">5</div><div class="stage-label">重启中</div><div class="stage-detail" id="esd5"></div></div>
<div class="stage-node" id="es5"><div class="stage-dot">5</div><div class="stage-label">�滚鍳銝?/div><div class="stage-detail" id="esd5"></div></div>
<div class="stage-node" id="es6"><div class="stage-dot">6</div><div class="stage-label">�臬𢆡摰峕�</div><div class="stage-detail" id="esd6"></div></div>
</div>
<!-- BLE OTA stages -->
@@ -334,7 +334,7 @@
<div class="stage-flow" id="ecatStages" style="display:none;">
<div class="stage-node" id="ec1"><div class="stage-dot">1</div><div class="stage-label">霂餃��𨅯�</div><div class="stage-detail" id="ecd1"></div></div>
<div class="stage-node" id="ec2"><div class="stage-dot">2</div><div class="stage-label">�典�銝餌�</div><div class="stage-detail" id="ecd2"></div></div>
<div class="stage-node" id="ec3"><div class="stage-dot">3</div><div class="stage-label">交接进 BOOT</div><div class="stage-detail" id="ecd3"></div></div>
<div class="stage-node" id="ec3"><div class="stage-dot">3</div><div class="stage-label">鈭斗𦻖餈?BOOT</div><div class="stage-detail" id="ecd3"></div></div>
<div class="stage-node" id="ec4"><div class="stage-dot">4</div><div class="stage-label">蝖株恕撘訫紡蝔见�</div><div class="stage-detail" id="ecd4"></div></div>
<div class="stage-node" id="ec5"><div class="stage-dot">5</div><div class="stage-label">�桃拳���</div><div class="stage-detail" id="ecd5"></div></div>
<div class="stage-node" id="ec6"><div class="stage-dot">6</div><div class="stage-label">隞𡒊�憭滢�</div><div class="stage-detail" id="ecd6"></div></div>
@@ -362,35 +362,35 @@
<!-- Primary status -->
<div class="card card--status">
<div class="card-head"><span class="ico">📡</span> 设备状态</div>
<div class="card-head"><span class="ico">�摱</span> 霈曉��嗆�?/div>
<div class="card-body">
<div class="badge-grid">
<div class="badge-stat">
<div class="v err" id="bConn">蝳餌瑪</div>
<div class="k">连接状态</div>
<div class="k">餈墧𦻖�嗆�?/div>
</div>
<div class="badge-stat badge-stat-click" id="healthBadge"
role="button" tabindex="0" title="�孵稬�亦��臬𢆡�芣�"
aria-expanded="false" aria-controls="healthBootPanel">
<div class="v" id="mHealth">--</div>
<div class="k">健康状态 <span class="health-boot-hint">▾ 自检</span></div>
<div class="k">�亙熒�嗆�?<span class="health-boot-hint">�?�芣�</span></div>
</div>
<div class="badge-stat">
<div class="v err" id="connBadge">offline</div>
<div class="k">BLE 餈墧𦻖</div>
</div>
<div class="badge-stat">
<div class="v" id="gattState" style="font-size:16px;">未就绪</div>
<div class="k">GATT 状态</div>
<div class="v" id="gattState" style="font-size:16px;">�芸停蝏?/div>
<div class="k">GATT �嗆�?/div>
</div>
</div>
<!-- 启动自检:点健康状态展开,默认折叠 -->
<!-- �臬𢆡�芣�嚗𡁶��亙熒�嗆���撘�嚗屸�霈斗��?-->
<div class="health-boot-panel collapsed" id="healthBootPanel" hidden>
<div class="health-boot-head">
<span class="health-boot-title">�臬𢆡�芣�</span>
<span class="health-boot-summary" id="mBootResult">--</span>
</div>
<div class="health-boot-failed">失败/跳过:<b id="mBootFailed">--</b></div>
<div class="health-boot-failed">憭梯揖/頝唾�嚗?b id="mBootFailed">--</b></div>
<div class="boot-module-list" id="bootModuleList" aria-label="�臬𢆡璅∪��𡑒”"></div>
</div>
</div>
@@ -402,10 +402,10 @@
<div class="card-body">
<div class="metric-grid">
<div class="metric"><div class="k">ESP32 皜拙漲</div><div class="v" id="mTemp">--</div></div>
<div class="metric"><div class="k">GD32 温度</div><div class="v" id="mGd32Temp" title="SPI 0xC4;片内温度">--</div></div>
<div class="metric"><div class="k">GD32 负载</div><div class="v" id="mGd32Load" title="DCU_APP CPU 负载率:中断+非延迟处理(任务派发/OTA中继)占墙钟比,不含常开轮询与空转;EtherCAT 输入 PDO 段5,1s 窗口">--</div></div>
<div class="metric"><div class="k">输入 VCC</div><div class="v" id="mVcc" title="PA6 分压反推:VCC—47k—ADC—4.7k—GND">--</div></div>
<div class="metric"><div class="k">VDDA</div><div class="v" id="mVdda" title="片内 VREFINT 反推的 MCU 模拟供电">--</div></div>
<div class="metric"><div class="k">GD32 皜拙漲</div><div class="v" id="mGd32Temp" title="SPI 0xC4嚗𤤿���萱摨?>--</div></div>
<div class="metric"><div class="k">GD32 韐蠘蝸</div><div class="v" id="mGd32Load" title="DCU_APP CPU 韐蠘蝸���銝剜鱏+�𧼮辣餈笔��?隞餃𦛚瘣曉�/OTA銝剔誧)�惩����嚗䔶��怠虜撘�頧株砭銝𡒊征頧穿�EtherCAT 颲枏� PDO 畾?嚗?s 蝒堒藁">--</div></div>
<div class="metric"><div class="k">颲枏� VCC</div><div class="v" id="mVcc" title="PA6 ����齿綫嚗间CC�?7k�𨀞DC�?.7k�浧ND">--</div></div>
<div class="metric"><div class="k">VDDA</div><div class="v" id="mVdda" title="��� VREFINT �齿綫�?MCU 璅⊥�靘𤤿㩞">--</div></div>
<div class="metric"><div class="k">GD32 APP</div><div class="v" id="mGd32App">--</div></div>
<div class="metric"><div class="k">GD32 BOOT</div><div class="v" id="mGd32Boot">--</div></div>
<div class="metric"><div class="k">GD32 �芣�</div><div class="v" id="mGd32Init" title="GD32 APP 銝羓㩞�嘥��𣇉𠶖���SPI 0xA3嚗𥟇��𦦵�憭梯揖璅∪�/憭滢�皞琜�">--</div></div>
@@ -415,13 +415,13 @@
<div class="card card--mem" style="display:none">
<div class="card-head">
<span class="ico">🧾</span> 系统状态 (/system/status)
<span class="ico">�屁</span> 蝟餌��嗆�?(/system/status)
<button class="btn btn-ghost btn-sm card-head-btn" data-action="refresh-system-status">�瑟鰵</button>
</div>
<div class="card-body">
<div class="status-kv-grid">
<div class="status-kv"><span class="k">OTA 状态</span><b id="sOtaState">--</b></div>
<div class="status-kv"><span class="k">Relay 状态</span><b id="sRelayState">--</b></div>
<div class="status-kv"><span class="k">OTA �嗆�?/span><b id="sOtaState">--</b></div>
<div class="status-kv"><span class="k">Relay �嗆�?/span><b id="sRelayState">--</b></div>
<div class="status-kv"><span class="k">�瑟鰵�園𡢿</span><b id="sStatusUpdated">--</b></div>
</div>
</div>
@@ -430,7 +430,7 @@
<!-- Log panel -->
<div class="card card--mem log-panel">
<div class="card-head" style="justify-content:space-between;">
<span><span class="ico">🖥️</span> 调试日志</span>
<span><span class="ico">�棅儭?/span> 靚���亙�</span>
<span style="font-size:11px;font-weight:400;color:var(--text-label);text-transform:none;letter-spacing:0;font-family:var(--font-mono);">UDP :6666</span>
</div>
<div class="card-body">
@@ -444,10 +444,10 @@
<button class="btn btn-ghost btn-sm" onclick="toggleAutoScroll()" id="autoScrollBtn" title="��揢�芸𢆡皛𡁜𢆡">�� �芸𢆡皛𡁜𢆡</button>
</div>
<div class="log-scroll" id="logScroll">
<div class="log-line"><span class="lt">[--:--:--]</span><span class="lv I">I</span><span class="lg">[系统]</span><span class="lm">等待上位机连接...</span></div>
<div class="log-line"><span class="lt">[--:--:--]</span><span class="lv I">I</span><span class="lg">[蝟餌�]</span><span class="lm">蝑匧�銝𠹺��箄��?..</span></div>
</div>
<div class="log-foot">
<span>共 <span id="logCount">0</span> 条</span>
<span>�?<span id="logCount">0</span> �?/span>
<button class="btn btn-ghost btn-sm" onclick="clearLogs()">皜�膄�亙�</button>
</div>
</div>
@@ -457,15 +457,15 @@
</div>
</div>
<!-- 右侧滑出:堆与任务栈(默认露出一条,悬停展开) -->
<aside class="sys-drawer" id="sysDrawer" aria-label="堆与任务栈">
<div class="sys-drawer-rail" title="悬停展开堆与任务栈">
<!-- �喃儒皛穃枂嚗𡁜�銝𦒘遙�⊥�嚗��霈日蠧�箔��∴��砍�撅訫�嚗?-->
<aside class="sys-drawer" id="sysDrawer" aria-label="���隞餃𦛚�?>
<div class="sys-drawer-rail" title="�砍�撅訫����隞餃𦛚�?>
<span class="sys-drawer-rail-ico">��</span>
<span class="sys-drawer-rail-text">堆与任务栈</span>
<span class="sys-drawer-rail-text">���隞餃𦛚�?/span>
</div>
<div class="sys-drawer-panel card card--mem">
<div class="card-head sys-drawer-head">
<span class="ico">🧠</span> 堆与任务栈
<span class="ico">��</span> ���隞餃𦛚�?
<button class="btn btn-ghost btn-sm card-head-btn" type="button" onclick="refreshSystemStatusNow(event)">�瑟鰵</button>
</div>
<div class="card-body sys-drawer-body">
@@ -480,19 +480,19 @@
<div class="heap-detail-row">
<span>蝛粹𤦭: <b id="cpuIdlePct">--</b></span>
<span>蝒堒藁: <b id="cpuSampleMs">--</b></span>
<span>任务数: <b id="cpuTaskCount">--</b></span>
<span>隞餃𦛚�? <b id="cpuTaskCount">--</b></span>
</div>
</div>
<div class="status-task-list cpu-task-list list-scroll-top3" id="cpuTaskList" title="按占用降序,默认显示前 3 项,下滑查看其余">
<div class="status-empty">等待下一次状态刷新...</div>
<div class="status-task-list cpu-task-list list-scroll-top3" id="cpuTaskList" title="�匧��券�摨𧶏�暺䁅恕�曄內�?3 憿對�銝𧢲��亦��嗡�">
<div class="status-empty">蝑匧�銝衤�甈∠𠶖����?..</div>
</div>
<div class="status-section-title">���璁��</div>
<div class="heap-group">
<div class="heap-group-title">芯片 SRAM 总览 <span style="font-weight:400;color:var(--text-dim);font-size:10px;">(ESP32-C3 · 静态段可拆分)</span></div>
<div class="heap-group-title">�舐� SRAM �餉� <span style="font-weight:400;color:var(--text-dim);font-size:10px;">(ESP32-C3 繚 �蹱��挾�舀��?</span></div>
<div class="heap-bar-row">
<span class="heap-bar-text" id="memSramUsage">--</span>
<span class="heap-bar-track mem-sram-track" id="memSramTrack" title="紫=IRAM · 橙=.data · 灰=.bss · 青=堆已用 · 暗=堆空闲">
<span class="heap-bar-track mem-sram-track" id="memSramTrack" title="蝝?IRAM 繚 璈?.data 繚 �?.bss 繚 �?��歇�?繚 �?��征�?>
<span class="mem-seg mem-seg-iram" id="memSegIram"></span>
<span class="mem-seg mem-seg-data" id="memSegData"></span>
<span class="mem-seg mem-seg-bss" id="memSegBss"></span>
@@ -505,17 +505,17 @@
<span class="heap-legend-item"><i class="mem-dot mem-dot-iram"></i>IRAM <b id="mIram">--</b></span>
<span class="heap-legend-item"><i class="mem-dot mem-dot-data"></i>.data <b id="mData">--</b></span>
<span class="heap-legend-item"><i class="mem-dot mem-dot-bss"></i>.bss <b id="mBss">--</b></span>
<span class="heap-legend-item"><i class="mem-dot mem-dot-used"></i>堆已用 <b id="mHeapUsed">--</b></span>
<span class="heap-legend-item"><i class="mem-dot mem-dot-free"></i>堆空闲 <b id="mHeapFree">--</b></span>
<span class="heap-legend-item"><i class="mem-dot mem-dot-used"></i>��歇�?<b id="mHeapUsed">--</b></span>
<span class="heap-legend-item"><i class="mem-dot mem-dot-free"></i>��征�?<b id="mHeapFree">--</b></span>
</div>
<div class="heap-detail-row">
<span>SOC 蝒堒藁: <b id="mSramSoc">--</b></span>
<span>撠暸�靽萘�: <b id="mReservedTail">--</b></span>
<span>任务栈合计: <b id="mTaskStackTotal">--</b></span>
<span>隞餃𦛚���霈? <b id="mTaskStackTotal">--</b></span>
</div>
</div>
<div class="heap-group">
<div class="heap-group-title">内部 DRAM 堆 <span style="font-weight:400;color:var(--text-dim);font-size:10px;">(malloc 数据堆)</span></div>
<div class="heap-group-title">��� DRAM �?<span style="font-weight:400;color:var(--text-dim);font-size:10px;">(malloc �唳旿�?</span></div>
<div class="heap-bar-row">
<span class="heap-bar-text" id="memInternalUsage">--</span>
<span class="heap-bar-track"><span class="heap-bar-fill" id="memInternalFill"></span></span>
@@ -523,26 +523,26 @@
</div>
<div class="heap-detail-row">
<span>蝛粹𤦭: <b id="mInternalHeap">--</b></span>
<span>最低空闲: <b id="mInternalMinHeap">--</b></span>
<span>��雿𡒊征�? <b id="mInternalMinHeap">--</b></span>
<span>��憭批�: <b id="mInternalLargestBlock">--</b></span>
</div>
<div class="heap-detail-row">
<span>DMA 蝛粹𤦭: <b id="mDmaFree">--</b></span>
<span>RTC 堆空闲: <b id="mRtcFree">--</b></span>
<span>RTC ��征�? <b id="mRtcFree">--</b></span>
<span>����埈㺭: <b id="mAllocBlocks">--</b></span>
</div>
</div>
<div class="status-section-title">任务栈水位 <span style="font-weight:400;text-transform:none;letter-spacing:0;color:var(--text-dim);">(峰值占用 Top,下滑查看)</span></div>
<div class="status-task-list list-scroll-top3" id="taskStackList" title="按峰值占用降序,默认显示前 3 项,下滑查看其余">
<div class="status-empty">等待状态刷新...</div>
<div class="status-section-title">隞餃𦛚��偌雿?<span style="font-weight:400;text-transform:none;letter-spacing:0;color:var(--text-dim);">嚗�陸�澆��?Top嚗䔶�皛烐䰻�页�</span></div>
<div class="status-task-list list-scroll-top3" id="taskStackList" title="�匧陸�澆��券�摨𧶏�暺䁅恕�曄內�?3 憿對�銝𧢲��亦��嗡�">
<div class="status-empty">蝑匧��嗆����?..</div>
</div>
<div class="status-subfold collapsed" id="statusJsonFold">
<div class="status-subfold-head" role="button" tabindex="0"
onclick="this.parentElement.classList.toggle('collapsed')"
onkeydown="if(event.key==='Enter'||event.key===' '){event.preventDefault();this.parentElement.classList.toggle('collapsed');}">
<span class="status-section-title status-subfold-title">�笔� JSON</span>
<span class="collapse-arrow">▼</span>
<span class="collapse-arrow">�?/span>
</div>
<div class="status-subfold-body">
<pre class="status-json" id="statusJson">--</pre>
@@ -554,20 +554,20 @@
<!-- Toast -->
<div class="toast" id="toast">
<span class="toast-ico" id="toastIco">✓</span>
<span class="toast-ico" id="toastIco">�?/span>
<span id="toastMsg">�滢��𣂼�</span>
</div>
<!-- app 蝒堒藁蝘毺漲嚗𡁏𧋦憿萎��芸𢆡�㕑絲 EtherCAT PDO 敺芰㴓嚗𠃑D32 韐蠘蝸嚗㚁�
必须持有租约,否则服务端在租约归零宽限期后会把循环又停掉。
与 tabs.html / motor.html 并存时连接数>1,互不影响。 -->
敹�◆���蝘毺漲嚗�炏�蹱��∠垢�函�蝥血��嗅捐�鞉��𦒘��𠰴儐�臬��𨀣��?
銝?tabs.html / motor.html 撟嗅��嗉��交㺭>1嚗䔶�銝滚蔣�溻�?-->
<script src="../js/common/app-lease.js"></script>
<script type="module" src="../js/app.js?v=20260919a"></script>
<script type="module" src="../js/ota/console-mode.js?v=20260916d"></script>
<script type="module" src="../js/ble_ota.js?v=20260901d"></script>
<!-- 内联兜底:同步 BLE 按钮 data-ble-state 与 checkbox.checked
不依赖 ES 模块(子模块可能被浏览器缓存为旧版,不含 data-ble-state 逻辑)。
connecting 态由 session.js click handler 设置,此处跳过不覆盖。 -->
<!-- ����𨅯�嚗𡁜�甇?BLE �厰僼 data-ble-state 銝?checkbox.checked
銝滢�韏?ES 璅∪�嚗��璅∪��航�鋡急�閫�膥蝻枏�銝箸唂���銝滚鉄 data-ble-state �餉�嚗剹�?
connecting ��眏 session.js click handler 霈曄蔭嚗峕迨憭�歲餈��閬���?-->
<script type="module">
setInterval(function() {
var btn = document.querySelector('.ble-launch-btn');