@@ -66,24 +93,46 @@ const loadingPolicy = ref(false)
const savingPolicy = ref(false)
const policySaved = ref(false)
+// #56 — réglages des créneaux offerts
+const booking = reactive({ lead_hours: 24, day_start: 8, day_end: 18, days_offered: [1, 2, 3, 4, 5], horizon_days: 21, max_per_day: 0, hold_minutes: 10 })
+const bookingFields = ref([])
+const weekdays = ref([])
+const savingBooking = ref(false)
+const bookingSaved = ref(false)
+
onMounted(async () => {
loadingPolicy.value = true
try {
const d = await getPolicy()
Object.assign(policy, d.policy || {})
+ if (d.policy?.booking) Object.assign(booking, d.policy.booking)
opts.reschedule = d.options?.reschedule || []
opts.escalation = d.options?.escalation || []
+ bookingFields.value = d.options?.booking_fields || []
+ weekdays.value = d.options?.weekdays || []
} catch (e) { /* defaults */ }
loadingPolicy.value = false
})
async function doSavePolicy () {
savingPolicy.value = true; policySaved.value = false
- try { await savePolicy({ ...policy }); policySaved.value = true; setTimeout(() => { policySaved.value = false }, 2500) }
+ try { await savePolicy({ reschedule: policy.reschedule, sms_enabled: policy.sms_enabled, sms_quiet_hours: policy.sms_quiet_hours, escalation: policy.escalation }); policySaved.value = true; setTimeout(() => { policySaved.value = false }, 2500) }
catch (e) { /* ignore */ }
savingPolicy.value = false
}
+function toggleDay (v) {
+ if (!Array.isArray(booking.days_offered)) booking.days_offered = []
+ const i = booking.days_offered.indexOf(v)
+ if (i >= 0) booking.days_offered.splice(i, 1); else booking.days_offered.push(v)
+}
+async function doSaveBooking () {
+ savingBooking.value = true; bookingSaved.value = false
+ try { await savePolicy({ booking: { ...booking, days_offered: [...(booking.days_offered || [])] } }); bookingSaved.value = true; setTimeout(() => { bookingSaved.value = false }, 2500) }
+ catch (e) { /* ignore */ }
+ savingBooking.value = false
+}
+
async function scrollDown () { await nextTick(); if (scrollEl.value) scrollEl.value.scrollTop = scrollEl.value.scrollHeight }
async function send () {
diff --git a/apps/ops/src/pages/RendezVousPage.vue b/apps/ops/src/pages/RendezVousPage.vue
index 0cb1fee..c649b75 100644
--- a/apps/ops/src/pages/RendezVousPage.vue
+++ b/apps/ops/src/pages/RendezVousPage.vue
@@ -3,7 +3,11 @@
@@ -11,14 +15,17 @@
- Jobs ({{ filteredJobs.length }})
+
+ {{ view === 'reschedule' ? 'À recontacter' : 'Jobs' }} ({{ filteredJobs.length }})
+
- {{ j.name }}
+ {{ j.customer_name || j.name }}
{{ j.service_location || '—' }} · {{ j.duration_h || 1 }}h
-
+
+
Aucun job.
@@ -29,9 +36,20 @@
Sélectionne un job à gauche pour prendre rendez-vous.
-
- {{ sel.name }}
- {{ sel.service_location || '—' }} · durée {{ params.duration }}h · tech actuel: {{ sel.assigned_tech || '—' }}
+
+
+
{{ sel.customer_name || sel.name }}
+
{{ sel.service_location || '—' }} · durée {{ params.duration }}h · tech actuel : {{ sel.assigned_tech || '—' }}
+
+
+
+
+
+
+
+ ⚠️ Client à recontacter. Propose un créneau ci-dessous (réassignation directe), ou laisse le client choisir :
+
+
@@ -43,13 +61,35 @@
-
+
+
+
+
+
+
{{ slots.length }} créneaux — clique pour réserver (bloqué {{ holdMinutes }} min pour les autres) :
+
+
{{ wk.label }}
+
+
{{ dayLabel(day.date) }}
+
+
+
{{ s.start }}–{{ s.end }}
+
{{ s.tech_name }}
+
+
+
+
+
+
+ Aucun créneau — élargis la période, la zone ou la compétence (le roster doit être publié, et la politique de créneaux peut filtrer).
+
+
-
+
Saisis les 3 disponibilités du client, en ordre de préférence. On place dans le 1er tenable.
{{ i + 1 }}
@@ -60,7 +100,7 @@
- ✅ Choix #{{ fit.chosen.rank }} retenu : {{ frDate(fit.chosen.date) }} {{ fit.chosen.start }}–{{ fit.chosen.end }} · {{ fit.chosen.tech_name }}
+ ✅ Choix #{{ fit.chosen.rank }} retenu : {{ dayLabel(fit.chosen.date) }} {{ fit.chosen.start }}–{{ fit.chosen.end }} · {{ fit.chosen.tech_name }}
@@ -73,23 +113,6 @@
-
-
-
-
-
-
{{ slots.length }} créneaux — clique pour sélectionner :
-
-
-
{{ frDate(s.date) }}
-
{{ s.start }}–{{ s.end }}
-
{{ s.tech_name }}
-
-
-
-
- Aucun créneau — élargis la période, la zone ou la compétence (le roster doit être publié).
-
@@ -97,30 +120,63 @@