绑盘机消费功能产品需求文档

1. 文档信息

项目 内容
产品 智慧营养健康餐厅绑盘机
模块 消费结算
文档版本 V0.9.6(三步页面简化与持卡人余额展示)
日期 2026-08-28
需求来源 用户口述需求、现有绑盘三步流程、消费页现状、新开普一卡通接口 B/C
目标读者 产品、UI、Android、后端、测试、交付实施
下一阶段 方案 B 视觉定稿后进入技术方案与开发计划

2. 背景与业务目标

当前消费页已经具备餐盘识别、订单查询、一卡通读卡与扣款的基础能力,但现有页面偏调试展示,流程、异常提示和结算反馈仍不够产品化。本需求将消费过程整理为与绑盘页面一致的三步引导流程,并围绕“一笔订单只能安全结算一次”建立完整业务闭环。

业务目标:

  1. 用户只需完成放盘和放卡两个必要动作;餐盘何时拿走由用户自行决定,不影响当前业务流程。
  2. 根据订单金额自动判断零元结算或一卡通支付,不要求用户点击“支付”按钮。
  3. 餐盘提前拿走时订单查询继续,且不能误识别下一只餐盘。
  4. 卡片在交易过程中被拿走时立即中断后续操作,并根据已执行阶段给出准确提示。
  5. 扣款一旦可能发生,系统绝不自动再次扣款。
  6. 订单信息、消费前读卡、扣款结果、消费后读卡和服务端反馈结果必须关联保存,支持追溯与补偿。

3. 范围

3.1 本期范围

3.2 非本期范围

4. 术语

术语 定义
餐盘会话 从识别到一只餐盘开始,直到该订单结束并允许识别下一只餐盘的一轮流程。
锁盘 锁定当前餐盘会话,暂不接收或处理其他餐盘码。餐盘物理移走不等于会话结束。
前读卡 扣款前完整读取卡片身份、余额和消费计数。
零元读卡 零元订单读取一次完整卡片信息,仅用于人员与卡片核验,不发送消费或写卡指令。
扣款结果 一卡通消费结果,可包含补贴钱包和主钱包两段成功交易。
后读卡 扣款结束后再次完整读取卡片,用于确认余额和消费计数。
扣款前失败 扣款指令尚未发送,可以确认没有发生扣款,例如前读卡失败、提前移卡、余额不足或扣款前读卡器断开。
扣款明确失败 扣款指令已经执行并返回明确失败,且一卡通结果能够确认实际扣款金额为 0。
结果不确定 扣款指令已发送,但无法确认是否已经写卡成功的状态。
交易结果反馈 调用接口 C,将零元结算、扣款成功或扣款明确失败结果提交给业务服务端。
上传失败 接口 C 网络不可用、超时、HTTP 失败、响应解析失败或业务返回失败;不等于一卡通扣款失败。
新卡入场 第三步先确认读卡区无卡,再检测到一次新的放卡事件;用于避免误扣上一位用户遗留的卡片。
卡片保护窗口 从检测到新卡并开始前读卡,直到后读卡完整成功的一段时间;窗口内不得拿走卡片。
安全终态 当前订单已确定未扣款、已完成结算、仅待反馈,或已转入禁止重扣的人工核对状态。
统一复位 业务已进入安全终态后,根据餐盘、卡片和结果展示条件释放会话并返回第一步。

