d0771597a6
- 添加前端设计文档(rui-admin、收银系统、模块打包) - 添加前端实施计划(收银后台功能完善) - 添加通用规范(API、编码、数据库、前端开发规则) - 建立文档索引和使用指南
1127 lines
48 KiB
Markdown
1127 lines
48 KiB
Markdown
# 收银系统(POS)设计文档
|
||
|
||
> **设计日期**: 2026-06-03
|
||
> **版本**: v2.0
|
||
> **状态**: 设计中
|
||
> **目标**: 为棋牌室、酒吧、KTV 等服务业态构建多端收银系统,支持多门店连锁运营
|
||
|
||
---
|
||
|
||
## 一、背景与目标
|
||
|
||
### 1.1 现状分析
|
||
|
||
目前运营 100+ 棋牌室门店,采用总部 → 代理商 → 门店三级管理模式。各门店急需一套收银系统来管理包间/桌台的开台、计费、结账流程。现有系统空缺,依赖人工记账,效率低、易出错、无法统一管理。
|
||
|
||
### 1.2 目标定义
|
||
|
||
1. **建立标准化收银流程**:支持开台、计时/计费、结账、退款的完整闭环
|
||
2. **多门店统一管理**:总部可查看所有门店数据,代理商管理名下门店,门店独立运营
|
||
3. **多端覆盖**:管理后台(Web)、收银台(APP/小程序),后续扩展收银机、PC 端
|
||
4. **灵活计费模式**:支持按时计费、包时段套餐、按局/圈等混合计费方式
|
||
5. **复杂结算场景**:预付款/后付款、小程序下单、小商品分离结算
|
||
6. **预留扩展能力**:会员钱包、优惠券/团购券、支付通道、第三方平台对接、智能设备控制
|
||
|
||
---
|
||
|
||
## 二、详细设计
|
||
|
||
### 2.1 整体架构
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ 前端层 │
|
||
├──────────────┬──────────────┬────────────────┬─────────────────┤
|
||
│ 管理后台 │ 收银台 APP │ 顾客小程序 │ 第三方平台 │
|
||
│ (admin-ui) │ (uni-app) │ (独立uni-app) │ (美团等) │
|
||
│ Vue3+Element│ Vue3语法 │ 二期开发 │ 三期对接 │
|
||
└──────────────┴──────────────┴────────────────┴─────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ 网关层 (rui-gateway) │
|
||
│ 路由转发 │ 鉴权 │ 限流 │ 负载均衡 │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ 业务服务层 (app/rui-cashier/) │
|
||
├──────────────┬──────────────┬────────────────┬─────────────────┤
|
||
│ rui-cashier-store│ rui-cashier-order│ rui-cashier-product│ rui-cashier-report │
|
||
│ 门店+包间服务 │ 订单服务 │ 商品服务 │ 报表服务 │
|
||
│ │ │ │ │
|
||
│ • 组织架构 │ • 开台/结账 │ • 商品档案 │ • 营业日报 │
|
||
│ • 门店管理 │ • 计费规则 │ • 服务分类 │ • 数据统计 │
|
||
│ • 包间/桌台 │ • 子订单管理 │ • 定价管理 │ • 趋势分析 │
|
||
│ • 套餐策略 │ • 退款处理 │ │ │
|
||
│ • 设备管理 │ │ │ │
|
||
└──────────────┴──────────────┴────────────────┴─────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ 基础设施层 │
|
||
│ MySQL 8.0 │ Redis │ Nacos │ MQ(RabbitMQ) │ Seata │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 2.2 服务职责划分
|
||
|
||
#### rui-cashier-store(门店+包间服务)
|
||
|
||
**职责**:组织架构、门店管理、包间/桌台管理、套餐策略、设备管理
|
||
|
||
**核心实体**:
|
||
- `Store`(门店):基本信息、所属代理商、营业状态、配置
|
||
- `StoreConfig`(门店配置):预付款/后付款、余额支付商品开关等
|
||
- `Agent`(代理商):基本信息、管理的门店列表
|
||
- `RoomType`(包间类型):名称、容纳人数
|
||
- `Room`(包间/桌台):所属门店、类型、状态、设备绑定
|
||
- `PricingStrategy`(定价策略):包间类型关联的套餐集合
|
||
- `PricingPackage`(套餐):具体的价格套餐,支持时段/日期限制
|
||
- `Device`(设备):网关、门锁、电源、音箱、打印机、锁球器等
|
||
|
||
**套餐策略设计**(核心变更):
|
||
|
||
```java
|
||
// 计费方式枚举
|
||
public enum BillingType {
|
||
HOURLY(1, "按时计费"), // 按小时计费,可设最低消费时长
|
||
FIXED_PERIOD(2, "包时段"), // 固定时段买断,如包下午场
|
||
PER_GAME(3, "按局计费"), // 按局/圈计费
|
||
MIXED(4, "混合模式"); // 组合计费
|
||
}
|
||
|
||
// 定价策略(一个包间类型对应一个策略,包含多条套餐)
|
||
@Data
|
||
public class PricingStrategy {
|
||
private Long id;
|
||
private Long roomTypeId; // 包间类型ID
|
||
private String strategyName; // 策略名称,如"标准计费"
|
||
private Integer status; // 状态:0-禁用 1-启用
|
||
}
|
||
|
||
// 套餐(策略中的具体套餐项)
|
||
@Data
|
||
public class PricingPackage {
|
||
private Long id;
|
||
private Long strategyId; // 所属策略ID
|
||
private String packageName; // 套餐名称,如"3小时套餐"
|
||
private Integer billingType; // 计费方式
|
||
private BigDecimal price; // 套餐价格
|
||
private Integer duration; // 时长(分钟),包时段时有效
|
||
private Integer sort; // 排序,第一条是默认/fallback
|
||
|
||
// 限制条件(JSON格式)
|
||
private String restrictions; // {
|
||
// "weekdays": [1,2,3,4,5], // 工作日可用
|
||
// "weekends": [6,7], // 周末可用
|
||
// "timeRanges": [ // 时段范围
|
||
// {"start": "08:00", "end": "12:00"}
|
||
// ],
|
||
// "holidays": { // 节假日设置
|
||
// "mode": "EXCLUDE", // EXCLUDE-不可用 INCLUDE-仅可用
|
||
// "dates": ["2026-10-01", "2026-10-02"]
|
||
// }
|
||
// }
|
||
|
||
private Integer isDefault; // 是否默认套餐(1-是 0-否),默认套餐不可配置限制条件
|
||
private Integer status; // 状态:0-禁用 1-启用
|
||
}
|
||
```
|
||
|
||
**套餐匹配逻辑**:
|
||
|
||
```java
|
||
public PricingPackage matchPackage(Long roomTypeId, LocalDateTime startTime) {
|
||
// 1. 获取包间类型的定价策略
|
||
PricingStrategy strategy = strategyService.getByRoomTypeId(roomTypeId);
|
||
|
||
// 2. 获取策略下的所有套餐,按 sort 排序
|
||
List<PricingPackage> packages = packageService.getByStrategyId(strategy.getId());
|
||
|
||
// 3. 依次匹配套餐限制条件
|
||
for (PricingPackage pkg : packages) {
|
||
if (pkg.getIsDefault() == 1) {
|
||
continue; // 默认套餐跳过,作为fallback
|
||
}
|
||
if (matchRestrictions(pkg.getRestrictions(), startTime)) {
|
||
return pkg; // 找到匹配的套餐
|
||
}
|
||
}
|
||
|
||
// 4. 没有匹配的,返回默认套餐(第一条)
|
||
return packages.stream()
|
||
.filter(p -> p.getIsDefault() == 1)
|
||
.findFirst()
|
||
.orElseThrow(() -> new BizException("无可用套餐"));
|
||
}
|
||
```
|
||
|
||
**包间状态机**:
|
||
|
||
```
|
||
空闲 ──[开台]──► 使用中 ──[结账]──► 待清洁 ──[清洁完成]──► 空闲
|
||
▲ │ │
|
||
│ │ [挂单] │
|
||
│ ▼ │
|
||
│ 已挂单 ──[恢复]───────────────────┘
|
||
│ │
|
||
│ │ [预约](二期)
|
||
│ ▼
|
||
│ 已预约 ──[开台]──► 使用中
|
||
│
|
||
└──[取消预约]─── 已预约
|
||
```
|
||
|
||
#### rui-cashier-order(订单服务)
|
||
|
||
**职责**:开台、计费计算、结账、退款、订单生命周期管理
|
||
|
||
**核心实体**:
|
||
- `Order`(主订单):订单整体信息
|
||
- `RoomSubOrder`(包间子订单):包间消费、计时计费
|
||
- `ProductSubOrder`(商品子订单):小商品消费
|
||
- `OrderTimeline`(订单时间线):开台、结账等关键时间点
|
||
|
||
**订单体系设计**(核心变更):
|
||
|
||
```java
|
||
// 主订单
|
||
@Data
|
||
public class Order {
|
||
private Long id;
|
||
private String orderNo; // 订单编号
|
||
private Long storeId; // 门店ID
|
||
private Long roomId; // 包间ID(包间订单时)
|
||
private Integer orderType; // 订单类型:1-包间订单 2-纯商品订单
|
||
private String customerName; // 顾客姓名
|
||
private String customerPhone; // 顾客电话
|
||
|
||
// 金额汇总
|
||
private BigDecimal roomAmount; // 包间费用
|
||
private BigDecimal productAmount; // 商品费用
|
||
private BigDecimal discountAmount;// 优惠金额
|
||
private BigDecimal totalAmount; // 订单总金额
|
||
private BigDecimal payAmount; // 实付金额
|
||
|
||
// 支付信息
|
||
private Integer payStatus; // 支付状态:0-未支付 1-部分支付 2-已支付
|
||
private Integer payType; // 支付方式
|
||
private LocalDateTime payTime; // 支付时间
|
||
|
||
// 状态
|
||
private Integer status; // 订单状态
|
||
private String remark; // 备注
|
||
private Long cashierId; // 收银员ID
|
||
}
|
||
|
||
// 包间子订单
|
||
@Data
|
||
public class RoomSubOrder {
|
||
private Long id;
|
||
private Long orderId; // 主订单ID
|
||
private Long roomId; // 包间ID
|
||
private Long packageId; // 使用的套餐ID
|
||
private Integer billingType; // 计费方式
|
||
private BigDecimal price; // 套餐价格/单价
|
||
private LocalDateTime startTime; // 开台时间
|
||
private LocalDateTime endTime; // 结账时间
|
||
private Integer duration; // 使用时长(分钟)
|
||
private Integer gameCount; // 局数
|
||
private BigDecimal amount; // 包间费用
|
||
private Integer status; // 状态
|
||
}
|
||
|
||
// 商品子订单
|
||
@Data
|
||
public class ProductSubOrder {
|
||
private Long id;
|
||
private Long orderId; // 主订单ID
|
||
private Long productId; // 商品ID
|
||
private String productName; // 商品名称
|
||
private BigDecimal productPrice; // 商品单价
|
||
private Integer quantity; // 数量
|
||
private BigDecimal amount; // 小计金额
|
||
private Integer payStatus; // 支付状态(单独控制)
|
||
private Integer source; // 来源:1-收银台 2-顾客小程序
|
||
private LocalDateTime createTime; // 创建时间
|
||
}
|
||
```
|
||
|
||
**结算场景支持**:
|
||
|
||
```java
|
||
// 门店配置
|
||
@Data
|
||
public class StoreConfig {
|
||
private Long storeId;
|
||
private Integer productPayMode; // 商品支付模式:1-先付款 2-后付款
|
||
private Integer balancePayProduct;// 余额是否可支付商品:0-否 1-是
|
||
private Integer notifyOnOrder; // 下单是否通知:0-否 1-是(喇叭+打印)
|
||
}
|
||
|
||
// 结算逻辑
|
||
public void checkout(Long orderId) {
|
||
Order order = orderService.getById(orderId);
|
||
StoreConfig config = storeService.getConfig(order.getStoreId());
|
||
|
||
// 1. 计算包间费用
|
||
RoomSubOrder roomOrder = roomSubOrderService.getByOrderId(orderId);
|
||
BigDecimal roomAmount = calculateRoomAmount(roomOrder);
|
||
|
||
// 2. 计算商品费用
|
||
List<ProductSubOrder> products = productSubOrderService.getByOrderId(orderId);
|
||
BigDecimal productAmount = products.stream()
|
||
.map(ProductSubOrder::getAmount)
|
||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||
|
||
// 3. 计算优惠(预留)
|
||
BigDecimal discountAmount = discountService.calculate(orderId);
|
||
|
||
// 4. 计算应付金额
|
||
BigDecimal totalAmount = roomAmount.add(productAmount).subtract(discountAmount);
|
||
|
||
// 5. 如果商品是先付款模式,商品费用已从实付中扣除
|
||
if (config.getProductPayMode() == 1) {
|
||
BigDecimal paidProductAmount = products.stream()
|
||
.filter(p -> p.getPayStatus() == 2)
|
||
.map(ProductSubOrder::getAmount)
|
||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||
totalAmount = totalAmount.subtract(paidProductAmount);
|
||
}
|
||
|
||
// 6. 更新订单
|
||
order.setRoomAmount(roomAmount);
|
||
order.setProductAmount(productAmount);
|
||
order.setDiscountAmount(discountAmount);
|
||
order.setTotalAmount(totalAmount);
|
||
order.setStatus(2); // 待支付
|
||
orderService.update(order);
|
||
}
|
||
```
|
||
|
||
**开台流程**(支持小程序预下单):
|
||
|
||
```
|
||
场景1:收银台直接开台
|
||
1. 收银员选择包间 → 检查包间状态"空闲"
|
||
2. 选择套餐(系统自动匹配当前时段可用套餐)
|
||
3. 确认顾客信息
|
||
4. 创建主订单 + 包间子订单
|
||
5. 包间状态变更为"使用中"
|
||
|
||
场景2:顾客小程序预订包间
|
||
1. 顾客选择门店、包间类型、时间段
|
||
2. 系统匹配可用套餐,显示价格
|
||
3. 顾客支付包间费用(预付款)
|
||
4. 创建主订单 + 包间子订单(状态:已支付)
|
||
5. 顾客到店后,收银员确认开台,包间状态变更为"使用中"
|
||
|
||
场景3:顾客小程序购买小商品
|
||
1. 顾客扫描包间二维码
|
||
2. 浏览商品,下单
|
||
3. 如果门店配置"先付款":在线支付 → 创建商品子订单
|
||
4. 如果门店配置"后付款":创建商品子订单(未支付)
|
||
5. 触发智能喇叭通知、打印小票(如配置)
|
||
6. 后付款的商品可在收银台统一结算
|
||
```
|
||
|
||
#### rui-cashier-product(商品服务)
|
||
|
||
**职责**:商品/服务档案管理、分类管理、价格管理
|
||
|
||
**核心实体**:
|
||
- `Product`(商品/服务):名称、分类、价格、状态
|
||
- `ProductCategory`(分类):名称、层级、排序
|
||
- `StoreProduct`(门店商品):门店可售商品及自定义价格
|
||
|
||
**设计要点**:
|
||
- 商品分为"普通商品"(饮料、零食)和"服务商品"(加时、换桌等)
|
||
- 支持总部统一配置,门店可自定义价格和上下架
|
||
|
||
#### rui-cashier-report(报表服务)
|
||
|
||
**职责**:营业数据统计、报表生成、数据看板
|
||
|
||
**核心功能**:
|
||
- 营业日报:按门店、按日期统计营业额、订单数、客单价
|
||
- 包间利用率:各包间使用时长/空闲时长占比
|
||
- 时段分析:高峰时段、低谷时段统计
|
||
- 代理商汇总:名下门店汇总数据
|
||
- 商品销售统计:各商品销量、销售额
|
||
|
||
**技术要点**:
|
||
- 报表数据定时从 order 服务同步,避免实时查询拖垮核心服务
|
||
- 支持按门店、代理商、时间维度筛选
|
||
|
||
### 2.3 数据流
|
||
|
||
#### 开台-结账核心流程
|
||
|
||
```
|
||
收银员(APP)/ 顾客(小程序)
|
||
│
|
||
▼
|
||
[选择包间/商品] ──► rui-cashier-store(检查包间状态/商品库存)
|
||
│
|
||
▼
|
||
[确认开台/下单] ──► rui-cashier-order(创建订单)
|
||
│ │
|
||
│ ├─ 创建主订单
|
||
│ ├─ 创建包间子订单(或商品子订单)
|
||
│ ▼
|
||
│ 包间状态变更为"使用中"
|
||
│ │
|
||
▼ ▼
|
||
[追加商品] ──► rui-cashier-product(查询商品)
|
||
│ │
|
||
│ ▼
|
||
│ 创建商品子订单
|
||
│ 触发硬件通知(喇叭+打印,如配置)
|
||
▼
|
||
[结账] ─────► rui-cashier-order(计算费用)
|
||
│ │
|
||
│ ├─ 计算包间费用(按时/套餐)
|
||
│ ├─ 汇总商品费用(扣除已支付的)
|
||
│ ├─ 计算优惠(预留)
|
||
│ ▼
|
||
│ 生成应付金额
|
||
│ │
|
||
▼ ▼
|
||
[支付完成] ──► rui-cashier-order(更新订单状态)
|
||
│ │
|
||
│ ▼
|
||
│ 包间状态变更为"待清洁"
|
||
▼
|
||
[清洁完成] ──► rui-cashier-store(包间状态变更为"空闲")
|
||
```
|
||
|
||
### 2.4 接口设计
|
||
|
||
#### rui-cashier-store 核心接口
|
||
|
||
```yaml
|
||
# 门店管理
|
||
POST /cashier/admin/store # 创建门店
|
||
PUT /cashier/admin/store/{id} # 更新门店
|
||
GET /cashier/admin/store/{id} # 门店详情
|
||
GET /cashier/admin/store/list # 门店列表(按代理商筛选)
|
||
DELETE /cashier/admin/store/{id} # 删除门店
|
||
|
||
# 门店配置
|
||
GET /cashier/admin/store/{id}/config # 获取门店配置
|
||
PUT /cashier/admin/store/{id}/config # 更新门店配置
|
||
|
||
# 包间类型管理
|
||
POST /cashier/admin/room-type # 创建包间类型
|
||
PUT /cashier/admin/room-type/{id} # 更新包间类型
|
||
GET /cashier/admin/room-type/list # 包间类型列表
|
||
|
||
# 包间管理
|
||
POST /cashier/admin/room # 创建包间
|
||
PUT /cashier/admin/room/{id} # 更新包间
|
||
GET /cashier/admin/room/list # 包间列表(按门店筛选)
|
||
GET /cashier/admin/room/{id}/status # 包间实时状态
|
||
|
||
# 定价策略管理
|
||
POST /cashier/admin/pricing-strategy # 创建定价策略
|
||
PUT /cashier/admin/pricing-strategy/{id} # 更新定价策略
|
||
GET /cashier/admin/pricing-strategy/list # 策略列表
|
||
|
||
# 套餐管理
|
||
POST /cashier/admin/pricing-package # 创建套餐
|
||
PUT /cashier/admin/pricing-package/{id} # 更新套餐
|
||
GET /cashier/admin/pricing-package/list # 套餐列表(按策略筛选)
|
||
|
||
# 设备管理
|
||
POST /cashier/admin/device # 注册设备
|
||
PUT /cashier/admin/device/{id} # 更新设备
|
||
GET /cashier/admin/device/list # 设备列表
|
||
POST /cashier/admin/device/{id}/control # 设备控制(预留)
|
||
```
|
||
|
||
#### rui-cashier-order 核心接口
|
||
|
||
```yaml
|
||
# 开台
|
||
POST /cashier/admin/order/open # 开台(创建订单)
|
||
body: {
|
||
"roomId": 1,
|
||
"packageId": 1, # 选择的套餐ID
|
||
"customerName": "张三", // 可选
|
||
"customerPhone": "138...", // 可选
|
||
"remark": "..." // 备注
|
||
}
|
||
|
||
# 追加商品(收银台)
|
||
POST /cashier/admin/order/{id}/product # 追加商品到订单
|
||
body: {
|
||
"productId": 1,
|
||
"quantity": 2,
|
||
"price": 15.00
|
||
}
|
||
|
||
# 顾客小程序下单商品
|
||
POST /cashier/app/order/{id}/product # 顾客下单商品
|
||
body: {
|
||
"productId": 1,
|
||
"quantity": 2,
|
||
"source": 2 // 来源:2-顾客小程序
|
||
}
|
||
|
||
# 结账
|
||
POST /cashier/admin/order/{id}/checkout # 结账
|
||
response: {
|
||
"orderId": 1,
|
||
"roomAmount": 120.00, // 包间费用
|
||
"productAmount": 30.00, // 商品费用(未支付部分)
|
||
"paidProductAmount": 20.00, // 已支付商品金额
|
||
"discountAmount": 0.00, // 优惠金额(预留)
|
||
"totalAmount": 130.00, // 应付金额
|
||
"duration": 120, // 使用时长(分钟)
|
||
"startTime": "2026-06-03T10:00:00",
|
||
"endTime": "2026-06-03T12:00:00"
|
||
}
|
||
|
||
# 确认支付
|
||
POST /cashier/admin/order/{id}/pay # 确认支付(预留支付通道)
|
||
body: {
|
||
"payType": "CASH", // CASH-现金, WECHAT-微信, ALIPAY-支付宝, BALANCE-余额
|
||
"amount": 130.00,
|
||
"remark": "..."
|
||
}
|
||
|
||
# 商品子订单支付(小程序先付款)
|
||
POST /cashier/app/product-order/{id}/pay # 商品子订单支付
|
||
body: {
|
||
"payType": "WECHAT",
|
||
"amount": 20.00
|
||
}
|
||
|
||
# 退款
|
||
POST /cashier/admin/order/{id}/refund # 订单退款
|
||
body: {
|
||
"refundAmount": 130.00,
|
||
"reason": "..."
|
||
}
|
||
|
||
# 订单查询
|
||
GET /cashier/admin/order/{id} # 订单详情
|
||
GET /cashier/admin/order/list # 订单列表(按门店、日期筛选)
|
||
GET /cashier/admin/order/{id}/timeline # 订单时间线
|
||
|
||
# 包间状态操作
|
||
POST /cashier/admin/room/{id}/clean # 清洁完成(包间恢复空闲)
|
||
```
|
||
|
||
### 2.5 数据库设计
|
||
|
||
#### 门店表(rui_cashier_store)
|
||
|
||
```sql
|
||
CREATE TABLE #prefix#cashier_store (
|
||
id BIGINT PRIMARY KEY COMMENT '门店ID',
|
||
agent_id BIGINT NOT NULL COMMENT '所属代理商ID',
|
||
store_name VARCHAR(100) NOT NULL COMMENT '门店名称',
|
||
store_code VARCHAR(50) NOT NULL COMMENT '门店编码',
|
||
contact_name VARCHAR(50) COMMENT '联系人',
|
||
contact_phone VARCHAR(20) COMMENT '联系电话',
|
||
address VARCHAR(200) COMMENT '地址',
|
||
business_hours VARCHAR(50) COMMENT '营业时间',
|
||
status TINYINT DEFAULT 1 COMMENT '状态:0-禁用 1-启用',
|
||
remark VARCHAR(500) COMMENT '备注',
|
||
tenant_id BIGINT DEFAULT 0 COMMENT '租户ID',
|
||
deleted TINYINT DEFAULT 0 COMMENT '删除标志',
|
||
create_by BIGINT COMMENT '创建人',
|
||
create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
update_by BIGINT COMMENT '更新人',
|
||
update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
UNIQUE KEY uk_store_code (store_code),
|
||
KEY idx_agent_id (agent_id)
|
||
) COMMENT='门店表';
|
||
```
|
||
|
||
#### 门店配置表(rui_cashier_store_config)
|
||
|
||
```sql
|
||
CREATE TABLE #prefix#cashier_store_config (
|
||
id BIGINT PRIMARY KEY COMMENT '配置ID',
|
||
store_id BIGINT NOT NULL COMMENT '门店ID',
|
||
config JSON NOT NULL COMMENT '配置内容:{
|
||
\"productPayMode\": 2, // 商品支付模式:1-先付款 2-后付款
|
||
\"balancePayProduct\": 0, // 余额是否可支付商品:0-否 1-是
|
||
\"notifyOnOrder\": 1, // 下单是否通知:0-否 1-是
|
||
\"autoCleanTime\": 10, // 自动清洁时间(分钟)
|
||
\"minDeposit\": 50.00, // 最低押金(可选)
|
||
\"overtimeRule\": { // 超时规则(可选)
|
||
\"type\": 1, // 1-按小时收费 2-按套餐收费
|
||
\"price\": 20.00
|
||
}
|
||
}',
|
||
tenant_id BIGINT DEFAULT 0 COMMENT '租户ID',
|
||
create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
UNIQUE KEY uk_store_id (store_id)
|
||
) COMMENT='门店配置表';
|
||
```
|
||
|
||
#### 包间类型表(rui_cashier_room_type)
|
||
|
||
```sql
|
||
CREATE TABLE #prefix#cashier_room_type (
|
||
id BIGINT PRIMARY KEY COMMENT '类型ID',
|
||
store_id BIGINT NOT NULL COMMENT '所属门店ID',
|
||
type_name VARCHAR(50) NOT NULL COMMENT '类型名称',
|
||
capacity INT DEFAULT 4 COMMENT '容纳人数',
|
||
icon VARCHAR(200) COMMENT '图标',
|
||
sort INT DEFAULT 0 COMMENT '排序',
|
||
status TINYINT DEFAULT 1 COMMENT '状态:0-禁用 1-启用',
|
||
tenant_id BIGINT DEFAULT 0 COMMENT '租户ID',
|
||
deleted TINYINT DEFAULT 0 COMMENT '删除标志',
|
||
create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
KEY idx_store_id (store_id)
|
||
) COMMENT='包间类型表';
|
||
```
|
||
|
||
#### 包间表(rui_cashier_room)
|
||
|
||
```sql
|
||
CREATE TABLE #prefix#cashier_room (
|
||
id BIGINT PRIMARY KEY COMMENT '包间ID',
|
||
store_id BIGINT NOT NULL COMMENT '所属门店ID',
|
||
room_type_id BIGINT NOT NULL COMMENT '包间类型ID',
|
||
room_name VARCHAR(50) NOT NULL COMMENT '包间名称',
|
||
room_no VARCHAR(20) NOT NULL COMMENT '包间编号',
|
||
room_status TINYINT DEFAULT 0 COMMENT '状态:0-空闲 1-使用中 2-待清洁 3-已挂单 4-已预约',
|
||
current_order_id BIGINT COMMENT '当前订单ID',
|
||
device_config JSON COMMENT '设备配置(关联的设备ID列表)',
|
||
sort INT DEFAULT 0 COMMENT '排序',
|
||
enabled TINYINT DEFAULT 1 COMMENT '启用状态:0-禁用 1-启用',
|
||
tenant_id BIGINT DEFAULT 0 COMMENT '租户ID',
|
||
deleted TINYINT DEFAULT 0 COMMENT '删除标志',
|
||
create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
UNIQUE KEY uk_room_no (store_id, room_no),
|
||
KEY idx_store_id (store_id),
|
||
KEY idx_room_status (room_status)
|
||
) COMMENT='包间表';
|
||
```
|
||
|
||
#### 定价策略表(rui_cashier_pricing_strategy)
|
||
|
||
```sql
|
||
CREATE TABLE #prefix#cashier_pricing_strategy (
|
||
id BIGINT PRIMARY KEY COMMENT '策略ID',
|
||
room_type_id BIGINT NOT NULL COMMENT '包间类型ID',
|
||
strategy_name VARCHAR(50) NOT NULL COMMENT '策略名称',
|
||
status TINYINT DEFAULT 1 COMMENT '状态:0-禁用 1-启用',
|
||
tenant_id BIGINT DEFAULT 0 COMMENT '租户ID',
|
||
deleted TINYINT DEFAULT 0 COMMENT '删除标志',
|
||
create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
UNIQUE KEY uk_room_type_id (room_type_id),
|
||
KEY idx_status (status)
|
||
) COMMENT='定价策略表';
|
||
```
|
||
|
||
#### 套餐表(rui_cashier_pricing_package)
|
||
|
||
```sql
|
||
CREATE TABLE #prefix#cashier_pricing_package (
|
||
id BIGINT PRIMARY KEY COMMENT '套餐ID',
|
||
strategy_id BIGINT NOT NULL COMMENT '策略ID',
|
||
package_name VARCHAR(50) NOT NULL COMMENT '套餐名称',
|
||
billing_type TINYINT NOT NULL COMMENT '计费方式:1-按时 2-包时段 3-按局',
|
||
price DECIMAL(19,4) NOT NULL COMMENT '套餐价格',
|
||
duration INT COMMENT '时长(分钟),包时段时有效',
|
||
min_duration INT DEFAULT 60 COMMENT '最低消费时长(分钟),按时计费时有效',
|
||
restrictions JSON COMMENT '限制条件(时段、工作日、节假日)',
|
||
is_default TINYINT DEFAULT 0 COMMENT '是否默认套餐:0-否 1-是',
|
||
sort INT DEFAULT 0 COMMENT '排序',
|
||
status TINYINT DEFAULT 1 COMMENT '状态:0-禁用 1-启用',
|
||
tenant_id BIGINT DEFAULT 0 COMMENT '租户ID',
|
||
deleted TINYINT DEFAULT 0 COMMENT '删除标志',
|
||
create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
KEY idx_strategy_id (strategy_id),
|
||
KEY idx_status (status)
|
||
) COMMENT='套餐表';
|
||
```
|
||
|
||
#### 设备表(rui_cashier_device)
|
||
|
||
```sql
|
||
CREATE TABLE #prefix#cashier_device (
|
||
id BIGINT PRIMARY KEY COMMENT '设备ID',
|
||
store_id BIGINT NOT NULL COMMENT '所属门店ID',
|
||
room_id BIGINT COMMENT '关联包间ID(设备可在公共区域,此时为空)',
|
||
location VARCHAR(100) COMMENT '设备位置:前台、茶水间、大厅等(设备在公共区域时填写)',
|
||
device_name VARCHAR(50) NOT NULL COMMENT '设备名称',
|
||
device_code VARCHAR(50) NOT NULL COMMENT '设备编号(唯一标识)',
|
||
device_type TINYINT NOT NULL COMMENT '设备类型:1-网关 2-门锁 3-电源 4-音箱 5-打印机 6-锁球器',
|
||
parent_id BIGINT COMMENT '父设备ID(门锁/电源等关联网关)',
|
||
online_status TINYINT DEFAULT 0 COMMENT '在线状态:0-离线 1-在线',
|
||
last_heartbeat DATETIME(3) COMMENT '最后心跳时间',
|
||
-- 4G设备信息
|
||
imei VARCHAR(20) COMMENT 'IMEI号(4G设备)',
|
||
sim_card_no VARCHAR(20) COMMENT '流量卡号(4G设备)',
|
||
sim_operator VARCHAR(20) COMMENT '运营商(移动/联通/电信)',
|
||
sim_expire_date DATE COMMENT '流量卡到期日期',
|
||
-- 设备功能配置
|
||
functions JSON COMMENT '设备功能配置:{
|
||
\"speaker\": { // 音箱功能(电源控制器自带音箱时)
|
||
\"enabled\": true,
|
||
\"type\": \"EXTERNAL\", // EXTERNAL-外置 INTERNAL-内置
|
||
\"volume\": 80 // 音量 0-100
|
||
},
|
||
\"power\": { // 电源功能
|
||
\"channels\": 4, // 通道数
|
||
\"channelNames\": [\"照明\", \"空调\", \"插座\", \"备用\"]
|
||
}
|
||
}',
|
||
config JSON COMMENT '扩展配置',
|
||
sort INT DEFAULT 0 COMMENT '排序',
|
||
status TINYINT DEFAULT 1 COMMENT '状态:0-禁用 1-启用',
|
||
tenant_id BIGINT DEFAULT 0 COMMENT '租户ID',
|
||
deleted TINYINT DEFAULT 0 COMMENT '删除标志',
|
||
create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
UNIQUE KEY uk_device_code (device_code),
|
||
KEY idx_store_id (store_id),
|
||
KEY idx_room_id (room_id),
|
||
KEY idx_device_type (device_type),
|
||
KEY idx_imei (imei)
|
||
) COMMENT='设备表';
|
||
```
|
||
|
||
#### 主订单表(rui_cashier_order)
|
||
|
||
```sql
|
||
CREATE TABLE #prefix#cashier_order (
|
||
id BIGINT PRIMARY KEY COMMENT '订单ID',
|
||
order_no VARCHAR(32) NOT NULL COMMENT '订单编号',
|
||
store_id BIGINT NOT NULL COMMENT '门店ID',
|
||
room_id BIGINT COMMENT '包间ID(包间订单时)',
|
||
order_type TINYINT DEFAULT 1 COMMENT '订单类型:1-包间订单 2-纯商品订单',
|
||
customer_name VARCHAR(50) COMMENT '顾客姓名',
|
||
customer_phone VARCHAR(20) COMMENT '顾客电话',
|
||
room_amount DECIMAL(19,4) DEFAULT 0 COMMENT '包间费用',
|
||
product_amount DECIMAL(19,4) DEFAULT 0 COMMENT '商品费用',
|
||
discount_amount DECIMAL(19,4) DEFAULT 0 COMMENT '优惠金额',
|
||
total_amount DECIMAL(19,4) DEFAULT 0 COMMENT '订单总金额',
|
||
pay_amount DECIMAL(19,4) DEFAULT 0 COMMENT '实付金额',
|
||
pay_status TINYINT DEFAULT 0 COMMENT '支付状态:0-未支付 1-部分支付 2-已支付',
|
||
pay_type VARCHAR(20) COMMENT '支付方式:CASH/WECHAT/ALIPAY/BALANCE',
|
||
pay_time DATETIME(3) COMMENT '支付时间',
|
||
status TINYINT DEFAULT 0 COMMENT '状态:0-开台中 1-已挂单 2-待支付 3-已完成 4-已退款',
|
||
remark VARCHAR(500) COMMENT '备注',
|
||
refund_amount DECIMAL(19,4) DEFAULT 0 COMMENT '退款金额',
|
||
refund_reason VARCHAR(500) COMMENT '退款原因',
|
||
refund_time DATETIME(3) COMMENT '退款时间',
|
||
cashier_id BIGINT COMMENT '收银员ID',
|
||
tenant_id BIGINT DEFAULT 0 COMMENT '租户ID',
|
||
deleted TINYINT DEFAULT 0 COMMENT '删除标志',
|
||
create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
UNIQUE KEY uk_order_no (order_no),
|
||
KEY idx_store_id (store_id),
|
||
KEY idx_room_id (room_id),
|
||
KEY idx_status (status),
|
||
KEY idx_create_time (create_time)
|
||
) COMMENT='主订单表';
|
||
```
|
||
|
||
#### 包间子订单表(rui_cashier_room_sub_order)
|
||
|
||
```sql
|
||
CREATE TABLE #prefix#cashier_room_sub_order (
|
||
id BIGINT PRIMARY KEY COMMENT '子订单ID',
|
||
order_id BIGINT NOT NULL COMMENT '主订单ID',
|
||
room_id BIGINT NOT NULL COMMENT '包间ID',
|
||
package_id BIGINT COMMENT '套餐ID',
|
||
billing_type TINYINT NOT NULL COMMENT '计费方式:1-按时 2-包时段 3-按局',
|
||
price DECIMAL(19,4) NOT NULL COMMENT '套餐价格/单价',
|
||
start_time DATETIME(3) COMMENT '开台时间',
|
||
end_time DATETIME(3) COMMENT '结账时间',
|
||
duration INT COMMENT '使用时长(分钟)',
|
||
game_count INT DEFAULT 0 COMMENT '局数',
|
||
amount DECIMAL(19,4) DEFAULT 0 COMMENT '包间费用',
|
||
status TINYINT DEFAULT 0 COMMENT '状态:0-进行中 1-已完成 2-已取消',
|
||
tenant_id BIGINT DEFAULT 0 COMMENT '租户ID',
|
||
deleted TINYINT DEFAULT 0 COMMENT '删除标志',
|
||
create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
UNIQUE KEY uk_order_id (order_id),
|
||
KEY idx_room_id (room_id)
|
||
) COMMENT='包间子订单表';
|
||
```
|
||
|
||
#### 商品子订单表(rui_cashier_product_sub_order)
|
||
|
||
```sql
|
||
CREATE TABLE #prefix#cashier_product_sub_order (
|
||
id BIGINT PRIMARY KEY COMMENT '子订单ID',
|
||
order_id BIGINT NOT NULL COMMENT '主订单ID',
|
||
product_id BIGINT NOT NULL COMMENT '商品ID',
|
||
product_name VARCHAR(100) NOT NULL COMMENT '商品名称',
|
||
product_price DECIMAL(19,4) NOT NULL COMMENT '商品单价',
|
||
quantity INT NOT NULL COMMENT '数量',
|
||
amount DECIMAL(19,4) NOT NULL COMMENT '小计金额',
|
||
pay_status TINYINT DEFAULT 0 COMMENT '支付状态:0-未支付 1-部分支付 2-已支付',
|
||
source TINYINT DEFAULT 1 COMMENT '来源:1-收银台 2-顾客小程序',
|
||
status TINYINT DEFAULT 0 COMMENT '状态:0-待处理 1-已确认 2-已取消',
|
||
tenant_id BIGINT DEFAULT 0 COMMENT '租户ID',
|
||
deleted TINYINT DEFAULT 0 COMMENT '删除标志',
|
||
create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
KEY idx_order_id (order_id),
|
||
KEY idx_product_id (product_id)
|
||
) COMMENT='商品子订单表';
|
||
```
|
||
|
||
#### 商品表(rui_cashier_product)
|
||
|
||
```sql
|
||
CREATE TABLE #prefix#cashier_product (
|
||
id BIGINT PRIMARY KEY COMMENT '商品ID',
|
||
category_id BIGINT COMMENT '分类ID',
|
||
product_name VARCHAR(100) NOT NULL COMMENT '商品名称',
|
||
product_code VARCHAR(50) COMMENT '商品编码',
|
||
product_type TINYINT DEFAULT 1 COMMENT '类型:1-普通商品 2-服务商品',
|
||
unit VARCHAR(20) COMMENT '单位',
|
||
sale_price DECIMAL(19,4) NOT NULL COMMENT '售价',
|
||
cost_price DECIMAL(19,4) COMMENT '成本价',
|
||
status TINYINT DEFAULT 1 COMMENT '状态:0-禁用 1-启用',
|
||
sort INT DEFAULT 0 COMMENT '排序',
|
||
tenant_id BIGINT DEFAULT 0 COMMENT '租户ID',
|
||
deleted TINYINT DEFAULT 0 COMMENT '删除标志',
|
||
create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
KEY idx_category_id (category_id)
|
||
) COMMENT='商品表';
|
||
```
|
||
|
||
### 2.6 错误码设计
|
||
|
||
收银系统错误码区间:**5000-5999**
|
||
|
||
| 错误码 | 含义 | 场景 |
|
||
|--------|------|------|
|
||
| 5000 | 门店不存在 | 操作不存在的门店 |
|
||
| 5001 | 门店已禁用 | 门店状态为禁用 |
|
||
| 5010 | 包间不存在 | 操作不存在的包间 |
|
||
| 5011 | 包间已占用 | 开台时包间不是空闲状态 |
|
||
| 5012 | 包间已禁用 | 包间状态为禁用 |
|
||
| 5020 | 订单不存在 | 操作不存在的订单 |
|
||
| 5021 | 订单状态错误 | 操作与当前状态不符 |
|
||
| 5022 | 订单已支付 | 重复支付 |
|
||
| 5023 | 退款金额超过订单金额 | 退款金额校验失败 |
|
||
| 5030 | 商品不存在 | 添加商品时商品不存在或已下架 |
|
||
| 5040 | 定价策略不存在 | 包间类型没有配置定价策略 |
|
||
| 5041 | 无可用套餐 | 当前时段没有匹配的套餐 |
|
||
| 5050 | 设备不存在 | 操作不存在的设备 |
|
||
| 5051 | 设备离线 | 设备控制时设备离线 |
|
||
| 5060 | 门店配置不存在 | 门店未配置 |
|
||
|
||
---
|
||
|
||
## 三、验收标准
|
||
|
||
### MVP 阶段验收标准
|
||
|
||
- [ ] **门店管理**:可创建、编辑、禁用门店,支持按代理商筛选
|
||
- [ ] **门店配置**:可配置商品支付模式、余额支付开关、下单通知开关
|
||
- [ ] **包间管理**:可创建包间类型和包间,配置设备绑定
|
||
- [ ] **套餐策略**:可创建定价策略,添加多个套餐,支持排序和默认套餐
|
||
- [ ] **开台流程**:收银员可选择空闲包间开台,系统自动匹配当前时段可用套餐
|
||
- [ ] **计费计算**:按时计费正确计算时长和费用,支持最低消费时长
|
||
- [ ] **商品管理**:可添加商品,支持收银台追加到订单
|
||
- [ ] **结账流程**:可正常结账,生成订单,支持预付款/后付款模式
|
||
- [ ] **退款功能**:可对已支付订单进行部分或全额退款
|
||
- [ ] **营业报表**:可查看门店营业日报(营业额、订单数、包间利用率)
|
||
- [ ] **权限控制**:不同角色(总部/代理商/店长/收银员)看到不同数据和功能
|
||
|
||
### 性能标准
|
||
|
||
- [ ] 包间状态查询响应时间 < 200ms
|
||
- [ ] 套餐匹配响应时间 < 300ms
|
||
- [ ] 开台操作响应时间 < 500ms
|
||
- [ ] 结账计算响应时间 < 500ms
|
||
- [ ] 报表查询响应时间 < 2s(支持日期范围筛选)
|
||
|
||
---
|
||
|
||
## 四、风险与依赖
|
||
|
||
| 风险 | 影响 | 缓解措施 |
|
||
|------|------|----------|
|
||
| **多门店数据量大** | 中 | 报表服务独立,定时同步数据;数据库按租户分表 |
|
||
| **套餐策略复杂** | 中 | 策略+套餐两级设计,限制条件JSON化;充分测试边界场景 |
|
||
| **支付 SDK 延迟** | 高 | 先实现现金支付,预留支付接口;等 SDK 就绪后对接 |
|
||
| **uni-app 性能** | 低 | 收银场景简单,无复杂动画;如性能不足可考虑原生小程序 |
|
||
| **智能设备对接** | 高 | 预留设备控制接口;等 IOT 平台就绪后对接;APP 端先集成插件 |
|
||
| **并发开台** | 中 | 包间状态变更加分布式锁;订单号使用雪花算法 |
|
||
| **第三方平台对接** | 中 | 预留开放平台 API;三期按需对接美团等平台 |
|
||
| **子订单分离** | 中 | 商品子订单独立支付状态,需保证数据一致性 |
|
||
|
||
---
|
||
|
||
## 五、预留扩展设计
|
||
|
||
### 5.1 会员钱包预留
|
||
|
||
```sql
|
||
-- 会员钱包表(二期)
|
||
CREATE TABLE #prefix#cashier_member_wallet (
|
||
id BIGINT PRIMARY KEY COMMENT '钱包ID',
|
||
member_id BIGINT NOT NULL COMMENT '会员ID',
|
||
real_balance DECIMAL(19,4) DEFAULT 0 COMMENT '实际金额',
|
||
gift_balance DECIMAL(19,4) DEFAULT 0 COMMENT '赠送金额',
|
||
total_balance DECIMAL(19,4) DEFAULT 0 COMMENT '总余额',
|
||
status TINYINT DEFAULT 1 COMMENT '状态',
|
||
tenant_id BIGINT DEFAULT 0 COMMENT '租户ID',
|
||
create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
UNIQUE KEY uk_member_id (member_id)
|
||
) COMMENT='会员钱包表';
|
||
|
||
-- 钱包流水表(二期)
|
||
CREATE TABLE #prefix#cashier_wallet_transaction (
|
||
id BIGINT PRIMARY KEY COMMENT '流水ID',
|
||
wallet_id BIGINT NOT NULL COMMENT '钱包ID',
|
||
transaction_type TINYINT NOT NULL COMMENT '类型:1-充值 2-消费 3-退款',
|
||
amount DECIMAL(19,4) NOT NULL COMMENT '金额',
|
||
real_amount DECIMAL(19,4) COMMENT '实际金额变动',
|
||
gift_amount DECIMAL(19,4) COMMENT '赠送金额变动',
|
||
order_no VARCHAR(32) COMMENT '关联订单号',
|
||
remark VARCHAR(500) COMMENT '备注',
|
||
tenant_id BIGINT DEFAULT 0 COMMENT '租户ID',
|
||
create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
KEY idx_wallet_id (wallet_id)
|
||
) COMMENT='钱包流水表';
|
||
```
|
||
|
||
```java
|
||
// 余额支付接口(预留)
|
||
public interface BalancePaymentService {
|
||
// 检查余额是否足够
|
||
boolean checkBalance(Long memberId, BigDecimal amount);
|
||
|
||
// 扣款(先扣赠送金额,再扣实际金额)
|
||
PaymentResult deduct(Long memberId, BigDecimal amount, String orderNo);
|
||
|
||
// 退款(退回实际金额)
|
||
PaymentResult refund(Long memberId, BigDecimal amount, String orderNo);
|
||
}
|
||
|
||
// 门店配置余额支付范围
|
||
// StoreConfig.balance_pay_product:0-余额不可支付商品 1-余额可支付商品
|
||
```
|
||
|
||
### 5.2 优惠券/团购券预留
|
||
|
||
```sql
|
||
-- 优惠券表(二期)
|
||
CREATE TABLE #prefix#cashier_coupon (
|
||
id BIGINT PRIMARY KEY COMMENT '优惠券ID',
|
||
coupon_name VARCHAR(100) NOT NULL COMMENT '优惠券名称',
|
||
coupon_type TINYINT NOT NULL COMMENT '类型:1-满减 2-折扣 3-立减',
|
||
face_value DECIMAL(19,4) NOT NULL COMMENT '面值',
|
||
min_amount DECIMAL(19,4) DEFAULT 0 COMMENT '最低消费金额',
|
||
valid_days INT COMMENT '有效天数',
|
||
status TINYINT DEFAULT 1 COMMENT '状态',
|
||
tenant_id BIGINT DEFAULT 0 COMMENT '租户ID',
|
||
create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
update_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间'
|
||
) COMMENT='优惠券表';
|
||
|
||
-- 第三方团购券表(二期)
|
||
CREATE TABLE #prefix#cashier_third_party_voucher (
|
||
id BIGINT PRIMARY KEY COMMENT '券ID',
|
||
platform VARCHAR(20) NOT NULL COMMENT '平台:MEITUAN/DIANPING',
|
||
voucher_code VARCHAR(50) NOT NULL COMMENT '券码',
|
||
voucher_name VARCHAR(100) COMMENT '券名称',
|
||
face_value DECIMAL(19,4) NOT NULL COMMENT '面值',
|
||
status TINYINT DEFAULT 0 COMMENT '状态:0-未使用 1-已使用 2-已过期',
|
||
use_time DATETIME(3) COMMENT '使用时间',
|
||
order_no VARCHAR(32) COMMENT '关联订单号',
|
||
tenant_id BIGINT DEFAULT 0 COMMENT '租户ID',
|
||
create_time DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
UNIQUE KEY uk_voucher_code (voucher_code)
|
||
) COMMENT='第三方团购券表';
|
||
```
|
||
|
||
```java
|
||
// 优惠计算接口(预留)
|
||
public interface DiscountService {
|
||
// 计算订单可使用的优惠
|
||
List<DiscountVO> calculateAvailableDiscounts(Long orderId, Long memberId);
|
||
|
||
// 应用优惠
|
||
DiscountResult applyDiscount(Long orderId, List<Long> couponIds, List<String> voucherCodes);
|
||
|
||
// 核销团购券
|
||
VoucherResult verifyVoucher(String voucherCode);
|
||
}
|
||
```
|
||
|
||
### 5.3 支付通道预留
|
||
|
||
```java
|
||
// 支付接口(预留)
|
||
public interface PaymentService {
|
||
// 发起支付
|
||
PaymentResult pay(Long orderId, String payType, BigDecimal amount);
|
||
|
||
// 查询支付状态
|
||
PaymentStatus queryStatus(String payOrderNo);
|
||
|
||
// 退款
|
||
RefundResult refund(Long orderId, BigDecimal amount, String reason);
|
||
}
|
||
|
||
// 当前实现:现金支付
|
||
@Component
|
||
public class CashPaymentService implements PaymentService {
|
||
// 仅记录支付流水,不调用第三方
|
||
}
|
||
|
||
// 后续扩展:微信支付、支付宝、余额支付等
|
||
@Component
|
||
public class WechatPaymentService implements PaymentService {
|
||
// 对接支付平台 SDK
|
||
}
|
||
```
|
||
|
||
### 5.4 第三方平台对接预留
|
||
|
||
```java
|
||
// 开放平台接口(预留)
|
||
@RestController
|
||
@RequestMapping("/cashier/open")
|
||
public class OpenPlatformController {
|
||
|
||
// 查询包间可用性
|
||
@GetMapping("/room/availability")
|
||
public Result<List<RoomAvailabilityVO>> queryAvailability(
|
||
@RequestParam Long storeId,
|
||
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startTime,
|
||
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endTime) {
|
||
// 返回各包间在指定时段的可用状态
|
||
}
|
||
|
||
// 查询套餐价格
|
||
@GetMapping("/room/{roomTypeId}/packages")
|
||
public Result<List<PackageVO>> queryPackages(
|
||
@PathVariable Long roomTypeId,
|
||
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startTime) {
|
||
// 返回当前时段可用套餐
|
||
}
|
||
|
||
// 第三方下单
|
||
@PostMapping("/order/create")
|
||
public Result<OrderVO> createOrder(@RequestBody @Valid OpenOrderDTO dto) {
|
||
// 创建订单,返回订单信息
|
||
}
|
||
|
||
// 订单状态同步
|
||
@GetMapping("/order/{orderNo}/status")
|
||
public Result<OrderStatusVO> queryStatus(@PathVariable String orderNo) {
|
||
// 返回订单当前状态
|
||
}
|
||
|
||
// 退款
|
||
@PostMapping("/order/{orderNo}/refund")
|
||
public Result<RefundVO> refund(@PathVariable String orderNo, @RequestBody RefundDTO dto) {
|
||
// 处理退款
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5.5 智能设备控制预留
|
||
|
||
```java
|
||
// 设备控制服务(预留)
|
||
public interface DeviceControlService {
|
||
// 开锁
|
||
Result<Void> unlock(Long roomId);
|
||
|
||
// 关锁
|
||
Result<Void> lock(Long roomId);
|
||
|
||
// 通电
|
||
Result<Void> powerOn(Long roomId);
|
||
|
||
// 断电
|
||
Result<Void> powerOff(Long roomId);
|
||
|
||
// 语音播报
|
||
Result<Void> playVoice(Long roomId, String content);
|
||
|
||
// 打印小票
|
||
Result<Void> printTicket(Long roomId, String content);
|
||
}
|
||
|
||
// 当前实现:空实现(记录日志)
|
||
@Component
|
||
public class DummyDeviceControlService implements DeviceControlService {
|
||
// 仅记录操作日志,等 IOT 平台对接后替换
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 六、模块结构
|
||
|
||
```
|
||
app/rui-cashier/
|
||
├── pom.xml # 聚合 POM
|
||
├── rui-cashier-store/ # 门店+包间服务
|
||
│ ├── rui-cashier-store-common/ # DTO、枚举、常量
|
||
│ ├── rui-cashier-store-core/ # Entity、Mapper、Service
|
||
│ └── rui-cashier-store-api/ # REST API
|
||
├── rui-cashier-order/ # 订单服务
|
||
│ ├── rui-cashier-order-common/
|
||
│ ├── rui-cashier-order-core/
|
||
│ └── rui-cashier-order-api/
|
||
├── rui-cashier-product/ # 商品服务
|
||
│ ├── rui-cashier-product-common/
|
||
│ ├── rui-cashier-product-core/
|
||
│ └── rui-cashier-product-api/
|
||
└── rui-cashier-report/ # 报表服务
|
||
├── rui-cashier-report-common/
|
||
├── rui-cashier-report-core/
|
||
└── rui-cashier-report-api/
|
||
```
|
||
|
||
---
|
||
|
||
## 七、实施阶段规划
|
||
|
||
### 阶段一:MVP(6-8 周)
|
||
- 搭建项目结构
|
||
- 实现 rui-cashier-store(门店+包间+套餐策略+设备管理)
|
||
- 实现 rui-cashier-order(开台、计费、结账、退款、子订单)
|
||
- 实现 rui-cashier-product(商品管理)
|
||
- 实现基础报表
|
||
- 开发管理后台页面(admin-ui)
|
||
- 开发收银台 APP(uni-app)
|
||
|
||
### 阶段二:会员+营销+顾客小程序(4-6 周)
|
||
- 会员系统(注册、积分、储值)
|
||
- 会员钱包(实际金额+赠送金额)
|
||
- 优惠券、营销活动
|
||
- 顾客小程序(预约、扫码开台、在线支付)
|
||
|
||
### 阶段三:生态对接(4-6 周)
|
||
- 支付通道对接(微信、支付宝、余额)
|
||
- 第三方平台对接(美团等)
|
||
- 第三方团购券对接
|
||
- IOT 设备对接(通过 IOT 平台)
|
||
- 收银机/PC 端开发
|
||
|
||
---
|
||
|
||
*文档结束*
|