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

@@ -3,12 +3,15 @@
{% block title %}Finish Good Scan{% endblock %}
{% block head %}
<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>
.error-message {
color: #ff4444;
font-size: 0.9em;
margin-top: 5px;
display: none;
grid-column: 2 / -1;
}
.error-message.show {
display: block;
@@ -275,6 +278,11 @@ document.addEventListener('DOMContentLoaded', function() {
} else {
operatorErrorMessage.classList.remove('show');
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 {
cpErrorMessage.classList.remove('show');
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 {
oc1ErrorMessage.classList.remove('show');
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 {
oc2ErrorMessage.classList.remove('show');
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);
// 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') {
console.log('Auto-submit: Scan-to-boxes enabled, calling submitScanWithBoxAssignment');
submitScanWithBoxAssignment();
@@ -647,6 +676,15 @@ document.addEventListener('DOMContentLoaded', function() {
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>
@@ -656,6 +694,10 @@ document.addEventListener('DOMContentLoaded', function() {
// Quick box creation button
document.getElementById('quick-box-create-btn').addEventListener('click', async function() {
try {
this.disabled = true;
this.textContent = 'Creating...';
// Step 1: Create box in database
const createResponse = await fetch('/warehouse/manage_boxes', {
method: 'POST',
headers: {
@@ -670,14 +712,56 @@ document.addEventListener('DOMContentLoaded', function() {
const result = await createResponse.json();
if (result.success && result.box_number) {
await assignCpToBox(result.box_number);
showNotification(`✅ Box ${result.box_number} created and CP assigned!`, 'success');
closeBoxModal();
const boxNumber = result.box_number;
// 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 {
throw new Error(result.error || 'Failed to create box');
}
} catch (error) {
showNotification('❌ Error creating box: ' + error.message, 'error');
} finally {
// Re-enable button
this.disabled = false;
this.textContent = 'Quick Box Label Creation';
}
});