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