patientAuthService = $patientAuthService; $this->planService = $planService; } /** * 获取号源日历(按月查询) * POST /api/h5/plan/calendar */ public function calendar(Request $request) { $payload = $request->attributes->get('payload'); $idCardNo = $this->patientAuthService->getPatientIdCardNo($payload); $examApplicationIds = $request->input('exam_application_ids', []); $year = $request->input('year', date('Y')); $month = $request->input('month', date('n')); $channelId = (int)$request->input('channel_id', 3); if (empty($examApplicationIds) || !is_array($examApplicationIds)) { return Rs::error('请选择检查项目'); } $count = DB::table('exam_application') ->whereIn('id', $examApplicationIds) ->where('patient_id_card_no', $idCardNo) ->count(); if ($count != count($examApplicationIds)) { return Rs::error('申请单校验失败'); } try { $firstDayOfMonth = strtotime(sprintf('%04d-%02d-01', $year, $month)); $firstDayOfWeek = date('w', $firstDayOfMonth); $startDate = date('Y-m-d', strtotime("-{$firstDayOfWeek} days", $firstDayOfMonth)); $daysInMonth = cal_days_in_month(CAL_GREGORIAN, $month, $year); $lastDayOfWeek = date('w', strtotime(sprintf('%04d-%02d-%d', $year, $month, $daysInMonth))); $totalDays = $firstDayOfWeek + $daysInMonth + (6 - $lastDayOfWeek); $totalRows = ceil($totalDays / 7); $today = date('Y-m-d'); $calendarDates = []; $currentDate = $startDate; for ($i = 0; $i < $totalRows * 7; $i++) { if ($currentDate >= $today) { $calendarDates[] = $currentDate; } $currentDate = date('Y-m-d', strtotime('+1 day', strtotime($currentDate))); } if (empty($calendarDates)) { return Rs::success(['resources' => []]); } $planData = $this->planService->queryPlanBatchesData( $examApplicationIds, $channelId, '', 0, $calendarDates ); $planBatches = $planData['planBatches']; $quotaByBatch = $planData['quotaByBatch']; if ($planBatches->isEmpty()) { return Rs::success(['resources' => []]); } $resourcesData = []; $batchesByResource = $planBatches->groupBy('resource_id'); foreach ($batchesByResource as $resourceId => $batches) { $resource = $batches->first(); $batchesByDate = $batches->groupBy('plan_date'); $datesData = []; foreach ($calendarDates as $date) { if (!isset($batchesByDate[$date])) { $datesData[$date] = [ 'date' => $date, 'total_count' => 0, 'available_count' => 0 ]; continue; } $totalCount = 0; $availableCount = 0; foreach ($batchesByDate[$date] as $batch) { $remaining = $this->planService->calculateRemainingQuota( $batch, $channelId, $quotaByBatch[$batch->batch_id]['channel'] ?? null, $quotaByBatch[$batch->batch_id]['public'] ?? null, 1 ); $quotas = $quotaByBatch[$batch->batch_id] ?? ['public' => null, 'channel' => null]; $publicQuota = $quotas['public']; $channelQuota = $quotas['channel']; $enableChannelQuota = ($batch->enable_channel_quota ?? 0) == 1; if (!$enableChannelQuota) { if (!$publicQuota) continue; $totalQuota = $publicQuota->total_quota; $usedQuota = $publicQuota->used_quota; $lockedQuota = $publicQuota->locked_quota ?? 0; } else { if (!$channelQuota) continue; $totalQuota = $channelQuota->total_quota; $usedQuota = $channelQuota->used_quota; $lockedQuota = $channelQuota->locked_quota ?? 0; $allowOveruse = $channelQuota->allow_overuse_public_pool ?? 0; if ($allowOveruse && $publicQuota) { $totalQuota += $publicQuota->total_quota; $usedQuota += $publicQuota->used_quota; $lockedQuota += $publicQuota->locked_quota ?? 0; } } $totalCount += $totalQuota; $availableCount += max(0, $totalQuota - $usedQuota - $lockedQuota); } $datesData[$date] = [ 'date' => $date, 'total_count' => $totalCount, 'available_count' => $availableCount ]; } $resourcesData[] = [ 'room_id' => $resourceId, 'room_name' => $resource->resource_name, 'slot_data' => array_values($datesData) ]; } return Rs::success(['resources' => $resourcesData]); } catch (\Exception $e) { return Rs::error('获取号源日历失败:' . $e->getMessage()); } } /** * 获取可用号源(选定日期后) * POST /api/h5/plan/available */ public function available(Request $request) { $payload = $request->attributes->get('payload'); $idCardNo = $this->patientAuthService->getPatientIdCardNo($payload); $examApplicationIds = $request->input('exam_application_ids', []); $startDate = $request->input('start_date', date('Y-m-d')); $channelId = (int)$request->input('channel_id', 3); // 默认微信,自助机传4 if (empty($examApplicationIds) || !is_array($examApplicationIds)) { return Rs::error('请选择检查项目'); } // 校验申请单属于当前患者 $count = DB::table('exam_application') ->whereIn('id', $examApplicationIds) ->where('patient_id_card_no', $idCardNo) ->count(); if ($count != count($examApplicationIds)) { return Rs::error('申请单校验失败'); } try { $planData = $this->planService->queryPlanBatchesData($examApplicationIds, $channelId, $startDate, 1); $planBatches = $planData['planBatches']; $quotaByBatch = $planData['quotaByBatch']; $totalUseSeats = $planData['totalUseSeats']; $now = now(); $currentDate = $now->format('Y-m-d'); $resourcesData = []; $batchesByResource = $planBatches->groupBy('resource_id'); foreach ($batchesByResource as $resourceId => $batches) { $resource = $batches->first(); $slotMode = $resource->slot_mode; $periods = []; foreach ($batches as $batch) { $isPastCutoff = ($batch->plan_date === $currentDate) && $now->gt(\Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $batch->plan_date . ' ' . $batch->cutoff_time)); $quotas = $quotaByBatch[$batch->batch_id] ?? ['public' => null, 'channel' => null]; $publicQuota = $quotas['public']; $channelQuota = $quotas['channel']; if ($slotMode == 1) { // 时间段模式 if (($batch->enable_channel_quota ?? 0) == 0) { if (!$publicQuota) continue; $effectiveQuota = $publicQuota; $allowOveruse = 0; } else { if (!$channelQuota) continue; $effectiveQuota = $channelQuota; $allowOveruse = $channelQuota->allow_overuse_public_pool ?? 0; } $totalQuota = $effectiveQuota->total_quota; $usedQuota = $effectiveQuota->used_quota; $lockedQuota = $effectiveQuota->locked_quota ?? 0; if ($allowOveruse && $publicQuota && ($batch->enable_channel_quota ?? 0) != 0) { $totalQuota += $publicQuota->total_quota; $usedQuota += $publicQuota->used_quota; $lockedQuota += $publicQuota->locked_quota ?? 0; } $remainCount = max(0, $totalQuota - $usedQuota - $lockedQuota); $enable = $remainCount >= $totalUseSeats && !$isPastCutoff; $planRecord = DB::table('plan') ->where('batch_id', $batch->batch_id) ->where('deleted', 0) ->select('id') ->first(); $periods[] = [ 'period_id' => $batch->batch_id, 'time_range' => substr($batch->start_time, 0, 5) . '-' . substr($batch->end_time, 0, 5), 'plan_id' => $planRecord ? $planRecord->id : null, 'remain_count' => $remainCount, 'total_count' => $totalQuota, 'enable' => $enable ]; } else { // 时间点模式 $enableChannelQuota = ($batch->enable_channel_quota ?? 0) == 1; if ($enableChannelQuota && !$channelQuota) continue; $overallTotal = 0; $overallUsed = 0; $hasQuota = false; if (!$enableChannelQuota) { if ($publicQuota) { $overallTotal = $publicQuota->total_quota; $overallUsed = $publicQuota->used_quota; $hasQuota = true; } } else { if ($channelQuota) { $overallTotal = $channelQuota->total_quota; $overallUsed = $channelQuota->used_quota; $allowOveruse = $channelQuota->allow_overuse_public_pool ?? 0; if ($allowOveruse && $publicQuota) { $overallTotal += $publicQuota->total_quota; $overallUsed += $publicQuota->used_quota; } $hasQuota = true; } } $timePoints = DB::table('plan') ->where('batch_id', $batch->batch_id) ->where(['status' => 1, 'deleted' => 0]) ->select('id', 'start_time', 'end_time', 'total_quota', 'used_quota', 'locked_quota') ->orderBy('start_time') ->get(); if ($timePoints->isEmpty()) continue; $slots = []; foreach ($timePoints as $tp) { $isTimeExpired = false; if ($batch->plan_date === $currentDate) { $tpStartTime = \Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $batch->plan_date . ' ' . $tp->start_time); $isTimeExpired = $now->gt($tpStartTime); } if (!$hasQuota || ($overallTotal - $overallUsed) <= 0) { $slots[] = ['id' => $tp->id, 'time' => substr($tp->start_time, 0, 5), 'enable' => false, 'remain_count' => 0, 'total_count' => $tp->total_quota]; } else { $available = $tp->total_quota - $tp->used_quota - ($tp->locked_quota ?? 0); $slots[] = ['id' => $tp->id, 'time' => substr($tp->start_time, 0, 5), 'enable' => $available > 0 && !$isPastCutoff && !$isTimeExpired, 'remain_count' => max(0, $available), 'total_count' => $tp->total_quota]; } } $periods[] = [ 'period_id' => $batch->batch_id, 'time_range' => substr($batch->start_time, 0, 5) . '-' . substr($batch->end_time, 0, 5), 'plan_id' => null, 'slots' => $slots ]; } } $resourcesData[] = [ 'room_id' => $resourceId, 'room_name' => $resource->resource_name, 'slot_mode' => $slotMode, 'periods' => $periods ]; } return Rs::success(['resources' => $resourcesData]); } catch (\Exception $e) { return Rs::error('获取可用号源失败:' . $e->getMessage()); } } }