diff --git a/web/core/styles.css b/web/core/styles.css index caa41d7..5025bcc 100644 --- a/web/core/styles.css +++ b/web/core/styles.css @@ -143,6 +143,31 @@ body { .grid-app-config .panel.app-config-main { grid-column: 1; grid-row: 1; } +.unit-config-list { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); + gap: 8px; + padding: 8px; + align-content: start; +} + +.unit-config-list .unit-card { + border: 1px solid var(--border); + border-radius: 4px; + padding: 10px; +} + +.unit-config-list .unit-card .unit-equipment-tags { + display: flex; + flex-wrap: wrap; + gap: 4px; + padding-top: 4px; +} + +.unit-config-list .unit-card .unit-equipment-tags .badge { + font-size: 12px; +} + /* config view slot assignments */ .grid-config .panel.top-left { grid-column: 1; grid-row: 1; } .grid-config .panel.top-right { grid-column: 2 / 4; grid-row: 1; } diff --git a/web/feeder/index.html b/web/feeder/index.html index 0412de8..d4ea2c7 100644 --- a/web/feeder/index.html +++ b/web/feeder/index.html @@ -22,6 +22,20 @@
+ + diff --git a/web/feeder/js/app.js b/web/feeder/js/app.js index dc6b147..c7df84a 100644 --- a/web/feeder/js/app.js +++ b/web/feeder/js/app.js @@ -32,7 +32,7 @@ import { } from "./points.js"; import { state } from "./state.js"; import { loadSources, saveSource } from "./sources.js"; -import { closeUnitModal, loadUnits, openCreateUnitModal, resetUnitForm, renderUnits, saveUnit } from "./units.js"; +import { bindUnitEquipmentModalEvents, closeUnitModal, loadUnits, openCreateUnitModal, resetUnitForm, renderUnits, saveUnit } from "./units.js"; let _configLoaded = false; let _appConfigLoaded = false; @@ -83,7 +83,7 @@ function switchView(view) { if (view === "app-config") { if (!_appConfigLoaded) { _appConfigLoaded = true; - withStatus(loadUnits()); + withStatus(Promise.all([loadUnits(), loadEquipments()])); } } } @@ -185,6 +185,7 @@ function bindEvents() { dom.refreshUnitBtn2.addEventListener("click", () => withStatus(loadUnits().then(loadEvents))); dom.newUnitBtn2.addEventListener("click", openCreateUnitModal); + bindUnitEquipmentModalEvents(); document.addEventListener("equipments-updated", () => { renderUnits(); diff --git a/web/feeder/js/dom.js b/web/feeder/js/dom.js index 633f5ed..7f22f17 100644 --- a/web/feeder/js/dom.js +++ b/web/feeder/js/dom.js @@ -69,6 +69,11 @@ export const dom = { refreshUnitBtn2: byId("refreshUnitBtn2"), newUnitBtn2: byId("newUnitBtn2"), unitConfigList: byId("unitConfigList"), + unitEquipmentModal: byId("unitEquipmentModal"), + unitEquipmentList: byId("unitEquipmentList"), + closeUnitEquipmentModalBtn: byId("closeUnitEquipmentModal"), + cancelUnitEquipmentBtn: byId("cancelUnitEquipment"), + confirmUnitEquipmentBtn: byId("confirmUnitEquipment"), closeUnitModalBtn: byId("closeUnitModal"), closeEquipmentModalBtn: byId("closeEquipmentModal"), refreshEventBtn: byId("refreshEventBtn"), diff --git a/web/feeder/js/units.js b/web/feeder/js/units.js index 30006bb..ebec9a0 100644 --- a/web/feeder/js/units.js +++ b/web/feeder/js/units.js @@ -1,16 +1,26 @@ -import { apiFetch } from "./api.js"; +import { apiFetch, withStatus } from "./api.js"; import { dom } from "./dom.js"; import { loadEvents } from "./events.js"; -import { renderEquipments } from "./equipment.js"; +import { loadEquipments, renderEquipments } from "./equipment.js"; import { state } from "./state.js"; +function equipmentOf(item) { + return item && item.equipment ? item.equipment : item; +} + function equipmentCount(unitId) { return state.equipments.filter((item) => { - const equipment = item.equipment || item; + const equipment = equipmentOf(item); return equipment.unit_id === unitId; }).length; } +function boundEquipments(unitId) { + return state.equipments + .map(equipmentOf) + .filter((e) => e.unit_id === unitId); +} + export function renderUnitOptions(selected = "", target = dom.equipmentUnitId, includeEmpty = true) { if (!target) { return; @@ -97,11 +107,17 @@ function runtimeBadge(runtime) { return `${label}`; } -function buildUnitCard(unit, interactive) { +function buildUnitCard(unit, mode) { const card = document.createElement("div"); - const selected = interactive && state.selectedUnitId === unit.id; + const selected = mode === "interactive" && state.selectedUnitId === unit.id; card.className = `list-item unit-card ${selected ? "selected" : ""}`; const runtime = state.runtimes.get(unit.id); + + const bound = boundEquipments(unit.id); + const equipTags = bound.length + ? bound.map((e) => `${e.code}`).join("") + : '无设备'; + card.innerHTML = `