From 627a819e463af4f521e1f5e0ecd161a139a92b11 Mon Sep 17 00:00:00 2001 From: Karlcarlo Date: Fri, 18 Sep 2026 21:12:49 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BA=95tab=E3=80=8C=E5=85=9C=E7=88=B8?= =?UTF-8?q?=E5=BF=83=E9=80=89=E3=80=8D/=E3=80=8C=E8=BF=9B=E5=85=A5?= =?UTF-8?q?=E5=95=86=E5=9F=8E=E3=80=8D=E8=90=BD=E7=82=B9=E6=94=B9=E5=95=86?= =?UTF-8?q?=E5=9F=8E=E9=A6=96=E9=A1=B5=EF=BC=9A=E5=B0=8F=E7=A8=8B=E5=BA=8F?= =?UTF-8?q?=E5=8E=9F=E8=A3=85=E8=A3=85=E4=BF=AE=E9=A6=96=E9=A1=B5=E5=B7=B2?= =?UTF-8?q?=E6=81=A2=E5=A4=8D=E4=B8=BA=20pages/index/mall=EF=BC=88DIY=20?= =?UTF-8?q?=E5=BA=95=E9=83=A8=E5=AF=BC=E8=88=AA=E7=AC=AC2=E9=A1=B9?= =?UTF-8?q?=EF=BC=89=EF=BC=8CgoMall=20=E6=94=B9=20switchTab=20=E8=AF=A5?= =?UTF-8?q?=E9=A1=B5=E5=B9=B6=E8=A1=A5=20fail=20=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=EF=BC=9B=E9=A6=96=E9=A1=B5=E6=96=B0=E5=A2=9E=E4=BB=8A=E6=97=A5?= =?UTF-8?q?=E8=84=9A=E5=8D=B0=EF=BC=88=E6=95=B0=E8=83=8E=E5=8A=A8=E5=AF=B9?= =?UTF-8?q?=E5=A4=96=20API=EF=BC=8Cbox=5Fapp=20=E5=B0=81=E8=A3=85=EF=BC=8C?= =?UTF-8?q?=E6=8B=89=E4=B8=8D=E5=88=B0=E5=9B=9E=E9=80=80=E5=86=85=E7=BD=AE?= =?UTF-8?q?=EF=BC=89=EF=BC=9B=E7=89=88=E6=9C=AC=20v26091802?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 2 +- js/app.js | 100 +++++++++++++++++++++++++++++++++++++++++++++++++- js/wx-auth.js | 6 ++- 3 files changed, 103 insertions(+), 5 deletions(-) diff --git a/index.html b/index.html index a7d72f0..0646bfa 100644 --- a/index.html +++ b/index.html @@ -7,7 +7,7 @@ 兜爸心选 · 孕育陪伴 - + diff --git a/js/app.js b/js/app.js index 14abf43..13b7ce8 100644 --- a/js/app.js +++ b/js/app.js @@ -3,7 +3,7 @@ (function () { 'use strict'; /* 页面版本号(YYMMDD+序号):显示在「关于兜爸心选」页底部;bump 时同步 head 注释与 ?v= */ - var VER = '26091602'; + var VER = '26091802'; const $ = (s, c) => (c || document).querySelector(s); const $$ = (s, c) => Array.from((c || document).querySelectorAll(s)); @@ -4187,6 +4187,9 @@ applyRemoteAll(); // 第三批远程数据(宝宝来信)—— 同样随 init 一起拉,失败回退内置样例 applyRemoteLetters(); + // 第四批远程数据(今日脚印,来自数胎动)—— 渲染首页 .today-line 时间轴, + // 拉不到/未关联都各有回退,见 applyRemoteFootprint 内的分支说明 + applyRemoteFootprint(); } /* ---------- 远程配置(box_app 后台下发) ---------- 本页托管在 box_app(/mama-box/)时,启动后拉一次运营配置: @@ -4435,10 +4438,93 @@ }).catch(function () { /* 静默回退内置样例 */ }); } + /* ---------- 今日脚印(box_app → 数胎动对外 API,动态获取) ---------- + 首页 .today-line 时间轴原来是纯演示内容(无真实数据源,访客/未完善态整块隐藏), + 现在启动后拉 /footprint/today 动态渲染。后端封装见 box_app 的 FootprintService: + 上游数胎动按 unionid 建档(openid 跨应用互不相干),H5 身份注入惯例带 + openid+unionid,unionid 缺失时后端用映射表兜底,这里只管把参数带上。 + + 各分支(对齐全站「远程数据为准、拉不到回退内置」的惯例): + - linked=false(未关联数胎动 / 上游查无此人)→ 整块隐藏。演示行是假数据, + 这用户在数胎动体系里没有档案,不能留着冒充真足迹。 + - linked=true + events → 重建 .steps 行。textContent 拼装(上游文案直接进 + DOM,杜绝注入);最多 8 条(接口升序,取最近 8 条,更早的让给「查看全部」)。 + - linked=true + 无事件 → 一条占位,别让卡空成一截竖线。 + - 拉取失败 → 什么都不动,保持内置演示行(跟 letters 的回退一致); + 访客态不请求(pregEmpty 分支已整块隐藏,不会露出)。 + ⚠️ 竞态:本函数与 applyRemoteProfile 并行。profile 回来若判 pregEmpty 会 + 隐藏时间轴,所以这里落笔前再看一眼 state.pregEmpty,别把刚藏好的放出来。 */ + var _footprintApplied = false; + function applyRemoteFootprint() { + if (_footprintApplied) return; // init 只跑一次,防重复 fetch + _footprintApplied = true; + const openid = hashParam('openid'); + if (!openid) return; // 访客态: pregEmpty 分支已隐藏,保持 + const qs = ['openid=' + encodeURIComponent(openid)]; + const unionid = hashParam('unionid'); + if (unionid) qs.push('unionid=' + encodeURIComponent(unionid)); + fetch('/api/mp/public/mama-box/footprint/today?' + qs.join('&')) + .then(r => (r.ok ? r.json() : null)) + .then(j => { + if (!j || j.code !== 200 || !j.result) return; // 拉不到 → 回退演示行 + const r = j.result; + const tl = document.querySelector('.today-line'); + const steps = $('#tlSteps'); + if (!tl || !steps) return; + if (!r.linked) { tl.style.display = 'none'; return; } + if (state.pregEmpty) return; // 别把 profile 刚藏好的放出来 + const events = (r.events || []).slice(-8); // 升序取最近 8 条 + steps.innerHTML = ''; + if (!events.length) { steps.append(emptyFootprintStep()); return; } + events.forEach(e => steps.append(buildFootprintStep(e))); + }) + .catch(function () { /* 静默回退演示行 */ }); + } + + /* 一行脚印:与 index.html 演示行同构(时间/圆点/文案/来源)。 + 文案里的数字段加粗对齐演示排版(「数胎动 2 次」), + 全程 createElement+textContent,上游字段再离谱也进不来标签。 */ + function buildFootprintStep(e) { + const d = document.createElement('div'); d.className = 'step'; + const time = document.createElement('span'); time.className = 'st-time'; + time.textContent = e.at || '--:--'; + const dot = document.createElement('span'); dot.className = 'st-dot'; + const txt = document.createElement('span'); txt.className = 'st-txt'; + const m = String(e.label || '').match(/^(.*?)(\d[\d.]*)(.*)$/); + if (m) { + if (m[1]) txt.append(m[1]); + const b = document.createElement('b'); b.textContent = m[2]; txt.append(b); + if (m[3]) txt.append(m[3]); + } else { + txt.textContent = String(e.label || ''); + } + const from = document.createElement('span'); from.className = 'st-from'; + from.textContent = e.app ? '来源 · ' + e.app : ''; + d.append(time, dot, txt, from); + return d; + } + + /* 无足迹占位行:同构的一行,读屏和眼睛都不会把空卡当成坏卡。 */ + function emptyFootprintStep() { + const d = document.createElement('div'); d.className = 'step'; + const time = document.createElement('span'); time.className = 'st-time'; + time.textContent = '今天'; + const dot = document.createElement('span'); dot.className = 'st-dot'; + const txt = document.createElement('span'); txt.className = 'st-txt'; + txt.textContent = '还没有足迹'; + const from = document.createElement('span'); from.className = 'st-from'; + from.textContent = '去逛逛上面的工具吧'; + d.append(time, dot, txt, from); + return d; + } + /* ---------- 进商城(web-view 内跳商城原生页) ---------- 兜爸心选 H5 由小程序 web-view 承载;点「商城」跳回商城原生页。 需微信 JS-SDK 的 wx.miniProgram.switchTab —— tabBar 页必须用 switchTab (详见 docs/mama-box-api-plan.md 2.4)。 + 落点 260918 起改为「商城」tab(/pages/index/mall)=原装 CRMEB 装修首页 + 恢复成的第 5 个 tabBar 页;此前一直落在分类页 /pages/goods_cate/goods_cate + (商品列表),按用户要求改成进商城先看首页。 仅在 web-view 环境生效;浏览器独立打开时 wx.miniProgram 不可用,降级为 toast。 */ function goMall() { haptic(); @@ -4449,7 +4535,17 @@ window.wx.miniProgram.getEnv(function (r) { responded = true; if (r && r.miniprogram) { - window.wx.miniProgram.switchTab({ url: '/pages/goods_cate/goods_cate' }); + /* fail 兜底:宿主小程序若还是旧版(没有「商城」tab /pages/index/mall), + switchTab 会失败且无任何反应 —— 这里给出提示,别让用户点了没动静。 + (发布顺序:先发小程序版再加这个 H5 落点;反过来也不会白屏/死寂) */ + window.wx.miniProgram.switchTab({ + url: '/pages/index/mall', + fail: function (err) { + var m = (err && err.errMsg) || '未知原因'; + toast('打开商城失败:' + m); + try { console.warn('[goMall] switchTab fail:', m); } catch (e) {} + } + }); } else { toast('请在微信小程序中打开商城'); } diff --git a/js/wx-auth.js b/js/wx-auth.js index edd3349..d741d6f 100644 --- a/js/wx-auth.js +++ b/js/wx-auth.js @@ -101,12 +101,14 @@ }, /* ⑤ 跳小程序商城(tabBar 页用 switchTab;非 tabBar 用 navigateTo) */ /* ⑤ 跳商城:环境判定与 requestProfile 同一套 —— 仅小程序 webview 内 switchTab, - UA 非微信/微信内非 webview(或 getEnv 不回调)都提示「请在小程序中打开商城」。 */ + UA 非微信/微信内非 webview(或 getEnv 不回调)都提示「请在小程序中打开商城」。 + 默认落点 260918 起为「商城」tab(/pages/index/mall,原装装修首页恢复页), + 与 app.js 的 goMall() 保持一致;此前是分类页 /pages/goods_cate/goods_cate。 */ goMall: function (url) { var self = this; function go() { window.wx.miniProgram.switchTab({ - url: url || '/pages/goods_cate/goods_cate', + url: url || '/pages/index/mall', fail: function (err) { var m = (err && err.errMsg) || '未知原因'; self.toast('打开商城失败:' + m);