Compare commits

...

5 Commits

Author SHA1 Message Date
c0aac3e49c working on chart 2025-03-16 14:39:08 +01:00
182443530a add insert data 2025-03-13 20:53:40 +01:00
d62741e139 add leading 0 of every entry 2025-03-13 19:32:10 +01:00
8426bd1ae8 add parseWorkHours 2025-03-12 23:33:58 +01:00
b18296f8a8 clean up from comments 2025-03-12 19:45:33 +01:00
8 changed files with 424 additions and 131 deletions

View File

@@ -7,7 +7,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Odoo Hours</title>
<!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
</head>
<body>

44
app/package-lock.json generated
View File

@@ -9,8 +9,10 @@
"version": "0.0.0",
"dependencies": {
"bootstrap": "^5.3.3",
"chart.js": "^4.4.8",
"pinia": "^3.0.1",
"vue": "^3.5.13",
"vue-chartjs": "^5.3.2",
"vue-router": "^4.5.0"
},
"devDependencies": {
@@ -298,14 +300,14 @@
}
},
"node_modules/@babel/helpers": {
"version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.9.tgz",
"integrity": "sha512-Mz/4+y8udxBKdmzt/UjPACs4G3j5SshJJEFFKxlCGPydG4JAHXxjWjAwjd09tf6oINvl1VfMJo+nB7H2YKQ0dA==",
"version": "7.26.10",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.10.tgz",
"integrity": "sha512-UPYc3SauzZ3JGgj87GgZ89JVdC5dj0AoetR5Bw6wj4niittNyFh6+eOGonYvJ1ao6B8lEa3Q3klS7ADZ53bc5g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/template": "^7.26.9",
"@babel/types": "^7.26.9"
"@babel/types": "^7.26.10"
},
"engines": {
"node": ">=6.9.0"
@@ -476,9 +478,9 @@
}
},
"node_modules/@babel/types": {
"version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.9.tgz",
"integrity": "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==",
"version": "7.26.10",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.10.tgz",
"integrity": "sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==",
"license": "MIT",
"dependencies": {
"@babel/helper-string-parser": "^7.25.9",
@@ -965,6 +967,12 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@kurkle/color": {
"version": "0.3.4",
"resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz",
"integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==",
"license": "MIT"
},
"node_modules/@polka/url": {
"version": "1.0.0-next.28",
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz",
@@ -1631,6 +1639,18 @@
],
"license": "CC-BY-4.0"
},
"node_modules/chart.js": {
"version": "4.4.8",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.8.tgz",
"integrity": "sha512-IkGZlVpXP+83QpMm4uxEiGqSI7jFizwVtF3+n5Pc3k7sMO+tkd0qxh2OzLhenM0K80xtmAONWGBn082EiBQSDA==",
"license": "MIT",
"dependencies": {
"@kurkle/color": "^0.3.0"
},
"engines": {
"pnpm": ">=8"
}
},
"node_modules/convert-source-map": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
@@ -2759,6 +2779,16 @@
}
}
},
"node_modules/vue-chartjs": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/vue-chartjs/-/vue-chartjs-5.3.2.tgz",
"integrity": "sha512-NrkbRRoYshbXbWqJkTN6InoDVwVb90C0R7eAVgMWcB9dPikbruaOoTFjFYHE/+tNPdIe6qdLCDjfjPHQ0fw4jw==",
"license": "MIT",
"peerDependencies": {
"chart.js": "^4.1.1",
"vue": "^3.0.0-0 || ^2.7.0"
}
},
"node_modules/vue-router": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.5.0.tgz",

View File

