f2ff4ae123
- 将 FLOW_USE_CUSTOM_PROCESS 从 true 改为 false,禁用自定义流程 - 在 BlockTest 测试用例中改用 setBlockMode 方法设置阻断模式 - 设置统一的错误处理,将错误转为异常抛出 - 重命名 BlockTest 测试文件路径,优化测试组织结构 - 更新 IDE php include paths,调整依赖包引用顺序 - 删除无用的 tests/flow/Test.php 测试文件 - 微调 start.php、webman、windows.php 配置或代码模块
311 lines
11 KiB
PHP
311 lines
11 KiB
PHP
<?php
|
|
|
|
namespace app\repository;
|
|
|
|
use app\flow\context\bean\BatchNo;
|
|
use app\flow\context\ProcessContext;
|
|
use app\flow\enum\DbOperationType;
|
|
use app\model\EctActions;
|
|
use app\utils\Logger;
|
|
|
|
/**
|
|
* EctActions 数据操作仓库
|
|
* 封装 ect_actions 表的所有读写操作
|
|
*/
|
|
class EctActionsRepository extends BaseRepository
|
|
{
|
|
public function __construct()
|
|
{
|
|
$this->model = new EctActions();
|
|
}
|
|
|
|
public static function new(): static
|
|
{
|
|
return new self();
|
|
}
|
|
|
|
/**
|
|
* 从数据库查询最大的批次号
|
|
* 用于分布式场景下保证批次号一致性
|
|
*
|
|
* @param string $machineId
|
|
* @return string|null 批次号,未找到返回 null
|
|
*/
|
|
public function findTodayActiveBatchNo(string $machineId): ?string
|
|
{
|
|
try {
|
|
// 1. 精准限定今日时间范围(避免跨天数据)
|
|
$todayStart = date('Y-m-d 00:00:00');
|
|
$todayEnd = date('Y-m-d 23:59:59');
|
|
|
|
$todayDate = date('Ymd');
|
|
|
|
$record = EctActions::where('process_name', '<>', '结束')
|
|
->whereBetween('created_at', [$todayStart, $todayEnd])
|
|
->where('op_batchno', 'like', $todayDate . $machineId . '%') // 匹配今日日期+指定机器ID开头的批次号
|
|
->select('op_batchno')
|
|
->orderBy('op_batchno', 'desc') // 降序排列,最大的序列号(批次号)排在最前
|
|
->lockForUpdate()
|
|
->first(); // 获取第一条(即序列号最大的)记录
|
|
|
|
// 3. 严谨的空值判断
|
|
if (empty($record) || empty(trim($record->op_batchno))) {
|
|
return null;
|
|
}
|
|
|
|
return (string)trim($record->op_batchno);
|
|
} catch (\Exception $e) {
|
|
// 记录异常(可选:根据项目日志规范调整)
|
|
Logger::error('查询最大批次号失败:', [
|
|
'error' => $e->getMessage(),
|
|
'trace' => $e->getTraceAsString()
|
|
]);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 查询内镜最后一条洗消操作记录
|
|
*
|
|
* @param string $endoscopeId 内镜ID
|
|
* @param array $excludeActionTypes 排除的操作类型(如 [0, 7, 8])
|
|
* @return EctActions|null
|
|
*/
|
|
public function findLastAction(string $endoscopeId, array $excludeActionTypes = []): ?EctActions
|
|
{
|
|
$query = EctActions::where('endoscope_id', $endoscopeId);
|
|
if (!empty($excludeActionTypes)) {
|
|
$query->whereNotIn('action_type', $excludeActionTypes);
|
|
}
|
|
/** @var EctActions|null */
|
|
return $query->orderBy('action_id', 'desc')->first();
|
|
}
|
|
|
|
/**
|
|
* 查询今日洗消记录数
|
|
*
|
|
* @param string $endoscopeId 内镜ID
|
|
* @param array $excludeActionTypes 排除的操作类型 0诊疗 1手工洗 2机洗 3 手工洗(晨洗)4机洗(晨洗)5手工洗(加强)6机洗(加强)7测漏 8存储
|
|
* @return int
|
|
*/
|
|
public function countTodayActions(string $endoscopeId, string $todayStart, array $excludeActionTypes = []): int
|
|
{
|
|
$todayStart = date('Y-m-d H:i:s', strtotime($todayStart));
|
|
$query = EctActions::where('endoscope_id', $endoscopeId)
|
|
->where('created_at', '>=', $todayStart);
|
|
if (!empty($excludeActionTypes)) {
|
|
$query->whereNotIn('action_type', $excludeActionTypes);
|
|
}
|
|
// 遍历
|
|
$count = 0;
|
|
$today = date('Ymd');
|
|
$query->lazy()->each(function (EctActions $record) use (&$count, $today) {
|
|
$batchInfo = BatchNo::fromString($record->op_batchno);
|
|
$dateTime = $batchInfo->getTimestamp();
|
|
if (empty($batchInfo->getDateStr()) || $dateTime === false) return;
|
|
$recordDate = date('Ymd', $dateTime);
|
|
if ($recordDate >= $today) {
|
|
$count += 1;
|
|
}
|
|
});
|
|
return $count;
|
|
}
|
|
|
|
/**
|
|
* 查询最后一次存储入库时间
|
|
*
|
|
* @param string $endoscopeId 内镜ID
|
|
* @return string|null op_starttime,未找到返回 null
|
|
*/
|
|
public function findLastStorageTime(string $endoscopeId): ?string
|
|
{
|
|
$record = EctActions::where('endoscope_id', $endoscopeId)
|
|
->where('action_type', 8)
|
|
->where('process_name', '内镜放入')
|
|
->select('op_starttime')
|
|
->orderBy('action_id', 'desc')
|
|
->first();
|
|
|
|
if ($record === null) {
|
|
return null;
|
|
}
|
|
|
|
return (string)$record->op_starttime;
|
|
}
|
|
|
|
/**
|
|
* 查询内镜当前是否在存储柜中
|
|
* 根据最后一次存储操作判断:入库则在库中,出库则不在
|
|
*
|
|
* @param string $endoscopeId 内镜ID
|
|
* @return bool true=在库中,false=不在库中
|
|
*/
|
|
public function isEndoscopeInStorage(string $endoscopeId): bool
|
|
{
|
|
$record = EctActions::where('endoscope_id', $endoscopeId)
|
|
->where('action_type', 8)
|
|
->whereIn('process_name', ['内镜放入', '内镜取出'])
|
|
->select('process_name', 'op_starttime')
|
|
->orderBy('action_id', 'desc')
|
|
->first();
|
|
|
|
if ($record === null) {
|
|
return false;
|
|
}
|
|
|
|
return $record->process_name === '内镜放入';
|
|
}
|
|
|
|
/**
|
|
* 查询最后一次存储操作记录
|
|
*
|
|
* @param string $endoscopeId 内镜ID
|
|
* @return array|null ['process_name' => ..., 'op_starttime' => ...] 或 null
|
|
*/
|
|
public function findLastStorageAction(string $endoscopeId): ?array
|
|
{
|
|
$record = EctActions::where('endoscope_id', $endoscopeId)
|
|
->where('action_type', 8)
|
|
->whereIn('process_name', ['内镜放入', '内镜取出'])
|
|
->select('process_name', 'op_starttime', 'action_id')
|
|
->orderBy('action_id', 'desc')
|
|
->first();
|
|
|
|
if ($record === null) {
|
|
return null;
|
|
}
|
|
|
|
return [
|
|
'process_name' => (string)$record->process_name,
|
|
'op_starttime' => (string)$record->op_starttime,
|
|
'action_id' => (int)$record->action_id,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 查询批次号对应的操作员信息
|
|
*
|
|
* @param string $batchNo 批次号
|
|
* @return array|null [字段名=> 值, ...] 或 null
|
|
*/
|
|
public function findOperatorByBatchNo(string $batchNo): ?array
|
|
{
|
|
$record = EctActions::where('op_batchno', $batchNo)
|
|
->whereNotNull('opuser_id')
|
|
->select('opuser_id', 'opuser_name', 'opuser_rfid', 'opuser_type')
|
|
->first();
|
|
|
|
if ($record === null) {
|
|
return null;
|
|
}
|
|
|
|
return [
|
|
'id' => (string)$record->opuser_id,
|
|
'name' => (string)$record->opuser_name,
|
|
'rfid' => (string)$record->opuser_rfid,
|
|
'type' => (int)$record->opuser_type,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 插入一条洗消记录
|
|
*
|
|
* @param array $data 字段数组
|
|
* @return EctActions
|
|
*/
|
|
public function insert(array $data): EctActions
|
|
{
|
|
return EctActions::create($data);
|
|
}
|
|
|
|
/**
|
|
* 从 ProcessContext 保存洗消记录
|
|
*
|
|
* @param ProcessContext $context 流程上下文
|
|
* @param int $opuserType 操作员类型
|
|
* @return EctActions|null
|
|
*/
|
|
public function saveFromContext(ProcessContext $context, int $opuserType): ?EctActions
|
|
{
|
|
$op_endtime = null;
|
|
$process_order = 1;
|
|
if ($context->getCurrentStep() === '结束') {
|
|
$op_endtime = date('Y-m-d H:i:s');
|
|
}
|
|
if (!empty($context->getPreviousAction())) {
|
|
$process_order = (int)($context->getPreviousAction()->process_order ?? 1);
|
|
}
|
|
if (in_array(DbOperationType::INSERT, $context->getDbOperations())) {
|
|
return $this->insert([
|
|
'op_batchno' => $context->getBatchNo(),
|
|
'action_type' => $this->mapActionType($context->getProcessType()),
|
|
'action_type_name' => $context->getProcessType(),
|
|
'process_name' => $context->getCurrentStep(),
|
|
'process_order' => $process_order + 1,
|
|
'op_morning' => $context->getMorningWash()->needMorningWash ? 1 : 0,
|
|
'op_enhance' => $context->isEnhanceWashNeeded() ? 1 : 0,
|
|
'reader_id' => (int)$context->getReader()->id ?: null,
|
|
'reader_no' => $context->getReader()->no ?: null,
|
|
'opuser_type' => $opuserType,
|
|
'opuser_id' => (int)$context->getOperator()->id ?: null,
|
|
'opuser_rfid' => $context->getOperator()->rfid ?: null,
|
|
'opuser_name' => $context->getOperator()->name ?: null,
|
|
'endoscope_id' => (int)$context->getEndoscope()->id ?: null,
|
|
'endoscope_rfid' => $context->getEndoscope()->cardNo ?: null,
|
|
'endoscope_name' => $context->getEndoscope()->name ?: null,
|
|
'op_starttime' => $context->getActionStartTime() ?: date('Y-m-d H:i:s'),
|
|
'op_endtime' => $op_endtime,
|
|
'op_duration' => $context->getDuration() ?: null,
|
|
'created_at' => date('Y-m-d H:i:s'),
|
|
]);
|
|
} elseif (in_array(DbOperationType::UPDATE, $context->getDbOperations())) {
|
|
EctActions::where('op_batchno', $context->getBatchNo())
|
|
->where('endoscope_id', $context->getEndoscope()->id)
|
|
->update([
|
|
'action_type' => $this->mapActionType($context->getProcessType()),
|
|
'action_type_name' => $context->getProcessType(),
|
|
]);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* 映射流程类型到 action_type
|
|
* 0诊疗 1手工洗 2机洗 3 手工洗(晨洗)4机洗(晨洗)5手工洗(加强)6机洗(加强)
|
|
*/
|
|
protected function mapActionType(string $processType): int
|
|
{
|
|
$mapping = [
|
|
'诊疗' => 0,
|
|
'手工洗' => 1,
|
|
'手工洗(晨洗)' => 3,
|
|
'手工洗(加强)' => 5,
|
|
'机洗' => 2,
|
|
'机洗(晨洗)' => 4,
|
|
'机洗(加强)' => 6,
|
|
'测漏' => 7,
|
|
'存储' => 8,
|
|
];
|
|
return $mapping[$processType] ?? 1;
|
|
}
|
|
|
|
/**
|
|
* 更新批次号最后一条记录的结束时间和时长
|
|
*
|
|
* @param string $batchNo 批次号
|
|
* @param string $endTime 结束时间
|
|
* @param int $duration 时长(秒)
|
|
* @return int 影响行数
|
|
*/
|
|
public function updateEndTime(string $batchNo, string $endTime, int $duration): int
|
|
{
|
|
return EctActions::where('op_batchno', $batchNo)
|
|
->orderBy('action_id', 'desc')
|
|
->limit(1)
|
|
->update([
|
|
'op_endtime' => $endTime,
|
|
'op_duration' => $duration,
|
|
]);
|
|
}
|
|
}
|