This commit is contained in:
2026-04-21 22:36:48 +08:00
commit 488c695fdf
748 changed files with 266838 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
package repositories
import (
"context"
"hyapi-server/internal/domains/certification/entities"
"hyapi-server/internal/domains/certification/enums"
"hyapi-server/internal/shared/interfaces"
)
// CertificationCommandRepository 认证命令仓储接口
// 专门处理认证数据的变更操作符合CQRS模式
type CertificationCommandRepository interface {
// 基础CRUD操作
Create(ctx context.Context, cert entities.Certification) error
Update(ctx context.Context, cert entities.Certification) error
Delete(ctx context.Context, id string) error
// 业务特定的更新操作
UpdateStatus(ctx context.Context, id string, status enums.CertificationStatus) error
UpdateAuthFlowID(ctx context.Context, id string, authFlowID string) error
UpdateContractInfo(ctx context.Context, id string, contractFileID, esignFlowID, contractURL, contractSignURL string) error
UpdateFailureInfo(ctx context.Context, id string, reason enums.FailureReason, message string) error
// 批量操作
BatchUpdateStatus(ctx context.Context, ids []string, status enums.CertificationStatus) error
// 事务支持
WithTx(tx interfaces.Transaction) CertificationCommandRepository
}

View File

@@ -0,0 +1,89 @@
package repositories
import (
"context"
"time"
"hyapi-server/internal/domains/certification/entities"
"hyapi-server/internal/domains/certification/enums"
"hyapi-server/internal/domains/certification/repositories/queries"
)
// CertificationQueryRepository 认证查询仓储接口
// 专门处理认证数据的查询操作符合CQRS模式
type CertificationQueryRepository interface {
// 基础查询操作
GetByID(ctx context.Context, id string) (*entities.Certification, error)
GetByUserID(ctx context.Context, userID string) (*entities.Certification, error)
Exists(ctx context.Context, id string) (bool, error)
ExistsByUserID(ctx context.Context, userID string) (bool, error)
// 列表查询
List(ctx context.Context, query *queries.ListCertificationsQuery) ([]*entities.Certification, int64, error)
ListByUserIDs(ctx context.Context, userIDs []string) ([]*entities.Certification, error)
ListByStatus(ctx context.Context, status enums.CertificationStatus, limit int) ([]*entities.Certification, error)
// 业务查询
FindByAuthFlowID(ctx context.Context, authFlowID string) (*entities.Certification, error)
FindByEsignFlowID(ctx context.Context, esignFlowID string) (*entities.Certification, error)
ListPendingRetry(ctx context.Context, maxRetryCount int) ([]*entities.Certification, error)
GetPendingCertifications(ctx context.Context) ([]*entities.Certification, error)
GetExpiredContracts(ctx context.Context) ([]*entities.Certification, error)
GetCertificationsByDateRange(ctx context.Context, startDate, endDate time.Time) ([]*entities.Certification, error)
GetUserActiveCertification(ctx context.Context, userID string) (*entities.Certification, error)
CountByFailureReason(ctx context.Context, reason enums.FailureReason) (int64, error)
GetProgressStatistics(ctx context.Context) (*CertificationProgressStats, error)
// 搜索查询
SearchByCompanyName(ctx context.Context, companyName string, limit int) ([]*entities.Certification, error)
SearchByLegalPerson(ctx context.Context, legalPersonName string, limit int) ([]*entities.Certification, error)
// 缓存相关
InvalidateCache(ctx context.Context, keys ...string) error
RefreshCache(ctx context.Context, certificationID string) error
}
// CertificationTimePeriod 时间周期枚举
type CertificationTimePeriod string
const (
PeriodDaily CertificationTimePeriod = "daily"
PeriodWeekly CertificationTimePeriod = "weekly"
PeriodMonthly CertificationTimePeriod = "monthly"
PeriodYearly CertificationTimePeriod = "yearly"
)
// CertificationProgressStats 进度统计信息
type CertificationProgressStats struct {
StatusProgress map[enums.CertificationStatus]int64 `json:"status_progress"`
ProgressDistribution map[int]int64 `json:"progress_distribution"` // key: progress percentage
// 各阶段耗时统计
StageTimeStats map[string]*CertificationStageTimeInfo `json:"stage_time_stats"`
}
// CertificationStageTimeInfo 阶段耗时信息
type CertificationStageTimeInfo struct {
StageName string `json:"stage_name"`
AverageTime time.Duration `json:"average_time"`
MinTime time.Duration `json:"min_time"`
MaxTime time.Duration `json:"max_time"`
SampleCount int64 `json:"sample_count"`
}
// CertificationRetryStats 重试统计信息
type CertificationRetryStats struct {
TotalRetries int64 `json:"total_retries"`
SuccessfulRetries int64 `json:"successful_retries"`
FailedRetries int64 `json:"failed_retries"`
RetrySuccessRate float64 `json:"retry_success_rate"`
// 各阶段重试统计
EnterpriseRetries int64 `json:"enterprise_retries"`
ContractRetries int64 `json:"contract_retries"`
// 重试原因分布
RetryReasonStats map[enums.FailureReason]int64 `json:"retry_reason_stats"`
}

