「我的资料」改「孕期档案」:照数胎动改成一行一项白卡,头像放第一行;孕周 / 预产期点开滚轮选择 v26101025

Co-Authored-By: AI 助手
This commit is contained in:
karlcarlo
2026-10-11 14:59:27 +00:00
parent cc97ee2b6c
commit b3f13468a9
3 changed files with 230 additions and 122 deletions

128
js/app.js
View File

@@ -3,7 +3,7 @@
(function () {
'use strict';
/* 页面版本号(YYMMDD+序号):显示在「关于兜爸心选」页底部;bump 时同步 head 注释与 ?v= */
var VER = '26101024';
var VER = '26101025';
const $ = (s, c) => (c || document).querySelector(s);
const $$ = (s, c) => Array.from((c || document).querySelectorAll(s));
@@ -1302,7 +1302,15 @@
function syncDuePh() {
const due = parseDay(pgDue.value);
const t = $('#pgDueTxt');
if (t) { t.textContent = due ? fmtDay(due) : '点这里选预产期'; t.parentNode.classList.toggle('is-set', !!due); }
/* 孕期档案两行(2026-10-11 改版):右侧值都从 #pgDue 现算 */
if (t) { t.textContent = due ? due.getFullYear() + ' 年 ' + (due.getMonth() + 1) + ' 月 ' + due.getDate() + ' 日' : '去填写'; t.classList.toggle('is-empty', !due); }
const wt = $('#pgWeekTxt');
if (wt) {
const lf = due ? Math.round((midnight(due) - midnight(new Date())) / DAY_MS) : null;
const g = due ? gaFromDue(due) : 0;
wt.textContent = !due ? '去填写' : lf < 0 ? '宝宝已出生' : '孕 ' + Math.floor(g / 7) + ' 周' + (g % 7 ? ' +' + (g % 7) + ' 天' : '');
wt.classList.toggle('is-empty', !due);
}
const sum = $('#pgSum');
if (!sum) return;
sum.classList.toggle('is-set', !!due);
@@ -1382,11 +1390,112 @@
}));
/* 性别三选一 */
/* 性别:男孩 / 女孩二选一,再点一下已选的就取消(= 还不知道,保存成 unknown) */
$$('#pgSex .pick').forEach(b => b.addEventListener('click', () => {
$$('#pgSex .pick').forEach(x => x.classList.toggle('is-active', x === b));
const on = !b.classList.contains('is-active');
$$('#pgSex .pick').forEach(x => x.classList.toggle('is-active', on && x === b));
haptic();
}));
/* ---------- 孕期档案 · 滚轮选择(2026-10-11,照数胎动的孕期档案) ----------
week:孕 0–42 周 × 0–6 天,下面实时显示对应预产期;due:年 / 月 / 日,下面显示对应孕周。
确定后写 #pgWeek/#pgDay 或 #pgDue 并 dispatch change —— 换算、行内文字都走原来那两个监听,不另算一套。 */
const PK_H = 40; /* 每行高度,CSS .pk-col i 同值 */
const pkSheet = $('#pkSheet'), pkScrim = $('#pkScrim'), pkWheels = $('#pkWheels');
let pkMode = 'week';
function pkCol(key, items, sel) {
return '<div class="pk-col" data-k="' + key + '">' + items.map((t, i) => '<i data-i="' + i + '">' + t + '</i>').join('') + '</div>';
}
function pkIdx(col) { return Math.max(0, Math.min(col.children.length - 1, Math.round(col.scrollTop / PK_H))); }
function pkSet(col, i) {
col.scrollTop = i * PK_H;
$$('i', col).forEach((x, k) => x.classList.toggle('on', k === i));
}
function pkGet(k) { const c = $('.pk-col[data-k="' + k + '"]', pkWheels); return c ? pkIdx(c) : 0; }
const pkYears = () => { const y = new Date().getFullYear(); return [y - 1, y, y + 1]; };
function pkDayCol(keep) {
const ys = pkYears(), y = ys[pkGet('y')], m = pkGet('m');
const n = new Date(y, m + 1, 0).getDate();
const old = $('.pk-col[data-k="d"]', pkWheels);
const tmp = document.createElement('div');
tmp.innerHTML = pkCol('d', Array.from({ length: n }, (_, i) => (i + 1) + ' 日'));
const col = tmp.firstChild;
old.replaceWith(col);
pkBind(col);
pkSet(col, Math.min(keep, n - 1));
}
function pkResult() {
if (pkMode === 'week') {
const due = dueFromGA(pkGet('w') * 7 + pkGet('dd'));
$('#pkResL').textContent = '预产期';
$('#pkResV').textContent = toISO(due);
} else {
const ys = pkYears(), due = new Date(ys[pkGet('y')], pkGet('m'), pkGet('d') + 1);
const left = Math.round((midnight(due) - midnight(new Date())) / DAY_MS), g = gaFromDue(due);
$('#pkResL').textContent = '对应孕周';
$('#pkResV').textContent = left < 0 ? '已过预产期' : left > TERM ? '还没怀上哦' : '孕 ' + Math.floor(g / 7) + ' 周' + (g % 7 ? ' +' + (g % 7) + ' 天' : '');
}
}
function pkBind(col) {
let tm = 0;
col.addEventListener('scroll', () => {
clearTimeout(tm);
tm = setTimeout(() => {
const i = pkIdx(col);
$$('i', col).forEach((x, k) => x.classList.toggle('on', k === i));
if (col.dataset.k === 'y' || col.dataset.k === 'm') pkDayCol(pkGet('d'));
pkResult();
}, 90);
}, { passive: true });
col.addEventListener('click', e => { const it = e.target.closest('i'); if (it) col.scrollTo({ top: +it.dataset.i * PK_H, behavior: 'smooth' }); });
}
function openPicker(mode) {
pkMode = mode;
const cur = parseDay(pgDue.value);
if (mode === 'week') {
$('#pkT').textContent = '你现在怀孕多久了?';
$('#pkSub').textContent = '按孕周推算预产期';
$('#pkAlt').textContent = '知道预产期?直接选日期';
pkWheels.innerHTML = pkCol('w', Array.from({ length: 43 }, (_, i) => '孕 ' + i + ' 周')) + pkCol('dd', Array.from({ length: 7 }, (_, i) => i + ' 天'));
const g = cur ? gaFromDue(cur) : 12 * 7;
$$('.pk-col', pkWheels).forEach(pkBind);
pkSet($('.pk-col[data-k="w"]', pkWheels), Math.floor(g / 7));
pkSet($('.pk-col[data-k="dd"]', pkWheels), g % 7);
} else {
$('#pkT').textContent = '预产期是哪一天?';
$('#pkSub').textContent = '以产检单 / B 超单上写的为准';
$('#pkAlt').textContent = '不知道预产期?按孕周填';
const d = cur || dueFromGA(12 * 7), ys = pkYears();
pkWheels.innerHTML = pkCol('y', ys.map(y => y + ' 年')) + pkCol('m', Array.from({ length: 12 }, (_, i) => (i + 1) + ' 月')) + pkCol('d', ['1 日']);
$$('.pk-col', pkWheels).forEach(pkBind);
pkSet($('.pk-col[data-k="y"]', pkWheels), Math.max(0, ys.indexOf(d.getFullYear())));
pkSet($('.pk-col[data-k="m"]', pkWheels), d.getMonth());
pkDayCol(d.getDate() - 1);
}
pkWheels.className = 'pk-wheels n' + $$('.pk-col', pkWheels).length;
pkResult();
pkScrim.classList.add('show');
pkSheet.classList.add('show');
haptic();
}
function closePicker() { pkScrim.classList.remove('show'); pkSheet.classList.remove('show'); }
$('#pfWeekRow').addEventListener('click', () => openPicker('week'));
$('#pfDueRow').addEventListener('click', () => openPicker('due'));
$('#pkAlt').addEventListener('click', () => openPicker(pkMode === 'week' ? 'due' : 'week'));
pkScrim.addEventListener('click', closePicker);
$('#pkOk').addEventListener('click', () => {
if (pkMode === 'week') {
pgWeek.value = pkGet('w'); pgDay.value = pkGet('dd');
pgWeek.dispatchEvent(new Event('change'));
} else {
const ys = pkYears();
pgDue.value = toISO(new Date(ys[pkGet('y')], pkGet('m'), pkGet('d') + 1));
pgDue.dispatchEvent(new Event('change'));
}
closePicker();
haptic();
});
/* 环的目标值改了要顺手清掉上一轮动画的终值,否则 animateRings 不会重跑 */
function setRing(el, p) {
if (!el) return;
@@ -1575,7 +1684,7 @@
$('#arTitleName').textContent = nm;
$('#arLine1').textContent = '完善孕期信息后开启';
$('#arDays').textContent = '--';
$('#arLine2').textContent = '先去「我的资料」填预产期';
$('#arLine2').textContent = '先去「孕期档案」填预产期';
$('#arPct').textContent = '0%';
setArBar(0);
$('#genWeekTag').textContent = '--';
@@ -1761,7 +1870,13 @@
/* 点大圆 → 转交给隐藏的 file input。openModal 里会 focus 第一个输入框,
这里 avFile 排在 pfName 前面,所以 openModal 用的选择器只取 .modal-ta/input
可能命中 file input——用 :not([type=file]) 排除掉,见 openModal */
avBig.addEventListener('click', () => avFile.click());
avBig.addEventListener('click', e => { e.stopPropagation(); avFile.click(); });
/* 孕期档案里头像是一整行,点行上任何地方都换头像 */
const pfMeRow = $('#pfMe');
if (pfMeRow) {
pfMeRow.addEventListener('click', e => { if (e.target !== avFile) avFile.click(); });
pfMeRow.addEventListener('keydown', e => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); avFile.click(); } });
}
avFile.addEventListener('change', () => {
const f = avFile.files && avFile.files[0];
@@ -1786,8 +1901,7 @@
/* 预产期是一切的源头:孕周、剩余天数、信里的日期全从它算。没有它没什么可存的。 */
if (!parseDay(pgDue.value)) {
toast('先填一下预产期,孕周会自动算出来');
setPgMode('due');
pgDue.focus();
openPicker('week');
return;
}
const name = $('#pfName').value.trim() || '妈妈';