5. 已确认业务规则

  1. 消费流程采用三个页面,视觉与交互节奏参考现有绑盘三步页面。
  2. 第一步识别餐盘成功后自动进入第二步。
  3. 第二步只显示订单确认中的必要提示;订单成功后直接进入第三步,订单金额在第三步集中展示,是否支付仍只根据订单金额判断。
  4. amount = 0 为零元单,不进行一卡通消费,但必须进入第三步等待新卡、读取一次完整卡片信息后调用接口 C。
  5. amount > 0 进入一卡通支付流程;amount < 0 或金额缺失视为无效订单。
  6. 获取订单和支付过程中对餐盘保持中性,不提示拿走,也不提示不要拿走;餐盘被拿走后请求与判断仍继续。
  7. 识别餐盘后锁定当前餐盘会话,直到订单进入安全终态并完成统一复位;锁盘期间不能让下一只餐盘覆盖当前订单。
  8. 所有有效订单自动进入第三步;零元单执行读卡核验,正金额执行读卡扣款,餐盘是否已经拿走不影响页面切换。
  9. 正金额第三步使用语音“请放卡片进行支付”;零元单使用“本单金额为 0 元,请放卡核验”页面文案且不播放带“支付”含义的语音。
  10. 卡片交易期间不得拿走卡片;拿走后按实际执行阶段提示并中断后续交易。
  11. 发生卡片中途移除后:餐盘未拿走则停留在异常状态,直至餐盘拿走;餐盘已拿走则结束本轮并返回第一步。
  12. 零元单读卡成功后携带真实卡片信息调用接口 C;正金额扣款成功后携带前读卡、扣款结果和后读卡结果调用接口 C。
  13. 多钱包分段扣款时,amount 传实际扣款总额,psamID/psamJyNo/tac 取最后一段成功交易。
  14. 客户端本次不单独处理 Access-Token
  15. 第三步必须等待一次“读卡区无卡 → 新卡放入”的完整事件,不能直接使用进入页面前已停留在读卡区的卡片。
  16. 卡片保护窗口在后读卡完整成功后结束;之后接口 C 的网络反馈继续执行,但不再要求用户保留卡片。
  17. 接口 C 仅在系统配置 meal_model = 4 时启用,本功能也只在该模式下开放。
  18. 接口 C 上传成功或失败都必须推进前台业务;上传失败时先保存完整请求快照并进入后台补传,不得占用设备阻塞下一笔订单。
  19. 待上传记录每 3 分钟同步一次,每批最多 50 条;积压时同轮最多连续处理 2 批,即最多 100 条。
  20. 扣款前失败只保存本地记录并结束当前会话,不调用接口 C。
  21. 扣款指令明确成功时按成功格式调用接口 C;扣款指令返回明确失败且实际扣款金额为 0 时,按失败格式调用接口 C。
  22. 部分扣款、扣款结果不确定、后读卡失败或前后卡身份校验失败不得伪装为通用扣款失败,只保存本地异常并禁止自动再次扣款。
  23. 接口 C 上传失败与一卡通交易失败是两类独立状态;上传失败只触发原请求补传,前台业务继续统一复位。
  24. 页面展示状态与业务状态分离;前读卡、扣款、后读卡和结果反馈不得形成频繁切换的独立用户页面。
  25. 首次完整读卡后,第三步必须显示持卡人、补贴余额和现金余额;姓名通过 customerId 查询本地人员库,未同步时不得阻断交易。
  26. 正金额完整成功后使用真实后读卡快照更新结算后余额;零元单显示读卡余额;异常场景不得用计算值或扣款前余额冒充结算后余额。
  27. 新订单开始和统一复位时必须清空上一位用户的姓名、余额与卡片快照。

6. 关键产品决策与旧逻辑替换

6.1 采用方案

采用“单订单会话状态机 + 三页展示”的方案。三个页面只是同一订单状态的不同展示阶段,订单号是贯穿订单、卡片交易、本地记录和接口反馈的唯一业务关联键。

相较于“每页独立处理”或“一个页面堆叠全部状态”,该方案更适合处理餐盘提前移除、网络迟到、卡片移除和扣款后反馈失败,能避免页面切换造成交易状态丢失。

6.2 新规则覆盖旧规则

6.3 当前实现与本 PRD 的主要差距

以下差距已经通过当前源码核对,后续不能只做页面换肤:

  1. 当前 ConsumptionOrderCoordinator.onTrayRemoved() 会让未返回的订单请求失效;本需求要求查询继续并锁定本轮会话。
  2. 当前流程需要用户点击支付按钮,再武装读卡交易;本需求要求正金额判断完成后自动进入第三步。
  3. 当前页面和本地语音仍使用“请刷卡”;本需求统一改为“请放卡片进行支付”。
  4. 当前消费页是订单、硬件结果和原始数据并列的调试面板;本需求需要三个面向用餐者的独立步骤页。
  5. 当前接口 C 已支持零元和完整成功结果,但尚未形成应用重启后可恢复的持久化补传队列。
  6. 当前卡交易结果主要保存在页面状态和日志中,尚缺以订单号为主键的结构化本地交易记录及异常核对状态。
  7. 当前零元单直接反馈且卡信息为空;本次变更要求读卡成功后才能反馈,读卡失败则移卡后继续等待,不得生成成功反馈。

