Verbessert die Benutzeroberfläche in DiaryView.vue, indem die Struktur des Unfallformulars optimiert und die Audioinitialisierung an die Benutzerinteraktion angepasst wird. Fügt Logik zur Überprüfung von Aktivitätszeiten hinzu und stellt sicher, dass Audio nur bei aktivierter Funktion abgespielt wird.

This commit is contained in:
Torsten Schulz (local)
2025-09-01 11:23:02 +02:00
parent a1ab742126
commit c4b9a7d782

View File

@@ -311,30 +311,30 @@
<div v-if="showImage" class="memberImage">
<img :src="imageUrl" @click="closeImage" />
</div>
</div>
<div v-if="showAccidentForm" class="accidentForm">
<form @submit.prevent="submitAccident">
<div>
<label for="memberId">Mitglied:</label>
<select id="memberId" v-model="accident.memberId">
<template v-for="member in members" :key="member.id" :value="member.id">
<option v-if="participants.indexOf(member.id) >= 0" :value="member.id">{{ member.firstName + ' '
+ member.lastName }}</option>
</template>
</select>
</div>
<div>
<label for="accident">Unfall:</label>
<textarea id="accident" v-model="accident.accident" required></textarea>
</div>
<button type="button" @click="saveAccident">Eintragen</button>
<button type="button" @click="closeAccidentForm">Schießen</button>
<ul>
<li v-for="accident in accidents" :key="accident.id">{{ accident.firstName + ' ' + accident.lastName +
': '
+ accident.accident}}</li>
</ul>
</form>
<div v-if="showAccidentForm" class="accidentForm">
<form @submit.prevent="submitAccident">
<div>
<label for="memberId">Mitglied:</label>
<select id="memberId" v-model="accident.memberId">
<template v-for="member in members" :key="member.id" :value="member.id">
<option v-if="participants.indexOf(member.id) >= 0" :value="member.id">{{ member.firstName + ' '
+ member.lastName }}</option>
</template>
</select>
</div>
<div>
<label for="accident">Unfall:</label>
<textarea id="accident" v-model="accident.accident" required></textarea>
</div>
<button type="button" @click="saveAccident">Eintragen</button>
<button type="button" @click="closeAccidentForm">Schießen</button>
<ul>
<li v-for="accident in accidents" :key="accident.id">{{ accident.firstName + ' ' + accident.lastName +
': '
+ accident.accident}}</li>
</ul>
</form>
</div>
</div>
</template>
@@ -398,9 +398,12 @@ export default {
tagHistoryMember: null,
tagHistory: null,
intermediateTimes: [],
bellSound: new Audio('/sound/bell-123742.mp3'),
thumbSound: new Audio('/sound/thump-105302.mp3'),
bellSound: null,
thumbSound: null,
soundEnabled: true,
debugSound: true,
timeChecker: null,
playedActivityMarks: [],
showAccidentForm: false,
accident: {
memberId: '',
@@ -465,6 +468,8 @@ export default {
}
},
async refreshDates(selectId) {
const response = await apiClient.get(`/diary/${this.currentClub}`);
this.dates = response.data.map(entry => ({ id: entry.id, date: entry.date }));
@@ -592,7 +597,7 @@ export default {
const response = await apiClient.get(`/group/${this.currentClub}/${this.date.id}`);
this.groups = response.data;
} catch (error) {
console.log(error);
// ignore
}
},
@@ -1168,6 +1173,7 @@ export default {
if (this.timeChecker) clearInterval(this.timeChecker);
this.timeChecker = setInterval(() => {
const currentTime = new Date().toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
// Zeit-Check Tick
if (!this.trainingStart || !this.trainingEnd) {
return;
}
@@ -1183,40 +1189,80 @@ export default {
}
if (startCheckTime && currentTime === startCheckTime) {
this.playBellSound();
}
if (endCheckTime && currentTime === endCheckTime) {
} else if (endCheckTime && currentTime === endCheckTime) {
this.playBellSound();
} else {
// Nach letzter Aktivität (Ende) nochmal Glocke
try { this.calculateAllItemTimes(); } catch (e) {}
const items = Array.isArray(this.trainingPlan) ? this.trainingPlan : [];
const lastItem = items.length ? items[items.length - 1] : null;
const lastEnd = lastItem && lastItem.endTime ? lastItem.endTime : null;
const lastEndSS = lastEnd ? (lastEnd.length === 5 ? lastEnd + ':00' : lastEnd) : null;
const lastEndMM = lastEndSS ? lastEndSS.slice(0, 5) : null;
const currentHHMM = currentTime.slice(0, 5);
if (lastEndSS && (currentTime === lastEndSS || (currentTime.endsWith(':00') && currentHHMM === lastEndMM))) {
this.playBellSound();
}
}
if (this.intermediateTimes.includes(currentTime)) {
// Aktivitätszeiten (Startzeiten) aus Trainingsplan prüfen
try { this.calculateAllItemTimes(); } catch (e) {}
const items = Array.isArray(this.trainingPlan) ? this.trainingPlan : [];
const startTimesSS = items
.map(it => (it && it.startTime ? (it.startTime.length === 5 ? it.startTime + ':00' : it.startTime) : null))
.filter(Boolean);
const startTimesMM = startTimesSS.map(t => t.slice(0, 5));
const currentHHMM = currentTime.slice(0, 5);
const isMatch = startTimesSS.includes(currentTime) || (currentTime.endsWith(':00') && startTimesMM.includes(currentHHMM));
if (isMatch) {
this.playThumbSound();
}
}, 1000);
},
playBellSound() {
this.bellSound.play();
if (!this.soundEnabled) return;
try {
this.bellSound && this.bellSound.play();
} catch (e) {
// ignore
}
},
playThumbSound() {
this.thumbSound.play();
if (!this.soundEnabled) return;
try {
this.thumbSound && this.thumbSound.play();
} catch (e) {
// ignore
}
},
calculateIntermediateTimes() {
// Stelle sicher, dass alle startTime-Werte aktuell sind
try { this.calculateAllItemTimes(); } catch(e) {}
if (!this.trainingPlan || this.trainingPlan.length === 0) {
this.intermediateTimes = [];
return;
}
let times = [];
let currentTime = new Date("2025-01-01 " + this.trainingStart);
this.trainingPlan.forEach(item => {
const rawItem = JSON.parse(JSON.stringify(item));
currentTime.setMinutes(currentTime.getMinutes() + item.duration);
times.push(currentTime.toTimeString({ hours: '2-digit', minutes: '2-digit', seconds: '2-digit' }).slice(0, 8));
});
times = [...new Set(times)].sort();
this.intermediateTimes = times.filter(time =>
time !== this.trainingStart && time !== this.trainingEnd
);
function withSeconds(hhmm) {
if (!hhmm) return null;
const parts = hhmm.split(':');
if (parts.length < 3) return hhmm + ':00';
return hhmm;
}
const times = [];
for (const item of this.trainingPlan) {
if (item && item.startTime) {
const t = withSeconds(item.startTime);
if (t) times.push(t);
}
}
const normalizedStart = withSeconds(this.trainingStart);
const unique = Array.from(new Set(times));
const filtered = unique.filter(t => t !== normalizedStart);
filtered.sort();
this.intermediateTimes = filtered;
},
async addAccident() {
@@ -1402,6 +1448,14 @@ export default {
},
async mounted() {
await this.init();
// Versuche, Audio erst bei Nutzerinteraktion zu initialisieren (Autoplay-Policy)
const tryInit = () => {
if (!this.bellSound) this.bellSound = new Audio('/sound/bell-123742.mp3');
if (!this.thumbSound) this.thumbSound = new Audio('/sound/thump-105302.mp3');
this.soundEnabled = true;
window.removeEventListener('click', tryInit, { once: true });
};
window.addEventListener('click', tryInit, { once: true });
},
beforeUnmount() {
if (this.timeChecker) {