Files
ccdi/docs/design/2026-03-23-credit-info-maintenance-design.md
2026-03-23 21:24:09 +08:00

13 KiB
Raw Blame History

征信维护设计文档

1. 背景

当前仓库已经具备两项征信解析基础能力:

  • ccdi-lsfx 已提供 POST /lsfx/credit/parse 征信解析联调接口,可接收 HTML 并返回 lx_headerlx_debtlx_publictype
  • lsfx-mock-server 已支持从征信 HTML 中解析员工姓名和身份证号,能够稳定返回本地联调 payload

本次需求是在“信息维护”菜单下新增“征信维护”菜单,支持批量导入员工征信 HTML 文件并提交上传。系统需要调用现有征信解析接口完成数据解析,并把返回结果批量落库。页面同时要展示当前已维护的员工征信信息,并支持删除现有征信数据。

2. 已确认约束

  • 菜单挂在“信息维护”下,页面为独立菜单,不挂到员工维护弹窗内
  • 页面主列表按员工维度展示摘要,一行一个员工
  • 批量上传按员工维度原子化处理,一个员工失败不影响其他员工
  • 负债明细表名固定为 ccdi_debts_info
  • 负债信息按照 assets/征信解析/ccdi_debts_info.xlsx 设计
  • 负面信息按照接口字段单独设计一张表
  • 每个员工只保留最新的征信信息
  • 列表操作列支持删除现有征信信息
  • 不新增征信主表,主列表通过明细表实时聚合

3. 目标

  • 在“信息维护”下新增“征信维护”菜单与页面
  • 支持一次上传多个 .html/.htm 征信文件
  • 上传后逐文件调用征信解析接口
  • 按员工身份证号归户,并按“最新征信优先”规则覆盖写入
  • 在页面展示员工维度的征信摘要列表
  • 在详情中展示负债明细和负面信息
  • 支持按员工删除当前已维护的征信数据

4. 非目标

  • 不改造现有 POST /lsfx/credit/parse 的协议语义
  • 不新增异步任务、轮询状态页或上传历史模块
  • 不保存多版本征信记录
  • 不保存原始 HTML 文件或原始 payload JSON
  • 不增加说明书之外的补丁性兜底方案

5. 方案对比

5.1 方案 A三张业务表增加征信主表

新增征信主表保存员工最新摘要,再配合负债表和负面信息表。

优点:

  • 列表查询简单
  • 聚合逻辑更少

缺点:

  • 引入额外主表,超出本次最短路径
  • 同一份摘要数据会与明细形成重复维护

5.2 方案 B仅保留两张业务表列表实时聚合

只建设 ccdi_debts_info 与负面信息表,主列表按员工维度实时聚合展示。

优点:

  • 满足“负债表固定命名”和“负面信息单独建表”
  • 不引入额外主表,路径最短
  • 删除和覆盖逻辑仍然清晰,按员工清空两张表即可

缺点:

  • 列表查询需要做员工维度聚合

5.3 方案 C两张业务表加原始 payload 存档

在方案 B 基础上额外保存原始 payload 或原始 HTML。

优点:

  • 排查解析问题时信息更全

缺点:

  • 增加冗余与维护成本
  • 超出当前需求

6. 最终方案

采用方案 B仅新增 ccdi_debts_infoccdi_credit_negative_info 两张业务表,列表按员工维度实时聚合,不新增征信主表。

选择原因:

  • 满足“每个员工只保留最新征信信息”的要求
  • 满足“负债信息按 Excel 设计、负面信息单独建表”的要求
  • 不额外增加主表,保持最短路径实现
  • 删除逻辑直接按员工清理两张业务表,语义明确

7. 总体架构

业务链路如下:

征信维护页面 -> 征信维护业务接口 -> 征信维护服务 -> /lsfx/credit/parse -> 征信解析服务

职责拆分如下:

  • 征信维护页面

    • 选择多个 HTML 文件并提交上传
    • 展示员工维度征信摘要列表
    • 打开详情弹窗查看负债明细与负面信息
    • 删除员工当前征信数据
  • 征信维护业务接口

    • 对外提供上传、列表、详情、删除接口
    • 不直接把前端耦合到 ccdi-lsfx
  • 征信维护服务

    • 逐文件调用征信解析接口
    • 根据员工身份证号归户
    • 校验“是否为最新征信”
    • 单员工事务覆盖写入两张业务表
  • ccdi-lsfx

    • 保持现有征信解析客户端能力
    • 继续作为外部征信解析接入边界

8. 数据模型设计

8.1 负债明细表 ccdi_debts_info

