1. 项目背景与核心需求
这个点名系统的开发源于高校教学管理的实际痛点。作为一名常年接触教育信息化的开发者,我注意到传统纸质点名或简单电子登记存在几个致命缺陷:数据孤立无法实时同步、无法验证学生身份真实性、与教务系统割裂导致数据重复录入。而市面上成熟的考勤系统又往往价格昂贵、操作复杂,很多学校特别是中小型培训机构难以承担。
基于uniapp的三端统一开发方案完美解决了这些痛点。我们实现了:
- 教师端:网页后台管理(课程/班级/学生管理+考勤报表生成)
- 学生端:微信小程序(扫码签到+个人考勤记录查询)
- 管理端:Android原生APP(数据看板+紧急通知推送)
- 数据层:通过爬虫与学校信息门户对接,自动同步课程表和学生名单
关键设计原则:所有终端共享同一套RESTful API接口,业务逻辑完全由后端处理,前端只负责展示层。这种架构使得后期维护成本降低60%以上。
2. 技术架构解析
2.1 跨端框架选型对比
我们放弃了React Native和Flutter,选择uniapp的核心考量:
- 微信小程序兼容性:uniapp对小程序组件支持度达95%以上
- 开发效率:vue语法+条件编译,三端代码复用率可达85%
- 插件生态:uView UI组件库完美适配教育类应用场景
实际开发中遇到的典型问题:
javascript复制// 条件编译示例(处理各端差异)
// #ifdef MP-WEIXIN
wx.requestVirtualPayment(options)
// #endif
// #ifdef APP-PLUS
uni.requestPayment(options)
// #endif
2.2 爬虫模块设计要点
学校信息门户的反爬机制包括:
- 动态token验证(每次请求需先获取csrfToken)
- 请求频率限制(单IP每分钟不超过30次)
- 行为验证码(仅异常流量触发)
我们的应对方案:
python复制# 使用selenium模拟登录获取cookie
def get_auth_cookie():
driver = webdriver.Chrome(options=chrome_options)
driver.get(login_url)
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "username"))
)
driver.find_element(By.ID,"username").send_keys(username)
driver.find_element(By.ID,"password").send_keys(password)
driver.find_element(By.CLASS_NAME,"submit-btn").click()
return {c['name']:c['value'] for c in driver.get_cookies()}
# 遵守robots.txt规则
REQUEST_DELAY = 3 # 每次请求间隔3秒
重要提示:爬虫必须设置合理的请求间隔(建议≥3秒),避免对学校服务器造成压力。我们曾因测试时忘记加延迟,导致整个信息门户短暂瘫痪,引发电教中心的警告。
3. 核心功能实现细节
3.1 实时考勤业务流程
-
教师创建签到:
- 后台生成含课程ID的动态二维码(有效期15分钟)
- 二维码内容示例:
{"courseId":1024,"expire":1640995200}
-
学生扫码签到:
javascript复制// 小程序端解码逻辑 onScanSuccess(res) { const payload = JSON.parse(res) if(Date.now()/1000 > payload.expire) { return uni.showToast({title: '二维码已过期'}) } this.submitAttendance(payload.courseId) } -
防作弊机制:
- GPS位置校验(允许误差半径500米)
- WiFi SSID匹配(需连接校园网)
- 人脸识别抽查(仅APP端支持)
3.2 数据同步方案对比
| 方案 | 延迟 | 可靠性 | 实现复杂度 |
|---|---|---|---|
| 轮询(Polling) | 高(1min) | 中 | ★★ |
| WebSocket | 低(<1s) | 高 | ★★★★ |
| 长轮询(Long Poll) | 中(10s) | 高 | ★★★ |
最终选择方案:WebSocket用于实时考勤状态推送 + 定时任务(每天2:00AM)全量同步基础数据
4. 性能优化实战记录
4.1 首屏加载加速
问题现象:APP端冷启动时,考勤列表加载需8-12秒
优化步骤:
- 使用Charles抓包分析,发现接口响应时间达6s
- 排查发现N+1查询问题(获取班级列表时未联查学生数)
- 解决方案:
sql复制/* 优化前 */ SELECT id,name FROM classes; SELECT COUNT(*) FROM students WHERE class_id=?; /* 优化后 */ SELECT c.id,c.name,COUNT(s.id) as student_count FROM classes c LEFT JOIN students s ON c.id=s.class_id GROUP BY c.id;
效果:加载时间降至1.3-2秒
4.2 高并发场景处理
压力测试时发现的典型问题:
- 同时200人扫码签到导致数据库连接池耗尽
- 解决方案:
- 引入Redis缓存签到请求
- 使用消息队列削峰填谷
- 数据库连接池从默认20调整为100
java复制// Spring Boot配置示例
@Configuration
public class DataSourceConfig {
@Bean
public HikariDataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setMaximumPoolSize(100);
return new HikariDataSource(config);
}
}
5. 踩坑经验大全
5.1 微信小程序审核被拒
问题:首次提交被拒,原因是"收集用户敏感信息"
解决过程:
- 移除不必要的GPS权限声明
- 在隐私协议中明确说明位置信息仅用于考勤验证
- 补充学校授权证明文件
经验:教育类小程序需特别注意《微信小程序运营规范》第3.5条关于数据收集的规定
5.2 Android后台服务被杀死
现象:APP切换到后台后,考勤结束提醒无法及时推送
解决方案:
- 使用WorkManager安排持久性任务
- 添加前台服务通知(需Android 8.0+适配)
- 引导用户关闭电池优化设置
xml复制<!-- AndroidManifest.xml 配置 -->
<service
android:name=".AttendanceForegroundService"
android:foregroundServiceType="location|connectedDevice" />
6. 扩展功能展望
这套架构其实可以轻松扩展为:
- 在线课堂系统(集成腾讯云TRTC)
- 作业提交平台(对接阿里云OSS)
- 校园社交网络(使用WebSocket实现即时通讯)
我在二次开发中最推荐先实现课堂互动功能,实测使用uniapp的renderjs技术调用WebRTC,可以在小程序和APP上获得一致的视频通话体验。具体实现时要注意:
- 小程序端需使用
和 组件 - APP端直接调用原生WebRTC API
- 网页端采用adapter.js兼容不同浏览器
