This commit is contained in:
2025-12-13 14:46:19 +08:00
parent 4b1564e30f
commit 7bdbf18a3b

View File

@@ -0,0 +1,333 @@
import React, { useState } from 'react';
import { Plus, Edit2, Trash2, X, Clock, AlertCircle } from 'lucide-react';
interface Medication {
id: string;
name: string;
dosage: string;
route: string;
times: string[];
withFood: boolean;
gracePeriod: number;
active: boolean;
}
/**
* 家属端用药计划界面
* 管理老人的用药提醒
*/
export const MedicationPlan: React.FC = () => {
const [showForm, setShowForm] = useState(false);
const [editingMed, setEditingMed] = useState<Medication | null>(null);
// 模拟数据
const medications: Medication[] = [
{
id: '1',
name: '氯沙坦',
dosage: '50mg',
route: '口服',
times: ['08:00', '20:00'],
withFood: true,
gracePeriod: 30,
active: true,
},
{
id: '2',
name: '二甲双胍',
dosage: '500mg',
route: '口服',
times: ['08:00', '12:00', '18:00'],
withFood: true,
gracePeriod: 30,
active: true,
},
{
id: '3',
name: '阿司匹林',
dosage: '100mg',
route: '口服',
times: ['21:00'],
withFood: false,
gracePeriod: 60,
active: true,
},
];
const handleEdit = (med: Medication) => {
setEditingMed(med);
setShowForm(true);
};
const handleDelete = (medId: string) => {
if (confirm('确定要删除这个用药计划吗?')) {
console.log('Delete medication:', medId);
}
};
return (
<div className="min-h-screen bg-gray-50">
{/* 顶部导航 */}
<div className="bg-white border-b">
<div className="max-w-7xl mx-auto px-6 py-4">
<div className="flex items-center justify-between">
<h1 className="text-2xl font-bold text-gray-900"></h1>
<button
onClick={() => {
setEditingMed(null);
setShowForm(true);
}}
className="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors flex items-center gap-2"
>
<Plus size={18} />
</button>
</div>
</div>
</div>
{/* 主要内容区 */}
<div className="max-w-7xl mx-auto px-6 py-8">
{/* 用药列表 */}
<div className="card p-0 overflow-hidden">
<table className="w-full">
<thead className="bg-gray-50 border-b">
<tr>
<th className="px-6 py-4 text-left text-sm font-semibold text-gray-900">
</th>
<th className="px-6 py-4 text-left text-sm font-semibold text-gray-900">
/
</th>
<th className="px-6 py-4 text-left text-sm font-semibold text-gray-900">
</th>
<th className="px-6 py-4 text-left text-sm font-semibold text-gray-900">
</th>
<th className="px-6 py-4 text-left text-sm font-semibold text-gray-900">
</th>
<th className="px-6 py-4 text-right text-sm font-semibold text-gray-900">
</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200">
{medications.map((med) => (
<tr key={med.id} className="hover:bg-gray-50">
<td className="px-6 py-4">
<div className="font-medium text-gray-900">{med.name}</div>
</td>
<td className="px-6 py-4">
<div className="text-sm text-gray-700">
{med.dosage} · {med.route}
</div>
</td>
<td className="px-6 py-4">
<div className="flex flex-wrap gap-2">
{med.times.map((time, index) => (
<span
key={index}
className="px-2 py-1 bg-blue-50 text-blue-700 text-sm rounded flex items-center gap-1"
>
<Clock size={14} />
{time}
</span>
))}
</div>
</td>
<td className="px-6 py-4">
<div className="space-y-1">
{med.withFood && (
<div className="text-sm text-gray-600"></div>
)}
<div className="text-sm text-gray-500">
{med.gracePeriod}
</div>
</div>
</td>
<td className="px-6 py-4">
<span
className={`px-3 py-1 rounded-full text-sm font-medium ${
med.active
? 'bg-green-100 text-green-700'
: 'bg-gray-100 text-gray-700'
}`}
>
{med.active ? '启用中' : '已暂停'}
</span>
</td>
<td className="px-6 py-4 text-right">
<div className="flex items-center justify-end gap-2">
<button
onClick={() => handleEdit(med)}
className="p-2 text-gray-600 hover:text-primary-600 hover:bg-gray-100 rounded-lg transition-colors"
aria-label="编辑"
>
<Edit2 size={18} />
</button>
<button
onClick={() => handleDelete(med.id)}
className="p-2 text-gray-600 hover:text-red-600 hover:bg-gray-100 rounded-lg transition-colors"
aria-label="删除"
>
<Trash2 size={18} />
</button>
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
{/* 提示信息 */}
<div className="mt-6 bg-blue-50 border-l-4 border-blue-400 p-4 rounded-lg">
<div className="flex items-start">
<AlertCircle className="text-blue-600 mt-0.5 mr-3 flex-shrink-0" size={20} />
<div className="text-sm text-blue-800">
<p className="font-medium mb-1"></p>
<ul className="list-disc list-inside space-y-1 text-blue-700">
<li></li>
<li></li>
<li></li>
</ul>
</div>
</div>
</div>
</div>
{/* 编辑/添加表单抽屉 */}
{showForm && (
<div className="fixed inset-0 bg-black bg-opacity-50 z-50 flex justify-end animate-fade-in">
<div className="bg-white w-full max-w-2xl h-full overflow-y-auto">
<div className="sticky top-0 bg-white border-b p-6 flex items-center justify-between">
<h2 className="text-xl font-bold text-gray-900">
{editingMed ? '编辑用药' : '添加用药'}
</h2>
<button
onClick={() => setShowForm(false)}
className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
>
<X size={24} />
</button>
</div>
<div className="p-6 space-y-6">
{/* 药品名称 */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
<span className="text-red-500">*</span>
</label>
<input
type="text"
placeholder="例如:氯沙坦"
defaultValue={editingMed?.name}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent"
/>
</div>
{/* 剂量 */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
<span className="text-red-500">*</span>
</label>
<input
type="text"
placeholder="例如50mg"
defaultValue={editingMed?.dosage}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent"
/>
</div>
{/* 给药途径 */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
</label>
<select
defaultValue={editingMed?.route}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent"
>
<option></option>
<option></option>
<option></option>
</select>
</div>
{/* 服用时间 */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
<span className="text-red-500">*</span>
</label>
<div className="space-y-2">
{(editingMed?.times || ['08:00']).map((time, index) => (
<div key={index} className="flex items-center gap-2">
<input
type="time"
defaultValue={time}
className="flex-1 px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent"
/>
<button className="p-2 text-red-600 hover:bg-red-50 rounded-lg">
<X size={20} />
</button>
</div>
))}
<button className="text-sm text-primary-600 hover:text-primary-700 font-medium flex items-center gap-1">
<Plus size={16} />
</button>
</div>
</div>
{/* 随餐服用 */}
<div>
<label className="flex items-center gap-2 cursor-pointer">
<input
type="checkbox"
defaultChecked={editingMed?.withFood}
className="rounded"
/>
<span className="text-sm text-gray-700"></span>
</label>
</div>
{/* 宽限期 */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
</label>
<select
defaultValue={editingMed?.gracePeriod}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent"
>
<option value="15">15 </option>
<option value="30">30 </option>
<option value="60">60 </option>
<option value="120">120 </option>
</select>
<p className="mt-1 text-xs text-gray-500">
</p>
</div>
{/* 操作按钮 */}
<div className="flex gap-3 pt-6 border-t">
<button
onClick={() => setShowForm(false)}
className="flex-1 py-3 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
>
</button>
<button className="flex-1 py-3 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors font-medium">
</button>
</div>
</div>
</div>
</div>
)}
</div>
);
};