基础架构

This commit is contained in:
2025-07-13 16:36:20 +08:00
parent e3d64e7485
commit 807004f78d
128 changed files with 17232 additions and 11396 deletions

View File

@@ -0,0 +1,353 @@
package repositories
import (
"context"
"time"
"go.uber.org/zap"
"gorm.io/gorm"
"tyapi-server/internal/domains/certification/entities"
"tyapi-server/internal/domains/certification/repositories"
"tyapi-server/internal/domains/certification/repositories/queries"
"tyapi-server/internal/shared/interfaces"
)
// GormCertificationRepository GORM认证仓储实现
type GormCertificationRepository struct {
db *gorm.DB
logger *zap.Logger
}
// 编译时检查接口实现
var _ repositories.CertificationRepository = (*GormCertificationRepository)(nil)
// NewGormCertificationRepository 创建GORM认证仓储
func NewGormCertificationRepository(db *gorm.DB, logger *zap.Logger) repositories.CertificationRepository {
return &GormCertificationRepository{
db: db,
logger: logger,
}
}
// ================ 基础CRUD操作 ================
// Create 创建认证申请
func (r *GormCertificationRepository) Create(ctx context.Context, cert entities.Certification) (entities.Certification, error) {
r.logger.Info("创建认证申请", zap.String("user_id", cert.UserID))
err := r.db.WithContext(ctx).Create(&cert).Error
return cert, err
}
// GetByID 根据ID获取认证申请
func (r *GormCertificationRepository) GetByID(ctx context.Context, id string) (entities.Certification, error) {
var cert entities.Certification
err := r.db.WithContext(ctx).Where("id = ?", id).First(&cert).Error
return cert, err
}
// Update 更新认证申请
func (r *GormCertificationRepository) Update(ctx context.Context, cert entities.Certification) error {
r.logger.Info("更新认证申请", zap.String("id", cert.ID))
return r.db.WithContext(ctx).Save(&cert).Error
}
// Delete 删除认证申请
func (r *GormCertificationRepository) Delete(ctx context.Context, id string) error {
r.logger.Info("删除认证申请", zap.String("id", id))
return r.db.WithContext(ctx).Delete(&entities.Certification{}, "id = ?", id).Error
}
// SoftDelete 软删除认证申请
func (r *GormCertificationRepository) SoftDelete(ctx context.Context, id string) error {
r.logger.Info("软删除认证申请", zap.String("id", id))
return r.db.WithContext(ctx).Delete(&entities.Certification{}, "id = ?", id).Error
}
// Restore 恢复认证申请
func (r *GormCertificationRepository) Restore(ctx context.Context, id string) error {
r.logger.Info("恢复认证申请", zap.String("id", id))
return r.db.WithContext(ctx).Unscoped().Model(&entities.Certification{}).Where("id = ?", id).Update("deleted_at", nil).Error
}
// Count 统计认证申请数量
func (r *GormCertificationRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
var count int64
query := r.db.WithContext(ctx).Model(&entities.Certification{})
if options.Filters != nil {
for key, value := range options.Filters {
query = query.Where(key+" = ?", value)
}
}
if options.Search != "" {
query = query.Where("user_id LIKE ?", "%"+options.Search+"%")
}
err := query.Count(&count).Error
return count, err
}
// Exists 检查认证申请是否存在
func (r *GormCertificationRepository) Exists(ctx context.Context, id string) (bool, error) {
var count int64
err := r.db.WithContext(ctx).Model(&entities.Certification{}).Where("id = ?", id).Count(&count).Error
return count > 0, err
}
// CreateBatch 批量创建认证申请
func (r *GormCertificationRepository) CreateBatch(ctx context.Context, certs []entities.Certification) error {
r.logger.Info("批量创建认证申请", zap.Int("count", len(certs)))
return r.db.WithContext(ctx).Create(&certs).Error
}
// GetByIDs 根据ID列表获取认证申请
func (r *GormCertificationRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.Certification, error) {
var certs []entities.Certification
err := r.db.WithContext(ctx).Where("id IN ?", ids).Find(&certs).Error
return certs, err
}
// UpdateBatch 批量更新认证申请
func (r *GormCertificationRepository) UpdateBatch(ctx context.Context, certs []entities.Certification) error {
r.logger.Info("批量更新认证申请", zap.Int("count", len(certs)))
return r.db.WithContext(ctx).Save(&certs).Error
}
// DeleteBatch 批量删除认证申请
func (r *GormCertificationRepository) DeleteBatch(ctx context.Context, ids []string) error {
r.logger.Info("批量删除认证申请", zap.Strings("ids", ids))
return r.db.WithContext(ctx).Delete(&entities.Certification{}, "id IN ?", ids).Error
}
// List 获取认证申请列表
func (r *GormCertificationRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.Certification, error) {
var certs []entities.Certification
query := r.db.WithContext(ctx).Model(&entities.Certification{})
if options.Filters != nil {
for key, value := range options.Filters {
query = query.Where(key+" = ?", value)
}
}
if options.Search != "" {
query = query.Where("user_id LIKE ?", "%"+options.Search+"%")
}
if options.Sort != "" {
order := "ASC"
if options.Order != "" {
order = options.Order
}
query = query.Order(options.Sort + " " + order)
}
if options.Page > 0 && options.PageSize > 0 {
offset := (options.Page - 1) * options.PageSize
query = query.Offset(offset).Limit(options.PageSize)
}
return certs, query.Find(&certs).Error
}
// WithTx 使用事务
func (r *GormCertificationRepository) WithTx(tx interface{}) interfaces.Repository[entities.Certification] {
if gormTx, ok := tx.(*gorm.DB); ok {
return &GormCertificationRepository{
db: gormTx,
logger: r.logger,
}
}
return r
}
// ================ 业务方法 ================
// ListCertifications 获取认证申请列表(带分页和筛选)
func (r *GormCertificationRepository) ListCertifications(ctx context.Context, query *queries.ListCertificationsQuery) ([]*entities.Certification, int64, error) {
var certs []entities.Certification
var total int64
dbQuery := r.db.WithContext(ctx).Model(&entities.Certification{})
// 应用筛选条件
if query.UserID != "" {
dbQuery = dbQuery.Where("user_id = ?", query.UserID)
}
if query.Status != "" {
dbQuery = dbQuery.Where("status = ?", query.Status)
}
if query.AdminID != "" {
dbQuery = dbQuery.Where("admin_id = ?", query.AdminID)
}
if query.StartDate != "" {
dbQuery = dbQuery.Where("created_at >= ?", query.StartDate)
}
if query.EndDate != "" {
dbQuery = dbQuery.Where("created_at <= ?", query.EndDate)
}
if query.EnterpriseName != "" {
dbQuery = dbQuery.Joins("JOIN enterprises ON certifications.enterprise_id = enterprises.id").
Where("enterprises.enterprise_name LIKE ?", "%"+query.EnterpriseName+"%")
}
// 统计总数
if err := dbQuery.Count(&total).Error; err != nil {
return nil, 0, err
}
// 应用分页
offset := (query.Page - 1) * query.PageSize
dbQuery = dbQuery.Offset(offset).Limit(query.PageSize)
// 默认排序
dbQuery = dbQuery.Order("created_at DESC")
// 查询数据
if err := dbQuery.Find(&certs).Error; err != nil {
return nil, 0, err
}
// 转换为指针切片
certPtrs := make([]*entities.Certification, len(certs))
for i := range certs {
certPtrs[i] = &certs[i]
}
return certPtrs, total, nil
}
// GetByUserID 根据用户ID获取认证申请
func (r *GormCertificationRepository) GetByUserID(ctx context.Context, userID string) (*entities.Certification, error) {
var cert entities.Certification
err := r.db.WithContext(ctx).Where("user_id = ?", userID).First(&cert).Error
if err != nil {
return nil, err
}
return &cert, nil
}
// GetByStatus 根据状态获取认证申请列表
func (r *GormCertificationRepository) GetByStatus(ctx context.Context, status string) ([]*entities.Certification, error) {
var certs []entities.Certification
err := r.db.WithContext(ctx).Where("status = ?", status).Find(&certs).Error
if err != nil {
return nil, err
}
certPtrs := make([]*entities.Certification, len(certs))
for i := range certs {
certPtrs[i] = &certs[i]
}
return certPtrs, nil
}
// UpdateStatus 更新认证状态
func (r *GormCertificationRepository) UpdateStatus(ctx context.Context, certificationID string, status string, adminID *string, notes string) error {
updates := map[string]interface{}{
"status": status,
}
if adminID != nil {
updates["admin_id"] = *adminID
}
if notes != "" {
updates["approval_notes"] = notes
}
// 根据状态设置相应的时间戳
switch status {
case "INFO_SUBMITTED":
updates["info_submitted_at"] = time.Now()
case "FACE_VERIFIED":
updates["face_verified_at"] = time.Now()
case "CONTRACT_APPLIED":
updates["contract_applied_at"] = time.Now()
case "CONTRACT_APPROVED":
updates["contract_approved_at"] = time.Now()
case "CONTRACT_SIGNED":
updates["contract_signed_at"] = time.Now()
case "COMPLETED":
updates["completed_at"] = time.Now()
}
return r.db.WithContext(ctx).
Model(&entities.Certification{}).
Where("id = ?", certificationID).
Updates(updates).Error
}
// GetPendingCertifications 获取待审核的认证申请
func (r *GormCertificationRepository) GetPendingCertifications(ctx context.Context) ([]*entities.Certification, error) {
return r.GetByStatus(ctx, "CONTRACT_PENDING")
}
// GetStats 获取认证统计信息
func (r *GormCertificationRepository) GetStats(ctx context.Context) (*repositories.CertificationStats, error) {
var stats repositories.CertificationStats
// 总认证申请数
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).Count(&stats.TotalCertifications).Error; err != nil {
return nil, err
}
// 待审核认证申请数
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).Where("status = ?", "CONTRACT_PENDING").Count(&stats.PendingCertifications).Error; err != nil {
return nil, err
}
// 已完成认证申请数
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).Where("status = ?", "COMPLETED").Count(&stats.CompletedCertifications).Error; err != nil {
return nil, err
}
// 被拒绝认证申请数
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).Where("status = ?", "REJECTED").Count(&stats.RejectedCertifications).Error; err != nil {
return nil, err
}
// 今日提交数
today := time.Now().Truncate(24 * time.Hour)
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).Where("created_at >= ?", today).Count(&stats.TodaySubmissions).Error; err != nil {
return nil, err
}
return &stats, nil
}
// GetStatsByDateRange 根据日期范围获取认证统计信息
func (r *GormCertificationRepository) GetStatsByDateRange(ctx context.Context, startDate, endDate string) (*repositories.CertificationStats, error) {
var stats repositories.CertificationStats
// 总认证申请数
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).Where("created_at BETWEEN ? AND ?", startDate, endDate).Count(&stats.TotalCertifications).Error; err != nil {
return nil, err
}
// 待审核认证申请数
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).Where("status = ? AND created_at BETWEEN ? AND ?", "CONTRACT_PENDING", startDate, endDate).Count(&stats.PendingCertifications).Error; err != nil {
return nil, err
}
// 已完成认证申请数
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).Where("status = ? AND created_at BETWEEN ? AND ?", "COMPLETED", startDate, endDate).Count(&stats.CompletedCertifications).Error; err != nil {
return nil, err
}
// 被拒绝认证申请数
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).Where("status = ? AND created_at BETWEEN ? AND ?", "REJECTED", startDate, endDate).Count(&stats.RejectedCertifications).Error; err != nil {
return nil, err
}
// 今日提交数
today := time.Now().Truncate(24 * time.Hour)
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).Where("created_at >= ?", today).Count(&stats.TodaySubmissions).Error; err != nil {
return nil, err
}
return &stats, nil
}

