Browse Source

feat: os文件管理 兼容本地文件上传

wanggaokun 1 year ago
parent
commit
ac5c37be48

+ 94 - 81
src/components/Upload/File.vue

@@ -3,7 +3,7 @@
     <el-upload
       ref="uploadRef"
       :action="uploadFileUrl"
-      v-model:file-list="_fileList"
+      :file-list="_fileList"
       class="upload-file-uploader"
       :show-file-list="false"
       :multiple="true"
@@ -32,9 +32,9 @@
     <!-- 文件列表 -->
     <transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
       <li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in _fileList">
-        <el-link :href="`${baseUrl}${file.url}`" :underline="false" target="_blank">
+        <el-link :href="`${file.url}`" :underline="false" target="_blank">
           <span class="document">
-            {{ getFileName(file.name) }}
+            {{ file.name }}
           </span>
         </el-link>
         <div class="ele-upload-list__item-content-action">
@@ -47,47 +47,47 @@
 
 <script setup lang="ts" name="UploadImgs">
 import { ref, computed, inject, watch } from 'vue'
-import type { UploadProps, UploadFile, UploadUserFile } from 'element-plus'
-import { ElNotification, ElMessage, formContextKey, formItemContextKey, UploadInstance } from 'element-plus'
-import { getToken } from '@/utils/token'
+import type { UploadProps, UploadFile } from 'element-plus'
+import { ElMessage, formContextKey, formItemContextKey, UploadInstance } from 'element-plus'
+import { showFullScreenLoading, tryHideFullScreenLoading } from '@/components/Loading/fullScreen'
+import { globalHeaders } from '@/api'
+import { OssVO } from '@/api/interface/system/oss'
+import { getListByIdsApi, delOssApi } from '@/api/modules/system/oss'
+import { listToString } from '@/utils/common'
 interface UploadFileProps {
-  modelValue?: any
+  modelValue?: string | object | Array<any>
   disabled?: boolean // 是否禁用上传组件 ==> 非必传(默认为 false)
   drag?: boolean // 是否支持拖拽上传 ==> 非必传(默认为 true)
   limit?: number // 最大图片上传数 ==> 非必传(默认为 5张)
   fileSize?: number // 图片大小限制 ==> 非必传(默认为 5M)
-  height?: string // 组件高度 ==> 非必传(默认为 150px)
-  width?: string // 组件宽度 ==> 非必传(默认为 150px)
-  borderRadius?: string // 组件边框圆角 ==> 非必传(默认为 8px)
   isShowTip?: boolean // 是否显示提示信息 ==> 非必传(默认为 true)
   text?: string // 按钮文字
   icon?: string
-  fileList?: UploadUserFile[]
-  fileType?: Array<any>
+  fileType?: Array<string>
 }
-// const emit = defineEmits(['update:modelValue'])
-const emit = defineEmits<{
-  'update:modelValue': [value: any]
-}>()
-const baseUrl = import.meta.env.VITE_API_URL
-const uploadFileUrl = ref(import.meta.env.VITE_API_URL + '/common/upload') // 上传文件服务器地址
-const headers = ref({ Authorization: 'Bearer ' + getToken() })
-const uploadRef = ref<UploadInstance>()
-const showTip = computed(() => props.isShowTip && (props.fileType || props.fileSize))
+// 默认值
 const props = withDefaults(defineProps<UploadFileProps>(), {
-  fileList: () => [],
+  modelValue: () => '',
   drag: true,
   disabled: false,
   limit: 1,
-  fileSize: 500,
-  fileType: () => ['doc', 'xls', 'xlsx', 'ppt', 'txt', 'pdf'],
-  height: '150px',
-  width: '150px',
-  borderRadius: '8px',
+  fileSize: 5,
+  fileType: () => ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'txt', 'pdf'],
   text: '文件上传',
-  isShowTip: false
+  isShowTip: true
 })
 
+const baseUrl = import.meta.env.VITE_API_URL
+const uploadFileUrl = ref(baseUrl + '/common/upload') // 上传文件服务器地址
+const headers = ref(globalHeaders())
+const uploadRef = ref<UploadInstance>()
+const number = ref(0)
+const showTip = computed(() => props.isShowTip && (props.fileType || props.fileSize))
+const uploadList = ref<any[]>([])
+const emit = defineEmits<{
+  'update:modelValue': [value: any]
+}>()
+
 // 获取 el-form 组件上下文
 const formContext = inject(formContextKey, void 0)
 // 获取 el-form-item 组件上下文
