reminder/resources/views/patients/index.blade.php
2026-01-12 12:42:48 +08:00

496 lines
21 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@extends('layouts.app')
@section('title', '患者列表 - 病例回访提醒系统')
@section('content')
<style>
/* 移动端卡片列表 */
.mobile-patient-list {
display: none;
}
.mobile-patient-card {
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: 12px;
padding: 16px;
margin-bottom: 12px;
}
.mobile-patient-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.mobile-patient-info {
display: flex;
align-items: center;
gap: 12px;
}
.mobile-patient-avatar {
width: 44px;
height: 44px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
font-size: 16px;
color: white;
flex-shrink: 0;
}
.mobile-patient-avatar.male {
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
}
.mobile-patient-avatar.female {
background: linear-gradient(135deg, #ec4899 0%, #f472b6 100%);
}
.mobile-patient-name {
font-weight: 600;
font-size: 16px;
color: var(--color-text);
margin-bottom: 2px;
}
.mobile-patient-meta {
font-size: 13px;
color: var(--color-text-secondary);
}
.mobile-patient-body {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
margin-bottom: 12px;
padding: 12px;
background: var(--color-bg);
border-radius: 8px;
}
.mobile-info-item {
display: flex;
flex-direction: column;
gap: 2px;
}
.mobile-info-label {
font-size: 11px;
color: var(--color-text-muted);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.mobile-info-value {
font-size: 13px;
color: var(--color-text);
font-weight: 500;
}
.mobile-info-value a {
color: var(--color-primary);
text-decoration: none;
}
.mobile-patient-progress {
margin-bottom: 12px;
}
.mobile-progress-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 6px;
}
.mobile-progress-label {
font-size: 12px;
color: var(--color-text-secondary);
}
.mobile-progress-value {
font-size: 12px;
font-weight: 600;
color: var(--color-text);
}
.mobile-progress-bar {
height: 6px;
background: var(--color-border);
border-radius: 3px;
overflow: hidden;
}
.mobile-progress-fill {
height: 100%;
background: linear-gradient(90deg, var(--color-success), #34d399);
border-radius: 3px;
transition: width 0.3s ease;
}
.mobile-patient-remark {
padding: 10px 12px;
background: var(--color-warning-light);
border-left: 3px solid var(--color-warning);
border-radius: 6px;
margin-bottom: 12px;
font-size: 13px;
color: var(--color-warning);
font-weight: 500;
}
.mobile-patient-actions {
display: flex;
gap: 10px;
}
.mobile-patient-actions .btn {
flex: 1;
justify-content: center;
padding: 10px 12px;
}
.mobile-patient-actions form {
flex: 1;
display: flex;
}
.mobile-patient-actions form .btn {
width: 100%;
}
/* 移动端显示控制 */
@media (max-width: 768px) {
.table-container {
display: none !important;
}
.mobile-patient-list {
display: block;
}
.custom-pagination {
flex-direction: column;
gap: 12px;
}
.pagination-info {
text-align: center;
font-size: 13px;
}
.pagination-links {
justify-content: center;
}
}
</style>
<div class="page-header">
<h1 class="page-title">患者列表</h1>
<p class="page-subtitle">管理所有患者信息,查看随访状态</p>
</div>
<div class="card">
<div class="card-header">
<div class="search-box">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="8"/>
<line x1="21" y1="21" x2="16.65" y2="16.65"/>
</svg>
<form action="{{ route('patients.index') }}" method="GET">
<input type="text" class="form-control" name="search" placeholder="搜索姓名、电话、地址..." value="{{ request('search') }}">
</form>
</div>
<div class="action-buttons">
<a href="{{ route('patients.import') }}" class="btn btn-primary">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="17 8 12 3 7 8"/>
<line x1="12" y1="3" x2="12" y2="15"/>
</svg>
导入数据
</a>
</div>
</div>
@if($patients->isEmpty())
<div class="empty-state">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
<circle cx="9" cy="7" r="4"/>
<path d="M23 21v-2a4 4 0 0 0-3-3.87"/>
<path d="M16 3.13a4 4 0 0 1 0 7.75"/>
</svg>
<div class="empty-state-title">暂无患者数据</div>
<p>请先导入患者数据,支持 Excel (.xlsx) CSV 格式</p>
<div style="margin-top: 20px;">
<a href="{{ route('patients.import') }}" class="btn btn-primary">导入患者数据</a>
</div>
</div>
@else
<!-- 桌面端表格 -->
<div class="table-container">
<table>
<thead>
<tr>
<th>姓名</th>
<th>性别</th>
<th>年龄</th>
<th>出院诊断</th>
<th>转诊日期</th>
<th>随访进度</th>
<th>状态</th>
<th>联系方式</th>
<th>备注</th>
<th>操作</th>
</tr>
</thead>
<tbody>
@foreach($patients as $patient)
<tr>
<td>
<strong>{{ $patient->name }}</strong>
</td>
<td>{{ $patient->gender }}</td>
<td>{{ $patient->age }}</td>
<td>{{ $patient->getDiagnosisType() }}</td>
<td>{{ $patient->discharge_date->format('Y-m-d') }}</td>
<td>
@php
$total = count($patient->getFollowUpSchedule());
$completed = $patient->follow_up_count;
@endphp
<div style="display: flex; align-items: center; gap: 8px;">
<div style="width: 60px; height: 6px; background: var(--color-border); border-radius: 3px; overflow: hidden;">
<div style="width: {{ ($completed / $total) * 100 }}%; height: 100%; background: var(--color-success); border-radius: 3px;"></div>
</div>
<span style="font-size: 13px; color: var(--color-text-secondary);">{{ $completed }}/{{ $total }}</span>
</div>
</td>
<td>
@php
$status = $patient->getFollowUpStatus();
$nextDate = $patient->getNextFollowUpDate();
@endphp
@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>
@elseif(str_contains($status, '即将'))
<span class="badge badge-info">{{ $status }}</span>
@else
<span class="badge badge-info">{{ $status }}</span>
@endif
</td>
<td>
@if($patient->phone)
<a href="tel:{{ $patient->phone }}" style="color: var(--color-primary); text-decoration: none;">
{{ $patient->phone }}
</a>
@else
<span style="color: var(--color-text-muted);">-</span>
@endif
</td>
<td>
@if($patient->remark)
<span style="color: var(--color-warning); font-weight: 500;">{{ $patient->remark }}</span>
@else
<span style="color: var(--color-text-muted);">-</span>
@endif
</td>
<td>
<div class="action-buttons">
@if(!$patient->isCompleted())
<form action="{{ route('patients.follow-up', $patient) }}" method="POST" style="display: inline;">
@csrf
<button type="submit" class="btn btn-outline btn-sm" onclick="return confirm('确认标记 {{ $patient->name }} 完成第{{ $patient->getNextFollowUpNumber() }}次随访?')">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14">
<polyline points="20 6 9 17 4 12"/>
</svg>
随访
</button>
</form>
@endif
<form action="{{ route('patients.destroy', $patient) }}" method="POST" style="display: inline;">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-outline btn-sm" style="color: var(--color-danger);" onclick="return confirm('确认删除患者 {{ $patient->name }}?此操作不可恢复。')">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14">
<polyline points="3 6 5 6 21 6"/>
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
</svg>
</button>
</form>
</div>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<!-- 移动端卡片列表 -->
<div class="mobile-patient-list">
@foreach($patients as $patient)
@php
$total = count($patient->getFollowUpSchedule());
$completed = $patient->follow_up_count;
$status = $patient->getFollowUpStatus();
@endphp
<div class="mobile-patient-card">
<div class="mobile-patient-header">
<div class="mobile-patient-info">
<div class="mobile-patient-avatar {{ $patient->gender == '女' ? 'female' : 'male' }}">
{{ mb_substr($patient->name, 0, 1) }}
</div>
<div>
<div class="mobile-patient-name">{{ $patient->name }}</div>
<div class="mobile-patient-meta">{{ $patient->gender }} · {{ $patient->age }}</div>
</div>
</div>
@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
</div>
<div class="mobile-patient-body">
<div class="mobile-info-item">
<span class="mobile-info-label">诊断</span>
<span class="mobile-info-value">{{ $patient->getDiagnosisType() }}</span>
</div>
<div class="mobile-info-item">
<span class="mobile-info-label">转诊日期</span>
<span class="mobile-info-value">{{ $patient->discharge_date->format('Y-m-d') }}</span>
</div>
<div class="mobile-info-item">
<span class="mobile-info-label">联系方式</span>
<span class="mobile-info-value">
@if($patient->phone)
<a href="tel:{{ $patient->phone }}">{{ $patient->phone }}</a>
@else
-
@endif
</span>
</div>
<div class="mobile-info-item">
<span class="mobile-info-label">地址</span>
<span class="mobile-info-value">{{ $patient->address ?: '-' }}</span>
</div>
</div>
@if($patient->remark)
<div class="mobile-patient-remark">
📝 {{ $patient->remark }}
</div>
@endif
<div class="mobile-patient-progress">
<div class="mobile-progress-header">
<span class="mobile-progress-label">随访进度</span>
<span class="mobile-progress-value">{{ $completed }}/{{ $total }}</span>
</div>
<div class="mobile-progress-bar">
<div class="mobile-progress-fill" style="width: {{ ($completed / $total) * 100 }}%"></div>
</div>
</div>
<div class="mobile-patient-actions">
@if($patient->phone)
<a href="tel:{{ $patient->phone }}" class="btn btn-outline btn-sm">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
<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>
拨打电话
</a>
@endif
@if(!$patient->isCompleted())
<form action="{{ route('patients.follow-up', $patient) }}" method="POST">
@csrf
<button type="submit" class="btn btn-primary btn-sm" onclick="return confirm('确认标记 {{ $patient->name }} 完成第{{ $patient->getNextFollowUpNumber() }}次随访?')">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
<polyline points="20 6 9 17 4 12"/>
</svg>
已随访
</button>
</form>
@endif
<form action="{{ route('patients.destroy', $patient) }}" method="POST">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-outline btn-sm" style="color: var(--color-danger); border-color: var(--color-danger);" onclick="return confirm('确认删除患者 {{ $patient->name }}')">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
<polyline points="3 6 5 6 21 6"/>
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
</svg>
</button>
</form>
</div>
</div>
@endforeach
</div>
<!-- 分页 -->
@if($patients->hasPages())
<div class="custom-pagination">
<div class="pagination-info">
显示 {{ $patients->firstItem() }} - {{ $patients->lastItem() }} 条,共 {{ $patients->total() }}
</div>
<div class="pagination-links">
{{-- 上一页 --}}
@if($patients->onFirstPage())
<span class="pagination-btn disabled">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
<polyline points="15 18 9 12 15 6"/>
</svg>
</span>
@else
<a href="{{ $patients->previousPageUrl() }}" class="pagination-btn">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
<polyline points="15 18 9 12 15 6"/>
</svg>
</a>
@endif
{{-- 页码 --}}
@foreach($patients->getUrlRange(1, $patients->lastPage()) as $page => $url)
@if($page == $patients->currentPage())
<span class="pagination-btn active">{{ $page }}</span>
@else
<a href="{{ $url }}" class="pagination-btn">{{ $page }}</a>
@endif
@endforeach
{{-- 下一页 --}}
@if($patients->hasMorePages())
<a href="{{ $patients->nextPageUrl() }}" class="pagination-btn">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
<polyline points="9 18 15 12 9 6"/>
</svg>
</a>
@else
<span class="pagination-btn disabled">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
<polyline points="9 18 15 12 9 6"/>
</svg>
</span>
@endif
</div>
</div>
@endif
@endif
</div>
@endsection