Differenze
Queste sono le differenze tra la revisione selezionata e la versione attuale della pagina.
Entrambe le parti precedenti la revisioneRevisione precedenteProssima revisione | Revisione precedente | ||
gestione_turni_med [2025/08/12 10:05] – neoadmin | gestione_turni_med [2025/08/12 10:16] (versione attuale) – neoadmin | ||
---|---|---|---|
Linea 7: | Linea 7: | ||
body { | body { | ||
font-family: | font-family: | ||
- | margin: | + | margin: |
background: #f5f5f5; | background: #f5f5f5; | ||
+ | line-height: | ||
} | } | ||
| | ||
Linea 15: | Linea 16: | ||
margin: 0 auto; | margin: 0 auto; | ||
background: white; | background: white; | ||
- | padding: | + | padding: |
- | border-radius: | + | border-radius: |
box-shadow: 0 2px 10px rgba(0, | box-shadow: 0 2px 10px rgba(0, | ||
} | } | ||
Linea 24: | Linea 25: | ||
background: linear-gradient(135deg, | background: linear-gradient(135deg, | ||
color: white; | color: white; | ||
- | padding: | + | padding: |
- | border-radius: | + | border-radius: |
- | margin-bottom: | + | margin-bottom: |
+ | } | ||
+ | |||
+ | .header h1 { | ||
+ | margin: 0 0 8px 0; | ||
+ | font-size: 22px; | ||
+ | font-weight: | ||
+ | } | ||
+ | |||
+ | .header h2 { | ||
+ | margin: 0 0 5px 0; | ||
+ | font-size: 16px; | ||
+ | font-weight: | ||
+ | } | ||
+ | |||
+ | .header p { | ||
+ | margin: 0; | ||
+ | font-size: 13px; | ||
+ | opacity: 0.9; | ||
} | } | ||
| | ||
.controls { | .controls { | ||
display: flex; | display: flex; | ||
- | gap: 20px; | + | gap: 15px; |
- | margin-bottom: | + | margin-bottom: |
flex-wrap: wrap; | flex-wrap: wrap; | ||
+ | align-items: | ||
} | } | ||
| | ||
Linea 39: | Linea 59: | ||
display: flex; | display: flex; | ||
flex-direction: | flex-direction: | ||
- | gap: 5px; | + | gap: 4px; |
+ | } | ||
+ | |||
+ | .control-group label { | ||
+ | font-size: 12px; | ||
+ | font-weight: | ||
+ | color: #2c3e50; | ||
} | } | ||
| | ||
select, input, button { | select, input, button { | ||
- | padding: | + | padding: |
border: 1px solid #ddd; | border: 1px solid #ddd; | ||
- | border-radius: | + | border-radius: |
- | font-size: | + | font-size: |
} | } | ||
| | ||
Linea 54: | Linea 80: | ||
cursor: pointer; | cursor: pointer; | ||
font-weight: | font-weight: | ||
+ | transition: background 0.3s; | ||
} | } | ||
| | ||
Linea 760: | Linea 787: | ||
} | } | ||
- | function | + | function |
- | const gestione | + | const range = XLSX.utils.decode_range(ws['!ref']); |
- | if (gestione) gestione.remove(); | + | |
+ | const borderStyle = { | ||
+ | border: { | ||
+ | top: { style: ' | ||
+ | bottom: { style: ' | ||
+ | left: { style: ' | ||
+ | right: { style: ' | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | // Intestazione (riga 0) | ||
+ | for (let col = 0; col < numColonne; col++) { | ||
+ | const cellAddress = XLSX.utils.encode_cell({ r: 0, c: col }); | ||
+ | | ||
+ | ws[cellAddress].s = { | ||
+ | font: { bold: true, color: { rgb: ' | ||
+ | fill: { fgColor: { rgb: ' | ||
+ | alignment: { horizontal: ' | ||
+ | border: borderStyle.border | ||
+ | }; | ||
+ | } | ||
+ | |||
+ | // Trova dove inizia la legenda | ||
+ | let inizioLegenda = -1; | ||
+ | for (let row = 0; row <= range.e.r; row++) { | ||
+ | const cellAddress = XLSX.utils.encode_cell({ r: row, c: 0 }); | ||
+ | if (ws[cellAddress] && ws[cellAddress].v === ' | ||
+ | inizioLegenda = row; | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Applica stili ai dati medici | ||
+ | for (let row = 1; row < (inizioLegenda > 0 ? inizioLegenda - 1 : range.e.r + 1); row++) { | ||
+ | for (let col = 0; col < numColonne; col++) { | ||
+ | const cellAddress = XLSX.utils.encode_cell({ r: row, c: col }); | ||
+ | if (!ws[cellAddress]) ws[cellAddress] = { v: '', | ||
+ | ws[cellAddress].s = { | ||
+ | alignment: { horizontal: ' | ||
+ | border: borderStyle.border | ||
+ | }; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Applica stili alla legenda | ||
+ | if (inizioLegenda > 0) { | ||
+ | for (let row = inizioLegenda; | ||
+ | for (let col = 0; col < numColonne; col++) { | ||
+ | const cellAddress = XLSX.utils.encode_cell({ r: row, c: col }); | ||
+ | if (!ws[cellAddress]) ws[cellAddress] = { v: '', | ||
+ | |||
+ | if (row === inizioLegenda) { | ||
+ | // Titolo legenda | ||
+ | ws[cellAddress].s = { | ||
+ | font: { bold: true, size: 12 }, | ||
+ | fill: { fgColor: { rgb: ' | ||
+ | alignment: { horizontal: ' | ||
+ | border: borderStyle.border | ||
+ | }; | ||
+ | } else { | ||
+ | // Contenuto legenda | ||
+ | ws[cellAddress].s = { | ||
+ | fill: { fgColor: { rgb: ' | ||
+ | alignment: { horizontal: ' | ||
+ | border: borderStyle.border | ||
+ | }; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Larghezza colonne ottimizzata | ||
+ | ws[' | ||
+ | { width: 8 }, { width: 10 }, { width: 15 }, { width: 10 }, { width: 10 }, | ||
+ | { width: 8 }, { width: 10 }, { width: 15 }, { width: 8 }, { width: 10 }, | ||
+ | { width: 15 }, { width: 8 }, { width: 10 }, { width: 10 }, { width: 10 } | ||
+ | ]; | ||
} | } | ||
Linea 794: | Linea 897: | ||
| | ||
const ws = XLSX.utils.aoa_to_sheet(exportData); | const ws = XLSX.utils.aoa_to_sheet(exportData); | ||
+ | | ||
+ | // Applica stili anche al foglio esportazione caratteristiche | ||
+ | applicaStiliCaratteristiche(ws, | ||
+ | | ||
XLSX.utils.book_append_sheet(wb, | XLSX.utils.book_append_sheet(wb, | ||
| | ||
Linea 1888: | Linea 1995: | ||
const wb = XLSX.utils.book_new(); | const wb = XLSX.utils.book_new(); | ||
| | ||
- | // FOGLIO 1: TURNI | + | // FOGLIO 1: TURNI CON BORDI |
const excelData = []; | const excelData = []; | ||
| | ||
- | // Intestazioni | + | // Intestazioni |
excelData.push([' | excelData.push([' | ||
excelData.push([' | excelData.push([' | ||
Linea 1900: | Linea 2007: | ||
| | ||
// Intestazioni giorni | // Intestazioni giorni | ||
- | const rigaIntestazioni = ['', | + | const rigaIntestazioni = ['MEDICO', '' |
for (let giorno = 1; giorno <= giorni; giorno++) { | for (let giorno = 1; giorno <= giorni; giorno++) { | ||
const data = new Date(anno, mese, giorno); | const data = new Date(anno, mese, giorno); | ||
Linea 1913: | Linea 2020: | ||
const tuttiMedici = Object.keys(medici); | const tuttiMedici = Object.keys(medici); | ||
tuttiMedici.forEach(codMedico => { | tuttiMedici.forEach(codMedico => { | ||
- | const rigaMedico = [medici[codMedico].nome, '' | + | const rigaMedico = [medici[codMedico].nomeCompleto, '' |
| | ||
for (let giorno = 1; giorno <= giorni; giorno++) { | for (let giorno = 1; giorno <= giorni; giorno++) { | ||
Linea 1934: | Linea 2041: | ||
const ws1 = XLSX.utils.aoa_to_sheet(excelData); | const ws1 = XLSX.utils.aoa_to_sheet(excelData); | ||
+ | | ||
+ | // Applica stili e bordi al foglio turni | ||
+ | applicaStiliExcel(ws1, | ||
+ | | ||
XLSX.utils.book_append_sheet(wb, | XLSX.utils.book_append_sheet(wb, | ||
Linea 1965: | Linea 2076: | ||
| | ||
const ws2 = XLSX.utils.aoa_to_sheet(statsData); | const ws2 = XLSX.utils.aoa_to_sheet(statsData); | ||
+ | | ||
+ | // Applica stili al foglio statistiche | ||
+ | applicaStiliStatistiche(ws2, | ||
+ | | ||
XLSX.utils.book_append_sheet(wb, | XLSX.utils.book_append_sheet(wb, | ||
- | // FOGLIO 3: VALIDAZIONE | + | // FOGLIO 3: VALIDAZIONE |
const validazione = validaTurniCompleti(); | const validazione = validaTurniCompleti(); | ||
const validazioneData = []; | const validazioneData = []; | ||
validazioneData.push([' | validazioneData.push([' | ||
+ | validazioneData.push([]); | ||
+ | validazioneData.push([' | ||
validazioneData.push([' | validazioneData.push([' | ||
validazioneData.push([' | validazioneData.push([' | ||
- | validazioneData.push([' | + | validazioneData.push([' |
+ | validazioneData.push([' | ||
validazioneData.push([]); | validazioneData.push([]); | ||
+ | | ||
+ | if (validazione.successiImportanti.length > 0) { | ||
+ | validazioneData.push([' | ||
+ | validazione.successiImportanti.forEach(successo => { | ||
+ | validazioneData.push([successo, | ||
+ | }); | ||
+ | validazioneData.push([]); | ||
+ | } | ||
| | ||
if (validazione.avvisi.length > 0) { | if (validazione.avvisi.length > 0) { | ||
- | validazioneData.push([' | + | validazioneData.push([' |
validazione.avvisi.forEach(avviso => { | validazione.avvisi.forEach(avviso => { | ||
- | validazioneData.push([avviso]); | + | validazioneData.push([avviso, ' |
}); | }); | ||
validazioneData.push([]); | validazioneData.push([]); | ||
Linea 1985: | Linea 2111: | ||
| | ||
if (validazione.errori.length > 0) { | if (validazione.errori.length > 0) { | ||
- | validazioneData.push([' | + | validazioneData.push([' |
validazione.errori.forEach(errore => { | validazione.errori.forEach(errore => { | ||
- | validazioneData.push([errore]); | + | validazioneData.push([errore, ' |
}); | }); | ||
} | } | ||
| | ||
const ws3 = XLSX.utils.aoa_to_sheet(validazioneData); | const ws3 = XLSX.utils.aoa_to_sheet(validazioneData); | ||
+ | | ||
+ | // Applica stili al foglio validazione | ||
+ | applicaStiliValidazione(ws3, | ||
+ | | ||
XLSX.utils.book_append_sheet(wb, | XLSX.utils.book_append_sheet(wb, | ||
- | | + | // 🎨 FUNZIONI PER STILI EXCEL CON BORDI |
+ | function applicaStiliExcel(ws, | ||
+ | const range = XLSX.utils.decode_range(ws[' | ||
+ | |||
+ | // Stili per bordi | ||
+ | const borderStyle = { | ||
+ | border: { | ||
+ | top: { style: ' | ||
+ | bottom: { style: ' | ||
+ | left: { style: ' | ||
+ | right: { style: ' | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | const headerStyle = { | ||
+ | font: { bold: true, color: { rgb: ' | ||
+ | fill: { fgColor: { rgb: ' | ||
+ | alignment: { horizontal: ' | ||
+ | border: { | ||
+ | top: { style: ' | ||
+ | bottom: { style: ' | ||
+ | left: { style: ' | ||
+ | right: { style: ' | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | const titleStyle = { | ||
+ | font: { bold: true, size: 14 }, | ||
+ | alignment: { horizontal: ' | ||
+ | border: borderStyle.border | ||
+ | }; | ||
+ | |||
+ | // Applica stili alle intestazioni (riga 7 - giorni) | ||
+ | for (let col = 0; col <= range.e.c; col++) { | ||
+ | const cellAddress = XLSX.utils.encode_cell({ r: 6, c: col }); | ||
+ | if (!ws[cellAddress]) ws[cellAddress] = { v: '', | ||
+ | ws[cellAddress].s = headerStyle; | ||
+ | } | ||
+ | |||
+ | // Applica bordi a tutte le celle dei dati | ||
+ | for (let row = 7; row <= range.e.r; row++) { | ||
+ | for (let col = 0; col <= range.e.c; col++) { | ||
+ | const cellAddress = XLSX.utils.encode_cell({ r: row, c: col }); | ||
+ | if (!ws[cellAddress]) ws[cellAddress] = { v: '', | ||
+ | |||
+ | if (col === 0) { | ||
+ | // Prima colonna (nomi medici) - stile speciale | ||
+ | ws[cellAddress].s = { | ||
+ | font: { bold: true }, | ||
+ | fill: { fgColor: { rgb: ' | ||
+ | alignment: { horizontal: ' | ||
+ | border: borderStyle.border | ||
+ | }; | ||
+ | } else { | ||
+ | // Altre celle - bordi normali | ||
+ | ws[cellAddress].s = { | ||
+ | alignment: { horizontal: ' | ||
+ | border: borderStyle.border | ||
+ | }; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Applica stili ai titoli (prime 5 righe) | ||
+ | for (let row = 0; row < 5; row++) { | ||
+ | const cellAddress = XLSX.utils.encode_cell({ r: row, c: 0 }); | ||
+ | if (!ws[cellAddress]) ws[cellAddress] = { v: '', | ||
+ | ws[cellAddress].s = titleStyle; | ||
+ | } | ||
+ | |||
+ | // Imposta larghezza colonne | ||
+ | const colWidths = [{ width: 20 }, { width: 3 }]; | ||
+ | for (let i = 2; i < numColonne; i++) { | ||
+ | colWidths.push({ width: 12 }); | ||
+ | } | ||
+ | ws[' | ||
+ | } | ||
+ | |||
+ | function applicaStiliStatistiche(ws, | ||
+ | const range = XLSX.utils.decode_range(ws[' | ||
+ | |||
+ | const borderStyle = { | ||
+ | border: { | ||
+ | top: { style: ' | ||
+ | bottom: { style: ' | ||
+ | left: { style: ' | ||
+ | right: { style: ' | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | // Intestazione (riga 1) | ||
+ | for (let col = 0; col < numColonne; col++) { | ||
+ | const cellAddress = XLSX.utils.encode_cell({ r: 1, c: col }); | ||
+ | if (!ws[cellAddress]) ws[cellAddress] = { v: '', | ||
+ | ws[cellAddress].s = { | ||
+ | font: { bold: true, color: { rgb: ' | ||
+ | fill: { fgColor: { rgb: ' | ||
+ | alignment: { horizontal: ' | ||
+ | border: borderStyle.border | ||
+ | }; | ||
+ | } | ||
+ | |||
+ | // Dati | ||
+ | for (let row = 2; row <= range.e.r; row++) { | ||
+ | for (let col = 0; col < numColonne; col++) { | ||
+ | const cellAddress = XLSX.utils.encode_cell({ r: row, c: col }); | ||
+ | if (!ws[cellAddress]) ws[cellAddress] = { v: '', | ||
+ | ws[cellAddress].s = { | ||
+ | alignment: { horizontal: ' | ||
+ | border: borderStyle.border | ||
+ | }; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Larghezza colonne | ||
+ | ws[' | ||
+ | { width: 25 }, { width: 12 }, { width: 12 }, { width: 8 }, { width: 8 }, | ||
+ | { width: 10 }, { width: 10 }, { width: 12 }, { width: 8 }, { width: 12 }, { width: 12 } | ||
+ | ]; | ||
+ | } | ||
+ | |||
+ | function applicaStiliValidazione(ws, | ||
+ | const range = XLSX.utils.decode_range(ws[' | ||
+ | |||
+ | const borderStyle = { | ||
+ | border: { | ||
+ | top: { style: ' | ||
+ | bottom: { style: ' | ||
+ | left: { style: ' | ||
+ | right: { style: ' | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | // Applica bordi a tutte le celle | ||
+ | for (let row = 0; row <= range.e.r; row++) { | ||
+ | for (let col = 0; col < numColonne; col++) { | ||
+ | const cellAddress = XLSX.utils.encode_cell({ r: row, c: col }); | ||
+ | if (!ws[cellAddress]) ws[cellAddress] = { v: '', | ||
+ | |||
+ | // Titoli sezioni in grassetto | ||
+ | if (ws[cellAddress].v && typeof ws[cellAddress].v === ' | ||
+ | if (ws[cellAddress].v.includes(' | ||
+ | ws[cellAddress].v.includes(' | ||
+ | ws[cellAddress].v.includes(' | ||
+ | ws[cellAddress].v.includes(' | ||
+ | ws[cellAddress].s = { | ||
+ | font: { bold: true, size: 12 }, | ||
+ | fill: { fgColor: { rgb: ' | ||
+ | alignment: { horizontal: ' | ||
+ | border: borderStyle.border | ||
+ | }; | ||
+ | } else { | ||
+ | ws[cellAddress].s = { | ||
+ | alignment: { horizontal: ' | ||
+ | border: borderStyle.border | ||
+ | }; | ||
+ | } | ||
+ | } else { | ||
+ | ws[cellAddress].s = { | ||
+ | border: borderStyle.border | ||
+ | }; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Larghezza colonne | ||
+ | ws[' | ||
+ | } | ||
+ | |||
+ | | ||
const fileName = `Turni_TIN_Perfezionati_${nomiMesi[mese]}_${anno}.xlsx`; | const fileName = `Turni_TIN_Perfezionati_${nomiMesi[mese]}_${anno}.xlsx`; | ||
XLSX.writeFile(wb, | XLSX.writeFile(wb, | ||
| | ||
- | mostraMessaggio(`✅ File Excel esportato con successo: ${fileName}`, | + | mostraMessaggio(`✅ File Excel esportato con bordi e stili: ${fileName}`, |
| | ||
} catch (error) { | } catch (error) { |