updated validation and auto submit
This commit is contained in:
473
py_app/app/templates/fg_scan.html
Normal file
473
py_app/app/templates/fg_scan.html
Normal file
@@ -0,0 +1,473 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Finish Good Scan{% endblock %}
|
||||
{% block head %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/scan.css') }}">
|
||||
<style>
|
||||
.error-message {
|
||||
color: #ff4444;
|
||||
font-size: 0.9em;
|
||||
margin-top: 5px;
|
||||
display: none;
|
||||
}
|
||||
.error-message.show {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const operatorCodeInput = document.getElementById('operator_code');
|
||||
const cpCodeInput = document.getElementById('cp_code');
|
||||
const oc1CodeInput = document.getElementById('oc1_code');
|
||||
const oc2CodeInput = document.getElementById('oc2_code');
|
||||
const defectCodeInput = document.getElementById('defect_code');
|
||||
const form = document.getElementById('fg-scan-form');
|
||||
|
||||
// Create error message element for operator code
|
||||
const operatorErrorMessage = document.createElement('div');
|
||||
operatorErrorMessage.className = 'error-message';
|
||||
operatorErrorMessage.id = 'operator-error';
|
||||
operatorErrorMessage.textContent = 'Please scan Quality Operator code (must start with OP)';
|
||||
operatorCodeInput.parentNode.insertBefore(operatorErrorMessage, operatorCodeInput.nextSibling);
|
||||
|
||||
// Create error message element for CP code
|
||||
const cpErrorMessage = document.createElement('div');
|
||||
cpErrorMessage.className = 'error-message';
|
||||
cpErrorMessage.id = 'cp-error';
|
||||
cpErrorMessage.textContent = 'Please scan a valid CP';
|
||||
cpCodeInput.parentNode.insertBefore(cpErrorMessage, cpCodeInput.nextSibling);
|
||||
|
||||
// Create error message element for OC1 code
|
||||
const oc1ErrorMessage = document.createElement('div');
|
||||
oc1ErrorMessage.className = 'error-message';
|
||||
oc1ErrorMessage.id = 'oc1-error';
|
||||
oc1ErrorMessage.textContent = 'Please scan a valid OC (must start with OC)';
|
||||
oc1CodeInput.parentNode.insertBefore(oc1ErrorMessage, oc1CodeInput.nextSibling);
|
||||
|
||||
// Create error message element for OC2 code
|
||||
const oc2ErrorMessage = document.createElement('div');
|
||||
oc2ErrorMessage.className = 'error-message';
|
||||
oc2ErrorMessage.id = 'oc2-error';
|
||||
oc2ErrorMessage.textContent = 'Please scan a valid OC (must start with OC)';
|
||||
oc2CodeInput.parentNode.insertBefore(oc2ErrorMessage, oc2CodeInput.nextSibling);
|
||||
|
||||
// Create error message element for defect code
|
||||
const defectErrorMessage = document.createElement('div');
|
||||
defectErrorMessage.className = 'error-message';
|
||||
defectErrorMessage.id = 'defect-error';
|
||||
defectErrorMessage.textContent = 'Defect code must be a 3-digit number (e.g., 000, 001, 123)';
|
||||
defectCodeInput.parentNode.insertBefore(defectErrorMessage, defectCodeInput.nextSibling);
|
||||
|
||||
// Validate operator code on input
|
||||
operatorCodeInput.addEventListener('input', function() {
|
||||
const value = this.value.toUpperCase();
|
||||
this.value = value; // Convert to uppercase
|
||||
|
||||
if (value.length >= 2 && !value.startsWith('OP')) {
|
||||
operatorErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must start with OP');
|
||||
} else {
|
||||
operatorErrorMessage.classList.remove('show');
|
||||
this.setCustomValidity('');
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent leaving operator code field if invalid
|
||||
operatorCodeInput.addEventListener('blur', function(e) {
|
||||
if (this.value.length > 0 && !this.value.startsWith('OP')) {
|
||||
operatorErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must start with OP');
|
||||
// Return focus to this field
|
||||
setTimeout(() => {
|
||||
this.focus();
|
||||
this.select();
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent Tab/Enter from moving to next field if operator code is invalid
|
||||
operatorCodeInput.addEventListener('keydown', function(e) {
|
||||
if ((e.key === 'Tab' || e.key === 'Enter') && this.value.length > 0 && !this.value.startsWith('OP')) {
|
||||
e.preventDefault();
|
||||
operatorErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must start with OP');
|
||||
this.select();
|
||||
}
|
||||
});
|
||||
|
||||
// Validate CP code on input
|
||||
cpCodeInput.addEventListener('input', function() {
|
||||
const value = this.value.toUpperCase();
|
||||
this.value = value; // Convert to uppercase
|
||||
|
||||
if (value.length >= 2 && !value.startsWith('CP')) {
|
||||
cpErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must start with CP');
|
||||
} else {
|
||||
cpErrorMessage.classList.remove('show');
|
||||
this.setCustomValidity('');
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent leaving CP code field if invalid
|
||||
cpCodeInput.addEventListener('blur', function(e) {
|
||||
if (this.value.length > 0 && !this.value.startsWith('CP')) {
|
||||
cpErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must start with CP');
|
||||
// Return focus to this field
|
||||
setTimeout(() => {
|
||||
this.focus();
|
||||
this.select();
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent Tab/Enter from moving to next field if CP code is invalid
|
||||
cpCodeInput.addEventListener('keydown', function(e) {
|
||||
if ((e.key === 'Tab' || e.key === 'Enter') && this.value.length > 0 && !this.value.startsWith('CP')) {
|
||||
e.preventDefault();
|
||||
cpErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must start with CP');
|
||||
this.select();
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent focusing on CP code if operator code is invalid
|
||||
cpCodeInput.addEventListener('focus', function(e) {
|
||||
if (operatorCodeInput.value.length > 0 && !operatorCodeInput.value.startsWith('OP')) {
|
||||
e.preventDefault();
|
||||
operatorErrorMessage.classList.add('show');
|
||||
operatorCodeInput.focus();
|
||||
operatorCodeInput.select();
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent focusing on OC1 code if CP code is invalid
|
||||
oc1CodeInput.addEventListener('focus', function(e) {
|
||||
if (cpCodeInput.value.length > 0 && !cpCodeInput.value.startsWith('CP')) {
|
||||
e.preventDefault();
|
||||
cpErrorMessage.classList.add('show');
|
||||
cpCodeInput.focus();
|
||||
cpCodeInput.select();
|
||||
}
|
||||
});
|
||||
|
||||
// Validate OC1 code on input
|
||||
oc1CodeInput.addEventListener('input', function() {
|
||||
const value = this.value.toUpperCase();
|
||||
this.value = value; // Convert to uppercase
|
||||
|
||||
if (value.length >= 2 && !value.startsWith('OC')) {
|
||||
oc1ErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must start with OC');
|
||||
} else {
|
||||
oc1ErrorMessage.classList.remove('show');
|
||||
this.setCustomValidity('');
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent leaving OC1 code field if invalid
|
||||
oc1CodeInput.addEventListener('blur', function(e) {
|
||||
if (this.value.length > 0 && !this.value.startsWith('OC')) {
|
||||
oc1ErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must start with OC');
|
||||
// Return focus to this field
|
||||
setTimeout(() => {
|
||||
this.focus();
|
||||
this.select();
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent Tab/Enter from moving to next field if OC1 code is invalid
|
||||
oc1CodeInput.addEventListener('keydown', function(e) {
|
||||
if ((e.key === 'Tab' || e.key === 'Enter') && this.value.length > 0 && !this.value.startsWith('OC')) {
|
||||
e.preventDefault();
|
||||
oc1ErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must start with OC');
|
||||
this.select();
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent focusing on OC2 code if CP code is invalid
|
||||
oc2CodeInput.addEventListener('focus', function(e) {
|
||||
if (cpCodeInput.value.length > 0 && !cpCodeInput.value.startsWith('CP')) {
|
||||
e.preventDefault();
|
||||
cpErrorMessage.classList.add('show');
|
||||
cpCodeInput.focus();
|
||||
cpCodeInput.select();
|
||||
}
|
||||
// Also check if OC1 is invalid
|
||||
if (oc1CodeInput.value.length > 0 && !oc1CodeInput.value.startsWith('OC')) {
|
||||
e.preventDefault();
|
||||
oc1ErrorMessage.classList.add('show');
|
||||
oc1CodeInput.focus();
|
||||
oc1CodeInput.select();
|
||||
}
|
||||
});
|
||||
|
||||
// Validate OC2 code on input
|
||||
oc2CodeInput.addEventListener('input', function() {
|
||||
const value = this.value.toUpperCase();
|
||||
this.value = value; // Convert to uppercase
|
||||
|
||||
if (value.length >= 2 && !value.startsWith('OC')) {
|
||||
oc2ErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must start with OC');
|
||||
} else {
|
||||
oc2ErrorMessage.classList.remove('show');
|
||||
this.setCustomValidity('');
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent leaving OC2 code field if invalid
|
||||
oc2CodeInput.addEventListener('blur', function(e) {
|
||||
if (this.value.length > 0 && !this.value.startsWith('OC')) {
|
||||
oc2ErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must start with OC');
|
||||
// Return focus to this field
|
||||
setTimeout(() => {
|
||||
this.focus();
|
||||
this.select();
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent Tab/Enter from moving to next field if OC2 code is invalid
|
||||
oc2CodeInput.addEventListener('keydown', function(e) {
|
||||
if ((e.key === 'Tab' || e.key === 'Enter') && this.value.length > 0 && !this.value.startsWith('OC')) {
|
||||
e.preventDefault();
|
||||
oc2ErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must start with OC');
|
||||
this.select();
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent focusing on defect code if CP code is invalid
|
||||
defectCodeInput.addEventListener('focus', function(e) {
|
||||
if (cpCodeInput.value.length > 0 && !cpCodeInput.value.startsWith('CP')) {
|
||||
e.preventDefault();
|
||||
cpErrorMessage.classList.add('show');
|
||||
cpCodeInput.focus();
|
||||
cpCodeInput.select();
|
||||
}
|
||||
// Also check if OC1 is invalid
|
||||
if (oc1CodeInput.value.length > 0 && !oc1CodeInput.value.startsWith('OC')) {
|
||||
e.preventDefault();
|
||||
oc1ErrorMessage.classList.add('show');
|
||||
oc1CodeInput.focus();
|
||||
oc1CodeInput.select();
|
||||
}
|
||||
// Also check if OC2 is invalid
|
||||
if (oc2CodeInput.value.length > 0 && !oc2CodeInput.value.startsWith('OC')) {
|
||||
e.preventDefault();
|
||||
oc2ErrorMessage.classList.add('show');
|
||||
oc2CodeInput.focus();
|
||||
oc2CodeInput.select();
|
||||
}
|
||||
});
|
||||
|
||||
// Validate defect code on input - only allow digits
|
||||
defectCodeInput.addEventListener('input', function() {
|
||||
// Remove any non-digit characters
|
||||
this.value = this.value.replace(/\D/g, '');
|
||||
|
||||
// Validate if it's a valid 3-digit number when length is 3
|
||||
if (this.value.length === 3) {
|
||||
const isValid = /^\d{3}$/.test(this.value);
|
||||
if (!isValid) {
|
||||
defectErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must be a 3-digit number');
|
||||
} else {
|
||||
defectErrorMessage.classList.remove('show');
|
||||
this.setCustomValidity('');
|
||||
}
|
||||
} else {
|
||||
defectErrorMessage.classList.remove('show');
|
||||
this.setCustomValidity('');
|
||||
}
|
||||
|
||||
// Auto-submit when 3 characters are entered and all validations pass
|
||||
if (this.value.length === 3) {
|
||||
// Validate operator code before submitting
|
||||
if (!operatorCodeInput.value.startsWith('OP')) {
|
||||
operatorErrorMessage.classList.add('show');
|
||||
operatorCodeInput.focus();
|
||||
operatorCodeInput.setCustomValidity('Must start with OP');
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate CP code before submitting
|
||||
if (!cpCodeInput.value.startsWith('CP')) {
|
||||
cpErrorMessage.classList.add('show');
|
||||
cpCodeInput.focus();
|
||||
cpCodeInput.setCustomValidity('Must start with CP');
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate OC1 code before submitting
|
||||
if (!oc1CodeInput.value.startsWith('OC')) {
|
||||
oc1ErrorMessage.classList.add('show');
|
||||
oc1CodeInput.focus();
|
||||
oc1CodeInput.setCustomValidity('Must start with OC');
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate OC2 code before submitting
|
||||
if (!oc2CodeInput.value.startsWith('OC')) {
|
||||
oc2ErrorMessage.classList.add('show');
|
||||
oc2CodeInput.focus();
|
||||
oc2CodeInput.setCustomValidity('Must start with OC');
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate defect code is a valid 3-digit number
|
||||
const isValidDefectCode = /^\d{3}$/.test(this.value);
|
||||
if (!isValidDefectCode) {
|
||||
defectErrorMessage.classList.add('show');
|
||||
this.focus();
|
||||
this.setCustomValidity('Must be a 3-digit number');
|
||||
return;
|
||||
}
|
||||
|
||||
// Update time field before submitting
|
||||
const timeInput = document.getElementById('time');
|
||||
const now = new Date();
|
||||
const hours = String(now.getHours()).padStart(2, '0');
|
||||
const minutes = String(now.getMinutes()).padStart(2, '0');
|
||||
const seconds = String(now.getSeconds()).padStart(2, '0');
|
||||
timeInput.value = `${hours}:${minutes}:${seconds}`;
|
||||
|
||||
// Submit the form
|
||||
form.submit();
|
||||
}
|
||||
});
|
||||
|
||||
// Validate form on submit
|
||||
form.addEventListener('submit', function(e) {
|
||||
let hasError = false;
|
||||
|
||||
if (!operatorCodeInput.value.startsWith('OP')) {
|
||||
e.preventDefault();
|
||||
operatorErrorMessage.classList.add('show');
|
||||
operatorCodeInput.setCustomValidity('Must start with OP');
|
||||
if (!hasError) {
|
||||
operatorCodeInput.focus();
|
||||
hasError = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cpCodeInput.value.startsWith('CP')) {
|
||||
e.preventDefault();
|
||||
cpErrorMessage.classList.add('show');
|
||||
cpCodeInput.setCustomValidity('Must start with CP');
|
||||
if (!hasError) {
|
||||
cpCodeInput.focus();
|
||||
hasError = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!oc1CodeInput.value.startsWith('OC')) {
|
||||
e.preventDefault();
|
||||
oc1ErrorMessage.classList.add('show');
|
||||
oc1CodeInput.setCustomValidity('Must start with OC');
|
||||
if (!hasError) {
|
||||
oc1CodeInput.focus();
|
||||
hasError = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!oc2CodeInput.value.startsWith('OC')) {
|
||||
e.preventDefault();
|
||||
oc2ErrorMessage.classList.add('show');
|
||||
oc2CodeInput.setCustomValidity('Must start with OC');
|
||||
if (!hasError) {
|
||||
oc2CodeInput.focus();
|
||||
hasError = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate defect code is a 3-digit number
|
||||
const isValidDefectCode = /^\d{3}$/.test(defectCodeInput.value);
|
||||
if (!isValidDefectCode) {
|
||||
e.preventDefault();
|
||||
defectErrorMessage.classList.add('show');
|
||||
defectCodeInput.setCustomValidity('Must be a 3-digit number');
|
||||
if (!hasError) {
|
||||
defectCodeInput.focus();
|
||||
hasError = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="scan-container">
|
||||
<!-- Input Form Card -->
|
||||
<div class="card scan-form-card">
|
||||
<h3>Scan Input</h3>
|
||||
<form method="POST" class="form-centered" id="fg-scan-form">
|
||||
<label for="operator_code">Quality Operator Code:</label>
|
||||
<input type="text" id="operator_code" name="operator_code" maxlength="4" required>
|
||||
|
||||
<label for="cp_code">CP Code:</label>
|
||||
<input type="text" id="cp_code" name="cp_code" maxlength="15" required>
|
||||
|
||||
<label for="oc1_code">OC1 Code:</label>
|
||||
<input type="text" id="oc1_code" name="oc1_code" maxlength="4" required>
|
||||
|
||||
<label for="oc2_code">OC2 Code:</label>
|
||||
<input type="text" id="oc2_code" name="oc2_code" maxlength="4" required>
|
||||
|
||||
<label for="defect_code">Defect Code:</label>
|
||||
<input type="text" id="defect_code" name="defect_code" maxlength="4" required>
|
||||
|
||||
<label for="date">Date:</label>
|
||||
<input type="text" id="date" name="date" value="{{ now().strftime('%Y-%m-%d') }}" placeholder="yyyy-mm-dd" pattern="\d{4}-\d{2}-\d{2}" required>
|
||||
|
||||
<label for="time">Time:</label>
|
||||
<input type="text" id="time" name="time" value="{{ now().strftime('%H:%M:%S') }}" readonly>
|
||||
|
||||
<button type="submit" class="btn">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Latest Scans Card -->
|
||||
<div class="card scan-table-card">
|
||||
<h3>Latest Scans</h3>
|
||||
<table class="scan-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Op Code</th>
|
||||
<th>CP Code</th>
|
||||
<th>OC1 Code</th>
|
||||
<th>OC2 Code</th>
|
||||
<th>Defect Code</th>
|
||||
<th>Date</th>
|
||||
<th>Time</th>
|
||||
<th>Apr. Quantity</th>
|
||||
<th>Rejec. Quantity</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for row in scan_data %}
|
||||
<tr>
|
||||
<td>{{ row[0] }}</td> <!-- Id -->
|
||||
<td>{{ row[1] }}</td> <!-- operator_code -->
|
||||
<td>{{ row[2] }}</td> <!-- CP_full_code -->
|
||||
<td>{{ row[3] }}</td> <!-- OC1_code -->
|
||||
<td>{{ row[4] }}</td> <!-- OC2_code -->
|
||||
<td>{{ row[5] }}</td> <!-- quality_code -->
|
||||
<td>{{ row[6] }}</td> <!-- date -->
|
||||
<td>{{ row[7] }}</td> <!-- time -->
|
||||
<td>{{ row[8] }}</td> <!-- approved quantity -->
|
||||
<td>{{ row[9] }}</td> <!-- rejected quantity -->
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="dashboard-card">
|
||||
<h3>Finish goods scanning</h3>
|
||||
<p>Access the scanning module for production orders.</p>
|
||||
<a href="{{ url_for('main.scan') }}" class="btn">Finish goods scanning</a>
|
||||
<a href="{{ url_for('main.fg_scan') }}" class="btn">Finish goods scan</a>
|
||||
</div>
|
||||
<!-- Card 2: View Scan History -->
|
||||
<div class="dashboard-card">
|
||||
|
||||
@@ -2,6 +2,400 @@
|
||||
{% block title %}Scan Module{% endblock %}
|
||||
{% block head %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/scan.css') }}">
|
||||
<style>
|
||||
.error-message {
|
||||
color: #ff4444;
|
||||
font-size: 0.9em;
|
||||
margin-top: 5px;
|
||||
display: none;
|
||||
}
|
||||
.error-message.show {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const operatorCodeInput = document.getElementById('operator_code');
|
||||
const cpCodeInput = document.getElementById('cp_code');
|
||||
const oc1CodeInput = document.getElementById('oc1_code');
|
||||
const oc2CodeInput = document.getElementById('oc2_code');
|
||||
const defectCodeInput = document.getElementById('defect_code');
|
||||
const form = document.querySelector('.form-centered');
|
||||
|
||||
// Create error message element for operator code
|
||||
const operatorErrorMessage = document.createElement('div');
|
||||
operatorErrorMessage.className = 'error-message';
|
||||
operatorErrorMessage.id = 'operator-error';
|
||||
operatorErrorMessage.textContent = 'Please scan Quality Operator code (must start with OP)';
|
||||
operatorCodeInput.parentNode.insertBefore(operatorErrorMessage, operatorCodeInput.nextSibling);
|
||||
|
||||
// Create error message element for CP code
|
||||
const cpErrorMessage = document.createElement('div');
|
||||
cpErrorMessage.className = 'error-message';
|
||||
cpErrorMessage.id = 'cp-error';
|
||||
cpErrorMessage.textContent = 'Please scan a valid CP';
|
||||
cpCodeInput.parentNode.insertBefore(cpErrorMessage, cpCodeInput.nextSibling);
|
||||
|
||||
// Create error message element for OC1 code
|
||||
const oc1ErrorMessage = document.createElement('div');
|
||||
oc1ErrorMessage.className = 'error-message';
|
||||
oc1ErrorMessage.id = 'oc1-error';
|
||||
oc1ErrorMessage.textContent = 'Please scan a valid OC (must start with OC)';
|
||||
oc1CodeInput.parentNode.insertBefore(oc1ErrorMessage, oc1CodeInput.nextSibling);
|
||||
|
||||
// Create error message element for OC2 code
|
||||
const oc2ErrorMessage = document.createElement('div');
|
||||
oc2ErrorMessage.className = 'error-message';
|
||||
oc2ErrorMessage.id = 'oc2-error';
|
||||
oc2ErrorMessage.textContent = 'Please scan a valid OC (must start with OC)';
|
||||
oc2CodeInput.parentNode.insertBefore(oc2ErrorMessage, oc2CodeInput.nextSibling);
|
||||
|
||||
// Create error message element for defect code
|
||||
const defectErrorMessage = document.createElement('div');
|
||||
defectErrorMessage.className = 'error-message';
|
||||
defectErrorMessage.id = 'defect-error';
|
||||
defectErrorMessage.textContent = 'Defect code must be a 3-digit number (e.g., 000, 001, 123)';
|
||||
defectCodeInput.parentNode.insertBefore(defectErrorMessage, defectCodeInput.nextSibling);
|
||||
|
||||
// Validate operator code on input
|
||||
operatorCodeInput.addEventListener('input', function() {
|
||||
const value = this.value.toUpperCase();
|
||||
this.value = value;
|
||||
|
||||
if (value.length >= 2 && !value.startsWith('OP')) {
|
||||
operatorErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must start with OP');
|
||||
} else {
|
||||
operatorErrorMessage.classList.remove('show');
|
||||
this.setCustomValidity('');
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent leaving operator code field if invalid
|
||||
operatorCodeInput.addEventListener('blur', function(e) {
|
||||
if (this.value.length > 0 && !this.value.startsWith('OP')) {
|
||||
operatorErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must start with OP');
|
||||
setTimeout(() => {
|
||||
this.focus();
|
||||
this.select();
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent Tab/Enter from moving to next field if operator code is invalid
|
||||
operatorCodeInput.addEventListener('keydown', function(e) {
|
||||
if ((e.key === 'Tab' || e.key === 'Enter') && this.value.length > 0 && !this.value.startsWith('OP')) {
|
||||
e.preventDefault();
|
||||
operatorErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must start with OP');
|
||||
this.select();
|
||||
}
|
||||
});
|
||||
|
||||
// Validate CP code on input
|
||||
cpCodeInput.addEventListener('input', function() {
|
||||
const value = this.value.toUpperCase();
|
||||
this.value = value;
|
||||
|
||||
if (value.length >= 2 && !value.startsWith('CP')) {
|
||||
cpErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must start with CP');
|
||||
} else {
|
||||
cpErrorMessage.classList.remove('show');
|
||||
this.setCustomValidity('');
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent leaving CP code field if invalid
|
||||
cpCodeInput.addEventListener('blur', function(e) {
|
||||
if (this.value.length > 0 && !this.value.startsWith('CP')) {
|
||||
cpErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must start with CP');
|
||||
setTimeout(() => {
|
||||
this.focus();
|
||||
this.select();
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent Tab/Enter from moving to next field if CP code is invalid
|
||||
cpCodeInput.addEventListener('keydown', function(e) {
|
||||
if ((e.key === 'Tab' || e.key === 'Enter') && this.value.length > 0 && !this.value.startsWith('CP')) {
|
||||
e.preventDefault();
|
||||
cpErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must start with CP');
|
||||
this.select();
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent focusing on CP code if operator code is invalid
|
||||
cpCodeInput.addEventListener('focus', function(e) {
|
||||
if (operatorCodeInput.value.length > 0 && !operatorCodeInput.value.startsWith('OP')) {
|
||||
e.preventDefault();
|
||||
operatorErrorMessage.classList.add('show');
|
||||
operatorCodeInput.focus();
|
||||
operatorCodeInput.select();
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent focusing on OC1 code if CP code is invalid
|
||||
oc1CodeInput.addEventListener('focus', function(e) {
|
||||
if (cpCodeInput.value.length > 0 && !cpCodeInput.value.startsWith('CP')) {
|
||||
e.preventDefault();
|
||||
cpErrorMessage.classList.add('show');
|
||||
cpCodeInput.focus();
|
||||
cpCodeInput.select();
|
||||
}
|
||||
});
|
||||
|
||||
// Validate OC1 code on input
|
||||
oc1CodeInput.addEventListener('input', function() {
|
||||
const value = this.value.toUpperCase();
|
||||
this.value = value;
|
||||
|
||||
if (value.length >= 2 && !value.startsWith('OC')) {
|
||||
oc1ErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must start with OC');
|
||||
} else {
|
||||
oc1ErrorMessage.classList.remove('show');
|
||||
this.setCustomValidity('');
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent leaving OC1 code field if invalid
|
||||
oc1CodeInput.addEventListener('blur', function(e) {
|
||||
if (this.value.length > 0 && !this.value.startsWith('OC')) {
|
||||
oc1ErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must start with OC');
|
||||
setTimeout(() => {
|
||||
this.focus();
|
||||
this.select();
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent Tab/Enter from moving to next field if OC1 code is invalid
|
||||
oc1CodeInput.addEventListener('keydown', function(e) {
|
||||
if ((e.key === 'Tab' || e.key === 'Enter') && this.value.length > 0 && !this.value.startsWith('OC')) {
|
||||
e.preventDefault();
|
||||
oc1ErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must start with OC');
|
||||
this.select();
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent focusing on OC2 code if CP code is invalid
|
||||
oc2CodeInput.addEventListener('focus', function(e) {
|
||||
if (cpCodeInput.value.length > 0 && !cpCodeInput.value.startsWith('CP')) {
|
||||
e.preventDefault();
|
||||
cpErrorMessage.classList.add('show');
|
||||
cpCodeInput.focus();
|
||||
cpCodeInput.select();
|
||||
}
|
||||
// Also check if OC1 is invalid
|
||||
if (oc1CodeInput.value.length > 0 && !oc1CodeInput.value.startsWith('OC')) {
|
||||
e.preventDefault();
|
||||
oc1ErrorMessage.classList.add('show');
|
||||
oc1CodeInput.focus();
|
||||
oc1CodeInput.select();
|
||||
}
|
||||
});
|
||||
|
||||
// Validate OC2 code on input
|
||||
oc2CodeInput.addEventListener('input', function() {
|
||||
const value = this.value.toUpperCase();
|
||||
this.value = value;
|
||||
|
||||
if (value.length >= 2 && !value.startsWith('OC')) {
|
||||
oc2ErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must start with OC');
|
||||
} else {
|
||||
oc2ErrorMessage.classList.remove('show');
|
||||
this.setCustomValidity('');
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent leaving OC2 code field if invalid
|
||||
oc2CodeInput.addEventListener('blur', function(e) {
|
||||
if (this.value.length > 0 && !this.value.startsWith('OC')) {
|
||||
oc2ErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must start with OC');
|
||||
setTimeout(() => {
|
||||
this.focus();
|
||||
this.select();
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent Tab/Enter from moving to next field if OC2 code is invalid
|
||||
oc2CodeInput.addEventListener('keydown', function(e) {
|
||||
if ((e.key === 'Tab' || e.key === 'Enter') && this.value.length > 0 && !this.value.startsWith('OC')) {
|
||||
e.preventDefault();
|
||||
oc2ErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must start with OC');
|
||||
this.select();
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent focusing on defect code if CP code is invalid
|
||||
defectCodeInput.addEventListener('focus', function(e) {
|
||||
if (cpCodeInput.value.length > 0 && !cpCodeInput.value.startsWith('CP')) {
|
||||
e.preventDefault();
|
||||
cpErrorMessage.classList.add('show');
|
||||
cpCodeInput.focus();
|
||||
cpCodeInput.select();
|
||||
}
|
||||
// Also check if OC1 is invalid
|
||||
if (oc1CodeInput.value.length > 0 && !oc1CodeInput.value.startsWith('OC')) {
|
||||
e.preventDefault();
|
||||
oc1ErrorMessage.classList.add('show');
|
||||
oc1CodeInput.focus();
|
||||
oc1CodeInput.select();
|
||||
}
|
||||
// Also check if OC2 is invalid
|
||||
if (oc2CodeInput.value.length > 0 && !oc2CodeInput.value.startsWith('OC')) {
|
||||
e.preventDefault();
|
||||
oc2ErrorMessage.classList.add('show');
|
||||
oc2CodeInput.focus();
|
||||
oc2CodeInput.select();
|
||||
}
|
||||
});
|
||||
|
||||
// Validate defect code on input - only allow digits
|
||||
defectCodeInput.addEventListener('input', function() {
|
||||
// Remove any non-digit characters
|
||||
this.value = this.value.replace(/\D/g, '');
|
||||
|
||||
// Validate if it's a valid 3-digit number when length is 3
|
||||
if (this.value.length === 3) {
|
||||
const isValid = /^\d{3}$/.test(this.value);
|
||||
if (!isValid) {
|
||||
defectErrorMessage.classList.add('show');
|
||||
this.setCustomValidity('Must be a 3-digit number');
|
||||
} else {
|
||||
defectErrorMessage.classList.remove('show');
|
||||
this.setCustomValidity('');
|
||||
}
|
||||
} else {
|
||||
defectErrorMessage.classList.remove('show');
|
||||
this.setCustomValidity('');
|
||||
}
|
||||
|
||||
// Auto-submit when 3 characters are entered and all validations pass
|
||||
if (this.value.length === 3) {
|
||||
// Validate operator code before submitting
|
||||
if (!operatorCodeInput.value.startsWith('OP')) {
|
||||
operatorErrorMessage.classList.add('show');
|
||||
operatorCodeInput.focus();
|
||||
operatorCodeInput.setCustomValidity('Must start with OP');
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate CP code before submitting
|
||||
if (!cpCodeInput.value.startsWith('CP')) {
|
||||
cpErrorMessage.classList.add('show');
|
||||
cpCodeInput.focus();
|
||||
cpCodeInput.setCustomValidity('Must start with CP');
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate OC1 code before submitting
|
||||
if (!oc1CodeInput.value.startsWith('OC')) {
|
||||
oc1ErrorMessage.classList.add('show');
|
||||
oc1CodeInput.focus();
|
||||
oc1CodeInput.setCustomValidity('Must start with OC');
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate OC2 code before submitting
|
||||
if (!oc2CodeInput.value.startsWith('OC')) {
|
||||
oc2ErrorMessage.classList.add('show');
|
||||
oc2CodeInput.focus();
|
||||
oc2CodeInput.setCustomValidity('Must start with OC');
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate defect code is a valid 3-digit number
|
||||
const isValidDefectCode = /^\d{3}$/.test(this.value);
|
||||
if (!isValidDefectCode) {
|
||||
defectErrorMessage.classList.add('show');
|
||||
this.focus();
|
||||
this.setCustomValidity('Must be a 3-digit number');
|
||||
return;
|
||||
}
|
||||
|
||||
// Update time field before submitting
|
||||
const timeInput = document.getElementById('time');
|
||||
const now = new Date();
|
||||
const hours = String(now.getHours()).padStart(2, '0');
|
||||
const minutes = String(now.getMinutes()).padStart(2, '0');
|
||||
const seconds = String(now.getSeconds()).padStart(2, '0');
|
||||
timeInput.value = `${hours}:${minutes}:${seconds}`;
|
||||
|
||||
// Submit the form
|
||||
form.submit();
|
||||
}
|
||||
});
|
||||
|
||||
// Validate form on submit
|
||||
form.addEventListener('submit', function(e) {
|
||||
let hasError = false;
|
||||
|
||||
if (!operatorCodeInput.value.startsWith('OP')) {
|
||||
e.preventDefault();
|
||||
operatorErrorMessage.classList.add('show');
|
||||
operatorCodeInput.setCustomValidity('Must start with OP');
|
||||
if (!hasError) {
|
||||
operatorCodeInput.focus();
|
||||
hasError = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cpCodeInput.value.startsWith('CP')) {
|
||||
e.preventDefault();
|
||||
cpErrorMessage.classList.add('show');
|
||||
cpCodeInput.setCustomValidity('Must start with CP');
|
||||
if (!hasError) {
|
||||
cpCodeInput.focus();
|
||||
hasError = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!oc1CodeInput.value.startsWith('OC')) {
|
||||
e.preventDefault();
|
||||
oc1ErrorMessage.classList.add('show');
|
||||
oc1CodeInput.setCustomValidity('Must start with OC');
|
||||
if (!hasError) {
|
||||
oc1CodeInput.focus();
|
||||
hasError = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!oc2CodeInput.value.startsWith('OC')) {
|
||||
e.preventDefault();
|
||||
oc2ErrorMessage.classList.add('show');
|
||||
oc2CodeInput.setCustomValidity('Must start with OC');
|
||||
if (!hasError) {
|
||||
oc2CodeInput.focus();
|
||||
hasError = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate defect code is a 3-digit number
|
||||
const isValidDefectCode = /^\d{3}$/.test(defectCodeInput.value);
|
||||
if (!isValidDefectCode) {
|
||||
e.preventDefault();
|
||||
defectErrorMessage.classList.add('show');
|
||||
defectCodeInput.setCustomValidity('Must be a 3-digit number');
|
||||
if (!hasError) {
|
||||
defectCodeInput.focus();
|
||||
hasError = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="scan-container">
|
||||
|
||||
Reference in New Issue
Block a user