@@ -0,0 +1,466 @@
package pdfg
import (
"context"
"encoding/json"
"errors"
"fmt"
"time"
"tyapi-server/internal/config"
"tyapi-server/internal/domains/api/dto"
"tyapi-server/internal/domains/api/services/processors"
"tyapi-server/internal/infrastructure/external/pdfgen"
"tyapi-server/internal/shared/logger"
"tyapi-server/internal/shared/pdf"
"go.uber.org/zap"
)
// ProcessPDFG01GZRequest PDFG01GZ 处理器 - 大数据租赁风险PDF报告
func ProcessPDFG01GZRequest ( ctx context . Context , params [ ] byte , deps * processors . ProcessorDependencies ) ( [ ] byte , error ) {
var paramsDto dto . PDFG01GZReq
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 )
}
// 获取全局logger
zapLogger := logger . GetGlobalLogger ( )
// 从context获取config( 如果存在)
var cacheTTL time . Duration = 24 * time . Hour
var cacheDir string
if cfg , ok := ctx . Value ( "config" ) . ( * config . Config ) ; ok && cfg != nil {
cacheTTL = cfg . PDFGen . Cache . TTL
if cacheTTL == 0 {
cacheTTL = 24 * time . Hour
}
cacheDir = cfg . PDFGen . Cache . CacheDir
}
// 获取最大缓存大小
var maxSize int64
if cfg , ok := ctx . Value ( "config" ) . ( * config . Config ) ; ok && cfg != nil {
maxSize = cfg . PDFGen . Cache . MaxSize
}
// 创建PDF缓存管理器
cacheManager , err := pdf . NewPDFCacheManager ( zapLogger , cacheDir , cacheTTL , maxSize )
if err != nil {
return nil , errors . Join ( processors . ErrSystem , fmt . Errorf ( "创建PDF缓存管理器失败: %w" , err ) )
}
// 从context获取config创建PDF生成服务
var pdfGenService * pdfgen . PDFGenService
if cfg , ok := ctx . Value ( "config" ) . ( * config . Config ) ; ok && cfg != nil {
pdfGenService = pdfgen . NewPDFGenService ( cfg , zapLogger )
} else {
// 如果无法获取config, 使用默认配置
defaultCfg := & config . Config {
App : config . AppConfig { Env : "development" } ,
PDFGen : config . PDFGenConfig {
DevelopmentURL : "http://pdfg.tianyuanapi.com" ,
ProductionURL : "http://localhost:15990" ,
APIPath : "/api/v1/generate/guangzhou" ,
Timeout : 120 * time . Second ,
} ,
}
pdfGenService = pdfgen . NewPDFGenService ( defaultCfg , zapLogger )
}
// 检查缓存
_ , hit , createdAt , err := cacheManager . Get ( paramsDto . Name , paramsDto . IDCard )
if err != nil {
zapLogger . Warn ( "检查缓存失败, 继续生成PDF" , zap . Error ( err ) )
} else if hit {
// 缓存命中,模拟慢几秒
zapLogger . Info ( "PDF缓存命中, 返回缓存文件" ,
zap . String ( "name" , paramsDto . Name ) ,
zap . String ( "id_card" , paramsDto . IDCard ) ,
zap . Time ( "created_at" , createdAt ) ,
)
// 模拟慢几秒( 2-4秒)
time . Sleep ( 2 * time . Second )
// 生成下载链接
downloadURL := generateDownloadURL ( paramsDto . Name , paramsDto . IDCard )
return json . Marshal ( map [ string ] interface { } {
"download_url" : downloadURL ,
"cached" : true ,
"created_at" : createdAt . Format ( time . RFC3339 ) ,
} )
}
// 缓存未命中, 需要生成PDF
zapLogger . Info ( "PDF缓存未命中, 开始生成PDF" ,
zap . String ( "name" , paramsDto . Name ) ,
zap . String ( "id_card" , paramsDto . IDCard ) ,
)
// 调用多个处理器获取数据(即使部分失败也继续)
apiData := collectAPIData ( ctx , paramsDto , deps , zapLogger )
// 格式化数据为PDF生成服务需要的格式( 为缺失的数据提供默认值)
formattedData := formatDataForPDF ( apiData , paramsDto , zapLogger )
// 从APPLICANT_BASIC_INFO中提取报告编号( 如果存在)
var reportNumber string
if len ( formattedData ) > 0 {
if basicInfo , ok := formattedData [ 0 ] [ "data" ] . ( map [ string ] interface { } ) ; ok {
if rn , ok := basicInfo [ "report_number" ] . ( string ) ; ok {
reportNumber = rn
}
}
}
// 如果没有提取到,生成新的报告编号
if reportNumber == "" {
reportNumber = generateReportNumber ( )
}
// 构建PDF生成请求
pdfReq := & pdfgen . GeneratePDFRequest {
Data : formattedData ,
ReportNumber : reportNumber ,
GenerateTime : time . Now ( ) . Format ( "2006-01-02 15:04:05" ) ,
}
// 调用PDF生成服务
// 即使部分子处理器失败, 只要有APPLICANT_BASIC_INFO就可以生成PDF
pdfResp , err := pdfGenService . GenerateGuangzhouPDF ( ctx , pdfReq )
if err != nil {
zapLogger . Error ( "生成PDF失败" ,
zap . Error ( err ) ,
zap . Int ( "data_items" , len ( formattedData ) ) ,
)
return nil , errors . Join ( processors . ErrSystem , fmt . Errorf ( "生成PDF失败: %w" , err ) )
}
// 保存到缓存
if err := cacheManager . Set ( paramsDto . Name , paramsDto . IDCard , pdfResp . PDFBytes ) ; err != nil {
zapLogger . Warn ( "保存PDF到缓存失败" , zap . Error ( err ) )
// 不影响返回结果,只记录警告
}
// 生成下载链接
downloadURL := generateDownloadURL ( paramsDto . Name , paramsDto . IDCard )
zapLogger . Info ( "PDF生成成功" ,
zap . String ( "name" , paramsDto . Name ) ,
zap . String ( "id_card" , paramsDto . IDCard ) ,
zap . String ( "report_number" , reportNumber ) ,
zap . String ( "download_url" , downloadURL ) ,
)
return json . Marshal ( map [ string ] interface { } {
"download_url" : downloadURL ,
"report_number" : reportNumber ,
"cached" : false ,
} )
}
// collectAPIData 收集所有需要的API数据
// 即使部分或全部子处理器失败, 也会返回结果( 失败的设为nil) , 确保流程继续
func collectAPIData ( ctx context . Context , params dto . PDFG01GZReq , deps * processors . ProcessorDependencies , logger * zap . Logger ) map [ string ] interface { } {
apiData := make ( map [ string ] interface { } )
// 并发调用多个处理器
type processorResult struct {
apiCode string
data interface { }
err error
}
results := make ( chan processorResult , 5 )
// 调用IVYZ5A9O - 需要: name, id_card, auth_authorize_file_code
go func ( ) {
defer func ( ) {
if r := recover ( ) ; r != nil {
logger . Error ( "调用IVYZ5A9O处理器时发生panic" ,
zap . Any ( "panic" , r ) ,
)
results <- processorResult { "IVYZ5A9O" , nil , fmt . Errorf ( "处理器panic: %v" , r ) }
}
} ( )
// 检查必需字段
if params . AuthAuthorizeFileCode == "" {
logger . Warn ( "IVYZ5A9O缺少auth_authorize_file_code字段, 跳过调用" )
results <- processorResult { "IVYZ5A9O" , nil , fmt . Errorf ( "缺少必需字段: auth_authorize_file_code" ) }
return
}
ivyzParams := map [ string ] interface { } {
"name" : params . Name ,
"id_card" : params . IDCard ,
"auth_authorize_file_code" : params . AuthAuthorizeFileCode ,
}
paramsBytes , err := json . Marshal ( ivyzParams )
if err != nil {
logger . Warn ( "序列化IVYZ5A9O参数失败" , zap . Error ( err ) )
results <- processorResult { "IVYZ5A9O" , nil , err }
return
}
data , err := callProcessor ( ctx , "IVYZ5A9O" , paramsBytes , deps )
results <- processorResult { "IVYZ5A9O" , data , err }
} ( )
// 调用JRZQ8A2D - 需要: name, id_card, mobile_no, authorized
go func ( ) {
defer func ( ) {
if r := recover ( ) ; r != nil {
logger . Error ( "调用JRZQ8A2D处理器时发生panic" ,
zap . Any ( "panic" , r ) ,
)
results <- processorResult { "JRZQ8A2D" , nil , fmt . Errorf ( "处理器panic: %v" , r ) }
}
} ( )
jrzq8a2dParams := map [ string ] interface { } {
"name" : params . Name ,
"id_card" : params . IDCard ,
"mobile_no" : params . MobileNo ,
"authorized" : params . Authorized ,
}
paramsBytes , err := json . Marshal ( jrzq8a2dParams )
if err != nil {
logger . Warn ( "序列化JRZQ8A2D参数失败" , zap . Error ( err ) )
results <- processorResult { "JRZQ8A2D" , nil , err }
return
}
data , err := callProcessor ( ctx , "JRZQ8A2D" , paramsBytes , deps )
results <- processorResult { "JRZQ8A2D" , data , err }
} ( )
// 调用FLXGDEA9 - 需要: name, id_card, authorized
go func ( ) {
defer func ( ) {
if r := recover ( ) ; r != nil {
logger . Error ( "调用FLXGDEA9处理器时发生panic" ,
zap . Any ( "panic" , r ) ,
)
results <- processorResult { "FLXGDEA9" , nil , fmt . Errorf ( "处理器panic: %v" , r ) }
}
} ( )
flxgParams := map [ string ] interface { } {
"name" : params . Name ,
"id_card" : params . IDCard ,
"authorized" : params . Authorized ,
}
paramsBytes , err := json . Marshal ( flxgParams )
if err != nil {
logger . Warn ( "序列化FLXGDEA9参数失败" , zap . Error ( err ) )
results <- processorResult { "FLXGDEA9" , nil , err }
return
}
data , err := callProcessor ( ctx , "FLXGDEA9" , paramsBytes , deps )
results <- processorResult { "FLXGDEA9" , data , err }
} ( )
// 调用JRZQ1D09 - 需要: name, id_card, mobile_no, authorized
go func ( ) {
defer func ( ) {
if r := recover ( ) ; r != nil {
logger . Error ( "调用JRZQ1D09处理器时发生panic" ,
zap . Any ( "panic" , r ) ,
)
results <- processorResult { "JRZQ1D09" , nil , fmt . Errorf ( "处理器panic: %v" , r ) }
}
} ( )
jrzq1d09Params := map [ string ] interface { } {
"name" : params . Name ,
"id_card" : params . IDCard ,
"mobile_no" : params . MobileNo ,
"authorized" : params . Authorized ,
}
paramsBytes , err := json . Marshal ( jrzq1d09Params )
if err != nil {
logger . Warn ( "序列化JRZQ1D09参数失败" , zap . Error ( err ) )
results <- processorResult { "JRZQ1D09" , nil , err }
return
}
data , err := callProcessor ( ctx , "JRZQ1D09" , paramsBytes , deps )
results <- processorResult { "JRZQ1D09" , data , err }
} ( )
// 调用JRZQ8B3C - 需要: name, id_card, mobile_no (不需要authorized)
go func ( ) {
defer func ( ) {
if r := recover ( ) ; r != nil {
logger . Error ( "调用JRZQ8B3C处理器时发生panic" ,
zap . Any ( "panic" , r ) ,
)
results <- processorResult { "JRZQ8B3C" , nil , fmt . Errorf ( "处理器panic: %v" , r ) }
}
} ( )
jrzq8b3cParams := map [ string ] interface { } {
"name" : params . Name ,
"id_card" : params . IDCard ,
"mobile_no" : params . MobileNo ,
}
paramsBytes , err := json . Marshal ( jrzq8b3cParams )
if err != nil {
logger . Warn ( "序列化JRZQ8B3C参数失败" , zap . Error ( err ) )
results <- processorResult { "JRZQ8B3C" , nil , err }
return
}
data , err := callProcessor ( ctx , "JRZQ8B3C" , paramsBytes , deps )
results <- processorResult { "JRZQ8B3C" , data , err }
} ( )
// 收集结果,即使所有处理器都失败也继续
successCount := 0
for i := 0 ; i < 5 ; i ++ {
result := <- results
if result . err != nil {
// 记录错误但不中断流程,允许部分数据缺失
logger . Warn ( "调用处理器失败,将使用默认值" ,
zap . String ( "api_code" , result . apiCode ) ,
zap . Error ( result . err ) ,
)
apiData [ result . apiCode ] = nil
} else {
apiData [ result . apiCode ] = result . data
successCount ++
}
}
logger . Info ( "子处理器调用完成" ,
zap . Int ( "total" , 5 ) ,
zap . Int ( "success" , successCount ) ,
zap . Int ( "failed" , 5 - successCount ) ,
)
return apiData
}
// callProcessor 调用指定的处理器
func callProcessor ( ctx context . Context , apiCode string , params [ ] byte , deps * processors . ProcessorDependencies ) ( interface { } , error ) {
// 通过CombService获取处理器
if combSvc , ok := deps . CombService . ( interface {
GetProcessor ( apiCode string ) ( processors . ProcessorFunc , bool )
} ) ; ok {
processor , exists := combSvc . GetProcessor ( apiCode )
if ! exists {
return nil , fmt . Errorf ( "未找到处理器: %s" , apiCode )
}
respBytes , err := processor ( ctx , params , deps )
if err != nil {
return nil , err
}
var data interface { }
if err := json . Unmarshal ( respBytes , & data ) ; err != nil {
return nil , fmt . Errorf ( "解析响应失败: %w" , err )
}
return data , nil
}
// 如果无法通过CombService获取, 返回错误
return nil , fmt . Errorf ( "无法获取处理器: %s, CombService不支持GetProcessor方法" , apiCode )
}
// formatDataForPDF 格式化数据为PDF生成服务需要的格式
// 为所有子处理器提供数据, 即使失败也提供默认值, 确保PDF生成服务能收到完整结构
func formatDataForPDF ( apiData map [ string ] interface { } , params dto . PDFG01GZReq , logger * zap . Logger ) [ ] map [ string ] interface { } {
result := make ( [ ] map [ string ] interface { } , 0 )
// 1. APPLICANT_BASIC_INFO - 申请人基本信息(始终存在)
result = append ( result , map [ string ] interface { } {
"apiID" : "APPLICANT_BASIC_INFO" ,
"data" : map [ string ] interface { } {
"name" : params . Name ,
"id_card" : params . IDCard ,
"mobile" : params . MobileNo ,
"query_time" : time . Now ( ) . Format ( "2006-01-02 15:04:05" ) ,
"report_number" : generateReportNumber ( ) ,
"generate_time" : time . Now ( ) . Format ( "2006-01-02 15:04:05" ) ,
} ,
} )
// 2. IVYZ5A9O - 自然人综合风险智能评估模型
if data , ok := apiData [ "IVYZ5A9O" ] ; ok && data != nil {
result = append ( result , map [ string ] interface { } {
"apiID" : "IVYZ5A9O" ,
"data" : data ,
} )
} else {
// 子处理器失败或无数据时,返回空对象 {}
logger . Debug ( "IVYZ5A9O数据缺失, 使用空对象" )
result = append ( result , map [ string ] interface { } {
"apiID" : "IVYZ5A9O" ,
"data" : map [ string ] interface { } { } ,
} )
}
// 3. JRZQ8A2D - 特殊名单验证B
if data , ok := apiData [ "JRZQ8A2D" ] ; ok && data != nil {
result = append ( result , map [ string ] interface { } {
"apiID" : "JRZQ8A2D" ,
"data" : data ,
} )
} else {
logger . Debug ( "JRZQ8A2D数据缺失, 使用空对象" )
result = append ( result , map [ string ] interface { } {
"apiID" : "JRZQ8A2D" ,
"data" : map [ string ] interface { } { } ,
} )
}
// 4. FLXGDEA9 - 公安不良人员名单
if data , ok := apiData [ "FLXGDEA9" ] ; ok && data != nil {
result = append ( result , map [ string ] interface { } {
"apiID" : "FLXGDEA9" ,
"data" : data ,
} )
} else {
logger . Debug ( "FLXGDEA9数据缺失, 使用空对象" )
result = append ( result , map [ string ] interface { } {
"apiID" : "FLXGDEA9" ,
"data" : map [ string ] interface { } { } ,
} )
}
// 5. JRZQ1D09 - 3C租赁申请意向
if data , ok := apiData [ "JRZQ1D09" ] ; ok && data != nil {
result = append ( result , map [ string ] interface { } {
"apiID" : "JRZQ1D09" ,
"data" : data ,
} )
} else {
logger . Debug ( "JRZQ1D09数据缺失, 使用空对象" )
result = append ( result , map [ string ] interface { } {
"apiID" : "JRZQ1D09" ,
"data" : map [ string ] interface { } { } ,
} )
}
// 6. JRZQ8B3C - 个人消费能力等级
if data , ok := apiData [ "JRZQ8B3C" ] ; ok && data != nil {
result = append ( result , map [ string ] interface { } {
"apiID" : "JRZQ8B3C" ,
"data" : data ,
} )
} else {
logger . Debug ( "JRZQ8B3C数据缺失, 使用空对象" )
result = append ( result , map [ string ] interface { } {
"apiID" : "JRZQ8B3C" ,
"data" : map [ string ] interface { } { } ,
} )
}
return result
}
// generateReportNumber 生成报告编号
func generateReportNumber ( ) string {
return fmt . Sprintf ( "RPT%s" , time . Now ( ) . Format ( "20060102150405" ) )
}
// generateDownloadURL 生成下载链接
func generateDownloadURL ( name , idCard string ) string {
// 这里应该生成实际的下载URL
// 暂时返回一个占位符,实际应该根据服务器配置生成
return fmt . Sprintf ( "/api/v1/pdfg/download?name=%s&id_card=%s" , name , idCard )
}