资讯详情

基于Node.js的演唱会路演行程安排小程序设计与实现

📅 2026/10/21 21:20:01 | 华诺云谱 👁 阅读
基于Node.js的演唱会路演行程安排小程序设计与实现
A同学拿着题目来找我的时候我第一反应是这名字看着长其实就是个典型的全栈业务系统。题目叫《基于Node.js的演唱会路演行程安排小程序的设计与实现》后面还跟着“完整源码LW部署说明演示视频”这一串交付物。别人看到的是标题我看到的是一个非常适合毕业设计的闭环项目前端小程序、后端Node服务、MySQL数据库、权限控制、消息提醒、地理位置签到全都齐了。这类题目的价值在于“业务能讲清楚、技术能写明白、演示有场景”。演唱会路演行程安排本质上就是把“一场活动拆成多个场次、多个时间点、多个执行人”再用小程序把所有人串起来。主办方创建路演计划团队成员查看今天的安排、按时签到、接收提醒、查看场馆位置后台还能对行程进行统计和管理。做完这个项目你对“需求分析、表结构设计、接口开发、联调部署”这套完整流程会有一个非常扎实的认知答辩论点也很容易展开。我准备把整个实现过程分五个部分来聊需求拆解、技术选型、核心设计、部署演示和踩坑记录。这些都是实操里真正会遇到的细节不是文档里那些套话。1. 项目拆解演唱会路演行程安排到底在解决什么问题1.1 需求从哪来为什么这个题目很适合毕设很多人拿到这种题目先慌的是“演唱会路演”四个字。其实不用慌路演的行程安排和普通会议日程安排没有本质区别只是业务名词更具体。你需要理解的核心是一个执行团队要在多个城市、多个场地之间完成一系列任务有人要协调时间有人要查看地点有人要确认到场有人要发布通知。这类系统通常有双方角色。管理端负责创建“路演计划”在计划下面添加“具体行程”例如某天上午在A场馆彩排下午在某地做设备调试晚上正式演出同时给每个行程安排负责人和参与成员。小程序端则面向执行团队成员他们登录后能看到自己被分配到的行程按时间排序查看地点点击导航到达后完成签到。作为毕设这个题目正好覆盖了小程序、后端接口、数据库表设计、状态管理、权限控制这些高频考点。工作量不会大到失控但又能体现完整的工程意识。A同学选它的时候我已经能判断出只要把行程状态流转和签到校验讲清楚答辩基本稳了。1.2 为什么后端选 Node.js不选 Java 和 Python后端技术栈是 Node.js很多人会问“为什么不用 Spring Boot”。我的看法是对于这个题目Node.js 在三个维度上都更占优势。第一是语言统一。小程序前端用的是 JavaScript后端如果用 Node.js前后端同一种语言理解成本低很多。A同学不是计算机科班出身JavaScript 基础还行让他同时写 Java 后端和微信小程序学习曲线会陡很多。Node.js 让他能把精力放在业务逻辑而不是语法切换上。第二是开发效率。Express 框架几行代码就能把服务搭起来搭配 mysql2 操作数据库、jsonwebtoken 做登录态、dayjs 处理时间几乎不需要额外配置。做毕设最重要的是在有限时间内跑通闭环而不是花两周写配置类。第三是适合这个场景。行程查看、签到上报、提醒推送这些接口都是典型的 I/O 密集型操作Node.js 的事件循环模型处理这种读多写少的接口非常从容。答辩时你可以说“利用非阻塞 I/O 提升并发处理能力”这是加分点。当然如果你熟练 Java选 Spring Boot 也没问题。但如果你是从零开始实现这个题目Node.js 的容错率明显更高。1.3 功能清单与角色权限先想清楚再动手动手写代码之前我习惯先把功能清单列成表格。这个项目我帮 A同学定的是四个端管理后台网页端、小程序用户端、Node 服务端、MySQL 数据库。为了控制工作量把管理端合并在 Node 服务提供的接口里前端用简单的管理页面调用或者直接用接口工具调试也说得通。规划功能模块时我建议把最低可行功能和高阶功能分开。最低可行功能是项目能交差的底线高阶功能是答辩时的亮点。模块核心功能使用角色用户认证小程序登录、Token 校验、角色判断所有用户路演计划创建计划、添加行程、调整状态管理员行程管理按时间查看行程、按地点筛选、确认参与人员管理员、行程负责人签到打卡获取当前位置、校验范围、记录签到时间普通成员消息提醒行程变更通知、开始前提醒系统后台触发数据统计签到率、未签人员列表、行程完成度管理员角色权限我用最简单的三档admin 管理员leader 行程负责人member 普通成员。管理员可以创建和修改所有行程负责人可以修改自己负责的行程状态比如将“未开始”置为“进行中”普通成员只能查看和签到。一开始可以把权限做成整块控制后续再细到字段级。毕设最重要的是把“有权限控制”这件事讲清楚而不是做一套过于复杂而自己也解释不了的 RBAC 模型。2. 从零设计数据库和后端接口2.1 表结构设计别一上来就堆字段A同学最开始想的是“一张行程表走天下”。我直接拦住了行程表之外必须要有独立的用户表、计划表、签到表、通知表。表设计不清晰后面每个功能都要返工。我给他定了六张核心表user、tour、schedule、schedule_member、checkin、notification。其中 schedule_member 是行程和用户的关联表用来表达“这个行程有哪些人参与”。如果只用一张行程表去存成员和签到信息查询时各种 JSON 拼接会让你想摔键盘。以核心的行程表为例字段设计大概是这样的CREATE TABLE schedule ( id int NOT NULL AUTO_INCREMENT, tour_id int NOT NULL COMMENT 所属路演计划, title varchar(100) NOT NULL COMMENT 行程标题如XX站彩排, location_name varchar(100) NOT NULL COMMENT 场地名称, longitude decimal(10, 6) NOT NULL COMMENT 经度, latitude decimal(10, 6) NOT NULL COMMENT 纬度, start_time datetime NOT NULL COMMENT 预计开始时间, end_time datetime NOT NULL COMMENT 预计结束时间, status tinyint NOT NULL DEFAULT 0 COMMENT 0未开始 1进行中 2已完成 3已取消, leader_id int DEFAULT NULL COMMENT 行程负责人, remark varchar(255) DEFAULT NULL COMMENT 备注, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这里有三个设计习惯值得你记下来。第一经纬度用 decimal(10,6)不用 float。float 的精度在地理坐标场景下会出偏差你不想因为签到距离判断出错在答辩时翻车。第二status 用 tinyint不用字符串。字符串在存储上更浪费而且容易拼写出错。程序里用常量对应数字例如 STATUS_CONST { UNSTARTED: 0, PROCESSING: 1, DONE: 2, CANCELED: 3 }。第三所有时间字段都用 datetime不存字符串。虽然小程序端传过来的可能是字符串但服务端接收后必须转成 Date 对象再写入数据库。排序和区间查询都会简单很多。签到表的设计比你想的更简单字段就是 id、schedule_id、user_id、sign_time、location_desc、status。不用存经纬度快照也行如果要做防作弊可以额外存一份当时的经纬度方便和实际场地坐标做对比。2.2 接口规划RESTful 风格怎么落到这个项目表结构定了接口就跟着清晰。我习惯先把接口清单列出来再写代码避免写着写着发现缺字段。基础接口大概是这些POST /api/user/login 小程序登录 GET /api/user/info 获取用户信息 GET /api/tour/list 路演计划列表 POST /api/tour/create 创建路演计划 POST /api/schedule/create 添加行程 GET /api/schedule/my 我参与的行程 PUT /api/schedule/status 更新行程状态 POST /api/checkin/submit 提交签到 GET /api/checkin/list 某行程签到记录 POST /api/notification/send 发送行程提醒接口返回格式统一用 { code: 0, message: success, data: ... }小程序端封装 request 时很省事。不要一会返回 code 一会返回 status看起来不专业。拿登录接口举例用 Express 实现大概是这样的const express require(express); const router express.Router(); const jwt require(jsonwebtoken); const bcrypt require(bcryptjs); const db require(../db); router.post(/login, async (req, res) { const { username, password } req.body; if (!username || !password) { return res.json({ code: 1, message: 用户名和密码不能为空 }); } const [rows] await db.query(SELECT * FROM user WHERE username ?, [username]); if (rows.length 0) { return res.json({ code: 1, message: 用户不存在 }); } const user rows[0]; const ok bcrypt.compareSync(password, user.password); if (!ok) { return res.json({ code: 1, message: 密码错误 }); } const token jwt.sign({ id: user.id, role: user.role }, process.env.JWT_SECRET, { expiresIn: 2h }); res.json({ code: 0, data: { token, userInfo: { id: user.id, nickname: user.nickname, role: user.role } } }); }); module.exports router;代码本身不难但要注意两个点。一是密码一定要用 bcrypt 这类算法加密存储不能直接存明文。答辩时如果被问到“数据库泄露怎么办”这就是你的回答。二是 JWT_SECRET 要放在环境变量里不要写死在源码中。我们最终打包交付时会把 .env 文件里的内容整理掉避免把密钥也交出去。2.3 鉴权与权限控制JWT 中间件要写清楚接口写完之后最容易被忽略的是权限控制。很多毕设项目所有接口都能直接访问演示很顺但答辩时被老师问“怎么防止普通用户删除行程”就傻眼了。这个项目里我写了一个 authMiddleware.js 做登录校验一个 adminMiddleware.js 做管理员校验。核心逻辑很直白从请求头拿到 Authorization 里的 token解密后把用户信息挂到 req.user然后判断角色。const jwt require(jsonwebtoken); function auth(req, res, next) { const header req.headers[authorization]; if (!header) { return res.status(401).json({ code: 401, message: 未登录 }); } const token header.split( )[1]; try { const payload jwt.verify(token, process.env.JWT_SECRET); req.user payload; next(); } catch (e) { return res.status(401).json({ code: 401, message: 登录已过期 }); } } function admin(req, res, next) { if (!req.user || req.user.role ! admin) { return res.status(403).json({ code: 403, message: 无权限 }); } next(); } module.exports { auth, admin };建议把“更新行程状态”这个接口保留给负责人或管理员把“创建行程”这个接口设置成只允许管理员。小程序端的所有请求都走封装好的 request 函数在收到 401 时统一跳回登录页。这套逻辑写完你在论文里可以单独写一节“系统安全设计”。3. 小程序端实现首页到行程详情3.1 原生小程序还是 uni-app毕设选哪个更稳微信小程序的原生开发和 uni-app 都是常见选择。我的建议是如果只是做毕设原生更稳。原生小程序的结构非常直接页面由 .wxml、.wxss、.js、.json 四个文件组成官方文档写得清楚调试工具也稳定。uni-app 好处是能编译到多端但中间多了一层转换遇到样式或者生命周期问题排查起来很痛苦。毕设时间有限不要为了“我在简历里写会 uni-app”这种想法去选一个自己都没把握的框架。项目页面我分了五个首页展示路演计划行程页展示我的日程地图页负责导航和签到消息页展示提醒我的页面展示用户信息。小程序端唯一要特别注意的就是不能在 setData 里传太多数据比如一个用户的全部行程可能有几十条可以分页加载每次拉十条滑动到底部再加载下一页。行程卡片是核心 UI 元素结构大概这样view classcard wx:for{{list}} wx:keyid bindtaptoDetail view classtime{{item.startText}}/view view classtitle{{item.title}}/view view classlocation{{item.locationName}}/view view classstatus {{item.statusClass}}{{item.statusText}}/view /view注意后端接口返回的时间如果是标准格式建议在小程序端先做格式化再放进渲染层。别在 WXML 里写大量表达式小程序模板的运算能力有限而且难调试。3.2 行程列表与状态流转核心逻辑怎么组织这个系统的“行程”不是简单的一条记录它有一个状态生命周期。我定的是未开始、进行中、已完成、已取消。用户看到的操作按钮要根据状态动态变化。比如一个行程处于“未开始”负责人可以点击“开始行程”状态变为“进行中”普通成员只能查看不能操作行程结束后负责人置为“已完成”。如果你还想做复杂点可以把“已取消”设计成只能由管理员操作并且取消时给所有参与成员发送通知。状态流转的核心在后端接口前端只需要根据状态渲染按钮。这里容易踩坑的是时间判断。比如一个行程的开始时间是今天 10 点用户 9 点打开页面状态还是“未开始”但如果管理员没有手动置为“进行中”到了 10 点系统会不会自动改状态我的做法是接口返回列表时动态计算一个 showStatus。如果数据库状态是“未开始”且当前时间大于开始时间且小于结束时间就显示“进行中”如果当前时间大于结束时间且状态仍然是“未开始”就显示“部分成员未签到状态待确认”。这种动态逻辑不必写进数据库查询时计算即可。3.3 提醒与签到给高分看的两个加分项提醒和签到是这个项目里最能体现业务思考的功能也是答辩时容易被追问的。先说提醒。微信小程序里做消息推送能用的是“订阅消息”。用户需要在页面里主动授权订阅服务端才能通过接口给该用户推送一条模板消息。最简单的实现方式是在用户点击“订阅该行程提醒”时前端先调用 wx.requestSubscribeMessage拿到一个标识再把这个标识提交给后端。后台在行程开始前通过定时任务或管理员手动触发向已订阅用户发送消息。真实项目中可能会用定时任务比如 node-schedule 每分钟扫一次数据库发现即将开始的行程就调用微信接口推送。但这个逻辑涉及到 Access Token 的获取和缓存要做也能做但要注意微信云函数的调用限制。我这里给 A同学的做法是管理端创建行程时勾选“是否发送提醒”然后后端在创建成功后立即拉取参与该行程的用户 openid调用订阅消息接口。这样用户虽然收到的是定时消息但实际上是在创建行程时触发的逻辑上也能说通。再说签到。签到不能只点一个按钮那是摆设。要给高分必须做“地理围栏校验”用户点击签到时小程序获取当前经纬度传给后端后端计算当前位置和场地坐标的距离如果超过设定范围例如 500 米就拒绝签到。距离计算我用的是 haversine 公式代码不长function getDistance(lat1, lng1, lat2, lng2) { const rad Math.PI / 180; const dLat (lat2 - lat1) * rad; const dLng (lng2 - lng1) * rad; const a Math.sin(dLat / 2) ** 2 Math.cos(lat1 * rad) * Math.cos(lat2 * rad) * Math.sin(dLng / 2) ** 2; return 2 * 6371000 * Math.asin(Math.sqrt(a)); // 单位米 }600 多公里的地球半径在这里用 6371000 米就够了。500 米这个阈值可以根据场景调整比如场馆大就放宽到 800 米。签到成功后后端记录签到时间和经纬度快照管理端可以看统计列表。签到这个小功能确实让这个项目的“行程安排”落到了实处也让答辩老师觉得你不是只会增删改查。4. 部署、打包和演示视频一条龙4.1 本地部署三步把项目跑起来这个项目交付的时候不能被“环境都跑不起来”毁掉。我整理了一套标准的部署流程跟着走基本不会出问题。第一步是装环境。需要 Node.js 16 或 18 LTS 版本、MySQL 8、微信开发者工具。不建议用 Node 20 或者更高的测试版有些老版本依赖会编译报错犯不着冒险。装好 MySQL 后新建一个数据库导入项目里提供的 init.sql 文件表结构和演示数据就都有了。第二步是改后端配置。项目根目录下有一个 .env.example 文件复制一份改成 .env填上你的 MySQL 用户名和密码还有 JWT 密钥。然后在后端目录执行npm install npm start如果一切正常控制台会输出类似“Server listening on port 3000”的日志。这里最常见的坑是 MySQL 的 host 写成了 localhost 但服务端跑在容器或者远程服务器上导致连不上。本地开发直接用 127.0.0.1 最稳。第三步是改小程序配置。在微信开发者工具里导入小程序项目目录修改 utils/request.js 里的 baseURL 为你的后端地址。如果你用开发者工具调试本地服务注意要在“详情-本地设置”里勾选“不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书”否则请求直接被拦截。部署到服务器时前端小程序的 baseURL 必须要改成服务器的公网地址而且需要 HTTPS 才能正式发布。毕设演示如果不需要线上发布用开发者工具的“不校验域名”模式就够了。4.2 演示视频怎么录才不翻车A同学问我演示视频是不是就是把每个页面点一遍我说那样录出来的视频答辩老师根本看不下去。正确的演示视频必须有一条业务主线。我给他定的脚本是管理员登录后台创建一个“某城市站”路演计划添加三条行程分别安排在不同时间和地点回到小程序端以成员身份登录查看我的行程列表点击某条行程查看详情进入地图页点击导航按钮模拟到达场地点击签到系统返回签到成功再切到管理端查看签到统计看到刚才的签到记录。整个过程控制在十分钟左右重点拍清楚操作步骤和返回结果。录屏时不要开一堆后台窗口手上最好把手机横屏模拟真实用户在小程序里操作。视频里可以配一条时间轴字幕例如“0:00 管理员创建行程2:30 小程序端查看列表6:10 位置签到演示”。这样老师看的时候能快速抓住重点。4.3 LW设计文档写作顺序和时间安排交付物里提到的 LW通常就是毕业设计论文或设计说明书。很多同学代码写完了才开始憋论文这是最痛苦的顺序。我建议反过来每写完一个模块立刻截图、记录设计思路最后写文档是拼装素材不是从零创作。论文结构我建议是绪论、相关技术、需求分析、系统设计、系统实现、系统测试、总结与展望。其中需求分析部分可以放“用户角色分析”和“功能用例图”系统设计部分重点写“总体架构”和“数据库设计”把表结构截图放进去系统实现部分按模块贴关键代码并解释用意测试部分列出测试用例表包括“正常创建行程”、“重复签到拦截”、“非管理员无权创建行程”等测试结果。时间安排上我给 A同学排了三周第一周做需求分析和数据库设计第二周完成后端接口和核心逻辑第三周做小程序页面、联调和写文档。实际操作下来因为他没有在选题上犹豫整个过程还挺流畅。最容易被问的是“为什么这么设计”而不是“代码怎么写”。所以文档里每个关键设计都要留一句话解释。例如“为什么用 JWT因为小程序接口是无状态请求JWT 可以避免在服务端存储大量 session 数据”。这样的描述远比写一段教材定义有价值。5. 踩坑记录与答辩速查5.1 最容易遇到的五个报错与解法我陪 A同学联调的时候踩过几个很典型的坑。整理成表格方便以后有人复现时直接对照。现象原因解法小程序请求本地接口报 404baseURL 写错或者端口不对检查 request.js 里的地址是否带端口号例如 http://127.0.0.1:3000MySQL 连接报 ER_NOT_SUPPORTED_AUTH_MODEMySQL 8 默认认证插件是 caching_sha2_passwordmysql2 驱动早期版本用不了使用新版 mysql2或者在连接参数里指定 authPluginsJWT 登录后很快失效token 有效期设置太短设置 expiresIn: 2h并让前端在收到 401 时跳转登录微信地图定位失败app.json 没配置位置接口权限在 app.json 里加 permission.scope.userLocation 声明npm install 报错 ERR_OSSL_EVP_UNSUPPORTEDNode 版本过高部分依赖使用旧版 OpenSSL降到 Node 16 LTS 再重新安装依赖这些坑不是看一眼就会的真要遇到了最快的排查方式是看控制台日志然后逐个排除。千万别一上来就怀疑代码逻辑十次里八次是环境问题。5.2 答辩前一定要准备的三个问题第一个问题“为什么选用 Node.js 而不是 Spring Boot”回答思路项目业务是轻量级接口和实时信息查询Node.js 的异步非阻塞模型很适合同时前后端都是 JavaScript整个项目语言栈统一维护成本低。不要只说“因为简单”要结合项目讲技术特点。第二个问题“行程状态是怎么管理的”回答思路数据库里用一个 status 字段程序里定义常量映射接口层根据请求角色做状态变更校验例如只有负责人才能把“未开始”改成“进行中”列表返回时还会结合当前时间动态计算显示状态。这个答案能体现出你考虑了真实业务里的边界情况。第三个问题“如果用户到了现场但手机定位不准签到失败了怎么办”回答思路允许用户手动选择“我已到达”并提交但会记录该操作管理端可以看到异常签到记录人工复核后可以修正状态。这里你跳出技术层面体现了产品设计意识答辩老师会认可。我个人在实际操作中的体会是这个项目真正难的不是某个单独的技术点而是把所有环节串起来的能力。A同学能顺利做完很大程度上是因为他在动手前把功能清单、数据表、角色权限都想清楚了。你要复现这个题目别急着写代码花两天把表结构和接口定义理清后面会顺很多。最后再分享一个小技巧交付项目和写文档时所有代码里的测试数据、临时二维码、本地图片路径都要清理干净。用一套干净的演示数据跑通流程截图、录视频整个交付物的完成度会立刻高一个档次。找个安静的时间从 init.sql 重新初始化一遍数据库把项目完整跑一遍这是最简单也最容易被忽略的验收动作。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