238 lines
6.5 KiB
TypeScript
238 lines
6.5 KiB
TypeScript
|
|
import { Button } from "@/components/ui/button";
|
|||
|
|
import {
|
|||
|
|
Dialog,
|
|||
|
|
DialogClose,
|
|||
|
|
DialogContent,
|
|||
|
|
DialogFooter,
|
|||
|
|
DialogHeader,
|
|||
|
|
DialogTitle,
|
|||
|
|
} from "@/components/ui/dialog";
|
|||
|
|
import { Spinner } from "@/components/ui/spinner";
|
|||
|
|
import { FileType, getFilePage } from "@/apis/file";
|
|||
|
|
import { Folder, FolderInput, CircleAlert, MoveRight } from "lucide-react";
|
|||
|
|
import clsx from "clsx";
|
|||
|
|
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
|||
|
|
import { DirectoryBreadcrumb } from "@/components/directory-breadcrumb";
|
|||
|
|
import { DataTable } from "@/components/data-table";
|
|||
|
|
import { Pagination } from "@/components/pagination";
|
|||
|
|
import { useMoveFile } from "@/hooks/use-move-flie";
|
|||
|
|
import { useEffect, useMemo, useState } from "react";
|
|||
|
|
import { getCoreRowModel, useReactTable } from "@tanstack/react-table";
|
|||
|
|
import { useQuery } from "@tanstack/react-query";
|
|||
|
|
|
|||
|
|
export function useColumns(handleChangeParentId: any) {
|
|||
|
|
return [
|
|||
|
|
{
|
|||
|
|
accessorKey: "fileName",
|
|||
|
|
header: "目录名",
|
|||
|
|
size: 200,
|
|||
|
|
cell: ({ row }: any) => (
|
|||
|
|
<div
|
|||
|
|
className={clsx(
|
|||
|
|
"w-full flex items-center gap-1 break-all",
|
|||
|
|
"cursor-pointer hover:underline hover:text-primary group",
|
|||
|
|
)}
|
|||
|
|
onClick={() => {
|
|||
|
|
handleChangeParentId(row?.original);
|
|||
|
|
}}
|
|||
|
|
>
|
|||
|
|
<Folder size={18} className="text-amber-500 group-hover:hidden" />
|
|||
|
|
<FolderInput
|
|||
|
|
size={18}
|
|||
|
|
className="text-amber-500 group-hover:block hidden"
|
|||
|
|
/>
|
|||
|
|
<span>{row.getValue("fileName")}</span>
|
|||
|
|
</div>
|
|||
|
|
),
|
|||
|
|
},
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
type MoveFileDialogProps = {
|
|||
|
|
open: boolean;
|
|||
|
|
setOpen: (open: boolean) => void;
|
|||
|
|
data?: any;
|
|||
|
|
refetch?: () => void;
|
|||
|
|
params: any;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
export function MoveFileDialog({
|
|||
|
|
open,
|
|||
|
|
setOpen,
|
|||
|
|
data,
|
|||
|
|
refetch,
|
|||
|
|
params,
|
|||
|
|
}: MoveFileDialogProps) {
|
|||
|
|
// 选中行
|
|||
|
|
const [rowSelection, setRowSelection] = useState({});
|
|||
|
|
// 当前打开的目录层级
|
|||
|
|
const [openDirectorys, setOpenDirectorys] = useState([]);
|
|||
|
|
// 文件目录ID
|
|||
|
|
const [parentId, setParentId] = useState(0);
|
|||
|
|
// 分页
|
|||
|
|
const [pagination, setPagination] = useState({
|
|||
|
|
pageIndex: 0,
|
|||
|
|
pageSize: 10,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 查询数据
|
|||
|
|
const query = useQuery<any>({
|
|||
|
|
queryKey: ["moveFiles", pagination, parentId, params],
|
|||
|
|
queryFn: () =>
|
|||
|
|
getFilePage({
|
|||
|
|
...params,
|
|||
|
|
parentId: parentId || 0,
|
|||
|
|
pageSize: pagination.pageSize,
|
|||
|
|
pageNo: pagination.pageIndex + 1,
|
|||
|
|
fileType: FileType.DIRECTORY,
|
|||
|
|
}).then((res) => res.data),
|
|||
|
|
enabled: open,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 切换上级ID
|
|||
|
|
const handleChangeParentId = (record: any) => {
|
|||
|
|
setParentId(record.id);
|
|||
|
|
// 重置分页
|
|||
|
|
table.setPageIndex(0);
|
|||
|
|
// @ts-ignore
|
|||
|
|
setOpenDirectorys((prev: any) => [...prev, record]);
|
|||
|
|
// 重置选中数据
|
|||
|
|
table.resetRowSelection();
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 过滤当前目录
|
|||
|
|
const list = useMemo(
|
|||
|
|
() =>
|
|||
|
|
query?.data?.entityList?.filter((item: any) => item.id !== data?.id) ||
|
|||
|
|
[],
|
|||
|
|
[query, data],
|
|||
|
|
);
|
|||
|
|
// 表格
|
|||
|
|
const columns = useColumns(handleChangeParentId);
|
|||
|
|
const table = useReactTable({
|
|||
|
|
data: list,
|
|||
|
|
columns,
|
|||
|
|
getCoreRowModel: getCoreRowModel(),
|
|||
|
|
manualPagination: false,
|
|||
|
|
rowCount: query?.data?.totalCount || 0,
|
|||
|
|
pageCount: query?.data?.pageCount || 0,
|
|||
|
|
onPaginationChange: setPagination,
|
|||
|
|
autoResetPageIndex: false,
|
|||
|
|
onRowSelectionChange: setRowSelection,
|
|||
|
|
state: {
|
|||
|
|
pagination,
|
|||
|
|
rowSelection,
|
|||
|
|
},
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const changeOpenDirectorys = (record?: any) => {
|
|||
|
|
setParentId(record?.id);
|
|||
|
|
// 重置分页
|
|||
|
|
table.setPageIndex(0);
|
|||
|
|
// @ts-ignore
|
|||
|
|
setOpenDirectorys((prev: any[]) => {
|
|||
|
|
const index = prev.findIndex((item: any) => item.id === record?.id);
|
|||
|
|
if (index > -1) {
|
|||
|
|
return [...prev.slice(0, index + 1)];
|
|||
|
|
}
|
|||
|
|
return [];
|
|||
|
|
});
|
|||
|
|
// 重置选中数据
|
|||
|
|
table.resetRowSelection();
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 重置
|
|||
|
|
const reset = () => {
|
|||
|
|
setParentId(0);
|
|||
|
|
// 重置分页
|
|||
|
|
table.setPageIndex(0);
|
|||
|
|
// @ts-ignore
|
|||
|
|
setOpenDirectorys([]);
|
|||
|
|
// 重置选中数据
|
|||
|
|
table.resetRowSelection();
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const { move, moveIsPending } = useMoveFile({
|
|||
|
|
onSuccess: () => {
|
|||
|
|
refetch?.();
|
|||
|
|
setOpen(false);
|
|||
|
|
},
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const handleSubmit = () => {
|
|||
|
|
move({
|
|||
|
|
...data,
|
|||
|
|
parentId,
|
|||
|
|
});
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
useEffect(() => {
|
|||
|
|
if (open) {
|
|||
|
|
reset();
|
|||
|
|
}
|
|||
|
|
}, [open]);
|
|||
|
|
|
|||
|
|
const currentDirectory = useMemo(
|
|||
|
|
() => openDirectorys?.[openDirectorys?.length - 1],
|
|||
|
|
[openDirectorys],
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<Dialog open={open} onOpenChange={setOpen}>
|
|||
|
|
<DialogContent className="w-[680px]">
|
|||
|
|
<DialogHeader>
|
|||
|
|
<DialogTitle>
|
|||
|
|
{data?.fileType === FileType.DIRECTORY ? "移动目录" : "移动文件"}
|
|||
|
|
</DialogTitle>
|
|||
|
|
</DialogHeader>
|
|||
|
|
|
|||
|
|
<div className="overflow-hidden space-y-2">
|
|||
|
|
<DirectoryBreadcrumb
|
|||
|
|
directorys={openDirectorys}
|
|||
|
|
onChangeDirectorys={changeOpenDirectorys}
|
|||
|
|
/>
|
|||
|
|
<div className="max-h-[400px] overflow-y-auto relative border rounded-lg">
|
|||
|
|
<DataTable table={table} query={query} />
|
|||
|
|
<Pagination
|
|||
|
|
table={table}
|
|||
|
|
simple
|
|||
|
|
className="p-2 justify-end sticky bottom-0 left-0 right-0 z-10 bg-white"
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div className="flex items-center gap-2 text-sm overflow-hidden">
|
|||
|
|
<span className="flex-1 overflow-hidden text-primary clamp-1 truncate p-2 rounded-lg bg-gray-100">
|
|||
|
|
{data?.fileName}
|
|||
|
|
</span>
|
|||
|
|
<MoveRight size={16} className="flex-none" />
|
|||
|
|
<span className="flex-1 overflow-hidden text-amber-500 clamp-1 truncate inline-flex items-center gap-1 p-2 rounded-lg bg-gray-100">
|
|||
|
|
<Folder size={16} className="flex-none " />
|
|||
|
|
{currentDirectory?.fileName || "根目录"}
|
|||
|
|
</span>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<Alert className="!bg-amber-50 !border-amber-200">
|
|||
|
|
<CircleAlert />
|
|||
|
|
<AlertTitle>
|
|||
|
|
您确定要将{data?.fileType === FileType.DIRECTORY ? "目录" : "文件"}
|
|||
|
|
移动到该目录下吗?
|
|||
|
|
</AlertTitle>
|
|||
|
|
<AlertDescription>
|
|||
|
|
如果是目录,则目录下的所有文件和子目录都会被移动
|
|||
|
|
</AlertDescription>
|
|||
|
|
</Alert>
|
|||
|
|
|
|||
|
|
<DialogFooter>
|
|||
|
|
<DialogClose asChild>
|
|||
|
|
<Button variant="outline">取消</Button>
|
|||
|
|
</DialogClose>
|
|||
|
|
<Button type="submit" disabled={moveIsPending} onClick={handleSubmit}>
|
|||
|
|
{moveIsPending && <Spinner />}确定
|
|||
|
|
</Button>
|
|||
|
|
</DialogFooter>
|
|||
|
|
</DialogContent>
|
|||
|
|
</Dialog>
|
|||
|
|
);
|
|||
|
|
}
|