7. 总体业务流程

flowchart TD
    A[第一步:等待放盘] -->|识别成功并锁盘| B[第二步:获取订单]
    B -->|订单请求中| C{餐盘是否拿走}
    C -->|否| D[继续查询,不提示餐盘动作]
    C -->|是| E[记录已移盘但流程继续]
    D --> F{订单金额}
    E --> F
    F -->|无效或查询失败| G[展示异常并进入统一复位]
    F -->|0 元或大于 0| I[进入第三步卡片结算]
    I --> L{读卡区是否已有卡}
    L -->|是| L1[提示先拿走遗留卡片]
    L1 -->|检测到无卡| L2[等待新卡放入]
    L -->|否| L2
    L2 -->|新卡放入| M[读取完整卡片信息]
    M -->|0 元| H[跳过扣款并反馈携卡零元结果]
    H -->|反馈成功| J[零元完成]
    H -->|反馈失败| K[保存原请求待补传]
    M -->|大于 0| N[一卡通扣款]
    N --> O[后读卡]
    N -->|明确失败且实际扣款为 0| W[接口 C 反馈扣款失败]
    O -->|成功并校验通过| P[结束卡片保护窗口并反馈接口 C]
    P -->|反馈成功| Q[支付完成]
    P -->|反馈失败| R[扣款已完成,仅重试反馈]
    M -->|卡片移除或失败| S[确定未扣款,中断支付]
    N -->|卡片移除或结果不确定| T[禁止再次扣款,进入异常核对]
    O -->|卡片移除或失败| U[扣款可能已完成,禁止再次扣款]
    J --> V[WAITING_RESET:统一复位]
    G --> V
    K --> V
    Q --> V
    R --> V
    S --> V
    T --> V
    U --> V
    W -->|上传成功或失败已落库| V
    V -->|复位条件满足并释放锁盘| A

8. 页面需求

8.1 第一步:等待放盘

页面目的

明确告诉用户把餐盘放到识别区,并等待系统自动识别。

页面内容

交互规则

  1. 页面打开后持续等待有效餐盘码。
  2. 无效码、空码或瞬时抖动不切页,可短暂提示“未识别到有效餐盘,请重新放置”。
  3. 识别到有效餐盘后立即创建餐盘会话、锁定餐盘识别,并自动切换第二步。
  4. 同一餐盘重复上报不得创建第二个会话或重复请求订单。
  5. 上一笔订单未安全结束时,即使检测到新餐盘,也不得覆盖上一笔订单。

8.2 第二步:获取订单并判断金额

页面目的

让用户知道系统正在确认订单,并展示最终订单号和金额。

请求中状态

餐盘在请求中被拿走

  1. 不取消订单请求,不返回第一步。
  2. 记录 tray_removed = true,页面改为:餐盘已取走,正在继续确认订单
  3. 保持锁盘,不处理其他餐盘识别结果。
  4. 请求返回后继续校验订单号和金额,并进入对应分支。

订单成功状态

金额判断

条件 处理
amount = 0 显示“本单无需支付”,自动进入第三步等待放卡核验;读卡成功后调用接口 C。
amount > 0 显示金额并自动进入第三步执行卡片支付,不提示餐盘动作。
amount < 0、缺失或类型错误 显示“订单金额异常,请联系工作人员”,禁止支付。

零元读卡与完成

订单查询异常

异常 页面与流程
网络不可用、超时、服务端失败 显示“订单获取失败,请联系工作人员”;可按可配置策略重试查询,但同一时刻只能有一个请求。
未查询到订单 显示“未查询到待结算订单,请联系工作人员”。
缺少设备编号 显示“设备未完成配置,请联系工作人员”。
返回订单号为空 视为无效订单,不进入第三步。
餐盘仍在 停留异常结果,餐盘拿走后复位。
餐盘已拿走 异常提示短暂展示后复位;迟到响应不得重新打开旧会话。

