jim800121chen 9b0d946acd feat(local-tool): splash 顯示實時啟動進度 + 拉長 timeout + 修正執行模式顯示
Splash 進度:
- app.go 新增 bootstrapStatus field + GetBootstrapStatus() binding
- 各 startup step 呼叫 setBootstrapStatus 更新文字:
  "正在初始化 Python 環境..."
  "正在解壓 Python runtime (~10 秒)..."
  "正在建立 Python 虛擬環境 (~5 秒)..."
  "正在安裝 N 個 Python 套件 (numpy / opencv / KneronPLUS ...) (~30-60 秒)..."
  "正在安裝 Kneron USB 驅動程式 (請在 UAC 視窗點「是」)..."
  "正在準備應用程式資料..."
  "正在啟動伺服器..."
  "等待伺服器就緒..."
  "載入主介面..."
- visiona-local/frontend/app.js 每 400ms 呼叫 GetBootstrapStatus 更新畫面
- wailsjs/go/main/App.js 手動補上新 binding export(避免等 wails generate)

Timeout:
- splash MAX_WAIT_MS 60s → 240s(涵蓋 UAC 被拖延 + 慢速硬碟)
- healthCheckTimeout 15s → 30s(server 首次啟動內部解析 + embed fs 載入)

設定 > 硬體 > 執行模式:
- 顯示預設值從 mock 改為 real(跟 app.go 實際預設對齊 - Q8 決策)
- 下拉選單寬度 240 → 420px 避免文字被截斷
- i18n 說明文字改為「預設為真實硬體模式,強制 Mock 請設 VISIONA_MOCK=1」
- 仍標 disabled — 未來 M8+ 會連 backend GET /api/system/config

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 08:42:59 +08:00

75 lines
2.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// visionA Local — splash / bootstrap
// 職責:顯示 app 啟動進度 → server 就緒後跳轉到 Next.js 主 UI
import { GetServerStatus, GetServerURL, GetBootstrapStatus } from './wailsjs/go/main/App.js';
const statusEl = document.getElementById('status');
const errorEl = document.getElementById('error');
const POLL_INTERVAL_MS = 400;
// 首次啟動最長容忍時間venv 解壓(10s) + 建 venv(5s) + pip install wheels(30-60s) +
// libwdi driver install with UAC(15-30s) + server spawn(3s) + health check(2s) ≈ 60-110s
// 給到 240 秒以涵蓋慢速硬碟 / UAC 被使用者拖延的情況
const MAX_WAIT_MS = 240_000;
const startTime = Date.now();
let lastStatus = '';
async function poll() {
const elapsed = Date.now() - startTime;
if (elapsed > MAX_WAIT_MS) {
showError(
`啟動逾時(${Math.round(MAX_WAIT_MS / 1000)} 秒)。\n` +
'請關閉此視窗並重新啟動應用程式,或查看 log\n' +
'%APPDATA%\\visiona-local\\logs\\wails.log'
);
return;
}
try {
// 先更新 bootstrap 進度文字venv / pip / driver / server...
const bootstrapMsg = await GetBootstrapStatus();
if (bootstrapMsg && bootstrapMsg !== lastStatus) {
statusEl.textContent = bootstrapMsg;
lastStatus = bootstrapMsg;
}
// 檢查 server 是否已就緒
const status = await GetServerStatus();
if (status && status.lastError) {
showError('伺服器啟動失敗:' + status.lastError);
return;
}
if (status && status.running && status.url) {
statusEl.textContent = '載入主介面...';
window.location.replace(status.url + '/');
return;
}
// 備用:直接問 URL
const url = await GetServerURL();
if (url) {
statusEl.textContent = '載入主介面...';
window.location.replace(url + '/');
return;
}
} catch (e) {
// binding 尚未就緒時會 throw繼續輪詢
}
setTimeout(poll, POLL_INTERVAL_MS);
}
function showError(msg) {
statusEl.hidden = true;
errorEl.textContent = msg;
errorEl.hidden = false;
}
// 等 Wails runtime 就緒再開始輪詢
if (window.runtime) {
poll();
} else {
window.addEventListener('load', () => setTimeout(poll, 200));
}