|
|
|
|
import io
|
|
|
|
|
from flask import Flask, request, jsonify, render_template, send_file
|
|
|
|
|
import pandas as pd
|
|
|
|
|
import os
|
|
|
|
|
import random
|
|
|
|
|
from flask_cors import CORS
|
|
|
|
|
|
|
|
|
|
app = Flask(__name__)
|
|
|
|
|
CORS(app)
|
|
|
|
|
|
|
|
|
|
# 学生类,包含姓名、学号和积分
|
|
|
|
|
class Student:
|
|
|
|
|
def __init__(self, id, name, score=0.0):
|
|
|
|
|
self.id = id
|
|
|
|
|
self.name = name
|
|
|
|
|
self.score = score
|
|
|
|
|
|
|
|
|
|
# 从Excel文件中读取学生名单
|
|
|
|
|
def Original_Reading(file):
|
|
|
|
|
df = pd.read_excel(file)
|
|
|
|
|
|
|
|
|
|
# 检查是否存在“积分”列,如果不存在则初始化一个积分列并设置为0
|
|
|
|
|
if '积分' not in df.columns:
|
|
|
|
|
df['积分'] = 0.0
|
|
|
|
|
|
|
|
|
|
students = []
|
|
|
|
|
for i, row in df.iterrows():
|
|
|
|
|
students.append(Student(row['学号'], row['姓名'], row['积分']))
|
|
|
|
|
return students
|
|
|
|
|
|
|
|
|
|
# 从排行榜文件中读取学生名单
|
|
|
|
|
def Leaderboard_Reading(file):
|
|
|
|
|
if not os.path.exists(file):
|
|
|
|
|
return None
|
|
|
|
|
df = pd.read_excel(file)
|
|
|
|
|
s = []
|
|
|
|
|
for i, row in df.iterrows():
|
|
|
|
|
s.append(Student(row['学号'], row['姓名'], row['积分']))
|
|
|
|
|
return s
|
|
|
|
|
|
|
|
|
|
# 随机选择一个学生
|
|
|
|
|
def Select_Student(students):
|
|
|
|
|
total = sum(s.score for s in students)
|
|
|
|
|
if total == 0:
|
|
|
|
|
# 如果总积分为零,所有学生的权重都为1
|
|
|
|
|
w = [1] * len(students)
|
|
|
|
|
else:
|
|
|
|
|
w = [(total - student.score + 1) for student in students]
|
|
|
|
|
selected_student = random.choices(students, weights=w, k=1)[0]
|
|
|
|
|
return selected_student
|
|
|
|
|
|
|
|
|
|
# 更新学生的积分
|
|
|
|
|
def update_score(s, arrived, repeated, correct):
|
|
|
|
|
if arrived == 1:
|
|
|
|
|
s.score += 1.0
|
|
|
|
|
if repeated == 1:
|
|
|
|
|
s.score += 0.5
|
|
|
|
|
elif repeated == 2:
|
|
|
|
|
s.score -= 1.0
|
|
|
|
|
if correct:
|
|
|
|
|
s.score += correct
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 将学生列表转换为DataFrame并按积分从大到小排序
|
|
|
|
|
def students_to_dataframe(students):
|
|
|
|
|
total = sum(s.score for s in students)
|
|
|
|
|
if total == 0:
|
|
|
|
|
# 如果总积分为零,所有学生的权重都为1
|
|
|
|
|
weights = [1] * len(students)
|
|
|
|
|
else:
|
|
|
|
|
weights = [(total - s.score + 1) for s in students]
|
|
|
|
|
|
|
|
|
|
total_weight = sum(weights)
|
|
|
|
|
pro = [weight / total_weight * 100 for weight in weights]
|
|
|
|
|
|
|
|
|
|
data = {'学号': [s.id for s in students],
|
|
|
|
|
'姓名': [s.name for s in students],
|
|
|
|
|
'积分': [s.score for s in students],
|
|
|
|
|
'抽取概率(%)': pro}
|
|
|
|
|
df = pd.DataFrame(data)
|
|
|
|
|
df = df.sort_values(by='积分', ascending=False).reset_index(drop=True)
|
|
|
|
|
return df
|
|
|
|
|
|
|
|
|
|
# 主程序
|
|
|
|
|
students = []
|
|
|
|
|
|
|
|
|
|
@app.route('/')
|
|
|
|
|
def index():
|
|
|
|
|
return render_template('index.html')
|
|
|
|
|
|
|
|
|
|
@app.route('/upload', methods=['POST'])
|
|
|
|
|
def upload_file():
|
|
|
|
|
global students
|
|
|
|
|
file = request.files['file']
|
|
|
|
|
if file and file.filename.endswith('.xlsx'):
|
|
|
|
|
students = Original_Reading(file)
|
|
|
|
|
return jsonify({'success': True})
|
|
|
|
|
return jsonify({'success': False})
|
|
|
|
|
|
|
|
|
|
@app.route('/select_student', methods=['GET'])
|
|
|
|
|
def select_student():
|
|
|
|
|
global students
|
|
|
|
|
if not students:
|
|
|
|
|
return jsonify({'error': 'No students available'})
|
|
|
|
|
selected_student = Select_Student(students)
|
|
|
|
|
return jsonify({'name': selected_student.name, 'id': selected_student.id, 'score': selected_student.score})
|
|
|
|
|
|
|
|
|
|
@app.route('/update_score', methods=['POST'])
|
|
|
|
|
def update_student_score():
|
|
|
|
|
global students
|
|
|
|
|
data = request.json
|
|
|
|
|
student_id = data.get('id')
|
|
|
|
|
arrived = data.get('arrived')
|
|
|
|
|
repeated = data.get('repeated')
|
|
|
|
|
correct = data.get('correct')
|
|
|
|
|
|
|
|
|
|
student = next((s for s in students if s.id == student_id), None)
|
|
|
|
|
if student:
|
|
|
|
|
update_score(student, arrived, repeated, correct)
|
|
|
|
|
return jsonify({'success': True, 'score': student.score})
|
|
|
|
|
return jsonify({'success': False, 'error': '未找到该学生'})
|
|
|
|
|
|
|
|
|
|
@app.route('/export_file', methods=['GET'])
|
|
|
|
|
def export_file():
|
|
|
|
|
global students
|
|
|
|
|
if not students:
|
|
|
|
|
return jsonify({'error': 'No students available'})
|
|
|
|
|
|
|
|
|
|
df = students_to_dataframe(students)
|
|
|
|
|
output = io.BytesIO()
|
|
|
|
|
with pd.ExcelWriter(output, engine='xlsxwriter') as writer:
|
|
|
|
|
df.to_excel(writer, sheet_name='students', index=False)
|
|
|
|
|
output.seek(0)
|
|
|
|
|
return send_file(output, download_name='students.xlsx', as_attachment=True)
|
|
|
|
|
|
|
|
|
|
@app.route('/check_probability', methods=['GET'])
|
|
|
|
|
def check_probability():
|
|
|
|
|
global students
|
|
|
|
|
student_id = request.args.get('id')
|
|
|
|
|
student = next((s for s in students if s.id == student_id), None)
|
|
|
|
|
if student:
|
|
|
|
|
total = sum(s.score for s in students)
|
|
|
|
|
if total == 0:
|
|
|
|
|
probability = 1 / len(students)
|
|
|
|
|
else:
|
|
|
|
|
probability = (total - student.score + 1) / total
|
|
|
|
|
return jsonify({'probability': probability})
|
|
|
|
|
return jsonify({'error': 'Student not found'})
|
|
|
|
|
|
|
|
|
|
@app.route('/select_ten_students', methods=['GET'])
|
|
|
|
|
def select_ten_students():
|
|
|
|
|
global students
|
|
|
|
|
if not students:
|
|
|
|
|
return jsonify({'error': 'No students available'})
|
|
|
|
|
|
|
|
|
|
selected_students = []
|
|
|
|
|
for _ in range(10):
|
|
|
|
|
selected_student = Select_Student(students)
|
|
|
|
|
selected_students.append({
|
|
|
|
|
'name': selected_student.name,
|
|
|
|
|
'id': selected_student.id,
|
|
|
|
|
'score': selected_student.score
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return jsonify({'students': selected_students})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
app.run(debug=True)
|