Files
tech-service-portal/app/static/demo.js
T

82 lines
7.7 KiB
JavaScript

"use strict";
// ---------- Демонстрационный режим (персональный) ----------
function setSession(t) {
token = t.access_token; localStorage.setItem("token", token); localStorage.setItem("refresh", t.refresh_token); me = null;
}
function demoBanner() {
const back = sessionStorage.getItem("admin_tokens");
return h("div", { class: "demobar" },
h("span", {}, "🎭 ДЕМО-РЕЖИМ (только у вас) — данные тестовые. Остальные пользователи работают с рабочими данными."),
back ? h("button", { class: "sm", onclick: backToAdmin }, "↩ Вернуться в админа") :
h("button", { class: "sm", onclick: guard(async () => {
if (!confirm("Выйти из демо-режима и вернуться к рабочим данным?")) return;
const t = await api("POST", "/demo/leave"); setSession(t); location.hash = "#/"; route();
}) }, "Выйти из демо"),
me.is_admin ? h("a", { href: "#/demo" }, "Управление") : null);
}
function backToAdmin() {
const t = JSON.parse(sessionStorage.getItem("admin_tokens") || "null");
sessionStorage.removeItem("admin_tokens");
if (t) { setSession(t); location.hash = "#/demo"; route(); }
}
async function demoPage() {
if (!me.is_admin) throw new Error("Только для администратора");
const info = await api("GET", "/demo");
const reload = () => demoPage();
const switchTo = guard(async (path, body, hash = "#/demo") => {
const t = await api("POST", path, body);
sessionStorage.removeItem("admin_tokens"); setSession(t); location.hash = hash; route();
});
const q = h("input", { type: "search", placeholder: "🔍 Найти пользователя", style: "max-width:320px" });
const tbody = h("tbody");
const drawUsers = () => {
const s = q.value.trim().toLowerCase();
tbody.replaceChildren(...info.users.filter(u => !s || (u.full_name + " " + u.username).toLowerCase().includes(s)).map(u => h("tr", {},
h("td", {}, u.full_name || u.username, h("div", { class: "small muted" }, u.username, u.is_admin ? " · админ" : "")),
h("td", {}, u.in_demo ? h("span", { class: "badge b-in_progress" }, "в демо") : h("span", { class: "muted" }, "рабочие данные")),
h("td", { class: "row end" }, u.id === me.id && info.in_demo ? h("span", { class: "small muted" }, "это вы") :
h("button", { class: "sec sm", onclick: guard(async () => {
if (!u.in_demo && !confirm(`Перевести «${u.full_name || u.username}» в демо-режим? Он увидит тестовые данные до выхода из демо.`)) return;
await api("POST", `/demo/users/${u.id}`, { on: !u.in_demo }); toast(u.in_demo ? "Выведен из демо" : "Переведён в демо"); reload();
}) }, u.in_demo ? "Выключить демо" : "Включить демо")))));
};
q.oninput = drawUsers;
drawUsers();
const usersCard = h("div", { class: "card tablewrap" }, h("h2", { style: "margin-top:0" }, "Кто в демо-режиме"),
h("p", { class: "small muted" }, "Демо включается каждому отдельно. Если кто-то включил его случайно и не может выйти — выключите здесь: со следующего действия он вернётся к рабочим данным."),
q, h("table", { style: "margin-top:8px" }, tbody));
const head = [h("a", { href: "#/admin" }, "← Администрирование"), h("h1", {}, "Демонстрационный режим")];
const intro = h("ul", { class: "small" },
h("li", {}, h("b", {}, "Демо — персональное."), " Его видит только тот, кто в него вошёл; остальные в это время работают с рабочими данными как обычно."),
h("li", {}, "Тестовая база отдельная: рабочие данные не изменяются. Всё, что сделано в демо, исчезнет при удалении демо-данных."),
h("li", {}, "Выйти из демо можно кнопкой в жёлтой полосе вверху экрана."));
if (!info.active) {
$app.replaceChildren(...head, h("div", { class: "card" },
h("p", {}, "Тестовый набор: сотрудники, графики, оборудование, чек-листы, наряды и задания за 14 дней, карта завода, склады, инциденты."), intro,
h("button", { onclick: () => confirm("Войти в демонстрационный режим?\nДругие пользователи его не увидят.") && switchTo("/demo/enable", { confirm: true }, "#/") }, "Войти в демо-режим")), usersCard);
return;
}
const control = h("div", { class: "card" },
h("p", {}, `Демо-данные созданы: ${fmtFull(info.since)}. Сейчас в демо: ${info.users.filter(u => u.in_demo).length} чел.`), intro,
h("div", { class: "row" },
info.in_demo ? h("button", { onclick: () => confirm("Выйти из демо и вернуться к рабочим данным?") && switchTo("/demo/leave", undefined, "#/") }, "Выйти из демо")
: h("button", { onclick: () => switchTo("/demo/enable", { confirm: true }, "#/") }, "Войти в демо"),
h("button", { class: "sec", onclick: guard(async () => { if (confirm("Пересоздать тестовые данные? Все правки в демо будут потеряны.")) { await api("POST", "/demo/reset"); toast("Демо-данные пересозданы"); location.reload(); } }) }, "Пересоздать демо-данные"),
h("button", { class: "bad", onclick: guard(async () => { if (confirm("Удалить демо-данные? Все, кто в демо, вернутся к рабочим данным.")) { await api("POST", "/demo/destroy"); toast("Демо-данные удалены"); location.reload(); } }) }, "Удалить демо-данные")));
const accounts = info.accounts && info.in_demo ? h("div", { class: "card tablewrap" }, h("h2", { style: "margin-top:0" }, "Тестовые учётные записи"),
h("p", { class: "small muted" }, "Пароль у всех: ", h("b", {}, info.password), ". «Войти как» открывает систему под этим пользователем без пароля — удобно показывать роли. Вернуться можно кнопкой в жёлтой полосе вверху."),
h("table", {}, h("thead", {}, h("tr", {}, ...["Логин", "ФИО", "Роль", "Должность", "Смена", ""].map(t => h("th", {}, t)))),
h("tbody", {}, ...info.accounts.map(a => h("tr", {}, h("td", {}, a.username), h("td", {}, a.full_name), h("td", {}, a.role), h("td", {}, a.position || "—"),
h("td", {}, a.position ? (a.on_shift ? "на смене" : "не на смене") : "—"),
h("td", {}, h("button", { class: "sec sm", onclick: guard(async () => {
const keep = { access_token: token, refresh_token: localStorage.getItem("refresh") };
const t = await api("POST", "/demo/impersonate", { user_id: a.id });
sessionStorage.setItem("admin_tokens", JSON.stringify(keep)); setSession(t); location.hash = "#/"; route();
}) }, "Войти как")))))))
: h("p", { class: "small muted" }, `Тестовые учётные записи (пароль ${info.password}) видны, когда вы сами в демо.`);
$app.replaceChildren(...head, control, usersCard, accounts);
}