View File

@@ -0,0 +1,422 @@
package repositories
import (
"context"
"fmt"
"go.uber.org/zap"
"gorm.io/gorm"
"tyapi-server/internal/domains/certification/entities"
"tyapi-server/internal/domains/certification/repositories"
"tyapi-server/internal/domains/certification/repositories/queries"
"tyapi-server/internal/shared/interfaces"
)
// GormContractRecordRepository GORM合同记录仓储实现
type GormContractRecordRepository struct {
db *gorm.DB
logger *zap.Logger
}
// 编译时检查接口实现
var _ repositories.ContractRecordRepository = (*GormContractRecordRepository)(nil)
// NewGormContractRecordRepository 创建GORM合同记录仓储
func NewGormContractRecordRepository(db *gorm.DB, logger *zap.Logger) repositories.ContractRecordRepository {
return &GormContractRecordRepository{
db: db,
logger: logger,
}
}
// ================ 基础CRUD操作 ================
// Create 创建合同记录
func (r *GormContractRecordRepository) Create(ctx context.Context, record entities.ContractRecord) (entities.ContractRecord, error) {
if err := r.db.WithContext(ctx).Create(&record).Error; err != nil {
r.logger.Error("创建合同记录失败",
zap.String("certification_id", record.CertificationID),
zap.String("contract_type", record.ContractType),
zap.Error(err),
)
return entities.ContractRecord{}, fmt.Errorf("创建合同记录失败: %w", err)
}
r.logger.Info("合同记录创建成功",
zap.String("id", record.ID),
zap.String("contract_type", record.ContractType),
)
return record, nil
}
// GetByID 根据ID获取合同记录
func (r *GormContractRecordRepository) GetByID(ctx context.Context, id string) (entities.ContractRecord, error) {
var record entities.ContractRecord
if err := r.db.WithContext(ctx).First(&record, "id = ?", id).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return entities.ContractRecord{}, fmt.Errorf("合同记录不存在")
}
r.logger.Error("获取合同记录失败",
zap.String("id", id),
zap.Error(err),
)
return entities.ContractRecord{}, fmt.Errorf("获取合同记录失败: %w", err)
}
return record, nil
}
// Update 更新合同记录
func (r *GormContractRecordRepository) Update(ctx context.Context, record entities.ContractRecord) error {
if err := r.db.WithContext(ctx).Save(&record).Error; err != nil {
r.logger.Error("更新合同记录失败",
zap.String("id", record.ID),
zap.Error(err),
)
return fmt.Errorf("更新合同记录失败: %w", err)
}
return nil
}
// Delete 删除合同记录
func (r *GormContractRecordRepository) Delete(ctx context.Context, id string) error {
if err := r.db.WithContext(ctx).Delete(&entities.ContractRecord{}, "id = ?", id).Error; err != nil {
r.logger.Error("删除合同记录失败",
zap.String("id", id),
zap.Error(err),
)
return fmt.Errorf("删除合同记录失败: %w", err)
}
return nil
}
// SoftDelete 软删除合同记录
func (r *GormContractRecordRepository) SoftDelete(ctx context.Context, id string) error {
return r.Delete(ctx, id)
}
// Restore 恢复合同记录
func (r *GormContractRecordRepository) Restore(ctx context.Context, id string) error {
if err := r.db.WithContext(ctx).Unscoped().Model(&entities.ContractRecord{}).Where("id = ?", id).Update("deleted_at", nil).Error; err != nil {
r.logger.Error("恢复合同记录失败",
zap.String("id", id),
zap.Error(err),
)
return fmt.Errorf("恢复合同记录失败: %w", err)
}
r.logger.Info("合同记录恢复成功", zap.String("id", id))
return nil
}
// Count 统计合同记录数量
func (r *GormContractRecordRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
var count int64
query := r.db.WithContext(ctx).Model(&entities.ContractRecord{})
if options.Filters != nil {
for key, value := range options.Filters {
query = query.Where(key+" = ?", value)
}
}
if options.Search != "" {
query = query.Where("contract_type LIKE ? OR contract_name LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%")
}
return count, query.Count(&count).Error
}
// Exists 检查合同记录是否存在
func (r *GormContractRecordRepository) Exists(ctx context.Context, id string) (bool, error) {
var count int64
err := r.db.WithContext(ctx).Model(&entities.ContractRecord{}).Where("id = ?", id).Count(&count).Error
return count > 0, err
}
// CreateBatch 批量创建合同记录
func (r *GormContractRecordRepository) CreateBatch(ctx context.Context, records []entities.ContractRecord) error {
r.logger.Info("批量创建合同记录", zap.Int("count", len(records)))
return r.db.WithContext(ctx).Create(&records).Error
}
// GetByIDs 根据ID列表获取合同记录
func (r *GormContractRecordRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.ContractRecord, error) {
var records []entities.ContractRecord
err := r.db.WithContext(ctx).Where("id IN ?", ids).Find(&records).Error
return records, err
}
// UpdateBatch 批量更新合同记录
func (r *GormContractRecordRepository) UpdateBatch(ctx context.Context, records []entities.ContractRecord) error {
r.logger.Info("批量更新合同记录", zap.Int("count", len(records)))
return r.db.WithContext(ctx).Save(&records).Error
}
// DeleteBatch 批量删除合同记录
func (r *GormContractRecordRepository) DeleteBatch(ctx context.Context, ids []string) error {
r.logger.Info("批量删除合同记录", zap.Strings("ids", ids))
return r.db.WithContext(ctx).Delete(&entities.ContractRecord{}, "id IN ?", ids).Error
}
// List 获取合同记录列表
func (r *GormContractRecordRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.ContractRecord, error) {
var records []entities.ContractRecord
query := r.db.WithContext(ctx).Model(&entities.ContractRecord{})
if options.Filters != nil {
for key, value := range options.Filters {
query = query.Where(key+" = ?", value)
}
}
if options.Search != "" {
query = query.Where("contract_type LIKE ? OR contract_name LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%")
}
if options.Sort != "" {
order := "ASC"
if options.Order != "" {
order = options.Order
}
query = query.Order(options.Sort + " " + order)
}
if options.Page > 0 && options.PageSize > 0 {
offset := (options.Page - 1) * options.PageSize
query = query.Offset(offset).Limit(options.PageSize)
}
return records, query.Find(&records).Error
}
// WithTx 使用事务
func (r *GormContractRecordRepository) WithTx(tx interface{}) interfaces.Repository[entities.ContractRecord] {
if gormTx, ok := tx.(*gorm.DB); ok {
return &GormContractRecordRepository{
db: gormTx,
logger: r.logger,
}
}
return r
}
// ================ 业务方法 ================
// GetByCertificationID 根据认证申请ID获取合同记录列表
func (r *GormContractRecordRepository) GetByCertificationID(ctx context.Context, certificationID string) ([]*entities.ContractRecord, error) {
var records []entities.ContractRecord
if err := r.db.WithContext(ctx).Where("certification_id = ?", certificationID).Order("created_at DESC").Find(&records).Error; err != nil {
r.logger.Error("根据认证申请ID获取合同记录失败",
zap.String("certification_id", certificationID),
zap.Error(err),
)
return nil, fmt.Errorf("获取合同记录失败: %w", err)
}
// 转换为指针切片
recordPtrs := make([]*entities.ContractRecord, len(records))
for i := range records {
recordPtrs[i] = &records[i]
}
return recordPtrs, nil
}
// GetLatestByCertificationID 根据认证申请ID获取最新的合同记录
func (r *GormContractRecordRepository) GetLatestByCertificationID(ctx context.Context, certificationID string) (*entities.ContractRecord, error) {
var record entities.ContractRecord
if err := r.db.WithContext(ctx).Where("certification_id = ?", certificationID).Order("created_at DESC").First(&record).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, fmt.Errorf("合同记录不存在")
}
r.logger.Error("根据认证申请ID获取最新合同记录失败",
zap.String("certification_id", certificationID),
zap.Error(err),
)
return nil, fmt.Errorf("获取合同记录失败: %w", err)
}
return &record, nil
}
// ListRecords 获取合同记录列表(带分页和筛选)
func (r *GormContractRecordRepository) ListRecords(ctx context.Context, query *queries.ListContractRecordsQuery) ([]*entities.ContractRecord, int64, error) {
var records []entities.ContractRecord
var total int64
dbQuery := r.db.WithContext(ctx).Model(&entities.ContractRecord{})
// 应用筛选条件
if query.CertificationID != "" {
dbQuery = dbQuery.Where("certification_id = ?", query.CertificationID)
}
if query.UserID != "" {
dbQuery = dbQuery.Where("user_id = ?", query.UserID)
}
if query.Status != "" {
dbQuery = dbQuery.Where("status = ?", query.Status)
}
if query.StartDate != "" {
dbQuery = dbQuery.Where("created_at >= ?", query.StartDate)
}
if query.EndDate != "" {
dbQuery = dbQuery.Where("created_at <= ?", query.EndDate)
}
// 统计总数
if err := dbQuery.Count(&total).Error; err != nil {
return nil, 0, err
}
// 应用分页
offset := (query.Page - 1) * query.PageSize
dbQuery = dbQuery.Offset(offset).Limit(query.PageSize)
// 默认排序
dbQuery = dbQuery.Order("created_at DESC")
// 查询数据
if err := dbQuery.Find(&records).Error; err != nil {
return nil, 0, err
}
// 转换为指针切片
recordPtrs := make([]*entities.ContractRecord, len(records))
for i := range records {
recordPtrs[i] = &records[i]
}
return recordPtrs, total, nil
}
// UpdateContractStatus 更新合同状态
func (r *GormContractRecordRepository) UpdateContractStatus(ctx context.Context, recordID string, status string, adminID *string, notes string) error {
updates := map[string]interface{}{
"status": status,
}
if adminID != nil {
updates["admin_id"] = *adminID
}
if notes != "" {
updates["admin_notes"] = notes
}
if err := r.db.WithContext(ctx).
Model(&entities.ContractRecord{}).
Where("id = ?", recordID).
Updates(updates).Error; err != nil {
r.logger.Error("更新合同状态失败",
zap.String("record_id", recordID),
zap.String("status", status),
zap.Error(err),
)
return fmt.Errorf("更新合同状态失败: %w", err)
}
r.logger.Info("合同状态更新成功",
zap.String("record_id", recordID),
zap.String("status", status),
)
return nil
}
// GetByUserID 根据用户ID获取合同记录列表
func (r *GormContractRecordRepository) GetByUserID(ctx context.Context, userID string, page, pageSize int) ([]*entities.ContractRecord, int, error) {
var records []entities.ContractRecord
var total int64
query := r.db.WithContext(ctx).Model(&entities.ContractRecord{}).Where("user_id = ?", userID)
// 获取总数
if err := query.Count(&total).Error; err != nil {
r.logger.Error("获取用户合同记录总数失败", zap.Error(err))
return nil, 0, fmt.Errorf("获取合同记录总数失败: %w", err)
}
// 分页查询
offset := (page - 1) * pageSize
if err := query.Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&records).Error; err != nil {
r.logger.Error("获取用户合同记录列表失败", zap.Error(err))
return nil, 0, fmt.Errorf("获取合同记录列表失败: %w", err)
}
// 转换为指针切片
recordPtrs := make([]*entities.ContractRecord, len(records))
for i := range records {
recordPtrs[i] = &records[i]
}
return recordPtrs, int(total), nil
}
// GetByStatus 根据状态获取合同记录列表
func (r *GormContractRecordRepository) GetByStatus(ctx context.Context, status string, page, pageSize int) ([]*entities.ContractRecord, int, error) {
var records []entities.ContractRecord
var total int64
query := r.db.WithContext(ctx).Model(&entities.ContractRecord{}).Where("status = ?", status)
// 获取总数
if err := query.Count(&total).Error; err != nil {
r.logger.Error("根据状态获取合同记录总数失败", zap.Error(err))
return nil, 0, fmt.Errorf("获取合同记录总数失败: %w", err)
}
// 分页查询
offset := (page - 1) * pageSize
if err := query.Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&records).Error; err != nil {
r.logger.Error("根据状态获取合同记录列表失败", zap.Error(err))
return nil, 0, fmt.Errorf("获取合同记录列表失败: %w", err)
}
// 转换为指针切片
recordPtrs := make([]*entities.ContractRecord, len(records))
for i := range records {
recordPtrs[i] = &records[i]
}
return recordPtrs, int(total), nil
}
// GetPendingContracts 获取待审核的合同记录
func (r *GormContractRecordRepository) GetPendingContracts(ctx context.Context, page, pageSize int) ([]*entities.ContractRecord, int, error) {
return r.GetByStatus(ctx, "PENDING", page, pageSize)
}
// GetExpiredSigningContracts 获取签署链接已过期的合同记录
func (r *GormContractRecordRepository) GetExpiredSigningContracts(ctx context.Context, limit int) ([]*entities.ContractRecord, error) {
var records []entities.ContractRecord
if err := r.db.WithContext(ctx).
Where("expires_at < NOW() AND status = ?", "APPROVED").
Limit(limit).
Order("expires_at ASC").
Find(&records).Error; err != nil {
r.logger.Error("获取过期签署合同记录失败", zap.Error(err))
return nil, fmt.Errorf("获取过期签署合同记录失败: %w", err)
}
// 转换为指针切片
recordPtrs := make([]*entities.ContractRecord, len(records))
for i := range records {
recordPtrs[i] = &records[i]
}
return recordPtrs, nil
}
// GetExpiredContracts 获取已过期的合同记录(通用方法)
func (r *GormContractRecordRepository) GetExpiredContracts(ctx context.Context, limit int) ([]*entities.ContractRecord, error) {
return r.GetExpiredSigningContracts(ctx, limit)
}

