410 SCAN CONTINUITY · REVIEW

410 型优卡特称重台扫码中断双层订单保护方案

Markdown 同步浏览版 · 更新日期:2026-09-10

项目:ZhctWeightingTableYoukate(410 型优卡特称重台)
沉淀日期:2026-09-10
文档状态:方案汇总,待产品、客户端、服务端、硬件和测试共同评审
实施状态:当前仅部分具备基础能力,双层方案尚未完整实现
评审责任人:待指定

一、结论

针对扫码头偶发短暂断码导致同一次取餐被拆成多笔订单的问题,建议采用两层保护:

  1. **前置防抖:900~1200ms 内不结束订单。**APK 收到空码后进入“疑似断码”状态,在宽限期内保持当前取餐会话;同一餐盘码恢复时继续原订单,只有持续空码超过宽限期才确认离盘。
  2. **后置纠错:2 分钟断连订单识别与合并。**如果前置防抖仍未拦住,服务端对同设备、同餐盘、同用户、同计重菜品的连续异常明细进行候选检测,满足全部规则后作废重复明细,并按秤体实际重量差生成一条纠正明细。

两层方案不是二选一:前置防抖是主防线,目标是避免错误订单产生;后置纠错是兜底,目标是修复已经产生的异常明细。红外逐步关闭属于硬件策略灰度验证,不能替代任一订单保护机制。

二、问题背景与数据链路

现有会议资料中的硬件口径为:扫码头约每 300ms 产生一次真实扫码结果,香山控制板可能把同一结果按 100ms × 3 或 50ms × 6 重复发送给 APK。这里的每一个 APK 回调不一定代表一次新的真实扫描。

扫码头真实扫描(约 300ms/次)
          ↓
控制板缓存同一结果
          ↓
按 100ms×3 或 50ms×6 重复组成复合包
          ↓
DeviceSDK 解析扫码字段和称重字段
          ↓
APK 根据有效码/空码判断取餐开始、继续或结束
          ↓
本地保存取餐记录并上传服务端

如果 APK 把重复上报的空码包当成多次独立扫码失败,就可能过早结束当前订单;同一餐盘随后重新被识别时,又会开始一笔新订单,形成断连拆单甚至重复计费。

三、方案一:900~1200ms 扫码断码宽限

3.1 目标

3.2 推荐状态机

无订单
  │ 收到有效餐盘码
  ▼
取餐进行中
  │ 首次收到空码
  ▼
疑似断码(保持订单,不结算)
  ├─ 宽限期内恢复同一餐盘码 → 回到取餐进行中
  ├─ 宽限期内出现不同餐盘码 → 进入冲突分支,按待确认规则处理
  └─ 持续空码达到宽限时间   → 确认离盘,只结束一次订单

3.3 判定规则

  1. 收到合法餐盘码时,记录最后一次有效餐盘码和单调时钟时间。
  2. 首次收到空码时,只标记“疑似断码”,不得立刻清空当前订单状态。
  3. 使用单调时钟计算断码持续时间,避免系统时间被校准后影响判断。
  4. 宽限期内恢复同一餐盘码时:
    • 清除疑似断码状态;
    • 保留原取餐起始重量、用户、菜品和会话标识;
    • 不上传、不结算、不生成新明细。
  5. 空码持续达到配置值时,才确认离盘并触发一次订单结束。
  6. 同一轮离盘确认必须具备幂等保护,避免多个延迟任务重复结束订单。

3.4 900ms 与 1200ms 的含义

宽限值 对应约 300ms 真实扫描周期 优点 代价
900ms 约 3 个周期 真离盘后的页面恢复和结算更快 对较长断码的容忍度较低
1200ms 约 4 个周期 更能降低偶发断码拆单 真离盘后多等待约 300ms

不建议仅把“空码次数”机械设置为 9 或 12 来替代时间判断,因为 APK 回调频率可配置,控制板还可能重复同一次真实扫描结果。最终默认值应通过 900ms、1200ms 两档真机数据比较后确定。

3.5 当前项目状态

当前源码已经具备连续空码次数确认,但还不是独立的时间窗口:

结论:方案一当前为部分实现,需要从“次数判断”升级为“时间判断”,并补充同一餐盘恢复、不同餐盘冲突和幂等结束规则。

3.6 红外逐步关闭策略

