Files
tyapi-server/internal/domains/certification/services/state_machine.go

259 lines
7.3 KiB
Go
Raw Normal View History

2025-07-11 21:05:58 +08:00
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 {
2025-07-20 20:53:26 +08:00
stateManager *CertificationStateManager
certRepo repositories.CertificationRepository
logger *zap.Logger
2025-07-11 21:05:58 +08:00
}
// NewCertificationStateMachine 创建认证状态机
func NewCertificationStateMachine(
certRepo repositories.CertificationRepository,
logger *zap.Logger,
) *CertificationStateMachine {
2025-07-20 20:53:26 +08:00
return &CertificationStateMachine{
stateManager: NewCertificationStateManager(),
certRepo: certRepo,
logger: logger,
2025-07-11 21:05:58 +08:00
}
}
// CanTransition 检查是否可以转换到指定状态
func (sm *CertificationStateMachine) CanTransition(
from enums.CertificationStatus,
to enums.CertificationStatus,
isUser bool,
isAdmin bool,
) (bool, string) {
2025-07-20 20:53:26 +08:00
return sm.stateManager.CanTransition(from, to, isUser, isAdmin)
2025-07-11 21:05:58 +08:00
}
// 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
2025-07-13 16:36:20 +08:00
sm.updateTimestamp(&cert, targetStatus)
2025-07-11 21:05:58 +08:00
// 更新其他字段
2025-07-13 16:36:20 +08:00
sm.updateCertificationFields(&cert, targetStatus, metadata)
2025-07-11 21:05:58 +08:00
// 保存到数据库
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) {
2025-07-20 20:53:26 +08:00
stateConfig := sm.stateManager.GetStateConfig(status)
if stateConfig == nil || stateConfig.TimestampField == "" {
return
}
2025-07-11 21:05:58 +08:00
now := time.Now()
2025-07-20 20:53:26 +08:00
switch stateConfig.TimestampField {
case "InfoSubmittedAt":
2025-07-11 21:05:58 +08:00
cert.InfoSubmittedAt = &now
2025-07-20 20:53:26 +08:00
case "EnterpriseVerifiedAt":
cert.EnterpriseVerifiedAt = &now
case "ContractAppliedAt":
2025-07-11 21:05:58 +08:00
cert.ContractAppliedAt = &now
2025-07-20 20:53:26 +08:00
case "ContractSignedAt":
2025-07-11 21:05:58 +08:00
cert.ContractSignedAt = &now
2025-07-20 20:53:26 +08:00
case "CompletedAt":
2025-07-11 21:05:58 +08:00
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 {
2025-07-20 20:53:26 +08:00
return sm.stateManager.GetNextValidStatuses(currentStatus)
2025-07-11 21:05:58 +08:00
}
// GetTransitionAction 获取状态转换对应的操作名称
func (sm *CertificationStateMachine) GetTransitionAction(
from enums.CertificationStatus,
to enums.CertificationStatus,
) string {
2025-07-20 20:53:26 +08:00
transitions := sm.stateManager.GetTransitionConfigs(from)
2025-07-11 21:05:58 +08:00
for _, transition := range transitions {
if transition.To == to {
return transition.Action
}
}
2025-07-20 20:53:26 +08:00
return ""
}
2025-07-11 21:05:58 +08:00
2025-07-20 20:53:26 +08:00
// 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
}
}
2025-07-11 21:05:58 +08:00
return ""
}
2025-07-13 16:36:20 +08:00
2025-07-20 20:53:26 +08:00
// 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)
}
2025-07-13 16:36:20 +08:00
// 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{}{},
})
}
2025-07-20 20:53:26 +08:00
if cert.EnterpriseVerifiedAt != nil {
2025-07-13 16:36:20 +08:00
history = append(history, map[string]interface{}{
2025-07-20 20:53:26 +08:00
"status": string(enums.StatusEnterpriseVerified),
"timestamp": *cert.EnterpriseVerifiedAt,
"action": "enterprise_verify",
"performer": "user",
2025-07-13 16:36:20 +08:00
"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,
2025-07-20 20:53:26 +08:00
"action": "sign_contract",
2025-07-13 16:36:20 +08:00
"performer": "user",
"metadata": metadata,
})
}
if cert.CompletedAt != nil {
history = append(history, map[string]interface{}{
"status": string(enums.StatusCompleted),
"timestamp": *cert.CompletedAt,
2025-07-20 20:53:26 +08:00
"action": "complete",
2025-07-13 16:36:20 +08:00
"performer": "system",
"metadata": map[string]interface{}{},
})
}
return history, nil
}