This commit is contained in:
Mrx
2026-06-10 16:05:47 +08:00
parent 50f21283e8
commit 9d4a3f584c
3 changed files with 412 additions and 21 deletions

View File

@@ -0,0 +1,33 @@
|
| 产品编码 | 产品名称 | 价格 |
| :--- | :--- | :--- |
|| mobile4Verify | 运营商状态查询 | ¥0.04 / 次 |
|| mobileDuration | 手机入网时长 | ¥0.10 / 次 |
|| mobile3Verify | 运营商三要素验证 | ¥0.15 / 次 |
|| realNameAuth | 实名认证 | ¥0.02 / 次 |
|| blackListV121_3 | 债务欺诈黑名单V3 | ¥0.22 / 次 |
|| loanRiskTagV10 | 风险变量V10 | ¥0.38 / 次 |
|| loanRiskTagV21 | 信用全景V21 | ¥0.30 / 次 |
|| loanRiskTagV11 | 借贷意向查询 | ¥0.20 / 次 |
|| loanRiskTagV12 | 特殊名单 | ¥0.00 / 次 |
|| mobileRiskV709 | 投诉风险筛查V709 | ¥0.20 / 次 |
|| blackListV110 | 特殊名单V110 | ¥0.20 / 次 |
|| personalLawsuit_cv1 | 个人法院涉诉定制版 | ¥0.20 / 次 |
| 产品编码 | 产品名称 | 价格 | API接口名称 |
| :--- | :--- | :--- | :--- |
|| YYSYE7V5 | 手机在网状态V即时版 | ¥0.03 / 次 | /v1/mobile_status/check |
|| YYSYP0T4 | 手机号码在网时长V即时版 | ¥0.15 / 次 | /v2/mobile_online/check |
|| YYSYK9R4 | 全网手机三要素验证 | ¥0.16 / 次 | /communication/personal/1979 |
|| IVYZN2P8 | 公安二要素政务版 | ¥0.02 / 次 | /v4/id_card/check |
|| JRZQV3HM | 债务欺诈黑名单V3 | ¥0.22 / 次 | blackListV121_3 |
|| JRZQ4B6C | 探针C | ¥0.38 / 次 | loanRiskTagV10 |
|| JRZQ5E9F | 借选指数 | ¥0.30 / 次 | loanRiskTagV21 |
|| JRZQ3C7B | 借贷意向验证 | ¥0.20 / 次 | loanRiskTagV11 |
|| JRZQV7MD | 特殊名单 | ¥0.00 / 次 | loanRiskTagV12 |
|| JRZQVT43 | 投诉风险筛查V709投诉黑名单 | ¥0.20 / 次 | mobileRiskV709 |
|| JRZQV0MD | 行为黑名单 | ¥0.20 / 次 | blackListV110 |
|| FLXG7E8F | 个人司法数据查询 | ¥0.20 / 次 | personalLawsuit_cv1 |

View File

