@tmsfe/tms-core 0.0.13 → 0.0.17

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.
@@ -131,6 +131,16 @@ function getLocationManager() {
131
131
  return setUserLocation;
132
132
  }
133
133
 
134
+ if (name === 'locForNoAuth') {
135
+ return {
136
+ province: '广东省',
137
+ cityCode: '440300',
138
+ cityName: '深圳市',
139
+ latitude: 22.54286,
140
+ longitude: 114.05956
141
+ };
142
+ }
143
+
134
144
  return function (...args) {
135
145
  return ps.then(() => invoke(manager, name, args));
136
146
  };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { R as Request, g as getLogManager, a as getRealtimeLogManager } from './request-4c9af397.js';
1
+ import { R as Request, g as getLogManager, a as getRealtimeLogManager } from './request-fea3ef26.js';
2
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
3
  import { s as syncApi, f as formatPlate, a as subStr, h as hidePhoneCenter, i as isValidPhone, b as isValidPlate, c as isValidAuthCode, r as roundStr, 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 serialize, p as rpxToPx } from './ipxHelper-71ef86c1.js';
4
4
  import { m as md5 } from './md5-34a9daf3.js';
@@ -28,6 +28,17 @@ const getSystemInfo$1 = () => {
28
28
  host
29
29
  };
30
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;
31
42
  /**
32
43
  * @class FastReport
33
44
  * @classdesc 快速上报模块,不依赖用户标识和位置
@@ -45,20 +56,20 @@ class FastReport {
45
56
  * @param {Boolean} appVer 是否上报小程序版本
46
57
  * @returns {Promsie} 返回上报结果
47
58
  */
48
- static report(param, simulatedUserId = true, simulatedUserIdIndex = 40, reportShowScene = true, appVer = true) {
59
+ static report(param = {}, simulatedUserId = true, simulatedUserIdIndex = 40, reportShowScene = true, appVer = true) {
49
60
  var _data$;
50
61
 
51
- if (!(param !== null && param !== void 0 && param[27])) return Promise.reject('invalid report param');
52
- const data = new Array(41);
62
+ if (!param[27]) return Promise.reject('invalid report param');
53
63
  const env = getEnvInfo();
54
- Object.keys(param).forEach(key => {
55
- const valType = typeof param[key];
56
- if (valType === 'string') data[key] = param[key];else if (valType === 'object') data[key] = JSON.stringify(param[key]);else data[key] = String(param[key]);
57
- });
64
+ const data = handleParamOfDifferentType(param);
58
65
  data[9] = '2';
59
66
  data[33] = encodeURIComponent(JSON.stringify(getSystemInfo$1()));
60
- appVer && !data[10] && (data[10] = env.appVersion);
61
- if (!data[26]) data[26] = (_data$ = data[27]) === null || _data$ === void 0 ? void 0 : _data$[0];
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]);
62
73
  data[28] = env.client;
63
74
 
