Files
mama-box/js/login-gate.js

140 lines
8.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 退出登录后「只看不写」(2026-11-07 用户定):
· 退出登录 ≠ 从没授权过:后端 user_auths.loggedOut 只在点了「退出登录」时置位,重新授权清掉;
从没授权过的新用户不受影响。
· 本机标记 localStorage mmbox.out.v1 = 退出时的 openid(首屏立刻知道,不等接口);
每次进页面再和服务器(只读接口 auth/status 的 loggedOut,查不到不建记录)对一次,对不上就改标记、重载一次。
· 退出后:首页按访客显示(app.js 里 hashParam 不给 openid);记录、评论、点赞、收藏、投稿、
兑换、改档案这些按钮点了弹「登录后才能使用」,去登录 = 小程序授权页(没有共享库的页面回首页「我的」)。
· 后端同样拦(box_app 返回 401 needLogin),这里只是让用户别白填。
首页 / 孕妈广场 / 专题页共用;按页面挑要拦的按钮(SEL)。 */
(function () {
if (window.mbGate) return;
var KEY = 'mmbox.out.v1', RL = 'mmbox.out.rl';
var me = document.currentScript && document.currentScript.src;
function param(n) {
var m = ((location.hash || '') + '&' + (location.search || '')).match(new RegExp('[#?&]' + n + '=([^&#?]*)'));
return m ? decodeURIComponent(m[1]) : '';
}
/* 11-07(消消乐 80d347e2 实测):maternal-bridge 会把 window.localStorage 换成落库的镜像,标记写进镜像会被同步到服务端 app_states,
刷新首屏又读不到 → 卡在登录态。退出标记只放本机真实存储:本脚本先于 bridge 加载时当场拿住;bridge 已接管时借一个同源隐藏 iframe 的。 */
var LS = (function () {
try {
if (!window.MaternalBridge) return window.localStorage;
var f = document.createElement('iframe');
f.style.display = 'none'; f.setAttribute('aria-hidden', 'true'); f.src = 'about:blank';
(document.body || document.documentElement).appendChild(f);
return f.contentWindow.localStorage;
} catch (e) { try { return window.localStorage; } catch (e2) { return null; } }
})();
var O = param('openid'), out = false;
try { out = !!O && LS.getItem(KEY) === O; } catch (e) {}
var root = document.documentElement;
if (out) root.classList.add('mb-out');
var G = window.mbGate = {
out: out,
openid: O,
set: function (v) {
G.out = !!v;
try { if (v) LS.setItem(KEY, O); else LS.removeItem(KEY); } catch (e) {}
root.classList.toggle('mb-out', !!v);
},
login: function () {
if (window.wxAuth && window.wxAuth.requestProfile) { window.wxAuth.requestProfile(); return; }
/* 广场 / 专题页没引共享授权库:回首页「我的」,那里有「点击登录」 */
var home = me ? new URL('../', me).pathname : '../';
location.href = home + '?go=me' + location.hash;
},
/* 退出状态下拦一次操作:返回 true = 已拦 */
need: function (e) {
if (!G.out) return false;
if (e) { e.preventDefault(); e.stopPropagation(); if (e.stopImmediatePropagation) e.stopImmediatePropagation(); }
prompt();
return true;
}
};
/* 和服务器对一次(在别的应用重新登录过 / 在别处退出过,本机标记会过期) */
if (O) {
fetch('/api/mp/public/auth/status?openid=' + encodeURIComponent(O)) /* 只读,查不到不建记录 */
.then(function (r) { return r.ok ? r.json() : null; })
.then(function (j) {
if (!j || j.code !== 200 || !j.result) return;
var lo = !!j.result.loggedOut;
if (lo === G.out) return;
G.set(lo);
/* 防循环:10 秒内只重载一次 */
var last = 0; try { last = +sessionStorage.getItem(RL) || 0; } catch (e) {}
if (Date.now() - last < 10000) return;
try { sessionStorage.setItem(RL, String(Date.now())); } catch (e) {}
location.reload();
})
.catch(function () {});
}
/* 弹窗:自带样式,夜间模式跟着变 */
var box = null;
function prompt() {
if (!box) {
var st = document.createElement('style');
st.textContent =
'.mbg-m{position:fixed;inset:0;z-index:99999;display:flex;align-items:center;justify-content:center;background:rgba(40,25,30,.42);opacity:0;transition:opacity .18s}' +
'.mbg-m.on{opacity:1}' +
'.mbg-c{width:min(300px,82vw);background:#fff;border-radius:20px;padding:24px 20px 18px;text-align:center;box-shadow:0 18px 50px rgba(60,20,30,.25);font-family:inherit}' +
'.mbg-c h3{margin:0 0 8px;font-size:18px;color:#3B2A2A}' +
'.mbg-c p{margin:0 0 18px;font-size:14px;line-height:1.6;color:#8A7470}' +
'.mbg-b{display:flex;gap:10px}.mbg-b button{flex:1;display:flex;align-items:center;justify-content:center;padding:0;text-align:center;height:42px;border-radius:21px;border:0;font-size:15px;font-weight:600;font-family:inherit}' +
'.mbg-x{background:#F6EEEC;color:#8A7470}.mbg-ok{background:linear-gradient(135deg,#FF8A7A,#F25F6B);color:#fff}' +
'html.night .mbg-c{background:#2D2730}html.night .mbg-c h3{color:#F4EAEF}html.night .mbg-c p{color:#B9A9AF}html.night .mbg-x{background:#3A3239;color:#C9B9BE}';
document.head.appendChild(st);
box = document.createElement('div');
box.className = 'mbg-m';
box.setAttribute('role', 'dialog');
box.setAttribute('aria-modal', 'true');
box.innerHTML = '<div class="mbg-c"><h3>' + (window.MB_GATE_TITLE || '登录后才能使用') + '</h3><p>' + (window.MB_GATE_TEXT || '你已退出登录。登录后就能记录、评论和点赞,之前的孕期资料和记录都还在。') + '</p>' +
'<div class="mbg-b"><button type="button" class="mbg-x">再看看</button><button type="button" class="mbg-ok">去登录</button></div></div>';
box.addEventListener('click', function (e) {
if (e.target.closest('.mbg-ok')) { hide(); G.login(); return; }
if (e.target === box || e.target.closest('.mbg-x')) hide();
});
}
if (!box.parentNode) document.body.appendChild(box);
box.style.display = 'flex';
requestAnimationFrame(function () { box.classList.add('on'); });
}
function hide() { if (!box) return; box.classList.remove('on'); setTimeout(function () { box.style.display = 'none'; }, 180); }
/* 要拦的按钮(各页面的写操作) */
var REC = ['taidong', 'yunqitizhong', 'yun', 'yunqixuetang', 'gongsuopinlv', 'taierguzhong', 'chanjianrili', 'bushui']
.map(function (t) { return '#htGrid .tg[data-tool="' + t + '"]'; }).join(',');
var SEL = {
home: REC + ',#vitals .vt-it,.tab-fab,.fab,.fab-w,#htEdit,.tg-add,#homeExchMod,#meExchCard,#meExchGo,#meExchOrders,#bbBanner,[data-modal="modalProfile"],[data-modal="modalWhisper"],#bfMe,.preg-card,#whSay,[data-hug]',
plaza: '#blk,#bfv,#csend,#cpic,#cemo,#cpOk,[data-like],[data-cl],[data-rk],#cmgo,[data-write],[data-mywrite],#tabRec',
topic: '.tc-lk,.tc-go,.tc-in .pic-b,.tc-in .emo-b'
};
var IN = { plaza: '#cin', topic: '.tc-in textarea' };
function page() {
if (document.getElementById('homeBody')) return 'home';
if (document.getElementById('wf')) return 'plaza';
if (/\/topic\//.test(location.pathname)) return 'topic';
return 'other';
}
/* 其他应用(数胎动、体重……)引本文件时自己指定:
window.MB_GATE_SEL = '.save-btn,.add-record'; 点了要拦的按钮(CSS 选择器)
window.MB_GATE_IN = '.note-input'; 一聚焦就提示的输入框
window.MB_GATE_TEXT = '登录后就能兑换好物…'; 弹窗正文(可选,标题用 MB_GATE_TITLE)
或在自己的提交函数里:if (window.mbGate && mbGate.need()) return; */
function selFor(map, cus) { return window[cus] || map[page()] || ''; }
document.addEventListener('click', function (e) {
if (!G.out || !e.target.closest) return;
var s = selFor(SEL, 'MB_GATE_SEL');
if (s && e.target.closest(s)) G.need(e);
}, true);
/* 评论输入框:一点进去就提示(别让人打完一段字才发现发不出去) */
document.addEventListener('focusin', function (e) {
if (!G.out || !e.target.matches) return;
var s = selFor(IN, 'MB_GATE_IN');
if (s && e.target.matches(s)) { e.target.blur(); prompt(); }
}, true);
})();