zhuli 2 недель назад
Родитель
Сommit
c3af6a6a1c
1 измененных файлов с 167 добавлено и 454 удалено
  1. 167 454
      HBuilderProjects/shareIndex.html

+ 167 - 454
HBuilderProjects/shareIndex.html

@@ -22,6 +22,10 @@
 			padding: 0;
 			box-sizing: border-box;
 		}
+		#staffGroupsMount{
+			height: 202px;
+			overflow: hidden;
+		}
 
 		html {
 			font-size: 16px;
@@ -472,27 +476,12 @@
 			pointer-events: auto;
 		}
 
-		#fabDock {
-			display: block;
-		}
-
 		.fab-dock__slot {
 			position: relative;
 			width: 100%;
 			max-width: 320px;
 			height: 48px;
 			margin: 0 auto;
-			-webkit-tap-highlight-color: transparent;
-		}
-
-		#openApp {
-			position: relative;
-			z-index: 1;
-			touch-action: manipulation;
-		}
-
-		#openApp img {
-			pointer-events: none;
 		}
 
 		.fab-wx-hit {
@@ -505,7 +494,6 @@
 			z-index: 3;
 		}
 
-		/* 底层 #openApp 始终显示;上层透明开放标签接收点击(标签未渲染时仍能看见并点底层按钮) */
 		#fabDock.wx-open-enabled .fab-wx-hit {
 			display: block;
 		}
@@ -515,25 +503,10 @@
 			width: 100%;
 			height: 48px;
 			min-height: 48px;
-			line-height: 48px;
 		}
 
-		#openAppToast {
-			display: none;
-			position: fixed;
-			left: 16px;
-			right: 16px;
-			bottom: calc(72px + var(--safe-bottom));
-			z-index: 10001;
-			padding: 10px 14px;
-			font-size: 13px;
-			line-height: 1.45;
-			color: #fff;
-			text-align: center;
-			background: rgba(0, 0, 0, 0.78);
-			border-radius: 8px;
+		#openApp img {
 			pointer-events: none;
