Compare commits
5 Commits
cf2049798a
...
c0aac3e49c
| Author | SHA1 | Date | |
|---|---|---|---|
| c0aac3e49c | |||
| 182443530a | |||
| d62741e139 | |||
| 8426bd1ae8 | |||
| b18296f8a8 |
@@ -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
44
app/package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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": {
|
||||
|
||||
89
app/src/components/BarChartComponent.vue
Normal file
89
app/src/components/BarChartComponent.vue
Normal 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>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
})
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user