diff --git a/.env b/.env index 54864c9..de1f174 100644 --- a/.env +++ b/.env @@ -11,7 +11,7 @@ BLOCK_MODE = false FLOW_PROCESS_CONFIG_KEY = standard -FLOW_USE_CUSTOM_PROCESS = false +FLOW_USE_CUSTOM_PROCESS = true # 机器ID,用于分布式环境,确保唯一。0 为使用 MAC 地址,HASH 散列两位 MACHINE_ID = 0 diff --git a/app/config/TODO.md b/app/config/TODO.md index 3e7d71a..0ed004f 100644 --- a/app/config/TODO.md +++ b/app/config/TODO.md @@ -4,4 +4,8 @@ 刷两次代表加强洗 -网关阻断 \ No newline at end of file +网关阻断 + +动态提示请刷XXX + +配置文件 required 无法生效 \ No newline at end of file diff --git a/app/config/custom_process_config.php b/app/config/custom_process_config.php index 994c77d..58436a4 100644 --- a/app/config/custom_process_config.php +++ b/app/config/custom_process_config.php @@ -23,7 +23,7 @@ return [ 'steps' => [ ['code' => '晨洗', 'class' => 'MorningWashNode', 'enabled' => true], ['code' => '清洗', 'class' => 'WashNode', 'enabled' => true,'required' => ['结束','晨洗']], - ['code' => '漂洗', 'class' => 'RinseNode', 'enabled' => true], + ['code' => '漂洗', 'class' => 'RinseNode', 'enabled' => true,'required' => ['结束']], ['code' => '消毒', 'class' => 'DisinfectNode', 'enabled' => true], ['code' => '终末漂洗', 'class' => 'FinalRinseNode', 'enabled' => true], ['code' => '干燥', 'class' => 'DryNode', 'enabled' => true], diff --git a/app/flow/ProcessEngine.php b/app/flow/ProcessEngine.php index 996ec38..b530f28 100644 --- a/app/flow/ProcessEngine.php +++ b/app/flow/ProcessEngine.php @@ -82,7 +82,7 @@ class ProcessEngine protected function buildChain(): void { Logger::debug("[ProcessEngine] 构建流程链..."); - $steps = $this->config->getSteps(); + $steps = $this->config->getSteps(); $prevNode = null; foreach ($steps as $step) { @@ -119,7 +119,7 @@ class ProcessEngine $prevNode = $node; Logger::debug("[{}] 节点创建完成", [$node->getName()]); } - Logger::debug("[ProcessEngine] 流程链构建完成"); + Logger::debug("[ProcessEngine] 流程链构建完成 node:{},steps:{}", [$this->chainHead->getChildNodeCount() + 1, count($steps)]); } /** @@ -178,13 +178,13 @@ class ProcessEngine if ($this->chainHead === null) { return $context->builder()->error(VoiceMessage::PROCESS_CHAIN_NOT_INITIALIZED)->build(); } - + Logger::debug('[ProcessEngine] 开始执行流程链 readerType={} currentStep={} endoscope={}', [ $context->getReader()->type, $context->getCurrentStep() ?: '(空)', $context->getEndoscope()->name ?: $context->getEndoscope()->id ?: '-', ]); - + $result = $this->chainHead->handle($context); Logger::debug('[ProcessEngine] 流程执行完成 endoscope={} step={} success={} error={}', [ @@ -193,7 +193,7 @@ class ProcessEngine $result->isSuccess() ? 'true' : 'false', $result->getVoice()->errorMessage->value ?: '-', ]); - + return $result; } diff --git a/app/flow/config/StepsConfig.php b/app/flow/config/StepsConfig.php index b64b0f7..8f8d0f7 100644 --- a/app/flow/config/StepsConfig.php +++ b/app/flow/config/StepsConfig.php @@ -29,7 +29,20 @@ class StepsConfig extends AbstractConfig } elseif ($override) { $this->steps = $parsed; } else { - $this->steps = array_merge(self::defaultSteps(), $parsed); + // 核心逻辑:合并默认步骤 + 自定义步骤,重复 code 以自定义步骤为准 + // 1. 将默认步骤转为「code => StepConfig」的关联数组(方便快速查找/覆盖) + $defaultStepsMap = []; + foreach (self::defaultSteps() as $defaultStep) { + $defaultStepsMap[$defaultStep->code] = $defaultStep; + } + + // 2. 遍历自定义步骤,覆盖默认步骤中相同 code 的元素 + foreach ($parsed as $customStep) { + $defaultStepsMap[$customStep->code] = $customStep; + } + + // 3. 转回索引数组(重置键名从0开始),赋值给 $this->steps + $this->steps = array_values($defaultStepsMap); } } @@ -152,12 +165,13 @@ class StepsConfig extends AbstractConfig */ private static function createStep(array $step): StepConfig { - $known = ['code', 'class', 'enabled']; + $known = ['code', 'class', 'enabled', 'required']; $expand = array_diff_key($step, array_flip($known)); return new StepConfig( $step['code'], $step['class'], $step['enabled'] ?? true, + $step['required'] ?? [], $expand ); } diff --git a/app/flow/nodes/AbstractProcessNode.php b/app/flow/nodes/AbstractProcessNode.php index 7080fe8..07297ed 100644 --- a/app/flow/nodes/AbstractProcessNode.php +++ b/app/flow/nodes/AbstractProcessNode.php @@ -138,6 +138,14 @@ abstract class AbstractProcessNode implements ProcessNodeInterface return (!empty($this->getConfig()->required)) ? $this->getConfig()->required : $default; } + /** + * 获取子节点数量 + */ + public function getChildNodeCount(): int + { + return count($this->getChildNodes()); + } + /** * 是否是需要的前置节点 * @param string $currentStep @@ -174,14 +182,14 @@ abstract class AbstractProcessNode implements ProcessNodeInterface protected function stopNext(ProcessContext $context): ProcessContext { return $context->builder() - ->skipNodeCount(count($this->getRemainingNodes())) + ->skipNodeCount(count($this->getChildNodes())) ->build(); } /** * 获取剩余节点 */ - protected function getRemainingNodes(): array + public function getChildNodes(): array { $remainingNodes = []; $node = $this->next; diff --git a/app/flow/nodes/ProcessNodeInterface.php b/app/flow/nodes/ProcessNodeInterface.php index 39c394c..3ce84a3 100644 --- a/app/flow/nodes/ProcessNodeInterface.php +++ b/app/flow/nodes/ProcessNodeInterface.php @@ -31,6 +31,10 @@ interface ProcessNodeInterface */ public function handle(ProcessContext $context): ProcessContext; + + public function getChildNodes(): array; + public function getChildNodeCount(): int; + /** * 获取节点名称 * @return string diff --git a/app/flow/nodes/StorageInNode.php b/app/flow/nodes/StorageInNode.php index e217409..69a8969 100644 --- a/app/flow/nodes/StorageInNode.php +++ b/app/flow/nodes/StorageInNode.php @@ -63,7 +63,7 @@ class StorageInNode extends AbstractProcessNode // 检查前置步骤要求 $validSteps = ['', '结束', '内镜取出', '测漏正常', '测漏异常']; - if (!in_array($context->getCurrentStep(), $validSteps)) { + if (!$this->isRequiredNode($context->getCurrentStep(), $validSteps)) { Logger::debug('[StorageInNode] 当前步骤 {} 不符合入库条件', [$context->getCurrentStep()]); return CanHandleResult::cannotHandle(); } diff --git a/app/flow/nodes/StorageNode.php b/app/flow/nodes/StorageNode.php index 1a8a1a7..83048cc 100644 --- a/app/flow/nodes/StorageNode.php +++ b/app/flow/nodes/StorageNode.php @@ -60,14 +60,14 @@ class StorageNode extends AbstractProcessNode if ($isInStorage) { // 内镜已在库中,执行出库 $validSteps = ['内镜放入', '结束']; - if (!in_array($context->getCurrentStep(), $validSteps)) { + if (!$this->isRequiredNode($context->getCurrentStep(), $validSteps)) { Logger::debug('[StorageNode] 当前步骤 {} 不符合出库条件', [$context->getCurrentStep()]); return CanHandleResult::cannotHandle(); } } else { // 内镜不在库中,执行入库 $validSteps = ['', '结束', '内镜取出', '测漏正常', '测漏异常']; - if (!in_array($context->getCurrentStep(), $validSteps)) { + if (!$this->isRequiredNode($context->getCurrentStep(), $validSteps)) { Logger::debug('[StorageNode] 当前步骤 {} 不符合入库条件', [$context->getCurrentStep()]); return CanHandleResult::cannotHandle(); } diff --git a/app/flow/nodes/StorageOutNode.php b/app/flow/nodes/StorageOutNode.php index 68183f0..7f79cac 100644 --- a/app/flow/nodes/StorageOutNode.php +++ b/app/flow/nodes/StorageOutNode.php @@ -63,7 +63,7 @@ class StorageOutNode extends AbstractProcessNode // 检查前置步骤要求:必须在库中才能出库 $validSteps = ['内镜放入', '结束']; - if (!in_array($context->getCurrentStep(), $validSteps)) { + if (!$this->isRequiredNode($context->getCurrentStep(), $validSteps)) { Logger::debug('[StorageOutNode] 当前步骤 {} 不符合出库条件', [$context->getCurrentStep()]); return CanHandleResult::cannotHandle(); } diff --git a/app/flow/nodes/WashNode.php b/app/flow/nodes/WashNode.php index 2c7e1b0..4b845cc 100644 --- a/app/flow/nodes/WashNode.php +++ b/app/flow/nodes/WashNode.php @@ -49,8 +49,10 @@ class WashNode extends AbstractProcessNode return CanHandleResult::cannotHandle(VoiceMessage::PLEASE_SWIPE_MORNING_WASH); } + + $validCurrentSteps = ['', '结束', '内镜取出', '内镜放入', '测漏正常', '晨洗']; - if (!in_array($context->getCurrentStep(), $validCurrentSteps)) { + if (!$this->isRequiredNode($context->getCurrentStep(), $validCurrentSteps)) { // 读卡器是清洗但步骤不对(如终末漂洗时刷清洗),提示应该先刷结束 return CanHandleResult::cannotHandle(); }