# =========================================== # 班级操行分管理系统 - 管理端路由 # # 开发者: Canglan # 联系方式: admin@sea-studio.top # 版权归属: Sea Network Technology Studio # 许可证: MIT License # # 版权所有 © Sea Network Technology Studio # =========================================== from fastapi import APIRouter, Request, Query, UploadFile, File from typing import Optional, List import json from middleware.permission import ( get_current_user, require_teacher, require_monitor, PermissionChecker ) from services.admin_service import AdminService from services.conduct_service import ConductService from services.homework_service import HomeworkService from services.attendance_service import AttendanceService from schemas.admin import ( AddPointsRequest, RevokeRequest, AddAdminRequest, UpdateHomeworkStatusRequest, AddAttendanceRequest ) from utils.response import success_response, error_response, paginated_response from utils.logger import get_logger from config import settings router = APIRouter() logger = get_logger(__name__) # ========== 学生管理 ========== @router.get("/students") async def get_students( request: Request, page: int = Query(1, ge=1), page_size: int = Query(20, ge=1, le=100), search: Optional[str] = None ): """ 获取所有学生列表(单班级) """ user = await get_current_user(request) result = await AdminService.get_students( page=page, page_size=page_size, search=search ) return success_response(data=result) @router.post("/students/import") async def import_students( request: Request, file: UploadFile = File(...) ): """ 批量导入学生(JSON格式) 初始操行分默认为60分 """ user = await get_current_user(request) # 检查权限(仅班主任) is_teacher = await PermissionChecker.check_is_teacher(user["user_id"]) if not is_teacher: return error_response(message="仅班主任可导入学生", code=403) # 检查文件大小 content = await file.read() file_size = len(content) if file_size > settings.MAX_UPLOAD_SIZE: return error_response(message=f"文件大小不能超过{settings.MAX_UPLOAD_SIZE // 1024 // 1024}MB") # 检查文件扩展名 filename = file.filename or "" extension = filename.split('.')[-1].lower() if '.' in filename else '' if extension not in settings.ALLOWED_EXTENSIONS: return error_response(message=f"不支持的文件类型,仅支持 {', '.join(settings.ALLOWED_EXTENSIONS)}") # 解析JSON try: data = json.loads(content.decode('utf-8')) students = data.get("students", []) except json.JSONDecodeError as e: return error_response(message=f"JSON格式错误: {str(e)}") except UnicodeDecodeError: return error_response(message="文件编码错误,请使用UTF-8编码") if not students: return error_response(message="文件中没有学生数据") # 导入学生(初始操行分60分) result = await AdminService.import_students( students=students, operator_id=user["user_id"], initial_points=60 ) return success_response(data=result, message=f"导入完成: 成功{result['success_count']}人,失败{result['failed_count']}人") @router.post("/students") async def add_student( request: Request, student_no: str, name: str, parent_phone: Optional[str] = None ): """ 新增学生 """ user = await get_current_user(request) is_teacher = await PermissionChecker.check_is_teacher(user["user_id"]) if not is_teacher: return error_response(message="仅班主任可新增学生", code=403) result = await AdminService.add_student( student_no=student_no, name=name, parent_phone=parent_phone, operator_id=user["user_id"], initial_points=60 ) if result["success"]: return success_response(data=result, message="学生添加成功") else: return error_response(message=result["message"]) # ========== 操行分管理 ========== @router.post("/conduct/add") async def add_conduct_points(request: Request, req: AddPointsRequest): """ 批量加减分 """ user = await get_current_user(request) result = await ConductService.add_points( student_ids=req.student_ids, points_change=req.points_change, reason=req.reason, recorder_id=user["user_id"], recorder_name=user["username"] ) if result["success"]: return success_response(data=result, message="操作成功") else: return error_response(message=result["message"]) @router.post("/conduct/revoke") async def revoke_conduct_record(request: Request, req: RevokeRequest): """ 撤销扣分记录 """ user = await get_current_user(request) result = await ConductService.revoke_record( record_id=req.record_id, revoker_id=user["user_id"] ) if result["success"]: return success_response(message="撤销成功") else: return error_response(message=result["message"]) @router.get("/conduct/history") async def get_conduct_history( request: Request, student_id: Optional[int] = None, page: int = Query(1, ge=1), page_size: int = Query(20, ge=1, le=100), start_date: Optional[str] = None, end_date: Optional[str] = None ): """ 获取操行分历史记录 """ user = await get_current_user(request) result = await ConductService.get_history( user_id=user["user_id"], student_id=student_id, page=page, page_size=page_size, start_date=start_date, end_date=end_date ) return success_response(data=result) # ========== 作业管理 ========== @router.get("/homework/assignments") async def get_assignments(request: Request): """ 获取作业列表 """ user = await get_current_user(request) result = await HomeworkService.get_assignments(user["user_id"]) return success_response(data=result) @router.get("/homework/submissions/{assignment_id}") async def get_submissions(request: Request, assignment_id: int): """ 获取作业提交记录 """ user = await get_current_user(request) result = await HomeworkService.get_submissions( assignment_id=assignment_id, user_id=user["user_id"] ) return success_response(data=result) @router.post("/homework/assignment") async def create_assignment( request: Request, subject_id: int, title: str, description: Optional[str] = None, deadline: str = None ): """ 发布作业(班主任) """ user = await get_current_user(request) is_teacher = await PermissionChecker.check_is_teacher(user["user_id"]) if not is_teacher: return error_response(message="仅班主任可发布作业", code=403) result = await HomeworkService.create_assignment( subject_id=subject_id, title=title, description=description, deadline=deadline, created_by=user["user_id"] ) if result["success"]: return success_response(data=result, message="作业发布成功") else: return error_response(message=result["message"]) @router.put("/homework/submission") async def update_submission_status(request: Request, req: UpdateHomeworkStatusRequest): """ 更新作业提交状态(科代表) """ user = await get_current_user(request) result = await HomeworkService.update_submission_status( submission_id=req.submission_id, status=req.status, comments=req.comments, apply_deduction=req.apply_deduction, operator_id=user["user_id"] ) if result["success"]: return success_response(message="状态更新成功") else: return error_response(message=result["message"]) # ========== 考勤管理 ========== @router.post("/attendance") async def add_attendance(request: Request, req: AddAttendanceRequest): """ 添加考勤记录(考勤委员) """ user = await get_current_user(request) result = await AttendanceService.add_attendance( student_id=req.student_id, date=str(req.date), status=req.status, reason=req.reason, apply_deduction=req.apply_deduction, recorder_id=user["user_id"] ) if result["success"]: return success_response(message="考勤记录添加成功") else: return error_response(message=result["message"]) @router.get("/attendance/records") async def get_attendance_records( request: Request, date: Optional[str] = None, student_id: Optional[int] = None ): """ 获取考勤记录 """ user = await get_current_user(request) result = await AttendanceService.get_records( user_id=user["user_id"], date=date, student_id=student_id ) return success_response(data=result) # ========== 管理员管理 ========== @router.post("/admin/add") async def add_admin(request: Request, req: AddAdminRequest): """ 添加管理员(班主任) """ user = await get_current_user(request) is_teacher = await PermissionChecker.check_is_teacher(user["user_id"]) if not is_teacher: return error_response(message="仅班主任可添加管理员", code=403) result = await AdminService.add_admin( username=req.username, real_name=req.real_name, password=req.password, role_type=req.role_type, operator_id=user["user_id"] ) if result["success"]: return success_response(data=result, message="管理员添加成功") else: return error_response(message=result["message"]) @router.get("/admin/list") async def get_admins(request: Request): """ 获取管理员列表(班主任) """ user = await get_current_user(request) is_teacher = await PermissionChecker.check_is_teacher(user["user_id"]) if not is_teacher: return error_response(message="仅班主任可查看管理员列表", code=403) result = await AdminService.get_admins() return success_response(data=result)