175 lines
5.9 KiB
Go
175 lines
5.9 KiB
Go
package service
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"github.com/jung-kurt/gofpdf"
|
||
"io"
|
||
"log"
|
||
"net/http"
|
||
"os"
|
||
"qnc-server/utils"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
const API_KEY = "aMsrBNGUJxgcgqdm3SEdcumm"
|
||
const SECRET_KEY = "sWlv2h2AWA3aAt5bjXCkE6WeA5AzpAAD"
|
||
|
||
type Feature struct {
|
||
}
|
||
|
||
// Service 函数:接受 base64 编码的图像,返回 OCR 识别结果
|
||
func (f *Feature) OCRService(imageBase64 string) (string, error) {
|
||
// 获取 Access Token
|
||
accessToken := f.GetAccessToken()
|
||
if accessToken == "" {
|
||
return "", fmt.Errorf("获取 Access Token 失败")
|
||
}
|
||
|
||
// 设置请求 URL
|
||
url := "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic?access_token=" + accessToken
|
||
|
||
// 设置请求体,包含图片的 base64 编码
|
||
payload := strings.NewReader(fmt.Sprintf("image=%s&detect_direction=false¶graph=false&probability=false&multidirectional_recognize=false", imageBase64))
|
||
|
||
// 创建 HTTP 客户端和请求
|
||
client := &http.Client{}
|
||
req, err := http.NewRequest("POST", url, payload)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
// 设置请求头
|
||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||
req.Header.Add("Accept", "application/json")
|
||
|
||
// 发送请求并获取响应
|
||
res, err := client.Do(req)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
defer res.Body.Close()
|
||
|
||
// 读取响应体
|
||
body, err := io.ReadAll(res.Body)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
return string(body), nil
|
||
}
|
||
|
||
/**
|
||
* 使用 AK,SK 生成鉴权签名(Access Token)
|
||
* @return string 鉴权签名信息(Access Token)
|
||
*/
|
||
func (f *Feature) GetAccessToken() string {
|
||
url := "https://aip.baidubce.com/oauth/2.0/token"
|
||
postData := fmt.Sprintf("grant_type=client_credentials&client_id=%s&client_secret=%s", API_KEY, SECRET_KEY)
|
||
resp, err := http.Post(url, "application/x-www-form-urlencoded", strings.NewReader(postData))
|
||
if err != nil {
|
||
fmt.Println(err)
|
||
return ""
|
||
}
|
||
defer resp.Body.Close()
|
||
body, err := io.ReadAll(resp.Body)
|
||
if err != nil {
|
||
fmt.Println(err)
|
||
return ""
|
||
}
|
||
accessTokenObj := map[string]interface{}{}
|
||
_ = json.Unmarshal(body, &accessTokenObj)
|
||
return accessTokenObj["access_token"].(string)
|
||
}
|
||
|
||
func (f *Feature) GenerateSignPDF(name string, id uint, signatureBase64 string) (fileName string, err error) {
|
||
// 创建 PDF 实例,A4 纸张大小
|
||
pdf := gofpdf.New("P", "mm", "A4", "")
|
||
|
||
fontPath := "simhei.ttf"
|
||
|
||
// 添加中文字体支持
|
||
pdf.AddUTF8Font("SimHei", "", fontPath) // 使用 simhei.ttf 字体
|
||
pdf.SetFont("SimHei", "", 12)
|
||
|
||
// 添加一页
|
||
pdf.AddPage()
|
||
|
||
// 插入标题,居中对齐
|
||
pdf.SetFont("SimHei", "", 20)
|
||
pdf.CellFormat(0, 10, "声明", "", 1, "C", false, 0, "") // C 表示居中对齐
|
||
pdf.Ln(12)
|
||
|
||
// 插入副标题
|
||
pdf.SetFont("SimHei", "", 14)
|
||
pdf.Cell(40, 10, "全能查声明:")
|
||
pdf.Ln(10)
|
||
|
||
// 插入正文内容,添加两字符的缩进(全角空格)
|
||
pdf.SetFont("SimHei", "", 12)
|
||
indent := " " // 两字符的缩进,使用全角空格
|
||
pdf.MultiCell(0, 10, indent+"1、本产品所有数据均来自第三方。可能部分数据未公开,数据更新延迟或信息受到限制,不一定全部返回,因此我们不做准确性、真实性、完整性承诺。不同数据格式及记录详细程度会存在差异,此为行业正常现象。本报告仅供参考,不能作为诉讼证据、决策性依据等材料,请结合实际情况,做出更准确的决策。", "", "", false)
|
||
pdf.Ln(3)
|
||
|
||
pdf.MultiCell(0, 10, indent+"2、本产品仅供用户本人查询或被授权查询。除非用户取得合法授权,用户不得利用本产品查询他人信息。用户因未获得合法授权而擅自查询他人信息所产生的任何后果,由用户自行承担责任。", "", "", false)
|
||
pdf.Ln(3)
|
||
|
||
// 插入承诺声明
|
||
pdf.SetFont("SimHei", "", 14)
|
||
pdf.Cell(40, 10, "本人承诺:")
|
||
pdf.Ln(10)
|
||
|
||
text := fmt.Sprintf("本人%s在此声明,我即将通过此小程序查询的婚姻状态信息仅涉及本人。本人确认不将所得信息用作任何诉讼证据,不会将所获取的信息用于任何非法用途,包括但不限于欺诈、胁迫、侵犯隐私或其他违法行为,不将所得信息转卖、传播给他人。本人承诺对查询结果所引发的任何后果承担全部责任。", name)
|
||
|
||
// 插入承诺内容,添加两字符的缩进
|
||
pdf.SetFont("SimHei", "", 12)
|
||
pdf.MultiCell(0, 10, indent+text, "", "", false)
|
||
pdf.Ln(10)
|
||
|
||
// 定位签名和日期到右下角
|
||
pageWidth, pageHeight := pdf.GetPageSize()
|
||
rightMargin := 20.0
|
||
bottomMargin := 20.0
|
||
|
||
// 设置签名部分的 XY 坐标,靠右下角
|
||
pdf.SetXY(pageWidth-rightMargin-40, pageHeight-bottomMargin-40) // 签名部分坐标
|
||
pdf.SetFont("SimHei", "", 12)
|
||
pdf.Cell(40, 10, "签名:")
|
||
|
||
// 解码 Base64 签名图片并保存为临时文件
|
||
var tempFileName = fmt.Sprintf("signature-%d.png", id)
|
||
signaturePath, err := utils.DecodeBase64ToPNG(signatureBase64, tempFileName)
|
||
if err != nil {
|
||
log.Printf("【签名图片生成】解码 Base64 签名图片并保存为临时文件失败:%v", err)
|
||
return "", err
|
||
}
|
||
|
||
// 在 PDF 中嵌入签名图片
|
||
pdf.ImageOptions(signaturePath, pageWidth-rightMargin-28, pageHeight-bottomMargin-40, 40, 10, false, gofpdf.ImageOptions{ImageType: "PNG"}, 0, "")
|
||
|
||
// 插入当前日期,显示在签名下方
|
||
currentDate := time.Now().Format("2006-01-02")
|
||
currentDateCN := time.Now().Format("2006年01月02日")
|
||
pdf.SetXY(pageWidth-rightMargin-40, pageHeight-bottomMargin-20)
|
||
pdf.Cell(40, 10, "日期:"+currentDateCN)
|
||
|
||
// 根据日期和 ID 动态生成文件名
|
||
outputDir := "signature"
|
||
os.MkdirAll(outputDir, os.ModePerm) // 如果不存在则创建目录
|
||
fileName = fmt.Sprintf("%s/%s_%d.pdf", outputDir, currentDate, id)
|
||
|
||
// 保存 PDF 文件
|
||
err = pdf.OutputFileAndClose(fileName)
|
||
if err != nil {
|
||
log.Printf("【签名图片生成】保存 PDF 文件失败:%v", err)
|
||
return "", err
|
||
}
|
||
// 删除临时签名图片文件
|
||
err = os.Remove(signaturePath)
|
||
if err != nil {
|
||
log.Printf("【签名图片生成】删除临时文件失败:%v", err)
|
||
}
|
||
return fileName, nil
|
||
}
|