Adds employee revenue and utilization chart
Updates package dependencies and charts for employee performance visualization Includes: - Upgrade to latest charting library version - New chart displaying revenue and utilization metrics - Forecast and actual data visualization with dual axis support
This commit is contained in:
parent
85b006e0d6
commit
6c3662f571
4 changed files with 156 additions and 5 deletions
8
package-lock.json
generated
8
package-lock.json
generated
|
|
@ -10,7 +10,7 @@
|
|||
"dependencies": {
|
||||
"@novadi/core": "^0.6.0",
|
||||
"@rollup/rollup-win32-x64-msvc": "^4.52.2",
|
||||
"@sevenweirdpeople/swp-charting": "^0.1.7",
|
||||
"@sevenweirdpeople/swp-charting": "^0.2.1",
|
||||
"dayjs": "^1.11.19",
|
||||
"fuse.js": "^7.1.0",
|
||||
"json-diff-ts": "^4.8.2",
|
||||
|
|
@ -1175,9 +1175,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@sevenweirdpeople/swp-charting": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@sevenweirdpeople/swp-charting/-/swp-charting-0.1.7.tgz",
|
||||
"integrity": "sha512-i3HEQMQmltmxykPGXCRcN8VMJZXD1sI8urb7rN8eTjB9EscDsACdkS+WyvxOEEEhyHj1hMdtULeX3BIZ1ZNrng==",
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@sevenweirdpeople/swp-charting/-/swp-charting-0.2.1.tgz",
|
||||
"integrity": "sha512-QtY77Dyv4Vs/rWfBVSDTmuxgD4L8tGu4pmTF0l3i8HDwK6qtT2wEtH35UHD1RDFE1VtOGcnU0/dTdqjNWCqzxA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/chai": {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@
|
|||
"dependencies": {
|
||||
"@novadi/core": "^0.6.0",
|
||||
"@rollup/rollup-win32-x64-msvc": "^4.52.2",
|
||||
"@sevenweirdpeople/swp-charting": "^0.1.7",
|
||||
"@sevenweirdpeople/swp-charting": "^0.2.1",
|
||||
"dayjs": "^1.11.19",
|
||||
"fuse.js": "^7.1.0",
|
||||
"json-diff-ts": "^4.8.2",
|
||||
|
|
|
|||
67
wwwroot/data/employee-revenue-utilization.json
Normal file
67
wwwroot/data/employee-revenue-utilization.json
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
{
|
||||
"categories": ["Uge 40", "Uge 41", "Uge 42", "Uge 43", "Uge 44", "Uge 45", "Uge 46", "Uge 47", "Uge 48", "Uge 49", "Uge 50", "Uge 51", "Uge 52", "Uge 1", "Uge 2", "Uge 3", "Uge 4", "Uge 5", "Uge 6", "Uge 7", "Uge 8", "Uge 9", "Uge 10", "Uge 11", "Uge 12"],
|
||||
"nowCategory": "Uge 52",
|
||||
"forecastStartCategory": "Uge 1",
|
||||
"actual": {
|
||||
"revenue": [
|
||||
{ "x": "Uge 40", "y": 38500 },
|
||||
{ "x": "Uge 41", "y": 42000 },
|
||||
{ "x": "Uge 42", "y": 35200 },
|
||||
{ "x": "Uge 43", "y": 44800 },
|
||||
{ "x": "Uge 44", "y": 41500 },
|
||||
{ "x": "Uge 45", "y": 39200 },
|
||||
{ "x": "Uge 46", "y": 46100 },
|
||||
{ "x": "Uge 47", "y": 43800 },
|
||||
{ "x": "Uge 48", "y": 40500 },
|
||||
{ "x": "Uge 49", "y": 45200 },
|
||||
{ "x": "Uge 50", "y": 42800 },
|
||||
{ "x": "Uge 51", "y": 44500 },
|
||||
{ "x": "Uge 52", "y": 28450 }
|
||||
],
|
||||
"utilization": [
|
||||
{ "x": "Uge 40", "y": 82 },
|
||||
{ "x": "Uge 41", "y": 88 },
|
||||
{ "x": "Uge 42", "y": 75 },
|
||||
{ "x": "Uge 43", "y": 91 },
|
||||
{ "x": "Uge 44", "y": 85 },
|
||||
{ "x": "Uge 45", "y": 80 },
|
||||
{ "x": "Uge 46", "y": 94 },
|
||||
{ "x": "Uge 47", "y": 89 },
|
||||
{ "x": "Uge 48", "y": 83 },
|
||||
{ "x": "Uge 49", "y": 92 },
|
||||
{ "x": "Uge 50", "y": 87 },
|
||||
{ "x": "Uge 51", "y": 90 },
|
||||
{ "x": "Uge 52", "y": 84 }
|
||||
]
|
||||
},
|
||||
"forecast": {
|
||||
"revenue": [
|
||||
{ "x": "Uge 1", "y": 0 },
|
||||
{ "x": "Uge 2", "y": 32500 },
|
||||
{ "x": "Uge 3", "y": 28800 },
|
||||
{ "x": "Uge 4", "y": 22400 },
|
||||
{ "x": "Uge 5", "y": 15200 },
|
||||
{ "x": "Uge 6", "y": 9800 },
|
||||
{ "x": "Uge 7", "y": 6500 },
|
||||
{ "x": "Uge 8", "y": 4200 },
|
||||
{ "x": "Uge 9", "y": 2800 },
|
||||
{ "x": "Uge 10", "y": 1500 },
|
||||
{ "x": "Uge 11", "y": 800 },
|
||||
{ "x": "Uge 12", "y": 0 }
|
||||
],
|
||||
"utilization": [
|
||||
{ "x": "Uge 1", "y": 0 },
|
||||
{ "x": "Uge 2", "y": 74 },
|
||||
{ "x": "Uge 3", "y": 58 },
|
||||
{ "x": "Uge 4", "y": 39 },
|
||||
{ "x": "Uge 5", "y": 21 },
|
||||
{ "x": "Uge 6", "y": 11 },
|
||||
{ "x": "Uge 7", "y": 8 },
|
||||
{ "x": "Uge 8", "y": 5 },
|
||||
{ "x": "Uge 9", "y": 3 },
|
||||
{ "x": "Uge 10", "y": 2 },
|
||||
{ "x": "Uge 11", "y": 1 },
|
||||
{ "x": "Uge 12", "y": 0 }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -1895,6 +1895,13 @@
|
|||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
swp-chart-subtitle {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
color: var(--color-text-muted);
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
swp-chart-legend {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
|
|
@ -2658,6 +2665,17 @@
|
|||
</swp-stat-card>
|
||||
</div>
|
||||
|
||||
<!-- Omsætning & Belægningsgrad chart -->
|
||||
<swp-card style="margin-bottom: 24px;">
|
||||
<swp-chart-section>
|
||||
<swp-chart-header>
|
||||
<swp-chart-title>Omsætning & Belægningsgrad</swp-chart-title>
|
||||
<swp-chart-subtitle>3 måneder bagud · 3 måneder frem</swp-chart-subtitle>
|
||||
</swp-chart-header>
|
||||
<swp-chart-container id="revenueUtilizationChart" style="height: 300px;"></swp-chart-container>
|
||||
</swp-chart-section>
|
||||
</swp-card>
|
||||
|
||||
<div class="grid-2">
|
||||
<swp-card>
|
||||
<swp-chart-section>
|
||||
|
|
@ -3489,6 +3507,72 @@
|
|||
height: 200,
|
||||
legend: false
|
||||
});
|
||||
|
||||
// Revenue & Utilization chart - dual axis (3 mdr bagud + 3 mdr frem)
|
||||
fetch('data/employee-revenue-utilization.json')
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
createChart(document.getElementById('revenueUtilizationChart'), {
|
||||
xAxis: { categories: data.categories },
|
||||
yAxis: [
|
||||
{ min: 0, max: 50000, format: v => `${(v/1000).toFixed(0)}k` }, // Left: Revenue
|
||||
{ min: 0, max: 100, format: v => `${v}%` }, // Right: Utilization
|
||||
],
|
||||
series: [
|
||||
// Actual revenue (solid bars)
|
||||
{
|
||||
name: 'Omsætning',
|
||||
color: '#3b82f6',
|
||||
type: 'bar',
|
||||
yAxisIndex: 0,
|
||||
unit: 'kr',
|
||||
data: data.actual.revenue,
|
||||
bar: { radius: 2 },
|
||||
},
|
||||
// Forecast revenue (transparent bars)
|
||||
{
|
||||
name: 'Omsætning (forecast)',
|
||||
color: '#3b82f6',
|
||||
type: 'bar',
|
||||
yAxisIndex: 0,
|
||||
unit: 'kr',
|
||||
data: data.forecast.revenue,
|
||||
bar: { radius: 2, opacity: 0.35 },
|
||||
},
|
||||
// Actual utilization (solid line)
|
||||
{
|
||||
name: 'Belægning',
|
||||
color: '#00897b',
|
||||
type: 'line',
|
||||
yAxisIndex: 1,
|
||||
unit: '%',
|
||||
data: data.actual.utilization,
|
||||
line: { width: 2.5 },
|
||||
point: { radius: 0 },
|
||||
showArea: false,
|
||||
},
|
||||
// Forecast utilization (dashed line)
|
||||
{
|
||||
name: 'Belægning (forecast)',
|
||||
color: '#00897b',
|
||||
type: 'line',
|
||||
yAxisIndex: 1,
|
||||
unit: '%',
|
||||
data: data.forecast.utilization,
|
||||
line: { width: 2.5, dashArray: '4 4' },
|
||||
point: { radius: 0 },
|
||||
showArea: false,
|
||||
},
|
||||
],
|
||||
annotations: [
|
||||
{ type: 'region', x: data.forecastStartCategory, x2: data.categories[data.categories.length - 1], backgroundColor: 'rgba(0,0,0,0.03)' },
|
||||
{ type: 'verticalLine', x: data.nowCategory, dashArray: '4 4', label: 'Nu', labelPosition: 'top' },
|
||||
],
|
||||
legend: { position: 'top', align: 'end' },
|
||||
padding: { right: 60 },
|
||||
height: 280,
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue