Files
hm-server-v2/app/main/api/internal/service/authorizationService.go

225 lines
9.9 KiB
Go
Raw Normal View History

2025-10-07 11:48:29 +08:00
package service
import (
"bytes"
"context"
"database/sql"
"fmt"
"hm-server/app/main/api/internal/config"
"hm-server/app/main/model"
"os"
"path/filepath"
"time"
"github.com/jung-kurt/gofpdf"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/logx"
)
type AuthorizationService struct {
config config.Config
authDocModel model.AuthorizationDocumentModel
fileStoragePath string
fileBaseURL string
}
// NewAuthorizationService 创建授权书服务实例
func NewAuthorizationService(c config.Config, authDocModel model.AuthorizationDocumentModel) *AuthorizationService {
return &AuthorizationService{
config: c,
authDocModel: authDocModel,
fileStoragePath: "data/authorization_docs", // 使用相对路径,兼容开发环境
fileBaseURL: c.Authorization.FileBaseURL, // 从配置文件读取
}
}
// GenerateAuthorizationDocument 生成授权书PDF
func (s *AuthorizationService) GenerateAuthorizationDocument(
ctx context.Context,
userID int64,
orderID int64,
queryID int64,
userInfo map[string]interface{},
) (*model.AuthorizationDocument, error) {
// 1. 生成PDF内容
pdfBytes, err := s.generatePDFContent(userInfo)
if err != nil {
return nil, errors.Wrapf(err, "生成PDF内容失败")
}
// 2. 创建文件存储目录
year := time.Now().Format("2006")
month := time.Now().Format("01")
dirPath := filepath.Join(s.fileStoragePath, year, month)
if err := os.MkdirAll(dirPath, 0755); err != nil {
return nil, errors.Wrapf(err, "创建存储目录失败: %s", dirPath)
}
// 3. 生成文件名和路径
fileName := fmt.Sprintf("auth_%d_%d_%s.pdf", userID, orderID, time.Now().Format("20060102_150405"))
filePath := filepath.Join(dirPath, fileName)
// 只存储相对路径,不包含域名
relativePath := fmt.Sprintf("%s/%s/%s", year, month, fileName)
// 4. 保存PDF文件
if err := os.WriteFile(filePath, pdfBytes, 0644); err != nil {
return nil, errors.Wrapf(err, "保存PDF文件失败: %s", filePath)
}
// 5. 保存到数据库
authDoc := &model.AuthorizationDocument{
UserId: userID,
OrderId: orderID,
QueryId: queryID,
FileName: fileName,
FilePath: filePath,
FileUrl: relativePath, // 只存储相对路径
FileSize: int64(len(pdfBytes)),
FileType: "pdf",
Status: "active",
ExpireTime: sql.NullTime{Valid: false}, // 永久保留,不设置过期时间
}
result, err := s.authDocModel.Insert(ctx, nil, authDoc)
if err != nil {
// 如果数据库保存失败,删除已创建的文件
os.Remove(filePath)
return nil, errors.Wrapf(err, "保存授权书记录失败")
}
authDoc.Id, _ = result.LastInsertId()
logx.Infof("授权书生成成功: userID=%d, orderID=%d, filePath=%s", userID, orderID, filePath)
return authDoc, nil
}
// GetFullFileURL 获取完整的文件访问URL
func (s *AuthorizationService) GetFullFileURL(relativePath string) string {
if relativePath == "" {
return ""
}
return fmt.Sprintf("%s/%s", s.fileBaseURL, relativePath)
}
// generatePDFContent 生成PDF内容
func (s *AuthorizationService) generatePDFContent(userInfo map[string]interface{}) ([]byte, error) {
// 创建PDF文档
pdf := gofpdf.New("P", "mm", "A4", "")
pdf.AddPage()
// 添加中文字体支持 - 参考imageService的路径处理方式
fontPaths := []string{
"static/SIMHEI.TTF", // 相对于工作目录的路径与imageService一致
"/app/static/SIMHEI.TTF", // Docker容器内的字体文件
"app/main/api/static/SIMHEI.TTF", // 开发环境备用路径
}
// 尝试添加字体
fontAdded := false
for _, fontPath := range fontPaths {
if _, err := os.Stat(fontPath); err == nil {
pdf.AddUTF8Font("ChineseFont", "", fontPath)
fontAdded = true
logx.Infof("成功加载字体: %s", fontPath)
break
} else {
logx.Debugf("字体文件不存在: %s, 错误: %v", fontPath, err)
}
}
// 如果没有找到字体文件,使用默认字体,并记录警告
if !fontAdded {
pdf.SetFont("Arial", "", 12)
logx.Errorf("未找到中文字体文件使用默认Arial字体可能无法正确显示中文")
} else {
// 设置默认字体
pdf.SetFont("ChineseFont", "", 12)
}
// 获取用户信息
name := getUserInfoString(userInfo, "name")
idCard := getUserInfoString(userInfo, "id_card")
// 生成当前日期
currentDate := time.Now().Format("2006年1月2日")
// 设置标题样式 - 大字体、居中
if fontAdded {
pdf.SetFont("ChineseFont", "", 20) // 使用20号字体
} else {
pdf.SetFont("Arial", "", 20)
}
pdf.CellFormat(0, 15, "授权书", "", 1, "C", false, 0, "")
// 添加空行
pdf.Ln(5)
// 设置正文样式 - 正常字体
if fontAdded {
pdf.SetFont("ChineseFont", "", 12)
} else {
pdf.SetFont("Arial", "", 12)
}
// 构建授权书内容(去掉标题部分)
2025-10-18 12:48:59 +08:00
content := fmt.Sprintf(`哈蜜瓜湖南互联网科技有限公司
2025-10-07 11:48:29 +08:00
本人%s拟向贵司申请大数据分析报告查询业务贵司需要了解本人相关状况用于查询大数据分析报告因此本人同意向贵司提供本人的姓名和手机号等个人信息并同意贵司向第三方包括但不限于西部数据交易有限公司传送上述信息第三方将使用上述信息核实信息真实情况查询信用记录并生成报告
授权内容如下
2025-10-18 12:48:59 +08:00
贵司向依法成立的第三方服务商包括但不限于海南省学宇思网络科技有限公司根据本人提交的信息进行核实并有权通过前述第三方服务机构查询使用本人的身份信息设备信息运营商信息等查询本人信息包括但不限于学历婚姻资产状况及对信息主体产生负面影响的不良信息出具相关报告
2025-10-07 11:48:29 +08:00
依法成立的第三方服务商查询或核实搜集保存处理共享使用含合法业务应用本人相关数据且不再另行告知本人但法律法规监管政策禁止的除外
本人授权有效期为自授权之日起 1个月本授权为不可撤销授权但法律法规另有规定的除外
用户声明与承诺
本人在授权签署前已通过实名认证及动态验证码验证或其他身份验证手段确认本授权行为为本人真实意思表示平台已履行身份验证义务
本人在此声明已充分理解上述授权条款含义知晓并自愿承担因授权数据使用可能带来的后果包括但不限于影响个人信用评分生活行为等本人确认授权范围内的相关信息由本人提供并真实有效
若用户冒名签署或提供虚假信息由用户自行承担全部法律责任平台不承担任何后果
特别提示
本产品所有数据均来自第三方可能部分数据未公开数据更新延迟或信息受到限制贵司不对数据的准确性真实性完整性做任何承诺用户需根据实际情况结合报告内容自行判断与决策
本产品仅供用户本人查询或被授权查询除非用户取得合法授权用户不得利用本产品查询他人信息用户因未获得合法授权而擅自查询他人信息所产生的任何后果由用户自行承担责任
本授权书涉及对本人敏感信息包括但不限于婚姻状态资产状况等的查询与使用本人已充分知晓相关信息的敏感性并明确同意贵司及其合作方依据授权范围使用相关信息
平台声明本授权书涉及的信息核实及查询结果由第三方服务商提供平台不对数据的准确性完整性实时性承担责任用户根据报告所作决策的风险由用户自行承担平台对此不承担法律责任
本授权书中涉及的数据查询和报告生成由依法成立的第三方服务商提供若因第三方行为导致数据错误或损失用户应向第三方主张权利平台不承担相关责任
附加说明
本人在授权的相关数据将依据法律法规及贵司内部数据管理规范妥善存储存储期限为法律要求的最短必要时间超过存储期限或在数据使用目的达成后贵司将对相关数据进行销毁或匿名化处理
本人有权随时撤回本授权书中的授权但撤回前的授权行为及其法律后果仍具有法律效力若需撤回授权本人可通过贵司官方渠道提交书面申请贵司将在收到申请后依法停止对本人数据的使用
2025-10-18 12:48:59 +08:00
你通过"天远数据"自愿支付相应费用用于购买哈蜜瓜湖南互联网科技有限公司的大数据报告产品如若对产品内容存在异议可通过邮箱admin@iieeii.com或APP"联系客服"按钮进行反馈贵司将在收到异议之日起20日内进行核查和处理并将结果答复
你向哈蜜瓜湖南互联网科技有限公司的支付方式为哈蜜瓜湖南互联网科技有限公司及其经官方授权的相关企业的支付宝账户
2025-10-07 11:48:29 +08:00
争议解决机制
2025-10-18 12:48:59 +08:00
若因本授权书引发争议双方应友好协商解决协商不成的双方同意将争议提交至授权书签署地有管辖权的人民法院解决
2025-10-07 11:48:29 +08:00
签署方式的法律效力声明
本授权书通过用户在线勾选电子签名或其他网络签署方式完成与手写签名具有同等法律效力平台已通过技术手段保存签署过程的完整记录作为用户真实意思表示的证据
本授权书于 %s 生效
授权人%s
身份证号%s
签署时间%s`, name, currentDate, name, idCard, currentDate)
// 将内容写入PDF
pdf.MultiCell(0, 6, content, "", "", false)
// 生成PDF字节数组
var buf bytes.Buffer
err := pdf.Output(&buf)
if err != nil {
return nil, errors.Wrapf(err, "生成PDF字节数组失败")
}
return buf.Bytes(), nil
}
// getUserInfoString 安全获取用户信息字符串
func getUserInfoString(userInfo map[string]interface{}, key string) string {
if value, exists := userInfo[key]; exists {
if str, ok := value.(string); ok {
return str
}
}
return ""
}