@jiabaida/tools 1.0.0 → 1.0.2

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.
Files changed (57) hide show
  1. package/dist/cjs/core/BleApiManager.js +1 -1
  2. package/dist/cjs/core/BleCmdAnalysis/BaseParamProtocol.js +1 -0
  3. package/dist/cjs/core/BleCmdAnalysis/BleCmdAnalysis.js +1 -0
  4. package/dist/cjs/core/BleCmdAnalysis/BleCmdDD.js +1 -0
  5. package/dist/cjs/core/BleCmdAnalysis/BleCmdFFAA.js +1 -0
  6. package/dist/cjs/core/BleCmdAnalysis/BleCmdHVES.js +1 -0
  7. package/dist/cjs/core/BleCmdAnalysis/ESHostProtocol.js +1 -0
  8. package/dist/cjs/core/BleCmdAnalysis/readAndSetParam.js +1 -0
  9. package/dist/cjs/core/BleCmdAnalysis.js +1 -0
  10. package/dist/cjs/core/BleDataProcess.js +1 -0
  11. package/dist/cjs/core/OtaUpgrade.js +1 -0
  12. package/dist/cjs/core/TelinkApi.js +1 -0
  13. package/dist/cjs/core/Transfer.js +1 -0
  14. package/dist/cjs/core/commonfun.js +1 -1
  15. package/dist/cjs/core/dataJson/baseParamsJson.js +1 -0
  16. package/dist/cjs/core/keyAndPwdManager.js +1 -0
  17. package/dist/cjs/index.js +1 -1
  18. package/dist/esm/core/BleApiManager.js +1 -1
  19. package/dist/esm/core/BleCmdAnalysis/BaseParamProtocol.js +1 -0
  20. package/dist/esm/core/BleCmdAnalysis/BleCmdAnalysis.js +1 -0
  21. package/dist/esm/core/BleCmdAnalysis/BleCmdDD.js +1 -0
  22. package/dist/esm/core/BleCmdAnalysis/BleCmdFFAA.js +1 -0
  23. package/dist/esm/core/BleCmdAnalysis/BleCmdHVES.js +1 -0
  24. package/dist/esm/core/BleCmdAnalysis/ESHostProtocol.js +1 -0
  25. package/dist/esm/core/BleCmdAnalysis/readAndSetParam.js +1 -0
  26. package/dist/esm/core/BleCmdAnalysis.js +1 -0
  27. package/dist/esm/core/BleDataProcess.js +1 -0
  28. package/dist/esm/core/OtaUpgrade.js +1 -0
  29. package/dist/esm/core/TelinkApi.js +1 -0
  30. package/dist/esm/core/Transfer.js +1 -0
  31. package/dist/esm/core/commonfun.js +1 -1
  32. package/dist/esm/core/dataJson/baseParamsJson.js +1 -0
  33. package/dist/esm/core/keyAndPwdManager.js +1 -0
  34. package/dist/esm/index.js +1 -1
  35. package/package.json +13 -3
  36. package/src/core/BleApiManager.js +487 -0
  37. package/src/core/BleCmdAnalysis/BaseParamProtocol.js +651 -0
  38. package/src/core/BleCmdAnalysis/BleCmdAnalysis.js +222 -0
  39. package/src/core/BleCmdAnalysis/BleCmdDD.js +1214 -0
  40. package/src/core/BleCmdAnalysis/BleCmdDDA4.js +762 -0
  41. package/src/core/BleCmdAnalysis/BleCmdFFAA.js +407 -0
  42. package/src/core/BleCmdAnalysis/BleCmdHVES.js +1222 -0
  43. package/src/core/BleCmdAnalysis/ESHostProtocol.js +829 -0
  44. package/src/core/BleCmdAnalysis/index.js +7 -0
  45. package/src/core/BleCmdAnalysis/readAndSetParam.js +288 -0
  46. package/src/core/BleDataProcess.js +355 -0
  47. package/src/core/OtaUpgrade.js +338 -0
  48. package/src/core/TelinkApi.js +73 -0
  49. package/src/core/Transfer.js +516 -0
  50. package/src/core/array.js +10 -0
  51. package/src/core/commonfun.js +87 -0
  52. package/src/core/dataJson/baseParamsJson.js +754 -0
  53. package/src/core/dataJson/index.js +1 -0
  54. package/src/core/keyAndPwdManager.js +346 -0
  55. package/src/core/mqttServer.js +296 -0
  56. package/src/core/rsaEncrypt.js +45 -0
  57. package/src/index.js +11 -0
