diff --git a/src/common/model/global/i18n/LangEn.ts b/src/common/model/global/i18n/LangEn.ts index d1dce02..d3b207f 100644 --- a/src/common/model/global/i18n/LangEn.ts +++ b/src/common/model/global/i18n/LangEn.ts @@ -160,6 +160,13 @@ let LangEn = { canIUse: 'To see if the current browser supports it', intoRecycleBin: 'Recycle bin', finishingTip: 'Please wait while files are sorted...', + crawl: 'Crawl File', + crawlLink: 'Link', + crawlLinkTip: 'Please enter link', + crawlFilename: 'Filename', + crawlFilenameTip: 'Please enter filename', + crawlBackground: 'Background', + crawlSuccessTip: 'Crawl successfully', }, router: { allFiles: 'All Files', @@ -415,6 +422,7 @@ let LangEn = { refresh: 'refresh', inputRequired: 'Input required', selectRequired: 'Select required', + more: 'More', }; export default LangEn; diff --git a/src/common/model/global/i18n/LangZh.ts b/src/common/model/global/i18n/LangZh.ts index 557d611..2af6913 100644 --- a/src/common/model/global/i18n/LangZh.ts +++ b/src/common/model/global/i18n/LangZh.ts @@ -154,6 +154,13 @@ let LangZh = { canIUse: '查看当前浏览器是否支持,点击跳转', intoRecycleBin: '放入回收站', finishingTip: '后台文件整理中,请稍候...', + crawl: '抓取文件', + crawlLink: '链接', + crawlLinkTip: '请输入链接', + crawlFilename: '文件名', + crawlFilenameTip: '请输入文件名', + crawlBackground: '后台抓取', + crawlSuccessTip: '抓取成功', }, router: { allFiles: '全部文件', @@ -408,6 +415,7 @@ let LangZh = { refresh: '刷新', inputRequired: '该项必填', selectRequired: '该项必选', + more: '更多', }; export default LangZh; diff --git a/src/common/model/matter/Matter.ts b/src/common/model/matter/Matter.ts index e428f06..610a93f 100644 --- a/src/common/model/matter/Matter.ts +++ b/src/common/model/matter/Matter.ts @@ -68,9 +68,9 @@ export default class Matter extends BaseEntity { static URL_MATTER_RENAME = '/api/matter/rename'; static URL_CHANGE_PRIVACY = '/api/matter/change/privacy'; static URL_MATTER_MOVE = '/api/matter/move'; - static URL_MATTER_DOWNLOAD = '/api/matter/download'; static URL_MATTER_UPLOAD = '/api/matter/upload'; static URL_MATTER_ZIP = '/api/matter/zip'; + static URL_MATTER_CRAWL = '/api/matter/crawl'; static MATTER_ROOT = 'root'; @@ -244,6 +244,28 @@ export default class Matter extends BaseEntity { ); } + static httpCrawl( + body: { + url: string; + puuid: string; + filename: string; + spaceUuid: string; + }, + successCallback?: any, + errorCallback?: any, + finallyCallback?: any + ) { + new HttpBase().httpPost( + Matter.URL_MATTER_CRAWL, + body, + function (response: any) { + typeof successCallback === 'function' && successCallback(response); + }, + errorCallback, + finallyCallback + ); + } + static httpDeleteBatch( uuids: string, spaceUuid: string, diff --git a/src/common/util/OptimizeUtil.ts b/src/common/util/OptimizeUtil.ts index e1e7bdc..8ee4fa9 100644 --- a/src/common/util/OptimizeUtil.ts +++ b/src/common/util/OptimizeUtil.ts @@ -1,9 +1,11 @@ export const debounce = (func: Function, wait: number) => { let timer: any = null; - return () => { + return (args?: any) => { if (timer) { clearTimeout(timer); } - timer = setTimeout(func, wait); + timer = setTimeout(() => { + func.call(this, args); + }, wait); }; }; diff --git a/src/pages/layout/widget/Capacity.tsx b/src/pages/layout/widget/Capacity.tsx index e0db11c..3e6c2bd 100644 --- a/src/pages/layout/widget/Capacity.tsx +++ b/src/pages/layout/widget/Capacity.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { Progress } from 'antd'; import TankComponent from '../../../common/component/TankComponent'; -import FileUtil from '../../../common/util/FileUtil'; import Moon from '../../../common/model/global/Moon'; import User from '../../../common/model/user/User'; import { debounce } from '../../../common/util/OptimizeUtil'; diff --git a/src/pages/matter/List.tsx b/src/pages/matter/List.tsx index 67fc38d..68e7dd1 100644 --- a/src/pages/matter/List.tsx +++ b/src/pages/matter/List.tsx @@ -11,8 +11,11 @@ import UploadMatterPanel from './widget/UploadMatterPanel'; import { Button, Col, + Dropdown, Empty, Input, + Menu, + message, Modal, Pagination, Row, @@ -21,12 +24,14 @@ import { } from 'antd'; import MessageBoxUtil from '../../common/util/MessageBoxUtil'; import { + CloudDownloadOutlined, CloudUploadOutlined, DeleteOutlined, DownloadOutlined, DragOutlined, ExclamationCircleFilled, FolderOutlined, + MenuOutlined, MinusSquareOutlined, PlusSquareOutlined, ShareAltOutlined, @@ -49,6 +54,7 @@ import MatterSortPanel from './widget/MatterSortPanel'; import { UploadRequestOption as RcCustomRequestOptions } from 'rc-upload/lib/interface'; import Capacity from '../layout/widget/Capacity'; import Space from '../../common/model/space/Space'; +import MatterCrawlModal, { ICrawlFormValues } from './widget/MatterCrawlModal'; interface IProps { spaceUuid?: string; @@ -59,6 +65,7 @@ interface IState {} export default class List extends TankComponent { // 当前空间 space = new Space(); + isInSpace = !!this.props.spaceUuid; // 是否在空间中 // 当前目录 currentDirectory = new Matter(); //准备新建的文件 @@ -83,6 +90,7 @@ export default class List extends TankComponent { // 最外层div wrapperRef = React.createRef(); + uploadDirectoryBtnRef = React.createRef(); //用来判断是否展示遮罩层 dragEnterCount = 0; @@ -97,6 +105,9 @@ export default class List extends TankComponent { uploadMattersMap: Record = Moon.getSingleton().uploadMattersMap; + // 抓取模态窗状态 + crawlModalVisible = false; + //持有全局唯一的实例。 static instance: List | null = null; @@ -507,11 +518,20 @@ export default class List extends TankComponent { ImagePreviewer.showMultiPhoto(imageArray, startIndex); } - delete() { + pagerAndCapacityRefresh() { Capacity.instance?.refresh(); this.refresh(); } + checkHandlePermission() { + return true; + } + + handleCloseMatterCrawlModal() { + this.crawlModalVisible = false; + this.pagerAndCapacityRefresh(); + } + goToDirectory(id: string) { this.searchText = null; this.pager.setFilterValue('puuid', id); @@ -587,6 +607,29 @@ export default class List extends TankComponent { return this.breadcrumbModels; } + getDropdownMenu() { + return ( + + } + onClick={() => this.uploadDirectoryBtnRef.current?.click()} + > + {Lang.t('matter.uploadDir')} + + + } + onClick={() => { + this.crawlModalVisible = true; + this.updateUI(); + }} + > + {Lang.t('matter.crawl')} + + + ); + } + render() { const { pager, director, selectedMatters, dragEnterCount } = this; return ( @@ -624,14 +667,6 @@ export default class List extends TankComponent { ) : null} {selectedMatters.length ? ( <> - - + {this.checkHandlePermission() && ( + <> + + + + )} {/*共享空间下暂不支持分享功能*/} - {!this.props.spaceUuid && ( + {!this.isInSpace && ( - - - - - + {this.checkHandlePermission() && ( + <> + this.triggerUpload(e)} + showUploadList={false} + multiple + > + + + + + + + + )} + + + + @@ -740,9 +801,9 @@ export default class List extends TankComponent { key={matter.uuid!} director={director} matter={matter} - isSpace={!!this.props.spaceUuid} + isSpace={this.isInSpace} onGoToDirectory={(id) => this.goToDirectory(id)} - onDeleteSuccess={() => this.delete()} + onDeleteSuccess={() => this.pagerAndCapacityRefresh()} onCheckMatter={(m) => this.checkMatter(m)} onPreviewImage={(m) => this.previewImage(m)} /> @@ -759,6 +820,13 @@ export default class List extends TankComponent { pageSize={pager.pageSize} hideOnSinglePage /> + {this.crawlModalVisible && ( + + )} ); } diff --git a/src/pages/matter/widget/MatterCrawlModal.tsx b/src/pages/matter/widget/MatterCrawlModal.tsx new file mode 100644 index 0000000..7daa17d --- /dev/null +++ b/src/pages/matter/widget/MatterCrawlModal.tsx @@ -0,0 +1,97 @@ +import React, { useState } from 'react'; +import { Form, Input, message, Modal, Spin } from 'antd'; +import Lang from '../../../common/model/global/Lang'; +import { FORM_LAYOUT } from '../../../common/const/Form'; +import { debounce } from '../../../common/util/OptimizeUtil'; +import Matter from '../../../common/model/matter/Matter'; + +export interface ICrawlFormValues { + link: string; + filename: string; +} +interface IProps { + spaceUuid: string; + puuid: string; + onClose: () => void; +} + +const MatterCrawlModal = ({ spaceUuid, puuid, onClose }: IProps) => { + const [form] = Form.useForm(); + const [filenameFocusFlag, setFilenameFocusFlag] = useState(false); + const [confirmLoading, setConfirmLoading] = useState(false); + + const handleChangeCrawlLink = debounce((link: string) => { + if (filenameFocusFlag) return; // 如果用户光标移入过filename输入框,则不自动填充filename + try { + const url = new URL(link); + const filename = url.pathname.split('/').pop(); + form.setFieldsValue({ + filename, + }); + } catch (e) { + form.setFieldsValue({ + filename: undefined, + }); + } + }, 200); + + const handleConfirm = () => { + const values = form.getFieldsValue(true); + setConfirmLoading(true); + Matter.httpCrawl( + { + url: values.link, + filename: values.filename, + spaceUuid, + puuid, + }, + () => { + message.success(Lang.t('matter.crawlSuccessTip')); + onClose(); + }, + null, + () => { + setConfirmLoading(false); + } + ); + }; + + return ( + +
+ + handleChangeCrawlLink(e.target.value)} + /> + + + setFilenameFocusFlag(true)} + /> + +
+
+ ); +}; + +export default MatterCrawlModal;