This commit is contained in:
2026-04-21 22:36:48 +08:00
commit 488c695fdf
748 changed files with 266838 additions and 0 deletions

View File

@@ -0,0 +1,111 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"strings"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shujubao"
)
// YYSY09CDResponse 最终返回结构
// code: 1000一致 1001不一致 1002查无
type YYSY09CDResponse struct {
Code string `json:"code"`
Data YYSY09CDResponseData `json:"data"`
}
type YYSY09CDResponseData struct {
Msg string `json:"msg"` // 一致/不一致/查无
PhoneType string `json:"phoneType"` // CMCC/CUCC/CTCC/CBN
Code int `json:"code"` // 1000/1001/1002
EncryptType string `json:"encryptType"` // MD5
}
// ProcessYYSY09CDRequest YYSY09CD API处理方法 - 运营商三要素查询
func ProcessYYSY09CDRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSY09CDReq
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
reqParams := map[string]interface{}{
"key": "c115708d915451da8f34a23e144dda6b",
"name": paramsDto.Name,
"idcard": paramsDto.IDCard,
"mobile": paramsDto.MobileNo,
}
apiPath := "/communication/personal/1979"
data, err := deps.ShujubaoService.CallAPI(ctx, apiPath, reqParams)
if err != nil {
if errors.Is(err, shujubao.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
}
if errors.Is(err, shujubao.ErrQueryEmpty) {
return nil, errors.Join(processors.ErrNotFound, err)
}
return nil, errors.Join(processors.ErrSystem, err)
}
out, err := mapYYSYK9R4ToYYSY09CD(data)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return json.Marshal(out)
}
// yysyk9r4Resp 数据宝 YYSYK9R4 接口 data 结构
// state: 1-验证一致 2-验证不一致 3-异常情况
type yysyk9r4Resp struct {
State string `json:"state"`
}
// mapYYSYK9R4ToYYSY09CD 数据宝 YYSYK9R4 的 data -> YYSY09CD 最终格式
// state: 1->1000一致 2->1001不一致 其它->1002查无
func mapYYSYK9R4ToYYSY09CD(data interface{}) (*YYSY09CDResponse, error) {
var r yysyk9r4Resp
b, err := json.Marshal(data)
if err != nil {
return nil, err
}
if err := json.Unmarshal(b, &r); err != nil {
return nil, err
}
// code/msg: 1000一致 1001不一致 1002查无
var codeStr string
var codeInt int
var msg string
switch strings.TrimSpace(r.State) {
case "1":
codeStr = "1000"
codeInt = 1000
msg = "一致"
case "2":
codeStr = "1001"
codeInt = 1001
msg = "不一致"
default:
codeStr = "1002"
codeInt = 1002
msg = "查无"
}
return &YYSY09CDResponse{
Code: codeStr,
Data: YYSY09CDResponseData{
Msg: msg,
PhoneType: "",
Code: codeInt,
EncryptType: "MD5",
},
}, nil
}

View File

@@ -0,0 +1,48 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shumai"
)
// ProcessYYSY35TARequest YYSY35TA API 运营商归属地数卖处理方法数脉
func ProcessYYSY35TARequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSY35TAReq
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
reqFormData := map[string]interface{}{
"mobile": paramsDto.MobileNo,
}
// 以表单方式调用数脉 API参数在 CallAPIForm 内转为 application/x-www-form-urlencoded
apiPath := "/v4/phone/number" // 接口路径,根据数脉文档填写(如 v4/xxx
respBytes, err := deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData)
if err != nil {
if errors.Is(err, shumai.ErrNotFound) {
// 查无记录情况
return nil, errors.Join(processors.ErrNotFound, err)
} else if errors.Is(err, shumai.ErrDatasource) {
// 数据源错误
return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, shumai.ErrSystem) {
// 系统错误
return nil, errors.Join(processors.ErrSystem, err)
} else {
// 其他未知错误
return nil, errors.Join(processors.ErrSystem, err)
}
}
return respBytes, nil
}

View File

@@ -0,0 +1,44 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shumai"
)
// ProcessYYSY3E7FRequest YYSY3E7F API处理方法 - 空号检测
func ProcessYYSY3E7FRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSY3E7FReq
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
reqFormData := map[string]interface{}{
"mobile": paramsDto.MobileNo,
}
// 以表单方式调用数脉 API参数在 CallAPIForm 内转为 application/x-www-form-urlencoded
apiPath := "/v4/mobile_empty/check" // 接口路径,根据数脉文档填写(
respBytes, err := deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData)
if err != nil {
if errors.Is(err, shumai.ErrDatasource) {
// 数据源错误
return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, shumai.ErrSystem) {
// 系统错误
return nil, errors.Join(processors.ErrSystem, err)
} else {
// 其他未知错误
return nil, errors.Join(processors.ErrSystem, err)
}
}
return respBytes, nil
}

View File

@@ -0,0 +1,45 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shumai"
)
// ProcessYYSY3M8SRequest YYSY3M8S 运营商二要素 API处理方法
func ProcessYYSY3M8SRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSY3M8SReq
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
reqFormData := map[string]interface{}{
"mobile": paramsDto.MobileNo,
"name": paramsDto.Name,
}
// 以表单方式调用数脉 API参数在 CallAPIForm 内转为 application/x-www-form-urlencoded
apiPath := "/v4/mobile_two/check" // 接口路径,根据数脉文档填写(如 v4/xxx
respBytes, err := deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData)
if err != nil {
if errors.Is(err, shumai.ErrDatasource) {
// 数据源错误
return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, shumai.ErrSystem) {
// 系统错误
return nil, errors.Join(processors.ErrSystem, err)
} else {
// 其他未知错误
return nil, errors.Join(processors.ErrSystem, err)
}
}
return respBytes, nil
}

