export and playback update

This commit is contained in:
Ivan 2023-09-17 15:22:14 +03:00
parent 8ec567409b
commit 4fbd8a1707
Signed by untrusted user who does not match committer: ppechenkoo
GPG Key ID: 0C191B86D9582583
4 changed files with 532 additions and 201 deletions

View File

@ -172,17 +172,17 @@ conn.on('error', function(err) {
}); });
// const DB_User = process.env.DB_USER; const DB_User = process.env.DB_USER;
// const DB_Password = process.env.DB_PASSWORD; const DB_Password = process.env.DB_PASSWORD;
// const DB_Host = process.env.DB_HOST; const DB_Host = process.env.DB_HOST;
// const DB_Port = process.env.DB_PORT; const DB_Port = process.env.DB_PORT;
// const DB_Name = process.env.DB_NAME; const DB_Name = process.env.DB_NAME;
const DB_User = "postgres"; // const DB_User = "postgres";
const DB_Password = process.env.POSTGRES_PASSWORD; // const DB_Password = process.env.POSTGRES_PASSWORD;
const DB_Host = "postgres"; // const DB_Host = "postgres";
const DB_Port = "5432"; // const DB_Port = "5432";
const DB_Name = "postgres"; // const DB_Name = "postgres";
async function index(req, res) { async function index(req, res) {
if (req.session.userId === undefined) { if (req.session.userId === undefined) {
@ -3283,7 +3283,7 @@ app.get('/getData', async (req, res) => {
try { try {
const successResponse = await axios.get(`http://krbl.ru:8080/http/filelist/request?serial=${selectedSerial}&querytime=${selectedDate}&channel=${selectedChannel}`); const successResponse = await axios.get(`http://krbl.ru:8080/http/filelist/request?serial=${selectedSerial}&querytime=${selectedDate}&channel=${selectedChannel}`);
if (successResponse.data.SUCCESS) { if (successResponse.data.SUCCESS) {
await new Promise(resolve => setTimeout(resolve, 5000)); await new Promise(resolve => setTimeout(resolve, 7000));
const dataResponse = await axios.get(`http://krbl.ru:8080/http/filelist/get?serial=${selectedSerial}&querytime=${selectedDate}&channel=${selectedChannel}`); const dataResponse = await axios.get(`http://krbl.ru:8080/http/filelist/get?serial=${selectedSerial}&querytime=${selectedDate}&channel=${selectedChannel}`);
if (successResponse.data.SUCCESS) { if (successResponse.data.SUCCESS) {
const dataId = dataResponse.data.DATAID; const dataId = dataResponse.data.DATAID;
@ -3356,12 +3356,14 @@ app.post("/getspeedarchive", async (req, res) => {
port: DB_Port, port: DB_Port,
}); });
const client = await pool.connect(); const client = await pool.connect();
const sqlQuery = `
SELECT speed, latitude, longitude // Запрос для получения первой и последней временных отметок
const timeRangeQuery = `
SELECT MIN(time) as min_time, MAX(time) as max_time
FROM geo FROM geo
WHERE serial = $1 WHERE serial = $1
AND time >= $2 AND time >= $2
AND time < $3; AND time <= $3;
`; `;
const startTime = new Date(formattedDateTime); const startTime = new Date(formattedDateTime);
@ -3369,29 +3371,64 @@ app.post("/getspeedarchive", async (req, res) => {
const endTime = new Date(startTime); const endTime = new Date(startTime);
endTime.setHours(endTime.getHours() + 1); endTime.setHours(endTime.getHours() + 1);
pool.query(sqlQuery, [serial, startTime, endTime], (error, results) => { // Первый запрос для получения временных отметок
pool.query(timeRangeQuery, [serial, startTime, endTime], (error, timeResults) => {
if (error) { if (error) {
console.error("Ошибка при выполнении SQL-запроса:", error); console.error("Ошибка при выполнении SQL-запроса:", error);
res.status(500).json({ error: "Ошибка на сервере" }); res.status(500).json({ error: "Ошибка на сервере" });
} else { } else {
const speeds = results.rows.map((row) => row.speed); const { min_time, max_time } = timeResults.rows[0];
const transformedSpeeds = speeds.map((speed) => {
if (speed > 150) { // Запрос для получения данных скорости и геолокации
return speed / 100; 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 { } else {
return speed; 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 geoData = results.rows.map((row) => ({
latitude: row.latitude,
longitude: row.longitude,
}));
res.json({ speeds: transformedSpeeds, geo: geoData });
} }
}); });
}); });
const port = 8081; const port = 8081;
app.listen(port, () => { app.listen(port, () => {
console.log(`Server is running on port ${port}`); console.log(`Server is running on port ${port}`);

View File

@ -325,9 +325,9 @@ header h2 span {
} }
.whole-width h1 { .whole-width h1 {
font-weight: 500; font-weight: 500 !important;
font-size: 30px; font-size: 30px !important;
margin: 35px 0 0 44px; margin: 35px 0 0 44px !important;
} }
.whole-width h3 { .whole-width h3 {
@ -355,6 +355,15 @@ header h2 span {
margin-bottom: 25px; margin-bottom: 25px;
} }
.loader-container {
width: fit-content;
height: fit-content;
padding: 50px;
padding-bottom: 25px;
border-radius: 10px;
background: white;
}
.square { .square {
background: #8086F9; background: #8086F9;
width: 10px; width: 10px;
@ -415,6 +424,54 @@ header h2 span {
animation: loader_5191 675ms ease-in-out 600ms infinite; animation: loader_5191 675ms ease-in-out 600ms infinite;
} }
#sq11 {
margin-top: -25px;
margin-left: -25px;
animation: loader_5191 675ms ease-in-out 0s infinite alternate;
}
#sq12 {
margin-top: -25px;
animation: loader_5191 675ms ease-in-out 75ms infinite alternate;
}
#sq13 {
margin-top: -25px;
margin-left: 15px;
animation: loader_5191 675ms ease-in-out 150ms infinite;
}
#sq14 {
margin-left: -25px;
animation: loader_5191 675ms ease-in-out 225ms infinite;
}
#sq15 {
animation: loader_5191 675ms ease-in-out 300ms infinite;
}
#sq16 {
margin-left: 15px;
animation: loader_5191 675ms ease-in-out 375ms infinite;
}
#sq17 {
margin-top: 15px;
margin-left: -25px;
animation: loader_5191 675ms ease-in-out 450ms infinite;
}
#sq18 {
margin-top: 15px;
animation: loader_5191 675ms ease-in-out 525ms infinite;
}
#sq19 {
margin-top: 15px;
margin-left: 15px;
animation: loader_5191 675ms ease-in-out 600ms infinite;
}
.content .organisation { .content .organisation {
width: 250px; width: 250px;

View File

@ -60,6 +60,7 @@
<section class="main"> <section class="main">
<section style="display: none;" class="dberror" id="exportLoading" > <section style="display: none;" class="dberror" id="exportLoading" >
<div class="erorr-container"> <div class="erorr-container">
<div class="loader-container">
<div id="loader" class="loader"> <div id="loader" class="loader">
<div class="square" id="sq1"></div> <div class="square" id="sq1"></div>
<div class="square" id="sq2"></div> <div class="square" id="sq2"></div>
@ -71,10 +72,27 @@
<div class="square" id="sq8"></div> <div class="square" id="sq8"></div>
<div class="square" id="sq9"></div> <div class="square" id="sq9"></div>
</div> </div>
</div>
<h1>Подготовка видео</h1> <br> <h1>Подготовка видео</h1> <br>
<span id="status">Пожалуйста, подождите..</span> <span id="status">Пожалуйста, подождите..</span>
</div> </div>
</section> </section>
<section style="display: none;" class="dberror" id="dataLoading" >
<div class="loader-container">
<div class="loader">
<div class="square" id="sq11"></div>
<div class="square" id="sq12"></div>
<div class="square" id="sq13"></div>
<div class="square" id="sq14"></div>
<div class="square" id="sq15"></div>
<div class="square" id="sq16"></div>
<div class="square" id="sq17"></div>
<div class="square" id="sq18"></div>
<div class="square" id="sq19"></div>
</div>
</div>
</section>
{{#if ifDBError}} {{#if ifDBError}}
<section class="dberror"> <section class="dberror">
<div class="erorr-container"> <div class="erorr-container">
@ -106,6 +124,7 @@
{{#each devices}} {{#each devices}}
<li class="device"> <li class="device">
<img> <img>
<input type="number" id="channels-{{this.serial}}" value="{{this.channels}}" hidden>
<input type="radio" name="camera-serial" id="radio-{{this.serial}}" class="radio-input" value="{{this.serial}}" hidden> <input type="radio" name="camera-serial" id="radio-{{this.serial}}" class="radio-input" value="{{this.serial}}" hidden>
<label for="radio-{{this.serial}}" class="radio-label active-{{this.status}}"> <label for="radio-{{this.serial}}" class="radio-label active-{{this.status}}">
{{this.serial}} {{this.serial}}
@ -125,84 +144,39 @@
<section class="table" style="position: relative;"> <section class="table" style="position: relative;">
<div class="map"> <div class="map">
<!-- <div id="properties" class="properties" style="display: none;">
<div class="propert"><h1>Группа</h1><br><h2 id="propert-group">Автобусы</h2></div>
<div class="propert"><h1>Скорость</h1><br><h2 id="propert-speed"> км/ч</h2></div>
<div class="propert"><h1>Номерной знак</h1><br><h2 id="propert-plate"></h2></div>
<div class="propert"><h1>Геопозиция</h1><br><h2 id="propert-geo"></h2></div>
</div> -->
<div id="map"></div> <div id="map"></div>
</div> </div>
<div id="cameras" class="cameras"> <div style="background: white;" class="cameras">
<div class="video-container"> <section style="border: 0;" class="whole-width">
<div id="camera-1" onclick="playVideo(1);"> <h1>Экспортировать запись с камеры</h1>
<img src="../../img/play-circle.svg"> <h3>Выберите камеру, время и нажмите кнопку "Скачать запись"</h3>
<span>Экспортировать 1 камеру</span> <form id="edit-group-form">
</div> <div class="parameters-input">
<div id="camera-2" onclick="playVideo(2);"> <label for="group-id">Камера</label>
<img src="../../img/play-circle.svg"> <select name="group-id" id="group-id">
<span>Экспортировать 2 камеру</span> <option value="">Выберите номер камеры</option>
</div> <option value="1">Камера 1</option>
<div id="camera-3" onclick="playVideo(3);"> <option value="2">Камера 2</option>
<img src="../../img/play-circle.svg"> <option value="3">Камера 3</option>
<span>Экспортировать 3 камеру</span> <option value="4">Камера 4</option>
</div> <option value="5">Камера 5</option>
<div id="camera-4" onclick="playVideo(4);"> <option value="6">Камера 6</option>
<img src="../../img/play-circle.svg"> <option value="7">Камера 7</option>
<span>Экспортировать 4 камеру</span> <option value="8">Камера 8</option>
</div> <option value="9">Камера 9</option>
<div id="camera-5" onclick="playVideo(5);"> <option value="10">Камера 10</option>
<img src="../../img/play-circle.svg"> <option value="11">Камера 11</option>
<span>Экспортировать 5 камеру</span> <option value="12">Камера 12</option>
</div> <option value="13">Камера 13</option>
<div id="camera-6" onclick="playVideo(6);"> </select>
<img src="../../img/play-circle.svg">
<span>Экспортировать 6 камеру</span>
</div>
<div id="camera-7" onclick="playVideo(7);">
<img src="../../img/play-circle.svg">
<span>Экспортировать 7 камеру</span>
</div>
<div id="camera-8" onclick="playVideo(8);">
<img src="../../img/play-circle.svg">
<span>Экспортировать 8 камеру</span>
</div>
<div id="camera-9" onclick="playVideo(9);">
<img src="../../img/play-circle.svg">
<span>Экспортировать 9 камеру</span>
</div>
<div id="camera-10" onclick="playVideo(10);">
<img src="../../img/play-circle.svg">
<span>Экспортировать 10 камеру</span>
</div>
<div id="camera-11" onclick="playVideo(11);">
<img src="../../img/play-circle.svg">
<span>Экспортировать 11 камеру</span>
</div>
<div id="camera-12" onclick="playVideo(12);">
<img src="../../img/play-circle.svg">
<span>Экспортировать 12 камеру</span>
</div>
</div>
<div class="video-container-right">
<div id="camera-13" onclick="playVideo(13);">
<img src="../../img/play-circle.svg">
<span>Экспортировать 13 камеру</span>
</div>
<div id="camera-14" onclick="playVideo(14);">
<img src="../../img/play-circle.svg">
<span>Экспортировать 14 камеру</span>
</div>
<div id="camera-15" onclick="playVideo(15);">
<img src="../../img/play-circle.svg">
<span>Экспортировать 15 камеру</span>
</div>
<div id="camera-16" onclick="playVideo(16);">
<img src="../../img/play-circle.svg">
<span>Экспортировать 16 камеру</span>
</div>
</div> </div>
</form>
<div style="margin-left: 44px; margin-right: 72px; width: calc(100% - 44px - 72px);" class="horizontal-line"></div>
<button style="margin-top: 15px;" id="group-edit" class="button-purple" type="button" onclick="playVideo();">Скачать запись</button>
</section>
</div> </div>
<div class="calendar"> <div class="calendar">
@ -271,13 +245,39 @@
} }
.speedometr div { .speedometr div {
height: 200px; height: 190px;
} }
</style> </style>
<script src="../scripts/jquery.min.js"></script> <script src="../scripts/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
function updateCameraOptions() {
var selectedSerial = document.querySelector('input[name="camera-serial"]:checked').value;
var channelsInput = document.querySelector('#channels-' + selectedSerial);
var numChannels = parseInt(channelsInput.value, 10);
var select = document.querySelector('#group-id');
select.innerHTML = '';
var defaultOption = document.createElement('option');
defaultOption.value = '';
defaultOption.textContent = 'Выберите номер камеры';
select.appendChild(defaultOption);
for (var i = 1; i <= numChannels; i++) {
var option = document.createElement('option');
option.value = i;
option.textContent = 'Камера ' + i;
select.appendChild(option);
}
}
</script>
<script> <script>
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () {
const areaNames = document.querySelectorAll('.area-name'); const areaNames = document.querySelectorAll('.area-name');
@ -356,7 +356,8 @@ var selectedChannel = 1;
async function sendPostRequest() { async function sendPostRequest() {
document.getElementById("cameras").style.opacity = "30%"; updateCameraOptions();
document.getElementById("dataLoading").style.display = 'flex';
// Получение данных из полей ввода // Получение данных из полей ввода
const selectedDate = document.getElementById("selectedDate").value; const selectedDate = document.getElementById("selectedDate").value;
const videoTime = document.getElementById("video-time").value; const videoTime = document.getElementById("video-time").value;
@ -395,8 +396,6 @@ async function sendPostRequest() {
.then((response) => response.json()) .then((response) => response.json())
.then((data) => { .then((data) => {
document.getElementById("cameras").style.opacity = "100%";
const existingChart = Chart.getChart("speed"); const existingChart = Chart.getChart("speed");
if (existingChart) { if (existingChart) {
@ -404,13 +403,13 @@ async function sendPostRequest() {
} }
const numberOfLabels = data.speeds.length; const numberOfLabels = data.speeds.length;
const labels = Array.from({ length: numberOfLabels }, () => ""); // const labels = Array.from({ length: numberOfLabels }, () => "");
// Обновление данных графика // Обновление данных графика
const chart = new Chart("speed", { const chart = new Chart("speed", {
type: "line", type: "line",
data: { data: {
labels: labels, labels: data.names,
datasets: [ datasets: [
{ {
label: "Скорость", label: "Скорость",
@ -445,6 +444,19 @@ async function sendPostRequest() {
}, },
}, },
x: { x: {
ticks: {
autoSkip: false,
callback: function(value, index, values) {
const data = this.chart.data.labels;
if (index === 0 || index === values.length - 1) {
return data[index];
} else {
return '';
}
},
position: 'bottom',
maxRotation: 0,
},
grid: { grid: {
display: false, display: false,
}, },
@ -482,19 +494,72 @@ async function sendPostRequest() {
}) })
.catch((error) => { .catch((error) => {
document.getElementById("dataLoading").style.display = 'none';
var h1Element = document.querySelector('.speedometr h1');
h1Element.textContent = 'Ошибка отправки запроса.';
console.error("Ошибка при отправке запроса:", error); console.error("Ошибка при отправке запроса:", error);
}); });
const endResponse = await fetch(`/getData?serial=${selectedSerial}&selectedDate=${formatDate(selectedDate)}&selectedTime=${formatTime(videoEndTime)}&selectedChannel=${selectedChannel}`); const endResponse = await fetch(`/getData?serial=${selectedSerial}&selectedDate=${formatDate(selectedDate)}&selectedTime=${formatTime(videoEndTime)}&selectedChannel=${selectedChannel}`);
const endData = await endResponse.json(); const endData = await endResponse.json();
if (endData.success) { if (endData.success) {
document.getElementById("dataLoading").style.display = 'none';
console.log(`Конечные данные доступны. DATAID: ${endData.dataId}`) console.log(`Конечные данные доступны. DATAID: ${endData.dataId}`)
const speedBG = document.getElementById("speed-bg"); const speedBG = document.getElementById("speed-bg");
speedBG.style.display = 'none'; speedBG.style.display = 'none';
HasData = true; HasData = true;
if (data.dataId != endData.dataId) { if (data.dataId != endData.dataId) {
const existingChart = Chart.getChart("speed");
if (existingChart) {
existingChart.destroy();
}
const chart = new Chart("speed", {
type: "line",
data: {
labels: "",
datasets: [
{
label: "Скорость",
borderColor: "#8086F9",
fill: false,
data: "",
pointStyle: false,
pointRadius: 25,
pointHoverRadius: 25,
tension: 0.1,
},
],
},
options: {
plugins: {
legend: {
display: false,
},
},
labelStep: "3",
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
stacked: true,
grid: {
display: true,
color: "#D9D9D9",
},
ticks: {
stepSize: 10,
},
},
x: {
grid: {
display: false,
},
},
},
},
});
HasData = false; HasData = false;
var h1Element = document.querySelector('.speedometr h1'); var h1Element = document.querySelector('.speedometr h1');
h1Element.textContent = 'Временной диапазон находится в разных видео сессиях. Измените время.'; h1Element.textContent = 'Временной диапазон находится в разных видео сессиях. Измените время.';
@ -502,6 +567,57 @@ async function sendPostRequest() {
speedBG.style.display = 'flex'; speedBG.style.display = 'flex';
} }
} else { } else {
document.getElementById("dataLoading").style.display = 'none';
const existingChart = Chart.getChart("speed");
if (existingChart) {
existingChart.destroy();
}
const chart = new Chart("speed", {
type: "line",
data: {
labels: "",
datasets: [
{
label: "Скорость",
borderColor: "#8086F9",
fill: false,
data: "",
pointStyle: false,
pointRadius: 25,
pointHoverRadius: 25,
tension: 0.1,
},
],
},
options: {
plugins: {
legend: {
display: false,
},
},
labelStep: "3",
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
stacked: true,
grid: {
display: true,
color: "#D9D9D9",
},
ticks: {
stepSize: 10,
},
},
x: {
grid: {
display: false,
},
},
},
},
});
HasData = false; HasData = false;
const speedBG = document.getElementById("speed-bg"); const speedBG = document.getElementById("speed-bg");
speedBG.style.display = 'flex'; speedBG.style.display = 'flex';
@ -511,6 +627,56 @@ async function sendPostRequest() {
} else { } else {
const existingChart = Chart.getChart("speed");
if (existingChart) {
existingChart.destroy();
}
const chart = new Chart("speed", {
type: "line",
data: {
labels: "",
datasets: [
{
label: "Скорость",
borderColor: "#8086F9",
fill: false,
data: "",
pointStyle: false,
pointRadius: 25,
pointHoverRadius: 25,
tension: 0.1,
},
],
},
options: {
plugins: {
legend: {
display: false,
},
},
labelStep: "3",
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
stacked: true,
grid: {
display: true,
color: "#D9D9D9",
},
ticks: {
stepSize: 10,
},
},
x: {
grid: {
display: false,
},
},
},
},
});
var h1Element = document.querySelector('.speedometr h1'); var h1Element = document.querySelector('.speedometr h1');
h1Element.textContent = 'Данных для выбранного периода нет.'; h1Element.textContent = 'Данных для выбранного периода нет.';
const speedBG = document.getElementById("speed-bg"); const speedBG = document.getElementById("speed-bg");
@ -530,10 +696,10 @@ const selectedDateInput = document.getElementById("selectedDate");
selectedDateInput.addEventListener("change", sendPostRequest); selectedDateInput.addEventListener("change", sendPostRequest);
const videoTimeInput = document.getElementById("video-time"); const videoTimeInput = document.getElementById("video-time");
videoTimeInput.addEventListener("change", sendPostRequest); videoTimeInput.addEventListener("blur", sendPostRequest);
const endVideoTimeInput = document.getElementById("video-end-time"); const endVideoTimeInput = document.getElementById("video-end-time");
endVideoTimeInput.addEventListener("change", sendPostRequest); endVideoTimeInput.addEventListener("blur", sendPostRequest);
</script> </script>
@ -652,13 +818,17 @@ endVideoTimeInput.addEventListener("change", sendPostRequest);
} }
async function playVideo(channel) { async function playVideo() {
document.getElementById("exportLoading").style.display = 'flex'; const channel = document.getElementById("group-id").value;
const selectedDevice = document.querySelector('input[name="camera-serial"]:checked'); const selectedDevice = document.querySelector('input[name="camera-serial"]:checked');
if (!selectedDevice) { if (!selectedDevice) {
alert('Пожалуйста, выберите устройство из списка.'); alert('Пожалуйста, выберите устройство из списка.');
return; return;
} }
if (channel === "") {
alert('Пожалуйста, выберите камеру из списка.');
return;
}
if (!HasData) { if (!HasData) {
alert('Пожалуйста, выберите другой временной период.'); alert('Пожалуйста, выберите другой временной период.');
return; return;
@ -667,6 +837,7 @@ endVideoTimeInput.addEventListener("change", sendPostRequest);
alert('Конечное время не может быть больше начального.'); alert('Конечное время не может быть больше начального.');
return; return;
} }
document.getElementById("exportLoading").style.display = 'flex';
const startTimeInput = document.getElementById('video-time'); const startTimeInput = document.getElementById('video-time');
const endTimeInput = document.getElementById('video-end-time'); const endTimeInput = document.getElementById('video-end-time');
@ -794,9 +965,7 @@ datasets: [
label: "Скорость", label: "Скорость",
borderColor: "#8086F9", borderColor: "#8086F9",
fill: false, fill: false,
data: [ data: "",
{{Speeds}}
],
pointStyle: false, pointStyle: false,
pointRadius: 25, pointRadius: 25,
pointHoverRadius: 25, pointHoverRadius: 25,

View File

@ -58,6 +58,21 @@
</section> </section>
<section class="main"> <section class="main">
<section style="display: none;" class="dberror" id="dataLoading" >
<div class="loader-container">
<div class="loader">
<div class="square" id="sq11"></div>
<div class="square" id="sq12"></div>
<div class="square" id="sq13"></div>
<div class="square" id="sq14"></div>
<div class="square" id="sq15"></div>
<div class="square" id="sq16"></div>
<div class="square" id="sq17"></div>
<div class="square" id="sq18"></div>
<div class="square" id="sq19"></div>
</div>
</div>
</section>
{{#if ifDBError}} {{#if ifDBError}}
<section class="dberror"> <section class="dberror">
<div class="erorr-container"> <div class="erorr-container">
@ -89,6 +104,7 @@
{{#each devices}} {{#each devices}}
<li class="device"> <li class="device">
<img> <img>
<input type="number" id="channels-{{this.serial}}" value="{{this.channels}}" hidden>
<input type="radio" name="camera-serial" id="radio-{{this.serial}}" class="radio-input" value="{{this.serial}}" hidden> <input type="radio" name="camera-serial" id="radio-{{this.serial}}" class="radio-input" value="{{this.serial}}" hidden>
<label for="radio-{{this.serial}}" class="radio-label active-{{this.status}}"> <label for="radio-{{this.serial}}" class="radio-label active-{{this.status}}">
{{this.serial}} {{this.serial}}
@ -108,86 +124,42 @@
<section class="table" style="position: relative;"> <section class="table" style="position: relative;">
<div class="map"> <div class="map">
<!-- <div id="properties" class="properties" style="display: none;">
<div class="propert"><h1>Группа</h1><br><h2 id="propert-group">Автобусы</h2></div>
<div class="propert"><h1>Скорость</h1><br><h2 id="propert-speed"> км/ч</h2></div>
<div class="propert"><h1>Номерной знак</h1><br><h2 id="propert-plate"></h2></div>
<div class="propert"><h1>Геопозиция</h1><br><h2 id="propert-geo"></h2></div>
</div> -->
<div id="map"></div> <div id="map"></div>
</div> </div>
<div class="cameras" id="cameras"> <div style="background: white;" class="cameras">
<div class="video-container"> <section style="border: 0;" class="whole-width">
<div id="camera-1" onclick="playVideo(1);"> <h1>Запустить запись с камеры</h1>
<img src="../../img/play-circle.svg"> <h3>Выберите камеру, время и нажмите кнопку "Запустить запись"</h3>
<span>Запустить 1 камеру</span> <form id="edit-group-form">
</div> <div class="parameters-input">
<div id="camera-2" onclick="playVideo(2);"> <label for="group-id">Камера</label>
<img src="../../img/play-circle.svg"> <select name="group-id" id="group-id">
<span>Запустить 2 камеру</span> <option value="">Выберите номер камеры</option>
</div> <option value="1">Камера 1</option>
<div id="camera-3" onclick="playVideo(3);"> <option value="2">Камера 2</option>
<img src="../../img/play-circle.svg"> <option value="3">Камера 3</option>
<span>Запустить 3 камеру</span> <option value="4">Камера 4</option>
</div> <option value="5">Камера 5</option>
<div id="camera-4" onclick="playVideo(4);"> <option value="6">Камера 6</option>
<img src="../../img/play-circle.svg"> <option value="7">Камера 7</option>
<span>Запустить 4 камеру</span> <option value="8">Камера 8</option>
</div> <option value="9">Камера 9</option>
<div id="camera-5" onclick="playVideo(5);"> <option value="10">Камера 10</option>
<img src="../../img/play-circle.svg"> <option value="11">Камера 11</option>
<span>Запустить 5 камеру</span> <option value="12">Камера 12</option>
</div> <option value="13">Камера 13</option>
<div id="camera-6" onclick="playVideo(6);"> </select>
<img src="../../img/play-circle.svg">
<span>Запустить 6 камеру</span>
</div>
<div id="camera-7" onclick="playVideo(7);">
<img src="../../img/play-circle.svg">
<span>Запустить 7 камеру</span>
</div>
<div id="camera-8" onclick="playVideo(8);">
<img src="../../img/play-circle.svg">
<span>Запустить 8 камеру</span>
</div>
<div id="camera-9" onclick="playVideo(9);">
<img src="../../img/play-circle.svg">
<span>Запустить 9 камеру</span>
</div>
<div id="camera-10" onclick="playVideo(10);">
<img src="../../img/play-circle.svg">
<span>Запустить 10 камеру</span>
</div>
<div id="camera-11" onclick="playVideo(11);">
<img src="../../img/play-circle.svg">
<span>Запустить 11 камеру</span>
</div>
<div id="camera-12" onclick="playVideo(12);">
<img src="../../img/play-circle.svg">
<span>Запустить 12 камеру</span>
</div>
</div>
<div class="video-container-right">
<div id="camera-13" onclick="playVideo(13);">
<img src="../../img/play-circle.svg">
<span>Запустить 13 камеру</span>
</div>
<div id="camera-14" onclick="playVideo(14);">
<img src="../../img/play-circle.svg">
<span>Запустить 14 камеру</span>
</div>
<div id="camera-15" onclick="playVideo(15);">
<img src="../../img/play-circle.svg">
<span>Запустить 15 камеру</span>
</div>
<div id="camera-16" onclick="playVideo(16);">
<img src="../../img/play-circle.svg">
<span>Запустить 16 камеру</span>
</div>
</div> </div>
</form>
<div style="margin-left: 44px; margin-right: 72px; width: calc(100% - 44px - 72px);" class="horizontal-line"></div>
<button style="margin-top: 15px;" id="group-edit" class="button-purple" type="button" onclick="playVideo();">Запустить запись</button>
</section>
</div> </div>
<div class="calendar"> <div class="calendar">
<div class="calendar-header"> <div class="calendar-header">
<button id="prevMonth"></button> <button id="prevMonth"></button>
@ -251,13 +223,39 @@
} }
.speedometr div { .speedometr div {
height: 200px; height: 190px;
} }
</style> </style>
<script src="../scripts/jquery.min.js"></script> <script src="../scripts/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
function updateCameraOptions() {
var selectedSerial = document.querySelector('input[name="camera-serial"]:checked').value;
var channelsInput = document.querySelector('#channels-' + selectedSerial);
var numChannels = parseInt(channelsInput.value, 10);
var select = document.querySelector('#group-id');
select.innerHTML = '';
var defaultOption = document.createElement('option');
defaultOption.value = '';
defaultOption.textContent = 'Выберите номер камеры';
select.appendChild(defaultOption);
for (var i = 1; i <= numChannels; i++) {
var option = document.createElement('option');
option.value = i;
option.textContent = 'Камера ' + i;
select.appendChild(option);
}
}
</script>
<script> <script>
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () {
const areaNames = document.querySelectorAll('.area-name'); const areaNames = document.querySelectorAll('.area-name');
@ -333,7 +331,8 @@ let HasData;
var selectedChannel = 1; var selectedChannel = 1;
async function sendPostRequest() { async function sendPostRequest() {
document.getElementById("cameras").style.opacity = "30%"; updateCameraOptions();
document.getElementById("dataLoading").style.display = 'flex';
// Получение данных из полей ввода // Получение данных из полей ввода
const selectedDate = document.getElementById("selectedDate").value; const selectedDate = document.getElementById("selectedDate").value;
const videoTime = document.getElementById("video-time").value; const videoTime = document.getElementById("video-time").value;
@ -365,7 +364,7 @@ async function sendPostRequest() {
.then((response) => response.json()) .then((response) => response.json())
.then((data) => { .then((data) => {
document.getElementById("cameras").style.opacity = "100%"; document.getElementById("dataLoading").style.display = 'none';
const existingChart = Chart.getChart("speed"); const existingChart = Chart.getChart("speed");
@ -374,13 +373,13 @@ async function sendPostRequest() {
} }
const numberOfLabels = data.speeds.length; const numberOfLabels = data.speeds.length;
const labels = Array.from({ length: numberOfLabels }, () => ""); // const labels = Array.from({ length: numberOfLabels }, () => "");
// Обновление данных графика // Обновление данных графика
const chart = new Chart("speed", { const chart = new Chart("speed", {
type: "line", type: "line",
data: { data: {
labels: labels, labels: data.names,
datasets: [ datasets: [
{ {
label: "Скорость", label: "Скорость",
@ -415,6 +414,19 @@ async function sendPostRequest() {
}, },
}, },
x: { x: {
ticks: {
autoSkip: false,
callback: function(value, index, values) {
const data = this.chart.data.labels;
if (index === 0 || index === values.length - 1) {
return data[index];
} else {
return '';
}
},
position: 'bottom',
maxRotation: 0,
},
grid: { grid: {
display: false, display: false,
}, },
@ -452,9 +464,62 @@ async function sendPostRequest() {
}) })
.catch((error) => { .catch((error) => {
document.getElementById("dataLoading").style.display = 'none';
var h1Element = document.querySelector('.speedometr h1');
h1Element.textContent = 'Ошибка отправки запроса.';
console.error("Ошибка при отправке запроса:", error); console.error("Ошибка при отправке запроса:", error);
}); });
} else { } else {
const existingChart = Chart.getChart("speed");
if (existingChart) {
existingChart.destroy();
}
const chart = new Chart("speed", {
type: "line",
data: {
labels: "",
datasets: [
{
label: "Скорость",
borderColor: "#8086F9",
fill: false,
data: "",
pointStyle: false,
pointRadius: 25,
pointHoverRadius: 25,
tension: 0.1,
},
],
},
options: {
plugins: {
legend: {
display: false,
},
},
labelStep: "3",
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
stacked: true,
grid: {
display: true,
color: "#D9D9D9",
},
ticks: {
stepSize: 10,
},
},
x: {
grid: {
display: false,
},
},
},
},
});
const speedBG = document.getElementById("speed-bg"); const speedBG = document.getElementById("speed-bg");
speedBG.style.display = 'flex'; speedBG.style.display = 'flex';
} }
@ -472,7 +537,7 @@ const selectedDateInput = document.getElementById("selectedDate");
selectedDateInput.addEventListener("change", sendPostRequest); selectedDateInput.addEventListener("change", sendPostRequest);
const videoTimeInput = document.getElementById("video-time"); const videoTimeInput = document.getElementById("video-time");
videoTimeInput.addEventListener("change", sendPostRequest); videoTimeInput.addEventListener("blur", sendPostRequest);
</script> </script>
@ -585,12 +650,17 @@ videoTimeInput.addEventListener("change", sendPostRequest);
return formatTime(`${hours}:${minutes}:${seconds}`); return formatTime(`${hours}:${minutes}:${seconds}`);
} }
function playVideo(channel) { function playVideo() {
const channel = document.getElementById("group-id").value;
const selectedDevice = document.querySelector('input[name="camera-serial"]:checked'); const selectedDevice = document.querySelector('input[name="camera-serial"]:checked');
if (!selectedDevice) { if (!selectedDevice) {
alert('Пожалуйста, выберите устройство из списка.'); alert('Пожалуйста, выберите устройство из списка.');
return; return;
} }
if (channel === "") {
alert('Пожалуйста, выберите камеру из списка.');
return;
}
if (!HasData) { if (!HasData) {
alert('Пожалуйста, выберите другой временной период.'); alert('Пожалуйста, выберите другой временной период.');
return; return;
@ -714,9 +784,7 @@ datasets: [
label: "Скорость", label: "Скорость",
borderColor: "#8086F9", borderColor: "#8086F9",
fill: false, fill: false,
data: [ data: "",
{{Speeds}}
],
pointStyle: false, pointStyle: false,
pointRadius: 25, pointRadius: 25,
pointHoverRadius: 25, pointHoverRadius: 25,