From d5f442d0f33ef06815426317acad7abeb71f13dc Mon Sep 17 00:00:00 2001 From: Adil Date: Fri, 14 Aug 2026 10:08:25 +0000 Subject: [PATCH] =?UTF-8?q?v2:=20=D1=81=D0=B8=D1=81=D1=82=D0=B5=D0=BC?= =?UTF-8?q?=D0=B0=20=D1=83=D1=87=D1=91=D1=82=D0=B0=20Starlink=20=D0=B0?= =?UTF-8?q?=D0=B1=D0=BE=D0=BD=D0=B5=D0=BD=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 482 +++++++++++++++++++++++++++++++++------------------ package.json | 8 + server.js | 137 +++++++++++++++ 3 files changed, 463 insertions(+), 164 deletions(-) create mode 100644 package.json create mode 100644 server.js diff --git a/index.html b/index.html index b5245df..0c4283b 100644 --- a/index.html +++ b/index.html @@ -3,189 +3,343 @@ -Оптика Алаколь — Строительство волоконно-оптической сети - - - +Starlink — Учёт абонентов -
-
-

Оптика Алаколь

-

Строительство современной волоконно-оптической сети на 400 абонентов в Алакольском районе. Высокоскоростной интернет для дома и бизнеса.

- Подключиться - О проекте -
-
- -
-

О проекте

-
-
-
📡
-

Современная технология

-

Волоконно-оптическая линия связи (ВОЛС) по технологии GPON — стабильный интернет без помех и обрывов.

-
-
-
🏘
-

Охват района

-

Подключение частных домов, квартир и объектов бизнеса в населённых пунктах Алакольского района.

-
-
-
⚡
-

Высокая скорость

-

Доступ к интернету на скоростях до 100 Мбит/с и выше. Подходит для работы, учёбы и развлечений.

+
+
+

📡 Starlink — Учёт абонентов

+
+
0
Абонентов
+
0
Активных
+
0 ₸
Доход
-
-
-
-
-
-
400
-
абонентов
-
-
-
100+
-
км оптоволокна
-
-
-
10
-
населённых пунктов
+
+ + + +
+ +
+
+

Добавить абонента

+
+
+ + + +
+ +
+
+ +
+

Все абоненты

+ + + + + + + + + + + + + + +
Лиц. счётФИОАдресТелефонБалансСтатусДействия
+
+
+ + + + -
+ -
-

Преимущества

-
-
-
🛡
-

Надёжность

-

Оптоволокно не боится грозы, перепадов температур и электромагнитных помех.

-
-
-
💰
-

Доступная цена

-

Конкурентные тарифы на подключение и ежемесячное обслуживание.

-
-
-
🔧
-

Поддержка

-

Техническая поддержка и оперативное устранение неисправностей.

-
-
-
📺
-

ТВ и телефония

-

Возможность подключения цифрового ТВ и домашней телефонии.

-
-
-
- -
-

Зона покрытия

-
-
-

🗺

-

Алакольский район
Карта зоны покрытия сети

-
-
-
- -
-

Заявка на подключение

-
-
-
- - +
- -
-

Контакты

-
-
-
📞
-

Телефон
+7 (777) 123-45-67

-
-
-
✉
-

Email
info@optika-alakol.kz

-
-
-
📍
-

Адрес
Алакольский район, с. Ушарал

-
-
-
+ diff --git a/package.json b/package.json new file mode 100644 index 0000000..963bf72 --- /dev/null +++ b/package.json @@ -0,0 +1,8 @@ +{ + "name": "starlink-subscribers", + "private": true, + "type": "commonjs", + "scripts": { + "start": "node server.js" + } +} diff --git a/server.js b/server.js new file mode 100644 index 0000000..5b61d91 --- /dev/null +++ b/server.js @@ -0,0 +1,137 @@ +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 { subscribers: [], payments: [] }; } +} +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, DELETE, OPTIONS"); + res.setHeader("Access-Control-Allow-Headers", "Content-Type"); + + if (req.method === "OPTIONS") { + res.writeHead(200); + return res.end(); + } + + // API: список абонентов + if (req.method === "GET" && req.url === "/api/subscribers") { + const data = readData(); + res.writeHead(200, { "Content-Type": "application/json" }); + return res.end(JSON.stringify(data.subscribers)); + } + + // API: добавить абонента + if (req.method === "POST" && req.url === "/api/subscribers") { + const sub = await body(req); + const data = readData(); + const newSub = { + id: Date.now(), + accountNumber: "LS" + Date.now(), + name: sub.name || "", + address: sub.address || "", + phone: sub.phone || "", + balance: 0, + status: "active", + createdAt: new Date().toISOString().slice(0, 10) + }; + data.subscribers.push(newSub); + writeData(data); + res.writeHead(200, { "Content-Type": "application/json" }); + return res.end(JSON.stringify({ ok: true, subscriber: newSub })); + } + + // API: обновить абонента + if (req.method === "PUT" && /^\/api\/subscribers\/\d+$/.test(req.url)) { + const id = parseInt(req.url.split("/")[3]); + const update = await body(req); + const data = readData(); + const idx = data.subscribers.findIndex(s => s.id === id); + if (idx !== -1) { + data.subscribers[idx] = { ...data.subscribers[idx], ...update }; + writeData(data); + res.writeHead(200, { "Content-Type": "application/json" }); + return res.end(JSON.stringify({ ok: true })); + } + res.writeHead(404); + return res.end(JSON.stringify({ error: "Not found" })); + } + + // API: удалить абонента + if (req.method === "DELETE" && /^\/api\/subscribers\/\d+$/.test(req.url)) { + const id = parseInt(req.url.split("/")[3]); + const data = readData(); + const idx = data.subscribers.findIndex(s => s.id === id); + if (idx !== -1) { + data.subscribers.splice(idx, 1); + writeData(data); + res.writeHead(200, { "Content-Type": "application/json" }); + return res.end(JSON.stringify({ ok: true })); + } + res.writeHead(404); + return res.end(JSON.stringify({ error: "Not found" })); + } + + // API: платежи + if (req.method === "GET" && req.url.startsWith("/api/payments")) { + const data = readData(); + const subscriberId = req.url.split("=")[1]; + const payments = subscriberId + ? data.payments.filter(p => p.subscriberId == subscriberId) + : data.payments; + res.writeHead(200, { "Content-Type": "application/json" }); + return res.end(JSON.stringify(payments)); + } + + // API: добавить платёж + if (req.method === "POST" && req.url === "/api/payments") { + const payment = await body(req); + const data = readData(); + const newPayment = { + id: Date.now(), + subscriberId: payment.subscriberId, + amount: parseFloat(payment.amount) || 0, + date: payment.date || new Date().toISOString().slice(0, 10), + comment: payment.comment || "" + }; + data.payments.push(newPayment); + + // Обновить баланс абонента + const subIdx = data.subscribers.findIndex(s => s.id == payment.subscriberId); + if (subIdx !== -1) { + data.subscribers[subIdx].balance = (data.subscribers[subIdx].balance || 0) + newPayment.amount; + } + + writeData(data); + res.writeHead(200, { "Content-Type": "application/json" }); + return res.end(JSON.stringify({ ok: true, payment: newPayment })); + } + + // Статика + 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" : "text/html"; + res.writeHead(200, { "Content-Type": type + "; charset=utf-8" }); + return res.end(fs.readFileSync(full)); + } + + res.writeHead(404); + res.end("Not found"); +}).listen(PORT, () => console.log("Сервер запущен на порту " + PORT));