View File

@@ -0,0 +1,45 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
)
// ProcessYYSY4B21Request YYSY4B21 API处理方法
func ProcessYYSY4B21Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSY4B21Req
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
encryptedMobileNo, err := deps.WestDexService.Encrypt(paramsDto.MobileNo)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
reqData := map[string]interface{}{
"data": map[string]interface{}{
"phone": encryptedMobileNo,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "G25BJ02", reqData)
if err != nil {
if errors.Is(err, westdex.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
}
return respBytes, nil
}

View File

@@ -0,0 +1,45 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
)
// ProcessYYSY4B37Request YYSY4B37 API处理方法
func ProcessYYSY4B37Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSY4B37Req
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
encryptedMobileNo, err := deps.WestDexService.Encrypt(paramsDto.MobileNo)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
reqData := map[string]interface{}{
"data": map[string]interface{}{
"phone": encryptedMobileNo,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "G02BJ02", reqData)
if err != nil {
if errors.Is(err, westdex.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
}
return respBytes, nil
}

View File

@@ -0,0 +1,62 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/zhicha"
)
// ProcessYYSY4F2ERequest YYSY4F2E API处理方法 - 运营商三要素验证(详版)
func ProcessYYSY4F2ERequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSY4F2EReq
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
encryptedName, err := deps.ZhichaService.Encrypt(paramsDto.Name)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
encryptedIDCard, err := deps.ZhichaService.Encrypt(paramsDto.IDCard)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
encryptedMobileNo, err := deps.ZhichaService.Encrypt(paramsDto.MobileNo)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
reqData := map[string]interface{}{
"name": encryptedName,
"idCard": encryptedIDCard,
"phone": encryptedMobileNo,
"authorized": paramsDto.Authorized,
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI002", reqData)
if err != nil {
if errors.Is(err, zhicha.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
}
// 将响应数据转换为JSON字节
respBytes, err := json.Marshal(respData)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return respBytes, nil
}

View File

@@ -0,0 +1,101 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"strings"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shumai"
)
// shumaiMobileTransferResp 数脉 /v4/mobile-transfer/query 返回结构
type shumaiMobileTransferResp struct {
OrderNo string `json:"order_no"`
Channel string `json:"channel"` // 移动/电信/联通
Status int `json:"status"` // 0-在网 1-不在网
Desc string `json:"desc"` // 不在网原因status=1时有效
}
// ProcessYYSY6D9ARequest YYSY6D9A API处理方法 - 全网手机号状态验证A
func ProcessYYSY6D9ARequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSY6D9AReq
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
reqFormData := map[string]interface{}{
"mobile": paramsDto.MobileNo,
}
// 以表单方式调用数脉 API参数在 CallAPIForm 内转为 application/x-www-form-urlencoded
apiPath := "/v4/mobile-transfer/query"
respBytes, err := deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData)
if err != nil {
if errors.Is(err, shumai.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, shumai.ErrSystem) {
return nil, errors.Join(processors.ErrSystem, err)
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
}
mapped, err := mapShumaiToYYSY6D9A(respBytes)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return json.Marshal(mapped)
}
// mapShumaiToYYSY6D9A 将数脉 mobile-transfer 响应映射为最终 state/operators 格式
// state: 1-正常 2-不在网(空号) 3-无短信能力 4-欠费 5-长时间关机 6-关机 7-通话中 -1-查询失败
// operators: 1-移动 2-联通 3-电信
func mapShumaiToYYSY6D9A(dataBytes []byte) (map[string]string, error) {
var r shumaiMobileTransferResp
if err := json.Unmarshal(dataBytes, &r); err != nil {
return map[string]string{"state": "-1", "operators": ""}, nil // 解析失败视为查询失败
}
operators := ispNameToCode(strings.TrimSpace(r.Channel))
state := statusDescToState(r.Status, r.Desc)
return map[string]string{
"state": state,
"operators": operators,
}, nil
}
// statusDescToState status: 0-在网 1-不在网desc 为不在网原因
func statusDescToState(status int, desc string) string {
if status == 0 {
return "1" // 正常
}
// status == 1 不在网,根据 desc 推断 state
d := strings.TrimSpace(desc)
if strings.Contains(d, "销号") || strings.Contains(d, "空号") {
return "2" // 不在网(空号)
}
if strings.Contains(d, "无短信") || strings.Contains(d, "在网不可用") {
return "3" // 无短信能力
}
if strings.Contains(d, "欠费") {
return "4" // 欠费
}
if strings.Contains(d, "长时间关机") {
return "5" // 长时间关机
}
if strings.Contains(d, "关机") {
return "6" // 关机
}
if strings.Contains(d, "通话中") {
return "7" // 通话中
}
return "2" // 不在网但未明确原因,默认空号
}

View File

