| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- <template>
- <div class="app-upload">
- <el-upload ref="uploadRef" :headers="headers" :accept="acceptTypes.join(',')" v-model:file-list="fileList"
- :limit="limit" :multiple="limit > 1" :action="uploadUrl" :before-upload="onBeforeUpload"
- :on-success="onSuccess" :on-preview="onPreview" :on-exceed="onExceed" :on-change="onChange">
- <template #tip>
- <div class="el-upload__tip">
- <slot name="tip"></slot>
- </div>
- </template>
- <slot>
- <el-button type="primary">{{ t('operation.upload') }}</el-button>
- </slot>
- </el-upload>
- <el-image-viewer :url-list="imageList" :initial-index="imageIndex" @close="onViewerClose" v-if="showViewer"
- teleported />
- </div>
- </template>
- <script lang="ts" setup>
- import { shallowRef, shallowReactive, computed, PropType, onMounted } from 'vue'
- import { ElMessage, UploadProps, UploadRawFile, UploadUserFile, UploadFile, UploadFiles, UploadInstance, genFileId } from 'element-plus'
- import { i18n, useLoginStore } from '@/stores'
- import { localData } from '@/stores/storage'
- import service from '@/services'
- import cryptojs from 'crypto-js'
- const props = defineProps({
- modelValue: {
- type: Array as PropType<UploadUserFile[]>,
- default: () => ([])
- },
- fileTypes: {
- type: Array as PropType<readonly ('image' | 'pdf' | 'word' | 'excel')[]>,
- default: () => ([])
- },
- limit: {
- type: Number,
- default: 1
- },
- maxSize: {
- type: Number,
- default: 0
- },
- typeMessage: {
- type: String,
- default: '请选择正确的文件类型'
- }
- })
- const { global: { t } } = i18n
- const emit = defineEmits(['update:modelValue', 'change'])
- const fileList = computed({
- get: () => props.modelValue,
- set: (val) => emit('update:modelValue', val)
- })
- const uploadUrl = service.getConfig('apiUrl') + '/common/uploadFile'
- const uploadRef = shallowRef<UploadInstance>()
- const showViewer = shallowRef(false)
- const acceptTypes = shallowReactive<string[]>([]) // 接受上传的文件类型
- const uploadTypes = shallowReactive<string[]>([]) // 允许上传的文件类型
- const imageIndex = shallowRef(0)
- const imageTypes = ['image/png', 'image/jpeg']
- const loginStore = useLoginStore()
- const timestamp = new Date().getTime()
- const headers = {
- 'Accept-Language': localData.getValue('appLanguage'),
- 'Sign-Id': loginStore.signId,
- Sign: cryptojs.SHA256(loginStore.sign + timestamp.toString()).toString(),
- Authorization: loginStore.token,
- Timestamp: timestamp.toString(),
- }
- // 预览图列表
- const imageList = computed(() => {
- return fileList.value.reduce<string[]>((pre, { url, raw }) => {
- // 判断是否图片类型
- if (url && raw && imageTypes.includes(raw.type)) {
- pre.push(url)
- }
- return pre
- }, [])
- })
- const onSuccess = (response: { code: number }, uploadFile: UploadFile) => {
- const { url, raw } = uploadFile
- if (response.code === 200) {
- if (!url && raw) {
- uploadFile.url = URL.createObjectURL(raw)
- }
- } else {
- fileList.value.pop()
- }
- }
- const onChange = (uploadFile: UploadFile, uploadFiles: UploadFiles) => {
- emit('change', uploadFile, uploadFiles)
- }
- // 当超出限制时的回调
- const onExceed = (files: File[]) => {
- if (props.limit === 1) {
- const el = uploadRef.value
- if (el) {
- const rawFile = files[0] as UploadRawFile
- if (!uploadTypes.length || uploadTypes.includes(rawFile.type)) {
- rawFile.uid = genFileId()
- el.clearFiles()
- el.handleStart(rawFile)
- el.submit()
- } else {
- ElMessage.warning(props.typeMessage)
- }
- }
- } else {
- ElMessage.warning(`最多只能上传${props.limit}个文件`)
- }
- }
- // 上传之前判断文件类型
- const onBeforeUpload = (rawFile: UploadRawFile) => {
- if (!uploadTypes.length || uploadTypes.includes(rawFile.type)) {
- return true
- }
- ElMessage.warning(props.typeMessage)
- return false
- }
- // 打开预览图
- const onPreview: UploadProps['onPreview'] = ({ url }: UploadFile) => {
- const index = imageList.value.findIndex((val) => val === url)
- if (index > -1) {
- imageIndex.value = index
- showViewer.value = true
- } else {
- window.open(url, '_blank')
- }
- }
- const onViewerClose = () => {
- showViewer.value = false
- }
- onMounted(() => {
- props.fileTypes.forEach((value) => {
- switch (value) {
- case 'image': {
- acceptTypes.push('.jpg', '.jpeg', '.png')
- uploadTypes.push(...imageTypes)
- break
- }
- case 'pdf': {
- acceptTypes.push('.pdf')
- uploadTypes.push('application/pdf')
- break
- }
- case 'word': {
- acceptTypes.push('.doc', '.docx')
- uploadTypes.push('application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document')
- break
- }
- case 'excel': {
- acceptTypes.push('.xls', '.xlsx')
- uploadTypes.push('application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
- break
- }
- }
- })
- })
- </script>
- <style lang="less">
- @import './index.less';
- </style>
|