8.3 第三步:卡片结算

页面目的

引导用户放置卡片。零元单完成只读核验,正金额完成一卡通支付;卡片处理期间清晰说明不可移卡。

进入页面

等待卡片

  1. 当前订单完成金额判断后均允许武装一次卡片流程;零元仅获得读卡执行权,正金额获得扣款执行权。
  2. 同一订单同时只能存在一个卡片硬件任务。
  3. 进入第三步时必须先确认读卡区为无卡状态;若已检测到卡片,页面提示 请先拿走卡片,此时禁止读卡和扣款。
  4. 检测到无卡后才进入“等待新卡”状态;只有随后发生的新放卡事件才能开始本订单交易。
  5. 等待新卡设置可配置安全超时。超时发生在扣款指令发送前,可安全取消本次支付:餐盘已拿走时展示结果后复位;餐盘仍在时保持超时状态,待餐盘拿走后复位。
  6. 超时后不得在原会话中自动重新寻卡。管理员可结束仍未扣款的超时会话,但不能结束已经发出扣款指令的会话。

零元只读卡

  1. 检测到新卡后执行一次完整 readCard,保存卡片身份、余额和消费次数。
  2. 不执行补贴/主钱包规划,不调用消费接口,不产生 PSAM/TAC。
  3. 反馈协议中的 before_card_infoafter_card_info 使用同一真实读卡快照;这是无写卡场景的协议镜像,不代表发生了第二次物理读卡。
  4. 读卡失败时只记录失败,不发送成功反馈;移卡后回到等待新卡状态。
  5. 读卡成功后结束卡片保护窗口,接口 C 反馈可在用户取卡后继续。

交易中

页面固定展示:

交易开始后隐藏或禁用所有可能重新发起支付的控件。餐盘在此阶段拿走不取消交易,只记录状态用于完成后的页面收尾。

后读卡完整成功并通过卡片一致性、金额及余额校验后,卡片保护窗口结束,页面改为 卡片读取完成,可拿走卡片。随后接口 C 的网络反馈可在卡片已经拿走的情况下继续,不得因移卡取消反馈或把反馈失败误判成扣款失败。

支付成功

只有以下条件全部满足,页面才能显示“支付成功”:

  1. 前读卡成功。
  2. 所有计划扣款段完整成功,实际扣款总额等于本次计划金额。
  3. 后读卡成功。
  4. 接口 C 返回业务成功 code = 0

成功文案:支付成功,请拿走卡片。卡片拿走后:

扣款成功但反馈失败

9. 餐盘行为规则

当前阶段 餐盘拿走后的处理
第一步等待放盘 无当前会话,不处理。
餐盘刚识别、尚未请求订单 会话继续,仍请求订单。
订单请求中 请求不中断,记录已移盘,锁盘持续。
零元读卡或反馈中 读卡任务/反馈不中断;成功或进入补传后可复位。
等待卡片 卡片会话保留,继续等待卡片。
前读卡、扣款、后读卡 不强制中断硬件交易,只记录已移盘。
结算反馈中 反馈不中断。
成功或失败终态 进入统一复位;餐盘已拿走时按最短结果展示时长返回第一步,餐盘仍在时可提示拿走餐盘。

锁盘释放条件:订单进入安全终态,且页面已经完成当前结果展示。单纯检测到餐盘物理移走不能提前释放锁盘。

锁盘范围是完整餐盘会话,而不只是订单查询阶段。即使订单金额已经判断完成,只要支付、反馈、异常落库或统一复位尚未达到安全条件,就不得接收下一只餐盘建立新会话。

10. 卡片中途移除与失败矩阵