@@ -0,0 +1,49 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/zhicha"
)
// ProcessYYSY6F2BRequestYYSY 6F2B API处理方法 - 手机消费区间验证
func ProcessYYSY6F2BRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSY6F2BReq
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
encryptedMobileNo, err := deps.ZhichaService.Encrypt(paramsDto.MobileNo)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
reqData := map[string]interface{}{
"phone": encryptedMobileNo,
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI041", reqData)
if err != nil {
if errors.Is(err, zhicha.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
}
// 将响应数据转换为JSON字节
respBytes, err := json.Marshal(respData)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return respBytes, nil
}

View File

@@ -0,0 +1,58 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
)
// ProcessYYSY6F2ERequest YYSY6F2E API处理方法
func ProcessYYSY6F2ERequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSY6F2EReq
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
encryptedName, err := deps.WestDexService.Encrypt(paramsDto.Name)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
encryptedIDCard, err := deps.WestDexService.Encrypt(paramsDto.IDCard)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
encryptedMobileNo, err := deps.WestDexService.Encrypt(paramsDto.MobileNo)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
reqData := map[string]interface{}{
"data": map[string]interface{}{
"name": encryptedName,
"idNo": encryptedIDCard,
"phone": encryptedMobileNo,
"phoneType": paramsDto.MobileType,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "G15BJ02", reqData)
if err != nil {
if errors.Is(err, westdex.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
}
return respBytes, nil
}

View File

@@ -0,0 +1,113 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"strings"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shumai"
)
// shumaiMobileTransferResp 数脉 /v4/mobile-transfer/query 携号转网返回结构
type shumaiMobileTransfer7d3eResp struct {
OrderNo string `json:"order_no"`
Mobile string `json:"mobile"`
Area *string `json:"area"`
IspType string `json:"ispType"` // 转网前运营商
NewIspType string `json:"newIspType"` // 转网后运营商
}
// yysy7d3eResp 携号转网查询对外响应结构
type yysy7d3eResp struct {
BatchNo string `json:"batchNo"`
QueryResult []yysy7d3eQueryItem `json:"queryResult"`
}
type yysy7d3eQueryItem struct {
Mobile string `json:"mobile"`
Result string `json:"result"` // 0:否 1:是
After string `json:"after"` // 转网后:-1未知 1移动 2联通 3电信 4广电
Before string `json:"before"` // 转网前:同上
}
// ProcessYYSY7D3ERequest YYSY7D3E API处理方法 - 携号转网查询
func ProcessYYSY7D3ERequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSY7D3EReq
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
reqFormData := map[string]interface{}{
"mobile": paramsDto.MobileNo,
}
// 以表单方式调用数脉 API参数在 CallAPIForm 内转为 application/x-www-form-urlencoded
apiPath := "/v4/mobile-transfer/query"
respBytes, err := deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData)
if err != nil {
if errors.Is(err, shumai.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, shumai.ErrSystem) {
return nil, errors.Join(processors.ErrSystem, err)
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
}
mapped, err := mapShumaiToYYSY7D3E(respBytes)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return json.Marshal(mapped)
}
// mapShumaiToYYSY7D3E 将数脉携号转网响应映射为 batchNo + queryResult 格式
func mapShumaiToYYSY7D3E(dataBytes []byte) (*yysy7d3eResp, error) {
var r shumaiMobileTransfer7d3eResp
if err := json.Unmarshal(dataBytes, &r); err != nil {
return nil, err
}
before := ispNameToCodeTransfer(strings.TrimSpace(r.IspType))
after := ispNameToCodeTransfer(strings.TrimSpace(r.NewIspType))
result := "0"
if r.IspType != "" && r.NewIspType != "" && strings.TrimSpace(r.IspType) != strings.TrimSpace(r.NewIspType) {
result = "1" // 转网前与转网后不同即为携号转网
}
out := &yysy7d3eResp{
BatchNo: r.OrderNo,
QueryResult: []yysy7d3eQueryItem{
{
Mobile: r.Mobile,
Result: result,
After: after,
Before: before,
},
},
}
return out, nil
}
// ispNameToCodeTransfer 运营商名称转编码:-1未知 1移动 2联通 3电信 4广电
func ispNameToCodeTransfer(name string) string {
switch name {
case "移动":
return "1"
case "联通":
return "2"
case "电信":
return "3"
case "广电":
return "4"
default:
return "-1"
}
}

View File

@@ -0,0 +1,100 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shumai"
)
// ProcessYYSY8B1CRequest YYSY8B1C API处理方法 - 手机在网时长
func ProcessYYSY8B1CRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSY8B1CReq
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
reqFormData := map[string]interface{}{
"mobile": paramsDto.MobileNo,
}
// 以表单方式调用数脉 API参数在 CallAPIForm 内转为 application/x-www-form-urlencoded
apiPath := "/v2/mobile_online/check" // 接口路径,根据数脉文档填写(如 v4/xxx
respBytes, err := deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData)
if err != nil {
if errors.Is(err, shumai.ErrDatasource) {
// 数据源错误
return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, shumai.ErrSystem) {
// 系统错误
return nil, errors.Join(processors.ErrSystem, err)
} else {
// 其他未知错误
return nil, errors.Join(processors.ErrSystem, err)
}
}
var shumaiResp struct {
OrderNo string `json:"order_no"`
Channel string `json:"channel"` // cmcc/cucc/ctcc/gdcc
Time string `json:"time"` // [0,3),[3,6),[6,12),[12,24),[24,-1)
}
if err := json.Unmarshal(respBytes, &shumaiResp); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
// 映射 channel -> operators
operators := channelToOperators(shumaiResp.Channel)
// 映射 time 区间 -> inTime
inTime := timeIntervalToInTime(shumaiResp.Time)
out := map[string]string{
"inTime": inTime,
"operators": operators,
}
return json.Marshal(out)
}
// channelToOperators 运营商编码转名称cmcc-移动 cucc-联通 ctcc-电信 gdcc-广电
func channelToOperators(channel string) string {
switch channel {
case "cmcc":
return "移动"
case "cucc":
return "联通"
case "ctcc":
return "电信"
case "gdcc":
return "广电"
default:
return ""
}
}
// timeIntervalToInTime 在网时间区间转 inTime 值
// [0,3)->0, [3,6)->3, [6,12)->6, [12,24)->12, [24,-1)->24
// 空或异常->99, 查无记录->-1此处按空/未知处理为99
func timeIntervalToInTime(timeInterval string) string {
switch timeInterval {
case "[0,3)":
return "0"
case "[3,6)":
return "3"
case "[6,12)":
return "6"
case "[12,24)":
return "12"
case "[24,-1)":
return "24"
case "":
return "-1"
default:
return "99"
}
}

View File

