@tmsfe/tms-core 0.0.22 → 0.0.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/distanceBetweenPoints.js +73 -0
- package/src/env.js +1 -1
- package/src/index.js +4 -2
- package/src/location/index.ts +1 -0
- package/src/report.js +1 -1
- package/dist/cloudService.js +0 -60
- package/dist/env-c7da70e1.js +0 -146
- package/dist/index-proxy.js +0 -243
- package/dist/index.js +0 -1764
- package/dist/objUtils-154b94db.js +0 -244
- package/dist/request-f8a4745b.js +0 -543
- package/dist/request.js +0 -3
- package/dist/storage-094c6ddb.js +0 -651
package/dist/index.js
DELETED
|
@@ -1,1764 +0,0 @@
|
|
|
1
|
-
import { R as Request, g as getLogManager, a as getRealtimeLogManager } from './request-f8a4745b.js';
|
|
2
|
-
import { g as getEnvInfo, a as getAuthInfo, s as setAuthInfo, i as isAppPageExist, b as getHomePage, c as setEnvInfo, d as setAppPagePaths } from './env-c7da70e1.js';
|
|
3
|
-
import { s as syncApi, r as roundStr, f as formatPlate, a as subStr, h as hidePhoneCenter, i as isValidPhone, b as isValidPlate, c as isValidAuthCode, d as formatTime, e as formatTimeStr, g as formatTimeWithDetails, j as dateToString, k as ipxInit, l as isIPX, m as getIpxClass, n as getIpxConfig, o as rpxToPx, p as storage } from './storage-094c6ddb.js';
|
|
4
|
-
import { m as md5, s as serialize } from './objUtils-154b94db.js';
|
|
5
|
-
import { callCloudFunc } from './cloudService.js';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @copyright 2020-present, Tencent, Inc. All rights reserved.
|
|
9
|
-
* @author Fenggang.Sun <fenggangsun@tencent.com>
|
|
10
|
-
* @file 快速上报数据,不处理过多逻辑,保证快速上报
|
|
11
|
-
*/
|
|
12
|
-
let simulatedUserIdCache; // 模拟用户id在内存里的缓存
|
|
13
|
-
|
|
14
|
-
const getSystemInfo$1 = () => {
|
|
15
|
-
const system = syncApi.getSystemInfoSync();
|
|
16
|
-
const {
|
|
17
|
-
model = '',
|
|
18
|
-
version: wxVersion = '',
|
|
19
|
-
platform = '',
|
|
20
|
-
SDKVersion = '',
|
|
21
|
-
host = ''
|
|
22
|
-
} = system;
|
|
23
|
-
return {
|
|
24
|
-
model,
|
|
25
|
-
wxVersion,
|
|
26
|
-
platform,
|
|
27
|
-
SDKVersion,
|
|
28
|
-
host
|
|
29
|
-
};
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const handleParamOfDifferentType = param => {
|
|
33
|
-
const data = new Array(41);
|
|
34
|
-
Object.keys(param).forEach(key => {
|
|
35
|
-
const valType = typeof param[key];
|
|
36
|
-
if (valType === 'string') data[key] = param[key];else if (valType === 'object') data[key] = JSON.stringify(param[key]);else data[key] = String(param[key]);
|
|
37
|
-
});
|
|
38
|
-
return data;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
const defAssign = (value, defaultValue) => value || defaultValue;
|
|
42
|
-
/**
|
|
43
|
-
* @class FastReport
|
|
44
|
-
* @classdesc 快速上报模块,不依赖用户标识和位置
|
|
45
|
-
*/
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
class FastReport {
|
|
49
|
-
/**
|
|
50
|
-
* @memberof FastReport
|
|
51
|
-
* @description 快速上报
|
|
52
|
-
* @param {Object} param 埋点数据
|
|
53
|
-
* @param {Boolean} simulatedUserId 是否上报模拟用户Id
|
|
54
|
-
* @param {Number} simulatedUserIdIndex 上报模拟用户ID时放在哪个字段
|
|
55
|
-
* @param {Boolean} reportShowScene 是否上报小程序onShow场景值
|
|
56
|
-
* @param {Boolean} appVer 是否上报小程序版本
|
|
57
|
-
* @returns {Promsie} 返回上报结果
|
|
58
|
-
*/
|
|
59
|
-
static report(param = {}, simulatedUserId = true, simulatedUserIdIndex = 40, reportShowScene = true, appVer = true) {
|
|
60
|
-
var _data$;
|
|
61
|
-
|
|
62
|
-
if (!param[27]) return Promise.reject('invalid report param');
|
|
63
|
-
const env = getEnvInfo();
|
|
64
|
-
const data = handleParamOfDifferentType(param);
|
|
65
|
-
data[9] = '2';
|
|
66
|
-
data[33] = encodeURIComponent(JSON.stringify(getSystemInfo$1()));
|
|
67
|
-
|
|
68
|
-
if (appVer) {
|
|
69
|
-
data[10] = defAssign(data[10], env.appVersion);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
data[26] = defAssign(data[26], (_data$ = data[27]) === null || _data$ === void 0 ? void 0 : _data$[0]);
|
|
73
|
-
data[28] = env.client;
|
|
74
|
-
|
|
75
|
-
if (reportShowScene && !data[29]) {
|
|
76
|
-
const appShowScene = wx.getStorageSync('appShowScene');
|
|
77
|
-
if (appShowScene) data[29] = String(appShowScene);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (simulatedUserId && !data[simulatedUserIdIndex]) {
|
|
81
|
-
data[simulatedUserIdIndex] = FastReport.getSimulatedUserId();
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return new Request().post('basic/event/upload', {
|
|
85
|
-
batch: [data]
|
|
86
|
-
}).catch(() => null);
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* @memberof FastReport
|
|
90
|
-
* @description 获取模拟的用户身份标识
|
|
91
|
-
* @returns {String} 用户的临时标识
|
|
92
|
-
*/
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
static getSimulatedUserId() {
|
|
96
|
-
// 优先使用内存级缓存
|
|
97
|
-
if (simulatedUserIdCache) return simulatedUserIdCache;
|
|
98
|
-
const key = 'SimulatedUserKey'; // 读取本地缓存记录的值
|
|
99
|
-
|
|
100
|
-
simulatedUserIdCache = wx.getStorageSync(key);
|
|
101
|
-
if (simulatedUserIdCache) return simulatedUserIdCache; // 生成新的值
|
|
102
|
-
|
|
103
|
-
const nonce = Math.random().toString(36).substr(2, 10);
|
|
104
|
-
simulatedUserIdCache = `${Date.now()}_${nonce}`;
|
|
105
|
-
wx.setStorage({
|
|
106
|
-
key,
|
|
107
|
-
data: simulatedUserIdCache
|
|
108
|
-
});
|
|
109
|
-
return simulatedUserIdCache;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* 小程序云控配置实现
|
|
116
|
-
*/
|
|
117
|
-
|
|
118
|
-
const parseAllCfgs = (configPaths, resData, defaultCfgs) => configPaths.map((path, index) => {
|
|
119
|
-
const found = resData.find(cfg => cfg.configPath === path);
|
|
120
|
-
|
|
121
|
-
if (found) {
|
|
122
|
-
return JSON.parse(found.configValue);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if (defaultCfgs && defaultCfgs[index]) {
|
|
126
|
-
return defaultCfgs[index];
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return {}; // 没找到配置,返回一个空对象
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
const formatConfigPaths = configPath => {
|
|
133
|
-
const configPaths = Array.isArray(configPath) ? configPath : [configPath];
|
|
134
|
-
const {
|
|
135
|
-
client
|
|
136
|
-
} = getEnvInfo();
|
|
137
|
-
configPaths.forEach((path, index) => {
|
|
138
|
-
configPaths[index] = path.replace(/\$\{client\}/, client);
|
|
139
|
-
});
|
|
140
|
-
return configPaths;
|
|
141
|
-
};
|
|
142
|
-
/**
|
|
143
|
-
* getConfig 批量拉取配置
|
|
144
|
-
* @description 拉取运营平台上的配置内容。关于运营平台的具体用法,参见{@link https://iwiki.woa.com/pages/viewpage.action?pageId=527948584}
|
|
145
|
-
* @category 配置相关
|
|
146
|
-
* @example <caption>拉取单个配置</caption>
|
|
147
|
-
* const cfg = await app.tms.getConfig('/${client}/violation/subscribe', {}, { title: '当前城市不支持订阅'})
|
|
148
|
-
* console.log(cfg); // 成功则返回服务端存储的配置,失败返回默认值
|
|
149
|
-
* @example <caption>批量拉取配置</caption>
|
|
150
|
-
const cfgs = await app.tms.getConfig([
|
|
151
|
-
'/${client}/home/service',
|
|
152
|
-
'/${client}/home/navbar',
|
|
153
|
-
], {}, [
|
|
154
|
-
[
|
|
155
|
-
{ caption: '违章代缴', icon: 'violation.png' }
|
|
156
|
-
],
|
|
157
|
-
{ title: '晚上好,欢迎~' }
|
|
158
|
-
]);
|
|
159
|
-
console.log(cfgs); // 成功则返回服务端存储的配置,失败返回默认值
|
|
160
|
-
* @param {String|Array} configPath 配置路径,单个路径或配置路径数组,支持替换${client}为当前小程序。例如在出行小程序,${client}会变替换为sinan
|
|
161
|
-
* @param {Object} extendAttr 扩展属性,传给配置服务用于检索哪个版本的配置适用于当前用户。
|
|
162
|
-
* @param {Object} [defaultCfg] 默认配置,请求失败返回默认值。
|
|
163
|
-
* @returns {Promise<Object|Array<Object>>}
|
|
164
|
-
* 有默认值时,请求失败返回默认值。无默认值时,请求失败返回Promise.reject
|
|
165
|
-
*/
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
function getConfig(configPath, extendAttr = {}, defaultCfg) {
|
|
169
|
-
if (Array.isArray(configPath)) {
|
|
170
|
-
// 复数形式
|
|
171
|
-
if (defaultCfg) {
|
|
172
|
-
// 有默认值
|
|
173
|
-
if (!Array.isArray(defaultCfg) || configPath.length !== defaultCfg.length) {
|
|
174
|
-
throw new Error('配置路径和默认值的数组长度不一致');
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const configPaths = formatConfigPaths(configPath);
|
|
180
|
-
const defaultCfgs = defaultCfg && (Array.isArray(defaultCfg) ? defaultCfg : [defaultCfg]) || null;
|
|
181
|
-
const extendAttrs = typeof extendAttr === 'string' ? extendAttr : JSON.stringify(extendAttr);
|
|
182
|
-
const api = new Request();
|
|
183
|
-
return api.post('marketing/config', {
|
|
184
|
-
extendAttrs,
|
|
185
|
-
configPaths
|
|
186
|
-
}).then((res = {}) => {
|
|
187
|
-
const {
|
|
188
|
-
errCode,
|
|
189
|
-
resData
|
|
190
|
-
} = res || {};
|
|
191
|
-
|
|
192
|
-
if (resData && resData.length > 0) {
|
|
193
|
-
const parsed = parseAllCfgs(configPaths, resData, defaultCfgs);
|
|
194
|
-
|
|
195
|
-
if (Array.isArray(configPath)) {
|
|
196
|
-
return parsed;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
return parsed[0];
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
if (defaultCfgs) {
|
|
203
|
-
return Array.isArray(configPath) ? defaultCfgs : defaultCfgs[0];
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
return Promise.reject({
|
|
207
|
-
errCode,
|
|
208
|
-
resData,
|
|
209
|
-
msg: `获取${configPaths.join(',')}配置失败,接口调用出错`
|
|
210
|
-
});
|
|
211
|
-
}).catch(e => {
|
|
212
|
-
if (defaultCfgs) {
|
|
213
|
-
return Promise.resolve(Array.isArray(configPath) ? defaultCfgs : defaultCfgs[0]);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
return Promise.reject({
|
|
217
|
-
err: e,
|
|
218
|
-
msg: `获取${configPaths.join(',')}配置失败,接口调用出错`
|
|
219
|
-
});
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* @copyright 2021-present, Tencent, Inc. All rights reserved.
|
|
225
|
-
* @author Davislu <davislu@tencent.com>
|
|
226
|
-
* @brief navigator provides some function to navigate pages in miniprogram.
|
|
227
|
-
*
|
|
228
|
-
*/
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* DEFN 空方法
|
|
232
|
-
* @private
|
|
233
|
-
* @returns {undefined} 无返回值
|
|
234
|
-
*/
|
|
235
|
-
const DEFN = () => {};
|
|
236
|
-
/**
|
|
237
|
-
* navigateToWebview 方法 跳转到小程序的 web-view 容器打开 H5
|
|
238
|
-
* @param {object} setting 配置信息
|
|
239
|
-
* @param {string} setting.url 需要跳转的 H5 连接
|
|
240
|
-
* @param {function} setting.complete 跳转成功后的回调函数
|
|
241
|
-
* @param {function} setting.message 用于获取 H5 中的 postMessage 的数据
|
|
242
|
-
* @param {object} setting.share 页面分享信息
|
|
243
|
-
* @param {string} setting.share.title 页面分享标题
|
|
244
|
-
* @param {string} setting.share.image 页面分享图片
|
|
245
|
-
* @param {string} setting.share.disable 是否禁用页面分享
|
|
246
|
-
* @param {object} setting.navbar 页面导航栏设置
|
|
247
|
-
* @param {string} setting.navbar.frontColor 导航栏字体颜色
|
|
248
|
-
* @param {string} setting.navbar.backgroundColor 导航栏背景颜色
|
|
249
|
-
* @returns {undefined} 无返回值
|
|
250
|
-
*/
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
const navigateToWebview = ({
|
|
254
|
-
url: webUrl,
|
|
255
|
-
complete = DEFN,
|
|
256
|
-
message = DEFN,
|
|
257
|
-
share = {},
|
|
258
|
-
navbar = {}
|
|
259
|
-
}) => {
|
|
260
|
-
const page = '/modules/x/webcontainer/webcontainer';
|
|
261
|
-
let query = `url=${encodeURIComponent(webUrl)}`;
|
|
262
|
-
|
|
263
|
-
if (share.disable) {
|
|
264
|
-
query += '&disableShare=true';
|
|
265
|
-
} else if (share.title) {
|
|
266
|
-
const image = share.image ? `&image=${encodeURIComponent(share.image)}` : '';
|
|
267
|
-
query += `&title=${encodeURIComponent(share.title)}${image}`;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
if (navbar.frontColor) query += `&navbarFront=${navbar.frontColor}`;
|
|
271
|
-
if (navbar.backgroundColor) query += `&navbarBg=${navbar.backgroundColor}`;
|
|
272
|
-
const url = `${page}${/\?/.test(page) ? '&' : '?'}${query}`;
|
|
273
|
-
const navSetting = {
|
|
274
|
-
url,
|
|
275
|
-
complete
|
|
276
|
-
};
|
|
277
|
-
navSetting.events = {
|
|
278
|
-
onMessage: message
|
|
279
|
-
};
|
|
280
|
-
wx.navigateTo(navSetting);
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
const obj = {
|
|
284
|
-
navigateToWebview
|
|
285
|
-
};
|
|
286
|
-
var nav = obj;
|
|
287
|
-
|
|
288
|
-
/* eslint-disable require-jsdoc */
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Copyright 2017-present, Tencent, Inc.
|
|
292
|
-
* All rights reserved.
|
|
293
|
-
*
|
|
294
|
-
* @desc: 自定义事件机制
|
|
295
|
-
* @author: kexinwu@tencent.com
|
|
296
|
-
*
|
|
297
|
-
*/
|
|
298
|
-
|
|
299
|
-
/**
|
|
300
|
-
* EventDispatcher 类 事件监听器
|
|
301
|
-
* @class EventDispatcher
|
|
302
|
-
* @classdesc 用于统一维护小程序的事件
|
|
303
|
-
*/
|
|
304
|
-
class EventDispatcher {
|
|
305
|
-
constructor() {
|
|
306
|
-
this.handlers = [];
|
|
307
|
-
}
|
|
308
|
-
/**
|
|
309
|
-
* @memberof EventDispatcher
|
|
310
|
-
* @param {String} type 事件名
|
|
311
|
-
* @param {Function} handler 事件处理函数
|
|
312
|
-
* @returns {Function} handler 事件处理函数
|
|
313
|
-
*/
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
bind(type, handler) {
|
|
317
|
-
if (typeof this.handlers[type] === 'undefined') {
|
|
318
|
-
this.handlers[type] = [];
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
this.handlers[type].push(handler);
|
|
322
|
-
}
|
|
323
|
-
/**
|
|
324
|
-
* @memberof EventDispatcher
|
|
325
|
-
* @param {String} type 事件名
|
|
326
|
-
* @param {Function} handler 事件处理函数
|
|
327
|
-
* @returns {Function} handler 事件处理函数
|
|
328
|
-
*/
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
bindOnce(type, handler) {
|
|
332
|
-
if (typeof this.handlers[type] === 'undefined') {
|
|
333
|
-
this.handlers[type] = [];
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
const isBinded = this.handlers[type].length === 0;
|
|
337
|
-
|
|
338
|
-
if (isBinded) {
|
|
339
|
-
this.handlers[type].push(handler);
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
/**
|
|
343
|
-
* @memberof EventDispatcher
|
|
344
|
-
* @param {String} type 事件名
|
|
345
|
-
* @returns {Void} 无返回值
|
|
346
|
-
*/
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
remove(type) {
|
|
350
|
-
this.handlers[type] = [];
|
|
351
|
-
}
|
|
352
|
-
/**
|
|
353
|
-
* @memberof EventDispatcher
|
|
354
|
-
* @param {String} type 事件名
|
|
355
|
-
* @param {Function} handler 事件处理函数
|
|
356
|
-
* @returns {Void} 无返回值
|
|
357
|
-
*/
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
unbind(type, handler) {
|
|
361
|
-
if (this.handlers[type] instanceof Array) {
|
|
362
|
-
const handlers = this.handlers[type];
|
|
363
|
-
let i = 0;
|
|
364
|
-
const l = handlers.length;
|
|
365
|
-
|
|
366
|
-
for (; i < l; i += 1) {
|
|
367
|
-
if (handlers[i] === handler) {
|
|
368
|
-
break;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
handlers.splice(i, 1);
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
/**
|
|
376
|
-
* @memberof EventDispatcher
|
|
377
|
-
* @param {Object} evt 事件描述
|
|
378
|
-
* @param {String} evt.type 事件类型
|
|
379
|
-
* @returns {Function} handler 事件处理函数
|
|
380
|
-
*/
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
dispatch(evt) {
|
|
384
|
-
if (this.handlers[evt.type] instanceof Array) {
|
|
385
|
-
const handlers = this.handlers[evt.type];
|
|
386
|
-
handlers.forEach(handler => handler(evt));
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
const event$2 = new EventDispatcher();
|
|
393
|
-
// 获取位置状态 -- true: 成功 false: 失败
|
|
394
|
-
let getLocationStatus = true; // eslint-disable-line
|
|
395
|
-
const LocationScopeKey = 'scope.userLocation';
|
|
396
|
-
// 获取授权设置promise
|
|
397
|
-
let getSettingPromise;
|
|
398
|
-
const EventName$1 = 'loc_status_changed';
|
|
399
|
-
/**
|
|
400
|
-
* @param {string} scopeKey 授权项
|
|
401
|
-
* @returns {promise} 授权页操作状态
|
|
402
|
-
*/
|
|
403
|
-
function openSetting(scopeKey = LocationScopeKey) {
|
|
404
|
-
return new Promise((resolve, reject) => {
|
|
405
|
-
// 打开设置页
|
|
406
|
-
wx.openSetting({
|
|
407
|
-
success: (res) => {
|
|
408
|
-
// 从authSetting中获取用户的授权结果
|
|
409
|
-
const { authSetting } = res;
|
|
410
|
-
const authResult = authSetting[scopeKey];
|
|
411
|
-
// 已经打开授权
|
|
412
|
-
if (authResult) {
|
|
413
|
-
resolve(res);
|
|
414
|
-
return;
|
|
415
|
-
}
|
|
416
|
-
// 未打开授权
|
|
417
|
-
reject(res);
|
|
418
|
-
},
|
|
419
|
-
fail: reject,
|
|
420
|
-
});
|
|
421
|
-
});
|
|
422
|
-
}
|
|
423
|
-
/**
|
|
424
|
-
* @description 更新获取位置状态
|
|
425
|
-
* @param {Boolean} status 成功true或失败false
|
|
426
|
-
* @returns {Promise<void>} 用户是否授权
|
|
427
|
-
*/
|
|
428
|
-
async function updateLocStatus(status) {
|
|
429
|
-
if (status && !getLocationStatus) {
|
|
430
|
-
let isAuthed = false;
|
|
431
|
-
try {
|
|
432
|
-
isAuthed = await getSetting();
|
|
433
|
-
getLocationStatus = true;
|
|
434
|
-
}
|
|
435
|
-
catch (e) {
|
|
436
|
-
if (isAuthed !== false) {
|
|
437
|
-
event$2.dispatch({ type: EventName$1 });
|
|
438
|
-
}
|
|
439
|
-
const timer = setTimeout(() => {
|
|
440
|
-
updateLocStatus(status);
|
|
441
|
-
clearTimeout(timer);
|
|
442
|
-
}, 200);
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
else {
|
|
446
|
-
getLocationStatus = status;
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
/**
|
|
450
|
-
* 获取用户授权信息
|
|
451
|
-
* @param { string } scopeKey 是否授权过位置信息
|
|
452
|
-
* @returns { Promise } 用户授权对象
|
|
453
|
-
*/
|
|
454
|
-
function getSetting(scopeKey = LocationScopeKey) {
|
|
455
|
-
if (getSettingPromise) { // eslint-disable-line
|
|
456
|
-
return getSettingPromise;
|
|
457
|
-
}
|
|
458
|
-
getSettingPromise = new Promise((resolve, reject) => {
|
|
459
|
-
wx.getSetting({
|
|
460
|
-
success: ({ authSetting = {} }) => {
|
|
461
|
-
resolve(authSetting[scopeKey]);
|
|
462
|
-
getSettingPromise = null;
|
|
463
|
-
},
|
|
464
|
-
fail: (err) => {
|
|
465
|
-
getSettingPromise = null;
|
|
466
|
-
const { errMsg = '' } = err || {};
|
|
467
|
-
// wx.getSetting接口没有响应时errMsg
|
|
468
|
-
const reason = 'getSetting:fail data no response';
|
|
469
|
-
// 部分机型上,wx.getSetting接口没有响应,此时,当做位置开关是打开的来处理
|
|
470
|
-
if (errMsg.indexOf(reason) > -1) {
|
|
471
|
-
resolve(true);
|
|
472
|
-
return;
|
|
473
|
-
}
|
|
474
|
-
reject(err);
|
|
475
|
-
},
|
|
476
|
-
});
|
|
477
|
-
});
|
|
478
|
-
return getSettingPromise;
|
|
479
|
-
}
|
|
480
|
-
/**
|
|
481
|
-
* getTextByReason 获取提示语文案
|
|
482
|
-
* @param {*} locationEnabled 是否开启位置授权
|
|
483
|
-
* @param {*} isSysAndWechatAllowedGetLoc 是否开启微信位置授权
|
|
484
|
-
* @returns {object} 提示语文案
|
|
485
|
-
*/
|
|
486
|
-
function getTextByReason(locationEnabled, isSysAndWechatAllowedGetLoc) {
|
|
487
|
-
const authLevelName = locationEnabled ? '微信' : '系统';
|
|
488
|
-
const confirmText = isSysAndWechatAllowedGetLoc ? '去开启' : '好的';
|
|
489
|
-
return { authLevelName, confirmText };
|
|
490
|
-
}
|
|
491
|
-
/**
|
|
492
|
-
* @function
|
|
493
|
-
* @description 获取设备系统信息
|
|
494
|
-
* @returns {Object} 设备系统信息
|
|
495
|
-
*/
|
|
496
|
-
function getSystemInfo() {
|
|
497
|
-
try {
|
|
498
|
-
const sys = wx.getSystemInfoSync();
|
|
499
|
-
// 方便开发时调试
|
|
500
|
-
if (sys.platform === 'devtools') {
|
|
501
|
-
sys.locationEnabled = true;
|
|
502
|
-
sys.locationAuthorized = true;
|
|
503
|
-
}
|
|
504
|
-
return sys;
|
|
505
|
-
}
|
|
506
|
-
catch (err) { }
|
|
507
|
-
}
|
|
508
|
-
/**
|
|
509
|
-
* @function
|
|
510
|
-
* @description 格式化城市编码
|
|
511
|
-
* @param {String} cityCode 城市编码,以国家编码开始
|
|
512
|
-
* @param {String} nationCode 国家编码
|
|
513
|
-
* @returns {String} 去掉国家编码后的城市编码
|
|
514
|
-
*/
|
|
515
|
-
function formatCityCode(cityCode, nationCode) {
|
|
516
|
-
let code = cityCode;
|
|
517
|
-
if (cityCode.startsWith(nationCode)) {
|
|
518
|
-
code = cityCode.substr(nationCode.length);
|
|
519
|
-
}
|
|
520
|
-
return code;
|
|
521
|
-
}
|
|
522
|
-
/**
|
|
523
|
-
* 格式化poi数据
|
|
524
|
-
* @param {Object} geo 逆地址解析接口返回的数据
|
|
525
|
-
* @returns {object} 格式化后的poi结果
|
|
526
|
-
*/
|
|
527
|
-
function formatPoi(geo) {
|
|
528
|
-
const { pois = [], address_reference: addressRefer } = geo;
|
|
529
|
-
if (pois.length) {
|
|
530
|
-
return pois[0];
|
|
531
|
-
}
|
|
532
|
-
if (addressRefer?.landmark_l2) {
|
|
533
|
-
return addressRefer.landmark_l2;
|
|
534
|
-
}
|
|
535
|
-
return {};
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
const event$1 = new EventDispatcher();
|
|
539
|
-
let getLocPromise = null;
|
|
540
|
-
// 用户位置信息缓存
|
|
541
|
-
let userLocationCache$1;
|
|
542
|
-
// 默认获取经纬度坐标的名称
|
|
543
|
-
const defaultLocationType = 'gcj02';
|
|
544
|
-
// 派发事件的名称
|
|
545
|
-
const EventName = 'loc_status_changed';
|
|
546
|
-
/**
|
|
547
|
-
* @private 将wx.getLocation获取位置方法用promise封装
|
|
548
|
-
* @param { string } type 获取位置类型
|
|
549
|
-
* @returns { Promise<any> } 用户位置信息
|
|
550
|
-
*/
|
|
551
|
-
function getWxLocation(type = defaultLocationType) {
|
|
552
|
-
return new Promise((resolve, reject) => {
|
|
553
|
-
wx.getLocation({
|
|
554
|
-
type,
|
|
555
|
-
success: (res) => {
|
|
556
|
-
resolve(res);
|
|
557
|
-
},
|
|
558
|
-
fail: reject,
|
|
559
|
-
});
|
|
560
|
-
});
|
|
561
|
-
}
|
|
562
|
-
// 是否开启监听位置变更
|
|
563
|
-
let isListenerLocation = false;
|
|
564
|
-
/**
|
|
565
|
-
* @class Location
|
|
566
|
-
* @classdesc 基于微信api,封装location相关的接口。 包括监听位置变化, 获取用户位置信息
|
|
567
|
-
* 获取位置授权等等。业务无关
|
|
568
|
-
*/
|
|
569
|
-
class LocationBase {
|
|
570
|
-
/**
|
|
571
|
-
* @private 开启监听位置变更,要在授权之后才能开启
|
|
572
|
-
*/
|
|
573
|
-
listenerLocation() {
|
|
574
|
-
if (!isListenerLocation) {
|
|
575
|
-
isListenerLocation = true;
|
|
576
|
-
wx.onLocationChange(this.subscribeLocationChnage);
|
|
577
|
-
wx.startLocationUpdate({});
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
/**
|
|
581
|
-
* 获取用户当前位置(经纬度)
|
|
582
|
-
* @memberof Location
|
|
583
|
-
* @param {boolean} showModalWhenCloseAuth 获取位置时,如果用户关闭了位置授权,是否弹窗提示用户打开授权
|
|
584
|
-
* @param {string} type 坐标类型
|
|
585
|
-
* @param {string} content 弹窗内容
|
|
586
|
-
* @param {boolean} showCancel 是否显示取消按钮
|
|
587
|
-
* @returns {Promise<LOC|ERR>} 返回对象
|
|
588
|
-
* @returns {Promise<LOC|ERR>} 返回对象
|
|
589
|
-
*/
|
|
590
|
-
getLocation(showModalWhenCloseAuth, type, content = '', showCancel = true) {
|
|
591
|
-
// 如果缓存中没有, 并且getLocPromise有值, 说明正在请求中。 返回请求的promise
|
|
592
|
-
if (!userLocationCache$1 && getLocPromise) { // eslint-disable-line
|
|
593
|
-
return getLocPromise;
|
|
594
|
-
}
|
|
595
|
-
// 如果缓存中没有, 并且getLocPromise没有值,新建一个请求
|
|
596
|
-
if (!userLocationCache$1 && !getLocPromise) { // eslint-disable-line
|
|
597
|
-
getLocPromise = this.getWxLocationPromise(showModalWhenCloseAuth, type, content, showCancel);
|
|
598
|
-
return getLocPromise;
|
|
599
|
-
}
|
|
600
|
-
// 缓存中有数据, 证明用户已经获取过, 那么直接返回缓存中的位置
|
|
601
|
-
return Promise.resolve(userLocationCache$1);
|
|
602
|
-
}
|
|
603
|
-
/**
|
|
604
|
-
* @description 获取位置(经纬度)底层封装
|
|
605
|
-
* @memberof Location
|
|
606
|
-
* @param {boolean} showModalWhenCloseAuth 获取位置时,如果用户关闭了位置授权,是否弹窗提示用户打开授权
|
|
607
|
-
* @param {string} type 坐标类型
|
|
608
|
-
* @param {string} content 弹窗内容
|
|
609
|
-
* @param {boolean} showCancel 是否显示取消按钮
|
|
610
|
-
* @returns {Promise<LOC|ERR>} 返回对象
|
|
611
|
-
* @example
|
|
612
|
-
* <caption>LOC类型示例</caption>
|
|
613
|
-
* {
|
|
614
|
-
* cityName: '北京市',
|
|
615
|
-
* cityCode: '100100',
|
|
616
|
-
* latitude: 325.255333,
|
|
617
|
-
* longitude: 116.2545454,
|
|
618
|
-
* adCode: 1212144,
|
|
619
|
-
* poi: {
|
|
620
|
-
* id: '1114545554511',
|
|
621
|
-
* title: '腾讯北京总部大厦',
|
|
622
|
-
* address : '北京市海淀区东北旺西路',
|
|
623
|
-
* }
|
|
624
|
-
*/
|
|
625
|
-
getWxLocationPromise(showModalWhenCloseAuth, type, content = '', showCancel = true) {
|
|
626
|
-
return new Promise((resolve, reject) => {
|
|
627
|
-
getWxLocation(type).then((res) => {
|
|
628
|
-
this.listenerLocation();
|
|
629
|
-
userLocationCache$1 = res;
|
|
630
|
-
// 更新用户状态 -- todo
|
|
631
|
-
updateLocStatus(true);
|
|
632
|
-
resolve(res);
|
|
633
|
-
})
|
|
634
|
-
.catch((err) => {
|
|
635
|
-
getLocPromise = null;
|
|
636
|
-
updateLocStatus(false);
|
|
637
|
-
this.openLocationAuth(showModalWhenCloseAuth, type, content, showCancel, err).then((res) => {
|
|
638
|
-
resolve(res);
|
|
639
|
-
}, (err) => {
|
|
640
|
-
reject(err);
|
|
641
|
-
});
|
|
642
|
-
});
|
|
643
|
-
});
|
|
644
|
-
}
|
|
645
|
-
/**
|
|
646
|
-
* 如果没有权限,自动开启授权弹窗
|
|
647
|
-
* @memberof Location
|
|
648
|
-
* @param {boolean} showModalWhenCloseAuth 获取位置时,如果用户关闭了位置授权,是否弹窗提示用户打开授权
|
|
649
|
-
* @param {string} type 坐标类型
|
|
650
|
-
* @param {string} content 弹窗内容
|
|
651
|
-
* @param {boolean} showCancel 是否显示取消按钮
|
|
652
|
-
* @param {object} err 错误信息
|
|
653
|
-
* @returns {Promise} 返回对象
|
|
654
|
-
*/
|
|
655
|
-
openLocationAuth(showModalWhenCloseAuth, type, content, showCancel, err) {
|
|
656
|
-
return new Promise((resolve, reject) => {
|
|
657
|
-
const { locationEnabled, locationAuthorized } = getSystemInfo();
|
|
658
|
-
// 系统位置定位开关打开 && 允许微信使用位置定位能力开关打开
|
|
659
|
-
if (locationEnabled && locationAuthorized) {
|
|
660
|
-
if (err.errMsg.search(/auth [deny|denied]|authorize/) < 0) {
|
|
661
|
-
reject();
|
|
662
|
-
return;
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
if (!showModalWhenCloseAuth) {
|
|
666
|
-
const rejectData = { ...err, unAuthed: true };
|
|
667
|
-
reject(rejectData);
|
|
668
|
-
return;
|
|
669
|
-
}
|
|
670
|
-
// 控制地理位置开关的名称(系统控制的开关,还是微信层面的开关)
|
|
671
|
-
const isSysAndWechatAllowedGetLoc = (locationEnabled && locationAuthorized);
|
|
672
|
-
const { authLevelName, confirmText } = getTextByReason(locationEnabled, isSysAndWechatAllowedGetLoc);
|
|
673
|
-
wx.showModal({
|
|
674
|
-
confirmText,
|
|
675
|
-
title: `未开启${authLevelName}位置信息权限`,
|
|
676
|
-
content: content || `开启${authLevelName}位置信息权限\n体验更顺畅的出行服务`,
|
|
677
|
-
showCancel: (showCancel && isSysAndWechatAllowedGetLoc),
|
|
678
|
-
confirmColor: '#4875fd',
|
|
679
|
-
success: (res) => {
|
|
680
|
-
// 用户拒绝去授权
|
|
681
|
-
if (!res.confirm || !locationEnabled || !locationAuthorized) {
|
|
682
|
-
const rejectData = { ...err, unAuthed: true };
|
|
683
|
-
return reject(rejectData);
|
|
684
|
-
}
|
|
685
|
-
// 用户同意去打开授权(只是打开小程序设置页,用户不一定打开了位置授权,所以需要重新进行获取位置)
|
|
686
|
-
openSetting()
|
|
687
|
-
.then(() => {
|
|
688
|
-
resolve(this.getLocation(showModalWhenCloseAuth, type, content, showCancel));
|
|
689
|
-
})
|
|
690
|
-
.catch((err) => {
|
|
691
|
-
const rejectData = { ...err, unAuthed: true };
|
|
692
|
-
reject(rejectData);
|
|
693
|
-
});
|
|
694
|
-
},
|
|
695
|
-
});
|
|
696
|
-
});
|
|
697
|
-
}
|
|
698
|
-
/**
|
|
699
|
-
* 订阅用户位置信息变化
|
|
700
|
-
* @param { object } res 用户位置信息对象
|
|
701
|
-
* @returns { undefined } no retrurn
|
|
702
|
-
*/
|
|
703
|
-
subscribeLocationChnage(res) {
|
|
704
|
-
userLocationCache$1 = res;
|
|
705
|
-
}
|
|
706
|
-
/**
|
|
707
|
-
* @description
|
|
708
|
-
* 以静默方式获取用户位置(经纬度),说明如下:<br>
|
|
709
|
-
* 1、从未授权情况下 | 用户删除小程序之后调用该方法不会弹微信自带的授权弹窗;<br>
|
|
710
|
-
* 2、拒绝授权后,调用该方法不会弹窗提示用户去授权(wx.showModal);<br>
|
|
711
|
-
* @memberof Location
|
|
712
|
-
* @param {String} type 非必填。坐标类型,默认'gcj02'
|
|
713
|
-
* @returns {Promise<LOC|ERR>} 返回位置信息
|
|
714
|
-
* @example
|
|
715
|
-
* <caption>LOC类型示例</caption>
|
|
716
|
-
* {
|
|
717
|
-
* latitude: 33.253321,
|
|
718
|
-
* longitude: 115.2444,
|
|
719
|
-
* }
|
|
720
|
-
* @example
|
|
721
|
-
* <caption>ERR类型示例</caption>
|
|
722
|
-
* {
|
|
723
|
-
* err,
|
|
724
|
-
* unAuthed: true,
|
|
725
|
-
* locationScopeStatus: false
|
|
726
|
-
* }
|
|
727
|
-
*/
|
|
728
|
-
async getLocationSilent(type) {
|
|
729
|
-
let err = null;
|
|
730
|
-
let locationScopeStatus;
|
|
731
|
-
try {
|
|
732
|
-
locationScopeStatus = await getSetting();
|
|
733
|
-
// 用户已授权. locationScopeStatus = true
|
|
734
|
-
if (locationScopeStatus) {
|
|
735
|
-
return this.getLocation(false, type);
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
catch (ex) {
|
|
739
|
-
err = ex;
|
|
740
|
-
}
|
|
741
|
-
updateLocStatus(false);
|
|
742
|
-
// 用户关闭了授权. locationScopeStatus = false
|
|
743
|
-
// 用户未授权过(删除小程序之后再次打开小程序). locationScopeStatus = undefined
|
|
744
|
-
return Promise.reject({ err, unAuthed: true, locationScopeStatus });
|
|
745
|
-
}
|
|
746
|
-
/**
|
|
747
|
-
* @memberof Location
|
|
748
|
-
* @description 监听获取位置状态变化(目前只有失败->成功时会触发事件)
|
|
749
|
-
* @param {Function} cb 监听事件回调函数
|
|
750
|
-
* @returns {void}
|
|
751
|
-
*/
|
|
752
|
-
onLocStatusChange(cb) {
|
|
753
|
-
if (cb && typeof cb === 'function') {
|
|
754
|
-
event$1.bind(EventName, cb);
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
var LocationBase$1 = LocationBase;
|
|
759
|
-
|
|
760
|
-
const request = new Request();
|
|
761
|
-
const event = new EventDispatcher();
|
|
762
|
-
const userLocationCache = {}; // 获取位置缓存
|
|
763
|
-
// 用户手动选择的位置信息(切换城市后的位置信息)
|
|
764
|
-
let userLocation;
|
|
765
|
-
// 用户所在的城市
|
|
766
|
-
let cityTheUserAt = '';
|
|
767
|
-
// 用户城市变化事件名
|
|
768
|
-
const CityChangeEventName = 'loc_city_changed';
|
|
769
|
-
const LocationType = 'gcj02'; // 获取经纬度时的坐标名称
|
|
770
|
-
let ipLocationPromise = null; // ip定位请求的promise
|
|
771
|
-
/**
|
|
772
|
-
* @class Location
|
|
773
|
-
* @classdesc 基于LocationBase,封装业务侧位置的接口。 将用户经纬度转化为城市等展示信息
|
|
774
|
-
*/
|
|
775
|
-
class Location extends LocationBase$1 {
|
|
776
|
-
// 默认位置信息
|
|
777
|
-
locForNoAuth = {
|
|
778
|
-
province: '广东省',
|
|
779
|
-
cityCode: '440300',
|
|
780
|
-
cityName: '深圳市',
|
|
781
|
-
latitude: 22.54286,
|
|
782
|
-
longitude: 114.05956,
|
|
783
|
-
};
|
|
784
|
-
/**
|
|
785
|
-
* 构造函数
|
|
786
|
-
*/
|
|
787
|
-
constructor() {
|
|
788
|
-
super();
|
|
789
|
-
}
|
|
790
|
-
/**
|
|
791
|
-
* 获取解析后的用户位置, 比如城市信息
|
|
792
|
-
* @param { number } lat 用户纬度信息
|
|
793
|
-
* @param { number } lng 用户经度信息
|
|
794
|
-
* @param { number } getPoi 位置
|
|
795
|
-
* @returns { Promise<PostionType | void> } 获取位置信息的promise
|
|
796
|
-
*/
|
|
797
|
-
getPoiInfo(lat, lng, getPoi) {
|
|
798
|
-
// 优先查询缓存中是否有位置信息,如果有直接返回
|
|
799
|
-
const cacheName = `${lat}-${lng}-${getPoi}`;
|
|
800
|
-
// @ts-ignore
|
|
801
|
-
if (userLocationCache[cacheName]) { // eslint-disable-line
|
|
802
|
-
return userLocationCache[cacheName];
|
|
803
|
-
}
|
|
804
|
-
userLocationCache[cacheName] = request.post('basic/lbs/decode', { lat, lng, getPoi }).then((res) => {
|
|
805
|
-
const { errCode, resData = {} } = res;
|
|
806
|
-
if (errCode === 0) {
|
|
807
|
-
const { result = {} } = resData;
|
|
808
|
-
const { ad_info: adInfo = {} } = result;
|
|
809
|
-
const loc = {
|
|
810
|
-
province: adInfo.province,
|
|
811
|
-
cityName: adInfo.city,
|
|
812
|
-
adCode: adInfo.adcode,
|
|
813
|
-
cityCode: formatCityCode(adInfo.city_code, adInfo.nation_code),
|
|
814
|
-
latitude: lat,
|
|
815
|
-
longitude: lng,
|
|
816
|
-
};
|
|
817
|
-
if (getPoi === 0) {
|
|
818
|
-
return loc;
|
|
819
|
-
}
|
|
820
|
-
loc.adCode = adInfo.adcode;
|
|
821
|
-
loc.poi = formatPoi(result);
|
|
822
|
-
return loc;
|
|
823
|
-
}
|
|
824
|
-
return Promise.reject(res);
|
|
825
|
-
})
|
|
826
|
-
.catch(err => Promise.reject(err));
|
|
827
|
-
return userLocationCache[cacheName];
|
|
828
|
-
}
|
|
829
|
-
/**
|
|
830
|
-
* @function
|
|
831
|
-
* @memberof Location
|
|
832
|
-
* @description 获取位置、城市信息
|
|
833
|
-
* @param {Boolean} showModalWhenCloseAuth 获取位置时,如果用户关闭了位置授权,是否弹窗提示用户打开授权
|
|
834
|
-
* @param {String} type 坐标类型
|
|
835
|
-
* @param {String} content 弹窗内容
|
|
836
|
-
* @param {Number} getPoi 是否获取详细poi信息, 0 - 不获取(不返回poi字段), 1 - 获取(返回poi字段)
|
|
837
|
-
* @returns {Promise<POI|ERR>} 返回对象
|
|
838
|
-
* @example
|
|
839
|
-
* <caption>POI类型示例</caption>
|
|
840
|
-
* {
|
|
841
|
-
* cityName: '北京市',
|
|
842
|
-
* cityCode: '100100',
|
|
843
|
-
* province: '北京市',
|
|
844
|
-
* latitude: 325.255333,
|
|
845
|
-
* longitude: 116.2545454,
|
|
846
|
-
* adCode: 1212144,
|
|
847
|
-
* poi: {
|
|
848
|
-
* id: '1114545554511',
|
|
849
|
-
* title: '腾讯北京总部大厦',
|
|
850
|
-
* address : '北京市海淀区东北旺西路',
|
|
851
|
-
* }
|
|
852
|
-
* }
|
|
853
|
-
* @example
|
|
854
|
-
* <caption>ERR类型示例</caption>
|
|
855
|
-
* {
|
|
856
|
-
* err,
|
|
857
|
-
* unAuthed: true,
|
|
858
|
-
* locationScopeStatus: false
|
|
859
|
-
* }
|
|
860
|
-
*/
|
|
861
|
-
getLocationDetail(showModalWhenCloseAuth = false, type = LocationType, content = '', getPoi = 0) {
|
|
862
|
-
return this.getLocation(showModalWhenCloseAuth, type, content)
|
|
863
|
-
.then((res) => this.getPoiInfo(res.latitude, res.longitude, getPoi))
|
|
864
|
-
.catch(err => Promise.reject(err));
|
|
865
|
-
}
|
|
866
|
-
/**
|
|
867
|
-
* @description 以静默方式获取用户详细位置(经纬度,poi信息, 省市信息),说明如下:<br>
|
|
868
|
-
* 1、从未授权情况下 | 用户删除小程序之后调用该方法不会弹微信自带的授权弹窗;<br>
|
|
869
|
-
* 2、拒绝授权后,调用该方法不会弹窗提示用户去授权(wx.showModal);<br>
|
|
870
|
-
* @memberof Location
|
|
871
|
-
* @param {Number} getPoi 是否获取详细poi信息, 0 - 不获取(不返回poi字段), 1 - 获取(返回poi字段)
|
|
872
|
-
* @param {String} type 非必填。坐标类型,默认'gcj02'
|
|
873
|
-
* @returns {Promise<LOC|ERR>} 返回对象
|
|
874
|
-
* @example
|
|
875
|
-
* <caption>LOC类型示例</caption>
|
|
876
|
-
* {
|
|
877
|
-
* cityName: '北京市',
|
|
878
|
-
* cityCode: '100100',
|
|
879
|
-
* latitude: 325.255333,
|
|
880
|
-
* longitude: 116.2545454,
|
|
881
|
-
* adCode: 1212144,
|
|
882
|
-
* poi: {
|
|
883
|
-
* id: '1114545554511',
|
|
884
|
-
* title: '腾讯北京总部大厦',
|
|
885
|
-
* address : '北京市海淀区东北旺西路',
|
|
886
|
-
* }
|
|
887
|
-
* }
|
|
888
|
-
* @example
|
|
889
|
-
* <caption>ERR类型示例</caption>
|
|
890
|
-
* {
|
|
891
|
-
* err,
|
|
892
|
-
* unAuthed: true,
|
|
893
|
-
* locationScopeStatus: false
|
|
894
|
-
* }
|
|
895
|
-
*/
|
|
896
|
-
getLocationDetailSilent(getPoi = 0, type = 'gcj02') {
|
|
897
|
-
return this.getLocationSilent(type)
|
|
898
|
-
.then((res) => this.getPoiInfo(res.latitude, res.longitude, getPoi))
|
|
899
|
-
.catch(err => Promise.reject(err));
|
|
900
|
-
}
|
|
901
|
-
/**
|
|
902
|
-
* @description 获取用户手动选择的位置信息
|
|
903
|
-
* @memberof Location
|
|
904
|
-
* @returns {Null|LOC} 返回用户位置信息
|
|
905
|
-
* @example
|
|
906
|
-
* <caption>LOC类型示例</caption>
|
|
907
|
-
* {
|
|
908
|
-
* province: '北京市',
|
|
909
|
-
* cityName: '北京市',
|
|
910
|
-
* cityCode: '100100',
|
|
911
|
-
* latitude: 325.255333,
|
|
912
|
-
* longitude: 116.2545454,
|
|
913
|
-
* adCode: 1212144,
|
|
914
|
-
* }
|
|
915
|
-
*/
|
|
916
|
-
getUserLocation() {
|
|
917
|
-
return userLocation;
|
|
918
|
-
}
|
|
919
|
-
/**
|
|
920
|
-
* @description 设置用户位置(小程序生命周期内有效)
|
|
921
|
-
* @memberof Location
|
|
922
|
-
* @param {Object} loc 用户手动选择的位置
|
|
923
|
-
* @params {String} loc.province 省份
|
|
924
|
-
* @params {String} loc.cityName 城市
|
|
925
|
-
* @params {String} loc.cityCode citycode
|
|
926
|
-
* @params {Number} loc.latitude 纬度
|
|
927
|
-
* @params {Number} loc.longitude 经度
|
|
928
|
-
* @params {Number} loc.adCode adCode
|
|
929
|
-
* @returns {Void} 无返回值
|
|
930
|
-
* @example
|
|
931
|
-
* <caption>loc类型示例</caption>
|
|
932
|
-
* {
|
|
933
|
-
* province: '北京市',
|
|
934
|
-
* cityName: '北京市',
|
|
935
|
-
* cityCode: '100100',
|
|
936
|
-
* latitude: 325.255333,
|
|
937
|
-
* longitude: 116.2545454,
|
|
938
|
-
* adCode: 1212144,
|
|
939
|
-
* }
|
|
940
|
-
*/
|
|
941
|
-
setUserLocation(loc) {
|
|
942
|
-
if (!loc || typeof loc !== 'object') {
|
|
943
|
-
return;
|
|
944
|
-
}
|
|
945
|
-
// 如果城市发生变化,派发事件
|
|
946
|
-
const { cityName: curCityName } = loc;
|
|
947
|
-
if (curCityName && (cityTheUserAt !== curCityName)) {
|
|
948
|
-
cityTheUserAt = curCityName;
|
|
949
|
-
userLocation = loc;
|
|
950
|
-
event.dispatch({ type: CityChangeEventName });
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
/**
|
|
954
|
-
* @description 获取用户选择的城市位置信息 或者 用户真实的位置信息(这个方法说明有问题)
|
|
955
|
-
* @memberof Location
|
|
956
|
-
* @param {Boolean} showModalWhenCloseAuth 没有授权时是否展示授权弹窗
|
|
957
|
-
* @returns {Promise} 用户位置信息
|
|
958
|
-
*/
|
|
959
|
-
async getMergedLocation(showModalWhenCloseAuth = true) {
|
|
960
|
-
const userLocatioin = this.getUserLocation();
|
|
961
|
-
// 优先用户选择的城市
|
|
962
|
-
if (userLocatioin) {
|
|
963
|
-
return userLocatioin;
|
|
964
|
-
}
|
|
965
|
-
return await this.getLocationDetail(showModalWhenCloseAuth, LocationType);
|
|
966
|
-
}
|
|
967
|
-
/**
|
|
968
|
-
* @memberof Location
|
|
969
|
-
* @description 监听用户城市变化(如: 北京市->深圳市)
|
|
970
|
-
* @param {Function} cb 监听事件回调函数
|
|
971
|
-
* @returns {void}
|
|
972
|
-
*/
|
|
973
|
-
onCityChange(cb) {
|
|
974
|
-
if (cb && typeof cb === 'function') {
|
|
975
|
-
event.bind(CityChangeEventName, cb);
|
|
976
|
-
}
|
|
977
|
-
}
|
|
978
|
-
/**
|
|
979
|
-
* @memberof Location
|
|
980
|
-
* @description 获取路线规划
|
|
981
|
-
* @param {String} to 目的地坐标,格式:lat,lng
|
|
982
|
-
* @param {String} depart 出发地坐标,格式:lat,lng
|
|
983
|
-
* @param {String} mode 出行方式, driving 驾车[默认]
|
|
984
|
-
* @returns {Object} result.routes 返回数据 [{}, ...]
|
|
985
|
-
*/
|
|
986
|
-
async getRoute(to, depart, mode = 'driving') {
|
|
987
|
-
let from = depart;
|
|
988
|
-
const coorReg = new RegExp(/(\d+\.\d{6,}),(\d+\.\d{6,})/);
|
|
989
|
-
if (!coorReg.test(to))
|
|
990
|
-
throw Error('目的地参数格式错误');
|
|
991
|
-
if (!coorReg.test(from)) { // 出发地缺省使用当前位置
|
|
992
|
-
const { latitude, longitude } = await this.getMergedLocation();
|
|
993
|
-
from = `${latitude},${longitude}`;
|
|
994
|
-
}
|
|
995
|
-
return request.post('basic/lbs/direction', { from, to, mode });
|
|
996
|
-
}
|
|
997
|
-
/**
|
|
998
|
-
* ip定位
|
|
999
|
-
* 原理:通过调手图接口查询当前IP所在位置,市级的准确率是91%
|
|
1000
|
-
* 注意:由于服务端对该查询服务有次数限制,所以本函数会缓存成功的promise
|
|
1001
|
-
* @param force 是否清除上次的缓存重新请求
|
|
1002
|
-
*/
|
|
1003
|
-
getIpLocation(force = false) {
|
|
1004
|
-
if (ipLocationPromise === null || force) {
|
|
1005
|
-
ipLocationPromise = new Promise((resolve, reject) => {
|
|
1006
|
-
request.post('basic/lbs/decodeip')
|
|
1007
|
-
.then((res) => {
|
|
1008
|
-
if (res.errCode === 0) {
|
|
1009
|
-
resolve(res.resData);
|
|
1010
|
-
return;
|
|
1011
|
-
}
|
|
1012
|
-
reject({ erMsg: res.errMsg });
|
|
1013
|
-
ipLocationPromise = null;
|
|
1014
|
-
})
|
|
1015
|
-
.catch((e) => {
|
|
1016
|
-
reject(e);
|
|
1017
|
-
ipLocationPromise = null;
|
|
1018
|
-
});
|
|
1019
|
-
});
|
|
1020
|
-
}
|
|
1021
|
-
return ipLocationPromise;
|
|
1022
|
-
}
|
|
1023
|
-
}
|
|
1024
|
-
// 因为在构造函数中会用到wx的api,所以使用到时才实例化
|
|
1025
|
-
let instance;
|
|
1026
|
-
function getLocInstance() {
|
|
1027
|
-
if (!instance) {
|
|
1028
|
-
instance = new Location();
|
|
1029
|
-
}
|
|
1030
|
-
return instance;
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
|
-
const R = new Request();
|
|
1034
|
-
const ReportInterval = 3000; // 轮训上报间隔
|
|
1035
|
-
|
|
1036
|
-
const ReportDataQueue = []; // 上报数据队列
|
|
1037
|
-
|
|
1038
|
-
let ReportTaskId = -1; // 轮训上报id
|
|
1039
|
-
|
|
1040
|
-
let appShowOptions = null; // 设置小程序onShow参数
|
|
1041
|
-
|
|
1042
|
-
function getAppShowOptions() {
|
|
1043
|
-
if (appShowOptions === null) {
|
|
1044
|
-
try {
|
|
1045
|
-
appShowOptions = wx.getLaunchOptionsSync();
|
|
1046
|
-
} catch (_) {
|
|
1047
|
-
appShowOptions = {};
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
|
-
|
|
1051
|
-
return appShowOptions;
|
|
1052
|
-
}
|
|
1053
|
-
|
|
1054
|
-
function getTMS() {
|
|
1055
|
-
return getApp({
|
|
1056
|
-
allowDefault: true
|
|
1057
|
-
}).tms;
|
|
1058
|
-
} // 缓存系统信息,避免每次都重新获取系统信息
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
let systemPromise = null;
|
|
1062
|
-
/**
|
|
1063
|
-
* 获取系统信息
|
|
1064
|
-
* @private
|
|
1065
|
-
* @returns {object} 系统信息
|
|
1066
|
-
*/
|
|
1067
|
-
|
|
1068
|
-
const getSystemPromise = () => {
|
|
1069
|
-
if (systemPromise === null) {
|
|
1070
|
-
systemPromise = new Promise(resolve => {
|
|
1071
|
-
wx.getSystemInfo({
|
|
1072
|
-
success: systemInfo => {
|
|
1073
|
-
const {
|
|
1074
|
-
model,
|
|
1075
|
-
version: wxVersion,
|
|
1076
|
-
platform,
|
|
1077
|
-
SDKVersion,
|
|
1078
|
-
host
|
|
1079
|
-
} = systemInfo;
|
|
1080
|
-
resolve({
|
|
1081
|
-
model,
|
|
1082
|
-
wxVersion,
|
|
1083
|
-
platform,
|
|
1084
|
-
SDKVersion,
|
|
1085
|
-
host
|
|
1086
|
-
});
|
|
1087
|
-
},
|
|
1088
|
-
fail: () => {
|
|
1089
|
-
resolve({});
|
|
1090
|
-
}
|
|
1091
|
-
});
|
|
1092
|
-
});
|
|
1093
|
-
}
|
|
1094
|
-
|
|
1095
|
-
return systemPromise;
|
|
1096
|
-
};
|
|
1097
|
-
|
|
1098
|
-
let networkPromise = null;
|
|
1099
|
-
/**
|
|
1100
|
-
* 获取网络信息
|
|
1101
|
-
* @private
|
|
1102
|
-
* @returns {string} 网络信息
|
|
1103
|
-
*/
|
|
1104
|
-
|
|
1105
|
-
const getNetworkType = () => {
|
|
1106
|
-
if (networkPromise === null) {
|
|
1107
|
-
networkPromise = new Promise(resolve => {
|
|
1108
|
-
wx.getNetworkType({
|
|
1109
|
-
success: netInfo => {
|
|
1110
|
-
resolve(netInfo.networkType);
|
|
1111
|
-
},
|
|
1112
|
-
fail: () => {
|
|
1113
|
-
resolve('unknown');
|
|
1114
|
-
}
|
|
1115
|
-
});
|
|
1116
|
-
});
|
|
1117
|
-
}
|
|
1118
|
-
|
|
1119
|
-
return networkPromise;
|
|
1120
|
-
};
|
|
1121
|
-
|
|
1122
|
-
let ProvinceInfoCache = null;
|
|
1123
|
-
/**
|
|
1124
|
-
* 获取省市信息
|
|
1125
|
-
* @private
|
|
1126
|
-
*/
|
|
1127
|
-
|
|
1128
|
-
const getProvinceInfo = () => {
|
|
1129
|
-
if (!ProvinceInfoCache) {
|
|
1130
|
-
ProvinceInfoCache = new Promise(async resolve => {
|
|
1131
|
-
try {
|
|
1132
|
-
const loc = await getLocInstance().getLocationDetailSilent();
|
|
1133
|
-
resolve({
|
|
1134
|
-
cityName: loc.cityName,
|
|
1135
|
-
province: loc.province
|
|
1136
|
-
});
|
|
1137
|
-
} catch (_) {
|
|
1138
|
-
// 获取位置失败时,尝试获取本地存储的位置信息
|
|
1139
|
-
const loc = getLocInstance().getUserLocation();
|
|
1140
|
-
|
|
1141
|
-
if (loc !== null && loc !== void 0 && loc.cityName) {
|
|
1142
|
-
resolve(loc);
|
|
1143
|
-
} else {
|
|
1144
|
-
resolve({
|
|
1145
|
-
cityName: '',
|
|
1146
|
-
province: ''
|
|
1147
|
-
});
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
});
|
|
1151
|
-
}
|
|
1152
|
-
|
|
1153
|
-
return ProvinceInfoCache;
|
|
1154
|
-
};
|
|
1155
|
-
|
|
1156
|
-
let ProvinceInfoCacheByIp = null;
|
|
1157
|
-
/**
|
|
1158
|
-
* 调接口获取省市信息
|
|
1159
|
-
* @private
|
|
1160
|
-
*/
|
|
1161
|
-
|
|
1162
|
-
const getProvinceInfoByIp = () => {
|
|
1163
|
-
if (!ProvinceInfoCacheByIp) {
|
|
1164
|
-
ProvinceInfoCacheByIp = new Promise(async resolve => {
|
|
1165
|
-
try {
|
|
1166
|
-
const loc = await getLocInstance().getIpLocation();
|
|
1167
|
-
const {
|
|
1168
|
-
city,
|
|
1169
|
-
province
|
|
1170
|
-
} = loc.ad_info;
|
|
1171
|
-
resolve({
|
|
1172
|
-
cityName: city,
|
|
1173
|
-
province
|
|
1174
|
-
});
|
|
1175
|
-
} catch (_) {
|
|
1176
|
-
resolve({
|
|
1177
|
-
cityName: '',
|
|
1178
|
-
province: ''
|
|
1179
|
-
});
|
|
1180
|
-
}
|
|
1181
|
-
});
|
|
1182
|
-
}
|
|
1183
|
-
|
|
1184
|
-
return ProvinceInfoCacheByIp;
|
|
1185
|
-
}; // 用于缓存用户唯一标识userId
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
let userId = '';
|
|
1189
|
-
/**
|
|
1190
|
-
* 获取用户唯一标识userId
|
|
1191
|
-
* @private
|
|
1192
|
-
* @returns {string} userId
|
|
1193
|
-
*/
|
|
1194
|
-
|
|
1195
|
-
const getUserId = async () => {
|
|
1196
|
-
if (userId) {
|
|
1197
|
-
return userId;
|
|
1198
|
-
}
|
|
1199
|
-
|
|
1200
|
-
({
|
|
1201
|
-
userId
|
|
1202
|
-
} = await getAuthInfo());
|
|
1203
|
-
return userId;
|
|
1204
|
-
};
|
|
1205
|
-
|
|
1206
|
-
let launchFrom = '';
|
|
1207
|
-
/**
|
|
1208
|
-
* 获取用户启动小程序时的渠道来源值
|
|
1209
|
-
* @private
|
|
1210
|
-
* @returns {string} 用户启动小程序时的渠道来源值
|
|
1211
|
-
*/
|
|
1212
|
-
|
|
1213
|
-
const getLaunchFrom = () => {
|
|
1214
|
-
if (launchFrom) {
|
|
1215
|
-
return launchFrom;
|
|
1216
|
-
}
|
|
1217
|
-
|
|
1218
|
-
try {
|
|
1219
|
-
const LaunchOptions = wx.getLaunchOptionsSync() || {};
|
|
1220
|
-
const {
|
|
1221
|
-
query = {}
|
|
1222
|
-
} = LaunchOptions;
|
|
1223
|
-
launchFrom = query.from || '';
|
|
1224
|
-
return launchFrom;
|
|
1225
|
-
} catch (_) {
|
|
1226
|
-
return '';
|
|
1227
|
-
}
|
|
1228
|
-
};
|
|
1229
|
-
/**
|
|
1230
|
-
* 将上报的对象类型的数据转换成数组类型
|
|
1231
|
-
* @private
|
|
1232
|
-
* @param {object} reportData 需要上报的数据
|
|
1233
|
-
* @returns {array} 数组格式的上报数据
|
|
1234
|
-
*/
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
const getReportDataList = (reportData = {}) => {
|
|
1238
|
-
const reportList = [];
|
|
1239
|
-
reportList.length = 40;
|
|
1240
|
-
Object.keys(reportData).forEach(key => {
|
|
1241
|
-
const reportIndex = Number(key);
|
|
1242
|
-
reportList[reportIndex] = reportData[key];
|
|
1243
|
-
});
|
|
1244
|
-
return reportList;
|
|
1245
|
-
}; // 小程序版本号
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
let verNum = null;
|
|
1249
|
-
|
|
1250
|
-
function getMiniProgramVersion() {
|
|
1251
|
-
if (verNum === null) {
|
|
1252
|
-
const {
|
|
1253
|
-
miniProgram: {
|
|
1254
|
-
version
|
|
1255
|
-
} = {}
|
|
1256
|
-
} = wx.getAccountInfoSync() || {};
|
|
1257
|
-
verNum = version;
|
|
1258
|
-
}
|
|
1259
|
-
|
|
1260
|
-
return verNum;
|
|
1261
|
-
}
|
|
1262
|
-
/**
|
|
1263
|
-
* 格式化上报数据
|
|
1264
|
-
* @private
|
|
1265
|
-
* @param {object} reportData 需要上报的数据
|
|
1266
|
-
* @param {object} deviceData 设备数据(系统信息,网络状况,位置信息)
|
|
1267
|
-
* @returns {array} 格式化后的上报数据
|
|
1268
|
-
*/
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
const formatReportData = async (reportData, deviceData) => {
|
|
1272
|
-
const [system, netType, provinceInfo] = deviceData;
|
|
1273
|
-
const param = Array.isArray(reportData.param) ? reportData.param : getReportDataList(reportData);
|
|
1274
|
-
const {
|
|
1275
|
-
client
|
|
1276
|
-
} = await getTMS().getEnvInfo();
|
|
1277
|
-
param[5] = await getUserId();
|
|
1278
|
-
param[10] = getMiniProgramVersion(); // 上报小程序版本号
|
|
1279
|
-
|
|
1280
|
-
param[16] = getLaunchFrom(); // 渠道公共参数
|
|
1281
|
-
|
|
1282
|
-
param[17] = param[17] || (provinceInfo === null || provinceInfo === void 0 ? void 0 : provinceInfo.province);
|
|
1283
|
-
param[18] = param[18] || (provinceInfo === null || provinceInfo === void 0 ? void 0 : provinceInfo.cityName);
|
|
1284
|
-
param[19] = system === null || system === void 0 ? void 0 : system.host; // 上报宿主app信息 { appId, env, version }
|
|
1285
|
-
|
|
1286
|
-
param[28] = client; // 默认上报数据
|
|
1287
|
-
|
|
1288
|
-
const defaultReportData = {
|
|
1289
|
-
9: '2',
|
|
1290
|
-
12: netType,
|
|
1291
|
-
13: '2',
|
|
1292
|
-
29: getAppShowOptions().scene,
|
|
1293
|
-
// 打开小程序的场景值
|
|
1294
|
-
33: JSON.stringify(system),
|
|
1295
|
-
// 数据字符串化
|
|
1296
|
-
36: getAppShowOptions() // 打开小程序的场景值及参数
|
|
1297
|
-
|
|
1298
|
-
}; // 对部分空数据使用默认数据填充
|
|
1299
|
-
|
|
1300
|
-
const handleDefaultData = (paramItem, defaultData) => {
|
|
1301
|
-
const arr = [paramItem, paramItem === 0, paramItem === false];
|
|
1302
|
-
return arr.some(item => !!item) ? paramItem : defaultData || '';
|
|
1303
|
-
};
|
|
1304
|
-
|
|
1305
|
-
Object.keys(defaultReportData).forEach(index => {
|
|
1306
|
-
const paramItem = param[index];
|
|
1307
|
-
param[index] = handleDefaultData(paramItem, defaultReportData[index]);
|
|
1308
|
-
}); // 所有上报数据都转换为字符串
|
|
1309
|
-
|
|
1310
|
-
param.forEach((reportItem, index) => {
|
|
1311
|
-
if (reportItem && typeof reportItem !== 'string') {
|
|
1312
|
-
param[index] = `${JSON.stringify(reportItem)}`;
|
|
1313
|
-
} else {
|
|
1314
|
-
param[index] = handleDefaultData(reportItem, '');
|
|
1315
|
-
}
|
|
1316
|
-
});
|
|
1317
|
-
return param.map(item => item !== null ? encodeURIComponent(item) : item);
|
|
1318
|
-
};
|
|
1319
|
-
/**
|
|
1320
|
-
* 格式化上报到小程序后台的数据(自定义分析使用)
|
|
1321
|
-
* @private
|
|
1322
|
-
* @param {array} data 埋点数据
|
|
1323
|
-
* @returns {object} 格式化的数据
|
|
1324
|
-
*/
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
const formatAnalyticsData = async data => {
|
|
1328
|
-
const analyticsData = {};
|
|
1329
|
-
const {
|
|
1330
|
-
10: version,
|
|
1331
|
-
29: scene
|
|
1332
|
-
} = data;
|
|
1333
|
-
analyticsData[10] = version; // 小程序版本号
|
|
1334
|
-
|
|
1335
|
-
analyticsData[29] = scene; // 小程序场景值
|
|
1336
|
-
|
|
1337
|
-
analyticsData[17] = decodeURIComponent(data[17]); // 用户所在省份
|
|
1338
|
-
|
|
1339
|
-
analyticsData[18] = decodeURIComponent(data[18]); // 用户所在城市
|
|
1340
|
-
// 将30-40位埋点字段补充到上报数据中
|
|
1341
|
-
|
|
1342
|
-
for (let i = 30; i < 41; i += 1) {
|
|
1343
|
-
analyticsData[i] = decodeURIComponent(data[i] || ''); // 如果第33列是设备信息,则忽略
|
|
1344
|
-
|
|
1345
|
-
if (data[33] && data[33].indexOf('model') > -1) {
|
|
1346
|
-
analyticsData[33] = '';
|
|
1347
|
-
}
|
|
1348
|
-
}
|
|
1349
|
-
|
|
1350
|
-
const {
|
|
1351
|
-
client
|
|
1352
|
-
} = await getTMS().getEnvInfo();
|
|
1353
|
-
return {
|
|
1354
|
-
analyticsData,
|
|
1355
|
-
eventName: `${client}_${data[27]}`
|
|
1356
|
-
};
|
|
1357
|
-
};
|
|
1358
|
-
/**
|
|
1359
|
-
* 上报数据到小程序后台
|
|
1360
|
-
* @private
|
|
1361
|
-
* @param {array} list 需要上报的数据列表
|
|
1362
|
-
* @returns {void}
|
|
1363
|
-
*/
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
const reportAnalytics = (list = []) => {
|
|
1367
|
-
try {
|
|
1368
|
-
list.forEach(item => {
|
|
1369
|
-
const {
|
|
1370
|
-
eventName,
|
|
1371
|
-
analyticsData
|
|
1372
|
-
} = formatAnalyticsData(item);
|
|
1373
|
-
wx.reportAnalytics(eventName, analyticsData);
|
|
1374
|
-
});
|
|
1375
|
-
} catch (_) {}
|
|
1376
|
-
};
|
|
1377
|
-
/**
|
|
1378
|
-
* @description report 方法 将上报数据缓存到内存中
|
|
1379
|
-
* @name report
|
|
1380
|
-
* @param {object} reportData 需要上报的数据
|
|
1381
|
-
* @param {boolean} reportNow 是否立即上报
|
|
1382
|
-
* @param {boolean} locPoi 是否通过微信接口获取poi
|
|
1383
|
-
* @returns {Void} 无返回值
|
|
1384
|
-
*/
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
const cache = (reportData, reportNow, locPoi = true) => {
|
|
1388
|
-
// 如果是微信爬虫 | 自动化测试场景,则不进行数据上报
|
|
1389
|
-
const DO_NOT_NEED_REPORT_SCENES = [1030, 1129];
|
|
1390
|
-
|
|
1391
|
-
if (DO_NOT_NEED_REPORT_SCENES.includes(getAppShowOptions().scene)) {
|
|
1392
|
-
return Promise.resolve();
|
|
1393
|
-
}
|
|
1394
|
-
|
|
1395
|
-
const task = [getSystemPromise(), getNetworkType()];
|
|
1396
|
-
|
|
1397
|
-
if (locPoi) {
|
|
1398
|
-
task.push(getProvinceInfo());
|
|
1399
|
-
} else {
|
|
1400
|
-
task.push(getProvinceInfoByIp());
|
|
1401
|
-
}
|
|
1402
|
-
|
|
1403
|
-
return Promise.all(task).then(async deviceData => {
|
|
1404
|
-
// 先对上报数据进行预处理
|
|
1405
|
-
const result = await formatReportData(reportData, deviceData); // 将需要上报的数据缓存在队列中
|
|
1406
|
-
|
|
1407
|
-
ReportDataQueue.push(result);
|
|
1408
|
-
}).then(() => {
|
|
1409
|
-
if (reportNow) {
|
|
1410
|
-
return sendData();
|
|
1411
|
-
}
|
|
1412
|
-
|
|
1413
|
-
return {
|
|
1414
|
-
cache: true
|
|
1415
|
-
};
|
|
1416
|
-
});
|
|
1417
|
-
};
|
|
1418
|
-
/**
|
|
1419
|
-
* 发送数据到服务端
|
|
1420
|
-
* @private
|
|
1421
|
-
* @returns {promise} 发送请求
|
|
1422
|
-
*/
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
const sendData = async () => {
|
|
1426
|
-
// 没有数据时,不发送上报请求
|
|
1427
|
-
if (ReportDataQueue.length === 0) {
|
|
1428
|
-
return Promise.resolve();
|
|
1429
|
-
}
|
|
1430
|
-
|
|
1431
|
-
const cacheReportData = [...ReportDataQueue];
|
|
1432
|
-
return R.post('basic/event/upload', {
|
|
1433
|
-
userId: await getUserId(),
|
|
1434
|
-
batch: cacheReportData
|
|
1435
|
-
}).then((res = {}) => {
|
|
1436
|
-
const {
|
|
1437
|
-
errCode
|
|
1438
|
-
} = res || {}; // 已经发送成功,则将本次发送的数据从数据队列中删除
|
|
1439
|
-
|
|
1440
|
-
if (errCode === 0) {
|
|
1441
|
-
ReportDataQueue.splice(0, cacheReportData.length);
|
|
1442
|
-
reportAnalytics(cacheReportData); // 将数据上报至小程序后台
|
|
1443
|
-
}
|
|
1444
|
-
});
|
|
1445
|
-
};
|
|
1446
|
-
/**
|
|
1447
|
-
* 开启轮询上报定时器
|
|
1448
|
-
* @private
|
|
1449
|
-
* @param {boolean} clearTimerAfterSend 是发送完数据后否清除定时器标识
|
|
1450
|
-
* @returns {void}
|
|
1451
|
-
*/
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
const startSendTimer = clearTimerAfterSend => {
|
|
1455
|
-
ReportTaskId = setInterval(async () => {
|
|
1456
|
-
sendData();
|
|
1457
|
-
|
|
1458
|
-
if (clearTimerAfterSend) {
|
|
1459
|
-
clearInterval(ReportTaskId);
|
|
1460
|
-
}
|
|
1461
|
-
}, ReportInterval);
|
|
1462
|
-
};
|
|
1463
|
-
/**
|
|
1464
|
-
* 停止定时器
|
|
1465
|
-
* @private
|
|
1466
|
-
* @returns {void}
|
|
1467
|
-
*/
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
const stopSendTimer = () => {
|
|
1471
|
-
clearInterval(ReportTaskId);
|
|
1472
|
-
};
|
|
1473
|
-
/**
|
|
1474
|
-
* 发送上报数据到服务端
|
|
1475
|
-
* @private
|
|
1476
|
-
* @param {boolean} reportNow 是否立即上报
|
|
1477
|
-
* @param {boolean} clearTimerAfterSend 是否发送之后清除定时器
|
|
1478
|
-
* @returns {void}
|
|
1479
|
-
*/
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
const report = (reportNow = false, clearTimerAfterSend = false) => {
|
|
1483
|
-
if (reportNow) {
|
|
1484
|
-
if (ReportDataQueue.length > 0) {
|
|
1485
|
-
sendData();
|
|
1486
|
-
}
|
|
1487
|
-
|
|
1488
|
-
if (!clearTimerAfterSend) {
|
|
1489
|
-
startSendTimer(clearTimerAfterSend);
|
|
1490
|
-
} else {
|
|
1491
|
-
stopSendTimer();
|
|
1492
|
-
}
|
|
1493
|
-
} else {
|
|
1494
|
-
startSendTimer(clearTimerAfterSend);
|
|
1495
|
-
}
|
|
1496
|
-
};
|
|
1497
|
-
/**
|
|
1498
|
-
* 更新小程序onShow参数
|
|
1499
|
-
* @private
|
|
1500
|
-
* @param {object} options 小程序onShow参数
|
|
1501
|
-
* @returns {void}
|
|
1502
|
-
*/
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
const setAppShowOptions = options => {
|
|
1506
|
-
appShowOptions = options;
|
|
1507
|
-
};
|
|
1508
|
-
/**
|
|
1509
|
-
* init之后再监听
|
|
1510
|
-
*/
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
const startListenApp = () => {
|
|
1514
|
-
/**
|
|
1515
|
-
* 监听小程序onShow事件
|
|
1516
|
-
* @private
|
|
1517
|
-
*/
|
|
1518
|
-
wx.onAppShow(options => {
|
|
1519
|
-
// 更新onShow参数
|
|
1520
|
-
setAppShowOptions(options); // 上报数据
|
|
1521
|
-
|
|
1522
|
-
report(true);
|
|
1523
|
-
});
|
|
1524
|
-
/**
|
|
1525
|
-
* 监听小程序onHide事件
|
|
1526
|
-
* @private
|
|
1527
|
-
*/
|
|
1528
|
-
|
|
1529
|
-
wx.onAppHide(() => {
|
|
1530
|
-
// onHide时立即上报,并清除定时器
|
|
1531
|
-
report(true, true);
|
|
1532
|
-
});
|
|
1533
|
-
};
|
|
1534
|
-
|
|
1535
|
-
/**
|
|
1536
|
-
* 四舍五入(支持保留n位小数,n>=0)
|
|
1537
|
-
* @param {any} x 原数字
|
|
1538
|
-
* 如果n不是合法数字或者无法转换为合法数字,round结果返回NaN
|
|
1539
|
-
* @param {any} n 保留几位小数,默认0
|
|
1540
|
-
* 如果n不是合法数字或者无法转换为合法数字,round结果返回NaN
|
|
1541
|
-
* 如果n小于0,round结果返回NaN
|
|
1542
|
-
* 如果n的值包含小数部分,round处理时只关注n的整数部分值
|
|
1543
|
-
* @return {number} 返回一个保留n位小数的数字,异常情况下可能是NaN
|
|
1544
|
-
*/
|
|
1545
|
-
|
|
1546
|
-
const round = (x, n = 0) => parseFloat(roundStr(x, n, false));
|
|
1547
|
-
|
|
1548
|
-
/**
|
|
1549
|
-
* 支持服务接入相关接口
|
|
1550
|
-
*/
|
|
1551
|
-
/**
|
|
1552
|
-
* getMpOpenId 获取接入方用户唯一标识 [变更为 getOuterOpenId]
|
|
1553
|
-
* @private
|
|
1554
|
-
* @description 唯一标识 openId 用于与服务商建立账号关联关系
|
|
1555
|
-
* @category 服务接入
|
|
1556
|
-
* @param {String} mpId 接入服务商渠道标识
|
|
1557
|
-
* @param {String} userId 出行用户标识
|
|
1558
|
-
* @returns {Promise<String>} 返回 openId,失败时返回空
|
|
1559
|
-
*/
|
|
1560
|
-
|
|
1561
|
-
async function getMpOpenId(mpId, userId) {
|
|
1562
|
-
const {
|
|
1563
|
-
resData
|
|
1564
|
-
} = await new Request().post('user/mpinfo', {
|
|
1565
|
-
userId,
|
|
1566
|
-
mpId
|
|
1567
|
-
});
|
|
1568
|
-
const {
|
|
1569
|
-
openId = ''
|
|
1570
|
-
} = resData || {};
|
|
1571
|
-
return openId;
|
|
1572
|
-
}
|
|
1573
|
-
/**
|
|
1574
|
-
* getOuterOpenId 获取接入方用户唯一标识
|
|
1575
|
-
* @public
|
|
1576
|
-
* @description 唯一标识 openId 用于服务接入方作为唯一标识、向腾讯出行服务同步订单等
|
|
1577
|
-
* @category 服务接入
|
|
1578
|
-
* @param {String} apiKey 服务接入方渠道标识
|
|
1579
|
-
* @returns {Promise<String>} 返回 openId,失败时返回空
|
|
1580
|
-
*/
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
async function getOuterOpenId(apiKey) {
|
|
1584
|
-
const {
|
|
1585
|
-
resData
|
|
1586
|
-
} = await new Request().post('user/mpinfo', {
|
|
1587
|
-
mpId: apiKey
|
|
1588
|
-
});
|
|
1589
|
-
const {
|
|
1590
|
-
openId = ''
|
|
1591
|
-
} = resData || {};
|
|
1592
|
-
return openId;
|
|
1593
|
-
}
|
|
1594
|
-
|
|
1595
|
-
/**
|
|
1596
|
-
* @public
|
|
1597
|
-
* @description 创建网络请求对象,用于向腾讯出行服务平台后台发送网络请求
|
|
1598
|
-
* @param {Object} [config] 参数配置
|
|
1599
|
-
* @param {Boolean} [config.withAuth=true] 是否填充登录态参数
|
|
1600
|
-
* @param {String} [config.host] 自定义的host域名
|
|
1601
|
-
* @param {Object} [config.baseParam] 默认携带的参数
|
|
1602
|
-
* @returns {Object} [Request实例](#class-request)
|
|
1603
|
-
* @example
|
|
1604
|
-
* const $ = getApp().tms.createRequest();
|
|
1605
|
-
* $.get(apiPath)
|
|
1606
|
-
* .then((resp) => {
|
|
1607
|
-
* // ...
|
|
1608
|
-
* })
|
|
1609
|
-
* .catch((err) => {
|
|
1610
|
-
* // ...
|
|
1611
|
-
* });
|
|
1612
|
-
*/
|
|
1613
|
-
|
|
1614
|
-
const createRequest = (config = {}) => new Request(config);
|
|
1615
|
-
/**
|
|
1616
|
-
* @description 埋点上报
|
|
1617
|
-
* @returns {Object} 包含[report方法](#report)的对象
|
|
1618
|
-
* @example
|
|
1619
|
-
* getReporter().report(reportData, reportNow);
|
|
1620
|
-
*/
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
const getReporter = () => ({
|
|
1624
|
-
report: cache
|
|
1625
|
-
});
|
|
1626
|
-
/**
|
|
1627
|
-
* @description 埋点上报(快速上报,不依赖用户userId标识)
|
|
1628
|
-
* @returns {Class} [FastReporter类](#class-fastreport)
|
|
1629
|
-
*/
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
const getFastReporter = () => FastReport;
|
|
1633
|
-
/**
|
|
1634
|
-
* @description 自定义事件机制
|
|
1635
|
-
* @returns {Object} [EventDispatcher实例](#class-eventdispatcher)
|
|
1636
|
-
*/
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
const getEventDispatcher = () => new EventDispatcher();
|
|
1640
|
-
/**
|
|
1641
|
-
* @description 获取地理位置方法的集合
|
|
1642
|
-
* @returns {Class} [Location类](#class-location)
|
|
1643
|
-
*/
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
const getLocationManager = () => getLocInstance();
|
|
1647
|
-
/**
|
|
1648
|
-
* @description 获取位置信息base类(业务无关)
|
|
1649
|
-
* @returns {Class} [Location类](#class-location)
|
|
1650
|
-
*/
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
const getLocationBaseClass = () => LocationBase$1;
|
|
1654
|
-
/**
|
|
1655
|
-
* @description init core包初始化, 小程序已在app.js中对齐初始化
|
|
1656
|
-
* @param {Object} options 初始化
|
|
1657
|
-
* @returns {undefined} 无返回值.
|
|
1658
|
-
*/
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
const init = (options = {}) => {
|
|
1662
|
-
startListenApp();
|
|
1663
|
-
const {
|
|
1664
|
-
appVersion,
|
|
1665
|
-
wxAppId,
|
|
1666
|
-
client,
|
|
1667
|
-
defaultHost,
|
|
1668
|
-
cloudEnvId,
|
|
1669
|
-
appEnv,
|
|
1670
|
-
appPagePaths,
|
|
1671
|
-
homePage
|
|
1672
|
-
} = options;
|
|
1673
|
-
setEnvInfo({
|
|
1674
|
-
wxAppId,
|
|
1675
|
-
appVersion,
|
|
1676
|
-
appEnv,
|
|
1677
|
-
client,
|
|
1678
|
-
cloudEnvId
|
|
1679
|
-
});
|
|
1680
|
-
setAppPagePaths(appPagePaths, homePage);
|
|
1681
|
-
Request.defaultHost = defaultHost; // 初始化云环境
|
|
1682
|
-
|
|
1683
|
-
wx.cloud.init({
|
|
1684
|
-
env: cloudEnvId
|
|
1685
|
-
});
|
|
1686
|
-
};
|
|
1687
|
-
/**
|
|
1688
|
-
* @description 获取用户位置信息 -- 兼容版 现有业务中有的使用promise, 有的没有, 做一下兼容
|
|
1689
|
-
* @returns { Promise } 位置信息
|
|
1690
|
-
*/
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
const getUserLocation = () => {
|
|
1694
|
-
const userLocation = getLocInstance().getUserLocation();
|
|
1695
|
-
|
|
1696
|
-
if (userLocation) {
|
|
1697
|
-
return Promise.resolve(userLocation);
|
|
1698
|
-
}
|
|
1699
|
-
|
|
1700
|
-
return getLocInstance().getLocationDetail(false);
|
|
1701
|
-
};
|
|
1702
|
-
|
|
1703
|
-
const api = {
|
|
1704
|
-
init,
|
|
1705
|
-
createRequest,
|
|
1706
|
-
setAuthInfo,
|
|
1707
|
-
getLogManager,
|
|
1708
|
-
getRealtimeLogManager,
|
|
1709
|
-
md5,
|
|
1710
|
-
getReporter,
|
|
1711
|
-
getFastReporter,
|
|
1712
|
-
getLocationManager,
|
|
1713
|
-
getLocationBaseClass,
|
|
1714
|
-
getEventDispatcher,
|
|
1715
|
-
getEnvInfo,
|
|
1716
|
-
getConfig,
|
|
1717
|
-
navigateToWebview: nav.navigateToWebview,
|
|
1718
|
-
isAppPageExist,
|
|
1719
|
-
getHomePage,
|
|
1720
|
-
callCloudFunc,
|
|
1721
|
-
setUserLocation: loc => {
|
|
1722
|
-
getLocInstance().setUserLocation(loc);
|
|
1723
|
-
},
|
|
1724
|
-
getUserLocation,
|
|
1725
|
-
|
|
1726
|
-
/* 字符串方法 */
|
|
1727
|
-
formatPlate,
|
|
1728
|
-
subStr,
|
|
1729
|
-
hidePhoneCenter,
|
|
1730
|
-
isValidPhone,
|
|
1731
|
-
isValidPlate,
|
|
1732
|
-
isValidAuthCode,
|
|
1733
|
-
roundStr,
|
|
1734
|
-
|
|
1735
|
-
/* 数字方法 */
|
|
1736
|
-
round,
|
|
1737
|
-
|
|
1738
|
-
/* 时间方法 */
|
|
1739
|
-
formatTime,
|
|
1740
|
-
formatTimeStr,
|
|
1741
|
-
formatTimeWithDetails,
|
|
1742
|
-
dateToString,
|
|
1743
|
-
|
|
1744
|
-
/* IPX方法 */
|
|
1745
|
-
ipxInit,
|
|
1746
|
-
isIPX,
|
|
1747
|
-
getIpxClass,
|
|
1748
|
-
getIpxConfig,
|
|
1749
|
-
|
|
1750
|
-
/* 处理对象方法 */
|
|
1751
|
-
serialize,
|
|
1752
|
-
|
|
1753
|
-
/* 获取外部合作商openid */
|
|
1754
|
-
getMpOpenId,
|
|
1755
|
-
// 变更为 getOuterOpenId
|
|
1756
|
-
getOuterOpenId,
|
|
1757
|
-
|
|
1758
|
-
/** rpx转px */
|
|
1759
|
-
rpxToPx,
|
|
1760
|
-
storage,
|
|
1761
|
-
...syncApi
|
|
1762
|
-
};
|
|
1763
|
-
|
|
1764
|
-
export { api as default };
|