const express = require("express"); const app = express(); const path = require("path"); const { Pool } = require("pg"); const fs = require("fs"); const handlebars = require("handlebars"); require("dotenv").config(); const multer = require("multer"); const http = require("http"); const axios = require('axios'); const moment = require('moment'); const bodyParser = require('body-parser'); const _ = require('lodash'); const puppeteer = require('puppeteer'); const session = require('express-session'); const storage = multer.diskStorage({ destination: function (req, file, cb) { cb(null, "uploads"); }, filename: function (req, file, cb) { cb(null, Date.now() + "-" + file.originalname); }, }); const upload = multer({ storage: storage }); app.use( session({ secret: process.env.SEKRET, resave: false, saveUninitialized: true, cookie: { maxAge: 24 * 60 * 60 * 1000 }, }) ); app.use(express.static(path.join(__dirname, "static"))); app.use(express.json()); app.use(express.urlencoded({ extended: false })); app.use(bodyParser.json()); app.get("/", index); app.get("/signin", signin); app.get("/register", register); app.get("/live", live); app.get("/reports", reports); app.get("/devices", devices); // app.get("/devices/drivers", drivers); app.get("/devices/update", update); app.get("/devices/groups", groups) app.get("/videos", videos); app.get("/videos/export",videoExport); app.get("/settings", settings); app.get("/admin", adminPanel); app.get("/admin/organisation", organisation); async function getUserInfo(userId) { const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); try { let userInfo = { Organisation: "", User: '', Users: [], EditTransport: false, DeleteTransport: false, Update: false, }; if (userId != "admin") { const queryUsers = ` SELECT name, surname, devices, edittransport, deletetransport, update FROM users WHERE id = $1 `; const usersResult = await client.query(queryUsers, [userId]); const user = usersResult.rows[0]; userInfo.Users.push({ name: user.name, surname: user.surname, devices: user.devices, edittransport: user.edittransport, deletetransport: user.deletetransport, update: user.update, }); userInfo.User = user.name + " " + user.surname; userInfo.EditTransport = user.edittransport; userInfo.DeleteTransport = user.deletetransport; userInfo.Update = user.update; } else { userInfo.User = "Администратор" userInfo.EditTransport = true; userInfo.DeleteTransport = true; userInfo.Update = true; } const queryMain = `SELECT organisation FROM main`; const mainResult = await client.query(queryMain); userInfo.Organisation = mainResult.rows[0].organisation; return userInfo; } catch (error) { console.error(error); throw error; } finally { client.release(); } } app.post("/videos/restart", async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } var options = { method: 'GET', url: `http://${process.env.SERVER_IP}:8080/http/restart`, headers: {'Content-Type': 'application/json'}, data: {video: true} }; axios.request(options).then(function (response) { res.status(200).json({ message: "Команда для рестарта выполнена." }); return; }).catch(function (error) { console.error(error); res.status(500).json({ error: "Ошибка сервера" }); return; }); }); // const DB_User = process.env.DB_USER; // const DB_Password = process.env.DB_PASSWORD; // const DB_Host = process.env.DB_HOST; // const DB_Port = process.env.DB_PORT; // const DB_Name = process.env.DB_NAME; const DB_User = "postgres"; const DB_Password = process.env.POSTGRES_PASSWORD; const DB_Host = "postgres"; const DB_Port = "5432"; const DB_Name = "postgres"; async function index(req, res) { if (req.session.userId === undefined) { return res.redirect("/signin"); } const userInfo = await getUserInfo(req.session.userId); var templateData = { SERVER_IP: process.env.SERVER_IP, Organisation: userInfo.Organisation, User: userInfo.User, UserInfo: userInfo.Users, isAdmin: req.session.userId === 'admin', ifDBError: false, Count: "", AlarmsLast11Days: new Array(11).fill(0), Alarms11DaysBefore: new Array(11).fill(0), Dates: [], PositionsLast11Days: new Array(11).fill(0), }; try { const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); const query = ` SELECT COUNT(*) AS count FROM registrars `; const registrars = await client.query(query); templateData.Count = registrars.rows[0].count; let serialValues = []; if (!templateData.isAdmin) { const userDevicesQuery = ` SELECT devices FROM users WHERE id = $1 `; const userDevicesResult = await client.query(userDevicesQuery, [req.session.userId]); if (userDevicesResult.rows[0].devices.length > 0) { serialValues = userDevicesResult.rows[0].devices; templateData.Count = serialValues.length; } else { templateData.Count = 0; } } const last11DaysQuery = ` WITH date_sequence AS ( SELECT DATE_TRUNC('day', NOW() - INTERVAL '10 days' - INTERVAL '3 hours') + (generate_series(0, 10) || ' days')::interval AS day ) SELECT date_sequence.day AS day, COALESCE(COUNT(DISTINCT a.evtuuid), 0) AS count FROM date_sequence LEFT JOIN ( SELECT DISTINCT ON (evtuuid) evtuuid, time FROM alarms WHERE alarmtype = 56 AND time >= NOW() - INTERVAL '11 days' + INTERVAL '3 hours' AND time <= NOW() + INTERVAL '1 day' + INTERVAL '3 hours' ${!templateData.isAdmin ? 'AND serial = ANY($1)' : ''} ORDER BY evtuuid, time DESC LIMIT 100 ) AS a ON DATE_TRUNC('day', a.time) = date_sequence.day GROUP BY date_sequence.day ORDER BY date_sequence.day DESC; `; const last11DaysAlarms = await client.query(last11DaysQuery, templateData.isAdmin ? [] : [serialValues]); const daysBeforeQuery = ` WITH date_sequence AS ( SELECT DATE_TRUNC('day', NOW() - INTERVAL '21 days' - INTERVAL '3 hours') + (generate_series(0, 10) || ' days')::interval AS day ) SELECT date_sequence.day AS day, COALESCE(COUNT(DISTINCT a.evtuuid), 0) AS count FROM date_sequence LEFT JOIN ( SELECT DISTINCT ON (evtuuid) evtuuid, time FROM alarms WHERE alarmtype = 56 AND time >= NOW() - INTERVAL '21 days' + INTERVAL '3 hours' AND time <= NOW() + INTERVAL '10 day' + INTERVAL '3 hours' ${!templateData.isAdmin ? 'AND serial = ANY($1)' : ''} ORDER BY evtuuid, time DESC LIMIT 100 ) AS a ON DATE_TRUNC('day', a.time) = date_sequence.day GROUP BY date_sequence.day ORDER BY date_sequence.day DESC; `; const daysBeforeAlarms = await client.query(daysBeforeQuery, templateData.isAdmin ? [] : [serialValues]); const currentDate = new Date(); const dates = []; const dates11DaysAgo = []; for (let i = 10; i >= 0; i--) { const date = new Date(currentDate - i * 24 * 60 * 60 * 1000); const formattedDate = date.toLocaleDateString('ru-RU', { day: '2-digit', month: '2-digit' }); dates.push(formattedDate); const date11DaysAgo = new Date(currentDate - i * 24 * 60 * 60 * 1000 - 11 * 24 * 60 * 60 * 1000); const formattedDate11DaysAgo = date11DaysAgo.toLocaleDateString('ru-RU', { day: '2-digit', month: '2-digit' }); dates11DaysAgo.push(formattedDate11DaysAgo); } templateData.Dates = dates; dates11DaysAgo.reverse(); const positionsLast11DaysQuery = ` SELECT COUNT(*) AS count, DATE_TRUNC('day', time) AS day, CASE WHEN COUNT(*) = 0 THEN 0 ELSE 1 END AS sort_value FROM geo WHERE time >= NOW() - INTERVAL '10 days' + INTERVAL '3 hours' AND time <= NOW() + INTERVAL '1 day' + INTERVAL '3 hours' ${!templateData.isAdmin ? 'AND serial = ANY($1)' : ''} GROUP BY DATE_TRUNC('day', time) ORDER BY sort_value DESC, day DESC; `; const positionsLast11Days = await client.query(positionsLast11DaysQuery, templateData.isAdmin ? [] : [serialValues]); templateData.Dates.reverse(); const last11DaysMap = new Map(last11DaysAlarms.rows.map(row => [row.day.toLocaleDateString('ru-RU', { day: '2-digit', month: '2-digit' }), parseInt(row.count, 10)])); for (let i = 0; i < dates.length; i++) { const dateKey = dates[i]; templateData.AlarmsLast11Days[i] = last11DaysMap.has(dateKey) ? last11DaysMap.get(dateKey) : 0; } const beforeDaysMap = new Map(daysBeforeAlarms.rows.map(row => [row.day.toLocaleDateString('ru-RU', { day: '2-digit', month: '2-digit' }), parseInt(row.count, 10)])); for (let i = 0; i < dates.length; i++) { const dateKey = dates11DaysAgo[i]; templateData.Alarms11DaysBefore[i] = beforeDaysMap.has(dateKey) ? beforeDaysMap.get(dateKey) : 0; } const positionsMap = new Map(positionsLast11Days.rows.map(row => [row.day.toLocaleDateString('ru-RU', { day: '2-digit', month: '2-digit' }), parseInt(row.count, 10)])); for (let i = 0; i < dates.length; i++) { const dateKey = dates[i]; templateData.PositionsLast11Days[i] = positionsMap.has(dateKey) ? positionsMap.get(dateKey) : 0; } // console.log(templateData); const source = fs.readFileSync("static/templates/index.html", "utf8"); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); } catch (error) { console.error(error); templateData.ifDBError = true; const source = fs.readFileSync("static/templates/index.html", "utf8"); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); } } function signin(req, res) { if (req.session.userId != undefined) { return res.redirect("/"); } const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); pool.query('SELECT COUNT(*) FROM main', (error, result) => { if (error) { console.error('Ошибка при выполнении запроса к базе данных:', error); res.status(500).send('Ошибка сервера'); return; } const rowCount = parseInt(result.rows[0].count, 10); if (rowCount === 0) { res.redirect('/register'); } else { res.sendFile(path.join(__dirname, 'static/templates/signin.html')); } }); } function register(req, res) { if (req.session.userId != undefined) { return res.redirect("/"); } const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); pool.query('SELECT COUNT(*) FROM main', (err, result) => { if (err) { console.error('Ошибка выполнения SQL-запроса:', err); res.status(500).send('Внутренняя ошибка сервера'); return; } if (result.rows[0].count > 0) { res.redirect('/signin'); } else { res.sendFile(path.join(__dirname, 'static/templates/register.html')); } }); } app.post('/setup', async (req, res) => { if (req.session.userId != undefined) { return res.redirect("/"); } try { const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const { name, login, password } = req.body; const checkQuery = 'SELECT * FROM main LIMIT 1'; const checkResult = await pool.query(checkQuery); if (checkResult.rows.length > 0) { res.redirect('/signin'); } const insertQuery = 'INSERT INTO main (organisation, login, password) VALUES ($1, $2, $3)'; await pool.query(insertQuery, [name, login, password]); res.status(200).json({ message: 'Данные успешно добавлены' }); } catch (error) { console.error('Ошибка при обработке запроса:', error); res.status(500).json({ error: 'Произошла ошибка при обработке запроса' }); } }); app.post('/login', async (req, res) => { if (req.session.userId != undefined) { return res.redirect("/"); } const { email, password } = req.body; try { const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const mainQuery = await pool.query( 'SELECT * FROM main WHERE login = $1 AND password = $2', [email, password] ); const mainUser = mainQuery.rows[0]; if (mainUser) { req.session.userId = "admin"; console.log("Авторизация успешна (из таблицы main)"); return res.status(200).json({ message: 'Авторизация успешна' }); } const userQuery = await pool.query( 'SELECT id, name, surname FROM users WHERE email = $1 AND password = $2', [email, password] ); const user = userQuery.rows[0]; if (!user) { return res.status(401).json({ message: 'Неправильное имя пользователя или пароль' }); } req.session.userId = user.id; console.log("Авторизация успешна (из таблицы users)"); res.status(200).json({ message: 'Авторизация успешна' }); } catch (error) { console.error('Ошибка при выполнении запроса к базе данных:', error); res.status(500).json({ message: 'Ошибка сервера' }); } }); app.get('/logout', (req, res) => { req.session.destroy((err) => { if (err) { console.error('Ошибка при выходе из системы:', err); res.status(500).json({ message: 'Ошибка сервера' }); } else { res.redirect('/signin'); } }); }); async function live(req, res) { if (req.session.userId === undefined) { return res.redirect("/signin"); } const userInfo = await getUserInfo(req.session.userId); let templateData = { SERVER_IP: process.env.SERVER_IP, Organisation: userInfo.Organisation, User: userInfo.User, UserInfo: userInfo.Users, isAdmin: req.session.userId === 'admin', ifDBError: false, Registrars: [], Alarms: [], Count: 0, Groups: [], }; try { const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); const minuteInMillis = 90 * 1000; let serialValues = []; if (!templateData.isAdmin) { const userDevicesQuery = ` SELECT devices FROM users WHERE id = $1 `; const userDevicesResult = await client.query(userDevicesQuery, [req.session.userId]); if (userDevicesResult.rows[0].devices.length > 0) { serialValues = userDevicesResult.rows[0].devices; } } const query = ` SELECT id, serial, channels, lastkeepalive, number FROM registrars ${!templateData.isAdmin ? 'WHERE serial = ANY($1)' : ''} ORDER BY id ASC `; const registrars = await client.query(query, templateData.isAdmin ? [] : [serialValues]); templateData.Registrars = registrars.rows.map((row) => ({ id: row.id, serial: row.serial, channels: row.channels, status: Date.now() - Date.parse(row.lastkeepalive) <= minuteInMillis, number: row.number, })); const subquery = ` SELECT a.evtuuid, a.id, a.cmdno, a.time, a.serial, a.st, r.plate, g.latitude, g.longitude FROM ( SELECT DISTINCT ON (evtuuid) evtuuid, id, cmdno, time, serial, st FROM alarms WHERE alarmtype = 56 ${!templateData.isAdmin ? 'AND serial = ANY($2)' : ''} ORDER BY evtuuid, time DESC LIMIT 100 ) AS a LEFT JOIN registrars AS r ON a.serial = r.serial LEFT JOIN ( SELECT *, ROW_NUMBER() OVER (PARTITION BY serial ORDER BY ABS(EXTRACT(EPOCH FROM (time - $1)))) AS row_num FROM geo ) AS g ON a.serial = g.serial AND g.row_num = 1 ORDER BY a.time DESC; `; const alarms = await client.query(subquery, templateData.isAdmin ? [new Date()] : [new Date(), serialValues]); function formatDate(date) { const options = { year: "2-digit", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", }; const adjustedDate = new Date(date); adjustedDate.setHours(adjustedDate.getHours() - 3); const formattedDate = adjustedDate.toLocaleString("ru-RU", options); return formattedDate.replace(",", ""); } (templateData.Alarms = alarms.rows.map((alarm) => { let type; switch (alarm.st) { case "0": type = "Усталость"; break; case "1": type = "Водитель пропал"; break; case "2": type = "Разговор по телефону"; break; case "3": type = "Курение за рулём"; break; case "4": type = "Водитель отвлекся"; break; case "5": type = "Выезд с полосы движения"; break; case "6": type = "!!! Лобовое столкновение"; break; case "7": type = "Скорость превышена"; break; case "8": type = "Распознавание номерных знаков"; break; case "9": type = "!! Маленькое расстояние спереди"; break; case "10": type = "Водитель зевает"; break; case "11": type = "!!! Столкновение с пешеходом"; break; case "12": type = "Проходы переполнены"; break; case "13": type = "!! Посадка/высадка вне остановки"; break; case "14": type = "!! Смена полосы с нарушением ПДД"; break; case "15": type = "! Включенный телефон у водителя"; break; case "16": type = "!!! Ремень безопасности"; break; case "17": type = "Проверка не удалась"; break; case "18": type = "Слепые зоны справа"; break; case "19": type = "!!! Заднее столкновение"; break; case "20": type = "!!! Управление без рук"; break; case "21": type = "!! Управление одной рукой"; break; case "22": type = "Очки, блокирующие инфракрасное"; break; case "23": type = "Слепые зоны слева"; break; case "24": type = "Помехи для пассажиров"; break; case "25": type = "На перекрестке ограничена скорость"; break; case "26": type = "Обнаружен перекресток"; break; case "27": type = "Пешеходы на переходе"; break; case "28": type = "! Неучтивое отношение к пешеходам"; break; case "29": type = "Обнаружен пешеходный переход"; break; case "30": type = "Водитель матерится"; break; default: type = "Неизвестный тип"; } return { id: alarm.id, cmdno: alarm.cmdno, time: formatDate(alarm.time), serial: alarm.serial, st: alarm.st, type: type, plate: alarm.plate, latitude: (alarm.latitude).toFixed(6), longitude: (alarm.longitude).toFixed(6), geo: alarm.latitude + "," + alarm.longitude, }; })) templateData.Count = templateData.Alarms.length; // Получаем список групп и их идентификаторов из таблицы groups const groupsQuery = "SELECT id, name FROM groups"; const groupsResult = await client.query(groupsQuery); const groupsMap = {}; groupsResult.rows.forEach((group) => { groupsMap[group.id] = group.name; }); // Выполняем запрос, чтобы получить все данные из таблицы registrars const queryRegistrars = ` SELECT id, serial, channels, lastkeepalive, "group", name, plate, sim, ip, port, number FROM registrars ${!templateData.isAdmin ? 'WHERE serial = ANY($1)' : ''} ORDER BY id `; const registrarsResult = await client.query(queryRegistrars, templateData.isAdmin ? [] : [serialValues]); const allRegistrars = registrarsResult.rows; const groupedRegistrars = {}; allRegistrars.forEach((registrar) => { const groupName = groupsMap[registrar.group] || "Другое"; // Используем "Другое", если группа неизвестна if (!groupedRegistrars[groupName]) { groupedRegistrars[groupName] = []; } groupedRegistrars[groupName].push({ id: registrar.id, serial: registrar.serial, channels: registrar.channels, status: Date.now() - Date.parse(registrar.lastkeepalive) <= minuteInMillis, name: registrar.name, group: groupsMap[registrar.group] || "Другое", plate: registrar.plate, sim: registrar.sim, ip: registrar.ip, port: registrar.port, number: registrar.number, }); }); templateData.Registrars = allRegistrars.map((registrar) => ({ id: registrar.id, serial: registrar.serial, channels: registrar.channels, status: Date.now() - Date.parse(registrar.lastkeepalive) <= minuteInMillis, name: registrar.name, group: groupsMap[registrar.group] || "Другое", plate: registrar.plate, sim: registrar.sim, ip: registrar.ip, port: registrar.port, })); templateData.Groups = Object.keys(groupedRegistrars).map((groupName) => ({ name: groupName, devices: groupedRegistrars[groupName], })); const source = fs.readFileSync("static/templates/live.html", "utf8"); const template = handlebars.compile(source); const resultHTML = template(templateData); res.send(resultHTML); client.release(); } catch (error) { console.error(error); templateData.ifDBError = true; const source = fs.readFileSync("static/templates/live.html", "utf8"); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); } } app.post("/devices-geo", async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } const selectedDevices = req.body.devices; const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const placeholders = selectedDevices .map((_, index) => `$${index + 1}`) .join(","); const subquery = ` SELECT g.serial, g.longitude, g.latitude, g.direction, g.speed, r.lastkeepalive, r.plate, r.group, r.number FROM geo g INNER JOIN ( SELECT serial, MAX(time) AS time FROM geo WHERE serial IN ( SELECT serial FROM registrars WHERE id IN (${placeholders}) ) GROUP BY serial ) s ON g.serial = s.serial AND g.time = s.time INNER JOIN registrars r ON g.serial = r.serial `; pool.query(subquery, selectedDevices, async (err, result) => { if (err) { console.error("Ошибка выполнения запроса:", err); res.status(500).json({ error: "Ошибка сервера" }); return; } const minuteInMillis = 60000; const devicesData = []; for (const row of result.rows) { if (row.speed > 150) { row.speed /= 100; } const groupName = await getGroupNameById(pool, row.group); const deviceData = { serial: row.serial, longitude: row.longitude, latitude: row.latitude, direction: row.direction, speed: row.speed, status: Date.now() - Date.parse(row.lastkeepalive) <= minuteInMillis, number: row.number, plate: row.plate, group: row.group, groupName: groupName, }; devicesData.push(deviceData); } res.json({ devicesData }); }); }); async function getGroupNameById(pool, groupId) { const query = "SELECT name FROM groups WHERE id = $1"; const result = await pool.query(query, [groupId]); if (result.rows.length > 0) { return result.rows[0].name; } return 'Другое'; } async function reports(req, res) { if (req.session.userId === undefined) { return res.redirect("/signin"); } const userInfo = await getUserInfo(req.session.userId); let templateData = { SERVER_IP: process.env.SERVER_IP, Organisation: userInfo.Organisation, User: userInfo.User, UserInfo: userInfo.Users, isAdmin: req.session.userId === 'admin', ifDBError: false, Registrars: [], Groups: [], }; try { const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); let serialValues = []; if (!templateData.isAdmin) { const userDevicesQuery = ` SELECT devices FROM users WHERE id = $1 `; const userDevicesResult = await client.query(userDevicesQuery, [req.session.userId]); if (userDevicesResult.rows[0].devices.length > 0) { serialValues = userDevicesResult.rows[0].devices; } } const query = ` SELECT a.evtuuid, a.id, a.cmdno, a.time, a.serial, a.st, r.plate, g.latitude, g.longitude FROM ( SELECT DISTINCT ON (evtuuid) evtuuid, id, cmdno, time, serial, st FROM alarms WHERE alarmtype = 56 ${!templateData.isAdmin ? 'AND serial = ANY($2)' : ''} ORDER BY evtuuid, time DESC LIMIT 100 ) AS a LEFT JOIN registrars AS r ON a.serial = r.serial LEFT JOIN ( SELECT *, ROW_NUMBER() OVER (PARTITION BY serial ORDER BY ABS(EXTRACT(EPOCH FROM (time - $1)))) AS row_num FROM geo ) AS g ON a.serial = g.serial AND g.row_num = 1 ORDER BY a.time DESC; `; const alarms = await client.query(query, templateData.isAdmin ? [new Date()] : [new Date(), serialValues]); function formatDate(date) { const options = { year: "2-digit", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", }; const adjustedDate = new Date(date); adjustedDate.setHours(adjustedDate.getHours() - 3); const formattedDate = adjustedDate.toLocaleString("ru-RU", options); return formattedDate.replace(",", ""); } (templateData.Alarms = alarms.rows.map((alarm) => { let type; switch (alarm.st) { case "0": type = "Усталость"; break; case "1": type = "Водитель пропал"; break; case "2": type = "Разговор по телефону"; break; case "3": type = "Курение за рулём"; break; case "4": type = "Водитель отвлекся"; break; case "5": type = "Выезд с полосы движения"; break; case "6": type = "!!! Лобовое столкновение"; break; case "7": type = "Скорость превышена"; break; case "8": type = "Распознавание номерных знаков"; break; case "9": type = "!! Маленькое расстояние спереди"; break; case "10": type = "Водитель зевает"; break; case "11": type = "!!! Столкновение с пешеходом"; break; case "12": type = "Проходы переполнены"; break; case "13": type = "!! Посадка/высадка вне остановки"; break; case "14": type = "!! Смена полосы с нарушением ПДД"; break; case "15": type = "! Включенный телефон у водителя"; break; case "16": type = "!!! Ремень безопасности"; break; case "17": type = "Проверка не удалась"; break; case "18": type = "Слепые зоны справа"; break; case "19": type = "!!! Заднее столкновение"; break; case "20": type = "!!! Управление без рук"; break; case "21": type = "!! Управление одной рукой"; break; case "22": type = "Очки, блокирующие инфракрасное излучение"; break; case "23": type = "Слепые зоны слева"; break; case "24": type = "Помехи для пассажиров"; break; case "25": type = "На перекрестке ограничена скорость"; break; case "26": type = "Обнаружен перекресток"; break; case "27": type = "Пешеходы на переходе"; break; case "28": type = "! Неучтивое отношение к пешеходам"; break; case "29": type = "Обнаружен пешеходный переход"; break; case "30": type = "Водитель матерится"; break; default: type = "Неизвестный тип"; } return { id: alarm.id, cmdno: alarm.cmdno, time: formatDate(alarm.time), serial: alarm.serial, st: alarm.st, type: type, plate: alarm.plate, latitude: (alarm.latitude).toFixed(6), longitude: (alarm.longitude).toFixed(6), geo: (alarm.latitude).toFixed(6) + "," + (alarm.longitude).toFixed(6), }; })) const groupsQuery = "SELECT id, name FROM groups"; const groupsResult = await client.query(groupsQuery); const groupsMap = {}; groupsResult.rows.forEach((group) => { groupsMap[group.id] = group.name; }); const minuteInMillis = 90 * 1000; // Выполняем запрос, чтобы получить все данные из таблицы registrars const queryRegistrars = ` SELECT id, serial, lastkeepalive, "group", name, plate, sim, ip, port, number FROM registrars ${!templateData.isAdmin ? 'WHERE serial = ANY($1)' : ''} ORDER BY id `; const registrarsResult = await client.query(queryRegistrars, templateData.isAdmin ? [] : [serialValues]); const allRegistrars = registrarsResult.rows; const groupedRegistrars = {}; const groupedNumbers = {}; allRegistrars.forEach((registrar) => { const groupName = groupsMap[registrar.group] || "Другое"; // Используем "Другое", если группа неизвестна if (!groupedRegistrars[groupName]) { groupedRegistrars[groupName] = []; groupedNumbers[groupName] = []; } groupedRegistrars[groupName].push(registrar.serial); groupedNumbers[groupName].push(registrar.number); }); templateData.Groups = Object.keys(groupedRegistrars).map((groupName) => ({ name: groupName, serials: groupedRegistrars[groupName], numbers: groupedNumbers[groupName], })); const source = fs.readFileSync( "static/templates/reports/index.html", "utf8" ); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); } catch (error) { console.error(error); templateData.ifDBError = true; const source = fs.readFileSync( "static/templates/reports/index.html", "utf8" ); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); } } app.get("/api/devices", async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } try { const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const { page = 1, limit = 10 } = req.query; const offset = (page - 1) * limit; let serialValues = []; if (!templateData.isAdmin) { const userDevicesQuery = ` SELECT devices FROM users WHERE id = $1 `; const userDevicesResult = await client.query(userDevicesQuery, [req.session.userId]); if (userDevicesResult.rows[0].devices.length > 0) { serialValues = userDevicesResult.rows[0].devices; } } const query = ` SELECT a.id, a.cmdno, a.time, a.serial, a.st, r.plate, g.latitude, g.longitude FROM ( SELECT id, cmdno, time, serial, st FROM alarms ${!templateData.isAdmin ? 'WHERE serial = ANY($4)' : ''} ORDER BY time DESC LIMIT $1 OFFSET $2 ) AS a LEFT JOIN registrars AS r ON a.serial = r.serial LEFT JOIN ( SELECT *, ROW_NUMBER() OVER (PARTITION BY serial ORDER BY ABS(EXTRACT(EPOCH FROM (time - $3)))) AS row_num FROM geo ) AS g ON a.serial = g.serial AND g.row_num = 1 ORDER BY a.time DESC; `; const alarms = await pool.query(query, templateData.isAdmin ? [limit, offset, new Date()] : [limit, offset, new Date(), serialValues]); function formatDate(date) { const options = { year: "2-digit", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", }; const adjustedDate = new Date(date); adjustedDate.setHours(adjustedDate.getHours() - 3); const formattedDate = adjustedDate.toLocaleString("ru-RU", options); return formattedDate.replace(",", ""); } const alarmsData = alarms.rows.map((alarm) => { let type; switch (alarm.st) { case "0": type = "Усталость"; break; case "1": type = "Отсутствие водителя"; break; case "2": type = "Разговор по телефону"; break; default: type = "Неизвестный тип"; } return { id: alarm.id, cmdno: alarm.cmdno, time: formatDate(alarm.time), serial: alarm.serial, st: alarm.st, type: type, plate: alarm.plate, latitude: alarm.latitude, longitude: alarm.longitude, geo: alarm.latitude + "," + alarm.longitude, }; }); const totalCountQuery = `SELECT COUNT(*) FROM alarms ${!templateData.isAdmin ? 'WHERE serial = ANY($1)' : ''};`; const totalCount = await pool.query(totalCountQuery, templateData.isAdmin ? [] : [serialValues]); const totalPages = Math.ceil(totalCount.rows[0].count / limit); res.json({ data: alarmsData, totalPages: totalPages, }); } catch (error) { console.error("Error executing query:", error); res.status(500).json({ error: "Internal server error" }); } }); app.get('/reports/:id', async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } const userInfo = await getUserInfo(req.session.userId); const id = req.params.id; let templateData = { SERVER_IP: process.env.SERVER_IP, Organisation: userInfo.Organisation, User: userInfo.User, UserInfo: userInfo.Users, isAdmin: req.session.userId === 'admin', ifDBError: false, Id: id, Type: "", Speed: "", Date: "", Serial: "", Geo: "", Latitude: "", Longitude: "", QueryTime: "", StartTime: "", EndTime: "", DriverName: "", DriverPhone: "", DriverEmail: "", DriverLicense: "", PrevLatitude: "", PrevLongitude: "", NextLatitude: "", NextLongitude: "", Speeds: "", }; try { const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); const minuteInMillis = 90 * 1000; let serialValues = []; if (!templateData.isAdmin) { const userDevicesQuery = ` SELECT devices FROM users WHERE id = $1 `; const userDevicesResult = await client.query(userDevicesQuery, [req.session.userId]); if (userDevicesResult.rows[0].devices.length > 0) { serialValues = userDevicesResult.rows[0].devices; } } const query = ` WITH PrevNextGeo AS ( SELECT a.serial, a.st, a.time, a.geoid, (SELECT g1.latitude FROM alarms a1 LEFT JOIN geo g1 ON a1.geoid = g1.id WHERE a1.evtuuid = a.evtuuid ORDER BY a1.time ASC LIMIT 1) AS prev_latitude, (SELECT g2.longitude FROM alarms a2 LEFT JOIN geo g2 ON a2.geoid = g2.id WHERE a2.evtuuid = a.evtuuid ORDER BY a2.time ASC LIMIT 1) AS prev_longitude, (SELECT g3.latitude FROM alarms a3 LEFT JOIN geo g3 ON a3.geoid = g3.id WHERE a3.evtuuid = a.evtuuid ORDER BY a3.time DESC LIMIT 1) AS next_latitude, (SELECT g4.longitude FROM alarms a4 LEFT JOIN geo g4 ON a4.geoid = g4.id WHERE a4.evtuuid = a.evtuuid ORDER BY a4.time DESC LIMIT 1) AS next_longitude, g.longitude, g.latitude, g.speed, d.name, d.surname, d.card, d.phone, d.email FROM alarms a LEFT JOIN geo g ON a.geoid = g.id LEFT JOIN drivers d ON a.serial = d.transport WHERE a.id = ${id} LIMIT 1 ), Speeds AS ( SELECT g.speed, ROW_NUMBER() OVER (ORDER BY ABS(EXTRACT(EPOCH FROM (a.time - (SELECT time FROM PrevNextGeo)))) ASC) AS row_number FROM alarms a LEFT JOIN geo g ON a.geoid = g.id WHERE g.serial = (SELECT serial FROM PrevNextGeo) -- Ограничиваем результаты только записями с тем же serial ) SELECT *, ( SELECT array_agg(speed) FROM Speeds WHERE row_number <= 11 ) AS nearest_speeds FROM PrevNextGeo; `; const alarm = (await client.query(query)).rows[0]; // console.log(alarm); function formatDate(date) { const options = { year: "2-digit", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", }; const adjustedDate = new Date(date); adjustedDate.setHours(adjustedDate.getHours() - 3); const formattedDate = adjustedDate.toLocaleString("ru-RU", options); return formattedDate.replace(",", ""); } function formatDateToYYYYMMDD(sqlDate) { const date = new Date(sqlDate); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${year}${month}${day}`; } function formatTimeToHHMMSSBefore(sqlDate) { const date = new Date(sqlDate); date.setSeconds(date.getSeconds() - 10); const hours = String(date.getHours()).padStart(2, '0'); const minutes = String(date.getMinutes()).padStart(2, '0'); const seconds = String(date.getSeconds()).padStart(2, '0'); return `${hours}${minutes}${seconds}`; } function formatTimeToHHMMSSAfter(sqlDate) { const date = new Date(sqlDate); date.setSeconds(date.getSeconds() + 10); const hours = String(date.getHours()).padStart(2, '0'); const minutes = String(date.getMinutes()).padStart(2, '0'); const seconds = String(date.getSeconds()).padStart(2, '0'); return `${hours}${minutes}${seconds}`; } let type; switch (alarm.st) { case "0": type = "Усталость"; break; case "1": type = "Водитель пропал"; break; case "2": type = "Разговор по телефону"; break; case "3": type = "Курение за рулём"; break; case "4": type = "Водитель отвлекся"; break; case "5": type = "Выезд с полосы движения"; break; case "6": type = "!!! Лобовое столкновение"; break; case "7": type = "Скорость превышена"; break; case "8": type = "Распознавание номерных знаков"; break; case "9": type = "!! Маленькое расстояние спереди"; break; case "10": type = "Водитель зевает"; break; case "11": type = "!!! Столкновение с пешеходом"; break; case "12": type = "Проходы переполнены"; break; case "13": type = "!! Посадка/высадка вне остановки"; break; case "14": type = "!! Смена полосы с нарушением ПДД"; break; case "15": type = "! Включенный телефон у водителя"; break; case "16": type = "!!! Ремень безопасности"; break; case "17": type = "Проверка не удалась"; break; case "18": type = "Слепые зоны справа"; break; case "19": type = "!!! Заднее столкновение"; break; case "20": type = "!!! Управление без рук"; break; case "21": type = "!! Управление одной рукой"; break; case "22": type = "Очки, блокирующие инфракрасное излучение"; break; case "23": type = "Слепые зоны слева"; break; case "24": type = "Помехи для пассажиров"; break; case "25": type = "На перекрестке ограничена скорость"; break; case "26": type = "Обнаружен перекресток"; break; case "27": type = "Пешеходы на переходе"; break; case "28": type = "! Неучтивое отношение к пешеходам"; break; case "29": type = "Обнаружен пешеходный переход"; break; case "30": type = "Водитель матерится"; break; default: type = "Неизвестный тип"; } var actualSpeed; if (alarm.speed > 150) { actualSpeed = alarm.speed / 100 } else { actualSpeed = alarm.speed } if (serialValues.includes(alarm.serial) || templateData.isAdmin) { templateData.Type = type; templateData.Speed = actualSpeed; templateData.Date = formatDate(alarm.time); templateData.Serial = alarm.serial; templateData.Geo = alarm.latitude + "," + alarm.longitude; templateData.Latitude = alarm.latitude templateData.Longitude = alarm.longitude templateData.QueryTime = formatDateToYYYYMMDD(alarm.time); templateData.StartTime = formatTimeToHHMMSSBefore(alarm.time); templateData.EndTime = formatTimeToHHMMSSAfter(alarm.time); templateData.DriverName = alarm.name + " " + alarm.surname; templateData.DriverPhone = alarm.phone; templateData.DriverEmail = alarm.email; templateData.DriverLicense = alarm.card; templateData.PrevLatitude = alarm.prev_latitude; templateData.PrevLongitude = alarm.prev_longitude; templateData.NextLatitude = alarm.next_latitude; templateData.NextLongitude = alarm.next_longitude; templateData.Speeds = alarm.nearest_speeds templateData.Speeds = templateData.Speeds.map(speed => { if (speed > 150) { return speed / 100; } else { return speed; } }); } else { console.log("Нет доступа к данному аларму") templateData.ifDBError = true; } // console.log(templateData); const source = fs.readFileSync("static/templates/reports/report.html", "utf8"); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); client.release(); } catch (error) { console.error(error); templateData.ifDBError = true; const source = fs.readFileSync( "static/templates/reports/report.html", "utf8" ); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); } }); app.get('/generate-pdf/:id', async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } const userInfo = await getUserInfo(req.session.userId); const id = req.params.id; let templateData = { SERVER_IP: process.env.SERVER_IP, Organisation: userInfo.Organisation, User: userInfo.User, UserInfo: userInfo.Users, isAdmin: req.session.userId === 'admin', ifDBError: false, Id: id, Type: "", Speed: "", Date: "", Serial: "", Geo: "", Latitude: "", Longitude: "", DriverName: "", DriverPhone: "", DriverEmail: "", DriverLicense: "", PrevLatitude: "", PrevLongitude: "", NextLatitude: "", NextLongitude: "", Speeds: "", }; try { const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); const minuteInMillis = 90 * 1000; const query = ` WITH PrevNextGeo AS ( SELECT a.serial, a.st, a.time, a.geoid, (SELECT g1.latitude FROM alarms a1 LEFT JOIN geo g1 ON a1.geoid = g1.id WHERE a1.evtuuid = a.evtuuid ORDER BY a1.time ASC LIMIT 1) AS prev_latitude, (SELECT g2.longitude FROM alarms a2 LEFT JOIN geo g2 ON a2.geoid = g2.id WHERE a2.evtuuid = a.evtuuid ORDER BY a2.time ASC LIMIT 1) AS prev_longitude, (SELECT g3.latitude FROM alarms a3 LEFT JOIN geo g3 ON a3.geoid = g3.id WHERE a3.evtuuid = a.evtuuid ORDER BY a3.time DESC LIMIT 1) AS next_latitude, (SELECT g4.longitude FROM alarms a4 LEFT JOIN geo g4 ON a4.geoid = g4.id WHERE a4.evtuuid = a.evtuuid ORDER BY a4.time DESC LIMIT 1) AS next_longitude, g.longitude, g.latitude, g.speed, d.name, d.surname, d.card, d.phone, d.email FROM alarms a LEFT JOIN geo g ON a.geoid = g.id LEFT JOIN drivers d ON a.serial = d.transport WHERE a.id = ${id} LIMIT 1 ), Speeds AS ( SELECT g.speed, ROW_NUMBER() OVER (ORDER BY ABS(EXTRACT(EPOCH FROM (a.time - (SELECT time FROM PrevNextGeo)))) ASC) AS row_number FROM alarms a LEFT JOIN geo g ON a.geoid = g.id WHERE g.serial = (SELECT serial FROM PrevNextGeo) -- Ограничиваем результаты только записями с тем же serial ) SELECT *, ( SELECT array_agg(speed) FROM Speeds WHERE row_number <= 11 ) AS nearest_speeds FROM PrevNextGeo; `; const alarm = (await client.query(query)).rows[0]; // console.log(alarm); function formatDate(date) { const options = { year: "2-digit", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", }; const adjustedDate = new Date(date); adjustedDate.setHours(adjustedDate.getHours() - 3); const formattedDate = adjustedDate.toLocaleString("ru-RU", options); return formattedDate.replace(",", ""); } let type; switch (alarm.st) { case "0": type = "Усталость"; break; case "1": type = "Водитель пропал"; break; case "2": type = "Разговор по телефону"; break; case "3": type = "Курение за рулём"; break; case "4": type = "Водитель отвлекся"; break; case "5": type = "Выезд с полосы движения"; break; case "6": type = "!!! Лобовое столкновение"; break; case "7": type = "Скорость превышена"; break; case "8": type = "Распознавание номерных знаков"; break; case "9": type = "!! Маленькое расстояние спереди"; break; case "10": type = "Водитель зевает"; break; case "11": type = "!!! Столкновение с пешеходом"; break; case "12": type = "Проходы переполнены"; break; case "13": type = "!! Посадка/высадка вне остановки"; break; case "14": type = "!! Смена полосы с нарушением ПДД"; break; case "15": type = "! Включенный телефон у водителя"; break; case "16": type = "!!! Ремень безопасности"; break; case "17": type = "Проверка не удалась"; break; case "18": type = "Слепые зоны справа"; break; case "19": type = "!!! Заднее столкновение"; break; case "20": type = "!!! Управление без рук"; break; case "21": type = "!! Управление одной рукой"; break; case "22": type = "Очки, блокирующие инфракрасное излучение"; break; case "23": type = "Слепые зоны слева"; break; case "24": type = "Помехи для пассажиров"; break; case "25": type = "На перекрестке ограничена скорость"; break; case "26": type = "Обнаружен перекресток"; break; case "27": type = "Пешеходы на переходе"; break; case "28": type = "! Неучтивое отношение к пешеходам"; break; case "29": type = "Обнаружен пешеходный переход"; break; case "30": type = "Водитель матерится"; break; default: type = "Неизвестный тип"; } var actualSpeed; if (alarm.speed > 150) { actualSpeed = alarm.speed / 100 } else { actualSpeed = alarm.speed } templateData.Type = type; templateData.Speed = actualSpeed; templateData.Date = formatDate(alarm.time); templateData.Serial = alarm.serial; templateData.Geo = alarm.latitude + "," + alarm.longitude; templateData.Latitude = alarm.latitude templateData.Longitude = alarm.longitude templateData.DriverName = alarm.name + " " + alarm.surname; templateData.DriverPhone = alarm.phone; templateData.DriverEmail = alarm.email; templateData.DriverLicense = alarm.card; templateData.PrevLatitude = alarm.prev_latitude; templateData.PrevLongitude = alarm.prev_longitude; templateData.NextLatitude = alarm.next_latitude; templateData.NextLongitude = alarm.next_longitude; templateData.Speeds = alarm.nearest_speeds templateData.Speeds = templateData.Speeds.map(speed => { if (speed > 150) { return speed / 100; } else { return speed; } }); let data = { Id: templateData.Id, Organisation: templateData.Organisation, Type: templateData.Type, Speed: templateData.Speed, Date: templateData.Date, Serial: templateData.Serial, Geo: templateData.Geo, PrevLongitude: templateData.PrevLongitude, PrevLatitude: templateData.PrevLatitude, NextLongitude: templateData.NextLongitude, NextLatitude: templateData.NextLatitude, Speeds: templateData.Speeds, }; const source = fs.readFileSync("static/templates/reports/pdf.html", "utf8"); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); } catch (error) { console.error(error); templateData.ifDBError = true; const source = fs.readFileSync( "static/templates/reports/pdf.html", "utf8" ); const template = handlebars.compile(source); const resultT = template(data); res.send(resultT); } }); async function devices(req, res) { if (req.session.userId === undefined) { return res.redirect("/signin"); } let userInfo; let templateData = { SERVER_IP: process.env.SERVER_IP, Organisation: '', User: '', UserInfo: '', isAdmin: req.session.userId === 'admin', ifDBError: false, Registrars: [], Groups: [], GroupsList: [], EditTransport: false, DeleteTransport: false, Update: false, }; try { const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); let serialValues = []; if (!templateData.isAdmin) { const userDevicesQuery = ` SELECT devices FROM users WHERE id = $1 `; const userDevicesResult = await client.query(userDevicesQuery, [req.session.userId]); if (userDevicesResult.rows[0].devices.length > 0) { serialValues = userDevicesResult.rows[0].devices; } } const groupsQuery = "SELECT id, name FROM groups"; const groupsResult = await client.query(groupsQuery); const groupsMap = {}; groupsResult.rows.forEach((group) => { groupsMap[group.id] = group.name; }); const minuteInMillis = 90 * 1000; const queryRegistrars = ` SELECT id, serial, lastkeepalive, "group", name, plate, sim, ip, port, number FROM registrars ${!templateData.isAdmin ? 'WHERE serial = ANY($1)' : ''} ORDER BY id `; const registrarsResult = await client.query(queryRegistrars, templateData.isAdmin ? [] : [serialValues]); const allRegistrars = registrarsResult.rows; const groupedRegistrars = {}; const groupedNumbers = {}; allRegistrars.forEach((registrar) => { const groupName = groupsMap[registrar.group] || "Другое"; // Используем "Другое", если группа неизвестна if (!groupedRegistrars[groupName]) { groupedRegistrars[groupName] = []; groupedNumbers[groupName] = []; } groupedRegistrars[groupName].push(registrar.serial); groupedNumbers[groupName].push(registrar.number); }); userInfo = await getUserInfo(req.session.userId); templateData = { SERVER_IP: process.env.SERVER_IP, Organisation: userInfo.Organisation, User: userInfo.User, UserInfo: userInfo.Users, EditTransport: userInfo.EditTransport, DeleteTransport: userInfo.DeleteTransport, Update: userInfo.Update, isAdmin: req.session.userId === 'admin', ifDBError: false, Registrars: allRegistrars.map((registrar) => ({ id: registrar.id, number: registrar.number, serial: registrar.serial, status: Date.now() - Date.parse(registrar.lastkeepalive) <= minuteInMillis, name: registrar.name, group: groupsMap[registrar.group] || "Другое", plate: registrar.plate, sim: registrar.sim, ip: registrar.ip, port: registrar.port, })), Groups: Object.keys(groupedRegistrars).map((groupName) => ({ name: groupName, serials: groupedRegistrars[groupName], numbers: groupedNumbers[groupName], })), GroupsList: groupsResult.rows, }; const source = fs.readFileSync("static/templates/devices/index.html", "utf8"); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); client.release(); } catch (error) { console.error(error); if (templateData) { templateData.ifDBError = true; const source = fs.readFileSync( "static/templates/devices/index.html", "utf8" ); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); } } } async function groups(req, res) { if (req.session.userId === undefined) { return res.redirect("/signin"); } const userInfo = await getUserInfo(req.session.userId); if (!userInfo.EditTransport) { return res.redirect("/signin"); } let templateData = { SERVER_IP: process.env.SERVER_IP, Organisation: userInfo.Organisation, User: userInfo.User, ifDBError: false, UserInfo: userInfo.Users, isAdmin: req.session.userId === 'admin', Groups: [], EditTransport: userInfo.EditTransport, DeleteTransport: userInfo.DeleteTransport, Update: userInfo.Update, }; try { const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); const result = await client.query('SELECT id, name FROM groups'); const groups = result.rows; client.release(); templateData.Groups = groups; const source = fs.readFileSync("static/templates/devices/groups.html", "utf8"); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); } catch (error) { console.error(error); templateData.ifDBError = true; const source = fs.readFileSync( "static/templates/devices/groups.html", "utf8" ); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); } } app.post('/update-group', async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } try { const { groupId, newName } = req.body; const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const query = 'UPDATE groups SET name = $1 WHERE id = $2'; const values = [newName, groupId]; await pool.query(query, values); res.status(200).json({ message: 'Данные группы обновлены успешно' }); } catch (error) { console.error('Ошибка при обновлении данных группы:', error); res.status(500).json({ error: 'Внутренняя ошибка сервера' }); } }); async function getParameters(serial) { const requestResponse = await axios.get(`http://${process.env.SERVER_IP}:8080/http/parameters/request?serial=${serial}`, { headers: { 'Content-Type': 'application/json', }, data: JSON.stringify({ "FIELDS": [ "DOSD" ] }), }); const requestResponse2 = await axios.get(`http://${process.env.SERVER_IP}:8080/http/parameters/request?serial=${serial}`, { headers: { 'Content-Type': 'application/json', }, data: JSON.stringify({ "FIELDS": [ "GSP" ] }), }); const requestResponse3 = await axios.get(`http://${process.env.SERVER_IP}:8080/http/parameters/request?serial=${serial}`, { headers: { 'Content-Type': 'application/json', }, data: JSON.stringify({ "FIELDS": [ "TIMEP" ] }), }); const requestResponse4 = await axios.get(`http://${process.env.SERVER_IP}:8080/http/parameters/request?serial=${serial}`, { headers: { 'Content-Type': 'application/json', }, data: JSON.stringify({ "FIELDS": [ "SUBSTRNET" ] }), }); const requestResponse5 = await axios.get(`http://${process.env.SERVER_IP}:8080/http/parameters/request?serial=${serial}`, { headers: { 'Content-Type': 'application/json', }, data: JSON.stringify({ "FIELDS": [ "AR" ] }), }); // console.log(requestResponse.data); await new Promise(resolve => setTimeout(resolve, 300)); const getResponse = await axios.get(`http://${process.env.SERVER_IP}:8080/http/parameters/get?serial=${serial}`); // console.log(getResponse.data); return getResponse.data; } app.post('/device-parameters', async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } try { const { serial } = req.body; // Используем асинхронный цикл для выполнения GET-запросов по очереди const responseData = await getParameters(serial); res.json(responseData); } catch (error) { console.error(error); res.status(500).json({ error: 'Internal server error' }); } }); app.put('/device-parameters', async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } // Получаем данные из PUT запроса const requestData = req.body; const { serial } = req.query; // Извлекаем необходимые параметры const { DATEMOD, TIMEFORMAT, LANGUAGE, VIDEOFORMAT, GEOMOD, SUBSTREAMMODE, TIMEZ, NE, TE, VE, SE, GE } = requestData; // Создаем JSON для GET запроса const requestBody = { "TIMEP": { "DATEM": parseInt(DATEMOD, 10) || 1, "TIMEM": parseInt(TIMEFORMAT, 10) || 0, "TIMEZ": TIMEZ || "180C" }, "GSP": { "LANT": parseInt(LANGUAGE, 10) || 12, "VGA": parseInt(VIDEOFORMAT, 10) || 0, "GM": parseInt(GEOMOD, 10) || 0 }, "SUBSTRNET": { "SM": parseInt(SUBSTREAMMODE, 10) || 1 }, "DOSD": { "NE": parseInt(NE, 10) || 1, "TE": parseInt(TE, 10) || 1, "VE": parseInt(VE, 10) || 0, "SE": parseInt(SE, 10) || 0, "GE": parseInt(GE, 10) || 0 } }; // Отправляем GET запрос с JSON BODY try { const response = await axios.get(`http://${process.env.SERVER_IP}:8080/http/parameters/set?serial=${serial}`, { data: JSON.stringify(requestBody), headers: { 'Content-Type': 'application/json' } }); res.status(response.status).send(response.data); } catch (error) { res.status(500).send('Произошла ошибка при отправке GET запроса.'); } }); app.put('/camera-parameters', async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } // Получаем данные из PUT запроса const camerasData = req.body; const { serial } = req.query; // Создаем JSON для GET запроса const requestBody = { "AR": camerasData }; // Отправляем GET запрос с JSON BODY try { const response = await axios.get(`http://${process.env.SERVER_IP}:8080/http/parameters/set?serial=${serial}`, { data: JSON.stringify(requestBody), headers: { 'Content-Type': 'application/json' } }); res.status(response.status).send(response.data); } catch (error) { res.status(500).send('Произошла ошибка при отправке GET запроса.'); } }); app.post("/devicedata", async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } const id = req.body.id; const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); try { const query = "SELECT * FROM registrars WHERE id = $1;"; const devicedata = await client.query(query, [id]); const response = devicedata.rows[0]; res.json(response); } finally { client.release(); } }); app.post("/updatedevice", async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); var { serialNumber, deviceNumber, plateNumber, channelsAmount, plateColor, IPAddress, serverPort, deviceGroup, connectionProtocol, sumNumber, simIMEI, simIMSI, simModule, transportType, transportFactory, transportStrength, transportEngine, transportStanina, transportFuel, transportCertificate, transportCategory, transportExpire, transportConsumption, transportProvince, transportCity, equipmentName, equipmentPassword, equipmentNumber, equipmentReleased, equipmentInstaller, equipmentInstalled, equipmentDescription, } = req.body; try { const query = ` UPDATE registrars SET plate = $1, plate_color = $2, channels = $3, protocol = $4, ip = $5, "group" = $6, port = $7, sim = $8, imei = $9, imsi = $10, module = $11, auto = $12, factory = $13, capacity = $14, engine = $15, stanina = $16, fuel = $17, certificate = $18, category = $19, certificate_exp = $20, consumption = $21, region = $22, city = $23, name = $24, password = $25, batch = $26, release = $27, installer = $28, installation = $29, description = $30, number = $31 WHERE serial = $32 RETURNING *; `; const values = [ plateNumber, plateColor, channelsAmount, connectionProtocol, IPAddress, deviceGroup, serverPort, sumNumber, simIMEI, simIMSI, simModule, transportType, transportFactory, transportStrength, transportEngine, transportStanina, transportFuel, transportCertificate, transportCategory, transportExpire, transportConsumption, transportProvince, transportCity, equipmentName, equipmentPassword, equipmentNumber, equipmentReleased, equipmentInstaller, equipmentInstalled, equipmentDescription, deviceNumber, serialNumber, ]; const result = await client.query(query, values); const updatedRow = result.rows[0]; // console.log("Updated row:", updatedRow); res.send("Data updated successfully"); } catch (error) { console.error("Error updating data:", error); res.status(500).send("An error occurred while updating data"); } finally { client.release(); } }); app.post("/updatedriver", upload.single("upload-file"), async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); var { driverName, driverSurname, driverCard, driverGender, driverLicense, driverPassport, driverPhone, driverEmail, driverTransport, driverDescription, driverID, } = req.body; try { // Вставка новой строки в таблицу drivers const query = ` UPDATE drivers SET name = $1, surname = $2, card = $3, gender = $4, license = $5, passport = $6, phone = $7, email = $8, transport = $9, description = $10 WHERE id = $11 RETURNING *; `; const values = [ driverName, driverSurname, driverCard, driverGender, driverLicense, driverPassport, driverPhone, driverEmail, driverTransport, driverDescription, driverID, ]; const result = await client.query(query, values); const newRow = result.rows[0]; // console.log("New driver added:", newRow); res.send("Data added successfully"); } catch (error) { console.error("Error adding data:", error); res.status(500).send("An error occurred while adding data"); } finally { client.release(); } }); app.post("/adddriver", upload.single("upload-file"), async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); var { driverName, driverSurname, driverCard, driverGender, driverLicense, driverPassport, driverPhone, driverEmail, driverTransport, driverDescription, } = req.body; try { // Вставка новой строки в таблицу drivers const query = ` INSERT INTO drivers ( name, surname, card, gender, license, passport, phone, email, transport, description ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) RETURNING *; `; const values = [ driverName, driverSurname, driverCard, driverGender, driverLicense, driverPassport, driverPhone, driverEmail, driverTransport, driverDescription, ]; const result = await client.query(query, values); const newRow = result.rows[0]; // console.log("New driver added:", newRow); res.send("Data added successfully"); } catch (error) { console.error("Error adding data:", error); res.status(500).send("An error occurred while adding data"); } finally { client.release(); } }); app.post("/driverdata", async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } const id = req.body.id; const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); try { // Выполняем запрос и получаем результат const query = "SELECT * FROM drivers WHERE id = $1;"; const driverdata = await client.query(query, [id]); // Формирование и отправка ответа const response = driverdata.rows[0]; res.json(response); } finally { client.release(); } }); app.post("/userdata", async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } const id = req.body.id; const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); try { // Выполняем запрос и получаем результат const query = "SELECT * FROM users WHERE id = $1;"; const userdata = await client.query(query, [id]); // Формирование и отправка ответа const response = userdata.rows[0]; res.json(response); } finally { client.release(); } }); app.post("/groupdata", async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } const id = req.body.id; const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); try { // Выполняем запрос и получаем результат const query = "SELECT * FROM groups WHERE id = $1;"; const userdata = await client.query(query, [id]); // Формирование и отправка ответа const response = userdata.rows[0]; res.json(response); } finally { client.release(); } }); app.post("/deletedriver", async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } const id = req.body.id; const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); try { // Выполняем запрос и получаем результат const query = "DELETE FROM drivers WHERE id = $1;"; const driverdata = await client.query(query, [id]); // Формирование и отправка ответа res.send("Data deleted successfully"); } finally { client.release(); } }); app.post("/deleteuser", async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } const id = req.body.id; const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); try { // Выполняем запрос и получаем результат const query = "DELETE FROM users WHERE id = $1;"; const userdata = await client.query(query, [id]); // Формирование и отправка ответа res.send("Data deleted successfully"); } finally { client.release(); } }); app.post("/deletegroup", async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } const id = req.body.id; const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); try { // Выполняем запрос и получаем результат const query = "DELETE FROM groups WHERE id = $1;"; const userdata = await client.query(query, [id]); // Формирование и отправка ответа res.send("Data deleted successfully"); } finally { client.release(); } }); app.post("/add-group", async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } const { name } = req.body; try { const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); const query = ` INSERT INTO groups (name) VALUES ($1) RETURNING id `; const result = await client.query(query, [name]); // Освобождение клиента client.release(); console.log("Группа успешно добавлена"); res.json({ message: "Группа успешно добавлена" }); } catch (err) { console.error("Ошибка при вставке данных в базу данных:", err); res.status(500).json({ error: "Ошибка при добавлении пользователя" }); } }); async function drivers(req, res) { if (req.session.userId === undefined) { return res.redirect("/signin"); } const userInfo = await getUserInfo(req.session.userId); let templateData = { SERVER_IP: process.env.SERVER_IP, Organisation: userInfo.Organisation, User: userInfo.User, UserInfo: userInfo.Users, isAdmin: req.session.userId === 'admin', ifDBError: false, Drivers: [], Registrars: [], }; try { const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); // Выполняем запрос для объединения данных из таблиц drivers и registrars const queryDrivers = ` SELECT d.id, d.name, d.surname, d.transport, d.phone, d.email, d.card, r.connected FROM drivers d LEFT JOIN registrars r ON d.transport = r.serial ORDER BY r.connected DESC NULLS LAST, CASE WHEN r.connected = true THEN 0 ELSE 1 END, d.id `; const driversResult = await client.query(queryDrivers); templateData.Drivers = driversResult.rows.map((driver) => ({ id: driver.id, name: driver.name, surname: driver.surname, transport: driver.transport, phone: driver.phone, email: driver.email, card: driver.card, })); const queryRegistrars = ` SELECT serial FROM registrars `; const registrarsResult = await client.query(queryRegistrars); templateData.Registrars = registrarsResult.rows.map( (registrar) => registrar.serial ); // console.log(templateData); const source = fs.readFileSync( "static/templates/devices/drivers.html", "utf8" ); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); client.release(); } catch (error) { console.error(error); templateData.ifDBError = true; const source = fs.readFileSync( "static/templates/devices/drivers.html", "utf8" ); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); } } async function update(req, res) { if (req.session.userId === undefined) { return res.redirect("/signin"); } const userInfo = await getUserInfo(req.session.userId); if (!userInfo.Update) { return res.redirect("/signin"); } let templateData = { SERVER_IP: process.env.SERVER_IP, Organisation: userInfo.Organisation, User: userInfo.User, ifDBError: false, UserInfo: userInfo.Users, isAdmin: req.session.userId === 'admin', EditTransport: userInfo.EditTransport, DeleteTransport: userInfo.DeleteTransport, Update: userInfo.Update, }; try { const source = fs.readFileSync("static/templates/devices/update.html", "utf8"); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); } catch (error) { console.error(error); templateData.ifDBError = true; const source = fs.readFileSync( "static/templates/devices/update.html", "utf8" ); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); } } async function settings(req, res) { if (req.session.userId === undefined) { return res.redirect("/signin"); } const userInfo = await getUserInfo(req.session.userId); let templateData = { SERVER_IP: process.env.SERVER_IP, Organisation: userInfo.Organisation, User: userInfo.User, ifDBError: false, UserInfo: userInfo.Users, isAdmin: req.session.userId === 'admin', }; try { const source = fs.readFileSync("static/templates/settings.html", "utf8"); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); } catch (error) { console.error(error); templateData.ifDBError = true; const source = fs.readFileSync( "static/templates/settings.html", "utf8" ); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); } } async function organisation(req, res) { if (req.session.userId === undefined) { return res.redirect("/signin"); } if (req.session.userId != "admin") { return res.redirect("/signin"); } const userInfo = await getUserInfo(req.session.userId); let templateData = { SERVER_IP: process.env.SERVER_IP, Organisation: userInfo.Organisation, User: userInfo.User, ifDBError: false, UserInfo: userInfo.Users, isAdmin: req.session.userId === 'admin', }; try { const source = fs.readFileSync("static/templates/admin/organisation.html", "utf8"); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); } catch (error) { console.error(error); templateData.ifDBError = true; const source = fs.readFileSync( "static/templates/admin/organisation.html", "utf8" ); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); } } app.post('/update-organisation', async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } if (req.session.userId != "admin") { return res.redirect("/signin"); } try { const { name } = req.body; const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); await client.query('UPDATE main SET organisation = $1 WHERE id = 1', [name]); client.release(); res.status(200).json({ message: 'Значение успешно обновлено' }); } catch (error) { console.error(error); res.status(500).json({ error: 'Произошла ошибка при обновлении значения' }); } }); async function adminPanel(req, res) { if (req.session.userId === undefined) { return res.redirect("/signin"); } if (req.session.userId != "admin") { return res.redirect("/signin"); } const userInfo = await getUserInfo(req.session.userId); let templateData = { SERVER_IP: process.env.SERVER_IP, Organisation: userInfo.Organisation, User: userInfo.User, ifDBError: false, Users: [], UserInfo: userInfo.Users, isAdmin: req.session.userId === 'admin', }; try { const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); const queryUsers = ` SELECT id, name, surname, email, phone, added FROM users ORDER BY id `; const usersResult = await client.query(queryUsers); const allUsers = usersResult.rows; templateData.Users = allUsers.map((user) => ({ id: user.id, name: user.name, surname: user.surname, email: user.email, phone: user.phone, added: new Date(user.added).toLocaleDateString('ru-RU', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }), })); // console.log(templateData); const source = fs.readFileSync("static/templates/admin/index.html", "utf8"); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); client.release(); } catch (error) { console.error(error); templateData.ifDBError = true; const source = fs.readFileSync( "static/templates/admin/index.html", "utf8" ); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); } } // Обработка POST-запроса для добавления пользователя app.post("/add-user", async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } if (req.session.userId != "admin") { return res.redirect("/signin"); } const { name, surname, email, phone, password } = req.body; // console.log(name, surname, email, phone, password) try { const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); const query = ` INSERT INTO users (name, surname, email, phone, password, added) VALUES ($1, $2, $3, $4, $5, NOW()) RETURNING id `; const result = await client.query(query, [name, surname, email, phone, password]); // Освобождение клиента client.release(); console.log("Пользователь успешно добавлен"); res.json({ message: "Пользователь успешно добавлен" }); } catch (err) { console.error("Ошибка при вставке данных в базу данных:", err); res.status(500).json({ error: "Ошибка при добавлении пользователя" }); } }); app.get('/admin/user/:id', async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } if (req.session.userId != "admin") { return res.redirect("/signin"); } const userInfo = await getUserInfo(req.session.userId); const id = req.params.id; let templateData = { SERVER_IP: process.env.SERVER_IP, Organisation: userInfo.Organisation, User: userInfo.User, UserInfo: userInfo.Users, isAdmin: req.session.userId === 'admin', ifDBError: false, Id: id, Name: "", Surname: "", Email: "", Phone: "", Password: "", Devices: [], EditTransport: false, DeleteTransport: false, Update: false, Groups: [], }; try { const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); const groupsQuery = "SELECT id, name FROM groups"; const groupsResult = await client.query(groupsQuery); const groupsMap = {}; groupsResult.rows.forEach((group) => { groupsMap[group.id] = group.name; }); const minuteInMillis = 90 * 1000; const queryRegistrars = ` SELECT id, serial, lastkeepalive, "group", name, plate, sim, ip, port, number FROM registrars ORDER BY id `; const registrarsResult = await client.query(queryRegistrars); const allRegistrars = registrarsResult.rows; const groupedRegistrars = {}; const groupedNumbers = {}; allRegistrars.forEach((registrar) => { const groupName = groupsMap[registrar.group] || "Другое"; // Используем "Другое", если группа неизвестна if (!groupedRegistrars[groupName]) { groupedRegistrars[groupName] = []; groupedNumbers[groupName] = []; } groupedRegistrars[groupName].push({ serial: registrar.serial, checked: false, }); groupedNumbers[groupName].push(registrar.number); }); const query = "SELECT * FROM users WHERE id = $1;"; const userdata = await client.query(query, [id]); const response = userdata.rows[0]; if (response.devices && response.devices.length > 0) { for (const groupName in groupedRegistrars) { groupedRegistrars[groupName].forEach((serialObj) => { serialObj.checked = response.devices.includes(serialObj.serial); }); } } templateData.Name = response.name; templateData.Surname = response.surname; templateData.Email = response.email; templateData.Phone = response.phone; templateData.Password = response.password; templateData.Devices = response.devices; templateData.DeleteTransport = response.deletetransport; templateData.EditTransport = response.edittransport; templateData.Update = response.update; templateData.Groups = Object.keys(groupedRegistrars).map((groupName) => ({ name: groupName, serials: groupedRegistrars[groupName], numbers: groupedNumbers[groupName], })); const source = fs.readFileSync("static/templates/admin/user.html", "utf8"); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); client.release(); } catch (error) { console.error(error); templateData.ifDBError = true; const source = fs.readFileSync( "static/templates/admin/user.html", "utf8" ); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); } }); app.post("/updateuser/:id", async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } if (req.session.userId != "admin") { return res.redirect("/signin"); } const id = req.params.id; const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); var { name, surname, email, phone, password, EditTransport, DeleteTransport, Update, } = req.body.formData; var devices = req.body.devices try { const query = ` UPDATE users SET name = $2, surname = $3, email = $4, phone = $5, password = $6, editTransport = $7, deleteTransport = $8, update = $9, devices = $10 WHERE id = $1 RETURNING *; `; const values = [ id, name, surname, email, phone, password, EditTransport, DeleteTransport, Update, devices, ]; const result = await client.query(query, values); const updatedRow = result.rows[0]; // console.log("Updated row:", updatedRow); res.send("Data updated successfully"); } catch (error) { console.error("Error updating data:", error); res.status(500).send("An error occurred while updating data"); } finally { client.release(); } }); async function videos(req, res) { if (req.session.userId === undefined) { return res.redirect("/signin"); } const userInfo = await getUserInfo(req.session.userId); let templateData = { SERVER_IP: process.env.SERVER_IP, Organisation: userInfo.Organisation, User: userInfo.User, UserInfo: userInfo.Users, isAdmin: req.session.userId === 'admin', ifDBError: false, Registrars: [], Groups: [], }; try { const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); let serialValues = []; if (!templateData.isAdmin) { const userDevicesQuery = ` SELECT devices FROM users WHERE id = $1 `; const userDevicesResult = await client.query(userDevicesQuery, [req.session.userId]); if (userDevicesResult.rows[0].devices.length > 0) { serialValues = userDevicesResult.rows[0].devices; } } const minuteInMillis = 60 * 1000; // Получаем список групп и их идентификаторов из таблицы groups const groupsQuery = "SELECT id, name FROM groups"; const groupsResult = await client.query(groupsQuery); const groupsMap = {}; groupsResult.rows.forEach((group) => { groupsMap[group.id] = group.name; }); // Выполняем запрос, чтобы получить все данные из таблицы registrars const queryRegistrars = ` SELECT id, serial, channels, lastkeepalive, "group", name, plate, sim, ip, port, number FROM registrars ${!templateData.isAdmin ? 'WHERE serial = ANY($1)' : ''} ORDER BY id `; const registrarsResult = await client.query(queryRegistrars, templateData.isAdmin ? [] : [serialValues]); const allRegistrars = registrarsResult.rows; const groupedRegistrars = {}; allRegistrars.forEach((registrar) => { const groupName = groupsMap[registrar.group] || "Другое"; // Используем "Другое", если группа неизвестна if (!groupedRegistrars[groupName]) { groupedRegistrars[groupName] = []; } groupedRegistrars[groupName].push({ id: registrar.id, serial: registrar.serial, channels: registrar.channels, status: Date.now() - Date.parse(registrar.lastkeepalive) <= minuteInMillis, name: registrar.name, group: groupsMap[registrar.group] || "Другое", plate: registrar.plate, sim: registrar.sim, ip: registrar.ip, port: registrar.port, number: registrar.number, }); }); templateData.Registrars = allRegistrars.map((registrar) => ({ id: registrar.id, serial: registrar.serial, channels: registrar.channels, status: Date.now() - Date.parse(registrar.lastkeepalive) <= minuteInMillis, name: registrar.name, group: groupsMap[registrar.group] || "Другое", plate: registrar.plate, sim: registrar.sim, ip: registrar.ip, port: registrar.port, })); templateData.Groups = Object.keys(groupedRegistrars).map((groupName) => ({ name: groupName, devices: groupedRegistrars[groupName], })); // console.log(templateData); const source = fs.readFileSync("static/templates/videos/playback.html", "utf8"); const template = handlebars.compile(source); const resultHTML = template(templateData); res.send(resultHTML); client.release(); } catch (error) { console.error(error); templateData.ifDBError = true; const source = fs.readFileSync("static/templates/videos/playback.html", "utf8"); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); } } async function videoExport(req, res) { if (req.session.userId === undefined) { return res.redirect("/signin"); } const userInfo = await getUserInfo(req.session.userId); let templateData = { SERVER_IP: process.env.SERVER_IP, Organisation: userInfo.Organisation, User: userInfo.User, UserInfo: userInfo.Users, isAdmin: req.session.userId === 'admin', ifDBError: false, Registrars: [], Groups: [], }; try { const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); let serialValues = []; if (!templateData.isAdmin) { const userDevicesQuery = ` SELECT devices FROM users WHERE id = $1 `; const userDevicesResult = await client.query(userDevicesQuery, [req.session.userId]); if (userDevicesResult.rows[0].devices.length > 0) { serialValues = userDevicesResult.rows[0].devices; } } const minuteInMillis = 60 * 1000; // Получаем список групп и их идентификаторов из таблицы groups const groupsQuery = "SELECT id, name FROM groups"; const groupsResult = await client.query(groupsQuery); const groupsMap = {}; groupsResult.rows.forEach((group) => { groupsMap[group.id] = group.name; }); // Выполняем запрос, чтобы получить все данные из таблицы registrars const queryRegistrars = ` SELECT id, serial, channels, lastkeepalive, "group", name, plate, sim, ip, port, number FROM registrars ${!templateData.isAdmin ? 'WHERE serial = ANY($1)' : ''} ORDER BY id `; const registrarsResult = await client.query(queryRegistrars, templateData.isAdmin ? [] : [serialValues]); const allRegistrars = registrarsResult.rows; const groupedRegistrars = {}; allRegistrars.forEach((registrar) => { const groupName = groupsMap[registrar.group] || "Другое"; // Используем "Другое", если группа неизвестна if (!groupedRegistrars[groupName]) { groupedRegistrars[groupName] = []; } groupedRegistrars[groupName].push({ id: registrar.id, serial: registrar.serial, channels: registrar.channels, status: Date.now() - Date.parse(registrar.lastkeepalive) <= minuteInMillis, name: registrar.name, group: groupsMap[registrar.group] || "Другое", plate: registrar.plate, sim: registrar.sim, ip: registrar.ip, port: registrar.port, number: registrar.number }); }); templateData.Registrars = allRegistrars.map((registrar) => ({ id: registrar.id, serial: registrar.serial, channels: registrar.channels, status: Date.now() - Date.parse(registrar.lastkeepalive) <= minuteInMillis, name: registrar.name, group: groupsMap[registrar.group] || "Другое", plate: registrar.plate, sim: registrar.sim, ip: registrar.ip, port: registrar.port, })); templateData.Groups = Object.keys(groupedRegistrars).map((groupName) => ({ name: groupName, devices: groupedRegistrars[groupName], })); // console.log(templateData); const source = fs.readFileSync("static/templates/videos/export.html", "utf8"); const template = handlebars.compile(source); const resultHTML = template(templateData); res.send(resultHTML); client.release(); } catch (error) { console.error(error); templateData.ifDBError = true; const source = fs.readFileSync("static/templates/videos/export.html", "utf8"); const template = handlebars.compile(source); const resultT = template(templateData); res.send(resultT); } } app.get('/getData', async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } const selectedSerial = req.query.serial; const selectedDate = req.query.selectedDate; const selectedTime = req.query.selectedTime; const selectedChannel = req.query.selectedChannel; try { const successResponse = await axios.get(`http://${process.env.SERVER_IP}:8080/http/filelist/request?serial=${selectedSerial}&querytime=${selectedDate}&channel=${selectedChannel}`); if (successResponse.data.SUCCESS) { await new Promise(resolve => setTimeout(resolve, 7000)); const dataResponse = await axios.get(`http://${process.env.SERVER_IP}:8080/http/filelist/get?serial=${selectedSerial}&querytime=${selectedDate}&channel=${selectedChannel}`); if (successResponse.data.SUCCESS) { const dataId = dataResponse.data.DATAID; const dateRanges = dataResponse.data.DATA; let dataFound = false; let selectedDataId = null; const selectedDateTime = moment(selectedDate + selectedTime, 'YYYYMMDDHHmmss').valueOf(); if (dateRanges.length === 1) { // Если в массиве DATA только одно значение const [startRange, endRange] = dateRanges[0].split('-'); const startDateTime = moment(startRange, 'YYYYMMDDHHmmss').valueOf(); const endDateTime = moment(endRange, 'YYYYMMDDHHmmss').valueOf(); if (!isNaN(selectedDateTime) && !isNaN(startDateTime) && !isNaN(endDateTime)) { if (selectedDateTime >= startDateTime && selectedDateTime <= endDateTime) { dataFound = true; selectedDataId = dataId[0]; } } else { console.error("Неверный формат данных для сравнения."); } } else { // Если в массиве DATA больше одного значения for (let i = 0; i < dateRanges.length; i++) { const [startRange, endRange] = dateRanges[i].split('-'); const startDateTime = moment(startRange, 'YYYYMMDDHHmmss').valueOf(); const endDateTime = moment(endRange, 'YYYYMMDDHHmmss').valueOf(); if (!isNaN(selectedDateTime) && !isNaN(startDateTime) && !isNaN(endDateTime)) { if (selectedDateTime >= startDateTime && selectedDateTime <= endDateTime) { dataFound = true; selectedDataId = dataId[i]; break; } } else { console.error("Неверный формат данных для сравнения."); } } } if (dataFound) { // Здесь можно отправить запрос скоростей и отрисовать график res.json({ success: true, dataId: selectedDataId }); } else { res.json({ success: false, message: 'Данных для выбранного периода нет' }); } }} else { res.json({ success: false, message: 'Ошибка при получении данных' }); } } catch (error) { console.error('Ошибка при отправке запроса:', error); res.json({ success: false, message: 'Ошибка при отправке запроса' }); } }); app.post("/getspeedarchive", async (req, res) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } const { serial, datetime } = req.body; const formattedDateTime = new Date(datetime).toISOString(); const pool = new Pool({ user: DB_User, host: DB_Host, database: DB_Name, password: DB_Password, port: DB_Port, }); const client = await pool.connect(); // Запрос для получения первой и последней временных отметок const timeRangeQuery = ` SELECT MIN(time) as min_time, MAX(time) as max_time FROM geo WHERE serial = $1 AND time >= $2 AND time <= $3; `; const startTime = new Date(formattedDateTime); startTime.setMinutes(0, 0, 0); // Округление до начала часа const endTime = new Date(startTime); endTime.setHours(endTime.getHours() + 1); // Первый запрос для получения временных отметок pool.query(timeRangeQuery, [serial, startTime, endTime], (error, timeResults) => { if (error) { console.error("Ошибка при выполнении SQL-запроса:", error); res.status(500).json({ error: "Ошибка на сервере" }); } else { const { min_time, max_time } = timeResults.rows[0]; // Запрос для получения данных скорости и геолокации const sqlQuery = ` SELECT speed, latitude, longitude, time FROM geo WHERE serial = $1 AND time >= $2 AND time <= $3; `; pool.query(sqlQuery, [serial, startTime, endTime], (error, results) => { if (error) { console.error("Ошибка при выполнении SQL-запроса:", error); res.status(500).json({ error: "Ошибка на сервере" }); } else { const data = results.rows.map((row) => ({ speed: row.speed > 150 ? row.speed / 100 : row.speed, geo: { latitude: row.latitude, longitude: row.longitude, }, time: row.time.toLocaleTimeString("ru-RU", { hour: "2-digit", minute: "2-digit", hour12: false, }), })); // Функция для сравнения времени в формате "час:минута" function compareTime(a, b) { return new Date('1970-01-01 ' + a.time) - new Date('1970-01-01 ' + b.time); } // Сортируем массив данных data.sort(compareTime); // Разделяем отсортированный массив обратно на отдельные массивы const transformedSpeeds = data.map((item) => item.speed); const geoData = data.map((item) => item.geo); const names = data.map((item) => item.time); res.json({ speeds: transformedSpeeds, geo: geoData, names }); } }); } }); }); const port = 8081; app.listen(port, () => { console.log(`Server is running on port ${port}`); }); app.use((req, res, next) => { if (req.session.userId === undefined) { return res.redirect("/signin"); } res.sendFile(path.join(__dirname, "static/templates/404.html")); });