static Menubar apply boostrap css

This commit is contained in:
2026-01-16 13:04:59 +05:30
parent 1022923509
commit dd4b494435
4 changed files with 116 additions and 143 deletions

View File

@@ -1,42 +1,49 @@
import pandas as pd import pandas as pd
import io import io
from flask import Blueprint, render_template, request, send_file, flash from flask import Blueprint, render_template, request, send_file, flash
from app.utils.helpers import login_required
from app.models.subcontractor_model import Subcontractor from app.models.subcontractor_model import Subcontractor
from app.models.manhole_excavation_model import ManholeExcavation from app.models.manhole_excavation_model import ManholeExcavation
from app.models.trench_excavation_model import TrenchExcavation from app.models.trench_excavation_model import TrenchExcavation
from app.models.manhole_domestic_chamber_model import ManholeDomesticChamber from app.models.manhole_domestic_chamber_model import ManholeDomesticChamber
from app.models.laying_model import Laying
from app.models.mh_ex_client_model import ManholeExcavationClient from app.models.mh_ex_client_model import ManholeExcavationClient
from app.models.tr_ex_client_model import TrenchExcavationClient from app.models.tr_ex_client_model import TrenchExcavationClient
from app.models.mh_dc_client_model import ManholeDomesticChamberClient from app.models.mh_dc_client_model import ManholeDomesticChamberClient
from app.utils.helpers import login_required from app.models.laying_client_model import LayingClient
# --- BLUEPRINT DEFINITION --- # --- BLUEPRINT DEFINITION ---
file_report_bp = Blueprint("file_report", __name__, url_prefix="/file") file_report_bp = Blueprint("file_report", __name__, url_prefix="/file")
# --- DATA WRAPPERS --- # --- Client class ---
class ClientBill: class ClientBill:
def __init__(self): def __init__(self):
self.df_tr = pd.DataFrame() self.df_tr = pd.DataFrame()
self.df_mh = pd.DataFrame() self.df_mh = pd.DataFrame()
self.df_dc = pd.DataFrame() self.df_dc = pd.DataFrame()
self.df_laying = pd.DataFrame()
def Fetch(self, RA_Bill_No): def Fetch(self, RA_Bill_No):
trench = TrenchExcavationClient.query.filter_by(RA_Bill_No=RA_Bill_No).all() trench = TrenchExcavationClient.query.filter_by(RA_Bill_No=RA_Bill_No).all()
mh = ManholeExcavationClient.query.filter_by(RA_Bill_No=RA_Bill_No).all() mh = ManholeExcavationClient.query.filter_by(RA_Bill_No=RA_Bill_No).all()
dc = ManholeDomesticChamberClient.query.filter_by(RA_Bill_No=RA_Bill_No).all() dc = ManholeDomesticChamberClient.query.filter_by(RA_Bill_No=RA_Bill_No).all()
lay = LayingClient.query.filter_by(RA_Bill_No=RA_Bill_No).all()
self.df_tr = pd.DataFrame([c.serialize() for c in trench]) self.df_tr = pd.DataFrame([c.serialize() for c in trench])
self.df_mh = pd.DataFrame([c.serialize() for c in mh]) self.df_mh = pd.DataFrame([c.serialize() for c in mh])
self.df_dc = pd.DataFrame([c.serialize() for c in dc]) self.df_dc = pd.DataFrame([c.serialize() for c in dc])
self.df_laying = pd.DataFrame([c.serialize() for c in lay])
if not self.df_dc.empty and "MH_NO" in self.df_dc.columns:
self.df_dc.rename(columns={"MH_NO": "Node_No"}, inplace=True)
drop_cols = ["id", "created_at", "_sa_instance_state"] drop_cols = ["id", "created_at", "_sa_instance_state"]
for df in [self.df_tr, self.df_mh, self.df_dc]: for df in [self.df_tr, self.df_mh, self.df_dc, self.df_laying]:
if not df.empty: if not df.empty:
df.drop(columns=drop_cols, errors="ignore", inplace=True) df.drop(columns=drop_cols, errors="ignore", inplace=True)
# --- Subcontractor class ---
class SubcontractorBill: class SubcontractorBill:
def __init__(self): def __init__(self):
self.df_tr = pd.DataFrame() self.df_tr = pd.DataFrame()
@@ -54,22 +61,19 @@ class SubcontractorBill:
trench = TrenchExcavation.query.filter_by(**filters).all() trench = TrenchExcavation.query.filter_by(**filters).all()
mh = ManholeExcavation.query.filter_by(**filters).all() mh = ManholeExcavation.query.filter_by(**filters).all()
dc = ManholeDomesticChamber.query.filter_by(**filters).all() dc = ManholeDomesticChamber.query.filter_by(**filters).all()
lay = ManholeDomesticChamber.query.filter_by(**filters).all() lay = Laying.query.filter_by(**filters).all()
self.df_tr = pd.DataFrame([c.serialize() for c in trench]) self.df_tr = pd.DataFrame([c.serialize() for c in trench])
self.df_mh = pd.DataFrame([c.serialize() for c in mh]) self.df_mh = pd.DataFrame([c.serialize() for c in mh])
self.df_dc = pd.DataFrame([c.serialize() for c in dc]) self.df_dc = pd.DataFrame([c.serialize() for c in dc])
self.df_laying = pd.DataFrame([c.serialize() for c in lay]) self.df_laying = pd.DataFrame([c.serialize() for c in lay])
# if not self.df_dc.empty and "MH_NO" in self.df_dc.columns:
# self.df_dc.rename(columns={"MH_NO": "Node_No"}, inplace=True)
drop_cols = ["id", "created_at", "_sa_instance_state"] drop_cols = ["id", "created_at", "_sa_instance_state"]
for df in [self.df_tr, self.df_mh, self.df_dc, self.df_laying]: for df in [self.df_tr, self.df_mh, self.df_dc, self.df_laying]:
if not df.empty: if not df.empty:
df.drop(columns=drop_cols, errors="ignore", inplace=True) df.drop(columns=drop_cols, errors="ignore", inplace=True)
# --- subcontractor report only ---
@file_report_bp.route("/report", methods=["GET", "POST"]) @file_report_bp.route("/report", methods=["GET", "POST"])
@login_required @login_required
def report_file(): def report_file():
@@ -118,7 +122,8 @@ def report_file():
return send_file(output, download_name=file_name, as_attachment=True) return send_file(output, download_name=file_name, as_attachment=True)
# We add bootstrap classes directly to the pandas output # We add bootstrap classes directly to the pandas output
table_classes = "table table-hover table-bordered table-striped" # table_classes = "table table-hover table-bordered table-striped"
table_classes = "table table-bordered table-striped table-hover table-sm mb-0"
tables = { tables = {
"tr": bill_gen.df_tr.to_html(classes=table_classes, index=False), "tr": bill_gen.df_tr.to_html(classes=table_classes, index=False),
"mh": bill_gen.df_mh.to_html(classes=table_classes, index=False), "mh": bill_gen.df_mh.to_html(classes=table_classes, index=False),
@@ -136,6 +141,7 @@ def report_file():
download_all=download_all download_all=download_all
) )
# --- client comparison ---
@file_report_bp.route("/client_vs_subcont", methods=["GET", "POST"]) @file_report_bp.route("/client_vs_subcont", methods=["GET", "POST"])
@login_required @login_required
def client_vs_all_subcontractor(): def client_vs_all_subcontractor():

