@lambo-design-mobile/lambo-js-bridge 1.0.0-beta.4 → 1.0.0-beta.40

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.
@@ -1,301 +1,704 @@
1
+ /* eslint-disable no-undef */
2
+ /* eslint-disable @typescript-eslint/no-unused-vars */
1
3
  // import * as ww from '@wecom/jssdk'
2
- import ajax from "@lambo-design-mobile/shared/utils/ajax";
3
- import config from "@lambo-design-mobile/shared/config/config";
4
+ import ajax from '@lambo-design-mobile/shared/utils/ajax';
5
+ import config from '@lambo-design-mobile/shared/config/config';
4
6
 
5
7
  class WeComAdapter {
6
- constructor(_options) {
7
- this.corpId = _options.weComId; // 保存 appId 以便在 getInitInfo 中使用
8
- // if(!window.wx){
9
- // // const script = document.createElement('script')
10
- // // script.src = "//wwcdn.weixin.qq.com/node/open/js/wecom-jssdk-1.3.1.js"
11
- // // document.head.appendChild(script)
12
- // const script = document.createElement('script');
13
- // script.src = "//res.wx.qq.com/open/js/jweixin-1.2.0.js";
14
- // document.head.appendChild(script);
15
- // const script1 = document.createElement('script');
16
- // script1.src = "https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js";
17
- // document.head.appendChild(script1);
18
- // }
19
- // this.init( _options)
20
- function loadScript(src) {
21
- return new Promise((resolve, reject) => {
22
- const script = document.createElement('script');
23
- script.src = src;
24
- script.onload = () => resolve(script);
25
- script.onerror = () => reject(new Error('Failed to load script'));
26
- document.head.appendChild(script);
27
- });
28
- }
29
- loadScript('//res.wx.qq.com/open/js/jweixin-1.2.0.js')
30
- .then(script => {
31
- console.log('Script loaded');
32
- this.init(_options);
33
- })
34
- .catch(err => console.error(err));
8
+ constructor(_options) {
9
+ this.corpId = _options.weComId; // 保存 appId 以便在 getInitInfo 中使用
10
+ this.agentId = _options.agentId;
11
+ this.isRecording = false;
12
+ // if(!window.wx){
13
+ // // const script = document.createElement('script')
14
+ // // script.src = "//wwcdn.weixin.qq.com/node/open/js/wecom-jssdk-1.3.1.js"
15
+ // // document.head.appendChild(script)
16
+ // const script = document.createElement('script');
17
+ // script.src = "//res.wx.qq.com/open/js/jweixin-1.2.0.js";
18
+ // document.head.appendChild(script);
19
+ // const script1 = document.createElement('script');
20
+ // script1.src = "https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js";
21
+ // document.head.appendChild(script1);
22
+ // }
23
+ // this.init( _options)
24
+ function loadScript(src) {
25
+ return new Promise((resolve, reject) => {
26
+ const script = document.createElement('script');
27
+ script.src = src;
28
+ script.onload = () => resolve(script);
29
+ script.onerror = () => reject(new Error('Failed to load script'));
30
+ document.head.appendChild(script);
31
+ });
35
32
  }
36
33
 
34
+ let self = this;
35
+ function initJsSdk() {
36
+ loadScript('//res.wx.qq.com/open/js/jweixin-1.2.0.js')
37
+ .then((script) => {
38
+ console.log('Script loaded');
39
+ self.init(_options);
40
+ })
41
+ .catch((err) => console.error(err));
42
+ }
37
43
 
44
+ const ua = navigator.userAgent;
45
+ const isiOS = /iPhone|iPad|iPod/i.test(ua);
46
+ const isMiniProgramUA = /miniProgram/i.test(ua);
47
+ const isiOSMiniProgramUA = isiOS && isMiniProgramUA;
38
48
 
39
- async init(options) {
40
- const currentUrl = encodeURIComponent(window.location.href.split('#')[0]);
41
- ajax.request({
42
- url: config.upmsServerContext + '/manage/ibpWxCpBaseinfo/gtJsTicket?corpId='+options.weComId+"&url="+currentUrl,
43
- method: 'get'
44
- }).then((resp) => {
45
- if(resp.data.code===1){
46
- const {data} = resp.data
47
- wx.config({
48
- beta:true,
49
- // debug: true,
50
- appId: data.corpId, // 必填,企业微信的corpid,必须与当前登录的企业一致
51
- // agentid: '1000065', // 必填,企业微信的应用id (e.g. 1000247)
52
- timestamp: data.timestamp, // 必填,生成签名的时间戳
53
- nonceStr: data.noncestr, // 必填,生成签名的随机串
54
- signature: data.signature,// 必填,签名,见附录-JS-SDK使用权限签名算法
55
- jsApiList: ['getLocation','scanQRCode','chooseImage','openLocation','getLocalImgData'], //必填,传入需要使用的接口名称
56
- success: function(res) {
57
- console.log("ready...")
58
- },
59
- fail: function(res) {
60
- if(res.errMsg.indexOf('function not exist') > -1){
61
- alert('版本过低请升级')
62
- }
63
- }
64
- });
49
+ // iOS 使用的是 WKWebview,其 JavaScript 注入时机与 UIWebview 不同,存在更严格的同步性要求。
50
+ // 如果在你调用 wx.config 时,微信的 JS 桥还没有完全注入到当前 Webview 中,初始化就会失败。
51
+ if (isiOSMiniProgramUA) {
52
+ setTimeout(() => {
53
+ initJsSdk();
54
+ }, 1000);
55
+ } else {
56
+ initJsSdk();
57
+ }
58
+ }
65
59
 
66
- wx.error(function (res) {
67
- console.error(res)
68
- });
69
- wx.ready(function(){
70
- console.log("ready.....")
71
- // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
60
+ /**
61
+ * 初始化jssdk
62
+ * 2025-12-4 16:49:11 修改,增加审计日志回调函数auditLog,在不同阶段会调用该回调函数,调用参数如下
63
+ * {
64
+ * seg: 阶段,当前有 beforeConfig、configError、afterConfig、ready
65
+ * title: 对阶段的文字描述
66
+ * }
67
+ * 业务系统有需要对初始化jssdk进行审计的需求,在初始化jssdk的时候,在options中增加auditLog属性,并根据需要记录所需记录日志的阶段或者全部记录
68
+ * @param {*} options
69
+ * @returns
70
+ */
71
+ async init(options) {
72
+ // 在iOS小程序的webview中,currentUrl不能使用动态的,要使用小程序首次打开webview的URL,通过参数传进来
73
+ const currentUrl = encodeURIComponent(window.location.href.split('#')[0]);
74
+ if (options.auditLog && options.auditLog instanceof Function) {
75
+ options.auditLog({
76
+ seg: 'beforeConfig',
77
+ title: '开始企业微信jssdk认证',
78
+ });
79
+ }
80
+ ajax
81
+ .request({
82
+ url:
83
+ config.upmsServerContext +
84
+ '/manage/ibpWxCpBaseinfo/gtJsTicket?corpId=' +
85
+ options.weComId +
86
+ '&agentId=' +
87
+ options.agentId +
88
+ '&url=' +
89
+ (options.currentUrl || currentUrl),
90
+ method: 'get',
91
+ })
92
+ .then((resp) => {
93
+ if (resp.data.code === 1) {
94
+ const { data } = resp.data;
95
+ wx.config({
96
+ beta: true,
97
+ // debug: true,
98
+ appId: data.corpId, // 必填,企业微信的corpid,必须与当前登录的企业一致
99
+ // agentid: '1000065', // 必填,企业微信的应用id (e.g. 1000247)
100
+ timestamp: data.timestamp, // 必填,生成签名的时间戳
101
+ nonceStr: data.noncestr, // 必填,生成签名的随机串
102
+ signature: data.signature, // 必填,签名,见附录-JS-SDK使用权限签名算法
103
+ jsApiList: [
104
+ 'getLocation',
105
+ 'scanQRCode',
106
+ 'chooseImage',
107
+ 'openLocation',
108
+ 'getLocalImgData',
109
+ 'startRecord',
110
+ 'stopRecord',
111
+ 'onVoiceRecordEnd',
112
+ 'uploadVoice',
113
+ ], // 必填,传入需要使用的接口名称
114
+ success(res) {
115
+ console.log('ready...');
116
+ if (options.auditLog && options.auditLog instanceof Function) {
117
+ options.auditLog({
118
+ seg: 'afterConfig',
119
+ title: '完成企业微信jssdk认证',
72
120
  });
73
- wx.checkJsApi({
74
- jsApiList: ['getLocation','scanQRCode','chooseImage','openLocation'], // 需要检测的JS接口列表
75
- success: function(res) {
76
- // 以键值对的形式返回,可用的api值true,不可用为false
77
- // 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}
78
- }
121
+ }
122
+ },
123
+ fail(res) {
124
+ if (options.auditLog && options.auditLog instanceof Function) {
125
+ options.auditLog({
126
+ seg: 'configError',
127
+ title: '企业微信jssdk认证异常' + res.errMsg,
79
128
  });
129
+ }
130
+ if (res.errMsg.indexOf('function not exist') > -1) {
131
+ alert('版本过低请升级');
132
+ }
133
+ },
134
+ });
80
135
 
81
-
136
+ wx.error(function (res) {
137
+ if (options.auditLog && options.auditLog instanceof Function) {
138
+ options.auditLog({
139
+ seg: 'configError',
140
+ title: '企业微信jssdk认证异常wxerror',
141
+ });
82
142
  }
143
+ console.error(res);
144
+ });
145
+ wx.ready(function () {
146
+ if (options.auditLog && options.auditLog instanceof Function) {
147
+ options.auditLog({
148
+ seg: 'ready',
149
+ title: '完成企业微信jssdk认证,进入ready状态',
150
+ });
151
+ }
152
+ console.log('ready.....');
153
+ // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
154
+ });
155
+ wx.checkJsApi({
156
+ jsApiList: [
157
+ 'getLocation',
158
+ 'scanQRCode',
159
+ 'chooseImage',
160
+ 'openLocation',
161
+ 'getLocalImgData',
162
+ 'startRecord',
163
+ 'stopRecord',
164
+ 'onVoiceRecordEnd',
165
+ 'uploadVoice',
166
+ ], // 需要检测的JS接口列表
167
+ success(res) {
168
+ // 以键值对的形式返回,可用的api值true,不可用为false
169
+ // 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}
170
+ },
171
+ });
172
+ } else {
173
+ if (options.auditLog && options.auditLog instanceof Function) {
174
+ options.auditLog({
175
+ seg: 'configError',
176
+ title:
177
+ '企业微信jssdk认证异常请求认证参返回结果异常' +
178
+ JSON.stringify(resp),
179
+ });
180
+ }
181
+ }
182
+ })
183
+ .catch((err) => {
184
+ if (options.auditLog && options.auditLog instanceof Function) {
185
+ options.auditLog({
186
+ seg: 'configError',
187
+ title: '企业微信jssdk认证异常请求认证参数失败',
188
+ });
189
+ }
190
+ console.error(err);
191
+ });
192
+ }
83
193
 
84
- }).catch((err) => {
85
- console.error(err)
86
- })
194
+ async startWeComRecording(options = {}) {
195
+ if (this.isRecording) {
196
+ throw new Error('录音已在进行中');
87
197
  }
88
198
 
89
- async getLocation(options) {
90
- return new Promise((resolve, reject) => {
91
- wx.ready(() => {
92
- // 检查 options.type,如果为空或者不含有 'wgs84' 或 'bd09',则设置为 'gcj02'
93
- let locationType = options.type;
94
- if (!options.type || (options.type !== 'wgs84' && options.type !== 'bd09')) {
95
- locationType = 'gcj02';
199
+ return new Promise((resolve, reject) => {
200
+ wx.ready(() => {
201
+ wx.onVoiceRecordEnd({
202
+ complete: (res) => {
203
+ if (!this.isRecording) return;
204
+ this.isRecording = false;
205
+ console.log('录音满1分钟自动停止,开始处理...');
206
+ this._uploadAndSave(res.localId)
207
+ .then((fileInfo) => {
208
+ if (
209
+ options.onAutoStopSuccess &&
210
+ typeof options.onAutoStopSuccess === 'function'
211
+ ) {
212
+ options.onAutoStopSuccess(fileInfo);
213
+ }
214
+ })
215
+ .catch((error) => {
216
+ if (
217
+ options.onAutoStopError &&
218
+ typeof options.onAutoStopError === 'function'
219
+ ) {
220
+ options.onAutoStopError(error);
96
221
  }
222
+ });
223
+ },
224
+ });
225
+ wx.startRecord({
226
+ success: () => {
227
+ this.isRecording = true;
228
+ console.log('录音已开始...');
229
+ resolve();
230
+ },
231
+ fail: (err) => {
232
+ console.error('startRecord failed:', err);
233
+ reject(new Error('开始录音失败'));
234
+ },
235
+ });
236
+ });
237
+ });
238
+ }
97
239
 
98
- const fetchLocation = (type) => {
99
- return new Promise((resolve, reject) => {
100
- wx.getLocation({
101
- ...options,
102
- type: type,
103
- success: location => {
104
- const unifiedLocation = {
105
- latitude: location.latitude || location.lat || null, // 统一纬度属性
106
- longitude: location.longitude || location.lng || null, // 统一经度属性
107
- accuracy: location.accuracy || null // 精确度,如果有的话
108
- };
109
-
110
- if (!unifiedLocation.latitude || !unifiedLocation.longitude) {
111
- return reject(new Error('Invalid location data'));
112
- }
113
-
114
- resolve(unifiedLocation);
115
- },
116
- fail: err => {
117
- console.error("getLocation failed:", err);
118
- reject(err);
119
- }
120
- });
121
- });
240
+ async stopWeComRecording() {
241
+ if (!this.isRecording) {
242
+ return Promise.reject(new Error('当前没有正在进行的录音'));
243
+ }
244
+ return new Promise((resolve, reject) => {
245
+ wx.ready(() => {
246
+ wx.stopRecord({
247
+ success: (res) => {
248
+ this.isRecording = false;
249
+ console.log('用户手动停止录音,开始处理...');
250
+ this._uploadAndSave(res.localId).then(resolve).catch(reject);
251
+ },
252
+ fail: (err) => {
253
+ this.isRecording = false;
254
+ console.error('stopRecord failed:', err);
255
+ reject(new Error('停止录音失败'));
256
+ },
257
+ });
258
+ });
259
+ });
260
+ }
261
+ async _uploadAndSave(localId) {
262
+ return new Promise((resolve, reject) => {
263
+ wx.uploadVoice({
264
+ localId: localId,
265
+ isShowProgressTips: 1,
266
+ success: (uploadRes) => {
267
+ this._saveVoiceToServer(uploadRes.serverId)
268
+ .then(resolve)
269
+ .catch(reject);
270
+ },
271
+ fail: (err) => {
272
+ console.error('wx.uploadVoice failed:', err);
273
+ reject(new Error('上传语音至微信服务器失败'));
274
+ },
275
+ });
276
+ });
277
+ }
278
+ async _saveVoiceToServer(serverId) {
279
+ if (!this.corpId || !this.agentId) {
280
+ return Promise.reject(new Error('corpId 或 agentId 未初始化'));
281
+ }
282
+
283
+ // 后端接口使用 @RequestParam,对应 'application/x-www-form-urlencoded'
284
+ // const params = new URLSearchParams();
285
+ // params.append('corpId', this.corpId);
286
+ // params.append('agentId', this.agentId);
287
+ // params.append('mediaId', serverId);
288
+
289
+ try {
290
+ const response = await ajax({
291
+ method: 'post',
292
+ url: config.upmsServerContext + '/manage/ibpWxCpBaseinfo/handleVoice',
293
+ data: {
294
+ corpId: this.corpId,
295
+ agentId: this.agentId,
296
+ mediaId: this.serverId,
297
+ },
298
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
299
+ });
300
+ if (response.data && response.data.code === 1) {
301
+ console.log('后端处理成功,返回 FileInfoVO:', response.data.data);
302
+ return response.data.data; // 返回 FileInfoVO 对象
303
+ } else {
304
+ throw new Error(response.data.msg || '服务器处理录音文件失败');
305
+ }
306
+ } catch (err) {
307
+ console.error('调用后端 /handleVoice 接口失败:', err);
308
+ throw err;
309
+ }
310
+ }
311
+ /**
312
+ * 获取定位
313
+ * 2025-11-28 15:49:23 修改,增加审计日志回调函数auditLog,在不同阶段会调用该回调函数,调用参数如下
314
+ * {
315
+ * seg: 阶段,当前有 beforeCheck、checkError、afterCheck、beforeLocation、successLocation、errorLocation1、errorLocation2
316
+ * title: 对阶段的文字描述
317
+ * }
318
+ * 业务系统有需要对定位进行审计的需求,在调用定位的时候,在options中增加auditLog属性,并根据需要记录所需记录日志的阶段或者全部记录
319
+ * @param {*} options
320
+ * @returns
321
+ */
322
+ async getLocation(options) {
323
+ return new Promise((resolve, reject) => {
324
+ wx.ready(async () => {
325
+ // 解决在 URL 变化时,由于 wx.config 和 wx.ready 的异步特性导致的微信接口调用使用旧配置、签名失效或调用失败的问题
326
+ // 新增重试机制检查接口可用性
327
+ let retryInterval;
328
+ if (options.auditLog && options.auditLog instanceof Function) {
329
+ options.auditLog({
330
+ seg: 'beforeCheck',
331
+ title: '开始检测企业微信jssdk授权状态',
332
+ });
333
+ }
334
+ try {
335
+ await new Promise((retryResolve, retryReject) => {
336
+ let retryCount = 0;
337
+ const maxRetries = 30; // 最大重试次数 (30*100ms=3秒超时)
338
+ retryInterval = setInterval(async () => {
339
+ if (retryCount++ >= maxRetries) {
340
+ clearInterval(retryInterval);
341
+ retryReject(new Error('JS-SDK接口初始化超时'));
342
+ return;
343
+ }
344
+
345
+ // 检查getLocation接口是否可用
346
+ wx.checkJsApi({
347
+ jsApiList: ['getLocation'],
348
+ success: (res) => {
349
+ if (res.checkResult.getLocation === true) {
350
+ clearInterval(retryInterval);
351
+ retryResolve();
352
+ }
353
+ },
354
+ fail: () => {
355
+ /* 失败不计入重试,继续轮询 */
356
+ },
357
+ });
358
+ }, 100); // 每100ms检查一次
359
+ });
360
+ } catch (error) {
361
+ if (options.auditLog && options.auditLog instanceof Function) {
362
+ options.auditLog({
363
+ seg: 'checkError',
364
+ title: '检测企业微信jssdk授权状态异常并中止定位',
365
+ });
366
+ }
367
+ reject(new Error(`接口初始化失败: ${error.message}`));
368
+ return;
369
+ }
370
+
371
+ if (options.auditLog && options.auditLog instanceof Function) {
372
+ options.auditLog({
373
+ seg: 'afterCheck',
374
+ title: '检测企业微信jssdk授权状态结束',
375
+ });
376
+ }
377
+
378
+ // 检查 options.type,如果为空或者不含有 'wgs84' 或 'bd09',则设置为 'gcj02'
379
+ let locationType = options.type;
380
+ if (
381
+ !options.type ||
382
+ (options.type !== 'wgs84' && options.type !== 'bd09')
383
+ ) {
384
+ locationType = 'gcj02';
385
+ }
386
+
387
+ const fetchLocation = (type) => {
388
+ return new Promise((resolve, reject) => {
389
+ if (options.auditLog && options.auditLog instanceof Function) {
390
+ options.auditLog({
391
+ seg: 'beforeLocation',
392
+ title: '企业微信调用jssdk发起定位',
393
+ });
394
+ }
395
+ wx.getLocation({
396
+ ...options,
397
+ type,
398
+ success: (location) => {
399
+ const unifiedLocation = {
400
+ latitude: location.latitude || location.lat || null, // 统一纬度属性
401
+ longitude: location.longitude || location.lng || null, // 统一经度属性
402
+ accuracy: location.accuracy || null, // 精确度,如果有的话
122
403
  };
123
404
 
124
- if (locationType === 'bd09') {
125
- // 先获取 gcj02 坐标
126
- fetchLocation('gcj02').then(unifiedLocation => {
127
- // 将 gcj02 坐标转换为 bd09
128
- const [bd09Lng, bd09Lat] = coordtransform.gcj02tobd09(unifiedLocation.longitude, unifiedLocation.latitude);
129
- unifiedLocation.longitude = bd09Lng;
130
- unifiedLocation.latitude = bd09Lat;
131
- resolve(unifiedLocation);
132
- }).catch(err => {
133
- reject(err);
405
+ if (options.auditLog && options.auditLog instanceof Function) {
406
+ options.auditLog({
407
+ seg: 'successLocation',
408
+ title:
409
+ '企业微信调用jssdk定位成功' +
410
+ JSON.stringify(unifiedLocation),
411
+ });
412
+ }
413
+
414
+ if (!unifiedLocation.latitude || !unifiedLocation.longitude) {
415
+ if (
416
+ options.auditLog &&
417
+ options.auditLog instanceof Function
418
+ ) {
419
+ options.auditLog({
420
+ seg: 'errorLocation1',
421
+ title: '企业微信调用jssdk定位异常,未取到经纬度',
134
422
  });
135
- } else {
136
- fetchLocation(locationType).then(resolve).catch(reject);
423
+ }
424
+ return reject(new Error('Invalid location data'));
137
425
  }
426
+
427
+ resolve(unifiedLocation);
428
+ },
429
+ fail: (err) => {
430
+ console.error('getLocation failed:', err);
431
+ if (options.auditLog && options.auditLog instanceof Function) {
432
+ options.auditLog({
433
+ seg: 'errorLocation2',
434
+ title: '企业微信调用jssdk定位异常,' + JSON.stringify(err),
435
+ });
436
+ }
437
+ reject(err);
438
+ },
138
439
  });
139
- });
140
- }
440
+ });
441
+ };
141
442
 
142
- async openLocation(options) {
143
- return new Promise((resolve, reject) => {
144
- wx.ready(() => {
145
- wx.openLocation({
146
- latitude: options.latitude,
147
- longitude: options.longitude,
148
- name: options.name || '',
149
- address: options.address || '',
150
- scale: options.scale || 1,
151
- infoUrl: options.infoUrl || '',
152
- success: () => {
153
- console.log("openLocation success");
154
- resolve();
155
- },
156
- fail: err => {
157
- console.error("openLocation failed:", err);
158
- reject(err);
159
- }
160
- });
443
+ if (locationType === 'bd09') {
444
+ // 先获取 gcj02 坐标
445
+ fetchLocation('gcj02')
446
+ .then((unifiedLocation) => {
447
+ // 将 gcj02 坐标转换为 bd09
448
+ const [bd09Lng, bd09Lat] = coordtransform.gcj02tobd09(
449
+ unifiedLocation.longitude,
450
+ unifiedLocation.latitude
451
+ );
452
+ unifiedLocation.longitude = bd09Lng;
453
+ unifiedLocation.latitude = bd09Lat;
454
+ resolve(unifiedLocation);
455
+ })
456
+ .catch((err) => {
457
+ reject(err);
161
458
  });
459
+ } else {
460
+ fetchLocation(locationType).then(resolve).catch(reject);
461
+ }
462
+ });
463
+ });
464
+ }
465
+
466
+ async openLocation(options) {
467
+ return new Promise((resolve, reject) => {
468
+ wx.ready(() => {
469
+ wx.openLocation({
470
+ latitude: options.latitude,
471
+ longitude: options.longitude,
472
+ name: options.name || '',
473
+ address: options.address || '',
474
+ scale: options.scale || 1,
475
+ infoUrl: options.infoUrl || '',
476
+ success: () => {
477
+ console.log('openLocation success');
478
+ resolve();
479
+ },
480
+ fail: (err) => {
481
+ console.error('openLocation failed:', err);
482
+ reject(err);
483
+ },
162
484
  });
163
- }
485
+ });
486
+ });
487
+ }
164
488
 
165
- async scanCode(options) {
166
- return new Promise((resolve, reject) => {
167
- wx.ready(() => {
168
- wx.scanQRCode({
169
- ...options,
170
- needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果
171
- success: (res) => {
172
- console.log("scanQRCode success:", res);
173
- resolve(res); // 当needResult 为 1 时,扫码返回的结果
174
- },
175
- fail: (err) => {
176
- console.error("scanQRCode failed:", err);
177
- reject(err);
178
- }
179
- });
180
- });
489
+ async scanCode(options) {
490
+ return new Promise((resolve, reject) => {
491
+ wx.ready(() => {
492
+ wx.scanQRCode({
493
+ ...options,
494
+ needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果
495
+ success: (res) => {
496
+ console.log('scanQRCode success:', res);
497
+ resolve(res); // 当needResult 为 1 时,扫码返回的结果
498
+ },
499
+ fail: (err) => {
500
+ console.error('scanQRCode failed:', err);
501
+ reject(err);
502
+ },
181
503
  });
182
- }
504
+ });
505
+ });
506
+ }
183
507
 
184
- async takePhoto(options) {
185
- return new Promise((resolve, reject) => {
186
- wx.ready(() => {
187
- wx.chooseImage({
188
- ...options,
189
- // count: 1, // 默认9,设置为1表示只选择一张图片
190
- // sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
191
- // sourceType: ['camera','album'], // 可以指定来源是相册还是相机,默认二者都有
192
- success: async (res) => {
193
- const imageInfo = res.localIds[0]; // 返回选定照片的第一个本地ID
194
- const results = {};
195
-
196
- if (!options.outputType) {
197
- // outputType为空,返回所有结果
198
- results.imageInfo = imageInfo;
199
- wx.getLocalImgData({
200
- localId: imageInfo,
201
- success: (dataRes) => {
202
- results.imageData = dataRes.localData;
203
- resolve(results);
204
- },
205
- fail: (err) => {
206
- console.error("getLocalImgData failed:", err);
207
- reject(err);
208
- }
209
- });
210
- } else {
211
- if (options.outputType.includes('info')) {
212
- results.imageInfo = imageInfo;
213
- }
214
- if (options.outputType.includes('data')) {
215
- await new Promise((resolve, reject) => {
216
- wx.getLocalImgData({
217
- localId: imageInfo, // 这里使用返回的第一个localId
218
- success: (dataRes) => {
219
- results.imageData = dataRes.localData;
220
- resolve();
221
- },
222
- fail: (err) => {
223
- console.error("getLocalImgData failed:", err);
224
- reject(err);
225
- }
226
- });
227
- });
228
- }
229
- if (options.outputType.includes('oss')) {
230
- await new Promise((resolve, reject) => {
231
- wx.getLocalImgData({
232
- localId: imageInfo, // 获取base64数据
233
- success: (dataRes) => {
234
- const file = this.dataURLtoFile(dataRes.localData, 'image.png');
235
- this.uploadToOSS(file, options).then((ossResult) => {
236
- results.imageOss = ossResult;
237
- resolve();
238
- }).catch((err) => {
239
- console.error("uploadToOSS failed:", err);
240
- reject(err);
241
- });
242
- },
243
- fail: (err) => {
244
- console.error("getLocalImgData failed:", err);
245
- reject(err);
246
- }
247
- });
248
- });
249
- }
250
- resolve(results);
251
- }
252
- },
253
- fail: (err) => {
254
- console.error("chooseImage failed:", err);
255
- reject(err);
508
+ async takePhoto(options) {
509
+ return new Promise((resolve, reject) => {
510
+ wx.ready(() => {
511
+ wx.chooseImage({
512
+ ...options,
513
+ // count: 1, // 默认9,设置为1表示只选择一张图片
514
+ // sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
515
+ // sourceType: ['camera','album'], // 可以指定来源是相册还是相机,默认二者都有
516
+ success: async (res) => {
517
+ const imageInfo = res.localIds[0]; // 返回选定照片的第一个本地ID
518
+ const results = {};
519
+
520
+ // 检查 outputType 是否为空或不包含 'info', 'data', 'oss' 中的任意一个值
521
+ if (
522
+ !options.outputType ||
523
+ !['info', 'data', 'oss'].some((type) =>
524
+ options.outputType.includes(type)
525
+ )
526
+ ) {
527
+ options.outputType = ['info', 'data', 'oss'];
528
+ }
529
+
530
+ if (options.outputType.includes('info')) {
531
+ results.imageInfo = imageInfo;
532
+ }
533
+
534
+ if (options.outputType.includes('data')) {
535
+ await new Promise((resolve, reject) => {
536
+ wx.getLocalImgData({
537
+ localId: imageInfo,
538
+ success: (dataRes) => {
539
+ results.imageData = dataRes.localData;
540
+ resolve();
541
+ },
542
+ fail: (err) => {
543
+ console.error('getLocalImgData failed:', err);
544
+ reject(err);
545
+ },
546
+ });
547
+ });
548
+ }
549
+
550
+ if (options.outputType.includes('oss')) {
551
+ await new Promise((resolve, reject) => {
552
+ wx.getLocalImgData({
553
+ localId: imageInfo,
554
+ success: (dataRes) => {
555
+ const fileName = new Date().getTime() + '.png';
556
+ let file;
557
+ if (options.method == 'file') {
558
+ file = this.dataURLtoFile(dataRes.localData, fileName);
559
+ } else {
560
+ file = this.dataUrltoBlob(dataRes.localData, fileName);
256
561
  }
562
+ this.uploadToOSS(file, options)
563
+ .then((ossResult) => {
564
+ results.imageOss = ossResult;
565
+ resolve();
566
+ })
567
+ .catch((err) => {
568
+ console.error('uploadToOSS failed:', err);
569
+ reject(err);
570
+ });
571
+ },
572
+ fail: (err) => {
573
+ console.error('getLocalImgData failed:', err);
574
+ reject(err);
575
+ },
257
576
  });
258
- });
577
+ });
578
+ }
579
+
580
+ resolve(results);
581
+ },
582
+ fail: (err) => {
583
+ console.error('chooseImage failed:', err);
584
+ reject(err);
585
+ },
259
586
  });
260
- }
587
+ });
588
+ });
589
+ }
261
590
 
262
- dataURLtoFile(dataurl, filename) {
263
- let arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
264
- bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
265
- while (n--) {
266
- u8arr[n] = bstr.charCodeAt(n);
267
- }
268
- return new File([u8arr], filename, {type: mime});
591
+ dataURLtoFile(dataurl, filename) {
592
+ const arr = dataurl.split(',');
593
+ const mime = arr[0].match(/:(.*?);/)[1];
594
+ const bstr = atob(arr[1]);
595
+ let n = bstr.length;
596
+ const u8arr = new Uint8Array(n);
597
+ while (n--) {
598
+ u8arr[n] = bstr.charCodeAt(n);
269
599
  }
600
+ return new File([u8arr], filename, { type: mime });
601
+ }
270
602
 
271
- uploadToOSS(file, options) {
272
- return new Promise((resolve, reject) => {
273
- let formData = new FormData();
274
- formData.append('file', file);
275
- ajax.post(options.ossServerContext + options.ossImgPutUrl, formData, { payload : true }).then(response => {
276
- if (response.data.code === 1) {
277
- const result = response.data.data;
278
- if (result.length > 0) {
279
- resolve(result[0]);
280
- } else {
281
- reject(new Error('No fileId returned'));
282
- }
283
- } else {
284
- reject(new Error('Upload failed'));
285
- }
286
- }).catch(error =>{
287
- reject(error);
288
- });
289
- });
603
+ dataUrltoBlob(dataurl, filename) {
604
+ const arr = dataurl.split(',');
605
+ const mime = arr[0].match(/:(.*?);/)[1];
606
+ console.log('base64^^^^^', arr[1]);
607
+ console.log('mime is ^^^^^^^', mime);
608
+ return this.base64ToBlob(arr[1], mime);
609
+ }
610
+
611
+ base64ToBlob(base64Data, contentType) {
612
+ contentType = contentType || '';
613
+ const sliceSize = 1024;
614
+ const byteCharacters = atob(base64Data);
615
+ const bytesLength = byteCharacters.length;
616
+ const slicesCount = Math.ceil(bytesLength / sliceSize);
617
+ const byteArrays = new Array(slicesCount);
618
+
619
+ for (let sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
620
+ const begin = sliceIndex * sliceSize;
621
+ const end = Math.min(begin + sliceSize, bytesLength);
622
+
623
+ const bytes = new Array(end - begin);
624
+ for (let offset = begin, i = 0; offset < end; ++i, ++offset) {
625
+ bytes[i] = byteCharacters[offset].charCodeAt(0);
626
+ }
627
+ byteArrays[sliceIndex] = new Uint8Array(bytes);
290
628
  }
629
+ return new Blob(byteArrays, { type: contentType });
630
+ }
291
631
 
292
- async getPlatform(options = {}) {
293
- // 获取初始化信息
294
- return {
295
- appId: this.corpId,
296
- platform: 'WeCom'
297
- };
632
+ uploadToOSS(file, options) {
633
+ if (options.method == 'file') {
634
+ return new Promise((resolve, reject) => {
635
+ const formData = new FormData();
636
+ formData.append('file', file);
637
+ ajax
638
+ .post(options.ossServerContext + options.ossImgPutUrl, formData, {
639
+ payload: true,
640
+ })
641
+ .then((response) => {
642
+ if (response.data.code === 1) {
643
+ const result = response.data.data;
644
+ if (result.length > 0) {
645
+ resolve(result[0]);
646
+ } else {
647
+ reject(new Error('No fileId returned'));
648
+ }
649
+ } else {
650
+ reject(new Error('Upload failed'));
651
+ }
652
+ })
653
+ .catch((error) => {
654
+ reject(error);
655
+ });
656
+ });
657
+ } else {
658
+ return new Promise((resolve, reject) => {
659
+ let formData = new FormData();
660
+ console.log('upload to oss file is ^^^^', file);
661
+ formData.append(
662
+ 'file',
663
+ file,
664
+ file.name || new Date().getTime() + '.png'
665
+ );
666
+ for (var value of formData.values()) {
667
+ console.log('upload to oss data is ^^^^', value);
668
+ }
669
+ ajax({
670
+ method: 'post',
671
+ url: options.ossServerContext + options.ossImgPutUrl,
672
+ headers: { 'Content-Type': 'multipart/form-data' },
673
+ data: formData,
674
+ payload: true,
675
+ })
676
+ .then((response) => {
677
+ if (response.data.code == 1) {
678
+ const result = response.data.data;
679
+ if (result.length > 0) {
680
+ resolve(result[0]);
681
+ } else {
682
+ reject(new Error('No fileId returned'));
683
+ }
684
+ } else {
685
+ reject(new Error('Upload failed'));
686
+ }
687
+ })
688
+ .catch((err) => {
689
+ reject(err);
690
+ });
691
+ });
298
692
  }
693
+ }
694
+
695
+ async getPlatform(options = {}) {
696
+ // 获取初始化信息
697
+ return {
698
+ appId: this.corpId,
699
+ platform: 'WeCom',
700
+ };
701
+ }
299
702
  }
300
703
 
301
704
  export default WeComAdapter;