|
@@ -3,6 +3,7 @@ import DownloadTipModal from '@/components/common/DownloadTipModal.vue'
|
|
|
import CommonFileUpload from '@/components/form/CommonFileUpload.vue'
|
|
|
|
|
|
import { useRequest } from '@/hooks/useRequest.ts'
|
|
|
+import type { ResponseInfo } from '@/types/res.ts'
|
|
|
|
|
|
import { FilterType, type QueryInfo } from '@/types/table.ts'
|
|
|
import axiosInstance from '@/utils/axios/axiosInstance.ts'
|
|
@@ -321,9 +322,9 @@ const handleCreate = async () => {
|
|
|
const res = (await axiosInstance.post(AllApi.makeDir, {
|
|
|
dir: getFullPath(),
|
|
|
dirName: makeDirDialogConfig.value.formData.name
|
|
|
- })) as { code: number }
|
|
|
+ })) as { code: number; msg: string }
|
|
|
if (res.code !== 0) {
|
|
|
- ElMessage.error('创建文件夹失败')
|
|
|
+ ElMessage.error(`创建文件夹失败,${res.msg}`)
|
|
|
return
|
|
|
}
|
|
|
ElMessage.success('创建文件夹成功')
|
|
@@ -409,17 +410,83 @@ const downloadSingleFile = async (url: string) => {
|
|
|
/**
|
|
|
* 批量下载文件
|
|
|
* @param urls 文件下载地址列表
|
|
|
+ * @param folderDownloadPaths 文件下载地址列表
|
|
|
*/
|
|
|
-const handleBatchDownload = async (urls: string[]) => {
|
|
|
+// const handleBatchDownload = async (urls: string[], folderDownloadPaths: any) => {
|
|
|
+// console.log(folderDownloadPaths)
|
|
|
+// 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`)
|
|
|
+// }
|
|
|
+
|
|
|
+const handleBatchDownload = async (urls: string[], folderDownloadPaths: any) => {
|
|
|
const zip = new JSZip()
|
|
|
+ const promises: Promise<void>[] = []
|
|
|
+
|
|
|
+ // 辅助函数:从URL提取文件名
|
|
|
+ const getFileNameFromUrl = (url: string): string => {
|
|
|
+ return url.split('/').pop()?.split('?')[0] ?? ''
|
|
|
+ }
|
|
|
+
|
|
|
+ // 辅助函数:下载文件并添加到ZIP
|
|
|
+ const fetchFileAndAddToZip = async (url: string, filename: string) => {
|
|
|
+ try {
|
|
|
+ const response = await fetch(url)
|
|
|
+ const blob = await response.blob()
|
|
|
+ zip.file(filename, blob)
|
|
|
+ } catch (error) {
|
|
|
+ console.error(`下载失败: ${url}`, error)
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- 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)
|
|
|
+ // 处理普通URL列表
|
|
|
+ urls.forEach((url) => {
|
|
|
+ const filename = getFileNameFromUrl(url)
|
|
|
+ if (filename) {
|
|
|
+ promises.push(fetchFileAndAddToZip(url, filename))
|
|
|
+ }
|
|
|
})
|
|
|
+
|
|
|
+ // 递归处理嵌套结构
|
|
|
+ const processNestedFolder = (content: any, basePath: string) => {
|
|
|
+ if (typeof content === 'string') {
|
|
|
+ promises.push(fetchFileAndAddToZip(content, basePath))
|
|
|
+ } else if (typeof content === 'object' && content !== null) {
|
|
|
+ Object.entries(content).forEach(([key, value]) => {
|
|
|
+ const newPath = basePath ? `${basePath}/${key}` : key
|
|
|
+ processNestedFolder(value, newPath)
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理文件夹结构
|
|
|
+ if (Array.isArray(folderDownloadPaths)) {
|
|
|
+ folderDownloadPaths.forEach((item) => {
|
|
|
+ if (typeof item === 'string') {
|
|
|
+ const filename = getFileNameFromUrl(item)
|
|
|
+ if (filename) {
|
|
|
+ promises.push(fetchFileAndAddToZip(item, filename))
|
|
|
+ }
|
|
|
+ } else if (typeof item === 'object' && item !== null) {
|
|
|
+ Object.entries(item).forEach(([folderName, content]) => {
|
|
|
+ processNestedFolder(content, folderName)
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // 等待所有文件下载完成
|
|
|
await Promise.all(promises)
|
|
|
+
|
|
|
+ // 生成并保存ZIP文件
|
|
|
const content = await zip.generateAsync({ type: 'blob' })
|
|
|
FileSaver.saveAs(content, `${new Date().getTime()}.zip`)
|
|
|
}
|
|
@@ -433,8 +500,26 @@ 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 folderDirs = info
|
|
|
+ .filter((item) => item.type === 2)
|
|
|
+ .map((item) => item.dir + item.file_name + '/') // 筛选出文件夹ID
|
|
|
+
|
|
|
+ const downloadQueue: Promise<ResponseInfo>[] = []
|
|
|
+ folderDirs.forEach((item) => {
|
|
|
+ downloadQueue.push(
|
|
|
+ axiosInstance.post(AllApi.downloadFolder, {
|
|
|
+ dir: item
|
|
|
+ })
|
|
|
+ )
|
|
|
+ })
|
|
|
+ const folderDownloadPaths = await Promise.all(downloadQueue).then((res) => {
|
|
|
+ return res.map((item) => item.data)
|
|
|
+ })
|
|
|
+
|
|
|
const fileDownloadPaths = info.filter((item) => item.type === 1).map((item) => item.cos_path)
|
|
|
+ if (singleFileDownloadUrl) {
|
|
|
+ fileDownloadPaths.push(singleFileDownloadUrl)
|
|
|
+ }
|
|
|
|
|
|
const totalNums = fileDownloadPaths.length
|
|
|
// 总的文件下载数量,单个或者传入了单个文件的下载地址的话直接下,否则打包下
|
|
@@ -442,17 +527,12 @@ const downloadFiles = async (singleFileDownloadUrl?: string) => {
|
|
|
|
|
|
downloadProgressRef.value?.show()
|
|
|
|
|
|
- if (isSingle) {
|
|
|
+ if (isSingle && folderDownloadPaths.length === 0) {
|
|
|
const url = singleFileDownloadUrl || fileDownloadPaths[0]
|
|
|
await downloadSingleFile(url)
|
|
|
return
|
|
|
}
|
|
|
- // 这里防止意外情况
|
|
|
- if (fileDownloadPaths.length === 0) {
|
|
|
- ElMessage.warning('请至少选择一个文件进行下载')
|
|
|
- return
|
|
|
- }
|
|
|
- await handleBatchDownload(fileDownloadPaths)
|
|
|
+ await handleBatchDownload(fileDownloadPaths, folderDownloadPaths)
|
|
|
|
|
|
ElNotification({
|
|
|
title: 'Success',
|