View File

@@ -1,35 +0,0 @@
body {
background: #f5f7fa;
font-family: Arial;
padding: 40px;
}
form {
width: 420px;
padding: 20px;
background: #fff;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
label {
margin-top: 10px;
display: block;
font-weight: bold;
}
input,
textarea {
width: 100%;
padding: 8px;
margin-top: 4px;
}
button {
margin-top: 20px;
padding: 10px 20px;
background: #0055ff;
color: #fff;
border: 0;
cursor: pointer;
}

View File

@@ -16,7 +16,9 @@
<body class="bg-light"> <body class="bg-light">
<!-- NAVBAR --> <!-- NAVBAR -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark shadow-sm"> <!-- <nav class="navbar navbar-expand-lg navbar-dark bg-dark shadow-sm"> -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark shadow-sm fixed-top">
<div class="container-fluid"> <div class="container-fluid">
<!-- Brand --> <!-- Brand -->
@@ -72,7 +74,7 @@
</li> </li>
<li> <li>
<a class="dropdown-item" href="/file/report"> <a class="dropdown-item" href="/file/report">
<i class="bi bi-download me-2"></i> Download Reports <i class="bi bi-download me-2"></i> Show Reports
</a> </a>
</li> </li>
</ul> </ul>
@@ -92,7 +94,7 @@
<li> <li>
<a class="dropdown-item" href="/file/client_vs_subcont"> <a class="dropdown-item" href="/file/client_vs_subcont">
<i class="bi bi-arrow-left-right me-2"></i> Comparison Report <i class="bi bi-arrow-left-right me-2"></i> Show Report
</a> </a>
</li> </li>
</ul> </ul>
@@ -170,25 +172,32 @@
</div> </div>
</nav> </nav>
<!-- FLASH MESSAGES -->
<div class="container mt-3">
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ category }} alert-dismissible fade show">
{{ message }}
<button class="btn-close" data-bs-dismiss="alert"></button>
</div>
{% endfor %}
{% endif %}
{% endwith %}
</div>
<!-- PAGE CONTENT --> <!-- PAGE CONTENT -->
<div class="container mt-4"> <div class="container-fluid vh-100 pt-5 overflow-hidden">
{% block content %}{% endblock %} <!-- FLASH MESSAGES -->
<div class="container mt-3">
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ category }} alert-dismissible fade show">
{{ message }}
<button class="btn-close" data-bs-dismiss="alert"></button>
</div>
{% endfor %}
{% endif %}
{% endwith %}
</div>
<div class="overflow-auto h-100">
<div class="container mt-4">
{% block content %}{% endblock %}
</div>
</div>
</div> </div>
<!-- Bootstrap JS --> <!-- Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>

