← Torna alla Home

Codice completo di : Carica Dati su Disco Esterno




<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Gestionale Didattico Locale</title>

<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.25/jspdf.plugin.autotable.min.js"></script>

<style>

/* STILE CSS: Layout e Aspetto */
body { font-family: 'Segoe UI', sans-serif; margin: 0; padding: 0; background-color: #f4f4f4; }

/* Layout a due zone: Maschera Input (Top) e Dati (Bottom) */
.container { max-width: 1200px; margin: 0 auto; padding: 20px; }

/* Sezione Maschera Inserimento */
.input-mask {
background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);
margin-bottom: 20px; border-left: 5px solid #2ecc71;
}

.input-mask h2 { margin-top: 0; color: #333; }

.form-grid {
display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px;
}

.form-group label { display: block; margin-bottom: 5px; font-weight: bold; font-size: 0.9em; }
.form-group input, .form-group select {
width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box;
}

/* Pulsanti */
.btn-group { margin-top: 20px; display: flex; gap: 10px; flex-wrap: wrap; }
button {
padding: 10px 15px; border: none; border-radius: 4px; cursor: pointer; color: white; font-weight: bold;
}
.btn-add { background-color: #2ecc71; } /* Verde */
.btn-csv { background-color: #3498db; } /* Blu */
.btn-pdf { background-color: #e74c3c; } /* Rosso */
.btn-mail { background-color: #f1c40f; color: #333; } /* Giallo */
.btn-save { background-color: #9b59b6; } /* Viola - DB */

/* Sezione Tabella Dati */
.data-view {
background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}

table { width: 100%; border-collapse: collapse; margin-top: 10px; }
th, td { padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }
th { background-color: #f8f9fa; color: #333; }
tr:hover { background-color: #f1f1f1; }

/* Colore per le operazioni */
.op-entrata { color: green; font-weight: bold; }
.op-uscita { color: red; font-weight: bold; }
.op-garanzia { color: orange; font-weight: bold; }

/* Area Grafico (nascosta di default) */
#chartContainer { margin-top: 20px; display: none; height: 300px; }

/* --- IL PULSANTE HOME (Fisso e Stile Coerente) --- */
.btn-top-left {
position: fixed;
top: 20px;
left: 20px;
z-index: 1000;

display: inline-block;
padding: 10px 20px;
background-color: #007BFF; /* Blu istituzionale */
color: #ffffff !important; /* Forza il bianco */
text-decoration: none;
font-weight: bold;
font-family: Arial, sans-serif; /* Font bastoni per il bottone interfaccia */
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
transition: background-color 0.3s;
}

.btn-top-left:hover {
background-color: #0056b3;
}
</style>
</head>
<body>
<a href="index.html" class="btn-top-left">← Torna alla Home</a>
<br><br>
<div class="container">

<div class="input-mask">
<h2>Gestione Operazioni</h2>
<div class="form-grid">
<div class="form-group">
<label>Data (Automatica)</label>
<input type="date" id="inputData" readonly>
</div>
<div class="form-group">
<label>Nominativo</label>
<input type="text" id="inputNome" placeholder="Mario Rossi">
</div>
<div class="form-group">
<label>Cod. Fisc / P.IVA</label>
<input type="text" id="inputCF" placeholder="CODICE...">
</div>
<div class="form-group">
<label>Operazione</label>
<select id="inputOp">
<option value="Entrate">Entrate</option>
<option value="Uscite">Uscite</option>
<option value="Garanzia">Garanzia</option>
</select>
</div>
<div class="form-group">
<label>Euro (€)</label>
<input type="number" id="inputEuro" step="0.01" placeholder="0.00">
</div>
<div class="form-group">
<label>Telefono</label>
<input type="tel" id="inputTel" placeholder="333...">
</div>
<div class="form-group">
<label>Email</label>
<input type="email" id="inputEmail" placeholder="email@esempio.com">
</div>
</div>

<div class="btn-group">
<button class="btn-add" onclick="aggiungiRiga()">+ Aggiungi Riga</button>
<button class="btn-save" onclick="salvaDatabase()">💾 Salva DB su Disco</button>
<button class="btn-save" onclick="document.getElementById('fileInput').click()">📂 Carica DB</button>
<input type="file" id="fileInput" style="display: none;" onchange="caricaDatabase(this)">
</div>

<hr>

<div class="btn-group">
<button class="btn-csv" onclick="esportaCSV()">Esporta CSV</button>
<button class="btn-pdf" onclick="esportaPDF()">Esporta PDF</button>
<button class="btn-mail" onclick="generaReportMail()">📧 Report Mail & Grafici</button>
</div>

<div id="chartContainer">
<canvas id="myChart"></canvas>
</div>
</div>

<div class="data-view">
<h3>Database Dati</h3>
<table id="mainTable">
<thead>
<tr>
<th>Sel.</th>
<th>Data</th>
<th>Nominativo</th>
<th>CF/P.IVA</th>
<th>Operazione</th>
<th>Euro</th>
<th>Telefono</th>
<th>Email</th>
<th>Azioni</th>
</tr>
</thead>
<tbody id="tableBody">
</tbody>
</table>
</div>

</div>

<script>
/**
* LOGICA JAVASCRIPT
* Scopo: Gestione array di oggetti, manipolazione DOM, Export file.
*/

// 1. STATO DELL'APPLICAZIONE (Il nostro Database in memoria RAM)
let database = [];

// Al caricamento della pagina
window.onload = function() {
// Imposta la data odierna nel campo input
document.getElementById('inputData').valueAsDate = new Date();

// Controlla se c'è un salvataggio precedente nel LocalStorage (memoria browser)
const savedData = localStorage.getItem('db_gestionale_g');
if (savedData) {
database = JSON.parse(savedData);
renderTable();
}
};

// 2. FUNZIONE: Aggiungi Riga
function aggiungiRiga() {
// Recupero valori dal DOM
const data = document.getElementById('inputData').value;
const nome = document.getElementById('inputNome').value;
const cf = document.getElementById('inputCF').value;
const op = document.getElementById('inputOp').value;
const euro = parseFloat(document.getElementById('inputEuro').value) || 0;
const tel = document.getElementById('inputTel').value;
const email = document.getElementById('inputEmail').value;

// Validazione minima
if(nome === "" || euro === 0) {
alert("Compilare almeno Nome e Importo!");
return;
}

// Creazione Oggetto Riga
const nuovaRiga = {
id: Date.now(), // timestamp univoco
selezionato: false,
data: data,
nominativo: nome,
codfisc: cf,
operazione: op,
euro: euro,
telefono: tel,
email: email
};

// Aggiorna Array e Vista
database.push(nuovaRiga);
salvaInLocale(); // Salva nel browser
renderTable(); // Ridisegna tabella

// Reset campi (tranne la data che resta odierna)
document.getElementById('inputNome').value = "";
document.getElementById('inputEuro').value = "";
}

// 3. FUNZIONE: Disegna Tabella (Render)
function renderTable() {
const tbody = document.getElementById('tableBody');
tbody.innerHTML = ""; // Pulisce tabella attuale

database.forEach((riga, index) => {
// Determina classe CSS per colore operazione
let colorClass = "";
if(riga.operazione === "Entrate") colorClass = "op-entrata";
else if(riga.operazione === "Uscite") colorClass = "op-uscita";
else colorClass = "op-garanzia";

const tr = document.createElement('tr');
tr.innerHTML = `
<td><input type="checkbox" onchange="toggleSelezione(${index})" ${riga.selezionato ? 'checked' : ''}></td>
<td>${riga.data}</td>
<td>${riga.nominativo}</td>
<td>${riga.codfisc}</td>
<td class="${colorClass}">${riga.operazione}</td>
<td>€ ${riga.euro.toFixed(2)}</td>
<td>${riga.telefono}</td>
<td>${riga.email}</td>
<td><button onclick="rimuoviRiga(${index})" style="background:#e74c3c; padding:5px;">X</button></td>
`;
tbody.appendChild(tr);
});
}

// Gestione Spunta/Selezione
function toggleSelezione(index) {
database[index].selezionato = !database[index].selezionato;
salvaInLocale();
}

// Rimuovi riga
function rimuoviRiga(index) {
if(confirm("Eliminare questa riga?")) {
database.splice(index, 1);
salvaInLocale();
renderTable();
}
}

// 4. PERSISTENZA DATI (Simulazione DB su File)

// Salva nel browser (veloce)
function salvaInLocale() {
localStorage.setItem('db_gestionale_g', JSON.stringify(database));
}

// Salva su Disco G: (Download file JSON)
function salvaDatabase() {
const dataStr = JSON.stringify(database, null, 2);
const blob = new Blob([dataStr], { type: "application/json" });
const url = URL.createObjectURL(blob);

const a = document.createElement('a');
a.href = url;
a.download = "database_gestionale.json"; // Nome file su disco
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}

// Carica da Disco G:
function caricaDatabase(input) {
const file = input.files[0];
if (!file) return;

const reader = new FileReader();
reader.onload = function(e) {
try {
database = JSON.parse(e.target.result);
salvaInLocale();
renderTable();
alert("Database caricato con successo!");
} catch(err) {
alert("Errore nel file database.");
}
};
reader.readAsText(file);
}

// 5. ESPORTAZIONE CSV
function esportaCSV() {
let csvContent = "data:text/csv;charset=utf-8,";
csvContent += "Data,Nominativo,CF,Operazione,Euro,Telefono,Email\n"; // Intestazione

database.forEach(row => {
// Solo se selezionato? Se nessuno selezionato, esporta tutto.
// Qui esportiamo tutto per semplicità, oppure filtriamo:
// const rowsToExport = database.filter(r => r.selezionato).length > 0 ? database.filter(r => r.selezionato) : database;

let rowStr = `${row.data},${row.nominativo},${row.codfisc},${row.operazione},${row.euro},${row.telefono},${row.email}`;
csvContent += rowStr + "\n";
});

const encodedUri = encodeURI(csvContent);
const link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", "export_dati.csv");
document.body.appendChild(link);
link.click();
}

// 6. ESPORTAZIONE PDF (Libreria jsPDF)
function esportaPDF() {
const { jsPDF } = window.jspdf;
const doc = new jsPDF();

doc.text("Report Gestionale", 14, 15);

// Colonne e righe per autoTable
const tableColumn = ["Data", "Nominativo", "Operazione", "Euro"];
const tableRows = [];

database.forEach(row => {
const rowData = [row.data, row.nominativo, row.operazione, row.euro.toFixed(2)];
tableRows.push(rowData);
});

doc.autoTable({
head: [tableColumn],
body: tableRows,
startY: 20,
});

doc.save("report_gestionale.pdf");
}

// 7. GRAFICI E MAIL (Reportistica)
function generaReportMail() {
// A. Calcolo Totali per il grafico
let totEntrate = 0;
let totUscite = 0;
let totGaranzia = 0;

database.forEach(r => {
if(r.operazione === "Entrate") totEntrate += r.euro;
if(r.operazione === "Uscite") totUscite += r.euro;
if(r.operazione === "Garanzia") totGaranzia += r.euro;
});

// B. Generazione Grafico a Torta (Chart.js)
document.getElementById('chartContainer').style.display = 'block';
const ctx = document.getElementById('myChart').getContext('2d');

// Distruggiamo il grafico precedente se esiste per rifarlo
if(window.myPieChart) window.myPieChart.destroy();

window.myPieChart = new Chart(ctx, {
type: 'pie', // O 'bar'
data: {
labels: ['Entrate', 'Uscite', 'Garanzia'],
datasets: [{
data: [totEntrate, totUscite, totGaranzia],
backgroundColor: ['#2ecc71', '#e74c3c', '#f1c40f']
}]
},
options: { responsive: true, maintainAspectRatio: false }
});

// C. Creazione Mailto (Simulazione invio mail)
// Nota didattica: Non si può allegare l'immagine del grafico direttamente via mailto standard HTML.
// Si inviano i dati testuali.

const subject = "Report Gestionale Giornaliero";
const body = `Buongiorno,%0D%0A%0D%0AEcco il riepilogo operazioni:%0D%0A` +
`- Totale Entrate: € ${totEntrate.toFixed(2)}%0D%0A` +
`- Totale Uscite: € ${totUscite.toFixed(2)}%0D%0A` +
`- Totale Garanzia: € ${totGaranzia.toFixed(2)}%0D%0A%0D%0A` +
`Il grafico è visibile sulla dashboard locale.`;

window.location.href = `mailto:?subject=${subject}&body=${body}`;
}

</script>

</body>
</html>