扫码头灵敏度和识读距离增强后,可以评估减少红外依赖,但建议按设备或餐线灰度:

  1. 选择一台设备或一条餐线关闭红外。
  2. 记录设备编号、APK 版本、控制板版本、操作时间和回退方式。
  3. 对比关闭前后的扫码成功率、短暂断码率、误拆单率、真离盘延迟、重启/休眠异常。
  4. 指标无恶化且连续运行达到约定周期后,再扩大范围。
  5. 出现扫码下降、订单拆分或无法确认硬件状态时立即恢复红外。

红外灰度必须保留人工回退;在设备未提供状态回读前,不能只根据 APK 的“命令已发送”认定红外已经关闭。

四、方案二:2 分钟断连订单过滤与纠错

4.1 目标

当前置防抖未拦截成功、同一次取餐已经形成多条订单明细时,识别高度疑似的断连拆单,并把计费结果纠正为秤体实际取餐重量。

该方案建议由服务端实施,因为服务端才能统一查询订单、锁定候选明细、处理结算冲正、重新计算金额/营养/库存并保留完整审计链。

4.2 候选触发条件

以新明细产生时间为结束点,向前检查滚动 2 分钟窗口。至少满足以下基础条件才启动深度检测:

“不少于 4 条”只是进入检测的门槛,不代表等满 2 分钟处理。第 4 条明细产生时即可立即回查过去 2 分钟。

4.3 全量判定条件

候选组必须同时满足以下条件,任一条件不满足都不得自动纠错:

条件 A:菜品与计价方式一致

候选明细必须全部属于同一个计重菜品。换菜、按份、按个或固定价格菜品不能仅按重量合并。

条件 B:重量序列符合断连特征

截图方案要求“各次称重连续递增,单步误差不超过 5g”。建议将公式明确为:

w[i] >= w[i-1] - 5g

这里的 w[i] 必须先明确是“同一次操作的累计取餐重量”。如果现有订单明细保存的是每段独立取餐重量,这条递增规则就不成立,必须改用原始秤重轨迹或累计重量快照,不能直接套用。

条件 C:订单合计与秤体实际重量差明显不一致

实际取餐重量 = |操作开始稳定重量 - 操作结束稳定重量|
订单明细总重量 = Σ 候选明细重量
异常差值 = |订单明细总重量 - 实际取餐重量|

只有异常差值达到或超过 15g 时,才认为存在需要修正的计费偏差。15g 用于排除正常称重波动,但仍需结合秤的检定精度和起跳值验证。

示例:

项目 数值
操作开始稳定重量 5000g
操作结束稳定重量 4900g
实际取餐重量 100g
断连明细 25g、50g、75g、100g
明细合计 250g
异常差值 150g

该组数据满足明显重复累计特征,纠正后的计费重量应为 100g,而不是 250g。

条件 D:期间只有同一用户且没有异常加菜

候选期间不能切换用户。秤体剩余重量也不能出现超出容差的明显上升,否则可能发生补菜、换盆、用户放回菜品、压秤或重新置零,开始重量与结束重量不再足以代表单人取餐量。

4.4 推荐纠错流程

发现候选组
  → 对设备/餐盘/会话加锁
  → 回读并再次校验全部条件
  → 计算实际取餐重量
  → 生成唯一纠错事件 ID
  → 将原明细标记为“断连纠正已作废”
  → 新建一条纠正明细
  → 重算金额、余额、营养和库存
  → 保存原明细与纠正明细的关联关系
  → 写审计日志并释放锁

不建议物理删除原订单明细。更安全的方式是业务作废或冲正:保留原始重量、金额、生成时间、作废原因、纠错规则版本和替代明细 ID,以便财务追溯、问题复盘和重复执行防护。

4.5 当前项目状态

当前 Android 项目没有实现截图中的完整后置规则:

结论:方案二当前为未实现,且需要服务端、客户端数据契约和结算链路联合设计。

五、两个方案的关系

对比项 方案一:前置防抖 方案二:后置纠错
发生阶段 订单结束前 异常明细产生后
核心目标 不让短暂断码拆单 修复已产生的重复/错误明细
主要执行端 Android APK 服务端,Android 补充证据字段
时间尺度 900~1200ms 滚动 2 分钟
主要依据 最后一次有效码与持续空码时间 设备、餐盘、用户、菜品、明细序列和实际重量差
用户感知 真离盘结算延迟增加约 0.9~1.2 秒 可能涉及已展示金额的撤销、冲正或重新计算
风险 过长会延迟真离盘,过短仍会拆单 误判可能改错账,必须强审计和幂等
定位 主防线 兜底防线

