恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

Flask + Vue 餐厅点餐系统全栈开发实战:数据库设计与订单管理

  • 首页
  • 资讯中心
  • /
  • Flask + Vue 餐厅点餐系统全栈开发实战:数据库设计与订单管理

相关资讯

IMX6ULL车载终端设计:实时性、宽温与Linux裁剪实践 2026/10/20 20:42:11
小橘子V4.790:本地可调试塔防策略模拟器 2026/10/20 20:42:11
Win11访问Win7共享报错0x80070035?SMB协议与网络配置修复指南 2026/10/20 20:42:11

最新资讯

2026零门槛AI工具实测:不学提示词,普通人也能直接用
HTTP大文件断点续传实战:分片、校验与续传状态管理
AI编程核心基本功:问题拆解、上下文管理与结果验证
Agent+大模型:AI编程开发新范式,程序员效率革命
AI分镜脚本生成器怎么用?18个字段详解带货短视频高效创作
本地OCR+大模型:从图片到结构化文档的完整工作流实战

今日推荐

高频变压器实战经验总结:磁芯选型、绕组工艺与故障排查全解析
U-Boot移植的关键:深入理解Kconfig配置系统与依赖关系
步进电机原理与调试全解析:从步距角到丢步排查

本周热门

基于GMM的语音识别系统原理与MATLAB实现详解
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

Flask + Vue 餐厅点餐系统全栈开发实战:数据库设计与订单管理

