package handlers import ( "fmt" "net/http" "strings" "time" "github.com/gin-gonic/gin" "go.uber.org/zap" "tyapi-server/internal/shared/interfaces" "tyapi-server/internal/shared/pdf" ) // PDFGHandler PDFG处理器 type PDFGHandler struct { cacheManager *pdf.PDFCacheManager responseBuilder interfaces.ResponseBuilder logger *zap.Logger } // NewPDFGHandler 创建PDFG处理器 func NewPDFGHandler( cacheManager *pdf.PDFCacheManager, responseBuilder interfaces.ResponseBuilder, logger *zap.Logger, ) *PDFGHandler { return &PDFGHandler{ cacheManager: cacheManager, responseBuilder: responseBuilder, logger: logger, } } // DownloadPDF 下载PDF文件 // GET /api/v1/pdfg/download?id=报告ID func (h *PDFGHandler) DownloadPDF(c *gin.Context) { reportID := c.Query("id") if reportID == "" { h.responseBuilder.BadRequest(c, "报告ID不能为空") return } // 通过报告ID获取PDF文件 pdfBytes, hit, createdAt, err := h.cacheManager.GetByReportID(reportID) if err != nil { h.logger.Error("获取PDF缓存失败", zap.String("report_id", reportID), zap.Error(err), ) h.responseBuilder.InternalError(c, "获取PDF文件失败") return } if !hit { h.logger.Warn("PDF文件不存在或已过期", zap.String("report_id", reportID), ) h.responseBuilder.NotFound(c, "PDF文件不存在或已过期,请重新生成") return } // 检查是否过期(从文件生成时间开始算24小时) expiresAt := createdAt.Add(24 * time.Hour) if time.Now().After(expiresAt) { h.logger.Warn("PDF文件已过期", zap.String("report_id", reportID), zap.Time("expires_at", expiresAt), ) h.responseBuilder.NotFound(c, "PDF文件已过期,请重新生成") return } // 设置响应头 c.Header("Content-Type", "application/pdf") // 使用报告ID前缀作为下载文件名的一部分 filename := "大数据租赁风险报告.pdf" if idx := strings.LastIndex(reportID, "-"); idx > 0 { // 使用前缀(报告编号部分)作为文件名的一部分 prefix := reportID[:idx] filename = fmt.Sprintf("大数据租赁风险报告_%s.pdf", prefix) } c.Header("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, filename)) c.Header("Content-Length", fmt.Sprintf("%d", len(pdfBytes))) // 发送PDF文件 c.Data(http.StatusOK, "application/pdf", pdfBytes) h.logger.Info("PDF文件下载成功", zap.String("report_id", reportID), zap.Int("file_size", len(pdfBytes)), ) }