import { apiFetch } from "./api.js"; import { dom } from "./dom.js"; import { loadPoints, loadTree, renderSelectedNodes } from "./points.js"; import { state } from "./state.js"; export function renderSources() { dom.sourceList.innerHTML = ""; state.sources.forEach((source) => { const item = document.createElement("div"); item.className = `list-item ${state.selectedSourceId === source.id ? "selected" : ""}`; item.innerHTML = `
${source.name} ${source.is_connected ? "在线" : "离线"}
${source.endpoint}
`; item.addEventListener("click", () => { selectSource(source.id).catch((error) => { dom.statusText.textContent = error.message; }); }); const actions = document.createElement("div"); actions.className = "row"; const selectBtn = document.createElement("button"); selectBtn.textContent = "选入点位"; selectBtn.addEventListener("click", (event) => { event.stopPropagation(); selectSource(source.id) .then(() => { dom.pointModal.classList.remove("hidden"); return loadTree(); }) .catch((error) => { dom.statusText.textContent = error.message; }); }); const editBtn = document.createElement("button"); editBtn.className = "secondary"; editBtn.textContent = "编辑"; editBtn.addEventListener("click", (event) => { event.stopPropagation(); dom.sourceId.value = source.id; dom.sourceName.value = source.name || ""; dom.sourceEndpoint.value = source.endpoint || ""; dom.sourceEnabled.checked = !!source.enabled; dom.sourceModal.classList.remove("hidden"); }); const reconnectBtn = document.createElement("button"); reconnectBtn.className = "secondary"; reconnectBtn.textContent = "重连"; reconnectBtn.addEventListener("click", (event) => { event.stopPropagation(); reconnectSource(source.id, source.name).catch((error) => { dom.statusText.textContent = error.message; }); }); const deleteBtn = document.createElement("button"); deleteBtn.className = "danger"; deleteBtn.textContent = "删除"; deleteBtn.addEventListener("click", (event) => { event.stopPropagation(); deleteSource(source.id).catch((error) => { dom.statusText.textContent = error.message; }); }); actions.append(selectBtn, editBtn, reconnectBtn, deleteBtn); item.appendChild(actions); dom.sourceList.appendChild(item); }); } export async function loadSources() { state.sources = await apiFetch("/api/source"); renderSources(); } export async function selectSource(sourceId) { state.selectedSourceId = sourceId; state.selectedNodeIds.clear(); state.pointsPage = 1; renderSources(); renderSelectedNodes(); await loadPoints(); await loadTree(); } export async function saveSource(event) { event.preventDefault(); const payload = { name: dom.sourceName.value.trim(), endpoint: dom.sourceEndpoint.value.trim(), enabled: dom.sourceEnabled.checked, }; const id = dom.sourceId.value; await apiFetch(id ? `/api/source/${id}` : "/api/source", { method: id ? "PUT" : "POST", body: JSON.stringify(payload), }); dom.sourceModal.classList.add("hidden"); dom.sourceForm.reset(); await loadSources(); } export async function deleteSource(sourceId) { if (!window.confirm("确认删除该 Source?")) { return; } await apiFetch(`/api/source/${sourceId}`, { method: "DELETE" }); await loadSources(); } export async function reconnectSource(sourceId, name) { dom.statusText.textContent = `正在重连 ${name || "Source"}...`; await apiFetch(`/api/source/${sourceId}/reconnect`, { method: "POST" }); await loadSources(); dom.statusText.textContent = "Ready"; } export async function browseNodes() { if (!state.selectedSourceId) { throw new Error("请先选择数据源"); } await apiFetch(`/api/source/${state.selectedSourceId}/browse`, { method: "POST" }); await loadTree(); }