Dashboard update
add monthly Sales Graph add Monthly Registered Customers Graph add Active Users Graph
This commit is contained in:
parent
771bc9d8d9
commit
cbe2602b69
@ -90,7 +90,7 @@ foreach ($tmp as $plan) {
|
|||||||
$used = ORM::for_table('tbl_voucher')
|
$used = ORM::for_table('tbl_voucher')
|
||||||
->where('id_plan', $plan['id'])
|
->where('id_plan', $plan['id'])
|
||||||
->where('status', 1)->count();
|
->where('status', 1)->count();
|
||||||
if($unused>0 || $used>0){
|
if ($unused > 0 || $used > 0) {
|
||||||
$plans[$n]['name_plan'] = $plan['name_plan'];
|
$plans[$n]['name_plan'] = $plan['name_plan'];
|
||||||
$plans[$n]['unused'] = $unused;
|
$plans[$n]['unused'] = $unused;
|
||||||
$plans[$n]['used'] = $used;
|
$plans[$n]['used'] = $used;
|
||||||
@ -100,6 +100,68 @@ foreach ($tmp as $plan) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Monthly Registered Customers
|
||||||
|
$result = ORM::for_table('tbl_customers')
|
||||||
|
->select_expr('MONTH(created_at)', 'month')
|
||||||
|
->select_expr('COUNT(*)', 'count')
|
||||||
|
->where_raw('YEAR(created_at) = YEAR(NOW())')
|
||||||
|
->group_by_expr('MONTH(created_at)')
|
||||||
|
->find_many();
|
||||||
|
|
||||||
|
$counts = [];
|
||||||
|
foreach ($result as $row) {
|
||||||
|
$counts[] = [
|
||||||
|
'date' => $row->month,
|
||||||
|
'count' => $row->count
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query to retrieve monthly data
|
||||||
|
$query = ORM::for_table('tbl_transactions')
|
||||||
|
->select_expr('MONTH(recharged_on)', 'month')
|
||||||
|
->select_expr('SUM(price)', 'total')
|
||||||
|
->where_raw("YEAR(recharged_on) = YEAR(CURRENT_DATE())") // Filter by the current year
|
||||||
|
->group_by_expr('MONTH(recharged_on)')
|
||||||
|
->find_many();
|
||||||
|
|
||||||
|
// Execute the query and retrieve the monthly sales data
|
||||||
|
$results = $query->find_many();
|
||||||
|
|
||||||
|
// Create an array to hold the monthly sales data
|
||||||
|
$monthlySales = array();
|
||||||
|
|
||||||
|
// Iterate over the results and populate the array
|
||||||
|
foreach ($results as $result) {
|
||||||
|
$month = $result->month;
|
||||||
|
$totalSales = $result->total;
|
||||||
|
|
||||||
|
$monthlySales[$month] = array(
|
||||||
|
'month' => $month,
|
||||||
|
'totalSales' => $totalSales
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill in missing months with zero sales
|
||||||
|
for ($month = 1; $month <= 12; $month++) {
|
||||||
|
if (!isset($monthlySales[$month])) {
|
||||||
|
$monthlySales[$month] = array(
|
||||||
|
'month' => $month,
|
||||||
|
'totalSales' => 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort the array by month
|
||||||
|
ksort($monthlySales);
|
||||||
|
|
||||||
|
// Reindex the array
|
||||||
|
$monthlySales = array_values($monthlySales);
|
||||||
|
|
||||||
|
// Assign the monthly sales data to Smarty
|
||||||
|
$ui->assign('monthlySales', $monthlySales);
|
||||||
|
$ui->assign('xheader', '<script src="https://cdn.jsdelivr.net/npm/apexcharts@3.28.0/dist/apexcharts.min.js"></script>');
|
||||||
|
$ui->assign('xfooter', '');
|
||||||
|
$ui->assign('counts', $counts);
|
||||||
$ui->assign('stocks', $stocks);
|
$ui->assign('stocks', $stocks);
|
||||||
$ui->assign('plans', $plans);
|
$ui->assign('plans', $plans);
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{include file="sections/header.tpl"}
|
{include file="sections/header.tpl"}
|
||||||
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-3 col-xs-6">
|
<div class="col-lg-3 col-xs-6">
|
||||||
<div class="small-box bg-aqua">
|
<div class="small-box bg-aqua">
|
||||||
@ -59,38 +60,73 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- solid sales graph -->
|
||||||
|
<div class="box box-solid ">
|
||||||
|
<div class="box-header">
|
||||||
|
<i class="fa fa-th"></i>
|
||||||
|
|
||||||
|
<h3 class="box-title">{Lang::T('Monthly Registered Customers')}</h3>
|
||||||
|
|
||||||
|
<div class="box-tools pull-right">
|
||||||
|
<button type="button" class="btn bg-teal btn-sm" data-widget="collapse"><i class="fa fa-minus"></i>
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn bg-teal btn-sm" data-widget="remove"><i class="fa fa-times"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="box-body border-radius-none">
|
||||||
|
<canvas class="chart" id="chart" style="height: 250px;"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- solid sales graph -->
|
||||||
|
<div class="box box-solid ">
|
||||||
|
<div class="box-header">
|
||||||
|
<i class="fa fa-inbox"></i>
|
||||||
|
|
||||||
|
<h3 class="box-title">{Lang::T('Total Monthly Sales')}</h3>
|
||||||
|
|
||||||
|
<div class="box-tools pull-right">
|
||||||
|
<button type="button" class="btn bg-teal btn-sm" data-widget="collapse"><i class="fa fa-minus"></i>
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn bg-teal btn-sm" data-widget="remove"><i class="fa fa-times"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="box-body border-radius-none">
|
||||||
|
<canvas class="chart" id="salesChart" style="height: 250px;"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-7">
|
<div class="col-md-7">
|
||||||
{if $_c['disable_voucher'] != 'yes' && $stocks['unused']>0 || $stocks['used']>0}
|
{if $_c['disable_voucher'] != 'yes' && $stocks['unused']>0 || $stocks['used']>0}
|
||||||
<div class="panel panel-primary mb20 panel-hovered project-stats table-responsive">
|
<div class="panel panel-primary mb20 panel-hovered project-stats table-responsive">
|
||||||
<div class="panel-heading">Vouchers Stock</div>
|
<div class="panel-heading">Vouchers Stock</div>
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
|
||||||
<th>{$_L['Plan_Name']}</th>
|
|
||||||
<th>unused</th>
|
|
||||||
<th>used</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{foreach $plans as $stok}
|
|
||||||
<tr>
|
|
||||||
<td>{$stok['name_plan']}</td>
|
|
||||||
<td>{$stok['unused']}</td>
|
|
||||||
<td>{$stok['used']}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
{/foreach}
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>Total</td>
|
<th>{$_L['Plan_Name']}</th>
|
||||||
<td>{$stocks['unused']}</td>
|
<th>unused</th>
|
||||||
<td>{$stocks['used']}</td>
|
<th>used</th>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</thead>
|
||||||
</div>
|
<tbody>
|
||||||
|
{foreach $plans as $stok}
|
||||||
|
<tr>
|
||||||
|
<td>{$stok['name_plan']}</td>
|
||||||
|
<td>{$stok['unused']}</td>
|
||||||
|
<td>{$stok['used']}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
{/foreach}
|
||||||
|
<tr>
|
||||||
|
<td>Total</td>
|
||||||
|
<td>{$stocks['unused']}</td>
|
||||||
|
<td>{$stocks['used']}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="panel panel-warning mb20 panel-hovered project-stats table-responsive">
|
<div class="panel panel-warning mb20 panel-hovered project-stats table-responsive">
|
||||||
<div class="panel-heading">{$_L['User_Expired_Today']}</div>
|
<div class="panel-heading">{$_L['User_Expired_Today']}</div>
|
||||||
@ -107,15 +143,15 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{$no = 1}
|
{$no = 1}
|
||||||
{foreach $expire as $expired}
|
{foreach $expire as $expired}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{$no++}</td>
|
<td>{$no++}</td>
|
||||||
<td><a href="{$_url}customers/viewu/{$expired['username']}">{$expired['username']}</a></td>
|
<td><a href="{$_url}customers/viewu/{$expired['username']}">{$expired['username']}</a></td>
|
||||||
<td>{Lang::dateAndTimeFormat($expired['recharged_on'],$expired['recharged_time'])}
|
<td>{Lang::dateAndTimeFormat($expired['recharged_on'],$expired['recharged_time'])}
|
||||||
</td>
|
</td>
|
||||||
<td>{Lang::dateAndTimeFormat($expired['expiration'],$expired['time'])}
|
<td>{Lang::dateAndTimeFormat($expired['expiration'],$expired['time'])}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
{/foreach}
|
{/foreach}
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@ -123,38 +159,201 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="col-md-5">
|
<div class="col-md-5">
|
||||||
<div class="panel panel-success panel-hovered mb20 activities">
|
<div class="panel panel-success panel-hovered mb20 activities">
|
||||||
<div class="panel-heading">{Lang::T('Payment Gateway')}: {$_c['payment_gateway']}</div>
|
<div class="panel-heading">{Lang::T('Payment Gateway')}: {$_c['payment_gateway']}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="panel panel-info panel-hovered mb20 activities">
|
||||||
|
<div class="panel-heading">{Lang::T('Active Users')}</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<canvas id="userRechargesChart"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="panel panel-info panel-hovered mb20 activities">
|
<div class="panel panel-info panel-hovered mb20 activities">
|
||||||
<div class="panel-heading"><a href="{$_url}logs">{$_L['Activity_Log']}</a></div>
|
<div class="panel-heading"><a href="{$_url}logs">{$_L['Activity_Log']}</a></div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled">
|
||||||
{foreach $dlog as $dlogs}
|
{foreach $dlog as $dlogs}
|
||||||
<li class="primary">
|
<li class="primary">
|
||||||
<span class="point"></span>
|
<span class="point"></span>
|
||||||
<span class="time small text-muted">{time_elapsed_string($dlogs['date'],true)}</span>
|
<span class="time small text-muted">{time_elapsed_string($dlogs['date'],true)}</span>
|
||||||
<p>{$dlogs['description']}</p>
|
<p>{$dlogs['description']}</p>
|
||||||
</li>
|
</li>
|
||||||
{/foreach}
|
{/foreach}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.5.1/dist/chart.min.js"></script>
|
||||||
|
{literal}
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
var counts = JSON.parse('{/literal}{$counts|json_encode}{literal}');
|
||||||
|
|
||||||
|
var monthNames = [
|
||||||
|
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
|
||||||
|
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
|
||||||
|
];
|
||||||
|
|
||||||
|
var labels = [];
|
||||||
|
var data = [];
|
||||||
|
|
||||||
|
for (var i = 1; i <= 12; i++) {
|
||||||
|
var month = counts.find(count => count.date === i);
|
||||||
|
labels.push(month ? monthNames[i - 1] : monthNames[i - 1].substring(0, 3));
|
||||||
|
data.push(month ? month.count : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
var ctx = document.getElementById('chart').getContext('2d');
|
||||||
|
var chart = new Chart(ctx, {
|
||||||
|
type: 'bar',
|
||||||
|
data: {
|
||||||
|
labels: labels,
|
||||||
|
datasets: [{
|
||||||
|
label: 'Registered Members',
|
||||||
|
data: data,
|
||||||
|
backgroundColor: 'rgba(0, 0, 255, 0.5)',
|
||||||
|
borderColor: 'rgba(0, 0, 255, 0.7)',
|
||||||
|
borderWidth: 1
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
grid: {
|
||||||
|
display: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
beginAtZero: true,
|
||||||
|
grid: {
|
||||||
|
color: 'rgba(0, 0, 0, 0.1)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
var monthlySales = JSON.parse('{/literal}{$monthlySales|json_encode}{literal}');
|
||||||
|
|
||||||
|
var monthNames = [
|
||||||
|
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
|
||||||
|
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
|
||||||
|
];
|
||||||
|
|
||||||
|
var labels = [];
|
||||||
|
var data = [];
|
||||||
|
|
||||||
|
for (var i = 1; i <= 12; i++) {
|
||||||
|
var month = findMonthData(monthlySales, i);
|
||||||
|
labels.push(month ? monthNames[i - 1] : monthNames[i - 1].substring(0, 3));
|
||||||
|
data.push(month ? month.totalSales : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
var ctx = document.getElementById('salesChart').getContext('2d');
|
||||||
|
var chart = new Chart(ctx, {
|
||||||
|
type: 'bar',
|
||||||
|
data: {
|
||||||
|
labels: labels,
|
||||||
|
datasets: [{
|
||||||
|
label: 'Monthly Sales',
|
||||||
|
data: data,
|
||||||
|
backgroundColor: 'rgba(2, 10, 242)', // Customize the background color
|
||||||
|
borderColor: 'rgba(255, 99, 132, 1)', // Customize the border color
|
||||||
|
borderWidth: 1
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
grid: {
|
||||||
|
display: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
beginAtZero: true,
|
||||||
|
grid: {
|
||||||
|
color: 'rgba(0, 0, 0, 0.1)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function findMonthData(monthlySales, month) {
|
||||||
|
for (var i = 0; i < monthlySales.length; i++) {
|
||||||
|
if (monthlySales[i].month === month) {
|
||||||
|
return monthlySales[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
// Get the data from PHP and assign it to JavaScript variables
|
||||||
|
var u_act = '{/literal}{$u_act}{literal}';
|
||||||
|
var u_all = '{/literal}{$u_all}{literal}';
|
||||||
|
|
||||||
|
// Create the chart data
|
||||||
|
var data = {
|
||||||
|
labels: ['Active Users', 'Inactive Users'],
|
||||||
|
datasets: [{
|
||||||
|
label: 'User Recharges',
|
||||||
|
data: [parseInt(u_act), parseInt(u_all)],
|
||||||
|
backgroundColor: ['rgba(4, 191, 13)', 'rgba(191, 35, 4)'],
|
||||||
|
borderColor: ['rgba(0, 255, 0, 1)', 'rgba(255, 99, 132, 1)'],
|
||||||
|
borderWidth: 1
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create chart options
|
||||||
|
var options = {
|
||||||
|
responsive: true,
|
||||||
|
aspectRatio: 1,
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
position: 'bottom',
|
||||||
|
labels: {
|
||||||
|
boxWidth: 15
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get the canvas element and create the chart
|
||||||
|
var ctx = document.getElementById('userRechargesChart').getContext('2d');
|
||||||
|
var chart = new Chart(ctx, {
|
||||||
|
type: 'pie',
|
||||||
|
data: data,
|
||||||
|
options: options
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{/literal}
|
||||||
<script>
|
<script>
|
||||||
window.addEventListener('DOMContentLoaded', function() {
|
window.addEventListener('DOMContentLoaded', function () {
|
||||||
$.getJSON("./version.json?" + Math.random(), function(data) {
|
$.getJSON("./version.json?" + Math.random(), function (data) {
|
||||||
var localVersion = data.version;
|
var localVersion = data.version;
|
||||||
$('#version').html('Version: ' + localVersion);
|
$('#version').html('Version: ' + localVersion);
|
||||||
$.getJSON(
|
$.getJSON(
|
||||||
"https://raw.githubusercontent.com/hotspotbilling/phpnuxbill/master/version.json?" +
|
"https://raw.githubusercontent.com/hotspotbilling/phpnuxbill/master/version.json?" +
|
||||||
Math
|
Math
|
||||||
.random(),
|
.random(),
|
||||||
function(data) {
|
function (data) {
|
||||||
var latestVersion = data.version;
|
var latestVersion = data.version;
|
||||||
if (localVersion !== latestVersion) {
|
if (localVersion !== latestVersion) {
|
||||||
$('#version').html('Latest Version: ' + latestVersion);
|
$('#version').html('Latest Version: ' + latestVersion);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user