工作流表单+模型代码提交

This commit is contained in:
2024-05-09 14:18:39 +08:00
parent eeef608ccd
commit 06611f527a
266 changed files with 18227 additions and 22039 deletions

View File

@@ -0,0 +1,5 @@
import UploadImg from './src/UploadImg.vue'
import UploadImgs from './src/UploadImgs.vue'
import UploadFile from './src/UploadFile.vue'
export { UploadImg, UploadImgs, UploadFile }

View File

@@ -0,0 +1,214 @@
<template>
<div class='upload-file'>
<el-upload
ref='uploadRef'
v-model:file-list='fileList'
:action='uploadUrl'
:auto-upload='autoUpload'
:before-upload='beforeUpload'
:disabled='disabled'
:drag='drag'
:http-request='httpRequest'
:limit='props.limit'
:multiple='props.limit > 1'
:on-error='excelUploadError'
:on-exceed='handleExceed'
:on-preview='handlePreview'
:on-remove='handleRemove'
:on-success='handleFileSuccess'
:show-file-list='true'
class='upload-file-uploader'
name='file'
>
<el-button v-if='!disabled' type='primary'>
<UploadFilled />
选取文件
</el-button>
<template v-if='isShowTip && !disabled' #tip>
<div style='font-size: 8px'>
大小不超过 <b style='color: #f56c6c'>{{ fileSize }}MB</b>
</div>
<div style='font-size: 8px'>
格式为 <b style='color: #f56c6c'>{{ fileType.join('/') }}</b> 的文件
</div>
</template>
<template #file='row'>
<div class='flex items-center'>
<span>{{ row.file.name }}</span>
<div class='ml-10px'>
<el-link
:href='row.file.url'
:underline='false'
download
target='_blank'
type='primary'
>
下载
</el-link>
</div>
<div class='ml-10px'>
<el-button link type='danger' @click='handleRemove(row.file)'> 删除</el-button>
</div>
</div>
</template>
</el-upload>
</div>
</template>
<script lang='ts' setup>
import { propTypes } from '@/utils/propTypes'
import { UploadFilled } from '@element-plus/icons-vue'
import type { UploadInstance, UploadProps, UploadRawFile, UploadUserFile } from 'element-plus'
import { isString } from '@/utils/is'
import { useUpload } from '@/components/UploadFile/src/useUpload'
import { UploadFile } from 'element-plus/es/components/upload/src/upload'
defineOptions({ name: 'UploadFile' })
const message = useMessage() // 消息弹窗
const emit = defineEmits(['update:modelValue'])
const props = defineProps({
modelValue: propTypes.oneOfType<string | string[]>([String, Array<String>]).isRequired,
fileType: propTypes.array.def(['doc', 'xls', 'ppt', 'txt', 'pdf']), // 文件类型, 例如['png', 'jpg', 'jpeg']
fileSize: propTypes.number.def(5), // 大小限制(MB)
limit: propTypes.number.def(5), // 数量限制
autoUpload: propTypes.bool.def(true), // 自动上传
drag: propTypes.bool.def(false), // 拖拽上传
isShowTip: propTypes.bool.def(true), // 是否显示提示
disabled: propTypes.bool.def(false) // 是否禁用上传组件 ==> 非必传(默认为 false
})
// ========== 上传相关 ==========
const uploadRef = ref<UploadInstance>()
const uploadList = ref<UploadUserFile[]>([])
const fileList = ref<UploadUserFile[]>([])
const uploadNumber = ref<number>(0)
const { uploadUrl, httpRequest } = useUpload()
// 文件上传之前判断
const beforeUpload: UploadProps['beforeUpload'] = (file: UploadRawFile) => {
if (fileList.value.length >= props.limit) {
message.error(`上传文件数量不能超过${props.limit}个!`)
return false
}
let fileExtension = ''
if (file.name.lastIndexOf('.') > -1) {
fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1)
}
const isImg = props.fileType.some((type: string) => {
if (file.type.indexOf(type) > -1) return true
return !!(fileExtension && fileExtension.indexOf(type) > -1)
})
const isLimit = file.size < props.fileSize * 1024 * 1024
if (!isImg) {
message.error(`文件格式不正确, 请上传${props.fileType.join('/')}格式!`)
return false
}
if (!isLimit) {
message.error(`上传文件大小不能超过${props.fileSize}MB!`)
return false
}
message.success('正在上传文件,请稍候...')
uploadNumber.value++
}
// 处理上传的文件发生变化
// const handleFileChange = (uploadFile: UploadFile): void => {
// uploadRef.value.data.path = uploadFile.name
// }
// 文件上传成功
const handleFileSuccess: UploadProps['onSuccess'] = (res: any): void => {
message.success('上传成功')
// 删除自身
const index = fileList.value.findIndex((item) => item.response?.data === res.data)
fileList.value.splice(index, 1)
uploadList.value.push({ name: res.data, url: res.data })
if (uploadList.value.length == uploadNumber.value) {
fileList.value.push(...uploadList.value)
uploadList.value = []
uploadNumber.value = 0
emitUpdateModelValue()
}
}
// 文件数超出提示
const handleExceed: UploadProps['onExceed'] = (): void => {
message.error(`上传文件数量不能超过${props.limit}个!`)
}
// 上传错误提示
const excelUploadError: UploadProps['onError'] = (): void => {
message.error('导入数据失败,请您重新上传!')
}
// 删除上传文件
const handleRemove = (file: UploadFile) => {
const index = fileList.value.map((f) => f.name).indexOf(file.name)
if (index > -1) {
fileList.value.splice(index, 1)
emitUpdateModelValue()
}
}
const handlePreview: UploadProps['onPreview'] = (uploadFile) => {
console.log(uploadFile)
}
// 监听模型绑定值变动
watch(
() => props.modelValue,
(val: string | string[]) => {
if (!val) {
fileList.value = [] // fix处理掉缓存表单重置后上传组件的内容并没有重置
return
}
fileList.value = [] // 保障数据为空
// 情况1字符串
if (isString(val)) {
fileList.value.push(
...val.split(',').map((url) => ({ name: url.substring(url.lastIndexOf('/') + 1), url }))
)
return
}
// 情况2数组
fileList.value.push(
...(val as string[]).map((url) => ({ name: url.substring(url.lastIndexOf('/') + 1), url }))
)
},
{ immediate: true, deep: true }
)
// 发送文件链接列表更新
const emitUpdateModelValue = () => {
// 情况1数组结果
let result: string | string[] = fileList.value.map((file) => file.url!)
// 情况2逗号分隔的字符串
if (props.limit === 1 || isString(props.modelValue)) {
result = result.join(',')
}
emit('update:modelValue', result)
}
</script>
<style lang='scss' scoped>
.upload-file-uploader {
margin-bottom: 5px;
}
:deep(.upload-file-list .el-upload-list__item) {
position: relative;
margin-bottom: 10px;
line-height: 2;
border: 1px solid #e4e7ed;
}
:deep(.el-upload-list__item-file-name) {
max-width: 250px;
}
:deep(.upload-file-list .ele-upload-list__item-content) {
display: flex;
justify-content: space-between;
align-items: center;
color: inherit;
}
:deep(.ele-upload-list__item-content-action .el-link) {
margin-right: 10px;
}
</style>

