import { stationApi } from "./api.js";
import { el, escapeHtml, setBanner } from "./dom.js";
const STATION_TYPES = [
"load",
"dry_in",
"dry_step",
"dry_out",
"fire_in",
"fire_step",
"fire_out",
"transfer",
"unload",
"return",
];
const SIGNAL_ROLES = ["presence", "vacancy", "arrived", "allow_in", "done", "fault"];
const stations = new Map();
const expanded = new Set();
let stationDetails = new Map(); // station_id -> { signals: [...] }
let editing = null; // station_id being edited inline
let creating = false;
function renderForm(initial) {
const data = initial || {};
return `
`;
}
function renderSignalForm() {
return `
`;
}
function renderSignals(signals) {
if (!signals?.length) {
return `未绑定信号
`;
}
return `
| 角色 | Point | 推导 | 取反 | |
${signals
.map(
(sig) => `
| ${escapeHtml(sig.signal_role)} |
${escapeHtml(sig.point_id || "")} |
${escapeHtml(sig.derived_from_role || "")} |
${sig.invert_value ? "是" : "否"} |
|
`,
)
.join("")}
`;
}
function renderRow(station) {
const isExpanded = expanded.has(station.id);
const isEditing = editing === station.id;
const detail = stationDetails.get(station.id);
return `
${escapeHtml(station.code)}
${escapeHtml(station.name)}
${station.line_code ? `${escapeHtml(station.line_code)}` : ""}
${escapeHtml(station.station_type)}
${station.enabled ? "" : `已禁用`}
${isEditing ? `${renderForm(station)}
` : ""}
${
isExpanded
? `
${renderSignals(detail?.signals)}
${renderSignalForm()}
`
: ""
}
`;
}
function renderAll() {
const root = el("stationList");
if (!root) return;
const list = Array.from(stations.values()).sort((a, b) => a.code.localeCompare(b.code));
root.innerHTML = `
${creating ? `${renderForm({})}
` : ""}
${list.length === 0 ? `尚无工位
` : list.map(renderRow).join("")}
`;
}
function formToPayload(form) {
const data = Object.fromEntries(new FormData(form));
const payload = {
code: data.code?.trim(),
name: data.name?.trim(),
station_type: data.station_type,
enabled: form.elements.enabled.checked,
};
if (data.line_code) payload.line_code = data.line_code.trim();
if (data.segment_code) payload.segment_code = data.segment_code.trim();
if (data.description) payload.description = data.description;
return payload;
}
function signalFormToPayload(form) {
const data = Object.fromEntries(new FormData(form));
const payload = { signal_role: data.signal_role };
if (data.point_id) payload.point_id = data.point_id.trim();
if (data.derived_from_role) payload.derived_from_role = data.derived_from_role;
payload.invert_value = form.elements.invert_value.checked;
return payload;
}
async function refreshDetail(stationId) {
try {
const detail = await stationApi.detail(stationId);
stationDetails.set(stationId, { signals: detail.signals || [] });
} catch (err) {
setBanner(el("stationList"), err.message || String(err), "error");
}
}
async function handleClick(event) {
const button = event.target.closest("button[data-action]");
if (!button) return;
const action = button.dataset.action;
const row = event.target.closest(".config-row");
const stationId = row?.dataset?.stationId;
switch (action) {
case "cancel-form":
creating = false;
editing = null;
return renderAll();
case "toggle":
if (!stationId) return;
if (expanded.has(stationId)) {
expanded.delete(stationId);
} else {
expanded.add(stationId);
await refreshDetail(stationId);
}
return renderAll();
case "edit":
editing = editing === stationId ? null : stationId;
return renderAll();
case "delete":
if (!stationId) return;
if (!window.confirm("确认删除该工位?此操作不可恢复。")) return;
try {
await stationApi.remove(stationId);
stations.delete(stationId);
expanded.delete(stationId);
if (editing === stationId) editing = null;
renderAll();
setBanner(el("stationList"), "工位已删除", "info");
} catch (err) {
setBanner(el("stationList"), err.message || String(err), "error");
}
return;
case "delete-signal": {
if (!stationId) return;
const role = button.dataset.role;
try {
await stationApi.deleteSignal(stationId, role);
await refreshDetail(stationId);
renderAll();
setBanner(el("stationList"), `已解除 ${role} 绑定`, "info");
} catch (err) {
setBanner(el("stationList"), err.message || String(err), "error");
}
return;
}
default:
return;
}
}
async function handleSubmit(event) {
const form = event.target.closest("form[data-form]");
if (!form) return;
event.preventDefault();
const row = form.closest(".config-row");
const stationId = row?.dataset?.stationId;
if (form.dataset.form === "station") {
const payload = formToPayload(form);
try {
if (stationId && editing === stationId) {
await stationApi.update(stationId, payload);
setBanner(el("stationList"), "工位已更新", "info");
} else {
await stationApi.create(payload);
setBanner(el("stationList"), "工位已创建", "info");
}
creating = false;
editing = null;
await loadStations();
} catch (err) {
setBanner(el("stationList"), err.message || String(err), "error");
}
return;
}
if (form.dataset.form === "signal") {
if (!stationId) return;
const payload = signalFormToPayload(form);
try {
await stationApi.upsertSignal(stationId, payload);
await refreshDetail(stationId);
renderAll();
setBanner(el("stationList"), "信号绑定已保存", "info");
} catch (err) {
setBanner(el("stationList"), err.message || String(err), "error");
}
}
}
export async function loadStations() {
try {
const rows = await stationApi.list();
stations.clear();
rows.forEach((s) => stations.set(s.id, s));
renderAll();
} catch (err) {
setBanner(el("stationList"), err.message || String(err), "error");
}
}
export function bindStationEvents() {
const root = el("stationList");
if (root) {
root.addEventListener("click", handleClick);
root.addEventListener("submit", handleSubmit);
}
const addBtn = el("addStationBtn");
if (addBtn) {
addBtn.addEventListener("click", () => {
creating = !creating;
editing = null;
renderAll();
});
}
const refreshBtn = el("refreshStationsBtn");
if (refreshBtn) refreshBtn.addEventListener("click", () => loadStations());
}