新增 usePageData hook(useDidShow 节流 + usePullDownRefresh + loadingRef 防重入 + enabled 条件守卫), 44/58 页面迁移接入,消灭 4 种数据加载模式并存。 - 新增 hooks/usePageData.ts — 统一页面数据加载生命周期 - 新增 stores/index.ts — resetAllStores() 解耦 auth↔health store 依赖 - 新增 pages/index/useHomeData.ts — 首页数据 hook(424→282 行) - 新增 pages/health/useHealthData.ts — 健康页数据 hook(422→254 行) - 44 个页面迁移到 usePageData(9 患者端 + 15 医生端 + 20 子包) - auth store logout 不再直接导入 health store 构建通过,测试 74/75(1 个预存失败)。
133 lines
4.3 KiB
TypeScript
133 lines
4.3 KiB
TypeScript
import React, { useState, useCallback } from 'react';
|
|
import { View, Text } from '@tarojs/components';
|
|
import Taro from '@tarojs/taro';
|
|
import { usePageData } from '@/hooks/usePageData';
|
|
import { listPatientAlerts, type Alert } from '@/services/alert';
|
|
import { useAuthStore } from '@/stores/auth';
|
|
import Loading from '@/components/Loading';
|
|
import { useElderClass } from '../../../hooks/useElderClass';
|
|
import './index.scss';
|
|
|
|
const SEVERITY_MAP: Record<string, { label: string; className: string }> = {
|
|
info: { label: '提示', className: 'sev-info' },
|
|
warning: { label: '警告', className: 'sev-warning' },
|
|
critical: { label: '严重', className: 'sev-critical' },
|
|
urgent: { label: '紧急', className: 'sev-urgent' },
|
|
};
|
|
|
|
const STATUS_TABS = [
|
|
{ key: '', label: '全部' },
|
|
{ key: 'pending', label: '待处理' },
|
|
{ key: 'acknowledged', label: '已确认' },
|
|
{ key: 'resolved', label: '已恢复' },
|
|
];
|
|
|
|
export default function PatientAlerts() {
|
|
const modeClass = useElderClass();
|
|
const currentPatient = useAuthStore((s) => s.currentPatient);
|
|
const [alerts, setAlerts] = useState<Alert[]>([]);
|
|
const [total, setTotal] = useState(0);
|
|
const [page, setPage] = useState(1);
|
|
const [status, setStatus] = useState('');
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
const fetchAlerts = useCallback(
|
|
async (pageNum: number, s: string, isRefresh = false) => {
|
|
if (!currentPatient) return;
|
|
setLoading(true);
|
|
try {
|
|
const res = await listPatientAlerts(currentPatient.id, {
|
|
page: pageNum,
|
|
page_size: 20,
|
|
status: s || undefined,
|
|
});
|
|
const list = res.data || [];
|
|
if (isRefresh) {
|
|
setAlerts(list);
|
|
} else {
|
|
setAlerts((prev) => [...prev, ...list]);
|
|
}
|
|
setTotal(res.total);
|
|
setPage(pageNum);
|
|
} catch {
|
|
Taro.showToast({ title: '加载失败', icon: 'none' });
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
},
|
|
[currentPatient],
|
|
);
|
|
|
|
usePageData(
|
|
async () => {
|
|
Taro.setNavigationBarTitle({ title: '健康告警' });
|
|
await fetchAlerts(1, status, true);
|
|
},
|
|
{ throttleMs: 10000, enablePullDown: true },
|
|
);
|
|
|
|
const handleTabChange = (key: string) => {
|
|
setStatus(key);
|
|
fetchAlerts(1, key, true);
|
|
};
|
|
|
|
if (!currentPatient) {
|
|
return (
|
|
<View className={`alerts-page ${modeClass}`}>
|
|
<View className='alerts-empty'>
|
|
<Text className='alerts-empty-text'>请先完善个人档案</Text>
|
|
<View className='alerts-empty-action' onClick={() => Taro.navigateTo({ url: '/pages/pkg-profile/family-add/index' })}>
|
|
<Text className='alerts-empty-action-text'>去建档</Text>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<View className={`alerts-page ${modeClass}`}>
|
|
<View className='alerts-tabs'>
|
|
{STATUS_TABS.map((tab) => (
|
|
<View
|
|
key={tab.key}
|
|
className={`alerts-tab ${status === tab.key ? 'active' : ''}`}
|
|
onClick={() => handleTabChange(tab.key)}
|
|
>
|
|
<Text className={`alerts-tab-text ${status === tab.key ? 'active' : ''}`}>{tab.label}</Text>
|
|
</View>
|
|
))}
|
|
</View>
|
|
|
|
{alerts.length === 0 && !loading ? (
|
|
<View className='alerts-empty'>
|
|
<Text className='alerts-empty-text'>暂无告警记录</Text>
|
|
<Text className='alerts-empty-hint'>您的各项指标正常</Text>
|
|
</View>
|
|
) : (
|
|
<View className='alerts-list'>
|
|
{alerts.map((item) => {
|
|
const sev = SEVERITY_MAP[item.severity] || SEVERITY_MAP.warning;
|
|
return (
|
|
<View className='alert-card' key={item.id}>
|
|
<View className='alert-header'>
|
|
<View className={`alert-badge ${sev.className}`}>
|
|
<Text className='alert-badge-text'>{sev.label}</Text>
|
|
</View>
|
|
<Text className='alert-time'>
|
|
{new Date(item.created_at).toLocaleDateString()}
|
|
</Text>
|
|
</View>
|
|
<Text className='alert-title'>{item.title}</Text>
|
|
</View>
|
|
);
|
|
})}
|
|
{loading && <Loading />}
|
|
{!loading && alerts.length >= total && total > 0 && (
|
|
<Loading text='没有更多了' />
|
|
)}
|
|
</View>
|
|
)}
|
|
</View>
|
|
);
|
|
}
|