定义套餐ID从 100000 开始自增,这是为了区分单点菜品ID,这样,我们就可以将套餐id 与 单点菜品 id 统一起来,一个 id 唯一对应一个 套餐 或 单点。
不过有个前提,即单点菜品的数量不会有高达10万之多(容忍少许自增键并发带来的误差)
套餐的原价应该是可以通过具体菜品计算出来的,但为了避免过多的联表查询,我们选择冗余存储
| 套餐ID | 套餐名称 | 套餐原价 | 月销售量 |
|---|---|---|---|
| id | combo_name | price | sell_num |
| 套餐ID | 菜品ID | 菜品数量 | 喜欢数量 |
|---|---|---|---|
| combo_id | dish_id | dish_num | favor_num |
定义菜品ID从 1 开始自增,严格区分套餐 id,这里的销售量是所有店铺一起统计的。
| 菜品ID | 菜品名称 | 菜品图片 | 菜品原价 | 七天销售量 | 菜品描述 | 喜欢数量 |
|---|---|---|---|---|---|---|
| id | dish_name | dish_image | price | sell_num | desc | favor_num |
| 菜品ID | 主料 | 辅料 | 凉热 | 制作方法 | 分量 | 制作时间 |
|---|---|---|---|---|---|---|
| dish_id | main | aid | cool_hot | method | weight | time |
不同店铺的库存数量是不一样的,注意套餐无须存储库存量,因为套餐的库存是根据其具体菜品的最小库存决定的。
| 菜品ID | 店铺ID | 库存 |
|---|---|---|
| dish_id | store_id | stock |
| 菜品(套餐)ID | 内容 |
|---|---|
| dish_id | text |
| 推荐菜品ID | 推荐指数 | 推荐理由 |
|---|---|---|
| dish_id | stars | reason |
下单时,需要冻结菜品数量,订单完成时解冻并且扣除数量。
冻结数量的修改是及其频繁的,因此我们采用分表的方法。
| 菜品(套餐)ID | 店铺ID | 冻结数目 |
|---|---|---|
| dish_id | store_id | num |
分表是有好处的,可以避免一个表过大而造成IO缓慢,并且,折扣活动是时常改变的,属于热数据,将冷热数据分离可以增加读写的效率。
在这里,type可选 1、2 当选择 1 时表示为折扣活动,此时 val 是一个 (0, 10) 的值,表示几折,例如 type = 0, val = 5 表示该菜品打五折;当为 2 时表示立减活动,val 是立减的价格;
虽然没有活动的菜品在数据库端将不会被记录,但在前端代码中,type = 0 表示没有活动。
此外,我们允许不同的店铺开展不同的活动。
| 菜品(套餐)ID | 店铺ID | 折扣类型 | 值 | 每日可享受次数 |
|---|---|---|---|---|
| dish_id | store_id | type | val | count |
| 用户ID | 店铺ID | 菜品(套餐)ID | 今日已享受次数 |
|---|---|---|---|
| user_id | store_id | dish_id | count |
这张表具体记载了对应菜品或套餐的单日销售,为了避免频繁修改,应该使用Redis作为缓存。我们在菜品中仍然定义了七天销售量,该销售量表示为所有店铺的总销售量,这是为了避免每一次都要经过复杂计算,我们只需在每日晚12点定时计算菜品七天销售额即可。
这里记录的是不同店铺的销售量。
| 菜品(套餐)ID | 店铺ID | 销售日期 | 单日销售量 |
|---|---|---|---|
| dish_id | store_id | date | sell_num |
| 门店ID | 门店名称 | 门店图片 | 经度 | 纬度 | 营业时间 | 是否支持外卖配送 | 联系 |
|---|---|---|---|---|---|---|---|
| id | store_name | img | longitude | latitude | time | flag | phone |
未区分点餐 Order 的区别,我们将订单取名为 form,form是表单的意思。
consume_type 0 对应扫码点餐 经历流程:待点餐 - 确认中 - 待支付 - 已完成
consume_type 1 对应到店消费 经历流程:支付保证金 - 确认中 - 备餐中 - 待用餐 - 待支付 - 已完成
consume_type 2 对应到店自取 经历流程:待支付 - 确认中 - 备餐中 - 待取餐 - 已完成
consume_type 3 对应外卖 经历流程:待支付 - 确认中 - 备餐中 - 配送中 - 已完成
formType: 0待点餐(保留以后使用), 1待支付, 2确认中,3备餐中,4待用餐,5待取餐,6配送中,7已完成,8取消确认中,9已取消
在后台管理系统中,每接收到一个订单时都要确认订单,确认之前订单处于待确认状态,确认后处于备餐中(非扫码点餐)状态,备餐完成,管理员需要手动确认备餐完毕等待用户取餐,最终由管理员关闭订单(已完成)。
| 订单ID | 订单类型 | 消费门店 | 用户ID | 支付方式 | 消费方式 | 消费桌位 | 下单时间 | 完成时间 | 原价 | 店铺优惠 | 使用券优惠 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| id | form_type | store_id | user_id | pay_type | consume_type | table | first_time | final_time | origin_price | discount1 | discount2 |
由于菜品无论是名称还是价格都可能是实时变更的,而订单中的信息不应该再更改,因此,不能直接存储菜品的 ID,但是 dishID 的存储是必要的,这是因为短时间内用户很可能继续加菜,我们需要保存对应的订单信息
| 订单ID | 菜品ID | 菜品名 | 菜品数量 | 菜品单价 |
|---|---|---|---|---|
| form_id | dish_id | dish_name | num | price |
这一类信息当订单完成后即可删除,故我们分开建表
taste 0 1 2 3 表示 不辣 微辣 中辣 辣
| 订单ID | 预约时间 | 口味 | 备注 | 送货地址 |
|---|---|---|---|---|
| form_id | expected_time | taste | remark | address |
| 用户ID | 会员等级 | 会员积分 | 钱包 | 姓名 | 联系电话 |
|---|---|---|---|---|---|
| id | rank | integral | wallet | name | phone |
| 用户ID | 店铺ID |
|---|---|
| user_id | store_id |
| 用户ID | 菜品(套餐)ID |
|---|---|
| user_id | dish_id |
| 用户ID | 菜品(套餐)ID |
|---|---|
| user_id | dish_id |
| 用户ID | 菜品(套餐)ID |
|---|---|
| user_id | dish_id |
菜品展示时,对应的展示分类,例如:下酒菜,主食,汤。由于一个菜可能对应多个标签,需要分表处理。
| 菜品ID | 分类标签 |
|---|---|
| dish_id | tag |
| 分类标签 | 图标 |
|---|---|
| tag | icon |