Files
SharedClassManager/.cospec/plan/changes/fix-admin-multi-issues/task.md
2026-04-14 14:11:06 +08:00

17 KiB
Raw Blame History

实施

阶段 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 后缀的文件名,如 dashboardstudents)为当前页面对应的导航项添加 active class - 密码链接统一写为 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() 等全局复用函数) - 后端 API GET /api/admin/students(加载学生列表,参见 conduct.php 第 77-95 行的 loadStudents() 调用方式) - 后端 API POST /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/addreason 字段格式如 "[作业扣分] 未交作业 - 原因内容" 以区分来源 - 错误处理遵循仓库既有风格:调用 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,方格网格样式) - 后端 API GET /api/admin/students(加载学生列表) - 后端 API POST /api/admin/attendance(添加考勤记录,请求体:{ student_id: number, date: string, status: string, reason?: string, apply_deduction: boolean } - 后端 API GET /api/admin/attendance/records(查询考勤记录,参数:{ date: string } 【修改内容】 - 页面顶部工具栏:日期选择器(默认当天)+ 考勤状态选择(缺勤/迟到/请假单选按钮组)+ 原因输入框 - 主体区域:加载所有学生,以方格网格展示(使用 .student-grid 容器和 .student-cell 方格) - 每个方格显示学生姓名,点击切换选中/取消状态(添加/移除 .selected class - 底部工具栏:全选按钮 + 取消全选按钮 + 提交按钮 - 提交逻辑:遍历所有选中的学生,对每个学生调用 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.examplefrontend/config.phpfrontend/includes/header.phpfrontend/admin/homework.phpfrontend/admin/attendance.php 【修改目的】将作业和考勤的默认扣分量从 .env 文件配置,前端快捷按钮动态读取配置值,作业加减分有上限限制 【修改方式】 - .env.example 新增6个扣分配置项有默认值 - config.php 读取并 define 为常量 - header.php 注入到 JS 全局变量 - homework.php 快捷按钮使用配置值 + 自定义输入 + ±HOMEWORK_MAX_POINTS 限制 - attendance.php 状态按钮使用配置值

阶段 6CORS 跨域拦截修复

  • 6.1 注册 AuthMiddleware 为全局中间件并修复 CORS 执行顺序 【目标对象】backend/main.pybackend/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 中添加标记参数,防止浏览器缓存导致的循环