#include "mainwindow.h" #include "./ui_mainwindow.h" #include "alarmsservice.h" #include "flowlayout.h" #include "paginationbar.h" #include "sensordialog.h" #include "alarmwidget.h" #include "journalservice.h" #include "logwidget.h" #include "qcustomplot.h" #include "serverwidget.h" #include #include #include #include #include #include #include #include #include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); httpClient = new HttpClient(this); sensorService = new SensorService(httpClient, this); alarmsService = new AlarmsService(httpClient, this); journalService = new JournalService(httpClient, this); TranslateUpdate(); SetupSensorTab(); startRefreshTimer(); SetupIncidentTab(); SetupStatisticTab(); SetupJournalTab(); //------------------------------------------------------------------------------ settings = sensorService->getSettings(); ui->serialLineEdit->setText(settings.serial); ui->factoryLineEdit->setText(settings.factory); ui->exhuyantLineEdit->setText(settings.exhuyant); ui->fleetLineEdit->setText(settings.fleet); ui->sideLineEdit->setText(settings.side); ui->gosNumberLineEdit->setText(settings.gosNumber); ui->factoryNumberLineEdit->setText(settings.factoryNumber); ui->groupLineEdit->setText(settings.group); ui->adresLineEdit->setText(settings.adres); ui->userNameLineEdit->setText(settings.userName); ui->userPasswordLineEdit->setText(settings.userPassword); ui->argusSerialLineEdit->setText(settings.argusSerial); QLayoutItem *child; while ((child = ui->scrollAreaServersLayout->takeAt(0)) != nullptr) { if (child->widget()) { child->widget()->deleteLater(); } } for (const auto &server : settings.servers) { QString domain = server.first; int port = server.second.toInt(); ServerWidget *serverWidget = new ServerWidget(domain, port, this); connect(serverWidget, &ServerWidget::removeWidget, this, [this, serverWidget]() { serverWidget->deleteLater(); }); ui->scrollAreaServersLayout->addWidget(serverWidget); } connect(ui->tabWidget, &QTabWidget::currentChanged, this, [this](int index) { if (index == 4) { settings = sensorService->getSettings(); } }); connect(ui->serverButtonSettings, &QPushButton::clicked, this, &MainWindow::onServerButtonSettings); connect(ui->saveButtonSettings, &QPushButton::clicked, this, &MainWindow::onSaveButtonSettings); connect(ui->cancelButtonSettings, &QPushButton::clicked, this, &MainWindow::onCancelButtonSettings); connect(ui->importButtonSettings, &QPushButton::clicked, this, &MainWindow::onImportButtonSettings); connect(ui->exportButtonSettings, &QPushButton::clicked, this, &MainWindow::onExportButtonSettings); } void MainWindow::onServerButtonSettings() { ServerWidget *serverWidget = new ServerWidget("", 0000, this); connect(serverWidget, &ServerWidget::removeWidget, this, [this, serverWidget]() { serverWidget->deleteLater(); }); ui->scrollAreaServersLayout->addWidget(serverWidget); } void MainWindow::onSaveButtonSettings(){ settings.serial = ui->serialLineEdit->text(); settings.factory = ui->factoryLineEdit->text(); settings.exhuyant = ui->exhuyantLineEdit->text(); settings.fleet = ui->fleetLineEdit->text(); settings.side = ui->sideLineEdit->text(); settings.gosNumber = ui->gosNumberLineEdit->text(); settings.factoryNumber = ui->factoryNumberLineEdit->text(); settings.group = ui->groupLineEdit->text(); settings.adres = ui->adresLineEdit->text(); settings.userName = ui->userNameLineEdit->text(); settings.userPassword = ui->userPasswordLineEdit->text(); settings.argusSerial = ui->argusSerialLineEdit->text(); settings.servers.clear(); QList> updatedServers; for (int i = 0; i < ui->scrollAreaServersLayout->count(); ++i) { if (auto *serverWidget = qobject_cast(ui->scrollAreaServersLayout->itemAt(i)->widget())) { if (!serverWidget->deleted) { qDebug() << serverWidget->getDomain() << ' ' << serverWidget->deleted; updatedServers.append(qMakePair(serverWidget->getDomain(), serverWidget->getPort())); } } } settings.servers = updatedServers; sensorService->updateSettings(settings); onCancelButtonSettings(); } void MainWindow::onCancelButtonSettings(){ settings = sensorService->getSettings(); ui->serialLineEdit->setText(settings.serial); ui->factoryLineEdit->setText(settings.factory); ui->exhuyantLineEdit->setText(settings.exhuyant); ui->fleetLineEdit->setText(settings.fleet); ui->sideLineEdit->setText(settings.side); ui->gosNumberLineEdit->setText(settings.gosNumber); ui->factoryNumberLineEdit->setText(settings.factoryNumber); ui->groupLineEdit->setText(settings.group); ui->adresLineEdit->setText(settings.adres); ui->userNameLineEdit->setText(settings.userName); ui->userPasswordLineEdit->setText(settings.userPassword); ui->argusSerialLineEdit->setText(settings.argusSerial); QLayoutItem *child; while ((child = ui->scrollAreaServersLayout->takeAt(0)) != nullptr) { if (child->widget()) { child->widget()->deleteLater(); } } for (const auto &server : settings.servers) { QString domain = server.first; int port = server.second.toInt(); ServerWidget *serverWidget = new ServerWidget(domain, port, this); connect(serverWidget, &ServerWidget::removeWidget, this, [this, serverWidget]() { serverWidget->deleteLater(); }); ui->scrollAreaServersLayout->addWidget(serverWidget); } } void MainWindow::onImportButtonSettings() { QString filePath = QFileDialog::getOpenFileName( this, "Открыть файл настроек", QDir::homePath(), "JSON файлы (*.json);;Все файлы (*)" ); if (filePath.isEmpty()) { return; } QFile file(filePath); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { QMessageBox::critical(this, "Ошибка", "Не удалось открыть файл настроек."); return; } QByteArray fileData = file.readAll(); file.close(); QJsonParseError parseError; QJsonDocument jsonDoc = QJsonDocument::fromJson(fileData, &parseError); if (parseError.error != QJsonParseError::NoError) { QMessageBox::critical(this, "Ошибка", "Файл содержит некорректный JSON: " + parseError.errorString()); return; } if (!jsonDoc.isObject()) { QMessageBox::critical(this, "Ошибка", "Файл настроек должен содержать JSON-объект."); return; } QJsonObject settingsJson = jsonDoc.object(); QJsonObject response = httpClient->post(utils::API_URL + "/settings/deviceSettings", settingsJson); if (response.isEmpty()) { QMessageBox::critical(this, "Ошибка", "Не удалось отправить настройки на сервер."); } else { QMessageBox::information(this, "Успех", "Настройки успешно импортированы."); } onCancelButtonSettings(); } void MainWindow::onExportButtonSettings(){ QJsonObject responseJson = httpClient->get(utils::API_URL + "/settings/deviceSettings"); if (responseJson.isEmpty()) { QMessageBox::warning(this, "Ошибка", "Не удалось получить настройки с сервера."); return; } QString filePath = QFileDialog::getSaveFileName( this, "Сохранить файл настроек", QDir::homePath() + "/settings.json", "JSON файлы (*.json);;Все файлы (*)" ); // Если путь не выбран, выходим if (filePath.isEmpty()) { return; } // Конвертируем JSON в строку QJsonDocument jsonDoc(responseJson); QByteArray jsonData = jsonDoc.toJson(QJsonDocument::Indented); // Сохраняем JSON в файл QFile file(filePath); if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { file.write(jsonData); file.close(); QMessageBox::information(this, "Успех", "Настройки успешно сохранены в файл."); } else { QMessageBox::critical(this, "Ошибка", "Не удалось сохранить настройки в файл."); } } void MainWindow::SetupStatisticTab() { statisticType = 0; ui->startSelectStatistic->setDisplayFormat("dd/MM/yyyy HH:mm"); ui->endSelectStatistic->setDisplayFormat("dd/MM/yyyy HH:mm"); updateComboboxStatistic(); realTimeChartTimer = new QTimer(this); statisticChart = new QCustomPlot(this); statisticChart->setFixedSize(1210, 650); statisticChart->addGraph(); QPen pen; pen.setColor(QColor(19, 58, 97)); pen.setWidth(2); statisticChart->graph(0)->setPen(pen); QSharedPointer dateTimeTicker(new QCPAxisTickerDateTime); dateTimeTicker->setDateTimeFormat("HH:mm:ss dd.MM.yyyy"); statisticChart->xAxis->setTicker(dateTimeTicker); statisticChart->axisRect()->setupFullAxesBox(); statisticChart->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); ui->chartNButtonsLayout->addWidget(statisticChart); statisticChart->hide(); connect(realTimeChartTimer, &QTimer::timeout, this, &MainWindow::updateRealTimeChart); connect(ui->sensorSelectStatistic, QOverload::of(&QComboBox::currentIndexChanged), this, &MainWindow::onSensorSelectStatisticChanged); connect(ui->realTimeButtonStatistic, &QPushButton::clicked, this, &MainWindow::onRealTimeStatisticClicked); connect(ui->archiveButtonStatistic, &QPushButton::clicked, this, &MainWindow::onArchiveStatisticClicked); connect(ui->showStatisticButton, &QPushButton::clicked, this, &MainWindow::onShowStatisticClicked); } void MainWindow::ondialogClosedFromWidget(QString groupWithSensor, QDateTime start, QDateTime end) { ui->tabWidget->setCurrentIndex(2); ui->sensorSelectStatistic->setCurrentIndex(groupWithSensorToIndex[groupWithSensor]); ui->startSelectStatistic->setDateTime(start); ui->endSelectStatistic->setDateTime(end); onArchiveStatisticClicked(); onShowStatisticClicked(); } void MainWindow::onSensorSelectStatisticChanged(int index) { if(statisticType) { onRealTimeStatisticClicked(); } } void MainWindow::updateRealTimeChart() { if (!statisticChart) return; qint64 endTime = QDateTime::currentSecsSinceEpoch(); qint64 startTime = endTime - 5; PlotData newData = sensorService->getDeviceSensorData( groupWithSensor[ui->sensorSelectStatistic->currentIndex()], startTime, endTime); if (!newData.X.isEmpty() && !newData.Y.isEmpty()) { for(size_t i = 0; i < newData.X.size(); ++i) { statisticChart->graph(0)->addData(newData.X[i], newData.Y[i]); } statisticChart->replot(); } } void MainWindow::onRealTimeStatisticClicked() { statisticType = 1; ui->startSelectStatistic->hide(); ui->endSelectStatistic->hide(); ui->showStatisticButton->hide(); ui->label_16->hide(); ui->label_14->hide(); if (statisticType) { ui->realTimeButtonStatistic->setStyleSheet(R"( QPushButton { border-style: solid; border-color: #d5cb7a; border-width: 2px; background-color: #d5cb7a; color: #13385F; font-family: Inter; font-size: 22px; font-weight: 500; line-height: 26.63px; text-align: center; border-top-left-radius: 5px; border-bottom-left-radius: 5px; } )"); ui->archiveButtonStatistic->setStyleSheet(R"( QPushButton { border-style: solid; border-color: #d5cb7a; border-width: 2px; color: #13385F; font-family: Inter; font-size: 22px; font-weight: 500; line-height: 26.63px; text-align: center; border-top-right-radius: 5px; border-bottom-right-radius: 5px; } )"); } ui->pseudoChart->hide(); statisticChart->show(); qint64 currentTime = QDateTime::currentSecsSinceEpoch(); qint64 initialStartTime = 1; PlotData initialData = sensorService->getDeviceSensorData( groupWithSensor[ui->sensorSelectStatistic->currentIndex()], initialStartTime, currentTime); if (!initialData.X.isEmpty() && !initialData.Y.isEmpty()) { statisticChart->graph(0)->setData(initialData.X, initialData.Y); statisticChart->xAxis->setRange(initialData.X.last() - 600, initialData.X.last()); statisticChart->yAxis->setRange(*std::min_element(initialData.Y.begin(), initialData.Y.end()) - 10, *std::max_element(initialData.Y.begin(), initialData.Y.end()) + 10); statisticChart->replot(); } realTimeChartTimer->start(5000); } void MainWindow::onArchiveStatisticClicked() { if (realTimeChartTimer && realTimeChartTimer->isActive()) { realTimeChartTimer->stop(); } statisticType = 0; statisticChart->hide(); ui->pseudoChart->show(); ui->startSelectStatistic->show(); ui->endSelectStatistic->show(); ui->showStatisticButton->show(); ui->label_16->show(); ui->label_14->show(); if(!statisticType) { ui->realTimeButtonStatistic->setStyleSheet(R"( QPushButton { border-style: solid; border-color: #d5cb7a; border-width: 2px; color: #13385F; font-family: Inter; font-size: 22px; font-weight: 500; line-height: 26.63px; text-align: center; border-top-left-radius: 5px; border-bottom-left-radius: 5px; } )"); ui->archiveButtonStatistic->setStyleSheet(R"( QPushButton { border-style: solid; border-color: #d5cb7a; border-width: 2px; background-color: #d5cb7a; color: #13385F; font-family: Inter; font-size: 22px; font-weight: 500; line-height: 26.63px; text-align: center; border-top-right-radius: 5px; border-bottom-right-radius: 5px; } )"); } } void MainWindow::onShowStatisticClicked() { qDebug() << "1"; ui->pseudoChart->hide(); qDebug() << "2"; if (!statisticChart) { qDebug() << "statisticChart is nullptr!"; return; } statisticChart->show(); qDebug() << "3"; qint64 start = ui->startSelectStatistic->dateTime().toSecsSinceEpoch(); if(!start) { start = 1; } qint64 end = ui->endSelectStatistic->dateTime().toSecsSinceEpoch(); if(!end) { end = QDateTime::currentMSecsSinceEpoch(); } PlotData data = sensorService->getDeviceSensorData(groupWithSensor[ui->sensorSelectStatistic->currentIndex()], start, end); qDebug() << "3"; statisticChart->graph(0)->setData(data.X, data.Y); statisticChart->yAxis->setRange(*std::min_element(data.Y.begin(), data.Y.end()) - 10, *std::max_element(data.Y.begin(), data.Y.end()) + 10); statisticChart->graph(0)->rescaleAxes(); statisticChart->replot(); } void MainWindow::updateComboboxStatistic() { ui->sensorSelectStatistic->clear(); groupWithSensor.clear(); sensorGroupTree tree = sensorService->getSensorGroupsTree(); QStringList groups = tree.groupToLocalGroup.keys(); std::sort(groups.begin(), groups.end(), [&tree](const QString &a, const QString &b) { return tree.groupToLocalGroup[a] < tree.groupToLocalGroup[b]; }); int index = 0; for (const QString &group : groups) { const QString &localizedGroupName = tree.groupToLocalGroup[group]; if (tree.groupToSensorWithLocal.contains(group)) { const QMap &sensors = tree.groupToSensorWithLocal[group]; for (auto it = sensors.begin(); it != sensors.end(); ++it) { const QString &sensorId = it.key(); const QString &sensorName = it.value(); QString itemData = group + '/' + sensorId; groupWithSensorToIndex[itemData] = index; groupWithSensor.append(itemData); ui->sensorSelectStatistic->addItem(localizedGroupName + '/' + sensorName, QVariant::fromValue(itemData)); index++; } } } } void MainWindow::SetupJournalTab() { loadSensorsTree(ui->treeJournal); connect(ui->searchJournal, &QLineEdit::textChanged, this, &MainWindow::onSearchJournalTextChanged); ui->timeIntervalJournal->addItems( {"За всё время", "За сегодня", "За вчера", "За последние 7 дней"}); ui->statusJournal->addItems( {"Все статусы", "Отладка", "Информация", "Предупреждение", "Ошибка", "Экстренно"}); ui->sortJournal->addItems({"По времени", "По критичности"}); journalSettings = getJournalDataSettings(); int amount = journalService->getLogsAmount(journalSettings->groupsWithSensors, journalSettings->status, journalSettings->start_time, journalSettings->end_time); paginationBarJournal = new PaginationBar((amount + 24 - 1)/ 24); ui->paginationBarJournalLayout->addStretch(); ui->paginationBarJournalLayout->addWidget(paginationBarJournal); ui->paginationBarJournalLayout->addStretch(); QList arr = journalService->getLogs(journalSettings->groupsWithSensors, journalSettings->status, journalSettings->cmp, journalSettings->start_time, journalSettings->end_time, 1, 24); for(int i = 0; i < arr.size(); ++i) { LogWidget *logWidget = new LogWidget(translate, arr[i].getTime(), arr[i].getMessage(), arr[i].getSensorId(), arr[i].getSensorGroup(), arr[i].getThreatLevel(), ui->scrollWidgetJournal); logWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); ui->scrollLayoutJournal->addWidget(logWidget); } if (arr.size() < 24) { QSpacerItem *spacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); ui->scrollLayoutJournal->addSpacerItem(spacer); } connect(ui->searchLogs, &QPushButton::clicked, this, &MainWindow::onSearchJournalClicked); connect(ui->updateTreeButtonJournal, &QPushButton::clicked, this, &MainWindow::updateTreeClicked); connect(paginationBarJournal, &PaginationBar::pageChanged, this, &MainWindow::onJournalPageChanged); } void MainWindow::onJournalPageChanged(int page) { while (QLayoutItem *item = ui->scrollLayoutJournal->takeAt(0)) { if (QWidget *widget = item->widget()) { widget->deleteLater(); } delete item; } QList arr = journalService->getLogs(journalSettings->groupsWithSensors, journalSettings->status, journalSettings->cmp, journalSettings->start_time, journalSettings->end_time, page, 24); for(int i = 0; i < arr.size(); ++i) { LogWidget *logWidget = new LogWidget(translate, arr[i].getTime(), arr[i].getMessage(), arr[i].getSensorId(), arr[i].getSensorGroup(), arr[i].getThreatLevel(), ui->scrollWidgetJournal); logWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); ui->scrollLayoutJournal->addWidget(logWidget); } if (arr.size() < 24) { QSpacerItem *spacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); ui->scrollLayoutJournal->addSpacerItem(spacer); } } void MainWindow::onSearchJournalClicked() { while (QLayoutItem *item = ui->scrollLayoutJournal->takeAt(0)) { if (QWidget *widget = item->widget()) { widget->deleteLater(); } delete item; } journalSettings = getJournalDataSettings(); int amount = journalService->getLogsAmount(journalSettings->groupsWithSensors, journalSettings->status, journalSettings->start_time, journalSettings->end_time); paginationBarJournal->setTotalPages((amount + 24 - 1)/ 24); QList arr = journalService->getLogs(journalSettings->groupsWithSensors, journalSettings->status, journalSettings->cmp, journalSettings->start_time, journalSettings->end_time, 1, 24); for(int i = 0; i < arr.size(); ++i) { LogWidget *logWidget = new LogWidget(translate, arr[i].getTime(), arr[i].getMessage(), arr[i].getSensorId(), arr[i].getSensorGroup(), arr[i].getThreatLevel(), ui->scrollWidgetJournal); logWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); ui->scrollLayoutJournal->addWidget(logWidget); } if (arr.size() < 24) { QSpacerItem *spacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); ui->scrollLayoutJournal->addSpacerItem(spacer); } } JournalSettings* MainWindow::getJournalDataSettings() { QString time = ui->timeIntervalJournal->currentText(); qint64 start_time, end_time; QTimeZone systemTimeZone = QTimeZone::systemTimeZone(); QTimeZone spbTimeZone("Europe/Moscow"); QDateTime now = QDateTime::currentDateTime(); now.setTimeZone(systemTimeZone); now = now.toTimeZone(spbTimeZone); if (time == "За всё время") { start_time = 1; end_time = now.toSecsSinceEpoch(); } else if (time == "За сегодня") { QDateTime startOfDay = now.date().startOfDay(); start_time = startOfDay.toSecsSinceEpoch(); end_time = now.toSecsSinceEpoch(); } else if (time == "За вчера") { QDateTime startOfYesterday = now.addDays(-1).date().startOfDay(); QDateTime endOfYesterday = startOfYesterday.addDays(1).addSecs(-1); start_time = startOfYesterday.toSecsSinceEpoch(); end_time = endOfYesterday.toSecsSinceEpoch(); } else if (time == "За последние 7 дней") { QDateTime startOf7DaysAgo = now.addDays(-6).date().startOfDay(); start_time = startOf7DaysAgo.toSecsSinceEpoch(); end_time = now.toSecsSinceEpoch(); } else { start_time = 1; end_time = now.toSecsSinceEpoch(); } QString searchQuery = ui->searchJournal->text().trimmed(); searchQuery = searchQuery.toLower(); QMap> sensorsMap; for (int i = 0; i < ui->treeJournal->topLevelItemCount(); ++i) { QTreeWidgetItem *groupItem = ui->treeJournal->topLevelItem(i); QString groupName = groupItem->data(0, Qt::UserRole).toString(); QList sensorIds; for (int j = 0; j < groupItem->childCount(); ++j) { QTreeWidgetItem *sensorItem = groupItem->child(j); if (sensorItem->checkState(0) == Qt::Checked) { QString sensorId = sensorItem->data(0, Qt::UserRole).toString(); if (searchQuery.isEmpty() || sensorId.toLower().contains(searchQuery)) { sensorIds.append(sensorId); } } } if (!sensorIds.isEmpty()) { sensorsMap[groupName] = sensorIds; } } bool cmp = ui->sortJournal->currentText() == "По времени" ? 0 : 1; QList status; QString statusText = ui->statusJournal->currentText(); if (statusText == "Отладка"){ status = {0}; } else if (statusText == "Информация"){ status = {1}; } else if (statusText == "Предупреждение"){ status = {2}; } else if (statusText == "Ошибка"){ status = {3}; } else if (statusText == "Экстренно"){ status = {4}; } return new JournalSettings(sensorsMap, start_time, end_time, cmp, status); } void MainWindow::onTreeJournalChanged(QTreeWidgetItem *item, int column) { Q_UNUSED(column); } void MainWindow::onSearchJournalTextChanged(const QString &text) { Q_UNUSED(text); if (text.isEmpty()) { ui->searchJournal->setStyleSheet(R"( QLineEdit { width: 778px; height: 60px; border: 2px solid #DCD174; font-family: Inter; font-size: 26px; font-weight: 400; line-height: 31.47px; text-align: left; background: #00000000; color: #a6a6a6; } )"); } else { ui->searchJournal->setStyleSheet(R"( QLineEdit { width: 778px; height: 60px; border: 2px solid #DCD174; font-family: Inter; font-size: 26px; font-weight: 400; line-height: 31.47px; text-align: left; background: #00000000; color: #13385F; } )"); } } void MainWindow::SetupIncidentTab() { loadSensorsTree(ui->treeIncidents); connect(ui->treeIncidents, &QTreeWidget::itemChanged, this, &MainWindow::onTreeIncidentsChanged); connect(ui->searchIncedents, &QLineEdit::textChanged, this, &MainWindow::onSearchIncedentsTextChanged); ui->timeIntervalIncedents->addItems( {"За всё время", "За сегодня", "За вчера", "За последние 7 дней"}); settingsIncident = getIncidentDataSettings(); int amount = alarmsService->getAlarmsAmount(settingsIncident->groupsWithSensors, settingsIncident->start_time, settingsIncident->end_time); paginationBarIncident = new PaginationBar((amount + 24 - 1)/ 24, this); QList arr = alarmsService->getAlarms(settingsIncident->groupsWithSensors, settingsIncident->start_time, settingsIncident->end_time, 1, 24); for(int i = 0; i < arr.size(); ++i) { AlarmWidget *a = new AlarmWidget(translate, arr[i].getSensorId(), arr[i].getSensorGroup(), arr[i].getStartTime().left(10), arr[i].getStartTime().mid(11, 15), arr[i].getEndTime(), sensorService, ui->scrollWidgetIncidents); connect(a, &AlarmWidget::dialogClosedFromWidget, this, &MainWindow::ondialogClosedFromWidget); a->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); ui->scrollLayoutIncidents->addWidget(a); } if (arr.size() < 24) { QSpacerItem *spacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); ui->scrollLayoutIncidents->addSpacerItem(spacer); } ui->paginationBarIncedentsLayout->addStretch(); ui->paginationBarIncedentsLayout->addWidget(paginationBarIncident); ui->paginationBarIncedentsLayout->addStretch(); connect(ui->searchIncidents, &QPushButton::clicked, this, &MainWindow::onSearchIncidentsClicked); connect(ui->updateTreeButtonIncident, &QPushButton::clicked, this, &MainWindow::updateTreeClicked); connect(paginationBarIncident, &PaginationBar::pageChanged, this, &MainWindow::onIncidentsPageChanged); } void MainWindow::onIncidentsPageChanged(int page) { while (QLayoutItem *item = ui->scrollLayoutIncidents->takeAt(0)) { if (QWidget *widget = item->widget()) { widget->deleteLater(); } delete item; } QList arr = alarmsService->getAlarms(settingsIncident->groupsWithSensors, settingsIncident->start_time, settingsIncident->end_time, page, 24); for(int i = 0; i < arr.size(); ++i) { AlarmWidget *alarmWidget = new AlarmWidget(translate, arr[i].getSensorId(), arr[i].getSensorGroup(), arr[i].getStartTime().left(10), arr[i].getStartTime().mid(11, 15), arr[i].getEndTime(), sensorService, ui->scrollWidgetIncidents); alarmWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); ui->scrollLayoutIncidents->addWidget(alarmWidget); } if (arr.size() < 24) { QSpacerItem *spacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); ui->scrollLayoutIncidents->addSpacerItem(spacer); } } void MainWindow::onSearchIncidentsClicked() { while (QLayoutItem *item = ui->scrollLayoutIncidents->takeAt(0)) { if (QWidget *widget = item->widget()) { widget->deleteLater(); } delete item; } settingsIncident = getIncidentDataSettings(); int amount = alarmsService->getAlarmsAmount(settingsIncident->groupsWithSensors, settingsIncident->start_time, settingsIncident->end_time); paginationBarIncident->setTotalPages((amount + 24 - 1)/ 24); QList arr = alarmsService->getAlarms(settingsIncident->groupsWithSensors, settingsIncident->start_time, settingsIncident->end_time, 1, 24); for(int i = 0; i < arr.size(); ++i) { AlarmWidget *a = new AlarmWidget(translate, arr[i].getSensorId(), arr[i].getSensorGroup(), arr[i].getStartTime().left(10), arr[i].getStartTime().mid(11, 15), arr[i].getEndTime(), sensorService, ui->scrollWidgetIncidents); a->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); ui->scrollLayoutIncidents->addWidget(a); } if (arr.size() < 24) { QSpacerItem *spacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); ui->scrollLayoutIncidents->addSpacerItem(spacer); } } AlarmSettings* MainWindow::getIncidentDataSettings() { QString time = ui->timeIntervalIncedents->currentText(); qint64 start_time, end_time; QTimeZone systemTimeZone = QTimeZone::systemTimeZone(); QTimeZone spbTimeZone("Europe/Moscow"); QDateTime now = QDateTime::currentDateTime(); now.setTimeZone(systemTimeZone); now = now.toTimeZone(spbTimeZone); if (time == "За всё время") { start_time = 1; end_time = now.toSecsSinceEpoch(); } else if (time == "За сегодня") { QDateTime startOfDay = now.date().startOfDay(); start_time = startOfDay.toSecsSinceEpoch(); end_time = now.toSecsSinceEpoch(); } else if (time == "За вчера") { QDateTime startOfYesterday = now.addDays(-1).date().startOfDay(); QDateTime endOfYesterday = startOfYesterday.addDays(1).addSecs(-1); start_time = startOfYesterday.toSecsSinceEpoch(); end_time = endOfYesterday.toSecsSinceEpoch(); } else if (time == "За последние 7 дней") { QDateTime startOf7DaysAgo = now.addDays(-6).date().startOfDay(); start_time = startOf7DaysAgo.toSecsSinceEpoch(); end_time = now.toSecsSinceEpoch(); } else { start_time = 1; end_time = now.toSecsSinceEpoch(); } QString searchQuery = ui->searchIncedents->text().trimmed(); searchQuery = searchQuery.toLower(); QMap> sensorsMap; for (int i = 0; i < ui->treeIncidents->topLevelItemCount(); ++i) { QTreeWidgetItem *groupItem = ui->treeIncidents->topLevelItem(i); QString groupName = groupItem->data(0, Qt::UserRole).toString(); QList sensorIds; for (int j = 0; j < groupItem->childCount(); ++j) { QTreeWidgetItem *sensorItem = groupItem->child(j); if (sensorItem->checkState(0) == Qt::Checked) { QString sensorId = sensorItem->data(0, Qt::UserRole).toString(); if (searchQuery.isEmpty() || sensorId.toLower().contains(searchQuery)) { sensorIds.append(sensorId); } } } if (!sensorIds.isEmpty()) { sensorsMap[groupName] = sensorIds; } } return new AlarmSettings(sensorsMap, start_time, end_time); } void MainWindow::onTreeIncidentsChanged(QTreeWidgetItem *item, int column) { Q_UNUSED(column); } void MainWindow::onSearchIncedentsTextChanged(const QString &text) { Q_UNUSED(text); if (text.isEmpty()) { ui->searchIncedents->setStyleSheet(R"( QLineEdit { width: 778px; height: 60px; border: 2px solid #DCD174; font-family: Inter; font-size: 26px; font-weight: 400; line-height: 31.47px; text-align: left; background: #00000000; color: #a6a6a6; } )"); } else { ui->searchIncedents->setStyleSheet(R"( QLineEdit { width: 778px; height: 60px; border: 2px solid #DCD174; font-family: Inter; font-size: 26px; font-weight: 400; line-height: 31.47px; text-align: left; background: #00000000; color: #13385F; } )"); } } void MainWindow::loadSensorsTree(QTreeWidget *treeWidget) { if (!treeWidget) return; QTreeWidget *bufferTree = new QTreeWidget(); sensorGroupTree tree = sensorService->getSensorGroupsTree(); QStringList groups = tree.groupToLocalGroup.keys(); std::sort(groups.begin(), groups.end()); for (const QString &group : groups) { QTreeWidgetItem *groupItem = new QTreeWidgetItem(bufferTree); const QString &localizedGroupName = tree.groupToLocalGroup[group]; groupItem->setText(0, localizedGroupName); groupItem->setData(0, Qt::UserRole, group); if (tree.groupToSensorWithLocal.contains(group)) { const QMap &sensors = tree.groupToSensorWithLocal[group]; for (auto it = sensors.begin(); it != sensors.end(); ++it) { const QString &sensorId = it.key(); const QString &sensorName = it.value(); nameToId[sensorName] = sensorId; QTreeWidgetItem *sensorItem = new QTreeWidgetItem(groupItem); sensorItem->setText(0, sensorName); sensorItem->setCheckState(0, Qt::Checked); sensorItem->setData(0, Qt::UserRole, sensorId); } } } treeWidget->clear(); moveTopLevelItems(bufferTree, treeWidget); delete bufferTree; } void MainWindow::moveTopLevelItems(QTreeWidget *source, QTreeWidget *destination) { while (source->topLevelItemCount() > 0) { QTreeWidgetItem *item = source->takeTopLevelItem(0); destination->addTopLevelItem(item); } } void MainWindow::SetupSensorTab() { QScrollArea *scrollArea = new QScrollArea(this); scrollArea->setStyleSheet("QScrollArea {" " background: transparent;" " border: none;" "}" "QScrollBar:vertical {" " background: #ebebeb;" " width: 10px;" " border-radius: 5px;" "}" "QScrollBar::handle:vertical {" " background: #6d6d6d;" " border-radius: 5px;" " min-height: 20px;" "}" "QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical {" " border: none;" " background: none;" " color: none;" "}" "QScrollBar::sub-line:vertical, QScrollBar::add-line:vertical {" " background: transparent;" " border: none;" "}" "QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {" " background: transparent;" "}"); scrollArea->setWidgetResizable(true); scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); widgetContainer = new QWidget(scrollArea); widgetContainer->setStyleSheet("background: transparent;"); layout = new FlowLayout(widgetContainer, 10, 10, 10); widgetContainer->setLayout(layout); scrollArea->setWidget(widgetContainer); ui->sensorsLayout->addWidget(scrollArea); connect(ui->search, &QLineEdit::textChanged, this, &MainWindow::onSearchTextChanged); ui->showHiddenSelect->addItems({"Да", "Нет"}); connect(ui->groupSelect, QOverload::of(&QComboBox::currentIndexChanged), this, &MainWindow::onGroupSelected); connect(ui->showHiddenSelect, QOverload::of(&QComboBox::currentIndexChanged), this, &MainWindow::onShowHiddenSelected); loadSensorGroups(); } void MainWindow::updateTreeClicked() { QObject *senderObj = sender(); if (!senderObj) return; if (senderObj == ui->updateTreeButtonJournal) { ui->treeJournal->hide(); loadSensorsTree(ui->treeJournal); ui->treeJournal->show(); } else if (senderObj == ui->updateTreeButtonIncident) { ui->treeIncidents->hide(); loadSensorsTree(ui->treeIncidents); ui->treeIncidents->show(); } } //TODO: посмотреть что с таймером void MainWindow::startRefreshTimer() { QTimer *refreshTimer = new QTimer(this); connect(refreshTimer, &QTimer::timeout, this, [this]() { if (ui->tabWidget->currentWidget() == ui->sensorsTab) { updateDisplayedWidgets(); } TranslateUpdate(); }); refreshTimer->start(5000); //5 sec } void MainWindow::TranslateUpdate() { translate = sensorService->getTranslate(); } void MainWindow::showSensorDialog(SensorWidget *sensor) { SensorDialog *dialog = new SensorDialog(this, sensor, httpClient); dialog->setWindowModality(Qt::ApplicationModal); connect(dialog, &SensorDialog::resultReady, this, &MainWindow::onSensorDialogFinished); dialog->exec(); } void MainWindow::onSensorDialogFinished(int result) { switch (result) { case SensorDialog::SaveSuccess: updateDisplayedWidgets(); break; case SensorDialog::SaveError: QMessageBox::critical(nullptr, "Ошибка", "Данные не сохранены, попробуйте еще раз"); break; case SensorDialog::NoSave: updateDisplayedWidgets(); break; default: break; } } void MainWindow::loadSensorGroups() { QMap groupsMap = sensorService->getLocalizedSensorGroups(); if (groupsMap.isEmpty()) { QTimer::singleShot(5000, this, &MainWindow::loadSensorGroups); return; } ui->groupSelect->clear(); for (auto it = groupsMap.begin(); it != groupsMap.end(); ++it) { if(it.key() == "*SYSTEM") { continue; } ui->groupSelect->addItem(it.key(), it.value()); } if (!groupsMap.isEmpty()) { loadSensors(groupsMap[groupsMap.firstKey()]); } } void MainWindow::loadSensors(const QString &group) { QList sensors = sensorService->getSensors(group); const auto &existingWidgets = widgetContainer->findChildren(); for (SensorWidget *widget : existingWidgets) { delete widget; } layout->clear(); for (const Sensor &sensor : sensors) { if(sensor.id == "*NAME") { continue; } SensorWidget *s = new SensorWidget(nullptr, sensor); layout->addWidget(s); connect(s, &SensorWidget::clicked, this, &MainWindow::showSensorDialog); } widgetContainer->update(); } void MainWindow::updateDisplayedWidgets() { QString selectedGroup = ui->groupSelect->currentData().toString(); QString showHidden = ui->showHiddenSelect->currentText(); QString searchText = ui->search->text(); // Загружаем датчики только для выбранной группы QList sensors = sensorService->getSensors(selectedGroup); // Храним уже добавленные виджеты QMap existingWidgets; // Сохраняем существующие виджеты и их сенсоры для последующего обновления const auto &widgets = widgetContainer->findChildren(); for (SensorWidget *widget : widgets) { existingWidgets[widget->getSensor().id] = widget; } layout->clear(); // Очищаем layout, но не удаляем сами виджеты // Проходим по новым датчикам и добавляем их в layout, если они ещё не добавлены for (const Sensor &sensor : sensors) { SensorWidget *widget = nullptr; if(sensor.id == "*NAME") { continue; } // Проверяем, существует ли виджет для данного сенсора if (existingWidgets.contains(sensor.id)) { widget = existingWidgets[sensor.id]; widget->setSensor(sensor); // Обновляем данные существующего виджета } else { widget = new SensorWidget(nullptr, sensor); connect(widget, &SensorWidget::clicked, this, &MainWindow::showSensorDialog); } // Применяем фильтрацию по условиям bool matchesHidden = (showHidden == "Да") || !sensor.isHide; bool matchesSearch = sensor.name.contains(searchText, Qt::CaseInsensitive); if (matchesHidden && matchesSearch) { layout->addWidget(widget); widget->show(); } else { widget->hide(); } } widgetContainer->update(); // Обновляем виджеты в контейнере } void MainWindow::onGroupSelected(int index) { Q_UNUSED(index); loadSensors(ui->groupSelect->currentText()); updateDisplayedWidgets(); } void MainWindow::onShowHiddenSelected(int index) { Q_UNUSED(index); updateDisplayedWidgets(); } void MainWindow::onSearchTextChanged(const QString &text) { Q_UNUSED(text); if (text.isEmpty()) { ui->search->setStyleSheet(R"( QLineEdit { width: 778px; height: 60px; border: 2px solid #DCD174; font-family: Inter; font-size: 26px; font-weight: 400; line-height: 31.47px; text-align: left; background: #00000000; color: #a6a6a6; } )"); } else { ui->search->setStyleSheet(R"( QLineEdit { width: 778px; height: 60px; border: 2px solid #DCD174; font-family: Inter; font-size: 26px; font-weight: 400; line-height: 31.47px; text-align: left; background: #00000000; color: #13385F; } )"); } updateDisplayedWidgets(); } MainWindow::~MainWindow() { delete ui; }