From 6122040752b5c5fa30733deb8d42d6c1451eb3aa Mon Sep 17 00:00:00 2001 From: Vladislav Ostapov Date: Fri, 31 Jan 2025 13:41:43 +0300 Subject: [PATCH 1/3] =?UTF-8?q?=D0=BF=D0=BE=D0=BF=D1=8B=D1=82=D0=BA=D0=B0?= =?UTF-8?q?=20=D0=BD=D0=B0=D1=80=D0=B8=D1=81=D0=BE=D0=B2=D0=B0=D1=82=D1=8C?= =?UTF-8?q?=20=D0=B3=D1=80=D0=B0=D1=84=D0=B8=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.cpp | 9 +++++ static/dev.html | 54 ++++++++++++++++++----------- static/js/chart.js | 20 +++++++++++ static/js/chartjs-adapter-moment.js | 7 ++++ static/js/moment.js | 15 ++++++++ 5 files changed, 85 insertions(+), 20 deletions(-) create mode 100644 static/js/chart.js create mode 100644 static/js/chartjs-adapter-moment.js create mode 100644 static/js/moment.js diff --git a/src/main.cpp b/src/main.cpp index 4078bc2..5694aee 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -95,6 +95,9 @@ public: // картинки, их даже можно кешировать static constexpr const char* FAVICON_ICO = "/favicon.ico"; static constexpr const char* VUE_JS = "/js/vue.js"; // это тоже можно кешировать + static constexpr const char* CHARTJS = "/js/chart.js"; + static constexpr const char* MOMENT_JS = "/js/moment.js"; + static constexpr const char* CHARTJS_ADAPTER_MOMENT = "/js/chartjs-adapter-moment.js"; // а эти стили нельзя кешировать в отладочной версии static constexpr const char* STYLE_CSS = "/style.css"; @@ -117,6 +120,9 @@ public: auth.users.emplace_back(std::make_shared("developer", "10628cfc434fb87f31d675d37e0402c2d824cfe8393aff7a61ee57aaa7d909c3", http::auth::User::SUPERUSER)); sf->registerFile(staticFilesPath + "/favicon.png", FAVICON_ICO, mime_types::image_png, true); + sf->registerFile(staticFilesPath + CHARTJS, CHARTJS, mime_types::javascript, true); + sf->registerFile(staticFilesPath + MOMENT_JS, MOMENT_JS, mime_types::javascript, true); + sf->registerFile(staticFilesPath + CHARTJS_ADAPTER_MOMENT, CHARTJS_ADAPTER_MOMENT, mime_types::javascript, true); #ifdef USE_DEBUG sf->registerFile(staticFilesPath + VUE_JS, VUE_JS, mime_types::javascript, true); #else @@ -185,6 +191,9 @@ public: s.resources.emplace_back(std::make_unique(STYLE_CSS, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(STYLE_CSS, rep); })); s.resources.emplace_back(std::make_unique(FIELDS_CSS, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(FIELDS_CSS, rep); })); s.resources.emplace_back(std::make_unique(VUE_JS, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(VUE_JS, rep); })); + s.resources.emplace_back(std::make_unique(CHARTJS, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(CHARTJS, rep); })); + s.resources.emplace_back(std::make_unique(MOMENT_JS, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(MOMENT_JS, rep); })); + s.resources.emplace_back(std::make_unique(CHARTJS_ADAPTER_MOMENT, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(CHARTJS_ADAPTER_MOMENT, rep); })); s.resources.emplace_back(std::make_unique(INTERNET_JPG, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(INTERNET_JPG, rep); })); s.resources.emplace_back(std::make_unique("/api/get/statistics", this->auth, http::auth::User::WATCH_STATISTICS, [this](const auto& req, auto& rep) { diff --git a/static/dev.html b/static/dev.html index cfa3ab9..c5cd2cb 100644 --- a/static/dev.html +++ b/static/dev.html @@ -94,22 +94,14 @@

Просмотр логов

