140 lines
4.1 KiB
JavaScript
140 lines
4.1 KiB
JavaScript
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 = `
|
||
<div class="row">
|
||
<strong>${source.name}</strong>
|
||
<span class="badge ${source.is_connected ? "" : "offline"}">${source.is_connected ? "在线" : "离线"}</span>
|
||
</div>
|
||
<div class="muted">${source.endpoint}</div>
|
||
`;
|
||
|
||
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();
|
||
}
|