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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
package dto
// PDFG01GZReq PDFG01GZ 请求参数
type PDFG01GZReq struct {
Name string `json:"name" validate:"required,min=1,validName"`
IDCard string `json:"id_card" validate:"required,validIDCard"`
MobileNo string `json:"mobile_no" validate:"required,min=11,max=11,validMobileNo"`
Authorized string `json:"authorized" validate:"required,oneof=0 1"` // 授权标识0或1
}

View File

@@ -0,0 +1,154 @@
package entities
import (
"errors"
"time"
"github.com/google/uuid"
"github.com/shopspring/decimal"
"gorm.io/gorm"
)
// ApiCallStatus API调用状态
const (
ApiCallStatusPending = "pending"
ApiCallStatusSuccess = "success"
ApiCallStatusFailed = "failed"
)
// ApiCall错误类型常量定义供各领域服务和应用层统一引用。
// 使用时可通过 entities.ApiCallErrorInvalidAccess 方式获得,编辑器可自动补全和提示。
// 错误类型与业务含义:
//
// ApiCallErrorInvalidAccess = "invalid_access" // 无效AccessId
// ApiCallErrorFrozenAccount = "frozen_account" // 账户冻结
// ApiCallErrorInvalidIP = "invalid_ip" // IP无效
// ApiCallErrorArrears = "arrears" // 账户欠费
// ApiCallErrorNotSubscribed = "not_subscribed" // 未订阅产品
// ApiCallErrorProductNotFound = "product_not_found" // 产品不存在
// ApiCallErrorProductDisabled = "product_disabled" // 产品已停用
// ApiCallErrorSystem = "system_error" // 系统错误
// ApiCallErrorDatasource = "datasource_error" // 数据源异常
// ApiCallErrorInvalidParam = "invalid_param" // 参数不正确
// ApiCallErrorDecryptFail = "decrypt_fail" // 解密失败
const (
ApiCallErrorInvalidAccess = "invalid_access" // 无效AccessId
ApiCallErrorFrozenAccount = "frozen_account" // 账户冻结
ApiCallErrorInvalidIP = "invalid_ip" // IP无效
ApiCallErrorArrears = "arrears" // 账户欠费
ApiCallErrorNotSubscribed = "not_subscribed" // 未订阅产品
ApiCallErrorProductNotFound = "product_not_found" // 产品不存在
ApiCallErrorProductDisabled = "product_disabled" // 产品已停用
ApiCallErrorSystem = "system_error" // 系统错误
ApiCallErrorDatasource = "datasource_error" // 数据源异常
ApiCallErrorInvalidParam = "invalid_param" // 参数不正确
ApiCallErrorDecryptFail = "decrypt_fail" // 解密失败
ApiCallErrorQueryEmpty = "query_empty" // 查询为空
)
// ApiCall API调用聚合根
type ApiCall struct {
ID string `gorm:"type:varchar(64);primaryKey" json:"id"`
AccessId string `gorm:"type:varchar(64);not null;index" json:"access_id"`
UserId *string `gorm:"type:varchar(36);index" json:"user_id,omitempty"`
ProductId *string `gorm:"type:varchar(64);index" json:"product_id,omitempty"`
TransactionId string `gorm:"type:varchar(36);not null;uniqueIndex" json:"transaction_id"`
ClientIp string `gorm:"type:varchar(64);not null;index" json:"client_ip"`
RequestParams string `gorm:"type:text" json:"request_params"`
ResponseData *string `gorm:"type:text" json:"response_data,omitempty"`
Status string `gorm:"type:varchar(20);not null;default:'pending'" json:"status"`
StartAt time.Time `gorm:"not null;index" json:"start_at"`
EndAt *time.Time `gorm:"index" json:"end_at,omitempty"`
Cost *decimal.Decimal `gorm:"default:0" json:"cost,omitempty"`
ErrorType *string `gorm:"type:varchar(32)" json:"error_type,omitempty"`
ErrorMsg *string `gorm:"type:varchar(256)" json:"error_msg,omitempty"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
}
// NewApiCall 工厂方法
func NewApiCall(accessId, requestParams, clientIp string) (*ApiCall, error) {
if accessId == "" {
return nil, errors.New("AccessId不能为空")
}
if clientIp == "" {
return nil, errors.New("ClientIp不能为空")
}
return &ApiCall{
ID: uuid.New().String(),
AccessId: accessId,
TransactionId: GenerateTransactionID(),
ClientIp: clientIp,
RequestParams: requestParams,
Status: ApiCallStatusPending,
StartAt: time.Now(),
}, nil
}
// MarkSuccess 标记为成功
func (a *ApiCall) MarkSuccess(cost decimal.Decimal) error {
// 校验除ErrorMsg和ErrorType外所有字段不能为空
if a.ID == "" || a.AccessId == "" || a.TransactionId == "" || a.Status == "" || a.StartAt.IsZero() {
return errors.New("ApiCall字段不能为空除ErrorMsg和ErrorType")
}
// 可选字段也要有值
if a.UserId == nil || a.ProductId == nil {
return errors.New("ApiCall标记成功时UserId、ProductId不能为空")
}
a.Status = ApiCallStatusSuccess
endAt := time.Now()
a.EndAt = &endAt
a.Cost = &cost
a.ErrorType = nil
a.ErrorMsg = nil
return nil
}
// MarkFailed 标记为失败
func (a *ApiCall) MarkFailed(errorType, errorMsg string) {
a.Status = ApiCallStatusFailed
a.ErrorType = &errorType
shortMsg := errorMsg
if len(shortMsg) > 120 {
shortMsg = shortMsg[:120]
}
a.ErrorMsg = &shortMsg
endAt := time.Now()
a.EndAt = &endAt
}
// Validate 校验ApiCall聚合根的业务规则
func (a *ApiCall) Validate() error {
if a.ID == "" {
return errors.New("ID不能为空")
}
if a.AccessId == "" {
return errors.New("AccessId不能为空")
}
if a.TransactionId == "" {
return errors.New("TransactionId不能为空")
}
if a.Status != ApiCallStatusPending && a.Status != ApiCallStatusSuccess && a.Status != ApiCallStatusFailed {
return errors.New("无效的调用状态")
}
return nil
}
// GenerateTransactionID 生成UUID格式的交易单号
func GenerateTransactionID() string {
return uuid.New().String()
}
// TableName 指定数据库表名
func (ApiCall) TableName() string {
return "api_calls"
}
// BeforeCreate GORM钩子创建前自动生成UUID
func (c *ApiCall) BeforeCreate(tx *gorm.DB) error {
if c.ID == "" {
c.ID = uuid.New().String()
}
return nil
}

View File

@@ -0,0 +1,362 @@
package entities
import (
"crypto/rand"
"database/sql/driver"
"encoding/hex"
"encoding/json"
"errors"
"io"
"net"
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
// ApiUserStatus API用户状态
const (
ApiUserStatusNormal = "normal"
ApiUserStatusFrozen = "frozen"
)
// WhiteListItem 白名单项包含IP地址、添加时间和备注
type WhiteListItem struct {
IPAddress string `json:"ip_address"` // IP地址
AddedAt time.Time `json:"added_at"` // 添加时间
Remark string `json:"remark"` // 备注
}
// WhiteList 白名单类型,支持向后兼容(旧的字符串数组格式)
type WhiteList []WhiteListItem
// Value 实现 driver.Valuer 接口,用于数据库写入
func (w WhiteList) Value() (driver.Value, error) {
if w == nil {
return "[]", nil
}
data, err := json.Marshal(w)
if err != nil {
return nil, err
}
return string(data), nil
}
// Scan 实现 sql.Scanner 接口,用于数据库读取(支持向后兼容)
func (w *WhiteList) Scan(value interface{}) error {
if value == nil {
*w = WhiteList{}
return nil
}
var bytes []byte
switch v := value.(type) {
case []byte:
bytes = v
case string:
bytes = []byte(v)
default:
return errors.New("无法扫描 WhiteList 类型")
}
if len(bytes) == 0 || string(bytes) == "[]" || string(bytes) == "null" {
*w = WhiteList{}
return nil
}
// 首先尝试解析为新格式(结构体数组)
var items []WhiteListItem
if err := json.Unmarshal(bytes, &items); err == nil {
// 成功解析为新格式
*w = WhiteList(items)
return nil
}
// 如果失败,尝试解析为旧格式(字符串数组)
var oldFormat []string
if err := json.Unmarshal(bytes, &oldFormat); err != nil {
return err
}
// 将旧格式转换为新格式
now := time.Now()
items = make([]WhiteListItem, 0, len(oldFormat))
for _, ip := range oldFormat {
items = append(items, WhiteListItem{
IPAddress: ip,
AddedAt: now, // 使用当前时间作为添加时间(因为旧数据没有时间信息)
Remark: "", // 旧数据没有备注信息
})
}
*w = WhiteList(items)
return nil
}
// ApiUser API用户聚合根
type ApiUser struct {
ID string `gorm:"primaryKey;type:varchar(64)" json:"id"`
UserId string `gorm:"type:varchar(36);not null;uniqueIndex" json:"user_id"`
AccessId string `gorm:"type:varchar(64);not null;uniqueIndex" json:"access_id"`
SecretKey string `gorm:"type:varchar(128);not null" json:"secret_key"`
Status string `gorm:"type:varchar(20);not null;default:'normal'" json:"status"`
WhiteList WhiteList `gorm:"type:json;default:'[]'" json:"white_list"` // 支持多个白名单包含IP和添加时间支持向后兼容
// 余额预警配置
BalanceAlertEnabled bool `gorm:"default:true" json:"balance_alert_enabled" comment:"是否启用余额预警"`
BalanceAlertThreshold float64 `gorm:"default:200.00" json:"balance_alert_threshold" comment:"余额预警阈值"`
AlertPhone string `gorm:"type:varchar(20)" json:"alert_phone" comment:"预警手机号"`
LastLowBalanceAlert *time.Time `json:"last_low_balance_alert" comment:"最后低余额预警时间"`
LastArrearsAlert *time.Time `json:"last_arrears_alert" comment:"最后欠费预警时间"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
}
// IsWhiteListed 校验IP/域名是否在白名单
func (u *ApiUser) IsWhiteListed(target string) bool {
for _, w := range u.WhiteList {
if w.IPAddress == target {
return true
}
}
return false
}
// IsActive 是否可用
func (u *ApiUser) IsActive() bool {
return u.Status == ApiUserStatusNormal
}
// IsFrozen 是否冻结
func (u *ApiUser) IsFrozen() bool {
return u.Status == ApiUserStatusFrozen
}
// NewApiUser 工厂方法
func NewApiUser(userId string, defaultAlertEnabled bool, defaultAlertThreshold float64) (*ApiUser, error) {
if userId == "" {
return nil, errors.New("用户ID不能为空")
}
accessId, err := GenerateSecretId()
if err != nil {
return nil, err
}
secretKey, err := GenerateSecretKey()
if err != nil {
return nil, err
}
return &ApiUser{
ID: uuid.New().String(),
UserId: userId,
AccessId: accessId,
SecretKey: secretKey,
Status: ApiUserStatusNormal,
WhiteList: WhiteList{},
BalanceAlertEnabled: defaultAlertEnabled,
BalanceAlertThreshold: defaultAlertThreshold,
}, nil
}
// 领域行为
func (u *ApiUser) Freeze() {
u.Status = ApiUserStatusFrozen
}
func (u *ApiUser) Unfreeze() {
u.Status = ApiUserStatusNormal
}
func (u *ApiUser) UpdateWhiteList(list []WhiteListItem) {
u.WhiteList = WhiteList(list)
}
// AddToWhiteList 新增白名单项(防御性校验)
func (u *ApiUser) AddToWhiteList(entry string, remark string) error {
if len(u.WhiteList) >= 10 {
return errors.New("白名单最多只能有10个")
}
if net.ParseIP(entry) == nil {
return errors.New("非法IP")
}
for _, w := range u.WhiteList {
if w.IPAddress == entry {
return errors.New("白名单已存在")
}
}
u.WhiteList = append(u.WhiteList, WhiteListItem{
IPAddress: entry,
AddedAt: time.Now(),
Remark: remark,
})
return nil
}
// BeforeUpdate GORM钩子更新前确保WhiteList不为nil
func (u *ApiUser) BeforeUpdate(tx *gorm.DB) error {
if u.WhiteList == nil {
u.WhiteList = WhiteList{}
}
return nil
}
// RemoveFromWhiteList 删除白名单项
func (u *ApiUser) RemoveFromWhiteList(entry string) error {
newList := make([]WhiteListItem, 0, len(u.WhiteList))
for _, w := range u.WhiteList {
if w.IPAddress != entry {
newList = append(newList, w)
}
}
if len(newList) == len(u.WhiteList) {
return errors.New("白名单不存在")
}
u.WhiteList = newList
return nil
}
// 余额预警相关方法
// UpdateBalanceAlertSettings 更新余额预警设置
func (u *ApiUser) UpdateBalanceAlertSettings(enabled bool, threshold float64, phone string) error {
if threshold < 0 {
return errors.New("预警阈值不能为负数")
}
if phone != "" && len(phone) != 11 {
return errors.New("手机号格式不正确")
}
u.BalanceAlertEnabled = enabled
u.BalanceAlertThreshold = threshold
u.AlertPhone = phone
return nil
}
// ShouldSendLowBalanceAlert 是否应该发送低余额预警24小时冷却期
func (u *ApiUser) ShouldSendLowBalanceAlert(balance float64) bool {
if !u.BalanceAlertEnabled || u.AlertPhone == "" {
return false
}
// 余额低于阈值
if balance < u.BalanceAlertThreshold {
// 检查是否已经发送过预警(避免频繁发送)
if u.LastLowBalanceAlert != nil {
// 如果距离上次预警不足24小时不发送
if time.Since(*u.LastLowBalanceAlert) < 24*time.Hour {
return false
}
}
return true
}
return false
}
// ShouldSendArrearsAlert 是否应该发送欠费预警(不受冷却期限制)
func (u *ApiUser) ShouldSendArrearsAlert(balance float64) bool {
if !u.BalanceAlertEnabled || u.AlertPhone == "" {
return false
}
// 余额为负数(欠费)- 欠费预警不受冷却期限制
if balance < 0 {
return true
}
return false
}
// MarkLowBalanceAlertSent 标记低余额预警已发送
func (u *ApiUser) MarkLowBalanceAlertSent() {
now := time.Now()
u.LastLowBalanceAlert = &now
}
// MarkArrearsAlertSent 标记欠费预警已发送
func (u *ApiUser) MarkArrearsAlertSent() {
now := time.Now()
u.LastArrearsAlert = &now
}
// Validate 校验ApiUser聚合根的业务规则
func (u *ApiUser) Validate() error {
if u.UserId == "" {
return errors.New("用户ID不能为空")
}
if u.AccessId == "" {
return errors.New("AccessId不能为空")
}
if u.SecretKey == "" {
return errors.New("SecretKey不能为空")
}
switch u.Status {
case ApiUserStatusNormal, ApiUserStatusFrozen:
// ok
default:
return errors.New("无效的用户状态")
}
if len(u.WhiteList) > 10 {
return errors.New("白名单最多只能有10个")
}
for _, item := range u.WhiteList {
if net.ParseIP(item.IPAddress) == nil {
return errors.New("白名单项必须为合法IP地址: " + item.IPAddress)
}
}
return nil
}
// 生成AES-128密钥的函数符合市面规范
func GenerateSecretKey() (string, error) {
key := make([]byte, 16) // 16字节密钥
_, err := io.ReadFull(rand.Reader, key)
if err != nil {
return "", err
}
return hex.EncodeToString(key), nil
}
func GenerateSecretId() (string, error) {
// 创建一个字节数组,用于存储随机数据
bytes := make([]byte, 8) // 因为每个字节表示两个16进制字符
// 读取随机字节到数组中
_, err := rand.Read(bytes)
if err != nil {
return "", err
}
// 将字节数组转换为16进制字符串
return hex.EncodeToString(bytes), nil
}
// TableName 指定数据库表名
func (ApiUser) TableName() string {
return "api_users"
}
// BeforeCreate GORM钩子创建前自动生成UUID并确保WhiteList不为nil
func (c *ApiUser) BeforeCreate(tx *gorm.DB) error {
if c.ID == "" {
c.ID = uuid.New().String()
}
if c.WhiteList == nil {
c.WhiteList = WhiteList{}
}
return nil
}
// AfterFind GORM钩子查询后处理数据确保AddedAt不为零值
func (u *ApiUser) AfterFind(tx *gorm.DB) error {
// 如果 WhiteList 为空,初始化为空数组
if u.WhiteList == nil {
u.WhiteList = WhiteList{}
return nil
}
// 确保所有项的AddedAt不为零值处理可能从旧数据迁移的情况
now := time.Now()
for i := range u.WhiteList {
if u.WhiteList[i].AddedAt.IsZero() {
u.WhiteList[i].AddedAt = now
}
}
return nil
}

View File

@@ -0,0 +1,35 @@
package entities
import "time"
// Report 报告记录实体
// 用于持久化存储各类报告(企业报告等),通过编号和类型区分
type Report struct {
// 报告编号,直接使用业务生成的 reportId 作为主键
ReportID string `gorm:"primaryKey;type:varchar(64)" json:"report_id"`
// 报告类型,例如 enterprise企业报告、personal 等
Type string `gorm:"type:varchar(32);not null;index" json:"type"`
// 调用来源API编码例如 QYGLJ1U9
ApiCode string `gorm:"type:varchar(32);not null;index" json:"api_code"`
// 企业名称和统一社会信用代码,便于后续检索
EntName string `gorm:"type:varchar(255);index" json:"ent_name"`
EntCode string `gorm:"type:varchar(64);index" json:"ent_code"`
// 原始请求参数JSON字符串用于审计和排错
RequestParams string `gorm:"type:text" json:"request_params"`
// 报告完整JSON内容
ReportData string `gorm:"type:text" json:"report_data"`
// 创建时间
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
}
// TableName 指定数据库表名
func (Report) TableName() string {
return "reports"
}

View File

@@ -0,0 +1,50 @@
package repositories
import (
"context"
"time"
"hyapi-server/internal/domains/api/entities"
"hyapi-server/internal/shared/interfaces"
)
type ApiCallRepository interface {
Create(ctx context.Context, call *entities.ApiCall) error
Update(ctx context.Context, call *entities.ApiCall) error
FindById(ctx context.Context, id string) (*entities.ApiCall, error)
FindByUserId(ctx context.Context, userId string, limit, offset int) ([]*entities.ApiCall, error)
// 新增分页查询用户API调用记录
ListByUserId(ctx context.Context, userId string, options interfaces.ListOptions) ([]*entities.ApiCall, int64, error)
// 新增根据条件筛选API调用记录
ListByUserIdWithFilters(ctx context.Context, userId string, filters map[string]interface{}, options interfaces.ListOptions) ([]*entities.ApiCall, int64, error)
// 新增根据条件筛选API调用记录包含产品名称
ListByUserIdWithFiltersAndProductName(ctx context.Context, userId string, filters map[string]interface{}, options interfaces.ListOptions) (map[string]string, []*entities.ApiCall, int64, error)
// 新增统计用户API调用次数
CountByUserId(ctx context.Context, userId string) (int64, error)
// 新增根据用户ID和产品ID统计API调用次数
CountByUserIdAndProductId(ctx context.Context, userId string, productId string) (int64, error)
// 新增根据TransactionID查询
FindByTransactionId(ctx context.Context, transactionId string) (*entities.ApiCall, error)
// 统计相关方法
CountByUserIdAndDateRange(ctx context.Context, userId string, startDate, endDate time.Time) (int64, error)
GetDailyStatsByUserId(ctx context.Context, userId string, startDate, endDate time.Time) ([]map[string]interface{}, error)
GetMonthlyStatsByUserId(ctx context.Context, userId string, startDate, endDate time.Time) ([]map[string]interface{}, error)
// 管理端根据条件筛选所有API调用记录包含产品名称
ListWithFiltersAndProductName(ctx context.Context, filters map[string]interface{}, options interfaces.ListOptions) (map[string]string, []*entities.ApiCall, int64, error)
// 系统级别统计方法
GetSystemTotalCalls(ctx context.Context) (int64, error)
GetSystemCallsByDateRange(ctx context.Context, startDate, endDate time.Time) (int64, error)
GetSystemDailyStats(ctx context.Context, startDate, endDate time.Time) ([]map[string]interface{}, error)
GetSystemMonthlyStats(ctx context.Context, startDate, endDate time.Time) ([]map[string]interface{}, error)
// API受欢迎程度排行榜
GetApiPopularityRanking(ctx context.Context, period string, limit int) ([]map[string]interface{}, error)
}

View File

@@ -0,0 +1,13 @@
package repositories
import (
"context"
"hyapi-server/internal/domains/api/entities"
)
type ApiUserRepository interface {
Create(ctx context.Context, user *entities.ApiUser) error
Update(ctx context.Context, user *entities.ApiUser) error
FindByAccessId(ctx context.Context, accessId string) (*entities.ApiUser, error)
FindByUserId(ctx context.Context, userId string) (*entities.ApiUser, error)
}

View File

@@ -0,0 +1,16 @@
package repositories
import (
"context"
"hyapi-server/internal/domains/api/entities"
)
// ReportRepository 报告记录仓储接口
type ReportRepository interface {
// Create 创建报告记录
Create(ctx context.Context, report *entities.Report) error
// FindByReportID 根据报告编号查询记录
FindByReportID(ctx context.Context, reportID string) (*entities.Report, error)
}

View File

@@ -0,0 +1,69 @@
package services
import (
"context"
"fmt"
"hyapi-server/internal/domains/api/entities"
repo "hyapi-server/internal/domains/api/repositories"
"gorm.io/gorm"
)
// ApiCallAggregateService 聚合服务管理ApiCall生命周期
type ApiCallAggregateService interface {
CreateApiCall(accessId, requestParams, clientIp string) (*entities.ApiCall, error)
LoadApiCall(ctx context.Context, id string) (*entities.ApiCall, error)
SaveApiCall(ctx context.Context, call *entities.ApiCall) error
}
type ApiCallAggregateServiceImpl struct {
apiUserRepo repo.ApiUserRepository
apiCallRepo repo.ApiCallRepository
}
func NewApiCallAggregateService(apiUserRepo repo.ApiUserRepository, apiCallRepo repo.ApiCallRepository) ApiCallAggregateService {
return &ApiCallAggregateServiceImpl{
apiUserRepo: apiUserRepo,
apiCallRepo: apiCallRepo,
}
}
// NewApiCall 创建ApiCall
func (s *ApiCallAggregateServiceImpl) CreateApiCall(accessId, requestParams, clientIp string) (*entities.ApiCall, error) {
return entities.NewApiCall(accessId, requestParams, clientIp)
}
// GetApiCallById 查询ApiCall
func (s *ApiCallAggregateServiceImpl) LoadApiCall(ctx context.Context, id string) (*entities.ApiCall, error) {
return s.apiCallRepo.FindById(ctx, id)
}
// SaveApiCall 保存ApiCall
func (s *ApiCallAggregateServiceImpl) SaveApiCall(ctx context.Context, call *entities.ApiCall) error {
// 先尝试查找现有记录
existingCall, err := s.apiCallRepo.FindById(ctx, call.ID)
if err != nil {
if err == gorm.ErrRecordNotFound {
// 记录不存在,执行创建
err = s.apiCallRepo.Create(ctx, call)
if err != nil {
return fmt.Errorf("创建ApiCall失败: %w", err)
}
return nil
}
// 其他错误
return fmt.Errorf("查询ApiCall失败: %w", err)
}
// 记录存在,执行更新
if existingCall != nil {
err = s.apiCallRepo.Update(ctx, call)
if err != nil {
return fmt.Errorf("更新ApiCall失败: %w", err)
}
return nil
}
// 理论上不会到达这里,但为了安全起见
return s.apiCallRepo.Create(ctx, call)
}

View File

