From 0dd6529dcfa18e3c89f4908e083edcdc08b867b0 Mon Sep 17 00:00:00 2001 From: Ethanfly Date: Mon, 12 Jan 2026 13:55:41 +0800 Subject: [PATCH] Refactor patient follow-up system to focus on monthly reminders. Updated logic to filter and display only patients needing follow-up this month. Enhanced patient model methods for calculating follow-up dates and counts. Improved UI in reminders view with new layout and call button functionality. --- README.md | 9 +- app/Http/Controllers/PatientController.php | 80 ++++-------- app/Models/Patient.php | 82 +++++++------ resources/views/layouts/app.blade.php | 34 ++++- resources/views/patients/index.blade.php | 51 +------- resources/views/patients/reminders.blade.php | 123 +++++++------------ 6 files changed, 149 insertions(+), 230 deletions(-) diff --git a/README.md b/README.md index 33ee8d5..4df27bf 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,10 @@ - 🗑️ 删除患者记录 ### 随访提醒 -- ⏰ 智能计算随访日期(出院后1周、1月、3月、6月) -- 🔴 过期提醒 - 显示已过期未随访的患者 -- 🟡 今日到期 - 当天需要随访的患者 -- 🔵 即将到期 - 7天内需要随访的患者 -- ✅ 标记随访完成,自动计算下次随访时间 +- ⏰ 智能计算随访日期(出院后1、3、6、12个月) +- 📅 本月提醒 - 只显示本月需要随访的患者列表 +- 📊 进度自动更新 - 过期月份自动算作已完成 +- 📞 一键拨打电话进行回访 ### 用户系统 - 👤 用户注册/登录 diff --git a/app/Http/Controllers/PatientController.php b/app/Http/Controllers/PatientController.php index 7e416ae..05abf7a 100644 --- a/app/Http/Controllers/PatientController.php +++ b/app/Http/Controllers/PatientController.php @@ -46,54 +46,33 @@ class PatientController extends Controller } /** - * 显示需要随访提醒的患者 + * 显示需要随访提醒的患者(只显示当月需要随访的) */ public function reminders(Request $request) { $patients = $this->userPatients()->get(); - // 筛选需要随访的患者 + // 只筛选当月需要随访的患者 $reminders = $patients->filter(function ($patient) { - return !$patient->isCompleted(); + return $patient->needsFollowUpThisMonth(); })->map(function ($patient) { - $nextDate = $patient->getNextFollowUpDate(); return [ 'patient' => $patient, - 'next_follow_up_date' => $nextDate, - 'next_follow_up_number' => $patient->getNextFollowUpNumber(), - 'status' => $patient->getFollowUpStatus(), - 'needs_attention' => $patient->needsFollowUp(), - 'days_until' => $nextDate ? Carbon::today()->diffInDays($nextDate, false) : null, + 'follow_up_date' => $patient->getCurrentMonthFollowUpDate(), + 'follow_up_number' => $patient->getCurrentMonthFollowUpNumber(), ]; - })->sortBy('days_until'); - - // 筛选类型 - $filter = $request->input('filter', 'all'); - - if ($filter === 'overdue') { - $reminders = $reminders->filter(fn($r) => $r['days_until'] !== null && $r['days_until'] < 0); - } elseif ($filter === 'today') { - $reminders = $reminders->filter(fn($r) => $r['days_until'] === 0); - } elseif ($filter === 'upcoming') { - $reminders = $reminders->filter(fn($r) => $r['days_until'] !== null && $r['days_until'] > 0 && $r['days_until'] <= 7); - } + })->sortBy(function ($r) { + return $r['follow_up_date']; + }); // 统计数据 $stats = [ - 'total' => $this->userPatients()->count(), - 'overdue' => $patients->filter(fn($p) => !$p->isCompleted() && $p->getNextFollowUpDate()?->lt(Carbon::today()))->count(), - 'today' => $patients->filter(fn($p) => !$p->isCompleted() && $p->getNextFollowUpDate()?->isToday())->count(), - 'upcoming' => $patients->filter(function ($p) { - if ($p->isCompleted()) return false; - $next = $p->getNextFollowUpDate(); - if (!$next) return false; - $diff = Carbon::today()->diffInDays($next, false); - return $diff > 0 && $diff <= 7; - })->count(), + 'count' => $reminders->count(), 'completed' => $patients->filter(fn($p) => $p->isCompleted())->count(), + 'total' => $patients->count(), ]; - return view('patients.reminders', compact('reminders', 'stats', 'filter')); + return view('patients.reminders', compact('reminders', 'stats')); } /** @@ -359,46 +338,34 @@ class PatientController extends Controller } /** - * 导出提醒列表 (使用 xlswriter 生成 Excel) + * 导出本月随访列表 (使用 xlswriter 生成 Excel) */ public function export(Request $request) { - $filter = $request->input('filter', 'all'); - $patients = $this->userPatients()->get(); - // 筛选需要随访的患者 + // 只筛选本月需要随访的患者 $reminders = $patients->filter(function ($patient) { - return !$patient->isCompleted(); + return $patient->needsFollowUpThisMonth(); })->map(function ($patient) { - $nextDate = $patient->getNextFollowUpDate(); return [ 'patient' => $patient, - 'next_follow_up_date' => $nextDate, - 'next_follow_up_number' => $patient->getNextFollowUpNumber(), - 'status' => $patient->getFollowUpStatus(), - 'days_until' => $nextDate ? Carbon::today()->diffInDays($nextDate, false) : null, + 'follow_up_date' => $patient->getCurrentMonthFollowUpDate(), + 'follow_up_number' => $patient->getCurrentMonthFollowUpNumber(), ]; - })->sortBy('days_until'); - - // 根据筛选条件过滤 - if ($filter === 'overdue') { - $reminders = $reminders->filter(fn($r) => $r['days_until'] !== null && $r['days_until'] < 0); - } elseif ($filter === 'today') { - $reminders = $reminders->filter(fn($r) => $r['days_until'] === 0); - } elseif ($filter === 'upcoming') { - $reminders = $reminders->filter(fn($r) => $r['days_until'] !== null && $r['days_until'] > 0 && $r['days_until'] <= 7); - } + })->sortBy(function ($r) { + return $r['follow_up_date']; + }); // 使用 xlswriter 生成 Excel 文件 $config = ['path' => sys_get_temp_dir()]; - $filename = '随访提醒_' . date('Y-m-d_His') . '.xlsx'; + $filename = '本月随访_' . date('Y-m') . '.xlsx'; $excel = new \Vtiful\Kernel\Excel($config); // 创建文件并设置表头 $fileHandle = $excel->fileName($filename) - ->header(['姓名', '性别', '年龄', '出院诊断', '转诊时间', '下次随访日期', '第几次随访', '状态', '户籍地址', '联系方式', '备注']); + ->header(['姓名', '性别', '年龄', '出院诊断', '转诊时间', '随访日期', '第几次随访', '户籍地址', '联系方式', '备注']); // 设置表头样式 $headerStyle = $fileHandle->getHandle(); @@ -415,9 +382,8 @@ class PatientController extends Controller $p->age, $p->diagnosis, $p->discharge_date->format('Y-m-d'), - $reminder['next_follow_up_date']?->format('Y-m-d') ?? '', - '第' . $reminder['next_follow_up_number'] . '次', - $reminder['status'], + $reminder['follow_up_date']?->format('Y-m-d') ?? '', + '第' . $reminder['follow_up_number'] . '次', $p->address ?? '', $p->phone ?? '', $p->remark ?? '', diff --git a/app/Models/Patient.php b/app/Models/Patient.php index aa7e6fb..f7e92e1 100644 --- a/app/Models/Patient.php +++ b/app/Models/Patient.php @@ -53,66 +53,74 @@ class Patient extends Model } /** - * 获取下次随访日期 + * 自动计算已完成的随访次数(过期的月份自动算已完成) */ - public function getNextFollowUpDate(): ?Carbon + public function getAutoFollowUpCount(): int { $schedule = $this->getFollowUpSchedule(); - $nextIndex = $this->follow_up_count; + $currentMonth = Carbon::now()->startOfMonth(); + $completed = 0; - if ($nextIndex >= count($schedule)) { - return null; // 已完成所有随访 + foreach ($schedule as $months) { + $followUpDate = $this->discharge_date->copy()->addMonths($months); + // 如果随访日期的月份早于当前月份,则算作已完成 + if ($followUpDate->startOfMonth()->lt($currentMonth)) { + $completed++; + } else { + break; + } } - $months = $schedule[$nextIndex]; - return $this->discharge_date->copy()->addMonths($months); + return $completed; } /** - * 获取下次随访是第几次 + * 获取当月需要随访的日期(如果有的话) */ - public function getNextFollowUpNumber(): int + public function getCurrentMonthFollowUpDate(): ?Carbon { - return $this->follow_up_count + 1; + $schedule = $this->getFollowUpSchedule(); + $currentMonth = Carbon::now(); + $monthStart = $currentMonth->copy()->startOfMonth(); + $monthEnd = $currentMonth->copy()->endOfMonth(); + + foreach ($schedule as $index => $months) { + $followUpDate = $this->discharge_date->copy()->addMonths($months); + // 如果随访日期在当月内 + if ($followUpDate->gte($monthStart) && $followUpDate->lte($monthEnd)) { + return $followUpDate; + } + } + + return null; } /** - * 检查是否需要随访(到期或已过期) + * 获取当月随访是第几次 */ - public function needsFollowUp(): bool + public function getCurrentMonthFollowUpNumber(): ?int { - $nextDate = $this->getNextFollowUpDate(); + $schedule = $this->getFollowUpSchedule(); + $currentMonth = Carbon::now(); + $monthStart = $currentMonth->copy()->startOfMonth(); + $monthEnd = $currentMonth->copy()->endOfMonth(); - if (!$nextDate) { - return false; + foreach ($schedule as $index => $months) { + $followUpDate = $this->discharge_date->copy()->addMonths($months); + if ($followUpDate->gte($monthStart) && $followUpDate->lte($monthEnd)) { + return $index + 1; + } } - return $nextDate->lte(Carbon::today()); + return null; } /** - * 获取随访状态 + * 检查当月是否需要随访 */ - public function getFollowUpStatus(): string + public function needsFollowUpThisMonth(): bool { - $nextDate = $this->getNextFollowUpDate(); - - if (!$nextDate) { - return '已完成'; - } - - $today = Carbon::today(); - $diff = $today->diffInDays($nextDate, false); - - if ($diff < 0) { - return '已过期 ' . abs($diff) . ' 天'; - } elseif ($diff == 0) { - return '今日到期'; - } elseif ($diff <= 7) { - return '即将到期(' . $diff . '天后)'; - } else { - return '未到期'; - } + return $this->getCurrentMonthFollowUpDate() !== null; } /** @@ -120,7 +128,7 @@ class Patient extends Model */ public function isCompleted(): bool { - return $this->follow_up_count >= count($this->getFollowUpSchedule()); + return $this->getAutoFollowUpCount() >= count($this->getFollowUpSchedule()); } /** diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index 683b167..756fd17 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -1113,7 +1113,31 @@ .reminder-actions { display: flex; gap: 10px; - justify-content: flex-end; + margin-top: 16px; + padding-top: 16px; + border-top: 1px solid var(--color-border-light); + } + + .call-btn { + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + width: 100%; + padding: 12px 16px; + background: linear-gradient(135deg, var(--color-success), #34d399); + color: white; + border: none; + border-radius: 10px; + font-size: 14px; + font-weight: 600; + text-decoration: none; + transition: all 0.2s; + } + + .call-btn:hover { + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(16, 185, 129, 0.4); } .action-form { @@ -1778,12 +1802,12 @@ 随访提醒 @php - $overdueCount = \App\Models\Patient::where('user_id', Auth::id())->get()->filter(function($p) { - return !$p->isCompleted() && $p->getNextFollowUpDate()?->lt(\Carbon\Carbon::today()); + $monthCount = \App\Models\Patient::where('user_id', Auth::id())->get()->filter(function($p) { + return $p->needsFollowUpThisMonth(); })->count(); @endphp - @if($overdueCount > 0) - {{ $overdueCount }} + @if($monthCount > 0) + {{ $monthCount }} @endif diff --git a/resources/views/patients/index.blade.php b/resources/views/patients/index.blade.php index 71b8235..54127cd 100644 --- a/resources/views/patients/index.blade.php +++ b/resources/views/patients/index.blade.php @@ -600,7 +600,6 @@ 诊断 转诊日期 随访进度 - 状态 联系方式 备注 操作 @@ -610,8 +609,7 @@ @foreach($patients as $patient) @php $total = count($patient->getFollowUpSchedule()); - $completed = $patient->follow_up_count; - $status = $patient->getFollowUpStatus(); + $completed = $patient->getAutoFollowUpCount(); @endphp @@ -637,17 +635,6 @@ {{ $completed }}/{{ $total }} - - @if($patient->isCompleted()) - 已完成 - @elseif(str_contains($status, '过期')) - {{ $status }} - @elseif(str_contains($status, '今日')) - {{ $status }} - @else - {{ $status }} - @endif - @if($patient->phone) {{ $patient->phone }} @@ -671,16 +658,6 @@ @endif - @if(!$patient->isCompleted()) -
- @csrf - -
- @endif
@csrf @method('DELETE') @@ -705,8 +682,7 @@ @foreach($patients as $patient) @php $total = count($patient->getFollowUpSchedule()); - $completed = $patient->follow_up_count; - $status = $patient->getFollowUpStatus(); + $completed = $patient->getAutoFollowUpCount(); @endphp
@@ -719,15 +695,7 @@
{{ $patient->gender }} · {{ $patient->age }}岁 · {{ $patient->getDiagnosisType() }}
- @if($patient->isCompleted()) - 已完成 - @elseif(str_contains($status, '过期')) - {{ $status }} - @elseif(str_contains($status, '今日')) - {{ $status }} - @else - {{ $status }} - @endif + {{ $completed }}/{{ $total }}
@@ -780,19 +748,6 @@
@endif - @if(!$patient->isCompleted()) - - @csrf - - - @else -
- @endif
@csrf diff --git a/resources/views/patients/reminders.blade.php b/resources/views/patients/reminders.blade.php index 7acbcdc..461c4f8 100644 --- a/resources/views/patients/reminders.blade.php +++ b/resources/views/patients/reminders.blade.php @@ -4,35 +4,27 @@ @section('content') - +
@else - +
@foreach($reminders as $reminder) @php $patient = $reminder['patient']; - $nextDate = $reminder['next_follow_up_date']; - $daysUntil = $reminder['days_until']; + $followUpDate = $reminder['follow_up_date']; + $followUpNumber = $reminder['follow_up_number']; @endphp
{{-- 卡片头部 --}}
-
{{ mb_substr($patient->name, 0, 1) }}
+
{{ mb_substr($patient->name, 0, 1) }}
{{ $patient->name }}
{{ $patient->gender }} · {{ $patient->age }}岁
- @if($daysUntil !== null && $daysUntil < 0) - 过期 {{ abs($daysUntil) }} 天 - @elseif($daysUntil === 0) - 今日到期 - @elseif($daysUntil !== null && $daysUntil <= 7) - {{ $daysUntil }} 天后 - @else - 未到期 - @endif + 第{{ $followUpNumber }}次
{{-- 诊断标签 --}}
{{ $patient->getDiagnosisType() }} -
{{-- 关键信息 --}}
+
+ 🏥 + 转诊日期 + {{ $patient->discharge_date->format('Y-m-d') }} +
📅 随访日期 - {{ $nextDate ? $nextDate->format('Y-m-d') : '-' }} + {{ $followUpDate->format('Y-m-d') }}
📞 联系方式 - {{ $patient->phone ?: '-' }} + + @if($patient->phone) + {{ $patient->phone }} + @else + - + @endif +
📍 @@ -111,7 +102,7 @@ {{ $patient->address ?: '-' }}
@if($patient->remark) -
+
📝 备注 {{ $patient->remark }} @@ -119,41 +110,17 @@ @endif
- {{-- 进度条 --}} -
- @php - $total = count($patient->getFollowUpSchedule()); - $completed = $patient->follow_up_count; - $percent = ($completed / $total) * 100; - @endphp -
- 随访进度 - {{ $completed }}/{{ $total }} -
-
-
-
-
- - {{-- 操作按钮 --}} + {{-- 拨打电话按钮 --}} + @if($patient->phone)
- @if($patient->phone) - - - - - - @endif - - @csrf - - + + + + + 拨打电话 +
+ @endif
@endforeach