|
|
@@ -469,6 +469,21 @@
|
|
|
pointer-events: auto;
|
|
|
}
|
|
|
|
|
|
+ #fabWrapWx {
|
|
|
+ display: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ #fabWrapWx.is-active {
|
|
|
+ display: block;
|
|
|
+ }
|
|
|
+
|
|
|
+ #launch-btn {
|
|
|
+ display: block;
|
|
|
+ width: 100%;
|
|
|
+ max-width: 320px;
|
|
|
+ margin: 0 auto;
|
|
|
+ }
|
|
|
+
|
|
|
.fab {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
@@ -967,21 +982,43 @@
|
|
|
<div id="staffGroupsMount"></div>
|
|
|
</section>
|
|
|
</div>
|
|
|
- <wx-open-launch-app
|
|
|
- id="launch-btn"
|
|
|
- appid="wxf5f1efe3a9f5012e"
|
|
|
- extinfo="https://test.ailien.shop/h5/HBuilderProjects/shareIndex.html"
|
|
|
- >
|
|
|
- <div id="shareBelowContentEl">
|
|
|
- <div class="fab-wrap">
|
|
|
- <button type="button" class="fab" id="openApp">
|
|
|
- <img src="images/uBtn.png" alt="APP内打开" decoding="async">
|
|
|
+ <!-- 微信内:wx-open-launch-app(需 JSSDK 签名 + 公众号关联 App);非微信见 #fabWrapFallback -->
|
|
|
+ <div id="fabWrapWx" class="fab-wrap" aria-hidden="true">
|
|
|
+ <wx-open-launch-app id="launch-btn" appid="wxf5f1efe3a9f5012e">
|
|
|
+ <script type="text/wxtag-template">
|
|
|
+ <style>
|
|
|
+ .wx-open-app-btn {
|
|
|
+ display: block;
|
|
|
+ width: 100%;
|
|
|
+ max-width: 320px;
|
|
|
+ height: 48px;
|
|
|
+ margin: 0 auto;
|
|
|
+ padding: 0;
|
|
|
+ border: none;
|
|
|
+ background: transparent;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+ .wx-open-app-btn img {
|
|
|
+ display: block;
|
|
|
+ width: 100%;
|
|
|
+ height: 48px;
|
|
|
+ object-fit: contain;
|
|
|
+ }
|
|
|
+ </style>
|
|
|
+ <button class="wx-open-app-btn" aria-label="APP内打开">
|
|
|
+ <img src="https://test.ailien.shop/h5/HBuilderProjects/images/uBtn.png" alt="APP内打开" />
|
|
|
</button>
|
|
|
- <div class="home-indicator" aria-hidden="true"></div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </wx-open-launch-app>
|
|
|
- <script src="http://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
|
|
|
+ </script>
|
|
|
+ </wx-open-launch-app>
|
|
|
+ <div class="home-indicator" aria-hidden="true"></div>
|
|
|
+ </div>
|
|
|
+ <div id="fabWrapFallback" class="fab-wrap">
|
|
|
+ <button type="button" class="fab" id="openApp">
|
|
|
+ <img src="images/uBtn.png" alt="APP内打开" decoding="async">
|
|
|
+ </button>
|
|
|
+ <div class="home-indicator" aria-hidden="true"></div>
|
|
|
+ </div>
|
|
|
+ <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
|
|
|
<script>
|
|
|
(function () {
|
|
|
'use strict';
|
|
|
@@ -1002,6 +1039,20 @@
|
|
|
*/
|
|
|
var API_BASE = 'https://test.ailien.shop/alienStore';
|
|
|
|
|
|
+ /** 微信开放标签:移动应用 AppID(与 wx-open-launch-app appid 一致) */
|
|
|
+ var WECHAT_OPEN_APP_ID = 'wxf5f1efe3a9f5012e';
|
|
|
+ /**
|
|
|
+ * JSSDK 签名接口路径(相对 API_BASE);后端需返回 appId、timestamp、nonceStr、signature。
|
|
|
+ * 可用 ?wxSignPath=/your/path 或完整 ?wxSignUrl=https://... 覆盖。
|
|
|
+ */
|
|
|
+ var WECHAT_JSSDK_SIGN_PATHS = [
|
|
|
+ '/wechat/mp/jsapi-signature',
|
|
|
+ '/wechat/jsapi/getSign',
|
|
|
+ '/wx/jsapi/signature'
|
|
|
+ ];
|
|
|
+ var H5_PAGE_BASE_FALLBACK = 'https://test.ailien.shop/h5/HBuilderProjects/';
|
|
|
+ var weChatOpenTagReady = false;
|
|
|
+
|
|
|
/**
|
|
|
* 关店(businessStatus=99)更多推荐:POST …/ai/multimodal-services/api/v1/search/global/store-recommend
|
|
|
* 与 shareCheckInUndefined.html 一致;请求体 page、pageSize、storeId、userCity、userLat、userLng 可由 URL 覆盖。
|
|
|
@@ -1076,6 +1127,203 @@
|
|
|
return /MicroMessenger/i.test(navigator.userAgent || '');
|
|
|
}
|
|
|
|
|
|
+ function getWeChatJssdkSignRequestUrl() {
|
|
|
+ var custom = String(q('wxSignPath') || q('wxSignUrl') || '').trim();
|
|
|
+ if (!custom) return '';
|
|
|
+ if (/^https?:\/\//i.test(custom)) return custom;
|
|
|
+ return API_BASE.replace(/\/$/, '') + (custom.charAt(0) === '/' ? custom : '/' + custom);
|
|
|
+ }
|
|
|
+
|
|
|
+ function getPageUrlForWxSign() {
|
|
|
+ var u = String(location.href || '').split('#')[0];
|
|
|
+ if (!u || u.indexOf('file:') === 0) {
|
|
|
+ return H5_PAGE_BASE_FALLBACK + 'shareIndex.html' + (location.search || '');
|
|
|
+ }
|
|
|
+ return u;
|
|
|
+ }
|
|
|
+
|
|
|
+ function buildWeChatLaunchExtinfo() {
|
|
|
+ var deep = buildAppDeepLink();
|
|
|
+ if (deep && deep.length <= 1024) return deep;
|
|
|
+ var page = getPageUrlForWxSign();
|
|
|
+ return page.length <= 1024 ? page : page.slice(0, 1024);
|
|
|
+ }
|
|
|
+
|
|
|
+ function absH5AssetUrl(rel) {
|
|
|
+ rel = String(rel || '').replace(/^\//, '');
|
|
|
+ var origin = location.origin;
|
|
|
+ if (origin && origin !== 'null' && /^https?:/i.test(origin)) {
|
|
|
+ var dir = location.pathname.replace(/[^/]*$/, '');
|
|
|
+ return origin + dir + rel;
|
|
|
+ }
|
|
|
+ return H5_PAGE_BASE_FALLBACK + rel;
|
|
|
+ }
|
|
|
+
|
|
|
+ function normalizeWxJssdkSignPayload(res) {
|
|
|
+ if (!res || typeof res !== 'object') return null;
|
|
|
+ var d = res.data != null && typeof res.data === 'object' ? res.data : res;
|
|
|
+ if (!d || typeof d !== 'object') return null;
|
|
|
+ var appId = d.appId || d.appid || WECHAT_OPEN_APP_ID;
|
|
|
+ var timestamp = d.timestamp != null ? d.timestamp : d.timeStamp;
|
|
|
+ var nonceStr = d.nonceStr || d.noncestr || d.nonce;
|
|
|
+ var signature = d.signature || d.sign;
|
|
|
+ if (!appId || timestamp == null || !nonceStr || !signature) return null;
|
|
|
+ return {
|
|
|
+ appId: String(appId),
|
|
|
+ timestamp: Number(timestamp),
|
|
|
+ nonceStr: String(nonceStr),
|
|
|
+ signature: String(signature)
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ function fetchWeChatJssdkSign() {
|
|
|
+ var signPageUrl = getPageUrlForWxSign();
|
|
|
+ var urls = [];
|
|
|
+ var custom = getWeChatJssdkSignRequestUrl();
|
|
|
+ if (custom) {
|
|
|
+ var sep0 = custom.indexOf('?') >= 0 ? '&' : '?';
|
|
|
+ urls.push(custom + sep0 + 'url=' + encodeURIComponent(signPageUrl));
|
|
|
+ } else {
|
|
|
+ var base = API_BASE.replace(/\/$/, '');
|
|
|
+ for (var pi = 0; pi < WECHAT_JSSDK_SIGN_PATHS.length; pi++) {
|
|
|
+ urls.push(
|
|
|
+ base +
|
|
|
+ WECHAT_JSSDK_SIGN_PATHS[pi] +
|
|
|
+ '?url=' +
|
|
|
+ encodeURIComponent(signPageUrl)
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ function tryUrl(idx) {
|
|
|
+ if (idx >= urls.length) return Promise.resolve(null);
|
|
|
+ return fetch(urls[idx], {
|
|
|
+ method: 'GET',
|
|
|
+ mode: 'cors',
|
|
|
+ credentials: 'omit',
|
|
|
+ headers: { Accept: 'application/json' }
|
|
|
+ })
|
|
|
+ .then(function (r) {
|
|
|
+ if (!r.ok) throw new Error('HTTP ' + r.status);
|
|
|
+ return r.json();
|
|
|
+ })
|
|
|
+ .then(function (res) {
|
|
|
+ if (res && res.code != null) {
|
|
|
+ var c = Number(res.code);
|
|
|
+ if (c !== 200 && c !== 0 && res.success !== true) {
|
|
|
+ throw new Error(res.msg || 'sign rejected');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ var pack = normalizeWxJssdkSignPayload(res);
|
|
|
+ if (!pack) throw new Error('empty sign payload');
|
|
|
+ return pack;
|
|
|
+ })
|
|
|
+ .catch(function () {
|
|
|
+ return tryUrl(idx + 1);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return tryUrl(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ function setFabLaunchMode(mode) {
|
|
|
+ var wxWrap = document.getElementById('fabWrapWx');
|
|
|
+ var fbWrap = document.getElementById('fabWrapFallback');
|
|
|
+ if (mode === 'wx') {
|
|
|
+ if (wxWrap) {
|
|
|
+ wxWrap.classList.add('is-active');
|
|
|
+ wxWrap.setAttribute('aria-hidden', 'false');
|
|
|
+ }
|
|
|
+ if (fbWrap) {
|
|
|
+ fbWrap.style.display = 'none';
|
|
|
+ fbWrap.setAttribute('aria-hidden', 'true');
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (wxWrap) {
|
|
|
+ wxWrap.classList.remove('is-active');
|
|
|
+ wxWrap.setAttribute('aria-hidden', 'true');
|
|
|
+ }
|
|
|
+ if (fbWrap) {
|
|
|
+ fbWrap.style.display = '';
|
|
|
+ fbWrap.setAttribute('aria-hidden', 'false');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function bindWeChatLaunchTagEvents() {
|
|
|
+ var tag = document.getElementById('launch-btn');
|
|
|
+ if (!tag) return;
|
|
|
+ try {
|
|
|
+ tag.setAttribute('extinfo', buildWeChatLaunchExtinfo());
|
|
|
+ } catch (eExt) {}
|
|
|
+ tag.addEventListener('launch', function () {
|
|
|
+ weChatOpenTagReady = true;
|
|
|
+ });
|
|
|
+ tag.addEventListener('error', function (e) {
|
|
|
+ console.warn('[wx-open-launch-app]', e && e.detail);
|
|
|
+ weChatOpenTagReady = false;
|
|
|
+ setFabLaunchMode('scheme');
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ function initWeChatOpenLaunchApp() {
|
|
|
+ if (!isWeChatInAppBrowser()) {
|
|
|
+ setFabLaunchMode('scheme');
|
|
|
+ return Promise.resolve(false);
|
|
|
+ }
|
|
|
+ /** 签名完成前不展示 scheme 按钮,避免误点触发无效唤起 */
|
|
|
+ var fbWrap0 = document.getElementById('fabWrapFallback');
|
|
|
+ if (fbWrap0) {
|
|
|
+ fbWrap0.style.display = 'none';
|
|
|
+ fbWrap0.setAttribute('aria-hidden', 'true');
|
|
|
+ }
|
|
|
+ if (typeof wx === 'undefined') {
|
|
|
+ console.warn('[wx] jweixin not loaded');
|
|
|
+ setFabLaunchMode('scheme');
|
|
|
+ return Promise.resolve(false);
|
|
|
+ }
|
|
|
+ bindWeChatLaunchTagEvents();
|
|
|
+ return fetchWeChatJssdkSign()
|
|
|
+ .then(function (sign) {
|
|
|
+ if (!sign) {
|
|
|
+ console.warn('[wx] JSSDK sign unavailable — check WECHAT_JSSDK_SIGN_PATHS or ?wxSignPath=');
|
|
|
+ setFabLaunchMode('scheme');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return new Promise(function (resolve) {
|
|
|
+ wx.config({
|
|
|
+ debug: String(q('wxDebug') || '') === '1',
|
|
|
+ appId: sign.appId,
|
|
|
+ timestamp: sign.timestamp,
|
|
|
+ nonceStr: sign.nonceStr,
|
|
|
+ signature: sign.signature,
|
|
|
+ jsApiList: [],
|
|
|
+ openTagList: ['wx-open-launch-app']
|
|
|
+ });
|
|
|
+ wx.ready(function () {
|
|
|
+ weChatOpenTagReady = true;
|
|
|
+ var tag = document.getElementById('launch-btn');
|
|
|
+ if (tag) {
|
|
|
+ try {
|
|
|
+ tag.setAttribute('extinfo', buildWeChatLaunchExtinfo());
|
|
|
+ } catch (eReady) {}
|
|
|
+ }
|
|
|
+ setFabLaunchMode('wx');
|
|
|
+ resolve(true);
|
|
|
+ });
|
|
|
+ wx.error(function (err) {
|
|
|
+ console.warn('[wx.config]', err);
|
|
|
+ weChatOpenTagReady = false;
|
|
|
+ setFabLaunchMode('scheme');
|
|
|
+ resolve(false);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ })
|
|
|
+ .catch(function (e) {
|
|
|
+ console.warn('[wx] init failed', e);
|
|
|
+ setFabLaunchMode('scheme');
|
|
|
+ return false;
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
/** 部分 WebView 对 location.href 拦截,用 a 标签点击略稳 */
|
|
|
function launchAppDeepLink(deepLink) {
|
|
|
|
|
|
@@ -1094,9 +1342,13 @@
|
|
|
|
|
|
/**
|
|
|
* 有 plus:检测 App 是否安装后 openURL;深链形如 shopro://{APP_UNI_STORE_PATH}?…
|
|
|
- * 系统浏览器:唤起 scheme;微信内常拦截 scheme,需「在浏览器打开」。
|
|
|
+ * 系统浏览器:scheme 唤起;微信内优先 wx-open-launch-app,失败再 scheme(不再弹「在浏览器中打开」)。
|
|
|
*/
|
|
|
function tryOpenHBuilderApp() {
|
|
|
+ if (isWeChatInAppBrowser() && weChatOpenTagReady) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
var deepLink = buildAppDeepLink();
|
|
|
|
|
|
if (typeof plus !== 'undefined' && plus.runtime) {
|
|
|
@@ -1141,10 +1393,6 @@
|
|
|
document.addEventListener('visibilitychange', onVis);
|
|
|
window.addEventListener('pagehide', onHide);
|
|
|
|
|
|
- if (isWeChatInAppBrowser()) {
|
|
|
- window.alert('若点击后无法打开 App:请先点右上角「···」,选择「在浏览器中打开」,再点「APP内打开」。');
|
|
|
- }
|
|
|
-
|
|
|
try {
|
|
|
launchAppDeepLink(deepLink);
|
|
|
} catch (e3) {
|
|
|
@@ -2322,6 +2570,7 @@
|
|
|
tryOpenHBuilderApp();
|
|
|
});
|
|
|
}
|
|
|
+ initWeChatOpenLaunchApp();
|
|
|
}
|
|
|
|
|
|
if (document.readyState === 'complete') {
|