Add File
This commit is contained in:
333
src/family/pages/MedicationPlan.tsx
Normal file
333
src/family/pages/MedicationPlan.tsx
Normal 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>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user