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

<?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;
}
}