"""班级管理和考勤路由""" from datetime import date from flask import render_template, request, redirect, url_for, flash, session from models import (db, Class_, Course, Teacher, Student, ClassStudent, StudentAccount, AttendanceRecord) from utils import ( login_required, log_operation, permission_required, export_excel, filter_classes_query, filter_students_query, teacher_can_access_class, ) def register_routes(app): @app.route('/classes', endpoint='class_list') @login_required @permission_required('class_view') def class_list(): keyword = request.args.get('keyword', '') query = filter_classes_query(Class_.query) if keyword: query = query.filter(Class_.name.contains(keyword)) classes = query.order_by(Class_.id.desc()).all() courses = {c.id: c.name for c in Course.query.all()} teachers = {t.id: t.name for t in Teacher.query.all()} return render_template('class_list.html', classes=classes, courses=courses, teachers=teachers, keyword=keyword) @app.route('/classes/add', methods=['GET', 'POST'], endpoint='class_add') @login_required @permission_required('class_add') def class_add(): if request.method == 'POST': cls = Class_( name=request.form.get('name'), course_id=int(request.form.get('course_id')), teacher_id=int(request.form.get('teacher_id')), max_students=int(request.form.get('max_students', 20)), status=int(request.form.get('status', 1)), remark=request.form.get('remark', '') ) db.session.add(cls) db.session.commit() log_operation('创建班级', f'班级:{cls.name}') flash('班级创建成功', 'success') return redirect(url_for('class_list')) courses = Course.query.filter_by(status=1).all() teachers = Teacher.query.filter_by(status=1).all() return render_template('class_form.html', class_=None, courses=courses, teachers=teachers) @app.route('/classes/edit/', methods=['GET', 'POST'], endpoint='class_edit') @login_required @permission_required('class_edit') def class_edit(id): cls = db.session.get(Class_, id) if request.method == 'POST': cls.name = request.form.get('name') cls.course_id = int(request.form.get('course_id')) cls.teacher_id = int(request.form.get('teacher_id')) cls.max_students = int(request.form.get('max_students', 20)) cls.status = int(request.form.get('status', 1)) cls.remark = request.form.get('remark', '') db.session.commit() log_operation('编辑班级', f'班级ID:{id}') flash('班级更新成功', 'success') return redirect(url_for('class_list')) courses = Course.query.filter_by(status=1).all() teachers = Teacher.query.filter_by(status=1).all() return render_template('class_form.html', class_=cls, courses=courses, teachers=teachers) @app.route('/classes/detail/', endpoint='class_detail') @login_required @permission_required('class_view') def class_detail(id): cls = db.session.get(Class_, id) if not cls: flash('班级不存在', 'danger') return redirect(url_for('class_list')) course = db.session.get(Course, cls.course_id) if cls else None teacher = db.session.get(Teacher, cls.teacher_id) if cls else None class_students = ClassStudent.query.filter_by(class_id=id, status=1).all() attendance_records = ( AttendanceRecord.query.filter_by(class_id=id) .order_by(AttendanceRecord.date.desc(), AttendanceRecord.id.desc()) .limit(20) .all() ) student_ids = [cs.student_id for cs in class_students] students = {s.id: s for s in Student.query.filter(Student.id.in_(student_ids)).all()} if student_ids else {} # 计算可用学生(未在该班级的) enrolled_ids = set(student_ids) base = filter_students_query(Student.query.filter_by(status=1)) available_students = base.filter(~Student.id.in_(enrolled_ids)).all() if enrolled_ids else base.all() return render_template('class_detail.html', class_=cls, course=course, teacher=teacher, class_students=class_students, students=students, available_students=available_students, attendance_records=attendance_records) @app.route('/classes//add_student', methods=['POST'], endpoint='class_add_student') @login_required @permission_required('class_edit') def class_add_student(class_id): student_id = int(request.form.get('student_id')) existing = ClassStudent.query.filter_by(class_id=class_id, student_id=student_id, status=1).first() if existing: flash('该学员已在班级中', 'warning') else: cs = ClassStudent(class_id=class_id, student_id=student_id, join_date=date.today(), status=1) db.session.add(cs) db.session.commit() log_operation('添加班级学员', f'班级ID:{class_id} 学员ID:{student_id}') flash('学员添加成功', 'success') return redirect(url_for('class_detail', id=class_id)) @app.route('/classes//remove_student/', endpoint='class_remove_student') @login_required @permission_required('class_edit') def class_remove_student(class_id, student_id): cs = ClassStudent.query.filter_by(class_id=class_id, student_id=student_id, status=1).first() if cs: cs.status = 0 db.session.commit() log_operation('移除班级学员', f'班级ID:{class_id} 学员ID:{student_id}') flash('学员已移除', 'success') return redirect(url_for('class_detail', id=class_id)) @app.route('/classes//attendance', methods=['GET', 'POST'], endpoint='class_attendance') @login_required @permission_required('attendance_add') def class_attendance(class_id): cls = db.session.get(Class_, class_id) if not cls: flash('班级不存在', 'danger') return redirect(url_for('class_list')) class_students = ClassStudent.query.filter_by(class_id=class_id, status=1).all() student_ids = [cs.student_id for cs in class_students] students = {s.id: s for s in Student.query.filter(Student.id.in_(student_ids)).all()} if student_ids else {} if request.method == 'POST': att_date_str = request.form.get('att_date') or date.today().isoformat() att_date = __import__('datetime').datetime.strptime(att_date_str, '%Y-%m-%d').date() for cs in class_students: status = request.form.get(f'status_{cs.student_id}', 'present') remark = request.form.get(f'remark_{cs.student_id}', '') record = AttendanceRecord( class_id=class_id, student_id=cs.student_id, date=att_date, status=status, remark=remark ) db.session.add(record) db.session.commit() log_operation('考勤录入', f'班级ID:{class_id} 日期:{att_date_str}') flash('考勤录入成功', 'success') return redirect(url_for('class_detail', id=class_id)) return render_template('attendance_form.html', class_=cls, class_students=class_students, students=students, today=date.today().isoformat()) @app.route('/attendance', endpoint='attendance_select') @login_required @permission_required('attendance_view') def attendance_select(): """考勤入口:选择班级""" classes = filter_classes_query(Class_.query.filter_by(status=1)).all() courses = {c.id: c.name for c in Course.query.all()} return render_template('attendance_select.html', classes=classes, courses=courses) @app.route('/classes/export', endpoint='class_export') @login_required @permission_required('class_export') def class_export(): from utils import export_classes as do_export return do_export()