@@ -0,0 +1,47 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/xingwei"
)
// ProcessYYSY8C2DRequest YYSY8C2D API处理方法 - 运营商三要素查询
func ProcessYYSY8C2DRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSY8C2DReq
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
// 构建请求数据,将项目规范的字段名转换为 XingweiService 需要的字段名
reqData := map[string]interface{}{
"name": paramsDto.Name,
"idCardNum": paramsDto.IDCard,
"phoneNumber": paramsDto.MobileNo,
}
// 调用行为数据API使用指定的project_id
projectID := "CDJ-1100244702166183936"
respBytes, err := deps.XingweiService.CallAPI(ctx, projectID, reqData)
if err != nil {
if errors.Is(err, xingwei.ErrNotFound) {
return nil, errors.Join(processors.ErrNotFound, err)
} else if errors.Is(err, xingwei.ErrDatasource) {
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)
}
}
return respBytes, nil
}

View File

@@ -0,0 +1,51 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/xingwei"
)
// ProcessYYSY8F3ARequest YYSY8F3A API处理方法 - 行为数据查询
func ProcessYYSY8F3ARequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSY8F3AReq
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
// 构建请求数据,直接传递姓名、身份证、手机号
reqData := map[string]interface{}{
"name": paramsDto.Name,
"idCardNum": paramsDto.IDCard,
"phoneNumber": paramsDto.MobileNo,
}
// 调用行为数据API使用指定的project_id
projectID := "CDJ-1100244697766359040"
respBytes, err := deps.XingweiService.CallAPI(ctx, projectID, reqData)
if err != nil {
if errors.Is(err, xingwei.ErrNotFound) {
// 查空情况,返回特定的查空错误
return nil, errors.Join(processors.ErrNotFound, err)
} else if errors.Is(err, xingwei.ErrDatasource) {
// 数据源错误
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)
}
}
return respBytes, nil
}

View File

@@ -0,0 +1,158 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"strconv"
"strings"
"time"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shumai"
)
// shumaiMobileThreeResp 数脉 /v4/mobile_three/check 返回的 data 结构
// result: 0-一致 1-不一致 2-无记录channel: cmcc/cucc/ctcc/gdcc
type shumaiMobileThreeResp struct {
OrderNo string `json:"order_no"`
Result string `json:"result"`
Desc string `json:"desc"`
Channel string `json:"channel"`
Sex string `json:"sex"`
Birthday string `json:"birthday"`
Address string `json:"address"`
}
// yysy9a1bOut 最终返回格式
// result: 01一致 02不一致 03不确定 04失败/虚拟号type: 1移动 2联通 3电信 4广电
type yysy9a1bOut struct {
OrderNo string `json:"orderNo"`
HandleTime string `json:"handleTime"`
Type string `json:"type"` // 1:移动 2:联通 3:电信 4:广电
Result string `json:"result"`
Gender string `json:"gender"`
Age string `json:"age"`
Remark string `json:"remark"`
}
// ProcessYYSY9A1BRequest YYSY9A1B API处理方法 - 运营商三要素查询
func ProcessYYSY9A1BRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSY9A1BReq
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
reqFormData := map[string]interface{}{
"idcard": paramsDto.IDCard,
"name": paramsDto.Name,
"mobile": paramsDto.MobileNo,
}
// 以表单方式调用数脉 API参数在 CallAPIForm 内转为 application/x-www-form-urlencoded
apiPath := "/v4/mobile_three/check"
// 先尝试使用政务接口app_id2 和 app_secret2
respBytes, err := deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData, true)
if err != nil {
// 使用实时接口app_id 和 app_secret重试
respBytes, err = deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData, false)
// 如果重试后仍然失败,返回错误
if err != nil {
if errors.Is(err, shumai.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, shumai.ErrSystem) {
return nil, errors.Join(processors.ErrSystem, err)
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
}
}
// 将数脉 data 映射为最终返回格式
out, err := mapShumaiMobileThreeToYYSY9A1B(respBytes)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return json.Marshal(out)
}
// mapShumaiMobileThreeToYYSY9A1B 数脉 mobile_three/check 的 data -> 最终格式
// result: 0->01 1->02 2->04 其它->04remark: 认证一致/认证不一致/无记录/虚拟号gender: 男->1 女->2type: cmcc->1 cucc->2 ctcc->3 gdcc->4
func mapShumaiMobileThreeToYYSY9A1B(dataBytes []byte) (*yysy9a1bOut, error) {
var r shumaiMobileThreeResp
if err := json.Unmarshal(dataBytes, &r); err != nil {
return nil, err
}
// result: 01一致 02不一致 03不确定 04失败/虚拟号;原 2-无记录 及 其它 均映射为 04
// remark: 认证一致;认证不一致;无记录;虚拟号
var res, remark string
switch strings.TrimSpace(r.Result) {
case "0":
res = "01"
remark = "认证一致"
case "1":
res = "02"
remark = "认证不一致"
case "2":
res = "04"
remark = "无记录"
default:
res = "04"
remark = "虚拟号"
}
// type: 运营商 channel -> 1移动 2联通 3电信 4广电cmcc/cucc/ctcc/gdcc未知为空
ch := strings.ToLower(strings.TrimSpace(r.Channel))
var chType string
switch ch {
case "cmcc":
chType = "1"
case "cucc":
chType = "2"
case "ctcc":
chType = "3"
case "gdcc":
chType = "4"
}
// gender: 男->1 女->2
sex := strings.TrimSpace(r.Sex)
var gender string
if sex == "男" {
gender = "1"
} else if sex == "女" {
gender = "2"
}
return &yysy9a1bOut{
OrderNo: r.OrderNo,
HandleTime: time.Now().Format("2006-01-02 15:04:05"),
Type: chType,
Result: res,
Gender: gender,
Age: ageFromBirthday(r.Birthday),
Remark: remark,
}, nil
}
func ageFromBirthday(s string) string {
s = strings.TrimSpace(s)
if len(s) < 4 {
return ""
}
y, err := strconv.Atoi(s[0:4])
if err != nil || y <= 0 {
return ""
}
age := time.Now().Year() - y
if age < 0 {
age = 0
}
return strconv.Itoa(age)
}

