owned this note
owned this note
Published
Linked with GitHub
# NOTE系統門診記錄模式
這個畫面是在中間的文字編輯區,用右上角的switch來切換


這部分的格式參考 [NOTE前往做功課](/7gh_YzwBTq-1OjYDmppMOw)
## Claude Artifact
https://claude.site/artifacts/8dd98691-4132-4db0-9d0c-47cd2748ca5a
## Source Code
```javascript
import React, { useState, useEffect } from 'react';
import {
Calendar,
ChevronRight,
Check,
Edit2,
AlertTriangle
} from 'lucide-react';
const MedicalRecordEditor = () => {
const [isClinicMode, setIsClinicMode] = useState(false);
const [step, setStep] = useState(1);
const [selectedFilter, setSelectedFilter] = useState('week');
const [selectedRecord, setSelectedRecord] = useState(null);
const [showSnackbar, setShowSnackbar] = useState(false);
const [showImportDialog, setShowImportDialog] = useState(false);
const [showExitDialog, setShowExitDialog] = useState(false);
const [showMyClinicOnly, setShowMyClinicOnly] = useState(true);
const [showSameDepartment, setShowSameDepartment] = useState(false);
const [showAccessWarning, setShowAccessWarning] = useState(false);
const [pendingRecord, setPendingRecord] = useState(null);
useEffect(() => {
const handleBeforeUnload = (e) => {
if (step === 2) {
e.preventDefault();
e.returnValue = '';
}
};
window.addEventListener('beforeunload', handleBeforeUnload);
return () => window.removeEventListener('beforeunload', handleBeforeUnload);
}, [step]);
const currentDoctor = "陳小鵬";
const statusStyles = {
'未做功課': 'text-gray-600 bg-gray-100',
'已做功課': 'text-blue-600 bg-blue-100',
'病歷未完成': 'text-red-600 bg-red-100',
'病歷完成': 'text-green-600 bg-green-100'
};
const clinicRecords = [
// 陳小鵬的門診記錄
{ date: '2024-11-18', session: '上午', doctor: '陳小鵬', department: '內科', status: '病歷完成' },
{ date: '2024-11-16', session: '下午', doctor: '陳小鵬', department: '內科', status: '病歷未完成' },
{ date: '2024-11-15', session: '上午', doctor: '陳小鵬', department: '內科', status: '已做功課' },
{ date: '2024-11-14', session: '下午', doctor: '陳小鵬', department: '內科', status: '未做功課' },
{ date: '2024-11-13', session: '上午', doctor: '陳小鵬', department: '內科', status: '病歷完成' },
// 其他醫師的門診記錄
{ date: '2024-11-17', session: '上午', doctor: '陳大鵬', department: '內科', status: '病歷完成' },
{ date: '2024-11-17', session: '下午', doctor: '陳中鵬', department: '外科', status: '病歷未完成' },
{ date: '2024-11-16', session: '上午', doctor: '陳大鵬', department: '內科', status: '已做功課' },
{ date: '2024-11-15', session: '下午', doctor: '陳中鵬', department: '外科', status: '未做功課' },
];
const filteredRecords = clinicRecords.filter(record => {
if (showMyClinicOnly && record.doctor !== currentDoctor) return false;
if (showSameDepartment && record.department !== '內科') return false;
return true;
});
const handleRecordSelect = (record) => {
if (record.doctor !== currentDoctor) {
setPendingRecord(record);
setShowAccessWarning(true);
} else {
proceedToRecord(record);
}
};
const proceedToRecord = (record) => {
setSelectedRecord(record);
setStep(2);
setShowSnackbar(true);
setTimeout(() => setShowSnackbar(false), 3000);
setPendingRecord(null);
setShowAccessWarning(false);
};
const handleBack = () => {
setShowExitDialog(true);
};
const confirmExit = () => {
setStep(1);
setShowExitDialog(false);
};
const handleImport = () => {
setShowImportDialog(true);
};
return (
<div className="w-full max-w-4xl mx-auto p-4">
<div className="flex items-center justify-between mb-6">
<h2 className="text-2xl font-bold">病人: 王大明</h2>
<div className="flex items-center gap-2">
<span>門診紀錄模式</span>
<button
className={`
w-14 h-7 rounded-full p-1 transition-colors duration-200 ease-in-out
${isClinicMode ? 'bg-blue-600' : 'bg-gray-200'}
`}
onClick={() => setIsClinicMode(!isClinicMode)}
>
<div
className={`
bg-white h-5 w-5 rounded-full shadow-md transform transition-transform duration-200 ease-in-out
${isClinicMode ? 'translate-x-7' : 'translate-x-0'}
`}
/>
</button>
</div>
</div>
{isClinicMode && (
<div className="space-y-4">
<nav className="flex mb-4">
<button
onClick={step === 2 ? handleBack : undefined}
className="text-blue-600 hover:text-blue-800"
>
選擇門診記錄
</button>
{step === 2 && selectedRecord && (
<>
<ChevronRight className="h-4 w-4 mx-2 mt-1" />
<span>編輯記錄 - {selectedRecord.date} {selectedRecord.session} {selectedRecord.doctor}</span>
</>
)}
</nav>
{step === 1 && (
<div className="space-y-4">
<div className="flex gap-4">
<select
value={selectedFilter}
onChange={(e) => setSelectedFilter(e.target.value)}
className="border rounded-md px-3 py-2 bg-white hover:bg-gray-50 transition-colors"
>
<option value="week">一週內</option>
<option value="month">一月內</option>
<option value="year">一年內</option>
<option value="all">全部</option>
</select>
<button
className={`px-4 py-2 border rounded-md transition-colors ${
showSameDepartment ? 'bg-blue-100 border-blue-300' : 'hover:bg-gray-50'
}`}
onClick={() => setShowSameDepartment(!showSameDepartment)}
>
同科別
</button>
<button
className={`px-4 py-2 border rounded-md transition-colors ${
showMyClinicOnly ? 'bg-blue-100 border-blue-300' : 'hover:bg-gray-50'
}`}
onClick={() => setShowMyClinicOnly(!showMyClinicOnly)}
>
我的門診
</button>
</div>
<div className="overflow-x-auto rounded-lg border">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-2 sm:px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
日期/時段
</th>
<th className="px-2 sm:px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
醫師
</th>
<th className="px-2 sm:px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
科別
</th>
<th className="px-2 sm:px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
病歷狀態
</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{filteredRecords.map((record, index) => (
<tr
key={index}
className="cursor-pointer transform transition-all duration-200 hover:bg-gray-50 hover:scale-[1.01] active:scale-[0.99] group"
onClick={() => handleRecordSelect(record)}
>
<td className="px-2 sm:px-4 py-2 whitespace-nowrap">
{record.date} {record.session}
</td>
<td className="px-2 sm:px-4 py-2 whitespace-nowrap">
{record.doctor}
</td>
<td className="px-2 sm:px-4 py-2 whitespace-nowrap">
{record.department}
</td>
<td className="px-2 sm:px-4 py-2 whitespace-nowrap relative">
<span className={`px-2 py-1 rounded-full text-sm ${statusStyles[record.status]}`}>
{record.status}
</span>
<div className="absolute top-1/2 -translate-y-1/2 right-2 opacity-0 group-hover:opacity-100 transition-opacity bg-blue-600 text-white px-2 py-1 rounded text-xs flex items-center gap-1">
<Edit2 className="h-3 w-3" />
編輯紀錄
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
{step === 2 && (
<div className="space-y-4">
<div className="flex justify-end">
<button
onClick={handleImport}
className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors"
>
帶入
</button>
</div>
<textarea
className="w-full h-64 p-4 border rounded-md"
placeholder="請輸入門診紀錄..."
/>
</div>
)}
</div>
)}
{!isClinicMode && (
<textarea
className="w-full h-64 p-4 border rounded-md"
placeholder="請輸入紀錄..."
/>
)}
{showSnackbar && (
<div className="fixed bottom-4 right-4">
<div className="bg-green-500 text-white px-4 py-2 rounded-md flex items-center gap-2 shadow-lg">
<Check className="h-4 w-4" />
已選擇門診記錄
</div>
</div>
)}
{showImportDialog && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center">
<div className="bg-white p-6 rounded-lg shadow-xl">
<h3 className="text-lg font-bold mb-4">確認帶入之前紀錄?</h3>
<div className="flex justify-end gap-2">
<button
className="px-4 py-2 border rounded-md hover:bg-gray-50 transition-colors"
onClick={() => setShowImportDialog(false)}
>
取消
</button>
<button
className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors"
onClick={() => setShowImportDialog(false)}
>
確認
</button>
</div>
</div>
</div>
)}
{showExitDialog && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center">
<div className="bg-white p-6 rounded-lg shadow-xl">
<h3 className="text-lg font-bold mb-4">確定要離開嗎?</h3>
<div className="flex justify-end gap-2">
<button
className="px-4 py-2 border rounded-md hover:bg-gray-50 transition-colors"
onClick={() => setShowExitDialog(false)}
>
取消
</button>
<button
className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors"
onClick={confirmExit}
>
確認
</button>
</div>
</div>
</div>
)}
{showAccessWarning && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center">
<div className="bg-white p-6 rounded-lg shadow-xl max-w-md">
<div className="flex items-center gap-3 mb-4">
<AlertTriangle className="h-6 w-6 text-yellow-500" />
<h3 className="text-lg font-bold">不是你的門診</h3>
</div>
<p className="mb-6 text-gray-600">
這是 {pendingRecord?.doctor} 的門診記錄,確定要進去編輯嗎?
</p>
<div className="flex justify-end gap-2">
<button
className="px-4 py-2 border rounded-md hover:bg-gray-50 transition-colors"
onClick={() => setShowAccessWarning(false)}
>
取消
</button>
<button
className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors"
onClick={() => proceedToRecord(pendingRecord)}
>
確認
</button>
</div>
</div>
</div>
)}
</div>
);
};
export default MedicalRecordEditor;
```