added scan page
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
from flask import Flask
|
from flask import Flask
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
db = SQLAlchemy()
|
db = SQLAlchemy()
|
||||||
|
|
||||||
@@ -14,6 +15,9 @@ def create_app():
|
|||||||
from .routes import bp
|
from .routes import bp
|
||||||
app.register_blueprint(bp)
|
app.register_blueprint(bp)
|
||||||
|
|
||||||
|
# Add 'now' function to Jinja2 globals
|
||||||
|
app.jinja_env.globals['now'] = datetime.now
|
||||||
|
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
db.create_all() # Create database tables if they don't exist
|
db.create_all() # Create database tables if they don't exist
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -1,10 +1,34 @@
|
|||||||
import os
|
import os
|
||||||
|
import pyodbc
|
||||||
from flask import Blueprint, render_template, redirect, url_for, request, flash, session, current_app
|
from flask import Blueprint, render_template, redirect, url_for, request, flash, session, current_app
|
||||||
from .models import User
|
from .models import User
|
||||||
from . import db
|
from . import db
|
||||||
|
|
||||||
bp = Blueprint('main', __name__)
|
bp = Blueprint('main', __name__)
|
||||||
|
|
||||||
|
def get_db_connection():
|
||||||
|
"""Reads the external_server.conf file and returns a database connection."""
|
||||||
|
settings_file = os.path.join(current_app.instance_path, 'external_server.conf')
|
||||||
|
if not os.path.exists(settings_file):
|
||||||
|
raise FileNotFoundError("The external_server.conf file is missing in the instance folder.")
|
||||||
|
|
||||||
|
# Read settings from the configuration file
|
||||||
|
settings = {}
|
||||||
|
with open(settings_file, 'r') as f:
|
||||||
|
for line in f:
|
||||||
|
key, value = line.strip().split('=', 1)
|
||||||
|
settings[key] = value
|
||||||
|
|
||||||
|
# Create a database connection string
|
||||||
|
connection_string = (
|
||||||
|
f"DRIVER={{ODBC Driver 17 for SQL Server}};"
|
||||||
|
f"SERVER={settings['server_domain']},{settings['port']};"
|
||||||
|
f"DATABASE={settings['database_name']};"
|
||||||
|
f"UID={settings['username']};"
|
||||||
|
f"PWD={settings['password']};"
|
||||||
|
)
|
||||||
|
return pyodbc.connect(connection_string)
|
||||||
|
|
||||||
@bp.route('/login', methods=['GET', 'POST'])
|
@bp.route('/login', methods=['GET', 'POST'])
|
||||||
def login():
|
def login():
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
@@ -59,12 +83,48 @@ def warehouse():
|
|||||||
return redirect(url_for('main.dashboard'))
|
return redirect(url_for('main.dashboard'))
|
||||||
return render_template('warehouse.html')
|
return render_template('warehouse.html')
|
||||||
|
|
||||||
@bp.route('/scan')
|
@bp.route('/scan', methods=['GET', 'POST'])
|
||||||
def scan():
|
def scan():
|
||||||
if 'role' not in session or session['role'] not in ['superadmin', 'scan']:
|
if 'role' not in session or session['role'] not in ['superadmin', 'scan']:
|
||||||
flash('Access denied: Scan users only.')
|
flash('Access denied: Scan users only.')
|
||||||
return redirect(url_for('main.dashboard'))
|
return redirect(url_for('main.dashboard'))
|
||||||
return render_template('scan.html')
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
# Handle form submission
|
||||||
|
operator_code = request.form.get('operator_code')
|
||||||
|
cp_code = request.form.get('cp_code')
|
||||||
|
oc1_code = request.form.get('oc1_code')
|
||||||
|
oc2_code = request.form.get('oc2_code')
|
||||||
|
defect_code = request.form.get('defect_code')
|
||||||
|
date = request.form.get('date')
|
||||||
|
time = request.form.get('time')
|
||||||
|
|
||||||
|
try:
|
||||||
|
conn = get_db_connection()
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute(
|
||||||
|
"INSERT INTO scanare (operator_code, cp_code, oc1_code, oc2_code, defect_code, date, time, quantity) "
|
||||||
|
"VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
||||||
|
operator_code, cp_code, oc1_code, oc2_code, defect_code, date, time, 1
|
||||||
|
)
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
flash('Scan data saved successfully.')
|
||||||
|
except Exception as e:
|
||||||
|
flash(f"Error saving scan data: {e}")
|
||||||
|
|
||||||
|
# Fetch the latest scan data for display
|
||||||
|
scan_data = []
|
||||||
|
try:
|
||||||
|
conn = get_db_connection()
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute("SELECT TOP 14 * FROM scanare ORDER BY id DESC")
|
||||||
|
scan_data = cursor.fetchall()
|
||||||
|
conn.close()
|
||||||
|
except Exception as e:
|
||||||
|
flash(f"Error fetching scan data: {e}")
|
||||||
|
|
||||||
|
return render_template('scan.html', scan_data=scan_data)
|
||||||
|
|
||||||
@bp.route('/logout')
|
@bp.route('/logout')
|
||||||
def logout():
|
def logout():
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
width: 100%;
|
width: 95%;
|
||||||
margin: auto;
|
margin: 15px auto; /* Add 15px top margin */
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding: 0; /* Remove padding */
|
padding: 0; /* Remove padding */
|
||||||
background: none; /* Remove white background */
|
background: none; /* Remove white background */
|
||||||
@@ -443,18 +443,19 @@ body.dark-mode .popup-content {
|
|||||||
.form-centered {
|
.form-centered {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center; /* Center the input fields */
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-centered label {
|
.form-centered label {
|
||||||
width: 75%; /* Align labels with the input fields */
|
width: 100%;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-centered input {
|
.form-centered input {
|
||||||
width: 75%; /* Set input fields to 75% of the card width */
|
width: 80%;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
@@ -462,19 +463,44 @@ body.dark-mode .popup-content {
|
|||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-centered button {
|
.scan-table {
|
||||||
width: 50%; /* Center the button and reduce its width */
|
width: 100%;
|
||||||
padding: 10px;
|
border-collapse: collapse;
|
||||||
font-size: 1em;
|
margin-top: 20px;
|
||||||
background-color: #007bff;
|
|
||||||
color: #fff;
|
|
||||||
border: none;
|
|
||||||
border-radius: 5px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-centered button:hover {
|
.scan-table th, .scan-table td {
|
||||||
background-color: #0056b3;
|
border: 1px solid #ddd;
|
||||||
|
padding: 8px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scan-table th {
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dark mode styles for the scan table */
|
||||||
|
body.dark-mode .scan-table {
|
||||||
|
background-color: #1e1e1e; /* Dark background for the table */
|
||||||
|
color: #fff; /* Light text for better contrast */
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .scan-table th {
|
||||||
|
background-color: #333; /* Darker background for table headers */
|
||||||
|
color: #fff; /* Light text for headers */
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .scan-table td {
|
||||||
|
color: #ddd; /* Slightly lighter text for table cells */
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .scan-table tr:nth-child(even) {
|
||||||
|
background-color: #2a2a2a; /* Slightly lighter background for even rows */
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .scan-table tr:nth-child(odd) {
|
||||||
|
background-color: #1e1e1e; /* Match the table background for odd rows */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Container for the cards */
|
/* Container for the cards */
|
||||||
@@ -487,9 +513,66 @@ body.dark-mode .popup-content {
|
|||||||
max-width: 1200px; /* Optional: Limit the maximum width of the container */
|
max-width: 1200px; /* Optional: Limit the maximum width of the container */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Container for the scan page */
|
||||||
|
.scan-container {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap; /* Allow wrapping on smaller screens */
|
||||||
|
gap: 20px; /* Add 20px spacing between the cards */
|
||||||
|
margin: 20px auto; /* Center the container vertically and horizontally */
|
||||||
|
justify-content: center; /* Center the cards horizontally */
|
||||||
|
align-items: stretch; /* Make all cards the same height */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Input Form Card */
|
||||||
|
.scan-form-card {
|
||||||
|
flex: 0 0 500px; /* Fixed width of 500px */
|
||||||
|
max-width: 500px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column; /* Ensure content inside the card is vertically aligned */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Latest Scans Card */
|
||||||
|
.scan-table-card {
|
||||||
|
flex: 2 1 1000px; /* Take up twice the space compared to other cards */
|
||||||
|
max-width: 1000px; /* Ensure the card doesn't exceed 1000px in width */
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||||
|
overflow-x: auto; /* Allow horizontal scrolling for the table */
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column; /* Ensure content inside the card is vertically aligned */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Table styles */
|
||||||
|
.scan-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scan-table th, .scan-table td {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 8px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scan-table th {
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
/* Media query for smaller screens */
|
/* Media query for smaller screens */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.card {
|
.card {
|
||||||
flex: 1 1 100%; /* Make cards take full width on smaller screens */
|
flex: 1 1 100%; /* Make cards take full width on smaller screens */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.scan-form-card, .scan-table-card {
|
||||||
|
flex: 1 1 100%; /* Make both cards take full width on smaller screens */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -3,9 +3,17 @@
|
|||||||
{% block title %}Dashboard{% endblock %}
|
{% block title %}Dashboard{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="card">
|
<div class="card-container">
|
||||||
|
<div class="card">
|
||||||
|
<h3>Accesare modul scanare</h3>
|
||||||
|
<p>Modul de scanare finala a comenzilor de productie</p>
|
||||||
|
<a href="{{ url_for('main.scan') }}" class="btn">Lansare modul de scanare</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
<h3>Manage Settings</h3>
|
<h3>Manage Settings</h3>
|
||||||
<p>Access and manage application settings.</p>
|
<p>Access and manage application settings.</p>
|
||||||
<a href="{{ url_for('main.settings') }}" class="btn">Access Settings Page</a>
|
<a href="{{ url_for('main.settings') }}" class="btn">Access Settings Page</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -1,6 +1,69 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block title %}Scan Module{% endblock %}
|
{% block title %}Scan Module{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h2>Scan Module</h2>
|
<div class="scan-container">
|
||||||
<p>Welcome to the Scan Module.</p>
|
<!-- Input Form Card -->
|
||||||
|
<div class="card scan-form-card">
|
||||||
|
<h3>Scan Input</h3>
|
||||||
|
<form method="POST" class="form-centered">
|
||||||
|
<label for="operator_code">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="14" 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') }}" readonly>
|
||||||
|
|
||||||
|
<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>Operator 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>Quantity</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for row in scan_data %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ row.id }}</td>
|
||||||
|
<td>{{ row.operator_code }}</td>
|
||||||
|
<td>{{ row.cp_code }}</td>
|
||||||
|
<td>{{ row.oc1_code }}</td>
|
||||||
|
<td>{{ row.oc2_code }}</td>
|
||||||
|
<td>{{ row.defect_code }}</td>
|
||||||
|
<td>{{ row.date }}</td>
|
||||||
|
<td>{{ row.time }}</td>
|
||||||
|
<td>{{ row.quantity }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -3,3 +3,4 @@ Flask-SSLify==0.1.5
|
|||||||
Werkzeug==2.2.2
|
Werkzeug==2.2.2
|
||||||
gunicorn==20.1.0
|
gunicorn==20.1.0
|
||||||
flask-sqlalchemy==2.5.1
|
flask-sqlalchemy==2.5.1
|
||||||
|
pyodbc==4.0.0
|
||||||
Reference in New Issue
Block a user