From 9244ff90f6560d11973bf600345b0c16d7467965 Mon Sep 17 00:00:00 2001 From: ske087 Date: Thu, 17 Apr 2025 15:02:08 +0300 Subject: [PATCH] added scan page --- py_app/app/__init__.py | 4 + .../app/__pycache__/__init__.cpython-311.pyc | Bin 1242 -> 1393 bytes py_app/app/__pycache__/routes.cpython-311.pyc | Bin 10979 -> 14563 bytes py_app/app/routes.py | 64 +++++++++- py_app/app/static/style.css | 115 +++++++++++++++--- py_app/app/templates/dashboard.html | 16 ++- py_app/app/templates/scan.html | 67 +++++++++- py_app/requirements.txt | 1 + 8 files changed, 243 insertions(+), 24 deletions(-) diff --git a/py_app/app/__init__.py b/py_app/app/__init__.py index f9429e8..0458074 100644 --- a/py_app/app/__init__.py +++ b/py_app/app/__init__.py @@ -1,5 +1,6 @@ from flask import Flask from flask_sqlalchemy import SQLAlchemy +from datetime import datetime db = SQLAlchemy() @@ -14,6 +15,9 @@ def create_app(): from .routes import bp app.register_blueprint(bp) + # Add 'now' function to Jinja2 globals + app.jinja_env.globals['now'] = datetime.now + with app.app_context(): db.create_all() # Create database tables if they don't exist diff --git a/py_app/app/__pycache__/__init__.cpython-311.pyc b/py_app/app/__pycache__/__init__.cpython-311.pyc index 7db3f91f741048fc0e22a178ac97840143cc9a86..790d91963bfc6766ae776587eccb3f9771ba7355 100644 GIT binary patch delta 449 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 delta 2073 zcmZ`)OKcle6rDHYZzgt}_?I}&51P7eaK6NiNSachfFOKY+Dce}HOagtL&tV_Gf5yU zS`dP5s#mE9WkEOTB8ZKJ)Fm61M5zc;GZhk2H&7%LBr2pV5ckg1PLl~^&+)wX&bf2u zzI(^_Ke&G(d@B@c5a8Ihgt>ExYvI;pN)m({f-0y)7Yg_*>ZBwVuAT146G4?!kKRy{ z3$lIf)f-EpLWl^WKt+41vkG zi;$=hGKmAhk}htt#?7@tj)*HqZ7xM?U6DFe(e6^T)fMSO6&)@`s-_s|JXF!;Qnah& zEg{>@-;oxp>%s3yPXzYG3M?3um6Z~;0`rPtELE7A6cz%q35oL?p|MmKQab>wpsE;i(-noO z>`53W`0t@{(pBvZzb}#mUx^HPk}%B&eF>jM*e*HAw<1%)6iOvU*LkNur+F&#v}}0| zlWFttGp}o=W6aNv1CjM1J7iGP)XK9)@sg%fi(Ilix>lx^beVo+c^4IZff{}wb~}gT zE>IJ(XJ9E^U2Pr}1DFTMQ7_+)4v{36W4X2`V2africR1UVUVAVy-m9KdhDk?+2`@m z5qzlS@RGvlTm^QZf6grF>?Fz#ggS+D2q*ZT@q&!^SoRJWGfJ6y35)XOBWbxl!xH@F zk@2xMlr|#ZRg^<8@V%oIv2(vc_9BM$Be$rjQ2Boxo0{J5!IEaF$ztfi)}j&iG5{Eu!t1>yy9cl{ zu#_H^IaM{&@$v>NOv7pXBkT{TK|Uh{2{l-mSKyK5w(KbXL;r;%(OzP zVk*;$L5uj-cr5oBPKR$@u|4L{SwF%60{(@uK>#aIQZ7R#m|^(=?Eu3#?_FY=Nwa=- z9;p`)E+Xue#V8K*0PZG@7|J3o(hng4<%pse)oJ!F5Lb|VkKb$_uKqak1Ci1!$G;jq zf5q}LC|PR1lZ6o!{=dLt3^-%Z}(F$94pOza&A7 P)@K^|!xIlY*#7?k>Y2T! diff --git a/py_app/app/routes.py b/py_app/app/routes.py index a964cee..9d96574 100644 --- a/py_app/app/routes.py +++ b/py_app/app/routes.py @@ -1,10 +1,34 @@ import os +import pyodbc from flask import Blueprint, render_template, redirect, url_for, request, flash, session, current_app from .models import User from . import db 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']) def login(): if request.method == 'POST': @@ -59,12 +83,48 @@ def warehouse(): return redirect(url_for('main.dashboard')) return render_template('warehouse.html') -@bp.route('/scan') +@bp.route('/scan', methods=['GET', 'POST']) def scan(): if 'role' not in session or session['role'] not in ['superadmin', 'scan']: flash('Access denied: Scan users only.') 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') def logout(): diff --git a/py_app/app/static/style.css b/py_app/app/static/style.css index 019630f..ec47f52 100644 --- a/py_app/app/static/style.css +++ b/py_app/app/static/style.css @@ -6,8 +6,8 @@ body { } .container { - width: 100%; - margin: auto; + width: 95%; + margin: 15px auto; /* Add 15px top margin */ overflow: hidden; padding: 0; /* Remove padding */ background: none; /* Remove white background */ @@ -443,18 +443,19 @@ body.dark-mode .popup-content { .form-centered { display: flex; flex-direction: column; - align-items: center; /* Center the input fields */ + align-items: center; + margin-bottom: 20px; } .form-centered label { - width: 75%; /* Align labels with the input fields */ + width: 100%; text-align: left; margin-bottom: 5px; font-weight: bold; } .form-centered input { - width: 75%; /* Set input fields to 75% of the card width */ + width: 80%; padding: 10px; margin-bottom: 15px; font-size: 1em; @@ -462,19 +463,44 @@ body.dark-mode .popup-content { border-radius: 5px; } -.form-centered button { - width: 50%; /* Center the button and reduce its width */ - padding: 10px; - font-size: 1em; - background-color: #007bff; - color: #fff; - border: none; - border-radius: 5px; - cursor: pointer; +.scan-table { + width: 100%; + border-collapse: collapse; + margin-top: 20px; } -.form-centered button:hover { - background-color: #0056b3; +.scan-table th, .scan-table td { + 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 */ @@ -487,9 +513,66 @@ body.dark-mode .popup-content { 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 (max-width: 768px) { .card { 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 */ + } } \ No newline at end of file diff --git a/py_app/app/templates/dashboard.html b/py_app/app/templates/dashboard.html index ba00a1f..8d36521 100644 --- a/py_app/app/templates/dashboard.html +++ b/py_app/app/templates/dashboard.html @@ -3,9 +3,17 @@ {% block title %}Dashboard{% endblock %} {% block content %} -
-

