[stepName => seconds]] */ private array $dbDurationCache = []; public function __construct(TimeValidationConfig $config) { parent::__construct([]); $this->timeValidationConfig = $config; Logger::debug("TimeValidationStrategy 初始化完成"); } /** * 从数据库获取步骤时长(按流程类型精确匹配) * 优先级:数据库记录 > 构造时配置 > 内置 fallback */ protected function getDurationFromDb(string $stepCode, string $processType): int { if (empty($processType)) { return $this->timeValidationConfig->getDuration($stepCode, $processType); } // 整批加载并缓存,减少查询次数 if (!isset($this->dbDurationCache[$processType])) { $this->dbDurationCache[$processType] = ProcessDurationRepository::new() ->getDurationsByProcessType($processType); } $dbValue = $this->dbDurationCache[$processType][$stepCode] ?? null; if ($dbValue !== null) { return $dbValue; } // fallback:返回配置中的默认值 return $this->timeValidationConfig->getDuration($stepCode); } /** * 执行时间验证 */ protected function doExecute(ProcessContext $context, ProcessNodeInterface $node): ProcessContext { $stepCode = $node->getCode(); $currentStep = $context->currentStep; $processType = $context->processType; Logger::debug("开始执行时间验证策略,步骤:{$stepCode},流程类型:{$processType}"); $configDuration = $this->timeValidationConfig->getDuration($stepCode,$processType); Logger::debug("步骤:{$stepCode},流程类型:{$processType},配置时长:{$configDuration}s"); if ($configDuration > 0) { // 配置中有明确时长,直接使用 $requiredDuration = $configDuration; } else { Logger::debug("步骤:{$stepCode},流程类型:{$processType},无配置时长,从数据库查询"); // 从数据库按流程类型精确查询 $requiredDuration = $this->getDurationFromDb($stepCode, $context->processType); if ($requiredDuration > 0) { $context->setStepDuration($stepCode, $requiredDuration); } else { // 最后使用上下文已缓存值 $requiredDuration = $context->getStepDuration($stepCode); } } // 无需时间验证,直接放行 if ($requiredDuration <= 0) { return $context; } // 获取上次该步骤的操作时间 $duration = $context->duration; // 没有上次记录(第一次操作),允许通过 if (empty($duration)) { Logger::debug("步骤:{$stepCode},流程类型:{$processType},无上次记录,允许通过"); return $context; } if ($duration < $requiredDuration) { Logger::debug("[{$stepCode}] 时间不足,剩余: {}s", [$requiredDuration - $duration]); if (Config::getInstance()->blockMode){ $voice = VoiceMessage::NOT_ENOUGH_TIME->value; $voice = str_replace('{step}', $stepCode, $voice); $voice = str_replace('{time}', $requiredDuration - $duration, $voice); $context->setCustomError($voice); } return $context; } return $context; } /** * 判断策略是否适用 * 只有在 timeValidationConfig 中登记的步骤才参与时间验证 */ public function isApplicable(ProcessContext $context, ProcessNodeInterface $node): bool { if ($context->currentStep != $context->previousAction->process_name) return false; if (!$this->timeValidationConfig->hasStep($node->getCode(), $context->processType)) return false; return true; } /** * 获取策略名称 */ public function getName(): string { return '时间验证策略'; } /** * 手动设置步骤时长(覆盖 fallback,不影响数据库缓存) */ public function setStepDuration(string $stepCode, int $seconds): self { $this->timeValidationConfig->setDuration($stepCode, $seconds); return $this; } }