View File

@@ -0,0 +1,394 @@
package repositories
import (
"context"
"fmt"
"go.uber.org/zap"
"gorm.io/gorm"
"tyapi-server/internal/domains/certification/entities"
"tyapi-server/internal/domains/certification/repositories"
"tyapi-server/internal/domains/certification/repositories/queries"
"tyapi-server/internal/shared/interfaces"
)
// GormFaceVerifyRecordRepository GORM人脸识别记录仓储实现
type GormFaceVerifyRecordRepository struct {
db *gorm.DB
logger *zap.Logger
}
// 编译时检查接口实现
var _ repositories.FaceVerifyRecordRepository = (*GormFaceVerifyRecordRepository)(nil)
// NewGormFaceVerifyRecordRepository 创建GORM人脸识别记录仓储
func NewGormFaceVerifyRecordRepository(db *gorm.DB, logger *zap.Logger) repositories.FaceVerifyRecordRepository {
return &GormFaceVerifyRecordRepository{
db: db,
logger: logger,
}
}
// ================ 基础CRUD操作 ================
// Create 创建人脸识别记录
func (r *GormFaceVerifyRecordRepository) Create(ctx context.Context, record entities.FaceVerifyRecord) (entities.FaceVerifyRecord, error) {
if err := r.db.WithContext(ctx).Create(&record).Error; err != nil {
r.logger.Error("创建人脸识别记录失败",
zap.String("certification_id", record.CertificationID),
zap.String("certify_id", record.CertifyID),
zap.Error(err),
)
return entities.FaceVerifyRecord{}, fmt.Errorf("创建人脸识别记录失败: %w", err)
}
r.logger.Info("人脸识别记录创建成功",
zap.String("id", record.ID),
zap.String("certify_id", record.CertifyID),
)
return record, nil
}
// GetByID 根据ID获取人脸识别记录
func (r *GormFaceVerifyRecordRepository) GetByID(ctx context.Context, id string) (entities.FaceVerifyRecord, error) {
var record entities.FaceVerifyRecord
if err := r.db.WithContext(ctx).First(&record, "id = ?", id).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return entities.FaceVerifyRecord{}, fmt.Errorf("人脸识别记录不存在")
}
r.logger.Error("获取人脸识别记录失败",
zap.String("id", id),
zap.Error(err),
)
return entities.FaceVerifyRecord{}, fmt.Errorf("获取人脸识别记录失败: %w", err)
}
return record, nil
}
// Update 更新人脸识别记录
func (r *GormFaceVerifyRecordRepository) Update(ctx context.Context, record entities.FaceVerifyRecord) error {
if err := r.db.WithContext(ctx).Save(&record).Error; err != nil {
r.logger.Error("更新人脸识别记录失败",
zap.String("id", record.ID),
zap.Error(err),
)
return fmt.Errorf("更新人脸识别记录失败: %w", err)
}
return nil
}
// Delete 删除人脸识别记录
func (r *GormFaceVerifyRecordRepository) Delete(ctx context.Context, id string) error {
if err := r.db.WithContext(ctx).Delete(&entities.FaceVerifyRecord{}, "id = ?", id).Error; err != nil {
r.logger.Error("删除人脸识别记录失败",
zap.String("id", id),
zap.Error(err),
)
return fmt.Errorf("删除人脸识别记录失败: %w", err)
}
return nil
}
// SoftDelete 软删除人脸识别记录
func (r *GormFaceVerifyRecordRepository) SoftDelete(ctx context.Context, id string) error {
return r.Delete(ctx, id)
}
// Restore 恢复人脸识别记录
func (r *GormFaceVerifyRecordRepository) Restore(ctx context.Context, id string) error {
if err := r.db.WithContext(ctx).Unscoped().Model(&entities.FaceVerifyRecord{}).Where("id = ?", id).Update("deleted_at", nil).Error; err != nil {
r.logger.Error("恢复人脸识别记录失败",
zap.String("id", id),
zap.Error(err),
)
return fmt.Errorf("恢复人脸识别记录失败: %w", err)
}
r.logger.Info("人脸识别记录恢复成功", zap.String("id", id))
return nil
}
// Count 统计人脸识别记录数量
func (r *GormFaceVerifyRecordRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
var count int64
query := r.db.WithContext(ctx).Model(&entities.FaceVerifyRecord{})
if options.Filters != nil {
for key, value := range options.Filters {
query = query.Where(key+" = ?", value)
}
}
if options.Search != "" {
query = query.Where("certify_id LIKE ? OR user_id LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%")
}
return count, query.Count(&count).Error
}
// Exists 检查人脸识别记录是否存在
func (r *GormFaceVerifyRecordRepository) Exists(ctx context.Context, id string) (bool, error) {
var count int64
err := r.db.WithContext(ctx).Model(&entities.FaceVerifyRecord{}).Where("id = ?", id).Count(&count).Error
return count > 0, err
}
// CreateBatch 批量创建人脸识别记录
func (r *GormFaceVerifyRecordRepository) CreateBatch(ctx context.Context, records []entities.FaceVerifyRecord) error {
r.logger.Info("批量创建人脸识别记录", zap.Int("count", len(records)))
return r.db.WithContext(ctx).Create(&records).Error
}
// GetByIDs 根据ID列表获取人脸识别记录
func (r *GormFaceVerifyRecordRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.FaceVerifyRecord, error) {
var records []entities.FaceVerifyRecord
err := r.db.WithContext(ctx).Where("id IN ?", ids).Find(&records).Error
return records, err
}
// UpdateBatch 批量更新人脸识别记录
func (r *GormFaceVerifyRecordRepository) UpdateBatch(ctx context.Context, records []entities.FaceVerifyRecord) error {
r.logger.Info("批量更新人脸识别记录", zap.Int("count", len(records)))
return r.db.WithContext(ctx).Save(&records).Error
}
// DeleteBatch 批量删除人脸识别记录
func (r *GormFaceVerifyRecordRepository) DeleteBatch(ctx context.Context, ids []string) error {
r.logger.Info("批量删除人脸识别记录", zap.Strings("ids", ids))
return r.db.WithContext(ctx).Delete(&entities.FaceVerifyRecord{}, "id IN ?", ids).Error
}
// List 获取人脸识别记录列表
func (r *GormFaceVerifyRecordRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.FaceVerifyRecord, error) {
var records []entities.FaceVerifyRecord
query := r.db.WithContext(ctx).Model(&entities.FaceVerifyRecord{})
if options.Filters != nil {
for key, value := range options.Filters {
query = query.Where(key+" = ?", value)
}
}
if options.Search != "" {
query = query.Where("certify_id LIKE ? OR user_id LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%")
}
if options.Sort != "" {
order := "ASC"
if options.Order != "" {
order = options.Order
}
query = query.Order(options.Sort + " " + order)
}
if options.Page > 0 && options.PageSize > 0 {
offset := (options.Page - 1) * options.PageSize
query = query.Offset(offset).Limit(options.PageSize)
}
return records, query.Find(&records).Error
}
// WithTx 使用事务
func (r *GormFaceVerifyRecordRepository) WithTx(tx interface{}) interfaces.Repository[entities.FaceVerifyRecord] {
if gormTx, ok := tx.(*gorm.DB); ok {
return &GormFaceVerifyRecordRepository{
db: gormTx,
logger: r.logger,
}
}
return r
}
// ================ 业务方法 ================
// GetByCertificationID 根据认证申请ID获取人脸识别记录列表
func (r *GormFaceVerifyRecordRepository) GetByCertificationID(ctx context.Context, certificationID string) ([]*entities.FaceVerifyRecord, error) {
var records []entities.FaceVerifyRecord
if err := r.db.WithContext(ctx).Where("certification_id = ?", certificationID).Order("created_at DESC").Find(&records).Error; err != nil {
r.logger.Error("根据认证申请ID获取人脸识别记录失败",
zap.String("certification_id", certificationID),
zap.Error(err),
)
return nil, fmt.Errorf("获取人脸识别记录失败: %w", err)
}
// 转换为指针切片
recordPtrs := make([]*entities.FaceVerifyRecord, len(records))
for i := range records {
recordPtrs[i] = &records[i]
}
return recordPtrs, nil
}
// GetLatestByCertificationID 根据认证申请ID获取最新的人脸识别记录
func (r *GormFaceVerifyRecordRepository) GetLatestByCertificationID(ctx context.Context, certificationID string) (*entities.FaceVerifyRecord, error) {
var record entities.FaceVerifyRecord
if err := r.db.WithContext(ctx).Where("certification_id = ?", certificationID).Order("created_at DESC").First(&record).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, fmt.Errorf("人脸识别记录不存在")
}
r.logger.Error("根据认证申请ID获取最新人脸识别记录失败",
zap.String("certification_id", certificationID),
zap.Error(err),
)
return nil, fmt.Errorf("获取人脸识别记录失败: %w", err)
}
return &record, nil
}
// ListRecords 获取人脸识别记录列表(带分页和筛选)
func (r *GormFaceVerifyRecordRepository) ListRecords(ctx context.Context, query *queries.ListFaceVerifyRecordsQuery) ([]*entities.FaceVerifyRecord, int64, error) {
var records []entities.FaceVerifyRecord
var total int64
dbQuery := r.db.WithContext(ctx).Model(&entities.FaceVerifyRecord{})
// 应用筛选条件
if query.CertificationID != "" {
dbQuery = dbQuery.Where("certification_id = ?", query.CertificationID)
}
if query.UserID != "" {
dbQuery = dbQuery.Where("user_id = ?", query.UserID)
}
if query.Status != "" {
dbQuery = dbQuery.Where("status = ?", query.Status)
}
if query.StartDate != "" {
dbQuery = dbQuery.Where("created_at >= ?", query.StartDate)
}
if query.EndDate != "" {
dbQuery = dbQuery.Where("created_at <= ?", query.EndDate)
}
// 统计总数
if err := dbQuery.Count(&total).Error; err != nil {
return nil, 0, err
}
// 应用分页
offset := (query.Page - 1) * query.PageSize
dbQuery = dbQuery.Offset(offset).Limit(query.PageSize)
// 默认排序
dbQuery = dbQuery.Order("created_at DESC")
// 查询数据
if err := dbQuery.Find(&records).Error; err != nil {
return nil, 0, err
}
// 转换为指针切片
recordPtrs := make([]*entities.FaceVerifyRecord, len(records))
for i := range records {
recordPtrs[i] = &records[i]
}
return recordPtrs, total, nil
}
// GetSuccessRate 获取成功率
func (r *GormFaceVerifyRecordRepository) GetSuccessRate(ctx context.Context, days int) (float64, error) {
var totalCount int64
var successCount int64
// 计算指定天数前的日期
startDate := fmt.Sprintf("DATE_SUB(NOW(), INTERVAL %d DAY)", days)
// 获取总数
if err := r.db.WithContext(ctx).Model(&entities.FaceVerifyRecord{}).
Where("created_at >= " + startDate).Count(&totalCount).Error; err != nil {
return 0, err
}
// 获取成功数
if err := r.db.WithContext(ctx).Model(&entities.FaceVerifyRecord{}).
Where("created_at >= "+startDate+" AND status = ?", "SUCCESS").Count(&successCount).Error; err != nil {
return 0, err
}
if totalCount == 0 {
return 0, nil
}
return float64(successCount) / float64(totalCount) * 100, nil
}
// GetByCertifyID 根据认证ID获取人脸识别记录
func (r *GormFaceVerifyRecordRepository) GetByCertifyID(ctx context.Context, certifyID string) (*entities.FaceVerifyRecord, error) {
var record entities.FaceVerifyRecord
if err := r.db.WithContext(ctx).First(&record, "certify_id = ?", certifyID).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, fmt.Errorf("人脸识别记录不存在")
}
r.logger.Error("根据认证ID获取人脸识别记录失败",
zap.String("certify_id", certifyID),
zap.Error(err),
)
return nil, fmt.Errorf("获取人脸识别记录失败: %w", err)
}
return &record, nil
}
// GetByUserID 根据用户ID获取人脸识别记录列表
func (r *GormFaceVerifyRecordRepository) GetByUserID(ctx context.Context, userID string, page, pageSize int) ([]*entities.FaceVerifyRecord, int, error) {
var records []entities.FaceVerifyRecord
var total int64
query := r.db.WithContext(ctx).Model(&entities.FaceVerifyRecord{}).Where("user_id = ?", userID)
// 获取总数
if err := query.Count(&total).Error; err != nil {
r.logger.Error("获取用户人脸识别记录总数失败", zap.Error(err))
return nil, 0, fmt.Errorf("获取人脸识别记录总数失败: %w", err)
}
// 分页查询
offset := (page - 1) * pageSize
if err := query.Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&records).Error; err != nil {
r.logger.Error("获取用户人脸识别记录列表失败", zap.Error(err))
return nil, 0, fmt.Errorf("获取人脸识别记录列表失败: %w", err)
}
// 转换为指针切片
recordPtrs := make([]*entities.FaceVerifyRecord, len(records))
for i := range records {
recordPtrs[i] = &records[i]
}
return recordPtrs, int(total), nil
}
// GetExpiredRecords 获取已过期的人脸识别记录
func (r *GormFaceVerifyRecordRepository) GetExpiredRecords(ctx context.Context, limit int) ([]*entities.FaceVerifyRecord, error) {
var records []entities.FaceVerifyRecord
if err := r.db.WithContext(ctx).
Where("expires_at < NOW() AND status = ?", "PROCESSING").
Limit(limit).
Order("expires_at ASC").
Find(&records).Error; err != nil {
r.logger.Error("获取过期人脸识别记录失败", zap.Error(err))
return nil, fmt.Errorf("获取过期人脸识别记录失败: %w", err)
}
// 转换为指针切片
recordPtrs := make([]*entities.FaceVerifyRecord, len(records))
for i := range records {
recordPtrs[i] = &records[i]
}
return recordPtrs, nil
}

