拿到"基于Node.js的演唱会路演微信小程序"这类课设题目,大部分同学的第一反应是到处搜源码、下模板,结果搜到的版本要么是老掉牙的PHP后台,要么是前后端写死在一起、数据库文件带一堆脏数据的半成品。我毕业设计时正好做过一个类似的售票系统,后来也帮别人整理和重构过同题项目,今天干脆把这个题目完整拆一遍:从需求分析、技术选型、数据库设计,到接口落地、小程序页面开发、环境配置踩坑,最后到答辩文档怎么组织,一条线全部走通。项目主体是 Node.js 后端 + 微信小程序前端 + MySQL 数据库,实现一个包含演唱会、路演门票浏览、选座、下单、订单管理、后台统计的完整售票系统,附带的源码、数据库脚本和万字文档我也会讲清楚各自该装什么内容。
1. 先搞清楚这个课设题目到底在考什么
先说结论:这类题目考察的重点不是"你会不会写小程序页面",而是你能否把一个模糊的业务需求拆解成清晰的功能模块,并且让前后端数据形成闭环。标题里只写了"演唱会路演小程序"和"售票系统"几个字,没写用户是谁、要买什么、管理员管什么,这些都需要你自己在需求分析阶段补全。
1.1 需求不写清楚,是所有课设混乱的根源
我的习惯是先做角色分析。这个系统至少有三类人:普通用户,在小程序里浏览演出、选座买票、查看订单;票务管理员,维护演出场次、配置票价、处理核销;系统管理员,管理用户、查看统计报表。如果题目带"路演"两个字,还需要额外理解一下:路演通常是小型巡回演出,场次多、座位少、票价档位简单;而大型演唱会则正好相反。两者核心交易模型是一样的,只是数据规模不同,所以可以用一套"演出+场次+座位"的模型统一管理,不需要做两套系统。
很多同学一开始就纠结"演唱会"和"路演"的区别,其实没必要。你只要在数据库里把演出类型(type字段)区分开,列表页加一个筛选标签,就同时覆盖了两种场景。这个细节在文档的需求分析里写一句,会显得你考虑过业务,而不只是照抄模板。
1.2 三大模块:用户端、票务端、管理端
功能切分我建议按角色来,这样第三章画模块图、第四章写需求分析的时候都能直接复用。
- 用户端:微信授权登录、演出列表与详情、场次选择、可视化座位图选座、提交订单、模拟支付、我的订单列表、订单取消、个人信息维护。
- 票务端:演出管理(增删改查)、场次管理、票价档位配置、座位图维护、订单查询、验票核销。
- 管理端:用户管理、订单统计、演出销售排行、退票率统计、基础数据看板。
这个清单可以直接当作任务分解表用。每个功能点对应前端一个页面或模块、后端一组接口、数据表若干字段。我见过有人把"秒杀""优惠券""会员积分"全写进功能清单,结果两个月都做不完,最后答辩只演示登录和列表页。课设的核心是闭环,不是功能堆砌。选座、下单、支付、订单状态流转是必做主线,其余都是加分项。
1.3 一个可复用的功能优先级表格
我当年做任务分解时列了下面这个表,按优先级从高到低排,你可以直接参考:
| 优先级 | 功能模块 | 关键说明 | 对应数据表 |
|---|---|---|---|
| P0 | 微信登录 | code换openid,签发token | user |
| P0 | 演出列表/详情 | 首页核心入口 | concert |
| P0 | 场次选择 | 时间、场地、剩余座位 | session |
| P0 | 可视化选座 | 座位锁定防止超卖 | seat |
| P0 | 下单+支付 | 事务保证订单一致性 | orders / payment |
| P1 | 我的订单 | 状态展示、取消操作 | orders |
| P1 | 演出/场次管理 | 后台维护数据 | concert / session |
| P2 | 销售统计 | 简单聚合报表 | orders |
| P2 | 验票核销 | 二维码扫码或手动核销 | orders |
P0做完,系统已经能完整闭环演示;P1保证后台不是空架子;P2属于锦上添花。按这个顺序开发,每周都有可演示的阶段性成果,无论做课设还是毕设,进度压力都会小很多。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术选型:Node.js + 原生小程序 + MySQL 的组合逻辑
技术选型这一节在文档里通常占两三页,但答辩时老师最爱问的就是"为什么选这个"。你得把理由说得既有逻辑又有对比,而不是一句"大家都用这个"。
2.1 后端为什么起在 Node.js 上
候选方案无非是 Java Spring Boot、Python Flask/Django、PHP、Node.js 这几类。我直接给对比结论:
- Java Spring Boot:能写,但环境重、依赖多、启动慢,课设时间花在配置上的比例太高,而且代码量对初学者不友好。
- Python Flask:轻量灵活,写起来快,但如果前端要复用业务逻辑,语言统一性就不如 Node。
- PHP:很多老系统在用,生态偏传统,现在新项目没必要再选。
- Node.js:最大的优势是全栈语言统一——前端小程序写 JavaScript,后端也用 JavaScript,一处数据结构、加解密逻辑、时间格式化工具可以前后端复用。再加上异步非阻塞 IO 模型,处理"选座锁座、并发下单"这类 IO 密集场景有天然优势,npm 生态里上手最快的后端框架 Express 也足够应付这类业务。
我在实际项目里用的是 Express 4.x + mysql2 连接池,路由加控制器分层,代码量适中、结构清晰,老师能看懂,你答辩也能说清楚。
2.2 小程序用原生还是 uniapp
很多人纠结这个问题。我的建议很直接:课设就用原生微信小程序开发,不要上 uniapp。原因有三。第一,原生是最稳的,文档、社区、调试工具都是官方维护,遇到问题搜索方案最快;uniapp 多一层编译,照样还是要懂小程序原生规范,等于学两套东西。第二,课设评委老师通常只看小程序跑起来的效果和代码结构,原生代码结构直白,不需要解释编译层的概念。第三,题目明确写的是"微信小程序",你用 uniapp 打包出来虽然也是小程序,但源代码里全是 Vue 语法,答辩时容易被认为是挂羊头卖狗肉。
真要用 uniapp,那除非题目本身写的是"基于 uniapp 开发",否则没必要给自己增加风险。
2.3 数据库为什么选 MySQL 而不是 MongoDB
售票系统本质是交易系统,交易最怕的数据问题是:一个座位被两个人同时买走。这依赖数据库的事务特性和行级锁,MySQL(InnoDB 引擎)在这块非常成熟。MongoDB 虽然文档型模型灵活,但在多文档事务、复杂聚合上要么能力受限要么写法反人类。再加上课设标题要求附数据库文件,MySQL 导出 .sql 脚本最通用,老师用 Navicat 一键就能导入查看。
如果你对数据库没经验,我就明说:MySQL 8.0 + Navicat 管理工具是这套系统的最稳组合,没有之一。锁表、事务、索引这些概念在文档里也更好解释。
3. 系统架构与服务端代码组织
系统整体是经典三层结构:微信小程序前端只负责渲染和交互,后端 Express 提供 RESTful API,MySQL 存数据。每一层只依赖相邻的下层,不要跨层调用。
3.1 请求流转与分层思想
一次完整的购票请求是这样跑的:小程序端用户点击选座页面的"立即购买"按钮,wx.request 把订单数据 POST 到后端接口;后端先经过中间件(校验 token、校验参数),再进入订单控制器;控制器调用订单服务层,服务层里开启数据库事务,更新座位状态、写入订单记录、生成支付流水;全部成功后向前端返回订单编号;前端拿到编号跳转支付页。谁出问题,数据库整体回滚,前端收到错误提示。
为什么一定要分成 controllers 和 services 两层?我见过很多课设代码把所有逻辑塞在一个路由文件里,一个文件八百行,改一个 bug 就得滚半天进度条。控制器只做参数接收和结果返回,业务规则(比如"订单只能取消待支付的")全部放在服务层,这样答辩老师问"某个规则写在哪里",你十秒钟就能指出来。
3.2 后端目录结构与路由规划
一个我反复用、效果稳定的目录结构如下:
text复制server/
├── app.js # 入口文件,启动服务
├── config/
│ └── db.js # 数据库连接池配置
├── routes/ # 路由定义,只做路径分发
├── controllers/ # 控制器:接收参数、返回结果
├── services/ # 业务逻辑层:事务、规则校验
├── models/ # 数据模型/DAO:SQL查询
├── middleware/ # 中间件:token校验、错误处理
├── utils/ # 工具函数:订单号生成、时间格式化
└── package.json
路由规划按资源划分,遵循 REST 风格,既好写文档又好对接口。下面的表直接可用于文档的"接口设计"章节:
| 模块 | 方法 | 路径 | 说明 |
|---|---|---|---|
| 用户 | POST | /api/user/login | 微信登录,换取 token |
| 用户 | GET | /api/user/info | 获取当前用户信息 |
| 演出 | GET | /api/concert/list | 演出列表(分页) |
| 演出 | GET | /api/concert/:id | 演出详情及场次 |
| 场次 | GET | /api/session/:id/seats | 获取座位图 |
| 锁定 | POST | /api/session/:id/lock | 锁定座位 |
| 订单 | POST | /api/order/create | 创建订单 |
| 订单 | GET | /api/order/list | 我的订单 |
| 支付 | POST | /api/pay/mock | 模拟支付 |
| 后台 | POST | /api/admin/concert/save | 演出保存/编辑 |
我建议用 Postman 或 Apifox 在开发时逐个调试这些接口,把请求参数和返回结果截图,后面文档里"系统实现"章节直接就有素材了,一举两得。
3.3 统一响应格式与错误码设计
前后端联调最怕各写各的格式。我定的统一响应结构是:
json复制{
"code": 0,
"msg": "ok",
"data": {}
}
code 为 0 表示成功,非 0 表示业务错误。错误码分段定义:10000 段为通用错误(参数缺失、未登录、token过期),20000 段为演出相关(演出不存在、场次已下架),30000 段为座位与订单相关(座位已被锁定、订单超时、重复支付)等等。前端拿到非 0 的 code,直接弹 msg 提示用户,后端所有错误在日志里能看到完整堆栈。这个习惯从一开始就建立,能省掉后面大量联调时间。
4. 数据库设计:座位、场次、订单怎么建模
数据库是整个项目的地基,也是文档里最好写、老师最爱问的部分。表设计不合理,后面写接口寸步难行;表设计合理,接口就是"查表 + 更新状态"的体力活。
4.1 核心表清单与关联关系
我用的核心表有 8 张,下面是表名和职责说明:
- user:用户表,存储微信 openid、昵称、头像、手机号、注册时间。
- concert:演出表,存储标题、艺人、封面图、演出类型(演唱会/路演)、城市、介绍。
- session:场次表,一场演出可能有多场时间,存演出 ID、场次时间、场馆名称、总座位数、票价档位。
- seat:座位表,每个场次下划分区、排、座,状态区分空闲/锁定/已售。
- orders:订单表,存储订单号、用户 ID、场次 ID、座位 ID 集合、金额、状态、创建/支付时间。
- order_seat:订单和座位的关联表,因为一个订单可以买多张票,用一张关系表表达这种多对多关系。
- payment:支付流水表,记录模拟支付或真实支付的流水号、金额、时间。
- admin:后台管理员表,区分票务管理员和系统管理员角色。
关系一句话概括:用户 1 对多 订单,场次 1 对多 座位,订单 多对多 座位(通过 order_seat 关联),订单 1 对 1 支付流水。
下面给出最核心的 orders 和 seat 建表 SQL,其余表的结构类似,文档里可以全部用表格呈现字段列表:
sql复制CREATE TABLE `seat` (
`id` INT NOT NULL AUTO_INCREMENT,
`session_id` INT NOT NULL COMMENT '场次ID',
`zone` VARCHAR(20) DEFAULT 'A区' COMMENT '分区',
`row_no` INT NOT NULL COMMENT '排号',
`col_no` INT NOT NULL COMMENT '列号',
`status` TINYINT NOT NULL DEFAULT 0 COMMENT '0空闲 1锁定 2已售',
`lock_time` DATETIME DEFAULT NULL COMMENT '锁定时间',
`order_id` VARCHAR(32) DEFAULT NULL COMMENT '关联订单号',
PRIMARY KEY (`id`),
KEY `idx_session_status` (`session_id`, `status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
sql复制CREATE TABLE `orders` (
`id` INT NOT NULL AUTO_INCREMENT,
`order_no` VARCHAR(32) NOT NULL COMMENT '订单号',
`user_id` INT NOT NULL,
`session_id` INT NOT NULL,
`seat_ids` VARCHAR(255) NOT NULL COMMENT '座位ID集合',
`total_amount` DECIMAL(10,2) NOT NULL,
`status` TINYINT NOT NULL DEFAULT 0 COMMENT '0待支付 1已支付 2已取消 3已退款',
`create_time` DATETIME NOT NULL,
`pay_time` DATETIME DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_order_no` (`order_no`),
KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
4.2 座位表的锁与释放:防超卖的关键
售票系统最核心的问题是防超卖。如果用户 A 和用户 B 同时点同一张票,两个人都看到"可选",都提交订单,那就超卖了。解决思路在数据库层面非常经典:用条件更新座位状态,而不是先查询再更新。
选座锁定时执行:
sql复制UPDATE seat SET status = 1, lock_time = NOW(), order_id = ?
WHERE id IN (?,?,?) AND status = 0;
这条 SQL 的关键在 AND status = 0。MySQL 会对命中的行加锁,两个并发请求同时执行时,只有第一个能更新成功,第二个更新的受影响行数为 0,后端据此判断"有座位已被选走",提示用户刷新座位图。这就是所谓的乐观锁思路,不需要分布式锁,代码简单还经得起答辩提问。
锁定之后不能一直占着不放,否则系统会被未支付的订单占满。我的做法是给锁定座位设置 30 分钟有效期,超过时间自动释放。释放策略后面第 5 章会讲。
4.3 订单状态机:待支付、已支付、已取消、已退款
订单状态用 TINYINT 存储,比字符串省空间,下面这张状态流转表我建议原样写进文档:
| 状态 | 值 | 说明 | 可流转到 |
|---|---|---|---|
| 待支付 | 0 | 用户下单成功,尚未支付 | 已支付、已取消 |
| 已支付 | 1 | 用户完成支付,票有效 | 已退款 |
| 已取消 | 2 | 未支付或主动取消 | 无 |
| 已退款 | 3 | 支付后退款 | 无 |
状态流转必须在服务层做校验。比如"待支付"才能取消,"已支付"才能退款,不允许从"已支付"直接跳"已取消"。用数据库事务配合状态条件更新,能避免因为用户快速重复点击导致的脏状态。
在支付环节,真实接入微信支付需要商户号、证书、回调域名,对课设来说太重了。我推荐做"模拟支付":提交订单后进入支付页,点击"确认支付"由后端直接标记订单为已支付,写入一条支付流水,再跳回订单详情页。同时在文档里预留一节写清楚真实微信支付的接入思路,表明你知道完整方案,只是受条件限制用模拟支付演示。这套做法在课设答辩里既安全又讨巧。
5. 核心业务链路:从查演出到出票的接口落地
有了表和分层,接口本身不复杂,难点全在几个容易出错的业务节点上。这一章按完整购票链路讲,你跟着走一遍就能在本地跑通主流程。
5.1 微信登录与 token 机制
小程序前端调用 wx.login 拿到临时 code,传给后端 POST /api/user/login。后端拿 code 去微信接口换 openid 和 session_key,再把 openid 存到 user 表(没有则新建用户),最后用 jsonwebtoken 签发一个 token 返回前端。前端把 token 存到 storage,之后的每一个请求都在 header 里带上。
为什么不用微信的 session_key 直接当前端凭证?因为 session_key 是微信会话密钥,本意是用来解密手机号、运动数据这类敏感信息的,不适合做业务层的长期登录态。自己签发 token 的好处是过期时间可控、字段可自定义(比如把 userId 塞进去),token 过期时后端返回 401,前端统一清理登录态并引导重新登录。这个 token 机制是答辩老师几乎必问的点,提前理解好。
5.2 选座锁定与超时释放
选座页加载时,前端请求 GET /api/session/:id/seats,后端把该场次所有座位按 [{row: 1, cols: [{col: 1, status: 0}, ...]}] 返回。用户点击座位,前端先把它标记为"我的选中态",但不提交后端;用户在底部确认"选好了",前端调用锁定接口,传入场次 ID 和选中的座位 ID 数组。
后端按 4.2 的 UPDATE 语句逐批更新,任何一张座位受影响行数为 0 就说明被别人抢了,整体返回失败并附上冲突座位号。锁定成功后前端开始 30 分钟倒计时,倒计时结束或用户主动取消时调用释放接口:
sql复制UPDATE seat SET status = 0, lock_time = NULL, order_id = NULL
WHERE order_id = ? AND status = 1;
超时释放我建议做成双保险:一是前端倒计时到点后主动释放;二是后端提供惰性释放——用户再查座位图时,顺便把所有 lock_time 超过 30 分钟且状态为 1 的座位重置为空闲。惰性释放不用额外起定时任务,简单稳定,课设完全够用。
5.3 下单事务与模拟支付
锁定成功后进入确认订单页,展示场次、座位、票价,用户点击"提交订单",后端执行创建订单接口。这里必须用事务,流程是:校验用户登录态和参数;生成订单号(我常用 时间戳 + 6位随机数 + 用户ID后四位,唯一索引兜底);插入 orders 表;把选中的座位更新为"已售",保持锁定占位;返回订单 ID。
事务的 ACID 特性在这个场景体现得非常直观:步骤 3 和步骤 4 只要有一个失败,订单记录和座位状态都不会留下半截数据。代码里就是 connection.beginTransaction() 开始,connection.commit() 提交,connection.rollback() 回滚,配合 try-catch-finally。哪怕你没写过事务,这个结构也是背下来就能用。
支付页点击"确认支付"后,后端 POST /api/pay/mock 做三件事:校验订单属于当前用户且状态为待支付;将 orders 状态改为已支付并写支付时间;插入 payment 流水记录。这样订单详情页就能展示"订单编号 + 座位号 + 支付金额 + 支付时间"的完整信息。
5.4 订单超时处理与重复点击防护
超时场景是:用户锁了座位但一直没下单。我的处理方案是订单创建后 15 分钟未支付自动取消,同时释放座位。实现上同样可以用惰性方案:用户查看订单列表时,后端把该用户"待支付且创建时间超过 15 分钟"的订单置为已取消,并调用释放座位逻辑;下单接口里也会先做一次清理。这种"读取时清理"的模式在课设里完全够用,还避免引入定时任务组件。
另外两个高发问题:一是用户在订单页疯狂点击"提交订单",前端要做好按钮 loading 防重复点击,后端在创建订单接口开头判断该用户是否已有同场次待支付订单,有就提示"请先处理待支付订单";二是模拟支付接口要防止重复提交,条件更新 SET status = 1 WHERE order_no = ? AND status = 0,受影响行数为 0 时直接返回"订单状态已变化"。这些小细节写进文档,明显能拉高项目专业度。
6. 环境配置实录:从 Node.js 安装到 npm 第一次跑通
每次带人搭这套环境,出问题最多的环节不是写代码,而是环境本身。以下内容是从真实报错里攒出来的,按顺序来基本能半小时跑通。
6.1 Node.js 版本选择与安装路径的坑
去 Node.js 官网下载 LTS 版本(Long Term Support 长期支持版),我建议 16.x 或 18.x,不要追求最新版,课设依赖的 Express 4 和老文档模板在较新版本上偶尔有兼容问题。安装时一路 Next 即可,唯一的建议是安装路径改成 D:\nodejs 这种纯英文无空格目录,避免默认 C:\Program Files\nodejs 在后续 npm 全局安装时因为路径带空格产生奇怪权限问题。
安装完成后打开命令行验证:
bash复制node -v
npm -v
能输出版本号,环境就算通了。如果 node 有版本号而 npm 没反应,检查一下环境变量里的 Path 是否包含 Node.js 安装目录。
6.2 npm.ps1 无法加载的解决办法
这是个高频报错,错误内容一般是:npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚本。原因是 PowerShell 默认执行策略是 Restricted,不允许运行 .ps1 脚本文件。
两个解决办法任选其一。方法一:以管理员身份打开 PowerShell,执行:
bash复制Set-ExecutionPolicy RemoteSigned
询问是否更改执行策略时输入 Y 回车。方法二:放弃 PowerShell,改用 CMD(命令提示符)来跑 npm 命令,CMD 不检查 .ps1 执行策略,直接就能用。
我个人的建议是方法一更彻底,因为后面很多教程里的脚本命令都默认在 PowerShell 里执行,提前放开省得反复踩坑。这个报错我在 Windows 上遇到不下十次,每次解决后 npm 各种命令都顺畅了。
6.3 数据库连接、依赖安装与常见报错
数据库用 MySQL 8.0,安装完成后在 Navicat 里新建数据库,字符集选 utf8mb4,导入项目提供的 .sql 文件即可。后端连接配置我习惯单独写在 config/db.js:
javascript复制const mysql = require('mysql2/promise');
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: '你的数据库密码',
database: 'ticket_system',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
module.exports = pool;
高频报错有三个:ER_ACCESS_DENIED_ERROR 说明用户名或密码不对;ER_BAD_DB_ERROR 说明数据库名字不存在或写错;ECONNREFUSED 说明 MySQL 服务没启动。前两个改配置,第三个去 Windows 服务里把 MySQL 服务启动就行了。
依赖安装统一用:
bash复制npm install express mysql2 jsonwebtoken cors
npm install -D nodemon
如果 npm 下载慢,可以改用国内镜像源:
bash复制npm config set registry https://registry.npmmirror.com
node_modules 目录反复破损是 Windows 上常见病,出现奇怪的依赖报错时,直接删掉 node_modules 和 package-lock.json 再重新 npm install,大概率能解决。
7. 小程序端页面实现与适配细节
小程序前端是用户能直接看到的成果,也是演示时最容易出彩的部分。我按页面维度和高频难点讲,你照着做就不会走偏。
7.1 页面结构与底部导航
我的页面结构是五页四 Tab:
text复制pages/
├── index/ # 首页:演出列表、筛选
├── detail/ # 演出详情:场次选择、票价
├── choose-seat/ # 选座页:座位图
├── order-confirm/ # 确认订单
├── order-list/ # 订单列表
├── order-detail/ # 订单详情
└── mine/ # 我的:登录信息、功能入口
底部 TabBar 放四个:首页、订单、我的,加上一个可选的"演出日历"。注意 TabBar 页面不能带参数跳转,所以演出详情、选座、确认订单这些页面都不要放在 Tab 目录里,用 wx.navigateTo 跳转。这个结构和微信小程序原生路由规则是匹配的,照抄不会踩坑。
7.2 自定义导航栏高度计算
默认导航栏只有白色和黑色两种背景,视觉上比较单调。很多课设要求顶部跟主色调统一,这时候就得开自定义导航栏,但坑也随之而来:不同机型状态栏高度不一样,刘海屏和小屏手机差异尤其大。
我封装了一个通用计算函数:
javascript复制function getNavBarHeight() {
const sysInfo = wx.getSystemInfoSync();
const menuBtn = wx.getMenuButtonBoundingClientRect();
const statusBarHeight = sysInfo.statusBarHeight;
const navBarHeight = (menuBtn.top - statusBarHeight) * 2 + menuBtn.height;
return { statusBarHeight, navBarHeight, menuBtn };
}
原理是:胶囊按钮顶部到状态栏底部的距离,乘以 2 再加大胶囊高度,就是导航栏总高度。用这个函数动态设置占位视图的高度,iOS 和安卓、有无刘海的机型都能对齐。这也是热词里大家常搜"微信小程序顶部导航栏高度"的原因,确实没有官方文档给一个现成参数,必须自己算。
7.3 网络请求封装、token 注入与防重复点击
每个页面直接写 wx.request 会出现大量重复代码,我一般封装一个 request.js:
javascript复制const request = (url, method, data) => {
return new Promise((resolve, reject) => {
wx.request({
url: baseUrl + url,
method,
data,
header: {
'Content-Type': 'application/json',
'Authorization': wx.getStorageSync('token') || ''
},
success: (res) => {
if (res.data.code === 0) {
resolve(res.data.data);
} else if (res.statusCode === 401) {
wx.removeStorageSync('token');
wx.navigateTo({ url: '/pages/login/login' });
} else {
wx.showToast({ title: res.data.msg, icon: 'none' });
reject(res.data);
}
},
fail: reject
});
});
};
选座页和订单确认页尤其要防重复点击。用户连续双击"提交订单",后端就算有校验,前端也应该先把按钮设为 loading。我习惯在点击处理函数开头判断标志位,请求结束后再还原,同时配合 wx.showLoading 给用户明确反馈。这个细节在演示时很出效果:疯狂点按钮也不会产生重复订单,老师在文档评分表里通常会给交互逻辑打高分。
8. 万字文档与答辩:会做系统更要会讲系统
最后说文档和答辩,这部分经常被当成凑页数的环节,其实它决定了项目分数的上限。一个能跑的系统加一套逻辑清晰的文档,就是妥妥的课程设计优秀档。
8.1 文档章节怎么编排
我推荐的结构是七章,和大部分学校的课设模板能对齐:
- 第一章 引言:项目背景、意义、国内外现状、主要工作。
- 第二章 相关技术介绍:Node.js、Express、微信小程序、MySQL、token 机制。不要只罗列名词,要写出"为什么用在项目里"。
- 第三章 需求分析:角色分析、功能需求、非功能需求(并发、安全性)、用例表。
- 第四章 系统设计:架构图、功能模块划分、数据库 ER 图、数据表结构说明。
- 第五章 系统实现:按模块截图加关键代码,讲清每个模块怎么实现的。
- 第六章 系统测试:测试环境、功能测试用例表、结果分析。
- 第七章 总结与展望:项目总结、不足、改进方向。
重点是第五章,每个模块都遵循"功能截图 + 核心代码片段 + 业务逻辑说明"的三段式写法。比如订单模块,放下单接口的代码,旁边写上"本模块通过事务保证座位与订单一致",比大段贴代码强太多。
8.2 ER 图、流程图怎么画
画图工具用 draw.io 或 ProcessOn 都行,注意图表要有编号,比如"图 4-1 系统总体架构图""图 4-2 数据库 ER 图"。数据库 ER 图我建议把表名、字段、主键外键关系画清楚,这是老师看得最仔细的一张图;业务流程图画一条主链路:浏览演出 → 选择场次 → 锁定座位 → 创建订单 → 模拟支付 → 订单完成。画图的原则是"让读者一分钟看懂,十秒能复述",花里胡哨的配色不重要。
8.3 答辩演示脚本与三个必答预案
答辩演示不要临场发挥,提前按脚本走一遍。我的演示顺序是:用户登录 → 首页查看演出列表 → 进入详情选择场次 → 选座页锁定 3 个座位 → 确认订单提交 → 模拟支付 → 订单列表看到已支付订单 → 切到后台看到新增了一条订单记录和支付流水。整套流程五分钟,覆盖了所有核心功能。
同时准备三个高频问题的预案:
- 为什么选 Node.js?答:全栈语言统一、异步 IO 适合并发选座、npm 生态成熟、开发效率高。
- 怎么防止同一个座位被买两次?答:座位表条件更新,
WHERE status = 0,并发下数据库行锁保证只有一个请求成功。 - token 过期了怎么办?答:后端返回 401,前端拦截并清理本地 token 跳回登录页重新授权。
最后再分享一个我自己的体会。这类课设项目,代码能跑只是及格线,真正把分数拉开的地方是"你能否讲清楚每个用户在界面上的一次操作,在数据库里落到了哪张表的哪个字段、变成了什么状态"。我帮别人整理项目时发现,多数卡壳的同学不是不会写代码,而是从来没把页面、接口、数据表、状态流转串成一条线。按这篇文章的思路把数据库表梳理一遍,把座位状态、订单状态的口径统一好,再照着演示脚本走两遍,这个项目的逻辑闭环就牢牢长在你自己脑子里了。答辩的时候哪怕老师往深里追问,你也能稳得住。