10.1 基本原则

  1. 检测到新卡并开始前读卡后进入卡片保护窗口;窗口内任一步检测到卡片移除,都停止尚未开始的后续动作。
  2. 已经发送的硬件指令不能通过 UI 强行撤销。
  3. 只要存在“可能已经扣款”,当前订单就永久禁止自动再次扣款,直到人工或可靠数据确认。
  4. 页面必须提示具体失败阶段,不能统一显示“支付失败”。
  5. 后读卡完整成功并通过客户端校验后,卡片保护窗口结束;此后用户拿走卡片不影响接口 C 反馈。
  6. 前读卡失败、提前移卡、余额不足或扣款前硬件断开属于扣款前失败,只记本地,不调用接口 C。
  7. 只有扣款指令已经返回明确失败且能确认实际扣款金额为 0,才作为“扣款明确失败”调用接口 C。
  8. 零元单读卡失败没有写卡风险,移卡后允许在同一订单会话继续等待下一次放卡;没有完整卡信息时禁止反馈零元成功。

10.2 分阶段处理

中断点 扣款风险 页面提示 后续处理
放卡后、前读卡尚未完成 确定未扣款 卡片已拿走,未读取到完整卡片信息 中断本次支付。餐盘未拿走则保持此状态,拿走后复位;默认不在原会话自动重新寻卡。
前读卡成功、扣款指令尚未发送 确定未扣款 卡片已拿走,尚未扣款 同上;记录前读卡和失败阶段。
扣款指令返回明确失败且实际扣款为 0 明确未扣款 支付未完成,请取走卡片和餐盘后重新操作 记录一卡通失败结果,按失败格式调用接口 C;上传结果不阻塞统一复位。
扣款指令发送后、未确认结果 结果不确定 卡片已拿走,扣款结果待核对,请勿再次支付 立即阻止后续钱包扣款和整单重试,保存异常记录,进入人工核对。
部分钱包扣款成功、后续钱包失败 已发生部分扣款 已扣款部分金额,后续扣款未完成,请勿再次支付 保存每段成功结果和失败原因,不自动补扣剩余金额。
全部扣款成功、后读卡失败 已完成扣款 扣款已完成,但余额确认失败,请勿再次支付 保存前读卡和扣款结果;不得重新扣款,等待异常补偿或人工处理。
后读卡成功、接口 C 反馈失败 已完成扣款 扣款已完成,结算结果正在补传 仅重试反馈。

10.3 前后读卡与扣款校验

接口 C 服务端不校验前后卡片是否属于同一人员,也不校验反馈扣款金额是否等于订单金额,因此客户端在显示成功和调用成功反馈前必须完成:

  1. 前后读卡的 uidcustomerIDcardNOcardASN 分别一致;任何关键身份字段缺失或不一致,都不得按成功处理,进入 DEBITED_VALIDATION_FAILED 并禁止再次扣款。
  2. 所有已完成钱包扣款段的金额合计必须等于订单金额;不相等时进入部分扣款或异常核对状态。
  3. 根据一卡通协议校验消费前后钱包余额和消费计数变化,与实际完成的各段扣款一致。
  4. 校验使用结构化字段,不依赖页面文本或日志字符串;校验失败原因写入本地交易记录。

10.4 餐盘状态联动

11. 一卡通钱包规则

  1. 订单金额单位为分,必须使用整数计算。
  2. 扣款顺序为补贴钱包优先、主钱包补足。
  3. 补贴足够时只产生一段补贴钱包交易。
  4. 补贴不足但总余额足够时,先扣尽所需补贴金额,再从主钱包扣剩余金额。
  5. 补贴为零时只扣主钱包。
  6. 总余额不足必须在发送第一条扣款指令前拒绝,页面显示 卡内余额不足
  7. 多钱包部分成功不能按整单成功展示,也不能自动从头重试。

12. 接口需求

12.1 接口 B:按餐盘查询待结算订单

客户端要求:同一餐盘会话只允许一个有效请求;换盘或页面销毁后的迟到响应不得覆盖新会话。订单号是服务端生成的唯一业务标识,接口 B 按其既有定义只返回待结算订单;本期不增加跨设备并发结算设计。

12.2 接口 C:反馈一卡通扣款结果

零元订单

{
  "order_no": "订单号",
  "equipment_code": "设备编号",
  "settlement_result": {
    "code": 0,
    "amount": 0
  },
  "before_card_info": { "customerID": 29373, "cardNO": 1705827, "...": "完整读卡字段" },
  "after_card_info": { "customerID": 29373, "cardNO": 1705827, "...": "与前读卡相同" }
}

