Moving away from Azure Devops #1
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