@@ -0,0 +1,430 @@
package services
import (
"context"
"encoding/json"
"fmt"
"hyapi-server/internal/application/api/commands"
appconfig "hyapi-server/internal/config"
api_repositories "hyapi-server/internal/domains/api/repositories"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/domains/api/services/processors/comb"
"hyapi-server/internal/domains/api/services/processors/dwbg"
"hyapi-server/internal/domains/api/services/processors/flxg"
"hyapi-server/internal/domains/api/services/processors/ivyz"
"hyapi-server/internal/domains/api/services/processors/jrzq"
"hyapi-server/internal/domains/api/services/processors/pdfg"
"hyapi-server/internal/domains/api/services/processors/qcxg"
"hyapi-server/internal/domains/api/services/processors/qygl"
"hyapi-server/internal/domains/api/services/processors/test"
"hyapi-server/internal/domains/api/services/processors/yysy"
"hyapi-server/internal/domains/product/services"
"hyapi-server/internal/infrastructure/external/alicloud"
"hyapi-server/internal/infrastructure/external/jiguang"
"hyapi-server/internal/infrastructure/external/muzi"
"hyapi-server/internal/infrastructure/external/shujubao"
"hyapi-server/internal/infrastructure/external/shumai"
"hyapi-server/internal/infrastructure/external/tianyancha"
"hyapi-server/internal/infrastructure/external/westdex"
"hyapi-server/internal/infrastructure/external/xingwei"
"hyapi-server/internal/infrastructure/external/yushan"
"hyapi-server/internal/infrastructure/external/zhicha"
"hyapi-server/internal/shared/interfaces"
)
var (
ErrDatasource = processors.ErrDatasource
ErrSystem = processors.ErrSystem
ErrInvalidParam = processors.ErrInvalidParam
ErrNotFound = processors.ErrNotFound
)
type ApiRequestService struct {
// 可注入依赖,如第三方服务、模型等
westDexService *westdex.WestDexService
muziService *muzi.MuziService
yushanService *yushan.YushanService
tianYanChaService *tianyancha.TianYanChaService
alicloudService *alicloud.AlicloudService
validator interfaces.RequestValidator
processorDeps *processors.ProcessorDependencies
combService *comb.CombService
config *appconfig.Config
reportRepo api_repositories.ReportRepository
}
func NewApiRequestService(
westDexService *westdex.WestDexService,
shujubaoService *shujubao.ShujubaoService,
muziService *muzi.MuziService,
yushanService *yushan.YushanService,
tianYanChaService *tianyancha.TianYanChaService,
alicloudService *alicloud.AlicloudService,
zhichaService *zhicha.ZhichaService,
xingweiService *xingwei.XingweiService,
jiguangService *jiguang.JiguangService,
shumaiService *shumai.ShumaiService,
validator interfaces.RequestValidator,
productManagementService *services.ProductManagementService,
cfg *appconfig.Config,
) *ApiRequestService {
return NewApiRequestServiceWithRepos(
westDexService,
shujubaoService,
muziService,
yushanService,
tianYanChaService,
alicloudService,
zhichaService,
xingweiService,
jiguangService,
shumaiService,
validator,
productManagementService,
cfg,
nil,
nil,
)
}
// NewApiRequestServiceWithRepos 带自定义仓储的构造函数,便于扩展(例如企业报告记录)
func NewApiRequestServiceWithRepos(
westDexService *westdex.WestDexService,
shujubaoService *shujubao.ShujubaoService,
muziService *muzi.MuziService,
yushanService *yushan.YushanService,
tianYanChaService *tianyancha.TianYanChaService,
alicloudService *alicloud.AlicloudService,
zhichaService *zhicha.ZhichaService,
xingweiService *xingwei.XingweiService,
jiguangService *jiguang.JiguangService,
shumaiService *shumai.ShumaiService,
validator interfaces.RequestValidator,
productManagementService *services.ProductManagementService,
cfg *appconfig.Config,
reportRepo api_repositories.ReportRepository,
qyglReportPDFScheduler processors.QYGLReportPDFScheduler,
) *ApiRequestService {
// 创建组合包服务
combService := comb.NewCombService(productManagementService)
apiPublicBase := ""
if cfg != nil {
apiPublicBase = appconfig.ResolveAPIPublicBaseURL(&cfg.API)
}
// 创建处理器依赖容器
processorDeps := processors.NewProcessorDependencies(
westDexService,
shujubaoService,
muziService,
yushanService,
tianYanChaService,
alicloudService,
zhichaService,
xingweiService,
jiguangService,
shumaiService,
validator,
combService,
reportRepo,
qyglReportPDFScheduler,
apiPublicBase,
)
// 统一注册所有处理器
registerAllProcessors(combService)
return &ApiRequestService{
westDexService: westDexService,
muziService: muziService,
yushanService: yushanService,
tianYanChaService: tianYanChaService,
alicloudService: alicloudService,
validator: validator,
processorDeps: processorDeps,
combService: combService,
config: cfg,
reportRepo: reportRepo,
}
}
// registerAllProcessors 统一注册所有处理器
func registerAllProcessors(combService *comb.CombService) {
// 定义所有处理器映射
processorMap := map[string]processors.ProcessorFunc{
// FLXG系列处理器
"FLXG0V3B": flxg.ProcessFLXG0V3Bequest,
"FLXG0V4B": flxg.ProcessFLXG0V4BRequest,
"FLXG162A": flxg.ProcessFLXG162ARequest,
"FLXG3D56": flxg.ProcessFLXG3D56Request,
"FLXG54F5": flxg.ProcessFLXG54F5Request,
"FLXG5876": flxg.ProcessFLXG5876Request,
"FLXG75FE": flxg.ProcessFLXG75FERequest,
"FLXG9687": flxg.ProcessFLXG9687Request,
"FLXG970F": flxg.ProcessFLXG970FRequest,
"FLXGC9D1": flxg.ProcessFLXGC9D1Request,
"FLXGCA3D": flxg.ProcessFLXGCA3DRequest,
"FLXGDEC7": flxg.ProcessFLXGDEC7Request,
"FLXG8A3F": flxg.ProcessFLXG8A3FRequest,
"FLXG5B2E": flxg.ProcessFLXG5B2ERequest,
"FLXG0687": flxg.ProcessFLXG0687Request,
"FLXGBC21": flxg.ProcessFLXGBC21Request,
"FLXGDEA8": flxg.ProcessFLXGDEA8Request,
"FLXGDEA9": flxg.ProcessFLXGDEA9Request,
"FLXG5A3B": flxg.ProcessFLXG5A3BRequest,
"FLXG9C1D": flxg.ProcessFLXG9C1DRequest,
"FLXG2E8F": flxg.ProcessFLXG2E8FRequest,
"FLXG7E8F": flxg.ProcessFLXG7E8FRequest,
"FLXG3A9B": flxg.ProcessFLXG3A9BRequest,
"FLXGK5D2": flxg.ProcessFLXGK5D2Request,
"FLXGDJG3": flxg.ProcessFLXGDJG3Request, //董监高司法综合信息核验
// JRZQ系列处理器
"JRZQ8203": jrzq.ProcessJRZQ8203Request,
"JRZQ0A03": jrzq.ProcessJRZQ0A03Request,
"JRZQ4AA8": jrzq.ProcessJRZQ4AA8Request,
"JRZQDCBE": jrzq.ProcessJRZQDCBERequest,
"JRZQACAB": jrzq.ProcessJRZQACABERequest, // 银行卡四要素
"JRZQ09J8": jrzq.ProcessJRZQ09J8Request,
"JRZQ1D09": jrzq.ProcessJRZQ1D09Request,
"JRZQ3C7B": jrzq.ProcessJRZQ3C7BRequest,
"JRZQ8A2D": jrzq.ProcessJRZQ8A2DRequest,
"JRZQ5E9F": jrzq.ProcessJRZQ5E9FRequest,
"JRZQ4B6C": jrzq.ProcessJRZQ4B6CRequest,
"JRZQ7F1A": jrzq.ProcessJRZQ7F1ARequest,
"JRZQ9E2A": jrzq.ProcessJRZQ9E2ARequest,
"JRZQ6F2A": jrzq.ProcessJRZQ6F2ARequest,
"JRZQ8B3C": jrzq.ProcessJRZQ8B3CRequest,
"JRZQ9D4E": jrzq.ProcessJRZQ9D4ERequest,
"JRZQ0L85": jrzq.ProcessJRZQ0L85Request,
"JRZQ2F8A": jrzq.ProcessJRZQ2F8ARequest,
"JRZQ1E7B": jrzq.ProcessJRZQ1E7BRequest,
"JRZQ3C9R": jrzq.ProcessJRZQ3C9RRequest,
"JRZQ0B6Y": jrzq.ProcessJRZQ0B6YRequest,
"JRZQ9A1W": jrzq.ProcessJRZQ9A1WRequest,
"JRZQ8F7C": jrzq.ProcessJRZQ8F7CRequest,
"JRZQ1W4X": jrzq.ProcessJRZQ1W4XRequest,
"JRZQ3P01": jrzq.ProcessJRZQ3P01Request,
"JRZQ3AG6": jrzq.ProcessJRZQ3AG6Request,
"JRZQO6L7": jrzq.ProcessJRZQO6L7Request, // 全国自然人经济特征评分模型v3 简版
"JRZQO7L1": jrzq.ProcessJRZQO7L1Request, // 全国自然人经济特征评分模型v4 详版
"JRZQS7G0": jrzq.ProcessJRZQS7G0Request, // 社保综合评分V1
"JRZQ1P5G": jrzq.ProcessJRZQ1P5GRequest, // 全国自然人借贷压力指数查询2
"JRZQOCRE": jrzq.ProcessJRZQOCREERequest, // 银行卡OCR数卖
"JRZQOCRY": jrzq.ProcessJRZQOCRYERequest, // 银行卡OCR数据宝
// QYGL系列处理器
"QYGL8261": qygl.ProcessQYGL8261Request,
"QYGL2ACD": qygl.ProcessQYGL2ACDRequest,
"QYGL45BD": qygl.ProcessQYGL45BDRequest,
"QYGL6F2D": qygl.ProcessQYGL6F2DRequest,
"QYGL8271": qygl.ProcessQYGL8271Request,
"QYGLB4C0": qygl.ProcessQYGLB4C0Request,
"QYGL23T7": qygl.ProcessQYGL23T7Request, // 企业三要素验证
"QYGL5A3C": qygl.ProcessQYGL5A3CRequest, // 对外投资历史
"QYGL8B4D": qygl.ProcessQYGL8B4DRequest, // 融资历史
"QYGL9E2F": qygl.ProcessQYGL9E2FRequest, // 行政处罚
"QYGL7C1A": qygl.ProcessQYGL7C1ARequest, // 经营异常
"QYGL3F8E": qygl.ProcessQYGL3F8ERequest, // 人企关系加强版
"QYGL7D9A": qygl.ProcessQYGL7D9ARequest, // 欠税公告
"QYGL4B2E": qygl.ProcessQYGL4B2ERequest, // 税收违法
"COMENT01": qygl.ProcessCOMENT01Request, // 企业风险报告
"QYGL5F6A": qygl.ProcessQYGL5F6ARequest, // 企业相关查询
"QYGL2B5C": qygl.ProcessQYGL2B5CRequest, // 企业联系人实际经营地址
"QYGL6S1B": qygl.ProcessQYGL6S1BRequest, //董监高司法综合信息核验
"QYGL9T1Q": qygl.ProcessQYGL9T1QRequest, //全国企业借贷意向验证查询_V1
"QYGL5A9T": qygl.ProcessQYGL5A9TRequest, //全国企业各类工商风险统计数量查询
"QYGL2S0W": qygl.ProcessQYGL2S0WRequest, //失信被执行企业个人查询
"QYGL5CMP": qygl.ProcessQYGL5CMPRequest, //企业五要素验证
"QYGL66SL": qygl.ProcessQYGL66SLRequest, //全国企业司法模型服务查询_V1
"QYGL2NAO": qygl.ProcessQYGL2naoRequest, //股权变更
"QYGLNIO8": qygl.ProcessQYGLNIO8Request, //企业基本信息
"QYGLP0HT": qygl.ProcessQYGLP0HTRequest, //股权穿透
"QYGL5S1I": qygl.ProcessQYGL5S1IRequest, //企业司法涉诉I
"QYGLJ1U9": qygl.ProcessQYGLJ1U9Request, //企业全景报告(聚合 QYGLUY3S/QYGLJ0Q1/QYGL5S1I
"QYGLJ0Q1": qygl.ProcessQYGLJ0Q1Request, //企业股权结构全景查询
"QYGLUY3S": qygl.ProcessQYGLUY3SRequest, //企业经营状态全景查询
"QYGLDJ12": qygl.ProcessQYGLDJ12Request, //企业年报信息核验
"QYGL8848": qygl.ProcessQYGL8848Request, //企业税收违法核查
// YYSY系列处理器
"YYSY35TA": yysy.ProcessYYSY35TARequest, //运营商归属地数卖
"YYSYD50F": yysy.ProcessYYSYD50FRequest,
"YYSY09CD": yysy.ProcessYYSY09CDRequest,
"YYSY4B21": yysy.ProcessYYSY4B21Request,
"YYSY4B37": yysy.ProcessYYSY4B37Request,
"YYSY6F2E": yysy.ProcessYYSY6F2ERequest,
"YYSYBE08": yysy.ProcessYYSYBE08Request,
"YYSYBE08TEST": yysy.ProcessYYSYBE08testRequest, // 二要素(阿里云市场),与 YYSYBE08 入参一致
"YYSYF7DB": yysy.ProcessYYSYF7DBRequest,
"YYSY4F2E": yysy.ProcessYYSY4F2ERequest,
"YYSY8B1C": yysy.ProcessYYSY8B1CRequest,
"YYSY6D9A": yysy.ProcessYYSY6D9ARequest,
"YYSY3E7F": yysy.ProcessYYSY3E7FRequest,
"YYSY8F3A": yysy.ProcessYYSY8F3ARequest,
"YYSY9A1B": yysy.ProcessYYSY9A1BRequest,
"YYSY8C2D": yysy.ProcessYYSY8C2DRequest,
"YYSY7D3E": yysy.ProcessYYSY7D3ERequest,
"YYSY9E4A": yysy.ProcessYYSY9E4ARequest,
"YYSY9F1B": yysy.ProcessYYSY9F1BYequest,
"YYSY6F2B": yysy.ProcessYYSY6F2BRequest,
"YYSY3M8S": yysy.ProcessYYSY3M8SRequest, //运营商二要素查询
"YYSYC4R9": yysy.ProcessYYSYC4R9Request, //运营商三要素详版查询
"YYSYH6D2": yysy.ProcessYYSYH6D2Request, //运营商三要素简版查询
"YYSYP0T4": yysy.ProcessYYSYP0T4Request, //在网时长查询
"YYSYE7V5": yysy.ProcessYYSYE7V5Request, //手机在网状态查询
"YYSYS9W1": yysy.ProcessYYSYS9W1Request, //手机携号转网查询
"YYSYK8R3": yysy.ProcessYYSYK8R3Request, //手机空号检测查询
"YYSYH6F3": yysy.ProcessYYSYH6F3Request, //运营商三要素即时版查询
"YYSYK9R4": yysy.ProcessYYSYK9R4Request, //全网手机三要素验证1979周更新版
"YYSYF2T7": yysy.ProcessYYSYF2T7Request, //手机二次放号检测查询
// IVYZ系列处理器
"IVYZ0B03": ivyz.ProcessIVYZ0B03Request,
"IVYZ2125": ivyz.ProcessIVYZ2125Request,
"IVYZ385E": ivyz.ProcessIVYZ385ERequest,
"IVYZ5733": ivyz.ProcessIVYZ5733Request,
"IVYZ9363": ivyz.ProcessIVYZ9363Request,
"IVYZ9A2B": ivyz.ProcessIVYZ9A2BRequest,
"IVYZADEE": ivyz.ProcessIVYZADEERequest,
"IVYZ7F2A": ivyz.ProcessIVYZ7F2ARequest,
"IVYZ4E8B": ivyz.ProcessIVYZ4E8BRequest,
"IVYZ1C9D": ivyz.ProcessIVYZ1C9DRequest,
"IVYZGZ08": ivyz.ProcessIVYZGZ08Request,
"IVYZ2A8B": ivyz.ProcessIVYZ2A8BRequest,
"IVYZ7C9D": ivyz.ProcessIVYZ7C9DRequest,
"IVYZ5E3F": ivyz.ProcessIVYZ5E3FRequest,
"IVYZ7F3A": ivyz.ProcessIVYZ7F3ARequest,
"IVYZ3P9M": ivyz.ProcessIVYZ3P9MRequest,
"IVYZ3A7F": ivyz.ProcessIVYZ3A7FRequest,
"IVYZ9D2E": ivyz.ProcessIVYZ9D2ERequest,
"IVYZ81NC": ivyz.ProcessIVYZ81NCRequest,
"IVYZ2MN6": ivyz.ProcessIVYZ2MN6Request,
"IVYZ6G7H": ivyz.ProcessIVYZ6G7HRequest,
"IVYZ8I9J": ivyz.ProcessIVYZ8I9JRequest,
"IVYZ9K2L": ivyz.ProcessIVYZ9K2LRequest,
"IVYZ2C1P": ivyz.ProcessIVYZ2C1PRequest,
"IVYZP2Q6": ivyz.ProcessIVYZP2Q6Request,
"IVYZ2B2T": ivyz.ProcessIVYZ2B2TRequest, //能力资质核验(学历)
"IVYZ5A9O": ivyz.ProcessIVYZ5A9ORequest, //全国⾃然⼈⻛险评估评分模型
"IVYZ6M8P": ivyz.ProcessIVYZ6M8PRequest, //职业资格证书
"IVYZ9H2M": ivyz.ProcessIVYZ9H2MRequest, //极光个人婚姻查询V2版
"IVYZZQT3": ivyz.ProcessIVYZZQT3Request, //人脸比对V3
"IVYZBPQ2": ivyz.ProcessIVYZBPQ2Request, //人脸比对V2
"IVYZSFEL": ivyz.ProcessIVYZSFELRequest, //全国自然人人像三要素核验_V1
"IVYZ0S0D": ivyz.ProcessIVYZ0S0DRequest, //劳动仲裁信息查询(个人版)
"IVYZ1J7H": ivyz.ProcessIVYZ1J7HRequest, //行驶证核查v2
"IVYZ9K7F": ivyz.ProcessIVYZ9K7FRequest, //身份证实名认证即时版
"IVYZA1B3": ivyz.ProcessIVYZA1B3Request, //公安三要素人脸识别
"IVYZFIC1": ivyz.ProcessIVYZFIC1Request, //人脸身份证比对(数脉)
"IVYZN2P8": ivyz.ProcessIVYZN2P8Request, //身份证实名认证政务版
"IVYZX5QZ": ivyz.ProcessIVYZX5QZRequest, //活体检测
"IVYZX5Q2": ivyz.ProcessIVYZX5Q2Request, //活体识别步骤二
"IVYZOCR1": ivyz.ProcessIVYZOCR1Request, //身份证OCR
"IVYZOCR2": ivyz.ProcessIVYZOCR2Request, //身份证OCR2数卖
"IVYZ18HY": ivyz.ProcessIVYZ18HYRequest, //婚姻状况核验V2单人
"IVYZ28HY": ivyz.ProcessIVYZ28HYRequest, //婚姻状况核验(单人)
"IVYZ38SR": ivyz.ProcessIVYZ38SRRequest, //婚姻状态核验(双人)
"IVYZ48SR": ivyz.ProcessIVYZ48SRRequest, //婚姻状态核验V2双人
"IVYZ5E22": ivyz.ProcessIVYZ5E22Request, //双人婚姻评估查询zhicha版本
// COMB系列处理器 - 只注册有自定义逻辑的组合包
"COMB86PM": comb.ProcessCOMB86PMRequest, // 有自定义逻辑重命名ApiCode
"COMBHZY2": comb.ProcessCOMBHZY2Request, // 自定义处理:生成合规报告
"COMBWD01": comb.ProcessCOMBWD01Request, // 自定义处理:将返回结构从数组改为对象
// QCXG系列处理器
"QCXG7A2B": qcxg.ProcessQCXG7A2BRequest,
"QCXG9P1C": qcxg.ProcessQCXG9P1CRequest,
"QCXG8A3D": qcxg.ProcessQCXG8A3DRequest,
"QCXG6B4E": qcxg.ProcessQCXG6B4ERequest,
"QCXG4896": qcxg.ProcessQCXG4896Request,
"QCXG5F3A": qcxg.ProcessQCXG5F3ARequest, // 极光个人车辆查询
"QCXG4D2E": qcxg.ProcessQCXG4D2ERequest, // 极光名下车辆数量查询
"QCXGJJ2A": qcxg.ProcessQCXGJJ2ARequest, // vin码查车辆信息(一对多)
"QCXGGJ3A": qcxg.ProcessQCXGGJ3ARequest, // 车辆vin码查询号牌
"QCXGYTS2": qcxg.ProcessQCXGYTS2Request, // 车辆二要素核验v2
"QCXGP00W": qcxg.ProcessQCXGP00WRequest, // 车辆出险详版查询
"QCXGGB2Q": qcxg.ProcessQCXGGB2QRequest, // 车辆二要素核验V1
"QCXG4I1Z": qcxg.ProcessQCXG4I1ZRequest, // 车辆过户详版查询
"QCXG1H7Y": qcxg.ProcessQCXG1H7YRequest, // 车辆过户简版查询
"QCXG3Z3L": qcxg.ProcessQCXG3Z3LRequest, // 车辆维保详细版查询
"QCXG3Y6B": qcxg.ProcessQCXG3Y6BRequest, // 车辆维保简版查询
"QCXG2T6S": qcxg.ProcessQCXG2T6SRequest, // 车辆里程记录(品牌查询)
"QCXG1U4U": qcxg.ProcessQCXG1U4URequest, //
"QCXG9F5C": qcxg.ProcessQCXG9F5CERequest, //疑似营运车辆注册平台数 10386
"QCXG3B8Z": qcxg.ProcessQCXG3B8ZRequest, //疑似运营车辆查询月度里程10268
"QCXGP1W3": qcxg.ProcessQCXGP1W3Request, //疑似运营车辆查询季度里程10269
"QCXGM7R9": qcxg.ProcessQCXGM7R9Request, //疑似运营车辆查询半年度里程10270
"QCXGU2K4": qcxg.ProcessQCXGU2K4Request, //疑似运营车辆查询年度里程10271
"QCXG5U0Z": qcxg.ProcessQCXG5U0ZRequest, // 车辆静态信息查询 10479
"QCXGY7F2": qcxg.ProcessQCXGY7F2Request, // 二手车VIN估值 10443
"QCXG3M7Z": qcxg.ProcessQCXG3M7ZRequest, //人车关系核验ETC10093 月更
// DWBG系列处理器 - 多维报告
"DWBG6A2C": dwbg.ProcessDWBG6A2CRequest,
"DWBG8B4D": dwbg.ProcessDWBG8B4DRequest,
"DWBG7F3A": dwbg.ProcessDWBG7F3ARequest,
"DWBG5SAM": dwbg.ProcessDWBG5SAMRequest,
// FLXG系列处理器 - 风险管控 (包含原FXHY功能)
"FLXG8B4D": flxg.ProcessFLXG8B4DRequest,
// TEST系列处理器 - 测试用处理器
"TEST001": test.ProcessTestRequest,
"TEST002": test.ProcessTestErrorRequest,
"TEST003": test.ProcessTestTimeoutRequest,
// PDFG系列处理器 - PDF生成
"PDFG01GZ": pdfg.ProcessPDFG01GZRequest,
}
// 批量注册到组合包服务
for apiCode, processor := range processorMap {
combService.RegisterProcessor(apiCode, processor)
}
// 同时设置全局处理器映射
RequestProcessors = processorMap
}
// 注册API处理器 - 现在通过registerAllProcessors统一管理
var RequestProcessors map[string]processors.ProcessorFunc
// PreprocessRequestApi 调用指定的请求处理函数
func (a *ApiRequestService) PreprocessRequestApi(ctx context.Context, apiCode string, params []byte, options *commands.ApiCallOptions, callContext *processors.CallContext) ([]byte, error) {
// 设置Options和CallContext到依赖容器
deps := a.processorDeps.WithOptions(options).WithCallContext(callContext)
// 将apiCode放入context供外部服务使用
ctx = context.WithValue(ctx, "api_code", apiCode)
// 将config放入context供处理器使用
ctx = context.WithValue(ctx, "config", a.config)
// 1. 优先查找已注册的自定义处理器
if processor, exists := RequestProcessors[apiCode]; exists {
return processor(ctx, params, deps)
}
// 2. 检查是否为组合包COMB开头使用通用组合包处理器
if len(apiCode) >= 4 && apiCode[:4] == "COMB" {
return a.processGenericCombRequest(ctx, apiCode, params, deps)
}
return nil, fmt.Errorf("%s: 未找到处理器: %s", ErrSystem, apiCode)
}
// processGenericCombRequest 通用组合包处理器
func (a *ApiRequestService) processGenericCombRequest(ctx context.Context, apiCode string, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
// 调用组合包服务处理请求
// 这里不需要验证参数,因为组合包的参数验证由各个子处理器负责
combinedResult, err := deps.CombService.ProcessCombRequest(ctx, params, deps, apiCode)
if err != nil {
return nil, err
}
// 直接返回组合结果,无任何自定义处理
return json.Marshal(combinedResult)
}

View File

