分享一套锋哥原创的微信小程序系统扫码点餐系统(云函数,云数据库)

0 阅读3分钟

大家好,我是java1234_小锋老师,分享一套微信小程序系统扫码点餐系统(云函数,云数据库)  。

未命名.jpg

项目简介

设计并实现了一套基于微信小程序和微信云开发的扫码点餐系统——"小店点餐"。系统采用Serverless架构,前端使用微信小程序原生框架开发,后端依托微信云开发平台的云函数、云数据库和云存储服务,实现了完全免服务器的部署方案。系统面向小型餐饮门店,主要包含顾客端和管理员端两大模块。

顾客端实现了扫码识别桌号、浏览菜品分类、购物车管理、在线下单、加菜追加、历史订单查询等功能。管理员端提供了今日数据统计、订单管理(接单/完成/取消)、菜品管理(增删改/上下架/热门标记)、分类管理、桌号管理(含小程序码生成)、用户管理(冻结/解冻)等完整的后台管理功能。系统还实现了基于云数据库watch机制的实时订单通知和轮询兜底方案,以及完善的鉴权中间件和风控限频机制。

本系统采用单入口云函数配合命令路由的架构设计,结合前端控制器模式、命令模式、观察者模式等设计模式,确保了系统的可扩展性和可维护性。实际测试表明,系统运行稳定,功能完善,能够有效提升小型餐饮门店的运营效率。

源码下载

链接: pan.baidu.com/s/1_i-LnA9t…

提取码: 1234

相关截图

0717297a-6839-4477-9b3b-81f3a4cdbd6a.png

QQ截图20260411204031.jpg

核心代码

/**
 * 云函数统一入口
 * 职责:鉴权中间件(用户身份校验 + 风控限频)+ 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)
}