ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

微信小程序点餐外卖源码解析:从解压到上线全流程指南

2026/9/11 18:15:24 拓冰建站 浏览量
微信小程序点餐外卖源码解析:从解压到上线全流程指南 简介微信小程序点餐外卖完整源码面向正在学习小程序开发或需要快速搭建点餐系统的开发者无论是学生还是从业者均能从中获益。压缩包共 1147 个文件、约 3.91MB包含前端 WXML/WXSS/JS 页面、PHP 后端脚本、PNG 图片素材以及 JSON/DAT 配置数据目录中还有说明文档和安装脚本便于理解整体结构。已有 4964 人学习下载工程覆盖用户注册登录、菜品展示、购物车、订单提交、微信支付、配送跟踪等主流外卖流程并包含数据库表设计和接口交互逻辑。研读这份源码可以掌握小程序从前端渲染到后端接口协同工作的方式也能借鉴订单状态管理与安全校验等经验初学者可从调试运行入手逐模块拆解有经验者可直接复用或二次开发作为真实点餐项目的起步模板。1. 点餐外卖小程序源码 zip 解压后先看清工程构成再动手第一次拿到“微信小程序-点餐外卖小程序完整源码.zip”的开发者多数会直接解压并拖进微信开发者工具然后被同一组错误打断AppID 还是别人的所有 wx.request 指向一个已经失效的域名页面能渲染但加购、下单全都没反应。这套源码能否跑起来其实在解压后几分钟内就能判断前提是先看目录结构而不是先跑代码。按点餐外卖源码常见的打包方式可以把它们分成纯前端包、前后端分离包和云开发包三类。下面的顺序是通用分析路径先分结构再配环境后改业务最后过支付和上线验证。这套方法不依赖某一个具体项目只讲这类源码包的工程化拆解方式。2. 从目录结构判断“完整”程度小程序端、管理端与服务端怎么区分“完整源码”四个字在不同来源里含义并不统一。解压后第一步先看顶层目录而不是翻 README。常见的源码包结构大概如下顶层特征包含内容能直接跑吗后续工作重点只有 pages/、app.js、app.json小程序前端能编译但接口缺失自写服务端或先用 Mockclient/ server/ admin/小程序端、后端、管理后台需要本地建库和配服务端改数据库配置和后端启动参数miniprogram/ cloudfunctions/小程序端、云函数依赖腾讯云开发环境开通云开发、导入云函数src/ manifest.jsonuni-app 工程需要先编译再导入安装依赖并生成 mp-weixin 产物第一行最容易被标题误导。如果解压之后只有小程序页面目录说明这个包只有“点餐前端”服务端被单独拆走或根本不存在。点餐外卖主链路是“选菜-加购-下单-支付-接单-出餐”缺了服务端加购和下单这两步都走不通。拿到手先确认根目录是否存在 server、api、cloudfunctions、admin 这四个关键词之一一个都没有后面所有工作都要从补齐接口开始。第二行是相对完整的工程。这种结构通常带着数据库 SQL 文件、Web 管理后台和服务端源码但数据库不会自动建。常见情况是 SQL 文件躺在 server/sql 目录里需要手动导入 MySQL再改 application.yml 或 env 文件里的库名、密码和端口。跑起来的失败点多数集中在数据库连接而不是小程序端。2.1 三类源码包结构纯前端、前后端分离、云开发三类结构对应的投入差别很大。纯前端包工作量最大要做的不只是“接入接口”而是把登录、商品、购物车、订单、支付这些状态模型重新建一遍。前后端分离包相对省事数据库脚本和接口文档齐全的话一天左右能把本地环境跑通。云开发包要注意版本差异老项目的 cloudfunctions 目录里常常是已经过期、依赖老版本运行时的函数导入时需要按当前云开发运行环境重新上传部署。判断完类型后还有一个容易忽略的动作看压缩包生成时间。点餐外卖这类业务变化快两年前的源码可能用着旧版微信登录接口、旧版支付 API 和已经移除的组件库。如果发现接口文档里写的还是 wx.getUserInfo 实时获取用户手机号的旧链路要预期后续会花时间升级到新的匿名登录和手机号快捷验证方式。2.2 通过 app.json 或 manifest.json 区分原生小程序与 uni-app怎么判断这个小程序端是原生写还是 uni-app 写看入口文件。原生小程序一定会同时存在 app.json、app.js、app.wxssuni-app 工程通常有 src/manifest.json、src/pages.json 和 package.jsonTaro 是 config/index.js。先跑一条命令cd 解压目录 test -f app.json echo 原生小程序: app.json test -f src/manifest.json echo uni-app 工程: 需要 HBuilderX 或 CLI 编译 test -d cloudfunctions echo 云开发工程: 后端位于腾讯云开发环境命令输出直接决定后面的工具链。原生小程序可以立刻导入微信开发者工具uni-app 要先安装 npm 依赖再打包。很多人把 uni-app 的源码根目录拖进开发者工具结果是空白页面或“文件不合法”的报错。正确的是先执行npm install再用 HBuilderX 菜单里的“运行 - 运行到小程序模拟器”生成 dist/dev/mp-weixin 目录然后把这个产物目录当作小程序工程导入。另外要看 project.config.json。开发者工具认这个文件里面 miniprogramRoot 字段说明真正的代码根目录嵌套在哪一层。老源码常把小程序主体放在 miniprogram/ 子目录导入时选错层级就会提示找不到 app.json。AppID 也要在这里检查压缩包里写的基本都是打包者的不换成本人拥有的 AppID本地编译可以过真机预览和上传一定失败。如果 app.json 的 window 配置里出现navigationStyle: custom说明这个源码用了自定义导航栏。点餐外卖首页经常这样做让门店头图延伸到状态栏。老源码里常见的做法是在 app.js 里通过 wx.getMenuButtonBoundingClientRect 拿到胶囊按钮位置套用 statusBarHeight再把导航栏高度写死成一个静态值。Android 和 iOS 的胶囊位置并不完全一致折叠屏和灵动岛机型差异更大改造时要把这两个值动态算出来不要沿用写死的顶部导航栏高度。2.3 从依赖文件与请求封装反推服务端技术栈服务端目录有时候藏得很深不一定叫 server。判断技术栈最有效的办法是找依赖文件pom.xml 对应 Spring Bootrequirements.txt 或 manage.py 对应 Pythoncomposer.json 对应 PHPgo.mod 对应 Go。找不到依赖文件时看接口地址特征也能猜出大概# 找服务端入口文件线索 find . -maxdepth 3 \( -name pom.xml -o -name requirements.txt -o -name go.mod -o -name composer.json \) # 检索小程序端写死的接口域名 grep -rInE https?://[a-zA-Z0-9.-] pages miniprogram src --include*.js | head -n 40这里的输出有两个用途。一是确认后端语言决定本机要不要装对应运行时二是统计接口地址写在哪些文件里。老源码喜欢在每个页面里直接调用 wx.request而不是统一封装地址散落越多后续改造成本越高。如果 grep 结果里出现http://192.168.x.x这类内网地址说明源码是在开发环境直接打包的大概率还带着一套本地数据库配置。真机预览之前要全部换掉。3. 微信开发者工具运行完整源码AppID、baseUrl 与合法域名配置3.1 导入项目project.config.json 决定入口AppID 决定能否真机预览把工程跑起来的正确顺序是在微信开发者工具里选择“导入项目”目录选包含 project.config.json 的那一层编译类型保持“小程序”AppID 先用测试号或自己的正式 AppID。导入后看模拟器是否出现页面没出现就打开 Console 看第一行报错。多数情况是 appid 不对、miniprogramRoot 指错目录或页面路径在 app.json 里少注册了一行。只做本地调试时测试号够用要调用登录、支付、订阅消息必须换成自己账号下的 AppID。源码包里那个 wx 开头的 AppID 属于打包者继续使用会报“appid 与账号不匹配”这不是代码问题。换成自己的 AppID 后再跑一遍登录如果报 login:fail把 Network 面板打开看登录接口有没有请求发出没发出就去查 wx.login 是否被放进了某个未触发的生命周期钩子发出了但没返回则是后端登录地址还没指向自己的服务。3.2 统一请求层把写死的接口地址改成自己的测试环境点餐外卖这类流通量大的源码最普遍的问题就是接口地址散落。直接改一处 baseUrl 不够因为页面里可能还有wx.request({ url: http://192.168.1.10:8080/api })这种硬编码调用。先建一个统一请求层再把页面逐步替换过去比一次性全局替换更稳// utils/request.js const config require(./config) function request(path, data, method GET) { return new Promise((resolve, reject) { wx.request({ url: config.baseUrl path, method, data, timeout: 10000, header: { Content-Type: application/json }, success(res) { if (res.statusCode 200 res.statusCode 300) { resolve(res.data) } else { reject(res) } }, fail: reject }) }) } module.exports { get: (p, d) request(p, d, GET), post: (p, d) request(p, d, POST) }config 里只保留一处地址// utils/config.js module.exports { baseUrl: http://192.168.31.24:8080/api // 本地联调 // baseUrl: https://api.example.com/api // 发布前启用 }封装理由wx.request 不返回 Promise页面里每个请求都要写一遍 success/fail代码会越来越难改。统一之后页面调用request.post(/order/create, data)即可。替换过程中用 Network 面板对照请求点击加购按钮应该有对应的 POST 请求发出如果点按钮没反应先排查事件绑定再看是否被入口文件中的弹窗逻辑拦截。本地联调时手机预览不能访问 localhost。想要手机直接连电脑把 baseUrl 改成电脑局域网 IP且确保手机和电脑同网段。老源码里如果用了http://localhost:8080而预览时接口全部失败就是这个问题。想看代码真的把请求发到了哪里可以在电脑端抓取微信小程序的流量确认请求没有落到旧域名。3.3 合法域名校验本地绕过、真机必须走 HTTPS跑模拟器时“不在以下 request 合法域名列表中”是出现频次最高的报错。小程序运行时有域名校验wx.request 和 wx.uploadFile 的目标域名必须在微信公众平台后台配置过且必须是 HTTPS。开发阶段可以在“详情 - 本地设置”里勾选“不校验合法域名”这个选项只管开发者工具真机预览时仍然会被拦截。真机预览面对的是正式环境约束要有自己的域名、HTTPS 证书并在小程序后台的“开发管理 - 开发设置 - 服务器域名”里完成配置。还没有正式域名时常见的过渡做法是用 nginx 把本地服务代理到 HTTPS 端口让手机走域名访问内网服务server { listen 443 ssl; server_name api.dev.example.com; ssl_certificate /etc/nginx/certs/dev.crt; ssl_certificate_key /etc/nginx/certs/dev.key; location /api/ { proxy_pass http://127.0.0.1:8080/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }把微信端请求指向https://api.dev.example.com/api/...nginx 再转发给本机的 Java 或 Node 服务。证书是自签的开发者工具需要临时关掉 SSL 校验真机则要安装并信任证书。这个方案只适合联调。正式发布必须使用受信任证书且域名完成备案否则小程序后台配置合法域名后真机还会出现资源加载失败或请求超时问题的根源往往在证书不在代码。4. 把点餐流程改到自己的业务购物车、SKU 和订单状态4.1 购物车状态要跨页面共享不能只放在页面 data 里点餐小程序页面结构大同小异菜单页负责点菜购物车页负责确认订单页展示历史订单我的页面放个人信息。菜单页加购后跳到购物车页中间要经过页面跳转。如果把购物车数组放在某个页面的 data 里跳到购物车页就得通过 getStorageSync 重新读两次读取之间没有共享状态必然出现数量和金额不一致。把购物车抽成独立模块是更合理的做法// utils/cart.js —— 页面间共享的购物车单例 const cart { items: [], // dish 对象至少包含 id、name、priceprice 单位为分 add(dish, skuId) { const found this.items.find( (item) item.dishId dish.id item.skuId skuId ) if (found) { found.quantity } else { this.items.push({ dishId: dish.id, skuId, name: dish.name, price: dish.price, quantity: 1, remark: , }) } wx.setStorageSync(cart, this.items) this.emit this.emit(this.items) }, totalCents() { return this.items.reduce( (sum, item) sum item.price * item.quantity, 0 ) }, } module.exports cart购物车模块的核心是 items 数组在所有页面共享任何页面 add 或 remove 之后其他页面通过 require 拿到的都是同一份引用。配合 wx.setStorageSync 做持久化小程序被系统回收后再打开购物车数据还能恢复。注意不要在这里直接用浮点数算总价价格按“分”存储可以避免 0.10.2 的精度问题展示时再除以 100。4.2 规格和加价数据结构和价格计算都要先定清楚点餐和普通电商的差别在于规格不是简单的 SKU 字符串而是一组必选或可选的选项。一份饮品要选大杯小杯、正常冰少冰、三分糖七分糖还可能加珍珠加椰果每种组合价格不同。老源码如果只在菜表里放一个价格字段改造的第一步就是要拆表CREATE TABLE dish ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, name VARCHAR(64) NOT NULL, price_cents INT NOT NULL COMMENT 基础价格单位分, image VARCHAR(255), status TINYINT NOT NULL DEFAULT 1 COMMENT 1上架 0下架, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE spec_group ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, dish_id INT UNSIGNED NOT NULL, name VARCHAR(32) NOT NULL COMMENT 辣度/甜度/加料, required TINYINT NOT NULL DEFAULT 1 COMMENT 1必选 0可选, multiple TINYINT NOT NULL DEFAULT 0 COMMENT 1可多选, sort_order INT NOT NULL DEFAULT 0, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE spec_item ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, group_id INT UNSIGNED NOT NULL, name VARCHAR(32) NOT NULL, price_delta_cents INT NOT NULL DEFAULT 0 COMMENT 相对基础价的加减价, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这个结构覆盖了大多数点餐场景spec_group 的 required 字段控制选项是否必选multiple 控制是否能多选spec_item 里存的是相对于基础价格的加减价。小程序端把选中的一组 specItemId 随订单提交后端再根据规格项实时算价。必须强调不要信任前端传来的 money 字段。把总价计算放在服务端后端重新按菜品基础价加规格价求和可以挡掉改动价格、刷优惠这类作弊方式。4.3 订单状态机设计从待付款到已完成的状态流转点餐外卖源码在订单状态上最容易出现的问题是状态字段含义不清。有的是数字、有的是字符串有的把“待接单”和“制作中”混成一个值最后商家后台无法区分该接单还是该出餐。状态值含义触发方触发条件0待付款用户提交订单生成开始等待支付1已支付/待接单系统微信支付回调成功2制作中商家商家后台点击接单3待取餐/配送中商家出餐或骑手取货4已完成系统或用户确认收货或超时自动完成5已取消用户或系统用户取消或超时未支付这套状态机的关键在商家接单这个动作。外卖平台里用户支付后订单进入“待接单”商家端接单后才开始制作。如果源码只区分“待支付、已支付、已完成”三段说明它是简化模板需要在管理后台订单列表里补一个“接单”按钮并处理接单超时、拒单和退款。状态变更最好写进 order_status_log包含原状态、新状态、操作人和时间售后排查时比任何临时日志都好用。重复下单也是一个高频问题前端按钮加 loading 状态只能减少误触真正的防重要在后端判断同一用户对同一商品组合的最近一单是否已支付或待支付。5. 上线前的验证技巧支付回调验签与排查清单5.1 微信支付 V3 回调验签前端显示已支付订单却停在待付款完整源码改造到支付这一环最常见的现象是手机弹窗显示支付成功商户后台也看到账单但小程序订单还停在“待付款”。这不是前端问题是支付结果通知没有正确写回后端。微信支付成功后调用的是商户后台配置的 notify_url而不是前端。老源码回调地址通常是打包者的服务器换成自己的域名之前通知根本到不了你的代码。常见做法是先验签再改订单状态// 支付回调验签骨架Node 版。实际开发通常使用官方 SDK这里展示原理 const crypto require(crypto) function verifyNotifySign(headers, rawBody, publicKey) { const message [ headers[wechatpay-timestamp], headers[wechatpay-nonce], rawBody, ].join(\n) const verify crypto.createVerify(RSA-SHA256) verify.update(message) return verify.verify(publicKey, headers[wechatpay-signature], base64) }微信支付 V3 的通知验签用的是微信支付平台证书里的公钥商户自己的 APIv3 私钥是给请求签名用的不要把两者搞反。验签通过后解析 body 里的 resource再用 out_trade_no 跟库里订单匹配在事务里把状态改成已支付最后返回{code:SUCCESS}。不返回成功微信会持续重试通知。很多流通源码没有验签过程直接把 body 解析出来改库这等于给第三方留了一个伪造回调的入口检查源码时看到“支付回调里没有验签”这一条优先补上再上线。5.2 提交审核前的 5 项排查AppID 换成自己账号下的正式 AppIDproject.config.json 与小程序后台一致。所有接口域名已加入 request 合法域名证书是受信任的 HTTPS 证书。支付商户号、证书序列号、APIv3 私钥全部换成自己主体下的避免支付资金进入别的商户号。页面里需要采集的信息已在隐私协议中说明出现授权弹窗时能够正常唤起。清掉源码包自带的项目名、示例商品图片和 mock 数据至少完整走一遍“首页-选菜-加购-下单-支付-商家接单”流程。如果首页进入时白屏很久先看加载逻辑。有些老源码把全部商品放在一个接口里首页 onLoad 一次性请求弱网下体验很差。想优化刚进入的加载页把分类和商品拆成两个接口首屏只拉分类和前几个商品滚动到对应分类再懒加载。5.3 一条命令核对写死的旧域名# 在项目根目录执行找出所有还在使用 http/https 字面量的页面文件 grep -rInE https?:// pages utils --include*.js | grep -v api.example.com | head -n 40如果输出结果有内容说明还有绕过统一请求层的写死地址逐条替换为 request 封装调用。全部清完后关掉开发者工具里“不校验合法域名”用真机从冷启动跑一遍主链路。点餐外卖项目上线后的维护集中在三类菜品 SKU 调整、商家接单流程、支付回调重试。这三块在源码阶段理顺后面改起来会顺很多。本文还有配套的精品资源点击获取