feat: FASE 6.5 - Report PDF (WeasyPrint + Kaleido)
Add PDF report generation for Metrologist dashboard with SPC and measurement reports including SVG charts, capability indices, and company logo embedding. New files: - server/services/report_service.py (Jinja2 + Plotly/Kaleido + WeasyPrint) - server/routers/reports.py (2 GET endpoints with auth) - server/templates/reports/ (base, spc, measurement HTML templates) Modified: - server/main.py (register reports router) - client dashboard (download buttons + proxy routes) - i18n strings IT/EN Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
"""Metrologist blueprint - SPC statistics dashboard and API proxies."""
|
||||
from flask import Blueprint, jsonify, render_template, request
|
||||
import requests as http_requests
|
||||
|
||||
from flask import Blueprint, jsonify, render_template, request, session
|
||||
from flask_babel import gettext as _
|
||||
|
||||
from blueprints.auth import login_required, role_required
|
||||
from config import Config
|
||||
from services.api_client import api_client
|
||||
|
||||
statistics_bp = Blueprint("statistics", __name__)
|
||||
@@ -105,3 +108,71 @@ def api_subtasks():
|
||||
return jsonify(resp)
|
||||
|
||||
return jsonify(resp)
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# PROXY REPORT PDF → FastAPI
|
||||
# ============================================================================
|
||||
|
||||
def _proxy_report(endpoint: str):
|
||||
"""Forward query params to a FastAPI reports endpoint and return PDF."""
|
||||
params = {}
|
||||
for key in [
|
||||
"recipe_id", "version_id", "subtask_id",
|
||||
"date_from", "date_to", "operator_id",
|
||||
"lot_number", "serial_number",
|
||||
]:
|
||||
val = request.args.get(key)
|
||||
if val is not None and val != "":
|
||||
params[key] = val
|
||||
|
||||
base_url = Config.API_SERVER_URL.rstrip("/")
|
||||
headers = {}
|
||||
api_key = session.get("api_key")
|
||||
if api_key:
|
||||
headers["X-API-Key"] = api_key
|
||||
|
||||
try:
|
||||
resp = http_requests.get(
|
||||
f"{base_url}/api/reports/{endpoint}",
|
||||
headers=headers,
|
||||
params=params,
|
||||
timeout=120,
|
||||
)
|
||||
except (http_requests.ConnectionError, http_requests.Timeout) as e:
|
||||
return jsonify({"error": True, "detail": str(e)}), 502
|
||||
|
||||
if not resp.ok:
|
||||
try:
|
||||
err = resp.json()
|
||||
detail = err.get("detail", f"HTTP {resp.status_code}")
|
||||
except Exception:
|
||||
detail = f"HTTP {resp.status_code}"
|
||||
return jsonify({"error": True, "detail": detail}), resp.status_code
|
||||
|
||||
from flask import Response as FlaskResponse
|
||||
return FlaskResponse(
|
||||
resp.content,
|
||||
mimetype="application/pdf",
|
||||
headers={
|
||||
"Content-Disposition": resp.headers.get(
|
||||
"Content-Disposition", f'attachment; filename="report.pdf"'
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@statistics_bp.route("/api/report-spc")
|
||||
@login_required
|
||||
@role_required("Metrologist")
|
||||
def api_report_spc():
|
||||
"""Proxy: download SPC PDF report."""
|
||||
return _proxy_report("spc")
|
||||
|
||||
|
||||
@statistics_bp.route("/api/report-measurements")
|
||||
@login_required
|
||||
@role_required("Metrologist")
|
||||
def api_report_measurements():
|
||||
"""Proxy: download measurements PDF report."""
|
||||
return _proxy_report("measurements")
|
||||
|
||||
Reference in New Issue
Block a user