Files
tyapi-server/internal/shared/pdf/table_parser.go
2025-12-04 10:47:58 +08:00

199 lines
5.5 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"
"strings"
"tyapi-server/internal/domains/product/entities"
"github.com/jung-kurt/gofpdf/v2"
"go.uber.org/zap"
)
// TableBlock 表格块(用于向后兼容)
type TableBlock struct {
BeforeText string
TableData [][]string
AfterText string
}
// TableParser 表格解析器
// 从数据库读取数据并转换为表格格式
type TableParser struct {
logger *zap.Logger
fontManager *FontManager
databaseReader *DatabaseTableReader
databaseRenderer *DatabaseTableRenderer
}
// NewTableParser 创建表格解析器
func NewTableParser(logger *zap.Logger, fontManager *FontManager) *TableParser {
reader := NewDatabaseTableReader(logger)
renderer := NewDatabaseTableRenderer(logger, fontManager)
return &TableParser{
logger: logger,
fontManager: fontManager,
databaseReader: reader,
databaseRenderer: renderer,
}
}
// ParseAndRenderTable 从产品文档中解析并渲染表格(支持多个表格,带标题)
func (tp *TableParser) ParseAndRenderTable(ctx context.Context, pdf *gofpdf.Fpdf, doc *entities.ProductDocumentation, fieldType string) error {
// 从数据库读取表格数据(支持多个表格)
tableData, err := tp.databaseReader.ReadTableFromDocumentation(ctx, doc, fieldType)
if err != nil {
// 如果内容为空,不渲染,也不报错(静默跳过)
if strings.Contains(err.Error(), "内容为空") {
tp.logger.Debug("表格内容为空,跳过渲染", zap.String("field_type", fieldType))
return nil
}
return fmt.Errorf("读取表格数据失败: %w", err)
}
// 检查表格数据是否有效
if tableData == nil || len(tableData.Headers) == 0 {
tp.logger.Warn("表格数据无效,跳过渲染",
zap.String("field_type", fieldType),
zap.Bool("is_nil", tableData == nil))
return nil
}
// 渲染表格到PDF
if err := tp.databaseRenderer.RenderTable(pdf, tableData); err != nil {
// 错误已返回,不记录日志
return fmt.Errorf("渲染表格失败: %w", err)
}
return nil
}
// ParseAndRenderTablesWithTitles 从产品文档中解析并渲染多个表格(带标题)
func (tp *TableParser) ParseAndRenderTablesWithTitles(ctx context.Context, pdf *gofpdf.Fpdf, doc *entities.ProductDocumentation, fieldType string) error {
var content string
switch fieldType {
case "request_params":
content = doc.RequestParams
case "response_fields":
content = doc.ResponseFields
case "response_example":
content = doc.ResponseExample
case "error_codes":
content = doc.ErrorCodes
default:
return fmt.Errorf("未知的字段类型: %s", fieldType)
}
if strings.TrimSpace(content) == "" {
return nil
}
// 解析多个表格(带标题)
tablesWithTitles, err := tp.databaseReader.parseMarkdownTablesWithTitles(content)
if err != nil {
tp.logger.Warn("解析表格失败,回退到单个表格", zap.Error(err))
// 回退到单个表格渲染
return tp.ParseAndRenderTable(ctx, pdf, doc, fieldType)
}
if len(tablesWithTitles) == 0 {
return nil
}
// 分别渲染每个表格,并在表格前显示标题
_, lineHt := pdf.GetFontSize()
for i, twt := range tablesWithTitles {
if twt.Table == nil || len(twt.Table.Headers) == 0 {
continue
}
// 如果不是第一个表格,添加间距
if i > 0 {
pdf.Ln(5)
}
// 如果有标题,显示标题
if strings.TrimSpace(twt.Title) != "" {
pdf.SetTextColor(0, 0, 0)
tp.fontManager.SetFont(pdf, "B", 12)
_, lineHt = pdf.GetFontSize()
pdf.CellFormat(0, lineHt, twt.Title, "", 1, "L", false, 0, "")
pdf.Ln(2)
}
// 渲染表格
if err := tp.databaseRenderer.RenderTable(pdf, twt.Table); err != nil {
tp.logger.Warn("渲染表格失败", zap.Error(err), zap.String("title", twt.Title))
continue
}
}
return nil
}
// ParseTableData 仅解析表格数据,不渲染
func (tp *TableParser) ParseTableData(ctx context.Context, doc *entities.ProductDocumentation, fieldType string) (*TableData, error) {
return tp.databaseReader.ReadTableFromDocumentation(ctx, doc, fieldType)
}
// ParseMarkdownTable 解析Markdown表格兼容方法
func (tp *TableParser) ParseMarkdownTable(text string) [][]string {
// 使用数据库读取器的markdown解析功能
tableData, err := tp.databaseReader.parseMarkdownTable(text)
if err != nil {
tp.logger.Warn("解析markdown表格失败", zap.Error(err))
return nil
}
// 转换为旧格式 [][]string
result := make([][]string, 0, len(tableData.Rows)+1)
result = append(result, tableData.Headers)
result = append(result, tableData.Rows...)
return result
}
// ExtractAllTables 提取所有表格块(兼容方法)
func (tp *TableParser) ExtractAllTables(content string) []TableBlock {
// 使用数据库读取器解析markdown表格
tableData, err := tp.databaseReader.parseMarkdownTable(content)
if err != nil {
return []TableBlock{}
}
// 转换为TableBlock格式
if len(tableData.Headers) > 0 {
rows := make([][]string, 0, len(tableData.Rows)+1)
rows = append(rows, tableData.Headers)
rows = append(rows, tableData.Rows...)
return []TableBlock{
{
BeforeText: "",
TableData: rows,
AfterText: "",
},
}
}
return []TableBlock{}
}
// IsValidTable 验证表格是否有效(兼容方法)
func (tp *TableParser) IsValidTable(tableData [][]string) bool {
if len(tableData) == 0 {
return false
}
if len(tableData[0]) == 0 {
return false
}
// 检查表头是否有有效内容
for _, cell := range tableData[0] {
if strings.TrimSpace(cell) != "" {
return true
}
}
return false
}