View File

@@ -0,0 +1,57 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/zhicha"
)
// ProcessYYSY9E4ARequest YYSY9E4A API处理方法 - 手机号归属地查询
func ProcessYYSY9E4ARequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSY9E4AReq
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
encryptedMobileNo, err := deps.ZhichaService.Encrypt(paramsDto.MobileNo)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
reqData := map[string]interface{}{
"phone": encryptedMobileNo,
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI026", reqData)
if err != nil {
if errors.Is(err, zhicha.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
}
// 兼容上游有时返回 JSON 字符串的情况:如果是字符串则尝试再反序列化一次
if str, ok := respData.(string); ok && str != "" {
var parsed interface{}
if err := json.Unmarshal([]byte(str), &parsed); err == nil {
respData = parsed
}
}
// 将响应数据转换为JSON字节
respBytes, err := json.Marshal(respData)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return respBytes, nil
}

View File

@@ -0,0 +1,114 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shumai"
)
// ProcessYYSY9F1BYequest YYSY9F1B API处理方法 - 手机二要素验证
func ProcessYYSY9F1BYequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSY9F1BReq
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
reqFormData := map[string]interface{}{
"mobile": paramsDto.MobileNo,
"name": paramsDto.Name,
}
// 3m8s 运营商二要素order_no, fee, result(0-一致 1-不一致)。失败则直接返回,不再调携号转网接口。
apiPath := "/v4/mobile_two/check"
respBytes, err := deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData)
if err != nil {
if errors.Is(err, shumai.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, shumai.ErrSystem) {
return nil, errors.Join(processors.ErrSystem, err)
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
}
// s9w1 手机携号转网(仅在上方二要素成功后再调)
apiPath2 := "/v4/mobile-transfer/query"
respBytes2, err := deps.ShumaiService.CallAPIForm(ctx, apiPath2, reqFormData)
if err != nil {
if errors.Is(err, shumai.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, shumai.ErrSystem) {
return nil, errors.Join(processors.ErrSystem, err)
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
}
var twoFactorResp struct {
OrderNo string `json:"order_no"`
Fee int `json:"fee"`
Result int `json:"result"` // 0-一致 1-不一致
}
if err := json.Unmarshal(respBytes, &twoFactorResp); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
var transferResp struct {
OrderNo string `json:"order_no"`
Mobile string `json:"mobile"`
Area *string `json:"area"`
IspType string `json:"ispType"` // 转网前运营商
NewIspType string `json:"newIspType"` // 转网后运营商
}
if err := json.Unmarshal(respBytes2, &transferResp); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
// state: 1-一致 2-不一致 3-异常
state := "3"
switch twoFactorResp.Result {
case 0:
state = "1"
case 1:
state = "2"
}
operator := ispNameToCode(transferResp.IspType)
operatorReal := ispNameToCode(transferResp.NewIspType)
// is_xhzw: 0-否 1-是(转网前与转网后运营商不同即为携号转网)
isXhzw := "0"
if transferResp.IspType != "" && transferResp.NewIspType != "" && transferResp.IspType != transferResp.NewIspType {
isXhzw = "1"
}
out := map[string]string{
"operator_real": operatorReal,
"state": state,
"is_xhzw": isXhzw,
"operator": operator,
}
return json.Marshal(out)
}
// ispNameToCode 运营商名称转编码1-移动 2-联通 3-电信
func ispNameToCode(name string) string {
switch name {
case "移动":
return "1"
case "联通":
return "2"
case "电信":
return "3"
default:
return ""
}
}

View File

@@ -0,0 +1,134 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"strconv"
"strings"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
)
// ProcessYYSYBE08Request YYSYBE08 API处理方法 - 使用数脉二要素验证
func ProcessYYSYBE08Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSYBE08Req
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
reqFormData := map[string]interface{}{
"idcard": paramsDto.IDCard,
"name": paramsDto.Name,
}
// 以表单方式调用数脉 API参数在 CallAPIForm 内转为 application/x-www-form-urlencoded
apiPath := "/v4/id_card/check"
// 先尝试使用政务接口app_id2 和 app_secret2
respBytes, err := deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData, true)
if err != nil {
// 使用实时接口app_id 和 app_secret重试
respBytes, err = deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData, false)
// 重试仍失败:阿里云身份证二要素兜底,并直接返回统一映射响应
if err != nil {
return callAliyunIDCardCheckRaw(ctx, deps, paramsDto.Name, paramsDto.IDCard)
}
}
// 解析数脉 /v4/id_card/check 的 data 内容CallAPIForm 返回的即 data 对象)
// 数卖响应: result 0-一致 1-不一致 2-无记录(预留); desc 如 "一致"/"不一致"
var shumaiData struct {
Result interface{} `json:"result"`
OrderNo string `json:"order_no"`
Desc string `json:"desc"`
Sex string `json:"sex"`
Birthday string `json:"birthday"`
Address string `json:"address"`
}
if err := json.Unmarshal(respBytes, &shumaiData); err != nil {
// 解析失败,返回系统错误 - 转换为目标格式
errorResponse := map[string]interface{}{
"ctidRequest": map[string]interface{}{
"ctidAuth": map[string]interface{}{
"idCard": paramsDto.IDCard,
"name": paramsDto.Name,
"resultCode": "500",
"resultMsg": "响应解析失败",
"verifyResult": "",
},
},
}
return json.Marshal(errorResponse)
}
// 按数卖 result 验证结果处理: 0-一致 1-不一致 2-无记录(预留)
// resultCode: 0XXX=一致, 5XXX=不一致/无记录
resultCode, verifyResult, resultMsg := mapIDCardCheckResult(shumaiData.Result, shumaiData.Desc)
// 构建目标格式的响应
response := map[string]interface{}{
"ctidRequest": map[string]interface{}{
"ctidAuth": map[string]interface{}{
"idCard": paramsDto.IDCard,
"name": paramsDto.Name,
"resultCode": resultCode,
"resultMsg": resultMsg,
"verifyResult": verifyResult,
},
},
}
return json.Marshal(response)
}
func mapIDCardCheckResult(rawResult interface{}, desc string) (resultCode, verifyResult, resultMsg string) {
if isResultZero(rawResult) {
resultCode = "0XXX"
verifyResult = "一致"
resultMsg = desc
if resultMsg == "" {
resultMsg = "成功"
}
return
}
resultCode = "5XXX"
verifyResult = "不一致"
resultMsg = desc
if resultMsg == "" {
resultMsg = "不一致"
}
return
}
func isResultZero(v interface{}) bool {
switch r := v.(type) {
case float64:
return r == 0
case int:
return r == 0
case int32:
return r == 0
case int64:
return r == 0
case json.Number:
n, err := r.Int64()
return err == nil && n == 0
case string:
s := strings.TrimSpace(r)
if s == "" {
return false
}
n, err := strconv.ParseFloat(s, 64)
return err == nil && n == 0
default:
return false
}
}

