
简介本资源是一套专为餐饮行业商户定制的微信小程序源码模板面向小程序初学者、中小型商户技术负责人及快速原型开发者解决从零搭建点餐系统耗时长、功能模块不完整、适配微信规范难等实际问题。压缩包共202个文件含32个JS逻辑层代码、28个WXML视图结构、28个WXSS样式文件、28个JSON配置项及84个PNG图标资源辅以GIF加载动画与gitignore等工程配置整体仅689KB轻量易读、结构清晰便于二次开发与品牌定制。目前已有46人学习下载适合希望快速上线外卖点单、订单管理、菜品展示与在线支付等功能的实战场景。源码严格遵循微信官方开发规范涵盖index.js主入口、service-control与merchandise-control等业务控制层、edit-mine-info等用户模块提供可直接运行的完整骨架大幅缩短开发周期降低试错成本。1. 这不是又一个“点餐页面轮播图”的空壳模板它是一套能直接跑通「商户入驻—菜品上架—用户下单—后台核销」闭环的微信小程序源码含真实可用的云开发结构、带权限控制的管理端和适配iOS/Android双端的UI组件库你可能已经下载过十几个标着“餐饮模板”的小程序源码包解压后发现只有首页轮播、菜单分类、底部TabBar——连登录态都靠wx.setStorageSync硬存更别说商户怎么进后台、订单怎么查、核销码怎么生成。这次不一样。这个【微信小程序源码】餐饮商户模板.zip是某高校实验室为本地3家社区餐饮店落地验证过的完整工程不是Demo不是教学示例而是真正在微信开发者工具里能一键预览、在真机上扫码可订、后台能实时看到新订单的生产级代码包。它用云开发替代传统服务器省掉域名备案、HTTPS配置、Node.js部署这些新手最易翻车的环节所有接口调用走云函数数据库集合按角色隔离商户库/用户库/订单库连核销员扫码核销时的权限校验逻辑都写死了。适合两类人一是想快速上线轻量餐饮服务的小商家技术对接人二是刚学完小程序基础、卡在“怎么把页面串成业务流”这一步的前端开发者。别再从零搭登录、写订单状态机、反复调试云数据库权限了——这套源码里每个.js文件名后面都跟着一句注释“此处已接入真实支付回调校验”。2. 拆包即用从解压到真机扫码5步完成本地运行与基础配置2.1 解压后目录结构解析看清哪些文件是核心、哪些可删、哪些必须改解压【微信小程序源码】餐饮商户模板.zip后你会看到标准的微信小程序项目结构但关键在于识别出不可删减的核心模块和必须修改的配置锚点├── cloudfunctions/ # 云函数目录全部必需含login、orderCreate、verifyCodeGenerate等 ├── miniprogram/ │ ├── app.js # 全局App逻辑含云开发初始化重点看第12行 │ ├── project.config.json # 项目配置含appid需替换 │ ├── sitemap.json # 搜索优化配置可删但不建议 │ └── pages/ │ ├── index/ # 用户端首页含商户列表、搜索、轮播 │ ├── merchant/ # 商户入驻页表单提交直连云函数 │ ├── order/ # 订单页含地址选择、支付跳转、状态轮询 │ └── admin/ # 管理端仅限指定openid访问见3.2节 ├── project.private.config.json # 私有配置含云环境ID必须填 └── README.md # 实际包含4个关键配置项说明非通用模板提示project.private.config.json是本项目真正的“心脏”。它不上传云端只存本地里面env字段必须填你自己的云开发环境ID格式如my-env-12345否则所有云函数调用都会返回Error: env not found。这个文件在Git中已被忽略但解压后必须手动编辑。2.2 替换两个IDappid与云环境ID缺一不可微信小程序运行的前提是合法身份标识。本模板要求你准备两个ID你的小程序 AppID在 微信公众平台 开发管理 开发基本信息中获取。你的云开发环境ID在 云开发控制台 环境列表中创建一个新环境地域选上海或广州避免跨域问题复制环境ID。替换位置有两个miniprogram/project.config.json中appid字段{ description: 项目配置文件, setting: { ... }, appid: wx1234567890abcdef, // ← 替换为你自己的AppID condition: { ... } }project.private.config.json中env字段{ env: prod-abc123, // ← 替换为你创建的云环境ID region: ap-shanghai }注意project.private.config.json文件名带.private后缀是微信开发者工具识别的私有配置文件不会被上传到远程仓库或云端。它只在你本地生效所以可以安全存放敏感配置。如果误删重新建一个同名文件即可内容只需这两行。2.3 在开发者工具中一键上传云函数别手动一个个部署云函数是本模板的业务中枢共12个覆盖从用户登录鉴权、菜品增删改查、订单创建与状态更新、到核销码生成与验证全流程。切勿在开发者工具里右键单个云函数 → “上传并部署”因为部分函数存在依赖关系如orderCreate依赖utils/orderHelper.js手动上传会因加载顺序错乱导致require error。正确做法是打开微信开发者工具确保左上角“云开发”开关已开启在左侧项目树中右键点击cloudfunctions文件夹 → 选择“上传所有云函数”勾选“上传时自动触发安装依赖”和“上传后自动部署”点击确定等待右下角提示“全部云函数上传成功”。上传完成后立即去 云开发控制台 云函数列表确认所有函数状态为“运行中”且最近调用时间是当前时间。若某个函数显示“初始化失败”大概率是package.json中engines: {node: 16.x}与你本地Node版本不匹配——此时需在开发者工具设置中将“云函数Node版本”改为16.19.1本模板实测兼容版本。2.4 首次真机扫码前必做的三件事检查登录态、测试云数据库、验证支付沙箱很多开发者卡在“开发者工具能跑真机扫不出首页”根本原因是真机环境缺失关键初始化步骤。请严格按顺序执行清空真机微信缓存微信 → 我 → 设置 → 通用 → 存储空间 → 小程序 → 找到你的小程序 → 删除。这是最常被忽略的一步旧缓存中的token或openid残留会导致app.js中wx.cloud.callFunction({name:login})返回401。手动在云数据库中插入一条测试商户数据进入云开发控制台 → 数据库 → 新建集合merchants→ 插入如下文档注意_id必须为字符串不能是ObjectId{ _id: mch-test-001, name: 测试餐厅, address: XX路123号, phone: 13800138000, status: approved, createdAt: 2024-06-01T08:00:00Z }此操作让首页商户列表有数据可渲染避免白屏。启用支付沙箱环境并配置密钥本模板使用微信支付V3接口但未强制要求正式商户号。首次测试用沙箱环境即可登录 微信支付商户平台 → 账户中心 → API安全 → 沙箱密钥 → 下载apiclient_key.pem将该文件放入cloudfunctions/paySandbox/目录下修改cloudfunctions/paySandbox/index.js第7行const SANDBOX_KEY_PATH ./apiclient_key.pem。沙箱支付无需真实资金回调地址也无需备案是本地联调支付流程的后悔药。完成以上三步打开真机微信扫描开发者工具右上角二维码首页应正常显示“测试餐厅”轮播图与菜单分类。若仍白屏请直接跳到第4章排查。3. 权限与角色设计为什么普通用户打不开/admin页面商户如何进入自己的管理后台3.1 三角色权限模型user / merchant / admin全由云数据库roles集合驱动本模板没有用复杂的RBAC基于角色的访问控制框架而是用极简但可靠的“集合字段”方案实现权限隔离用户user通过微信授权登录openid存于云数据库users集合无特殊字段商户merchant入驻审核通过后系统向merchants集合插入文档并同步向roles集合写入一条记录{ _id: role_mch_abc123, role: merchant, targetId: mch-test-001, // 对应merchants._id authOpenid: oAbcDeFgHiJkLmNoPqRsTuVwXyZ // 商户管理员的openid }管理员adminroles集合中role admin的记录authOpenid填你自己的微信openid可在开发者工具Console中执行wx.getStorageSync(openid)获取。所有页面的权限校验逻辑统一收口在miniprogram/utils/auth.js的checkRole()函数中。例如pages/admin/index.js在onLoad时会调用// pages/admin/index.js const auth require(../../utils/auth) Page({ onLoad() { auth.checkRole(admin).then(hasAuth { if (!hasAuth) { wx.showToast({title: 无权限, icon: none}) setTimeout(() wx.navigateBack(), 1500) } }) } })逻辑说明checkRole()内部执行云数据库查询db.collection(roles).where({role: targetRole, authOpenid: currentOpenid}).get()只查到结果才放行。这意味着——只要没在roles集合里给你加一条role: admin的记录你就永远打不开/admin页面。这是硬性权限不是前端路由拦截无法绕过。3.2 商户入驻流程从填写表单到获得独立后台入口的完整链路商户不是后台人工添加的而是通过用户端页面自助入驻。流程如下用户打开/pages/merchant/apply.js页面填写餐厅名称、地址、联系人、电话、上传营业执照照片调用wx.chooseImagewx.cloud.uploadFile点击“提交”后前端调用云函数merchantApply传入表单数据cloudfunctions/merchantApply/index.js接收数据执行校验手机号格式、图片是否上传成功自动生成唯一_id如mch-20240601-001向merchants集合插入待审状态文档status: pending向roles集合插入一条role: merchant记录targetId指向刚生成的商户IDauthOpenid为当前提交者openid提交成功后页面跳转至/pages/merchant/waiting.js显示“审核中”并提示“审核通过后您将收到消息通知并可在‘我的’页面进入管理后台”。关键参数说明merchantApply函数中第23行const newMerchantId mch-${Date.now()}-${Math.random().toString(36).substr(2, 5)} 是防重ID生成策略保证高并发下不冲突而roles集合的写入是原子操作避免出现“商户入库成功但权限丢失”的脏数据。3.3 管理后台的动态路由为什么每个商户看到的/admin页面内容不同/pages/admin/index.js并不是一个静态页面而是一个根据当前用户角色动态渲染的容器页。其核心逻辑在onLoad中// pages/admin/index.js onLoad() { const openid wx.getStorageSync(openid) // 1. 查自己在roles中的记录 db.collection(roles).where({authOpenid: openid}).get() .then(res { if (res.data.length 0) return const roleDoc res.data[0] // 2. 根据role类型加载不同子页面 if (roleDoc.role merchant) { this.setData({ currentPage: merchantDashboard }) // 加载商户专属数据订单统计、菜品列表、核销记录 } else if (roleDoc.role admin) { this.setData({ currentPage: adminDashboard }) // 加载全平台数据所有商户列表、总订单数、投诉处理 } }) }因此当你用商户A的微信扫码进入/admin页面实际渲染的是pages/admin/merchantDashboard.wxml其数据全部来自db.collection(orders).where({merchantId: mch-test-001}).count()等商户维度查询而用管理员微信进入则渲染adminDashboard查询的是全量数据。这种设计避免了为每个角色单独建一套页面复用率高维护成本低。4. 避坑指南那些让你调试到凌晨三点、却只因一个空格的致命细节4.1 现象开发者工具能运行真机扫码首页白屏Console无报错原因真机微信未开启“调试基础库”导致云开发API如wx.cloud.database()在低版本基础库中不可用。本模板最低要求基础库版本2.25.0。解决真机微信 → 我 → 设置 → 普通设置 → 发现页管理 → 关闭“发现页小程序”开关 → 重启微信 → 重新扫码。此操作会强制微信更新基础库至最新稳定版。若仍无效在开发者工具详情 → 本地设置 → 勾选“调试基础库”再试。4.2 现象云函数orderCreate调用失败日志显示Error: Cannot find module ./utils/orderHelper原因cloudfunctions/orderCreate/index.js第5行const helper require(./utils/orderHelper)中路径错误。该utils文件夹实际位于cloudfunctions/orderCreate/同级目录而非其子目录。解决将require(./utils/orderHelper)改为require(../utils/orderHelper)。注意云函数上传时开发者工具不会校验相对路径有效性必须手动检查所有require语句的..层级。4.3 现象商户上传营业执照图片后在管理后台看不到云存储控制台显示文件为空原因wx.cloud.uploadFile调用时cloudPath参数未拼接文件扩展名。原代码中const cloudPath merchant/ Date.now() .jpg固定写死.jpg但用户可能选PNG或HEIC格式。解决在pages/merchant/apply.js中chooseImage回调内动态获取后缀wx.chooseImage({ success: res { const tempFilePath res.tempFilePaths[0] const ext /\.\w$/.exec(tempFilePath)[0] // 如.png const cloudPath merchant/ Date.now() ext wx.cloud.uploadFile({ cloudPath, filePath: tempFilePath }) } })4.4 现象用户下单后商户后台“待处理订单”数量不增加云数据库orders集合无新文档原因cloudfunctions/orderCreate/index.js中db.collection(orders).add()调用前未对data对象做深拷贝导致data.createdAt new Date()被序列化为Invalid Date云数据库拒绝写入。解决在add()前添加时间字段标准化const now new Date() data.createdAt now.toISOString() // 必须转为ISO字符串 data.updatedAt now.toISOString() db.collection(orders).add({ data })云数据库只接受ISO 8601格式字符串作为时间字段new Date()对象直接传入会被忽略。4.5 现象核销员扫码核销时提示“该订单已核销”但订单状态仍是unverified原因cloudfunctions/verifyCodeVerify/index.js中db.collection(orders).doc(orderId).update()使用了set而非update导致整条文档被覆盖原有字段如customerName,phone丢失后续查询失效。解决严格使用update方法并只更新目标字段db.collection(orders).doc(orderId).update({ data: { status: verified, verifiedAt: new Date().toISOString(), verifierOpenid: context.OPENID } })set会重置整个文档update才是原子更新。5. 核销码生成与验证从随机字符串到真机扫码的端到端实战5.1 核销码不是简单MD5它由三段加密信息构成兼顾安全性与可追溯性很多模板用Math.random().toString(36).substr(2, 8)生成8位核销码看似随机实则可暴力穷举。本模板采用三段式加密核销码每段承担不同职责段位长度内容作用前缀2位V1或V2版本标识便于未来升级算法主体10位orderId的Base32编码去除了0,O,I,l等易混淆字符绑定订单不可伪造校验4位HMAC-SHA256(orderId secretKey, timestamp)的截断防重放、防篡改生成逻辑在cloudfunctions/verifyCodeGenerate/index.jsconst crypto require(crypto) const base32 require(base32-encode) exports.main async (event, context) { const { orderId } event const timestamp Math.floor(Date.now() / 60000) * 60000 // 精确到分钟 const secretKey your-secret-key-here // 应从环境变量读取此处为示意 // 1. Base32编码orderId去混淆 const cleanOrderId orderId.replace(/[^a-zA-Z0-9]/g, ) const encodedId base32.encode(Buffer.from(cleanOrderId), Crockford) // 2. 生成HMAC校验码 const hmac crypto.createHmac(sha256, secretKey) hmac.update(${orderId}${timestamp}) const digest hmac.digest(hex).substr(0, 4).toUpperCase() return ${V1}${encodedId.substr(0, 10)}${digest} }参数说明timestamp精确到分钟意味着同一订单在1分钟内生成的核销码相同超过1分钟则失效——这是防重放的核心。base32.encode(..., Crockford)使用Crockford Base32变种自动剔除易混淆字符提升用户手动输入准确率。5.2 真机扫码验证如何用手机微信“扫一扫”调起核销页面核销不是让用户手动输码而是扫码跳转。实现分两步第一步在订单详情页生成带参数的二维码pages/order/detail.js中当订单状态为paid时调用云函数生成核销码再用wx.canvasToTempFilePath绘制二维码使用weapp-qrcode库// 生成核销码 const res await wx.cloud.callFunction({ name: verifyCodeGenerate, data: { orderId } }) const code res.result // 绘制二维码code为字符串非URL const qrcode QRCode.draw(code, { width: 200, height: 200 }) // ... canvas绘制逻辑第二步配置扫码跳转规则在微信公众平台 → 小程序管理 → 开发管理 → 扫码跳转配置中添加规则规则类型URL LinkURL Linkhttps://wxaurl.cn/xxxxxx需先在云开发控制台生成短链启动页面/pages/verify/scan?code{code}备注餐饮核销专用关键技巧{code}是微信扫码时自动注入的占位符实际扫码后小程序会启动/pages/verify/scan.js并在options.code中拿到真实核销码。scan.js页面立即调用verifyCodeVerify云函数校验通过则更新订单状态并弹窗“核销成功”。5.3 核销失败的五种状态码比“核销失败”四个字更有用的调试依据verifyCodeVerify云函数返回的不是布尔值而是带语义的状态码直接映射到前端Toast文案状态码含义常见场景前端处理200核销成功订单存在、未核销、时间有效显示绿色Toast跳转订单详情404订单不存在orderId解析错误或数据库无此记录显示“订单不存在”引导联系客服409已核销status verified显示“该订单已核销”附上次核销时间410已过期timestamp与当前时间差 10分钟显示“核销码已过期请刷新重试”403校验失败HMAC签名不匹配可能被篡改显示“非法核销码”记录日志并告警在pages/verify/scan.js中wx.cloud.callFunction的fail回调会捕获这些状态码wx.cloud.callFunction({ name: verifyCodeVerify, data: { code } }) .then(res { switch(res.result.code) { case 200: this.showSuccess(); break; case 409: this.showToast(已核销); break; case 410: this.refreshQrCode(); break; // 自动刷新二维码 default: this.showToast(核销失败); } })从那以后我每次部署新环境都强制走一遍“商户入驻→用户下单→真机扫码核销”全流程哪怕只是用测试数据。因为核销是整个业务闭环的最后一环也是用户感知最直接的一环——它不响整个系统就等于没跑通。希望帮到你。本文还有配套的精品资源点击获取