refactor(mp): 迁移医护+健康页面 — 使用 PageShell + ContentCard 统一组件库
行动收件箱、医护工作台、健康趋势、患者告警、体征录入、 日常监测、设备同步共 7 个页面迁移: - 最外层容器 → PageShell - 卡片元素 → ContentCard - SCSS 删除 min-height/background/box-shadow 通用样式
This commit is contained in:
@@ -1,10 +1,8 @@
|
||||
@import '../../../styles/variables.scss';
|
||||
@import '../../../styles/mixins.scss';
|
||||
@import '../../styles/variables.scss';
|
||||
@import '../../styles/mixins.scss';
|
||||
|
||||
.action-inbox-page {
|
||||
min-height: 100vh;
|
||||
background: $bg;
|
||||
}
|
||||
// PageShell 已接管:min-height, background
|
||||
// ContentCard 已接管:inbox-card 背景/圆角/阴影/触摸反馈
|
||||
|
||||
.inbox-list {
|
||||
height: calc(100vh - 50px);
|
||||
@@ -12,11 +10,7 @@
|
||||
}
|
||||
|
||||
.inbox-card {
|
||||
background: $card;
|
||||
border-radius: $r-sm;
|
||||
padding: 14px 16px;
|
||||
margin-bottom: 10px;
|
||||
box-shadow: $shadow-sm;
|
||||
|
||||
.inbox-card-header {
|
||||
display: flex;
|
||||
|
||||
@@ -13,6 +13,8 @@ import Loading from '@/components/Loading';
|
||||
import ErrorState from '@/components/ErrorState';
|
||||
import EmptyState from '@/components/EmptyState';
|
||||
import SegmentTabs from '@/components/SegmentTabs';
|
||||
import PageShell from '@/components/ui/PageShell';
|
||||
import ContentCard from '@/components/ui/ContentCard';
|
||||
import { useElderClass } from '../../../hooks/useElderClass';
|
||||
import './index.scss';
|
||||
|
||||
@@ -119,7 +121,7 @@ export default function ActionInboxPage() {
|
||||
};
|
||||
|
||||
return (
|
||||
<View className={`action-inbox-page ${modeClass}`}>
|
||||
<PageShell padding="none" className={modeClass}>
|
||||
<SegmentTabs tabs={STATUS_TABS} activeKey={activeTab} onChange={handleTabChange} variant="underline" />
|
||||
|
||||
{error ? (
|
||||
@@ -129,10 +131,11 @@ export default function ActionInboxPage() {
|
||||
) : (
|
||||
<ScrollView scrollY className="inbox-list">
|
||||
{items.map((item) => (
|
||||
<View
|
||||
<ContentCard
|
||||
key={item.id}
|
||||
className="inbox-card"
|
||||
onClick={() => handleItemClick(item)}
|
||||
activeFeedback="opacity"
|
||||
onPress={() => handleItemClick(item)}
|
||||
>
|
||||
<View className="inbox-card-header">
|
||||
<Text
|
||||
@@ -146,7 +149,7 @@ export default function ActionInboxPage() {
|
||||
{item.patient_name} ·{' '}
|
||||
{new Date(item.created_at).toLocaleDateString('zh-CN')}
|
||||
</Text>
|
||||
</View>
|
||||
</ContentCard>
|
||||
))}
|
||||
{loading && <Loading />}
|
||||
{!loading && items.length >= total && total > 0 && (
|
||||
@@ -208,6 +211,6 @@ export default function ActionInboxPage() {
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</PageShell>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
@import '../../styles/variables.scss';
|
||||
@import '../../styles/mixins.scss';
|
||||
|
||||
// PageShell 已接管:min-height, background, padding
|
||||
|
||||
.doctor-home {
|
||||
min-height: 100vh;
|
||||
background: $bg;
|
||||
padding: 32px;
|
||||
padding-bottom: calc(160px + env(safe-area-inset-bottom));
|
||||
|
||||
&__header {
|
||||
margin-bottom: 40px;
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { useState, useMemo, useCallback } from 'react';
|
||||
import { View, Text, Input, ScrollView } from '@tarojs/components';
|
||||
import { View, Text, Input } from '@tarojs/components';
|
||||
import Taro from '@tarojs/taro';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useElderClass } from '../../hooks/useElderClass';
|
||||
import { usePageData } from '@/hooks/usePageData';
|
||||
import { getDashboard, type DoctorDashboard } from '@/services/doctor/dashboard';
|
||||
import Loading from '@/components/Loading';
|
||||
import PageShell from '@/components/ui/PageShell';
|
||||
import './index.scss';
|
||||
|
||||
interface CardConfig {
|
||||
@@ -107,7 +108,7 @@ export default function DoctorHome() {
|
||||
if (loading) return <Loading />;
|
||||
|
||||
return (
|
||||
<ScrollView scrollY className={`doctor-home ${modeClass}`}>
|
||||
<PageShell safeBottom={false} className={`doctor-home ${modeClass}`}>
|
||||
<View className='doctor-home__header'>
|
||||
<Text className='doctor-home__title'>医护工作台</Text>
|
||||
<Text className='doctor-home__greeting'>
|
||||
@@ -192,6 +193,6 @@ export default function DoctorHome() {
|
||||
<View className='doctor-home__footer'>
|
||||
<Text className='doctor-home__logout' onClick={handleLogout}>退出登录</Text>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</PageShell>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
@import '../../../styles/variables.scss';
|
||||
@import '../../../styles/mixins.scss';
|
||||
|
||||
.alerts-page {
|
||||
min-height: 100vh;
|
||||
background: $bg;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
// PageShell 已接管:min-height, background, safe-bottom
|
||||
// ContentCard 已接管:alert-card 背景/圆角/阴影
|
||||
|
||||
.alerts-tabs {
|
||||
display: flex;
|
||||
@@ -39,11 +36,7 @@
|
||||
}
|
||||
|
||||
.alert-card {
|
||||
background: $card;
|
||||
border-radius: $r;
|
||||
padding: 24px;
|
||||
margin-bottom: 16px;
|
||||
box-shadow: $shadow-sm;
|
||||
}
|
||||
|
||||
.alert-header {
|
||||
|
||||
@@ -8,6 +8,8 @@ import Loading from '@/components/Loading';
|
||||
import ErrorState from '@/components/ErrorState';
|
||||
import EmptyState from '@/components/EmptyState';
|
||||
import SegmentTabs from '@/components/SegmentTabs';
|
||||
import PageShell from '@/components/ui/PageShell';
|
||||
import ContentCard from '@/components/ui/ContentCard';
|
||||
import { useElderClass } from '../../../hooks/useElderClass';
|
||||
import './index.scss';
|
||||
|
||||
@@ -79,23 +81,23 @@ export default function PatientAlerts() {
|
||||
|
||||
if (!currentPatient) {
|
||||
return (
|
||||
<View className={`alerts-page ${modeClass}`}>
|
||||
<PageShell padding="none" className={modeClass}>
|
||||
<ErrorState text='请先完善个人档案' onRetry={() => Taro.navigateTo({ url: '/pages/pkg-profile/family-add/index' })} />
|
||||
</View>
|
||||
</PageShell>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<View className={`alerts-page ${modeClass}`}>
|
||||
<PageShell padding="none" className={modeClass}>
|
||||
<SegmentTabs tabs={STATUS_TABS} activeKey={status} onChange={handleTabChange} variant="pill" />
|
||||
<ErrorState onRetry={() => fetchAlerts(1, status, true)} />
|
||||
</View>
|
||||
</PageShell>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View className={`alerts-page ${modeClass}`}>
|
||||
<PageShell padding="none" className={modeClass}>
|
||||
<SegmentTabs tabs={STATUS_TABS} activeKey={status} onChange={handleTabChange} variant="pill" />
|
||||
|
||||
{alerts.length === 0 && !loading ? (
|
||||
@@ -105,7 +107,7 @@ export default function PatientAlerts() {
|
||||
{alerts.map((item) => {
|
||||
const sev = SEVERITY_MAP[item.severity] || SEVERITY_MAP.warning;
|
||||
return (
|
||||
<View className='alert-card' key={item.id}>
|
||||
<ContentCard className='alert-card' key={item.id}>
|
||||
<View className='alert-header'>
|
||||
<View className={`alert-badge ${sev.className}`}>
|
||||
<Text className='alert-badge-text'>{sev.label}</Text>
|
||||
@@ -115,7 +117,7 @@ export default function PatientAlerts() {
|
||||
</Text>
|
||||
</View>
|
||||
<Text className='alert-title'>{item.title}</Text>
|
||||
</View>
|
||||
</ContentCard>
|
||||
);
|
||||
})}
|
||||
{loading && <Loading />}
|
||||
@@ -124,6 +126,6 @@ export default function PatientAlerts() {
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</PageShell>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
@import '../../../styles/variables.scss';
|
||||
@import '../../../styles/mixins.scss';
|
||||
|
||||
.dm-page {
|
||||
min-height: 100vh;
|
||||
background: $bg;
|
||||
padding: 0 0 60px;
|
||||
}
|
||||
// PageShell 已接管:min-height, background
|
||||
// ContentCard 已接管:dm-card/dm-group 背景/圆角/阴影
|
||||
|
||||
/* ── hero ── */
|
||||
.dm-hero {
|
||||
@@ -44,10 +41,6 @@
|
||||
|
||||
/* ── card (standalone, used for date picker) ── */
|
||||
.dm-card {
|
||||
background: $card;
|
||||
border-radius: $r;
|
||||
box-shadow: $shadow-md;
|
||||
padding: 28px;
|
||||
margin: 0 24px 20px;
|
||||
}
|
||||
|
||||
@@ -98,9 +91,6 @@
|
||||
|
||||
/* ── collapsible group ── */
|
||||
.dm-group {
|
||||
background: $card;
|
||||
border-radius: $r;
|
||||
box-shadow: $shadow-md;
|
||||
margin: 0 24px 20px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import { clearRequestCache } from '@/services/request';
|
||||
import { trackEvent } from '@/services/analytics';
|
||||
import { useSafeTimeout } from '@/hooks/useSafeTimeout';
|
||||
import { useElderClass } from '@/hooks/useElderClass';
|
||||
import PageShell from '@/components/ui/PageShell';
|
||||
import ContentCard from '@/components/ui/ContentCard';
|
||||
import {
|
||||
BP_RANGE, WEIGHT_RANGE, SUGAR_RANGE, VOLUME_RANGE,
|
||||
checkAbnormal, formatDate, FIELD_LABELS,
|
||||
@@ -218,7 +220,7 @@ export default function DailyMonitoring() {
|
||||
const bloodSugarAbnormal = checkAbnormal(bloodSugar, 'bloodSugar');
|
||||
|
||||
return (
|
||||
<View className={`dm-page ${modeClass}`}>
|
||||
<PageShell padding="none" safeBottom className={modeClass}>
|
||||
{/* 页面标题 */}
|
||||
<View className='dm-hero'>
|
||||
<View className='dm-hero-icon'>
|
||||
@@ -229,7 +231,7 @@ export default function DailyMonitoring() {
|
||||
</View>
|
||||
|
||||
{/* 日期选择 (standalone card) */}
|
||||
<View className='dm-card'>
|
||||
<ContentCard className='dm-card'>
|
||||
<View className='dm-card-header'>
|
||||
<Text className='dm-card-title'>记录日期</Text>
|
||||
{isToday && (
|
||||
@@ -247,10 +249,10 @@ export default function DailyMonitoring() {
|
||||
<Text className='dm-date-arrow'>V</Text>
|
||||
</View>
|
||||
</Picker>
|
||||
</View>
|
||||
</ContentCard>
|
||||
|
||||
{/* ── Group 1: 晨间体征 (default open) ── */}
|
||||
<View className={`dm-group${collapsed.morning ? ' dm-group-collapsed' : ''}`}>
|
||||
<ContentCard className={`dm-group${collapsed.morning ? ' dm-group-collapsed' : ''}`}>
|
||||
<View className='dm-group-header' onClick={() => toggleSection('morning')}>
|
||||
<Text className='dm-group-title'>晨间体征</Text>
|
||||
<Text className={`dm-group-arrow${collapsed.morning ? '' : ' dm-group-arrow-open'}`}>▸</Text>
|
||||
@@ -295,10 +297,10 @@ export default function DailyMonitoring() {
|
||||
</View>
|
||||
<Text className='dm-field-unit'>mmHg</Text>
|
||||
</View>
|
||||
</View>
|
||||
</ContentCard>
|
||||
|
||||
{/* ── Group 2: 晚间体征 (default open) ── */}
|
||||
<View className={`dm-group${collapsed.evening ? ' dm-group-collapsed' : ''}`}>
|
||||
<ContentCard className={`dm-group${collapsed.evening ? ' dm-group-collapsed' : ''}`}>
|
||||
<View className='dm-group-header' onClick={() => toggleSection('evening')}>
|
||||
<Text className='dm-group-title'>晚间体征</Text>
|
||||
<Text className={`dm-group-arrow${collapsed.evening ? '' : ' dm-group-arrow-open'}`}>▸</Text>
|
||||
@@ -343,10 +345,10 @@ export default function DailyMonitoring() {
|
||||
</View>
|
||||
<Text className='dm-field-unit'>mmHg</Text>
|
||||
</View>
|
||||
</View>
|
||||
</ContentCard>
|
||||
|
||||
{/* ── Group 3: 其他指标 (default collapsed) ── */}
|
||||
<View className={`dm-group${collapsed.other ? ' dm-group-collapsed' : ''}`}>
|
||||
<ContentCard className={`dm-group${collapsed.other ? ' dm-group-collapsed' : ''}`}>
|
||||
<View className='dm-group-header' onClick={() => toggleSection('other')}>
|
||||
<Text className='dm-group-title'>其他指标</Text>
|
||||
<Text className={`dm-group-arrow${collapsed.other ? '' : ' dm-group-arrow-open'}`}>▸</Text>
|
||||
@@ -428,7 +430,7 @@ export default function DailyMonitoring() {
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</ContentCard>
|
||||
|
||||
{/* 提交 */}
|
||||
<View
|
||||
@@ -442,6 +444,6 @@ export default function DailyMonitoring() {
|
||||
<View className='dm-reset' onClick={resetForm}>
|
||||
<Text className='dm-reset-text'>清空表单</Text>
|
||||
</View>
|
||||
</View>
|
||||
</PageShell>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
@import '../../../styles/variables.scss';
|
||||
@import '../../../styles/mixins.scss';
|
||||
|
||||
.device-sync-page {
|
||||
min-height: 100vh;
|
||||
background: $bg;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
// PageShell 已接管:min-height, background, safe-bottom
|
||||
// ContentCard 已接管:sync-status-card/sync-result-card 背景/圆角/阴影
|
||||
|
||||
.sync-header {
|
||||
background: $pri;
|
||||
@@ -130,11 +127,7 @@
|
||||
.sync-status-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: $card;
|
||||
border-radius: $r-sm;
|
||||
padding: 24px;
|
||||
margin-bottom: 16px;
|
||||
box-shadow: $shadow-sm;
|
||||
}
|
||||
|
||||
.sync-status-dot {
|
||||
@@ -225,9 +218,6 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
background: $card;
|
||||
border-radius: $r;
|
||||
padding: 48px 24px;
|
||||
margin-bottom: 24px;
|
||||
box-shadow: $shadow-sm;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ import { uploadReadings } from '@/services/device-sync';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import type { BLEDevice, NormalizedReading } from '@/services/ble/types';
|
||||
import { useElderClass } from '@/hooks/useElderClass';
|
||||
import PageShell from '@/components/ui/PageShell';
|
||||
import ContentCard from '@/components/ui/ContentCard';
|
||||
import './index.scss';
|
||||
|
||||
/** liveReadings 最大保留条数,防止内存无限增长 */
|
||||
@@ -232,10 +234,10 @@ export default function DeviceSync() {
|
||||
|
||||
const renderConnected = () => (
|
||||
<View className="sync-section">
|
||||
<View className="sync-status-card">
|
||||
<ContentCard className="sync-status-card">
|
||||
<Text className="sync-status-dot sync-status-dot--connected" />
|
||||
<Text className="sync-status-text">已连接: {selectedDevice?.name}</Text>
|
||||
</View>
|
||||
</ContentCard>
|
||||
|
||||
{liveReadings.length > 0 && (
|
||||
<View className="sync-readings-panel">
|
||||
@@ -276,11 +278,11 @@ export default function DeviceSync() {
|
||||
|
||||
const renderDone = () => (
|
||||
<View className="sync-section">
|
||||
<View className="sync-result-card">
|
||||
<ContentCard className="sync-result-card">
|
||||
<Text className="sync-result-icon">V</Text>
|
||||
<Text className="sync-result-title">同步完成</Text>
|
||||
<Text className="sync-result-count">成功上传 {syncCount} 条数据</Text>
|
||||
</View>
|
||||
</ContentCard>
|
||||
<View className="sync-action" onClick={() => {
|
||||
handleDisconnect();
|
||||
if (returnTo === 'input') {
|
||||
@@ -293,7 +295,7 @@ export default function DeviceSync() {
|
||||
);
|
||||
|
||||
return (
|
||||
<View className={`device-sync-page ${modeClass}`}>
|
||||
<PageShell padding="none" className={modeClass}>
|
||||
<View className="sync-header">
|
||||
<Text className="sync-header-title">设备同步</Text>
|
||||
</View>
|
||||
@@ -317,6 +319,6 @@ export default function DeviceSync() {
|
||||
{(pageState === 'idle' || pageState === 'error') && renderIdle()}
|
||||
{pageState === 'connected' && renderConnected()}
|
||||
{pageState === 'done' && renderDone()}
|
||||
</View>
|
||||
</PageShell>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
@import '../../../styles/variables.scss';
|
||||
@import '../../../styles/mixins.scss';
|
||||
|
||||
.input-page {
|
||||
min-height: 100vh;
|
||||
background: $bg;
|
||||
padding: 0 0 60px;
|
||||
}
|
||||
// PageShell 已接管:min-height, background
|
||||
// ContentCard 已接管:input-card 背景/圆角/阴影
|
||||
|
||||
/* ── hero ── */
|
||||
.input-hero {
|
||||
@@ -47,10 +44,6 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: $card;
|
||||
border-radius: $r;
|
||||
box-shadow: $shadow-sm;
|
||||
padding: 24px 28px;
|
||||
margin: 0 24px 20px;
|
||||
border: 1px dashed $pri;
|
||||
|
||||
@@ -72,10 +65,6 @@
|
||||
|
||||
/* ── card ── */
|
||||
.input-card {
|
||||
background: $card;
|
||||
border-radius: $r;
|
||||
box-shadow: $shadow-md;
|
||||
padding: 28px;
|
||||
margin: 0 24px 20px;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ import { useSafeTimeout } from '@/hooks/useSafeTimeout';
|
||||
import { trackEvent } from '@/services/analytics';
|
||||
import { useElderClass } from '../../../hooks/useElderClass';
|
||||
import Loading from '../../../components/Loading';
|
||||
import PageShell from '@/components/ui/PageShell';
|
||||
import ContentCard from '@/components/ui/ContentCard';
|
||||
import './index.scss';
|
||||
|
||||
const INDICATORS = [
|
||||
@@ -176,7 +178,7 @@ export default function HealthInput() {
|
||||
const indicatorInitial = INDICATORS[indicatorIdx].label.charAt(0);
|
||||
|
||||
return (
|
||||
<View className={`input-page ${modeClass}`}>
|
||||
<PageShell padding="none" safeBottom className={modeClass}>
|
||||
{loadingThresholds && <Loading />}
|
||||
|
||||
{!loadingThresholds && (
|
||||
@@ -197,7 +199,7 @@ export default function HealthInput() {
|
||||
</View>
|
||||
|
||||
{/* 指标类型选择 */}
|
||||
<View className='input-card'>
|
||||
<ContentCard className='input-card'>
|
||||
<View className='input-card-header'>
|
||||
<View className='input-card-indicator'>
|
||||
<Text className='input-card-indicator-char'>{indicatorInitial}</Text>
|
||||
@@ -215,11 +217,11 @@ export default function HealthInput() {
|
||||
<Text className='input-picker-arrow'>V</Text>
|
||||
</View>
|
||||
</Picker>
|
||||
</View>
|
||||
</ContentCard>
|
||||
|
||||
{/* 数值输入 */}
|
||||
{BP_INDICATORS.includes(INDICATORS[indicatorIdx].value) ? (
|
||||
<View className='input-card'>
|
||||
<ContentCard className='input-card'>
|
||||
<Text className='input-section-title'>血压数值</Text>
|
||||
<View className='input-bp-group'>
|
||||
<View className='input-bp-field'>
|
||||
@@ -249,9 +251,9 @@ export default function HealthInput() {
|
||||
</View>
|
||||
</View>
|
||||
<Text className='input-field-unit'>mmHg</Text>
|
||||
</View>
|
||||
</ContentCard>
|
||||
) : (
|
||||
<View className='input-card'>
|
||||
<ContentCard className='input-card'>
|
||||
<Text className='input-section-title'>检测数值</Text>
|
||||
<Input
|
||||
type='digit'
|
||||
@@ -263,11 +265,11 @@ export default function HealthInput() {
|
||||
<Text className='input-field-unit'>
|
||||
{INDICATORS[indicatorIdx].label.match(/\((.+)\)/)?.[1] || ''}
|
||||
</Text>
|
||||
</View>
|
||||
</ContentCard>
|
||||
)}
|
||||
|
||||
{/* 备注 */}
|
||||
<View className='input-card'>
|
||||
<ContentCard className='input-card'>
|
||||
<Text className='input-section-title'>备注</Text>
|
||||
<Input
|
||||
className='input-field-box input-field-full'
|
||||
@@ -275,7 +277,7 @@ export default function HealthInput() {
|
||||
value={note}
|
||||
onInput={(e) => setNote(e.detail.value)}
|
||||
/>
|
||||
</View>
|
||||
</ContentCard>
|
||||
|
||||
{/* 提交 */}
|
||||
<View
|
||||
@@ -286,6 +288,6 @@ export default function HealthInput() {
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
</PageShell>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
@import '../../../styles/variables.scss';
|
||||
@import '../../../styles/mixins.scss';
|
||||
|
||||
.trend-page {
|
||||
min-height: 100vh;
|
||||
background: $bg;
|
||||
// PageShell 已接管:min-height, background
|
||||
// ContentCard 已接管:trend-chart-card 背景/圆角/阴影
|
||||
|
||||
.trend-page-shell {
|
||||
padding-bottom: 60px;
|
||||
}
|
||||
|
||||
@@ -48,10 +49,6 @@
|
||||
/* ── chart card ── */
|
||||
.trend-chart-card {
|
||||
margin: 0 24px 20px;
|
||||
background: $card;
|
||||
border-radius: $r;
|
||||
box-shadow: $shadow-md;
|
||||
padding: 24px;
|
||||
min-height: 300px;
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -59,9 +56,6 @@
|
||||
/* ── reference card ── */
|
||||
.trend-ref-card {
|
||||
margin: 0 24px 20px;
|
||||
background: $acc-l;
|
||||
border-radius: $r;
|
||||
padding: 20px 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
|
||||
@@ -8,6 +8,8 @@ import Loading from '@/components/Loading';
|
||||
import ErrorState from '@/components/ErrorState';
|
||||
import EmptyState from '@/components/EmptyState';
|
||||
import SegmentTabs from '@/components/SegmentTabs';
|
||||
import PageShell from '@/components/ui/PageShell';
|
||||
import ContentCard from '@/components/ui/ContentCard';
|
||||
import { useElderClass } from '../../../hooks/useElderClass';
|
||||
import './index.scss';
|
||||
|
||||
@@ -67,7 +69,7 @@ export default function Trend() {
|
||||
};
|
||||
|
||||
return (
|
||||
<View className={`trend-page ${modeClass}`}>
|
||||
<PageShell padding="none" className={modeClass}>
|
||||
{/* 页面标题 */}
|
||||
<View className='trend-hero'>
|
||||
<View className='trend-hero-icon'>
|
||||
@@ -81,36 +83,36 @@ export default function Trend() {
|
||||
|
||||
{/* ECharts 折线图 */}
|
||||
{loading ? (
|
||||
<View className='trend-chart-card'>
|
||||
<ContentCard className='trend-chart-card'>
|
||||
<Loading />
|
||||
</View>
|
||||
</ContentCard>
|
||||
) : error ? (
|
||||
<View className='trend-chart-card'>
|
||||
<ContentCard className='trend-chart-card'>
|
||||
<ErrorState onRetry={fetchTrend} />
|
||||
</View>
|
||||
</ContentCard>
|
||||
) : points.length === 0 ? (
|
||||
<View className='trend-chart-card'>
|
||||
<ContentCard className='trend-chart-card'>
|
||||
<EmptyState text='暂无趋势数据' />
|
||||
</View>
|
||||
</ContentCard>
|
||||
) : (
|
||||
<View className='trend-chart-card'>
|
||||
<ContentCard className='trend-chart-card'>
|
||||
<TrendChart
|
||||
data={points}
|
||||
referenceMin={meta.refMin}
|
||||
referenceMax={meta.refMax}
|
||||
unit={meta.unit}
|
||||
/>
|
||||
</View>
|
||||
</ContentCard>
|
||||
)}
|
||||
|
||||
{/* 参考区间 */}
|
||||
{!loading && points.length > 0 && meta.refMin !== undefined && meta.refMax !== undefined && (
|
||||
<View className='trend-ref-card'>
|
||||
<ContentCard variant="outlined" className='trend-ref-card'>
|
||||
<Text className='trend-ref-label'>参考区间</Text>
|
||||
<Text className='trend-ref-value'>
|
||||
{meta.refMin} ~ {meta.refMax} {meta.unit}
|
||||
</Text>
|
||||
</View>
|
||||
</ContentCard>
|
||||
)}
|
||||
|
||||
{/* 数据列表 */}
|
||||
@@ -135,6 +137,6 @@ export default function Trend() {
|
||||
})}
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</PageShell>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user