You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

175 lines
5.6 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

from flask import Flask, render_template, request, jsonify, send_file, redirect, url_for, flash
from services import RollCallService, ScoreService
import io
from models import init_db, get_db, Student # 新增导入
import pandas as pd # 新增导入
# 初始化数据库(首次运行创建表)
init_db()
app = Flask(__name__)
app.secret_key = 'your_secret_key' # 用于flash提示
roll_call_service = RollCallService()
score_service = ScoreService()
# 首页
@app.route('/')
def index():
return render_template('index.html')
# 点名页面(支持选择模式)
@app.route('/roll_call')
def roll_call_page():
return render_template('roll_call.html')
# 积分页面(含可视化)
@app.route('/scores')
def scores_page():
class_name = request.args.get('class_name', '软工K班')
chart_base64 = score_service.generate_score_chart(class_name)
return render_template('scores.html', chart_base64=chart_base64, class_name=class_name)
# 新增Excel导入页面
@app.route('/import')
def import_page():
return render_template('import.html')
# APIExcel导入学生 - 修复版本
@app.route('/api/students/import', methods=['POST'])
def import_students(): # 移除嵌套的函数定义
try:
# 检查文件是否存在
if 'excel_file' not in request.files:
return jsonify({'success': False, 'message': '未选择文件'})
file = request.files['excel_file']
# 检查文件名
if file.filename == '':
return jsonify({'success': False, 'message': '未选择文件'})
# 检查文件格式
if not (file.filename.endswith('.xlsx') or file.filename.endswith('.xls')):
return jsonify({'success': False, 'message': '只支持 .xlsx 或 .xls 格式'})
# 读取Excel文件
df = pd.read_excel(file)
required_columns = ['学号', '姓名']
missing_columns = [col for col in required_columns if col not in df.columns]
if missing_columns:
return jsonify({
'success': False,
'message': f'缺少必要列: {", ".join(missing_columns)}'
})
# 检查数据是否为空
if df.empty:
return jsonify({'success': False, 'message': 'Excel文件为空'})
# 数据验证
for index, row in df.iterrows():
if pd.isna(row['学号']) or pd.isna(row['姓名']):
return jsonify({
'success': False,
'message': f'{index + 2}行数据不完整'
})
# 获取数据库会话
db = next(get_db())
# 保存到数据库
students_imported = 0
for index, row in df.iterrows():
# 检查学生是否已存在
existing_student = db.query(Student).filter_by(student_id=str(row['学号'])).first()
if not existing_student:
# 简化:只需要学号和姓名,其他字段使用默认值
student = Student(
student_id=str(row['学号']),
name=row['姓名'],
major='软件工程', # 默认专业
class_name='软工K班', # 默认班级
total_score=0,
call_count=0
)
db.add(student)
students_imported += 1
else:
# 如果学生已存在,更新姓名
existing_student.name = row['姓名']
db.commit()
db.close()
return jsonify({
'success': True,
'message': f'成功导入 {students_imported} 名学生数据'
})
except Exception as e:
# 错误处理
db.rollback()
db.close()
return jsonify({
'success': False,
'message': f'导入失败: {str(e)}'
})
# API点名支持random/order模式
@app.route('/api/roll_call', methods=['POST'])
def roll_call():
data = request.json
class_name = data.get('class_name', '软工K班')
call_mode = data.get('call_mode', 'random') # 新增模式参数
student, msg = roll_call_service.roll_call(class_name, call_mode)
if student:
return jsonify({'success': True, 'data': student.to_dict()})
return jsonify({'success': False, 'message': msg})
# 其他原有API保持不变仅更新积分更新接口
@app.route('/api/scores/update', methods=['POST'])
def update_score():
data = request.json
student_id = data.get('student_id')
answer_type = data.get('answer_type')
performance = data.get('performance')
status = data.get('status', 'present') # 新增到场状态
success, score_delta = roll_call_service.update_student_score(student_id, answer_type, performance, status)
return jsonify({'success': success, 'score_delta': score_delta})
# 新增导出积分详单API复用原有路由内部逻辑已更新
@app.route('/api/scores/export_detailed')
def export_detailed_scores():
class_name = request.args.get('class_name', '软工K班')
excel_data = score_service.export_scores_excel(class_name)
return send_file(
excel_data,
mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
as_attachment=True,
download_name=f'{class_name}_积分详单.xlsx'
)
@app.route('/api/scores/ranking')
def get_class_ranking():
class_name = request.args.get('class_name', '软工K班')
students = score_service.get_class_ranking(class_name)
return jsonify({
'success': True,
'data': [s.to_dict() for s in students]
})
if __name__ == '__main__':
app.run(debug=True, port=5000)