A02 报警认领补录实施计划
目标:为 A02 未放餐盘报警增加两按钮门控的刷管理卡解除与放餐盘认领补录,复用现有本地取餐记录和 Worker 上传链路,并确保报警日报志完整可追溯。
实施边界
- 仅改变 A02;A01、A03 保持现有页面、扫码和解除规则。
- 60 秒超时只回到解除方式选择页,不自动解除报警。
- 报警前基准重量固定;无餐盘、稳定状态下逃单重量按基准减当前重量实时更新。
- 当前稳定重量恢复至基准重量或更高时,以
WEIGHT_RECOVERED自动解除,不创建或上传取餐记录。 - A02 认领不进入正常打餐流程,不调用
scanCodeResult(0, ...)、handleScanResult(...)或switchToOngoingFragment()。 - 本地保存首次失败后自动重试 2 次;三次均失败进入
LOCAL_SAVE_FAILED,停止认领扫码,只允许管理卡以异常原因解除。 - 本地保存成功后,网络类上传失败立即重试 3 次;三次失败保留记录进入定时队列、提示累计暂未同步并离线解除;业务失败和本地删除失败保持报警。
- 延迟上传成功时,仅当前认领餐盘仍在打餐页才主动刷新累计;否则下次放盘读取服务端累计。
code=1保留候选记录的旧删除策略,但 A02 不解除;工作人员绑定餐盘后移开并重新放盘再认领。- Git 提交不在本计划中,由项目负责人控制。
文件地图
| 路径 | 职责 |
|---|---|
antiescape/A02AlarmAction.java | 新增三态按钮门控枚举 |
NoTrayPickDetector.java | 暴露 A02 触发基准和重量证据 |
AntiEscapeAlarm.java | 报警流水号、固定基准和实时逃单重量 |
HomeActivity.java | 实时重量、恢复自动解除、刷卡/认领分支、Worker 结果事件处理和审计 |
AntiEscapeAlarmDialogFragment.java | A02 按钮、等待状态和实时重量展示 |
PickMealRecord、DAO、DB Helper | 来源/报警关联与安全迁移 |
UploadPickMealRecordWorker.java | 上传结果回写日报警日志并发布 A02 专用结果事件 |
任务 1:A02 基准与实时重量
新增 A02AlarmAction:NONE、WAIT_MANAGER_CARD、WAIT_TRAY_CLAIM。保持 NoTrayPickDetector.onWeight(...) 的布尔返回值不变,在触发分支保存固定基准和触发重量证据。活动 A02 在无餐盘、稳定、取餐前页时按 max(0, baselineWeight - currentWeight) 实时更新;当前稳定重量恢复至基准或更高时写 WEIGHT_RECOVERED 并自动解除。
任务 2:A02 两按钮页面
在既有全屏 A02 报警图上增加默认隐藏的操作容器:实时逃单重量、提示、刷管理卡按钮和放餐盘认领按钮。两按钮必须左右等宽地位于同一横行,中间间距 12dp;文案水平居中,最多可在按钮内换两行,不能截断。等待任一输入时显示“返回重新选择”;默认选择页、餐盘查人或上传进行中、以及 LOCAL_SAVE_FAILED 均隐藏它。Fragment 仅对 A02 显示控件,并通过 Activity 回调上报选择或取消。传入初始 alarmPickWeight 后,由 Activity 在无餐盘有效稳定读数时更新页面;餐盘识别后保持最后一次有效值。
任务 3:60 秒门控与扫码拦截
在 HomeActivity 增加当前动作、认领请求标记和 60,000ms Runnable。选择动作后写 ACTION_SELECT、启动计时;超时写 ACTION_TIMEOUT、回到 NONE,但不停止报警。尚未接收有效输入时可主动取消:移除计时、清空待处理餐盘状态、写 ACTION_CANCEL 并回到 NONE;查询/上传进行中和 LOCAL_SAVE_FAILED 拒绝取消。触发、解除、停止、销毁均取消旧计时。
A02 扫码优先走专用分支:默认状态忽略全部;管理卡等待态仅接受有效解除卡;餐盘等待态仅接受非管理卡的六位餐盘码,且不进入普通扫码流程。
ACTION_CANCEL;再验证 60 秒超时后日志有 ACTION_TIMEOUT。任务 4:管理卡解除审计
仅在管理卡等待态读取有效卡。写入 RESOLVE|method=MANAGER_CARD|cardCode=...|durationMs=... 后调用既有解除方法,不创建取餐记录。A02 触发日志增加 alarmId、固定基准重量、触发重量与最终实时逃单重量。
888888:一条选择日志、一条含卡值/时长/最终实时逃单重量的解除日志、无新增取餐记录。任务 5:放盘认领复用现有上传
从 uploadPickInfo(int) 提取参数化的 savePickMealRecord(...)。正常取餐传 source=NORMAL;A02 传触发时间、认领前最后一次有效实时重量、绑定人员、认领餐盘、source=ANTI_ESCAPE_A02 与 alarmId。
认领使用现有 newGetStaffInfoByTray(trayCode, dishUuid)。同一餐盘持续上报时只查询一次。查到人员后使用同一认领上下文保存,首次保存失败自动再试 2 次;三次失败进入 LOCAL_SAVE_FAILED:隐藏或禁用放盘认领、忽略后续餐盘码,提示“取餐记录保存失败,无法进行放盘补录,请工作人员刷管理卡解除报警。”,仅管理卡可用 LOCAL_SAVE_FAILED_ADMIN_OVERRIDE 解除。保存成功后立即上传;网络类失败重试 3 次后入既有定时队列并以 TRAY_CLAIM_DEFERRED_NETWORK 放行,页面提示累计可能暂未同步。只有 code=0 且本地删除成功才以正常成功原因解除。延迟上传成功时当前餐盘仍在打餐页则刷新人员累计。code=1 时按旧策略删除候选记录但不解除,提示先绑定餐盘后重新认领。
任务 6:安全数据库迁移
为 PickMealRecord、DAO 和表增加 source、alarm_id。数据库升至 v2,v1 升 v2 使用两条 ALTER TABLE,绝不删除 pick_record。旧记录的来源默认 NORMAL、alarmId 为空。
任务 7:同步结果写入日报警日志
Worker 和即时上传协调器对 ANTI_ESCAPE_A02 来源追加日志:code 0 且删除成功为 UPLOAD_SUCCESS;code 1 为 UPLOAD_DROPPED_LEGACY_POLICY;本地删除失败为 UPLOAD_DELETE_FAILED。仅网络类失败计数,第三次写 UPLOAD_DEFERRED_NETWORK,保留记录进定时队列并以 TRAY_CLAIM_DEFERRED_NETWORK 解除。延迟成功携带餐盘码;若仍为当前打餐餐盘则刷新人员累计。业务失败保持报警。
任务 8:构建、验收与变更记录
使用 JDK 8 运行 :app:testDebugUnitTest 与 :app:assembleDebug。设备覆盖默认忽略、管理卡、有效/无效餐盘、60 秒超时、落库失败、离线补传、A01/A03、正常取餐和旧库升级。源码实施并验证后,在项目 change_records/ 创建同名 Markdown 与 HTML 变更记录,附构建、测试与设备证据。
完成标准
- A02 默认状态不响应任何扫描或放盘。
- 无餐盘、稳定状态下,A02 逃单重量按固定基准与当前重量实时更新;重量恢复至基准或更高时自动解除并写
WEIGHT_RECOVERED,无取餐记录和上传。 - A02 两种解除按钮左右等宽、同一行显示,间距
12dp,文案完整可读。 - 三次本地保存失败时仅管理卡可解除、没有上传队列记录;每次保存尝试和最后错误可审计。
- 三次网络类上传失败时记录进入定时队列、离线解除并提示累计延迟;成功后当前餐盘累计刷新。
code=1时删除候选记录但保持报警,提示先绑盘后移开、重新放盘认领。- 上传最终结果可在日报警分类日志中关联到报警流水号和本地记录 ID。
- A01、A03、正常取餐和历史离线记录无回归。