99 lines
3.0 KiB
TypeScript
99 lines
3.0 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { PageHeader } from '@/components/layout/PageHeader';
|
|
import { Card } from '@/components/common/Card';
|
|
import { Empty } from '@/components/common/Empty';
|
|
import { useNotificationStore } from '@/stores/notification.store';
|
|
import { formatRelative } from '@/utils/format';
|
|
import type { NotificationType, Notification } from '@/types';
|
|
import styles from './NotificationListPage.module.css';
|
|
|
|
const TYPE_TABS: { key: NotificationType | 'all'; label: string }[] = [
|
|
{ key: 'all', label: '全部' },
|
|
{ key: 'medication', label: '用药提醒' },
|
|
{ key: 'followup', label: '复查提醒' },
|
|
{ key: 'consultation', label: '问诊消息' },
|
|
{ key: 'system', label: '系统' },
|
|
];
|
|
|
|
function getNavPath(n: Notification): string | null {
|
|
switch (n.type) {
|
|
case 'consultation':
|
|
return '/services/consultation';
|
|
case 'medication':
|
|
return '/health/medications';
|
|
case 'followup':
|
|
return '/services/follow-ups';
|
|
case 'report':
|
|
return n.relatedId ? `/services/reports/${n.relatedId}` : '/services/reports';
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export function NotificationListPage() {
|
|
const navigate = useNavigate();
|
|
const { notifications, unreadCount, fetchNotifications, markRead, markAllRead } = useNotificationStore();
|
|
const [tab, setTab] = useState<NotificationType | 'all'>('all');
|
|
|
|
useEffect(() => {
|
|
fetchNotifications();
|
|
}, [fetchNotifications]);
|
|
|
|
const filtered = tab === 'all'
|
|
? notifications
|
|
: notifications.filter((n) => n.type === tab);
|
|
|
|
const handleClick = (n: Notification) => {
|
|
if (!n.isRead) markRead(n.id);
|
|
const path = getNavPath(n);
|
|
if (path) navigate(path);
|
|
};
|
|
|
|
return (
|
|
<div className="page--no-tab">
|
|
<PageHeader
|
|
title="消息通知"
|
|
rightAction={
|
|
unreadCount > 0 ? (
|
|
<button className={styles.markAllBtn} onClick={markAllRead}>
|
|
全部已读
|
|
</button>
|
|
) : undefined
|
|
}
|
|
/>
|
|
|
|
<div className={styles.tabs}>
|
|
{TYPE_TABS.map((t) => (
|
|
<button
|
|
key={t.key}
|
|
className={`${styles.tab} ${tab === t.key ? styles.tabActive : ''}`}
|
|
onClick={() => setTab(t.key)}
|
|
>
|
|
{t.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
{filtered.length === 0 ? (
|
|
<Empty icon="🔔" message="暂无通知" />
|
|
) : (
|
|
filtered.map((n) => (
|
|
<Card
|
|
key={n.id}
|
|
className={`${styles.notifCard} ${!n.isRead ? styles.unread : ''}`}
|
|
onClick={() => handleClick(n)}
|
|
>
|
|
<div className={styles.notifHeader}>
|
|
<span className={styles.notifTitle}>{n.title}</span>
|
|
{!n.isRead && <span className={styles.unreadDot} />}
|
|
</div>
|
|
<p className={styles.notifContent}>{n.content}</p>
|
|
<span className={styles.notifTime}>{formatRelative(n.createdAt)}</span>
|
|
</Card>
|
|
))
|
|
)}
|
|
</div>
|
|
);
|
|
}
|