import { useState, useRef } from 'react'; import { View, Text } from '@tarojs/components'; import Taro, { useDidShow, useReachBottom } from '@tarojs/taro'; import { listConsultations, ConsultationSession } from '../../services/consultation'; import { notificationService } from '../../services/notification'; import Loading from '../../components/Loading'; import GuestGuard from '../../components/GuestGuard'; import { useAuthStore } from '../../stores/auth'; import './index.scss'; type MsgTab = 'consultation' | 'notification'; interface NotificationItem { id: string; title: string; desc: string; time: string; type: string; read?: boolean; } const NOTIFY_ICONS: Record = { appointment: { icon: '约', bg: '#F0DDD4', color: '#C4623A' }, alert: { icon: '警', bg: '#FFF3E0', color: '#C4873A' }, followup: { icon: '随', bg: '#E8F0E8', color: '#5B7A5E' }, points: { icon: '分', bg: '#F0DDD4', color: '#C4623A' }, report: { icon: '报', bg: '#E8F0E8', color: '#5B7A5E' }, }; export default function Messages() { const user = useAuthStore((s) => s.user); const [activeTab, setActiveTab] = useState('consultation'); const [sessions, setSessions] = useState([]); const [notifications, setNotifications] = useState([]); const [loading, setLoading] = useState(false); const [page, setPage] = useState(1); const [total, setTotal] = useState(0); const loadingRef = useRef(false); const loadData = async (tab: MsgTab, pageNum: number = 1, isRefresh = false) => { if (loadingRef.current) return; loadingRef.current = true; setLoading(true); try { if (tab === 'consultation') { const res = await listConsultations({ page: pageNum, page_size: 20 }); const list = res.data || []; if (isRefresh) { setSessions(list); } else { setSessions((prev) => [...prev, ...list]); } setTotal(res.total || 0); } else { const res = await notificationService.list<{ data: unknown[]; total?: number }>({ page: pageNum, page_size: 20 }); const list = (res as { data?: unknown[] })?.data || []; if (isRefresh) { setNotifications(list as NotificationItem[]); } else { setNotifications((prev) => [...prev, ...(list as NotificationItem[])]); } setTotal((res as { total?: number })?.total || 0); } setPage(pageNum); } catch { if (isRefresh) { if (tab === 'consultation') setSessions([]); else setNotifications([]); } } finally { setLoading(false); loadingRef.current = false; } }; useDidShow(() => { if (user) loadData(activeTab, 1, true); }); const handleTabChange = (tab: MsgTab) => { setActiveTab(tab); loadData(tab, 1, true); }; useReachBottom(() => { const currentList = activeTab === 'consultation' ? sessions : notifications; if (!loading && currentList.length < total) { loadData(activeTab, page + 1); } }); const formatTime = (dateStr: string | null) => { if (!dateStr) return ''; const d = new Date(dateStr); const now = new Date(); const diffMs = now.getTime() - d.getTime(); const diffMin = Math.floor(diffMs / 60000); if (diffMin < 60) return `${diffMin} 分钟前`; const diffHour = Math.floor(diffMin / 60); if (diffHour < 24) return `${diffHour} 小时前`; return dateStr.slice(0, 10); }; if (!user) { return ; } const unreadConsultCount = sessions.filter((s) => s.unread_count_patient > 0).length; return ( {/* 页头 */} 消息 {/* 分段控件 Tab */} handleTabChange('consultation')} > 咨询 {unreadConsultCount > 0 && ( {unreadConsultCount} )} handleTabChange('notification')} > 通知 {/* 咨询列表 */} {activeTab === 'consultation' && ( loading ? ( ) : sessions.length === 0 ? ( 暂无咨询消息 ) : ( {sessions.map((session) => { const doctorName = session.last_message?.slice(0, 1) || '医'; const hasUnread = session.unread_count_patient > 0; return ( Taro.navigateTo({ url: `/pages/consultation/detail/index?id=${session.id}` })} > {doctorName} {session.consultation_type === 'online' ? '在线咨询' : '门诊咨询'} {formatTime(session.last_message_at)} {session.last_message || session.subject || '暂无消息'} {hasUnread && ( {session.unread_count_patient > 99 ? '99+' : session.unread_count_patient} )} ); })} ) )} {/* 通知列表 */} {activeTab === 'notification' && ( loading ? ( ) : notifications.length === 0 ? ( 暂无新通知 ) : ( {notifications.map((n) => { const cfg = NOTIFY_ICONS[n.type] || NOTIFY_ICONS.report; const isUnread = !n.read; return ( {cfg.icon} {n.title} {n.time} {n.desc} {isUnread && } ); })} ) )} ); }