feat(n7web): sync N7 scene cards and optimize runtime

This commit is contained in:
Miayui
2026-09-17 11:04:05 +08:00
parent 75ce391312
commit 7d196db02b
31 changed files with 2924 additions and 126 deletions
+36 -14
View File
@@ -151,6 +151,12 @@ class SeatWebApiTests(unittest.TestCase):
with self.assertRaises(urllib.error.HTTPError) as caught:
unauthenticated.open(f"{self.base_url}/api/runtime", timeout=3)
self.assertEqual(caught.exception.code, 401)
with self.assertRaises(urllib.error.HTTPError) as sync_status_denied:
unauthenticated.open(
f"{self.base_url}/api/mode-profiles/status",
timeout=3,
)
self.assertEqual(sync_status_denied.exception.code, 401)
with self.assertRaises(urllib.error.HTTPError) as state_denied:
unauthenticated.open(
@@ -292,7 +298,9 @@ class SeatWebApiTests(unittest.TestCase):
self.assertGreaterEqual(catalog["scene_count"], 13)
self.assertEqual(catalog["scene_count"], len(catalog["scenes"]))
office = next(scene for scene in catalog["scenes"] if scene["id"] == "office")
self.assertIn(office["origin"], {"preset", "customized"})
self.assertIn(office["origin"], {"preset", "customized", "n7_mqtt"})
if office["origin"] == "n7_mqtt":
self.assertEqual(office["source_topic"], "from_n7/scenes")
self.assertTrue(office["actions"])
self.assertIn("capability", office["actions"][0])
self.assertNotIn("command_flow", json.dumps(catalog, ensure_ascii=False))
@@ -306,6 +314,20 @@ class SeatWebApiTests(unittest.TestCase):
self.assertEqual(response.headers["Access-Control-Allow-Origin"], "*")
self.assertIn("GET", response.headers["Access-Control-Allow-Methods"])
def test_mode_profile_sync_status_is_lightweight_and_authenticated(self) -> None:
with self.opener.open(
f"{self.base_url}/api/mode-profiles/status",
timeout=3,
) as response:
payload = json.loads(response.read().decode("utf-8"))
self.assertEqual(response.status, 200)
self.assertIn("catalog_revision", payload)
self.assertIn("scene_count", payload)
self.assertIn("mode_scene_ingress", payload)
self.assertIn("imported_count", payload["mode_scene_ingress"])
self.assertNotIn("modes", payload)
def test_user_mode_delete_endpoint_removes_only_user_profiles(self) -> None:
original_registry = self.service.mode_profiles
with tempfile.TemporaryDirectory() as directory:
@@ -932,14 +954,14 @@ operations:
vite_entry = (web_console_root / "src" / "main.js").read_text(
encoding="utf-8"
)
with self.opener.open(f"{self.base_url}/app.js?v=dual-seat-141", timeout=3) as response:
with self.opener.open(f"{self.base_url}/app.js?v=dual-seat-145-n7-dispatch", timeout=3) as response:
app_script = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/gesture-control.js?v=android-pad-9", timeout=3
) as response:
gesture_script = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/console-v2.js?v=local-first-76", timeout=3
f"{self.base_url}/console-v2.js?v=local-first-77-performance", timeout=3
) as response:
console_script = response.read().decode("utf-8")
with self.opener.open(
@@ -959,7 +981,7 @@ operations:
) as response:
speech_worklet = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/self-extension.js?v=pet-settings-52", timeout=3
f"{self.base_url}/self-extension.js?v=pet-settings-53-performance", timeout=3
) as response:
extension_script = response.read().decode("utf-8")
with self.opener.open(
@@ -971,7 +993,7 @@ operations:
) as response:
assistant_script = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/energy-monitor.js?v=energy-monitor-4", timeout=3
f"{self.base_url}/energy-monitor.js?v=energy-monitor-5-performance", timeout=3
) as response:
energy_script = response.read().decode("utf-8")
with self.opener.open(
@@ -1018,10 +1040,10 @@ operations:
self.assertIn("CMD 0x431 · FB 0x41A · CH1", template)
self.assertIn("CMD 0x431 · FB 0x388 · CH1", template)
self.assertNotIn("透明车体 · 实体设备", template)
self.assertIn('src="/app.js?v=dual-seat-141"', html)
self.assertIn('src="/app.js?v=dual-seat-145-n7-dispatch"', html)
self.assertIn('import "../styles.css";', vite_entry)
self.assertNotIn('class="vehicle-system-hud"', template)
self.assertIn('src="/console-v2.js?v=local-first-76"', html)
self.assertIn('src="/console-v2.js?v=local-first-77-performance"', html)
self.assertIn('import "../console-v2.css";', vite_entry)
self.assertIn('src="/speech-input.js?v=sensevoice-13"', html)
self.assertIn('import "../speech-input.css";', vite_entry)
@@ -1030,7 +1052,7 @@ operations:
self.assertIn('<body class="console-v2">', html)
self.assertIn('id="v2BootScreen"', template)
self.assertIn('正在加载车机控制与实时状态', template)
self.assertIn('src="/self-extension.js?v=pet-settings-52"', html)
self.assertIn('src="/self-extension.js?v=pet-settings-53-performance"', html)
self.assertIn('import "../self-extension.css";', vite_entry)
self.assertNotIn("self-calibration", template)
self.assertNotIn("self-repair", template)
@@ -1041,7 +1063,7 @@ operations:
self.assertIn('import "../assistant-chat.css";', vite_entry)
self.assertIn('src="/assistant-chat.js?v=codex-assistant-34"', html)
self.assertIn('import "../energy-monitor.css";', vite_entry)
self.assertIn('src="/energy-monitor.js?v=energy-monitor-4"', html)
self.assertIn('src="/energy-monitor.js?v=energy-monitor-5-performance"', html)
self.assertIn('import "../codepen-glass-theme.css";', vite_entry)
self.assertEqual(extension_control_status["source_label"], "车端 MQTT")
self.assertIn("action_statuses", extension_control_status)
@@ -1331,16 +1353,16 @@ operations:
self.assertIn('canvas.addEventListener("webglcontextlost"', app_script)
self.assertIn('"cognitive-agent:module-change"', app_script)
self.assertIn(
'const CACHE_VERSION = "cognitive-agent-pad-v317-nfc-auth-routing"',
'const CACHE_VERSION = "cognitive-agent-pad-v321-n7-dispatch"',
service_worker,
)
self.assertIn('/console-v2.css?v=delivery-state-69', service_worker)
self.assertIn('/console-v2.js?v=local-first-76', service_worker)
self.assertIn('/console-v2.js?v=local-first-77-performance', service_worker)
self.assertIn('/assistant-chat.css?v=codex-assistant-29', service_worker)
self.assertIn('/assistant-chat.js?v=codex-assistant-34', service_worker)
self.assertIn('/energy-monitor.css?v=energy-monitor-4', service_worker)
self.assertIn('/energy-monitor.js?v=energy-monitor-4', service_worker)
self.assertIn('"/app.js?v=dual-seat-141"', service_worker)
self.assertIn('/energy-monitor.js?v=energy-monitor-5-performance', service_worker)
self.assertIn('"/app.js?v=dual-seat-145-n7-dispatch"', service_worker)
self.assertIn('"/speech-input.js?v=sensevoice-13"', service_worker)
self.assertIn('"/speech-input.css?v=sensevoice-7"', service_worker)
self.assertIn('"/speech-audio-worklet.js?v=sensevoice-5"', service_worker)
@@ -1800,7 +1822,7 @@ operations:
) as response:
extension_script = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/app.js?v=dual-seat-141", timeout=3
f"{self.base_url}/app.js?v=dual-seat-145-n7-dispatch", timeout=3
) as response:
app_script = response.read().decode("utf-8")