View File

@@ -0,0 +1,82 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/alicloud"
)
// ProcessYYSYBE08testRequest 与 YYSYBE08 相同入参,底层使用阿里云市场身份证二要素校验;响应映射为 ctidRequest.ctidAuth 格式
func ProcessYYSYBE08testRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSYBE08Req
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
return callAliyunIDCardCheckRaw(ctx, deps, paramsDto.Name, paramsDto.IDCard)
}
// callAliyunIDCardCheckRaw POST api-mall/api/id_card/checkform: name、idcard并映射为 ctidRequest.ctidAuth 响应
func callAliyunIDCardCheckRaw(ctx context.Context, deps *processors.ProcessorDependencies, name, idCard string) ([]byte, error) {
_ = ctx
reqData := map[string]interface{}{
"name": name,
"idcard": idCard,
}
respBytes, err := deps.AlicloudService.CallAPI("api-mall/api/id_card/check", reqData)
if err != nil {
if errors.Is(err, alicloud.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
}
return nil, errors.Join(processors.ErrSystem, err)
}
var aliyunData struct {
Msg string `json:"msg"`
Success bool `json:"success"`
Code int `json:"code"`
Data struct {
Birthday string `json:"birthday"`
Result interface{} `json:"result"`
Address string `json:"address"`
OrderNo string `json:"orderNo"`
Sex string `json:"sex"`
Desc string `json:"desc"`
} `json:"data"`
Result interface{} `json:"result"`
Desc string `json:"desc"`
}
if err := json.Unmarshal(respBytes, &aliyunData); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
rawResult := aliyunData.Result
rawDesc := aliyunData.Desc
// 优先使用 code=200 时 data 内的字段;兼容旧格式直接返回 result/desc
if aliyunData.Code == 200 {
rawResult = aliyunData.Data.Result
rawDesc = aliyunData.Data.Desc
}
resultCode, verifyResult, resultMsg := mapIDCardCheckResult(rawResult, rawDesc)
response := map[string]interface{}{
"ctidRequest": map[string]interface{}{
"ctidAuth": map[string]interface{}{
"idCard": idCard,
"name": name,
"resultCode": resultCode,
"resultMsg": resultMsg,
"verifyResult": verifyResult,
},
},
}
return json.Marshal(response)
}

View File

@@ -0,0 +1,46 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shumai"
)
// ProcessYYSYC4R9Request YYSYC4R9 运营商三要素详版API处理方法
func ProcessYYSYC4R9Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSYC4R9Req
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
reqFormData := map[string]interface{}{
"idcard": paramsDto.IDCard,
"name": paramsDto.Name,
"mobile": paramsDto.MobileNo,
}
// 以表单方式调用数脉 API参数在 CallAPIForm 内转为 application/x-www-form-urlencoded
apiPath := "/v2/mobile_three/check/detail" // 接口路径,根据数脉文档填写(如 v4/xxx
respBytes, err := deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData)
if err != nil {
if errors.Is(err, shumai.ErrDatasource) {
// 数据源错误
return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, shumai.ErrSystem) {
// 系统错误
return nil, errors.Join(processors.ErrSystem, err)
} else {
// 其他未知错误
return nil, errors.Join(processors.ErrSystem, err)
}
}
return respBytes, nil
}

View File

@@ -0,0 +1,51 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
)
// ProcessYYSYD50FRequest YYSYD50F API处理方法
func ProcessYYSYD50FRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSYD50FReq
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
encryptedMobileNo, err := deps.WestDexService.Encrypt(paramsDto.MobileNo)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
encryptedIDCard, err := deps.WestDexService.Encrypt(paramsDto.IDCard)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
reqData := map[string]interface{}{
"data": map[string]interface{}{
"phone": encryptedMobileNo,
"idNo": encryptedIDCard,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "G18BJ02", reqData)
if err != nil {
if errors.Is(err, westdex.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
}
return respBytes, nil
}

View File

@@ -0,0 +1,44 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shumai"
)
// ProcessYYSYE7V5Request YYSYE7V5 手机在网状态查询API处理方法
func ProcessYYSYE7V5Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSYE7V5Req
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
reqFormData := map[string]interface{}{
"mobile": paramsDto.MobileNo,
}
// 以表单方式调用数脉 API参数在 CallAPIForm 内转为 application/x-www-form-urlencoded
apiPath := "/v1/mobile_status/check" // 接口路径,根据数脉文档填写(
respBytes, err := deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData)
if err != nil {
if errors.Is(err, shumai.ErrDatasource) {
// 数据源错误
return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, shumai.ErrSystem) {
// 系统错误
return nil, errors.Join(processors.ErrSystem, err)
} else {
// 其他未知错误
return nil, errors.Join(processors.ErrSystem, err)
}
}
return respBytes, nil
}

