fujian_water_biz_doc/docs/superpowers/specs/2026-07-13-counter-topup-persistent-display-design.md

7.7 KiB
Raw Blame History

柜台预存持久回显与缴费历史修复设计

日期2026-07-13

背景

柜台无欠费客户完成预存后,页面会临时插入一条“预存款 / 收讫”记录。该记录只存在于前端内存,重新查询客户时会被清除。与此同时,客户缴费记录接口虽然查询了多条有效支付主单,却只返回其中最新一条,导致较早的预存记录被后续缴费记录覆盖。缴费记录响应中的期初余额、期末余额字段也未从可靠的账务快照赋值。

本次修复以 biz_payment_record 为缴费记录主数据源,以 biz_account_log 的余额变动快照为余额证据,建立“预存成功后显示、重新查询后仍能从后端恢复、客户历史可完整分页查询”的闭环。

目标

  1. 无欠费客户完成柜台预存后,当前页面继续展示“预存款 / 收讫”记录。
  2. 重新查询同一无欠费客户时,页面从后端支付记录恢复最近一笔有效预存,不依赖前端缓存。
  3. 客户详情的缴费记录按时间倒序返回全部有效历史,并保持正确分页、统计和导出语义。
  4. 新产生的预存记录能够展示可追溯的期初余额和期末余额。
  5. 已红冲支付记录不作为有效预存回显,也不进入正常缴费历史。

非目标

  • 本次不修复主副卡付款户解析错误和柜台有效余额读取错误。
  • 本次不对无法可靠关联账户流水的旧支付记录伪造期初、期末余额。
  • 本次不把所有历史预存与当前待收费账单混合展示。
  • 本次不引入浏览器本地缓存、localStorage 或跨会话前端状态作为账务记录来源。

方案选择

采用“后端持久记录回显”方案:

  • 缴费历史接口返回全部符合条件的有效支付主单,再由现有分页参数截取当前页。
  • 查询请求增加可选业务场景过滤;柜台页面用 DEPOSIT_TOPUP 精确查询最近一笔有效预存。
  • 柜台页面仅在当前客户没有待缴账单时回显最近预存,避免历史记录进入可勾选的待收费账单集合。
  • 新预存交易将支付主单 ID 写入对应账户流水来源字段,并由查询层映射余额变动前后值。

不采用以下方案:

  • 仅保留前端临时数组或写入浏览器缓存:换页面、换设备或重新登录后仍会丢失,也不能作为账务证据。
  • 无条件把最近预存和待缴账单混合展示:会让历史收款记录进入当前收费语境,增加误选和重复收费风险。

后端设计

缴费历史查询

将当前“查询全部候选记录后只保留第一条”的实现改为返回全部有效候选记录:

  • 继续按 payTimeid 倒序排列。
  • 继续使用现有可见性规则过滤已红冲及非正常记录。
  • skipCountmaxResultCount 在过滤后的完整集合上分页。
  • totalCounttotalAmounttopUpCounttopUpTotalMoney 均基于过滤后的完整集合计算。
  • 导出使用与页面查询相同的过滤规则,但不受页面分页截断。

PaymentRecordPageNewReqVO 增加可选 bizScene

  • 未传时保持客户缴费历史的全场景查询。
  • DEPOSIT_TOPUP 时只返回柜台预存记录。
  • 过滤由后端查询条件完成,不由前端拉取一页数据后自行猜测。

预存余额快照关联

柜台预存保持单事务执行,但调整事务内顺序:

  1. 创建 DEPOSIT_TOPUP 支付主单,获得 paymentRecordId
  2. 增加实际付款账户预存余额。
  3. 写入账户流水时,将 paymentRecordId 写入 payDetailId
  4. 返回支付主单信息和变更后余额。

任一步失败时整个事务回滚,不留下只有支付记录或只有余额变动的半成品。

查询缴费历史时,针对 DEPOSIT_TOPUP 通过 payDetailId = paymentRecordId 获取账户流水:

  • lastDeposit 映射 balanceBefore
  • deposit 映射 balanceAfter

