533 lines
25 KiB
PHP
533 lines
25 KiB
PHP
<!DOCTYPE html>
|
|
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
|
<head>
|
|
@include('layout.header')
|
|
<style>
|
|
.content-wrapper .card {
|
|
border: 0px !important;
|
|
}
|
|
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="row" id="x" style="display: none;">
|
|
<div class="col-12">
|
|
<span class="d-flex align-items-center purchase-popup">
|
|
<i class="typcn typcn-delete-outline" id="bannerClose"></i>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<div class="container-scroller">
|
|
@include('layout.navbar')
|
|
<!-- partial -->
|
|
@include('layout.breadscrum')
|
|
<div class="container-fluid page-body-wrapper">
|
|
|
|
@include('layout.sidebar')
|
|
|
|
<!-- partial -->
|
|
<div class="main-panel">
|
|
<div class="content-wrapper">
|
|
<div class="row">
|
|
<div class="col-xl-12 mb-0 grid-margin stretch-card flex-column">
|
|
<div class="row">
|
|
|
|
<div class="col-md-3 grid-margin stretch-card">
|
|
<div class="card shadow rounded" style="border-radius: 25px" >
|
|
|
|
<div class="card-body">
|
|
<div class="dropdown pull-right">
|
|
<button class="btn bg-white p-0 pb-1 text-muted btn-sm dropdown-toggle" type="button" id="dropdownMenuSizeButton4" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
|
|
|
</button>
|
|
<div class="dropdown-menu" aria-labelledby="dropdownMenuSizeButton4">
|
|
<a class="dropdown-item" href="#" onclick="filterSample('today')">{{__('general.chart_filter_today')}}</a>
|
|
<a class="dropdown-item" href="#" onclick="filterSample('this_month')">{{__('general.chart_filter_this_month')}}</a>
|
|
<a class="dropdown-item" href="#" onclick="filterSample('this_year')">{{__('general.chart_filter_this_year')}}</a>
|
|
{{-- <a class="dropdown-item" href="#" onclick="filterSample('last_year')">{{__('general.chart_filter_last_year')}}</a> --}}
|
|
</div>
|
|
</div>
|
|
<div class="row no-gutters align-items-center">
|
|
<div class="col mr-2">
|
|
<div class="text-xs font-weight-bold text-uppercase mb-1"> {{ __('general.total_samples') }}</div>
|
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
|
<h5 class="mb- font-weight-bold text-info" id="totalSample">{{number_format($totalSample,0)}}</h5>
|
|
<div class="d-flex align-items-baseline" id="growthSampleBox">
|
|
@if($growthSample>=0)
|
|
<i class="typcn typcn-arrow-up-thick text-primary"></i>
|
|
<p class="text-primary mb-0">{{$growthSample}}%</p>
|
|
@else
|
|
<i class="typcn typcn-arrow-down-thick text-danger"></i>
|
|
<p class="text-danger mb-0">{{$growthSample}}%</p>
|
|
@endif
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
<div class="row">
|
|
<p class="font-weight-bold ml-2 text-info" id="sampleData">{{__($displaySample)}}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-3 grid-margin stretch-card">
|
|
<div class="card shadow rounded" style="border-radius: 25px" >
|
|
|
|
<div class="card-body">
|
|
<div class="dropdown pull-right">
|
|
<button class="btn bg-white p-0 pb-1 text-muted btn-sm dropdown-toggle" type="button" id="dropdownMenuSizeButton4" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
|
|
|
</button>
|
|
<div class="dropdown-menu" aria-labelledby="dropdownMenuSizeButton4">
|
|
<a class="dropdown-item" href="#" onclick="filterIncome('today')">{{__('general.chart_filter_today')}}</a>
|
|
<a class="dropdown-item" href="#" onclick="filterIncome('this_month')">{{__('general.chart_filter_this_month')}}</a>
|
|
<a class="dropdown-item" href="#" onclick="filterIncome('this_year')">{{__('general.chart_filter_this_year')}}</a>
|
|
{{-- <a class="dropdown-item" href="{{url('dashboard?filter=income&dt=last_year')}}">{{__('general.chart_filter_last_year')}}</a> --}}
|
|
</div>
|
|
</div>
|
|
<div class="row no-gutters align-items-center">
|
|
<div class="col mr-2">
|
|
<div class="text-xs font-weight-bold text-uppercase mb-1"> {{ __('general.total_income') }}</div>
|
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
|
<h5 class="mb- font-weight-bold text-info" id="totalIncome">$ {{number_format($totalIncome,2)}}</h5>
|
|
<div class="d-flex align-items-baseline" id="growthIncomeBox">
|
|
@if($growthIncome>=0)
|
|
<i class="typcn typcn-arrow-up-thick text-primary"></i>
|
|
<p class="text-primary mb-0">{{$growthIncome}}%</p>
|
|
@else
|
|
<i class="typcn typcn-arrow-down-thick text-danger"></i>
|
|
<p class="text-danger mb-0">{{$growthIncome}}%</p>
|
|
@endif
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
<div class="row">
|
|
<p class="text-info font-weight-bold ml-2" id="displayIncome">{{__($displayIncome)}}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-3 grid-margin stretch-card">
|
|
<div class="card shadow rounded" style="border-radius: 25px" >
|
|
|
|
<div class="card-body">
|
|
<div class="dropdown pull-right">
|
|
<button class="btn bg-white p-0 pb-1 text-muted btn-sm dropdown-toggle" type="button" id="dropdownMenuSizeButton4" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
|
|
|
</button>
|
|
<div class="dropdown-menu" aria-labelledby="dropdownMenuSizeButton4">
|
|
<a class="dropdown-item" href="#" onclick="filterPatient('today')">{{__('general.chart_filter_today')}}</a>
|
|
<a class="dropdown-item" href="#" onclick="filterPatient('this_month')">{{__('general.chart_filter_this_month')}}</a>
|
|
<a class="dropdown-item" href="#" onclick="filterPatient('this_year')">{{__('general.chart_filter_this_year')}}</a>
|
|
{{-- <a class="dropdown-item" href="#" onclick="filterPatient('last_year')">{{__('general.chart_filter_last_year')}}</a> --}}
|
|
</div>
|
|
</div>
|
|
<div class="row no-gutters align-items-center">
|
|
<div class="col mr-2">
|
|
<div class="text-xs font-weight-bold text-uppercase mb-1"> {{ __('general.total_patient') }}</div>
|
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
|
<h5 class="mb- font-weight-bold text-info" id="totalPatient">{{number_format($totalPatient,0)}}</h5>
|
|
<div class="d-flex align-items-baseline" id="growthPatientBox">
|
|
@if($growthPatient>=0)
|
|
<i class="typcn typcn-arrow-up-thick text-primary"></i>
|
|
<p class="text-primary mb-0">{{$growthPatient}}%</p>
|
|
@else
|
|
<i class="typcn typcn-arrow-down-thick text-danger"></i>
|
|
<p class="text-danger mb-0">{{$growthPatient}}%</p>
|
|
@endif
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
<div class="row">
|
|
<p class="text-info font-weight-bold ml-2" id="displayPatient">{{__($displayPatient)}}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-3 grid-margin stretch-card">
|
|
<div class="card shadow rounded" style="border-radius: 25px" >
|
|
|
|
<div class="card-body">
|
|
<div class="dropdown pull-right">
|
|
<button class="btn bg-white p-0 pb-1 text-muted btn-sm dropdown-toggle" type="button" id="dropdownMenuSizeButton4" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
|
|
|
</button>
|
|
<div class="dropdown-menu" aria-labelledby="dropdownMenuSizeButton4">
|
|
<a class="dropdown-item" href="#" onclick="filterRejectedSample('today')">{{__('general.chart_filter_today')}}</a>
|
|
<a class="dropdown-item" href="#" onclick="filterRejectedSample('this_month')">{{__('general.chart_filter_this_month')}}</a>
|
|
<a class="dropdown-item" href="#" onclick="filterRejectedSample('this_year')">{{__('general.chart_filter_this_year')}}</a>
|
|
{{-- <a class="dropdown-item" href="#" onclick="filterRejectedSample('last_year')">{{__('general.chart_filter_last_year')}}</a> --}}
|
|
</div>
|
|
</div>
|
|
<div class="row no-gutters align-items-center">
|
|
<div class="col mr-2">
|
|
<div class="text-xs font-weight-bold text-uppercase mb-1"> {{ __('general.total_rejected_sample') }}</div>
|
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
|
<h5 class="mb- font-weight-bold text-info" id="totalRejectedSample">{{number_format($totalRejectedSample,0)}}</h5>
|
|
<div class="d-flex align-items-baseline" id="growthRejectedSampleBox">
|
|
@if($growthRejectedSample>=0)
|
|
<i class="typcn typcn-arrow-up-thick text-primary"></i>
|
|
<p class="text-primary mb-0">{{$growthRejectedSample}}%</p>
|
|
@else
|
|
<i class="typcn typcn-arrow-down-thick text-danger"></i>
|
|
<p class="text-danger mb-0">{{$growthRejectedSample}}%</p>
|
|
@endif
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
<div class="row">
|
|
<p class="text-info font-weight-bold ml-2" id="displayRejectedSample">{{($displayRejectedSample)}}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6 col-xl-6 grid-margin stretch-card">
|
|
<div class="card bg-inverse-light shadow rounded" style="border-radius:25px">
|
|
<div class="card-body border-bottom">
|
|
<div class="d-flex justify-content-between align-items-center flex-wrap">
|
|
<h6 class="mb-2 mb-md-0 text-uppercase font-weight-medium">{{ __('general.monthly_sample_trend') }}</h6>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<canvas id="samplesCompare"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-6 col-xl-6 grid-margin stretch-card">
|
|
<div class="card bg-inverse-light shadow rounded" style="border-radius:25px">
|
|
<div class="card-body border-bottom">
|
|
<div class="d-flex justify-content-between align-items-center flex-wrap">
|
|
<h6 class="mb-2 mb-md-0 text-uppercase font-weight-medium">{{ __('general.monthly_income_trend') }}</h6>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<canvas id="revenueCompare"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6 col-xl-6 grid-margin stretch-card">
|
|
<div class="card bg-inverse-light shadow rounded" style="border-radius:25px">
|
|
<div class="card-body border-bottom">
|
|
<div class="d-flex justify-content-between align-items-center flex-wrap">
|
|
<h6 class="mb-2 mb-md-0 text-uppercase font-weight-medium">{{ __('general.sample_source_distribution') }}</h6>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<canvas id="sourceDistributor"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-6 col-xl-6 grid-margin stretch-card">
|
|
<div class="card bg-inverse-light shadow rounded" style="border-radius:25px">
|
|
<div class="card-body border-bottom">
|
|
<div class="d-flex justify-content-between align-items-center flex-wrap">
|
|
<h6 class="mb-2 mb-md-0 text-uppercase font-weight-medium">{{ __('general.panel_distribution') }}</h6>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<canvas id="topTests"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
@include('layout.footer')
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@include('layout.common_script')
|
|
|
|
<script src="{{url(env("APP_URL").'storage/assets/libs/chart.js/Chart.min.js')}}"></script>
|
|
{{-- <script src="{{url(env("APP_URL").'storage/assets/js/chart.js')}}"></script> --}}
|
|
<script>
|
|
function generateColorCodeByYear(year) {
|
|
const seed = parseInt(year.toString().slice(-2));
|
|
const red = (Math.sin(seed * 1) * 127 + 128) | 0;
|
|
const green = (Math.sin(seed * 2) * 127 + 128) | 0;
|
|
const blue = (Math.sin(seed * 3) * 127 + 128) | 0;
|
|
|
|
return `#${red.toString(16).padStart(2, '0')}${green.toString(16).padStart(2, '0')}${blue.toString(16).padStart(2, '0')}`;
|
|
}
|
|
|
|
function generateColors(count) {
|
|
const baseColors = [
|
|
'#2563eb',
|
|
'#16a34a',
|
|
'#f59e0b',
|
|
'#dc2626',
|
|
'#8b5cf6',
|
|
'#14b8a6',
|
|
'#e11d48',
|
|
'#10b981',
|
|
'#f97316',
|
|
'#3b82f6',
|
|
'#22c55e',
|
|
'#fbbf24',
|
|
'#ef4444',
|
|
'#a855f7',
|
|
'#06b6d4',
|
|
'#e53935',
|
|
];
|
|
|
|
return Array.from({ length: count }, (_, i) =>
|
|
baseColors[i % baseColors.length]
|
|
);
|
|
}
|
|
</script>
|
|
|
|
<script>
|
|
var urlSourceDistribution = "{{url('dashboard/source-distribution')}}";
|
|
fetch(urlSourceDistribution)
|
|
.then(res => res.json())
|
|
.then(data => {
|
|
const labels = data.map(d => d.sample_source);
|
|
const counts = data.map(d => d.total_samples);
|
|
|
|
const colors = generateColors(labels.length);
|
|
|
|
new Chart(document.getElementById('sourceDistributor'), {
|
|
type: 'line',
|
|
data: {
|
|
labels: labels,
|
|
datasets: [{
|
|
label: '{{__("general.total_samples")}}',
|
|
data: counts,
|
|
backgroundColor: colors
|
|
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
legend: { position: 'bottom' }
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<script>
|
|
var urlTopTests = "{{url('dashboard/panel-distribution')}}";
|
|
fetch(urlTopTests)
|
|
.then(res => res.json())
|
|
.then(data => {
|
|
const labels = data.map(d => d.panel);
|
|
const counts = data.map(d => d.total_samples);
|
|
|
|
const panelDisColors = generateColors(labels.length);
|
|
|
|
new Chart(document.getElementById('topTests'), {
|
|
type: 'doughnut',
|
|
data: {
|
|
labels: labels,
|
|
datasets: [{
|
|
label: '{{__("general.total_samples")}}',
|
|
data: counts,
|
|
backgroundColor: panelDisColors
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
legend: { position: 'bottom' },
|
|
scales: {
|
|
y: { beginAtZero: true }
|
|
}
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<script>
|
|
|
|
function renderGrowth(growthData, boxId) {
|
|
let icon = '';
|
|
let colorClass = '';
|
|
|
|
if (growthData>= 0) {
|
|
icon = '<i class="typcn typcn-arrow-up-thick text-primary"></i>';
|
|
colorClass = 'text-primary';
|
|
} else {
|
|
icon = '<i class="typcn typcn-arrow-down-thick text-danger"></i>';
|
|
colorClass = 'text-danger';
|
|
}
|
|
|
|
boxId.innerHTML = `
|
|
${icon}
|
|
<p class="${colorClass} mb-0">${growthData}%</p>
|
|
`;
|
|
}
|
|
|
|
|
|
var urlFilterSample = "{{url('dashboard/filter/samples')}}";
|
|
function filterSample(filter) {
|
|
fetch(`${urlFilterSample}?dt=${filter}`)
|
|
.then(res => res.json())
|
|
.then(data => {
|
|
renderGrowth(data.growthSample, document.getElementById('growthSampleBox'));
|
|
$('#sampleData').text(data.displaySample);
|
|
$('#totalSample').text(data.displaySampleResult);
|
|
});
|
|
}
|
|
|
|
var urlFilterIncome = "{{url('dashboard/filter/income')}}";
|
|
function filterIncome(filter) {
|
|
fetch(`${urlFilterIncome}?dt=${filter}`)
|
|
.then(res => res.json())
|
|
.then(data => {
|
|
renderGrowth(data.growthIncome, document.getElementById('growthIncomeBox'));
|
|
$('#displayIncome').text(data.displayIncome);
|
|
$('#totalIncome').text('$ ' + data.displayIncomeResult);
|
|
});
|
|
}
|
|
|
|
var urlFilterPatient = "{{url('dashboard/filter/patient')}}";
|
|
function filterPatient(filter) {
|
|
fetch(`${urlFilterPatient}?dt=${filter}`)
|
|
.then(res => res.json())
|
|
.then(data => {
|
|
renderGrowth(data.growthPatient, document.getElementById('growthPatientBox'));
|
|
$('#displayPatient').text(data.displayPatient);
|
|
$('#totalPatient').text(data.displayPatientResult);
|
|
});
|
|
}
|
|
|
|
var urlFilterRejectedSample = "{{url('dashboard/filter/rejected-sample')}}";
|
|
function filterRejectedSample(filter) {
|
|
fetch(`${urlFilterRejectedSample}?dt=${filter}`)
|
|
.then(res => res.json())
|
|
.then(data => {
|
|
renderGrowth(data.growthRejectedSample, document.getElementById('growthRejectedSampleBox'));
|
|
$('#displayRejectedSample').text(data.displayRejectedSample);
|
|
$('#totalRejectedSample').text(data.displayRejectedSampleResult);
|
|
});
|
|
}
|
|
|
|
</script>
|
|
|
|
|
|
<script>
|
|
const now = new Date();
|
|
|
|
const trend_thisYear = now.getFullYear();
|
|
const trend_lastYear = trend_thisYear - 1;
|
|
var urlTrend = "{{url('dashboard/trend/samples-comparison')}}";
|
|
fetch(urlTrend)
|
|
.then(res => res.json())
|
|
.then(data => {
|
|
|
|
const labels = data.map(d => d.month);
|
|
const thisYear = data.map(d => d.this_year);
|
|
const lastYear = data.map(d => d.last_year);
|
|
|
|
new Chart(document.getElementById('samplesCompare'), {
|
|
type: 'bar',
|
|
data: {
|
|
labels: labels,
|
|
datasets: [
|
|
{
|
|
label: trend_thisYear,
|
|
data: thisYear,
|
|
borderColor: '#ffffff', //green
|
|
backgroundColor: 'rgba(235,156,37,0.85)',
|
|
tension: 0.4,
|
|
fill: true
|
|
},
|
|
{
|
|
label: trend_lastYear,
|
|
data: lastYear,
|
|
borderColor: '#ffffff', //green
|
|
backgroundColor: 'rgba(4,100,144,0.96)',
|
|
tension: 0.4,
|
|
fill: true
|
|
}
|
|
]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
legend: { position: 'bottom' },
|
|
scales: {
|
|
y: { beginAtZero: true }
|
|
}
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
</script>
|
|
|
|
<script>
|
|
var urlRevenueTrend = "{{url('dashboard/trend/revenue-comparison')}}";
|
|
fetch(urlRevenueTrend)
|
|
.then(res => res.json())
|
|
.then(data => {
|
|
|
|
const labels = data.map(d => d.month);
|
|
const thisYear = data.map(d => d.this_year);
|
|
const lastYear = data.map(d => d.last_year);
|
|
|
|
new Chart(document.getElementById('revenueCompare'), {
|
|
type: 'line',
|
|
data: {
|
|
labels: labels,
|
|
datasets: [
|
|
{
|
|
label: trend_thisYear,
|
|
data: thisYear,
|
|
borderColor: '#2563eb', // blue
|
|
backgroundColor: 'rgba(37, 99, 235, 0.1)',
|
|
tension: 0.4,
|
|
fill: true
|
|
},
|
|
{
|
|
label: trend_lastYear,
|
|
data: lastYear,
|
|
borderColor: '#10b981', //green
|
|
backgroundColor: 'rgba(16, 185, 129, 0.1)',
|
|
tension: 0.4,
|
|
fill: true
|
|
}
|
|
]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
legend: { position: 'bottom' },
|
|
scales: {
|
|
y: { beginAtZero: true }
|
|
}
|
|
}
|
|
});
|
|
|
|
});
|
|
</script>
|
|
|
|
|
|
</body>
|
|
|
|
</html>
|
|
|