from fastapi import FastAPI, File, UploadFile, HTTPException, Body from fastapi.responses import HTMLResponse from starlette.middleware.cors import CORSMiddleware from starlette.staticfiles import StaticFiles from typing import Union, Dict, List from io import BytesIO import pandas as pd import random app = FastAPI() # 假设你的静态文件存放在名为 'static' 的文件夹中 app.mount("/static", StaticFiles(directory="static"), name="static") data: List[Dict[str, Union[str, int]]] = [] students_scores = {} app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) @app.get("/", response_class=HTMLResponse) async def read_root(): # 返回 stu_roll.html 页面 with open("stu_roll.html", "r", encoding="utf-8") as f: return f.read() @app.post("/upload") async def list_upload(file: UploadFile = File(...)): global data, students_scores if file.content_type != "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": return {"message": "错误的文件格式,请重新上传!"} file_content = await file.read() # 使用 openpyxl 作为引擎读取 .xlsx 文件 df = pd.read_excel(BytesIO(file_content), engine='openpyxl') if "学号" not in df.columns or "姓名" not in df.columns: return {"message": "文件中缺少学号或姓名列!"} data = [{"学号": str(row["学号"]).strip(), "姓名": row["姓名"], "积分": 0, "被点名次数": 0} for row in df.to_dict(orient='records')] students_scores = {student["学号"]: 0 for student in data} print(f"Uploaded students: {students_scores}") return {"message": "名单上传成功!", "students": data} # 返回学生数据 @app.get("/roll") def list_roll(enable_random_events: bool = False): if not data: return {"message": "还未上传学生名单,暂无任何数据!"} total_score = sum(students_scores.values()) # 计算所有学生的总积分 # 如果总积分为零,给所有学生相同的权重 if total_score <= 0: weights = [1] * len(data) # 所有学生的权重相同 else: # 计算权重 weights = [total_score - students_scores[student["学号"]] for student in data] # 使用权重进行随机选择 chosen_student = random.choices(data, weights=weights, k=1)[0] # 更新被点名次数 chosen_student["被点名次数"] += 1 print(f"Chosen student: {chosen_student['姓名']} - 被点名次数: {chosen_student['被点名次数']}") # 打印调试信息 print(f"Chosen student: {chosen_student}") # 检查是否有转移权 if chosen_student["被点名次数"] >= 3: chosen_student["被点名次数"] = 0 return {"学号": chosen_student["学号"], "姓名": chosen_student["姓名"], "转移权": True} # 处理随机事件 if enable_random_events: random_event_result = handle_random_events(chosen_student) return {"学号": chosen_student["学号"], "姓名": chosen_student["姓名"], "转移权": False, "随机事件": random_event_result} return {"学号": chosen_student["学号"], "姓名": chosen_student["姓名"], "转移权": False} @app.get("/rank") def list_rank(): if not data: return {"message": "请先上传学生名单!"} sorted_data = sorted(data, key=lambda x: x["积分"], reverse=True) return sorted_data @app.post("/evaluate-answer") async def evaluate_answer( student_id: str = Body(...), is_come: bool = Body(...), can_repeat: bool = Body(...), answer_correct: str = Body(...) ): global students_scores, data score_delta = 0 print( f"Received student_id: {student_id}, is_come: {is_come}, can_repeat: {can_repeat}, answer_correct: {answer_correct}") # 检查学生 ID 是否存在 if student_id not in students_scores: print(f"Student ID {student_id} not found in scores.") raise HTTPException(status_code=404, detail="Student not found.") # 根据回答情况计算积分变化 if is_come: score_delta += 1 if can_repeat: score_delta += 0.5 else: score_delta -= 0.5 if answer_correct == "完全正确": score_delta += 3 elif answer_correct == "部分正确": score_delta += 1.5 else: score_delta -= 1 # 更新 students_scores 字典 students_scores[student_id] += score_delta # 更新 data 列表中的积分 for student in data: if student["学号"] == student_id: student["积分"] += score_delta break print(f"Score updated for student_id: {student_id}, new score: {students_scores[student_id]}") return {"success": True} def handle_random_events(chosen_student): event = random.choice(["mdfucker", "士多啤梨", "吖食啦嘞", "abandon", "疯狂星期四V你50"]) event_description = "" if event == "surprise mdfucker": print(f"{chosen_student['姓名']} surprise mdfucker!") students_scores[chosen_student["学号"]] += 2 chosen_student["积分"] += 2 event_description = "surprise mdfucker" elif event == "士多啤梨": print(f"{chosen_student['姓名']} 士多啤梨!") students_scores[chosen_student["学号"]] += 1 chosen_student["积分"] += 1 event_description = "士多啤梨" if event == "吖食啦嘞": print(f"{chosen_student['姓名']} 吖食啦嘞!") students_scores[chosen_student["学号"]] -= 2 chosen_student["积分"] -= 2 event_description = "吖食啦嘞" if event == "abandon": print(f"{chosen_student['姓名']} abandon!") students_scores[chosen_student["学号"]] -= 1 chosen_student["积分"] -= 1 event_description = "abandon" elif event == "疯狂星期四V你50": if chosen_student["积分"] % 50 == 0: # 积分是50的因数 print(f"{chosen_student['姓名']} 疯狂星期四V你50!") students_scores[chosen_student["学号"]] += 1.5 chosen_student["积分"] += 1.5 event_description = "疯狂星期四V你50" return event_description