2baf29b3ae
Deliver encrypted health zone, observation API, baseline maturity pipeline, page-data bindings, and H5/WeChat channel integration for health P0. Co-authored-by: Cursor <cursoragent@cursor.com>
74 lines
2.4 KiB
JavaScript
74 lines
2.4 KiB
JavaScript
import { isValidObservationForBaseline } from './health-baseline-maturity.mjs';
|
||
|
||
const METRIC_LABELS = Object.freeze({
|
||
bp_systolic: '收缩压',
|
||
bp_diastolic: '舒张压',
|
||
hr: '心率',
|
||
spo2: '血氧',
|
||
weight: '体重',
|
||
temperature: '体温',
|
||
sleep_minutes: '睡眠',
|
||
symptom: '症状',
|
||
});
|
||
|
||
function dayKey(observedAt) {
|
||
const date = new Date(Number(observedAt));
|
||
if (Number.isNaN(date.getTime())) return 'unknown';
|
||
return date.toISOString().slice(0, 10);
|
||
}
|
||
|
||
function formatMetricValue(row) {
|
||
if (row.metricType === 'symptom') {
|
||
return row.valueText ?? '—';
|
||
}
|
||
if (row.valueNum == null) return '—';
|
||
const unit = row.unit ? ` ${row.unit}` : '';
|
||
return `${row.valueNum}${unit}`;
|
||
}
|
||
|
||
export function buildHealthTimeline(observations = [], { limitDays = 30 } = {}) {
|
||
const valid = observations.filter(isValidObservationForBaseline);
|
||
const byDay = new Map();
|
||
|
||
for (const row of valid) {
|
||
const key = dayKey(row.observedAt);
|
||
if (!byDay.has(key)) byDay.set(key, []);
|
||
byDay.get(key).push(row);
|
||
}
|
||
|
||
const days = [...byDay.keys()].sort((a, b) => b.localeCompare(a)).slice(0, limitDays);
|
||
return days.map((date) => {
|
||
const rows = byDay.get(date) ?? [];
|
||
const metrics = {};
|
||
for (const row of rows) {
|
||
const label = METRIC_LABELS[row.metricType] ?? row.metricType;
|
||
metrics[row.metricType] = {
|
||
label,
|
||
value: formatMetricValue(row),
|
||
context: row.context ?? null,
|
||
qualityFlag: row.qualityFlag ?? 'ok',
|
||
observedAt: row.observedAt,
|
||
};
|
||
}
|
||
return { date, metrics, count: rows.length };
|
||
});
|
||
}
|
||
|
||
export function summarizeTimelineForAssess(timeline = []) {
|
||
if (!timeline.length) {
|
||
return '还没有足够的健康记录。请先连续录入几天晨间血压、睡眠和症状,基线成熟后才能做评估。';
|
||
}
|
||
const latest = timeline[0];
|
||
const lines = [`最近一天(${latest.date}):`];
|
||
for (const item of Object.values(latest.metrics)) {
|
||
lines.push(`- ${item.label}: ${item.value}`);
|
||
}
|
||
if (timeline.length >= 7) {
|
||
lines.push('', `近 ${Math.min(timeline.length, 14)} 天已有 ${timeline.length} 天记录,可开始观察个人基线变化。`);
|
||
} else {
|
||
lines.push('', `当前仅 ${timeline.length} 天记录,建议至少连续 7 天后再看趋势。`);
|
||
}
|
||
lines.push('', '这不是医疗诊断;如有不适请及时就医。');
|
||
return lines.join('\n');
|
||
}
|