@@ -0,0 +1,135 @@
package services
import (
"context"
"time"
"hyapi-server/internal/config"
"hyapi-server/internal/domains/api/entities"
repo "hyapi-server/internal/domains/api/repositories"
)
type ApiUserAggregateService interface {
CreateApiUser(ctx context.Context, apiUserId string) error
UpdateWhiteList(ctx context.Context, apiUserId string, whiteList []string) error
AddToWhiteList(ctx context.Context, apiUserId string, entry string, remark string) error
RemoveFromWhiteList(ctx context.Context, apiUserId string, entry string) error
FreezeApiUser(ctx context.Context, apiUserId string) error
UnfreezeApiUser(ctx context.Context, apiUserId string) error
LoadApiUserByUserId(ctx context.Context, apiUserId string) (*entities.ApiUser, error)
LoadApiUserByAccessId(ctx context.Context, accessId string) (*entities.ApiUser, error)
SaveApiUser(ctx context.Context, apiUser *entities.ApiUser) error
}
type ApiUserAggregateServiceImpl struct {
repo repo.ApiUserRepository
cfg *config.Config
}
func NewApiUserAggregateService(repo repo.ApiUserRepository, cfg *config.Config) ApiUserAggregateService {
return &ApiUserAggregateServiceImpl{repo: repo, cfg: cfg}
}
func (s *ApiUserAggregateServiceImpl) CreateApiUser(ctx context.Context, apiUserId string) error {
apiUser, err := entities.NewApiUser(apiUserId, s.cfg.Wallet.BalanceAlert.DefaultEnabled, s.cfg.Wallet.BalanceAlert.DefaultThreshold)
if err != nil {
return err
}
if err := apiUser.Validate(); err != nil {
return err
}
return s.repo.Create(ctx, apiUser)
}
func (s *ApiUserAggregateServiceImpl) UpdateWhiteList(ctx context.Context, apiUserId string, whiteList []string) error {
apiUser, err := s.repo.FindByUserId(ctx, apiUserId)
if err != nil {
return err
}
// 将字符串数组转换为WhiteListItem数组
items := make([]entities.WhiteListItem, 0, len(whiteList))
now := time.Now()
for _, ip := range whiteList {
items = append(items, entities.WhiteListItem{
IPAddress: ip,
AddedAt: now, // 批量更新时使用当前时间
})
}
apiUser.UpdateWhiteList(items) // UpdateWhiteList 会转换为 WhiteList 类型
return s.repo.Update(ctx, apiUser)
}
func (s *ApiUserAggregateServiceImpl) AddToWhiteList(ctx context.Context, apiUserId string, entry string, remark string) error {
apiUser, err := s.repo.FindByUserId(ctx, apiUserId)
if err != nil {
return err
}
err = apiUser.AddToWhiteList(entry, remark)
if err != nil {
return err
}
return s.repo.Update(ctx, apiUser)
}
func (s *ApiUserAggregateServiceImpl) RemoveFromWhiteList(ctx context.Context, apiUserId string, entry string) error {
apiUser, err := s.repo.FindByUserId(ctx, apiUserId)
if err != nil {
return err
}
err = apiUser.RemoveFromWhiteList(entry)
if err != nil {
return err
}
return s.repo.Update(ctx, apiUser)
}
func (s *ApiUserAggregateServiceImpl) FreezeApiUser(ctx context.Context, apiUserId string) error {
apiUser, err := s.repo.FindByUserId(ctx, apiUserId)
if err != nil {
return err
}
apiUser.Freeze()
return s.repo.Update(ctx, apiUser)
}
func (s *ApiUserAggregateServiceImpl) UnfreezeApiUser(ctx context.Context, apiUserId string) error {
apiUser, err := s.repo.FindByUserId(ctx, apiUserId)
if err != nil {
return err
}
apiUser.Unfreeze()
return s.repo.Update(ctx, apiUser)
}
func (s *ApiUserAggregateServiceImpl) LoadApiUserByAccessId(ctx context.Context, accessId string) (*entities.ApiUser, error) {
return s.repo.FindByAccessId(ctx, accessId)
}
func (s *ApiUserAggregateServiceImpl) LoadApiUserByUserId(ctx context.Context, apiUserId string) (*entities.ApiUser, error) {
apiUser, err := s.repo.FindByUserId(ctx, apiUserId)
if err != nil {
return nil, err
}
// 确保WhiteList不为nil
if apiUser.WhiteList == nil {
apiUser.WhiteList = entities.WhiteList{}
}
return apiUser, nil
}
func (s *ApiUserAggregateServiceImpl) SaveApiUser(ctx context.Context, apiUser *entities.ApiUser) error {
exists, err := s.repo.FindByUserId(ctx, apiUser.UserId)
if err != nil {
return err
}
if exists != nil {
// 确保WhiteList不为nil
if apiUser.WhiteList == nil {
apiUser.WhiteList = []entities.WhiteListItem{}
}
return s.repo.Update(ctx, apiUser)
} else {
return s.repo.Create(ctx, apiUser)
}
}

View File

@@ -0,0 +1,804 @@
package services
import (
"context"
"reflect"
"strings"
"hyapi-server/internal/domains/api/dto"
product_services "hyapi-server/internal/domains/product/services"
)
// FormField 表单字段配置
type FormField struct {
Name string `json:"name"`
Label string `json:"label"`
Type string `json:"type"`
Required bool `json:"required"`
Validation string `json:"validation"`
Description string `json:"description"`
Example string `json:"example"`
Placeholder string `json:"placeholder"`
}
// FormConfig 表单配置
type FormConfig struct {
ApiCode string `json:"api_code"`
Fields []FormField `json:"fields"`
}
// FormConfigService 表单配置服务接口
type FormConfigService interface {
GetFormConfig(ctx context.Context, apiCode string) (*FormConfig, error)
}
// FormConfigServiceImpl 表单配置服务实现
type FormConfigServiceImpl struct {
productManagementService *product_services.ProductManagementService
}
// NewFormConfigService 创建表单配置服务
func NewFormConfigService(productManagementService *product_services.ProductManagementService) FormConfigService {
return &FormConfigServiceImpl{
productManagementService: productManagementService,
}
}
// NewFormConfigServiceWithoutDependencies 创建表单配置服务(不注入依赖,用于测试)
func NewFormConfigServiceWithoutDependencies() FormConfigService {
return &FormConfigServiceImpl{
productManagementService: nil,
}
}
// GetFormConfig 获取指定API的表单配置
func (s *FormConfigServiceImpl) GetFormConfig(ctx context.Context, apiCode string) (*FormConfig, error) {
// 根据API代码获取对应的DTO结构体
dtoStruct, err := s.getDTOStruct(ctx, apiCode)
if err != nil {
return nil, err
}
if dtoStruct == nil {
return nil, nil
}
// 通过反射解析结构体字段
fields := s.parseDTOFields(dtoStruct)
config := &FormConfig{
ApiCode: apiCode,
Fields: fields,
}
return config, nil
}
// getDTOStruct 根据API代码获取对应的DTO结构体
func (s *FormConfigServiceImpl) getDTOStruct(ctx context.Context, apiCode string) (interface{}, error) {
// 建立API代码到DTO结构体的映射
dtoMap := map[string]interface{}{
"IVYZ9363": &dto.IVYZ9363Req{},
"IVYZ385E": &dto.IVYZ385EReq{},
"IVYZ5733": &dto.IVYZ5733Req{},
"FLXG3D56": &dto.FLXG3D56Req{},
"FLXG75FE": &dto.FLXG75FEReq{},
"FLXG0V3B": &dto.FLXG0V3BReq{},
"FLXG0V4B": &dto.FLXG0V4BReq{},
"FLXG54F5": &dto.FLXG54F5Req{},
"FLXG162A": &dto.FLXG162AReq{},
"FLXG0687": &dto.FLXG0687Req{},
"FLXGBC21": &dto.FLXGBC21Req{},
"FLXG970F": &dto.FLXG970FReq{},
"FLXG5876": &dto.FLXG5876Req{},
"FLXG9687": &dto.FLXG9687Req{},
"FLXGC9D1": &dto.FLXGC9D1Req{},
"FLXGCA3D": &dto.FLXGCA3DReq{},
"FLXGDEC7": &dto.FLXGDEC7Req{},
"JRZQ0A03": &dto.JRZQ0A03Req{},
"JRZQ4AA8": &dto.JRZQ4AA8Req{},
"JRZQ8203": &dto.JRZQ8203Req{},
"JRZQDCBE": &dto.JRZQDCBEReq{},
"QYGL2ACD": &dto.QYGL2ACDReq{},
"QYGL6F2D": &dto.QYGL6F2DReq{},
"QYGL45BD": &dto.QYGL45BDReq{},
"QYGL8261": &dto.QYGL8261Req{},
"QYGL8271": &dto.QYGL8271Req{},
"QYGLB4C0": &dto.QYGLB4C0Req{},
"QYGL23T7": &dto.QYGL23T7Req{},
"QYGL5A3C": &dto.QYGL5A3CReq{},
"QYGL8B4D": &dto.QYGL8B4DReq{},
"QYGL9E2F": &dto.QYGL9E2FReq{},
"QYGL7C1A": &dto.QYGL7C1AReq{},
"QYGL3F8E": &dto.QYGL3F8EReq{},
"YYSY4B37": &dto.YYSY4B37Req{},
"YYSY4B21": &dto.YYSY4B21Req{},
"YYSY6F2E": &dto.YYSY6F2EReq{},
"YYSY09CD": &dto.YYSY09CDReq{},
"IVYZ0B03": &dto.IVYZ0B03Req{},
"YYSYBE08": &dto.YYSYBE08Req{},
"YYSYBE08TEST": &dto.YYSYBE08Req{},
"YYSYD50F": &dto.YYSYD50FReq{},
"YYSYF7DB": &dto.YYSYF7DBReq{},
"IVYZ9A2B": &dto.IVYZ9A2BReq{},
"IVYZ7F2A": &dto.IVYZ7F2AReq{},
"IVYZ4E8B": &dto.IVYZ4E8BReq{},
"IVYZ1C9D": &dto.IVYZ1C9DReq{},
"IVYZGZ08": &dto.IVYZGZ08Req{},
"FLXG8A3F": &dto.FLXG8A3FReq{},
"FLXG5B2E": &dto.FLXG5B2EReq{},
"COMB298Y": &dto.COMB298YReq{},
"COMB86PM": &dto.COMB86PMReq{},
"QCXG7A2B": &dto.QCXG7A2BReq{},
"COMENT01": &dto.COMENT01Req{},
"JRZQ09J8": &dto.JRZQ09J8Req{},
"FLXGDEA8": &dto.FLXGDEA8Req{},
"FLXGDEA9": &dto.FLXGDEA9Req{},
"JRZQ1D09": &dto.JRZQ1D09Req{},
"IVYZ2A8B": &dto.IVYZ2A8BReq{},
"IVYZ7C9D": &dto.IVYZ7C9DReq{},
"IVYZ5E3F": &dto.IVYZ5E3FReq{},
"YYSY4F2E": &dto.YYSY4F2EReq{},
"YYSY8B1C": &dto.YYSY8B1CReq{},
"YYSY6D9A": &dto.YYSY6D9AReq{},
"YYSY3E7F": &dto.YYSY3E7FReq{},
"FLXG5A3B": &dto.FLXG5A3BReq{},
"FLXG9C1D": &dto.FLXG9C1DReq{},
"FLXG2E8F": &dto.FLXG2E8FReq{},
"JRZQ3C7B": &dto.JRZQ3C7BReq{},
"JRZQ8A2D": &dto.JRZQ8A2DReq{},
"JRZQ5E9F": &dto.JRZQ5E9FReq{},
"JRZQ4B6C": &dto.JRZQ4B6CReq{},
"JRZQ7F1A": &dto.JRZQ7F1AReq{},
"DWBG6A2C": &dto.DWBG6A2CReq{},
"DWBG8B4D": &dto.DWBG8B4DReq{},
"FLXG8B4D": &dto.FLXG8B4DReq{},
"IVYZ81NC": &dto.IVYZ81NCReq{},
"IVYZ2MN6": &dto.IVYZ2MN6Req{},
"IVYZ7F3A": &dto.IVYZ7F3AReq{},
"IVYZ3P9M": &dto.IVYZ3P9MReq{},
"IVYZ3A7F": &dto.IVYZ3A7FReq{},
"IVYZ9D2E": &dto.IVYZ9D2EReq{},
"IVYZ9K2L": &dto.IVYZ9K2LReq{},
"DWBG7F3A": &dto.DWBG7F3AReq{},
"YYSY8F3A": &dto.YYSY8F3AReq{},
"QCXG9P1C": &dto.QCXG9P1CReq{},
"JRZQ9E2A": &dto.JRZQ9E2AReq{},
"YYSY9A1B": &dto.YYSY9A1BReq{},
"YYSY8C2D": &dto.YYSY8C2DReq{},
"YYSY7D3E": &dto.YYSY7D3EReq{},
"YYSY9E4A": &dto.YYSY9E4AReq{},
"JRZQ6F2A": &dto.JRZQ6F2AReq{},
"JRZQ8B3C": &dto.JRZQ8B3CReq{},
"JRZQ9D4E": &dto.JRZQ9D4EReq{},
"FLXG7E8F": &dto.FLXG7E8FReq{},
"QYGL5F6A": &dto.QYGL5F6AReq{},
"IVYZ6G7H": &dto.IVYZ6G7HReq{},
"IVYZ8I9J": &dto.IVYZ8I9JReq{},
"JRZQ0L85": &dto.JRZQ0L85Req{},
"COMBHZY2": &dto.COMBHZY2Req{}, //
"QCXG8A3D": &dto.QCXG8A3DReq{},
"QCXG6B4E": &dto.QCXG6B4EReq{},
"QYGL2B5C": &dto.QYGL2B5CReq{},
"QYGLJ1U9": &dto.QYGLJ1U9Req{},
"JRZQ2F8A": &dto.JRZQ2F8AReq{},
"JRZQ1E7B": &dto.JRZQ1E7BReq{},
"JRZQ3C9R": &dto.JRZQ3C9RReq{},
"IVYZ2C1P": &dto.IVYZ2C1PReq{},
"YYSY9F1B": &dto.YYSY9F1BReq{},
"YYSY6F2B": &dto.YYSY6F2BReq{},
"QYGL6S1B": &dto.QYGL6S1BReq{},
"JRZQ0B6Y": &dto.JRZQ0B6YReq{},
"JRZQ9A1W": &dto.JRZQ9A1WReq{},
"JRZQ8F7C": &dto.JRZQ8F7CReq{}, //综合多头
"FLXGK5D2": &dto.FLXGK5D2Req{},
"FLXG3A9B": &dto.FLXG3A9BReq{},
"IVYZP2Q6": &dto.IVYZP2Q6Req{},
"JRZQ1W4X": &dto.JRZQ1W4XReq{}, //全景档案
"QYGL2S0W": &dto.QYGL2S0WReq{}, //失信被执行企业个人查询
"QYGL9T1Q": &dto.QYGL9T1QReq{}, //全国企业借贷意向验证查询_V1
"QYGL5A9T": &dto.QYGL5A9TReq{}, //全国企业各类工商风险统计数量查询
"JRZQ3P01": &dto.JRZQ3P01Req{}, //海宇风控决策
"JRZQ3AG6": &dto.JRZQ3AG6Req{}, //轻松查公积
"IVYZ2B2T": &dto.IVYZ2B2TReq{}, //能力资质核验(学历)
"IVYZ5A9O": &dto.IVYZ5A9OReq{}, //全国⾃然⼈⻛险评估评分模型
"IVYZ6M8P": &dto.IVYZ6M8PReq{}, //职业资格证书
"IVYZ9H2M": &dto.IVYZ9H2MReq{}, //极光个人婚姻查询V2版
"QYGL5CMP": &dto.QYGL5CMPReq{}, //企业五要素验证
"QCXG4896": &dto.QCXG4896Req{}, //网约车风险查询
"IVYZZQT3": &dto.IVYZZQT3Req{}, //人脸比对V3
"IVYZBPQ2": &dto.IVYZBPQ2Req{}, //人脸比对V2
"IVYZSFEL": &dto.IVYZSFELReq{}, //全国自然人人像三要素核验_V1
"QYGL66SL": &dto.QYGL66SLReq{}, //全国企业司法模型服务查询_V1
"QCXG5F3A": &dto.QCXG5F3AReq{}, //极光个人车辆查询
"QCXG4D2E": &dto.QCXG4D2EReq{}, //极光名下车辆数量查询
"QYGLP0HT": &dto.QYGLP0HTReq{}, //股权穿透
"QYGL2NAO": &dto.QYGL2naoReq{}, //股权变更
"QYGLNIO8": &dto.QYGLNIO8Req{}, //企业基本信息
"QYGL4B2E": &dto.QYGL5A3CReq{}, //税收违法
"QYGL7D9A": &dto.QYGL5A3CReq{}, //欠税公告
"IVYZ0S0D": &dto.IVYZ0S0DReq{}, //劳动仲裁信息查询(个人版)
"IVYZ1J7H": &dto.IVYZ1J7HReq{}, //行驶证核查v2
"QCXGJJ2A": &dto.QCXGJJ2AReq{}, //vin码查车辆信息(一对多)
"QCXGGJ3A": &dto.QCXGGJ3AReq{}, //车辆vin码查询号牌
"QCXGYTS2": &dto.QCXGYTS2Req{}, //车辆二要素核验v2
"QCXGP00W": &dto.QCXGP00WReq{}, //车辆出险详版查询
"QCXGGB2Q": &dto.QCXGGB2QReq{}, //车辆二要素核验V1
"QCXG4I1Z": &dto.QCXG4I1ZReq{}, //车辆过户详版查询
"QCXG1H7Y": &dto.QCXG1H7YReq{}, //车辆过户简版查询
"QCXG3Z3L": &dto.QCXG3Z3LReq{}, //车辆维保详细版查询
"QCXG3Y6B": &dto.QCXG1U4UReq{}, //车辆维保简版查询
"QCXG2T6S": &dto.QCXG2T6SReq{}, //车辆里程记录(品牌查询)
"QCXG1U4U": &dto.QCXG1U4UReq{}, //车辆里程记录(混合查询)
"JRZQO6L7": &dto.JRZQO6L7Req{}, //全国自然人经济特征评分模型v3 简版
"JRZQO7L1": &dto.JRZQO7L1Req{}, //全国自然人经济特征评分模型v4 详版
"JRZQS7G0": &dto.JRZQS7G0Req{}, //社保综合评分V1
"IVYZ9K7F": &dto.IVYZ9K7FReq{}, //身份证实名认证即时版
"YYSY3M8S": &dto.YYSY3M8SReq{}, //运营商二要素查询
"YYSYC4R9": &dto.YYSYC4R9Req{}, //运营商三要素详版查询
"YYSYH6D2": &dto.YYSYH6D2Req{}, //运营商三要素简版政务版查询
"YYSYP0T4": &dto.YYSYP0T4Req{}, //在网时长查询
"YYSYE7V5": &dto.YYSYE7V5Req{}, //手机在网状态查询
"YYSYS9W1": &dto.YYSYS9W1Req{}, //手机携号转网查询
"YYSYK8R3": &dto.YYSYK8R3Req{}, //手机空号检测查询
"YYSYF2T7": &dto.YYSYF2T7Req{}, //手机二次放号检测查询
"IVYZA1B3": &dto.IVYZA1B3Req{}, //公安三要素人脸识别
"IVYZFIC1": &dto.IVYZFIC1Req{}, //人脸身份证比对(数脉)
"IVYZX5QZ": &dto.IVYZX5QZReq{}, //活体识别
"IVYZN2P8": &dto.IVYZ9K7FReq{}, //身份证实名认证政务版
"YYSYH6F3": &dto.YYSYH6F3Req{}, //运营商三要素简版即时版查询
"IVYZX5Q2": &dto.IVYZX5Q2Req{}, //活体识别步骤二
"PDFG01GZ": &dto.PDFG01GZReq{}, //
"QYGL5S1I": &dto.QYGL5S1IReq{}, //企业司法涉诉V2
"JRZQACAB": &dto.JRZQACABReq{}, //银行卡四要素
"QCXG9F5C": &dto.QCXG9F5CReq{}, //疑似营运车辆注册平台数 10386
"QCXG3B8Z": &dto.QCXG3B8ZReq{}, //疑似运营车辆查询月度里程10268
"QCXGP1W3": &dto.QCXGP1W3Req{}, //疑似运营车辆查询季度里程10269
"QCXGM7R9": &dto.QCXGM7R9Req{}, //疑似运营车辆查询半年度里程10270
"QCXGU2K4": &dto.QCXGU2K4Req{}, //疑似运营车辆查询年度里程10271
"QCXG5U0Z": &dto.QCXG5U0ZReq{}, //车辆静态信息查询 10479
"QCXGY7F2": &dto.QCXGY7F2Req{}, //二手车VIN估值 10443
"YYSYK9R4": &dto.YYSYK9R4Req{}, //全网手机三要素验证1979周更新版
"QCXG3M7Z": &dto.QCXG3M7ZReq{}, //人车关系核验ETC10093 月更
"JRZQ1P5G": &dto.JRZQ1P5GReq{}, //全国自然人借贷压力指数查询2
"IVYZOCR1": &dto.IVYZOCR1Req{}, //身份证OCR
"IVYZOCR2": &dto.IVYZOCR1Req{}, //身份证OCR2数卖
"QYGLJ0Q1": &dto.QYGLJ0Q1Req{}, //企业股权结构全景查询
"QYGLUY3S": &dto.QYGLUY3SReq{}, //企业全量信息核验V2 可用
"JRZQOCRE": &dto.JRZQOCREReq{}, //银行卡OCR数卖
"JRZQOCRY": &dto.JRZQOCRYReq{}, //银行卡OCR数据宝
"YYSY35TA": &dto.YYSY35TAReq{}, //运营商归属地数卖
"QYGLDJ12": &dto.QYGLDJ12Req{}, //企业年报信息核验
"FLXGDJG3": &dto.FLXGDJG3Req{}, //董监高司法综合信息核验
"QYGL8848": &dto.QYGLDJ12Req{}, //企业税收违法核查
"IVYZ18HY": &dto.IVYZ18HYReq{}, //婚姻状况核验V2单人
"IVYZ28HY": &dto.IVYZ28HYReq{}, //婚姻状况核验(单人)
"IVYZ38SR": &dto.IVYZ38SRReq{}, //婚姻状态核验(双人)
"IVYZ48SR": &dto.IVYZ48SRReq{}, //婚姻状态核验V2双人
"IVYZ5E22": &dto.IVYZ5E22Req{}, //双人婚姻评估查询zhicha版本
"DWBG5SAM": &dto.DWBG5SAMReq{}, //海宇指迷报告
}
// 优先返回已配置的DTO
if dto, exists := dtoMap[apiCode]; exists {
return dto, nil
}
// 检查是否为通用组合包COMB开头且未单独配置
if len(apiCode) >= 4 && apiCode[:4] == "COMB" {
// 动态从数据库获取组合包的子产品信息并合并DTO
return s.mergeCombPackageDTOs(ctx, apiCode, dtoMap)
}
return nil, nil
}
// parseDTOFields 通过反射解析DTO结构体字段
func (s *FormConfigServiceImpl) parseDTOFields(dtoStruct interface{}) []FormField {
var fields []FormField
t := reflect.TypeOf(dtoStruct).Elem()
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
// 获取JSON标签
jsonTag := field.Tag.Get("json")
if jsonTag == "" {
continue
}
// 获取验证标签
validateTag := field.Tag.Get("validate")
// 解析验证规则
required := strings.Contains(validateTag, "required")
validation := s.parseValidationRules(validateTag)
// 根据字段类型和验证规则生成前端字段类型
fieldType := s.getFieldType(field.Type, validation)
// 生成字段标签(将下划线转换为中文)
label := s.generateFieldLabel(jsonTag)
// 生成示例值
example := s.generateExampleValue(field.Type, jsonTag)
// 生成占位符
placeholder := s.generatePlaceholder(jsonTag, fieldType)
// 生成字段描述
description := s.generateDescription(jsonTag, validation)
formField := FormField{
Name: jsonTag,
Label: label,
Type: fieldType,
Required: required,
Validation: validation,
Description: description,
Example: example,
Placeholder: placeholder,
}
fields = append(fields, formField)
}
return fields
}
// parseValidationRules 解析验证规则
func (s *FormConfigServiceImpl) parseValidationRules(validateTag string) string {
if validateTag == "" {
return ""
}
// 将验证规则转换为前端可理解的格式
rules := strings.Split(validateTag, ",")
var frontendRules []string
for _, rule := range rules {
rule = strings.TrimSpace(rule)
switch {
case rule == "required":
frontendRules = append(frontendRules, "必填")
case strings.HasPrefix(rule, "min="):
min := strings.TrimPrefix(rule, "min=")
frontendRules = append(frontendRules, "最小长度"+min)
case strings.HasPrefix(rule, "max="):
max := strings.TrimPrefix(rule, "max=")
frontendRules = append(frontendRules, "最大长度"+max)
case rule == "validMobileNo":
frontendRules = append(frontendRules, "手机号格式")
case rule == "validIDCard":
frontendRules = append(frontendRules, "身份证格式")
case rule == "validName":
frontendRules = append(frontendRules, "姓名格式")
case rule == "validUSCI":
frontendRules = append(frontendRules, "统一社会信用代码格式")
case rule == "validEnterpriseName" || rule == "enterprise_name":
frontendRules = append(frontendRules, "企业名称格式")
case rule == "validBankCard":
frontendRules = append(frontendRules, "银行卡号格式")
case rule == "validDate":
frontendRules = append(frontendRules, "日期格式")
case rule == "validAuthDate":
frontendRules = append(frontendRules, "授权日期格式")
case rule == "validDateRange":
frontendRules = append(frontendRules, "日期范围格式(YYYYMMDD-YYYYMMDD)")
case rule == "validTimeRange":
frontendRules = append(frontendRules, "时间范围格式")
case rule == "validMobileType":
frontendRules = append(frontendRules, "手机类型")
case rule == "validUniqueID":
frontendRules = append(frontendRules, "唯一标识格式")
case rule == "validReturnURL":
frontendRules = append(frontendRules, "返回链接格式")
case rule == "validAuthorizationURL":
frontendRules = append(frontendRules, "授权链接格式")
case rule == "validBase64Image":
frontendRules = append(frontendRules, "Base64图片格式JPG、BMP、PNG")
case rule == "base64" || rule == "validBase64":
frontendRules = append(frontendRules, "Base64编码格式支持图片/PDF")
case strings.HasPrefix(rule, "oneof="):
values := strings.TrimPrefix(rule, "oneof=")
frontendRules = append(frontendRules, "可选值: "+values)
}
}
return strings.Join(frontendRules, "、")
}
// getFieldType 根据字段类型和验证规则确定前端字段类型
func (s *FormConfigServiceImpl) getFieldType(fieldType reflect.Type, validation string) string {
switch fieldType.Kind() {
case reflect.String:
if strings.Contains(validation, "手机号") {
return "tel"
} else if strings.Contains(validation, "身份证") {
return "text"
} else if strings.Contains(validation, "姓名") {
return "text"
} else if strings.Contains(validation, "时间范围格式") {
return "text" // time_range是HH:MM-HH:MM格式使用文本输入
} else if strings.Contains(validation, "授权日期格式") {
return "text" // auth_date是YYYYMMDD-YYYYMMDD格式使用文本输入
} else if strings.Contains(validation, "日期范围格式") {
return "text" // date_range 为 YYYYMMDD-YYYYMMDD使用文本输入便于直接输入
} else if strings.Contains(validation, "日期") {
return "date"
} else if strings.Contains(validation, "链接") {
return "url"
} else if strings.Contains(validation, "可选值") {
return "select"
} else if strings.Contains(validation, "Base64图片") || strings.Contains(validation, "Base64编码") || strings.Contains(validation, "base64") {
return "textarea"
} else if strings.Contains(validation, "图片地址") {
return "url"
}
return "text"
case reflect.Int64:
return "number"
case reflect.Bool:
return "checkbox"
default:
return "text"
}
}
// generateFieldLabel 生成字段标签
func (s *FormConfigServiceImpl) generateFieldLabel(jsonTag string) string {
// 将下划线命名转换为中文标签
labelMap := map[string]string{
"mobile_no": "手机号码",
"id_card": "身份证号",
"idCard": "身份证号",
"name": "姓名",
"man_name": "男方姓名",
"woman_name": "女方姓名",
"man_id_card": "男方身份证",
"woman_id_card": "女方身份证",
"ent_name": "企业名称",
"legal_person": "法人姓名",
"ent_code": "企业代码",
"ent_reg_no": "企业注册号",
"auth_date": "授权日期",
"date_range": "日期范围",
"time_range": "时间范围",
"authorized": "是否授权",
"authorization_url": "授权链接",
"unique_id": "唯一标识",
"return_url": "返回链接",
"mobile_type": "手机类型",
"start_date": "开始日期",
"years": "年数",
"bank_card": "银行卡号",
"user_type": "关系类型",
"vehicle_type": "车辆类型",
"page_num": "页码",
"page_size": "每页数量",
"use_scenario": "使用场景",
"auth_authorize_file_code": "授权文件编码",
"plate_no": "车牌号",
"plate_type": "号牌类型",
"vin_code": "车辆识别代号VIN码",
"return_type": "返回类型",
"photo_data": "入参图片base64编码",
"owner_type": "企业主类型",
"type": "查询类型",
"query_reason_id": "查询原因ID",
"flag": "层次",
"dir": "方向",
"min_percent": "股权穿透比例下限",
"max_percent": "股权穿透比例上限",
"engine_number": "发动机号码",
"notice_model": "车辆型号",
"vlphoto_data": "行驶证图片",
"carplate_type": "车辆号牌类型",
"image_url": "入参图片地址",
"reg_url": "车辆登记证图片地址",
"token": "token采集及获取结果时所使用的凭证有效期2个小时在此时效内应用侧可以发起采集请求重复的采集所触发的结果会被忽略和结果查询",
"vehicle_name": "车型名称",
"vehicle_location": "车辆所在地",
"first_registrationdate": "首次登记日期",
"color": "颜色",
"plate_color": "车牌颜色",
"marital_type": "婚姻状况类型",
"auth_authorize_file_base64": "PDF授权文件Base64编码5MB以内",
}
if label, exists := labelMap[jsonTag]; exists {
return label
}
// 如果没有预定义,尝试自动转换
return strings.ReplaceAll(jsonTag, "_", " ")
}
// generateExampleValue 生成示例值
func (s *FormConfigServiceImpl) generateExampleValue(fieldType reflect.Type, jsonTag string) string {
exampleMap := map[string]string{
"mobile_no": "13800138000",
"id_card": "110101199001011234",
"idCard": "110101199001011234",
"name": "张三",
"man_name": "张三",
"woman_name": "李四",
"ent_name": "示例企业有限公司",
"legal_person": "王五",
"ent_code": "91110000123456789X",
"ent_reg_no": "110000000123456",
"auth_date": "20240101-20241231",
"date_range": "20240101-20241231",
"time_range": "09:00-18:00",
"authorized": "1",
"years": "5",
"bank_card": "6222021234567890123",
"mobile_type": "移动",
"start_date": "2024-01-01",
"unique_id": "UNIQUE123456",
"return_url": "https://example.com/return",
"authorization_url": "https://example.com/auth20250101.pdf 注意请不要使用示例链接示例链接仅作为参考格式。必须为实际的被查询人授权具有法律效益的授权书文件链接如访问不到或为不实授权书将追究责任。协议必须为http https",
"user_type": "1",
"vehicle_type": "0",
"page_num": "1",
"page_size": "10",
"use_scenario": "1",
"auth_authorize_file_code": "AUTH123456",
"plate_no": "京A12345",
"plate_type": "01",
"vin_code": "LSGBF53M8DS123456",
"return_type": "1",
"photo_data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
"ownerType": "1",
"type": "per",
"query_reason_id": "1",
"flag": "4",
"dir": "down",
"min_percent": "0",
"max_percent": "1",
"engine_number": "1234567890",
"notice_model": "1",
"vlphoto_data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
"carplate_type": "01",
"image_url": "https://example.com/images/driving_license.jpg",
"reg_url": "https://example.com/images/vehicle_registration.jpg",
"token": "0fc79b80371f45e2ac1c693ef9136b24",
"vehicle_name": "车型名称,示例:凌派 2020款 锐·混动 1.5L 锐·舒适版",
"vehicle_location": "车辆所在地,示例:北京",
"first_registrationdate": "初登日期示例2020-05",
"color": "示例:白色",
"plate_color": "0",
"marital_type": "10",
"auth_authorize_file_base64": "JVBERi0xLjQKJcTl8uXr...示例PDF的Base64编码",
}
if example, exists := exampleMap[jsonTag]; exists {
return example
}
// 根据字段类型生成默认示例
switch fieldType.Kind() {
case reflect.String:
return "示例值"
case reflect.Int64:
return "123"
case reflect.Bool:
return "true"
default:
return "示例值"
}
}
// generatePlaceholder 生成占位符
func (s *FormConfigServiceImpl) generatePlaceholder(jsonTag string, fieldType string) string {
placeholderMap := map[string]string{
"mobile_no": "请输入11位手机号码",
"id_card": "请输入18位身份证号码",
"idCard": "请输入18位身份证号码",
"name": "请输入真实姓名",
"man_name": "请输入男方真实姓名",
"woman_name": "请输入女方真实姓名",
"ent_name": "请输入企业全称",
"legal_person": "请输入法人真实姓名",
"ent_code": "请输入统一社会信用代码",
"ent_reg_no": "请输入企业注册号(统一社会信用代码)",
"auth_date": "请输入授权日期范围YYYYMMDD-YYYYMMDD",
"date_range": "请输入日期范围YYYYMMDD-YYYYMMDD",
"time_range": "请输入时间范围HH:MM-HH:MM",
"authorized": "请选择是否授权",
"years": "请输入查询年数0-100",
"bank_card": "请输入银行卡号",
"mobile_type": "请选择手机类型",
"start_date": "请选择开始日期",
"unique_id": "请输入唯一标识",
"return_url": "请输入返回链接",
"authorization_url": "请输入授权链接",
"user_type": "请选择关系类型",
"vehicle_type": "请选择车辆类型",
"page_num": "请输入页码",
"page_size": "请输入每页数量1-100",
"use_scenario": "请选择使用场景",
"auth_authorize_file_code": "请输入授权文件编码",
"plate_no": "请输入车牌号",
"plate_type": "请选择号牌类型01或02",
"vin_code": "请输入17位车辆识别代号VIN码",
"return_type": "请选择返回类型",
"photo_data": "请输入base64编码的入参图片支持JPG、BMP、PNG格式",
"ownerType": "请选择企业主类型",
"type": "请选择查询类型",
"query_reason_id": "请选择查询原因ID",
"flag": "请输入层次最大4",
"dir": "请选择方向up-向上down-向下)",
"min_percent": "请输入股权穿透比例下限默认0",
"max_percent": "请输入股权穿透比例上限默认1",
"engine_number": "请输入发动机号码",
"notice_model": "请输入车辆型号",
"vlphoto_data": "请输入行驶证图片",
"carplate_type": "请选择车辆号牌类型01-大型汽车 02-小型汽车 03-使馆汽车 04-领馆汽车 05-境外汽车 06-外籍汽车 07-普通摩托车 08-轻便摩托车 09-使馆摩托车 10-领馆摩托车 11-境外摩托车 12-外籍摩托车 13-低速车 14-拖拉机 15-挂车 16-教练汽车 17-教练摩托车 20-临时入境汽车 21-临时入境摩托车 22-临时行驶车 23-警用汽车 24-警用摩托 51-新能源大型车 52-新能源小型车)",
"image_url": "请输入入参图片地址",
"reg_url": "请输入车辆登记证图片地址",
"token": "请输入token",
"vehicle_name": "请输入车型名称",
"vehicle_location": "请输入车辆所在地",
"first_registrationdate": "请输入首次登记日期格式YYYY-MM",
"color": "请输入颜色",
"plate_color": "请输入车牌颜色",
"marital_type": "请选择婚姻状况类型",
"auth_authorize_file_base64": "请输入PDF文件的Base64编码字符串",
}
if placeholder, exists := placeholderMap[jsonTag]; exists {
return placeholder
}
// 根据字段类型生成默认占位符
switch fieldType {
case "tel":
return "请输入电话号码"
case "date":
return "请选择日期"
case "url":
return "请输入链接地址"
case "number":
return "请输入数字"
default:
return "请输入" + s.generateFieldLabel(jsonTag)
}
}
// generateDescription 生成字段描述
func (s *FormConfigServiceImpl) generateDescription(jsonTag string, validation string) string {
descMap := map[string]string{
"mobile_no": "请输入11位手机号码",
"id_card": "请输入18位身份证号码最后一位如是字母请大写",
"idCard": "请输入18位身份证号码最后一位如是字母请大写",
"name": "请输入真实姓名",
"man_name": "请输入男方真实姓名",
"woman_name": "请输入女方真实姓名",
"ent_name": "请输入企业全称",
"legal_person": "请输入法人真实姓名",
"ent_code": "请输入统一社会信用代码",
"ent_reg_no": "请输入企业注册号(统一社会信用代码)",
"auth_date": "请输入授权日期范围格式YYYYMMDD-YYYYMMDD且日期范围必须包括今天",
"date_range": "请输入日期范围格式YYYYMMDD-YYYYMMDD",
"time_range": "请输入时间范围格式HH:MM-HH:MM",
"authorized": "请输入是否授权0-未授权1-已授权",
"years": "请输入查询年数0-100",
"bank_card": "请输入银行卡号",
"mobile_type": "请选择手机类型",
"start_date": "请选择开始日期",
"unique_id": "请输入唯一标识",
"return_url": "请输入返回链接",
"authorization_url": "请输入授权链接",
"user_type": "关系类型1-ETC开户人2-车辆所有人3-ETC经办人默认1-ETC开户人",
"vehicle_type": "车辆类型0-客车1-货车2-全部(默认查全部)",
"page_num": "请输入页码从1开始",
"page_size": "请输入每页数量范围1-100",
"use_scenario": "使用场景1-信贷审核2-保险评估3-招聘背景调查4-其他业务场景99-其他",
"auth_authorize_file_code": "请输入授权文件编码",
"plate_no": "请输入车牌号",
"plate_type": "号牌类型01-小型汽车02-大型汽车(可选)",
"vin_code": "请输入17位车辆识别代号VIN码Vehicle Identification Number",
"return_type": "返回类型1-专业和学校名称数据返回编码形式默认2-专业和学校名称数据返回中文名称",
"photo_data": "入参图片base64编码的图片数据仅支持JPG、BMP、PNG三种格式",
"owner_type": "企业主类型编码1-法定代表人2-主要人员3-自然人股东4-法定代表人及自然人股东5-其他",
"type": "查询类型per-人员ent-企业 ",
"query_reason_id": "查询原因ID1-授信审批2-贷中管理3-贷后管理4-异议处理5-担保查询6-租赁资质审查7-融资租赁审批8-借贷撮合查询9-保险审批10-资质审核11-风控审核12-企业背调",
"flag": "层次最大4",
"dir": "方向up-向上穿透down-向下穿透",
"min_percent": "股权穿透比例下限大于等于默认为0支持小数点后两位以小数指代百分比",
"max_percent": "股权穿透比例上限小于等于默认为1支持小数点后两位以小数指代百分比",
"engine_number": "发动机号码",
"notice_model": "车辆型号",
"vlphoto_data": "行驶证图片:base64编码的图片数据仅支持JPG、BMP、PNG三种格式",
"carplate_type": "车辆号牌类型01-大型汽车02-小型汽车03-使馆汽车04-领馆汽车05-境外汽车06-外籍汽车07-普通摩托车08-轻便摩托车09-使馆摩托车10-领馆摩托车11-境外摩托车12-外籍摩托车13-低速车14-拖拉机15-挂车16-教练汽车17-教练摩托车20-临时入境汽车21-临时入境摩托车22-临时行驶车23-警用汽车24-警用摩托51-新能源大型车52-新能源小型车",
"image_url": "入参图片url地址",
"reg_url": "车辆登记证图片地址非必填请提供车辆登记证的图片URL地址",
"token": "token采集及获取结果时所使用的凭证有效期2个小时在此时效内应用侧可以发起采集请求重复的采集所触发的结果会被忽略和结果查询",
"vehicle_name": "车型名称,示例:凌派 2020款 锐·混动 1.5L 锐·舒适版",
"vehicle_location": "车辆所在地",
"first_registrationdate": "首次登记日期格式YYYY-MM",
"color": "颜色",
"plate_color": "车牌颜色",
"marital_type": "婚姻状况类型10-未登记无登记记录20-已婚30-丧偶40-离异",
"auth_authorize_file_base64": "请输入PDF文件的Base64编码字符串",
}
if desc, exists := descMap[jsonTag]; exists {
return desc
}
return "请输入" + s.generateFieldLabel(jsonTag)
}
// mergeCombPackageDTOs 动态合并组合包的子产品DTO结构体
func (s *FormConfigServiceImpl) mergeCombPackageDTOs(ctx context.Context, apiCode string, dtoMap map[string]interface{}) (interface{}, error) {
// 如果productManagementService为nil测试环境返回空结构体
if s.productManagementService == nil {
return &struct{}{}, nil
}
// 1. 从数据库获取组合包产品信息
packageProduct, err := s.productManagementService.GetProductByCode(ctx, apiCode)
if err != nil {
// 如果获取失败,返回空结构体
return &struct{}{}, nil
}
// 2. 检查是否为组合包
if !packageProduct.IsPackage {
return &struct{}{}, nil
}
// 3. 获取组合包的所有子产品
packageItems, err := s.productManagementService.GetPackageItems(ctx, packageProduct.ID)
if err != nil || len(packageItems) == 0 {
return &struct{}{}, nil
}
// 4. 收集所有子产品的DTO字段并去重
// 使用map记录已存在的字段key为json tag
fieldMap := make(map[string]reflect.StructField)
for _, item := range packageItems {
subProductCode := item.Product.Code
// 在dtoMap中查找子产品的DTO
if subDTO, exists := dtoMap[subProductCode]; exists {
// 解析DTO的字段
dtoType := reflect.TypeOf(subDTO).Elem()
for i := 0; i < dtoType.NumField(); i++ {
field := dtoType.Field(i)
jsonTag := field.Tag.Get("json")
if jsonTag != "" && jsonTag != "-" {
// 去除omitempty等选项
jsonTag = strings.Split(jsonTag, ",")[0]
// 如果字段不存在或已存在但新字段有required标记则覆盖
if existingField, exists := fieldMap[jsonTag]; !exists {
fieldMap[jsonTag] = field
} else {
// 如果新字段有required且旧字段没有则用新字段
newValidate := field.Tag.Get("validate")
oldValidate := existingField.Tag.Get("validate")
if strings.Contains(newValidate, "required") && !strings.Contains(oldValidate, "required") {
fieldMap[jsonTag] = field
}
}
}
}
}
}
// 5. 动态创建结构体
fields := make([]reflect.StructField, 0, len(fieldMap))
for _, field := range fieldMap {
fields = append(fields, field)
}
// 创建结构体类型
structType := reflect.StructOf(fields)
// 创建并返回结构体实例
structValue := reflect.New(structType)
return structValue.Interface(), nil
}