View File

@@ -0,0 +1,374 @@
package repositories
import (
"context"
"fmt"
"go.uber.org/zap"
"gorm.io/gorm"
"tyapi-server/internal/domains/certification/entities"
"tyapi-server/internal/domains/certification/repositories"
"tyapi-server/internal/domains/certification/repositories/queries"
"tyapi-server/internal/shared/interfaces"
)
// GormLicenseUploadRecordRepository GORM营业执照上传记录仓储实现
type GormLicenseUploadRecordRepository struct {
db *gorm.DB
logger *zap.Logger
}
// 编译时检查接口实现
var _ repositories.LicenseUploadRecordRepository = (*GormLicenseUploadRecordRepository)(nil)
// NewGormLicenseUploadRecordRepository 创建GORM营业执照上传记录仓储
func NewGormLicenseUploadRecordRepository(db *gorm.DB, logger *zap.Logger) repositories.LicenseUploadRecordRepository {
return &GormLicenseUploadRecordRepository{
db: db,
logger: logger,
}
}
// ================ 基础CRUD操作 ================
// Create 创建上传记录
func (r *GormLicenseUploadRecordRepository) Create(ctx context.Context, record entities.LicenseUploadRecord) (entities.LicenseUploadRecord, error) {
if err := r.db.WithContext(ctx).Create(&record).Error; err != nil {
r.logger.Error("创建上传记录失败",
zap.String("user_id", record.UserID),
zap.String("file_name", record.OriginalFileName),
zap.Error(err),
)
return entities.LicenseUploadRecord{}, fmt.Errorf("创建上传记录失败: %w", err)
}
r.logger.Info("上传记录创建成功",
zap.String("id", record.ID),
zap.String("file_name", record.OriginalFileName),
)
return record, nil
}
// GetByID 根据ID获取上传记录
func (r *GormLicenseUploadRecordRepository) GetByID(ctx context.Context, id string) (entities.LicenseUploadRecord, error) {
var record entities.LicenseUploadRecord
if err := r.db.WithContext(ctx).First(&record, "id = ?", id).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return entities.LicenseUploadRecord{}, fmt.Errorf("上传记录不存在")
}
r.logger.Error("获取上传记录失败",
zap.String("id", id),
zap.Error(err),
)
return entities.LicenseUploadRecord{}, fmt.Errorf("获取上传记录失败: %w", err)
}
return record, nil
}
// Update 更新上传记录
func (r *GormLicenseUploadRecordRepository) Update(ctx context.Context, record entities.LicenseUploadRecord) error {
if err := r.db.WithContext(ctx).Save(&record).Error; err != nil {
r.logger.Error("更新上传记录失败",
zap.String("id", record.ID),
zap.Error(err),
)
return fmt.Errorf("更新上传记录失败: %w", err)
}
return nil
}
// Delete 删除上传记录
func (r *GormLicenseUploadRecordRepository) Delete(ctx context.Context, id string) error {
if err := r.db.WithContext(ctx).Delete(&entities.LicenseUploadRecord{}, "id = ?", id).Error; err != nil {
r.logger.Error("删除上传记录失败",
zap.String("id", id),
zap.Error(err),
)
return fmt.Errorf("删除上传记录失败: %w", err)
}
return nil
}
// SoftDelete 软删除上传记录
func (r *GormLicenseUploadRecordRepository) SoftDelete(ctx context.Context, id string) error {
return r.Delete(ctx, id)
}
// Restore 恢复上传记录
func (r *GormLicenseUploadRecordRepository) Restore(ctx context.Context, id string) error {
if err := r.db.WithContext(ctx).Unscoped().Model(&entities.LicenseUploadRecord{}).Where("id = ?", id).Update("deleted_at", nil).Error; err != nil {
r.logger.Error("恢复上传记录失败",
zap.String("id", id),
zap.Error(err),
)
return fmt.Errorf("恢复上传记录失败: %w", err)
}
r.logger.Info("上传记录恢复成功", zap.String("id", id))
return nil
}
// Count 统计上传记录数量
func (r *GormLicenseUploadRecordRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
var count int64
query := r.db.WithContext(ctx).Model(&entities.LicenseUploadRecord{})
if options.Filters != nil {
for key, value := range options.Filters {
query = query.Where(key+" = ?", value)
}
}
if options.Search != "" {
query = query.Where("original_file_name LIKE ? OR user_id LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%")
}
return count, query.Count(&count).Error
}
// Exists 检查上传记录是否存在
func (r *GormLicenseUploadRecordRepository) Exists(ctx context.Context, id string) (bool, error) {
var count int64
err := r.db.WithContext(ctx).Model(&entities.LicenseUploadRecord{}).Where("id = ?", id).Count(&count).Error
return count > 0, err
}
// CreateBatch 批量创建上传记录
func (r *GormLicenseUploadRecordRepository) CreateBatch(ctx context.Context, records []entities.LicenseUploadRecord) error {
r.logger.Info("批量创建上传记录", zap.Int("count", len(records)))
return r.db.WithContext(ctx).Create(&records).Error
}
// GetByIDs 根据ID列表获取上传记录
func (r *GormLicenseUploadRecordRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.LicenseUploadRecord, error) {
var records []entities.LicenseUploadRecord
err := r.db.WithContext(ctx).Where("id IN ?", ids).Find(&records).Error
return records, err
}
// UpdateBatch 批量更新上传记录
func (r *GormLicenseUploadRecordRepository) UpdateBatch(ctx context.Context, records []entities.LicenseUploadRecord) error {
r.logger.Info("批量更新上传记录", zap.Int("count", len(records)))
return r.db.WithContext(ctx).Save(&records).Error
}
// DeleteBatch 批量删除上传记录
func (r *GormLicenseUploadRecordRepository) DeleteBatch(ctx context.Context, ids []string) error {
r.logger.Info("批量删除上传记录", zap.Strings("ids", ids))
return r.db.WithContext(ctx).Delete(&entities.LicenseUploadRecord{}, "id IN ?", ids).Error
}
// List 获取上传记录列表
func (r *GormLicenseUploadRecordRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.LicenseUploadRecord, error) {
var records []entities.LicenseUploadRecord
query := r.db.WithContext(ctx).Model(&entities.LicenseUploadRecord{})
if options.Filters != nil {
for key, value := range options.Filters {
query = query.Where(key+" = ?", value)
}
}
if options.Search != "" {
query = query.Where("original_file_name LIKE ? OR user_id LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%")
}
if options.Sort != "" {
order := "ASC"
if options.Order != "" {
order = options.Order
}
query = query.Order(options.Sort + " " + order)
}
if options.Page > 0 && options.PageSize > 0 {
offset := (options.Page - 1) * options.PageSize
query = query.Offset(offset).Limit(options.PageSize)
}
return records, query.Find(&records).Error
}
// WithTx 使用事务
func (r *GormLicenseUploadRecordRepository) WithTx(tx interface{}) interfaces.Repository[entities.LicenseUploadRecord] {
if gormTx, ok := tx.(*gorm.DB); ok {
return &GormLicenseUploadRecordRepository{
db: gormTx,
logger: r.logger,
}
}
return r
}
// ================ 业务方法 ================
// GetByCertificationID 根据认证ID获取上传记录
func (r *GormLicenseUploadRecordRepository) GetByCertificationID(ctx context.Context, certificationID string) (*entities.LicenseUploadRecord, error) {
var record entities.LicenseUploadRecord
if err := r.db.WithContext(ctx).First(&record, "certification_id = ?", certificationID).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, fmt.Errorf("上传记录不存在")
}
r.logger.Error("根据认证ID获取上传记录失败",
zap.String("certification_id", certificationID),
zap.Error(err),
)
return nil, fmt.Errorf("获取上传记录失败: %w", err)
}
return &record, nil
}
// ListRecords 获取上传记录列表(带分页和筛选)
func (r *GormLicenseUploadRecordRepository) ListRecords(ctx context.Context, query *queries.ListLicenseUploadRecordsQuery) ([]*entities.LicenseUploadRecord, int64, error) {
var records []entities.LicenseUploadRecord
var total int64
dbQuery := r.db.WithContext(ctx).Model(&entities.LicenseUploadRecord{})
// 应用筛选条件
if query.CertificationID != "" {
dbQuery = dbQuery.Where("certification_id = ?", query.CertificationID)
}
if query.UserID != "" {
dbQuery = dbQuery.Where("user_id = ?", query.UserID)
}
if query.Status != "" {
dbQuery = dbQuery.Where("status = ?", query.Status)
}
if query.StartDate != "" {
dbQuery = dbQuery.Where("created_at >= ?", query.StartDate)
}
if query.EndDate != "" {
dbQuery = dbQuery.Where("created_at <= ?", query.EndDate)
}
// 统计总数
if err := dbQuery.Count(&total).Error; err != nil {
return nil, 0, err
}
// 应用分页
offset := (query.Page - 1) * query.PageSize
dbQuery = dbQuery.Offset(offset).Limit(query.PageSize)
// 默认排序
dbQuery = dbQuery.Order("created_at DESC")
// 查询数据
if err := dbQuery.Find(&records).Error; err != nil {
return nil, 0, err
}
// 转换为指针切片
recordPtrs := make([]*entities.LicenseUploadRecord, len(records))
for i := range records {
recordPtrs[i] = &records[i]
}
return recordPtrs, total, nil
}
// UpdateOCRResult 更新OCR结果
func (r *GormLicenseUploadRecordRepository) UpdateOCRResult(ctx context.Context, recordID string, ocrResult string, confidence float64) error {
updates := map[string]interface{}{
"ocr_result": ocrResult,
"ocr_confidence": confidence,
"ocr_processed": true,
"ocr_success": true,
}
if err := r.db.WithContext(ctx).
Model(&entities.LicenseUploadRecord{}).
Where("id = ?", recordID).
Updates(updates).Error; err != nil {
r.logger.Error("更新OCR结果失败",
zap.String("record_id", recordID),
zap.Error(err),
)
return fmt.Errorf("更新OCR结果失败: %w", err)
}
r.logger.Info("OCR结果更新成功",
zap.String("record_id", recordID),
zap.Float64("confidence", confidence),
)
return nil
}
// GetByUserID 根据用户ID获取上传记录列表
func (r *GormLicenseUploadRecordRepository) GetByUserID(ctx context.Context, userID string, page, pageSize int) ([]*entities.LicenseUploadRecord, int, error) {
var records []entities.LicenseUploadRecord
var total int64
query := r.db.WithContext(ctx).Model(&entities.LicenseUploadRecord{}).Where("user_id = ?", userID)
// 获取总数
if err := query.Count(&total).Error; err != nil {
r.logger.Error("获取用户上传记录总数失败", zap.Error(err))
return nil, 0, fmt.Errorf("获取上传记录总数失败: %w", err)
}
// 分页查询
offset := (page - 1) * pageSize
if err := query.Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&records).Error; err != nil {
r.logger.Error("获取用户上传记录列表失败", zap.Error(err))
return nil, 0, fmt.Errorf("获取上传记录列表失败: %w", err)
}
// 转换为指针切片
recordPtrs := make([]*entities.LicenseUploadRecord, len(records))
for i := range records {
recordPtrs[i] = &records[i]
}
return recordPtrs, int(total), nil
}
// GetByQiNiuKey 根据七牛云Key获取上传记录
func (r *GormLicenseUploadRecordRepository) GetByQiNiuKey(ctx context.Context, key string) (*entities.LicenseUploadRecord, error) {
var record entities.LicenseUploadRecord
if err := r.db.WithContext(ctx).First(&record, "qiniu_key = ?", key).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, fmt.Errorf("上传记录不存在")
}
r.logger.Error("根据七牛云Key获取上传记录失败",
zap.String("qiniu_key", key),
zap.Error(err),
)
return nil, fmt.Errorf("获取上传记录失败: %w", err)
}
return &record, nil
}
// GetPendingOCR 获取待OCR处理的上传记录
func (r *GormLicenseUploadRecordRepository) GetPendingOCR(ctx context.Context, limit int) ([]*entities.LicenseUploadRecord, error) {
var records []entities.LicenseUploadRecord
if err := r.db.WithContext(ctx).
Where("ocr_processed = ? OR (ocr_processed = ? AND ocr_success = ?)", false, true, false).
Limit(limit).
Order("created_at ASC").
Find(&records).Error; err != nil {
r.logger.Error("获取待OCR处理记录失败", zap.Error(err))
return nil, fmt.Errorf("获取待OCR处理记录失败: %w", err)
}
// 转换为指针切片
recordPtrs := make([]*entities.LicenseUploadRecord, len(records))
for i := range records {
recordPtrs[i] = &records[i]
}
return recordPtrs, nil
}

