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 <noreply@anthropic.com>
This commit is contained in:
caoqianming 2026-03-26 10:33:19 +08:00
parent 0545388b85
commit 4338895e0a
3 changed files with 19 additions and 12 deletions

View File

@ -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();

View File

@ -93,7 +93,7 @@ export function startPointSocket() {
_reconnectDelay = 1000;
if (_connectedOnce) {
loadUnits().catch(() => {});
loadEquipments().catch(() => {});
if (state.activeView === "config") loadEquipments().catch(() => {});
}
_connectedOnce = true;
};

View File

@ -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) {