471 lines
12 KiB
Markdown
471 lines
12 KiB
Markdown
# 内镜清洗流程管理系统 - 使用与配置
|
||
|
||
## 一、快速开始
|
||
|
||
### 1.1 基础使用示例
|
||
|
||
```php
|
||
use app\flow\FlowProcessor;
|
||
use app\flow\config\ProcessConfig;
|
||
use app\net\PacketContext;
|
||
|
||
// 接收刷卡数据
|
||
public function onMessage(TcpConnection $connection, $data): void
|
||
{
|
||
// 1. 解析数据包
|
||
$packet = PacketParserFactory::parse($data);
|
||
$packetContext = new PacketContext($connection, $packet);
|
||
|
||
// 2. 创建流程处理器(使用标准配置)
|
||
$config = ProcessConfig::createStandard();
|
||
$processor = new FlowProcessor($config);
|
||
|
||
// 3. 处理流程
|
||
$result = $processor->process($packetContext);
|
||
|
||
// 4. 输出结果
|
||
if ($result->success) {
|
||
echo "语音播报: " . $result->getFullVoice();
|
||
echo "当前步骤: " . $result->currentStep;
|
||
echo "批次号: " . $result->batchNo;
|
||
} else {
|
||
echo "错误: " . $result->errorMessage;
|
||
}
|
||
}
|
||
```
|
||
|
||
## 二、配置方式
|
||
|
||
### 2.1 预置配置
|
||
|
||
```php
|
||
use app\flow\config\ProcessConfig;
|
||
|
||
// 标准完整流程
|
||
$config = ProcessConfig::createStandard();
|
||
|
||
// 无晨洗流程
|
||
$config = ProcessConfig::createNoMorningWash();
|
||
|
||
// 简化流程(只清洗)
|
||
$config = ProcessConfig::createSimple();
|
||
|
||
// 机洗流程
|
||
$config = ProcessConfig::createMachineWash();
|
||
|
||
// 无干燥流程
|
||
$config = ProcessConfig::createNoDry();
|
||
|
||
// 仅干燥流程
|
||
$config = ProcessConfig::createDryOnly();
|
||
```
|
||
|
||
### 2.2 自定义配置
|
||
|
||
```php
|
||
use app\flow\config\ProcessConfig;
|
||
|
||
$config = new ProcessConfig([
|
||
// 定义的 steps 是带有顺序的
|
||
// 流程步骤配置
|
||
'steps' => [
|
||
['code' => '清洗', 'class' => 'WashNode', 'enabled' => true],
|
||
['code' => '消毒', 'class' => 'DisinfectNode', 'enabled' => true],
|
||
['code' => '结束', 'class' => 'EndNode', 'enabled' => true],
|
||
],
|
||
|
||
// 晨洗配置
|
||
'morning_wash' => [
|
||
'mode' => 'storage_time', // 根据存储时间判断
|
||
'storage_threshold' => 4, // 4小时阈值
|
||
'morning_start_time' => '06:00:00',
|
||
],
|
||
|
||
// 时间验证配置
|
||
'time_validation' => [
|
||
'durations' => [
|
||
'清洗' => 300, // 5分钟
|
||
'消毒' => 600, // 10分钟(自定义)
|
||
],
|
||
],
|
||
|
||
// 语音模板配置
|
||
'voice_templates' => [
|
||
'custom' => [
|
||
'清洗' => '第一步清洗开始',
|
||
'消毒' => '第三步消毒开始,请确保消毒时间',
|
||
],
|
||
],
|
||
]);
|
||
```
|
||
|
||
### 2.3 动态调整配置
|
||
|
||
```php
|
||
use app\flow\ProcessEngine;
|
||
|
||
$engine = ProcessEngine::createStandard();
|
||
|
||
// 禁用某些步骤
|
||
$engine->disableNode('干燥');
|
||
$engine->disableNode('终末漂洗');
|
||
|
||
// 启用步骤
|
||
$engine->enableNode('干燥');
|
||
|
||
// 设置自定义语音
|
||
$engine->setStepVoice('清洗', '请开始清洗');
|
||
|
||
// 设置晨洗模式
|
||
$engine->setMorningWashMode('none');
|
||
```
|
||
|
||
## 三、晨洗模式配置
|
||
|
||
### 3.1 不需要晨洗
|
||
```php
|
||
$config = new ProcessConfig([
|
||
'morning_wash' => [
|
||
'mode' => 'none',
|
||
],
|
||
]);
|
||
```
|
||
|
||
### 3.2 所有镜子都需要晨洗
|
||
```php
|
||
$config = new ProcessConfig([
|
||
'morning_wash' => [
|
||
'mode' => 'all',
|
||
],
|
||
]);
|
||
```
|
||
|
||
### 3.3 根据存储时间判断(义乌模式)
|
||
```php
|
||
$config = new ProcessConfig([
|
||
'morning_wash' => [
|
||
'mode' => 'storage_time',
|
||
'storage_threshold' => 4, // 超过4小时需要晨洗
|
||
'morning_start_time' => '06:00:00',
|
||
],
|
||
]);
|
||
```
|
||
|
||
### 3.4 每天第一次需要晨洗(忠县模式)
|
||
```php
|
||
$config = new ProcessConfig([
|
||
'morning_wash' => [
|
||
'mode' => 'daily_first',
|
||
'morning_start_time' => '06:00:00',
|
||
],
|
||
]);
|
||
```
|
||
|
||
### 3.5 特定类型镜子需要晨洗
|
||
```php
|
||
$config = new ProcessConfig([
|
||
'morning_wash' => [
|
||
'mode' => 'specific_types',
|
||
'specific_types' => ['胃镜', '十二指肠镜'],
|
||
],
|
||
]);
|
||
```
|
||
|
||
## 四、医院特殊流程配置
|
||
|
||
### 4.1 机洗后不允许刷终末漂洗
|
||
|
||
```php
|
||
use app\flow\ProcessEngine;
|
||
|
||
$engine = ProcessEngine::createStandard();
|
||
|
||
// 获取终末漂洗节点并配置
|
||
$finalRinseNode = $engine->getNode('终末漂洗');
|
||
$finalRinseNode->setAllowAfterMachineWash(false);
|
||
```
|
||
|
||
**效果**:机洗完成后,刷卡到终末漂洗读卡器会提示错误,只能刷干燥或结束。
|
||
|
||
### 4.2 机洗后必须直接刷干燥
|
||
|
||
```php
|
||
$dryNode = $engine->getNode('干燥');
|
||
$dryNode->setRequireDirectAfterMachineWash(true);
|
||
```
|
||
|
||
**效果**:机洗完成后,必须刷干燥或结束,不能刷其他步骤。
|
||
|
||
### 4.3 自定义步骤时间
|
||
|
||
```php
|
||
use app\flow\strategies\TimeValidationStrategy;
|
||
|
||
$strategy = new TimeValidationStrategy([
|
||
'durations' => [
|
||
'清洗' => 600, // 10分钟
|
||
'消毒' => 900, // 15分钟
|
||
],
|
||
]);
|
||
|
||
$engine->addStrategy('time_validation', $strategy);
|
||
```
|
||
|
||
### 4.4 自定义语音模板
|
||
|
||
```php
|
||
$engine->setStepVoice('清洗', '第一步:请开始清洗内镜');
|
||
$engine->setStepVoice('消毒', '第三步:消毒时间必须达到5分钟');
|
||
$engine->setStepVoice('结束', '清洗流程完成,请妥善保管');
|
||
```
|
||
|
||
## 五、从配置文件加载
|
||
|
||
### 5.1 创建配置文件
|
||
|
||
```php
|
||
// config/flow/hospital_a.php
|
||
return [
|
||
'name' => '医院A-无晨洗流程',
|
||
'morning_wash' => [
|
||
'mode' => 'none',
|
||
],
|
||
'steps' => [
|
||
['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],
|
||
],
|
||
];
|
||
```
|
||
|
||
### 5.2 加载配置
|
||
|
||
```php
|
||
$config = ProcessConfig::fromFile(__DIR__ . '/config/flow/hospital_a.php');
|
||
$processor = new FlowProcessor($config);
|
||
```
|
||
|
||
## 六、全局配置类(Config.php)
|
||
|
||
### 6.1 配置类说明
|
||
|
||
系统提供全局配置单例类 `app\config\Config`,用于统一管理数据库配置和自定义流程配置:
|
||
|
||
```php
|
||
use app\config\Config;
|
||
|
||
// 获取配置实例
|
||
$config = Config::getInstance();
|
||
|
||
// 获取数据库配置
|
||
$databaseConfig = $config->database;
|
||
|
||
// 获取自定义流程配置(从 app/config/custom_process_config.php 加载)
|
||
$customProcess = $config->customProcess;
|
||
```
|
||
|
||
### 6.2 配置文件位置
|
||
|
||
自定义流程配置文件位于:`app/config/custom_process_config.php`
|
||
|
||
该文件返回一个数组,包含多种预设的医院流程配置:
|
||
|
||
```php
|
||
return [
|
||
'standard' => [...], // 标准完整流程
|
||
'no_morning_wash' => [...], // 无晨洗流程
|
||
'partial_morning_wash' => [...], // 部分镜子晨洗(义乌模式)
|
||
'no_dry' => [...], // 无干燥流程
|
||
'dry_only' => [...], // 仅干燥流程
|
||
'machine_wash' => [...], // 机洗流程
|
||
'simple' => [...], // 简化流程
|
||
'custom_voice' => [...], // 自定义语音流程
|
||
];
|
||
```
|
||
|
||
### 6.3 使用全局配置创建流程
|
||
|
||
```php
|
||
use app\config\Config;
|
||
use app\flow\ProcessConfig;
|
||
use app\flow\FlowProcessor;
|
||
|
||
// 获取全局配置
|
||
$globalConfig = Config::getInstance();
|
||
|
||
// 从全局配置中获取特定医院配置
|
||
$hospitalConfig = $globalConfig->customProcess['no_morning_wash'] ?? null;
|
||
|
||
if ($hospitalConfig) {
|
||
// 创建流程配置
|
||
$processConfig = ProcessConfig::fromArray($hospitalConfig);
|
||
|
||
// 创建流程处理器
|
||
$processor = new FlowProcessor($processConfig);
|
||
|
||
// 处理刷卡请求...
|
||
}
|
||
```
|
||
|
||
### 6.4 配置优先级
|
||
|
||
配置加载优先级(从高到低):
|
||
1. 代码中动态设置的配置(`$engine->setStepVoice()`)
|
||
2. 从配置文件加载的配置(`ProcessConfig::fromFile()`)
|
||
3. 全局配置类中的配置(`Config::getInstance()->customProcess`)
|
||
4. 默认配置(`ProcessConfig::createStandard()`)
|
||
|
||
## 七、多医院配置示例
|
||
|
||
```php
|
||
class HospitalFlowManager
|
||
{
|
||
protected array $processors = [];
|
||
|
||
public function __construct()
|
||
{
|
||
// 医院A:标准流程
|
||
$this->processors['hospital_a'] = new FlowProcessor(
|
||
ProcessConfig::createStandard()
|
||
);
|
||
|
||
// 医院B:无晨洗
|
||
$this->processors['hospital_b'] = new FlowProcessor(
|
||
ProcessConfig::createNoMorningWash()
|
||
);
|
||
|
||
// 医院C:义乌模式
|
||
$configC = new ProcessConfig([
|
||
'morning_wash' => [
|
||
'mode' => 'storage_time',
|
||
'storage_threshold' => 4,
|
||
],
|
||
]);
|
||
$this->processors['hospital_c'] = new FlowProcessor($configC);
|
||
|
||
// 医院D:机洗流程
|
||
$this->processors['hospital_d'] = new FlowProcessor(
|
||
ProcessConfig::createMachineWash()
|
||
);
|
||
}
|
||
|
||
public function process(string $hospitalId, PacketContext $packetContext): ProcessContext
|
||
{
|
||
$processor = $this->processors[$hospitalId] ?? $this->processors['hospital_a'];
|
||
return $processor->process($packetContext);
|
||
}
|
||
}
|
||
```
|
||
|
||
## 八、处理结果
|
||
|
||
### 8.1 成功结果
|
||
|
||
```php
|
||
$result = $processor->process($packetContext);
|
||
|
||
if ($result->isSuccess()) {
|
||
// 基础信息
|
||
$result->endoscopeId; // 内镜ID
|
||
$result->endoscopeName; // 内镜名称
|
||
$result->currentStep; // 当前步骤
|
||
$result->processType; // 流程类型
|
||
$result->batchNo; // 批次号
|
||
|
||
// 语音播报
|
||
$voice = $result->getFullVoice(); // 完整语音(含内镜名称)
|
||
$voice = $result->voiceMessage; // 仅流程语音
|
||
|
||
// 数据库标记
|
||
$result->needDbInsert; // 是否需要插入数据库
|
||
$result->dbOperation; // insert / update
|
||
|
||
// WebSocket标记
|
||
$result->needWebSocketNotify; // 是否需要发送通知
|
||
}
|
||
```
|
||
|
||
### 8.2 失败结果
|
||
|
||
```php
|
||
if (!$result->isSuccess()) {
|
||
$errorMessage = $result->errorMessage; // 错误信息
|
||
$voice = $result->voiceMessage; // 错误语音
|
||
|
||
// 常见错误:
|
||
// - "刷错,清洗剩余180秒"(时间未到)
|
||
// - "刷卡错误,请刷消毒"(步骤错误)
|
||
// - "内镜未绑定"(数据错误)
|
||
}
|
||
```
|
||
|
||
## 九、数据库表结构参考
|
||
|
||
### 9.1 流程配置表(ect_meta_process)
|
||
|
||
```sql
|
||
CREATE TABLE `ect_meta_process` (
|
||
`process_id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
`process_name` varchar(255) COMMENT '流程名称(清洗/消毒/干燥等)',
|
||
`process_duration` int COMMENT '流程时长(秒)',
|
||
`process_type` varchar(20) COMMENT '洗消类型(手工洗/机洗等)',
|
||
`optional` int COMMENT '0=选配 1=必配',
|
||
`process_order` int COMMENT '顺序',
|
||
`status` int COMMENT '1=启用 0=禁用',
|
||
PRIMARY KEY (`process_id`)
|
||
);
|
||
```
|
||
|
||
### 9.2 操作记录表(ect_actions)
|
||
|
||
```sql
|
||
CREATE TABLE `ect_actions` (
|
||
`action_id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
`batch_no` varchar(50) COMMENT '批次号(同一次清洗流程相同)',
|
||
`action_type` int COMMENT '操作类型',
|
||
`action_type_name` varchar(50) COMMENT '操作类型名称',
|
||
`process_name` varchar(50) COMMENT '流程名称(清洗/消毒等)',
|
||
`reader_id` bigint COMMENT '读卡器ID',
|
||
`reader_no` varchar(50) COMMENT '读卡器编号',
|
||
`endoscope_id` bigint COMMENT '内镜ID',
|
||
`endoscope_rfid` varchar(50) COMMENT '内镜RFID',
|
||
`endoscope_name` varchar(100) COMMENT '内镜名称',
|
||
`op_starttime` datetime COMMENT '操作开始时间',
|
||
`op_endtime` datetime COMMENT '操作结束时间',
|
||
`created_at` datetime,
|
||
PRIMARY KEY (`action_id`)
|
||
);
|
||
```
|
||
|
||
## 十、常见问题
|
||
|
||
### Q1: 如何跳过某个步骤?
|
||
```php
|
||
$engine->disableNode('干燥');
|
||
```
|
||
|
||
### Q2: 如何修改步骤时间?
|
||
```php
|
||
$config = new ProcessConfig([
|
||
'time_validation' => [
|
||
'durations' => ['消毒' => 600],
|
||
],
|
||
]);
|
||
```
|
||
|
||
### Q3: 批次号如何保证分布式一致?
|
||
系统会从数据库查询该内镜未完成的流程批次号,如果存在则使用已有批次号,不存在则生成新的。
|
||
|
||
### Q4: 如何添加自定义语音?
|
||
```php
|
||
$engine->setStepVoice('清洗', '自定义语音内容');
|
||
```
|
||
|
||
### Q5: 如何支持新的流程类型?
|
||
1. 创建新的节点类继承 `AbstractProcessNode`
|
||
2. 在配置中添加步骤
|
||
3. 实现 `canHandle()` 和 `doHandle()` 方法
|