feat: update assessment portal

This commit is contained in:
2026-07-06 16:53:06 +08:00
parent a75e857c71
commit f385f9747b
17 changed files with 1866 additions and 884 deletions
+92 -10
View File
@@ -17,14 +17,32 @@ from flask import (
url_for,
)
from flask_login import current_user, login_required, login_user, logout_user
from sqlalchemy.orm import joinedload
from .config import BASE_DIR
from .extensions import db
from .models import UploadRecord, User
from .models import AppSetting, UploadRecord, User
from .prediction import PredictionError, run_prediction
from .security import new_captcha
bp = Blueprint("main", __name__)
REFERENCE_PDF_NAME = "20260630标准文本——供水管道健康状态与剩余寿命评估技术导则.pdf"
REGISTRATION_SETTING_KEY = "allow_registration"
RECORDS_PER_PAGE = 10
def registration_allowed() -> bool:
return AppSetting.get_bool(
REGISTRATION_SETTING_KEY,
current_app.config["ALLOW_REGISTRATION"],
)
def requested_page() -> int:
try:
return max(int(request.args.get("page", 1)), 1)
except (TypeError, ValueError):
return 1
@bp.route("/")
@@ -64,12 +82,13 @@ def login():
@bp.route("/register", methods=["GET", "POST"])
def register():
if not current_app.config["ALLOW_REGISTRATION"]:
abort(404)
if request.method == "GET":
return render_template("login.html", mode="register", captcha="")
if not registration_allowed():
flash("当前未开放自助注册,请联系管理员。", "error")
return render_template("login.html", mode="register", captcha=""), 403
username = request.form.get("username", "").strip()
password = request.form.get("password", "")
@@ -108,12 +127,19 @@ def home():
@bp.route("/history")
@login_required
def history_page():
records = (
page = requested_page()
pagination = (
UploadRecord.query.filter_by(user_id=current_user.id)
.order_by(UploadRecord.upload_time.desc())
.all()
.paginate(page=page, per_page=RECORDS_PER_PAGE, error_out=False)
)
if pagination.pages and page > pagination.pages:
return redirect(url_for("main.history_page", page=pagination.pages))
return render_template(
"history.html",
pagination=pagination,
records=pagination.items,
)
return render_template("history.html", records=records)
@bp.route("/admin")
@@ -121,8 +147,44 @@ def history_page():
def admin_dashboard():
if not current_user.is_admin:
abort(403)
records = UploadRecord.query.order_by(UploadRecord.upload_time.desc()).all()
return render_template("admin.html", records=records)
page = requested_page()
pagination = (
UploadRecord.query.options(joinedload(UploadRecord.user))
.order_by(UploadRecord.upload_time.desc())
.paginate(page=page, per_page=RECORDS_PER_PAGE, error_out=False)
)
if pagination.pages and page > pagination.pages:
return redirect(url_for("main.admin_dashboard", page=pagination.pages))
return render_template(
"admin.html",
pagination=pagination,
records=pagination.items,
registration_allowed=registration_allowed(),
)
@bp.route("/admin/registration", methods=["POST"])
@login_required
def update_registration_setting():
if not current_user.is_admin:
abort(403)
allow_registration = request.form.get("allow_registration") == "on"
AppSetting.set_bool(REGISTRATION_SETTING_KEY, allow_registration)
db.session.commit()
message = "已开放用户自助注册" if allow_registration else "已关闭用户自助注册"
if request.headers.get("X-Requested-With") == "XMLHttpRequest":
return jsonify(
{
"message": message,
"registration_allowed": allow_registration,
"status_label": "已开放" if allow_registration else "已关闭",
}
)
flash(message, "info")
return redirect(url_for("main.admin_dashboard"))
@bp.route("/download/<int:record_id>/<file_type>")
@@ -152,6 +214,26 @@ def download_template():
return send_file(template_path, as_attachment=True, download_name="example.xlsx")
@bp.route("/reference_pdf")
@login_required
def reference_pdf():
pdf_path = BASE_DIR / REFERENCE_PDF_NAME
if not pdf_path.exists():
abort(404)
return send_file(
pdf_path,
as_attachment=False,
download_name=REFERENCE_PDF_NAME,
mimetype="application/pdf",
)
@bp.route("/reference")
@login_required
def reference_page():
return render_template("reference.html")
@bp.route("/result")
@login_required
def result_page():
@@ -197,7 +279,7 @@ def predict():
"excel_url": url_for("main.download_file", record_id=record.id, file_type="prediction"),
"result_url": url_for("main.result_page"),
"sample_count": int(artifacts.sample_count),
"summary_rows": artifacts.summary_rows[:3],
"summary_rows": artifacts.summary_rows[:6],
"analysis_text": artifacts.analysis_text,
}
session["last_result"] = last_result