View File

@@ -0,0 +1,273 @@
<template>
<div class='upload-box'>
<el-upload
:id='uuid'
:accept="fileType.join(',')"
:action='uploadUrl'
:before-upload='beforeUpload'
:class="['upload', drag ? 'no-border' : '']"
:disabled='disabled'
:drag='drag'
:http-request='httpRequest'
:multiple='false'
:on-error='uploadError'
:on-success='uploadSuccess'
:show-file-list='false'
>
<template v-if='modelValue'>
<img :src='modelValue' class='upload-image' />
<div class='upload-handle' @click.stop>
<div v-if='!disabled' class='handle-icon' @click='editImg'>
<Edit />
<span v-if='showBtnText'>{{ t('action.edit') }}</span>
</div>
<div class='handle-icon' @click='imagePreview(modelValue)'>
<ZoomIn />
<span v-if='showBtnText'>{{ t('action.detail') }}</span>
</div>
<div v-if='showDelete && !disabled' class='handle-icon' @click='deleteImg'>
<Delete />
<span v-if='showBtnText'>{{ t('action.del') }}</span>
</div>
</div>
</template>
<template v-else>
<div class='upload-empty'>
<slot name='empty'>
<Plus />
<!-- <span>请上传图片</span> -->
</slot>
</div>
</template>
</el-upload>
<div class='el-upload__tip'>
<slot name='tip'></slot>
</div>
</div>
</template>
<script lang='ts' setup>
import type { UploadProps } from 'element-plus'
import { Plus,Edit,ZoomIn,Delete} from '@element-plus/icons-vue'
import { generateUUID } from '@/utils'
import { propTypes } from '@/utils/propTypes'
import { createImageViewer } from '@/components/ImageViewer'
import { useUpload } from '@/components/UploadFile/src/useUpload'
import { useI18n } from '@/hooks/web/useI18n'
import { useMessage } from '@/hooks/web/useMessage'
defineOptions({ name: 'UploadImg' })
type FileTypes =
| 'image/apng'
| 'image/bmp'
| 'image/gif'
| 'image/jpeg'
| 'image/pjpeg'
| 'image/png'
| 'image/svg+xml'
| 'image/tiff'
| 'image/webp'
| 'image/x-icon'
// 接受父组件参数
const props = defineProps({
modelValue: propTypes.string.def(''),
drag: propTypes.bool.def(true), // 是否支持拖拽上传 ==> 非必传(默认为 true
disabled: propTypes.bool.def(false), // 是否禁用上传组件 ==> 非必传(默认为 false
fileSize: propTypes.number.def(5), // 图片大小限制 ==> 非必传(默认为 5M
fileType: propTypes.array.def(['image/jpeg', 'image/png', 'image/gif']), // 图片类型限制 ==> 非必传(默认为 ["image/jpeg", "image/png", "image/gif"]
height: propTypes.string.def('150px'), // 组件高度 ==> 非必传(默认为 150px
width: propTypes.string.def('150px'), // 组件宽度 ==> 非必传(默认为 150px
borderradius: propTypes.string.def('8px'), // 组件边框圆角 ==> 非必传(默认为 8px
showDelete: propTypes.bool.def(true), // 是否显示删除按钮
showBtnText: propTypes.bool.def(true) // 是否显示按钮文字
})
const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗
// 生成组件唯一id
const uuid = ref('id-' + generateUUID())
// 查看图片
const imagePreview = (imgUrl: string) => {
createImageViewer({
zIndex: 9999999,
urlList: [imgUrl]
})
}
const emit = defineEmits(['update:modelValue'])
const deleteImg = () => {
emit('update:modelValue', '')
}
const { uploadUrl, httpRequest } = useUpload()
const editImg = () => {
const dom = document.querySelector(`#${uuid.value} .el-upload__input`)
dom && dom.dispatchEvent(new MouseEvent('click'))
}
const beforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
const imgSize = rawFile.size / 1024 / 1024 < props.fileSize
const imgType = props.fileType
if (!imgType.includes(rawFile.type as FileTypes))
message.notifyWarning('上传图片不符合所需的格式!')
if (!imgSize) message.notifyWarning(`上传图片大小不能超过 ${props.fileSize}M`)
return imgType.includes(rawFile.type as FileTypes) && imgSize
}
// 图片上传成功提示
const uploadSuccess: UploadProps['onSuccess'] = (res: any): void => {
message.success('上传成功')
emit('update:modelValue', res.data)
}
// 图片上传错误提示
const uploadError = () => {
message.notifyError('图片上传失败,请您重新上传!')
}
</script>
<style lang='scss' scoped>
.is-error {
.upload {
:deep(.el-upload),
:deep(.el-upload-dragger) {
border: 1px dashed var(--el-color-danger) !important;
&:hover {
border-color: var(--el-color-primary) !important;
}
}
}
}
:deep(.disabled) {
.el-upload,
.el-upload-dragger {
cursor: not-allowed !important;
background: var(--el-disabled-bg-color);
border: 1px dashed var(--el-border-color-darker) !important;
&:hover {
border: 1px dashed var(--el-border-color-darker) !important;
}
}
}
.upload-box {
.no-border {
:deep(.el-upload) {
border: none !important;
}
}
:deep(.upload) {
.el-upload {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: v-bind(width);
height: v-bind(height);
overflow: hidden;
border: 1px dashed var(--el-border-color-darker);
border-radius: v-bind(borderradius);
transition: var(--el-transition-duration-fast);
&:hover {
border-color: var(--el-color-primary);
.upload-handle {
opacity: 1;
}
}
.el-upload-dragger {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
padding: 0;
overflow: hidden;
background-color: transparent;
border: 1px dashed var(--el-border-color-darker);
border-radius: v-bind(borderradius);
&:hover {
border: 1px dashed var(--el-color-primary);
}
}
.el-upload-dragger.is-dragover {
background-color: var(--el-color-primary-light-9);
border: 2px dashed var(--el-color-primary) !important;
}
.upload-image {
width: 100%;
height: 100%;
object-fit: contain;
}
.upload-empty {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 12px;
line-height: 30px;
color: var(--el-color-info);
.el-icon {
font-size: 28px;
color: var(--el-text-color-secondary);
}
}
.upload-handle {
position: absolute;
top: 0;
right: 0;
display: flex;
width: 100%;
height: 100%;
cursor: pointer;
background: rgb(0 0 0 / 60%);
opacity: 0;
box-sizing: border-box;
transition: var(--el-transition-duration-fast);
align-items: center;
justify-content: center;
.handle-icon {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 0 6%;
color: aliceblue;
.el-icon {
margin-bottom: 40%;
font-size: 130%;
line-height: 130%;
}
span {
font-size: 85%;
line-height: 85%;
}
}
}
}
}
.el-upload__tip {
line-height: 18px;
text-align: center;
}
}
</style>

