|
|
@@ -6,155 +6,91 @@
|
|
|
|
|
|
<main class="main-content">
|
|
|
<div class="monitoring-content">
|
|
|
- <!-- 健康指标概览 -->
|
|
|
- <section class="health-overview">
|
|
|
- <div class="section-header">
|
|
|
- <h2>健康指标概览</h2>
|
|
|
- <button class="add-record-btn" (click)="openRecordModal('heartRate')">+ 记录数据</button>
|
|
|
- </div>
|
|
|
- <div class="health-cards">
|
|
|
- <!-- 心率监测卡片 -->
|
|
|
- <div class="health-card" (click)="openDetailModal('heartRate')">
|
|
|
- <div class="card-header">
|
|
|
- <h3>心率</h3>
|
|
|
- <span class="status-indicator" [ngClass]="heartRate.status" title="{{ getStatusText(heartRate.status) }}"></span>
|
|
|
- <span class="last-updated">最后更新: {{ formatDate(heartRate.timestamp) }}</span>
|
|
|
- </div>
|
|
|
- <div class="card-content">
|
|
|
- <div class="metric-value {{ getStatusClass(heartRate.status) }}">
|
|
|
- {{ heartRate.value }}<span class="metric-unit">{{ heartRate.unit }}</span>
|
|
|
- <span class="trend-icon">{{ getTrendIcon(heartRate.trend) }}</span>
|
|
|
+ <!-- 综合健康状态卡片 - 重新设计 -->
|
|
|
+ <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="health-progress">
|
|
|
- <div class="progress-bar">
|
|
|
- <div class="progress-fill {{ getStatusClass(heartRate.status) }}" style="width: 60%;"></div>
|
|
|
- </div>
|
|
|
- <div class="progress-range">
|
|
|
- <span>60</span>
|
|
|
- <span>100</span>
|
|
|
- </div>
|
|
|
+ <div class="status-badge-large good">
|
|
|
+ <span class="status-icon">✓</span>
|
|
|
+ <span class="status-text">良好</span>
|
|
|
</div>
|
|
|
- <p class="health-advice">{{ getHealthAdvice('heartRate') }}</p>
|
|
|
- </div>
|
|
|
- <div class="card-actions">
|
|
|
- <button class="card-button primary" (click)="$event.stopPropagation(); openRecordModal('heartRate')">记录</button>
|
|
|
- <button class="card-button secondary" (click)="$event.stopPropagation(); openDetailModal('heartRate')">详情</button>
|
|
|
</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="health-card" (click)="openDetailModal('bloodPressure')">
|
|
|
- <div class="card-header">
|
|
|
- <h3>血压</h3>
|
|
|
- <span class="status-indicator" [ngClass]="bloodPressure.systolic.status" title="{{ getStatusText(bloodPressure.systolic.status) }}"></span>
|
|
|
- <span class="last-updated">最后更新: {{ formatDate(bloodPressure.systolic.timestamp) }}</span>
|
|
|
- </div>
|
|
|
- <div class="card-content">
|
|
|
- <div class="blood-pressure-values">
|
|
|
- <div class="bp-value systolic {{ getStatusClass(bloodPressure.systolic.status) }}">
|
|
|
- {{ bloodPressure.systolic.value }}
|
|
|
+
|
|
|
+ <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>
|
|
|
- <span class="bp-separator">/</span>
|
|
|
- <div class="bp-value diastolic {{ getStatusClass(bloodPressure.diastolic.status) }}">
|
|
|
- {{ bloodPressure.diastolic.value }}
|
|
|
+ <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>
|
|
|
- <span class="metric-unit">{{ bloodPressure.systolic.unit }}</span>
|
|
|
</div>
|
|
|
- <p class="health-advice">{{ getHealthAdvice('bloodPressure') }}</p>
|
|
|
- </div>
|
|
|
- <div class="card-actions">
|
|
|
- <button class="card-button primary" (click)="$event.stopPropagation(); openRecordModal('bloodPressure')">记录</button>
|
|
|
- <button class="card-button secondary" (click)="$event.stopPropagation(); openDetailModal('bloodPressure')">详情</button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 血氧监测卡片 -->
|
|
|
- <div class="health-card" (click)="openDetailModal('bloodOxygen')">
|
|
|
- <div class="card-header">
|
|
|
- <h3>血氧</h3>
|
|
|
- <span class="status-indicator" [ngClass]="bloodOxygen.status" title="{{ getStatusText(bloodOxygen.status) }}"></span>
|
|
|
- <span class="last-updated">最后更新: {{ formatDate(bloodOxygen.timestamp) }}</span>
|
|
|
- </div>
|
|
|
- <div class="card-content">
|
|
|
- <div class="metric-value {{ getStatusClass(bloodOxygen.status) }}">
|
|
|
- {{ bloodOxygen.value }}<span class="metric-unit">{{ bloodOxygen.unit }}</span>
|
|
|
- <span class="trend-icon">{{ getTrendIcon(bloodOxygen.trend) }}</span>
|
|
|
+
|
|
|
+ <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="health-progress">
|
|
|
- <div class="progress-bar">
|
|
|
- <div class="progress-fill {{ getStatusClass(bloodOxygen.status) }}" style="width: 90%;"></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="progress-range">
|
|
|
- <span>90</span>
|
|
|
- <span>100</span>
|
|
|
+ <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>
|
|
|
- <p class="health-advice">{{ getHealthAdvice('bloodOxygen') }}</p>
|
|
|
- </div>
|
|
|
- <div class="card-actions">
|
|
|
- <button class="card-button primary" (click)="$event.stopPropagation(); openRecordModal('bloodOxygen')">记录</button>
|
|
|
- <button class="card-button secondary" (click)="$event.stopPropagation(); openDetailModal('bloodOxygen')">详情</button>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</section>
|
|
|
|
|
|
- <!-- 综合健康状态卡片 -->
|
|
|
- <section class="health-status-section">
|
|
|
- <div class="health-status-card">
|
|
|
- <div class="health-status-header">
|
|
|
- <h3>综合健康状态</h3>
|
|
|
- <div class="overall-status good">良好</div>
|
|
|
- </div>
|
|
|
- <p class="status-description">您的整体健康状况良好,心率、血压和血氧指标均在正常范围内。建议继续保持当前的生活方式和健康习惯。</p>
|
|
|
- <div class="key-metrics-summary">
|
|
|
- <div class="key-metric-item">
|
|
|
- <span class="metric-label">健康评分:</span>
|
|
|
- <span class="metric-value">85/100</span>
|
|
|
- </div>
|
|
|
- <div class="key-metric-item">
|
|
|
- <span class="metric-label">心率:</span>
|
|
|
- <span class="metric-value">{{ heartRate.value }} {{ heartRate.unit }}</span>
|
|
|
- </div>
|
|
|
- <div class="key-metric-item">
|
|
|
- <span class="metric-label">血压:</span>
|
|
|
- <span class="metric-value">{{ bloodPressure.systolic.value }}/{{ bloodPressure.diastolic.value }}</span>
|
|
|
- </div>
|
|
|
- <div class="key-metric-item">
|
|
|
- <span class="metric-label">血氧:</span>
|
|
|
- <span class="metric-value">{{ bloodOxygen.value }}%</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="card-actions">
|
|
|
- <button class="card-button secondary" (click)="openDetailModal('comprehensive')">查看综合报告</button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </section>
|
|
|
-
|
|
|
- <!-- 经期监测卡片 (仅女性用户显示) -->
|
|
|
- @if (isFemaleUser) {
|
|
|
- <div class="health-card" (click)="openDetailModal('menstrualCycle')">
|
|
|
- <div class="card-header">
|
|
|
- <h3>经期监测</h3>
|
|
|
- <span class="status-indicator normal" title="规律"></span>
|
|
|
- </div>
|
|
|
- <div class="card-content">
|
|
|
- <div class="menstrual-info">
|
|
|
- <p><strong>上次经期:</strong> {{ formatDate(menstrualCycle.startDate) }} - {{ formatDate(menstrualCycle.endDate) }}</p>
|
|
|
- <p><strong>预计下次经期:</strong> {{ formatDate(menstrualCycle.predictedNextStartDate || today) }}</p>
|
|
|
- <p><strong>距离下次经期:</strong> {{ getDaysUntilNextPeriod() }} 天</p>
|
|
|
- @if (menstrualCycle.symptoms && menstrualCycle.symptoms.length > 0) {
|
|
|
- <p><strong>常见症状:</strong> {{ menstrualCycle.symptoms.join('、') }}</p>
|
|
|
- }
|
|
|
- </div>
|
|
|
- <p class="health-advice">{{ getHealthAdvice('menstrualCycle') }}</p>
|
|
|
- </div>
|
|
|
- <div class="card-actions">
|
|
|
- <button class="card-button secondary" (click)="$event.stopPropagation(); openDetailModal('menstrualCycle')">详情</button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- }
|
|
|
-
|
|
|
<!-- 数据可视化区域 -->
|
|
|
<section class="data-visualization">
|
|
|
<div class="section-header">
|
|
|
@@ -297,6 +233,111 @@
|
|
|
</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>
|
|
|
+ <div class="status-item">
|
|
|
+ <span class="status-label">周期长度</span>
|
|
|
+ <span class="status-value">{{ menstrualCycle.length }} 天</span>
|
|
|
+ </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>
|
|
|
+ </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>
|
|
|
</main>
|
|
|
</div>
|
|
|
@@ -339,16 +380,21 @@
|
|
|
<span class="unit">mmHg</span>
|
|
|
</div>
|
|
|
|
|
|
- <div class="form-group">
|
|
|
+ <div class="form-group datetime-wrapper">
|
|
|
<label for="recordDate">记录时间:</label>
|
|
|
<input
|
|
|
type="datetime-local"
|
|
|
id="recordDate"
|
|
|
- [(ngModel)]="recordForm.date"
|
|
|
+ [(ngModel)]="recordFormDateTimeString"
|
|
|
+ (ngModelChange)="onRecordDateChange($event)"
|
|
|
name="recordDate"
|
|
|
- format="yyyy年MM月dd日 HH:mm"
|
|
|
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">
|