|
@@ -801,232 +801,47 @@
|
|
|
return pathPart.replace(/^\/+/, '');
|
|
return pathPart.replace(/^\/+/, '');
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /** App shopro / wx extinfo:item 须双重 URL 编码;若已是 %257B… 则不再编码 */
|
|
|
|
|
- function formatItemForShoproQuery(rawItem) {
|
|
|
|
|
- var s = String(rawItem || '').trim();
|
|
|
|
|
- if (!s) return '';
|
|
|
|
|
- if (/^%25(?:7B|5B|22)/i.test(s)) {
|
|
|
|
|
- return s;
|
|
|
|
|
- }
|
|
|
|
|
- if (/^%7B/i.test(s)) {
|
|
|
|
|
- return encodeURIComponent(s);
|
|
|
|
|
- }
|
|
|
|
|
- var parsed = tryParseJsonObject(s);
|
|
|
|
|
- if (parsed) {
|
|
|
|
|
- try {
|
|
|
|
|
- return encodeURIComponent(encodeURIComponent(JSON.stringify(parsed)));
|
|
|
|
|
- } catch (eJson) {}
|
|
|
|
|
- }
|
|
|
|
|
- if (s.charAt(0) === '{' || s.charAt(0) === '[') {
|
|
|
|
|
- return encodeURIComponent(encodeURIComponent(s));
|
|
|
|
|
- }
|
|
|
|
|
- return encodeURIComponent(encodeURIComponent(s));
|
|
|
|
|
|
|
+ function appendFromShareDynamicToRaw(qs) {
|
|
|
|
|
+ var s = String(qs || '').trim();
|
|
|
|
|
+ if (!s) return 'fromShareDynamic=1';
|
|
|
|
|
+ var pad = '&' + s + '&';
|
|
|
|
|
+ if (/[&?](fromShareDynamic|FROMSHAREDYNAMIC)=/i.test(pad)) return s;
|
|
|
|
|
+ return s + '&fromShareDynamic=1';
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * 与 shareIndex buildAppLaunchQueryParams 类似:先解析 sourceId/sourceType/userId,
|
|
|
|
|
- * 再拼有序 query,避免 fromHomeFeed=1 触发首页种子导致 newdetails「操作无效」。
|
|
|
|
|
- */
|
|
|
|
|
- function resolveShareDynamicLaunchMeta() {
|
|
|
|
|
- var blob = parseShareDynamicItemBlob();
|
|
|
|
|
- if (!blob) blob = parseOptionsItem();
|
|
|
|
|
- var sourceId =
|
|
|
|
|
- getMergedParam('sourceId') ||
|
|
|
|
|
- getMergedParam('dynamicId') ||
|
|
|
|
|
- getMergedParam('id') ||
|
|
|
|
|
- q('dynamicId') ||
|
|
|
|
|
- q('id');
|
|
|
|
|
- if (!sourceId && blob && blob.id != null && String(blob.id).trim() !== '') {
|
|
|
|
|
- sourceId = String(blob.id);
|
|
|
|
|
- }
|
|
|
|
|
- var sourceType =
|
|
|
|
|
- getMergedParam('sourceType') ||
|
|
|
|
|
- getMergedParam('businessType') ||
|
|
|
|
|
- q('sourceType') ||
|
|
|
|
|
- q('businessType');
|
|
|
|
|
- if (!sourceType && blob && blob.type != null && String(blob.type).trim() !== '') {
|
|
|
|
|
- sourceType = String(blob.type);
|
|
|
|
|
- }
|
|
|
|
|
- var userId = getMergedParam('userId') || q('userId');
|
|
|
|
|
- if (!userId && blob) {
|
|
|
|
|
- if (blob.userId != null && String(blob.userId).trim() !== '') {
|
|
|
|
|
- userId = String(blob.userId);
|
|
|
|
|
- } else if (blob.createdUserId != null && String(blob.createdUserId).trim() !== '') {
|
|
|
|
|
- userId = String(blob.createdUserId);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- return {
|
|
|
|
|
- blob: blob,
|
|
|
|
|
- sourceId: String(sourceId || '').trim(),
|
|
|
|
|
- sourceType: String(sourceType || '').trim(),
|
|
|
|
|
- userId: String(userId || '').trim()
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ function rawQueryHasItem(qs) {
|
|
|
|
|
+ return /(?:^|&)item=/i.test('&' + String(qs || '') + '&');
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 固定顺序:item → needShowMore → fromHomeFeed(0) → fromShareDynamic(1) → sourceId/dynamicId/sourceType/userId → 其余
|
|
|
|
|
- * compact:微信 extinfo 超长时不带 item,仅 id 类参数(App 内再拉详情)
|
|
|
|
|
|
|
+ * 唤起 App 时原样透传 query:优先保留 URL 原始编码(item 双重编码、OSS 的 &fm= 等不被 URLSearchParams 截断/重编)。
|
|
|
|
|
+ * search 与 hash 内 ? 后均可能有参数;hash 覆盖 search(与 mergeSearchAndHashParams 一致),含 item 的一侧优先。
|
|
|
*/
|
|
*/
|
|
|
- function buildShareDynamicLaunchSegs(options) {
|
|
|
|
|
- options = options || {};
|
|
|
|
|
- var compact = !!options.compact;
|
|
|
|
|
- var params = mergeSearchAndHashParams();
|
|
|
|
|
- var meta = resolveShareDynamicLaunchMeta();
|
|
|
|
|
- var segs = [];
|
|
|
|
|
- var skipKeys = {
|
|
|
|
|
- item: 1,
|
|
|
|
|
- needshowmore: 1,
|
|
|
|
|
- fromhomefeed: 1,
|
|
|
|
|
- fromsharedynamic: 1,
|
|
|
|
|
- sourceid: 1,
|
|
|
|
|
- dynamicid: 1,
|
|
|
|
|
- sourcetype: 1,
|
|
|
|
|
- userid: 1,
|
|
|
|
|
- id: 1
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ function getRawMergedQueryForAppOpen() {
|
|
|
|
|
+ var rawSearch =
|
|
|
|
|
+ location.search && location.search.length > 1 ? location.search.slice(1) : '';
|
|
|
|
|
+ var hash0 = location.hash || '';
|
|
|
|
|
+ var hqi0 = hash0.indexOf('?');
|
|
|
|
|
+ var rawHashQ = hqi0 >= 0 ? hash0.slice(hqi0 + 1) : '';
|
|
|
|
|
|
|
|
- if (!compact) {
|
|
|
|
|
- var itemForShopro = '';
|
|
|
|
|
- try {
|
|
|
|
|
- itemForShopro = getMergedParam('item');
|
|
|
|
|
- } catch (eGi) {
|
|
|
|
|
- itemForShopro = '';
|
|
|
|
|
- }
|
|
|
|
|
- if (!itemForShopro || String(itemForShopro).trim() === '') {
|
|
|
|
|
- itemForShopro = params.get('item') || '';
|
|
|
|
|
- }
|
|
|
|
|
- if (itemForShopro && String(itemForShopro).trim()) {
|
|
|
|
|
- segs.push('item=' + formatItemForShoproQuery(itemForShopro));
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- var nsmRaw = params.get('needShowMore');
|
|
|
|
|
- var nsmOut =
|
|
|
|
|
- nsmRaw != null && String(nsmRaw).trim() !== '' ? String(nsmRaw).trim() : 'true';
|
|
|
|
|
- segs.push('needShowMore=' + encodeURIComponent(nsmOut));
|
|
|
|
|
- /** 分享 H5 唤起:勿用首页种子 fromHomeFeed=1,否则 newdetails 易白屏并提示「操作无效」 */
|
|
|
|
|
- segs.push('fromHomeFeed=0');
|
|
|
|
|
- segs.push('fromShareDynamic=1');
|
|
|
|
|
|
|
+ if (!rawSearch && !rawHashQ) return '';
|
|
|
|
|
|
|
|
- if (meta.sourceId) {
|
|
|
|
|
- segs.push('sourceId=' + encodeURIComponent(meta.sourceId));
|
|
|
|
|
- segs.push('dynamicId=' + encodeURIComponent(meta.sourceId));
|
|
|
|
|
- }
|
|
|
|
|
- if (meta.sourceType) {
|
|
|
|
|
- segs.push('sourceType=' + encodeURIComponent(meta.sourceType));
|
|
|
|
|
- }
|
|
|
|
|
- if (meta.userId) {
|
|
|
|
|
- segs.push('userId=' + encodeURIComponent(meta.userId));
|
|
|
|
|
|
|
+ if (rawHashQ && rawSearch) {
|
|
|
|
|
+ if (rawQueryHasItem(rawHashQ)) return rawHashQ;
|
|
|
|
|
+ if (rawQueryHasItem(rawSearch)) return rawSearch;
|
|
|
|
|
+ return rawHashQ;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- if (!compact) {
|
|
|
|
|
- params.forEach(function (val, key) {
|
|
|
|
|
- var kl = String(key || '')
|
|
|
|
|
- .trim()
|
|
|
|
|
- .toLowerCase();
|
|
|
|
|
- if (!kl || skipKeys[kl]) return;
|
|
|
|
|
- if (val == null) return;
|
|
|
|
|
- var vs = String(val);
|
|
|
|
|
- if (vs === '') return;
|
|
|
|
|
- segs.push(encodeURIComponent(key) + '=' + encodeURIComponent(vs));
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return segs;
|
|
|
|
|
|
|
+ return rawHashQ || rawSearch;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function buildAppOpenQueryStringMerged() {
|
|
function buildAppOpenQueryStringMerged() {
|
|
|
- var params = mergeSearchAndHashParams();
|
|
|
|
|
-
|
|
|
|
|
- /** newdetails onLoad:仅当地址栏未带 item 时补全;同时按需补顶层 imagePath */
|
|
|
|
|
- if (!params.has('item')) {
|
|
|
|
|
- var itemObj = parseOptionsItem();
|
|
|
|
|
- var imagePath = getMergedParam('imagePath');
|
|
|
|
|
- if (!imagePath && itemObj && itemObj.imagePath != null && String(itemObj.imagePath).trim() !== '') {
|
|
|
|
|
- imagePath = String(itemObj.imagePath);
|
|
|
|
|
- }
|
|
|
|
|
- if (!imagePath) {
|
|
|
|
|
- var carouselUrls = collectImageUrlsFromUrl();
|
|
|
|
|
- if (carouselUrls && carouselUrls.length) {
|
|
|
|
|
- imagePath = carouselUrls.join(',');
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- imagePath = normalizeMediaUrl(imagePath) || imagePath;
|
|
|
|
|
- }
|
|
|
|
|
- var dynId =
|
|
|
|
|
- getMergedParam('sourceId') ||
|
|
|
|
|
- getMergedParam('dynamicId') ||
|
|
|
|
|
- getMergedParam('id') ||
|
|
|
|
|
- q('id');
|
|
|
|
|
- if (!dynId && itemObj && itemObj.id != null && String(itemObj.id).trim() !== '') {
|
|
|
|
|
- dynId = String(itemObj.id);
|
|
|
|
|
- }
|
|
|
|
|
- var base = {};
|
|
|
|
|
- if (itemObj) {
|
|
|
|
|
- try {
|
|
|
|
|
- base = JSON.parse(JSON.stringify(itemObj));
|
|
|
|
|
- } catch (eCopy) {
|
|
|
|
|
- base = {};
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- if (imagePath) {
|
|
|
|
|
- base.imagePath = imagePath;
|
|
|
|
|
- }
|
|
|
|
|
- if (dynId != null && String(dynId).trim() !== '' && base.id == null) {
|
|
|
|
|
- base.id = dynId;
|
|
|
|
|
- }
|
|
|
|
|
- if (Object.keys(base).length) {
|
|
|
|
|
- try {
|
|
|
|
|
- params.set('item', JSON.stringify(base));
|
|
|
|
|
- } catch (eItem) {}
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (!params.has('imagePath')) {
|
|
|
|
|
- var ipTop = getMergedParam('imagePath');
|
|
|
|
|
- if (!ipTop) {
|
|
|
|
|
- var it2 = parseOptionsItem();
|
|
|
|
|
- if (it2 && it2.imagePath != null && String(it2.imagePath).trim() !== '') {
|
|
|
|
|
- ipTop = String(it2.imagePath);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- if (!ipTop) {
|
|
|
|
|
- var cu = collectImageUrlsFromUrl();
|
|
|
|
|
- if (cu && cu.length) {
|
|
|
|
|
- ipTop = cu.join(',');
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- if (ipTop) {
|
|
|
|
|
- params.set('imagePath', normalizeMediaUrl(ipTop) || ipTop);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ var rawQs = getRawMergedQueryForAppOpen();
|
|
|
|
|
+ if (rawQs) {
|
|
|
|
|
+ return '?' + appendFromShareDynamicToRaw(rawQs);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- var sid = params.get('storeId') || params.get('id') || '';
|
|
|
|
|
- if (sid && !params.has('storeId')) {
|
|
|
|
|
- params.set('storeId', sid);
|
|
|
|
|
- }
|
|
|
|
|
- /** 顶层 imagePath 若未 encode,URLSearchParams 会截断在 OSS 的 &fm= 等处;用原始串解析结果覆盖 */
|
|
|
|
|
- var ipMerged = getMergedParam('imagePath');
|
|
|
|
|
- if (ipMerged) {
|
|
|
|
|
- params.set('imagePath', normalizeMediaUrl(ipMerged) || ipMerged);
|
|
|
|
|
- }
|
|
|
|
|
- /**
|
|
|
|
|
- * 与 App utils/shareVideoPrecache.js 一致:无 shareVideoCk 时从页面解析首条 https .mp4,写入唤起链接,
|
|
|
|
|
- * 便于 App 端 downloadFile 预缓存并与 hash 对齐后优先本地播放。
|
|
|
|
|
- */
|
|
|
|
|
- try {
|
|
|
|
|
- var ckPrev = params.get('shareVideoCk');
|
|
|
|
|
- if (!ckPrev || String(ckPrev).trim() === '') {
|
|
|
|
|
- var pvid = pickFirstHttpsMp4ForShareVideoPrecache();
|
|
|
|
|
- if (pvid) {
|
|
|
|
|
- var hck = hashShareVideoRemoteUrl(pvid);
|
|
|
|
|
- if (hck) {
|
|
|
|
|
- params.set('shareVideoCk', hck);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- } catch (eShareCk) {}
|
|
|
|
|
- return '?' + buildShareDynamicLaunchSegs({ compact: false }).join('&');
|
|
|
|
|
|
|
+ var params = mergeSearchAndHashParams();
|
|
|
|
|
+ var qsOut = params.toString();
|
|
|
|
|
+ return qsOut ? '?' + appendFromShareDynamicToRaw(qsOut) : '';
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1106,14 +921,19 @@
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * wx-open-launch-app extinfo:与 buildAppUniPageLaunchUrl 一致(参照 shareIndex 短参数 + 有序 query)
|
|
|
|
|
- * 微信 extinfo 上限 1024;超长时去掉 item,保留 sourceId/sourceType/userId。
|
|
|
|
|
|
|
+ * wx-open-launch-app extinfo:与 buildAppUniPageLaunchUrl 一致,pages/newdetails/index?item=双重编码…
|
|
|
|
|
+ * 微信 extinfo 上限 1024 字符;超长时保留 item+needShowMore+fromHomeFeed+fromShareDynamic,仍超长则退化为 dynamicId。
|
|
|
*/
|
|
*/
|
|
|
function buildWeChatLaunchExtinfo() {
|
|
function buildWeChatLaunchExtinfo() {
|
|
|
- var path = getAppUniPathForShareDynamic().replace(/^\//, '');
|
|
|
|
|
- var fullQs = buildShareDynamicLaunchSegs({ compact: false }).join('&');
|
|
|
|
|
- var fullPage = fullQs ? path + '?' + fullQs : path;
|
|
|
|
|
- if (fullPage.length <= 1024) return fullPage;
|
|
|
|
|
|
|
+ var uniPage = buildAppUniPageLaunchUrl();
|
|
|
|
|
+ if (uniPage.length <= 1024) return uniPage;
|
|
|
|
|
+
|
|
|
|
|
+ var path = getAppUniPathForShareDynamic();
|
|
|
|
|
+ var rawQs = getRawMergedQueryForAppOpen();
|
|
|
|
|
+ if (rawQs) {
|
|
|
|
|
+ var packedRaw = path + '?' + appendFromShareDynamicToRaw(rawQs);
|
|
|
|
|
+ if (packedRaw.length <= 1024) return packedRaw;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
if (!/newdetails/i.test(path)) {
|
|
if (!/newdetails/i.test(path)) {
|
|
|
var deepOther = buildAppDeepLink().replace(/^shopro:\/\//i, '');
|
|
var deepOther = buildAppDeepLink().replace(/^shopro:\/\//i, '');
|
|
@@ -1121,23 +941,30 @@
|
|
|
return deepOther.slice(0, 1024);
|
|
return deepOther.slice(0, 1024);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- var compactQs = buildShareDynamicLaunchSegs({ compact: true }).join('&');
|
|
|
|
|
- var compactPage = compactQs ? path + '?' + compactQs : path;
|
|
|
|
|
- if (compactPage.length <= 1024) return compactPage;
|
|
|
|
|
-
|
|
|
|
|
- var meta = resolveShareDynamicLaunchMeta();
|
|
|
|
|
|
|
+ var blob = parseShareDynamicItemBlob();
|
|
|
var mini = new URLSearchParams();
|
|
var mini = new URLSearchParams();
|
|
|
- if (meta.sourceId) {
|
|
|
|
|
- mini.set('sourceId', meta.sourceId);
|
|
|
|
|
- mini.set('dynamicId', meta.sourceId);
|
|
|
|
|
- }
|
|
|
|
|
- if (meta.sourceType) mini.set('sourceType', meta.sourceType);
|
|
|
|
|
- if (meta.userId) mini.set('userId', meta.userId);
|
|
|
|
|
- mini.set('needShowMore', 'true');
|
|
|
|
|
- mini.set('fromHomeFeed', '0');
|
|
|
|
|
|
|
+ if (blob && blob.id != null && String(blob.id).trim() !== '') {
|
|
|
|
|
+ var did = String(blob.id).trim();
|
|
|
|
|
+ mini.set('dynamicId', did);
|
|
|
|
|
+ mini.set('sourceId', did);
|
|
|
|
|
+ }
|
|
|
|
|
+ var st =
|
|
|
|
|
+ getMergedParam('sourceType') ||
|
|
|
|
|
+ getMergedParam('type') ||
|
|
|
|
|
+ (blob && blob.type != null ? String(blob.type) : '');
|
|
|
|
|
+ if (st) mini.set('sourceType', st);
|
|
|
|
|
+ var nsmRaw = getMergedParam('needShowMore');
|
|
|
|
|
+ if (nsmRaw != null && String(nsmRaw).trim() !== '') {
|
|
|
|
|
+ mini.set('needShowMore', String(nsmRaw).trim());
|
|
|
|
|
+ }
|
|
|
|
|
+ var fhfRaw = getMergedParam('fromHomeFeed');
|
|
|
|
|
+ if (fhfRaw != null && String(fhfRaw).trim() !== '') {
|
|
|
|
|
+ mini.set('fromHomeFeed', String(fhfRaw).trim());
|
|
|
|
|
+ }
|
|
|
mini.set('fromShareDynamic', '1');
|
|
mini.set('fromShareDynamic', '1');
|
|
|
var shortPage = path + '?' + mini.toString();
|
|
var shortPage = path + '?' + mini.toString();
|
|
|
- return shortPage.length <= 1024 ? shortPage : shortPage.slice(0, 1024);
|
|
|
|
|
|
|
+ if (shortPage.length <= 1024) return shortPage;
|
|
|
|
|
+ return shortPage.slice(0, 1024);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function buildAppDeepLink() {
|
|
function buildAppDeepLink() {
|