基于微信小程序的美食点餐订餐系统

发布于:2025-06-21 ⋅ 阅读:(17) ⋅ 点赞:(0)

1. 项目概述

在移动互联网时代,餐饮行业数字化转型已成为必然趋势。今天我想分享一个基于小程序的美食点餐/订餐系统的设计与实现,该系统包含用户模块、首页模块、分类模块、购物车模块和个人中心等核心功能模块。

2. 项目思维导图

在这里插入图片描述

3. 系统架构特点

  • 纯前端实现:不依赖服务器,所有数据存储在本地
  • 基于微信小程序API数据存储:主要使用wx.setStorageSync/wx.getStorageSync
  • 数据持久化:关闭小程序后数据不会丢失

4. 核心模块实现代码

1. 登录注册

//用户注册
onRegisterHandle(){
    if(this.data.username==='' || this.data.password ===''){
      wx.showToast({
        title: '注册信息不能为空',
        icon :'error'
      })
      return
    }
    let users =wx.getStorageSync('users') ||[]
    if(users.some(item => item.username === this.data.username)){
        wx.showToast({
          title: '用户名已存在',
          icon: 'error'
        })
      return
    }
    let user ={
      username: this.data.username,
      password: this.data.password
    }
    users.push(user)
    wx.setStorageSync("users",users)

    wx.showToast({
        title: '注册成功',
        icon :'success'
    })

    setTimeout(() => {
      wx.navigateBack()
    },500)

  }



//用户登录
onLoginHandle(options) {
    if (this.data.username === '' || this.data.password === '') {
      wx.showToast({
        title: '登录信息不能为空',
        icon: 'error'
      })
      return
    }
    let users = wx.getStorageSync('users') || []
    if (users.some(item => item.username === this.data.username && item.password === this.data.password)) {
      wx.showToast({
        title: '登录成功',
        icon: 'success'
      })
      let user = {
        username: this.data.username,
        password: this.data.password
      }
      //保存当前用户登录信息
      wx.setStorageSync("user", user)

      setTimeout(() => {
        wx.navigateBack()
      }, 500)

    } else {
      wx.showToast({
        title: '用户名或密码错误',
        icon: 'error'
      })
    }
  },

2. 首页模块实现
//导入数据
import { bannerList, startList, produtList } from '../../utils/dataservice'

Page({

  data: {
    bannerList: [],
    startList: [],
    produtList: []
  },

  onLoad() {
    this.setData({
      //加载轮播图数据
      bannerList: bannerList,
      //加载精刚区数据
      startList: startList,
      //加载首页商品列表数据
      produtList: produtList
    })
  },

  /**
    * 列表点击事件
    */
  onItemClickHandle(options) {
    const item = encodeURIComponent(JSON.stringify(options.currentTarget.dataset.item))
    wx.navigateTo({
      url: `/pages/detail/detail?productInfo=${item}`,
    })
  },
})
4. 分类模块实现
// pages/category/category.js

