Improve FG scan page UX and integrate scan-to-boxes with QZ Tray printing

- Redesigned scan card layout: 500px width with horizontal label-input layout
- Reduced spacing and optimized for no scrolling (700px max-height)
- Added auto-advance between fields when valid data is entered
- Integrated scan-to-boxes popup with warehouse box assignment
- Added QZ Tray printing to Quick Box Creation button
- Box labels now print automatically after creation in scan workflow
- Fixed warehouse blueprint URL prefix registration (/warehouse)
- Updated manage_boxes to return JSON for AJAX requests
- Improved error message grid layout to maintain form alignment
This commit is contained in:
ske087
2025-12-18 21:53:56 +02:00
parent e6193511e0
commit 3d5e468a28
2 changed files with 114 additions and 12 deletions

View File

@@ -1,30 +1,48 @@
/* Scan Module Specific Styles */ /* Scan Module Specific Styles */
.scan-form-card { .scan-form-card {
width: 380px; width: 500px;
max-width: 380px; max-width: 500px;
margin: 0 auto 20px auto; margin: 0 auto 20px auto;
max-height: 660px; max-height: 700px;
overflow-y: auto; overflow-y: auto;
padding: 18px 18px 12px 18px; padding: 12px 18px 12px 18px;
}
.scan-form-card h3 {
margin-top: 0;
margin-bottom: 8px;
} }
.scan-form-card form { .scan-form-card form {
display: flex; display: grid;
flex-direction: column; grid-template-columns: 140px 1fr;
gap: 4px; gap: 8px;
align-items: center;
} }
.scan-form-card label { .scan-form-card label {
font-weight: 500; font-weight: 500;
margin-bottom: 1px; margin-bottom: 0;
margin-top: 0;
font-size: 13px; font-size: 13px;
text-align: left;
padding-right: 8px;
} }
.scan-form-card input[type="text"] { .scan-form-card input[type="text"] {
padding: 5px 10px; padding: 5px 10px;
font-size: 13px; font-size: 13px;
margin-bottom: 2px; margin-bottom: 0;
}
.scan-form-card button[type="submit"],
.scan-form-card button[type="button"] {
grid-column: 1 / -1;
}
.scan-form-card > form > div {
grid-column: 1 / -1;
} }
.scan-table-card { .scan-table-card {

View File

@@ -3,12 +3,15 @@
{% block title %}Finish Good Scan{% endblock %} {% block title %}Finish Good Scan{% endblock %}
{% block head %} {% block head %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/scan.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='css/scan.css') }}">
<!-- QZ Tray for printing -->
<script src="https://cdn.jsdelivr.net/npm/qz-tray@2.2.0/qz-tray.min.js"></script>
<style> <style>
.error-message { .error-message {
color: #ff4444; color: #ff4444;
font-size: 0.9em; font-size: 0.9em;
margin-top: 5px; margin-top: 5px;
display: none; display: none;
grid-column: 2 / -1;
} }
.error-message.show { .error-message.show {
display: block; display: block;
@@ -275,6 +278,11 @@ document.addEventListener('DOMContentLoaded', function() {
} else { } else {
operatorErrorMessage.classList.remove('show'); operatorErrorMessage.classList.remove('show');
this.setCustomValidity(''); this.setCustomValidity('');
// Auto-advance when field is complete and valid
if (value.length === 4 && value.startsWith('OP')) {
cpCodeInput.focus();
}
} }
}); });
@@ -312,6 +320,11 @@ document.addEventListener('DOMContentLoaded', function() {
} else { } else {
cpErrorMessage.classList.remove('show'); cpErrorMessage.classList.remove('show');
this.setCustomValidity(''); this.setCustomValidity('');
// Auto-advance when field is complete and valid
if (value.length === 15 && value.startsWith('CP')) {
oc1CodeInput.focus();
}
} }
}); });
@@ -369,6 +382,11 @@ document.addEventListener('DOMContentLoaded', function() {
} else { } else {
oc1ErrorMessage.classList.remove('show'); oc1ErrorMessage.classList.remove('show');
this.setCustomValidity(''); this.setCustomValidity('');
// Auto-advance when field is complete and valid
if (value.length === 4 && value.startsWith('OC')) {
oc2CodeInput.focus();
}
} }
}); });
@@ -423,6 +441,11 @@ document.addEventListener('DOMContentLoaded', function() {
} else { } else {
oc2ErrorMessage.classList.remove('show'); oc2ErrorMessage.classList.remove('show');
this.setCustomValidity(''); this.setCustomValidity('');
// Auto-advance when field is complete and valid
if (value.length === 4 && value.startsWith('OC')) {
defectCodeInput.focus();
}
} }
}); });
@@ -550,6 +573,12 @@ document.addEventListener('DOMContentLoaded', function() {
localStorage.setItem('fg_scan_last_defect', defectCodeInput.value); localStorage.setItem('fg_scan_last_defect', defectCodeInput.value);
// Check if scan-to-boxes is enabled and defect code is 000 // Check if scan-to-boxes is enabled and defect code is 000
console.log('Auto-submit check:', {
scanToBoxesEnabled: scanToBoxesEnabled,
defectCode: this.value,
shouldShowModal: scanToBoxesEnabled && this.value === '000'
});
if (scanToBoxesEnabled && this.value === '000') { if (scanToBoxesEnabled && this.value === '000') {
console.log('Auto-submit: Scan-to-boxes enabled, calling submitScanWithBoxAssignment'); console.log('Auto-submit: Scan-to-boxes enabled, calling submitScanWithBoxAssignment');
submitScanWithBoxAssignment(); submitScanWithBoxAssignment();
@@ -647,6 +676,15 @@ document.addEventListener('DOMContentLoaded', function() {
alert('✅ Saved Quality Operator code cleared! Please re-enter your operator code.'); alert('✅ Saved Quality Operator code cleared! Please re-enter your operator code.');
} }
}); });
// Initialize QZ Tray for printing box labels
if (window.qz) {
window.qz.websocket.connect().then(() => {
console.log('QZ Tray connected for box label printing');
}).catch(err => {
console.warn('QZ Tray not available:', err);
});
}
}); });
</script> </script>
@@ -656,6 +694,10 @@ document.addEventListener('DOMContentLoaded', function() {
// Quick box creation button // Quick box creation button
document.getElementById('quick-box-create-btn').addEventListener('click', async function() { document.getElementById('quick-box-create-btn').addEventListener('click', async function() {
try { try {
this.disabled = true;
this.textContent = 'Creating...';
// Step 1: Create box in database
const createResponse = await fetch('/warehouse/manage_boxes', { const createResponse = await fetch('/warehouse/manage_boxes', {
method: 'POST', method: 'POST',
headers: { headers: {
@@ -670,14 +712,56 @@ document.addEventListener('DOMContentLoaded', function() {
const result = await createResponse.json(); const result = await createResponse.json();
if (result.success && result.box_number) { if (result.success && result.box_number) {
await assignCpToBox(result.box_number); const boxNumber = result.box_number;
showNotification(`✅ Box ${result.box_number} created and CP assigned!`, 'success');
closeBoxModal(); // Step 2: Print the box label using QZ Tray
try {
// Check QZ Tray connection
if (!window.qz || !window.qz.websocket.isActive()) {
throw new Error('QZ Tray not connected. Please ensure QZ Tray is running.');
}
// Get available printers
const printers = await window.qz.printers.find();
if (printers.length === 0) {
throw new Error('No printers found');
}
// Use first available printer
const printer = printers[0];
// Create ZPL code for box label
const zpl = `^XA
^FO50,50^A0N,40,40^FDBox: ${boxNumber}^FS
^FO50,120^BY2,3,80^BCN,80,Y,N,N^FD${boxNumber}^FS
^XZ`;
const config = window.qz.configs.create(printer);
await window.qz.print(config, [zpl]);
showNotification(`✅ Box ${boxNumber} created and label printed!`, 'success');
// Step 3: Keep modal open and focus on scan input
document.getElementById('scan-box-input').value = '';
document.getElementById('scan-box-input').focus();
document.getElementById('scan-box-input').placeholder = 'Scan the printed label now...';
} catch (printError) {
console.error('Print error:', printError);
showNotification(`⚠️ Box ${boxNumber} created but print failed: ${printError.message}`, 'warning');
// Still keep modal open for manual entry
document.getElementById('scan-box-input').focus();
}
} else { } else {
throw new Error(result.error || 'Failed to create box'); throw new Error(result.error || 'Failed to create box');
} }
} catch (error) { } catch (error) {
showNotification('❌ Error creating box: ' + error.message, 'error'); showNotification('❌ Error creating box: ' + error.message, 'error');
} finally {
// Re-enable button
this.disabled = false;
this.textContent = 'Quick Box Label Creation';
} }
}); });