# 客户号查询选择客户内码设计

## 背景

在利率定价流程新增时，现有页面流程为：

1. 列表页点击“新增”。
2. 选择个人客户或企业客户。
3. 直接打开对应新增弹窗。
4. 用户手工输入客户内码和客户名称。

新需求要求在选择个人或企业后，先根据客户号调用映射接口查询客户信息，由用户从返回结果中选择一条客户内码，再自动带入新增弹窗。映射接口请求和返回字段以 `doc/上虞_客户内码客户_历史利率_映射表.xlsx` 的“客户号与客户内码映射”sheet 为准。

本次设计只覆盖客户号映射查询、选择和自动带入，不调整模型测算接口调用逻辑，不新增数据库字段，不改变现有流程创建接口的请求结构。

## 已确认规则

- 个人和企业分别有客户号映射接口地址。
- 当前先在本项目内新增两个 mock 接口，不直接调用生产网关。
- 配置文件新增客户号映射接口地址，当前配置指向本项目 mock 接口。
- mock 接口随机返回 1 条或多条客户映射数据。
- 后端业务接口返回给前端的字段保持下划线命名。
- 用户选择客户映射记录后，新增弹窗自动填入客户内码和客户名称。
- 新增弹窗中的客户内码和客户名称改为只读。
- 其余新增流程字段和提交接口保持现状。

## 接口字段

客户号映射请求参数：

| 字段 | 名称 |
| --- | --- |
| `cust_id` | 客户号 |

客户号映射返回字段：

| 字段 | 名称 | 用途 |
| --- | --- | --- |
| `cust_id` | 客户号 | 前端展示 |
| `cust_isn` | 客户内码 | 用户选择后作为流程创建入参 `custIsn` |
| `cust_name` | 客户名称 | 用户选择后作为流程创建入参 `custName` |
| `faith_day` | 用信天数 | 前端展示，辅助判断 |
| `balance_avg` | 存款年日均 | 前端展示，辅助判断 |
| `loan_count_his` | 历史贷款次数 | 前端展示，辅助判断 |
| `last_loan_date` | 上次贷款日期 | 前端展示，辅助判断 |

## 后端设计

新增客户号映射查询业务接口：

- `GET /loanPricing/workflow/customer-map/personal?custId=...`
- `GET /loanPricing/workflow/customer-map/corporate?custId=...`

业务接口职责：

1. 校验 `custId` 非空。
2. 根据个人或企业读取对应配置地址。
3. 使用 GET 调用配置地址，请求 mock 时传参名为 `cust_id`。
4. 解析 mock 返回结果。
5. 返回给前端的客户映射数据字段保持下划线，不转 camelCase。

新增 mock 接口：

- `GET /rate/pricing/mock/customer-map/personal?cust_id=...`
- `GET /rate/pricing/mock/customer-map/corporate?cust_id=...`

mock 接口职责：

1. 校验 `cust_id` 非空。
2. 随机生成 1 条或多条客户映射记录。
3. 返回字段使用 `cust_id`、`cust_isn`、`cust_name`、`faith_day`、`balance_avg`、`loan_count_his`、`last_loan_date`。

新增配置节点：

```yaml
customer-map:
  personal-url: http://localhost:63310/rate/pricing/mock/customer-map/personal
  corporate-url: http://localhost:63310/rate/pricing/mock/customer-map/corporate
```

配置节点与现有 `model.personal-url`、`model.corporate-url` 分开，避免客户号映射接口和模型测算接口混用。需要启动的 profile 均应包含该配置，当前统一指向本项目 mock 地址。

## 前端设计

新增一个客户号查询选择弹窗组件，个人和企业共用，通过 `customerType` 区分调用个人或企业查询接口。

弹窗内容：

- 输入框：客户号。
- 按钮：查询。
- 表格列：客户号、客户内码、客户名称、用信天数、存款年日均、历史贷款次数、上次贷款日期。
- 操作列：选择。

新增流程：

1. 列表页点击“新增”。
2. 打开现有客户类型选择弹窗。
3. 用户选择个人客户或企业客户。
4. 打开客户号查询选择弹窗。
5. 用户输入客户号并点击查询。
6. 前端调用对应业务接口。
7. 用户从结果表格选择一条客户映射记录。
8. 前端关闭查询选择弹窗，打开对应新增弹窗。
9. 新增弹窗将 `cust_isn` 带入 `custIsn`，将 `cust_name` 带入 `custName`。
10. 新增弹窗中客户内码和客户名称只读。
11. 用户继续填写其余字段并提交。

个人和企业新增弹窗需要增加一个入参，用于接收选中的客户映射记录。弹窗重置时清空本次客户选择，下一次新增必须重新查询选择。

现有创建接口保持不变：

- `POST /loanPricing/workflow/create/personal`
- `POST /loanPricing/workflow/create/corporate`

提交时仍只提交现有流程创建字段，不提交 `faith_day`、`balance_avg`、`loan_count_his`、`last_loan_date`。

## 异常处理

- 客户号为空：前端拦截，提示“请输入客户号”。
- 后端业务接口收到空 `custId`：返回参数错误。
- mock 接口收到空 `cust_id`：返回参数错误。
- 映射接口调用失败：后端返回错误，前端展示接口错误提示。
- 映射接口返回空列表：前端提示“未查询到客户信息”。
- 用户没有选择客户映射记录：不打开新增弹窗。
- 新增弹窗中的客户内码、客户名称虽然只读，但保留必填校验，防止异常状态提交空值。

## 测试方案

后端验证：

- 个人客户映射查询接口正常返回下划线字段。
- 企业客户映射查询接口正常返回下划线字段。
- 缺少 `custId` 时返回参数错误。
- mock 个人接口返回随机客户映射列表。
- mock 企业接口返回随机客户映射列表。
- 配置读取个人和企业映射地址，不复用模型测算地址。

前端验证：

- 客户号为空时点击查询，提示“请输入客户号”。
- 个人客户类型下调用个人映射查询接口。
- 企业客户类型下调用企业映射查询接口。
- 查询结果表格展示全部返回字段。
- 选择一条结果后，个人新增弹窗自动带入 `custIsn`、`custName`，且两项只读。
- 选择一条结果后，企业新增弹窗自动带入 `custIsn`、`custName`，且两项只读。
- 关闭新增弹窗后再次新增，需要重新查询客户号。

真实页面验证：

1. 启动后端进程，确保最新代码生效。
2. 启动前端页面。
3. 使用浏览器进入利率定价流程列表。
4. 跑通个人客户新增：新增 -> 选择个人 -> 查询客户号 -> 选择客户内码 -> 新增弹窗只读带入 -> 填写其余字段 -> 提交。
5. 跑通企业客户新增：新增 -> 选择企业 -> 查询客户号 -> 选择客户内码 -> 新增弹窗只读带入 -> 填写其余字段 -> 提交。
6. 验证列表或详情中新增流程存在。
7. 测试结束后关闭本次启动的前后端进程。

## 不在本次范围

- 不新增数据库字段。
- 不修改现有流程创建接口请求结构。
- 不把 `faith_day`、`balance_avg`、`loan_count_his`、`last_loan_date` 写入流程表。
- 不调整模型测算个人/企业接口。
- 不直接调用生产网关地址。
