temp
This commit is contained in:
@@ -0,0 +1,370 @@
|
||||
package certification
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"tyapi-server/internal/domains/certification/entities"
|
||||
"tyapi-server/internal/domains/certification/enums"
|
||||
"tyapi-server/internal/domains/certification/repositories"
|
||||
"tyapi-server/internal/shared/database"
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
)
|
||||
|
||||
// ================ 常量定义 ================
|
||||
|
||||
const (
|
||||
// 表名常量
|
||||
CertificationsTable = "certifications"
|
||||
|
||||
// 缓存时间常量
|
||||
CacheTTLPrimaryQuery = 30 * time.Minute // 主键查询缓存时间
|
||||
CacheTTLBusinessQuery = 15 * time.Minute // 业务查询缓存时间
|
||||
CacheTTLUserQuery = 10 * time.Minute // 用户相关查询缓存时间
|
||||
CacheTTLWarmupLong = 30 * time.Minute // 预热长期缓存
|
||||
CacheTTLWarmupMedium = 15 * time.Minute // 预热中期缓存
|
||||
|
||||
// 缓存键模式常量
|
||||
CachePatternTable = "gorm_cache:certifications:*"
|
||||
CachePatternUser = "certification:user_id:*"
|
||||
)
|
||||
|
||||
// ================ Repository 实现 ================
|
||||
|
||||
// GormCertificationCommandRepository 认证命令仓储GORM实现
|
||||
//
|
||||
// 特性说明:
|
||||
// - 基于 CachedBaseRepositoryImpl 实现自动缓存管理
|
||||
// - 支持多级缓存策略(主键查询30分钟,业务查询15分钟)
|
||||
// - 自动缓存失效:写操作时自动清理相关缓存
|
||||
// - 智能缓存选择:根据查询复杂度自动选择缓存策略
|
||||
// - 内置监控支持:提供缓存统计和性能监控
|
||||
type GormCertificationCommandRepository struct {
|
||||
*database.CachedBaseRepositoryImpl
|
||||
}
|
||||
|
||||
// 编译时检查接口实现
|
||||
var _ repositories.CertificationCommandRepository = (*GormCertificationCommandRepository)(nil)
|
||||
|
||||
// NewGormCertificationCommandRepository 创建认证命令仓储
|
||||
//
|
||||
// 参数:
|
||||
// - db: GORM数据库连接实例
|
||||
// - logger: 日志记录器
|
||||
//
|
||||
// 返回:
|
||||
// - repositories.CertificationCommandRepository: 仓储接口实现
|
||||
func NewGormCertificationCommandRepository(db *gorm.DB, logger *zap.Logger) repositories.CertificationCommandRepository {
|
||||
return &GormCertificationCommandRepository{
|
||||
CachedBaseRepositoryImpl: database.NewCachedBaseRepositoryImpl(db, logger, CertificationsTable),
|
||||
}
|
||||
}
|
||||
|
||||
// ================ 基础CRUD操作 ================
|
||||
|
||||
// Create 创建认证
|
||||
//
|
||||
// 业务说明:
|
||||
// - 创建新的认证申请
|
||||
// - 自动触发相关缓存失效
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - cert: 认证实体
|
||||
//
|
||||
// 返回:
|
||||
// - error: 创建失败时的错误信息
|
||||
func (r *GormCertificationCommandRepository) Create(ctx context.Context, cert entities.Certification) error {
|
||||
r.GetLogger().Info("创建认证申请",
|
||||
zap.String("user_id", cert.UserID),
|
||||
zap.String("status", string(cert.Status)))
|
||||
|
||||
return r.CreateEntity(ctx, &cert)
|
||||
}
|
||||
|
||||
// Update 更新认证
|
||||
//
|
||||
// 缓存影响:
|
||||
// - GORM缓存插件会自动失效相关缓存
|
||||
// - 无需手动管理缓存一致性
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - cert: 认证实体
|
||||
//
|
||||
// 返回:
|
||||
// - error: 更新失败时的错误信息
|
||||
func (r *GormCertificationCommandRepository) Update(ctx context.Context, cert entities.Certification) error {
|
||||
r.GetLogger().Info("更新认证",
|
||||
zap.String("id", cert.ID),
|
||||
zap.String("status", string(cert.Status)))
|
||||
|
||||
return r.UpdateEntity(ctx, &cert)
|
||||
}
|
||||
|
||||
// Delete 删除认证
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - id: 认证ID
|
||||
//
|
||||
// 返回:
|
||||
// - error: 删除失败时的错误信息
|
||||
func (r *GormCertificationCommandRepository) Delete(ctx context.Context, id string) error {
|
||||
r.GetLogger().Info("删除认证", zap.String("id", id))
|
||||
return r.DeleteEntity(ctx, id, &entities.Certification{})
|
||||
}
|
||||
|
||||
// ================ 业务特定的更新操作 ================
|
||||
|
||||
// UpdateStatus 更新认证状态
|
||||
//
|
||||
// 业务说明:
|
||||
// - 更新认证的状态
|
||||
// - 自动更新时间戳
|
||||
//
|
||||
// 缓存影响:
|
||||
// - GORM缓存插件会自动失效表相关的缓存
|
||||
// - 状态更新会影响列表查询和统计结果
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - id: 认证ID
|
||||
// - status: 新状态
|
||||
//
|
||||
// 返回:
|
||||
// - error: 更新失败时的错误信息
|
||||
func (r *GormCertificationCommandRepository) UpdateStatus(ctx context.Context, id string, status enums.CertificationStatus) error {
|
||||
r.GetLogger().Info("更新认证状态",
|
||||
zap.String("id", id),
|
||||
zap.String("status", string(status)))
|
||||
|
||||
updates := map[string]interface{}{
|
||||
"status": status,
|
||||
"updated_at": time.Now(),
|
||||
}
|
||||
|
||||
return r.GetDB(ctx).Model(&entities.Certification{}).
|
||||
Where("id = ?", id).
|
||||
Updates(updates).Error
|
||||
}
|
||||
|
||||
// UpdateAuthFlowID 更新认证流程ID
|
||||
//
|
||||
// 业务说明:
|
||||
// - 记录e签宝企业认证流程ID
|
||||
// - 用于回调处理和状态跟踪
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - id: 认证ID
|
||||
// - authFlowID: 认证流程ID
|
||||
//
|
||||
// 返回:
|
||||
// - error: 更新失败时的错误信息
|
||||
func (r *GormCertificationCommandRepository) UpdateAuthFlowID(ctx context.Context, id string, authFlowID string) error {
|
||||
r.GetLogger().Info("更新认证流程ID",
|
||||
zap.String("id", id),
|
||||
zap.String("auth_flow_id", authFlowID))
|
||||
|
||||
updates := map[string]interface{}{
|
||||
"auth_flow_id": authFlowID,
|
||||
"updated_at": time.Now(),
|
||||
}
|
||||
|
||||
return r.GetDB(ctx).Model(&entities.Certification{}).
|
||||
Where("id = ?", id).
|
||||
Updates(updates).Error
|
||||
}
|
||||
|
||||
// UpdateContractInfo 更新合同信息
|
||||
//
|
||||
// 业务说明:
|
||||
// - 记录合同相关的ID和URL信息
|
||||
// - 用于合同管理和用户下载
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - id: 认证ID
|
||||
// - contractFileID: 合同文件ID
|
||||
// - esignFlowID: e签宝流程ID
|
||||
// - contractURL: 合同URL
|
||||
// - contractSignURL: 合同签署URL
|
||||
//
|
||||
// 返回:
|
||||
// - error: 更新失败时的错误信息
|
||||
func (r *GormCertificationCommandRepository) UpdateContractInfo(ctx context.Context, id string, contractFileID, esignFlowID, contractURL, contractSignURL string) error {
|
||||
r.GetLogger().Info("更新合同信息",
|
||||
zap.String("id", id),
|
||||
zap.String("contract_file_id", contractFileID),
|
||||
zap.String("esign_flow_id", esignFlowID))
|
||||
|
||||
updates := map[string]interface{}{
|
||||
"contract_file_id": contractFileID,
|
||||
"esign_flow_id": esignFlowID,
|
||||
"contract_url": contractURL,
|
||||
"contract_sign_url": contractSignURL,
|
||||
"updated_at": time.Now(),
|
||||
}
|
||||
|
||||
return r.GetDB(ctx).Model(&entities.Certification{}).
|
||||
Where("id = ?", id).
|
||||
Updates(updates).Error
|
||||
}
|
||||
|
||||
// UpdateFailureInfo 更新失败信息
|
||||
//
|
||||
// 业务说明:
|
||||
// - 记录认证失败的原因和详细信息
|
||||
// - 用于错误分析和用户提示
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - id: 认证ID
|
||||
// - reason: 失败原因
|
||||
// - message: 失败详细信息
|
||||
//
|
||||
// 返回:
|
||||
// - error: 更新失败时的错误信息
|
||||
func (r *GormCertificationCommandRepository) UpdateFailureInfo(ctx context.Context, id string, reason enums.FailureReason, message string) error {
|
||||
r.GetLogger().Info("更新失败信息",
|
||||
zap.String("id", id),
|
||||
zap.String("reason", string(reason)),
|
||||
zap.String("message", message))
|
||||
|
||||
updates := map[string]interface{}{
|
||||
"failure_reason": reason,
|
||||
"failure_message": message,
|
||||
"updated_at": time.Now(),
|
||||
}
|
||||
|
||||
return r.GetDB(ctx).Model(&entities.Certification{}).
|
||||
Where("id = ?", id).
|
||||
Updates(updates).Error
|
||||
}
|
||||
|
||||
// ================ 批量操作 ================
|
||||
|
||||
// BatchUpdateStatus 批量更新状态
|
||||
//
|
||||
// 业务说明:
|
||||
// - 批量更新多个认证的状态
|
||||
// - 适用于管理员批量操作
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - ids: 认证ID列表
|
||||
// - status: 新状态
|
||||
//
|
||||
// 返回:
|
||||
// - error: 更新失败时的错误信息
|
||||
func (r *GormCertificationCommandRepository) BatchUpdateStatus(ctx context.Context, ids []string, status enums.CertificationStatus) error {
|
||||
if len(ids) == 0 {
|
||||
return fmt.Errorf("批量更新状态:ID列表不能为空")
|
||||
}
|
||||
|
||||
r.GetLogger().Info("批量更新认证状态",
|
||||
zap.Strings("ids", ids),
|
||||
zap.String("status", string(status)))
|
||||
|
||||
updates := map[string]interface{}{
|
||||
"status": status,
|
||||
"updated_at": time.Now(),
|
||||
}
|
||||
|
||||
result := r.GetDB(ctx).Model(&entities.Certification{}).
|
||||
Where("id IN ?", ids).
|
||||
Updates(updates)
|
||||
|
||||
if result.Error != nil {
|
||||
return fmt.Errorf("批量更新认证状态失败: %w", result.Error)
|
||||
}
|
||||
|
||||
r.GetLogger().Info("批量更新完成", zap.Int64("affected_rows", result.RowsAffected))
|
||||
return nil
|
||||
}
|
||||
|
||||
// ================ 事务支持 ================
|
||||
|
||||
// WithTx 使用事务
|
||||
//
|
||||
// 业务说明:
|
||||
// - 返回支持事务的仓储实例
|
||||
// - 用于复杂业务操作的事务一致性保证
|
||||
//
|
||||
// 参数:
|
||||
// - tx: 事务对象
|
||||
//
|
||||
// 返回:
|
||||
// - repositories.CertificationCommandRepository: 支持事务的仓储实例
|
||||
func (r *GormCertificationCommandRepository) WithTx(tx interfaces.Transaction) repositories.CertificationCommandRepository {
|
||||
// 获取事务的底层*gorm.DB
|
||||
txDB := tx.GetDB()
|
||||
if gormDB, ok := txDB.(*gorm.DB); ok {
|
||||
return &GormCertificationCommandRepository{
|
||||
CachedBaseRepositoryImpl: database.NewCachedBaseRepositoryImpl(gormDB, r.GetLogger(), CertificationsTable),
|
||||
}
|
||||
}
|
||||
|
||||
r.GetLogger().Warn("不支持的事务类型,返回原始仓储")
|
||||
return r
|
||||
}
|
||||
|
||||
// ================ 缓存管理方法 ================
|
||||
|
||||
// WarmupCache 预热认证缓存
|
||||
//
|
||||
// 业务说明:
|
||||
// - 系统启动时预热常用查询的缓存
|
||||
// - 提升首次访问的响应速度
|
||||
//
|
||||
// 预热策略:
|
||||
// - 活跃认证:30分钟长期缓存
|
||||
// - 最近创建:15分钟中期缓存
|
||||
func (r *GormCertificationCommandRepository) WarmupCache(ctx context.Context) error {
|
||||
r.GetLogger().Info("开始预热认证缓存")
|
||||
|
||||
queries := []database.WarmupQuery{
|
||||
{
|
||||
Name: "active_certifications",
|
||||
TTL: CacheTTLWarmupLong,
|
||||
Dest: &[]entities.Certification{},
|
||||
},
|
||||
{
|
||||
Name: "recent_certifications",
|
||||
TTL: CacheTTLWarmupMedium,
|
||||
Dest: &[]entities.Certification{},
|
||||
},
|
||||
}
|
||||
|
||||
return r.WarmupCommonQueries(ctx, queries)
|
||||
}
|
||||
|
||||
// RefreshCache 刷新认证缓存
|
||||
//
|
||||
// 业务说明:
|
||||
// - 手动刷新认证相关的所有缓存
|
||||
// - 适用于数据迁移或批量更新后的缓存清理
|
||||
func (r *GormCertificationCommandRepository) RefreshCache(ctx context.Context) error {
|
||||
r.GetLogger().Info("刷新认证缓存")
|
||||
return r.CachedBaseRepositoryImpl.RefreshCache(ctx, CachePatternTable)
|
||||
}
|
||||
|
||||
// GetCacheStats 获取缓存统计信息
|
||||
//
|
||||
// 返回当前Repository的缓存使用统计,包括:
|
||||
// - 基础缓存信息(命中率、键数量等)
|
||||
// - 特定的缓存模式列表
|
||||
// - 性能指标
|
||||
func (r *GormCertificationCommandRepository) GetCacheStats() map[string]interface{} {
|
||||
stats := r.GetCacheInfo()
|
||||
stats["specific_patterns"] = []string{
|
||||
CachePatternTable,
|
||||
CachePatternUser,
|
||||
}
|
||||
return stats
|
||||
}
|
||||
@@ -0,0 +1,514 @@
|
||||
package certification
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"tyapi-server/internal/domains/certification/entities"
|
||||
"tyapi-server/internal/domains/certification/enums"
|
||||
"tyapi-server/internal/domains/certification/repositories"
|
||||
"tyapi-server/internal/domains/certification/repositories/queries"
|
||||
"tyapi-server/internal/shared/database"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// ================ 常量定义 ================
|
||||
|
||||
const (
|
||||
// 缓存时间常量
|
||||
QueryCacheTTLPrimaryQuery = 30 * time.Minute // 主键查询缓存时间
|
||||
QueryCacheTTLBusinessQuery = 15 * time.Minute // 业务查询缓存时间
|
||||
QueryCacheTTLUserQuery = 10 * time.Minute // 用户相关查询缓存时间
|
||||
QueryCacheTTLSearchQuery = 2 * time.Minute // 搜索查询缓存时间
|
||||
QueryCacheTTLActiveRecords = 5 * time.Minute // 活跃记录查询缓存时间
|
||||
QueryCacheTTLWarmupLong = 30 * time.Minute // 预热长期缓存
|
||||
QueryCacheTTLWarmupMedium = 15 * time.Minute // 预热中期缓存
|
||||
|
||||
// 缓存键模式常量
|
||||
QueryCachePatternTable = "gorm_cache:certifications:*"
|
||||
QueryCachePatternUser = "certification:user_id:*"
|
||||
)
|
||||
|
||||
// ================ Repository 实现 ================
|
||||
|
||||
// GormCertificationQueryRepository 认证查询仓储GORM实现
|
||||
//
|
||||
// 特性说明:
|
||||
// - 基于 CachedBaseRepositoryImpl 实现自动缓存管理
|
||||
// - 支持多级缓存策略(主键查询30分钟,业务查询15分钟,搜索2分钟)
|
||||
// - 自动缓存失效:写操作时自动清理相关缓存
|
||||
// - 智能缓存选择:根据查询复杂度自动选择缓存策略
|
||||
// - 内置监控支持:提供缓存统计和性能监控
|
||||
type GormCertificationQueryRepository struct {
|
||||
*database.CachedBaseRepositoryImpl
|
||||
}
|
||||
|
||||
// 编译时检查接口实现
|
||||
var _ repositories.CertificationQueryRepository = (*GormCertificationQueryRepository)(nil)
|
||||
|
||||
// NewGormCertificationQueryRepository 创建认证查询仓储
|
||||
//
|
||||
// 参数:
|
||||
// - db: GORM数据库连接实例
|
||||
// - logger: 日志记录器
|
||||
//
|
||||
// 返回:
|
||||
// - repositories.CertificationQueryRepository: 仓储接口实现
|
||||
func NewGormCertificationQueryRepository(
|
||||
db *gorm.DB,
|
||||
logger *zap.Logger,
|
||||
) repositories.CertificationQueryRepository {
|
||||
return &GormCertificationQueryRepository{
|
||||
CachedBaseRepositoryImpl: database.NewCachedBaseRepositoryImpl(db, logger, CertificationsTable),
|
||||
}
|
||||
}
|
||||
|
||||
// ================ 基础查询操作 ================
|
||||
|
||||
// GetByID 根据ID获取认证
|
||||
//
|
||||
// 缓存策略:
|
||||
// - 使用智能主键查询,自动缓存30分钟
|
||||
// - 主键查询命中率高,适合长期缓存
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - id: 认证ID
|
||||
//
|
||||
// 返回:
|
||||
// - *entities.Certification: 查询到的认证,未找到时返回nil
|
||||
// - error: 查询失败时的错误信息
|
||||
func (r *GormCertificationQueryRepository) GetByID(ctx context.Context, id string) (*entities.Certification, error) {
|
||||
var cert entities.Certification
|
||||
if err := r.SmartGetByID(ctx, id, &cert); err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, fmt.Errorf("认证记录不存在")
|
||||
}
|
||||
return nil, fmt.Errorf("查询认证记录失败: %w", err)
|
||||
}
|
||||
return &cert, nil
|
||||
}
|
||||
|
||||
// GetByUserID 根据用户ID获取认证
|
||||
//
|
||||
// 缓存策略:
|
||||
// - 业务查询,缓存15分钟
|
||||
// - 用户查询频率较高,适合中期缓存
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - userID: 用户ID
|
||||
//
|
||||
// 返回:
|
||||
// - *entities.Certification: 查询到的认证,未找到时返回nil
|
||||
// - error: 查询失败时的错误信息
|
||||
func (r *GormCertificationQueryRepository) GetByUserID(ctx context.Context, userID string) (*entities.Certification, error) {
|
||||
var cert entities.Certification
|
||||
err := r.SmartGetByField(ctx, &cert, "user_id", userID, QueryCacheTTLUserQuery)
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, fmt.Errorf("用户尚未创建认证申请")
|
||||
}
|
||||
return nil, fmt.Errorf("查询用户认证记录失败: %w", err)
|
||||
}
|
||||
return &cert, nil
|
||||
}
|
||||
|
||||
// Exists 检查认证是否存在
|
||||
func (r *GormCertificationQueryRepository) Exists(ctx context.Context, id string) (bool, error) {
|
||||
return r.ExistsEntity(ctx, id, &entities.Certification{})
|
||||
}
|
||||
|
||||
// ================ 列表查询 ================
|
||||
|
||||
// List 分页列表查询
|
||||
//
|
||||
// 缓存策略:
|
||||
// - 搜索查询:短期缓存2分钟(避免频繁数据库查询但保证实时性)
|
||||
// - 常规列表:智能缓存(根据查询复杂度自动选择缓存策略)
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - query: 列表查询条件
|
||||
//
|
||||
// 返回:
|
||||
// - []*entities.Certification: 查询结果列表
|
||||
// - int64: 总记录数
|
||||
// - error: 查询失败时的错误信息
|
||||
func (r *GormCertificationQueryRepository) List(ctx context.Context, query *queries.ListCertificationsQuery) ([]*entities.Certification, int64, error) {
|
||||
db := r.GetDB(ctx).Model(&entities.Certification{})
|
||||
|
||||
// 应用过滤条件
|
||||
if query.UserID != "" {
|
||||
db = db.Where("user_id = ?", query.UserID)
|
||||
}
|
||||
if query.Status != "" {
|
||||
db = db.Where("status = ?", query.Status)
|
||||
}
|
||||
if len(query.Statuses) > 0 {
|
||||
db = db.Where("status IN ?", query.Statuses)
|
||||
}
|
||||
|
||||
// 获取总数
|
||||
var total int64
|
||||
if err := db.Count(&total).Error; err != nil {
|
||||
return nil, 0, fmt.Errorf("查询认证总数失败: %w", err)
|
||||
}
|
||||
|
||||
// 应用排序和分页
|
||||
if query.SortBy != "" {
|
||||
orderClause := query.SortBy
|
||||
if query.SortOrder != "" {
|
||||
orderClause += " " + strings.ToUpper(query.SortOrder)
|
||||
}
|
||||
db = db.Order(orderClause)
|
||||
} else {
|
||||
db = db.Order("created_at DESC")
|
||||
}
|
||||
|
||||
offset := (query.Page - 1) * query.PageSize
|
||||
db = db.Offset(offset).Limit(query.PageSize)
|
||||
|
||||
// 执行查询
|
||||
var certifications []*entities.Certification
|
||||
if err := db.Find(&certifications).Error; err != nil {
|
||||
return nil, 0, fmt.Errorf("查询认证列表失败: %w", err)
|
||||
}
|
||||
|
||||
return certifications, total, nil
|
||||
}
|
||||
|
||||
// ListByUserIDs 根据用户ID列表查询
|
||||
func (r *GormCertificationQueryRepository) ListByUserIDs(ctx context.Context, userIDs []string) ([]*entities.Certification, error) {
|
||||
if len(userIDs) == 0 {
|
||||
return []*entities.Certification{}, nil
|
||||
}
|
||||
|
||||
var certifications []*entities.Certification
|
||||
if err := r.GetDB(ctx).Where("user_id IN ?", userIDs).Find(&certifications).Error; err != nil {
|
||||
return nil, fmt.Errorf("根据用户ID列表查询认证失败: %w", err)
|
||||
}
|
||||
|
||||
return certifications, nil
|
||||
}
|
||||
|
||||
// ListByStatus 根据状态查询
|
||||
func (r *GormCertificationQueryRepository) ListByStatus(ctx context.Context, status enums.CertificationStatus, limit int) ([]*entities.Certification, error) {
|
||||
db := r.GetDB(ctx).Where("status = ?", status)
|
||||
if limit > 0 {
|
||||
db = db.Limit(limit)
|
||||
}
|
||||
|
||||
var certifications []*entities.Certification
|
||||
if err := db.Find(&certifications).Error; err != nil {
|
||||
return nil, fmt.Errorf("根据状态查询认证失败: %w", err)
|
||||
}
|
||||
|
||||
return certifications, nil
|
||||
}
|
||||
|
||||
// ================ 业务查询 ================
|
||||
|
||||
// FindByAuthFlowID 根据认证流程ID查询
|
||||
//
|
||||
// 缓存策略:
|
||||
// - 业务查询,缓存15分钟
|
||||
// - 回调查询频率较高
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - authFlowID: 认证流程ID
|
||||
//
|
||||
// 返回:
|
||||
// - *entities.Certification: 查询到的认证,未找到时返回nil
|
||||
// - error: 查询失败时的错误信息
|
||||
func (r *GormCertificationQueryRepository) FindByAuthFlowID(ctx context.Context, authFlowID string) (*entities.Certification, error) {
|
||||
var cert entities.Certification
|
||||
err := r.SmartGetByField(ctx, &cert, "auth_flow_id", authFlowID, QueryCacheTTLBusinessQuery)
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, fmt.Errorf("认证流程不存在")
|
||||
}
|
||||
return nil, fmt.Errorf("根据认证流程ID查询失败: %w", err)
|
||||
}
|
||||
return &cert, nil
|
||||
}
|
||||
|
||||
// FindByEsignFlowID 根据e签宝流程ID查询
|
||||
//
|
||||
// 缓存策略:
|
||||
// - 业务查询,缓存15分钟
|
||||
// - 回调查询频率较高
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - esignFlowID: e签宝流程ID
|
||||
//
|
||||
// 返回:
|
||||
// - *entities.Certification: 查询到的认证,未找到时返回nil
|
||||
// - error: 查询失败时的错误信息
|
||||
func (r *GormCertificationQueryRepository) FindByEsignFlowID(ctx context.Context, esignFlowID string) (*entities.Certification, error) {
|
||||
var cert entities.Certification
|
||||
err := r.SmartGetByField(ctx, &cert, "esign_flow_id", esignFlowID, QueryCacheTTLBusinessQuery)
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, fmt.Errorf("e签宝流程不存在")
|
||||
}
|
||||
return nil, fmt.Errorf("根据e签宝流程ID查询失败: %w", err)
|
||||
}
|
||||
return &cert, nil
|
||||
}
|
||||
|
||||
// ListPendingRetry 查询待重试的认证
|
||||
//
|
||||
// 缓存策略:
|
||||
// - 管理查询,不缓存保证数据实时性
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - maxRetryCount: 最大重试次数
|
||||
//
|
||||
// 返回:
|
||||
// - []*entities.Certification: 待重试的认证列表
|
||||
// - error: 查询失败时的错误信息
|
||||
func (r *GormCertificationQueryRepository) ListPendingRetry(ctx context.Context, maxRetryCount int) ([]*entities.Certification, error) {
|
||||
var certifications []*entities.Certification
|
||||
err := r.WithoutCache().GetDB(ctx).
|
||||
Where("status IN ? AND retry_count < ?",
|
||||
[]enums.CertificationStatus{
|
||||
enums.StatusInfoRejected,
|
||||
enums.StatusContractRejected,
|
||||
enums.StatusContractExpired,
|
||||
},
|
||||
maxRetryCount).
|
||||
Order("created_at ASC").
|
||||
Find(&certifications).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询待重试认证失败: %w", err)
|
||||
}
|
||||
|
||||
return certifications, nil
|
||||
}
|
||||
|
||||
// GetPendingCertifications 获取待处理认证
|
||||
func (r *GormCertificationQueryRepository) GetPendingCertifications(ctx context.Context) ([]*entities.Certification, error) {
|
||||
var certifications []*entities.Certification
|
||||
err := r.WithoutCache().GetDB(ctx).
|
||||
Where("status IN ?", []enums.CertificationStatus{
|
||||
enums.StatusPending,
|
||||
enums.StatusInfoSubmitted,
|
||||
}).
|
||||
Order("created_at ASC").
|
||||
Find(&certifications).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询待处理认证失败: %w", err)
|
||||
}
|
||||
|
||||
return certifications, nil
|
||||
}
|
||||
|
||||
// GetExpiredContracts 获取过期合同
|
||||
func (r *GormCertificationQueryRepository) GetExpiredContracts(ctx context.Context) ([]*entities.Certification, error) {
|
||||
var certifications []*entities.Certification
|
||||
err := r.WithoutCache().GetDB(ctx).
|
||||
Where("status = ?", enums.StatusContractExpired).
|
||||
Order("updated_at DESC").
|
||||
Find(&certifications).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询过期合同失败: %w", err)
|
||||
}
|
||||
|
||||
return certifications, nil
|
||||
}
|
||||
|
||||
// GetCertificationsByDateRange 根据日期范围获取认证
|
||||
func (r *GormCertificationQueryRepository) GetCertificationsByDateRange(ctx context.Context, startDate, endDate time.Time) ([]*entities.Certification, error) {
|
||||
var certifications []*entities.Certification
|
||||
err := r.GetDB(ctx).
|
||||
Where("created_at BETWEEN ? AND ?", startDate, endDate).
|
||||
Order("created_at DESC").
|
||||
Find(&certifications).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("根据日期范围查询认证失败: %w", err)
|
||||
}
|
||||
|
||||
return certifications, nil
|
||||
}
|
||||
|
||||
// GetUserActiveCertification 获取用户当前活跃认证
|
||||
func (r *GormCertificationQueryRepository) GetUserActiveCertification(ctx context.Context, userID string) (*entities.Certification, error) {
|
||||
var cert entities.Certification
|
||||
err := r.GetDB(ctx).
|
||||
Where("user_id = ? AND status NOT IN ?", userID, []enums.CertificationStatus{
|
||||
enums.StatusContractSigned,
|
||||
enums.StatusInfoRejected,
|
||||
enums.StatusContractRejected,
|
||||
enums.StatusContractExpired,
|
||||
}).
|
||||
First(&cert).Error
|
||||
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, fmt.Errorf("用户没有活跃的认证申请")
|
||||
}
|
||||
return nil, fmt.Errorf("查询用户活跃认证失败: %w", err)
|
||||
}
|
||||
|
||||
return &cert, nil
|
||||
}
|
||||
|
||||
// ================ 统计查询 ================
|
||||
|
||||
// GetStatistics 获取统计数据
|
||||
func (r *GormCertificationQueryRepository) GetStatistics(ctx context.Context, period repositories.CertificationTimePeriod) (*repositories.CertificationStatistics, error) {
|
||||
now := time.Now()
|
||||
var startDate time.Time
|
||||
|
||||
switch period {
|
||||
case repositories.PeriodDaily:
|
||||
startDate = now.AddDate(0, 0, -1)
|
||||
case repositories.PeriodWeekly:
|
||||
startDate = now.AddDate(0, 0, -7)
|
||||
case repositories.PeriodMonthly:
|
||||
startDate = now.AddDate(0, -1, 0)
|
||||
case repositories.PeriodYearly:
|
||||
startDate = now.AddDate(-1, 0, 0)
|
||||
default:
|
||||
startDate = now.AddDate(0, 0, -7)
|
||||
}
|
||||
|
||||
// 使用短期缓存进行统计查询
|
||||
var totalCount int64
|
||||
r.WithShortCache().GetDB(ctx).Model(&entities.Certification{}).
|
||||
Where("created_at BETWEEN ? AND ?", startDate, now).
|
||||
Count(&totalCount)
|
||||
|
||||
var completedCount int64
|
||||
r.WithShortCache().GetDB(ctx).Model(&entities.Certification{}).
|
||||
Where("created_at BETWEEN ? AND ? AND status = ?", startDate, now, enums.StatusContractSigned).
|
||||
Count(&completedCount)
|
||||
|
||||
successRate := float64(0)
|
||||
if totalCount > 0 {
|
||||
successRate = float64(completedCount) / float64(totalCount)
|
||||
}
|
||||
|
||||
return &repositories.CertificationStatistics{
|
||||
Period: period,
|
||||
StartDate: startDate,
|
||||
EndDate: now,
|
||||
TotalCertifications: totalCount,
|
||||
CompletedCount: completedCount,
|
||||
SuccessRate: successRate,
|
||||
StatusDistribution: make(map[enums.CertificationStatus]int64),
|
||||
FailureDistribution: make(map[enums.FailureReason]int64),
|
||||
AvgProcessingTime: 24 * time.Hour, // 简化实现
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CountByStatus 按状态统计
|
||||
func (r *GormCertificationQueryRepository) CountByStatus(ctx context.Context, status enums.CertificationStatus) (int64, error) {
|
||||
var count int64
|
||||
if err := r.WithShortCache().GetDB(ctx).Model(&entities.Certification{}).Where("status = ?", status).Count(&count).Error; err != nil {
|
||||
return 0, fmt.Errorf("按状态统计认证失败: %w", err)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// CountByFailureReason 按失败原因统计
|
||||
func (r *GormCertificationQueryRepository) CountByFailureReason(ctx context.Context, reason enums.FailureReason) (int64, error) {
|
||||
var count int64
|
||||
if err := r.WithShortCache().GetDB(ctx).Model(&entities.Certification{}).Where("failure_reason = ?", reason).Count(&count).Error; err != nil {
|
||||
return 0, fmt.Errorf("按失败原因统计认证失败: %w", err)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// GetProgressStatistics 获取进度统计
|
||||
func (r *GormCertificationQueryRepository) GetProgressStatistics(ctx context.Context) (*repositories.CertificationProgressStats, error) {
|
||||
// 简化实现
|
||||
return &repositories.CertificationProgressStats{
|
||||
StatusProgress: make(map[enums.CertificationStatus]int64),
|
||||
ProgressDistribution: make(map[int]int64),
|
||||
StageTimeStats: make(map[string]*repositories.CertificationStageTimeInfo),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SearchByCompanyName 按公司名搜索
|
||||
func (r *GormCertificationQueryRepository) SearchByCompanyName(ctx context.Context, companyName string, limit int) ([]*entities.Certification, error) {
|
||||
// 简化实现,暂时返回空结果
|
||||
r.GetLogger().Warn("按公司名搜索功能待实现,需要企业信息服务支持")
|
||||
return []*entities.Certification{}, nil
|
||||
}
|
||||
|
||||
// SearchByLegalPerson 按法人搜索
|
||||
func (r *GormCertificationQueryRepository) SearchByLegalPerson(ctx context.Context, legalPersonName string, limit int) ([]*entities.Certification, error) {
|
||||
// 简化实现,暂时返回空结果
|
||||
r.GetLogger().Warn("按法人搜索功能待实现,需要企业信息服务支持")
|
||||
return []*entities.Certification{}, nil
|
||||
}
|
||||
|
||||
// InvalidateCache 清除缓存
|
||||
func (r *GormCertificationQueryRepository) InvalidateCache(ctx context.Context, keys ...string) error {
|
||||
// 简化实现,暂不处理缓存
|
||||
return nil
|
||||
}
|
||||
|
||||
// RefreshCache 刷新缓存
|
||||
func (r *GormCertificationQueryRepository) RefreshCache(ctx context.Context, certificationID string) error {
|
||||
// 简化实现,暂不处理缓存
|
||||
return nil
|
||||
}
|
||||
|
||||
// ================ 缓存管理方法 ================
|
||||
|
||||
// WarmupCache 预热认证查询缓存
|
||||
//
|
||||
// 业务说明:
|
||||
// - 系统启动时预热常用查询的缓存
|
||||
// - 提升首次访问的响应速度
|
||||
//
|
||||
// 预热策略:
|
||||
// - 活跃认证:30分钟长期缓存
|
||||
// - 待处理认证:15分钟中期缓存
|
||||
func (r *GormCertificationQueryRepository) WarmupCache(ctx context.Context) error {
|
||||
r.GetLogger().Info("开始预热认证查询缓存")
|
||||
|
||||
queries := []database.WarmupQuery{
|
||||
{
|
||||
Name: "active_certifications",
|
||||
TTL: QueryCacheTTLWarmupLong,
|
||||
Dest: &[]entities.Certification{},
|
||||
},
|
||||
{
|
||||
Name: "pending_certifications",
|
||||
TTL: QueryCacheTTLWarmupMedium,
|
||||
Dest: &[]entities.Certification{},
|
||||
},
|
||||
}
|
||||
|
||||
return r.WarmupCommonQueries(ctx, queries)
|
||||
}
|
||||
|
||||
// GetCacheStats 获取缓存统计信息
|
||||
//
|
||||
// 返回当前Repository的缓存使用统计,包括:
|
||||
// - 基础缓存信息(命中率、键数量等)
|
||||
// - 特定的缓存模式列表
|
||||
// - 性能指标
|
||||
func (r *GormCertificationQueryRepository) GetCacheStats() map[string]interface{} {
|
||||
stats := r.GetCacheInfo()
|
||||
stats["specific_patterns"] = []string{
|
||||
QueryCachePatternTable,
|
||||
QueryCachePatternUser,
|
||||
}
|
||||
return stats
|
||||
}
|
||||
@@ -1,370 +0,0 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"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
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return entities.Certification{}, gorm.ErrRecordNotFound
|
||||
}
|
||||
return entities.Certification{}, err
|
||||
}
|
||||
return cert, err
|
||||
}
|
||||
|
||||
// GetByAuthFlowID 根据认证流程ID获取认证申请
|
||||
func (r *GormCertificationRepository) GetByAuthFlowID(ctx context.Context, authFlowID string) (entities.Certification, error) {
|
||||
var cert entities.Certification
|
||||
err := r.db.WithContext(ctx).Where("auth_flow_id = ?", authFlowID).First(&cert).Error
|
||||
return cert, err
|
||||
}
|
||||
|
||||
// GetByEsignFlowID 根据签署流程ID获取认证申请
|
||||
func (r *GormCertificationRepository) GetByEsignFlowID(ctx context.Context, esignFlowID string) (entities.Certification, error) {
|
||||
var cert entities.Certification
|
||||
err := r.db.WithContext(ctx).Where("esign_flow_id = ?", esignFlowID).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.StartDate != "" {
|
||||
dbQuery = dbQuery.Where("created_at >= ?", query.StartDate)
|
||||
}
|
||||
if query.EndDate != "" {
|
||||
dbQuery = dbQuery.Where("created_at <= ?", query.EndDate)
|
||||
}
|
||||
if query.EnterpriseName != "" {
|
||||
// 简化企业名称查询,暂时不关联企业表
|
||||
dbQuery = dbQuery.Where("user_id IN (SELECT user_id FROM enterprise_infos WHERE company_name LIKE ?)", "%"+query.EnterpriseName+"%")
|
||||
}
|
||||
|
||||
// 统计总数
|
||||
if err := dbQuery.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 应用分页
|
||||
if query.Page > 0 && query.PageSize > 0 {
|
||||
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
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
var result []*entities.Certification
|
||||
for i := range certs {
|
||||
result = append(result, &certs[i])
|
||||
}
|
||||
|
||||
return result, 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 {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, gorm.ErrRecordNotFound
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
var result []*entities.Certification
|
||||
for i := range certs {
|
||||
result = append(result, &certs[i])
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// UpdateStatus 更新认证状态
|
||||
func (r *GormCertificationRepository) UpdateStatus(ctx context.Context, certificationID string, status string) error {
|
||||
r.logger.Info("更新认证状态",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.String("status", status),
|
||||
)
|
||||
|
||||
updates := map[string]interface{}{
|
||||
"status": status,
|
||||
"updated_at": time.Now(),
|
||||
}
|
||||
|
||||
// 根据状态更新时间戳
|
||||
switch status {
|
||||
case "info_submitted":
|
||||
updates["info_submitted_at"] = time.Now()
|
||||
case "enterprise_verified":
|
||||
updates["enterprise_verified_at"] = time.Now()
|
||||
case "contract_applied":
|
||||
updates["contract_applied_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, "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 = ?", "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
|
||||
}
|
||||
|
||||
// 今日提交数
|
||||
today := time.Now().Format("2006-01-02")
|
||||
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).
|
||||
Where("DATE(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 ?", "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
|
||||
}
|
||||
|
||||
// 今日提交数
|
||||
today := time.Now().Format("2006-01-02")
|
||||
if err := r.db.WithContext(ctx).Model(&entities.Certification{}).
|
||||
Where("DATE(created_at) = ?", today).
|
||||
Count(&stats.TodaySubmissions).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &stats, nil
|
||||
}
|
||||
@@ -1,596 +0,0 @@
|
||||
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/database"
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
)
|
||||
|
||||
// ================ 常量定义 ================
|
||||
|
||||
const (
|
||||
// 表名常量
|
||||
EnterpriseInfoSubmitRecordsTable = "enterprise_info_submit_records"
|
||||
|
||||
// 缓存时间常量
|
||||
CacheTTLPrimaryQuery = 30 * time.Minute // 主键查询缓存时间
|
||||
CacheTTLBusinessQuery = 15 * time.Minute // 业务查询缓存时间
|
||||
CacheTTLUserQuery = 10 * time.Minute // 用户相关查询缓存时间
|
||||
CacheTTLSearchQuery = 2 * time.Minute // 搜索查询缓存时间
|
||||
CacheTTLActiveRecords = 5 * time.Minute // 活跃记录查询缓存时间
|
||||
CacheTTLWarmupLong = 30 * time.Minute // 预热长期缓存
|
||||
CacheTTLWarmupMedium = 15 * time.Minute // 预热中期缓存
|
||||
|
||||
// 缓存键模式常量
|
||||
CachePatternTable = "gorm_cache:enterprise_info_submit_records:*"
|
||||
CachePatternCertification = "enterprise_info:certification_id:*"
|
||||
CachePatternUser = "enterprise_info:user_id:*"
|
||||
|
||||
// 业务常量
|
||||
StatusActive = "active"
|
||||
StatusPending = "pending"
|
||||
)
|
||||
|
||||
// ================ Repository 实现 ================
|
||||
|
||||
// GormEnterpriseInfoSubmitRecordRepository 企业信息提交记录GORM仓储实现
|
||||
//
|
||||
// 特性说明:
|
||||
// - 基于 CachedBaseRepositoryImpl 实现自动缓存管理
|
||||
// - 支持多级缓存策略(主键查询30分钟,业务查询15分钟,搜索2分钟)
|
||||
// - 自动缓存失效:写操作时自动清理相关缓存
|
||||
// - 智能缓存选择:根据查询复杂度自动选择缓存策略
|
||||
// - 内置监控支持:提供缓存统计和性能监控
|
||||
type GormEnterpriseInfoSubmitRecordRepository struct {
|
||||
*database.CachedBaseRepositoryImpl
|
||||
}
|
||||
|
||||
// 编译时检查接口实现
|
||||
var _ repositories.EnterpriseInfoSubmitRecordRepository = (*GormEnterpriseInfoSubmitRecordRepository)(nil)
|
||||
|
||||
// NewGormEnterpriseInfoSubmitRecordRepository 创建企业信息提交记录GORM仓储
|
||||
//
|
||||
// 参数:
|
||||
// - db: GORM数据库连接实例
|
||||
// - logger: 日志记录器
|
||||
//
|
||||
// 返回:
|
||||
// - repositories.EnterpriseInfoSubmitRecordRepository: 仓储接口实现
|
||||
func NewGormEnterpriseInfoSubmitRecordRepository(db *gorm.DB, logger *zap.Logger) repositories.EnterpriseInfoSubmitRecordRepository {
|
||||
return &GormEnterpriseInfoSubmitRecordRepository{
|
||||
CachedBaseRepositoryImpl: database.NewCachedBaseRepositoryImpl(db, logger, EnterpriseInfoSubmitRecordsTable),
|
||||
}
|
||||
}
|
||||
|
||||
// ================ Repository[T] 接口实现 ================
|
||||
|
||||
// Create 创建企业信息提交记录
|
||||
//
|
||||
// 业务说明:
|
||||
// - 创建新的企业信息提交记录
|
||||
// - 自动触发相关缓存失效
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - record: 要创建的记录实体
|
||||
//
|
||||
// 返回:
|
||||
// - entities.EnterpriseInfoSubmitRecord: 创建后的记录(包含生成的ID)
|
||||
// - error: 创建失败时的错误信息
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) Create(ctx context.Context, record entities.EnterpriseInfoSubmitRecord) (entities.EnterpriseInfoSubmitRecord, error) {
|
||||
r.GetLogger().Info("创建企业信息提交记录",
|
||||
zap.String("user_id", record.UserID),
|
||||
zap.String("company_name", record.CompanyName))
|
||||
|
||||
err := r.CreateEntity(ctx, &record)
|
||||
return record, err
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取企业信息提交记录
|
||||
//
|
||||
// 缓存策略:
|
||||
// - 使用智能主键查询,自动缓存30分钟
|
||||
// - 主键查询命中率高,适合长期缓存
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - id: 记录ID
|
||||
//
|
||||
// 返回:
|
||||
// - entities.EnterpriseInfoSubmitRecord: 查询到的记录
|
||||
// - error: 查询失败或记录不存在时的错误
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) GetByID(ctx context.Context, id string) (entities.EnterpriseInfoSubmitRecord, error) {
|
||||
var record entities.EnterpriseInfoSubmitRecord
|
||||
err := r.SmartGetByID(ctx, id, &record)
|
||||
return record, err
|
||||
}
|
||||
|
||||
// Update 更新企业信息提交记录
|
||||
//
|
||||
// 缓存影响:
|
||||
// - GORM缓存插件会自动失效相关缓存
|
||||
// - 无需手动管理缓存一致性
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - record: 要更新的记录实体
|
||||
//
|
||||
// 返回:
|
||||
// - error: 更新失败时的错误信息
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) Update(ctx context.Context, record entities.EnterpriseInfoSubmitRecord) error {
|
||||
r.GetLogger().Info("更新企业信息提交记录",
|
||||
zap.String("id", record.ID),
|
||||
zap.String("company_name", record.CompanyName))
|
||||
|
||||
return r.UpdateEntity(ctx, &record)
|
||||
}
|
||||
|
||||
// CreateBatch 批量创建企业信息提交记录
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) CreateBatch(ctx context.Context, records []entities.EnterpriseInfoSubmitRecord) error {
|
||||
r.GetLogger().Info("批量创建企业信息提交记录", zap.Int("count", len(records)))
|
||||
return r.CreateBatchEntity(ctx, &records)
|
||||
}
|
||||
|
||||
// GetByIDs 根据ID列表获取企业信息提交记录
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.EnterpriseInfoSubmitRecord, error) {
|
||||
var records []entities.EnterpriseInfoSubmitRecord
|
||||
err := r.GetEntitiesByIDs(ctx, ids, &records)
|
||||
return records, err
|
||||
}
|
||||
|
||||
// UpdateBatch 批量更新企业信息提交记录
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) UpdateBatch(ctx context.Context, records []entities.EnterpriseInfoSubmitRecord) error {
|
||||
r.GetLogger().Info("批量更新企业信息提交记录", zap.Int("count", len(records)))
|
||||
return r.UpdateBatchEntity(ctx, &records)
|
||||
}
|
||||
|
||||
// DeleteBatch 批量删除企业信息提交记录
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) DeleteBatch(ctx context.Context, ids []string) error {
|
||||
r.GetLogger().Info("批量删除企业信息提交记录", zap.Strings("ids", ids))
|
||||
return r.DeleteBatchEntity(ctx, ids, &entities.EnterpriseInfoSubmitRecord{})
|
||||
}
|
||||
|
||||
// List 获取企业信息提交记录列表
|
||||
//
|
||||
// 缓存策略:
|
||||
// - 搜索查询:短期缓存2分钟(避免频繁数据库查询但保证实时性)
|
||||
// - 常规列表:智能缓存(根据查询复杂度自动选择缓存策略)
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - options: 列表查询选项(分页、排序、筛选、搜索等)
|
||||
//
|
||||
// 返回:
|
||||
// - []entities.EnterpriseInfoSubmitRecord: 查询结果列表
|
||||
// - error: 查询失败时的错误信息
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.EnterpriseInfoSubmitRecord, error) {
|
||||
var records []entities.EnterpriseInfoSubmitRecord
|
||||
|
||||
// 搜索查询:使用短期缓存避免频繁数据库查询
|
||||
if options.Search != "" {
|
||||
return r.handleSearchQuery(ctx, options)
|
||||
}
|
||||
|
||||
// 常规列表:使用智能缓存策略
|
||||
err := r.SmartList(ctx, &records, options)
|
||||
return records, err
|
||||
}
|
||||
|
||||
// ================ BaseRepository 接口实现 ================
|
||||
|
||||
// Delete 删除企业信息提交记录
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) Delete(ctx context.Context, id string) error {
|
||||
return r.DeleteEntity(ctx, id, &entities.EnterpriseInfoSubmitRecord{})
|
||||
}
|
||||
|
||||
// Exists 检查企业信息提交记录是否存在
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) Exists(ctx context.Context, id string) (bool, error) {
|
||||
return r.ExistsEntity(ctx, id, &entities.EnterpriseInfoSubmitRecord{})
|
||||
}
|
||||
|
||||
// Count 统计企业信息提交记录数量
|
||||
//
|
||||
// 缓存策略:
|
||||
// - 搜索统计:使用自定义搜索逻辑,不缓存保证准确性
|
||||
// - 常规统计:使用基础实现的缓存策略
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
|
||||
if options.Search != "" {
|
||||
return r.CountWhere(ctx, &entities.EnterpriseInfoSubmitRecord{},
|
||||
"company_name LIKE ? OR unified_social_code LIKE ? OR legal_person_name LIKE ?",
|
||||
"%"+options.Search+"%", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
}
|
||||
return r.CountWithOptions(ctx, &entities.EnterpriseInfoSubmitRecord{}, options)
|
||||
}
|
||||
|
||||
// SoftDelete 软删除企业信息提交记录
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) SoftDelete(ctx context.Context, id string) error {
|
||||
return r.SoftDeleteEntity(ctx, id, &entities.EnterpriseInfoSubmitRecord{})
|
||||
}
|
||||
|
||||
// Restore 恢复企业信息提交记录
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) Restore(ctx context.Context, id string) error {
|
||||
return r.RestoreEntity(ctx, id, &entities.EnterpriseInfoSubmitRecord{})
|
||||
}
|
||||
|
||||
// ================ 业务专用查询方法 ================
|
||||
|
||||
// GetByCertificationID 根据认证ID获取企业信息提交记录
|
||||
//
|
||||
// 业务说明:
|
||||
// - 每个认证流程对应一个企业信息提交记录
|
||||
// - 适用于认证流程中查询企业信息
|
||||
//
|
||||
// 缓存策略:
|
||||
// - 业务查询,缓存15分钟
|
||||
// - 认证ID查询频率较高,适合中期缓存
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - certificationID: 认证流程ID
|
||||
//
|
||||
// 返回:
|
||||
// - *entities.EnterpriseInfoSubmitRecord: 查询到的记录,未找到时返回nil
|
||||
// - error: 查询失败时的错误信息
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) GetByCertificationID(ctx context.Context, certificationID string) (*entities.EnterpriseInfoSubmitRecord, error) {
|
||||
var record entities.EnterpriseInfoSubmitRecord
|
||||
err := r.SmartGetByField(ctx, &record, "certification_id", certificationID, CacheTTLBusinessQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
// GetByUserID 根据用户ID获取企业信息提交记录列表
|
||||
//
|
||||
// 业务说明:
|
||||
// - 获取某用户的所有企业信息提交记录
|
||||
// - 按创建时间倒序排列,最新的在前
|
||||
//
|
||||
// 缓存策略:
|
||||
// - 用户相关查询,使用中期缓存10分钟
|
||||
// - 用户查询频率中等,适合中期缓存
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - userID: 用户ID
|
||||
//
|
||||
// 返回:
|
||||
// - []*entities.EnterpriseInfoSubmitRecord: 查询结果列表
|
||||
// - error: 查询失败时的错误信息
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) GetByUserID(ctx context.Context, userID string) ([]*entities.EnterpriseInfoSubmitRecord, error) {
|
||||
var records []*entities.EnterpriseInfoSubmitRecord
|
||||
|
||||
err := r.WithMediumCache().GetDB(ctx).
|
||||
Where("user_id = ?", userID).
|
||||
Order("created_at DESC").
|
||||
Find(&records).Error
|
||||
|
||||
return records, err
|
||||
}
|
||||
|
||||
// GetLatestByUserID 根据用户ID获取最新的企业信息提交记录
|
||||
//
|
||||
// 业务说明:
|
||||
// - 获取用户最新提交的企业信息记录
|
||||
// - 适用于用户中心显示最新提交状态
|
||||
//
|
||||
// 缓存策略:
|
||||
// - 最新记录查询,缓存15分钟
|
||||
// - 用户中心访问频率较高
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) GetLatestByUserID(ctx context.Context, userID string) (*entities.EnterpriseInfoSubmitRecord, error) {
|
||||
var record entities.EnterpriseInfoSubmitRecord
|
||||
err := r.GetDB(ctx).
|
||||
Where("user_id = ?", userID).
|
||||
Order("created_at DESC").
|
||||
First(&record).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
// ================ 业务状态管理方法 ================
|
||||
|
||||
// UpdateStatus 更新企业信息提交记录状态
|
||||
//
|
||||
// 业务说明:
|
||||
// - 更新记录的审核状态和备注信息
|
||||
// - 适用于管理员审核流程
|
||||
//
|
||||
// 缓存影响:
|
||||
// - GORM缓存插件会自动失效表相关的缓存
|
||||
// - 状态更新会影响列表查询和统计结果
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - recordID: 记录ID
|
||||
// - status: 新状态
|
||||
// - reason: 状态变更原因或备注
|
||||
//
|
||||
// 返回:
|
||||
// - error: 更新失败时的错误信息
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) UpdateStatus(ctx context.Context, recordID string, status string, reason string) error {
|
||||
r.GetLogger().Info("更新企业信息提交记录状态",
|
||||
zap.String("record_id", recordID),
|
||||
zap.String("status", status),
|
||||
zap.String("reason", reason))
|
||||
|
||||
updates := map[string]interface{}{
|
||||
"status": status,
|
||||
"updated_at": time.Now(),
|
||||
}
|
||||
|
||||
if reason != "" {
|
||||
updates["reason"] = reason
|
||||
}
|
||||
|
||||
return r.GetDB(ctx).Model(&entities.EnterpriseInfoSubmitRecord{}).
|
||||
Where("id = ?", recordID).
|
||||
Updates(updates).Error
|
||||
}
|
||||
|
||||
// ================ 高级查询方法 ================
|
||||
|
||||
// ListRecords 获取企业信息提交记录列表(带分页和高级筛选)
|
||||
//
|
||||
// 业务说明:
|
||||
// - 管理员后台的高级查询接口
|
||||
// - 支持多维度筛选和分页
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - query: 高级查询条件
|
||||
//
|
||||
// 返回:
|
||||
// - []*entities.EnterpriseInfoSubmitRecord: 查询结果
|
||||
// - int64: 总记录数
|
||||
// - error: 查询失败时的错误
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) ListRecords(ctx context.Context, query *queries.ListEnterpriseInfoSubmitRecordsQuery) ([]*entities.EnterpriseInfoSubmitRecord, int64, error) {
|
||||
var records []*entities.EnterpriseInfoSubmitRecord
|
||||
var total int64
|
||||
|
||||
dbQuery := r.GetDB(ctx).Model(&entities.EnterpriseInfoSubmitRecord{})
|
||||
|
||||
// 构建查询条件
|
||||
dbQuery = r.buildQueryConditions(dbQuery, query)
|
||||
|
||||
// 统计总数
|
||||
if err := dbQuery.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 应用分页和排序
|
||||
dbQuery = r.applyPaginationAndSorting(dbQuery, query)
|
||||
|
||||
// 查询数据
|
||||
if err := dbQuery.Find(&records).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return records, total, nil
|
||||
}
|
||||
|
||||
// ================ 缓存管理方法 ================
|
||||
|
||||
// GetActiveRecords 获取活跃记录
|
||||
//
|
||||
// 业务说明:
|
||||
// - 获取状态为活跃的企业信息提交记录
|
||||
// - 适用于仪表板统计
|
||||
//
|
||||
// 缓存策略:
|
||||
// - 活跃记录查询使用短期缓存5分钟
|
||||
// - 活跃状态变化较频繁,使用短期缓存
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) GetActiveRecords(ctx context.Context) ([]entities.EnterpriseInfoSubmitRecord, error) {
|
||||
var records []entities.EnterpriseInfoSubmitRecord
|
||||
err := r.WithShortCache().FindWithCache(ctx, &records, CacheTTLActiveRecords, "status = ?", StatusActive)
|
||||
return records, err
|
||||
}
|
||||
|
||||
// GetPendingRecords 获取待审核记录
|
||||
//
|
||||
// 业务说明:
|
||||
// - 获取待审核的企业信息提交记录
|
||||
// - 适用于管理员工作台
|
||||
//
|
||||
// 缓存策略:
|
||||
// - 禁用缓存,保证数据实时性
|
||||
// - 待审核状态需要实时准确的数据
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) GetPendingRecords(ctx context.Context) ([]entities.EnterpriseInfoSubmitRecord, error) {
|
||||
var records []entities.EnterpriseInfoSubmitRecord
|
||||
|
||||
db := r.WithoutCache().GetDB(ctx)
|
||||
err := db.Where("status = ?", StatusPending).
|
||||
Order("created_at ASC").
|
||||
Find(&records).Error
|
||||
|
||||
return records, err
|
||||
}
|
||||
|
||||
// WarmupCache 预热企业信息提交记录缓存
|
||||
//
|
||||
// 业务说明:
|
||||
// - 系统启动时预热常用查询的缓存
|
||||
// - 提升首次访问的响应速度
|
||||
//
|
||||
// 预热策略:
|
||||
// - 活跃记录:30分钟长期缓存
|
||||
// - 最近提交:15分钟中期缓存
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) WarmupCache(ctx context.Context) error {
|
||||
r.GetLogger().Info("开始预热企业信息提交记录缓存")
|
||||
|
||||
queries := []database.WarmupQuery{
|
||||
{
|
||||
Name: "active_records",
|
||||
TTL: CacheTTLWarmupLong,
|
||||
Dest: &[]entities.EnterpriseInfoSubmitRecord{},
|
||||
},
|
||||
{
|
||||
Name: "recent_submissions",
|
||||
TTL: CacheTTLWarmupMedium,
|
||||
Dest: &[]entities.EnterpriseInfoSubmitRecord{},
|
||||
},
|
||||
}
|
||||
|
||||
return r.WarmupCommonQueries(ctx, queries)
|
||||
}
|
||||
|
||||
// RefreshRecordCache 刷新记录缓存
|
||||
//
|
||||
// 业务说明:
|
||||
// - 手动刷新企业信息提交记录相关的所有缓存
|
||||
// - 适用于数据迁移或批量更新后的缓存清理
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) RefreshRecordCache(ctx context.Context) error {
|
||||
r.GetLogger().Info("刷新企业信息提交记录缓存")
|
||||
return r.RefreshCache(ctx, CachePatternTable)
|
||||
}
|
||||
|
||||
// GetCacheStats 获取缓存统计信息
|
||||
//
|
||||
// 返回当前Repository的缓存使用统计,包括:
|
||||
// - 基础缓存信息(命中率、键数量等)
|
||||
// - 特定的缓存模式列表
|
||||
// - 性能指标
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) GetCacheStats() map[string]interface{} {
|
||||
stats := r.GetCacheInfo()
|
||||
stats["specific_patterns"] = []string{
|
||||
CachePatternTable,
|
||||
CachePatternCertification,
|
||||
CachePatternUser,
|
||||
}
|
||||
return stats
|
||||
}
|
||||
|
||||
// ================ 私有辅助方法 ================
|
||||
|
||||
// handleSearchQuery 处理搜索查询
|
||||
//
|
||||
// 业务逻辑:
|
||||
// - 支持按企业名称、统一社会信用代码、法定代表人姓名搜索
|
||||
// - 使用短期缓存避免频繁数据库查询
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - options: 查询选项
|
||||
//
|
||||
// 返回:
|
||||
// - []entities.EnterpriseInfoSubmitRecord: 搜索结果
|
||||
// - error: 查询失败时的错误
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) handleSearchQuery(ctx context.Context, options interfaces.ListOptions) ([]entities.EnterpriseInfoSubmitRecord, error) {
|
||||
var records []entities.EnterpriseInfoSubmitRecord
|
||||
|
||||
db := r.GetDB(ctx).
|
||||
Set("cache:enabled", true).
|
||||
Set("cache:ttl", CacheTTLSearchQuery).
|
||||
Model(&entities.EnterpriseInfoSubmitRecord{})
|
||||
|
||||
// 应用筛选条件
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
db = db.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
// 企业信息特定的搜索逻辑
|
||||
db = db.Where("company_name LIKE ? OR unified_social_code LIKE ? OR legal_person_name LIKE ?",
|
||||
"%"+options.Search+"%", "%"+options.Search+"%", "%"+options.Search+"%")
|
||||
|
||||
// 应用预加载
|
||||
for _, include := range options.Include {
|
||||
db = db.Preload(include)
|
||||
}
|
||||
|
||||
// 应用排序
|
||||
db = r.applySorting(db, options)
|
||||
|
||||
// 应用分页
|
||||
db = r.applyPagination(db, options)
|
||||
|
||||
return records, db.Find(&records).Error
|
||||
}
|
||||
|
||||
// buildQueryConditions 构建查询条件
|
||||
//
|
||||
// 参数:
|
||||
// - db: GORM数据库查询对象
|
||||
// - query: 查询条件
|
||||
//
|
||||
// 返回:
|
||||
// - *gorm.DB: 应用查询条件后的数据库对象
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) buildQueryConditions(db *gorm.DB, query *queries.ListEnterpriseInfoSubmitRecordsQuery) *gorm.DB {
|
||||
if query.UserID != "" {
|
||||
db = db.Where("user_id = ?", query.UserID)
|
||||
}
|
||||
if query.Status != "" {
|
||||
db = db.Where("status = ?", query.Status)
|
||||
}
|
||||
if query.StartDate != "" {
|
||||
db = db.Where("created_at >= ?", query.StartDate)
|
||||
}
|
||||
if query.EndDate != "" {
|
||||
db = db.Where("created_at <= ?", query.EndDate)
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
// applyPaginationAndSorting 应用分页和排序
|
||||
//
|
||||
// 参数:
|
||||
// - db: GORM数据库查询对象
|
||||
// - query: 查询条件
|
||||
//
|
||||
// 返回:
|
||||
// - *gorm.DB: 应用分页和排序后的数据库对象
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) applyPaginationAndSorting(db *gorm.DB, query *queries.ListEnterpriseInfoSubmitRecordsQuery) *gorm.DB {
|
||||
// 应用分页
|
||||
offset := (query.Page - 1) * query.PageSize
|
||||
db = db.Offset(offset).Limit(query.PageSize)
|
||||
|
||||
// 默认排序
|
||||
db = db.Order("created_at DESC")
|
||||
|
||||
return db
|
||||
}
|
||||
|
||||
// applySorting 应用排序规则
|
||||
//
|
||||
// 参数:
|
||||
// - db: GORM数据库查询对象
|
||||
// - options: 查询选项
|
||||
//
|
||||
// 返回:
|
||||
// - *gorm.DB: 应用排序后的数据库对象
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) applySorting(db *gorm.DB, options interfaces.ListOptions) *gorm.DB {
|
||||
if options.Sort != "" {
|
||||
order := "ASC"
|
||||
if options.Order == "desc" || options.Order == "DESC" {
|
||||
order = "DESC"
|
||||
}
|
||||
return db.Order(options.Sort + " " + order)
|
||||
}
|
||||
return db.Order("created_at DESC")
|
||||
}
|
||||
|
||||
// applyPagination 应用分页规则
|
||||
//
|
||||
// 参数:
|
||||
// - db: GORM数据库查询对象
|
||||
// - options: 查询选项
|
||||
//
|
||||
// 返回:
|
||||
// - *gorm.DB: 应用分页后的数据库对象
|
||||
func (r *GormEnterpriseInfoSubmitRecordRepository) applyPagination(db *gorm.DB, options interfaces.ListOptions) *gorm.DB {
|
||||
if options.Page > 0 && options.PageSize > 0 {
|
||||
offset := (options.Page - 1) * options.PageSize
|
||||
return db.Offset(offset).Limit(options.PageSize)
|
||||
}
|
||||
return db
|
||||
}
|
||||
@@ -1,315 +0,0 @@
|
||||
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"
|
||||
)
|
||||
|
||||
// GormEsignContractGenerateRecordRepository e签宝生成合同记录GORM仓储实现
|
||||
type GormEsignContractGenerateRecordRepository struct {
|
||||
db *gorm.DB
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// 编译时检查接口实现
|
||||
var _ repositories.EsignContractGenerateRecordRepository = (*GormEsignContractGenerateRecordRepository)(nil)
|
||||
|
||||
// NewGormEsignContractGenerateRecordRepository 创建e签宝生成合同记录GORM仓储
|
||||
func NewGormEsignContractGenerateRecordRepository(db *gorm.DB, logger *zap.Logger) repositories.EsignContractGenerateRecordRepository {
|
||||
return &GormEsignContractGenerateRecordRepository{
|
||||
db: db,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// ================ 基础CRUD操作 ================
|
||||
|
||||
// Create 创建e签宝生成合同记录
|
||||
func (r *GormEsignContractGenerateRecordRepository) Create(ctx context.Context, record entities.EsignContractGenerateRecord) (entities.EsignContractGenerateRecord, error) {
|
||||
r.logger.Info("创建e签宝生成合同记录", zap.String("certification_id", record.CertificationID))
|
||||
err := r.db.WithContext(ctx).Create(&record).Error
|
||||
return record, err
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取e签宝生成合同记录
|
||||
func (r *GormEsignContractGenerateRecordRepository) GetByID(ctx context.Context, id string) (entities.EsignContractGenerateRecord, error) {
|
||||
var record entities.EsignContractGenerateRecord
|
||||
err := r.db.WithContext(ctx).Where("id = ?", id).First(&record).Error
|
||||
return record, err
|
||||
}
|
||||
|
||||
// Update 更新e签宝生成合同记录
|
||||
func (r *GormEsignContractGenerateRecordRepository) Update(ctx context.Context, record entities.EsignContractGenerateRecord) error {
|
||||
r.logger.Info("更新e签宝生成合同记录", zap.String("id", record.ID))
|
||||
return r.db.WithContext(ctx).Save(&record).Error
|
||||
}
|
||||
|
||||
// Delete 删除e签宝生成合同记录
|
||||
func (r *GormEsignContractGenerateRecordRepository) Delete(ctx context.Context, id string) error {
|
||||
r.logger.Info("删除e签宝生成合同记录", zap.String("id", id))
|
||||
return r.db.WithContext(ctx).Delete(&entities.EsignContractGenerateRecord{}, "id = ?", id).Error
|
||||
}
|
||||
|
||||
// SoftDelete 软删除e签宝生成合同记录
|
||||
func (r *GormEsignContractGenerateRecordRepository) SoftDelete(ctx context.Context, id string) error {
|
||||
r.logger.Info("软删除e签宝生成合同记录", zap.String("id", id))
|
||||
return r.db.WithContext(ctx).Delete(&entities.EsignContractGenerateRecord{}, "id = ?", id).Error
|
||||
}
|
||||
|
||||
// Restore 恢复e签宝生成合同记录
|
||||
func (r *GormEsignContractGenerateRecordRepository) Restore(ctx context.Context, id string) error {
|
||||
r.logger.Info("恢复e签宝生成合同记录", zap.String("id", id))
|
||||
return r.db.WithContext(ctx).Unscoped().Model(&entities.EsignContractGenerateRecord{}).Where("id = ?", id).Update("deleted_at", nil).Error
|
||||
}
|
||||
|
||||
// Count 统计e签宝生成合同记录数量
|
||||
func (r *GormEsignContractGenerateRecordRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
|
||||
var count int64
|
||||
query := r.db.WithContext(ctx).Model(&entities.EsignContractGenerateRecord{})
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Search != "" {
|
||||
query = query.Where("contract_name LIKE ?", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
err := query.Count(&count).Error
|
||||
return count, err
|
||||
}
|
||||
|
||||
// Exists 检查e签宝生成合同记录是否存在
|
||||
func (r *GormEsignContractGenerateRecordRepository) Exists(ctx context.Context, id string) (bool, error) {
|
||||
var count int64
|
||||
err := r.db.WithContext(ctx).Model(&entities.EsignContractGenerateRecord{}).Where("id = ?", id).Count(&count).Error
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
// CreateBatch 批量创建e签宝生成合同记录
|
||||
func (r *GormEsignContractGenerateRecordRepository) CreateBatch(ctx context.Context, records []entities.EsignContractGenerateRecord) error {
|
||||
r.logger.Info("批量创建e签宝生成合同记录", zap.Int("count", len(records)))
|
||||
return r.db.WithContext(ctx).Create(&records).Error
|
||||
}
|
||||
|
||||
// GetByIDs 根据ID列表获取e签宝生成合同记录
|
||||
func (r *GormEsignContractGenerateRecordRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.EsignContractGenerateRecord, error) {
|
||||
var records []entities.EsignContractGenerateRecord
|
||||
err := r.db.WithContext(ctx).Where("id IN ?", ids).Find(&records).Error
|
||||
return records, err
|
||||
}
|
||||
|
||||
// UpdateBatch 批量更新e签宝生成合同记录
|
||||
func (r *GormEsignContractGenerateRecordRepository) UpdateBatch(ctx context.Context, records []entities.EsignContractGenerateRecord) error {
|
||||
r.logger.Info("批量更新e签宝生成合同记录", zap.Int("count", len(records)))
|
||||
return r.db.WithContext(ctx).Save(&records).Error
|
||||
}
|
||||
|
||||
// DeleteBatch 批量删除e签宝生成合同记录
|
||||
func (r *GormEsignContractGenerateRecordRepository) DeleteBatch(ctx context.Context, ids []string) error {
|
||||
r.logger.Info("批量删除e签宝生成合同记录", zap.Strings("ids", ids))
|
||||
return r.db.WithContext(ctx).Delete(&entities.EsignContractGenerateRecord{}, "id IN ?", ids).Error
|
||||
}
|
||||
|
||||
// List 获取e签宝生成合同记录列表
|
||||
func (r *GormEsignContractGenerateRecordRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.EsignContractGenerateRecord, error) {
|
||||
var records []entities.EsignContractGenerateRecord
|
||||
query := r.db.WithContext(ctx).Model(&entities.EsignContractGenerateRecord{})
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Search != "" {
|
||||
query = query.Where("contract_name 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 records, query.Find(&records).Error
|
||||
}
|
||||
|
||||
// WithTx 使用事务
|
||||
func (r *GormEsignContractGenerateRecordRepository) WithTx(tx interface{}) interfaces.Repository[entities.EsignContractGenerateRecord] {
|
||||
if gormTx, ok := tx.(*gorm.DB); ok {
|
||||
return &GormEsignContractGenerateRecordRepository{
|
||||
db: gormTx,
|
||||
logger: r.logger,
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// ================ 业务方法 ================
|
||||
|
||||
// GetByCertificationID 根据认证ID获取e签宝生成合同记录
|
||||
func (r *GormEsignContractGenerateRecordRepository) GetByCertificationID(ctx context.Context, certificationID string) (*entities.EsignContractGenerateRecord, error) {
|
||||
var record entities.EsignContractGenerateRecord
|
||||
err := r.db.WithContext(ctx).Where("certification_id = ?", certificationID).First(&record).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
// GetByUserID 根据用户ID获取e签宝生成合同记录列表
|
||||
func (r *GormEsignContractGenerateRecordRepository) GetByUserID(ctx context.Context, userID string) ([]*entities.EsignContractGenerateRecord, error) {
|
||||
var records []entities.EsignContractGenerateRecord
|
||||
err := r.db.WithContext(ctx).Where("user_id = ?", userID).Find(&records).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result []*entities.EsignContractGenerateRecord
|
||||
for i := range records {
|
||||
result = append(result, &records[i])
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetLatestByCertificationID 根据认证ID获取最新的e签宝生成合同记录
|
||||
func (r *GormEsignContractGenerateRecordRepository) GetLatestByCertificationID(ctx context.Context, certificationID string) (*entities.EsignContractGenerateRecord, error) {
|
||||
var record entities.EsignContractGenerateRecord
|
||||
err := r.db.WithContext(ctx).Where("certification_id = ?", certificationID).Order("created_at DESC").First(&record).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
// ListRecords 获取e签宝生成合同记录列表(带分页和筛选)
|
||||
func (r *GormEsignContractGenerateRecordRepository) ListRecords(ctx context.Context, query *queries.ListEsignContractGenerateRecordsQuery) ([]*entities.EsignContractGenerateRecord, int64, error) {
|
||||
var records []entities.EsignContractGenerateRecord
|
||||
var total int64
|
||||
|
||||
dbQuery := r.db.WithContext(ctx).Model(&entities.EsignContractGenerateRecord{})
|
||||
|
||||
// 应用筛选条件
|
||||
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.ContractType != "" {
|
||||
dbQuery = dbQuery.Where("contract_type = ?", query.ContractType)
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// 应用分页
|
||||
if query.Page > 0 && query.PageSize > 0 {
|
||||
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
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
var result []*entities.EsignContractGenerateRecord
|
||||
for i := range records {
|
||||
result = append(result, &records[i])
|
||||
}
|
||||
|
||||
return result, total, nil
|
||||
}
|
||||
|
||||
// UpdateStatus 更新状态
|
||||
func (r *GormEsignContractGenerateRecordRepository) UpdateStatus(ctx context.Context, recordID string, status string, reason string) error {
|
||||
r.logger.Info("更新e签宝生成合同记录状态",
|
||||
zap.String("record_id", recordID),
|
||||
zap.String("status", status),
|
||||
)
|
||||
|
||||
updates := map[string]interface{}{
|
||||
"status": status,
|
||||
"updated_at": time.Now(),
|
||||
}
|
||||
|
||||
// 根据状态设置相应的时间戳
|
||||
switch status {
|
||||
case "generating":
|
||||
// 不需要额外时间戳
|
||||
case "success":
|
||||
updates["generated_at"] = time.Now()
|
||||
case "failed":
|
||||
updates["failed_at"] = time.Now()
|
||||
updates["failure_reason"] = reason
|
||||
}
|
||||
|
||||
return r.db.WithContext(ctx).Model(&entities.EsignContractGenerateRecord{}).
|
||||
Where("id = ?", recordID).
|
||||
Updates(updates).Error
|
||||
}
|
||||
|
||||
// UpdateSuccessInfo 更新成功信息
|
||||
func (r *GormEsignContractGenerateRecordRepository) UpdateSuccessInfo(ctx context.Context, recordID, esignFlowID, contractFileID, contractURL string) error {
|
||||
r.logger.Info("更新e签宝生成合同记录成功信息",
|
||||
zap.String("record_id", recordID),
|
||||
zap.String("esign_flow_id", esignFlowID),
|
||||
)
|
||||
|
||||
now := time.Now()
|
||||
updates := map[string]interface{}{
|
||||
"status": "success",
|
||||
"esign_flow_id": esignFlowID,
|
||||
"contract_file_id": contractFileID,
|
||||
"contract_url": contractURL,
|
||||
"generated_at": &now,
|
||||
"updated_at": now,
|
||||
}
|
||||
|
||||
return r.db.WithContext(ctx).Model(&entities.EsignContractGenerateRecord{}).
|
||||
Where("id = ?", recordID).
|
||||
Updates(updates).Error
|
||||
}
|
||||
|
||||
// IncrementRetry 增加重试次数
|
||||
func (r *GormEsignContractGenerateRecordRepository) IncrementRetry(ctx context.Context, recordID string) error {
|
||||
r.logger.Info("增加e签宝生成合同记录重试次数", zap.String("record_id", recordID))
|
||||
|
||||
return r.db.WithContext(ctx).Model(&entities.EsignContractGenerateRecord{}).
|
||||
Where("id = ?", recordID).
|
||||
UpdateColumn("retry_count", gorm.Expr("retry_count + 1")).Error
|
||||
}
|
||||
@@ -1,356 +0,0 @@
|
||||
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"
|
||||
)
|
||||
|
||||
// GormEsignContractSignRecordRepository e签宝签署合同记录GORM仓储实现
|
||||
type GormEsignContractSignRecordRepository struct {
|
||||
db *gorm.DB
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// 编译时检查接口实现
|
||||
var _ repositories.EsignContractSignRecordRepository = (*GormEsignContractSignRecordRepository)(nil)
|
||||
|
||||
// NewGormEsignContractSignRecordRepository 创建e签宝签署合同记录GORM仓储
|
||||
func NewGormEsignContractSignRecordRepository(db *gorm.DB, logger *zap.Logger) repositories.EsignContractSignRecordRepository {
|
||||
return &GormEsignContractSignRecordRepository{
|
||||
db: db,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// ================ 基础CRUD操作 ================
|
||||
|
||||
// Create 创建e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) Create(ctx context.Context, record entities.EsignContractSignRecord) (entities.EsignContractSignRecord, error) {
|
||||
r.logger.Info("创建e签宝签署合同记录", zap.String("certification_id", record.CertificationID))
|
||||
err := r.db.WithContext(ctx).Create(&record).Error
|
||||
return record, err
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) GetByID(ctx context.Context, id string) (entities.EsignContractSignRecord, error) {
|
||||
var record entities.EsignContractSignRecord
|
||||
err := r.db.WithContext(ctx).Where("id = ?", id).First(&record).Error
|
||||
return record, err
|
||||
}
|
||||
|
||||
// Update 更新e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) Update(ctx context.Context, record entities.EsignContractSignRecord) error {
|
||||
r.logger.Info("更新e签宝签署合同记录", zap.String("id", record.ID))
|
||||
return r.db.WithContext(ctx).Save(&record).Error
|
||||
}
|
||||
|
||||
// Delete 删除e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) Delete(ctx context.Context, id string) error {
|
||||
r.logger.Info("删除e签宝签署合同记录", zap.String("id", id))
|
||||
return r.db.WithContext(ctx).Delete(&entities.EsignContractSignRecord{}, "id = ?", id).Error
|
||||
}
|
||||
|
||||
// SoftDelete 软删除e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) SoftDelete(ctx context.Context, id string) error {
|
||||
r.logger.Info("软删除e签宝签署合同记录", zap.String("id", id))
|
||||
return r.db.WithContext(ctx).Delete(&entities.EsignContractSignRecord{}, "id = ?", id).Error
|
||||
}
|
||||
|
||||
// Restore 恢复e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) Restore(ctx context.Context, id string) error {
|
||||
r.logger.Info("恢复e签宝签署合同记录", zap.String("id", id))
|
||||
return r.db.WithContext(ctx).Unscoped().Model(&entities.EsignContractSignRecord{}).Where("id = ?", id).Update("deleted_at", nil).Error
|
||||
}
|
||||
|
||||
// Count 统计e签宝签署合同记录数量
|
||||
func (r *GormEsignContractSignRecordRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
|
||||
var count int64
|
||||
query := r.db.WithContext(ctx).Model(&entities.EsignContractSignRecord{})
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Search != "" {
|
||||
query = query.Where("signer_name LIKE ?", "%"+options.Search+"%")
|
||||
}
|
||||
|
||||
err := query.Count(&count).Error
|
||||
return count, err
|
||||
}
|
||||
|
||||
// Exists 检查e签宝签署合同记录是否存在
|
||||
func (r *GormEsignContractSignRecordRepository) Exists(ctx context.Context, id string) (bool, error) {
|
||||
var count int64
|
||||
err := r.db.WithContext(ctx).Model(&entities.EsignContractSignRecord{}).Where("id = ?", id).Count(&count).Error
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
// CreateBatch 批量创建e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) CreateBatch(ctx context.Context, records []entities.EsignContractSignRecord) error {
|
||||
r.logger.Info("批量创建e签宝签署合同记录", zap.Int("count", len(records)))
|
||||
return r.db.WithContext(ctx).Create(&records).Error
|
||||
}
|
||||
|
||||
// GetByIDs 根据ID列表获取e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.EsignContractSignRecord, error) {
|
||||
var records []entities.EsignContractSignRecord
|
||||
err := r.db.WithContext(ctx).Where("id IN ?", ids).Find(&records).Error
|
||||
return records, err
|
||||
}
|
||||
|
||||
// UpdateBatch 批量更新e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) UpdateBatch(ctx context.Context, records []entities.EsignContractSignRecord) error {
|
||||
r.logger.Info("批量更新e签宝签署合同记录", zap.Int("count", len(records)))
|
||||
return r.db.WithContext(ctx).Save(&records).Error
|
||||
}
|
||||
|
||||
// DeleteBatch 批量删除e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) DeleteBatch(ctx context.Context, ids []string) error {
|
||||
r.logger.Info("批量删除e签宝签署合同记录", zap.Strings("ids", ids))
|
||||
return r.db.WithContext(ctx).Delete(&entities.EsignContractSignRecord{}, "id IN ?", ids).Error
|
||||
}
|
||||
|
||||
// List 获取e签宝签署合同记录列表
|
||||
func (r *GormEsignContractSignRecordRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.EsignContractSignRecord, error) {
|
||||
var records []entities.EsignContractSignRecord
|
||||
query := r.db.WithContext(ctx).Model(&entities.EsignContractSignRecord{})
|
||||
|
||||
if options.Filters != nil {
|
||||
for key, value := range options.Filters {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Search != "" {
|
||||
query = query.Where("signer_name 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 records, query.Find(&records).Error
|
||||
}
|
||||
|
||||
// WithTx 使用事务
|
||||
func (r *GormEsignContractSignRecordRepository) WithTx(tx interface{}) interfaces.Repository[entities.EsignContractSignRecord] {
|
||||
if gormTx, ok := tx.(*gorm.DB); ok {
|
||||
return &GormEsignContractSignRecordRepository{
|
||||
db: gormTx,
|
||||
logger: r.logger,
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// ================ 业务方法 ================
|
||||
|
||||
// GetByCertificationID 根据认证ID获取e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) GetByCertificationID(ctx context.Context, certificationID string) (*entities.EsignContractSignRecord, error) {
|
||||
var record entities.EsignContractSignRecord
|
||||
err := r.db.WithContext(ctx).Where("certification_id = ?", certificationID).First(&record).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
// GetByUserID 根据用户ID获取e签宝签署合同记录列表
|
||||
func (r *GormEsignContractSignRecordRepository) GetByUserID(ctx context.Context, userID string) ([]*entities.EsignContractSignRecord, error) {
|
||||
var records []entities.EsignContractSignRecord
|
||||
err := r.db.WithContext(ctx).Where("user_id = ?", userID).Find(&records).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result []*entities.EsignContractSignRecord
|
||||
for i := range records {
|
||||
result = append(result, &records[i])
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetLatestByCertificationID 根据认证ID获取最新的e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) GetLatestByCertificationID(ctx context.Context, certificationID string) (*entities.EsignContractSignRecord, error) {
|
||||
var record entities.EsignContractSignRecord
|
||||
err := r.db.WithContext(ctx).Where("certification_id = ?", certificationID).Order("created_at DESC").First(&record).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
// GetByGenerateRecordID 根据生成记录ID获取e签宝签署合同记录
|
||||
func (r *GormEsignContractSignRecordRepository) GetByGenerateRecordID(ctx context.Context, generateRecordID string) (*entities.EsignContractSignRecord, error) {
|
||||
var record entities.EsignContractSignRecord
|
||||
err := r.db.WithContext(ctx).Where("generate_record_id = ?", generateRecordID).First(&record).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
// ListRecords 获取e签宝签署合同记录列表(带分页和筛选)
|
||||
func (r *GormEsignContractSignRecordRepository) ListRecords(ctx context.Context, query *queries.ListEsignContractSignRecordsQuery) ([]*entities.EsignContractSignRecord, int64, error) {
|
||||
var records []entities.EsignContractSignRecord
|
||||
var total int64
|
||||
|
||||
dbQuery := r.db.WithContext(ctx).Model(&entities.EsignContractSignRecord{})
|
||||
|
||||
// 应用筛选条件
|
||||
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.SignerName != "" {
|
||||
dbQuery = dbQuery.Where("signer_name LIKE ?", "%"+query.SignerName+"%")
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// 应用分页
|
||||
if query.Page > 0 && query.PageSize > 0 {
|
||||
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
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
var result []*entities.EsignContractSignRecord
|
||||
for i := range records {
|
||||
result = append(result, &records[i])
|
||||
}
|
||||
|
||||
return result, total, nil
|
||||
}
|
||||
|
||||
// UpdateStatus 更新状态
|
||||
func (r *GormEsignContractSignRecordRepository) UpdateStatus(ctx context.Context, recordID string, status string, reason string) error {
|
||||
r.logger.Info("更新e签宝签署合同记录状态",
|
||||
zap.String("record_id", recordID),
|
||||
zap.String("status", status),
|
||||
)
|
||||
|
||||
updates := map[string]interface{}{
|
||||
"status": status,
|
||||
"updated_at": time.Now(),
|
||||
}
|
||||
|
||||
// 根据状态设置相应的时间戳
|
||||
switch status {
|
||||
case "signing":
|
||||
// 不需要额外时间戳
|
||||
case "success":
|
||||
updates["signed_at"] = time.Now()
|
||||
case "failed":
|
||||
updates["failed_at"] = time.Now()
|
||||
updates["failure_reason"] = reason
|
||||
case "expired":
|
||||
updates["expired_at"] = time.Now()
|
||||
}
|
||||
|
||||
return r.db.WithContext(ctx).Model(&entities.EsignContractSignRecord{}).
|
||||
Where("id = ?", recordID).
|
||||
Updates(updates).Error
|
||||
}
|
||||
|
||||
// UpdateSuccessInfo 更新成功信息
|
||||
func (r *GormEsignContractSignRecordRepository) UpdateSuccessInfo(ctx context.Context, recordID, signedFileURL string) error {
|
||||
r.logger.Info("更新e签宝签署合同记录成功信息",
|
||||
zap.String("record_id", recordID),
|
||||
)
|
||||
|
||||
now := time.Now()
|
||||
updates := map[string]interface{}{
|
||||
"status": "success",
|
||||
"signed_file_url": signedFileURL,
|
||||
"signed_at": &now,
|
||||
"updated_at": now,
|
||||
}
|
||||
|
||||
return r.db.WithContext(ctx).Model(&entities.EsignContractSignRecord{}).
|
||||
Where("id = ?", recordID).
|
||||
Updates(updates).Error
|
||||
}
|
||||
|
||||
// SetSignURL 设置签署链接
|
||||
func (r *GormEsignContractSignRecordRepository) SetSignURL(ctx context.Context, recordID, signURL string) error {
|
||||
r.logger.Info("设置e签宝签署合同记录签署链接",
|
||||
zap.String("record_id", recordID),
|
||||
)
|
||||
|
||||
updates := map[string]interface{}{
|
||||
"sign_url": signURL,
|
||||
"updated_at": time.Now(),
|
||||
}
|
||||
|
||||
return r.db.WithContext(ctx).Model(&entities.EsignContractSignRecord{}).
|
||||
Where("id = ?", recordID).
|
||||
Updates(updates).Error
|
||||
}
|
||||
|
||||
// IncrementRetry 增加重试次数
|
||||
func (r *GormEsignContractSignRecordRepository) IncrementRetry(ctx context.Context, recordID string) error {
|
||||
r.logger.Info("增加e签宝签署合同记录重试次数", zap.String("record_id", recordID))
|
||||
|
||||
return r.db.WithContext(ctx).Model(&entities.EsignContractSignRecord{}).
|
||||
Where("id = ?", recordID).
|
||||
UpdateColumn("retry_count", gorm.Expr("retry_count + 1")).Error
|
||||
}
|
||||
|
||||
// MarkExpiredRecords 标记过期的记录
|
||||
func (r *GormEsignContractSignRecordRepository) MarkExpiredRecords(ctx context.Context) error {
|
||||
r.logger.Info("标记过期的e签宝签署合同记录")
|
||||
|
||||
now := time.Now()
|
||||
updates := map[string]interface{}{
|
||||
"status": "expired",
|
||||
"expired_at": &now,
|
||||
"updated_at": now,
|
||||
}
|
||||
|
||||
return r.db.WithContext(ctx).Model(&entities.EsignContractSignRecord{}).
|
||||
Where("status = ? AND expired_at < ?", "pending", now).
|
||||
Updates(updates).Error
|
||||
}
|
||||
291
internal/infrastructure/events/certification_event_publisher.go
Normal file
291
internal/infrastructure/events/certification_event_publisher.go
Normal file
@@ -0,0 +1,291 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
)
|
||||
|
||||
// ================ 常量定义 ================
|
||||
|
||||
const (
|
||||
// 事件类型
|
||||
EventTypeCertificationCreated = "certification.created"
|
||||
EventTypeEnterpriseInfoSubmitted = "certification.enterprise_info_submitted"
|
||||
EventTypeEnterpriseVerificationCompleted = "certification.enterprise_verification_completed"
|
||||
EventTypeContractGenerated = "certification.contract_generated"
|
||||
EventTypeContractSigned = "certification.contract_signed"
|
||||
EventTypeCertificationCompleted = "certification.completed"
|
||||
EventTypeCertificationFailed = "certification.failed"
|
||||
EventTypeStatusTransitioned = "certification.status_transitioned"
|
||||
|
||||
// 重试配置
|
||||
MaxRetries = 3
|
||||
RetryDelay = 5 * time.Second
|
||||
)
|
||||
|
||||
// ================ 事件结构 ================
|
||||
|
||||
// CertificationEventData 认证事件数据结构
|
||||
type CertificationEventData struct {
|
||||
EventType string `json:"event_type"`
|
||||
CertificationID string `json:"certification_id"`
|
||||
UserID string `json:"user_id"`
|
||||
Data map[string]interface{} `json:"data"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
// ================ 事件发布器实现 ================
|
||||
|
||||
// CertificationEventPublisher 认证事件发布器实现
|
||||
//
|
||||
// 职责:
|
||||
// - 发布认证域相关的事件
|
||||
// - 支持异步发布和重试机制
|
||||
// - 提供事件持久化能力
|
||||
// - 集成监控和日志
|
||||
type CertificationEventPublisher struct {
|
||||
eventBus interfaces.EventBus
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewCertificationEventPublisher 创建认证事件发布器
|
||||
func NewCertificationEventPublisher(
|
||||
eventBus interfaces.EventBus,
|
||||
logger *zap.Logger,
|
||||
) *CertificationEventPublisher {
|
||||
return &CertificationEventPublisher{
|
||||
eventBus: eventBus,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// ================ 事件发布方法 ================
|
||||
|
||||
// PublishCertificationCreated 发布认证创建事件
|
||||
func (p *CertificationEventPublisher) PublishCertificationCreated(
|
||||
ctx context.Context,
|
||||
certificationID, userID string,
|
||||
data map[string]interface{},
|
||||
) error {
|
||||
eventData := &CertificationEventData{
|
||||
EventType: EventTypeCertificationCreated,
|
||||
CertificationID: certificationID,
|
||||
UserID: userID,
|
||||
Data: data,
|
||||
Timestamp: time.Now(),
|
||||
Version: "1.0",
|
||||
}
|
||||
|
||||
return p.publishEventData(ctx, eventData)
|
||||
}
|
||||
|
||||
// PublishEnterpriseInfoSubmitted 发布企业信息提交事件
|
||||
func (p *CertificationEventPublisher) PublishEnterpriseInfoSubmitted(
|
||||
ctx context.Context,
|
||||
certificationID, userID string,
|
||||
data map[string]interface{},
|
||||
) error {
|
||||
eventData := &CertificationEventData{
|
||||
EventType: EventTypeEnterpriseInfoSubmitted,
|
||||
CertificationID: certificationID,
|
||||
UserID: userID,
|
||||
Data: data,
|
||||
Timestamp: time.Now(),
|
||||
Version: "1.0",
|
||||
}
|
||||
|
||||
return p.publishEventData(ctx, eventData)
|
||||
}
|
||||
|
||||
// PublishEnterpriseVerificationCompleted 发布企业认证完成事件
|
||||
func (p *CertificationEventPublisher) PublishEnterpriseVerificationCompleted(
|
||||
ctx context.Context,
|
||||
certificationID, userID string,
|
||||
data map[string]interface{},
|
||||
) error {
|
||||
eventData := &CertificationEventData{
|
||||
EventType: EventTypeEnterpriseVerificationCompleted,
|
||||
CertificationID: certificationID,
|
||||
UserID: userID,
|
||||
Data: data,
|
||||
Timestamp: time.Now(),
|
||||
Version: "1.0",
|
||||
}
|
||||
|
||||
return p.publishEventData(ctx, eventData)
|
||||
}
|
||||
|
||||
// PublishContractGenerated 发布合同生成事件
|
||||
func (p *CertificationEventPublisher) PublishContractGenerated(
|
||||
ctx context.Context,
|
||||
certificationID, userID string,
|
||||
data map[string]interface{},
|
||||
) error {
|
||||
eventData := &CertificationEventData{
|
||||
EventType: EventTypeContractGenerated,
|
||||
CertificationID: certificationID,
|
||||
UserID: userID,
|
||||
Data: data,
|
||||
Timestamp: time.Now(),
|
||||
Version: "1.0",
|
||||
}
|
||||
|
||||
return p.publishEventData(ctx, eventData)
|
||||
}
|
||||
|
||||
// PublishContractSigned 发布合同签署事件
|
||||
func (p *CertificationEventPublisher) PublishContractSigned(
|
||||
ctx context.Context,
|
||||
certificationID, userID string,
|
||||
data map[string]interface{},
|
||||
) error {
|
||||
eventData := &CertificationEventData{
|
||||
EventType: EventTypeContractSigned,
|
||||
CertificationID: certificationID,
|
||||
UserID: userID,
|
||||
Data: data,
|
||||
Timestamp: time.Now(),
|
||||
Version: "1.0",
|
||||
}
|
||||
|
||||
return p.publishEventData(ctx, eventData)
|
||||
}
|
||||
|
||||
// PublishCertificationCompleted 发布认证完成事件
|
||||
func (p *CertificationEventPublisher) PublishCertificationCompleted(
|
||||
ctx context.Context,
|
||||
certificationID, userID string,
|
||||
data map[string]interface{},
|
||||
) error {
|
||||
eventData := &CertificationEventData{
|
||||
EventType: EventTypeCertificationCompleted,
|
||||
CertificationID: certificationID,
|
||||
UserID: userID,
|
||||
Data: data,
|
||||
Timestamp: time.Now(),
|
||||
Version: "1.0",
|
||||
}
|
||||
|
||||
return p.publishEventData(ctx, eventData)
|
||||
}
|
||||
|
||||
// PublishCertificationFailed 发布认证失败事件
|
||||
func (p *CertificationEventPublisher) PublishCertificationFailed(
|
||||
ctx context.Context,
|
||||
certificationID, userID string,
|
||||
data map[string]interface{},
|
||||
) error {
|
||||
eventData := &CertificationEventData{
|
||||
EventType: EventTypeCertificationFailed,
|
||||
CertificationID: certificationID,
|
||||
UserID: userID,
|
||||
Data: data,
|
||||
Timestamp: time.Now(),
|
||||
Version: "1.0",
|
||||
}
|
||||
|
||||
return p.publishEventData(ctx, eventData)
|
||||
}
|
||||
|
||||
// PublishStatusTransitioned 发布状态转换事件
|
||||
func (p *CertificationEventPublisher) PublishStatusTransitioned(
|
||||
ctx context.Context,
|
||||
certificationID, userID string,
|
||||
data map[string]interface{},
|
||||
) error {
|
||||
eventData := &CertificationEventData{
|
||||
EventType: EventTypeStatusTransitioned,
|
||||
CertificationID: certificationID,
|
||||
UserID: userID,
|
||||
Data: data,
|
||||
Timestamp: time.Now(),
|
||||
Version: "1.0",
|
||||
}
|
||||
|
||||
return p.publishEventData(ctx, eventData)
|
||||
}
|
||||
|
||||
// ================ 内部实现 ================
|
||||
|
||||
// publishEventData 发布事件数据(带重试机制)
|
||||
func (p *CertificationEventPublisher) publishEventData(ctx context.Context, eventData *CertificationEventData) error {
|
||||
p.logger.Info("发布认证事件",
|
||||
zap.String("event_type", eventData.EventType),
|
||||
zap.String("certification_id", eventData.CertificationID),
|
||||
zap.Time("timestamp", eventData.Timestamp))
|
||||
|
||||
// 尝试发布事件,带重试机制
|
||||
var lastErr error
|
||||
for attempt := 0; attempt <= MaxRetries; attempt++ {
|
||||
if attempt > 0 {
|
||||
// 指数退避重试
|
||||
delay := time.Duration(attempt) * RetryDelay
|
||||
p.logger.Warn("事件发布重试",
|
||||
zap.String("event_type", eventData.EventType),
|
||||
zap.Int("attempt", attempt),
|
||||
zap.Duration("delay", delay))
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-time.After(delay):
|
||||
// 继续重试
|
||||
}
|
||||
}
|
||||
|
||||
// 简化的事件发布:直接记录日志
|
||||
p.logger.Info("模拟事件发布",
|
||||
zap.String("event_type", eventData.EventType),
|
||||
zap.String("certification_id", eventData.CertificationID),
|
||||
zap.Any("data", eventData.Data))
|
||||
|
||||
// TODO: 这里可以集成真正的事件总线
|
||||
// if err := p.eventBus.Publish(ctx, eventData); err != nil {
|
||||
// lastErr = err
|
||||
// continue
|
||||
// }
|
||||
|
||||
// 发布成功
|
||||
p.logger.Info("事件发布成功",
|
||||
zap.String("event_type", eventData.EventType),
|
||||
zap.String("certification_id", eventData.CertificationID))
|
||||
return nil
|
||||
}
|
||||
|
||||
// 理论上不会到达这里,因为简化实现总是成功
|
||||
return lastErr
|
||||
}
|
||||
|
||||
// ================ 事件处理器注册 ================
|
||||
|
||||
// RegisterEventHandlers 注册事件处理器
|
||||
func (p *CertificationEventPublisher) RegisterEventHandlers() error {
|
||||
// TODO: 注册具体的事件处理器
|
||||
// 例如:发送通知、更新统计数据、触发后续流程等
|
||||
|
||||
p.logger.Info("认证事件处理器已注册")
|
||||
return nil
|
||||
}
|
||||
|
||||
// ================ 工具方法 ================
|
||||
|
||||
// CreateEventData 创建事件数据
|
||||
func CreateEventData(eventType, certificationID, userID string, data map[string]interface{}) map[string]interface{} {
|
||||
if data == nil {
|
||||
data = make(map[string]interface{})
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"event_type": eventType,
|
||||
"certification_id": certificationID,
|
||||
"user_id": userID,
|
||||
"data": data,
|
||||
"timestamp": time.Now(),
|
||||
"version": "1.0",
|
||||
}
|
||||
}
|
||||
295
internal/infrastructure/external/esign/certification_esign_service.go
vendored
Normal file
295
internal/infrastructure/external/esign/certification_esign_service.go
vendored
Normal file
@@ -0,0 +1,295 @@
|
||||
package esign
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"tyapi-server/internal/domains/certification/enums"
|
||||
"tyapi-server/internal/domains/certification/repositories"
|
||||
"tyapi-server/internal/domains/certification/value_objects"
|
||||
"tyapi-server/internal/shared/esign"
|
||||
)
|
||||
|
||||
// ================ 常量定义 ================
|
||||
|
||||
const (
|
||||
// 企业认证超时时间
|
||||
EnterpriseAuthTimeout = 30 * time.Minute
|
||||
|
||||
// 合同签署超时时间
|
||||
ContractSignTimeout = 7 * 24 * time.Hour // 7天
|
||||
|
||||
// 回调重试次数
|
||||
MaxCallbackRetries = 3
|
||||
)
|
||||
|
||||
// ================ 服务实现 ================
|
||||
|
||||
// CertificationEsignService 认证e签宝服务实现
|
||||
//
|
||||
// 业务职责:
|
||||
// - 处理企业认证流程
|
||||
// - 处理合同生成和签署
|
||||
// - 处理e签宝回调
|
||||
// - 管理认证状态更新
|
||||
type CertificationEsignService struct {
|
||||
esignClient *esign.Client
|
||||
commandRepo repositories.CertificationCommandRepository
|
||||
queryRepo repositories.CertificationQueryRepository
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewCertificationEsignService 创建认证e签宝服务
|
||||
func NewCertificationEsignService(
|
||||
esignClient *esign.Client,
|
||||
commandRepo repositories.CertificationCommandRepository,
|
||||
queryRepo repositories.CertificationQueryRepository,
|
||||
logger *zap.Logger,
|
||||
) *CertificationEsignService {
|
||||
return &CertificationEsignService{
|
||||
esignClient: esignClient,
|
||||
commandRepo: commandRepo,
|
||||
queryRepo: queryRepo,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// ================ 企业认证流程 ================
|
||||
|
||||
// StartEnterpriseAuth 开始企业认证
|
||||
//
|
||||
// 业务流程:
|
||||
// 1. 调用e签宝企业认证API
|
||||
// 2. 更新认证记录的auth_flow_id
|
||||
// 3. 更新状态为企业认证中
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - certificationID: 认证ID
|
||||
// - enterpriseInfo: 企业信息
|
||||
//
|
||||
// 返回:
|
||||
// - authURL: 认证URL
|
||||
// - error: 错误信息
|
||||
func (s *CertificationEsignService) StartEnterpriseAuth(
|
||||
ctx context.Context,
|
||||
certificationID string,
|
||||
enterpriseInfo *value_objects.EnterpriseInfo,
|
||||
) (string, error) {
|
||||
s.logger.Info("开始企业认证",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.String("company_name", enterpriseInfo.CompanyName))
|
||||
|
||||
// TODO: 实现e签宝企业认证API调用
|
||||
// 暂时使用模拟响应
|
||||
authFlowID := fmt.Sprintf("auth_%s_%d", certificationID, time.Now().Unix())
|
||||
authURL := fmt.Sprintf("https://esign.example.com/auth/%s", authFlowID)
|
||||
|
||||
s.logger.Info("模拟调用e签宝企业认证API",
|
||||
zap.String("auth_flow_id", authFlowID),
|
||||
zap.String("auth_url", authURL))
|
||||
|
||||
// 更新认证记录
|
||||
if err := s.commandRepo.UpdateAuthFlowID(ctx, certificationID, authFlowID); err != nil {
|
||||
s.logger.Error("更新认证流程ID失败", zap.Error(err))
|
||||
return "", fmt.Errorf("更新认证流程ID失败: %w", err)
|
||||
}
|
||||
|
||||
s.logger.Info("企业认证启动成功",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.String("auth_flow_id", authFlowID))
|
||||
|
||||
return authURL, nil
|
||||
}
|
||||
|
||||
// HandleEnterpriseAuthCallback 处理企业认证回调
|
||||
//
|
||||
// 业务流程:
|
||||
// 1. 根据回调信息查找认证记录
|
||||
// 2. 根据回调状态更新认证状态
|
||||
// 3. 如果成功,继续合同生成流程
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - authFlowID: 认证流程ID
|
||||
// - success: 是否成功
|
||||
// - message: 回调消息
|
||||
//
|
||||
// 返回:
|
||||
// - error: 错误信息
|
||||
func (s *CertificationEsignService) HandleEnterpriseAuthCallback(
|
||||
ctx context.Context,
|
||||
authFlowID string,
|
||||
success bool,
|
||||
message string,
|
||||
) error {
|
||||
s.logger.Info("处理企业认证回调",
|
||||
zap.String("auth_flow_id", authFlowID),
|
||||
zap.Bool("success", success))
|
||||
|
||||
// 查找认证记录
|
||||
cert, err := s.queryRepo.FindByAuthFlowID(ctx, authFlowID)
|
||||
if err != nil {
|
||||
s.logger.Error("根据认证流程ID查找认证记录失败", zap.Error(err))
|
||||
return fmt.Errorf("查找认证记录失败: %w", err)
|
||||
}
|
||||
|
||||
if success {
|
||||
// 企业认证成功,更新状态
|
||||
if err := s.commandRepo.UpdateStatus(ctx, cert.ID, enums.StatusEnterpriseVerified); err != nil {
|
||||
s.logger.Error("更新认证状态失败", zap.Error(err))
|
||||
return fmt.Errorf("更新认证状态失败: %w", err)
|
||||
}
|
||||
|
||||
s.logger.Info("企业认证成功", zap.String("certification_id", cert.ID))
|
||||
} else {
|
||||
// 企业认证失败,更新状态
|
||||
if err := s.commandRepo.UpdateStatus(ctx, cert.ID, enums.StatusInfoRejected); err != nil {
|
||||
s.logger.Error("更新认证状态失败", zap.Error(err))
|
||||
return fmt.Errorf("更新认证状态失败: %w", err)
|
||||
}
|
||||
|
||||
s.logger.Info("企业认证失败", zap.String("certification_id", cert.ID), zap.String("reason", message))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ================ 合同管理流程 ================
|
||||
|
||||
// GenerateContract 生成认证合同
|
||||
//
|
||||
// 业务流程:
|
||||
// 1. 调用e签宝合同生成API
|
||||
// 2. 更新认证记录的合同信息
|
||||
// 3. 更新状态为合同已生成
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - certificationID: 认证ID
|
||||
//
|
||||
// 返回:
|
||||
// - contractSignURL: 合同签署URL
|
||||
// - error: 错误信息
|
||||
func (s *CertificationEsignService) GenerateContract(
|
||||
ctx context.Context,
|
||||
certificationID string,
|
||||
) (string, error) {
|
||||
s.logger.Info("生成认证合同", zap.String("certification_id", certificationID))
|
||||
|
||||
// TODO: 实现e签宝合同生成API调用
|
||||
// 暂时使用模拟响应
|
||||
contractFileID := fmt.Sprintf("contract_%s_%d", certificationID, time.Now().Unix())
|
||||
esignFlowID := fmt.Sprintf("flow_%s_%d", certificationID, time.Now().Unix())
|
||||
contractURL := fmt.Sprintf("https://esign.example.com/contract/%s", contractFileID)
|
||||
contractSignURL := fmt.Sprintf("https://esign.example.com/sign/%s", esignFlowID)
|
||||
|
||||
s.logger.Info("模拟调用e签宝合同生成API",
|
||||
zap.String("contract_file_id", contractFileID),
|
||||
zap.String("esign_flow_id", esignFlowID))
|
||||
|
||||
// 更新认证记录
|
||||
if err := s.commandRepo.UpdateContractInfo(
|
||||
ctx,
|
||||
certificationID,
|
||||
contractFileID,
|
||||
esignFlowID,
|
||||
contractURL,
|
||||
contractSignURL,
|
||||
); err != nil {
|
||||
s.logger.Error("更新合同信息失败", zap.Error(err))
|
||||
return "", fmt.Errorf("更新合同信息失败: %w", err)
|
||||
}
|
||||
|
||||
// 更新状态
|
||||
if err := s.commandRepo.UpdateStatus(ctx, certificationID, enums.StatusContractApplied); err != nil {
|
||||
s.logger.Error("更新认证状态失败", zap.Error(err))
|
||||
return "", fmt.Errorf("更新认证状态失败: %w", err)
|
||||
}
|
||||
|
||||
s.logger.Info("认证合同生成成功",
|
||||
zap.String("certification_id", certificationID),
|
||||
zap.String("contract_file_id", contractFileID))
|
||||
|
||||
return contractSignURL, nil
|
||||
}
|
||||
|
||||
// HandleContractSignCallback 处理合同签署回调
|
||||
//
|
||||
// 业务流程:
|
||||
// 1. 根据回调信息查找认证记录
|
||||
// 2. 根据回调状态更新认证状态
|
||||
// 3. 如果成功,认证流程完成
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - esignFlowID: e签宝流程ID
|
||||
// - success: 是否成功
|
||||
// - signedFileURL: 已签署文件URL
|
||||
//
|
||||
// 返回:
|
||||
// - error: 错误信息
|
||||
func (s *CertificationEsignService) HandleContractSignCallback(
|
||||
ctx context.Context,
|
||||
esignFlowID string,
|
||||
success bool,
|
||||
signedFileURL string,
|
||||
) error {
|
||||
s.logger.Info("处理合同签署回调",
|
||||
zap.String("esign_flow_id", esignFlowID),
|
||||
zap.Bool("success", success))
|
||||
|
||||
// 查找认证记录
|
||||
cert, err := s.queryRepo.FindByEsignFlowID(ctx, esignFlowID)
|
||||
if err != nil {
|
||||
s.logger.Error("根据e签宝流程ID查找认证记录失败", zap.Error(err))
|
||||
return fmt.Errorf("查找认证记录失败: %w", err)
|
||||
}
|
||||
|
||||
if success {
|
||||
// 合同签署成功,认证完成
|
||||
if err := s.commandRepo.UpdateStatus(ctx, cert.ID, enums.StatusContractSigned); err != nil {
|
||||
s.logger.Error("更新认证状态失败", zap.Error(err))
|
||||
return fmt.Errorf("更新认证状态失败: %w", err)
|
||||
}
|
||||
|
||||
s.logger.Info("认证流程完成", zap.String("certification_id", cert.ID))
|
||||
} else {
|
||||
// 合同签署失败
|
||||
if err := s.commandRepo.UpdateStatus(ctx, cert.ID, enums.StatusContractRejected); err != nil {
|
||||
s.logger.Error("更新认证状态失败", zap.Error(err))
|
||||
return fmt.Errorf("更新认证状态失败: %w", err)
|
||||
}
|
||||
|
||||
s.logger.Info("合同签署失败", zap.String("certification_id", cert.ID))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ================ 辅助方法 ================
|
||||
|
||||
// GetContractSignURL 获取合同签署URL
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 上下文
|
||||
// - certificationID: 认证ID
|
||||
//
|
||||
// 返回:
|
||||
// - signURL: 签署URL
|
||||
// - error: 错误信息
|
||||
func (s *CertificationEsignService) GetContractSignURL(ctx context.Context, certificationID string) (string, error) {
|
||||
cert, err := s.queryRepo.GetByID(ctx, certificationID)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("获取认证信息失败: %w", err)
|
||||
}
|
||||
|
||||
if cert.ContractSignURL == "" {
|
||||
return "", fmt.Errorf("合同签署URL尚未生成")
|
||||
}
|
||||
|
||||
return cert.ContractSignURL, nil
|
||||
}
|
||||
@@ -1,10 +1,6 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
|
||||
@@ -12,157 +8,150 @@ import (
|
||||
"tyapi-server/internal/application/certification/dto/commands"
|
||||
"tyapi-server/internal/application/certification/dto/queries"
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
"tyapi-server/internal/shared/middleware"
|
||||
)
|
||||
|
||||
// CertificationHandler 认证处理器
|
||||
// 负责处理HTTP请求,参数验证,调用应用服务,返回HTTP响应
|
||||
// CertificationHandler 认证HTTP处理器
|
||||
type CertificationHandler struct {
|
||||
certAppService certification.CertificationApplicationService
|
||||
esignCallbackService certification.EsignCallbackApplicationService
|
||||
response interfaces.ResponseBuilder
|
||||
validator interfaces.RequestValidator
|
||||
logger *zap.Logger
|
||||
appService certification.CertificationApplicationService
|
||||
response interfaces.ResponseBuilder
|
||||
validator interfaces.RequestValidator
|
||||
logger *zap.Logger
|
||||
jwtAuth *middleware.JWTAuthMiddleware
|
||||
}
|
||||
|
||||
// NewCertificationHandler 创建认证处理器
|
||||
func NewCertificationHandler(
|
||||
certAppService certification.CertificationApplicationService,
|
||||
esignCallbackService certification.EsignCallbackApplicationService,
|
||||
appService certification.CertificationApplicationService,
|
||||
response interfaces.ResponseBuilder,
|
||||
validator interfaces.RequestValidator,
|
||||
logger *zap.Logger,
|
||||
jwtAuth *middleware.JWTAuthMiddleware,
|
||||
) *CertificationHandler {
|
||||
return &CertificationHandler{
|
||||
certAppService: certAppService,
|
||||
esignCallbackService: esignCallbackService,
|
||||
response: response,
|
||||
validator: validator,
|
||||
logger: logger,
|
||||
appService: appService,
|
||||
response: response,
|
||||
validator: validator,
|
||||
logger: logger,
|
||||
jwtAuth: jwtAuth,
|
||||
}
|
||||
}
|
||||
|
||||
// GetCertificationStatus 获取认证状态
|
||||
// @Summary 获取认证状态
|
||||
// @Description 获取当前用户的认证状态信息,包括认证进度、当前状态等
|
||||
// @Tags 企业认证
|
||||
// ================ 认证申请管理 ================
|
||||
|
||||
// CreateCertification 创建认证申请
|
||||
// @Summary 创建认证申请
|
||||
// @Description 为用户创建企业认证申请
|
||||
// @Tags 认证管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Success 200 {object} map[string]interface{} "获取认证状态成功"
|
||||
// @Failure 401 {object} map[string]interface{} "用户未登录"
|
||||
// @Param request body commands.CreateCertificationCommand true "创建认证申请请求"
|
||||
// @Success 201 {object} responses.CertificationResponse "认证申请创建成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certification/status [get]
|
||||
func (h *CertificationHandler) GetCertificationStatus(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
// @Router /api/v1/certifications [post]
|
||||
func (h *CertificationHandler) CreateCertification(c *gin.Context) {
|
||||
var cmd commands.CreateCertificationCommand
|
||||
cmd.UserID = h.getCurrentUserID(c)
|
||||
if cmd.UserID == "" {
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
query := &queries.GetCertificationStatusQuery{
|
||||
UserID: userID,
|
||||
}
|
||||
|
||||
result, err := h.certAppService.GetCertificationStatus(c.Request.Context(), query)
|
||||
result, err := h.appService.CreateCertification(c.Request.Context(), &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("获取认证状态失败", zap.Error(err))
|
||||
h.logger.Error("创建认证申请失败", zap.Error(err), zap.String("user_id", cmd.UserID))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result, "获取认证状态成功")
|
||||
h.response.Created(c, result, "认证申请创建成功")
|
||||
}
|
||||
|
||||
// GetCertificationDetails 获取认证详情
|
||||
// GetCertification 获取认证详情
|
||||
// @Summary 获取认证详情
|
||||
// @Description 获取当前用户的详细认证信息,包括企业信息、认证记录等
|
||||
// @Tags 企业认证
|
||||
// @Description 根据认证ID获取认证详情
|
||||
// @Tags 认证管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Success 200 {object} map[string]interface{} "获取认证详情成功"
|
||||
// @Failure 401 {object} map[string]interface{} "用户未登录"
|
||||
// @Param id path string true "认证ID"
|
||||
// @Success 200 {object} responses.CertificationResponse "获取认证详情成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "认证记录不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certification/details [get]
|
||||
func (h *CertificationHandler) GetCertificationDetails(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
// @Router /api/v1/certifications/{id} [get]
|
||||
func (h *CertificationHandler) GetCertification(c *gin.Context) {
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
query := &queries.GetCertificationDetailsQuery{
|
||||
UserID: userID,
|
||||
certificationID := c.Param("id")
|
||||
if certificationID == "" {
|
||||
h.response.BadRequest(c, "认证ID不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.certAppService.GetCertificationDetails(c.Request.Context(), query)
|
||||
query := &queries.GetCertificationQuery{
|
||||
CertificationID: certificationID,
|
||||
UserID: userID,
|
||||
}
|
||||
|
||||
result, err := h.appService.GetCertification(c.Request.Context(), query)
|
||||
if err != nil {
|
||||
h.logger.Error("获取认证详情失败", zap.Error(err))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
h.logger.Error("获取认证详情失败", zap.Error(err), zap.String("certification_id", certificationID))
|
||||
h.response.NotFound(c, "认证记录不存在")
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result, "获取认证详情成功")
|
||||
}
|
||||
|
||||
// GetCertificationProgress 获取认证进度
|
||||
// @Summary 获取认证进度
|
||||
// @Description 获取当前用户的认证进度百分比和下一步操作提示
|
||||
// @Tags 企业认证
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Success 200 {object} map[string]interface{} "获取认证进度成功"
|
||||
// @Failure 401 {object} map[string]interface{} "用户未登录"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certification/progress [get]
|
||||
func (h *CertificationHandler) GetCertificationProgress(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.certAppService.GetCertificationProgress(c.Request.Context(), userID)
|
||||
if err != nil {
|
||||
h.logger.Error("获取认证进度失败", zap.Error(err))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result, "获取认证进度成功")
|
||||
}
|
||||
// ================ 企业信息管理 ================
|
||||
|
||||
// SubmitEnterpriseInfo 提交企业信息
|
||||
// @Summary 提交企业信息
|
||||
// @Description 提交企业四要素信息(企业名称、统一社会信用代码、法定代表人姓名、法定代表人身份证),完成企业信息验证。如果用户没有认证申请,系统会自动创建
|
||||
// @Tags 企业认证
|
||||
// @Description 提交企业认证所需的企业信息
|
||||
// @Tags 认证管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param request body commands.SubmitEnterpriseInfoCommand true "企业信息提交请求"
|
||||
// @Success 200 {object} map[string]interface{} "企业信息提交成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误或验证码无效"
|
||||
// @Failure 401 {object} map[string]interface{} "用户未登录"
|
||||
// @Param id path string true "认证ID"
|
||||
// @Param request body commands.SubmitEnterpriseInfoCommand true "提交企业信息请求"
|
||||
// @Success 200 {object} responses.CertificationResponse "企业信息提交成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "认证记录不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certification/submit-enterprise-info [post]
|
||||
// @Router /api/v1/certifications/{id}/enterprise-info [post]
|
||||
func (h *CertificationHandler) SubmitEnterpriseInfo(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
certificationID := c.Param("id")
|
||||
if certificationID == "" {
|
||||
h.response.BadRequest(c, "认证ID不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
var cmd commands.SubmitEnterpriseInfoCommand
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
cmd.CertificationID = certificationID
|
||||
cmd.UserID = userID
|
||||
|
||||
result, err := h.certAppService.SubmitEnterpriseInfo(c.Request.Context(), &cmd)
|
||||
result, err := h.appService.SubmitEnterpriseInfo(c.Request.Context(), &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("提交企业信息失败", zap.Error(err))
|
||||
h.logger.Error("提交企业信息失败", zap.Error(err), zap.String("certification_id", certificationID))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
@@ -170,57 +159,38 @@ func (h *CertificationHandler) SubmitEnterpriseInfo(c *gin.Context) {
|
||||
h.response.Success(c, result, "企业信息提交成功")
|
||||
}
|
||||
|
||||
// GetEnterpriseAuthURL 获取企业认证链接
|
||||
// @Summary 获取企业认证链接
|
||||
// @Description 获取e签宝企业认证链接,用户可通过该链接完成企业认证
|
||||
// @Tags 企业认证
|
||||
// ================ 合同管理 ================
|
||||
|
||||
// ApplyContract 申请合同签署
|
||||
// @Summary 申请合同签署
|
||||
// @Description 申请企业认证合同签署
|
||||
// @Tags 认证管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Success 200 {object} map[string]interface{} "获取企业认证链接成功"
|
||||
// @Failure 401 {object} map[string]interface{} "用户未登录"
|
||||
// @Failure 400 {object} map[string]interface{} "企业信息未提交或认证状态异常"
|
||||
// @Param request body commands.ApplyContractCommand true "申请合同请求"
|
||||
// @Success 200 {object} responses.ContractSignUrlResponse "合同申请成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "认证记录不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certification/enterprise-auth-url [get]
|
||||
func (h *CertificationHandler) GetEnterpriseAuthURL(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.certAppService.GetEnterpriseAuthURL(c.Request.Context(), userID)
|
||||
if err != nil {
|
||||
h.logger.Error("获取企业认证链接失败", zap.Error(err))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result, "获取企业认证链接成功")
|
||||
}
|
||||
|
||||
// ApplyContract 申请合同
|
||||
// @Summary 申请合同
|
||||
// @Description 为企业认证用户申请合同,生成合同文档
|
||||
// @Tags 企业认证
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Success 200 {object} map[string]interface{} "合同申请成功"
|
||||
// @Failure 401 {object} map[string]interface{} "用户未登录"
|
||||
// @Failure 400 {object} map[string]interface{} "企业认证未完成或合同申请失败"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certification/apply-contract [post]
|
||||
// @Router /api/v1/certifications/apply-contract [post]
|
||||
func (h *CertificationHandler) ApplyContract(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.certAppService.ApplyContract(c.Request.Context(), userID)
|
||||
var cmd commands.ApplyContractCommand
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
cmd.UserID = userID
|
||||
|
||||
result, err := h.appService.ApplyContract(c.Request.Context(), &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("申请合同失败", zap.Error(err))
|
||||
h.logger.Error("申请合同失败", zap.Error(err), zap.String("certification_id", cmd.CertificationID))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
@@ -228,161 +198,282 @@ func (h *CertificationHandler) ApplyContract(c *gin.Context) {
|
||||
h.response.Success(c, result, "合同申请成功")
|
||||
}
|
||||
|
||||
// GetContractSignURL 获取合同签署链接
|
||||
// @Summary 获取合同签署链接
|
||||
// @Description 获取e签宝合同签署链接,用户可通过该链接完成合同签署
|
||||
// @Tags 企业认证
|
||||
// ================ 重试操作 ================
|
||||
|
||||
// RetryOperation 重试操作
|
||||
// @Summary 重试操作
|
||||
// @Description 重试失败的企业认证或合同申请操作
|
||||
// @Tags 认证管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Success 200 {object} map[string]interface{} "获取合同签署链接成功"
|
||||
// @Failure 401 {object} map[string]interface{} "用户未登录"
|
||||
// @Failure 400 {object} map[string]interface{} "合同未申请或签署状态异常"
|
||||
// @Param request body commands.RetryOperationCommand true "重试操作请求"
|
||||
// @Success 200 {object} responses.CertificationResponse "重试操作成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "认证记录不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certification/contract-sign-url [get]
|
||||
func (h *CertificationHandler) GetContractSignURL(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
// @Router /api/v1/certifications/retry [post]
|
||||
func (h *CertificationHandler) RetryOperation(c *gin.Context) {
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
cmd := &commands.GetContractSignURLCommand{
|
||||
UserID: userID,
|
||||
var cmd commands.RetryOperationCommand
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
cmd.UserID = userID
|
||||
|
||||
result, err := h.certAppService.GetContractSignURL(c.Request.Context(), cmd)
|
||||
result, err := h.appService.RetryOperation(c.Request.Context(), &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("获取合同签署链接失败", zap.Error(err))
|
||||
h.logger.Error("重试操作失败", zap.Error(err), zap.String("certification_id", cmd.CertificationID))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result, "获取合同签署链接成功")
|
||||
h.response.Success(c, result, "重试操作成功")
|
||||
}
|
||||
|
||||
// EsignCallback e签宝回调
|
||||
// @Summary e签宝回调接口
|
||||
// @Description 接收e签宝认证和签署的回调通知
|
||||
// @Tags 企业认证
|
||||
// ================ 查询操作 ================
|
||||
|
||||
// GetUserCertifications 获取用户认证列表
|
||||
// @Summary 获取用户认证列表
|
||||
// @Description 获取当前用户的认证申请列表
|
||||
// @Tags 认证管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} map[string]interface{} "回调处理成功"
|
||||
// @Failure 400 {object} map[string]interface{} "回调参数错误"
|
||||
// @Security Bearer
|
||||
// @Param status query string false "认证状态"
|
||||
// @Param include_completed query bool false "是否包含已完成"
|
||||
// @Param include_failed query bool false "是否包含失败"
|
||||
// @Param page query int false "页码" default(1)
|
||||
// @Param page_size query int false "每页数量" default(10)
|
||||
// @Success 200 {object} responses.CertificationListResponse "获取用户认证列表成功"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certification/esign-callback [post]
|
||||
func (h *CertificationHandler) EsignCallback(c *gin.Context) {
|
||||
// 记录请求基本信息
|
||||
h.logger.Info("收到e签宝回调请求",
|
||||
zap.String("method", c.Request.Method),
|
||||
zap.String("url", c.Request.URL.String()),
|
||||
zap.String("remote_addr", c.ClientIP()),
|
||||
zap.String("user_agent", c.GetHeader("User-Agent")),
|
||||
)
|
||||
|
||||
// 记录所有请求头
|
||||
headers := make(map[string]string)
|
||||
for key, values := range c.Request.Header {
|
||||
if len(values) > 0 {
|
||||
headers[key] = values[0]
|
||||
}
|
||||
}
|
||||
h.logger.Info("回调请求头信息", zap.Any("headers", headers))
|
||||
|
||||
// 记录URL查询参数
|
||||
queryParams := make(map[string]string)
|
||||
for key, values := range c.Request.URL.Query() {
|
||||
if len(values) > 0 {
|
||||
queryParams[key] = values[0]
|
||||
}
|
||||
}
|
||||
if len(queryParams) > 0 {
|
||||
h.logger.Info("回调URL查询参数", zap.Any("query_params", queryParams))
|
||||
// @Router /api/v1/certifications/user [get]
|
||||
func (h *CertificationHandler) GetUserCertifications(c *gin.Context) {
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
// 读取并记录请求体
|
||||
var requestBody interface{}
|
||||
var callbackData map[string]interface{}
|
||||
if c.Request.Body != nil {
|
||||
// 读取请求体
|
||||
bodyBytes, err := c.GetRawData()
|
||||
if err != nil {
|
||||
h.logger.Error("读取回调请求体失败", zap.Error(err))
|
||||
h.response.BadRequest(c, "读取请求体失败")
|
||||
return
|
||||
}
|
||||
var query queries.GetUserCertificationsQuery
|
||||
if err := h.validator.BindAndValidate(c, &query); err != nil {
|
||||
return
|
||||
}
|
||||
query.UserID = userID
|
||||
|
||||
// 尝试解析为JSON
|
||||
if err := c.ShouldBindJSON(&callbackData); err == nil {
|
||||
requestBody = callbackData
|
||||
} else {
|
||||
// 如果不是JSON,记录原始字符串
|
||||
requestBody = string(bodyBytes)
|
||||
h.logger.Error("回调请求体不是有效的JSON格式", zap.Error(err))
|
||||
h.response.BadRequest(c, "请求体格式错误")
|
||||
return
|
||||
}
|
||||
h.logger.Info("回调请求体内容", zap.Any("body", requestBody))
|
||||
|
||||
// 重新设置请求体,以便后续处理
|
||||
c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||
result, err := h.appService.GetUserCertifications(c.Request.Context(), &query)
|
||||
if err != nil {
|
||||
h.logger.Error("获取用户认证列表失败", zap.Error(err), zap.String("user_id", userID))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 记录Content-Type
|
||||
contentType := c.GetHeader("Content-Type")
|
||||
h.logger.Info("回调请求Content-Type", zap.String("content_type", contentType))
|
||||
|
||||
// 记录Content-Length
|
||||
contentLength := c.GetHeader("Content-Length")
|
||||
if contentLength != "" {
|
||||
h.logger.Info("回调请求Content-Length", zap.String("content_length", contentLength))
|
||||
}
|
||||
|
||||
// 记录时间戳
|
||||
h.logger.Info("回调请求时间",
|
||||
zap.Time("request_time", time.Now()),
|
||||
zap.String("request_id", c.GetHeader("X-Request-ID")),
|
||||
)
|
||||
|
||||
// 记录完整的请求信息摘要
|
||||
h.logger.Info("e签宝回调完整信息摘要",
|
||||
zap.String("method", c.Request.Method),
|
||||
zap.String("url", c.Request.URL.String()),
|
||||
zap.String("client_ip", c.ClientIP()),
|
||||
zap.String("content_type", contentType),
|
||||
zap.Any("headers", headers),
|
||||
zap.Any("query_params", queryParams),
|
||||
zap.Any("body", requestBody),
|
||||
)
|
||||
|
||||
// 处理回调数据
|
||||
if callbackData != nil {
|
||||
// 构建请求头映射
|
||||
headers := make(map[string]string)
|
||||
for key, values := range c.Request.Header {
|
||||
if len(values) > 0 {
|
||||
headers[key] = values[0]
|
||||
}
|
||||
}
|
||||
|
||||
// 构建查询参数映射
|
||||
queryParams := make(map[string]string)
|
||||
for key, values := range c.Request.URL.Query() {
|
||||
if len(values) > 0 {
|
||||
queryParams[key] = values[0]
|
||||
}
|
||||
}
|
||||
|
||||
if err := h.esignCallbackService.HandleCallback(c.Request.Context(), callbackData, headers, queryParams); err != nil {
|
||||
h.logger.Error("处理e签宝回调失败", zap.Error(err))
|
||||
h.response.BadRequest(c, "回调处理失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 返回成功响应
|
||||
c.JSON(200, map[string]interface{}{
|
||||
"code": "200",
|
||||
"msg": "success",
|
||||
})
|
||||
h.response.Success(c, result, "获取用户认证列表成功")
|
||||
}
|
||||
|
||||
// ListCertifications 获取认证列表(管理员)
|
||||
// @Summary 获取认证列表
|
||||
// @Description 管理员获取认证申请列表
|
||||
// @Tags 认证管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param page query int false "页码" default(1)
|
||||
// @Param page_size query int false "每页数量" default(10)
|
||||
// @Param sort_by query string false "排序字段"
|
||||
// @Param sort_order query string false "排序方向" Enums(asc, desc)
|
||||
// @Param status query string false "认证状态"
|
||||
// @Param user_id query string false "用户ID"
|
||||
// @Param company_name query string false "公司名称"
|
||||
// @Param legal_person_name query string false "法人姓名"
|
||||
// @Param search_keyword query string false "搜索关键词"
|
||||
// @Success 200 {object} responses.CertificationListResponse "获取认证列表成功"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 403 {object} map[string]interface{} "权限不足"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certifications [get]
|
||||
func (h *CertificationHandler) ListCertifications(c *gin.Context) {
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
var query queries.ListCertificationsQuery
|
||||
if err := h.validator.BindAndValidate(c, &query); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.appService.ListCertifications(c.Request.Context(), &query)
|
||||
if err != nil {
|
||||
h.logger.Error("获取认证列表失败", zap.Error(err))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result, "获取认证列表成功")
|
||||
}
|
||||
|
||||
// GetCertificationStatistics 获取认证统计
|
||||
// @Summary 获取认证统计
|
||||
// @Description 获取认证相关的统计数据
|
||||
// @Tags 认证管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param start_date query string true "开始日期" format(date)
|
||||
// @Param end_date query string true "结束日期" format(date)
|
||||
// @Param period query string false "统计周期" Enums(daily, weekly, monthly, yearly) default(daily)
|
||||
// @Param group_by query []string false "分组字段"
|
||||
// @Param user_ids query []string false "用户ID列表"
|
||||
// @Param statuses query []string false "状态列表"
|
||||
// @Success 200 {object} responses.CertificationStatisticsResponse "获取认证统计成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certifications/statistics [get]
|
||||
func (h *CertificationHandler) GetCertificationStatistics(c *gin.Context) {
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
var query queries.GetCertificationStatisticsQuery
|
||||
if err := h.validator.BindAndValidate(c, &query); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.appService.GetCertificationStatistics(c.Request.Context(), &query)
|
||||
if err != nil {
|
||||
h.logger.Error("获取认证统计失败", zap.Error(err))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result, "获取认证统计成功")
|
||||
}
|
||||
|
||||
// ================ 回调处理 ================
|
||||
|
||||
// HandleEsignCallback 处理e签宝回调
|
||||
// @Summary 处理e签宝回调
|
||||
// @Description 处理e签宝的企业认证和合同签署回调
|
||||
// @Tags 认证管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body commands.EsignCallbackCommand true "e签宝回调数据"
|
||||
// @Success 200 {object} responses.CallbackResponse "回调处理成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certifications/callbacks [post]
|
||||
func (h *CertificationHandler) HandleEsignCallback(c *gin.Context) {
|
||||
var cmd commands.EsignCallbackCommand
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.appService.HandleEsignCallback(c.Request.Context(), &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("处理e签宝回调失败", zap.Error(err), zap.String("certification_id", cmd.CertificationID))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result, "回调处理成功")
|
||||
}
|
||||
|
||||
// ================ 管理员操作 ================
|
||||
|
||||
// ForceTransitionStatus 强制状态转换(管理员)
|
||||
// @Summary 强制状态转换
|
||||
// @Description 管理员强制转换认证状态
|
||||
// @Tags 认证管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param request body commands.ForceTransitionStatusCommand 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/force-transition [post]
|
||||
func (h *CertificationHandler) ForceTransitionStatus(c *gin.Context) {
|
||||
adminID := h.getCurrentUserID(c)
|
||||
if adminID == "" {
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
var cmd commands.ForceTransitionStatusCommand
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
cmd.AdminID = adminID
|
||||
|
||||
result, err := h.appService.ForceTransitionStatus(c.Request.Context(), &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("强制状态转换失败", zap.Error(err), zap.String("certification_id", cmd.CertificationID))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result, "状态转换成功")
|
||||
}
|
||||
|
||||
// GetSystemMonitoring 获取系统监控数据
|
||||
// @Summary 获取系统监控数据
|
||||
// @Description 获取认证系统的监控数据
|
||||
// @Tags 认证管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param time_range query string false "时间范围" Enums(1h, 6h, 24h, 7d, 30d) default(24h)
|
||||
// @Param metrics query []string false "监控指标"
|
||||
// @Success 200 {object} responses.SystemMonitoringResponse "获取系统监控数据成功"
|
||||
// @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/monitoring [get]
|
||||
func (h *CertificationHandler) GetSystemMonitoring(c *gin.Context) {
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
var query queries.GetSystemMonitoringQuery
|
||||
if err := h.validator.BindAndValidate(c, &query); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.appService.GetSystemMonitoring(c.Request.Context(), &query)
|
||||
if err != nil {
|
||||
h.logger.Error("获取系统监控数据失败", zap.Error(err))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result, "获取系统监控数据成功")
|
||||
}
|
||||
|
||||
// ================ 辅助方法 ================
|
||||
|
||||
// getCurrentUserID 获取当前用户ID
|
||||
func (h *CertificationHandler) getCurrentUserID(c *gin.Context) string {
|
||||
if userID, exists := c.Get("user_id"); exists {
|
||||
if id, ok := userID.(string); ok {
|
||||
return id
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -1,58 +1,100 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"tyapi-server/internal/infrastructure/http/handlers"
|
||||
sharedhttp "tyapi-server/internal/shared/http"
|
||||
"tyapi-server/internal/shared/middleware"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"tyapi-server/internal/infrastructure/http/handlers"
|
||||
"tyapi-server/internal/shared/http"
|
||||
"tyapi-server/internal/shared/middleware"
|
||||
)
|
||||
|
||||
// CertificationRoutes 认证路由注册器
|
||||
// CertificationRoutes 认证路由
|
||||
type CertificationRoutes struct {
|
||||
handler *handlers.CertificationHandler
|
||||
authMiddleware *middleware.JWTAuthMiddleware
|
||||
logger *zap.Logger
|
||||
handler *handlers.CertificationHandler
|
||||
router *http.GinRouter
|
||||
logger *zap.Logger
|
||||
auth *middleware.JWTAuthMiddleware
|
||||
optional *middleware.OptionalAuthMiddleware
|
||||
}
|
||||
|
||||
// NewCertificationRoutes 创建认证路由注册器
|
||||
// NewCertificationRoutes 创建认证路由
|
||||
func NewCertificationRoutes(
|
||||
handler *handlers.CertificationHandler,
|
||||
authMiddleware *middleware.JWTAuthMiddleware,
|
||||
router *http.GinRouter,
|
||||
logger *zap.Logger,
|
||||
auth *middleware.JWTAuthMiddleware,
|
||||
optional *middleware.OptionalAuthMiddleware,
|
||||
) *CertificationRoutes {
|
||||
return &CertificationRoutes{
|
||||
handler: handler,
|
||||
authMiddleware: authMiddleware,
|
||||
logger: logger,
|
||||
handler: handler,
|
||||
router: router,
|
||||
logger: logger,
|
||||
auth: auth,
|
||||
optional: optional,
|
||||
}
|
||||
}
|
||||
|
||||
// Register 注册认证相关路由
|
||||
func (r *CertificationRoutes) Register(router *sharedhttp.GinRouter) {
|
||||
// 认证相关路由组
|
||||
engine := router.GetEngine()
|
||||
certificationGroup := engine.Group("/api/v1/certification")
|
||||
certificationGroup.Use(r.authMiddleware.Handle())
|
||||
// Register 注册认证路由
|
||||
func (r *CertificationRoutes) Register(router *http.GinRouter) {
|
||||
// 认证管理路由组
|
||||
certificationGroup := router.GetEngine().Group("/api/v1/certifications")
|
||||
{
|
||||
// 认证状态查询
|
||||
certificationGroup.GET("/status", r.handler.GetCertificationStatus) // 获取认证状态
|
||||
certificationGroup.GET("/details", r.handler.GetCertificationDetails) // 获取认证详情
|
||||
certificationGroup.GET("/progress", r.handler.GetCertificationProgress) // 获取认证进度
|
||||
// 需要认证的路由
|
||||
authGroup := certificationGroup.Group("")
|
||||
authGroup.Use(r.auth.Handle())
|
||||
{
|
||||
authGroup.GET("/user", r.handler.GetUserCertifications) // 获取用户认证列表
|
||||
authGroup.GET("", r.handler.ListCertifications) // 查询认证列表(管理员)
|
||||
authGroup.GET("/statistics", r.handler.GetCertificationStatistics) // 获取认证统计
|
||||
|
||||
// 企业信息管理
|
||||
certificationGroup.POST("/submit-enterprise-info", r.handler.SubmitEnterpriseInfo) // 提交企业信息(自动创建认证申请)
|
||||
// 1. 获取认证详情
|
||||
authGroup.GET("/:id", r.handler.GetCertification)
|
||||
|
||||
// 企业认证
|
||||
certificationGroup.GET("/enterprise-auth-url", r.handler.GetEnterpriseAuthURL) // 获取企业认证链接
|
||||
// 2. 提交企业信息
|
||||
authGroup.POST("/:id/enterprise-info", r.handler.SubmitEnterpriseInfo)
|
||||
|
||||
// 合同管理
|
||||
certificationGroup.POST("/apply-contract", r.handler.ApplyContract) // 申请合同
|
||||
certificationGroup.GET("/contract-sign-url", r.handler.GetContractSignURL) // 获取合同签署链接
|
||||
// 合同管理
|
||||
authGroup.POST("/apply-contract", r.handler.ApplyContract) // 申请合同签署
|
||||
|
||||
// 重试操作
|
||||
authGroup.POST("/retry", r.handler.RetryOperation) // 重试操作
|
||||
|
||||
// 管理员操作
|
||||
authGroup.POST("/force-transition", r.handler.ForceTransitionStatus) // 强制状态转换
|
||||
authGroup.GET("/monitoring", r.handler.GetSystemMonitoring) // 获取系统监控数据
|
||||
}
|
||||
|
||||
// 回调路由(不需要认证,但需要验证签名)
|
||||
callbackGroup := certificationGroup.Group("/callbacks")
|
||||
{
|
||||
callbackGroup.POST("", r.handler.HandleEsignCallback) // e签宝回调(统一处理企业认证和合同签署回调)
|
||||
}
|
||||
}
|
||||
callbackGroup := engine.Group("/api/v1/certification")
|
||||
// e签宝回调
|
||||
callbackGroup.POST("/esign-callback", r.handler.EsignCallback) // e签宝回调
|
||||
|
||||
r.logger.Info("认证路由注册完成")
|
||||
}
|
||||
|
||||
// GetRoutes 获取路由信息(用于调试)
|
||||
func (r *CertificationRoutes) GetRoutes() []RouteInfo {
|
||||
return []RouteInfo{
|
||||
{Method: "POST", Path: "/api/v1/certifications", Handler: "CreateCertification", Auth: true},
|
||||
{Method: "GET", Path: "/api/v1/certifications/:id", Handler: "GetCertification", Auth: true},
|
||||
{Method: "GET", Path: "/api/v1/certifications/user", Handler: "GetUserCertifications", Auth: true},
|
||||
{Method: "GET", Path: "/api/v1/certifications", Handler: "ListCertifications", Auth: true},
|
||||
{Method: "GET", Path: "/api/v1/certifications/statistics", Handler: "GetCertificationStatistics", Auth: true},
|
||||
{Method: "POST", Path: "/api/v1/certifications/:id/enterprise-info", Handler: "SubmitEnterpriseInfo", Auth: true},
|
||||
{Method: "POST", Path: "/api/v1/certifications/apply-contract", Handler: "ApplyContract", Auth: true},
|
||||
{Method: "POST", Path: "/api/v1/certifications/retry", Handler: "RetryOperation", Auth: true},
|
||||
{Method: "POST", Path: "/api/v1/certifications/force-transition", Handler: "ForceTransitionStatus", Auth: true},
|
||||
{Method: "GET", Path: "/api/v1/certifications/monitoring", Handler: "GetSystemMonitoring", Auth: true},
|
||||
{Method: "POST", Path: "/api/v1/certifications/callbacks", Handler: "HandleEsignCallback", Auth: false},
|
||||
}
|
||||
}
|
||||
|
||||
// RouteInfo 路由信息
|
||||
type RouteInfo struct {
|
||||
Method string
|
||||
Path string
|
||||
Handler string
|
||||
Auth bool
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user