// 家属 · 碰一碰分享接收页:渲染对方设备碰一碰传来的长者健康报告卡 // 数据来源:EntryAbility.reportData 解析 smartsenior://report?data= 写入 AppStorage.pendingReportData import { HealthReportData } from '../../utils/KnockShare'; import { FontScaleLevel, FONT_SCALE_MAP } from '../../utils/FontScale'; @Entry @Component struct FamilyReportCard { @StorageProp('fontScale') fontScaleLevel: FontScaleLevel = 'system'; private scaleFor(): number { return FONT_SCALE_MAP[this.fontScaleLevel] ?? 1.0; } @StorageProp('pendingReportData') reportStr: string = ''; @State report: HealthReportData | null = null; @State parseFailed: boolean = false; aboutToAppear(): void { if (this.reportStr.length === 0) { this.parseFailed = true; return; } try { const raw = JSON.parse(this.reportStr) as HealthReportData; // 防御旧版发送端:报告字段可能整体缺失,统一补默认值避免 undefined 崩溃 this.report = { name: raw.name ?? '', gender: raw.gender ?? '', age: raw.age ?? 0, room: raw.room ?? '', care_level: raw.care_level ?? '', health_score: raw.health_score ?? null, status: raw.status ?? '', risks: raw.risks ?? [], medical_history: raw.medical_history ?? '', allergies: raw.allergies ?? '', medications: raw.medications ?? [], caregiver: raw.caregiver ?? '', emergency_contact: raw.emergency_contact ?? '', report_title: raw.report_title ?? '', report_period: raw.report_period ?? '', report_summary: raw.report_summary ?? '', report_ai: raw.report_ai ?? '', shared_at: raw.shared_at ?? '', }; } catch (err) { this.parseFailed = true; } } @Builder InfoRow(label: string, value: string) { Row({ space: 12 }) { Text(label) .fontSize(Math.round(16 * this.scaleFor())) .fontColor($r('app.color.text_secondary')) .width(88) Text(value.length > 0 ? value : '--') .fontSize(Math.round(16 * this.scaleFor())) .fontColor($r('app.color.text_primary')) .layoutWeight(1) } .width('100%') } build() { Scroll() { Column({ space: 16 }) { if (this.parseFailed) { Text('未收到健康报告数据') .fontSize(Math.round(18 * this.scaleFor())) .fontColor($r('app.color.text_secondary')) .margin({ top: 120 }) Text('请与对方设备碰一碰后重新接收') .fontSize(Math.round(14 * this.scaleFor())) .fontColor($r('app.color.inactive_tab')) } else if (this.report !== null) { // 报告头 Column({ space: 8 }) { Text('长者健康报告') .fontSize(Math.round(14 * this.scaleFor())) .fontColor('#FFFFFF') .opacity(0.9) Text(this.report.name) .fontSize(Math.round(32 * this.scaleFor())) .fontWeight(FontWeight.Bold) .fontColor('#FFFFFF') Text(`${this.report.age}岁 · ${this.report.gender}${this.report.room.length > 0 ? ' · ' + this.report.room : ''}`) .fontSize(Math.round(15 * this.scaleFor())) .fontColor('#FFFFFF') .opacity(0.9) if (this.report.health_score !== null) { Text(`健康评分 ${this.report.health_score}`) .fontSize(Math.round(15 * this.scaleFor())) .fontWeight(FontWeight.Medium) .fontColor('#FFFFFF') .padding({ left: 14, right: 14, top: 6, bottom: 6 }) .backgroundColor('#33FFFFFF') .borderRadius(16) } } .width('100%') .padding(24) .borderRadius(18) .linearGradient({ angle: 135, colors: [[$r('app.color.accent_blue'), 0], ['#5B8DEF', 1]] }) .alignItems(HorizontalAlign.Center) Text(this.report.care_level) .fontSize(Math.round(14 * this.scaleFor())) .fontColor($r('app.color.accent_blue')) .width('100%') // 报告内容 Column({ space: 14 }) { Text('健康信息') .fontSize(Math.round(17 * this.scaleFor())) .fontWeight(FontWeight.Bold) .fontColor($r('app.color.text_primary')) .width('100%') this.InfoRow('健康状态', this.report.status) this.InfoRow('风险标签', this.report.risks.length > 0 ? this.report.risks.join('、') : '') this.InfoRow('病史', this.report.medical_history) this.InfoRow('过敏', this.report.allergies) this.InfoRow('常用药物', this.report.medications.length > 0 ? this.report.medications.join('、') : '') this.InfoRow('主责护理员', this.report.caregiver) this.InfoRow('紧急联系人', this.report.emergency_contact) } .width('100%') .padding(18) .backgroundColor($r('app.color.background_card')) .borderRadius(14) .alignItems(HorizontalAlign.Start) if (this.report.report_title.length > 0) { // AI 健康报告(周期总结 + AI 分析) Column({ space: 10 }) { Row({ space: 6 }) { Text('AI 健康报告') .fontSize(Math.round(16 * this.scaleFor())) .fontWeight(FontWeight.Bold) .fontColor($r('app.color.accent_blue')) Text(this.report.report_title) .fontSize(Math.round(13 * this.scaleFor())) .fontColor($r('app.color.text_secondary')) .layoutWeight(1) .maxLines(1) .textOverflow({ overflow: TextOverflow.Ellipsis }) } .width('100%') if (this.report.report_period.length > 0) { Text(this.report.report_period) .fontSize(Math.round(12 * this.scaleFor())) .fontColor($r('app.color.inactive_tab')) .width('100%') } if (this.report.report_summary.length > 0) { Text(this.report.report_summary) .fontSize(Math.round(14 * this.scaleFor())) .fontColor($r('app.color.text_primary')) .width('100%') .lineHeight(Math.round(22 * this.scaleFor())) } if (this.report.report_ai.length > 0) { Divider().color($r('app.color.background')) Text('AI 分析') .fontSize(Math.round(13 * this.scaleFor())) .fontWeight(FontWeight.Medium) .fontColor($r('app.color.accent_blue')) .width('100%') Text(this.report.report_ai) .fontSize(Math.round(14 * this.scaleFor())) .fontColor($r('app.color.text_primary')) .width('100%') .lineHeight(Math.round(22 * this.scaleFor())) } } .width('100%') .padding(18) .backgroundColor($r('app.color.background_card')) .borderRadius(14) .alignItems(HorizontalAlign.Start) } Text(`分享时间:${this.report.shared_at}`) .fontSize(Math.round(12 * this.scaleFor())) .fontColor($r('app.color.inactive_tab')) .width('100%') } } .width('100%') .padding({ left: 16, right: 16, top: 72, bottom: 30 }) } .width('100%') .height('100%') .scrollBar(BarState.Auto) .edgeEffect(EdgeEffect.Spring) .align(Alignment.Top) .backgroundColor($r('app.color.background')) } }