fstarter 2.10.56 → 2.11.1
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,925 @@
|
|
|
1
|
+
// native.js
|
|
2
|
+
import native from './native-js-sdk.js'
|
|
3
|
+
import ImageCropper from './components/imageCropper.vue';
|
|
4
|
+
import {
|
|
5
|
+
Toast
|
|
6
|
+
} from "vant"
|
|
7
|
+
import "vant/lib/toast/style";
|
|
8
|
+
import axios from 'axios'
|
|
9
|
+
import {
|
|
10
|
+
JSEncrypt
|
|
11
|
+
} from 'jsencrypt'
|
|
12
|
+
const publicKey = `-----BEGIN PUBLIC KEY-----
|
|
13
|
+
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCSd6fXGTr+aQRQCFt3Vz7Pi3zW
|
|
14
|
+
rqUtVJt/U8lGVU8XX1aQ9mvqNTpeKwyHFNJSKBDbM3OrnHo2FvX7c8/ymhGKMBM3
|
|
15
|
+
NQfTlKqP3qXn3hvDppIrImpNAuYLNgfbiyHw37ggCpA1ynwJWqdHjOhllnuNsv67
|
|
16
|
+
1TpLHC4iCdA2vizuBwIDAQAB
|
|
17
|
+
-----END PUBLIC KEY-----`
|
|
18
|
+
const auth = 0 // 0: 不需要token 1: 需要token
|
|
19
|
+
import Vue from "vue";
|
|
20
|
+
const nativeUtils = {
|
|
21
|
+
/**
|
|
22
|
+
* 扫描二维码
|
|
23
|
+
*/
|
|
24
|
+
scanQRCode() {
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
native.utils.scanQRCode().then(res => {
|
|
27
|
+
resolve(res);
|
|
28
|
+
}).catch(error => {
|
|
29
|
+
Toast.fail(`扫描二维码失败: ${error.message}`)
|
|
30
|
+
reject(error);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
/**
|
|
35
|
+
* 阅读pdf h5
|
|
36
|
+
*/
|
|
37
|
+
pdfRead(pdfs, options = {}) {
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
try {
|
|
40
|
+
// 确保pdfs是数组格式
|
|
41
|
+
let pdfList = Array.isArray(pdfs) ? pdfs : [pdfs];
|
|
42
|
+
|
|
43
|
+
// 格式化PDF数据
|
|
44
|
+
const formattedPdfs = pdfList.map(pdf => typeof pdf === 'string' ? {
|
|
45
|
+
url: pdf
|
|
46
|
+
} : pdf);
|
|
47
|
+
|
|
48
|
+
// 创建挂载点
|
|
49
|
+
const mountElement = document.createElement('div');
|
|
50
|
+
mountElement.id = 'pdf-preview-mount-' + Date.now();
|
|
51
|
+
document.body.appendChild(mountElement);
|
|
52
|
+
|
|
53
|
+
// 动态导入组件
|
|
54
|
+
import('./components/pdfPreview.vue').then(componentModule => {
|
|
55
|
+
const PdfPreviewComponent = componentModule.default;
|
|
56
|
+
|
|
57
|
+
const instance = new Vue({
|
|
58
|
+
el: mountElement,
|
|
59
|
+
render: h => h(PdfPreviewComponent, {
|
|
60
|
+
ref: 'pdfPreview'
|
|
61
|
+
}),
|
|
62
|
+
mounted() {
|
|
63
|
+
this.$nextTick(() => {
|
|
64
|
+
const pdfPreview = this.$refs.pdfPreview;
|
|
65
|
+
if (pdfPreview) {
|
|
66
|
+
pdfPreview.open(formattedPdfs, options);
|
|
67
|
+
|
|
68
|
+
// 监听关闭事件
|
|
69
|
+
pdfPreview.$on('close', () => {
|
|
70
|
+
document.body.removeChild(mountElement);
|
|
71
|
+
resolve({
|
|
72
|
+
success: true
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
} else {
|
|
76
|
+
document.body.removeChild(mountElement);
|
|
77
|
+
reject(new Error('PdfPreview引用未找到'));
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}).catch(err => {
|
|
83
|
+
console.error('Failed to load PDF preview component:', err);
|
|
84
|
+
document.body.removeChild(mountElement);
|
|
85
|
+
reject(new Error('无法加载PDF预览组件'));
|
|
86
|
+
});
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.error('Error in pdfRead method:', error);
|
|
89
|
+
reject(error);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
},
|
|
93
|
+
Toast(message) {
|
|
94
|
+
Toast(message)
|
|
95
|
+
},
|
|
96
|
+
/**
|
|
97
|
+
* 添加日历事件
|
|
98
|
+
*/
|
|
99
|
+
addCalendarEvent(params) {
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
Toast.fail(`h5无法调起添加日历`)
|
|
102
|
+
});
|
|
103
|
+
},
|
|
104
|
+
/**
|
|
105
|
+
* 持久化存储
|
|
106
|
+
*/
|
|
107
|
+
setItem(key, value) {
|
|
108
|
+
return new Promise((resolve, reject) => {
|
|
109
|
+
try {
|
|
110
|
+
// 将值转换为字符串并存储到localStorage中
|
|
111
|
+
localStorage.setItem(key, JSON.stringify(value));
|
|
112
|
+
resolve({
|
|
113
|
+
success: true
|
|
114
|
+
});
|
|
115
|
+
} catch (error) {
|
|
116
|
+
Toast.fail(`持久化存储失败: ${error.message}`);
|
|
117
|
+
reject(error);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* 持久化获取
|
|
124
|
+
*/
|
|
125
|
+
getItem(key) {
|
|
126
|
+
return new Promise((resolve, reject) => {
|
|
127
|
+
try {
|
|
128
|
+
// 从localStorage中获取值
|
|
129
|
+
const item = localStorage.getItem(key);
|
|
130
|
+
if (item) {
|
|
131
|
+
// 尝试解析JSON,如果失败则返回原始值
|
|
132
|
+
try {
|
|
133
|
+
const parsedItem = JSON.parse(item);
|
|
134
|
+
resolve(parsedItem);
|
|
135
|
+
} catch (parseError) {
|
|
136
|
+
// 如果不是有效的JSON,直接返回原始值
|
|
137
|
+
resolve(item);
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
resolve(null);
|
|
141
|
+
}
|
|
142
|
+
} catch (error) {
|
|
143
|
+
Toast.fail(`持久化获取失败: ${error.message}`);
|
|
144
|
+
reject(error);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* 持久化删除
|
|
151
|
+
*/
|
|
152
|
+
removeItem(key) {
|
|
153
|
+
return new Promise((resolve, reject) => {
|
|
154
|
+
try {
|
|
155
|
+
// 从localStorage中删除指定键
|
|
156
|
+
localStorage.removeItem(key);
|
|
157
|
+
resolve({
|
|
158
|
+
success: true
|
|
159
|
+
});
|
|
160
|
+
} catch (error) {
|
|
161
|
+
Toast.fail(`持久化删除失败: ${error.message}`);
|
|
162
|
+
reject(error);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* 获取设备信息
|
|
169
|
+
*/
|
|
170
|
+
getDeviceInfo() {
|
|
171
|
+
return new Promise((resolve, reject) => {
|
|
172
|
+
Toast.fail(`获取设备信息失败`)
|
|
173
|
+
reject(`获取设备信息失败`);
|
|
174
|
+
});
|
|
175
|
+
},
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* 获取缓存大小
|
|
179
|
+
*/
|
|
180
|
+
getCacheSize() {
|
|
181
|
+
return new Promise((resolve, reject) => {
|
|
182
|
+
Toast.fail(`h5无法获取缓存大小`)
|
|
183
|
+
});
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* 清除缓存
|
|
188
|
+
*/
|
|
189
|
+
clearCache() {
|
|
190
|
+
return new Promise((resolve, reject) => {
|
|
191
|
+
Toast.fail(`h5无法清除缓存`)
|
|
192
|
+
});
|
|
193
|
+
},
|
|
194
|
+
|
|
195
|
+
// 跳转页面
|
|
196
|
+
openPage(jumpUrl) {
|
|
197
|
+
return new Promise((resolve, reject) => {
|
|
198
|
+
try {
|
|
199
|
+
// 使用H5方式跳转页面
|
|
200
|
+
window.location.href = jumpUrl;
|
|
201
|
+
resolve({
|
|
202
|
+
success: true
|
|
203
|
+
});
|
|
204
|
+
} catch (error) {
|
|
205
|
+
Toast.fail(`打开页面失败: ${error.message}`);
|
|
206
|
+
reject(error);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
},
|
|
210
|
+
// 跳转页面带分享
|
|
211
|
+
openPageWithShare(params) {
|
|
212
|
+
return new Promise((resolve, reject) => {
|
|
213
|
+
native.navigator.openPage({
|
|
214
|
+
name: 'externalH5',
|
|
215
|
+
params: {
|
|
216
|
+
url: params.url,
|
|
217
|
+
actionType: 'share',
|
|
218
|
+
title: params.title,
|
|
219
|
+
shareInfo: {
|
|
220
|
+
type: params.shareInfo.type, // 分享类型 webpage|text|image|miniProgram
|
|
221
|
+
// scene: 'session', // 可选值: session|timeline
|
|
222
|
+
content: {
|
|
223
|
+
title: params.shareInfo.content.title ? params.shareInfo.content.title : '恒安标准人寿',
|
|
224
|
+
description: params.shareInfo.content.description ? params.shareInfo.content.description : '恒安标准人寿',
|
|
225
|
+
webpageUrl: params.shareInfo.content.webpageUrl, // 替换为实际的分享链接
|
|
226
|
+
thumb: params.shareInfo.content.thumb ? params.shareInfo.content.thumb : 'https://www.ihasl.com/pages/salessupport/app/images/logo.png',
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}).then(res => {
|
|
231
|
+
resolve(res);
|
|
232
|
+
}).catch(error => {
|
|
233
|
+
Toast.fail(`打开页面失败: ${error.message}`)
|
|
234
|
+
reject(error);
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
},
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* 关闭当前H5页面
|
|
241
|
+
*/
|
|
242
|
+
closePage() {
|
|
243
|
+
return new Promise((resolve, reject) => {
|
|
244
|
+
native.navigator.closePage().then(res => {
|
|
245
|
+
resolve(res);
|
|
246
|
+
}).catch(error => {
|
|
247
|
+
Toast.fail(`关闭当前H5页面失败: ${error.message}`)
|
|
248
|
+
reject(error);
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
},
|
|
252
|
+
|
|
253
|
+
// 隐藏原生标题
|
|
254
|
+
setNavigationBarVisible(visible) {
|
|
255
|
+
return new Promise((resolve, reject) => {
|
|
256
|
+
resolve();
|
|
257
|
+
console.log('h5无法调起隐藏原生标题')
|
|
258
|
+
});
|
|
259
|
+
},
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* 拨打电话
|
|
263
|
+
* @param {*} phoneNo 手机号
|
|
264
|
+
*/
|
|
265
|
+
callphone(phoneNo) {
|
|
266
|
+
return new Promise((resolve, reject) => {
|
|
267
|
+
resolve();
|
|
268
|
+
console.log('h5无法调起拨打电话')
|
|
269
|
+
});
|
|
270
|
+
},
|
|
271
|
+
|
|
272
|
+
// 短信
|
|
273
|
+
sendSMS(phone, content) {
|
|
274
|
+
return new Promise((resolve, reject) => {
|
|
275
|
+
resolve();
|
|
276
|
+
console.log(`h5无法调起发送短信`)
|
|
277
|
+
});
|
|
278
|
+
},
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* 加密 先加密-再转base64
|
|
282
|
+
*/
|
|
283
|
+
encrypt(content) {
|
|
284
|
+
return new Promise((resolve, reject) => {
|
|
285
|
+
// 创建JSEncrypt对象
|
|
286
|
+
const encrypt = new JSEncrypt()
|
|
287
|
+
// 设置公钥
|
|
288
|
+
encrypt.setPublicKey(publicKey)
|
|
289
|
+
// 执行加密
|
|
290
|
+
const encrypted = encrypt.encrypt(content)
|
|
291
|
+
if (encrypted) {
|
|
292
|
+
resolve(btoa(encrypted))
|
|
293
|
+
} else {
|
|
294
|
+
reject(new Error('加密失败'))
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
},
|
|
298
|
+
/**
|
|
299
|
+
* 解密 仅为示例,先base64解码-再解密
|
|
300
|
+
*/
|
|
301
|
+
decrypt(content) {
|
|
302
|
+
return new Promise((resolve, reject) => {
|
|
303
|
+
// 1.创建JSEncrypt对象用于解密
|
|
304
|
+
const decrypt = new JSEncrypt();
|
|
305
|
+
// 2.设置私钥
|
|
306
|
+
decrypt.setPrivateKey(`-----BEGIN RSA PRIVATE KEY-----
|
|
307
|
+
MIIBOQIBAAJAe87bvdKkch7/tNDl1RvsO+av72yMXdbiryuhS88WjoldxzPZpzAR
|
|
308
|
+
UR74cEHk0svxtWtM6rIBmk4w//x9z0s4tQIDAQABAkA8DrFbmIW68jyaSsdipEPp
|
|
309
|
+
HtNzchV5I9ccoC6DJrbLdzjhGuTT51aa2qC4CfamW6zEYCjSbgeMqT4CzfZOKGaB
|
|
310
|
+
AiEA2iFY/H4+0s1CO1p6VoHOMDP3W+Ahy1Lu74G8fRQkzuECIQCRTWxVpPuxPzQ3
|
|
311
|
+
pfKZe5QrVRucb5vEhbV6Q3lu3YuIVQIhAKnQBEKs1aOuf71NNqhZ7XbBPfScjDKJ
|
|
312
|
+
odF7Io4NPIqBAiBBy3k+3tJJ1IDkofRUo6zYYlV6ZN94AcPHdT5LgW5pcQIgF2by
|
|
313
|
+
nFqBB1zM586NpO+4hua/1Ol5OiqoQJ4iQinyDiA=
|
|
314
|
+
-----END RSA PRIVATE KEY-----`);
|
|
315
|
+
// 3.执行解码
|
|
316
|
+
const decodedData = atob(content)
|
|
317
|
+
// 4.再进行RSA解密
|
|
318
|
+
const decrypted = decrypt.decrypt(decodedData);
|
|
319
|
+
if (decrypted) {
|
|
320
|
+
resolve(decrypted)
|
|
321
|
+
} else {
|
|
322
|
+
reject(new Error('解密失败'))
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
},
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* 唤起通讯录,并且返回name phone
|
|
329
|
+
*/
|
|
330
|
+
readContacts() {
|
|
331
|
+
return new Promise((resolve, reject) => {
|
|
332
|
+
native.device.readContacts({
|
|
333
|
+
fields: ['name', 'phone'],
|
|
334
|
+
sceneDesc: '获取通讯录',
|
|
335
|
+
}).then((data) => {
|
|
336
|
+
resolve((data))
|
|
337
|
+
}).catch(error => {
|
|
338
|
+
Toast.fail(`获取通讯录失败: ${error.message}`)
|
|
339
|
+
reject(error);
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
},
|
|
343
|
+
/**
|
|
344
|
+
* 拍照 actions:1.身份证:正面ocr_id0 反面是ocr_id1 2.银行卡ocr_bc 3.默认为空
|
|
345
|
+
*/
|
|
346
|
+
takePhoto(maxSize = 10240, actions = '', domain, buz, buzId, isCopper = false) {
|
|
347
|
+
return new Promise((resolve, reject) => {
|
|
348
|
+
// 创建一个input框 执行上传
|
|
349
|
+
// 创建隐藏的文件输入元素
|
|
350
|
+
const fileInput = document.createElement('input');
|
|
351
|
+
fileInput.type = 'file';
|
|
352
|
+
fileInput.accept = 'image/*';
|
|
353
|
+
fileInput.capture = 'environment'; // 使用后置摄像头
|
|
354
|
+
|
|
355
|
+
// 监听文件选择事件
|
|
356
|
+
fileInput.onchange = async (event) => {
|
|
357
|
+
const file = event.target.files[0];
|
|
358
|
+
if (!file) return;
|
|
359
|
+
|
|
360
|
+
try {
|
|
361
|
+
nativeUtils.closeDialog();
|
|
362
|
+
// 转换为base64
|
|
363
|
+
const reader = new FileReader();
|
|
364
|
+
reader.readAsDataURL(file);
|
|
365
|
+
|
|
366
|
+
// 返回一个Promise来处理异步读取
|
|
367
|
+
const base64Files = await new Promise((resolve, reject) => {
|
|
368
|
+
reader.onload = () => resolve({
|
|
369
|
+
imageBase64: reader.result
|
|
370
|
+
});
|
|
371
|
+
reader.onerror = error => reject(error);
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
// 身份证银行卡 必须裁剪
|
|
375
|
+
if (actions === 'ocr_id0' || actions === 'ocr_id1' || actions === 'ocr_bc' || isCopper) {
|
|
376
|
+
base64Files.imageBase64 = await nativeUtils.cropper(base64Files.imageBase64, actions);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
await Toast.loading({
|
|
380
|
+
forbidClick: true,
|
|
381
|
+
message: '上传中...',
|
|
382
|
+
duration: 0, // 持续展示 toast
|
|
383
|
+
})
|
|
384
|
+
|
|
385
|
+
// 转file
|
|
386
|
+
const newFile = await nativeUtils.base64ToFile(base64Files.imageBase64, 'image.png');
|
|
387
|
+
// 上传文件
|
|
388
|
+
const result = await nativeUtils.uploadFile(base64Files, newFile, actions, domain, buz, buzId);
|
|
389
|
+
resolve(result);
|
|
390
|
+
Toast.clear();
|
|
391
|
+
} catch (error) {
|
|
392
|
+
Toast.fail(`文件上传失败: ${error.message}`)
|
|
393
|
+
reject(error);
|
|
394
|
+
} finally {
|
|
395
|
+
// 清理input元素
|
|
396
|
+
if (fileInput.parentNode) {
|
|
397
|
+
fileInput.parentNode.removeChild(fileInput);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
// 添加到页面并触发点击
|
|
403
|
+
document.body.appendChild(fileInput);
|
|
404
|
+
fileInput.click();
|
|
405
|
+
|
|
406
|
+
// 如果用户取消选择,也需要清理
|
|
407
|
+
setTimeout(() => {
|
|
408
|
+
if (fileInput.parentNode) {
|
|
409
|
+
fileInput.parentNode.removeChild(fileInput);
|
|
410
|
+
}
|
|
411
|
+
}, 5000);
|
|
412
|
+
});
|
|
413
|
+
},
|
|
414
|
+
/**
|
|
415
|
+
* 相册
|
|
416
|
+
*/
|
|
417
|
+
chooseImage(params) {
|
|
418
|
+
return new Promise((resolve, reject) => {
|
|
419
|
+
nativeUtils.closeDialog();
|
|
420
|
+
|
|
421
|
+
// 创建隐藏的文件输入元素
|
|
422
|
+
const fileInput = document.createElement('input');
|
|
423
|
+
fileInput.type = 'file';
|
|
424
|
+
fileInput.accept = 'image/*';
|
|
425
|
+
fileInput.multiple = true; // 允许多选
|
|
426
|
+
|
|
427
|
+
// 监听文件选择事件
|
|
428
|
+
fileInput.onchange = async (event) => {
|
|
429
|
+
const files = Array.from(event.target.files);
|
|
430
|
+
if (!files.length) return;
|
|
431
|
+
|
|
432
|
+
// 检查选择的文件数量是否超过最大限制
|
|
433
|
+
if (files.length > params.maxCount) {
|
|
434
|
+
Toast.fail(`最多只能选择${params.maxCount}张图片,请重新选择`);
|
|
435
|
+
// 清理input元素
|
|
436
|
+
document.body.removeChild(fileInput);
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
try {
|
|
441
|
+
const base64Files = [];
|
|
442
|
+
|
|
443
|
+
// 将所有文件转换为base64
|
|
444
|
+
for (let i = 0; i < files.length; i++) {
|
|
445
|
+
const file = files[i];
|
|
446
|
+
const reader = new FileReader();
|
|
447
|
+
|
|
448
|
+
reader.readAsDataURL(file);
|
|
449
|
+
|
|
450
|
+
// 等待文件读取完成
|
|
451
|
+
await new Promise((resolve, reject) => {
|
|
452
|
+
reader.onload = () => {
|
|
453
|
+
base64Files.push({
|
|
454
|
+
imageBase64: reader.result
|
|
455
|
+
});
|
|
456
|
+
resolve();
|
|
457
|
+
};
|
|
458
|
+
reader.onerror = error => reject(error);
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// 大于一张图片时,提示信息
|
|
463
|
+
if (base64Files.length > 1) {
|
|
464
|
+
Toast.loading({
|
|
465
|
+
forbidClick: true,
|
|
466
|
+
message: `选择了${base64Files.length}张图片,正在上传第1张`,
|
|
467
|
+
duration: 0, // 持续展示 toast
|
|
468
|
+
})
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
const uploadResults = [];
|
|
472
|
+
let successCount = 0;
|
|
473
|
+
let failCount = 0;
|
|
474
|
+
|
|
475
|
+
// 是否需要裁剪 / 身份证,银行卡 isCropper是true 选择的图片是一张,出现裁剪
|
|
476
|
+
let isCropper = false;
|
|
477
|
+
if ((params.actions === 'ocr_id0' || params.actions === 'ocr_id1' || params.actions === 'ocr_bc' || params.isCropper) && base64Files.length === 1) {
|
|
478
|
+
isCropper = true;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// 逐个上传图片
|
|
482
|
+
for (let i = 0; i < base64Files.length; i++) {
|
|
483
|
+
const element = base64Files[i];
|
|
484
|
+
// 更新提示信息,显示当前正在上传第几张
|
|
485
|
+
if (base64Files.length > 1) {
|
|
486
|
+
Toast.loading({
|
|
487
|
+
forbidClick: true,
|
|
488
|
+
message: `选择了${base64Files.length}张图片,正在上传第${i+1}张`,
|
|
489
|
+
duration: 0, // 持续展示 toast
|
|
490
|
+
})
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
try {
|
|
494
|
+
// 1.裁剪
|
|
495
|
+
if (isCropper) {
|
|
496
|
+
element.imageBase64 = await nativeUtils.cropper(element.imageBase64, params.actions);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
await Toast.loading({
|
|
500
|
+
forbidClick: true,
|
|
501
|
+
message: '上传中...',
|
|
502
|
+
duration: 0, // 持续展示 toast
|
|
503
|
+
})
|
|
504
|
+
|
|
505
|
+
// 2.转file
|
|
506
|
+
const file = await nativeUtils.base64ToFile(element.imageBase64, 'image.png');
|
|
507
|
+
// 3.上传文件
|
|
508
|
+
const result = await nativeUtils.uploadFile(element.imageBase64, file, params.actions, params.domain, params.buz, params.buzId);
|
|
509
|
+
// 4.保存结果
|
|
510
|
+
uploadResults.push(result);
|
|
511
|
+
successCount++;
|
|
512
|
+
} catch (error) {
|
|
513
|
+
// 上传失败时增加失败计数,但不中断循环,继续上传下一张
|
|
514
|
+
failCount++;
|
|
515
|
+
console.error(`第${i+1}张图片上传失败:`, error);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// 根据上传结果进行处理
|
|
520
|
+
if (successCount > 0) {
|
|
521
|
+
// 有成功上传的图片,返回成功结果,如果只上传了一张,返回对象
|
|
522
|
+
if (uploadResults.length === 1) {
|
|
523
|
+
resolve(uploadResults[0]);
|
|
524
|
+
} else {
|
|
525
|
+
// 返回数组
|
|
526
|
+
resolve(uploadResults);
|
|
527
|
+
}
|
|
528
|
+
Toast.clear();
|
|
529
|
+
// 可选:提示用户部分图片上传失败
|
|
530
|
+
if (failCount > 0) {
|
|
531
|
+
Toast.fail(`有${failCount}张图片上传失败`);
|
|
532
|
+
}
|
|
533
|
+
} else {
|
|
534
|
+
// 所有图片都上传失败
|
|
535
|
+
reject(new Error('所有图片上传都失败了'));
|
|
536
|
+
}
|
|
537
|
+
} catch (error) {
|
|
538
|
+
Toast.fail(`选择图片上传失败: ${error.message}`)
|
|
539
|
+
reject(error);
|
|
540
|
+
} finally {
|
|
541
|
+
// 清理input元素
|
|
542
|
+
if (fileInput.parentNode) {
|
|
543
|
+
fileInput.parentNode.removeChild(fileInput);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
};
|
|
547
|
+
|
|
548
|
+
// 添加到页面并触发点击
|
|
549
|
+
document.body.appendChild(fileInput);
|
|
550
|
+
fileInput.click();
|
|
551
|
+
|
|
552
|
+
// 如果用户取消选择,也需要清理
|
|
553
|
+
setTimeout(() => {
|
|
554
|
+
if (document.body.contains(fileInput)) {
|
|
555
|
+
document.body.removeChild(fileInput);
|
|
556
|
+
}
|
|
557
|
+
}, 5000);
|
|
558
|
+
});
|
|
559
|
+
},
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* 拍照+相册 h5自己封装
|
|
563
|
+
*/
|
|
564
|
+
takePicture(params) {
|
|
565
|
+
return new Promise((resolve, reject) => {
|
|
566
|
+
nativeUtils._takePictureResolve = resolve;
|
|
567
|
+
nativeUtils._takePictureReject = reject;
|
|
568
|
+
nativeUtils.openCameraDialog(params)
|
|
569
|
+
});
|
|
570
|
+
},
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* 唤起相机相册选择弹窗
|
|
574
|
+
*/
|
|
575
|
+
openCameraDialog(params) {
|
|
576
|
+
// 移除已存在的弹窗(如果存在)
|
|
577
|
+
const existingDialog = document.getElementById('cameraDialog');
|
|
578
|
+
if (existingDialog) {
|
|
579
|
+
document.body.removeChild(existingDialog);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// 创建弹窗容器
|
|
583
|
+
const dialog = document.createElement('div');
|
|
584
|
+
dialog.id = 'cameraDialog';
|
|
585
|
+
|
|
586
|
+
// 添加样式
|
|
587
|
+
const styles = `
|
|
588
|
+
.camera-dialog {
|
|
589
|
+
position: fixed;
|
|
590
|
+
top: 0;
|
|
591
|
+
left: 0;
|
|
592
|
+
width: 100%;
|
|
593
|
+
height: 100%;
|
|
594
|
+
background: rgba(0, 0, 0, 0.3);
|
|
595
|
+
display: flex;
|
|
596
|
+
justify-content: center;
|
|
597
|
+
align-items: center;
|
|
598
|
+
z-index: 1000;
|
|
599
|
+
opacity: 0;
|
|
600
|
+
animation: fadeIn 0.3s forwards;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
@keyframes fadeIn {
|
|
604
|
+
to { opacity: 1; }
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
.dialog-content {
|
|
608
|
+
width: 100%;
|
|
609
|
+
max-width: 400px;
|
|
610
|
+
border-radius: 6px;
|
|
611
|
+
overflow: hidden;
|
|
612
|
+
transform: translateY(20px);
|
|
613
|
+
animation: slideUp 0.3s forwards;
|
|
614
|
+
position: fixed;
|
|
615
|
+
bottom: 0;
|
|
616
|
+
z-index: 1001;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
@keyframes slideUp {
|
|
620
|
+
to { transform: translateY(0); }
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
.dialog-body {
|
|
624
|
+
padding: 20px 0px;
|
|
625
|
+
margin: 0 20px;
|
|
626
|
+
}
|
|
627
|
+
.options {
|
|
628
|
+
border-radius: 10px;
|
|
629
|
+
background: #fff;
|
|
630
|
+
overflow: hidden;
|
|
631
|
+
}
|
|
632
|
+
.option-btn {
|
|
633
|
+
display: flex;
|
|
634
|
+
align-items: center;
|
|
635
|
+
justify-content: center;
|
|
636
|
+
width: 100%;
|
|
637
|
+
padding: 17px;
|
|
638
|
+
background: #fff;
|
|
639
|
+
border-bottom: 1px solid #e0e0e0;
|
|
640
|
+
font-size: 16px;
|
|
641
|
+
cursor: pointer;
|
|
642
|
+
transition: all 0.2s ease;
|
|
643
|
+
color: #007EEC;
|
|
644
|
+
font-weight: 500;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
.cancel-btn {
|
|
648
|
+
margin-top: 10px;
|
|
649
|
+
background: #fff;
|
|
650
|
+
color: #007EEC;
|
|
651
|
+
border: none;
|
|
652
|
+
margin-bottom: 20px;
|
|
653
|
+
padding: 17px;
|
|
654
|
+
width: 100%;
|
|
655
|
+
font-size: 16px;
|
|
656
|
+
cursor: pointer;
|
|
657
|
+
transition: all 0.2s ease;
|
|
658
|
+
border-radius: 8px;
|
|
659
|
+
font-weight: bold;
|
|
660
|
+
}
|
|
661
|
+
`;
|
|
662
|
+
|
|
663
|
+
// 创建样式元素
|
|
664
|
+
const styleEl = document.createElement('style');
|
|
665
|
+
styleEl.textContent = styles;
|
|
666
|
+
document.head.appendChild(styleEl);
|
|
667
|
+
|
|
668
|
+
// 弹窗内容
|
|
669
|
+
dialog.innerHTML = `
|
|
670
|
+
<div class="camera-dialog">
|
|
671
|
+
<div class="dialog-content">
|
|
672
|
+
<div class="dialog-body">
|
|
673
|
+
<div class="options">
|
|
674
|
+
<button class="option-btn" id="cameraBtn">
|
|
675
|
+
拍照
|
|
676
|
+
</button>
|
|
677
|
+
<button class="option-btn" id="albumBtn">
|
|
678
|
+
从相册选择
|
|
679
|
+
</button>
|
|
680
|
+
</div>
|
|
681
|
+
<button class="cancel-btn" id="cancelBtn">取消</button>
|
|
682
|
+
</div>
|
|
683
|
+
</div>
|
|
684
|
+
</div>
|
|
685
|
+
`;
|
|
686
|
+
setTimeout(() => {
|
|
687
|
+
document.getElementById('cameraBtn').addEventListener('click', () => {
|
|
688
|
+
nativeUtils.handleCamera(nativeUtils._takePictureResolve, nativeUtils._takePictureReject, params);
|
|
689
|
+
});
|
|
690
|
+
document.getElementById('albumBtn').addEventListener('click', () => {
|
|
691
|
+
nativeUtils.handleAlbum(nativeUtils._takePictureResolve, nativeUtils._takePictureReject, params);
|
|
692
|
+
});
|
|
693
|
+
document.getElementById('cancelBtn').addEventListener('click', () => {
|
|
694
|
+
nativeUtils.closeDialog();
|
|
695
|
+
nativeUtils._takePictureReject(new Error('用户取消了操作'));
|
|
696
|
+
});
|
|
697
|
+
}, 0);
|
|
698
|
+
|
|
699
|
+
// 添加到文档
|
|
700
|
+
document.body.appendChild(dialog);
|
|
701
|
+
|
|
702
|
+
// 添加事件监听器,点击背景关闭弹窗
|
|
703
|
+
dialog.addEventListener('click', function (e) {
|
|
704
|
+
if (e.target.classList.contains('camera-dialog')) {
|
|
705
|
+
this.closeDialog();
|
|
706
|
+
}
|
|
707
|
+
});
|
|
708
|
+
},
|
|
709
|
+
// 关闭弹窗
|
|
710
|
+
closeDialog() {
|
|
711
|
+
const dialog = document.getElementById('cameraDialog');
|
|
712
|
+
if (dialog) {
|
|
713
|
+
dialog.querySelector('.camera-dialog').style.animation = 'fadeOut 0.3s forwards';
|
|
714
|
+
// 添加淡出动画
|
|
715
|
+
const styles = document.querySelector('style');
|
|
716
|
+
if (styles && !styles.textContent.includes('fadeOut')) {
|
|
717
|
+
styles.textContent += `
|
|
718
|
+
@keyframes fadeOut {
|
|
719
|
+
from { opacity: 1; }
|
|
720
|
+
to { opacity: 0; }
|
|
721
|
+
}
|
|
722
|
+
`;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
setTimeout(() => {
|
|
726
|
+
document.body.removeChild(dialog);
|
|
727
|
+
}, 300);
|
|
728
|
+
}
|
|
729
|
+
delete nativeUtils._takePictureResolve;
|
|
730
|
+
delete nativeUtils._takePictureReject;
|
|
731
|
+
},
|
|
732
|
+
|
|
733
|
+
// 处理拍照
|
|
734
|
+
async handleCamera(resolve, reject, params) {
|
|
735
|
+
try {
|
|
736
|
+
const res = await nativeUtils.takePhoto(params.maxSize, params.actions, params.domain, params.buz, params.buzId, params.isCropper);
|
|
737
|
+
resolve(res); // 返回数组以保持与多图一致
|
|
738
|
+
nativeUtils.closeDialog();
|
|
739
|
+
} catch (error) {
|
|
740
|
+
reject(error);
|
|
741
|
+
nativeUtils.closeDialog();
|
|
742
|
+
}
|
|
743
|
+
},
|
|
744
|
+
|
|
745
|
+
// 处理相册选择
|
|
746
|
+
async handleAlbum(resolve, reject, params) {
|
|
747
|
+
try {
|
|
748
|
+
const res = await nativeUtils.chooseImage(params);
|
|
749
|
+
resolve(res);
|
|
750
|
+
nativeUtils.closeDialog();
|
|
751
|
+
} catch (error) {
|
|
752
|
+
reject(error);
|
|
753
|
+
nativeUtils.closeDialog();
|
|
754
|
+
}
|
|
755
|
+
},
|
|
756
|
+
/**
|
|
757
|
+
* 裁剪图片
|
|
758
|
+
* @param {string} base64String - 原始图片的base64数据
|
|
759
|
+
* @returns {Promise<string>} 裁剪后图片的base64数据
|
|
760
|
+
*/
|
|
761
|
+
cropper(base64String, actions) {
|
|
762
|
+
return new Promise((resolve, reject) => {
|
|
763
|
+
// 创建裁剪容器
|
|
764
|
+
const cropperContainer = document.createElement('div');
|
|
765
|
+
cropperContainer.id = 'image-cropper-container';
|
|
766
|
+
document.body.appendChild(cropperContainer);
|
|
767
|
+
|
|
768
|
+
// 创建Vue实例
|
|
769
|
+
const cropperInstance = new Vue({
|
|
770
|
+
data() {
|
|
771
|
+
return {
|
|
772
|
+
imgSrc: base64String,
|
|
773
|
+
};
|
|
774
|
+
},
|
|
775
|
+
methods: {
|
|
776
|
+
handleConfirm(croppedData) {
|
|
777
|
+
var divToDelete = document.querySelector('.image-cropper-container');
|
|
778
|
+
divToDelete.remove()
|
|
779
|
+
resolve(croppedData);
|
|
780
|
+
},
|
|
781
|
+
handleCancel() {
|
|
782
|
+
var divToDelete = document.querySelector('.image-cropper-container');
|
|
783
|
+
divToDelete.remove()
|
|
784
|
+
reject(new Error('用户取消裁剪'));
|
|
785
|
+
}
|
|
786
|
+
},
|
|
787
|
+
render(h) {
|
|
788
|
+
return h(ImageCropper, {
|
|
789
|
+
props: {
|
|
790
|
+
imgSrc: this.imgSrc,
|
|
791
|
+
actions: actions
|
|
792
|
+
},
|
|
793
|
+
on: {
|
|
794
|
+
confirm: this.handleConfirm,
|
|
795
|
+
cancel: this.handleCancel
|
|
796
|
+
}
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
}).$mount(cropperContainer);
|
|
800
|
+
});
|
|
801
|
+
},
|
|
802
|
+
/**
|
|
803
|
+
* 将base64字符串转换为File对象
|
|
804
|
+
* @param {string} base64String - base64编码的字符串
|
|
805
|
+
* @param {string} filename - 文件名
|
|
806
|
+
* @param {string} mimeType - MIME类型,默认为'image/jpeg'
|
|
807
|
+
* @returns {File} File对象
|
|
808
|
+
*/
|
|
809
|
+
base64ToFile(base64String, filename = 'file.png') {
|
|
810
|
+
return new Promise((resolve, reject) => {
|
|
811
|
+
// 检查 base64String 是否包含数据 URI 前缀
|
|
812
|
+
if (base64String.includes(',')) {
|
|
813
|
+
const arr = base64String.split(',');
|
|
814
|
+
const mimeMatch = arr[0].match(/:(.*?);/);
|
|
815
|
+
const mime = mimeMatch ? mimeMatch[1] : 'application/octet-stream';
|
|
816
|
+
const bstr = atob(arr[1]);
|
|
817
|
+
let n = bstr.length;
|
|
818
|
+
const u8arr = new Uint8Array(n);
|
|
819
|
+
|
|
820
|
+
while (n--) {
|
|
821
|
+
u8arr[n] = bstr.charCodeAt(n);
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
const file = new File([u8arr], filename, {
|
|
825
|
+
type: mime
|
|
826
|
+
});
|
|
827
|
+
resolve(file);
|
|
828
|
+
} else {
|
|
829
|
+
// 如果不包含逗号,可能是纯 base64 字符串
|
|
830
|
+
const bstr = atob(base64String);
|
|
831
|
+
let n = bstr.length;
|
|
832
|
+
const u8arr = new Uint8Array(n);
|
|
833
|
+
|
|
834
|
+
while (n--) {
|
|
835
|
+
u8arr[n] = bstr.charCodeAt(n);
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
const file = new File([u8arr], filename, {
|
|
839
|
+
type: 'application/octet-stream'
|
|
840
|
+
});
|
|
841
|
+
resolve(file);
|
|
842
|
+
}
|
|
843
|
+
});
|
|
844
|
+
},
|
|
845
|
+
/**
|
|
846
|
+
* 上传文件到服务器
|
|
847
|
+
*/
|
|
848
|
+
async uploadFile(imageBase64, file, actions = '', domain, buz, buzId) {
|
|
849
|
+
const params = new FormData();
|
|
850
|
+
params.append('file', file);
|
|
851
|
+
params.append('domain', domain); //业务系统代码
|
|
852
|
+
params.append('buz', buz); //文件种类代码
|
|
853
|
+
params.append('actions', actions);
|
|
854
|
+
params.append('buzId', buzId); // 业务编码
|
|
855
|
+
params.append('expired', '-1'); // 失效时间
|
|
856
|
+
params.append('auth', auth); // 是否需要token
|
|
857
|
+
|
|
858
|
+
try {
|
|
859
|
+
const response = await axios({
|
|
860
|
+
method: 'post',
|
|
861
|
+
url: 'https://testfile.ihasl.com/file/v1/hasl/fileAdmin/fileAdmin/upload',
|
|
862
|
+
data: params,
|
|
863
|
+
timeout: 60 * 1000,
|
|
864
|
+
headers: {
|
|
865
|
+
'Content-Type': 'multipart/form-data',
|
|
866
|
+
'Authorization': 'Basic ' + 'eyJhbGciOiJIUzI1NiJ9.eyJ0Z3QiOiI1NTFiZDM0ZmRhN2Y0OTQxOWRkZGZmOTM5MDFkZmE1MiIsInN1YiI6IlBFMDkyOCIsIm5iZiI6MTc1ODU5MjcyMiwiZXhwIjoxNzU4NjM1OTIyLCJ1c2VyaWQiOiJQRTA5MjgiLCJpYXQiOjE3NTg1OTI3MjIsImtleSI6IjU1MWJkMzRmZGE3ZjQ5NDE5ZGRkZmY5MzkwMWRmYTUyLVJFRCJ9.A78OM2H7wJxr8CORGlSWLo4M8RBHtUzEStVBTQNLrww',
|
|
867
|
+
'Accept-Device': 'Null',
|
|
868
|
+
'Accept-DeviceOS': 'NULL',
|
|
869
|
+
'Accept-Location': 'NULL',
|
|
870
|
+
'Accept-ISP': 'NULL',
|
|
871
|
+
'Accept-StartTime': 'NULL',
|
|
872
|
+
'Accept-TimeZone': 28800000,
|
|
873
|
+
'Accept-Attr1': 'NULL',
|
|
874
|
+
'Accept-Attr2': 'PC',
|
|
875
|
+
'Accept-Attr3': 'en_CN',
|
|
876
|
+
'Real-Ip': 'NULL',
|
|
877
|
+
'Accept-Attr4': 'NULL',
|
|
878
|
+
'Accept-Attr6': '623023198301252893'
|
|
879
|
+
}
|
|
880
|
+
});
|
|
881
|
+
|
|
882
|
+
// 检查响应是否有效
|
|
883
|
+
if (!response || !response.data) {
|
|
884
|
+
throw new Error('无效的服务器响应');
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
// 检查返回数据结构
|
|
888
|
+
if (!response.data.data) {
|
|
889
|
+
throw new Error('服务器返回数据结构不完整');
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
// 安全地提取返回数据
|
|
893
|
+
const fileId = response.data.data.fileId;
|
|
894
|
+
const ext = response.data.data.ext;
|
|
895
|
+
const returnedActions = response.data.data.actions;
|
|
896
|
+
|
|
897
|
+
// 验证必要字段
|
|
898
|
+
if (!fileId) {
|
|
899
|
+
throw new Error('服务器未返回fileId');
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
// 返回结果
|
|
903
|
+
return {
|
|
904
|
+
fileId: fileId,
|
|
905
|
+
ext: ext,
|
|
906
|
+
imageBase64: imageBase64 || '',
|
|
907
|
+
actions: returnedActions || ''
|
|
908
|
+
};
|
|
909
|
+
} catch (error) {
|
|
910
|
+
// 详细错误处理
|
|
911
|
+
if (error.response) {
|
|
912
|
+
// 服务器响应了错误状态码
|
|
913
|
+
throw new Error(`上传失败: ${error.response.status} - ${error.response.statusText}`);
|
|
914
|
+
} else if (error.request) {
|
|
915
|
+
// 请求已发出但没有收到响应
|
|
916
|
+
throw new Error('网络错误: 无法连接到服务器');
|
|
917
|
+
} else {
|
|
918
|
+
// 其他错误
|
|
919
|
+
throw new Error(`上传过程中发生错误: ${error.message}`);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
},
|
|
923
|
+
};
|
|
924
|
+
|
|
925
|
+
export default nativeUtils;
|