From e8be3166ac57f7627b4d5523259daf7ddca2926c Mon Sep 17 00:00:00 2001 From: int2001 Date: Tue, 30 Dec 2025 11:22:37 +0000 Subject: [PATCH] Add Monthly stats --- application/controllers/Statistics.php | 22 +++++ application/models/Logbook_model.php | 35 +++++++ application/views/statistics/index.php | 26 +++++ assets/js/sections/statistics.js | 126 +++++++++++++++++++++++++ 4 files changed, 209 insertions(+) diff --git a/application/controllers/Statistics.php b/application/controllers/Statistics.php index 5e4fcc118..562afe48c 100644 --- a/application/controllers/Statistics.php +++ b/application/controllers/Statistics.php @@ -65,6 +65,28 @@ class Statistics extends CI_Controller { echo json_encode($yearstats); } + public function get_year_month() { + $this->load->model('logbook_model'); + + $yr = xss_clean($this->input->post('yr')) ?? 'All'; + + // get data + $totals_month = $this->logbook_model->totals_year_month($yr); + + $monthstats = array(); + + $i = 0; + if ($totals_month) { + foreach($totals_month->result() as $qso_numbers) { + $monthstats[$i]['month'] = intval($qso_numbers->month); + $monthstats[$i++]['total'] = $qso_numbers->total; + } + } + + header('Content-Type: application/json'); + echo json_encode($monthstats); + } + public function get_mode() { $this->load->model('logbook_model'); $yr = xss_clean($this->input->post('yr')) ?? 'All'; diff --git a/application/models/Logbook_model.php b/application/models/Logbook_model.php index a32c47ab7..032b6bee6 100644 --- a/application/models/Logbook_model.php +++ b/application/models/Logbook_model.php @@ -3462,6 +3462,41 @@ class Logbook_model extends CI_Model { return $query; } + function totals_year_month($year = null) { + + $this->load->model('logbooks_model'); + $logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook')); + + if (!$logbooks_locations_array) { + return null; + } + + $location_list = implode(',', array_fill(0, count($logbooks_locations_array), '?')); + $params = $logbooks_locations_array; + + if ($year === null || $year === 'All') { + // Aggregate across all years + $sql = "SELECT DATE_FORMAT(COL_TIME_ON, '%m') AS month, COUNT(COL_PRIMARY_KEY) AS total + FROM " . $this->config->item('table_name') . " + WHERE station_id IN ($location_list) + GROUP BY DATE_FORMAT(COL_TIME_ON, '%m') + ORDER BY month ASC"; + } else { + // Filter by specific year + $sql = "SELECT DATE_FORMAT(COL_TIME_ON, '%m') AS month, COUNT(COL_PRIMARY_KEY) AS total + FROM " . $this->config->item('table_name') . " + WHERE station_id IN ($location_list) + AND DATE_FORMAT(COL_TIME_ON, '%Y') = ? + GROUP BY DATE_FORMAT(COL_TIME_ON, '%m') + ORDER BY month ASC"; + $params[] = $year; + } + + $query = $this->db->query($sql, $params); + + return $query; + } + /* Return total number of qsos */ function total_qsos($StationLocationsArray = null, $api_key = null) { if ($StationLocationsArray == null) { diff --git a/application/views/statistics/index.php b/application/views/statistics/index.php index 958e7b51d..3aa0a8747 100644 --- a/application/views/statistics/index.php +++ b/application/views/statistics/index.php @@ -12,16 +12,35 @@
@@ -60,6 +79,9 @@ + @@ -81,6 +103,10 @@
+
+
+
+
diff --git a/assets/js/sections/statistics.js b/assets/js/sections/statistics.js index 954bc9eb7..824f62735 100644 --- a/assets/js/sections/statistics.js +++ b/assets/js/sections/statistics.js @@ -28,6 +28,12 @@ $("a[href='#yearstab']").on('shown.bs.tab', function(e) { $("#yr").hide(); }); +$("a[href='#monthstab']").on('shown.bs.tab', function(e) { + activeTab='totalQsosPerMonth()'; + totalQsosPerMonth(); + $("#yr").show(); +}); + $("a[href='#bandtab']").on('shown.bs.tab', function(e) { totalBandQsos(); activeTab='totalBandQsos()' @@ -268,6 +274,126 @@ function totalQsosPerYear() { }); } +function totalQsosPerMonth() { + // using this to change color of legend and label according to background color + var color = ifDarkModeThemeReturn('white', 'grey'); + + $.ajax({ + url: base_url+'index.php/statistics/get_year_month', + type: 'post', + data: { yr: $("#yr option:selected").val() }, + success: function (data) { + if (data.length > 0) { + $(".months").html(''); + $(".months").append('

' + lang_statistics_months + '

'); + $("#monthContainer").append(""); + + // appending table to hold the data + $("#monthTable").append('' + + '' + + '' + + '' + + '' + + '' + + '' + + '
#' + lang_statistics_month +'' + lang_statistics_number_of_qso_worked + '
'); + + var labels = []; + var dataQso = []; + + var $myTable = $('.monthtable'); + var i = 1; + + // building the rows in the table + var rowElements = data.map(function (row) { + var $row = $(''); + + // Convert month number to string with leading zero + var monthKey = row.month.toString().padStart(2, '0'); + var monthName = monthNames[monthKey] || monthKey; + + var $iterator = $('').html(i++); + var $type = $('').html(monthName); + var $content = $('').html(row.total); + + $row.append($iterator, $type, $content); + + return $row; + }); + + // finally inserting the rows + $myTable.append(rowElements); + + $.each(data, function () { + var monthKey = this.month.toString().padStart(2, '0'); + var monthName = monthNames[monthKey] || monthKey; + labels.push(monthName); + dataQso.push(this.total); + }); + + var ctx = document.getElementById("monthChart").getContext('2d'); + var myChart = new Chart(ctx, { + type: 'bar', + data: { + labels: labels, + datasets: [{ + label: decodeHtml(lang_statistics_number_of_qso_worked_each_month), + data: dataQso, + backgroundColor: 'rgba(54, 162, 235, 0.2)', + borderColor: 'rgba(54, 162, 235, 1)', + borderWidth: 2, + color: color + }] + }, + options: { + scales: { + y: { + ticks: { + beginAtZero: true, + color: color + } + }, + x: { + ticks: { + color: color + } + } + }, + plugins: { + legend: { + labels: { + color: color + } + } + + } + } + }); + $('.monthtable').DataTable({ + responsive: false, + ordering: false, + "scrollY": "320px", + "scrollCollapse": true, + "paging": false, + "scrollX": true, + "language": { + url: getDataTablesLanguageUrl(), + }, + bFilter: false, + bInfo: false + }); + + // using this to change color of csv-button if dark mode is chosen + var background = $('body').css("background-color"); + + if (background != ('rgb(255, 255, 255)')) { + $(".buttons-csv").css("color", "white"); + } + } + } + }); +} + function totalModeQsos() { // using this to change color of legend and label according to background color var color = ifDarkModeThemeReturn('white', 'grey');