-			word-break: break-all;
 		}
 
 		.fab {
@@ -1034,15 +1007,13 @@
 			<div id="staffGroupsMount"></div>
 		</section>
 	</div>
-	<pre id="wxDebugBar" style="display:none;position:fixed;left:8px;right:8px;top:8px;z-index:9999;max-height:40vh;overflow:auto;margin:0;padding:8px;font-size:11px;line-height:1.35;background:rgba(0,0,0,.82);color:#0f0;white-space:pre-wrap;word-break:break-all;border-radius:6px;pointer-events:none;"></pre>
-	<div id="openAppToast" role="status" aria-live="polite"></div>
 	<div id="fabDock" class="fab-wrap">
 		<div class="fab-dock__slot">
 			<button type="button" class="fab" id="openApp">
 				<img src="images/uBtn.png" alt="APP内打开" decoding="async">
 			</button>
 			<div id="fabWxHit" class="fab-wx-hit" aria-hidden="true">
-				<wx-open-launch-app id="launch-btn" appid="wx412792c77f47babd">
+				<wx-open-launch-app id="launch-btn" appid="wxf5f1efe3a9f5012e">
 					<script type="text/wxtag-template">
 						<style>
 							.wx-open-app-btn {
@@ -1052,11 +1023,18 @@
 								margin: 0;
 								padding: 0;
 								border: none;
-								opacity: 0;
 								background: transparent;
 							}
+							.wx-open-app-btn img {
+								display: block;
+								width: 100%;
+								height: 48px;
+								object-fit: contain;
+							}
 						</style>
-						<button class="wx-open-app-btn" aria-label="APP内打开">打开</button>
+						<button class="wx-open-app-btn" aria-label="APP内打开">
+							<img src="https://test.ailien.shop/h5/HBuilderProjects/images/uBtn.png" alt="APP内打开" />
+						</button>
 					</script>
 				</wx-open-launch-app>
 			</div>
@@ -1084,77 +1062,48 @@
 		 */
 		var API_BASE = 'https://test.ailien.shop/alienStore';
 
-		/** wx-open-launch-app 的 appid(开放平台移动应用;若与公众号不同,只改这里和标签 appid) */
-		var WECHAT_OPEN_APP_ID = 'wx412792c77f47babd';
-		/** 可选:强制 wx.config 使用的公众号 appId;默认用 getWxConfig 返回的 data.appId */
-		var WECHAT_MP_APP_ID = '';
 		/**
-		 * 进入页 GET {API_BASE}/wx/getWxConfig?url={当前页完整 URL,含 ? 参数,不含 #}
-		 * 微信校验签名与 location.href.split('#')[0] 必须一致,不能只签 shareIndex.html 无参数
-		 * 可用 ?wxSignPath= 或 ?wxSignUrl= 覆盖。
+		 * 微信 JSSDK(服务号「麦丽恩严U店」)— 仅用于 wx.config 签名,Secret 只放后端
+		 * 后端 GET {API_BASE}/wx/getWxConfig 须用:AppID wx412792c77f47babd + 服务号 AppSecret
 		 */
+		var WECHAT_MP_APP_ID = 'wx412792c77f47babd';
+		/** 微信开放标签 wx-open-launch-app — 移动应用「U店在哪」AppID(不是服务号 ID) */
+		var WECHAT_OPEN_APP_ID = 'wxf5f1efe3a9f5012e';
 		var WECHAT_GET_WX_CONFIG_PATH = '/wx/getWxConfig';
 		var H5_PAGE_BASE_FALLBACK = 'https://test.ailien.shop/h5/HBuilderProjects/';
-		/** 本地 file:// 预览时传给 getWxConfig 的默认 url(无 query) */
-		var WX_GET_CONFIG_SIGN_URL = 'https://test.ailien.shop/h5/HBuilderProjects/shareIndex.html';
-		/** wx.config 已成功(开放标签可展示);与「用户已成功唤起 App」不是同一回事 */
+		var WX_GET_CONFIG_SIGN_URL = H5_PAGE_BASE_FALLBACK + 'shareIndex.html';
+		var WECHAT_JS_SAFE_HOSTS = ['uat.ailien.shop', 'test.ailien.shop'];
 		var weChatJssdkConfigured = false;
 		var wxConfigSignRetriedBaseUrl = false;
 		var wxSignUrlFullBeforeStrip = '';
-		var wxDebugLastStatus = '';
-
-		function isWxDebugOn() {
-			return String(q('wxDebug') || '') === '1';
-		}
-
-		function stringifyWxDebugPayload(obj) {
-			try {
-				return JSON.stringify(obj, null, 2);
-			} catch (eJson) {
-				return String(obj && obj.errMsg ? obj.errMsg : obj);
-			}
-		}
-
-		/** ?wxDebug=1 时弹窗 + 页内条展示完整 errMsg(微信 debug 弹窗有时信息不全) */
-		function reportWxDebug(stage, payload, extraLines) {
-			var lines = ['【' + stage + '】'];
-			if (extraLines && extraLines.length) {
-				for (var i = 0; i < extraLines.length; i++) lines.push(extraLines[i]);
-			}
-			if (payload != null) {
-				lines.push(stringifyWxDebugPayload(payload));
-			}
-			var text = lines.join('\n');
-			wxDebugLastStatus = text;
-			console.log('[wxDebug]', text);
-			if (!isWxDebugOn()) return;
-			var bar = document.getElementById('wxDebugBar');
-			if (bar) {
-				bar.style.display = 'block';
-				bar.textContent = text;
-			}
-			if (isWeChatInAppBrowser()) {
-				window.alert(text.slice(0, 900));
-			}
-		}
 
 		/**
 		 * 关店(businessStatus=99)更多推荐:POST …/ai/multimodal-services/api/v1/search/global/store-recommend
-		 * 与 shareCheckInUndefined.html 一致;请求体 page、pageSize、storeId、userCity、userLat、userLng 可由 URL 覆盖
+		 * 与 shareCheckInUndefined.html 一致;请求体 userCity/userLat/userLng 优先取 URL:userCity、lat、lon(兼认 userLat/userLng、weidu/jingdu 等)。
 		 */
 		var API_LIFE_AI_BASE = 'http://183.252.196.135:9100';
 		var STORE_GLOBAL_RECOMMEND_PATH =
 			'/ai/multimodal-services/api/v1/search/global/store-recommend';
-		var DEFAULT_REC_USER_LAT = 38.925747;
-		var DEFAULT_REC_USER_LNG = 121.662531;
-		var DEFAULT_REC_USER_CITY = '大连市';
+		/** 关店推荐用户位置:优先 URL 的 lat、lon、userCity;缺省再用大连默认值 */
+		function getClosedRecommendUserLocation() {
+			var latRaw = (q('lat') || q('userLat') || q('latitude') || q('weidu') || '').trim();
+			var lonRaw = (q('lon') || q('userLng') || q('longitude') || q('lng') || q('jingdu') || '').trim();
+			var cityRaw = (q('userCity') || q('city') || '').trim();
+			return {
+				userLat:
+					latRaw !== '' && !isNaN(Number(latRaw)) ? Number(latRaw) : 38.925747,
+				userLng:
+					lonRaw !== '' && !isNaN(Number(lonRaw)) ? Number(lonRaw) : 121.662531,
+				userCity: cityRaw !== '' ? cityRaw : '大连市'
+			};
+		}
 
 		/**
 		 * 与 group_user 一致:
 		 * - manifest:app-plus.distribute.android.schemes、ios.urltypes → shopro(即 shopro://)
 		 * - Android 包名:manifest 未写 packagename 时与 App.vue 升级配置 androidPackageName 一致(云打包以 HBuilderX 为准)
 		 */
-		var APP_ANDROID_PACKAGE = 'com.alien.Udianzaina';
+		var APP_ANDROID_PACKAGE = 'com.alien.Udianzaizhe';
 		var APP_IOS_URL_SCHEME = 'shopro://';
 		/** businessSection 未传或其它值时的默认落地页(与 1 相同) */
 		var APP_UNI_STORE_PATH = 'pages/ieisureEntertainment/eightTypeList/delicacyDetails';
@@ -1168,47 +1117,6 @@
 			}
 		}
 
