config = Config::getInstance(); // 初始化值对象为空对象 $this->endoscope = EndoscopeInfo::empty(); $this->reader = ReaderInfo::empty(); $this->operator = OperatorInfo::empty(); $this->storage = StorageStatus::notInStorage(); $this->morningWash = MorningWashStatus::notRequired(); $this->voice = VoiceState::empty(); $this->result = ExecutionResult::success(); $this->processStatus = ProcessStatus::empty(); $this->reminder = ReminderStatus::none(); } /** * 从 PacketContext 创建构造器 */ public static function fromPacketContext(PacketContext $packetContext, array $additionalData = []): self { $builder = new self(); $builder->packetContext = $packetContext; $builder->engineConfig = $additionalData['engineConfig'] ?? null; if (empty($builder->engineConfig)) Logger::warn("fromPacketContext 需要通过 additionalData 传递 engineConfig"); // 获取原始卡号和读卡器编号 $cardNo = $packetContext->packet->card ?? ''; $readerNo = $packetContext->packet->reader ?? ''; $builder->rawData = $packetContext->packet->toArray(); // 获取晨洗开始时间 if ($builder->engineConfig !== null) { $builder->morningStartTime = $builder->engineConfig->getMorningWashConfig()->morningStartTime; } // 1. 加载内镜/操作员信息 $builder->loadEndoscopeOrOperatorInfo($cardNo); // 2. 加载读卡器信息 $builder->loadReaderInfo($readerNo); // 3. 加载内镜操作记录相关信息(仅当内镜ID存在时执行) if (!$builder->endoscope->isEmpty()) { $builder->loadEndoscopeActionInfo(); $builder->loadStorageStatus(); } // 4. 初始化晨洗状态 $builder->morningWash = new MorningWashStatus( needMorningWash: false, // TODO: 由策略计算 morningWashed: false, startTime: $builder->morningStartTime, todayWashRecords: $builder->morningWash->todayWashRecords ); // 5. 合并额外数据 foreach ($additionalData as $key => $value) { if (property_exists($builder, $key) && $value !== null) { $builder->$key = $value; } } Logger::debug("从 PacketContext 创建 ProcessContextBuilder"); return $builder; } /** * 从现有的 ProcessContext 创建构造器 * 用于基于现有上下文创建修改后的新实例 */ public static function from(ProcessContext $context): self { $builder = new self(); // 复制值对象 $builder->endoscope = $context->getEndoscope(); $builder->reader = $context->getReader(); $builder->operator = $context->getOperator(); $builder->storage = $context->getStorage(); $builder->morningWash = $context->getMorningWash(); $builder->voice = $context->getVoice(); $builder->result = $context->getResult(); $builder->processStatus = $context->getProcessStatus(); $builder->reminder = $context->getReminder(); // 复制原始数据 $builder->packetContext = $context->getPacketContext(); $builder->engineConfig = $context->getEngineConfig(); $builder->rawData = $context->getRawData(); // 复制标记 $builder->isOperatorCard = $context->isOperatorCard(); $builder->stepDurations = $context->getStepDurations(); return $builder; } // ==================== 数据加载方法 ==================== /** * 加载内镜或操作员信息 */ private function loadEndoscopeOrOperatorInfo(string $cardNo): void { if (empty($cardNo)) { return; } // 优先查询内镜信息 $endoscope = EndoscopeRepository::new()->findByCardNo($cardNo); if ($endoscope !== null) { $this->endoscope = new EndoscopeInfo( id: (string)$endoscope->endoscope_id, name: (string)$endoscope->endoscope_name, cardNo: $cardNo, type: (string)$endoscope->endoscope_type ); return; } // 内镜无记录则查询人员卡信息 try { $user = UserRepository::new()->findByRfid($cardNo); if ($user !== null) { $this->isOperatorCard = true; $this->operator = new OperatorInfo( id: (string)$user->user_id, name: (string)$user->user_name, rfid: (string)$user->user_rfid ); } } catch (Exception $e) { Logger::error("[ProcessContextBuilder] 查询人员卡信息出错: {}", [$e->getMessage()]); } } /** * 加载读卡器信息 */ private function loadReaderInfo(string $readerNo): void { if (empty($readerNo)) { return; } $readerInfo = ReaderRepository::new()->findReaderInfo($readerNo); if ($readerInfo !== null) { $this->reader = new ReaderInfo( no: $readerNo, type: $readerInfo['readerType'], id: $readerInfo['readerId'] ); } } /** * 加载内镜操作记录相关信息 */ private function loadEndoscopeActionInfo(): void { $actionsRepo = EctActionsRepository::new(); // 查询最后一条操作记录 $lastAction = $actionsRepo->findLastAction($this->endoscope->id, [0, 7, 8]); if (empty($lastAction)) { return; } $lastStepStartTime = $lastAction->op_starttime; $duration = time() - strtotime($lastStepStartTime); $this->handleLastAction($lastAction, $actionsRepo, $duration); // 查询今日洗消记录数(晨洗判断) $todayWashRecords = $actionsRepo->countTodayActions($this->endoscope->id, $this->morningStartTime, [0, 7, 8]); Logger::debug("{} 内镜今日洗消记录数: {}", [$this->endoscope->name,$todayWashRecords]); $this->morningWash = new MorningWashStatus( needMorningWash: $this->morningWash->needMorningWash, morningWashed: $this->morningWash->morningWashed, startTime: $this->morningStartTime, todayWashRecords: $todayWashRecords ); } /** * 加载内镜存储状态 */ private function loadStorageStatus(): void { $actionsRepo = EctActionsRepository::new(); // 查询最后一次存储操作记录 $lastStorageAction = $actionsRepo->findLastStorageAction($this->endoscope->id); if ($lastStorageAction !== null) { $isInStorage = ($lastStorageAction['process_name'] === '内镜放入'); $inTime = $isInStorage ? $lastStorageAction['op_starttime'] : null; $this->storage = new StorageStatus( isInStorage: $isInStorage, lastAction: $lastStorageAction['process_name'], inTime: $inTime ); } // 查询最后一次存储入库时间(义乌模式晨洗判断) $storageTime = $actionsRepo->findLastStorageTime($this->endoscope->id); if ($storageTime !== null) { $this->storage = new StorageStatus( isInStorage: $this->storage->isInStorage, lastAction: $this->storage->lastAction, inTime: $storageTime ); } } /** * 处理最后一条操作记录的核心逻辑 */ private function handleLastAction(EctActions $lastAction, EctActionsRepository $actionsRepo, int $duration): void { // 设置基础操作信息 $currentStep = (string)$lastAction->process_name; $actionStartTime = date('Y-m-d H:i:s'); $processType = ''; $batchNo = ''; // 处理批次号逻辑 if ($currentStep === '结束') { $batchNo = $this->generateBatchNo(); } else { $batchNo = (string)$lastAction->op_batchno; $processType = (string)$lastAction->action_type_name; } $this->processStatus = new ProcessStatus( currentStep: $currentStep, processType: $processType, batchNo: $batchNo, actionStartTime: $actionStartTime, duration: $duration, previousAction: $lastAction ); // 加载批次操作员信息 if ($currentStep !== '结束' && !empty($batchNo)) { $this->loadBatchOperatorInfo($actionsRepo, $batchNo); } } /** * 加载批次对应的操作员信息 */ private function loadBatchOperatorInfo(EctActionsRepository $actionsRepo, string $batchNo): void { $operator = $actionsRepo->findOperatorByBatchNo($batchNo); if ($operator !== null) { $this->operator = new OperatorInfo( id: $operator['id'], name: $operator['name'], rfid: $operator['rfid'] ); } } /** * 生成批次号 * @return string 批次号值 */ private function generateBatchNo(): string { return BatchNo::generate($this->config->machineId)->value; } // ==================== 值对象设置方法 ==================== public function withEndoscope(EndoscopeInfo $endoscope): self { $this->endoscope = $endoscope; return $this; } public function withReader(ReaderInfo $reader): self { $this->reader = $reader; return $this; } public function withOperator(OperatorInfo $operator): self { $this->operator = $operator; return $this; } public function withStorage(StorageStatus $storage): self { $this->storage = $storage; return $this; } public function withMorningWash(MorningWashStatus $morningWash): self { $this->morningWash = $morningWash; return $this; } public function withVoice(VoiceState $voice): self { $this->voice = $voice; return $this; } public function withResult(ExecutionResult $result): self { $this->result = $result; return $this; } public function withProcessStatus(ProcessStatus $processStatus): self { $this->processStatus = $processStatus; return $this; } public function withReminder(ReminderStatus $reminder): self { $this->reminder = $reminder; return $this; } // ==================== 流程状态便捷设置方法 ==================== public function withCurrentStep(string $currentStep): self { $this->processStatus = new ProcessStatus( currentStep: $currentStep, processType: $this->processStatus->processType, batchNo: $this->processStatus->batchNo, actionStartTime: $this->processStatus->actionStartTime, duration: $this->processStatus->duration, previousAction: $this->processStatus->previousAction ); return $this; } public function withProcessType(string $processType): self { $this->processStatus = new ProcessStatus( currentStep: $this->processStatus->currentStep, processType: $processType, batchNo: $this->processStatus->batchNo, actionStartTime: $this->processStatus->actionStartTime, duration: $this->processStatus->duration, previousAction: $this->processStatus->previousAction ); return $this; } public function withBatchNo(string $batchNo): self { $this->processStatus = new ProcessStatus( currentStep: $this->processStatus->currentStep, processType: $this->processStatus->processType, batchNo: $batchNo, actionStartTime: $this->processStatus->actionStartTime, duration: $this->processStatus->duration, previousAction: $this->processStatus->previousAction ); return $this; } public function withDuration(?int $duration): self { $this->processStatus = new ProcessStatus( currentStep: $this->processStatus->currentStep, processType: $this->processStatus->processType, batchNo: $this->processStatus->batchNo, actionStartTime: $this->processStatus->actionStartTime, duration: $duration, previousAction: $this->processStatus->previousAction ); return $this; } public function withPreviousAction(?EctActions $action): self { $this->processStatus = new ProcessStatus( currentStep: $this->processStatus->currentStep, processType: $this->processStatus->processType, batchNo: $this->processStatus->batchNo, actionStartTime: $this->processStatus->actionStartTime, duration: $this->processStatus->duration, previousAction: $action ); return $this; } // ==================== 便捷设置方法(语义化) ==================== /** * 设置成功状态 */ public function success(): self { $this->result = new ExecutionResult(success: true); return $this; } /** * 设置错误状态和消息 */ public function error(VoiceMessage $message): self { $this->voice = $this->voice->withError($message); $this->result = $this->result->fail(); return $this; } /** * 设置自定义错误 */ public function customError(string $message): self { $this->voice = $this->voice->withMessage($message)->withError(VoiceMessage::CUSTOM); $this->result = $this->result->fail(); return $this; } /** * 设置语音消息 */ public function voiceMessage(string|VoiceMessage $message): self { $this->voice = $this->voice->withMessage($message); return $this; } /** * 设置期望下一步 */ public function expectedNextStep(VoiceMessage $expected): self { $this->voice = $this->voice->withExpectedNextStep($expected); return $this; } /** * 添加数据库操作 */ public function dbOperation(DbOperationType $operation): self { $this->result = $this->result->addDbOperation($operation); return $this; } /** * 设置需要数据库操作 */ public function needDatabaseOperation(bool $need = true): self { $this->result = new ExecutionResult( success: $this->result->success, needDatabaseOperation: $need, dbOperations: $this->result->dbOperations, needWebSocketNotify: $this->result->needWebSocketNotify, skipNodeCount: $this->result->skipNodeCount ); return $this; } /** * 设置需要WebSocket通知 */ public function needWebSocketNotify(bool $need = true): self { $this->result = $this->result->withWebSocketNotify($need); return $this; } /** * 设置跳过节点数 */ public function skipNodeCount(int $count): self { $this->result = $this->result->withSkipNodeCount($count); return $this; } // ==================== 提醒状态便捷设置方法 ==================== public function withNeedEnhanceWash(bool $need): self { $this->reminder = $this->reminder->withEnhanceWash($need); return $this; } public function withNeedLeakTestRemind(bool $need): self { $this->reminder = $this->reminder->withLeakTestRemind($need); return $this; } public function withNeedStorageRemind(bool $need): self { $this->reminder = $this->reminder->withStorageRemind($need); return $this; } public function withLeakTestDone(bool $done, string $result = ''): self { $this->reminder = $this->reminder->withLeakTestDone($result); return $this; } // ==================== 标记设置方法 ==================== public function withIsOperatorCard(bool $isOperatorCard): self { $this->isOperatorCard = $isOperatorCard; return $this; } public function withStepDuration(string $stepCode, int $duration): self { $this->stepDurations[$stepCode] = $duration; return $this; } // ==================== 构建方法 ==================== /** * 构建不可变的 ProcessContext 实例 */ public function build(): ProcessContext { Logger::debug("ProcessContextBuilder 构建 ProcessContext 完成"); return new ProcessContext( endoscope: $this->endoscope, reader: $this->reader, operator: $this->operator, storage: $this->storage, morningWash: $this->morningWash, voice: $this->voice, result: $this->result, processStatus: $this->processStatus, reminder: $this->reminder, packetContext: $this->packetContext, engineConfig: $this->engineConfig, rawData: $this->rawData, isOperatorCard: $this->isOperatorCard, stepDurations: $this->stepDurations, ); } }