You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
312 lines
9.0 KiB
PHP
312 lines
9.0 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
/**
|
|
* 项目规则校验服务
|
|
*/
|
|
class ItemRuleValidationService
|
|
{
|
|
/**
|
|
* 星期映射: 数字转中文
|
|
*/
|
|
private const WEEKDAY_MAP = [
|
|
1 => '周一',
|
|
2 => '周二',
|
|
3 => '周三',
|
|
4 => '周四',
|
|
5 => '周五',
|
|
6 => '周六',
|
|
7 => '周日',
|
|
];
|
|
|
|
/**
|
|
* 性别映射: 数据库值转中文
|
|
*/
|
|
private const GENDER_MAP = [
|
|
1 => '男',
|
|
2 => '女',
|
|
0 => '未知',
|
|
];
|
|
|
|
/**
|
|
* 校验项目规则
|
|
*
|
|
* @param array $itemCodes 检查项目code数组
|
|
* @param int $patientId 患者ID
|
|
* @param int $planId 号源ID
|
|
* @return array ['valid' => bool, 'conflicts' => [...], 'patient_info' => [...], 'appointment_time' => '...']
|
|
*/
|
|
public function validate(array $itemCodes, int $patientId, int $planId): array
|
|
{
|
|
// 1. 查询患者信息
|
|
$patientInfo = $this->getPatientInfo($patientId);
|
|
if (!$patientInfo) {
|
|
return [
|
|
'valid' => false,
|
|
'conflicts' => [[
|
|
'type' => 'ITEM_RULE',
|
|
'rule_type' => '',
|
|
'item_code' => '',
|
|
'message' => '患者信息不存在',
|
|
]],
|
|
];
|
|
}
|
|
|
|
// 2. 查询预约时间
|
|
$appointmentInfo = $this->getAppointmentInfo($planId);
|
|
if (!$appointmentInfo) {
|
|
return [
|
|
'valid' => false,
|
|
'conflicts' => [[
|
|
'type' => 'ITEM_RULE',
|
|
'rule_type' => '',
|
|
'item_code' => '',
|
|
'message' => '号源信息不存在',
|
|
]],
|
|
];
|
|
}
|
|
|
|
// 3. 查询项目及其绑定的规则
|
|
$itemRules = $this->getItemRules($itemCodes);
|
|
if (empty($itemRules)) {
|
|
return [
|
|
'valid' => true,
|
|
'conflicts' => [],
|
|
'patient_info' => $patientInfo,
|
|
'appointment_time' => $appointmentInfo['full_time'],
|
|
];
|
|
}
|
|
|
|
// 4. 执行校验
|
|
$conflicts = [];
|
|
foreach ($itemRules as $itemCode => $rules) {
|
|
foreach ($rules as $rule) {
|
|
$conflict = $this->validateRule(
|
|
$rule,
|
|
$patientInfo,
|
|
$appointmentInfo,
|
|
$itemCode
|
|
);
|
|
if ($conflict) {
|
|
$conflicts[] = $conflict;
|
|
}
|
|
}
|
|
}
|
|
|
|
return [
|
|
'valid' => empty($conflicts),
|
|
'conflicts' => $conflicts,
|
|
'patient_info' => $patientInfo,
|
|
'appointment_time' => $appointmentInfo['full_time'],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 获取患者信息
|
|
*/
|
|
private function getPatientInfo(int $patientId): ?array
|
|
{
|
|
$application = DB::table('exam_application')
|
|
->where('patient_id', $patientId)
|
|
->orderBy('id', 'desc')
|
|
->select('patient_age', 'patient_gender')
|
|
->first();
|
|
|
|
if (!$application) {
|
|
return null;
|
|
}
|
|
|
|
return [
|
|
'age' => $application->patient_age,
|
|
'gender' => self::GENDER_MAP[$application->patient_gender] ?? '未知',
|
|
'gender_raw' => $application->patient_gender,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 获取预约信息
|
|
*/
|
|
private function getAppointmentInfo(int $planId): ?array
|
|
{
|
|
$plan = DB::table('plan as p')
|
|
->join('plan_batch as pb', 'p.batch_id', '=', 'pb.id')
|
|
->where('p.id', $planId)
|
|
->select('pb.plan_date', 'p.start_time', 'p.end_time', 'pb.weekname')
|
|
->first();
|
|
|
|
if (!$plan) {
|
|
return null;
|
|
}
|
|
|
|
// 组合完整的预约时间
|
|
$fullTime = $plan->plan_date . ' ' . $plan->start_time;
|
|
|
|
return [
|
|
'date' => $plan->plan_date,
|
|
'start_time' => $plan->start_time,
|
|
'end_time' => $plan->end_time,
|
|
'weekday' => self::WEEKDAY_MAP[$plan->weekname] ?? '未知',
|
|
'weekday_raw' => $plan->weekname,
|
|
'full_time' => $fullTime,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 获取项目绑定的规则
|
|
*/
|
|
private function getItemRules(array $itemCodes): array
|
|
{
|
|
if (empty($itemCodes)) {
|
|
return [];
|
|
}
|
|
|
|
// 获取项目ID
|
|
$items = DB::table('exam_item')
|
|
->whereIn('code', $itemCodes)
|
|
->where('deleted', 0)
|
|
->select('id', 'code')
|
|
->get()
|
|
->keyBy('id')
|
|
->toArray();
|
|
|
|
$itemIds = array_column($items, 'id');
|
|
|
|
if (empty($itemIds)) {
|
|
return [];
|
|
}
|
|
|
|
// 获取绑定的规则
|
|
$rules = DB::table('exam_item_rule')
|
|
->whereIn('target_id', $itemIds)
|
|
->where('target_type', 'ITEM')
|
|
->where('status', 1)
|
|
->where('deleted', 0)
|
|
->select('target_id', 'rule_type', 'rule_value')
|
|
->get()
|
|
->toArray();
|
|
|
|
// 按code分组
|
|
$result = [];
|
|
foreach ($rules as $rule) {
|
|
$itemCode = $items[$rule->target_id]->code ?? null;
|
|
if ($itemCode) {
|
|
$rule->rule_value = json_decode($rule->rule_value, true);
|
|
$result[$itemCode][] = $rule;
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* 校验单个规则
|
|
*/
|
|
private function validateRule(object $rule, array $patientInfo, array $appointmentInfo, string $itemCode): ?array
|
|
{
|
|
$ruleType = $rule->rule_type;
|
|
$ruleValue = $rule->rule_value;
|
|
|
|
switch ($ruleType) {
|
|
case 'AGE_LIMIT':
|
|
return $this->validateAgeLimit($ruleValue, $patientInfo, $itemCode);
|
|
|
|
case 'GENDER_LIMIT':
|
|
return $this->validateGenderLimit($ruleValue, $patientInfo, $itemCode);
|
|
|
|
case 'TIME_RESTRICTION':
|
|
return $this->validateTimeRestriction($ruleValue, $patientInfo, $appointmentInfo, $itemCode);
|
|
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 校验年龄限制
|
|
*/
|
|
private function validateAgeLimit(array $ruleValue, array $patientInfo, string $itemCode): ?array
|
|
{
|
|
$minAge = (int)($ruleValue['min_age'] ?? 0);
|
|
$maxAge = (int)($ruleValue['max_age'] ?? 150);
|
|
$patientAge = (int)$patientInfo['age'];
|
|
|
|
if ($patientAge < $minAge || $patientAge > $maxAge) {
|
|
return [
|
|
'type' => 'ITEM_RULE',
|
|
'rule_type' => 'AGE_LIMIT',
|
|
'item_code' => $itemCode,
|
|
'message' => "年龄限制{$minAge}-{$maxAge}岁,患者年龄{$patientAge}岁不符合要求",
|
|
];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* 校验性别限制
|
|
*/
|
|
private function validateGenderLimit(array $ruleValue, array $patientInfo, string $itemCode): ?array
|
|
{
|
|
$requiredGender = $ruleValue['gender'] ?? '';
|
|
$patientGender = $patientInfo['gender'];
|
|
|
|
if ($requiredGender && $patientGender !== $requiredGender && $patientGender !== '未知') {
|
|
return [
|
|
'type' => 'ITEM_RULE',
|
|
'rule_type' => 'GENDER_LIMIT',
|
|
'item_code' => $itemCode,
|
|
'message' => "性别限制{$requiredGender},患者性别{$patientGender}不符合要求",
|
|
];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* 校验预约时间段限制
|
|
*/
|
|
private function validateTimeRestriction(array $ruleValue, array $patientInfo, array $appointmentInfo, string $itemCode): ?array
|
|
{
|
|
$errors = [];
|
|
|
|
// 校验时间段
|
|
$startTime = $ruleValue['start_time'] ?? null;
|
|
$endTime = $ruleValue['end_time'] ?? null;
|
|
$appointmentStartTime = $appointmentInfo['start_time'];
|
|
|
|
if ($startTime && $endTime) {
|
|
// 比较时间,需要转换为时间戳
|
|
$startTimestamp = strtotime('2000-01-01 ' . $startTime);
|
|
$endTimestamp = strtotime('2000-01-01 ' . $endTime);
|
|
$appointmentTimestamp = strtotime('2000-01-01 ' . $appointmentStartTime);
|
|
|
|
if ($appointmentTimestamp < $startTimestamp || $appointmentTimestamp > $endTimestamp) {
|
|
$errors[] = "预约时间{$appointmentStartTime}不在允许时间段({$startTime}-{$endTime})内";
|
|
}
|
|
}
|
|
|
|
// 校验星期
|
|
$allowedDays = $ruleValue['days'] ?? [];
|
|
$appointmentWeekday = $appointmentInfo['weekday'];
|
|
|
|
if (!empty($allowedDays) && !in_array($appointmentWeekday, $allowedDays)) {
|
|
$daysStr = implode(',', $allowedDays);
|
|
$errors[] = "预约日期为{$appointmentWeekday},仅允许在{$daysStr}预约";
|
|
}
|
|
|
|
if (!empty($errors)) {
|
|
return [
|
|
'type' => 'ITEM_RULE',
|
|
'rule_type' => 'TIME_RESTRICTION',
|
|
'item_code' => $itemCode,
|
|
'message' => implode('; ', $errors),
|
|
];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|