@@ -0,0 +1,516 @@
1
+ import { getOS } from './commonfun';
2
+
3
+ const zhHansReg = /[\u4E00-\u9FA5]/;
4
+
5
+ export const Transfer = {
6
+ // 十六进制字符串转二进制
7
+ hexStringToBinary(hexString) {
8
+ const decimalNumber = parseInt(hexString, 16);
9
+ const binaryString = decimalNumber.toString(2);
10
+ return binaryString;
11
+ },
12
+ // 循环遍历给定的数组 arr 中的每一项,并且检查该项中是否有一个键 key 的值等于给定的值 val。如果找到了这样的项,则返回该项在数组中的索引 i,否则返回 -1。去重
13
+ inArray(arr, key, val) {
14
+ for (let i = 0; i < arr.length; i++) {
15
+ if (arr[i][key] === val) {
16
+ return i;
17
+ }
18
+ }
19
+ return -1;
20
+ },
21
+ // 十进制转十六进制
22
+ decimalToHex(decimal, padding = 2) {
23
+ const hexDigits = [];
24
+ const hexMap = {
25
+ 10: 'A',
26
+ 11: 'B',
27
+ 12: 'C',
28
+ 13: 'D',
29
+ 14: 'E',
30
+ 15: 'F',
31
+ };
32
+
33
+ while (decimal > 0) {
34
+ const remainder = decimal % 16;
35
+ if (remainder >= 10) {
36
+ hexDigits.unshift(hexMap[remainder]);
37
+ } else {
38
+ hexDigits.unshift(`${remainder}`);
39
+ }
40
+ decimal = Math.floor(decimal / 16);
41
+ }
42
+
43
+ const hex = hexDigits.join('').padStart(padding, '0');
44
+ return hex;
45
+ },
46
+ decimalToHexArray(decimal, padding = 2) {
47
+ const inputHex = this.decimalToHex(decimal, padding);
48
+ const data = [('0' + inputHex.slice(-4, -2)).slice(-2), ('0' + inputHex.slice(-2)).slice(-2)].map((o) => `0x${o}`);
49
+ return data;
50
+ },
51
+ // 十六进制转十进制
52
+ hexToDecimal(hex) {
53
+ let decimal = 0;
54
+ const hexMap = {
55
+ A: 10,
56
+ B: 11,
57
+ C: 12,
58
+ D: 13,
59
+ E: 14,
60
+ F: 15,
61
+ };
62
+
63
+ for (let i = 0; i < hex.length; i++) {
64
+ const currentDigit = hex[i];
65
+ if (hexMap.hasOwnProperty(currentDigit)) {
66
+ decimal = decimal * 16 + hexMap[currentDigit];
67
+ } else {
68
+ decimal = decimal * 16 + parseFloat(currentDigit, 16);
69
+ }
70
+ }
71
+
72
+ return decimal;
73
+ },
74
+ // ArrayBuffer转16进制字符串
75
+ arrayBufferToHex(arrayBuffer) {
76
+ return this.arrayBufferToHexArray(arrayBuffer, false).join('');
77
+ },
78
+ // ArrayBuffer转16进制数组
79
+ arrayBufferToHexArray(arrayBuffer, withPrefix = true) {
80
+ return Array.prototype.map.call(new Uint8Array(arrayBuffer), (x) => {
81
+ let hex = ('00' + x.toString(16)).slice(-2);
82
+ return withPrefix ? `0x${hex}` : hex;
83
+ });
84
+ },
85
+ // 判断数组数据是否重复
86
+ areArraysEqual(arr1, arr2) {
87
+ if (arr1.length !== arr2.length) {
88
+ return false;
89
+ }
90
+ return arr1.every((value, index) => value === arr2[index]);
91
+ },
92
+ // 取ascii码转十六进制
93
+ convertASCIItoHex(asciiVal) {
94
+ let asciiCode = asciiVal.charCodeAt(0);
95
+ let hexValue = this.decimalToHex(asciiCode);
96
+ return hexValue;
97
+ },
98
+ // 获取参数指令校验位 为数据段内容+长度字节+状态码字节的校验和然后在取反加1
99
+ getParamCheck(content) {
100
+ // 命令码+数据长度
101
+ // let sum = (content[0] & 0x0ff) + (content[1] & 0x0ff);
102
+ let sum = 0;
103
+ for (let i = 0; i < content.length; i++) {
104
+ sum = sum + (content[i] & 0x0ff);
105
+ }
106
+ sum = sum ^ 0xffff;
107
+ // 此为十进制数据
108
+ sum = sum + 1;
109
+ // 转为十六进制 并拆分为两个字节
110
+ sum = this.decimalToHex(sum);
111
+ let check1 = sum.substr(0, 2);
112
+ let check2 = sum.substr(2, 2);
113
+
114
+ return { check1: '0x' + check1, check2: '0x' + check2 };
115
+ },
116
+ // 将一个数字分隔为数组,每个元素表示两位的十六进制数
117
+ splitNumberToHexArray(decimalNumber) {
118
+ // 转换为十六进制并转为字符串
119
+ let hexString = decimalNumber.toString(16);
120
+ // 补零至偶数长度
121
+ hexString = hexString.length % 2 === 0 ? hexString : '0' + hexString;
122
+ // 分隔为两位一组的数组
123
+ let hexArray = hexString.match(/.{1,2}/g);
124
+ // 补零,确保结果数组有两个元素
125
+ while (hexArray.length < 2) {
126
+ hexArray.unshift('00');
127
+ }
128
+ // 添加 '0x' 前缀
129
+ return hexArray.map((hex) => '0x' + hex);
130
+ },
131
+ /**
132
+ *
133
+ * @param {string} base64
134
+ * @param {bool} withPrefix If ture returns a 0x prefix. Default as True.
135
+ * @returns {Array} Hex array
136
+ */
137
+ base64ToHexArray(base64, withPrefix = true) {
138
+ const arrayBuffer = uni.base64ToArrayBuffer(base64);
139
+ return this.arrayBufferToHexArray(arrayBuffer, withPrefix);
140
+ },
141
+ // 十进制数字转2byte的十六进制数组
142
+ decimalToTwoByteHexArray(decimal) {
143
+ let f = `00${decimal >> 8}`.slice(-2);
144
+ let e = `00${(decimal & 0xff).toString(16)}`.slice(-2);
145
+ return [`0x${f}`, `0x${e}`];
146
+ },
147
+ // 字符串转换为十六进制数组
148
+ stringToHexArray(str) {
149
+ const hexArray = [];
150
+ for (let i = 0; i < str.length; i++) {
151
+ let charCode = str.charCodeAt(i).toString(16);
152
+ charCode = charCode.length === 1 ? '0' + charCode : charCode;
153
+ hexArray.push(charCode);
154
+ }
155
+ return hexArray;
156
+ },
157
+ // 获取校验位的值
158
+ getAtValueCheck(cmdCode, lengthCode, hexArray) {
159
+ // 将十六进制转为十进制取和
160
+ let sum = 0;
161
+ hexArray.forEach((hexValue) => {
162
+ sum += parseInt(hexValue, 16);
163
+ });
164
+ let codeHex = this.getCheck(cmdCode, lengthCode, sum);
165
+ return codeHex;
166
+ },
167
+ // 获取at指令的check值
168
+ getCheck(cmdCode, lengthCode, sum) {
169
+ // 转为十进制 取和
170
+ let checkSum = this.hexToDecimal(cmdCode) + this.hexToDecimal(lengthCode) + sum;
171
+ // 转为带0x的十六进制
172
+ let codeHex = '0x' + this.decimalToHex(checkSum);
173
+ // 取低8位
174
+ codeHex = codeHex & 0xff;
175
+ // 转为十六进制 即为check值
176
+ return '0x' + this.decimalToHex(codeHex);
177
+ },
178
+ // 将HexArray转成Module指定格式的ArrayBuffer
179
+ hexArrayToModuleArrayBuffer(fields, hexArray, withCheck = true, withPrefix = true) {
180
+ const fieldsLength = fields.length; //e.g [0xff, 0xaa, 0x80]: 包头(2Byte) 指令码(1Byte)
181
+ let offset = fieldsLength + 1; // +1 for data length
182
+ if (withCheck) offset++; // check
183
+
184
+ let bufferLength = hexArray.length + offset;
185
+ const buffer = new ArrayBuffer(bufferLength);
186
+ const dataView = new DataView(buffer);
187
+ const lengthCode = this.decimalToHex(hexArray.length);
188
+
189
+ // 包头&指令码
190
+ fields.forEach((field, i) => {
191
+ dataView.setUint8(i, field);
192
+ });
193
+ // 数据位长度
194
+ dataView.setUint8(fieldsLength, '0x' + lengthCode);
195
+ // 数据位
196
+ let indexNum = fieldsLength + 1;
197
+ hexArray.forEach((el, index) => {
198
+ dataView.setUint8(indexNum, withPrefix ? '0x' + el : el);
199
+ indexNum += 1;
200
+ });
201
+ // 校验位
202
+ if (withCheck) {
203
+ const code = fields[2].toString(16); //
204
+ let check = this.getAtValueCheck(code, lengthCode, hexArray);
205
+ dataView.setUint8(bufferLength - 1, check);
206
+ }
207
+ return buffer;
208
+ },
209
+
210
+ };
211
+ function runPromiseInSequence(arr, input) {
212
+ return arr.reduce((promiseChain, currentFunction) => promiseChain.then(currentFunction), Promise.resolve(input));
213
+ }
214
+ const TAG = '[BLE_OTA]';
215
+ const DELAY = 25;
216
+ function myWrite({ deviceId, value, index }, succeed, fail) {
217
+ console.log(TAG, `即将${DELAY}毫秒后写入第 ${index} 个小包...`);
218
+ uni.writeBLECharacteristicValue({
219
+ deviceId,
220
+ serviceId: '0000FF00-0000-1000-8000-00805F9B34FB',
221
+ characteristicId: '0000FF02-0000-1000-8000-00805F9B34FB',
222
+ value,
223
+ writeType: 'writeNoResponse',
224
+ success: (res) => {
225
+ console.log(TAG, `写入第 ${index} 个小包 成功`);
226
+ succeed?.(JSON.stringify(res));
227
+ },
228
+ fail: (res) => {
229
+ console.log(TAG, `Error-写入第 ${index} 个小包 失败`, res);
230
+ fail?.(JSON.stringify(res));
231
+ },
232
+ });
233
+ }
234
+ function myWriteDelay(params) {
235
+ return new Promise((resolve, reject) => {
236
+ setTimeout(() => {
237
+ myWrite(
238
+ params,
239
+ (msg) => {
240
+ resolve({ succeed: true, msg });
241
+ },
242
+ (msg) => {
243
+ resolve({ succeed: false, msg });
244
+ }
245
+ );
246
+ }, DELAY);
247
+ });
248
+ }
249
+ export const BLE = {
250
+ serviceId: '0000FF00-0000-1000-8000-00805F9B34FB', //蓝牙特征值对应服务的 uuid
251
+ writeUUID: '0000FF02-0000-1000-8000-00805F9B34FB', //蓝牙特征值的 uuid
252
+ readUUID: '0000FF01-0000-1000-8000-00805F9B34FB',
253
+ TAG: '[BLE_OTA]',
254
+ WRITE_DELAY: 25,
255
+ PACKAGE_MAX_LENGTH: 240,
256
+ // 分包发送
257
+ sendMsgToKey(buffer, deviceId, fail) {
258
+ const { isAndroid, isIOS } = getOS();
259
+ // const writeType = isAndroid ? 'writeNoResponse' : 'write';
260
+ const writeType = 'writeNoResponse'; // 因IOS在小程序用write时会失败,统一使用无响应方式写入
261
+ console.log(TAG, `大包数据: Len=${buffer.byteLength} writeType=${writeType}`);
262
+ console.log(TAG, `写入中...`);
263
+ uni.writeBLECharacteristicValue({
264
+ deviceId,
265
+ serviceId: '0000FF00-0000-1000-8000-00805F9B34FB',
266
+ characteristicId: '0000FF02-0000-1000-8000-00805F9B34FB',
267
+ value: buffer,
268
+ writeType,
269
+ success: () => {
270
+ console.log(TAG, `写入成功`);
271
+ },
272
+ fail: (res) => {
273
+ console.log(TAG, `Error-写入失败`);
274
+ fail?.(JSON.stringify(res));
275
+ },
276
+ });
277
+ // if (isAndroid) {
278
+ // console.log(TAG, `[Android] 写入中...`);
279
+ // let promiseArr = [];
280
+ // const offset = 255;
281
+ // let bytes = buffer.byteLength;
282
+ // const times = Math.ceil(bytes / offset);
283
+ // for (let i = 1; i <= times; i++) {
284
+ // (function (index) {
285
+ // promiseArr.push(
286
+ // ({ succeed, msg }) =>
287
+ // new Promise(async (resolve, reject) => {
288
+ // if (succeed) {
289
+ // const value = buffer.slice((index - 1) * offset, index * offset);
290
+ // console.log(TAG, '排队中...', index, `Len: ${value.byteLength}`);
291
+ // const result = await myWriteDelay({ deviceId, value, index });
292
+ // resolve(result);
293
+ // } else {
294
+ // resolve({ succeed, msg });
295
+ // }
296
+ // })
297
+ // );
298
+ // })(i);
299
+ // }
300
+ // console.log(TAG, '大包数据Promise: ', promiseArr.length);
301
+
302
+ // runPromiseInSequence(promiseArr, { succeed: true, msg: 'init_value' }).then(({ succeed, msg }) => {
303
+ // console.log(TAG, '--------队列执行结果: ', succeed);
304
+ // if (succeed) {
305
+ // console.log(TAG, '大包数据顺序发送 成功 ');
306
+ // } else {
307
+ // console.log(TAG, 'Error-大包数据顺序发送 失败 ', msg);
308
+ // fail?.(msg);
309
+ // }
310
+ // });
311
+ // } else if (isIOS) {
312
+ // console.log(TAG, `[IOS] 写入中...`);
313
+ // uni.writeBLECharacteristicValue({
314
+ // deviceId,
315
+ // serviceId: '0000FF00-0000-1000-8000-00805F9B34FB',
316
+ // characteristicId: '0000FF02-0000-1000-8000-00805F9B34FB',
317
+ // value: buffer,
318
+ // writeType: 'write',
319
+ // success: () => {
320
+ // console.log(TAG, `[IOS] 写入成功`);
321
+ // },
322
+ // fail: (res) => {
323
+ // console.log(TAG, `[IOS] Error-写入失败`);
324
+ // fail?.(JSON.stringify(res));
325
+ // },
326
+ // });
327
+ // }
328
+
329
+ // let _this = this;
330
+ // const offset = 20;
331
+ // let bytes = buffer.byteLength;
332
+ // let pos = 0;
333
+ // while (bytes > 0) {
334
+ // let endPos = bytes > offset ? pos + offset : pos + bytes;
335
+ // const tempBuffer = buffer.slice(pos, endPos);
336
+ // pos += offset;
337
+ // bytes -= offset;
338
+ // // add delay to resolve 10007 error.
339
+ // await _this.sendDelay(_this.WRITE_DELAY, tempBuffer).then((buffer) => {
340
+ // _this.sendMsg(deviceId, buffer, fail);
341
+ // });
342
+ // }
343
+ },
344
+ sendDelay(delay, buffer) {
345
+ return new Promise((resolve, reject) => {
346
+ setTimeout(() => resolve(buffer), delay);
347
+ });
348
+ },
349
+ sendMsg(deviceId, value, fail) {
350
+ uni.writeBLECharacteristicValue({
351
+ deviceId,
352
+ serviceId: this.serviceId,
353
+ characteristicId: this.writeUUID,
354
+ value,
355
+ writeType: 'writeNoResponse',
356
+ success: (res) => {
357
+ console.log('[OTA] sendMsg succeed');
358
+ },
359
+ fail: (res) => {
360
+ console.error('[OTA] sendMsg failed', JSON.stringify(res));
361
+ fail?.(JSON.stringify(res));
362
+ // setTimeout(() => {
363
+ // _this.sendMsg(_deviceId, _value);
364
+ // }, 15);
365
+ },
366
+ });
367
+ },
368
+ sendMsgDelay(delay, deviceId, value, fail) {
369
+ return new Promise((resolve, reject) => {
370
+ setTimeout(() => {
371
+ uni.writeBLECharacteristicValue({
372
+ deviceId,
373
+ serviceId: this.serviceId,
374
+ characteristicId: this.writeUUID,
375
+ value,
376
+ writeType: 'writeNoResponse',
377
+ success: (res) => {
378
+ // console.log('[OTA] sendMsg succeed');
379
+ resolve(true);
380
+ },
381
+ fail: (res) => {
382
+ console.error('[OTA] sendMsg failed', JSON.stringify(res));
383
+ resolve(false);
384
+ },
385
+ });
386
+ }, delay);
387
+ });
388
+ },
389
+ //
390
+ retryWarpper(asyncFunc, defaultRetryTime = 2, retryInterval = 20) {
391
+ let retryTime = defaultRetryTime;
392
+ const retryCallback = async function (...args) {
393
+ try {
394
+ return await asyncFunc(...args);
395
+ } catch (e) {
396
+ if (retryTime <= 0) throw e;
397
+ console.log(`写入失败,将在 ${retryInterval} 毫秒后重试,剩余重试次数 ${retryTime}`);
398
+ retryTime -= 1;
399
+ await new Promise((reslove) => setTimeout(reslove, retryInterval));
400
+ return await retryCallback(...args);
401
+ }
402
+ };
403
+ return retryCallback;
404
+ },
405
+ write(buffer, deviceId, delay = 20) {
406
+ console.log('write', deviceId, buffer.byteLength);
407
+ return new Promise((resolve, reject) =>
408
+ setTimeout(() => {
409
+ uni.writeBLECharacteristicValue({
410
+ deviceId,
411
+ serviceId: this.serviceId,
412
+ characteristicId: this.writeUUID,
413
+ value: buffer,
414
+ writeType: 'writeNoResponse',
415
+ success: (res) => {
416
+ resolve('ok');
417
+ },
418
+ fail: (res) => {
419
+ reject(JSON.stringify(res));
420
+ },
421
+ });
422
+ }, delay)
423
+ );
424
+ },
425
+ async loopSendMsg(buffer, deviceId, fail) {
426
+ console.log('loopSendMsg', deviceId, buffer.byteLength);
427
+ let _this = this;
428
+
429
+ const fetchDataWithRetry = _this.retryWarpper(_this.write);
430
+
431
+ const offset = 20;
432
+ let bytes = buffer.byteLength;
433
+ let pos = 0;
434
+ while (bytes > 0) {
435
+ let endPos = bytes > offset ? pos + offset : pos + bytes;
436
+ const tempBuffer = buffer.slice(pos, endPos);
437
+ pos += offset;
438
+ bytes -= offset;
439
+ // add delay to resolve 10007 error.
440
+ const res = await fetchDataWithRetry(tempBuffer, deviceId, _this.WRITE_DELAY).catch((e) => fail?.(e));
441
+ if (!res) {
442
+ break;
443
+ }
444
+ }
445
+ },
446
+ writeATCmd(atValue, deviceId, fail) {
447
+ const hexArray = Transfer.stringToHexArray(atValue + '\r\n');
448
+ let ab = Transfer.hexArrayToModuleArrayBuffer([0xff, 0xaa, 0x80], hexArray, true, true);
449
+ this.sendMsgToKey(ab, deviceId, fail);
450
+ },
451
+ transferFirmwareFileCmd(deviceId, hexArray, isEnd = false, fail) {
452
+ let ab = Transfer.hexArrayToModuleArrayBuffer([0xff, 0xaa, isEnd ? 0x51 : 0x50], hexArray, true, false);
453
+ this.sendMsgToKey(ab, deviceId, fail);
454
+ },
455
+ formatOTAContent(content) {
456
+ if (content != '') {
457
+ const [_otaInfo, otaStart, otaReStart] = content.split(';');
458
+ const [p1, p2, p3, filePath] = _otaInfo.split(',');
459
+ const otaInfo = _otaInfo.replace(filePath, 'local');
460
+ return { filePath, otaInfo, otaStart, otaReStart };
461
+ }
462
+ return null;
463
+ },
464
+ };
465
+ export class Observer {
466
+ constructor(exec) {
467
+ this.listeners = new Set();
468
+ exec({
469
+ next: (value) => this.listeners.forEach(({ next }) => next && next(value)),
470
+ error: (err) => this.listeners.forEach(({ error }) => error && error(err)),
471
+ complete: (value) => this.listeners.forEach(({ complete }) => complete && complete(value)),
472
+ });
473
+ }
474
+ subscribe(listeners) {
475
+ this.listeners.add(listeners);
476
+ return {
477
+ unsubscribe: () => this.listeners.delete(listeners),
478
+ };
479
+ }
480
+ }
481
+
482
+ export class Logger {
483
+ key;
484
+ temp;
485
+ constructor(key) {
486
+ this.key = key;
487
+ this.temp = {};
488
+ }
489
+ log(...args) {
490
+ console.log(this.key, '[OTA] ', ...args);
491
+ }
492
+ error(...args) {
493
+ console.error(this.key, '[OTA] ', ...args);
494
+ }
495
+ time(key) {
496
+ const obj = this.temp;
497
+ if (obj.hasOwnProperty(key)) {
498
+ this.error(`Timer '${key}' already exists`);
499
+ }
500
+ obj[key] = new Date().getTime();
501
+ }
502
+ timeEnd(key) {
503
+ const obj = this.temp;
504
+ if (!obj.hasOwnProperty(key)) {
505
+ this.error(`Timer '${key}' does not exist`);
506
+ return;
507
+ }
508
+ let s = obj[key];
509
+ let e = new Date().getTime();
510
+ this.log(`${key}: ${e - s}ms`);
511
+ delete obj[key];
512
+ return e - s;
513
+ }
514
+ }
515
+
516
+ export default Transfer;
@@ -0,0 +1,10 @@
1
+ // 导出独立函数而非默认导出
2
+ export const chunk = (array, size) => {
3
+ const chunks = [];
4
+ for (let i = 0; i < array.length; i += size) {
5
+ chunks.push(array.slice(i, i + size));
6
+ }
7
+ return chunks;
8
+ };
9
+
10
+ export const unique = (array) => [...new Set(array)];
@@ -0,0 +1,87 @@
1
+
2
+ export function isEmpty(v) {
3
+ return v === null || v === undefined || v === '';
4
+ }
5
+ export function isNotEmpty(v) {
6
+ return !isEmpty(v);
7
+ }
8
+
9
+ /**
10
+ * 检查数组中是否存在指定键值对
11
+ * @param {Array} arr - 要检查的数组
12
+ * @param {string} key - 要检查的键名
13
+ * @param {*} val - 要检查的键值
14
+ * @returns {number} - 如果找到匹配项,返回其索引;否则返回 -1
15
+ */
16
+ export function inArray(arr, key, val) {
17
+ for (let i = 0; i < arr.length; i++) {
18
+ if (arr[i][key] === val) {
19
+ return i
20
+ }
21
+ }
22
+ return -1
23
+ }
24
+ export function formatTimeHHmm(hours) {
25
+ const hour = Math.floor(hours);
26
+ const minute = Math.floor((hours - hour) * 60);
27
+ // #ifdef H5
28
+ console.log('H5环境')
29
+ // #endif
30
+ return `${hour}H:${minute}m`;
31
+ }
32
+
33
+ export function getOS() {
34
+ const os = uni.getSystemInfoSync()?.osName;
35
+ return {
36
+ isIOS: os == 'ios',
37
+ isAndroid: os == 'android',
38
+ };
39
+ }
40
+ export function getPlatform() {
41
+ return uni.getSystemInfoSync()?.uniPlatform || '';
42
+ }
43
+ // #region 事件总线
44
+ // 添加事件总线
45
+ export const eventBus = {
46
+ events: {},
47
+ /**
48
+ * 订阅事件
49
+ * @param {string} event - 事件名称
50
+ * @param {function} callback - 回调函数
51
+ */
52
+ on(event, callback) {
53
+ if (!this.events[event]) {
54
+ this.events[event] = [];
55
+ }
56
+ this.events[event].push(callback);
57
+ },
58
+ /**
59
+ * 取消订阅
60
+ * @param {string} event - 事件名称
61
+ * @param {Function} [callback] - 可选,指定要移除的回调
62
+ */
63
+ off(event, callback) {
64
+ if (!this.events[event]) return;
65
+ if (!callback) {
66
+ // 移除事件所有订阅
67
+ delete this.events[event];
68
+ return;
69
+ }
70
+ // 只移除指定回调
71
+ this.events[event] = this.events[event].filter(cb => cb !== callback);
72
+ // 清空时删除事件
73
+ if (this.events[event].length === 0) {
74
+ delete this.events[event];
75
+ }
76
+ },
77
+ /**
78
+ * 触发事件
79
+ * @param {string} event - 事件名称
80
+ * @param {...any} args - 事件参数
81
+ */
82
+ emit(event, ...args) {
83
+ if (!this.events[event]) return;
84
+ this.events[event].forEach(callback => callback(...args));
85
+ }
86
+ };
87
+