36 KiB
实施
阶段 1:统一导航栏
-
1.1 创建统一导航栏模板 【目标对象】
frontend/includes/nav.php(新建) 【修改目的】将所有 admin 页面硬编码的导航栏抽取为共享模板,解决各页面导航不一致的问题;同时修复 dashboard.php 中密码链接passwork.php的拼写错误 【修改方式】新建 PHP 文件,定义导航栏 HTML 结构,直接读取$role和$current_page变量(已由header.php第 17-19 行定义)来动态生成导航项和 active 状态 【相关依赖】frontend/includes/header.php(第 17-19 行已定义$current_page、$user_type、$role变量,在 include nav.php 之前已可用) 【修改内容】 - 直接使用$role和$current_page变量(无需参数传递,因为 header.php 在 nav.php 之前被 include) - 导航项及角色条件统一为: - 首页(dashboard):所有管理员可见 - 学生管理(students):所有管理员可见 - 操行分管理(conduct):$role==='班主任' || $role==='班长' - 作业管理(homework):$role==='班主任' || $role==='学习委员' - 考勤管理(attendance):$role==='班主任' || $role==='考勤委员' - 科目管理(subjects):$role==='班主任' || $role==='学习委员' - 管理员管理(admins):$role==='班主任' - 历史记录(history):所有管理员可见 - 修改密码(password):所有管理员可见 - 根据$current_page(值为不含.php后缀的文件名,如dashboard、students)为当前页面对应的导航项添加activeclass - 密码链接统一写为password.php(修复 dashboard 中passwork.php拼写错误) - 导航栏外层容器沿用现有<div class="nav">结构 -
1.2 各 admin 页面引入统一导航模板 【目标对象】所有
frontend/admin/*.php页面 【修改目的】移除各页面硬编码的<div class="nav">...</div>块,替换为include nav.php,统一导航栏 【修改方式】在以下每个页面中,找到<div class="nav">到对应的</div>之间的导航栏块,整块替换为<?php include __DIR__ . '/../includes/nav.php'; ?>【相关依赖】frontend/includes/nav.php(任务 1.1 创建) 【修改内容】 -frontend/admin/dashboard.php:替换第 25-43 行的<div class="nav">...</div>为 include nav.php -frontend/admin/students.php:替换第 25-43 行的<div class="nav">...</div>为 include nav.php -frontend/admin/conduct.php:替换第 31-47 行的<div class="nav">...</div>为 include nav.php -frontend/admin/homework.php:替换第 31-47 行的<div class="nav">...</div>为 include nav.php(注意:此页面后续会在任务 2.2 完全重写,此处仅替换导航栏部分) -frontend/admin/attendance.php:替换第 31-47 行的<div class="nav">...</div>为 include nav.php(注意:此页面后续会在任务 3.3 完全重写,此处仅替换导航栏部分) -frontend/admin/history.php:替换第 25-43 行的<div class="nav">...</div>为 include nav.php -frontend/admin/subjects.php:替换第 30-48 行的<div class="nav">...</div>为 include nav.php -frontend/admin/admins.php:替换第 30-46 行的<div class="nav">...</div>为 include nav.php -frontend/admin/password.php:替换第 25-43 行的<div class="nav">...</div>为 include nav.php - 替换后需确认 include 语句位于include header.php;之后、页面主体内容之前
阶段 2:作业管理改版
-
2.1 清理
admin.js中废弃的作业管理函数 【目标对象】frontend/assets/js/admin.js【修改目的】移除作业管理改版后不再使用的旧作业管理函数,避免全局函数污染和潜在冲突 【修改方式】删除第 174-220 行的三个函数:showAddAssignmentModal()、loadSubjectsForSelect()、submitAddAssignment()【相关依赖】无(homework.php 将在任务 2.2 完全重写,不再依赖这些全局函数) 【修改内容】 - 删除第 174-178 行的showAddAssignmentModal()函数 - 删除第 180-192 行的loadSubjectsForSelect()函数 - 删除第 194-220 行的submitAddAssignment()函数 - 注意:admin.js中其他通用函数(如submitBatchPoints()、closeModal()、escapeHtml()、toggleSelectAll())保持不变,仍被 conduct.php 和 students.php 使用 -
2.2 重写作业管理前端页面 【目标对象】
frontend/admin/homework.php【修改目的】将作业发布/提交管理模式改为单纯的加减操行分模式,交互方式参照conduct.php【修改方式】完全重写页面 HTML 内容和<script>中的 JavaScript 逻辑(保留文件头部的 PHP 鉴权部分和 include 结构) 【相关依赖】 -frontend/includes/nav.php(任务 1.1,导航栏引入) -frontend/assets/js/admin.js(提供submitBatchPoints()、showBatchPointsModal()、closeModal()、escapeHtml()、toggleSelectAll()等全局复用函数) - 后端 APIGET /api/admin/students(加载学生列表,参见conduct.php第 77-95 行的loadStudents()调用方式) - 后端 APIPOST /api/admin/conduct/add(加减分接口,请求体:{ student_ids: number[], points_change: number, reason: string }) 【修改内容】 - 角色权限判断(第 23 行)统一为in_array($role, ['班主任', '学习委员'])(之前是科代表,与后端admin.py第 228 行的角色检查一致) - 移除发布作业按钮和发布作业模态框 - 移除作业列表和提交记录展示 - 新增学生列表表格(列:复选框、学号、姓名、当前操行分、操作-加减分按钮),参照conduct.php第 57-71 行的表格结构 - 新增批量加减分模态框(复用conduct.php第 116-143 行和students.php第 214-241 行的batchPointsModal模态框结构),包含: - 已选学生数量显示 - 扣分类型快捷选择:未交作业(-2分)、迟交作业(-1分)、自定义(选择后自动填入分数变动输入框) - 分数变动输入框(支持正数加分、负数扣分) - 原因输入框(textarea) - 确认提交按钮 - 页面级 JS 中定义let selectedStudentIds = [];和loadStudents()、showSinglePointsModal()函数(与 conduct.php 和 students.php 的页面级变量风格一致) - 提交时复用admin.js中已有的submitBatchPoints()函数(该函数调用POST /api/admin/conduct/add),reason字段格式如"[作业扣分] 未交作业 - 原因内容"以区分来源 - 错误处理遵循仓库既有风格:调用apiPost()后检查res.success,失败时使用showToast(res.message || '操作失败', 'error')提示(参见admin.js第 57-64 行的submitBatchPoints错误处理模式) - 加载学生列表失败时,在表格区域显示错误提示文本
阶段 3:考勤管理改版
-
3.1 清理
admin.js中废弃的考勤管理函数 【目标对象】frontend/assets/js/admin.js【修改目的】移除考勤管理改版后不再使用的旧考勤添加函数,避免全局函数污染和潜在冲突 【修改方式】删除原始文件第 222-268 行的三个函数(因任务 2.1 已删除第 174-220 行,实际操作时行号已前移约 47 行,请按函数名定位):showAddAttendanceModal()、loadStudentsForSelect()、submitAddAttendance()【相关依赖】任务 2.1(先删除作业相关函数,行号会偏移) 【修改内容】 - 删除showAddAttendanceModal()函数(原始第 222-227 行) - 删除loadStudentsForSelect()函数(原始第 229-238 行) - 删除submitAddAttendance()函数(原始第 241-268 行) - 建议按函数名搜索定位删除,而非依赖行号 - 注意:attendance.php 页面重写后,所有考勤相关 JS 逻辑将在页面级<script>中定义,不依赖admin.js中的旧函数 -
3.2 新增考勤方格网格 CSS 样式 【目标对象】
frontend/assets/css/admin.css【修改目的】为考勤页面的学生方格网格提供样式 【修改方式】在文件末尾追加新样式规则 【相关依赖】无 【修改内容】 -.student-grid容器:display: flex; flex-wrap: wrap; gap: 10px;布局 -.student-cell方格:width: calc(100% / 7 - 10px);(每行 7 个),带边框、圆角、居中文字、内边距、cursor: pointer -.student-cell.selected选中状态:红色/粉色背景高亮(如background: #fee2e2; border-color: #ef4444;) -.student-cell.has-record已有考勤记录标记:灰色虚线边框(如border: 2px dashed #9ca3af;),用于标识当天已有考勤记录的学生 -.student-cell:hover悬停效果:浅色背景变化 -.attendance-toolbar工具栏样式:flex 布局,按钮间距 - 移动端响应式:小屏幕下.student-cell宽度调整为calc(100% / 4 - 10px)或更宽 -
3.3 重写考勤管理前端页面 【目标对象】
frontend/admin/attendance.php【修改目的】将单个学生下拉选择模式改为学生方格网格模式(一行 7 个),选中扣分制 【修改方式】完全重写页面 UI 和<script>中的 JavaScript 逻辑(保留文件头部的 PHP 鉴权部分和 include 结构) 【相关依赖】 -frontend/includes/nav.php(任务 1.1,导航栏引入) -frontend/assets/css/admin.css(任务 3.2,方格网格样式) - 后端 APIGET /api/admin/students(加载学生列表) - 后端 APIPOST /api/admin/attendance(添加考勤记录,请求体:{ student_id: number, date: string, status: string, reason?: string, apply_deduction: boolean }) - 后端 APIGET /api/admin/attendance/records(查询考勤记录,参数:{ date: string }) 【修改内容】 - 页面顶部工具栏:日期选择器(默认当天)+ 考勤状态选择(缺勤/迟到/请假单选按钮组)+ 原因输入框 - 主体区域:加载所有学生,以方格网格展示(使用.student-grid容器和.student-cell方格) - 每个方格显示学生姓名,点击切换选中/取消状态(添加/移除.selectedclass) - 底部工具栏:全选按钮 + 取消全选按钮 + 提交按钮 - 提交逻辑:遍历所有选中的学生,对每个学生调用POST /api/admin/attendance,参数为{ student_id, date, status, reason, apply_deduction: true }- 提交过程中的错误处理:使用Promise.allSettled()并发提交,提交完成后汇总成功/失败数量,使用showToast()提示结果(与仓库既有风格一致) - 重复考勤记录边界处理:后端AttendanceService.add_attendance不检查同一学生同一天是否已有考勤记录,允许重复提交。前端在提交前先调用GET /api/admin/attendance/records获取当天已有记录,对已有考勤记录的学生在方格上添加视觉标记(如.has-record样式,灰色虚线边框),并在提交时confirm()提示"以下学生已有考勤记录,是否继续提交?" - 下方保留历史考勤记录表格:调用GET /api/admin/attendance/records查询指定日期的记录并渲染(参照现有attendance.php第 112-131 行的渲染逻辑) - 移除原有的单个学生下拉选择添加考勤模态框 - 加载学生列表失败时,在网格区域显示错误提示文本 - 错误提示风格遵循仓库既有模式:使用showToast(message, 'error')函数
阶段 4:家长手机号权限控制
- 4.1 家长手机号权限控制
阶段 5:扣分规则配置化
- 5.1 作业和考勤扣分规则配置化
【目标对象】
frontend/.env.example、frontend/config.php、frontend/includes/header.php、frontend/admin/homework.php、frontend/admin/attendance.php【修改目的】将作业和考勤的默认扣分量从 .env 文件配置,前端快捷按钮动态读取配置值,作业加减分有上限限制 【修改方式】 - .env.example 新增6个扣分配置项(有默认值) - config.php 读取并 define 为常量 - header.php 注入到 JS 全局变量 - homework.php 快捷按钮使用配置值 + 自定义输入 + ±HOMEWORK_MAX_POINTS 限制 - attendance.php 状态按钮使用配置值
阶段 6:CORS 跨域拦截修复
- 6.1 注册 AuthMiddleware 为全局中间件并修复 CORS 执行顺序
【目标对象】
backend/main.py、backend/middleware/auth_middleware.py【修改目的】修复 CORS 跨域拦截问题:AuthMiddleware 未注册导致 request.state 属性缺失,路由层 500 错误被浏览器误报为 CORS 错误 【修改方式】 - auth_middleware.py: dispatch 方法顶部添加 OPTIONS 请求跳过逻辑 - main.py: 注册 AuthMiddleware 为全局中间件(先注册后执行),CORS 在 Auth 之后注册(后注册先执行) - main.py: 添加 CORS 配置启动日志和空值警告 【中间件执行顺序】CORS → Auth → access_log → 路由 【后续修复】将 AuthMiddleware 从 BaseHTTPMiddleware 改为纯 ASGI 中间件,解决 BaseHTTPMiddleware 提前返回响应时 CORS 头丢失的问题 【目标对象】frontend/admin/students.php【修改目的】除班主任角色外,隐藏家长手机号列的显示内容,保护隐私 【修改方式】在表头 HTML 和 JS 渲染处添加$role判断 【相关依赖】$_SESSION['role'](已存储在$role变量中,由各页面顶部从 session 读取) 【修改内容】 - 第 68 行表头处:<th>家长手机号</th>改为<?php if ($role === '班主任'): ?><th>家长手机号</th><?php endif; ?>(表头列有条件显示) - 在页面<script>标签开头注入角色信息:const userRole = '<?php echo $role; ?>';- 第 148 行 JS 渲染处:<td>${student.parent_phone || '-'}</td>改为根据userRole判断渲染内容:班主任显示真实手机号,其他角色显示***- 第 156 行空数据提示处:colspan="6"需根据角色动态调整——班主任 6 列,非班主任 5 列(可用 PHP 输出:colspan="<?php echo $role === '班主任' ? '6' : '5'; ?>") - 新增学生表单(第 101-129 行)和导入学生功能中的手机号字段保持不变,任何有学生管理权限的角色都能录入(与 proposal 一致)
阶段 7:修复 AuthMiddleware 401 无限循环
-
7.1 AuthMiddleware 添加调试日志和修复潜在问题 【目标对象】
backend/middleware/auth_middleware.py【修改目的】修复 401 无限循环问题。当前 AuthMiddleware 注册为全局中间件后,所有非公开路径的请求都需要 JWT 认证,但缺少详细日志无法定位 Token 验证失败的具体原因。需要添加详细日志并修复 OPEN_PATHS 未被检查的 Bug。 【修改方式】在 dispatch 方法中添加每个认证步骤的调试日志,修复 OPEN_PATHS 逻辑,添加更多公开路径 【修改内容】 - 在 dispatch 方法中每个关键检查点添加 logger.debug 日志: 1. 请求路径和方法 2. Authorization header 是否存在 3. JWT 验证结果(成功时记录 user_id,失败时记录原因) 4. Redis Token 查询结果(stored_token 是否存在、是否匹配) - 修复 OPEN_PATHS 未被检查的 Bug:在 is_public_path 检查后增加 OPEN_PATHS 检查,OPEN_PATHS 中的路径跳过 Token 验证但仍继续到路由层 - 将/api/auth/me和/api/auth/change-password添加到 PUBLIC_PATHS(目前 OPEN_PATHS 逻辑未被 dispatch 使用,导致这些路径被拦截) -_cors_response方法中的 allowed_origins 改为从 config.settings 读取,而非硬编码 -
7.2 前端 common.js 添加 401 防循环机制 【目标对象】
frontend/assets/js/common.js【修改目的】防止 401 响应导致的无限刷新循环。当前 apiRequest 在收到 401 时直接 clearAuth + redirect,如果用户重新登录后 Token 仍然无效(如 Redis 重启),会形成 401 → 登录 → 401 → 登录的无限循环。 【修改方式】在 401 处理逻辑中添加防循环机制 【修改内容】 - 在 401 处理中添加路径判断:如果当前已在/index.php(登录页),不执行重定向 - 添加重定向频率限制:使用 sessionStorage 记录最近一次 401 重定向时间,如果 5 秒内重复 401,停止重定向并在控制台输出警告 - 清除认证信息后,在跳转前添加延迟或在 URL 中添加标记参数,防止浏览器缓存导致的循环
阶段 8:修复 302 循环 - 401 时同步清除 PHP Session
- 8.1 修复 302 循环 - 401 时同步清除 PHP Session
【目标对象】
frontend/assets/js/common.js【修改目的】修复 PHP Session 与 JWT Token 不同步导致的 302 无限重定向循环。当 JWT Token 无效(如后端重启后 Redis 清空)导致 API 返回 401 时,clearAuth()只清除了 localStorage 中的 JWT Token,但 PHP Session 仍然有效,导致index.php第 15-23 行检测到有效 Session 后又 302 重定向到 dashboard,形成循环。 【修改方式】在apiRequest函数的 401 处理逻辑中,clearAuth()之后增加对/api/clear_session.php的 POST 调用,以同步清除 PHP Session 【修改内容】 - 在clearAuth()调用后、路径检查之前,添加fetch('/api/clear_session.php', { method: 'POST', headers: { 'Content-Type': 'application/json' } })调用 - 使用 try-catch 包裹,失败时仅输出 console.warn 警告,不阻塞后续重定向逻辑 -/api/clear_session.php是同源路径(由 Nginx 直接处理,不经过后端 FastAPI),不需要 Authorization header,也不会触发跨域问题
阶段 9:修复 500 响应 CORS 头丢失 + admin.js 变量重复声明
-
9.1 修复 500 响应 CORS 头丢失 【目标对象】
backend/middleware/auth_middleware.py【修改目的】当路由层抛出异常导致 500 时,BaseHTTPMiddleware 的 call_next 返回的 500 响应不会经过 CORSMiddleware,导致 CORS 头缺失。浏览器报告"CORS Missing Allow Origin",前端无法读取错误信息。 【修改方式】在 dispatch 方法中将return await call_next(request)改为 try-except 包裹,确保所有响应都有 CORS 头 【修改内容】 - 用 try-except 包裹call_next(request)调用 - 在 try 中获取 response 后检查是否已有 CORS 头,若无则补充 - 在 except 中捕获路由层异常,返回带 CORS 头的 500 响应 -
9.2 修复 admin.js selectedStudentIds 重复声明 【目标对象】
frontend/assets/js/admin.js、frontend/admin/conduct.php、frontend/admin/homework.php【修改目的】admin.js 通过 footer.php 在所有 admin 页面加载,其let selectedStudentIds = []与 conduct.php 和 homework.php 页面级<script>中的同名声明冲突,导致 SyntaxError 【修改方式】将let改为var,var允许重复声明 【修改内容】 - admin.js 第12-16行:let→var(4个变量声明) - conduct.php 第59行:let selectedStudentIds = []→var selectedStudentIds = []- homework.php 第94行:let selectedStudentIds = []→var selectedStudentIds = []
阶段 10:修复 500 Internal Server Error - SQL 引用不存在的 class_id 列
- 10.1 修复代码与数据库 schema 不匹配问题(13个文件)
阶段 11:修复 422 参数校验 + JS 变量重复声明 + RANK() 兼容性
- 11.1 修复历史记录页 422 和 JS 变量声明问题
- 11.2 修复首页 RANK() OVER 窗口函数兼容性
阶段 12:全面项目审查 - 消灭潜在问题
-
12.1 修复后端角色名"科代表"→"学习委员"(3处)+ 存储过程缺失 + 权限逻辑 + security工具类 【目标对象】
backend/services/conduct_service.py、backend/services/homework_service.py、backend/models/conduct.py、backend/middleware/permission.py、backend/utils/security.py【修改目的】1) "科代表"角色在数据库ENUM中不存在,应为"学习委员";2) revoke_conduct_record存储过程在init.sql中不存在,需替换为内联SQL;3) get_user_subject_ids方法逻辑顺序有误;4) validate_points_change返回类型不一致 【修改方式】 - conduct_service.py 第58行:elif role in ["科代表", "考勤委员"]:→elif role in ["学习委员", "考勤委员"]:- homework_service.py 第35行:elif role == "科代表":→elif role == "学习委员":- homework_service.py 第82行:if role == "科代表":→if role == "学习委员":- conduct.py revoke_record方法: 替换call_procedure('revoke_conduct_record', ...)为内联SQL:UPDATE conduct_records SET is_revoked=1, revoked_by=%s, revoked_at=NOW() WHERE record_id=%s,使用execute_update执行 - permission.py get_user_subject_ids: 调整逻辑顺序,先检查role_type是否为班主任,再检查subject_id - security.py 第126行:return f"单次分值变动不能超过{max_abs}分"→return False, f"单次分值变动不能超过{max_abs}分" -
12.2 修复前端学生端/家长端关键问题 + 管理端小问题 + 配置修复 【目标对象】
frontend/student/dashboard.php、frontend/api/save_session.php、frontend/index.php、frontend/student/attendance.php、frontend/admin/homework.php、frontend/config.php、frontend/student/conduct_history.php【修改目的】1) student/dashboard.php的common.js加载顺序错误导致API函数未定义;2) save_session.php将user_id错误存储为student_id;3) student/dashboard.php中hw.subject字段名错误;4) homework.php重复调用loadStudents;5) config.php中ICP_ENABLED逻辑反转;6) conduct_history.php文件为空 【修改方式】 - student/dashboard.php: 将<script src="/assets/js/common.js"></script>移到内联script之前;删除局部const API_BASE_URL和const JWT_STORAGE_KEY/USER_STORAGE_KEY,改用window.API_BASE_URL = '<?php echo API_BASE_URL; ?>'等全局变量(在common.js加载之前设置);将hw.subject改为hw.subject_name- save_session.php: 第106行$_SESSION['student_id'] = $data['user_id'];改为从请求中获取实际student_id:$_SESSION['student_id'] = $data['student_id'] ?? $data['user_id'];;同时添加student_id到requiredFields验证(仅学生时必须) - index.php: 登录成功后save_session调用中添加student_id: userData.student_id参数 - student/attendance.php: 第21行$student_id = $_SESSION['student_id'];保持不变(修复save_session后此值会正确) - admin/homework.php: 删除第176行重复的loadStudents();调用 - config.php: 第61行define('ICP_ENABLED', $config['ICP_ENABLED'] === 'false');改为define('ICP_ENABLED', $config['ICP_ENABLED'] !== 'false');- student/conduct_history.php: 文件为空,需要重定向到dashboard或创建基本页面。最简方案:创建一个重定向到 /student/dashboard.php 的页面 【目标对象】backend/models/attendance.py、backend/services/attendance_service.py、backend/models/conduct.py、backend/services/conduct_service.py、backend/models/homework.py、backend/services/homework_service.py、backend/models/student.py、backend/middleware/permission.py、backend/services/auth_service.py、backend/schemas/student.py、backend/schemas/admin.py、backend/services/student_service.py、backend/routes/student.py【修改目的】数据库 schema(单班级系统)中students和assignments表没有class_id列,但后端代码中大量 SQL 引用了该列,导致 MySQL 报错 → 500 Internal Server Error。同时PermissionChecker.get_user_subject_ids()和check_can_manage_student()方法不存在但被调用。 【修改方式】全面移除所有class_id引用(单班级系统不需要),添加缺失的方法 【修改内容】 - attendance.py: get_class_records 移除 class_id 参数和 WHERE 条件 - attendance_service.py: 移除 class_id 传参和 check_can_manage_student 调用 - conduct.py: 移除 class_id 过滤条件 - conduct_service.py: 移除 class_id 传参和 check_can_manage_student 调用 - homework.py: 所有方法移除 class_id,get_assignments_by_class 重命名为 get_all_assignments - homework_service.py: 移除 class_id 传参 - student.py: create 方法移除 class_id 参数和 INSERT 列 - permission.py: 添加 get_user_subject_ids 和 check_can_manage_student 方法 - auth_service.py: 移除 class_id 和 class_name 引用 - schemas/student.py 和 schemas/admin.py: 移除 class_id 和 class_name 字段 - student_service.py 和 routes/student.py: 移除 class_id 参数 -
12.3 修复CRITICAL: total_points在所有Service中从未更新(操行分系统完全失效) 【目标对象】
backend/services/conduct_service.py、backend/services/attendance_service.py、backend/services/homework_service.py【修改目的】StudentModel.update_total_points()方法已存在但从未被调用,导致students.total_points永远保持初始值60分,排行榜、仪表盘、家长端显示的所有总分都是错误的 【修改方式】 - conduct_service.py add_points: 在ConductModel.create_record()后添加await StudentModel.update_total_points(student_id, points_change)- conduct_service.py revoke_record: 重写撤销逻辑,先获取原记录,撤销后调用await StudentModel.update_total_points(record["student_id"], -record["points_change"])反向恢复总分 - attendance_service.py add_attendance: 在ConductModel.create_record()后添加await StudentModel.update_total_points(student_id, points_change)- homework_service.py update_submission_status: 在ConductModel.create_record()后添加await StudentModel.update_total_points(submission["student_id"], points_change) -
12.4 修复前端: student/homework.php字段名 + nav.php劳动委员 + parent/attendance.php死链 【目标对象】
frontend/student/homework.php、frontend/includes/nav.php、frontend/parent/attendance.php【修改目的】1) homework.php中hw.subject字段名与后端API不匹配;2) 劳动委员无法在导航栏看到操行分管理入口(README要求±1分权限);3) parent/attendance.php有指向不存在的/parent/homework.php的死链接 【修改方式】 - student/homework.php 第56行:hw.subject→hw.subject_name- nav.php 第4行: 添加|| $role === '劳动委员'到操行分管理导航条件 - parent/attendance.php: 删除指向不存在的 /parent/homework.php 的死链接,导航只保留"首页"和"考勤记录" -
12.5 修复学生端导航死链接: 3个页面的"操行分"链接指向不存在的/student/conduct.php 【目标对象】
frontend/student/homework.php、frontend/student/attendance.php、frontend/student/password.php【修改目的】学生端3个子页面导航栏中的"操行分"链接指向/student/conduct.php,但实际文件名是conduct_history.php,导致404 【修改方式】 - password.php 第26行:/student/conduct.php→/student/conduct_history.php -
12.6 修复劳动委员页面级权限被拦截 + 仪表盘快捷操作缺失 【目标对象】
frontend/admin/conduct.php、frontend/admin/dashboard.php【修改目的】README规定劳动委员有操行分管理权限(±1分),但conduct.php页面级权限检查只允许班主任和班长访问,劳动委员会被重定向到dashboard;dashboard.php快捷操作也缺少劳动委员 【修改方式】 - conduct.php 第23行:['班主任', '班长']→['班主任', '班长', '劳动委员']- conduct.php 第115行: 分数变动提示文字改为 if/elseif/else 结构,劳动委员显示"劳动委员仅限±1分" - dashboard.php 第61行: 快捷操作条件添加劳动委员 - attendance.php 第27行:/student/conduct.php→/student/conduct_history.php- password.php 第26行:/student/conduct.php→/student/conduct_history.php -
12.7 同步学生端dashboard.php页眉(使用header.php/footer.php) 【目标对象】
frontend/student/dashboard.php【修改目的】学生端dashboard.php使用自定义HTML结构,与管理端不统一,缺少共享页眉和ICP备案号 【修改方式】 - 移除自定义的<!DOCTYPE html>,<head>,<body>和自定义 header div - 添加$page_title = '学生端'; include __DIR__ . '/../includes/header.php';- 移除重复的window.API_BASE_URL等变量设置(header.php已处理) - 添加include __DIR__ . '/../includes/footer.php';以显示ICP备案号 -
12.8 登录页面补充备案号悬挂 【目标对象】
frontend/index.php【修改目的】登录页面的页脚缺少ICP备案号 【修改方式】 - 在登录页 footer 的版权信息后,添加ICP备案号链接(使用ICP_ENABLED和ICP_NUMBER常量) - 链接指向 https://beian.miit.gov.cn/,target="_blank" -
12.9 修复用户报告的4个运行时Bug 【目标对象】
backend/schemas/admin.py、frontend/admin/conduct.php、frontend/admin/homework.php、frontend/admin/attendance.php【修改目的】用户报告:1) 历史记录在加减分后无内容; 2) 管理员无法添加学生; 3) 加减分页面仅显示21人; 4) 管理端修改密码失败 【修改方式】 - 12.9a 历史记录问题:已在12.3中通过添加StudentModel.update_total_points()调用修复 - 12.9b 添加学生422错误:add_student路由使用裸函数参数而非Pydantic body,FastAPI从query string读取导致422。创建AddStudentRequestschema,路由改用Pydantic body - 12.9c 仅显示21人:loadStudents()未传page_size,后端默认20。前端3个文件添加{page_size: 1000}- 12.9d 修改密码:已确认代码正确(sha1_md5_password+need_change_password=0) -
12.10 修复登录及管理员日志未写入数据库 【目标对象】
backend/models/log.py(新建)、backend/services/log_service.py(新建)、backend/services/auth_service.py、backend/routes/auth.py、backend/routes/admin.py【修改目的】数据库中login_logs和operation_logs表已存在,但没有任何后端代码写入数据。README中规划了models/operation_log.py和services/log_service.py,但文件不存在 【修改方式】 - 新建backend/models/log.py:包含LoginLogModel和OperationLogModel,分别向 login_logs 和 operation_logs 表写入记录 - 新建backend/services/log_service.py:LogService提供write_login_log和write_operation_log方法,用 try-except 包裹确保日志写入失败不影响主业务 - 修改auth_service.py:login 方法增加user_agent参数,在5个退出点(失败次数过多、用户不存在、密码错误、账号禁用、登录成功)均写入 login_logs - 修改auth.py:从 HTTP 请求头获取 user-agent 并传递给 AuthService.login() - 修改admin.py:8个管理操作成功后写入 operation_logs(import_students、add_student、add_points、revoke_record、create_assignment、update_submission、add_attendance、add_admin) -
12.11 修复CRITICAL: 登录返回数据缺少student_id导致学生端完全无法工作 【目标对象】
backend/services/auth_service.py、backend/routes/auth.py【修改目的】登录成功后返回给前端的数据中没有 student_id 字段,导致 index.php 无法传递 student_id 给 save_session.php,Session 中缺少 student_id,学生端所有页面 $student_id 为 null,所有 API 调用路径变成 /api/student/conduct/null 导致失败。这是学生端显示"假数据"的根本原因 【修改方式】 - auth_service.py: login 方法返回字典添加"student_id": user["student_id"]- auth.py: 登录路由 success_response data 字典添加"student_id": result.get("student_id") -
12.12 批量修复6个管理端/学生端Bug 【目标对象】
backend/models/user.py、backend/routes/admin.py、frontend/assets/js/admin.js、backend/services/conduct_service.py、backend/models/conduct.py、frontend/admin/history.php【修改目的】用户报告6个运行时Bug:1) 修改密码失败;2) 管理端学生列表422;3) 添加管理员404;4) admin.js报错null;5) 历史记录500;6) history.php学生列表不完整 【修改方式】 - user.py: get_by_user_id SQL 添加 password_hash 字段(修改密码时验证旧密码需要此字段) - admin.py: page_size 上限 le=100→le=1000;路由 /admin/add→/add, /admin/list→/list(避免双重/api/admin前缀) - admin.js: showAddAdminModal 中 addAdminForm.reset() 改为 ?.reset() - conduct_service.py: get_history 方法开头添加空字符串→None转换 - conduct.py: get_all_records 方法开头添加空字符串→None转换 - history.php: loadStudentsForSelect 传 {page_size: 1000} -
12.13 修复强制改密"原密码错误" + 科目管理/管理员管理500错误确认 【目标对象】
backend/schemas/auth.py、backend/services/auth_service.py、backend/routes/auth.py、frontend/student/dashboard.php【修改目的】用户报告3个Bug:1) 学生端首次登录强制改密时没有原密码输入框,但提交后报"原密码错误";2) 科目管理页/api/subject/list返回500;3) 管理员管理页/api/admin/list返回500 【修改方式】 - schemas/auth.py: ChangePasswordRequest中old_password改为可选(default=""),新增force字段(bool, default=False) - auth_service.py: change_password方法新增force参数,当force=True时跳过旧密码验证 - auth.py: change_password路由从请求中读取force参数传递给服务层 - dashboard.php: 强制改密请求中添加force:true, old_password设为空字符串 - 科目管理500和管理员管理500: 经代码审查确认代码逻辑正确(SQL、路由、模型均无问题),500错误为后端服务未重启导致旧代码仍在运行 -
12.14 添加全局异常处理器 + 4个500路由添加try-except + 历史记录page_size上限修复 【目标对象】
backend/main.py、backend/routes/subject.py、backend/routes/admin.py、backend/routes/student.py【修改目的】用户确认后端已重启但仍报500,4个路由持续返回500 Internal Server Error(科目管理、管理员管理、历史记录、学生端操行分)。无法直接查看后端日志,需通过全局异常处理器和路由级try-except捕获具体错误原因 【修改方式】 - main.py: 添加全局异常处理器 global_exception_handler,捕获所有未处理异常,返回包含str(exc)的message和可选的traceback detail(仅DEBUG模式) - subject.py: get_subjects路由添加try-except,新增logger导入 - admin.py: get_admins和get_conduct_history路由添加try-except;get_conduct_history的page_size参数le=100→le=1000 - student.py: get_conduct_history路由添加try-except,新增logger导入