吉林大学软件学院 2023 级《企业实训》 Qt 组项目自助点餐系统。
本概要设计书面向"Qt 自助点餐系统"项目,目标是将需求落实到可实施的模块结构与关键实现点:
- 给出客户端、服务端与数据库的整体架构与模块边界
- 明确主要业务流程(浏览菜品、加入购物车、提交订单、服务请求、后厨/前台处理等)的时序与接口
- 给出核心数据结构与主要类的职责划分,确保后续详细设计与编码可直接落地
- 说明异常处理与资源利用策略,为系统稳定运行与交付验收提供依据
Qt 自助点餐系统面向餐厅自助点餐场景,采用"客户端点餐 + 服务端管理 + 数据库持久化"的三端协作方式:
- 客户端(
Client):负责用户登录、菜品展示与筛选、购物车管理、提交订单以及呼叫服务等交互 - 服务端(
Server):提供管理端界面,负责订单管理、服务请求处理与业务状态展示,并通过数据库完成数据查询与落库 - 数据库(
Database):系统通过 Qt SQL 模块建立数据库连接(由DbManager统一初始化并向各页面注入连接),在订单管理页面中通过 SQL 联表查询加载订单列表,并在订单详情对订单菜品明细进行二次查询,完成可追溯的订单闭环
- 客户端:登录/注册与桌号绑定、菜品浏览与分类检索、购物车增删改、订单提交与备注、订单历史查看、呼叫服务/催单等
- 服务端:订单列表展示与刷新、订单详情弹窗、服务请求页面(用户登录分配桌号、接收呼叫、接收订单并生成上菜队列)、后台状态提示与消息弹窗
- 数据库:用户、菜品、订单、订单明细等表结构设计;提供订单列表联表查询与订单明细查询;对异常查询给出错误提示与回滚策略
总体架构采用分层思想:
- 表现层:UI
- 业务层:流程控制
- 数据访问层:SQL
- 持久层:MySQL
各端的设计如下:
Client:Qt Widgets 交互界面,封装NetworkManager负责与服务器通信Server:Qt Widgets 管理端界面 + Server 单例组件(接收客户端消息并发出login、submitOrder、callWaiter等信号)DB:通过db::DbManager::instance().db()初始化QSqlDatabase,并注入到各业务页面使用QSqlQuery完成 CRUD 操作
关键业务时序如下:
- 用户登录:
Client→Server(login请求)→Server发出login(userId)信号 →ServiceRequest_Page::onUserLogin分配桌号 - 提交订单:
Client→Server(submitOrder请求)→Server发出submitOrder(orderId, userId)信号 →ServiceRequest_Page::onSubmitOrder将菜品加入上菜队列 - 订单管理:
Server端OrderInfo_Page通过QSqlDatabase执行联表查询加载订单列表;点击订单进入OrderDetailDialog,再查询订单明细 以上信号连接关系与槽函数命名已在服务端主窗口中完成绑定。
系统整体业务流程:用户进入客户端 → 登录/注册 → 浏览菜品 → 加入购物车 → 确认订单(备注/数量)→ 提交订单 → 服务端接收并写入数据库 → 服务端订单管理页面可查询/刷新 → 后厨/服务人员依据上菜队列处理 → 用户可发起呼叫服务。
客户端从服务端请求菜品列表并展示(支持按分类/关键词筛选)。用户点击菜品后加入购物车,购物车支持数量增减与删除。在购物车界面实时计算总价($\sum \text{单价} \times \text{数量}$),并允许填写备注(如口味、忌口)。
用户在购物车确认后提交订单。服务端接收订单请求后生成订单号并写入 t_order,随后将每个菜品明细写入订单明细表。服务端同时触发 submitOrder 信号,将订单加入上菜队列。客户端可进入"订单历史/订单详情"查询订单状态与明细。
客户端在用餐过程中可发起服务请求(如呼叫服务员、催单)。服务端接收后在 ServiceRequest_Page 中提示对应桌号/用户,并记录处理状态。用户登录时服务端为其分配桌号(assignTable 返回桌号,-1 表示无空闲桌号)。
服务端订单管理页面启动或切换到"订单管理"节点时,调用 loadOrdersFromDatabase() 从数据库加载订单列表。该查询对订单表与用户表进行 LEFT JOIN,并按创建时间倒序显示。点击订单可打开订单详情对话框加载菜品明细。
在订单详情对话框中,若数据库连接可用则执行 loadOrderDetailFromDatabase() 查询订单菜品明细。查询结果组装为 OrderDish 列表;当 rating 为空时按 0.0 处理,保证界面展示稳定。
| 类/组件 | 所在端 | 核心职责 | 关键协作 |
|---|---|---|---|
ClientMainWindow |
Client | 客户端主窗口,组织点餐、购物车、历史订单等页面 | NetworkManager、各页面组件 |
NetworkManager |
Client | 封装客户端到服务端的通信(登录、请求菜品、提交订单、呼叫服务) | Server(服务端)、消息协议 |
MainWindow |
Server | 服务端主窗口,组装订单管理/服务请求等管理页面并绑定信号槽 | Server、OrderInfo_Page、ServiceRequest_Page |
Server |
Server | 服务器单例:接收客户端消息并发出 login、submitOrder、callWaiter 等信号 |
MainWindow、ServiceRequest_Page |
ServiceRequest_Page |
Server | 服务请求页面:onUserLogin 分配桌号,onSubmitOrder 加入上菜队列,onCallWaiter 处理呼叫 |
Server、数据库(可选) |
OrderInfo_Page |
Server | 订单列表页面:loadOrdersFromDatabase 联表查询订单并展示 |
QSqlDatabase、OrderDetailDialog |
OrderDetailDialog |
Server | 订单详情弹窗:loadOrderDetailFromDatabase 查询菜品明细并展示 |
QSqlDatabase、Order/OrderDish |
db::DbManager |
Server | 数据库连接管理:初始化并提供 QSqlDatabase 实例 |
QSqlDatabase、各页面 |
Order / Dish / OrderDish |
共用模型 | 领域模型:承载订单、菜品与数量/评分等数据 | UI 页面、SQL 查询结果 |
目标:为登录成功的用户分配可用桌号,并维护 userId → tableId 的映射,供订单与服务请求使用。
输入:userId
输出:tableId(无空闲桌号返回 -1)
算法步骤
- 维护桌位状态集合
$T = {1..N}$ ,以及占用集合UsedTables(可放内存,也可由数据库表维护) - 用户登录触发
onUserLogin(userId)后,遍历桌号从小到大寻找首个空闲桌号$t$ - 若找到:
- 标记
$t$ 为占用(加入UsedTables) - 写入映射表
UserTableMap[userId] = t - 返回
$t$
- 标记
- 若未找到:返回
-1,提示"无空闲桌号"
异常/边界处理
- 同一用户重复登录:若已存在映射,直接返回已分配桌号(避免重复占用)
- 用户退出/结账:释放桌号(从占用集合移除),否则长期运行会造成"桌号耗尽"
复杂度:$O(N)$($N$ 为桌位数;通常很小)
目标:在购物车界面实时更新总价,保证 UI 展示与提交订单金额一致。
输入:购物车条目列表 CartItems = {(dishId, price, qty)}
输出:totalPrice
算法步骤
- 每次用户执行"加/减数量、删除条目、清空购物车"事件时触发重算
- 初始化
total = 0 - 遍历购物车条目:
total += price * qty - UI 更新:展示
total,同时刷新每行小计
异常/边界处理
qty <= 0:直接移除条目或强制修正为1price精度:统一用decimal(10,2)或整型分(分为单位)避免浮点误差(概要设计可注明"金额用分存储")
复杂度:$O(M)$($M$ 为购物车条目数)
目标:保证订单主表与明细表一致写入;任何一步失败都不产生"半条订单"。
输入:订单主信息、购物车明细列表
输出:成功(orderId)/失败(错误信息)
算法步骤(事务)
BEGIN TRANSACTION- 插入
t_order(主表):订单号、用户、桌号、总价、创建时间、初始状态 - 遍历购物车条目,批量插入订单明细表(
dishId、qty、unitPrice、subtotal等) - 若所有 SQL 成功:
COMMIT - 任意一步失败:
ROLLBACK,返回失败
异常/边界处理
- 空购物车:直接拒绝创建订单
- 字段缺失:参数校验前置
- 插入明细失败:必须回滚主表插入
复杂度:$O(M)$($M$ 为明细条目数)
输入:可选筛选条件(状态/时间范围/用户)
输出:订单列表记录集
算法步骤
- 构造 SQL:订单表
LEFT JOIN用户表 - 添加排序:
ORDER BY create_time DESC - 执行查询并映射为 UI 列表项
- 点击列表项进入详情对话框
异常处理
db.isOpen()==false:提示"数据库未连接"并禁止刷新- SQL 执行失败:弹窗显示错误原因(便于调试与验收)
复杂度:取决于索引;建议对 create_time、user_id 建索引提升查询
6.2.5 服务请求工单处理算法(呼叫服务/催单)
目标:服务端能接收呼叫并记录处理状态,避免重复提醒与遗漏。
输入:userId/tableId/type
输出:服务请求状态(已收到/处理中/已处理)
算法步骤
- 服务端接收
callWaiter()请求,生成工单ticketId(可用时间戳/自增) - 在
ServiceRequest_Page列表新增一条记录:桌号、类型、时间、状态=NEW - 处理人员点击"处理"后状态置为
PROCESSING/DONE - 可选:将状态变更回传客户端提示用户
异常处理
- 找不到桌号:提示"桌号未知"并记录日志(通常是登录映射丢失)
- 重复请求:可按"桌号+类型+时间窗口"做去重(如 30 秒内合并)
- 数据库未连接或连接失效:各页面在执行查询前检查
db.isOpen();失败时提示并阻断后续流程。 - 输入非法:数量必须为正整数;备注长度限制;对空购物车禁止提交订单。
- 空闲桌号不足:
assignTable返回-1,并提示前台人工处理。
- 网络消息乱序/重复:服务端以订单号与用户会话为幂等键进行去重;重复提交返回上次结果。
- 界面刷新冲突:订单列表刷新采用互斥或禁用按钮的方式避免并发查询
- 消息格式校验:服务端对每个请求做字段完整性校验(必填字段缺失直接返回错误码),避免解析异常导致崩溃
- 统一响应结构:定义统一响应为
code/message/data,客户端只依据code决策 UI 提示与重试,避免"字符串匹配"
客户端与服务端界面所需图标、菜品图片等资源通过 Qt Resource(.qrc)打包;发布版本中静态资源随可执行文件分发,减少运行期文件依赖。
界面列表采用按需加载与复用控件的方式降低峰值内存;数据库查询结果以轻量模型(Order/Dish/OrderDish)承载,展示后及时释放临时对象。
- GitHub 仓库:包含
client、server、database、docs等目录 - 数据库脚本/说明:位于
database目录(含连接管理DbManager与表结构/初始化脚本)
- 双击运行客户端程序
client - 进入登录界面后:
- 已有账号:输入账号与密码,点击"登录"
- 新用户:点击"注册",按提示填写信息完成注册后返回登录
- 登录成功后系统将显示点餐主页;如系统启用桌号绑定,登录成功后会自动分配/绑定桌号(无空闲桌号时会提示联系前台)。
- 在菜品页面可查看全部菜品列表
- 可通过"分类"切换不同类别菜品;也可在搜索框输入关键词筛选菜品
- 点击菜品可查看详情(如图片、价格、评分等信息)
- 在菜品列表/详情页点击"加入购物车"
- 进入购物车页面后可:
- 点击 "
+" / "-" 调整数量 - 点击"删除"移除某一条目
- 系统会实时计算总价($\sum \text{单价} \times \text{数量}$)
- 点击 "
- 在购物车页面点击"去结算/确认订单"
- 可填写备注(如口味、忌口等)
- 检查订单金额与菜品明细无误后点击"提交订单"
- 提交后若成功,会返回订单号并显示订单初始状态
- 在"订单历史/订单详情"页面可查询:
- 历史订单列表(按时间排序)
- 指定订单的菜品明细与状态
- 用餐过程中可点击“呼叫服务/催单”。
- 系统将向服务端发送服务请求,服务端处理后客户端会收到提示(已收到/处理中/已处理)。
- 启动服务端程序 server。
- 启动后确认数据库连接状态:
- 若连接成功:可正常进入订单管理与服务请求页面;
- 若连接失败:会提示错误信息,请先检查数据库配置与驱动。
- 进入“订单管理”页面,系统会自动加载订单列表。
- 订单列表显示订单号、用户/桌号、创建时间、金额、状态等信息。
- 点击“刷新”可重新从数据库加载最新订单。
- 点击某条订单可打开订单详情对话框。
- 在订单详情中查看订单主信息与菜品明细。
- 若评分等字段为空,系统会按默认值展示,避免界面异常。
- 若查询失败(数据库不可用或 SQL 错误),服务端会提示错误并停止加载。
- 进入 ServiceRequest 页面查看服务请求列表/提示。
- 收到请求后可查看对应桌号/用户与请求类型。
- 处理完成后将请求标记为“已处理”,避免重复提醒。
- 操作系统:Windows。
- Qt:Qt 5。
- 数据库:MySQL。
- Qt SQL 驱动:需确保 Qt 能加载 MySQL/ODBC 驱动(例如 QODBC 或 QMYSQL)。
- Qt 前端组件库:ElaWidgetTools。
- 安装并启动 MySQL,创建数据库与表结构(用户表、菜品表、订单表、订单明细表等)。
- 若使用 ODBC:
- 在系统中配置 ODBC 数据源(DSN),填写服务器地址、端口、数据库名、账号密码。
- 在项目配置文件或代码中填写连接信息(或读取 DSN 连接)。
- 先启动 MySQL 数据库服务。
- 启动服务端 server,确认“数据库连接成功”。
- 启动客户端 client,登录后开始点餐流程。