View File

@@ -0,0 +1,324 @@
<template>
<div class='upload-box'>
<el-upload
v-model:file-list='fileList'
:accept="fileType.join(',')"
:action='uploadUrl'
:before-upload='beforeUpload'
:class="['upload', drag ? 'no-border' : '']"
:disabled='disabled'
:drag='drag'
:http-request='httpRequest'
:limit='limit'
:multiple='true'
:on-error='uploadError'
:on-exceed='handleExceed'
:on-success='uploadSuccess'
list-type='picture-card'
>
<div class='upload-empty'>
<slot name='empty'>
<Plus />
<!-- <span>请上传图片</span> -->
</slot>
</div>
<template #file='{ file }'>
<img :src='file.url' class='upload-image' />
<div class='upload-handle' @click.stop>
<div class='handle-icon' @click='handlePictureCardPreview(file)'>
<ZoomIn />
<span>查看</span>
</div>
<div v-if='!disabled' class='handle-icon' @click='handleRemove(file)'>
<Delete />
<span>删除</span>
</div>
</div>
</template>
</el-upload>
<div class='el-upload__tip'>
<slot name='tip'></slot>
</div>
<el-image-viewer
v-if='imgViewVisible'
:url-list='[viewImageUrl]'
@close='imgViewVisible = false'
/>
</div>
</template>
<script lang='ts' setup>
import type { UploadFile, UploadProps, UploadUserFile } from 'element-plus'
import { ElNotification } from 'element-plus'
import { propTypes } from '@/utils/propTypes'
import { useUpload } from '@/components/UploadFile/src/useUpload'
import { Plus, Edit, ZoomIn, Delete } from '@element-plus/icons-vue'
defineOptions({ name: 'UploadImgs' })
const message = useMessage() // 消息弹窗
type FileTypes =
| 'image/apng'
| 'image/bmp'
| 'image/gif'
| 'image/jpeg'
| 'image/pjpeg'
| 'image/png'
| 'image/svg+xml'
| 'image/tiff'
| 'image/webp'
| 'image/x-icon'
const props = defineProps({
modelValue: propTypes.oneOfType<string | string[]>([String, Array<String>]).isRequired,
drag: propTypes.bool.def(true), // 是否支持拖拽上传 ==> 非必传(默认为 true
disabled: propTypes.bool.def(false), // 是否禁用上传组件 ==> 非必传(默认为 false
limit: propTypes.number.def(5), // 最大图片上传数 ==> 非必传(默认为 5张
fileSize: propTypes.number.def(5), // 图片大小限制 ==> 非必传(默认为 5M
fileType: propTypes.array.def(['image/jpeg', 'image/png', 'image/gif']), // 图片类型限制 ==> 非必传(默认为 ["image/jpeg", "image/png", "image/gif"]
height: propTypes.string.def('150px'), // 组件高度 ==> 非必传(默认为 150px
width: propTypes.string.def('150px'), // 组件宽度 ==> 非必传(默认为 150px
borderradius: propTypes.string.def('8px') // 组件边框圆角 ==> 非必传(默认为 8px
})
const { uploadUrl, httpRequest } = useUpload()
const fileList = ref<UploadUserFile[]>([])
const uploadNumber = ref<number>(0)
const uploadList = ref<UploadUserFile[]>([])
/**
* @description 文件上传之前判断
* @param rawFile 上传的文件
* */
const beforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
const imgSize = rawFile.size / 1024 / 1024 < props.fileSize
const imgType = props.fileType
if (!imgType.includes(rawFile.type as FileTypes))
ElNotification({
title: '温馨提示',
message: '上传图片不符合所需的格式!',
type: 'warning'
})
if (!imgSize)
ElNotification({
title: '温馨提示',
message: `上传图片大小不能超过 ${props.fileSize}M`,
type: 'warning'
})
uploadNumber.value++
return imgType.includes(rawFile.type as FileTypes) && imgSize
}
// 图片上传成功
interface UploadEmits {
(e: 'update:modelValue', value: string[]): void
}
const emit = defineEmits<UploadEmits>()
const uploadSuccess: UploadProps['onSuccess'] = (res: any): void => {
message.success('上传成功')
// 删除自身
const index = fileList.value.findIndex((item) => item.response?.data === res.data)
fileList.value.splice(index, 1)
uploadList.value.push({ name: res.data, url: res.data })
if (uploadList.value.length == uploadNumber.value) {
fileList.value.push(...uploadList.value)
uploadList.value = []
uploadNumber.value = 0
emitUpdateModelValue()
}
}
// 监听模型绑定值变动
watch(
() => props.modelValue,
(val: string | string[]) => {
if (!val) {
fileList.value = [] // fix处理掉缓存表单重置后上传组件的内容并没有重置
return
}
fileList.value = [] // 保障数据为空
fileList.value.push(
...(val as string[]).map((url) => ({ name: url.substring(url.lastIndexOf('/') + 1), url }))
)
},
{ immediate: true, deep: true }
)
// 发送图片链接列表更新
const emitUpdateModelValue = () => {
let result: string[] = fileList.value.map((file) => file.url!)
emit('update:modelValue', result)
}
// 删除图片
const handleRemove = (uploadFile: UploadFile) => {
fileList.value = fileList.value.filter(
(item) => item.url !== uploadFile.url || item.name !== uploadFile.name
)
emit(
'update:modelValue',
fileList.value.map((file) => file.url!)
)
}
// 图片上传错误提示
const uploadError = () => {
ElNotification({
title: '温馨提示',
message: '图片上传失败,请您重新上传!',
type: 'error'
})
}
// 文件数超出提示
const handleExceed = () => {
ElNotification({
title: '温馨提示',
message: `当前最多只能上传 ${props.limit} 张图片,请移除后上传!`,
type: 'warning'
})
}
// 图片预览
const viewImageUrl = ref('')
const imgViewVisible = ref(false)
const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
viewImageUrl.value = uploadFile.url!
imgViewVisible.value = true
}
</script>
<style lang='scss' scoped>
.is-error {
.upload {
:deep(.el-upload--picture-card),
:deep(.el-upload-dragger) {
border: 1px dashed var(--el-color-danger) !important;
&:hover {
border-color: var(--el-color-primary) !important;
}
}
}
}
:deep(.disabled) {
.el-upload--picture-card,
.el-upload-dragger {
cursor: not-allowed;
background: var(--el-disabled-bg-color) !important;
border: 1px dashed var(--el-border-color-darker);
&:hover {
border-color: var(--el-border-color-darker) !important;
}
}
}
.upload-box {
.no-border {
:deep(.el-upload--picture-card) {
border: none !important;
}
}
:deep(.upload) {
.el-upload-dragger {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
padding: 0;
overflow: hidden;
border: 1px dashed var(--el-border-color-darker);
border-radius: v-bind(borderradius);
&:hover {
border: 1px dashed var(--el-color-primary);
}
}
.el-upload-dragger.is-dragover {
background-color: var(--el-color-primary-light-9);
border: 2px dashed var(--el-color-primary) !important;
}
.el-upload-list__item,
.el-upload--picture-card {
width: v-bind(width);
height: v-bind(height);
background-color: transparent;
border-radius: v-bind(borderradius);
}
.upload-image {
width: 100%;
height: 100%;
object-fit: contain;
}
.upload-handle {
position: absolute;
top: 0;
right: 0;
display: flex;
width: 100%;
height: 100%;
cursor: pointer;
background: rgb(0 0 0 / 60%);
opacity: 0;
box-sizing: border-box;
transition: var(--el-transition-duration-fast);
align-items: center;
justify-content: center;
.handle-icon {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 0 6%;
color: aliceblue;
.el-icon {
margin-bottom: 15%;
font-size: 140%;
}
span {
font-size: 100%;
}
}
}
.el-upload-list__item {
&:hover {
.upload-handle {
opacity: 1;
}
}
}
.upload-empty {
display: flex;
flex-direction: column;
align-items: center;
font-size: 12px;
line-height: 30px;
color: var(--el-color-info);
.el-icon {
font-size: 28px;
color: var(--el-text-color-secondary);
}
}
}
.el-upload__tip {
line-height: 15px;
text-align: center;
}
}
</style>