Manage Settings

-

Access and manage application settings.

- Access Settings Page +
+
+

Accesare modul scanare

+

Modul de scanare finala a comenzilor de productie

+ Lansare modul de scanare +
+ +
+

Manage Settings

+

Access and manage application settings.

+ Access Settings Page +
{% endblock %} \ No newline at end of file diff --git a/py_app/app/templates/scan.html b/py_app/app/templates/scan.html index 06a0a89..42e5e81 100644 --- a/py_app/app/templates/scan.html +++ b/py_app/app/templates/scan.html @@ -1,6 +1,69 @@ {% extends "base.html" %} {% block title %}Scan Module{% endblock %} {% block content %} -

Scan Module

-

Welcome to the Scan Module.

+
+ +
+

Scan Input

+
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+

Latest Scans

+ + + + + + + + + + + + + + + + {% for row in scan_data %} + + + + + + + + + + + + {% endfor %} + +
IDOperator CodeCP CodeOC1 CodeOC2 CodeDefect CodeDateTimeQuantity
{{ row.id }}{{ row.operator_code }}{{ row.cp_code }}{{ row.oc1_code }}{{ row.oc2_code }}{{ row.defect_code }}{{ row.date }}{{ row.time }}{{ row.quantity }}
+
+
{% endblock %} \ No newline at end of file diff --git a/py_app/requirements.txt b/py_app/requirements.txt index ad4356b..c9148f2 100644 --- a/py_app/requirements.txt +++ b/py_app/requirements.txt @@ -3,3 +3,4 @@ Flask-SSLify==0.1.5 Werkzeug==2.2.2 gunicorn==20.1.0 flask-sqlalchemy==2.5.1 +pyodbc==4.0.0 \ No newline at end of file