diff --git a/data.json b/data.json new file mode 100644 index 0000000..e46cf4b --- /dev/null +++ b/data.json @@ -0,0 +1,8 @@ +{ + "items": [ + { "id": 1, "title": "Заказ #001", "client": "Иванов А.", "amount": 15000, "status": "active", "createdAt": "2026-08-25" }, + { "id": 2, "title": "Заказ #002", "client": "Петрова Б.", "amount": 28000, "status": "completed", "createdAt": "2026-08-24" }, + { "id": 3, "title": "Заказ #003", "client": "Сидоров В.", "amount": 42000, "status": "active", "createdAt": "2026-08-23" } + ], + "stats": { "total": 3, "active": 2, "completed": 1 } +} diff --git a/index.html b/index.html index 0624d39..305e1e7 100644 --- a/index.html +++ b/index.html @@ -3,170 +3,193 @@ -Мой проект - +Дашборд -
+
-

Заголовок вашего проекта

-

Краткое описание — расскажите, что вы предлагаете и какую проблему решаете для клиента. 2-3 предложения, которые цепляют.

-
-Оставить заявку -Узнать больше +

📊 Панель управления

-
-
-

Почему выбирают нас

-

Мы предлагаем лучшие условия на рынке и гарантируем результат

-
-
-⚡ -

Быстро

-

Выполняем работу в кратчайшие сроки без потери качества. Ценим ваше время.

-
-
-💎 -

Качественно

-

Используем проверенные решения и современные технологии. Гарантия на все услуги.

-
-
-🤝 -

Надёжно

-

Работаем официально, несём ответственность за результат. Сотни довольных клиентов.

-
-
-
-
- -
-
-
-
-

О нашем проекте

-

Расскажите здесь историю вашего проекта, компании или о себе. Почему вы начали этим заниматься и что вами движет.

-

Добавьте информацию о команде, опыте работы, подходе к клиентам. Люди любят истории и искренность.

-
-500+ -Клиентов +
+
Всего
+
0
-
-5 лет -Опыта +
+
В работе
+
0
-
-100% -Гарантия +
+
Завершено
+
0
-
-О проекте -
-
-
-
-
-

Свяжитесь с нами

-

Оставьте заявку и мы свяжемся с вами в течение 15 минут

-
- - - - +
+
+

📋 Заказы

+ + + + + +
IDНазваниеКлиентСуммаСтатусДатаДействия
+ +
+ +
+

➕ Добавить

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

Контакты

-

Мы всегда на связи и готовы ответить на любые вопросы

-
-
-📍 -г. Алматы, ул. Примерная, 100 -
-
-📞 -+7 (777) 123-45-67 -
-
-✉️ -hello@example.com -
-
-🕐 -Пн-Пт: 9:00 - 18:00
-
-
- - diff --git a/package.json b/package.json new file mode 100644 index 0000000..4ce00c5 --- /dev/null +++ b/package.json @@ -0,0 +1,8 @@ +{ + "name": "dashboard-app", + "private": true, + "type": "commonjs", + "scripts": { + "start": "node server.js" + } +} diff --git a/server.js b/server.js new file mode 100644 index 0000000..17419d3 --- /dev/null +++ b/server.js @@ -0,0 +1,91 @@ +const http = require("http"); +const fs = require("fs"); +const path = require("path"); + +const PORT = process.env.PORT || 3000; +const DATA = path.join(__dirname, "data.json"); + +function readData() { + try { return JSON.parse(fs.readFileSync(DATA, "utf8")); } catch (_) { return { items: [], stats: { total: 0, active: 0, completed: 0 } }; } +} +function writeData(data) { + fs.writeFileSync(DATA, JSON.stringify(data, null, 2)); +} +function body(req) { + return new Promise((resolve) => { + let s = ""; + req.on("data", (c) => (s += c)); + req.on("end", () => { try { resolve(JSON.parse(s || "{}")); } catch (_) { resolve({}); } }); + }); +} + +http.createServer(async (req, res) => { + res.setHeader("Access-Control-Allow-Origin", "*"); + res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE"); + res.setHeader("Access-Control-Allow-Headers", "Content-Type"); + + if (req.method === "OPTIONS") { + res.writeHead(200); + return res.end(); + } + + if (req.method === "GET" && req.url === "/api/data") { + res.writeHead(200, { "Content-Type": "application/json" }); + return res.end(JSON.stringify(readData())); + } + + if (req.method === "POST" && req.url === "/api/data") { + const data = readData(); + const item = await body(req); + item.id = Date.now(); + item.createdAt = new Date().toISOString().slice(0, 10); + data.items.push(item); + data.stats.total = data.items.length; + data.stats.active = data.items.filter(i => i.status === "active").length; + data.stats.completed = data.items.filter(i => i.status === "completed").length; + writeData(data); + res.writeHead(200, { "Content-Type": "application/json" }); + return res.end(JSON.stringify({ ok: true, item })); + } + + if (req.method === "PUT" && req.url.startsWith("/api/data/")) { + const id = parseInt(req.url.split("/").pop()); + const data = readData(); + const idx = data.items.findIndex(i => i.id === id); + if (idx !== -1) { + const update = await body(req); + data.items[idx] = { ...data.items[idx], ...update }; + data.stats.active = data.items.filter(i => i.status === "active").length; + data.stats.completed = data.items.filter(i => i.status === "completed").length; + writeData(data); + res.writeHead(200, { "Content-Type": "application/json" }); + return res.end(JSON.stringify({ ok: true })); + } + res.writeHead(404, { "Content-Type": "application/json" }); + return res.end(JSON.stringify({ error: "Not found" })); + } + + if (req.method === "DELETE" && req.url.startsWith("/api/data/")) { + const id = parseInt(req.url.split("/").pop()); + const data = readData(); + data.items = data.items.filter(i => i.id !== id); + data.stats.total = data.items.length; + data.stats.active = data.items.filter(i => i.status === "active").length; + data.stats.completed = data.items.filter(i => i.status === "completed").length; + writeData(data); + res.writeHead(200, { "Content-Type": "application/json" }); + return res.end(JSON.stringify({ ok: true })); + } + + let file = req.url === "/" ? "/index.html" : req.url.split("?")[0]; + const full = path.join(__dirname, file); + if (full.startsWith(__dirname) && fs.existsSync(full) && fs.statSync(full).isFile()) { + const ext = path.extname(full); + const type = ext === ".css" ? "text/css" : ext === ".js" ? "application/javascript" : ext === ".svg" ? "image/svg+xml" : "text/html"; + res.writeHead(200, { "Content-Type": type + "; charset=utf-8" }); + return res.end(fs.readFileSync(full)); + } + + res.writeHead(404, { "Content-Type": "text/html" }); + res.end("Not found"); +}).listen(PORT, () => console.log("Dashboard running on port " + PORT));