198 lines
14 KiB
HTML
198 lines
14 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
|
||
<meta name="format-detection" content="telephone=no">
|
||
<title>预产期计算器</title>
|
||
<!-- 孕期计算器 · 预产期(2026-11-04 用户:「孕期增重那个是记录工具、不是算出来的,换掉,给我一个能算的」→ 新做本页替换百宝箱 / topic/jisuan 里的「孕期增重」)。
|
||
算法(常规产科算法):
|
||
末次月经:预产期 = 末次月经第一天 + 280 天 +(周期 − 28)天;
|
||
试管移植:第 3 天胚胎 = 移植日 + 263 天,第 5 天囊胚 = 移植日 + 261 天;
|
||
孕周 = 今天 −(预产期 − 280 天),各项产检窗口按孕周换算成日期。
|
||
自成一页:不引 app.js;返回走 back,直接打开回 ../../(带回 search + hash)。上次填的值记在 localStorage「mmbox.edd.calc」,再进来直接出结果。 -->
|
||
<style>
|
||
:root{--c:#E25C7A;--cbg:#FFEEF2;--h:#1F2329;--t:#4E5969;--m:#86909C;--line:#F1E9EB}
|
||
*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}
|
||
html,body{height:100%;overflow:hidden;background:#fff;color:var(--t);font:15px/1.7 -apple-system,BlinkMacSystemFont,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif}
|
||
#scroll{position:fixed;inset:0;overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;overscroll-behavior:none;padding-bottom:calc(28px + env(safe-area-inset-bottom))}
|
||
button,input{font:inherit;border:0;background:none;color:inherit}
|
||
button{cursor:pointer}
|
||
.num{font-variant-numeric:tabular-nums}
|
||
.ic{width:20px;height:20px;flex:none;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
|
||
.bar{position:sticky;top:0;z-index:20;display:flex;align-items:center;gap:4px;height:48px;padding:0 8px;padding-top:env(safe-area-inset-top);border-bottom:1px solid transparent;transition:background .2s,border-color .2s}
|
||
.bar.on{background:#fff;border-bottom-color:var(--line)}
|
||
.bar .back{width:36px;height:36px;border-radius:50%;display:grid;place-items:center;color:var(--h)}
|
||
.bar .t{font-size:15px;font-weight:700;color:var(--h)}
|
||
.hd{margin-top:-48px;padding:60px 20px 6px;background:linear-gradient(180deg,var(--cbg),#fff)}
|
||
.hd p{font-size:12.5px;font-weight:700;color:var(--c);letter-spacing:1px}
|
||
.hd h1{margin-top:4px;font-size:25px;font-weight:900;line-height:1.3;color:var(--h)}
|
||
.hd span{display:block;margin-top:4px;font-size:14px;color:var(--m)}
|
||
.calc{margin:12px 16px 0;padding:16px;border-radius:20px;background:#fff;box-shadow:0 10px 30px -18px rgba(226,92,122,.55);border:1px solid #F7E3E8}
|
||
.res{padding:16px;border-radius:16px;background:linear-gradient(135deg,#FF8FA8,#E25C7A);color:#fff}
|
||
.res .empty{padding:14px 0;text-align:center;font-size:14px;opacity:.9}
|
||
.res small{font-size:12.5px;opacity:.9}
|
||
.res .due{display:block;margin-top:2px;font-size:28px;font-weight:900;line-height:1.25}
|
||
.res .wk{display:flex;gap:10px;margin-top:12px}
|
||
.res .wk div{flex:1;padding:8px 10px;border-radius:12px;background:rgba(255,255,255,.18)}
|
||
.res .wk b{display:block;font-size:17px;font-weight:900}
|
||
.res .pg{position:relative;height:6px;margin-top:12px;border-radius:99px;background:rgba(255,255,255,.3);overflow:hidden}
|
||
.res .pg i{position:absolute;left:0;top:0;bottom:0;border-radius:99px;background:#fff}
|
||
.tabs{display:flex;gap:6px;margin-top:16px;padding:4px;border-radius:12px;background:#F7F1F3}
|
||
.tabs button{flex:1;height:34px;border-radius:9px;font-size:14px;font-weight:700;color:var(--m)}
|
||
.tabs button.on{background:#fff;color:var(--c);box-shadow:0 2px 6px rgba(226,92,122,.15)}
|
||
.fld{margin-top:14px}
|
||
.lb{display:block;font-size:13.5px;font-weight:700;color:var(--h)}
|
||
.lb small{margin-left:6px;font-weight:400;color:var(--m)}
|
||
.in{display:block;width:100%;height:46px;margin-top:6px;padding:0 14px;border-radius:12px;background:#F8F5F6;font-size:16px;color:var(--h)}
|
||
.stp{display:flex;align-items:center;gap:10px;margin-top:6px}
|
||
.stp button{width:42px;height:42px;border-radius:12px;background:#F8F5F6;font-size:20px;font-weight:700;color:var(--c)}
|
||
.stp b{flex:1;text-align:center;font-size:18px;color:var(--h)}
|
||
.seg{display:flex;gap:8px;margin-top:6px}
|
||
.seg button{flex:1;height:42px;border-radius:12px;background:#F8F5F6;font-size:14px;font-weight:700;color:var(--t)}
|
||
.seg button.on{background:var(--cbg);color:var(--c);box-shadow:inset 0 0 0 1.5px var(--c)}
|
||
.hide{display:none!important}
|
||
.sec{margin:26px 20px 0}
|
||
.sec h2{font-size:18px;font-weight:900;color:var(--h)}
|
||
.sec .lead{margin-top:2px;font-size:13px;color:var(--m)}
|
||
.tl{list-style:none;margin-top:12px}
|
||
.tl li{position:relative;display:flex;gap:12px;padding:0 0 16px 0}
|
||
.tl li::before{content:"";position:absolute;left:7px;top:18px;bottom:0;width:2px;background:#F3E3E7}
|
||
.tl li:last-child::before{display:none}
|
||
.tl .d{flex:none;width:16px;height:16px;margin-top:3px;border-radius:50%;border:3px solid #F6CBD6;background:#fff}
|
||
.tl li.done .d{border-color:var(--c);background:var(--c)}
|
||
.tl li.now .d{border-color:var(--c);box-shadow:0 0 0 4px rgba(226,92,122,.18)}
|
||
.tl .m{flex:1;min-width:0}
|
||
.tl .m b{font-size:15px;color:var(--h)}
|
||
.tl .m b em{margin-left:6px;padding:0 6px;border-radius:99px;background:var(--cbg);color:var(--c);font-size:11px;font-style:normal;font-weight:800}
|
||
.tl .m span{display:block;font-size:13px;color:var(--m)}
|
||
.tl .m span i{font-style:normal;font-weight:700;color:var(--t)}
|
||
.tip{margin:18px 20px 0;padding:12px 14px;border-radius:14px;background:#FFF8F4;font-size:13px;line-height:1.7;color:var(--t)}
|
||
.tip b{color:var(--h)}
|
||
.foot{margin:14px 20px 0;font-size:12px;color:var(--m);text-align:center;line-height:1.6}
|
||
</style>
|
||
<link rel="stylesheet" href="../_shared/wizard.css?v=26110446">
|
||
</head>
|
||
<body>
|
||
<svg style="position:absolute;width:0;height:0" aria-hidden="true"><symbol id="i-back" viewBox="0 0 24 24"><path d="M15 5l-7 7 7 7"/></symbol></svg>
|
||
<div id="scroll">
|
||
<header class="bar" id="bar">
|
||
<button class="back" id="back" aria-label="返回"><svg class="ic"><use href="#i-back"/></svg></button>
|
||
<span class="t">孕期计算器</span>
|
||
</header>
|
||
<section class="hd"><p>孕期计算器</p><h1>预产期计算器</h1><span>填末次月经或移植日,算出预产期、现在几周、每项产检哪天去</span></section>
|
||
|
||
<section class="calc">
|
||
<div class="res" id="res"><div class="empty">填好下面的日期,马上出结果</div></div>
|
||
<div class="tabs" id="tabs" data-q="你想按哪个算?"><button type="button" data-m="lmp" class="on">按末次月经</button><button type="button" data-m="ivf">按试管移植</button></div>
|
||
<div id="fLmp">
|
||
<div class="fld"><label class="lb" for="cLmp">末次月经第一天</label><input class="in num" type="date" id="cLmp"></div>
|
||
<div class="fld"><span class="lb">月经周期<small>两次月经第一天间隔几天</small></span>
|
||
<div class="stp"><button type="button" id="cyM" aria-label="减一天">−</button><b class="num" id="cyV">28 天</b><button type="button" id="cyP" aria-label="加一天">+</button></div></div>
|
||
</div>
|
||
<div id="fIvf" class="hide">
|
||
<div class="fld"><label class="lb" for="cTr">胚胎移植日</label><input class="in num" type="date" id="cTr"></div>
|
||
<div class="fld"><span class="lb">移植的胚胎</span>
|
||
<div class="seg" id="cEmb"><button type="button" data-v="3">第 3 天胚胎</button><button type="button" data-v="5" class="on">第 5 天囊胚</button></div></div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="sec hide" id="plan">
|
||
<h2>我的产检时间表</h2>
|
||
<p class="lead">按预产期倒推的建议时间,具体听你的产检医生安排</p>
|
||
<ol class="tl" id="tl"></ol>
|
||
</section>
|
||
|
||
<div class="tip"><b>以早孕 B 超为准:</b>月经不规律、记不清末次月经,或 B 超算出的孕周和月经差得多,医生会按孕早期 B 超(头臀长)改预产期。预产期是个参考,37~41+6 周生都算足月。</div>
|
||
<p class="foot">计算结果仅供参考,不能代替医生诊断。</p>
|
||
</div>
|
||
|
||
<script>
|
||
(function () {
|
||
'use strict';
|
||
var $ = function (s) { return document.querySelector(s); };
|
||
var sc = $('#scroll'), KEY = 'mmbox.edd.calc', DAY = 864e5;
|
||
$('#back').addEventListener('click', function () {
|
||
if (document.referrer && document.referrer.indexOf(location.host) >= 0 && history.length > 1) history.back();
|
||
else location.href = '../../' + location.search + location.hash;
|
||
});
|
||
sc.addEventListener('scroll', function () { $('#bar').classList.toggle('on', sc.scrollTop > 8); }, { passive: true });
|
||
|
||
/* 日期一律按北京时间的「日」算,避免时区差一天 */
|
||
function today() { var n = new Date(Date.now() + 288e5); return Date.UTC(n.getUTCFullYear(), n.getUTCMonth(), n.getUTCDate()); }
|
||
function parse(v) { var m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(v || ''); return m ? Date.UTC(+m[1], m[2] - 1, +m[3]) : NaN; }
|
||
function fmt(t) { var d = new Date(t); return d.getUTCFullYear() + '-' + ('0' + (d.getUTCMonth() + 1)).slice(-2) + '-' + ('0' + d.getUTCDate()).slice(-2); }
|
||
function cn(t, y) { var d = new Date(t); return (y ? d.getUTCFullYear() + ' 年 ' : '') + (d.getUTCMonth() + 1) + ' 月 ' + d.getUTCDate() + ' 日'; }
|
||
var WD = '日一二三四五六';
|
||
|
||
var st = { m: 'lmp', lmp: '', cy: 28, tr: '', emb: 5 };
|
||
try { var sv = JSON.parse(localStorage.getItem(KEY) || 'null'); if (sv) Object.keys(st).forEach(function (k) { if (sv[k] != null) st[k] = sv[k]; }); } catch (e) {}
|
||
var T = today();
|
||
$('#cLmp').max = fmt(T); $('#cLmp').min = fmt(T - 300 * DAY);
|
||
$('#cTr').max = fmt(T); $('#cTr').min = fmt(T - 280 * DAY);
|
||
|
||
function ui() {
|
||
[].forEach.call($('#tabs').children, function (b) { b.classList.toggle('on', b.dataset.m === st.m); });
|
||
$('#fLmp').classList.toggle('hide', st.m !== 'lmp'); $('#fIvf').classList.toggle('hide', st.m !== 'ivf');
|
||
$('#cLmp').value = st.lmp; $('#cTr').value = st.tr; $('#cyV').textContent = st.cy + ' 天';
|
||
[].forEach.call($('#cEmb').children, function (b) { b.classList.toggle('on', +b.dataset.v === +st.emb); });
|
||
}
|
||
function due() {
|
||
if (st.m === 'lmp') { var l = parse(st.lmp); return isNaN(l) ? NaN : l + (280 + st.cy - 28) * DAY; }
|
||
var t = parse(st.tr); return isNaN(t) ? NaN : t + (+st.emb === 3 ? 263 : 261) * DAY;
|
||
}
|
||
/* 产检窗口(孕周,含首尾):常规产检时间,具体以医生安排为准 */
|
||
var PLAN = [
|
||
['建档 + 第一次产检', 6, 12, '查血、B 超确认胎心,拿到孕妇手册'],
|
||
['NT 检查', 11, 13.86, '11~13+6 周,错过就不能补'],
|
||
['唐筛 / 无创', 15, 20.86, '早唐可和 NT 一起做,中唐 15~20+6 周'],
|
||
['大排畸', 20, 24, '系统超声,看宝宝结构'],
|
||
['糖耐', 24, 28, '空腹去,喝糖水抽 3 次血'],
|
||
['胎心监护', 34, 40, '一般 34~36 周起,每周一次'],
|
||
['足月', 37, 37, '这之后生都算足月,待产包备好'],
|
||
['预产期', 40, 40, '']
|
||
];
|
||
function paint() {
|
||
var d = due(), R = $('#res');
|
||
try { localStorage.setItem(KEY, JSON.stringify(st)); } catch (e) {}
|
||
if (isNaN(d)) { R.innerHTML = '<div class="empty">填好下面的日期,马上出结果</div>'; $('#plan').classList.add('hide'); return; }
|
||
var s0 = d - 280 * DAY, g = Math.floor((T - s0) / DAY), w = Math.floor(g / 7), dd = g % 7, left = Math.round((d - T) / DAY);
|
||
var wk = g < 0 ? '还没开始' : w + ' 周' + (dd ? ' + ' + dd + ' 天' : ''), stage = w < 14 ? '孕早期' : w < 28 ? '孕中期' : '孕晚期';
|
||
R.innerHTML = '<small>你的预产期</small><b class="due num">' + cn(d, 1) + ' 周' + WD[new Date(d).getUTCDay()] + '</b>' +
|
||
'<div class="wk"><div><small>今天</small><b class="num">' + (g >= 0 && g <= 300 ? '孕 ' + wk : '—') + '</b></div><div><small>' + (left >= 0 ? '离见面还有' : '已过预产期') + '</small><b class="num">' + Math.abs(left) + ' 天</b></div></div>' +
|
||
'<div class="pg"><i style="width:' + Math.max(0, Math.min(100, g / 280 * 100)).toFixed(1) + '%"></i></div>' +
|
||
'<small style="display:block;margin-top:6px">' + (g >= 0 && left >= 0 ? stage + ' · 已走过 ' + Math.round(g / 280 * 100) + '%' : '预产期仅供参考,以医生判断为准') + '</small>';
|
||
$('#tl').innerHTML = PLAN.map(function (p) {
|
||
var a = s0 + Math.round(p[1] * 7) * DAY, b = s0 + Math.round(p[2] * 7) * DAY, done = T > b, now = T >= a && T <= b;
|
||
return '<li class="' + (done ? 'done' : now ? 'now' : '') + '"><i class="d"></i><div class="m"><b>' + p[0] + (now ? '<em>就是现在</em>' : '') + '</b>' +
|
||
'<span><i class="num">' + (a === b ? cn(a) : cn(a) + ' ~ ' + cn(b)) + '</i>' + (p[3] ? ' · ' + p[3] : '') + '</span></div></li>';
|
||
}).join('');
|
||
$('#plan').classList.remove('hide');
|
||
}
|
||
$('#tabs').addEventListener('click', function (e) { var b = e.target.closest('button'); if (!b) return; st.m = b.dataset.m; ui(); paint(); });
|
||
$('#cLmp').addEventListener('change', function () { st.lmp = this.value; paint(); });
|
||
$('#cTr').addEventListener('change', function () { st.tr = this.value; paint(); });
|
||
$('#cyM').addEventListener('click', function () { st.cy = Math.max(21, st.cy - 1); ui(); paint(); });
|
||
$('#cyP').addEventListener('click', function () { st.cy = Math.min(45, st.cy + 1); ui(); paint(); });
|
||
$('#cEmb').addEventListener('click', function (e) { var b = e.target.closest('button'); if (!b) return; st.emb = +b.dataset.v; ui(); paint(); });
|
||
ui(); paint();
|
||
|
||
/* 禁止下拉回弹:固定外壳 + 容器滚动 + 到顶/到底时拦 touchmove */
|
||
var y0 = 0;
|
||
sc.addEventListener('touchstart', function (e) { y0 = e.touches[0].clientY; }, { passive: true });
|
||
sc.addEventListener('touchmove', function (e) {
|
||
var dy = e.touches[0].clientY - y0;
|
||
if ((sc.scrollTop <= 0 && dy > 0) || (sc.scrollTop + sc.clientHeight >= sc.scrollHeight - 1 && dy < 0)) e.preventDefault();
|
||
}, { passive: false });
|
||
document.addEventListener('touchmove', function (e) { if (!sc.contains(e.target)) e.preventDefault(); }, { passive: false });
|
||
})();
|
||
</script>
|
||
<script src="../_shared/brand.js?v=26110203"></script>
|
||
<script src="../../js/share-card.js?v=26110446"></script>
|
||
<script>window.mbShare('../../assets/share/t/yuchanqi-js.jpg', '预产期计算器:宝宝哪天到?还有几天见面'); /* 11-04 微信转发图 */</script>
|
||
<!-- 11-04 分步模式:一步一题、最后出结果(同生娃计算器),见 ../_shared/wizard.js -->
|
||
<script src="../_shared/wizard.js?v=26110446"></script>
|
||
<script>CKW.init({ root: '.calc', res: '#res', after: '#scroll > section.calc ~ *' });</script>
|
||
</body>
|
||
</html>
|