Add function Language
Some checks failed
Test / test (push) Has been cancelled

This commit is contained in:
2026-06-16 16:44:04 +07:00
parent 1156e1ab29
commit a2e87aeb29
11 changed files with 1790 additions and 474 deletions

View File

@@ -3,6 +3,7 @@
const COIL_MAX = 2000;
const el = (id) => document.getElementById(id);
const t = (key, vars) => window.I18n?.t(key, vars) ?? key;
const triggerListEl = el("integrationTriggerList");
const triggerEmptyEl = el("integrationTriggerEmpty");
const coilGridEl = el("integrationCoilGrid");
@@ -72,7 +73,7 @@
const data = await apiJson("/api/fleet/robots");
store.robots = Array.isArray(data) ? data : [];
} catch {
store.robots = [{ id: "default", name: "Robot chính" }];
store.robots = [{ id: "default", name: t("integrations.defaultRobot") }];
}
}
@@ -96,7 +97,7 @@
if (!store.missions.length) {
const opt = document.createElement("option");
opt.value = "";
opt.textContent = "— Chưa có mission —";
opt.textContent = t("integrations.noMissions");
selectEl.appendChild(opt);
return;
}
@@ -122,7 +123,7 @@
if (!store.robots.length) {
const opt = document.createElement("option");
opt.value = "default";
opt.textContent = "Robot chính";
opt.textContent = t("integrations.defaultRobot");
opt.selected = selected === "default";
selectEl.appendChild(opt);
}
@@ -133,24 +134,24 @@
triggerListEl.innerHTML = "";
if (triggerEmptyEl) triggerEmptyEl.hidden = store.triggers.length > 0;
store.triggers.forEach((t) => {
store.triggers.forEach((trigger) => {
const row = document.createElement("div");
row.className = "missionListItem integrationRow";
const coil = t.coil_id;
const coil = trigger.coil_id;
const on = store.coils[String(coil)] === true;
row.innerHTML = `
<div>
<div class="missionListItemTitle">${escapeHtml(t.name)}</div>
<div class="missionListItemTitle">${escapeHtml(trigger.name)}</div>
<div class="missionListItemMeta">
Coil <span class="mono">${coil}</span>
${escapeHtml(missionName(t.mission_id))}
· ${t.enabled === false ? "Tắt" : "Bật"}
· coil hiện tại: <span class="mono">${on ? "ON" : "OFF"}</span>
${escapeHtml(missionName(trigger.mission_id))}
· ${trigger.enabled === false ? t("common.disabled") : t("common.enabled")}
· ${t("integrations.coilState", { state: on ? "ON" : "OFF" })}
</div>
</div>
<div class="missionListItemActions">
<button type="button" class="btn subtle" data-fire-coil="${coil}">Kích hoạt</button>
<button type="button" class="btn subtle danger" data-delete-trigger="${escapeHtml(t.id)}">Xóa</button>
<button type="button" class="btn subtle" data-fire-coil="${coil}">${t("integrations.fireTrigger")}</button>
<button type="button" class="btn subtle danger" data-delete-trigger="${escapeHtml(trigger.id)}">${t("common.delete")}</button>
</div>`;
triggerListEl.appendChild(row);
});
@@ -160,10 +161,10 @@
if (!coilGridEl) return;
const assigned = new Map(store.triggers.map((t) => [t.coil_id, t]));
const chips = [];
assigned.forEach((t, coilId) => {
assigned.forEach((trigger, coilId) => {
const on = store.coils[String(coilId)] === true;
chips.push(
`<button type="button" class="integrationCoilChip${on ? " on" : ""}" data-fire-coil="${coilId}" title="${escapeHtml(t.name)}">
`<button type="button" class="integrationCoilChip${on ? " on" : ""}" data-fire-coil="${coilId}" title="${escapeHtml(trigger.name)}">
${coilId}
</button>`
);
@@ -171,11 +172,11 @@
coilGridEl.innerHTML =
chips.length > 0
? chips.join("")
: `<span class="mutedNote">Chưa gán coil. Thêm trigger bên trên (10012000).</span>`;
: `<span class="mutedNote">${t("integrations.coilsEmpty")}</span>`;
}
function formatScheduleTime(s) {
if (!s.start_at) return s.start_mode === "scheduled" ? "—" : "Ngay (asap)";
if (!s.start_at) return s.start_mode === "scheduled" ? "—" : t("integrations.dialog.schedule.asap");
try {
return new Date(s.start_at).toLocaleString("vi-VN");
} catch {
@@ -204,7 +205,7 @@
</div>
</div>
<div class="missionListItemActions">
<button type="button" class="btn subtle" data-run-schedule="${escapeHtml(s.id)}">Chạy ngay</button>
<button type="button" class="btn subtle" data-run-schedule="${escapeHtml(s.id)}">${t("integrations.schedule.runNow")}</button>
<button type="button" class="btn subtle danger" data-delete-schedule="${escapeHtml(s.id)}">Xóa</button>
</div>`;
scheduleListEl.appendChild(row);
@@ -316,7 +317,7 @@
}
async function deleteTrigger(id) {
if (!confirm("Xóa trigger Modbus này?")) return;
if (!confirm(t("integrations.confirm.deleteTrigger"))) return;
try {
await apiJson(`/api/triggers/${id}`, { method: "DELETE" });
await refreshAll();
@@ -326,7 +327,7 @@
}
async function deleteSchedule(id) {
if (!confirm("Xóa lịch fleet này?")) return;
if (!confirm(t("integrations.confirm.deleteSchedule"))) return;
try {
await apiJson(`/api/fleet/schedules/${id}`, { method: "DELETE" });
await refreshAll();
@@ -446,6 +447,12 @@
function boot() {
init();
}
window.addEventListener("lm:locale-change", () => {
renderTriggers();
renderCoilGrid();
renderSchedules();
});
if (window.AuthApp?.isReady()) boot();
else window.addEventListener("lm:auth-ready", boot, { once: true });
})();