View File

@@ -0,0 +1,134 @@
package services
import (
"context"
"testing"
)
func TestFormConfigService_GetFormConfig(t *testing.T) {
service := NewFormConfigServiceWithoutDependencies()
// 测试获取存在的API配置
config, err := service.GetFormConfig(context.Background(), "IVYZ9363")
if err != nil {
t.Fatalf("获取表单配置失败: %v", err)
}
if config == nil {
t.Fatal("表单配置不应为空")
}
if config.ApiCode != "IVYZ9363" {
t.Errorf("期望API代码为 IVYZ9363实际为 %s", config.ApiCode)
}
if len(config.Fields) == 0 {
t.Fatal("字段列表不应为空")
}
// 验证字段信息
expectedFields := map[string]bool{
"man_name": false,
"man_id_card": false,
"woman_name": false,
"woman_id_card": false,
}
for _, field := range config.Fields {
if _, exists := expectedFields[field.Name]; !exists {
t.Errorf("意外的字段: %s", field.Name)
}
expectedFields[field.Name] = true
}
for fieldName, found := range expectedFields {
if !found {
t.Errorf("缺少字段: %s", fieldName)
}
}
// 测试获取不存在的API配置
config, err = service.GetFormConfig(context.Background(), "NONEXISTENT")
if err != nil {
t.Fatalf("获取不存在的API配置不应返回错误: %v", err)
}
if config != nil {
t.Fatal("不存在的API配置应返回nil")
}
}
func TestFormConfigService_FieldValidation(t *testing.T) {
service := NewFormConfigServiceWithoutDependencies()
config, err := service.GetFormConfig(context.Background(), "FLXG3D56")
if err != nil {
t.Fatalf("获取表单配置失败: %v", err)
}
if config == nil {
t.Fatal("表单配置不应为空")
}
// 验证手机号字段
var mobileField *FormField
for _, field := range config.Fields {
if field.Name == "mobile_no" {
mobileField = &field
break
}
}
if mobileField == nil {
t.Fatal("应找到mobile_no字段")
}
if !mobileField.Required {
t.Error("mobile_no字段应为必填")
}
if mobileField.Type != "tel" {
t.Errorf("mobile_no字段类型应为tel实际为%s", mobileField.Type)
}
if !contains(mobileField.Validation, "手机号格式") {
t.Errorf("mobile_no字段验证规则应包含'手机号格式',实际为: %s", mobileField.Validation)
}
}
func TestFormConfigService_FieldLabels(t *testing.T) {
service := NewFormConfigServiceWithoutDependencies()
config, err := service.GetFormConfig(context.Background(), "IVYZ9363")
if err != nil {
t.Fatalf("获取表单配置失败: %v", err)
}
// 验证字段标签
expectedLabels := map[string]string{
"man_name": "男方姓名",
"man_id_card": "男方身份证",
"woman_name": "女方姓名",
"woman_id_card": "女方身份证",
}
for _, field := range config.Fields {
if expectedLabel, exists := expectedLabels[field.Name]; exists {
if field.Label != expectedLabel {
t.Errorf("字段 %s 的标签应为 %s实际为 %s", field.Name, expectedLabel, field.Label)
}
}
}
}
// 辅助函数
func contains(s, substr string) bool {
return len(s) >= len(substr) && (s == substr || (len(s) > len(substr) && (s[:len(substr)] == substr || s[len(s)-len(substr):] == substr || func() bool {
for i := 0; i <= len(s)-len(substr); i++ {
if s[i:i+len(substr)] == substr {
return true
}
}
return false
}())))
}

View File

@@ -0,0 +1,128 @@
# 处理器错误处理解决方案
## 问题描述
在使用 `errors.Join(processors.ErrInvalidParam, err)` 包装错误后,外层的 `errors.Is(err, processors.ErrInvalidParam)` 无法正确识别错误类型。
## 原因分析
`fmt.Errorf` 创建的包装错误虽然实现了 `Unwrap()` 接口,但没有实现 `Is()` 接口,因此 `errors.Is` 无法正确判断错误类型。
## 解决方案
### 🎯 **推荐方案:使用 `errors.Join`Go 1.20+**
这是最简洁、最标准的解决方案Go 1.20+ 原生支持:
```go
// 在处理器中创建错误
return nil, errors.Join(processors.ErrInvalidParam, err)
// 在应用服务层判断错误
if errors.Is(err, processors.ErrInvalidParam) {
// 现在可以正确识别了!
businessError = ErrInvalidParam
return ErrInvalidParam
}
```
### ✅ **优势**
1. **极简代码**:一行代码解决问题
2. **标准库支持**Go 1.20+ 原生功能
3. **完全兼容**`errors.Is` 可以正确识别错误类型
4. **性能优秀**:标准库实现,性能最佳
5. **向后兼容**:现有的错误处理代码无需修改
### 📝 **使用方法**
#### 在处理器中(替换旧方式):
```go
// 旧方式 ❌
return nil, errors.Join(processors.ErrInvalidParam, err)
// 新方式 ✅
return nil, errors.Join(processors.ErrInvalidParam, err)
```
#### 在应用服务层(现在可以正确工作):
```go
if errors.Is(err, processors.ErrInvalidParam) {
// 现在可以正确识别了!
businessError = ErrInvalidParam
return ErrInvalidParam
}
```
## 其他方案对比
### 方案1`errors.Join`(推荐 ⭐⭐⭐⭐⭐)
- **简洁度**:⭐⭐⭐⭐⭐
- **兼容性**:⭐⭐⭐⭐⭐
- **性能**:⭐⭐⭐⭐⭐
- **维护性**:⭐⭐⭐⭐⭐
### 方案2自定义错误类型
- **简洁度**:⭐⭐⭐
- **兼容性**:⭐⭐⭐⭐⭐
- **性能**:⭐⭐⭐⭐
- **维护性**:⭐⭐⭐
### 方案3继续使用 `fmt.Errorf`
- **简洁度**:⭐⭐⭐⭐
- **兼容性**:❌(无法识别错误类型)
- **性能**:⭐⭐⭐⭐
- **维护性**:❌
## 迁移指南
### 步骤1: 检查Go版本
确保项目使用 Go 1.20 或更高版本
### 步骤2: 更新错误创建
将所有处理器中的 `fmt.Errorf("%s: %w", processors.ErrXXX, err)` 替换为 `errors.Join(processors.ErrXXX, err)`
### 步骤3: 验证错误判断
确保应用服务层的 `errors.Is(err, processors.ErrXXX)` 能正确工作
### 步骤4: 测试验证
运行测试确保所有错误处理逻辑正常工作
## 示例
```go
// 处理器层
func ProcessRequest(ctx context.Context, params []byte, deps *ProcessorDependencies) ([]byte, error) {
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
// ... 其他逻辑
}
// 应用服务层
if err := s.apiRequestService.PreprocessRequestApi(ctx, cmd.ApiName, requestParams, &cmd.Options, callContext); err != nil {
if errors.Is(err, processors.ErrInvalidParam) {
// 现在可以正确识别了!
businessError = ErrInvalidParam
return ErrInvalidParam
}
// ... 其他错误处理
}
```
## 注意事项
1. **Go版本要求**:需要 Go 1.20 或更高版本
2. **错误消息格式**`errors.Join` 使用换行符分隔多个错误
3. **完全兼容**`errors.Is` 现在可以正确识别所有错误类型
4. **性能提升**:标准库实现,性能优于自定义解决方案
## 总结
使用 `errors.Join` 是最简洁、最标准的解决方案:
- ✅ 一行代码解决问题
- ✅ 完全兼容 `errors.Is`
- ✅ Go 1.20+ 原生支持
- ✅ 性能优秀,维护简单
如果你的项目使用 Go 1.20+,强烈推荐使用这个方案!

View File

@@ -0,0 +1,74 @@
# 组合包处理器说明
## 🚀 动态组合包机制
从现在开始,组合包支持**动态处理机制**,大大简化了组合包的开发和维护工作。
## 📋 工作原理
### 1. 自动识别
- 所有以 `COMB` 开头的API编码会被自动识别为组合包
- 系统会自动调用通用组合包处理器处理请求
### 2. 处理流程
1. **优先级检查**:首先检查是否有注册的自定义处理器
2. **通用处理**如果没有自定义处理器且API编码以COMB开头使用通用处理器
3. **数据库驱动**:根据数据库中的组合包配置自动调用相应的子产品处理器
## 🛠️ 使用方式
### 普通组合包(无自定义逻辑)
**只需要在数据库配置,无需编写任何代码!**
1.`products` 表中创建组合包产品:
```sql
INSERT INTO products (code, name, is_package, ...)
VALUES ('COMB1234', '新组合包', true, ...);
```
2. 在 `product_package_items` 表中配置子产品:
```sql
INSERT INTO product_package_items (package_id, product_id, sort_order)
VALUES
('组合包产品ID', '子产品1ID', 1),
('组合包产品ID', '子产品2ID', 2);
```
3. **直接调用**无需任何额外编码API立即可用
### 自定义组合包(有特殊逻辑)
如果需要对组合包结果进行后处理,才需要编写代码:
1. **创建处理器文件**`combXXXX_processor.go`
2. **注册处理器**:在 `api_request_service.go` 中注册
3. **实现自定义逻辑**:在处理器中实现特殊业务逻辑
## 📁 现有组合包示例
### COMB86PM自定义处理器
```go
// 有自定义逻辑重命名子产品ApiCode
for _, resp := range combinedResult.Responses {
if resp.ApiCode == "FLXGBC21" {
resp.ApiCode = "FLXG54F5"
}
}
```
### COMB298Y通用处理器
- **无需编码**:已删除专门的处理器文件
- **自动处理**:通过数据库配置自动工作
## ✅ 优势
1. **零配置**:普通组合包只需数据库配置,无需编码
2. **灵活性**:特殊需求仍可通过自定义处理器实现
3. **维护性**:减少重复代码,统一处理逻辑
4. **扩展性**:新增组合包极其简单,配置即用
## 🔧 开发建议
1. **优先使用通用处理器**:除非有特殊业务逻辑,否则不要编写自定义处理器
2. **命名规范**:组合包编码必须以 `COMB` 开头
3. **数据库配置**:确保组合包在数据库中正确配置了 `is_package=true` 和子产品关系
4. **排序控制**:通过 `sort_order` 字段控制子产品在响应中的顺序

