重构文件系统
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-github-calendar": "^4.2.2",
|
||||||
"react-hot-toast": "^2.4.1",
|
"react-hot-toast": "^2.4.1",
|
||||||
"react-icons": "^4.12.0",
|
"react-icons": "^4.12.0",
|
||||||
|
"react-masonry-css": "^1.0.16",
|
||||||
"react-router-dom": "^6.14.2",
|
"react-router-dom": "^6.14.2",
|
||||||
"react-toastify": "^9.1.3",
|
"react-toastify": "^9.1.3",
|
||||||
"rehype-callouts": "^1.4.1",
|
"rehype-callouts": "^1.4.1",
|
||||||
@@ -7546,6 +7547,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
"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": {
|
"node_modules/react-refresh": {
|
||||||
"version": "0.14.0",
|
"version": "0.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
"react-github-calendar": "^4.2.2",
|
"react-github-calendar": "^4.2.2",
|
||||||
"react-hot-toast": "^2.4.1",
|
"react-hot-toast": "^2.4.1",
|
||||||
"react-icons": "^4.12.0",
|
"react-icons": "^4.12.0",
|
||||||
|
"react-masonry-css": "^1.0.16",
|
||||||
"react-router-dom": "^6.14.2",
|
"react-router-dom": "^6.14.2",
|
||||||
"react-toastify": "^9.1.3",
|
"react-toastify": "^9.1.3",
|
||||||
"rehype-callouts": "^1.4.1",
|
"rehype-callouts": "^1.4.1",
|
||||||
|
|||||||
@@ -1,28 +1,14 @@
|
|||||||
import Request from '@/utils/request'
|
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`, {
|
export const getFileListAPI = (dir: string) => Request<File[]>("GET", `/file/plus/list?dir=${dir}`)
|
||||||
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 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 { InboxOutlined } from '@ant-design/icons';
|
||||||
import { message, Modal, Radio, Select, Spin } from 'antd';
|
import { message, Modal, Radio, Select, Spin } from 'antd';
|
||||||
import { useUserStore } from '@/stores';
|
import { useUserStore } from '@/stores';
|
||||||
import { FileDir } from '@/types/app/file';
|
import { DirList } from '@/types/app/file';
|
||||||
import { baseURL } from '@/utils/request';
|
import { baseURL } from '@/utils/request';
|
||||||
import Compressor from 'compressorjs';
|
import Compressor from 'compressorjs';
|
||||||
|
|
||||||
interface UploadFileProps {
|
interface UploadFileProps {
|
||||||
dir: FileDir,
|
dir: DirList,
|
||||||
open: boolean,
|
open: boolean,
|
||||||
onSuccess: (urls: string[]) => void,
|
onSuccess: (urls: string[]) => void,
|
||||||
onCancel: () => 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",
|
method: "POST",
|
||||||
body: formData,
|
body: formData,
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
.FilePage {
|
.FilePage {
|
||||||
.ant-image {
|
.ant-image {
|
||||||
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
.ant-image-img {
|
.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 fileSvg from './image/file.svg'
|
||||||
import { delFileDataAPI, getDirListAPI, getFileListAPI } from '@/api/File'
|
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 { PiKeyReturnFill } from "react-icons/pi";
|
||||||
import { DeleteOutlined, DownloadOutlined, RotateLeftOutlined, RotateRightOutlined, SwapOutlined, UndoOutlined, ZoomInOutlined, ZoomOutOutlined, } from '@ant-design/icons';
|
import { DeleteOutlined, DownloadOutlined, RotateLeftOutlined, RotateRightOutlined, SwapOutlined, UndoOutlined, ZoomInOutlined, ZoomOutOutlined, } from '@ant-design/icons';
|
||||||
|
import Masonry from "react-masonry-css";
|
||||||
import "./index.scss"
|
import "./index.scss"
|
||||||
|
|
||||||
|
const breakpointColumnsObj = {
|
||||||
|
default: 4,
|
||||||
|
1100: 3,
|
||||||
|
700: 2,
|
||||||
|
500: 1
|
||||||
|
};
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
|
|
||||||
@@ -17,7 +25,7 @@ export default () => {
|
|||||||
const [openFileInfoDrawer, setOpenFileInfoDrawer] = useState(false);
|
const [openFileInfoDrawer, setOpenFileInfoDrawer] = useState(false);
|
||||||
const [openFilePreviewDrawer, setOpenFilePreviewDrawer] = useState(false);
|
const [openFilePreviewDrawer, setOpenFilePreviewDrawer] = useState(false);
|
||||||
|
|
||||||
const [dirList, setDirList] = useState<string[]>([])
|
const [dirList, setDirList] = useState<FileDir[]>([])
|
||||||
const [fileList, setFileList] = useState<File[]>([])
|
const [fileList, setFileList] = useState<File[]>([])
|
||||||
|
|
||||||
const [dirName, setDirName] = useState("")
|
const [dirName, setDirName] = useState("")
|
||||||
@@ -33,7 +41,7 @@ export default () => {
|
|||||||
|
|
||||||
// 获取指定目录的文件列表
|
// 获取指定目录的文件列表
|
||||||
const getFileList = async (dir: string) => {
|
const getFileList = async (dir: string) => {
|
||||||
const { data } = await getFileListAPI({ dir })
|
const { data } = await getFileListAPI(dir)
|
||||||
|
|
||||||
if (!fileList.length && !(data as File[]).length) message.error("该目录中没有文件")
|
if (!fileList.length && !(data as File[]).length) message.error("该目录中没有文件")
|
||||||
|
|
||||||
@@ -44,7 +52,10 @@ export default () => {
|
|||||||
// 删除图片
|
// 删除图片
|
||||||
const onDeleteImage = async (data: File) => {
|
const onDeleteImage = async (data: File) => {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
await delFileDataAPI(`${dirName}/${data.name}`)
|
|
||||||
|
let filePath = data.url.replace(/^https?:\/\//, '');
|
||||||
|
|
||||||
|
await delFileDataAPI(filePath)
|
||||||
message.success("🎉 删除图片成功")
|
message.success("🎉 删除图片成功")
|
||||||
getFileList(dirName)
|
getFileList(dirName)
|
||||||
setFile({} as File)
|
setFile({} as File)
|
||||||
@@ -107,22 +118,36 @@ export default () => {
|
|||||||
{
|
{
|
||||||
fileList.length
|
fileList.length
|
||||||
? (
|
? (
|
||||||
fileList.map((item, index) =>
|
<Masonry
|
||||||
<div
|
breakpointCols={breakpointColumnsObj}
|
||||||
key={index}
|
className="masonry-grid"
|
||||||
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`}
|
columnClassName="masonry-grid_column"
|
||||||
onClick={() => viewOpenFileInfo(item)}>
|
>
|
||||||
<img src={item.url} alt="" className='rounded-md w-full h-full object-cover object-center' />
|
{
|
||||||
</div>
|
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
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className='group w-25 flex flex-col items-center cursor-pointer mx-4 my-2'
|
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="" />
|
<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>
|
</div>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,4 +38,17 @@
|
|||||||
border-radius: 100% 60% 60% 100%/100% 100% 60% 60%;
|
border-radius: 100% 60% 60% 100%/100% 100% 60% 60%;
|
||||||
transform: translate3d(0, -3px, 0) rotate(.01deg)
|
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 {
|
export interface File {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -6,4 +6,9 @@ export interface File {
|
|||||||
type: string;
|
type: string;
|
||||||
url: string;
|
url: string;
|
||||||
createTime: number;
|
createTime: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FileDir {
|
||||||
|
path: string,
|
||||||
|
name: string
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user