You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ElectronClient/tax-guidance/docs/实名制采集保存-Java改写说明.md

264 lines
8.0 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 实名制采集保存smz.saveSmzcjxx— Java 改写说明
> 对应原 C#`CallClient/TaxTrueNameCaiji.cs` → `BaishuiModel.SmzSaveSmzcjxx`
> 目标:前端传入手机号 / 邮箱 / 固话 / 比对序号Java 后端再转发调用百税 `smz.saveSmzcjxx`。
---
## 1. 原 C# 行为摘要
```text
办税员弹窗 TaxerInfo
→ 点击「实名采集」(未采集时可见)
→ 弹出 TaxTrueNameCaiji
→ 用户填写:手机号(必填)、电子邮箱、固定电话
→ 点击登记
→ 调用百税 smz.saveSmzcjxx
入参rxsfzBdxh、sjhm、dzyx、lxdh
→ result.code == "00" → 提示成功,关闭弹窗,隐藏采集按钮并回填手机号
```
比对序号 `rxsfzBdxh` 在原客户端来自办税员窗已加载的 `CompareCode`(取号时人脸比对结果),不在采集窗输入。
---
## 2. 改写后的职责划分
| 角色 | 职责 |
|------|------|
| 前端 | 收集并校验:手机号、电子邮箱、固定电话、人像身份证比对序号;调用 Java API |
| Java 后端 | 接收前端参数 → 校验 → 组装百税请求 → 调用 `smz.saveSmzcjxx` → 将结果返回前端 |
| 百税网关 | 按原协议处理采集保存 |
前端不再直连百税;百税 URL、编码、表单协议只存在于 Java 侧。
---
## 3. Java 对外 API暴露给前端
### 3.1 接口定义(建议)
| 项 | 建议值 |
|----|--------|
| Method | `POST` |
| Path | `/api/smz/save-cjxx`(可按现有工程规范调整) |
| Content-Type | `application/json` |
### 3.2 请求 Body
```json
{
"rxsfzBdxh": "418206",
"sjhm": "13800138000",
"dzyx": "a@example.com",
"lxdh": "0571-88888888"
}
```
| 字段 | 类型 | 必填 | 含义 | 对应百税字段 |
|------|------|------|------|--------------|
| `rxsfzBdxh` | string | 是 | 人像身份证比对序号 | `rxsfzBdxh` |
| `sjhm` | string | 是 | 手机号码 | `sjhm` |
| `dzyx` | string | 否 | 电子邮箱 | `dzyx` |
| `lxdh` | string | 否 | 固定电话 | `lxdh` |
### 3.3 前端校验(与 C# 对齐)
| 规则 | 说明 |
|------|------|
| `sjhm` 不能为空 | C#`所登记的手机号不能为空` |
| 占位文案不作为有效值 | C# 会把「请输入手机号码」等占位当成空串 |
| `rxsfzBdxh` 不能为空 | 原客户端从办税员窗带入Java 版由前端显式传入,后端应二次校验 |
邮箱、固话格式是否严格校验:原 C# 未做正则Java 侧可选增强,非必须。
### 3.4 响应 Body建议
透传百税业务结果,便于前端按原逻辑提示:
```json
{
"success": true,
"code": "00",
"mess": "保存成功"
}
```
| 字段 | 说明 |
|------|------|
| `success` | Java 层业务成功标志(建议:`code == "00"` 或 `"0"` 时为 true |
| `code` | 百税 `result.code` |
| `mess` | 百税 `result.mess`;空时可回落「保存成功」 |
失败示例:
```json
{
"success": false,
"code": "99",
"mess": "无返回错误信息"
}
```
网关/网络异常时返回明确错误信息HTTP 状态可用 `502` / `500`,或统一 `200` + `success=false`(与现有工程约定一致即可)。
---
## 4. Java 调用百税 `smz.saveSmzcjxx`
### 4.1 百税协议(与 BaiShuiSDK 一致)
| 项 | 值 |
|----|-----|
| Method | `POST` |
| URL | 配置项,对应原 `REALNAME_CHECK_API` / `ApiUrl` |
| Content-Type | `application/x-www-form-urlencoded` |
| Body | `domain.ywId=smz.saveSmzcjxx&domain.parmJson={UrlEncode(JSON)}` |
`parmJson` 序列化规则:
1. 整对象转 JSON`ver`、`bid` 及业务字段)
2. **忽略 null 字段**
3. 中文保持原文,不做 `\uXXXX`
4. 再对整段 JSON 做 URL 编码;建议与 C# `HttpUtils.UrlEncode(..., Encoding.Default)` 对齐(中文环境多为 GBK`%XX` 大写),避免 `2003 JSON解析出错`
### 4.2 组装给百税的 `parmJson`
```json
{
"ver": "1.0",
"bid": "smz.saveSmzcjxx",
"rxsfzBdxh": "418206",
"sjhm": "13800138000",
"dzyx": "a@example.com",
"lxdh": "0571-88888888"
}
```
字段映射前端入参原样写入同名字段空的可选字段不传null 忽略)。
### 4.3 百税响应
HTTP 外层:
```json
{
"domain": {
"ywId": "smz.saveSmzcjxx",
"retJson": "{\"result\":{\"code\":\"00\",\"mess\":\"保存成功\"}}"
}
}
```
解析 `domain.retJson` 后:
```json
{
"result": {
"code": "00",
"mess": "保存成功"
}
}
```
无额外业务字段(`JhxtSaveSmzcjxxResult` 仅含 `code` / `mess`)。
C# SDK 中 `SmzSaveSmzcjxx` **不强制**校验 `code == "00"` 后抛异常,而是把 `result` 交回 UI 判断。Java 建议:
- 能解析出 `result`:按 `code` 组装对外响应,不抛中断(除非工程统一要求失败抛异常)
- 通信失败 / 无 `retJson`:记日志并返回失败给前端
---
## 5. 后端处理流程
```text
① 接收前端 JSON
② 校验 sjhm、rxsfzBdxh 非空(可选:手机号格式)
③ 组装 BsRequest
ver=1.0, bid=smz.saveSmzcjxx,
rxsfzBdxh, sjhm, dzyx?, lxdh?
④ POST 百税网关form-urlencoded + UrlEncode
⑤ 解析 domain.retJson → result.code / result.mess
⑥ 返回给前端success / code / mess
```
伪代码:
```java
@PostMapping("/api/smz/save-cjxx")
public ApiResult saveCjxx(@RequestBody SaveSmzcjxxReq req) {
if (isBlank(req.getSjhm())) {
return ApiResult.fail("所登记的手机号不能为空");
}
if (isBlank(req.getRxsfzBdxh())) {
return ApiResult.fail("人像身份证比对序号不能为空");
}
Map<String, Object> parm = new LinkedHashMap<>();
parm.put("ver", "1.0");
parm.put("bid", "smz.saveSmzcjxx");
parm.put("rxsfzBdxh", req.getRxsfzBdxh());
parm.put("sjhm", req.getSjhm());
if (notBlank(req.getDzyx())) parm.put("dzyx", req.getDzyx());
if (notBlank(req.getLxdh())) parm.put("lxdh", req.getLxdh());
BsResult result = bsClient.execute("smz.saveSmzcjxx", parm);
boolean ok = "00".equals(result.getCode()) || "0".equals(result.getCode());
String mess = blankToDefault(result.getMess(), ok ? "保存成功" : "无返回错误信息");
return new ApiResult(ok, result.getCode(), mess);
}
```
---
## 6. 配置项
| 配置键(建议) | 含义 | 对应原系统 |
|----------------|------|------------|
| `baishui.api-url` / `REALNAME_CHECK_API` | 百税网关完整 URL | `TaxTrueNameCaiji.ApiUrl` / `SystemControl.Get("REALNAME_CHECK_API")` |
| 超时时间 | HTTP 超时 | C# `PostSync` 约 60s 量级 |
---
## 7. 前端对接要点(办税员窗复刻)
1. 打开采集弹窗前,确保已有 `rxsfzBdxh`(来自票的比对序号 / 办税员信息加载结果)。
2. 用户填写 `sjhm`(必填)、`dzyx`、`lxdh`。
3. 调用 Java `/api/smz/save-cjxx`
4. `success == true`(或 `code == "00"`
- 提示成功
- 关闭弹窗
- 隐藏「实名采集」按钮
- 回填展示手机号(原 `SetTruceNameCaijiOk`
5. 失败:展示 `mess`
说明:查询是否已采集仍可走原逻辑对应的 `smz.getSmzcjxx`(若也改写到 Java另文说明**本文仅覆盖采集保存**。
---
## 8. 实现清单
| 优先级 | 项 | 说明 |
|--------|----|------|
| P0 | 对外 REST API | 暴露四个参数,校验手机号与比对序号 |
| P0 | 百税 Client | form-urlencoded + `domain.ywId` / `domain.parmJson` + UrlEncode |
| P0 | 调用 `smz.saveSmzcjxx` | 字段映射与响应解析 |
| P1 | 统一错误码 / 日志 | 记录入参(可脱敏手机号)与百税返回 |
| P2 | 手机号格式校验 | 原 C# 未做,可选 |
---
## 9. 源码索引
| 说明 | 路径 |
|------|------|
| 采集弹窗 / 提交 | `CallClient/TaxTrueNameCaiji.cs` |
| 办税员窗打开采集 | `CallClient/WPF/TaxerInfo.xaml.cs``Caiji_Click` |
| 成功回调 | `TaxerInfo.SetTruceNameCaijiOk` |
| 请求模型 | `BaiShuiSDK/Request/SmzJhxtSaveSmzcjxxRequest.cs``bid = smz.saveSmzcjxx` |
| 响应模型 | `BaiShuiSDK/Response/SmzJhxtSaveSmzcjxxResponse.cs` |
| SDK 封装 | `BaiShuiSDK/Model/BaishuiModel.cs``SmzSaveSmzcjxx` |
| HTTP 协议 | `BaiShuiSDK/Client/BsDefaultClient.cs` |
| 协议参考 | `BaiShuiSDK/smz.rxsfzBd-接口说明.md`协议相同bid 不同) |