# 柜台预存持久回显与缴费历史修复设计 日期: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` - 对应前端源码契约或页面状态测试