Choix du nombre d'exemplaires a l'impression

- Boutons +/- pour choisir le nombre d'exemplaires (1 a copies_max)
- copies_max configurable dans le backoffice (defaut: 5)
- Backend limite les copies au max configure

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-21 23:15:10 +01:00
parent f9c600c026
commit bffdf52c56
6 changed files with 95 additions and 10 deletions

View File

@@ -208,13 +208,18 @@ async def api_imprimantes():
@app.post("/api/imprimer")
async def api_imprimer(donnees: dict):
nom = donnees.get("photo", "")
copies = donnees.get("copies", 1)
# Limiter au max configure
config = charger_config()
copies_max = config.get("impression", {}).get("copies_max", 5)
copies = max(1, min(copies, copies_max))
# Chercher dans exports d'abord, puis photos
chemin = DOSSIER_EXPORTS / nom
if not chemin.exists():
chemin = DOSSIER_PHOTOS / nom
if not chemin.exists():
return JSONResponse({"erreur": "Photo introuvable"}, status_code=404)
ok = imprimer(chemin)
ok = imprimer(chemin, copies=copies)
if ok:
distribuer_photo(chemin, imprimee=True)
return {"succes": ok}

View File

@@ -45,7 +45,7 @@
},
"impression": {
"imprimante": null,
"copies": 1,
"copies_max": 5,
"format": "10x15"
},
"cadres": {

View File

@@ -369,6 +369,55 @@ html, body {
font-size: 2.5rem;
}
/* Choix exemplaires impression */
.form-impression {
display: flex;
gap: 1rem;
align-items: center;
margin: 1rem 0;
}
.exemplaires-choix {
display: flex;
align-items: center;
gap: 0.5rem;
}
.btn-exemplaire {
width: 48px;
height: 48px;
border-radius: 50%;
border: 2px solid var(--primaire);
background: transparent;
color: var(--primaire);
font-size: 1.5rem;
font-weight: 700;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: var(--transition);
}
.btn-exemplaire:active {
background: var(--primaire);
color: #fff;
transform: scale(0.9);
}
#nb-exemplaires {
font-size: 2.5rem;
font-weight: 700;
color: var(--texte);
min-width: 50px;
text-align: center;
}
.exemplaires-label {
color: var(--texte-secondaire);
font-size: 1rem;
}
.form-email {
display: flex;
gap: 0.8rem;

View File

@@ -77,7 +77,7 @@
<img id="photo-partage" src="" alt="Photo">
</div>
<div class="grille-partage">
<button class="btn-partage" id="btn-imprimer" onclick="lancerImpression()">
<button class="btn-partage" id="btn-imprimer" onclick="ouvrirImpression()">
<div class="partage-icone">&#128424;</div>
<span>Imprimer</span>
</button>
@@ -90,6 +90,17 @@
<span>QR Code</span>
</button>
</div>
<!-- Choix exemplaires impression -->
<div id="form-impression" class="form-impression cache">
<div class="exemplaires-choix">
<button class="btn-exemplaire" onclick="changerExemplaires(-1)">-</button>
<span id="nb-exemplaires">1</span>
<button class="btn-exemplaire" onclick="changerExemplaires(1)">+</button>
</div>
<span class="exemplaires-label">exemplaire(s)</span>
<button class="btn-action" onclick="lancerImpression()">Imprimer</button>
<button class="btn-secondaire" onclick="fermerImpression()">Annuler</button>
</div>
<div id="form-email" class="form-email cache">
<input type="email" id="input-email" placeholder="votre@email.com" autocomplete="off">
<button class="btn-action" onclick="envoyerEmail()">Envoyer</button>
@@ -156,8 +167,8 @@
<button class="btn-secondaire btn-petit" onclick="rafraichirImprimantes()">Rafraichir</button>
</div>
<div class="champ">
<label>Copies par impression</label>
<input type="number" id="admin-copies" min="1" max="5" value="1">
<label>Nombre max d'exemplaires</label>
<input type="number" id="admin-copies-max" min="1" max="20" value="5">
</div>
<button class="btn-action" onclick="sauvegarderMateriel()">Sauvegarder</button>
</div>

View File

@@ -54,7 +54,7 @@ async function chargerMateriel() {
// Imprimantes
await rafraichirImprimantes();
if (imp.imprimante) document.getElementById('admin-imprimante').value = imp.imprimante;
setValue('admin-copies', imp.copies || 1);
setValue('admin-copies-max', imp.copies_max || 5);
}
async function rafraichirImprimantes() {
@@ -82,7 +82,7 @@ async function sauvegarderMateriel() {
},
impression: {
imprimante: getValue('admin-imprimante'),
copies: parseInt(getValue('admin-copies')) || 1,
copies_max: parseInt(getValue('admin-copies-max')) || 5,
},
});
afficherStatut('Materiel sauvegarde', 'succes');

View File

@@ -1,11 +1,31 @@
/* Module partage - Impression, email, QR code */
let nbExemplaires = 1;
let copiesMax = 5;
function ouvrirImpression() {
copiesMax = config.impression?.copies_max || 5;
nbExemplaires = 1;
document.getElementById('nb-exemplaires').textContent = nbExemplaires;
document.getElementById('form-impression').classList.remove('cache');
}
function fermerImpression() {
document.getElementById('form-impression').classList.add('cache');
}
function changerExemplaires(delta) {
nbExemplaires = Math.max(1, Math.min(copiesMax, nbExemplaires + delta));
document.getElementById('nb-exemplaires').textContent = nbExemplaires;
}
async function lancerImpression() {
if (!photoFinale) return;
afficherStatut('Impression en cours...', 'succes');
const resultat = await apiPost('/api/imprimer', { photo: photoFinale });
fermerImpression();
afficherStatut(`Impression de ${nbExemplaires} exemplaire(s)...`, 'succes');
const resultat = await apiPost('/api/imprimer', { photo: photoFinale, copies: nbExemplaires });
if (resultat.succes) {
afficherStatut('Photo envoyee a l\'imprimante !', 'succes');
afficherStatut(`${nbExemplaires} exemplaire(s) envoye(s) a l'imprimante !`, 'succes');
} else {
afficherStatut('Erreur d\'impression', 'erreur');
}