-		function showFabToast(msg, ms) {
-			var tip = String(msg || '').trim();
-			if (!tip) return;
-			var el = document.getElementById('openAppToast');
-			if (el) {
-				el.textContent = tip;
-				el.style.display = 'block';
-				if (showFabToast._timer) clearTimeout(showFabToast._timer);
-				showFabToast._timer = setTimeout(function () {
-					el.style.display = 'none';
-				}, ms || 3200);
-			}
-			console.log('[openApp]', tip);
-		}
-
-		function showAppOpenFailTip(msg) {
-			var tip =
-				msg ||
-				'未能打开 App,请确认已安装最新版「U店在哪」;微信内请使用页面底部按钮打开。';
-			showFabToast(tip, 4000);
-			if (typeof uni !== 'undefined' && typeof uni.showToast === 'function') {
-				uni.showToast({ title: tip, icon: 'none', duration: 2800 });
-			} else if (isWeChatInAppBrowser() && isWxDebugOn()) {
-				window.alert(tip);
-			}
-		}
-
-		/** 与公众平台「JS接口安全域名」一致;分享页实际打开的 host 必须在此列表中 */
-		var WECHAT_JS_SAFE_HOSTS = ['uat.ailien.shop', 'test.ailien.shop'];
-
-		function checkWxJsSafeDomainHint() {
-			var host = String(location.hostname || '').toLowerCase();
-			if (!host || host === 'localhost' || host === '127.0.0.1') return '';
-			if (WECHAT_JS_SAFE_HOSTS.indexOf(host) >= 0) return '';
-			return (
-				'当前页面域名为「' +
-				host +
-				'」,未在 WECHAT_JS_SAFE_HOSTS 中;请在公众号后台「JS接口安全域名」添加该域名(不含 https:// 与路径)。'
-			);
-		}
-
 		/** 详情页 onLoad 使用 storeId;分享链常为 id,补全 storeId 避免 App 内参数为空 */
 		function buildAppOpenQueryString() {
 			var raw = (location.search && location.search.charAt(0) === '?') ? location.search.slice(1) : (location.search || '');
@@ -1253,14 +1161,10 @@
 			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 isWxDebugOn() {
+			return String(q('wxDebug') || '') === '1';
 		}
 
-		/** 微信 JSSDK 参与签名的 url:完整链(含 ?),不含 # */
 		function getWxSignUrlFull() {
 			var forced = String(q('wxSignUrl') || '').trim();
 			if (forced) return forced.split('#')[0];
@@ -1276,7 +1180,6 @@
 			return WX_GET_CONFIG_SIGN_URL;
 		}
 
-		/** 无 query 的页面地址(后端若只签该地址,须配合 syncBrowserUrlForWxSign) */
 		function getWxSignUrlBase() {
 			if (location.origin && /^https?:/i.test(location.origin)) {
 				return location.origin + (location.pathname || '/h5/HBuilderProjects/shareIndex.html');
@@ -1289,82 +1192,37 @@
 			return getWxSignUrlFull();
 		}
 
-		/**
-		 * 微信校验签名用的是地址栏当前 url(不含#)。
-		 * 若后端只签了无参地址,须先把地址栏 sync 成与签名 url 一致再 wx.config。
-		 */
 		function syncBrowserUrlForWxSign(signUrl) {
 			var target = String(signUrl || '').split('#')[0];
 			if (!target) return;
-			var hash = location.hash || '';
 			var current = String(location.href || '').split('#')[0];
 			if (current !== target) {
-				history.replaceState(history.state, document.title, target + hash);
+				history.replaceState(history.state, document.title, target + (location.hash || ''));
 			}
 		}
 
-		/** 唤起 App 的 extinfo:保留完整分享链 */
-		function getPageUrlForWxSign() {
-			return getWxSignUrlFull();
-		}
-
 		function buildWxGetConfigRequestUrl(signPageUrl) {
-			var base = API_BASE.replace(/\/$/, '');
 			return (
-				base +
+				API_BASE.replace(/\/$/, '') +
 				WECHAT_GET_WX_CONFIG_PATH +
 				'?url=' +
 				encodeURIComponent(signPageUrl || getWxConfigSignUrl())
 			);
 		}
 
-		/**
-		 * 微信开放标签 extinfo:优先传当前 H5 分享链(与 App 解析分享 URL 一致);
-		 * 超长时再传 path+query JSON,最后才用 shopro://。
-		 */
-		function buildWeChatLaunchExtinfo() {
-			var pageUrl = getPageUrlForWxSign();
-			if (pageUrl && pageUrl.length <= 1024) return pageUrl;
-			var path = getAppUniPathForBusinessSection().replace(/^\//, '');
-			var qs = buildAppOpenQueryString().replace(/^\?/, '');
-			try {
-				var pack = JSON.stringify({
-					path: path,
-					query: qs,
-					h5: pageUrl
-				});
-				if (pack.length <= 1024) return pack;
-			} catch (eJson) {}
-			var deep = buildAppDeepLink();
-			if (deep && deep.length <= 1024) return deep;
-			return pageUrl ? pageUrl.slice(0, 1024) : deep.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 resolveWxConfigAppIdFromSignData(d) {
 			if (!d || typeof d !== 'object') return '';
 			var mp =
 				d.mpAppId ||
 				d.mpAppid ||
 				d.officialAppId ||
-				d.officialAccountAppId ||
 				d.gzhAppId ||
 				d.serviceAppId;
 			if (mp != null && String(mp).trim() !== '') return String(mp).trim();
 			var fromQuery = String(q('wxMpAppId') || WECHAT_MP_APP_ID || '').trim();
 			if (fromQuery) return fromQuery;
 			var raw = d.appId || d.appid || d.wxAppId;
-			if (raw == null || String(raw).trim() === '') return '';
-			return String(raw).trim();
+			return raw != null && String(raw).trim() !== '' ? String(raw).trim() : '';
 		}
 
 		function normalizeWxJssdkSignPayload(res, signUrlUsed) {
@@ -1405,73 +1263,58 @@
 		function formatWxConfigErrorTip(err, signPageUrl) {
 			var errMsg = getWxErrMsg(err);
 			var tip = '微信 JSSDK 配置失败';
-			if (/require\s*subscribe/i.test(errMsg)) {
-				return (
-					tip +
-					':' +
-					errMsg +
-					'。测试号须用当前微信号在 mp.weixin.qq.com/debug.cgi 关注后再打开本页。'
-				);
-			}
 			if (/invalid signature/i.test(errMsg)) {
-				var signUrl = signPageUrl || getWxSignUrlFull();
-				var pageNow = String(location.href || '').split('#')[0];
 				return (
 					tip +
-					':签名无效。请让后端用与地址栏完全相同的 url 参与签名(不含#)。当前地址栏:' +
-					pageNow +
-					';本次请求签名 url:' +
-					signUrl
+					':签名无效。地址栏:' +
+					String(location.href || '').split('#')[0] +
+					';签名 url:' +
+					(signPageUrl || getWxSignUrlFull())
 				);
 			}
-			if (/invalid appid/i.test(errMsg)) {
-				return tip + ':appId 无效,请使用已认证服务号的公众号 AppID。';
-			}
-			if (/invalid url/i.test(errMsg)) {
-				return tip + ':域名未在公众号 JS 接口安全域名中,或未在开放平台绑定域名与移动应用。';
+			if (/require\s*subscribe/i.test(errMsg)) {
+				return tip + ':' + errMsg + '(服务号需用户已关注)';
 			}
-			if (errMsg) return tip + ':' + errMsg;
-			return tip + ',开放标签不可用。';
+			return errMsg ? tip + ':' + errMsg : tip;
+		}
+
+		function buildWeChatLaunchExtinfo() {
+			var pageUrl = getWxSignUrlFull();
+			if (pageUrl && pageUrl.length <= 1024) return pageUrl;
+			var path = getAppUniPathForBusinessSection().replace(/^\//, '');
+			var qs = buildAppOpenQueryString().replace(/^\?/, '');
+			try {
+				var pack = JSON.stringify({ path: path, query: qs, h5: pageUrl });
+				if (pack.length <= 1024) return pack;
+			} catch (eJ) {}
+			var deep = buildAppDeepLink();
+			return deep.length <= 1024 ? deep : (pageUrl || deep).slice(0, 1024);
 		}
 
 		function fetchWeChatJssdkSign(signPageUrl) {
 			signPageUrl = signPageUrl || getWxConfigSignUrl();
-			var urls = [];
-			var custom = getWeChatJssdkSignRequestUrl();
-			if (custom) {
-				var sep0 = custom.indexOf('?') >= 0 ? '&' : '?';
-				urls.push(custom + sep0 + 'url=' + encodeURIComponent(signPageUrl));
-			} else {
-				urls.push(buildWxGetConfigRequestUrl(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' }
+			var url = buildWxGetConfigRequestUrl(signPageUrl);
+			return fetch(url, {
+				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 (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');
-							}
+				.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, signPageUrl);
-						if (!pack) throw new Error('empty sign payload');
-						return pack;
-					})
-					.catch(function () {
-						return tryUrl(idx + 1);
-					});
-			}
-			return tryUrl(0);
+					}
+					var pack = normalizeWxJssdkSignPayload(res, signPageUrl);
+					if (!pack) throw new Error('empty sign');
+					return pack;
+				});
 		}
 
 		function applyWxConfig(sign, signPageUrl) {
@@ -1480,44 +1323,35 @@
 					? String(sign.signUrl).trim()
 					: signPageUrl;
 			syncBrowserUrlForWxSign(urlForWx);
-			console.log('[wx.config] appId=', sign.appId, 'signUrl=', urlForWx, 'page=', location.href.split('#')[0]);
-
 			return new Promise(function (resolve) {
 				wx.config({
-					debug: String(q('wxDebug') || '') === '1',
+					debug: isWxDebugOn(),
 					appId: sign.appId,
 					timestamp: sign.timestamp,
 					nonceStr: sign.nonceStr,
 					signature: sign.signature,
-					jsApiList: ['checkJsApi'],
+					jsApiList: [],
 					openTagList: ['wx-open-launch-app']
 				});
 				wx.ready(function () {
 					weChatJssdkConfigured = true;
-					reportWxDebug('wx.ready / config:ok', { errMsg: 'config:ok' }, [
-						'appId(config)=' + sign.appId,
-						'openTag appid=' + WECHAT_OPEN_APP_ID,
-						'signUrl=' + urlForWx,
-						'page=' + location.href.split('#')[0],
-						'开放标签层=' + (isWeChatInAppBrowser() ? '已启用' : '非微信')
-					]);
 					if (wxSignUrlFullBeforeStrip) {
-						var restore = wxSignUrlFullBeforeStrip + (location.hash || '');
-						history.replaceState(history.state, document.title, restore);
+						history.replaceState(
+							history.state,
+							document.title,
+							wxSignUrlFullBeforeStrip + (location.hash || '')
+						);
 						wxSignUrlFullBeforeStrip = '';
 					}
 					scheduleWxOpenTagRefresh();
 					resolve(true);
 				});
 				wx.error(function (err) {
+					weChatJssdkConfigured = false;
+					updateFabOpenLayer();
 					var errMsg = getWxErrMsg(err);
-					console.warn('[wx.config]', err, 'signUrl=', urlForWx);
-					reportWxDebug('wx.error / config:fail', err, [
-						'完整 errMsg=' + errMsg,
-						'appId(config)=' + sign.appId,
-						'signUrl=' + urlForWx,
-						'page=' + location.href.split('#')[0]
-					]);
+					if (isWxDebugOn()) window.alert(formatWxConfigErrorTip(err, urlForWx));
+					console.warn('[wx.config]', errMsg, urlForWx);
 					var baseUrl = getWxSignUrlBase();
 					var fullUrl = getWxSignUrlFull();
 					if (
@@ -1526,69 +1360,35 @@
 						baseUrl === fullUrl ||
 						urlForWx === baseUrl
 					) {
-						weChatJssdkConfigured = false;
-						updateFabOpenLayer();
-						showAppOpenFailTip(formatWxConfigErrorTip(err, urlForWx));
 						resolve(false);
 						return;
 					}
 					wxConfigSignRetriedBaseUrl = true;
 					wxSignUrlFullBeforeStrip = fullUrl;
-					console.warn('[wx.config] retry with base url (no query):', baseUrl);
 					fetchWeChatJssdkSign(baseUrl)
 						.then(function (sign2) {
 							if (!sign2) {
-								weChatJssdkConfigured = false;
-								updateFabOpenLayer();
-								showAppOpenFailTip(formatWxConfigErrorTip(err, urlForWx));
 								resolve(false);
 								return;
 							}
 							applyWxConfig(sign2, baseUrl).then(resolve);
 						})
 						.catch(function () {
-							weChatJssdkConfigured = false;
-							updateFabOpenLayer();
-							showAppOpenFailTip(formatWxConfigErrorTip(err, urlForWx));
 							resolve(false);
 						});
 				});
 			});
 		}
 
-		function tryTriggerWxOpenLaunchApp() {
-			var tag = document.getElementById('launch-btn');
-			if (!tag) return false;
-			try {
-				if (tag.shadowRoot) {
-					var inner = tag.shadowRoot.querySelector('button');
-					if (inner && typeof inner.click === 'function') {
-						inner.click();
-						return true;
-					}
-				}
-				if (typeof tag.click === 'function') {
-					tag.click();
-					return true;
-				}
-			} catch (eWx) {
-				console.warn('[wx-open-launch-app] trigger', eWx);
-			}
-			return false;
-		}
-
 		function refreshWxLaunchTagAttrs() {
 			var tag = document.getElementById('launch-btn');
 			if (!tag) return;
 			try {
-				if (WECHAT_OPEN_APP_ID) tag.setAttribute('appid', WECHAT_OPEN_APP_ID);
+				tag.setAttribute('appid', WECHAT_OPEN_APP_ID);
 				tag.setAttribute('extinfo', buildWeChatLaunchExtinfo());
-			} catch (eAttr) {
-				console.warn('[wx-open-launch-app] set attrs', eAttr);
-			}
+			} catch (eA) {}
 		}
 
-		/** wx.config 成功后即切换为开放标签按钮(不再依赖 offsetHeight 检测) */
 		function updateFabOpenLayer() {
 			var dock = document.getElementById('fabDock');
 			var hit = document.getElementById('fabWxHit');
@@ -1604,119 +1404,62 @@
 		function scheduleWxOpenTagRefresh() {
 			refreshWxLaunchTagAttrs();
 			updateFabOpenLayer();
-			var delays = [100, 400, 1000, 2000];
-			for (var i = 0; i < delays.length; i++) {
-				(function (ms) {
-					window.setTimeout(function () {
-						if (!weChatJssdkConfigured) return;
-						refreshWxLaunchTagAttrs();
-						updateFabOpenLayer();
-					}, ms);
-				})(delays[i]);
-			}
-		}
-
-		var openAppFabClickLock = 0;
-		function handleOpenAppFabClick() {
-			var now = Date.now();
-			if (now - openAppFabClickLock < 500) return;
-			openAppFabClickLock = now;
-			tryOpenHBuilderApp();
-		}
-
-		function bindOpenAppFabClick() {
-			var btn = document.getElementById('openApp');
-			if (btn) {
-				btn.addEventListener('click', function (e) {
-					if (e && e.cancelable) e.preventDefault();
-					handleOpenAppFabClick();
-				});
-			}
+			[200, 600, 1500].forEach(function (ms) {
+				setTimeout(function () {
+					if (!weChatJssdkConfigured) return;
+					refreshWxLaunchTagAttrs();
+					updateFabOpenLayer();
+				}, ms);
+			});
 		}
 
 		function bindWeChatLaunchTagEvents() {
 			var tag = document.getElementById('launch-btn');
 			if (!tag) return;
 			refreshWxLaunchTagAttrs();
-			tag.addEventListener('launch', function (e) {
-				console.log('[wx-open-launch-app] launch ok', e && e.detail);
-				reportWxDebug('wx-open-launch-app launch', e && e.detail ? e.detail : { errMsg: 'launch:ok' }, [
-					'extinfo=' + (tag.getAttribute('extinfo') || '').slice(0, 200)
-				]);
+			tag.addEventListener('launch', function () {
+				console.log('[wx-open-launch-app] launch ok');
 			});
 			tag.addEventListener('error', function (e) {
 				var detail = e && e.detail;
-				console.warn('[wx-open-launch-app]', detail);
-				reportWxDebug('wx-open-launch-app error', detail, [
-					'openTag appid=' + WECHAT_OPEN_APP_ID,
-					'完整 errMsg=' +
-						(detail && detail.errMsg
-							? String(detail.errMsg)
-							: detail && detail.errmsg
-								? String(detail.errmsg)
-								: '(无)')
-				]);
 				var errMsg =
 					detail && detail.errMsg
 						? String(detail.errMsg)
 						: detail && detail.errmsg
 							? String(detail.errmsg)
 							: '';
-				if (/launch:fail/i.test(errMsg)) {
-					showAppOpenFailTip(
-						'微信未能唤起 App(' +
-							errMsg +
-							')。请确认:①已安装 U店在哪;②开放标签 appid 为移动应用 ID;③开放平台已绑定域名与 App。'
-					);
-				} else {
-					showAppOpenFailTip(
-						errMsg
-							? '开放标签错误:' + errMsg
-							: '开放标签唤起失败,请用 wxDebug=1 查看详情。'
-					);
-				}
+				console.warn('[wx-open-launch-app]', detail);
+				showAppOpenFailTip(
+					errMsg
+						? '未能唤起 App:' + errMsg
+						: '未能唤起 App,请确认已安装 U店在哪,且开放平台已绑定服务号与移动应用。'
+				);
 			});
 		}
 
-		/**
-		 * 进入页即 GET /wx/getWxConfig(任意浏览器都会请求,便于联调);
-		 * 仅微信内且签名成功后再 wx.config + 展示开放标签按钮。
-		 */
 		function initWeChatOpenLaunchApp() {
-			var inWx = isWeChatInAppBrowser();
+			if (!isWeChatInAppBrowser()) return Promise.resolve(false);
 			wxConfigSignRetriedBaseUrl = false;
 			var signPageUrl = getWxConfigSignUrl();
-			var reqUrl = buildWxGetConfigRequestUrl(signPageUrl);
-
-			if (inWx) {
-				var domainHint = checkWxJsSafeDomainHint();
-				if (domainHint) {
-					console.warn('[wx]', domainHint);
-					showAppOpenFailTip(domainHint);
-				}
+			if (typeof wx === 'undefined') {
+				console.warn('[wx] jweixin not loaded');
+				return Promise.resolve(false);
 			}
-
-			console.log('[wx] GET', reqUrl);
-
+			bindWeChatLaunchTagEvents();
 			return fetchWeChatJssdkSign(signPageUrl)
 				.then(function (sign) {
-					if (!inWx) {
-						if (!sign) {
-							console.warn('[wx] getWxConfig empty (non-wechat preview)');
-						}
-						return false;
-					}
-					if (typeof wx === 'undefined') {
-						console.warn('[wx] jweixin not loaded');
+					if (!sign) {
+						console.warn('[wx] getWxConfig empty');
 						return false;
 					}
-					bindWeChatLaunchTagEvents();
-					if (!sign) {
-						console.warn('[wx] GET ' + WECHAT_GET_WX_CONFIG_PATH + ' — empty or invalid sign payload');
-						showAppOpenFailTip(
-							'微信 JSSDK:getWxConfig 未返回可用的 appId/timestamp/nonceStr/signature。'
+					if (sign.appId !== WECHAT_MP_APP_ID) {
+						console.warn(
+							'[wx] config appId=' +
+								sign.appId +
+								' 与 WECHAT_MP_APP_ID=' +
+								WECHAT_MP_APP_ID +
+								' 不一致,请后端用服务号 ID 签名'
 						);
-						return false;
 					}
 					return applyWxConfig(sign, signPageUrl);
 				})
@@ -1726,61 +1469,46 @@
 				});
 		}
 
-		function isCustomAppSchemeUrl(url) {
-			var s = String(url || '').trim();
-			if (!s) return false;
-			if (/^https?:/i.test(s)) return false;
-			return /^[a-z][a-z0-9+.-]*:/i.test(s);
+		function showAppOpenFailTip(msg) {
+			var tip = msg || '未能打开 App,请确认已安装最新版「U店在哪」。';
+			if (typeof uni !== 'undefined' && typeof uni.showToast === 'function') {
+				uni.showToast({ title: tip, icon: 'none', duration: 2800 });
+			} else if (isWeChatInAppBrowser()) {
+				window.alert(tip);
+			} else {
+				console.warn('[openApp]', tip);
+			}
 		}
 
+		/** 部分 WebView 对 location.href 拦截,用 a 标签点击略稳 */
 		function launchAppDeepLink(deepLink) {
-			deepLink = String(deepLink || '').trim();
-			if (!deepLink) return;
-			if (isCustomAppSchemeUrl(deepLink)) {
-				var anchor = document.getElementById('appDeepLinkAnchor');
-				if (!anchor) {
-					anchor = document.createElement('a');
-					anchor.id = 'appDeepLinkAnchor';
-					anchor.setAttribute('aria-hidden', 'true');
-					anchor.style.cssText =
-						'position:fixed;left:-9999px;top:0;width:1px;height:1px;opacity:0;pointer-events:none;';
-					document.body.appendChild(anchor);
-				}
-				anchor.setAttribute('href', deepLink);
-				anchor.click();
-				return;
-			}
+			
+			try {
+				var a = document.createElement('a');
+				a.href = deepLink;
+				a.setAttribute('target', '_self');
+				document.body.appendChild(a);
+				a.click();
+				document.body.removeChild(a);
+			} catch (e1) {}
 			try {
 				window.location.href = deepLink;
-			} catch (eHref) {}
+			} catch (e2) {}
 		}
 
 		/**
 		 * 有 plus:检测 App 是否安装后 openURL;深链形如 shopro://{APP_UNI_STORE_PATH}?…
-		 * 系统浏览器:scheme 唤起;微信内优先 wx-open-launch-app,失败再 scheme(不再弹「在浏览器中打开」)
+		 * 系统浏览器:唤起 scheme;微信内常拦截 scheme,需「在浏览器打开」
 		 */
 		function tryOpenHBuilderApp() {
 			var inWx = isWeChatInAppBrowser();
-			showFabToast('正在尝试打开 U店在哪…');
-
+			if (inWx && weChatJssdkConfigured) {
+				return;
+			}
 			if (inWx && !weChatJssdkConfigured) {
 				showAppOpenFailTip(
-					'微信 JSSDK 未就绪:请先关注测试号并确保 wx.config 成功。链接可加 wxDebug=1 查看 config 报错。'
+					'微信内请先完成 JSSDK 配置(服务号 wx412792c77f47babd 签名)。可加 ?wxDebug=1 查看报错。'
 				);
-				launchAppDeepLink(buildAppDeepLink());
-				return;
-			}
-
-			if (inWx && weChatJssdkConfigured) {
-				refreshWxLaunchTagAttrs();
-				updateFabOpenLayer();
-				if (tryTriggerWxOpenLaunchApp()) {
-					showFabToast('正在打开 U店在哪…');
-				} else {
-					showAppOpenFailTip(
-						'请点击底部 APP内打开 图片按钮;若仍无效,请用 wxDebug=1 查看开放标签是否 launch:fail。'
-					);
-				}
 				return;
 			}
 
@@ -1798,19 +1526,20 @@
 				} catch (e) {
 					console.warn(e);
 				}
+				if (installed === false) {
+					showDownloadTip();
+					return;
+				}
 				try {
 					plus.runtime.openURL(deepLink);
 				} catch (e2) {
 					console.warn(e2);
-					if (installed === false) {
-						showDownloadTip();
-					} else if (!inWx) {
-						showAppOpenFailTip();
-					}
+					showDownloadTip();
 				}
 				return;
 			}
 
+			var t0 = Date.now();
 			var done = false;
 			function finish() {
 				if (done) return;
@@ -1831,17 +1560,13 @@
 				launchAppDeepLink(deepLink);
 			} catch (e3) {
 				finish();
-				if (!inWx) showAppOpenFailTip();
+				showDownloadTip();
 				return;
 			}
 
-			/**
-			 * 微信内 scheme 常被拦截且页面仍 visible,原 2.6s 后 showDownloadTip 会误报「请到应用商店下载」。
-			 * 与 shareDynamic 一致:超时仅收尾,不弹下载提示。
-			 */
 			window.setTimeout(function () {
 				finish();
-			}, 3200);
+			}, 2600);
 		}
 
 		function qs() {
@@ -2606,28 +2331,20 @@
 		}
 
 		function fetchShareClosedStoreRecommend(storeIdStr) {
-			var latRaw = (q('userLat') || q('latitude') || q('lat') || q('weidu')).trim();
-			var lngRaw = (q('userLng') || q('longitude') || q('lon') || q('jingdu')).trim();
-			var userLat =
-				latRaw !== '' && !isNaN(Number(latRaw)) ? Number(latRaw) : DEFAULT_REC_USER_LAT;
-			var userLng =
-				lngRaw !== '' && !isNaN(Number(lngRaw)) ? Number(lngRaw) : DEFAULT_REC_USER_LNG;
+			var loc = getClosedRecommendUserLocation();
 
 			var page = parseInt(q('page') || '1', 10);
 			var pageSize = parseInt(q('pageSize') || '10', 10);
 			if (isNaN(page) || page < 1) page = 1;
 			if (isNaN(pageSize) || pageSize < 1) pageSize = 10;
 
-			var userCityRaw = (q('userCity') || q('city') || '').trim();
-			var userCity = userCityRaw !== '' ? userCityRaw : DEFAULT_REC_USER_CITY;
-
 			var body = {
 				page: page,
 				pageSize: pageSize,
 				storeId: String(storeIdStr || ''),
-				userCity: userCity,
-				userLat: userLat,
-				userLng: userLng
+				userCity: loc.userCity,
+				userLat: loc.userLat,
+				userLng: loc.userLng
 			};
 
 			return fetch(API_LIFE_AI_BASE + STORE_GLOBAL_RECOMMEND_PATH, {
@@ -2999,16 +2716,12 @@
 			bindMarketingMore();
 			bindStaffSection();
 			var launchTag = document.getElementById('launch-btn');
-			if (launchTag && WECHAT_OPEN_APP_ID) {
-				launchTag.setAttribute('appid', WECHAT_OPEN_APP_ID);
-			}
-			bindOpenAppFabClick();
-			updateFabOpenLayer();
-			if (isWxDebugOn()) {
-				reportWxDebug('page load', { errMsg: 'wxDebug=1 已开启' }, [
-					'UA=' + (navigator.userAgent || '').slice(0, 120),
-					'page=' + location.href.split('#')[0]
-				]);
+			if (launchTag) launchTag.setAttribute('appid', WECHAT_OPEN_APP_ID);
+			var openBtn = document.getElementById('openApp');
+			if (openBtn) {
+				openBtn.addEventListener('click', function () {
+					tryOpenHBuilderApp();
+				});
 			}
 			initWeChatOpenLaunchApp();
 		}