import { apiFetch } from "./api.js";
import { openChart } from "./chart.js";
import { dom } from "./dom.js";
import { loadEquipments, renderEquipmentOptions } from "./equipment.js";
import { state } from "./state.js";
export function formatValue(monitor) {
if (!monitor) {
return "--";
}
if (monitor.value_text) {
return monitor.value_text;
}
if (monitor.value === null || monitor.value === undefined) {
return "--";
}
return typeof monitor.value === "string" ? monitor.value : JSON.stringify(monitor.value);
}
export function renderSelectedNodes() {
dom.selectedCount.textContent = `已选中 ${state.selectedNodeIds.size} 个节点`;
}
function renderNode(node) {
const details = document.createElement("details");
const summary = document.createElement("summary");
if (node.children?.length) {
summary.classList.add("has-children");
}
const checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.checked = state.selectedNodeIds.has(node.id);
checkbox.addEventListener("change", () => {
if (checkbox.checked) {
state.selectedNodeIds.add(node.id);
} else {
state.selectedNodeIds.delete(node.id);
}
renderSelectedNodes();
});
const label = document.createElement("span");
label.className = "node-label";
label.textContent = `${node.display_name || node.browse_name} (${node.node_class})`;
summary.append(checkbox, label);
details.appendChild(summary);
(node.children || []).forEach((child) => {
details.appendChild(renderNode(child));
});
return details;
}
export async function loadTree() {
if (!state.selectedSourceId) {
dom.nodeTree.innerHTML = '
请选择数据源
';
return;
}
const data = await apiFetch(`/api/source/${state.selectedSourceId}/node-tree`);
dom.nodeTree.innerHTML = "";
(data || []).forEach((node) => dom.nodeTree.appendChild(renderNode(node)));
}
export async function createPoints() {
if (!state.selectedNodeIds.size) {
return;
}
await apiFetch("/api/point/batch", {
method: "POST",
body: JSON.stringify({ node_ids: Array.from(state.selectedNodeIds) }),
});
state.selectedNodeIds.clear();
renderSelectedNodes();
dom.pointModal.classList.add("hidden");
await loadPoints();
}
export async function loadPoints() {
const sourceQuery = state.selectedSourceId ? `&source_id=${state.selectedSourceId}` : "";
const data = await apiFetch(
`/api/point?page=${state.pointsPage}&page_size=${state.pointsPageSize}${sourceQuery}`,
);
const items = data.data || [];
state.pointsTotal = typeof data.total === "number" ? data.total : items.length;
state.pointEls.clear();
dom.pointList.innerHTML = "";
if (!items.length) {
dom.pointList.innerHTML = '| 暂无点位 |
';
dom.pointsPageInfo.textContent = `${state.pointsPage} / 1`;
return;
}
items.forEach((item) => {
const point = item.point || item;
const monitor = item.point_monitor || null;
const equipment = point.equipment_id ? state.equipmentMap.get(point.equipment_id) : null;
const tr = document.createElement("tr");
tr.addEventListener("click", () => {
openChart(point.id, point.name).catch((error) => {
dom.statusText.textContent = error.message;
});
});
tr.innerHTML = `
${point.name}
${point.node_id}
|
${formatValue(monitor)} |
${(monitor?.quality || "unknown").toUpperCase()} |
|
${monitor?.timestamp || "--"} |
|
`;
const actionCell = tr.lastElementChild;
const bindBtn = document.createElement("button");
bindBtn.className = "secondary";
bindBtn.textContent = "绑定";
bindBtn.addEventListener("click", (event) => {
event.stopPropagation();
openPointBinding(point);
});
const deleteBtn = document.createElement("button");
deleteBtn.className = "danger";
deleteBtn.textContent = "删除";
deleteBtn.addEventListener("click", (event) => {
event.stopPropagation();
deletePoint(point.id).catch((error) => {
dom.statusText.textContent = error.message;
});
});
actionCell.append(bindBtn, deleteBtn);
dom.pointList.appendChild(tr);
state.pointEls.set(point.id, {
row: tr,
value: tr.querySelector(".point-value"),
quality: tr.querySelector(".badge"),
time: tr.querySelector("td:nth-child(5) .muted"),
});
});
const totalPages = Math.max(1, Math.ceil(state.pointsTotal / state.pointsPageSize));
dom.pointsPageInfo.textContent = `${state.pointsPage} / ${totalPages}`;
}
export function openPointBinding(point) {
dom.bindingPointId.value = point.id;
dom.bindingPointName.value = point.name || "";
dom.bindingSignalRole.value = point.signal_role || "";
renderEquipmentOptions(point.equipment_id || "");
dom.pointBindingModal.classList.remove("hidden");
}
export async function savePointBinding(event) {
event.preventDefault();
await apiFetch(`/api/point/${dom.bindingPointId.value}`, {
method: "PUT",
body: JSON.stringify({
equipment_id: dom.bindingEquipmentId.value || null,
signal_role: dom.bindingSignalRole.value.trim() || null,
}),
});
dom.pointBindingModal.classList.add("hidden");
await loadEquipments();
await loadPoints();
}
export async function deletePoint(pointId) {
if (!window.confirm("确认删除该点位?")) {
return;
}
await apiFetch(`/api/point/${pointId}`, { method: "DELETE" });
await loadPoints();
}