ai-chore(config): 调整流程配置及改进测试代码

- 将 FLOW_USE_CUSTOM_PROCESS 从 true 改为 false,禁用自定义流程
- 在 BlockTest 测试用例中改用 setBlockMode 方法设置阻断模式
- 设置统一的错误处理,将错误转为异常抛出
- 重命名 BlockTest 测试文件路径,优化测试组织结构
- 更新 IDE php include paths,调整依赖包引用顺序
- 删除无用的 tests/flow/Test.php 测试文件
- 微调 start.php、webman、windows.php 配置或代码模块
This commit is contained in:
zimoyin
2026-03-11 13:48:40 +08:00
parent 6c874221ad
commit f2ff4ae123
42 changed files with 246 additions and 158 deletions
+3
View File
@@ -7,6 +7,9 @@ DB_PASSWORD = user
DB_DEBUG = false DB_DEBUG = false
BLOCK_MODE = false
FLOW_PROCESS_CONFIG_KEY = standard FLOW_PROCESS_CONFIG_KEY = standard
FLOW_USE_CUSTOM_PROCESS = false FLOW_USE_CUSTOM_PROCESS = false
File diff suppressed because one or more lines are too long
+2
View File
@@ -3,3 +3,5 @@
内镜未刷取出就操作 内镜未刷取出就操作
刷两次代表加强洗 刷两次代表加强洗
网关阻断
+1
View File
@@ -4,6 +4,7 @@ namespace app\flow;
use app\config\Config; use app\config\Config;
use app\flow\config\ProcessConfig; use app\flow\config\ProcessConfig;
use app\flow\context\ProcessContext;
use app\net\PacketContext; use app\net\PacketContext;
use app\utils\Logger; use app\utils\Logger;
+1 -1
View File
@@ -94,7 +94,7 @@ class FlowProcessor
if ($mgr->hasOperator($context->getReader()->id) || $context->hasOperator()) { if ($mgr->hasOperator($context->getReader()->id) || $context->hasOperator()) {
if ($mgr->hasOperator($context->getReader()->id)) { if ($mgr->hasOperator($context->getReader()->id)) {
$op = $mgr->getOperator($context->getReader()->id, $context->getReader()->type); $op = $mgr->getOperator($context->getReader()->id, $context->getReader()->type);
$context = $context->builder()->withOperator(new \app\flow\vo\OperatorInfo( $context = $context->builder()->withOperator(new \app\flow\context\bean\OperatorInfo(
id: $op['id'], id: $op['id'],
name: $op['name'], name: $op['name'],
rfid: $op['rfid'] rfid: $op['rfid']
+8 -2
View File
@@ -103,7 +103,13 @@ class OperatorSessionManager
*/ */
public function hasOperator(string $readerId): bool public function hasOperator(string $readerId): bool
{ {
return isset($this->sessions[$readerId]); $cache = $this->sessions[$readerId] ?? null;
if (empty($cache)) return false;
// 如果时间过去了,返回没有
if ($this->expire > 0 && isset($cache['time']) && (time() - $cache['time']) > $this->expire) {
return false;
}
return true;
} }
/** /**
@@ -124,7 +130,7 @@ class OperatorSessionManager
public function pop(string $readerId): ?array public function pop(string $readerId): ?array
{ {
$op = $this->getOperator($readerId); $op = $this->sessions[$readerId] ?? null;
$this->clearOperator($readerId); $this->clearOperator($readerId);
return $op; return $op;
} }
+12 -11
View File
@@ -3,15 +3,16 @@
namespace app\flow\context; namespace app\flow\context;
use app\flow\config\ProcessConfig; use app\flow\config\ProcessConfig;
use app\flow\vo\EndoscopeInfo; use app\flow\context\bean\EndoscopeInfo;
use app\flow\vo\ExecutionResult; use app\flow\context\bean\ExecutionResult;
use app\flow\vo\MorningWashStatus; use app\flow\context\bean\MorningWashStatus;
use app\flow\vo\OperatorInfo; use app\flow\context\bean\OperatorInfo;
use app\flow\vo\ProcessStatus; use app\flow\context\bean\ProcessStatus;
use app\flow\vo\ReaderInfo; use app\flow\context\bean\ReaderInfo;
use app\flow\vo\ReminderStatus; use app\flow\context\bean\ReminderStatus;
use app\flow\vo\StorageStatus; use app\flow\context\bean\StorageStatus;
use app\flow\vo\VoiceState; use app\flow\context\bean\VoiceState;
use app\model\EctActions;
use app\net\PacketContext; use app\net\PacketContext;
/** /**
@@ -206,9 +207,9 @@ readonly class ProcessContext
/** /**
* 获取上一个操作记录 * 获取上一个操作记录
* @return \app\model\EctActions|null 上一个操作记录 (来源: ProcessStatus) * @return EctActions|null 上一个操作记录 (来源: ProcessStatus)
*/ */
public function getPreviousAction(): ?\app\model\EctActions public function getPreviousAction(): ?EctActions
{ {
return $this->processStatus->previousAction; return $this->processStatus->previousAction;
} }
+12 -10
View File
@@ -4,18 +4,18 @@ namespace app\flow\context;
use app\config\Config; use app\config\Config;
use app\flow\config\ProcessConfig; use app\flow\config\ProcessConfig;
use app\flow\vo\EndoscopeInfo; use app\flow\context\bean\EndoscopeInfo;
use app\flow\vo\ExecutionResult; use app\flow\context\bean\ExecutionResult;
use app\flow\vo\MorningWashStatus; use app\flow\context\bean\MorningWashStatus;
use app\flow\vo\OperatorInfo; use app\flow\context\bean\OperatorInfo;
use app\flow\vo\ProcessStatus; use app\flow\context\bean\ProcessStatus;
use app\flow\vo\ReaderInfo; use app\flow\context\bean\ReaderInfo;
use app\flow\vo\ReminderStatus; use app\flow\context\bean\ReminderStatus;
use app\flow\vo\StorageStatus; use app\flow\context\bean\StorageStatus;
use app\flow\vo\VoiceState; use app\flow\context\bean\VoiceState;
use app\flow\enum\DbOperationType; use app\flow\enum\DbOperationType;
use app\flow\enum\VoiceMessage; use app\flow\enum\VoiceMessage;
use app\flow\vo\BatchNo; use app\flow\context\bean\BatchNo;
use app\model\EctActions; use app\model\EctActions;
use app\net\PacketContext; use app\net\PacketContext;
use app\repository\EctActionsRepository; use app\repository\EctActionsRepository;
@@ -79,6 +79,7 @@ class ProcessContextBuilder
$builder = new self(); $builder = new self();
$builder->packetContext = $packetContext; $builder->packetContext = $packetContext;
$builder->engineConfig = $additionalData['engineConfig'] ?? null; $builder->engineConfig = $additionalData['engineConfig'] ?? null;
if (empty($builder->engineConfig)) Logger::warn("fromPacketContext 需要通过 additionalData 传递 engineConfig");
// 获取原始卡号和读卡器编号 // 获取原始卡号和读卡器编号
$cardNo = $packetContext->packet->card ?? ''; $cardNo = $packetContext->packet->card ?? '';
@@ -228,6 +229,7 @@ class ProcessContextBuilder
// 查询今日洗消记录数(晨洗判断) // 查询今日洗消记录数(晨洗判断)
$todayWashRecords = $actionsRepo->countTodayActions($this->endoscope->id, $this->morningStartTime, [0, 7, 8]); $todayWashRecords = $actionsRepo->countTodayActions($this->endoscope->id, $this->morningStartTime, [0, 7, 8]);
Logger::debug("{} 内镜今日洗消记录数: {}", [$this->endoscope->name,$todayWashRecords]);
$this->morningWash = new MorningWashStatus( $this->morningWash = new MorningWashStatus(
needMorningWash: $this->morningWash->needMorningWash, needMorningWash: $this->morningWash->needMorningWash,
morningWashed: $this->morningWash->morningWashed, morningWashed: $this->morningWash->morningWashed,
@@ -1,6 +1,6 @@
<?php <?php
namespace app\flow\vo; namespace app\flow\context\bean;
use app\config\Config; use app\config\Config;
use app\repository\EctActionsRepository; use app\repository\EctActionsRepository;
@@ -14,7 +14,9 @@ readonly class BatchNo
public function __construct( public function __construct(
/** 批次号值 */ /** 批次号值 */
public string $value = '', public string $value = '',
) {} )
{
}
/** /**
* 创建空批次号 * 创建空批次号
@@ -86,6 +88,20 @@ readonly class BatchNo
]; ];
} }
/**
* 解析批次号结构
* @deprecated
* @return array{date: string, machineId: string, sequence: int, dateFormatted: string}
*/
public static function parseBatchNo(string $batchNo): array
{
$batch = BatchNo::fromString($batchNo);
if (!$batch->isValid()) {
throw new \InvalidArgumentException('Invalid batch string: ' . $batchNo);
}
return $batch->parse();
}
/** /**
* 验证批次号格式是否有效 * 验证批次号格式是否有效
*/ */
@@ -123,12 +139,23 @@ readonly class BatchNo
/** /**
* 获取日期部分 * 获取日期部分
*/ */
public function getDate(): string public function getDateStr(): string
{ {
$parsed = $this->parse(); $parsed = $this->parse();
return $parsed['dateFormatted']; return $parsed['dateFormatted'];
} }
/**
* 获取时间戳
* @return int|false
*/
public function getTimestamp(): int|false
{
$parsed = $this->parse();
return strtotime($parsed['dateFormatted']);
}
/** /**
* 获取机器ID * 获取机器ID
*/ */
@@ -1,6 +1,6 @@
<?php <?php
namespace app\flow\vo; namespace app\flow\context\bean;
use app\flow\enum\VoiceMessage; use app\flow\enum\VoiceMessage;
@@ -20,7 +20,7 @@ readonly class CanHandleResult
/** /**
* 创建可以处理的结果 * 创建可以处理的结果
*/ */
public static function yes(): self public static function canHandle(): self
{ {
return new self(canHandle: true); return new self(canHandle: true);
} }
@@ -28,7 +28,7 @@ readonly class CanHandleResult
/** /**
* 创建不能处理的结果 * 创建不能处理的结果
*/ */
public static function no(?VoiceMessage $expectedNextStep = null): self public static function cannotHandle(?VoiceMessage $expectedNextStep = null): self
{ {
return new self( return new self(
canHandle: false, canHandle: false,
@@ -1,6 +1,6 @@
<?php <?php
namespace app\flow\vo; namespace app\flow\context\bean;
/** /**
* 内镜信息值对象 * 内镜信息值对象
@@ -1,6 +1,6 @@
<?php <?php
namespace app\flow\vo; namespace app\flow\context\bean;
use app\flow\enum\DbOperationType; use app\flow\enum\DbOperationType;
@@ -1,6 +1,6 @@
<?php <?php
namespace app\flow\vo; namespace app\flow\context\bean;
/** /**
* 晨洗状态值对象 * 晨洗状态值对象
@@ -1,6 +1,6 @@
<?php <?php
namespace app\flow\vo; namespace app\flow\context\bean;
/** /**
* 操作员信息值对象 * 操作员信息值对象
@@ -1,6 +1,6 @@
<?php <?php
namespace app\flow\vo; namespace app\flow\context\bean;
use app\model\EctActions; use app\model\EctActions;
@@ -1,6 +1,6 @@
<?php <?php
namespace app\flow\vo; namespace app\flow\context\bean;
/** /**
* 读卡器信息值对象 * 读卡器信息值对象
@@ -1,6 +1,6 @@
<?php <?php
namespace app\flow\vo; namespace app\flow\context\bean;
/** /**
* 提醒状态值对象 * 提醒状态值对象
@@ -1,6 +1,6 @@
<?php <?php
namespace app\flow\vo; namespace app\flow\context\bean;
/** /**
* 存储状态值对象 * 存储状态值对象
@@ -1,6 +1,6 @@
<?php <?php
namespace app\flow\vo; namespace app\flow\context\bean;
use app\flow\enum\VoiceMessage; use app\flow\enum\VoiceMessage;
+3 -1
View File
@@ -44,7 +44,9 @@ enum VoiceMessage: string
case PLEASE_SWIPE_MORNING_WASH = '请刷消毒或机洗,开启晨洗流程'; case PLEASE_SWIPE_MORNING_WASH = '请刷消毒或机洗,开启晨洗流程';
// 流程链未初始化 // 流程链未初始化
case PROCESS_CHAIN_NOT_INITIALIZED = '流程链未初始化'; case PROCESS_CHAIN_NOT_INITIALIZED = '流程链未初始化';
case UNKNOWN_ERROR = '未知错误';
// 未知错误,通常是无节点匹配的时候
case UNKNOWN_ERROR = '未知错误,无匹配的节点';
// 卡号未绑定 // 卡号未绑定
case CARD_NOT_BOUND = '卡号未绑定'; case CARD_NOT_BOUND = '卡号未绑定';
+3 -3
View File
@@ -5,7 +5,7 @@ namespace app\flow\nodes;
use app\flow\config\StepConfig; use app\flow\config\StepConfig;
use app\flow\context\ProcessContext; use app\flow\context\ProcessContext;
use app\flow\strategies\ProcessStrategyInterface; use app\flow\strategies\ProcessStrategyInterface;
use app\flow\vo\CanHandleResult; use app\flow\context\bean\CanHandleResult;
use app\utils\Logger; use app\utils\Logger;
/** /**
@@ -302,9 +302,9 @@ abstract class AbstractProcessNode implements ProcessNodeInterface
public function canHandle(ProcessContext $context): CanHandleResult public function canHandle(ProcessContext $context): CanHandleResult
{ {
if ($context->getCurrentStep() === $this->getCode()) { if ($context->getCurrentStep() === $this->getCode()) {
return CanHandleResult::yes(); return CanHandleResult::canHandle();
} }
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
/** /**
+3 -3
View File
@@ -5,7 +5,7 @@ namespace app\flow\nodes;
use app\flow\enum\DbOperationType; use app\flow\enum\DbOperationType;
use app\flow\context\ProcessContext; use app\flow\context\ProcessContext;
use app\flow\enum\VoiceMessage; use app\flow\enum\VoiceMessage;
use app\flow\vo\CanHandleResult; use app\flow\context\bean\CanHandleResult;
use app\repository\EctActionsRepository; use app\repository\EctActionsRepository;
use app\utils\Logger; use app\utils\Logger;
@@ -39,9 +39,9 @@ class CloseNode extends AbstractProcessNode
public function canHandle(ProcessContext $context): CanHandleResult public function canHandle(ProcessContext $context): CanHandleResult
{ {
if (!$context->isSuccess() || $context->isDatabaseOperationNeeded() || !empty($context->getVoice()->message)) { if (!$context->isSuccess() || $context->isDatabaseOperationNeeded() || !empty($context->getVoice()->message)) {
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
return CanHandleResult::yes(); return CanHandleResult::canHandle();
} }
/** /**
+6 -6
View File
@@ -5,7 +5,7 @@ namespace app\flow\nodes;
use app\flow\enum\DbOperationType; use app\flow\enum\DbOperationType;
use app\flow\context\ProcessContext; use app\flow\context\ProcessContext;
use app\flow\enum\VoiceMessage; use app\flow\enum\VoiceMessage;
use app\flow\vo\CanHandleResult; use app\flow\context\bean\CanHandleResult;
/** /**
* 消毒节点 * 消毒节点
@@ -36,22 +36,22 @@ class DisinfectNode extends AbstractProcessNode
{ {
// 如果内镜未取出 // 如果内镜未取出
if ($context->getStorage()->isInStorage) { if ($context->getStorage()->isInStorage) {
return CanHandleResult::no(VoiceMessage::PLEASE_SWIPE_STORAGE_OUT); return CanHandleResult::cannotHandle(VoiceMessage::PLEASE_SWIPE_STORAGE_OUT);
} }
if (!$this->isMatchReaderType($context)) { if (!$this->isMatchReaderType($context)) {
if ($context->getCurrentStep() === RinseNode::getName()) { if ($context->getCurrentStep() === RinseNode::getName()) {
return CanHandleResult::no(VoiceMessage::PLEASE_SWIPE_DISINFECT); return CanHandleResult::cannotHandle(VoiceMessage::PLEASE_SWIPE_DISINFECT);
} }
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
// 上一个步骤必须是漂洗 或者 晨洗 // 上一个步骤必须是漂洗 或者 晨洗
if (!$this->isRequiredNode($context->getCurrentStep(), [RinseNode::getName(), MorningWashNode::getName()])) { if (!$this->isRequiredNode($context->getCurrentStep(), [RinseNode::getName(), MorningWashNode::getName()])) {
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
return CanHandleResult::yes(); return CanHandleResult::canHandle();
} }
/** /**
+6 -6
View File
@@ -5,7 +5,7 @@ namespace app\flow\nodes;
use app\flow\enum\DbOperationType; use app\flow\enum\DbOperationType;
use app\flow\context\ProcessContext; use app\flow\context\ProcessContext;
use app\flow\enum\VoiceMessage; use app\flow\enum\VoiceMessage;
use app\flow\vo\CanHandleResult; use app\flow\context\bean\CanHandleResult;
use app\utils\Logger; use app\utils\Logger;
/** /**
@@ -40,23 +40,23 @@ class DryNode extends AbstractProcessNode
{ {
// 如果内镜未取出 // 如果内镜未取出
if ($context->getStorage()->isInStorage) { if ($context->getStorage()->isInStorage) {
return CanHandleResult::no(VoiceMessage::PLEASE_SWIPE_STORAGE_OUT); return CanHandleResult::cannotHandle(VoiceMessage::PLEASE_SWIPE_STORAGE_OUT);
} }
if (!$this->isMatchReaderType($context)) { if (!$this->isMatchReaderType($context)) {
if ($context->getCurrentStep() === FinalRinseNode::getName()) { if ($context->getCurrentStep() === FinalRinseNode::getName()) {
if (!$context->isSuccess()) Logger::debug("[DryNode] 刷卡错误,当前步骤是终末漂洗,但是刷的读卡器类型不是终末漂洗,对用户进行语音提示刷终末漂洗读卡器"); if (!$context->isSuccess()) Logger::debug("[DryNode] 刷卡错误,当前步骤是终末漂洗,但是刷的读卡器类型不是终末漂洗,对用户进行语音提示刷终末漂洗读卡器");
return CanHandleResult::no(VoiceMessage::PLEASE_SWIPE_DRY); return CanHandleResult::cannotHandle(VoiceMessage::PLEASE_SWIPE_DRY);
} }
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
// 上一个步骤必须是终末漂洗 // 上一个步骤必须是终末漂洗
if (!$this->isRequiredNode($context->getCurrentStep(), [FinalRinseNode::getName()])) { if (!$this->isRequiredNode($context->getCurrentStep(), [FinalRinseNode::getName()])) {
return CanHandleResult::no(VoiceMessage::PLEASE_SWIPE_DISINFECT); return CanHandleResult::cannotHandle(VoiceMessage::PLEASE_SWIPE_DISINFECT);
} }
return CanHandleResult::yes(); return CanHandleResult::canHandle();
} }
/** /**
+3 -3
View File
@@ -5,7 +5,7 @@ namespace app\flow\nodes;
use app\flow\enum\DbOperationType; use app\flow\enum\DbOperationType;
use app\flow\context\ProcessContext; use app\flow\context\ProcessContext;
use app\flow\enum\VoiceMessage; use app\flow\enum\VoiceMessage;
use app\flow\vo\CanHandleResult; use app\flow\context\bean\CanHandleResult;
use app\repository\EctActionsRepository; use app\repository\EctActionsRepository;
use app\utils\Logger; use app\utils\Logger;
@@ -40,9 +40,9 @@ class DuplicateCheckNode extends AbstractProcessNode
public function canHandle(ProcessContext $context): CanHandleResult public function canHandle(ProcessContext $context): CanHandleResult
{ {
if ($context->getPreviousAction()?->process_name === $context->getReader()->type) { if ($context->getPreviousAction()?->process_name === $context->getReader()->type) {
return CanHandleResult::yes(); return CanHandleResult::canHandle();
} }
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
/** /**
+9 -10
View File
@@ -5,7 +5,7 @@ namespace app\flow\nodes;
use app\flow\enum\DbOperationType; use app\flow\enum\DbOperationType;
use app\flow\context\ProcessContext; use app\flow\context\ProcessContext;
use app\flow\enum\VoiceMessage; use app\flow\enum\VoiceMessage;
use app\flow\vo\CanHandleResult; use app\flow\context\bean\CanHandleResult;
/** /**
* 结束节点 * 结束节点
@@ -36,26 +36,25 @@ class EndNode extends AbstractProcessNode
{ {
// 如果内镜未取出 // 如果内镜未取出
if ($context->getStorage()->isInStorage) { if ($context->getStorage()->isInStorage) {
return CanHandleResult::no(VoiceMessage::PLEASE_SWIPE_STORAGE_OUT); return CanHandleResult::cannotHandle(VoiceMessage::PLEASE_SWIPE_STORAGE_OUT);
} }
if (!$this->isMatchReaderType($context)) { if (!$this->isMatchReaderType($context)) {
if ($context->getCurrentStep() === DryNode::getName() && $context->getCurrentStep() === FinalRinseNode::getName()) { if ($context->getCurrentStep() === DryNode::getName() || $context->getCurrentStep() === FinalRinseNode::getName()) {
return CanHandleResult::no(VoiceMessage::PLEASE_SWIPE_END); return CanHandleResult::cannotHandle(VoiceMessage::PLEASE_SWIPE_END);
} }
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
// 上一个步骤必须是干燥、终末漂洗或机洗 // 上一个步骤必须是干燥、终末漂洗或机洗
$validSteps = ['干燥', '终末漂洗', '机洗']; if (!$this->isRequiredNode($context->getCurrentStep(), ['干燥', '终末漂洗', '机洗'])) {
if ($this->isRequiredNode($context->getCurrentStep(), ['干燥', '终末漂洗', '机洗'])) {
if ($context->getCurrentStep() === FinalRinseNode::getName()) { if ($context->getCurrentStep() === FinalRinseNode::getName()) {
return CanHandleResult::no(VoiceMessage::PLEASE_SWIPE_WASH); return CanHandleResult::cannotHandle(VoiceMessage::PLEASE_SWIPE_WASH);
} }
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
return CanHandleResult::yes(); return CanHandleResult::canHandle();
} }
/** /**
+6 -6
View File
@@ -5,7 +5,7 @@ namespace app\flow\nodes;
use app\flow\enum\DbOperationType; use app\flow\enum\DbOperationType;
use app\flow\context\ProcessContext; use app\flow\context\ProcessContext;
use app\flow\enum\VoiceMessage; use app\flow\enum\VoiceMessage;
use app\flow\vo\CanHandleResult; use app\flow\context\bean\CanHandleResult;
use app\utils\Logger; use app\utils\Logger;
/** /**
@@ -39,22 +39,22 @@ class FinalRinseNode extends AbstractProcessNode
{ {
// 如果内镜未取出 // 如果内镜未取出
if ($context->getStorage()->isInStorage) { if ($context->getStorage()->isInStorage) {
return CanHandleResult::no(VoiceMessage::PLEASE_SWIPE_STORAGE_OUT); return CanHandleResult::cannotHandle(VoiceMessage::PLEASE_SWIPE_STORAGE_OUT);
} }
if (!$this->isMatchReaderType($context)) { if (!$this->isMatchReaderType($context)) {
if ($context->getCurrentStep() === DisinfectNode::getName()) { if ($context->getCurrentStep() === DisinfectNode::getName()) {
if (!$context->isSuccess()) Logger::debug("[FinalRinseNode] 刷卡错误,当前步骤是消毒,但是刷的读卡器类型不是消毒,对用户进行语音提示刷消毒读卡器"); if (!$context->isSuccess()) Logger::debug("[FinalRinseNode] 刷卡错误,当前步骤是消毒,但是刷的读卡器类型不是消毒,对用户进行语音提示刷消毒读卡器");
return CanHandleResult::no(VoiceMessage::PLEASE_SWIPE_FINAL_RINSE); return CanHandleResult::cannotHandle(VoiceMessage::PLEASE_SWIPE_FINAL_RINSE);
} }
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
// 上一个步骤必须是消毒或机洗 // 上一个步骤必须是消毒或机洗
if ($this->isRequiredNode($context->getCurrentStep(), ['消毒', '机洗'])) { if ($this->isRequiredNode($context->getCurrentStep(), ['消毒', '机洗'])) {
return CanHandleResult::yes(); return CanHandleResult::canHandle();
} }
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
/** /**
+8 -8
View File
@@ -5,7 +5,7 @@ namespace app\flow\nodes;
use app\flow\enum\DbOperationType; use app\flow\enum\DbOperationType;
use app\flow\context\ProcessContext; use app\flow\context\ProcessContext;
use app\flow\enum\VoiceMessage; use app\flow\enum\VoiceMessage;
use app\flow\vo\CanHandleResult; use app\flow\context\bean\CanHandleResult;
/** /**
* 机洗节点 * 机洗节点
@@ -36,30 +36,30 @@ class MachineWashNode extends AbstractProcessNode
{ {
// 如果内镜未取出 // 如果内镜未取出
if ($context->getStorage()->isInStorage) { if ($context->getStorage()->isInStorage) {
return CanHandleResult::no(VoiceMessage::PLEASE_SWIPE_STORAGE_OUT); return CanHandleResult::cannotHandle(VoiceMessage::PLEASE_SWIPE_STORAGE_OUT);
} }
if (!$this->isMatchReaderType($context)) { if (!$this->isMatchReaderType($context)) {
if ($context->getCurrentStep() === WashNode::getName()) { if ($context->getCurrentStep() === WashNode::getName()) {
return CanHandleResult::no(VoiceMessage::PLEASE_SWIPE_MACHINE_WASH); return CanHandleResult::cannotHandle(VoiceMessage::PLEASE_SWIPE_MACHINE_WASH);
} }
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
// 需要晨洗但未完成:提示先进行晨洗 // 需要晨洗但未完成:提示先进行晨洗
if ($context->getMorningWash()->needMorningWash && !$context->getMorningWash()->morningWashed) { if ($context->getMorningWash()->needMorningWash && !$context->getMorningWash()->morningWashed) {
return CanHandleResult::no(VoiceMessage::PLEASE_SWIPE_MORNING_WASH); return CanHandleResult::cannotHandle(VoiceMessage::PLEASE_SWIPE_MORNING_WASH);
} }
// 机洗可以在多个步骤后执行:空步骤(新流程)、结束、内镜取出、清洗,晨洗 // 机洗可以在多个步骤后执行:空步骤(新流程)、结束、内镜取出、清洗,晨洗
if (!$this->isRequiredNode($context->getCurrentStep(), ['', '结束', '内镜取出', '清洗', MachineWashNode::getName()])) { if (!$this->isRequiredNode($context->getCurrentStep(), ['', '结束', '内镜取出', '清洗', MachineWashNode::getName()])) {
if ($context->getCurrentStep() === EndNode::getName()) { if ($context->getCurrentStep() === EndNode::getName()) {
return CanHandleResult::no(VoiceMessage::PLEASE_SWIPE_MACHINE_WASH); return CanHandleResult::cannotHandle(VoiceMessage::PLEASE_SWIPE_MACHINE_WASH);
} }
return CanHandleResult::no(VoiceMessage::PLEASE_SWIPE_END); return CanHandleResult::cannotHandle(VoiceMessage::PLEASE_SWIPE_END);
} }
return CanHandleResult::yes(); return CanHandleResult::canHandle();
} }
/** /**
+6 -6
View File
@@ -5,8 +5,8 @@ namespace app\flow\nodes;
use app\flow\enum\DbOperationType; use app\flow\enum\DbOperationType;
use app\flow\context\ProcessContext; use app\flow\context\ProcessContext;
use app\flow\enum\VoiceMessage; use app\flow\enum\VoiceMessage;
use app\flow\vo\CanHandleResult; use app\flow\context\bean\CanHandleResult;
use app\flow\vo\MorningWashStatus; use app\flow\context\bean\MorningWashStatus;
use app\utils\Logger; use app\utils\Logger;
/** /**
@@ -38,19 +38,19 @@ class MorningWashNode extends AbstractProcessNode
{ {
// 如果内镜未取出 // 如果内镜未取出
if ($context->getStorage()->isInStorage) { if ($context->getStorage()->isInStorage) {
return CanHandleResult::no(VoiceMessage::PLEASE_SWIPE_STORAGE_OUT); return CanHandleResult::cannotHandle(VoiceMessage::PLEASE_SWIPE_STORAGE_OUT);
} }
// 只有需要晨洗且未完成晨洗时才处理 // 只有需要晨洗且未完成晨洗时才处理
if (!$context->getMorningWash()->needMorningWash || $context->getMorningWash()->morningWashed) { if (!$context->getMorningWash()->needMorningWash || $context->getMorningWash()->morningWashed) {
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
// 检查当前读卡器类型是否匹配 // 检查当前读卡器类型是否匹配
if (!$this->isRequiredNode($context->getReader()->type, ['漂洗', '机洗'])){ if (!$this->isRequiredNode($context->getReader()->type, ['漂洗', '机洗'])){
return CanHandleResult::no(VoiceMessage::PLEASE_SWIPE_MORNING_WASH); return CanHandleResult::cannotHandle(VoiceMessage::PLEASE_SWIPE_MORNING_WASH);
} }
return CanHandleResult::yes(); return CanHandleResult::canHandle();
} }
/** /**
+1 -1
View File
@@ -3,7 +3,7 @@
namespace app\flow\nodes; namespace app\flow\nodes;
use app\flow\context\ProcessContext; use app\flow\context\ProcessContext;
use app\flow\vo\CanHandleResult; use app\flow\context\bean\CanHandleResult;
/** /**
* 流程节点接口 * 流程节点接口
+6 -6
View File
@@ -5,7 +5,7 @@ namespace app\flow\nodes;
use app\flow\enum\DbOperationType; use app\flow\enum\DbOperationType;
use app\flow\context\ProcessContext; use app\flow\context\ProcessContext;
use app\flow\enum\VoiceMessage; use app\flow\enum\VoiceMessage;
use app\flow\vo\CanHandleResult; use app\flow\context\bean\CanHandleResult;
/** /**
* 漂洗节点 * 漂洗节点
@@ -38,24 +38,24 @@ class RinseNode extends AbstractProcessNode
{ {
// 如果内镜未取出 // 如果内镜未取出
if ($context->getStorage()->isInStorage) { if ($context->getStorage()->isInStorage) {
return CanHandleResult::no(VoiceMessage::PLEASE_SWIPE_STORAGE_OUT); return CanHandleResult::cannotHandle(VoiceMessage::PLEASE_SWIPE_STORAGE_OUT);
} }
// 期望当前读卡器为漂洗 // 期望当前读卡器为漂洗
if (!$this->isMatchReaderType($context)) { if (!$this->isMatchReaderType($context)) {
// 当前步骤是清洗且读卡器不符:说明清洗完了应该刷漂洗 // 当前步骤是清洗且读卡器不符:说明清洗完了应该刷漂洗
if ($context->getCurrentStep() === WashNode::getName()) { if ($context->getCurrentStep() === WashNode::getName()) {
return CanHandleResult::no(VoiceMessage::PLEASE_SWIPE_RINSE); return CanHandleResult::cannotHandle(VoiceMessage::PLEASE_SWIPE_RINSE);
} }
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
// 上一个步骤必须是清洗 // 上一个步骤必须是清洗
if (!$this->isRequiredNode($context->getCurrentStep(), [WashNode::getName()])) { if (!$this->isRequiredNode($context->getCurrentStep(), [WashNode::getName()])) {
return CanHandleResult::no(VoiceMessage::PLEASE_SWIPE_WASH); return CanHandleResult::cannotHandle(VoiceMessage::PLEASE_SWIPE_WASH);
} }
return CanHandleResult::yes(); return CanHandleResult::canHandle();
} }
/** /**
+7 -7
View File
@@ -6,8 +6,8 @@ use app\config\Config;
use app\flow\enum\DbOperationType; use app\flow\enum\DbOperationType;
use app\flow\context\ProcessContext; use app\flow\context\ProcessContext;
use app\flow\enum\VoiceMessage; use app\flow\enum\VoiceMessage;
use app\flow\vo\CanHandleResult; use app\flow\context\bean\CanHandleResult;
use app\flow\vo\StorageStatus; use app\flow\context\bean\StorageStatus;
use app\utils\Logger; use app\utils\Logger;
/** /**
@@ -44,12 +44,12 @@ class StorageInNode extends AbstractProcessNode
// 单读卡器模式不处理,由 StorageNode 统一处理 // 单读卡器模式不处理,由 StorageNode 统一处理
if ($singleReaderMode) { if ($singleReaderMode) {
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
// 读卡器不是内镜放入类型,不处理 // 读卡器不是内镜放入类型,不处理
if (!$this->isMatchReaderType($context)) { if (!$this->isMatchReaderType($context)) {
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
// 获取内镜当前存储状态 // 获取内镜当前存储状态
@@ -58,17 +58,17 @@ class StorageInNode extends AbstractProcessNode
// 如果内镜已在库中,则当前应该是出库操作,不处理 // 如果内镜已在库中,则当前应该是出库操作,不处理
if ($isInStorage) { if ($isInStorage) {
Logger::debug('[StorageInNode] 内镜已在库中,转由出库节点处理'); Logger::debug('[StorageInNode] 内镜已在库中,转由出库节点处理');
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
// 检查前置步骤要求 // 检查前置步骤要求
$validSteps = ['', '结束', '内镜取出', '测漏正常', '测漏异常']; $validSteps = ['', '结束', '内镜取出', '测漏正常', '测漏异常'];
if (!in_array($context->getCurrentStep(), $validSteps)) { if (!in_array($context->getCurrentStep(), $validSteps)) {
Logger::debug('[StorageInNode] 当前步骤 {} 不符合入库条件', [$context->getCurrentStep()]); Logger::debug('[StorageInNode] 当前步骤 {} 不符合入库条件', [$context->getCurrentStep()]);
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
return CanHandleResult::yes(); return CanHandleResult::canHandle();
} }
/** /**
+7 -7
View File
@@ -6,8 +6,8 @@ use app\config\Config;
use app\flow\enum\DbOperationType; use app\flow\enum\DbOperationType;
use app\flow\context\ProcessContext; use app\flow\context\ProcessContext;
use app\flow\enum\VoiceMessage; use app\flow\enum\VoiceMessage;
use app\flow\vo\CanHandleResult; use app\flow\context\bean\CanHandleResult;
use app\flow\vo\StorageStatus; use app\flow\context\bean\StorageStatus;
use app\utils\Logger; use app\utils\Logger;
/** /**
@@ -47,12 +47,12 @@ class StorageNode extends AbstractProcessNode
// 非单读卡器模式不处理 // 非单读卡器模式不处理
if (!$singleReaderMode) { if (!$singleReaderMode) {
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
// 读卡器类型必须是'内镜放入'或'内镜取出' // 读卡器类型必须是'内镜放入'或'内镜取出'
if (!in_array($context->getReader()->type, ['内镜放入', '内镜取出'])) { if (!in_array($context->getReader()->type, ['内镜放入', '内镜取出'])) {
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
$isInStorage = $context->getStorage()->isInStorage; $isInStorage = $context->getStorage()->isInStorage;
@@ -62,18 +62,18 @@ class StorageNode extends AbstractProcessNode
$validSteps = ['内镜放入', '结束']; $validSteps = ['内镜放入', '结束'];
if (!in_array($context->getCurrentStep(), $validSteps)) { if (!in_array($context->getCurrentStep(), $validSteps)) {
Logger::debug('[StorageNode] 当前步骤 {} 不符合出库条件', [$context->getCurrentStep()]); Logger::debug('[StorageNode] 当前步骤 {} 不符合出库条件', [$context->getCurrentStep()]);
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
} else { } else {
// 内镜不在库中,执行入库 // 内镜不在库中,执行入库
$validSteps = ['', '结束', '内镜取出', '测漏正常', '测漏异常']; $validSteps = ['', '结束', '内镜取出', '测漏正常', '测漏异常'];
if (!in_array($context->getCurrentStep(), $validSteps)) { if (!in_array($context->getCurrentStep(), $validSteps)) {
Logger::debug('[StorageNode] 当前步骤 {} 不符合入库条件', [$context->getCurrentStep()]); Logger::debug('[StorageNode] 当前步骤 {} 不符合入库条件', [$context->getCurrentStep()]);
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
} }
return CanHandleResult::yes(); return CanHandleResult::canHandle();
} }
/** /**
+7 -7
View File
@@ -6,8 +6,8 @@ use app\config\Config;
use app\flow\enum\DbOperationType; use app\flow\enum\DbOperationType;
use app\flow\context\ProcessContext; use app\flow\context\ProcessContext;
use app\flow\enum\VoiceMessage; use app\flow\enum\VoiceMessage;
use app\flow\vo\CanHandleResult; use app\flow\context\bean\CanHandleResult;
use app\flow\vo\StorageStatus; use app\flow\context\bean\StorageStatus;
use app\utils\Logger; use app\utils\Logger;
/** /**
@@ -44,12 +44,12 @@ class StorageOutNode extends AbstractProcessNode
// 单读卡器模式不处理,由 StorageNode 统一处理 // 单读卡器模式不处理,由 StorageNode 统一处理
if ($singleReaderMode) { if ($singleReaderMode) {
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
// 读卡器不是内镜取出类型,不处理 // 读卡器不是内镜取出类型,不处理
if (!$this->isMatchReaderType($context)) { if (!$this->isMatchReaderType($context)) {
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
// 获取内镜当前存储状态 // 获取内镜当前存储状态
@@ -58,17 +58,17 @@ class StorageOutNode extends AbstractProcessNode
// 如果内镜不在库中,则当前应该是入库操作,不处理 // 如果内镜不在库中,则当前应该是入库操作,不处理
if (!$isInStorage) { if (!$isInStorage) {
Logger::debug('[StorageOutNode] 内镜不在库中,转由入库节点处理'); Logger::debug('[StorageOutNode] 内镜不在库中,转由入库节点处理');
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
// 检查前置步骤要求:必须在库中才能出库 // 检查前置步骤要求:必须在库中才能出库
$validSteps = ['内镜放入', '结束']; $validSteps = ['内镜放入', '结束'];
if (!in_array($context->getCurrentStep(), $validSteps)) { if (!in_array($context->getCurrentStep(), $validSteps)) {
Logger::debug('[StorageOutNode] 当前步骤 {} 不符合出库条件', [$context->getCurrentStep()]); Logger::debug('[StorageOutNode] 当前步骤 {} 不符合出库条件', [$context->getCurrentStep()]);
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
return CanHandleResult::yes(); return CanHandleResult::canHandle();
} }
/** /**
+5 -5
View File
@@ -6,7 +6,7 @@ use app\config\Config;
use app\flow\enum\DbOperationType; use app\flow\enum\DbOperationType;
use app\flow\context\ProcessContext; use app\flow\context\ProcessContext;
use app\flow\enum\VoiceMessage; use app\flow\enum\VoiceMessage;
use app\flow\vo\CanHandleResult; use app\flow\context\bean\CanHandleResult;
/** /**
* 虚拟清洗机节点 * 虚拟清洗机节点
@@ -37,18 +37,18 @@ class VirtualWashMachineNode extends AbstractProcessNode
{ {
// 如果内镜未取出 // 如果内镜未取出
if ($context->getStorage()->isInStorage) { if ($context->getStorage()->isInStorage) {
return CanHandleResult::no(VoiceMessage::PLEASE_SWIPE_STORAGE_OUT); return CanHandleResult::cannotHandle(VoiceMessage::PLEASE_SWIPE_STORAGE_OUT);
} }
// 如果不是机洗 // 如果不是机洗
if ($context->getReader()->type !== MachineWashNode::getName()) { if ($context->getReader()->type !== MachineWashNode::getName()) {
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
if (Config::getInstance()->enableVirtualCleanerParser) { if (Config::getInstance()->enableVirtualCleanerParser) {
return CanHandleResult::yes(); return CanHandleResult::canHandle();
} }
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
/** /**
+11 -9
View File
@@ -5,7 +5,7 @@ namespace app\flow\nodes;
use app\flow\enum\DbOperationType; use app\flow\enum\DbOperationType;
use app\flow\context\ProcessContext; use app\flow\context\ProcessContext;
use app\flow\enum\VoiceMessage; use app\flow\enum\VoiceMessage;
use app\flow\vo\CanHandleResult; use app\flow\context\bean\CanHandleResult;
use app\utils\Logger; use app\utils\Logger;
/** /**
@@ -39,26 +39,28 @@ class WashNode extends AbstractProcessNode
// 如果内镜未取出 // 如果内镜未取出
if ($context->getStorage()->isInStorage) { if ($context->getStorage()->isInStorage) {
return CanHandleResult::no(VoiceMessage::PLEASE_SWIPE_STORAGE_OUT); return CanHandleResult::cannotHandle(VoiceMessage::PLEASE_SWIPE_STORAGE_OUT);
} }
// 读卡器不是本节点,不处理
if (!$this->isMatchReaderType($context)) {
return CanHandleResult::no();
}
// 需要晨洗但未完成:提示先进行晨洗 // 需要晨洗但未完成:提示先进行晨洗
if ($context->getMorningWash()->needMorningWash && !$context->getMorningWash()->morningWashed) { if ($context->getMorningWash()->needMorningWash && !$context->getMorningWash()->morningWashed) {
return CanHandleResult::no(VoiceMessage::PLEASE_SWIPE_MORNING_WASH); return CanHandleResult::cannotHandle(VoiceMessage::PLEASE_SWIPE_MORNING_WASH);
} }
$validCurrentSteps = ['', '结束', '内镜取出', '内镜放入', '测漏正常', '晨洗']; $validCurrentSteps = ['', '结束', '内镜取出', '内镜放入', '测漏正常', '晨洗'];
if (!in_array($context->getCurrentStep(), $validCurrentSteps)) { if (!in_array($context->getCurrentStep(), $validCurrentSteps)) {
// 读卡器是清洗但步骤不对(如终末漂洗时刷清洗),提示应该先刷结束 // 读卡器是清洗但步骤不对(如终末漂洗时刷清洗),提示应该先刷结束
return CanHandleResult::no(); return CanHandleResult::cannotHandle();
} }
return CanHandleResult::yes(); // 读卡器不是本节点,不处理
if (!$this->isMatchReaderType($context)) {
return CanHandleResult::cannotHandle(VoiceMessage::PLEASE_SWIPE_WASH);
}
return CanHandleResult::canHandle();
} }
/** /**
+1 -1
View File
@@ -6,7 +6,7 @@ use app\flow\config\MorningMode;
use app\flow\config\MorningWashConfig; use app\flow\config\MorningWashConfig;
use app\flow\context\ProcessContext; use app\flow\context\ProcessContext;
use app\flow\nodes\ProcessNodeInterface; use app\flow\nodes\ProcessNodeInterface;
use app\flow\vo\MorningWashStatus; use app\flow\context\bean\MorningWashStatus;
use app\utils\Logger; use app\utils\Logger;
/** /**
@@ -59,15 +59,16 @@ class TimeValidationStrategy extends AbstractStrategy
/** /**
* 执行时间验证 * 执行时间验证
* 验证上一步骤(currentStep)的时长是否达标
*/ */
protected function doExecute(ProcessContext $context, ProcessNodeInterface $node): ProcessContext protected function doExecute(ProcessContext $context, ProcessNodeInterface $node): ProcessContext
{ {
$stepCode = $node->getCode(); // 验证的是上一步骤(currentStep)的时长,而不是当前节点
$currentStep = $context->getCurrentStep(); $stepCode = $context->getCurrentStep();
$processType = $context->getProcessType(); $processType = $context->getProcessType();
Logger::debug("开始执行时间验证策略,步骤:{$stepCode},流程类型:{$processType}"); Logger::debug("开始执行时间验证策略,步骤:{$stepCode},流程类型:{$processType}");
$configDuration = $this->timeValidationConfig->getDuration($stepCode,$processType); $configDuration = $this->timeValidationConfig->getDuration($stepCode, $processType);
Logger::debug("步骤:{$stepCode},流程类型:{$processType},配置时长:{$configDuration}s"); Logger::debug("步骤:{$stepCode},流程类型:{$processType},配置时长:{$configDuration}s");
if ($configDuration > 0) { if ($configDuration > 0) {
@@ -76,7 +77,7 @@ class TimeValidationStrategy extends AbstractStrategy
} else { } else {
Logger::debug("步骤:{$stepCode},流程类型:{$processType},无配置时长,从数据库查询"); Logger::debug("步骤:{$stepCode},流程类型:{$processType},无配置时长,从数据库查询");
// 从数据库按流程类型精确查询 // 从数据库按流程类型精确查询
$requiredDuration = $this->getDurationFromDb($stepCode, $context->getProcessType()); $requiredDuration = $this->getDurationFromDb($stepCode, $processType);
if ($requiredDuration > 0) { if ($requiredDuration > 0) {
$context = $context->builder()->withStepDuration($stepCode, $requiredDuration)->build(); $context = $context->builder()->withStepDuration($stepCode, $requiredDuration)->build();
} else { } else {
@@ -116,11 +117,13 @@ class TimeValidationStrategy extends AbstractStrategy
/** /**
* 判断策略是否适用 * 判断策略是否适用
* 只有在 timeValidationConfig 中登记的步骤才参与时间验证 * 只有在 timeValidationConfig 中登记的步骤才参与时间验证
* 验证的是上一步骤(currentStep)的时长
*/ */
public function isApplicable(ProcessContext $context, ProcessNodeInterface $node): bool public function isApplicable(ProcessContext $context, ProcessNodeInterface $node): bool
{ {
if ($context->getCurrentStep() != $context->getPreviousAction()?->process_name) return false; if ($context->getCurrentStep() != $context->getPreviousAction()?->process_name) return false;
if (!$this->timeValidationConfig->hasStep($node->getCode(), $context->getProcessType())) return false; // 检查的是 currentStep(上一步骤)是否有时间配置
if (!$this->timeValidationConfig->hasStep($context->getCurrentStep(), $context->getProcessType())) return false;
return true; return true;
} }
+4 -3
View File
@@ -2,6 +2,7 @@
namespace app\repository; namespace app\repository;
use app\flow\context\bean\BatchNo;
use app\flow\context\ProcessContext; use app\flow\context\ProcessContext;
use app\flow\enum\DbOperationType; use app\flow\enum\DbOperationType;
use app\model\EctActions; use app\model\EctActions;
@@ -99,9 +100,9 @@ class EctActionsRepository extends BaseRepository
$count = 0; $count = 0;
$today = date('Ymd'); $today = date('Ymd');
$query->lazy()->each(function (EctActions $record) use (&$count, $today) { $query->lazy()->each(function (EctActions $record) use (&$count, $today) {
$batchInfo = ProcessContext::parseBatchNo($record->op_batchno); $batchInfo = BatchNo::fromString($record->op_batchno);
$dateTime = strtotime($batchInfo['date']); $dateTime = $batchInfo->getTimestamp();
if (empty($batchInfo['date']) || $dateTime === false) return; if (empty($batchInfo->getDateStr()) || $dateTime === false) return;
$recordDate = date('Ymd', $dateTime); $recordDate = date('Ymd', $dateTime);
if ($recordDate >= $today) { if ($recordDate >= $today) {
$count += 1; $count += 1;
+27 -9
View File
@@ -3,16 +3,16 @@
namespace tests\flow; namespace tests\flow;
use app\flow\config\ProcessConfig; use app\flow\config\ProcessConfig;
use app\flow\context\bean\EndoscopeInfo;
use app\flow\context\bean\ExecutionResult;
use app\flow\context\bean\MorningWashStatus;
use app\flow\context\bean\OperatorInfo;
use app\flow\context\bean\ProcessStatus;
use app\flow\context\bean\ReaderInfo;
use app\flow\context\bean\ReminderStatus;
use app\flow\context\bean\StorageStatus;
use app\flow\context\bean\VoiceState;
use app\flow\context\ProcessContext; use app\flow\context\ProcessContext;
use app\flow\vo\EndoscopeInfo;
use app\flow\vo\ExecutionResult;
use app\flow\vo\MorningWashStatus;
use app\flow\vo\OperatorInfo;
use app\flow\vo\ProcessStatus;
use app\flow\vo\ReaderInfo;
use app\flow\vo\ReminderStatus;
use app\flow\vo\StorageStatus;
use app\flow\vo\VoiceState;
use app\model\EctActions; use app\model\EctActions;
/** /**
@@ -284,6 +284,7 @@ class VirtualContextBuilder
$action->op_batchno = $batchNo ?: $this->processStatus->batchNo; $action->op_batchno = $batchNo ?: $this->processStatus->batchNo;
$action->op_starttime = date('Y-m-d H:i:s', time() - 60); $action->op_starttime = date('Y-m-d H:i:s', time() - 60);
$action->op_endtime = $opEndtime; $action->op_endtime = $opEndtime;
$action->action_type = $this->mapActionType($this->processStatus->processType);
$action->action_type_name = $this->processStatus->processType; $action->action_type_name = $this->processStatus->processType;
$this->processStatus = new ProcessStatus( $this->processStatus = new ProcessStatus(
@@ -297,6 +298,23 @@ class VirtualContextBuilder
return $this; return $this;
} }
/**
* 映射流程类型到 action_type 数字
*/
private function mapActionType(string $processType): int
{
return match ($processType) {
'手工洗' => 1,
'机洗' => 2,
'手工洗(加强)' => 3,
'机洗(加强)' => 4,
'手工洗(晨洗)' => 5,
'机洗(晨洗)' => 6,
'晨洗' => 7,
default => 0,
};
}
/** /**
* 设置晨洗状态 - 需要晨洗 * 设置晨洗状态 - 需要晨洗
*/ */
+18 -4
View File
@@ -5,9 +5,9 @@ namespace tests\flow;
use app\flow\config\ProcessConfig; use app\flow\config\ProcessConfig;
use app\flow\context\ProcessContext; use app\flow\context\ProcessContext;
use app\flow\ProcessEngine; use app\flow\ProcessEngine;
use app\flow\vo\EndoscopeInfo; use app\flow\context\bean\EndoscopeInfo;
use app\flow\vo\OperatorInfo; use app\flow\context\bean\OperatorInfo;
use app\flow\vo\ReaderInfo; use app\flow\context\bean\ReaderInfo;
use app\utils\Logger; use app\utils\Logger;
/** /**
@@ -166,6 +166,11 @@ class VirtualityFlowProcessor
$builder->currentStep($currentState->getCurrentStep()) $builder->currentStep($currentState->getCurrentStep())
->batchNo($currentState->getBatchNo()) ->batchNo($currentState->getBatchNo())
->processType($currentState->getProcessType()); ->processType($currentState->getProcessType());
// 设置 previousAction:上一步骤名称就是当前状态的 currentStep
if (!empty($currentState->getCurrentStep())) {
$builder->previousAction($currentState->getCurrentStep(), $currentState->getBatchNo());
}
} else { } else {
// 新流程 // 新流程
$builder->newProcess(); $builder->newProcess();
@@ -185,6 +190,14 @@ class VirtualityFlowProcessor
// 执行流程 // 执行流程
$result = $this->engine->execute($context); $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->endoscopeStates[$endoscopeData['id']] = $result;
$this->history[] = $result; $this->history[] = $result;
@@ -214,8 +227,9 @@ class VirtualityFlowProcessor
Logger::info("当前流程:{}", [$result->getProcessType()]); Logger::info("当前流程:{}", [$result->getProcessType()]);
Logger::info("当前批次号:{}", [$result->getBatchNo()]); Logger::info("当前批次号:{}", [$result->getBatchNo()]);
Logger::info("当前步骤:{}", [$result->getCurrentStep()]); Logger::info("当前步骤:{}", [$result->getCurrentStep()]);
Logger::info("上一个步骤类型:{}", [$result->getPreviousAction()->action_type??"null"]); Logger::info("上一个步骤类型:{}", [$result->getPreviousAction()->action_type_name?? "null"]);
Logger::info("上一个步骤:{}", [$result->getPreviousAction()->process_name??"null"]); Logger::info("上一个步骤:{}", [$result->getPreviousAction()->process_name??"null"]);
Logger::info("时长:{}", [$result->getDuration()?? "null"]);
Logger::info("当前语音:{$result->getFullVoice()}\n"); Logger::info("当前语音:{$result->getFullVoice()}\n");
return $result; return $result;
} }
+7
View File
@@ -80,11 +80,14 @@ class BlockTest extends TestCase
Config::getInstance()->setBlockMode(true); Config::getInstance()->setBlockMode(true);
// 创建一个时间不足的场景(只有5秒) // 创建一个时间不足的场景(只有5秒)
// 关键:设置 previousAction 和 processType 使得时间验证策略生效
$context = $this->processor->createContextBuilder() $context = $this->processor->createContextBuilder()
->endoscope('胃镜1') ->endoscope('胃镜1')
->reader('漂洗') ->reader('漂洗')
->operator('操作员1') ->operator('操作员1')
->currentStep('清洗') ->currentStep('清洗')
->previousAction('清洗') // 上一步也是清洗,表示重复刷同一步骤
->processType('手工洗') // 必须设置流程类型,否则 hasStep 返回 false
->duration(5) // 只有5秒,时间不足 ->duration(5) // 只有5秒,时间不足
->batchNo(date('Ymd') . '010001') ->batchNo(date('Ymd') . '010001')
->build(); ->build();
@@ -112,6 +115,8 @@ class BlockTest extends TestCase
->reader('漂洗') ->reader('漂洗')
->operator('操作员1') ->operator('操作员1')
->currentStep('清洗') ->currentStep('清洗')
->previousAction('清洗') // 设置 previousAction 使时间验证生效
->processType('手工洗') // 必须设置流程类型
->duration(5) // 只有5秒,时间不足 ->duration(5) // 只有5秒,时间不足
->batchNo(date('Ymd') . '010001') ->batchNo(date('Ymd') . '010001')
->build(); ->build();
@@ -161,6 +166,8 @@ class BlockTest extends TestCase
->reader('漂洗') ->reader('漂洗')
->operator('操作员1') ->operator('操作员1')
->currentStep('清洗') ->currentStep('清洗')
->previousAction('清洗') // 设置 previousAction 使时间验证生效
->processType('手工洗') // 必须设置流程类型
->duration(120) // 120秒,时间充足 ->duration(120) // 120秒,时间充足
->batchNo(date('Ymd') . '010001') ->batchNo(date('Ymd') . '010001')
->build(); ->build();