5273 lines
144 KiB
JavaScript
5273 lines
144 KiB
JavaScript
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 session = require("express-session");
|
||
const bcrypt = require("bcrypt");
|
||
|
||
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/update", update);
|
||
app.get("/devices/groups", groups);
|
||
app.get("/videos", videos);
|
||
app.get("/videos/export", videoExport);
|
||
app.get("/settings", settings);
|
||
app.get("/documentation", documentation);
|
||
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.API_ADDRESS}/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 = {
|
||
VIRTUAL_HOST: process.env.VIRTUAL_HOST,
|
||
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', CURRENT_DATE - INTERVAL '10 days') + (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 >= CURRENT_DATE - INTERVAL '11 days'
|
||
AND time <= CURRENT_DATE + INTERVAL '1 day'
|
||
${!templateData.isAdmin ? "AND serial = ANY($1)" : ""}
|
||
ORDER BY evtuuid, time DESC
|
||
) 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', CURRENT_DATE - INTERVAL '21 days') + (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 >= CURRENT_DATE - INTERVAL '21 days'
|
||
AND time <= CURRENT_DATE + INTERVAL '10 day'
|
||
${!templateData.isAdmin ? "AND serial = ANY($1)" : ""}
|
||
ORDER BY evtuuid, time DESC
|
||
) 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 >= CURRENT_DATE - INTERVAL '10 days'
|
||
AND time <= CURRENT_DATE + INTERVAL '1 day'
|
||
${!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);
|
||
}
|
||
}
|
||
|
||
async function checkLastKeepAlive(serial) {
|
||
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();
|
||
|
||
try {
|
||
const lastKeepAliveQuery = `SELECT lastkeepalive FROM registrars WHERE serial = $1`;
|
||
const lastKeepAliveResult = await client.query(lastKeepAliveQuery, [
|
||
serial,
|
||
]);
|
||
|
||
if (lastKeepAliveResult.rows.length > 0) {
|
||
const lastKeepAlive = lastKeepAliveResult.rows[0].lastkeepalive;
|
||
const currentTime = new Date();
|
||
const lastKeepAliveTime = new Date(lastKeepAlive);
|
||
const minutesDifference =
|
||
(currentTime - lastKeepAliveTime) / (1000 * 60);
|
||
|
||
if (minutesDifference > 1) {
|
||
return false; // lastkeepalive старше минуты
|
||
} else {
|
||
return true; // lastkeepalive в пределах минуты
|
||
}
|
||
} else {
|
||
return false; // Устройство не найдено
|
||
}
|
||
} finally {
|
||
client.release();
|
||
}
|
||
} catch (error) {
|
||
console.error("Ошибка при проверке lastkeepalive:", error);
|
||
throw new Error("Произошла ошибка при проверке lastkeepalive.");
|
||
}
|
||
}
|
||
|
||
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,
|
||
});
|
||
|
||
let templateData = {
|
||
Page: "",
|
||
};
|
||
|
||
const page = req.query.page || "";
|
||
|
||
if (page) {
|
||
templateData.Page = page;
|
||
}
|
||
|
||
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 {
|
||
const source = fs.readFileSync("static/templates/signin.html", "utf8");
|
||
const template = handlebars.compile(source);
|
||
const resultT = template(templateData);
|
||
res.send(resultT);
|
||
}
|
||
});
|
||
}
|
||
|
||
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 hashedPassword = await bcrypt.hash(password, saltRounds);
|
||
|
||
const insertQuery =
|
||
"INSERT INTO main (organisation, login, password) VALUES ($1, $2, $3)";
|
||
await pool.query(insertQuery, [name, login, hashedPassword]);
|
||
|
||
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 login, password FROM main WHERE login = $1",
|
||
[email]
|
||
);
|
||
|
||
const mainUser = mainQuery.rows[0];
|
||
|
||
if (mainUser) {
|
||
const mainPasswordMatch = await bcrypt.compare(
|
||
password,
|
||
mainUser.password
|
||
);
|
||
|
||
if (mainPasswordMatch) {
|
||
req.session.userId = "admin";
|
||
|
||
console.log("Авторизация успешна (админ)");
|
||
return res.status(200).json({ message: "Авторизация успешна (админ)" });
|
||
}
|
||
}
|
||
|
||
const userQuery = await pool.query(
|
||
"SELECT id, password FROM users WHERE email = $1",
|
||
[email]
|
||
);
|
||
|
||
const user = userQuery.rows[0];
|
||
|
||
if (!user) {
|
||
return res
|
||
.status(401)
|
||
.json({ message: "Неправильное имя пользователя или пароль" });
|
||
}
|
||
|
||
const passwordMatch = await bcrypt.compare(password, user.password);
|
||
|
||
if (passwordMatch) {
|
||
req.session.userId = user.id;
|
||
|
||
console.log("Авторизация успешна");
|
||
return res.status(200).json({ message: "Авторизация успешна" });
|
||
} else {
|
||
return res
|
||
.status(401)
|
||
.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?page=live");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
let templateData = {
|
||
VIRTUAL_HOST: process.env.VIRTUAL_HOST,
|
||
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, r.number, 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($1)" : ""}
|
||
ORDER BY evtuuid, time DESC
|
||
) 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 - NOW())))) AS row_num
|
||
FROM geo
|
||
) AS g ON a.serial = g.serial AND g.row_num = 1
|
||
ORDER BY a.time DESC
|
||
LIMIT 100;
|
||
`;
|
||
const alarms = await client.query(
|
||
subquery,
|
||
templateData.isAdmin ? [] : [serialValues]
|
||
);
|
||
|
||
function formatDate(date) {
|
||
const options = {
|
||
year: "2-digit",
|
||
month: "2-digit",
|
||
day: "2-digit",
|
||
hour: "2-digit",
|
||
minute: "2-digit",
|
||
hour12: false,
|
||
};
|
||
|
||
const dateString = date.toISOString().replace("T", " ").slice(0, 19);
|
||
|
||
const [datePart, timePart] = dateString.split(" ");
|
||
const [year, month, day] = datePart.split("-");
|
||
const [hour, minute, second] = timePart.split(":");
|
||
|
||
const formattedDate = `${("0" + day).slice(-2)}.${("0" + month).slice(
|
||
-2
|
||
)}.${year.slice(-2)} ${("0" + hour).slice(-2)}:${("0" + minute).slice(
|
||
-2
|
||
)}`;
|
||
|
||
return formattedDate;
|
||
}
|
||
|
||
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),
|
||
number: alarm.number,
|
||
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, our_registrator
|
||
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,
|
||
ourreg: registrar.our_registrator,
|
||
});
|
||
});
|
||
|
||
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?page=live");
|
||
}
|
||
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?page=reports");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
let templateData = {
|
||
VIRTUAL_HOST: process.env.VIRTUAL_HOST,
|
||
Organisation: userInfo.Organisation,
|
||
User: userInfo.User,
|
||
UserInfo: userInfo.Users,
|
||
isAdmin: req.session.userId === "admin",
|
||
ifDBError: false,
|
||
Registrars: [],
|
||
Groups: [],
|
||
Count: 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();
|
||
|
||
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, r.number
|
||
FROM (
|
||
SELECT DISTINCT ON (evtuuid) evtuuid, id, cmdno, time, serial, st
|
||
FROM alarms
|
||
WHERE alarmtype = 56
|
||
${!templateData.isAdmin ? "AND serial = ANY($1)" : ""}
|
||
ORDER BY evtuuid, time DESC
|
||
) 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 - NOW())))) AS row_num
|
||
FROM geo
|
||
) AS g ON a.serial = g.serial AND g.row_num = 1
|
||
ORDER BY a.time DESC
|
||
LIMIT 14;
|
||
`;
|
||
const alarms = await client.query(
|
||
query,
|
||
templateData.isAdmin ? [] : [serialValues]
|
||
);
|
||
|
||
function formatDate(date) {
|
||
const options = {
|
||
year: "2-digit",
|
||
month: "2-digit",
|
||
day: "2-digit",
|
||
hour: "2-digit",
|
||
minute: "2-digit",
|
||
hour12: false,
|
||
};
|
||
|
||
const dateString = date.toISOString().replace("T", " ").slice(0, 19);
|
||
|
||
const [datePart, timePart] = dateString.split(" ");
|
||
const [year, month, day] = datePart.split("-");
|
||
const [hour, minute, second] = timePart.split(":");
|
||
|
||
const formattedDate = `${("0" + day).slice(-2)}.${("0" + month).slice(
|
||
-2
|
||
)}.${year.slice(-2)} ${("0" + hour).slice(-2)}:${("0" + minute).slice(
|
||
-2
|
||
)}`;
|
||
|
||
return formattedDate;
|
||
}
|
||
|
||
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),
|
||
number: alarm.number,
|
||
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 countQueryText = `
|
||
SELECT COUNT(*) AS total
|
||
FROM (
|
||
SELECT DISTINCT a.evtuuid
|
||
FROM alarms 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 - NOW())))) AS row_num
|
||
FROM geo
|
||
) AS g ON a.serial = g.serial AND g.row_num = 1
|
||
WHERE a.alarmtype = 56
|
||
${!templateData.isAdmin ? "AND a.serial = ANY($1)" : ""}
|
||
) AS unique_events
|
||
`;
|
||
|
||
const countResult = await pool.query(
|
||
countQueryText,
|
||
templateData.isAdmin ? [] : [serialValues]
|
||
);
|
||
templateData.Count = countResult.rows[0].total;
|
||
|
||
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.post("/getreports", async (req, res) => {
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin?page=reports");
|
||
}
|
||
try {
|
||
const pool = new Pool({
|
||
user: DB_User,
|
||
host: DB_Host,
|
||
database: DB_Name,
|
||
password: DB_Password,
|
||
port: DB_Port,
|
||
});
|
||
|
||
let serialValues = [];
|
||
if (req.session.userId != "admin") {
|
||
const userDevicesQuery = `
|
||
SELECT devices
|
||
FROM users
|
||
WHERE id = $1
|
||
`;
|
||
const userDevicesResult = await pool.query(userDevicesQuery, [
|
||
req.session.userId,
|
||
]);
|
||
|
||
if (userDevicesResult.rows[0].devices.length > 0) {
|
||
serialValues = userDevicesResult.rows[0].devices;
|
||
}
|
||
}
|
||
|
||
const { page, timeRangeStart, timeRangeEnd, serials, searchText } =
|
||
req.body;
|
||
|
||
let timeRangeStartCheck = timeRangeStart;
|
||
let timeRangeEndCheck = timeRangeEnd;
|
||
let serialsCheck = serials;
|
||
|
||
console.log(req.body);
|
||
|
||
if (!timeRangeStartCheck || !timeRangeEndCheck || serialsCheck.length < 1) {
|
||
const minMaxSerialQuery = `
|
||
SELECT
|
||
MIN(time) AS min_date,
|
||
MAX(time) AS max_date,
|
||
ARRAY_AGG(DISTINCT serial) AS unique_serials
|
||
FROM
|
||
alarms;
|
||
`;
|
||
|
||
const minMaxDateResult = await pool.query(minMaxSerialQuery);
|
||
|
||
if (!timeRangeStartCheck) {
|
||
timeRangeStartCheck = minMaxDateResult.rows[0].min_date;
|
||
}
|
||
|
||
if (!timeRangeEndCheck) {
|
||
timeRangeEndCheck = minMaxDateResult.rows[0].max_date;
|
||
}
|
||
|
||
if (serialsCheck.length < 1) {
|
||
if (req.session.userId != "admin") {
|
||
serialsCheck = serialValues;
|
||
} else {
|
||
serialsCheck = minMaxDateResult.rows[0].unique_serials;
|
||
}
|
||
}
|
||
}
|
||
|
||
const violationsMapping = {
|
||
0: "усталость",
|
||
1: "водитель пропал",
|
||
2: "разговор по телефону",
|
||
3: "курение за рулём",
|
||
4: "водитель отвлекся",
|
||
5: "выезд с полосы движения",
|
||
6: "!!! лобовое столкновение",
|
||
7: "скорость превышена",
|
||
8: "распознавание номерных знаков",
|
||
9: "!! маленькое расстояние спереди",
|
||
10: "водитель зевает",
|
||
11: "!!! столкновение с пешеходом",
|
||
12: "проходы переполнены",
|
||
13: "!! посадка/высадка вне остановки",
|
||
14: "!! смена полосы с нарушением ПДД",
|
||
15: "! включенный телефон у водителя",
|
||
16: "!!! ремень безопасности",
|
||
17: "проверка не удалась",
|
||
18: "слепые зоны справа",
|
||
19: "!!! заднее столкновение",
|
||
20: "!!! управление без рук",
|
||
21: "!! управление одной рукой",
|
||
22: "очки, блокирующие инфракрасное излучение",
|
||
23: "слепые зоны слева",
|
||
24: "помехи для пассажиров",
|
||
25: "на перекрестке ограничена скорость",
|
||
26: "обнаружен перекресток",
|
||
27: "пешеходы на переходе",
|
||
28: "! неучтивое отношение к пешеходам",
|
||
29: "обнаружен пешеходный переход",
|
||
30: "водитель матерится",
|
||
};
|
||
|
||
const idList = Object.entries(violationsMapping)
|
||
.filter(([id, violation]) => violation.includes(searchText.toLowerCase()))
|
||
.map(([id, violation]) => id);
|
||
|
||
console.log(idList);
|
||
|
||
const searchConditions = [
|
||
"a.evtuuid::TEXT ILIKE $4",
|
||
"a.id::TEXT ILIKE $4",
|
||
"r.plate::TEXT ILIKE $4",
|
||
"a.serial::TEXT ILIKE $4",
|
||
"g.latitude::TEXT ILIKE $4",
|
||
"g.longitude::TEXT ILIKE $4",
|
||
];
|
||
|
||
const countQueryText = `
|
||
SELECT COUNT(*) AS total
|
||
FROM (
|
||
SELECT DISTINCT a.evtuuid
|
||
FROM alarms 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 - NOW())))) AS row_num
|
||
FROM geo
|
||
) AS g ON a.serial = g.serial AND g.row_num = 1
|
||
WHERE a.alarmtype = 56
|
||
AND a.time >= $1::timestamp
|
||
AND a.time <= $2::timestamp
|
||
AND a.serial = ANY($3)
|
||
${
|
||
searchText
|
||
? `AND (${
|
||
idList.length > 0 ? "st = ANY($5) OR" : ""
|
||
} (${searchConditions.join(" OR ")}))`
|
||
: ""
|
||
}
|
||
) AS unique_events;
|
||
`;
|
||
|
||
const countValues = [timeRangeStartCheck, timeRangeEndCheck, serialsCheck];
|
||
|
||
if (searchText.length > 0) {
|
||
countValues.push(`%${searchText}%`);
|
||
}
|
||
|
||
if (idList.length > 0 && idList.length !== 31) {
|
||
countValues.push(idList);
|
||
}
|
||
|
||
const countResult = await pool.query(countQueryText, countValues);
|
||
const totalCount = countResult.rows[0].total;
|
||
|
||
const queryConditions = [
|
||
"a.evtuuid::TEXT ILIKE $6",
|
||
"a.id::TEXT ILIKE $6",
|
||
"r.plate::TEXT ILIKE $6",
|
||
"a.serial::TEXT ILIKE $6",
|
||
"g.latitude::TEXT ILIKE $6",
|
||
"g.longitude::TEXT ILIKE $6",
|
||
];
|
||
|
||
const queryText = `
|
||
SELECT a.evtuuid, a.id, a.cmdno, a.time, a.serial, a.st, r.plate, g.latitude, g.longitude, r.number
|
||
FROM (
|
||
SELECT DISTINCT ON (evtuuid) evtuuid, id, cmdno, time, serial, st
|
||
FROM alarms
|
||
WHERE alarmtype = 56
|
||
AND time >= $1::timestamp
|
||
AND time <= $2::timestamp
|
||
ORDER BY evtuuid, time DESC
|
||
) 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 - NOW())))) AS row_num
|
||
FROM geo
|
||
) AS g ON a.serial = g.serial AND g.row_num = 1
|
||
WHERE a.time >= $1::timestamp
|
||
AND a.time <= $2::timestamp
|
||
AND a.serial = ANY($3)
|
||
${
|
||
searchText
|
||
? `AND (${
|
||
idList.length > 0 ? "st = ANY($7) OR" : ""
|
||
} (${queryConditions.join(" OR ")}))`
|
||
: ``
|
||
}
|
||
ORDER BY a.time DESC
|
||
OFFSET $4 LIMIT $5;
|
||
`;
|
||
|
||
const values = [
|
||
timeRangeStartCheck,
|
||
timeRangeEndCheck,
|
||
serialsCheck,
|
||
(page - 1) * 14,
|
||
14,
|
||
];
|
||
|
||
if (searchText.length > 0) {
|
||
values.push(`%${searchText}%`);
|
||
}
|
||
|
||
if (idList.length > 0 && idList.length !== 31) {
|
||
values.push(idList);
|
||
}
|
||
|
||
const result = await pool.query(queryText, values);
|
||
|
||
function formatDate(date) {
|
||
const options = {
|
||
year: "2-digit",
|
||
month: "2-digit",
|
||
day: "2-digit",
|
||
hour: "2-digit",
|
||
minute: "2-digit",
|
||
hour12: false,
|
||
};
|
||
|
||
const dateString = date.toISOString().replace("T", " ").slice(0, 19);
|
||
|
||
const [datePart, timePart] = dateString.split(" ");
|
||
const [year, month, day] = datePart.split("-");
|
||
const [hour, minute, second] = timePart.split(":");
|
||
|
||
const formattedDate = `${("0" + day).slice(-2)}.${("0" + month).slice(
|
||
-2
|
||
)}.${year.slice(-2)} ${("0" + hour).slice(-2)}:${("0" + minute).slice(
|
||
-2
|
||
)}`;
|
||
|
||
return formattedDate;
|
||
}
|
||
|
||
const Alarms = result.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),
|
||
number: alarm.number,
|
||
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),
|
||
};
|
||
});
|
||
|
||
res.json({
|
||
total: totalCount,
|
||
data: Alarms,
|
||
});
|
||
} catch (error) {
|
||
console.error("Error handling request:", error);
|
||
res.status(500).send("Internal Server Error");
|
||
}
|
||
});
|
||
|
||
app.get("/api/devices", async (req, res) => {
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin?page=live");
|
||
}
|
||
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",
|
||
hour12: false,
|
||
};
|
||
|
||
const dateString = date.toISOString().replace("T", " ").slice(0, 19);
|
||
|
||
const [datePart, timePart] = dateString.split(" ");
|
||
const [year, month, day] = datePart.split("-");
|
||
const [hour, minute, second] = timePart.split(":");
|
||
|
||
const formattedDate = `${("0" + day).slice(-2)}.${("0" + month).slice(
|
||
-2
|
||
)}.${year.slice(-2)} ${("0" + hour).slice(-2)}:${("0" + minute).slice(
|
||
-2
|
||
)}`;
|
||
|
||
return formattedDate;
|
||
}
|
||
|
||
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) => {
|
||
const id = req.params.id;
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin?page=reports/" + id);
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
|
||
let templateData = {
|
||
VIRTUAL_HOST: process.env.VIRTUAL_HOST,
|
||
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: "",
|
||
|
||
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
|
||
FROM alarms a
|
||
LEFT JOIN geo g ON a.geoid = g.id
|
||
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",
|
||
hour12: false,
|
||
};
|
||
|
||
const dateString = date.toISOString().replace("T", " ").slice(0, 19);
|
||
|
||
const [datePart, timePart] = dateString.split(" ");
|
||
const [year, month, day] = datePart.split("-");
|
||
const [hour, minute, second] = timePart.split(":");
|
||
|
||
const formattedDate = `${("0" + day).slice(-2)}.${("0" + month).slice(
|
||
-2
|
||
)}.${year.slice(-2)} ${("0" + hour).slice(-2)}:${("0" + minute).slice(
|
||
-2
|
||
)}`;
|
||
|
||
return formattedDate;
|
||
}
|
||
|
||
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.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) => {
|
||
const id = req.params.id;
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin?page=generate-pdf/" + id);
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
|
||
let templateData = {
|
||
VIRTUAL_HOST: process.env.VIRTUAL_HOST,
|
||
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: "",
|
||
|
||
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
|
||
FROM alarms a
|
||
LEFT JOIN geo g ON a.geoid = g.id
|
||
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",
|
||
hour12: false,
|
||
};
|
||
|
||
const dateString = date.toISOString().replace("T", " ").slice(0, 19);
|
||
|
||
const [datePart, timePart] = dateString.split(" ");
|
||
const [year, month, day] = datePart.split("-");
|
||
const [hour, minute, second] = timePart.split(":");
|
||
|
||
const formattedDate = `${("0" + day).slice(-2)}.${("0" + month).slice(
|
||
-2
|
||
)}.${year.slice(-2)} ${("0" + hour).slice(-2)}:${("0" + minute).slice(
|
||
-2
|
||
)}`;
|
||
|
||
return formattedDate;
|
||
}
|
||
|
||
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.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?page=devices");
|
||
}
|
||
|
||
let userInfo;
|
||
let templateData = {
|
||
VIRTUAL_HOST: process.env.VIRTUAL_HOST,
|
||
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 = {
|
||
VIRTUAL_HOST: process.env.VIRTUAL_HOST,
|
||
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);
|
||
}
|
||
}
|
||
}
|
||
|
||
app.get("/devices/device/system/:serial", async (req, res) => {
|
||
const serial = req.params.serial;
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin?page=devices/device/system/" + serial);
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.EditTransport) {
|
||
return res.redirect("/devices");
|
||
}
|
||
|
||
let templateData = {
|
||
VIRTUAL_HOST: process.env.VIRTUAL_HOST,
|
||
Organisation: userInfo.Organisation,
|
||
User: userInfo.User,
|
||
UserInfo: userInfo.Users,
|
||
isAdmin: req.session.userId === "admin",
|
||
ifDBError: false,
|
||
Serial: serial,
|
||
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();
|
||
|
||
const source = fs.readFileSync(
|
||
"static/templates/devices/system.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/system.html",
|
||
"utf8"
|
||
);
|
||
const template = handlebars.compile(source);
|
||
const resultT = template(templateData);
|
||
res.send(resultT);
|
||
}
|
||
});
|
||
|
||
app.get("/devices/device/:serial", async (req, res) => {
|
||
const serial = req.params.serial;
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin?page=devices/device/" + serial);
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.EditTransport) {
|
||
return res.redirect("/devices");
|
||
}
|
||
|
||
let templateData = {
|
||
VIRTUAL_HOST: process.env.VIRTUAL_HOST,
|
||
Organisation: userInfo.Organisation,
|
||
User: userInfo.User,
|
||
UserInfo: userInfo.Users,
|
||
isAdmin: req.session.userId === "admin",
|
||
ifDBError: false,
|
||
Serial: serial,
|
||
EditTransport: false,
|
||
DeleteTransport: false,
|
||
Update: false,
|
||
GroupsList: [],
|
||
|
||
Number: "",
|
||
Plate: "",
|
||
PlateColor: "",
|
||
Channels: "",
|
||
Protocol: "",
|
||
Ip: "",
|
||
Group: "",
|
||
Port: "",
|
||
Sim: "",
|
||
Imei: "",
|
||
Imsi: "",
|
||
Module: "",
|
||
Type: "",
|
||
Factory: "",
|
||
Capacity: "",
|
||
Engine: "",
|
||
Stanina: "",
|
||
Fuel: "",
|
||
Certificate: "",
|
||
Category: "",
|
||
Expire: "",
|
||
Consumption: "",
|
||
Region: "",
|
||
City: "",
|
||
Name: "",
|
||
Password: "",
|
||
Batch: "",
|
||
Release: "",
|
||
Installer: "",
|
||
Installation: "",
|
||
Description: "",
|
||
OurRegistrator: "",
|
||
};
|
||
|
||
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 * FROM registrars WHERE serial = $1";
|
||
const result = await client.query(query, [serial]);
|
||
|
||
const groupsQuery = "SELECT id, name FROM groups";
|
||
const groupsResult = await client.query(groupsQuery);
|
||
|
||
templateData.GroupsList = groupsResult.rows.map((row) => ({
|
||
id: row.id,
|
||
name: row.name,
|
||
}));
|
||
|
||
// Предполагается, что результат запроса содержит одну строку данных.
|
||
if (result.rows.length === 1) {
|
||
const rowData = result.rows[0];
|
||
|
||
// Заполнение данных из результата SQL запроса в объект templateData.
|
||
templateData.Number = rowData.number;
|
||
templateData.Plate = rowData.plate;
|
||
templateData.PlateColor = rowData.plate_color;
|
||
templateData.Channels = rowData.channels;
|
||
templateData.Protocol = rowData.protocol;
|
||
templateData.Ip = rowData.ip;
|
||
templateData.Group = rowData.group;
|
||
templateData.Port = rowData.port;
|
||
templateData.Sim = rowData.sim;
|
||
templateData.Imei = rowData.imei;
|
||
templateData.Imsi = rowData.imsi;
|
||
templateData.Module = rowData.module;
|
||
templateData.Type = rowData.auto;
|
||
templateData.Factory = rowData.factory;
|
||
templateData.Capacity = rowData.capacity;
|
||
templateData.Engine = rowData.engine;
|
||
templateData.Stanina = rowData.stanina;
|
||
templateData.Fuel = rowData.fuel;
|
||
templateData.Certificate = rowData.certificate;
|
||
templateData.Category = rowData.category;
|
||
templateData.Expire = rowData.certificate_exp;
|
||
templateData.Consumption = rowData.consumption;
|
||
templateData.Region = rowData.region;
|
||
templateData.City = rowData.city;
|
||
templateData.Name = rowData.name;
|
||
templateData.Password = rowData.password;
|
||
templateData.Batch = rowData.batch;
|
||
templateData.Release = rowData.release;
|
||
templateData.Installer = rowData.installer;
|
||
templateData.Installation = rowData.installation;
|
||
templateData.Description = rowData.description;
|
||
templateData.OurRegistrator = rowData.our_registrator;
|
||
}
|
||
|
||
const source = fs.readFileSync(
|
||
"static/templates/devices/device.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/device.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?page=devices/groups");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.EditTransport) {
|
||
return res.redirect("/signin");
|
||
}
|
||
let templateData = {
|
||
VIRTUAL_HOST: process.env.VIRTUAL_HOST,
|
||
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?page=devices/groups");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.EditTransport) {
|
||
return res.redirect("/devices");
|
||
}
|
||
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.API_ADDRESS}/http/parameters/request?serial=${serial}`,
|
||
{
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
},
|
||
data: JSON.stringify({
|
||
FIELDS: ["EOSD"],
|
||
}),
|
||
}
|
||
);
|
||
|
||
await new Promise((resolve) => setTimeout(resolve, 300));
|
||
|
||
const requestResponse2 = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/http/parameters/request?serial=${serial}`,
|
||
{
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
},
|
||
data: JSON.stringify({
|
||
FIELDS: ["GSP"],
|
||
}),
|
||
}
|
||
);
|
||
|
||
await new Promise((resolve) => setTimeout(resolve, 300));
|
||
|
||
const requestResponse3 = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/http/parameters/request?serial=${serial}`,
|
||
{
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
},
|
||
data: JSON.stringify({
|
||
FIELDS: ["TIMEP"],
|
||
}),
|
||
}
|
||
);
|
||
|
||
await new Promise((resolve) => setTimeout(resolve, 300));
|
||
|
||
const requestResponse5 = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/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.API_ADDRESS}/http/parameters/get?serial=${serial}`
|
||
);
|
||
|
||
return getResponse.data;
|
||
}
|
||
|
||
app.post("/main-parameters", async (req, res) => {
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.EditTransport) {
|
||
return res.redirect("/devices");
|
||
}
|
||
try {
|
||
const { serial } = req.body;
|
||
|
||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||
|
||
const requestResponse = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/http/parameters/request?serial=${serial}`,
|
||
{
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
},
|
||
data: JSON.stringify({
|
||
FIELDS: ["RIP", "VS"],
|
||
}),
|
||
}
|
||
);
|
||
|
||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||
|
||
const getResponse = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/http/parameters/get?serial=${serial}`
|
||
);
|
||
|
||
res.json(getResponse.data);
|
||
} catch (error) {
|
||
console.error(error);
|
||
res.status(500).json({ error: "Internal server error" });
|
||
}
|
||
});
|
||
|
||
app.put("/main-parameters", async (req, res) => {
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.EditTransport) {
|
||
return res.redirect("/devices");
|
||
}
|
||
const requestData = req.body;
|
||
const { serial } = req.query;
|
||
|
||
const { NUMBER, PLATE, VIN } = requestData;
|
||
|
||
const requestBody = {
|
||
RIP: {
|
||
BN: NUMBER,
|
||
BID: PLATE,
|
||
},
|
||
VS: {
|
||
VIN: VIN,
|
||
},
|
||
};
|
||
|
||
try {
|
||
const isLastKeepAliveValid = await checkLastKeepAlive(serial);
|
||
|
||
if (!isLastKeepAliveValid) {
|
||
return res
|
||
.status(400)
|
||
.send("Ошибка: lastkeepalive старше минуты или устройство не найдено.");
|
||
}
|
||
const response = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/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("/device-parameters", async (req, res) => {
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.EditTransport) {
|
||
return res.redirect("/devices");
|
||
}
|
||
try {
|
||
const { serial } = req.body;
|
||
|
||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||
|
||
const responseData = await getParameters(serial);
|
||
|
||
res.json(responseData);
|
||
} catch (error) {
|
||
console.error(error);
|
||
res.status(500).json({ error: "Internal server error" });
|
||
}
|
||
});
|
||
|
||
app.post("/ethernet-parameters", async (req, res) => {
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.EditTransport) {
|
||
return res.redirect("/devices");
|
||
}
|
||
try {
|
||
const { serial } = req.body;
|
||
|
||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||
|
||
const requestResponse = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/http/parameters/request?serial=${serial}`,
|
||
{
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
},
|
||
data: JSON.stringify({
|
||
FIELDS: ["ETHERNET", "KEYS"],
|
||
}),
|
||
}
|
||
);
|
||
|
||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||
|
||
const getResponse = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/http/parameters/get?serial=${serial}`
|
||
);
|
||
|
||
res.json(getResponse.data);
|
||
} catch (error) {
|
||
console.error(error);
|
||
res.status(500).json({ error: "Internal server error" });
|
||
}
|
||
});
|
||
|
||
app.put("/ethernet-parameters", async (req, res) => {
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.EditTransport) {
|
||
return res.redirect("/devices");
|
||
}
|
||
const requestData = req.body;
|
||
const { serial } = req.query;
|
||
|
||
const { IPMODE, IPADDR, SUBMASK, GATEWAY, DNSMODE, PDNS, ADNS, MAC } =
|
||
requestData;
|
||
|
||
const requestBody = {
|
||
ETHERNET: {
|
||
IPMODE: IPMODE,
|
||
PIP: {
|
||
IPADDR: IPADDR,
|
||
SUBMASK: SUBMASK,
|
||
GATEWAY: GATEWAY,
|
||
},
|
||
DNSMODE: DNSMODE,
|
||
DNS: {
|
||
PDNS: PDNS,
|
||
ADNS: ADNS,
|
||
},
|
||
},
|
||
KEYS: {
|
||
MAC: MAC,
|
||
},
|
||
};
|
||
|
||
try {
|
||
const isLastKeepAliveValid = await checkLastKeepAlive(serial);
|
||
|
||
if (!isLastKeepAliveValid) {
|
||
return res
|
||
.status(400)
|
||
.send("Ошибка: lastkeepalive старше минуты или устройство не найдено.");
|
||
}
|
||
const response = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/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("/wifi-parameters", async (req, res) => {
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.EditTransport) {
|
||
return res.redirect("/devices");
|
||
}
|
||
try {
|
||
const { serial } = req.body;
|
||
|
||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||
|
||
const requestResponse = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/http/parameters/request?serial=${serial}`,
|
||
{
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
},
|
||
data: JSON.stringify({
|
||
FIELDS: ["WIFI"],
|
||
}),
|
||
}
|
||
);
|
||
|
||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||
|
||
const getResponse = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/http/parameters/get?serial=${serial}`
|
||
);
|
||
|
||
res.json(getResponse.data);
|
||
} catch (error) {
|
||
console.error(error);
|
||
res.status(500).json({ error: "Internal server error" });
|
||
}
|
||
});
|
||
|
||
app.put("/wifi-parameters", async (req, res) => {
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.EditTransport) {
|
||
return res.redirect("/devices");
|
||
}
|
||
const requestData = req.body;
|
||
const { serial } = req.query;
|
||
|
||
const { WIFI, ESSID, ECRYPTTYPE, PWD, IPMODE, IPADDR, SUBMASK, GATEWAY } =
|
||
requestData;
|
||
|
||
const requestBody = {
|
||
WIFI: {
|
||
ENABLE: WIFI,
|
||
ESSID: ESSID,
|
||
ECRYPTTYPE: ECRYPTTYPE,
|
||
IPMODE: IPMODE,
|
||
PWD: PWD,
|
||
PIP: {
|
||
IPADDR: IPADDR,
|
||
SUBMASK: SUBMASK,
|
||
GATEWAY: GATEWAY,
|
||
},
|
||
},
|
||
};
|
||
|
||
try {
|
||
const isLastKeepAliveValid = await checkLastKeepAlive(serial);
|
||
|
||
if (!isLastKeepAliveValid) {
|
||
return res
|
||
.status(400)
|
||
.send("Ошибка: lastkeepalive старше минуты или устройство не найдено.");
|
||
}
|
||
const response = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/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("/communication-parameters", async (req, res) => {
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.EditTransport) {
|
||
return res.redirect("/devices");
|
||
}
|
||
try {
|
||
const { serial } = req.body;
|
||
|
||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||
|
||
const requestResponse = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/http/parameters/request?serial=${serial}`,
|
||
{
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
},
|
||
data: JSON.stringify({
|
||
FIELDS: ["M3G"],
|
||
}),
|
||
}
|
||
);
|
||
|
||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||
|
||
const getResponse = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/http/parameters/get?serial=${serial}`
|
||
);
|
||
|
||
res.json(getResponse.data);
|
||
} catch (error) {
|
||
console.error(error);
|
||
res.status(500).json({ error: "Internal server error" });
|
||
}
|
||
});
|
||
|
||
app.put("/communication-parameters", async (req, res) => {
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.EditTransport) {
|
||
return res.redirect("/devices");
|
||
}
|
||
|
||
const requestData = req.body;
|
||
const { serial } = req.query;
|
||
|
||
const { NM1, APN1, UN1, PW1, NM2, APN2, UN2, PW2, AT, TN1, TN2, TN3 } =
|
||
requestData;
|
||
|
||
const requestBody = {
|
||
M3G: {
|
||
M3M: {
|
||
AT: AT,
|
||
TN1: TN1,
|
||
TN2: TN2,
|
||
TN3: TN3,
|
||
},
|
||
MP: {
|
||
NM: NM1,
|
||
APN: APN1,
|
||
UN: UN1,
|
||
PW: PW1,
|
||
},
|
||
M4G: {
|
||
NM: NM2,
|
||
APN: APN2,
|
||
UN: UN2,
|
||
PW: PW2,
|
||
},
|
||
},
|
||
};
|
||
|
||
try {
|
||
const isLastKeepAliveValid = await checkLastKeepAlive(serial);
|
||
|
||
if (!isLastKeepAliveValid) {
|
||
return res
|
||
.status(400)
|
||
.send("Ошибка: lastkeepalive старше минуты или устройство не найдено.");
|
||
}
|
||
const response = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/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("/install-parameters", async (req, res) => {
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.EditTransport) {
|
||
return res.redirect("/devices");
|
||
}
|
||
try {
|
||
const { serial } = req.body;
|
||
|
||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||
|
||
const requestResponse = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/http/parameters/request?serial=${serial}`,
|
||
{
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
},
|
||
data: JSON.stringify({
|
||
FIELDS: ["MCMS"],
|
||
}),
|
||
}
|
||
);
|
||
|
||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||
|
||
const getResponse = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/http/parameters/get?serial=${serial}`
|
||
);
|
||
|
||
res.json(getResponse.data);
|
||
} catch (error) {
|
||
console.error(error);
|
||
res.status(500).json({ error: "Internal server error" });
|
||
}
|
||
});
|
||
|
||
app.post("/ai-parameters", async (req, res) => {
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.EditTransport) {
|
||
return res.redirect("/devices");
|
||
}
|
||
try {
|
||
const { serial } = req.body;
|
||
|
||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||
|
||
const requestResponse = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/http/parameters/request?serial=${serial}`,
|
||
{
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
},
|
||
data: JSON.stringify({
|
||
FIELDS: ["DSM"],
|
||
}),
|
||
}
|
||
);
|
||
|
||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||
|
||
const getResponse = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/http/parameters/get?serial=${serial}`
|
||
);
|
||
|
||
res.json(getResponse.data);
|
||
} catch (error) {
|
||
console.error(error);
|
||
res.status(500).json({ error: "Internal server error" });
|
||
}
|
||
});
|
||
|
||
app.put("/ai-parameters", async (req, res) => {
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.EditTransport) {
|
||
return res.redirect("/devices");
|
||
}
|
||
|
||
const requestData = req.body;
|
||
const { serial } = req.query;
|
||
|
||
const { DSMA, DSMFE, RWFE } = requestData;
|
||
|
||
const requestBody = {
|
||
DSM: {
|
||
DSMA: DSMA,
|
||
DSMFE: DSMFE,
|
||
RWFE: RWFE,
|
||
},
|
||
};
|
||
|
||
try {
|
||
const isLastKeepAliveValid = await checkLastKeepAlive(serial);
|
||
|
||
if (!isLastKeepAliveValid) {
|
||
return res
|
||
.status(400)
|
||
.send("Ошибка: lastkeepalive старше минуты или устройство не найдено.");
|
||
}
|
||
const response = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/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("/cameras-parameters", async (req, res) => {
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.EditTransport) {
|
||
return res.redirect("/devices");
|
||
}
|
||
try {
|
||
const { serial } = req.body;
|
||
|
||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||
|
||
const requestResponse = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/http/parameters/request?serial=${serial}`,
|
||
{
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
},
|
||
data: JSON.stringify({
|
||
FIELDS: ["MAIN"],
|
||
}),
|
||
}
|
||
);
|
||
|
||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||
|
||
const getResponse = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/http/parameters/get?serial=${serial}`
|
||
);
|
||
|
||
res.json(getResponse.data);
|
||
} catch (error) {
|
||
console.error(error);
|
||
res.status(500).json({ error: "Internal server error" });
|
||
}
|
||
});
|
||
|
||
app.put("/cameras-parameters", async (req, res) => {
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.EditTransport) {
|
||
return res.redirect("/devices");
|
||
}
|
||
|
||
const requestData = req.body;
|
||
const { serial } = req.query;
|
||
|
||
const { MAIN } = requestData;
|
||
|
||
const requestBody = {
|
||
MAIN: MAIN,
|
||
};
|
||
|
||
try {
|
||
const isLastKeepAliveValid = await checkLastKeepAlive(serial);
|
||
|
||
if (!isLastKeepAliveValid) {
|
||
return res
|
||
.status(400)
|
||
.send("Ошибка: lastkeepalive старше минуты или устройство не найдено.");
|
||
}
|
||
const response = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/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("/install-parameters", async (req, res) => {
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.EditTransport) {
|
||
return res.redirect("/devices");
|
||
}
|
||
|
||
const requestData = req.body;
|
||
const { serial } = req.query;
|
||
|
||
const { SP, M } = requestData;
|
||
|
||
const requestBody = {
|
||
MCMS: {
|
||
M: parseInt(M, 10),
|
||
SP: SP,
|
||
},
|
||
};
|
||
|
||
try {
|
||
const isLastKeepAliveValid = await checkLastKeepAlive(serial);
|
||
|
||
if (!isLastKeepAliveValid) {
|
||
return res
|
||
.status(400)
|
||
.send("Ошибка: lastkeepalive старше минуты или устройство не найдено.");
|
||
}
|
||
const response = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/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("/device-parameters", async (req, res) => {
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.EditTransport) {
|
||
return res.redirect("/devices");
|
||
}
|
||
// Получаем данные из PUT запроса
|
||
const requestData = req.body;
|
||
const { serial } = req.query;
|
||
|
||
// Извлекаем необходимые параметры
|
||
const {
|
||
DATEMOD,
|
||
TIMEFORMAT,
|
||
LANGUAGE,
|
||
GEOMOD,
|
||
TIMEZ,
|
||
NE,
|
||
TE,
|
||
VE,
|
||
SE,
|
||
GE,
|
||
DE,
|
||
TX,
|
||
TY,
|
||
SX,
|
||
SY,
|
||
VX,
|
||
VY,
|
||
GX,
|
||
GY,
|
||
NX,
|
||
NY,
|
||
DX,
|
||
DY,
|
||
} = requestData;
|
||
|
||
// Создаем JSON для GET запроса
|
||
const requestBody = {
|
||
TIMEP: {
|
||
DATEM: parseInt(DATEMOD, 10),
|
||
TIMEM: parseInt(TIMEFORMAT, 10),
|
||
TIMEZ: TIMEZ,
|
||
},
|
||
GSP: {
|
||
LANT: parseInt(LANGUAGE, 10),
|
||
GM: parseInt(GEOMOD, 10),
|
||
},
|
||
EOSD: [
|
||
{
|
||
GE: GE,
|
||
NE: NE,
|
||
SE: SE,
|
||
TE: TE,
|
||
VE: VE,
|
||
DE: DE,
|
||
TX: TX,
|
||
TY: TY,
|
||
SX: SX,
|
||
SY: SY,
|
||
VX: VX,
|
||
VY: VY,
|
||
GX: GX,
|
||
GY: GY,
|
||
NX: NX,
|
||
NY: NY,
|
||
DX: DX,
|
||
DY: DY,
|
||
},
|
||
{
|
||
GE: GE,
|
||
NE: NE,
|
||
SE: SE,
|
||
TE: TE,
|
||
VE: VE,
|
||
DE: DE,
|
||
TX: TX,
|
||
TY: TY,
|
||
SX: SX,
|
||
SY: SY,
|
||
VX: VX,
|
||
VY: VY,
|
||
GX: GX,
|
||
GY: GY,
|
||
NX: NX,
|
||
NY: NY,
|
||
DX: DX,
|
||
DY: DY,
|
||
},
|
||
{
|
||
GE: GE,
|
||
NE: NE,
|
||
SE: SE,
|
||
TE: TE,
|
||
VE: VE,
|
||
DE: DE,
|
||
TX: TX,
|
||
TY: TY,
|
||
SX: SX,
|
||
SY: SY,
|
||
VX: VX,
|
||
VY: VY,
|
||
GX: GX,
|
||
GY: GY,
|
||
NX: NX,
|
||
NY: NY,
|
||
DX: DX,
|
||
DY: DY,
|
||
},
|
||
{
|
||
GE: GE,
|
||
NE: NE,
|
||
SE: SE,
|
||
TE: TE,
|
||
VE: VE,
|
||
DE: DE,
|
||
TX: TX,
|
||
TY: TY,
|
||
SX: SX,
|
||
SY: SY,
|
||
VX: VX,
|
||
VY: VY,
|
||
GX: GX,
|
||
GY: GY,
|
||
NX: NX,
|
||
NY: NY,
|
||
DX: DX,
|
||
DY: DY,
|
||
},
|
||
{
|
||
GE: GE,
|
||
NE: NE,
|
||
SE: SE,
|
||
TE: TE,
|
||
VE: VE,
|
||
DE: DE,
|
||
TX: TX,
|
||
TY: TY,
|
||
SX: SX,
|
||
SY: SY,
|
||
VX: VX,
|
||
VY: VY,
|
||
GX: GX,
|
||
GY: GY,
|
||
NX: NX,
|
||
NY: NY,
|
||
DX: DX,
|
||
DY: DY,
|
||
},
|
||
{
|
||
GE: GE,
|
||
NE: NE,
|
||
SE: SE,
|
||
TE: TE,
|
||
VE: VE,
|
||
DE: DE,
|
||
TX: TX,
|
||
TY: TY,
|
||
SX: SX,
|
||
SY: SY,
|
||
VX: VX,
|
||
VY: VY,
|
||
GX: GX,
|
||
GY: GY,
|
||
NX: NX,
|
||
NY: NY,
|
||
DX: DX,
|
||
DY: DY,
|
||
},
|
||
{
|
||
GE: GE,
|
||
NE: NE,
|
||
SE: SE,
|
||
TE: TE,
|
||
VE: VE,
|
||
DE: DE,
|
||
TX: TX,
|
||
TY: TY,
|
||
SX: SX,
|
||
SY: SY,
|
||
VX: VX,
|
||
VY: VY,
|
||
GX: GX,
|
||
GY: GY,
|
||
NX: NX,
|
||
NY: NY,
|
||
DX: DX,
|
||
DY: DY,
|
||
},
|
||
{
|
||
GE: GE,
|
||
NE: NE,
|
||
SE: SE,
|
||
TE: TE,
|
||
VE: VE,
|
||
DE: DE,
|
||
TX: TX,
|
||
TY: TY,
|
||
SX: SX,
|
||
SY: SY,
|
||
VX: VX,
|
||
VY: VY,
|
||
GX: GX,
|
||
GY: GY,
|
||
NX: NX,
|
||
NY: NY,
|
||
DX: DX,
|
||
DY: DY,
|
||
},
|
||
{
|
||
GE: GE,
|
||
NE: NE,
|
||
SE: SE,
|
||
TE: TE,
|
||
VE: VE,
|
||
DE: DE,
|
||
TX: TX,
|
||
TY: TY,
|
||
SX: SX,
|
||
SY: SY,
|
||
VX: VX,
|
||
VY: VY,
|
||
GX: GX,
|
||
GY: GY,
|
||
NX: NX,
|
||
NY: NY,
|
||
DX: DX,
|
||
DY: DY,
|
||
},
|
||
{
|
||
GE: GE,
|
||
NE: NE,
|
||
SE: SE,
|
||
TE: TE,
|
||
VE: VE,
|
||
DE: DE,
|
||
TX: TX,
|
||
TY: TY,
|
||
SX: SX,
|
||
SY: SY,
|
||
VX: VX,
|
||
VY: VY,
|
||
GX: GX,
|
||
GY: GY,
|
||
NX: NX,
|
||
NY: NY,
|
||
DX: DX,
|
||
DY: DY,
|
||
},
|
||
{
|
||
GE: GE,
|
||
NE: NE,
|
||
SE: SE,
|
||
TE: TE,
|
||
VE: VE,
|
||
DE: DE,
|
||
TX: TX,
|
||
TY: TY,
|
||
SX: SX,
|
||
SY: SY,
|
||
VX: VX,
|
||
VY: VY,
|
||
GX: GX,
|
||
GY: GY,
|
||
NX: NX,
|
||
NY: NY,
|
||
DX: DX,
|
||
DY: DY,
|
||
},
|
||
{
|
||
GE: GE,
|
||
NE: NE,
|
||
SE: SE,
|
||
TE: TE,
|
||
VE: VE,
|
||
DE: DE,
|
||
TX: TX,
|
||
TY: TY,
|
||
SX: SX,
|
||
SY: SY,
|
||
VX: VX,
|
||
VY: VY,
|
||
GX: GX,
|
||
GY: GY,
|
||
NX: NX,
|
||
NY: NY,
|
||
DX: DX,
|
||
DY: DY,
|
||
},
|
||
{
|
||
GE: GE,
|
||
NE: NE,
|
||
SE: SE,
|
||
TE: TE,
|
||
VE: VE,
|
||
DE: DE,
|
||
TX: TX,
|
||
TY: TY,
|
||
SX: SX,
|
||
SY: SY,
|
||
VX: VX,
|
||
VY: VY,
|
||
GX: GX,
|
||
GY: GY,
|
||
NX: NX,
|
||
NY: NY,
|
||
DX: DX,
|
||
DY: DY,
|
||
},
|
||
{
|
||
GE: GE,
|
||
NE: NE,
|
||
SE: SE,
|
||
TE: TE,
|
||
VE: VE,
|
||
DE: DE,
|
||
TX: TX,
|
||
TY: TY,
|
||
SX: SX,
|
||
SY: SY,
|
||
VX: VX,
|
||
VY: VY,
|
||
GX: GX,
|
||
GY: GY,
|
||
NX: NX,
|
||
NY: NY,
|
||
DX: DX,
|
||
DY: DY,
|
||
},
|
||
{
|
||
GE: GE,
|
||
NE: NE,
|
||
SE: SE,
|
||
TE: TE,
|
||
VE: VE,
|
||
DE: DE,
|
||
TX: TX,
|
||
TY: TY,
|
||
SX: SX,
|
||
SY: SY,
|
||
VX: VX,
|
||
VY: VY,
|
||
GX: GX,
|
||
GY: GY,
|
||
NX: NX,
|
||
NY: NY,
|
||
DX: DX,
|
||
DY: DY,
|
||
},
|
||
{
|
||
GE: GE,
|
||
NE: NE,
|
||
SE: SE,
|
||
TE: TE,
|
||
VE: VE,
|
||
DE: DE,
|
||
TX: TX,
|
||
TY: TY,
|
||
SX: SX,
|
||
SY: SY,
|
||
VX: VX,
|
||
VY: VY,
|
||
GX: GX,
|
||
GY: GY,
|
||
NX: NX,
|
||
NY: NY,
|
||
DX: DX,
|
||
DY: DY,
|
||
},
|
||
],
|
||
};
|
||
|
||
// Отправляем GET запрос с JSON BODY
|
||
try {
|
||
const isLastKeepAliveValid = await checkLastKeepAlive(serial);
|
||
|
||
if (!isLastKeepAliveValid) {
|
||
return res
|
||
.status(400)
|
||
.send("Ошибка: lastkeepalive старше минуты или устройство не найдено.");
|
||
}
|
||
const response = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/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");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.EditTransport) {
|
||
return res.redirect("/devices");
|
||
}
|
||
// Получаем данные из PUT запроса
|
||
const camerasData = req.body;
|
||
const { serial } = req.query;
|
||
|
||
// Создаем JSON для GET запроса
|
||
const requestBody = {
|
||
MAIN: camerasData,
|
||
};
|
||
|
||
// Отправляем GET запрос с JSON BODY
|
||
try {
|
||
const isLastKeepAliveValid = await checkLastKeepAlive(serial);
|
||
|
||
if (!isLastKeepAliveValid) {
|
||
return res
|
||
.status(400)
|
||
.send("Ошибка: lastkeepalive старше минуты или устройство не найдено.");
|
||
}
|
||
const response = await axios.get(
|
||
`http://${process.env.API_ADDRESS}/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 userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.EditTransport) {
|
||
return res.redirect("/devices");
|
||
}
|
||
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,
|
||
vinNumber,
|
||
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,
|
||
ourRegistrator,
|
||
} = req.body;
|
||
|
||
if (ourRegistrator == "on") {
|
||
ourRegistrator = true;
|
||
} else {
|
||
ourRegistrator = false;
|
||
}
|
||
|
||
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,
|
||
vin = $32,
|
||
our_registrator = $33
|
||
WHERE serial = $34
|
||
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,
|
||
vinNumber,
|
||
ourRegistrator,
|
||
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("/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("/deletedevice", async (req, res) => {
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.DeleteTransport) {
|
||
return res.redirect("/devices");
|
||
}
|
||
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 registrars WHERE id = $1;";
|
||
const devicedata = 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");
|
||
}
|
||
if (req.session.userId != "admin") {
|
||
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 userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.EditTransport) {
|
||
return res.redirect("/devices");
|
||
}
|
||
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 userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.EditTransport) {
|
||
return res.redirect("/devices");
|
||
}
|
||
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 update(req, res) {
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin?page=devices/update");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
if (!userInfo.Update) {
|
||
return res.redirect("/signin");
|
||
}
|
||
let templateData = {
|
||
VIRTUAL_HOST: process.env.VIRTUAL_HOST,
|
||
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?page=settings");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
let templateData = {
|
||
VIRTUAL_HOST: process.env.VIRTUAL_HOST,
|
||
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 documentation(req, res) {
|
||
if (req.session.userId === undefined) {
|
||
let templateData = {
|
||
VIRTUAL_HOST: process.env.VIRTUAL_HOST,
|
||
};
|
||
|
||
const source = fs.readFileSync(
|
||
"static/templates/documentation-NA.html",
|
||
"utf8"
|
||
);
|
||
const template = handlebars.compile(source);
|
||
const resultT = template(templateData);
|
||
res.send(resultT);
|
||
return;
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
let templateData = {
|
||
VIRTUAL_HOST: process.env.VIRTUAL_HOST,
|
||
Organisation: userInfo.Organisation,
|
||
User: userInfo.User,
|
||
ifDBError: false,
|
||
UserInfo: userInfo.Users,
|
||
isAdmin: req.session.userId === "admin",
|
||
};
|
||
|
||
try {
|
||
const source = fs.readFileSync(
|
||
"static/templates/documentation.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/documentation.html",
|
||
"utf8"
|
||
);
|
||
const template = handlebars.compile(source);
|
||
const resultT = template(templateData);
|
||
res.send(resultT);
|
||
}
|
||
}
|
||
|
||
app.get("/download/:filename", (req, res) => {
|
||
const filename = req.params.filename;
|
||
const filePath = path.join(__dirname, "static", "docs", filename);
|
||
|
||
// Проверяем существование файла
|
||
const exists = require("fs").existsSync(filePath);
|
||
if (!exists) {
|
||
return res.status(404).send("File not found");
|
||
}
|
||
|
||
// Отправляем файл для скачивания
|
||
res.download(filePath, filename, (err) => {
|
||
if (err) {
|
||
console.error(err);
|
||
res.status(500).send("Internal Server Error");
|
||
}
|
||
});
|
||
});
|
||
|
||
async function organisation(req, res) {
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin?page=admin/organisation");
|
||
}
|
||
if (req.session.userId != "admin") {
|
||
return res.redirect("/signin?page=admin/organisation");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
let templateData = {
|
||
VIRTUAL_HOST: process.env.VIRTUAL_HOST,
|
||
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?page=admin");
|
||
}
|
||
if (req.session.userId != "admin") {
|
||
return res.redirect("/signin?page=admin");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
let templateData = {
|
||
VIRTUAL_HOST: process.env.VIRTUAL_HOST,
|
||
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-запроса для добавления пользователя
|
||
const saltRounds = 10;
|
||
|
||
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;
|
||
|
||
try {
|
||
const hashedPassword = await bcrypt.hash(password, saltRounds);
|
||
|
||
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, devices)
|
||
VALUES ($1, $2, $3, $4, $5, NOW(), $6)
|
||
RETURNING id
|
||
`;
|
||
|
||
const result = await client.query(query, [
|
||
name,
|
||
surname,
|
||
email,
|
||
phone,
|
||
hashedPassword,
|
||
"{}",
|
||
]);
|
||
|
||
// Освобождение клиента
|
||
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) => {
|
||
const id = req.params.id;
|
||
if (req.session.userId === undefined) {
|
||
return res.redirect("/signin?page=admin/user/" + id);
|
||
}
|
||
if (req.session.userId != "admin") {
|
||
return res.redirect("/signin?page=admin/user/" + id);
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
|
||
let templateData = {
|
||
VIRTUAL_HOST: process.env.VIRTUAL_HOST,
|
||
Organisation: userInfo.Organisation,
|
||
User: userInfo.User,
|
||
UserInfo: userInfo.Users,
|
||
isAdmin: req.session.userId === "admin",
|
||
ifDBError: false,
|
||
Id: id,
|
||
Name: "",
|
||
Surname: "",
|
||
Email: "",
|
||
Phone: "",
|
||
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.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 {
|
||
if (password === "" || password === undefined) {
|
||
const query = `
|
||
UPDATE users
|
||
SET
|
||
name = $2,
|
||
surname = $3,
|
||
email = $4,
|
||
phone = $5,
|
||
editTransport = $6,
|
||
deleteTransport = $7,
|
||
update = $8,
|
||
devices = $9
|
||
WHERE id = $1
|
||
RETURNING *;
|
||
`;
|
||
|
||
const values = [
|
||
id,
|
||
name,
|
||
surname,
|
||
email,
|
||
phone,
|
||
EditTransport,
|
||
DeleteTransport,
|
||
Update,
|
||
devices,
|
||
];
|
||
|
||
const result = await client.query(query, values);
|
||
} else {
|
||
const hashedPassword = await bcrypt.hash(password, saltRounds);
|
||
|
||
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,
|
||
hashedPassword,
|
||
EditTransport,
|
||
DeleteTransport,
|
||
Update,
|
||
devices,
|
||
];
|
||
|
||
const result = await client.query(query, values);
|
||
}
|
||
|
||
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?page=videos");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
let templateData = {
|
||
VIRTUAL_HOST: process.env.VIRTUAL_HOST,
|
||
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, our_registrator
|
||
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,
|
||
ourreg: registrar.our_registrator,
|
||
});
|
||
});
|
||
|
||
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,
|
||
ourreg: registrar.our_registrator,
|
||
}));
|
||
|
||
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?page=videos/export");
|
||
}
|
||
const userInfo = await getUserInfo(req.session.userId);
|
||
let templateData = {
|
||
VIRTUAL_HOST: process.env.VIRTUAL_HOST,
|
||
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, our_registrator
|
||
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,
|
||
ourreg: registrar.our_registrator,
|
||
});
|
||
});
|
||
|
||
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,
|
||
ourreg: registrar.our_registrator,
|
||
}));
|
||
|
||
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.API_ADDRESS}/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.API_ADDRESS}/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"));
|
||
});
|