feat(auth): integrate codice-fiscale-js for fiscal code validation in registration
This commit is contained in:
@@ -29,6 +29,15 @@ const media = computed(() => (reportData.value as any)?.media || [])
|
||||
const statusHistory = computed(() => (reportData.value as any)?.history || [])
|
||||
const messages = computed(() => (messagesData.value as any)?.messages || [])
|
||||
const summary = computed(() => (summaryData.value as any)?.summary)
|
||||
const statusMeta: Record<string, string> = {
|
||||
OPEN: 'Aperta',
|
||||
UNDER_REVIEW: 'In revisione',
|
||||
ASSIGNED: 'Assegnata',
|
||||
IN_PROGRESS: 'In lavorazione',
|
||||
RESOLVED: 'Risolta',
|
||||
REJECTED: 'Respinta',
|
||||
CLOSED: 'Chiusa'
|
||||
}
|
||||
|
||||
// Form Cambia Stato
|
||||
const newStatus = ref<ReportStatus>('IN_PROGRESS')
|
||||
@@ -125,80 +134,132 @@ const formatDate = (dateString: string) => {
|
||||
|
||||
<template>
|
||||
<div v-if="report">
|
||||
<div class="bg-light border-bottom py-3">
|
||||
<div class="container d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<NuxtLink to="/operator/assigned" class="btn btn-sm btn-link text-decoration-none ps-0">
|
||||
← Torna alle assegnazioni
|
||||
</NuxtLink>
|
||||
<h1 class="h4 font-weight-bold mb-1">Intervento #{{ reportId }}</h1>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<StatusBadge :status="report.status" />
|
||||
<small class="text-muted">{{ report.category_name }}</small>
|
||||
<div class="report-hero py-4">
|
||||
<div class="container">
|
||||
<NuxtLink to="/operator/assigned" class="btn btn-sm btn-link text-decoration-none ps-0 mb-2">
|
||||
← Torna alle assegnazioni
|
||||
</NuxtLink>
|
||||
<div class="row g-3 align-items-end">
|
||||
<div class="col-12 col-lg-8">
|
||||
<div class="report-hero-meta mb-2">
|
||||
<span class="report-id">Intervento #{{ reportId }}</span>
|
||||
<StatusBadge :status="report.status" />
|
||||
</div>
|
||||
<h1 class="h3 font-weight-bold mb-2">{{ report.category_name }}</h1>
|
||||
<p class="mb-0 report-hero-address">{{ report.address }}</p>
|
||||
</div>
|
||||
<div class="col-12 col-lg-4">
|
||||
<div class="report-hero-stats">
|
||||
<div class="hero-stat">
|
||||
<span class="hero-stat-label">Stato</span>
|
||||
<strong>{{ statusMeta[report.status] || report.status }}</strong>
|
||||
</div>
|
||||
<div class="hero-stat">
|
||||
<span class="hero-stat-label">Aperta</span>
|
||||
<strong>{{ formatDate(report.created_at) }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container my-5">
|
||||
<div class="row">
|
||||
<!-- Sinistra: Dettagli -->
|
||||
<div class="col-12 col-lg-7 mb-4">
|
||||
<div class="card card-bg mb-4">
|
||||
<div class="row g-4">
|
||||
<div class="col-12 col-xl-7">
|
||||
<div class="card card-bg border-0 shadow-sm mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title font-weight-bold mb-3">Dettagli Cittadino</h5>
|
||||
<p class="mb-1"><strong>Indirizzo:</strong> {{ report.address }}</p>
|
||||
<p class="mb-3"><strong>Posizione:</strong> {{ report.latitude }}, {{ report.longitude }}</p>
|
||||
|
||||
<h6 class="font-weight-bold">Descrizione</h6>
|
||||
<p class="text-break bg-white p-3 border rounded">{{ report.description }}</p>
|
||||
<div class="report-section-head mb-3">
|
||||
<BIIcon name="it-map-marker-circle" size="sm" color="primary" class="me-2" />
|
||||
<h2 class="h6 mb-0">Dettagli segnalazione</h2>
|
||||
</div>
|
||||
<dl class="report-detail-grid mb-0">
|
||||
<div>
|
||||
<dt>Indirizzo</dt>
|
||||
<dd>{{ report.address }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>Coordinate</dt>
|
||||
<dd>{{ report.latitude }}, {{ report.longitude }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>Area</dt>
|
||||
<dd>{{ report.area_name || 'Non specificata' }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>Operatore assegnato</dt>
|
||||
<dd>{{ report.assigned_operator_id ? `#${report.assigned_operator_id}` : 'Non assegnato' }}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
|
||||
<div class="report-description mt-4">
|
||||
<h3 class="h6 mb-2">Descrizione</h3>
|
||||
<p class="mb-0 text-break">{{ report.description }}</p>
|
||||
</div>
|
||||
|
||||
<div v-if="media.length > 0">
|
||||
<h6 class="font-weight-bold mt-4 mb-3">Allegati del cittadino</h6>
|
||||
<h3 class="h6 mt-4 mb-3">Allegati del cittadino</h3>
|
||||
<div class="row g-2">
|
||||
<div v-for="m in media" :key="m.id" class="col-4 col-md-3">
|
||||
<img v-if="m.media_kind === 'IMAGE'" :src="runtimeConfig.public.api + m.url" class="img-fluid rounded object-fit-cover shadow-sm" style="aspect-ratio: 1;" />
|
||||
<img v-if="m.media_kind === 'IMAGE'" :src="runtimeConfig.public.api + m.url" class="img-fluid rounded object-fit-cover shadow-sm report-media-frame" style="aspect-ratio: 1;" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-bg mb-4">
|
||||
<div class="card card-bg border-0 shadow-sm mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title font-weight-bold mb-3">Comunicazioni con il Cittadino</h5>
|
||||
<div class="report-chat-header mb-3">
|
||||
<div>
|
||||
<div class="report-section-head mb-1">
|
||||
<BIIcon name="it-comment" size="sm" color="primary" class="me-2" />
|
||||
<h2 class="h6 mb-0">Comunicazioni con cittadino</h2>
|
||||
</div>
|
||||
<p class="text-muted small mb-0">Chat unica pratica. Mantieni aggiornamenti chiari e brevi.</p>
|
||||
</div>
|
||||
<span class="badge bg-light text-dark border">{{ messages.length }} messaggi</span>
|
||||
</div>
|
||||
<MessageList :messages="messages" />
|
||||
<MessageComposer @send="handleSendMessage" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Destra: Strumenti Operatore -->
|
||||
<div class="col-12 col-lg-5">
|
||||
|
||||
<!-- Summary Box -->
|
||||
<div class="card border-primary mb-4 shadow-sm" v-if="summary">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0">Riepilogo Intervento</h5>
|
||||
</div>
|
||||
<div class="col-12 col-xl-5">
|
||||
<div class="report-sidebar">
|
||||
<div class="card card-bg border-0 shadow-sm mb-4" v-if="summary">
|
||||
<div class="card-body">
|
||||
<p class="mb-2"><strong>Operatore Assegnato:</strong> {{ summary.operator_id ? `#${summary.operator_id}` : 'Nessuno' }}</p>
|
||||
<p class="mb-2"><strong>Squadra Assegnata:</strong> <span class="badge bg-secondary">{{ summary.assigned_to_team || 'Nessuna' }}</span></p>
|
||||
<p class="mb-2"><strong>Data Prevista:</strong> {{ summary.estimated_resolution_date ? formatDate(summary.estimated_resolution_date) : 'Non impostata' }}</p>
|
||||
<p class="mb-0"><strong>Note Interne:</strong></p>
|
||||
<p class="small text-muted bg-light p-2 rounded border mt-1 mb-0">{{ summary.internal_notes || 'Nessuna nota interna' }}</p>
|
||||
<h2 class="h6 mb-3">Riepilogo intervento</h2>
|
||||
<ul class="report-summary-list list-unstyled mb-4">
|
||||
<li>
|
||||
<span>Operatore</span>
|
||||
<strong>{{ summary.operator_id ? `#${summary.operator_id}` : 'Nessuno' }}</strong>
|
||||
</li>
|
||||
<li>
|
||||
<span>Squadra</span>
|
||||
<strong>{{ summary.assigned_to_team || 'Nessuna' }}</strong>
|
||||
</li>
|
||||
<li>
|
||||
<span>Data prevista</span>
|
||||
<strong>{{ summary.estimated_resolution_date ? formatDate(summary.estimated_resolution_date) : 'Non impostata' }}</strong>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="report-description">
|
||||
<h3 class="h6 mb-2">Note interne</h3>
|
||||
<p class="small mb-0">{{ summary.internal_notes || 'Nessuna nota interna' }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer bg-white border-top-0 pt-0">
|
||||
<div class="card-body pt-0">
|
||||
<button class="btn btn-outline-primary w-100" @click="isAssignModalOpen = true">
|
||||
Gestisci Squadra e Note
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modifica Stato -->
|
||||
<div class="card mb-4">
|
||||
<div class="card card-bg border-0 shadow-sm mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title font-weight-bold mb-3">Aggiorna Stato</h5>
|
||||
<h2 class="h6 mb-3">Aggiorna stato</h2>
|
||||
<form @submit.prevent="handleStatusUpdate">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Nuovo Stato</label>
|
||||
@@ -220,10 +281,9 @@ const formatDate = (dateString: string) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cronologia -->
|
||||
<div class="card card-bg">
|
||||
<div class="card card-bg border-0 shadow-sm">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title font-weight-bold mb-3">Cronologia Eventi</h5>
|
||||
<h2 class="h6 mb-3">Cronologia eventi</h2>
|
||||
<div v-if="statusHistory.length === 0" class="small text-muted">Nessun evento registrato.</div>
|
||||
<ul class="list-unstyled mb-0 ms-2">
|
||||
<li v-for="item in statusHistory" :key="item.id" class="mb-3 border-start border-primary border-3 ps-3">
|
||||
@@ -238,7 +298,7 @@ const formatDate = (dateString: string) => {
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -286,7 +346,116 @@ const formatDate = (dateString: string) => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.report-hero {
|
||||
background: linear-gradient(180deg, #f0f6fc 0%, #ffffff 100%);
|
||||
border-bottom: 1px solid #d9e3ee;
|
||||
}
|
||||
|
||||
.report-hero-meta,
|
||||
.report-section-head {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.report-hero-meta {
|
||||
flex-wrap: wrap;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.report-id {
|
||||
color: #5c6f82;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.report-hero-address {
|
||||
color: #455b71;
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
.report-hero-stats {
|
||||
background: #fff;
|
||||
border: 1px solid #d9e3ee;
|
||||
border-radius: 8px;
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.hero-stat {
|
||||
display: grid;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.hero-stat-label,
|
||||
.report-detail-grid dt {
|
||||
color: #5c6f82;
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 700;
|
||||
margin: 0 0 0.25rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.report-detail-grid {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.report-detail-grid dd {
|
||||
color: #17324d;
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.report-description {
|
||||
background: #f7fafc;
|
||||
border: 1px solid #e4ebf1;
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.report-chat-header {
|
||||
align-items: flex-start;
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.report-summary-list {
|
||||
display: grid;
|
||||
gap: 0.875rem;
|
||||
}
|
||||
|
||||
.report-summary-list li {
|
||||
align-items: baseline;
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.report-sidebar {
|
||||
position: sticky;
|
||||
top: 1.5rem;
|
||||
}
|
||||
|
||||
.report-media-frame {
|
||||
border: 1px solid #d9e3ee;
|
||||
}
|
||||
|
||||
.object-fit-cover {
|
||||
object-fit: cover;
|
||||
}
|
||||
</style>
|
||||
|
||||
@media (max-width: 991.98px) {
|
||||
.report-detail-grid,
|
||||
.report-hero-stats {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.report-sidebar {
|
||||
position: static;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user