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>
|
||||||
|
|
||||||
<div class="printer-states">
|
<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
|
{% if p.state == 'idle' %}✅ Disponible
|
||||||
{% elif p.state == 'printing' %}🖨 En impression
|
{% elif p.state == 'printing' %}🖨 En impression
|
||||||
{% elif p.state == 'disabled' %}⏸ Désactivée
|
{% elif p.state == 'disabled' %}⏸ Désactivée
|
||||||
{% elif p.state == 'offline' %}❌ Hors ligne
|
{% elif p.state == 'offline' %}❌ Hors ligne
|
||||||
{% else %}❓ {{ p.state }}{% endif %}
|
{% else %}❓ {{ p.state }}{% endif %}
|
||||||
</span>
|
</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' }}
|
{{ '✓ Accepte les jobs' if p.accepting else '✗ Refuse les jobs' }}
|
||||||
</span>
|
</span>
|
||||||
{% if p.jobs_count %}
|
{% if p.jobs_count %}
|
||||||
@@ -151,15 +151,15 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Erreurs / raisons CUPS -->
|
<!-- Erreurs / raisons CUPS -->
|
||||||
|
<div class="printer-reasons" style="display:flex;flex-direction:column;gap:.3rem">
|
||||||
{% if p.reasons %}
|
{% if p.reasons %}
|
||||||
<div style="display:flex;flex-direction:column;gap:.3rem">
|
|
||||||
{% for reason in p.reasons %}
|
{% 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">
|
<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 }}
|
{{ reason }}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Niveaux encre/ruban -->
|
<!-- Niveaux encre/ruban -->
|
||||||
{% if p.markers %}
|
{% if p.markers %}
|
||||||
@@ -344,27 +344,76 @@ document.querySelectorAll('input[name="print-mode"]').forEach(r => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// ── Imprimantes ────────────────────────────────────────────────────────────────
|
// ── 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() {
|
async function refreshPrinters() {
|
||||||
try {
|
try {
|
||||||
const printers = await api('GET', '/api/print/printers');
|
const printers = await api('GET', '/api/print/printers');
|
||||||
printers.forEach(p => {
|
printers.forEach(p => {
|
||||||
// Met à jour les badges et compteur de jobs
|
|
||||||
const card = document.getElementById('pc-' + p.name);
|
const card = document.getElementById('pc-' + p.name);
|
||||||
if (!card) return;
|
if (!card) return;
|
||||||
|
|
||||||
|
// Classe de la carte
|
||||||
card.className = `printer-card state-${p.state}`;
|
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);
|
const jobsDiv = document.getElementById('jobs-' + p.name);
|
||||||
if (jobsDiv) {
|
if (jobsDiv) {
|
||||||
if (p.jobs && p.jobs.length) {
|
jobsDiv.innerHTML = p.jobs && p.jobs.length
|
||||||
jobsDiv.innerHTML = p.jobs.map(j => `
|
? p.jobs.map(j => `
|
||||||
<div class="cups-job-row">
|
<div class="cups-job-row">
|
||||||
<span class="cups-job-id">${j.id}</span>
|
<span class="cups-job-id">${j.id}</span>
|
||||||
<span class="cups-job-info">${j.user} — ${j.size}</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>
|
<button class="btn-xs btn-clear" style="padding:.2rem .5rem;font-size:.75rem" onclick="cancelJob('${j.id}')">✕</button>
|
||||||
</div>`).join('');
|
</div>`).join('')
|
||||||
} else {
|
: '<div class="cups-empty">Aucun job en cours</div>';
|
||||||
jobsDiv.innerHTML = '<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) {}
|
} 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;
|
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() {
|
async function saveBrightness() {
|
||||||
const val = parseInt(document.getElementById('brightness-slider').value);
|
const val = parseInt(document.getElementById('brightness-slider').value);
|
||||||
try {
|
try {
|
||||||
await api('PUT', `/api/leds/brightness?value=${val}`);
|
await api('PUT', `/api/leds/brightness?value=${val}`);
|
||||||
showToast(`✅ Luminosité réglée à ${val}`, 'success');
|
showToast(`✅ Luminosité ${val} sauvegardée`, 'success');
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
showToast('Erreur : ' + e.message, 'error');
|
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) {
|
async function setAutoBrightness(enabled) {
|
||||||
try {
|
try {
|
||||||
await api('PUT', `/api/leds/auto-brightness?enabled=${enabled}`);
|
await api('PUT', `/api/leds/auto-brightness?enabled=${enabled}`);
|
||||||
@@ -836,5 +898,6 @@ async function setAutoBrightness(enabled) {
|
|||||||
|
|
||||||
// ── Init ──────────────────────────────────────────────────────────────────────
|
// ── Init ──────────────────────────────────────────────────────────────────────
|
||||||
loadBrightnessConfig();
|
loadBrightnessConfig();
|
||||||
|
loadFlashConfig();
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user