lifeAiFetch.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /**
  2. * 分享页「更多推荐」AI 接口请求(HTTPS 页在 iOS 微信内不能直连 HTTP:9100,须走同源 alienStore 网关)。
  3. * URL 可用 lifeAiBase 覆盖,例如 lifeAiBase=https://test.ailien.shop/alienStore
  4. */
  5. (function (global) {
  6. 'use strict';
  7. var API_LIFE_AI_HTTP = 'http://183.252.196.135:9100';
  8. function isPageHttps() {
  9. return (location.protocol || '').toLowerCase() === 'https:';
  10. }
  11. function isIosWxBrowser() {
  12. var ua = navigator.userAgent || '';
  13. return /iphone|ipad|ipod/i.test(ua) && /micromessenger/i.test(ua);
  14. }
  15. function readQueryParam(name) {
  16. var params = new URLSearchParams(location.search || '');
  17. var v = params.get(name);
  18. if (v != null) return String(v);
  19. var hash = location.hash || '';
  20. var qi = hash.indexOf('?');
  21. if (qi >= 0) {
  22. var hp = new URLSearchParams(hash.slice(qi + 1));
  23. var hv = hp.get(name);
  24. if (hv != null) return String(hv);
  25. }
  26. return '';
  27. }
  28. /**
  29. * @param {string} [alienStoreBase] 页面内 API_BASE,如 https://test.ailien.shop/alienStore
  30. */
  31. function resolveLifeAiApiBases(alienStoreBase) {
  32. var out = [];
  33. var seen = {};
  34. function push(base) {
  35. base = String(base || '').trim().replace(/\/+$/, '');
  36. if (!base || seen[base]) return;
  37. seen[base] = true;
  38. out.push(base);
  39. }
  40. var custom = readQueryParam('lifeAiBase').trim();
  41. if (custom) push(custom);
  42. var host = (location.hostname || '').toLowerCase();
  43. if (host === 'test.ailien.shop' || host === 'uat.ailien.shop') {
  44. push('https://' + host + '/alienStore');
  45. } else if (alienStoreBase) {
  46. push(String(alienStoreBase).replace(/\/+$/, ''));
  47. }
  48. /* iOS+HTTPS 会拦截明文 fetch;Android 微信常仍可回落直连 IP */
  49. if (!isPageHttps() || !isIosWxBrowser()) {
  50. push(API_LIFE_AI_HTTP);
  51. }
  52. return out;
  53. }
  54. function isLifeAiApiOk(res) {
  55. if (!res || typeof res !== 'object') return false;
  56. if (res.success === false) return false;
  57. var c = res.code;
  58. return c === 200 || c === '200' || Number(c) === 200;
  59. }
  60. function extractRecommendList(res) {
  61. if (!res || typeof res !== 'object') return [];
  62. if (!isLifeAiApiOk(res)) return [];
  63. var raw = res.data != null ? res.data : res.result;
  64. if (Array.isArray(raw)) return raw;
  65. if (raw && typeof raw === 'object') {
  66. var keys = [
  67. 'list',
  68. 'records',
  69. 'rows',
  70. 'content',
  71. 'stores',
  72. 'storeList',
  73. 'storeVos',
  74. 'items'
  75. ];
  76. for (var i = 0; i < keys.length; i++) {
  77. if (Array.isArray(raw[keys[i]])) return raw[keys[i]];
  78. }
  79. }
  80. if (Array.isArray(res.list)) return res.list;
  81. if (Array.isArray(res.records)) return res.records;
  82. return [];
  83. }
  84. /**
  85. * 按顺序尝试多个 API 根地址,401/404/网络失败时换下一个。
  86. */
  87. function fetchLifeAiPostJson(alienStoreBase, apiPath, body) {
  88. var bases = resolveLifeAiApiBases(alienStoreBase);
  89. var idx = 0;
  90. function next(err) {
  91. if (idx >= bases.length) {
  92. return Promise.reject(err || new Error('lifeAi recommend failed'));
  93. }
  94. var url = bases[idx++] + apiPath;
  95. return fetch(url, {
  96. method: 'POST',
  97. mode: 'cors',
  98. credentials: 'omit',
  99. headers: {
  100. Accept: 'application/json',
  101. 'Content-Type': 'application/json;charset=UTF-8'
  102. },
  103. body: JSON.stringify(body)
  104. })
  105. .then(function (res) {
  106. if (!res.ok) {
  107. if (res.status === 401 || res.status === 403 || res.status === 404) {
  108. return next(new Error('HTTP ' + res.status));
  109. }
  110. throw new Error('HTTP ' + res.status);
  111. }
  112. return res.json();
  113. })
  114. .then(function (json) {
  115. if (json && (json.code === 401 || json.code === '401')) {
  116. return next(new Error('code 401'));
  117. }
  118. return json;
  119. })
  120. .catch(function (e) {
  121. return next(e);
  122. });
  123. }
  124. return next();
  125. }
  126. /**
  127. * @param {function(string): string} getParam 如 getMergedParam / mergedQ
  128. */
  129. function getMergedRecommendUserLocation(getParam, defaults) {
  130. defaults = defaults || {};
  131. var defLat = defaults.lat != null ? defaults.lat : 38.925747;
  132. var defLng = defaults.lng != null ? defaults.lng : 121.662531;
  133. var defCity = defaults.city || '大连市';
  134. var gp =
  135. typeof getParam === 'function'
  136. ? getParam
  137. : function (n) {
  138. return readQueryParam(n);
  139. };
  140. function pick() {
  141. var args = arguments;
  142. var i;
  143. for (i = 0; i < args.length; i++) {
  144. var v = String(gp(args[i]) || '').trim();
  145. if (v) return v;
  146. }
  147. return '';
  148. }
  149. var latRaw = pick('userLat', 'latitude', 'lat', 'weidu');
  150. var lngRaw = pick('userLng', 'longitude', 'lon', 'lng', 'jingdu');
  151. var cityRaw = pick('userCity', 'city');
  152. return {
  153. userLat:
  154. latRaw !== '' && !isNaN(Number(latRaw)) ? Number(latRaw) : defLat,
  155. userLng:
  156. lngRaw !== '' && !isNaN(Number(lngRaw)) ? Number(lngRaw) : defLng,
  157. userCity: cityRaw !== '' ? cityRaw : defCity
  158. };
  159. }
  160. global.LifeAiFetch = {
  161. API_LIFE_AI_HTTP: API_LIFE_AI_HTTP,
  162. isPageHttps: isPageHttps,
  163. isIosWxBrowser: isIosWxBrowser,
  164. resolveLifeAiApiBases: resolveLifeAiApiBases,
  165. isLifeAiApiOk: isLifeAiApiOk,
  166. extractRecommendList: extractRecommendList,
  167. fetchLifeAiPostJson: fetchLifeAiPostJson,
  168. getMergedRecommendUserLocation: getMergedRecommendUserLocation
  169. };
  170. })(typeof window !== 'undefined' ? window : this);