mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-06-02 17:27:15 +08:00
### What problem does this PR solve? feat: Move files in file manager #1826 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
parent
4c2906d6fd
commit
c55e9d16da
6
web/src/assets/svg/move.svg
Normal file
6
web/src/assets/svg/move.svg
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<svg t="1722928702193" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6094"
|
||||||
|
width="200" height="200">
|
||||||
|
<path
|
||||||
|
d="M572.330667 597.333333H298.666667v-85.333333h273.664l-77.994667-77.994667L554.666667 373.632 735.701333 554.666667l-60.373333 60.330666L554.666667 735.701333l-60.330667-60.373333L572.330667 597.333333zM533.333333 263.509333H853.333333a85.333333 85.333333 0 0 1 85.333334 85.333334V810.666667a85.333333 85.333333 0 0 1-85.333334 85.333333H170.666667a85.333333 85.333333 0 0 1-85.333334-85.333333V213.333333a85.333333 85.333333 0 0 1 85.333334-85.333333h241.493333a85.333333 85.333333 0 0 1 76.117333 46.72L533.333333 263.509333z m0 85.333334a85.333333 85.333333 0 0 1-76.117333-46.72L412.202667 213.333333H170.666667v597.333334h682.666666V348.842667h-320z"
|
||||||
|
fill="#666666" p-id="6095"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 877 B |
@ -28,6 +28,23 @@ export interface IListResult {
|
|||||||
loading: boolean;
|
loading: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const useFetchPureFileList = () => {
|
||||||
|
const { mutateAsync, isPending: loading } = useMutation({
|
||||||
|
mutationKey: ['fetchPureFileList'],
|
||||||
|
gcTime: 0,
|
||||||
|
|
||||||
|
mutationFn: async (parentId: string) => {
|
||||||
|
const { data } = await fileManagerService.listFile({
|
||||||
|
parent_id: parentId,
|
||||||
|
});
|
||||||
|
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { loading, fetchList: mutateAsync };
|
||||||
|
};
|
||||||
|
|
||||||
export const useFetchFileList = (): ResponseType<any> & IListResult => {
|
export const useFetchFileList = (): ResponseType<any> & IListResult => {
|
||||||
const { searchString, handleInputChange } = useHandleSearchChange();
|
const { searchString, handleInputChange } = useHandleSearchChange();
|
||||||
const { pagination, setPagination } = useGetPaginationWithRouter();
|
const { pagination, setPagination } = useGetPaginationWithRouter();
|
||||||
@ -225,3 +242,31 @@ export const useConnectToKnowledge = () => {
|
|||||||
|
|
||||||
return { data, loading, connectFileToKnowledge: mutateAsync };
|
return { data, loading, connectFileToKnowledge: mutateAsync };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface IMoveFileBody {
|
||||||
|
src_file_ids: string[];
|
||||||
|
dest_file_id: string; // target folder id
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useMoveFile = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
isPending: loading,
|
||||||
|
mutateAsync,
|
||||||
|
} = useMutation({
|
||||||
|
mutationKey: ['moveFile'],
|
||||||
|
mutationFn: async (params: IMoveFileBody) => {
|
||||||
|
const { data } = await fileManagerService.moveFile(params);
|
||||||
|
if (data.retcode === 0) {
|
||||||
|
message.success(t('message.operated'));
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['fetchFileList'] });
|
||||||
|
}
|
||||||
|
return data.retcode;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { data, loading, moveFile: mutateAsync };
|
||||||
|
};
|
||||||
|
@ -26,6 +26,7 @@ export default {
|
|||||||
download: 'Download',
|
download: 'Download',
|
||||||
close: 'Close',
|
close: 'Close',
|
||||||
preview: 'Preview',
|
preview: 'Preview',
|
||||||
|
move: 'Move',
|
||||||
},
|
},
|
||||||
login: {
|
login: {
|
||||||
login: 'Sign in',
|
login: 'Sign in',
|
||||||
@ -564,6 +565,7 @@ The above is the content you need to summarize.`,
|
|||||||
fileError: 'File error',
|
fileError: 'File error',
|
||||||
uploadLimit:
|
uploadLimit:
|
||||||
'The file size cannot exceed 10M, and the total number of files cannot exceed 128',
|
'The file size cannot exceed 10M, and the total number of files cannot exceed 128',
|
||||||
|
destinationFolder: 'Destination folder',
|
||||||
},
|
},
|
||||||
flow: {
|
flow: {
|
||||||
cite: 'Cite',
|
cite: 'Cite',
|
||||||
|
@ -26,6 +26,7 @@ export default {
|
|||||||
download: '下載',
|
download: '下載',
|
||||||
close: '關閉',
|
close: '關閉',
|
||||||
preview: '預覽',
|
preview: '預覽',
|
||||||
|
move: '移動',
|
||||||
},
|
},
|
||||||
login: {
|
login: {
|
||||||
login: '登入',
|
login: '登入',
|
||||||
@ -524,6 +525,7 @@ export default {
|
|||||||
preview: '預覽',
|
preview: '預覽',
|
||||||
fileError: '文件錯誤',
|
fileError: '文件錯誤',
|
||||||
uploadLimit: '文件大小不能超過10M,文件總數不超過128個',
|
uploadLimit: '文件大小不能超過10M,文件總數不超過128個',
|
||||||
|
destinationFolder: '目標資料夾',
|
||||||
},
|
},
|
||||||
flow: {
|
flow: {
|
||||||
cite: '引用',
|
cite: '引用',
|
||||||
|
@ -26,6 +26,7 @@ export default {
|
|||||||
download: '下载',
|
download: '下载',
|
||||||
close: '关闭',
|
close: '关闭',
|
||||||
preview: '预览',
|
preview: '预览',
|
||||||
|
move: '移动',
|
||||||
},
|
},
|
||||||
login: {
|
login: {
|
||||||
login: '登录',
|
login: '登录',
|
||||||
@ -542,6 +543,7 @@ export default {
|
|||||||
preview: '预览',
|
preview: '预览',
|
||||||
fileError: '文件错误',
|
fileError: '文件错误',
|
||||||
uploadLimit: '文件大小不能超过10M,文件总数不超过128个',
|
uploadLimit: '文件大小不能超过10M,文件总数不超过128个',
|
||||||
|
destinationFolder: '目标文件夹',
|
||||||
},
|
},
|
||||||
flow: {
|
flow: {
|
||||||
flow: '工作流',
|
flow: '工作流',
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
|
import NewDocumentLink from '@/components/new-document-link';
|
||||||
|
import SvgIcon from '@/components/svg-icon';
|
||||||
import { useTranslate } from '@/hooks/common-hooks';
|
import { useTranslate } from '@/hooks/common-hooks';
|
||||||
import { IFile } from '@/interfaces/database/file-manager';
|
import { IFile } from '@/interfaces/database/file-manager';
|
||||||
import { api_host } from '@/utils/api';
|
import { api_host } from '@/utils/api';
|
||||||
|
import {
|
||||||
|
getExtension,
|
||||||
|
isSupportedPreviewDocumentType,
|
||||||
|
} from '@/utils/document-util';
|
||||||
import { downloadFile } from '@/utils/file-util';
|
import { downloadFile } from '@/utils/file-util';
|
||||||
import {
|
import {
|
||||||
DeleteOutlined,
|
DeleteOutlined,
|
||||||
@ -11,18 +17,13 @@ import {
|
|||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import { Button, Space, Tooltip } from 'antd';
|
import { Button, Space, Tooltip } from 'antd';
|
||||||
import { useHandleDeleteFile } from '../hooks';
|
import { useHandleDeleteFile } from '../hooks';
|
||||||
|
|
||||||
import NewDocumentLink from '@/components/new-document-link';
|
|
||||||
import {
|
|
||||||
getExtension,
|
|
||||||
isSupportedPreviewDocumentType,
|
|
||||||
} from '@/utils/document-util';
|
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
record: IFile;
|
record: IFile;
|
||||||
setCurrentRecord: (record: any) => void;
|
setCurrentRecord: (record: any) => void;
|
||||||
showRenameModal: (record: IFile) => void;
|
showRenameModal: (record: IFile) => void;
|
||||||
|
showMoveFileModal: (ids: string[]) => void;
|
||||||
showConnectToKnowledgeModal: (record: IFile) => void;
|
showConnectToKnowledgeModal: (record: IFile) => void;
|
||||||
setSelectedRowKeys(keys: string[]): void;
|
setSelectedRowKeys(keys: string[]): void;
|
||||||
}
|
}
|
||||||
@ -33,6 +34,7 @@ const ActionCell = ({
|
|||||||
showRenameModal,
|
showRenameModal,
|
||||||
showConnectToKnowledgeModal,
|
showConnectToKnowledgeModal,
|
||||||
setSelectedRowKeys,
|
setSelectedRowKeys,
|
||||||
|
showMoveFileModal,
|
||||||
}: IProps) => {
|
}: IProps) => {
|
||||||
const documentId = record.id;
|
const documentId = record.id;
|
||||||
const beingUsed = false;
|
const beingUsed = false;
|
||||||
@ -64,6 +66,10 @@ const ActionCell = ({
|
|||||||
showConnectToKnowledgeModal(record);
|
showConnectToKnowledgeModal(record);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onShowMoveFileModal = () => {
|
||||||
|
showMoveFileModal([documentId]);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Space size={0}>
|
<Space size={0}>
|
||||||
{isKnowledgeBase || (
|
{isKnowledgeBase || (
|
||||||
@ -90,6 +96,18 @@ const ActionCell = ({
|
|||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
|
{isKnowledgeBase || (
|
||||||
|
<Tooltip title={t('move', { keyPrefix: 'common' })}>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
disabled={beingUsed}
|
||||||
|
onClick={onShowMoveFileModal}
|
||||||
|
className={styles.iconButton}
|
||||||
|
>
|
||||||
|
<SvgIcon name={`move`} width={16}></SvgIcon>
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
{isKnowledgeBase || (
|
{isKnowledgeBase || (
|
||||||
<Tooltip title={t('delete', { keyPrefix: 'common' })}>
|
<Tooltip title={t('delete', { keyPrefix: 'common' })}>
|
||||||
<Button
|
<Button
|
||||||
|
@ -17,13 +17,14 @@ import {
|
|||||||
MenuProps,
|
MenuProps,
|
||||||
Space,
|
Space,
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import { useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import {
|
import {
|
||||||
useHandleBreadcrumbClick,
|
useHandleBreadcrumbClick,
|
||||||
useHandleDeleteFile,
|
useHandleDeleteFile,
|
||||||
useSelectBreadcrumbItems,
|
useSelectBreadcrumbItems,
|
||||||
} from './hooks';
|
} from './hooks';
|
||||||
|
|
||||||
|
import SvgIcon from '@/components/svg-icon';
|
||||||
import {
|
import {
|
||||||
IListResult,
|
IListResult,
|
||||||
useFetchParentFolderList,
|
useFetchParentFolderList,
|
||||||
@ -36,6 +37,7 @@ interface IProps
|
|||||||
showFolderCreateModal: () => void;
|
showFolderCreateModal: () => void;
|
||||||
showFileUploadModal: () => void;
|
showFileUploadModal: () => void;
|
||||||
setSelectedRowKeys: (keys: string[]) => void;
|
setSelectedRowKeys: (keys: string[]) => void;
|
||||||
|
showMoveFileModal: (ids: string[]) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FileToolbar = ({
|
const FileToolbar = ({
|
||||||
@ -45,6 +47,7 @@ const FileToolbar = ({
|
|||||||
setSelectedRowKeys,
|
setSelectedRowKeys,
|
||||||
searchString,
|
searchString,
|
||||||
handleInputChange,
|
handleInputChange,
|
||||||
|
showMoveFileModal,
|
||||||
}: IProps) => {
|
}: IProps) => {
|
||||||
const { t } = useTranslate('knowledgeDetails');
|
const { t } = useTranslate('knowledgeDetails');
|
||||||
const breadcrumbItems = useSelectBreadcrumbItems();
|
const breadcrumbItems = useSelectBreadcrumbItems();
|
||||||
@ -111,6 +114,10 @@ const FileToolbar = ({
|
|||||||
setSelectedRowKeys,
|
setSelectedRowKeys,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleShowMoveFileModal = useCallback(() => {
|
||||||
|
showMoveFileModal(selectedRowKeys);
|
||||||
|
}, [selectedRowKeys, showMoveFileModal]);
|
||||||
|
|
||||||
const disabled = selectedRowKeys.length === 0;
|
const disabled = selectedRowKeys.length === 0;
|
||||||
|
|
||||||
const items: MenuProps['items'] = useMemo(() => {
|
const items: MenuProps['items'] = useMemo(() => {
|
||||||
@ -127,8 +134,20 @@ const FileToolbar = ({
|
|||||||
</Flex>
|
</Flex>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: '5',
|
||||||
|
onClick: handleShowMoveFileModal,
|
||||||
|
label: (
|
||||||
|
<Flex gap={10}>
|
||||||
|
<span className={styles.deleteIconWrapper}>
|
||||||
|
<SvgIcon name={`move`} width={18}></SvgIcon>
|
||||||
|
</span>
|
||||||
|
<b>{t('move', { keyPrefix: 'common' })}</b>
|
||||||
|
</Flex>
|
||||||
|
),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
}, [handleRemoveFile, t]);
|
}, [handleShowMoveFileModal, t, handleRemoveFile]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.filter}>
|
<div className={styles.filter}>
|
||||||
|
@ -21,24 +21,12 @@ const FolderCreateModal = ({ visible, hideModal, loading, onOk }: IProps) => {
|
|||||||
return onOk(ret.name);
|
return onOk(ret.name);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
|
||||||
hideModal();
|
|
||||||
};
|
|
||||||
|
|
||||||
const onFinish = (values: any) => {
|
|
||||||
console.log('Success:', values);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onFinishFailed = (errorInfo: any) => {
|
|
||||||
console.log('Failed:', errorInfo);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title={t('newFolder', { keyPrefix: 'fileManager' })}
|
title={t('newFolder', { keyPrefix: 'fileManager' })}
|
||||||
open={visible}
|
open={visible}
|
||||||
onOk={handleOk}
|
onOk={handleOk}
|
||||||
onCancel={handleCancel}
|
onCancel={hideModal}
|
||||||
okButtonProps={{ loading }}
|
okButtonProps={{ loading }}
|
||||||
confirmLoading={loading}
|
confirmLoading={loading}
|
||||||
>
|
>
|
||||||
@ -47,8 +35,6 @@ const FolderCreateModal = ({ visible, hideModal, loading, onOk }: IProps) => {
|
|||||||
labelCol={{ span: 4 }}
|
labelCol={{ span: 4 }}
|
||||||
wrapperCol={{ span: 20 }}
|
wrapperCol={{ span: 20 }}
|
||||||
style={{ maxWidth: 600 }}
|
style={{ maxWidth: 600 }}
|
||||||
onFinish={onFinish}
|
|
||||||
onFinishFailed={onFinishFailed}
|
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
form={form}
|
form={form}
|
||||||
>
|
>
|
||||||
|
@ -4,6 +4,7 @@ import {
|
|||||||
useCreateFolder,
|
useCreateFolder,
|
||||||
useDeleteFile,
|
useDeleteFile,
|
||||||
useFetchParentFolderList,
|
useFetchParentFolderList,
|
||||||
|
useMoveFile,
|
||||||
useRenameFile,
|
useRenameFile,
|
||||||
useUploadFile,
|
useUploadFile,
|
||||||
} from '@/hooks/file-manager-hooks';
|
} from '@/hooks/file-manager-hooks';
|
||||||
@ -246,3 +247,48 @@ export const useHandleBreadcrumbClick = () => {
|
|||||||
|
|
||||||
return { handleBreadcrumbClick };
|
return { handleBreadcrumbClick };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useHandleMoveFile = (
|
||||||
|
setSelectedRowKeys: (keys: string[]) => void,
|
||||||
|
) => {
|
||||||
|
const {
|
||||||
|
visible: moveFileVisible,
|
||||||
|
hideModal: hideMoveFileModal,
|
||||||
|
showModal: showMoveFileModal,
|
||||||
|
} = useSetModalState();
|
||||||
|
const { moveFile, loading } = useMoveFile();
|
||||||
|
const [sourceFileIds, setSourceFileIds] = useState<string[]>([]);
|
||||||
|
|
||||||
|
const onMoveFileOk = useCallback(
|
||||||
|
async (targetFolderId: string) => {
|
||||||
|
const ret = await moveFile({
|
||||||
|
src_file_ids: sourceFileIds,
|
||||||
|
dest_file_id: targetFolderId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (ret === 0) {
|
||||||
|
setSelectedRowKeys([]);
|
||||||
|
hideMoveFileModal();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
},
|
||||||
|
[moveFile, hideMoveFileModal, sourceFileIds, setSelectedRowKeys],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleShowMoveFileModal = useCallback(
|
||||||
|
(ids: string[]) => {
|
||||||
|
setSourceFileIds(ids);
|
||||||
|
showMoveFileModal();
|
||||||
|
},
|
||||||
|
[showMoveFileModal],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
initialValue: '',
|
||||||
|
moveFileLoading: loading,
|
||||||
|
onMoveFileOk,
|
||||||
|
moveFileVisible,
|
||||||
|
hideMoveFileModal,
|
||||||
|
showMoveFileModal: handleShowMoveFileModal,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
@ -9,6 +9,7 @@ import {
|
|||||||
useGetRowSelection,
|
useGetRowSelection,
|
||||||
useHandleConnectToKnowledge,
|
useHandleConnectToKnowledge,
|
||||||
useHandleCreateFolder,
|
useHandleCreateFolder,
|
||||||
|
useHandleMoveFile,
|
||||||
useHandleUploadFile,
|
useHandleUploadFile,
|
||||||
useNavigateToOtherFolder,
|
useNavigateToOtherFolder,
|
||||||
useRenameCurrentFile,
|
useRenameCurrentFile,
|
||||||
@ -23,6 +24,7 @@ import { getExtension } from '@/utils/document-util';
|
|||||||
import ConnectToKnowledgeModal from './connect-to-knowledge-modal';
|
import ConnectToKnowledgeModal from './connect-to-knowledge-modal';
|
||||||
import FolderCreateModal from './folder-create-modal';
|
import FolderCreateModal from './folder-create-modal';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
|
import FileMovingModal from './move-file-modal';
|
||||||
|
|
||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
|
||||||
@ -61,7 +63,13 @@ const FileManager = () => {
|
|||||||
initialValue,
|
initialValue,
|
||||||
connectToKnowledgeLoading,
|
connectToKnowledgeLoading,
|
||||||
} = useHandleConnectToKnowledge();
|
} = useHandleConnectToKnowledge();
|
||||||
// const { pagination } = useGetFilesPagination();
|
const {
|
||||||
|
showMoveFileModal,
|
||||||
|
moveFileVisible,
|
||||||
|
onMoveFileOk,
|
||||||
|
hideMoveFileModal,
|
||||||
|
moveFileLoading,
|
||||||
|
} = useHandleMoveFile(setSelectedRowKeys);
|
||||||
const { pagination, data, searchString, handleInputChange, loading } =
|
const { pagination, data, searchString, handleInputChange, loading } =
|
||||||
useFetchFileList();
|
useFetchFileList();
|
||||||
const columns: ColumnsType<IFile> = [
|
const columns: ColumnsType<IFile> = [
|
||||||
@ -139,6 +147,7 @@ const FileManager = () => {
|
|||||||
console.info(record);
|
console.info(record);
|
||||||
}}
|
}}
|
||||||
showRenameModal={showFileRenameModal}
|
showRenameModal={showFileRenameModal}
|
||||||
|
showMoveFileModal={showMoveFileModal}
|
||||||
showConnectToKnowledgeModal={showConnectToKnowledgeModal}
|
showConnectToKnowledgeModal={showConnectToKnowledgeModal}
|
||||||
setSelectedRowKeys={setSelectedRowKeys}
|
setSelectedRowKeys={setSelectedRowKeys}
|
||||||
></ActionCell>
|
></ActionCell>
|
||||||
@ -155,6 +164,7 @@ const FileManager = () => {
|
|||||||
showFolderCreateModal={showFolderCreateModal}
|
showFolderCreateModal={showFolderCreateModal}
|
||||||
showFileUploadModal={showFileUploadModal}
|
showFileUploadModal={showFileUploadModal}
|
||||||
setSelectedRowKeys={setSelectedRowKeys}
|
setSelectedRowKeys={setSelectedRowKeys}
|
||||||
|
showMoveFileModal={showMoveFileModal}
|
||||||
></FileToolbar>
|
></FileToolbar>
|
||||||
<Table
|
<Table
|
||||||
dataSource={data?.files}
|
dataSource={data?.files}
|
||||||
@ -191,6 +201,14 @@ const FileManager = () => {
|
|||||||
onOk={onConnectToKnowledgeOk}
|
onOk={onConnectToKnowledgeOk}
|
||||||
loading={connectToKnowledgeLoading}
|
loading={connectToKnowledgeLoading}
|
||||||
></ConnectToKnowledgeModal>
|
></ConnectToKnowledgeModal>
|
||||||
|
{moveFileVisible && (
|
||||||
|
<FileMovingModal
|
||||||
|
visible={moveFileVisible}
|
||||||
|
hideModal={hideMoveFileModal}
|
||||||
|
onOk={onMoveFileOk}
|
||||||
|
loading={moveFileLoading}
|
||||||
|
></FileMovingModal>
|
||||||
|
)}
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
import { useFetchPureFileList } from '@/hooks/file-manager-hooks';
|
||||||
|
import { IFile } from '@/interfaces/database/file-manager';
|
||||||
|
import type { GetProp, TreeSelectProps } from 'antd';
|
||||||
|
import { TreeSelect } from 'antd';
|
||||||
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
type DefaultOptionType = GetProp<TreeSelectProps, 'treeData'>[number];
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
value?: string;
|
||||||
|
onChange?: (value: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AsyncTreeSelect = ({ value, onChange }: IProps) => {
|
||||||
|
const { fetchList } = useFetchPureFileList();
|
||||||
|
const [treeData, setTreeData] = useState<Omit<DefaultOptionType, 'label'>[]>(
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
const onLoadData: TreeSelectProps['loadData'] = useCallback(
|
||||||
|
async ({ id }) => {
|
||||||
|
const ret = await fetchList(id);
|
||||||
|
if (ret.retcode === 0) {
|
||||||
|
setTreeData((tree) => {
|
||||||
|
return tree.concat(
|
||||||
|
ret.data.files
|
||||||
|
.filter((x: IFile) => x.type === 'folder')
|
||||||
|
.map((x: IFile) => ({
|
||||||
|
id: x.id,
|
||||||
|
pId: x.parent_id,
|
||||||
|
value: x.id,
|
||||||
|
title: x.name,
|
||||||
|
isLeaf: false,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[fetchList],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleChange = (newValue: string) => {
|
||||||
|
onChange?.(newValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
onLoadData?.({ id: '', props: '' });
|
||||||
|
}, [onLoadData]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TreeSelect
|
||||||
|
treeDataSimpleMode
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
value={value}
|
||||||
|
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
|
||||||
|
placeholder="Please select"
|
||||||
|
onChange={handleChange}
|
||||||
|
loadData={onLoadData}
|
||||||
|
treeData={treeData}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AsyncTreeSelect;
|
54
web/src/pages/file-manager/move-file-modal/index.tsx
Normal file
54
web/src/pages/file-manager/move-file-modal/index.tsx
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { IModalManagerChildrenProps } from '@/components/modal-manager';
|
||||||
|
import { useTranslate } from '@/hooks/common-hooks';
|
||||||
|
import { Form, Modal } from 'antd';
|
||||||
|
import AsyncTreeSelect from './async-tree-select';
|
||||||
|
|
||||||
|
interface IProps extends Omit<IModalManagerChildrenProps, 'showModal'> {
|
||||||
|
loading: boolean;
|
||||||
|
onOk: (id: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FileMovingModal = ({ visible, hideModal, loading, onOk }: IProps) => {
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
const { t } = useTranslate('fileManager');
|
||||||
|
|
||||||
|
type FieldType = {
|
||||||
|
name?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOk = async () => {
|
||||||
|
const ret = await form.validateFields();
|
||||||
|
|
||||||
|
return onOk(ret.name);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
title={t('move', { keyPrefix: 'common' })}
|
||||||
|
open={visible}
|
||||||
|
onOk={handleOk}
|
||||||
|
onCancel={hideModal}
|
||||||
|
okButtonProps={{ loading }}
|
||||||
|
confirmLoading={loading}
|
||||||
|
width={600}
|
||||||
|
>
|
||||||
|
<Form
|
||||||
|
name="basic"
|
||||||
|
labelCol={{ span: 6 }}
|
||||||
|
wrapperCol={{ span: 18 }}
|
||||||
|
autoComplete="off"
|
||||||
|
form={form}
|
||||||
|
>
|
||||||
|
<Form.Item<FieldType>
|
||||||
|
label={t('destinationFolder')}
|
||||||
|
name="name"
|
||||||
|
rules={[{ required: true, message: t('pleaseSelect') }]}
|
||||||
|
>
|
||||||
|
<AsyncTreeSelect></AsyncTreeSelect>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FileMovingModal;
|
@ -13,6 +13,7 @@ const {
|
|||||||
connectFileToKnowledge,
|
connectFileToKnowledge,
|
||||||
get_document_file,
|
get_document_file,
|
||||||
getFile,
|
getFile,
|
||||||
|
moveFile,
|
||||||
} = api;
|
} = api;
|
||||||
|
|
||||||
const methods = {
|
const methods = {
|
||||||
@ -49,6 +50,10 @@ const methods = {
|
|||||||
method: 'get',
|
method: 'get',
|
||||||
responseType: 'blob',
|
responseType: 'blob',
|
||||||
},
|
},
|
||||||
|
moveFile: {
|
||||||
|
url: moveFile,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
const fileManagerService = registerServer<keyof typeof methods>(
|
const fileManagerService = registerServer<keyof typeof methods>(
|
||||||
|
@ -79,6 +79,7 @@ export default {
|
|||||||
createFolder: `${api_host}/file/create`,
|
createFolder: `${api_host}/file/create`,
|
||||||
connectFileToKnowledge: `${api_host}/file2document/convert`,
|
connectFileToKnowledge: `${api_host}/file2document/convert`,
|
||||||
getFile: `${api_host}/file/get`,
|
getFile: `${api_host}/file/get`,
|
||||||
|
moveFile: `${api_host}/file/mv`,
|
||||||
|
|
||||||
// system
|
// system
|
||||||
getSystemVersion: `${api_host}/system/version`,
|
getSystemVersion: `${api_host}/system/version`,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user