fstarter 2.10.56 → 2.10.57
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/.babelrc +6 -6
- package/.editorconfig +9 -9
- package/index.html +22 -22
- package/index.js +222 -222
- package/package.json +104 -104
- package/src/App.vue +38 -38
- package/src/i18n/en-US.js +35 -35
- package/src/i18n/zh-CN.js +35 -35
- package/src/main.js +95 -95
- package/src/plugins/assets/ak.js +948 -948
- package/src/plugins/assets/callNative.js +490 -490
- package/src/plugins/assets/compressImg.js +75 -75
- package/src/plugins/assets/config.js +106 -106
- package/src/plugins/assets/fileServer.js +469 -469
- package/src/plugins/assets/http.js +344 -344
- package/src/plugins/assets/ua.js +27 -27
- package/src/plugins/components/BSButton.vue +61 -61
- package/src/plugins/components/BSCascader.vue +465 -465
- package/src/plugins/components/BSCell.vue +48 -48
- package/src/plugins/components/BSDatePicker.vue +167 -167
- package/src/plugins/components/BSImage.vue +42 -42
- package/src/plugins/components/BSInput.vue +140 -140
- package/src/plugins/components/BSList.vue +81 -81
- package/src/plugins/components/BSPicCode.vue +96 -96
- package/src/plugins/components/BSPopup.vue +43 -43
- package/src/plugins/components/BSRadio.vue +97 -97
- package/src/plugins/components/BSSearch.vue +109 -109
- package/src/plugins/components/BSSelect.vue +144 -144
- package/src/plugins/components/BSSign.vue +454 -454
- package/src/plugins/components/BSStepper.vue +115 -115
- package/src/plugins/components/BSUpload.vue +92 -92
- package/src/plugins/components/BSUpload2.vue +397 -397
- package/src/plugins/components/BSVerCode.vue +128 -128
- package/src/plugins/components/BSViewer.vue +92 -92
- package/src/plugins/components/base.js +496 -496
- package/src/plugins/components/base2.js +489 -489
- package/src/plugins/lib/weixin.js +20 -20
- package/src/plugins/platform/index.js +7 -7
- package/src/plugins/platform/isp_phone.js +310 -310
- package/src/plugins/plugins/README.md +560 -0
- package/src/plugins/plugins/browserUtils.js +925 -0
- package/src/plugins/plugins/components/imageCropper.vue +299 -0
- package/src/plugins/plugins/components/images/bz.png +0 -0
- package/src/plugins/plugins/components/images/correct.png +0 -0
- package/src/plugins/plugins/components/images/error.png +0 -0
- package/src/plugins/plugins/components/images/mohu.png +0 -0
- package/src/plugins/plugins/components/images/qs.png +0 -0
- package/src/plugins/plugins/components/images/zd.png +0 -0
- package/src/plugins/plugins/components/pdfPreview.vue +688 -0
- package/src/plugins/plugins/demo.vue +832 -0
- package/src/plugins/plugins/native-js-sdk.js +360 -0
- package/src/plugins/plugins/nativeUtils.js +1444 -0
- package/src/plugins/route/index.js +140 -140
- package/src/plugins/selector/index.js +342 -342
- package/src/plugins/service/index.js +81 -81
- package/src/plugins/services/callCamera.js +53 -53
- package/src/plugins/services/exit.js +37 -36
- package/src/plugins/services/face.js +69 -69
- package/src/plugins/services/faceH5.js +54 -54
- package/src/plugins/services/faceInApp.js +31 -31
- package/src/plugins/services/faceTx.js +61 -61
- package/src/plugins/services/getFaceResult.js +104 -104
- package/src/plugins/services/getH5FaceResult.js +62 -62
- package/src/plugins/services/getMenus.js +40 -40
- package/src/plugins/services/getSystemData.js +144 -128
- package/src/plugins/services/getToken.js +93 -79
- package/src/plugins/services/getTxFaceResult.js +83 -83
- package/src/plugins/services/getUserInfo.js +47 -47
- package/src/plugins/services/goSetPage.js +40 -40
- package/src/plugins/services/hideFhoneTitle.js +36 -36
- package/src/plugins/services/index.js +45 -45
- package/src/plugins/services/init.js +35 -35
- package/src/plugins/services/jumpView.js +42 -40
- package/src/plugins/services/logout.js +44 -43
- package/src/plugins/services/share.js +113 -113
- package/src/plugins/services/statusBarHeight.js +39 -39
- package/src/plugins/session/index.js +32 -32
- package/src/services/getAuthInfo.js +22 -22
- package/src/services/index.js +9 -9
- package/src/services/sendVerCode.js +23 -23
- package/src/views/auth.vue +367 -367
- package/src/views/auth2.vue +90 -90
- package/src/views/auth3.vue +157 -157
- package/src/views/auth4.vue +8979 -8979
- package/src/views/auth5.vue +50 -50
- package/src/views/authh5.vue +369 -369
- package/src/views/components/BankSelect.vue +55 -55
- package/src/views/foot.vue +140 -140
- package/src/views/page.vue +222 -222
- package/src/views/shellFunc.vue +41 -41
- package/themes/basic.css +1 -1
- package/webpack.config.js +144 -144
- package/fstarter.iml +0 -9
|
@@ -0,0 +1,1444 @@
|
|
|
1
|
+
import native from './native-js-sdk.js'
|
|
2
|
+
import ImageCropper from './components/imageCropper.vue';
|
|
3
|
+
import { Toast } from "vant"
|
|
4
|
+
import axios from 'axios'
|
|
5
|
+
import { JSEncrypt } from 'jsencrypt'
|
|
6
|
+
const publicKey = `-----BEGIN PUBLIC KEY-----
|
|
7
|
+
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCSd6fXGTr+aQRQCFt3Vz7Pi3zW
|
|
8
|
+
rqUtVJt/U8lGVU8XX1aQ9mvqNTpeKwyHFNJSKBDbM3OrnHo2FvX7c8/ymhGKMBM3
|
|
9
|
+
NQfTlKqP3qXn3hvDppIrImpNAuYLNgfbiyHw37ggCpA1ynwJWqdHjOhllnuNsv67
|
|
10
|
+
1TpLHC4iCdA2vizuBwIDAQAB
|
|
11
|
+
-----END PUBLIC KEY-----`
|
|
12
|
+
import Vue from "vue";
|
|
13
|
+
// 获取当前环境是否为生产环境
|
|
14
|
+
function isProductionEnvironment(){
|
|
15
|
+
const url = window.location.href;
|
|
16
|
+
// 将URL转换为小写以便不区分大小写比较
|
|
17
|
+
const lowerUrl = url.toLowerCase();
|
|
18
|
+
console.log(lowerUrl, 'lowerUrl');
|
|
19
|
+
|
|
20
|
+
// 修复正则表达式 - 正确的IP地址匹配模式
|
|
21
|
+
const ipPattern = /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/;
|
|
22
|
+
|
|
23
|
+
// 其他测试环境关键词
|
|
24
|
+
const testKeywords = ['teststatic', 'testwx'];
|
|
25
|
+
|
|
26
|
+
// 如果URL包含IP地址格式或任一测试关键词,则返回false(测试环境)
|
|
27
|
+
// 否则返回true(生产环境)
|
|
28
|
+
return !(ipPattern.test(lowerUrl) || testKeywords.some(keyword => lowerUrl.includes(keyword)));
|
|
29
|
+
}
|
|
30
|
+
// 根据环境设置请求url key
|
|
31
|
+
let auth = 0 // 0: 不需要token 1: 需要token
|
|
32
|
+
let upLoadUrl = ''
|
|
33
|
+
let creatFaceUrl = ''
|
|
34
|
+
let faceResultUrl = ''
|
|
35
|
+
let appid = ''
|
|
36
|
+
let tokenKey = ''
|
|
37
|
+
let loginUrl = ''
|
|
38
|
+
// 是否登录
|
|
39
|
+
let loginPromise = null
|
|
40
|
+
|
|
41
|
+
if(isProductionEnvironment()){
|
|
42
|
+
console.log('生产环境')
|
|
43
|
+
auth = 1
|
|
44
|
+
upLoadUrl = 'https://file.ihasl.com/file/v1/hasl/fileAdmin/fileAdmin/upload'
|
|
45
|
+
creatFaceUrl = 'https://bcs.ihasl.com/api/v1/bcs/face/h5CreateOrder'
|
|
46
|
+
faceResultUrl = 'https://bcs.ihasl.com/api/v1/bcs/face/faceResultQuery'
|
|
47
|
+
appid = 'wx751d925fbededc73' // 回调安全域名 wx.ihasl
|
|
48
|
+
tokenKey = '6297391dca6d4090ae60959acb73cda1'
|
|
49
|
+
loginUrl = 'https://www.ihasl.com/pages/salessupport/app/#/login'
|
|
50
|
+
} else {
|
|
51
|
+
console.log('测试环境')
|
|
52
|
+
auth = 0
|
|
53
|
+
upLoadUrl = 'https://testfile.ihasl.com/file/v1/hasl/fileAdmin/fileAdmin/upload'
|
|
54
|
+
creatFaceUrl = 'https://testbcs.ihasl.com/api/v1/bcs/face/h5CreateOrder'
|
|
55
|
+
faceResultUrl = 'https://testbcs.ihasl.com/api/v1/bcs/face/faceResultQuery'
|
|
56
|
+
appid = 'wx38c646900b5b7ec0' // 回调安全域名 teststatic.com
|
|
57
|
+
tokenKey = '814a0b7eb0f82e02246da5e098b6e2b5'
|
|
58
|
+
loginUrl = 'https://teststatic.ihasl.com/pages/salessupport/app/#/login'
|
|
59
|
+
// 本地的
|
|
60
|
+
// loginUrl = 'http://172.20.10.2:8080/#/login'
|
|
61
|
+
}
|
|
62
|
+
console.log(appid, 'appid')
|
|
63
|
+
|
|
64
|
+
//
|
|
65
|
+
const nativeUtils = {
|
|
66
|
+
/**
|
|
67
|
+
* 判断当前环境是否为生产环境
|
|
68
|
+
*/
|
|
69
|
+
isProductionEnvironment(){
|
|
70
|
+
const url = window.location.href;
|
|
71
|
+
// 将URL转换为小写以便不区分大小写比较
|
|
72
|
+
const lowerUrl = url.toLowerCase();
|
|
73
|
+
|
|
74
|
+
// 检查URL中是否包含测试环境的关键词
|
|
75
|
+
const testKeywords = ['ip', 'teststatic', 'testwx'];
|
|
76
|
+
|
|
77
|
+
// 如果URL包含任一测试关键词,则返回false(测试环境)
|
|
78
|
+
// 否则返回true(生产环境)
|
|
79
|
+
return !testKeywords.some(keyword => lowerUrl.includes(keyword));
|
|
80
|
+
},
|
|
81
|
+
/**
|
|
82
|
+
* 设置用户信息
|
|
83
|
+
*/
|
|
84
|
+
setUserInfo(parmas) {
|
|
85
|
+
return new Promise((resolve, reject) => {
|
|
86
|
+
native.auth.setUserInfo(parmas).then(res => {
|
|
87
|
+
resolve(res);
|
|
88
|
+
}).catch(error => {
|
|
89
|
+
Toast.fail(`设置用户信息失败: ${error.message}`)
|
|
90
|
+
reject(error);
|
|
91
|
+
});
|
|
92
|
+
})
|
|
93
|
+
},
|
|
94
|
+
/**
|
|
95
|
+
* 获取用户信息
|
|
96
|
+
*/
|
|
97
|
+
getUserInfo() {
|
|
98
|
+
return new Promise((resolve, reject) => {
|
|
99
|
+
native.auth.getUserInfo().then(res => {
|
|
100
|
+
if(!!res){
|
|
101
|
+
resolve(res);
|
|
102
|
+
} else {
|
|
103
|
+
// 拿不到信息跳转登录
|
|
104
|
+
nativeUtils.toLogin()
|
|
105
|
+
}
|
|
106
|
+
}).catch(error => {
|
|
107
|
+
Toast.fail(`获取用户信息: ${error.message}`)
|
|
108
|
+
reject(error);
|
|
109
|
+
});
|
|
110
|
+
})
|
|
111
|
+
},
|
|
112
|
+
/**
|
|
113
|
+
* 清除用户信息
|
|
114
|
+
*/
|
|
115
|
+
clearUserInfo() {
|
|
116
|
+
return new Promise((resolve, reject) => {
|
|
117
|
+
native.auth.clearUserInfo().then(res => {
|
|
118
|
+
resolve(res);
|
|
119
|
+
}).catch(error => {
|
|
120
|
+
Toast.fail(`清除用户信息失败: ${error.message}`)
|
|
121
|
+
reject(error);
|
|
122
|
+
});
|
|
123
|
+
})
|
|
124
|
+
},
|
|
125
|
+
/**
|
|
126
|
+
* 微信分享
|
|
127
|
+
*/
|
|
128
|
+
share(parmas) {
|
|
129
|
+
return new Promise((resolve, reject) => {
|
|
130
|
+
native.thirdParty.wechat.share(parmas).then(res => {
|
|
131
|
+
resolve(res);
|
|
132
|
+
}).catch(error => {
|
|
133
|
+
Toast.fail(`分享失败: ${error.message}`)
|
|
134
|
+
reject(error);
|
|
135
|
+
});
|
|
136
|
+
})
|
|
137
|
+
},
|
|
138
|
+
/**
|
|
139
|
+
* 微信登录
|
|
140
|
+
*/
|
|
141
|
+
wechatLogin() {
|
|
142
|
+
return new Promise((resolve, reject) => {
|
|
143
|
+
native.thirdParty.wechat.login({
|
|
144
|
+
state: 'custom_state'
|
|
145
|
+
}).then(res => {
|
|
146
|
+
resolve(res);
|
|
147
|
+
}).catch(error => {
|
|
148
|
+
Toast.fail(`微信登录: ${error.message}`)
|
|
149
|
+
reject(error);
|
|
150
|
+
});
|
|
151
|
+
})
|
|
152
|
+
},
|
|
153
|
+
/**
|
|
154
|
+
* 打开系统浏览器
|
|
155
|
+
*/
|
|
156
|
+
openSystemBrowser(url) {
|
|
157
|
+
return new Promise((resolve, reject) => {
|
|
158
|
+
native.utils.openSystemBrowser({
|
|
159
|
+
url: url
|
|
160
|
+
}).then(res => {
|
|
161
|
+
resolve(res);
|
|
162
|
+
}).catch(error => {
|
|
163
|
+
Toast.fail(`微信登录: ${error.message}`)
|
|
164
|
+
reject(error);
|
|
165
|
+
});
|
|
166
|
+
})
|
|
167
|
+
},
|
|
168
|
+
/**
|
|
169
|
+
* 截屏
|
|
170
|
+
*/
|
|
171
|
+
screenshot(maxSize = 1024) {
|
|
172
|
+
return new Promise((resolve, reject) => {
|
|
173
|
+
native.utils.screenshot({
|
|
174
|
+
maxSize: maxSize // 截图压缩大小,单位为KB,默认200KB
|
|
175
|
+
}).then(res => {
|
|
176
|
+
resolve(res);
|
|
177
|
+
}).catch(error => {
|
|
178
|
+
Toast.fail(`截屏: ${error.message}`)
|
|
179
|
+
reject(error);
|
|
180
|
+
});
|
|
181
|
+
})
|
|
182
|
+
},
|
|
183
|
+
/**
|
|
184
|
+
* 横竖屏切换
|
|
185
|
+
*/
|
|
186
|
+
setScreenOrientation(screenOrientation) {
|
|
187
|
+
return new Promise((resolve, reject) => {
|
|
188
|
+
native.device.setScreenOrientation({
|
|
189
|
+
orientation: screenOrientation, // 可选值:'portrait', 'landscape' 或 'auto'
|
|
190
|
+
}).then(res => {
|
|
191
|
+
resolve(res);
|
|
192
|
+
}).catch(error => {
|
|
193
|
+
Toast.fail(`横竖屏切换: ${error.message}`)
|
|
194
|
+
reject(error);
|
|
195
|
+
});
|
|
196
|
+
})
|
|
197
|
+
},
|
|
198
|
+
/**
|
|
199
|
+
* 唤起其他app
|
|
200
|
+
*/
|
|
201
|
+
launchApp(params) {
|
|
202
|
+
return new Promise((resolve, reject) => {
|
|
203
|
+
native.utils.launchApp(params).then(res => {
|
|
204
|
+
resolve(res);
|
|
205
|
+
}).catch(error => {
|
|
206
|
+
Toast.fail(`唤起其他app: ${error.message}`)
|
|
207
|
+
reject(error);
|
|
208
|
+
});
|
|
209
|
+
})
|
|
210
|
+
},
|
|
211
|
+
/**
|
|
212
|
+
* 返回拦截
|
|
213
|
+
*/
|
|
214
|
+
setBackInterceptor(enable) {
|
|
215
|
+
return new Promise((resolve, reject) => {
|
|
216
|
+
native.navigator.setBackInterceptor({
|
|
217
|
+
enable: enable
|
|
218
|
+
}).then(res => {
|
|
219
|
+
resolve(res);
|
|
220
|
+
}).catch(error => {
|
|
221
|
+
Toast.fail(`设置返回拦截失败: ${error.message}`)
|
|
222
|
+
reject(error);
|
|
223
|
+
});
|
|
224
|
+
})
|
|
225
|
+
},
|
|
226
|
+
/**
|
|
227
|
+
* 页面重定向
|
|
228
|
+
*/
|
|
229
|
+
redirectTo(url) {
|
|
230
|
+
return new Promise((resolve, reject) => {
|
|
231
|
+
native.navigator.redirectTo({
|
|
232
|
+
name: 'h5',
|
|
233
|
+
params: {
|
|
234
|
+
url: url
|
|
235
|
+
}
|
|
236
|
+
}).then(res => {
|
|
237
|
+
resolve(res);
|
|
238
|
+
}).catch(error => {
|
|
239
|
+
Toast.fail(`页面重定向失败: ${error.message}`)
|
|
240
|
+
reject(error);
|
|
241
|
+
});
|
|
242
|
+
})
|
|
243
|
+
},
|
|
244
|
+
/**
|
|
245
|
+
* 去人脸
|
|
246
|
+
*/
|
|
247
|
+
goCheckFace(params) {
|
|
248
|
+
return new Promise((resolve, reject) => {
|
|
249
|
+
axios({
|
|
250
|
+
method: 'post',
|
|
251
|
+
url: creatFaceUrl,
|
|
252
|
+
data: params,
|
|
253
|
+
timeout: 30 * 1000, // 30秒超时
|
|
254
|
+
headers: {
|
|
255
|
+
'Content-Type': 'application/json',
|
|
256
|
+
'Accept-Attr4': 'NULL'
|
|
257
|
+
}
|
|
258
|
+
}).then(response => {
|
|
259
|
+
if (response.data.resultType === 'SUCCESS') {
|
|
260
|
+
resolve(response.data)
|
|
261
|
+
} else {
|
|
262
|
+
reject(new Error('接口调用失败'))
|
|
263
|
+
}
|
|
264
|
+
}).catch(error => {
|
|
265
|
+
if (error) {
|
|
266
|
+
reject(new Error('接口调用失败'))
|
|
267
|
+
}
|
|
268
|
+
})
|
|
269
|
+
});
|
|
270
|
+
},
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* 检查当前页面URL中是否同时存在resultType和orderNo参数
|
|
274
|
+
* @returns {boolean} 如果两个参数都存在返回true,否则返回false
|
|
275
|
+
*/
|
|
276
|
+
hasResultTypeAndOrderNo() {
|
|
277
|
+
const hash = window.location.hash;
|
|
278
|
+
let search = '';
|
|
279
|
+
|
|
280
|
+
// 如果有hash并且包含查询参数
|
|
281
|
+
if (hash.includes('?')) {
|
|
282
|
+
search = hash.split('?')[1];
|
|
283
|
+
} else {
|
|
284
|
+
// 否则使用标准的location.search
|
|
285
|
+
search = window.location.search.substring(1);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// 如果没有查询参数,直接返回false
|
|
289
|
+
if (!search) {
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const urlParams = new URLSearchParams(search);
|
|
294
|
+
return urlParams.has('resultType') && urlParams.has('orderNo');
|
|
295
|
+
},
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* 检测人脸识别
|
|
299
|
+
*/
|
|
300
|
+
checkFace() {
|
|
301
|
+
return new Promise((resolve, reject) => {
|
|
302
|
+
if (nativeUtils.hasResultTypeAndOrderNo()) {
|
|
303
|
+
Toast.loading({
|
|
304
|
+
mask: true,
|
|
305
|
+
message: '人脸结果加载中...',
|
|
306
|
+
duration: 0, // 持续展示 toast
|
|
307
|
+
});
|
|
308
|
+
// 处理Vue Router hash模式下的查询参数
|
|
309
|
+
const hash = window.location.hash;
|
|
310
|
+
let search = '';
|
|
311
|
+
|
|
312
|
+
// 如果有hash并且包含查询参数
|
|
313
|
+
if (hash.includes('?')) {
|
|
314
|
+
search = hash.split('?')[1];
|
|
315
|
+
} else {
|
|
316
|
+
// 否则使用标准的location.search
|
|
317
|
+
search = window.location.search.substring(1);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const urlParams = new URLSearchParams(search);
|
|
321
|
+
|
|
322
|
+
let params = {
|
|
323
|
+
orderNo: urlParams.get('orderNo'), // 从URL中获取orderNo参数
|
|
324
|
+
requestSource: 'WX', // 请求来源
|
|
325
|
+
meta: { // 元数据
|
|
326
|
+
tenantCode: 'WX', // 租户编码
|
|
327
|
+
businessCode: 'WX-EDOR', // 业务编码
|
|
328
|
+
serviceType: 'FACE' // 业务类型
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
axios({
|
|
332
|
+
method: 'post',
|
|
333
|
+
url: faceResultUrl,
|
|
334
|
+
data: params,
|
|
335
|
+
timeout: 30 * 1000, // 30秒超时
|
|
336
|
+
headers: {
|
|
337
|
+
'Content-Type': 'application/json',
|
|
338
|
+
'Accept-Attr4': 'NULL'
|
|
339
|
+
}
|
|
340
|
+
}).then(response => {
|
|
341
|
+
if (response.data.resultType === 'SUCCESS') {
|
|
342
|
+
// console.log('接口调用成功', response)
|
|
343
|
+
// if(response.facePhotoUrl && response.facePhotoUrl!=='null' && response.similarity && response.similarity!=='null'){
|
|
344
|
+
// resolve(response.data)
|
|
345
|
+
// } else {
|
|
346
|
+
// Toast('人脸对比未返回图片和相似度,请重试');
|
|
347
|
+
// }
|
|
348
|
+
Toast.clear()
|
|
349
|
+
resolve({
|
|
350
|
+
similarity: "99",
|
|
351
|
+
liveRate: "99",
|
|
352
|
+
facePhotoUrl: "http://testfile.ihasl.com/file/v1/hasl/fileAdmin/fileAdmin/get/z254g0pc55tj11apjge0dun8hvxjdxxs.jpg",
|
|
353
|
+
})
|
|
354
|
+
} else {
|
|
355
|
+
reject(new Error('接口调用失败'))
|
|
356
|
+
}
|
|
357
|
+
}).catch(error => {
|
|
358
|
+
if (error) {
|
|
359
|
+
reject(new Error('接口调用失败'))
|
|
360
|
+
}
|
|
361
|
+
})
|
|
362
|
+
} else {
|
|
363
|
+
reject(new Error('缺少必要的参数'))
|
|
364
|
+
}
|
|
365
|
+
})
|
|
366
|
+
},
|
|
367
|
+
/**
|
|
368
|
+
* 扫描二维码
|
|
369
|
+
*/
|
|
370
|
+
scanQRCode() {
|
|
371
|
+
return new Promise((resolve, reject) => {
|
|
372
|
+
native.utils.scanQRCode().then(res => {
|
|
373
|
+
resolve(res);
|
|
374
|
+
}).catch(error => {
|
|
375
|
+
Toast.fail(`扫描二维码失败: ${error.message}`)
|
|
376
|
+
reject(error);
|
|
377
|
+
});
|
|
378
|
+
});
|
|
379
|
+
},
|
|
380
|
+
/**
|
|
381
|
+
* 阅读pdf
|
|
382
|
+
*/
|
|
383
|
+
pdfRead(pdfs, options = {}) {
|
|
384
|
+
return new Promise((resolve, reject) => {
|
|
385
|
+
try {
|
|
386
|
+
// 确保pdfs是数组格式
|
|
387
|
+
let pdfList = Array.isArray(pdfs) ? pdfs : [pdfs];
|
|
388
|
+
|
|
389
|
+
// 格式化PDF数据
|
|
390
|
+
const formattedPdfs = pdfList.map(pdf => typeof pdf === 'string' ? {
|
|
391
|
+
url: pdf
|
|
392
|
+
} : pdf);
|
|
393
|
+
|
|
394
|
+
// 创建挂载点
|
|
395
|
+
const mountElement = document.createElement('div');
|
|
396
|
+
mountElement.id = 'pdf-preview-mount-' + Date.now();
|
|
397
|
+
document.body.appendChild(mountElement);
|
|
398
|
+
|
|
399
|
+
// 动态导入组件
|
|
400
|
+
import('./components/pdfPreview.vue').then(componentModule => {
|
|
401
|
+
const PdfPreviewComponent = componentModule.default;
|
|
402
|
+
|
|
403
|
+
const instance = new Vue({
|
|
404
|
+
el: mountElement,
|
|
405
|
+
render: h => h(PdfPreviewComponent, {
|
|
406
|
+
ref: 'pdfPreview'
|
|
407
|
+
}),
|
|
408
|
+
mounted() {
|
|
409
|
+
this.$nextTick(() => {
|
|
410
|
+
const pdfPreview = this.$refs.pdfPreview;
|
|
411
|
+
if (pdfPreview) {
|
|
412
|
+
pdfPreview.open(formattedPdfs, options);
|
|
413
|
+
|
|
414
|
+
// 监听关闭事件
|
|
415
|
+
pdfPreview.$on('close', () => {
|
|
416
|
+
try {
|
|
417
|
+
if (mountElement && mountElement.parentNode) {
|
|
418
|
+
mountElement.parentNode.removeChild(mountElement);
|
|
419
|
+
}
|
|
420
|
+
} catch (e) {
|
|
421
|
+
console.warn('Error removing PDF preview element:', e);
|
|
422
|
+
}
|
|
423
|
+
resolve({
|
|
424
|
+
success: true
|
|
425
|
+
});
|
|
426
|
+
});
|
|
427
|
+
} else {
|
|
428
|
+
document.body.removeChild(mountElement);
|
|
429
|
+
reject(new Error('PdfPreview引用未找到'));
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
}).catch(err => {
|
|
435
|
+
console.error('Failed to load PDF preview component:', err);
|
|
436
|
+
document.body.removeChild(mountElement);
|
|
437
|
+
reject(new Error('无法加载PDF预览组件'));
|
|
438
|
+
});
|
|
439
|
+
} catch (error) {
|
|
440
|
+
console.error('Error in pdfRead method:', error);
|
|
441
|
+
reject(error);
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
},
|
|
445
|
+
Toast(message) {
|
|
446
|
+
Toast(message)
|
|
447
|
+
},
|
|
448
|
+
/**
|
|
449
|
+
* 添加日历事件
|
|
450
|
+
*/
|
|
451
|
+
addCalendarEvent(params) {
|
|
452
|
+
return new Promise((resolve, reject) => {
|
|
453
|
+
native.device.addCalendarEvent(params).then(res => {
|
|
454
|
+
resolve(res);
|
|
455
|
+
}).catch(error => {
|
|
456
|
+
Toast.fail(`添加日历事件失败: ${error.message}`)
|
|
457
|
+
reject(error);
|
|
458
|
+
});
|
|
459
|
+
});
|
|
460
|
+
},
|
|
461
|
+
/**
|
|
462
|
+
* 持久化存储
|
|
463
|
+
*/
|
|
464
|
+
setItem(key, value) {
|
|
465
|
+
return new Promise((resolve, reject) => {
|
|
466
|
+
native.storage.setItem(key, value).then(res => {
|
|
467
|
+
resolve(res);
|
|
468
|
+
}).catch(error => {
|
|
469
|
+
Toast.fail(`持久化存储失败: ${error.message}`)
|
|
470
|
+
reject(error);
|
|
471
|
+
});
|
|
472
|
+
});
|
|
473
|
+
},
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* 持久化获取
|
|
477
|
+
*/
|
|
478
|
+
getItem(key) {
|
|
479
|
+
return new Promise((resolve, reject) => {
|
|
480
|
+
native.storage.getItem(key).then(res => {
|
|
481
|
+
resolve(res);
|
|
482
|
+
}).catch(error => {
|
|
483
|
+
console.log(error, 'error')
|
|
484
|
+
Toast.fail(`持久化获取失败: ${error.message}`)
|
|
485
|
+
reject(error);
|
|
486
|
+
});
|
|
487
|
+
});
|
|
488
|
+
},
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* 持久化删除
|
|
492
|
+
*/
|
|
493
|
+
removeItem(key) {
|
|
494
|
+
return new Promise((resolve, reject) => {
|
|
495
|
+
native.storage.removeItem(key).then(res => {
|
|
496
|
+
resolve(res);
|
|
497
|
+
}).catch(error => {
|
|
498
|
+
Toast.fail(`持久化删除失败: ${error.message}`)
|
|
499
|
+
reject(error);
|
|
500
|
+
});
|
|
501
|
+
});
|
|
502
|
+
},
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* 获取定位信息
|
|
506
|
+
*/
|
|
507
|
+
getLocation() {
|
|
508
|
+
return new Promise((resolve, reject) => {
|
|
509
|
+
native.thirdParty.geo.getLocation().then(res => {
|
|
510
|
+
resolve(res)
|
|
511
|
+
}).catch(error => {
|
|
512
|
+
Toast.fail(`获取定位信息失败: ${error.message}`)
|
|
513
|
+
reject(error);
|
|
514
|
+
});
|
|
515
|
+
});
|
|
516
|
+
},
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* 获取设备信息
|
|
520
|
+
*/
|
|
521
|
+
getDeviceInfo() {
|
|
522
|
+
return new Promise((resolve, reject) => {
|
|
523
|
+
native.device.getDeviceInfo({
|
|
524
|
+
fields: ['osName', 'model', 'brand', 'osVersion', 'screen', 'deviceId', 'networkType', 'ip', 'timezone', 'StartTime', 'packageInfo', 'isp', 'appVersion'],
|
|
525
|
+
sceneDesc: '获取设备信息'
|
|
526
|
+
}).then(res => {
|
|
527
|
+
resolve(res);
|
|
528
|
+
}).catch(error => {
|
|
529
|
+
Toast.fail(`获取设备信息失败: ${error.message}`)
|
|
530
|
+
reject(error);
|
|
531
|
+
});
|
|
532
|
+
});
|
|
533
|
+
},
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* 获取缓存大小
|
|
537
|
+
*/
|
|
538
|
+
getCacheSize() {
|
|
539
|
+
return new Promise((resolve, reject) => {
|
|
540
|
+
native.utils.getCacheSize().then(res => {
|
|
541
|
+
resolve(res);
|
|
542
|
+
}).catch(error => {
|
|
543
|
+
Toast.fail(`获取缓存大小失败: ${error.message}`)
|
|
544
|
+
reject(error);
|
|
545
|
+
});
|
|
546
|
+
});
|
|
547
|
+
},
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* 清除缓存
|
|
551
|
+
*/
|
|
552
|
+
clearCache() {
|
|
553
|
+
return new Promise((resolve, reject) => {
|
|
554
|
+
native.utils.clearCache().then(res => {
|
|
555
|
+
resolve(res)
|
|
556
|
+
}).catch(error => {
|
|
557
|
+
Toast.fail(`清除缓存失败: ${error.message}`)
|
|
558
|
+
reject(error);
|
|
559
|
+
});
|
|
560
|
+
});
|
|
561
|
+
},
|
|
562
|
+
|
|
563
|
+
// 跳转页面
|
|
564
|
+
openPage(jumpUrl, visible = false, title = '', safeArea = true) {
|
|
565
|
+
return new Promise((resolve, reject) => {
|
|
566
|
+
// 兼容测试、生产、环境
|
|
567
|
+
let result = jumpUrl
|
|
568
|
+
let url = ''
|
|
569
|
+
const replaceRules = [
|
|
570
|
+
{ // 测试环境-e行
|
|
571
|
+
pattern: "https://teststatic.ihasl.com/pages/eas/#/",
|
|
572
|
+
replacement: "https://teststatic.ihasl.com/pages/uat2/eas/#/"
|
|
573
|
+
},
|
|
574
|
+
{ // 生产环境-e行
|
|
575
|
+
pattern: "https://www.ihasl.com/pages/eas/#/",
|
|
576
|
+
replacement: "https://www.ihasl.com/pages/master2/eas/#/"
|
|
577
|
+
},
|
|
578
|
+
{ // 测试环境-app-hasl
|
|
579
|
+
pattern: "https://teststatic.ihasl.com/pages/salessupport/app/#/",
|
|
580
|
+
replacement: "https://teststatic.ihasl.com/pages/uat2/salessupport/app/#/"
|
|
581
|
+
},
|
|
582
|
+
{ // 生产环境-app-hasl
|
|
583
|
+
pattern: "https://www.ihasl.com/pages/salessupport/app/#/",
|
|
584
|
+
replacement: "https://www.ihasl.com/pages/master2/salessupport/app/#/"
|
|
585
|
+
},
|
|
586
|
+
{ //测试环境 app2-hasl
|
|
587
|
+
pattern: "https://teststatic.ihasl.com/pages/app2-hasl/#/",
|
|
588
|
+
replacement: "https://teststatic.ihasl.com/pages/uat2/app2-hasl/#/"
|
|
589
|
+
},
|
|
590
|
+
{ //生产环境 app2-hasl
|
|
591
|
+
pattern: "https://www.ihasl.com/pages/app2-hasl/#/",
|
|
592
|
+
replacement: "https://www.ihasl.com/pages/master2/app2-hasl/#/"
|
|
593
|
+
},
|
|
594
|
+
{ // 测试环境 招募recruit
|
|
595
|
+
pattern: "https://teststatic.ihasl.com/pages/salessupport/recruit/#/",
|
|
596
|
+
replacement: "https://teststatic.ihasl.com/pages/uat2/salessupport/recruit/#/"
|
|
597
|
+
},
|
|
598
|
+
{ // 生产环境 招募recruit
|
|
599
|
+
pattern: "https://www.ihasl.com/pages/salessupport/recruit/#/",
|
|
600
|
+
replacement: "https://www.ihasl.com/pages/master2/salessupport/recruit/#/"
|
|
601
|
+
}
|
|
602
|
+
]
|
|
603
|
+
|
|
604
|
+
// 遍历所有规则,找到匹配的进行替换
|
|
605
|
+
for (let rule of replaceRules) {
|
|
606
|
+
if (result.includes(rule.pattern)) {
|
|
607
|
+
url = result.replace(rule.pattern, rule.replacement);
|
|
608
|
+
break; // 找到匹配后跳出循环
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
native.navigator.openPage({
|
|
612
|
+
name: 'h5',
|
|
613
|
+
params: {
|
|
614
|
+
url: url,
|
|
615
|
+
navigationBarVisible: visible, // false:不显示 true:显示
|
|
616
|
+
title: title,
|
|
617
|
+
safeArea: safeArea, // true处理安全区 false不处理 默认false不处理
|
|
618
|
+
}
|
|
619
|
+
}).then(res => {
|
|
620
|
+
resolve(res);
|
|
621
|
+
}).catch(error => {
|
|
622
|
+
Toast.fail(`打开页面失败: ${error.message}`)
|
|
623
|
+
reject(error);
|
|
624
|
+
});
|
|
625
|
+
});
|
|
626
|
+
},
|
|
627
|
+
// 跳转页面带分享
|
|
628
|
+
openPageWithShare(params) {
|
|
629
|
+
return new Promise((resolve, reject) => {
|
|
630
|
+
native.navigator.openPage({
|
|
631
|
+
name: 'externalH5',
|
|
632
|
+
params: {
|
|
633
|
+
url: params.url,
|
|
634
|
+
actionType: 'share',
|
|
635
|
+
title: params.title,
|
|
636
|
+
shareInfo: {
|
|
637
|
+
type: params.shareInfo.type, // 分享类型 webpage|text|image|miniProgram
|
|
638
|
+
// scene: 'session', // 可选值: session|timeline
|
|
639
|
+
content: {
|
|
640
|
+
title: params.shareInfo.content.title ? params.shareInfo.content.title : '恒安标准人寿',
|
|
641
|
+
description: params.shareInfo.content.description ? params.shareInfo.content.description : '恒安标准人寿',
|
|
642
|
+
webpageUrl: params.shareInfo.content.webpageUrl, // 替换为实际的分享链接
|
|
643
|
+
thumb: params.shareInfo.content.thumb ? params.shareInfo.content.thumb : 'https://www.ihasl.com/pages/salessupport/app/images/logo.png',
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}).then(res => {
|
|
648
|
+
resolve(res);
|
|
649
|
+
}).catch(error => {
|
|
650
|
+
Toast.fail(`打开页面失败: ${error.message}`)
|
|
651
|
+
reject(error);
|
|
652
|
+
});
|
|
653
|
+
});
|
|
654
|
+
},
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* 关闭当前H5页面
|
|
658
|
+
*/
|
|
659
|
+
closePage() {
|
|
660
|
+
return new Promise((resolve, reject) => {
|
|
661
|
+
native.navigator.closePage().then(res => {
|
|
662
|
+
resolve(res);
|
|
663
|
+
}).catch(error => {
|
|
664
|
+
Toast.fail(`关闭当前H5页面失败: ${error.message}`)
|
|
665
|
+
reject(error);
|
|
666
|
+
});
|
|
667
|
+
});
|
|
668
|
+
},
|
|
669
|
+
|
|
670
|
+
// 隐藏原生标题
|
|
671
|
+
setNavigationBarVisible(visible) {
|
|
672
|
+
return new Promise((resolve, reject) => {
|
|
673
|
+
native.navigator.setNavigationBarVisible({
|
|
674
|
+
visible: visible
|
|
675
|
+
}).then(res => {
|
|
676
|
+
resolve(res);
|
|
677
|
+
}).catch(error => {
|
|
678
|
+
Toast.fail(`隐藏原生标题失败: ${error.message}`)
|
|
679
|
+
reject(error);
|
|
680
|
+
});
|
|
681
|
+
});
|
|
682
|
+
},
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* 拨打电话
|
|
686
|
+
* @param {*} phoneNo 手机号
|
|
687
|
+
*/
|
|
688
|
+
callphone(phoneNo) {
|
|
689
|
+
return new Promise((resolve, reject) => {
|
|
690
|
+
native.device.callPhone({
|
|
691
|
+
phoneNo: phoneNo,
|
|
692
|
+
sceneDesc: '拨打电话'
|
|
693
|
+
}).then(res => {
|
|
694
|
+
resolve(res);
|
|
695
|
+
}).catch(error => {
|
|
696
|
+
if (error.code === 2000) {
|
|
697
|
+
Toast.fail(`拨打电话失败: ${error.message}`)
|
|
698
|
+
}
|
|
699
|
+
reject(error);
|
|
700
|
+
});
|
|
701
|
+
});
|
|
702
|
+
},
|
|
703
|
+
|
|
704
|
+
// 短信
|
|
705
|
+
sendSMS(phone, content) {
|
|
706
|
+
return new Promise((resolve, reject) => {
|
|
707
|
+
native.device.sendSMS({
|
|
708
|
+
phoneNo: phone,
|
|
709
|
+
message: content,
|
|
710
|
+
sceneDesc: '发送短信',
|
|
711
|
+
}).then(() => {
|
|
712
|
+
resolve()
|
|
713
|
+
}).catch(error => {
|
|
714
|
+
Toast.fail(`发送短信失败: ${error.message}`)
|
|
715
|
+
reject(error);
|
|
716
|
+
});
|
|
717
|
+
});
|
|
718
|
+
},
|
|
719
|
+
segmentedEncrypt(data) {
|
|
720
|
+
try {
|
|
721
|
+
// 创建JSEncrypt对象
|
|
722
|
+
const encrypt = new JSEncrypt()
|
|
723
|
+
// 设置公钥
|
|
724
|
+
encrypt.setPublicKey(publicKey)
|
|
725
|
+
|
|
726
|
+
// RSA 1024位密钥的最大加密长度为117字节
|
|
727
|
+
const maxChunkSize = 117
|
|
728
|
+
const bytes = nativeUtils.stringToBytes(data)
|
|
729
|
+
const chunks = []
|
|
730
|
+
|
|
731
|
+
// 分段处理
|
|
732
|
+
for (let i = 0; i < bytes.length; i += maxChunkSize) {
|
|
733
|
+
const chunk = bytes.slice(i, i + maxChunkSize)
|
|
734
|
+
const chunkStr = nativeUtils.bytesToString(chunk)
|
|
735
|
+
const encryptedChunk = encrypt.encrypt(chunkStr)
|
|
736
|
+
|
|
737
|
+
if (!encryptedChunk) {
|
|
738
|
+
throw new Error(`加密第${i/maxChunkSize + 1}段数据时失败`)
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
chunks.push(encryptedChunk)
|
|
742
|
+
}
|
|
743
|
+
console.log('chunks', chunks)
|
|
744
|
+
// 将所有加密段用分隔符连接
|
|
745
|
+
return chunks.join('|SEGMENT|')
|
|
746
|
+
} catch (e) {
|
|
747
|
+
console.error('分段加密失败:', e)
|
|
748
|
+
return null
|
|
749
|
+
}
|
|
750
|
+
},
|
|
751
|
+
/**
|
|
752
|
+
* 字符串转字节数组
|
|
753
|
+
*/
|
|
754
|
+
stringToBytes(str) {
|
|
755
|
+
const bytes = []
|
|
756
|
+
for (let i = 0; i < str.length; i++) {
|
|
757
|
+
const code = str.charCodeAt(i)
|
|
758
|
+
bytes.push(code)
|
|
759
|
+
}
|
|
760
|
+
return bytes
|
|
761
|
+
},
|
|
762
|
+
|
|
763
|
+
/**
|
|
764
|
+
* 字节数组转字符串
|
|
765
|
+
*/
|
|
766
|
+
bytesToString(bytes) {
|
|
767
|
+
return String.fromCharCode.apply(null, bytes)
|
|
768
|
+
},
|
|
769
|
+
|
|
770
|
+
/**
|
|
771
|
+
* 加密 先加密-再转base64
|
|
772
|
+
*/
|
|
773
|
+
encrypt(content) {
|
|
774
|
+
return new Promise((resolve, reject) => {
|
|
775
|
+
// 创建JSEncrypt对象
|
|
776
|
+
// const encrypt = new JSEncrypt()
|
|
777
|
+
// // 设置公钥
|
|
778
|
+
// encrypt.setPublicKey(publicKey)
|
|
779
|
+
// // 执行加密
|
|
780
|
+
// const encrypted = encrypt.encrypt(content)
|
|
781
|
+
const encrypted = nativeUtils.segmentedEncrypt(content)
|
|
782
|
+
if (encrypted) {
|
|
783
|
+
// resolve(btoa(encrypted))
|
|
784
|
+
resolve(encrypted)
|
|
785
|
+
} else {
|
|
786
|
+
reject(new Error('加密失败'))
|
|
787
|
+
}
|
|
788
|
+
});
|
|
789
|
+
},
|
|
790
|
+
/**
|
|
791
|
+
* 解密 仅为示例,先base64解码-再解密
|
|
792
|
+
*/
|
|
793
|
+
decrypt(content) {
|
|
794
|
+
return new Promise((resolve, reject) => {
|
|
795
|
+
// 1.创建JSEncrypt对象用于解密
|
|
796
|
+
const decrypt = new JSEncrypt();
|
|
797
|
+
// 2.设置私钥
|
|
798
|
+
decrypt.setPrivateKey(`-----BEGIN RSA PRIVATE KEY-----
|
|
799
|
+
MIIBOQIBAAJAe87bvdKkch7/tNDl1RvsO+av72yMXdbiryuhS88WjoldxzPZpzAR
|
|
800
|
+
UR74cEHk0svxtWtM6rIBmk4w//x9z0s4tQIDAQABAkA8DrFbmIW68jyaSsdipEPp
|
|
801
|
+
HtNzchV5I9ccoC6DJrbLdzjhGuTT51aa2qC4CfamW6zEYCjSbgeMqT4CzfZOKGaB
|
|
802
|
+
AiEA2iFY/H4+0s1CO1p6VoHOMDP3W+Ahy1Lu74G8fRQkzuECIQCRTWxVpPuxPzQ3
|
|
803
|
+
pfKZe5QrVRucb5vEhbV6Q3lu3YuIVQIhAKnQBEKs1aOuf71NNqhZ7XbBPfScjDKJ
|
|
804
|
+
odF7Io4NPIqBAiBBy3k+3tJJ1IDkofRUo6zYYlV6ZN94AcPHdT5LgW5pcQIgF2by
|
|
805
|
+
nFqBB1zM586NpO+4hua/1Ol5OiqoQJ4iQinyDiA=
|
|
806
|
+
-----END RSA PRIVATE KEY-----`);
|
|
807
|
+
// 3.执行解码
|
|
808
|
+
const decodedData = atob(content)
|
|
809
|
+
// 4.再进行RSA解密
|
|
810
|
+
const decrypted = decrypt.decrypt(decodedData);
|
|
811
|
+
if (decrypted) {
|
|
812
|
+
resolve(decrypted)
|
|
813
|
+
} else {
|
|
814
|
+
reject(new Error('解密失败'))
|
|
815
|
+
}
|
|
816
|
+
});
|
|
817
|
+
},
|
|
818
|
+
|
|
819
|
+
/**
|
|
820
|
+
* 唤起通讯录,并且返回name phone
|
|
821
|
+
*/
|
|
822
|
+
readContacts() {
|
|
823
|
+
return new Promise((resolve, reject) => {
|
|
824
|
+
native.device.readContacts({
|
|
825
|
+
fields: ['name', 'phone'],
|
|
826
|
+
sceneDesc: '获取通讯录',
|
|
827
|
+
}).then((data) => {
|
|
828
|
+
resolve(data)
|
|
829
|
+
}).catch(error => {
|
|
830
|
+
Toast.fail(`获取通讯录失败: ${error.message}`)
|
|
831
|
+
reject(error);
|
|
832
|
+
});
|
|
833
|
+
});
|
|
834
|
+
},
|
|
835
|
+
/**
|
|
836
|
+
* 拍照上传
|
|
837
|
+
* @param {Object} params 参数对象
|
|
838
|
+
* @param {string} params.actions 图片类型:身份证正面ocr_id0、反面ocr_id1、银行卡ocr_bc、默认为空
|
|
839
|
+
* @param {number} params.maxSize 图片最大大小,默认1024
|
|
840
|
+
* @param {string} params.domain 域名,默认INDUCTION
|
|
841
|
+
* @param {string} params.buz 业务类型,默认PICTURE
|
|
842
|
+
* @param {string} params.buzId 业务ID,默认111
|
|
843
|
+
* @param {boolean} params.isCopper 是否需要裁剪,默认false
|
|
844
|
+
* @param {boolean} params.isUpload 是否需要上传,默认true
|
|
845
|
+
*/
|
|
846
|
+
takePhoto(params) {
|
|
847
|
+
console.log(params, '拍照上传参数');
|
|
848
|
+
return new Promise((resolve, reject) => {
|
|
849
|
+
// 参数默认值处理
|
|
850
|
+
const {
|
|
851
|
+
maxSize = 1024,
|
|
852
|
+
actions = '',
|
|
853
|
+
domain = 'INDUCTION',
|
|
854
|
+
buz = 'PICTURE',
|
|
855
|
+
buzId = '111',
|
|
856
|
+
isCopper = false
|
|
857
|
+
} = params;
|
|
858
|
+
|
|
859
|
+
// isUpload特殊处理:未传值时默认为true,传值时使用传入值
|
|
860
|
+
const isUpload = (params.isUpload !== undefined) ? params.isUpload : true;
|
|
861
|
+
|
|
862
|
+
console.log(isCopper, '-------是否需要裁剪-------');
|
|
863
|
+
console.log(isUpload, '-------是否需要上传-------');
|
|
864
|
+
|
|
865
|
+
native.media.takePhoto({
|
|
866
|
+
maxSize: maxSize
|
|
867
|
+
}).then(async (data) => {
|
|
868
|
+
nativeUtils.closeDialog();
|
|
869
|
+
try {
|
|
870
|
+
// 调接口上传base64至文件服务器
|
|
871
|
+
const base64Files = data;
|
|
872
|
+
|
|
873
|
+
// 身份证银行卡必须裁剪,或者明确指定需要裁剪
|
|
874
|
+
const needCropper = actions === 'ocr_id0' || actions === 'ocr_id1' || actions === 'ocr_bc' || isCopper;
|
|
875
|
+
if (needCropper) {
|
|
876
|
+
base64Files.imageBase64 = await nativeUtils.cropper(base64Files.imageBase64, actions);
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
// 如果不需要上传,直接返回base64数据
|
|
880
|
+
if (!isUpload) {
|
|
881
|
+
resolve({
|
|
882
|
+
imageBase64: base64Files.imageBase64
|
|
883
|
+
});
|
|
884
|
+
return;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
// 需要上传:显示上传提示
|
|
888
|
+
await Toast.loading({
|
|
889
|
+
forbidClick: true,
|
|
890
|
+
message: '上传中...',
|
|
891
|
+
duration: 0, // 持续展示 toast
|
|
892
|
+
});
|
|
893
|
+
|
|
894
|
+
// 将base64转换为file对象
|
|
895
|
+
const file = await nativeUtils.base64ToFile(base64Files.imageBase64, 'image.png');
|
|
896
|
+
|
|
897
|
+
// 上传文件到服务器
|
|
898
|
+
const result = await nativeUtils.uploadFile(base64Files, file, actions, domain, buz, buzId);
|
|
899
|
+
|
|
900
|
+
resolve(result);
|
|
901
|
+
Toast.clear();
|
|
902
|
+
} catch (error) {
|
|
903
|
+
Toast.fail(`文件上传失败: ${error.message}`);
|
|
904
|
+
reject(error);
|
|
905
|
+
}
|
|
906
|
+
}).catch(error => {
|
|
907
|
+
Toast.fail(`拍照失败: ${error.message}`);
|
|
908
|
+
reject(error);
|
|
909
|
+
});
|
|
910
|
+
});
|
|
911
|
+
},
|
|
912
|
+
|
|
913
|
+
/**
|
|
914
|
+
* 从相册选择图片
|
|
915
|
+
* @param {Object} params 参数对象
|
|
916
|
+
* @param {number} params.maxCount 最大选择数量,超过9张时自动设为9
|
|
917
|
+
* @param {string} params.actions 图片类型
|
|
918
|
+
* @param {string} params.domain 域名
|
|
919
|
+
* @param {string} params.buz 业务类型
|
|
920
|
+
* @param {string} params.buzId 业务ID
|
|
921
|
+
* @param {boolean} params.isCopper 是否需要裁剪
|
|
922
|
+
* @param {boolean} params.isCropper 是否启用裁剪(单张图片时)
|
|
923
|
+
* @param {boolean} params.isUpload 是否需要上传,默认true
|
|
924
|
+
*/
|
|
925
|
+
chooseImage(params) {
|
|
926
|
+
// 参数预处理
|
|
927
|
+
params.isCopper = params.isCopper ? params.isCopper : false;
|
|
928
|
+
params.isUpload = (params.isUpload !== undefined) ? params.isUpload : true;
|
|
929
|
+
|
|
930
|
+
// 限制最大选择数量为9张
|
|
931
|
+
if (params.maxCount > 9) {
|
|
932
|
+
params.maxCount = 9;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
console.log(params, '相册上传参数');
|
|
936
|
+
|
|
937
|
+
return new Promise((resolve, reject) => {
|
|
938
|
+
nativeUtils.closeDialog();
|
|
939
|
+
|
|
940
|
+
native.media.chooseImage(params).then(async (data) => {
|
|
941
|
+
const base64Files = data;
|
|
942
|
+
const uploadResults = []; // 存储所有处理结果
|
|
943
|
+
let successCount = 0; // 成功计数
|
|
944
|
+
let failCount = 0; // 失败计数
|
|
945
|
+
|
|
946
|
+
console.log(base64Files.length, '--------------选择的图片数量---------');
|
|
947
|
+
|
|
948
|
+
// 判断是否需要裁剪:身份证、银行卡或明确指定需要裁剪,且只选择了一张图片时才进行裁剪
|
|
949
|
+
let isCropper = false;
|
|
950
|
+
const isSpecialAction = params.actions === 'ocr_id0' || params.actions === 'ocr_id1' || params.actions === 'ocr_bc';
|
|
951
|
+
if ((isSpecialAction || params.isCropper) && base64Files.length === 1) {
|
|
952
|
+
isCropper = true;
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
// 逐个处理图片
|
|
956
|
+
for (let i = 0; i < base64Files.length; i++) {
|
|
957
|
+
const element = base64Files[i];
|
|
958
|
+
|
|
959
|
+
// 需要上传时显示进度提示
|
|
960
|
+
if (params.isUpload) {
|
|
961
|
+
Toast.loading({
|
|
962
|
+
forbidClick: true,
|
|
963
|
+
message: `选择了${base64Files.length}张图片,正在上传第${i+1}张`,
|
|
964
|
+
duration: 0, // 持续展示 toast
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
try {
|
|
969
|
+
console.log(isCropper, '--------------是否需要裁剪---------');
|
|
970
|
+
|
|
971
|
+
// 1. 裁剪处理:只有在需要裁剪且只有一张图片时才进行裁剪
|
|
972
|
+
if (isCropper && base64Files.length === 1) {
|
|
973
|
+
element.imageBase64 = await nativeUtils.cropper(element.imageBase64, params.actions);
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
// 2. 不需要上传:直接返回base64数据
|
|
977
|
+
if (!params.isUpload) {
|
|
978
|
+
uploadResults.push({
|
|
979
|
+
imageBase64: element.imageBase64
|
|
980
|
+
});
|
|
981
|
+
|
|
982
|
+
// 如果是最后一张图片,返回所有base64数据
|
|
983
|
+
if (i === base64Files.length - 1) {
|
|
984
|
+
// 单张返回对象,多张返回数组
|
|
985
|
+
const result = uploadResults.length === 1 ? uploadResults[0] : uploadResults;
|
|
986
|
+
resolve(result);
|
|
987
|
+
return;
|
|
988
|
+
}
|
|
989
|
+
continue; // 继续处理下一张图片
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
// 3. 需要上传:转换为文件并上传
|
|
993
|
+
const file = await nativeUtils.base64ToFile(element.imageBase64, 'image.png');
|
|
994
|
+
const result = await nativeUtils.uploadFile(
|
|
995
|
+
element.imageBase64,
|
|
996
|
+
file,
|
|
997
|
+
params.actions,
|
|
998
|
+
params.domain,
|
|
999
|
+
params.buz,
|
|
1000
|
+
params.buzId
|
|
1001
|
+
);
|
|
1002
|
+
|
|
1003
|
+
// 保存上传结果
|
|
1004
|
+
uploadResults.push(result);
|
|
1005
|
+
successCount++;
|
|
1006
|
+
|
|
1007
|
+
} catch (error) {
|
|
1008
|
+
// 单张图片失败不影响其他图片上传
|
|
1009
|
+
failCount++;
|
|
1010
|
+
console.error(`第${i+1}张图片上传失败:`, error);
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
// 所有图片处理完成后的结果处理
|
|
1015
|
+
if (successCount > 0) {
|
|
1016
|
+
// 有成功上传的图片:单张返回对象,多张返回数组
|
|
1017
|
+
const result = uploadResults.length === 1 ? uploadResults[0] : uploadResults;
|
|
1018
|
+
resolve(result);
|
|
1019
|
+
Toast.clear();
|
|
1020
|
+
|
|
1021
|
+
// 有失败图片时提示用户
|
|
1022
|
+
if (failCount > 0) {
|
|
1023
|
+
Toast.fail(`有${failCount}张图片上传失败`);
|
|
1024
|
+
}
|
|
1025
|
+
} else {
|
|
1026
|
+
// 所有图片都上传失败
|
|
1027
|
+
reject(new Error('所有图片上传都失败了'));
|
|
1028
|
+
}
|
|
1029
|
+
}).catch(error => {
|
|
1030
|
+
Toast.fail(`选择图片失败: ${error.message}`);
|
|
1031
|
+
reject(error);
|
|
1032
|
+
});
|
|
1033
|
+
});
|
|
1034
|
+
},
|
|
1035
|
+
|
|
1036
|
+
/**
|
|
1037
|
+
* 拍照+相册 h5自己封装
|
|
1038
|
+
*/
|
|
1039
|
+
takePicture(params) {
|
|
1040
|
+
return new Promise((resolve, reject) => {
|
|
1041
|
+
nativeUtils._takePictureResolve = resolve;
|
|
1042
|
+
nativeUtils._takePictureReject = reject;
|
|
1043
|
+
nativeUtils.openCameraDialog(params)
|
|
1044
|
+
});
|
|
1045
|
+
},
|
|
1046
|
+
|
|
1047
|
+
/**
|
|
1048
|
+
* 唤起相机相册选择弹窗
|
|
1049
|
+
*/
|
|
1050
|
+
openCameraDialog(params) {
|
|
1051
|
+
// 移除已存在的弹窗(如果存在)
|
|
1052
|
+
const existingDialog = document.getElementById('cameraDialog');
|
|
1053
|
+
if (existingDialog) {
|
|
1054
|
+
document.body.removeChild(existingDialog);
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
// 创建弹窗容器
|
|
1058
|
+
const dialog = document.createElement('div');
|
|
1059
|
+
dialog.id = 'cameraDialog';
|
|
1060
|
+
|
|
1061
|
+
// 添加样式
|
|
1062
|
+
const styles = `
|
|
1063
|
+
.camera-dialog {
|
|
1064
|
+
position: fixed;
|
|
1065
|
+
top: 0;
|
|
1066
|
+
left: 0;
|
|
1067
|
+
width: 100%;
|
|
1068
|
+
height: 100%;
|
|
1069
|
+
background: rgba(0, 0, 0, 0.3);
|
|
1070
|
+
display: flex;
|
|
1071
|
+
justify-content: center;
|
|
1072
|
+
align-items: center;
|
|
1073
|
+
z-index: 1000;
|
|
1074
|
+
opacity: 0;
|
|
1075
|
+
animation: fadeIn 0.3s forwards;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
@keyframes fadeIn {
|
|
1079
|
+
to { opacity: 1; }
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
.dialog-content {
|
|
1083
|
+
width: 100%;
|
|
1084
|
+
max-width: 400px;
|
|
1085
|
+
border-radius: 6px;
|
|
1086
|
+
overflow: hidden;
|
|
1087
|
+
transform: translateY(20px);
|
|
1088
|
+
animation: slideUp 0.3s forwards;
|
|
1089
|
+
position: fixed;
|
|
1090
|
+
bottom: 0;
|
|
1091
|
+
z-index: 1001;
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
@keyframes slideUp {
|
|
1095
|
+
to { transform: translateY(0); }
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
.dialog-body {
|
|
1099
|
+
padding: 20px 0px;
|
|
1100
|
+
margin: 0 20px;
|
|
1101
|
+
}
|
|
1102
|
+
.options {
|
|
1103
|
+
border-radius: 10px;
|
|
1104
|
+
background: #fff;
|
|
1105
|
+
overflow: hidden;
|
|
1106
|
+
}
|
|
1107
|
+
.option-btn {
|
|
1108
|
+
display: flex;
|
|
1109
|
+
align-items: center;
|
|
1110
|
+
justify-content: center;
|
|
1111
|
+
width: 100%;
|
|
1112
|
+
padding: 17px;
|
|
1113
|
+
background: #fff;
|
|
1114
|
+
border-bottom: 1px solid #e0e0e0;
|
|
1115
|
+
font-size: 16px;
|
|
1116
|
+
cursor: pointer;
|
|
1117
|
+
transition: all 0.2s ease;
|
|
1118
|
+
color: #007EEC;
|
|
1119
|
+
font-weight: 500;
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
.cancel-btn {
|
|
1123
|
+
margin-top: 10px;
|
|
1124
|
+
background: #fff;
|
|
1125
|
+
color: #007EEC;
|
|
1126
|
+
border: none;
|
|
1127
|
+
margin-bottom: 20px;
|
|
1128
|
+
padding: 17px;
|
|
1129
|
+
width: 100%;
|
|
1130
|
+
font-size: 16px;
|
|
1131
|
+
cursor: pointer;
|
|
1132
|
+
transition: all 0.2s ease;
|
|
1133
|
+
border-radius: 8px;
|
|
1134
|
+
font-weight: bold;
|
|
1135
|
+
}
|
|
1136
|
+
`;
|
|
1137
|
+
|
|
1138
|
+
// 创建样式元素
|
|
1139
|
+
const styleEl = document.createElement('style');
|
|
1140
|
+
styleEl.textContent = styles;
|
|
1141
|
+
document.head.appendChild(styleEl);
|
|
1142
|
+
|
|
1143
|
+
// 弹窗内容
|
|
1144
|
+
dialog.innerHTML = `
|
|
1145
|
+
<div class="camera-dialog">
|
|
1146
|
+
<div class="dialog-content">
|
|
1147
|
+
<div class="dialog-body">
|
|
1148
|
+
<div class="options">
|
|
1149
|
+
<button class="option-btn" id="cameraBtn">
|
|
1150
|
+
拍照
|
|
1151
|
+
</button>
|
|
1152
|
+
<button class="option-btn" id="albumBtn">
|
|
1153
|
+
从相册选择
|
|
1154
|
+
</button>
|
|
1155
|
+
</div>
|
|
1156
|
+
<button class="cancel-btn" id="cancelBtn">取消</button>
|
|
1157
|
+
</div>
|
|
1158
|
+
</div>
|
|
1159
|
+
</div>
|
|
1160
|
+
`;
|
|
1161
|
+
setTimeout(() => {
|
|
1162
|
+
document.getElementById('cameraBtn').addEventListener('click', () => {
|
|
1163
|
+
nativeUtils.handleCamera(nativeUtils._takePictureResolve, nativeUtils._takePictureReject, params);
|
|
1164
|
+
});
|
|
1165
|
+
document.getElementById('albumBtn').addEventListener('click', () => {
|
|
1166
|
+
nativeUtils.handleAlbum(nativeUtils._takePictureResolve, nativeUtils._takePictureReject, params);
|
|
1167
|
+
});
|
|
1168
|
+
document.getElementById('cancelBtn').addEventListener('click', () => {
|
|
1169
|
+
nativeUtils.closeDialog();
|
|
1170
|
+
nativeUtils._takePictureReject(new Error('用户取消了操作'));
|
|
1171
|
+
});
|
|
1172
|
+
}, 0);
|
|
1173
|
+
|
|
1174
|
+
// 添加到文档
|
|
1175
|
+
document.body.appendChild(dialog);
|
|
1176
|
+
|
|
1177
|
+
// 添加事件监听器,点击背景关闭弹窗
|
|
1178
|
+
dialog.addEventListener('click', function (e) {
|
|
1179
|
+
if (e.target.classList.contains('camera-dialog')) {
|
|
1180
|
+
this.closeDialog();
|
|
1181
|
+
}
|
|
1182
|
+
});
|
|
1183
|
+
},
|
|
1184
|
+
// 关闭弹窗
|
|
1185
|
+
closeDialog() {
|
|
1186
|
+
const dialog = document.getElementById('cameraDialog');
|
|
1187
|
+
if (dialog) {
|
|
1188
|
+
dialog.querySelector('.camera-dialog').style.animation = 'fadeOut 0.3s forwards';
|
|
1189
|
+
// 添加淡出动画
|
|
1190
|
+
const styles = document.querySelector('style');
|
|
1191
|
+
if (styles && !styles.textContent.includes('fadeOut')) {
|
|
1192
|
+
styles.textContent += `
|
|
1193
|
+
@keyframes fadeOut {
|
|
1194
|
+
from { opacity: 1; }
|
|
1195
|
+
to { opacity: 0; }
|
|
1196
|
+
}
|
|
1197
|
+
`;
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
setTimeout(() => {
|
|
1201
|
+
document.body.removeChild(dialog);
|
|
1202
|
+
}, 300);
|
|
1203
|
+
}
|
|
1204
|
+
delete nativeUtils._takePictureResolve;
|
|
1205
|
+
delete nativeUtils._takePictureReject;
|
|
1206
|
+
},
|
|
1207
|
+
|
|
1208
|
+
// 处理拍照
|
|
1209
|
+
async handleCamera(resolve, reject, params) {
|
|
1210
|
+
try {
|
|
1211
|
+
const res = await nativeUtils.takePhoto(params);
|
|
1212
|
+
resolve(res); // 返回数组以保持与多图一致
|
|
1213
|
+
nativeUtils.closeDialog();
|
|
1214
|
+
} catch (error) {
|
|
1215
|
+
reject(error);
|
|
1216
|
+
nativeUtils.closeDialog();
|
|
1217
|
+
}
|
|
1218
|
+
},
|
|
1219
|
+
|
|
1220
|
+
// 处理相册选择
|
|
1221
|
+
async handleAlbum(resolve, reject, params) {
|
|
1222
|
+
try {
|
|
1223
|
+
const res = await nativeUtils.chooseImage(params);
|
|
1224
|
+
resolve(res);
|
|
1225
|
+
nativeUtils.closeDialog();
|
|
1226
|
+
} catch (error) {
|
|
1227
|
+
reject(error);
|
|
1228
|
+
nativeUtils.closeDialog();
|
|
1229
|
+
}
|
|
1230
|
+
},
|
|
1231
|
+
/**
|
|
1232
|
+
* 裁剪图片
|
|
1233
|
+
* @param {string} base64String - 原始图片的base64数据
|
|
1234
|
+
* @returns {Promise<string>} 裁剪后图片的base64数据
|
|
1235
|
+
*/
|
|
1236
|
+
cropper(base64String, actions) {
|
|
1237
|
+
return new Promise((resolve, reject) => {
|
|
1238
|
+
// 创建裁剪容器
|
|
1239
|
+
const cropperContainer = document.createElement('div');
|
|
1240
|
+
cropperContainer.id = 'image-cropper-container';
|
|
1241
|
+
document.body.appendChild(cropperContainer);
|
|
1242
|
+
|
|
1243
|
+
// 创建Vue实例
|
|
1244
|
+
const cropperInstance = new Vue({
|
|
1245
|
+
data() {
|
|
1246
|
+
return {
|
|
1247
|
+
imgSrc: 'data:image/jpeg;base64,' + base64String,
|
|
1248
|
+
};
|
|
1249
|
+
},
|
|
1250
|
+
methods: {
|
|
1251
|
+
handleConfirm(croppedData) {
|
|
1252
|
+
var divToDelete = document.querySelector('.image-cropper-container');
|
|
1253
|
+
divToDelete.remove()
|
|
1254
|
+
resolve(croppedData);
|
|
1255
|
+
},
|
|
1256
|
+
handleCancel() {
|
|
1257
|
+
var divToDelete = document.querySelector('.image-cropper-container');
|
|
1258
|
+
divToDelete.remove()
|
|
1259
|
+
reject(new Error('用户取消裁剪'));
|
|
1260
|
+
}
|
|
1261
|
+
},
|
|
1262
|
+
render(h) {
|
|
1263
|
+
return h(ImageCropper, {
|
|
1264
|
+
props: {
|
|
1265
|
+
imgSrc: this.imgSrc,
|
|
1266
|
+
actions: actions
|
|
1267
|
+
},
|
|
1268
|
+
on: {
|
|
1269
|
+
confirm: this.handleConfirm,
|
|
1270
|
+
cancel: this.handleCancel
|
|
1271
|
+
}
|
|
1272
|
+
});
|
|
1273
|
+
}
|
|
1274
|
+
}).$mount(cropperContainer);
|
|
1275
|
+
});
|
|
1276
|
+
},
|
|
1277
|
+
/**
|
|
1278
|
+
* 将base64字符串转换为File对象
|
|
1279
|
+
* @param {string} base64String - base64编码的字符串
|
|
1280
|
+
* @param {string} filename - 文件名
|
|
1281
|
+
* @param {string} mimeType - MIME类型,默认为'image/jpeg'
|
|
1282
|
+
* @returns {File} File对象
|
|
1283
|
+
*/
|
|
1284
|
+
base64ToFile(base64String, filename = 'file.png') {
|
|
1285
|
+
return new Promise((resolve, reject) => {
|
|
1286
|
+
// 检查 base64String 是否包含数据 URI 前缀
|
|
1287
|
+
if (base64String.includes(',')) {
|
|
1288
|
+
const arr = base64String.split(',');
|
|
1289
|
+
const mimeMatch = arr[0].match(/:(.*?);/);
|
|
1290
|
+
const mime = mimeMatch ? mimeMatch[1] : 'application/octet-stream';
|
|
1291
|
+
const bstr = atob(arr[1]);
|
|
1292
|
+
let n = bstr.length;
|
|
1293
|
+
const u8arr = new Uint8Array(n);
|
|
1294
|
+
|
|
1295
|
+
while (n--) {
|
|
1296
|
+
u8arr[n] = bstr.charCodeAt(n);
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
const file = new File([u8arr], filename, {
|
|
1300
|
+
type: mime
|
|
1301
|
+
});
|
|
1302
|
+
resolve(file);
|
|
1303
|
+
} else {
|
|
1304
|
+
// 如果不包含逗号,可能是纯 base64 字符串
|
|
1305
|
+
const bstr = atob(base64String);
|
|
1306
|
+
let n = bstr.length;
|
|
1307
|
+
const u8arr = new Uint8Array(n);
|
|
1308
|
+
|
|
1309
|
+
while (n--) {
|
|
1310
|
+
u8arr[n] = bstr.charCodeAt(n);
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
const file = new File([u8arr], filename, {
|
|
1314
|
+
type: 'application/octet-stream'
|
|
1315
|
+
});
|
|
1316
|
+
resolve(file);
|
|
1317
|
+
}
|
|
1318
|
+
});
|
|
1319
|
+
},
|
|
1320
|
+
/**
|
|
1321
|
+
* 上传文件到服务器
|
|
1322
|
+
*/
|
|
1323
|
+
async uploadFile(imageBase64, file, actions = '', domain, buz, buzId) {
|
|
1324
|
+
const params = new FormData();
|
|
1325
|
+
params.append('file', file);
|
|
1326
|
+
params.append('domain', domain); //业务系统代码
|
|
1327
|
+
params.append('buz', buz); //文件种类代码
|
|
1328
|
+
params.append('actions', actions);
|
|
1329
|
+
params.append('buzId', buzId); // 业务编码
|
|
1330
|
+
params.append('expired', '-1'); // 失效时间
|
|
1331
|
+
params.append('auth', auth); // 是否需要token
|
|
1332
|
+
console.log(params, '-----壳方法上传的参数----nativeUtils.js------');
|
|
1333
|
+
// token 自己生成一个吧
|
|
1334
|
+
try {
|
|
1335
|
+
const response = await axios({
|
|
1336
|
+
method: 'post',
|
|
1337
|
+
url: upLoadUrl,
|
|
1338
|
+
data: params,
|
|
1339
|
+
timeout: 60 * 1000,
|
|
1340
|
+
headers: {
|
|
1341
|
+
'Content-Type': 'multipart/form-data',
|
|
1342
|
+
'Authorization': 'Bearer ' + SSOToken.getToken('iscl', tokenKey, 60 * 10),
|
|
1343
|
+
'Accept-Device': 'Null',
|
|
1344
|
+
'Accept-DeviceOS': 'NULL',
|
|
1345
|
+
'Accept-Location': 'NULL',
|
|
1346
|
+
'Accept-ISP': 'NULL',
|
|
1347
|
+
'Accept-StartTime': 'NULL',
|
|
1348
|
+
'Accept-TimeZone': 28800000,
|
|
1349
|
+
'Accept-Attr1': 'NULL',
|
|
1350
|
+
'Accept-Attr2': 'PC',
|
|
1351
|
+
'Accept-Attr3': 'en_CN',
|
|
1352
|
+
'Real-Ip': 'NULL',
|
|
1353
|
+
'Accept-Attr4': 'NULL',
|
|
1354
|
+
'Accept-Attr6': '623023198301252893'
|
|
1355
|
+
}
|
|
1356
|
+
});
|
|
1357
|
+
|
|
1358
|
+
// 检查响应是否有效
|
|
1359
|
+
if (!response || !response.data) {
|
|
1360
|
+
throw new Error('无效的服务器响应');
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
// 检查返回数据结构
|
|
1364
|
+
if (!response.data.data) {
|
|
1365
|
+
throw new Error('服务器返回数据结构不完整');
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
// 安全地提取返回数据
|
|
1369
|
+
const fileId = response.data.data.fileId;
|
|
1370
|
+
const ext = response.data.data.ext;
|
|
1371
|
+
const returnedActions = response.data.data.actions;
|
|
1372
|
+
|
|
1373
|
+
// 验证必要字段
|
|
1374
|
+
if (!fileId) {
|
|
1375
|
+
throw new Error('服务器未返回fileId');
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
// 返回结果
|
|
1379
|
+
return {
|
|
1380
|
+
fileId: fileId,
|
|
1381
|
+
ext: ext,
|
|
1382
|
+
actions: returnedActions || ''
|
|
1383
|
+
};
|
|
1384
|
+
} catch (error) {
|
|
1385
|
+
// 详细错误处理
|
|
1386
|
+
if (error.response) {
|
|
1387
|
+
// 服务器响应了错误状态码
|
|
1388
|
+
throw new Error(`上传失败: ${error.response.status} - ${error.response.statusText}`);
|
|
1389
|
+
} else if (error.request) {
|
|
1390
|
+
// 请求已发出但没有收到响应
|
|
1391
|
+
throw new Error('网络错误: 无法连接到服务器');
|
|
1392
|
+
} else {
|
|
1393
|
+
// 其他错误
|
|
1394
|
+
throw new Error(`上传过程中发生错误: ${error.message}`);
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
},
|
|
1398
|
+
/**
|
|
1399
|
+
* 跳转到登录页面
|
|
1400
|
+
*/
|
|
1401
|
+
/**
|
|
1402
|
+
* 跳转到登录页面
|
|
1403
|
+
*/
|
|
1404
|
+
async toLogin() {
|
|
1405
|
+
// 如果已经有登录中的 Promise,直接返回它
|
|
1406
|
+
if (loginPromise) {
|
|
1407
|
+
console.log('登录操作正在进行中')
|
|
1408
|
+
return loginPromise
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
loginPromise = (async () => {
|
|
1412
|
+
try {
|
|
1413
|
+
console.log('----clearCache----nativeUtils.js------')
|
|
1414
|
+
await nativeUtils.clearCache()
|
|
1415
|
+
await nativeUtils.clearUserInfo()
|
|
1416
|
+
console.log('----toLogin----nativeUtils.js------', loginUrl)
|
|
1417
|
+
await nativeUtils.openPage(loginUrl)
|
|
1418
|
+
return false
|
|
1419
|
+
} finally {
|
|
1420
|
+
loginPromise = null
|
|
1421
|
+
}
|
|
1422
|
+
})()
|
|
1423
|
+
|
|
1424
|
+
return loginPromise
|
|
1425
|
+
},
|
|
1426
|
+
/**
|
|
1427
|
+
* 跳转到首页
|
|
1428
|
+
*/
|
|
1429
|
+
toHome(refresh = false, path = '') {
|
|
1430
|
+
return new Promise((resolve, reject) => {
|
|
1431
|
+
native.navigator.toHome({
|
|
1432
|
+
refresh: refresh,
|
|
1433
|
+
path: path // 可选参数,指定打开的页面路径
|
|
1434
|
+
}).then(res => {
|
|
1435
|
+
resolve(res);
|
|
1436
|
+
}).catch(error => {
|
|
1437
|
+
Toast.fail(`返回首页: ${error.message}`)
|
|
1438
|
+
reject(error);
|
|
1439
|
+
});
|
|
1440
|
+
})
|
|
1441
|
+
}
|
|
1442
|
+
};
|
|
1443
|
+
|
|
1444
|
+
export default nativeUtils;
|