重构文件系统
This commit is contained in:
10
package-lock.json
generated
10
package-lock.json
generated
@@ -28,6 +28,7 @@
|
||||
"react-github-calendar": "^4.2.2",
|
||||
"react-hot-toast": "^2.4.1",
|
||||
"react-icons": "^4.12.0",
|
||||
"react-masonry-css": "^1.0.16",
|
||||
"react-router-dom": "^6.14.2",
|
||||
"react-toastify": "^9.1.3",
|
||||
"rehype-callouts": "^1.4.1",
|
||||
@@ -7546,6 +7547,15 @@
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"node_modules/react-masonry-css": {
|
||||
"version": "1.0.16",
|
||||
"resolved": "https://registry.npmmirror.com/react-masonry-css/-/react-masonry-css-1.0.16.tgz",
|
||||
"integrity": "sha512-KSW0hR2VQmltt/qAa3eXOctQDyOu7+ZBevtKgpNDSzT7k5LA/0XntNa9z9HKCdz3QlxmJHglTZ18e4sX4V8zZQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": ">=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-refresh": {
|
||||
"version": "0.14.0",
|
||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
"react-github-calendar": "^4.2.2",
|
||||
"react-hot-toast": "^2.4.1",
|
||||
"react-icons": "^4.12.0",
|
||||
"react-masonry-css": "^1.0.16",
|
||||
"react-router-dom": "^6.14.2",
|
||||
"react-toastify": "^9.1.3",
|
||||
"rehype-callouts": "^1.4.1",
|
||||
|
||||
@@ -1,28 +1,14 @@
|
||||
import Request from '@/utils/request'
|
||||
import { File } from '@/types/app/file'
|
||||
import { File, FileDir } from '@/types/app/file'
|
||||
|
||||
// 删除文件
|
||||
export const delFileDataAPI = (filePath: string) => Request<File>("DELETE", `/file?filePath=${filePath}`)
|
||||
export const delFileDataAPI = (filePath: string) => Request<File>("DELETE", `/file/plus?filePath=${filePath}`)
|
||||
|
||||
// 获取文件
|
||||
export const getFileDataAPI = (filePath: string) => Request<File>("GET", `/file/info?filePath=${filePath}`)
|
||||
export const getFileDataAPI = (filePath: string) => Request<File>("GET", `/file/plus/info?filePath=${filePath}`)
|
||||
|
||||
// 获取文件列表
|
||||
export const getFileListAPI = (data?: QueryData) => Request<File[]>("POST", `/file/list`, {
|
||||
data: { ...data?.query },
|
||||
params: {
|
||||
dir: data?.dir
|
||||
}
|
||||
})
|
||||
|
||||
// 分页获取文件列表
|
||||
export const getFilePagingAPI = (data?: QueryData) => Request<Paginate<File[]>>("POST", `/file/paging`, {
|
||||
data: { ...data?.query },
|
||||
params: {
|
||||
dir: data?.dir,
|
||||
...data?.pagination
|
||||
}
|
||||
})
|
||||
export const getFileListAPI = (dir: string) => Request<File[]>("GET", `/file/plus/list?dir=${dir}`)
|
||||
|
||||
// 获取目录列表
|
||||
export const getDirListAPI = () => Request<string[]>("GET", '/file/dir');;
|
||||
export const getDirListAPI = () => Request<FileDir[]>("GET", '/file/plus/dir')
|
||||
@@ -2,12 +2,12 @@ import { useRef, useState } from 'react';
|
||||
import { InboxOutlined } from '@ant-design/icons';
|
||||
import { message, Modal, Radio, Select, Spin } from 'antd';
|
||||
import { useUserStore } from '@/stores';
|
||||
import { FileDir } from '@/types/app/file';
|
||||
import { DirList } from '@/types/app/file';
|
||||
import { baseURL } from '@/utils/request';
|
||||
import Compressor from 'compressorjs';
|
||||
|
||||
interface UploadFileProps {
|
||||
dir: FileDir,
|
||||
dir: DirList,
|
||||
open: boolean,
|
||||
onSuccess: (urls: string[]) => void,
|
||||
onCancel: () => void
|
||||
@@ -52,7 +52,7 @@ export default ({ dir, open, onCancel, onSuccess }: UploadFileProps) => {
|
||||
}
|
||||
|
||||
// 发起网络请求
|
||||
const res = await fetch(`${baseURL}/file`, {
|
||||
const res = await fetch(`${baseURL}/file/plus`, {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
headers: {
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
.FilePage {
|
||||
.ant-image {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.ant-image-img {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,19 @@ import FileUpload from '@/components/FileUpload'
|
||||
|
||||
import fileSvg from './image/file.svg'
|
||||
import { delFileDataAPI, getDirListAPI, getFileListAPI } from '@/api/File'
|
||||
import { File } from '@/types/app/file'
|
||||
import { File, FileDir } from '@/types/app/file'
|
||||
import { PiKeyReturnFill } from "react-icons/pi";
|
||||
import { DeleteOutlined, DownloadOutlined, RotateLeftOutlined, RotateRightOutlined, SwapOutlined, UndoOutlined, ZoomInOutlined, ZoomOutOutlined, } from '@ant-design/icons';
|
||||
import Masonry from "react-masonry-css";
|
||||
import "./index.scss"
|
||||
|
||||
const breakpointColumnsObj = {
|
||||
default: 4,
|
||||
1100: 3,
|
||||
700: 2,
|
||||
500: 1
|
||||
};
|
||||
|
||||
export default () => {
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
@@ -17,7 +25,7 @@ export default () => {
|
||||
const [openFileInfoDrawer, setOpenFileInfoDrawer] = useState(false);
|
||||
const [openFilePreviewDrawer, setOpenFilePreviewDrawer] = useState(false);
|
||||
|
||||
const [dirList, setDirList] = useState<string[]>([])
|
||||
const [dirList, setDirList] = useState<FileDir[]>([])
|
||||
const [fileList, setFileList] = useState<File[]>([])
|
||||
|
||||
const [dirName, setDirName] = useState("")
|
||||
@@ -33,7 +41,7 @@ export default () => {
|
||||
|
||||
// 获取指定目录的文件列表
|
||||
const getFileList = async (dir: string) => {
|
||||
const { data } = await getFileListAPI({ dir })
|
||||
const { data } = await getFileListAPI(dir)
|
||||
|
||||
if (!fileList.length && !(data as File[]).length) message.error("该目录中没有文件")
|
||||
|
||||
@@ -44,7 +52,10 @@ export default () => {
|
||||
// 删除图片
|
||||
const onDeleteImage = async (data: File) => {
|
||||
setLoading(true)
|
||||
await delFileDataAPI(`${dirName}/${data.name}`)
|
||||
|
||||
let filePath = data.url.replace(/^https?:\/\//, '');
|
||||
|
||||
await delFileDataAPI(filePath)
|
||||
message.success("🎉 删除图片成功")
|
||||
getFileList(dirName)
|
||||
setFile({} as File)
|
||||
@@ -107,22 +118,36 @@ export default () => {
|
||||
{
|
||||
fileList.length
|
||||
? (
|
||||
fileList.map((item, index) =>
|
||||
<div
|
||||
key={index}
|
||||
className={`group relative overflow-hidden w-[21.625rem] h-44 p-[2px] flex flex-col items-center cursor-pointer m-4 border-2 ${file.url === item.url ? 'border-primary' : 'border-[#eee]'} rounded-md`}
|
||||
onClick={() => viewOpenFileInfo(item)}>
|
||||
<img src={item.url} alt="" className='rounded-md w-full h-full object-cover object-center' />
|
||||
</div>
|
||||
)
|
||||
<Masonry
|
||||
breakpointCols={breakpointColumnsObj}
|
||||
className="masonry-grid"
|
||||
columnClassName="masonry-grid_column"
|
||||
>
|
||||
{
|
||||
fileList.map((item, index) =>
|
||||
<div
|
||||
key={index}
|
||||
className={`group relative overflow-hidden rounded-md cursor-pointer mb-4 border-2 border-[#eee] dark:border-transparent hover:!border-primary p-1 ${file.url === item.url ? 'border-primary' : 'border-gray-100'}`}
|
||||
onClick={() => viewOpenFileInfo(item)}>
|
||||
<Image
|
||||
src={item.url}
|
||||
alt=""
|
||||
className='w-full rounded-md'
|
||||
loading="lazy"
|
||||
preview={false}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</Masonry>
|
||||
)
|
||||
: dirList.map((dir, index) => (
|
||||
: dirList.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className='group w-25 flex flex-col items-center cursor-pointer mx-4 my-2'
|
||||
onClick={() => openDir(dir)}>
|
||||
onClick={() => openDir(item.name)}>
|
||||
<img src={fileSvg} alt="" />
|
||||
<p className='group-hover:text-primary transition-colors'>{dir}</p>
|
||||
<p className='group-hover:text-primary transition-colors'>{item.name}</p>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
|
||||
@@ -38,4 +38,17 @@
|
||||
border-radius: 100% 60% 60% 100%/100% 100% 60% 60%;
|
||||
transform: translate3d(0, -3px, 0) rotate(.01deg)
|
||||
}
|
||||
}
|
||||
|
||||
// 瀑布流布局
|
||||
.masonry-grid {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.masonry-grid_column {
|
||||
padding-left: 10px;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
7
src/types/app/file.d.ts
vendored
7
src/types/app/file.d.ts
vendored
@@ -1,4 +1,4 @@
|
||||
export type FileDir = ("default" | "article" | "swiper" | string)
|
||||
export type DirList = ("default" | "article" | "swiper" | string)
|
||||
|
||||
export interface File {
|
||||
name: string;
|
||||
@@ -6,4 +6,9 @@ export interface File {
|
||||
type: string;
|
||||
url: string;
|
||||
createTime: number;
|
||||
}
|
||||
|
||||
export interface FileDir {
|
||||
path: string,
|
||||
name: string
|
||||
}
|
||||
Reference in New Issue
Block a user