package certification import ( "context" "fmt" "tyapi-server/internal/application/certification/dto/commands" "tyapi-server/internal/application/certification/dto/queries" "tyapi-server/internal/application/certification/dto/responses" "tyapi-server/internal/domains/certification/entities" "tyapi-server/internal/domains/certification/enums" "tyapi-server/internal/domains/certification/repositories" "tyapi-server/internal/domains/certification/services" "tyapi-server/internal/domains/certification/services/state_machine" "go.uber.org/zap" ) // CertificationApplicationServiceImpl 认证应用服务实现 // 负责用例协调,DTO转换,是应用层的核心组件 type CertificationApplicationServiceImpl struct { // 领域服务依赖 aggregateService services.CertificationAggregateService workflowOrchestrator services.CertificationWorkflowOrchestrator // 仓储依赖 queryRepository repositories.CertificationQueryRepository // 基础设施依赖 callbackHandler *state_machine.EsignCallbackHandler logger *zap.Logger } // NewCertificationApplicationService 创建认证应用服务 func NewCertificationApplicationService( aggregateService services.CertificationAggregateService, workflowOrchestrator services.CertificationWorkflowOrchestrator, queryRepository repositories.CertificationQueryRepository, callbackHandler *state_machine.EsignCallbackHandler, logger *zap.Logger, ) CertificationApplicationService { return &CertificationApplicationServiceImpl{ aggregateService: aggregateService, workflowOrchestrator: workflowOrchestrator, queryRepository: queryRepository, callbackHandler: callbackHandler, logger: logger, } } // ================ 用户操作用例 ================ // CreateCertification 创建认证申请 func (s *CertificationApplicationServiceImpl) CreateCertification( ctx context.Context, cmd *commands.CreateCertificationCommand, ) (*responses.CertificationResponse, error) { s.logger.Info("开始创建认证申请", zap.String("user_id", cmd.UserID)) // 1. 调用聚合服务创建认证 cert, err := s.aggregateService.CreateCertification(ctx, cmd.UserID) if err != nil { s.logger.Error("创建认证申请失败", zap.Error(err), zap.String("user_id", cmd.UserID)) return nil, fmt.Errorf("创建认证申请失败: %w", err) } // 2. 转换为响应DTO response := s.convertToResponse(cert) s.logger.Info("认证申请创建成功", zap.String("user_id", cmd.UserID), zap.String("certification_id", cert.ID)) return response, nil } // SubmitEnterpriseInfo 提交企业信息 func (s *CertificationApplicationServiceImpl) SubmitEnterpriseInfo( ctx context.Context, cmd *commands.SubmitEnterpriseInfoCommand, ) (*responses.CertificationResponse, error) { s.logger.Info("开始提交企业信息", zap.String("certification_id", cmd.CertificationID), zap.String("user_id", cmd.UserID)) // 1. 构建工作流命令 workflowCmd := &services.SubmitEnterpriseInfoCommand{ CertificationID: cmd.CertificationID, UserID: cmd.UserID, EnterpriseInfo: cmd.EnterpriseInfo, } // 2. 执行工作流 workflowResult, err := s.workflowOrchestrator.SubmitEnterpriseInfo(ctx, workflowCmd) if err != nil { s.logger.Error("提交企业信息失败", zap.Error(err)) return nil, fmt.Errorf("提交企业信息失败: %w", err) } // 3. 加载最新的认证信息 cert, err := s.aggregateService.LoadCertification(ctx, cmd.CertificationID) if err != nil { s.logger.Error("加载认证信息失败", zap.Error(err)) return nil, fmt.Errorf("加载认证信息失败: %w", err) } // 4. 转换为响应DTO response := s.convertToResponse(cert) // 5. 添加工作流结果信息 if workflowResult.Data != nil { response.Metadata = workflowResult.Data } s.logger.Info("企业信息提交成功", zap.String("certification_id", cmd.CertificationID)) return response, nil } // ApplyContract 申请合同签署 func (s *CertificationApplicationServiceImpl) ApplyContract( ctx context.Context, cmd *commands.ApplyContractCommand, ) (*responses.ContractSignUrlResponse, error) { s.logger.Info("开始申请合同签署", zap.String("certification_id", cmd.CertificationID), zap.String("user_id", cmd.UserID)) // 1. 构建工作流命令 workflowCmd := &services.ApplyContractCommand{ CertificationID: cmd.CertificationID, UserID: cmd.UserID, } // 2. 执行工作流 workflowResult, err := s.workflowOrchestrator.ApplyContract(ctx, workflowCmd) if err != nil { s.logger.Error("申请合同签署失败", zap.Error(err)) return nil, fmt.Errorf("申请合同签署失败: %w", err) } // 3. 从工作流结果提取签署URL信息 signURL, _ := workflowResult.Data["contract_sign_url"].(string) contractURL, _ := workflowResult.Data["contract_url"].(string) nextAction, _ := workflowResult.Data["next_action"].(string) // 4. 构建响应 response := responses.NewContractSignUrlResponse( cmd.CertificationID, signURL, contractURL, nextAction, workflowResult.Message, ) s.logger.Info("合同申请成功", zap.String("certification_id", cmd.CertificationID)) return response, nil } // RetryOperation 重试失败操作 func (s *CertificationApplicationServiceImpl) RetryOperation( ctx context.Context, cmd *commands.RetryOperationCommand, ) (*responses.CertificationResponse, error) { s.logger.Info("开始重试操作", zap.String("certification_id", cmd.CertificationID), zap.String("operation", cmd.Operation)) // 1. 执行重试工作流 workflowResult, err := s.workflowOrchestrator.RetryOperation(ctx, cmd.CertificationID, cmd.Operation) if err != nil { s.logger.Error("重试操作失败", zap.Error(err)) return nil, fmt.Errorf("重试操作失败: %w", err) } // 2. 加载最新的认证信息 cert, err := s.aggregateService.LoadCertification(ctx, cmd.CertificationID) if err != nil { s.logger.Error("加载认证信息失败", zap.Error(err)) return nil, fmt.Errorf("加载认证信息失败: %w", err) } // 3. 转换为响应DTO response := s.convertToResponse(cert) // 4. 添加重试结果信息 if workflowResult.Data != nil { response.Metadata = workflowResult.Data } s.logger.Info("重试操作成功", zap.String("certification_id", cmd.CertificationID)) return response, nil } // ================ 查询用例 ================ // GetCertification 获取认证详情 func (s *CertificationApplicationServiceImpl) GetCertification( ctx context.Context, query *queries.GetCertificationQuery, ) (*responses.CertificationResponse, error) { s.logger.Debug("获取认证详情", zap.String("certification_id", query.CertificationID)) // 1. 从查询仓储获取认证信息 cert, err := s.queryRepository.GetByID(ctx, query.CertificationID) if err != nil { s.logger.Error("获取认证信息失败", zap.Error(err)) return nil, fmt.Errorf("认证信息不存在: %w", err) } // 2. 权限验证(如果提供了用户ID) if query.UserID != "" && cert.UserID != query.UserID { return nil, fmt.Errorf("无权限访问此认证信息") } // 3. 转换为响应DTO response := s.convertToResponse(cert) return response, nil } // GetUserCertifications 获取用户认证列表 func (s *CertificationApplicationServiceImpl) GetUserCertifications( ctx context.Context, query *queries.GetUserCertificationsQuery, ) (*responses.CertificationListResponse, error) { s.logger.Debug("获取用户认证列表", zap.String("user_id", query.UserID)) // 1. 转换为通用列表查询对象 domainQuery := &queries.ListCertificationsQuery{ Page: query.Page, PageSize: query.PageSize, UserID: query.UserID, Status: query.Status, } // 根据包含选项设置状态过滤 if !query.IncludeCompleted && !query.IncludeFailed { // 只显示进行中的认证 domainQuery.Statuses = []enums.CertificationStatus{ enums.StatusPending, enums.StatusInfoSubmitted, enums.StatusEnterpriseVerified, enums.StatusContractApplied, } } // 转换为领域查询对象 listQuery := domainQuery.ToDomainQuery() // 2. 执行查询 certs, total, err := s.queryRepository.List(ctx, listQuery) if err != nil { s.logger.Error("查询用户认证列表失败", zap.Error(err)) return nil, fmt.Errorf("查询用户认证列表失败: %w", err) } // 3. 转换为响应DTO items := make([]*responses.CertificationResponse, len(certs)) for i, cert := range certs { items[i] = s.convertToResponse(cert) } // 4. 构建列表响应 response := responses.NewCertificationListResponse(items, total, query.Page, query.PageSize) return response, nil } // ListCertifications 获取认证列表(管理员) func (s *CertificationApplicationServiceImpl) ListCertifications( ctx context.Context, query *queries.ListCertificationsQuery, ) (*responses.CertificationListResponse, error) { s.logger.Debug("获取认证列表(管理员)") // 1. 转换为领域查询对象 domainQuery := query.ToDomainQuery() // 2. 执行查询 certs, total, err := s.queryRepository.List(ctx, domainQuery) if err != nil { s.logger.Error("查询认证列表失败", zap.Error(err)) return nil, fmt.Errorf("查询认证列表失败: %w", err) } // 3. 转换为响应DTO items := make([]*responses.CertificationResponse, len(certs)) for i, cert := range certs { items[i] = s.convertToResponse(cert) } // 4. 构建列表响应 response := responses.NewCertificationListResponse(items, total, query.Page, query.PageSize) return response, nil } // SearchCertifications 搜索认证 func (s *CertificationApplicationServiceImpl) SearchCertifications( ctx context.Context, query *queries.SearchCertificationsQuery, ) (*responses.CertificationListResponse, error) { s.logger.Debug("搜索认证", zap.String("keyword", query.Keyword)) // 1. 转换为领域查询对象 domainQuery := query.ToDomainQuery() // 2. 根据搜索字段选择不同的搜索方法 var certs []*entities.Certification var total int64 var err error if len(domainQuery.SearchFields) == 1 { switch domainQuery.SearchFields[0] { case "company_name": certs, err = s.queryRepository.SearchByCompanyName(ctx, domainQuery.Keyword, domainQuery.GetLimit()) total = int64(len(certs)) // 简化实现,实际应该有单独的计数方法 case "legal_person_name": certs, err = s.queryRepository.SearchByLegalPerson(ctx, domainQuery.Keyword, domainQuery.GetLimit()) total = int64(len(certs)) default: // 通用搜索,这里简化为按公司名搜索 certs, err = s.queryRepository.SearchByCompanyName(ctx, domainQuery.Keyword, domainQuery.GetLimit()) total = int64(len(certs)) } } else { // 多字段搜索,这里简化为按公司名搜索 certs, err = s.queryRepository.SearchByCompanyName(ctx, domainQuery.Keyword, domainQuery.GetLimit()) total = int64(len(certs)) } if err != nil { s.logger.Error("搜索认证失败", zap.Error(err)) return nil, fmt.Errorf("搜索认证失败: %w", err) } // 3. 转换为响应DTO items := make([]*responses.CertificationResponse, len(certs)) for i, cert := range certs { items[i] = s.convertToResponse(cert) } // 4. 构建列表响应 response := responses.NewCertificationListResponse(items, total, query.Page, query.PageSize) return response, nil } // GetCertificationStatistics 获取认证统计 func (s *CertificationApplicationServiceImpl) GetCertificationStatistics( ctx context.Context, query *queries.GetCertificationStatisticsQuery, ) (*responses.CertificationStatisticsResponse, error) { s.logger.Debug("获取认证统计", zap.String("period", query.Period)) // 1. 转换为领域查询对象 domainQuery := query.ToDomainQuery() // 2. 验证查询参数 if err := domainQuery.Validate(); err != nil { return nil, fmt.Errorf("统计查询参数无效: %w", err) } // 3. 确定时间周期 var period repositories.CertificationTimePeriod switch query.Period { case "daily": period = repositories.PeriodDaily case "weekly": period = repositories.PeriodWeekly case "monthly": period = repositories.PeriodMonthly case "yearly": period = repositories.PeriodYearly default: period = repositories.PeriodDaily } // 4. 获取统计数据 stats, err := s.queryRepository.GetStatistics(ctx, period) if err != nil { s.logger.Error("获取认证统计失败", zap.Error(err)) return nil, fmt.Errorf("获取认证统计失败: %w", err) } // 5. 获取进度统计(如果需要) var progressStats *repositories.CertificationProgressStats if query.IncludeProgressStats { progressStats, err = s.queryRepository.GetProgressStatistics(ctx) if err != nil { s.logger.Warn("获取进度统计失败", zap.Error(err)) } } // 6. 构建响应 response := &responses.CertificationStatisticsResponse{ Period: query.Period, TimeRange: domainQuery.GetTimeRange(), Statistics: stats, ProgressStats: progressStats, GeneratedAt: domainQuery.StartDate, Charts: s.generateChartsData(stats, progressStats), } return response, nil } // ================ e签宝回调处理 ================ // HandleEsignCallback 处理e签宝回调 func (s *CertificationApplicationServiceImpl) HandleEsignCallback( ctx context.Context, cmd *commands.EsignCallbackCommand, ) (*responses.CallbackResponse, error) { s.logger.Info("开始处理e签宝回调", zap.String("certification_id", cmd.CertificationID), zap.String("callback_type", cmd.CallbackType)) // 1. 解析回调数据 callbackData, err := s.callbackHandler.ParseCallbackData(cmd.RawData) if err != nil { s.logger.Error("解析回调数据失败", zap.Error(err)) return responses.NewCallbackResponse(false, cmd.CertificationID, cmd.CallbackType, fmt.Sprintf("解析回调数据失败: %s", err.Error())), err } // 2. 构建工作流回调命令 workflowCmd := &services.EsignCallbackCommand{ CertificationID: cmd.CertificationID, CallbackType: cmd.CallbackType, CallbackData: callbackData, } // 3. 根据回调类型分发处理 var workflowResult *services.WorkflowResult switch cmd.CallbackType { case "auth_result": workflowResult, err = s.workflowOrchestrator.HandleEnterpriseVerificationCallback(ctx, workflowCmd) case "sign_result": workflowResult, err = s.workflowOrchestrator.HandleContractSignCallback(ctx, workflowCmd) default: err = fmt.Errorf("不支持的回调类型: %s", cmd.CallbackType) } if err != nil { s.logger.Error("处理回调失败", zap.Error(err)) return responses.NewCallbackResponse(false, cmd.CertificationID, cmd.CallbackType, fmt.Sprintf("处理回调失败: %s", err.Error())), err } // 4. 构建成功响应 response := responses.NewCallbackResponse(true, cmd.CertificationID, cmd.CallbackType, workflowResult.Message) // 5. 设置状态转换信息 if workflowResult.StateTransition != nil { response.StateTransition = workflowResult.StateTransition response.OldStatus = workflowResult.StateTransition.OldStatus response.NewStatus = workflowResult.StateTransition.NewStatus } s.logger.Info("e签宝回调处理成功", zap.String("certification_id", cmd.CertificationID)) return response, nil } // ================ 管理员操作 ================ // ForceTransitionStatus 强制状态转换(管理员) func (s *CertificationApplicationServiceImpl) ForceTransitionStatus( ctx context.Context, cmd *commands.ForceTransitionStatusCommand, ) (*responses.CertificationResponse, error) { s.logger.Info("开始强制状态转换", zap.String("certification_id", cmd.CertificationID), zap.String("admin_id", cmd.AdminID), zap.String("target_status", string(cmd.TargetStatus))) // 1. 权限验证(这里简化,实际应该有更复杂的权限验证) // TODO: 实现管理员权限验证逻辑 // 2. 执行状态转换 result, err := s.aggregateService.TransitionState( ctx, cmd.CertificationID, cmd.TargetStatus, enums.ActorTypeAdmin, cmd.AdminID, cmd.Reason, map[string]interface{}{ "force": cmd.Force, }, ) if err != nil { s.logger.Error("强制状态转换失败", zap.Error(err)) return nil, fmt.Errorf("强制状态转换失败: %w", err) } // 3. 加载最新的认证信息 cert, err := s.aggregateService.LoadCertification(ctx, cmd.CertificationID) if err != nil { s.logger.Error("加载认证信息失败", zap.Error(err)) return nil, fmt.Errorf("加载认证信息失败: %w", err) } // 4. 转换为响应DTO response := s.convertToResponse(cert) // 5. 添加状态转换信息 if result != nil { response.Metadata = map[string]interface{}{ "state_transition": result, "admin_operation": true, } } s.logger.Info("强制状态转换成功", zap.String("certification_id", cmd.CertificationID)) return response, nil } // GetSystemMonitoring 获取系统监控数据 func (s *CertificationApplicationServiceImpl) GetSystemMonitoring( ctx context.Context, query *queries.GetSystemMonitoringQuery, ) (*responses.SystemMonitoringResponse, error) { s.logger.Debug("获取系统监控数据", zap.String("time_range", query.TimeRange)) // 1. 获取基础统计数据 stats, err := s.queryRepository.GetStatistics(ctx, repositories.PeriodDaily) if err != nil { s.logger.Error("获取基础统计失败", zap.Error(err)) return nil, fmt.Errorf("获取系统监控数据失败: %w", err) } // 2. 构建监控指标 metrics := make(map[string]interface{}) if query.ShouldIncludeMetric("certification_count") { metrics["certification_count"] = stats.TotalCertifications } if query.ShouldIncludeMetric("success_rate") { metrics["success_rate"] = stats.SuccessRate } if query.ShouldIncludeMetric("failure_rate") { metrics["failure_rate"] = 1.0 - stats.SuccessRate } if query.ShouldIncludeMetric("avg_processing_time") { metrics["avg_processing_time"] = stats.AvgProcessingTime.String() } if query.ShouldIncludeMetric("status_distribution") { metrics["status_distribution"] = stats.StatusDistribution } // 3. 生成系统警告 alerts := s.generateSystemAlerts(stats) // 4. 评估系统健康状态 systemHealth := s.evaluateSystemHealth(stats, alerts) // 5. 构建响应 response := &responses.SystemMonitoringResponse{ TimeRange: query.TimeRange, Metrics: metrics, Alerts: alerts, SystemHealth: systemHealth, LastUpdatedAt: stats.StartDate, } return response, nil } // ================ 辅助方法 ================ // convertToResponse 转换实体为响应DTO func (s *CertificationApplicationServiceImpl) convertToResponse(cert *entities.Certification) *responses.CertificationResponse { response := &responses.CertificationResponse{ ID: cert.ID, UserID: cert.UserID, Status: cert.Status, StatusName: enums.GetStatusName(cert.Status), Progress: cert.GetProgress(), CreatedAt: cert.CreatedAt, UpdatedAt: cert.UpdatedAt, InfoSubmittedAt: cert.InfoSubmittedAt, EnterpriseVerifiedAt: cert.EnterpriseVerifiedAt, ContractAppliedAt: cert.ContractAppliedAt, ContractSignedAt: cert.ContractSignedAt, IsCompleted: cert.IsCompleted(), IsFailed: enums.IsFailureStatus(cert.Status), IsUserActionRequired: cert.IsUserActionRequired(), NextAction: enums.GetUserActionHint(cert.Status), AvailableActions: cert.GetAvailableActions(), RetryCount: cert.RetryCount, Metadata: make(map[string]interface{}), } // 设置企业信息(从认证实体中构建) // TODO: 这里需要从企业信息服务或其他地方获取完整的企业信息 // response.EnterpriseInfo = cert.EnterpriseInfo // 设置合同信息(从认证实体中构建) if cert.ContractFileID != "" || cert.EsignFlowID != "" { // TODO: 从认证实体字段构建合同信息值对象 // response.ContractInfo = &value_objects.ContractInfo{...} } // 设置失败信息 if enums.IsFailureStatus(cert.Status) { response.FailureReason = cert.FailureReason response.FailureReasonName = enums.GetFailureReasonName(cert.FailureReason) response.FailureMessage = cert.FailureMessage response.CanRetry = enums.IsRetryable(cert.FailureReason) } return response } // generateChartsData 生成图表数据 func (s *CertificationApplicationServiceImpl) generateChartsData( stats *repositories.CertificationStatistics, progressStats *repositories.CertificationProgressStats, ) map[string]interface{} { charts := make(map[string]interface{}) // 状态分布饼图 if stats.StatusDistribution != nil { statusChart := make(map[string]interface{}) statusChart["type"] = "pie" statusChart["data"] = stats.StatusDistribution charts["status_distribution"] = statusChart } // 失败原因分布 if stats.FailureDistribution != nil { failureChart := make(map[string]interface{}) failureChart["type"] = "bar" failureChart["data"] = stats.FailureDistribution charts["failure_distribution"] = failureChart } // 进度分布 if progressStats != nil && progressStats.ProgressDistribution != nil { progressChart := make(map[string]interface{}) progressChart["type"] = "histogram" progressChart["data"] = progressStats.ProgressDistribution charts["progress_distribution"] = progressChart } return charts } // generateSystemAlerts 生成系统警告 func (s *CertificationApplicationServiceImpl) generateSystemAlerts(stats *repositories.CertificationStatistics) []responses.SystemAlert { var alerts []responses.SystemAlert // 成功率警告 if stats.SuccessRate < 0.8 { level := "warning" if stats.SuccessRate < 0.6 { level = "critical" } alert := responses.SystemAlert{ Level: level, Type: "success_rate_low", Message: fmt.Sprintf("认证成功率过低:%.1f%%", stats.SuccessRate*100), Metric: "success_rate", Value: stats.SuccessRate, Threshold: 0.8, CreatedAt: stats.StartDate, } alerts = append(alerts, alert) } // 处理时间警告 if stats.AvgProcessingTime.Hours() > 24 { alert := responses.SystemAlert{ Level: "warning", Type: "processing_time_high", Message: fmt.Sprintf("平均处理时间过长:%.1f小时", stats.AvgProcessingTime.Hours()), Metric: "avg_processing_time", Value: stats.AvgProcessingTime.String(), Threshold: "24h", CreatedAt: stats.StartDate, } alerts = append(alerts, alert) } return alerts } // evaluateSystemHealth 评估系统健康状态 func (s *CertificationApplicationServiceImpl) evaluateSystemHealth( stats *repositories.CertificationStatistics, alerts []responses.SystemAlert, ) responses.SystemHealthStatus { overall := "healthy" components := map[string]string{ "certification_service": "healthy", "esign_integration": "healthy", "database": "healthy", "state_machine": "healthy", } // 根据警告判断健康状态 for _, alert := range alerts { if alert.Level == "critical" { overall = "critical" break } else if alert.Level == "warning" && overall == "healthy" { overall = "warning" } } // 根据统计数据评估组件状态 if stats.SuccessRate < 0.6 { components["certification_service"] = "critical" components["esign_integration"] = "warning" } else if stats.SuccessRate < 0.8 { components["certification_service"] = "warning" } return responses.SystemHealthStatus{ Overall: overall, Components: components, LastCheck: stats.StartDate, Details: map[string]interface{}{ "total_certifications": stats.TotalCertifications, "success_rate": stats.SuccessRate, "avg_processing_time": stats.AvgProcessingTime.String(), }, } }