View File

@@ -0,0 +1,49 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"strings"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shumai"
)
// ProcessYYSYF2T7Request YYSYF2T7 手机二次放号检测查询API处理方法
func ProcessYYSYF2T7Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSYF2T7Req
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
// 从入参 date_rangeYYYYMMDD-YYYYMMDD提取右区间作为 date
parts := strings.SplitN(paramsDto.DateRange, "-", 2)
dateEnd := strings.TrimSpace(parts[1]) // 校验已保证格式正确,取结束日期
reqFormData := map[string]interface{}{
"mobile": paramsDto.MobileNo,
"date": dateEnd,
}
// 以表单方式调用数脉 API参数在 CallAPIForm 内转为 application/x-www-form-urlencoded
apiPath := "/v4/mobile_twice/check" // 接口路径,根据数脉文档填写(
respBytes, err := deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData)
if err != nil {
if errors.Is(err, shumai.ErrDatasource) {
// 数据源错误
return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, shumai.ErrSystem) {
// 系统错误
return nil, errors.Join(processors.ErrSystem, err)
} else {
// 其他未知错误
return nil, errors.Join(processors.ErrSystem, err)
}
}
return respBytes, nil
}

View File

@@ -0,0 +1,133 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"strings"
"time"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shumai"
)
// westdexG19BJ02Resp 上游 G19BJ02 实际返回结构order_no->guid, result->code, channel->phoneType, desc->msg
type westdexG19BJ02Resp struct {
Result int `json:"result"` // 0-是二次卡 1-不是二次卡 2-数据库中无信息(预留)
OrderNo string `json:"orderNo"`
Channel string `json:"channel"` // cmcc/cucc/ctcc
Desc string `json:"desc"`
}
// YYSYF7DBResponse 手机二次卡查询成功响应(最终返回结构)
type YYSYF7DBResponse struct {
Code string `json:"code"`
Data YYSYF7DBResponseData `json:"data"`
}
// YYSYF7DBResponseData 手机二次卡 data 结构
type YYSYF7DBResponseData struct {
Code int `json:"code"`
EncryptType string `json:"encryptType"`
Guid string `json:"guid"` // 来自 order_no
Msg string `json:"msg"` // 来自 desc按 result0-是二次卡 1-不是二次卡
PhoneType string `json:"phoneType"` // 来自 channelcmcc->CMCC 等
}
// ProcessYYSYF7DBRequest YYSYF7DB API处理方法
func ProcessYYSYF7DBRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSYF7DBReq
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
// 组装日期:开始日期 + 当前日期YYYYMMDD-YYYYMMDD
today := time.Now().Format("20060102")
// dateRange := startDateYyyymmdd + "-" + today
reqFormData := map[string]interface{}{
"mobile": paramsDto.MobileNo,
"date": today,
}
// 以表单方式调用数脉 API参数在 CallAPIForm 内转为 application/x-www-form-urlencoded
apiPath := "/v4/mobile_twice/check" // 接口路径,根据数脉文档填写(
respBytes, err := deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData)
if err != nil {
if errors.Is(err, shumai.ErrDatasource) {
// 数据源错误
return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, shumai.ErrSystem) {
// 系统错误
return nil, errors.Join(processors.ErrSystem, err)
} else {
// 其他未知错误
return nil, errors.Join(processors.ErrSystem, err)
}
}
mapped, err := mapWestdexG19BJ02ToYYSYF7DB(respBytes)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return json.Marshal(mapped)
}
// mapWestdexG19BJ02ToYYSYF7DB 将上游 result/orderNo/channel/desc 映射为最终 code/data 结构
// result: 0->1025(是二次卡) 1->1026(不是二次卡) 2->1027(数据库中无信息)channel: cmcc->CMCC cucc->CUCC ctcc->CTCC
func mapWestdexG19BJ02ToYYSYF7DB(dataBytes []byte) (*YYSYF7DBResponse, error) {
var r westdexG19BJ02Resp
if err := json.Unmarshal(dataBytes, &r); err != nil {
return nil, err
}
var codeStr string
var codeInt int
var msg string
switch r.Result {
case 0:
codeStr = "1025"
codeInt = 1025
msg = "二次卡"
case 1:
codeStr = "1026"
codeInt = 1026
msg = "不是二次卡"
default:
codeStr = "1027"
codeInt = 1027
msg = "不是二次卡"
}
if r.Desc != "" {
msg = strings.TrimSpace(r.Desc)
}
ch := strings.ToLower(strings.TrimSpace(r.Channel))
var phoneType string
switch ch {
case "cmcc":
phoneType = "CMCC"
case "cucc":
phoneType = "CUCC"
case "ctcc":
phoneType = "CTCC"
default:
phoneType = "UNKNOWN"
}
return &YYSYF7DBResponse{
Code: codeStr,
Data: YYSYF7DBResponseData{
Code: codeInt,
EncryptType: "MD5",
Guid: r.OrderNo,
Msg: msg,
PhoneType: phoneType,
},
}, nil
}

View File

