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.

330 lines
14 KiB
PHP

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
namespace App\Http\Controllers\API\H5;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Lib\Rs;
use App\Services\PatientAuthService;
use App\Services\PlanService;
use Illuminate\Support\Facades\DB;
class PlanController extends Controller
{
private PatientAuthService $patientAuthService;
private PlanService $planService;
public function __construct(PatientAuthService $patientAuthService, PlanService $planService)
{
$this->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());
}
}
}