一条记录表示一条负债明细,字段按 assets/征信解析/ccdi_debts_info.xlsx 设计:

  • debt_idBIGINT 主键,自增
  • person_idVARCHAR(18),员工身份证号
  • person_nameVARCHAR(100),员工姓名
  • query_dateDATE,征信查询日期
  • debt_main_typeVARCHAR(50),负债大类
  • debt_sub_typeVARCHAR(50),负债小类
  • creditor_typeVARCHAR(50),债权人类型
  • debt_nameVARCHAR(100),负债名称
  • principal_balanceDECIMAL(18,2),负债本金余额
  • debt_total_amountDECIMAL(18,2),负债总额
  • debt_statusVARCHAR(20),负债状态
  • create_byVARCHAR(64)
  • create_timeDATETIME
  • update_byVARCHAR(64)
  • update_timeDATETIME

建议索引:

  • idx_person_id(person_id)
  • idx_query_date(query_date)
  • idx_person_query_date(person_id, query_date)

8.2 负面信息表 ccdi_credit_negative_info

一条记录表示一个员工当前最新征信对应的负面信息汇总:

  • negative_idBIGINT 主键,自增
  • person_idVARCHAR(18),员工身份证号
  • person_nameVARCHAR(100),员工姓名
  • query_dateDATE,征信查询日期
  • civil_cntINT,民事案件笔数
  • enforce_cntINT,强制执行笔数
  • adm_cntINT,行政处罚笔数
  • civil_lmtDECIMAL(18,2),民事案件金额
  • enforce_lmtDECIMAL(18,2),强制执行金额
  • adm_lmtDECIMAL(18,2),行政处罚金额
  • create_byVARCHAR(64)
  • create_timeDATETIME
  • update_byVARCHAR(64)
  • update_timeDATETIME

建议索引:

  • uk_person_id(person_id) 唯一索引

9. 解析字段映射设计

9.1 归户字段

从解析结果 lx_header 中读取:

  • query_cert_no -> 员工身份证号 person_id
  • query_cust_name -> 员工姓名 person_name
  • report_time -> 征信查询日期 query_date

query_cert_no 作为员工唯一归户标识,并校验该身份证号必须存在于 ccdi_base_staff

9.2 lx_debtccdi_debts_info 的映射

lx_debt 当前为 7 组固定字段,每组映射成一条负债明细:

接口前缀 负债大类 负债小类 债权人类型 负债名称
uncle_bank_house 银行 住房贷款 银行 未结清银行住房贷款
uncle_bank_car 银行 汽车贷款 银行 未结清银行汽车贷款
uncle_bank_manage 银行 经营贷款 银行 未结清银行经营贷款
uncle_bank_consume 银行 消费贷款 银行 未结清银行消费贷款
uncle_bank_other 银行 其他贷款 银行 未结清银行其他贷款
uncle_not_bank 非银 非银行贷款 非银 未结清非银行贷款
uncle_credit_cart 银行 信用卡 银行 未结清信用卡

字段映射规则:

  • *_bal -> principal_balance
  • *_lmt -> debt_total_amount
  • *_state -> debt_status

落库过滤规则:

  • 当某组 principal_balancedebt_total_amount 都为空或 0,且 debt_status 为空时,不生成明细记录
  • 其余情况生成一条明细

9.3 lx_publictypeccdi_credit_negative_info 的映射

按接口字段直接映射:

  • civil_cnt -> civil_cnt
  • enforce_cnt -> enforce_cnt
  • adm_cnt -> adm_cnt
  • civil_lmt -> civil_lmt
  • enforce_lmt -> enforce_lmt
  • adm_lmt -> adm_lmt

10. 最新征信判定与覆盖策略

系统只保留员工最新征信,规则如下:

  • person_id 作为员工唯一标识
  • query_date 作为征信最新时间判定字段
  • 员工上传新文件时:
    • 若库中无现有征信数据,直接写入
    • 若新 query_date 大于等于现有 query_date,覆盖旧数据
    • 若新 query_date 小于现有 query_date,该员工本次文件判定为失败,不覆盖

单员工覆盖写入步骤:

  1. 删除 ccdi_debts_info 中该员工旧记录
  2. 删除 ccdi_credit_negative_info 中该员工旧记录
  3. 插入本次解析后的最新负债明细
  4. 插入本次解析后的最新负面信息

以上 4 步置于同一事务中,保证员工维度原子化。

11. 页面设计

11.1 菜单

在“信息维护”下新增菜单:

  • 菜单名称:征信维护
  • 路由:creditInfo
  • 组件:ccdiCreditInfo/index
  • 权限前缀:ccdi:creditInfo:*

11.2 顶部操作区

  • 批量上传征信 HTML 按钮
  • 查询条件:
    • 员工姓名
    • 柜员号
    • 身份证号
    • 是否已维护征信

上传弹窗要求:

  • 仅允许选择 .html/.htm
  • 支持一次选择多个文件
  • 提交后调用业务上传接口
  • 接口返回后直接展示成功/失败汇总及失败清单

11.3 主列表

主列表按员工一行展示,字段建议:

  • 员工姓名
  • 柜员号
  • 身份证号
  • 所属部门
  • 最近征信查询日期
  • 负债笔数
  • 负债总额
  • 民事案件笔数
  • 强制执行笔数
  • 行政处罚笔数
  • 操作