View File

@@ -0,0 +1,36 @@
package comb
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
)
// ProcessCOMB86PMRequest COMB86PM API处理方法
func ProcessCOMB86PMRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.COMB86PMReq
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)
}
// 调用组合包服务处理请求
// Options会自动传递给所有子处理器
combinedResult, err := deps.CombService.ProcessCombRequest(ctx, params, deps, "COMB86PM")
if err != nil {
return nil, err
}
// 如果有ApiCode为FLXG54F5的子产品改名为FLXG54F6
for _, resp := range combinedResult.Responses {
if resp.ApiCode == "FLXGBC21" {
resp.ApiCode = "FLXG54F5"
}
}
return json.Marshal(combinedResult)
}

View File

@@ -0,0 +1,178 @@
package comb
import (
"context"
"encoding/json"
"fmt"
"sort"
"strings"
"sync"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/domains/product/entities"
"hyapi-server/internal/domains/product/services"
)
// CombService 组合包服务
type CombService struct {
productManagementService *services.ProductManagementService
processorRegistry map[string]processors.ProcessorFunc
}
// NewCombService 创建组合包服务
func NewCombService(productManagementService *services.ProductManagementService) *CombService {
return &CombService{
productManagementService: productManagementService,
processorRegistry: make(map[string]processors.ProcessorFunc),
}
}
// RegisterProcessor 注册处理器
func (cs *CombService) RegisterProcessor(apiCode string, processor processors.ProcessorFunc) {
cs.processorRegistry[apiCode] = processor
}
// GetProcessor 获取处理器(用于内部调用)
func (cs *CombService) GetProcessor(apiCode string) (processors.ProcessorFunc, bool) {
processor, exists := cs.processorRegistry[apiCode]
return processor, exists
}
// ProcessCombRequest 处理组合包请求 - 实现 CombServiceInterface
func (cs *CombService) ProcessCombRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies, packageCode string) (*processors.CombinedResult, error) {
// 1. 根据组合包code获取产品信息
packageProduct, err := cs.productManagementService.GetProductByCode(ctx, packageCode)
if err != nil {
return nil, fmt.Errorf("获取组合包信息失败: %s", err.Error())
}
if !packageProduct.IsPackage {
return nil, fmt.Errorf("产品 %s 不是组合包", packageCode)
}
// 2. 获取组合包的所有子产品
packageItems, err := cs.productManagementService.GetPackageItems(ctx, packageProduct.ID)
if err != nil {
return nil, fmt.Errorf("获取组合包子产品失败: %s", err.Error())
}
if len(packageItems) == 0 {
return nil, fmt.Errorf("组合包 %s 没有配置子产品", packageCode)
}
// 3. 并发调用所有子产品的处理器
results := cs.processSubProducts(ctx, params, deps, packageItems)
// 4. 组合结果
return cs.combineResults(results)
}
// processSubProducts 并发处理子产品
func (cs *CombService) processSubProducts(
ctx context.Context,
params []byte,
deps *processors.ProcessorDependencies,
packageItems []*entities.ProductPackageItem,
) []*processors.SubProductResult {
results := make([]*processors.SubProductResult, 0, len(packageItems))
var wg sync.WaitGroup
var mu sync.Mutex
// 并发处理每个子产品
for _, item := range packageItems {
wg.Add(1)
go func(item *entities.ProductPackageItem) {
defer wg.Done()
result := cs.processSingleSubProduct(ctx, params, deps, item)
mu.Lock()
results = append(results, result)
mu.Unlock()
}(item)
}
wg.Wait()
// 按SortOrder排序
sort.Slice(results, func(i, j int) bool {
return results[i].SortOrder < results[j].SortOrder
})
return results
}
// processSingleSubProduct 处理单个子产品
func (cs *CombService) processSingleSubProduct(
ctx context.Context,
params []byte,
deps *processors.ProcessorDependencies,
item *entities.ProductPackageItem,
) *processors.SubProductResult {
result := &processors.SubProductResult{
ApiCode: item.Product.Code,
SortOrder: item.SortOrder,
Success: false,
}
// 查找对应的处理器
processor, exists := cs.processorRegistry[item.Product.Code]
if !exists {
result.Error = fmt.Sprintf("未找到处理器: %s", item.Product.Code)
return result
}
// 调用处理器
respBytes, err := processor(ctx, params, deps)
if err != nil {
result.Error = err.Error()
return result
}
// 解析响应
var responseData interface{}
if err := json.Unmarshal(respBytes, &responseData); err != nil {
result.Error = fmt.Sprintf("解析响应失败: %s", err.Error())
return result
}
result.Success = true
result.Data = responseData
return result
}
// combineResults 组合所有子产品的结果
// 只要至少有一个子产品成功,就返回成功结果(部分成功也算成功)
// 只有当所有子产品都失败时,才返回错误
func (cs *CombService) combineResults(results []*processors.SubProductResult) (*processors.CombinedResult, error) {
// 检查是否至少有一个成功的子产品
hasSuccess := false
for _, result := range results {
if result.Success {
hasSuccess = true
break
}
}
// 构建组合结果
combinedResult := &processors.CombinedResult{
Responses: results,
}
// 如果所有子产品都失败,返回错误
if !hasSuccess && len(results) > 0 {
// 构建错误信息,包含所有失败的原因
errorMessages := make([]string, 0, len(results))
for _, result := range results {
if result.Error != "" {
errorMessages = append(errorMessages, fmt.Sprintf("%s: %s", result.ApiCode, result.Error))
}
}
errorMsg := fmt.Sprintf("组合包所有子产品调用失败: %s", strings.Join(errorMessages, "; "))
return nil, fmt.Errorf(errorMsg)
}
// 至少有一个成功,返回成功结果
return combinedResult, nil
}

View File

@@ -0,0 +1,148 @@
package comb
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/shared/logger"
"go.uber.org/zap"
)
// ProcessCOMBHZY2Request 处理 COMBHZY2 组合包请求
func ProcessCOMBHZY2Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
log := logger.GetGlobalLogger()
var req dto.COMBHZY2Req
if err := json.Unmarshal(params, &req); err != nil {
log.Error("COMBHZY2请求参数反序列化失败",
zap.Error(err),
zap.String("params", string(params)),
zap.String("api_code", "COMBHZY2"),
)
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(req); err != nil {
log.Error("COMBHZY2请求参数验证失败",
zap.Error(err),
zap.String("api_code", "COMBHZY2"),
)
return nil, errors.Join(processors.ErrInvalidParam, err)
}
combinedResult, err := deps.CombService.ProcessCombRequest(ctx, params, deps, "COMBHZY2")
if err != nil {
log.Error("COMBHZY2组合包服务调用失败",
zap.Error(err),
zap.String("api_code", "COMBHZY2"),
)
return nil, err
}
if combinedResult == nil {
log.Error("COMBHZY2组合包响应为空",
zap.String("api_code", "COMBHZY2"),
)
return nil, errors.New("组合包响应为空")
}
log.Info("COMBHZY2组合包服务调用成功",
zap.Int("子产品数量", len(combinedResult.Responses)),
zap.String("api_code", "COMBHZY2"),
)
sourceCtx, err := buildSourceContextFromCombined(ctx, combinedResult)
if err != nil {
log.Error("COMBHZY2构建源数据上下文失败",
zap.Error(err),
zap.String("api_code", "COMBHZY2"),
)
return nil, err
}
report := buildTargetReport(ctx, sourceCtx)
reportBytes, err := json.Marshal(report)
if err != nil {
log.Error("COMBHZY2报告序列化失败",
zap.Error(err),
zap.String("api_code", "COMBHZY2"),
)
return nil, errors.Join(processors.ErrSystem, err)
}
return reportBytes, nil
}
func buildSourceContextFromCombined(ctx context.Context, result *processors.CombinedResult) (*sourceContext, error) {
log := logger.GetGlobalLogger()
if result == nil {
log.Error("组合包响应为空", zap.String("api_code", "COMBHZY2"))
return nil, errors.New("组合包响应为空")
}
src := sourceFile{Responses: make([]sourceResponse, 0, len(result.Responses))}
successCount := 0
failedCount := 0
for _, resp := range result.Responses {
if !resp.Success {
log.Warn("子产品调用失败,跳过",
zap.String("api_code", resp.ApiCode),
zap.String("error", resp.Error),
zap.String("parent_api_code", "COMBHZY2"),
)
failedCount++
continue
}
if resp.Data == nil {
log.Warn("子产品数据为空,跳过",
zap.String("api_code", resp.ApiCode),
zap.String("parent_api_code", "COMBHZY2"),
)
failedCount++
continue
}
raw, err := json.Marshal(resp.Data)
if err != nil {
log.Error("序列化子产品数据失败",
zap.Error(err),
zap.String("api_code", resp.ApiCode),
zap.String("parent_api_code", "COMBHZY2"),
)
failedCount++
continue
}
src.Responses = append(src.Responses, sourceResponse{
ApiCode: resp.ApiCode,
Data: raw,
Success: resp.Success,
})
successCount++
}
log.Info("组合包子产品处理完成",
zap.Int("成功数量", successCount),
zap.Int("失败数量", failedCount),
zap.Int("总数量", len(result.Responses)),
zap.String("api_code", "COMBHZY2"),
)
if len(src.Responses) == 0 {
log.Error("组合包子产品全部调用失败",
zap.Int("总数量", len(result.Responses)),
zap.String("api_code", "COMBHZY2"),
)
return nil, errors.New("组合包子产品全部调用失败")
}
return buildSourceContext(ctx, src)
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,91 @@
package comb
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/shared/logger"
"go.uber.org/zap"
)
// ProcessCOMBWD01Request 处理 COMBWD01 组合包请求
// 将返回结构从数组改为以 api_code 为 key 的对象结构
func ProcessCOMBWD01Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
log := logger.GetGlobalLogger()
// 调用组合包服务处理请求
combinedResult, err := deps.CombService.ProcessCombRequest(ctx, params, deps, "COMBWD01")
if err != nil {
log.Error("COMBWD01组合包服务调用失败",
zap.Error(err),
zap.String("api_code", "COMBWD01"),
)
return nil, err
}
if combinedResult == nil {
log.Error("COMBWD01组合包响应为空",
zap.String("api_code", "COMBWD01"),
)
return nil, errors.New("组合包响应为空")
}
log.Info("COMBWD01组合包服务调用成功",
zap.Int("子产品数量", len(combinedResult.Responses)),
zap.String("api_code", "COMBWD01"),
)
// 将数组结构转换为对象结构
responsesMap := make(map[string]*ResponseItem)
for _, resp := range combinedResult.Responses {
item := &ResponseItem{
ApiCode: resp.ApiCode,
Success: resp.Success,
}
// 根据成功/失败状态设置 data 和 error 字段
if resp.Success {
// 成功时data 有值(可能为 nilerror 为 null
item.Data = resp.Data
item.Error = nil
} else {
// 失败时data 为 nullerror 有值
item.Data = nil
if resp.Error != "" {
item.Error = resp.Error
} else {
item.Error = "未知错误"
}
}
responsesMap[resp.ApiCode] = item
}
// 构建新的响应结构
result := map[string]interface{}{
"responses": responsesMap,
}
// 序列化并返回
resultBytes, err := json.Marshal(result)
if err != nil {
log.Error("COMBWD01响应序列化失败",
zap.Error(err),
zap.String("api_code", "COMBWD01"),
)
return nil, errors.Join(processors.ErrSystem, err)
}
return resultBytes, nil
}
// ResponseItem 响应项结构
type ResponseItem struct {
ApiCode string `json:"api_code"`
Success bool `json:"success"`
Data interface{} `json:"data"`
Error interface{} `json:"error"`
}

View File

@@ -0,0 +1,124 @@
package processors
import (
"context"
"hyapi-server/internal/application/api/commands"
"hyapi-server/internal/domains/api/repositories"
"hyapi-server/internal/infrastructure/external/alicloud"
"hyapi-server/internal/infrastructure/external/jiguang"
"hyapi-server/internal/infrastructure/external/muzi"
"hyapi-server/internal/infrastructure/external/shujubao"
"hyapi-server/internal/infrastructure/external/shumai"
"hyapi-server/internal/infrastructure/external/tianyancha"
"hyapi-server/internal/infrastructure/external/westdex"
"hyapi-server/internal/infrastructure/external/xingwei"
"hyapi-server/internal/infrastructure/external/yushan"
"hyapi-server/internal/infrastructure/external/zhicha"
"hyapi-server/internal/shared/interfaces"
)
// CombServiceInterface 组合包服务接口
type CombServiceInterface interface {
ProcessCombRequest(ctx context.Context, params []byte, deps *ProcessorDependencies, packageCode string) (*CombinedResult, error)
}
// CallContext CallApi调用上下文包含调用相关的数据
type CallContext struct {
ContractCode string // 合同编号
}
// ProcessorDependencies 处理器依赖容器
type ProcessorDependencies struct {
WestDexService *westdex.WestDexService
ShujubaoService *shujubao.ShujubaoService
MuziService *muzi.MuziService
YushanService *yushan.YushanService
TianYanChaService *tianyancha.TianYanChaService
AlicloudService *alicloud.AlicloudService
ZhichaService *zhicha.ZhichaService
XingweiService *xingwei.XingweiService
JiguangService *jiguang.JiguangService
ShumaiService *shumai.ShumaiService
Validator interfaces.RequestValidator
CombService CombServiceInterface // Changed to interface to break import cycle
Options *commands.ApiCallOptions // 添加Options支持
CallContext *CallContext // 添加CallApi调用上下文
// 企业报告记录仓储,用于持久化 QYGLJ1U9 生成的企业报告
ReportRepo repositories.ReportRepository
// 企业报告 PDF 异步预生成(可为 nil
ReportPDFScheduler QYGLReportPDFScheduler
// APIPublicBaseURL 对外 API 根地址(无尾斜杠),用于 QYGL reportUrl 等
APIPublicBaseURL string
}
// NewProcessorDependencies 创建处理器依赖容器
func NewProcessorDependencies(
westDexService *westdex.WestDexService,
shujubaoService *shujubao.ShujubaoService,
muziService *muzi.MuziService,
yushanService *yushan.YushanService,
tianYanChaService *tianyancha.TianYanChaService,
alicloudService *alicloud.AlicloudService,
zhichaService *zhicha.ZhichaService,
xingweiService *xingwei.XingweiService,
jiguangService *jiguang.JiguangService,
shumaiService *shumai.ShumaiService,
validator interfaces.RequestValidator,
combService CombServiceInterface, // Changed to interface
reportRepo repositories.ReportRepository,
reportPDFScheduler QYGLReportPDFScheduler,
apiPublicBaseURL string,
) *ProcessorDependencies {
return &ProcessorDependencies{
WestDexService: westDexService,
ShujubaoService: shujubaoService,
MuziService: muziService,
YushanService: yushanService,
TianYanChaService: tianYanChaService,
AlicloudService: alicloudService,
ZhichaService: zhichaService,
XingweiService: xingweiService,
JiguangService: jiguangService,
ShumaiService: shumaiService,
Validator: validator,
CombService: combService,
Options: nil, // 初始化为nil在调用时设置
CallContext: nil, // 初始化为nil在调用时设置
ReportRepo: reportRepo,
ReportPDFScheduler: reportPDFScheduler,
APIPublicBaseURL: apiPublicBaseURL,
}
}
// WithOptions 设置Options的便捷方法
func (deps *ProcessorDependencies) WithOptions(options *commands.ApiCallOptions) *ProcessorDependencies {
deps.Options = options
return deps
}
// WithCallContext 设置CallContext的便捷方法
func (deps *ProcessorDependencies) WithCallContext(callContext *CallContext) *ProcessorDependencies {
deps.CallContext = callContext
return deps
}
// ProcessorFunc 处理器函数类型定义
type ProcessorFunc func(ctx context.Context, params []byte, deps *ProcessorDependencies) ([]byte, error)
// CombinedResult 组合结果
type CombinedResult struct {
Responses []*SubProductResult `json:"responses"` // 子接口响应列表
}
// SubProductResult 子产品处理结果
type SubProductResult struct {
ApiCode string `json:"api_code"` // 子接口标识
Data interface{} `json:"data"` // 子接口返回数据
Success bool `json:"success"` // 是否成功
Error string `json:"error,omitempty"` // 错误信息(仅在失败时)
SortOrder int `json:"-"` // 排序字段不输出到JSON
}

View File

@@ -0,0 +1,67 @@
package dwbg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/zhicha"
)
// ProcessDWBG5SAMRequest DWBG5SAM 海宇指迷报告
func ProcessDWBG5SAMRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.DWBG5SAMReq
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,
"accessoryUrl": paramsDto.AuthorizationURL,
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI112", 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)
}
}
// 过滤响应数据,删除指定字段
if respMap, ok := respData.(map[string]interface{}); ok {
delete(respMap, "reportUrl")
}
// 将响应数据转换为JSON字节
respBytes, err := json.Marshal(respData)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return respBytes, nil
}

View File

@@ -0,0 +1,67 @@
package dwbg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/zhicha"
)
// ProcessDWBG6A2CRequest DWBG6A2C API处理方法 - 司南报告
func ProcessDWBG6A2CRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.DWBG6A2CReq
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,
"accessoryUrl": paramsDto.AuthorizationURL,
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI102", 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)
}
}
// 过滤响应数据,删除指定字段
if respMap, ok := respData.(map[string]interface{}); ok {
delete(respMap, "reportUrl")
delete(respMap, "multCourtInfo")
// delete(respMap, "judiciaRiskInfos")
}
// 将响应数据转换为JSON字节
respBytes, err := json.Marshal(respData)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return respBytes, nil
}

View File

@@ -0,0 +1,51 @@
package dwbg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/xingwei"
)
// ProcessDWBG7F3ARequest DWBG7F3A API处理方法 - 行为数据查询
func ProcessDWBG7F3ARequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.DWBG7F3AReq
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)
}
// 构建请求数据使用xingwei服务的正确字段名
reqData := map[string]interface{}{
"name": paramsDto.Name,
"idCardNum": paramsDto.IDCard,
"phoneNumber": paramsDto.MobileNo,
}
// 调用行为数据API使用指定的project_id
projectID := "CDJ-1101695406546284544"
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
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
package processors
import "errors"
// 处理器相关错误类型
var (
ErrDatasource = errors.New("数据源异常")
ErrSystem = errors.New("系统异常")
ErrInvalidParam = errors.New("参数校验不正确")
ErrNotFound = errors.New("查询为空")
)

View File

@@ -0,0 +1,91 @@
package processors
import (
"errors"
"testing"
)
func TestErrorsJoin_Is(t *testing.T) {
// 创建一个参数验证错误
originalErr := errors.New("字段验证失败")
joinedErr := errors.Join(ErrInvalidParam, originalErr)
// 测试 errors.Is 是否能正确识别错误类型
if !errors.Is(joinedErr, ErrInvalidParam) {
t.Errorf("errors.Is(joinedErr, ErrInvalidParam) 应该返回 true")
}
if errors.Is(joinedErr, ErrSystem) {
t.Errorf("errors.Is(joinedErr, ErrSystem) 应该返回 false")
}
// 测试错误消息
expectedMsg := "参数校验不正确\n字段验证失败"
if joinedErr.Error() != expectedMsg {
t.Errorf("错误消息不匹配,期望: %s, 实际: %s", expectedMsg, joinedErr.Error())
}
}
func TestErrorsJoin_Unwrap(t *testing.T) {
originalErr := errors.New("原始错误")
joinedErr := errors.Join(ErrSystem, originalErr)
// 测试 Unwrap - errors.Join 的 Unwrap 行为
// errors.Join 的 Unwrap 可能返回 nil 或者第一个错误,这取决于实现
// 我们主要关心 errors.Is 是否能正确工作
if !errors.Is(joinedErr, ErrSystem) {
t.Errorf("errors.Is(joinedErr, ErrSystem) 应该返回 true")
}
}
func TestErrorsJoin_MultipleErrors(t *testing.T) {
err1 := errors.New("错误1")
err2 := errors.New("错误2")
joinedErr := errors.Join(ErrNotFound, err1, err2)
// 测试 errors.Is 识别多个错误类型
if !errors.Is(joinedErr, ErrNotFound) {
t.Errorf("errors.Is(joinedErr, ErrNotFound) 应该返回 true")
}
// 测试错误消息
expectedMsg := "查询为空\n错误1\n错误2"
if joinedErr.Error() != expectedMsg {
t.Errorf("错误消息不匹配,期望: %s, 实际: %s", expectedMsg, joinedErr.Error())
}
}
func TestErrorsJoin_RealWorldScenario(t *testing.T) {
// 模拟真实的处理器错误场景
validationErr := errors.New("手机号格式不正确")
processorErr := errors.Join(ErrInvalidParam, validationErr)
// 在应用服务层,现在应该可以正确识别错误类型
if !errors.Is(processorErr, ErrInvalidParam) {
t.Errorf("应用服务层应该能够识别 ErrInvalidParam")
}
// 错误消息应该包含两种信息
errorMsg := processorErr.Error()
if !contains(errorMsg, "参数校验不正确") {
t.Errorf("错误消息应该包含错误类型: %s", errorMsg)
}
if !contains(errorMsg, "手机号格式不正确") {
t.Errorf("错误消息应该包含原始错误: %s", errorMsg)
}
}
// 辅助函数:检查字符串是否包含子字符串
func contains(s, substr string) bool {
return len(s) >= len(substr) && (s == substr ||
(len(s) > len(substr) && (s[:len(substr)] == substr ||
s[len(s)-len(substr):] == substr ||
func() bool {
for i := 1; i <= len(s)-len(substr); i++ {
if s[i:i+len(substr)] == substr {
return true
}
}
return false
}())))
}

View File

@@ -0,0 +1,39 @@
package flxg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/yushan"
)
// ProcessFLXG0687Request FLXG0687 API处理方法
func ProcessFLXG0687Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXG0687Req
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{}{
"keyWord": paramsDto.IDCard,
"type": 3,
}
respBytes, err := deps.YushanService.CallAPI(ctx, "RIS031", reqData)
if err != nil {
if errors.Is(err, yushan.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
}
return respBytes, nil
}

View File

