feat(portal): migrate V3 console to React 19 + Vite + TypeScript + Zustand + Tailwind v4

Browse Source
This commit is contained in:
Yin Kou committed 2026-11-07 00:07:22 +08:00
1 parent 518f1e757e
commit eae4596aa3
20 files changed
+4162 -3

No files matched your search

+21 -3
View File
@@ -11,12 +11,14 @@ import subprocess
import threading import threading
import time import time
import urllib.request import urllib.request
import mimetypes
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path from pathlib import Path
PORT = int(os.environ.get("PORT", "3004")) PORT = int(os.environ.get("PORT", "3004"))
BASE_DIR = Path(__file__).resolve().parent BASE_DIR = Path(__file__).resolve().parent
DIST_DIR = BASE_DIR / "dist"
INDEX_FILE = BASE_DIR / "index.html" INDEX_FILE = BASE_DIR / "index.html"
_cache = {"data": None, "ts": 0.0} _cache = {"data": None, "ts": 0.0}
@@ -285,9 +287,25 @@ class PortalHandler(BaseHTTPRequestHandler):
self._send_json(collect_telemetry()) self._send_json(collect_telemetry())
return return
# Serve SPA index.html for root and any path # Serve static assets from Vite build output (dist/) if available
if INDEX_FILE.exists(): clean_path = self.path.split("?", 1)[0].lstrip("/")
body = INDEX_FILE.read_bytes() if clean_path and DIST_DIR.exists():
asset_file = (DIST_DIR / clean_path).resolve()
if str(asset_file).startswith(str(DIST_DIR.resolve())) and asset_file.is_file():
body = asset_file.read_bytes()
mime, _ = mimetypes.guess_type(str(asset_file))
self.send_response(200)
self.send_header("Content-Type", mime or "application/octet-stream")
self.send_header("Cache-Control", "public, max-age=86400")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
return
# Serve SPA index.html from dist/index.html (React+Vite build) or fallback index.html
spa_index = (DIST_DIR / "index.html") if (DIST_DIR / "index.html").exists() else INDEX_FILE
if spa_index.exists():
body = spa_index.read_bytes()
self.send_response(200) self.send_response(200)
self.send_header("Content-Type", "text/html; charset=utf-8") self.send_header("Content-Type", "text/html; charset=utf-8")
self.send_header("Cache-Control", "no-cache") self.send_header("Cache-Control", "no-cache")