From 4338895e0a4357b00c32f3c7eaa30e86e0a88d7a Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 26 Mar 2026 10:33:19 +0800 Subject: [PATCH] refactor(ops): use units-embedded equipments, lazy-load config data Ops view now reads equipment+role_points from state.units (returned by unit list API) instead of state.equipments, eliminating the loadEquipments() call on bootstrap. Config data (sources, equipments, events, points) is deferred until the user first switches to config view. On WS reconnect, loadEquipments is only refreshed when config view is active. Co-Authored-By: Claude Sonnet 4.6 --- web/js/app.js | 21 ++++++++++++++------- web/js/logs.js | 2 +- web/js/ops.js | 8 ++++---- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/web/js/app.js b/web/js/app.js index 7832d79..81aa1e4 100644 --- a/web/js/app.js +++ b/web/js/app.js @@ -35,6 +35,8 @@ import { state } from "./state.js"; import { loadSources, saveSource } from "./sources.js"; import { closeUnitModal, loadUnits, openCreateUnitModal, resetUnitForm, renderUnits, saveUnit } from "./units.js"; +let _configLoaded = false; + function switchView(view) { state.activeView = view; const main = document.querySelector("main"); @@ -60,6 +62,15 @@ function switchView(view) { if (view === "config") { startLogs(); + if (!_configLoaded) { + _configLoaded = true; + withStatus(Promise.all([ + loadSources(), + loadEquipments(), + loadEvents(), + loadPoints(), + ])); + } } else { stopLogs(); } @@ -161,13 +172,13 @@ function bindEvents() { document.addEventListener("equipments-updated", () => { renderUnits(); - renderOpsUnits(); - if (!state.selectedOpsUnitId) loadAllEquipmentCards(); + // Re-fetch units so embedded equipment data stays in sync with config changes. + loadUnits().catch(() => {}); }); document.addEventListener("units-loaded", () => { renderOpsUnits(); - if (state.equipments.length > 0 && !state.selectedOpsUnitId) loadAllEquipmentCards(); + if (!state.selectedOpsUnitId) loadAllEquipmentCards(); }); } @@ -182,10 +193,6 @@ async function bootstrap() { await withStatus(loadUnits()); startOps(); - await withStatus(loadSources()); - await withStatus(loadEquipments()); - await withStatus(loadEvents()); - await withStatus(loadPoints()); } bootstrap(); diff --git a/web/js/logs.js b/web/js/logs.js index 1e7faf6..d87f1bd 100644 --- a/web/js/logs.js +++ b/web/js/logs.js @@ -93,7 +93,7 @@ export function startPointSocket() { _reconnectDelay = 1000; if (_connectedOnce) { loadUnits().catch(() => {}); - loadEquipments().catch(() => {}); + if (state.activeView === "config") loadEquipments().catch(() => {}); } _connectedOnce = true; }; diff --git a/web/js/ops.js b/web/js/ops.js index 8015cb7..fcf651b 100644 --- a/web/js/ops.js +++ b/web/js/ops.js @@ -84,18 +84,18 @@ function selectOpsUnit(unitId) { state.opsPointEls.clear(); if (!state.selectedOpsUnitId) { - renderOpsEquipments(state.equipments); + renderOpsEquipments(state.units.flatMap((u) => u.equipments || [])); return; } - const filtered = state.equipments.filter((eq) => eq.unit_id === unitId); - renderOpsEquipments(filtered); + const unit = state.unitMap.get(unitId); + renderOpsEquipments(unit ? (unit.equipments || []) : []); } export function loadAllEquipmentCards() { if (!dom.opsEquipmentArea) return; state.opsPointEls.clear(); - renderOpsEquipments(state.equipments); + renderOpsEquipments(state.units.flatMap((u) => u.equipments || [])); } function renderOpsEquipments(equipments) {