feat(此刻): A+B 改版——和你一样孕 N 周的妈妈们(在做/和你比/今天别忘了/在聊/同周动态),去掉应用 logo 改用妈妈头像 (v26100108)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
17
index.html
17
index.html
@@ -7,7 +7,7 @@
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<title>兜爸心选 · 孕育陪伴</title>
|
||||
<!-- V:26100107 缓存版本标记:改 css/js 时同步 bump 该值(与 js/app.js 的 VER 同源),静态资源按 mtime 走 ETag 自动刷新 -->
|
||||
<!-- V:26100108 缓存版本标记:改 css/js 时同步 bump 该值(与 js/app.js 的 VER 同源),静态资源按 mtime 走 ETag 自动刷新 -->
|
||||
<link rel="stylesheet" href="mama-box.css">
|
||||
<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
|
||||
<!-- 共享助手:授权/跳商城/位置上报(分享卡片同步,见 docs/h5-auth-standard.md 第四节) -->
|
||||
@@ -295,7 +295,20 @@
|
||||
<span class="pl-orb o1" aria-hidden="true"></span><span class="pl-orb o2" aria-hidden="true"></span>
|
||||
<div class="pl-head">
|
||||
<span class="pl-live"><i></i>此刻</span>
|
||||
<h2 class="pl-title">孕妈们在做什么</h2>
|
||||
<h2 class="pl-title" id="plTitle">孕妈们在做什么</h2>
|
||||
</div>
|
||||
<!-- 同孕周妈妈(2026-10-01「此刻」A+B 改版):接口带 ?week= 时返回 peer 才出现,此时下面的全站统计让位。
|
||||
用户原话「要 A 的那些,同时加一些 B 这一块的内容融入进去……不要去太重叠」——
|
||||
A = 同孕周妈妈在做什么 / 在聊什么 + 和你自己比;B = 今日待办(产检倒数、本周盲盒),点击直达。
|
||||
视觉上用人物头像和聊天气泡,不用应用 logo,避免和上面的孕育工具区撞脸。 -->
|
||||
<div class="pl-peer hide" id="plPeer">
|
||||
<div class="pp-crowd">
|
||||
<span class="pp-avs" id="ppAvs" aria-hidden="true"></span>
|
||||
<span class="pp-ct"><span><b id="ppCount">0</b> 位妈妈和你同一周</span><small id="ppDue"></small></span>
|
||||
</div>
|
||||
<div class="pp-doing" id="ppDoing"></div>
|
||||
<div class="pl-todo hide" id="plTodo"><span class="tdo-h">今天别忘了</span><span class="tdo-list" id="plTodoList"></span></div>
|
||||
<div class="pp-talk hide" id="ppTalk"><span class="pp-sub">她们在聊</span><div id="ppTalkList"></div></div>
|
||||
</div>
|
||||
<div class="pl-total hide" id="plTotal">
|
||||
<span class="pl-avs" aria-hidden="true"><i></i><i></i><i></i><i></i></span>
|
||||
|
||||
156
js/app.js
156
js/app.js
@@ -3,7 +3,7 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
/* 页面版本号(YYMMDD+序号):显示在「关于兜爸心选」页底部;bump 时同步 head 注释与 ?v= */
|
||||
var VER = '26100107';
|
||||
var VER = '26100108';
|
||||
const $ = (s, c) => (c || document).querySelector(s);
|
||||
const $$ = (s, c) => Array.from((c || document).querySelectorAll(s));
|
||||
|
||||
@@ -2933,6 +2933,7 @@
|
||||
}
|
||||
// 统一回刷依赖这些 state 的展示
|
||||
syncPregnancy();
|
||||
if (plHook) setTimeout(plHook, 0); // 「此刻」按孕周重拉(setTimeout:等下面 syncStaticDates 把 #calNext 算好)
|
||||
/* 新用户空态:syncPregnancy 已写完引导占位(含称呼/静态位归零)。
|
||||
⚠️ 下面 syncBabyWords/syncStaticDates 全按 state.week 重算,
|
||||
而 pregEmpty 时 state.week 还是内置默认 27 —— 不拦住的话,
|
||||
@@ -3101,7 +3102,10 @@
|
||||
· 数据是模拟还是真实由 box_app 后台 pulseMode 决定,前端不区分、不兜底造数:show=false / 接口失败 → 整卡隐藏。
|
||||
⚠️ 模拟阶段是 AGENTS.md §4.12 登记的例外,只限这张卡;别把这里的「失败兜底」改成前端自造数字。
|
||||
· 动效:进入视口时大数字从 0 数上去;之后每 60 秒刷新一次,数字平滑涨到新值;动态每 3 秒往上翻一条。
|
||||
· 今日三项可点:kick / weight 复用首页工具卡的跳转(MINI_APP_MAP),game 去消消乐。 */
|
||||
· 今日三项可点:kick / weight 复用首页工具卡的跳转(MINI_APP_MAP),game 去消消乐。
|
||||
· 2026-10-01 A+B 改版:已建档时带 ?week= 拉,接口多给 peer → 卡片换成「和你一样孕 N 周的妈妈们」:
|
||||
同周人数 + 她们今天在做(百分比条,右侧对比「你今天还没数 ›」可直达)+ 今天别忘了(产检倒数 / 本周盲盒)
|
||||
+ 她们在聊(气泡)+ 同周动态。此时全站统计两块让位。无 peer(访客 / real 模式)→ 原版式。 */
|
||||
const PULSE_ICO = {
|
||||
kick: '<svg viewBox="0 0 24 24"><ellipse cx="10" cy="15" rx="5" ry="6.5" fill="currentColor"/><circle cx="16.5" cy="6" r="2" fill="currentColor"/><circle cx="12.5" cy="4.6" r="1.6" fill="currentColor"/><circle cx="19.4" cy="9.6" r="1.6" fill="currentColor"/></svg>',
|
||||
weight: '<svg viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="16" rx="5" fill="none" stroke="currentColor" stroke-width="2.2"/><path d="M8 10a4 4 0 018 0z" fill="currentColor"/><path d="M12 10l1.6-2.4" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg>',
|
||||
@@ -3109,16 +3113,33 @@
|
||||
game: '<svg viewBox="0 0 24 24"><rect x="3" y="3" width="8" height="8" rx="2.5" fill="currentColor"/><rect x="13" y="3" width="8" height="8" rx="2.5" fill="currentColor" opacity=".6"/><rect x="3" y="13" width="8" height="8" rx="2.5" fill="currentColor" opacity=".6"/><rect x="13" y="13" width="8" height="8" rx="2.5" fill="currentColor"/></svg>',
|
||||
box: '<svg viewBox="0 0 24 24"><rect x="4" y="11" width="16" height="10" rx="2" fill="currentColor"/><rect x="2.5" y="7.5" width="19" height="4.5" rx="1.6" fill="currentColor"/><path d="M12 7.5V21" stroke="#fff" stroke-width="2"/><path d="M12 7.5C10 3.5 6 4 7.5 6.6 8.3 7.8 10.4 7.6 12 7.5zM12 7.5c2-4 6-3.5 4.5-.9-.8 1.2-2.9 1-4.5.9z" fill="currentColor"/></svg>'
|
||||
};
|
||||
/* 2026-10-01 用户要求:图标一律换成对应应用的 logo(数胎动就用数胎动的 logo)。
|
||||
logo 取 App 表(APP_BY_ID[identifier].logo,后台换 logo 即生效);应用列表还没回来时先用上面的单色图标顶一下。
|
||||
消消乐、盲盒不在 App 表里 → 用本站 assets/img 里的同风格 logo。 */
|
||||
const PULSE_APP = { kick: 'taidong', weight: 'yunqitizhong', cal: 'chanjianrili' };
|
||||
const PULSE_LOGO = { game: 'assets/img/429ffcba0d6e.svg', box: 'assets/img/b0087c3c012a.svg' };
|
||||
/* 2026-10-01 曾按用户要求换成应用 logo;同日「此刻」A+B 改版用户又要求「去掉应用 logo 一类的工具化视觉、
|
||||
改用表现人的元素」(和上面孕育工具区撞脸)→ 动态行改用妈妈头像(momAva),全站统计格回到单色小图标。 */
|
||||
function pulseIco(k, cls) {
|
||||
const a = APP_BY_ID[PULSE_APP[k]], src = (a && a.logo) || PULSE_LOGO[k];
|
||||
return '<span class="' + cls + (src ? ' is-logo' : '') + '">' +
|
||||
(src ? '<img class="logo" src="' + String(src).replace(/"/g, '"') + '" alt="">' : (PULSE_ICO[k] || PULSE_ICO.box)) + '</span>';
|
||||
return '<span class="' + cls + '">' + (PULSE_ICO[k] || PULSE_ICO.box) + '</span>';
|
||||
}
|
||||
/* 妈妈头像插画(纯 SVG,5 种发色 × 3 种发型 × 5 种底色,按 seed 取)。只是装饰,不代表任何真实用户。 */
|
||||
const MOM_HAIR = ['#4A3328', '#2F2420', '#6B4532', '#3B2A2A', '#7A5038'];
|
||||
const MOM_BG = ['#FFD9CB', '#E6DCFF', '#FFE9B8', '#CDEBDD', '#FFD3E1'];
|
||||
const MOM_TOP = ['#FF9E85', '#9F8CF0', '#F2B84B', '#6CBF9A', '#F07AA0'];
|
||||
function momAva(seed) {
|
||||
const i = Math.abs(seed | 0), h = MOM_HAIR[i % 5], st = Math.floor(i / 5) % 3;
|
||||
const bg = MOM_BG[Math.floor(i / 3) % 5], top = MOM_TOP[(i + 2) % 5];
|
||||
const back = st === 0 ? '<circle cx="20" cy="9" r="4.6" fill="' + h + '"/><path d="M11 21c0-7 4-11.5 9-11.5s9 4.5 9 11.5z" fill="' + h + '"/>'
|
||||
: st === 1 ? '<path d="M9.5 23c0-9 4.6-14 10.5-14s10.5 5 10.5 14v11h-21z" fill="' + h + '"/>'
|
||||
: '<path d="M10.3 25c-1-9 3.4-15.4 9.7-15.4S30.7 16 29.7 25l-2 2.4H12.3z" fill="' + h + '"/>';
|
||||
return '<svg viewBox="0 0 40 40" aria-hidden="true"><rect width="40" height="40" fill="' + bg + '"/>' + back +
|
||||
'<path d="M7 41c1.2-6.4 6.4-9.6 13-9.6S31.8 34.6 33 41z" fill="' + top + '"/>' +
|
||||
'<rect x="17.6" y="28" width="4.8" height="4.6" rx="2" fill="#F6CDB8"/>' +
|
||||
'<ellipse cx="20" cy="22.4" rx="8" ry="8.8" fill="#FFE3D3"/>' +
|
||||
'<path d="M12 21.4c0-5.6 3.6-9.4 8-9.4s8 3.8 8 9.4c-2.6-2.6-5.8-3.9-8.6-4.1-2.4 1.6-4.6 3-7.4 4.1z" fill="' + h + '"/>' +
|
||||
'<path d="M15.8 23.4q1.3 1.1 2.6 0M21.6 23.4q1.3 1.1 2.6 0" stroke="#5A3A2E" stroke-width="1.2" fill="none" stroke-linecap="round"/>' +
|
||||
'<circle cx="15" cy="26" r="1.5" fill="#FF8F7A" opacity=".45"/><circle cx="25" cy="26" r="1.5" fill="#FF8F7A" opacity=".45"/>' +
|
||||
'<path d="M18.6 27.2q1.4 1 2.8 0" stroke="#D9735E" stroke-width="1" fill="none" stroke-linecap="round"/></svg>';
|
||||
}
|
||||
const strSeed = t => { let x = 7; for (let i = 0; i < t.length; i++) x = (x * 31 + t.charCodeAt(i)) | 0; return Math.abs(x); };
|
||||
/* 「此刻」重绘钩子:足迹 / 档案 / 盲盒状态回来时调用(它们决定「和你比」「今日待办」和孕周) */
|
||||
let plHook = null;
|
||||
const fmtN = n => String(Math.round(n)).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||
/* 数字补间:el.dataset.v 记当前值,从它平滑走到 to;首次(无 dataset.v)从 0 起 */
|
||||
function tweenNum(el, to, dur) {
|
||||
@@ -3136,18 +3157,46 @@
|
||||
(function pulseCard() {
|
||||
const sec = $('#pulse');
|
||||
if (!sec) return;
|
||||
let seen = false, last = null, feed = [], fi = 0, ticking = null;
|
||||
let seen = false, last = null, feed = [], fi = 0, ticking = null, peerMode = false, loadedWk = null;
|
||||
const esc = s => String(s == null ? '' : s).replace(/[&<>"]/g, c => ({ '&': '&', '<': '<', '>': '>', '"': '"' })[c]);
|
||||
const tapMini = k => { const b = $('.mini-card[data-mini="' + k + '"]'); if (b) b.click(); };
|
||||
const TODAY_GO = {
|
||||
kick: () => { const b = $('.mini-card[data-mini="kick"]'); if (b) b.click(); },
|
||||
weight: () => { const b = $('.mini-card[data-mini="weight"]'); if (b) b.click(); },
|
||||
kick: () => tapMini('kick'),
|
||||
weight: () => tapMini('weight'),
|
||||
cal: () => tapMini('cal'),
|
||||
box: () => openBoxEntry(),
|
||||
game: () => { if (GAME_URL) jumpApp(GAME_URL, GAME_ID); }
|
||||
};
|
||||
/* 用户自己今天做没做(足迹 used[].appId 是上游 URL slug)。足迹没回来 / 读不到 → null,不显示「你」那半句 */
|
||||
const SELF_APP = { kick: 'taidong', weight: 'yunqi-tizhong' };
|
||||
const SELF_TXT = { kick: ['你今天还没数', '你也数过了'], weight: ['你今天还没记', '你也记过了'] };
|
||||
function selfDone(k) {
|
||||
if (_fpMode !== 'rows' && _fpMode !== 'guide') return null;
|
||||
return ((_fpData && _fpData.used) || []).some(u => u.appId === SELF_APP[k]);
|
||||
}
|
||||
/* 今日待办(B):只放上面「她们在做」没覆盖的 —— 产检倒数(≤14 天)、本周盲盒没开 / 有可解锁的 */
|
||||
function todos() {
|
||||
const out = [];
|
||||
if (state.pregEmpty === false && !state.postpartum) {
|
||||
const m = String(($('#calNext') || {}).textContent || '').match(/(\d{1,2})月(\d{1,2})日/);
|
||||
if (m) {
|
||||
const t = midnight(new Date()), d = new Date(t.getFullYear(), +m[1] - 1, +m[2]);
|
||||
if (d < t - 86400000 * 60) d.setFullYear(d.getFullYear() + 1);
|
||||
const n = Math.round((d - t) / 86400000);
|
||||
if (n >= 0 && n <= 14) out.push({ k: 'cal', t: n === 0 ? '今天产检' : n === 1 ? '明天产检' : '距下次产检 <b>' + n + '</b> 天' });
|
||||
}
|
||||
}
|
||||
if (BB && BB.enabled && !BB.notYet && !BB.needProfile && !BB.ended) {
|
||||
if (!BB.currentOpened && (BB.openable || []).indexOf(BB.week) >= 0) out.push({ k: 'box', t: '本周盲盒还没开', hot: 1 });
|
||||
else if ((BB.locked || []).length && BB.credits) out.push({ k: 'box', t: '可解锁 <b>' + BB.credits + '</b> 个盲盒', hot: 1 });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
function rowHTML(f) {
|
||||
/* 「孕 29 周的妈妈 数完胎动,宝宝动了 13 次」→ 上行「孕 29 周的妈妈 · 刚刚」,下行动作;数字标色 */
|
||||
/* 「孕 29 周的妈妈 数完胎动,宝宝动了 13 次」→ 上行「孕 29 周的妈妈 · 刚刚」(同周版式写「一位同周妈妈」),下行动作;数字标色 */
|
||||
const t = String(f.text || ''), i = t.indexOf('的妈妈 ');
|
||||
const who = i > 0 ? t.slice(0, i + 3) : '一位妈妈', what = i > 0 ? t.slice(i + 4) : t;
|
||||
const esc = s => s.replace(/[&<>"]/g, c => ({ '&': '&', '<': '<', '>': '>', '"': '"' })[c]);
|
||||
return '<div class="pl-row a-' + (PULSE_ICO[f.act] ? f.act : 'box') + '">' + pulseIco(PULSE_ICO[f.act] ? f.act : 'box', 'pr-ico') +
|
||||
const who = peerMode ? '一位同周妈妈' : (i > 0 ? t.slice(0, i + 3) : '一位妈妈'), what = i > 0 ? t.slice(i + 4) : t;
|
||||
return '<div class="pl-row"><span class="pr-ava">' + momAva(strSeed(t + (f.ago || ''))) + '</span>' +
|
||||
'<span class="pr-t"><span class="pr-who">' + esc(who) + ' · ' + esc(f.ago || '刚刚') + '</span><span class="pr-do">' +
|
||||
esc(what).replace(/(\d+)/g, '<em>$1</em>') + '</span></span></div>';
|
||||
}
|
||||
@@ -3160,51 +3209,91 @@
|
||||
tr.style.transform = 'translateY(-46px)';
|
||||
setTimeout(() => {
|
||||
tr.classList.remove('is-move');
|
||||
if (tr.firstElementChild) tr.removeChild(tr.firstElementChild);
|
||||
/* 翻动途中若 paint() 重置过轨道(只剩 1 行),别把仅剩的那行也删了 */
|
||||
if (tr.childElementCount > 1) tr.removeChild(tr.firstElementChild);
|
||||
tr.style.transform = '';
|
||||
}, 600);
|
||||
}
|
||||
function paintPeer(p) {
|
||||
$('#plTitle').textContent = '和你一样孕 ' + p.week + ' 周的妈妈们';
|
||||
const avs = $('#ppAvs');
|
||||
if (!avs.firstChild) avs.innerHTML = [3, 11, 7, 14, 1].map(x => '<i>' + momAva(x + p.week) + '</i>').join('');
|
||||
if (seen) tweenNum($('#ppCount'), p.count, 1600);
|
||||
$('#ppDue').textContent = state.due ? '宝宝们都会在 ' + (state.due.getMonth() + 1) + ' 月前后出生' : '';
|
||||
$('#ppDoing').innerHTML = (p.doing || []).map(d => {
|
||||
const me = SELF_TXT[d.key] ? selfDone(d.key) : null;
|
||||
const meH = me == null ? '' : me
|
||||
? '<span class="pp-me ok">' + SELF_TXT[d.key][1] + ' ✓</span>'
|
||||
: '<button class="pp-me todo" type="button" data-go="' + d.key + '">' + SELF_TXT[d.key][0] + ' ›</button>';
|
||||
return '<div class="pp-do k-' + esc(d.key) + '"><div class="pp-dl"><span class="pp-dt">她们 <b>' + (+d.pct || 0) + '%</b> ' +
|
||||
esc(d.label) + '</span>' + meH + '</div><div class="pp-bar"><i style="width:' + Math.min(100, +d.pct || 0) + '%"></i></div></div>';
|
||||
}).join('');
|
||||
const td = todos();
|
||||
$('#plTodo').classList.toggle('hide', !td.length);
|
||||
$('#plTodoList').innerHTML = td.map(x => '<button class="tdo-chip' + (x.hot ? ' hot' : '') + '" type="button" data-go="' + x.k + '">' +
|
||||
pulseIco(x.k, 'tdo-ico') + '<span>' + x.t + '</span><i>›</i></button>').join('');
|
||||
const tk = p.talk || [];
|
||||
$('#ppTalk').classList.toggle('hide', !tk.length);
|
||||
$('#ppTalkList').innerHTML = tk.map((x, i) => '<div class="pp-bub' + (i % 2 ? ' r' : '') + '"><span class="pb-ava">' + momAva(strSeed(x.text)) +
|
||||
'</span><span class="pb-t">' + esc(x.text) + '</span><em>' + fmtN(x.n) + ' 人在聊</em></div>').join('');
|
||||
}
|
||||
function paint() {
|
||||
const r = last;
|
||||
if (!r || !r.show) { sec.classList.add('hide'); return; }
|
||||
sec.classList.remove('hide');
|
||||
peerMode = !!r.peer;
|
||||
sec.classList.toggle('is-peer', peerMode);
|
||||
$('#plPeer').classList.toggle('hide', !peerMode);
|
||||
if (peerMode) paintPeer(r.peer);
|
||||
else $('#plTitle').textContent = '孕妈们在做什么';
|
||||
const tot = $('#plTotal');
|
||||
tot.classList.toggle('hide', !r.total);
|
||||
tot.classList.toggle('hide', !r.total || peerMode);
|
||||
if (r.total) {
|
||||
$('#plPre').textContent = r.total.prefix || '';
|
||||
$('#plSuf').textContent = r.total.suffix || '';
|
||||
if (seen) tweenNum($('#plNum'), r.total.value, 1800);
|
||||
}
|
||||
const td = $('#plToday'), items = r.today || [];
|
||||
const td = $('#plToday'), items = peerMode ? [] : (r.today || []);
|
||||
td.classList.toggle('hide', !items.length);
|
||||
const keys = items.map(x => x.key).join(',') + (APP_BY_ID.taidong ? '|L' : ''); // 应用 logo 到了再重画一次
|
||||
const keys = items.map(x => x.key).join(',');
|
||||
if (td.dataset.keys !== keys) {
|
||||
td.dataset.keys = keys;
|
||||
const was = {}; // logo 到了重画时,数字接着上次的值走,不从 0 再数一遍
|
||||
$$('.pl-stat', td).forEach(b => { const n = b.querySelector('b'); if (n && n.dataset.v != null) was[b.dataset.k] = n.dataset.v; });
|
||||
td.innerHTML = items.map(x => '<button class="pl-stat k-' + x.key + '" type="button" data-k="' + x.key + '">' +
|
||||
pulseIco(x.key, 'ps-ico') + '<b' + (was[x.key] != null ? ' data-v="' + was[x.key] + '">' + fmtN(+was[x.key]) : '>0') + '</b><span>' + String(x.label || '').replace(/[<>&]/g, '') + '</span><i class="go">›</i></button>').join('');
|
||||
pulseIco(x.key, 'ps-ico') + '<b>0</b><span>' + esc(x.label) + '</span><i class="go">›</i></button>').join('');
|
||||
}
|
||||
if (seen) items.forEach(x => tweenNum(td.querySelector('[data-k="' + x.key + '"] b'), x.value, 1600));
|
||||
feed = r.feed || [];
|
||||
const nf = (peerMode ? r.peer.feed : r.feed) || [];
|
||||
const fe = $('#plFeed');
|
||||
fe.classList.toggle('hide', !feed.length);
|
||||
if (feed.length) {
|
||||
fe.classList.toggle('hide', !nf.length);
|
||||
/* 每分钟刷新时只在内容真变了才重置滚动,否则正在翻的那条会跳回第一条 */
|
||||
const sig = nf.map(x => x.text).join('|');
|
||||
if (nf.length && fe.dataset.sig !== sig) {
|
||||
fe.dataset.sig = sig;
|
||||
feed = nf;
|
||||
fi = 0;
|
||||
$('#plTrack').innerHTML = rowHTML(feed[0]);
|
||||
const tr = $('#plTrack');
|
||||
tr.classList.remove('is-move');
|
||||
tr.style.transform = '';
|
||||
tr.innerHTML = rowHTML(feed[0]);
|
||||
if (!ticking) ticking = setInterval(tick, 3000);
|
||||
}
|
||||
}
|
||||
$('#plToday').addEventListener('click', e => {
|
||||
const b = e.target.closest('.pl-stat');
|
||||
if (b && TODAY_GO[b.dataset.k]) { haptic(); TODAY_GO[b.dataset.k](); }
|
||||
sec.addEventListener('click', e => {
|
||||
const b = e.target.closest('.pl-stat,[data-go]');
|
||||
const k = b && (b.dataset.k || b.dataset.go);
|
||||
if (k && TODAY_GO[k]) { haptic(); TODAY_GO[k](); }
|
||||
});
|
||||
const myWeek = () => (state.pregEmpty === false && !state.postpartum && state.week >= 4) ? state.week : null;
|
||||
function load() {
|
||||
return fetch('/api/mp/public/mama-box/pulse')
|
||||
const w = myWeek();
|
||||
loadedWk = w;
|
||||
return fetch('/api/mp/public/mama-box/pulse' + (w ? '?week=' + w : ''))
|
||||
.then(r => (r.ok ? r.json() : null))
|
||||
.then(j => { if (j && j.code === 200 && j.result) { last = j.result; paint(); } })
|
||||
.catch(() => { /* 静默:保持现状(首次失败即一直隐藏) */ });
|
||||
}
|
||||
/* 档案回来孕周才可信 → 孕周变了重拉;否则只是足迹 / 盲盒状态变了,就地重画「和你比」「今日待办」 */
|
||||
plHook = () => { if (myWeek() !== loadedWk) load(); else if (last) paint(); };
|
||||
/* 进入视口才开始数数,否则用户滑到这里时数字早就数完了 */
|
||||
function onSeen() {
|
||||
if (seen) return;
|
||||
@@ -3300,6 +3389,7 @@
|
||||
const BX_TASK_ICO = { kick3: '👶', weight: '⚖️', tool: '📅' };
|
||||
let bxLockSel = null, bxPrizeQ = [];
|
||||
function renderBanner() {
|
||||
if (plHook) plHook(); // 「此刻」的今日待办看本周盲盒开没开
|
||||
const ban = $('#bbBanner');
|
||||
const set = (t, s, cta, ready, calm) => {
|
||||
$('#bbTitle').textContent = t;
|
||||
@@ -3786,7 +3876,7 @@
|
||||
⚠️ 模块显隐只有 fpRender 一个 owner(原来 syncPregnancy 也直接改 display,会撞竞态)。 */
|
||||
let _fpMode = 'pending'; // pending(加载中) | rows | guide | hide
|
||||
let _fpData = null; // 接口 result(events / digest / lead / unused…)
|
||||
function fpApply(mode, r) { _fpMode = mode; _fpData = r || null; fpRender(); }
|
||||
function fpApply(mode, r) { _fpMode = mode; _fpData = r || null; fpRender(); if (plHook) plHook(); }
|
||||
function fpRender() {
|
||||
const tl = document.querySelector('.today-line'), steps = $('#tlSteps'), guide = $('#tlGuide');
|
||||
if (!tl || !steps) return;
|
||||
|
||||
53
mama-box.css
53
mama-box.css
@@ -2646,12 +2646,53 @@ a.skip:focus{left:16px;top:16px}
|
||||
.bx-t .fb{display:grid;place-items:center;width:100%;height:100%;background:radial-gradient(circle at 50% 40%,#fff 0,#FFE6DA 70%)}
|
||||
.bx-keep,.bx-open{text-align:center}
|
||||
|
||||
/* 此刻卡 · 应用 logo(2026-10-01:图标换成对应应用自己的 logo;logo 自带圆角方底,外层底色去掉) */
|
||||
.pl-stat .ps-ico.is-logo,.pl-row .pr-ico.is-logo{background:none!important}
|
||||
.pl-stat .ps-ico img.logo{width:26px;height:26px;border-radius:8px;display:block;box-shadow:0 3px 8px rgba(120,70,50,.14)}
|
||||
.pl-stat .ps-ico{width:26px;height:26px}
|
||||
.pl-row .pr-ico img.logo{width:28px;height:28px;border-radius:9px;display:block;box-shadow:0 2px 6px rgba(120,70,50,.12)}
|
||||
.pl-row .pr-ico{width:28px;height:28px}
|
||||
/* 此刻卡 · A+B 改版(2026-10-01):同孕周妈妈。用人物头像 + 聊天气泡表现「人」,刻意不用应用 logo / 工具格,
|
||||
和上面孕育工具区(方格 + logo)在视觉上拉开。配色沿用本卡的暖白底 + 品牌橙。 */
|
||||
.pl-row .pr-ava,.pp-avs i,.pp-bub .pb-ava{flex:0 0 auto;display:block;border-radius:50%;overflow:hidden;background:#FFE3D3}
|
||||
.pl-row .pr-ava{width:30px;height:30px;box-shadow:0 2px 6px rgba(160,90,60,.14)}
|
||||
.pr-ava svg,.pp-avs svg,.pb-ava svg{display:block;width:100%;height:100%}
|
||||
.pl-peer.hide,.pl-todo.hide,.pp-talk.hide{display:none}
|
||||
.pulse.is-peer .pl-title{font-size:16px}
|
||||
.pp-crowd{display:flex;align-items:center;gap:10px;margin-top:13px}
|
||||
.pp-avs{display:flex}
|
||||
.pp-avs i{width:30px;height:30px;margin-left:-10px;border:2px solid #fff;box-shadow:0 2px 6px rgba(160,90,60,.16)}
|
||||
.pp-avs i:first-child{margin-left:0}
|
||||
.pp-ct{display:flex;flex-direction:column;gap:1px;min-width:0;font-size:13px;color:var(--ink-2);line-height:1.3}
|
||||
.pp-ct b{font-size:20px;font-weight:900;letter-spacing:-.4px;color:var(--brand);font-variant-numeric:tabular-nums;margin-right:2px}
|
||||
.pp-ct small{font-size:11.5px;color:var(--muted)}
|
||||
.pp-doing{display:flex;flex-direction:column;gap:10px;margin-top:14px}
|
||||
.pp-doing:empty{display:none}
|
||||
.pp-dl{display:flex;align-items:center;justify-content:space-between;gap:8px;font-size:13px;color:var(--ink-2)}
|
||||
.pp-dt b{font-size:15px;font-weight:900;color:var(--ink);font-variant-numeric:tabular-nums}
|
||||
.pp-me{flex:0 0 auto;font:inherit;font-size:11.5px;font-weight:700;border:0;border-radius:999px;padding:3px 10px;white-space:nowrap}
|
||||
.pp-me.todo{color:#fff;background:linear-gradient(135deg,#FF7A5C,#F4593C);box-shadow:0 3px 8px rgba(244,89,60,.25)}
|
||||
.pp-me.todo:active{transform:scale(.95)}
|
||||
.pp-me.ok{color:#4E8A43;background:#EAF5E6}
|
||||
.pp-bar{position:relative;height:7px;margin-top:6px;border-radius:99px;background:#F6ECE6;overflow:hidden}
|
||||
.pp-bar i{position:absolute;left:0;top:0;bottom:0;border-radius:99px;background:linear-gradient(90deg,#FFC2A8,#FF8A66);
|
||||
transition:width 1.2s var(--ease)}
|
||||
.pp-do.k-weight .pp-bar i{background:linear-gradient(90deg,#CBB9FF,#9F8CF0)}
|
||||
.pl-todo{display:flex;align-items:center;gap:8px;margin-top:14px;padding:9px 10px;border-radius:14px;background:#FFF4EC;
|
||||
border:1px dashed #FFCDB8}
|
||||
.tdo-h{flex:0 0 auto;font-size:11.5px;font-weight:800;color:#C2593F;writing-mode:horizontal-tb}
|
||||
.tdo-list{display:flex;flex-wrap:wrap;gap:6px;min-width:0}
|
||||
.tdo-chip{display:inline-flex;align-items:center;gap:4px;border:0;font:inherit;font-size:12px;font-weight:700;color:var(--ink);
|
||||
background:#fff;border-radius:999px;padding:4px 9px 4px 5px;box-shadow:0 1px 4px rgba(160,90,60,.1)}
|
||||
.tdo-chip:active{transform:scale(.95)}
|
||||
.tdo-chip b{color:var(--brand)}
|
||||
.tdo-chip i{font-style:normal;opacity:.4}
|
||||
.tdo-ico{width:18px;height:18px;border-radius:50%;display:grid;place-items:center;color:#fff;background:#5B8FD6}
|
||||
.tdo-ico svg{width:11px;height:11px}
|
||||
.tdo-chip.hot .tdo-ico{background:linear-gradient(135deg,#FFB547,#FF7A5C)}
|
||||
.pp-talk{margin-top:14px}
|
||||
.pp-sub{display:block;font-size:12px;font-weight:800;color:var(--muted);margin-bottom:8px}
|
||||
.pp-bub{display:flex;align-items:center;gap:7px;margin-top:7px}
|
||||
.pp-bub.r{flex-direction:row-reverse}
|
||||
.pp-bub .pb-ava{width:26px;height:26px}
|
||||
.pb-t{position:relative;max-width:62%;font-size:13px;font-weight:700;color:var(--ink);background:#FBF3EE;
|
||||
padding:7px 11px;border-radius:4px 14px 14px 14px}
|
||||
.pp-bub.r .pb-t{background:#F3EEFF;border-radius:14px 4px 14px 14px}
|
||||
.pp-bub em{font-style:normal;font-size:10.5px;color:var(--muted);white-space:nowrap}
|
||||
|
||||
/* 孕期小知识 · 压缩版(2026-10-01:标题前带孕周;今日卡、7 天圆点、四张小卡都收紧,四卡改一行横滑) */
|
||||
.pt-head{margin-bottom:8px;align-items:center}
|
||||
|
||||
Reference in New Issue
Block a user