View File

@@ -0,0 +1,344 @@
package repositories
import (
"context"
"fmt"
"go.uber.org/zap"
"gorm.io/gorm"
"tyapi-server/internal/domains/certification/entities"
"tyapi-server/internal/domains/certification/repositories"
"tyapi-server/internal/domains/certification/repositories/queries"
"tyapi-server/internal/shared/interfaces"
)
// GormNotificationRecordRepository GORM通知记录仓储实现
type GormNotificationRecordRepository struct {
db *gorm.DB
logger *zap.Logger
}
// 编译时检查接口实现
var _ repositories.NotificationRecordRepository = (*GormNotificationRecordRepository)(nil)
// NewGormNotificationRecordRepository 创建GORM通知记录仓储
func NewGormNotificationRecordRepository(db *gorm.DB, logger *zap.Logger) repositories.NotificationRecordRepository {
return &GormNotificationRecordRepository{
db: db,
logger: logger,
}
}
// ================ 基础CRUD操作 ================
// Create 创建通知记录
func (r *GormNotificationRecordRepository) Create(ctx context.Context, record entities.NotificationRecord) (entities.NotificationRecord, error) {
if err := r.db.WithContext(ctx).Create(&record).Error; err != nil {
r.logger.Error("创建通知记录失败",
zap.String("user_id", *record.UserID),
zap.String("type", record.NotificationType),
zap.Error(err),
)
return entities.NotificationRecord{}, fmt.Errorf("创建通知记录失败: %w", err)
}
r.logger.Info("通知记录创建成功",
zap.String("id", record.ID),
zap.String("type", record.NotificationType),
)
return record, nil
}
// GetByID 根据ID获取通知记录
func (r *GormNotificationRecordRepository) GetByID(ctx context.Context, id string) (entities.NotificationRecord, error) {
var record entities.NotificationRecord
if err := r.db.WithContext(ctx).First(&record, "id = ?", id).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return entities.NotificationRecord{}, fmt.Errorf("通知记录不存在")
}
r.logger.Error("获取通知记录失败",
zap.String("id", id),
zap.Error(err),
)
return entities.NotificationRecord{}, fmt.Errorf("获取通知记录失败: %w", err)
}
return record, nil
}
// Update 更新通知记录
func (r *GormNotificationRecordRepository) Update(ctx context.Context, record entities.NotificationRecord) error {
if err := r.db.WithContext(ctx).Save(&record).Error; err != nil {
r.logger.Error("更新通知记录失败",
zap.String("id", record.ID),
zap.Error(err),
)
return fmt.Errorf("更新通知记录失败: %w", err)
}
return nil
}
// Delete 删除通知记录
func (r *GormNotificationRecordRepository) Delete(ctx context.Context, id string) error {
if err := r.db.WithContext(ctx).Delete(&entities.NotificationRecord{}, "id = ?", id).Error; err != nil {
r.logger.Error("删除通知记录失败",
zap.String("id", id),
zap.Error(err),
)
return fmt.Errorf("删除通知记录失败: %w", err)
}
return nil
}
// SoftDelete 软删除通知记录
func (r *GormNotificationRecordRepository) SoftDelete(ctx context.Context, id string) error {
return r.Delete(ctx, id)
}
// Restore 恢复通知记录
func (r *GormNotificationRecordRepository) Restore(ctx context.Context, id string) error {
if err := r.db.WithContext(ctx).Unscoped().Model(&entities.NotificationRecord{}).Where("id = ?", id).Update("deleted_at", nil).Error; err != nil {
r.logger.Error("恢复通知记录失败",
zap.String("id", id),
zap.Error(err),
)
return fmt.Errorf("恢复通知记录失败: %w", err)
}
r.logger.Info("通知记录恢复成功", zap.String("id", id))
return nil
}
// Count 统计通知记录数量
func (r *GormNotificationRecordRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
var count int64
query := r.db.WithContext(ctx).Model(&entities.NotificationRecord{})
if options.Filters != nil {
for key, value := range options.Filters {
query = query.Where(key+" = ?", value)
}
}
if options.Search != "" {
query = query.Where("title LIKE ? OR content LIKE ? OR user_id LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%", "%"+options.Search+"%")
}
return count, query.Count(&count).Error
}
// Exists 检查通知记录是否存在
func (r *GormNotificationRecordRepository) Exists(ctx context.Context, id string) (bool, error) {
var count int64
err := r.db.WithContext(ctx).Model(&entities.NotificationRecord{}).Where("id = ?", id).Count(&count).Error
return count > 0, err
}
// CreateBatch 批量创建通知记录
func (r *GormNotificationRecordRepository) CreateBatch(ctx context.Context, records []entities.NotificationRecord) error {
r.logger.Info("批量创建通知记录", zap.Int("count", len(records)))
return r.db.WithContext(ctx).Create(&records).Error
}
// GetByIDs 根据ID列表获取通知记录
func (r *GormNotificationRecordRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.NotificationRecord, error) {
var records []entities.NotificationRecord
err := r.db.WithContext(ctx).Where("id IN ?", ids).Find(&records).Error
return records, err
}
// UpdateBatch 批量更新通知记录
func (r *GormNotificationRecordRepository) UpdateBatch(ctx context.Context, records []entities.NotificationRecord) error {
r.logger.Info("批量更新通知记录", zap.Int("count", len(records)))
return r.db.WithContext(ctx).Save(&records).Error
}
// DeleteBatch 批量删除通知记录
func (r *GormNotificationRecordRepository) DeleteBatch(ctx context.Context, ids []string) error {
r.logger.Info("批量删除通知记录", zap.Strings("ids", ids))
return r.db.WithContext(ctx).Delete(&entities.NotificationRecord{}, "id IN ?", ids).Error
}
// List 获取通知记录列表
func (r *GormNotificationRecordRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.NotificationRecord, error) {
var records []entities.NotificationRecord
query := r.db.WithContext(ctx).Model(&entities.NotificationRecord{})
if options.Filters != nil {
for key, value := range options.Filters {
query = query.Where(key+" = ?", value)
}
}
if options.Search != "" {
query = query.Where("title LIKE ? OR content LIKE ? OR user_id LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%", "%"+options.Search+"%")
}
if options.Sort != "" {
order := "ASC"
if options.Order != "" {
order = options.Order
}
query = query.Order(options.Sort + " " + order)
}
if options.Page > 0 && options.PageSize > 0 {
offset := (options.Page - 1) * options.PageSize
query = query.Offset(offset).Limit(options.PageSize)
}
return records, query.Find(&records).Error
}
// WithTx 使用事务
func (r *GormNotificationRecordRepository) WithTx(tx interface{}) interfaces.Repository[entities.NotificationRecord] {
if gormTx, ok := tx.(*gorm.DB); ok {
return &GormNotificationRecordRepository{
db: gormTx,
logger: r.logger,
}
}
return r
}
// ================ 业务方法 ================
// GetByCertificationID 根据认证申请ID获取通知记录列表
func (r *GormNotificationRecordRepository) GetByCertificationID(ctx context.Context, certificationID string) ([]*entities.NotificationRecord, error) {
var records []entities.NotificationRecord
if err := r.db.WithContext(ctx).Where("certification_id = ?", certificationID).Order("created_at DESC").Find(&records).Error; err != nil {
r.logger.Error("根据认证申请ID获取通知记录失败",
zap.String("certification_id", certificationID),
zap.Error(err),
)
return nil, fmt.Errorf("获取通知记录失败: %w", err)
}
// 转换为指针切片
recordPtrs := make([]*entities.NotificationRecord, len(records))
for i := range records {
recordPtrs[i] = &records[i]
}
return recordPtrs, nil
}
// GetUnreadByUserID 根据用户ID获取未读通知记录列表
func (r *GormNotificationRecordRepository) GetUnreadByUserID(ctx context.Context, userID string) ([]*entities.NotificationRecord, error) {
var records []entities.NotificationRecord
if err := r.db.WithContext(ctx).Where("user_id = ? AND is_read = ?", userID, false).Order("created_at DESC").Find(&records).Error; err != nil {
r.logger.Error("根据用户ID获取未读通知记录失败",
zap.String("user_id", userID),
zap.Error(err),
)
return nil, fmt.Errorf("获取未读通知记录失败: %w", err)
}
// 转换为指针切片
recordPtrs := make([]*entities.NotificationRecord, len(records))
for i := range records {
recordPtrs[i] = &records[i]
}
return recordPtrs, nil
}
// ListRecords 获取通知记录列表(带分页和筛选)
func (r *GormNotificationRecordRepository) ListRecords(ctx context.Context, query *queries.ListNotificationRecordsQuery) ([]*entities.NotificationRecord, int64, error) {
var records []entities.NotificationRecord
var total int64
dbQuery := r.db.WithContext(ctx).Model(&entities.NotificationRecord{})
// 应用筛选条件
if query.CertificationID != "" {
dbQuery = dbQuery.Where("certification_id = ?", query.CertificationID)
}
if query.UserID != "" {
dbQuery = dbQuery.Where("user_id = ?", query.UserID)
}
if query.Type != "" {
dbQuery = dbQuery.Where("type = ?", query.Type)
}
if query.IsRead != nil {
dbQuery = dbQuery.Where("is_read = ?", *query.IsRead)
}
if query.StartDate != "" {
dbQuery = dbQuery.Where("created_at >= ?", query.StartDate)
}
if query.EndDate != "" {
dbQuery = dbQuery.Where("created_at <= ?", query.EndDate)
}
// 统计总数
if err := dbQuery.Count(&total).Error; err != nil {
return nil, 0, err
}
// 应用分页
offset := (query.Page - 1) * query.PageSize
dbQuery = dbQuery.Offset(offset).Limit(query.PageSize)
// 默认排序
dbQuery = dbQuery.Order("created_at DESC")
// 查询数据
if err := dbQuery.Find(&records).Error; err != nil {
return nil, 0, err
}
// 转换为指针切片
recordPtrs := make([]*entities.NotificationRecord, len(records))
for i := range records {
recordPtrs[i] = &records[i]
}
return recordPtrs, total, nil
}
// BatchCreate 批量创建通知记录
func (r *GormNotificationRecordRepository) BatchCreate(ctx context.Context, records []entities.NotificationRecord) error {
r.logger.Info("批量创建通知记录", zap.Int("count", len(records)))
return r.db.WithContext(ctx).Create(&records).Error
}
// MarkAsRead 标记通知记录为已读
func (r *GormNotificationRecordRepository) MarkAsRead(ctx context.Context, recordIDs []string) error {
if err := r.db.WithContext(ctx).
Model(&entities.NotificationRecord{}).
Where("id IN ?", recordIDs).
Update("is_read", true).Error; err != nil {
r.logger.Error("标记通知记录为已读失败",
zap.Strings("record_ids", recordIDs),
zap.Error(err),
)
return fmt.Errorf("标记通知记录为已读失败: %w", err)
}
r.logger.Info("通知记录标记为已读成功", zap.Strings("record_ids", recordIDs))
return nil
}
// MarkAllAsReadByUser 标记用户所有通知记录为已读
func (r *GormNotificationRecordRepository) MarkAllAsReadByUser(ctx context.Context, userID string) error {
if err := r.db.WithContext(ctx).
Model(&entities.NotificationRecord{}).
Where("user_id = ? AND is_read = ?", userID, false).
Update("is_read", true).Error; err != nil {
r.logger.Error("标记用户所有通知记录为已读失败",
zap.String("user_id", userID),
zap.Error(err),
)
return fmt.Errorf("标记用户所有通知记录为已读失败: %w", err)
}
r.logger.Info("用户所有通知记录标记为已读成功", zap.String("user_id", userID))
return nil
}