feat: 实现TCP Server
This commit is contained in:
@@ -0,0 +1,232 @@
|
||||
<?php
|
||||
|
||||
namespace app\config;
|
||||
|
||||
use app\config\DatabaseConfig;
|
||||
use app\utils\Logger;
|
||||
|
||||
class Config
|
||||
{
|
||||
/**
|
||||
* 是否使用自定义流程配置(从Config加载)
|
||||
*/
|
||||
public bool $flowUseCustomProcess {
|
||||
get => $this->flowUseCustomProcess;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义流程配置键名(默认使用 'standard' 注意:此次为空,并非使用自定义配置文件里面的 'standard')
|
||||
*/
|
||||
public string $flowProcessConfigKey {
|
||||
get => $this->flowProcessConfigKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var int 普通日志轮转时间默认 14 天
|
||||
*/
|
||||
public int $logRotationTimeByDay {
|
||||
get => $this->logRotationTimeByDay;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var int 错误日志轮转时间默认 30 天
|
||||
*/
|
||||
public int $errorLogRotationTimeByDay {
|
||||
get => $this->errorLogRotationTimeByDay;
|
||||
}
|
||||
|
||||
public DatabaseConfig $database {
|
||||
get => $this->database;
|
||||
}
|
||||
|
||||
public array $customProcess {
|
||||
get => $this->customProcess;
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储单读卡器模式
|
||||
* true=单读卡器模式(一个读卡器交替入库/出库)
|
||||
* false=双读卡器模式(分别使用"内镜放入"和"内镜取出"读卡器)
|
||||
*/
|
||||
public bool $storageSingleReader {
|
||||
get => $this->storageSingleReader;
|
||||
}
|
||||
|
||||
/**
|
||||
* 机器ID,用于分布式环境,确保唯一
|
||||
*/
|
||||
public string $machineId {
|
||||
get => $this->machineId;
|
||||
}
|
||||
|
||||
public bool $dbDebug {
|
||||
get => $this->dbDebug;
|
||||
}
|
||||
|
||||
/**
|
||||
* 方式 类:方法
|
||||
* 方式 类
|
||||
* 方式 :方法
|
||||
* 允许使用正则 * 作为通配符
|
||||
* @var array 日志过滤器
|
||||
*/
|
||||
public array $logFilter {
|
||||
get => $this->logFilter;
|
||||
}
|
||||
|
||||
public int $logLevel {
|
||||
get => $this->logLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* 阻断模式
|
||||
*/
|
||||
public bool $blockMode {
|
||||
get => $this->blockMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 人员刷卡记录缓存记录多久。然后是 0 表示不计算缓存时间,只要被使用了就删除
|
||||
*/
|
||||
public int $openCardRecordCacheTime = 0 {
|
||||
get => $this->openCardRecordCacheTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 人员刷卡记录记录哪些读卡器的
|
||||
* 设置为空则表示所有读卡器
|
||||
*/
|
||||
public array $openCardRecordReaders = [] {
|
||||
get => $this->openCardRecordReaders;
|
||||
}
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
$this->database = new DatabaseConfig();
|
||||
$this->customProcess = require __DIR__ . '/custom_process_config.php';
|
||||
$this->machineId = self::getStringEnv("MACHINE_ID", "0");
|
||||
if (empty($this->machineId) || $this->machineId == '0') {
|
||||
$this->machineId = $this->getMachineIdByMac();
|
||||
}
|
||||
$this->dbDebug = self::getBoolEnv('DB_DEBUG');
|
||||
$this->flowUseCustomProcess = self::getBoolEnv('FLOW_USE_CUSTOM_PROCESS', true);
|
||||
$this->flowProcessConfigKey = self::getStringEnv('FLOW_PROCESS_CONFIG_KEY', '');
|
||||
$this->logRotationTimeByDay = self::getIntEnv('LOG_ROTATION_TIME_BY_DAY', 14);
|
||||
$this->errorLogRotationTimeByDay = self::getIntEnv('ERROR_LOG_ROTATION_TIME_BY_DAY', 30);
|
||||
$this->logFilter = self::getStringArrayEnv('LOG_FILTER', []);
|
||||
$this->logLevel = match (strtoupper(self::getStringEnv('LOG_LEVEL', 'DEBUG'))) {
|
||||
'INFO' => \Monolog\Logger::INFO,
|
||||
'WARNING' => \Monolog\Logger::WARNING,
|
||||
'ERROR' => \Monolog\Logger::ERROR,
|
||||
'ALERT' => \Monolog\Logger::ALERT,
|
||||
'EMERGENCY' => \Monolog\Logger::EMERGENCY,
|
||||
'CRITICAL' => \Monolog\Logger::CRITICAL,
|
||||
'NOTICE' => \Monolog\Logger::NOTICE,
|
||||
default => \Monolog\Logger::DEBUG
|
||||
};
|
||||
$this->blockMode = self::getBoolEnv('BLOCK_MODE', true);
|
||||
$this->openCardRecordCacheTime = self::getIntEnv('OPEN_CARD_RECORD_CACHE_TIME', 60);
|
||||
$this->openCardRecordReaders = self::getStringArrayEnv('OPEN_CARD_RECORD_READERS', []);
|
||||
$this->storageSingleReader = self::getBoolEnv('STORAGE_SINGLE_READER', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取服务器MAC地址并散列成2位数字(00-99)作为机器ID
|
||||
* 兼容Linux/Windows系统,失败时降级使用IP散列
|
||||
*
|
||||
* @return string 2位机器ID(00-99)
|
||||
*/
|
||||
public function getMachineIdByMac(): string
|
||||
{
|
||||
try {
|
||||
// 步骤1:根据系统类型执行命令获取MAC地址
|
||||
$mac = '';
|
||||
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
|
||||
// Windows系统
|
||||
$output = shell_exec('ipconfig /all');
|
||||
if (preg_match('/物理地址[.:\s]+([0-9A-F]{2}[-:][0-9A-F]{2}[-:][0-9A-F]{2}[-:][0-9A-F]{2}[-:][0-9A-F]{2}[-:][0-9A-F]{2})/i', $output, $matches)) {
|
||||
$mac = str_replace(['-', ':'], '', strtolower($matches[1]));
|
||||
}
|
||||
} else {
|
||||
// Linux/Mac系统
|
||||
$output = shell_exec('cat /sys/class/net/*/address 2>/dev/null || ifconfig');
|
||||
if (preg_match('/([0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2})/i', $output, $matches)) {
|
||||
// 过滤虚拟网卡(docker/lo等),取第一个有效物理网卡MAC
|
||||
$mac = str_replace(':', '', strtolower($matches[1]));
|
||||
// 排除回环地址、docker虚拟网卡等无效MAC
|
||||
$invalidPrefixes = ['00:00:00', '02:42:ac', '12:34:56'];
|
||||
$isInvalid = false;
|
||||
foreach ($invalidPrefixes as $prefix) {
|
||||
if (str_starts_with($matches[1], $prefix)) {
|
||||
$isInvalid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($isInvalid) {
|
||||
$mac = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 步骤2:若MAC获取失败,降级使用服务器IP
|
||||
if (empty($mac)) {
|
||||
// 获取外网/内网IP(优先内网)
|
||||
$ip = $_SERVER['SERVER_ADDR'] ?? gethostbyname(gethostname());
|
||||
if (empty($ip) || $ip === '127.0.0.1') {
|
||||
$ip = '0.0.0.0'; // 兜底
|
||||
}
|
||||
$mac = $ip; // 用IP替代MAC做散列
|
||||
}
|
||||
|
||||
$hash = md5($mac); // 生成32位哈希值
|
||||
$hashInt = hexdec(substr($hash, 0, 4));
|
||||
$chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
$base = 62; // 62进制基数
|
||||
$char1 = $chars[$hashInt % $base];
|
||||
$char2 = $chars[(int)($hashInt / $base) % $base];
|
||||
$machineId = $char2 . $char1;
|
||||
|
||||
// 步骤4:补零为2位(如5→05,99→99)
|
||||
return str_pad($machineId, 2, '0', STR_PAD_LEFT);
|
||||
} catch (\Exception $e) {
|
||||
// 极端异常时返回默认值(建议日志记录)
|
||||
Logger::error('获取机器ID失败:', ['error' => $e->getMessage()]);
|
||||
return '01'; // 默认机器ID
|
||||
}
|
||||
}
|
||||
|
||||
public static function getBoolEnv($name, $default = false)
|
||||
{
|
||||
$value = getenv($name);
|
||||
return empty($value) ? $default : filter_var($value, FILTER_VALIDATE_BOOLEAN);
|
||||
}
|
||||
|
||||
public static function getIntEnv($name, $default = 0)
|
||||
{
|
||||
$value = getenv($name);
|
||||
return empty($value) ? $default : (int)$value;
|
||||
}
|
||||
|
||||
public static function getStringEnv($name, $default = null)
|
||||
{
|
||||
$value = getenv($name);
|
||||
return empty($value) ? $default : $value;
|
||||
}
|
||||
|
||||
private static ?Config $instance = null;
|
||||
|
||||
public static function getInstance(): Config
|
||||
{
|
||||
if (self::$instance === null) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
private static function getStringArrayEnv(string $string, array $array): array
|
||||
{
|
||||
$value = getenv($string);
|
||||
return empty($value) ? $array : array_map('trim', explode(';', $value));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace app\config;
|
||||
|
||||
|
||||
use Illuminate\Database\Connection;
|
||||
use support\Db;
|
||||
|
||||
class DatabaseConfig
|
||||
{
|
||||
public string $host = 'localhost' {
|
||||
get {
|
||||
return $this->host;
|
||||
}
|
||||
}
|
||||
public string $username = 'root' {
|
||||
get {
|
||||
return $this->username;
|
||||
}
|
||||
}
|
||||
public string $password = '' {
|
||||
get {
|
||||
return $this->password;
|
||||
}
|
||||
}
|
||||
public string $database = 'opm_ectms' {
|
||||
get {
|
||||
return $this->database;
|
||||
}
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->host = getenv('DB_HOST');
|
||||
$this->username = getenv('DB_USER');
|
||||
$this->password = getenv('DB_PASSWORD');
|
||||
$this->database = getenv('DB_NAME');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $connection string|null
|
||||
* @return Connection
|
||||
*/
|
||||
public function getConnection(?string $connection = null): Connection
|
||||
{
|
||||
return Db::connection($connection);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 流程配置示例文件
|
||||
* 演示如何灵活配置不同医院的业务流程
|
||||
*/
|
||||
|
||||
return [
|
||||
// ============================================
|
||||
// 示例1: 标准完整流程(默认配置)
|
||||
// 晨洗→清洗→漂洗→消毒→终末漂洗→干燥→结束
|
||||
// ============================================
|
||||
'standard' => [
|
||||
'name' => '标准完整流程',
|
||||
'description' => '包含所有步骤的完整清洗流程',
|
||||
// 覆盖 steps
|
||||
'override_steps' => false,
|
||||
'morning_wash' => [
|
||||
'mode' => 'daily_first', // 每天第一次需要晨洗
|
||||
'storage_threshold' => 4,
|
||||
'morning_start_time' => '00:00:00',
|
||||
],
|
||||
'steps' => [
|
||||
['code' => '晨洗', 'class' => 'MorningWashNode', 'enabled' => true],
|
||||
['code' => '清洗', 'class' => 'WashNode', 'enabled' => true,'required' => ['结束','晨洗']],
|
||||
['code' => '漂洗', 'class' => 'RinseNode', 'enabled' => true],
|
||||
['code' => '消毒', 'class' => 'DisinfectNode', 'enabled' => true],
|
||||
['code' => '终末漂洗', 'class' => 'FinalRinseNode', 'enabled' => true],
|
||||
['code' => '干燥', 'class' => 'DryNode', 'enabled' => true],
|
||||
['code' => '结束', 'class' => 'EndNode', 'enabled' => true],
|
||||
['code' => '机洗', 'class' => 'MachineWashNode', 'enabled' => true],
|
||||
],
|
||||
'time_validation' => [
|
||||
'手工洗' => [
|
||||
'清洗' => 120,
|
||||
'漂洗' => 60,
|
||||
'消毒' => 300,
|
||||
'终末漂洗' => 120,
|
||||
'干燥' => 30,
|
||||
'机洗' => 360,
|
||||
]
|
||||
],
|
||||
],
|
||||
|
||||
// ============================================
|
||||
// 示例2: 无晨洗流程
|
||||
// 医院不需要晨洗功能
|
||||
// 清洗→漂洗→消毒→终末漂洗→干燥→结束
|
||||
// ============================================
|
||||
'no_morning_wash' => [
|
||||
'name' => '无晨洗流程',
|
||||
'description' => '医院不需要晨洗功能',
|
||||
'morning_wash' => [
|
||||
'mode' => 'none', // 完全禁用晨洗
|
||||
],
|
||||
'steps' => [
|
||||
['code' => '晨洗', 'class' => 'MorningWashNode', 'enabled' => false], // 禁用晨洗节点
|
||||
['code' => '清洗', 'class' => 'WashNode', 'enabled' => true],
|
||||
['code' => '漂洗', 'class' => 'RinseNode', 'enabled' => true],
|
||||
['code' => '消毒', 'class' => 'DisinfectNode', 'enabled' => true],
|
||||
['code' => '终末漂洗', 'class' => 'FinalRinseNode', 'enabled' => true],
|
||||
['code' => '干燥', 'class' => 'DryNode', 'enabled' => true],
|
||||
['code' => '结束', 'class' => 'EndNode', 'enabled' => true],
|
||||
['code' => '机洗', 'class' => 'MachineWashNode', 'enabled' => true],
|
||||
],
|
||||
],
|
||||
|
||||
// ============================================
|
||||
// 示例3: 部分镜子需要晨洗(义乌模式)
|
||||
// 根据存储时间判断:超过4小时需要晨洗
|
||||
// ============================================
|
||||
'partial_morning_wash' => [
|
||||
'name' => '部分镜子晨洗(义乌模式)',
|
||||
'description' => '普通镜柜超过4小时需要晨洗,无菌镜柜免晨消',
|
||||
'morning_wash' => [
|
||||
'mode' => 'storage_time', // 根据存储时间判断
|
||||
'storage_threshold' => 4, // 4小时阈值
|
||||
'morning_start_time' => '06:00:00',
|
||||
],
|
||||
'steps' => [
|
||||
['code' => '晨洗', 'class' => 'MorningWashNode', 'enabled' => true],
|
||||
['code' => '清洗', 'class' => 'WashNode', 'enabled' => true],
|
||||
['code' => '漂洗', 'class' => 'RinseNode', 'enabled' => true],
|
||||
['code' => '消毒', 'class' => 'DisinfectNode', 'enabled' => true],
|
||||
['code' => '终末漂洗', 'class' => 'FinalRinseNode', 'enabled' => true],
|
||||
['code' => '干燥', 'class' => 'DryNode', 'enabled' => true],
|
||||
['code' => '结束', 'class' => 'EndNode', 'enabled' => true],
|
||||
['code' => '机洗', 'class' => 'MachineWashNode', 'enabled' => true],
|
||||
],
|
||||
],
|
||||
|
||||
// ============================================
|
||||
// 示例4: 无干燥流程
|
||||
// 医院不需要干燥步骤,消毒后直接结束
|
||||
// 清洗→漂洗→消毒→结束
|
||||
// ============================================
|
||||
'no_dry' => [
|
||||
'name' => '无干燥流程',
|
||||
'description' => '医院不需要干燥步骤',
|
||||
'morning_wash' => [
|
||||
'mode' => 'none',
|
||||
],
|
||||
'steps' => [
|
||||
['code' => '晨洗', 'class' => 'MorningWashNode', 'enabled' => false],
|
||||
['code' => '清洗', 'class' => 'WashNode', 'enabled' => true],
|
||||
['code' => '漂洗', 'class' => 'RinseNode', 'enabled' => true],
|
||||
['code' => '消毒', 'class' => 'DisinfectNode', 'enabled' => true],
|
||||
['code' => '终末漂洗', 'class' => 'FinalRinseNode', 'enabled' => false], // 跳过终末漂洗
|
||||
['code' => '干燥', 'class' => 'DryNode', 'enabled' => false], // 禁用干燥
|
||||
['code' => '结束', 'class' => 'EndNode', 'enabled' => true],
|
||||
['code' => '机洗', 'class' => 'MachineWashNode', 'enabled' => true],
|
||||
],
|
||||
],
|
||||
|
||||
// ============================================
|
||||
// 示例5: 仅干燥流程
|
||||
// 医院只有干燥步骤,没有完整清洗流程
|
||||
// 干燥→结束
|
||||
// ============================================
|
||||
'dry_only' => [
|
||||
'name' => '仅干燥流程',
|
||||
'description' => '医院只有干燥步骤',
|
||||
'morning_wash' => [
|
||||
'mode' => 'none',
|
||||
],
|
||||
'steps' => [
|
||||
['code' => '晨洗', 'class' => 'MorningWashNode', 'enabled' => false],
|
||||
['code' => '清洗', 'class' => 'WashNode', 'enabled' => false],
|
||||
['code' => '漂洗', 'class' => 'RinseNode', 'enabled' => false],
|
||||
['code' => '消毒', 'class' => 'DisinfectNode', 'enabled' => false],
|
||||
['code' => '终末漂洗', 'class' => 'FinalRinseNode', 'enabled' => false],
|
||||
['code' => '干燥', 'class' => 'DryNode', 'enabled' => true],
|
||||
['code' => '结束', 'class' => 'EndNode', 'enabled' => true],
|
||||
['code' => '机洗', 'class' => 'MachineWashNode', 'enabled' => false],
|
||||
],
|
||||
],
|
||||
|
||||
// ============================================
|
||||
// 示例6: 机洗流程
|
||||
// 清洗→机洗→终末漂洗→干燥→结束
|
||||
// ============================================
|
||||
'machine_wash' => [
|
||||
'name' => '机洗流程',
|
||||
'description' => '刷完机洗后接终末漂洗再干燥结束',
|
||||
'morning_wash' => [
|
||||
'mode' => 'none',
|
||||
],
|
||||
'steps' => [
|
||||
['code' => '晨洗', 'class' => 'MorningWashNode', 'enabled' => false],
|
||||
['code' => '清洗', 'class' => 'WashNode', 'enabled' => true],
|
||||
['code' => '漂洗', 'class' => 'RinseNode', 'enabled' => false], // 跳过硬洗漂洗
|
||||
['code' => '消毒', 'class' => 'DisinfectNode', 'enabled' => false], // 跳过硬洗消毒
|
||||
['code' => '机洗', 'class' => 'MachineWashNode', 'enabled' => true],
|
||||
['code' => '终末漂洗', 'class' => 'FinalRinseNode', 'enabled' => true],
|
||||
['code' => '干燥', 'class' => 'DryNode', 'enabled' => true],
|
||||
['code' => '结束', 'class' => 'EndNode', 'enabled' => true],
|
||||
],
|
||||
],
|
||||
|
||||
// ============================================
|
||||
// 示例7: 简化流程
|
||||
// 只刷一个清洗就结束
|
||||
// 清洗→结束
|
||||
// ============================================
|
||||
'simple' => [
|
||||
'name' => '简化流程',
|
||||
'description' => '只刷一个清洗就结束',
|
||||
'morning_wash' => [
|
||||
'mode' => 'none',
|
||||
],
|
||||
'steps' => [
|
||||
['code' => '晨洗', 'class' => 'MorningWashNode', 'enabled' => false],
|
||||
['code' => '清洗', 'class' => 'WashNode', 'enabled' => true],
|
||||
['code' => '漂洗', 'class' => 'RinseNode', 'enabled' => false],
|
||||
['code' => '消毒', 'class' => 'DisinfectNode', 'enabled' => false],
|
||||
['code' => '终末漂洗', 'class' => 'FinalRinseNode', 'enabled' => false],
|
||||
['code' => '干燥', 'class' => 'DryNode', 'enabled' => false],
|
||||
['code' => '结束', 'class' => 'EndNode', 'enabled' => true],
|
||||
['code' => '机洗', 'class' => 'MachineWashNode', 'enabled' => false],
|
||||
],
|
||||
],
|
||||
|
||||
// ============================================
|
||||
// 示例8: 自定义语音流程
|
||||
// 针对某个流程特殊定制语音
|
||||
// ============================================
|
||||
'custom_voice' => [
|
||||
'name' => '自定义语音流程',
|
||||
'description' => '针对流程特殊定制语音',
|
||||
'morning_wash' => [
|
||||
'mode' => 'daily_first',
|
||||
],
|
||||
'steps' => [
|
||||
['code' => '晨洗', 'class' => 'MorningWashNode', 'enabled' => true],
|
||||
['code' => '清洗', 'class' => 'WashNode', 'enabled' => true],
|
||||
['code' => '漂洗', 'class' => 'RinseNode', 'enabled' => true],
|
||||
['code' => '消毒', 'class' => 'DisinfectNode', 'enabled' => true],
|
||||
['code' => '终末漂洗', 'class' => 'FinalRinseNode', 'enabled' => true],
|
||||
['code' => '干燥', 'class' => 'DryNode', 'enabled' => true],
|
||||
['code' => '结束', 'class' => 'EndNode', 'enabled' => true],
|
||||
['code' => '机洗', 'class' => 'MachineWashNode', 'enabled' => true],
|
||||
],
|
||||
'voice_templates' => [
|
||||
// 与 VoiceGenerationStrategy 中默认配置进行合并
|
||||
'normal_wash' => [
|
||||
'清洗' => '第一步清洗开始,请认真清洗',
|
||||
'漂洗' => '第二步漂洗开始',
|
||||
'消毒' => '第三步消毒开始,请确保消毒时间',
|
||||
'终末漂洗' => '第四步终末漂洗开始',
|
||||
'干燥' => '最后一步干燥开始',
|
||||
'结束' => '清洗流程全部完成,请妥善保管内镜',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
// ============================================
|
||||
// 示例9: 特定类型镜子晨洗
|
||||
// 只有特定类型的镜子需要晨洗
|
||||
// ============================================
|
||||
'specific_type_morning_wash' => [
|
||||
'name' => '特定类型镜子晨洗',
|
||||
'description' => '只有胃镜需要晨洗,肠镜不需要',
|
||||
'morning_wash' => [
|
||||
'mode' => 'specific_types',
|
||||
'specific_types' => ['胃镜', '十二指肠镜'], // 只有这些类型需要晨洗
|
||||
],
|
||||
'steps' => [
|
||||
['code' => '晨洗', 'class' => 'MorningWashNode', 'enabled' => true],
|
||||
['code' => '清洗', 'class' => 'WashNode', 'enabled' => true],
|
||||
['code' => '漂洗', 'class' => 'RinseNode', 'enabled' => true],
|
||||
['code' => '消毒', 'class' => 'DisinfectNode', 'enabled' => true],
|
||||
['code' => '终末漂洗', 'class' => 'FinalRinseNode', 'enabled' => true],
|
||||
['code' => '干燥', 'class' => 'DryNode', 'enabled' => true],
|
||||
['code' => '结束', 'class' => 'EndNode', 'enabled' => true],
|
||||
['code' => '机洗', 'class' => 'MachineWashNode', 'enabled' => true],
|
||||
],
|
||||
],
|
||||
|
||||
// ============================================
|
||||
// 示例10: 自定义时间要求
|
||||
// 不同医院对步骤时间有不同要求
|
||||
// ============================================
|
||||
'custom_duration' => [
|
||||
'name' => '自定义时间要求',
|
||||
'description' => '消毒时间要求10分钟',
|
||||
// 覆盖 steps
|
||||
'override_steps' => false,
|
||||
'morning_wash' => [
|
||||
'mode' => 'daily_first',
|
||||
],
|
||||
'steps' => [
|
||||
['code' => '晨洗', 'class' => 'MorningWashNode', 'enabled' => true],
|
||||
['code' => '清洗', 'class' => 'WashNode', 'enabled' => true],
|
||||
['code' => '漂洗', 'class' => 'RinseNode', 'enabled' => true],
|
||||
['code' => '消毒', 'class' => 'DisinfectNode', 'enabled' => true],
|
||||
['code' => '终末漂洗', 'class' => 'FinalRinseNode', 'enabled' => true],
|
||||
['code' => '干燥', 'class' => 'DryNode', 'enabled' => true],
|
||||
['code' => '结束', 'class' => 'EndNode', 'enabled' => true],
|
||||
['code' => '机洗', 'class' => 'MachineWashNode', 'enabled' => true],
|
||||
],
|
||||
'time_validation' => [
|
||||
'durations' => [
|
||||
'清洗' => 300, // 5分钟
|
||||
'漂洗' => 120, // 2分钟
|
||||
'消毒' => 600, // 10分钟(自定义)
|
||||
'终末漂洗' => 180, // 3分钟(自定义)
|
||||
'干燥' => 300, // 5分钟(自定义)
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
Reference in New Issue
Block a user