refactor(mp): 分包策略优化 — 合并单页分包 + doctor 拆包 + consultation 移出主包
- 合并 4 个单页分包:report→pkg-profile/reports, followup→pkg-profile/followups, events→pkg-profile/events, device-sync→pkg-health - consultation/detail 移出主包到 pkg-consultation 分包(减少主包体积) - doctor 18 页拆分为 pkg-doctor-core(8页) + pkg-doctor-clinical(10页) - 全部导航路径和 import 路径同步更新 - 分包 10→8 个,主包页面 13→12
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
@import '../../../../styles/variables.scss';
|
||||
@import '../../../../styles/mixins.scss';
|
||||
|
||||
.alert-detail-page {
|
||||
min-height: 100vh;
|
||||
background: $bg;
|
||||
padding: 24px;
|
||||
padding-bottom: 160px;
|
||||
}
|
||||
|
||||
.alert-detail-header {
|
||||
margin-bottom: 24px;
|
||||
|
||||
&__tags {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
&__time {
|
||||
font-size: var(--tk-font-h2);
|
||||
color: $tx3;
|
||||
}
|
||||
}
|
||||
|
||||
.detail-severity {
|
||||
font-size: var(--tk-font-h2);
|
||||
font-weight: 600;
|
||||
padding: 6px 16px;
|
||||
border-radius: $r-sm;
|
||||
|
||||
&--info {
|
||||
background: $bd-l;
|
||||
color: $tx2;
|
||||
}
|
||||
|
||||
&--warning {
|
||||
background: $wrn-l;
|
||||
color: $wrn;
|
||||
}
|
||||
|
||||
&--critical {
|
||||
background: $dan-l;
|
||||
color: $dan;
|
||||
}
|
||||
|
||||
&--urgent {
|
||||
background: $dan-l;
|
||||
color: $dan;
|
||||
}
|
||||
}
|
||||
|
||||
.detail-status {
|
||||
font-size: var(--tk-font-h2);
|
||||
padding: 6px 16px;
|
||||
border-radius: $r-sm;
|
||||
|
||||
&--pending {
|
||||
background: $wrn-l;
|
||||
color: $wrn;
|
||||
}
|
||||
|
||||
&--acknowledged {
|
||||
background: $pri-l;
|
||||
color: $pri;
|
||||
}
|
||||
|
||||
&--resolved {
|
||||
background: $acc-l;
|
||||
color: $acc;
|
||||
}
|
||||
|
||||
&--dismissed {
|
||||
background: $bd-l;
|
||||
color: $tx3;
|
||||
}
|
||||
}
|
||||
|
||||
.alert-detail-card {
|
||||
background: $card;
|
||||
border-radius: $r-lg;
|
||||
padding: 24px;
|
||||
margin-bottom: 16px;
|
||||
box-shadow: $shadow-sm;
|
||||
|
||||
&__label {
|
||||
font-size: var(--tk-font-h2);
|
||||
color: $tx2;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
&__value {
|
||||
font-size: var(--tk-font-body-lg);
|
||||
color: $tx;
|
||||
word-break: break-all;
|
||||
|
||||
&--id {
|
||||
font-size: var(--tk-font-h2);
|
||||
color: $tx3;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
&--detail {
|
||||
font-size: var(--tk-font-body);
|
||||
color: $tx2;
|
||||
font-family: monospace;
|
||||
line-height: 1.6;
|
||||
white-space: pre-wrap;
|
||||
background: $bg;
|
||||
padding: 16px;
|
||||
border-radius: $r;
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.alert-detail-actions {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
margin-top: 32px;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.alert-action-btn {
|
||||
flex: 1;
|
||||
height: 88px;
|
||||
line-height: 88px;
|
||||
font-size: var(--tk-font-body-lg);
|
||||
font-weight: 600;
|
||||
border-radius: $r-lg;
|
||||
text-align: center;
|
||||
|
||||
&--primary {
|
||||
background: $pri;
|
||||
color: $card;
|
||||
border: none;
|
||||
|
||||
&::after {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
&--default {
|
||||
background: $bd-l;
|
||||
color: $tx2;
|
||||
border: none;
|
||||
|
||||
&::after {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
&--resolve {
|
||||
background: $acc-l;
|
||||
color: $acc;
|
||||
border: none;
|
||||
|
||||
&::after {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
&[disabled] {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { View, Text, ScrollView, Button } from '@tarojs/components';
|
||||
import Taro from '@tarojs/taro';
|
||||
import { usePageData } from '@/hooks/usePageData';
|
||||
import {
|
||||
getAlert, acknowledgeAlert, dismissAlert, resolveAlert,
|
||||
type Alert,
|
||||
} from '@/services/doctor/alerts';
|
||||
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: 'detail-severity--info' },
|
||||
warning: { label: '警告', className: 'detail-severity--warning' },
|
||||
critical: { label: '严重', className: 'detail-severity--critical' },
|
||||
urgent: { label: '紧急', className: 'detail-severity--urgent' },
|
||||
};
|
||||
|
||||
const STATUS_MAP: Record<string, { label: string; className: string }> = {
|
||||
pending: { label: '待处理', className: 'detail-status--pending' },
|
||||
acknowledged: { label: '已确认', className: 'detail-status--acknowledged' },
|
||||
resolved: { label: '已恢复', className: 'detail-status--resolved' },
|
||||
dismissed: { label: '已忽略', className: 'detail-status--dismissed' },
|
||||
};
|
||||
|
||||
export default function AlertDetail() {
|
||||
const modeClass = useElderClass();
|
||||
const [alert, setAlert] = useState<Alert | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [actionLoading, setActionLoading] = useState(false);
|
||||
|
||||
const alertId = Taro.getCurrentInstance().router?.params?.id || '';
|
||||
|
||||
const loadAlert = useCallback(async () => {
|
||||
if (!alertId) return;
|
||||
try {
|
||||
const data = await getAlert(alertId);
|
||||
setAlert(data);
|
||||
} catch {
|
||||
Taro.showToast({ title: '加载失败', icon: 'none' });
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [alertId]);
|
||||
|
||||
usePageData(loadAlert, { throttleMs: 60000, enablePullDown: false, enabled: !!alertId });
|
||||
|
||||
const handleAcknowledge = async () => {
|
||||
if (!alert) return;
|
||||
setActionLoading(true);
|
||||
try {
|
||||
const updated = await acknowledgeAlert(alert.id, alert.version);
|
||||
setAlert(updated);
|
||||
Taro.showToast({ title: '已确认', icon: 'success' });
|
||||
} catch {
|
||||
Taro.showToast({ title: '操作失败', icon: 'none' });
|
||||
} finally {
|
||||
setActionLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDismiss = async () => {
|
||||
if (!alert) return;
|
||||
setActionLoading(true);
|
||||
try {
|
||||
const updated = await dismissAlert(alert.id, alert.version);
|
||||
setAlert(updated);
|
||||
Taro.showToast({ title: '已忽略', icon: 'success' });
|
||||
} catch {
|
||||
Taro.showToast({ title: '操作失败', icon: 'none' });
|
||||
} finally {
|
||||
setActionLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleResolve = async () => {
|
||||
if (!alert) return;
|
||||
setActionLoading(true);
|
||||
try {
|
||||
const updated = await resolveAlert(alert.id, alert.version);
|
||||
setAlert(updated);
|
||||
Taro.showToast({ title: '已恢复', icon: 'success' });
|
||||
} catch {
|
||||
Taro.showToast({ title: '操作失败', icon: 'none' });
|
||||
} finally {
|
||||
setActionLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (loading) return <Loading />;
|
||||
if (!alert) {
|
||||
return (
|
||||
<View className={`alert-detail-page ${modeClass}`}>
|
||||
<Text>告警不存在</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const severity = SEVERITY_MAP[alert.severity] ?? SEVERITY_MAP.info;
|
||||
const status = STATUS_MAP[alert.status] ?? STATUS_MAP.pending;
|
||||
const isPending = alert.status === 'pending';
|
||||
const isAcknowledged = alert.status === 'acknowledged';
|
||||
|
||||
return (
|
||||
<ScrollView scrollY className={`alert-detail-page ${modeClass}`}>
|
||||
{/* 顶部状态 */}
|
||||
<View className='alert-detail-header'>
|
||||
<View className='alert-detail-header__tags'>
|
||||
<Text className={`detail-severity ${severity.className}`}>
|
||||
{severity.label}
|
||||
</Text>
|
||||
<Text className={`detail-status ${status.className}`}>
|
||||
{status.label}
|
||||
</Text>
|
||||
</View>
|
||||
<Text className='alert-detail-header__time'>
|
||||
{new Date(alert.created_at).toLocaleString('zh-CN')}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* 告警信息 */}
|
||||
<View className='alert-detail-card'>
|
||||
<Text className='alert-detail-card__label'>告警标题</Text>
|
||||
<Text className='alert-detail-card__value'>{alert.title}</Text>
|
||||
</View>
|
||||
|
||||
<View className='alert-detail-card'>
|
||||
<Text className='alert-detail-card__label'>患者 ID</Text>
|
||||
<Text className='alert-detail-card__value alert-detail-card__value--id'>
|
||||
{alert.patient_id ? `${alert.patient_id.slice(0, 8)}...` : '-'}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View className='alert-detail-card'>
|
||||
<Text className='alert-detail-card__label'>严重程度</Text>
|
||||
<Text className='alert-detail-card__value'>{severity.label}</Text>
|
||||
</View>
|
||||
|
||||
{alert.detail && (
|
||||
<View className='alert-detail-card'>
|
||||
<Text className='alert-detail-card__label'>告警详情</Text>
|
||||
<Text className='alert-detail-card__value alert-detail-card__value--detail'>
|
||||
{JSON.stringify(alert.detail, null, 2)}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{alert.acknowledged_by && (
|
||||
<View className='alert-detail-card'>
|
||||
<Text className='alert-detail-card__label'>处理人</Text>
|
||||
<Text className='alert-detail-card__value'>{alert.acknowledged_by}</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{alert.acknowledged_at && (
|
||||
<View className='alert-detail-card'>
|
||||
<Text className='alert-detail-card__label'>确认时间</Text>
|
||||
<Text className='alert-detail-card__value'>
|
||||
{new Date(alert.acknowledged_at).toLocaleString('zh-CN')}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{alert.resolved_at && (
|
||||
<View className='alert-detail-card'>
|
||||
<Text className='alert-detail-card__label'>恢复时间</Text>
|
||||
<Text className='alert-detail-card__value'>
|
||||
{new Date(alert.resolved_at).toLocaleString('zh-CN')}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* 操作按钮 */}
|
||||
{(isPending || isAcknowledged) && (
|
||||
<View className='alert-detail-actions'>
|
||||
{isPending && (
|
||||
<>
|
||||
<Button
|
||||
className='alert-action-btn alert-action-btn--primary'
|
||||
onClick={handleAcknowledge}
|
||||
disabled={actionLoading}
|
||||
>
|
||||
确认
|
||||
</Button>
|
||||
<Button
|
||||
className='alert-action-btn alert-action-btn--default'
|
||||
onClick={handleDismiss}
|
||||
disabled={actionLoading}
|
||||
>
|
||||
忽略
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
{(isPending || isAcknowledged) && (
|
||||
<Button
|
||||
className='alert-action-btn alert-action-btn--resolve'
|
||||
onClick={handleResolve}
|
||||
disabled={actionLoading}
|
||||
>
|
||||
恢复
|
||||
</Button>
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
174
apps/miniprogram/src/pages/pkg-doctor-clinical/alerts/index.scss
Normal file
174
apps/miniprogram/src/pages/pkg-doctor-clinical/alerts/index.scss
Normal file
@@ -0,0 +1,174 @@
|
||||
@import '../../../styles/variables.scss';
|
||||
@import '../../../styles/mixins.scss';
|
||||
|
||||
.alert-list-page {
|
||||
min-height: 100vh;
|
||||
background: $bg;
|
||||
padding: 24px;
|
||||
padding-bottom: 120px;
|
||||
}
|
||||
|
||||
.alert-list-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.alert-list-title {
|
||||
font-size: var(--tk-font-num-lg);
|
||||
font-weight: 600;
|
||||
color: $tx;
|
||||
}
|
||||
|
||||
.alert-list-count {
|
||||
font-size: var(--tk-font-h2);
|
||||
color: $tx2;
|
||||
}
|
||||
|
||||
.alert-tabs {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.alert-tab {
|
||||
padding: 10px 24px;
|
||||
border-radius: $r-pill;
|
||||
background: $bd-l;
|
||||
font-size: var(--tk-font-h2);
|
||||
color: $tx2;
|
||||
transition: all 0.2s;
|
||||
|
||||
&--active {
|
||||
background: $pri;
|
||||
color: $card;
|
||||
}
|
||||
}
|
||||
|
||||
.alert-cards {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.alert-card {
|
||||
background: $card;
|
||||
border-radius: $r-lg;
|
||||
padding: 24px;
|
||||
box-shadow: $shadow-sm;
|
||||
border-left: 4px solid $wrn;
|
||||
|
||||
&:active {
|
||||
background: $bd-l;
|
||||
}
|
||||
|
||||
&--critical {
|
||||
border-left-color: $dan;
|
||||
}
|
||||
|
||||
&--info {
|
||||
border-left-color: $tx3;
|
||||
}
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: var(--tk-font-body-lg);
|
||||
font-weight: 500;
|
||||
color: $tx;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__time {
|
||||
font-size: var(--tk-font-body);
|
||||
color: $tx3;
|
||||
}
|
||||
}
|
||||
|
||||
.alert-severity {
|
||||
font-size: var(--tk-font-body);
|
||||
font-weight: 600;
|
||||
padding: 4px 12px;
|
||||
border-radius: $r-sm;
|
||||
|
||||
&--info {
|
||||
background: $bd-l;
|
||||
color: $tx2;
|
||||
}
|
||||
|
||||
&--warning {
|
||||
background: $wrn-l;
|
||||
color: $wrn;
|
||||
}
|
||||
|
||||
&--critical {
|
||||
background: $dan-l;
|
||||
color: $dan;
|
||||
}
|
||||
|
||||
&--urgent {
|
||||
background: $dan-l;
|
||||
color: $dan;
|
||||
}
|
||||
}
|
||||
|
||||
.alert-status {
|
||||
font-size: var(--tk-font-body);
|
||||
padding: 4px 12px;
|
||||
border-radius: $r-sm;
|
||||
|
||||
&--pending {
|
||||
background: $wrn-l;
|
||||
color: $wrn;
|
||||
}
|
||||
|
||||
&--acknowledged {
|
||||
background: $pri-l;
|
||||
color: $pri;
|
||||
}
|
||||
|
||||
&--resolved {
|
||||
background: $acc-l;
|
||||
color: $acc;
|
||||
}
|
||||
|
||||
&--dismissed {
|
||||
background: $bd-l;
|
||||
color: $tx3;
|
||||
}
|
||||
}
|
||||
|
||||
.alert-pagination {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 24px;
|
||||
margin-top: 32px;
|
||||
|
||||
&__btn {
|
||||
font-size: var(--tk-font-h1);
|
||||
color: $pri;
|
||||
padding: 12px 24px;
|
||||
|
||||
&.disabled {
|
||||
color: $tx3;
|
||||
}
|
||||
}
|
||||
|
||||
&__info {
|
||||
font-size: var(--tk-font-h2);
|
||||
color: $tx2;
|
||||
}
|
||||
}
|
||||
165
apps/miniprogram/src/pages/pkg-doctor-clinical/alerts/index.tsx
Normal file
165
apps/miniprogram/src/pages/pkg-doctor-clinical/alerts/index.tsx
Normal file
@@ -0,0 +1,165 @@
|
||||
import { useState, useEffect, useMemo, useCallback, useRef } from 'react';
|
||||
import { View, Text, ScrollView } from '@tarojs/components';
|
||||
import Taro from '@tarojs/taro';
|
||||
import { usePageData } from '@/hooks/usePageData';
|
||||
import { listAlerts, type Alert } from '@/services/doctor/alerts';
|
||||
import Loading from '@/components/Loading';
|
||||
import EmptyState from '@/components/EmptyState';
|
||||
import { useElderClass } from '../../../hooks/useElderClass';
|
||||
import { safeNavigateTo } from '@/utils/navigate';
|
||||
import './index.scss';
|
||||
|
||||
const SEVERITY_MAP: Record<string, { label: string; className: string }> = {
|
||||
info: { label: '提示', className: 'alert-severity--info' },
|
||||
warning: { label: '警告', className: 'alert-severity--warning' },
|
||||
critical: { label: '严重', className: 'alert-severity--critical' },
|
||||
urgent: { label: '紧急', className: 'alert-severity--urgent' },
|
||||
};
|
||||
|
||||
const STATUS_MAP: Record<string, { label: string; className: string }> = {
|
||||
pending: { label: '待处理', className: 'alert-status--pending' },
|
||||
acknowledged: { label: '已确认', className: 'alert-status--acknowledged' },
|
||||
resolved: { label: '已恢复', className: 'alert-status--resolved' },
|
||||
dismissed: { label: '已忽略', className: 'alert-status--dismissed' },
|
||||
};
|
||||
|
||||
const STATUS_TABS = [
|
||||
{ value: '', label: '全部' },
|
||||
{ value: 'pending', label: '待处理' },
|
||||
{ value: 'acknowledged', label: '已确认' },
|
||||
{ value: 'resolved', label: '已恢复' },
|
||||
];
|
||||
|
||||
export default function AlertList() {
|
||||
const modeClass = useElderClass();
|
||||
const [alerts, setAlerts] = useState<Alert[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [activeTab, setActiveTab] = useState('');
|
||||
const [total, setTotal] = useState(0);
|
||||
const [page, setPage] = useState(1);
|
||||
const mountedRef = useRef(false);
|
||||
|
||||
const totalPages = useMemo(() => Math.ceil(total / 20), [total]);
|
||||
|
||||
const loadAlerts = useCallback(async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const res = await listAlerts({
|
||||
status: activeTab || undefined,
|
||||
page,
|
||||
page_size: 20,
|
||||
});
|
||||
setAlerts(res.data || []);
|
||||
setTotal(res.total || 0);
|
||||
} catch {
|
||||
Taro.showToast({ title: '加载失败', icon: 'none' });
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [activeTab, page]);
|
||||
|
||||
const { trigger } = usePageData(loadAlerts);
|
||||
|
||||
// tab/page 变化时重新加载(跳过首次 mount,由 usePageData 的 useDidShow 处理)
|
||||
useEffect(() => {
|
||||
if (mountedRef.current) {
|
||||
trigger();
|
||||
}
|
||||
mountedRef.current = true;
|
||||
}, [page, activeTab, trigger]);
|
||||
|
||||
const handleTabChange = (value: string) => {
|
||||
setActiveTab(value);
|
||||
setPage(1);
|
||||
};
|
||||
|
||||
const handleAlertClick = (alert: Alert) => {
|
||||
safeNavigateTo(`/pages/pkg-doctor-clinical/alerts/detail/index?id=${alert.id}`);
|
||||
};
|
||||
|
||||
const formatTime = (dateStr: string) => {
|
||||
const d = new Date(dateStr);
|
||||
const now = new Date();
|
||||
const diff = now.getTime() - d.getTime();
|
||||
const minutes = Math.floor(diff / 60000);
|
||||
if (minutes < 1) return '刚刚';
|
||||
if (minutes < 60) return `${minutes}分钟前`;
|
||||
const hours = Math.floor(minutes / 60);
|
||||
if (hours < 24) return `${hours}小时前`;
|
||||
return d.toLocaleDateString('zh-CN', { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' });
|
||||
};
|
||||
|
||||
if (loading && alerts.length === 0) return <Loading />;
|
||||
|
||||
return (
|
||||
<ScrollView scrollY className={`alert-list-page ${modeClass}`}>
|
||||
<View className='alert-list-header'>
|
||||
<Text className='alert-list-title'>告警列表</Text>
|
||||
<Text className='alert-list-count'>共 {total} 条</Text>
|
||||
</View>
|
||||
|
||||
<View className='alert-tabs'>
|
||||
{STATUS_TABS.map((tab) => (
|
||||
<Text
|
||||
key={tab.value}
|
||||
className={`alert-tab ${activeTab === tab.value ? 'alert-tab--active' : ''}`}
|
||||
onClick={() => handleTabChange(tab.value)}
|
||||
>
|
||||
{tab.label}
|
||||
</Text>
|
||||
))}
|
||||
</View>
|
||||
|
||||
{alerts.length === 0 ? (
|
||||
<EmptyState description='暂无告警' />
|
||||
) : (
|
||||
<View className='alert-cards'>
|
||||
{alerts.map((alert) => {
|
||||
const severity = SEVERITY_MAP[alert.severity] ?? SEVERITY_MAP.info;
|
||||
const status = STATUS_MAP[alert.status] ?? STATUS_MAP.pending;
|
||||
return (
|
||||
<View
|
||||
key={alert.id}
|
||||
className='alert-card'
|
||||
onClick={() => handleAlertClick(alert)}
|
||||
>
|
||||
<View className='alert-card__header'>
|
||||
<Text className={`alert-severity ${severity.className}`}>
|
||||
{severity.label}
|
||||
</Text>
|
||||
<Text className={`alert-status ${status.className}`}>
|
||||
{status.label}
|
||||
</Text>
|
||||
</View>
|
||||
<Text className='alert-card__title'>{alert.title}</Text>
|
||||
<View className='alert-card__footer'>
|
||||
<Text className='alert-card__time'>{formatTime(alert.created_at)}</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
)}
|
||||
|
||||
{total > 20 && (
|
||||
<View className='alert-pagination'>
|
||||
<Text
|
||||
className={`alert-pagination__btn ${page <= 1 ? 'disabled' : ''}`}
|
||||
onClick={() => page > 1 && setPage(page - 1)}
|
||||
>
|
||||
上一页
|
||||
</Text>
|
||||
<Text className='alert-pagination__info'>
|
||||
{page} / {totalPages}
|
||||
</Text>
|
||||
<Text
|
||||
className={`alert-pagination__btn ${page >= totalPages ? 'disabled' : ''}`}
|
||||
onClick={() => page < totalPages && setPage(page + 1)}
|
||||
>
|
||||
下一页
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user