mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-16 20:22:15 +01:00
Updated PDF footer and added pie chart to aggregate report
This commit is contained in:
committed by
Constantin Graf
parent
05da595470
commit
620c4c97dc
@@ -234,6 +234,7 @@ class TimeEntryController extends Controller
|
|||||||
$request = Gotenberg::chromium(config('services.gotenberg.url'))
|
$request = Gotenberg::chromium(config('services.gotenberg.url'))
|
||||||
->pdf()
|
->pdf()
|
||||||
->pdfa('PDF/A-3b')
|
->pdfa('PDF/A-3b')
|
||||||
|
->margins(0.39, 0.78, 0.39, 0.39)
|
||||||
->paperSize('8.27', '11.7') // A4
|
->paperSize('8.27', '11.7') // A4
|
||||||
->footer(Stream::string('footer', $footerHtml))
|
->footer(Stream::string('footer', $footerHtml))
|
||||||
->html(Stream::string('body', $html));
|
->html(Stream::string('body', $html));
|
||||||
@@ -411,6 +412,7 @@ class TimeEntryController extends Controller
|
|||||||
->pdf()
|
->pdf()
|
||||||
->waitForExpression("window.status === 'ready'")
|
->waitForExpression("window.status === 'ready'")
|
||||||
->pdfa('PDF/A-3b')
|
->pdfa('PDF/A-3b')
|
||||||
|
->margins(0.39, 0.78, 0.39, 0.39)
|
||||||
->paperSize('8.27', '11.7') // A4
|
->paperSize('8.27', '11.7') // A4
|
||||||
->footer(Stream::string('footer', $footerHtml))
|
->footer(Stream::string('footer', $footerHtml))
|
||||||
->assets(Stream::path(resource_path('pdf-js/echarts.min.js'), 'echarts.min.js'))
|
->assets(Stream::path(resource_path('pdf-js/echarts.min.js'), 'echarts.min.js'))
|
||||||
|
|||||||
@@ -1,17 +1,20 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<style>
|
<style>
|
||||||
body {
|
.page-number {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
margin-top: 40px;
|
margin-left: 46px;
|
||||||
margin-left: 47px;
|
margin-bottom: 40px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<p>
|
<div class="page-number">
|
||||||
Page <span class="pageNumber"></span> of <span class="totalPages"></span>
|
Page <span class="pageNumber"></span> of <span class="totalPages"></span>
|
||||||
</p>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
@use('PhpOffice\PhpSpreadsheet\Cell\DataType')
|
@use('PhpOffice\PhpSpreadsheet\Cell\DataType')
|
||||||
@use('Carbon\CarbonInterval')
|
@use('Carbon\CarbonInterval')
|
||||||
@inject('interval', 'App\Service\IntervalService')
|
@inject('interval', 'App\Service\IntervalService')
|
||||||
<!DOCTYPE html>
|
@inject('colorService', 'App\Service\ColorService')
|
||||||
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
@@ -36,6 +37,13 @@
|
|||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.data-table {
|
||||||
|
break-after: auto;
|
||||||
|
}
|
||||||
|
.no-break {
|
||||||
|
break-after: avoid-page;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
window.status = 'processing';
|
window.status = 'processing';
|
||||||
@@ -43,6 +51,7 @@
|
|||||||
<script src="echarts.min.js"></script>
|
<script src="echarts.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<h1>Report</h1>
|
<h1>Report</h1>
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
@@ -56,10 +65,13 @@
|
|||||||
<span>Total cost: {{ Money::of(BigDecimal::ofUnscaledValue($aggregatedData['cost'], 2)->__toString(), $currency)->formatTo('en_US') }}</span><br>
|
<span>Total cost: {{ Money::of(BigDecimal::ofUnscaledValue($aggregatedData['cost'], 2)->__toString(), $currency)->formatTo('en_US') }}</span><br>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="main-chart" style="width: 100%; height:400px; margin-bottom: 50px;"></div>
|
<div id="main-chart" style="width: 100%; height:400px;"></div>
|
||||||
|
|
||||||
|
<div id="pie-chart" style="width: 100%; height: 150px; margin-bottom: 50px;"></div>
|
||||||
|
|
||||||
@foreach($aggregatedData['grouped_data'] as $group1Entry)
|
@foreach($aggregatedData['grouped_data'] as $group1Entry)
|
||||||
<h2>{{ $group1Entry['description'] ?? $group1Entry['key'] ?? 'No '.Str::lower($group->description()) }}</h2>
|
<div class="data-table">
|
||||||
|
<h2 class="no-break">{{ $group1Entry['description'] ?? $group1Entry['key'] ?? 'No '.Str::lower($group->description()) }}</h2>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
@@ -109,30 +121,85 @@
|
|||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Initialize the echarts instance based on the prepared dom
|
let elementPieChart = document.getElementById('pie-chart');
|
||||||
let element = document.getElementById('main-chart');
|
let pieChart = echarts.init(elementPieChart, null, {
|
||||||
let myChart = echarts.init(element, null, {
|
|
||||||
renderer: 'svg'
|
renderer: 'svg'
|
||||||
});
|
});
|
||||||
|
let pieChartOptions = {
|
||||||
|
legend: {
|
||||||
|
left: '25%',
|
||||||
|
align: 'left',
|
||||||
|
top: 'middle',
|
||||||
|
orient: 'vertical',
|
||||||
|
},
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
label: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
data: {!! json_encode(collect($aggregatedData['grouped_data'])->map(function (array $data) use (&$colorService, $group): object {
|
||||||
|
$color = $data['color'];
|
||||||
|
if ($color === null) {
|
||||||
|
$color = $colorService->getRandomColor();
|
||||||
|
}
|
||||||
|
if ($data['key'] === null) {
|
||||||
|
$color = '#CCCCCC';
|
||||||
|
}
|
||||||
|
return (object)[
|
||||||
|
'value' => $data['seconds'],
|
||||||
|
'name' => $data['description'] ?? $data['key'] ?? 'No '.Str::lower($group->description()),
|
||||||
|
'color' => $color,
|
||||||
|
'itemStyle' => (object) [
|
||||||
|
'color' => $color.'BB',
|
||||||
|
],
|
||||||
|
'emphasis' => (object) [
|
||||||
|
'itemStyle' => (object) [
|
||||||
|
'color' => $color,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
})->toArray()) !!},
|
||||||
|
center: ['10%', '50%'],
|
||||||
|
radius: ['30%', '60%'],
|
||||||
|
left: 'left',
|
||||||
|
type: 'pie',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
pieChart.on('finished', () => {
|
||||||
|
window.pieChartFinished = true;
|
||||||
|
if (window.mainChartFinished && window.pieChartFinished) {
|
||||||
|
window.status = 'ready';
|
||||||
|
}
|
||||||
|
})
|
||||||
|
pieChart.setOption(pieChartOptions);
|
||||||
|
|
||||||
// Specify the configuration items and data for the chart
|
let elementMainChart = document.getElementById('main-chart');
|
||||||
let option = {
|
let mainChart = echarts.init(elementMainChart, null, {
|
||||||
|
renderer: 'svg'
|
||||||
|
});
|
||||||
|
let mainChartOptions = {
|
||||||
tooltip: {},
|
tooltip: {},
|
||||||
xAxis: {
|
xAxis: {
|
||||||
data: ['{!! collect($dataHistoryChart['grouped_data'])->pluck('key')->implode("', '") !!}'],
|
data: ['{!! collect($dataHistoryChart['grouped_data'])->pluck('key')->implode("', '") !!}'],
|
||||||
axisLabel: {
|
axisLabel: {
|
||||||
show: true,
|
fontSize: 12,
|
||||||
|
fontWeight: 600,
|
||||||
|
color: 'rgb(120, 120, 120)',
|
||||||
|
margin: 16,
|
||||||
|
fontFamily: 'Outfit, sans-serif',
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
interval: 0,
|
interval: 0,
|
||||||
rotate: 90,
|
alignWithLabel: true,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
bottom: 0,
|
|
||||||
containLabel: true
|
containLabel: true
|
||||||
},
|
},
|
||||||
yAxis: {
|
yAxis: {
|
||||||
@@ -164,6 +231,9 @@
|
|||||||
name: 'time',
|
name: 'time',
|
||||||
type: 'bar',
|
type: 'bar',
|
||||||
data: [{!! collect($dataHistoryChart['grouped_data'])->pluck('seconds')->implode(', ') !!}],
|
data: [{!! collect($dataHistoryChart['grouped_data'])->pluck('seconds')->implode(', ') !!}],
|
||||||
|
itemStyle: {
|
||||||
|
borderColor: '#5470c6',
|
||||||
|
},
|
||||||
label: {
|
label: {
|
||||||
show: true,
|
show: true,
|
||||||
position: 'top',
|
position: 'top',
|
||||||
@@ -192,13 +262,13 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
mainChart.on('finished', () => {
|
||||||
myChart.on('finished', () => {
|
window.mainChartFinished = true;
|
||||||
|
if (window.mainChartFinished && window.pieChartFinished) {
|
||||||
window.status = 'ready';
|
window.status = 'ready';
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
mainChart.setOption(mainChartOptions);
|
||||||
// Display the chart using the configuration items and data just specified.
|
|
||||||
myChart.setOption(option);
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,17 +1,20 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<style>
|
<style>
|
||||||
body {
|
.page-number {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
margin-top: 40px;
|
margin-left: 46px;
|
||||||
margin-left: 47px;
|
margin-bottom: 40px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<p>
|
<div class="page-number">
|
||||||
Page <span class="pageNumber"></span> of <span class="totalPages"></span>
|
Page <span class="pageNumber"></span> of <span class="totalPages"></span>
|
||||||
</p>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user