@@ -10,8 +10,10 @@
},
"dependencies": {
"bootstrap": "^5.3.3",
"chart.js": "^4.4.8",
"pinia": "^3.0.1",
"vue": "^3.5.13",
"vue-chartjs": "^5.3.2",
"vue-router": "^4.5.0"
},
"devDependencies": {

View File

@@ -0,0 +1,89 @@
<template>
<div class="chart-container">
<Bar :data="chartData" :options="chartOptions" :plugins="[chartOptions.plugins.customLabels]" />
</div>
</template>
<script setup>
import { Bar } from 'vue-chartjs'
import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale } from 'chart.js'
// Rejestracja wymaganych komponentów Chart.js
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale)
// Dane wykresu z dwiema seriami, które będą układane jedna nad drugą
const chartData = {
labels: ['Styczeń', 'Luty', 'Marzec', 'Kwiecień', 'Maj', 'Czerwiec', 'Lipiec'],
datasets: [
{
label: 'Sprzedaż Online',
data: [30, 40, 50, 60, 70],
backgroundColor: 'rgba(54, 162, 235, 0.7)',
stack: 'stack1',
// borderWidth: 5,
// borderRadius: 15,
// borderSkipped: false,
// borderColor: 'rgba(64, 148, 204, 0.7)',
},
{
label: 'Sprzedaż Stacjonarna',
data: [20, 30, 40, 50, -50],
backgroundColor: 'rgba(255, 99, 132, 0.7)',
stack: 'stack1',
// borderWidth: 5,
// borderRadius: 15,
// borderSkipped: false,
// borderColor: 'rgba(64, 148, 204, 0.7)',
}
]
}
// Konfiguracja wykresu włączenie stacking
const chartOptions = {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { position: 'top' },
tooltip: { enabled: true },
// Własny plugin do wyświetlania sumy wartości nad słupkami
customLabels: {
id: 'customLabels',
afterDatasetsDraw(chart) {
const { ctx, data, scales: { x, y } } = chart
ctx.save()
ctx.font = 'bold 12px Arial'
ctx.fillStyle = 'black'
ctx.textAlign = 'center'
data.labels.forEach((label, index) => {
const total = data.datasets.reduce((sum, dataset) => sum + dataset.data[index], 0) // Oblicza sumę wartości dla danej kategorii
const barX = x.getPixelForValue(index)
const barY = y.getPixelForValue(total) - 10 // Umieszcza tekst nad słupkiem
ctx.fillText(total, barX, barY)
})
ctx.restore()
}
}
},
scales: {
x: {
stacked: true,
grid: { display: false }
},
y: {
stacked: true,
// grid: { display: false }
}
}
}
</script>
<style scoped>
.chart-container {
width: 100%;
height: 200px;
/* Ustawienie wysokości */
}
</style>

View File

