门店收银 POS 离线工作设计文档(支持线上线下一体化)
- 📘 背景与目标
在门店运营中,POS 端(收银机/安卓终端)经常会遇到以下情况:
• 网络中断(Wi-Fi、4G、服务器不可达);
• 临时维护或总部系统升级;
• 云端数据同步延迟。
因此,系统必须支持 离线工作模式(Offline Mode),保证收银业务不中断,并在网络恢复后实现数据自动同步与校验。
目标
目标
描述
✅ 离线可用
断网时仍能销售、挂单、打印、收款
✅ 数据安全
所有离线交易加密存储本地
✅ 自动同步
网络恢复后自动上传销售单、更新库存
✅ 差异对账
离线与云端自动校验、冲突检测
✅ 快速响应
商品、会员、价格从本地缓存读取
- 🧠 总体架构设计
2.1 架构图(简化)
┌───────────────┐ ┌───────────────┐
│ 云端服务端 │ ←Kafka→ │ 消息中间件 │
│ (Spring Boot) │ │ (Redis / MQ) │
└───────────────┘ └───────────────┘
↑ ↑
│HTTP/API │Push
│ │
┌────────────────────────────┐
│ POS 端离线缓存引擎 (WPF/Android) │
│ - SQLite本地数据库 │
│ - 数据版本号控制 │
│ - 本地消息队列(未同步订单) │
└────────────────────────────┘
2.2 数据同步机制
模块
数据流方向
同步方式
商品、会员、价格
云端 → POS
增量拉取 + WebSocket 推送
库存变动
双向
Kafka 消息同步
订单
POS → 云端
离线缓存后自动上报
交接班记录
POS → 云端
上传并锁定
打印模板
云端 → POS
手动或定时拉取
- 💾 本地缓存设计(SQLite)
离线POS端通过内嵌SQLite存储关键数据表:
表名
描述
local_member
会员缓存(member_id、姓名、手机号、余额、积分、等级)
local_product
商品信息(sku_code、名称、价格、库存、本地版本号)
local_price
门店价格与会员价、阶梯价
local_order
本地订单主表(含未同步标志)
local_order_item
本地订单明细
local_stock
本地库存缓存
local_version
各模块版本号对照表
sync_log
同步任务记录与状态(PENDING / SYNCED / FAILED)
- 🔁 数据同步策略
4.1 版本号控制机制
每类数据(商品、会员、价格、库存)均维护一个版本号字段。
字段
说明
version_id
自增版本号(云端维护)
last_sync_version
POS 端上次同步版本
change_flag
记录数据是否变动
同步逻辑示例:
SELECT * FROM product WHERE version_id > @last_sync_version;
UPDATE local_version SET last_sync_version = @max_version;
4.2 离线订单同步流程
- POS 在离线状态下创建订单:
INSERT INTO local_order (order_code, member_id, total_amount, sync_status)
VALUES ('POS20251017001', 1001, 89.50, 'PENDING'); - 网络恢复 → 启动同步任务:
◦ 批量上传订单到云端 API /api/orders/offlineSync
◦ 云端落表并返回成功状态 - POS 更新状态:
UPDATE local_order SET sync_status='SYNCED' WHERE order_code='POS20251017001';
⚠️ 若同步失败 → 写入 sync_log 记录错误原因并重试。
4.3 数据冲突处理策略
场景
策略
同一会员离线充值+线上消费
优先云端交易,POS冲正
离线销售库存与线上库存冲突
按时间先后顺序补差
同步时商品被下架
自动标记订单为异常待审核
网络恢复后部分明细上传失败
自动重传三次并记录日志
- 🔐 数据安全设计
5.1 本地加密
• 离线SQLite文件加密(AES-256)。
• 离线订单敏感字段(手机号、金额)二次加密存储。
• 启动时需POS授权码校验。
5.2 安全机制
项目
措施
用户登录
Token缓存(断网可使用本地令牌)
本地数据
AES 加密 + 文件锁
同步接口
HTTPS + 签名校验
数据追踪
所有订单、同步记录带签名校验值(MD5/签名字段)
- 📲 离线POS前端逻辑结构
[本地缓存管理器]
├── 数据加载器(DataLoader)
│ ├── 从云端同步 → SQLite
│ └── 定期校验版本号
├── 订单缓存器(OrderBuffer)
│ ├── 离线销售单存储
│ ├── 恢复后批量上传
├── 同步管理器(SyncManager)
│ ├── 自动定时任务
│ └── 异常记录与重试
├── 网络检测器(NetWatcher)
│ ├── 监听网络状态
│ └── 启动同步
- ⚙️ 同步任务调度逻辑(伪代码)
if (NetworkUtils.isConnected()) {
ListunsyncedOrders = localDb.getOrdersByStatus("PENDING");
for (Order order : unsyncedOrders) {
boolean result = api.upload(order);
if (result) localDb.updateOrderStatus(order.getId(), "SYNCED");
else localDb.logSyncFailure(order);
}
}
- 📊 离线状态提示与操作限制
功能
离线状态下
恢复后
开单收银
✅ 支持
✅ 同步
挂单取单
✅ 支持本机挂单
✅ 云端同步
会员余额支付
⚠️ 限当前缓存余额
✅ 云端验证
积分消费
⚠️ 暂不允许
✅ 可同步
价格更新
❌ 暂停自动更新
✅ 恢复后自动刷新
打印小票
✅ 可离线打印
✅ 云端归档
交接班
✅ 本地统计
✅ 上报结算数据
- 🧾 同步日志表结构(SQLite)
CREATE TABLE sync_log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
entity_type TEXT NOT NULL, -- 'ORDER','MEMBER','STOCK'
entity_id TEXT,
sync_status TEXT DEFAULT 'PENDING',
last_try_time DATETIME,
error_message TEXT
);
- ✅ 网络恢复后任务顺序
- 上传未同步订单(local_order → order_h)
- 上传交接班数据
- 同步库存、会员余额、积分状态
- 拉取商品与价格更新
- 更新本地版本号表
- 清理成功同步的本地缓存数据
- 💡 优化建议
模块
优化方向
同步模块
引入批量事务与压缩传输(gzip/json batch)
订单号生成
离线采用「本机号 + 时间戳」避免冲突
安全性
本地离线文件每日自动备份(USB/云)
可视化
POS端提供「离线模式」明显标识与状态条
差异日志
支持对账页面查看云端与本地差异记录
- 🔍 小结
功能
支持离线
同步方向
商品查询
✅
云 → POS
价格查询
✅
云 → POS
下单销售
✅
POS → 云
会员识别
✅(缓存匹配)
双向
积分、余额
⚠️ 部分
POS缓存
打印功能
✅
本地
库存同步
✅
双向(冲突检测)
数据加密
✅
本地AES
异常恢复
✅
自动补偿机制