'周一', 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; } }