View File

@@ -1,22 +1,14 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
<div class="container mt-4"> <div class="container my-4">
<h2 class="mb-4 text-center">Generate Subcontractor Report</h2>
{% with messages = get_flashed_messages(with_categories=true) %} <h2 class="text-center mb-4">Generate Subcontractor Report</h2>
{% if messages %}
{% for category, message in messages %} <!-- FORM -->
<div class="alert alert-{{ category }} alert-dismissible fade show" role="alert"> <div class="card shadow-sm p-3 p-md-4 mx-auto" style="max-width:600px;">
{{ message }} <form method="POST">
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
{% endfor %}
{% endif %}
{% endwith %}
<div class="card p-4 shadow-sm mx-auto" style="max-width: 600px;">
<form method="POST" id="reportForm">
<div class="mb-3"> <div class="mb-3">
<label class="form-label fw-semibold">Select Subcontractor</label> <label class="form-label fw-semibold">Select Subcontractor</label>
<select name="subcontractor_id" class="form-select" required> <select name="subcontractor_id" class="form-select" required>
@@ -30,120 +22,121 @@
</div> </div>
<div class="form-check form-switch mb-3"> <div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" name="download_all" value="true" id="downloadAllSwitch" <input class="form-check-input" type="checkbox" id="downloadAllSwitch" name="download_all" value="true"
onchange="toggleRAInput(this)" {% if download_all %}checked{% endif %}> {% if download_all %}checked{% endif %}>
<label class="form-check-label fw-bold text-primary" for="downloadAllSwitch"> <label class="form-check-label fw-bold text-primary">
Download All RA Bills for this Contractor Download All RA Bills
</label> </label>
</div> </div>
<div class="mb-4" id="ra_bill_container"> <div class="mb-4" id="ra_bill_container">
<label class="form-label fw-semibold">RA Bill Number</label> <label class="form-label fw-semibold">RA Bill Number</label>
<input type="text" name="ra_bill_no" id="ra_bill_input" class="form-control" placeholder="e.g. 01" <input type="text" name="ra_bill_no" id="ra_bill_input" class="form-control"
value="{{ ra_bill_no or '' }}"> value="{{ ra_bill_no or '' }}">
<small class="text-muted">Required if "Download All" is off.</small>
</div> </div>
<div class="row g-2"> <div class="row g-2">
<div class="col-md-6"> <div class="col-12 col-md-6">
<button type="submit" name="action" value="preview" class="btn btn-outline-primary w-100 py-2"> <button class="btn btn-outline-primary w-100" name="action" value="preview">
<i class="fas fa-eye me-2"></i>Preview Data Preview Data
</button> </button>
</div> </div>
<div class="col-md-6"> <div class="col-12 col-md-6">
<button type="submit" name="action" value="download" class="btn btn-primary w-100 py-2"> <button class="btn btn-primary w-100" name="action" value="download">
<i class="fas fa-download me-2"></i>Download Excel Download Excel
</button> </button>
</div> </div>
</div> </div>
</form> </form>
</div> </div>
{% if tables %} {% if tables %}
<div class="mt-5 mb-5"> <!-- REPORT PREVIEW -->
<hr> <div class="mt-5">
<h3 class="text-center mb-4">Report Preview</h3>
<h3 class="text-center mb-3">Report Preview</h3>
<div class="card shadow-sm"> <div class="card shadow-sm">
<div class="card-header bg-light">
<ul class="nav nav-tabs card-header-tabs" id="reportTabs" role="tablist">
<li class="nav-item">
<button class="nav-link active" id="tr-tab" data-bs-toggle="tab" data-bs-target="#tr"
type="button">Tr.Ex.</button>
</li>
<li class="nav-item">
<button class="nav-link" id="mh-tab" data-bs-toggle="tab" data-bs-target="#mh"
type="button">MH.Ex. </button>
</li>
<li class="nav-item">
<button class="nav-link" id="dc-tab" data-bs-toggle="tab" data-bs-target="#dc" type="button">MH
& DC</button>
</li>
<!-- MOBILE SCROLLABLE TABS -->
<div class="card-header p-0">
<ul class="nav nav-tabs flex-nowrap overflow-auto">
<li class="nav-item"> <li class="nav-item">
<button class="nav-link" id="dc-tab" data-bs-toggle="tab" data-bs-target="#dc" <button class="nav-link active" data-bs-toggle="tab" data-bs-target="#tr">
type="button">Laying</button> Trench Excavation
</button>
</li>
<li class="nav-item">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#mh">
Manhole Excavation
</button>
</li>
<li class="nav-item">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#dc">
Manhole & Domestic Chambers
</button>
</li>
<li class="nav-item">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#laying">
Pipe Laying
</button>
</li> </li>
</ul> </ul>
</div> </div>
<div class="card-body tab-content" id="reportTabsContent">
<div class="tab-pane fade show active" id="tr" role="tabpanel"> <!-- TAB CONTENT -->
<div class="table-responsive"> <div class="card-body tab-content">
<div class="tab-pane fade show active" id="tr">
<div class="table-responsive overflow-auto">
{{ tables.tr | safe }} {{ tables.tr | safe }}
</div> </div>
</div> </div>
<div class="tab-pane fade" id="mh" role="tabpanel">
<div class="table-responsive"> <div class="tab-pane fade" id="mh">
<div class="table-responsive overflow-auto">
{{ tables.mh | safe }} {{ tables.mh | safe }}
</div> </div>
</div> </div>
<div class="tab-pane fade" id="dc" role="tabpanel">
<div class="table-responsive"> <div class="tab-pane fade" id="dc">
<div class="table-responsive overflow-auto">
{{ tables.dc | safe }} {{ tables.dc | safe }}
</div> </div>
</div> </div>
<div class="tab-pane fade" id="laying" role="tabpanel"> <div class="tab-pane fade" id="laying">
<div class="table-responsive"> <div class="table-responsive overflow-auto">
{{ tables.laying | safe }} {{ tables.laying | safe }}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{% endif %} {% endif %}
</div> </div>
<style> <!-- BOOTSTRAP-ONLY JS -->
/* Styling specifically for pandas output */
.table-responsive .table {
font-size: 0.9rem;
white-space: nowrap;
}
.table-responsive thead {
background-color: #f8f9fa;
}
</style>
<script> <script>
function toggleRAInput(checkbox) { function toggleRAInput() {
const input = document.getElementById('ra_bill_input'); const checkbox = document.getElementById("downloadAllSwitch");
const container = document.getElementById('ra_bill_container'); const input = document.getElementById("ra_bill_input");
const container = document.getElementById("ra_bill_container");
if (checkbox.checked) { if (checkbox.checked) {
input.value = ""; input.value = "";
input.disabled = true; input.disabled = true;
container.style.opacity = "0.5"; container.classList.add("opacity-50");
} else { } else {
input.disabled = false; input.disabled = false;
container.style.opacity = "1"; container.classList.remove("opacity-50");
} }
} }
// Check status on load to handle form persistence document.addEventListener("DOMContentLoaded", toggleRAInput);
document.addEventListener("DOMContentLoaded", function () { document.getElementById("downloadAllSwitch").addEventListener("change", toggleRAInput);
toggleRAInput(document.getElementById('downloadAllSwitch'));
});
</script> </script>
{% endblock %} {% endblock %}