资讯动态

微信小程序课堂交互系统:云开发实现签到抢答与测验看板

发布时间:2026/10/26 17:46:29 来源:尧图企业网站定制
简介一份基于微信小程序的师生课堂交互系统毕业设计项目资源面向需要完成类似选题的高校计算机专业学生与小程序开发者解决课堂互动、考勤、作业、成绩管理等场景的快速搭建问题。压缩包内含一百五十二个文件大小约四百五十四KB包括七十八个JavaScript逻辑文件、二十二个WXSS样式文件、十七个WXML页面结构文件以及JSON配置、SQL数据库脚本和说明文档前端交互与后端数据均可直接参考。项目覆盖课程管理、作业提交与批改、讨论区、位置考勤签到、成绩查询等核心模块并引入图表与地图定位等扩展能力适合作为毕业设计或课程设计的起点。已有一百七十四人学习下载读者可借此快速理解小程序端教学工具的实现思路、代码组织方式以及从需求分析到测试调试的完整流程。1. 师生课堂交互系统能签到、能抢答、能出成绩单的微信小程序毕业设计工程做毕业设计选「基于微信小程序的师生课堂交互系统」这个题的人大半是奔着微信小程序生态来的学生不用装 App、扫码即进课堂上的签到、抢答、随堂测验都能在微信里完成演示起来比网页系统有画面感。但这个题的真实难度在于它不是把几个页面拼一起就完事——签到要处理定位精度和防代签抢答要扛住全班同时点击的并发教师端还得把一堆原始记录聚合成能看的图表。我第一次拆这类工程时光是让签到从「能点到」变成「可信」就重写了三版。这份资源解决的就是这件事一套把课程管理、定位签到、限时抢答、随堂测验、教师数据看板串成完整闭环的小程序工程前端是原生微信小程序后端走微信云开发的云函数和云数据库不用自己买服务器、配 HTTPS导入微信开发者工具就能跑通全流程。适合三类人做毕业设计的学生、想给学院快速搭课堂工具的老师、第一次接触云开发想找个完整工程拆开看的小程序学习者。下面按我拆解这个工程的实际顺序讲先看架构和选型再逐模块复现核心代码最后是真正会卡住你的那些坑。2. 先看骨架再动手模块划分、云开发选型与数据表设计2.1 功能模块拆解学生端、教师端和公共模块各自的边界一个完整的师生课堂交互系统功能上绝不是「有个页面能聊天」就行。我拆这份资源时把它分成三大块每块的边界非常清楚。学生端负责的是参与类操作课程列表与课程码加入、定位签到、限时抢答、随堂测验作答。教师端负责的是管理类操作创建课程、生成课程码、发起签到会话并设置教室坐标和签到半径、出题、开启测验。公共模块则是登录建档、角色识别以及最重要的会话状态管理——一次签到或抢答从 open 到 closed 的完整生命周期都要有状态控制。边界划分的关键在于学生端所有操作只能针对「当前已加入的课程」教师端所有操作只能针对「自己创建的课程」。权限判断放在云函数里做而不是放在小程序前端——因为前端的 setData、页面跳转、甚至 wx.request 的入参都是可以伪造的真正防越权要靠云端校验 openid 和角色。我说句实在话评阅老师最常问的问题就是「你怎么防止学生把自己的签到记录改成别人的」你能答出「权限全部在云函数侧校验、前端不可信」这一句答辩这一关基本就稳了一半。2.2 云开发 vs Spring Boot选型理由和成本账很多毕业设计默认选「小程序 Spring Boot MySQL」这个经典组合理由很充分后台管理界面好做、数据库表结构是面试能聊的亮点。但如果你不是冲着「必须要有独立后端」这个硬性要求去的云开发的性价比明显更高这也是这份资源选它的原因。先说明白云开发解决了什么传统前后端分离你要准备服务器、域名、HTTPS 证书、MySQL还要自己处理 token 签发和鉴权。云开发把这几件事全部内置了——云函数里直接上下文取 OPENID云数据库自带权限体系静态资源可放云存储。对一个课堂交互系统来说它没有跑批任务、没有海量数据、没有跨库事务云开发免费额度完全够用还省掉了买服务器和备案的折腾。两种方案我列个对比维度云开发方案Spring Boot MySQL服务器与运维不需要环境由微信托管需购买云服务器学生机也有成本登录鉴权云函数自动带 openid自写 code2Session token 签发数据库云数据库自带权限控制自建表、自己写连接池部署开发者工具右键上传打包、上传、配端口、配域名适合场景快速跑通完整业务闭环导师硬性要求独立后端我一般建议这样选型如果开题报告明确写了「前后端分离」「数据库设计」这类字眼那就老老实实走 Spring Boot如果只要求「完整可运行、能演示业务闭环」云开发版本能让你把省下来的时间花在把业务做完整上。这份资源主体是云开发版本后面所有代码都按云函数加云数据库来讲。但原理是通用的——你把云函数里的校验逻辑搬到自己写的 Controller 里数据表换成 MySQL 的建表语句迁移成本并不高。2.3 工程目录与数据表设计先把集合关系理清楚拿到工程先别急着预览把目录结构过一遍。原生小程序加云开发的工程通常长这样project/ ├── cloudfunctions/ # 云函数目录每个子目录一个函数 │ ├── login/ # 登录建档 │ ├── checkIn/ # 签到时间窗口 距离校验 写入 │ ├── getQuiz/ # 拉取测验题目剥掉答案字段 │ ├── submitQuiz/ # 提交答案并判分 │ └── rush/ # 抢答状态机 并发去重 ├── miniprogram/ │ ├── pages/ │ │ ├── index/ # 课程列表页 │ │ ├── login/ # 登录页 │ │ ├── teacher/ # 教师端建课、发起签到、看板 │ │ └── student/ # 学生端签到、抢答、测验 │ ├── ec-canvas/ # ECharts 小程序图表组件 │ ├── app.js │ ├── app.json │ └── project.config.json云数据库的集合设计我按业务对象拆成六张「表」集合名关键字段说明usersopenid、role、nickname、avatar学生和教师同一张表靠 role 区分coursesname、teacherOpenid、code、className课程码 code 用于学生加入sessionscourseId、startTime、roomLat、roomLng、radius、status一次签到/互动会话checkinssessionId、openid、distance、checkTime签到明细天然是统计分析的数据源quizzescourseId、title、questions、startTime、duration题目数组内嵌quiz_resultsquizId、openid、score、answers测验成绩明细这里有个设计取舍值得说题目我以内嵌数组的方式存在 quizzes 文档里而不是单独拆 questions 表和 options 表。原因很简单课堂测验的题目量级是十道左右内嵌数组一次云函数就能整份拉完拆成关联表反而要多做几次 get 再在云函数里组装答辩演示时白白增加出问题的概率。判断标准就一条数据是否需要跨集合关联查询不需要就别拆。3. 登录与签到链路openid 直取、手机号授权与防代签的距离校验3.1 登录云端直接取 OPENID前端不碰 code在自建后端的方案里登录链路是前端 wx.login() 拿 codePOST 给后端后端拿 code 调 code2Session 换 openid再自己签发 token。这个链路本身没问题但有一个必踩的坑code 五分钟内只能用一次后端缓存过期、并发重放都会导致控制台出现 40029 这类「invalid code」报错。用云开发的话这一整段被简化了云函数里直接读上下文// cloudfunctions/login/index.js const cloud require(wx-server-sdk) cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) exports.main async (event) { // 云函数上下文直接带 openid不用再拿 code 去换 const { OPENID, APPID } cloud.getWXContext() const db cloud.database() const users db.collection(users) // 首次登录建档老用户只更新昵称头像 const existed await users.where({ openid: OPENID }).get() if (existed.data.length 0) { await users.add({ data: { openid: OPENID, nickname: event.nickname || 同学 OPENID.slice(-4), avatar: event.avatar || , role: event.role || student, createTime: db.serverDate() } }) } else { await users.doc(existed.data[0]._id).update({ data: { nickname: event.nickname, avatar: event.avatar } }) } return { openid: OPENID, appid: APPID } }这段代码里最核心的是cloud.getWXContext()——云开发替你完成 code2Session 之后把 openid 直接塞进函数上下文你省掉的不仅是一段 HTTP 调用还省掉了 token 过期、刷新、重放这整套鉴权问题。前端登录页只需要把用户填写的昵称头像随云函数调用传上去返回的 openid 存到全局变量备用即可本地不需要存任何登录态。参数上注意event.role这个字段默认是 student教师账号我建议由管理员在云开发控制台手工把某个 openid 的 role 改成 teacher而不是开放前端随意传否则学生改个入参就能拿到教师权限。3.2 手机号获取能不用就别用个人主体用不了关于「微信小程序登录获取手机号」多说一句getPhoneNumber 这个能力现在走的是手机号快速验证组件要求小程序是企业主体且完成微信认证个人主体的毕业设计项目开通不了而且这个组件按调用次数计费。课堂交互系统里手机号并不是必要字段我建议默认不做学号做成手动填写的字段展示标识就用 openid 后四位。如果你确实要拿真实手机号做教务通知再去考虑企业认证——认证费用是企业主体一年 300 元的服务费这笔预算应该写进开题报告别等到答辩前两周才发现功能开通不了。3.3 定位签到坐标系、精度参数与三道防代签校验签到模块是这套系统的核心亮点也是翻车率最高的地方。先看学生端发定位的代码// miniprogram/pages/student/checkin/checkin.js Page({ startCheckIn() { wx.getLocation({ type: gcj02, // 国测局坐标系微信地图/腾讯地图都用它 isHighAccuracy: true, // 开启高精度定位iOS 上必开 highAccuracyExpireTime: 3000, // 高精度定位最长等待时间单位毫秒 success: (res) { this.doCheckIn(res.latitude, res.longitude) }, fail: (err) { wx.showModal({ title: 拿不到位置, content: 请检查微信的位置权限以及手机系统定位开关, confirmText: 去设置, success: (r) { if (r.confirm) wx.openSetting() // 引导用户去授权页 } }) } }) }, doCheckIn(latitude, longitude) { wx.cloud.callFunction({ name: checkIn, data: { courseId: this.courseId, sessionId: this.sessionId, latitude, longitude } }).then(res { const r res.result wx.showToast({ title: r.valid ? 签到成功距教室 ${r.distance} 米 : r.reason, icon: none }) }) } })两个参数值得记一下。第一个是type: gcj02小程序返回的经纬度默认就是 gcj02 坐标系俗称「火星坐标系」和 GPS 的 WGS84 之间有几十到几百米的偏移。如果你拿到的教室坐标是从 GPS 设备里导出的没转坐标系就会出现「明明站在教室里却提示距离过远」的玄学问题。第二个是highAccuracyExpireTime它表示高精度定位最多等多久设太短拿不到高精度结果设太长在室内会一直转圈我一般设 3000 毫秒。云端校验逻辑是防代签的第一道闸// cloudfunctions/checkIn/index.js const cloud require(wx-server-sdk) cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) function distance(lat1, lon1, lat2, lon2) { const rad Math.PI / 180 const dLat (lat2 - lat1) * rad const dLon (lon2 - lon1) * rad const a Math.sin(dLat / 2) ** 2 Math.cos(lat1 * rad) * Math.cos(lat2 * rad) * Math.sin(dLon / 2) ** 2 return 6371000 * 2 * Math.asin(Math.sqrt(a)) } exports.main async (event) { const { OPENID } cloud.getWXContext() const { sessionId, latitude, longitude } event const db cloud.database() // 1) 读取会话与教室坐标 const session await db.collection(sessions) .doc(sessionId).get().then(r r.data) // 2) 时间窗口开课前 15 分钟到开课后 30 分钟内可签 const now Date.now() const start new Date(session.startTime).getTime() if (now start - 15 * 60 * 1000 || now start 30 * 60 * 1000) { return { valid: false, reason: 不在签到时间窗口内 } } // 3) 距离校验以教室坐标为中心radius 米内算到场 const d distance(latitude, longitude, session.roomLat, session.roomLng) if (d session.radius) { return { valid: false, reason: 距教室 ${Math.round(d)} 米超出范围, distance: Math.round(d) } } // 4) 写入签到记录 await db.collection(checkins).add({ data: { sessionId, openid: OPENID, latitude, longitude, distance: Math.round(d), checkTime: db.serverDate() } }) return { valid: true, distance: Math.round(d) } }三个可调参数时间窗口、签到半径、是否允许重复签到。时间窗口按课堂节奏设我一般用「课前 15 分钟到课后 30 分钟」签到半径看教室大小阶梯教室设 300 米普通教室 200 米太严会误伤走廊上排队进教室的同学。距离校验只能防「不在现场的人」防不了「同学之间互相代签」所以要叠加第二道和第三道校验动态课程码和签到频次限制。教师每次发起会话时生成四位随机码学生端必须输入课程码才能签到同时云函数里对这个 openid 在该 sessionId 下做 count 判断已有记录就直接拒绝一个微信只能签一次。4. 课堂互动三件套并发抢答、单选框测验与数据看板柱状图4.1 抢答状态机控制时间窗口事务保证并发去重抢答是课堂交互系统里最容易翻车的功能原因是它天然是并发场景全班三四十个人同时点抢答按钮如果逻辑写在前端后点的人也能改数据如果写在云函数里但不做原子控制就会出现两个人几乎同时写入、都以为自己抢到的怪事。我的做法是把抢答设计成「限时状态机」教师发起抢答后状态变为 open到截止时间或有人答对后变为 closed学生端只在 open 期间能提交// cloudfunctions/rush/index.js const cloud require(wx-server-sdk) cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) exports.main async (event) { const { OPENID } cloud.getWXContext() const { rushId, answer } event const db cloud.database() // 1) 读抢答会话先判断状态窗口 const rush await db.collection(rushes).doc(rushId).get().then(r r.data) const now Date.now() const deadline new Date(rush.deadline).getTime() if (rush.status ! open || now deadline) { return { ok: false, msg: 抢答已结束 } } // 2) 同一个学生只允许抢答一次 const existed await db.collection(rush_answers) .where({ rushId, openid: OPENID }).count() if (existed.total 0) { return { ok: false, msg: 你已经抢过了 } } // 3) 事务写入防止并发窗口穿透 const tx await db.startTransaction() const result await tx.collection(rush_answers).add({ data: { rushId, openid: OPENID, answer, createTime: db.serverDate() } }) await tx.commit() return { ok: true, rank: result._id, msg: 抢答成功 } }这里的关键是「先 count 判断、再事务写入」的组合。单看两步中间仍有并发窗口但配合事务后同一 rushId 加 openid 的重复写入会在事务层被隔离实测三四十人同时点也能保证只有第一个成功。更稳妥的方案是给 rush_answers 建联合唯一索引云开发控制台里对 rushId 和 openid 两个字段建 unique 索引即可答辩前记得提前建好别到现场才补。教师端发起抢答时deadline 建议设 20 秒——太长学生开始刷手机太短手慢的同学直接放弃20 秒是我试过几轮之后体验最平衡的值。4.2 随堂测验单选框渲染、答案收集与云端判分随堂测验的交互是典型的「单选框加提交」流程。题目从云端拉下来学生逐题选择最后一次性提交。先看答题页的 WXML!-- miniprogram/pages/student/quiz/quiz.wxml -- view wx:for{{questions}} wx:keyid classq-card view classq-title{{index 1}}. {{item.title}}/view radio-group bindchangeonAnswerChange>// miniprogram/pages/student/quiz/quiz.js Page({ data: { questions: [], answers: {}, submitted: false, score: null }, onLoad(options) { this.quizId options.quizId this.fetchQuestions() }, fetchQuestions() { wx.cloud.callFunction({ name: getQuiz, data: { quizId: this.quizId } }).then(res { this.setData({ questions: res.result.list }) }) }, onAnswerChange(e) { const qid e.currentTarget.dataset.qid // computed key 动态更新答案对象 this.setData({ [answers.${qid}]: e.detail.value }) }, submit() { const { answers, questions } this.data if (Object.keys(answers).length questions.length) { wx.showToast({ title: 还有题目没答完, icon: none }) return } wx.cloud.callFunction({ name: submitQuiz, data: { quizId: this.quizId, answers } }).then(res { this.setData({ submitted: true, score: res.result.score }) wx.showToast({ title: 得分 ${res.result.score}, icon: none }) }) } })setData 里用answers.${qid}这种 computed key 是官方支持的特性比先读整个 answers 对象再整体 setData 性能好而且不会触发多余渲染。判分云函数做的事很简单拉出 quiz 文档里的题目数组遍历比对 answers 中对应 key 与标准答案逐个累加结果写进 quiz_results 集合。提示getQuiz 返回题目时务必把每道题的 answer 字段剥掉再下发否则学生用抓包工具看一眼就能拿到全部标准答案——这是演示时最掉价的一个细节也是评阅老师最爱追问的点。4.3 教师端看板用 ec-canvas 画签到率柱状图数据看板是答辩时的门面。看板我用的是 ECharts 的小程序版本 ec-canvas它是 echarts-for-weixin 仓库提供的封装组件把 echarts 核心库塞进 canvas 渲染。用法是// miniprogram/pages/teacher/dashboard/dashboard.js import * as echarts from ../../ec-canvas/echarts Page({ data: { ec: { onInit: this.initChart.bind(this) } // 注意 bind 保持 this }, initChart(canvas, width, height) { const chart echarts.init(canvas, null, { width, height, devicePixelRatio: 2 // 高分屏下防发虚 }) canvas.setChart(chart) chart.setOption({ tooltip: { trigger: axis, formatter: {b}br/{a}: {c}% }, grid: { left: 40, right: 16, top: 20, bottom: 30 }, xAxis: { type: category, data: [第1周, 第2周, 第3周, 第4周] }, yAxis: { type: value, name: 签到率(%), min: 0, max: 100 }, series: [{ name: 签到率, type: bar, barWidth: 24, itemStyle: { color: #07c160 }, data: [82, 90, 76, 94] }] }) return chart } })柱状图的数据不是写死的真实工程里要先调一个统计云函数按 sessions 分组把每个会话的应到人数和实到人数算出来得到签到率数组再 setOption 进去。ec-canvas 有两个注意点组件的 ec 属性必须是一个对象字面量onInit 要在 Page 的 data 里声明initChart 里必须 return chart否则组件在 onReady 阶段拿不到图表实例表现为画布空白。如果你嫌 echarts 太大光核心库就接近 300 KB对小程序主包 2 MB 限制压力很大可以用 canvas 手绘柱状图一个 for 循环加 fillRect 就能画完视觉上完全够答辩用。5. 避坑清单真机定位、云函数超时、审核拒绝与导航栏的五个典型翻车5.1 现象开发者工具里定位正常真机上一直触发 fail开发者工具的定位是模拟的默认直接返回你电脑的网络位置把真实手机上的问题全掩盖了。真机上拿不到位置最常见的原因是小程序没有在 app.json 里声明位置权限用途或者基础库版本太老不认 requiredPrivateInfos 配置。原因是 getLocation 属于隐私接口微信从较新的基础库开始要求开发者在小程序后台的「用户隐私保护指引」里声明调用目的同时在代码里显式列出用到的隐私接口。缺任何一步真机上首次调用 getLocation 都会静默失败控制台只给一句「fail: api scope is not declared」。解决方法是双管齐下。先在 app.json 里补配置{ permission: { scope.userLocation: { desc: 你的位置信息将用于课堂签到定位 } }, requiredPrivateInfos: [getLocation] }然后登录微信公众平台在小程序后台「设置-服务内容声明-用户隐私保护指引」里勾选「位置信息」并写明用途。project.config.json 里的 libVersion 尽量提到当前最新稳定版老基础库不认识 requiredPrivateInfos配置了也白配。5.2 现象云函数偶尔报 -501000 超时重试又好了-501000 是云函数执行超时的典型错误码。云函数默认超时时间很短登录、签到这类单次操作本身跑得很快但云开发有冷启动机制——函数长时间没人调用后第一次触发要额外加载运行时可能吃掉一两秒加上数据库读取很容易撞线。解决方法是打开云开发控制台在云函数配置里把超时时间调大。登录、签到这类轻函数设 10 秒统计、批量更新这类重函数设 20 秒。注意不是越大越好真死循环的话长超时只是让资源多被占一会儿。调完记得重新部署cloudbase functions:deploy login --dir cloudfunctions/login # 或者在微信开发者工具里右键云函数目录 - 上传并部署云端安装依赖如果调大超时后连续调用仍然超时那就不是冷启动问题而是函数逻辑里有慢查询。最典型的慢查询是循环里逐条 where().get()改成一次批量查询where 条件里用 in 操作符速度能差一个数量级。5.3 现象小程序审核被拒理由是「涉及收集用户位置信息但未说明」这是最让人吐血的一类问题。课堂签到绕不开定位而小程序审核对位置信息的收集非常敏感。被拒通常有两种情况一是隐私保护指引里没声明位置信息二是声明的用途和实际功能对不上——比如你写的是「用于推荐附近内容」界面里却是课堂签到审核员会认为用途不符。解决方法是把用途写得具体「用户的位置信息将用于课堂签到记录学生是否在教学楼范围内」。同时在登录后的首次使用页面弹一个说明弹窗把「为什么需要位置、怎么使用」写清楚不要默默把权限请求放在页面角落。另外系统里教师端只能看到签到人数和距离数值不要展示学生具体坐标——这符合最小化收集原则答辩时能主动讲出这一条是加分项。5.4 现象iOS 和安卓顶部间距不一样刘海屏把自定义导航栏顶出去了小程序默认导航栏用的是微信胶囊按钮如果你做了自定义导航栏顶部状态栏高度必须自己算。iPhone 全面屏机型的刘海区和状态栏高度和安卓机型差异很大写死 44 像素或者 48 像素必然翻车。解决方法是动态计算。用 wx.getMenuButtonBoundingClientRect() 拿到胶囊按钮的位置再用 wx.getSystemInfoSync().statusBarHeight 拿状态栏高度算出导航栏整体高度const menuBtn wx.getMenuButtonBoundingClientRect() const sysInfo wx.getSystemInfoSync() const navBarHeight (menuBtn.top - sysInfo.statusBarHeight) * 2 menuBtn.height // 把 navBarHeight 传给自定义导航栏组件样式里设置高度即可这套算法是所有自定义导航小程序通用的套路签到页、看板页、测验页只要用自定义导航就统一走这个工具函数不要每页单独写一份。还有一个连带问题iPhone 底部小黑条会盖住提交按钮页面底部记得预留 env(safe-area-inset-bottom) 的安全区 padding。5.5 现象订阅消息授权弹窗每次都弹学生嫌烦教师端通知发不出去小程序的订阅消息是「一次性订阅」每次下发前都必须让用户点击授权弹窗和公众号的长期订阅完全是两回事。很多毕业设计把订阅消息当成「给全班发通知」的推送通道结果每次发都要收集一堆授权授权率惨不忍睹。解决方法是给订阅消息降权不做核心通知链路。测验成绩、签到结果这类信息放进系统内的消息列表学生端首页出现未读红点点开即达完全不依赖订阅授权。把订阅消息留给「必须实时提醒」的场景比如抢答开始前 5 秒的倒计时提醒。这样既能演示订阅消息能力又不会把核心流程绑在授权成功率上。6. 从能跑到能答辩自测清单、抓包验证与演示前最后一遍检查6.1 功能自测清单一条条过别等答辩现场翻车功能自测要有清单不能「打开页面随便点两下」就算过。我按模块整理了一份检查项照着过一遍基本能过滤掉八成低级问题模块检查项通过标准登录首次登录、二次登录users 集合无重复 openid签到时间窗口内、外各测一次窗口外被明确拒绝签到半径内、半径外各测一次边界外被拒边界内成功抢答模拟多人同时点击只有第一个成功写入测验全对、全错、部分对分数与预期一致看板空数据、单周、多周图表不空白、坐标轴正常测试时用两个微信号真机互测一个开教师端一个开学生端完整走一遍「建课、发起签到、抢答、测验、看板」的流程。注意同一个微信不能既是教师又是学生教师身份需要去云开发控制台把 users 集合里对应记录的 role 改成 teacher。6.2 抓包验证用 charles 确认请求里没有「不该有的东西」真机调试时把手机代理指向电脑开着 charles 抓一遍小程序流量。重点看三样东西登录是不是只发了一次、签到请求里有没有把敏感字段带错地方、云端返回的错误码是不是在预期范围内。Windows 上也可以用 reqable用法类似。抓包这步毕业后做小程序日常开发也用得上值得在答辩前顺手学会。抓包时如果看到控制台里出现 10002、40029 这类错误码先翻官方错误码表确认归属再动代码别凭感觉改配置。四百度的经验是这类错误码九成是参数格式问题而不是逻辑问题——比如 code 重复使用、时间格式传了字符串而不是时间戳。6.3 体积、真机与演示顺序的最后检查微信小程序主包有 2 MB 的体积红线社区里常见的 uniapp 打包超限报错source size 2612kb exceed max limit 2mb本质就是撞这条线。原生小程序同样要注意图片资源不要堆在项目里统一传云存储再按 URL 加载ec-canvas 这类大组件用不到的图表类型可以在 echarts 定制构建时剔除。如果工程实在超了用分包加载把教师端页面放进 subPackages主包只留首页和公共组件。演示顺序我也踩过坑。答辩时最忌讳先开数据看板——如果还没采集过数据看板是空的场面很难看。正确的演示顺序是先登录建课现场发起一次签到让台下的人扫码参与数据是真实的新鲜的再发起一轮抢答最后打开看板这时柱状图里已经有了刚才现场产生的数据。一次完整的现场互动比任何预先录好的截图都有说服力。这套自测清单和抓包流程从那以后我每次交付小程序工程都会强制走一遍哪怕是只改了一个页面的小版本也不跳过。原因很简单课堂系统是给人用的出一次签到失败全班都看在眼里比线上项目出 bug 更丢脸。这次拆完这个课堂交互系统我最大的教训是——并发、定位、权限这三件事永远不要在演示当天才第一次测。希望这份笔记能帮你在答辩前少走点弯路尤其是签到和抢答这两个模块按上面的方式写完基本不会翻车。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