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.
290 lines
11 KiB
PHP
290 lines
11 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\API\Internal;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Lib\Rs;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class PlanAutoGenerateController extends Controller
|
|
{
|
|
public function generate(Request $request)
|
|
{
|
|
$data = $request->validate([
|
|
'target_date' => 'nullable|date',
|
|
]);
|
|
|
|
$targetDate = $data['target_date'] ?? null;
|
|
if ($targetDate) {
|
|
$targetDate = date('Y-m-d', strtotime($targetDate));
|
|
} else {
|
|
$targetDate = date('Y-m-d', strtotime('+15 days'));
|
|
}
|
|
|
|
Log::info('号源自动生成开始', ['target_date' => $targetDate]);
|
|
|
|
$dayOfWeek = date('N', strtotime($targetDate));
|
|
|
|
$allModels = DB::table('plan_model as pm')
|
|
->join('plan_model_type as pmt', 'pm.model_type_id', '=', 'pmt.id')
|
|
->where('pm.deleted', 0)
|
|
->where('pm.status', 1)
|
|
->where('pmt.deleted', 0)
|
|
->select('pm.*', 'pmt.date_info', 'pmt.holiday_mode', 'pmt.type as model_type')
|
|
->get();
|
|
|
|
$channelQuotaRecords = DB::table('plan_model_channel_quota')
|
|
->whereIn('model_id', $allModels->pluck('id')->toArray())
|
|
->where('deleted', 0)
|
|
->select('id', 'model_id', 'channel_id', 'total_quota', 'allow_overuse_public_pool')
|
|
->get();
|
|
$channelQuotaMap = [];
|
|
foreach ($channelQuotaRecords as $cq) {
|
|
$channelQuotaMap[$cq->model_id][] = $cq;
|
|
}
|
|
|
|
$holidayMap = [];
|
|
$holidayRecords = DB::table('holiday')
|
|
->where('deleted', 0)
|
|
->where('status', 1)
|
|
->where('date', $targetDate)
|
|
->get();
|
|
foreach ($holidayRecords as $h) {
|
|
$holidayMap[$h->date] = $h->type;
|
|
}
|
|
|
|
$existingBatches = DB::table('plan_batch')
|
|
->where('plan_date', $targetDate)
|
|
->where('deleted', 0)
|
|
->select('id', 'resource_id', 'plan_date', 'start_time', 'end_time')
|
|
->get()
|
|
->groupBy('resource_id');
|
|
|
|
$existingByResource = [];
|
|
foreach ($existingBatches as $resourceId => $batches) {
|
|
$existingByResource[$resourceId] = $batches;
|
|
}
|
|
|
|
$grouped = $allModels->groupBy('department_id');
|
|
|
|
$totalBatches = 0;
|
|
$totalPlans = 0;
|
|
$skippedCount = 0;
|
|
$errors = [];
|
|
|
|
foreach ($grouped as $deptId => $models) {
|
|
try {
|
|
DB::beginTransaction();
|
|
|
|
$deptBatches = 0;
|
|
$deptPlans = 0;
|
|
|
|
foreach ($models as $model) {
|
|
$allowedDateRanges = $this->resolveDateRanges($model);
|
|
$holidayMode = $model->holiday_mode ?? 0;
|
|
|
|
$currentDate = new \DateTime($targetDate);
|
|
$shouldGenerate = $this->shouldGenerateForDate($currentDate, $model, $allowedDateRanges, $holidayMode, $holidayMap);
|
|
|
|
if (!$shouldGenerate) {
|
|
continue;
|
|
}
|
|
|
|
$resourceId = $model->resource_id;
|
|
$existing = $existingByResource[$resourceId] ?? collect();
|
|
|
|
$newStartTime = strtotime('2000-01-01 ' . $model->start_time);
|
|
$newEndTime = strtotime('2000-01-01 ' . $model->end_time);
|
|
|
|
$shouldSkip = false;
|
|
foreach ($existing as $plan) {
|
|
$existingStartTime = strtotime('2000-01-01 ' . $plan->start_time);
|
|
$existingEndTime = strtotime('2000-01-01 ' . $plan->end_time);
|
|
if (!($newEndTime <= $existingStartTime || $newStartTime >= $existingEndTime)) {
|
|
$shouldSkip = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ($shouldSkip) {
|
|
$skippedCount++;
|
|
continue;
|
|
}
|
|
|
|
$channelQuotas = collect($channelQuotaMap[$model->id] ?? []);
|
|
$hasChannelQuota = $channelQuotas->where('channel_id', '>', 0)->isNotEmpty();
|
|
|
|
$batchId = DB::table('plan_batch')->insertGetId([
|
|
'model_id' => $model->id,
|
|
'slot_mode' => $model->slot_mode,
|
|
'plan_date' => $targetDate,
|
|
'weekname' => $dayOfWeek,
|
|
'department_id' => $model->department_id,
|
|
'resource_id' => $model->resource_id,
|
|
'patient_type_mask' => $model->patient_type_mask,
|
|
'total_quota' => $model->total_quota,
|
|
'used_quota' => 0,
|
|
'start_time' => $model->start_time,
|
|
'end_time' => $model->end_time,
|
|
'cutoff_time' => $model->cutoff_time,
|
|
'status' => $model->status,
|
|
'enable_channel_quota' => $hasChannelQuota ? 1 : 0,
|
|
'adduser' => 0,
|
|
'deleted' => 0,
|
|
'created_at' => now(),
|
|
'updated_at' => now(),
|
|
]);
|
|
|
|
$deptBatches++;
|
|
|
|
if ($model->slot_mode == 1) {
|
|
DB::table('plan')->insert([
|
|
'batch_id' => $batchId,
|
|
'start_time' => $model->start_time,
|
|
'end_time' => $model->end_time,
|
|
'total_quota' => $model->total_quota,
|
|
'used_quota' => 0,
|
|
'status' => $model->status,
|
|
'created_at' => now(),
|
|
'updated_at' => now(),
|
|
]);
|
|
$deptPlans++;
|
|
} else {
|
|
$modelStartTime = strtotime('2000-01-01 ' . $model->start_time);
|
|
$modelEndTime = strtotime('2000-01-01 ' . $model->end_time);
|
|
$totalSeconds = $modelEndTime - $modelStartTime;
|
|
$intervalSeconds = (int)round($totalSeconds / $model->total_quota);
|
|
|
|
for ($i = 0; $i < $model->total_quota; $i++) {
|
|
$pointStartTime = $modelStartTime + ($i * $intervalSeconds);
|
|
$pointEndTime = $i == $model->total_quota - 1
|
|
? $modelEndTime
|
|
: $modelStartTime + (($i + 1) * $intervalSeconds);
|
|
|
|
DB::table('plan')->insert([
|
|
'batch_id' => $batchId,
|
|
'start_time' => date('H:i:s', $pointStartTime),
|
|
'end_time' => date('H:i:s', $pointEndTime),
|
|
'total_quota' => 1,
|
|
'used_quota' => 0,
|
|
'status' => $model->status,
|
|
'created_at' => now(),
|
|
'updated_at' => now(),
|
|
]);
|
|
$deptPlans++;
|
|
}
|
|
}
|
|
|
|
foreach ($channelQuotas as $quota) {
|
|
DB::table('plan_batch_channel_quota')->insert([
|
|
'batch_id' => $batchId,
|
|
'channel_id' => $quota->channel_id,
|
|
'total_quota' => $quota->total_quota,
|
|
'used_quota' => 0,
|
|
'created_at' => now(),
|
|
'updated_at' => now(),
|
|
]);
|
|
}
|
|
}
|
|
|
|
DB::commit();
|
|
$totalBatches += $deptBatches;
|
|
$totalPlans += $deptPlans;
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
$deptName = DB::table('department')->where('id', $deptId)->value('name');
|
|
$errors[] = [
|
|
'department_id' => $deptId,
|
|
'department_name' => $deptName ?? '',
|
|
'error' => $e->getMessage(),
|
|
];
|
|
Log::error('号源自动生成科室失败', [
|
|
'department_id' => $deptId,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
}
|
|
}
|
|
|
|
$result = [
|
|
'target_date' => $targetDate,
|
|
'day_of_week' => $dayOfWeek,
|
|
'total_batches' => $totalBatches,
|
|
'total_plans' => $totalPlans,
|
|
'skipped' => $skippedCount,
|
|
'errors' => $errors,
|
|
];
|
|
|
|
Log::info('号源自动生成完成', $result);
|
|
|
|
$message = "目标日期 {$targetDate},生成 {$totalBatches} 个批次、{$totalPlans} 个号源";
|
|
if ($skippedCount > 0) {
|
|
$message .= ",跳过 {$skippedCount} 个已存在";
|
|
}
|
|
|
|
return Rs::success($result, $message);
|
|
}
|
|
|
|
private function resolveDateRanges($model): array
|
|
{
|
|
$allowedDateRanges = [];
|
|
if (!empty($model->date_info)) {
|
|
$dateInfo = json_decode($model->date_info, true);
|
|
if ($model->model_type == 1) {
|
|
if (is_array($dateInfo) && count($dateInfo) > 0) {
|
|
if (is_array($dateInfo[0]) && count($dateInfo[0]) == 2) {
|
|
$allowedDateRanges = $dateInfo;
|
|
} else {
|
|
$allowedDateRanges = [$dateInfo];
|
|
}
|
|
}
|
|
} else {
|
|
if (is_array($dateInfo) && count($dateInfo) > 0) {
|
|
foreach ($dateInfo as $date) {
|
|
$allowedDateRanges[] = [$date, $date];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return $allowedDateRanges;
|
|
}
|
|
|
|
private function shouldGenerateForDate(\DateTime $currentDate, $model, array $allowedDateRanges, int $holidayMode, array $holidayMap): bool
|
|
{
|
|
$planDate = $currentDate->format('Y-m-d');
|
|
$planMonthDay = $currentDate->format('m-d');
|
|
$dayOfWeek = $currentDate->format('N');
|
|
|
|
$dateAllowed = false;
|
|
if (empty($allowedDateRanges)) {
|
|
$dateAllowed = true;
|
|
} else {
|
|
foreach ($allowedDateRanges as $range) {
|
|
if ($planMonthDay >= $range[0] && $planMonthDay <= $range[1]) {
|
|
$dateAllowed = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
$isHoliday = isset($holidayMap[$planDate]) && $holidayMap[$planDate] == 1;
|
|
$isMakeupWork = isset($holidayMap[$planDate]) && $holidayMap[$planDate] == 2;
|
|
$weeknameMatch = in_array($dayOfWeek, explode(',', $model->weekname));
|
|
|
|
if ($holidayMode == 1) {
|
|
return $dateAllowed && $weeknameMatch;
|
|
} elseif ($holidayMode == 2) {
|
|
return $dateAllowed && $isHoliday;
|
|
} else {
|
|
if ($isHoliday) {
|
|
return false;
|
|
} elseif ($isMakeupWork) {
|
|
return $dateAllowed;
|
|
} else {
|
|
return $dateAllowed && $weeknameMatch;
|
|
}
|
|
}
|
|
}
|
|
}
|