//导入数据
import getCategoryList from '../../utils/dataservice';
Page({

  /**
   * 页面的初始数据
   */
  data: {
    categoryList: [
      { "category_id": 0, "category_name": "新品推荐" },
      { "category_id": 1, "category_name": "招牌爆款" },
      { "category_id": 2, "category_name": "主厨推荐" },
      { "category_id": 3, "category_name": "开胃前菜" },
      { "category_id": 4, "category_name": "美味主食" },
      { "category_id": 5, "category_name": "美味甜品" },
      { "category_id": 6, "category_name": "鲜榨果品" },
      { "category_id": 7, "category_name": "蔬菜沙拉" },
      { "category_id": 8, "category_name": "轻食小吃" },
    ],
    productList: [],
    selectedIndex: 0
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {
    //获取商品分类列表数据
    this.getCategoryListData(this.data.selectedIndex)
  },


  /**
   * 商品分类选择
   */
  onSelectedHandle(options) {
    this.setData({
      selectedIndex: options.currentTarget.dataset.item.category_id
    })

    //获取商品分类列表数据
    this.getCategoryListData(this.data.selectedIndex)
  },


  /**
   * 获取商品分类列表数据
   */
  getCategoryListData(selectedIndex) {
    const result = getCategoryList(selectedIndex)
    this.setData({
      productList: result
    })
  },


  /**
   * 列表点击事件
   */
  onItemClickHandle(options) {
    const item = encodeURIComponent(JSON.stringify(options.currentTarget.dataset.item))
    wx.navigateTo({
      url: `/pages/detail/detail?productInfo=${item}`,
    })
  },

})
5. 购物车模块实现
// pages/cart/cart.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    carts: [],
    totalPrice: 0
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onShow(options) {
    this.loadCartData();
  },

  /**
   * 加载购物车数据
   */
  loadCartData() {
    const user = wx.getStorageSync('user') || {};
    const allCarts = wx.getStorageSync('carts') || [];
    // 提取当前用户的数据
    const userCart = allCarts.find(cart => cart.username === user.username) || { items: [] };
    this.setData({
      carts: userCart.items,
      totalPrice: this.calculateTotalPrice(userCart.items)
    });
  },

  // 计算总价方法  
  calculateTotalPrice(cartItems) {
    // 使用 reduce 方法累加每个商品的总价
    return cartItems.reduce((total, item) => {
      return total + (item.price * item.count);
    }, 0).toFixed(2) * 100; // 保留两位小数
  },

  /**
   * 加购
   */
  plus(options) {
    const user = wx.getStorageSync('user') || {};
    const item = options.currentTarget.dataset.item;
    // 1. 获取所有用户的购物车数据
    const allCarts = wx.getStorageSync('carts') || [];
    // 2. 找到当前用户的购物车(没有则初始化)
    let userCart = allCarts.find(cart => cart.username === user.username);
    if (!userCart) {
      userCart = { username: user.username, items: [] };
      allCarts.push(userCart);
    }
    // 3. 修改当前用户的购物车商品数量
    const updatedItems = userCart.items.map(cartItem => {
      return cartItem.product_id === item.product_id ? { ...cartItem, count: cartItem.count + 1 } : cartItem;
    });

    // 4. 更新数据
    userCart.items = updatedItems;
    wx.setStorageSync('carts', allCarts);
    // 5. 更新页面显示(只展示当前用户的数据)
    this.setData({
      carts: updatedItems,
      totalPrice: this.calculateTotalPrice(updatedItems)
    });
  },
  // 更新购物车数据
  updateCart(updatedCart) {
    wx.setStorageSync('carts', updatedCart);
    this.setData({
      carts: updatedCart,
      totalPrice: this.calculateTotalPrice(updatedCart)
    });
  },
  /**
 * 减购
 */
  minus(options) {
    // 获取当前点击商品数据
    const product = options.currentTarget.dataset.item;
    const allCarts = wx.getStorageSync('carts') || [];
    const user = wx.getStorageSync('user');
    // 1. 找到当前用户的购物车
    const userCart = allCarts.find(cart => cart.username === user.username);
    if (!userCart) return; // 无购物车则退出
    // 2. 找到商品在购物车中的索引
    const itemIndex = userCart.items.findIndex(item => item.product_id === product.product_id);
    if (itemIndex === -1) return; // 商品不存在则退出
    // 3. 减少数量
    userCart.items[itemIndex].count -= 1;
    // 4. 保存数据并更新 UI
    wx.setStorageSync('carts', allCarts);
    this.setData({
      carts: userCart.items || [], // 确保空购物车时传空数组
      totalPrice: this.calculateTotalPrice(userCart.items || [])
    });
  },

  /**
   * 删除商品
   */
  removeItemHandle(options) {
    // 获取要删除的商品
    const product = options.currentTarget.dataset.item;
    wx.showModal({
      title: '温馨提示',
      content: '确定要从购物车移除该商品吗?',
      complete: (res) => {
        if (res.confirm) {
          const user = wx.getStorageSync('user');
          const allCarts = wx.getStorageSync('carts') || [];
          // 1. 找到当前用户的购物车
          const userCartIndex = allCarts.findIndex(cart => cart.username === user.username);
          if (userCartIndex === -1) return; // 用户购物车不存在则退出
          // 2. 从该用户的 items 中移除目标商品
          const updatedItems = allCarts[userCartIndex].items.filter(item => item.product_id !== product.product_id);
          // 3. 更新数据
          allCarts[userCartIndex].items = updatedItems;
          // 4. 保存数据并更新 UI
          wx.setStorageSync('carts', allCarts);
          this.setData({
            carts: updatedItems, // 更新当前页面的购物车列表
            totalPrice: this.calculateTotalPrice(updatedItems)
          });
        }
      }
    })
  },

  /**
   * 提交订单
   */
  onSubmit(options) {
    const user = wx.getStorageSync('user')
    if (!user) {
      wx.showModal({
        title: '温馨提示',
        content: '系统检测到您未登录,请先登录',
        complete: (res) => {
          if (res.confirm) {
            wx.navigateTo({
              url: '/pages/login/login',
            })
          }
        }
      })
      return;
    }

    if (this.data.totalPrice === 0) {
      wx.showToast({
        title: '购物车空空如也,去看看吧~',
        icon: 'error',
        success: () => {
          setTimeout(() => {
            wx.switchTab({
              url: '/pages/category/category',
            })
          }, 500)
        }
      })
      return;
    }

    wx.showModal({
      title: '温馨提示',
      content: '您确定下单吗?',
      complete: (res) => {
        if (res.confirm) {
          // 1. 获取当前用户的购物车数据
          const allCarts = wx.getStorageSync('carts') || [];
          const userCartIndex = allCarts.findIndex(cart => cart.username === user.username);
          if (userCartIndex === -1 || allCarts[userCartIndex].items.length === 0) {
            wx.showToast({ title: '购物车为空', icon: 'error' });
            return;
          }
          const userCartItems = allCarts[userCartIndex].items;
          // 2. 生成订单(添加订单时间、状态等元信息)
          const newOrder = {
            order_id: Date.now().toString(), // 简单生成订单ID(实际项目建议更严谨的方式)
            username: user.username,
            items: userCartItems,
            create_time: new Date().toLocaleString(),
            status: '支付成功'
          }

          // 3. 保存订单(多用户订单隔离)
          const allOrders = wx.getStorageSync('orders') || [];
          allOrders.push(newOrder); // 将新订单追加到订单列表
          wx.setStorageSync('orders', allOrders);
          // 4. 清空当前用户的购物车(不影响其他用户)
          allCarts[userCartIndex].items = []; // 清空items而非删除用户条目,保留用户购物车结构
          wx.setStorageSync('carts', allCarts);

         // 5. 更新页面状态
          this.setData({
            carts: [],
            totalPrice: 0
          });

          wx.showToast({
            title: '下单成功',
          })
        }
      }
    })
  }
})
6. 订单模块实现
// pages/order/order.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    orderList: []
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {
    this.loadUserOrders();
  },

  /**
   * 订单加载方法中预处理数据
   */
  loadUserOrders() {
    const { username } = wx.getStorageSync('user');
    // 1. 获取所有订单(假设数据结构为订单数组,每个订单包含items)
    const result = wx.getStorageSync('orders') || [];
    //2. 过滤出当前用户的订单,并平铺items
    const userOrder = result
      .filter(item => item.username === username)
      .flatMap(order => {
        // 为每个商品添加订单元信息(可选)
        return order.items.map(item => ({
          ...item,
          order_id: order.order_id,     // 关联订单ID
          order_status: order.status,    // 订单状态
          create_time: order.create_time, // 下单时间
          unique_id: `${order.order_id}${item.product_id}`
        }));
      })
    // 3. 更新数据
    this.setData({
      orderList: userOrder
    })
  },

  /**
   * 删除订单
   */
  removeOrderHandle(options) {
    const orderInfo = options.currentTarget.dataset.item;
    const user = wx.getStorageSync('user')
    wx.showModal({
      title: '温馨提示',
      content: '确定要从订单中删除该商品吗?',
      complete: (res) => {
        if (res.confirm) {
          // 1. 获取所有订单数据
          const allOrders = wx.getStorageSync('orders') || [];
          // 2. 遍历查找目标商品
          const updatedOrders = allOrders.map(order => {
            // 2.1 检查订单归属
            if (order.username !== user.username) {
              return order;
            }
            // 2.2 过滤掉目标商品
            const updatedItems = order.items.filter(item => `${order.order_id}${item.product_id}` !== orderInfo.unique_id)
           // 2.3  updatedItems 可能返回空items的订单,所有加判空处理
            return updatedItems.length > 0 ? { ...order, items: updatedItems } : null;
          })
          .filter(Boolean) // 移除null(即空订单)
          console.log(updatedOrders)

          // 4. 保存数据
          wx.setStorageSync('orders', updatedOrders);

          // 5. 重新加载
          this.loadUserOrders();
          wx.showToast({
            title: '删除成功',
          })
        }
      }
    })
  }
})

