refactor(mp): 迁移患者端详情页 — 使用统一组件库 (10/12)

报告详情、随访详情、透析记录详情、透析处方详情页:
- View.detail-page → PageShell 替代手写 page 容器
- .detail-card → ContentCard 替代手写卡片样式
- 删除通用 page 容器和 card 样式,保留业务布局样式
This commit is contained in:
iven
2026-05-16 01:16:49 +08:00
parent 85701ddeb2
commit 61f1061092
8 changed files with 68 additions and 138 deletions

View File

@@ -1,28 +1,11 @@
@import '../../../../styles/variables.scss';
@import '../../../../styles/mixins.scss';
.detail-page {
min-height: 100vh;
background: $bg;
padding: 24px;
padding-bottom: 40px;
}
.detail-card {
background: $card;
border-radius: $r;
padding: 28px;
margin-bottom: 20px;
box-shadow: $shadow-sm;
}
.header-card {
.header-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.header-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.detail-title {

View File

@@ -5,6 +5,8 @@ import { usePageData } from '@/hooks/usePageData';
import { getDialysisPrescription } from '@/services/dialysis';
import type { DialysisPrescription } from '@/services/dialysis';
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';
@@ -36,8 +38,8 @@ export default function DialysisPrescriptionDetail() {
usePageData(fetchDetail, { throttleMs: 60000 });
if (loading) return <View className={`detail-page ${modeClass}`}><Loading /></View>;
if (!rx) return <View className={`detail-page ${modeClass}`}><View className='empty-state'><Text className='empty-text'></Text></View></View>;
if (loading) return <PageShell className={modeClass}><Loading /></PageShell>;
if (!rx) return <PageShell className={modeClass}><View className='empty-state'><Text className='empty-text'></Text></View></PageShell>;
const si = STATUS_MAP[rx.status] || { label: rx.status, cls: '' };
@@ -52,9 +54,9 @@ export default function DialysisPrescriptionDetail() {
};
return (
<View className={`detail-page ${modeClass}`}>
<PageShell className={modeClass}>
{/* 状态头部 */}
<View className='detail-card header-card'>
<ContentCard>
<View className='header-row'>
<Text className='detail-title'>{rx.dialyzer_model || '透析处方'}</Text>
<Text className={`status-tag ${si.cls}`}>{si.label}</Text>
@@ -62,10 +64,10 @@ export default function DialysisPrescriptionDetail() {
{(rx.effective_from || rx.effective_to) && (
<Text className='header-sub'>{rx.effective_from || '...'} ~ {rx.effective_to || '...'}</Text>
)}
</View>
</ContentCard>
{/* 基本参数 */}
<View className='detail-card'>
<ContentCard>
<Text className='section-title'></Text>
<Row label='透析器型号' value={rx.dialyzer_model} />
<Row label='膜面积' value={rx.membrane_area != null ? `${rx.membrane_area}` : null} />
@@ -73,48 +75,48 @@ export default function DialysisPrescriptionDetail() {
<Row label='透析液流量' value={rx.dialysate_flow_rate != null ? `${rx.dialysate_flow_rate} ml/min` : null} />
<Row label='频率' value={rx.frequency_per_week != null ? `${rx.frequency_per_week} 次/周` : null} />
<Row label='每次时长' value={rx.duration_minutes != null ? `${rx.duration_minutes} 分钟` : null} />
</View>
</ContentCard>
{/* 透析液配比 */}
<View className='detail-card'>
<ContentCard>
<Text className='section-title'></Text>
<Row label='钾浓度' value={rx.dialysate_potassium != null ? `${rx.dialysate_potassium} mmol/L` : null} />
<Row label='钙浓度' value={rx.dialysate_calcium != null ? `${rx.dialysate_calcium} mmol/L` : null} />
<Row label='碳酸氢盐浓度' value={rx.dialysate_bicarbonate != null ? `${rx.dialysate_bicarbonate} mmol/L` : null} />
</View>
</ContentCard>
{/* 抗凝方案 */}
<View className='detail-card'>
<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='detail-card'>
<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='detail-card'>
<ContentCard>
<Text className='section-title'></Text>
<Row label='目标超滤量' value={rx.target_ultrafiltration_ml != null ? `${rx.target_ultrafiltration_ml} ml` : null} />
<Row label='目标干体重' value={rx.target_dry_weight != null ? `${rx.target_dry_weight} kg` : null} />
</View>
</ContentCard>
)}
{/* 备注 */}
{rx.notes && (
<View className='detail-card'>
<ContentCard>
<Text className='section-title'></Text>
<Text className='notes-text'>{rx.notes}</Text>
</View>
</ContentCard>
)}
</View>
</PageShell>
);
}

View File

@@ -1,28 +1,11 @@
@import '../../../../styles/variables.scss';
@import '../../../../styles/mixins.scss';
.detail-page {
min-height: 100vh;
background: $bg;
padding: 24px;
padding-bottom: 40px;
}
.detail-card {
background: $card;
border-radius: $r;
padding: 28px;
margin-bottom: 20px;
box-shadow: $shadow-sm;
}
.header-card {
.header-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.header-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.detail-title {

View File

@@ -5,6 +5,8 @@ import { usePageData } from '@/hooks/usePageData';
import { getDialysisRecord } from '@/services/dialysis';
import type { DialysisRecord } from '@/services/dialysis';
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';
@@ -42,25 +44,25 @@ export default function DialysisRecordDetail() {
usePageData(fetchDetail, { throttleMs: 60000 });
if (loading) return <View className={`detail-page ${modeClass}`}><Loading /></View>;
if (!record) return <View className={`detail-page ${modeClass}`}><View className='empty-state'><Text className='empty-text'></Text></View></View>;
if (loading) return <PageShell className={modeClass}><Loading /></PageShell>;
if (!record) return <PageShell className={modeClass}><View className='empty-state'><Text className='empty-text'></Text></View></PageShell>;
const si = STATUS_MAP[record.status] || { label: record.status, cls: '' };
return (
<View className={`detail-page ${modeClass}`}>
<PageShell className={modeClass}>
{/* 状态头部 */}
<View className='detail-card header-card'>
<ContentCard>
<View className='header-row'>
<Text className='detail-title'>{record.dialysis_date}</Text>
<Text className={`status-tag ${si.cls}`}>{si.label}</Text>
</View>
<Text className='header-sub'>{TYPE_MAP[record.dialysis_type] || record.dialysis_type}</Text>
{record.reviewed_at && <Text className='review-info'> {record.reviewed_at}</Text>}
</View>
</ContentCard>
{/* 基本信息 */}
<View className='detail-card'>
<ContentCard>
<Text className='section-title'></Text>
{record.start_time && (
<View className='detail-row'><Text className='detail-label'></Text><Text className='detail-value'>{record.start_time}</Text></View>
@@ -77,10 +79,10 @@ export default function DialysisRecordDetail() {
{record.ultrafiltration_volume != null && (
<View className='detail-row'><Text className='detail-label'></Text><Text className='detail-value'>{record.ultrafiltration_volume} ml</Text></View>
)}
</View>
</ContentCard>
{/* 体重与血压 */}
<View className='detail-card'>
<ContentCard>
<Text className='section-title'></Text>
{record.dry_weight != null && (
<View className='detail-row'><Text className='detail-label'></Text><Text className='detail-value'>{record.dry_weight} kg</Text></View>
@@ -103,11 +105,11 @@ export default function DialysisRecordDetail() {
{record.post_heart_rate != null && (
<View className='detail-row'><Text className='detail-label'></Text><Text className='detail-value'>{record.post_heart_rate} bpm</Text></View>
)}
</View>
</ContentCard>
{/* 症状与并发症 */}
{(record.symptoms || record.complication_notes) && (
<View className='detail-card'>
<ContentCard>
<Text className='section-title'></Text>
{record.symptoms && Object.keys(record.symptoms).length > 0 && (
<View className='detail-row'><Text className='detail-label'></Text><Text className='detail-value'>{JSON.stringify(record.symptoms)}</Text></View>
@@ -115,8 +117,8 @@ export default function DialysisRecordDetail() {
{record.complication_notes && (
<View className='detail-row'><Text className='detail-label'></Text><Text className='detail-value'>{record.complication_notes}</Text></View>
)}
</View>
</ContentCard>
)}
</View>
</PageShell>
);
}

View File

@@ -1,21 +1,6 @@
@import '../../../../styles/variables.scss';
@import '../../../../styles/mixins.scss';
.detail-page {
min-height: 100vh;
background: $bg;
padding: 24px;
padding-bottom: 40px;
}
.detail-card {
background: $card;
border-radius: $r;
padding: 28px;
margin-bottom: 20px;
box-shadow: $shadow-sm;
}
.detail-title {
@include section-title;
font-size: var(--tk-font-num-lg);
@@ -79,13 +64,6 @@
line-height: 1.6;
}
.submit-card {
background: $card;
border-radius: $r;
padding: 28px;
box-shadow: $shadow-sm;
}
.section-title {
@include section-title;
margin-bottom: 16px;

View File

@@ -8,6 +8,8 @@ import { TEMPLATE_IDS } from '@/services/wechat-templates';
import { trackEvent } from '@/services/analytics';
import Loading from '@/components/Loading';
import ErrorState from '@/components/ErrorState';
import PageShell from '@/components/ui/PageShell';
import ContentCard from '@/components/ui/ContentCard';
import { useElderClass } from '@/hooks/useElderClass';
import './index.scss';
@@ -89,25 +91,25 @@ export default function FollowUpDetail() {
if (loading) {
return (
<View className={`detail-page ${modeClass}`}>
<PageShell className={modeClass}>
<Loading />
</View>
</PageShell>
);
}
if (error || !task) {
return (
<View className={`detail-page ${modeClass}`}>
<PageShell className={modeClass}>
<ErrorState text='任务不存在' />
</View>
</PageShell>
);
}
const isCompleted = task.status === 'completed';
return (
<View className={`detail-page ${modeClass}`}>
<View className='detail-card'>
<PageShell className={modeClass}>
<ContentCard>
<Text className='detail-title'>{task.follow_up_type}</Text>
<View className='detail-row'>
<Text className='detail-label'></Text>
@@ -132,10 +134,10 @@ export default function FollowUpDetail() {
<Text className='detail-desc-text'>{task.content_template}</Text>
</View>
)}
</View>
</ContentCard>
{!isCompleted && (
<View className='submit-card'>
<ContentCard>
<Text className='section-title'>访</Text>
<Textarea
className='submit-textarea'
@@ -152,8 +154,8 @@ export default function FollowUpDetail() {
{submitting ? '提交中...' : '提交'}
</Text>
</View>
</View>
</ContentCard>
)}
</View>
</PageShell>
);
}

View File

@@ -1,21 +1,6 @@
@import '../../../../styles/variables.scss';
@import '../../../../styles/mixins.scss';
.detail-page {
min-height: 100vh;
background: $bg;
padding: 24px;
padding-bottom: 40px;
}
.detail-card {
background: $card;
border-radius: $r;
padding: 28px;
margin-bottom: 20px;
box-shadow: $shadow-sm;
}
.detail-title {
font-family: 'Georgia', 'Times New Roman', serif;
font-size: var(--tk-font-num-lg);
@@ -51,13 +36,6 @@
margin-left: 24px;
}
.indicators-card {
background: $card;
border-radius: $r;
padding: 28px;
box-shadow: $shadow-sm;
}
.section-title {
font-family: 'Georgia', 'Times New Roman', serif;
font-size: var(--tk-font-num);

View File

@@ -4,6 +4,8 @@ import Taro, { useRouter } from '@tarojs/taro';
import { usePageData } from '@/hooks/usePageData';
import { getReportDetail, LabReport } from '@/services/report';
import Loading from '@/components/Loading';
import PageShell from '@/components/ui/PageShell';
import ContentCard from '@/components/ui/ContentCard';
import { useElderClass } from '@/hooks/useElderClass';
import { useAuthStore } from '@/stores/auth';
import './index.scss';
@@ -62,26 +64,26 @@ export default function ReportDetail() {
if (loading) {
return (
<View className={`detail-page ${modeClass}`}>
<PageShell className={modeClass}>
<Loading />
</View>
</PageShell>
);
}
if (!report) {
return (
<View className={`detail-page ${modeClass}`}>
<PageShell className={modeClass}>
<View className='empty-state'>
<Text className='empty-text'></Text>
</View>
</View>
</PageShell>
);
}
return (
<View className={`detail-page ${modeClass}`}>
<PageShell className={modeClass}>
{/* 基本信息 */}
<View className='detail-card'>
<ContentCard>
<Text className='detail-title'>{report.report_type}</Text>
<View className='detail-row'>
<Text className='detail-label'></Text>
@@ -93,10 +95,10 @@ export default function ReportDetail() {
<Text className='detail-value'>{report.doctor_interpretation}</Text>
</View>
)}
</View>
</ContentCard>
{/* 指标列表 */}
<View className='indicators-card'>
<ContentCard>
<Text className='section-title'></Text>
{indicators.map((item) => {
const statusInfo = getStatusInfo(item.status);
@@ -122,7 +124,7 @@ export default function ReportDetail() {
</View>
);
})}
</View>
</View>
</ContentCard>
</PageShell>
);
}