operatorInfo) */ private array $operatorSessions = []; /** @var ProcessContext[] 执行历史 */ private array $history = []; /** @var array 当前内镜的流程状态 (endoscopeId => ProcessContext) */ private array $endoscopeStates = []; /** * 构造函数 * * @param ProcessConfig|null $config 流程配置 * @param string|null $envPath 环境配置文件路径 */ public function __construct(?ProcessConfig $config = null, ?string $envPath = null) { $this->envPath = $envPath ?? (__DIR__ . '/../resources/default_environment.json'); $this->loadEnvironment(); $this->engine = ProcessEngine::create($config ?? ProcessConfig::createStandard()); } /** * 加载环境配置 */ private function loadEnvironment(): void { if (!file_exists($this->envPath)) { throw new \RuntimeException("环境配置文件不存在: {$this->envPath}"); } $content = file_get_contents($this->envPath); $this->environment = json_decode($content, true); if (json_last_error() !== JSON_ERROR_NONE) { throw new \RuntimeException("环境配置文件解析失败: " . json_last_error_msg()); } } // ==================== 静态工厂方法 ==================== /** * 创建标准流程处理器 */ public static function create(?ProcessConfig $config = null, ?string $envPath = null): self { return new self($config, $envPath); } /** * 创建标准手工洗流程处理器 */ public static function createStandard(?string $envPath = null): self { return new self(ProcessConfig::createStandard(), $envPath); } /** * 创建无晨洗流程处理器 */ public static function createNoMorningWash(?string $envPath = null): self { return new self(ProcessConfig::createNoMorningWash(), $envPath); } /** * 创建机洗流程处理器 */ public static function createMachineWash(?string $envPath = null): self { return new self(ProcessConfig::createMachineWash(), $envPath); } // ==================== 刷卡模拟方法 ==================== /** * 模拟刷人员卡 * * @param string $operatorName 操作员名称(环境配置中定义) * @param string $readerType 读卡器类型 * @return ProcessContext */ public function swipeOperatorCard(string $operatorName, string $readerType = '清洗'): ProcessContext { $operatorData = $this->environment['operators'][$operatorName] ?? throw new \InvalidArgumentException("未找到操作员: {$operatorName}"); $readerData = $this->environment['readers'][$readerType] ?? throw new \InvalidArgumentException("未找到读卡器: {$readerType}"); // 保存操作员会话 $this->operatorSessions[$readerData['id']] = $operatorData; // 构建上下文 $context = VirtualContextBuilder::create($this->envPath) ->operator($operatorName) ->reader($readerType) ->asOperatorCard() ->withEngineConfig($this->engine->getConfig()) ->build(); // 人员卡不走流程链,直接返回 $result = $context->builder() ->voiceMessage('请刷内镜卡') ->build(); $this->history[] = $result; return $result; } /** * 模拟刷内镜卡 * * @param string $endoscopeName 内镜名称(环境配置中定义) * @param string $readerType 读卡器类型 * @return ProcessContext */ public function swipeEndoscopeCard(string $endoscopeName, string $readerType): ProcessContext { $readerData = $this->environment['readers'][$readerType] ?? throw new \InvalidArgumentException("未找到读卡器: {$readerType}"); $endoscopeData = $this->environment['endoscopes'][$endoscopeName] ?? throw new \InvalidArgumentException("未找到内镜: {$endoscopeName}"); // 获取内镜当前状态 $currentState = $this->endoscopeStates[$endoscopeData['id']] ?? null; // 构建上下文 $builder = VirtualContextBuilder::create($this->envPath) ->endoscope($endoscopeName) ->reader($readerType) ->withEngineConfig($this->engine->getConfig()); // 如果有操作员会话,添加操作员信息 if (isset($this->operatorSessions[$readerData['id']])) { $opData = $this->operatorSessions[$readerData['id']]; $builder->customOperator($opData['id'], $opData['name'], $opData['rfid']); } // 继承之前的流程状态 if ($currentState !== null) { $builder->currentStep($currentState->getCurrentStep()) ->batchNo($currentState->getBatchNo()) ->processType($currentState->getProcessType()); // 设置 previousAction:上一步骤名称就是当前状态的 currentStep if (!empty($currentState->getCurrentStep())) { $builder->previousAction($currentState->getCurrentStep(), $currentState->getBatchNo()); } } else { // 新流程 $builder->newProcess(); } $context = $builder->build(); // 未刷人员卡检查 if (!$context->hasOperator() && !isset($this->operatorSessions[$readerData['id']])) { $result = $context->builder() ->error(\app\flow\enum\VoiceMessage::PLEASE_SWIPE_OPERATOR) ->build(); $this->history[] = $result; return $result; } // 执行流程 $result = $this->engine->execute($context); // 确保 previousAction 在结果中正确设置 // 如果执行成功且有上一步骤信息,确保 previousAction 被保留 if ($result->isSuccess() && $context->getPreviousAction() !== null && $result->getPreviousAction() === null) { $result = $result->builder() ->withPreviousAction($context->getPreviousAction()) ->build(); } // 保存状态 $this->endoscopeStates[$endoscopeData['id']] = $result; $this->history[] = $result; return $result; } /** * 快捷方法:完整刷卡(先刷人员卡再刷内镜卡) * * @param string $operatorName 操作员名称 * @param string $endoscopeName 内镜名称 * @param string $readerType 读卡器类型 * @return ProcessContext 返回内镜卡刷卡结果 */ public function swipe(string $operatorName, string $endoscopeName, string $readerType): ProcessContext { Logger::info("测试刷卡:{$operatorName}, {$endoscopeName}, {$readerType}"); // 刷人员卡 $result = $this->swipeOperatorCard($operatorName, $readerType); // 当前语音 Logger::info("当前语音:{$result->getFullVoice()}"); // 刷内镜卡 Logger::info("测试刷卡:{$endoscopeName}, {$readerType}"); $result = $this->swipeEndoscopeCard($endoscopeName, $readerType); Logger::info("当前流程:{}", [$result->getProcessType()]); Logger::info("当前批次号:{}", [$result->getBatchNo()]); Logger::info("当前步骤:{}", [$result->getCurrentStep()]); Logger::info("上一个步骤类型:{}", [$result->getPreviousAction()->action_type_name?? "null"]); Logger::info("上一个步骤:{}", [$result->getPreviousAction()->process_name??"null"]); Logger::info("时长:{}", [$result->getDuration()?? "null"]); Logger::info("当前语音:{$result->getFullVoice()}\n"); return $result; } /** * 执行完整的手工洗流程 * * @param string $operatorName 操作员名称 * @param string $endoscopeName 内镜名称 * @return array 每个步骤的执行结果 */ public function executeFullManualWash(string $operatorName, string $endoscopeName): array { $steps = ['清洗', '漂洗', '消毒', '终末漂洗', '干燥']; $results = []; foreach ($steps as $step) { $results[$step] = $this->swipe($operatorName, $endoscopeName, $step); } return $results; } /** * 执行完整的机洗流程 * * @param string $operatorName 操作员名称 * @param string $endoscopeName 内镜名称 * @return ProcessContext */ public function executeMachineWash(string $operatorName, string $endoscopeName): ProcessContext { return $this->swipe($operatorName, $endoscopeName, '机洗'); } // ==================== 状态管理方法 ==================== /** * 重置所有状态 */ public function reset(): self { $this->operatorSessions = []; $this->endoscopeStates = []; $this->history = []; return $this; } /** * 清除指定内镜的状态 */ public function clearEndoscopeState(string $endoscopeName): self { $endoscopeData = $this->environment['endoscopes'][$endoscopeName] ?? null; if ($endoscopeData !== null) { unset($this->endoscopeStates[$endoscopeData['id']]); } return $this; } /** * 清除指定读卡器的操作员会话 */ public function clearOperatorSession(string $readerType): self { $readerData = $this->environment['readers'][$readerType] ?? null; if ($readerData !== null) { unset($this->operatorSessions[$readerData['id']]); } return $this; } /** * 手动设置内镜状态 */ public function setEndoscopeState(string $endoscopeName, ProcessContext $context): self { $endoscopeData = $this->environment['endoscopes'][$endoscopeName] ?? null; if ($endoscopeData !== null) { $this->endoscopeStates[$endoscopeData['id']] = $context; } return $this; } // ==================== 查询方法 ==================== /** * 获取执行历史 */ public function getHistory(): array { return $this->history; } /** * 获取最后一次执行结果 */ public function getLastResult(): ?ProcessContext { return end($this->history) ?: null; } /** * 获取内镜当前状态 */ public function getEndoscopeState(string $endoscopeName): ?ProcessContext { $endoscopeData = $this->environment['endoscopes'][$endoscopeName] ?? null; if ($endoscopeData === null) { return null; } return $this->endoscopeStates[$endoscopeData['id']] ?? null; } /** * 获取流程引擎 */ public function getEngine(): ProcessEngine { return $this->engine; } /** * 获取环境配置 */ public function getEnvironment(): array { return $this->environment; } /** * 创建上下文构建器 */ public function createContextBuilder(): VirtualContextBuilder { return VirtualContextBuilder::create($this->envPath) ->withEngineConfig($this->engine->getConfig()); } // ==================== 断言辅助方法 ==================== /** * 获取语音内容(用于断言) */ public function getVoice(?ProcessContext $context = null): string { $ctx = $context ?? $this->getLastResult(); return $ctx?->getFullVoice() ?? ''; } /** * 检查是否成功 */ public function isSuccess(?ProcessContext $context = null): bool { $ctx = $context ?? $this->getLastResult(); return $ctx?->isSuccess() ?? false; } /** * 获取当前步骤 */ public function getCurrentStep(?ProcessContext $context = null): string { $ctx = $context ?? $this->getLastResult(); return $ctx?->getCurrentStep() ?? ''; } }