Files
tcpserver-flow/tests/flow/VirtualContextBuilder.php
zimoyin 18254d82f5 test
2026-03-13 20:27:18 +08:00

483 lines
14 KiB
PHP

<?php
namespace tests\flow;
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\model\EctActions;
/**
* 虚拟上下文构建器
*
* 用于在测试中创建 ProcessContext,无需数据库依赖。
* 支持从 JSON 环境配置文件加载测试数据。
*/
class VirtualContextBuilder
{
private array $environment;
private ?ProcessConfig $engineConfig = null;
// 值对象
private EndoscopeInfo $endoscope;
private ReaderInfo $reader;
private OperatorInfo $operator;
private StorageStatus $storage;
private MorningWashStatus $morningWash;
private VoiceState $voice;
private ExecutionResult $result;
private ProcessStatus $processStatus;
private ReminderStatus $reminder;
// 标记
private bool $isOperatorCard = false;
private array $stepDurations = [];
private array $rawData = [];
/**
* 构造函数
*
* @param string|null $envPath 环境配置文件路径,null 时使用默认配置
*/
public function __construct(?string $envPath = null)
{
$this->loadEnvironment($envPath);
$this->initDefaults();
}
/**
* 加载环境配置
*/
private function loadEnvironment(?string $envPath): void
{
$defaultPath = __DIR__ . '/../resources/default_environment.json';
$path = $envPath ?? $defaultPath;
if (!file_exists($path)) {
throw new \RuntimeException("环境配置文件不存在: {$path}");
}
$content = file_get_contents($path);
$this->environment = json_decode($content, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new \RuntimeException("环境配置文件解析失败: " . json_last_error_msg());
}
}
/**
* 初始化默认值
*/
private function initDefaults(): void
{
$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();
// 从环境配置加载步骤时长
if (isset($this->environment['stepDurations'])) {
$this->stepDurations = $this->environment['stepDurations'];
}
}
/**
* 创建构建器实例(静态工厂)
*/
public static function create(?string $envPath = null): self
{
return new self($envPath);
}
// ==================== 便捷设置方法 ====================
/**
* 设置内镜(从环境配置名称)
*/
public function endoscope(string $name): self
{
$data = $this->environment['endoscopes'][$name] ?? null;
if ($data === null) {
throw new \InvalidArgumentException("未找到内镜配置: {$name}");
}
$this->endoscope = new EndoscopeInfo(
id: $data['id'],
name: $data['name'],
cardNo: $data['cardNo'],
type: $data['type']
);
return $this;
}
/**
* 设置自定义内镜
*/
public function customEndoscope(string $id, string $name, string $cardNo, string $type = ''): self
{
$this->endoscope = new EndoscopeInfo(
id: $id,
name: $name,
cardNo: $cardNo,
type: $type
);
return $this;
}
/**
* 设置读卡器(从环境配置名称/类型)
*/
public function reader(string $typeOrName): self
{
$data = $this->environment['readers'][$typeOrName] ?? null;
if ($data === null) {
throw new \InvalidArgumentException("未找到读卡器配置: {$typeOrName}");
}
$this->reader = new ReaderInfo(
no: $data['no'],
type: $data['type'],
id: $data['id']
);
return $this;
}
/**
* 设置自定义读卡器
*/
public function customReader(string $no, string $type, string $id = ''): self
{
$this->reader = new ReaderInfo(no: $no, type: $type, id: $id);
return $this;
}
/**
* 设置操作员(从环境配置名称)
*/
public function operator(string $name): self
{
$data = $this->environment['operators'][$name] ?? null;
if ($data === null) {
throw new \InvalidArgumentException("未找到操作员配置: {$name}");
}
$this->operator = new OperatorInfo(
id: $data['id'],
name: $data['name'],
rfid: $data['rfid']
);
return $this;
}
/**
* 设置自定义操作员
*/
public function customOperator(string $id, string $name, string $rfid = ''): self
{
$this->operator = new OperatorInfo(id: $id, name: $name, rfid: $rfid);
return $this;
}
/**
* 设置当前步骤
*/
public function currentStep(string $step): self
{
// 自动从环境配置加载该步骤的时长(如果未手动设置)
$duration = $this->processStatus->duration;
if ($duration === null && isset($this->stepDurations[$step])) {
$duration = $this->stepDurations[$step];
}
$this->processStatus = new ProcessStatus(
currentStep: $step,
processType: $this->processStatus->processType,
batchNo: $this->processStatus->batchNo,
actionStartTime: $this->processStatus->actionStartTime,
duration: $duration,
previousAction: $this->processStatus->previousAction
);
return $this;
}
/**
* 设置批次号
*/
public function batchNo(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 processType(string $type): self
{
$this->processStatus = new ProcessStatus(
currentStep: $this->processStatus->currentStep,
processType: $type,
batchNo: $this->processStatus->batchNo,
actionStartTime: $this->processStatus->actionStartTime,
duration: $this->processStatus->duration,
previousAction: $this->processStatus->previousAction
);
return $this;
}
/**
* 设置操作时长(秒)
*/
public function setDuration(?int $seconds): self
{
$this->processStatus = new ProcessStatus(
currentStep: $this->processStatus->currentStep,
processType: $this->processStatus->processType,
batchNo: $this->processStatus->batchNo,
actionStartTime: $this->processStatus->actionStartTime,
duration: $seconds,
previousAction: $this->processStatus->previousAction
);
return $this;
}
/**
* 设置操作开始时间
*/
public function actionStartTime(string $time): self
{
$this->processStatus = new ProcessStatus(
currentStep: $this->processStatus->currentStep,
processType: $this->processStatus->processType,
batchNo: $this->processStatus->batchNo,
actionStartTime: $time,
duration: $this->processStatus->duration,
previousAction: $this->processStatus->previousAction
);
return $this;
}
/**
* 设置上一条操作记录(虚拟)
*/
public function setPreviousAction(string $processName, string $batchNo = '', ?string $opEndtime = null): self
{
$action = new EctActions();
$action->process_name = $processName;
$action->op_batchno = $batchNo ?: $this->processStatus->batchNo;
$action->op_starttime = date('Y-m-d H:i:s', time() - 60);
$action->op_endtime = $opEndtime;
$action->action_type = $this->mapActionType($this->processStatus->processType);
$action->action_type_name = $this->processStatus->processType;
$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;
}
/**
* 映射流程类型到 action_type 数字
*/
private function mapActionType(string $processType): int
{
return match ($processType) {
'手工洗' => 1,
'机洗' => 2,
'手工洗(加强)' => 3,
'机洗(加强)' => 4,
'手工洗(晨洗)' => 5,
'机洗(晨洗)' => 6,
'晨洗' => 7,
default => 0,
};
}
/**
* 设置晨洗状态 - 需要晨洗
*/
public function needMorningWash(int $todayRecords = 0): self
{
$startTime = $this->environment['config']['morningWashStartTime'] ?? '06:00:00';
$this->morningWash = MorningWashStatus::required($startTime, $todayRecords);
return $this;
}
/**
* 设置晨洗状态 - 已完成晨洗
*/
public function morningWashCompleted(): self
{
$startTime = $this->environment['config']['morningWashStartTime'] ?? '06:00:00';
$this->morningWash = MorningWashStatus::completed($startTime);
return $this;
}
/**
* 设置晨洗状态 - 不需要晨洗
*/
public function noMorningWash(): self
{
$this->morningWash = MorningWashStatus::notRequired();
return $this;
}
/**
* 设置存储状态 - 在库中
*/
public function inStorage(?string $inTime = null): self
{
$this->storage = StorageStatus::inStorage($inTime ?? date('Y-m-d H:i:s', time() - 3600));
return $this;
}
/**
* 设置存储状态 - 已出库
*/
public function outOfStorage(): self
{
$this->storage = StorageStatus::outOfStorage();
return $this;
}
/**
* 设置为人员卡
*/
public function asOperatorCard(): self
{
$this->isOperatorCard = true;
return $this;
}
/**
* 设置流程引擎配置
*/
public function withEngineConfig(ProcessConfig $config): self
{
$this->engineConfig = $config;
return $this;
}
/**
* 设置步骤时长
*/
public function setStepDuration(string $stepCode, int $duration): self
{
$this->stepDurations[$stepCode] = $duration;
return $this;
}
/**
* 新流程开始(清空当前步骤,生成新批次号)
*/
public function newProcess(): self
{
$machineId = $this->environment['config']['machineId'] ?? '01';
$batchNo = date('Ymd') . $machineId . str_pad(rand(1, 9999), 4, '0', STR_PAD_LEFT);
$this->processStatus = new ProcessStatus(
currentStep: '',
processType: '',
batchNo: $batchNo,
actionStartTime: date('Y-m-d H:i:s'),
duration: 0,
previousAction: null
);
return $this;
}
/**
* 模拟结束状态
*/
public function finished(): self
{
return $this->currentStep('结束');
}
// ==================== 构建方法 ====================
/**
* 构建 ProcessContext
*/
public function build(): 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: null,
engineConfig: $this->engineConfig,
rawData: $this->rawData,
isOperatorCard: $this->isOperatorCard,
stepDurations: $this->stepDurations,
);
}
/**
* 获取当前环境配置
*/
public function getEnvironment(): array
{
return $this->environment;
}
/**
* 获取读卡器配置列表
*/
public function getAvailableReaders(): array
{
return array_keys($this->environment['readers'] ?? []);
}
/**
* 获取内镜配置列表
*/
public function getAvailableEndoscopes(): array
{
return array_keys($this->environment['endoscopes'] ?? []);
}
/**
* 获取操作员配置列表
*/
public function getAvailableOperators(): array
{
return array_keys($this->environment['operators'] ?? []);
}
}