潘志宝
6 天以前 12024e7c6f22f7bf68e877f6a688ba7bde0fe9c2
提交 | 用户 | 时间
820397 1 import * as FileApi from '@/api/infra/file'
H 2 import CryptoJS from 'crypto-js'
3 import { UploadRawFile, UploadRequestOptions } from 'element-plus/es/components/upload/src/upload'
4 import axios from 'axios'
5
221c1c 6 /**
H 7  * 获得上传 URL
8  */
9 export const getUploadUrl = (): string => {
10   return import.meta.env.VITE_BASE_URL + import.meta.env.VITE_API_URL + '/infra/file/upload'
11 }
12
820397 13 export const useUpload = () => {
H 14   // 后端上传地址
221c1c 15   const uploadUrl = getUploadUrl()
820397 16   // 是否使用前端直连上传
H 17   const isClientUpload = UPLOAD_TYPE.CLIENT === import.meta.env.VITE_UPLOAD_TYPE
18   // 重写ElUpload上传方法
19   const httpRequest = async (options: UploadRequestOptions) => {
20     // 模式一:前端上传
21     if (isClientUpload) {
22       // 1.1 生成文件名称
23       const fileName = await generateFileName(options.file)
24       // 1.2 获取文件预签名地址
25       const presignedInfo = await FileApi.getFilePresignedUrl(fileName)
26       // 1.3 上传文件(不能使用 ElUpload 的 ajaxUpload 方法的原因:其使用的是 FormData 上传,Minio 不支持)
221c1c 27       return axios
H 28         .put(presignedInfo.uploadUrl, options.file, {
29           headers: {
30             'Content-Type': options.file.type
31           }
32         })
33         .then(() => {
34           // 1.4. 记录文件信息到后端(异步)
35           createFile(presignedInfo, fileName, options.file)
36           // 通知成功,数据格式保持与后端上传的返回结果一致
37           return { data: presignedInfo.url }
38         })
820397 39     } else {
H 40       // 模式二:后端上传
41       // 重写 el-upload httpRequest 文件上传成功会走成功的钩子,失败走失败的钩子
42       return new Promise((resolve, reject) => {
43         FileApi.updateFile({ file: options.file })
44           .then((res) => {
45             if (res.code === 0) {
46               resolve(res)
47             } else {
48               reject(res)
49             }
50           })
51           .catch((res) => {
52             reject(res)
53           })
54       })
55     }
56   }
57
58   return {
59     uploadUrl,
60     httpRequest
61   }
62 }
63
64 /**
65  * 创建文件信息
66  * @param vo 文件预签名信息
67  * @param name 文件名称
68  * @param file 文件
69  */
70 function createFile(vo: FileApi.FilePresignedUrlRespVO, name: string, file: UploadRawFile) {
71   const fileVo = {
72     configId: vo.configId,
73     url: vo.url,
74     path: name,
75     name: file.name,
76     type: file.type,
77     size: file.size
78   }
79   FileApi.createFile(fileVo)
80   return fileVo
81 }
82
83 /**
84  * 生成文件名称(使用算法SHA256)
85  * @param file 要上传的文件
86  */
87 async function generateFileName(file: UploadRawFile) {
88   // 读取文件内容
89   const data = await file.arrayBuffer()
90   const wordArray = CryptoJS.lib.WordArray.create(data)
91   // 计算SHA256
92   const sha256 = CryptoJS.SHA256(wordArray).toString()
93   // 拼接后缀
94   const ext = file.name.substring(file.name.lastIndexOf('.'))
95   return `${sha256}${ext}`
96 }
97
98 /**
99  * 上传类型
100  */
101 enum UPLOAD_TYPE {
102   // 客户端直接上传(只支持S3服务)
103   CLIENT = 'client',
104   // 客户端发送到后端上传
105   SERVER = 'server'
106 }