2026-01-27 16:26:48 +08:00
|
|
|
|
package pdfgen
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"bytes"
|
|
|
|
|
|
"context"
|
|
|
|
|
|
"encoding/json"
|
|
|
|
|
|
"fmt"
|
|
|
|
|
|
"io"
|
|
|
|
|
|
"net/http"
|
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
|
|
"tyapi-server/internal/config"
|
|
|
|
|
|
|
|
|
|
|
|
"go.uber.org/zap"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// PDFGenService PDF生成服务客户端
|
|
|
|
|
|
type PDFGenService struct {
|
|
|
|
|
|
baseURL string
|
|
|
|
|
|
apiPath string
|
|
|
|
|
|
logger *zap.Logger
|
|
|
|
|
|
client *http.Client
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// NewPDFGenService 创建PDF生成服务客户端
|
|
|
|
|
|
func NewPDFGenService(cfg *config.Config, logger *zap.Logger) *PDFGenService {
|
|
|
|
|
|
// 根据环境选择服务地址
|
|
|
|
|
|
var baseURL string
|
|
|
|
|
|
if cfg.App.IsProduction() {
|
|
|
|
|
|
baseURL = cfg.PDFGen.ProductionURL
|
|
|
|
|
|
} else {
|
|
|
|
|
|
baseURL = cfg.PDFGen.DevelopmentURL
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果配置为空,使用默认值
|
|
|
|
|
|
if baseURL == "" {
|
|
|
|
|
|
if cfg.App.IsProduction() {
|
|
|
|
|
|
baseURL = "http://localhost:15990"
|
|
|
|
|
|
} else {
|
|
|
|
|
|
baseURL = "http://1.117.67.95:15990"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取API路径,如果为空使用默认值
|
|
|
|
|
|
apiPath := cfg.PDFGen.APIPath
|
|
|
|
|
|
if apiPath == "" {
|
|
|
|
|
|
apiPath = "/api/v1/generate/guangzhou"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取超时时间,如果为0使用默认值
|
|
|
|
|
|
timeout := cfg.PDFGen.Timeout
|
|
|
|
|
|
if timeout == 0 {
|
|
|
|
|
|
timeout = 120 * time.Second
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
logger.Info("PDF生成服务已初始化",
|
|
|
|
|
|
zap.String("base_url", baseURL),
|
|
|
|
|
|
zap.String("api_path", apiPath),
|
|
|
|
|
|
zap.Duration("timeout", timeout),
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
return &PDFGenService{
|
|
|
|
|
|
baseURL: baseURL,
|
|
|
|
|
|
apiPath: apiPath,
|
|
|
|
|
|
logger: logger,
|
|
|
|
|
|
client: &http.Client{
|
|
|
|
|
|
Timeout: timeout,
|
2026-01-27 17:33:09 +08:00
|
|
|
|
Transport: &http.Transport{
|
|
|
|
|
|
Proxy: nil, // 不使用任何代理
|
|
|
|
|
|
},
|
2026-01-27 16:26:48 +08:00
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GeneratePDFRequest PDF生成请求
|
|
|
|
|
|
type GeneratePDFRequest struct {
|
|
|
|
|
|
Data []map[string]interface{} `json:"data"`
|
|
|
|
|
|
ReportNumber string `json:"report_number,omitempty"`
|
|
|
|
|
|
GenerateTime string `json:"generate_time,omitempty"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GeneratePDFResponse PDF生成响应
|
|
|
|
|
|
type GeneratePDFResponse struct {
|
|
|
|
|
|
PDFBytes []byte
|
|
|
|
|
|
FileName string
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GenerateGuangzhouPDF 生成广州大数据租赁风险PDF报告
|
|
|
|
|
|
func (s *PDFGenService) GenerateGuangzhouPDF(ctx context.Context, req *GeneratePDFRequest) (*GeneratePDFResponse, error) {
|
|
|
|
|
|
// 构建请求体
|
|
|
|
|
|
reqBody, err := json.Marshal(req)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, fmt.Errorf("序列化请求失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 构建请求URL
|
|
|
|
|
|
url := fmt.Sprintf("%s%s", s.baseURL, s.apiPath)
|
|
|
|
|
|
|
|
|
|
|
|
// 创建HTTP请求
|
|
|
|
|
|
httpReq, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(reqBody))
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, fmt.Errorf("创建请求失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 设置请求头
|
|
|
|
|
|
httpReq.Header.Set("Content-Type", "application/json")
|
|
|
|
|
|
|
2026-01-27 19:00:09 +08:00
|
|
|
|
start := time.Now()
|
|
|
|
|
|
|
2026-01-27 16:26:48 +08:00
|
|
|
|
// 发送请求
|
|
|
|
|
|
s.logger.Info("开始调用PDF生成服务",
|
|
|
|
|
|
zap.String("url", url),
|
|
|
|
|
|
zap.Int("data_count", len(req.Data)),
|
2026-01-29 15:03:38 +08:00
|
|
|
|
zap.ByteString("reqBody", reqBody),
|
2026-01-27 16:26:48 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
resp, err := s.client.Do(httpReq)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
s.logger.Error("调用PDF生成服务失败",
|
|
|
|
|
|
zap.String("url", url),
|
2026-01-27 19:00:09 +08:00
|
|
|
|
zap.Duration("duration", time.Since(start)),
|
2026-01-27 16:26:48 +08:00
|
|
|
|
zap.Error(err),
|
|
|
|
|
|
)
|
|
|
|
|
|
return nil, fmt.Errorf("调用PDF生成服务失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
|
|
// 检查HTTP状态码
|
|
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
|
|
// 尝试读取错误信息
|
|
|
|
|
|
errorBody, _ := io.ReadAll(resp.Body)
|
|
|
|
|
|
s.logger.Error("PDF生成服务返回错误",
|
2026-01-27 19:00:09 +08:00
|
|
|
|
zap.String("url", url),
|
2026-01-27 16:26:48 +08:00
|
|
|
|
zap.Int("status_code", resp.StatusCode),
|
2026-01-27 19:00:09 +08:00
|
|
|
|
zap.Duration("duration", time.Since(start)),
|
2026-01-27 16:26:48 +08:00
|
|
|
|
zap.String("error_body", string(errorBody)),
|
|
|
|
|
|
)
|
|
|
|
|
|
return nil, fmt.Errorf("PDF生成失败,状态码: %d, 错误: %s", resp.StatusCode, string(errorBody))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 读取PDF文件
|
|
|
|
|
|
pdfBytes, err := io.ReadAll(resp.Body)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, fmt.Errorf("读取PDF文件失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 生成文件名
|
|
|
|
|
|
fileName := "大数据租赁风险报告.pdf"
|
|
|
|
|
|
if req.ReportNumber != "" {
|
|
|
|
|
|
fileName = fmt.Sprintf("%s.pdf", req.ReportNumber)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
s.logger.Info("PDF生成成功",
|
2026-01-27 19:00:09 +08:00
|
|
|
|
zap.String("url", url),
|
2026-01-27 16:26:48 +08:00
|
|
|
|
zap.String("file_name", fileName),
|
|
|
|
|
|
zap.Int("file_size", len(pdfBytes)),
|
2026-01-27 19:00:09 +08:00
|
|
|
|
zap.Duration("duration", time.Since(start)),
|
2026-01-27 16:26:48 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
return &GeneratePDFResponse{
|
|
|
|
|
|
PDFBytes: pdfBytes,
|
|
|
|
|
|
FileName: fileName,
|
|
|
|
|
|
}, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|