Скачать -
- - - - - - - - - -
{{ h }}
{{ value }}
-
+
+ + + @@ -181,11 +183,27 @@ let logfileContent = await resp.text() const lines = logfileContent.trim().split(/\r\n|\n/) + let datasets = [] + // столбец timestamp пропускаем - this.chart.data.labels = lines.shift().split('\t').shift() + let labels = lines.shift().split('\t') + labels.shift() + let rows = lines.map(line => line.split('\t')) - - // this.chartDataset.rows = lines.map(line => line.split('\t')) + for (let li = 0; li < labels.length; li++) { + let td = [] + for (let ri = 0; ri < rows.length; ri++) { + td.push({x: new Date(rows[ri][0]), y: rows[ri][li + 1]}) + } + datasets.push({ + label: labels[li], + data: td, + //borderColor: 'blue', + borderWidth: 2, + fill: false, + }) + } + this.chart.datasets = datasets this.chart.update() }) .catch((reason) => { alert(`Ошибка при чтении логов: ${reason}`) }) @@ -205,31 +223,39 @@ this.updateLoggingStatisticsSettings(vals) } doFetchSettings().then(() => {}) - let chart = new Chart( - document.getElementById("mainChart"), - { - type: 'line', - datasets: [ - { - label: 'Net sales', - data: [ - {x: new Date('2021-11-06 23:39:30'), y: 50}, - {x: new Date('2021-11-07 01:00:28'), y: 60}, - {x: new Date('2021-11-07 09:00:28'), y: 20} - ] - } - ], - options: { - scales: { - x: { - type: 'time', - } + let chart = new Chart(document.getElementById('mainChart').getContext('2d'), { + type: 'line', + data: { + datasets: [] + }, + options: { + responsive: true, + scales: { + x: { + type: 'time', + title: { + display: true, + text: 'Время', + font: { + padding: 4, + size: 20, + weight: 'bold', + family: 'Arial' + }, + //color: 'darkblue' + }, + }, + y: { + beginAtZero: true, + type: 'linear', + position: 'left' } } } - ) + }) this.chart = chart document.getElementById("app").removeAttribute("hidden") + //this.chart = chart } }); app.mount('#app') From 1eaedeef0fd837d24f5ba4779436889c063f5900 Mon Sep 17 00:00:00 2001 From: Vladislav Ostapov Date: Tue, 8 Apr 2025 17:37:20 +0300 Subject: [PATCH 3/3] =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=87=D0=B8=D0=B5?= =?UTF-8?q?=20=D0=B3=D1=80=D0=B0=D1=84=D0=B8=D0=BA=D0=B8=20=D0=BD=D0=B0=20?= =?UTF-8?q?=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=86=D0=B5=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20=D1=80=D0=B0=D0=B7=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=87?= =?UTF-8?q?=D0=B8=D0=BA=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/dev.html | 66 ++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/static/dev.html b/static/dev.html index 4f24b11..4f8bcc9 100644 --- a/static/dev.html +++ b/static/dev.html @@ -109,6 +109,37 @@ function updateHeaderHeight() { const header = document.querySelector('header'); document.body.style.setProperty('--header-height', `${header.offsetHeight}px`); } window.addEventListener('load', updateHeaderHeight); window.addEventListener('resize', updateHeaderHeight); + let MainChart = new Chart(document.getElementById('mainChart').getContext('2d'), { + type: 'line', + data: { + datasets: [] + }, + options: { + responsive: true, + scales: { + x: { + type: 'time', + title: { + display: true, + text: 'Время', + font: { + padding: 4, + size: 20, + weight: 'bold', + family: 'Arial' + }, + //color: 'darkblue' + }, + }, + y: { + beginAtZero: true, + type: 'linear', + position: 'left' + } + } + } + }) + const app = Vue.createApp({ data() { return { @@ -203,8 +234,8 @@ fill: false, }) } - this.chart.datasets = datasets - this.chart.update() + MainChart.datasets = datasets + MainChart.update() }) .catch((reason) => { alert(`Ошибка при чтении логов: ${reason}`) }) .finally(() => { this.submitStatus.logView = false }) @@ -223,37 +254,6 @@ this.updateLoggingStatisticsSettings(vals) } doFetchSettings().then(() => {}) - let chart = new Chart(document.getElementById('mainChart').getContext('2d'), { - type: 'line', - data: { - datasets: [] - }, - options: { - responsive: true, - scales: { - x: { - type: 'time', - title: { - display: true, - text: 'Время', - font: { - padding: 4, - size: 20, - weight: 'bold', - family: 'Arial' - }, - //color: 'darkblue' - }, - }, - y: { - beginAtZero: true, - type: 'linear', - position: 'left' - } - } - } - }) - this.chart = chart document.getElementById("app").removeAttribute("hidden") //this.chart = chart }