@@ -0,0 +1,174 @@
# DWBG9FB3 个人风险档案 — 响应结构说明
## 概述
`DWBG9FB3`(个人风险档案)本身是一个独立接口,接收三要素入参后,**并发**调用 12 个子产品处理器,将各子接口原始返回数据**直接拼接融合**为一个 JSON 对象返回。
- 不使用 `success` / `data` / `error` 等包装结构
- 顶层 key 为简短**英文单词**字段名
- 每个大字段的 value 即为对应子处理器的原始返回对象
- 子产品调用失败时,该字段值为 `null`,不影响其他字段
## 字段映射表
| 产品编码 | 产品名称 | 英文字段名 | 子处理器 |
| :--- | :--- | :--- | :--- |
| YYSYE7V5 | 手机在网状态V即时版 | `presence` | `ProcessYYSYE7V5Request` |
| YYSYP0T4 | 手机号码在网时长V即时版 | `duration` | `ProcessYYSYP0T4Request` |
| YYSYK9R4 | 全网手机三要素验证 | `triple` | `ProcessYYSYK9R4Request` |
| IVYZN2P8 | 公安二要素政务版 | `identity` | `ProcessIVYZN2P8Request` |
| JRZQV3HM | 债务欺诈黑名单V3 | `fraud` | `ProcessJRZQV3HMRequest` |
| JRZQ4B6C | 探针C | `probe` | `ProcessJRZQ4B6CRequest` |
| JRZQ5E9F | 借选指数 | `rating` | `ProcessJRZQ5E9FRequest` |
| JRZQ3C7B | 借贷意向验证 | `intent` | `ProcessJRZQ3C7BRequest` |
| JRZQV7MD | 特殊名单 | `special` | `ProcessJRZQV7MDRequest` |
| JRZQVT43 | 投诉风险筛查V709 | `complaint` | `ProcessJRZQVT43Request` |
| JRZQV0MD | 行为黑名单 | `behavior` | `ProcessJRZQV0MDRequest` |
| FLXG7E8F | 个人司法数据查询 | `judicial` | `ProcessFLXG7E8FRequest` |
## 请求参数
```json
{
"id_card": "110101199001011234",
"name": "张三",
"mobile_no": "13800138000"
}
```
## 响应结构
顶层为一个扁平对象12 个字段并列,每个字段 value 为子处理器原始返回的 JSON 对象:
```json
{
"presence": { },
"duration": { },
"triple": { },
"identity": { },
"fraud": { },
"probe": { },
"rating": { },
"intent": { },
"special": { },
"complaint": { },
"behavior": { },
"judicial": { }
}
```
## 响应示例
```json
{
"presence": {
"status": "1",
"operator": "1"
},
"duration": {
"result": "3",
"desc": "在网时长12-24个月"
},
"triple": {
"state": "1",
"operator": "1"
},
"identity": {
"result": 0,
"desc": "一致",
"sex": "男",
"birthday": "1990-01-01",
"address": "北京市东城区"
},
"fraud": {
"hit": 0
},
"probe": {
"score": 650,
"risk_level": "B"
},
"rating": {
"score": 720,
"level": "A"
},
"intent": {
"apply_loan": {
"d7": { "id": 0, "cell": 1 },
"m1": { "id": 1, "cell": 2 }
}
},
"special": {
"hit": 0
},
"complaint": {
"hit": 0
},
"behavior": {
"hit": 0
},
"judicial": {
"judicial_data": {
"lawsuitStat": {
"count_total": 0,
"count_jie_total": 0,
"count_wei_total": 0
},
"breachCaseList": [],
"consumptionRestrictionList": []
}
}
}
```
## 部分失败示例
某个子产品查无记录或异常时,对应字段为 `null`,其余字段正常返回:
```json
{
"presence": {
"status": "1",
"operator": "1"
},
"judicial": null
}
```
## 调用流程
```mermaid
flowchart LR
A[DWBG9FB3 请求] --> B[参数校验]
B --> C[并发调用 12 个子处理器]
C --> D1[presence]
C --> D2[duration]
C --> D3[triple]
C --> D4[identity]
C --> D5[fraud]
C --> D6[probe]
C --> D7[rating]
C --> D8[intent]
C --> D9[special]
C --> D10[complaint]
C --> D11[behavior]
C --> D12[judicial]
D1 --> E[拼接融合为一个对象]
D2 --> E
D3 --> E
D4 --> E
D5 --> E
D6 --> E
D7 --> E
D8 --> E
D9 --> E
D10 --> E
D11 --> E
D12 --> E
E --> F[返回 JSON]
```
## 实现说明
- 复用 `dwbg8b4d` 中的 `callProcessor`,通过 `CombService.GetProcessor` 按产品编码路由。
- 12 个 goroutine 并发执行,结果写入 `map[英文字段名]子处理器原始数据`
- 子产品数据保持各处理器原有返回结构,不做二次转换。

View File

