feat: 微信审核适配 — 移除提现/分销页面 + 分享图片预取 + 登录链路修复
- pages.json 移除 14 个提现/分销页面注册(user_cash/user_spread/spreadData/promoter/distributor),文件保留可恢复 - template4.vue 隐藏'立即提现'区块(用户中心可见入口,分销功能已关闭) - record.vue 抽奖记录移除提现收款跳转(改 toast 提示) - web_view 分享图片:太阳码/点击应用时从 box_app 预取 shareImageUrl,H5 postMessage 传图优先 - web_view _fetchOpenidAndLoad 兼容老用户响应(openid 从 userInfo/JWT 兜底解析)并写回缓存 - App.vue 移除 expired=[object Promise] 无意义日志
This commit is contained in:
@@ -1,14 +1,9 @@
|
||||
<template>
|
||||
<view>
|
||||
<!-- 调试浮层(debugMsg 有值时显示,点击关闭) -->
|
||||
<cover-view v-if="false" class="debug-overlay" @click="debugMsg=''">
|
||||
<cover-view class="debug-text">{{ debugMsg }}</cover-view>
|
||||
</cover-view>
|
||||
<web-view v-if="url" class="web-view" :webview-styles="webviewStyles" :src="url"
|
||||
:style="{width: windowW + 'px', height: windowH + 'px'}" @message="handleMessage"></web-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import store from '@/store';
|
||||
import { HTTP_REQUEST_URL, TRUSTED_DOMAINS } from '@/config/app';
|
||||
@@ -58,18 +53,21 @@ function getOpenid() {
|
||||
}
|
||||
|
||||
function getCurrentUser() {
|
||||
const token = store.state.app.token;
|
||||
if (!token) return { openid: '', unionid: '' };
|
||||
// 即使 token 失效/退出登录,也从 store + 缓存中读取 openid/unionid。
|
||||
// 微信匿名标识同小程序内永久稳定,退出后仍需向可信 H5 注入身份。
|
||||
const token = store.state.app.token || '';
|
||||
let openid = getOpenid();
|
||||
let unionid = store.state.app.unionid || '';
|
||||
if (!unionid) { try { unionid = uni.getStorageSync('UNIONID'); } catch (e) {} }
|
||||
if (!unionid) {
|
||||
if ((!openid || !unionid) && token) {
|
||||
try {
|
||||
let parts = token.split('.');
|
||||
if (parts.length === 3) {
|
||||
let payload = parts[1].replace(/-/g, '+').replace(/_/g, '/');
|
||||
while (payload.length % 4 !== 0) payload += '=';
|
||||
unionid = JSON.parse(base64Decode(payload)).unionid || '';
|
||||
const data = JSON.parse(base64Decode(payload));
|
||||
if (!openid) openid = data.openid || '';
|
||||
if (!unionid) unionid = data.unionid || '';
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
@@ -100,24 +98,18 @@ export default {
|
||||
shareTitle: '',
|
||||
shareSummary: '',
|
||||
shareImageUrl: '',
|
||||
shareTimelineImage: '',
|
||||
shareHref: '',
|
||||
debugMsg: '',
|
||||
savedUrl: ''
|
||||
savedUrl: '',
|
||||
_shareFetched: false
|
||||
}
|
||||
},
|
||||
onLoad(option) {
|
||||
console.log('========== [DEBUG 太阳码] onLoad 触发 ==========');
|
||||
console.log('[DEBUG 太阳码] option 完整:', JSON.stringify(option));
|
||||
console.log('[DEBUG 太阳码] option.scene:', option.scene);
|
||||
console.log('[DEBUG 太阳码] option.url:', option.url);
|
||||
// 显示在页面
|
||||
// 太阳码 scene 解析:scene="app=<identifier>" 时调 box_app 查 url
|
||||
// 例如 box_app /api/wxacode?app=pregnancy → scene="app=pregnancy"
|
||||
// CRMEB 收到后查 box_app /api/mp/apps?isPublished=1 找 url,跳对应 H5
|
||||
console.log('[DEBUG 太阳码] 执行 scene 检查...');
|
||||
const sceneRaw = decodeURIComponent(option.scene || option.wxscene || '');
|
||||
if (sceneRaw.indexOf('app=') === 0) {
|
||||
console.log('[DEBUG 太阳码] ✅ scene 匹配成功! 原始:', option.scene, '解码:', sceneRaw);
|
||||
// scene 格式: "app=pregnancy" 或 "app=pregnancy&ch=YFMM"
|
||||
const source = sceneRaw;
|
||||
const identifier = source.slice(4).split('&')[0];
|
||||
@@ -139,29 +131,28 @@ export default {
|
||||
// 登录返回后:页面仍在栈中,onLoad 不会再次触发
|
||||
// 1) 首次登录返回(savedUrl 有值,url 未设置)→ 用保存的 URL 重新处理身份
|
||||
// 2) H5 内 requireAuth 跳登录页返回 → url 已有值,但 token/身份可能刚更新 → 强制刷新注入新身份
|
||||
if (this.savedUrl && store.state.app.token && !this.url) {
|
||||
console.log('[auth-flow] 🔄 onShow: 首次登录返回,重新处理 URL:', this.savedUrl.substring(0, 80));
|
||||
// 3) 退出登录后再次进入 web_view(url 已存在)→ 用缓存的 openid 重新注入
|
||||
const { openid, unionid } = getCurrentUser();
|
||||
if (this.savedUrl && !this.url) {
|
||||
console.log('[auth-flow] 🔄 onShow: savedUrl 重新处理 → openid=' + (openid || '(空)'));
|
||||
const targetUrl = this.savedUrl;
|
||||
const { openid, unionid } = getCurrentUser();
|
||||
const urlOpenid = getUrlParam(targetUrl, 'openid');
|
||||
console.log('[auth-flow] onShow 身份: openid=' + (openid || '(空)') + ', unionid=' + (unionid || '(空)'));
|
||||
if (openid) {
|
||||
this._applyIdentity(targetUrl, openid, unionid, urlOpenid);
|
||||
} else {
|
||||
console.warn('[auth-flow] ⚠️ onShow: 仍无 openid,加载原始URL');
|
||||
this._finalizeUrl(targetUrl);
|
||||
}
|
||||
} else if (this.url && store.state.app.token) {
|
||||
// H5 授权登录返回:重新注入最新身份(openid 可能刚获取到)
|
||||
const { openid, unionid } = getCurrentUser();
|
||||
} else if (this.url && openid) {
|
||||
// H5 授权登录返回 / 退出后回到 web_view:重新注入最新身份
|
||||
const currentUrl = this.url;
|
||||
const urlOpenid = getUrlParam(currentUrl, 'openid');
|
||||
console.log('[auth-flow] 🔄 onShow: H5 授权返回检测 → openid=' + (openid || '(空)') + ', urlOpenid=' + (urlOpenid || '(无)'));
|
||||
if (openid && urlOpenid !== openid) {
|
||||
console.log('[auth-flow] 🔄 onShow: 身份变更检测 → openid=' + openid + ', urlOpenid=' + (urlOpenid || '(无)'));
|
||||
if (urlOpenid !== openid) {
|
||||
console.log('[auth-flow] ✅ 授权返回,刷新身份 openid=', openid, ', unionid=', unionid || '(空)');
|
||||
this._applyIdentity(currentUrl, openid, unionid, urlOpenid);
|
||||
} else {
|
||||
console.log('[auth-flow] onShow: 身份一致或仍无 openid,不刷新');
|
||||
console.log('[auth-flow] onShow: 身份一致,不刷新');
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -180,9 +171,15 @@ export default {
|
||||
console.log('[web_view] 太阳码 scene 解析响应:', JSON.stringify(res.statusCode));
|
||||
const items = res.data && res.data.result && res.data.result.items;
|
||||
if (res.statusCode === 200 && items && items.length > 0) {
|
||||
const app = items.find(it => it.identifier === identifier) || items[0];
|
||||
// identifier 严格匹配,避免误用其他应用的 URL / 分享图(张冠李戴)
|
||||
const app = items.find(it => it.identifier === identifier);
|
||||
if (app && app.url) {
|
||||
const appUrl = app.url;
|
||||
// 预取分享图片(转发给好友时用作分享卡片图)
|
||||
if (app.shareImageUrl) {
|
||||
this._applyShareImage(app.shareImageUrl);
|
||||
console.log('[web_view] 分享图片: ' + app.shareImageUrl);
|
||||
}
|
||||
let finalUrl = appUrl;
|
||||
if (option._channel) {
|
||||
const separator = finalUrl.includes('?') ? '&' : '?';
|
||||
@@ -191,7 +188,7 @@ export default {
|
||||
console.log('[web_view] 解析到 H5 url:', appUrl, option._channel ? ' ch=' + option._channel : '');
|
||||
option.url = encodeURIComponent(finalUrl);
|
||||
} else {
|
||||
console.warn('[DEBUG 太阳码] 降级到 CRMEB 首页');
|
||||
console.warn('[web_view] 太阳码 scene 解析: 未找到对应 app,降级到 CRMEB 首页');
|
||||
option.url = encodeURIComponent('https://shop.douba.top');
|
||||
}
|
||||
} else {
|
||||
@@ -213,84 +210,50 @@ export default {
|
||||
let targetUrl = decodeURIComponent(option.url);
|
||||
console.log('[web_view] 原始URL:', targetUrl);
|
||||
|
||||
console.log('[DEBUG 太阳码] 检查可信域...');
|
||||
console.log('[DEBUG 太阳码] targetUrl:', targetUrl);
|
||||
console.log('[DEBUG 太阳码] HTTP_REQUEST_URL:', HTTP_REQUEST_URL);
|
||||
const isTrustedDomain = targetUrl.indexOf(HTTP_REQUEST_URL) === 0 ||
|
||||
(TRUSTED_DOMAINS || []).some(d => targetUrl.indexOf(d) === 0);
|
||||
|
||||
console.log('[DEBUG 太阳码] 可信域:', isTrustedDomain);
|
||||
if (isTrustedDomain) {
|
||||
const token = store.state.app.token;
|
||||
console.log('[auth-flow] ===== 进入 H5 跳转流程 =====');
|
||||
console.log('[auth-flow] 入口: 太阳码/点击应用');
|
||||
console.log('[auth-flow] token:', token ? '有' : '无');
|
||||
console.log('[auth-flow] store openid:', store.state.app.openid || '(空)', ', unionid:', store.state.app.unionid || '(空)');
|
||||
if (token) {
|
||||
let { openid, unionid } = getCurrentUser();
|
||||
const { openid, unionid } = getCurrentUser();
|
||||
if (openid) {
|
||||
const urlOpenid = getUrlParam(targetUrl, 'openid');
|
||||
console.log('[auth-flow] 静默身份: openid=' + (openid || '(空)') + ', unionid=' + (unionid || '(空)'));
|
||||
console.log('[auth-flow] URL 已有 openid:', urlOpenid || '(无)');
|
||||
|
||||
// 收集调试信息
|
||||
let info = '[debug] token=' + (token ? '有' : '无') +
|
||||
', myOpenid=' + (openid || '(空)') +
|
||||
', urlOpenid=' + (urlOpenid || '(空)') +
|
||||
', url=' + targetUrl.substring(0, 80);
|
||||
if (openid && urlOpenid && urlOpenid !== openid) this.debugMsg += '→ 身份不一致,将替换';
|
||||
|
||||
if (!openid) {
|
||||
// 获取不到身份信息,用 setTimeout 重试
|
||||
console.warn('[auth-flow] ⚠️ 有 token 但 openid 为空,500ms 后重试', info);
|
||||
setTimeout(() => {
|
||||
try {
|
||||
const retry = getCurrentUser();
|
||||
console.log('[auth-flow] 重试后 openid=' + (retry.openid || '(空)') + ', unionid=' + (retry.unionid || '(空)'));
|
||||
if (retry.openid) {
|
||||
console.log('[auth-flow] ✅ 重试成功,注入身份并跳转');
|
||||
this._applyIdentity(targetUrl, retry.openid, retry.unionid, urlOpenid);
|
||||
} else {
|
||||
console.warn('[auth-flow] ⚠️ 重试仍无 openid,匿名加载 H5(unionid 无法携带)');
|
||||
this.url = targetUrl;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[auth-flow] 重试异常,匿名加载:', e);
|
||||
this.url = targetUrl;
|
||||
}
|
||||
}, 500);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('[auth-flow] ✅ 有 openid,注入身份跳转(unionid ' + (unionid ? '已携带' : '为空,可接受') + ')');
|
||||
this._applyIdentity(targetUrl, openid, unionid, urlOpenid);
|
||||
return; // _applyIdentity 内部已调用 _finalizeUrl,避免163重复覆盖
|
||||
} else {
|
||||
// 无 token:可能是冷启动竞态(onLaunch 静默授权尚未完成)
|
||||
// 延迟重试等待 token,最多 3 次;仍无则匿名直达(不弹授权)
|
||||
let retryCount = 0;
|
||||
const maxRetry = 3;
|
||||
const tryLoad = () => {
|
||||
const t2 = store.state.app.token;
|
||||
console.log('[auth-flow] ⏳ 无 token,第 ' + (retryCount + 1) + ' 次等待静默授权...');
|
||||
if (t2) {
|
||||
let { openid, unionid } = getCurrentUser();
|
||||
console.log('[auth-flow] ✅ 静默授权完成: token=有, openid=' + (openid || '(空)') + ', unionid=' + (unionid || '(空)'));
|
||||
if (openid) {
|
||||
this._applyIdentity(targetUrl, openid, unionid, getUrlParam(targetUrl, 'openid'));
|
||||
return;
|
||||
return; // _applyIdentity 内部已调用 _finalizeUrl
|
||||
}
|
||||
if (token) {
|
||||
// 有 token 但 openid 仍空(极少见:JWT 不含 openid 字段):500ms 重试一次
|
||||
console.warn('[auth-flow] ⚠️ 有 token 但 openid 为空,500ms 后重试');
|
||||
setTimeout(() => {
|
||||
try {
|
||||
const retry = getCurrentUser();
|
||||
if (retry.openid) {
|
||||
console.log('[auth-flow] ✅ 重试成功,注入身份并跳转');
|
||||
this._applyIdentity(targetUrl, retry.openid, retry.unionid, getUrlParam(targetUrl, 'openid'));
|
||||
} else {
|
||||
console.warn('[auth-flow] ⚠️ 重试仍无 openid,匿名加载 H5');
|
||||
this._finalizeUrl(targetUrl);
|
||||
}
|
||||
}
|
||||
retryCount++;
|
||||
if (retryCount < maxRetry) {
|
||||
setTimeout(tryLoad, 800);
|
||||
} else {
|
||||
console.warn('[auth-flow] ⚠️ 等待 ' + maxRetry + ' 次仍无 token,匿名直达 H5(按需授权由 H5 requireAuth 触发)');
|
||||
} catch (e) {
|
||||
console.error('[auth-flow] 重试异常,匿名加载:', e);
|
||||
this._finalizeUrl(targetUrl);
|
||||
}
|
||||
};
|
||||
tryLoad();
|
||||
}, 500);
|
||||
return;
|
||||
}
|
||||
// 无 token + 无 openid(新用户 / 退出后 / 静默授权失败 / 冷启动竞态兜底超时):
|
||||
// 主动用 wx.login 拿 code 调 CRMEB silenceAuthNoLogin(v2/wechat/silence_auth)
|
||||
// 拿到 openid 后注入 URL,让 H5 端完成 openid-login 建档
|
||||
// 该端点不查 store_user_mobile,新用户也能拿到 openid
|
||||
console.log('[auth-flow] 🔑 无 openid,调 silenceAuthNoLogin 拿 openid');
|
||||
this._fetchOpenidAndLoad(targetUrl);
|
||||
return;
|
||||
} else {
|
||||
console.log('[web_view] 非可信域,不做身份替换');
|
||||
}
|
||||
@@ -305,6 +268,93 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 主动 wx.login() 拿 code,调 CRMEB /v2/wechat/silence_auth 拿 openid
|
||||
* 然后注入 URL 并加载 H5(即使后端返回 auth_login=1 无 token,openid 已够 H5 端走 openid-login 建档)
|
||||
* @param {string} targetUrl - 原始 H5 URL
|
||||
*/
|
||||
_fetchOpenidAndLoad(targetUrl) {
|
||||
uni.login({
|
||||
provider: 'weixin',
|
||||
success: (loginRes) => {
|
||||
const code = (loginRes && loginRes.code) || '';
|
||||
if (!code) {
|
||||
console.warn('[auth-flow] ⚠️ wx.login 返回空 code,匿名加载 H5');
|
||||
this._finalizeUrl(targetUrl);
|
||||
return;
|
||||
}
|
||||
console.log('[auth-flow] wx.login 拿到 code(前 8 位: ' + code.substring(0, 8) + '...),调 silenceAuthNoLogin');
|
||||
// 调 api/public.js 已有的 silenceAuth(MP 端 → v2/wechat/silence_auth)
|
||||
// 动态 import 避免在 web_view 页面外被 import 失败
|
||||
const apiPath = '@/api/public.js';
|
||||
// #ifdef MP
|
||||
import('@/api/public.js').then(api => {
|
||||
api.silenceAuth({ code: code }).then(res => {
|
||||
const data = res.data || {};
|
||||
// 兼容两种响应格式:
|
||||
// 1) 新用户 notLogin=true: {auth_login:1, key, openid, unionid}(顶层 openid)
|
||||
// 2) 老用户: {token, userInfo:{...}, expires_time, params:{openid}}(openid 在 JWT/userInfo 里)
|
||||
let openid = data.openid || '';
|
||||
let unionid = data.unionid || '';
|
||||
if (!openid) {
|
||||
// 从 userInfo 里取
|
||||
const ui = data.userInfo || {};
|
||||
openid = ui.openid || '';
|
||||
unionid = ui.unionid || '';
|
||||
}
|
||||
if (!openid && data.token) {
|
||||
// 从 JWT payload 里解 openid(兜底)
|
||||
try {
|
||||
const parts = String(data.token).split('.');
|
||||
if (parts.length === 3) {
|
||||
let payload = parts[1].replace(/-/g, '+').replace(/_/g, '/');
|
||||
while (payload.length % 4 !== 0) payload += '=';
|
||||
const p = JSON.parse(base64Decode(payload));
|
||||
openid = p.openid || '';
|
||||
unionid = p.unionid || '';
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[auth-flow] JWT 解码 openid 失败:', e.message);
|
||||
}
|
||||
}
|
||||
// 拿到 openid 后同步到 store/缓存(避免后续重复请求)
|
||||
if (openid) {
|
||||
try {
|
||||
store.commit('SET_OPENID', openid);
|
||||
uni.setStorageSync('OPENID', openid);
|
||||
} catch (e) {}
|
||||
if (unionid) {
|
||||
try {
|
||||
store.commit('SET_UNIONID', unionid);
|
||||
uni.setStorageSync('UNIONID', unionid);
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
console.log('[auth-flow] silenceAuthNoLogin 响应: status=' + res.status + ', has openid=' + !!openid + ', auth_login=' + data.auth_login);
|
||||
if (openid) {
|
||||
console.log('[auth-flow] ✅ 拿到 openid=' + openid.substring(0, 8) + '...,注入 URL');
|
||||
this._applyIdentity(targetUrl, openid, unionid, getUrlParam(targetUrl, 'openid'));
|
||||
} else {
|
||||
console.warn('[auth-flow] ⚠️ silenceAuthNoLogin 未返回 openid,匿名加载 H5');
|
||||
this._finalizeUrl(targetUrl);
|
||||
}
|
||||
}).catch(err => {
|
||||
console.warn('[auth-flow] ⚠️ silenceAuthNoLogin 网络失败,匿名加载 H5:', err);
|
||||
this._finalizeUrl(targetUrl);
|
||||
});
|
||||
}).catch(err => {
|
||||
console.warn('[auth-flow] ⚠️ import api 失败,匿名加载 H5:', err);
|
||||
this._finalizeUrl(targetUrl);
|
||||
});
|
||||
// #endif
|
||||
},
|
||||
fail: (err) => {
|
||||
console.warn('[auth-flow] ⚠️ wx.login 失败,匿名加载 H5:', err);
|
||||
this._finalizeUrl(targetUrl);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_applyIdentity(targetUrl, openid, unionid, urlOpenid) {
|
||||
console.log('[auth-flow] _applyIdentity: openid=' + (openid || '(空)') + ', unionid=' + (unionid || '(空)') + ', urlOpenid=' + (urlOpenid || '(无)'));
|
||||
if (urlOpenid && urlOpenid !== openid) {
|
||||
@@ -327,12 +377,9 @@ export default {
|
||||
console.log('[auth-flow] 身份一致,保留原 URL');
|
||||
}
|
||||
console.log('[auth-flow] 最终注入 URL:', targetUrl.substring(0, 120));
|
||||
this.debugMsg += ' [最终URL] ' + targetUrl.substring(0, 120);
|
||||
this._finalizeUrl(targetUrl);
|
||||
},
|
||||
_finalizeUrl(targetUrl) {
|
||||
console.log('[DEBUG 太阳码] _finalizeUrl 设置 this.url');
|
||||
console.log('[DEBUG 太阳码] 最终 URL:', targetUrl.substring(0, 100));
|
||||
console.log('[web_view] 最终URL:', targetUrl);
|
||||
try {
|
||||
const qIdx = targetUrl.indexOf('?');
|
||||
@@ -343,31 +390,123 @@ export default {
|
||||
uni.showShareMenu({ menus: ['shareAppMessage', 'shareTimeline'] });
|
||||
// #endif
|
||||
|
||||
// 自动关闭调试浮层(3秒后)
|
||||
setTimeout(() => {
|
||||
if (this.debugMsg) this.debugMsg = '';
|
||||
}, 3000);
|
||||
|
||||
this.url = targetUrl;
|
||||
try {
|
||||
const res = uni.getWindowInfo();
|
||||
this.windowW = res.windowWidth;
|
||||
this.windowH = res.windowHeight;
|
||||
} catch (_) {}
|
||||
|
||||
// 预取分享图片:太阳码场景 _resolveAppScene 已设置 shareImageUrl
|
||||
// 点击应用场景(JumpPath 无 identifier)或 H5 未传 imageUrl 时兜底拉取
|
||||
// 优先保留 H5 postMessage 传来的分享数据,未设置时才用 box_app 的
|
||||
this._fetchShareImage(targetUrl);
|
||||
},
|
||||
|
||||
/**
|
||||
* 根据当前 H5 URL 反查 box_app 应用,获取分享图片(shareImageUrl)
|
||||
* URL 形如 https://mp.yizhezhe.com/app_03/ 或 https://mp.yizhezhe.com/test_app/?ch=YFMM
|
||||
* 通过 mp/apps 列表匹配 url 前缀,找到对应应用后取 shareImageUrl
|
||||
* 命中本地缓存直接复用(进入页面后立刻分享也能带图),避免每次重复反查
|
||||
* @param {string} targetUrl
|
||||
*/
|
||||
_fetchShareImage(targetUrl) {
|
||||
if (!targetUrl) return;
|
||||
// H5 已通过 postMessage 设置分享图片,不覆盖
|
||||
if (this.shareImageUrl) return;
|
||||
// 页面内只请求一次,避免重复拉取
|
||||
if (this._shareFetched) return;
|
||||
this._shareFetched = true;
|
||||
try {
|
||||
const originPath = targetUrl.split('?')[0].replace(/\/$/, '');
|
||||
// 本地缓存:同一应用 URL 二次进入直接复用分享图,降低首帧分享无图概率
|
||||
const cacheKey = 'web_view_share_img:' + originPath;
|
||||
let cached = '';
|
||||
try { cached = uni.getStorageSync(cacheKey); } catch (e) {}
|
||||
if (cached) {
|
||||
this._applyShareImage(cached);
|
||||
console.log('[web_view] 分享图片(缓存命中): ' + cached);
|
||||
return;
|
||||
}
|
||||
uni.request({
|
||||
url: 'https://mp.yizhezhe.com/api/mp/apps?isPublished=1&pageSize=100',
|
||||
method: 'GET',
|
||||
success: (res) => {
|
||||
try {
|
||||
const items = res.data && res.data.result && res.data.result.items;
|
||||
if (!items || !items.length) return;
|
||||
const matched = items.find(it => {
|
||||
if (!it.url) return false;
|
||||
const appBase = it.url.split('?')[0].replace(/\/$/, '');
|
||||
// 当前 URL 与应用的 url 前缀匹配(如 https://mp.yizhezhe.com/app_03 == https://mp.yizhezhe.com/app_03/)
|
||||
return originPath === appBase || originPath.indexOf(appBase + '/') === 0;
|
||||
});
|
||||
if (matched && matched.shareImageUrl) {
|
||||
try { uni.setStorageSync(cacheKey, matched.shareImageUrl); } catch (e) {}
|
||||
this._applyShareImage(matched.shareImageUrl);
|
||||
console.log('[web_view] 分享图片(兜底): ' + matched.shareImageUrl);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[web_view] 分享图片解析失败:', e);
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
// 常见原因:mp.yizhezhe.com 未加入小程序后台 request/downloadFile 合法域名白名单
|
||||
console.warn('[web_view] 分享图片请求失败(请检查 mp.yizhezhe.com 是否已加入合法域名白名单):', err);
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
console.warn('[web_view] _fetchShareImage 异常:', e);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 统一设置分享图:同时准备好友转发图(shareImageUrl)与朋友圈本地图(shareTimelineImage)
|
||||
* @param {string} url 网络图片地址(box_app 返回或 H5 postMessage 传入)
|
||||
*/
|
||||
_applyShareImage(url) {
|
||||
if (!url) return;
|
||||
if (url === this.shareImageUrl) return; // 同一张图不重复处理(H5 可能重复 postMessage)
|
||||
this.shareImageUrl = url;
|
||||
this._prepareTimelineImage(url);
|
||||
},
|
||||
/**
|
||||
* 朋友圈分享图必须是本地路径/代码包路径(网络图会被微信静默忽略),
|
||||
* 这里用 getImageInfo 把网络图转成本地临时路径;失败则留空,回退微信默认截图。
|
||||
* 注意:getImageInfo 对网络图同样受 downloadFile 合法域名限制,域名未配置时朋友圈无自定义图。
|
||||
* @param {string} url 网络图片地址
|
||||
*/
|
||||
_prepareTimelineImage(url) {
|
||||
if (!url) return;
|
||||
uni.getImageInfo({
|
||||
src: url,
|
||||
success: (res) => {
|
||||
this.shareTimelineImage = res.path || '';
|
||||
console.log('[web_view] 朋友圈分享图已转本地:', this.shareTimelineImage);
|
||||
},
|
||||
fail: (err) => {
|
||||
console.warn('[web_view] 朋友圈分享图转本地失败(网络图/域名问题,回退默认截图):', err);
|
||||
this.shareTimelineImage = '';
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
onShareAppMessage() {
|
||||
return {
|
||||
title: this.shareTitle || '分享',
|
||||
path: '/pages/annex/web_view/index?url=' + encodeURIComponent(this.shareHref || this.url),
|
||||
// 分享出去必须剥离 openid/unionid/t 身份参数:
|
||||
// 1) 避免把分享者的微信匿名标识泄露给接收者;
|
||||
// 2) 接收者打开后由 web_view 按自己的身份重新注入(onShow/onLoad 有兜底替换)。
|
||||
path: '/pages/annex/web_view/index?url=' + encodeURIComponent(stripAuthParams(this.shareHref || this.url)),
|
||||
imageUrl: this.shareImageUrl || ''
|
||||
}
|
||||
},
|
||||
onShareTimeline() {
|
||||
return {
|
||||
title: this.shareTitle || '分享',
|
||||
query: 'url=' + encodeURIComponent(this.shareHref || this.url),
|
||||
imageUrl: this.shareImageUrl || ''
|
||||
query: 'url=' + encodeURIComponent(stripAuthParams(this.shareHref || this.url)),
|
||||
// 朋友圈分享图必须是本地路径/代码包路径,网络图会被微信静默忽略;
|
||||
// 网络图已在 _prepareTimelineImage 中通过 getImageInfo 转成本地临时路径。
|
||||
imageUrl: this.shareTimelineImage || ''
|
||||
}
|
||||
},
|
||||
handleMessage(e) {
|
||||
@@ -378,11 +517,17 @@ export default {
|
||||
switch (data.action) {
|
||||
case 'share':
|
||||
// 存储分享数据,供 onShareAppMessage / onShareTimeline 使用
|
||||
// title/imageUrl/href 各自独立处理,避免单个字段缺失导致整包分享数据被丢弃
|
||||
if (data.title) {
|
||||
this.shareTitle = data.title;
|
||||
this.shareSummary = data.summary || '';
|
||||
this.shareImageUrl = data.imageUrl || '';
|
||||
this.shareHref = data.href || this.url;
|
||||
}
|
||||
// H5 传了 imageUrl 才覆盖(否则保留 box_app 预取的分享图片)
|
||||
if (data.imageUrl) {
|
||||
this._applyShareImage(data.imageUrl);
|
||||
}
|
||||
if (data.href) {
|
||||
this.shareHref = data.href;
|
||||
}
|
||||
// 小程序中无法用代码触发分享面板,引导用户点击右上角 ··· 按钮
|
||||
uni.showToast({ title: '点击右上角 ··· 分享给好友', icon: 'none', duration: 2500 });
|
||||
@@ -411,16 +556,3 @@ export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.debug-overlay {
|
||||
position: fixed; top: 0; left: 0; right: 0; height: 45%;
|
||||
background: rgba(0,0,0,0.8); z-index: 9999;
|
||||
padding: 20px; box-sizing: border-box;
|
||||
overflow-y: auto; border-bottom: 2px solid #0f0;
|
||||
}
|
||||
.debug-text {
|
||||
color: #0f0; font-size: 13px;
|
||||
white-space: pre-wrap; word-break: break-all; line-height: 1.6;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -107,11 +107,13 @@
|
||||
url: '/pages/users/user_money/index'
|
||||
})
|
||||
} else if (type == 4) {
|
||||
if(item.wechat_state == 'WAIT_USER_CONFIRM'){
|
||||
uni.navigateTo({
|
||||
url: '/pages/users/user_spread_money/receiving?type=2&id=' + item.order_id
|
||||
})
|
||||
}
|
||||
// 微信红包/佣金奖品:原跳 user_spread_money/receiving(页面已移除,审核要求,待恢复)
|
||||
// if(item.wechat_state == 'WAIT_USER_CONFIRM'){
|
||||
// uni.navigateTo({
|
||||
// url: '/pages/users/user_spread_money/receiving?type=2&id=' + item.order_id
|
||||
// })
|
||||
// }
|
||||
uni.showToast({ title: '请联系客服领取奖品', icon: 'none' })
|
||||
} else if (type == 5) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/users/user_coupon/index'
|
||||
|
||||
@@ -60,6 +60,7 @@ export default {
|
||||
<text v-if="userInfo.service_num" class="number">{{ userInfo.service_num >= 100 ? '99+' : userInfo.service_num }}</text>
|
||||
</text>
|
||||
</view>
|
||||
<!-- 分销/提现区块已隐藏(微信审核要求:分销功能关闭,提现页面已移除,待审核通过后可恢复)
|
||||
<view class="distribution">
|
||||
<view class="acea-row row-middle row-between withdraw">
|
||||
<view>
|
||||
@@ -89,6 +90,7 @@ export default {
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
-->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user