parent
c429af6d34
commit
2e8bfdc470
@ -0,0 +1,271 @@
|
||||
from flask import Flask, render_template, request, redirect, flash, session
|
||||
import random
|
||||
import atexit
|
||||
import os
|
||||
import sys
|
||||
import database
|
||||
import file_handler
|
||||
|
||||
# 添加当前目录到 Python 路径(必要)
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
# 初始化管理器(必要)
|
||||
db_manager = database.DatabaseManager()
|
||||
file_handler = file_handler.FileHandler()
|
||||
|
||||
app = Flask(__name__)
|
||||
app.secret_key = 'dev'
|
||||
|
||||
def init_database():
|
||||
"""应用启动时初始化数据库连接"""
|
||||
print("应用启动:初始化数据库连接")
|
||||
if db_manager.connect():
|
||||
print("数据库连接初始化成功")
|
||||
return True
|
||||
else:
|
||||
print("数据库连接初始化失败")
|
||||
return False
|
||||
|
||||
def close_database():
|
||||
"""应用关闭时清理数据库连接"""
|
||||
print("应用关闭:清理数据库连接")
|
||||
db_manager.disconnect()
|
||||
|
||||
atexit.register(close_database)
|
||||
|
||||
@app.route('/')
|
||||
def page1():
|
||||
"""主页面"""
|
||||
return render_template('page.html', student=None)
|
||||
|
||||
@app.route('/upload', methods=['POST'])
|
||||
def upload_file():
|
||||
"""上传学生名单文件"""
|
||||
if 'file' not in request.files:
|
||||
flash('没有选择文件')
|
||||
return redirect('/')
|
||||
|
||||
file = request.files['file']
|
||||
|
||||
if file.filename == '':
|
||||
flash('没有选择文件')
|
||||
return redirect('/')
|
||||
|
||||
if file and file_handler.allowed_file(file.filename):
|
||||
try:
|
||||
if not db_manager.connection or not db_manager.connection.is_connected():
|
||||
db_manager.connect()
|
||||
|
||||
processed_data = file_handler.process_for_database(file)
|
||||
|
||||
|
||||
|
||||
# 处理文件上传
|
||||
success = db_manager.process_file_upload(processed_data)
|
||||
|
||||
if success:
|
||||
flash('文件上传成功,新数据已添加到现有数据中')
|
||||
else:
|
||||
flash('数据导入失败')
|
||||
|
||||
return redirect('/')
|
||||
|
||||
except Exception as e:
|
||||
flash(f'文件处理失败: {str(e)}')
|
||||
return redirect('/')
|
||||
else:
|
||||
flash('不允许的文件类型')
|
||||
return redirect('/')
|
||||
|
||||
@app.route('/sequential_roll_call')
|
||||
def sequential_roll_call():
|
||||
"""顺序点名 - 简单循环"""
|
||||
try:
|
||||
if not db_manager.connection or not db_manager.connection.is_connected():
|
||||
db_manager.connect()
|
||||
|
||||
students = db_manager.get_all_students()
|
||||
if not students:
|
||||
flash('没有学生数据,请先上传文件')
|
||||
return redirect('/')
|
||||
|
||||
# 按学号排序
|
||||
sorted_students = sorted(students, key=lambda x: x['id'])
|
||||
|
||||
# 获取上次点名的学生ID
|
||||
last_student_id = session.get('last_student_id')
|
||||
|
||||
if last_student_id:
|
||||
# 找到上次学生的位置
|
||||
current_index = next((i for i, s in enumerate(sorted_students)
|
||||
if s['id'] == last_student_id), -1)
|
||||
# 点下一个学生
|
||||
next_index = (current_index + 1) % len(sorted_students)
|
||||
else:
|
||||
# 第一次点名,点第一个学生
|
||||
next_index = 0
|
||||
|
||||
current_student = sorted_students[next_index]
|
||||
session['last_student_id'] = current_student['id']
|
||||
|
||||
flash(f'顺序点到: {current_student["name"]} (第{next_index + 1}个)')
|
||||
|
||||
return render_template('page.html', student=current_student)
|
||||
|
||||
except Exception as e:
|
||||
flash(f'点名失败: {str(e)}')
|
||||
return redirect('/')
|
||||
|
||||
@app.route('/random_roll_call')
|
||||
def random_roll_call():
|
||||
"""随机点名(积分越低被点概率越高)"""
|
||||
try:
|
||||
if not db_manager.connection or not db_manager.connection.is_connected():
|
||||
db_manager.connect()
|
||||
|
||||
students = db_manager.get_all_students()
|
||||
if not students:
|
||||
flash('没有学生数据,请先上传文件')
|
||||
return redirect('/')
|
||||
|
||||
# 计算权重:分数越低,权重越高
|
||||
weights = []
|
||||
for student in students:
|
||||
weight = 10 + (100 - student['score']) * 0.5
|
||||
weights.append(max(weight, 1))
|
||||
|
||||
selected_student = random.choices(students, weights=weights, k=1)[0]
|
||||
|
||||
# 记录随机点名次数
|
||||
db_manager.increment_random_call_count(selected_student['id'])
|
||||
|
||||
flash(f'随机点到: {selected_student["name"]}')
|
||||
|
||||
# 渲染页面并传递学生信息
|
||||
return render_template('page.html', student=selected_student)
|
||||
|
||||
except Exception as e:
|
||||
flash(f'随机点名失败: {str(e)}')
|
||||
return redirect('/')
|
||||
|
||||
@app.route('/update_score', methods=['POST'])
|
||||
def update_score():
|
||||
"""更新学生分数"""
|
||||
try:
|
||||
if not db_manager.connection or not db_manager.connection.is_connected():
|
||||
db_manager.connect()
|
||||
|
||||
student_id = request.form.get('student_id')
|
||||
action = request.form.get('action')
|
||||
performance = request.form.get('performance', 1)
|
||||
|
||||
student = db_manager.get_student_by_id(student_id)
|
||||
if not student:
|
||||
flash('学生不存在')
|
||||
return redirect('/')
|
||||
|
||||
score_change = 0
|
||||
message = ""
|
||||
|
||||
if action == 'attend':
|
||||
score_change = 1
|
||||
message = f"{student['name']} 到达课堂,+1分"
|
||||
elif action == 'repeat_question_success':
|
||||
score_change = 0.5
|
||||
message = f"{student['name']} 准确重复问题,+0.5分"
|
||||
elif action == 'repeat_question_fail':
|
||||
score_change = -1
|
||||
message = f"{student['name']} 未能重复问题,-1分"
|
||||
elif action == 'answer_question':
|
||||
try:
|
||||
performance_score = float(performance)
|
||||
score_change = min(max(performance_score, 0.5), 3)
|
||||
message = f"{student['name']} 回答问题,+{score_change}分"
|
||||
except:
|
||||
flash('请输入有效的分数')
|
||||
return redirect('/')
|
||||
|
||||
success = db_manager.update_student_score(student_id, score_change)
|
||||
|
||||
if success:
|
||||
flash(message)
|
||||
# 获取更新后的学生信息并传递到页面
|
||||
updated_student = db_manager.get_student_by_id(student_id)
|
||||
return render_template('page.html', student=updated_student)
|
||||
else:
|
||||
flash('更新分数失败')
|
||||
return redirect('/')
|
||||
|
||||
except Exception as e:
|
||||
flash(f'更新分数失败: {str(e)}')
|
||||
return redirect('/')
|
||||
|
||||
@app.route('/export_students')
|
||||
def export_students():
|
||||
"""导出学生数据到Excel"""
|
||||
try:
|
||||
if not db_manager.connection or not db_manager.connection.is_connected():
|
||||
db_manager.connect()
|
||||
|
||||
students = db_manager.get_all_students()
|
||||
if students:
|
||||
exported_file = file_handler.export_to_excel(students)
|
||||
if exported_file:
|
||||
flash(f'导出成功: {exported_file}')
|
||||
else:
|
||||
flash('导出失败')
|
||||
else:
|
||||
flash('导出失败,没有学生数据')
|
||||
|
||||
return redirect('/')
|
||||
|
||||
except Exception as e:
|
||||
flash(f'导出失败: {str(e)}')
|
||||
return redirect('/')
|
||||
|
||||
@app.route('/show_chart')
|
||||
def show_chart():
|
||||
"""直接显示积分图表页面"""
|
||||
try:
|
||||
if not db_manager.connection or not db_manager.connection.is_connected():
|
||||
db_manager.connect()
|
||||
|
||||
students = db_manager.get_all_students()
|
||||
|
||||
if students:
|
||||
chart_data = file_handler.generate_simple_score_chart(students, top_n=10)
|
||||
if chart_data:
|
||||
# 直接渲染包含图表的页面
|
||||
return render_template('chart.html', chart_data=chart_data)
|
||||
|
||||
# 如果没有数据,返回错误信息
|
||||
return render_template('chart.html', error='没有学生数据或生成图表失败')
|
||||
|
||||
except Exception as e:
|
||||
return render_template('chart.html', error=f'生成图表失败: {str(e)}')
|
||||
|
||||
@app.route('/clear_data', methods=['POST'])
|
||||
def clear_data():
|
||||
"""清空学生数据"""
|
||||
try:
|
||||
if not db_manager.connection or not db_manager.connection.is_connected():
|
||||
db_manager.connect()
|
||||
|
||||
success = db_manager.clear_student_data()
|
||||
|
||||
if success:
|
||||
flash('数据清空成功')
|
||||
else:
|
||||
flash('数据清空失败')
|
||||
|
||||
return redirect('/')
|
||||
|
||||
except Exception as e:
|
||||
flash(f'清空数据失败: {str(e)}')
|
||||
return redirect('/')
|
||||
|
||||
if __name__ == '__main__':
|
||||
if init_database():
|
||||
app.run(debug=True, host='0.0.0.0', port=5000)
|
||||
else:
|
||||
print("应用启动失败:数据库连接初始化失败")
|
||||
Loading…
Reference in new issue