View File

@@ -0,0 +1,99 @@
// import * as FileApi from '@/api/infra/file'
import CryptoJS from 'crypto-js'
import { UploadRawFile, UploadRequestOptions } from 'element-plus/es/components/upload/src/upload'
import axios from 'axios'
import { uploadFile } from '@/api/system-boot/file'
export const useUpload = () => {
// 后端上传地址
const uploadUrl = 'import.meta.env.VITE_UPLOAD_URL'
// // 是否使用前端直连上传
// const isClientUpload = UPLOAD_TYPE.CLIENT === import.meta.env.VITE_UPLOAD_TYPE
const isClientUpload = false
// 重写ElUpload上传方法
const httpRequest = async (options: UploadRequestOptions) => {
// 模式一:前端上传
// if (isClientUpload) {
// // 1.1 生成文件名称
// const fileName = await generateFileName(options.file)
// // 1.2 获取文件预签名地址
// const presignedInfo = await FileApi.getFilePresignedUrl(fileName)
// // 1.3 上传文件(不能使用 ElUpload 的 ajaxUpload 方法的原因:其使用的是 FormData 上传Minio 不支持)
// return axios.put(presignedInfo.uploadUrl, options.file, {
// headers: {
// 'Content-Type': options.file.type,
// }
// }).then(() => {
// // 1.4. 记录文件信息到后端(异步)
// createFile(presignedInfo, fileName, options.file)
// // 通知成功,数据格式保持与后端上传的返回结果一致
// return { data: presignedInfo.url }
// })
// } else {
// 模式二:后端上传
// 重写 el-upload httpRequest 文件上传成功会走成功的钩子,失败走失败的钩子
return new Promise((resolve, reject) => {
uploadFile({ file: options.file, path: 'backUpFile' })
.then((res) => {
if (res.code === 0) {
resolve(res)
} else {
reject(res)
}
})
.catch((res) => {
reject(res)
})
})
// }
}
return {
uploadUrl,
httpRequest
}
}
/**
* 创建文件信息
* @param vo 文件预签名信息
* @param name 文件名称
* @param file 文件
*/
function createFile(vo: FileApi.FilePresignedUrlRespVO, name: string, file: UploadRawFile) {
const fileVo = {
configId: vo.configId,
url: vo.url,
path: name,
name: file.name,
type: file.type,
size: file.size
}
FileApi.createFile(fileVo)
return fileVo
}
/**
* 生成文件名称使用算法SHA256
* @param file 要上传的文件
*/
async function generateFileName(file: UploadRawFile) {
// 读取文件内容
const data = await file.arrayBuffer()
const wordArray = CryptoJS.lib.WordArray.create(data)
// 计算SHA256
const sha256 = CryptoJS.SHA256(wordArray).toString()
// 拼接后缀
const ext = file.name.substring(file.name.lastIndexOf('.'))
return `${sha256}${ext}`
}
/**
* 上传类型
*/
enum UPLOAD_TYPE {
// 客户端直接上传只支持S3服务
CLIENT = 'client',
// 客户端发送到后端上传
SERVER = 'server'
}