Grotti 2.5.1: Druckbericht, Statistik, Spulenakte und Protokoll-Fixes.
This commit is contained in:
1 parent
b277ca48aa
commit
efd0801cd1
30 files changed
+3393
-178
No files matched your search
+229
-39
@@ -98,9 +98,19 @@ let wallSpools = [];
|
||||
let deskViewer = null;
|
||||
let deskCamFails = 0;
|
||||
let deskViewerFileId = null;
|
||||
let deskSyncGen = 0;
|
||||
let deskExcludeSelected = "";
|
||||
const wallPullTried = new Set();
|
||||
const toolpathCache = new Map();
|
||||
|
||||
/** Kurzes leeres filename vom Drucker nicht übernehmen — sonst springt der Name alle paar Sekunden. */
|
||||
function stickyFilename(printer, previous) {
|
||||
const next = (printer && printer.filename) || "";
|
||||
if (next) return next;
|
||||
const state = shownState(printer || {});
|
||||
if (previous && ["printing", "paused", "heating", "complete"].includes(state)) return previous;
|
||||
return "";
|
||||
}
|
||||
const cardNodes = new Map();
|
||||
const runningJobs = new Map();
|
||||
const printerCache = new Map();
|
||||
@@ -208,6 +218,14 @@ function setHtml(el, html) {
|
||||
}
|
||||
}
|
||||
|
||||
function setText(el, text) {
|
||||
if (!el) return;
|
||||
const next = text == null ? "" : String(text);
|
||||
if (el._text === next) return;
|
||||
el._text = next;
|
||||
el.textContent = next;
|
||||
}
|
||||
|
||||
function tempbarHtml(label, value, target, scale, iconName) {
|
||||
if (value == null) return "";
|
||||
const now = Math.round(value);
|
||||
@@ -265,12 +283,19 @@ function swatchesHtml(printer) {
|
||||
}).join("");
|
||||
}
|
||||
|
||||
function actionsHtml(state) {
|
||||
function etikettHtml(printer) {
|
||||
const runId = printer && printer.live_run_id;
|
||||
if (!runId) return "";
|
||||
return `<a class="ghost" href="/etikett/lauf/${runId}?mode=druck" target="_blank" rel="noopener">Etikett</a>`;
|
||||
}
|
||||
|
||||
function actionsHtml(state, printer) {
|
||||
const label = (state === "printing" || state === "paused") ? etikettHtml(printer) : "";
|
||||
if (state === "printing") {
|
||||
return `<button type="button" class="ghost" data-cmd="pause">${icon("pause")}Pause</button><button type="button" class="warn" data-cmd="abbrechen">${icon("stop")}Abbrechen</button>`;
|
||||
return `${label}<button type="button" class="ghost" data-cmd="pause">${icon("pause")}Pause</button><button type="button" class="warn" data-cmd="abbrechen">${icon("stop")}Abbrechen</button>`;
|
||||
}
|
||||
if (state === "paused") {
|
||||
return `<button type="button" data-cmd="fortsetzen">${icon("play")}Weiter</button><button type="button" class="warn" data-cmd="abbrechen">${icon("stop")}Abbrechen</button>`;
|
||||
return `${label}<button type="button" data-cmd="fortsetzen">${icon("play")}Weiter</button><button type="button" class="warn" data-cmd="abbrechen">${icon("stop")}Abbrechen</button>`;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
@@ -327,13 +352,107 @@ function stripsHtml(printer, state) {
|
||||
return bits.join("");
|
||||
}
|
||||
|
||||
function dryerLabel(status) {
|
||||
if (status === "drying") return "trocknet";
|
||||
if (status === "heater_err") return "Fehler";
|
||||
return "aus";
|
||||
}
|
||||
|
||||
function dryerDefaultTemp(dryer) {
|
||||
if (dryer.target > 0) return dryer.target;
|
||||
if (dryer.temp > 0) return dryer.temp;
|
||||
return 45;
|
||||
}
|
||||
|
||||
function aceSteerKey(printer) {
|
||||
const dryers = printer.dryers || [];
|
||||
const dryerPart = dryers.map((d) => String(d.id)).join(",");
|
||||
const slots = wallSpools
|
||||
.filter((s) => s.printer_host === printer.host && s.ace_slot)
|
||||
.map((s) => Number(s.ace_slot))
|
||||
.sort((a, b) => a - b)
|
||||
.join(",");
|
||||
return dryerPart + "|" + slots;
|
||||
}
|
||||
|
||||
function spoolHex(spool) {
|
||||
const colors = spool && spool.colors;
|
||||
if (Array.isArray(colors)) {
|
||||
for (const item of colors) {
|
||||
if (item && item.hex) return item.hex;
|
||||
if (typeof item === "string" && item.trim()) return item.trim();
|
||||
}
|
||||
}
|
||||
const label = spool && spool.color;
|
||||
if (typeof label === "string" && /^#?[0-9a-fA-F]{6}([0-9a-fA-F]{2})?$/.test(label.trim())) {
|
||||
return label.trim().startsWith("#") ? label.trim() : "#" + label.trim();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function aceSlotLabel(slot) {
|
||||
const n = Number(slot);
|
||||
if (n <= 4) return "ACE 1 · " + n;
|
||||
return "ACE 2 · " + (n - 4);
|
||||
}
|
||||
|
||||
function aceSteerHtml(printer) {
|
||||
const dryers = printer.dryers || [];
|
||||
if (!dryers.length) return "";
|
||||
const bits = [];
|
||||
dryers.forEach((dryer) => {
|
||||
const id = Number(dryer.id);
|
||||
const label = "ACE " + (id + 1);
|
||||
const status = dryerLabel(dryer.status);
|
||||
const temp = dryer.temp || 0;
|
||||
const target = dryer.target || 0;
|
||||
const remain = dryer.remain || 0;
|
||||
const dur = remain > 0 ? remain : 240;
|
||||
const hot = dryerDefaultTemp(dryer);
|
||||
const info = [
|
||||
status,
|
||||
temp || target ? temp + "°" + (target ? " / " + target + "°" : "") : "",
|
||||
remain > 0 ? "noch " + remain + " min" : "",
|
||||
].filter(Boolean).join(" · ");
|
||||
bits.push(`<div class="steer-ace" data-dryer-id="${id}">
|
||||
<div class="steer-ace-head"><b>${escapeHtml(label)} Trockner</b><span class="tiny" data-dryer-info>${escapeHtml(info)}</span></div>
|
||||
<div class="steer-row">
|
||||
<label>Temp °C <input type="number" data-steer="dryer-temp-${id}" min="35" max="65" value="${escapeHtml(String(hot))}"></label>
|
||||
<label>Dauer min <input type="number" data-steer="dryer-dur-${id}" min="1" max="720" value="${escapeHtml(String(dur))}"></label>
|
||||
<button type="button" data-steer-go="dryer_start" data-dryer-id="${id}">Start</button>
|
||||
<button type="button" class="ghost" data-steer-go="dryer_stop" data-dryer-id="${id}">Stopp</button>
|
||||
</div>
|
||||
</div>`);
|
||||
});
|
||||
const loaded = wallSpools
|
||||
.filter((s) => s.printer_host === printer.host && s.ace_slot)
|
||||
.slice()
|
||||
.sort((a, b) => Number(a.ace_slot) - Number(b.ace_slot));
|
||||
if (loaded.length) {
|
||||
bits.push(`<div class="steer-ace-slots"><div class="steer-ace-head"><b>Plätze</b><span class="tiny">Sorte und Farbe aus Grotti</span></div>`);
|
||||
loaded.forEach((spool) => {
|
||||
const slot = Number(spool.ace_slot);
|
||||
const hex = spoolHex(spool) || "#555";
|
||||
const kind = spool.material_type || "—";
|
||||
bits.push(`<div class="steer-slot-row">
|
||||
<span class="dot" style="background:${escapeHtml(hex)}"></span>
|
||||
<span class="grow"><b>${escapeHtml(aceSlotLabel(slot))}</b> · ${escapeHtml(kind)} · ${escapeHtml(spool.name || "")}</span>
|
||||
<button type="button" class="ghost" data-steer-go="slot_setzen" data-ace-slot="${slot}">an den Drucker</button>
|
||||
</div>`);
|
||||
});
|
||||
bits.push(`</div>`);
|
||||
}
|
||||
return bits.join("");
|
||||
}
|
||||
|
||||
function steerPanelHtml(printer) {
|
||||
const n = printer.nozzle_target != null ? Math.round(printer.nozzle_target) : "";
|
||||
const b = printer.bed_target != null ? Math.round(printer.bed_target) : "";
|
||||
const sp = typeof printer.speed_factor === "number" ? Math.round(printer.speed_factor * 100) : 100;
|
||||
const flow = typeof printer.extrude_factor === "number" ? Math.round(printer.extrude_factor * 100) : 100;
|
||||
const fan = typeof printer.fan === "number" ? Math.round(printer.fan * 100) : 0;
|
||||
return `<div class="steer" data-steer-host="${escapeHtml(printer.host)}">
|
||||
const aceKey = aceSteerKey(printer);
|
||||
return `<div class="steer" data-steer-host="${escapeHtml(printer.host)}" data-ace-key="${escapeHtml(aceKey)}">
|
||||
<div class="steer-row">
|
||||
<label>${icon("nozzle")} Düse <input type="number" data-steer="nozzle" data-steer-action="nozzle" min="0" max="350" value="${escapeHtml(String(n))}"></label>
|
||||
<label>${icon("bed")} Bett <input type="number" data-steer="bed" data-steer-action="bed" min="0" max="150" value="${escapeHtml(String(b))}"></label>
|
||||
@@ -345,6 +464,7 @@ function steerPanelHtml(printer) {
|
||||
<label>Flow % <input type="number" data-steer="flow" data-steer-action="flow" min="50" max="150" value="${escapeHtml(String(flow))}"></label>
|
||||
<label>${icon("fan")} Fan % <input type="number" data-steer="fan" data-steer-action="fan" min="0" max="100" value="${escapeHtml(String(fan))}"></label>
|
||||
</div>
|
||||
${aceSteerHtml(printer)}
|
||||
<p class="tiny">Enter im Feld setzt nur diesen Wert.</p>
|
||||
</div>`;
|
||||
}
|
||||
@@ -447,8 +567,9 @@ function anycubicTaskLine(printer) {
|
||||
return "<span>Anycubic <b>" + escapeHtml(bits.join(" · ")) + "</b></span>";
|
||||
}
|
||||
|
||||
function jobLineVisible(printer, state) {
|
||||
return !!printer.filename && state !== "standby" && state !== "offline";
|
||||
function jobLineVisible(printer, state, filename) {
|
||||
const name = filename != null ? filename : (printer && printer.filename);
|
||||
return !!name && state !== "standby" && state !== "offline";
|
||||
}
|
||||
|
||||
function shortName(name) {
|
||||
@@ -517,11 +638,13 @@ function patchSteerValues(root, printer) {
|
||||
if (steerHasFocus(root)) return;
|
||||
const steer = root.querySelector("[data-role=steer]");
|
||||
if (!steer) return;
|
||||
const nozzle = steer.querySelector('[data-steer="nozzle"]');
|
||||
const bed = steer.querySelector('[data-steer="bed"]');
|
||||
const speed = steer.querySelector('[data-steer="speed"]');
|
||||
const flow = steer.querySelector('[data-steer="flow"]');
|
||||
const fan = steer.querySelector('[data-steer="fan"]');
|
||||
const panel = steer.querySelector(".steer");
|
||||
if (!panel) return;
|
||||
const nozzle = panel.querySelector('[data-steer="nozzle"]');
|
||||
const bed = panel.querySelector('[data-steer="bed"]');
|
||||
const speed = panel.querySelector('[data-steer="speed"]');
|
||||
const flow = panel.querySelector('[data-steer="flow"]');
|
||||
const fan = panel.querySelector('[data-steer="fan"]');
|
||||
if (nozzle && document.activeElement !== nozzle) {
|
||||
nozzle.value = printer.nozzle_target != null ? Math.round(printer.nozzle_target) : "";
|
||||
}
|
||||
@@ -537,13 +660,39 @@ function patchSteerValues(root, printer) {
|
||||
if (fan && document.activeElement !== fan && typeof printer.fan === "number") {
|
||||
fan.value = Math.round(printer.fan * 100);
|
||||
}
|
||||
(printer.dryers || []).forEach((dryer) => {
|
||||
const id = Number(dryer.id);
|
||||
const box = panel.querySelector(`[data-dryer-id="${id}"]`);
|
||||
if (!box) return;
|
||||
const info = box.querySelector("[data-dryer-info]");
|
||||
if (info) {
|
||||
const status = dryerLabel(dryer.status);
|
||||
const temp = dryer.temp || 0;
|
||||
const target = dryer.target || 0;
|
||||
const remain = dryer.remain || 0;
|
||||
info.textContent = [
|
||||
status,
|
||||
temp || target ? temp + "°" + (target ? " / " + target + "°" : "") : "",
|
||||
remain > 0 ? "noch " + remain + " min" : "",
|
||||
].filter(Boolean).join(" · ");
|
||||
}
|
||||
const tempInput = box.querySelector(`[data-steer="dryer-temp-${id}"]`);
|
||||
const durInput = box.querySelector(`[data-steer="dryer-dur-${id}"]`);
|
||||
if (tempInput && document.activeElement !== tempInput && dryer.status === "drying" && dryer.target > 0) {
|
||||
tempInput.value = dryer.target;
|
||||
}
|
||||
if (durInput && document.activeElement !== durInput && dryer.remain > 0) {
|
||||
durInput.value = dryer.remain;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function patchCard(article, printer) {
|
||||
const state = shownState(printer);
|
||||
const clearNow = needsClear(printer);
|
||||
const shownFile = stickyFilename(printer, article.dataset.filename || "");
|
||||
article.dataset.state = state;
|
||||
article.dataset.filename = printer.filename || "";
|
||||
article.dataset.filename = shownFile;
|
||||
article.dataset.progress = String(printer.progress || 0);
|
||||
article.dataset.family = printer.family || "";
|
||||
article.dataset.needsClear = clearNow ? "1" : "";
|
||||
@@ -558,7 +707,7 @@ function patchCard(article, printer) {
|
||||
setHtml(role("stats"), statsHtml(printer, state));
|
||||
setHtml(role("temps"), tempbarsHtml(printer, state));
|
||||
const jobline = role("jobline");
|
||||
const jobVisible = jobLineVisible(printer, state);
|
||||
const jobVisible = jobLineVisible(printer, state, shownFile);
|
||||
const hasThumb = !!(jobVisible && printer.preview);
|
||||
if (jobline) {
|
||||
jobline.hidden = !jobVisible;
|
||||
@@ -590,13 +739,13 @@ function patchCard(article, printer) {
|
||||
}
|
||||
const job = role("job");
|
||||
if (job) {
|
||||
job.textContent = jobName(printer.filename) || "";
|
||||
job.title = printer.filename || "";
|
||||
setText(job, jobName(shownFile) || "");
|
||||
job.title = shownFile || "";
|
||||
}
|
||||
setHtml(role("swatches"), swatchesHtml(printer));
|
||||
setHtml(role("flow"), flowHtml(printer));
|
||||
setHtml(role("strips"), stripsHtml(printer, state));
|
||||
setHtml(role("controls"), actionsHtml(state));
|
||||
setHtml(role("controls"), actionsHtml(state, printer));
|
||||
}
|
||||
|
||||
function refreshDeskCamera(printer) {
|
||||
@@ -687,9 +836,10 @@ function patchDesk(printer) {
|
||||
if (!printer || printer.host !== deskHost) return;
|
||||
const state = shownState(printer);
|
||||
const prevFile = deskEl.dataset.filename || "";
|
||||
const fileChanged = prevFile !== (printer.filename || "");
|
||||
const shownFile = stickyFilename(printer, prevFile);
|
||||
const fileChanged = prevFile !== shownFile;
|
||||
deskEl.dataset.host = printer.host;
|
||||
deskEl.dataset.filename = printer.filename || "";
|
||||
deskEl.dataset.filename = shownFile;
|
||||
deskEl.dataset.progress = String(printer.progress || 0);
|
||||
deskEl.classList.remove(...DESK_STATES);
|
||||
deskEl.classList.add(state);
|
||||
@@ -712,11 +862,12 @@ function patchDesk(printer) {
|
||||
setHtml(role("temps"), tempbarsHtml(printer, state));
|
||||
|
||||
const jobline = role("jobline");
|
||||
if (jobline) jobline.hidden = !jobLineVisible(printer, state) && !printer.preview;
|
||||
const jobVisible = jobLineVisible(printer, state, shownFile);
|
||||
if (jobline) jobline.hidden = !jobVisible && !printer.preview;
|
||||
const job = role("job");
|
||||
if (job) {
|
||||
job.textContent = jobName(printer.filename) || (jobLineVisible(printer, state) ? "" : "Kein Auftrag");
|
||||
job.title = printer.filename || "";
|
||||
setText(job, jobName(shownFile) || (jobVisible ? "" : "Kein Auftrag"));
|
||||
job.title = shownFile || "";
|
||||
}
|
||||
const preview = role("preview");
|
||||
if (preview) {
|
||||
@@ -732,7 +883,7 @@ function patchDesk(printer) {
|
||||
setHtml(role("facts"), factsHtml(printer));
|
||||
setHtml(role("flow"), flowHtml(printer));
|
||||
setHtml(role("strips"), stripsHtml(printer, state));
|
||||
setHtml(role("controls"), actionsHtml(state));
|
||||
setHtml(role("controls"), actionsHtml(state, printer));
|
||||
const estop = role("estop");
|
||||
if (estop) {
|
||||
const showStop = state === "printing" || state === "paused" || state === "heating";
|
||||
@@ -745,10 +896,14 @@ function patchDesk(printer) {
|
||||
}
|
||||
|
||||
const steer = role("steer");
|
||||
if (steer && (!steer.querySelector(".steer") || fileChanged)) {
|
||||
setHtml(steer, steerPanelHtml(printer));
|
||||
} else {
|
||||
patchSteerValues(deskEl, printer);
|
||||
if (steer) {
|
||||
const panel = steer.querySelector(".steer");
|
||||
const nextKey = aceSteerKey(printer);
|
||||
if (!panel || fileChanged || panel.dataset.aceKey !== nextKey) {
|
||||
setHtml(steer, steerPanelHtml(printer));
|
||||
} else {
|
||||
patchSteerValues(deskEl, printer);
|
||||
}
|
||||
}
|
||||
setHtml(role("mesh"), heatMapHtml(printer));
|
||||
|
||||
@@ -761,8 +916,9 @@ async function syncDeskViewer(printer) {
|
||||
const canvas = deskEl.querySelector('[data-role="path-canvas"]');
|
||||
const caption = deskEl.querySelector('[data-role="path-caption"]');
|
||||
if (!canvas || !window.GrottiGcodeViewer || !window.THREE) return;
|
||||
const filename = printer.filename || "";
|
||||
const filename = stickyFilename(printer, deskEl.dataset.filename || "");
|
||||
const progress = Number(printer.progress || 0);
|
||||
const gen = ++deskSyncGen;
|
||||
if (!deskViewer) {
|
||||
deskViewer = GrottiGcodeViewer.create(canvas);
|
||||
deskViewer.setExcludeObjects({ objects: [], excluded: [], current: null }, {
|
||||
@@ -777,45 +933,55 @@ async function syncDeskViewer(printer) {
|
||||
let file = matchLibraryFile(filename);
|
||||
if (!file && filename && !wallPullTried.has(deskHost + "|" + filename)) {
|
||||
wallPullTried.add(deskHost + "|" + filename);
|
||||
if (caption) caption.textContent = "lade vom Drucker …";
|
||||
setText(caption, "lade vom Drucker …");
|
||||
try {
|
||||
const saved = await api("/dateien/von-drucker", {
|
||||
method: "POST",
|
||||
json: { host: deskHost, filename },
|
||||
});
|
||||
if (gen !== deskSyncGen) return;
|
||||
libraryFiles = await api("/dateien");
|
||||
if (gen !== deskSyncGen) return;
|
||||
file = saved || matchLibraryFile(filename);
|
||||
} catch (error) {
|
||||
/* bleibt leer */
|
||||
}
|
||||
}
|
||||
if (!file) {
|
||||
// Kurz leerer filename: Pfad und Caption nicht verwerfen (sonst Flackern alle 5 s).
|
||||
if (!filename && deskViewerFileId) return;
|
||||
deskViewer.setPath({ points: [] });
|
||||
deskViewerFileId = null;
|
||||
if (caption) caption.textContent = filename ? "Datei nicht in Grotti" : "kein Auftrag";
|
||||
setText(caption, filename ? "Datei nicht in Grotti" : "kein Auftrag");
|
||||
renderExcludePanel(printer);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
let data = toolpathCache.get(file.id);
|
||||
const needLoad = !data || data.version !== 8 || deskViewerFileId !== file.id;
|
||||
if (needLoad) {
|
||||
if (caption) caption.textContent = "wird gelesen …";
|
||||
const cachedOk = data && Number(data.version) === 8;
|
||||
const needFetch = !cachedOk;
|
||||
const needSetPath = deskViewerFileId !== file.id;
|
||||
if (needFetch) {
|
||||
if (needSetPath) setText(caption, "wird gelesen …");
|
||||
data = await api("/dateien/" + file.id + "/pfad?tp=8");
|
||||
if (gen !== deskSyncGen) return;
|
||||
toolpathCache.set(file.id, data);
|
||||
const sameFile = deskViewerFileId === file.id;
|
||||
deskViewer.setPath(data, { keepView: sameFile });
|
||||
}
|
||||
if (needFetch || needSetPath) {
|
||||
deskViewer.setPath(data, { keepView: deskViewerFileId === file.id });
|
||||
deskViewerFileId = file.id;
|
||||
}
|
||||
if (!(data.points && data.points.length)) {
|
||||
if (caption) caption.textContent = "leer in Datei";
|
||||
setText(caption, "leer in Datei");
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
// File-Id behalten — sonst setzt der nächste Poll die 3D-Ansicht zurück
|
||||
if (caption) caption.textContent = error.message || "fehlgeschlagen";
|
||||
if (gen !== deskSyncGen) return;
|
||||
setText(caption, error.message || "fehlgeschlagen");
|
||||
return;
|
||||
}
|
||||
if (gen !== deskSyncGen) return;
|
||||
deskViewer.setProgress(progress, {
|
||||
layer: printer.layer,
|
||||
layers: printer.layers,
|
||||
@@ -836,7 +1002,7 @@ async function syncDeskViewer(printer) {
|
||||
const layerTxt = printer.layers
|
||||
? " · Schicht " + (printer.layer || 0) + "/" + printer.layers
|
||||
: "";
|
||||
if (caption) caption.textContent = file.name + " · " + Math.round(progress * 100) + " %" + layerTxt;
|
||||
setText(caption, jobName(file.name) + " · " + Math.round(progress * 100) + " %" + layerTxt);
|
||||
}
|
||||
|
||||
function renderExcludePanel(printer) {
|
||||
@@ -1036,8 +1202,8 @@ async function refresh() {
|
||||
if (!libraryFiles.length) {
|
||||
try { libraryFiles = await api("/dateien"); } catch (error) { libraryFiles = []; }
|
||||
}
|
||||
if (!wallSpools.length) {
|
||||
try { wallSpools = await api("/spulen"); } catch (error) { wallSpools = []; }
|
||||
if (!wallSpools.length || deskHost) {
|
||||
try { wallSpools = await api("/spulen"); } catch (error) { /* behalten */ }
|
||||
}
|
||||
const all = await api("/drucker");
|
||||
const printers = sortPrinters(all.slice());
|
||||
@@ -1259,11 +1425,35 @@ async function handleWallClick(event) {
|
||||
method: "POST", json: { action: "fan", percent: 0 },
|
||||
});
|
||||
toast("Heizung und Lüfter aus.");
|
||||
} else if (go === "dryer_start") {
|
||||
const id = Number(steerBtn.dataset.dryerId);
|
||||
const temp = val("dryer-temp-" + id);
|
||||
const duration = val("dryer-dur-" + id);
|
||||
await api("/drucker/" + encodeURIComponent(host) + "/steuern", {
|
||||
method: "POST",
|
||||
json: { action: "dryer_start", id, temp, duration },
|
||||
});
|
||||
toast("Trockner gestartet.");
|
||||
} else if (go === "dryer_stop") {
|
||||
const id = Number(steerBtn.dataset.dryerId);
|
||||
await api("/drucker/" + encodeURIComponent(host) + "/steuern", {
|
||||
method: "POST",
|
||||
json: { action: "dryer_stop", id },
|
||||
});
|
||||
toast("Trockner gestoppt.");
|
||||
} else if (go === "slot_setzen") {
|
||||
const aceSlot = Number(steerBtn.dataset.aceSlot);
|
||||
await api("/drucker/" + encodeURIComponent(host) + "/steuern", {
|
||||
method: "POST",
|
||||
json: { action: "slot_setzen", ace_slot: aceSlot },
|
||||
});
|
||||
toast("Platz an den Drucker geschrieben.");
|
||||
}
|
||||
showNote("note", null);
|
||||
refresh();
|
||||
} catch (error) {
|
||||
showNote("note", error);
|
||||
toast(error.message, "bad");
|
||||
} finally {
|
||||
steerBtn.disabled = false;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user