@@ -38,26 +38,26 @@ const props = defineProps({
const emit = defineEmits(["update:hour", "update:minute"]);
const interval = ref(null);
const timeout = ref(null);
// Tymczasowe zmienne na input
const tempHour = ref(props.hour);
const tempMinute = ref(props.minute);
// Nasłuchiwanie zmian propsów, aby synchronizować z ref
const tempHour = ref(String(props.hour).padStart(2, "0"));
const tempMinute = ref(String(props.minute).padStart(2, "0"));
watch(() => props.hour, (newVal) => {
tempHour.value = newVal;
tempHour.value = String(newVal).padStart(2, "0");
console.log("watch")
});
watch(() => props.minute, (newVal) => {
tempMinute.value = newVal;
tempMinute.value = String(newVal).padStart(2, "0");
});
// Funkcje walidacyjne
const validateHour = () => {
const hour = Number(tempHour.value);
if (!isNaN(hour) && hour >= 6 && hour <= 18) {
emit("update:hour", hour);
} else {
tempHour.value = props.hour; // Przywróć poprzednią wartość
tempHour.value = props.hour;
}
@@ -65,40 +65,34 @@ const validateHour = () => {
const validateMinute = () => {
const minute = Number(tempMinute.value);
if (!isNaN(minute) && minute >= 0 && minute <= 59) {
if (!isNaN(minute) && minute >= 0 && minute < 60) {
emit("update:minute", minute);
} else {
tempMinute.value = props.minute; // Przywróć poprzednią wartość
tempMinute.value = props.minute;
}
};
const incrementValue = (type) => {
if (type == "hour") {
let newHour = tempHour.value + 1;
let newHour = props.hour + 1;
if (newHour >= 6 && newHour <= 18) {
// tempHour.value = newHour;
emit("update:hour", newHour);
}
// validateHour();
} else if (type === "minute") {
let newMinute = tempMinute.value + 1;
if (newMinute >= 0 && newMinute <= 59) {
emit("update:minute", newMinute);
}
let newMinute = (props.minute + 1) % 60;
emit("update:minute", newMinute);
}
}
const decrementValue = (type) => {
if (type == "hour") {
let newHour = tempHour.value - 1;
let newHour = props.hour - 1;
if (newHour >= 6 && newHour <= 18) {
emit("update:hour", newHour);
}
} else if (type === "minute") {
let newMinute = tempMinute.value - 1;
if (newMinute >= 0 && newMinute <= 59) {
emit("update:minute", newMinute);
}
let newMinute = (props.minute + 59) % 60;
emit("update:minute", newMinute);
}
}
const onIncrementClick = (type) => {
@@ -107,7 +101,7 @@ const onIncrementClick = (type) => {
interval.value = setInterval(() => {
incrementValue(type);
}, 100);
}, 1000);
}, 500);
}
const onDecrementClick = (type) => {
@@ -116,7 +110,7 @@ const onDecrementClick = (type) => {
interval.value = setInterval(() => {
decrementValue(type);
}, 100);
}, 1000);
}, 500);
}
@@ -129,10 +123,6 @@ const stopInterval = () => {
</script>
<style scoped>
button {
width: 2.5rem;
}
.visibility-hidden {
visibility: hidden;
}

View File

@@ -48,6 +48,7 @@ export const useWorkHoursStore = defineStore('workHours', () => {
watch(
() => workHours.value.map((entry, index) => ({
index,
date: entry.date,
enterHour: entry.enterHour,
enterMinute: entry.enterMinute,
leaveHour: entry.leaveHour,
@@ -55,10 +56,15 @@ export const useWorkHoursStore = defineStore('workHours', () => {
})),
(newVal, oldVal) => {
newVal.forEach((newEntry, index) => {
const oldEntry = oldVal[index];
const oldEntry = oldVal?.[index];
if (!oldEntry) {
calculateWorkTime(workHours.value[index]);
}
// Sprawdzamy, czy cokolwiek się zmieniło
if (
else if (
newEntry.date !== oldEntry.date ||
newEntry.enterHour !== oldEntry.enterHour ||
newEntry.enterMinute !== oldEntry.enterMinute ||
newEntry.leaveHour !== oldEntry.leaveHour ||
@@ -81,19 +87,71 @@ export const useWorkHoursStore = defineStore('workHours', () => {
};
const getWeekday = (index) => {
const dayNames = ['NIE', 'PON', 'WTO', 'śRO', 'CZW', 'PIĄ', 'SOB'];
const dayNames = ['NIE', 'PON', 'WTO', 'ŚRO', 'CZW', 'PIĄ', 'SOB'];
const weekday = workHours.value[index].date.getDay();
return [weekday, dayNames[weekday]];
}
};
const clear = () => {
workHours.value = [];
}
};
const parseWorkHours = (userInput) => {
const lines = userInput.split('\n').map(line => line.trim()).filter(line => line);
const result = [];
// przykładowa linia userInput: Marcin Nowak 21.02.2025 07:06:59 21.02.2025 15:58:04 08:51
// const timeRegex = /(\d{2}\.\d{2}\.\d{4})\s(\d{2}):(\d{2}):\d{2}\s\d{2}\.\d{2}\.\d{4}\s(\d{2}):(\d{2}):\d{2}\s(\d{2}):(\d{2})/;
const timeRegex = /(\d{2})\.(\d{2})\.(\d{4})\s(\d{2}):(\d{2}):\d{2}\s\d{2}\.\d{2}\.\d{4}\s(\d{2}):(\d{2}):\d{2}\s(\d{2}):(\d{2})/;
for (const line of lines) {
const match = line.match(timeRegex);
if (match) {
const [_, day, month, year, enterHour, enterMinute, leaveHour, leaveMinute, workHours, workMinutes] = match;
const workDate = new Date(year, month - 1, day);
result.push({
date: workDate,
enterHour: parseInt(enterHour),
enterMinute: parseInt(enterMinute),
leaveHour: parseInt(leaveHour),
leaveMinute: parseInt(leaveMinute),
workHours: null,
workMinutes: null,
});
}
}
result.sort((a, b) => a.date - b.date);
workHours.value = result;
};
const addWorkDay = (date) => {
const newEntry = {
date: date,
enterHour: 7,
enterMinute: 0,
leaveHour: 15,
leaveMinute: 15,
workHours: null,
workMinutes: null
};
const index = workHours.value.findIndex((entry) => entry.date > newEntry.date);
if (index === -1) {
workHours.value.push(newEntry);
} else {
workHours.value.splice(index, 0, newEntry);
}
};
return {
workHours,
getDate,
getWeekday,
clear
clear,
parseWorkHours,
addWorkDay,
}
})

View File

@@ -1,14 +1,15 @@
<template>
<div class="container text-center">
<div class="row align-items-center">
<!-- Przyciski -->
<!-- buttons -->
<div class="col-3"></div>
<div class="col d-flex justify-content-center align-items-center">
<button type="button" class="btn btn-outline-primary mx-2" style="width: 150px;" data-bs-toggle="modal"
data-bs-target="#inputModal">WCZYTAJ</button>
<button type="button" class="btn btn-outline-primary mx-2" style="width: 150px;" data-bs-toggle="modal"
data-bs-target="#clearAllModal">USUŃ</button>
<button type="button" class="btn btn-outline-primary mx-2" style="width: 150px;">DODAJ</button>
<button type="button" class="btn btn-outline-primary mx-2" style="width: 150px;" data-bs-toggle="modal"
data-bs-target="#addModal">DODAJ</button>
</div>
<!-- Toggle -->
@@ -19,22 +20,6 @@
</div>
</div>
</div>
<!-- <div class="d-flex flex-row justify-content-center align-items-center">
Przyciski
<div class="d-flex">
<button type="button" class="btn btn-outline-primary mx-2" style="width: 150px;" data-bs-toggle="modal"
data-bs-target="#inputModal">WCZYTAJ</button>
<button type="button" class="btn btn-outline-primary mx-2" style="width: 150px;" data-bs-toggle="modal"
data-bs-target="#clearAllModal">USUŃ</button>
<button type="button" class="btn btn-outline-primary mx-2" style="width: 150px;">DODAJ</button>
</div>
Toggle
<div class="form-check form-switch ms-5">
<input class="form-check-input" type="checkbox" id="toggleSwitch">
<label class="form-check-label" for="toggleSwitch">Toggle</label>
</div>
</div> -->
</div>
<div class="container-fluid ">
<div class="text-center">
@@ -59,46 +44,16 @@
{{ storeWorkHours.getWeekday(index)[1] }}</span>
</td>
<td class="align-middle">
<!-- <div class="d-flex align-items-center justify-content-center">
Godziny dla Enter
<input class="form-control text-center" style="width: 4rem;" type="text"
v-model="day.enterHour" @focus="saveOldValue(day, 'enterHour')"
@blur="validate(day, 'enterHour', 6, 18, $event)">
<span class="mx-1">:</span>
Minuty dla Enter
<input class="form-control text-center" style="width: 4rem;" type="text"
v-model="day.enterMinute" @focus="saveOldValue(day, 'enterMinute')"
@blur="validate(day, 'enterMinute', 0, 59, $event)">
</div> -->
<TimeInputComponent v-model:hour="day.enterHour" v-model:minute="day.enterMinute"
:showButtons="showButtons" />
</td>
<td class="align-middle">
<!-- <div class="d-flex align-items-center justify-content-center">
Godziny dla Leave
<input class="form-control text-center" style="width: 4rem;" type="text"
v-model="day.leaveHour" @focus="saveOldValue(day, 'leaveHour')"
@blur="validate(day, 'leaveHour', 6, 18, $event)">
<span class="mx-1">:</span>
Minuty dla Leave
<input class="form-control text-center" style="width: 4rem;" type="text"
v-model="day.leaveMinute" @focus="saveOldValue(day, 'leaveMinute')"
@blur="validate(day, 'leaveMinute', 0, 59, $event)">
</div> -->
<TimeInputComponent v-model:hour="day.leaveHour" v-model:minute="day.leaveMinute"
:showButtons="showButtons" />
</td>
<td class="align-middle">
<div class="d-flex align-items-center justify-content-center">
<!-- Godziny dla Hours -->
<!-- <input class="form-control text-center" style="width: 4rem;" type="text"
v-model="day.workHours" @focus="saveOldValue(day, 'workHours')"
@blur="validate(day, 'workHours', 6, 18, $event)"> -->
<span class="mx-1 fs-5">{{ formattedWorkTime(day) }}</span>
<!-- Minuty dla Hours -->
<!-- <input class="form-control text-center" style="width: 4rem;" type="text"
v-model="day.workMinutes" @focus="saveOldValue(day, 'workMinutes')"
@blur="validate(day, 'workMinutes', 0, 59, $event)"> -->
</div>
</td>
</tr>
@@ -154,50 +109,63 @@
</div>
</div>
<!-- modal add entry -->
<div class="modal fade" id="addModal" tabindex="-1" aria-labelledby="addModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="addModalLabel">Dodaj dzień roboczy</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<label for="inputDate" class="form-label">wybierz date:</label>
<input type="date" id="inputDate" class="form-control" placeholder="dd-mm-yyyy" v-model="newDate">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Zamknij</button>
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" :disabled="!newDate"
@click="insertWorkDay">Dodaj dzień</button>
</div>
</div>
</div>
</div>
</template>
<script setup>
import TimeInputComponent from "@/components/TimeInputComponent.vue";
import { useWorkHoursStore } from "../stores/counter.js";
import { Modal } from 'bootstrap';
import { useWorkHoursStore } from "../stores/WorkHoursStore.js";
import { computed, watch, ref, onMounted } from "vue";
const rawText = ref("");
const storeWorkHours = useWorkHoursStore();
// const oldValue = ref(0);
const showButtons = ref(false);
const newDate = ref(null);
onMounted(() => {
const modalElement = document.getElementById('inputModal');
const inputModal = document.getElementById('inputModal');
const addModal = document.getElementById('addModal');
if (modalElement) {
modalElement.addEventListener('hidden.bs.modal', () => {
console.log('Modal został zamknięty kliknięciem poza oknem lub przez kliknięcie przycisku zamykania.');
// Tutaj możesz dodać własną logikę
clearInput();
if (inputModal) {
inputModal.addEventListener('hidden.bs.modal', () => {
rawText.value = '';
});
}
if (addModal) {
addModal.addEventListener('hidden.bs.modal', () => {
newDate.value = null;
});
}
});
const formattedWorkTime = (day) => {
const hours = String(day.workHours).padStart(2, '0'); // Dodaj wiodące zero do godzin
const minutes = String(day.workMinutes).padStart(2, '0'); // Dodaj wiodące zero do minut
return `${hours}:${minutes}`; // Zwróć sformatowany czas
const hours = String(day.workHours).padStart(2, '0');
const minutes = String(day.workMinutes).padStart(2, '0');
return `${hours}:${minutes}`;
};
// function saveOldValue(item, field) {
// oldValue.value = item[field];
// };
// const validate = (item, field, min, max, event) => {
// const newValue = Number(event.target.value);
// console.log("validate: " + field + ", min: " + min + ", max: " + max + ", newValue: " + newValue + ", oldValue: " + oldValue.value);
// if (isNaN(newValue) || newValue < min || newValue > max) {
// item[field] = oldValue.value; // Przywróć starą wartość
// }
// };
const getClassWeekday = (index) => {
switch (storeWorkHours.getWeekday(index)[0]) {
case 0:
@@ -210,20 +178,13 @@ const getClassWeekday = (index) => {
}
const processInputText = () => {
console.log(rawText.value);
}
const clearInput = () => {
rawText.value = '';
}
// const closeModal = () => {
// const modalElement = document.getElementById('staticBackdrop');
// const modal = Modal.getInstance(modalElement);
// if (modal) {
// modal.hide();
// }
// }
storeWorkHours.parseWorkHours(rawText.value);
};
const insertWorkDay = () => {
const date = new Date(newDate.value);
storeWorkHours.addWorkDay(date);
newDate.value = null;
};
</script>

View File

@@ -1,7 +1,169 @@
<template>
<h1>Table</h1>
<div class="container">
<div class="row gx-3">
<div class="col-4">
<div class="card bg-left text-light h-100">
<div class="row g-0 h-100">
<div class="col-3 ">
<h2 class="rounded-start bg-light h-100 d-flex justify-content-center align-items-center">
<i class="text-left fa-solid fa-calendar"></i>
</h2>
</div>
<div class="col-9 ">
<div class="card-body">
<h6 class="card-title">MIESIĄC:</h6>
<h3 class="card-subtitle">Marzec</h3>
</div>
</div>
</div>
</div>
</div>
<div class="col-4">
<div class="card bg-mid text-light h-100">
<div class="row g-0 ">
<div class="col-3 ">
<h2 class="rounded-start bg-light h-100 d-flex justify-content-center align-items-center">
<i class="text-mid fa-solid fa-hammer"></i>
</h2>
</div>
<div class="col-9 ">
<div class="card-body">
<h6 class="card-title">ILOŚĆ DNI ROBOCZYCH:</h6>
<h3 class="card-subtitle">21</h3>
</div>
</div>
</div>
</div>
</div>
<div class="col-4">
<div class="card bg-right text-light h-100">
<div class="row g-0 ">
<div class="col-3 ">
<h2 class="rounded-start bg-light h-100 d-flex justify-content-center align-items-center">
<i class="text-right fa-solid fa-clock "></i>
</h2>
</div>
<div class="col-9 ">
<div class="card-body">
<h6 class="card-title">WYMAGANA ILOŚĆ GODZIN:</h6>
<h3 class="card-subtitle">168</h3>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row gx-3 mt-3 text-center">
<div class="col-2">
<div class="card h-100">
<div class="card-header text-bg-primary">ILOŚĆ GODZIN</div>
<div class="card-body">
<h3 class="card-title">182</h3>
<!-- <h6 class="card-text mb-2 ">Marzec 2025</h6> -->
</div>
</div>
</div>
<div class="col-2">
<div class="card h-100">
<div class="card-header text-bg-primary">RÓŻNICA GODZIN</div>
<div class="card-body">
<h5 class="card-title">+15</h5>
<!-- <h6 class="card-text mb-2 ">Marzec 2025</h6> -->
</div>
</div>
</div>
<div class="col-2">
<div class="card h-100">
<div class="card-header text-bg-primary">PROGRES</div>
<div class="card-body">
<h5 class="card-title">18/21</h5>
<!-- <h6 class="card-text mb-2 ">Marzec 2025</h6> -->
</div>
</div>
</div>
<div class="col-2">
<div class="card h-100">
<div class="card-header text-bg-primary">DNI URLOPU</div>
<div class="card-body">
<h5 class="card-title">0</h5>
<!-- <h6 class="card-text mb-2 ">Marzec 2025</h6> -->
</div>
</div>
</div>
<div class="col-2">
<div class="card h-100">
<div class="card-header text-bg-primary">DNI CHOROBOWEGO</div>
<div class="card-body">
<h5 class="card-title">0</h5>
<!-- <h6 class="card-text mb-2 ">Marzec 2025</h6> -->
</div>
</div>
</div>
<div class="col-2">
<div class="card h-100">
<div class="card-header text-bg-primary">DNI ŚWIĄTECZNE</div>
<div class="card-body">
<h5 class="card-title">1</h5>
<!-- <h6 class="card-text mb-2 ">Marzec 2025</h6> -->
</div>
</div>
</div>
</div>
<!-- <div class="d-flex justify-content-center g-1">
<div class="col-auto mx-auto"></div>
</div> -->
<div class="row gx-3">
<!-- <div class="col-auto"> -->
<BarChartComponent />
<!-- </div> -->
</div>
</div>
</template>
<script setup>
</script>
import BarChartComponent from '@/components/BarChartComponent.vue';
</script>
<style scoped>
.bg-left {
background: rgb(25, 135, 84);
}
.text-left {
color: rgb(25, 135, 84);
}
.text-left-light {
color: rgb(253, 126, 20);
}
.bg-mid {
background: rgb(202, 101, 16);
}
.text-mid {
color: rgb(202, 101, 16);
}
.text-mid-light {
color: rgb(253, 126, 20);
}
.bg-right {
background: rgb(10, 162, 192);
}
.text-right {
color: rgb(10, 162, 192);
}
.text-right-light {
color: rgb(253, 126, 20);
}
</style>