Files
tyapi-server/internal/shared/pdf/html_pdf_generator.go
2026-03-11 15:27:32 +08:00

89 lines
2.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package pdf
import (
"context"
"fmt"
"time"
"github.com/chromedp/cdproto/page"
"github.com/chromedp/chromedp"
"go.uber.org/zap"
)
// HTMLPDFGenerator 使用 headless Chrome 将 HTML 页面渲染为 PDF
type HTMLPDFGenerator struct {
logger *zap.Logger
}
// NewHTMLPDFGenerator 创建 HTMLPDFGenerator
func NewHTMLPDFGenerator(logger *zap.Logger) *HTMLPDFGenerator {
if logger == nil {
logger = zap.NewNop()
}
return &HTMLPDFGenerator{
logger: logger,
}
}
// GenerateFromURL 使用 headless Chrome 打开指定 URL并导出为 PDF 字节流
// 这里固定使用 A4 纵向纸张,开启背景打印
func (g *HTMLPDFGenerator) GenerateFromURL(ctx context.Context, url string) ([]byte, error) {
if ctx == nil {
ctx = context.Background()
}
// 整个生成过程增加超时时间,避免长时间卡死
timeoutCtx, cancel := context.WithTimeout(ctx, 60*time.Second)
defer cancel()
// 创建 Chrome 上下文(使用系统默认的 headless Chrome/Chromium
chromeCtx, cancelChrome := chromedp.NewContext(timeoutCtx)
defer cancelChrome()
var pdfBuf []byte
tasks := chromedp.Tasks{
chromedp.Navigate(url),
// 等待页面主体和报告容器就绪,确保数据渲染完成
chromedp.WaitReady("body", chromedp.ByQuery),
chromedp.WaitVisible(".page", chromedp.ByQuery),
chromedp.ActionFunc(func(ctx context.Context) error {
g.logger.Info("开始通过 headless Chrome 生成企业报告 PDF", zap.String("url", url))
var (
buf []byte
err error
)
buf, _, err = page.PrintToPDF().
WithPrintBackground(true).
WithPaperWidth(8.27). // A4 宽度(英寸 -> 约 210mm
WithPaperHeight(11.69). // A4 高度(英寸 -> 约 297mm
WithMarginTop(0.4).
WithMarginBottom(0.4).
WithMarginLeft(0.4).
WithMarginRight(0.4).
Do(ctx)
if err == nil {
pdfBuf = buf
}
return err
}),
}
if err := chromedp.Run(chromeCtx, tasks); err != nil {
g.logger.Error("使用 headless Chrome 生成 HTML 报告 PDF 失败", zap.String("url", url), zap.Error(err))
return nil, err
}
if len(pdfBuf) == 0 {
return nil, fmt.Errorf("生成的 PDF 内容为空")
}
g.logger.Info("通过 headless Chrome 生成企业报告 PDF 成功",
zap.String("url", url),
zap.Int("pdf_size", len(pdfBuf)),
)
return pdfBuf, nil
}