简介这是一套面向高校学生与开发者的评教系统完整源码采用微信小程序与Web应用双端架构适合用作毕业设计、课程设计或全栈练手项目。资源包共528个文件约9.43MB以JavaScript业务逻辑、JSON配置、WXSS样式与WXML页面结构为主辅以Less预处理样式、WXS脚本及少量图片资源前后端代码组织清晰便于按模块阅读与二次开发。项目围绕学生评教、教师管理与数据统计等典型场景展开涵盖小程序端页面渲染、接口调用与后台管理功能代码经过测试可直接运行省去从零搭建的繁琐。目前已有186人学习下载适合希望快速获得可运行项目、理解小程序与Web协同开发流程的读者参考借鉴。1. 评教系统做成微信小程序一份 zip 源码背后真正要落地的四件事每学期期末教务群里最热闹的话题永远是评教——学生嫌入口难找老师盯着参评率发愁教务处的老师则要手动把几千条记录从后台导出来做统计。把评教系统做成微信小程序本质上是把「登录—选课—打分—提交—统计」这条链路塞进一个不用装 App、扫码即用的入口里。你手上如果正好有一份「评教系统微信小程序.zip」它大概率包含小程序前端页面、后端接口和一份数据库脚本但真正决定它能不能上线的不是代码写得多漂亮而是四件事微信登录怎么和学号绑定、评教数据怎么保证一人一课一评、主观题和客观题怎么存、以及教务端怎么把结果导出来。这篇笔记面向的是拿到源码想跑通、想改成自己学校能用的开发者也适合正在评估「微信小程序项目实例」能不能直接套用的教务信息化同学。下面按「先跑起来、再改对、最后防坑」的顺序讲。2. 把 zip 跑起来环境、目录与最小可运行链路2.1 先看清 zip 里通常有什么再决定改哪里拿到一份评教系统源码别急着点「编译」。先解压用编辑器打开根目录按下面的方式快速判断它的技术栈。常见的评教小程序项目结构大致是这几类文件目录/文件作用你要关注的点miniprogram/或pages/小程序前端页面登录页、课程列表、评教表单、提交结果页app.js/app.json全局逻辑与页面注册app.json里的pages数组决定入口页utils/request.js请求封装看 baseURL 指向哪个后端server/或backend/后端服务Node/Java/PHP 都有可能看package.json或pom.xml*.sql数据库脚本建表语句里能看出评教维度设计判断技术栈的命令很简单在解压目录执行# 看后端语言和依赖 ls -la cat package.json 2/dev/null || cat pom.xml 2/dev/null || echo 可能是 PHP 或其它 # 找数据库脚本 find . -name *.sql -maxdepth 3 # 找请求基地址 grep -rn baseUrl\|baseURL\|request( --include*.js miniprogram/ 2/dev/null | head -20逻辑说明package.json存在说明后端是 Nodepom.xml是 Java两者都没有就要看有没有index.php或application.properties。grep那一条是为了定位前端请求打到哪个域名这决定了你后面要不要改request合法域名。参数上--include*.js限定只搜 JShead -20防止输出刷屏。提示如果app.json里pages第一项是pages/login/login说明强制先登录如果是pages/index/index可能允许游客浏览评教系统一般应该是前者。2.2 微信登录换学号wx.login到后端openid的完整链路评教系统最关键的一步是「这个人是谁」。微信小程序不能直接拿学号标准做法是前端wx.login拿code后端用code换openid再把openid和学号做绑定。前端代码通常长这样// pages/login/login.js Page({ onLoad() { // 页面加载时先静默登录拿到 code wx.login({ success: (res) { if (res.code) { // 把 code 发给自己的后端由后端去换 openid wx.request({ url: https://your-domain.com/api/login, method: POST, data: { code: res.code }, success: (r) { // 后端返回 token 和是否已绑定学号 wx.setStorageSync(token, r.data.token); if (!r.data.bound) { wx.navigateTo({ url: /pages/bind/bind }); } } }); } } }); } });逻辑说明wx.login的code只能用一次、五分钟内有效所以必须立刻发给后端。后端拿到code后调用微信的code2Session接口换openid和session_key这一步涉及appid和secret绝对不能放在前端。参数上wx.request的url必须是 HTTPS 且在小程序后台「request 合法域名」里配置过否则真机直接报「不在以下 request 合法域名列表中」。后端换openid的伪代码逻辑是接收code→ 请求微信接口 → 拿到openid→ 查数据库里这个openid有没有绑学号 → 有就发 token没有就返回bound: false。绑定页让学生输入学号和姓名后端拿学号去教务库比对比对成功就把openid和学号写进绑定表。这里有个血泪经验很多学校教务库不开放只能导入一份学生名单做比对那就把名单表建好绑定接口查这张表。2.3 评教表单客观题用单选、主观题用文本别混着存评教表单一般分两类题客观题打分、单选和主观题建议、评语。微信小程序里客观题用radio-group主观题用textarea。数据结构建议前端提交时统一成数组// 提交评教结果 const answers [ { questionId: 1, type: radio, value: A }, // 客观题 { questionId: 2, type: radio, value: B }, { questionId: 3, type: text, value: 老师讲课很清晰 } // 主观题 ]; wx.request({ url: https://your-domain.com/api/evaluate, method: POST, header: { Authorization: wx.getStorageSync(token) }, data: { courseId: 101, teacherId: 5, answers }, success: (r) { if (r.data.code 0) { wx.showToast({ title: 评教成功 }); } } });逻辑说明questionId对应题库表主键type区分题型value存选项或文本。后端收到后按type分别写入客观题结果表和主观题结果表或者统一存一张 JSON 字段表。参数上courseId和teacherId是评教的维度必须和选课表关联否则统计时对不上。注意header里带 token 做鉴权防止别人替你评教。注意微信小程序的radio组件在部分安卓机型上点击区域偏小建议给label包一层并设置padding否则学生会觉得「点不动」。3. 评教系统的数据设计一人一课一评怎么保证3.1 三张核心表学生、课程、评教记录评教系统的数据库设计决定了后面统计能不能做。最小可用方案是三张表加一张题库表-- 学生绑定表 CREATE TABLE student_bind ( id INT PRIMARY KEY AUTO_INCREMENT, openid VARCHAR(64) UNIQUE NOT NULL, student_no VARCHAR(20) NOT NULL, real_name VARCHAR(20), created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 评教记录表 CREATE TABLE evaluation ( id INT PRIMARY KEY AUTO_INCREMENT, student_no VARCHAR(20) NOT NULL, course_id INT NOT NULL, teacher_id INT NOT NULL, submit_time DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_stu_course (student_no, course_id) ); -- 评教答案表 CREATE TABLE evaluation_answer ( id INT PRIMARY KEY AUTO_INCREMENT, evaluation_id INT NOT NULL, question_id INT NOT NULL, answer_value VARCHAR(500), INDEX idx_eval (evaluation_id) );逻辑说明student_bind的openid加唯一索引防止一个微信绑多个学号。evaluation表的UNIQUE KEY uk_stu_course是核心它保证同一个学生对同一门课只能提交一次这就是「一人一课一评」的数据库级约束。evaluation_answer用evaluation_id关联主观题的长文本也放得下VARCHAR(500)够用不够改TEXT。参数上student_no用字符串而不是数字因为有些学号带字母或前导零。submit_time默认当前时间方便后面按学期筛选。如果学校要求匿名评教那evaluation表里就不要存student_no改成存一个随机token但这样就没法做「一人一课一评」的约束了——这是匿名和防重复之间的取舍常见做法是存student_no但统计时只输出聚合结果不暴露个人。3.2 提交接口的幂等处理重复提交怎么拦前端可能因为网络卡顿重复点提交后端必须做幂等。最直接的方式是利用UNIQUE KEY插入冲突时返回友好提示// Node.js 示例提交评教 app.post(/api/evaluate, async (req, res) { const { courseId, teacherId, answers } req.body; const studentNo req.user.studentNo; // 从 token 解析 try { const [result] await db.execute( INSERT INTO evaluation (student_no, course_id, teacher_id) VALUES (?, ?, ?), [studentNo, courseId, teacherId] ); const evalId result.insertId; // 批量插入答案 const values answers.map(a [evalId, a.questionId, a.value]); await db.query(INSERT INTO evaluation_answer (evaluation_id, question_id, answer_value) VALUES ?, [values]); res.json({ code: 0, msg: ok }); } catch (e) { if (e.code ER_DUP_ENTRY) { return res.json({ code: 1001, msg: 你已经评过这门课了 }); } res.json({ code: 500, msg: 提交失败 }); } });逻辑说明先插evaluation主表拿到evalId再用批量插入写答案减少数据库往返。ER_DUP_ENTRY是 MySQL 唯一键冲突的错误码捕获后返回「已评过」而不是报 500。参数上answers.map把前端数组转成二维数组db.query的?占位批量插入比循环单条快很多。提示如果学校要求「提交后不可修改」那就在提交成功后把该学生的评教入口置灰如果允许修改就用INSERT ... ON DUPLICATE KEY UPDATE但评教一般不允许改防止事后改分。3.3 教务端统计从评教记录到教师得分统计是评教系统的出口。常见需求是「每个老师每门课的平均分」和「主观题原文导出」。平均分用 SQL 聚合SELECT e.teacher_id, e.course_id, AVG(CASE WHEN q.type radio THEN CAST(a.answer_value AS UNSIGNED) END) AS avg_score, COUNT(DISTINCT e.student_no) AS participant_count FROM evaluation e JOIN evaluation_answer a ON a.evaluation_id e.id JOIN question q ON q.id a.question_id GROUP BY e.teacher_id, e.course_id;逻辑说明CASE WHEN只对客观题求平均主观题不参与。CAST把选项值转成数字前提是选项设计成 A5、B4 这种分值。COUNT(DISTINCT e.student_no)统计参评人数用来算参评率。参数上如果选项是字母需要在题库表里存一个score字段做映射别在 SQL 里硬编码。主观题导出一般做成 CSV教务老师用 Excel 打开。注意 CSV 要加 BOM 头否则 Excel 打开中文乱码const csv \uFEFF rows.map(r ${r.teacher_name},${r.course_name},${r.answer_value}).join(\n);\uFEFF就是 BOM${r.answer_value}用引号包住防止评语里有逗号。4. 微信小程序评教系统的避坑与排查4.1 真机请求失败合法域名和 HTTPS 证书现象开发者工具里一切正常真机预览时所有接口报「request:fail」。原因小程序真机强制要求 HTTPS且域名必须在小程序后台「开发—开发设置—服务器域名」里配置。解决把后端域名加进 request 合法域名证书用受信任的 CA 签发自签名证书不行。如果只是内网测试可以在开发者工具「详情—本地设置」勾选「不校验合法域名」但真机不行。4.2 登录态过期token 失效后页面白屏现象学生评教到一半提交时提示未登录返回登录页后数据丢了。原因token 设了过期时间或者后端重启导致 session 丢失。解决前端在request封装里统一拦截 401跳转登录前把当前表单数据存进wx.setStorageSync登录后回填。token 建议用 JWT后端无状态重启不影响。4.3 单选组件取值取不到radio-group的bindchange现象学生选了选项提交时value是空。原因radio必须包在radio-group里且bindchange绑在radio-group上不是radio上。解决radio-group bindchangeonRadioChange style="width:16px;margin-left:4px;vertical-align:text-bottom;cursor:text;" />
