From c4fad42cb496b3e4c862d0d002dd8f909988663f Mon Sep 17 00:00:00 2001 From: weijuesen Date: Wed, 12 Aug 2026 17:42:01 +0800 Subject: [PATCH] =?UTF-8?q?feat(web/miniapp):=20=E9=AB=98=E5=8F=91?= =?UTF-8?q?=E7=97=85=E5=A4=A9=E6=B0=94=E9=A2=84=E8=AD=A6=E5=B1=95=E7=A4=BA?= =?UTF-8?q?=EF=BC=88#12=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- miniapp/src/api/weather.ts | 12 ++++++ miniapp/src/pages/alerts/index.module.scss | 41 +++++++++++++++++++++ miniapp/src/pages/alerts/index.tsx | 21 +++++++++++ web/src/dal/weather.ts | 12 ++++++ web/src/pages/Alert.tsx | 43 ++++++++++++++++++++-- 5 files changed, 125 insertions(+), 4 deletions(-) create mode 100644 miniapp/src/api/weather.ts create mode 100644 web/src/dal/weather.ts diff --git a/miniapp/src/api/weather.ts b/miniapp/src/api/weather.ts new file mode 100644 index 0000000..4bf1eca --- /dev/null +++ b/miniapp/src/api/weather.ts @@ -0,0 +1,12 @@ +import { get } from './request'; + +export interface WeatherAlert { + id: string; + disease: string; + level: string; + reason: string; + createdAt?: string; +} + +export const getWeatherAlerts = (limit = 5) => + get('/weather/alerts', { limit }); diff --git a/miniapp/src/pages/alerts/index.module.scss b/miniapp/src/pages/alerts/index.module.scss index 26a1d24..82883f0 100644 --- a/miniapp/src/pages/alerts/index.module.scss +++ b/miniapp/src/pages/alerts/index.module.scss @@ -6,6 +6,47 @@ padding-bottom: $spacing-xl; } +.weatherWrap { + display: flex; + flex-direction: column; + gap: $spacing-sm; + margin: $spacing-md $spacing-lg 0; +} + +.weatherCard { + background: rgba(255, 125, 0, 0.08); + border-radius: $radius-md; + padding: $spacing-md; +} + +.weatherHeader { + display: flex; + align-items: center; + gap: $spacing-sm; + margin-bottom: 4rpx; +} + +.weatherBadge { + font-size: $font-size-xs; + color: $color-warning; + background: rgba(255, 125, 0, 0.15); + padding: 4rpx $spacing-sm; + border-radius: $radius-round; + flex-shrink: 0; +} + +.weatherDisease { + font-size: $font-size-md; + font-weight: $font-weight-medium; + color: $color-text-primary; +} + +.weatherReason { + font-size: $font-size-xs; + color: $color-text-secondary; + line-height: $line-height-normal; +} + .filterBar { display: flex; background: $color-bg-card; diff --git a/miniapp/src/pages/alerts/index.tsx b/miniapp/src/pages/alerts/index.tsx index e3661f5..e0d0e3f 100644 --- a/miniapp/src/pages/alerts/index.tsx +++ b/miniapp/src/pages/alerts/index.tsx @@ -3,6 +3,7 @@ import { View, Text } from '@tarojs/components'; import Taro, { useDidShow, usePullDownRefresh } from '@tarojs/taro'; import styles from './index.module.scss'; import { getAlarms, acknowledgeAlarm, getAlarmClip } from '@/api/alarms'; +import { getWeatherAlerts, type WeatherAlert } from '@/api/weather'; import { formatDateTime, formatRelativeTime, @@ -16,6 +17,7 @@ import type { Alarm } from '@/types'; const AlertsPage: React.FC = () => { const [alarms, setAlarms] = useState([]); + const [weatherAlerts, setWeatherAlerts] = useState([]); const [filterOpen, setFilterOpen] = useState(true); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); @@ -25,6 +27,8 @@ const AlertsPage: React.FC = () => { setError(''); const res = await getAlarms({ openOnly: filterOpen }).catch(() => [] as Alarm[]); setAlarms(res); + const weatherRes = await getWeatherAlerts(5).catch(() => [] as WeatherAlert[]); + setWeatherAlerts(weatherRes); } catch (err) { console.error('[Alerts] 数据加载失败:', err); setError(err instanceof Error ? err.message : '数据加载失败'); @@ -147,6 +151,23 @@ const AlertsPage: React.FC = () => { + {/* 高发病天气预警 */} + {weatherAlerts.length > 0 ? ( + + {weatherAlerts.map((w) => ( + + + + {w.level === 'orange' ? '高风险' : w.level === 'red' ? '极高风险' : '注意'} + + {w.disease} + + {w.reason} + + ))} + + ) : null} + {alarms.length === 0 ? ( {filterOpen ? '✅' : '🔔'} diff --git a/web/src/dal/weather.ts b/web/src/dal/weather.ts new file mode 100644 index 0000000..a5ea6e9 --- /dev/null +++ b/web/src/dal/weather.ts @@ -0,0 +1,12 @@ +import { get } from '../api/http'; + +export interface WeatherAlert { + id: string; + disease: string; + level: string; + reason: string; + createdAt?: string; +} + +export const listWeatherAlerts = (limit = 5) => + get('/weather/alerts', { params: { limit } }); diff --git a/web/src/pages/Alert.tsx b/web/src/pages/Alert.tsx index 11e1fea..9707a5c 100644 --- a/web/src/pages/Alert.tsx +++ b/web/src/pages/Alert.tsx @@ -1,9 +1,10 @@ -import { Button, Tag, message } from 'antd'; +import { Button, Card, Space, Tag, message } from 'antd'; import { CheckOutlined } from '@ant-design/icons'; import { ProTable, type ProColumns } from '@ant-design/pro-components'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import dayjs from 'dayjs'; import { getAlertClip, listAlerts, markAlertRead, markAllRead, type Alert } from '../dal/alert'; +import { listWeatherAlerts, type WeatherAlert } from '../dal/weather'; const LEVEL_MAP: Record = { info: { color: 'blue', text: '提示' }, @@ -19,6 +20,37 @@ const LEVEL_MAP: Record = { const levelOf = (alert: Alert) => alert.level || alert.severity || 'info'; const isRead = (alert: Alert) => alert.read ?? alert.acknowledged ?? false; +const WEATHER_LEVEL_COLORS: Record = { + yellow: 'gold', + orange: 'orange', + red: 'red', +}; + +function WeatherAlertsBlock() { + const [alerts, setAlerts] = useState([]); + useEffect(() => { + listWeatherAlerts(5) + .then(setAlerts) + .catch(() => {}); + }, []); + if (alerts.length === 0) return null; + return ( + + + {alerts.map((a) => ( +
+ + {a.level === 'orange' ? '高风险' : a.level === 'red' ? '极高风险' : '注意'} + + {a.disease} + {a.reason} +
+ ))} +
+
+ ); +} + export default function AlertPage() { const [, setTick] = useState(0); @@ -89,7 +121,9 @@ export default function AlertPage() { ]; return ( - + <> + + rowKey="id" columns={columns} request={async (p) => { @@ -109,6 +143,7 @@ export default function AlertPage() { 全部标为已读 , ]} - /> + /> + ); }