正金额成功订单

扣款明确失败

幂等和重试

  1. 每次反馈必须携带原始 order_no
  2. 接口超时或失败不代表扣款失败。
  3. 本地已经记录扣款成功时,只能重试原反馈,不得再次扣款。
  4. 服务端对已成功反馈订单重复收到成功结果时应幂等返回成功。
  5. 服务端业务成功以响应体 code = 0 为准,不能只判断 HTTP 状态。
  6. 接口 C 的上传结果不作为前台放行条件;上传成功时标记完成,上传失败时可靠落入补传队列,两种情况都继续当前订单的结果展示和统一复位。
  7. “上传失败”包括网络不可用、请求超时、HTTP 失败、响应解析失败和服务端业务 code != 0;以上情况必须保存最近失败原因,但不得重新扣款或阻塞下一笔订单。
  8. 同一订单出现重复上传,只能来自首次上传未确认成功后的补传;必须使用相同 order_no 和原始请求快照,不创建新订单号或新结算记录。
  9. 服务端已经确认相同订单的成功反馈具备幂等处理;订单号相同是识别同一笔反馈的业务键,本期不再把重复上传列为待确认项。

交易失败与上传失败边界

13. 本地记录与可靠补偿

13.1 记录要求

每笔订单建立一条可持续更新的本地交易记录,至少包含:

13.2 写入时机

  1. 获取订单成功后立即创建记录。
  2. 每完成一个硬件阶段立即更新,不等待整笔流程结束。
  3. 扣款指令发送前写入“即将扣款”的事务标记;结果返回后立即更新为成功、失败或不确定。
  4. 调用接口 C 前保存完整请求快照,确保网络失败或应用重启后能原样重试。
  5. “即将扣款”事务标记必须成功持久化后才能向硬件发送扣款指令;落库失败、磁盘空间不足或数据库不可用时立即停止支付并提示联系工作人员。

13.3 补传队列

13.4 应用重启恢复矩阵

重启前最后持久化状态 恢复处理
ORDER_LOADING 丢弃未完成的前台请求;不自动恢复旧页面,后续重新放盘时再查询。
WAITING_CARD、前读卡未完成且未发送扣款 可安全结束旧会话,不自动寻卡或扣款。
已写入扣款意图,但无确定硬件结果 恢复为 DEBIT_UNKNOWN,禁止重新扣款并进入人工核对。
部分扣款或扣款完成但后读卡失败 恢复对应异常状态,禁止重新扣款。
接口 C 请求快照已保存但未确认成功 恢复持久化补传,仅重放原请求。
COMPLETEDREPORT_PENDINGDEBITED_REPORT_PENDING 已结算订单永不重新扣款;待反馈状态继续后台补传。

恢复判断只能依据已持久化事务记录,不能依据 Activity、Fragment、内存标志或语音播放状态。

13.5 数据安全

14. 状态机

