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

160 lines
7.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 柜台预存持久回显与缴费历史修复设计
日期2026-07-13
## 背景
柜台无欠费客户完成预存后,页面会临时插入一条“预存款 / 收讫”记录。该记录只存在于前端内存,重新查询客户时会被清除。与此同时,客户缴费记录接口虽然查询了多条有效支付主单,却只返回其中最新一条,导致较早的预存记录被后续缴费记录覆盖。缴费记录响应中的期初余额、期末余额字段也未从可靠的账务快照赋值。
本次修复以 `biz_payment_record` 为缴费记录主数据源,以 `biz_account_log` 的余额变动快照为余额证据,建立“预存成功后显示、重新查询后仍能从后端恢复、客户历史可完整分页查询”的闭环。
## 目标
1. 无欠费客户完成柜台预存后,当前页面继续展示“预存款 / 收讫”记录。
2. 重新查询同一无欠费客户时,页面从后端支付记录恢复最近一笔有效预存,不依赖前端缓存。
3. 客户详情的缴费记录按时间倒序返回全部有效历史,并保持正确分页、统计和导出语义。
4. 新产生的预存记录能够展示可追溯的期初余额和期末余额。
5. 已红冲支付记录不作为有效预存回显,也不进入正常缴费历史。
## 非目标
- 本次不修复主副卡付款户解析错误和柜台有效余额读取错误。
- 本次不对无法可靠关联账户流水的旧支付记录伪造期初、期末余额。
- 本次不把所有历史预存与当前待收费账单混合展示。
- 本次不引入浏览器本地缓存、`localStorage` 或跨会话前端状态作为账务记录来源。
## 方案选择
采用“后端持久记录回显”方案:
- 缴费历史接口返回全部符合条件的有效支付主单,再由现有分页参数截取当前页。
- 查询请求增加可选业务场景过滤;柜台页面用 `DEPOSIT_TOPUP` 精确查询最近一笔有效预存。
- 柜台页面仅在当前客户没有待缴账单时回显最近预存,避免历史记录进入可勾选的待收费账单集合。
- 新预存交易将支付主单 ID 写入对应账户流水来源字段,并由查询层映射余额变动前后值。
不采用以下方案:
- 仅保留前端临时数组或写入浏览器缓存:换页面、换设备或重新登录后仍会丢失,也不能作为账务证据。
- 无条件把最近预存和待缴账单混合展示:会让历史收款记录进入当前收费语境,增加误选和重复收费风险。
## 后端设计
### 缴费历史查询
将当前“查询全部候选记录后只保留第一条”的实现改为返回全部有效候选记录:
- 继续按 `payTime``id` 倒序排列。
- 继续使用现有可见性规则过滤已红冲及非正常记录。
- `skipCount``maxResultCount` 在过滤后的完整集合上分页。
- `totalCount``totalAmount``topUpCount``topUpTotalMoney` 均基于过滤后的完整集合计算。
- 导出使用与页面查询相同的过滤规则,但不受页面分页截断。
`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)` 完成待缴账单和统计查询后:
- 有待缴账单:按现有逻辑展示待缴账单,不混入历史预存。
- 无待缴账单:调用缴费历史接口,传入 `custId``bizScene=DEPOSIT_TOPUP``skipCount=0``maxResultCount=1`
- 查询到有效预存:转换为不可勾选的“预存款 / 收讫”展示行。
- 没有有效预存:保持空表状态。
- 恢复查询失败:不影响客户和待缴账单主查询,记录错误并提示“最近预存记录加载失败”。
历史回显行只用于确认最近一次成功预存,不参与选中账单、应收统计或再次收费计算。
### 客户缴费记录
客户详情沿用现有分页组件和接口参数。后端返回完整结果后:
- 翻页能看到较早记录。
- 统计金额和笔数使用完整过滤结果。
- 有可靠账户流水关联的新预存显示期初、期末余额。
- 无可靠余额证据的旧记录继续显示 `-`,不得转成 `0`
## 错误处理
- 支付主单创建或余额增加失败时事务整体回滚,前端不插入成功行。
- 最近预存查询失败不清空客户基本信息和待缴账单结果。
- 接口返回空记录时不沿用上一个客户的预存展示行。
- 已红冲记录不可通过页面刷新重新出现。
## 测试设计
### 后端单元测试
1. 两条有效支付记录均进入候选集合,分页返回正确记录和总数。
2. 最新记录已红冲时被过滤,较早有效记录仍可查询。
3. `bizScene=DEPOSIT_TOPUP` 时只返回预存记录。
4. 汇总金额、预存笔数和预存金额基于全部有效记录计算。
5. 新柜台预存先生成支付主单,再写入带 `paymentRecordId` 的账户流水。
6. 有账户流水关联时正确映射 `balanceBefore``balanceAfter`;无关联时余额字段为空。
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`
- 对应前端源码契约或页面状态测试