Files
memind/health-timeline.mjs
T
john 2baf29b3ae feat(health): complete P0 health channel — baseline engine, page-data, MindSpace UI
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>
2026-09-09 18:04:57 +08:00

74 lines
2.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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');
}