兜豆兑换入口接入:跳 doudou-duihuan(带 openid/return_url)、余额与可兑件数、本场热门好物;配色改用商城 berry
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
86
js/app.js
86
js/app.js
@@ -3,7 +3,7 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
/* 页面版本号(YYMMDD+序号):显示在「关于兜爸心选」页底部;bump 时同步 head 注释与 ?v= */
|
||||
var VER = '26100136';
|
||||
var VER = '26100137';
|
||||
const $ = (s, c) => (c || document).querySelector(s);
|
||||
const $$ = (s, c) => Array.from((c || document).querySelectorAll(s));
|
||||
|
||||
@@ -4144,24 +4144,88 @@
|
||||
}
|
||||
}
|
||||
/* ---------- 兜豆兑换商城入口(2026-10-01) ----------
|
||||
两个入口:「我的」页金色主卡 #meExchCard、首页婴儿房下面那条 #homeExch。
|
||||
链接优先取应用后台(APP_BY_ID,identifier 按候选名逐个找),走 jumpApp()
|
||||
—— 与其它 H5 应用同一条路(带 openid/unionid)。后台还没配、兜底地址也空时提示,
|
||||
不静默。⚠️ EXCH_FALLBACK_URL 待兑换商城侧给出正式地址后填上。 */
|
||||
const EXCH_IDS = ['duihuan', 'exchange', 'doudou', 'duihuanshangcheng'];
|
||||
const EXCH_FALLBACK_URL = '';
|
||||
两个入口:「我的」页兜豆卡 #meExchCard、首页婴儿房下面那条 #homeExch。
|
||||
地址/接口由「兜爸商城」侧提供(2026-10-01):正式与预览同一个 URL,后端切生产时 URL 不变。
|
||||
· 跳转走 jumpApp()(query 带 openid/unionid),另带 return_url —— 商城左上角出返回按钮。
|
||||
· 应用后台若配了同名应用(EXCH_IDS 里任一 identifier),以后台 URL 为准。 */
|
||||
const EXCH_IDS = ['doudou-duihuan', 'doudouduihuan', 'duihuan'];
|
||||
const EXCH_URL = 'https://taidong.douba.top/doudou-duihuan/';
|
||||
const DOU_API = EXCH_URL + 'api';
|
||||
function openExchange() {
|
||||
haptic();
|
||||
let app = null;
|
||||
for (const id of EXCH_IDS) { if (APP_BY_ID[id]) { app = APP_BY_ID[id]; break; } }
|
||||
const url = (app && app.url) || EXCH_FALLBACK_URL;
|
||||
if (!url) { toast('兜豆兑换商城即将开放,先攒着兜豆吧'); return; }
|
||||
jumpApp(url, (app && app.identifier) || 'duihuan');
|
||||
const base = (app && app.url) || EXCH_URL;
|
||||
const url = base + (base.indexOf('?') >= 0 ? '&' : '?') + 'return_url=' + encodeURIComponent(location.href);
|
||||
jumpApp(url, (app && app.identifier) || 'doudou-duihuan');
|
||||
}
|
||||
$$('#meExchCard, #homeExch').forEach(function (b) {
|
||||
b.addEventListener('click', openExchange);
|
||||
});
|
||||
|
||||
/* 兜豆余额 + 可兑件数 + 本场热门好物。
|
||||
· /mall/drop 无需登录:拿商品(热门前 3 显示在「我的」页卡片底部);
|
||||
· 有 openid 时 /auth/openid-login 换 token → /dou/summary 拿 balance;
|
||||
· 可兑 M 件 = stock>0 且 price<=balance 且(opens_at 为空或已到点),口径与商城侧约定一致。
|
||||
任何一步失败都静默保留默认文案「攒兜豆,好物免费兑」,不影响页面其它部分。
|
||||
从商城返回(页面重新可见)时再刷一次,兑换后余额能跟上。 */
|
||||
let douToken = '';
|
||||
function setExchSub(t) {
|
||||
$$('#meExchSub, #homeExchSub').forEach(function (el) { el.textContent = t; });
|
||||
}
|
||||
function renderDrop(d) {
|
||||
const box = $('#meExchDrop'); if (!box) return;
|
||||
const now = d && d.server_time ? new Date(d.server_time).getTime() : Date.now();
|
||||
const goods = ((d && d.goods) || []).filter(function (g) {
|
||||
return g.stock > 0 && (!g.opens_at || new Date(g.opens_at).getTime() <= now);
|
||||
})
|
||||
.sort(function (x, y) { return (y.heat_30m || 0) - (x.heat_30m || 0); }).slice(0, 3);
|
||||
if (!goods.length) { box.classList.add('hide'); return; }
|
||||
const dr = d.drop || {};
|
||||
$('#meExchDropT').textContent = (dr.title || '本场好物') + (dr.open && dr.left != null ? ' · 剩 ' + dr.left + ' 件' : '');
|
||||
const wrap = $('#meExchGoods'); wrap.textContent = '';
|
||||
goods.forEach(function (g) {
|
||||
const it = document.createElement('span'); it.className = 'bd-it';
|
||||
const im = document.createElement('img'); im.alt = ''; im.loading = 'lazy';
|
||||
im.src = /^https?:/.test(g.img || '') ? g.img : EXCH_URL + String(g.img || '').replace(/^\//, '');
|
||||
const nm = document.createElement('span'); nm.className = 'bd-nm'; nm.textContent = g.name || '';
|
||||
const pr = document.createElement('b'); pr.textContent = g.price + ' 兜豆';
|
||||
it.append(im, nm, pr); wrap.appendChild(it);
|
||||
});
|
||||
box.classList.remove('hide');
|
||||
}
|
||||
function loadDou() {
|
||||
const oid = hashParam('openid'), uid = hashParam('unionid');
|
||||
const dropP = fetch(DOU_API + '/mall/drop').then(function (r) { return r.ok ? r.json() : null; }).catch(function () { return null; });
|
||||
dropP.then(renderDrop);
|
||||
if (!oid) return;
|
||||
const tokP = douToken ? Promise.resolve(douToken) :
|
||||
fetch(DOU_API + '/auth/openid-login', {
|
||||
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ openid: oid, unionid: uid || null, app_id: 'doudou-duihuan' })
|
||||
}).then(function (r) { return r.ok ? r.json() : null; }).then(function (j) { return (douToken = (j && j.token) || ''); });
|
||||
tokP.then(function (tok) {
|
||||
if (!tok) return null;
|
||||
return fetch(DOU_API + '/dou/summary', { headers: { Authorization: 'Bearer ' + tok } })
|
||||
.then(function (r) { if (r.status === 401) douToken = ''; return r.ok ? r.json() : null; });
|
||||
}).then(function (sum) {
|
||||
if (!sum || typeof sum.balance !== 'number') return;
|
||||
return dropP.then(function (d) {
|
||||
const now = d && d.server_time ? new Date(d.server_time).getTime() : Date.now();
|
||||
const n = ((d && d.goods) || []).filter(function (g) {
|
||||
return g.stock > 0 && g.price <= sum.balance && (!g.opens_at || new Date(g.opens_at).getTime() <= now);
|
||||
}).length;
|
||||
/* 0 兜豆时「兜豆 0 · 可兑 0 件」读着像在劝退 —— 保留引导文案;有豆但一件都不够时给句鼓励 */
|
||||
if (!sum.balance) setExchSub('攒兜豆,好物免费兑');
|
||||
else if (!d) setExchSub('兜豆 ' + sum.balance);
|
||||
else setExchSub('兜豆 ' + sum.balance + (n ? ' · 可兑 ' + n + ' 件' : ' · 再攒攒就能兑'));
|
||||
});
|
||||
}).catch(function () {});
|
||||
}
|
||||
loadDou();
|
||||
document.addEventListener('visibilitychange', function () {
|
||||
if (document.visibilityState === 'visible') loadDou();
|
||||
});
|
||||
|
||||
/* 商城入口:「我的」页服务卡与首页商城主卡。
|
||||
⚠️ 2026-09-19:底 tab #tabMall 已经改回「宝宝来信」(见下面的 #tabLetter 绑定),
|
||||
不再走 goMall —— 所以这里只留两颗真正的商城入口。 */
|
||||
|
||||
Reference in New Issue
Block a user