refactor(mp): 迁移医生临床详情页 — 使用统一组件库 (4/12)

告警详情、报告详情、处方详情、透析详情页:
- ScrollView → PageShell 替代手写 min-height/bg/padding
- .section / .alert-detail-card → ContentCard 替代手写卡片样式
- 删除通用 page 容器和 card 样式,保留业务布局样式
This commit is contained in:
iven
2026-05-16 01:16:16 +08:00
parent 8d41d5a167
commit 5e230ba1b5
8 changed files with 67 additions and 117 deletions

View File

@@ -1,13 +1,6 @@
@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;
@@ -77,12 +70,6 @@
}
.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;

View File

@@ -1,5 +1,5 @@
import { useState, useCallback } from 'react';
import { View, Text, ScrollView, Button } from '@tarojs/components';
import { View, Text, Button } from '@tarojs/components';
import Taro from '@tarojs/taro';
import { usePageData } from '@/hooks/usePageData';
import {
@@ -7,6 +7,8 @@ import {
type Alert,
} from '@/services/doctor/alerts';
import Loading from '@/components/Loading';
import PageShell from '@/components/ui/PageShell';
import ContentCard from '@/components/ui/ContentCard';
import { useElderClass } from '../../../../hooks/useElderClass';
import './index.scss';
@@ -91,9 +93,9 @@ export default function AlertDetail() {
if (loading) return <Loading />;
if (!alert) {
return (
<View className={`alert-detail-page ${modeClass}`}>
<PageShell className={modeClass}>
<Text></Text>
</View>
</PageShell>
);
}
@@ -103,7 +105,7 @@ export default function AlertDetail() {
const isAcknowledged = alert.status === 'acknowledged';
return (
<ScrollView scrollY className={`alert-detail-page ${modeClass}`}>
<PageShell className={modeClass}>
{/* 顶部状态 */}
<View className='alert-detail-header'>
<View className='alert-detail-header__tags'>
@@ -120,55 +122,55 @@ export default function AlertDetail() {
</View>
{/* 告警信息 */}
<View className='alert-detail-card'>
<ContentCard>
<Text className='alert-detail-card__label'></Text>
<Text className='alert-detail-card__value'>{alert.title}</Text>
</View>
</ContentCard>
<View className='alert-detail-card'>
<ContentCard>
<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>
</ContentCard>
<View className='alert-detail-card'>
<ContentCard>
<Text className='alert-detail-card__label'></Text>
<Text className='alert-detail-card__value'>{severity.label}</Text>
</View>
</ContentCard>
{alert.detail && (
<View className='alert-detail-card'>
<ContentCard>
<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>
</ContentCard>
)}
{alert.acknowledged_by && (
<View className='alert-detail-card'>
<ContentCard>
<Text className='alert-detail-card__label'></Text>
<Text className='alert-detail-card__value'>{alert.acknowledged_by}</Text>
</View>
</ContentCard>
)}
{alert.acknowledged_at && (
<View className='alert-detail-card'>
<ContentCard>
<Text className='alert-detail-card__label'></Text>
<Text className='alert-detail-card__value'>
{new Date(alert.acknowledged_at).toLocaleString('zh-CN')}
</Text>
</View>
</ContentCard>
)}
{alert.resolved_at && (
<View className='alert-detail-card'>
<ContentCard>
<Text className='alert-detail-card__label'></Text>
<Text className='alert-detail-card__value'>
{new Date(alert.resolved_at).toLocaleString('zh-CN')}
</Text>
</View>
</ContentCard>
)}
{/* 操作按钮 */}
@@ -203,6 +205,6 @@ export default function AlertDetail() {
)}
</View>
)}
</ScrollView>
</PageShell>
);
}

View File

