From d0fcc1e98827221bdef132515d5d3a87e1a1256d Mon Sep 17 00:00:00 2001 From: Karlcarlo Date: Wed, 23 Sep 2026 03:36:57 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E4=BB=8A=E6=97=A5=E8=84=9A=E5=8D=B0):=20?= =?UTF-8?q?=E5=88=A4=E6=8D=AE=E6=94=B9=E7=94=A8=20used=20=E2=80=94?= =?UTF-8?q?=E2=80=94=20=E3=80=8C=E7=94=A8=E8=BF=87=E4=BD=86=E6=B2=A1?= =?UTF-8?q?=E7=95=99=E4=B8=8B=E8=AE=B0=E5=BD=95=E3=80=8D=E4=B8=8D=E5=86=8D?= =?UTF-8?q?=E9=94=99=E6=98=BE=E7=A4=BA=E3=80=8C=E8=BF=98=E6=B2=A1=E6=9C=89?= =?UTF-8?q?=E8=84=9A=E5=8D=B0=E3=80=8D(v26092219)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 接口方 2026-09-23 排查回复纠正了我方一处真实口径错误(原话:lead 只在当天 used 为空时才有值; 你们 H5 是用 results 是否为空判断的,建议改用 used 是否为空;used 非空但没 results 时显示应用名列表即可)。 我方原来的逻辑:`events.length ? rows : guide` —— events 来自 results,于是「今天用过应用但没留下记录」 的日子会走引导,页面上就出现「还没有脚印」与气泡里那句「今天用了 1 个工具,还没有留下具体记录。」 自相矛盾(用户截图里正是这个现象)。 改动: - 分支判据改为 `used`:used 空 → 引导(含上游查无此人);used 非空 → 时间轴。 - 时间轴补「用过但没留下记录」的应用行:按 first_at(收口成北京 HH:MM 的 used[].at)出一行 「13:37 孕检日历」,与真实记录行按时间合并排序、最多 8 行。 - 引导芯片改用上游带回的 `url`(2026-09-23 起它只推我们已上架的应用、并带 url, 接口方原话「有 url 就直接跳,不用再对 App 表」);App 表只作兜底,identifier 仍用于 last_app 上报。 本地验证(桩后端五种返回):rows→事件行;**usedonly→应用行 09:10 数胎动 / 13:37 孕检日历,且不再出现引导**; guide→上游 lead + 可点芯片;degraded / 接口 500→整块不显示。无 JS 异常。 --- index.html | 2 +- js/app.js | 40 +++++++++++++++++++++++++++++++--------- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/index.html b/index.html index 6c57e39..8fc0f40 100644 --- a/index.html +++ b/index.html @@ -7,7 +7,7 @@ 兜爸心选 · 孕育陪伴 - + diff --git a/js/app.js b/js/app.js index 411ee28..5c7e26f 100644 --- a/js/app.js +++ b/js/app.js @@ -3,7 +3,7 @@ (function () { 'use strict'; /* 页面版本号(YYMMDD+序号):显示在「关于兜爸心选」页底部;bump 时同步 head 注释与 ?v= */ - var VER = '26092218'; + var VER = '26092219'; const $ = (s, c) => (c || document).querySelector(s); const $$ = (s, c) => Array.from((c || document).querySelectorAll(s)); @@ -3108,7 +3108,8 @@ /* 今日脚印(2026-09-23,B 方案:数据全部来自 box_app 的 /footprint/today, 它的上游是数胎动平台的**用户面**接口 /user/daily/footprint): rows 拿到事件 → 时间轴;AI 气泡用接口给的 digest.text(**真文案**) - guide 今天没有任何活动 / 上游查无此人 → 引导占位:文案用接口的 lead、应用用 unused[], + guide 今天**一次都没用过**(used 为空)/ 上游查无此人 → 引导占位:文案用接口的 lead、 + 应用用 unused[](上游已按我们上架清单过滤,且带回 url), 对得上 App 表的还能直接点进该应用 hide 接口读不到(网络 / 非 200 / 上游故障且无旧值)→ **整块不显示** ⚠️ AI 气泡不再挂写死的那句「今天你数到我动了 3 次」:文案一律取 digest.text,取不到就收起气泡 @@ -3135,7 +3136,23 @@ steps.style.display = ''; steps.innerHTML = ''; if (mode === 'pending') { steps.append(pendingFootprintStep()); return; } - (r.events || []).forEach(e => steps.append(buildFootprintStep(e))); + /* ⚠️ 上游口径(2026-09-23 接口方确认):`used` = 当天**用过**(有页面访问或有业务结果), + `results` 只是其中的**业务记录**。所以「用过但没留下记录」的日子 `used` 非空、`results` 为空 —— + 这种日子要显示**应用名列表**,不能走「还没有脚印」引导(否则会和气泡里那句 + 「今天用了 N 个工具,还没有留下具体记录。」自相矛盾,用户截图里就是这个现象)。 + 两类行按 HH:MM 合并排序:有记录的行来自 events,没记录的应用按 first_at 出一行。 */ + const rows = (r.events || []).map(e => ({ at: e.at || '', label: e.label || '', detail: e.detail || '', app: e.app || '' })); + const withEvents = new Set((r.events || []).map(e => e.appId).filter(Boolean)); + (r.used || []).filter(u => u.appId && !withEvents.has(u.appId)).forEach(u => { + rows.push({ + at: u.at || '', + label: u.appName || '', + detail: u.views > 1 ? '浏览 ' + u.views + ' 次' : '', + app: '', + }); + }); + rows.sort((a, b) => String(a.at).localeCompare(String(b.at))); + rows.slice(-8).forEach(row => steps.append(buildFootprintStep(row))); } /* 引导占位:文案与应用都来自上游 —— lead 是上游自己的引导语,unused[] 是今天没用过的应用。 @@ -3148,12 +3165,16 @@ ((r && r.unused) || []).slice(0, 5).forEach(u => { const ident = u.identifier || ''; const app = ident ? APP_BY_ID[ident] : null; - if (app && app.url) { + /* ⚠️ 优先用上游带回的 `url`(2026-09-23 起它只推**我们已上架**的应用并把正式 url 带回来, + 接口方原话「有 url 就直接跳,不用再对 App 表」);App 表只作兜底。 + identifier 仍用于 jumpApp 的 last_app 上报(服务端会校验 url 对得上在架应用)。 */ + const href = u.url || (app && app.url) || ''; + if (href) { const b = document.createElement('button'); b.type = 'button'; b.className = 'tl-chip ripple'; b.textContent = u.appName || app.name || ident; - b.addEventListener('click', () => jumpApp(app.url, app.identifier)); + b.addEventListener('click', () => jumpApp(href, (app && app.identifier) || ident || '')); box.appendChild(b); } else if (u.appName) { const sp = document.createElement('span'); @@ -3195,10 +3216,11 @@ const r = (j && j.code === 200 && j.result) ? j.result : null; if (!r) { fpApply('hide'); return; } // 读不到 → 不显示(不再编数据) if (r.degraded) { fpApply('hide'); return; } // 上游故障且无旧值 → 不显示 - const events = (r.events || []).slice(-8); // 升序取最近 8 条 - /* 有事件 → 时间轴;一条都没有(上游查无此人 linked=false、今天 kind=fallback 没活动、 - 或只浏览没产出记录)→ 统一走引导:文案与应用名都由接口给,不再自己编。 */ - if (events.length) { fpApply('rows', r); return; } + /* 判据是 `used`(当天用没用过),**不是** `results`(有没有留下记录)—— + 接口方 2026-09-23 明确:lead 只在 used 为空时才有值;used 非空但没 results 时应显示应用名列表。 + 所以:used 空 → 引导(上游查无此人 linked=false 时也是这个分支); + used 非空 → 时间轴(里面自带"用过但没记录"的行,见 fpRender)。 */ + if ((r.used || []).length) { fpApply('rows', r); return; } fpApply('guide', r); }) .catch(function () { fpApply('hide'); }); // 读不到 → 不显示