推荐完整链路:

扫码短暂为空
  → APK 启动 900~1200ms 宽限
  → 同码恢复:继续原订单
  → 持续空码:正常结束订单
  → 若仍形成多条异常明细
  → 服务端 2 分钟规则先只检测告警
  → 规则准确率验收后再开启自动作废与纠正

六、职责与数据契约建议

责任方 建议职责
扫码头厂商 明确真实扫描周期、同码输出和空码行为
香山控制板 明确重复包节奏,最好提供真实采样序号、时间戳或新旧标识
Android APK 实现时间型宽限、会话连续性、一次性结束、日志和纠错证据字段
服务端 候选检测、并发锁、幂等纠错、业务作废、金额/余额/营养/库存重算和审计
测试 构造断码、重复包、异码、换菜、换人、补菜、置零、网络重试和并发场景
交付/现场 执行红外灰度、记录设备版本和前后指标、保留回退

建议新增或确认的数据字段:

七、建议实施顺序

阶段 0:冻结口径

阶段 1:先落地前置防抖

阶段 2:后置规则只检测不改账

阶段 3:开启自动纠错

八、验收标准

8.1 前置防抖

  1. 构造 100ms×3 和 50ms×6 重复空码包,订单结束时间只由宽限时间决定,不由包数量决定。
  2. 断码在 900ms 内恢复同一餐盘码时,订单不结束、不新增明细、取餐起始状态不重置。
  3. 断码在 900~1200ms 区间恢复时,能验证两档配置的差异。
  4. 空码持续超过配置值时,只产生一次离盘、一次结算和一条正常明细。
  5. 宽限期内出现不同餐盘码时,结果符合评审后的冲突规则。
  6. 真实移盘延迟、误拆单率和漏结算率达到项目约定指标。

8.2 后置纠错

  1. 同设备、同餐盘、同用户、同计重菜品且不少于 4 条时才进入候选检测。
  2. 换菜、换人、异常加菜、置零、跨设备、跨餐盘任一场景不得自动合并。
  3. 5g 和 15g 边界值分别有正反测试。
  4. 同一候选组重复执行不会产生第二条纠正明细。
  5. 并发上传和纠错时不会漏单、重复扣费或部分作废。
  6. 原明细、纠正明细、金额变化和规则版本可完整追溯。
  7. 观察期误报率达到业务批准标准后,方可启用自动纠错。

8.3 红外灰度

  1. 每次切换均记录设备、版本、时间、执行结果和回退结果。
  2. 切换前后对比扫码成功率、断码率、拆单率和设备异常率。
  3. 任一核心指标恶化时可以立即恢复原策略。

九、P0 待确认项

  1. 断码宽限最终默认 900ms 还是 1200ms,是否允许现场配置。
  2. 宽限期内出现不同餐盘码时,旧订单与新订单如何处理。
  3. 控制板重复包是否具有采样序号、时间戳或新旧标识。
  4. 方案二的递增重量字段到底是累计重量还是独立明细重量。
  5. “无异常加菜”的计算窗口、阈值和稳定条件。
  6. 15g 是否适用于所有秤体、菜品和起跳配置。
  7. 已扣费/已结算明细的纠错方式和财务审计要求。
  8. 原明细是否允许物理删除;本方案建议只业务作废,不物理删除。

上述口径未关闭前,方案二不得直接进入自动改账开发。

十、证据等级与边界

内容 证据等级 说明
当前 APK 使用连续空码次数结束订单 A:源码直接证据 依据当前 zymy_ongoing 分支代码核查
当前可配置 3~10 次、默认回调约 100ms A:源码直接证据 受设备实际保存配置影响
300ms 真实扫描、100ms×3/50ms×6 B:会议与人员口径 待供应商书面说明或串口抓包确认
扫码灵敏度和距离已增强 B:项目人员反馈 待现场对比数据确认
2 分钟、≥4 条、5g、15g 规则 B:用户提供的业务方案 当前项目未实现,规则字段语义仍待冻结
业务作废、幂等纠错、分阶段上线 C:工程建议 需产品、财务、服务端和测试评审

本文件没有修改业务源码,没有认定方案已经上线,也没有将临时聊天截图复制进项目仓库。

十一、来源索引

十二、人审状态