This commit is contained in:
2026-01-27 16:26:48 +08:00
parent 3ef7b7d1fb
commit f8806eb71c
19 changed files with 1260 additions and 358 deletions

View File

@@ -338,6 +338,43 @@ func (h *CertificationHandler) ListCertifications(c *gin.Context) {
h.response.Success(c, result, "获取认证列表成功")
}
// AdminCompleteCertificationWithoutContract 管理员代用户完成认证(暂不关联合同)
// @Summary 管理员代用户完成认证(暂不关联合同)
// @Description 后台补充企业信息并直接完成认证,暂时不要求上传合同
// @Tags 认证管理
// @Accept json
// @Produce json
// @Security Bearer
// @Param request body commands.AdminCompleteCertificationCommand true "管理员代用户完成认证请求"
// @Success 200 {object} responses.CertificationResponse "代用户完成认证成功"
// @Failure 400 {object} map[string]interface{} "请求参数错误"
// @Failure 401 {object} map[string]interface{} "未认证"
// @Failure 403 {object} map[string]interface{} "权限不足"
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
// @Router /api/v1/certifications/admin/complete-without-contract [post]
func (h *CertificationHandler) AdminCompleteCertificationWithoutContract(c *gin.Context) {
adminID := h.getCurrentUserID(c)
if adminID == "" {
h.response.Unauthorized(c, "用户未登录")
return
}
var cmd commands.AdminCompleteCertificationCommand
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
return
}
cmd.AdminID = adminID
result, err := h.appService.AdminCompleteCertificationWithoutContract(c.Request.Context(), &cmd)
if err != nil {
h.logger.Error("管理员代用户完成认证失败", zap.Error(err), zap.String("admin_id", adminID), zap.String("user_id", cmd.UserID))
h.response.BadRequest(c, err.Error())
return
}
h.response.Success(c, result, "代用户完成认证成功")
}
// ================ 回调处理 ================
// HandleEsignCallback 处理e签宝回调

View File

@@ -0,0 +1,93 @@
package handlers
import (
"fmt"
"net/http"
"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?name=xxx&id_card=xxx
func (h *PDFGHandler) DownloadPDF(c *gin.Context) {
name := c.Query("name")
idCard := c.Query("id_card")
if name == "" || idCard == "" {
h.responseBuilder.BadRequest(c, "姓名和身份证号不能为空")
return
}
// 从缓存获取PDF
pdfBytes, hit, createdAt, err := h.cacheManager.Get(name, idCard)
if err != nil {
h.logger.Error("获取PDF缓存失败",
zap.String("name", name),
zap.String("id_card", idCard),
zap.Error(err),
)
h.responseBuilder.InternalError(c, "获取PDF文件失败")
return
}
if !hit {
h.logger.Warn("PDF文件不存在或已过期",
zap.String("name", name),
zap.String("id_card", idCard),
)
h.responseBuilder.NotFound(c, "PDF文件不存在或已过期请重新生成")
return
}
// 检查是否过期从文件生成时间开始算24小时
expiresAt := createdAt.Add(24 * time.Hour)
if time.Now().After(expiresAt) {
h.logger.Warn("PDF文件已过期",
zap.String("name", name),
zap.String("id_card", idCard),
zap.Time("expires_at", expiresAt),
)
h.responseBuilder.NotFound(c, "PDF文件已过期请重新生成")
return
}
// 设置响应头
c.Header("Content-Type", "application/pdf")
c.Header("Content-Disposition", `attachment; filename="大数据租赁风险报告.pdf"`)
c.Header("Content-Length", fmt.Sprintf("%d", len(pdfBytes)))
// 发送PDF文件
c.Data(http.StatusOK, "application/pdf", pdfBytes)
h.logger.Info("PDF文件下载成功",
zap.String("name", name),
zap.String("id_card", idCard),
zap.Int("file_size", len(pdfBytes)),
)
}

View File

@@ -826,7 +826,7 @@ func (h *ProductHandler) DownloadProductDocumentation(c *gin.Context) {
if h.pdfCacheManager != nil {
var cacheErr error
pdfBytes, cacheHit, cacheErr = h.pdfCacheManager.Get(productID, docVersion)
pdfBytes, cacheHit, cacheErr = h.pdfCacheManager.GetByProduct(productID, docVersion)
if cacheErr != nil {
h.logger.Warn("从缓存获取PDF失败将重新生成",
zap.String("product_id", productID),
@@ -972,7 +972,7 @@ func (h *ProductHandler) DownloadProductDocumentation(c *gin.Context) {
// 保存到缓存(异步,不阻塞响应)
if h.pdfCacheManager != nil {
go func() {
if err := h.pdfCacheManager.Set(productID, docVersion, pdfBytes); err != nil {
if err := h.pdfCacheManager.SetByProduct(productID, docVersion, pdfBytes); err != nil {
h.logger.Warn("保存PDF到缓存失败",
zap.String("product_id", productID),
zap.String("version", docVersion),

View File

@@ -66,6 +66,9 @@ func (r *CertificationRoutes) Register(router *http.GinRouter) {
// 前端确认是否完成签署
authGroup.POST("/confirm-sign", r.handler.ConfirmSign)
// 管理员代用户完成认证(暂不关联合同)
authGroup.POST("/admin/complete-without-contract", r.handler.AdminCompleteCertificationWithoutContract)
}
// 回调路由(不需要认证,但需要验证签名)

View File

@@ -0,0 +1,39 @@
package routes
import (
"go.uber.org/zap"
sharedhttp "tyapi-server/internal/shared/http"
"tyapi-server/internal/infrastructure/http/handlers"
)
// PDFGRoutes PDFG路由
type PDFGRoutes struct {
pdfgHandler *handlers.PDFGHandler
logger *zap.Logger
}
// NewPDFGRoutes 创建PDFG路由
func NewPDFGRoutes(
pdfgHandler *handlers.PDFGHandler,
logger *zap.Logger,
) *PDFGRoutes {
return &PDFGRoutes{
pdfgHandler: pdfgHandler,
logger: logger,
}
}
// Register 注册相关路由
func (r *PDFGRoutes) Register(router *sharedhttp.GinRouter) {
engine := router.GetEngine()
apiGroup := engine.Group("/api/v1")
{
// PDF下载接口 - 不需要认证(因为下载链接已经包含了验证信息)
apiGroup.GET("/pdfg/download", r.pdfgHandler.DownloadPDF)
}
r.logger.Info("PDFG路由注册完成")
}