View File

@@ -0,0 +1,34 @@
package repositories
import (
"context"
"hyapi-server/internal/domains/certification/entities"
)
// ListSubmitRecordsFilter 提交记录列表筛选(以状态机 certification 状态为准)
type ListSubmitRecordsFilter struct {
CertificationStatus string // 认证状态筛选,如 info_pending_review / info_submitted / info_rejected空为全部
CompanyName string // 企业名称(模糊搜索)
LegalPersonPhone string // 法人手机号
LegalPersonName string // 法人姓名(模糊搜索)
Page int
PageSize int
}
// ListSubmitRecordsResult 列表结果
type ListSubmitRecordsResult struct {
Records []*entities.EnterpriseInfoSubmitRecord
Total int64
}
type EnterpriseInfoSubmitRecordRepository interface {
Create(ctx context.Context, record *entities.EnterpriseInfoSubmitRecord) error
Update(ctx context.Context, record *entities.EnterpriseInfoSubmitRecord) error
Exists(ctx context.Context, ID string) (bool, error)
FindByID(ctx context.Context, id string) (*entities.EnterpriseInfoSubmitRecord, error)
FindLatestByUserID(ctx context.Context, userID string) (*entities.EnterpriseInfoSubmitRecord, error)
FindLatestVerifiedByUserID(ctx context.Context, userID string) (*entities.EnterpriseInfoSubmitRecord, error)
// ExistsByUnifiedSocialCodeExcludeUser 检查该统一社会信用代码是否已被其他用户提交(已提交/已通过验证,排除指定用户)
ExistsByUnifiedSocialCodeExcludeUser(ctx context.Context, unifiedSocialCode string, excludeUserID string) (bool, error)
List(ctx context.Context, filter ListSubmitRecordsFilter) (*ListSubmitRecordsResult, error)
}

View File

