# order-dinner **Repository Path**: qazll/order-dinner ## Basic Information - **Project Name**: order-dinner - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-26 - **Last Updated**: 2026-07-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 今天吃什么 · 点菜(order-dinner) 一个面向移动端的「点菜 / 今天吃什么」Web 应用,帮你解决"今天吃什么"的终极难题。支持菜品管理、手动点菜下单、转盘随机选菜、订单持久化、以及通过二维码分享订单给朋友。 后端 **Spring Boot 2.7 + SQLite + MyBatis-Plus**,前端纯 **HTML/CSS/JS**(不依赖任何前端框架),二维码由 [qrcodejs](https://github.com/davidshimjs/qrcodejs) CDN 库生成。 --- ## 功能概览 | 模块 | 说明 | | --- | --- | | 菜品管理 | 按分类增删改菜品,含名称、价格、备注 | | 点菜下单 | 按分类浏览菜品,加减号控制数量,底部实时合计金额;下单时可填写订单备注和单品备注 | | 转盘选菜 | 按分类转盘随机抽取一道菜,中奖后可一键加入购物车 | | 下单历史 | 所有订单持久化到 SQLite,按时间倒序展示最近 50 条,支持查看详情和删除 | | 分享订单 | 生成带订单详情的海报图(Canvas 绘制),图片中嵌入二维码,朋友扫码即可看到同样的订单 | | 链接即状态 | URL 参数 `?orderId=N` 扫码即加载完整订单;`?cart=id:qty,...` 自动填充购物车 | | 用户系统 | 轻量级昵称登录,个人中心可设置状态(如"饿了""想吃辣的"等),首页展示最新订单和用户状态 | | 数据持久化 | 菜品 + 订单存 SQLite(单文件 `order_dinner.db`),购物车和用户状态存浏览器 localStorage | --- ## 技术栈 | 层 | 技术 | 版本 | | --- | --- | --- | | 运行时 | Java | 8 | | 框架 | Spring Boot | 2.7.18 | | ORM | MyBatis-Plus | 3.5.7 | | 数据库 | SQLite(Xerial JDBC) | 3.45.1.0 | | 构建 | Maven | 3.x | | 前端 | HTML + CSS + JavaScript(原生,无框架) | — | | 二维码 | qrcodejs(CDN) | 1.0.0 | --- ## 操作指南 ### 环境要求 - JDK 8 或更高版本 - Maven 3.x ### 启动服务 ```bash # 在项目根目录执行 mvn spring-boot:run ``` 启动成功后会打印: ``` ------------------------------------------------------------ 点菜小程序启动成功 本地访问 : http://localhost:8080 局域网访问 : http://192.168.x.x:8080 (手机/同网段设备) ------------------------------------------------------------ ``` ### 访问应用 - **本机**:浏览器打开 `http://localhost:8080` - **手机/同局域网设备**:用启动日志中的局域网 IP 访问(如 `http://192.168.1.10:8080`) 首次启动会自动创建 `order_dinner.db` 数据库文件,并初始化 7 道示例菜品。 ### 使用流程 1. **登录**:启动后弹出昵称登录弹窗,输入昵称后进入应用(数据存 localStorage,刷新不丢失) 2. **首页**:展示最新订单信息和快捷入口(去点菜 / 转盘选菜) 3. **点菜**:按分类浏览菜品,点击 `+` `−` 调整数量,底部实时显示已选数量和总价 4. **下单**:点击底部「下单」→ 弹出备注弹窗(可填订单备注和单品备注)→ 确认下单 → 自动跳转订单详情页 5. **转盘**:选择分类 → 点击「开始转盘」→ 转盘停稳后显示结果 → 可「加入点菜」或「再转一次」 6. **分享**:在订单详情页点击「分享订单」,生成带二维码的海报图,可保存图片或系统分享 7. **历史**:个人中心 →「下单历史」查看所有历史订单,每条可查看详情、分享或删除 8. **管理**:个人中心 →「菜品管理」可增删改菜品 ### 扫码使用 - 分享页生成的二维码包含 `?orderId=N` 参数 - 用手机扫描二维码 → 自动打开应用并加载对应的订单详情 - 点菜页分享菜单时会先保存订单再生成二维码,确保链接有效 --- ## 实现方式 ### 整体架构 ``` ┌─────────────────────────────────────────────┐ │ 浏览器 │ │ ┌─────────┐ ┌──────────┐ ┌────────────┐ │ │ │ index.html │ │ app.js │ │ styles.css │ │ │ └────┬────┘ └─────┬────┘ └────────────┘ │ │ │ │ │ │ │ fetch() │ localStorage │ │ │ /api/* │ (购物车/用户/状态) │ └───────┼─────────────┼────────────────────────┘ │ │ ┌───────┼─────────────┼────────────────────────┐ │ ▼ ▼ 服务端 │ │ ┌──────────┐ ┌───────────┐ │ │ │Controller│ │ Database │ │ │ │ REST API │──│ Initializer│ │ │ └────┬─────┘ └─────┬─────┘ │ │ │ │ │ │ ┌────▼─────┐ ┌─────▼─────┐ │ │ │ Service │ │ Mapper │ │ │ │ 业务逻辑 │──│ 数据访问 │ │ │ └──────────┘ └─────┬─────┘ │ │ │ │ │ ┌────▼─────┐ │ │ │ SQLite │ │ │ │ .db 文件 │ │ │ └──────────┘ │ └──────────────────────────────────────────────┘ ``` ### 后端设计 - **RESTful API**:前端通过 `fetch()` 调用 `/api/*` 接口,JSON 格式交互 - **分层架构**:Controller(接口层)→ Service(业务层)→ Mapper(数据访问层) - **MyBatis-Plus**:通过继承 `BaseMapper` 和 `ServiceImpl` 获得大部分 CRUD 能力,无需手写 XML - **SQLite 单文件数据库**:零配置、零依赖,数据文件即 `order_dinner.db`,方便迁移和备份 - **连接池**:HikariCP 最大连接数设为 1,避免 SQLite 的 "database is locked" 问题 - **自动初始化**:`DatabaseInitializer` 在 Spring Boot 启动后自动建表(`CREATE TABLE IF NOT EXISTS`)并插入示例数据 - **启动信息**:`OrderDinnerApplication` 实现 `ApplicationRunner`,启动后打印本机 IP 方便手机访问 - **CORS**:`WebConfig` 全局放开 `/api/**` 的跨域访问,方便前后端分离调试 ### 前端设计 - **单页面应用(SPA)**:通过切换 `state.view` 渲染不同页面(首页/点菜/转盘/管理/历史) - **购物车**:存于 `localStorage`,key 为 `order_dinner_cart_v1`,格式 `{ dishId: quantity }` - **用户系统**:昵称和状态存 `localStorage`,纯前端实现,下单时随请求发送到后端记录 - **Canvas 海报**:`drawMenuImage()` / `drawShareImage()` 用 Canvas API 绘制订单海报(含渐变背景、菜品列表、二维码),生成 PNG 图片供下载或系统分享 - **转盘动画**:CSS `transition` + `transform: rotate()` 实现转盘旋转,`cubic-bezier` 缓动模拟真实转盘效果 - **二维码生成**:qrcodejs CDN 库,`makeQRCanvas()` 包装函数生成 Canvas 元素,容错级别 M(15%) - **URL 状态恢复**:`loadStateFromUrl()` 在页面加载时解析 URL 参数,自动恢复购物车或加载订单详情 ### 数据表结构 **dishes(菜品表)** | 字段 | 类型 | 说明 | | --- | --- | --- | | id | INTEGER PK AUTOINCREMENT | 主键 | | name | TEXT NOT NULL | 菜名 | | category | TEXT NOT NULL | 分类 | | price | REAL | 价格 | | remark | TEXT | 备注 | **orders(订单表)** | 字段 | 类型 | 说明 | | --- | --- | --- | | id | INTEGER PK AUTOINCREMENT | 主键 | | items | TEXT NOT NULL | 订单内容 JSON | | total | REAL | 合计金额 | | created_at | TEXT | 下单时间 | | username | TEXT | 下单用户 | | note | TEXT | 订单备注 | > items 字段存储格式:`[{"id":1,"name":"宫保鸡丁","qty":2,"price":38.0,"note":""}, ...]` --- ## 各文件用途 ### 后端 Java 源码 | 文件 | 用途 | | --- | --- | | `src/main/java/com/orderdinner/OrderDinnerApplication.java` | Spring Boot 启动类,实现 `ApplicationRunner` 打印启动信息和本机 IP | | `src/main/java/com/orderdinner/config/WebConfig.java` | 全局 CORS 配置,允许任意来源访问 `/api/**` | | `src/main/java/com/orderdinner/init/DatabaseInitializer.java` | 启动时建表(dishes + orders),表为空时插入 7 道示例菜品,并为旧 orders 表补齐 username/note 列 | | `src/main/java/com/orderdinner/controller/DishController.java` | 菜品 REST 接口:列表、随机、分类列表、新增、修改、删除 | | `src/main/java/com/orderdinner/controller/OrderController.java` | 订单 REST 接口:创建订单、历史列表(最近 50 条)、单条详情、最新订单、删除 | | `src/main/java/com/orderdinner/service/DishService.java` | 菜品业务层接口,继承 MyBatis-Plus 的 `IService` | | `src/main/java/com/orderdinner/service/DishServiceImpl.java` | 菜品业务层实现,包含按分类查询、随机抽取(SQLite `ORDER BY RANDOM()`)等逻辑 | | `src/main/java/com/orderdinner/mapper/DishMapper.java` | 菜品数据访问层,继承 `BaseMapper`,额外定义建表、计数、分类查询 | | `src/main/java/com/orderdinner/mapper/OrderMapper.java` | 订单数据访问层,继承 `BaseMapper`,额外定义建表和列补齐 | | `src/main/java/com/orderdinner/model/Dish.java` | 菜品实体类,映射 `dishes` 表 | | `src/main/java/com/orderdinner/model/Order.java` | 订单实体类,映射 `orders` 表,items 字段为 JSON 字符串 | ### 配置文件 | 文件 | 用途 | | --- | --- | | `src/main/resources/application.yml` | Spring Boot 配置:SQLite 数据源(HikariCP 连接池大小=1)、服务绑定 `0.0.0.0:8080`、Jackson 忽略 null 字段 | | `pom.xml` | Maven 项目配置,定义依赖:spring-boot-starter-web、sqlite-jdbc、mybatis-plus-boot-starter | ### 前端静态资源 | 文件 | 用途 | | --- | --- | | `src/main/resources/static/index.html` | 主页面 HTML,定义所有弹窗结构(登录、下单备注、菜品编辑、订单详情、分享、个人中心),引入 qrcodejs CDN | | `src/main/resources/static/app.js` | 前端主逻辑(约 1000 行):页面路由、API 调用、购物车 CRUD、转盘绘制与动画、Canvas 海报生成、二维码生成、URL 参数解析、弹窗交互 | | `src/main/resources/static/styles.css` | 全局样式:手机外框布局、底部 TabBar、首页卡片、菜品列表、转盘、下单历史、弹窗、订单详情页等全部 UI 样式 | ### 数据文件 | 文件 | 用途 | | --- | --- | | `order_dinner.db` | SQLite 数据库文件,首次启动自动创建,包含 dishes 和 orders 两张表 | --- ## REST API 接口 基础路径:`/api` ### 菜品接口 | 方法 | 路径 | 说明 | | --- | --- | --- | | GET | `/api/dishes` | 菜品列表(可选 `?category=热菜` 过滤,不传或传"全部"返回全部) | | GET | `/api/dishes/random` | 随机一道菜(可选 `?category=热菜`,空表返回 204) | | GET | `/api/dishes/categories` | 去重后的分类列表 | | POST | `/api/dishes` | 新增菜品(body: `{name, category, price, remark}`) | | PUT | `/api/dishes/{id}` | 修改菜品 | | DELETE | `/api/dishes/{id}` | 删除菜品 | ### 订单接口 | 方法 | 路径 | 说明 | | --- | --- | --- | | POST | `/api/orders` | 创建订单(body: `{items, total, createdAt, username, note}`) | | GET | `/api/orders` | 订单历史(最近 50 条倒序) | | GET | `/api/orders/{id}` | 单条订单详情(用于扫码恢复) | | GET | `/api/orders/latest` | 最新一条订单(首页展示用) | | DELETE | `/api/orders/{id}` | 删除订单 | ### 静态资源 - `GET /` → 返回 `index.html` - `GET /styles.css` → 返回样式 - `GET /app.js` → 返回前端逻辑 --- ## 下单 → 分享完整流程 ``` 1. 用户在「点菜」页选择菜品,点击底部「下单」 │ ▼ 2. 弹出下单备注弹窗(可填订单备注 + 每道菜的单独备注) │ ▼ 3. 点击「确认下单」→ POST /api/orders 写入 SQLite │ ▼ 4. 下单成功后跳转订单详情页(只读模式) │ ▼ 5. 点击「分享订单」→ 重新加载订单 → Canvas 绘制海报(含菜品列表 + 二维码) │ ├── 「保存图片」:下载 PNG 到本地 └── 「系统分享」:调用 Web Share API 分享图片文件 │ ▼ 6. 朋友扫码(或点击链接)→ 打开应用,URL 参数 ?orderId=N → loadStateFromUrl() 解析 → 加载订单详情页 ``` 二维码编码的是完整 URL(`http://host/?orderId=N`),扫码后直接从后端加载订单数据,菜品信息完全由服务端保证一致性,不依赖前端菜品 ID 匹配。 --- ## 项目特点 - **零外部数据库依赖**:SQLite 单文件,无需安装 MySQL/PostgreSQL,开箱即用 - **手机优先设计**:max-width 430px 的模拟手机外框,适配移动端触摸操作 - **局域网共享**:服务绑定 `0.0.0.0`,同 WiFi 下手机直接访问,适合家庭/小团队使用 - **无前端构建步骤**:原生 HTML/CSS/JS,无需 npm/webpack,直接由 Spring Boot 托管静态资源 - **链接即分享**:二维码参数即状态,不依赖后端生成短链接或上传图片