From 3f91dc91ec4da234f2021767cba59cfb990ff3b5 Mon Sep 17 00:00:00 2001 From: Danamir Date: Mon, 10 Nov 2025 08:45:25 +0300 Subject: [PATCH] feat(frontend): Vue (CDN) UI matching templates design; reuse /static CSS and Bootstrap; mount /static in FastAPI --- backend/main.py | 3 +- frontend/app.js | 111 +++++++++++++++++++------------------------- frontend/index.html | 98 +++++++++++++++++++++++++------------- 3 files changed, 115 insertions(+), 97 deletions(-) diff --git a/backend/main.py b/backend/main.py index 3c90fb5..c28c42b 100644 --- a/backend/main.py +++ b/backend/main.py @@ -30,7 +30,8 @@ def ping(): return {"message": "pong"} -# Serve static frontend +# Serve static assets and frontend +app.mount("/static", StaticFiles(directory="static"), name="static") app.mount("/app", StaticFiles(directory="frontend", html=True), name="frontend") @app.get("/") diff --git a/frontend/app.js b/frontend/app.js index ab3e6e0..34fb61f 100644 --- a/frontend/app.js +++ b/frontend/app.js @@ -1,3 +1,5 @@ +const { createApp } = Vue; + const api = { auds: "/auditories/", oboruds: (audId) => `/oboruds/?aud_id=${encodeURIComponent(audId)}`, @@ -9,68 +11,49 @@ async function fetchJSON(url) { return res.json(); } -function setStatus(msg, type = "info") { - const el = document.getElementById("status"); - el.textContent = msg || ""; - el.className = `status ${type}`; -} - -async function loadAuditories() { - setStatus("Загрузка аудиторий…"); - try { - const data = await fetchJSON(api.auds); - const select = document.getElementById("aud-select"); - select.innerHTML = ''; - data.forEach((a) => { - const opt = document.createElement("option"); - opt.value = a.id; - opt.textContent = `${a.id} — ${a.audnazvanie}`; - select.appendChild(opt); - }); - setStatus(""); - } catch (e) { - console.error(e); - setStatus("Не удалось загрузить аудитории", "error"); +createApp({ + data() { + return { + view: 'byAud', + auditories: [], + selectedAudId: '', + oboruds: [], + status: '', + error: '', + }; + }, + methods: { + async loadAuditories() { + this.status = 'Загрузка аудиторий…'; + this.error = ''; + try { + this.auditories = await fetchJSON(api.auds); + this.status = ''; + } catch (e) { + console.error(e); + this.error = 'Не удалось загрузить аудитории'; + this.status = ''; + } + }, + async loadOboruds() { + if (!this.selectedAudId) { + this.error = ''; + this.status = 'Выберите аудиторию'; + return; + } + this.status = 'Загрузка оборудования…'; + this.error = ''; + try { + this.oboruds = await fetchJSON(api.oboruds(this.selectedAudId)); + this.status = ''; + } catch (e) { + console.error(e); + this.error = 'Не удалось загрузить оборудование'; + this.status = ''; + } + }, + }, + mounted() { + this.loadAuditories(); } -} - -function renderOboruds(items) { - const tbody = document.querySelector("#ob-table tbody"); - tbody.innerHTML = ""; - items.forEach((it) => { - const tr = document.createElement("tr"); - tr.innerHTML = ` - ${it.id} - ${it.invNumber ?? ""} - ${it.nazvanie ?? ""} - ${it.raspologenie ?? ""} - ${it.kolichestvo ?? ""} - ${it.type?.name ?? ""} - `; - tbody.appendChild(tr); - }); -} - -async function loadOborudsForSelected() { - const select = document.getElementById("aud-select"); - const audId = select.value; - if (!audId) { - setStatus("Выберите аудиторию", "warn"); - return; - } - setStatus("Загрузка оборудования…"); - try { - const data = await fetchJSON(api.oboruds(audId)); - renderOboruds(data); - setStatus(""); - } catch (e) { - console.error(e); - setStatus("Не удалось загрузить оборудование", "error"); - } -} - -document.addEventListener("DOMContentLoaded", () => { - document.getElementById("load-btn").addEventListener("click", loadOborudsForSelected); - loadAuditories(); -}); - +}).mount('#app'); diff --git a/frontend/index.html b/frontend/index.html index d290d84..f09791f 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -3,45 +3,79 @@ - ASU Inventory — Фронт - + АСУ Инвентаризация + +
-

ASU Inventory

- +

+ АСУ Инвентаризация +

+

Учет оборудования. Демоверсия

-
-
-

Оборудование по аудитории

-
- - - +
+
-
+ + +
+
+
+
+

Оборудование по аудитории

+
+ + + +
+
{{ status }}
+
+ + + + + + + + + + + + + + + + + + + + + +
IDИнв. номерНазваниеРасположениеКол-воТип
{{ it.id }}{{ it.invNumber ?? '' }}{{ it.nazvanie ?? '' }}{{ it.raspologenie ?? '' }}{{ it.kolichestvo ?? '' }}{{ it.type?.name ?? '' }}
+
+
+
+
+
+ + -