@@ -0,0 +1,279 @@
package queries
import (
"fmt"
"time"
"hyapi-server/internal/domains/certification/enums"
)
// GetCertificationQuery 获取单个认证查询
type GetCertificationQuery struct {
ID string `json:"id" validate:"required"`
UserID string `json:"user_id,omitempty"` // 可选的用户ID用于权限验证
}
// ListCertificationsQuery 认证列表查询
type ListCertificationsQuery struct {
// 分页参数
Page int `json:"page" validate:"min=1"`
PageSize int `json:"page_size" validate:"min=1,max=100"`
// 排序参数
SortBy string `json:"sort_by"` // 排序字段: created_at, updated_at, status, progress
SortOrder string `json:"sort_order"` // 排序方向: asc, desc
// 过滤条件
UserID string `json:"user_id,omitempty"`
Status enums.CertificationStatus `json:"status,omitempty"`
Statuses []enums.CertificationStatus `json:"statuses,omitempty"`
FailureReason enums.FailureReason `json:"failure_reason,omitempty"`
// 时间范围过滤
CreatedAfter *time.Time `json:"created_after,omitempty"`
CreatedBefore *time.Time `json:"created_before,omitempty"`
UpdatedAfter *time.Time `json:"updated_after,omitempty"`
UpdatedBefore *time.Time `json:"updated_before,omitempty"`
// 企业信息过滤
CompanyName string `json:"company_name,omitempty"`
LegalPersonName string `json:"legal_person_name,omitempty"`
// 业务状态过滤
IsCompleted *bool `json:"is_completed,omitempty"`
IsFailed *bool `json:"is_failed,omitempty"`
IsUserActionRequired *bool `json:"is_user_action_required,omitempty"`
// 高级过滤
MinRetryCount *int `json:"min_retry_count,omitempty"`
MaxRetryCount *int `json:"max_retry_count,omitempty"`
MinProgress *int `json:"min_progress,omitempty"`
MaxProgress *int `json:"max_progress,omitempty"`
// 搜索参数
SearchKeyword string `json:"search_keyword,omitempty"` // 通用搜索关键词
// 包含关联数据
IncludeMetadata bool `json:"include_metadata,omitempty"`
}
// DefaultValues 设置默认值
func (q *ListCertificationsQuery) DefaultValues() {
if q.Page <= 0 {
q.Page = 1
}
if q.PageSize <= 0 {
q.PageSize = 20
}
if q.SortBy == "" {
q.SortBy = "created_at"
}
if q.SortOrder == "" {
q.SortOrder = "desc"
}
}
// GetOffset 计算分页偏移量
func (q *ListCertificationsQuery) GetOffset() int {
return (q.Page - 1) * q.PageSize
}
// GetLimit 获取查询限制数量
func (q *ListCertificationsQuery) GetLimit() int {
return q.PageSize
}
// HasTimeFilter 检查是否有时间过滤条件
func (q *ListCertificationsQuery) HasTimeFilter() bool {
return q.CreatedAfter != nil || q.CreatedBefore != nil ||
q.UpdatedAfter != nil || q.UpdatedBefore != nil
}
// HasStatusFilter 检查是否有状态过滤条件
func (q *ListCertificationsQuery) HasStatusFilter() bool {
return q.Status != "" || len(q.Statuses) > 0
}
// HasSearchFilter 检查是否有搜索过滤条件
func (q *ListCertificationsQuery) HasSearchFilter() bool {
return q.CompanyName != "" || q.LegalPersonName != "" || q.SearchKeyword != ""
}
// GetSearchFields 获取搜索字段映射
func (q *ListCertificationsQuery) GetSearchFields() map[string]string {
fields := make(map[string]string)
if q.CompanyName != "" {
fields["company_name"] = q.CompanyName
}
if q.LegalPersonName != "" {
fields["legal_person_name"] = q.LegalPersonName
}
if q.SearchKeyword != "" {
fields["keyword"] = q.SearchKeyword
}
return fields
}
// CertificationStatisticsQuery 认证统计查询
type CertificationStatisticsQuery struct {
// 时间范围
StartDate time.Time `json:"start_date" validate:"required"`
EndDate time.Time `json:"end_date" validate:"required"`
// 统计周期
Period string `json:"period" validate:"oneof=daily weekly monthly yearly"`
// 分组维度
GroupBy []string `json:"group_by,omitempty"` // status, failure_reason, user_type, date
// 过滤条件
UserIDs []string `json:"user_ids,omitempty"`
Statuses []enums.CertificationStatus `json:"statuses,omitempty"`
// 统计类型
IncludeProgressStats bool `json:"include_progress_stats,omitempty"`
IncludeRetryStats bool `json:"include_retry_stats,omitempty"`
IncludeTimeStats bool `json:"include_time_stats,omitempty"`
}
// Validate 验证统计查询参数
func (q *CertificationStatisticsQuery) Validate() error {
if q.EndDate.Before(q.StartDate) {
return fmt.Errorf("结束时间不能早于开始时间")
}
// 检查时间范围是否合理不超过1年
if q.EndDate.Sub(q.StartDate) > 365*24*time.Hour {
return fmt.Errorf("查询时间范围不能超过1年")
}
return nil
}
// GetTimeRange 获取时间范围描述
func (q *CertificationStatisticsQuery) GetTimeRange() string {
return fmt.Sprintf("%s 到 %s",
q.StartDate.Format("2006-01-02"),
q.EndDate.Format("2006-01-02"))
}
// SearchCertificationsQuery 搜索认证查询
type SearchCertificationsQuery struct {
// 搜索关键词
Keyword string `json:"keyword" validate:"required,min=2"`
// 搜索字段
SearchFields []string `json:"search_fields,omitempty"` // company_name, legal_person_name, unified_social_code
// 过滤条件
Statuses []enums.CertificationStatus `json:"statuses,omitempty"`
UserID string `json:"user_id,omitempty"`
// 分页参数
Page int `json:"page" validate:"min=1"`
PageSize int `json:"page_size" validate:"min=1,max=50"`
// 排序参数
SortBy string `json:"sort_by"`
SortOrder string `json:"sort_order"`
// 搜索选项
ExactMatch bool `json:"exact_match,omitempty"` // 是否精确匹配
IgnoreCase bool `json:"ignore_case,omitempty"` // 是否忽略大小写
}
// DefaultValues 设置搜索查询默认值
func (q *SearchCertificationsQuery) DefaultValues() {
if q.Page <= 0 {
q.Page = 1
}
if q.PageSize <= 0 {
q.PageSize = 10
}
if q.SortBy == "" {
q.SortBy = "created_at"
}
if q.SortOrder == "" {
q.SortOrder = "desc"
}
if len(q.SearchFields) == 0 {
q.SearchFields = []string{"company_name", "legal_person_name"}
}
// 默认忽略大小写
q.IgnoreCase = true
}
// GetLimit 获取查询限制数量
func (q *SearchCertificationsQuery) GetLimit() int {
return q.PageSize
}
// GetSearchPattern 获取搜索模式
func (q *SearchCertificationsQuery) GetSearchPattern() string {
if q.ExactMatch {
return q.Keyword
}
// 模糊搜索,添加通配符
return "%" + q.Keyword + "%"
}
// UserCertificationsQuery 用户认证查询
type UserCertificationsQuery struct {
UserID string `json:"user_id" validate:"required"`
// 状态过滤
Status enums.CertificationStatus `json:"status,omitempty"`
IncludeCompleted bool `json:"include_completed,omitempty"`
IncludeFailed bool `json:"include_failed,omitempty"`
// 时间过滤
After *time.Time `json:"after,omitempty"`
Before *time.Time `json:"before,omitempty"`
// 分页
Page int `json:"page"`
PageSize int `json:"page_size"`
// 排序
SortBy string `json:"sort_by"`
SortOrder string `json:"sort_order"`
}
// DefaultValues 设置用户认证查询默认值
func (q *UserCertificationsQuery) DefaultValues() {
if q.Page <= 0 {
q.Page = 1
}
if q.PageSize <= 0 {
q.PageSize = 10
}
if q.SortBy == "" {
q.SortBy = "created_at"
}
if q.SortOrder == "" {
q.SortOrder = "desc"
}
}
// ShouldIncludeStatus 检查是否应该包含指定状态
func (q *UserCertificationsQuery) ShouldIncludeStatus(status enums.CertificationStatus) bool {
// 如果指定了特定状态,只返回该状态
if q.Status != "" {
return status == q.Status
}
// 根据包含选项决定
if enums.IsFinalStatus(status) && !q.IncludeCompleted {
return false
}
if enums.IsFailureStatus(status) && !q.IncludeFailed {
return false
}
return true
}