@@ -0,0 +1,51 @@
package flxg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
)
// ProcessFLXG0V3Bequest FLXG0V3B API处理方法
func ProcessFLXG0V3Bequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXG0V3BReq
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)
}
reqData := map[string]interface{}{
"data": map[string]interface{}{
"name": encryptedName,
"id_card": encryptedIDCard,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "G34BJ03", 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,527 @@
package flxg
import (
"context"
"encoding/json"
"errors"
"fmt"
"log"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
"github.com/tidwall/gjson"
)
// ProcessFLXG0V4BRequest FLXG0V4B API处理方法(身份证排空入口,身份证身份证身份证身份证身份证)
func ProcessFLXG0V4BRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXG0V4BReq
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)
}
// 去掉司法案件案件去掉身份证号码
if paramsDto.IDCard == "350681198611130611" || paramsDto.IDCard == "622301200006250550" || paramsDto.IDCard == "320682198910134998" || paramsDto.IDCard == "640102198708020925" || paramsDto.IDCard == "420624197310234034" || paramsDto.IDCard == "350104198501184416" || paramsDto.IDCard == "410521198606018056" {
return nil, errors.Join(processors.ErrNotFound, errors.New("查询为空"))
}
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)
}
if deps.CallContext.ContractCode == "" {
return nil, fmt.Errorf("%s: %w", processors.ErrSystem, errors.New("合同编号不能为空"))
}
encryptedAuthAuthorizeFileCode, err := deps.WestDexService.Encrypt(deps.CallContext.ContractCode)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
reqData := map[string]interface{}{
"data": map[string]interface{}{
"name": encryptedName,
"idcard": encryptedIDCard,
"auth_authorizeFileCode": encryptedAuthAuthorizeFileCode,
"inquired_auth": fmt.Sprintf("authed:%s", paramsDto.AuthDate),
},
}
log.Println("reqData", reqData)
respBytes, err := deps.WestDexService.CallAPI(ctx, "G22SC01", reqData)
if err != nil {
// 数据源错误
if errors.Is(err, westdex.ErrDatasource) {
// 如果有返回内容,优先解析返回内容
if respBytes != nil {
parsed, parseErr := ParseJsonResponse(respBytes)
if parseErr == nil {
// 通过gjson获取指定路径的数据
contentResult := gjson.GetBytes(parsed, "G22SC0101.G22SC0102.content")
if contentResult.Exists() {
return []byte(contentResult.Raw), errors.Join(processors.ErrDatasource, err)
}
return parsed, errors.Join(processors.ErrDatasource, err)
}
// 解析失败,返回原始内容和系统错误
return respBytes, fmt.Errorf("%s: %w", processors.ErrSystem, parseErr)
}
// 没有返回内容,直接返回数据源错误
return nil, errors.Join(processors.ErrDatasource, err)
}
// 其他系统错误
return nil, errors.Join(processors.ErrSystem, err)
}
// 正常返回 - 不管有没有deps.Options.Json都进行ParseJsonResponse
parsed, parseErr := ParseJsonResponse(respBytes)
if parseErr != nil {
return nil, fmt.Errorf("%s: %w", processors.ErrSystem, parseErr)
}
// 通过gjson获取指定路径的数据
contentResult := gjson.GetBytes(parsed, "G22SC0101.G22SC0102.content")
if contentResult.Exists() {
return []byte(contentResult.Raw), nil
} else {
return nil, errors.Join(processors.ErrDatasource, err)
}
}
// Content 数据内容
type FLXG0V4BResponse struct {
Sxbzxr Sxbzxr `json:"sxbzxr"` // 失信被执行人
Entout Entout `json:"entout"` // 涉诉信息
Xgbzxr Xgbzxr `json:"xgbzxr"` // 限高被执行人
}
// Sxbzxr 失信被执行人
type Sxbzxr struct {
Msg string `json:"msg"` // 备注信息
Data SxbzxrData `json:"data"` // 数据结果
}
// SxbzxrData 失信被执行人数据
type SxbzxrData struct {
Sxbzxr []SxbzxrItem `json:"sxbzxr"` // 失信被执行人列表
}
// SxbzxrItem 失信被执行人项
type SxbzxrItem struct {
Yw string `json:"yw"` // 生效法律文书确定的义务
PjjeGj int `json:"pjje_gj"` // 判决金额_估计
Xwqx string `json:"xwqx"` // 失信被执行人行为具体情形
ID string `json:"id"` // 标识
Zxfy string `json:"zxfy"` // 执行法院
Ah string `json:"ah"` // 案号
Zxyjwh string `json:"zxyjwh"` // 执行依据文号
Lxqk string `json:"lxqk"` // 被执行人的履行情况
Zxyjdw string `json:"zxyjdw"` // 出执行依据单位
Fbrq string `json:"fbrq"` // 发布时间(日期)
Xb string `json:"xb"` // 性别
Larq string `json:"larq"` // 立案日期
Sf string `json:"sf"` // 省份
}
// Entout 涉诉信息
type Entout struct {
Msg string `json:"msg"` // 备注信息
Data EntoutData `json:"data"` // 数据结果
}
// EntoutData 涉诉信息数据
type EntoutData struct {
Administrative Administrative `json:"administrative"` // 行政案件
Implement Implement `json:"implement"` // 执行案件
Count Count `json:"count"` // 统计
Preservation Preservation `json:"preservation"` // 案件类型(非诉保全审查)
Crc int `json:"crc"` // 当事人变更码
Civil Civil `json:"civil"` // 民事案件
Criminal Criminal `json:"criminal"` // 刑事案件
CasesTree CasesTree `json:"cases_tree"` // 串联树
Bankrupt Bankrupt `json:"bankrupt"` // 强制清算与破产案件
}
// Administrative 行政案件
type Administrative struct {
Cases []AdministrativeCase `json:"cases"` // 案件
Count Count `json:"count"` // 统计
}
// AdministrativeCase 行政案件项
type AdministrativeCase struct {
NjabdjeGjLevel int `json:"n_jabdje_gj_level"` // 结案标的金额估计等级
NjbfyCj string `json:"n_jbfy_cj"` // 法院所属层级
CgkwsGlah string `json:"c_gkws_glah"` // 相关案件号
Njafs string `json:"n_jafs"` // 结案方式
Nssdw string `json:"n_ssdw"` // 诉讼地位
Djarq string `json:"d_jarq"` // 结案时间
CgkwsPjjg string `json:"c_gkws_pjjg"` // 判决结果
Nqsbdje int `json:"n_qsbdje"` // 起诉标的金额
Ncrc int `json:"n_crc"` // 案件变更码
Cssdy string `json:"c_ssdy"` // 所属地域
Najjzjd string `json:"n_ajjzjd"` // 案件进展阶段
Njaay string `json:"n_jaay"` // 结案案由
Najlx string `json:"n_ajlx"` // 案件类型
CahYs string `json:"c_ah_ys"` // 原审案号
NlaayTree string `json:"n_laay_tree"` // 立案案由详细
NjabdjeLevel int `json:"n_jabdje_level"` // 结案标的金额等级
Nlaay string `json:"n_laay"` // 立案案由
Najbs string `json:"n_ajbs"` // 案件标识
Njbfy string `json:"n_jbfy"` // 经办法院
CgkwsID string `json:"c_gkws_id"` // 公开文书ID
NjabdjeGj int `json:"n_jabdje_gj"` // 结案标的金额估计
NpjVictory string `json:"n_pj_victory"` // 胜诉估计
CgkwsDsr string `json:"c_gkws_dsr"` // 当事人
Nslcx string `json:"n_slcx"` // 审理程序
NqsbdjeLevel int `json:"n_qsbdje_level"` // 起诉标的金额等级
CID string `json:"c_id"` // 案件唯一ID
NssdwYs string `json:"n_ssdw_ys"` // 一审诉讼地位
Cslfsxx string `json:"c_slfsxx"` // 审理方式信息
Cah string `json:"c_ah"` // 案号
Cdsrxx []Dsrxx `json:"c_dsrxx"` // 当事人
Dlarq string `json:"d_larq"` // 立案时间
NjaayTree string `json:"n_jaay_tree"` // 结案案由详细
CahHx string `json:"c_ah_hx"` // 后续案号
Njabdje int `json:"n_jabdje"` // 结案标的金额
}
// Implement 执行案件
type Implement struct {
Cases []ImplementCase `json:"cases"` // 案件
Count Count `json:"count"` // 统计
}
// ImplementCase 执行案件项
type ImplementCase struct {
Cdsrxx []Dsrxx `json:"c_dsrxx"` // 当事人
Cssdy string `json:"c_ssdy"` // 所属地域
NjabdjeGj int `json:"n_jabdje_gj"` // 结案标的金额估计
Ncrc int `json:"n_crc"` // 案件变更码
Nlaay string `json:"n_laay"` // 立案案由
Cah string `json:"c_ah"` // 案号
Nsqzxbdje int `json:"n_sqzxbdje"` // 申请执行标的金额
CahYs string `json:"c_ah_ys"` // 原审案号
CgkwsGlah string `json:"c_gkws_glah"` // 相关案件号
Najbs string `json:"n_ajbs"` // 案件标识
CgkwsPjjg string `json:"c_gkws_pjjg"` // 判决结果
Njafs string `json:"n_jafs"` // 结案方式
Njaay string `json:"n_jaay"` // 结案案由
NjbfyCj string `json:"n_jbfy_cj"` // 法院所属层级
CID string `json:"c_id"` // 案件唯一ID
Njabdje int `json:"n_jabdje"` // 结案标的金额
Najjzjd string `json:"n_ajjzjd"` // 案件进展阶段
Dlarq string `json:"d_larq"` // 立案时间
Najlx string `json:"n_ajlx"` // 案件类型
Nsjdwje int `json:"n_sjdwje"` // 实际到位金额
CgkwsID string `json:"c_gkws_id"` // 公开文书ID
CahHx string `json:"c_ah_hx"` // 后续案号
Nwzxje int `json:"n_wzxje"` // 未执行金额
Djarq string `json:"d_jarq"` // 结案时间
CgkwsDsr string `json:"c_gkws_dsr"` // 当事人
Njbfy string `json:"n_jbfy"` // 经办法院
Nssdw string `json:"n_ssdw"` // 诉讼地位
}
// Preservation 案件类型(非诉保全审查)
type Preservation struct {
Cases []PreservationCase `json:"cases"` // 案件
Count Count `json:"count"` // 统计
}
// PreservationCase 非诉保全审查案件项
type PreservationCase struct {
NjbfyCj string `json:"n_jbfy_cj"` // 法院所属层级
Nssdw string `json:"n_ssdw"` // 诉讼地位
Ncrc int `json:"n_crc"` // 案件变更码
Cssdy string `json:"c_ssdy"` // 所属地域
Dlarq string `json:"d_larq"` // 立案时间
CgkwsID string `json:"c_gkws_id"` // 公开文书ID
CahYs string `json:"c_ah_ys"` // 原审案号
Nsqbqse int `json:"n_sqbqse"` // 申请保全数额
Djarq string `json:"d_jarq"` // 结案时间
Najbs string `json:"n_ajbs"` // 案件标识
CgkwsDsr string `json:"c_gkws_dsr"` // 当事人
CgkwsPjjg string `json:"c_gkws_pjjg"` // 判决结果
Njbfy string `json:"n_jbfy"` // 经办法院
Njafs string `json:"n_jafs"` // 结案方式
Cdsrxx []Dsrxx `json:"c_dsrxx"` // 当事人
Najjzjd string `json:"n_ajjzjd"` // 案件进展阶段
Najlx string `json:"n_ajlx"` // 案件类型
CID string `json:"c_id"` // 案件唯一ID
Cah string `json:"c_ah"` // 案号
NsqbqseLevel int `json:"n_sqbqse_level"` // 申请保全数额等级
CahHx string `json:"c_ah_hx"` // 后续案号
Csqbqbdw string `json:"c_sqbqbdw"` // 申请保全标的物
CgkwsGlah string `json:"c_gkws_glah"` // 相关案件号
}
// Civil 民事案件
type Civil struct {
Cases []CivilCase `json:"cases"` // 案件
Count Count `json:"count"` // 统计
}
// CivilCase 民事案件项
type CivilCase struct {
NjabdjeLevel int `json:"n_jabdje_level"` // 结案标的金额等级
Nslcx string `json:"n_slcx"` // 审理程序
NjabdjeGjLevel int `json:"n_jabdje_gj_level"` // 结案标的金额估计等级
Najjzjd string `json:"n_ajjzjd"` // 案件进展阶段
Njafs string `json:"n_jafs"` // 结案方式
CgkwsPjjg string `json:"c_gkws_pjjg"` // 判决结果
Cslfsxx string `json:"c_slfsxx"` // 审理方式信息
Nlaay string `json:"n_laay"` // 立案案由
CgkwsGlah string `json:"c_gkws_glah"` // 相关案件号
Nssdw string `json:"n_ssdw"` // 诉讼地位
NssdwYs string `json:"n_ssdw_ys"` // 一审诉讼地位
NlaayTag string `json:"n_laay_tag"` // 立案案由标签
NqsbdjeLevel int `json:"n_qsbdje_level"` // 起诉标的金额等级
Ncrc int `json:"n_crc"` // 案件变更码
CahHx string `json:"c_ah_hx"` // 后续案号
NqsbdjeGjLevel int `json:"n_qsbdje_gj_level"` // 起诉标的金额估计等级
Njbfy string `json:"n_jbfy"` // 经办法院
Cah string `json:"c_ah"` // 案号
Njabdje int `json:"n_jabdje"` // 结案标的金额
NjabdjeGj int `json:"n_jabdje_gj"` // 结案标的金额估计
NqsbdjeGj int `json:"n_qsbdje_gj"` // 起诉标的金额估计
NjbfyCj string `json:"n_jbfy_cj"` // 法院所属层级
Cssdy string `json:"c_ssdy"` // 所属地域
Dlarq string `json:"d_larq"` // 立案时间
CgkwsID string `json:"c_gkws_id"` // 公开文书ID
NpjVictory string `json:"n_pj_victory"` // 胜诉估计
CgkwsDsr string `json:"c_gkws_dsr"` // 当事人
Djarq string `json:"d_jarq"` // 结案时间
Njaay string `json:"n_jaay"` // 结案案由
NlaayTree string `json:"n_laay_tree"` // 立案案由详细
Cdsrxx []Dsrxx `json:"c_dsrxx"` // 当事人
CahYs string `json:"c_ah_ys"` // 原审案号
Nqsbdje int `json:"n_qsbdje"` // 起诉标的金额
NjaayTree string `json:"n_jaay_tree"` // 结案案由详细
Najlx string `json:"n_ajlx"` // 案件类型
CID string `json:"c_id"` // 案件唯一ID
Najbs string `json:"n_ajbs"` // 案件标识
}
// Criminal 刑事案件
type Criminal struct {
Cases []CriminalCase `json:"cases"` // 案件
Count Count `json:"count"` // 统计
}
// CriminalCase 刑事案件项
type CriminalCase struct {
CgkwsDsr string `json:"c_gkws_dsr"` // 当事人
NpcpcjeLevel int `json:"n_pcpcje_level"` // 判处赔偿金额等级
Nbqqpcje int `json:"n_bqqpcje"` // 被请求赔偿金额
NpcpcjeGjLevel int `json:"n_pcpcje_gj_level"` // 判处赔偿金额估计等级
Dlarq string `json:"d_larq"` // 立案时间
Djarq string `json:"d_jarq"` // 结案时间
CahHx string `json:"c_ah_hx"` // 后续案号
Njafs string `json:"n_jafs"` // 结案方式
NjaayTag string `json:"n_jaay_tag"` // 结案案由标签
Njbfy string `json:"n_jbfy"` // 经办法院
NlaayTag string `json:"n_laay_tag"` // 立案案由标签
Ndzzm string `json:"n_dzzm"` // 定罪罪名
NjbfyCj string `json:"n_jbfy_cj"` // 法院所属层级
NlaayTree string `json:"n_laay_tree"` // 立案案由详细
NccxzxjeLevel int `json:"n_ccxzxje_level"` // 财产刑执行金额等级
Ncrc int `json:"n_crc"` // 案件变更码
Cdsrxx []Dsrxx `json:"c_dsrxx"` // 当事人
NccxzxjeGjLevel int `json:"n_ccxzxje_gj_level"` // 财产刑执行金额估计等级
Nfzje int `json:"n_fzje"` // 犯罪金额
CgkwsID string `json:"c_gkws_id"` // 公开文书ID
Cah string `json:"c_ah"` // 案号
Cssdy string `json:"c_ssdy"` // 所属地域
Npcpcje int `json:"n_pcpcje"` // 判处赔偿金额
CahYs string `json:"c_ah_ys"` // 原审案号
Najjzjd string `json:"n_ajjzjd"` // 案件进展阶段
CgkwsGlah string `json:"c_gkws_glah"` // 相关案件号
CgkwsPjjg string `json:"c_gkws_pjjg"` // 判决结果
Cslfsxx string `json:"c_slfsxx"` // 审理方式信息
NpcpcjeGj int `json:"n_pcpcje_gj"` // 判处赔偿金额估计
Najbs string `json:"n_ajbs"` // 案件标识
Nlaay string `json:"n_laay"` // 立案案由
Njaay string `json:"n_jaay"` // 结案案由
Nssdw string `json:"n_ssdw"` // 诉讼地位
NdzzmTree string `json:"n_dzzm_tree"` // 定罪罪名树
NjaayTree string `json:"n_jaay_tree"` // 结案案由详细
Npcjg string `json:"n_pcjg"` // 判处结果
CID string `json:"c_id"` // 案件唯一ID
NssdwYs string `json:"n_ssdw_ys"` // 一审诉讼地位
Nccxzxje int `json:"n_ccxzxje"` // 财产刑执行金额
NfzjeLevel int `json:"n_fzje_level"` // 犯罪金额等级
Nslcx string `json:"n_slcx"` // 审理程序
Najlx string `json:"n_ajlx"` // 案件类型
NbqqpcjeLevel int `json:"n_bqqpcje_level"` // 被请求赔偿金额等级
NccxzxjeGj int `json:"n_ccxzxje_gj"` // 财产刑执行金额估计
}
// CasesTree 串联树
type CasesTree struct {
Administrative []CasesTreeItem `json:"administrative"` // 行政案件
Criminal []CasesTreeItem `json:"criminal"` // 刑事案件
Civil []CasesTreeItem `json:"civil"` // 民事案件
}
// CasesTreeItem 串联树项
type CasesTreeItem struct {
Cah string `json:"c_ah"` // 案号
CaseType int `json:"case_type"` // 案件类型
Najbs string `json:"n_ajbs"` // 案件标识
StageType int `json:"stage_type"` // 审理阶段类型
Next *CasesTreeItem `json:"next"` // 下一个案件
}
// Bankrupt 强制清算与破产案件
type Bankrupt struct {
Cases []BankruptCase `json:"cases"` // 案件
Count Count `json:"count"` // 统计
}
// BankruptCase 强制清算与破产案件项
type BankruptCase struct {
Cdsrxx []Dsrxx `json:"c_dsrxx"` // 当事人
CgkwsID string `json:"c_gkws_id"` // 公开文书ID
Najbs string `json:"n_ajbs"` // 案件标识
NjbfyCj string `json:"n_jbfy_cj"` // 法院所属层级
CgkwsDsr string `json:"c_gkws_dsr"` // 当事人
CID string `json:"c_id"` // 案件唯一ID
Dlarq string `json:"d_larq"` // 立案时间
Djarq string `json:"d_jarq"` // 结案时间
Najlx string `json:"n_ajlx"` // 案件类型
CgkwsGlah string `json:"c_gkws_glah"` // 相关案件号
Njbfy string `json:"n_jbfy"` // 经办法院
Najjzjd string `json:"n_ajjzjd"` // 案件进展阶段
CgkwsPjjg string `json:"c_gkws_pjjg"` // 判决结果
Cssdy string `json:"c_ssdy"` // 所属地域
Ncrc int `json:"n_crc"` // 案件变更码
Nssdw string `json:"n_ssdw"` // 诉讼地位
Njafs string `json:"n_jafs"` // 结案方式
Cah string `json:"c_ah"` // 案号
}
// Dsrxx 当事人
type Dsrxx struct {
Nssdw string `json:"n_ssdw"` // 诉讼地位
CMc string `json:"c_mc"` // 名称
Ndsrlx string `json:"n_dsrlx"` // 当事人类型
}
// Count 统计
type Count struct {
MoneyYuangao int `json:"money_yuangao"` // 原告金额
AreaStat string `json:"area_stat"` // 涉案地点分布
CountJieBeigao int `json:"count_jie_beigao"` // 被告已结案总数
CountTotal int `json:"count_total"` // 案件总数
MoneyWeiYuangao int `json:"money_wei_yuangao"` // 原告未结案金额
CountWeiTotal int `json:"count_wei_total"` // 未结案总数
MoneyWeiBeigao int `json:"money_wei_beigao"` // 被告未结案金额
CountOther int `json:"count_other"` // 第三人总数
MoneyBeigao int `json:"money_beigao"` // 被告金额
CountYuangao int `json:"count_yuangao"` // 原告总数
MoneyJieOther int `json:"money_jie_other"` // 第三人已结案金额
MoneyTotal int `json:"money_total"` // 涉案总金额
MoneyWeiTotal int `json:"money_wei_total"` // 未结案金额
CountWeiYuangao int `json:"count_wei_yuangao"` // 原告未结案总数
AyStat string `json:"ay_stat"` // 涉案案由分布
CountBeigao int `json:"count_beigao"` // 被告总数
MoneyJieYuangao int `json:"money_jie_yuangao"` // 原告已结金额
JafsStat string `json:"jafs_stat"` // 结案方式分布
MoneyJieBeigao int `json:"money_jie_beigao"` // 被告已结案金额
CountWeiBeigao int `json:"count_wei_beigao"` // 被告未结案总数
CountJieOther int `json:"count_jie_other"` // 第三人已结案总数
CountJieTotal int `json:"count_jie_total"` // 已结案总数
CountWeiOther int `json:"count_wei_other"` // 第三人未结案总数
MoneyOther int `json:"money_other"` // 第三人金额
CountJieYuangao int `json:"count_jie_yuangao"` // 原告已结案总数
MoneyJieTotal int `json:"money_jie_total"` // 已结案金额
MoneyWeiOther int `json:"money_wei_other"` // 第三人未结案金额
MoneyWeiPercent float64 `json:"money_wei_percent"` // 未结案金额百分比
LarqStat string `json:"larq_stat"` // 涉案时间分布
}
// Xgbzxr 限高被执行人
type Xgbzxr struct {
Msg string `json:"msg"` // 备注信息
Data XgbzxrData `json:"data"` // 数据结果
}
// XgbzxrData 限高被执行人数据
type XgbzxrData struct {
Xgbzxr []XgbzxrItem `json:"xgbzxr"` // 限高被执行人列表
}
// XgbzxrItem 限高被执行人项
type XgbzxrItem struct {
Ah string `json:"ah"` // 案号
ID string `json:"id"` // 标识
Zxfy string `json:"zxfy"` // 执行法院
Fbrq string `json:"fbrq"` // 发布时间
}
// ParseWestResponse 解析西部返回的响应数据获取data字段后解析
// westResp: 西部返回的原始响应
// Returns: 解析后的数据字节数组
func ParseWestResponse(westResp []byte) ([]byte, error) {
dataResult := gjson.GetBytes(westResp, "data")
if !dataResult.Exists() {
return nil, errors.New("data not found")
}
return ParseJsonResponse([]byte(dataResult.Raw))
}
// ParseJsonResponse 直接解析JSON响应数据
// jsonResp: JSON响应数据
// Returns: 解析后的数据字节数组
func ParseJsonResponse(jsonResp []byte) ([]byte, error) {
parseResult, err := RecursiveParse(string(jsonResp))
if err != nil {
return nil, err
}
resultResp, marshalErr := json.Marshal(parseResult)
if marshalErr != nil {
return nil, err
}
return resultResp, nil
}
// RecursiveParse 递归解析JSON数据
func RecursiveParse(data interface{}) (interface{}, error) {
switch v := data.(type) {
case string:
var parsed interface{}
if err := json.Unmarshal([]byte(v), &parsed); err == nil {
return RecursiveParse(parsed)
}
return v, nil
case map[string]interface{}:
for key, val := range v {
parsed, err := RecursiveParse(val)
if err != nil {
return nil, err
}
v[key] = parsed
}
return v, nil
case []interface{}:
for i, item := range v {
parsed, err := RecursiveParse(item)
if err != nil {
return nil, err
}
v[i] = parsed
}
return v, nil
default:
return v, nil
}
}

View File

