feat: medication reminders, follow-up/visit separation, health record page
Backend: - MedicationService: today-summary with missed detection (local time) - FollowUpService: doctor-initiated follow-ups filter, AddAsync supports Notes - FollowUpController: type query param (followup/recheck) - MedicationController: today-summary endpoint - Auth: UpdateProfileRequest→class, StentDate/StentType, soft-delete fix Patient frontend: - HomePage: date display, medication reminder cards with missed status - MedicationListPage: beautified with delete button, slot preview - MedicationDetailPage: redesigned with progress bars, new CSS - ProfilePage: beautified menu icons, health record link - HealthRecordPage: new page with indicators, history, meds, reports - ServicesHub: added doctor-visit card - VisitListPage: doctor-initiated follow-ups view - EditProfilePage: removed height/weight, added stent fields - Fixed getProfile field mappings (nickname, height, weight, stent) Doctor frontend: - Layout: added 随访管理 sidebar item with SVG icon - FollowUpListPage: recheck-only filter, complete/delete buttons, collapsed completed - VisitListPage/EditPage: doctor follow-up management - PatientListPage: added stentType column - Dashboard: fixed pending reports endpoint - ReportListPage/DetailPage: fixed uploadedAt field - ChatPage: SignalR real-time, dynamic hostname
This commit is contained in:
@@ -41,6 +41,13 @@ const SIDEBAR_ICONS: Record<string, React.ReactNode> = {
|
||||
<line x1="3" y1="10" x2="21" y2="10" />
|
||||
</svg>
|
||||
),
|
||||
visits: (
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2" />
|
||||
<rect x="8" y="2" width="8" height="4" rx="1" ry="1" />
|
||||
<path d="M9 14l2 2 4-4" />
|
||||
</svg>
|
||||
),
|
||||
};
|
||||
|
||||
const navItems = [
|
||||
@@ -49,6 +56,7 @@ const navItems = [
|
||||
{ to: '/consultations', label: '在线问诊', ikey: 'consultations' },
|
||||
{ to: '/reports', label: '报告审核', ikey: 'reports' },
|
||||
{ to: '/follow-ups', label: '复查管理', ikey: 'followups' },
|
||||
{ to: '/visits', label: '随访管理', ikey: 'visits' },
|
||||
];
|
||||
|
||||
const sidebarStyles = {
|
||||
|
||||
@@ -45,7 +45,7 @@ export function FollowUpEditPage() {
|
||||
|
||||
return (
|
||||
<div style={{ padding: 28 }}>
|
||||
<h2 style={{ marginBottom: 20, fontSize: 20, fontWeight: 700, color: '#1A1D28' }}>{isNew ? '新建随访' : '编辑随访'}</h2>
|
||||
<h2 style={{ marginBottom: 20, fontSize: 20, fontWeight: 700, color: '#1A1D28' }}>{isNew ? '新建复查' : '编辑复查'}</h2>
|
||||
|
||||
<form onSubmit={handleSubmit} style={{ background: '#fff', padding: 28, borderRadius: 16, maxWidth: 520, boxShadow: '0 2px 12px rgba(0,0,0,0.04)' }}>
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
|
||||
@@ -9,41 +9,66 @@ interface RawFollowUpItem {
|
||||
|
||||
export function FollowUpListPage() {
|
||||
const [followUps, setFollowUps] = useState<RawFollowUpItem[]>([]);
|
||||
const [showCompleted, setShowCompleted] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
api.get<RawFollowUpItem[]>('/api/follow-ups').then((r) => setFollowUps(r.data)).catch(() => {});
|
||||
}, []);
|
||||
|
||||
const statusLabel = (s: string) => {
|
||||
switch (s) {
|
||||
case 'upcoming': return { text: '待随访', color: '#F59E0B', bg: '#FFF8E6' };
|
||||
case 'completed': return { text: '已完成', color: '#20C997', bg: '#E6F9F2' };
|
||||
case 'cancelled': return { text: '已取消', color: '#EF4444', bg: '#FEE9E9' };
|
||||
default: return { text: s, color: '#9BA0B4', bg: '#F5F6F9' };
|
||||
}
|
||||
const load = () => {
|
||||
api.get<RawFollowUpItem[]>('/api/follow-ups?type=recheck')
|
||||
.then((r) => setFollowUps(r.data)).catch(() => {});
|
||||
};
|
||||
|
||||
useEffect(() => { load(); }, []);
|
||||
|
||||
const handleComplete = async (e: React.MouseEvent, id: string) => {
|
||||
e.stopPropagation();
|
||||
try {
|
||||
await api.put(`/api/follow-ups/${id}`, { status: 'completed' });
|
||||
load();
|
||||
} catch { /* ignore */ }
|
||||
};
|
||||
|
||||
const handleDelete = async (e: React.MouseEvent, id: string) => {
|
||||
e.stopPropagation();
|
||||
if (!confirm('确定删除?')) return;
|
||||
try {
|
||||
await api.del(`/api/follow-ups/${id}`);
|
||||
load();
|
||||
} catch { /* ignore */ }
|
||||
};
|
||||
|
||||
const now = new Date();
|
||||
const statusLabel = (f: RawFollowUpItem) => {
|
||||
if (f.status === 'completed') return { text: '已完成', color: '#20C997', bg: '#E6F9F2' };
|
||||
if (f.status === 'cancelled') return { text: '已取消', color: '#EF4444', bg: '#FEE9E9' };
|
||||
if (f.scheduledAt && new Date(f.scheduledAt) < now) return { text: '已过期', color: '#EF4444', bg: '#FEE9E9' };
|
||||
return { text: '待复查', color: '#F59E0B', bg: '#FFF8E6' };
|
||||
};
|
||||
|
||||
const active = followUps.filter((f) => f.status !== 'completed');
|
||||
const completed = followUps.filter((f) => f.status === 'completed');
|
||||
const displayed = [...active, ...(showCompleted ? completed : [])];
|
||||
|
||||
return (
|
||||
<div style={{ padding: 28 }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 6 }}>
|
||||
<h2 style={{ fontSize: 20, fontWeight: 700, color: '#1A1D28', margin: 0 }}>随访管理</h2>
|
||||
<h2 style={{ fontSize: 20, fontWeight: 700, color: '#1A1D28', margin: 0 }}>复查管理</h2>
|
||||
<Link to="/follow-ups/new/edit" style={{
|
||||
padding: '10px 20px', background: 'linear-gradient(135deg, #4F6EF7 0%, #6C8AFF 100%)', color: '#fff',
|
||||
borderRadius: 10, textDecoration: 'none', fontSize: 13, fontWeight: 600,
|
||||
boxShadow: '0 4px 16px rgba(79,110,247,0.25)',
|
||||
}}>
|
||||
新建随访
|
||||
+ 新建复查
|
||||
</Link>
|
||||
</div>
|
||||
<p style={{ marginBottom: 18, fontSize: 13, color: '#9BA0B4' }}>共 {followUps.length} 条随访记录</p>
|
||||
<p style={{ marginBottom: 18, fontSize: 13, color: '#9BA0B4' }}>共 {followUps.length} 条复查记录</p>
|
||||
|
||||
<div style={{ background: '#fff', borderRadius: 16, boxShadow: '0 2px 12px rgba(0,0,0,0.04)', overflow: 'hidden' }}>
|
||||
{followUps.map((f) => {
|
||||
const s = statusLabel(f.status);
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
|
||||
{displayed.map((f) => {
|
||||
const s = statusLabel(f);
|
||||
return (
|
||||
<div key={f.id} style={{
|
||||
display: 'flex', justifyContent: 'space-between', alignItems: 'center',
|
||||
padding: '16px 22px', borderBottom: '1px solid #F5F6F9',
|
||||
padding: '16px 22px', background: '#fff', borderRadius: 14,
|
||||
boxShadow: '0 1px 4px rgba(0,0,0,0.04)', border: '1px solid #F0F2F5',
|
||||
}}>
|
||||
<div>
|
||||
<div style={{ fontSize: 14, fontWeight: 600, color: '#1A1D28' }}>{f.title}</div>
|
||||
@@ -51,22 +76,48 @@ export function FollowUpListPage() {
|
||||
{f.patientName || '未知'} · {f.scheduledAt?.split('T')[0]}
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<span style={{ padding: '4px 12px', borderRadius: 10, fontSize: 11, fontWeight: 500, background: s.bg, color: s.color }}>
|
||||
{s.text}
|
||||
</span>
|
||||
{f.status === 'upcoming' && (
|
||||
<button onClick={(e) => handleComplete(e, f.id)} style={{
|
||||
padding: '4px 10px', borderRadius: 6, fontSize: 11, fontWeight: 600,
|
||||
color: '#4F6EF7', background: '#EDF0FD', border: '1px solid #D0D5FD',
|
||||
cursor: 'pointer',
|
||||
}}>标记完成</button>
|
||||
)}
|
||||
<Link to={`/follow-ups/${f.id}/edit`} style={{
|
||||
color: '#4F6EF7', fontSize: 12, fontWeight: 600,
|
||||
padding: '4px 12px', background: '#EDF0FD', borderRadius: 6,
|
||||
padding: '4px 10px', background: '#EDF0FD', borderRadius: 6, textDecoration: 'none',
|
||||
}}>编辑</Link>
|
||||
<button onClick={(e) => handleDelete(e, f.id)} style={{
|
||||
width: 26, height: 26, borderRadius: 6, border: 'none',
|
||||
background: '#FEF2F2', color: '#EF4444', cursor: 'pointer',
|
||||
fontSize: 14, fontWeight: 700, display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||||
}} title="删除">×</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{followUps.length === 0 && (
|
||||
<div style={{ padding: 40, textAlign: 'center', color: '#9BA0B4', fontSize: 13 }}>暂无随访记录</div>
|
||||
<div style={{ padding: 40, textAlign: 'center', color: '#9BA0B4', fontSize: 13 }}>暂无复查记录</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{completed.length > 0 && (
|
||||
<button onClick={() => setShowCompleted(!showCompleted)} style={{
|
||||
display: 'flex', alignItems: 'center', gap: 6, margin: '12px auto 0',
|
||||
padding: '8px 20px', borderRadius: 20, border: '1px solid #E4E8EE',
|
||||
background: '#fff', color: '#9BA0B4', fontSize: 12, cursor: 'pointer',
|
||||
}}>
|
||||
{showCompleted ? '收起已完成' : `查看已完成 (${completed.length})`}
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"
|
||||
style={{ transform: showCompleted ? 'rotate(180deg)' : '' }}>
|
||||
<polyline points="6 9 12 15 18 9" />
|
||||
</svg>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
82
frontend-doctor/src/pages/followups/VisitEditPage.tsx
Normal file
82
frontend-doctor/src/pages/followups/VisitEditPage.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { api } from '../../services/api-client';
|
||||
|
||||
export function VisitEditPage() {
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const navigate = useNavigate();
|
||||
const isNew = !id || id === 'new';
|
||||
|
||||
const [title, setTitle] = useState('');
|
||||
const [patientId, setPatientId] = useState('');
|
||||
const [scheduledAt, setScheduledAt] = useState('');
|
||||
const [notes, setNotes] = useState('');
|
||||
const [patients, setPatients] = useState<{ id: string; name: string }[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
api.get<{ id: string; name: string }[]>('/api/patients').then((r) => setPatients(r.data));
|
||||
if (!isNew) {
|
||||
api.get<Record<string, unknown>>(`/api/follow-ups/${id}`).then((r) => {
|
||||
setTitle(r.data.title as string);
|
||||
setPatientId(r.data.patientId as string);
|
||||
setScheduledAt((r.data.scheduledAt as string)?.slice(0, 16) || '');
|
||||
setNotes((r.data.notes as string) || '');
|
||||
}).catch(() => {});
|
||||
}
|
||||
}, [id, isNew]);
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
try {
|
||||
if (isNew) {
|
||||
await api.post('/api/follow-ups', { title, patientId, scheduledAt, notes });
|
||||
} else {
|
||||
await api.put(`/api/follow-ups/${id}`, { title, patientId, scheduledAt, notes });
|
||||
}
|
||||
navigate('/visits');
|
||||
} catch { alert('操作失败'); }
|
||||
};
|
||||
|
||||
const inputStyle: React.CSSProperties = {
|
||||
width: '100%', padding: '10px 14px', border: '1.5px solid #E1E5ED',
|
||||
borderRadius: 10, fontSize: 13, outline: 'none', boxSizing: 'border-box',
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ padding: 28 }}>
|
||||
<h2 style={{ marginBottom: 20, fontSize: 20, fontWeight: 700, color: '#1A1D28' }}>
|
||||
{isNew ? '新建随访' : '编辑随访'}
|
||||
</h2>
|
||||
<form onSubmit={handleSubmit} style={{ background: '#fff', padding: 28, borderRadius: 16, maxWidth: 520, boxShadow: '0 2px 12px rgba(0,0,0,0.04)' }}>
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<label style={{ display: 'block', fontSize: 13, fontWeight: 500, color: '#5A6072', marginBottom: 5 }}>随访标题</label>
|
||||
<input value={title} onChange={(e) => setTitle(e.target.value)} required style={inputStyle}
|
||||
placeholder="如:PCI术后1个月随访" />
|
||||
</div>
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<label style={{ display: 'block', fontSize: 13, fontWeight: 500, color: '#5A6072', marginBottom: 5 }}>随访患者</label>
|
||||
<select value={patientId} onChange={(e) => setPatientId(e.target.value)} required style={inputStyle}>
|
||||
<option value="">请选择</option>
|
||||
{patients.map((p) => (<option key={p.id} value={p.id}>{p.name}</option>))}
|
||||
</select>
|
||||
</div>
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<label style={{ display: 'block', fontSize: 13, fontWeight: 500, color: '#5A6072', marginBottom: 5 }}>随访时间</label>
|
||||
<input type="datetime-local" value={scheduledAt} onChange={(e) => setScheduledAt(e.target.value)} required style={inputStyle} />
|
||||
</div>
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<label style={{ display: 'block', fontSize: 13, fontWeight: 500, color: '#5A6072', marginBottom: 5 }}>随访内容 / 备注</label>
|
||||
<textarea value={notes} onChange={(e) => setNotes(e.target.value)} rows={4}
|
||||
style={{ ...inputStyle, resize: 'vertical', fontFamily: 'inherit' }} placeholder="告知患者本次随访的目的、需要准备的材料等" />
|
||||
</div>
|
||||
<button type="submit" style={{
|
||||
padding: '11px 28px', background: 'linear-gradient(135deg, #4F6EF7 0%, #6C8AFF 100%)', color: '#fff',
|
||||
border: 'none', borderRadius: 10, fontSize: 14, fontWeight: 600,
|
||||
boxShadow: '0 4px 16px rgba(79,110,247,0.25)',
|
||||
}}>
|
||||
{isNew ? '创建随访' : '保存'}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
73
frontend-doctor/src/pages/followups/VisitListPage.tsx
Normal file
73
frontend-doctor/src/pages/followups/VisitListPage.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { api } from '../../services/api-client';
|
||||
|
||||
interface VisitItem {
|
||||
id: string; patientId: string; patientName: string;
|
||||
title: string; scheduledAt: string; status: string;
|
||||
}
|
||||
|
||||
export function VisitListPage() {
|
||||
const [visits, setVisits] = useState<VisitItem[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
api.get<VisitItem[]>('/api/follow-ups?type=followup')
|
||||
.then((r) => setVisits(r.data)).catch(() => {});
|
||||
}, []);
|
||||
|
||||
const statusLabel = (s: string) => {
|
||||
switch (s) {
|
||||
case 'upcoming': return { text: '待随访', color: '#F59E0B', bg: '#FFF8E6' };
|
||||
case 'completed': return { text: '已完成', color: '#20C997', bg: '#E6F9F2' };
|
||||
case 'cancelled': return { text: '已取消', color: '#EF4444', bg: '#FEE9E9' };
|
||||
default: return { text: s, color: '#9BA0B4', bg: '#F5F6F9' };
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ padding: 28 }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 6 }}>
|
||||
<h2 style={{ fontSize: 20, fontWeight: 700, color: '#1A1D28', margin: 0 }}>随访管理</h2>
|
||||
<Link to="/visits/new/edit" style={{
|
||||
padding: '10px 20px', background: 'linear-gradient(135deg, #4F6EF7 0%, #6C8AFF 100%)', color: '#fff',
|
||||
borderRadius: 10, textDecoration: 'none', fontSize: 13, fontWeight: 600,
|
||||
boxShadow: '0 4px 16px rgba(79,110,247,0.25)',
|
||||
}}>
|
||||
+ 新建随访
|
||||
</Link>
|
||||
</div>
|
||||
<p style={{ marginBottom: 18, fontSize: 13, color: '#9BA0B4' }}>共 {visits.length} 条随访计划</p>
|
||||
|
||||
<div style={{ background: '#fff', borderRadius: 16, boxShadow: '0 2px 12px rgba(0,0,0,0.04)', overflow: 'hidden' }}>
|
||||
{visits.map((v) => {
|
||||
const s = statusLabel(v.status);
|
||||
return (
|
||||
<div key={v.id} style={{
|
||||
display: 'flex', justifyContent: 'space-between', alignItems: 'center',
|
||||
padding: '16px 22px', borderBottom: '1px solid #F5F6F9',
|
||||
}}>
|
||||
<div>
|
||||
<div style={{ fontSize: 14, fontWeight: 600, color: '#1A1D28' }}>{v.title}</div>
|
||||
<div style={{ fontSize: 12, color: '#9BA0B4', marginTop: 3 }}>
|
||||
{v.patientName || '未知'} · {v.scheduledAt?.split('T')[0]}
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
|
||||
<span style={{ padding: '4px 12px', borderRadius: 10, fontSize: 11, fontWeight: 500, background: s.bg, color: s.color }}>
|
||||
{s.text}
|
||||
</span>
|
||||
<Link to={`/visits/${v.id}/edit`} style={{
|
||||
color: '#4F6EF7', fontSize: 12, fontWeight: 600,
|
||||
padding: '4px 12px', background: '#EDF0FD', borderRadius: 6,
|
||||
}}>详情</Link>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{visits.length === 0 && (
|
||||
<div style={{ padding: 40, textAlign: 'center', color: '#9BA0B4', fontSize: 13 }}>暂无随访计划</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import { api } from '../../services/api-client';
|
||||
|
||||
interface Patient {
|
||||
id: string; name: string; phone: string; gender: string;
|
||||
medicalHistory: string[]; stentDate: string;
|
||||
medicalHistory: string[]; stentDate: string; stentType: string;
|
||||
}
|
||||
|
||||
export function PatientListPage() {
|
||||
@@ -47,6 +47,7 @@ export function PatientListPage() {
|
||||
<th style={{ padding: '13px 20px', fontWeight: 600, color: '#5A6072' }}>性别</th>
|
||||
<th style={{ padding: '13px 20px', fontWeight: 600, color: '#5A6072' }}>病史</th>
|
||||
<th style={{ padding: '13px 20px', fontWeight: 600, color: '#5A6072' }}>支架日期</th>
|
||||
<th style={{ padding: '13px 20px', fontWeight: 600, color: '#5A6072' }}>支架类型</th>
|
||||
<th style={{ padding: '13px 20px', fontWeight: 600, color: '#5A6072' }}>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -58,6 +59,7 @@ export function PatientListPage() {
|
||||
<td style={{ padding: '12px 20px' }}>{p.gender || '-'}</td>
|
||||
<td style={{ padding: '12px 20px', color: '#5A6072' }}>{(p.medicalHistory || []).slice(0, 3).join('、') || '-'}</td>
|
||||
<td style={{ padding: '12px 20px', color: '#5A6072' }}>{p.stentDate || '-'}</td>
|
||||
<td style={{ padding: '12px 20px', color: '#5A6072' }}>{p.stentType || '-'}</td>
|
||||
<td style={{ padding: '12px 20px' }}>
|
||||
<Link to={`/patients/${p.id}`} style={{
|
||||
color: '#4F6EF7', fontSize: 12, fontWeight: 600,
|
||||
@@ -67,7 +69,7 @@ export function PatientListPage() {
|
||||
</tr>
|
||||
))}
|
||||
{filtered.length === 0 && (
|
||||
<tr><td colSpan={6} style={{ padding: 32, textAlign: 'center', color: '#9BA0B4' }}>暂无患者数据</td></tr>
|
||||
<tr><td colSpan={7} style={{ padding: 32, textAlign: 'center', color: '#9BA0B4' }}>暂无患者数据</td></tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -7,7 +7,7 @@ interface RawReport {
|
||||
imageUrls: string[]; status: string; riskLevel?: string;
|
||||
summary?: string; suggestions?: string;
|
||||
patientName?: string; doctorName?: string;
|
||||
createdAt: string; completedAt?: string;
|
||||
uploadedAt: string; completedAt?: string;
|
||||
items?: RawItem[];
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ export function ReportDetailPage() {
|
||||
<div style={{ marginTop: 8, fontSize: 13, color: '#888' }}>
|
||||
患者:{report.patientName || '未知'} |
|
||||
分类:{categoryMap[report.category] || report.category} |
|
||||
日期:{report.createdAt?.split('T')[0]}
|
||||
日期:{report.uploadedAt?.split('T')[0]}
|
||||
</div>
|
||||
</div>
|
||||
<span style={{
|
||||
|
||||
@@ -11,6 +11,8 @@ import { ReportListPage } from '../pages/reports/ReportListPage';
|
||||
import { ReportDetailPage } from '../pages/reports/ReportDetailPage';
|
||||
import { FollowUpListPage } from '../pages/followups/FollowUpListPage';
|
||||
import { FollowUpEditPage } from '../pages/followups/FollowUpEditPage';
|
||||
import { VisitListPage } from '../pages/followups/VisitListPage';
|
||||
import { VisitEditPage } from '../pages/followups/VisitEditPage';
|
||||
import { ProfilePage } from '../pages/settings/ProfilePage';
|
||||
|
||||
export const router = createBrowserRouter([
|
||||
@@ -35,6 +37,8 @@ export const router = createBrowserRouter([
|
||||
{ path: 'reports/:id', element: <ReportDetailPage /> },
|
||||
{ path: 'follow-ups', element: <FollowUpListPage /> },
|
||||
{ path: 'follow-ups/:id/edit', element: <FollowUpEditPage /> },
|
||||
{ path: 'visits', element: <VisitListPage /> },
|
||||
{ path: 'visits/:id/edit', element: <VisitEditPage /> },
|
||||
{ path: 'profile', element: <ProfilePage /> },
|
||||
],
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user