Files
memind/templates/health-p0-log.html
T
john f96fdcb3b9 feat(health): add P0 health channel kernel and encrypted health zone.
Lock health recording behind confirm-only state machines, reject public publishes for the health category, and ship the 14-day experiment Page Data templates with tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-09 18:04:26 +08:00

139 lines
6.2 KiB
HTML

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>MeMind Health P0 每日记录</title>
<style>
body { font-family: sans-serif; max-width: 40rem; margin: 1.5rem auto; padding: 0 1rem; color: #1f2937; }
label { display: block; margin: 0.6rem 0 0.2rem; font-weight: 600; }
input, select, textarea { width: 100%; box-sizing: border-box; padding: 0.5rem; }
.row { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 0.5rem; }
details { margin-top: 1rem; }
button { margin-top: 1rem; padding: 0.7rem 1.2rem; }
.status { margin-top: 1rem; min-height: 1.5rem; }
</style>
</head>
<body>
<h1>每日健康记录</h1>
<p>晨间血压必填。请先静坐 5 分钟,固定同一侧手臂,连测 2 次后记录第 2 次。</p>
<form id="log-form">
<label for="participant_code">编号</label>
<input id="participant_code" name="participant_code" required />
<label for="log_date">日期</label>
<input id="log_date" name="log_date" type="date" required />
<label for="am_measured_at">晨测时刻</label>
<input id="am_measured_at" name="am_measured_at" placeholder="07:20" required />
<div class="row">
<div>
<label for="am_systolic">收缩压</label>
<input id="am_systolic" name="am_systolic" type="number" inputmode="numeric" required />
</div>
<div>
<label for="am_diastolic">舒张压</label>
<input id="am_diastolic" name="am_diastolic" type="number" inputmode="numeric" required />
</div>
<div>
<label for="am_pulse">脉搏</label>
<input id="am_pulse" name="am_pulse" type="number" inputmode="numeric" />
</div>
</div>
<label for="symptoms">症状</label>
<select id="symptoms" name="symptoms">
<option value="none" selected></option>
<option value="dizziness">头晕</option>
<option value="headache">头痛</option>
<option value="chest_tightness">胸闷</option>
<option value="palpitation">心慌心悸</option>
<option value="fatigue">乏力</option>
<option value="shortness_of_breath">气短</option>
<option value="leg_edema">下肢水肿</option>
<option value="insomnia">失眠</option>
<option value="other">其他</option>
</select>
<details>
<summary>晚间血压 / 睡眠 / 体重 / 扰动(可选)</summary>
<label for="pm_measured_at">晚测时刻</label>
<input id="pm_measured_at" name="pm_measured_at" />
<div class="row">
<div>
<label for="pm_systolic">晚收缩压</label>
<input id="pm_systolic" name="pm_systolic" type="number" inputmode="numeric" />
</div>
<div>
<label for="pm_diastolic">晚舒张压</label>
<input id="pm_diastolic" name="pm_diastolic" type="number" inputmode="numeric" />
</div>
<div>
<label for="pm_pulse">晚脉搏</label>
<input id="pm_pulse" name="pm_pulse" type="number" inputmode="numeric" />
</div>
</div>
<label for="sleep_minutes">睡眠分钟</label>
<input id="sleep_minutes" name="sleep_minutes" type="number" inputmode="numeric" />
<label for="weight_kg">体重 kg</label>
<input id="weight_kg" name="weight_kg" type="number" step="0.1" inputmode="decimal" />
<label for="alcohol">昨日饮酒</label>
<select id="alcohol" name="alcohol">
<option value="none"></option>
<option value="light">少量</option>
<option value="heavy">较多</option>
</select>
<label for="stress">情绪压力</label>
<select id="stress" name="stress">
<option value="low"></option>
<option value="mid"></option>
<option value="high"></option>
</select>
<label for="other_note">备注</label>
<textarea id="other_note" name="other_note" rows="2"></textarea>
</details>
<button type="submit">保存今日记录</button>
</form>
<p id="status" class="status"></p>
<script src="/assets/page-data-client.js"></script>
<script>
const form = document.getElementById('log-form');
const statusEl = document.getElementById('status');
const params = new URLSearchParams(window.location.search);
const preset = params.get('p');
if (preset) document.getElementById('participant_code').value = preset;
const today = new Date();
const iso = today.toISOString().slice(0, 10);
document.getElementById('log_date').value = iso;
form.addEventListener('submit', async (event) => {
event.preventDefault();
const data = Object.fromEntries(new FormData(form).entries());
const client = MindSpacePageData.createClient({ apiBase: '/api' });
statusEl.textContent = '正在保存…';
try {
await client.insertRow('health_p0_daily_log', {
participant_code: data.participant_code,
log_date: data.log_date,
am_measured_at: data.am_measured_at || null,
am_systolic: data.am_systolic ? Number(data.am_systolic) : null,
am_diastolic: data.am_diastolic ? Number(data.am_diastolic) : null,
am_pulse: data.am_pulse ? Number(data.am_pulse) : null,
pm_measured_at: data.pm_measured_at || null,
pm_systolic: data.pm_systolic ? Number(data.pm_systolic) : null,
pm_diastolic: data.pm_diastolic ? Number(data.pm_diastolic) : null,
pm_pulse: data.pm_pulse ? Number(data.pm_pulse) : null,
sleep_minutes: data.sleep_minutes ? Number(data.sleep_minutes) : null,
weight_kg: data.weight_kg ? Number(data.weight_kg) : null,
symptoms: JSON.stringify([{ code: data.symptoms || 'none', severity: data.symptoms === 'none' ? null : 1 }]),
alcohol: data.alcohol || 'none',
stress: data.stress || 'low',
other_note: data.other_note || null,
entry_channel: 'h5_form',
photo_sent: false,
});
statusEl.textContent = '已记录。请继续按规程测量,不要依赖本页做医疗判断。';
} catch (error) {
statusEl.textContent = error instanceof Error ? error.message : '保存失败';
}
});
</script>
</body>
</html>