fhrons-mobile-next 2.0.0

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/upload.js ADDED
@@ -0,0 +1,518 @@
1
+ // cdn引入axios
2
+ if (!window.axios) {
3
+ loadJavaScript(
4
+ "https://scrm-pro-1251973116.file.myqcloud.com/funzg/form/axios.js",
5
+ () => {
6
+ console.log("axios 加载成功");
7
+ }
8
+ );
9
+ }
10
+ // if (!window.AWS) {
11
+ // loadJavaScript('https://dop-pro-1251973116.file.myqcloud.com/upload/jsfile/funzg/aws-sdk-2.1562.0.min.js', () => {
12
+ // console.log('aws-sdk 加载成功');
13
+ // });
14
+ // }
15
+ if (!window.COS) {
16
+ loadJavaScript(
17
+ "https://dop-pro-1251973116.file.myqcloud.com/upload/jsfile/funzg/cos-js-sdk-v5.min.js",
18
+ () => {
19
+ console.log("腾讯cos 加载成功");
20
+ }
21
+ );
22
+ }
23
+ if (!window.lrz) {
24
+ loadJavaScript(
25
+ "https://dop-pro-1251973116.file.myqcloud.com/upload/jsfile/funzg/lrz.all.bundle.min.js",
26
+ () => {
27
+ console.log("lrz加载成功");
28
+ }
29
+ );
30
+ }
31
+ if (!window.FHENCYPT) {
32
+ loadJavaScript(
33
+ "https://dop-pro-1251973116.file.myqcloud.com/upload/jsfile/funzg/fhEncypt.js",
34
+ () => {
35
+ console.log("FHENCYPT加载成功");
36
+ }
37
+ );
38
+ }
39
+
40
+ // const Minio = require('./utils/minio/internal/client.js')
41
+ // import * as Minio from 'minio'
42
+
43
+ /**
44
+ * 第一个参数的可选属性
45
+ * @param {Blob} file 要上传的文件
46
+ * @param {String} target 要上传的目标云,类型:0大陆环境/1港险环境
47
+ * @param {String} project 所属项目:0全局,1课程,2开放平台,4:scrm 5:营销 6:frcdap
48
+ * @param {Function} keyFunc 生成key的方法
49
+ * @param {Boolean} needWholeRes 是否需要返回完整的响应体
50
+ * @param {Number} urlMaxLength url 的长度限制
51
+ *
52
+ * 第二个参数
53
+ * @param {Function} onProgress 接收上传进度的回调
54
+ * @returns Link 上传完成后的图片链接
55
+ *
56
+ * 例:
57
+ * const param = {
58
+ * file, target = 'tencent', project = '0', keyFunc
59
+ * }
60
+ * upload(param,(percent)=>{
61
+ * console.log(percent) // 输出上传进度的百分比
62
+ * })
63
+ */
64
+ // 将函数提取到外部,避免重复定义
65
+ function getFullFileName(file) {
66
+ // 优先使用 File 对象的 name 属性
67
+ const fileName = file.name || file.filename || "";
68
+
69
+ // 如果已有后缀名(包含点号),直接返回
70
+ if (fileName.includes(".")) {
71
+ return fileName;
72
+ }
73
+
74
+ // 没有后缀名,从 type 中提取
75
+ if (file.type && file.type.includes("/")) {
76
+ let extension = file.type.split("/")[1]; // 从"image/jpeg"提取"jpeg"
77
+
78
+ // 特殊情况处理
79
+ if (extension === "jpeg") {
80
+ extension = "jpg";
81
+ }
82
+
83
+ // 清理扩展名中的参数(如 "svg+xml")
84
+ extension = extension.split("+")[0];
85
+
86
+ return `${fileName}.${extension}`;
87
+ }
88
+
89
+ // 如果连 type 都没有,返回原文件名
90
+ return fileName;
91
+ }
92
+ const contentTypeMap = {
93
+ // 图片
94
+ jpg: "image/*",
95
+ jpeg: "image/*",
96
+ png: "image/*",
97
+ gif: "image/*",
98
+ bmp: "image/*",
99
+ webp: "image/*",
100
+ svg: "image/*",
101
+ ico: "image/*",
102
+ // 视频
103
+ mp4: "video/*",
104
+ avi: "video/*",
105
+ mov: "video/*",
106
+ wmv: "video/*",
107
+ flv: "video/*",
108
+ mkv: "video/*",
109
+ webm: "video/*",
110
+ // 音频
111
+ mp3: "audio/*",
112
+ wav: "audio/*",
113
+ aac: "audio/*",
114
+ ogg: "audio/*",
115
+ m4a: "audio/*",
116
+ flac: "audio/*",
117
+ // PDF
118
+ pdf: "application/pdf",
119
+ // Office
120
+ doc: "application/*",
121
+ docx: "application/*",
122
+ xls: "application/*",
123
+ xlsx: "application/*",
124
+ ppt: "application/*",
125
+ pptx: "application/*",
126
+ // 文本
127
+ txt: "text/*",
128
+ csv: "text/*",
129
+ // 压缩文件
130
+ zip: "application/*",
131
+ rar: "application/*",
132
+ "7z": "application/*",
133
+ tar: "application/*",
134
+ gz: "application/*",
135
+ };
136
+
137
+ function getContentTypeByExtension(ext) {
138
+ console.log("getContentTypeByExtension ext", ext);
139
+
140
+ if (!ext || typeof ext !== "string") return null;
141
+ return contentTypeMap[ext.toLowerCase()] || null;
142
+ }
143
+ export function upload(
144
+ { file, target, project = "0", keyFunc, needWholeRes },
145
+ onProgress
146
+ ) {
147
+ let defaultTarget =
148
+ location.origin.includes("https://smnguat.fhrons.net") ||
149
+ location.origin.includes("https://openuat.fhrons.net") ||
150
+ location.origin.includes("https://smng.avantech.io") ||
151
+ location.origin.includes("https://open.avantech.io") ||
152
+ (process.env.VUE_APP_ENV_CONFIG &&
153
+ process.env.VUE_APP_ENV_CONFIG.includes("hk"))
154
+ ? "1"
155
+ : "0";
156
+ defaultTarget =
157
+ process.env.VUE_APP_ENV_CONFIG &&
158
+ process.env.VUE_APP_ENV_CONFIG.includes("poc")
159
+ ? "2"
160
+ : defaultTarget;
161
+ target = target ? (target === "tencent" ? "0" : "1") : defaultTarget;
162
+ if (!file) {
163
+ console.error("上传的文件不能为空");
164
+ return;
165
+ }
166
+ if (file.raw) file = file.raw; // 有的file对象里面的raw才是实际的文件内容
167
+ if (file.file) file = file.file; // vant文件选择器选到的文件里还有一层file
168
+ // target = target === 'tencent' ? '0' : '1'; // 根据传进来的target转换
169
+ // target = '2'
170
+ const filename = getFullFileName(file);
171
+ const temp = filename.split(".");
172
+ const fileSffix = temp[temp.length - 1];
173
+ const appName = process.env.VUE_APP_NAME || "common";
174
+ if (
175
+ typeof keyFunc !== "function" ||
176
+ (typeof keyFunc === "function" && !keyFunc())
177
+ )
178
+ keyFunc = () =>
179
+ `/${appName}/${new Date().valueOf()}_${temp[0]}${
180
+ fileSffix ? "." + fileSffix : ""
181
+ }`;
182
+
183
+ let newKey = keyFunc();
184
+ newKey = removeLeadingSlash(newKey);
185
+ console.log("newKey", newKey);
186
+
187
+ // if(urlMaxLength && newKey.length > urlMaxLength) return Promise.reject(`文件名长度过长,请保持在${urlMaxLength}以下`)
188
+ return axios
189
+ .post(
190
+ `/funapi/cbsconfig/oss/secureSign`,
191
+ {
192
+ type: target,
193
+ project: project,
194
+ filePath: newKey,
195
+ },
196
+ { headers: { "Content-Type": "application/json" } }
197
+ )
198
+ .then((res) => {
199
+ if (
200
+ target !== "2" &&
201
+ (typeof res.data === "string" || typeof res === "string")
202
+ )
203
+ res = JSON.parse(FHENCYPT.decrypt(res.data || res));
204
+ console.log("res", JSON.stringify(res));
205
+
206
+ const {
207
+ tmpSecretId,
208
+ tmpSecretKey,
209
+ token,
210
+ sessionToken,
211
+ startTime,
212
+ expiredTime,
213
+ requestId,
214
+ type,
215
+ bucketName,
216
+ region,
217
+ cdnUrl,
218
+ status = "SUCCESS",
219
+ message = "",
220
+ } = res.data || res;
221
+ if (status !== "SUCCESS") {
222
+ throw new Error(message);
223
+ }
224
+ /**
225
+ * @tmpSecretId 临时访问密钥的标识符。
226
+ * @tmpSecretKey 临时访问密钥的密钥。
227
+ * @type 0腾讯/1亚马逊/2 minio 字符串格式
228
+ * @startTime 腾讯使用的字段,开始时间
229
+ * @expiredTime 腾讯使用的字段,过期时间
230
+ * @bucketName 存储桶名称
231
+ * @cdnUrl cdn链接的前缀
232
+ * @region 存储区域
233
+ */
234
+ // if (type === '1') { // 亚马逊
235
+ // AWS.config.update({
236
+ // accessKeyId: tmpSecretId,
237
+ // secretAccessKey: tmpSecretKey,
238
+ // region: region,
239
+ // sessionToken: token
240
+ // });
241
+ // const s3 = new AWS.S3();
242
+ // const params = {
243
+ // Bucket: bucketName,
244
+ // Key: newKey,
245
+ // ContentType: type,
246
+ // Body: file,
247
+ // 'Access-Control-Allow-Credentials': '*'
248
+ // };
249
+ // const upload = s3.upload(params);
250
+ // upload.on('httpUploadProgress', (progress) => {
251
+ // const { loaded, total } = progress;
252
+ // /* 非必须 */
253
+ // const percent = Math.round(parseInt(loaded / total) * 100);
254
+ // if (typeof onProgress === 'function') onProgress(percent);
255
+ // });
256
+ // const uploadPromise = upload.promise();
257
+ // return uploadPromise.then(res => {
258
+ // const { key, Key } = res;
259
+ // console.log(res);
260
+ // // const tempUrl = (key.startsWith('/') ? '' : '/');
261
+ // const fileUrl = `${cdnUrl}${cdnUrl.endsWith('/') ? '' : '/'}${key || Key}`
262
+ // if (needWholeRes) {
263
+ // return {
264
+ // ...res,
265
+ // fileUrl
266
+ // };
267
+ // } return fileUrl;
268
+ // }).catch(err => {
269
+ // console.log(err);
270
+ // }).finally(_ => {
271
+ // });
272
+ // } else
273
+ // if (type === '2') { // 如果type=2 则使用minIO上传
274
+ // console.log(Minio)
275
+ // const minioClient = new Minio.Client({
276
+ // endPoint: 'poc.fhrons.com',
277
+ // // port: 31003,
278
+ // useSSL: true,
279
+ // accessKey: tmpSecretId,
280
+ // secretKey: tmpSecretKey,
281
+ // sessionToken: token
282
+ // })
283
+ // return uploadFileToMinio(file, minioClient, bucketName, newKey, cdnUrl, needWholeRes).then(res => {
284
+ // if (typeof onProgress === 'function') onProgress(100)
285
+ // console.log('上传成功,', res)
286
+ // return res
287
+ // }).catch(err => {
288
+ // console.log(err);
289
+ // })
290
+
291
+ // }
292
+ // 腾讯 如果没有type 则默认使用腾讯上传
293
+ const cos = new COS({
294
+ getAuthorization: function (options, callback) {
295
+ callback({
296
+ TmpSecretId: tmpSecretId,
297
+ TmpSecretKey: tmpSecretKey,
298
+ XCosSecurityToken: sessionToken,
299
+ StartTime: startTime,
300
+ ExpiredTime: expiredTime,
301
+ requestId: requestId,
302
+ SecurityToken: token,
303
+ });
304
+ },
305
+ });
306
+ // 在 cos.putObject().catch() 中抛出错误
307
+ return cos
308
+ .putObject({
309
+ Bucket: bucketName,
310
+ Region: region,
311
+ Key: newKey,
312
+ StorageClass: "STANDARD",
313
+ Body: file,
314
+ Headers: {
315
+ "x-cos-meta-test": "123",
316
+ "Cache-control": "no-cache",
317
+ "Content-Type": getContentTypeByExtension(fileSffix),
318
+ },
319
+ onProgress: (progressData) => {
320
+ const percent = Math.round(progressData.percent * 100);
321
+ if (typeof onProgress === "function") onProgress(percent);
322
+ },
323
+ })
324
+ .then((data) => {
325
+ console.log("cos", data);
326
+ let fileUrl = "";
327
+ if (data.statusCode == 200) {
328
+ fileUrl = `${cdnUrl}/${newKey}`;
329
+ return fileUrl; // ✅ 成功时返回 url
330
+ } else {
331
+ // ❌ 状态码不是 200,抛出错误
332
+ throw new Error(`上传失败,状态码: ${data.statusCode}`);
333
+ }
334
+ })
335
+ .catch((err) => {
336
+ console.log("COS 上传错误:", err);
337
+ // ✅ 抛出错误,让调用方 catch 能捕获
338
+ throw err; // 或者 return Promise.reject(err);
339
+ });
340
+ });
341
+ }
342
+
343
+ function uploadFileToMinio(
344
+ file,
345
+ minioClient,
346
+ bucketName,
347
+ newKey,
348
+ cdnUrl,
349
+ needWholeRes
350
+ ) {
351
+ return new Promise((resolve, reject) => {
352
+ const reader = new FileReader();
353
+ reader.onload = function (e) {
354
+ try {
355
+ const buffer = Buffer.from(e.target.result);
356
+ minioClient.putObject(bucketName, newKey, buffer, function (err, etag) {
357
+ if (err) {
358
+ console.log(err);
359
+ return err;
360
+ }
361
+ console.log(etag);
362
+ const fileUrl = `${cdnUrl}${
363
+ cdnUrl.endsWith("/") ? "" : "/"
364
+ }${newKey}`;
365
+ if (needWholeRes) {
366
+ resolve({
367
+ etag,
368
+ fileUrl,
369
+ });
370
+ }
371
+ resolve(fileUrl);
372
+ });
373
+ } catch (err) {
374
+ reject(err);
375
+ }
376
+ };
377
+ reader.onerror = function (err) {
378
+ reject(err);
379
+ };
380
+ reader.readAsArrayBuffer(file);
381
+ });
382
+ }
383
+
384
+ /**
385
+ * @param {Blob} file 上传的图片文件
386
+ * @param {Number} quality 压缩质量
387
+ * @returns 返回压缩后的图片文件
388
+ */
389
+ // 压缩文件
390
+ export async function compressFile(file, quality = 0.7) {
391
+ file = file.raw ? file.raw : file;
392
+ // const imageCompressor = new Compressor();
393
+ try {
394
+ let reFile = "";
395
+ const rst = await lrz(file, {
396
+ quality: quality, // 图片压缩质量,取值0-1,默认为0.7
397
+ });
398
+ // const rst = new Compressor(file);
399
+ reFile = new File([rst.file], file.name, {
400
+ type: "image/jpeg",
401
+ lastModified: Date.now(),
402
+ });
403
+ return reFile;
404
+ } catch (error) {
405
+ return "";
406
+ }
407
+ }
408
+
409
+ /**
410
+ * @param {Blob} file 上传的图片文件
411
+ * @param {Number} size 指定压缩后的图片大小
412
+ * @param {Number} quality 压缩质量
413
+ * @returns 返回压缩后的图片文件
414
+ */
415
+ // 循环压缩
416
+ export async function loopCompressFile(file, size, quality) {
417
+ if (!size) {
418
+ return new Error("size 不能为空");
419
+ }
420
+ // let reFile = file;
421
+ const reFile = await compressFile(file, quality);
422
+ if (reFile.size > size) {
423
+ compressFile(reFile, quality);
424
+ }
425
+ return reFile;
426
+ }
427
+
428
+ // 判断html文档中是否有重复引用的标签
429
+ /**
430
+ * @param {String} src 要检查的引用地址
431
+ */
432
+ function chectDuplicateScript(src) {
433
+ let result = false;
434
+ // 获取文档中所有的script标签
435
+ const scriptTags = document.getElementsByTagName("script");
436
+ // 创建一个存储已经出现过的URL集合
437
+ const scriptURLs = new Set();
438
+ // 遍历所有的tag 标签
439
+ for (let i = 0; i < scriptTags.length; i++) {
440
+ const currentSrc = scriptTags[i].getAttribute("src");
441
+ if (currentSrc && currentSrc === src) {
442
+ if (scriptURLs.has(currentSrc)) {
443
+ // console.log('重复引用,引用地址为', currentSrc);
444
+ result = true;
445
+ } else {
446
+ scriptURLs.add(currentSrc);
447
+ }
448
+ }
449
+ }
450
+ if (scriptURLs.size === 0) {
451
+ result = false;
452
+ // console.log('没有重复引用', src);
453
+ }
454
+ return result;
455
+ }
456
+ // 动态引入JS文件
457
+ export function loadJavaScript(src, callback) {
458
+ if (chectDuplicateScript(src)) return;
459
+ const script = document.createElement("script");
460
+ const head = document.getElementsByTagName("head")[0];
461
+ script.type = "text/javascript";
462
+ script.charset = "UTF-8";
463
+ script.src = src;
464
+ window.onerror = () => {
465
+ console.log(`loadJavaScript加载${src}失败`);
466
+ };
467
+ if (script.addEventListener) {
468
+ script.addEventListener(
469
+ "load",
470
+ function () {
471
+ callback();
472
+ },
473
+ false
474
+ );
475
+ } else if (script.attachEvent) {
476
+ script.attachEvent("onreadystatechange", function () {
477
+ const target = window.event.srcElement;
478
+ if (target.readyState === "loaded" || script.readState === "complate") {
479
+ callback();
480
+ }
481
+ });
482
+ }
483
+ script.addEventListener("error", (e) => {
484
+ if (!isEmpty(e)) {
485
+ callback("err");
486
+ }
487
+ });
488
+ if (src) {
489
+ // 如果src不存在,不加入到项目里面去,否则会报加载资源失败
490
+ head.appendChild(script);
491
+ }
492
+ }
493
+ /**
494
+ * 为空
495
+ * @param val
496
+ * @returns {boolean}
497
+ */
498
+ function isEmpty(val) {
499
+ if (
500
+ val === null ||
501
+ val === undefined ||
502
+ (typeof val === "string" &&
503
+ (val === "" || val === "undefined" || val === "null")) ||
504
+ (Array.isArray(val) && val.length === 0) ||
505
+ (Object.prototype.toString.call(val) === "[object Object]" &&
506
+ Object.keys(val).length === 0)
507
+ ) {
508
+ return true;
509
+ }
510
+ return false;
511
+ }
512
+
513
+ function removeLeadingSlash(str) {
514
+ if (str.startsWith("/")) {
515
+ return str.substring(1); // 返回去掉斜杠后的值
516
+ }
517
+ return str; // 如果字符串不以斜杠开头,则返回原始字符串
518
+ }
package/utils/tools.js ADDED
@@ -0,0 +1,22 @@
1
+ // base64转Blob 2
2
+ export function base64ToBlob (urlData, type) {
3
+ const arr = urlData.split(',');
4
+ if (arr.length > 1) {
5
+ const temp = arr[0].match(/:(.*?);/);
6
+ const mime = temp && temp.length > 1 ? (temp[1] || type) : type;
7
+ // 去掉url的头,并转化为byte
8
+ const bytes = window.atob(arr[1]);
9
+ // 处理异常,将ascii码小于0的转换为大于0
10
+ const ab = new ArrayBuffer(bytes.length);
11
+ // 生成视图(直接针对内存):8位无符号整数,长度1个字节
12
+ const ia = new Uint8Array(ab);
13
+ for (let i = 0; i < bytes.length; i++) {
14
+ ia[i] = bytes.charCodeAt(i);
15
+ }
16
+ const blob = new Blob([ab], {
17
+ type: mime
18
+ })
19
+ return new File([blob], `poster_${new Date().valueOf()}.png`, { type: mime });
20
+ }
21
+ }
22
+