199 lines
6.1 KiB
JavaScript
199 lines
6.1 KiB
JavaScript
import { apiFetch } from "./api.js";
|
|
import { dom } from "./dom.js";
|
|
import { loadPoints, openPointBinding } from "./points.js";
|
|
import { state } from "./state.js";
|
|
|
|
function equipmentOf(item) {
|
|
return item && item.equipment ? item.equipment : item;
|
|
}
|
|
|
|
export function renderEquipmentOptions(selected = "") {
|
|
const options = ['<option value="">未绑定</option>'];
|
|
state.equipments.forEach((item) => {
|
|
const equipment = equipmentOf(item);
|
|
const isSelected = equipment.id === selected ? "selected" : "";
|
|
options.push(
|
|
`<option value="${equipment.id}" ${isSelected}>${equipment.code} / ${equipment.name}</option>`,
|
|
);
|
|
});
|
|
dom.bindingEquipmentId.innerHTML = options.join("");
|
|
}
|
|
|
|
export function resetEquipmentForm() {
|
|
state.selectedEquipmentId = null;
|
|
dom.equipmentForm.reset();
|
|
dom.equipmentId.value = "";
|
|
dom.equipmentPointList.innerHTML =
|
|
'<tr><td colspan="3" class="empty-state">请选择设备</td></tr>';
|
|
}
|
|
|
|
export function renderEquipments() {
|
|
dom.equipmentList.innerHTML = "";
|
|
|
|
if (!state.equipments.length) {
|
|
dom.equipmentList.innerHTML = '<div class="list-item"><div class="muted">暂无设备</div></div>';
|
|
dom.equipmentPointList.innerHTML =
|
|
'<tr><td colspan="3" class="empty-state">暂无设备点位</td></tr>';
|
|
return;
|
|
}
|
|
|
|
state.equipments.forEach((item) => {
|
|
const equipment = equipmentOf(item);
|
|
const box = document.createElement("div");
|
|
box.className = `list-item ${state.selectedEquipmentId === equipment.id ? "selected" : ""}`;
|
|
box.innerHTML = `
|
|
<div class="row">
|
|
<strong>${equipment.code}</strong>
|
|
<span class="badge">${item.point_count ?? 0} pts</span>
|
|
</div>
|
|
<div>${equipment.name}</div>
|
|
<div class="muted">${equipment.kind || "未设置类型"}</div>
|
|
`;
|
|
|
|
box.addEventListener("click", () => {
|
|
state.selectedEquipmentId = equipment.id;
|
|
dom.equipmentId.value = equipment.id || "";
|
|
dom.equipmentCode.value = equipment.code || "";
|
|
dom.equipmentName.value = equipment.name || "";
|
|
dom.equipmentKind.value = equipment.kind || "";
|
|
dom.equipmentDescription.value = equipment.description || "";
|
|
renderEquipments();
|
|
loadEquipmentPoints(equipment.id).catch((error) => {
|
|
dom.statusText.textContent = error.message;
|
|
});
|
|
});
|
|
|
|
const actions = document.createElement("div");
|
|
actions.className = "row";
|
|
|
|
const deleteBtn = document.createElement("button");
|
|
deleteBtn.className = "danger";
|
|
deleteBtn.textContent = "删除";
|
|
deleteBtn.addEventListener("click", (event) => {
|
|
event.stopPropagation();
|
|
deleteEquipment(equipment.id).catch((error) => {
|
|
dom.statusText.textContent = error.message;
|
|
});
|
|
});
|
|
actions.appendChild(deleteBtn);
|
|
box.appendChild(actions);
|
|
dom.equipmentList.appendChild(box);
|
|
});
|
|
}
|
|
|
|
export async function loadEquipments() {
|
|
const keyword = dom.equipmentKeyword.value.trim();
|
|
const query = keyword
|
|
? `?page=1&page_size=-1&keyword=${encodeURIComponent(keyword)}`
|
|
: "?page=1&page_size=-1";
|
|
const data = await apiFetch(`/api/equipment${query}`);
|
|
state.equipments = data.data || [];
|
|
state.equipmentMap = new Map(
|
|
state.equipments.map((item) => {
|
|
const equipment = equipmentOf(item);
|
|
return [equipment.id, equipment];
|
|
}),
|
|
);
|
|
renderEquipmentOptions();
|
|
renderEquipments();
|
|
|
|
if (state.selectedEquipmentId && state.equipmentMap.has(state.selectedEquipmentId)) {
|
|
await loadEquipmentPoints(state.selectedEquipmentId);
|
|
}
|
|
}
|
|
|
|
export async function loadEquipmentPoints(equipmentId) {
|
|
const points = await apiFetch(`/api/equipment/${equipmentId}/points`);
|
|
dom.equipmentPointList.innerHTML = "";
|
|
|
|
if (!points.length) {
|
|
dom.equipmentPointList.innerHTML =
|
|
'<tr><td colspan="3" class="empty-state">该设备下暂无点位</td></tr>';
|
|
return;
|
|
}
|
|
|
|
points.forEach((point) => {
|
|
const tr = document.createElement("tr");
|
|
tr.innerHTML = `
|
|
<td>
|
|
<div class="point-name">${point.name}</div>
|
|
<div class="point-id">${point.node_id}</div>
|
|
</td>
|
|
<td>${point.signal_role || "--"}</td>
|
|
<td></td>
|
|
`;
|
|
|
|
const actionCell = tr.lastElementChild;
|
|
|
|
const editBtn = document.createElement("button");
|
|
editBtn.className = "secondary";
|
|
editBtn.textContent = "编辑绑定";
|
|
editBtn.addEventListener("click", () => openPointBinding(point));
|
|
|
|
const clearBtn = document.createElement("button");
|
|
clearBtn.className = "secondary";
|
|
clearBtn.textContent = "解绑";
|
|
clearBtn.addEventListener("click", () => {
|
|
clearPointBinding(point.id).catch((error) => {
|
|
dom.statusText.textContent = error.message;
|
|
});
|
|
});
|
|
|
|
actionCell.append(editBtn, clearBtn);
|
|
dom.equipmentPointList.appendChild(tr);
|
|
});
|
|
}
|
|
|
|
export async function saveEquipment(event) {
|
|
event.preventDefault();
|
|
|
|
const payload = {
|
|
code: dom.equipmentCode.value.trim(),
|
|
name: dom.equipmentName.value.trim(),
|
|
kind: dom.equipmentKind.value.trim() || null,
|
|
description: dom.equipmentDescription.value.trim() || null,
|
|
};
|
|
|
|
const id = dom.equipmentId.value;
|
|
await apiFetch(id ? `/api/equipment/${id}` : "/api/equipment", {
|
|
method: id ? "PUT" : "POST",
|
|
body: JSON.stringify(payload),
|
|
});
|
|
|
|
await loadEquipments();
|
|
await loadPoints();
|
|
}
|
|
|
|
export async function deleteEquipment(equipmentId) {
|
|
if (!window.confirm("确认删除该设备?")) {
|
|
return;
|
|
}
|
|
|
|
await apiFetch(`/api/equipment/${equipmentId}`, { method: "DELETE" });
|
|
resetEquipmentForm();
|
|
await loadEquipments();
|
|
await loadPoints();
|
|
}
|
|
|
|
export function openEquipmentDrawer() {
|
|
dom.equipmentDrawer.classList.remove("hidden");
|
|
loadEquipments().catch((error) => {
|
|
dom.statusText.textContent = error.message;
|
|
});
|
|
}
|
|
|
|
export function closeEquipmentDrawer() {
|
|
dom.equipmentDrawer.classList.add("hidden");
|
|
}
|
|
|
|
export async function clearPointBinding(pointId = dom.bindingPointId.value) {
|
|
await apiFetch(`/api/point/${pointId}`, {
|
|
method: "PUT",
|
|
body: JSON.stringify({ equipment_id: null, signal_role: null }),
|
|
});
|
|
|
|
dom.pointBindingModal.classList.add("hidden");
|
|
await loadEquipments();
|
|
await loadPoints();
|
|
}
|