大家好,我是java1234_小锋老师,分享一套微信小程序系统扫码点餐系统(云函数,云数据库) 。
项目简介
设计并实现了一套基于微信小程序和微信云开发的扫码点餐系统——"小店点餐"。系统采用Serverless架构,前端使用微信小程序原生框架开发,后端依托微信云开发平台的云函数、云数据库和云存储服务,实现了完全免服务器的部署方案。系统面向小型餐饮门店,主要包含顾客端和管理员端两大模块。
顾客端实现了扫码识别桌号、浏览菜品分类、购物车管理、在线下单、加菜追加、历史订单查询等功能。管理员端提供了今日数据统计、订单管理(接单/完成/取消)、菜品管理(增删改/上下架/热门标记)、分类管理、桌号管理(含小程序码生成)、用户管理(冻结/解冻)等完整的后台管理功能。系统还实现了基于云数据库watch机制的实时订单通知和轮询兜底方案,以及完善的鉴权中间件和风控限频机制。
本系统采用单入口云函数配合命令路由的架构设计,结合前端控制器模式、命令模式、观察者模式等设计模式,确保了系统的可扩展性和可维护性。实际测试表明,系统运行稳定,功能完善,能够有效提升小型餐饮门店的运营效率。
源码下载
链接: pan.baidu.com/s/1_i-LnA9t…
提取码: 1234
相关截图
核心代码
/**
* 云函数统一入口
* 职责:鉴权中间件(用户身份校验 + 风控限频)+ action 路由分发
* 所有业务处理器按模块拆分在 handlers/ 目录下
*/
const { cloud, db, _, verifyAdmin } = require('./handlers/common')
// 合并所有业务模块的 action → handler 映射
const handlers = Object.assign({},
require('./handlers/user'),
require('./handlers/category'),
require('./handlers/dish'),
require('./handlers/table'),
require('./handlers/order'),
require('./handlers/userManage'),
require('./handlers/init')
)
// 白名单:这些 action 不需要用户已绑定手机号即可调用
const whiteList = ['getOpenId', 'bindPhone', 'checkAdmin', 'getUserInfo', 'initData']
/**
* 云函数主入口
* 执行流程:
* 1) 获取调用方 openid
* 2) 白名单外的 action 需要:用户已注册 + 未冻结 + 风控限频
* 3) 根据 event.action 分发到对应业务处理器
*/
exports.main = async (event, context) => {
const wxContext = cloud.getWXContext()
const openid = wxContext.OPENID
// 未获取到 openid 说明调用环境异常
if (!openid) {
return { code: 401, msg: '未授权访问' }
}
// ---------- 鉴权与风控中间件(白名单 action 跳过) ----------
if (!whiteList.includes(event.action)) {
// 检查用户是否已注册(绑定手机号)
let userRes
try {
userRes = await db.collection('t_user').where({ openid }).get()
} catch (e) {
return { code: 403, msg: '请先绑定手机号' }
}
if (!userRes.data.length) {
return { code: 403, msg: '请先绑定手机号' }
}
// 检查用户是否被冻结
if (userRes.data[0].is_frozen) {
return { code: 403, msg: '账号已被冻结,请联系店家' }
}
// 非管理员执行风控限频:每日请求上限 100 次,超限自动冻结
const isAdmin = await verifyAdmin(openid)
if (!isAdmin) {
try {
const todayStart = new Date()
todayStart.setHours(0, 0, 0, 0)
const reqCount = await db.collection('t_request_log')
.where({ openid, timestamp: _.gte(todayStart.getTime()) })
.count()
if (reqCount.total >= 100) {
await db.collection('t_user').where({ openid }).update({
data: {
is_frozen: true,
frozen_time: db.serverDate(),
frozen_reason: '当日请求次数超过100次'
}
})
return { code: 403, msg: '今日请求过于频繁,账号已被冻结' }
}
} catch (e) { }
// 记录本次请求到日志表(用于限频统计)
try {
await db.collection('t_request_log').add({
data: { openid, action: event.action, timestamp: Date.now(), create_time: db.serverDate() }
})
} catch (e) { }
}
}
// ---------- action 路由分发 ----------
const handler = handlers[event.action]
if (!handler) {
return { code: -1, msg: '未知操作: ' + event.action }
}
return handler(openid, event)
}