5. 注意事项

  1. 存储限制:wx.setStorageSync有10MB大小限制
  2. 多设备同步:本地存储无法实现多设备同步
  3. 数据持久性:用户清理缓存会丢失所有数据

这个纯前端实现方案适合作为学习项目或个人小店使用,如果要开发商业应用,建议还是使用后端数据库存储数据。

6. 项目效果截图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

7. 关于作者其它项目视频教程介绍

本人在b站录制的一些视频教程项目,免费供大家学习

  1. Android新闻资讯app实战:https://www.bilibili.com/video/BV1CA1vYoEad/?vd_source=984bb03f768809c7d33f20179343d8c8
  2. Androidstudio开发购物商城实战:https://www.bilibili.com/video/BV1PjHfeXE8U/?vd_source=984bb03f768809c7d33f20179343d8c8
  3. Android开发备忘录记事本实战:https://www.bilibili.com/video/BV1FJ4m1u76G?vd_source=984bb03f768809c7d33f20179343d8c8&spm_id_from=333.788.videopod.sections
  4. Androidstudio底部导航栏实现:https://www.bilibili.com/video/BV1XB4y1d7et/?spm_id_from=333.337.search-card.all.click&vd_source=984bb03f768809c7d33f20179343d8c8
  5. Android使用TabLayout+ViewPager2实现左右滑动切换:https://www.bilibili.com/video/BV1Mz4y1c7eX/?spm_id_from=333.337.search-card.all.click&vd_source=984bb03f768809c7d33f20179343d8c8

网站公告

今日签到

点亮在社区的每一天
去签到