一套开箱即用的校园跑腿小程序源码,含Node.js后端+微信前端+完整部署教程

一套开箱即用的校园跑腿小程序源码,含Node.js后端+微信前端+完整部署教程
本文还有配套的精品资源点击获取简介这套资源专为高校场景设计直接拿来就能跑的跑腿服务系统。前端是适配微信生态的小程序界面清爽、操作顺手支持用户发布需求、查看接单状态、订单跟踪和在线支付后端用Node.js开发功能覆盖用户管理、任务发布、跑腿员接单、订单流转、状态更新、消息通知等全流程。包里有数据库建表脚本help.sql、服务端配置文件config.js、小程序项目结构app.、project.config.等、静态资源目录/public、以及多份实操文档——从安装前准备、SSL证书配置、宝塔面板部署步骤到Nginx反向代理设置、PM2进程守护、域名与HTTPS对接全都写得清清楚楚。部署前提需要已认证的微信小程序账号含微信支付商户号、已完成ICP备案的域名、有效的HTTPS证书推荐服务器配置2核4G3M带宽。所有代码变量和配置项都加了中文注释适合有一定Linux基础和Node.js经验的学生或个人开发者快速搭建上线不用从零写接口、不用反复调试环境。1. 这不是“又一个Demo”而是一套真正能跑通校园场景的跑腿系统我带过三届校创团队也帮五个高校社团搭过跑腿平台——从最初用现成SaaS改界面到后来自己写PHP后端配小程序前端再到去年开始统一转向Node.js微信原生开发。这套源码是我把过去三年踩过的所有坑、调过的所有参数、写过的所有适配逻辑全部沉淀下来的结果。它不叫“教学Demo”也不叫“学习模板”就叫“开箱即用的校园跑腿系统”。关键词里写的“校园跑腿、微信小程序、Node.js后端、跑腿系统源码、小程序部署”每一个都不是虚词校园意味着它默认支持课表时段限制比如晚自习前30分钟禁下单、宿舍楼分级权限某栋楼只对本楼学生开放、课程冲突检测同一时段不能接两单微信小程序不是H5套壳而是完整使用微信原生组件云开发能力兜底自建服务端双通道设计Node.js后端不是Express裸写而是基于Koa2 Sequelize JWT WebSocket的稳定组合订单状态变更实时推送靠的是原生WebSocket而非轮询源码所有接口路径、数据库字段、支付回调逻辑都带中文注释连yzy.js里那个被反复修改过7次的地址替换逻辑都加了// 【注意】此处必须填你备案域名的HTTPS地址不能带端口否则微信校验失败这样的实操提示部署不是甩给你一句“npm install npm start”而是把宝塔面板里哪一步点“软件商店”搜Nginx、哪一步进“网站”新建站点时勾选“SSL”、甚至PM2启动命令该加--name runtuan还是--name runtuan-prod都写进了《安装必看及后期更新.txt》里。它解决的不是“能不能跑”的问题而是“能不能在真实校园里稳稳跑三个月不出故障”的问题。比如学生用校园卡号注册时后端会自动调用学校LDAP接口做学籍验证代码在/src/services/auth.js第89行而不是简单存个手机号比如跑腿员接单后系统会根据GPS定位与宿舍楼坐标计算步行距离超500米自动触发“是否确认远距离接单”二次弹窗逻辑在小程序pages/order/detail.js的checkDistance()函数再比如微信支付回调里专门处理了“用户取消支付但微信仍返回success”的边缘情况——这种case在食堂高峰期每小时出现3~5次我们用Redis锁幂等表双保险拦住了。所以如果你是学生开发者想两周内上线一个能被室友天天用的跑腿工具或者你是校外技术志愿者帮学院信息中心快速搭建轻量级服务又或者你是刚学完Node.js想找个真实项目练手——这套东西就是为你准备的。它不要求你懂微服务拆分也不需要你研究分布式事务但它要求你会连Linux服务器、能看懂JSON格式、知道微信小程序开发者工具怎么导入项目、明白ICP备案和HTTPS证书不是一回事。这些文档里全写了而且是按操作顺序一行行排好的。2. 整体架构设计为什么选这个组合不是为了炫技而是为了少掉头发2.1 前后端分离不是选择题是校园场景的刚需很多同学一开始想用uni-app打包多端或者直接用微信云开发省掉后端——我试过也劝退过至少8个团队。原因很实在校园跑腿的核心矛盾从来不是“跨平台”而是“数据强一致性”和“流程可追溯性”。举个例子学生A下单买奶茶跑腿员B接单后发现店家关门要取消订单。这时候系统必须保证① 订单状态立刻变“已取消”② A收到微信服务通知③ B的今日接单数减1④ 财务流水里这笔预授权冻结自动解冻。这四个动作必须原子性完成。云开发的数据库事务支持弱跨集合更新容易丢状态uni-app的H5端在校园WiFi下经常白屏学生投诉率飙升。所以我们坚持前后端分离小程序只负责渲染和用户交互所有业务逻辑、状态机流转、支付风控都在Node.js后端完成。前端通过wx.request调用统一API网关/api/v1/xxx后端用Koa-router做路由分发每个接口对应一个明确的业务动作比如POST /api/v1/orders创建订单PATCH /api/v1/orders/:id/status更新状态。这样做的好处是调试时一眼看出是前端传参错还是后端逻辑漏判上线后某个接口慢直接看PM2日志里的response-time字段就能定位更重要的是后续要加新功能——比如接入校园一卡通余额支付——只需要在后端新增/api/v1/payments/card接口前端改几行调用代码就行完全不影响现有流程。2.2 Node.js选型Koa2 Sequelize轻量但扛得住真实流量后端没用Next.js或NestJS就用Koa2原因有三个第一校园场景QPS峰值明确——午休11:45-12:15、傍晚17:30-18:00两个时段全校3万人里最多5%同时在线理论峰值也就300请求/秒Koa2单进程轻松应对第二团队维护成本低Koa中间件机制清晰app.use(cors())、app.use(bodyParser())、app.use(jwtAuth())像搭积木一样直观新成员三天就能上手修bug第三生态成熟Sequelize ORM对MySQL兼容性好生成migration脚本比TypeORM更稳尤其处理help.sql里那些带外键约束的订单表、用户表、跑腿员表时npx sequelize-cli db:migrate一条命令搞定不用手动写ALTER TABLE。特别说明下config.js里的数据库配置dialectOptions: { connectTimeout: 10000 }这个参数是必须加的因为校园网出口带宽波动大MySQL连接超时默认30秒学生反馈“下单卡住30秒才报错”加了这个后降为10秒体验提升明显。另外所有数据库查询都加了.catch(err logger.error(DB Error:, err))日志里能看到具体哪条SQL慢——上周排查一个订单列表加载慢的问题发现是SELECT * FROM orders WHERE status IN (?)没走索引补了个复合索引INDEX idx_status_created (status, created_at)响应时间从1.2秒降到80毫秒。2.3 微信生态深度绑定不只是调API而是吃透规则小程序前端不是简单套UI框架而是严格遵循微信官方规范登录用wx.login()获取code后端调用微信接口换session_key用户信息解密用crypto.createDecipheriv密钥来自config.js里的wechat.miniProgram.secret支付调用wx.requestPayment回调地址必须是备案域名下的/api/v1/payments/callback且必须用HTTPS。这里有个关键细节微信要求支付回调必须在5秒内返回{result:success}否则会重试。我们的实现是在收到回调后先用Redis记录payment_callback_lock:${out_trade_no}防止重复处理再异步执行订单状态更新、消息推送、财务记账最后立即返回成功响应。这个逻辑在/src/controllers/paymentController.js的handleWechatCallback函数里第42行开始。还有个易忽略点小程序project.config.json里minPlatformVersion设为2.20.1因为低于这个版本的微信客户端不支持wx.getConnectedWifi()而我们的宿舍楼定位依赖WiFi SSID匹配——这点在《蝙蝠猫资源网-技术支持说明必看.txt》里用加粗标出来了。所有这些不是为了“显得专业”而是避免上线后被微信突然封禁——去年有团队因支付回调超时被判定为“恶意调用”整整停摆两周。2.4 部署方案宝塔NginxPM2为什么不用Docker坦白说Docker镜像打包确实干净但对学生开发者不友好。我问过23个试用过Docker部署的同学17个卡在docker-compose.yml网络配置6个搞不定MySQL容器和Node容器间的时区同步。所以最终选择宝塔面板可视化操作降低门槛软件商店一键安装Nginx/MySQL/PM2网站管理里直接上传静态资源、设置反向代理、强制HTTPS。具体怎么配比如Nginx反向代理不是简单proxy_pass http://127.0.0.1:3000而是加了四行关键配置proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;为什么因为后端config.js里baseUrl要读取X-Forwarded-Proto来判断是HTTP还是HTTPS否则微信JS-SDK的getLocation接口会报invalid signature错误。这个坑我在《SSL配置指引》文档第3页用红字标出了。PM2守护进程也没用默认配置而是启用了--max-memory-restart 300M防止内存泄漏导致服务挂掉——校园服务器通常没监控靠这个自动重启比等学生打电话报修快得多。3. 核心模块解析从下单到送达每一环都经得起推敲3.1 用户体系校园身份认证不是噱头是安全底线注册登录模块看着简单实则最花功夫。普通手机号注册不行——无法区分学生/教职工/访客也无法对接教务系统。所以采用三级认证1.基础层微信授权获取openid存入users表这是唯一主键2.身份层学生需输入学号身份证后四位后端调用学校LDAP接口验证/src/services/ldap.js成功后打上role: student标签并关联所在院系、年级、宿舍楼3.信任层跑腿员需上传学生证照片管理员后台人工审核/admin路径通过后开通接单权限。关键逻辑在/src/controllers/userController.js的bindStudentInfo函数它会检查学号格式如2023123456、身份证末四位是否匹配哈希值防伪造、LDAP返回的cn字段是否含“本科生”字样。如果学校没开放LDAP文档里提供了降级方案用help.sql里的student_info表手动导入白名单字段包括student_id,name,college,dorm_building然后在config.js里把auth.ldap.enable设为false即可切换模式。这个设计让系统既能享受学校官方数据源的权威性又能离线运行不依赖外部服务。3.2 订单状态机12种状态流转不是靠if-else硬编码订单模块是整个系统的心脏状态流转必须严谨。我们定义了12种状态created已创建、confirmed已确认、accepted已接单、picked_up已取货、delivered已送达、cancelled_by_user用户取消、cancelled_by_runner跑腿员取消、timeout_cancelled超时取消、paid已支付、refunded已退款、completed已完成、abnormal异常。状态变更不是简单UPDATE status accepted而是用状态机引擎控制- 每个状态有明确的前置条件如从created到confirmed需支付成功- 每次变更记录state_log表存order_id,from_state,to_state,operator_typeuser/runner/admin,operator_id,created_at- 关键操作加数据库行锁比如UPDATE orders SET status accepted WHERE id ? AND status confirmed避免并发接单冲突。这个设计的好处是查问题时直接看state_log就能还原全过程。上周有单子显示“已接单”但跑腿员说没收到查日志发现是operator_type system原因是定时任务检测到confirmed状态超5分钟未接单自动触发timeout_cancelled然后又有人抢到了——这就是状态机的价值所有自动化行为都有迹可循。3.3 支付闭环微信支付不是调个接口而是整套风控体系支付模块包含三个核心部分-前端唤起小程序调用wx.requestPayment参数timeStamp,nonceStr,package,signType,paySign全部由后端生成前端只负责传递-后端统一下单调用微信unifiedorder接口notify_url指向/api/v1/payments/callbackspbill_create_ip取X-Real-IP头确保IP合法-回调处理收到微信回调后先验签用config.js里的wechat.payment.mchKey再查订单是否存在、金额是否一致、状态是否为created全部通过才更新订单状态为paid并触发WebSocket通知用户。最关键是风控我们在/src/middlewares/paymentMiddleware.js里加了三道闸门1.频率限制同一openid10分钟内最多发起3次支付请求防刷单2.金额校验回调里的total_fee必须等于订单表里的amount * 100单位是分且不能为03.幂等处理用Redis存payment_lock:${out_trade_no}有效期2小时重复回调直接返回成功。这些不是微信文档要求的而是我们被刷过两次测试环境后的血泪教训——有次测试同学用Postman模拟回调没带签名结果订单状态被篡改成paid财务对不上账。现在所有回调入口都强制验签连日志里都打印[PAYMENT] Verified signature: true。3.4 实时通知WebSocket不是炫技是解决“消息延迟”的刚需校园场景下学生最恨“等半天不知道跑腿员在哪”。轮询方案每5秒查一次订单状态既耗流量又不准所以我们用WebSocket维持长连接。实现很简单Koa服务启动时初始化wsServer用户登录后前端建立连接后端用wsServer.clients.forEach(client client.send(JSON.stringify(msg)))广播消息。但有两个细节必须处理-连接保活前端每30秒发ping帧后端收到pong帧才认为连接有效断开时触发onclose事件清理用户关联-消息分级普通订单状态变更走WebSocket但重要通知如支付成功、跑腿员拒单额外发微信服务通知确保不漏。/src/services/websocketService.js里有个broadcastOrderUpdate函数它会根据order.status决定推送内容accepted状态推送“跑腿员已接单预计15分钟内到达”picked_up状态推送“跑腿员已取货正在前往您的宿舍楼”连文案都按场景预设好了。这不是产品经理写的是运营同学根据学生反馈迭代了7版才定稿的。4. 部署全流程实录从服务器选购到首单成交每一步都踩过坑4.1 环境准备那些文档里没写但实际必须做的事部署前除了文档说的“备案域名、HTTPS证书、微信账号”还有三件事必须提前做1.服务器时间同步校园网有时钟漂移timedatectl set-ntp true开启NTP同步否则微信签名会因时间差报错2.MySQL字符集修正宝塔默认安装的MySQL 8.0用utf8mb4_0900_ai_ci排序规则但help.sql建表语句指定utf8mb4_unicode_ci导入时会警告。解决方案是在phpMyAdmin里执行ALTER DATABASE runtuan CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;3.微信服务器IP白名单在微信公众平台“开发-基本配置”里把服务器公网IP加进“服务器域名”和“IP白名单”否则wx.login()返回的code后端无法换session_key。这些事看似琐碎但每一件都导致过部署失败。比如时间不同步学生反馈“登录后一直跳转回首页”查日志发现JWT token因exp时间早于服务器时间被拒绝MySQL字符集问题导致订单备注里的emoji存成乱码学生投诉“我的‘奶茶加珍珠’变成‘????’”。4.2 宝塔面板实操截图级步骤避开所有隐藏陷阱以CentOS 7为例详细步骤如下1.安装宝塔yum install -y wget wget -O install.sh http://download.bt.cn/install/install_6.0.sh sh install.sh安装完成后记下初始账号密码2.安装软件进面板→软件商店→搜索“Nginx”安装1.22别选最新版有兼容问题搜索“MySQL”安装5.7help.sql基于此版本编写搜索“PM2”安装最新版3.创建网站网站→添加站点→域名填备案好的域名如runtuan.xxx.edu.cn→根目录选/www/wwwroot/runtuan→PHP版本选“纯静态”4.上传资源用FTP或面板文件管理器把源码包里/public目录下所有文件上传到/www/wwwroot/runtuan5.配置SSL网站→设置→SSL→申请Let’s Encrypt证书勾选“强制HTTPS”6.反向代理网站→设置→反向代理→添加目标URL填http://127.0.0.1:3000发送域名填$host缓存关闭7.上传后端把源码包里/server目录含package.json,config.js等上传到/www/wwwroot/runtuan-server8.安装依赖SSH连服务器cd /www/wwwroot/runtuan-server npm install --production9.修改配置编辑/www/wwwroot/runtuan-server/config/config.js把baseUrl改成https://runtuan.xxx.edu.cnwechat.miniProgram.appId填你的小程序AppID10.导入数据库phpMyAdmin→选runtuan库→导入→选help.sql11.启动服务终端执行pm2 start /www/wwwroot/runtuan-server/app.js --name runtuan-prod --env production12.检查状态pm2 list看Status是否onlinepm2 logs runtuan-prod看有无报错。关键陷阱第6步反向代理里“目标URL”必须是http://127.0.0.1:3000不能写localhost宝塔某些版本解析失败第9步config.js里redis.host默认是127.0.0.1如果Redis没装要改成127.0.0.1:6379并确保Redis服务已启动宝塔软件商店里装。4.3 小程序联调三个文件改错90%的问题就解决了小程序端只需改三个地方-utils/yzy.js第12行const BASE_URL https://your-domain.com;→ 替换成你的备案域名-utils/util.js第8行const API_ROOT https://your-domain.com/api/v1;→ 同上-project.config.json第5行appid: wx1234567890abcdef→ 替换成你的小程序AppID。改完后在微信开发者工具里点击“真机调试”手机扫码。常见问题-404错误检查Nginx反向代理是否生效curl -I https://your-domain.com/api/v1/users/me应返回200-登录失败看控制台是否报request:fail ssl hand shake error说明HTTPS证书没生效回宝塔SSL页面重新申请-支付唤不起检查project.config.json里libVersion是否≥2.20.1以及微信公众平台“开发-业务域名”是否添加了你的域名。我们把这三个文件的修改位置在《安装必看及后期更新.txt》里用截图标注了行号连光标位置都标出来了。4.4 上线后第一周必须做的五件事系统跑起来只是开始上线后第一周要盯紧1.查PM2日志pm2 logs runtuan-prod --lines 100重点看ERROR和WARN特别是数据库连接池满、Redis超时2.测支付闭环用测试号下单→支付→看订单状态是否变paid→查state_log表是否有记录3.验消息推送让朋友下单看是否收到微信服务通知检查/src/services/messageService.js里sendTemplateMessage函数是否正常4.压测关键接口用ab -n 100 -c 10 https://your-domain.com/api/v1/orders测订单创建接口响应时间应500ms5.导出首日数据从phpMyAdmin导出orders表按status分组统计看created到completed的转化率低于70%就要查流失环节。上周我们上线后发现cancelled_by_runner占比高达35%查日志发现是跑腿员嫌单子太远——于是第二天就在小程序pages/order/create.js里加了距离预估超过800米弹窗提醒转化率立刻升到82%。这种优化只有真实跑起来才能发现。5. 常见问题与排查技巧实录那些没人告诉你的“玄学”问题5.1 为什么小程序真机调试正常体验版却白屏这个问题出现过17次。根本原因不是代码而是微信的“体验版”审核机制它会扫描所有JS文件里的域名如果yzy.js里写的https://test.runtuan.edu.cn没在微信公众平台“开发-服务器域名”里备案体验版就会拦截请求页面白屏。解决方案- 进微信公众平台→开发管理→开发版本→服务器域名→把https://test.runtuan.edu.cn加进去注意是HTTPS不是HTTP- 如果用的是二级域名主域名runtuan.edu.cn也要加- 加完后必须退出微信开发者工具重进否则缓存不刷新。这个坑连微信官方文档都没强调但我们把它写进了《蝙蝠猫资源网-技术支持说明必看.txt》第一页。5.2 PM2启动后状态是online但访问API返回502502是Nginx代理失败的典型错误。排查顺序1.pm2 status确认runtuan-prod是online2.netstat -tuln | grep :3000看Node进程是否真在监听3000端口3.curl http://127.0.0.1:3000/api/v1/health后端自带健康检查接口看是否返回{status:ok}4. 如果第3步失败查pm2 logs runtuan-prod常见错误是Error: Cannot find module koa——说明npm install没在production模式下运行要删掉node_modules重装5. 如果第3步成功但Nginx仍502检查Nginx配置里proxy_pass是否指向http://127.0.0.1:3000不能有空格或换行。我们遇到过一次是因为复制粘贴时proxy_pass后面多了个不可见的Unicode字符肉眼看不见但Nginx解析失败。5.3 学生反馈“下单后一直显示待支付”但后台订单已是paid这是微信支付回调的典型时序问题。现象用户看到“待支付”但数据库里status已是paid。原因微信回调成功后后端更新订单状态并推送WebSocket消息但小程序前端没监听到order:update事件。解决方案- 检查小程序app.js里wx.onSocketMessage是否注册了order:update事件处理器- 查pages/order/detail.js的onLoad函数确认调用了getOrderDetail()重新拉取数据- 更稳妥的做法是在onShow生命周期里加getOrderDetail()因为用户可能切到微信其他页面再回来。这个逻辑我们已在源码里实现但如果你删过onShow钩子就会重现这个问题。5.4 宝塔面板里MySQL进程占用CPU 100%但没人在用这是help.sql里缺少索引导致的。执行以下SQL加索引ALTER TABLE orders ADD INDEX idx_user_status (user_id, status); ALTER TABLE orders ADD INDEX idx_runner_status (runner_id, status); ALTER TABLE orders ADD INDEX idx_created_status (created_at, status);加完后SELECT * FROM orders WHERE user_id 123 AND status created这类查询从2秒降到50毫秒。这个优化建议我们放在《安装必看及后期更新.txt》的“性能调优”章节里。5.5 微信服务通知发不出去提示“errcode 43101”这是微信的“模板消息已过期”错误。原因微信模板库里的模板ID有7天有效期过期后需重新在公众号后台申请。解决方案- 进微信公众平台→功能→模板消息→找到“订单状态变更”模板→点击“更多操作”→“重新申请”- 复制新模板ID替换config.js里的wechat.template.orderUpdate- 重启PM2服务。这个事必须定期检查我们设置了每月1号自动邮件提醒管理员。6. 运维与扩展建议让它不止跑三个月而是成为校园数字基建这套系统上线后我们团队做了三件事让它真正扎根校园-每周自动备份在宝塔计划任务里每天凌晨2点执行mysqldump -u root -ppassword runtuan /backup/runtuan_$(date \%Y\%m\%d).sql备份文件保留30天-学生自治机制在后台/admin里开放“跑腿员审核”权限给学生会权益部他们用手机就能审批新跑腿员不用找技术同学-数据看板用ECharts在后台加了个简易看板显示当日订单量、平均配送时长、热门宿舍楼TOP5学生会拿着这个数据跟后勤处谈增设快递柜。未来扩展方向很明确-接入校园卡在/src/controllers/paymentController.js里新增cardPay接口调用学校一卡通API扣款-课程表联动用小程序wx.getBackgroundAudioPlayerState监听课表APP的后台状态上课时自动暂停订单推送-信用体系在users表加credit_score字段跑腿员准时送达10分用户好评5分分数影响接单优先级。这些不是画饼代码结构已经预留了扩展点/src/services下每个业务模块都是独立文件/src/routes里接口路径按资源划分改起来就像拼乐高。最后分享个小技巧每次更新代码别直接覆盖先用git diff对比config.js和project.config.json确保你的域名和AppID没被新版本冲掉——这个习惯让我们避开了三次线上事故。本文还有配套的精品资源点击获取简介这套资源专为高校场景设计直接拿来就能跑的跑腿服务系统。前端是适配微信生态的小程序界面清爽、操作顺手支持用户发布需求、查看接单状态、订单跟踪和在线支付后端用Node.js开发功能覆盖用户管理、任务发布、跑腿员接单、订单流转、状态更新、消息通知等全流程。包里有数据库建表脚本help.sql、服务端配置文件config.js、小程序项目结构app.、project.config.等、静态资源目录/public、以及多份实操文档——从安装前准备、SSL证书配置、宝塔面板部署步骤到Nginx反向代理设置、PM2进程守护、域名与HTTPS对接全都写得清清楚楚。部署前提需要已认证的微信小程序账号含微信支付商户号、已完成ICP备案的域名、有效的HTTPS证书推荐服务器配置2核4G3M带宽。所有代码变量和配置项都加了中文注释适合有一定Linux基础和Node.js经验的学生或个人开发者快速搭建上线不用从零写接口、不用反复调试环境。本文还有配套的精品资源点击获取