- Preview thread : poll uniquement quand ecran capture actif, keepalive 30s sinon - Sequence boot Canon : power cycle relais si absent USB au demarrage - Veille auto 30min : Canon coupe par relais apres inactivite, reveil au preview_start - Stats diagnostic /api/canon/stats : keepalive, preview, captures, connexions - Escalade reconnexion adoucie : pas d'USB reset les 2 premieres tentatives - Hard reset relais 10s (resistance decharge 990ohm sur dummy battery 8V) - Gestion fin evenement : date_fin + bouton terminer + guard 403 impression - Compteur base sur min(papier, ruban) avec cap evenement optionnel - Pre-eclairage countdown : projecteurs ON 3s avant capture pour mesure expo - Canon _configurer_init() : ISO 800, drivemode Single, viewfinder, EXIF preserve - Admin : detail evenement, compteur consommables, galerie impression Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WyN9xFp84P9VaWT3Qe2DXu
200 lines
7.2 KiB
JavaScript
200 lines
7.2 KiB
JavaScript
/* Module partage - Impression, email, QR code */
|
|
|
|
let nbExemplaires = 1;
|
|
let copiesMax = 2;
|
|
|
|
async function ouvrirImpression() {
|
|
copiesMax = config.impression?.copies_max || 2;
|
|
nbExemplaires = 1;
|
|
document.getElementById('nb-exemplaires').textContent = nbExemplaires;
|
|
cadreChoisi = null;
|
|
|
|
const hasCadres = await chargerCadresChoixImpression();
|
|
if (hasCadres) {
|
|
document.getElementById('popup-cadre-impression').classList.remove('cache');
|
|
} else {
|
|
document.getElementById('form-impression').classList.remove('cache');
|
|
}
|
|
}
|
|
|
|
function fermerImpression() {
|
|
document.getElementById('form-impression').classList.add('cache');
|
|
cadreChoisi = null;
|
|
}
|
|
|
|
function confirmerCadreImpression() {
|
|
document.getElementById('popup-cadre-impression').classList.add('cache');
|
|
document.getElementById('form-impression').classList.remove('cache');
|
|
}
|
|
|
|
function annulerCadreImpression() {
|
|
document.getElementById('popup-cadre-impression').classList.add('cache');
|
|
cadreChoisi = null;
|
|
}
|
|
|
|
async function chargerCadresChoixImpression() {
|
|
const fmt = (config.impression?.format || '15x20').replace('-2up', '');
|
|
const data = await apiGet(`/api/cadres-impression/${fmt}`).catch(() => null);
|
|
if (!data) return false;
|
|
|
|
// Mode impose : pas de choix, cadre force
|
|
if (data.event_mode === 'impose' && data.event_cadre) {
|
|
cadreChoisi = data.event_cadre;
|
|
return false;
|
|
}
|
|
|
|
const tousLesGlobaux = data.disponibles || [];
|
|
const tousLesEvent = data.event_cadres || [];
|
|
if (tousLesGlobaux.length === 0 && tousLesEvent.length === 0) return false;
|
|
|
|
const grille = document.getElementById('grille-cadres-impression');
|
|
grille.innerHTML = '';
|
|
|
|
const eventCadreDefaut = (data.event_mode === 'defaut') ? data.event_cadre : null;
|
|
|
|
const divAucun = document.createElement('div');
|
|
divAucun.className = 'cadre-choix-item cadre-choix-aucun' + (!eventCadreDefaut ? ' cadre-selectionne' : '');
|
|
divAucun.innerHTML = '<div class="cadre-choix-vide"></div><span>Sans cadre</span>';
|
|
divAucun.onclick = () => {
|
|
cadreChoisi = null;
|
|
grille.querySelectorAll('.cadre-choix-item').forEach(el => el.classList.remove('cadre-selectionne'));
|
|
divAucun.classList.add('cadre-selectionne');
|
|
};
|
|
grille.appendChild(divAucun);
|
|
|
|
// Cadres evenement
|
|
for (const nom of tousLesEvent) {
|
|
const isDefaut = (nom === eventCadreDefaut);
|
|
const div = document.createElement('div');
|
|
div.className = 'cadre-choix-item' + (isDefaut ? ' cadre-selectionne' : '');
|
|
div.innerHTML = `<div class="cadre-thumb-wrap"><img src="/data/evenements/${data.event_id}/cadres/${fmt}/${nom}" alt="${nom}"></div><span>${nom.replace('.png','')}</span>`;
|
|
div.onclick = () => {
|
|
cadreChoisi = nom;
|
|
grille.querySelectorAll('.cadre-choix-item').forEach(el => el.classList.remove('cadre-selectionne'));
|
|
div.classList.add('cadre-selectionne');
|
|
};
|
|
grille.appendChild(div);
|
|
if (isDefaut) cadreChoisi = nom;
|
|
}
|
|
|
|
// Cadres globaux
|
|
for (const nom of tousLesGlobaux) {
|
|
const div = document.createElement('div');
|
|
div.className = 'cadre-choix-item';
|
|
div.innerHTML = `<div class="cadre-thumb-wrap"><img src="/assets/cadres/${fmt}/${nom}" alt="${nom}"></div><span>${nom.replace('.png','')}</span>`;
|
|
div.onclick = () => {
|
|
cadreChoisi = nom;
|
|
grille.querySelectorAll('.cadre-choix-item').forEach(el => el.classList.remove('cadre-selectionne'));
|
|
div.classList.add('cadre-selectionne');
|
|
};
|
|
grille.appendChild(div);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function changerExemplaires(delta) {
|
|
nbExemplaires = Math.max(1, Math.min(copiesMax, nbExemplaires + delta));
|
|
document.getElementById('nb-exemplaires').textContent = nbExemplaires;
|
|
}
|
|
|
|
async function lancerImpression() {
|
|
if (!photoFinale) return;
|
|
fermerImpression();
|
|
// Pour les strips, imprimer la version 2 bandes sur 10x15
|
|
const fichierImpression = photoImpression || photoFinale;
|
|
afficherStatut(`Impression de ${nbExemplaires} exemplaire(s)...`, 'succes');
|
|
const resultat = await apiPost('/api/imprimer', {
|
|
photo: fichierImpression,
|
|
copies: nbExemplaires,
|
|
cadre: cadreChoisi || undefined,
|
|
format_papier: formatImpression || undefined,
|
|
});
|
|
if (resultat.attente) {
|
|
afficherStatutEco('⏳', resultat.message || 'Votre photo sortira avec la suivante !', 'attente-eco');
|
|
} else if (resultat.jumeau && resultat.succes) {
|
|
afficherStatutEco('🎁', 'Vous recevez 2 tirages identiques — gardez-en un, offrez l\'autre !', 'jumeau-eco');
|
|
} else if (resultat.succes) {
|
|
afficherStatut(`${nbExemplaires} exemplaire(s) envoye(s) a l'imprimante !`, 'succes');
|
|
} else if (resultat.erreur === 'evenement_termine') {
|
|
afficherStatut('Evenement termine — impression indisponible', 'erreur');
|
|
} else {
|
|
afficherStatut('Erreur d\'impression', 'erreur');
|
|
}
|
|
}
|
|
|
|
async function ouvrirEmail() {
|
|
document.getElementById('form-email').classList.remove('cache');
|
|
document.getElementById('input-email').value = '';
|
|
await chargerSuggestionsEmail();
|
|
}
|
|
|
|
function fermerEmail() {
|
|
document.getElementById('form-email').classList.add('cache');
|
|
document.getElementById('input-email').value = '';
|
|
}
|
|
|
|
async function chargerSuggestionsEmail() {
|
|
const container = document.getElementById('email-suggestions');
|
|
container.innerHTML = '';
|
|
const data = await apiGet('/api/emails/historique').catch(() => null);
|
|
if (!data || !data.emails || data.emails.length === 0) return;
|
|
for (const email of data.emails) {
|
|
const btn = document.createElement('button');
|
|
btn.textContent = email;
|
|
btn.onclick = () => {
|
|
document.getElementById('input-email').value = email;
|
|
};
|
|
container.appendChild(btn);
|
|
}
|
|
}
|
|
|
|
function clavierTape(car) {
|
|
const input = document.getElementById('input-email');
|
|
input.value += car;
|
|
filtrerSuggestionsEmail();
|
|
}
|
|
|
|
function clavierEffacer() {
|
|
const input = document.getElementById('input-email');
|
|
input.value = input.value.slice(0, -1);
|
|
filtrerSuggestionsEmail();
|
|
}
|
|
|
|
function filtrerSuggestionsEmail() {
|
|
const val = document.getElementById('input-email').value.toLowerCase();
|
|
const btns = document.querySelectorAll('#email-suggestions button');
|
|
btns.forEach(btn => {
|
|
btn.style.display = (!val || btn.textContent.includes(val)) ? '' : 'none';
|
|
});
|
|
}
|
|
|
|
async function envoyerEmail() {
|
|
const email = document.getElementById('input-email').value.trim();
|
|
if (!email || !photoFinale) return;
|
|
|
|
fermerEmail();
|
|
afficherStatut('Envoi en cours...', 'succes');
|
|
const resultat = await apiPost('/api/email', { email, photo: photoFinale });
|
|
if (resultat.spool) {
|
|
afficherStatut('Vous recevrez votre photo par email dans la semaine', 'succes');
|
|
} else if (resultat.succes) {
|
|
afficherStatut('Email envoyé !', 'succes');
|
|
} else {
|
|
afficherStatut('Erreur d\'envoi email', 'erreur');
|
|
}
|
|
}
|
|
|
|
async function afficherQR() {
|
|
const booth = config.booth || {};
|
|
if (!booth.actif || !booth.url || !photoFinale) return;
|
|
try {
|
|
const info = await apiGet('/api/booth/info');
|
|
if (!info.password) return;
|
|
const eventId = (config.evenement || {}).event_id || booth.event_id || 'default';
|
|
const qrUrl = `${booth.url}/g/${eventId}/view/${photoFinale}?p=${info.password}`;
|
|
document.getElementById('qr-photo').src = `/api/qr?url=${encodeURIComponent(qrUrl)}`;
|
|
document.getElementById('popup-qr').classList.remove('cache');
|
|
} catch (e) { console.error('afficherQR error:', e); }
|
|
}
|