f
This commit is contained in:
6
internal/domains/api/services/processors/1.json
Normal file
6
internal/domains/api/services/processors/1.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"result":{
|
||||||
|
"score": 87,
|
||||||
|
"riskCode": "11001-3|21001-2"
|
||||||
|
}
|
||||||
|
}
|
||||||
16
internal/domains/api/services/processors/1.md
Normal file
16
internal/domains/api/services/processors/1.md
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
riskCode码result 参数说明
|
||||||
|
参数名 类型 说明
|
||||||
|
score Number 分数区间 0-100,分数越高表明风险越大
|
||||||
|
riskCode 风险码 21001、21002、
|
||||||
|
11001、11002、11003、11004、11005、
|
||||||
|
12001、12002、
|
||||||
|
1 低风险 2 中风险 3 高风险
|
||||||
|
21001 疑似恶意借贷 恶意多方借贷、以贷养贷、蓄意制造借贷纠纷等违规行为
|
||||||
|
21002 疑似职业撸囗子 职业从事网络贷款撸口子,无还款意愿的恶意行为
|
||||||
|
11001 疑似涉黑涉赌 涉嫌参与传销、在线赌博等违法行为
|
||||||
|
11002 疑似网络投机 参与在线外汇、虚拟币、石油贵金属等风险投机行为
|
||||||
|
11003 疑似营销欺诈 在网络平台运营活动中,组团薅羊毛、套利等违规行为
|
||||||
|
11004 疑似黑中介包装 介包装伪造冒用资料、黑产中介圈团成员、老赖反催收等
|
||||||
|
11005 疑似恶意套现 信用卡恶意套现、第三方平台消费分期套现等违规行为
|
||||||
|
12001 疑似黑产设备 存在模拟器、多开、群控、代理等作弊行为的黑产设备
|
||||||
|
12002 疑似黑产账号 疑似黑产组织非法包装的手机号、身份证、支付等账号
|
||||||
14
internal/domains/api/services/processors/2.json
Normal file
14
internal/domains/api/services/processors/2.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
"sjbq_zlbz": "0",
|
||||||
|
"sjbq_ychy": "0",
|
||||||
|
"sjbq_xjzl": "0",
|
||||||
|
"sjbq_ymd": "0",
|
||||||
|
"sjbq_sfcy": "0",
|
||||||
|
"sjbq_ycxw": "0",
|
||||||
|
"sjbq_sxxw": "0",
|
||||||
|
"sjbq_zfyc": "0",
|
||||||
|
"sjbq_qtyc": "0",
|
||||||
|
"sjbq_swhjyc": "0"
|
||||||
|
}
|
||||||
14
internal/domains/api/services/processors/2.md
Normal file
14
internal/domains/api/services/processors/2.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
## 返回字段说明
|
||||||
|
|
||||||
|
| 检测项目 | 字段名 | 检测结果 |
|
||||||
|
|---------|--------|---------|
|
||||||
|
| 资料包装中介 | sjbq_zlbz | 0:未命中;1:命中;介包装伪造冒用资料、黑产中介圈团成员、老赖反催收等 |
|
||||||
|
| 异常行业 | sjbq_ychy | 0:未命中;1:命中;涉嫌参与传销、在线赌博等违法行为 |
|
||||||
|
| 虚假资料 | sjbq_xjzl | 0:未命中;1:命中;疑似黑产组织非法包装的手机号、身份证、支付等账号 |
|
||||||
|
| 羊毛党 | sjbq_ymd | 0:未命中;1:命中;在网络平台运营活动中,组团薅羊毛、套利等违规行为 |
|
||||||
|
| 身份信息存疑 | sjbq_sfcy | 0:未命中;1:命中;存在模拟器、多开、群控、代理等作弊行为的黑产设备 |
|
||||||
|
| 严重异常行为 | sjbq_ycxw | 0:未命中;1:命中;参与在线外汇、虚拟币、石油贵金属等风险投机行为 |
|
||||||
|
| 失信行为 | sjbq_sxxw | 0:未命中;1:命中;职业从事网络贷款撸口子,无还款意愿的恶意行为 |
|
||||||
|
| 支付异常行为 | sjbq_zfyc | 0:未命中;1:命中;信用卡恶意套现、第三方平台消费分期套现等违规行为 |
|
||||||
|
| 其他异常行为 | sjbq_qtyc | 0:未命中;1:命中;恶意多方借贷、以贷养贷、蓄意制造借贷纠纷等违规行为 |
|
||||||
|
| 上网环境异常 | sjbq_swhjyc | 0:未命中;1:命中;对应风险码 11001、11002、11004、12001、12002 |
|
||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
|
|
||||||
"tyapi-server/internal/domains/api/dto"
|
"tyapi-server/internal/domains/api/dto"
|
||||||
"tyapi-server/internal/domains/api/services/processors"
|
"tyapi-server/internal/domains/api/services/processors"
|
||||||
"tyapi-server/internal/infrastructure/external/xingwei"
|
"tyapi-server/internal/infrastructure/external/nuoer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProcessIVYZ8I9JRequest IVYZ8I9J API处理方法 - 互联网行为推测
|
// ProcessIVYZ8I9JRequest IVYZ8I9J API处理方法 - 互联网行为推测
|
||||||
@@ -21,27 +21,37 @@ func ProcessIVYZ8I9JRequest(ctx context.Context, params []byte, deps *processors
|
|||||||
return nil, errors.Join(processors.ErrInvalidParam, err)
|
return nil, errors.Join(processors.ErrInvalidParam, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构建请求数据,将项目规范的字段名转换为 XingweiService 需要的字段名
|
body := map[string]string{
|
||||||
reqData := map[string]interface{}{
|
|
||||||
"name": paramsDto.Name,
|
"name": paramsDto.Name,
|
||||||
"idCardNum": paramsDto.IDCard,
|
"idCard": paramsDto.IDCard,
|
||||||
"phoneNumber": paramsDto.MobileNo,
|
"mobile": paramsDto.MobileNo,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 调用行为数据API,使用指定的project_id
|
nuoerDoCheckAPIKey := "kunyu_fix_v3_tg_model"
|
||||||
projectID := "CDJ-1074522823015198720"
|
ApiPath := "/v1/doCheck"
|
||||||
respBytes, err := deps.XingweiService.CallAPI(ctx, projectID, reqData)
|
|
||||||
|
resp, err := deps.NuoerService.CallAPI(ctx, nuoerDoCheckAPIKey, ApiPath, body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, xingwei.ErrNotFound) {
|
if errors.Is(err, nuoer.ErrDatasource) {
|
||||||
return nil, errors.Join(processors.ErrNotFound, err)
|
|
||||||
} else if errors.Is(err, xingwei.ErrDatasource) {
|
|
||||||
return nil, errors.Join(processors.ErrDatasource, err)
|
return nil, errors.Join(processors.ErrDatasource, err)
|
||||||
} else if errors.Is(err, xingwei.ErrSystem) {
|
|
||||||
return nil, errors.Join(processors.ErrSystem, err)
|
|
||||||
} else {
|
|
||||||
return nil, errors.Join(processors.ErrSystem, err)
|
|
||||||
}
|
}
|
||||||
|
if errors.Is(err, nuoer.ErrNotFound) {
|
||||||
|
return nil, errors.Join(processors.ErrNotFound, err)
|
||||||
|
}
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return respBytes, nil
|
// 将响应数据序列化为 JSON
|
||||||
|
respBytes, err := json.Marshal(resp.Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 transform 函数转换响应数据
|
||||||
|
transformedBytes, err := IVYZ8I9JTransformResponseFromBytes(respBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return transformedBytes, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
package ivyz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RiskCodeMapping 风险码到字段的映射
|
||||||
|
// 注意:一个风险码可能映射到多个字段
|
||||||
|
var RiskCodeMapping = map[string][]string{
|
||||||
|
"11001": {"sjbq_ychy", "sjbq_swhjyc"}, // 疑似涉黑涉诈 → 异常行业、上网环境异常
|
||||||
|
"11002": {"sjbq_ycxw", "sjbq_qtyc", "sjbq_swhjyc"}, // 疑似网络投机 → 严重异常行为、其他异常行为、上网环境异常
|
||||||
|
"11003": {"sjbq_ymd"}, // 疑似营销欺诈 → 羊毛党
|
||||||
|
"11004": {"sjbq_zlbz", "sjbq_swhjyc"}, // 疑似黑中介包装 → 资料包装中介、上网环境异常
|
||||||
|
"11005": {"sjbq_zfyc"}, // 疑似恶意套现 → 支付异常行为
|
||||||
|
"12001": {"sjbq_sfcy", "sjbq_swhjyc"}, // 疑似黑产设备 → 身份信息存疑、上网环境异常
|
||||||
|
"12002": {"sjbq_xjzl", "sjbq_swhjyc"}, // 疑似黑产账号 → 虚假资料、上网环境异常
|
||||||
|
"21001": {"sjbq_ycxw"}, // 疑似恶意借贷 → 严重异常行为
|
||||||
|
"21002": {"sjbq_sxxw"}, // 疑似职业撸口子 → 失信行为
|
||||||
|
}
|
||||||
|
|
||||||
|
// IVYZ8I9JTransformResponseFromBytes 将包含 riskCode 的格式转换为多个布尔字段格式
|
||||||
|
func IVYZ8I9JTransformResponseFromBytes(respBytes []byte) ([]byte, error) {
|
||||||
|
// 获取 result 字段中的 riskCode
|
||||||
|
riskCodeResult := gjson.GetBytes(respBytes, "result.riskCode")
|
||||||
|
if !riskCodeResult.Exists() {
|
||||||
|
// 如果没有 riskCode 字段,返回默认值
|
||||||
|
return createDefaultResponse()
|
||||||
|
}
|
||||||
|
|
||||||
|
riskCode := riskCodeResult.String()
|
||||||
|
result, err := parseRiskCodeToFields(riskCode)
|
||||||
|
if err != nil {
|
||||||
|
return createDefaultResponse()
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseRiskCodeToFields 解析 riskCode 并转换为多个字段
|
||||||
|
// riskCode 格式: "11001-3|21001-2"
|
||||||
|
// 其中 "11001" 是风险码,"3" 是风险等级(1低风险、2中风险、3高风险)
|
||||||
|
// 只要风险码存在,就认为命中并映射到对应字段
|
||||||
|
func parseRiskCodeToFields(riskCode string) (map[string]string, error) {
|
||||||
|
// 初始化所有字段为 "0"
|
||||||
|
result := map[string]string{
|
||||||
|
"sjbq_zlbz": "0", // 资料包装中介 - 对应 11004 疑似黑中介包装
|
||||||
|
"sjbq_ychy": "0", // 异常行业 - 对应 11001 疑似涉黑涉诈
|
||||||
|
"sjbq_xjzl": "0", // 虚假资料 - 对应 12002 疑似黑产账号
|
||||||
|
"sjbq_ymd": "0", // 羊毛党 - 对应 11003 疑似营销欺诈
|
||||||
|
"sjbq_sfcy": "0", // 身份信息存疑 - 对应 12001 疑似黑产设备
|
||||||
|
"sjbq_ycxw": "0", // 严重异常行为 - 对应 21001 疑似恶意借贷
|
||||||
|
"sjbq_sxxw": "0", // 失信行为 - 对应 21002 疑似职业撸口子
|
||||||
|
"sjbq_zfyc": "0", // 支付异常行为 - 对应 11005 疑似恶意套现
|
||||||
|
"sjbq_qtyc": "0", // 其他异常行为 - 对应 11002 疑似网络涉赌
|
||||||
|
"sjbq_swhjyc": "0", // 上网环境异常 - 对应 11001/11004/11002 涉黑涉诈/黑中介包装/网络涉赌
|
||||||
|
}
|
||||||
|
|
||||||
|
if riskCode == "" || riskCode == "-1" {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分割多个风险码(用 | 分隔)
|
||||||
|
riskCodes := strings.Split(riskCode, "|")
|
||||||
|
for _, rc := range riskCodes {
|
||||||
|
rc = strings.TrimSpace(rc)
|
||||||
|
if rc == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析风险码和风险等级(用 - 分隔)
|
||||||
|
parts := strings.Split(rc, "-")
|
||||||
|
if len(parts) < 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
code := parts[0]
|
||||||
|
|
||||||
|
// 只要风险码存在,就认为命中(不管风险等级是 1、2 还是 3)
|
||||||
|
// 一个风险码可能映射到多个字段
|
||||||
|
if fieldNames, ok := RiskCodeMapping[code]; ok {
|
||||||
|
for _, fieldName := range fieldNames {
|
||||||
|
result[fieldName] = "1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// createDefaultResponse 创建默认响应(所有字段为 "0")
|
||||||
|
func createDefaultResponse() ([]byte, error) {
|
||||||
|
result := map[string]string{
|
||||||
|
"sjbq_zlbz": "0",
|
||||||
|
"sjbq_ychy": "0",
|
||||||
|
"sjbq_xjzl": "0",
|
||||||
|
"sjbq_ymd": "0",
|
||||||
|
"sjbq_sfcy": "0",
|
||||||
|
"sjbq_ycxw": "0",
|
||||||
|
"sjbq_sxxw": "0",
|
||||||
|
"sjbq_zfyc": "0",
|
||||||
|
"sjbq_qtyc": "0",
|
||||||
|
"sjbq_swhjyc": "0",
|
||||||
|
}
|
||||||
|
return json.Marshal(result)
|
||||||
|
}
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"scoreywbase": "728"
|
|
||||||
}
|
|
||||||
{
|
|
||||||
"result": {
|
|
||||||
"score": "40.49"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
"result": {
|
|
||||||
"score": "50.46"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
"scoreywbase": "665"
|
|
||||||
}
|
|
||||||
@@ -7,10 +7,10 @@ import (
|
|||||||
|
|
||||||
"tyapi-server/internal/domains/api/dto"
|
"tyapi-server/internal/domains/api/dto"
|
||||||
"tyapi-server/internal/domains/api/services/processors"
|
"tyapi-server/internal/domains/api/services/processors"
|
||||||
"tyapi-server/internal/infrastructure/external/zhicha"
|
"tyapi-server/internal/infrastructure/external/nuoer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProcessJRZQ3c9RRequest JRZQ3c9R API处理方法 - 支付行为指数
|
// ProcessJRZQ3c9RRequest JRZQ3C9R API处理方法 - 支付行为指数
|
||||||
func ProcessJRZQ3C9RRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
|
func ProcessJRZQ3C9RRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
|
||||||
var paramsDto dto.JRZQ3C9RReq
|
var paramsDto dto.JRZQ3C9RReq
|
||||||
if err := json.Unmarshal(params, ¶msDto); err != nil {
|
if err := json.Unmarshal(params, ¶msDto); err != nil {
|
||||||
@@ -21,42 +21,37 @@ func ProcessJRZQ3C9RRequest(ctx context.Context, params []byte, deps *processors
|
|||||||
return nil, errors.Join(processors.ErrInvalidParam, err)
|
return nil, errors.Join(processors.ErrInvalidParam, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
encryptedName, err := deps.ZhichaService.Encrypt(paramsDto.Name)
|
body := map[string]string{
|
||||||
if err != nil {
|
"name": paramsDto.Name,
|
||||||
return nil, errors.Join(processors.ErrSystem, err)
|
"idCard": paramsDto.IDCard,
|
||||||
|
"mobile": paramsDto.MobileNo,
|
||||||
}
|
}
|
||||||
|
|
||||||
encryptedIDCard, err := deps.ZhichaService.Encrypt(paramsDto.IDCard)
|
nuoerDoCheckAPIKey := "paymentTagS26"
|
||||||
if err != nil {
|
ApiPath := "/v1/doCheck"
|
||||||
return nil, errors.Join(processors.ErrSystem, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
encryptedMobileNo, err := deps.ZhichaService.Encrypt(paramsDto.MobileNo)
|
resp, err := deps.NuoerService.CallAPI(ctx, nuoerDoCheckAPIKey, ApiPath, body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Join(processors.ErrSystem, err)
|
if errors.Is(err, nuoer.ErrDatasource) {
|
||||||
}
|
|
||||||
|
|
||||||
reqData := map[string]interface{}{
|
|
||||||
"name": encryptedName,
|
|
||||||
"idCard": encryptedIDCard,
|
|
||||||
"phone": encryptedMobileNo,
|
|
||||||
"authorized": paramsDto.Authorized,
|
|
||||||
}
|
|
||||||
|
|
||||||
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI036", reqData)
|
|
||||||
if err != nil {
|
|
||||||
if errors.Is(err, zhicha.ErrDatasource) {
|
|
||||||
return nil, errors.Join(processors.ErrDatasource, err)
|
return nil, errors.Join(processors.ErrDatasource, err)
|
||||||
} else {
|
}
|
||||||
|
if errors.Is(err, nuoer.ErrNotFound) {
|
||||||
|
return nil, errors.Join(processors.ErrNotFound, err)
|
||||||
|
}
|
||||||
return nil, errors.Join(processors.ErrSystem, err)
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 将响应数据转换为JSON字节
|
// 将响应数据序列化为 JSON
|
||||||
respBytes, err := json.Marshal(respData)
|
respBytes, err := json.Marshal(resp.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Join(processors.ErrSystem, err)
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return respBytes, nil
|
// 使用 transform 函数转换响应数据,展开 result 字段
|
||||||
|
transformedBytes, err := JRZQ3C9RTransformResponseFromBytes(respBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Join(processors.ErrSystem, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return transformedBytes, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package jrzq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
|
)
|
||||||
|
|
||||||
|
// JRZQ3C9RTransformResponseFromBytes 从字节数组转换响应数据,将 result 字段展开到根级别
|
||||||
|
// respBytes: 原始响应数据的字节数组
|
||||||
|
// Returns: 转换后的数据字节数组
|
||||||
|
func JRZQ3C9RTransformResponseFromBytes(respBytes []byte) ([]byte, error) {
|
||||||
|
// 使用 gjson 获取 result 字段
|
||||||
|
resultResult := gjson.GetBytes(respBytes, "result")
|
||||||
|
if !resultResult.Exists() {
|
||||||
|
// 如果没有 result 字段,直接返回原始数据
|
||||||
|
return respBytes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回 result 字段的原始 JSON
|
||||||
|
return []byte(resultResult.Raw), nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user