Compare commits
10 Commits
e2d6489393
...
f99a4d59eb
| Author | SHA1 | Date | |
|---|---|---|---|
| f99a4d59eb | |||
| 60bc63a870 | |||
| 7868556042 | |||
| 1d0b780185 | |||
| fc7160a4f2 | |||
| bd82944f18 | |||
| 3cfe08cd73 | |||
| ced6b1ff08 | |||
| 81549a4f50 | |||
| 7b33902bdc |
BIN
assets/img/b3253e3c7a83.png
Normal file
BIN
assets/img/b3253e3c7a83.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 514 B |
84
index.html
84
index.html
@@ -6,17 +6,22 @@
|
||||
<meta name="theme-color" content="#F4593C">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<title>妈妈盒子 · 孕育陪伴</title>
|
||||
<!-- V:26090811 缓存版本标记:改 css/js 时同步 bump 该值,并给下方资源引用加 ?v= 以强制 webview 刷新子资源 -->
|
||||
<link rel="stylesheet" href="mama-box.css?v=26090811">
|
||||
<title>兜爸心选 · 孕育陪伴</title>
|
||||
<!-- V:26091602 缓存版本标记:改 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 第四节) -->
|
||||
<script src="js/wx-auth.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a class="skip" href="#screens">跳到内容</a>
|
||||
<div class="phone" id="phone">
|
||||
<nav class="tabbar" id="tabbar">
|
||||
<button class="tab is-active" data-tab="home">
|
||||
<span class="t-ico ic-home"></span><span class="t-txt">首页</span>
|
||||
<!-- ⚠️ 未读红点 #tabBadge 本批(第九批)从原「宝宝来信」tab 挪到这里:
|
||||
那枚 tab 改成了商城入口(见下方 #tabMall),把信件未读红点挂在商城里会误导。
|
||||
挪动是纯 DOM 位置调整,syncLetterCounts/applyRemote* 仍只按 id 取,JS 一行没改。 -->
|
||||
<span class="t-ico ic-home"></span><span class="t-badge" id="tabBadge"></span><span class="t-txt">首页</span>
|
||||
</button>
|
||||
<button class="tab" data-tab="archive">
|
||||
<span class="t-ico ic-archive"></span><span class="t-txt">档案</span>
|
||||
@@ -24,17 +29,16 @@
|
||||
<button class="tab tab-fab" data-sheet="open">
|
||||
<span class="fab"><img src="assets/img/69818ea975da.png" alt="" aria-hidden="true"></span><span class="t-txt">记一下</span>
|
||||
</button>
|
||||
<button class="tab" data-tab="letter">
|
||||
<!-- ⚠️ 「宝宝来信」。上一批按需求整条线改口叫过「宝宝消息」,本批用户明确要求
|
||||
**退回「来信」**,全线七处一起退(底 tab、首页卡、详情页顶栏、珍贵时刻卡
|
||||
标题 + 出处、搜索占位符、搜索 chip)。
|
||||
退回之后那条老矛盾会跟着回来:列表本身是聊天气泡(头像 + 气泡 + 时间戳),
|
||||
tab 上写「来信」、点进去是一屏对话,字面上对不齐。这是用户看过两版之后
|
||||
**选定**的说法,不是漏改 —— 想再改回「消息」之前先去问,别自己动。
|
||||
⚠️ 这枚标签**不跟小名走**(syncBabyWords 有意不碰它):底 tab 是全局导航,
|
||||
跟着改会变成「小汤圆来信」,四个 tab 里只有这一个宽度会变;
|
||||
而且导航栏本来就该是固定坐标,不随用户数据浮动。 -->
|
||||
<span class="t-ico ic-letter"></span><span class="t-badge" id="tabBadge"></span><span class="t-txt">宝宝来信</span>
|
||||
<button class="tab" id="tabMall">
|
||||
<!-- ⚠️ 本批(第九批)按用户要求,把原「宝宝来信」这枚底 tab 改成「兜爸心选」商城入口。
|
||||
⚠️ 与「档案」tab 同款:**不挂 data-tab**,点了直接走 goMall() 跳小程序原生商城页
|
||||
(switchTab /pages/goods_cate/goods_cate),所以它**没有** is-active 高亮态,
|
||||
也不参与 go() 的 tab 高亮切换。
|
||||
⚠️ 来信屏 #screen-letter **没有被删**:它仍在 swipe() 的 order 里,左右滑动还能进;
|
||||
只是底 tab 不再提供入口(用户本批明确选择「保留屏幕、滑动仍可进入」)。
|
||||
想再把这枚 tab 挂回来信之前先去问,别自己动。
|
||||
⚠️ 未读红点已挪到「首页」tab(原 #tabBadge 的位置),别再挂回这枚商城 tab。 -->
|
||||
<span class="t-ico ic-shop"></span><span class="t-txt">兜爸心选</span>
|
||||
</button>
|
||||
<button class="tab" data-tab="me">
|
||||
<span class="t-ico ic-me"></span><span class="t-txt">我的</span>
|
||||
@@ -79,7 +83,7 @@
|
||||
气泡一动,橙区那笔竖列账要连着重算 —— 已经算过,见 style.css 的 .home-hero。
|
||||
改字号 / 加字 / 挪气泡之前,把上面两笔账都重算一遍。 -->
|
||||
<div class="hero-top">
|
||||
<div class="hero-brand">妈妈盒子</div>
|
||||
<div class="hero-brand">兜爸心选</div>
|
||||
<p class="hero-slogan">每次记录都是一生记忆</p>
|
||||
</div>
|
||||
|
||||
@@ -209,9 +213,18 @@
|
||||
</button>
|
||||
<!-- 生长曲线原来是 flex:1,把这一列剩下的高度全吃了(约 134px),
|
||||
而它的内容和上面的孕检日历一模一样多。压到 80px,
|
||||
省下的 54px 给下面那张「更多工具」。 -->
|
||||
省下的 54px 给下面那张「更多工具」。
|
||||
⚠️ 本批(第九批)把这张卡从「生长曲线」换成「数宫缩」:
|
||||
文案改这一行;落点改 app.js 的 MINI_APP_MAP.curve
|
||||
(taiershengzhang → gongsuopinlv,指向已上架的「宫缩频率计算」)。
|
||||
⚠️「生长曲线」工具本身**没被删**:App 表里 taiershengzhang /
|
||||
taierquxian 都还在,仍会出现在「记一下」的全部工具列表里;
|
||||
这里换掉的只是首页这一个坑位。
|
||||
⚠️ 图标仍是原来那张 72f41378ef8e(曲线插画),本批未要求换;
|
||||
若要换成宫缩/宫缩计时的插画,属另一次改动。
|
||||
⚠️ 副标题仍是 data-wk="cn" 自动显示孕周,本批未要求改文案。 -->
|
||||
<button class="mini-card curve ripple" data-mini="curve">
|
||||
<div class="mc-title sm">生长曲线</div>
|
||||
<div class="mc-title sm">数宫缩</div>
|
||||
<div class="mc-sub" data-wk="cn">—</div>
|
||||
<img class="mc-art" src="assets/img/72f41378ef8e.png" alt="" aria-hidden="true">
|
||||
</button>
|
||||
@@ -722,7 +735,7 @@
|
||||
<section class="screen" id="screen-me" data-screen="me">
|
||||
<div class="me-top">
|
||||
<div class="hero-top">
|
||||
<!-- (商城图标已移除:进商城统一走下方「兜爸心选商城」模块 meMallCard)
|
||||
<!-- (商城图标已移除:进商城统一走下方「兜爸心选」模块 meMallCard)
|
||||
<button class="icon-btn plain" id="btnMall" aria-label="进商城">
|
||||
<svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true">
|
||||
<path d="M5 8h14l-1.2 11a2 2 0 0 1-2 1.8H8.2a2 2 0 0 1-2-1.8z" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round"/>
|
||||
@@ -850,10 +863,19 @@
|
||||
⚠️ 故意**不挂 data-modal="modalWx"**。那条通用通道直接调 openModal,
|
||||
会绕过 openWx() —— 弹窗的模式类名、引导语、上次残留的红字和
|
||||
输入内容、还有 wxPending 全都不会被重置。这里必须走 JS 那条路。
|
||||
⚠️ 这张卡**不随解锁状态隐藏**(资源库顶部那条 banner 会)。
|
||||
它是「我的」页的常驻入口,藏了会缺一块;代价是已解锁的人
|
||||
仍会看到福利文案 —— 由弹窗 done 模式的文案把动线接上,
|
||||
见 app.js openWx() 里那三段。这是有意的,不是漏改。 -->
|
||||
⚠️ 这张卡历史上**不随解锁状态隐藏**(资源库顶部那条 banner 会),
|
||||
定位是「我的」页的常驻入口。本批(第九批)按用户要求把整块
|
||||
「专属福利」先隐藏 —— 见下面 #meWelfareHidden 那段注释;
|
||||
上面这条「常驻」的旧约定随之暂停,恢复时把该容器的 display:none 去掉即可。 -->
|
||||
<!-- ⚠️ 本批(第九批)按用户要求**先隐藏**「专属福利」整块(标题 + 孕育顾问卡)。
|
||||
用外层容器 display:none 而不是删 DOM,原因有二:
|
||||
① #meWxCard 的点击绑定(app.js openWx('gift'))、syncBabyWords() 对
|
||||
#meWxTitle/#meWxSub 的写入都还引用它们,删了会当场报错;
|
||||
② 保留 DOM 便于随时一键恢复(去掉这里的 display:none 即可)。
|
||||
⚠️ 隐藏的只是这一块。下面「甄选好物 / 进入商城」(#meMallCard)**不动** ——
|
||||
它是另一张卡,用户没要求藏。
|
||||
⚠️ 资源库顶部那条 #rlGift banner 不在这一块里,本次未动。 -->
|
||||
<div id="meWelfareHidden" style="display:none">
|
||||
<h2 class="sec-title dark">专属福利</h2>
|
||||
<button class="wx-card ripple" id="meWxCard">
|
||||
<!-- ⚠️ 这一版是**三段竖排**:角标行 / 图文行 / 通栏 CTA。
|
||||
@@ -983,8 +1005,9 @@
|
||||
<button>,按钮套按钮是非法 HTML。 -->
|
||||
<span class="wx-cta">立即免费领取</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h2 class="sec-title dark">兜爸心选商城</h2>
|
||||
<h2 class="sec-title dark">甄选好物</h2>
|
||||
<button class="wx-card ripple" id="meMallCard">
|
||||
<!-- 「甄选好物」角标已按需求去掉(.wx-top 角标行整行移除;孕育顾问那条"限量福利"不受影响) -->
|
||||
<span class="wx-body">
|
||||
@@ -999,7 +1022,7 @@
|
||||
</span>
|
||||
<span class="wx-main">
|
||||
<span class="wx-head">
|
||||
<span class="wx-title">兜爸心选商城</span>
|
||||
<span class="wx-title">兜爸心选</span>
|
||||
<span class="wx-lim">母婴 · 好物</span>
|
||||
</span>
|
||||
<span class="wx-sub">为宝宝甄选的母婴好物,值得认真挑一挑</span>
|
||||
@@ -1019,7 +1042,7 @@
|
||||
<span class="li-t">帮助与反馈</span><i class="chev">›</i></button>
|
||||
<button class="li ripple" data-open="detailSetting" data-set="about">
|
||||
<span class="li-ico b"><svg viewBox="0 0 24 24" width="19" height="19" aria-hidden="true"><circle cx="12" cy="12" r="8.2" fill="none" stroke="currentColor" stroke-width="1.8"/><path d="M12 11v5.4" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round"/><circle cx="12" cy="7.9" r="1.15" fill="currentColor"/></svg></span>
|
||||
<span class="li-t">关于妈妈盒子</span><span class="li-v">v3.2.1</span><i class="chev">›</i></button>
|
||||
<span class="li-t">关于兜爸心选</span><span class="li-v">v3.2.1</span><i class="chev">›</i></button>
|
||||
<!-- 退出授权登录:仅已授权时显示(applyRemoteProfile 控制)。
|
||||
调 box_app /auth/logout —— 只翻授权状态,不清昵称/头像/手机号等资料 -->
|
||||
<button class="li ripple" id="meLogoutCard" style="display:none">
|
||||
@@ -1389,7 +1412,7 @@
|
||||
</section>
|
||||
|
||||
<!-- ================= 设置与服务 二级页 =================
|
||||
隐私与权限 / 帮助与反馈 / 关于妈妈盒子 三项共用这一个壳,
|
||||
隐私与权限 / 帮助与反馈 / 关于兜爸心选 三项共用这一个壳,
|
||||
内容由 js 里的 SETTINGS 表渲染进 #stBody,避免写四份几乎一样的结构 -->
|
||||
<section class="detail" id="detailSetting">
|
||||
<div class="detail-bar">
|
||||
@@ -1431,7 +1454,10 @@
|
||||
<button class="app ripple"><img class="a-ico" src="assets/img/505ace532176.png" alt="" aria-hidden="true">数胎动</button>
|
||||
<button class="app ripple"><img class="a-ico" src="assets/img/8b0f0a53938b.png" alt="" aria-hidden="true">孕期体重</button>
|
||||
<button class="app ripple"><img class="a-ico" src="assets/img/9a2e7fa472dc.png" alt="" aria-hidden="true">孕检日历</button>
|
||||
<button class="app ripple"><img class="a-ico" src="assets/img/f989a64fe960.png" alt="" aria-hidden="true">生长曲线</button>
|
||||
<!-- ⚠️ 下面这十几枚是**接口数据到达前的静态占位**:loadPublishedApps() 拉到
|
||||
/api/mp/apps 后会用 renderAppGrid() 整个 innerHTML 覆盖。所以这里改不改
|
||||
只影响首帧闪现;本批把「生长曲线」同步改成「数宫缩」,与首页卡口径一致。 -->
|
||||
<button class="app ripple"><img class="a-ico" src="assets/img/f989a64fe960.png" alt="" aria-hidden="true">数宫缩</button>
|
||||
<button class="app ripple"><img class="a-ico" src="assets/img/fd875eb78785.png" alt="" aria-hidden="true">胎心记录</button>
|
||||
<button class="app ripple"><img class="a-ico" src="assets/img/97c33531806b.png" alt="" aria-hidden="true">孕肚照</button>
|
||||
<button class="app ripple"><img class="a-ico" src="assets/img/de0bc9e250f2.png" alt="" aria-hidden="true">B超影像</button>
|
||||
@@ -1774,7 +1800,7 @@
|
||||
加载失败/离线时 window.wx 为 undefined,goMall() 会降级为 toast 提示,
|
||||
不影响应用其余功能。 -->
|
||||
|
||||
<script src="js/app.js?v=26090811"></script>
|
||||
<script src="js/app.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
88
js/app.js
88
js/app.js
@@ -1,9 +1,9 @@
|
||||
|
||||
/* ================= 妈妈盒子 H5 · 交互 ================= */
|
||||
/* ================= 兜爸心选 H5 · 交互 ================= */
|
||||
(function () {
|
||||
'use strict';
|
||||
/* 页面版本号(YYMMDD+序号):显示在「关于妈妈盒子」页底部;bump 时同步 head 注释与 ?v= */
|
||||
var VER = '26090811';
|
||||
/* 页面版本号(YYMMDD+序号):显示在「关于兜爸心选」页底部;bump 时同步 head 注释与 ?v= */
|
||||
var VER = '26091602';
|
||||
const $ = (s, c) => (c || document).querySelector(s);
|
||||
const $$ = (s, c) => Array.from((c || document).querySelectorAll(s));
|
||||
|
||||
@@ -156,19 +156,31 @@
|
||||
catch (e) { el.scrollTop = 0; }
|
||||
}
|
||||
|
||||
/* 「档案」tab 一期跳独立 H5(yunqi-dangan)。
|
||||
⚠️ 内置档案屏(#screen-archive)暂时屏蔽:数据来源未确认,不放进一期给用户。
|
||||
/* 「档案」tab 一期跳独立 H5。第九批(2026-09-16)按用户要求把落点从
|
||||
「孕期档案管理 yunqi-dangan」改成「孕检日历 chanjian-rili」。
|
||||
⚠️ 地址必须走业务域名 mp.yizhezhe.com(小程序 web-view 只放行业务域名,
|
||||
taidong.douba.top 直连会被拦),所以这里用的是 nginx 反代入口,不是源站直连。
|
||||
⚠️ 内置档案屏(#screen-archive)依旧屏蔽:数据来源未确认,不放进一期给用户。
|
||||
屏的代码/样式全部保留,后续确认数据源后把这里改回 go('archive') 原逻辑即可。
|
||||
身份转发:把当前 openid/unionid 带过去(query + hash 双写,对齐身份注入惯例)。 */
|
||||
/* 换页/换应用前向小程序宿主上报「即将进入的地址」(分享卡片状态同步)。
|
||||
背景:web-view 里的 H5 不能自己拉起分享面板,宿主只能靠 onShareAppMessage(options).webViewUrl
|
||||
拿到当前地址,而 onShareTimeline 没有回调参数;首页壳也不会随 H5 换页重新 onLoad。
|
||||
postMessage 非实时(微信在「分享 / 后退」等时机才派发),届时 web-view 已停在该地址。
|
||||
协议见 box_app/docs/h5-auth-standard.md 第四节。 */
|
||||
function reportHostLocation(url) {
|
||||
if (window.wxAuth && window.wxAuth.reportLocation) window.wxAuth.reportLocation({ href: url });
|
||||
}
|
||||
|
||||
function goArchiveH5() {
|
||||
const oid = hashParam('openid');
|
||||
const uid = hashParam('unionid');
|
||||
let u = 'https://mp.yizhezhe.com/yunqi-dangan/';
|
||||
let u = 'https://mp.yizhezhe.com/chanjian-rili/';
|
||||
const q = [];
|
||||
if (oid) q.push('openid=' + encodeURIComponent(oid));
|
||||
if (uid) q.push('unionid=' + encodeURIComponent(uid));
|
||||
if (q.length) u += '?' + q.join('&');
|
||||
if (oid) u += '#openid=' + encodeURIComponent(oid);
|
||||
reportHostLocation(u);
|
||||
location.href = u;
|
||||
}
|
||||
|
||||
@@ -182,6 +194,10 @@
|
||||
for (let i = 0; i < (name || '').length; i++) h = (h * 31 + name.charCodeAt(i)) >>> 0;
|
||||
return PALETTE[h % PALETTE.length];
|
||||
}
|
||||
/* 跳转到其它 H5 应用:身份只走 query(openid/unionid,原 URL 有 query 用 & 续接)。
|
||||
⚠️ 不再追加 #openid —— 部分应用自带 hash 路由(如 /baobao-yingji),追加 hash 会被当
|
||||
非法路由 → 页面未找到。宿主每次加载/onShow 会重新注入身份兜底;
|
||||
hash 仅保留作为「授权回传结果」(#phone/nickname/avatar)的通道。 */
|
||||
function jumpApp(url) {
|
||||
haptic();
|
||||
const oid = hashParam('openid');
|
||||
@@ -190,7 +206,7 @@
|
||||
if (oid) q.push('openid=' + encodeURIComponent(oid));
|
||||
if (uid) q.push('unionid=' + encodeURIComponent(uid));
|
||||
if (q.length) url += (url.indexOf('?') >= 0 ? '&' : '?') + q.join('&');
|
||||
if (oid) url += '#openid=' + encodeURIComponent(oid);
|
||||
reportHostLocation(url);
|
||||
location.href = url;
|
||||
}
|
||||
function renderAppGrid(apps) {
|
||||
@@ -481,23 +497,26 @@
|
||||
}));
|
||||
|
||||
/* 首页宫格入口。
|
||||
五个坑位里有三个已经有真站点了,点了直接跳过去;剩下两个(数胎动 / 生长曲线)
|
||||
还没有后端,维持原来弹 toast 的占位行为,不假装能打开。
|
||||
五个坑位现在**全部**指向已上架应用(都由 App 表下发 URL),没有占位 toast 了;
|
||||
某张卡的 identifier 在 App 表里查不到 / 没配 URL 时,才退回「即将上线」提示。
|
||||
跳转用 location.href 走**当前标签页**:这个壳是照着原生 App 做的,
|
||||
新开标签会在微信 / Safari 里堆出一串返回不去的页面;同页跳转的话,
|
||||
浏览器返回键就是天然的「返回」。 */
|
||||
/* 首页五张工具卡 → 已上架应用(identifier 在应用管理维护,后台改 URL 即生效)。
|
||||
⚠️ 不再裸跳旧 beian*.douba.top 域名:统一走 jumpApp 带身份(openid/unionid)。 */
|
||||
⚠️ 不再裸跳旧 beian*.douba.top 域名:统一走 jumpApp 带身份(openid/unionid)。
|
||||
⚠️ App 表里的 URL 一律用业务域名 mp.yizhezhe.com/<slug>/(nginx 反代到源站)——
|
||||
小程序 web-view 只放行业务域名,写 taidong.douba.top 直连会被拦。
|
||||
第九批(2026-09-16):curve 从「生长曲线 taiershengzhang」改成「数宫缩 gongsuopinlv」。 */
|
||||
const MINI_APP_MAP = {
|
||||
kick: 'taidong', // 数胎动 (1005)
|
||||
weight: 'yunqitizhong', // 孕期体重管理 (1012)
|
||||
cal: 'chanjianrili', // 孕检日历 (1009)
|
||||
curve: 'taiershengzhang', // 生长曲线 (1013)
|
||||
curve: 'gongsuopinlv', // 数宫缩(原「生长曲线」,第九批换坑位)
|
||||
fweight:'taierguzhong' // 胎儿估重 (1037)
|
||||
};
|
||||
const APP_BY_ID = {};
|
||||
$$('[data-mini]').forEach(b => b.addEventListener('click', () => {
|
||||
const map = { kick: '数胎动', weight: '孕期体重', cal: '孕检日历', curve: '生长曲线', fweight: '胎儿估重' };
|
||||
const map = { kick: '数胎动', weight: '孕期体重', cal: '孕检日历', curve: '数宫缩', fweight: '胎儿估重' };
|
||||
const app = APP_BY_ID[MINI_APP_MAP[b.dataset.mini]];
|
||||
if (app && app.url) { jumpApp(app.url); return; }
|
||||
toast('「' + map[b.dataset.mini] + '」即将上线');
|
||||
@@ -2216,7 +2235,7 @@
|
||||
txt 纯说明段落 */
|
||||
/* 说明:「提醒设置」整项已按需求删除(连同「我的」里的入口行)。
|
||||
隐私与权限去掉了「社区匿名发言」「设备权限」「数据」三处;
|
||||
帮助与反馈只留「联系我们」;关于妈妈盒子只留介绍。 */
|
||||
帮助与反馈只留「联系我们」;关于兜爸心选只留介绍。 */
|
||||
const SETTINGS = {
|
||||
privacy: {
|
||||
title: '隐私与权限', more: '你的记录只属于你',
|
||||
@@ -2243,20 +2262,20 @@
|
||||
['row', '加入内测群', '抢先体验新功能']
|
||||
] }
|
||||
],
|
||||
foot: '你提的每一条建议我们都会看,妈妈盒子有很多功能就是这么来的。'
|
||||
foot: '你提的每一条建议我们都会看,兜爸心选有很多功能就是这么来的。'
|
||||
},
|
||||
|
||||
about: {
|
||||
title: '关于妈妈盒子', more: '当前版本 v3.2.1',
|
||||
title: '关于兜爸心选', more: '当前版本 v3.2.1',
|
||||
hero: 1,
|
||||
lead: '妈妈盒子想做的事很简单:让你不用记录,也能留下记录。',
|
||||
lead: '兜爸心选想做的事很简单:让你不用记录,也能留下记录。',
|
||||
groups: [
|
||||
{ t: '', rows: [
|
||||
['txt', '怀孕已经够辛苦了,我们不想再让你多填一张表。你每一次数胎动、称体重、看产检、读宝宝的来信,妈妈盒子都会悄悄记下来,替你整理成一本档案。'],
|
||||
['txt', '怀孕已经够辛苦了,我们不想再让你多填一张表。你每一次数胎动、称体重、看产检、读宝宝的来信,兜爸心选都会悄悄记下来,替你整理成一本档案。'],
|
||||
['txt', '等宝宝出生、等他长大、等你某天忽然想起这段日子,这本档案都还在原地等你。']
|
||||
] }
|
||||
],
|
||||
foot: '妈妈盒子 v3.2.1 · 已陪伴 268 万位妈妈'
|
||||
foot: '兜爸心选 v3.2.1 · 已陪伴 268 万位妈妈'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2270,7 +2289,7 @@
|
||||
'fill="none" stroke="#F4593C" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"/>' +
|
||||
'</svg>' +
|
||||
'</div>' +
|
||||
'<div class="st-appname">妈妈盒子</div>' +
|
||||
'<div class="st-appname">兜爸心选</div>' +
|
||||
'<div class="st-ver">v3.2.1 · 陪你从两条杠到见面</div>' +
|
||||
'</div>';
|
||||
|
||||
@@ -2301,11 +2320,11 @@
|
||||
}).join('');
|
||||
|
||||
$('#stBody').innerHTML = html;
|
||||
/* 「关于妈妈盒子」页底部显示版本号(全站不再有固定底标) */
|
||||
/* 「关于兜爸心选」页底部显示版本号(全站不再有固定底标) */
|
||||
if (key === 'about') {
|
||||
let av = document.getElementById('aboutVer');
|
||||
if (!av) { av = document.createElement('p'); av.id = 'aboutVer'; av.className = 'about-ver'; $('#detailSetting .detail-body').appendChild(av); }
|
||||
av.textContent = '妈妈盒子 v' + VER;
|
||||
av.textContent = 'v' + VER;
|
||||
}
|
||||
scrollTop($('#detailSetting .detail-body'));
|
||||
}
|
||||
@@ -3061,7 +3080,7 @@
|
||||
if (kind === 'week') {
|
||||
const mon = weekRange()[0], sun = weekRange()[1];
|
||||
const todayOff = (midnight(new Date()).getDay() + 6) % 7;
|
||||
D.label = '妈妈盒子 · 本周档案';
|
||||
D.label = '兜爸心选 · 本周档案';
|
||||
D.range = fmtMD(mon) + ' — ' + fmtMD(sun);
|
||||
D.logs = WEEK_LOG.filter(l => l[0] <= todayOff).map(l => {
|
||||
const d = new Date(mon.getTime() + l[0] * DAY_MS);
|
||||
@@ -3072,7 +3091,7 @@
|
||||
D.foot = '孕 ' + week + ' 周 · 本周共 ' + D.logs.length + ' 条记录';
|
||||
} else {
|
||||
const tl = timelineLogs(), mo = momentLogs();
|
||||
D.label = '妈妈盒子 · 完整档案';
|
||||
D.label = '兜爸心选 · 完整档案';
|
||||
D.range = '从记录第一天到今天 · 共 ' + days + ' 天';
|
||||
D.stats = [['已陪伴', days + ' 天'], ['累计归档', '386 条'], ['珍贵时刻', mo.length + ' 个']];
|
||||
D.growth = growthData();
|
||||
@@ -3166,7 +3185,7 @@
|
||||
ctx.textAlign = 'center'; ctx.fillStyle = '#B39C8E'; ctx.font = pf(21, 600);
|
||||
ctx.fillText(D.foot, W / 2, y + 48);
|
||||
ctx.font = pf(20, 400);
|
||||
ctx.fillText('生成于 ' + fmtYMD(new Date()) + ' · 妈妈盒子', W / 2, y + 84);
|
||||
ctx.fillText('生成于 ' + fmtYMD(new Date()) + ' · 兜爸心选', W / 2, y + 84);
|
||||
ctx.textAlign = 'left';
|
||||
}
|
||||
return y + 84 + 46;
|
||||
@@ -3409,7 +3428,7 @@
|
||||
c.textAlign = 'center'; c.fillStyle = '#C9BBB1'; c.font = pf(19, 400);
|
||||
c.fillText('全书共 ' + total + ' 页 · 沿左侧装订线打孔即可成册',
|
||||
A4_W / 2, A4_H - MG.bottom + 46);
|
||||
c.fillText('生成于 ' + fmtYMD(new Date()) + ' · 妈妈盒子',
|
||||
c.fillText('生成于 ' + fmtYMD(new Date()) + ' · 兜爸心选',
|
||||
A4_W / 2, A4_H - MG.bottom + 78);
|
||||
c.textAlign = 'left';
|
||||
}
|
||||
@@ -3439,7 +3458,7 @@
|
||||
c.textAlign = 'center'; c.fillStyle = '#B39C8E'; c.font = pf(20, 600);
|
||||
c.fillText('— ' + no + ' —', A4_W / 2, A4_H - MG.bottom + 48);
|
||||
c.textAlign = 'right'; c.fillStyle = '#C9BBB1'; c.font = pf(17, 400);
|
||||
c.fillText('妈妈盒子 · 生成于 ' + fmtYMD(new Date()) + ' · 共 ' + total + ' 页',
|
||||
c.fillText('兜爸心选 · 生成于 ' + fmtYMD(new Date()) + ' · 共 ' + total + ' 页',
|
||||
A4_W - MG.out, A4_H - MG.bottom + 48);
|
||||
c.textAlign = 'left';
|
||||
}
|
||||
@@ -3448,7 +3467,7 @@
|
||||
/* 导出层是两个面板共用的(档案海报 + 来信分享卡),所以「这批图叫什么」
|
||||
不能再从 posterKind 推——加一组随 beginSheets() 一起设的标签。
|
||||
exportTag 进文件名,exportTitle 进系统分享面板的标题。 */
|
||||
let exportTag = '档案', exportTitle = '妈妈盒子';
|
||||
let exportTag = '档案', exportTitle = '兜爸心选';
|
||||
|
||||
/* 每次要铺新的一批图,必须先调这个。
|
||||
⚠️ posterURLs 是模块级的,两个面板都往里写。不清空的后果是静默的:
|
||||
@@ -3549,7 +3568,7 @@
|
||||
function posterFile(i) {
|
||||
const d = new Date(), p = n => (n < 10 ? '0' : '') + n;
|
||||
const stamp = d.getFullYear() + p(d.getMonth() + 1) + p(d.getDate());
|
||||
return '妈妈盒子-' + exportTag + '-' + stamp + (i ? '-第' + i + '页' : '') + '.png';
|
||||
return '兜爸心选-' + exportTag + '-' + stamp + (i ? '-第' + i + '页' : '') + '.png';
|
||||
}
|
||||
|
||||
/* 保存 / 分享 / 打印这三件事,档案面板和分享卡面板一模一样,
|
||||
@@ -3729,7 +3748,7 @@
|
||||
ctx.beginPath(); ctx.moveTo(P, fy); ctx.lineTo(W - P, fy); ctx.stroke();
|
||||
ctx.textAlign = 'left'; ctx.textBaseline = 'alphabetic';
|
||||
ctx.fillStyle = '#8B6E5E'; ctx.font = pf(26, 700);
|
||||
ctx.fillText('妈妈盒子', P, fy + 80);
|
||||
ctx.fillText('兜爸心选', P, fy + 80);
|
||||
ctx.fillStyle = '#B39C8E'; ctx.font = pf(21, 400);
|
||||
ctx.fillText('每周一封,宝宝写给妈妈的信', P, fy + 122);
|
||||
const qs = 118, qx = W - P - qs, qy = fy + 36;
|
||||
@@ -4133,6 +4152,8 @@
|
||||
|
||||
/* ================= 初始化 ================= */
|
||||
function init() {
|
||||
/* 首屏向小程序宿主上报当前位置:宿主据此解析分享卡片(见 reportHostLocation 说明)。 */
|
||||
if (window.wxAuth && window.wxAuth.reportLocation) window.wxAuth.reportLocation();
|
||||
/* 默认预产期是「今天 + 3 个月」现算出来的,标记里那些
|
||||
「孕 24 周 +3 天 / 预产期 2024年12月22日」只是设计稿留下的占位,
|
||||
进门先按真实 state 刷一遍,免得首屏闪一下旧数字 */
|
||||
@@ -4415,7 +4436,7 @@
|
||||
}
|
||||
|
||||
/* ---------- 进商城(web-view 内跳商城原生页) ----------
|
||||
妈妈盒子 H5 由小程序 web-view 承载;点「商城」跳回商城原生页。
|
||||
兜爸心选 H5 由小程序 web-view 承载;点「商城」跳回商城原生页。
|
||||
需微信 JS-SDK 的 wx.miniProgram.switchTab —— tabBar 页必须用 switchTab
|
||||
(详见 docs/mama-box-api-plan.md 2.4)。
|
||||
仅在 web-view 环境生效;浏览器独立打开时 wx.miniProgram 不可用,降级为 toast。 */
|
||||
@@ -4440,7 +4461,10 @@
|
||||
toast('请在微信小程序中打开商城');
|
||||
}
|
||||
}
|
||||
$$('#btnMall, #meMallCard').forEach(function (b) {
|
||||
/* 第九批:底部 tab「兜爸心选」(#tabMall)也走同一个 goMall()。
|
||||
它**不挂 data-tab**,因此不在上面的 tabs 集合里、不参与 go() 高亮切换;
|
||||
点击只做「跳商城」这一件事。落点与「我的」页「进入商城」完全一致。 */
|
||||
$$('#btnMall, #meMallCard, #tabMall').forEach(function (b) {
|
||||
b.addEventListener('click', goMall);
|
||||
});
|
||||
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
wxAuth.isAuthorized(); // 是否已授权(手机号/昵称/头像任一非空)
|
||||
wxAuth.requestProfile(); // 点「授权登录」→ postMessage 通知宿主页
|
||||
wxAuth.goMall(); // 点「进商城」→ 跳小程序商城 tabBar 页
|
||||
wxAuth.watchLocation(); // 换页/路由切换自动上报当前位置 → 宿主刷新分享卡片(推荐)
|
||||
wxAuth.reportLocation({title}); // 手动上报一次当前页(标题/图可选)
|
||||
分享卡片同步协议(location/share/setTitle/copyLink/requestProfile)见
|
||||
box_app/docs/h5-auth-standard.md 第四节
|
||||
回传协议:宿主页授权成功后更新 web-view src 为
|
||||
<H5地址>?t=<ts>#openid=..&phone=..&nickname=..&avatar=..
|
||||
(微信 webview 丢 query、不丢 hash,故授权结果放 hash)
|
||||
@@ -65,7 +69,16 @@
|
||||
requestProfile: function (authPage) {
|
||||
var self = this;
|
||||
function nav() {
|
||||
window.wx.miniProgram.navigateTo({ url: authPage || '/pages/annex/auth/index' });
|
||||
window.wx.miniProgram.navigateTo({
|
||||
url: authPage || '/pages/annex/auth/index',
|
||||
/* 页面不存在 / 页面栈超限(>10层) 时 navigateTo 是静默失败 —— 必须自己兜住并提示,
|
||||
否则用户只看到「正在打开授权页…」后再无反应,无从排查。 */
|
||||
fail: function (err) {
|
||||
var m = (err && err.errMsg) || '未知原因';
|
||||
self.toast('打开授权页失败:' + m);
|
||||
try { console.warn('[wxAuth] navigateTo fail:', m); } catch (e) {}
|
||||
}
|
||||
});
|
||||
self.toast('正在打开授权页…');
|
||||
}
|
||||
if (!/MicroMessenger/i.test(navigator.userAgent)) {
|
||||
@@ -92,7 +105,14 @@
|
||||
goMall: function (url) {
|
||||
var self = this;
|
||||
function go() {
|
||||
window.wx.miniProgram.switchTab({ url: url || '/pages/goods_cate/goods_cate' });
|
||||
window.wx.miniProgram.switchTab({
|
||||
url: url || '/pages/goods_cate/goods_cate',
|
||||
fail: function (err) {
|
||||
var m = (err && err.errMsg) || '未知原因';
|
||||
self.toast('打开商城失败:' + m);
|
||||
try { console.warn('[wxAuth] switchTab fail:', m); } catch (e) {}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!/MicroMessenger/i.test(navigator.userAgent)) {
|
||||
this.toast('请在小程序中打开商城');
|
||||
@@ -118,6 +138,65 @@
|
||||
if (nameEl && a.nickname) nameEl.textContent = a.nickname;
|
||||
if (avatarEl && a.avatar) avatarEl.src = a.avatar;
|
||||
},
|
||||
/* ⑦ 上报"当前在哪一页"(分享状态同步,不弹 toast、可频繁调用)。
|
||||
为什么需要:web-view 里的 H5 不能自己拉起分享面板,转发卡片由小程序宿主页产出;
|
||||
宿主只有 onShareAppMessage(options).webViewUrl 能拿到当前地址,而
|
||||
onShareTimeline(朋友圈)**没有回调参数**;首页壳又不会随 H5 换页重新 onLoad。
|
||||
所以应用在「页面/路由切换」时上报一次 location,宿主即可刷新分享图/标题/深链。
|
||||
协议:{action:'location', href, title?, summary?, imageUrl?} → 详见 docs/h5-auth-standard.md 第四节
|
||||
opts.imageUrl 给了就以 H5 为准(仅当前应用);不给则用 box_app 后台配置的分享图。 */
|
||||
reportLocation: function (opts) {
|
||||
opts = opts || {};
|
||||
if (!(window.wx && window.wx.miniProgram && window.wx.miniProgram.postMessage)) return false;
|
||||
try {
|
||||
window.wx.miniProgram.postMessage({
|
||||
data: {
|
||||
action: 'location',
|
||||
href: opts.href || location.href, // 可传 href:用于"即将跳转到的地址"上报
|
||||
title: opts.title || '',
|
||||
summary: opts.summary || '',
|
||||
imageUrl: opts.imageUrl || ''
|
||||
}
|
||||
});
|
||||
return true;
|
||||
} catch (e) {
|
||||
try { console.warn('[wxAuth] reportLocation fail:', e); } catch (e2) {}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
/* ⑧ 自动监听页面切换并上报(首屏一次 + hashchange/popstate + pushState/replaceState)。
|
||||
用法(推荐在 init 回调里调用):
|
||||
wxAuth.watchLocation(function () {
|
||||
return { title: document.title }; // 可选:本页分享标题/图
|
||||
});
|
||||
同一 href 只会发一次(内部去重),SPA 与多页应用都适用。 */
|
||||
watchLocation: function (getShare) {
|
||||
var self = this;
|
||||
var last = '';
|
||||
function pull() {
|
||||
if (location.href === last) return;
|
||||
last = location.href;
|
||||
var s = (typeof getShare === 'function') ? (getShare() || {}) : {};
|
||||
self.reportLocation(s);
|
||||
}
|
||||
pull(); // 首屏
|
||||
if (g.addEventListener) {
|
||||
g.addEventListener('hashchange', pull);
|
||||
g.addEventListener('popstate', pull);
|
||||
}
|
||||
/* history.pushState/replaceState 不触发上面两个事件,需要包一层 */
|
||||
['pushState', 'replaceState'].forEach(function (fn) {
|
||||
var orig = g.history && g.history[fn];
|
||||
if (typeof orig !== 'function') return;
|
||||
g.history[fn] = function () {
|
||||
var r = orig.apply(this, arguments);
|
||||
setTimeout(pull, 0);
|
||||
return r;
|
||||
};
|
||||
});
|
||||
return self;
|
||||
},
|
||||
|
||||
toast: function (m) {
|
||||
var t = document.getElementById('toast');
|
||||
if (!t) return;
|
||||
|
||||
@@ -2469,9 +2469,15 @@ a.skip:focus{left:16px;top:16px}
|
||||
.t-ico.ic-home{-webkit-mask-image:url(assets/img/1afd85e578dd.png);mask-image:url(assets/img/1afd85e578dd.png)}
|
||||
.t-ico.ic-archive{-webkit-mask-image:url(assets/img/fa7b793b47e8.png);mask-image:url(assets/img/fa7b793b47e8.png)}
|
||||
.t-ico.ic-letter{-webkit-mask-image:url(assets/img/949338312a1f.png);mask-image:url(assets/img/949338312a1f.png)}
|
||||
/* 「兜爸心选」商城 tab 的购物袋图标(第九批新增,占原「宝宝来信」那枚 tab 的坑位)。
|
||||
实心剪影风格:袋身圆角矩形 + 提手粗环,与另外四枚 mask 图标同规格(30×30 RGBA)。
|
||||
源图 assets/img/b3253e3c7a83.png。
|
||||
⚠️ 上面 .ic-letter 的规则与 949338312a1f.png **保留不删**:来信屏还在(swipe 可进),
|
||||
哪天要把 tab 挂回「宝宝来信」,把 index.html 那枚 span 的 class 换回去即可。 */
|
||||
.t-ico.ic-shop{-webkit-mask-image:url(assets/img/b3253e3c7a83.png);mask-image:url(assets/img/b3253e3c7a83.png)}
|
||||
.t-ico.ic-me{-webkit-mask-image:url(assets/img/0ebc7631fea4.png);mask-image:url(assets/img/0ebc7631fea4.png)}
|
||||
.tab.is-active .t-ico{transform:translateY(-2px) scale(1.06)}
|
||||
/* nowrap:最长的那条是「宝宝来信」,四个汉字 12.5px ≈ 50px,
|
||||
/* nowrap:最长的那条是「兜爸心选」(原「宝宝来信」,同为四个汉字),12.5px ≈ 50px,
|
||||
320px 视口下每格 tab ≈ 64px,塞得下。但字号一旦被系统放大就会折行,
|
||||
而 tab 是固定高度的,折了会把图标顶出去,所以宁可让它溢出也不折。 */
|
||||
.t-txt{font-size:12.5px;font-weight:600;line-height:1.1;letter-spacing:.2px;white-space:nowrap}
|
||||
|
||||
Reference in New Issue
Block a user