improved some bugs

This commit is contained in:
Luca Haid
2026-01-18 13:25:14 +01:00
parent b3bb4bb970
commit e99b0d4658
5 changed files with 158 additions and 77 deletions

View File

@@ -7,7 +7,7 @@
export default {
name: 'WorkorderModule',
emits: ['navigate', 'toast'],
emits: ['navigate', 'toast', 'detail-open', 'detail-close'],
props: {
user: Object,
submodule: String
@@ -63,10 +63,10 @@ export default {
const problemType = ref('');
const problemComment = ref('');
// Swipe state for list cards
const swipeStartX = ref(0);
const swipeCardId = ref(null);
const swipeOffset = ref({}); // { [workorderId]: offsetX }
const swipeOffset = ref({});
const swipeTriggered = ref(false);
// =====================
// COMPUTED
@@ -136,12 +136,10 @@ export default {
const allRequiredComplete = requiredItems.every(c => c.completed);
if (!allRequiredComplete) return false;
} else if (checklist.value.length > 0) {
// If no items are marked as required, check if at least some items are completed
const hasAnyCompleted = checklist.value.some(c => c.completed);
if (!hasAnyCompleted) return false;
const allCompleted = checklist.value.every(c => c.completed);
if (!allCompleted) return false;
}
// Check cable data if required
if (tenantConfig.value?.requireCableLength && !cableDataForm.value.cableLength?.trim()) {
return false;
}
@@ -201,6 +199,7 @@ export default {
selectedWorkorder.value = workorder;
isDetailLoading.value = true;
expandedCards.value = { customer: true, checklist: true, documentation: false, notes: false, journal: false, cableData: false };
emit('detail-open', workorder.id);
try {
// Fetch all workorder details in a single request
@@ -233,6 +232,7 @@ export default {
tenantConfig.value = null;
checklist.value = [];
isEditingNotes.value = false;
emit('detail-close');
};
const toggleCard = (cardId) => {
@@ -535,10 +535,16 @@ export default {
}
};
// Swipe handlers for list cards
const scrollIntoViewOnFocus = (e) => {
setTimeout(() => {
e.target.scrollIntoView({ behavior: 'smooth', block: 'center' });
}, 300);
};
const handleTouchStart = (e, wo) => {
swipeStartX.value = e.touches[0].clientX;
swipeCardId.value = wo.id;
swipeTriggered.value = false;
};
const handleTouchMove = (e, wo) => {
@@ -546,9 +552,11 @@ export default {
const currentX = e.touches[0].clientX;
const diff = swipeStartX.value - currentX;
// Only allow left swipe, max 100px
if (diff > 0) {
swipeOffset.value = { ...swipeOffset.value, [wo.id]: Math.min(diff, 100) };
if (diff > 10) {
swipeTriggered.value = true;
}
} else {
swipeOffset.value = { ...swipeOffset.value, [wo.id]: 0 };
}
@@ -558,18 +566,25 @@ export default {
if (swipeCardId.value !== wo.id) return;
const offset = swipeOffset.value[wo.id] || 0;
// If swiped more than 60px, trigger navigation
if (offset > 60 && wo.customerAddress) {
swipeTriggered.value = true;
triggerHaptic('light');
const address = encodeURIComponent(wo.customerAddress);
window.open(`https://maps.google.com/maps?q=${address}`, '_blank');
}
// Reset with animation
swipeOffset.value = { ...swipeOffset.value, [wo.id]: 0 };
swipeCardId.value = null;
};
const handleCardClick = (wo) => {
if (swipeTriggered.value) {
swipeTriggered.value = false;
return;
}
openDetail(wo);
};
const getSwipeStyle = (woId) => {
const offset = swipeOffset.value[woId] || 0;
return {
@@ -666,8 +681,10 @@ export default {
handleTouchStart,
handleTouchMove,
handleTouchEnd,
handleCardClick,
getSwipeStyle,
swipeOffset
swipeOffset,
scrollIntoViewOnFocus
};
},
@@ -767,13 +784,13 @@ export default {
<!-- Card content (slides on swipe) -->
<div
@click="openDetail(wo)"
@click="handleCardClick(wo)"
@touchstart="handleTouchStart($event, wo)"
@touchmove="handleTouchMove($event, wo)"
@touchend="handleTouchEnd($event, wo)"
:style="getSwipeStyle(wo.id)"
:style="{ ...getSwipeStyle(wo.id), touchAction: 'pan-y' }"
:class="[
'relative w-full bg-white dark:bg-slate-800 p-4 rounded-xl shadow-sm text-left cursor-pointer',
'relative w-full bg-white dark:bg-slate-800 p-4 rounded-xl shadow-sm text-left cursor-pointer card-contrast',
'border-l-4',
getStatusBorderColor(wo.status)
]"
@@ -808,14 +825,7 @@ export default {
<!-- DETAIL VIEW -->
<template v-else>
<!-- Header -->
<div class="flex items-center justify-between px-4 py-3 bg-white dark:bg-slate-800 border-b border-slate-100 dark:border-slate-700 flex-shrink-0">
<button @click="closeDetail" class="flex items-center text-slate-600 dark:text-slate-300">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
</svg>
Zurück
</button>
<div class="flex items-center gap-2">
<span v-if="selectedWorkorder.oaid" class="font-bold text-primary dark:text-sky-400">{{ selectedWorkorder.oaid }}</span>
<span v-else class="font-bold text-primary dark:text-sky-400">#{{ selectedWorkorder.id }}</span>
@@ -839,7 +849,7 @@ export default {
<template v-else>
<!-- Customer Card (Expanded by default) -->
<div class="bg-white dark:bg-slate-800 rounded-xl overflow-hidden">
<div class="bg-white dark:bg-slate-800 rounded-xl overflow-hidden card-contrast">
<button
@click="toggleCard('customer')"
class="w-full flex items-center justify-between p-4 text-left"
@@ -897,7 +907,7 @@ export default {
</div>
<!-- Checklist Card -->
<div class="bg-white dark:bg-slate-800 rounded-xl overflow-hidden">
<div class="bg-white dark:bg-slate-800 rounded-xl overflow-hidden card-contrast">
<button
@click="toggleCard('checklist')"
class="w-full flex items-center justify-between p-4 text-left"
@@ -963,7 +973,7 @@ export default {
</div>
<!-- Documentation Card -->
<div class="bg-white dark:bg-slate-800 rounded-xl overflow-hidden">
<div class="bg-white dark:bg-slate-800 rounded-xl overflow-hidden card-contrast">
<button
@click="toggleCard('documentation')"
class="w-full flex items-center justify-between p-4 text-left"
@@ -1020,7 +1030,7 @@ export default {
</div>
<!-- Notes Card -->
<div class="bg-white dark:bg-slate-800 rounded-xl overflow-hidden">
<div class="bg-white dark:bg-slate-800 rounded-xl overflow-hidden card-contrast">
<button
@click="toggleCard('notes')"
class="w-full flex items-center justify-between p-4 text-left"
@@ -1044,6 +1054,7 @@ export default {
rows="4"
class="w-full p-3 bg-slate-50 dark:bg-slate-700 rounded-lg text-slate-800 dark:text-white border-0 focus:ring-2 focus:ring-primary"
placeholder="Notiz eingeben..."
@focus="scrollIntoViewOnFocus"
></textarea>
<div class="flex justify-end gap-2 mt-2">
<button @click="cancelEditNotes" class="px-4 py-2 text-sm text-slate-600 dark:text-slate-300">
@@ -1067,7 +1078,7 @@ export default {
</div>
<!-- Journal Card -->
<div class="bg-white dark:bg-slate-800 rounded-xl overflow-hidden">
<div class="bg-white dark:bg-slate-800 rounded-xl overflow-hidden card-contrast">
<button
@click="toggleCard('journal')"
class="w-full flex items-center justify-between p-4 text-left"
@@ -1096,6 +1107,7 @@ export default {
placeholder="Neuer Eintrag..."
class="flex-1 px-3 py-2 bg-slate-50 dark:bg-slate-700 rounded-lg text-slate-800 dark:text-white border-0"
@keyup.enter="addJournalEntry"
@focus="scrollIntoViewOnFocus"
>
<button @click="addJournalEntry" class="px-4 py-2 bg-primary text-white rounded-lg">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
@@ -1117,7 +1129,7 @@ export default {
</div>
<!-- Cable Data Card (only if required) -->
<div v-if="tenantConfig && (tenantConfig.requireCableLength || tenantConfig.requireCableType)" class="bg-white dark:bg-slate-800 rounded-xl overflow-hidden">
<div v-if="tenantConfig && (tenantConfig.requireCableLength || tenantConfig.requireCableType)" class="bg-white dark:bg-slate-800 rounded-xl overflow-hidden card-contrast">
<button
@click="toggleCard('cableData')"
class="w-full flex items-center justify-between p-4 text-left"
@@ -1162,7 +1174,7 @@ export default {
</div>
<!-- Bottom Action Bar -->
<div class="absolute bottom-0 left-0 right-0 p-3 bg-white dark:bg-slate-800 border-t border-slate-100 dark:border-slate-700 flex gap-3">
<div class="absolute bottom-0 left-0 right-0 p-3 bg-white dark:bg-slate-800 border-t border-slate-100 dark:border-slate-700 flex gap-3" style="padding-bottom: calc(0.75rem + env(safe-area-inset-bottom, 0px));">
<button
@click="openProblemSheet"
class="flex-1 py-3 bg-amber-500 text-white rounded-xl font-medium flex items-center justify-center active:scale-95 transition"
@@ -1230,15 +1242,6 @@ export default {
</div>
<!-- Upload Buttons -->
<div class="space-y-2">
<input
ref="fileInputRef"
type="file"
accept="image/*,application/pdf"
multiple
class="hidden"
@change="handleFileSelect"
capture="environment"
>
<button
@click="triggerFileInput"
:disabled="isUploading"
@@ -1300,6 +1303,7 @@ export default {
rows="3"
placeholder="Weitere Details..."
class="w-full px-3 py-2 bg-slate-50 dark:bg-slate-700 rounded-lg text-slate-800 dark:text-white border-0"
@focus="scrollIntoViewOnFocus"
></textarea>
</div>
<!-- Submit -->
@@ -1368,6 +1372,16 @@ export default {
</div>
</transition>
</teleport>
<input
ref="fileInputRef"
type="file"
accept="image/*,application/pdf"
multiple
class="hidden"
@change="handleFileSelect"
capture="environment"
>
</div>
`
};