"""仪表盘路由""" from datetime import date, datetime from flask import render_template from sqlalchemy import func from sqlalchemy.orm import joinedload from models import ( db, Student, Course, Teacher, Class_, StudentAccount, MonthlySnapshot, ConsumptionRecord, ) from utils import login_required from keshi_display import get_latest_period, snapshot_lessons_display from keshi_stats import period_overview, monthly_trend_from_snapshots import business_rules as rules def register_routes(app): @app.route('/', endpoint='dashboard') @app.route('/dashboard', endpoint='dashboard') @login_required def dashboard(): today = date.today() py, pm = get_latest_period() period_label = f'{py}-{pm:02d}' if py and pm else '' total_students = Student.query.filter_by(status=1).count() total_courses = Course.query.filter_by(status=1).count() total_teachers = Teacher.query.filter_by(status=1).count() total_classes = Class_.query.filter_by(status=1).count() month_recharge = 0.0 month_consumption = 0.0 if py and pm: ov = period_overview(py, pm) month_recharge = ov['recharge'] month_consumption = ov['consumed_hours'] today_consumption = ConsumptionRecord.query.filter( ConsumptionRecord.consume_date == today, ).count() recent_recharges = [] threshold = rules.LOW_HOURS_WARNING_THRESHOLD low_hours_accounts = [] if py and pm: snaps = ( MonthlySnapshot.query.options( joinedload(MonthlySnapshot.account).joinedload(StudentAccount.student), joinedload(MonthlySnapshot.account).joinedload(StudentAccount.course), ) .filter(MonthlySnapshot.year == py, MonthlySnapshot.month == pm) .all() ) candidates = [] for s in snaps: acc = s.account if not acc or not acc.student: continue disp = snapshot_lessons_display(s, acc) total_h = disp.get('end_total_lessons') if total_h is None: continue th = float(total_h) if 0 < th <= threshold: candidates.append((acc, th, disp)) candidates.sort(key=lambda x: x[1]) low_hours_accounts = candidates[:8] recent_consumptions = ConsumptionRecord.query.order_by( ConsumptionRecord.consume_date.desc(), ).limit(8).all() trend = monthly_trend_from_snapshots() monthly_chart = [] max_amount = 1.0 for item in trend[-6:]: amt = float(item['recharge']) max_amount = max(max_amount, amt) monthly_chart.append({ 'label': item['label'], 'amount': amt, 'is_current': item['month'] == period_label, }) if not monthly_chart: max_amount = 1.0 hour = datetime.now().hour if hour < 12: greeting = '早上好' elif hour < 18: greeting = '下午好' else: greeting = '晚上好' return render_template( 'dashboard.html', greeting=greeting, monthly_chart=monthly_chart, chart_max=max_amount, recent_consumptions=recent_consumptions, total_students=total_students, total_courses=total_courses, total_teachers=total_teachers, total_classes=total_classes, month_recharge=float(month_recharge), month_consumption=float(month_consumption), today_consumption=today_consumption, recent_recharges=recent_recharges, low_hours_accounts=low_hours_accounts, period_label=period_label, )