Initial commit
This commit is contained in:
53
public/index.html
Normal file
53
public/index.html
Normal file
@@ -0,0 +1,53 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<title>Calculateur de Prix</title>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Section fixe en haut -->
|
||||
<div class="header">
|
||||
<div id="datetime"></div>
|
||||
<div class="header-row">
|
||||
<p>Montant Précédent: <span id="previous-amount">0.00 €</span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bouton "+" toujours visible -->
|
||||
<div id="add-row-container">
|
||||
<button id="add-row" class="add-row-button">+</button>
|
||||
</div>
|
||||
|
||||
<!-- Section centrale défilante -->
|
||||
<div class="articles">
|
||||
<div id="articles-scroll">
|
||||
<table id="articles-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Montant (€)</th>
|
||||
<th>Qtité</th>
|
||||
<th>Total</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Section fixe en bas -->
|
||||
<div class="footer">
|
||||
<div class="footer-content">
|
||||
<div class="totals">
|
||||
<p>Total Articles: <span id="article-total">0.00 €</span></p>
|
||||
<p>Total Final: <span id="final-total">0.00 €</span></p>
|
||||
</div>
|
||||
<button id="save">Enregistrer</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
131
public/script.js
Normal file
131
public/script.js
Normal file
@@ -0,0 +1,131 @@
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const datetimeElement = document.getElementById("datetime");
|
||||
const previousAmountElement = document.getElementById("previous-amount");
|
||||
const articleTotalElement = document.getElementById("article-total");
|
||||
const finalTotalElement = document.getElementById("final-total");
|
||||
const articlesTableBody = document.querySelector("#articles-table tbody");
|
||||
const addRowButton = document.getElementById("add-row");
|
||||
const saveButton = document.getElementById("save");
|
||||
|
||||
// Mettre à jour la date et l'heure
|
||||
const updateDatetime = () => {
|
||||
const now = new Date();
|
||||
datetimeElement.textContent = now.toLocaleString("fr-FR");
|
||||
};
|
||||
setInterval(updateDatetime, 1000);
|
||||
|
||||
// Charger le montant précédent
|
||||
fetch("/montant_precedent")
|
||||
.then(response => response.text())
|
||||
.then(data => {
|
||||
const previousAmount = parseFloat(data) || 0;
|
||||
previousAmountElement.textContent = `${previousAmount.toFixed(2)} €`;
|
||||
updateTotals();
|
||||
});
|
||||
|
||||
// Ajouter une ligne
|
||||
addRowButton.addEventListener("click", () => {
|
||||
const row = document.createElement("tr");
|
||||
|
||||
// Montant
|
||||
const montantCell = document.createElement("td");
|
||||
const montantInput = document.createElement("input");
|
||||
montantInput.type = "number";
|
||||
montantInput.step = "0.01";
|
||||
montantInput.placeholder = "0.00";
|
||||
montantCell.appendChild(montantInput);
|
||||
|
||||
// Quantité
|
||||
const quantiteCell = document.createElement("td");
|
||||
const quantiteSelect = document.createElement("select");
|
||||
for (let i = 1; i <= 10; i++) {
|
||||
const option = document.createElement("option");
|
||||
option.value = i;
|
||||
option.textContent = i;
|
||||
quantiteSelect.appendChild(option);
|
||||
}
|
||||
quantiteCell.appendChild(quantiteSelect);
|
||||
|
||||
// Total
|
||||
const totalCell = document.createElement("td");
|
||||
totalCell.textContent = "0.00 €";
|
||||
|
||||
// Bouton Option
|
||||
const optionCell = document.createElement("td");
|
||||
const optionButton = document.createElement("button");
|
||||
optionButton.textContent = "Option";
|
||||
optionButton.addEventListener("click", () => {
|
||||
const montant = parseFloat(montantInput.value || "0");
|
||||
montantInput.value = montant > 0 ? -montant : Math.abs(montant);
|
||||
updateRowTotal();
|
||||
});
|
||||
optionCell.appendChild(optionButton);
|
||||
|
||||
// Calculer le total de la ligne
|
||||
const updateRowTotal = () => {
|
||||
const montant = parseFloat(montantInput.value || "0");
|
||||
const quantite = parseFloat(quantiteSelect.value || "1");
|
||||
const total = montant * quantite;
|
||||
totalCell.textContent = `${total.toFixed(2)} €`;
|
||||
updateTotals();
|
||||
};
|
||||
|
||||
montantInput.addEventListener("input", updateRowTotal);
|
||||
quantiteSelect.addEventListener("change", updateRowTotal);
|
||||
|
||||
// Ajouter les cellules à la ligne
|
||||
row.appendChild(montantCell);
|
||||
row.appendChild(quantiteCell);
|
||||
row.appendChild(totalCell);
|
||||
row.appendChild(optionCell);
|
||||
articlesTableBody.appendChild(row);
|
||||
|
||||
// Placer le curseur sur le champ montant
|
||||
montantInput.focus();
|
||||
});
|
||||
|
||||
// Mettre à jour les totaux
|
||||
const updateTotals = () => {
|
||||
let articleTotal = 0;
|
||||
articlesTableBody.querySelectorAll("tr").forEach(row => {
|
||||
const totalCell = row.cells[2];
|
||||
articleTotal += parseFloat(totalCell.textContent || "0");
|
||||
});
|
||||
articleTotalElement.textContent = `${articleTotal.toFixed(2)} €`;
|
||||
|
||||
const previousAmount = parseFloat(previousAmountElement.textContent) || 0;
|
||||
finalTotalElement.textContent = `${(previousAmount + articleTotal).toFixed(2)} €`;
|
||||
};
|
||||
|
||||
// Sauvegarder les données
|
||||
saveButton.addEventListener("click", () => {
|
||||
const articles = [];
|
||||
articlesTableBody.querySelectorAll("tr").forEach(row => {
|
||||
const montant = parseFloat(row.cells[0].querySelector("input").value || "0");
|
||||
const quantite = parseFloat(row.cells[1].querySelector("select").value || "1");
|
||||
const total = montant * quantite;
|
||||
articles.push({ montant, quantite, total });
|
||||
});
|
||||
|
||||
const data = {
|
||||
date: new Date().toISOString(),
|
||||
previousAmount: parseFloat(previousAmountElement.textContent) || 0,
|
||||
articles,
|
||||
articleTotal: parseFloat(articleTotalElement.textContent) || 0,
|
||||
finalTotal: parseFloat(finalTotalElement.textContent) || 0
|
||||
};
|
||||
|
||||
fetch("/save", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(data)
|
||||
}).then(response => {
|
||||
if (response.ok) {
|
||||
alert("Données sauvegardées !");
|
||||
location.reload();
|
||||
} else {
|
||||
alert("Erreur lors de la sauvegarde.");
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
150
public/style.css
Normal file
150
public/style.css
Normal file
@@ -0,0 +1,150 @@
|
||||
/* Général */
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #f4f4f4;
|
||||
color: #333;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
/* En-tête fixe */
|
||||
.header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
background-color: #555;
|
||||
color: white;
|
||||
padding: 10px 15px;
|
||||
box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.1);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.header-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#datetime {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Bouton "+" */
|
||||
.add-row-button {
|
||||
position: fixed;
|
||||
top: 70px;
|
||||
right: 15px;
|
||||
z-index: 2000;
|
||||
padding: 10px 22px;
|
||||
background-color: #007bff; /* Bleu */
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.add-row-button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
|
||||
/* Section centrale défilante */
|
||||
.articles {
|
||||
position: relative;
|
||||
top: 120px;
|
||||
bottom: 60px;
|
||||
padding: 10px;
|
||||
overflow-y: auto;
|
||||
background-color: #e9ecef;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
#articles-scroll {
|
||||
overflow-x: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#articles-table {
|
||||
width: calc(100% - 20px);
|
||||
max-width: 600px;
|
||||
border-collapse: collapse;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
#articles-table th, #articles-table td {
|
||||
border: 1px solid #ddd;
|
||||
padding: 12px;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
#articles-table th {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
#articles-table td input {
|
||||
padding: 5px;
|
||||
width: 90%;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
#articles-table td button {
|
||||
background-color: #ffc107;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
padding: 5px 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
#articles-table tbody tr:nth-child(even) {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
/* Pied de page fixe */
|
||||
.footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
background-color: #555;
|
||||
color: white;
|
||||
padding: 15px 20px;
|
||||
box-shadow: 0px -2px 5px rgba(0, 0, 0, 0.1);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.footer-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.totals p {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
#save {
|
||||
margin-right: 20px;
|
||||
padding: 12px 25px;
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
#save:hover {
|
||||
background-color: #218838;
|
||||
}
|
||||
Reference in New Issue
Block a user