聚合规则:

  • 基础信息来自 ccdi_base_staff
  • 最近征信查询日期、负债笔数、负债总额来自 ccdi_debts_info
  • 三类负面计数来自 ccdi_credit_negative_info
  • 任一业务表存在数据,即视为“已维护征信”

11.4 详情弹窗

详情弹窗分为两部分:

  • 摘要区域

    • 员工姓名
    • 身份证号
    • 征信查询日期
    • 负债总额
    • 负债笔数
    • 民事案件笔数
    • 强制执行笔数
    • 行政处罚笔数
  • 明细区域

    • 负债信息表格
    • 负面信息汇总卡片

负债表格字段:

  • 负债大类
  • 负债小类
  • 债权人类型
  • 负债名称
  • 负债本金余额
  • 负债总额
  • 负债状态

负面信息展示字段:

  • 民事案件笔数 / 金额
  • 强制执行笔数 / 金额
  • 行政处罚笔数 / 金额

11.5 删除交互

列表点击删除时,提示:

确认删除该员工当前已维护的征信信息吗?

确认后删除该员工在两张业务表中的全部数据。

12. 接口设计

新增业务接口,前端不直接调用 /lsfx/credit/parse

12.1 批量上传

  • 方法:POST
  • 路径:/ccdi/creditInfo/upload
  • 入参:多个 HTML 文件
  • 返回:
    • 总文件数
    • 成功数
    • 失败数
    • 失败明细列表

失败明细建议字段:

  • fileName
  • personId
  • personName
  • reason

12.2 列表分页查询

  • 方法:GET
  • 路径:/ccdi/creditInfo/list
  • 功能:分页查询员工征信摘要列表

12.3 详情查询

  • 方法:GET
  • 路径:/ccdi/creditInfo/{personId}
  • 功能:查询员工征信摘要、负债明细和负面信息

12.4 删除

  • 方法:DELETE
  • 路径:/ccdi/creditInfo/{personId}
  • 功能:删除员工当前征信数据

13. 后端设计

建议改动集中在 ccdi-info-collection 模块,新增独立征信维护资源。

建议新增:

  • controller/CcdiCreditInfoController.java
  • service/ICcdiCreditInfoService.java
  • service/impl/CcdiCreditInfoServiceImpl.java
  • domain/CcdiCreditNegativeInfo.java
  • domain/dto/CreditInfoUploadResultDTO.java
  • domain/vo/CreditInfoListVO.java
  • domain/vo/CreditInfoDetailVO.java
  • mapper/CcdiCreditNegativeInfoMapper.java
  • mapper/CcdiCreditInfoQueryMapper.java
  • resources/mapper/...

职责说明:

  • CcdiCreditInfoController

    • 暴露上传、列表、详情、删除接口
  • CcdiCreditInfoService

    • 协调解析、归户、最新记录校验、覆盖写入
  • CcdiCreditNegativeInfoMapper

    • 维护负面信息表增删查
  • CcdiCreditInfoQueryMapper

    • 承担员工维度列表聚合查询和详情聚合查询

14. 异常处理

上传过程中逐文件处理,失败不影响其他员工成功:

  • 文件后缀非法:失败原因为“文件格式不支持”
  • 解析接口调用失败:失败原因为“征信解析失败”
  • 解析成功但身份证号为空:失败原因为“未解析到员工身份证号”
  • 身份证号未匹配到员工:失败原因为“未匹配到员工信息”
  • 上传征信日期早于当前最新记录:失败原因为“上传征信日期早于当前已维护最新记录”
  • 员工覆盖写入事务失败:失败原因为“征信数据保存失败”

删除接口按幂等处理:

  • 即使员工当前无征信数据,也返回删除成功

15. 测试方案

15.1 后端测试

  • 上传服务测试

    • 单文件解析成功后正确写入两张业务表
    • 同员工新日期文件覆盖旧数据
    • 同员工旧日期文件被拒绝覆盖
    • 一个员工失败不影响其他员工成功
    • 删除后两张表数据均被清空
  • 聚合查询测试

    • 只有负债信息
    • 只有负面信息
    • 两者都有
    • 两者都没有
    • 分页下聚合字段正确
  • 控制器测试

    • 批量上传成功
    • 混合成功/失败上传
    • 详情查询成功/无数据
    • 删除接口幂等

15.2 前端验证

  • 上传多个 HTML 文件并查看结果提示
  • 列表按员工维度展示聚合摘要
  • 详情弹窗正确显示负债表和负面信息
  • 删除后该员工征信摘要即时消失
  • 前端生产构建通过

16. 文档与脚本产出要求

本次实施阶段需同步补充:

  • 后端实施计划:docs/plans/backend/
  • 前端实施计划:docs/plans/frontend/
  • SQL 脚本:sql/sql/migration/
  • 实施记录:docs/reports/implementation/

文档落点需遵循仓库目录规范,避免写入错误目录。