@@ -0,0 +1,52 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shumai"
)
// ProcessYYSYH6D2Request YYSYH6D2 运营商三要素简版API处理方法
func ProcessYYSYH6D2Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSYH6D2Req
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
reqFormData := map[string]interface{}{
"idcard": paramsDto.IDCard,
"name": paramsDto.Name,
"mobile": paramsDto.MobileNo,
}
// 以表单方式调用数脉 API参数在 CallAPIForm 内转为 application/x-www-form-urlencoded
apiPath := "/v4/mobile_three/check" // 接口路径,根据数脉文档填写(如 v4/xxx
// 先尝试使用政务接口app_id2 和 app_secret2
respBytes, err := deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData, true)
if err != nil {
// 使用实时接口app_id 和 app_secret重试
respBytes, err = deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData, false)
// 如果重试后仍然失败,返回错误
if err != nil {
if errors.Is(err, shumai.ErrDatasource) {
// 数据源错误
return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, shumai.ErrSystem) {
// 系统错误
return nil, errors.Join(processors.ErrSystem, err)
} else {
// 其他未知错误
return nil, errors.Join(processors.ErrSystem, err)
}
}
}
return respBytes, nil
}

View File

@@ -0,0 +1,48 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shumai"
)
// ProcessYYSYH6F3Request YYSYH6F3 运营商三要素即时版API处理方法
func ProcessYYSYH6F3Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSYH6F3Req
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
reqFormData := map[string]interface{}{
"idcard": paramsDto.IDCard,
"name": paramsDto.Name,
"mobile": paramsDto.MobileNo,
}
// 以表单方式调用数脉 API参数在 CallAPIForm 内转为 application/x-www-form-urlencoded
// 走政务接口使用这个
apiPath := "/v4/mobile_three/check" // 接口路径,根据数脉文档填写(如 v4/xxx
respBytes, err := deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData)
if err != nil {
if errors.Is(err, shumai.ErrDatasource) {
// 数据源错误
return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, shumai.ErrSystem) {
// 系统错误
return nil, errors.Join(processors.ErrSystem, err)
} else {
// 其他未知错误
return nil, errors.Join(processors.ErrSystem, err)
}
}
return respBytes, nil
}

View File

@@ -0,0 +1,44 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shumai"
)
// ProcessYYSYK8R3Request YYSYK8R3 手机空号检测查询API处理方法
func ProcessYYSYK8R3Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSYK8R3Req
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
reqFormData := map[string]interface{}{
"mobile": paramsDto.MobileNo,
}
// 以表单方式调用数脉 API参数在 CallAPIForm 内转为 application/x-www-form-urlencoded
apiPath := "/v4/mobile_empty/check" // 接口路径,根据数脉文档填写(
respBytes, err := deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData)
if err != nil {
if errors.Is(err, shumai.ErrDatasource) {
// 数据源错误
return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, shumai.ErrSystem) {
// 系统错误
return nil, errors.Join(processors.ErrSystem, err)
} else {
// 其他未知错误
return nil, errors.Join(processors.ErrSystem, err)
}
}
return respBytes, nil
}

View File

@@ -0,0 +1,49 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shujubao"
)
// ProcessYYSYK9R4Request JRZQACAB 全网手机三要素验证1979周更新版 API 处理方法(使用数据宝服务示例)
func ProcessYYSYK9R4Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSYK9R4Req
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
reqParams := map[string]interface{}{
"key": "c115708d915451da8f34a23e144dda6b",
"name": paramsDto.Name,
"idcard": paramsDto.IDCard,
"mobile": paramsDto.MobileNo,
}
// 最终请求 URL = https://api.chinadatapay.com/communication + 拼接接口地址值,如 personal/197
apiPath := "/communication/personal/1979"
data, err := deps.ShujubaoService.CallAPI(ctx, apiPath, reqParams)
if err != nil {
if errors.Is(err, shujubao.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
}
if errors.Is(err, shujubao.ErrQueryEmpty) {
return nil, errors.Join(processors.ErrNotFound, err)
}
return nil, errors.Join(processors.ErrSystem, err)
}
respBytes, err := json.Marshal(data)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return respBytes, nil
}

View File

@@ -0,0 +1,44 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shumai"
)
// ProcessYYSYP0T4Request YYSYP0T4 在网时长API处理方法
func ProcessYYSYP0T4Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSYP0T4Req
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
reqFormData := map[string]interface{}{
"mobile": paramsDto.MobileNo,
}
// 以表单方式调用数脉 API参数在 CallAPIForm 内转为 application/x-www-form-urlencoded
apiPath := "/v2/mobile_online/check" // 接口路径,根据数脉文档填写(如 v4/xxx
respBytes, err := deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData)
if err != nil {
if errors.Is(err, shumai.ErrDatasource) {
// 数据源错误
return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, shumai.ErrSystem) {
// 系统错误
return nil, errors.Join(processors.ErrSystem, err)
} else {
// 其他未知错误
return nil, errors.Join(processors.ErrSystem, err)
}
}
return respBytes, nil
}

View File

@@ -0,0 +1,44 @@
package yysy
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shumai"
)
// ProcessYYSYS9W1Request YYSYS9W1 手机携号转网查询API处理方法
func ProcessYYSYS9W1Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.YYSYS9W1Req
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
reqFormData := map[string]interface{}{
"mobile": paramsDto.MobileNo,
}
// 以表单方式调用数脉 API参数在 CallAPIForm 内转为 application/x-www-form-urlencoded
apiPath := "/v4/mobile-transfer/query" // 接口路径,根据数脉文档填写(
respBytes, err := deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData)
if err != nil {
if errors.Is(err, shumai.ErrDatasource) {
// 数据源错误
return nil, errors.Join(processors.ErrDatasource, err)
} else if errors.Is(err, shumai.ErrSystem) {
// 系统错误
return nil, errors.Join(processors.ErrSystem, err)
} else {
// 其他未知错误
return nil, errors.Join(processors.ErrSystem, err)
}
}
return respBytes, nil
}