refactor(mp): 迁移医护+健康页面 — 使用 PageShell + ContentCard 统一组件库

行动收件箱、医护工作台、健康趋势、患者告警、体征录入、
日常监测、设备同步共 7 个页面迁移:
- 最外层容器 → PageShell
- 卡片元素 → ContentCard
- SCSS 删除 min-height/background/box-shadow 通用样式
This commit is contained in:
iven
2026-05-16 01:33:24 +08:00
parent 4dd5a1b4d9
commit 37327a4da4
14 changed files with 86 additions and 124 deletions

View File

@@ -1,10 +1,8 @@
@import '../../../styles/variables.scss'; @import '../../styles/variables.scss';
@import '../../../styles/mixins.scss'; @import '../../styles/mixins.scss';
.action-inbox-page { // PageShell 已接管min-height, background
min-height: 100vh; // ContentCard 已接管inbox-card 背景/圆角/阴影/触摸反馈
background: $bg;
}
.inbox-list { .inbox-list {
height: calc(100vh - 50px); height: calc(100vh - 50px);
@@ -12,11 +10,7 @@
} }
.inbox-card { .inbox-card {
background: $card;
border-radius: $r-sm;
padding: 14px 16px;
margin-bottom: 10px; margin-bottom: 10px;
box-shadow: $shadow-sm;
.inbox-card-header { .inbox-card-header {
display: flex; display: flex;

View File

@@ -13,6 +13,8 @@ import Loading from '@/components/Loading';
import ErrorState from '@/components/ErrorState'; import ErrorState from '@/components/ErrorState';
import EmptyState from '@/components/EmptyState'; import EmptyState from '@/components/EmptyState';
import SegmentTabs from '@/components/SegmentTabs'; import SegmentTabs from '@/components/SegmentTabs';
import PageShell from '@/components/ui/PageShell';
import ContentCard from '@/components/ui/ContentCard';
import { useElderClass } from '../../../hooks/useElderClass'; import { useElderClass } from '../../../hooks/useElderClass';
import './index.scss'; import './index.scss';
@@ -119,7 +121,7 @@ export default function ActionInboxPage() {
}; };
return ( return (
<View className={`action-inbox-page ${modeClass}`}> <PageShell padding="none" className={modeClass}>
<SegmentTabs tabs={STATUS_TABS} activeKey={activeTab} onChange={handleTabChange} variant="underline" /> <SegmentTabs tabs={STATUS_TABS} activeKey={activeTab} onChange={handleTabChange} variant="underline" />
{error ? ( {error ? (
@@ -129,10 +131,11 @@ export default function ActionInboxPage() {
) : ( ) : (
<ScrollView scrollY className="inbox-list"> <ScrollView scrollY className="inbox-list">
{items.map((item) => ( {items.map((item) => (
<View <ContentCard
key={item.id} key={item.id}
className="inbox-card" className="inbox-card"
onClick={() => handleItemClick(item)} activeFeedback="opacity"
onPress={() => handleItemClick(item)}
> >
<View className="inbox-card-header"> <View className="inbox-card-header">
<Text <Text
@@ -146,7 +149,7 @@ export default function ActionInboxPage() {
{item.patient_name} ·{' '} {item.patient_name} ·{' '}
{new Date(item.created_at).toLocaleDateString('zh-CN')} {new Date(item.created_at).toLocaleDateString('zh-CN')}
</Text> </Text>
</View> </ContentCard>
))} ))}
{loading && <Loading />} {loading && <Loading />}
{!loading && items.length >= total && total > 0 && ( {!loading && items.length >= total && total > 0 && (
@@ -208,6 +211,6 @@ export default function ActionInboxPage() {
)} )}
</View> </View>
)} )}
</View> </PageShell>
); );
} }

View File

@@ -1,11 +1,9 @@
@import '../../styles/variables.scss'; @import '../../styles/variables.scss';
@import '../../styles/mixins.scss'; @import '../../styles/mixins.scss';
// PageShell 已接管min-height, background, padding
.doctor-home { .doctor-home {
min-height: 100vh;
background: $bg;
padding: 32px;
padding-bottom: calc(160px + env(safe-area-inset-bottom));
&__header { &__header {
margin-bottom: 40px; margin-bottom: 40px;

View File

@@ -1,11 +1,12 @@
import { useState, useMemo, useCallback } from 'react'; 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 Taro from '@tarojs/taro';
import { useAuthStore } from '@/stores/auth'; import { useAuthStore } from '@/stores/auth';
import { useElderClass } from '../../hooks/useElderClass'; import { useElderClass } from '../../hooks/useElderClass';
import { usePageData } from '@/hooks/usePageData'; import { usePageData } from '@/hooks/usePageData';
import { getDashboard, type DoctorDashboard } from '@/services/doctor/dashboard'; import { getDashboard, type DoctorDashboard } from '@/services/doctor/dashboard';
import Loading from '@/components/Loading'; import Loading from '@/components/Loading';
import PageShell from '@/components/ui/PageShell';
import './index.scss'; import './index.scss';
interface CardConfig { interface CardConfig {
@@ -107,7 +108,7 @@ export default function DoctorHome() {
if (loading) return <Loading />; if (loading) return <Loading />;
return ( return (
<ScrollView scrollY className={`doctor-home ${modeClass}`}> <PageShell safeBottom={false} className={`doctor-home ${modeClass}`}>
<View className='doctor-home__header'> <View className='doctor-home__header'>
<Text className='doctor-home__title'></Text> <Text className='doctor-home__title'></Text>
<Text className='doctor-home__greeting'> <Text className='doctor-home__greeting'>
@@ -192,6 +193,6 @@ export default function DoctorHome() {
<View className='doctor-home__footer'> <View className='doctor-home__footer'>
<Text className='doctor-home__logout' onClick={handleLogout}>退</Text> <Text className='doctor-home__logout' onClick={handleLogout}>退</Text>
</View> </View>
</ScrollView> </PageShell>
); );
} }

View File

@@ -1,11 +1,8 @@
@import '../../../styles/variables.scss'; @import '../../../styles/variables.scss';
@import '../../../styles/mixins.scss'; @import '../../../styles/mixins.scss';
.alerts-page { // PageShell 已接管min-height, background, safe-bottom
min-height: 100vh; // ContentCard 已接管alert-card 背景/圆角/阴影
background: $bg;
padding-bottom: env(safe-area-inset-bottom);
}
.alerts-tabs { .alerts-tabs {
display: flex; display: flex;
@@ -39,11 +36,7 @@
} }
.alert-card { .alert-card {
background: $card;
border-radius: $r;
padding: 24px;
margin-bottom: 16px; margin-bottom: 16px;
box-shadow: $shadow-sm;
} }
.alert-header { .alert-header {

View File

@@ -8,6 +8,8 @@ import Loading from '@/components/Loading';
import ErrorState from '@/components/ErrorState'; import ErrorState from '@/components/ErrorState';
import EmptyState from '@/components/EmptyState'; import EmptyState from '@/components/EmptyState';
import SegmentTabs from '@/components/SegmentTabs'; import SegmentTabs from '@/components/SegmentTabs';
import PageShell from '@/components/ui/PageShell';
import ContentCard from '@/components/ui/ContentCard';
import { useElderClass } from '../../../hooks/useElderClass'; import { useElderClass } from '../../../hooks/useElderClass';
import './index.scss'; import './index.scss';
@@ -79,23 +81,23 @@ export default function PatientAlerts() {
if (!currentPatient) { if (!currentPatient) {
return ( return (
<View className={`alerts-page ${modeClass}`}> <PageShell padding="none" className={modeClass}>
<ErrorState text='请先完善个人档案' onRetry={() => Taro.navigateTo({ url: '/pages/pkg-profile/family-add/index' })} /> <ErrorState text='请先完善个人档案' onRetry={() => Taro.navigateTo({ url: '/pages/pkg-profile/family-add/index' })} />
</View> </PageShell>
); );
} }
if (error) { if (error) {
return ( return (
<View className={`alerts-page ${modeClass}`}> <PageShell padding="none" className={modeClass}>
<SegmentTabs tabs={STATUS_TABS} activeKey={status} onChange={handleTabChange} variant="pill" /> <SegmentTabs tabs={STATUS_TABS} activeKey={status} onChange={handleTabChange} variant="pill" />
<ErrorState onRetry={() => fetchAlerts(1, status, true)} /> <ErrorState onRetry={() => fetchAlerts(1, status, true)} />
</View> </PageShell>
); );
} }
return ( return (
<View className={`alerts-page ${modeClass}`}> <PageShell padding="none" className={modeClass}>
<SegmentTabs tabs={STATUS_TABS} activeKey={status} onChange={handleTabChange} variant="pill" /> <SegmentTabs tabs={STATUS_TABS} activeKey={status} onChange={handleTabChange} variant="pill" />
{alerts.length === 0 && !loading ? ( {alerts.length === 0 && !loading ? (
@@ -105,7 +107,7 @@ export default function PatientAlerts() {
{alerts.map((item) => { {alerts.map((item) => {
const sev = SEVERITY_MAP[item.severity] || SEVERITY_MAP.warning; const sev = SEVERITY_MAP[item.severity] || SEVERITY_MAP.warning;
return ( return (
<View className='alert-card' key={item.id}> <ContentCard className='alert-card' key={item.id}>
<View className='alert-header'> <View className='alert-header'>
<View className={`alert-badge ${sev.className}`}> <View className={`alert-badge ${sev.className}`}>
<Text className='alert-badge-text'>{sev.label}</Text> <Text className='alert-badge-text'>{sev.label}</Text>
@@ -115,7 +117,7 @@ export default function PatientAlerts() {
</Text> </Text>
</View> </View>
<Text className='alert-title'>{item.title}</Text> <Text className='alert-title'>{item.title}</Text>
</View> </ContentCard>
); );
})} })}
{loading && <Loading />} {loading && <Loading />}
@@ -124,6 +126,6 @@ export default function PatientAlerts() {
)} )}
</View> </View>
)} )}
</View> </PageShell>
); );
} }

View File

@@ -1,11 +1,8 @@
@import '../../../styles/variables.scss'; @import '../../../styles/variables.scss';
@import '../../../styles/mixins.scss'; @import '../../../styles/mixins.scss';
.dm-page { // PageShell 已接管min-height, background
min-height: 100vh; // ContentCard 已接管dm-card/dm-group 背景/圆角/阴影
background: $bg;
padding: 0 0 60px;
}
/* ── hero ── */ /* ── hero ── */
.dm-hero { .dm-hero {
@@ -44,10 +41,6 @@
/* ── card (standalone, used for date picker) ── */ /* ── card (standalone, used for date picker) ── */
.dm-card { .dm-card {
background: $card;
border-radius: $r;
box-shadow: $shadow-md;
padding: 28px;
margin: 0 24px 20px; margin: 0 24px 20px;
} }
@@ -98,9 +91,6 @@
/* ── collapsible group ── */ /* ── collapsible group ── */
.dm-group { .dm-group {
background: $card;
border-radius: $r;
box-shadow: $shadow-md;
margin: 0 24px 20px; margin: 0 24px 20px;
overflow: hidden; overflow: hidden;
} }

View File

@@ -10,6 +10,8 @@ import { clearRequestCache } from '@/services/request';
import { trackEvent } from '@/services/analytics'; import { trackEvent } from '@/services/analytics';
import { useSafeTimeout } from '@/hooks/useSafeTimeout'; import { useSafeTimeout } from '@/hooks/useSafeTimeout';
import { useElderClass } from '@/hooks/useElderClass'; import { useElderClass } from '@/hooks/useElderClass';
import PageShell from '@/components/ui/PageShell';
import ContentCard from '@/components/ui/ContentCard';
import { import {
BP_RANGE, WEIGHT_RANGE, SUGAR_RANGE, VOLUME_RANGE, BP_RANGE, WEIGHT_RANGE, SUGAR_RANGE, VOLUME_RANGE,
checkAbnormal, formatDate, FIELD_LABELS, checkAbnormal, formatDate, FIELD_LABELS,
@@ -218,7 +220,7 @@ export default function DailyMonitoring() {
const bloodSugarAbnormal = checkAbnormal(bloodSugar, 'bloodSugar'); const bloodSugarAbnormal = checkAbnormal(bloodSugar, 'bloodSugar');
return ( return (
<View className={`dm-page ${modeClass}`}> <PageShell padding="none" safeBottom className={modeClass}>
{/* 页面标题 */} {/* 页面标题 */}
<View className='dm-hero'> <View className='dm-hero'>
<View className='dm-hero-icon'> <View className='dm-hero-icon'>
@@ -229,7 +231,7 @@ export default function DailyMonitoring() {
</View> </View>
{/* 日期选择 (standalone card) */} {/* 日期选择 (standalone card) */}
<View className='dm-card'> <ContentCard className='dm-card'>
<View className='dm-card-header'> <View className='dm-card-header'>
<Text className='dm-card-title'></Text> <Text className='dm-card-title'></Text>
{isToday && ( {isToday && (
@@ -247,10 +249,10 @@ export default function DailyMonitoring() {
<Text className='dm-date-arrow'>V</Text> <Text className='dm-date-arrow'>V</Text>
</View> </View>
</Picker> </Picker>
</View> </ContentCard>
{/* ── Group 1: 晨间体征 (default open) ── */} {/* ── 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')}> <View className='dm-group-header' onClick={() => toggleSection('morning')}>
<Text className='dm-group-title'></Text> <Text className='dm-group-title'></Text>
<Text className={`dm-group-arrow${collapsed.morning ? '' : ' dm-group-arrow-open'}`}>&#9656;</Text> <Text className={`dm-group-arrow${collapsed.morning ? '' : ' dm-group-arrow-open'}`}>&#9656;</Text>
@@ -295,10 +297,10 @@ export default function DailyMonitoring() {
</View> </View>
<Text className='dm-field-unit'>mmHg</Text> <Text className='dm-field-unit'>mmHg</Text>
</View> </View>
</View> </ContentCard>
{/* ── Group 2: 晚间体征 (default open) ── */} {/* ── 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')}> <View className='dm-group-header' onClick={() => toggleSection('evening')}>
<Text className='dm-group-title'></Text> <Text className='dm-group-title'></Text>
<Text className={`dm-group-arrow${collapsed.evening ? '' : ' dm-group-arrow-open'}`}>&#9656;</Text> <Text className={`dm-group-arrow${collapsed.evening ? '' : ' dm-group-arrow-open'}`}>&#9656;</Text>
@@ -343,10 +345,10 @@ export default function DailyMonitoring() {
</View> </View>
<Text className='dm-field-unit'>mmHg</Text> <Text className='dm-field-unit'>mmHg</Text>
</View> </View>
</View> </ContentCard>
{/* ── Group 3: 其他指标 (default collapsed) ── */} {/* ── 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')}> <View className='dm-group-header' onClick={() => toggleSection('other')}>
<Text className='dm-group-title'></Text> <Text className='dm-group-title'></Text>
<Text className={`dm-group-arrow${collapsed.other ? '' : ' dm-group-arrow-open'}`}>&#9656;</Text> <Text className={`dm-group-arrow${collapsed.other ? '' : ' dm-group-arrow-open'}`}>&#9656;</Text>
@@ -428,7 +430,7 @@ export default function DailyMonitoring() {
/> />
</View> </View>
</View> </View>
</View> </ContentCard>
{/* 提交 */} {/* 提交 */}
<View <View
@@ -442,6 +444,6 @@ export default function DailyMonitoring() {
<View className='dm-reset' onClick={resetForm}> <View className='dm-reset' onClick={resetForm}>
<Text className='dm-reset-text'></Text> <Text className='dm-reset-text'></Text>
</View> </View>
</View> </PageShell>
); );
} }

View File

@@ -1,11 +1,8 @@
@import '../../../styles/variables.scss'; @import '../../../styles/variables.scss';
@import '../../../styles/mixins.scss'; @import '../../../styles/mixins.scss';
.device-sync-page { // PageShell 已接管min-height, background, safe-bottom
min-height: 100vh; // ContentCard 已接管sync-status-card/sync-result-card 背景/圆角/阴影
background: $bg;
padding-bottom: env(safe-area-inset-bottom);
}
.sync-header { .sync-header {
background: $pri; background: $pri;
@@ -130,11 +127,7 @@
.sync-status-card { .sync-status-card {
display: flex; display: flex;
align-items: center; align-items: center;
background: $card;
border-radius: $r-sm;
padding: 24px;
margin-bottom: 16px; margin-bottom: 16px;
box-shadow: $shadow-sm;
} }
.sync-status-dot { .sync-status-dot {
@@ -225,9 +218,6 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
background: $card;
border-radius: $r;
padding: 48px 24px;
margin-bottom: 24px; margin-bottom: 24px;
box-shadow: $shadow-sm; box-shadow: $shadow-sm;
} }

View File

@@ -12,6 +12,8 @@ import { uploadReadings } from '@/services/device-sync';
import { useAuthStore } from '@/stores/auth'; import { useAuthStore } from '@/stores/auth';
import type { BLEDevice, NormalizedReading } from '@/services/ble/types'; import type { BLEDevice, NormalizedReading } from '@/services/ble/types';
import { useElderClass } from '@/hooks/useElderClass'; import { useElderClass } from '@/hooks/useElderClass';
import PageShell from '@/components/ui/PageShell';
import ContentCard from '@/components/ui/ContentCard';
import './index.scss'; import './index.scss';
/** liveReadings 最大保留条数,防止内存无限增长 */ /** liveReadings 最大保留条数,防止内存无限增长 */
@@ -232,10 +234,10 @@ export default function DeviceSync() {
const renderConnected = () => ( const renderConnected = () => (
<View className="sync-section"> <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-dot sync-status-dot--connected" />
<Text className="sync-status-text">: {selectedDevice?.name}</Text> <Text className="sync-status-text">: {selectedDevice?.name}</Text>
</View> </ContentCard>
{liveReadings.length > 0 && ( {liveReadings.length > 0 && (
<View className="sync-readings-panel"> <View className="sync-readings-panel">
@@ -276,11 +278,11 @@ export default function DeviceSync() {
const renderDone = () => ( const renderDone = () => (
<View className="sync-section"> <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-icon">V</Text>
<Text className="sync-result-title"></Text> <Text className="sync-result-title"></Text>
<Text className="sync-result-count"> {syncCount} </Text> <Text className="sync-result-count"> {syncCount} </Text>
</View> </ContentCard>
<View className="sync-action" onClick={() => { <View className="sync-action" onClick={() => {
handleDisconnect(); handleDisconnect();
if (returnTo === 'input') { if (returnTo === 'input') {
@@ -293,7 +295,7 @@ export default function DeviceSync() {
); );
return ( return (
<View className={`device-sync-page ${modeClass}`}> <PageShell padding="none" className={modeClass}>
<View className="sync-header"> <View className="sync-header">
<Text className="sync-header-title"></Text> <Text className="sync-header-title"></Text>
</View> </View>
@@ -317,6 +319,6 @@ export default function DeviceSync() {
{(pageState === 'idle' || pageState === 'error') && renderIdle()} {(pageState === 'idle' || pageState === 'error') && renderIdle()}
{pageState === 'connected' && renderConnected()} {pageState === 'connected' && renderConnected()}
{pageState === 'done' && renderDone()} {pageState === 'done' && renderDone()}
</View> </PageShell>
); );
} }

View File

@@ -1,11 +1,8 @@
@import '../../../styles/variables.scss'; @import '../../../styles/variables.scss';
@import '../../../styles/mixins.scss'; @import '../../../styles/mixins.scss';
.input-page { // PageShell 已接管min-height, background
min-height: 100vh; // ContentCard 已接管input-card 背景/圆角/阴影
background: $bg;
padding: 0 0 60px;
}
/* ── hero ── */ /* ── hero ── */
.input-hero { .input-hero {
@@ -47,10 +44,6 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
background: $card;
border-radius: $r;
box-shadow: $shadow-sm;
padding: 24px 28px;
margin: 0 24px 20px; margin: 0 24px 20px;
border: 1px dashed $pri; border: 1px dashed $pri;
@@ -72,10 +65,6 @@
/* ── card ── */ /* ── card ── */
.input-card { .input-card {
background: $card;
border-radius: $r;
box-shadow: $shadow-md;
padding: 28px;
margin: 0 24px 20px; margin: 0 24px 20px;
} }

View File

@@ -12,6 +12,8 @@ import { useSafeTimeout } from '@/hooks/useSafeTimeout';
import { trackEvent } from '@/services/analytics'; import { trackEvent } from '@/services/analytics';
import { useElderClass } from '../../../hooks/useElderClass'; import { useElderClass } from '../../../hooks/useElderClass';
import Loading from '../../../components/Loading'; import Loading from '../../../components/Loading';
import PageShell from '@/components/ui/PageShell';
import ContentCard from '@/components/ui/ContentCard';
import './index.scss'; import './index.scss';
const INDICATORS = [ const INDICATORS = [
@@ -176,7 +178,7 @@ export default function HealthInput() {
const indicatorInitial = INDICATORS[indicatorIdx].label.charAt(0); const indicatorInitial = INDICATORS[indicatorIdx].label.charAt(0);
return ( return (
<View className={`input-page ${modeClass}`}> <PageShell padding="none" safeBottom className={modeClass}>
{loadingThresholds && <Loading />} {loadingThresholds && <Loading />}
{!loadingThresholds && ( {!loadingThresholds && (
@@ -197,7 +199,7 @@ export default function HealthInput() {
</View> </View>
{/* 指标类型选择 */} {/* 指标类型选择 */}
<View className='input-card'> <ContentCard className='input-card'>
<View className='input-card-header'> <View className='input-card-header'>
<View className='input-card-indicator'> <View className='input-card-indicator'>
<Text className='input-card-indicator-char'>{indicatorInitial}</Text> <Text className='input-card-indicator-char'>{indicatorInitial}</Text>
@@ -215,11 +217,11 @@ export default function HealthInput() {
<Text className='input-picker-arrow'>V</Text> <Text className='input-picker-arrow'>V</Text>
</View> </View>
</Picker> </Picker>
</View> </ContentCard>
{/* 数值输入 */} {/* 数值输入 */}
{BP_INDICATORS.includes(INDICATORS[indicatorIdx].value) ? ( {BP_INDICATORS.includes(INDICATORS[indicatorIdx].value) ? (
<View className='input-card'> <ContentCard className='input-card'>
<Text className='input-section-title'></Text> <Text className='input-section-title'></Text>
<View className='input-bp-group'> <View className='input-bp-group'>
<View className='input-bp-field'> <View className='input-bp-field'>
@@ -249,9 +251,9 @@ export default function HealthInput() {
</View> </View>
</View> </View>
<Text className='input-field-unit'>mmHg</Text> <Text className='input-field-unit'>mmHg</Text>
</View> </ContentCard>
) : ( ) : (
<View className='input-card'> <ContentCard className='input-card'>
<Text className='input-section-title'></Text> <Text className='input-section-title'></Text>
<Input <Input
type='digit' type='digit'
@@ -263,11 +265,11 @@ export default function HealthInput() {
<Text className='input-field-unit'> <Text className='input-field-unit'>
{INDICATORS[indicatorIdx].label.match(/\((.+)\)/)?.[1] || ''} {INDICATORS[indicatorIdx].label.match(/\((.+)\)/)?.[1] || ''}
</Text> </Text>
</View> </ContentCard>
)} )}
{/* 备注 */} {/* 备注 */}
<View className='input-card'> <ContentCard className='input-card'>
<Text className='input-section-title'></Text> <Text className='input-section-title'></Text>
<Input <Input
className='input-field-box input-field-full' className='input-field-box input-field-full'
@@ -275,7 +277,7 @@ export default function HealthInput() {
value={note} value={note}
onInput={(e) => setNote(e.detail.value)} onInput={(e) => setNote(e.detail.value)}
/> />
</View> </ContentCard>
{/* 提交 */} {/* 提交 */}
<View <View
@@ -286,6 +288,6 @@ export default function HealthInput() {
</View> </View>
</> </>
)} )}
</View> </PageShell>
); );
} }

View File

@@ -1,9 +1,10 @@
@import '../../../styles/variables.scss'; @import '../../../styles/variables.scss';
@import '../../../styles/mixins.scss'; @import '../../../styles/mixins.scss';
.trend-page { // PageShell 已接管min-height, background
min-height: 100vh; // ContentCard 已接管trend-chart-card 背景/圆角/阴影
background: $bg;
.trend-page-shell {
padding-bottom: 60px; padding-bottom: 60px;
} }
@@ -48,10 +49,6 @@
/* ── chart card ── */ /* ── chart card ── */
.trend-chart-card { .trend-chart-card {
margin: 0 24px 20px; margin: 0 24px 20px;
background: $card;
border-radius: $r;
box-shadow: $shadow-md;
padding: 24px;
min-height: 300px; min-height: 300px;
overflow: hidden; overflow: hidden;
} }
@@ -59,9 +56,6 @@
/* ── reference card ── */ /* ── reference card ── */
.trend-ref-card { .trend-ref-card {
margin: 0 24px 20px; margin: 0 24px 20px;
background: $acc-l;
border-radius: $r;
padding: 20px 24px;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 16px; gap: 16px;

View File

@@ -8,6 +8,8 @@ import Loading from '@/components/Loading';
import ErrorState from '@/components/ErrorState'; import ErrorState from '@/components/ErrorState';
import EmptyState from '@/components/EmptyState'; import EmptyState from '@/components/EmptyState';
import SegmentTabs from '@/components/SegmentTabs'; import SegmentTabs from '@/components/SegmentTabs';
import PageShell from '@/components/ui/PageShell';
import ContentCard from '@/components/ui/ContentCard';
import { useElderClass } from '../../../hooks/useElderClass'; import { useElderClass } from '../../../hooks/useElderClass';
import './index.scss'; import './index.scss';
@@ -67,7 +69,7 @@ export default function Trend() {
}; };
return ( return (
<View className={`trend-page ${modeClass}`}> <PageShell padding="none" className={modeClass}>
{/* 页面标题 */} {/* 页面标题 */}
<View className='trend-hero'> <View className='trend-hero'>
<View className='trend-hero-icon'> <View className='trend-hero-icon'>
@@ -81,36 +83,36 @@ export default function Trend() {
{/* ECharts 折线图 */} {/* ECharts 折线图 */}
{loading ? ( {loading ? (
<View className='trend-chart-card'> <ContentCard className='trend-chart-card'>
<Loading /> <Loading />
</View> </ContentCard>
) : error ? ( ) : error ? (
<View className='trend-chart-card'> <ContentCard className='trend-chart-card'>
<ErrorState onRetry={fetchTrend} /> <ErrorState onRetry={fetchTrend} />
</View> </ContentCard>
) : points.length === 0 ? ( ) : points.length === 0 ? (
<View className='trend-chart-card'> <ContentCard className='trend-chart-card'>
<EmptyState text='暂无趋势数据' /> <EmptyState text='暂无趋势数据' />
</View> </ContentCard>
) : ( ) : (
<View className='trend-chart-card'> <ContentCard className='trend-chart-card'>
<TrendChart <TrendChart
data={points} data={points}
referenceMin={meta.refMin} referenceMin={meta.refMin}
referenceMax={meta.refMax} referenceMax={meta.refMax}
unit={meta.unit} unit={meta.unit}
/> />
</View> </ContentCard>
)} )}
{/* 参考区间 */} {/* 参考区间 */}
{!loading && points.length > 0 && meta.refMin !== undefined && meta.refMax !== undefined && ( {!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-label'></Text>
<Text className='trend-ref-value'> <Text className='trend-ref-value'>
{meta.refMin} ~ {meta.refMax} {meta.unit} {meta.refMin} ~ {meta.refMax} {meta.unit}
</Text> </Text>
</View> </ContentCard>
)} )}
{/* 数据列表 */} {/* 数据列表 */}
@@ -135,6 +137,6 @@ export default function Trend() {
})} })}
</View> </View>
)} )}
</View> </PageShell>
); );
} }