@@ -4,13 +4,34 @@ import (
"context"
"encoding/json"
"errors"
"fmt"
"sync"
"tyapi-server/internal/domains/api/dto"
"tyapi-server/internal/domains/api/services/processors"
"tyapi-server/internal/infrastructure/external/nuoer"
"tyapi-server/internal/shared/logger"
"go.uber.org/zap"
)
// ProcessDWBG9FB3Request DWBG9FB3 API处理方法 - 个人风险档案
// dwbg9FB3FieldNames 子产品编码 → 响应字段名(单词缩写)
var dwbg9FB3FieldNames = map[string]string{
"YYSYE7V5": "presence", // 在网状态
"YYSYP0T4": "duration", // 在网时长
"YYSYK9R4": "triple", // 三要素验证
"IVYZN2P8": "identity", // 二要素认证
"JRZQV3HM": "fraud", // 债务欺诈黑名单
"JRZQ4B6C": "probe", // 探针C
"JRZQ5E9F": "rating", // 借选指数
"JRZQ3C7B": "intent", // 借贷意向
"JRZQV7MD": "special", // 特殊名单
"JRZQVT43": "complaint", // 投诉风险
"JRZQV0MD": "behavior", // 行为黑名单
"FLXG7E8F": "judicial", // 司法数据
}
// ProcessDWBG9FB3Request DWBG9FB3 API处理方法 - 个人风险档案
// 并发调用子产品处理器,将各子接口返回数据以大数据英文字段名拼接融合为一个对象
func ProcessDWBG9FB3Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.DWBG9FB3Req
if err := json.Unmarshal(params, &paramsDto); err != nil {
@@ -21,30 +42,193 @@ func ProcessDWBG9FB3Request(ctx context.Context, params []byte, deps *processors
return nil, errors.Join(processors.ErrInvalidParam, err)
}
body := map[string]string{
"idCard": paramsDto.IDCard,
"name": paramsDto.Name,
"mobile": paramsDto.MobileNo,
}
log := logger.GetGlobalLogger()
log.Info("开始处理个人风险档案请求",
zap.String("name", paramsDto.Name),
zap.String("id_card", maskIDCard(paramsDto.IDCard)),
zap.String("mobile_no", maskMobile(paramsDto.MobileNo)),
)
nuoerDoCheckAPIKey := "gamaReportPageP01"
ApiPath := "/v1/doCheck"
result := collectDWBG9FB3SubProducts(ctx, paramsDto, deps, log)
resp, err := deps.NuoerService.CallAPI(ctx, nuoerDoCheckAPIKey, ApiPath, body)
if err != nil {
if errors.Is(err, nuoer.ErrNotFound) {
return nil, errors.Join(processors.ErrNotFound, err)
}
if errors.Is(err, nuoer.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
}
return nil, errors.Join(processors.ErrSystem, err)
}
respBytes, err := json.Marshal(resp.Data)
respBytes, err := json.Marshal(result)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
log.Info("个人风险档案处理完成", zap.Int("field_count", len(result)))
return respBytes, nil
}
type dwbg9fb3APICall struct {
apiCode string
fieldName string
params map[string]interface{}
}
func collectDWBG9FB3SubProducts(
ctx context.Context,
params dto.DWBG9FB3Req,
deps *processors.ProcessorDependencies,
log *zap.Logger,
) map[string]interface{} {
apiCalls := []dwbg9fb3APICall{
{apiCode: "YYSYE7V5", fieldName: dwbg9FB3FieldNames["YYSYE7V5"], params: map[string]interface{}{"mobile_no": params.MobileNo}},
{apiCode: "YYSYP0T4", fieldName: dwbg9FB3FieldNames["YYSYP0T4"], params: map[string]interface{}{"mobile_no": params.MobileNo}},
{
apiCode: "YYSYK9R4",
fieldName: dwbg9FB3FieldNames["YYSYK9R4"],
params: map[string]interface{}{
"mobile_no": params.MobileNo,
"id_card": params.IDCard,
"name": params.Name,
},
},
{
apiCode: "IVYZN2P8",
fieldName: dwbg9FB3FieldNames["IVYZN2P8"],
params: map[string]interface{}{
"id_card": params.IDCard,
"name": params.Name,
},
},
{
apiCode: "JRZQV3HM",
fieldName: dwbg9FB3FieldNames["JRZQV3HM"],
params: map[string]interface{}{
"id_card": params.IDCard,
"name": params.Name,
"mobile_no": params.MobileNo,
},
},
{
apiCode: "JRZQ4B6C",
fieldName: dwbg9FB3FieldNames["JRZQ4B6C"],
params: map[string]interface{}{
"mobile_no": params.MobileNo,
"id_card": params.IDCard,
"name": params.Name,
"authorized": "1",
},
},
{
apiCode: "JRZQ5E9F",
fieldName: dwbg9FB3FieldNames["JRZQ5E9F"],
params: map[string]interface{}{
"mobile_no": params.MobileNo,
"id_card": params.IDCard,
"name": params.Name,
"authorized": "1",
},
},
{
apiCode: "JRZQ3C7B",
fieldName: dwbg9FB3FieldNames["JRZQ3C7B"],
params: map[string]interface{}{
"mobile_no": params.MobileNo,
"id_card": params.IDCard,
"name": params.Name,
"authorized": "1",
},
},
{
apiCode: "JRZQV7MD",
fieldName: dwbg9FB3FieldNames["JRZQV7MD"],
params: map[string]interface{}{
"id_card": params.IDCard,
"name": params.Name,
"mobile_no": params.MobileNo,
},
},
{
apiCode: "JRZQVT43",
fieldName: dwbg9FB3FieldNames["JRZQVT43"],
params: map[string]interface{}{
"id_card": params.IDCard,
"name": params.Name,
"mobile_no": params.MobileNo,
},
},
{
apiCode: "JRZQV0MD",
fieldName: dwbg9FB3FieldNames["JRZQV0MD"],
params: map[string]interface{}{
"id_card": params.IDCard,
"name": params.Name,
"mobile_no": params.MobileNo,
},
},
{
apiCode: "FLXG7E8F",
fieldName: dwbg9FB3FieldNames["FLXG7E8F"],
params: map[string]interface{}{
"name": params.Name,
"id_card": params.IDCard,
"mobile_no": params.MobileNo,
},
},
}
type callResult struct {
fieldName string
data interface{}
err error
}
results := make(chan callResult, len(apiCalls))
var wg sync.WaitGroup
for _, apiCall := range apiCalls {
wg.Add(1)
go func(ac dwbg9fb3APICall) {
defer wg.Done()
defer func() {
if r := recover(); r != nil {
log.Error("调用子产品处理器时发生panic",
zap.String("api_code", ac.apiCode),
zap.String("field_name", ac.fieldName),
zap.Any("panic", r),
)
results <- callResult{ac.fieldName, nil, fmt.Errorf("处理器panic: %v", r)}
}
}()
paramsBytes, err := json.Marshal(ac.params)
if err != nil {
results <- callResult{ac.fieldName, nil, err}
return
}
data, err := callProcessor(ctx, ac.apiCode, paramsBytes, deps)
results <- callResult{ac.fieldName, data, err}
}(apiCall)
}
go func() {
wg.Wait()
close(results)
}()
output := make(map[string]interface{}, len(apiCalls))
successCount := 0
for result := range results {
if result.err != nil {
log.Warn("子产品调用失败,该字段置空",
zap.String("field_name", result.fieldName),
zap.Error(result.err),
)
output[result.fieldName] = nil
continue
}
output[result.fieldName] = result.data
successCount++
}
log.Info("子产品调用完成",
zap.Int("total", len(apiCalls)),
zap.Int("success", successCount),
zap.Int("failed", len(apiCalls)-successCount),
)
return output
}