状态 含义 可进入状态
WAITING_TRAY 等待餐盘 ORDER_LOADING
ORDER_LOADING 已锁盘,正在获取订单 WAITING_CARD_CLEARWAITING_CARDORDER_ERROR
WAITING_CARD_CLEAR 第三步检测到遗留卡,等待读卡区无卡 WAITING_CARDCANCELLED
WAITING_CARD 读卡区已确认无卡,等待一次新卡放入 READING_ZERO_AMOUNT_CARDREADING_BEFOREWAITING_CARD_TIMEOUTCANCELLED
READING_ZERO_AMOUNT_CARD 零元单读取一次完整卡片信息,不写卡 REPORTINGWAITING_CARD
WAITING_CARD_TIMEOUT 扣款前等待新卡超时 WAITING_RESET
READING_BEFORE 前读卡 DEBITINGCARD_INTERRUPTED_NO_DEBIT
DEBITING 一卡通扣款 READING_AFTERDEBIT_FAILED_REPORTINGPARTIAL_DEBITDEBIT_UNKNOWN
READING_AFTER 后读卡及前后卡、金额、余额校验 REPORTINGDEBITED_AFTER_READ_FAILEDDEBITED_VALIDATION_FAILED
REPORTING 零元或正金额成功结果反馈中 COMPLETEDREPORT_PENDINGDEBITED_REPORT_PENDING
CARD_INTERRUPTED_NO_DEBIT 卡片在扣款指令前移除,确定未扣款 WAITING_RESET
DEBIT_FAILED_REPORTING 扣款指令明确失败且实际扣款为 0,正在反馈接口 C DEBIT_FAILEDFAILED_REPORT_PENDING
DEBIT_FAILED 扣款明确失败且接口 C 已上传成功 WAITING_RESET
FAILED_REPORT_PENDING 扣款明确失败,接口 C 请求待补传 WAITING_RESET,后台继续
REPORT_PENDING 零元结果待补传 WAITING_RESET,后台继续
DEBITED_REPORT_PENDING 已扣款、结果待补传 WAITING_RESET,后台继续
PARTIAL_DEBIT 部分钱包扣款成功 WAITING_RESET,人工核对
DEBIT_UNKNOWN 扣款结果不确定 WAITING_RESET,人工核对
DEBITED_AFTER_READ_FAILED 扣款完成但后读卡失败 WAITING_RESET,人工核对或专用补偿
DEBITED_VALIDATION_FAILED 后读卡完成但身份、金额或余额校验不通过 WAITING_RESET,人工核对
COMPLETED 服务端确认结算成功 WAITING_RESET
ORDER_ERROR 订单无效或查询失败 WAITING_RESET
CANCELLED 未扣款前安全取消 WAITING_RESET
WAITING_RESET 安全终态结果展示与设备清场 WAITING_TRAY

任何带 DEBITEDPARTIAL_DEBITDEBIT_UNKNOWN 的状态都必须设置 debit_retry_forbidden = trueWAITING_RESET 只有在本地终态记录落库成功、最短展示时长已满足、卡片不处于保护窗口且需要清场的卡片/餐盘已移除后,才能释放锁盘并进入 WAITING_TRAY

15. 页面文案与语音清单

场景 页面主文案 语音
第一步 请放置餐盘 可沿用放盘提示音,是否播放由原型评审确定
订单查询 正在确认订单;请稍候
查询时已移盘 正在确认订单;请稍候
零元等待放卡 请放卡核验;只读取卡片信息,不会扣款
零元读卡及反馈 卡片核验中;请勿移动卡片
零元完成或待补传 核验完成;请取走卡片和餐盘 可选成功提示音
正金额进入支付 请放卡片;请将卡片平放在读卡区域 请放卡片进行支付
读卡区已有卡 请先拿走卡片
等待卡片 请放卡片;请将卡片平放在读卡区域 请放卡片进行支付
等待卡片超时 等待支付超时,请取走餐盘后重新操作 可选异常提示音
前读卡、扣款、后读卡 结算处理中;请勿移动卡片
反馈中、成功或待补传 结算完成;请取走卡片和餐盘 可选成功提示音
确认未扣款 结算未完成;请取走卡片和餐盘后重新操作 异常提示音可选
结果不确定 结算结果待确认;请勿再次支付,并联系工作人员 异常提示音可选

首次完整读卡成功后,第三步原页面显示持卡人、补贴余额和现金余额。首次快照标记为读卡时余额,零元标记为卡片余额,正金额完整成功后更新为结算后余额

所有用户可见文案避免“刷卡”“技术错误码”“APDU”“PSAM”等技术词汇。管理员诊断入口可查看详细阶段和错误码,但不在主流程页面展示。

16. 防重复与并发要求

  1. 同一时刻只能存在一笔前台餐盘会话和一笔卡片硬件交易。
  2. 餐盘识别、订单请求、支付执行和结果反馈均使用订单会话 ID 隔离迟到回调。
  3. 同一订单号本地已有 COMPLETEDDEBITED_REPORT_PENDINGPARTIAL_DEBITDEBIT_UNKNOWN 时,不得再次扣款。
  4. 卡片持续放在读卡区时只能触发一次交易;必须检测到移卡并进入下一笔有效订单后才能再次交易。
  5. 页面重复创建、横竖屏变化、应用切后台或网络重连不得重复发起扣款。
  6. 断电或崩溃恢复时先检查本地事务记录,再决定继续反馈、进入人工核对或允许新订单。