旧数据如果没有 payDetailId 关联,不按金额和时间做模糊匹配,期初、期末余额显示为空值,由前端展示 -,避免错误余额成为账务证据。

红冲兼容

  • 已红冲原支付主单继续由现有可见性规则排除。
  • 红冲反向支付记录不作为正常 DEPOSIT_TOPUP 回显。
  • 柜台页面查询最近预存时只取最新一笔有效、未红冲的收入记录。

前端设计

柜台预存成功展示

预存成功后仍可立即显示本次“预存款 / 收讫”记录,但显示内容以接口返回的支付主单 ID、支付时间、金额和收费方式为准不再使用时间戳伪造记录 ID。

重新查询恢复

loadCustomerChargeData(custId) 完成待缴账单和统计查询后:

  • 有待缴账单:按现有逻辑展示待缴账单,不混入历史预存。
  • 无待缴账单:调用缴费历史接口,传入 custIdbizScene=DEPOSIT_TOPUPskipCount=0maxResultCount=1
  • 查询到有效预存:转换为不可勾选的“预存款 / 收讫”展示行。
  • 没有有效预存:保持空表状态。
  • 恢复查询失败:不影响客户和待缴账单主查询,记录错误并提示“最近预存记录加载失败”。

历史回显行只用于确认最近一次成功预存,不参与选中账单、应收统计或再次收费计算。

客户缴费记录

客户详情沿用现有分页组件和接口参数。后端返回完整结果后:

  • 翻页能看到较早记录。
  • 统计金额和笔数使用完整过滤结果。
  • 有可靠账户流水关联的新预存显示期初、期末余额。
  • 无可靠余额证据的旧记录继续显示 -,不得转成 0

错误处理

  • 支付主单创建或余额增加失败时事务整体回滚,前端不插入成功行。
  • 最近预存查询失败不清空客户基本信息和待缴账单结果。
  • 接口返回空记录时不沿用上一个客户的预存展示行。
  • 已红冲记录不可通过页面刷新重新出现。

测试设计

后端单元测试

  1. 两条有效支付记录均进入候选集合,分页返回正确记录和总数。
  2. 最新记录已红冲时被过滤,较早有效记录仍可查询。
  3. bizScene=DEPOSIT_TOPUP 时只返回预存记录。
  4. 汇总金额、预存笔数和预存金额基于全部有效记录计算。
  5. 新柜台预存先生成支付主单,再写入带 paymentRecordId 的账户流水。
  6. 有账户流水关联时正确映射 balanceBeforebalanceAfter;无关联时余额字段为空。
  7. 导出包含全部有效记录,不退化为只导出最新一条。

前端测试

  1. 无欠费客户重新查询时调用 DEPOSIT_TOPUP 过滤接口并恢复最近预存行。
  2. 有待缴账单时不把历史预存混入待收费列表。
  3. 切换客户时清空上一客户的临时或持久回显行。
  4. 最近预存加载失败时不破坏客户待缴账单查询结果。
  5. 客户缴费记录翻页使用后端完整总数,余额空值显示 - 而不是 0

验收标准

  1. 无欠费客户预存成功后可立即看到“预存款 / 收讫”记录。
  2. 刷新页面或重新输入同一客户查询,仍能从后端恢复最近一笔有效预存。
  3. 新增另一笔缴费后,客户缴费记录仍可通过分页查到之前的预存记录。
  4. 已红冲预存不再作为最近有效预存回显。
  5. 新预存记录显示正确的期初、期末余额;无法可靠恢复余额的旧数据显示 -
  6. 历史预存回显不参与当前收费选择和金额统计。

影响文件

后端预计修改:

  • PaymentRecordPageNewReqVO.java
  • PaymentQueryServiceImpl.java
  • ChargeServiceImpl.java
  • AccountLogMapper.java
  • 对应后端单元测试

前端预计修改:

  • src/api/operatingCharges/counterCharging/index.ts
  • src/views/operatingCharges/counterCharging/index.vue
  • 对应前端源码契约或页面状态测试