@@ -0,0 +1,57 @@
package flxg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
)
// ProcessFLXG162ARequest FLXG162A API处理方法
func ProcessFLXG162ARequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXG162AReq
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,
"id": encryptedIDCard,
"cell": encryptedMobileNo,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "G32BJ05", 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,60 @@
package flxg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/zhicha"
)
// ProcessFLXG2E8FRequest FLXG2E8F API处理方法 - 司法核验报告
func ProcessFLXG2E8FRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXG2E8FReq
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,
"accessoryUrl": paramsDto.AuthorizationURL,
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI101", 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,63 @@
package flxg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/zhicha"
)
// ProcessFLXG3A9BRequest FLXG3A9B API处理方法 - 法院被执行人限高版
func ProcessFLXG3A9BRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXG3A9BReq
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)
}
if paramsDto.IDCard == "410482198504029333" {
return nil, errors.Join(processors.ErrNotFound, errors.New("查询为空"))
}
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, "ZCI045", 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,66 @@
package flxg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
)
// ProcessFLXG3D56Request FLXG3D56 API处理方法
func ProcessFLXG3D56Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXG3D56Req
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,
"id": encryptedIDCard,
"cell": encryptedMobileNo,
},
}
// 只有当 TimeRange 不为空时才加密和传参
if paramsDto.TimeRange != "" {
encryptedTimeRange, err := deps.WestDexService.Encrypt(paramsDto.TimeRange)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
reqData["data"].(map[string]interface{})["time_range"] = encryptedTimeRange
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "G26BJ05", 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 flxg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
)
// ProcessFLXG54F5Request FLXG54F5 API处理方法
func ProcessFLXG54F5Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXG54F5Req
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{}{
"mobile": encryptedMobileNo,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx,"G03HZ01", 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 flxg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
)
// ProcessFLXG5876Request FLXG5876 易诉人识别API处理方法
func ProcessFLXG5876Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXG5876Req
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, "G03XM02", 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,58 @@
package flxg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/zhicha"
)
// ProcessFLXG5A3BRequest FLXG5A3B API处理方法 - 个人司法涉诉
func ProcessFLXG5A3BRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXG5A3BReq
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)
}
if paramsDto.IDCard == "350681198611130611" || paramsDto.IDCard == "622301200006250550" || paramsDto.IDCard == "320682198910134998" || paramsDto.IDCard == "640102198708020925" || paramsDto.IDCard == "420624197310234034" || paramsDto.IDCard == "350104198501184416" || paramsDto.IDCard == "410521198606018056" || paramsDto.IDCard == "410482198504029333" {
return nil, errors.Join(processors.ErrNotFound, errors.New("查询为空"))
}
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)
}
reqData := map[string]interface{}{
"name": encryptedName,
"idCard": encryptedIDCard,
"authorized": paramsDto.Authorized,
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI006", 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,88 @@
package flxg
import (
"context"
"encoding/json"
"errors"
"fmt"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
"github.com/tidwall/gjson"
)
// ProcessFLXG5B2ERequest FLXG5B2E API处理方法
func ProcessFLXG5B2ERequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXG5B2EReq
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)
}
if deps.CallContext.ContractCode == "" {
return nil, fmt.Errorf("%s: %w", processors.ErrSystem, errors.New("合同编号不能为空"))
}
encryptedAuthAuthorizeFileCode, err := deps.WestDexService.Encrypt(deps.CallContext.ContractCode)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
reqData := map[string]interface{}{
"data": map[string]interface{}{
"name": encryptedName,
"idcard": encryptedIDCard,
"auth_authorizeFileCode": encryptedAuthAuthorizeFileCode,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "G36SC01", reqData)
if err != nil {
if errors.Is(err, westdex.ErrDatasource) {
// 如果有返回内容,优先解析返回内容
if respBytes != nil {
parsed, parseErr := ParseJsonResponse(respBytes)
if parseErr == nil {
// 通过gjson获取指定路径的数据
contentResult := gjson.GetBytes(parsed, "G36SC0101.G36SC0102.content")
if contentResult.Exists() {
return []byte(contentResult.Raw), errors.Join(processors.ErrDatasource, err)
}
return parsed, errors.Join(processors.ErrDatasource, err)
}
// 解析失败,返回原始内容和系统错误
return respBytes, fmt.Errorf("%s: %w", processors.ErrSystem, parseErr)
}
// 没有返回内容,直接返回数据源错误
return nil, errors.Join(processors.ErrDatasource, err)
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
}
// 正常返回 - 不管有没有deps.Options.Json都进行ParseJsonResponse
parsed, parseErr := ParseJsonResponse(respBytes)
if parseErr != nil {
return nil, fmt.Errorf("%s: %w", processors.ErrSystem, parseErr)
}
// 通过gjson获取指定路径的数据
contentResult := gjson.GetBytes(parsed, "G36SC0101.G36SC0102.content")
if contentResult.Exists() {
return []byte(contentResult.Raw), nil
} else {
return nil, errors.Join(processors.ErrDatasource, err)
}
}

View File

@@ -0,0 +1,40 @@
package flxg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
)
// ProcessFLXG75FERequest FLXG75FE API处理方法
func ProcessFLXG75FERequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXG75FEReq
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,
"idCard": paramsDto.IDCard,
"mobile": paramsDto.MobileNo,
}
respBytes, err := deps.WestDexService.CallAPI(ctx,"FLXG75FE", 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,49 @@
package flxg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/xingwei"
)
// ProcessFLXG7E8FRequest FLXG7E8F API处理方法 - 个人司法数据查询
func ProcessFLXG7E8FRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXG7E8FReq
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)
}
if paramsDto.IDCard == "350681198611130611" || paramsDto.IDCard == "622301200006250550" || paramsDto.IDCard == "320682198910134998" || paramsDto.IDCard == "640102198708020925" || paramsDto.IDCard == "420624197310234034" || paramsDto.IDCard == "350104198501184416" || paramsDto.IDCard == "410521198606018056" || paramsDto.IDCard == "410482198504029333" {
return nil, errors.Join(processors.ErrNotFound, errors.New("查询为空"))
}
// 构建请求数据,将项目规范的字段名转换为 XingweiService 需要的字段名
reqData := map[string]interface{}{
"name": paramsDto.Name,
"idCardNum": paramsDto.IDCard,
"phoneNumber": paramsDto.MobileNo,
}
// 调用行为数据API使用指定的project_id
projectID := "CDJ-1101695378264092672"
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,86 @@
package flxg
import (
"context"
"encoding/json"
"errors"
"fmt"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
"github.com/tidwall/gjson"
)
// ProcessFLXG8A3FRequest FLXG8A3F API处理方法
func ProcessFLXG8A3FRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXG8A3FReq
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)
}
if deps.CallContext.ContractCode == "" {
return nil, fmt.Errorf("%s: %w", processors.ErrSystem, errors.New("合同编号不能为空"))
}
encryptedAuthAuthorizeFileCode, err := deps.WestDexService.Encrypt(deps.CallContext.ContractCode)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
reqData := map[string]interface{}{
"data": map[string]interface{}{
"name": encryptedName,
"idcard": encryptedIDCard,
"auth_authorizeFileCode": encryptedAuthAuthorizeFileCode,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "G37SC01", reqData)
if err != nil {
if errors.Is(err, westdex.ErrDatasource) {
// 如果有返回内容,优先解析返回内容
if respBytes != nil {
parsed, parseErr := ParseJsonResponse(respBytes)
if parseErr == nil {
// 通过gjson获取指定路径的数据
contentResult := gjson.GetBytes(parsed, "G37SC0101.G37SC0102.content")
if contentResult.Exists() {
return []byte(contentResult.Raw), errors.Join(processors.ErrDatasource, err)
}
return parsed, errors.Join(processors.ErrDatasource, err)
}
// 解析失败,返回原始内容和系统错误
return respBytes, fmt.Errorf("%s: %w", processors.ErrSystem, parseErr)
}
// 没有返回内容,直接返回数据源错误
return nil, errors.Join(processors.ErrDatasource, err)
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
}
// 正常返回 - 不管有没有deps.Options.Json都进行ParseJsonResponse
parsed, parseErr := ParseJsonResponse(respBytes)
if parseErr != nil {
return nil, fmt.Errorf("%s: %w", processors.ErrSystem, parseErr)
}
// 通过gjson获取指定路径的数据
contentResult := gjson.GetBytes(parsed, "G37SC0101.G37SC0102.content")
if contentResult.Exists() {
return []byte(contentResult.Raw), nil
} else {
return nil, errors.Join(processors.ErrDatasource, err)
}
}

View File

@@ -0,0 +1,104 @@
package flxg
import (
"context"
"encoding/json"
"errors"
"fmt"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/zhicha"
)
// ProcessFLXG8B4DRequest FLXG8B4D API处理方法 - 涉赌涉诈风险评估
func ProcessFLXG8B4DRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXG8B4DReq
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)
}
// 三选一校验MobileNo、IDCard、BankCard 必须且只能有一个
var fieldCount int
var selectedField string
var selectedValue string
if paramsDto.MobileNo != "" {
fieldCount++
selectedField = "mobile_no"
selectedValue = paramsDto.MobileNo
}
if paramsDto.IDCard != "" {
fieldCount++
selectedField = "id_card"
selectedValue = paramsDto.IDCard
}
if paramsDto.BankCard != "" {
fieldCount++
selectedField = "bank_card"
selectedValue = paramsDto.BankCard
}
if fieldCount == 0 {
return nil, fmt.Errorf("%s: %w", processors.ErrInvalidParam, errors.New("必须提供手机号、身份证号或银行卡号中的其中一个"))
}
if fieldCount > 1 {
return nil, fmt.Errorf("%s: %w", processors.ErrInvalidParam, errors.New("只能提供手机号、身份证号或银行卡号中的一个,不能同时提供多个"))
}
// 只对选中的字段进行加密
var encryptedValue string
var err error
switch selectedField {
case "mobile_no":
encryptedValue, err = deps.ZhichaService.Encrypt(selectedValue)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
case "id_card":
encryptedValue, err = deps.ZhichaService.Encrypt(selectedValue)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
case "bank_card":
encryptedValue, err = deps.ZhichaService.Encrypt(selectedValue)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
}
// 构建请求数据,根据选中的字段类型设置对应的参数
reqData := map[string]interface{}{
"authorized": paramsDto.Authorized,
}
switch selectedField {
case "mobile_no":
reqData["phone"] = encryptedValue
case "id_card":
reqData["idCard"] = encryptedValue
case "bank_card":
reqData["name"] = encryptedValue
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI027", 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,57 @@
package flxg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
)
// ProcessFLXG9687Request FLXG9687 API处理方法
func ProcessFLXG9687Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXG9687Req
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,
"id": encryptedIDCard,
"cell": encryptedMobileNo,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "G31BJ05", 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,51 @@
package flxg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
)
// ProcessFLXG970FRequest FLXG970F 风险人员核验API处理方法
func ProcessFLXG970FRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXG970FReq
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)
}
reqData := map[string]interface{}{
"data": map[string]interface{}{
"name": encryptedName,
"cardNo": encryptedIDCard,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "WEST00028", 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,58 @@
package flxg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/zhicha"
)
// ProcessFLXG9C1DRequest FLXG9C1D API处理方法 - 法院信息详情高级版
func ProcessFLXG9C1DRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXG9C1DReq
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)
}
if paramsDto.IDCard == "410482198504029333" {
return nil, errors.Join(processors.ErrNotFound, errors.New("查询为空"))
}
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)
}
reqData := map[string]interface{}{
"name": encryptedName,
"idCard": encryptedIDCard,
"authorized": paramsDto.Authorized,
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI007", 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,38 @@
package flxg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/yushan"
)
// ProcessFLXGBC21Request FLXGbc21 API处理方法
func ProcessFLXGBC21Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXGBC21Req
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{}{
"mobile": paramsDto.MobileNo,
}
respBytes, err := deps.YushanService.CallAPI(ctx, "MOB032", reqData)
if err != nil {
if errors.Is(err, yushan.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
}
return respBytes, nil
}

View File

@@ -0,0 +1,57 @@
package flxg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
)
// ProcessFLXGC9D1Request FLXGC9D1 API处理方法
func ProcessFLXGC9D1Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXGC9D1Req
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,
"id": encryptedIDCard,
"cell": encryptedMobileNo,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "G30BJ05", 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,57 @@
package flxg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
)
// ProcessFLXGCA3DRequest FLXGCA3D API处理方法
func ProcessFLXGCA3DRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXGCA3DReq
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)
}
if paramsDto.IDCard == "350681198611130611" || paramsDto.IDCard == "622301200006250550" || paramsDto.IDCard == "320682198910134998" || paramsDto.IDCard == "640102198708020925" || paramsDto.IDCard == "420624197310234034" || paramsDto.IDCard == "350104198501184416" || paramsDto.IDCard == "410521198606018056" {
return nil, errors.Join(processors.ErrNotFound, errors.New("查询为空"))
}
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)
}
reqData := map[string]interface{}{
"data": map[string]interface{}{
"name": encryptedName,
"id_card": encryptedIDCard,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "G22BJ03", reqData)
if err != nil {
if errors.Is(err, westdex.ErrDatasource) {
if respBytes != nil {
return respBytes, nil
} else {
return nil, errors.Join(processors.ErrDatasource, err)
}
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
}
return respBytes, nil
}

View File

@@ -0,0 +1,56 @@
package flxg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/zhicha"
)
// ProcessFLXGDEA8Request FLXGDEA8 API处理方法
func ProcessFLXGDEA8Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXGDEA8Req
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)
}
reqData := map[string]interface{}{
"name": encryptedName,
"idCard": encryptedIDCard,
"authorized": paramsDto.Authorized,
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI028", 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,57 @@
package flxg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/zhicha"
)
// ProcessFLXGDEA9Request FLXGDEA9 API处理方法
func ProcessFLXGDEA9Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXGDEA9Req
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)
}
if paramsDto.IDCard == "350681198611130611" || paramsDto.IDCard == "622301200006250550" || paramsDto.IDCard == "320682198910134998" || paramsDto.IDCard == "640102198708020925" || paramsDto.IDCard == "420624197310234034" || paramsDto.IDCard == "350104198501184416" || paramsDto.IDCard == "410521198606018056" {
return nil, errors.Join(processors.ErrNotFound, errors.New("查询为空"))
}
encryptedIDCard, err := deps.ZhichaService.Encrypt(paramsDto.IDCard)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
reqData := map[string]interface{}{
"name": encryptedName,
"idCard": encryptedIDCard,
"authorized": paramsDto.Authorized,
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI005", 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,51 @@
package flxg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
)
// ProcessFLXGDEC7Request FLXGDEC7 API处理方法
func ProcessFLXGDEC7Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXGDEC7Req
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)
}
reqData := map[string]interface{}{
"data": map[string]interface{}{
"name": encryptedName,
"id_card": encryptedIDCard,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "G23BJ03", 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,54 @@
package flxg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shujubao"
)
// ProcessFLXGDJG3Request FLXGDJG3 董监高司法综合信息核验 API 处理方法(使用数据宝服务示例)
func ProcessFLXGDJG3Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXGDJG3Req
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)
}
// 构建数据宝入参sign 外的业务参数可按需 AES 加密后作为 bodyData
reqParams := map[string]interface{}{
"key": "1cce582f0a6f3ca40de80f1bea9b9698",
"idcard": paramsDto.IDCard,
}
// 最终请求 URL = https://api.chinadatapay.com/communication + 拼接接口地址值,如 personal/197
apiPath := "/communication/personal/10166"
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)
}
// 解析响应中的 JSON 字符串(使用 qyglb4c0 中的 RecursiveParse
parsedResp, err := RecursiveParse(data)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
respBytes, err := json.Marshal(parsedResp)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return respBytes, nil
}

View File

@@ -0,0 +1,63 @@
package flxg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/zhicha"
)
// ProcessFLXGK5D2Request FLXGK5D2 API处理方法 - 法院被执行人高级版
func ProcessFLXGK5D2Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXGK5D2Req
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)
}
if paramsDto.IDCard == "410482198504029333" {
return nil, errors.Join(processors.ErrNotFound, errors.New("查询为空"))
}
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, "ZCI046", 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,51 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
)
// ProcessIVYZ0B03Request IVYZ0B03 API处理方法
func ProcessIVYZ0B03Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ0B03Req
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)
}
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,
"phone": encryptedMobileNo,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "G17BJ02", 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 ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/jiguang"
)
// ProcessIVYZ0S0DRequest IVYZ0S0D API处理方法 - 劳动仲裁信息查询(个人版)
func ProcessIVYZ0S0DRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ0S0DReq
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{}{
"id": paramsDto.IDCard,
"name": paramsDto.Name,
}
// 调用极光API
respBytes, err := deps.JiguangService.CallAPI(ctx, "labor-arbitration-information", "labor-arbitration-information", reqData)
if err != nil {
// 根据错误类型返回相应的错误
if errors.Is(err, jiguang.ErrNotFound) {
return nil, errors.Join(processors.ErrNotFound, err)
} else if errors.Is(err, jiguang.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
}
// 极光服务已经返回了 data 字段的 JSON直接返回即可
return respBytes, nil
}

View File

@@ -0,0 +1,63 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shujubao"
)
// ProcessIVYZ18HYRequest IVYZ18HY 婚姻状况核验V2单人 API 处理方法(使用数据宝服务示例)
func ProcessIVYZ18HYRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ18HYReq
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)
}
fixedData := map[string]interface{}{"msg": "请联系商务咨询"}
fixedRespBytes, err := json.Marshal(fixedData)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return fixedRespBytes, nil
authDate := ""
if len(paramsDto.AuthDate) >= 8 {
authDate = paramsDto.AuthDate[len(paramsDto.AuthDate)-8:]
}
reqParams := map[string]interface{}{
"key": "",
"idcard": paramsDto.IDCard,
"name": paramsDto.Name,
"maritalType": paramsDto.MaritalType,
"authcode": paramsDto.AuthAuthorizeFileBase64,
"authAuthorizeFileCode": paramsDto.AuthAuthorizeFileCode,
"authDate": authDate,
}
// 最终请求 URL = https://api.chinadatapay.com/communication + 拼接接口地址值,如 personal/197
apiPath := "/communication/personal/10333"
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,52 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
)
// ProcessIVYZ1C9DRequest IVYZ1C9D API处理方法
func ProcessIVYZ1C9DRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ1C9DReq
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)
}
reqData := map[string]interface{}{
"data": map[string]interface{}{
"xm": encryptedName,
"sfzh": encryptedIDCard,
"yearNum": paramsDto.Years,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "G38SC02", 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,46 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/jiguang"
)
// ProcessIVYZ1J7HRequest IVYZ1J7H API处理方法 - 行驶证核查v2
func ProcessIVYZ1J7HRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ1J7HReq
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{}{
"plate": paramsDto.PlateNo,
"plateType": paramsDto.CarPlateType,
"name": paramsDto.Name,
}
// 调用极光API
respBytes, err := deps.JiguangService.CallAPI(ctx, "vehicle-driving-license-v2", "vehicle/driving-license-v2", reqData)
if err != nil {
// 根据错误类型返回相应的错误
if errors.Is(err, jiguang.ErrNotFound) {
return nil, errors.Join(processors.ErrNotFound, err)
} else if errors.Is(err, jiguang.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
}
// 极光服务已经返回了 data 字段的 JSON直接返回即可
return respBytes, nil
}

View File

@@ -0,0 +1,38 @@
package ivyz
import (
"context"
"errors"
"hyapi-server/internal/domains/api/services/processors"
)
// ProcessIVYZ2125Request IVYZ2125 API处理方法
func ProcessIVYZ2125Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
return nil, errors.Join(processors.ErrSystem, errors.New("服务已停用"))
// var paramsDto dto.IVYZ2125Req
// 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,
// "idCard": paramsDto.IDCard,
// "mobile": paramsDto.Mobile,
// }
// respBytes, err := deps.WestDexService.CallAPI(ctx, "IVYZ2125", 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,54 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shujubao"
)
// ProcessIVYZ28HYRequest IVYZ28HY 婚姻状况核验单人) API 处理方法(使用数据宝服务示例)
func ProcessIVYZ28HYRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ28HYReq
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)
}
fixedData := map[string]interface{}{"msg": "请联系商务咨询"}
fixedRespBytes, err := json.Marshal(fixedData)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return fixedRespBytes, nil
reqParams := map[string]interface{}{
"key": "",
"idcard": paramsDto.IDCard,
"name": paramsDto.Name,
}
// 最终请求 URL = https://api.chinadatapay.com/communication + 拼接接口地址值,如 personal/197
apiPath := "/communication/personal/10149"
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,161 @@
package ivyz
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"
)
// ivyz2a8bShumaiResp 数脉 /v4/id_card/check 返回格式
type ivyz2a8bShumaiResp struct {
Result float64 `json:"result"`
OrderNo string `json:"order_no"`
Desc string `json:"desc"`
Sex string `json:"sex"`
Birthday string `json:"birthday"` // yyyyMMdd
Address string `json:"address"`
}
// ProcessIVYZ2A8BRequest IVYZ2A8B API处理方法 - 身份二要素认证政务版 数脉内部替换
func ProcessIVYZ2A8BRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ2A8BReq
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" // 接口路径,根据数脉文档填写(如 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.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)
}
}
}
// 将数脉返回的新格式映射为原有 API 输出格式
oldFormat, err := mapIVYZ2A8BShumaiToOld(respBytes)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return json.Marshal(oldFormat)
}
func mapIVYZ2A8BShumaiToOld(respBytes []byte) (map[string]interface{}, error) {
var r ivyz2a8bShumaiResp
if err := json.Unmarshal(respBytes, &r); err != nil {
return nil, err
}
// final_auth_result: "0"=一致,"1"=不一致/无记录;按 result0-一致1-不一致2-无记录(预留)
finalAuth := "1"
switch int(r.Result) {
case 0:
finalAuth = "0"
}
return map[string]interface{}{
"final_auth_result": finalAuth,
"birthday": formatBirthdayOld(r.Birthday),
"address": r.Address,
"constellation": constellationFromBirthday(r.Birthday),
"gender": r.Sex,
"age": ageFromBirthday(r.Birthday),
}, nil
}
func formatBirthdayOld(s string) string {
s = strings.TrimSpace(s)
if len(s) != 8 {
return s
}
for _, c := range s {
if c < '0' || c > '9' {
return s
}
}
return s[0:4] + "年" + s[4:6] + "月" + s[6:8] + "日"
}
func constellationFromBirthday(s string) string {
if len(s) != 8 {
return ""
}
month, _ := strconv.Atoi(s[4:6])
day, _ := strconv.Atoi(s[6:8])
if month < 1 || month > 12 || day < 1 || day > 31 {
return ""
}
switch {
case (month == 12 && day >= 22) || (month == 1 && day <= 19):
return "魔羯座"
case (month == 1 && day >= 20) || (month == 2 && day <= 18):
return "水瓶座"
case (month == 2 && day >= 19) || (month == 3 && day <= 20):
return "双鱼座"
case (month == 3 && day >= 21) || (month == 4 && day <= 19):
return "白羊座"
case (month == 4 && day >= 20) || (month == 5 && day <= 20):
return "金牛座"
case (month == 5 && day >= 21) || (month == 6 && day <= 21):
return "双子座"
case (month == 6 && day >= 22) || (month == 7 && day <= 22):
return "巨蟹座"
case (month == 7 && day >= 23) || (month == 8 && day <= 22):
return "狮子座"
case (month == 8 && day >= 23) || (month == 9 && day <= 22):
return "处女座"
case (month == 9 && day >= 23) || (month == 10 && day <= 23):
return "天秤座"
case (month == 10 && day >= 24) || (month == 11 && day <= 22):
return "天蝎座"
case (month == 11 && day >= 23) || (month == 12 && day <= 21):
return "射手座"
default:
return "魔羯座"
}
}
func ageFromBirthday(s string) string {
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,58 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"strconv"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
)
// ProcessIVYZ2B2TRequest IVYZ2B2T API处理方法 能力资质核验(学历)
func ProcessIVYZ2B2TRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ2B2TReq
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)
}
encryptedQueryReasonId, err := deps.WestDexService.Encrypt(strconv.FormatInt(paramsDto.QueryReasonId, 10))
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
reqData := map[string]interface{}{
"data": map[string]interface{}{
"idCard": encryptedIDCard,
"name": encryptedName,
"queryReasonId": encryptedQueryReasonId,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "G11JX01", 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,56 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/zhicha"
)
// ProcessIVYZ2C1PRequest IVYZ2C1P API处理方法 - 风控黑名单
func ProcessIVYZ2C1PRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ2C1PReq
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)
}
reqData := map[string]interface{}{
"name": encryptedName,
"idCard": encryptedIDCard,
"authorized": paramsDto.Authorized,
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI037", 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,54 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/zhicha"
)
// ProcessIVYZ2MN6Request IVYZ2MN6 API处理方法
func ProcessIVYZ2MN6Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ2MN6Req
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)
}
reqData := map[string]interface{}{
"name": encryptedName,
"idCard": encryptedIDCard,
"authorized": paramsDto.Authorized,
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI1004", reqData)
if err != nil {
if errors.Is(err, zhicha.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
}
return nil, errors.Join(processors.ErrSystem, err)
}
respBytes, err := json.Marshal(respData)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return respBytes, nil
}

View File

@@ -0,0 +1,49 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
)
// ProcessIVYZ385ERequest IVYZ385E API处理方法
func ProcessIVYZ385ERequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ385EReq
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)
}
reqData := map[string]interface{}{
"xm": encryptedName,
"gmsfzhm": encryptedIDCard,
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "WEST00020", 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,56 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shujubao"
)
// ProcessIVYZ38SRRequest IVYZ38SR 婚姻状态核验(双人) API 处理方法(使用数据宝服务示例)
func ProcessIVYZ38SRRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ38SRReq
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)
}
fixedData := map[string]interface{}{"msg": "请联系商务咨询"}
fixedRespBytes, err := json.Marshal(fixedData)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return fixedRespBytes, nil
reqParams := map[string]interface{}{
"key": "",
"name": paramsDto.ManName,
"idcard": paramsDto.ManIDCard,
"woman_name": paramsDto.WomanName,
"woman_idcard": paramsDto.WomanIDCard,
}
// 最终请求 URL = https://api.chinadatapay.com/communication + 拼接接口地址值,如 personal/197
apiPath := "/communication/personal/10148"
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,50 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/xingwei"
)
// ProcessIVYZ3A7FRequest IVYZ3A7F API处理方法 - 行为数据查询
func ProcessIVYZ3A7FRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ3A7FReq
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)
}
// 构建请求数据使用xingwei服务的正确字段名
reqData := map[string]interface{}{
"name": paramsDto.Name,
"idCardNum": paramsDto.IDCard,
}
// 调用行为数据API使用指定的project_id
projectID := "CDJ-1104648854749245440"
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,64 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/muzi"
)
// ProcessIVYZ3P9MRequest IVYZ3P9M API处理方法 - 学历查询实时版
func ProcessIVYZ3P9MRequest_2(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ3P9MReq
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.MuziService.Encrypt(paramsDto.Name)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
encryptedCertCode, err := deps.MuziService.Encrypt(paramsDto.IDCard)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
// 处理 returnType 参数,默认为 "1"
returnType := paramsDto.ReturnType
if returnType == "" {
returnType = "1"
}
paramSign := map[string]interface{}{
"returnType": returnType,
"realName": encryptedName,
"certCode": encryptedCertCode,
}
reqData := map[string]interface{}{
"realName": encryptedName,
"certCode": encryptedCertCode,
"returnType": returnType,
}
respData, err := deps.MuziService.CallAPI(ctx, "PC0041", "/academic", reqData, paramSign)
if err != nil {
switch {
case errors.Is(err, muzi.ErrDatasource):
return nil, errors.Join(processors.ErrDatasource, err)
case errors.Is(err, muzi.ErrSystem):
return nil, errors.Join(processors.ErrSystem, err)
default:
return nil, errors.Join(processors.ErrSystem, err)
}
}
return respData, nil
}

View File

