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.

This commit is contained in:
Ethanfly 2026-01-12 13:55:41 +08:00
parent ca4d1fa1a5
commit 0dd6529dcf
6 changed files with 149 additions and 230 deletions

View File

@ -11,11 +11,10 @@
- 🗑️ 删除患者记录 - 🗑️ 删除患者记录
### 随访提醒 ### 随访提醒
- ⏰ 智能计算随访日期出院后1周、1月、3月、6月 - ⏰ 智能计算随访日期出院后1、3、6、12个月
- 🔴 过期提醒 - 显示已过期未随访的患者 - 📅 本月提醒 - 只显示本月需要随访的患者列表
- 🟡 今日到期 - 当天需要随访的患者 - 📊 进度自动更新 - 过期月份自动算作已完成
- 🔵 即将到期 - 7天内需要随访的患者 - 📞 一键拨打电话进行回访
- ✅ 标记随访完成,自动计算下次随访时间
### 用户系统 ### 用户系统
- 👤 用户注册/登录 - 👤 用户注册/登录

View File

@ -46,54 +46,33 @@ class PatientController extends Controller
} }
/** /**
* 显示需要随访提醒的患者 * 显示需要随访提醒的患者(只显示当月需要随访的)
*/ */
public function reminders(Request $request) public function reminders(Request $request)
{ {
$patients = $this->userPatients()->get(); $patients = $this->userPatients()->get();
// 筛选需要随访的患者 // 筛选当月需要随访的患者
$reminders = $patients->filter(function ($patient) { $reminders = $patients->filter(function ($patient) {
return !$patient->isCompleted(); return $patient->needsFollowUpThisMonth();
})->map(function ($patient) { })->map(function ($patient) {
$nextDate = $patient->getNextFollowUpDate();
return [ return [
'patient' => $patient, 'patient' => $patient,
'next_follow_up_date' => $nextDate, 'follow_up_date' => $patient->getCurrentMonthFollowUpDate(),
'next_follow_up_number' => $patient->getNextFollowUpNumber(), 'follow_up_number' => $patient->getCurrentMonthFollowUpNumber(),
'status' => $patient->getFollowUpStatus(),
'needs_attention' => $patient->needsFollowUp(),
'days_until' => $nextDate ? Carbon::today()->diffInDays($nextDate, false) : null,
]; ];
})->sortBy('days_until'); })->sortBy(function ($r) {
return $r['follow_up_date'];
// 筛选类型 });
$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);
}
// 统计数据 // 统计数据
$stats = [ $stats = [
'total' => $this->userPatients()->count(), 'count' => $reminders->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(),
'completed' => $patients->filter(fn($p) => $p->isCompleted())->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) public function export(Request $request)
{ {
$filter = $request->input('filter', 'all');
$patients = $this->userPatients()->get(); $patients = $this->userPatients()->get();
// 筛选需要随访的患者 // 筛选本月需要随访的患者
$reminders = $patients->filter(function ($patient) { $reminders = $patients->filter(function ($patient) {
return !$patient->isCompleted(); return $patient->needsFollowUpThisMonth();
})->map(function ($patient) { })->map(function ($patient) {
$nextDate = $patient->getNextFollowUpDate();
return [ return [
'patient' => $patient, 'patient' => $patient,
'next_follow_up_date' => $nextDate, 'follow_up_date' => $patient->getCurrentMonthFollowUpDate(),
'next_follow_up_number' => $patient->getNextFollowUpNumber(), 'follow_up_number' => $patient->getCurrentMonthFollowUpNumber(),
'status' => $patient->getFollowUpStatus(),
'days_until' => $nextDate ? Carbon::today()->diffInDays($nextDate, false) : null,
]; ];
})->sortBy('days_until'); })->sortBy(function ($r) {
return $r['follow_up_date'];
// 根据筛选条件过滤 });
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);
}
// 使用 xlswriter 生成 Excel 文件 // 使用 xlswriter 生成 Excel 文件
$config = ['path' => sys_get_temp_dir()]; $config = ['path' => sys_get_temp_dir()];
$filename = '随访提醒_' . date('Y-m-d_His') . '.xlsx'; $filename = '本月随访_' . date('Y-m') . '.xlsx';
$excel = new \Vtiful\Kernel\Excel($config); $excel = new \Vtiful\Kernel\Excel($config);
// 创建文件并设置表头 // 创建文件并设置表头
$fileHandle = $excel->fileName($filename) $fileHandle = $excel->fileName($filename)
->header(['姓名', '性别', '年龄', '出院诊断', '转诊时间', '下次随访日期', '第几次随访', '状态', '户籍地址', '联系方式', '备注']); ->header(['姓名', '性别', '年龄', '出院诊断', '转诊时间', '随访日期', '第几次随访', '户籍地址', '联系方式', '备注']);
// 设置表头样式 // 设置表头样式
$headerStyle = $fileHandle->getHandle(); $headerStyle = $fileHandle->getHandle();
@ -415,9 +382,8 @@ class PatientController extends Controller
$p->age, $p->age,
$p->diagnosis, $p->diagnosis,
$p->discharge_date->format('Y-m-d'), $p->discharge_date->format('Y-m-d'),
$reminder['next_follow_up_date']?->format('Y-m-d') ?? '', $reminder['follow_up_date']?->format('Y-m-d') ?? '',
'第' . $reminder['next_follow_up_number'] . '次', '第' . $reminder['follow_up_number'] . '次',
$reminder['status'],
$p->address ?? '', $p->address ?? '',
$p->phone ?? '', $p->phone ?? '',
$p->remark ?? '', $p->remark ?? '',

View File

@ -53,66 +53,74 @@ class Patient extends Model
} }
/** /**
* 获取下次随访日期 * 自动计算已完成的随访次数(过期的月份自动算已完成)
*/ */
public function getNextFollowUpDate(): ?Carbon public function getAutoFollowUpCount(): int
{ {
$schedule = $this->getFollowUpSchedule(); $schedule = $this->getFollowUpSchedule();
$nextIndex = $this->follow_up_count; $currentMonth = Carbon::now()->startOfMonth();
$completed = 0;
if ($nextIndex >= count($schedule)) { foreach ($schedule as $months) {
return null; // 已完成所有随访 $followUpDate = $this->discharge_date->copy()->addMonths($months);
// 如果随访日期的月份早于当前月份,则算作已完成
if ($followUpDate->startOfMonth()->lt($currentMonth)) {
$completed++;
} else {
break;
}
} }
$months = $schedule[$nextIndex]; return $completed;
return $this->discharge_date->copy()->addMonths($months);
} }
/** /**
* 获取下次随访是第几次 * 获取当月需要随访的日期(如果有的话)
*/ */
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) { foreach ($schedule as $index => $months) {
return false; $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(); return $this->getCurrentMonthFollowUpDate() !== null;
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 '未到期';
}
} }
/** /**
@ -120,7 +128,7 @@ class Patient extends Model
*/ */
public function isCompleted(): bool public function isCompleted(): bool
{ {
return $this->follow_up_count >= count($this->getFollowUpSchedule()); return $this->getAutoFollowUpCount() >= count($this->getFollowUpSchedule());
} }
/** /**

View File

@ -1113,7 +1113,31 @@
.reminder-actions { .reminder-actions {
display: flex; display: flex;
gap: 10px; 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 { .action-form {
@ -1778,12 +1802,12 @@
</svg> </svg>
<span>随访提醒</span> <span>随访提醒</span>
@php @php
$overdueCount = \App\Models\Patient::where('user_id', Auth::id())->get()->filter(function($p) { $monthCount = \App\Models\Patient::where('user_id', Auth::id())->get()->filter(function($p) {
return !$p->isCompleted() && $p->getNextFollowUpDate()?->lt(\Carbon\Carbon::today()); return $p->needsFollowUpThisMonth();
})->count(); })->count();
@endphp @endphp
@if($overdueCount > 0) @if($monthCount > 0)
<span class="nav-badge">{{ $overdueCount }}</span> <span class="nav-badge">{{ $monthCount }}</span>
@endif @endif
</a> </a>

View File

@ -600,7 +600,6 @@
<th>诊断</th> <th>诊断</th>
<th>转诊日期</th> <th>转诊日期</th>
<th>随访进度</th> <th>随访进度</th>
<th>状态</th>
<th>联系方式</th> <th>联系方式</th>
<th>备注</th> <th>备注</th>
<th style="text-align: right;">操作</th> <th style="text-align: right;">操作</th>
@ -610,8 +609,7 @@
@foreach($patients as $patient) @foreach($patients as $patient)
@php @php
$total = count($patient->getFollowUpSchedule()); $total = count($patient->getFollowUpSchedule());
$completed = $patient->follow_up_count; $completed = $patient->getAutoFollowUpCount();
$status = $patient->getFollowUpStatus();
@endphp @endphp
<tr> <tr>
<td> <td>
@ -637,17 +635,6 @@
<span class="progress-text">{{ $completed }}/{{ $total }}</span> <span class="progress-text">{{ $completed }}/{{ $total }}</span>
</div> </div>
</td> </td>
<td>
@if($patient->isCompleted())
<span class="badge badge-success">已完成</span>
@elseif(str_contains($status, '过期'))
<span class="badge badge-danger">{{ $status }}</span>
@elseif(str_contains($status, '今日'))
<span class="badge badge-warning">{{ $status }}</span>
@else
<span class="badge badge-info">{{ $status }}</span>
@endif
</td>
<td> <td>
@if($patient->phone) @if($patient->phone)
<a href="tel:{{ $patient->phone }}" class="phone-link">{{ $patient->phone }}</a> <a href="tel:{{ $patient->phone }}" class="phone-link">{{ $patient->phone }}</a>
@ -671,16 +658,6 @@
</svg> </svg>
</a> </a>
@endif @endif
@if(!$patient->isCompleted())
<form action="{{ route('patients.follow-up', $patient) }}" method="POST" style="display: inline;">
@csrf
<button type="submit" class="btn-icon success" title="标记已随访" onclick="return confirm('确认标记 {{ $patient->name }} 完成第{{ $patient->getNextFollowUpNumber() }}次随访?')">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="20 6 9 17 4 12"/>
</svg>
</button>
</form>
@endif
<form action="{{ route('patients.destroy', $patient) }}" method="POST" style="display: inline;"> <form action="{{ route('patients.destroy', $patient) }}" method="POST" style="display: inline;">
@csrf @csrf
@method('DELETE') @method('DELETE')
@ -705,8 +682,7 @@
@foreach($patients as $patient) @foreach($patients as $patient)
@php @php
$total = count($patient->getFollowUpSchedule()); $total = count($patient->getFollowUpSchedule());
$completed = $patient->follow_up_count; $completed = $patient->getAutoFollowUpCount();
$status = $patient->getFollowUpStatus();
@endphp @endphp
<div class="mobile-patient-card"> <div class="mobile-patient-card">
<div class="mobile-patient-header"> <div class="mobile-patient-header">
@ -719,15 +695,7 @@
<div class="mobile-patient-meta">{{ $patient->gender }} · {{ $patient->age }} · {{ $patient->getDiagnosisType() }}</div> <div class="mobile-patient-meta">{{ $patient->gender }} · {{ $patient->age }} · {{ $patient->getDiagnosisType() }}</div>
</div> </div>
</div> </div>
@if($patient->isCompleted()) <span class="badge {{ $completed >= $total ? 'badge-success' : 'badge-info' }}">{{ $completed }}/{{ $total }}</span>
<span class="badge badge-success">已完成</span>
@elseif(str_contains($status, '过期'))
<span class="badge badge-danger">{{ $status }}</span>
@elseif(str_contains($status, '今日'))
<span class="badge badge-warning">{{ $status }}</span>
@else
<span class="badge badge-info">{{ $status }}</span>
@endif
</div> </div>
<div class="mobile-patient-body"> <div class="mobile-patient-body">
@ -780,19 +748,6 @@
<div></div> <div></div>
@endif @endif
@if(!$patient->isCompleted())
<form action="{{ route('patients.follow-up', $patient) }}" method="POST">
@csrf
<button type="submit" class="btn btn-primary" onclick="return confirm('确认标记 {{ $patient->name }} 完成第{{ $patient->getNextFollowUpNumber() }}次随访?')">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18">
<polyline points="20 6 9 17 4 12"/>
</svg>
已随访
</button>
</form>
@else
<div></div>
@endif
<form action="{{ route('patients.destroy', $patient) }}" method="POST"> <form action="{{ route('patients.destroy', $patient) }}" method="POST">
@csrf @csrf

View File

@ -4,35 +4,27 @@
@section('content') @section('content')
<div class="page-header"> <div class="page-header">
<h1 class="page-title">随访提醒</h1> <h1 class="page-title">本月随访</h1>
<p class="page-subtitle">查看需要随访的患者,及时完成回访工作</p> <p class="page-subtitle">{{ now()->format('Y年n月') }} 需要随访的患者</p>
</div> </div>
<!-- 统计筛选--> <!-- 统计-->
<div class="stats-filter-bar"> <div class="stats-filter-bar">
<div class="stats-filter-grid"> <div class="stats-filter-grid">
<a href="{{ route('patients.reminders', ['filter' => 'all']) }}" class="stats-filter-item {{ $filter === 'all' ? 'active' : '' }}"> <div class="stats-filter-item active">
<span class="sf-value">{{ $stats['total'] }}</span> <span class="sf-value">{{ $stats['count'] }}</span>
<span class="sf-label">全部</span> <span class="sf-label">本月待随访</span>
</a> </div>
<a href="{{ route('patients.reminders', ['filter' => 'overdue']) }}" class="stats-filter-item danger {{ $filter === 'overdue' ? 'active' : '' }}"> <div class="stats-filter-item success">
<span class="sf-value">{{ $stats['overdue'] }}</span>
<span class="sf-label">过期</span>
</a>
<a href="{{ route('patients.reminders', ['filter' => 'today']) }}" class="stats-filter-item warning {{ $filter === 'today' ? 'active' : '' }}">
<span class="sf-value">{{ $stats['today'] }}</span>
<span class="sf-label">今日</span>
</a>
<a href="{{ route('patients.reminders', ['filter' => 'upcoming']) }}" class="stats-filter-item info {{ $filter === 'upcoming' ? 'active' : '' }}">
<span class="sf-value">{{ $stats['upcoming'] }}</span>
<span class="sf-label">7天内</span>
</a>
<a href="{{ route('patients.reminders', ['filter' => 'completed']) }}" class="stats-filter-item success {{ $filter === 'completed' ? 'active' : '' }}">
<span class="sf-value">{{ $stats['completed'] }}</span> <span class="sf-value">{{ $stats['completed'] }}</span>
<span class="sf-label">完成</span> <span class="sf-label">已完成</span>
</a> </div>
<div class="stats-filter-item">
<span class="sf-value">{{ $stats['total'] }}</span>
<span class="sf-label">总患者</span>
</div>
</div> </div>
<a href="{{ route('patients.export', ['filter' => $filter]) }}" class="export-icon-btn" title="导出"> <a href="{{ route('patients.export') }}" class="export-icon-btn" title="导出">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/> <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="7 10 12 15 17 10"/> <polyline points="7 10 12 15 17 10"/>
@ -50,60 +42,59 @@
<line x1="9" y1="9" x2="9.01" y2="9"/> <line x1="9" y1="9" x2="9.01" y2="9"/>
<line x1="15" y1="9" x2="15.01" y2="9"/> <line x1="15" y1="9" x2="15.01" y2="9"/>
</svg> </svg>
<div class="empty-state-title">暂无需要随访的患者</div> <div class="empty-state-title">本月暂无需要随访的患者</div>
<p>当前筛选条件下没有需要随访的患者,您可以切换筛选条件或导入新的患者数据。</p> <p>太棒了!本月没有需要随访的患者</p>
<div style="margin-top: 20px;">
<a href="{{ route('patients.import') }}" class="btn btn-primary">导入患者数据</a>
</div>
</div> </div>
</div> </div>
@else @else
<!-- 提醒卡片列表 - 两列布局 --> <!-- 提醒卡片列表 -->
<div class="reminder-grid"> <div class="reminder-grid">
@foreach($reminders as $reminder) @foreach($reminders as $reminder)
@php @php
$patient = $reminder['patient']; $patient = $reminder['patient'];
$nextDate = $reminder['next_follow_up_date']; $followUpDate = $reminder['follow_up_date'];
$daysUntil = $reminder['days_until']; $followUpNumber = $reminder['follow_up_number'];
@endphp @endphp
<div class="reminder-card fade-in"> <div class="reminder-card fade-in">
{{-- 卡片头部 --}} {{-- 卡片头部 --}}
<div class="reminder-card-header"> <div class="reminder-card-header">
<div class="reminder-patient-info"> <div class="reminder-patient-info">
<div class="reminder-avatar">{{ mb_substr($patient->name, 0, 1) }}</div> <div class="reminder-avatar {{ $patient->gender == '女' ? 'female' : 'male' }}">{{ mb_substr($patient->name, 0, 1) }}</div>
<div> <div>
<div class="reminder-name">{{ $patient->name }}</div> <div class="reminder-name">{{ $patient->name }}</div>
<div class="reminder-meta">{{ $patient->gender }} · {{ $patient->age }}</div> <div class="reminder-meta">{{ $patient->gender }} · {{ $patient->age }}</div>
</div> </div>
</div> </div>
@if($daysUntil !== null && $daysUntil < 0) <span class="badge badge-info">{{ $followUpNumber }}</span>
<span class="badge badge-danger">过期 {{ abs($daysUntil) }} </span>
@elseif($daysUntil === 0)
<span class="badge badge-warning">今日到期</span>
@elseif($daysUntil !== null && $daysUntil <= 7)
<span class="badge badge-info">{{ $daysUntil }} 天后</span>
@else
<span class="badge badge-success">未到期</span>
@endif
</div> </div>
{{-- 诊断标签 --}} {{-- 诊断标签 --}}
<div class="reminder-diagnosis"> <div class="reminder-diagnosis">
<span class="diagnosis-tag">{{ $patient->getDiagnosisType() }}</span> <span class="diagnosis-tag">{{ $patient->getDiagnosisType() }}</span>
<span class="follow-up-tag">{{ $reminder['next_follow_up_number'] }}次随访</span>
</div> </div>
{{-- 关键信息 --}} {{-- 关键信息 --}}
<div class="reminder-details"> <div class="reminder-details">
<div class="detail-row">
<span class="detail-icon">🏥</span>
<span class="detail-label">转诊日期</span>
<span class="detail-value">{{ $patient->discharge_date->format('Y-m-d') }}</span>
</div>
<div class="detail-row"> <div class="detail-row">
<span class="detail-icon">📅</span> <span class="detail-icon">📅</span>
<span class="detail-label">随访日期</span> <span class="detail-label">随访日期</span>
<span class="detail-value">{{ $nextDate ? $nextDate->format('Y-m-d') : '-' }}</span> <span class="detail-value">{{ $followUpDate->format('Y-m-d') }}</span>
</div> </div>
<div class="detail-row"> <div class="detail-row">
<span class="detail-icon">📞</span> <span class="detail-icon">📞</span>
<span class="detail-label">联系方式</span> <span class="detail-label">联系方式</span>
<span class="detail-value">{{ $patient->phone ?: '-' }}</span> <span class="detail-value">
@if($patient->phone)
<a href="tel:{{ $patient->phone }}" class="phone-link">{{ $patient->phone }}</a>
@else
-
@endif
</span>
</div> </div>
<div class="detail-row"> <div class="detail-row">
<span class="detail-icon">📍</span> <span class="detail-icon">📍</span>
@ -111,7 +102,7 @@
<span class="detail-value text-truncate">{{ $patient->address ?: '-' }}</span> <span class="detail-value text-truncate">{{ $patient->address ?: '-' }}</span>
</div> </div>
@if($patient->remark) @if($patient->remark)
<div class="detail-row"> <div class="detail-row remark-row">
<span class="detail-icon">📝</span> <span class="detail-icon">📝</span>
<span class="detail-label">备注</span> <span class="detail-label">备注</span>
<span class="detail-value remark-text">{{ $patient->remark }}</span> <span class="detail-value remark-text">{{ $patient->remark }}</span>
@ -119,41 +110,17 @@
@endif @endif
</div> </div>
{{-- 进度条 --}} {{-- 拨打电话按钮 --}}
<div class="reminder-progress"> @if($patient->phone)
@php
$total = count($patient->getFollowUpSchedule());
$completed = $patient->follow_up_count;
$percent = ($completed / $total) * 100;
@endphp
<div class="progress-header">
<span>随访进度</span>
<span>{{ $completed }}/{{ $total }}</span>
</div>
<div class="progress-track">
<div class="progress-fill" style="width: {{ $percent }}%"></div>
</div>
</div>
{{-- 操作按钮 --}}
<div class="reminder-actions"> <div class="reminder-actions">
@if($patient->phone) <a href="tel:{{ $patient->phone }}" class="call-btn">
<a href="tel:{{ $patient->phone }}" class="action-btn action-call" title="拨打电话"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18"> <path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"/>
<path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"/> </svg>
</svg> 拨打电话
</a> </a>
@endif
<form action="{{ route('patients.follow-up', $patient) }}" method="POST" class="action-form">
@csrf
<button type="submit" class="action-btn action-complete" title="标记已随访" onclick="return confirm('确认标记 {{ $patient->name }} 完成第{{ $reminder['next_follow_up_number'] }}次随访?')">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18">
<polyline points="20 6 9 17 4 12"/>
</svg>
<span>已随访</span>
</button>
</form>
</div> </div>
@endif
</div> </div>
@endforeach @endforeach
</div> </div>