2023-07-03 22:31:18 +00:00
|
|
|
|
const express = require("express");
|
|
|
|
|
const app = express();
|
|
|
|
|
const path = require("path");
|
2023-07-16 16:09:25 +00:00
|
|
|
|
const { Pool } = require("pg");
|
|
|
|
|
const fs = require("fs");
|
|
|
|
|
const handlebars = require("handlebars");
|
|
|
|
|
require("dotenv").config();
|
|
|
|
|
const multer = require("multer");
|
2023-07-24 04:53:11 +00:00
|
|
|
|
const http = require("http");
|
|
|
|
|
|
|
|
|
|
// Для сохранения загруженных фотографий
|
|
|
|
|
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 });
|
2023-07-03 22:31:18 +00:00
|
|
|
|
|
|
|
|
|
app.use(express.static(path.join(__dirname, "static")));
|
2023-07-16 16:09:25 +00:00
|
|
|
|
app.use(express.json());
|
2023-07-24 04:53:11 +00:00
|
|
|
|
app.use(express.urlencoded({ extended: false }));
|
2023-07-03 22:31:18 +00:00
|
|
|
|
|
|
|
|
|
app.get("/", index);
|
|
|
|
|
app.get("/login", login);
|
|
|
|
|
app.get("/register", register);
|
|
|
|
|
app.get("/live", live);
|
|
|
|
|
app.get("/reports", reports);
|
|
|
|
|
app.get("/reports/346", reports346);
|
|
|
|
|
app.get("/devices", devices);
|
|
|
|
|
app.get("/devices/drivers", drivers);
|
2023-07-18 01:32:15 +00:00
|
|
|
|
app.get("/devices/update", update);
|
2023-07-03 22:31:18 +00:00
|
|
|
|
|
2023-07-16 17:02:59 +00:00
|
|
|
|
|
2023-08-01 13:08:08 +00:00
|
|
|
|
// 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;
|
2023-08-01 13:05:54 +00:00
|
|
|
|
|
2023-08-01 13:08:08 +00:00
|
|
|
|
const DB_User = "postgres";
|
2023-08-04 09:00:26 +00:00
|
|
|
|
const DB_Password = process.env.POSTGRES_PASSWORD;
|
2023-08-04 09:52:44 +00:00
|
|
|
|
const DB_Host = "postgres";
|
2023-08-01 13:08:08 +00:00
|
|
|
|
const DB_Port = "5432";
|
|
|
|
|
const DB_Name = "postgres";
|
2023-07-16 16:09:25 +00:00
|
|
|
|
|
|
|
|
|
async function index(req, res) {
|
2023-07-18 01:32:15 +00:00
|
|
|
|
var templateData = {
|
|
|
|
|
Organisation: "Название организации",
|
|
|
|
|
User: "Тестовое Имя",
|
|
|
|
|
ifDBError: false,
|
|
|
|
|
Count: "",
|
|
|
|
|
};
|
2023-07-16 16:09:25 +00:00
|
|
|
|
try {
|
2023-07-18 01:32:15 +00:00
|
|
|
|
const pool = new Pool({
|
|
|
|
|
user: DB_User,
|
|
|
|
|
host: DB_Host,
|
|
|
|
|
database: DB_Name,
|
|
|
|
|
password: DB_Password,
|
|
|
|
|
port: DB_Port,
|
|
|
|
|
});
|
|
|
|
|
const client = await pool.connect();
|
2023-07-16 16:09:25 +00:00
|
|
|
|
// Выполняем запрос и получаем результат
|
|
|
|
|
const query = `
|
|
|
|
|
SELECT COUNT(*) AS count
|
|
|
|
|
FROM registrars
|
|
|
|
|
`;
|
|
|
|
|
const registrars = await client.query(query);
|
|
|
|
|
|
2023-07-18 01:32:15 +00:00
|
|
|
|
templateData.Count = registrars.rows[0].count;
|
2023-07-16 16:09:25 +00:00
|
|
|
|
|
|
|
|
|
console.log(templateData);
|
|
|
|
|
|
|
|
|
|
const source = fs.readFileSync("static/templates/index.html", "utf8");
|
|
|
|
|
|
|
|
|
|
const template = handlebars.compile(source);
|
|
|
|
|
|
|
|
|
|
const resultT = template(templateData);
|
|
|
|
|
res.send(resultT);
|
2023-07-18 01:32:15 +00:00
|
|
|
|
} 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);
|
2023-07-16 16:09:25 +00:00
|
|
|
|
}
|
|
|
|
|
// res.sendFile(path.join(__dirname, "static/templates/index.html"));
|
2023-07-03 22:31:18 +00:00
|
|
|
|
}
|
|
|
|
|
function login(req, res) {
|
|
|
|
|
res.sendFile(path.join(__dirname, "static/templates/login.html"));
|
|
|
|
|
}
|
|
|
|
|
function register(req, res) {
|
|
|
|
|
res.sendFile(path.join(__dirname, "static/templates/register.html"));
|
|
|
|
|
}
|
2023-07-18 01:32:15 +00:00
|
|
|
|
|
|
|
|
|
async function live(req, res) {
|
|
|
|
|
let templateData = {
|
|
|
|
|
Organisation: "Название организации",
|
|
|
|
|
User: "Тестовое Имя",
|
|
|
|
|
ifDBError: false,
|
|
|
|
|
Registrars: [],
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const pool = new Pool({
|
|
|
|
|
user: DB_User,
|
|
|
|
|
host: DB_Host,
|
|
|
|
|
database: DB_Name,
|
|
|
|
|
password: DB_Password,
|
|
|
|
|
port: DB_Port,
|
|
|
|
|
});
|
|
|
|
|
const client = await pool.connect();
|
|
|
|
|
|
2023-08-01 12:35:10 +00:00
|
|
|
|
const minuteInMillis = 60 * 1000;
|
|
|
|
|
|
2023-07-18 01:32:15 +00:00
|
|
|
|
const query = `
|
2023-08-01 12:35:10 +00:00
|
|
|
|
SELECT id, serial, lastkeepalive FROM registrars ORDER BY id ASC
|
2023-07-18 01:32:15 +00:00
|
|
|
|
`;
|
|
|
|
|
const registrars = await client.query(query);
|
|
|
|
|
|
2023-08-01 11:52:35 +00:00
|
|
|
|
templateData.Registrars = registrars.rows.map((row) => ({
|
|
|
|
|
id: row.id,
|
|
|
|
|
serial: row.serial,
|
2023-08-01 12:35:10 +00:00
|
|
|
|
status: Date.now() - Date.parse(row.lastkeepalive) <= minuteInMillis,
|
2023-08-01 11:52:35 +00:00
|
|
|
|
}));
|
2023-07-18 01:32:15 +00:00
|
|
|
|
|
|
|
|
|
console.log(templateData);
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
2023-07-03 22:31:18 +00:00
|
|
|
|
}
|
2023-07-18 01:32:15 +00:00
|
|
|
|
|
|
|
|
|
app.post("/devices-geo", async (req, res) => {
|
|
|
|
|
const selectedDevices = req.body.devices;
|
|
|
|
|
|
|
|
|
|
const pool = new Pool({
|
|
|
|
|
user: DB_User,
|
|
|
|
|
host: DB_Host,
|
|
|
|
|
database: DB_Name,
|
|
|
|
|
password: DB_Password,
|
|
|
|
|
port: DB_Port,
|
|
|
|
|
});
|
|
|
|
|
|
2023-08-01 11:52:35 +00:00
|
|
|
|
// console.log(selectedDevices);
|
2023-07-18 01:32:15 +00:00
|
|
|
|
|
|
|
|
|
const placeholders = selectedDevices
|
2023-08-01 13:05:54 +00:00
|
|
|
|
.map((_, index) => `$${index + 1}`)
|
|
|
|
|
.join(",");
|
2023-07-18 01:32:15 +00:00
|
|
|
|
const subquery = `
|
2023-08-01 13:05:54 +00:00
|
|
|
|
SELECT g.serial, g.longitude, g.latitude, g.direction, g.speed, r.lastkeepalive
|
|
|
|
|
FROM geo g
|
|
|
|
|
INNER JOIN (
|
|
|
|
|
SELECT serial, MAX(time) AS time
|
2023-07-18 01:32:15 +00:00
|
|
|
|
FROM geo
|
|
|
|
|
WHERE serial IN (
|
|
|
|
|
SELECT serial
|
|
|
|
|
FROM registrars
|
|
|
|
|
WHERE id IN (${placeholders})
|
|
|
|
|
)
|
|
|
|
|
GROUP BY serial
|
2023-08-01 13:05:54 +00:00
|
|
|
|
) s ON g.serial = s.serial AND g.time = s.time
|
|
|
|
|
INNER JOIN registrars r ON g.serial = r.serial
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
pool.query(subquery, selectedDevices, (err, result) => {
|
|
|
|
|
if (err) {
|
|
|
|
|
console.error("Ошибка выполнения запроса:", err);
|
|
|
|
|
res.status(500).json({ error: "Ошибка сервера" });
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const minuteInMillis = 60000;
|
|
|
|
|
|
|
|
|
|
// Process the result to include lastkeepalive information
|
|
|
|
|
const devicesData = result.rows.map((row) => ({
|
|
|
|
|
serial: row.serial,
|
|
|
|
|
longitude: row.longitude,
|
|
|
|
|
latitude: row.latitude,
|
|
|
|
|
direction: row.direction,
|
|
|
|
|
speed: row.speed,
|
|
|
|
|
status: Date.now() - Date.parse(row.lastkeepalive) <= minuteInMillis,
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
2023-07-18 01:32:15 +00:00
|
|
|
|
|
2023-08-01 11:52:35 +00:00
|
|
|
|
// console.log(result.rows);
|
2023-07-18 01:32:15 +00:00
|
|
|
|
|
2023-08-01 13:05:54 +00:00
|
|
|
|
|
2023-07-18 01:32:15 +00:00
|
|
|
|
res.json({ devicesData });
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2023-07-16 16:09:25 +00:00
|
|
|
|
async function reports(req, res) {
|
2023-07-24 04:53:11 +00:00
|
|
|
|
let templateData = {
|
|
|
|
|
Organisation: "Название организации",
|
|
|
|
|
User: "Тестовое Имя",
|
|
|
|
|
ifDBError: false,
|
|
|
|
|
Registrars: [],
|
|
|
|
|
};
|
2023-07-16 16:09:25 +00:00
|
|
|
|
try {
|
2023-07-18 01:32:15 +00:00
|
|
|
|
const pool = new Pool({
|
|
|
|
|
user: DB_User,
|
|
|
|
|
host: DB_Host,
|
|
|
|
|
database: DB_Name,
|
|
|
|
|
password: DB_Password,
|
|
|
|
|
port: DB_Port,
|
|
|
|
|
});
|
|
|
|
|
const client = await pool.connect();
|
2023-07-16 16:09:25 +00:00
|
|
|
|
// Выполняем запрос и получаем результат
|
|
|
|
|
const query = `
|
2023-07-24 04:53:11 +00:00
|
|
|
|
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
|
|
|
|
|
ORDER BY time DESC
|
|
|
|
|
LIMIT 100
|
|
|
|
|
) AS a
|
|
|
|
|
LEFT JOIN registrars AS r ON a.serial = r.serial
|
|
|
|
|
LEFT JOIN (
|
|
|
|
|
SELECT *,
|
|
|
|
|
ROW_NUMBER() OVER (PARTITION BY serial ORDER BY ABS(EXTRACT(EPOCH FROM (time - $1)))) AS row_num
|
|
|
|
|
FROM geo
|
|
|
|
|
) AS g ON a.serial = g.serial AND g.row_num = 1
|
|
|
|
|
ORDER BY a.time DESC;
|
2023-07-16 16:09:25 +00:00
|
|
|
|
`;
|
2023-07-24 04:53:11 +00:00
|
|
|
|
const alarms = await client.query(query, [new Date()]); // Pass current date/time to the query for finding the nearest geoposition.
|
2023-07-16 16:09:25 +00:00
|
|
|
|
|
|
|
|
|
function formatDate(date) {
|
|
|
|
|
const options = {
|
|
|
|
|
year: "2-digit",
|
|
|
|
|
month: "2-digit",
|
|
|
|
|
day: "2-digit",
|
|
|
|
|
hour: "2-digit",
|
|
|
|
|
minute: "2-digit",
|
|
|
|
|
};
|
|
|
|
|
const formattedDate = new Date(date).toLocaleString("ru-RU", options);
|
|
|
|
|
return formattedDate.replace(",", "");
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-24 04:53:11 +00:00
|
|
|
|
(templateData.Alarms = alarms.rows.map((alarm) => {
|
|
|
|
|
let type;
|
|
|
|
|
switch (alarm.st) {
|
|
|
|
|
case "0":
|
|
|
|
|
type = "Усталость";
|
|
|
|
|
break;
|
|
|
|
|
case "1":
|
|
|
|
|
type = "Водитель пропал";
|
|
|
|
|
break;
|
|
|
|
|
case "2":
|
|
|
|
|
type = "Разговор по телефону";
|
|
|
|
|
break;
|
|
|
|
|
case "3":
|
|
|
|
|
type = "Курение за рулём";
|
|
|
|
|
break;
|
|
|
|
|
case "4":
|
|
|
|
|
type = "Водитель отвлекся";
|
|
|
|
|
break;
|
|
|
|
|
case "5":
|
|
|
|
|
type = "Выезд с полосы движения";
|
|
|
|
|
break;
|
|
|
|
|
case "6":
|
|
|
|
|
type = "!!! Лобовое столкновение";
|
|
|
|
|
break;
|
|
|
|
|
case "7":
|
|
|
|
|
type = "Скорость превышена";
|
|
|
|
|
break;
|
|
|
|
|
case "8":
|
|
|
|
|
type = "Распознавание номерных знаков";
|
|
|
|
|
break;
|
|
|
|
|
case "9":
|
|
|
|
|
type = "!! Маленькое расстояние спереди";
|
|
|
|
|
break;
|
|
|
|
|
case "10":
|
|
|
|
|
type = "Водитель зевает";
|
|
|
|
|
break;
|
|
|
|
|
case "11":
|
|
|
|
|
type = "!!! Столкновение с пешеходом";
|
|
|
|
|
break;
|
|
|
|
|
case "12":
|
|
|
|
|
type = "Проходы переполнены";
|
|
|
|
|
break;
|
|
|
|
|
case "13":
|
|
|
|
|
type = "!! Посадка/высадка вне остановки";
|
|
|
|
|
break;
|
|
|
|
|
case "14":
|
|
|
|
|
type = "!! Смена полосы с нарушением ПДД";
|
|
|
|
|
break;
|
|
|
|
|
case "15":
|
|
|
|
|
type = "! Включенный телефон у водителя";
|
|
|
|
|
break;
|
|
|
|
|
case "16":
|
|
|
|
|
type = "!!! Ремень безопасности";
|
|
|
|
|
break;
|
|
|
|
|
case "17":
|
|
|
|
|
type = "Проверка не удалась";
|
|
|
|
|
break;
|
|
|
|
|
case "18":
|
|
|
|
|
type = "Слепые зоны справа";
|
|
|
|
|
break;
|
|
|
|
|
case "19":
|
|
|
|
|
type = "!!! Заднее столкновение";
|
|
|
|
|
break;
|
|
|
|
|
case "20":
|
|
|
|
|
type = "!!! Управление без рук";
|
|
|
|
|
break;
|
|
|
|
|
case "21":
|
|
|
|
|
type = "!! Управление одной рукой";
|
|
|
|
|
break;
|
|
|
|
|
case "22":
|
|
|
|
|
type = "Очки, блокирующие инфракрасное излучение";
|
|
|
|
|
break;
|
|
|
|
|
case "23":
|
|
|
|
|
type = "Слепые зоны слева";
|
|
|
|
|
break;
|
|
|
|
|
case "24":
|
|
|
|
|
type = "Помехи для пассажиров";
|
|
|
|
|
break;
|
|
|
|
|
case "25":
|
|
|
|
|
type = "На перекрестке ограничена скорость";
|
|
|
|
|
break;
|
|
|
|
|
case "26":
|
|
|
|
|
type = "Обнаружен перекресток";
|
|
|
|
|
break;
|
|
|
|
|
case "27":
|
|
|
|
|
type = "Пешеходы на переходе";
|
|
|
|
|
break;
|
|
|
|
|
case "28":
|
|
|
|
|
type = "! Неучтивое отношение к пешеходам";
|
|
|
|
|
break;
|
|
|
|
|
case "29":
|
|
|
|
|
type = "Обнаружен пешеходный переход";
|
|
|
|
|
break;
|
|
|
|
|
case "30":
|
|
|
|
|
type = "Водитель матерится";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
type = "Неизвестный тип";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
id: alarm.id,
|
|
|
|
|
cmdno: alarm.cmdno,
|
|
|
|
|
time: formatDate(alarm.time),
|
|
|
|
|
serial: alarm.serial,
|
|
|
|
|
st: alarm.st,
|
|
|
|
|
type: type,
|
|
|
|
|
plate: alarm.plate,
|
|
|
|
|
latitude: alarm.latitude,
|
|
|
|
|
longitude: alarm.longitude,
|
|
|
|
|
geo: alarm.latitude + "," + alarm.longitude,
|
|
|
|
|
};
|
|
|
|
|
})),
|
|
|
|
|
console.log(templateData);
|
2023-07-16 16:09:25 +00:00
|
|
|
|
|
|
|
|
|
const source = fs.readFileSync(
|
|
|
|
|
"static/templates/reports/index.html",
|
|
|
|
|
"utf8"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const template = handlebars.compile(source);
|
|
|
|
|
|
|
|
|
|
const resultT = template(templateData);
|
|
|
|
|
res.send(resultT);
|
2023-07-18 01:32:15 +00:00
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error(error);
|
2023-07-24 04:53:11 +00:00
|
|
|
|
templateData.ifDBError = true;
|
2023-07-18 01:32:15 +00:00
|
|
|
|
|
|
|
|
|
const source = fs.readFileSync(
|
|
|
|
|
"static/templates/reports/index.html",
|
|
|
|
|
"utf8"
|
|
|
|
|
);
|
|
|
|
|
const template = handlebars.compile(source);
|
|
|
|
|
const resultT = template(templateData);
|
|
|
|
|
res.send(resultT);
|
2023-07-16 16:09:25 +00:00
|
|
|
|
}
|
2023-07-03 22:31:18 +00:00
|
|
|
|
}
|
2023-07-24 04:53:11 +00:00
|
|
|
|
app.get("/api/devices", async (req, res) => {
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
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, [limit, offset, new Date()]); // Pass current date/time to the query for finding the nearest geoposition.
|
|
|
|
|
|
|
|
|
|
function formatDate(date) {
|
|
|
|
|
const options = {
|
|
|
|
|
year: "2-digit",
|
|
|
|
|
month: "2-digit",
|
|
|
|
|
day: "2-digit",
|
|
|
|
|
hour: "2-digit",
|
|
|
|
|
minute: "2-digit",
|
|
|
|
|
};
|
|
|
|
|
const formattedDate = new Date(date).toLocaleString("ru-RU", options);
|
|
|
|
|
return formattedDate.replace(",", "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const alarmsData = alarms.rows.map((alarm) => {
|
|
|
|
|
let type;
|
|
|
|
|
switch (alarm.st) {
|
|
|
|
|
case "0":
|
|
|
|
|
type = "Усталость";
|
|
|
|
|
break;
|
|
|
|
|
case "1":
|
|
|
|
|
type = "Отсутствие водителя";
|
|
|
|
|
break;
|
|
|
|
|
case "2":
|
|
|
|
|
type = "Разговор по телефону";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
type = "Неизвестный тип";
|
|
|
|
|
}
|
|
|
|
|
return {
|
|
|
|
|
id: alarm.id,
|
|
|
|
|
cmdno: alarm.cmdno,
|
|
|
|
|
time: formatDate(alarm.time),
|
|
|
|
|
serial: alarm.serial,
|
|
|
|
|
st: alarm.st,
|
|
|
|
|
type: type,
|
|
|
|
|
plate: alarm.plate,
|
|
|
|
|
latitude: alarm.latitude,
|
|
|
|
|
longitude: alarm.longitude,
|
|
|
|
|
geo: alarm.latitude + "," + alarm.longitude,
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const totalCountQuery = "SELECT COUNT(*) FROM alarms;";
|
|
|
|
|
const totalCount = await pool.query(totalCountQuery);
|
|
|
|
|
|
|
|
|
|
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" });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2023-07-03 22:31:18 +00:00
|
|
|
|
function reports346(req, res) {
|
|
|
|
|
res.sendFile(path.join(__dirname, "static/templates/reports/346.html"));
|
|
|
|
|
}
|
2023-07-16 16:09:25 +00:00
|
|
|
|
async function devices(req, res) {
|
2023-07-18 01:32:15 +00:00
|
|
|
|
let templateData = {
|
|
|
|
|
Organisation: "Название организации",
|
|
|
|
|
User: "Тестовое Имя",
|
|
|
|
|
ifDBError: false,
|
|
|
|
|
Registrars: [],
|
|
|
|
|
};
|
|
|
|
|
|
2023-07-16 16:09:25 +00:00
|
|
|
|
try {
|
2023-07-18 01:32:15 +00:00
|
|
|
|
const pool = new Pool({
|
|
|
|
|
user: DB_User,
|
|
|
|
|
host: DB_Host,
|
|
|
|
|
database: DB_Name,
|
|
|
|
|
password: DB_Password,
|
|
|
|
|
port: DB_Port,
|
|
|
|
|
});
|
|
|
|
|
const client = await pool.connect();
|
2023-08-01 12:35:10 +00:00
|
|
|
|
|
|
|
|
|
const minuteInMillis = 60 * 1000;
|
|
|
|
|
|
|
|
|
|
// Выполняем запрос, чтобы получить все данные из таблицы registrars
|
|
|
|
|
const queryRegistrars = `
|
|
|
|
|
SELECT id, serial, lastkeepalive, name, "group", plate, sim, ip, port
|
2023-07-16 16:09:25 +00:00
|
|
|
|
FROM registrars
|
|
|
|
|
ORDER BY id
|
|
|
|
|
`;
|
2023-08-01 12:35:10 +00:00
|
|
|
|
const registrarsResult = await client.query(queryRegistrars);
|
|
|
|
|
const allRegistrars = registrarsResult.rows;
|
|
|
|
|
|
|
|
|
|
// Определяем статус connected на основе lastkeepalive
|
|
|
|
|
const templateData = {
|
|
|
|
|
Registrars: allRegistrars.map((registrar) => ({
|
2023-07-18 01:32:15 +00:00
|
|
|
|
id: registrar.id,
|
|
|
|
|
serial: registrar.serial,
|
2023-08-01 12:35:10 +00:00
|
|
|
|
status: Date.now() - Date.parse(registrar.lastkeepalive) <= minuteInMillis,
|
2023-07-18 01:32:15 +00:00
|
|
|
|
name: registrar.name,
|
|
|
|
|
group: registrar.group,
|
|
|
|
|
plate: registrar.plate,
|
|
|
|
|
sim: registrar.sim,
|
|
|
|
|
ip: registrar.ip,
|
|
|
|
|
port: registrar.port,
|
|
|
|
|
})),
|
2023-08-01 12:35:10 +00:00
|
|
|
|
};
|
|
|
|
|
|
2023-07-16 16:09:25 +00:00
|
|
|
|
console.log(templateData);
|
2023-08-01 12:35:10 +00:00
|
|
|
|
|
|
|
|
|
const source = fs.readFileSync("static/templates/devices/index.html", "utf8");
|
2023-07-16 16:09:25 +00:00
|
|
|
|
const template = handlebars.compile(source);
|
|
|
|
|
const resultT = template(templateData);
|
|
|
|
|
res.send(resultT);
|
2023-08-01 12:35:10 +00:00
|
|
|
|
|
2023-07-16 16:09:25 +00:00
|
|
|
|
client.release();
|
2023-07-18 01:32:15 +00:00
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error(error);
|
|
|
|
|
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);
|
2023-07-16 16:09:25 +00:00
|
|
|
|
}
|
2023-07-03 22:31:18 +00:00
|
|
|
|
}
|
2023-07-16 16:09:25 +00:00
|
|
|
|
|
|
|
|
|
app.post("/devicedata", async (req, res) => {
|
|
|
|
|
const id = req.body.id;
|
|
|
|
|
|
2023-07-18 01:32:15 +00:00
|
|
|
|
const pool = new Pool({
|
|
|
|
|
user: DB_User,
|
|
|
|
|
host: DB_Host,
|
|
|
|
|
database: DB_Name,
|
|
|
|
|
password: DB_Password,
|
|
|
|
|
port: DB_Port,
|
|
|
|
|
});
|
2023-07-16 16:09:25 +00:00
|
|
|
|
const client = await pool.connect();
|
2023-07-18 01:32:15 +00:00
|
|
|
|
|
2023-07-16 16:09:25 +00:00
|
|
|
|
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) => {
|
2023-07-24 04:53:11 +00:00
|
|
|
|
const pool = new Pool({
|
|
|
|
|
user: DB_User,
|
|
|
|
|
host: DB_Host,
|
|
|
|
|
database: DB_Name,
|
|
|
|
|
password: DB_Password,
|
|
|
|
|
port: DB_Port,
|
|
|
|
|
});
|
2023-07-16 16:09:25 +00:00
|
|
|
|
const client = await pool.connect();
|
|
|
|
|
|
|
|
|
|
var {
|
|
|
|
|
plateNumber,
|
|
|
|
|
plateColor,
|
|
|
|
|
serialNumber,
|
|
|
|
|
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,
|
|
|
|
|
} = req.body;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Обновление строки в таблице registrars
|
|
|
|
|
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
|
|
|
|
|
WHERE serial = $31
|
|
|
|
|
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,
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2023-07-24 04:53:11 +00:00
|
|
|
|
app.post("/updatedriver", upload.single("upload-file"), async (req, res) => {
|
|
|
|
|
const pool = new Pool({
|
|
|
|
|
user: DB_User,
|
|
|
|
|
host: DB_Host,
|
|
|
|
|
database: DB_Name,
|
|
|
|
|
password: DB_Password,
|
|
|
|
|
port: DB_Port,
|
|
|
|
|
});
|
|
|
|
|
const client = await pool.connect();
|
|
|
|
|
|
|
|
|
|
var {
|
|
|
|
|
driverName,
|
|
|
|
|
driverSurname,
|
|
|
|
|
driverCard,
|
|
|
|
|
driverGender,
|
|
|
|
|
driverLicense,
|
|
|
|
|
driverPassport,
|
|
|
|
|
driverPhone,
|
|
|
|
|
driverEmail,
|
|
|
|
|
driverTransport,
|
|
|
|
|
driverDescription,
|
|
|
|
|
driverID,
|
|
|
|
|
} = req.body;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Вставка новой строки в таблицу drivers
|
|
|
|
|
const query = `
|
|
|
|
|
UPDATE drivers
|
|
|
|
|
SET name = $1,
|
|
|
|
|
surname = $2,
|
|
|
|
|
card = $3,
|
|
|
|
|
gender = $4,
|
|
|
|
|
license = $5,
|
|
|
|
|
passport = $6,
|
|
|
|
|
phone = $7,
|
|
|
|
|
email = $8,
|
|
|
|
|
transport = $9,
|
|
|
|
|
description = $10
|
|
|
|
|
WHERE id = $11
|
|
|
|
|
RETURNING *;
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const values = [
|
|
|
|
|
driverName,
|
|
|
|
|
driverSurname,
|
|
|
|
|
driverCard,
|
|
|
|
|
driverGender,
|
|
|
|
|
driverLicense,
|
|
|
|
|
driverPassport,
|
|
|
|
|
driverPhone,
|
|
|
|
|
driverEmail,
|
|
|
|
|
driverTransport,
|
|
|
|
|
driverDescription,
|
|
|
|
|
driverID,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const result = await client.query(query, values);
|
|
|
|
|
|
|
|
|
|
const newRow = result.rows[0];
|
|
|
|
|
console.log("New driver added:", newRow);
|
|
|
|
|
|
|
|
|
|
res.send("Data added successfully");
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Error adding data:", error);
|
|
|
|
|
res.status(500).send("An error occurred while adding data");
|
|
|
|
|
} finally {
|
|
|
|
|
client.release();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
app.post("/adddriver", upload.single("upload-file"), async (req, res) => {
|
|
|
|
|
const pool = new Pool({
|
|
|
|
|
user: DB_User,
|
|
|
|
|
host: DB_Host,
|
|
|
|
|
database: DB_Name,
|
|
|
|
|
password: DB_Password,
|
|
|
|
|
port: DB_Port,
|
|
|
|
|
});
|
|
|
|
|
const client = await pool.connect();
|
|
|
|
|
|
|
|
|
|
var {
|
|
|
|
|
driverName,
|
|
|
|
|
driverSurname,
|
|
|
|
|
driverCard,
|
|
|
|
|
driverGender,
|
|
|
|
|
driverLicense,
|
|
|
|
|
driverPassport,
|
|
|
|
|
driverPhone,
|
|
|
|
|
driverEmail,
|
|
|
|
|
driverTransport,
|
|
|
|
|
driverDescription,
|
|
|
|
|
} = req.body;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Вставка новой строки в таблицу drivers
|
|
|
|
|
const query = `
|
|
|
|
|
INSERT INTO drivers (
|
|
|
|
|
name,
|
|
|
|
|
surname,
|
|
|
|
|
card,
|
|
|
|
|
gender,
|
|
|
|
|
license,
|
|
|
|
|
passport,
|
|
|
|
|
phone,
|
|
|
|
|
email,
|
|
|
|
|
transport,
|
|
|
|
|
description
|
|
|
|
|
)
|
|
|
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
|
|
|
|
RETURNING *;
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const values = [
|
|
|
|
|
driverName,
|
|
|
|
|
driverSurname,
|
|
|
|
|
driverCard,
|
|
|
|
|
driverGender,
|
|
|
|
|
driverLicense,
|
|
|
|
|
driverPassport,
|
|
|
|
|
driverPhone,
|
|
|
|
|
driverEmail,
|
|
|
|
|
driverTransport,
|
|
|
|
|
driverDescription,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const result = await client.query(query, values);
|
|
|
|
|
|
|
|
|
|
const newRow = result.rows[0];
|
|
|
|
|
console.log("New driver added:", newRow);
|
|
|
|
|
|
|
|
|
|
res.send("Data added successfully");
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Error adding data:", error);
|
|
|
|
|
res.status(500).send("An error occurred while adding data");
|
|
|
|
|
} finally {
|
|
|
|
|
client.release();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
app.post("/driverdata", async (req, res) => {
|
|
|
|
|
const id = req.body.id;
|
|
|
|
|
|
|
|
|
|
const pool = new Pool({
|
|
|
|
|
user: DB_User,
|
|
|
|
|
host: DB_Host,
|
|
|
|
|
database: DB_Name,
|
|
|
|
|
password: DB_Password,
|
|
|
|
|
port: DB_Port,
|
|
|
|
|
});
|
|
|
|
|
const client = await pool.connect();
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Выполняем запрос и получаем результат
|
|
|
|
|
const query = "SELECT * FROM drivers WHERE id = $1;";
|
|
|
|
|
const driverdata = await client.query(query, [id]);
|
|
|
|
|
|
|
|
|
|
// Формирование и отправка ответа
|
|
|
|
|
const response = driverdata.rows[0];
|
|
|
|
|
res.json(response);
|
|
|
|
|
} finally {
|
|
|
|
|
client.release();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
app.post("/deletedriver", async (req, res) => {
|
|
|
|
|
const id = req.body.id;
|
|
|
|
|
|
|
|
|
|
const pool = new Pool({
|
|
|
|
|
user: DB_User,
|
|
|
|
|
host: DB_Host,
|
|
|
|
|
database: DB_Name,
|
|
|
|
|
password: DB_Password,
|
|
|
|
|
port: DB_Port,
|
|
|
|
|
});
|
|
|
|
|
const client = await pool.connect();
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Выполняем запрос и получаем результат
|
|
|
|
|
const query = "DELETE FROM drivers WHERE id = $1;";
|
|
|
|
|
const driverdata = await client.query(query, [id]);
|
|
|
|
|
|
|
|
|
|
// Формирование и отправка ответа
|
|
|
|
|
res.send("Data deleted successfully");
|
|
|
|
|
} finally {
|
|
|
|
|
client.release();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
async function drivers(req, res) {
|
|
|
|
|
let templateData = {
|
|
|
|
|
Organisation: "Название организации",
|
|
|
|
|
User: "Тестовое Имя",
|
|
|
|
|
ifDBError: false,
|
|
|
|
|
Drivers: [],
|
|
|
|
|
Registrars: [],
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const pool = new Pool({
|
|
|
|
|
user: DB_User,
|
|
|
|
|
host: DB_Host,
|
|
|
|
|
database: DB_Name,
|
|
|
|
|
password: DB_Password,
|
|
|
|
|
port: DB_Port,
|
|
|
|
|
});
|
|
|
|
|
const client = await pool.connect();
|
|
|
|
|
|
|
|
|
|
// Выполняем запрос для объединения данных из таблиц drivers и registrars
|
|
|
|
|
const queryDrivers = `
|
|
|
|
|
SELECT d.id, d.name, d.surname, d.transport, d.phone, d.email, d.card, r.connected
|
|
|
|
|
FROM drivers d
|
|
|
|
|
LEFT JOIN registrars r ON d.transport = r.serial
|
|
|
|
|
ORDER BY r.connected DESC NULLS LAST, CASE WHEN r.connected = true THEN 0 ELSE 1 END, d.id
|
|
|
|
|
`;
|
|
|
|
|
const driversResult = await client.query(queryDrivers);
|
|
|
|
|
|
|
|
|
|
templateData.Drivers = driversResult.rows.map((driver) => ({
|
|
|
|
|
id: driver.id,
|
|
|
|
|
name: driver.name,
|
|
|
|
|
surname: driver.surname,
|
|
|
|
|
transport: driver.transport,
|
|
|
|
|
phone: driver.phone,
|
|
|
|
|
email: driver.email,
|
|
|
|
|
card: driver.card,
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
const queryRegistrars = `
|
|
|
|
|
SELECT serial
|
|
|
|
|
FROM registrars
|
|
|
|
|
`;
|
|
|
|
|
const registrarsResult = await client.query(queryRegistrars);
|
|
|
|
|
|
|
|
|
|
templateData.Registrars = registrarsResult.rows.map(
|
|
|
|
|
(registrar) => registrar.serial
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
console.log(templateData);
|
|
|
|
|
|
|
|
|
|
const source = fs.readFileSync(
|
|
|
|
|
"static/templates/devices/drivers.html",
|
|
|
|
|
"utf8"
|
|
|
|
|
);
|
|
|
|
|
const template = handlebars.compile(source);
|
|
|
|
|
const resultT = template(templateData);
|
|
|
|
|
res.send(resultT);
|
|
|
|
|
|
|
|
|
|
client.release();
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error(error);
|
|
|
|
|
templateData.ifDBError = true;
|
|
|
|
|
|
|
|
|
|
const source = fs.readFileSync(
|
|
|
|
|
"static/templates/devices/drivers.html",
|
|
|
|
|
"utf8"
|
|
|
|
|
);
|
|
|
|
|
const template = handlebars.compile(source);
|
|
|
|
|
const resultT = template(templateData);
|
|
|
|
|
res.send(resultT);
|
|
|
|
|
}
|
2023-07-03 22:31:18 +00:00
|
|
|
|
}
|
2023-07-24 04:53:11 +00:00
|
|
|
|
|
2023-07-18 01:32:15 +00:00
|
|
|
|
function update(req, res) {
|
|
|
|
|
res.sendFile(path.join(__dirname, "static/templates/devices/update.html"));
|
|
|
|
|
}
|
2023-07-03 22:31:18 +00:00
|
|
|
|
|
|
|
|
|
const port = 8081;
|
|
|
|
|
app.listen(port, () => {
|
|
|
|
|
console.log(`Server is running on port ${port}`);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// app.use((req, res, next) => {
|
|
|
|
|
// res.sendFile(path.join(__dirname, "static/templates/404.html"));
|
|
|
|
|
// });
|