@@ -0,0 +1,168 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"strings"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/zhicha"
)
// ProcessIVYZ3P9MRequest IVYZ3P9M API处理方法 - 学历查询实时版
func ProcessIVYZ3P9MRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ3P9MReq
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)
}
reqData := map[string]interface{}{
"name": encryptedName,
"idCard": encryptedIDCard,
"authorized": "1",
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI1004", reqData)
if err != nil {
if errors.Is(err, zhicha.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
}
return nil, errors.Join(processors.ErrSystem, err)
}
out, err := mapZCI1004ToIVYZ3P9M(respData, paramsDto.Name, paramsDto.IDCard)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return json.Marshal(out)
}
type zci1004Item struct {
EndDate string `json:"endDate"`
EducationLevel string `json:"educationLevel"`
LearningForm string `json:"learningForm"`
}
type ivyz3p9mItem struct {
GraduationDate string `json:"graduationDate"`
StudentName string `json:"studentName"`
EducationLevel string `json:"educationLevel"`
LearningForm string `json:"learningForm"`
IDNumber string `json:"idNumber"`
}
func mapZCI1004ToIVYZ3P9M(respData interface{}, name, idCard string) ([]ivyz3p9mItem, error) {
respBytes, err := json.Marshal(respData)
if err != nil {
return nil, err
}
var source []zci1004Item
if err := json.Unmarshal(respBytes, &source); err != nil {
var wrapped struct {
Data []zci1004Item `json:"data"`
}
if err2 := json.Unmarshal(respBytes, &wrapped); err2 != nil {
return nil, err
}
source = wrapped.Data
}
out := make([]ivyz3p9mItem, 0, len(source))
for _, it := range source {
out = append(out, ivyz3p9mItem{
GraduationDate: normalizeDateDigits(it.EndDate),
StudentName: name,
EducationLevel: mapEducationLevelToCode(it.EducationLevel),
LearningForm: mapLearningFormToCode(it.LearningForm),
IDNumber: idCard,
})
}
return out, nil
}
func mapEducationLevelToCode(level string) string {
v := normalizeText(level)
switch {
case strings.Contains(v, "第二学士"):
return "5"
case strings.Contains(v, "博士"):
return "4"
case strings.Contains(v, "硕士"):
return "3"
case strings.Contains(v, "本科"):
return "2"
case strings.Contains(v, "专科"), strings.Contains(v, "大专"):
return "1"
default:
return "99"
}
}
func mapLearningFormToCode(form string) string {
v := normalizeText(form)
switch {
case strings.Contains(v, "脱产"):
return "1"
case strings.Contains(v, "普通全日制"):
return "2"
case strings.Contains(v, "全日制"):
return "3"
case strings.Contains(v, "开放教育"), strings.Contains(v, "开放大学"):
return "4"
case strings.Contains(v, "夜大学"), strings.Contains(v, "夜大"):
return "5"
case strings.Contains(v, "函授"):
return "6"
case strings.Contains(v, "网络教育"), strings.Contains(v, "网教"), strings.Contains(v, "远程教育"):
return "7"
case strings.Contains(v, "非全日制"):
return "8"
case strings.Contains(v, "业余"):
return "9"
case strings.Contains(v, "自学考试"), strings.Contains(v, "自考"):
// 自考在既有枚举中无直对应,兼容并入“业余”
return "9"
default:
return "99"
}
}
func normalizeDateDigits(s string) string {
trimmed := strings.TrimSpace(s)
if trimmed == "" {
return ""
}
var b strings.Builder
for _, ch := range trimmed {
if ch >= '0' && ch <= '9' {
b.WriteRune(ch)
}
}
return b.String()
}
func normalizeText(s string) string {
v := strings.TrimSpace(strings.ToLower(s))
v = strings.ReplaceAll(v, " ", "")
v = strings.ReplaceAll(v, "-", "")
v = strings.ReplaceAll(v, "_", "")
return v
}

View File

@@ -0,0 +1,58 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shujubao"
)
// ProcessIVYZ48SRRequest IVYZ48SR 婚姻状态核验V2双人 API 处理方法(使用数据宝服务示例)
func ProcessIVYZ48SRRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ48SRReq
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)
}
fixedData := map[string]interface{}{"msg": "请联系商务咨询"}
fixedRespBytes, err := json.Marshal(fixedData)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return fixedRespBytes, nil
reqParams := map[string]interface{}{
"key": "",
"name": paramsDto.ManName,
"idcard": paramsDto.ManIDCard,
"woman_name": paramsDto.WomanName,
"woman_idcard": paramsDto.WomanIDCard,
"marital_type": paramsDto.MaritalType,
"auth_authorize_file_code": paramsDto.AuthAuthorizeFileCode,
}
// 最终请求 URL = https://api.chinadatapay.com/communication + 拼接接口地址值,如 personal/197
apiPath := "/communication/personal/10332"
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,84 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"fmt"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
"github.com/tidwall/gjson"
)
// ProcessIVYZ4E8BRequest IVYZ4E8B API处理方法
func ProcessIVYZ4E8BRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ4E8BReq
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)
}
reqData := map[string]interface{}{
"data": map[string]interface{}{
"name": encryptedName,
"idNo": encryptedIDCard,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "G09GZ02", 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)
}
}
// 解析响应提取data字段中的hyzk
var respMap map[string]interface{}
if err := json.Unmarshal(respBytes, &respMap); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
dataStr, ok := respMap["data"].(string)
if !ok {
return nil, fmt.Errorf("%s: data字段格式错误", processors.ErrDatasource)
}
// 使用gjson解析data字符串
hyzk := ""
{
result := gjson.Get(dataStr, "hyzk")
if !result.Exists() {
return nil, fmt.Errorf("%s: data中缺少hyzk字段", processors.ErrDatasource)
}
hyzk = result.String()
}
// 返回格式为 {"status": hyzk}
resp := map[string]interface{}{
"status": hyzk,
}
finalBytes, err := json.Marshal(resp)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return finalBytes, nil
}

View File

@@ -0,0 +1,83 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
)
// ProcessIVYZ5733Request IVYZ5733 API处理方法
func ProcessIVYZ5733Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ5733Req
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)
}
reqData := map[string]interface{}{
"data": map[string]interface{}{
"name": encryptedName,
"idNo": encryptedIDCard,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "G09GZ02", 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)
}
}
// 解析新源响应数据
var newResp struct {
Status string `json:"status"`
}
if err := json.Unmarshal(respBytes, &newResp); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
// 转换状态码
var statusCode string
switch newResp.Status {
case "结婚":
statusCode = "IA"
case "离婚":
statusCode = "IB"
case "未查得":
statusCode = "INR"
default:
statusCode = "INR"
}
// 构建旧格式响应
oldResp := map[string]interface{}{
"code": "0",
"data": map[string]interface{}{
"data": statusCode + ":匹配不成功",
},
"seqNo": "",
"message": "成功",
}
// 返回旧格式响应
return json.Marshal(oldResp)
}

View File

@@ -0,0 +1,57 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
)
// ProcessIVYZ5A9ORequest IVYZ5A9O API处理方法 全国⾃然⼈⻛险评估评分模型
func ProcessIVYZ5A9ORequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ5A9OReq
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)
}
encryptedAuthAuthorizeFileCode, err := deps.WestDexService.Encrypt(paramsDto.AuthAuthorizeFileCode)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
reqData := map[string]interface{}{
"data": map[string]interface{}{
"idcard": encryptedIDCard,
"name": encryptedName,
"auth_authorizeFileCode": encryptedAuthAuthorizeFileCode,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "G01SC01", 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,66 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/zhicha"
)
// ProcessIVYZ5E22Request API处理方法 - 双人婚姻评估查询
func ProcessIVYZ5E22Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ5E22Req
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)
}
encryptedManName, err := deps.ZhichaService.Encrypt(paramsDto.ManName)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
encryptedManIDCard, err := deps.ZhichaService.Encrypt(paramsDto.ManIDCard)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
encryptedWomanName, err := deps.ZhichaService.Encrypt(paramsDto.WomanName)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
encryptedWomanIDCard, err := deps.ZhichaService.Encrypt(paramsDto.WomanIDCard)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
reqData := map[string]interface{}{
"nameMan": encryptedManName,
"idCardMan": encryptedManIDCard,
"nameWoman": encryptedWomanName,
"idCardWoman": encryptedWomanIDCard,
"authorized": paramsDto.Authorized,
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI042", 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,56 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/zhicha"
)
// ProcessIVYZ5E3FRequest IVYZ5E3F API处理方法 - 婚姻评估查询
func ProcessIVYZ5E3FRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ5E3FReq
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)
}
reqData := map[string]interface{}{
"name": encryptedName,
"idCard": encryptedIDCard,
"authorized": paramsDto.Authorized,
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI029", 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,46 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/xingwei"
)
// ProcessIVYZ6G7HRequest IVYZ6G7H API处理方法 - 个人婚姻状况查询v2
func ProcessIVYZ6G7HRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ6G7HReq
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,
}
// 调用行为数据API使用指定的project_id
projectID := "CDJ-1104646268587536384"
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,46 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/xingwei"
)
// ProcessIVYZ6M8PRequest IVYZ6M8P 职业资格证书API处理方法
func ProcessIVYZ6M8PRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ6M8PReq
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,
}
// 调用行为数据API使用指定的project_id
projectID := "CDJ-1147725836315455488"
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,47 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/zhicha"
)
// ProcessIVYZ7C9DRequest IVYZ7C9D API处理方法 - 人脸识别
func ProcessIVYZ7C9DRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ7C9DReq
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,
"idCard": paramsDto.IDCard,
"returnUrl": paramsDto.ReturnURL,
"orderId": paramsDto.UniqueID,
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI013", 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,95 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"fmt"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
"github.com/tidwall/gjson"
)
// ProcessIVYZ7F2ARequest IVYZ7F2A API处理方法
func ProcessIVYZ7F2ARequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ7F2AReq
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)
}
encryptedManName, err := deps.WestDexService.Encrypt(paramsDto.ManName)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
encryptedManIDCard, err := deps.WestDexService.Encrypt(paramsDto.ManIDCard)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
encryptedWomanName, err := deps.WestDexService.Encrypt(paramsDto.WomanName)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
encryptedWomanIDCard, err := deps.WestDexService.Encrypt(paramsDto.WomanIDCard)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
reqData := map[string]interface{}{
"data": map[string]interface{}{
"manName": encryptedManName,
"manIdcard": encryptedManIDCard,
"womanName": encryptedWomanName,
"womanIdcard": encryptedWomanIDCard,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "G10GZ02", 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)
}
}
var respMap map[string]interface{}
if err := json.Unmarshal(respBytes, &respMap); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
dataStr, ok := respMap["data"].(string)
if !ok {
return nil, fmt.Errorf("%s: data字段格式错误", processors.ErrDatasource)
}
// 使用gjson解析data字符串
hyzk := ""
{
result := gjson.Get(dataStr, "hyzk")
if !result.Exists() {
return nil, fmt.Errorf("%s: data中缺少hyzk字段", processors.ErrDatasource)
}
hyzk = result.String()
}
// 返回格式为 {"status": hyzk}
resp := map[string]interface{}{
"status": hyzk,
}
finalBytes, err := json.Marshal(resp)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return finalBytes, nil
return respBytes, nil
}

View File

@@ -0,0 +1,56 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/zhicha"
)
// ProcessIVYZ7F3ARequest IVYZ7F3A API处理方法 - 学历信息查询B
func ProcessIVYZ7F3ARequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ7F3AReq
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)
}
reqData := map[string]interface{}{
"name": encryptedName,
"idCard": encryptedIDCard,
"authorized": paramsDto.Authorized,
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI035", 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,96 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/zhicha"
)
// ProcessIVYZ81NCRequest IVYZ81NC API处理方法
func ProcessIVYZ81NCRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ81NCReq
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)
}
reqData := map[string]interface{}{
"name": encryptedName,
"idCard": encryptedIDCard,
"authorized": "1", // 默认值
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI029", 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)
}
}
// 解析响应数据,期望格式为 {"state": "1"}
var stateResp struct {
State string `json:"state"`
RegTime string `json:"regTime"`
}
// 将 respData 转换为 JSON 字节再解析
respDataBytes, err := json.Marshal(respData)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := json.Unmarshal(respDataBytes, &stateResp); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
// 根据 state 值转换为 81nc 格式
var opType, opTypeDesc string
switch stateResp.State {
case "1": // 已婚
opType = "IA"
opTypeDesc = "结婚"
case "2": // 未婚/未在民政局登记
opType = "INR"
opTypeDesc = "匹配不成功"
case "3": // 离异
opType = "IB"
opTypeDesc = "离婚"
default:
opType = "INR"
opTypeDesc = "匹配不成功"
}
// 构建 81nc 格式响应
result := map[string]interface{}{
"code": "0",
"data": map[string]interface{}{
"op_date": stateResp.RegTime,
"op_type": opType,
"op_type_desc": opTypeDesc,
},
"message": "成功",
"seqNo": "",
}
// 返回 81nc 格式响应
return json.Marshal(result)
}

View File

@@ -0,0 +1,47 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/xingwei"
)
// ProcessIVYZ8I9JRequest IVYZ8I9J API处理方法 - 互联网行为推测
func ProcessIVYZ8I9JRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ8I9JReq
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-1074522823015198720"
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,68 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"strings"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
)
// ProcessIVYZ9363Request IVYZ9363 API处理方法
func ProcessIVYZ9363Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ9363Req
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)
}
// 新增:身份证一致性校验
if strings.EqualFold(strings.TrimSpace(paramsDto.ManIDCard), strings.TrimSpace(paramsDto.WomanIDCard)) {
return nil, errors.Join(processors.ErrInvalidParam, errors.New("请正确填写身份信息"))
}
encryptedManName, err := deps.WestDexService.Encrypt(paramsDto.ManName)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
encryptedManIDCard, err := deps.WestDexService.Encrypt(paramsDto.ManIDCard)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
encryptedWomanName, err := deps.WestDexService.Encrypt(paramsDto.WomanName)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
encryptedWomanIDCard, err := deps.WestDexService.Encrypt(paramsDto.WomanIDCard)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
reqData := map[string]interface{}{
"data": map[string]interface{}{
"name_man": encryptedManName,
"idcard_man": encryptedManIDCard,
"name_woman": encryptedWomanName,
"idcard_woman": encryptedWomanIDCard,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "G10XM02", 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,51 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
)
// ProcessIVYZ9A2BRequest IVYZ9A2B API处理方法
func ProcessIVYZ9A2BRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ9A2BReq
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)
}
reqData := map[string]interface{}{
"data": map[string]interface{}{
"name_value": encryptedName,
"id_card_value": encryptedIDCard,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "G11BJ06", 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,51 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/xingwei"
)
// ProcessIVYZ9D2ERequest IVYZ9D2E API处理方法 - 行为数据查询
func ProcessIVYZ9D2ERequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ9D2EReq
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)
}
// 构建请求数据使用xingwei服务的正确字段名
reqData := map[string]interface{}{
"name": paramsDto.Name,
"idCardNum": paramsDto.IDCard,
"scenario": paramsDto.UseScenario,
}
// 调用行为数据API使用指定的project_id
projectID := "CDJ-1104648845446279168"
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,47 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/jiguang"
)
// ProcessIVYZ9H2MRequest IVYZ9H2M API处理方法 - 极光个人婚姻查询V2版
func ProcessIVYZ9H2MRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ9H2MReq
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{}{
"id_no": paramsDto.IDCard,
"name": paramsDto.Name,
}
// 调用极光API
// apiCode: marriage-single-v2 (用于请求头)
// apiPath: marriage/single-v2 (用于URL路径)
respBytes, err := deps.JiguangService.CallAPI(ctx, "marriage-single-v2", "marriage/single-v2", reqData)
if err != nil {
// 根据错误类型返回相应的错误
if errors.Is(err, jiguang.ErrNotFound) {
return nil, errors.Join(processors.ErrNotFound, err)
} else if errors.Is(err, jiguang.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
}
// 极光服务已经返回了 data 字段的 JSON直接返回即可
return respBytes, nil
}

View File

@@ -0,0 +1,103 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"strconv"
"time"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
"github.com/tidwall/gjson"
)
// ProcessIVYZ9K2LRequest IVYZ9K2L API处理方法 - 身份认证三要素(人脸图像版)
func ProcessIVYZ9K2LRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ9K2LReq
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)
}
// 生成时间戳(毫秒)
timestamp := strconv.FormatInt(time.Now().UnixNano()/int64(time.Millisecond), 10)
// 获取自定义编号(从 WestDexService 配置中获取 secret_id
config := deps.WestDexService.GetConfig()
customNumber := config.SecretID
// 构建请求数据
reqData := map[string]interface{}{
"data": map[string]interface{}{
"timeStamp": timestamp,
"customNumber": customNumber,
"xM": encryptedName,
"gMSFZHM": encryptedIDCard,
"photoData": paramsDto.PhotoData,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "idCardThreeElements", reqData)
if err != nil {
switch {
case errors.Is(err, westdex.ErrDatasource):
return nil, errors.Join(processors.ErrDatasource, err)
case errors.Is(err, westdex.ErrSystem):
return nil, errors.Join(processors.ErrSystem, err)
default:
return nil, errors.Join(processors.ErrSystem, err)
}
}
// 使用gjson提取authResult字段
// 尝试多个可能的路径
var authResult string
paths := []string{
"WEST00037.WEST00038.authResult",
"WEST00036.WEST00037.WEST00038.authResult",
"authResult",
}
for _, path := range paths {
result := gjson.GetBytes(respBytes, path)
if result.Exists() {
authResult = result.String()
break
}
}
// 如果找不到authResult返回ErrDatasource
if authResult == "" {
return nil, errors.Join(processors.ErrDatasource, errors.New("响应中未找到authResult字段"))
}
// 构建返回格式 {result: XXXX}
response := map[string]interface{}{
"result": authResult,
}
responseBytes, err := json.Marshal(response)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return responseBytes, nil
}

View File

@@ -0,0 +1,48 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shumai"
)
// ProcessIVYZ9K7FRequest IVYZ9K7F 身份证实名认证即时版 API处理方法
func ProcessIVYZ9K7FRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ9K7FReq
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" // 接口路径,根据数脉文档填写(如 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,49 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shumai"
)
// ProcessIVYZA1B3Request IVYZA1B3 公安三要素人脸识别API处理方法
func ProcessIVYZA1B3Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZA1B3Req
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,
"image": paramsDto.PhotoData,
}
// 以表单方式调用数脉 API参数在 CallAPIForm 内转为 application/x-www-form-urlencoded
apiPath := "/v4/face_id_card/compare" // 接口路径,根据数脉文档填写(如 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,38 @@
package ivyz
import (
"context"
"errors"
"hyapi-server/internal/domains/api/services/processors"
)
// ProcessIVYZADEERequest IVYZADEE API处理方法
func ProcessIVYZADEERequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
return nil, errors.Join(processors.ErrSystem, errors.New("服务已停用"))
// var paramsDto dto.IVYZADEEReq
// 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,
// "idCard": paramsDto.IDCard,
// "mobile": paramsDto.Mobile,
// }
// respBytes, err := deps.WestDexService.CallAPI(ctx, "IVYZADEE", 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,51 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/xingwei"
)
// ProcessIVYZBPQ2Request IVYZBPQ2 人脸比对V2API处理方法
func ProcessIVYZBPQ2Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZBPQ2Req
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)
}
// 构建请求数据使用xingwei服务的正确字段名
reqData := map[string]interface{}{
"name": paramsDto.Name,
"idCardNum": paramsDto.IDCard,
"image": paramsDto.PhotoData,
}
// 调用行为数据API使用指定的project_id
projectID := "CDJ-1104321425593790464"
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,55 @@
package ivyz
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"
)
// ProcessIVYZFIC1Request IVYZFIC1 人脸身份证比对 API 处理方法(数脉)
func ProcessIVYZFIC1Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZFIC1Req
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)
}
if strings.TrimSpace(paramsDto.PhotoData) == "" && strings.TrimSpace(paramsDto.ImageUrl) == "" {
return nil, errors.Join(processors.ErrInvalidParam, errors.New("image和url至少传一个"))
}
reqFormData := map[string]interface{}{
"idcard": paramsDto.IDCard,
"name": paramsDto.Name,
"image": paramsDto.PhotoData,
"url": paramsDto.ImageUrl,
}
apiPath := "/v4/face_id_card/compare"
// 先尝试政务接口,再回退实时接口
respBytes, err := deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData, true)
if err != nil {
respBytes, err = deps.ShumaiService.CallAPIForm(ctx, apiPath, reqFormData, false)
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)
}
return nil, errors.Join(processors.ErrSystem, err)
}
}
return respBytes, nil
}

View File

@@ -0,0 +1,51 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/westdex"
)
// ProcessIVYZGZ08Request IVYZGZ08 API处理方法
func ProcessIVYZGZ08Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZGZ08Req
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)
}
reqData := map[string]interface{}{
"data": map[string]interface{}{
"xm": encryptedName,
"gmsfzhm": encryptedIDCard,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "G08SC02", 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,121 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shumai"
)
// ProcessIVYZN2P8Request IVYZN2P8 身份证实名认证政务版 API处理方法
func ProcessIVYZN2P8Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZ9K7FReq
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,
"idcard": paramsDto.IDCard,
}
// 以表单方式调用数脉 API参数在 CallAPIForm 内转为 application/x-www-form-urlencoded
apiPath := "/v4/id_card/check"
// 先尝试使用政务接口app_id2 和 app_secret2
respBytes, err := deps.ShumaiService.CallAPIForm(ctx, apiPath, reqData, true)
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)
}
}
return respBytes, nil
}
// 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)
// }
// return respBytes, nil
// // 对齐 yysybe08test 的原始响应结构,取 data 字段映射为 ivyzn2p8 返回
// var aliyunData struct {
// 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
// if aliyunData.Code == 200 {
// rawResult = aliyunData.Data.Result
// rawDesc = aliyunData.Data.Desc
// }
// response := map[string]interface{}{
// "result": normalizeResult(rawResult),
// "order_no": aliyunData.Data.OrderNo,
// "desc": rawDesc,
// "sex": aliyunData.Data.Sex,
// "birthday": aliyunData.Data.Birthday,
// "address": aliyunData.Data.Address,
// }
// return json.Marshal(response)
// }
// func normalizeResult(v interface{}) int {
// switch r := v.(type) {
// case float64:
// return int(r)
// case int:
// return r
// case int32:
// return int(r)
// case int64:
// return int(r)
// case json.Number:
// n, err := r.Int64()
// if err == nil {
// return int(n)
// }
// case string:
// s := strings.TrimSpace(r)
// if s == "" {
// return 1
// }
// n, err := strconv.Atoi(s)
// if err == nil {
// return n
// }
// }
// // 默认按不一致处理
// return 1
// }

View File

@@ -0,0 +1,48 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shujubao"
)
// ProcessIVYZOCR1Request IVYZOCR1 身份证OCR API 处理方法(使用数据宝服务示例)
func ProcessIVYZOCR1Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZOCR1Req
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)
}
// 构建数据宝入参姓名、身份证、手机号、银行卡号sign 外的业务参数可按需 AES 加密后作为 bodyData
reqParams := map[string]interface{}{
"key": "8782f2a32463f75b53096323461df735",
"imageId": paramsDto.PhotoData,
}
// 最终请求 URL = https://api.chinadatapay.com/communication + 拼接接口地址值,如 personal/197
apiPath := "/trade/user/1985"
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,56 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shumai"
)
// ProcessIVYZOCR2Request IVYZOCR2 OCR识别API处理方法数卖
func ProcessIVYZOCR2Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZOCR1Req
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)
}
if paramsDto.PhotoData == "" && paramsDto.ImageUrl == "" {
return nil, errors.Join(processors.ErrInvalidParam, errors.New("photo_data or image_url is required"))
}
// 2选1有值的用对应 key空则用另一个
reqFormData := make(map[string]interface{})
if paramsDto.PhotoData != "" {
reqFormData["image"] = paramsDto.PhotoData
} else {
reqFormData["url"] = paramsDto.ImageUrl
}
// 以表单方式调用数脉 API参数在 CallAPIForm 内转为 application/x-www-form-urlencoded
apiPath := "/v4/idcard/ocr" // 接口路径,根据数脉文档填写(如 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,84 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shumai"
)
// ProcessIVYZP2Q6Request IVYZP2Q6 API处理方法 - 身份认证二要素
func ProcessIVYZP2Q6Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZP2Q6Req
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" // 接口路径,根据数脉文档填写(如 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.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)
}
}
}
// 数据源返回 result(0-一致/1-不一致/2-无记录),映射为 state(1-匹配/2-不匹配/3-异常情况)
var dsResp struct {
Result int `json:"result"` // 0-一致 1-不一致 2-无记录(预留)
}
if err := json.Unmarshal(respBytes, &dsResp); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
state := resultToState(dsResp.Result)
out := map[string]interface{}{
"errMsg": "",
"state": state,
}
return json.Marshal(out)
}
// resultToState 将数据源 result 映射为接口 state1-匹配 2-不匹配 3-异常情况
func resultToState(result int) int {
switch result {
case 0: // 一致 → 匹配
return 1
case 1: // 不一致 → 不匹配
return 2
case 2: // 无记录(预留) → 异常情况
return 3
default:
return 3 // 未知/异常 → 异常情况
}
}

View File

@@ -0,0 +1,52 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/xingwei"
)
// ProcessIVYZSFELRequest IVYZSFEL 全国自然人人像三要素核验_V1API处理方法
func ProcessIVYZSFELRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZSFELReq
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)
}
// 构建请求数据使用xingwei服务的正确字段名
reqData := map[string]interface{}{
"name": paramsDto.Name,
"idCardNum": paramsDto.IDCard,
"photo": paramsDto.PhotoData,
"authAuthorizeFileCode": paramsDto.AuthAuthorizeFileCode,
}
// 调用行为数据API使用指定的project_id
projectID := "CDJ-1068350101927161856"
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,63 @@
package ivyz
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
"hyapi-server/internal/infrastructure/external/shumai"
"hyapi-server/internal/shared/logger"
"go.uber.org/zap"
)
// ProcessIVYZX5Q2Request IVYZX5Q2 活体识别步骤二API处理方法
func ProcessIVYZX5Q2Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.IVYZX5Q2Req
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{}{
"token": paramsDto.Token,
}
// 以表单方式调用数脉 API参数在 CallAPIForm 内转为 application/x-www-form-urlencoded
apiPath := "/v4/liveness/h5/v4/result" // 接口路径,根据数脉文档填写(如 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)
}
}
// result==2 时手动抛出错误(不通过/无记录,不返回正常响应)
var body struct {
Result int `json:"result"`
}
if err := json.Unmarshal(respBytes, &body); err == nil && body.Result == 2 {
log := logger.GetGlobalLogger()
log.Warn("IVYZX5Q2 活体检测 result=2 无记录或不通过,返回错误",
zap.Int("result", body.Result),
zap.ByteString("response", respBytes))
return nil, errors.Join(processors.ErrNotFound, errors.New("活体检测 result=2 无记录或不通过"))
}
return respBytes, nil
}

Some files were not shown because too many files have changed in this diff Show More