package services import ( "context" "fmt" "time" "tyapi-server/internal/domains/certification/entities" "tyapi-server/internal/domains/certification/enums" "tyapi-server/internal/domains/certification/repositories" "go.uber.org/zap" ) // CertificationStateMachine 认证状态机 type CertificationStateMachine struct { stateManager *CertificationStateManager certRepo repositories.CertificationRepository logger *zap.Logger } // NewCertificationStateMachine 创建认证状态机 func NewCertificationStateMachine( certRepo repositories.CertificationRepository, logger *zap.Logger, ) *CertificationStateMachine { return &CertificationStateMachine{ stateManager: NewCertificationStateManager(), certRepo: certRepo, logger: logger, } } // CanTransition 检查是否可以转换到指定状态 func (sm *CertificationStateMachine) CanTransition( from enums.CertificationStatus, to enums.CertificationStatus, isUser bool, isAdmin bool, ) (bool, string) { return sm.stateManager.CanTransition(from, to, isUser, isAdmin) } // TransitionTo 执行状态转换 func (sm *CertificationStateMachine) TransitionTo( ctx context.Context, certificationID string, targetStatus enums.CertificationStatus, isUser bool, isAdmin bool, metadata map[string]interface{}, ) error { // 获取当前认证记录 cert, err := sm.certRepo.GetByID(ctx, certificationID) if err != nil { return fmt.Errorf("获取认证记录失败: %w", err) } // 检查是否可以转换 canTransition, reason := sm.CanTransition(cert.Status, targetStatus, isUser, isAdmin) if !canTransition { return fmt.Errorf("状态转换失败: %s", reason) } // 更新状态和时间戳 oldStatus := cert.Status cert.Status = targetStatus sm.updateTimestamp(&cert, targetStatus) // 更新其他字段 sm.updateCertificationFields(&cert, targetStatus, metadata) // 保存到数据库 if err := sm.certRepo.Update(ctx, cert); err != nil { return fmt.Errorf("保存状态转换失败: %w", err) } sm.logger.Info("认证状态转换成功", zap.String("certification_id", certificationID), zap.String("from_status", string(oldStatus)), zap.String("to_status", string(targetStatus)), zap.Bool("is_user", isUser), zap.Bool("is_admin", isAdmin), ) return nil } // updateTimestamp 更新对应的时间戳字段 func (sm *CertificationStateMachine) updateTimestamp(cert *entities.Certification, status enums.CertificationStatus) { stateConfig := sm.stateManager.GetStateConfig(status) if stateConfig == nil || stateConfig.TimestampField == "" { return } now := time.Now() switch stateConfig.TimestampField { case "InfoSubmittedAt": cert.InfoSubmittedAt = &now case "EnterpriseVerifiedAt": cert.EnterpriseVerifiedAt = &now case "ContractAppliedAt": cert.ContractAppliedAt = &now case "ContractSignedAt": cert.ContractSignedAt = &now case "CompletedAt": cert.CompletedAt = &now } } // updateCertificationFields 根据状态更新认证记录的其他字段 func (sm *CertificationStateMachine) updateCertificationFields( cert *entities.Certification, status enums.CertificationStatus, metadata map[string]interface{}, ) { switch status { case enums.StatusContractSigned: if contractURL, ok := metadata["contract_url"].(string); ok { cert.ContractURL = contractURL } } } // GetValidNextStatuses 获取当前状态可以转换到的下一个状态列表 func (sm *CertificationStateMachine) GetValidNextStatuses( currentStatus enums.CertificationStatus, isUser bool, isAdmin bool, ) []enums.CertificationStatus { return sm.stateManager.GetNextValidStatuses(currentStatus) } // GetTransitionAction 获取状态转换对应的操作名称 func (sm *CertificationStateMachine) GetTransitionAction( from enums.CertificationStatus, to enums.CertificationStatus, ) string { transitions := sm.stateManager.GetTransitionConfigs(from) for _, transition := range transitions { if transition.To == to { return transition.Action } } return "" } // GetTransitionActionName 获取状态转换对应的操作中文名称 func (sm *CertificationStateMachine) GetTransitionActionName( from enums.CertificationStatus, to enums.CertificationStatus, ) string { transitions := sm.stateManager.GetTransitionConfigs(from) for _, transition := range transitions { if transition.To == to { return transition.ActionName } } return "" } // GetStateConfig 获取状态配置 func (sm *CertificationStateMachine) GetStateConfig(status enums.CertificationStatus) *StateConfig { return sm.stateManager.GetStateConfig(status) } // GetProgressPercentage 获取进度百分比 func (sm *CertificationStateMachine) GetProgressPercentage(status enums.CertificationStatus) int { return sm.stateManager.GetProgressPercentage(status) } // IsUserActionRequired 检查是否需要用户操作 func (sm *CertificationStateMachine) IsUserActionRequired(status enums.CertificationStatus) bool { return sm.stateManager.IsUserActionRequired(status) } // IsAdminActionRequired 检查是否需要管理员操作 func (sm *CertificationStateMachine) IsAdminActionRequired(status enums.CertificationStatus) bool { return sm.stateManager.IsAdminActionRequired(status) } // GetTransitionHistory 获取状态转换历史 func (sm *CertificationStateMachine) GetTransitionHistory(ctx context.Context, certificationID string) ([]map[string]interface{}, error) { cert, err := sm.certRepo.GetByID(ctx, certificationID) if err != nil { return nil, fmt.Errorf("获取认证记录失败: %w", err) } history := []map[string]interface{}{} // 添加创建时间 history = append(history, map[string]interface{}{ "status": "CREATED", "timestamp": cert.CreatedAt, "action": "create", "performer": "system", "metadata": map[string]interface{}{}, }) // 添加各个时间节点的状态转换 if cert.InfoSubmittedAt != nil { history = append(history, map[string]interface{}{ "status": string(enums.StatusInfoSubmitted), "timestamp": *cert.InfoSubmittedAt, "action": "submit_info", "performer": "user", "metadata": map[string]interface{}{}, }) } if cert.EnterpriseVerifiedAt != nil { history = append(history, map[string]interface{}{ "status": string(enums.StatusEnterpriseVerified), "timestamp": *cert.EnterpriseVerifiedAt, "action": "enterprise_verify", "performer": "user", "metadata": map[string]interface{}{}, }) } if cert.ContractAppliedAt != nil { history = append(history, map[string]interface{}{ "status": string(enums.StatusContractApplied), "timestamp": *cert.ContractAppliedAt, "action": "apply_contract", "performer": "user", "metadata": map[string]interface{}{}, }) } if cert.ContractSignedAt != nil { metadata := map[string]interface{}{} if cert.ContractURL != "" { metadata["contract_url"] = cert.ContractURL } history = append(history, map[string]interface{}{ "status": string(enums.StatusContractSigned), "timestamp": *cert.ContractSignedAt, "action": "sign_contract", "performer": "user", "metadata": metadata, }) } if cert.CompletedAt != nil { history = append(history, map[string]interface{}{ "status": string(enums.StatusCompleted), "timestamp": *cert.CompletedAt, "action": "complete", "performer": "system", "metadata": map[string]interface{}{}, }) } return history, nil }