From bc8b5a24ab19ae2f156eb9002da25fb3ded1e74c Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 20 Apr 2026 08:31:10 +0800 Subject: [PATCH] fix(feeder): render units in app-config panel, remove from platform-config - Delete feeder source-panel override (units no longer in platform config) - Extract buildUnitCard() and render to both unitList and unitConfigList - Guard null DOM refs for removed unit buttons Co-Authored-By: Claude Opus 4.6 --- web/feeder/html/source-panel.html | 22 ---- web/feeder/js/app.js | 6 +- web/feeder/js/units.js | 166 ++++++++++++++++-------------- 3 files changed, 92 insertions(+), 102 deletions(-) delete mode 100644 web/feeder/html/source-panel.html diff --git a/web/feeder/html/source-panel.html b/web/feeder/html/source-panel.html deleted file mode 100644 index 90f9fe6..0000000 --- a/web/feeder/html/source-panel.html +++ /dev/null @@ -1,22 +0,0 @@ -
-
-
-
-

控制单元

-
- - -
-
-
-
- -
-
-

数据源

- -
-
-
-
-
diff --git a/web/feeder/js/app.js b/web/feeder/js/app.js index 11daa1b..dc6b147 100644 --- a/web/feeder/js/app.js +++ b/web/feeder/js/app.js @@ -96,8 +96,8 @@ function bindEvents() { dom.batchBindingForm.addEventListener("submit", (event) => withStatus(saveBatchBinding(event))); dom.unitResetBtn.addEventListener("click", resetUnitForm); - dom.refreshUnitBtn.addEventListener("click", () => withStatus(loadUnits().then(loadEvents))); - dom.newUnitBtn.addEventListener("click", openCreateUnitModal); + if (dom.refreshUnitBtn) dom.refreshUnitBtn.addEventListener("click", () => withStatus(loadUnits().then(loadEvents))); + if (dom.newUnitBtn) dom.newUnitBtn.addEventListener("click", openCreateUnitModal); dom.closeUnitModalBtn.addEventListener("click", closeUnitModal); dom.sourceResetBtn.addEventListener("click", () => dom.sourceForm.reset()); @@ -183,7 +183,7 @@ function bindEvents() { dom.tabAppConfig.addEventListener("click", () => switchView("app-config")); dom.tabConfig.addEventListener("click", () => switchView("config")); - dom.refreshUnitBtn2.addEventListener("click", () => withStatus(loadUnits())); + dom.refreshUnitBtn2.addEventListener("click", () => withStatus(loadUnits().then(loadEvents))); dom.newUnitBtn2.addEventListener("click", openCreateUnitModal); document.addEventListener("equipments-updated", () => { diff --git a/web/feeder/js/units.js b/web/feeder/js/units.js index 3de467d..30006bb 100644 --- a/web/feeder/js/units.js +++ b/web/feeder/js/units.js @@ -97,92 +97,104 @@ function runtimeBadge(runtime) { return `${label}`; } -export function renderUnits() { - dom.unitList.innerHTML = ""; - - if (!state.units.length) { - dom.unitList.innerHTML = '
暂无控制单元
'; - return; - } - - state.units.forEach((unit) => { - const card = document.createElement("div"); - const selected = state.selectedUnitId === unit.id; - card.className = `list-item unit-card ${selected ? "selected" : ""}`; - const runtime = state.runtimes.get(unit.id); - card.innerHTML = ` -
- ${unit.code} - ${runtimeBadge(runtime)} - ${unit.enabled ? "EN" : "DIS"} -
-
${unit.name}
-
设备 ${equipmentCount(unit.id)} 台 | Acc ${runtime ? Math.floor(runtime.display_acc_sec / 1000) : 0}s
-
Run ${unit.run_time_sec}s / Stop ${unit.stop_time_sec}s / Acc ${unit.acc_time_sec}s / BL ${unit.bl_time_sec}s
-
- `; +function buildUnitCard(unit, interactive) { + const card = document.createElement("div"); + const selected = interactive && state.selectedUnitId === unit.id; + card.className = `list-item unit-card ${selected ? "selected" : ""}`; + const runtime = state.runtimes.get(unit.id); + card.innerHTML = ` +
+ ${unit.code} + ${runtimeBadge(runtime)} + ${unit.enabled ? "EN" : "DIS"} +
+
${unit.name}
+
设备 ${equipmentCount(unit.id)} 台 | Acc ${runtime ? Math.floor(runtime.display_acc_sec / 1000) : 0}s
+
Run ${unit.run_time_sec}s / Stop ${unit.stop_time_sec}s / Acc ${unit.acc_time_sec}s / BL ${unit.bl_time_sec}s
+
+ `; + if (interactive) { card.addEventListener("click", () => { selectUnit(unit.id).catch((error) => { dom.statusText.textContent = error.message; }); }); + } - const actions = card.querySelector(".unit-card-actions"); + const actions = card.querySelector(".unit-card-actions"); - const editBtn = document.createElement("button"); - editBtn.className = "secondary"; - editBtn.textContent = "Edit"; - editBtn.addEventListener("click", (event) => { - event.stopPropagation(); - openEditUnitModal(unit); - }); - - const deleteBtn = document.createElement("button"); - deleteBtn.className = "danger"; - deleteBtn.textContent = "Delete"; - deleteBtn.addEventListener("click", (event) => { - event.stopPropagation(); - deleteUnit(unit.id).catch((error) => { - dom.statusText.textContent = error.message; - }); - }); - - actions.append(editBtn, deleteBtn); - - const isAutoOn = runtime?.auto_enabled; - const startBlocked = !isAutoOn && (runtime?.fault_locked || runtime?.manual_ack_required || runtime?.rem_local); - const autoBtn = document.createElement("button"); - autoBtn.className = isAutoOn ? "danger" : "secondary"; - autoBtn.textContent = isAutoOn ? "Stop Auto" : "Start Auto"; - autoBtn.disabled = startBlocked; - autoBtn.title = startBlocked - ? (runtime?.fault_locked ? "设备故障中,无法启动自动控制" - : runtime?.rem_local ? "设备处于本地模式(REM关),无法启动自动控制" - : "需人工确认故障后才可启动自动控制") - : (isAutoOn ? "停止自动控制" : "启动自动控制"); - autoBtn.addEventListener("click", (e) => { - e.stopPropagation(); - const url = `/api/control/unit/${unit.id}/${isAutoOn ? "stop-auto" : "start-auto"}`; - apiFetch(url, { method: "POST" }).then(() => loadUnits()).catch(() => {}); - }); - actions.append(autoBtn); - - if (runtime?.manual_ack_required) { - const ackBtn = document.createElement("button"); - ackBtn.className = "danger"; - ackBtn.textContent = "Ack Fault"; - ackBtn.title = "人工确认解除故障锁定"; - ackBtn.addEventListener("click", (e) => { - e.stopPropagation(); - apiFetch(`/api/control/unit/${unit.id}/ack-fault`, { method: "POST" }) - .then(() => loadUnits()).catch(() => {}); - }); - actions.append(ackBtn); - } - - dom.unitList.appendChild(card); + const editBtn = document.createElement("button"); + editBtn.className = "secondary"; + editBtn.textContent = "Edit"; + editBtn.addEventListener("click", (event) => { + event.stopPropagation(); + openEditUnitModal(unit); }); + + const deleteBtn = document.createElement("button"); + deleteBtn.className = "danger"; + deleteBtn.textContent = "Delete"; + deleteBtn.addEventListener("click", (event) => { + event.stopPropagation(); + deleteUnit(unit.id).catch((error) => { + dom.statusText.textContent = error.message; + }); + }); + + actions.append(editBtn, deleteBtn); + + const isAutoOn = runtime?.auto_enabled; + const startBlocked = !isAutoOn && (runtime?.fault_locked || runtime?.manual_ack_required || runtime?.rem_local); + const autoBtn = document.createElement("button"); + autoBtn.className = isAutoOn ? "danger" : "secondary"; + autoBtn.textContent = isAutoOn ? "Stop Auto" : "Start Auto"; + autoBtn.disabled = startBlocked; + autoBtn.title = startBlocked + ? (runtime?.fault_locked ? "设备故障中,无法启动自动控制" + : runtime?.rem_local ? "设备处于本地模式(REM关),无法启动自动控制" + : "需人工确认故障后才可启动自动控制") + : (isAutoOn ? "停止自动控制" : "启动自动控制"); + autoBtn.addEventListener("click", (e) => { + e.stopPropagation(); + const url = `/api/control/unit/${unit.id}/${isAutoOn ? "stop-auto" : "start-auto"}`; + apiFetch(url, { method: "POST" }).then(() => loadUnits()).catch(() => {}); + }); + actions.append(autoBtn); + + if (runtime?.manual_ack_required) { + const ackBtn = document.createElement("button"); + ackBtn.className = "danger"; + ackBtn.textContent = "Ack Fault"; + ackBtn.title = "人工确认解除故障锁定"; + ackBtn.addEventListener("click", (e) => { + e.stopPropagation(); + apiFetch(`/api/control/unit/${unit.id}/ack-fault`, { method: "POST" }) + .then(() => loadUnits()).catch(() => {}); + }); + actions.append(ackBtn); + } + + return card; +} + +function renderToContainer(container, interactive) { + if (!container) return; + container.innerHTML = ""; + + if (!state.units.length) { + container.innerHTML = '
暂无控制单元
'; + return; + } + + state.units.forEach((unit) => { + container.appendChild(buildUnitCard(unit, interactive)); + }); +} + +export function renderUnits() { + renderToContainer(dom.unitList, true); + renderToContainer(dom.unitConfigList, false); } export async function loadUnits() {