孕周开放门槛:数胎动 16 / 数宫缩 20 / 胎儿估重 15 周前点入口弹定制提示,宫格与工具卡挂「N周+」角标 v26101013
Co-Authored-By: AI 助手
This commit is contained in:
65
js/app.js
65
js/app.js
@@ -3,7 +3,7 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
/* 页面版本号(YYMMDD+序号):显示在「关于兜爸心选」页底部;bump 时同步 head 注释与 ?v= */
|
||||
var VER = '26101012';
|
||||
var VER = '26101013';
|
||||
const $ = (s, c) => (c || document).querySelector(s);
|
||||
const $$ = (s, c) => Array.from((c || document).querySelectorAll(s));
|
||||
|
||||
@@ -337,9 +337,67 @@
|
||||
if (!oid && !uid) q.push('__no_identity=1');
|
||||
return q.length ? url + (url.indexOf('?') >= 0 ? '&' : '?') + q.join('&') : url;
|
||||
}
|
||||
/* ================= 孕周开放门槛(2026-10-11 用户)=================
|
||||
「数胎动 16 周、数宫缩 20 周、胎儿估重 15 周以后对外开放;选了没到的孕周(比如 10 周),
|
||||
这三个都不开放,点的时候告诉她几周后开放、现在还用不到,给一个定制感受。」
|
||||
· 只在**已知孕周且没到门槛**时拦:访客 / 未建档 / 产后都照常放行(拿不准就别拦人)。
|
||||
· 统一拦在 jumpApp() 里 —— 记一下宫格、首页工具卡、今日待办、盲盒任务……所有入口都走它,一处管全部。
|
||||
· 按 identifier 认,认不到再按 URL 目录认(今日待办的上游 url 可能不带 identifier)。 */
|
||||
const STAGE_GATE = [
|
||||
{ id: 'taidong', slug: '/taidong/', wk: 16, name: '数胎动',
|
||||
why: nm => nm + '现在还小,胎动要到孕 16 周以后才慢慢感觉得到。到时候每天数一数,就能知道' + nm + '今天好不好。' },
|
||||
{ id: 'gongsuopinlv', slug: '/gongsuo-pinlv/', wk: 20, name: '数宫缩',
|
||||
why: () => '宫缩计时主要用在孕中晚期,孕 20 周以后记下来才更有参考意义。现在先安心养着,不用急着用它。' },
|
||||
{ id: 'taierguzhong', slug: '/taier-guzhong/', wk: 15, name: '胎儿估重',
|
||||
why: nm => '估重要用到 B 超量出来的头围、股骨长这些数据,孕 15 周以后算出来才靠谱。等下次 B 超拿到报告,就能看看' + nm + '有多重啦。' },
|
||||
];
|
||||
function stageGateOf(url, identifier) {
|
||||
if (identifier) { const g = STAGE_GATE.find(x => x.id === identifier); if (g) return g; }
|
||||
let path = '';
|
||||
try { path = new URL(url, location.href).pathname; } catch (e) { path = String(url || ''); }
|
||||
return STAGE_GATE.find(x => path.indexOf(x.slug) === 0) || null;
|
||||
}
|
||||
/* 现在孕几天;拿不准(访客、未建档、产后)返回 null → 不拦 */
|
||||
function knownGA() {
|
||||
if (state.postpartum || state.pregEmpty || state.week == null) return null;
|
||||
return state.week * 7 + (state.day || 0);
|
||||
}
|
||||
function stageLocked(g) { const ga = knownGA(); return !!g && ga != null && ga < g.wk * 7; }
|
||||
function openStageGate(g) {
|
||||
const ga = knownGA(), left = g.wk * 7 - ga, nm = state.babyName || '宝宝';
|
||||
const app = APP_BY_ID[g.id], ico = app && (app.logo || app.icon);
|
||||
$('#sgIco').innerHTML = ico ? '<img src="' + ico + '" alt="" width="40" height="40">' : '<b>' + g.name.slice(0, 1) + '</b>';
|
||||
$('#sgT').textContent = g.name + ' · 孕 ' + g.wk + ' 周后开放';
|
||||
$('#sgNow').textContent = '你现在 ' + gaTxt(ga).replace('孕', '孕 ').replace('周', ' 周');
|
||||
$('#sgP').textContent = g.why(nm);
|
||||
$('#sgFrom').textContent = gaTxt(ga);
|
||||
$('#sgTo').textContent = '孕' + g.wk + '周';
|
||||
$('#sgBar').style.width = Math.max(6, Math.min(100, ga / (g.wk * 7) * 100)).toFixed(1) + '%';
|
||||
$('#sgLeft').textContent = (left >= 7 ? '还有 ' + Math.ceil(left / 7) + ' 周' : '还有 ' + left + ' 天') + ',大约 ' + mdTxt(gaToDate(g.wk * 7)) + ' 开放';
|
||||
openModal('modalStageGate');
|
||||
}
|
||||
/* 宫格 / 首页工具卡上的小角标「16周+」:没到门槛的灰一点,到了自动去掉 */
|
||||
function markStageLocks() {
|
||||
$$('#appsGrid .app').forEach(b => {
|
||||
const g = stageGateOf(decodeURIComponent(b.dataset.url || ''), decodeURIComponent(b.dataset.id || ''));
|
||||
const on = stageLocked(g);
|
||||
b.classList.toggle('is-locked', on);
|
||||
if (on) b.dataset.lock = g.wk + '周+'; else delete b.dataset.lock;
|
||||
});
|
||||
[['kick', 'taidong'], ['curve', 'gongsuopinlv'], ['fweight', 'taierguzhong']].forEach(([slot, id]) => {
|
||||
const el = $('.mini-card[data-mini="' + slot + '"]'), g = STAGE_GATE.find(x => x.id === id);
|
||||
if (!el) return;
|
||||
const on = stageLocked(g);
|
||||
el.classList.toggle('is-locked', on);
|
||||
if (on) el.dataset.lock = g.wk + '周+'; else delete el.dataset.lock;
|
||||
});
|
||||
}
|
||||
|
||||
/* 跳转到其它 H5 应用。identifier 可选(来自 App 表),用于 last_app 上报的服务端在架校验;
|
||||
缺省时服务端按 URL 前缀反查,效果一致。 */
|
||||
function jumpApp(url, identifier) {
|
||||
const sg = stageGateOf(url, identifier);
|
||||
if (stageLocked(sg)) { openStageGate(sg); return; } // 孕周没到:弹提示,不跳(见 STAGE_GATE)
|
||||
haptic();
|
||||
const target = withIdentity(url);
|
||||
reportLastApp(url, identifier); // 净地址:恢复时身份按当前用户重新注入
|
||||
@@ -372,6 +430,7 @@
|
||||
cnt.textContent = '共 ' + apps.length + ' 个 ›';
|
||||
cnt.dataset.toast = '共 ' + apps.length + ' 个孕期工具';
|
||||
}
|
||||
markStageLocks();
|
||||
}
|
||||
function loadPublishedApps() {
|
||||
fetch('/api/mp/apps?isPublished=1&pageSize=200')
|
||||
@@ -1362,6 +1421,7 @@
|
||||
}
|
||||
function syncPregnancy() {
|
||||
Promise.resolve().then(pubPreg);
|
||||
markStageLocks(); /* 孕周变了 → 「16周+」角标跟着变 */
|
||||
/* 孕期小知识:只认真实孕周(自己判显隐,见 renderTips) */
|
||||
renderTips();
|
||||
nurseryRender();
|
||||
@@ -4978,7 +5038,7 @@
|
||||
if (title) title.style.display = (r && r.lead) ? '' : 'none';
|
||||
if (!box) return;
|
||||
box.innerHTML = '';
|
||||
((r && r.unused) || []).slice(0, 4).forEach(u => {
|
||||
((r && r.unused) || []).filter(u => !stageLocked(stageGateOf(u.url, u.identifier))).slice(0, 4).forEach(u => {
|
||||
const ident = u.identifier || '';
|
||||
const app = ident ? APP_BY_ID[ident] : null;
|
||||
/* ⚠️ 优先用上游带回的 `url`(2026-09-23 起它只推**我们已上架**的应用并把正式 url 带回来,
|
||||
@@ -5029,6 +5089,7 @@
|
||||
const done = $('#skDone');
|
||||
let nx = null;
|
||||
for (const u of unused) {
|
||||
if (stageLocked(stageGateOf(u.url, u.identifier))) continue; // 孕周没到的不当「下一件」推
|
||||
const ident = u.identifier || '', app = ident ? APP_BY_ID[ident] : null;
|
||||
const href = u.url || (app && app.url) || '', name = u.appName || (app && app.name) || '';
|
||||
if (href && name) { nx = { href, name, id: (app && app.identifier) || ident }; break; }
|
||||
|
||||
Reference in New Issue
Block a user