修复日期: 2026-04-21
修复版本: v0.2.1
问题描述:
- 项目使用 ESLint 9,但配置还停留在旧的
.eslintrc.*格式 .eslintignore文件已废弃,导致警告
修复方案:
- ✅ 创建新的
eslint.config.js文件,符合 ESLint 9 标准 - ✅ 移除了废弃的
.eslintignore文件 - ✅ 配置包含 TypeScript 解析器和正确的 ignores 设置
文件修改:
新增:eslint.config.js删除:.eslintignore
验证:
npm run lint # 现在正常运行,无警告
npm run type-check # TypeScript 类型检查通过问题描述:
- 每次管理员手动调节学生的出缺席状态时,都会立即调用
fetchRecords()刷新整个列表 - 同时存在 10 秒自动刷新间隔
- 结果:用户每次操作都会看到明显的页面闪烁和卡顿
根本原因:
AttendanceRecords.tsx中的handleChangeStatus()函数在第 543 和 561 行无条件调用fetchRecords(weekNumber)
修复方案:
- ✅ 移除了
handleChangeStatus()中的立即刷新逻辑 - ✅ 改为让 10 秒的自动刷新间隔来处理数据更新
- ✅ 保留错误提示,但不再刷新(等待自动刷新)
改动代码:
// 修改前:
if (response.ok) {
fetchRecords(weekNumber); // 立即刷新 ❌
} else {
const data = await response.json();
alert('创建失败:' + (data.error || '未知错误'));
}
// 修改后:
if (!response.ok) {
const data = await response.json();
alert('创建失败:' + (data.error || '未知错误'));
}
// 不立即刷新,让自动刷新间隔处理 ✅文件修改:
修改:src/components/attendance/AttendanceRecords.tsx(第 515-573 行)
效果:
- ✅ 用户点击状态按钮时不再卡顿
- ✅ 10 秒后自动更新显示新状态
- ✅ 提升了用户体验
问题描述:
- 管理员为学生点名后,该学生有时会出现在另一个时段
- 例如:学生在时段 1 (15:20) 被标记为出席,但却出现在时段 2 (16:35) 中
- 这会导致出席统计混乱
根本原因分析:
-
API 数据不一致:
- 前端使用
record.$id作为 recordId - 后端期望的格式是
studentId_sessionNumber_weekNumber - 但前端生成的 pending 记录 ID 格式为
pending_${studentId}_${sessionTime}_week${weekNumber} - 导致格式不匹配
- 前端使用
-
sessionTime 设置错误:
- 在
src/app/api/attendance/record/route.ts第 191 行 - 创建新记录时设置
sessionTime: session${sessionNumber} - 这是一个占位符字符串,不是实际时间(如 "15:20" 或 "16:35")
- 后端在分类时匹配不到真实的时段
- 在
-
时段匹配逻辑混乱:
- 在
src/app/api/attendance/records/route.ts中 - isSession1/isSession2 函数包含多个匹配条件:
- 检查 uniqueKey 中的 sessionNumber
- 检查 sessionTime 是否等于配置值
- 使用 30 分钟容差范围
- 当 sessionTime 为 "session1" 或 "session2" 时,容差逻辑会出错
- 在
修复方案:
✅ 修复 1: 正确设置 sessionTime
// 修改前:
sessionTime: `session${sessionNumber}`, // ❌ 错误
// 修改后:
// 获取实际的时段配置
let sessionTimeStr = sessionNumber === 1 ? '15:20' : '16:35';
try {
const settingsDoc = await serverDatabases.getDocument(
databaseId,
CLUB_SETTINGS_COLLECTION_ID,
ATTENDANCE_CONFIG_DOC_ID
);
if (sessionNumber === 1 && settingsDoc.attendanceSession1Start) {
const s1 = JSON.parse(String(settingsDoc.attendanceSession1Start));
sessionTimeStr = `${s1.hour}:${String(s1.minute).padStart(2, '0')}`;
} else if (sessionNumber === 2 && settingsDoc.attendanceSession2Start) {
const s2 = JSON.parse(String(settingsDoc.attendanceSession2Start));
sessionTimeStr = `${s2.hour}:${String(s2.minute).padStart(2, '0')}`;
}
} catch (configErr) {
console.warn(`无法获取时段配置,使用默认值: ${sessionTimeStr}`, configErr);
}
sessionTime: sessionTimeStr, // ✅ 正确的时间字符串✅ 修复 2: 使用 uniqueKey 而不是 $id
// 前端修改:使用 uniqueKey 作为 recordId
onClick={() => handleChangeStatus(record.uniqueKey || record.$id, 'present', record)}
// 原因:
// - uniqueKey 格式: studentId_sessionNumber_weekNumber 或 studentId_sessionTime_weekNumber
// - 这是后端期望的格式
// - $id 格式不一致,可能导致查找失败文件修改:
修改:src/app/api/attendance/record/route.ts(第 156-216 行)修改:src/components/attendance/AttendanceRecords.tsx(多处使用 uniqueKey)
具体改动:
// AttendanceRecords.tsx 中的改动
// 所有状态按钮现在使用:
onClick={() => handleChangeStatus(record.uniqueKey || record.$id, newStatus, record)}
// updatingId 的检查也改为:
disabled={updatingId === (record.uniqueKey || record.$id)}
{updatingId === (record.uniqueKey || record.$id) ? ...}效果:
- ✅ 记录 ID 格式一致性提高
- ✅ 时段分类准确
- ✅ 学生不再跑到另一个时段
- ✅ 出席统计准确
| 文件 | 类型 | 改动 |
|---|---|---|
eslint.config.js |
新增 | ESLint 9 兼容配置 |
.eslintignore |
删除 | 已废弃(配置转移到 eslint.config.js) |
src/components/attendance/AttendanceRecords.tsx |
修改 | 移除刷新逻辑,使用 uniqueKey |
src/app/api/attendance/record/route.ts |
修改 | 正确设置 sessionTime,获取配置 |
npm run lint # 应无错误和警告
npm run type-check # TypeScript 类型检查通过场景 1: 手动调节考勤状态
- 打开
/admin/attendance页面 - 点击学生行的"出席"、"迟到"、"缺席"按钮
- 预期行为:
- 按钮有加载动画
- 不会立即刷新整个列表
- 10 秒后自动更新状态显示
场景 2: 时段分类准确性
- 初始化时段 1 和时段 2
- 为学生在时段 1 标记"出席"
- 预期行为:
- 学生仅出现在"时段 1"部分
- 不会同时出现在时段 2
- 重复测试时段 2
场景 3: 手动修改配置后
- 在系统设置中修改时段开始时间
- 创建新的考勤记录
- 预期行为:
- 新记录使用更新后的时间
- 时段分类基于新配置正确
✅ 类型检查: npm run type-check 通过
✅ Lint 检查: npm run lint 通过(无新错误)
✅ 代码格式: 符合项目规范
✅ 向后兼容: 不破坏现有功能
-
考虑减少自动刷新频率
- 当前: 10 秒刷新一次全局数据
- 建议: 增加到 15-30 秒,或改为仅在用户操作后刷新
-
添加离观察者模式
- 使用 WebSocket 实时更新,而不是定时轮询
- 减少服务器负载和网络流量
-
完善错误处理
- 考勤状态变化失败时,需要通知用户
- 可添加 toast 通知或其他 UI 反馈
-
性能优化
- 只刷新变化的部分,而不是整个列表
- 使用 React 的 key 和 memo 优化渲染
- 这些修复基于对代码的分析,建议在测试环境中验证
- 特别是时段分类逻辑,应与实际使用场景对应
- 如果仍有问题,检查数据库中的
clubSettingscollection 中的时段配置