16.1 页面生命周期与设备异常

  1. 扣款指令发送前,用户离开页面或管理员结束会话只能执行安全取消,并先持久化取消结果。
  2. 开始前读卡后禁用普通返回、重复进入其他业务页和普通退出;只有受控管理员入口可以查看状态,不得销毁交易会话。
  3. Activity/Fragment 重建、横竖屏、切后台或进程内页面跳转只重建展示层,订单状态机和硬件任务必须由独立于页面的会话层持有。
  4. 扣款指令发送后发生 USB 断连、读卡器掉线、硬件回调丢失或应用异常退出,一律记为 DEBIT_UNKNOWN,禁止再次扣款。
  5. 页面销毁不得取消已经发出的硬件指令,也不得删除已保存的接口 C 请求快照或补传任务。
  6. USB 在扣款前断开时可确定未扣款并安全结束;USB 恢复后不得自动沿用旧订单寻卡或发起扣款。

16.2 运行监控与容量保护

17. 验收标准

17.1 主流程

17.2 异常流程

17.3 数据与接口

17.4 设备验收

18. 产品补充建议

以下内容是为保证业务完整性补充的默认方案,若后续没有相反确认,原型和技术方案按此执行:

  1. 取消主流程支付按钮,订单金额判断后自动进入第三步。
  2. 订单查询和结果反馈使用持久化状态,不依赖 Activity 是否存活。
  3. 反馈失败允许页面复位,但必须保留后台补传任务。
  4. 结果不确定、部分扣款和扣款后复读失败不允许普通用户重试,后续应提供管理员异常处理入口。
  5. 页面以用户动作和结果为主;接口码、读卡原始数据和交易阶段明细放入管理员诊断或本地记录。
  6. 新卡入场校验、扣款前持久化闸门、前后卡身份校验和统一复位状态属于支付安全底线,不作为可选配置关闭。
  7. 订单查询期间到统一复位完成前持续锁定餐盘会话;餐盘拿走只影响收尾条件,不释放业务锁。

19. 待后续专项确认

以下事项不阻塞方案 B 定稿与主流程开发,但会影响最终运维和异常处置范围:

  1. DEBIT_UNKNOWNPARTIAL_DEBITDEBITED_AFTER_READ_FAILED 的后台人工处理入口由哪个系统提供。
  2. 补传连续失败的告警阈值和管理员处置方式;同步周期、批量及单轮上限已经确认。
  3. 成功、失败结果在餐盘和卡片均已拿走后的最短展示时长。
  4. 本地交易记录的具体保留天数和设备容量上限。
  5. 是否增加支付成功、异常提示音;“请放卡片进行支付”语音为必需。

20. 原型设计输入

原型必须至少覆盖以下可切换场景:

  1. 第一步等待放盘。
  2. 第二步正常查询订单。
  3. 第二步查询时餐盘已拿走。
  4. 零元订单等待放卡、读卡中、反馈中、成功、读卡失败重试和补传中。
  5. 正金额订单自动进入第三步,分别覆盖餐盘仍在和餐盘已拿走两种状态,但页面文案保持一致。
  6. 第三步等待卡片。
  7. 前读卡、扣款、后读卡、反馈四个处理中状态。
  8. 支付成功。
  9. 卡片在三个硬件阶段分别被拿走。
  10. 部分扣款、结果不确定、后读卡失败、反馈失败。
  11. 餐盘未拿走时保持结果,以及餐盘已拿走时自动复位。
  12. 进入第三步时读卡区已有卡、读卡区清空、重新放入新卡三个状态。
  13. 等待新卡超时、后读卡完成后允许移卡、统一复位和 USB 断连状态。

原型视觉需延续绑盘页面的三步结构、标题区、主插画和大字号提示,但不能照搬当前消费调试面板。主流程只保留用户需要理解的信息,详细订单和硬件数据通过管理员诊断入口查看。

21. 评审结论