
温馨提示本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片1. 项目背景与意义随着移动互联网和餐饮行业的深度融合传统纸质菜单点餐方式逐渐暴露出效率低、易出错、排队时间长等问题。顾客需要等待服务员记录菜品高峰期容易出现漏单、错单商家也难以快速掌握菜品销量和库存变化。线上点餐系统通过数字化手段将菜单展示、下单、支付、订单管理等环节搬到线上既提升了顾客的点餐体验也帮助商家降低人力成本、提高运营效率。本课题选择Python作为主要开发语言结合Web开发框架实现一套功能完整的线上点餐系统具有以下意义提升点餐效率顾客扫码即可浏览菜单、自助下单减少等待时间。降低运营成本减少服务员点单工作量缓解高峰期人力压力。数据驱动决策系统自动统计菜品销量和订单数据为商家调整菜单和备货提供依据。锻炼工程能力完整覆盖需求分析、数据库设计、接口开发、前端交互等环节是典型的全栈实践项目。2. 技术栈选型本系统采用前后端分离的开发模式整体技术栈如下层次技术选型说明后端框架Flask / DjangoFlask轻量灵活适合快速开发Django自带Admin和ORM适合功能较全的管理端数据库MySQL / SQLiteMySQL适合生产环境SQLite适合本地演示和课程设计ORMSQLAlchemy / Django ORM简化数据库操作避免手写SQL前端HTML CSS JavaScript / Vue.js实现菜单展示、购物车、下单等交互界面接口风格RESTful API前后端通过JSON格式进行数据交互身份认证Session / JWT实现用户登录和权限控制部署环境Linux Gunicorn Nginx用于生产环境部署可选本设计以Flask MySQL SQLAlchemy为主路线前端使用原生HTML/CSS/JavaScript配合Vue.js进行页面渲染兼顾开发效率和代码可读性。3. 系统功能模块设计系统面向三类角色顾客、商家管理员和系统管理员主要功能模块划分如下3.1 顾客端模块用户注册与登录支持手机号或用户名注册登录后维护个人资料。菜品浏览按分类展示菜品支持关键词搜索和价格排序。购物车管理添加、修改数量、删除菜品实时计算总价。在线下单填写配送地址或选择到店自取提交订单。订单查询查看历史订单和订单状态待接单、制作中、已完成、已取消。3.2 商家管理端模块菜品管理新增、编辑、上下架菜品维护菜品图片、价格和库存。分类管理维护菜品分类方便顾客浏览。订单处理查看新订单、确认接单、标记制作完成。数据统计按日/周查看订单量和销售额分析热门菜品。3.3 系统管理端模块用户管理查看和禁用违规用户账号。商家审核审核入驻商家的资质和信息。系统配置维护公告、轮播图等基础信息。4. 数据库设计系统核心数据表包括用户表、商家表、菜品表、菜品分类表、购物车表、订单表和订单明细表。下面给出主要表结构设计4.1 用户表user字段名类型说明idINT主键自增usernameVARCHAR(50)用户名唯一password_hashVARCHAR(128)密码哈希值phoneVARCHAR(20)手机号roleVARCHAR(20)角色customer / merchant / admincreated_atDATETIME注册时间4.2 菜品表dish字段名类型说明idINT主键自增merchant_idINT所属商家ID外键category_idINT所属分类ID外键nameVARCHAR(100)菜品名称priceDECIMAL(10,2)单价image_urlVARCHAR(255)菜品图片地址stockINT库存数量statusTINYINT状态1上架 / 0下架4.3 订单表orders字段名类型说明idINT主键自增order_noVARCHAR(32)订单编号唯一user_idINT下单用户ID外键merchant_idINT接单商家ID外键total_amountDECIMAL(10,2)订单总金额statusTINYINT状态0待接单 / 1制作中 / 2已完成 / 3已取消addressVARCHAR(255)配送地址created_atDATETIME下单时间4.4 订单明细表order_item字段名类型说明idINT主键自增order_idINT所属订单ID外键dish_idINT菜品ID外键dish_nameVARCHAR(100)下单时的菜品名称快照priceDECIMAL(10,2)下单时的单价快照quantityINT购买数量5. 核心功能实现下面给出系统中最核心的几个功能模块的Python实现代码。5.1 数据库模型定义使用Flask-SQLAlchemy定义用户、菜品、订单等数据模型from flask_sqlalchemy import SQLAlchemy from werkzeug.security import generate_password_hash, check_password_hash from datetime import datetime db SQLAlchemy() class User(db.Model): __tablename__ user id db.Column(db.Integer, primary_keyTrue) username db.Column(db.String(50), uniqueTrue, nullableFalse) password_hash db.Column(db.String(128), nullableFalse) phone db.Column(db.String(20)) role db.Column(db.String(20), defaultcustomer) created_at db.Column(db.DateTime, defaultdatetime.now) def set_password(self, password): self.password_hash generate_password_hash(password) def check_password(self, password): return check_password_hash(self.password_hash, password) class Dish(db.Model): __tablename__ dish id db.Column(db.Integer, primary_keyTrue) merchant_id db.Column(db.Integer, db.ForeignKey(user.id)) category_id db.Column(db.Integer, db.ForeignKey(category.id)) name db.Column(db.String(100), nullableFalse) price db.Column(db.Numeric(10, 2), nullableFalse) image_url db.Column(db.String(255)) stock db.Column(db.Integer, default0) status db.Column(db.SmallInteger, default1) class Order(db.Model): __tablename__ orders id db.Column(db.Integer, primary_keyTrue) order_no db.Column(db.String(32), uniqueTrue, nullableFalse) user_id db.Column(db.Integer, db.ForeignKey(user.id)) merchant_id db.Column(db.Integer, db.ForeignKey(user.id)) total_amount db.Column(db.Numeric(10, 2), nullableFalse) status db.Column(db.SmallInteger, default0) address db.Column(db.String(255)) created_at db.Column(db.DateTime, defaultdatetime.now) class OrderItem(db.Model): __tablename__ order_item id db.Column(db.Integer, primary_keyTrue) order_id db.Column(db.Integer, db.ForeignKey(orders.id)) dish_id db.Column(db.Integer, db.ForeignKey(dish.id)) dish_name db.Column(db.String(100)) price db.Column(db.Numeric(10, 2)) quantity db.Column(db.Integer, default1)5.2 用户注册与登录接口注册接口对用户名唯一性进行校验密码使用哈希存储登录接口校验密码并写入Sessionfrom flask import Blueprint, request, jsonify, session auth_bp Blueprint(auth, __name__) auth_bp.route(/api/register, methods[POST]) def register(): data request.get_json() username data.get(username) password data.get(password) phone data.get(phone, ) if not username or not password: return jsonify({code: 400, msg: 用户名和密码不能为空}), 400 if User.query.filter_by(usernameusername).first(): return jsonify({code: 400, msg: 用户名已存在}), 400 user User(usernameusername, phonephone) user.set_password(password) db.session.add(user) db.session.commit() return jsonify({code: 200, msg: 注册成功}) auth_bp.route(/api/login, methods[POST]) def login(): data request.get_json() username data.get(username) password data.get(password) user User.query.filter_by(usernameusername).first() if not user or not user.check_password(password): return jsonify({code: 400, msg: 用户名或密码错误}), 400 session[user_id] user.id session[role] user.role return jsonify({code: 200, msg: 登录成功, role: user.role})5.3 菜品列表查询接口支持按分类筛选和关键词搜索返回上架状态的菜品列表auth_bp.route(/api/dishes, methods[GET]) def get_dishes(): category_id request.args.get(category_id, typeint) keyword request.args.get(keyword, ).strip() query Dish.query.filter_by(status1) if category_id: query query.filter_by(category_idcategory_id) if keyword: query query.filter(Dish.name.like(f%{keyword}%)) dishes query.all() result [{ id: d.id, name: d.name, price: float(d.price), image_url: d.image_url, stock: d.stock } for d in dishes] return jsonify({code: 200, data: result})5.4 提交订单接口提交订单时校验库存、计算总价并同时写入订单表和订单明细表使用事务保证数据一致性import uuid from datetime import datetime auth_bp.route(/api/orders, methods[POST]) def create_order(): user_id session.get(user_id) if not user_id: return jsonify({code: 401, msg: 请先登录}), 401 data request.get_json() items data.get(items, []) address data.get(address, ) if not items: return jsonify({code: 400, msg: 订单不能为空}), 400 total 0 order_items [] merchant_id None for item in items: dish Dish.query.get(item[dish_id]) if not dish or dish.status ! 1: return jsonify({code: 400, msg: f菜品不存在或已下架}), 400 if dish.stock item[quantity]: return jsonify({code: 400, msg: f菜品{dish.name}库存不足}), 400 merchant_id dish.merchant_id subtotal float(dish.price) * item[quantity] total subtotal order_items.append({ dish_id: dish.id, dish_name: dish.name, price: float(dish.price), quantity: item[quantity] }) dish.stock - item[quantity] order Order( order_nouuid.uuid4().hex[:16], user_iduser_id, merchant_idmerchant_id, total_amounttotal, addressaddress, status0 ) db.session.add(order) db.session.flush() for oi in order_items: db.session.add(OrderItem(order_idorder.id, **oi)) db.session.commit() return jsonify({code: 200, msg: 下单成功, order_no: order.order_no})5.5 商家订单处理接口商家可以查看本店订单并更新订单状态auth_bp.route(/api/merchant/orders, methods[GET]) def merchant_orders(): user_id session.get(user_id) if session.get(role) ! merchant: return jsonify({code: 403, msg: 无权限}), 403 orders Order.query.filter_by(merchant_iduser_id).order_by(Order.created_at.desc()).all() result [{ id: o.id, order_no: o.order_no, total_amount: float(o.total_amount), status: o.status, address: o.address, created_at: o.created_at.strftime(%Y-%m-%d %H:%M:%S) } for o in orders] return jsonify({code: 200, data: result}) auth_bp.route(/api/merchant/orders/int:order_id/status, methods[PUT]) def update_order_status(orde