237 lines
6.5 KiB
TypeScript
237 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, 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<any[]>([]);
|
||
// 文件目录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">
|
||
<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>
|
||
);
|
||
}
|