mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-03 03:38:43 +08:00 
			
		
		
		
	feat: add upload component
This commit is contained in:
		@@ -21,6 +21,7 @@ import {
 | 
			
		||||
} from 'element-plus'
 | 
			
		||||
import { InputPassword } from '@/components/InputPassword'
 | 
			
		||||
import { Editor } from '@/components/Editor'
 | 
			
		||||
import { UploadImg, UploadFile } from '@/components/UploadFile'
 | 
			
		||||
import { ComponentName } from '@/types/components'
 | 
			
		||||
 | 
			
		||||
const componentMap: Recordable<Component, ComponentName> = {
 | 
			
		||||
@@ -45,7 +46,9 @@ const componentMap: Recordable<Component, ComponentName> = {
 | 
			
		||||
  TreeSelect: ElTreeSelect,
 | 
			
		||||
  RadioButton: ElRadioGroup,
 | 
			
		||||
  InputPassword: InputPassword,
 | 
			
		||||
  Editor: Editor
 | 
			
		||||
  Editor: Editor,
 | 
			
		||||
  UploadImg: UploadImg,
 | 
			
		||||
  UploadFile: UploadFile
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export { componentMap }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
import UploadImg from './src/UploadImg.vue'
 | 
			
		||||
import UploadFile from './src/UploadFile.vue'
 | 
			
		||||
 | 
			
		||||
export { UploadImg }
 | 
			
		||||
export { UploadImg, UploadFile }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										167
									
								
								yudao-ui-admin-vue3/src/components/UploadFile/src/UploadFile.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								yudao-ui-admin-vue3/src/components/UploadFile/src/UploadFile.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,167 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="upload-file">
 | 
			
		||||
    <el-upload
 | 
			
		||||
      ref="uploadRef"
 | 
			
		||||
      :multiple="props.limit > 1"
 | 
			
		||||
      name="file"
 | 
			
		||||
      v-model="valueRef"
 | 
			
		||||
      :file-list="fileList"
 | 
			
		||||
      :show-file-list="false"
 | 
			
		||||
      :action="updateUrl"
 | 
			
		||||
      :headers="uploadHeaders"
 | 
			
		||||
      :limit="props.limit"
 | 
			
		||||
      :before-upload="beforeUpload"
 | 
			
		||||
      :on-exceed="handleExceed"
 | 
			
		||||
      :on-success="handleFileSuccess"
 | 
			
		||||
      :on-error="excelUploadError"
 | 
			
		||||
      :on-remove="handleRemove"
 | 
			
		||||
      class="upload-file-uploader"
 | 
			
		||||
    >
 | 
			
		||||
      <Icon icon="ep:upload-filled" />
 | 
			
		||||
    </el-upload>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { ref, watch } from 'vue'
 | 
			
		||||
import { useMessage } from '@/hooks/web/useMessage'
 | 
			
		||||
import { propTypes } from '@/utils/propTypes'
 | 
			
		||||
import { getAccessToken, getTenantId } from '@/utils/auth'
 | 
			
		||||
import { ElUpload, UploadInstance, UploadProps, UploadRawFile, UploadUserFile } from 'element-plus'
 | 
			
		||||
 | 
			
		||||
const message = useMessage() // 消息弹窗
 | 
			
		||||
const emit = defineEmits(['update:modelValue'])
 | 
			
		||||
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
  modelValue: propTypes.oneOfType([String, Object, Array]),
 | 
			
		||||
  title: propTypes.string.def('文件上传'),
 | 
			
		||||
  updateUrl: propTypes.string.def(import.meta.env.VITE_UPLOAD_URL),
 | 
			
		||||
  fileType: propTypes.array.def(['doc', 'xls', 'ppt', 'txt', 'pdf']), // 文件类型, 例如['png', 'jpg', 'jpeg']
 | 
			
		||||
  fileSize: propTypes.number.def(5), // 大小限制(MB)
 | 
			
		||||
  limit: propTypes.number.def(5), // 数量限制
 | 
			
		||||
  isShowTip: propTypes.bool.def(false) // 是否显示提示
 | 
			
		||||
})
 | 
			
		||||