@@ -1,21 +1,6 @@
@import '../../../../styles/variables.scss';
@import '../../../../styles/mixins.scss';
.dialysis-detail {
min-height: 100vh;
background: $bg;
padding: 24px;
padding-bottom: 200px;
}
.section {
background: $card;
border-radius: $r;
padding: 24px;
margin-bottom: 16px;
box-shadow: $shadow-sm;
}
.section-title {
font-size: var(--tk-font-body-lg);
font-weight: bold;

View File

@@ -1,5 +1,5 @@
import { useState, useCallback } from 'react';
import { View, Text, ScrollView } from '@tarojs/components';
import { View, Text } from '@tarojs/components';
import Taro, { useRouter } from '@tarojs/taro';
import { usePageData } from '@/hooks/usePageData';
import {
@@ -8,6 +8,8 @@ import {
type DialysisRecord,
} from '@/services/doctor/dialysis';
import Loading from '@/components/Loading';
import PageShell from '@/components/ui/PageShell';
import ContentCard from '@/components/ui/ContentCard';
import { useElderClass } from '../../../../hooks/useElderClass';
import { useSafeTimeout } from '@/hooks/useSafeTimeout';
import './index.scss';
@@ -93,15 +95,15 @@ export default function DialysisDetail() {
};
if (loading) return <Loading />;
if (!record) return <View className={`error-text ${modeClass}`}><Text></Text></View>;
if (!record) return <PageShell className={modeClass}><View className='error-text'><Text></Text></View></PageShell>;
const canComplete = record.status === 'draft';
const canReview = record.status === 'completed';
return (
<ScrollView scrollY className={`dialysis-detail ${modeClass}`}>
<PageShell className={modeClass}>
{/* 状态头部 */}
<View className='section'>
<ContentCard>
<View className='record-header'>
<Text className='record-header__title'>{record.dialysis_date}</Text>
<Text className={`record-header__status record-header__status--${record.status}`}>
@@ -112,10 +114,10 @@ export default function DialysisDetail() {
{(record.dialysis_type === 'HD' ? '血液透析' : record.dialysis_type === 'HDF' ? '血液透析滤过' : record.dialysis_type === 'HF' ? '血液滤过' : record.dialysis_type)}
</Text>
{record.reviewed_at && <Text className='review-info'> {record.reviewed_at}</Text>}
</View>
</ContentCard>
{/* 基本信息 */}
<View className='section'>
<ContentCard>
<Text className='section-title'></Text>
<Row label='透析日期' value={record.dialysis_date} />
<Row label='开始时间' value={record.start_time} />
@@ -123,10 +125,10 @@ export default function DialysisDetail() {
<Row label='透析时长' value={record.dialysis_duration} unit=' 分钟' />
<Row label='血流速' value={record.blood_flow_rate} unit=' ml/min' />
<Row label='超滤量' value={record.ultrafiltration_volume} unit=' ml' />
</View>
</ContentCard>
{/* 体重与血压 */}
<View className='section'>
<ContentCard>
<Text className='section-title'></Text>
<Row label='干体重' value={record.dry_weight} unit=' kg' />
<Row label='透前体重' value={record.pre_weight} unit=' kg' />
@@ -139,17 +141,17 @@ export default function DialysisDetail() {
)}
<Row label='透前心率' value={record.pre_heart_rate} unit=' bpm' />
<Row label='透后心率' value={record.post_heart_rate} unit=' bpm' />
</View>
</ContentCard>
{/* 症状与并发症 */}
{(record.symptoms || record.complication_notes) && (
<View className='section'>
<ContentCard>
<Text className='section-title'></Text>
{record.symptoms && (
<Row label='症状' value={JSON.stringify(record.symptoms)} />
)}
<Row label='并发症备注' value={record.complication_notes} />
</View>
</ContentCard>
)}
{/* 操作按钮 */}
@@ -175,6 +177,6 @@ export default function DialysisDetail() {
<Text className='action-btn__text'></Text>
</View>
</View>
</ScrollView>
</PageShell>
);
}

View File

@@ -1,21 +1,6 @@
@import '../../../../styles/variables.scss';
@import '../../../../styles/mixins.scss';
.prescription-detail {
min-height: 100vh;
background: $bg;
padding: 24px;
padding-bottom: 200px;
}
.section {
background: $card;
border-radius: $r;
padding: 24px;
margin-bottom: 16px;
box-shadow: $shadow-sm;
}
.section-title {
font-size: var(--tk-font-body-lg);
font-weight: bold;

View File

@@ -1,5 +1,5 @@
import { useState, useCallback } from 'react';
import { View, Text, ScrollView } from '@tarojs/components';
import { View, Text } from '@tarojs/components';
import Taro, { useRouter } from '@tarojs/taro';
import { usePageData } from '@/hooks/usePageData';
import {
@@ -7,6 +7,8 @@ import {
type DialysisPrescription,
} from '@/services/doctor/dialysis';
import Loading from '@/components/Loading';
import PageShell from '@/components/ui/PageShell';
import ContentCard from '@/components/ui/ContentCard';
import { useElderClass } from '../../../../hooks/useElderClass';
import { useSafeTimeout } from '@/hooks/useSafeTimeout';
import './index.scss';
@@ -83,12 +85,12 @@ export default function PrescriptionDetail() {
};
if (loading) return <Loading />;
if (!rx) return <View className={`error-text ${modeClass}`}><Text></Text></View>;
if (!rx) return <PageShell className={modeClass}><View className='error-text'><Text></Text></View></PageShell>;
return (
<ScrollView scrollY className={`prescription-detail ${modeClass}`}>
<PageShell className={modeClass}>
{/* 状态头部 */}
<View className='section'>
<ContentCard>
<View className='rx-header'>
<Text className='rx-header__title'>{rx.dialyzer_model || '透析处方'}</Text>
<Text className={`rx-header__status rx-header__status--${rx.status}`}>
@@ -98,10 +100,10 @@ export default function PrescriptionDetail() {
{(rx.effective_from || rx.effective_to) && (
<Text className='rx-sub'>{rx.effective_from || '...'} ~ {rx.effective_to || '...'}</Text>
)}
</View>
</ContentCard>
{/* 基本参数 */}
<View className='section'>
<ContentCard>
<Text className='section-title'></Text>
<Row label='透析器型号' value={rx.dialyzer_model} />
<Row label='膜面积' value={rx.membrane_area != null ? `${rx.membrane_area}` : null} unit=' m²' />
@@ -109,47 +111,47 @@ export default function PrescriptionDetail() {
<Row label='透析液流量' value={rx.dialysate_flow_rate} unit=' ml/min' />
<Row label='频率' value={rx.frequency_per_week != null ? `${rx.frequency_per_week} 次/周` : null} />
<Row label='每次时长' value={rx.duration_minutes} unit=' 分钟' />
</View>
</ContentCard>
{/* 透析液配比 */}
<View className='section'>
<ContentCard>
<Text className='section-title'></Text>
<Row label='钾浓度' value={rx.dialysate_potassium} unit=' mmol/L' />
<Row label='钙浓度' value={rx.dialysate_calcium} unit=' mmol/L' />
<Row label='碳酸氢盐' value={rx.dialysate_bicarbonate} unit=' mmol/L' />
</View>
</ContentCard>
{/* 抗凝方案 */}
<View className='section'>
<ContentCard>
<Text className='section-title'></Text>
<Row label='抗凝类型' value={rx.anticoagulation_type} />
<Row label='抗凝剂量' value={rx.anticoagulation_dose} />
</View>
</ContentCard>
{/* 血管通路 */}
{(rx.vascular_access_type || rx.vascular_access_location) && (
<View className='section'>
<ContentCard>
<Text className='section-title'></Text>
<Row label='通路类型' value={rx.vascular_access_type} />
<Row label='通路位置' value={rx.vascular_access_location} />
</View>
</ContentCard>
)}
{/* 超滤目标 */}
{(rx.target_ultrafiltration_ml != null || rx.target_dry_weight != null) && (
<View className='section'>
<ContentCard>
<Text className='section-title'></Text>
<Row label='目标超滤量' value={rx.target_ultrafiltration_ml} unit=' ml' />
<Row label='目标干体重' value={rx.target_dry_weight} unit=' kg' />
</View>
</ContentCard>
)}
{/* 备注 */}
{rx.notes && (
<View className='section'>
<ContentCard>
<Text className='section-title'></Text>
<Text className='notes-text'>{rx.notes}</Text>
</View>
</ContentCard>
)}
{/* 操作按钮 */}
@@ -163,6 +165,6 @@ export default function PrescriptionDetail() {
<Text className='action-btn__text'></Text>
</View>
</View>
</ScrollView>
</PageShell>
);
}

View File

@@ -1,21 +1,6 @@
@import '../../../../styles/variables.scss';
@import '../../../../styles/mixins.scss';
.report-detail {
min-height: 100vh;
background: $bg;
padding: 24px;
padding-bottom: 120px;
}
.section {
background: $card;
border-radius: $r-lg;
padding: 28px;
margin-bottom: 20px;
box-shadow: $shadow-sm;
}
.section-title {
@include section-title;
}

View File

@@ -1,9 +1,11 @@
import { useState, useCallback } from 'react';
import { View, Text, Textarea, ScrollView } from '@tarojs/components';
import { View, Text, Textarea } from '@tarojs/components';
import Taro, { useRouter } from '@tarojs/taro';
import { usePageData } from '@/hooks/usePageData';
import { getLabReport, reviewLabReport, type LabReportDetail } from '@/services/doctor/labReport';
import Loading from '@/components/Loading';
import PageShell from '@/components/ui/PageShell';
import ContentCard from '@/components/ui/ContentCard';
import { useElderClass } from '../../../../hooks/useElderClass';
import './index.scss';
@@ -53,12 +55,12 @@ export default function ReportDetail() {
const formatDate = (d: string) => new Date(d).toLocaleDateString('zh-CN');
if (loading) return <Loading />;
if (!report) return <View className={`error-text ${modeClass}`}><Text></Text></View>;
if (!report) return <PageShell className={modeClass}><View className='error-text'><Text></Text></View></PageShell>;
return (
<ScrollView scrollY className={`report-detail ${modeClass}`}>
<PageShell className={modeClass}>
{/* 基本信息 */}
<View className='section'>
<ContentCard>
<View className='report-header'>
<Text className='report-header__type'>{report.report_type}</Text>
<Text className={`report-header__status report-header__status--${report.status}`}>
@@ -69,11 +71,11 @@ export default function ReportDetail() {
{report.reviewed_at && (
<Text className='review-info'>: {formatDate(report.reviewed_at)}</Text>
)}
</View>
</ContentCard>
{/* 指标列表 */}
{report.items && report.items.length > 0 && (
<View className='section'>
<ContentCard>
<Text className='section-title'></Text>
<View className='indicator-table'>
<View className='indicator-row indicator-row--header'>
@@ -102,11 +104,11 @@ export default function ReportDetail() {
</View>
))}
</View>
</View>
</ContentCard>
)}
{/* 医生注释 */}
<View className='section'>
<ContentCard>
<Text className='section-title'></Text>
{report.status === 'reviewed' && report.doctor_notes ? (
<View className='notes-display'>
@@ -129,7 +131,7 @@ export default function ReportDetail() {
</View>
</View>
)}
</View>
</ScrollView>
</ContentCard>
</PageShell>
);
}