发布时间:2026/10/20 20:47:12
Flask + Vue 餐厅点餐系统全栈开发实战:数据库设计与订单管理 帮朋友打理一家小餐馆的时候我第一次认真考虑怎么把点餐这件事搬到线上。那时候店里还是服务员手写单子、后厨看单喊菜到了饭点乱成一锅粥月底对账更是对到怀疑人生。后来我决定自己动手做一套基于 Flask 的餐厅点餐管理系统前端用 Vue 做移动端页面IDE 用 PyCharm 从开发到调试一路跑通。说实话动手之前我也在 Flask 和 Django 之间反复横跳了很久真正做完之后才明白选哪个框架不重要重要的是你能不能把业务链路想清楚。这篇文章不打算写成教科书式的项目说明书而是把我从技术选型、数据库建模、后端接口、Vue 页面到联调排坑的完整过程拆开来讲。如果你正准备用 Python 做类似的管理系统或者正在 PyCharm 里纠结第一个全栈项目该从哪里下手这篇文章应该能帮你少走不少弯路。1. 点餐系统到底解决什么问题从后厨传菜全靠吼说起1.1 纸质菜单时代的三个痛点我在调研需求的时候先蹲在店里观察了一个午饭高峰。最直观的感受是服务员手里夹着好几张手写单厨房窗口贴满了便利贴每张单子的字迹还不一样。这种模式有几个很要命的问题漏单和错单。一个人同时服务五桌口头加菜最容易漏记后厨看不清字迹就会做错口味。结账对不上。客人加菜、退菜、打折全靠人脑记高峰期一忙最后的账单和实际消费经常对不上。没有任何数据沉淀。什么菜卖得好、什么时间段是高峰、翻台率多少老板全靠感觉做决策没有依据。这不是某一家店的问题而是大量中小餐饮门店的真实写照。所以这个点餐管理系统的核心目标很朴素让顾客扫码点餐让后厨自动接单让老板打开手机就能看到今天的营业情况。1.2 核心流程与功能模块怎么划分整个系统的业务闭环其实不算复杂可以用一条主线串起来顾客扫桌台二维码进入小程序页面 → 浏览菜品分类和列表 → 把想吃的加入购物车 → 提交订单 → 模拟支付 → 后厨端看到新订单开始制作 → 顾客用餐完毕确认订单完成 → 桌台自动清空释放。围绕这条主线功能模块我拆成了三大块顾客端Vue 页面菜品浏览、分类切换、购物车、下单支付、历史订单。商家端Vue 页面菜品上下架、分类管理、桌台管理、实时订单列表、订单状态操作。后端服务Flask API用户鉴权、菜品查询、订单创建、订单状态流转、数据统计。模块划分的核心原则是先把完整的核心链路跑通再去考虑锦上添花的东西。1.3 第一版不要做什么MVP 边界很多人在做类似项目的时候容易陷入一个误区什么都想做结果什么都做不完。我给自己定的第一版边界非常明确不做真实的微信支付改用模拟支付接口前端调后端接口完成状态流转。不做会员积分和优惠券系统订单金额就是菜品单价乘以数量。不做后厨小票打印机的硬件对接后厨端用浏览器页面刷新待处理订单。不做复杂的权限角色管理只区分普通顾客和管理员两种角色。这样做的好处是你可以用一周时间把所有核心代码写完然后花时间在真正有价值的事情上把订单状态流转做严谨把金额计算做准确把交互体验做顺畅。2. 技术选型逻辑Flask 和 Django 之间我为什么选 Flask2.1 Flask 的轻量对一个单人项目意味着什么标题里同时出现 Flask 和 Django其实就是很多人在选型阶段的真实纠结。我自己也是从 Django 起步的但做到这个项目的时候我坚定地选了 Flask。原因其实非常简单Django 是一个全家桶框架自带 Admin 后台、ORM、表单处理、模板引擎、用户认证。这些功能确实强大但对一个目标非常聚焦的点餐系统来说一半以上我用不到。更关键的是Django 的项目结构是固定的apps、settings、urls这些目录和配置要求你在它的框架思维里写代码。Flask 不一样它只给你一个最小的核心路由怎么组织、蓝图怎么分、数据库怎么连你自己说了算。做这种中小型管理系统Flask 搭配 Flask-SQLAlchemy、Flask-CORS、Flask-JWT-Extended 这几个扩展已经能覆盖绝大多数需求而且每个组件你都能搞清楚它是怎么工作的。用 PyCharm 调试起来断点打在路由函数里请求进来走到哪一行一目了然这种掌控感在写 Django 项目的时候反而不容易获得。2.2 Vue 在前端页面交互里的优势需求里的前端是给顾客扫码用的使用场景是手机浏览器页面要像一个小程序一样流畅。如果后端用 Flask 自带的 Jinja2 模板渲染也不是不能做但一旦交互复杂起来比如购物车要实时更新角标、菜品分类要左右联动、下单后要轮询订单状态模板加 jQuery 的写法会让代码变得非常难维护。Vue 的组件化开发正好解决这个问题。我把页面拆成左侧分类导航组件。右侧菜品卡片组件。底部购物车栏组件。下单确认弹窗组件。每个组件只负责自己的数据和事件通过 Vuex 管理共享的购物车状态。前端只通过 Axios 调用 Flask 提供的 JSON 接口完全不关心后端模板长什么样这种前后端分离的架构在团队协作和后续扩展上都有明显优势。至于为什么是 Vue 而不是 React很大程度上是因为 Vue 对初学者更友好配合 Vant 组件库做移动端页面非常顺滑中文文档也足够完善。2.3 PyCharm 在整个开发流程里扮演的角色很多教程喜欢把 PyCharm 一句话带过但实际开发中它提供的帮助非常大。我用的是 PyCharm 专业版主要有四个功能在这个项目里帮了大忙虚拟环境管理。新建项目时直接创建 venv所有依赖装在隔离环境里不会把系统 Python 弄得乱七八糟。断点调试。后端接口出问题时在路由函数里打上断点用 Postman 或前端页面触发请求就能一步一步看变量变化比看日志猜问题高效太多。数据库面板。专业版内置 Database 工具可以直接连 MySQL查看表结构、执行 SQL、甚至可视化编辑数据完全不需要额外打开 Navicat。代码补全和重构。SQLAlchemy 模型的字段名、路由装饰器的参数写错了会在敲代码的时候就提示极大减少低级错误。3. 数据库设计菜单、桌台、订单到底该怎么建模3.1 六张核心表从分类到订单明细数据库设计是整个系统的基础表结构一旦定错后面写接口就是灾难般地返工。我最终定的核心表是六张分类表、菜品表、桌台表、用户表、订单主表、订单明细表。其中最有代表性的两张表建表 SQL 是这样CREATE TABLE category ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, sort INT DEFAULT 0, status TINYINT DEFAULT 1 ); CREATE TABLE menu ( id INT PRIMARY KEY AUTO_INCREMENT, category_id INT NOT NULL, name VARCHAR(100) NOT NULL, price DECIMAL(10, 2) NOT NULL, image VARCHAR(255), description VARCHAR(500), stock INT DEFAULT 9999, status TINYINT DEFAULT 1, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_category (category_id), CONSTRAINT fk_menu_category FOREIGN KEY (category_id) REFERENCES category(id) );菜品表单独放一个category_id外键而不是直接存分类名称字符串是因为分类名称可能会改比如川菜改成经典川菜。如果菜品表里直接冗余分类名改一次名称就要批量更新所有菜品用外键关联只需要改分类表里那一条记录。3.2 订单主表和明细表为什么要拆开订单表的设计是这个系统里最值得花心思的地方。我先说结论永远不要把顾客点的多道菜塞进同一个字段里比如用逗号拼接菜名那会让后续所有统计都无法实现。正确的做法是拆成两张表CREATE TABLE orders ( id BIGINT PRIMARY KEY AUTO_INCREMENT, order_no VARCHAR(32) NOT NULL UNIQUE, user_id INT NOT NULL, table_id INT NOT NULL, total_amount DECIMAL(10, 2) NOT NULL, status TINYINT DEFAULT 0 COMMENT 0待支付 1已支付 2制作中 3已完成 4已取消, remark VARCHAR(200), pay_time DATETIME, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_user (user_id), KEY idx_table (table_id) ); CREATE TABLE order_items ( id BIGINT PRIMARY KEY AUTO_INCREMENT, order_id BIGINT NOT NULL, menu_id INT NOT NULL, menu_name VARCHAR(100) NOT NULL, price DECIMAL(10, 2) NOT NULL, quantity INT NOT NULL, amount DECIMAL(10, 2) NOT NULL, CONSTRAINT fk_items_order FOREIGN KEY (order_id) REFERENCES orders(id) );订单主表记录一次消费的整体信息哪个用户、哪张桌子、总金额、当前状态。订单明细表记录这一单里每一道菜的信息菜名、单价、数量、小计。订单主表和明细表是一对多的关系。这里有一个细节值得注意order_items表里我冗余了menu_name和price。为什么因为在真实业务里一道菜的价格是会调整的甚至菜品会被删除。如果订单明细表只存menu_id等你想看三个月前那笔订单到底吃的什么、花了多少钱时可能这道菜已经下架了你的查询结果就永远缺失了数据。在写进订单的那一刻把快照保存下来才能保证历史订单永远可追溯。3.3 金额字段为什么必须用 DECIMAL 而不是 Float这个坑我刚入行的时候踩过后来在项目代码规范里就再也没用过浮点型存金额。经典的例子是0.1 0.2在浮点运算里结果不是0.3而是0.30000000000000004。金额这种需要精确到分的数据如果因为精度误差导致结账差一分钱运营上是非常尴尬的事情。所以在 MySQL 建表时所有金额字段都用DECIMAL(10, 2)在 SQLAlchemy 模型里对应的是Numeric(10, 2)。Python 后端在计算时使用Decimal类型而不是原生float等计算完毕需要返回给前端时再转成字符串或保留两位小数的数字。3.4 订单状态字段用数字枚举别用英文字符串订单状态我定义成了TINYINT数字类型然后用常量类管理class OrderStatus: UNPAID 0 PAID 1 COOKING 2 DONE 3 CANCELLED 4状态流转的核心链路是待支付 → 已支付 → 制作中 → 已完成另外待支付的状态可以取消变成已取消。为什么要刻意设计状态机因为一旦订单进入已支付阶段就涉及退款、后厨生产等下游动作状态之间不能随便乱跳。我见过一些项目用字符串状态比如unpaid、paid这样做的问题是拼写错误只能等到运行时才发现而且传参时大小写稍不一致就会导致查询失效。用数字枚举配合后端校验是最稳妥的方案。4. 后端 API 链路从鉴权到下单成功中间发生了什么4.1 项目结构与初始化方式后端的目录结构我用的是 Flask 的工厂模式加蓝图代码清晰扩展性也足够好restaurant/ ├── app.py # 入口创建 app 并启动 ├── config.py # 配置项数据库连接、密钥 ├── models.py # SQLAlchemy 模型定义 ├── requirements.txt ├── api/ │ ├── __init__.py # 注册蓝图 │ ├── auth.py # 登录鉴权 │ ├── menu.py # 菜品分类与列表 │ └── order.py # 订单创建、支付、状态流转 └── frontend/ # Vue 前端项目入口文件app.py看起来非常简洁from flask import Flask from config import Config from models import db from api import register_blueprints def create_app(): app Flask(__name__) app.config.from_object(Config) db.init_app(app) register_blueprints(app) return app if __name__ __main__: app create_app() app.run(host0.0.0.0, port5000, debugTrue)这里有一个容易忽略的细节db.init_app(app)之后必须先create_all()或者用 MySQL 执行建表 SQL否则模型和数据表是对不上的。我在项目里选择直接在数据库执行建表 SQL因为表结构涉及外键关系手动建表更可控。4.2 登录鉴权的简化实现真实的顾客扫码点餐场景里一般是微信授权登录前端拿到临时 code后端拿 code 去微信接口换openid再根据openid给用户签发自己的 token。但这个流程在本地开发环境里会非常麻烦需要公众号或小程序的 AppID 和 Secret。所以我第一版做了简化顾客首次进入时输入一个手机号和昵称后端自动创建一个用户签发一个 token 返回给前端。这个 token 用PyJWT生成后续所有接口都通过它识别用户身份。import jwt import datetime SECRET_KEY your-secret-key def generate_token(user_id): payload { user_id: user_id, exp: datetime.datetime.utcnow() datetime.timedelta(days7) } return jwt.encode(payload, SECRET_KEY, algorithmHS256)这个方案的优点是本地开发完全自洽不依赖第三方平台。等真正上线需要微信登录时只需要在登录接口里增加一步微信 code 换 openid 的逻辑用户表新增一个openid字段其余代码完全不用动。4.3 下单接口的完整逻辑下单是整个系统里最核心的接口也是最容易出 bug 的地方。我贴一下核心逻辑然后逐行讲清楚为什么这么写from decimal import Decimal from datetime import datetime import random from flask import request, jsonify from models import db, Order, OrderItem, Menu, Table api_bp.route(/order/create, methods[POST]) def create_order(): data request.get_json() user_id get_current_user_id() table_id data.get(table_id) items data.get(items) # [{menu_id: 1, quantity: 2}, ...] remark data.get(remark, ) table Table.query.get(table_id) if not table or table.status ! 0: return jsonify({code: 400, msg: 桌台不可用}) total Decimal(0.00) order_items [] for item in items: menu Menu.query.get(item[menu_id]) if not menu or menu.status ! 1: return jsonify({code: 400, msg: 菜品已下架}) price Decimal(str(menu.price)) qty int(item[quantity]) amount price * qty total amount order_items.append(OrderItem( menu_idmenu.id, menu_namemenu.name, priceprice, quantityqty, amountamount )) order_no datetime.now().strftime(%Y%m%d%H%M%S) str(random.randint(1000, 9999)) order Order( order_noorder_no, user_iduser_id, table_idtable_id, total_amounttotal, statusOrderStatus.UNPAID, remarkremark ) db.session.add(order) db.session.flush() for oi in order_items: oi.order_id order.id db.session.add(oi) table.status 1 db.session.commit() return jsonify({code: 0, data: {order_no: order_no, total_amount: str(total)}})几个关键点我在实际调试中验证过金额计算必须从数据库查出菜品单价后在后端统一算不能信任前端传过来的价格。否则用户改一下请求体里的金额字段后端就会用错误的价格入账。数据库价格字段是Numeric类型SQLAlchemy 查出来可能是Decimal也可能是str稳妥做法是Decimal(str(menu.price))再参与运算避免类型混用报错。先db.session.flush()拿到生成的订单 id再给明细表的外键赋值最后一起提交这样能保证事务的原子性。如果中途出错所有操作一起回滚不会出现只有订单没有明细的脏数据。桌台状态在提交订单时立刻改为使用中是为了防止同一桌被重复下单。但这只是第一道防线更严谨的并发控制我后面单独讲。4.4 模拟支付的设计与扩展方向第一版不做真实微信支付所以我用一个模拟支付接口完成状态流转api_bp.route(/order/pay, methods[POST]) def pay_order(): data request.get_json() order_no data.get(order_no) order Order.query.filter_by(order_noorder_no).first() if not order: return jsonify({code: 400, msg: 订单不存在}) if order.status ! OrderStatus.UNPAID: return jsonify({code: 400, msg: 订单状态不允许支付}) order.status OrderStatus.PAID order.pay_time datetime.now() db.session.commit() return jsonify({code: 0, msg: 支付成功})前端在用户点击模拟支付时先展示一个支付确认弹窗然后调用这个接口。接口返回成功后购物车清空订单详情页显示已支付状态。以后要接真实支付只需要把pay_order里调用微信统一下单、接收回调验签的逻辑替换进去订单状态在支付回调里更新即可。核心的订单服务逻辑不受影响这就是接口设计里面向扩展的好处。5. 前端 Vue 页面扫码点餐交互的落地过程5.1 脚手架与移动端组件库前端项目我放在了restaurant/frontend目录下用 Vue CLI 创建。除了基础依赖额外装了三个东西vue-router做页面路由、vuex做购物车状态管理、axios做 HTTP 请求。移动端 UI 我用了 Vant 组件库。它专为移动端设计组件风格很统一下拉刷新、商品卡片、购物车栏、弹出层这些组件开箱即用。特别方便的是它自带的Stepper步进器组件用来调整菜品数量非常合适省去了自己写加号减号的麻烦。5.2 购物车状态的 Vuex 设计购物车是整个前端最核心的状态。我把购物车定义为一个数组每个元素包含菜品的基本信息快照和数量const state { cart: [] // [{ menuId: 1, name: 宫保鸡丁, price: 28.0, quantity: 1 }] } const mutations { ADD_TO_CART(state, item) { const found state.cart.find(i i.menuId item.menuId) if (found) { found.quantity } else { state.cart.push({ ...item, quantity: 1 }) } }, REMOVE_FROM_CART(state, menuId) { state.cart state.cart.filter(i i.menuId ! menuId) }, CLEAR_CART(state) { state.cart [] } } const getters { cartTotal: state state.cart.reduce((sum, i) sum i.price * i.quantity, 0), cartCount: state state.cart.reduce((sum, i) sum i.quantity, 0) }这里要注意的是购物车里存一份菜品价格快照用户每次加菜后如果菜品价格变了提交订单时仍然以后端数据库价格为准前端购物车里的价格只用于展示。否则会出现一个经典问题用户把菜加入购物车时显示 28 元等到提交订单时后端返回 30 元体验很割裂。5.3 桌台号怎么通过二维码进入扫码点餐的体验关键在于桌台参数传递。我给每个桌台生成一个二维码二维码内容就是一个带桌台号的链接比如http://localhost:8080/?tableNo12。前端在路由入口读取query.tableNo存入localStorage后续所有接口都从localStorage里读桌台号。这个方案的优点是桌台和前端页面完全解耦餐厅新增一张桌子只需要在后台生成一个新二维码前端代码不用做任何修改。相比把桌台号写死在路由路径里这种方式更灵活。5.4 订单状态在前端的轮询展示顾客提交订单后需要看到订单进入制作中的状态。前端采用了简单轮询订单详情页每 10 秒调用一次订单状态接口当状态为已完成时自动弹出提示。轮询虽然不如 WebSocket 实时但对点餐场景完全够用而且实现成本低得多。后厨端页面则是通过一个按钮手动刷新待处理列表或者用 30 秒一次的定时器刷新。真实餐厅里后厨一般会配一个戴尔大屏随时看但在开发阶段浏览器刷新完全可以接受。6. 实测排坑记录跨域、金额精度、并发抢单6.1 跨域问题Flask-CORS 的正确姿势前后端分离开发第一个遇到的坑就是跨域。前端跑在http://localhost:8080后端跑在http://localhost:5000浏览器会拦截跨域的 AJAX 请求控制台报No Access-Control-Allow-Origin header is present。解决方案是用 Flask-CORS 扩展from flask_cors import CORS CORS(app, resources{r/api/*: {origins: *}})这里有一个容易被忽略的细节如果后续要在请求里带Authorization头或者Cookieorigins不能设置成*必须指定具体的来源地址并且加上allow_credentialsTrue。否则浏览器会报Access-Control-Allow-Origin不能是通配符的同时还要带上凭证。本地开发为了省事我用的是*线上部署时改成了前端的具体域名。这个坑排查起来很隐蔽因为接口在 Postman 里怎么请求都是正常的只有浏览器里会失败必须要对 CORS 的原理有基本了解才能快速定位。6.2 金额精度事故从 0.30000000000000004 说起前端购物车有一个实时显示总价的逻辑最初我用 JavaScript 的浮点数直接做累加结果用户买了两份 0.1 元的蘸料加一份 0.2 元的餐具总价显示成0.30000000000000004元。这种错误在测试环境容易被忽略但在真实餐厅场景里会让顾客觉得系统是个半成品。后来我做了三点修正前端展示统一用toFixed(2)购物车计算也只是为了展示不参与真实计价。后端计算金额全部使用Decimal数据库字段用DECIMAL(10, 2)。后端返回给前端时金额统一转成字符串或者保留两位小数的数字不让Decimal的精确值直接参与 JavaScript 的隐式转换。这里最值得强调的是金额计算的权威性必须完全放在后端前端只负责展示。这个原则在电商、点餐、外卖系统里都是通用的。6.3 同桌同时下单事务与行锁这个坑是在联调时被朋友发现的。他们店里有两桌客人几乎同时扫码结果其中一桌提交订单后另一桌也显示下单成功了。查数据库发现两笔订单都建出来了而且用的是同一个桌台号。问题的根源在并发两笔请求同时进入下单接口都查到了桌台状态是 0空闲然后都执行了更新为 1 的操作。我的第一个版本里桌台状态的检查是普通的查询没有任何锁机制所以两个事务都可以通过状态校验。正确的做法是在事务里加行锁让同一时刻只有一个请求能读取到这个桌台的行数据from sqlalchemy import select from sqlalchemy.orm import with_for_update with db.session.begin(): table db.session.execute( select(Table).where(Table.id table_id).with_for_update() ).scalar_one() if table.status ! 0: return jsonify({code: 400, msg: 桌台不可用}) # 后面的下单逻辑放在同一个事务里 # ...SELECT ... FOR UPDATE会对查到的行加排他锁另一个事务对同一行的查询会被阻塞直到第一个事务提交或回滚。这能保证一个桌台在任何时刻只能被一个下单请求占用。这个问题的排查思路值得展开讲一下。最开始我发现问题时先用日志记录了下单接口的入参确认两桌的桌台号确实不同排除了数据传错的可能。然后又打开 MySQL 的通用日志看到两条UPDATE table_info SET status 1几乎在同一毫秒执行。到这一步才确认是并发控制缺失而不是业务逻辑错误。这个排查链路的顺序非常重要先确认数据再看日志最后才能定位到并发问题。6.4 时间字段的时区隐患后端返回的created_at时间在数据库里是正常的但页面显示却差了 8 个小时。原因是 Python 的datetime.now()取的是本机默认时区而 MySQL 默认连接的时区可能跟本机不一致。接口返回给前端的时间字符串如果不带时区信息前端new Date()解析时会得到一个错误的时间点。我的解决方案是在config.py里统一规范时间处理from pytz import timezone def now_str(): return datetime.now(timezone(Asia/Shanghai)).strftime(%Y-%m-%d %H:%M:%S)所有需要记录时间的地方都调用这个统一函数不直接散落使用datetime.now()。这样至少能保证同一个项目里时间口径是一致的后期排查问题少掉一大类。7. 从 PyCharm 启动到前后端联调完整运行路径7.1 后端环境配置与启动这个项目我用 PyCharm 打开后在右下角配置了 Python 解释器直接创建了一个新的 venv 虚拟环境。所有依赖写在requirements.txt里安装命令就一行pip install -r requirements.txt数据库方面我在 PyCharm 的 Database 面板里连接了本机 MySQL手工执行了前面写的建表 SQL并插入了少量测试数据比如菜品分类、几道菜、几张桌台。然后在config.py里填入数据库连接串、密钥和前端地址。一切就绪后直接运行app.py控制台输出* Running on http://0.0.0.0:5000说明后端已经起来了。7.2 前端启动步骤前端项目在另一个终端窗口启动我习惯在 PyCharm 底部自带的 Terminal 里执行cd frontend npm install npm run serve等 Vite 或者 Vue CLI 编译完成浏览器访问http://localhost:8080就能看到点餐首页。注意npm install第一次执行会有点慢尤其在网络不太好的情况下建议用镜像源安装。7.3 联调验收清单前后端都跑起来之后我整理了一份验收清单每完成一项就打勾。这套清单在后来的测试里帮了大忙也推荐你在做类似项目时用起来验收点操作路径预期结果菜品加载打开首页选择分类对应分类的菜品列表正常展示图片能加载加入购物车点击菜品加号底部购物车栏数量增加总价更新购物车修改在购物车弹窗中增减数量数量不出现负数超出库存有限制提交订单点击去结算选择桌台号生成订单号页面跳转到待支付状态模拟支付点击模拟支付按钮订单状态变更为已支付购物车清空后厨接单打开商家端页面点击刷新新订单出现在待处理列表桌台状态变为使用中完成清台商家端点击完成订单订单状态变更为已完成桌台释放为空闲历史订单在顾客端查看历史订单历史订单按时间倒序展示明细完整这套清单覆盖了从顾客进店到结账离店的全部链路如果每一条都能跑通说明系统的核心闭环已经完成可以进入真实场景试用阶段。最后再分享一个小细节。第一版上线后朋友们反馈最多的不是功能缺失而是我想备注不要辣却找不到入口。我后来在订单表加了一个remark字段前端提交订单前加了一个备注输入框改动非常小但用户体验的提升却非常明显。所以如果你也要做类似的点餐系统请一定记得把口味备注当作核心需求来设计而不是可有可无的加分项。真正做过一次完整项目你就会发现系统能不能被用户接受靠的往往就是这些不起眼的细节。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号