138 lines
7.5 KiB
JavaScript
138 lines
7.5 KiB
JavaScript
/* 兜爸心选 · 页面访问记录(2026-11-07)
|
||
推送效果看板要看「推送打开后用户看了哪些页面」,用户同意做。后端 box_app:POST /api/mp/public/mama-box/pv(公开上报),
|
||
看板走 POST /api/mp/public/mama-box/pageviews/query(X-Api-Key)。说明见 box_app services/mama_box_pageview_serv.py。
|
||
|
||
一次「看一页」= 一个 visitId:进来 0.8 秒后报一条(停留 0),之后每 15 秒、切到后台、离开时报一次停留时长(只算页面在前台的时间)。
|
||
同一页里换内容也算新的一页:广场切笔记 / 话题 / 分类(pushState)、首页开关星空页(replaceState ?wh=1)—— 这里接管 history 自动识别,页面不用改。
|
||
首页 + 孕妈广场 + 测一测 + 专题页 / 计算器都引本文件(和 js/last-sub.js 放一起);新子页面记得加 script。
|
||
预览站 / 正式站由后端按路径分(/mama-box-preview/ → preview),这里不管。 */
|
||
(function () {
|
||
'use strict';
|
||
if (window.__mbPV) return;
|
||
window.__mbPV = 1;
|
||
|
||
var API = '/api/mp/public/mama-box/pv';
|
||
var BEAT = 15000;
|
||
var CAT_NAME = { family: '家庭婚姻', work: '职场方向', baby: '孕育经验' };
|
||
|
||
function param(k) {
|
||
var m = ((location.hash || '') + '&' + (location.search || '')).match(new RegExp('[#?&]' + k + '=([^&]*)'));
|
||
try { return m ? decodeURIComponent(m[1]).split('?')[0] : ''; } catch (e) { return ''; }
|
||
}
|
||
function who() {
|
||
if (window.mbGate && window.mbGate.out) return { openid: '', unionid: '' }; /* 11-07 退出登录 = 访客 */
|
||
var o = param('openid'), u = param('unionid');
|
||
if (!o) {
|
||
try {
|
||
var c = JSON.parse(sessionStorage.getItem('mmbox.identity') || 'null');
|
||
if (c && c.openid && (!c.at || Date.now() - c.at < 432e5)) { o = c.openid; u = u || c.unionid || ''; }
|
||
} catch (e) {}
|
||
}
|
||
return { openid: o, unionid: u };
|
||
}
|
||
|
||
/* 当前地址 → 是哪一页。base = 站点根(/mama-box-v2/ 或 /mama-box-preview/),rel = 之后的部分 */
|
||
function where() {
|
||
var p = location.pathname.replace(/index\.html$/, '');
|
||
var m = p.match(/^(\/[^/]+\/)(.*)$/) || [0, '/', ''];
|
||
var rel = m[2], q = new URLSearchParams(location.search), r = { group: 'other', page: rel || 'home', title: document.title || '' };
|
||
var T = function (v) { return String(v || '').replace(/\s*·\s*(测一测|孕妈广场)$/, ''); };
|
||
if (!rel) {
|
||
if (q.get('wh') === '1') { r.group = 'whisper'; r.page = 'whisper'; r.title = '孕妈悄悄话·星空页'; }
|
||
else { r.group = 'home'; r.page = 'home'; r.title = '妈妈盒子首页'; }
|
||
} else if (rel === 'guangchang/ceshi/') {
|
||
var id = q.get('id') || '', t = (window.GC_TESTS || []).filter(function (x) { return x.id === id; })[0];
|
||
r.group = 'ceshi'; r.page = id ? 'ceshi/test' : 'ceshi/list'; r.testId = id;
|
||
r.testTitle = t ? t.title : (id ? T(document.title) : '');
|
||
r.title = id ? '测一测·' + (r.testTitle || id) : '测一测·列表';
|
||
} else if (rel === 'guangchang/mine/') {
|
||
r.group = 'plaza'; r.page = 'plaza/mine'; r.title = '孕妈广场·我的投稿';
|
||
} else if (rel === 'guangchang/') {
|
||
var n = q.get('n') || '', tp = q.get('t') || '', c = q.get('c') || '';
|
||
var tid = tp || (n ? n.replace(/-\d+$/, '') : '');
|
||
var topic = (window.GC_TOPICS || []).filter(function (x) { return x.id === tid; })[0];
|
||
r.group = 'plaza';
|
||
if (tid) { r.topicId = tid; r.topicTitle = topic ? topic.name : ''; }
|
||
if (n) {
|
||
var d = window.GC_DATA && GC_DATA[tid], i = +(n.match(/-(\d+)$/) || [0, 0])[1];
|
||
r.page = 'plaza/note'; r.noteId = n; r.noteTitle = d && d.notes && d.notes[i - 1] ? d.notes[i - 1].title : '';
|
||
r.title = '孕妈广场·笔记详情';
|
||
} else if (tp) { r.page = 'plaza/topic'; r.title = '孕妈广场·话题'; }
|
||
else if (c === 'ceshi') { r.group = 'ceshi'; r.page = 'ceshi/list'; r.title = '测一测·列表'; }
|
||
else if (c) { r.page = 'plaza/cat'; r.title = '孕妈广场·' + (CAT_NAME[c] || c); }
|
||
else if (q.get('write') === '1') { r.page = 'plaza/write'; r.title = '孕妈广场·写笔记'; }
|
||
else if (q.get('fav') === '1') { r.page = 'plaza/fav'; r.title = '孕妈广场·我的收藏'; }
|
||
else if (q.get('mine') === '1') { r.page = 'plaza/mine'; r.title = '孕妈广场·我的投稿'; }
|
||
else { r.page = 'plaza/home'; r.title = '孕妈广场'; }
|
||
} else if (/^topic\/[a-z0-9_-]+\/$/.test(rel)) {
|
||
r.group = 'topic'; r.page = rel.replace(/\/$/, ''); r.title = T(document.title) || r.page;
|
||
}
|
||
r.key = r.page + '|' + (r.noteId || '') + '|' + (r.topicId || '') + '|' + (r.testId || '');
|
||
/* 净地址:不带身份(openid/unionid 在 hash,不记) */
|
||
r.path = location.pathname + (location.search || '').replace(/([?&])(openid|unionid)=[^&]*/g, '$1').replace(/[?&]+$/, '');
|
||
return r;
|
||
}
|
||
|
||
function send(o) {
|
||
var s = JSON.stringify(o);
|
||
try { if (navigator.sendBeacon && navigator.sendBeacon(API, new Blob([s], { type: 'text/plain' }))) return; } catch (e) {}
|
||
try { fetch(API, { method: 'POST', body: s, keepalive: true, headers: { 'Content-Type': 'text/plain' } }).catch(function () {}); } catch (e) {}
|
||
}
|
||
function vid() { return Date.now().toString(36) + Math.random().toString(36).slice(2, 10) + Math.random().toString(36).slice(2, 6); }
|
||
|
||
var cur = null, timer = 0;
|
||
function dur() {
|
||
if (!cur) return 0;
|
||
return cur.acc + (cur.shownAt ? Date.now() - cur.shownAt : 0);
|
||
}
|
||
function beat() {
|
||
if (!cur || !cur.sent) return;
|
||
var d = dur();
|
||
if (d - cur.lastDur < 1000) return;
|
||
cur.lastDur = d;
|
||
var w = who();
|
||
send({ visitId: cur.id, durationMs: d, openid: w.openid, unionid: w.unionid });
|
||
}
|
||
function first(c) {
|
||
if (c !== cur || c.sent) return;
|
||
var r = where(); /* 晚 0.8 秒再取:专题页 / 测试页的标题、广场数据那时才就绪 */
|
||
if (r.key !== c.r.key) r = c.r;
|
||
var w = who();
|
||
c.sent = true;
|
||
send({
|
||
visitId: c.id, openid: w.openid, unionid: w.unionid, page: r.page, pageGroup: r.group, pageTitle: r.title,
|
||
noteId: r.noteId || '', noteTitle: r.noteTitle || '', topicId: r.topicId || '', topicTitle: r.topicTitle || '',
|
||
testId: r.testId || '', testTitle: r.testTitle || '', path: c.r.path, enteredAt: c.at, durationMs: dur()
|
||
});
|
||
}
|
||
function close() {
|
||
if (!cur) return;
|
||
if (cur.sent) beat(); else if (dur() >= 800) first(cur);
|
||
cur = null;
|
||
}
|
||
function open() {
|
||
var r = where();
|
||
if (cur && cur.r.key === r.key) return;
|
||
close();
|
||
var c = cur = { id: vid(), r: r, at: Date.now(), acc: 0, shownAt: document.hidden ? 0 : Date.now(), sent: false, lastDur: 0 };
|
||
setTimeout(function () { first(c); }, 800);
|
||
}
|
||
|
||
['pushState', 'replaceState'].forEach(function (k) {
|
||
var f = history[k];
|
||
if (typeof f !== 'function') return;
|
||
history[k] = function () { var x = f.apply(this, arguments); try { setTimeout(open, 0); } catch (e) {} return x; };
|
||
});
|
||
window.addEventListener('popstate', function () { setTimeout(open, 0); });
|
||
document.addEventListener('visibilitychange', function () {
|
||
if (!cur) return;
|
||
if (document.hidden) { if (cur.shownAt) { cur.acc += Date.now() - cur.shownAt; cur.shownAt = 0; } beat(); }
|
||
else if (!cur.shownAt) cur.shownAt = Date.now();
|
||
});
|
||
window.addEventListener('pagehide', close);
|
||
window.addEventListener('pageshow', function (e) { if (e.persisted) open(); }); /* 从后退缓存回来 = 又看一次 */
|
||
timer = setInterval(function () { if (!document.hidden) beat(); }, BEAT);
|
||
|
||
open();
|
||
})();
|