兜豆兑换入口接入:跳 doudou-duihuan(带 openid/return_url)、余额与可兑件数、本场热门好物;配色改用商城 berry

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-01 16:00:10 +00:00
parent f1ab738865
commit 96b04877de
3 changed files with 126 additions and 59 deletions

View File

@@ -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 —— 所以这里只留两颗真正的商城入口。 */