fix: settings - add missing previewFlash/saveFlash/colorPickerToRgb/loadFlashConfig; fix previewBrightness to call API; fix printer refresh to update state badges
This commit is contained in:
@@ -128,14 +128,14 @@
|
||||
</div>
|
||||
|
||||
<div class="printer-states">
|
||||
<span class="badge-printer bs-{{ p.state }}">
|
||||
<span class="badge-printer badge-state bs-{{ p.state }}">
|
||||
{% if p.state == 'idle' %}✅ Disponible
|
||||
{% elif p.state == 'printing' %}🖨 En impression
|
||||
{% elif p.state == 'disabled' %}⏸ Désactivée
|
||||
{% elif p.state == 'offline' %}❌ Hors ligne
|
||||
{% else %}❓ {{ p.state }}{% endif %}
|
||||
</span>
|
||||
<span class="badge-printer {{ 'bs-accept' if p.accepting else 'bs-reject' }}">
|
||||
<span class="badge-printer badge-accept {{ 'bs-accept' if p.accepting else 'bs-reject' }}">
|
||||
{{ '✓ Accepte les jobs' if p.accepting else '✗ Refuse les jobs' }}
|
||||
</span>
|
||||
{% if p.jobs_count %}
|
||||
@@ -151,15 +151,15 @@
|
||||
</div>
|
||||
|
||||
<!-- Erreurs / raisons CUPS -->
|
||||
<div class="printer-reasons" style="display:flex;flex-direction:column;gap:.3rem">
|
||||
{% if p.reasons %}
|
||||
<div style="display:flex;flex-direction:column;gap:.3rem">
|
||||
{% for reason in p.reasons %}
|
||||
<div style="background:rgba(192,0,0,.12);border:1px solid rgba(192,0,0,.25);border-radius:6px;padding:.3rem .65rem;font-size:.82rem;color:#e05050">
|
||||
{{ reason }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Niveaux encre/ruban -->
|
||||
{% if p.markers %}
|
||||
@@ -344,27 +344,76 @@ document.querySelectorAll('input[name="print-mode"]').forEach(r => {
|
||||
});
|
||||
|
||||
// ── Imprimantes ────────────────────────────────────────────────────────────────
|
||||
const STATE_LABELS = {
|
||||
idle: '✅ Disponible',
|
||||
printing: '🖨 En impression',
|
||||
disabled: '⏸ Désactivée',
|
||||
offline: '❌ Hors ligne',
|
||||
error: '❌ Erreur',
|
||||
unknown: '❓ Inconnu',
|
||||
};
|
||||
const STATE_CLASSES = {
|
||||
idle: 'bs-idle', printing: 'bs-printing', disabled: 'bs-disabled',
|
||||
offline: 'bs-offline', error: 'bs-offline', unknown: 'bs-unknown',
|
||||
};
|
||||
|
||||
async function refreshPrinters() {
|
||||
try {
|
||||
const printers = await api('GET', '/api/print/printers');
|
||||
printers.forEach(p => {
|
||||
// Met à jour les badges et compteur de jobs
|
||||
const card = document.getElementById('pc-' + p.name);
|
||||
if (!card) return;
|
||||
|
||||
// Classe de la carte
|
||||
card.className = `printer-card state-${p.state}`;
|
||||
// Actualise les jobs CUPS
|
||||
|
||||
// Badge état
|
||||
const stateBadge = card.querySelector('.badge-state');
|
||||
if (stateBadge) {
|
||||
stateBadge.className = `badge-printer badge-state ${STATE_CLASSES[p.state] || 'bs-unknown'}`;
|
||||
stateBadge.textContent = STATE_LABELS[p.state] || p.state;
|
||||
}
|
||||
|
||||
// Badge accepting
|
||||
const acceptBadge = card.querySelector('.badge-accept');
|
||||
if (acceptBadge) {
|
||||
acceptBadge.className = `badge-printer badge-accept ${p.accepting ? 'bs-accept' : 'bs-reject'}`;
|
||||
acceptBadge.textContent = p.accepting ? '✓ Accepte les jobs' : '✗ Refuse les jobs';
|
||||
}
|
||||
|
||||
// Boutons actions
|
||||
const actionsDiv = card.querySelector('.printer-actions');
|
||||
if (actionsDiv) {
|
||||
actionsDiv.innerHTML = `
|
||||
${p.state === 'disabled'
|
||||
? `<button class="btn-xs btn-enable" onclick="printerAction('${p.name}','enable')">▶ Activer</button>`
|
||||
: `<button class="btn-xs btn-disable" onclick="printerAction('${p.name}','disable')">⏸ Désactiver</button>`}
|
||||
${p.accepting
|
||||
? `<button class="btn-xs btn-reject" onclick="printerAction('${p.name}','reject')">🚫 Refuser jobs</button>`
|
||||
: `<button class="btn-xs btn-enable" onclick="printerAction('${p.name}','enable')">✓ Accepter jobs</button>`}
|
||||
${p.jobs_count ? `<button class="btn-xs btn-clear" onclick="clearJobs('${p.name}')">✕ Vider file</button>` : ''}
|
||||
`;
|
||||
}
|
||||
|
||||
// Jobs CUPS
|
||||
const jobsDiv = document.getElementById('jobs-' + p.name);
|
||||
if (jobsDiv) {
|
||||
if (p.jobs && p.jobs.length) {
|
||||
jobsDiv.innerHTML = p.jobs.map(j => `
|
||||
<div class="cups-job-row">
|
||||
<span class="cups-job-id">${j.id}</span>
|
||||
<span class="cups-job-info">${j.user} — ${j.size}</span>
|
||||
<button class="btn-xs btn-clear" style="padding:.2rem .5rem;font-size:.75rem" onclick="cancelJob('${j.id}')">✕</button>
|
||||
</div>`).join('');
|
||||
} else {
|
||||
jobsDiv.innerHTML = '<div class="cups-empty">Aucun job en cours</div>';
|
||||
}
|
||||
jobsDiv.innerHTML = p.jobs && p.jobs.length
|
||||
? p.jobs.map(j => `
|
||||
<div class="cups-job-row">
|
||||
<span class="cups-job-id">${j.id}</span>
|
||||
<span class="cups-job-info">${j.user} — ${j.size}</span>
|
||||
<button class="btn-xs btn-clear" style="padding:.2rem .5rem;font-size:.75rem" onclick="cancelJob('${j.id}')">✕</button>
|
||||
</div>`).join('')
|
||||
: '<div class="cups-empty">Aucun job en cours</div>';
|
||||
}
|
||||
|
||||
// Erreurs/raisons
|
||||
const reasonsDiv = card.querySelector('.printer-reasons');
|
||||
if (reasonsDiv) {
|
||||
reasonsDiv.innerHTML = p.reasons && p.reasons.length
|
||||
? p.reasons.map(r => `<div style="background:rgba(192,0,0,.12);border:1px solid rgba(192,0,0,.25);border-radius:6px;padding:.3rem .65rem;font-size:.82rem;color:#e05050">${r}</div>`).join('')
|
||||
: '';
|
||||
}
|
||||
});
|
||||
} catch(err) {}
|
||||
|
||||
@@ -807,20 +807,82 @@ async function loadBrightnessConfig() {
|
||||
}
|
||||
}
|
||||
|
||||
function previewBrightness(val) {
|
||||
async function previewBrightness() {
|
||||
const val = parseInt(document.getElementById('brightness-slider').value);
|
||||
document.getElementById('brightness-val').textContent = val;
|
||||
try {
|
||||
await api('PUT', `/api/leds/brightness?value=${val}&save=false`);
|
||||
showToast(`👁 Aperçu luminosité : ${val}`, 'info');
|
||||
} catch(e) {
|
||||
showToast('Erreur aperçu : ' + e.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async function saveBrightness() {
|
||||
const val = parseInt(document.getElementById('brightness-slider').value);
|
||||
try {
|
||||
await api('PUT', `/api/leds/brightness?value=${val}`);
|
||||
showToast(`✅ Luminosité réglée à ${val}`, 'success');
|
||||
showToast(`✅ Luminosité ${val} sauvegardée`, 'success');
|
||||
} catch(e) {
|
||||
showToast('Erreur : ' + e.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async function previewFlash() {
|
||||
try {
|
||||
await api('POST', '/api/leds/effect?effect=capture');
|
||||
showToast('💡 Flash déclenché', 'info');
|
||||
} catch(e) {
|
||||
showToast('Erreur flash : ' + e.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async function saveFlash() {
|
||||
const r = parseInt(document.getElementById('flash-r').value) || 255;
|
||||
const g = parseInt(document.getElementById('flash-g').value) || 200;
|
||||
const b = parseInt(document.getElementById('flash-b').value) || 80;
|
||||
const duration = parseFloat(document.getElementById('flash-duration').value) || 0.3;
|
||||
const flashes = parseInt(document.getElementById('flash-count').value) || 2;
|
||||
try {
|
||||
await api('PUT', `/api/leds/effect/capture?r=${r}&g=${g}&b=${b}&flash_duration=${duration}&flashes=${flashes}`);
|
||||
showToast('✅ Flash sauvegardé', 'success');
|
||||
} catch(e) {
|
||||
showToast('Erreur : ' + e.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
function colorPickerToRgb(hex) {
|
||||
const r = parseInt(hex.slice(1,3), 16);
|
||||
const g = parseInt(hex.slice(3,5), 16);
|
||||
const b = parseInt(hex.slice(5,7), 16);
|
||||
document.getElementById('flash-r').value = r;
|
||||
document.getElementById('flash-g').value = g;
|
||||
document.getElementById('flash-b').value = b;
|
||||
document.getElementById('flash-preview').style.background = `rgb(${r},${g},${b})`;
|
||||
}
|
||||
|
||||
async function loadFlashConfig() {
|
||||
try {
|
||||
const effects = await api('GET', '/api/leds/effects');
|
||||
const cap = effects.capture;
|
||||
if (!cap) return;
|
||||
if (cap.color) {
|
||||
document.getElementById('flash-r').value = cap.color[0] ?? 255;
|
||||
document.getElementById('flash-g').value = cap.color[1] ?? 200;
|
||||
document.getElementById('flash-b').value = cap.color[2] ?? 80;
|
||||
document.getElementById('flash-preview').style.background =
|
||||
`rgb(${cap.color[0]},${cap.color[1]},${cap.color[2]})`;
|
||||
}
|
||||
if (cap.flash_duration !== undefined) {
|
||||
document.getElementById('flash-duration').value = cap.flash_duration;
|
||||
document.getElementById('flash-dur-val').textContent = cap.flash_duration.toFixed(2);
|
||||
}
|
||||
if (cap.flashes !== undefined) {
|
||||
document.getElementById('flash-count').value = cap.flashes;
|
||||
}
|
||||
} catch(e) { console.warn('loadFlashConfig:', e); }
|
||||
}
|
||||
|
||||
async function setAutoBrightness(enabled) {
|
||||
try {
|
||||
await api('PUT', `/api/leds/auto-brightness?enabled=${enabled}`);
|
||||
@@ -836,5 +898,6 @@ async function setAutoBrightness(enabled) {
|
||||
|
||||
// ── Init ──────────────────────────────────────────────────────────────────────
|
||||
loadBrightnessConfig();
|
||||
loadFlashConfig();
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user