64
75
  if (reportShowScene && !data[29]) {
@@ -117,6 +128,17 @@ const parseAllCfgs = (configPaths, resData, defaultCfgs) => configPaths.map((pat
117
128
 
118
129
  return {}; // 没找到配置,返回一个空对象
119
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
+ };
120
142
  /**
121
143
  * getConfig 批量拉取配置
122
144
  * @description 拉取运营平台上的配置内容。关于运营平台的具体用法,参见{@link https://iwiki.woa.com/pages/viewpage.action?pageId=527948584}
@@ -154,14 +176,8 @@ function getConfig(configPath, extendAttr = {}, defaultCfg) {
154
176
  }
155
177
  }
156
178
 
157
- const configPaths = Array.isArray(configPath) ? configPath : [configPath];
179
+ const configPaths = formatConfigPaths(configPath);
158
180
  const defaultCfgs = defaultCfg && (Array.isArray(defaultCfg) ? defaultCfg : [defaultCfg]) || null;
159
- const {
160
- client
161
- } = getEnvInfo();
162
- configPaths.forEach((path, index) => {
163
- configPaths[index] = path.replace(/\$\{client\}/, client);
164
- });
165
181
  const extendAttrs = typeof extendAttr === 'string' ? extendAttr : JSON.stringify(extendAttr);
166
182
  const api = new Request();
167
183
  return api.post('marketing/config', {
@@ -751,6 +767,7 @@ let cityTheUserAt = '';
751
767
  // 用户城市变化事件名
752
768
  const CityChangeEventName = 'loc_city_changed';
753
769
  const LocationType = 'gcj02'; // 获取经纬度时的坐标名称
770
+ let ipLocationPromise = null; // ip定位请求的promise
754
771
  /**
755
772
  * @class Location
756
773
  * @classdesc 基于LocationBase,封装业务侧位置的接口。 将用户经纬度转化为城市等展示信息
@@ -977,6 +994,32 @@ class Location extends LocationBase$1 {
977
994
  }
978
995
  return request.post('basic/lbs/direction', { from, to, mode });
979
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
+ }
980
1023
  }
981
1024
  // 因为在构造函数中会用到wx的api,所以使用到时才实例化
982
1025
  let instance;
@@ -1120,11 +1163,11 @@ const getProvinceInfoByIp = () => {
1120
1163
  if (!ProvinceInfoCacheByIp) {
1121
1164
  ProvinceInfoCacheByIp = new Promise(async resolve => {
1122
1165
  try {
1123
- const loc = await R.post('basic/lbs/decodeip');
1166
+ const loc = await getLocInstance().getIpLocation();
1124
1167
  const {
1125
1168
  city,
1126
1169
  province
1127
- } = loc.resData.ad_info;
1170
+ } = loc.ad_info;
1128
1171
  resolve({
1129
1172
  cityName: city,
1130
1173
  province
@@ -1254,16 +1297,21 @@ const formatReportData = async (reportData, deviceData) => {
1254
1297
 
1255
1298
  }; // 对部分空数据使用默认数据填充
1256
1299
 
1257
- Object.keys(defaultReportData).forEach(key => {
1258
- param[key] = param[key] !== null && JSON.stringify(param[key]) || defaultReportData[key];
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]);
1259
1308
  }); // 所有上报数据都转换为字符串
1260
1309
 
1261
1310
  param.forEach((reportItem, index) => {
1262
1311
  if (reportItem && typeof reportItem !== 'string') {
1263
1312
  param[index] = `${JSON.stringify(reportItem)}`;
1264
1313
  } else {
1265
- const paramItem = param[index];
1266
- param[index] = paramItem || paramItem === 0 ? `${paramItem}` : '';
1314
+ param[index] = handleDefaultData(reportItem, '');
1267
1315
  }
1268
1316
  });
1269
1317
  return param.map(item => item !== null ? encodeURIComponent(item) : item);
@@ -0,0 +1,538 @@
1
+ import { m as md5 } from './md5-34a9daf3.js';
2
+ import { a as getAuthInfo, g as getEnvInfo } from './env-c7da70e1.js';
3
+
4
+ /**
5
+ * 本文件主要负责在小程序中日志打印功能,包含本地日志及实时日志. 主要做了两件事:
6
+ * 1、参数序列化处理;支持传递任意多个参数,并对类型为对象的参数进行字符串序列化处理(避免打印出来是'[Object Object]'的格式);
7
+ * 2、低版本兼容;
8
+ */
9
+ // 低版本不支持getLogManager或者getRealtimeLogManager时,用ManagerForLowerVersionLib来兼容
10
+ const ManagerForLowerVersionLib = {
11
+ debug: () => {},
12
+ info: () => {},
13
+ log: () => {},
14
+ warn: () => {},
15
+ error: () => {},
16
+ addFilterMsg: () => {},
17
+ setFilterMsg: () => {}
18
+ }; // 小程序基础库2.7.1版本以上支持,所以需要兼容性处理
19
+
20
+ let logInstance = null;
21
+ let rtLogInstance = null;
22
+
23
+ function getLogInstance() {
24
+ if (logInstance === null) {
25
+ logInstance = wx.getLogManager ? wx.getLogManager() : ManagerForLowerVersionLib;
26
+ }
27
+
28
+ return logInstance;
29
+ }
30
+
31
+ function getRTLogInstance() {
32
+ if (rtLogInstance === null) {
33
+ rtLogInstance = wx.getRealtimeLogManager ? wx.getRealtimeLogManager() : ManagerForLowerVersionLib;
34
+ }
35
+
36
+ return rtLogInstance;
37
+ }
38
+ /**
39
+ * 参数中有对象类型的,将其转换为字符串类型,以便查看
40
+ * @param {Array<Any>} params 需要格式化的数据
41
+ * @returns {Array<String>} 字符串序列化后的数据
42
+ */
43
+
44
+
45
+ const format = params => params.map(param => typeof param === 'string' ? param : JSON.stringify(param));
46
+ /**
47
+ * @namespace LOG
48
+ * @description 普通日志管理器,将日志记录在小程序日志文件中,用户上传后,可以在小程序后台-反馈管理中看到
49
+ */
50
+
51
+
52
+ const LOG = {
53
+ /**
54
+ * @description 写debug日志
55
+ * @param {...Any} params 需要打印的数据,支持任意多个
56
+ * @returns {Void} 无返回值
57
+ */
58
+ debug(...params) {
59
+ getLogInstance().debug(...format(params));
60
+ },
61
+
62
+ /**
63
+ * @description 写info日志
64
+ * @param {...Any} params 需要打印的数据,支持任意多个
65
+ * @returns {Void} 无返回值
66
+ */
67
+ info(...params) {
68
+ getLogInstance().info(...format(params));
69
+ },
70
+
71
+ /**
72
+ * @description 写log日志
73
+ * @param {...Any} params 需要打印的数据,支持任意多个
74
+ * @returns {Void} 无返回值
75
+ */
76
+ log(...params) {
77
+ getLogInstance().log(...format(params));
78
+ },
79
+
80
+ /**
81
+ * @description 写warn日志
82
+ * @param {...Any} params 需要打印的数据,支持任意多个
83
+ * @returns {Void} 无返回值
84
+ */
85
+ warn(...params) {
86
+ getLogInstance().warn(...format(params));
87
+ },
88
+
89
+ /**
90
+ * @description 写warn日志. LogManager并没有error方法,为了兼容旧代码,所以声明一个error方法
91
+ * @param {...Any} params 需要打印的数据,支持任意多个
92
+ * @returns {Void} 无返回值
93
+ */
94
+ error(...params) {
95
+ LOG.warn(...params);
96
+ }
97
+
98
+ };
99
+ /**
100
+ * @namespace RTLOG
101
+ * @description 实时日志,将日志实时上传至小程序后台-开发-运维中心-实时日志,方便快速排查漏洞,定位问题
102
+ */
103
+
104
+ const RTLOG = {
105
+ /**
106
+ * @description 写info日志
107
+ * @param {...Any} params 需要打印的数据,支持任意多个
108
+ * @returns {Void} 无返回值
109
+ */
110
+ info(...params) {
111
+ getRTLogInstance().info(...format(params));
112
+ },
113
+
114
+ /**
115
+ * @description 写warn日志
116
+ * @param {...Any} params 需要打印的数据,支持任意多个
117
+ * @returns {Void} 无返回值
118
+ */
119
+ warn(...params) {
120
+ getRTLogInstance().warn(...format(params));
121
+ },
122
+
123
+ /**
124
+ * @description 写error日志
125
+ * @param {...Any} params 需要打印的数据,支持任意多个
126
+ * @returns {Void} 无返回值
127
+ */
128
+ error(...params) {
129
+ getRTLogInstance().error(...format(params));
130
+ },
131
+
132
+ /**
133
+ * @description 添加过滤关键字
134
+ * @param {String} msg 关键字
135
+ * @returns {Void} 无返回值
136
+ */
137
+ addFilterMsg(msg) {
138
+ getRTLogInstance().addFilterMsg(msg);
139
+ },
140
+
141
+ /**
142
+ * @description 设置过滤关键字
143
+ * @param {String} msg 关键字
144
+ * @returns {Void} 无返回值
145
+ */
146
+ setFilterMsg(msg) {
147
+ getRTLogInstance().setFilterMsg(msg);
148
+ }
149
+
150
+ };
151
+ /**
152
+ * @description 获取日志管理器对象,该对象提供的方法同wx.getLogManager()提供的方法,详见微信文档
153
+ * @returns {Object} [LOG](#namespace-log)
154
+ * @example
155
+ * const logger = getLogManager();
156
+ * logger.log(1, 'str', { a: 1 }, ...);
157
+ * logger.info(1, 'str', { a: 1 }, ...);
158
+ * logger.debug(1, 'str', { a: 1 }, ...);
159
+ * logger.awrn(1, 'str', { a: 1 }, ...);
160
+ */
161
+
162
+ const getLogManager = () => LOG;
163
+ /**
164
+ * @description 获取实时日志管理器对象,该对象提供的方法同wx.getRealtimeLogManager()提供的方法,详见微信文档
165
+ * @returns {Object} [RTLOG](#namespace-rtlog)
166
+ * @example
167
+ * const logger = getRealtimeLogManager();
168
+ * logger.info(1, 'str', { a: 1 }, ...);
169
+ * logger.warn(1, 'str', { a: 1 }, ...);
170
+ * logger.error(1, 'str', { a: 1 }, ...);
171
+ */
172
+
173
+
174
+ const getRealtimeLogManager = () => RTLOG;
175
+
176
+ /**
177
+ * @copyright 2021-present, Tencent, Inc. All rights reserved.
178
+ * @brief request.js用于发起网络请求.
179
+ * request模块作为基于 tms-core & tms-runtime 的应用的公共请求模块。
180
+ * 目前支持在出行服务小程序或基于出行服务的小程序中调用。在后续tms-runtime支持公众号H5后,
181
+ * 将支持在H5中调用。
182
+ *
183
+ * 考虑到对不同运行环境的支持,强依赖运行环境的依赖,比如 wx.request,应通过注入的形式提供。
184
+ * 框架判断在不同的运行环境,切换调用不同运行环境提供的方法。
185
+ */
186
+ /**
187
+ * 用于序列化需要签名的参数
188
+ * @private
189
+ * @param {object} param 需要序列化的参数
190
+ * @returns {string} 序列化之后的参数字符串
191
+ */
192
+
193
+ const seriesParam = param => {
194
+ const keys = Object.keys(param).filter(key => typeof param[key] !== 'undefined').sort();
195
+ const series = keys.map(key => {
196
+ const val = param[key];
197
+
198
+ if (typeof val === 'number' && isNaN(val)) {
199
+ return `${key}null`;
200
+ }
201
+
202
+ return `${key}${typeof val === 'object' ? JSON.stringify(val) : val}`;
203
+ });
204
+ return series.join('');
205
+ };
206
+ /**
207
+ * 用于对request请求对象做签名
208
+ * @private
209
+ * @param {object} param 需要做签名的参数
210
+ * @returns {object} 签名后的参数对象
211
+ */
212
+
213
+
214
+ const sign = (param = {}) => {
215
+ const token = '';
216
+ const signture = md5(seriesParam(param) + token);
217
+ return { ...param,
218
+ sign: signture
219
+ };
220
+ };
221
+ /**
222
+ * 用于对request请求对象添加系统参数
223
+ * @private
224
+ * @param {object} param 接口调用传入的参数
225
+ * @param {Boolean} withAuth 是否需要登录参数
226
+ * @param {object} baseParam request实例定义的基础参数
227
+ * @returns {object} 全部参数对象
228
+ */
229
+
230
+
231
+ const composeParam = async (param = {}, withAuth = true, baseParam = {}) => {
232
+ const version = '1.0';
233
+ const {
234
+ appVersion,
235
+ wxAppId,
236
+ client
237
+ } = getEnvInfo();
238
+ const nonce = Math.random().toString(36).substr(2, 10);
239
+ const timestamp = Date.now();
240
+ const random = Math.random().toString().slice(2, 7);
241
+ const sourceId = ['', 'sinan', 'mycar'].indexOf(client) + 7; // 6 未知 7 云函数 8 出行 9 我的车
242
+
243
+ const seqId = `${timestamp}${sourceId}${random}`;
244
+ const paramsWithAuth = await modifyAuthParam(param, withAuth);
245
+ const combinedParam = Object.assign({
246
+ version,
247
+ appVersion,
248
+ nonce,
249
+ timestamp,
250
+ seqId,
251
+ wxAppId
252
+ }, { ...baseParam
253
+ }, { ...paramsWithAuth
254
+ });
255
+ return combinedParam;
256
+ };
257
+ /**
258
+ * 用于保证业务参数的登录态参数,
259
+ * 若接口不依赖登录态 如 user/login,则保证参数中不包括userId & token,
260
+ * 若接口依赖登录态,则保证参数中填充userId & token,
261
+ * @private
262
+ * @param {object} param 要校验登录态的业务参数
263
+ * @param {boolean} withAuth 是否要校验登录态
264
+ * @returns {object} 增加登录态后的参数
265
+ */
266
+
267
+
268
+ const modifyAuthParam = async (param, withAuth) => {
269
+ const requestParam = { ...param
270
+ };
271
+
272
+ if (withAuth) {
273
+ const {
274
+ userId,
275
+ token
276
+ } = await getAuthInfo();
277
+ requestParam.userId = userId;
278
+ requestParam.token = token;
279
+ return requestParam;
280
+ }
281
+
282
+ delete requestParam.userId;
283
+ delete requestParam.userid;
284
+ delete requestParam.token;
285
+ return requestParam;
286
+ };
287
+ /**
288
+ * @public
289
+ * @class Request
290
+ * @classdesc 网络请求类,对签名、鉴权等逻辑进行封装处理,用于向腾讯出行服务平台后台发送网络请求
291
+ */
292
+
293
+
294
+ class Request {
295
+ /**
296
+ * 默认的request host域名
297
+ * defaultHost 在tms-runtime初始化时进行设置,为出行服务接入层域名
298
+ * 具体业务模块 new Request() 使用时,不指定自定义 host ,将使用defaultHost
299
+ */
300
+ static defaultHost = '';
301
+ host = '';
302
+ withAuth = true;
303
+ baseParam = {};
304
+ /**
305
+ * Request 构造函数
306
+ * @param {Object} config 构造参数
307
+ * @param {Object} config.withAuth 是否填充登录态参数
308
+ * @param {Object} config.host 自定义的host域名
309
+ * @param {Object} config.baseParam 默认携带的参数
310
+ */
311
+
312
+ constructor(config = {
313
+ withAuth: true
314
+ }) {
315
+ if (config.host) {
316
+ this.host = config.host;
317
+ }
318
+
319
+ if (typeof config.withAuth !== 'undefined') {
320
+ this.withAuth = !!config.withAuth;
321
+ }
322
+
323
+ this.baseParam = config.baseParam || {};
324
+ }
325
+ /**
326
+ * 格式化接口路径
327
+ * @private
328
+ * @param {string} path 需要格式化的接口路径
329
+ * @returns {string} 格式化后的接口路径
330
+ */
331
+
332
+
333
+ makeUrl(path) {
334
+ if (/^http/i.test(path)) return path;
335
+ const host = this.host || Request.defaultHost;
336
+ const validHost = /^http/i.test(host) ? host : `https://${host}`;
337
+ return `${validHost}/${path}`;
338
+ }
339
+
340
+ /**
341
+ * @public
342
+ * @memberof Request
343
+ * @param {String} path 请求接口路径
344
+ * @param {Object} [param] 请求参数
345
+ * @param {Object} [header] 自定义请求头
346
+ * @returns {Promise} 接口响应
347
+ * @example
348
+ * const $ = getApp().tms.createRequest();
349
+ * $.get(apiPath)
350
+ * .then((data) => {
351
+ * // data {Object} 响应数据
352
+ * // {
353
+ * // errCode {Number} 接口响应状态码
354
+ * // errMsg {String} 接口响应状态信息
355
+ * // resData {Object} 接口返回数据
356
+ * // }
357
+ * })
358
+ * .catch((e) => {
359
+ * // e {Object} 错误信息
360
+ * });
361
+ */
362
+ get(path, param, header) {
363
+ return this.doRequest(path, param, 'GET', header);
364
+ }
365
+ /**
366
+ * @public
367
+ * @memberof Request
368
+ * @param {String} path 请求接口路径
369
+ * @param {Object} [param] 请求参数
370
+ * @param {Object} [header] 自定义请求头
371
+ * @returns {Promise} 接口响应
372
+ * @example
373
+ * const $ = getApp().tms.createRequest();
374
+ * $.post(apiPath)
375
+ * .then((data) => {
376
+ * // data {Object} 响应数据
377
+ * // {
378
+ * // errCode {Number} 接口响应状态码
379
+ * // errMsg {String} 接口响应状态信息
380
+ * // resData {Object} 接口返回数据
381
+ * // }
382
+ * })
383
+ * .catch((e) => {
384
+ * // e {Object} 错误信息
385
+ * });
386
+ */
387
+
388
+
389
+ post(path, param, header) {
390
+ return this.doRequest(path, param, 'POST', header);
391
+ }
392
+ /**
393
+ * 发送get方式的请求,该方法会返回wx.request全量的返回值(含data,header,cookies,statusCode)
394
+ * @memberof Request
395
+ * @param {string} path 请求接口路径
396
+ * @param {object} param 业务参数
397
+ * @param {object} header 自定义请求头
398
+ * @returns {promise} 接口请求promise
399
+ */
400
+
401
+
402
+ execGet(path, param, header) {
403
+ return this.createRequestTask(path, param, 'GET', header);
404
+ }
405
+ /**
406
+ * 发送post方式的请求,该方法会返回wx.request全量的返回值(含data,header,cookies,statusCode等)
407
+ * @memberof Request
408
+ * @param {string} path 请求接口路径
409
+ * @param {object} param 业务参数
410
+ * @param {object} header 自定义请求头
411
+ * @returns {promise} 接口请求promise
412
+ */
413
+
414
+
415
+ execPost(path, param, header) {
416
+ return this.createRequestTask(path, param, 'POST', header);
417
+ }
418
+ /**
419
+ * @memberof Request
420
+ * @param {String} path 请求接口路径
421
+ * @param {String} filePath 上传文件的本地路径
422
+ * @param {Object} param 需要携带的其他参数
423
+ * @param {Object} header 自定义的请求头
424
+ * @returns {Object} 接口返回结果
425
+ */
426
+
427
+
428
+ async upload(path, filePath, param, header) {
429
+ const requestParam = await composeParam(param, this.withAuth, this.baseParam);
430
+ const res = await new Promise((resolve, reject) => {
431
+ wx.uploadFile({
432
+ name: 'content',
433
+ url: this.makeUrl(path),
434
+ filePath,
435
+ formData: sign(requestParam),
436
+ header,
437
+ success: resolve,
438
+ fail: reject
439
+ });
440
+ });
441
+
442
+ if (typeof (res === null || res === void 0 ? void 0 : res.data) === 'string') {
443
+ return JSON.parse(res === null || res === void 0 ? void 0 : res.data);
444
+ }
445
+
446
+ return res === null || res === void 0 ? void 0 : res.data;
447
+ }
448
+ /**
449
+ * @memberof Request
450
+ * @param {string} path 请求接口路径
451
+ * @param {string} param 业务参数
452
+ * @param {string} method 请求方法 get/post
453
+ * @param {object} header 自定义的请求头
454
+ * @returns {object} 接口返回结果
455
+ */
456
+
457
+
458
+ async doRequest(path, param = {}, method = 'POST', header = {}) {
459
+ const res = await this.createRequestTask(path, param, method, header);
460
+
461
+ if (typeof (res === null || res === void 0 ? void 0 : res.data) === 'string') {
462
+ return JSON.parse(res === null || res === void 0 ? void 0 : res.data);
463
+ }
464
+
465
+ return res === null || res === void 0 ? void 0 : res.data;
466
+ }
467
+ /**
468
+ * 序列化一个 get 请求地址
469
+ * @memberof Request
470
+ * @param {string} path 请求接口路径
471
+ * @param {object} data 业务参数
472
+ * @returns {Promise} 返回序列化之后的 get 请求地址
473
+ */
474
+
475
+
476
+ async serialize(path, data = {}) {
477
+ let url = this.makeUrl(path);
478
+ const signData = await composeParam(data, this.withAuth, this.baseParam);
479
+ const signture = sign(signData);
480
+ const params = [];
481
+ Object.keys(signture).forEach(key => {
482
+ const val = encodeURIComponent(signture[key]);
483
+ params.push(`${key}=${val}`);
484
+ });
485
+ if (params.length) url += (/\?/.test(url) ? '&' : '?') + params.join('&');
486
+ return Promise.resolve({
487
+ url
488
+ });
489
+ }
490
+ /**
491
+ * 创建发送请求任务
492
+ * @memberof Request
493
+ * @param {string} path 请求接口路径
494
+ * @param {string} param 业务参数
495
+ * @param {string} method 请求方法 get/post
496
+ * @param {object} header 自定义的请求头
497
+ * @returns {Promise} 接口返回结果
498
+ */
499
+
500
+
501
+ async createRequestTask(path, param = {}, method = 'POST', header = {}) {
502
+ const requestParam = await composeParam(param, this.withAuth, this.baseParam);
503
+ const data = sign(requestParam);
504
+ const logger = getLogManager();
505
+ const res = await new Promise((resolve, reject) => {
506
+ wx.request({
507
+ url: this.makeUrl(path),
508
+ header,
509
+ method,
510
+ data,
511
+ success: res => {
512
+ resolve(res);
513
+ logger.log({
514
+ path,
515
+ header,
516
+ method,
517
+ param: data,
518
+ res: res === null || res === void 0 ? void 0 : res.data
519
+ });
520
+ },
521
+ fail: err => {
522
+ reject(err);
523
+ logger.log({
524
+ path,
525
+ header,
526
+ method,
527
+ param: data,
528
+ err
529
+ });
530
+ }
531
+ });
532
+ });
533
+ return res;
534
+ }
535
+
536
+ }
537
+
538
+ export { Request as R, getRealtimeLogManager as a, getLogManager as g };
package/dist/request.js CHANGED
@@ -1,3 +1,3 @@
1
1
  import './md5-34a9daf3.js';
2
- export { R as default } from './request-4c9af397.js';
2
+ export { R as default } from './request-fea3ef26.js';
3
3
  import './env-c7da70e1.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tmsfe/tms-core",
3
- "version": "0.0.13",
3
+ "version": "0.0.17",
4
4
  "description": "tms运行时框架",
5
5
  "repository": {
6
6
  "type": "git",
@@ -34,9 +34,7 @@
34
34
  "rollup": "^2.6.1",
35
35
  "rollup-plugin-node-resolve": "^5.2.0",
36
36
  "rollup-plugin-terser": "^6.1.0",
37
- "rollup-plugin-typescript2": "0.27.0",
38
- "rollup-plugin-replace": "^2.2.0",
39
- "typescript": "^4.5.2"
37
+ "rollup-plugin-typescript2": "0.27.0"
40
38
  },
41
39
  "author": "tms·web",
42
40
  "gitHead": "72bf52451594b49a1c9f78edbad5956d414a66ca"
package/src/config.js CHANGED
@@ -15,6 +15,15 @@ const parseAllCfgs = (configPaths, resData, defaultCfgs) => configPaths.map((pat
15
15
  return {}; // 没找到配置,返回一个空对象
16
16
  });
17
17
 
18
+ const formatConfigPaths = (configPath) => {
19
+ const configPaths = Array.isArray(configPath) ? configPath : [configPath];
20
+ const { client } = getEnvInfo();
21
+ configPaths.forEach((path, index) => {
22
+ configPaths[index] = path.replace(/\$\{client\}/, client);
23
+ });
24
+ return configPaths;
25
+ };
26
+
18
27
  /**
19
28
  * getConfig 批量拉取配置
20
29
  * @description 拉取运营平台上的配置内容。关于运营平台的具体用法,参见{@link https://iwiki.woa.com/pages/viewpage.action?pageId=527948584}
@@ -47,12 +56,8 @@ function getConfig(configPath, extendAttr = {}, defaultCfg) {
47
56
  }
48
57
  }
49
58
  }
50
- const configPaths = Array.isArray(configPath) ? configPath : [configPath];
59
+ const configPaths = formatConfigPaths(configPath);
51
60
  const defaultCfgs = (defaultCfg && (Array.isArray(defaultCfg) ? defaultCfg : [defaultCfg])) || null;
52
- const { client } = getEnvInfo();
53
- configPaths.forEach((path, index) => {
54
- configPaths[index] = path.replace(/\$\{client\}/, client);
55
- });
56
61
  const extendAttrs = typeof extendAttr === 'string' ? extendAttr : JSON.stringify(extendAttr);
57
62
  const api = new Request();
58
63
  return api.post('marketing/config', {
package/src/fastreport.js CHANGED
@@ -16,6 +16,20 @@ const getSystemInfo = () => {
16
16
  return { model, wxVersion, platform, SDKVersion, host };
17
17
  };
18
18
 
19
+ const handleParamOfDifferentType = (param) => {
20
+ const data = new Array(41);
21
+ Object.keys(param).forEach((key) => {
22
+ const valType = typeof param[key];
23
+ if (valType === 'string') data[key] = param[key];
24
+ else if (valType === 'object') data[key] = JSON.stringify(param[key]);
25
+ else data[key] = String(param[key]);
26
+ });
27
+
28
+ return data;
29
+ };
30
+
31
+ const defAssign = (value, defaultValue) => (value || defaultValue);
32
+
19
33
  /**
20
34
  * @class FastReport
21
35
  * @classdesc 快速上报模块,不依赖用户标识和位置
@@ -31,20 +45,16 @@ export default class FastReport {
31
45
  * @param {Boolean} appVer 是否上报小程序版本
32
46
  * @returns {Promsie} 返回上报结果
33
47
  */
34
- static report(param, simulatedUserId = true, simulatedUserIdIndex = 40, reportShowScene = true, appVer = true) {
35
- if (!param?.[27]) return Promise.reject('invalid report param');
36
- const data = new Array(41);
48
+ static report(param = {}, simulatedUserId = true, simulatedUserIdIndex = 40, reportShowScene = true, appVer = true) {
49
+ if (!param[27]) return Promise.reject('invalid report param');
37
50
  const env = getEnvInfo();
38
- Object.keys(param).forEach((key) => {
39
- const valType = typeof param[key];
40
- if (valType === 'string') data[key] = param[key];
41
- else if (valType === 'object') data[key] = JSON.stringify(param[key]);
42
- else data[key] = String(param[key]);
43
- });
51
+ const data = handleParamOfDifferentType(param);
44
52
  data[9] = '2';
45
53
  data[33] = encodeURIComponent(JSON.stringify(getSystemInfo()));
46
- appVer && !data[10] && (data[10] = env.appVersion);
47
- if (!data[26]) data[26] = data[27]?.[0];
54
+ if (appVer) {
55
+ data[10] = defAssign(data[10], env.appVersion);
56
+ }
57
+ data[26] = defAssign(data[26], data[27]?.[0]);
48
58
  data[28] = env.client;
49
59
  if (reportShowScene && !data[29]) {
50
60
  const appShowScene = wx.getStorageSync('appShowScene');
@@ -134,6 +134,15 @@ function getLocationManager() {
134
134
  if (name === 'setUserLocation') {
135
135
  return setUserLocation;
136
136
  }
137
+ if (name === 'locForNoAuth') {
138
+ return {
139
+ province: '广东省',
140
+ cityCode: '440300',
141
+ cityName: '深圳市',
142
+ latitude: 22.54286,
143
+ longitude: 114.05956,
144
+ };
145
+ }
137
146
  return function (...args) {
138
147
  return ps.then(() => invoke(manager, name, args));
139
148
  };
@@ -16,6 +16,22 @@ interface UserLocationType {
16
16
  [key: string]: Promise<PostionType | void>
17
17
  }
18
18
 
19
+ interface IpLocationType {
20
+ ip: string,
21
+ ad_info: {
22
+ adcode: number,
23
+ city: string,
24
+ cityCode: string,
25
+ district: string,
26
+ nation: string,
27
+ province: string,
28
+ },
29
+ location: {
30
+ lat: number,
31
+ lng: number,
32
+ },
33
+ }
34
+
19
35
  const request = new Request();
20
36
  const event = new EventDispatcher();
21
37
 
@@ -27,6 +43,7 @@ let cityTheUserAt = '';
27
43
  // 用户城市变化事件名
28
44
  const CityChangeEventName = 'loc_city_changed';
29
45
  const LocationType = 'gcj02'; // 获取经纬度时的坐标名称
46
+ let ipLocationPromise: null | Promise<IpLocationType> = null; // ip定位请求的promise
30
47
 
31
48
  /**
32
49
  * @class Location
@@ -272,6 +289,33 @@ class Location extends LocationBase {
272
289
  }
273
290
  return request.post('basic/lbs/direction', { from, to, mode });
274
291
  }
292
+
293
+ /**
294
+ * ip定位
295
+ * 原理:通过调手图接口查询当前IP所在位置,市级的准确率是91%
296
+ * 注意:由于服务端对该查询服务有次数限制,所以本函数会缓存成功的promise
297
+ * @param force 是否清除上次的缓存重新请求
298
+ */
299
+ getIpLocation(force = false): Promise<IpLocationType> {
300
+ if (ipLocationPromise === null || force) {
301
+ ipLocationPromise = new Promise((resolve, reject) => {
302
+ request.post('basic/lbs/decodeip')
303
+ .then((res) => {
304
+ if (res.errCode === 0) {
305
+ resolve(res.resData as IpLocationType);
306
+ return;
307
+ }
308
+ reject({ erMsg: res.errMsg });
309
+ ipLocationPromise = null;
310
+ })
311
+ .catch((e) => {
312
+ reject(e);
313
+ ipLocationPromise = null;
314
+ });
315
+ });
316
+ }
317
+ return ipLocationPromise;
318
+ }
275
319
  }
276
320
 
277
321
  // 因为在构造函数中会用到wx的api,所以使用到时才实例化
package/src/report.js CHANGED
@@ -106,8 +106,8 @@ const getProvinceInfoByIp = () => {
106
106
  if (!ProvinceInfoCacheByIp) {
107
107
  ProvinceInfoCacheByIp = new Promise(async (resolve) => {
108
108
  try {
109
- const loc = await R.post('basic/lbs/decodeip');
110
- const { city, province } = loc.resData.ad_info;
109
+ const loc = await getLocInstance().getIpLocation();
110
+ const { city, province } = loc.ad_info;
111
111
  resolve({ cityName: city, province });
112
112
  } catch (_) {
113
113
  resolve({ cityName: '', province: '' });
@@ -212,8 +212,14 @@ const formatReportData = async (reportData, deviceData) => {
212
212
  36: getAppShowOptions(), // 打开小程序的场景值及参数
213
213
  };
214
214
  // 对部分空数据使用默认数据填充
215
- Object.keys(defaultReportData).forEach((key) => {
216
- param[key] = (param[key] !== null && JSON.stringify(param[key])) || defaultReportData[key];
215
+ const handleDefaultData = (paramItem, defaultData) => {
216
+ const arr = [paramItem, paramItem === 0, paramItem === false];
217
+ return (arr.some(item => !!item)) ? paramItem : (defaultData || '');
218
+ };
219
+
220
+ Object.keys(defaultReportData).forEach((index) => {
221
+ const paramItem = param[index];
222
+ param[index] = handleDefaultData(paramItem, defaultReportData[index]);
217
223
  });
218
224
 
219
225
  // 所有上报数据都转换为字符串
@@ -221,8 +227,7 @@ const formatReportData = async (reportData, deviceData) => {
221
227
  if (reportItem && typeof reportItem !== 'string') {
222
228
  param[index] = `${JSON.stringify(reportItem)}`;
223
229
  } else {
224
- const paramItem = param[index];
225
- param[index] = (paramItem || paramItem === 0) ? `${paramItem}` : '';
230
+ param[index] = handleDefaultData(reportItem, '');
226
231
  }
227
232
  });
228
233
 
package/src/request.js CHANGED
@@ -24,6 +24,9 @@ const seriesParam = (param) => {
24
24
  .sort();
25
25
  const series = keys.map((key) => {
26
26
  const val = param[key];
27
+ if (typeof val === 'number' && isNaN(val)) {
28
+ return `${key}null`;
29
+ }
27
30
  return `${key}${typeof val === 'object' ? JSON.stringify(val) : val}`;
28
31
  });
29
32
  return series.join('');