// ========== 上传相关 ==========
 | 
			
		||||
const valueRef = ref(props.modelValue)
 | 
			
		||||
const uploadRef = ref<UploadInstance>()
 | 
			
		||||
const uploadList = ref<UploadUserFile[]>([])
 | 
			
		||||
const fileList = ref<UploadUserFile[]>([])
 | 
			
		||||
const uploadNumber = ref<number>(0)
 | 
			
		||||
const uploadHeaders = ref({
 | 
			
		||||
  Authorization: 'Bearer ' + getAccessToken(),
 | 
			
		||||
  'tenant-id': getTenantId()
 | 
			
		||||
})
 | 
			
		||||
watch(
 | 
			
		||||
  () => props.modelValue,
 | 
			
		||||
  (val) => {
 | 
			
		||||
    if (val) {
 | 
			
		||||
      // 首先将值转为数组, 当只穿了一个图片时,会报map方法错误
 | 
			
		||||
      const list = Array.isArray(props.modelValue)
 | 
			
		||||
        ? props.modelValue
 | 
			
		||||
        : Array.isArray(props.modelValue?.split(','))
 | 
			
		||||
        ? props.modelValue?.split(',')
 | 
			
		||||
        : Array.of(props.modelValue)
 | 
			
		||||
      // 然后将数组转为对象数组
 | 
			
		||||
      fileList.value = list.map((item) => {
 | 
			
		||||
        if (typeof item === 'string') {
 | 
			
		||||
          // edit by 芋道源码
 | 
			
		||||
          item = { name: item, url: item }
 | 
			
		||||
        }
 | 
			
		||||
        return item
 | 
			
		||||
      })
 | 
			
		||||
    } else {
 | 
			
		||||
      fileList.value = []
 | 
			
		||||
      return []
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    deep: true,
 | 
			
		||||
    immediate: true
 | 
			
		||||
  }
 | 
			
		||||
)
 | 
			
		||||
// 文件上传之前判断
 | 
			
		||||
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('上传成功')
 | 
			
		||||
  uploadList.value.push({ name: res.data, url: res.data })
 | 
			
		||||
  if (uploadList.value.length == uploadNumber.value) {
 | 
			
		||||
    fileList.value = fileList.value.concat(uploadList.value)
 | 
			
		||||
    uploadList.value = []
 | 
			
		||||
    uploadNumber.value = 0
 | 
			
		||||
    emit('update:modelValue', listToString(fileList.value))
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
// 文件数超出提示
 | 
			
		||||
const handleExceed: UploadProps['onExceed'] = (): void => {
 | 
			
		||||
  message.error(`上传文件数量不能超过${props.limit}个!`)
 | 
			
		||||
}
 | 
			
		||||
// 上传错误提示
 | 
			
		||||
const excelUploadError: UploadProps['onError'] = (): void => {
 | 
			
		||||
  message.error('导入数据失败,请您重新上传!')
 | 
			
		||||
}
 | 
			
		||||
// 删除上传文件
 | 
			
		||||
const handleRemove = (file) => {
 | 
			
		||||
  const findex = fileList.value.map((f) => f.name).indexOf(file.name)
 | 
			
		||||
  if (findex > -1) {
 | 
			
		||||
    fileList.value.splice(findex, 1)
 | 
			
		||||
    emit('update:modelValue', listToString(fileList.value))
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
// 对象转成指定字符串分隔
 | 
			
		||||
const listToString = (list: UploadUserFile[], separator?: string) => {
 | 
			
		||||
  let strs = ''
 | 
			
		||||
  separator = separator || ','
 | 
			
		||||
  for (let i in list) {
 | 
			
		||||
    strs += list[i].url + separator
 | 
			
		||||
  }
 | 
			
		||||
  return strs != '' ? strs.substr(0, strs.length - 1) : ''
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.upload-file-uploader {
 | 
			
		||||
  margin-bottom: 5px;
 | 
			
		||||
}
 | 
			
		||||
.upload-file-list .el-upload-list__item {
 | 
			
		||||
  border: 1px solid #e4e7ed;
 | 
			
		||||
  line-height: 2;
 | 
			
		||||
  margin-bottom: 10px;
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
.upload-file-list .ele-upload-list__item-content {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  color: inherit;
 | 
			
		||||
}
 | 
			
		||||
.ele-upload-list__item-content-action .el-link {
 | 
			
		||||
  margin-right: 10px;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
@@ -1,24 +1,27 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <el-upload
 | 
			
		||||
    ref="uploadRef"
 | 
			
		||||
    :multiple="limit > 1"
 | 
			
		||||
    name="file"
 | 
			
		||||
    list-type="picture-card"
 | 
			
		||||
    v-model:file-list="fileList"
 | 
			
		||||
    :show-file-list="true"
 | 
			
		||||
    :action="updateUrl"
 | 
			
		||||
    :headers="uploadHeaders"
 | 
			
		||||
    :limit="limit"
 | 
			
		||||
    :before-upload="beforeUpload"
 | 
			
		||||
    :on-exceed="handleExceed"
 | 
			
		||||
    :on-success="handleFileSuccess"
 | 
			
		||||
    :on-error="excelUploadError"
 | 
			
		||||
    :on-remove="handleRemove"
 | 
			
		||||
    :on-preview="handlePictureCardPreview"
 | 
			
		||||
    :class="{ hide: fileList.length >= limit }"
 | 
			
		||||
  >
 | 
			
		||||
    <Icon icon="ep:upload-filled" />
 | 
			
		||||
  </el-upload>
 | 
			
		||||
  <div class="component-upload-image">
 | 
			
		||||
    <el-upload
 | 
			
		||||
      ref="uploadRef"
 | 
			
		||||
      :multiple="props.limit > 1"
 | 
			
		||||
      name="file"
 | 
			
		||||
      v-model="valueRef"
 | 
			
		||||
      list-type="picture-card"
 | 
			
		||||
      :file-list="fileList"
 | 
			
		||||
      :show-file-list="true"
 | 
			
		||||
      :action="updateUrl"
 | 
			
		||||
      :headers="uploadHeaders"
 | 
			
		||||
      :limit="props.limit"
 | 
			
		||||
      :before-upload="beforeUpload"
 | 
			
		||||
      :on-exceed="handleExceed"
 | 
			
		||||
      :on-success="handleFileSuccess"
 | 
			
		||||
      :on-error="excelUploadError"
 | 
			
		||||
      :on-remove="handleRemove"
 | 
			
		||||
      :on-preview="handlePictureCardPreview"
 | 
			
		||||
      :class="{ hide: fileList.length >= props.limit }"
 | 
			
		||||
    >
 | 
			
		||||
      <Icon icon="ep:upload-filled" />
 | 
			
		||||
    </el-upload>
 | 
			
		||||
  </div>
 | 
			
		||||
  <!-- 文件列表 -->
 | 
			
		||||
  <Dialog v-model="dialogVisible" title="预览" width="800" append-to-body>
 | 
			
		||||
    <img :src="dialogImageUrl" style="display: block; max-width: 100%; margin: 0 auto" />
 | 
			
		||||
@@ -32,10 +35,10 @@ import { getAccessToken, getTenantId } from '@/utils/auth'
 | 
			
		||||
import { ElUpload, UploadInstance, UploadProps, UploadRawFile, UploadUserFile } from 'element-plus'
 | 
			
		||||
 | 
			
		||||
const message = useMessage() // 消息弹窗
 | 
			
		||||
const emit = defineEmits(['input'])
 | 
			
		||||
const emit = defineEmits(['update:modelValue'])
 | 
			
		||||
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
  imgs: propTypes.oneOfType([String, Object, Array]),
 | 
			
		||||
  modelValue: propTypes.oneOfType([String, Object, Array]),
 | 
			
		||||
  title: propTypes.string.def('图片上传'),
 | 
			
		||||
  updateUrl: propTypes.string.def(import.meta.env.VITE_UPLOAD_URL),
 | 
			
		||||
  fileType: propTypes.array.def(['jpg', 'png', 'gif', 'jpeg']), // 文件类型, 例如['png', 'jpg', 'jpeg']
 | 
			
		||||
@@ -44,6 +47,7 @@ const props = defineProps({
 | 
			
		||||
  isShowTip: propTypes.bool.def(false) // 是否显示提示
 | 
			
		||||
})
 | 
			
		||||
// ========== 上传相关 ==========
 | 
			
		||||
const valueRef = ref(props.modelValue)
 | 
			
		||||
const uploadRef = ref<UploadInstance>()
 | 
			
		||||
const uploadList = ref<UploadUserFile[]>([])
 | 
			
		||||
const fileList = ref<UploadUserFile[]>([])
 | 
			
		||||
@@ -55,15 +59,15 @@ const uploadHeaders = ref({
 | 
			
		||||
  'tenant-id': getTenantId()
 | 
			
		||||
})
 | 
			
		||||
watch(
 | 
			
		||||
  () => props.imgs,
 | 
			
		||||
  () => props.modelValue,
 | 
			
		||||
  (val) => {
 | 
			
		||||
    if (val) {
 | 
			
		||||
      // 首先将值转为数组, 当只穿了一个图片时,会报map方法错误
 | 
			
		||||
      const list = Array.isArray(props.imgs)
 | 
			
		||||
        ? props.imgs
 | 
			
		||||
        : Array.isArray(props.imgs?.split(','))
 | 
			
		||||
        ? props.imgs?.split(',')
 | 
			
		||||
        : Array.of(props.imgs)
 | 
			
		||||
      const list = Array.isArray(props.modelValue)
 | 
			
		||||
        ? props.modelValue
 | 
			
		||||
        : Array.isArray(props.modelValue?.split(','))
 | 
			
		||||
        ? props.modelValue?.split(',')
 | 
			
		||||
        : Array.of(props.modelValue)
 | 
			
		||||
      // 然后将数组转为对象数组
 | 
			
		||||
      fileList.value = list.map((item) => {
 | 
			
		||||
        if (typeof item === 'string') {
 | 
			
		||||
@@ -84,6 +88,10 @@ watch(
 | 
			
		||||
)
 | 
			
		||||
// 文件上传之前判断
 | 
			
		||||
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)
 | 
			
		||||
@@ -111,14 +119,12 @@ const beforeUpload: UploadProps['beforeUpload'] = (file: UploadRawFile) => {
 | 
			
		||||
// 文件上传成功
 | 
			
		||||
const handleFileSuccess: UploadProps['onSuccess'] = (res: any): void => {
 | 
			
		||||
  message.success('上传成功')
 | 
			
		||||
  console.info(uploadList.value)
 | 
			
		||||
  console.info(fileList.value)
 | 
			
		||||
  uploadList.value.push({ name: res.data, url: res.data })
 | 
			
		||||
  if (uploadList.value.length == uploadNumber.value) {
 | 
			
		||||
    fileList.value = fileList.value.concat(uploadList.value)
 | 
			
		||||
    uploadList.value = []
 | 
			
		||||
    uploadNumber.value = 0
 | 
			
		||||
    emit('input', listToString(fileList.value))
 | 
			
		||||
    emit('update:modelValue', listToString(fileList.value))
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
// 文件数超出提示
 | 
			
		||||
@@ -134,7 +140,7 @@ const handleRemove = (file) => {
 | 
			
		||||
  const findex = fileList.value.map((f) => f.name).indexOf(file.name)
 | 
			
		||||
  if (findex > -1) {
 | 
			
		||||
    fileList.value.splice(findex, 1)
 | 
			
		||||
    emit('input', listToString(fileList.value))
 | 
			
		||||
    emit('update:modelValue', listToString(fileList.value))
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
// 对象转成指定字符串分隔
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user