@@ -97,25 +97,41 @@ const self_disabled = computed(() => {
   return props.disabled || formContext?.disabled
 })
 
-const _fileList = ref<UploadUserFile[]>(props.fileList)
+const _fileList = ref<any[]>([])
 
-// 获取文件名称
-const getFileName = name => {
-  if (name.lastIndexOf('/') > -1) {
-    return name.slice(name.lastIndexOf('/') + 1)
-  } else {
-    return ''
-  }
-}
-
-// 监听 props.fileList 列表默认值改变
+// 监听 props.modelValue 列表默认值改变
 watch(
-  () => props.fileList,
-  (n: UploadUserFile[]) => {
-    _fileList.value = n
-  }
+  () => props.modelValue,
+  async (val: string | object | Array<any>) => {
+    if (val) {
+      let temp = 1
+      // 首先将值转为数组
+      let list: any[] = []
+      if (Array.isArray(val)) {
+        list = val as OssVO[]
+      } else {
+        const res = await getListByIdsApi(val)
+        list = res.data.map(oss => {
+          return {
+            name: oss.originalName,
+            url: oss.url,
+            ossId: oss.ossId
+          }
+        })
+      }
+      // 然后将数组转为对象数组
+      _fileList.value = list.map(item => {
+        item = { name: item.name, url: item.url, ossId: item.ossId }
+        item.uid = item.uid || new Date().getTime() + temp++
+        return item
+      })
+    } else {
+      _fileList.value = []
+      return []
+    }
+  },
+  { deep: true, immediate: true }
 )
