|
@@ -1,4 +1,5 @@
|
|
|
<script setup lang="ts">
|
|
|
+import DownloadTipModal from '@/components/common/DownloadTipModal.vue'
|
|
|
import CommonFileUpload from '@/components/form/CommonFileUpload.vue'
|
|
|
|
|
|
import { useRequest } from '@/hooks/useRequest.ts'
|
|
@@ -6,8 +7,13 @@ import { useRequest } from '@/hooks/useRequest.ts'
|
|
|
import { FilterType, type QueryInfo } from '@/types/table.ts'
|
|
|
import axiosInstance from '@/utils/axios/axiosInstance.ts'
|
|
|
import { ElMessageBox, type FormInstance } from 'element-plus'
|
|
|
+import FileSaver from 'file-saver'
|
|
|
+import JSZip from 'jszip'
|
|
|
+
|
|
|
import { ref, onMounted } from 'vue'
|
|
|
|
|
|
+type DownloadProgressInstance = InstanceType<typeof DownloadTipModal>
|
|
|
+
|
|
|
interface PaginationConfig {
|
|
|
curPage: number
|
|
|
curSize: number
|
|
@@ -97,6 +103,9 @@ const makeDirDialogConfig = ref({
|
|
|
}
|
|
|
})
|
|
|
|
|
|
+// 下载文件进度条
|
|
|
+const downloadProgressRef = ref<DownloadProgressInstance>()
|
|
|
+
|
|
|
/**
|
|
|
* 获取当前文件路径的完整路径
|
|
|
* @returns 返回完整路径字符串,如 /a/b/
|
|
@@ -236,8 +245,13 @@ const handleDbClick = (id: number) => {
|
|
|
ElMessage.warning('未选中文件,请重试')
|
|
|
return
|
|
|
}
|
|
|
- // 是文件就返回
|
|
|
- if (selectedItem.type === 1) return
|
|
|
+ // 是文件就触发下载
|
|
|
+ if (selectedItem.type === 1) {
|
|
|
+ const url = selectedItem.cos_path
|
|
|
+ // downloadSingleFile(url)
|
|
|
+ downloadFiles(url)
|
|
|
+ return
|
|
|
+ }
|
|
|
breadcrumbList.value.push(selectedItem.file_name)
|
|
|
|
|
|
getFileList()
|
|
@@ -259,6 +273,7 @@ const handleSelectAll = (isSelected: boolean) => {
|
|
|
const handleOver = () => {
|
|
|
selectedAble.value = false
|
|
|
selectedRecord.value = {}
|
|
|
+ selectedAll.value = false
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -372,6 +387,93 @@ const handleDel = async () => {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * 获取选中的文件信息
|
|
|
+ * @returns 选中的文件信息
|
|
|
+ */
|
|
|
+const getSelectedInfo = () => {
|
|
|
+ const allIds = Object.keys(selectedRecord.value).map((item) => parseInt(item))
|
|
|
+ return fileListData.value.filter((item) => allIds.includes(item.id))
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 单个文件下载
|
|
|
+ * @param url 文件下载地址
|
|
|
+ */
|
|
|
+const downloadSingleFile = async (url: string) => {
|
|
|
+ const response = await fetch(url)
|
|
|
+ const blob = await response.blob()
|
|
|
+ const fileName = url.split('/').pop()?.split('?')[0] ?? `文件`
|
|
|
+ FileSaver.saveAs(blob, fileName)
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 批量下载文件
|
|
|
+ * @param urls 文件下载地址列表
|
|
|
+ */
|
|
|
+const handleBatchDownload = async (urls: string[]) => {
|
|
|
+ const zip = new JSZip()
|
|
|
+
|
|
|
+ const promises = urls.map(async (url, i) => {
|
|
|
+ const response = await fetch(url)
|
|
|
+ const blob = await response.blob()
|
|
|
+ const fileName = url.split('/').pop()?.split('?')[0] ?? `文件${i}`
|
|
|
+ zip.file(fileName, blob)
|
|
|
+ })
|
|
|
+ await Promise.all(promises)
|
|
|
+ const content = await zip.generateAsync({ type: 'blob' })
|
|
|
+ FileSaver.saveAs(content, `${new Date().getTime()}.zip`)
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 下载文件
|
|
|
+ * 当单个文件时,直接下载
|
|
|
+ * 多个文件则会打包为zip进行下载
|
|
|
+ */
|
|
|
+const downloadFiles = async (singleFileDownloadUrl?: string) => {
|
|
|
+ try {
|
|
|
+ const info = getSelectedInfo()
|
|
|
+ // 文件夹需要单独去请求一下里面包含的所有url,然后合并到fileDownloadPaths中
|
|
|
+ // const folderId = info.filter((item) => item.type === 2).map((item) => item.id) // 筛选出文件夹ID
|
|
|
+ const fileDownloadPaths = info.filter((item) => item.type === 1).map((item) => item.cos_path)
|
|
|
+
|
|
|
+ const totalNums = fileDownloadPaths.length
|
|
|
+ // 总的文件下载数量,单个或者传入了单个文件的下载地址的话直接下,否则打包下
|
|
|
+ const isSingle = singleFileDownloadUrl || totalNums === 1
|
|
|
+
|
|
|
+ downloadProgressRef.value?.show()
|
|
|
+
|
|
|
+ if (isSingle) {
|
|
|
+ const url = singleFileDownloadUrl || fileDownloadPaths[0]
|
|
|
+ await downloadSingleFile(url)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ // 这里防止意外情况
|
|
|
+ if (fileDownloadPaths.length === 0) {
|
|
|
+ ElMessage.warning('请至少选择一个文件进行下载')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ await handleBatchDownload(fileDownloadPaths)
|
|
|
+
|
|
|
+ ElNotification({
|
|
|
+ title: 'Success',
|
|
|
+ message: '下载完成',
|
|
|
+ type: 'success',
|
|
|
+ duration: 5000
|
|
|
+ })
|
|
|
+ } catch (err) {
|
|
|
+ console.error(err)
|
|
|
+ ElNotification({
|
|
|
+ title: 'Error',
|
|
|
+ message: '下载失败,请稍后重试',
|
|
|
+ type: 'error',
|
|
|
+ duration: 0
|
|
|
+ })
|
|
|
+ } finally {
|
|
|
+ handleOver()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
* 页面加载完成后,获取文件列表
|
|
|
*/
|
|
|
onMounted(async () => {
|
|
@@ -390,9 +492,10 @@ onMounted(async () => {
|
|
|
</div>
|
|
|
<div :class="['toolContainer', isLoadData ? 'disableHandle' : '']">
|
|
|
<el-button class="toolBtn" color="#197afb" @click="openUploadFile">上传文件</el-button>
|
|
|
+
|
|
|
<el-button class="toolBtn" color="#197afb" plain @click="openCreateFolder"
|
|
|
- >新建文件夹</el-button
|
|
|
- >
|
|
|
+ >新建文件夹
|
|
|
+ </el-button>
|
|
|
<el-button class="toolBtn" color="#197afb" plain @click="manageFile">管理</el-button>
|
|
|
</div>
|
|
|
|
|
@@ -406,6 +509,13 @@ onMounted(async () => {
|
|
|
</div>
|
|
|
<div class="operationGroup">
|
|
|
<el-button
|
|
|
+ class="toolBtn"
|
|
|
+ color="#197afb"
|
|
|
+ @click="() => downloadFiles()"
|
|
|
+ :disabled="Object.values(selectedRecord).filter((item) => item).length < 1"
|
|
|
+ >下载
|
|
|
+ </el-button>
|
|
|
+ <el-button
|
|
|
class="toolBtn delBtn"
|
|
|
color="#F56C6C"
|
|
|
:disabled="Object.values(selectedRecord).filter((item) => item).length !== 1"
|
|
@@ -493,13 +603,19 @@ onMounted(async () => {
|
|
|
|
|
|
<template #footer>
|
|
|
<div class="make-dir-footer" :style="{ textAlign: 'right', padding: '10px 20px' }">
|
|
|
- <el-button class="make-dir-btn confirm" type="primary" @click="handleCreate">确定</el-button>
|
|
|
+ <el-button class="make-dir-btn confirm" type="primary" @click="handleCreate"
|
|
|
+ >确定
|
|
|
+ </el-button>
|
|
|
<el-button class="make-dir-btn cancel" @click="handleClose">取消</el-button>
|
|
|
</div>
|
|
|
</template>
|
|
|
</el-dialog>
|
|
|
</div>
|
|
|
</div>
|
|
|
+
|
|
|
+ <!--下载进度-->
|
|
|
+
|
|
|
+ <DownloadTipModal ref="downloadProgressRef"></DownloadTipModal>
|
|
|
</div>
|
|
|
</template>
|
|
|
|