|
@@ -2,343 +2,180 @@
|
|
|
<app-page-header [title]="'健康监测'" (back)="backToDashboard()"></app-page-header>
|
|
<app-page-header [title]="'健康监测'" (back)="backToDashboard()"></app-page-header>
|
|
|
|
|
|
|
|
<main class="main-content">
|
|
<main class="main-content">
|
|
|
- <div class="monitoring-content">
|
|
|
|
|
- <!-- 综合健康状态卡片 - 重新设计 -->
|
|
|
|
|
- <section class="health-status-section">
|
|
|
|
|
- <div class="health-status-card-redesigned">
|
|
|
|
|
- <div class="status-left-panel">
|
|
|
|
|
- <h3 class="section-title">综合健康状态</h3>
|
|
|
|
|
- <div class="health-score-display">
|
|
|
|
|
- <div class="score-circle">
|
|
|
|
|
- <div class="score-number">85</div>
|
|
|
|
|
- <div class="score-label">健康评分</div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="status-badge-large good">
|
|
|
|
|
- <span class="status-icon">✓</span>
|
|
|
|
|
- <span class="status-text">良好</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <p class="status-description-compact">心率、血压和血氧指标均在正常范围内</p>
|
|
|
|
|
- <button class="view-report-btn" (click)="openDetailModal('comprehensive')">
|
|
|
|
|
- <span>查看详细报告</span>
|
|
|
|
|
- <span class="btn-arrow">→</span>
|
|
|
|
|
- </button>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div class="status-right-panel">
|
|
|
|
|
- <div class="metrics-grid">
|
|
|
|
|
- <div class="metric-card heart-rate clickable" (click)="openMetricModal('heartRate')">
|
|
|
|
|
- <div class="metric-card-top">
|
|
|
|
|
- <div class="metric-icon">💗</div>
|
|
|
|
|
- <div class="metric-info">
|
|
|
|
|
- <div class="metric-label">心率</div>
|
|
|
|
|
- <div class="metric-value-large">{{ heartRate.value }} <span class="unit">{{ heartRate.unit }}</span></div>
|
|
|
|
|
- <div class="metric-status status-{{ heartRate.status }}">{{ getStatusText(heartRate.status) }}</div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="metric-actions">
|
|
|
|
|
- <button class="metric-action-btn record" (click)="$event.stopPropagation(); openRecordModal('heartRate')" title="记录">
|
|
|
|
|
- <span>记录</span>
|
|
|
|
|
- </button>
|
|
|
|
|
- <button class="metric-action-btn detail" (click)="$event.stopPropagation(); openDetailModal('heartRate')" title="详情">
|
|
|
|
|
- <span>详情</span>
|
|
|
|
|
- </button>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div class="metric-card blood-pressure clickable" (click)="openMetricModal('bloodPressure')">
|
|
|
|
|
- <div class="metric-card-top">
|
|
|
|
|
- <div class="metric-icon">🩺</div>
|
|
|
|
|
- <div class="metric-info">
|
|
|
|
|
- <div class="metric-label">血压</div>
|
|
|
|
|
- <div class="metric-value-large">{{ bloodPressure.systolic.value }}/{{ bloodPressure.diastolic.value }} <span class="unit">mmHg</span></div>
|
|
|
|
|
- <div class="metric-status status-{{ bloodPressure.systolic.status }}">{{ getStatusText(bloodPressure.systolic.status) }}</div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="metric-actions">
|
|
|
|
|
- <button class="metric-action-btn record" (click)="$event.stopPropagation(); openRecordModal('bloodPressure')" title="记录">
|
|
|
|
|
- <span>记录</span>
|
|
|
|
|
- </button>
|
|
|
|
|
- <button class="metric-action-btn detail" (click)="$event.stopPropagation(); openDetailModal('bloodPressure')" title="详情">
|
|
|
|
|
- <span>详情</span>
|
|
|
|
|
- </button>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div class="metric-card blood-oxygen clickable" (click)="openMetricModal('bloodOxygen')">
|
|
|
|
|
- <div class="metric-card-top">
|
|
|
|
|
- <div class="metric-icon">🫁</div>
|
|
|
|
|
- <div class="metric-info">
|
|
|
|
|
- <div class="metric-label">血氧</div>
|
|
|
|
|
- <div class="metric-value-large">{{ bloodOxygen.value }}<span class="unit">%</span></div>
|
|
|
|
|
- <div class="metric-status status-{{ bloodOxygen.status }}">{{ getStatusText(bloodOxygen.status) }}</div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="metric-actions">
|
|
|
|
|
- <button class="metric-action-btn record" (click)="$event.stopPropagation(); openRecordModal('bloodOxygen')" title="记录">
|
|
|
|
|
- <span>记录</span>
|
|
|
|
|
- </button>
|
|
|
|
|
- <button class="metric-action-btn detail" (click)="$event.stopPropagation(); openDetailModal('bloodOxygen')" title="详情">
|
|
|
|
|
- <span>详情</span>
|
|
|
|
|
- </button>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <!-- 健康评分卡片 -->
|
|
|
|
|
+ <section class="health-score-card">
|
|
|
|
|
+ <div class="score-ring">
|
|
|
|
|
+ <svg width="90" height="90" viewBox="0 0 90 90">
|
|
|
|
|
+ <circle class="score-ring-bg" cx="45" cy="45" r="40"/>
|
|
|
|
|
+ <circle class="score-ring-progress" cx="45" cy="45" r="40" [style.stroke-dashoffset]="getScoreOffset()"/>
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ <div class="score-value">
|
|
|
|
|
+ <div class="score-number">{{ healthScore }}</div>
|
|
|
|
|
+ <div class="score-label">健康分</div>
|
|
|
</div>
|
|
</div>
|
|
|
- </section>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 数据可视化区域 -->
|
|
|
|
|
- <section class="data-visualization">
|
|
|
|
|
- <div class="section-header">
|
|
|
|
|
- <h2>数据趋势分析</h2>
|
|
|
|
|
- <div class="time-range-selector">
|
|
|
|
|
- <select [(ngModel)]="selectedTimeRange" (change)="onTimeRangeChange()">
|
|
|
|
|
- <option value="week">最近7天</option>
|
|
|
|
|
- <option value="month">最近30天</option>
|
|
|
|
|
- <option value="threeMonths">最近3个月</option>
|
|
|
|
|
- </select>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="score-info">
|
|
|
|
|
+ <div class="score-status" [class.good]="healthScore >= 80" [class.warning]="healthScore >= 60 && healthScore < 80" [class.danger]="healthScore < 60">
|
|
|
|
|
+ <span>{{ healthScore >= 80 ? '✓' : healthScore >= 60 ? '!' : '✗' }}</span>
|
|
|
|
|
+ <span>{{ healthScore >= 80 ? '状态良好' : healthScore >= 60 ? '需要关注' : '需要改善' }}</span>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ <p class="score-desc">{{ getHealthSummary() }}</p>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </section>
|
|
|
|
|
|
|
|
- <div class="charts-container">
|
|
|
|
|
- <!-- 心率图表 -->
|
|
|
|
|
- <div class="chart-card">
|
|
|
|
|
- <h3>心率趋势</h3>
|
|
|
|
|
- <div class="chart-wrapper">
|
|
|
|
|
- <div id="heartRateChart" style="width: 100%; height: 100%;"></div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 血压图表 -->
|
|
|
|
|
- <div class="chart-card">
|
|
|
|
|
- <h3>血压趋势</h3>
|
|
|
|
|
- <div class="chart-wrapper">
|
|
|
|
|
- <div id="bloodPressureChart" style="width: 100%; height: 100%;"></div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <!-- 核心指标网格 -->
|
|
|
|
|
+ <section class="metrics-grid">
|
|
|
|
|
+ <div class="metric-item" (click)="openMetricModal('heartRate')">
|
|
|
|
|
+ <div class="metric-icon">💗</div>
|
|
|
|
|
+ <div class="metric-value">{{ heartRate.value }}<span class="metric-unit">{{ heartRate.unit }}</span></div>
|
|
|
|
|
+ <div class="metric-label">心率</div>
|
|
|
|
|
+ <span class="metric-status" [class.status-normal]="heartRate.status === 'normal'" [class.status-warning]="heartRate.status === 'warning'" [class.status-danger]="heartRate.status === 'danger'">{{ getStatusText(heartRate.status) }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="metric-item" (click)="openMetricModal('bloodPressure')">
|
|
|
|
|
+ <div class="metric-icon">🩺</div>
|
|
|
|
|
+ <div class="metric-value">{{ bloodPressure.systolic.value }}<span class="metric-unit">/{{ bloodPressure.diastolic.value }}</span></div>
|
|
|
|
|
+ <div class="metric-label">血压</div>
|
|
|
|
|
+ <span class="metric-status" [class.status-normal]="bloodPressure.systolic.status === 'normal'" [class.status-warning]="bloodPressure.systolic.status === 'warning'" [class.status-danger]="bloodPressure.systolic.status === 'danger'">{{ getStatusText(bloodPressure.systolic.status) }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="metric-item" (click)="openMetricModal('bloodOxygen')">
|
|
|
|
|
+ <div class="metric-icon">🫁</div>
|
|
|
|
|
+ <div class="metric-value">{{ bloodOxygen.value }}<span class="metric-unit">%</span></div>
|
|
|
|
|
+ <div class="metric-label">血氧</div>
|
|
|
|
|
+ <span class="metric-status" [class.status-normal]="bloodOxygen.status === 'normal'" [class.status-warning]="bloodOxygen.status === 'warning'" [class.status-danger]="bloodOxygen.status === 'danger'">{{ getStatusText(bloodOxygen.status) }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </section>
|
|
|
|
|
|
|
|
- <!-- 血氧图表 -->
|
|
|
|
|
- <div class="chart-card">
|
|
|
|
|
- <h3>血氧趋势</h3>
|
|
|
|
|
- <div class="chart-wrapper">
|
|
|
|
|
- <div id="bloodOxygenChart" style="width: 100%; height: 100%;"></div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <!-- 快捷操作 -->
|
|
|
|
|
+ <section class="quick-actions">
|
|
|
|
|
+ <button class="quick-btn primary" (click)="openMetricSelectionModal()">📝 记录数据</button>
|
|
|
|
|
+ <button class="quick-btn" (click)="openDetailModal('comprehensive')">📊 详细报告</button>
|
|
|
|
|
+ </section>
|
|
|
|
|
|
|
|
- <!-- 健康指标关联分析图表 -->
|
|
|
|
|
- <div class="chart-card correlation-chart">
|
|
|
|
|
- <h3>健康指标关联分析</h3>
|
|
|
|
|
- <div class="chart-wrapper">
|
|
|
|
|
- <div id="correlationChart" style="width: 100%; height: 100%;"></div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <p class="chart-description">心率与收缩压的相关性分析,帮助了解身体状况的整体表现</p>
|
|
|
|
|
|
|
+ <!-- 趋势图 -->
|
|
|
|
|
+ <section class="trend-section">
|
|
|
|
|
+ <div class="section-header">
|
|
|
|
|
+ <span class="section-title">数据趋势</span>
|
|
|
|
|
+ <select class="time-select" [(ngModel)]="selectedTimeRange" (change)="onTimeRangeChange()">
|
|
|
|
|
+ <option value="week">最近7天</option>
|
|
|
|
|
+ <option value="month">最近30天</option>
|
|
|
|
|
+ <option value="threeMonths">最近3个月</option>
|
|
|
|
|
+ </select>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="trend-card">
|
|
|
|
|
+ <div class="trend-tabs">
|
|
|
|
|
+ <button class="trend-tab" [class.active]="activeTrendTab === 'heartRate'" (click)="setActiveTrendTab('heartRate')">心率</button>
|
|
|
|
|
+ <button class="trend-tab" [class.active]="activeTrendTab === 'bloodPressure'" (click)="setActiveTrendTab('bloodPressure')">血压</button>
|
|
|
|
|
+ <button class="trend-tab" [class.active]="activeTrendTab === 'bloodOxygen'" (click)="setActiveTrendTab('bloodOxygen')">血氧</button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="chart-wrapper">
|
|
|
|
|
+ <div id="trendChart" style="width: 100%; height: 100%;"></div>
|
|
|
|
|
+ <div class="chart-loading" *ngIf="!trendChart">
|
|
|
|
|
+ <div class="loading-spinner"></div>
|
|
|
|
|
+ <span>加载图表中...</span>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
- </section>
|
|
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </section>
|
|
|
|
|
|
|
|
- <!-- 慢性病监测区域 -->
|
|
|
|
|
- @if (chronicConditions.length > 0) {
|
|
|
|
|
- <section class="chronic-conditions-section">
|
|
|
|
|
- <h2>慢性病监测与锻炼注意事项</h2>
|
|
|
|
|
- <div class="chronic-conditions-list">
|
|
|
|
|
- @for (condition of chronicConditions; track condition.name) {
|
|
|
|
|
- <div class="chronic-condition-card">
|
|
|
|
|
- <div class="condition-header">
|
|
|
|
|
- <h3>{{ condition.name }}</h3>
|
|
|
|
|
- <span class="severity-badge severity-{{ condition.severity }}">
|
|
|
|
|
- {{ condition.severity === 'mild' ? '轻度' : condition.severity === 'moderate' ? '中度' : '重度' }}
|
|
|
|
|
- </span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="condition-content">
|
|
|
|
|
- <h4>锻炼注意事项:</h4>
|
|
|
|
|
- <ul class="exercise-restrictions">
|
|
|
|
|
- @for (restriction of condition.exerciseRestrictions; track restriction) {
|
|
|
|
|
- <li>{{ restriction }}</li>
|
|
|
|
|
- }
|
|
|
|
|
- </ul>
|
|
|
|
|
- <div class="checkup-info">
|
|
|
|
|
- <p><strong>上次检查:</strong> {{ formatDate(condition.lastCheckup) }}</p>
|
|
|
|
|
- @if (condition.nextCheckupReminder) {
|
|
|
|
|
- <p class="reminder"><strong>下次检查提醒:</strong> {{ formatDate(condition.nextCheckupReminder) }}</p>
|
|
|
|
|
- }
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- }
|
|
|
|
|
- </div>
|
|
|
|
|
- </section>
|
|
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
- <!-- 生活方式建议区域 -->
|
|
|
|
|
- <section class="lifestyle-tips-section">
|
|
|
|
|
- <h2>生活方式建议</h2>
|
|
|
|
|
- <div class="lifestyle-tips-cards">
|
|
|
|
|
- <div class="lifestyle-tip-card exercise">
|
|
|
|
|
- <h3>运动建议</h3>
|
|
|
|
|
- <p>建议每日进行30分钟中等强度有氧运动,如快走、游泳或骑行,可以有效提升心肺功能,维持健康体重。</p>
|
|
|
|
|
- <div class="tip-highlight">
|
|
|
|
|
- 运动前记得热身,运动后进行拉伸,避免剧烈运动导致受伤。
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="lifestyle-tip-card diet">
|
|
|
|
|
- <h3>饮食建议</h3>
|
|
|
|
|
- <p>保持饮食均衡,多摄入新鲜蔬菜和水果,减少盐分和脂肪摄入,选择全谷物和优质蛋白质来源。</p>
|
|
|
|
|
- <div class="tip-highlight">
|
|
|
|
|
- 建议每日盐摄入量不超过5克,避免加工食品和高糖饮料。
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="lifestyle-tip-card sleep">
|
|
|
|
|
- <h3>睡眠建议</h3>
|
|
|
|
|
- <p>保证每日7-8小时的充足睡眠,建立规律的睡眠习惯,避免熬夜和睡前使用电子设备。</p>
|
|
|
|
|
- <div class="tip-highlight">
|
|
|
|
|
- 睡前放松身心,可尝试冥想或听轻音乐帮助入睡。
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="lifestyle-tip-card hydration">
|
|
|
|
|
- <h3>水分补充</h3>
|
|
|
|
|
- <p>每天饮水约2000毫升,保持身体水分充足,促进新陈代谢和废物排出。</p>
|
|
|
|
|
- <div class="tip-highlight">
|
|
|
|
|
- 避免等到口渴才喝水,养成定时饮水的好习惯。
|
|
|
|
|
|
|
+ <!-- 慢性病监测 -->
|
|
|
|
|
+ @if (chronicConditions.length > 0) {
|
|
|
|
|
+ <section class="chronic-section">
|
|
|
|
|
+ <div class="section-header">
|
|
|
|
|
+ <span class="section-title">健康提醒</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @for (condition of chronicConditions; track condition.name) {
|
|
|
|
|
+ <div class="chronic-card">
|
|
|
|
|
+ <div class="chronic-header">
|
|
|
|
|
+ <span class="chronic-name">{{ condition.name }}</span>
|
|
|
|
|
+ <span class="chronic-badge" [class.mild]="condition.severity === 'mild'" [class.moderate]="condition.severity === 'moderate'" [class.severe]="condition.severity === 'severe'">
|
|
|
|
|
+ {{ condition.severity === 'mild' ? '轻度' : condition.severity === 'moderate' ? '中度' : '重度' }}
|
|
|
|
|
+ </span>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ <ul class="chronic-tips">
|
|
|
|
|
+ @for (restriction of condition.exerciseRestrictions; track restriction) {
|
|
|
|
|
+ <li>{{ restriction }}</li>
|
|
|
|
|
+ }
|
|
|
|
|
+ </ul>
|
|
|
|
|
+ @if (condition.nextCheckupReminder) {
|
|
|
|
|
+ <div class="chronic-reminder">📅 下次检查:{{ formatDate(condition.nextCheckupReminder) }}</div>
|
|
|
|
|
+ }
|
|
|
</div>
|
|
</div>
|
|
|
- </div>
|
|
|
|
|
|
|
+ }
|
|
|
</section>
|
|
</section>
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- <!-- AI健康建议区域 -->
|
|
|
|
|
- <section class="health-tips-section">
|
|
|
|
|
- <h2>AI健康建议</h2>
|
|
|
|
|
- <div class="health-tips-cards">
|
|
|
|
|
- <div class="health-tip-card">
|
|
|
|
|
- <h3>心率建议</h3>
|
|
|
|
|
- <p>{{ getHealthAdvice('heartRate') }}</p>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="health-tip-card">
|
|
|
|
|
- <h3>血压建议</h3>
|
|
|
|
|
- <p>{{ getHealthAdvice('bloodPressure') }}</p>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="health-tip-card">
|
|
|
|
|
- <h3>血氧建议</h3>
|
|
|
|
|
- <p>{{ getHealthAdvice('bloodOxygen') }}</p>
|
|
|
|
|
- </div>
|
|
|
|
|
- @if (isFemaleUser) {
|
|
|
|
|
- <div class="health-tip-card">
|
|
|
|
|
- <h3>经期建议</h3>
|
|
|
|
|
- <p>{{ getHealthAdvice('menstrualCycle') }}</p>
|
|
|
|
|
- </div>
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ <!-- 经期监测 -->
|
|
|
|
|
+ @if (isFemaleUser) {
|
|
|
|
|
+ <section class="menstrual-section">
|
|
|
|
|
+ <div class="section-header">
|
|
|
|
|
+ <span class="section-title">经期监测</span>
|
|
|
</div>
|
|
</div>
|
|
|
- <button class="report-btn" (click)="openDetailModal('comprehensive')">查看完整健康报告</button>
|
|
|
|
|
- </section>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 经期监测区域 (仅女性用户显示) -->
|
|
|
|
|
- @if (isFemaleUser) {
|
|
|
|
|
- <section class="menstrual-cycle-section">
|
|
|
|
|
- <h2>经期监测与健康管理</h2>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 当前周期状态卡片 -->
|
|
|
|
|
- <div class="menstrual-status-card">
|
|
|
|
|
- <div class="status-overview">
|
|
|
|
|
- <div class="status-item">
|
|
|
|
|
- <span class="status-label">当前阶段</span>
|
|
|
|
|
- <span class="status-value phase-{{ getCurrentPhase().toLowerCase() }}">{{ getCurrentPhase() }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="status-item">
|
|
|
|
|
- <span class="status-label">距离下次月经</span>
|
|
|
|
|
- <span class="status-value">{{ getDaysUntilNextPeriod() }} 天</span>
|
|
|
|
|
|
|
+ <div class="menstrual-card">
|
|
|
|
|
+ <div class="menstrual-card-content" (click)="openDetailModal('menstrualCycle')">
|
|
|
|
|
+ <div class="menstrual-header">
|
|
|
|
|
+ <span class="menstrual-title">生理周期</span>
|
|
|
|
|
+ <span class="phase-badge">{{ getCurrentPhase() }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="menstrual-info">
|
|
|
|
|
+ <div class="menstrual-stat">
|
|
|
|
|
+ <div class="menstrual-stat-value">{{ getDaysUntilNextPeriod() }}</div>
|
|
|
|
|
+ <div class="menstrual-stat-label">距下次月经(天)</div>
|
|
|
</div>
|
|
</div>
|
|
|
- <div class="status-item">
|
|
|
|
|
- <span class="status-label">周期长度</span>
|
|
|
|
|
- <span class="status-value">{{ menstrualCycle.length }} 天</span>
|
|
|
|
|
|
|
+ <div class="menstrual-stat">
|
|
|
|
|
+ <div class="menstrual-stat-value">{{ menstrualCycle.length }}</div>
|
|
|
|
|
+ <div class="menstrual-stat-label">周期长度(天)</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 周期可视化图表 -->
|
|
|
|
|
- <div class="menstrual-cycle-chart">
|
|
|
|
|
- <h3>生理周期阶段图</h3>
|
|
|
|
|
- <div class="cycle-timeline">
|
|
|
|
|
- @for (phase of cyclePhases; track phase.name) {
|
|
|
|
|
- <div class="phase-block"
|
|
|
|
|
- [style.width.%]="phase.duration / menstrualCycle.length * 100"
|
|
|
|
|
- [class.active]="phase.name === getCurrentPhase()">
|
|
|
|
|
- <div class="phase-header">
|
|
|
|
|
- <span class="phase-icon">{{ phase.icon }}</span>
|
|
|
|
|
- <span class="phase-name">{{ phase.name }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="phase-info">
|
|
|
|
|
- <span class="phase-days">{{ phase.startDay }}-{{ phase.endDay }} 天</span>
|
|
|
|
|
- <span class="phase-dates">{{ formatDate(phase.startDate) }} - {{ formatDate(phase.endDate) }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <div class="phase-bar">
|
|
|
|
|
+ @for (phase of cyclePhases; track phase.name; let i = $index) {
|
|
|
|
|
+ <div class="phase-segment" [class.active]="phase.name === getCurrentPhase()"></div>
|
|
|
}
|
|
}
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
-
|
|
|
|
|
- <!-- 各阶段详细建议 -->
|
|
|
|
|
- <div class="phase-advice-grid">
|
|
|
|
|
- @for (phase of cyclePhases; track phase.name) {
|
|
|
|
|
- <div class="phase-advice-card" [class.current]="phase.name === getCurrentPhase()">
|
|
|
|
|
- <div class="phase-advice-header">
|
|
|
|
|
- <span class="phase-icon-large">{{ phase.icon }}</span>
|
|
|
|
|
- <div>
|
|
|
|
|
- <h4>{{ phase.name }}</h4>
|
|
|
|
|
- <p class="phase-duration">第 {{ phase.startDay }}-{{ phase.endDay }} 天</p>
|
|
|
|
|
- </div>
|
|
|
|
|
- @if (phase.name === getCurrentPhase()) {
|
|
|
|
|
- <span class="current-badge">当前阶段</span>
|
|
|
|
|
- }
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div class="phase-advice-content">
|
|
|
|
|
- <div class="advice-section">
|
|
|
|
|
- <h5>🏃♀️ 运动建议</h5>
|
|
|
|
|
- <ul>
|
|
|
|
|
- @for (tip of phase.exerciseAdvice; track tip) {
|
|
|
|
|
- <li>{{ tip }}</li>
|
|
|
|
|
- }
|
|
|
|
|
- </ul>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div class="advice-section">
|
|
|
|
|
- <h5>🥗 健康建议</h5>
|
|
|
|
|
- <ul>
|
|
|
|
|
- @for (tip of phase.healthAdvice; track tip) {
|
|
|
|
|
- <li>{{ tip }}</li>
|
|
|
|
|
- }
|
|
|
|
|
- </ul>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- @if (phase.symptoms && phase.symptoms.length > 0) {
|
|
|
|
|
- <div class="advice-section symptoms">
|
|
|
|
|
- <h5>⚠️ 常见症状</h5>
|
|
|
|
|
- <div class="symptom-tags">
|
|
|
|
|
- @for (symptom of phase.symptoms; track symptom) {
|
|
|
|
|
- <span class="symptom-tag">{{ symptom }}</span>
|
|
|
|
|
- }
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- }
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- }
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 经期记录按钮 -->
|
|
|
|
|
- <div class="menstrual-actions">
|
|
|
|
|
- <button class="action-btn primary" (click)="openDetailModal('menstrualCycle')">
|
|
|
|
|
- <span>📝 记录经期数据</span>
|
|
|
|
|
- </button>
|
|
|
|
|
- <button class="action-btn secondary" (click)="openDetailModal('menstrualCycle')">
|
|
|
|
|
- <span>📊 查看历史记录</span>
|
|
|
|
|
- </button>
|
|
|
|
|
- </div>
|
|
|
|
|
- </section>
|
|
|
|
|
- }
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <button class="menstrual-btn" (click)="openMenstrualRecordModal($event)">📝 记录经期</button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </section>
|
|
|
|
|
+ }
|
|
|
</main>
|
|
</main>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
+<!-- 指标选择模态框 -->
|
|
|
|
|
+<app-modal
|
|
|
|
|
+ [(isOpen)]="showMetricSelectionModal"
|
|
|
|
|
+ [config]="{
|
|
|
|
|
+ title: '选择记录指标',
|
|
|
|
|
+ icon: '📝',
|
|
|
|
|
+ size: 'small',
|
|
|
|
|
+ theme: 'system'
|
|
|
|
|
+ }">
|
|
|
|
|
+ <div class="metric-selection-content">
|
|
|
|
|
+ <div class="metric-selection-grid">
|
|
|
|
|
+ <button class="metric-selection-btn" (click)="selectMetricAndRecord('heartRate')">
|
|
|
|
|
+ <div class="metric-selection-icon">💗</div>
|
|
|
|
|
+ <div class="metric-selection-info">
|
|
|
|
|
+ <div class="metric-selection-label">心率</div>
|
|
|
|
|
+ <div class="metric-selection-desc">记录心跳频率</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </button>
|
|
|
|
|
+ <button class="metric-selection-btn" (click)="selectMetricAndRecord('bloodPressure')">
|
|
|
|
|
+ <div class="metric-selection-icon">🩺</div>
|
|
|
|
|
+ <div class="metric-selection-info">
|
|
|
|
|
+ <div class="metric-selection-label">血压</div>
|
|
|
|
|
+ <div class="metric-selection-desc">记录收缩压/舒张压</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </button>
|
|
|
|
|
+ <button class="metric-selection-btn" (click)="selectMetricAndRecord('bloodOxygen')">
|
|
|
|
|
+ <div class="metric-selection-icon">🫁</div>
|
|
|
|
|
+ <div class="metric-selection-info">
|
|
|
|
|
+ <div class="metric-selection-label">血氧</div>
|
|
|
|
|
+ <div class="metric-selection-desc">记录血氧饱和度</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+</app-modal>
|
|
|
|
|
+
|
|
|
<!-- 数据记录模态框 -->
|
|
<!-- 数据记录模态框 -->
|
|
|
<app-modal
|
|
<app-modal
|
|
|
[(isOpen)]="showRecordModal"
|
|
[(isOpen)]="showRecordModal"
|
|
@@ -350,57 +187,33 @@
|
|
|
showFooter: false
|
|
showFooter: false
|
|
|
}">
|
|
}">
|
|
|
<div class="record-modal-content">
|
|
<div class="record-modal-content">
|
|
|
- <form (ngSubmit)="submitRecord()">
|
|
|
|
|
- <div class="form-group">
|
|
|
|
|
- <label for="recordValue">{{ recordForm.type === 'heartRate' ? '心率值' : recordForm.type === 'bloodPressure' ? '收缩压' : '血氧饱和度' }}:</label>
|
|
|
|
|
- <input
|
|
|
|
|
- type="number"
|
|
|
|
|
- id="recordValue"
|
|
|
|
|
- [(ngModel)]="recordForm.value"
|
|
|
|
|
- name="recordValue"
|
|
|
|
|
- placeholder="请输入数值"
|
|
|
|
|
- min="0"
|
|
|
|
|
- required
|
|
|
|
|
- >
|
|
|
|
|
|
|
+ <form (ngSubmit)="submitRecord()">
|
|
|
|
|
+ <div class="form-group">
|
|
|
|
|
+ <label for="recordValue">{{ recordForm.type === 'heartRate' ? '心率值' : recordForm.type === 'bloodPressure' ? '收缩压' : '血氧饱和度' }}:</label>
|
|
|
|
|
+ <div class="input-with-unit">
|
|
|
|
|
+ <input type="number" id="recordValue" [(ngModel)]="recordForm.value" name="recordValue" placeholder="请输入数值" min="0" required>
|
|
|
<span class="unit">{{ recordForm.type === 'heartRate' ? 'bpm' : recordForm.type === 'bloodPressure' ? 'mmHg' : '%' }}</span>
|
|
<span class="unit">{{ recordForm.type === 'heartRate' ? 'bpm' : recordForm.type === 'bloodPressure' ? 'mmHg' : '%' }}</span>
|
|
|
</div>
|
|
</div>
|
|
|
-
|
|
|
|
|
- <div class="form-group" *ngIf="recordForm.type === 'bloodPressure'">
|
|
|
|
|
- <label for="diastolicValue">舒张压:</label>
|
|
|
|
|
- <input
|
|
|
|
|
- type="number"
|
|
|
|
|
- id="diastolicValue"
|
|
|
|
|
- [(ngModel)]="recordForm.diastolic"
|
|
|
|
|
- name="diastolicValue"
|
|
|
|
|
- placeholder="请输入舒张压"
|
|
|
|
|
- min="0"
|
|
|
|
|
- required
|
|
|
|
|
- >
|
|
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="form-group" *ngIf="recordForm.type === 'bloodPressure'">
|
|
|
|
|
+ <label for="diastolicValue">舒张压:</label>
|
|
|
|
|
+ <div class="input-with-unit">
|
|
|
|
|
+ <input type="number" id="diastolicValue" [(ngModel)]="recordForm.diastolic" name="diastolicValue" placeholder="请输入舒张压" min="0" required>
|
|
|
<span class="unit">mmHg</span>
|
|
<span class="unit">mmHg</span>
|
|
|
</div>
|
|
</div>
|
|
|
-
|
|
|
|
|
- <div class="form-group datetime-wrapper">
|
|
|
|
|
- <label for="recordDate">记录时间:</label>
|
|
|
|
|
- <input
|
|
|
|
|
- type="datetime-local"
|
|
|
|
|
- id="recordDate"
|
|
|
|
|
- [(ngModel)]="recordFormDateTimeString"
|
|
|
|
|
- (ngModelChange)="onRecordDateChange($event)"
|
|
|
|
|
- name="recordDate"
|
|
|
|
|
- required
|
|
|
|
|
- class="datetime-picker-input"
|
|
|
|
|
- >
|
|
|
|
|
- <div class="datetime-preview" *ngIf="recordForm.date">
|
|
|
|
|
- <span class="preview-label">已选择:</span>
|
|
|
|
|
- <span class="preview-value">{{ getFormattedRecordDate() }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div class="form-actions">
|
|
|
|
|
- <button type="button" class="cancel-btn" (click)="closeRecordModal()">取消</button>
|
|
|
|
|
- <button type="submit" class="submit-btn">保存</button>
|
|
|
|
|
- </div>
|
|
|
|
|
- </form>
|
|
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="form-group">
|
|
|
|
|
+ <label for="recordDate">记录时间:</label>
|
|
|
|
|
+ <input type="datetime-local" id="recordDate" [(ngModel)]="recordFormDateTimeString" (ngModelChange)="onRecordDateChange($event)" name="recordDate" required>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="form-actions">
|
|
|
|
|
+ <button type="button" class="cancel-btn" (click)="closeRecordModal()">取消</button>
|
|
|
|
|
+ <button type="submit" class="submit-btn">保存</button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </form>
|
|
|
</div>
|
|
</div>
|
|
|
</app-modal>
|
|
</app-modal>
|
|
|
|
|
|
|
@@ -411,208 +224,165 @@
|
|
|
title: selectedMetric === 'heartRate' ? '心率详情' :
|
|
title: selectedMetric === 'heartRate' ? '心率详情' :
|
|
|
selectedMetric === 'bloodPressure' ? '血压详情' :
|
|
selectedMetric === 'bloodPressure' ? '血压详情' :
|
|
|
selectedMetric === 'bloodOxygen' ? '血氧详情' :
|
|
selectedMetric === 'bloodOxygen' ? '血氧详情' :
|
|
|
- selectedMetric === 'menstrualCycle' ? '经期详情' : '健康综合报告',
|
|
|
|
|
- icon: '📊',
|
|
|
|
|
|
|
+ selectedMetric === 'menstrualCycle' ? '经期详情' : '',
|
|
|
|
|
+ icon: selectedMetric === 'comprehensive' ? '' : '📊',
|
|
|
size: selectedMetric === 'comprehensive' ? 'large' : 'medium',
|
|
size: selectedMetric === 'comprehensive' ? 'large' : 'medium',
|
|
|
- theme: 'gradient'
|
|
|
|
|
|
|
+ theme: 'system',
|
|
|
|
|
+ showHeader: selectedMetric !== 'comprehensive'
|
|
|
}">
|
|
}">
|
|
|
<div class="detail-modal-content">
|
|
<div class="detail-modal-content">
|
|
|
- @if (selectedMetric === 'comprehensive') {
|
|
|
|
|
- <div class="report-content-new">
|
|
|
|
|
- <div class="report-header">
|
|
|
|
|
|
|
+ @if (selectedMetric === 'comprehensive') {
|
|
|
|
|
+ <div class="report-content">
|
|
|
|
|
+ <div class="report-header">
|
|
|
|
|
+ <div class="report-header-content">
|
|
|
<h2>📋 健康状况报告</h2>
|
|
<h2>📋 健康状况报告</h2>
|
|
|
<p class="report-date">{{ today | date: 'yyyy年MM月dd日' }}</p>
|
|
<p class="report-date">{{ today | date: 'yyyy年MM月dd日' }}</p>
|
|
|
</div>
|
|
</div>
|
|
|
-
|
|
|
|
|
- <div class="health-metrics-grid">
|
|
|
|
|
- <!-- 心率卡片 -->
|
|
|
|
|
- <div class="metric-report-card">
|
|
|
|
|
- <div class="metric-card-header">
|
|
|
|
|
- <span class="metric-icon-large">💗</span>
|
|
|
|
|
- <h3>心率状况</h3>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="metric-card-body">
|
|
|
|
|
- <div class="metric-main-value">
|
|
|
|
|
- <span class="value-number">{{ heartRate.value }}</span>
|
|
|
|
|
- <span class="value-unit">{{ heartRate.unit }}</span>
|
|
|
|
|
- <span class="status-badge badge-{{ heartRate.status }}">{{ getStatusText(heartRate.status) }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="metric-trend">
|
|
|
|
|
- <span class="trend-label">趋势:</span>
|
|
|
|
|
- <span class="trend-value trend-{{ heartRate.trend }}">{{ getTrendIcon(heartRate.trend) }} {{ getTrendText(heartRate.trend) }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 血压卡片 -->
|
|
|
|
|
- <div class="metric-report-card">
|
|
|
|
|
- <div class="metric-card-header">
|
|
|
|
|
- <span class="metric-icon-large">🩺</span>
|
|
|
|
|
- <h3>血压状况</h3>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="metric-card-body">
|
|
|
|
|
- <div class="metric-main-value">
|
|
|
|
|
- <span class="value-number">{{ bloodPressure.systolic.value }}/{{ bloodPressure.diastolic.value }}</span>
|
|
|
|
|
- <span class="value-unit">{{ bloodPressure.systolic.unit }}</span>
|
|
|
|
|
- <span class="status-badge badge-{{ bloodPressure.systolic.status }}">{{ getStatusText(bloodPressure.systolic.status) }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="metric-trend">
|
|
|
|
|
- <span class="trend-label">趋势:</span>
|
|
|
|
|
- <span class="trend-value trend-{{ bloodPressure.systolic.trend }}">{{ getTrendIcon(bloodPressure.systolic.trend) }} {{ getTrendText(bloodPressure.systolic.trend) }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 血氧卡片 -->
|
|
|
|
|
- <div class="metric-report-card">
|
|
|
|
|
- <div class="metric-card-header">
|
|
|
|
|
- <span class="metric-icon-large">🫁</span>
|
|
|
|
|
- <h3>血氧状况</h3>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="metric-card-body">
|
|
|
|
|
- <div class="metric-main-value">
|
|
|
|
|
- <span class="value-number">{{ bloodOxygen.value }}</span>
|
|
|
|
|
- <span class="value-unit">{{ bloodOxygen.unit }}</span>
|
|
|
|
|
- <span class="status-badge badge-{{ bloodOxygen.status }}">{{ getStatusText(bloodOxygen.status) }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="metric-trend">
|
|
|
|
|
- <span class="trend-label">趋势:</span>
|
|
|
|
|
- <span class="trend-value trend-{{ bloodOxygen.trend }}">{{ getTrendIcon(bloodOxygen.trend) }} {{ getTrendText(bloodOxygen.trend) }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <button class="report-close-btn" (click)="closeDetailModal()">×</button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="health-metrics-list">
|
|
|
|
|
+ <div class="metric-report-item">
|
|
|
|
|
+ <div class="metric-report-icon">💗</div>
|
|
|
|
|
+ <div class="metric-report-info">
|
|
|
|
|
+ <div class="metric-report-label">心率</div>
|
|
|
|
|
+ <div class="metric-report-value">{{ heartRate.value }} {{ heartRate.unit }}</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ <span class="metric-report-status" [class.normal]="heartRate.status === 'normal'" [class.warning]="heartRate.status === 'warning'" [class.danger]="heartRate.status === 'danger'">{{ getStatusText(heartRate.status) }}</span>
|
|
|
</div>
|
|
</div>
|
|
|
-
|
|
|
|
|
- <!-- 综合建议 -->
|
|
|
|
|
- <div class="advice-section-new">
|
|
|
|
|
- <div class="advice-header">
|
|
|
|
|
- <span class="advice-icon">💡</span>
|
|
|
|
|
- <h3>综合建议</h3>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="advice-list">
|
|
|
|
|
- <div class="advice-item">
|
|
|
|
|
- <span class="advice-item-icon">🏃</span>
|
|
|
|
|
- <span class="advice-text">保持每日30分钟中等强度有氧运动</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="advice-item">
|
|
|
|
|
- <span class="advice-item-icon">🥗</span>
|
|
|
|
|
- <span class="advice-text">饮食清淡,减少盐分和脂肪摄入</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="advice-item">
|
|
|
|
|
- <span class="advice-item-icon">😴</span>
|
|
|
|
|
- <span class="advice-text">保证充足睡眠,避免熬夜</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="advice-item">
|
|
|
|
|
- <span class="advice-item-icon">😊</span>
|
|
|
|
|
- <span class="advice-text">保持良好心态,避免长期精神压力</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- @if (bloodPressure.systolic.status !== 'normal' || bloodPressure.diastolic.status !== 'normal') {
|
|
|
|
|
- <div class="advice-item warning">
|
|
|
|
|
- <span class="advice-item-icon">⚠️</span>
|
|
|
|
|
- <span class="advice-text">建议每日测量血压并记录,如有异常及时就医</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ <div class="metric-report-item">
|
|
|
|
|
+ <div class="metric-report-icon">🩺</div>
|
|
|
|
|
+ <div class="metric-report-info">
|
|
|
|
|
+ <div class="metric-report-label">血压</div>
|
|
|
|
|
+ <div class="metric-report-value">{{ bloodPressure.systolic.value }}/{{ bloodPressure.diastolic.value }} mmHg</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ <span class="metric-report-status" [class.normal]="bloodPressure.systolic.status === 'normal'" [class.warning]="bloodPressure.systolic.status === 'warning'" [class.danger]="bloodPressure.systolic.status === 'danger'">{{ getStatusText(bloodPressure.systolic.status) }}</span>
|
|
|
</div>
|
|
</div>
|
|
|
- </div>
|
|
|
|
|
- } @else if (selectedMetric === 'heartRate') {
|
|
|
|
|
- <div class="metric-details">
|
|
|
|
|
- <div class="detail-item">
|
|
|
|
|
- <span class="label">当前心率:</span>
|
|
|
|
|
- <span class="value">{{ heartRate.value }} {{ heartRate.unit }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="detail-item">
|
|
|
|
|
- <span class="label">状态:</span>
|
|
|
|
|
- <span class="value" [ngClass]="heartRate.status">{{ getStatusText(heartRate.status) }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="detail-item">
|
|
|
|
|
- <span class="label">记录时间:</span>
|
|
|
|
|
- <span class="value">{{ heartRate.timestamp | date: 'yyyy-MM-dd HH:mm:ss' }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="detail-item">
|
|
|
|
|
- <span class="label">趋势:</span>
|
|
|
|
|
- <span class="value trend" [ngClass]="heartRate.trend">
|
|
|
|
|
- {{ getTrendText(heartRate.trend) }}
|
|
|
|
|
- </span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="advice-section">
|
|
|
|
|
- <h4>健康建议</h4>
|
|
|
|
|
- <p>{{ getHealthAdvice('heartRate') }}</p>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- } @else if (selectedMetric === 'bloodPressure') {
|
|
|
|
|
- <div class="metric-details">
|
|
|
|
|
- <div class="detail-item">
|
|
|
|
|
- <span class="label">收缩压:</span>
|
|
|
|
|
- <span class="value">{{ bloodPressure.systolic.value }} {{ bloodPressure.systolic.unit }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="detail-item">
|
|
|
|
|
- <span class="label">舒张压:</span>
|
|
|
|
|
- <span class="value">{{ bloodPressure.diastolic.value }} {{ bloodPressure.diastolic.unit }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="detail-item">
|
|
|
|
|
- <span class="label">状态:</span>
|
|
|
|
|
- <span class="value" [ngClass]="bloodPressure.systolic.status">{{ getStatusText(bloodPressure.systolic.status) }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="detail-item">
|
|
|
|
|
- <span class="label">记录时间:</span>
|
|
|
|
|
- <span class="value">{{ bloodPressure.systolic.timestamp | date: 'yyyy-MM-dd HH:mm:ss' }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="advice-section">
|
|
|
|
|
- <h4>健康建议</h4>
|
|
|
|
|
- <p>{{ getHealthAdvice('bloodPressure') }}</p>
|
|
|
|
|
|
|
+ <div class="metric-report-item">
|
|
|
|
|
+ <div class="metric-report-icon">🫁</div>
|
|
|
|
|
+ <div class="metric-report-info">
|
|
|
|
|
+ <div class="metric-report-label">血氧</div>
|
|
|
|
|
+ <div class="metric-report-value">{{ bloodOxygen.value }}%</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <span class="metric-report-status" [class.normal]="bloodOxygen.status === 'normal'" [class.warning]="bloodOxygen.status === 'warning'" [class.danger]="bloodOxygen.status === 'danger'">{{ getStatusText(bloodOxygen.status) }}</span>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
- } @else if (selectedMetric === 'bloodOxygen') {
|
|
|
|
|
- <div class="metric-details">
|
|
|
|
|
- <div class="detail-item">
|
|
|
|
|
- <span class="label">血氧饱和度:</span>
|
|
|
|
|
- <span class="value">{{ bloodOxygen.value }} {{ bloodOxygen.unit }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="detail-item">
|
|
|
|
|
- <span class="label">状态:</span>
|
|
|
|
|
- <span class="value" [ngClass]="bloodOxygen.status">{{ getStatusText(bloodOxygen.status) }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="detail-item">
|
|
|
|
|
- <span class="label">记录时间:</span>
|
|
|
|
|
- <span class="value">{{ bloodOxygen.timestamp | date: 'yyyy-MM-dd HH:mm:ss' }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="advice-section">
|
|
|
|
|
- <h4>健康建议</h4>
|
|
|
|
|
- <p>{{ getHealthAdvice('bloodOxygen') }}</p>
|
|
|
|
|
|
|
+
|
|
|
|
|
+ <div class="advice-section">
|
|
|
|
|
+ <h3>💡 综合建议</h3>
|
|
|
|
|
+ <div class="advice-list">
|
|
|
|
|
+ <div class="advice-item"><span class="advice-icon">🏃</span><span>保持每日30分钟中等强度有氧运动</span></div>
|
|
|
|
|
+ <div class="advice-item"><span class="advice-icon">🥗</span><span>饮食清淡,减少盐分和脂肪摄入</span></div>
|
|
|
|
|
+ <div class="advice-item"><span class="advice-icon">😴</span><span>保证充足睡眠,避免熬夜</span></div>
|
|
|
|
|
+ <div class="advice-item"><span class="advice-icon">😊</span><span>保持良好心态,避免长期精神压力</span></div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
- } @else if (selectedMetric === 'menstrualCycle') {
|
|
|
|
|
- <div class="metric-details">
|
|
|
|
|
- <div class="detail-item">
|
|
|
|
|
- <span class="label">上次经期开始:</span>
|
|
|
|
|
- <span class="value">{{ menstrualCycle.startDate | date: 'yyyy-MM-dd' }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="detail-item">
|
|
|
|
|
- <span class="label">上次经期结束:</span>
|
|
|
|
|
- <span class="value">{{ menstrualCycle.endDate | date: 'yyyy-MM-dd' }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="detail-item">
|
|
|
|
|
- <span class="label">下次经期预计:</span>
|
|
|
|
|
- <span class="value">{{ menstrualCycle.predictedNextStartDate | date: 'yyyy-MM-dd' }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="detail-item">
|
|
|
|
|
- <span class="label">月经周期:</span>
|
|
|
|
|
- <span class="value">{{ menstrualCycle.length }}天</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="symptoms-section">
|
|
|
|
|
|
|
+ </div>
|
|
|
|
|
+ } @else if (selectedMetric === 'heartRate') {
|
|
|
|
|
+ <div class="metric-details">
|
|
|
|
|
+ <div class="detail-item"><span class="label">当前心率:</span><span class="value">{{ heartRate.value }} {{ heartRate.unit }}</span></div>
|
|
|
|
|
+ <div class="detail-item"><span class="label">状态:</span><span class="value" [class.normal]="heartRate.status === 'normal'" [class.warning]="heartRate.status === 'warning'" [class.danger]="heartRate.status === 'danger'">{{ getStatusText(heartRate.status) }}</span></div>
|
|
|
|
|
+ <div class="detail-item"><span class="label">记录时间:</span><span class="value">{{ heartRate.timestamp | date: 'yyyy-MM-dd HH:mm' }}</span></div>
|
|
|
|
|
+ <div class="detail-item"><span class="label">趋势:</span><span class="value">{{ getTrendIcon(heartRate.trend) }} {{ getTrendText(heartRate.trend) }}</span></div>
|
|
|
|
|
+ <div class="advice-box"><h4>健康建议</h4><p>{{ getHealthAdvice('heartRate') }}</p></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ } @else if (selectedMetric === 'bloodPressure') {
|
|
|
|
|
+ <div class="metric-details">
|
|
|
|
|
+ <div class="detail-item"><span class="label">收缩压:</span><span class="value">{{ bloodPressure.systolic.value }} mmHg</span></div>
|
|
|
|
|
+ <div class="detail-item"><span class="label">舒张压:</span><span class="value">{{ bloodPressure.diastolic.value }} mmHg</span></div>
|
|
|
|
|
+ <div class="detail-item"><span class="label">状态:</span><span class="value" [class.normal]="bloodPressure.systolic.status === 'normal'" [class.warning]="bloodPressure.systolic.status === 'warning'" [class.danger]="bloodPressure.systolic.status === 'danger'">{{ getStatusText(bloodPressure.systolic.status) }}</span></div>
|
|
|
|
|
+ <div class="detail-item"><span class="label">记录时间:</span><span class="value">{{ bloodPressure.systolic.timestamp | date: 'yyyy-MM-dd HH:mm' }}</span></div>
|
|
|
|
|
+ <div class="advice-box"><h4>健康建议</h4><p>{{ getHealthAdvice('bloodPressure') }}</p></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ } @else if (selectedMetric === 'bloodOxygen') {
|
|
|
|
|
+ <div class="metric-details">
|
|
|
|
|
+ <div class="detail-item"><span class="label">血氧饱和度:</span><span class="value">{{ bloodOxygen.value }}%</span></div>
|
|
|
|
|
+ <div class="detail-item"><span class="label">状态:</span><span class="value" [class.normal]="bloodOxygen.status === 'normal'" [class.warning]="bloodOxygen.status === 'warning'" [class.danger]="bloodOxygen.status === 'danger'">{{ getStatusText(bloodOxygen.status) }}</span></div>
|
|
|
|
|
+ <div class="detail-item"><span class="label">记录时间:</span><span class="value">{{ bloodOxygen.timestamp | date: 'yyyy-MM-dd HH:mm' }}</span></div>
|
|
|
|
|
+ <div class="advice-box"><h4>健康建议</h4><p>{{ getHealthAdvice('bloodOxygen') }}</p></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ } @else if (selectedMetric === 'menstrualCycle') {
|
|
|
|
|
+ <div class="metric-details">
|
|
|
|
|
+ <div class="detail-item"><span class="label">上次经期开始:</span><span class="value">{{ menstrualCycle.startDate | date: 'yyyy-MM-dd' }}</span></div>
|
|
|
|
|
+ <div class="detail-item"><span class="label">上次经期结束:</span><span class="value">{{ menstrualCycle.endDate | date: 'yyyy-MM-dd' }}</span></div>
|
|
|
|
|
+ <div class="detail-item"><span class="label">下次经期预计:</span><span class="value">{{ menstrualCycle.predictedNextStartDate | date: 'yyyy-MM-dd' }}</span></div>
|
|
|
|
|
+ <div class="detail-item"><span class="label">月经周期:</span><span class="value">{{ menstrualCycle.length }}天</span></div>
|
|
|
|
|
+ @if (menstrualCycle.symptoms && menstrualCycle.symptoms.length > 0) {
|
|
|
|
|
+ <div class="symptoms-box">
|
|
|
<h4>记录的症状</h4>
|
|
<h4>记录的症状</h4>
|
|
|
- <ul>
|
|
|
|
|
|
|
+ <div class="symptom-tags">
|
|
|
@for (symptom of menstrualCycle.symptoms; track symptom) {
|
|
@for (symptom of menstrualCycle.symptoms; track symptom) {
|
|
|
- <li>{{ symptom }}</li>
|
|
|
|
|
- }
|
|
|
|
|
- </ul>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="advice-section">
|
|
|
|
|
- <h4>健康建议</h4>
|
|
|
|
|
- <p>{{ getHealthAdvice('menstrualCycle') }}</p>
|
|
|
|
|
|
|
+ <span class="symptom-tag">{{ symptom }}</span>
|
|
|
|
|
+ }
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ }
|
|
|
|
|
+ <div class="advice-box"><h4>健康建议</h4><p>{{ getHealthAdvice('menstrualCycle') }}</p></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ }
|
|
|
|
|
+ </div>
|
|
|
|
|
+</app-modal>
|
|
|
|
|
+
|
|
|
|
|
+<!-- 经期记录模态框 -->
|
|
|
|
|
+<app-modal
|
|
|
|
|
+ [(isOpen)]="showMenstrualRecordModal"
|
|
|
|
|
+ [config]="{
|
|
|
|
|
+ title: '记录经期',
|
|
|
|
|
+ icon: '📝',
|
|
|
|
|
+ size: 'medium',
|
|
|
|
|
+ theme: 'system'
|
|
|
|
|
+ }">
|
|
|
|
|
+ <div class="menstrual-record-content">
|
|
|
|
|
+ <form (ngSubmit)="submitMenstrualRecord()">
|
|
|
|
|
+ <div class="form-group">
|
|
|
|
|
+ <label for="startDate">开始日期:</label>
|
|
|
|
|
+ <input type="date" id="startDate" [(ngModel)]="menstrualRecordForm.startDate" name="startDate" required>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="form-group">
|
|
|
|
|
+ <label for="endDate">结束日期 (可选):</label>
|
|
|
|
|
+ <input type="date" id="endDate" [(ngModel)]="menstrualRecordForm.endDate" name="endDate">
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="form-group">
|
|
|
|
|
+ <label>经量:</label>
|
|
|
|
|
+ <div class="flow-options">
|
|
|
|
|
+ <label class="flow-option">
|
|
|
|
|
+ <input type="radio" [(ngModel)]="menstrualRecordForm.flow" name="flow" value="light">
|
|
|
|
|
+ <span>偏少</span>
|
|
|
|
|
+ </label>
|
|
|
|
|
+ <label class="flow-option">
|
|
|
|
|
+ <input type="radio" [(ngModel)]="menstrualRecordForm.flow" name="flow" value="normal">
|
|
|
|
|
+ <span>正常</span>
|
|
|
|
|
+ </label>
|
|
|
|
|
+ <label class="flow-option">
|
|
|
|
|
+ <input type="radio" [(ngModel)]="menstrualRecordForm.flow" name="flow" value="heavy">
|
|
|
|
|
+ <span>偏多</span>
|
|
|
|
|
+ </label>
|
|
|
</div>
|
|
</div>
|
|
|
- }
|
|
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="form-group">
|
|
|
|
|
+ <label>症状 (可多选):</label>
|
|
|
|
|
+ <div class="symptoms-grid">
|
|
|
|
|
+ @for (symptom of availableSymptoms; track symptom) {
|
|
|
|
|
+ <label class="symptom-option" [class.selected]="menstrualRecordForm.symptoms.includes(symptom)">
|
|
|
|
|
+ <input type="checkbox" [checked]="menstrualRecordForm.symptoms.includes(symptom)" (change)="toggleSymptom(symptom)">
|
|
|
|
|
+ <span>{{ symptom }}</span>
|
|
|
|
|
+ </label>
|
|
|
|
|
+ }
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="form-group">
|
|
|
|
|
+ <label for="notes">备注 (可选):</label>
|
|
|
|
|
+ <textarea id="notes" [(ngModel)]="menstrualRecordForm.notes" name="notes" placeholder="记录其他症状或注意事项" rows="3"></textarea>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="form-actions">
|
|
|
|
|
+ <button type="button" class="cancel-btn" (click)="closeMenstrualRecordModal()">取消</button>
|
|
|
|
|
+ <button type="submit" class="submit-btn">保存记录</button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </form>
|
|
|
</div>
|
|
</div>
|
|
|
-</app-modal>
|
|
|
|
|
|
|
+</app-modal>
|