-
 /**
  * @description 文件上传之前判断
  * @param rawFile 选择的文件
@@ -127,21 +143,16 @@ const beforeUpload: UploadProps['beforeUpload'] = rawFile => {
   const isTypeOk = props.fileType.indexOf(fileExt) >= 0
   // 校检文件大小
   const isLt = rawFile.size / 1024 / 1024 < props.fileSize
-
-  if (!isTypeOk)
-    ElNotification({
-      title: '温馨提示',
-      message: '上传文件不符合所需的格式!',
-      type: 'warning'
-    })
-  if (!isLt)
-    setTimeout(() => {
-      ElNotification({
-        title: '温馨提示',
-        message: `上传文件大小不能超过 ${props.fileSize}M!`,
-        type: 'warning'
-      })
-    }, 0)
+  if (!isTypeOk) {
+    ElMessage.error(`文件格式不正确, 请上传${props.fileType.join('/')}格式文件!`)
+    return false
+  }
+  if (!isLt) {
+    ElMessage.error(`文件大小不能超过 ${props.fileSize}M!`)
+    return false
+  }
+  number.value++
+  showFullScreenLoading('正在上传文件,请稍候...')
   return isTypeOk && isLt
 }
 
@@ -151,28 +162,29 @@ const beforeUpload: UploadProps['beforeUpload'] = rawFile => {
  * @param uploadFile 上传的文件
  * */
 const uploadSuccess = (response: any | undefined, uploadFile: UploadFile) => {
-  if (response.code === 200) {
-    uploadFile.url = response.url
-    uploadFile.name = response.fileName
-    emit('update:modelValue', _fileList.value)
-    // 调用 el-form 内部的校验方法(可自动校验)
-    formItemContext?.prop && formContext?.validateField([formItemContext.prop as string])
-    ElNotification({
-      title: '温馨提示',
-      message: '文件上传成功!',
-      type: 'success'
-    })
-  } else {
+  if (response.code !== 200) {
+    number.value--
     ElMessage.error(response.msg)
     uploadRef.value?.handleRemove(uploadFile)
+    uploadedSuccessfully()
+    return
+  }
+  uploadList.value.push({ name: response.data.fileName, url: response.data.url, ossId: response.data.ossId })
+  uploadedSuccessfully()
+}
+
+// 上传结束处理
+const uploadedSuccessfully = () => {
+  debugger
+  if (number.value > 0 && uploadList.value.length === number.value) {
+    _fileList.value = _fileList.value.filter(f => f.url !== undefined).concat(uploadList.value)
+    uploadList.value = []
+    number.value = 0
+    emit('update:modelValue', listToString(_fileList.value))
+    tryHideFullScreenLoading()
   }
-  //   code: 200
-  // fileName: "/profile/upload/2024/04/19/demo_20240419154324A003.txt"
-  // msg: "操作成功"
-  // newFileName: "demo_20240419154324A003.txt"
-  // originalFilename: "demo.txt"
-  // url: "http://localhost:8080/profile/upload/2024/04/19/demo_20240419154324A003.txt"
-  // uploadList.push({ name: res.fileName, url: res.fileName });
+  // 监听表单验证
+  formItemContext?.prop && formContext?.validateField([formItemContext.prop as string])
 }
 
 /**
@@ -180,9 +192,10 @@ const uploadSuccess = (response: any | undefined, uploadFile: UploadFile) => {
  * @param file 删除的文件
  * */
 const handleRemove = (index: number) => {
-  // _fileList.value = _fileList.value.filter(item => item.url !== file.url || item.name !== file.name)
+  let ossId = _fileList.value[index].ossId
+  delOssApi(ossId)
   _fileList.value.splice(index, 1)
-  emit('update:modelValue', _fileList.value)
+  emit('update:modelValue', listToString(_fileList.value))
 }
 
 /**
@@ -196,7 +209,7 @@ const uploadError = () => {
  * @description 文件数超出
  * */
 const handleExceed = () => {
-  ElMessage.error(`当前最多只能上传 ${props.limit} 个文件 ,请移除后上传!`)
+  ElMessage.warning(`当前最多只能上传 ${props.limit} 个文件 ,请移除后上传!`)
 }
 </script>
 

+ 1 - 1
src/components/Upload/FileS3.vue

@@ -32,7 +32,7 @@
     <!-- 文件列表 -->
     <transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
       <li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in _fileList">
-        <el-link :href="`${baseUrl}${file.url}`" :underline="false" target="_blank">
+        <el-link :href="`${file.url}`" :underline="false" target="_blank">
           <span class="document">
             {{ file.name }}
           </span>

+ 122 - 77
src/components/Upload/Imgs.vue

@@ -1,18 +1,18 @@
 <template>
   <div class="upload-box">
     <el-upload
-      v-model:file-list="_fileList"
-      action="#"
+      :file-list="_fileList"
+      :action="uploadImgUrl"
       list-type="picture-card"
-      :class="['upload', self_disabled ? 'disabled' : '', drag ? 'no-border' : '']"
-      :multiple="true"
-      :disabled="self_disabled"
-      :limit="limit"
-      :http-request="handleHttpUpload"
       :before-upload="beforeUpload"
-      :on-exceed="handleExceed"
       :on-success="uploadSuccess"
+      :on-exceed="handleExceed"
       :on-error="uploadError"
+      :class="['upload', self_disabled ? 'disabled' : '', drag ? 'no-border' : '', { hide: _fileList.length >= limit }]"
+      :multiple="true"
+      :headers="headers"
+      :disabled="self_disabled"
+      :limit="limit"
       :drag="drag"
       :accept="fileType.join(',')"
     >
@@ -36,6 +36,16 @@
         </div>
       </template>
     </el-upload>
+    <div v-if="showTip" class="el-upload__tip">
+      请上传
+      <template v-if="fileSize">
+        大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
+      </template>
+      <template v-if="fileType">
+        格式为 <b style="color: #f56c6c">{{ fileType.join('/') }}</b>
+      </template>
+      的文件
+    </div>
     <div class="el-upload__tip">
       <slot name="tip"></slot>
     </div>
@@ -46,13 +56,17 @@
 <script setup lang="ts" name="UploadImgs">
 import { ref, computed, inject, watch } from 'vue'
 import { Plus } from '@element-plus/icons-vue'
-import { uploadImg } from '@/api/modules/upload'
-import type { UploadProps, UploadFile, UploadUserFile, UploadRequestOptions } from 'element-plus'
-import { ElNotification, formContextKey, formItemContextKey } from 'element-plus'
-
+import type { UploadProps, UploadFile } from 'element-plus'
+import { ElMessage, formContextKey, formItemContextKey } from 'element-plus'
+import { listToString } from '@/utils/common'
+import { showFullScreenLoading, tryHideFullScreenLoading } from '@/components/Loading/fullScreen'
+import { compressAccurately } from 'image-conversion'
+import { OssVO } from '@/api/interface/system/oss'
+import { globalHeaders } from '@/api'
+import { getListByIdsApi, delOssApi } from '@/api/modules/system/oss'
+import { ResultData } from '@/api/interface'
 interface UploadFileProps {
-  fileList: UploadUserFile[]
-  api?: (params: any) => Promise<any> // 上传图片的 api 方法,一般项目上传都是同一个 api 方法,在组件里直接引入即可 ==> 非必传
+  modelValue: string | object | Array<any>
   drag?: boolean // 是否支持拖拽上传 ==> 非必传(默认为 true)
   disabled?: boolean // 是否禁用上传组件 ==> 非必传(默认为 false)
   limit?: number // 最大图片上传数 ==> 非必传(默认为 5张)
@@ -60,21 +74,30 @@ interface UploadFileProps {
   fileType?: File.ImageMimeType[] // 图片类型限制 ==> 非必传(默认为 ["image/jpeg", "image/png", "image/gif"])
   height?: string // 组件高度 ==> 非必传(默认为 150px)
   width?: string // 组件宽度 ==> 非必传(默认为 150px)
+  isShowTip?: boolean
   borderRadius?: string // 组件边框圆角 ==> 非必传(默认为 8px)
+  compressSupport?: boolean // 是否支持图片压缩 ==> 非必传(默认为 false)
+  compressTargetSize?: number // 图片压缩目标大小 ==> 非必传(默认为 300kb)
 }
 
 const props = withDefaults(defineProps<UploadFileProps>(), {
-  fileList: () => [],
+  modelValue: () => '',
   drag: true,
   disabled: false,
   limit: 5,
   fileSize: 5,
+  isShowTip: true,
+  compressSupport: false,
+  compressTargetSize: 300,
   fileType: () => ['image/jpeg', 'image/png', 'image/gif'],
   height: '150px',
   width: '150px',
   borderRadius: '8px'
 })
 
+const baseUrl = import.meta.env.VITE_API_URL
+const uploadImgUrl = ref(baseUrl + '/common/upload') // 上传的图片服务器地址
+const headers = ref(globalHeaders())
 // 获取 el-form 组件上下文
 const formContext = inject(formContextKey, void 0)
 // 获取 el-form-item 组件上下文
@@ -83,15 +106,42 @@ const formItemContext = inject(formItemContextKey, void 0)
 const self_disabled = computed(() => {
   return props.disabled || formContext?.disabled
 })
-
-const _fileList = ref<UploadUserFile[]>(props.fileList)
-
-// 监听 props.fileList 列表默认值改变
+const showTip = computed(() => props.isShowTip && (props.fileType || props.fileSize))
+const _fileList = ref<any[]>([])
+const uploadList = ref<any[]>([])
+const number = ref(0)
+const imageUploadRef = ref<ElUploadInstance>()
+// 监听 props.modelValue 列表默认值改变
 watch(
-  () => props.fileList,
-  (n: UploadUserFile[]) => {
-    _fileList.value = n
-  }
+  () => props.modelValue,
+  async (val: string | object | Array<any>) => {
+    if (val) {
+      // 首先将值转为数组
+      let list: OssVO[] = []
+      if (Array.isArray(val)) {
+        list = val as OssVO[]
+      } else {
+        const res = await getListByIdsApi(val)
+        list = res.data
+      }
+      // 然后将数组转为对象数组
+      _fileList.value = list.map(item => {
+        // 字符串回显处理 如果此处存的是url可直接回显 如果存的是id需要调用接口查出来
+        let itemData
+        if (typeof item === 'string') {
+          itemData = { name: item, url: item }
+        } else {
+          // 此处name使用ossId 防止删除出现重名
+          itemData = { name: item.ossId, url: item.url, ossId: item.ossId }
+        }
+        return itemData
+      })
+    } else {
+      _fileList.value = []
+      return []
+    }
+  },
+  { deep: true, immediate: true }
 )
 
 /**
@@ -101,37 +151,21 @@ watch(
 const beforeUpload: UploadProps['beforeUpload'] = rawFile => {
   const imgSize = rawFile.size / 1024 / 1024 < props.fileSize
   const imgType = props.fileType.includes(rawFile.type as File.ImageMimeType)
-  if (!imgType)
-    ElNotification({
-      title: '温馨提示',
-      message: '上传图片不符合所需的格式!',
-      type: 'warning'
-    })
-  if (!imgSize)
-    setTimeout(() => {
-      ElNotification({
-        title: '温馨提示',
-        message: `上传图片大小不能超过 ${props.fileSize}M!`,
-        type: 'warning'
-      })
-    }, 0)
-  return imgType && imgSize
-}
-
-/**
- * @description 图片上传
- * @param options upload 所有配置项
- * */
-const handleHttpUpload = async (options: UploadRequestOptions) => {
-  let formData = new FormData()
-  formData.append('file', options.file)
-  try {
-    const api = props.api ?? uploadImg
-    const { data } = await api(formData)
-    options.onSuccess(data)
-  } catch (error) {
-    options.onError(error as any)
+  if (!imgType) {
+    ElMessage.error(`上传图片不符合所需的格式,  请上传${props.fileType.join('/')}图片格式文件!`)
+    return false
   }
+  if (!imgSize) {
+    ElMessage.error('图片大小不能超过 ' + props.fileSize + 'M!')
+    return false
+  }
+  if (props.compressSupport && rawFile.size / 1024 > props.compressTargetSize) {
+    return compressAccurately(rawFile, props.compressTargetSize)
+  }
+  showFullScreenLoading('正在上传图片,请稍候...')
+  number.value++
+  console.log('number', number.value)
+  return imgType && imgSize
 }
 
 /**
@@ -140,19 +174,31 @@ const handleHttpUpload = async (options: UploadRequestOptions) => {
  * @param uploadFile 上传的文件
  * */
 const emit = defineEmits<{
-  'update:fileList': [value: UploadUserFile[]]
+  'update:modelValue': [value: string]
 }>()
-const uploadSuccess = (response: { fileUrl: string } | undefined, uploadFile: UploadFile) => {
-  if (!response) return
-  uploadFile.url = response.fileUrl
-  emit('update:fileList', _fileList.value)
-  // 调用 el-form 内部的校验方法(可自动校验)
+const uploadSuccess = (response: ResultData, uploadFile: UploadFile) => {
+  if (response.code !== 200) {
+    number.value--
+    ElMessage.error(response.msg)
+    imageUploadRef.value?.handleRemove(uploadFile)
+    uploadedSuccessfully()
+    return
+  }
+  uploadList.value.push({ name: response.data.fileName, url: response.data.url, ossId: response.data.ossId })
+  uploadedSuccessfully()
+}
+
+// 上传结束处理
+const uploadedSuccessfully = () => {
+  if (number.value > 0 && uploadList.value.length === number.value) {
+    _fileList.value = _fileList.value.filter(f => f.url !== undefined).concat(uploadList.value)
+    uploadList.value = []
+    number.value = 0
+    emit('update:modelValue', listToString(_fileList.value))
+    tryHideFullScreenLoading()
+  }
+  // 监听表单验证
   formItemContext?.prop && formContext?.validateField([formItemContext.prop as string])
-  ElNotification({
-    title: '温馨提示',
-    message: '图片上传成功!',
-    type: 'success'
-  })
 }
 
 /**
@@ -160,30 +206,30 @@ const uploadSuccess = (response: { fileUrl: string } | undefined, uploadFile: Up
  * @param file 删除的文件
  * */
 const handleRemove = (file: UploadFile) => {
-  _fileList.value = _fileList.value.filter(item => item.url !== file.url || item.name !== file.name)
-  emit('update:fileList', _fileList.value)
+  const fIndex = _fileList.value.map(f => f.name).indexOf(file.name)
+  if (fIndex > -1 && uploadList.value.length === number.value) {
+    let ossId = _fileList.value[fIndex].ossId
+    delOssApi(ossId)
+    _fileList.value.splice(fIndex, 1)
+    emit('update:modelValue', listToString(_fileList.value))
+    formItemContext?.prop && formContext?.validateField([formItemContext.prop as string])
+    return false
+  }
+  return true
 }
 
 /**
  * @description 图片上传错误
  * */
 const uploadError = () => {
-  ElNotification({
-    title: '温馨提示',
-    message: '图片上传失败,请您重新上传!',
-    type: 'error'
-  })
+  ElMessage.error('图片上传失败,请您重新上传!')
 }
 
 /**
  * @description 文件数超出
  * */
 const handleExceed = () => {
-  ElNotification({
-    title: '温馨提示',
-    message: `当前最多只能上传 ${props.limit} 张图片,请移除后上传!`,
-    type: 'warning'
-  })
+  ElMessage.warning(`当前最多只能上传 ${props.limit} 张图片,请移除后上传!`)
 }
 
 /**
@@ -310,7 +356,6 @@ const handlePictureCardPreview: UploadProps['onPreview'] = file => {
   }
   .el-upload__tip {
     line-height: 15px;
-    text-align: center;
   }
 }
 </style>

+ 0 - 3
src/components/Upload/index.scss

@@ -1,3 +0,0 @@
-.upload {
-  width: 80%;
-}

+ 0 - 257
src/components/Upload/index.vue

@@ -1,257 +0,0 @@
-<template>
-  <el-dialog v-model="dialogVisible" :width="parameter.width" :top="parameter.top" :title="`${parameter.title}`" :destroy-on-close="true" draggable>
-    <el-form class="drawer-multiColumn-form" label-width="100px">
-      <el-form-item label="文件上传">
-        <el-upload
-          ref="imageUpload"
-          :file-list="_fileList"
-          :action="uploadImgUrl"
-          list-type="picture-card"
-          :class="['upload', { hide: _fileList.length >= limit }]"
-          :headers="headers"
-          :limit="limit"
-          :multiple="multiple"
-          :show-file-list="true"
-          :before-upload="beforeUpload"
-          :on-exceed="handleExceed"
-          :on-success="uploadSuccess"
-          :on-error="uploadError"
-          :accept="fileType!.join(',')"
-        >
-          <div class="upload-empty">
-            <slot name="empty">
-              <el-icon><Plus /></el-icon>
-              <!-- <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)">
-                <el-icon><ZoomIn /></el-icon>
-                <span>查看</span>
-              </div>
-              <div v-if="!self_disabled" class="handle-icon" @click="handleRemove(file)">
-                <el-icon><Delete /></el-icon>
-                <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" />
-      </el-form-item>
-    </el-form>
-    <template #footer>
-      <span class="dialog-footer">
-        <el-button type="primary" @click="handleSubmit">确认</el-button>
-        <el-button @click="dialogVisible = false">取消</el-button>
-      </span>
-    </template>
-  </el-dialog>
-</template>
-
-<script setup lang="ts" name="ImportExcel">
-import { ref, computed, inject, watch } from 'vue'
-import { ElMessage, ElNotification, UploadInstance, formContextKey, formItemContextKey } from 'element-plus'
-import type { UploadProps, UploadFile, UploadUserFile } from 'element-plus'
-import { compressAccurately } from 'image-conversion'
-import { globalHeaders } from '@/api'
-import { OssVO } from '@/api/interface/system/oss'
-import { listToString } from '@/utils/common'
-import { getListByIdsApi } from '@/api/modules/system/oss'
-import { showFullScreenLoading, tryHideFullScreenLoading } from '@/components/Loading/fullScreen'
-export interface UploadImgProps {
-  modelValue?: string | object | any[]
-  fileSize?: number // 上传文件的大小
-  limit?: number // 上传文件个数
-  width?: number | string // 组件高度 ==> 非必传(默认为 150px
-  height?: number | string // 组件高度 ==> 非必传(默认为 150px)
-  multiple?: boolean // 是否支持多选文件
-  fileType?: File.ImageMimeType[] // 图片类型限制 ==> 非必传(默认为 ["image/jpeg", "image/png", "image/gif"])
-  drag?: boolean // 是否支持拖拽上传 ==> 非必传(默认为 true)
-  disabled?: boolean // 是否禁用上传组件 ==> 非必传(默认为 false)
-  borderRadius?: string // 组件边框圆角 ==> 非必传(默认为 8px)
-  compressTargetSize?: number // 压缩图片尺寸 ==> 非必传(默认为 300)
-  compressSupport?: boolean // 是否支持压缩图片 ==> 非必传(默认为 false)
-}
-export interface DialogProps {
-  title: string // 标题
-  top?: string // 离顶部距离
-  width?: number | string // 弹框宽度
-  getTableList?: () => void // 获取表格数据的Api
-}
-
-// 统计图片数量
-// const number = ref(0)
-// const uploadList = ref<any[]>([])
-// dialog状态
-const dialogVisible = ref(false)
-// 获取 el-form 组件上下文
-const formContext = inject(formContextKey, void 0)
-// 获取 el-form-item 组件上下文
-const formItemContext = inject(formItemContextKey, void 0)
-// 父组件传过来的参数
-const props = withDefaults(defineProps<UploadImgProps>(), {
-  fileList: () => [],
-  drag: true,
-  modelValue: () => [],
-  disabled: false,
-  limit: 5,
-  fileSize: 5,
-  multiple: true,
-  fileType: () => ['image/jpeg', 'image/png', 'image/gif'],
-  height: '150px',
-  width: '150px',
-  borderRadius: '8px',
-  compressTargetSize: 300,
-  compressSupport: false
-})
-// 弹窗参数
-const parameter = ref<DialogProps>({
-  title: '',
-  width: 500,
-  top: '20vh'
-})
-const _fileList = ref<UploadUserFile[]>([])
-
-// 监听 props.fileList 列表默认值改变
-watch(
-  () => props.modelValue,
-  async (val: string | object | any[]) => {
-    if (val) {
-      // 首先将值转为数组
-      let list: OssVO[] = []
-      if (Array.isArray(val)) {
-        list = val as OssVO[]
-      } else {
-        const res = await getListByIdsApi(val)
-        list = res.data
-      }
-      // 然后将数组转为对象数组
-      _fileList.value = list.map(item => {
-        // 字符串回显处理 如果此处存的是url可直接回显 如果存的是id需要调用接口查出来
-        let itemData
-        if (typeof item === 'string') {
-          itemData = { name: item, url: item }
-        } else {
-          // 此处name使用ossId 防止删除出现重名
-          itemData = { name: item.ossId, url: item.url, ossId: item.ossId }
-        }
-        return itemData
-      })
-    } else {
-      _fileList.value = []
-      return []
-    }
-  },
-  { deep: true, immediate: true }
-)
-const baseUrl = import.meta.env.VITE_API_URL
-const uploadImgUrl = ref(baseUrl + '/resource/oss/upload') // 上传的图片服务器地址
-const headers = ref(globalHeaders())
-// 接收父组件参数
-const acceptParams = (params: DialogProps) => {
-  debugger
-  parameter.value = { ...parameter.value, ...params }
-  dialogVisible.value = true
-}
-
-const self_disabled = computed(() => {
-  return props.disabled || formContext?.disabled
-})
-/**
- * @description 文件数超出
- * */
-const handleExceed = () => {
-  ElMessage.error(`当前最多只能上传 ${props.limit} 张图片,请移除后上传!`)
-}
-const uploadRef = ref<UploadInstance>()
-const handleSubmit = () => {
-  uploadRef.value!.submit()
-}
-
-/**
- * @description 文件上传之前判断
- * @param rawFile 选择的文件
- * */
-const beforeUpload: UploadProps['beforeUpload'] = rawFile => {
-  const imgSize = rawFile.size / 1024 / 1024 < props.fileSize
-  const imgType = props.fileType.includes(rawFile.type as File.ImageMimeType)
-  if (!imgType)
-    ElNotification({
-      title: '温馨提示',
-      message: '上传图片不符合所需的格式!',
-      type: 'warning'
-    })
-  if (!imgSize)
-    setTimeout(() => {
-      ElNotification({
-        title: '温馨提示',
-        message: `上传图片大小不能超过 ${props.fileSize}M!`,
-        type: 'warning'
-      })
-    }, 0)
-  if (props.compressSupport && rawFile.size / 1024 > props.compressTargetSize) {
-    return compressAccurately(rawFile, props.compressTargetSize)
-  }
-  showFullScreenLoading('正在上传图片,请稍候...')
-  return imgType && imgSize
-}
-
-const emit = defineEmits<{
-  'update:modelValue': [value: string]
-}>()
-/**
- * @description 图片上传成功
- * @param response 上传响应结果
- * @param uploadFile 上传的文件
- * */
-const uploadSuccess = (response: { fileUrl: string } | undefined, uploadFile: UploadFile) => {
-  if (!response) return
-  uploadFile.url = response.fileUrl
-  emit('update:modelValue', listToString(_fileList.value))
-  // 调用 el-form 内部的校验方法(可自动校验)
-  formItemContext?.prop && formContext?.validateField([formItemContext.prop as string])
-  tryHideFullScreenLoading()
-  ElNotification({
-    title: '温馨提示',
-    message: '图片上传成功!',
-    type: 'success'
-  })
-}
-
-// 上传错误提示
-const uploadError = () => {
-  ElMessage.error('图片上传失败,请您重新上传!')
-  tryHideFullScreenLoading()
-}
-
-/**
- * @description 删除图片
- * @param file 删除的文件
- * */
-const handleRemove = (file: UploadFile) => {
-  _fileList.value = _fileList.value.filter(item => item.url !== file.url || item.name !== file.name)
-  emit('update:modelValue', listToString(_fileList.value))
-}
-
-/**
- * @description 图片预览
- * @param file 预览的文件
- * */
-const viewImageUrl = ref('')
-const imgViewVisible = ref(false)
-const handlePictureCardPreview: UploadProps['onPreview'] = file => {
-  viewImageUrl.value = file.url!
-  imgViewVisible.value = true
-}
-defineExpose({
-  acceptParams
-})
-</script>
-<style lang="scss" scoped>
-@import './index.scss';
-</style>

+ 34 - 0
src/hooks/useDownload.ts

@@ -83,6 +83,40 @@ export default {
       downloadLoadingInstance.close()
     }
   },
+  async localResource(resource: string) {
+    let url = baseURL + '/common/download/resource?resource=' + encodeURI(resource)
+    axios({
+      method: 'get',
+      url: url,
+      responseType: 'blob',
+      headers: globalHeaders()
+    }).then(async res => {
+      const isLogin = await blobValidate(res.data)
+      if (isLogin) {
+        const blob = new Blob([res.data])
+        saveAs(blob, decodeURI(res.headers['download-filename']))
+      } else {
+        this.printErrMsg(res.data)
+      }
+    })
+  },
+  async localName(name: string, isDelete = true) {
+    let url = baseURL + '/common/download?fileName=' + encodeURI(name) + '&delete=' + isDelete
+    axios({
+      method: 'get',
+      url: url,
+      responseType: 'blob',
+      headers: globalHeaders()
+    }).then(async res => {
+      const isLogin = await blobValidate(res.data)
+      if (isLogin) {
+        const blob = new Blob([res.data])
+        saveAs(blob, decodeURI(res.headers['download-filename']))
+      } else {
+        this.printErrMsg(res.data)
+      }
+    })
+  },
   async printErrMsg(data: any) {
     const resText = await data.text()
     const rspObj = JSON.parse(resText)

+ 6 - 0
src/views/system/oss/index.vue

@@ -5,6 +5,8 @@
       <template #tableHeader="scope">
         <el-button type="primary" v-auth="['system:oss:upload']" icon="Upload" plain @click="handleFile('file-upload-s3')"> 上传文件 </el-button>
         <el-button type="primary" v-auth="['system:oss:upload']" icon="Upload" plain @click="handleFile('img-upload-s3')"> 上传图片 </el-button>
+        <el-button type="primary" v-auth="['system:oss:upload']" icon="Upload" plain @click="handleFile('img-upload')"> 本地图片 </el-button>
+        <el-button type="primary" v-auth="['system:oss:upload']" icon="Upload" plain @click="handleFile('file-upload')"> 本地上传 </el-button>
         <el-button
           type="danger"
           v-auth="['system:oss:remove']"
@@ -115,6 +117,10 @@ const batchDelete = async (ids: string[]) => {
 /** 下载按钮操作 */
 const handleDownload = (row: OssVO) => {
   console.log(row)
+  if (row.service === 'Local') {
+    useDownload.localResource(row.url)
+    return
+  }
   useDownload.oss(row.ossId)
 }