seeder-resources-view 1.3.9 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.esm.js +979 -795
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +977 -793
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { memo, useMemo, useCallback, useState, useEffect, useRef, forwardRef, useContext, createContext } from 'react';
|
|
2
|
-
import { Spin, List, Dropdown, Checkbox, Image, Typography, Form, Modal, Button, Cascader, Progress,
|
|
3
|
-
import {
|
|
2
|
+
import { Spin, List, Dropdown, Checkbox, Image, Typography, Form, Modal, Button, Cascader, Progress, App, Flex, Input, Space, Popover, Popconfirm, Empty, ConfigProvider, Tree } from 'antd';
|
|
3
|
+
import { ExclamationCircleFilled, SearchOutlined, CloudUploadOutlined, FolderOpenOutlined, FolderOutlined } from '@ant-design/icons';
|
|
4
4
|
import axios from 'axios';
|
|
5
5
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
6
6
|
|
|
@@ -17555,6 +17555,466 @@ const UploadProgress = _ref => {
|
|
|
17555
17555
|
};
|
|
17556
17556
|
var UploadProgress$1 = /*#__PURE__*/memo(UploadProgress);
|
|
17557
17557
|
|
|
17558
|
+
const createUrlBuilder = function () {
|
|
17559
|
+
let config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
17560
|
+
const {
|
|
17561
|
+
baseUrl = '',
|
|
17562
|
+
isDev = false,
|
|
17563
|
+
devBaseUrl = '',
|
|
17564
|
+
isBrowser = false
|
|
17565
|
+
} = config;
|
|
17566
|
+
return path => {
|
|
17567
|
+
if (!path) return '';
|
|
17568
|
+
|
|
17569
|
+
// 如果传入的是完整 URL,直接返回
|
|
17570
|
+
if (/^https?:\/\//.test(path)) {
|
|
17571
|
+
return path;
|
|
17572
|
+
}
|
|
17573
|
+
|
|
17574
|
+
// 去除 path 开头可能的多余斜杠
|
|
17575
|
+
const cleanPath = path.replace(/^\/+/, '');
|
|
17576
|
+
|
|
17577
|
+
// 开发环境使用 devBaseUrl,否则使用 baseUrl
|
|
17578
|
+
const host = isDev ? devBaseUrl : baseUrl;
|
|
17579
|
+
|
|
17580
|
+
// 如果没有配置 baseUrl,则根据环境返回相对路径或完整路径
|
|
17581
|
+
if (!host) {
|
|
17582
|
+
return isBrowser ? "/".concat(cleanPath) : cleanPath;
|
|
17583
|
+
}
|
|
17584
|
+
return host ? "".concat(host, "/").concat(cleanPath) : "/".concat(cleanPath);
|
|
17585
|
+
};
|
|
17586
|
+
};
|
|
17587
|
+
|
|
17588
|
+
const pathUtils = {
|
|
17589
|
+
replaceRoot: path => path.replace(/^root$|^root\//, '')
|
|
17590
|
+
};
|
|
17591
|
+
const ResourcesView = _ref => {
|
|
17592
|
+
let {
|
|
17593
|
+
apiConfig = {},
|
|
17594
|
+
features = {},
|
|
17595
|
+
className = '',
|
|
17596
|
+
style = {},
|
|
17597
|
+
renderTreeHeader,
|
|
17598
|
+
renderGridHeader,
|
|
17599
|
+
withRootNode = true,
|
|
17600
|
+
acceptFileTypes = "video/*,.mxf,application/mxf,video/mxf",
|
|
17601
|
+
uploadTimeout = 60 * 60 * 1000,
|
|
17602
|
+
searchPlaceholder = "Search ...",
|
|
17603
|
+
refreshSignal = 0,
|
|
17604
|
+
// 新增:外部刷新信号,数值变化时触发刷新
|
|
17605
|
+
treeMode = 'mode1' // 新增:控制使用哪种模式的hook
|
|
17606
|
+
} = _ref;
|
|
17607
|
+
const {
|
|
17608
|
+
message,
|
|
17609
|
+
modal
|
|
17610
|
+
} = App.useApp();
|
|
17611
|
+
|
|
17612
|
+
// 合并默认配置和传入配置
|
|
17613
|
+
const mergedApiConfig = useMemo(() => _objectSpread2({
|
|
17614
|
+
upload: '/api/dvr/media/source/upload',
|
|
17615
|
+
download: '/download'
|
|
17616
|
+
}, apiConfig), [apiConfig]);
|
|
17617
|
+
const mergedFeatures = useMemo(() => _objectSpread2({
|
|
17618
|
+
upload: true,
|
|
17619
|
+
download: true,
|
|
17620
|
+
copy: true,
|
|
17621
|
+
delete: true,
|
|
17622
|
+
search: true,
|
|
17623
|
+
batchOperations: true
|
|
17624
|
+
}, features), [features]);
|
|
17625
|
+
|
|
17626
|
+
// 根据treeMode选择不同的hook
|
|
17627
|
+
const useTreeHook = useMemo(() => {
|
|
17628
|
+
if (treeMode === 'mode2') {
|
|
17629
|
+
// 录像机资源管理页面
|
|
17630
|
+
return require('./hooks/useDirectoryTree2').useDirectoryTree;
|
|
17631
|
+
}
|
|
17632
|
+
return require('./hooks/useDirectoryTree').useDirectoryTree;
|
|
17633
|
+
}, [treeMode]);
|
|
17634
|
+
const {
|
|
17635
|
+
directoryTree,
|
|
17636
|
+
contents,
|
|
17637
|
+
currentPath,
|
|
17638
|
+
loading,
|
|
17639
|
+
originTreeData,
|
|
17640
|
+
updateFileContents,
|
|
17641
|
+
removeFile,
|
|
17642
|
+
refreshTreeData
|
|
17643
|
+
} = useTreeHook({
|
|
17644
|
+
getFolderData: mergedApiConfig.getFolderData,
|
|
17645
|
+
createFolder: mergedApiConfig.createFolder,
|
|
17646
|
+
removeFolderFile: mergedApiConfig.removeFolderFile,
|
|
17647
|
+
renameFolderFile: mergedApiConfig.renameFolderFile,
|
|
17648
|
+
batchOperations: mergedFeatures.batchOperations,
|
|
17649
|
+
withRootNode
|
|
17650
|
+
});
|
|
17651
|
+
|
|
17652
|
+
// 监听外部刷新信号变化
|
|
17653
|
+
useEffect(() => {
|
|
17654
|
+
if (refreshTreeData && refreshSignal > 0) {
|
|
17655
|
+
refreshTreeData();
|
|
17656
|
+
}
|
|
17657
|
+
}, [refreshSignal, refreshTreeData]);
|
|
17658
|
+
const [showProgress, setShowProgress] = useState(false);
|
|
17659
|
+
const [percent, setPercent] = useState(0);
|
|
17660
|
+
const inputRef = useRef(null);
|
|
17661
|
+
const uploadController = useRef(new AbortController());
|
|
17662
|
+
const [modalVisible, setModalVisible] = useState(false);
|
|
17663
|
+
// 处理批量操作
|
|
17664
|
+
const [selectedItems, setSelectedItems] = useState([]);
|
|
17665
|
+
const [indeterminate, setIndeterminate] = useState(false);
|
|
17666
|
+
const [checkAll, setCheckAll] = useState(false);
|
|
17667
|
+
const [batchLoading, setBatchLoading] = useState(false);
|
|
17668
|
+
const [keyword, setKeyword] = useState('');
|
|
17669
|
+
const [debouncedKeyword, setDebouncedKeyword] = useState('');
|
|
17670
|
+
|
|
17671
|
+
// 创建防抖函数(延迟 300ms)
|
|
17672
|
+
const debouncedSearch = useMemo(() => lodashExports.debounce(searchValue => {
|
|
17673
|
+
setDebouncedKeyword(searchValue);
|
|
17674
|
+
}, 300), []);
|
|
17675
|
+
|
|
17676
|
+
// 监听 keyword 变化并触发防抖
|
|
17677
|
+
useEffect(() => {
|
|
17678
|
+
debouncedSearch(keyword);
|
|
17679
|
+
return () => debouncedSearch.cancel(); // 组件卸载时取消防抖
|
|
17680
|
+
}, [keyword, debouncedSearch]);
|
|
17681
|
+
|
|
17682
|
+
// 过滤内容
|
|
17683
|
+
const filteredContents = useMemo(() => {
|
|
17684
|
+
if (!debouncedKeyword) return contents;
|
|
17685
|
+
return contents.filter(item => item.name.toLowerCase().includes(debouncedKeyword.toLowerCase()));
|
|
17686
|
+
}, [contents, debouncedKeyword]);
|
|
17687
|
+
|
|
17688
|
+
// 在组件卸载时取消上传
|
|
17689
|
+
useEffect(() => {
|
|
17690
|
+
return () => {
|
|
17691
|
+
var _uploadController$cur;
|
|
17692
|
+
return (_uploadController$cur = uploadController.current) === null || _uploadController$cur === void 0 ? void 0 : _uploadController$cur.abort();
|
|
17693
|
+
};
|
|
17694
|
+
}, []);
|
|
17695
|
+
|
|
17696
|
+
// 重置批量状态的效果
|
|
17697
|
+
useEffect(() => {
|
|
17698
|
+
setSelectedItems([]);
|
|
17699
|
+
setIndeterminate(false);
|
|
17700
|
+
setCheckAll(false);
|
|
17701
|
+
}, [currentPath]);
|
|
17702
|
+
|
|
17703
|
+
// 上传相关函数
|
|
17704
|
+
const onTriggerUpload = useCallback(() => {
|
|
17705
|
+
var _inputRef$current;
|
|
17706
|
+
(_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 || _inputRef$current.click();
|
|
17707
|
+
}, []);
|
|
17708
|
+
const onUploadFile = async event => {
|
|
17709
|
+
const files = event.target.files;
|
|
17710
|
+
if (!(files !== null && files !== void 0 && files.length)) return;
|
|
17711
|
+
|
|
17712
|
+
// 初始化上传状态
|
|
17713
|
+
setShowProgress(true);
|
|
17714
|
+
setPercent(0);
|
|
17715
|
+
try {
|
|
17716
|
+
await uploadFiles(files, pathUtils.replaceRoot(currentPath));
|
|
17717
|
+
// 延迟2s刷新数据
|
|
17718
|
+
// eslint-disable-next-line no-promise-executor-return
|
|
17719
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
17720
|
+
await updateFileContents();
|
|
17721
|
+
} catch (error) {
|
|
17722
|
+
if (axios.isCancel(error)) {
|
|
17723
|
+
console.log('Upload canceled');
|
|
17724
|
+
} else if (error.response) {
|
|
17725
|
+
var _error$response$data;
|
|
17726
|
+
console.error("Upload failed: ".concat(((_error$response$data = error.response.data) === null || _error$response$data === void 0 ? void 0 : _error$response$data.message) || error.response.status));
|
|
17727
|
+
} else {
|
|
17728
|
+
console.error("Upload error: ".concat(error.message));
|
|
17729
|
+
}
|
|
17730
|
+
} finally {
|
|
17731
|
+
resetUploadState();
|
|
17732
|
+
}
|
|
17733
|
+
};
|
|
17734
|
+
const uploadFiles = async (files, folder) => {
|
|
17735
|
+
// 计算所有文件的总大小
|
|
17736
|
+
const totalSize = calculateTotalSize(files);
|
|
17737
|
+
// 存储每个文件的上一次 loaded 值(避免重复计算)
|
|
17738
|
+
const previousLoadedMap = new Map();
|
|
17739
|
+
let uploadedSize = 0; // 记录已上传的字节数
|
|
17740
|
+
|
|
17741
|
+
const uploadTasks = Array.from(files).map(file => uploadSingleFile(file, folder, previousLoadedMap, newLoaded => {
|
|
17742
|
+
uploadedSize += newLoaded;
|
|
17743
|
+
updateProgress(uploadedSize, totalSize);
|
|
17744
|
+
}));
|
|
17745
|
+
await Promise.all(uploadTasks);
|
|
17746
|
+
};
|
|
17747
|
+
|
|
17748
|
+
// 计算总文件大小
|
|
17749
|
+
const calculateTotalSize = files => Array.from(files).reduce((sum, file) => sum + file.size, 0);
|
|
17750
|
+
|
|
17751
|
+
// 上传单个文件
|
|
17752
|
+
const uploadSingleFile = (file, folder, previousLoadedMap, onProgress) => {
|
|
17753
|
+
const formData = new FormData();
|
|
17754
|
+
formData.append('file', file);
|
|
17755
|
+
formData.append('folder', folder);
|
|
17756
|
+
return axios.post(mergedApiConfig.upload, formData, {
|
|
17757
|
+
timeout: uploadTimeout,
|
|
17758
|
+
headers: {
|
|
17759
|
+
'Content-Type': 'multipart/form-data'
|
|
17760
|
+
},
|
|
17761
|
+
// signal: uploadController.current.signal,
|
|
17762
|
+
onUploadProgress: progressEvent => {
|
|
17763
|
+
if (progressEvent.lengthComputable) {
|
|
17764
|
+
// 获取当前文件的上一次 loaded 值(默认 0)
|
|
17765
|
+
const previousLoaded = previousLoadedMap.get(file.name) || 0;
|
|
17766
|
+
// 计算新增的字节数(避免重复累加)
|
|
17767
|
+
const newLoaded = progressEvent.loaded - previousLoaded;
|
|
17768
|
+
// 更新当前文件的 loaded 值
|
|
17769
|
+
previousLoadedMap.set(file.name, progressEvent.loaded);
|
|
17770
|
+
onProgress(newLoaded);
|
|
17771
|
+
}
|
|
17772
|
+
}
|
|
17773
|
+
});
|
|
17774
|
+
};
|
|
17775
|
+
const updateProgress = (uploadedSize, totalSize) => {
|
|
17776
|
+
const totalPercent = Math.round(uploadedSize / totalSize * 100);
|
|
17777
|
+
setPercent(totalPercent);
|
|
17778
|
+
};
|
|
17779
|
+
|
|
17780
|
+
// 重置上传状态
|
|
17781
|
+
const resetUploadState = () => {
|
|
17782
|
+
setShowProgress(false);
|
|
17783
|
+
setPercent(0);
|
|
17784
|
+
if (inputRef.current) inputRef.current.value = "";
|
|
17785
|
+
};
|
|
17786
|
+
|
|
17787
|
+
// 文件操作函数
|
|
17788
|
+
const downloadFile = async url => {
|
|
17789
|
+
try {
|
|
17790
|
+
const isDev = process.env.NODE_ENV === 'development';
|
|
17791
|
+
const baseUrl = isDev ? process.env.API_HOST // 开发环境默认值
|
|
17792
|
+
: window.location.origin; // 生产环境用当前域名
|
|
17793
|
+
|
|
17794
|
+
const link = document.createElement('a');
|
|
17795
|
+
link.href = "".concat(baseUrl).concat(mergedApiConfig.download, "/").concat(url);
|
|
17796
|
+
// link.download = filename;
|
|
17797
|
+
link.style.display = 'none';
|
|
17798
|
+
document.body.appendChild(link);
|
|
17799
|
+
link.click();
|
|
17800
|
+
document.body.removeChild(link);
|
|
17801
|
+
} catch (error) {
|
|
17802
|
+
console.error("Download failed:", error);
|
|
17803
|
+
}
|
|
17804
|
+
};
|
|
17805
|
+
const copyFile = () => {
|
|
17806
|
+
setModalVisible(true);
|
|
17807
|
+
};
|
|
17808
|
+
const onContextMenu = (key, item) => {
|
|
17809
|
+
if (key === 'del') removeFile(item.url);
|
|
17810
|
+
if (key === 'download') downloadFile(item.url);
|
|
17811
|
+
if (key === 'copy') copyFile(item.url);
|
|
17812
|
+
};
|
|
17813
|
+
const handleBatchRemove = useCallback(async () => {
|
|
17814
|
+
if (!selectedItems.length) return;
|
|
17815
|
+
modal.confirm({
|
|
17816
|
+
icon: /*#__PURE__*/jsx(ExclamationCircleFilled, {}),
|
|
17817
|
+
title: "Are you sure you want to delete ".concat(selectedItems.length, " files?"),
|
|
17818
|
+
cancelText: "No",
|
|
17819
|
+
okText: "Yes",
|
|
17820
|
+
onOk: async () => {
|
|
17821
|
+
try {
|
|
17822
|
+
// 批量处理所有删除请求
|
|
17823
|
+
await mergedApiConfig.removeFolderFile({
|
|
17824
|
+
paths: selectedItems.map(itemUrl => ({
|
|
17825
|
+
path: itemUrl
|
|
17826
|
+
}))
|
|
17827
|
+
});
|
|
17828
|
+
|
|
17829
|
+
// 更新状态
|
|
17830
|
+
setSelectedItems([]);
|
|
17831
|
+
setIndeterminate(false);
|
|
17832
|
+
setCheckAll(false);
|
|
17833
|
+
await updateFileContents(); // 刷新文件列表
|
|
17834
|
+
} catch (error) {
|
|
17835
|
+
console.error('Batch deletion error:', error);
|
|
17836
|
+
}
|
|
17837
|
+
}
|
|
17838
|
+
});
|
|
17839
|
+
}, [selectedItems, mergedApiConfig, updateFileContents]);
|
|
17840
|
+
const handleBatchDownload = useCallback(async () => {
|
|
17841
|
+
if (!selectedItems.length) return;
|
|
17842
|
+
setBatchLoading(true);
|
|
17843
|
+
try {
|
|
17844
|
+
// 逐个下载文件
|
|
17845
|
+
for (let i = 0; i < selectedItems.length; i++) {
|
|
17846
|
+
const url = selectedItems[i];
|
|
17847
|
+
downloadFile(url);
|
|
17848
|
+
|
|
17849
|
+
// 添加延迟避免浏览器并发限制(建议 500-1000ms)
|
|
17850
|
+
if (i < selectedItems.length - 1) {
|
|
17851
|
+
// eslint-disable-next-line no-promise-executor-return
|
|
17852
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
17853
|
+
}
|
|
17854
|
+
}
|
|
17855
|
+
} catch (error) {
|
|
17856
|
+
console.error('Batch download error:', error);
|
|
17857
|
+
} finally {
|
|
17858
|
+
setBatchLoading(false);
|
|
17859
|
+
}
|
|
17860
|
+
}, [selectedItems, downloadFile]);
|
|
17861
|
+
const handleCopyConfirm = useCallback(async newPath => {
|
|
17862
|
+
setBatchLoading(true);
|
|
17863
|
+
try {
|
|
17864
|
+
// 批量处理所有拷贝请求
|
|
17865
|
+
await mergedApiConfig.copyFile({
|
|
17866
|
+
old_paths: selectedItems.map(itemUrl => ({
|
|
17867
|
+
old_path: itemUrl
|
|
17868
|
+
})),
|
|
17869
|
+
new_path: newPath
|
|
17870
|
+
});
|
|
17871
|
+
|
|
17872
|
+
// 更新状态
|
|
17873
|
+
setSelectedItems([]);
|
|
17874
|
+
setIndeterminate(false);
|
|
17875
|
+
setCheckAll(false);
|
|
17876
|
+
message.success('Success');
|
|
17877
|
+
setModalVisible(false);
|
|
17878
|
+
|
|
17879
|
+
// 延迟2s刷新数据
|
|
17880
|
+
// eslint-disable-next-line no-promise-executor-return
|
|
17881
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
17882
|
+
await updateFileContents();
|
|
17883
|
+
} catch (error) {
|
|
17884
|
+
console.error("Batch copy error:", error);
|
|
17885
|
+
} finally {
|
|
17886
|
+
setBatchLoading(false);
|
|
17887
|
+
}
|
|
17888
|
+
}, [selectedItems, mergedApiConfig, updateFileContents]);
|
|
17889
|
+
|
|
17890
|
+
// 处理单个项目的选择变化
|
|
17891
|
+
const handleSelectChange = (item, checked) => {
|
|
17892
|
+
const newSelectedItems = checked ? [...selectedItems, item.url] : selectedItems.filter(url => url !== item.url);
|
|
17893
|
+
setSelectedItems(newSelectedItems);
|
|
17894
|
+
setIndeterminate(!!newSelectedItems.length && newSelectedItems.length !== filteredContents.length);
|
|
17895
|
+
setCheckAll(newSelectedItems.length === filteredContents.length);
|
|
17896
|
+
};
|
|
17897
|
+
|
|
17898
|
+
// 处理全选/取消全选
|
|
17899
|
+
const handleSelectAll = e => {
|
|
17900
|
+
const checked = e.target.checked;
|
|
17901
|
+
setSelectedItems(checked ? filteredContents.map(item => item.url) : []);
|
|
17902
|
+
setIndeterminate(false);
|
|
17903
|
+
setCheckAll(checked);
|
|
17904
|
+
};
|
|
17905
|
+
|
|
17906
|
+
// 搜索框变化处理
|
|
17907
|
+
const handleSearchChange = e => {
|
|
17908
|
+
setKeyword(e.target.value);
|
|
17909
|
+
};
|
|
17910
|
+
|
|
17911
|
+
// 创建 URL 构建器
|
|
17912
|
+
const getFullUrl = useMemo(() => {
|
|
17913
|
+
return createUrlBuilder({
|
|
17914
|
+
baseUrl: apiConfig.baseUrl,
|
|
17915
|
+
devBaseUrl: apiConfig.devBaseUrl,
|
|
17916
|
+
isDev: process.env.NODE_ENV === 'development',
|
|
17917
|
+
isBrowser: typeof window !== 'undefined'
|
|
17918
|
+
});
|
|
17919
|
+
}, [apiConfig.baseUrl, apiConfig.devBaseUrl]);
|
|
17920
|
+
return /*#__PURE__*/jsxs("div", {
|
|
17921
|
+
className: "resources-view ".concat(className),
|
|
17922
|
+
style: style,
|
|
17923
|
+
children: [/*#__PURE__*/jsxs("div", {
|
|
17924
|
+
className: "content-container",
|
|
17925
|
+
children: [/*#__PURE__*/jsxs("div", {
|
|
17926
|
+
className: "directory-tree",
|
|
17927
|
+
children: [renderTreeHeader ? renderTreeHeader() : /*#__PURE__*/jsx("div", {
|
|
17928
|
+
className: "search-bar"
|
|
17929
|
+
}), directoryTree]
|
|
17930
|
+
}), /*#__PURE__*/jsxs("div", {
|
|
17931
|
+
className: "folder-contents",
|
|
17932
|
+
children: [/*#__PURE__*/jsxs(Flex, {
|
|
17933
|
+
justify: "center",
|
|
17934
|
+
align: "center",
|
|
17935
|
+
className: "search-bar",
|
|
17936
|
+
children: [mergedFeatures.search && /*#__PURE__*/jsx(Input, {
|
|
17937
|
+
value: keyword,
|
|
17938
|
+
onChange: handleSearchChange,
|
|
17939
|
+
placeholder: searchPlaceholder,
|
|
17940
|
+
prefix: /*#__PURE__*/jsx(SearchOutlined, {}),
|
|
17941
|
+
allowClear: true,
|
|
17942
|
+
className: "search-input"
|
|
17943
|
+
}), mergedFeatures.upload && /*#__PURE__*/jsxs(Fragment, {
|
|
17944
|
+
children: [/*#__PURE__*/jsx(CloudUploadOutlined, {
|
|
17945
|
+
className: "upload-icon",
|
|
17946
|
+
title: "upload",
|
|
17947
|
+
onClick: onTriggerUpload
|
|
17948
|
+
}), /*#__PURE__*/jsx("input", {
|
|
17949
|
+
ref: inputRef,
|
|
17950
|
+
type: "file",
|
|
17951
|
+
onChange: onUploadFile,
|
|
17952
|
+
className: "hidden",
|
|
17953
|
+
accept: acceptFileTypes,
|
|
17954
|
+
multiple: true
|
|
17955
|
+
})]
|
|
17956
|
+
})]
|
|
17957
|
+
}), /*#__PURE__*/jsxs("div", {
|
|
17958
|
+
className: "media-grid-container",
|
|
17959
|
+
onContextMenu: e => e.preventDefault(),
|
|
17960
|
+
children: [renderGridHeader ? renderGridHeader() : filteredContents.length > 0 && mergedFeatures.batchOperations && /*#__PURE__*/jsx("div", {
|
|
17961
|
+
className: "batch-operations",
|
|
17962
|
+
children: /*#__PURE__*/jsxs(Space, {
|
|
17963
|
+
size: "middle",
|
|
17964
|
+
children: [/*#__PURE__*/jsx(Checkbox, {
|
|
17965
|
+
indeterminate: indeterminate,
|
|
17966
|
+
checked: checkAll,
|
|
17967
|
+
onChange: handleSelectAll,
|
|
17968
|
+
children: "Select All"
|
|
17969
|
+
}), /*#__PURE__*/jsx(Button, {
|
|
17970
|
+
type: "primary",
|
|
17971
|
+
disabled: !selectedItems.length,
|
|
17972
|
+
onClick: () => setModalVisible(true),
|
|
17973
|
+
children: "Copy"
|
|
17974
|
+
}), /*#__PURE__*/jsx(Button, {
|
|
17975
|
+
className: "btn-gray",
|
|
17976
|
+
disabled: !selectedItems.length,
|
|
17977
|
+
onClick: handleBatchRemove,
|
|
17978
|
+
children: "Delete"
|
|
17979
|
+
}), /*#__PURE__*/jsx(Button, {
|
|
17980
|
+
className: "btn-gray",
|
|
17981
|
+
disabled: !selectedItems.length,
|
|
17982
|
+
onClick: handleBatchDownload,
|
|
17983
|
+
children: "Download"
|
|
17984
|
+
})]
|
|
17985
|
+
})
|
|
17986
|
+
}), /*#__PURE__*/jsx(MediaGrid$1, {
|
|
17987
|
+
items: filteredContents,
|
|
17988
|
+
loading: loading,
|
|
17989
|
+
onContextMenu: mergedFeatures.delete || mergedFeatures.download || mergedFeatures.copy ? onContextMenu : null,
|
|
17990
|
+
selectedKeys: selectedItems,
|
|
17991
|
+
showCheckbox: mergedFeatures.batchOperations,
|
|
17992
|
+
onSelectChange: mergedFeatures.batchOperations ? handleSelectChange : null,
|
|
17993
|
+
gridConfig: mergedFeatures.batchOperations ? {
|
|
17994
|
+
gutter: 0,
|
|
17995
|
+
column: 6
|
|
17996
|
+
} : {
|
|
17997
|
+
gutter: 24,
|
|
17998
|
+
column: 6
|
|
17999
|
+
},
|
|
18000
|
+
features: mergedFeatures,
|
|
18001
|
+
getFullUrl: getFullUrl
|
|
18002
|
+
})]
|
|
18003
|
+
})]
|
|
18004
|
+
})]
|
|
18005
|
+
}), showProgress && /*#__PURE__*/jsx(UploadProgress$1, {
|
|
18006
|
+
percent: percent
|
|
18007
|
+
}), /*#__PURE__*/jsx(SelectFolderPathModal$1, {
|
|
18008
|
+
open: modalVisible,
|
|
18009
|
+
directoryTree: originTreeData,
|
|
18010
|
+
batchLoading: batchLoading,
|
|
18011
|
+
onClose: () => setModalVisible(false),
|
|
18012
|
+
onOk: handleCopyConfirm
|
|
18013
|
+
})]
|
|
18014
|
+
});
|
|
18015
|
+
};
|
|
18016
|
+
var ResourcesView$1 = ResourcesView;
|
|
18017
|
+
|
|
17558
18018
|
const PopoverContent = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
17559
18019
|
let {
|
|
17560
18020
|
onClose,
|
|
@@ -17724,7 +18184,14 @@ const TreeTitleNode = _ref2 => {
|
|
|
17724
18184
|
title: "Confirm deletion?",
|
|
17725
18185
|
onConfirm: () => handleDel(nodeData),
|
|
17726
18186
|
okText: "Yes",
|
|
17727
|
-
cancelText: "No"
|
|
18187
|
+
cancelText: "No"
|
|
18188
|
+
// okButtonProps={{
|
|
18189
|
+
// size: "middle" // 增大确认按钮
|
|
18190
|
+
// }}
|
|
18191
|
+
// cancelButtonProps={{
|
|
18192
|
+
// size: "middle" // 增大取消按钮
|
|
18193
|
+
// }}
|
|
18194
|
+
,
|
|
17728
18195
|
children: /*#__PURE__*/jsx("div", {
|
|
17729
18196
|
className: "px-1",
|
|
17730
18197
|
title: "Delete",
|
|
@@ -17830,29 +18297,6 @@ const buildDirectoryTree = function (data) {
|
|
|
17830
18297
|
return build(processedData);
|
|
17831
18298
|
};
|
|
17832
18299
|
|
|
17833
|
-
/**
|
|
17834
|
-
* 查找树中指定key的节点
|
|
17835
|
-
* @param {Array} treeData - 树数据
|
|
17836
|
-
* @param {string} targetKey - 要查找的key
|
|
17837
|
-
* @returns {Array} 包含匹配节点的数组
|
|
17838
|
-
*/
|
|
17839
|
-
const findTreeNode = (treeData, targetKey) => {
|
|
17840
|
-
if (!Array.isArray(treeData) || typeof targetKey !== 'string') return [];
|
|
17841
|
-
const result = [];
|
|
17842
|
-
const stack = [...treeData];
|
|
17843
|
-
while (stack.length) {
|
|
17844
|
-
const node = stack.pop();
|
|
17845
|
-
if (node.key === targetKey) {
|
|
17846
|
-
result.push(node);
|
|
17847
|
-
// 如果只需要第一个匹配项,可以在这里break
|
|
17848
|
-
}
|
|
17849
|
-
if (Array.isArray(node.children)) {
|
|
17850
|
-
stack.push(...node.children);
|
|
17851
|
-
}
|
|
17852
|
-
}
|
|
17853
|
-
return result;
|
|
17854
|
-
};
|
|
17855
|
-
|
|
17856
18300
|
/**
|
|
17857
18301
|
* 获取树中所有节点的keys
|
|
17858
18302
|
* @param {Array} treeData - 树数据
|
|
@@ -17865,831 +18309,571 @@ const getAllNodeKeys = treeData => {
|
|
|
17865
18309
|
while (stack.length) {
|
|
17866
18310
|
const node = stack.pop();
|
|
17867
18311
|
if (node.key !== null) {
|
|
17868
|
-
keys.push(node.key);
|
|
17869
|
-
}
|
|
17870
|
-
if (Array.isArray(node.children)) {
|
|
17871
|
-
stack.push(...node.children);
|
|
17872
|
-
}
|
|
17873
|
-
}
|
|
17874
|
-
return keys;
|
|
17875
|
-
};
|
|
17876
|
-
|
|
17877
|
-
/**
|
|
17878
|
-
* 根据 URL 查找树节点
|
|
17879
|
-
* @param {Array} treeData - 树数据
|
|
17880
|
-
* @param {string} url - 要查找的 URL
|
|
17881
|
-
* @param {Object} options - 配置选项
|
|
17882
|
-
* @param {boolean} options.exactMatch - 是否精确匹配(默认true)
|
|
17883
|
-
* @param {boolean} options.returnFirst - 是否返回第一个匹配项(默认false,返回所有匹配项)
|
|
17884
|
-
* @returns {Array} 包含匹配节点的数组
|
|
17885
|
-
*/
|
|
17886
|
-
const findTreeNodeByUrl = function (treeData, url) {
|
|
17887
|
-
let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
17888
|
-
const {
|
|
17889
|
-
exactMatch = true,
|
|
17890
|
-
returnFirst = false
|
|
17891
|
-
} = options;
|
|
17892
|
-
if (!Array.isArray(treeData) || typeof url !== 'string' || !url.trim()) {
|
|
17893
|
-
return [];
|
|
17894
|
-
}
|
|
17895
|
-
const result = [];
|
|
17896
|
-
const stack = [...treeData];
|
|
17897
|
-
while (stack.length) {
|
|
17898
|
-
const node = stack.pop();
|
|
17899
|
-
|
|
17900
|
-
// 检查当前节点是否匹配
|
|
17901
|
-
if (node.url) {
|
|
17902
|
-
const isMatch = exactMatch ? node.url === url : node.url.includes(url);
|
|
17903
|
-
if (isMatch) {
|
|
17904
|
-
result.push(node);
|
|
17905
|
-
if (returnFirst) {
|
|
17906
|
-
return result; // 找到第一个匹配项就结束
|
|
17907
|
-
}
|
|
17908
|
-
}
|
|
17909
|
-
}
|
|
17910
|
-
|
|
17911
|
-
// 递归处理子节点
|
|
17912
|
-
if (Array.isArray(node.children)) {
|
|
17913
|
-
stack.push(...node.children);
|
|
17914
|
-
}
|
|
17915
|
-
}
|
|
17916
|
-
return result;
|
|
17917
|
-
};
|
|
17918
|
-
|
|
17919
|
-
const useDirectoryTree = _ref => {
|
|
17920
|
-
let {
|
|
17921
|
-
getFolderData,
|
|
17922
|
-
createFolder,
|
|
17923
|
-
removeFolderFile,
|
|
17924
|
-
renameFolderFile,
|
|
17925
|
-
mediaType,
|
|
17926
|
-
isEditable = true,
|
|
17927
|
-
batchOperations = true,
|
|
17928
|
-
withRootNode = true,
|
|
17929
|
-
height = 828,
|
|
17930
|
-
theme = {
|
|
17931
|
-
components: {
|
|
17932
|
-
Tree: {
|
|
17933
|
-
titleHeight: 30
|
|
17934
|
-
}
|
|
17935
|
-
}
|
|
17936
|
-
},
|
|
17937
|
-
treeStyle = {},
|
|
17938
|
-
// Tree 组件样式
|
|
17939
|
-
wrapperStyle = {
|
|
17940
|
-
paddingTop: 16
|
|
17941
|
-
},
|
|
17942
|
-
// 包装器样式
|
|
17943
|
-
expandable = true,
|
|
17944
|
-
// 新增:是否允许展开/折叠
|
|
17945
|
-
onSelectDir,
|
|
17946
|
-
// 新增:选择目录回调
|
|
17947
|
-
selectedDirPath = null // 新增:外部传入的选中目录名
|
|
17948
|
-
} = _ref;
|
|
17949
|
-
const [treeState, setTreeState] = useState({
|
|
17950
|
-
data: [],
|
|
17951
|
-
selectedKeys: [],
|
|
17952
|
-
expandedKeys: [],
|
|
17953
|
-
currentPath: "",
|
|
17954
|
-
contents: [],
|
|
17955
|
-
loading: false
|
|
17956
|
-
});
|
|
17957
|
-
const [originTreeData, setOriginTreeData] = useState([]);
|
|
17958
|
-
const updateTreeState = partialState => {
|
|
17959
|
-
setTreeState(prev => _objectSpread2(_objectSpread2({}, prev), partialState));
|
|
17960
|
-
};
|
|
17961
|
-
|
|
17962
|
-
// 错误处理
|
|
17963
|
-
const handleError = (error, operation) => {
|
|
17964
|
-
console.error("".concat(operation, " ERROR"), error);
|
|
17965
|
-
// 可以添加通知等统一错误处理
|
|
17966
|
-
};
|
|
17967
|
-
|
|
17968
|
-
// 路径处理工具
|
|
17969
|
-
const pathUtils = {
|
|
17970
|
-
replaceRoot: path => path.replace(/^root\//, ''),
|
|
17971
|
-
getNewPath: (node, newTitle) => {
|
|
17972
|
-
const arr = node.path.split('/');
|
|
17973
|
-
arr[arr.length - 1] = newTitle;
|
|
17974
|
-
return arr.join('/');
|
|
17975
|
-
},
|
|
17976
|
-
isSamePath: (path1, path2) => {
|
|
17977
|
-
return pathUtils.replaceRoot(path1) === pathUtils.replaceRoot(path2);
|
|
17978
|
-
}
|
|
17979
|
-
};
|
|
17980
|
-
|
|
17981
|
-
// 节点查找工具
|
|
17982
|
-
const nodeUtils = {
|
|
17983
|
-
findNode: (treeData, key) => {
|
|
17984
|
-
return findTreeNode(treeData, key);
|
|
17985
|
-
},
|
|
17986
|
-
findNodeByUrl: (treeData, url) => {
|
|
17987
|
-
return findTreeNodeByUrl(treeData, url);
|
|
17988
|
-
}
|
|
17989
|
-
};
|
|
17990
|
-
|
|
17991
|
-
// 获取文件夹数据 文件夹名称为空时返回根目录数据
|
|
17992
|
-
const fetchFolderData = useCallback(async function () {
|
|
17993
|
-
let initialization = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
|
17994
|
-
try {
|
|
17995
|
-
// 构建请求参数
|
|
17996
|
-
const requestParams = {
|
|
17997
|
-
folder: ""
|
|
17998
|
-
};
|
|
17999
|
-
if (mediaType) {
|
|
18000
|
-
requestParams.media_type = mediaType;
|
|
18001
|
-
}
|
|
18002
|
-
const data = await getFolderData(requestParams);
|
|
18003
|
-
if (!(data !== null && data !== void 0 && data.directoryTree)) {
|
|
18004
|
-
return null;
|
|
18005
|
-
}
|
|
18006
|
-
setOriginTreeData(data.directoryTree);
|
|
18007
|
-
|
|
18008
|
-
// 递归生成treenodes
|
|
18009
|
-
const treeNodes = buildDirectoryTree(data.directoryTree, {
|
|
18010
|
-
withRoot: withRootNode
|
|
18011
|
-
});
|
|
18012
|
-
if (!treeNodes.length) {
|
|
18013
|
-
return null;
|
|
18014
|
-
}
|
|
18015
|
-
|
|
18016
|
-
// 确定选中的节点
|
|
18017
|
-
let selectedNode = null;
|
|
18018
|
-
|
|
18019
|
-
// 情况1:selectedDirPath 未传(undefined/null)
|
|
18020
|
-
if (selectedDirPath === undefined || selectedDirPath === null) {
|
|
18021
|
-
var _selectedNode;
|
|
18022
|
-
selectedNode = treeNodes[0];
|
|
18023
|
-
console.log('No path provided, using first node:', (_selectedNode = selectedNode) === null || _selectedNode === void 0 ? void 0 : _selectedNode.title);
|
|
18024
|
-
}
|
|
18025
|
-
// 情况2:selectedDirPath 为空字符串
|
|
18026
|
-
else if (selectedDirPath.trim() === '') {
|
|
18027
|
-
// 不设置 selectedNode,保持为 null
|
|
18028
|
-
// console.log('Empty path provided, not setting default node');
|
|
18029
|
-
}
|
|
18030
|
-
// 情况3:selectedDirPath 有值
|
|
18031
|
-
else {
|
|
18032
|
-
try {
|
|
18033
|
-
const foundNodes = nodeUtils.findNodeByUrl(treeNodes, selectedDirPath);
|
|
18034
|
-
selectedNode = (foundNodes === null || foundNodes === void 0 ? void 0 : foundNodes[0]) || null;
|
|
18035
|
-
if (!selectedNode) {
|
|
18036
|
-
console.warn("No node found for path: \"".concat(selectedDirPath, "\""));
|
|
18037
|
-
}
|
|
18038
|
-
} catch (error) {
|
|
18039
|
-
console.error('Error finding node by URL:', error);
|
|
18040
|
-
selectedNode = null;
|
|
18041
|
-
}
|
|
18042
|
-
}
|
|
18043
|
-
const newState = _objectSpread2({
|
|
18044
|
-
data: treeNodes
|
|
18045
|
-
}, initialization && _objectSpread2({
|
|
18046
|
-
expandedKeys: getAllNodeKeys(treeNodes)
|
|
18047
|
-
}, selectedNode ? {
|
|
18048
|
-
selectedKeys: [selectedNode.key].filter(Boolean),
|
|
18049
|
-
currentPath: selectedNode.path || '',
|
|
18050
|
-
contents: selectedNode.contents || []
|
|
18051
|
-
} : {
|
|
18052
|
-
selectedKeys: [],
|
|
18053
|
-
currentPath: '',
|
|
18054
|
-
contents: []
|
|
18055
|
-
}));
|
|
18056
|
-
updateTreeState(newState);
|
|
18057
|
-
return treeNodes;
|
|
18058
|
-
} catch (error) {
|
|
18059
|
-
handleError(error, 'GET FOLDER DATA');
|
|
18060
|
-
}
|
|
18061
|
-
}, [mediaType, withRootNode]);
|
|
18062
|
-
|
|
18063
|
-
// 初始化数据
|
|
18064
|
-
useEffect(() => {
|
|
18065
|
-
fetchFolderData(true);
|
|
18066
|
-
}, [fetchFolderData]);
|
|
18067
|
-
|
|
18068
|
-
// 创建文件夹
|
|
18069
|
-
const handleCreate = useCallback(async (node, newTitle) => {
|
|
18070
|
-
if (!(newTitle !== null && newTitle !== void 0 && newTitle.trim())) return false;
|
|
18071
|
-
try {
|
|
18072
|
-
var _parentNode$;
|
|
18073
|
-
const path = pathUtils.replaceRoot("".concat(node.path, "/").concat(newTitle));
|
|
18074
|
-
await createFolder({
|
|
18075
|
-
path
|
|
18076
|
-
});
|
|
18077
|
-
const newTreeData = await fetchFolderData();
|
|
18078
|
-
|
|
18079
|
-
// 找到新增节点的父节点
|
|
18080
|
-
const parentNode = nodeUtils.findNode(newTreeData, node.key);
|
|
18081
|
-
if (parentNode !== null && parentNode !== void 0 && (_parentNode$ = parentNode[0]) !== null && _parentNode$ !== void 0 && _parentNode$.children) {
|
|
18082
|
-
const expectedPath = "".concat(node.path, "/").concat(newTitle);
|
|
18083
|
-
// 通过 path 找到新增节点,得到新增节点的key
|
|
18084
|
-
const addedNode = parentNode[0].children.find(ch => pathUtils.isSamePath(ch.path, expectedPath));
|
|
18085
|
-
if (addedNode) {
|
|
18086
|
-
updateTreeState({
|
|
18087
|
-
selectedKeys: [addedNode.key],
|
|
18088
|
-
expandedKeys: [...treeState.expandedKeys, addedNode.key, parentNode[0].key],
|
|
18089
|
-
currentPath: addedNode.path,
|
|
18090
|
-
contents: []
|
|
18091
|
-
});
|
|
18092
|
-
}
|
|
18093
|
-
}
|
|
18094
|
-
;
|
|
18095
|
-
} catch (error) {
|
|
18096
|
-
handleError(error, 'CREATE FOLDER');
|
|
18097
|
-
}
|
|
18098
|
-
}, [fetchFolderData, treeState.expandedKeys]);
|
|
18099
|
-
|
|
18100
|
-
// 删除文件/文件夹
|
|
18101
|
-
const handleRemove = useCallback(async node => {
|
|
18102
|
-
if (!node.path) return;
|
|
18103
|
-
try {
|
|
18104
|
-
batchOperations ? await removeFolderFile({
|
|
18105
|
-
paths: [{
|
|
18106
|
-
path: pathUtils.replaceRoot(node.path)
|
|
18107
|
-
}]
|
|
18108
|
-
}) : await removeFolderFile({
|
|
18109
|
-
path: pathUtils.replaceRoot(node.path)
|
|
18110
|
-
});
|
|
18111
|
-
// 如果删除的是当前选中节点,则重新初始化
|
|
18112
|
-
const shouldReinitialize = treeState.selectedKeys[0] === node.key;
|
|
18113
|
-
await fetchFolderData(shouldReinitialize);
|
|
18114
|
-
} catch (error) {
|
|
18115
|
-
handleError(error, 'REMOVE FOLDER/FILE');
|
|
18116
|
-
}
|
|
18117
|
-
}, [fetchFolderData, treeState.selectedKeys]);
|
|
18118
|
-
|
|
18119
|
-
// 修改文件/文件夹
|
|
18120
|
-
const handleRename = useCallback(async node => {
|
|
18121
|
-
const newPath = pathUtils.getNewPath(node, node.title);
|
|
18122
|
-
if (pathUtils.isSamePath(node.path, newPath)) return false;
|
|
18123
|
-
try {
|
|
18124
|
-
await renameFolderFile({
|
|
18125
|
-
old_path: pathUtils.replaceRoot(node.path),
|
|
18126
|
-
new_path: pathUtils.replaceRoot(newPath)
|
|
18127
|
-
});
|
|
18128
|
-
await fetchFolderData();
|
|
18129
|
-
} catch (error) {
|
|
18130
|
-
handleError(error, 'RENAME FOLDER/FILE');
|
|
18131
|
-
}
|
|
18132
|
-
}, [fetchFolderData]);
|
|
18133
|
-
|
|
18134
|
-
// 选择节点
|
|
18135
|
-
const onSelect = useCallback(async (keys, info) => {
|
|
18136
|
-
// 如果选中了 root 节点,并且有传 onSelectDir 回调,则直接返回
|
|
18137
|
-
if (info.node.path === 'root' && onSelectDir) return;
|
|
18138
|
-
if (!keys.length || keys[0] === treeState.selectedKeys[0] && pathUtils.isSamePath(info.node.path, treeState.currentPath)) return;
|
|
18139
|
-
updateTreeState({
|
|
18140
|
-
selectedKeys: keys,
|
|
18141
|
-
currentPath: info.node.path,
|
|
18142
|
-
loading: true
|
|
18143
|
-
});
|
|
18144
|
-
|
|
18145
|
-
// 触发 onSelectDir 回调(如果存在)
|
|
18146
|
-
if (onSelectDir) {
|
|
18147
|
-
onSelectDir(info.node.rawData);
|
|
18148
|
-
}
|
|
18149
|
-
try {
|
|
18150
|
-
// 模拟延迟加载
|
|
18151
|
-
// eslint-disable-next-line no-promise-executor-return
|
|
18152
|
-
await new Promise(resolve => setTimeout(resolve, 300));
|
|
18153
|
-
updateTreeState({
|
|
18154
|
-
contents: info.node.contents,
|
|
18155
|
-
loading: false
|
|
18156
|
-
});
|
|
18157
|
-
} catch (error) {
|
|
18158
|
-
handleError(error, 'SELECT NODE');
|
|
18159
|
-
updateTreeState({
|
|
18160
|
-
loading: false
|
|
18161
|
-
});
|
|
18312
|
+
keys.push(node.key);
|
|
18162
18313
|
}
|
|
18163
|
-
|
|
18314
|
+
if (Array.isArray(node.children)) {
|
|
18315
|
+
stack.push(...node.children);
|
|
18316
|
+
}
|
|
18317
|
+
}
|
|
18318
|
+
return keys;
|
|
18319
|
+
};
|
|
18164
18320
|
|
|
18165
|
-
|
|
18166
|
-
|
|
18167
|
-
|
|
18168
|
-
|
|
18169
|
-
|
|
18170
|
-
|
|
18321
|
+
/**
|
|
18322
|
+
* 根据 URL 查找树节点
|
|
18323
|
+
* @param {Array} treeData - 树数据
|
|
18324
|
+
* @param {string} url - 要查找的 URL
|
|
18325
|
+
* @param {Object} options - 配置选项
|
|
18326
|
+
* @param {boolean} options.exactMatch - 是否精确匹配(默认true)
|
|
18327
|
+
* @param {boolean} options.returnFirst - 是否返回第一个匹配项(默认false,返回所有匹配项)
|
|
18328
|
+
* @returns {Array} 包含匹配节点的数组
|
|
18329
|
+
*/
|
|
18330
|
+
const findTreeNodeByUrl = function (treeData, url) {
|
|
18331
|
+
let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
18332
|
+
const {
|
|
18333
|
+
exactMatch = true,
|
|
18334
|
+
returnFirst = false
|
|
18335
|
+
} = options;
|
|
18336
|
+
if (!Array.isArray(treeData) || typeof url !== 'string' || !url.trim()) {
|
|
18337
|
+
return [];
|
|
18338
|
+
}
|
|
18339
|
+
const result = [];
|
|
18340
|
+
const stack = [...treeData];
|
|
18341
|
+
while (stack.length) {
|
|
18342
|
+
const node = stack.pop();
|
|
18171
18343
|
|
|
18172
|
-
|
|
18173
|
-
|
|
18174
|
-
|
|
18175
|
-
|
|
18176
|
-
|
|
18177
|
-
|
|
18178
|
-
|
|
18179
|
-
let shouldUpdateContents = false;
|
|
18180
|
-
if (currentKey && treeNodes) {
|
|
18181
|
-
const foundNode = nodeUtils.findNode(treeNodes, currentKey);
|
|
18182
|
-
if (foundNode !== null && foundNode !== void 0 && foundNode[0]) {
|
|
18183
|
-
shouldUpdateContents = true;
|
|
18184
|
-
updateTreeState({
|
|
18185
|
-
contents: foundNode[0].contents || []
|
|
18186
|
-
});
|
|
18187
|
-
} else {
|
|
18188
|
-
// 如果当前选中节点不存在了,清除选中状态
|
|
18189
|
-
updateTreeState({
|
|
18190
|
-
selectedKeys: [],
|
|
18191
|
-
currentPath: '',
|
|
18192
|
-
contents: []
|
|
18193
|
-
});
|
|
18344
|
+
// 检查当前节点是否匹配
|
|
18345
|
+
if (node.url) {
|
|
18346
|
+
const isMatch = exactMatch ? node.url === url : node.url.includes(url);
|
|
18347
|
+
if (isMatch) {
|
|
18348
|
+
result.push(node);
|
|
18349
|
+
if (returnFirst) {
|
|
18350
|
+
return result; // 找到第一个匹配项就结束
|
|
18194
18351
|
}
|
|
18195
18352
|
}
|
|
18196
|
-
} catch (error) {
|
|
18197
|
-
handleError(error, 'REFRESH TREE DATA');
|
|
18198
|
-
return null;
|
|
18199
|
-
}
|
|
18200
|
-
}, [fetchFolderData, treeState.selectedKeys]);
|
|
18201
|
-
|
|
18202
|
-
// 上传右侧文件或删除右侧文件 成功后的回调函数
|
|
18203
|
-
const updateFileContents = useCallback(async () => {
|
|
18204
|
-
// 找到当前选中的节点,更新当前节点的 contents
|
|
18205
|
-
const newTreeData = await fetchFolderData();
|
|
18206
|
-
const selectedNode = nodeUtils.findNode(newTreeData, treeState.selectedKeys[0]);
|
|
18207
|
-
if (selectedNode !== null && selectedNode !== void 0 && selectedNode[0]) {
|
|
18208
|
-
updateTreeState({
|
|
18209
|
-
contents: selectedNode[0].contents
|
|
18210
|
-
});
|
|
18211
18353
|
}
|
|
18212
|
-
}, [fetchFolderData, treeState.selectedKeys]);
|
|
18213
18354
|
|
|
18214
|
-
|
|
18215
|
-
|
|
18216
|
-
|
|
18217
|
-
await removeFolderFile({
|
|
18218
|
-
path: url
|
|
18219
|
-
});
|
|
18220
|
-
await updateFileContents();
|
|
18221
|
-
} catch (error) {
|
|
18222
|
-
handleError(error, 'REMOVE FILE');
|
|
18223
|
-
}
|
|
18224
|
-
}, [updateFileContents]);
|
|
18225
|
-
const MemoizedTree = useMemo(() => {
|
|
18226
|
-
var _treeState$data;
|
|
18227
|
-
if (!((_treeState$data = treeState.data) !== null && _treeState$data !== void 0 && _treeState$data.length)) {
|
|
18228
|
-
return /*#__PURE__*/jsx(Empty, {
|
|
18229
|
-
image: Empty.PRESENTED_IMAGE_SIMPLE
|
|
18230
|
-
});
|
|
18355
|
+
// 递归处理子节点
|
|
18356
|
+
if (Array.isArray(node.children)) {
|
|
18357
|
+
stack.push(...node.children);
|
|
18231
18358
|
}
|
|
18232
|
-
|
|
18233
|
-
|
|
18234
|
-
children: /*#__PURE__*/jsx(ConfigProvider, {
|
|
18235
|
-
theme: theme,
|
|
18236
|
-
children: /*#__PURE__*/jsx(Tree, {
|
|
18237
|
-
blockNode: true,
|
|
18238
|
-
showIcon: true,
|
|
18239
|
-
selectedKeys: treeState.selectedKeys,
|
|
18240
|
-
expandedKeys: treeState.expandedKeys,
|
|
18241
|
-
onSelect: onSelect,
|
|
18242
|
-
onExpand: expandable ? onExpand : undefined // 不允许展开时不绑定事件
|
|
18243
|
-
,
|
|
18244
|
-
treeData: treeState.data,
|
|
18245
|
-
titleRender: nodeData => /*#__PURE__*/jsx(TreeTitle$1, {
|
|
18246
|
-
title: nodeData.title,
|
|
18247
|
-
nodeData: nodeData,
|
|
18248
|
-
isEditable: isEditable,
|
|
18249
|
-
handleSave: handleRename,
|
|
18250
|
-
handleDel: handleRemove,
|
|
18251
|
-
handleAdd: handleCreate
|
|
18252
|
-
}),
|
|
18253
|
-
height: height,
|
|
18254
|
-
style: treeStyle
|
|
18255
|
-
})
|
|
18256
|
-
})
|
|
18257
|
-
}, "folder-directory");
|
|
18258
|
-
}, [treeState.data, treeState.selectedKeys, treeState.expandedKeys]);
|
|
18259
|
-
return {
|
|
18260
|
-
directoryTree: MemoizedTree,
|
|
18261
|
-
contents: treeState.contents,
|
|
18262
|
-
currentPath: treeState.currentPath,
|
|
18263
|
-
loading: treeState.loading,
|
|
18264
|
-
originTreeData,
|
|
18265
|
-
updateFileContents,
|
|
18266
|
-
removeFile,
|
|
18267
|
-
refreshTreeData,
|
|
18268
|
-
// 暴露刷新方法
|
|
18269
|
-
fetchFolderData: refreshTreeData // 也可以保留别名
|
|
18270
|
-
};
|
|
18359
|
+
}
|
|
18360
|
+
return result;
|
|
18271
18361
|
};
|
|
18272
18362
|
|
|
18273
|
-
|
|
18274
|
-
|
|
18363
|
+
/**
|
|
18364
|
+
* 通过路径查找树节点
|
|
18365
|
+
* @param {Array} treeData - 树数据
|
|
18366
|
+
* @param {string} targetPath - 要查找的路径
|
|
18367
|
+
* @param {Object} options - 配置选项
|
|
18368
|
+
* @param {boolean} options.exactMatch - 是否精确匹配(默认true)
|
|
18369
|
+
* @param {boolean} options.returnFirst - 是否返回第一个匹配项(默认false,返回所有匹配项)
|
|
18370
|
+
* @returns {Array} 包含匹配节点的数组
|
|
18371
|
+
*/
|
|
18372
|
+
const findTreeNodeByPath = function (treeData, targetPath) {
|
|
18373
|
+
let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
18275
18374
|
const {
|
|
18276
|
-
|
|
18277
|
-
|
|
18278
|
-
|
|
18279
|
-
|
|
18280
|
-
|
|
18281
|
-
|
|
18282
|
-
|
|
18375
|
+
exactMatch = true,
|
|
18376
|
+
returnFirst = false
|
|
18377
|
+
} = options;
|
|
18378
|
+
if (!Array.isArray(treeData) || typeof targetPath !== 'string' || !targetPath.trim()) {
|
|
18379
|
+
return [];
|
|
18380
|
+
}
|
|
18381
|
+
const result = [];
|
|
18382
|
+
const stack = [...treeData];
|
|
18383
|
+
while (stack.length) {
|
|
18384
|
+
const node = stack.pop();
|
|
18283
18385
|
|
|
18284
|
-
//
|
|
18285
|
-
if (
|
|
18286
|
-
|
|
18386
|
+
// 检查当前节点是否匹配 - 目录有 path 属性
|
|
18387
|
+
if (node.path) {
|
|
18388
|
+
const isMatch = exactMatch ? node.path === targetPath : node.path.includes(targetPath);
|
|
18389
|
+
if (isMatch) {
|
|
18390
|
+
result.push(node);
|
|
18391
|
+
if (returnFirst) {
|
|
18392
|
+
return result; // 找到第一个匹配项就结束
|
|
18393
|
+
}
|
|
18394
|
+
}
|
|
18287
18395
|
}
|
|
18288
18396
|
|
|
18289
|
-
//
|
|
18290
|
-
|
|
18291
|
-
|
|
18292
|
-
// 开发环境使用 devBaseUrl,否则使用 baseUrl
|
|
18293
|
-
const host = isDev ? devBaseUrl : baseUrl;
|
|
18294
|
-
|
|
18295
|
-
// 如果没有配置 baseUrl,则根据环境返回相对路径或完整路径
|
|
18296
|
-
if (!host) {
|
|
18297
|
-
return isBrowser ? "/".concat(cleanPath) : cleanPath;
|
|
18397
|
+
// 递归处理子节点
|
|
18398
|
+
if (Array.isArray(node.children)) {
|
|
18399
|
+
stack.push(...node.children);
|
|
18298
18400
|
}
|
|
18299
|
-
|
|
18300
|
-
|
|
18401
|
+
}
|
|
18402
|
+
return result;
|
|
18301
18403
|
};
|
|
18302
18404
|
|
|
18303
|
-
const
|
|
18304
|
-
replaceRoot: path => path.replace(/^root$|^root\//, '')
|
|
18305
|
-
};
|
|
18306
|
-
const ResourcesView = _ref => {
|
|
18405
|
+
const useDirectoryTree = _ref => {
|
|
18307
18406
|
let {
|
|
18308
|
-
|
|
18309
|
-
|
|
18310
|
-
|
|
18311
|
-
|
|
18312
|
-
|
|
18313
|
-
|
|
18407
|
+
getFolderData,
|
|
18408
|
+
createFolder,
|
|
18409
|
+
removeFolderFile,
|
|
18410
|
+
renameFolderFile,
|
|
18411
|
+
mediaType,
|
|
18412
|
+
isEditable = true,
|
|
18413
|
+
batchOperations = true,
|
|
18314
18414
|
withRootNode = true,
|
|
18315
|
-
|
|
18316
|
-
|
|
18317
|
-
|
|
18318
|
-
|
|
18415
|
+
height = 828,
|
|
18416
|
+
theme = {
|
|
18417
|
+
components: {
|
|
18418
|
+
Tree: {
|
|
18419
|
+
titleHeight: 30
|
|
18420
|
+
}
|
|
18421
|
+
}
|
|
18422
|
+
},
|
|
18423
|
+
treeStyle = {},
|
|
18424
|
+
// Tree 组件样式
|
|
18425
|
+
wrapperStyle = {
|
|
18426
|
+
paddingTop: 16
|
|
18427
|
+
},
|
|
18428
|
+
// 包装器样式
|
|
18429
|
+
expandable = true,
|
|
18430
|
+
// 新增:是否允许展开/折叠
|
|
18431
|
+
onSelectDir,
|
|
18432
|
+
// 新增:选择目录回调
|
|
18433
|
+
selectedDirPath = null // 新增:外部传入的选中目录名
|
|
18319
18434
|
} = _ref;
|
|
18320
|
-
const {
|
|
18321
|
-
|
|
18322
|
-
|
|
18323
|
-
|
|
18324
|
-
|
|
18325
|
-
|
|
18326
|
-
|
|
18327
|
-
|
|
18328
|
-
|
|
18329
|
-
|
|
18330
|
-
|
|
18331
|
-
|
|
18332
|
-
download: true,
|
|
18333
|
-
copy: true,
|
|
18334
|
-
delete: true,
|
|
18335
|
-
search: true,
|
|
18336
|
-
batchOperations: true
|
|
18337
|
-
}, features), [features]);
|
|
18338
|
-
const {
|
|
18339
|
-
directoryTree,
|
|
18340
|
-
contents,
|
|
18341
|
-
currentPath,
|
|
18342
|
-
loading,
|
|
18343
|
-
originTreeData,
|
|
18344
|
-
updateFileContents,
|
|
18345
|
-
removeFile,
|
|
18346
|
-
refreshTreeData
|
|
18347
|
-
} = useDirectoryTree({
|
|
18348
|
-
getFolderData: mergedApiConfig.getFolderData,
|
|
18349
|
-
createFolder: mergedApiConfig.createFolder,
|
|
18350
|
-
removeFolderFile: mergedApiConfig.removeFolderFile,
|
|
18351
|
-
renameFolderFile: mergedApiConfig.renameFolderFile,
|
|
18352
|
-
batchOperations: mergedFeatures.batchOperations,
|
|
18353
|
-
withRootNode
|
|
18435
|
+
const [treeState, setTreeState] = useState({
|
|
18436
|
+
data: [],
|
|
18437
|
+
// 树结构数据
|
|
18438
|
+
selectedKeys: [],
|
|
18439
|
+
// 选中节点keys
|
|
18440
|
+
expandedKeys: [],
|
|
18441
|
+
// 展开节点keys
|
|
18442
|
+
currentPath: "",
|
|
18443
|
+
// 当前选中路径
|
|
18444
|
+
contents: [],
|
|
18445
|
+
// 当前选中节点的文件列表
|
|
18446
|
+
loading: false // 加载状态
|
|
18354
18447
|
});
|
|
18448
|
+
const [originTreeData, setOriginTreeData] = useState([]);
|
|
18449
|
+
const updateTreeState = partialState => {
|
|
18450
|
+
setTreeState(prev => _objectSpread2(_objectSpread2({}, prev), partialState));
|
|
18451
|
+
};
|
|
18452
|
+
|
|
18453
|
+
// 错误处理
|
|
18454
|
+
const handleError = (error, operation) => {
|
|
18455
|
+
console.error("".concat(operation, " ERROR"), error);
|
|
18456
|
+
// 可以添加通知等统一错误处理
|
|
18457
|
+
};
|
|
18355
18458
|
|
|
18356
|
-
//
|
|
18357
|
-
|
|
18358
|
-
|
|
18359
|
-
|
|
18459
|
+
// 路径处理工具
|
|
18460
|
+
const pathUtils = {
|
|
18461
|
+
replaceRoot: path => path.replace(/^root\//, ''),
|
|
18462
|
+
getNewPath: (node, newTitle) => {
|
|
18463
|
+
const arr = node.path.split('/');
|
|
18464
|
+
arr[arr.length - 1] = newTitle;
|
|
18465
|
+
return arr.join('/');
|
|
18466
|
+
},
|
|
18467
|
+
isSamePath: (path1, path2) => {
|
|
18468
|
+
return pathUtils.replaceRoot(path1) === pathUtils.replaceRoot(path2);
|
|
18469
|
+
},
|
|
18470
|
+
getParentPath: path => {
|
|
18471
|
+
if (!path) return '';
|
|
18472
|
+
const parts = path.split('/');
|
|
18473
|
+
parts.pop(); // 移除最后一部分
|
|
18474
|
+
return parts.join('/') || '';
|
|
18360
18475
|
}
|
|
18361
|
-
}
|
|
18362
|
-
const [showProgress, setShowProgress] = useState(false);
|
|
18363
|
-
const [percent, setPercent] = useState(0);
|
|
18364
|
-
const inputRef = useRef(null);
|
|
18365
|
-
const uploadController = useRef(new AbortController());
|
|
18366
|
-
const [modalVisible, setModalVisible] = useState(false);
|
|
18367
|
-
// 处理批量操作
|
|
18368
|
-
const [selectedItems, setSelectedItems] = useState([]);
|
|
18369
|
-
const [indeterminate, setIndeterminate] = useState(false);
|
|
18370
|
-
const [checkAll, setCheckAll] = useState(false);
|
|
18371
|
-
const [batchLoading, setBatchLoading] = useState(false);
|
|
18372
|
-
const [keyword, setKeyword] = useState('');
|
|
18373
|
-
const [debouncedKeyword, setDebouncedKeyword] = useState('');
|
|
18476
|
+
};
|
|
18374
18477
|
|
|
18375
|
-
//
|
|
18376
|
-
const
|
|
18377
|
-
|
|
18378
|
-
}, 300), []);
|
|
18478
|
+
// 根据路径确定选中的节点
|
|
18479
|
+
const determineSelectedNode = useCallback((treeNodes, path) => {
|
|
18480
|
+
if (treeNodes.length === 0) return null;
|
|
18379
18481
|
|
|
18380
|
-
|
|
18381
|
-
|
|
18382
|
-
|
|
18383
|
-
|
|
18384
|
-
}, [keyword, debouncedSearch]);
|
|
18482
|
+
// 情况1:未传路径,使用第一个节点
|
|
18483
|
+
if (path === undefined || path === null) {
|
|
18484
|
+
return treeNodes[0];
|
|
18485
|
+
}
|
|
18385
18486
|
|
|
18386
|
-
|
|
18387
|
-
|
|
18388
|
-
|
|
18389
|
-
|
|
18390
|
-
}, [contents, debouncedKeyword]);
|
|
18487
|
+
// 情况2:空字符串,不选中任何节点
|
|
18488
|
+
if (path.trim() === '') {
|
|
18489
|
+
return null;
|
|
18490
|
+
}
|
|
18391
18491
|
|
|
18392
|
-
|
|
18393
|
-
|
|
18394
|
-
|
|
18395
|
-
|
|
18396
|
-
|
|
18397
|
-
|
|
18492
|
+
// 情况3:有值,查找对应节点
|
|
18493
|
+
try {
|
|
18494
|
+
const foundNodes = findTreeNodeByUrl(treeNodes, path);
|
|
18495
|
+
return (foundNodes === null || foundNodes === void 0 ? void 0 : foundNodes[0]) || null;
|
|
18496
|
+
} catch (error) {
|
|
18497
|
+
console.error('Error finding node by URL:', error);
|
|
18498
|
+
return null;
|
|
18499
|
+
}
|
|
18398
18500
|
}, []);
|
|
18399
18501
|
|
|
18400
|
-
//
|
|
18502
|
+
// 获取树结构(目录层级)
|
|
18503
|
+
const getTreeStructure = useCallback(async folder => {
|
|
18504
|
+
try {
|
|
18505
|
+
// 构建请求参数
|
|
18506
|
+
const requestParams = {
|
|
18507
|
+
folder: folder
|
|
18508
|
+
};
|
|
18509
|
+
if (mediaType) {
|
|
18510
|
+
requestParams.media_type = mediaType;
|
|
18511
|
+
}
|
|
18512
|
+
const data = await getFolderData(requestParams);
|
|
18513
|
+
if (!(data !== null && data !== void 0 && data.directoryTree)) {
|
|
18514
|
+
return null;
|
|
18515
|
+
}
|
|
18516
|
+
|
|
18517
|
+
// 只在初始化时保存原始数据
|
|
18518
|
+
if (folder === '') {
|
|
18519
|
+
setOriginTreeData(data.directoryTree);
|
|
18520
|
+
}
|
|
18521
|
+
return buildDirectoryTree(data.directoryTree, {
|
|
18522
|
+
withRoot: withRootNode
|
|
18523
|
+
});
|
|
18524
|
+
} catch (error) {
|
|
18525
|
+
handleError(error, 'GET TREE STRUCTURE');
|
|
18526
|
+
return null;
|
|
18527
|
+
}
|
|
18528
|
+
}, [mediaType, withRootNode]);
|
|
18529
|
+
|
|
18530
|
+
// 初始化树结构
|
|
18531
|
+
const initTreeData = useCallback(async () => {
|
|
18532
|
+
try {
|
|
18533
|
+
updateTreeState({
|
|
18534
|
+
loading: true
|
|
18535
|
+
});
|
|
18536
|
+
const treeNodes = await getTreeStructure('');
|
|
18537
|
+
if (!(treeNodes !== null && treeNodes !== void 0 && treeNodes.length)) {
|
|
18538
|
+
updateTreeState({
|
|
18539
|
+
data: [],
|
|
18540
|
+
selectedKeys: [],
|
|
18541
|
+
currentPath: '',
|
|
18542
|
+
contents: [],
|
|
18543
|
+
loading: false
|
|
18544
|
+
});
|
|
18545
|
+
return;
|
|
18546
|
+
}
|
|
18547
|
+
|
|
18548
|
+
// 确定选中的节点
|
|
18549
|
+
let selectedNode = determineSelectedNode(treeNodes, selectedDirPath);
|
|
18550
|
+
|
|
18551
|
+
// 获取初始选中节点的contents
|
|
18552
|
+
let initialContents = [];
|
|
18553
|
+
if (selectedNode) {
|
|
18554
|
+
initialContents = selectedNode.contents;
|
|
18555
|
+
}
|
|
18556
|
+
updateTreeState({
|
|
18557
|
+
data: treeNodes,
|
|
18558
|
+
selectedKeys: selectedNode ? [selectedNode.key] : [],
|
|
18559
|
+
expandedKeys: getAllNodeKeys(treeNodes),
|
|
18560
|
+
currentPath: (selectedNode === null || selectedNode === void 0 ? void 0 : selectedNode.path) || '',
|
|
18561
|
+
contents: initialContents,
|
|
18562
|
+
loading: false
|
|
18563
|
+
});
|
|
18564
|
+
} catch (error) {
|
|
18565
|
+
handleError(error, 'INIT TREE DATA');
|
|
18566
|
+
updateTreeState({
|
|
18567
|
+
loading: false
|
|
18568
|
+
});
|
|
18569
|
+
}
|
|
18570
|
+
}, [getTreeStructure, selectedDirPath]);
|
|
18571
|
+
|
|
18572
|
+
// 初始化数据
|
|
18401
18573
|
useEffect(() => {
|
|
18402
|
-
|
|
18403
|
-
|
|
18404
|
-
setCheckAll(false);
|
|
18405
|
-
}, [currentPath]);
|
|
18574
|
+
initTreeData();
|
|
18575
|
+
}, [initTreeData]);
|
|
18406
18576
|
|
|
18407
|
-
//
|
|
18408
|
-
const
|
|
18409
|
-
|
|
18410
|
-
(
|
|
18411
|
-
|
|
18412
|
-
|
|
18413
|
-
|
|
18414
|
-
|
|
18577
|
+
// 选择节点
|
|
18578
|
+
const onSelect = useCallback(async (keys, info) => {
|
|
18579
|
+
// 如果选中了 root 节点,并且有传 onSelectDir 回调,则直接返回
|
|
18580
|
+
if (info.node.path === 'root' && onSelectDir) return;
|
|
18581
|
+
if (!keys.length || keys[0] === treeState.selectedKeys[0] && pathUtils.isSamePath(info.node.path, treeState.currentPath)) {
|
|
18582
|
+
return;
|
|
18583
|
+
}
|
|
18584
|
+
updateTreeState({
|
|
18585
|
+
selectedKeys: keys,
|
|
18586
|
+
currentPath: info.node.path,
|
|
18587
|
+
loading: true
|
|
18588
|
+
});
|
|
18415
18589
|
|
|
18416
|
-
//
|
|
18417
|
-
|
|
18418
|
-
|
|
18590
|
+
// 触发 onSelectDir 回调(如果存在)
|
|
18591
|
+
if (onSelectDir) {
|
|
18592
|
+
onSelectDir(info.node.rawData);
|
|
18593
|
+
}
|
|
18419
18594
|
try {
|
|
18420
|
-
|
|
18421
|
-
//
|
|
18422
|
-
await new Promise(resolve => setTimeout(resolve,
|
|
18423
|
-
|
|
18595
|
+
// 模拟延迟加载
|
|
18596
|
+
// eslint-disable-next-line no-promise-executor-return
|
|
18597
|
+
await new Promise(resolve => setTimeout(resolve, 300));
|
|
18598
|
+
updateTreeState({
|
|
18599
|
+
contents: info.node.contents,
|
|
18600
|
+
loading: false
|
|
18601
|
+
});
|
|
18424
18602
|
} catch (error) {
|
|
18425
|
-
|
|
18426
|
-
|
|
18427
|
-
|
|
18428
|
-
|
|
18429
|
-
console.error("Upload failed: ".concat(((_error$response$data = error.response.data) === null || _error$response$data === void 0 ? void 0 : _error$response$data.message) || error.response.status));
|
|
18430
|
-
} else {
|
|
18431
|
-
console.error("Upload error: ".concat(error.message));
|
|
18432
|
-
}
|
|
18433
|
-
} finally {
|
|
18434
|
-
resetUploadState();
|
|
18603
|
+
handleError(error, 'SELECT NODE');
|
|
18604
|
+
updateTreeState({
|
|
18605
|
+
loading: false
|
|
18606
|
+
});
|
|
18435
18607
|
}
|
|
18436
|
-
};
|
|
18437
|
-
const uploadFiles = async (files, folder) => {
|
|
18438
|
-
// 计算所有文件的总大小
|
|
18439
|
-
const totalSize = calculateTotalSize(files);
|
|
18440
|
-
// 存储每个文件的上一次 loaded 值(避免重复计算)
|
|
18441
|
-
const previousLoadedMap = new Map();
|
|
18442
|
-
let uploadedSize = 0; // 记录已上传的字节数
|
|
18608
|
+
}, [treeState.selectedKeys, treeState.currentPath]);
|
|
18443
18609
|
|
|
18444
|
-
|
|
18445
|
-
|
|
18446
|
-
|
|
18447
|
-
|
|
18448
|
-
|
|
18449
|
-
};
|
|
18610
|
+
// 展开节点
|
|
18611
|
+
const onExpand = useCallback(keys => {
|
|
18612
|
+
updateTreeState({
|
|
18613
|
+
expandedKeys: keys
|
|
18614
|
+
});
|
|
18615
|
+
}, []);
|
|
18450
18616
|
|
|
18451
|
-
//
|
|
18452
|
-
const
|
|
18617
|
+
// 创建文件夹
|
|
18618
|
+
const handleCreate = useCallback(async (node, newTitle) => {
|
|
18619
|
+
if (!(newTitle !== null && newTitle !== void 0 && newTitle.trim())) return false;
|
|
18620
|
+
try {
|
|
18621
|
+
const path = pathUtils.replaceRoot("".concat(node.path, "/").concat(newTitle));
|
|
18622
|
+
await createFolder({
|
|
18623
|
+
path
|
|
18624
|
+
});
|
|
18453
18625
|
|
|
18454
|
-
|
|
18455
|
-
|
|
18456
|
-
|
|
18457
|
-
|
|
18458
|
-
|
|
18459
|
-
|
|
18460
|
-
|
|
18461
|
-
|
|
18462
|
-
|
|
18463
|
-
}
|
|
18464
|
-
|
|
18465
|
-
|
|
18466
|
-
|
|
18467
|
-
|
|
18468
|
-
|
|
18469
|
-
|
|
18470
|
-
|
|
18471
|
-
|
|
18472
|
-
|
|
18473
|
-
onProgress(newLoaded);
|
|
18474
|
-
}
|
|
18626
|
+
// 刷新树结构
|
|
18627
|
+
const newTreeData = await getTreeStructure('');
|
|
18628
|
+
if (!newTreeData) return;
|
|
18629
|
+
|
|
18630
|
+
// 查找新增的节点
|
|
18631
|
+
const newPath = "".concat(node.path, "/").concat(newTitle);
|
|
18632
|
+
const foundNodes = findTreeNodeByPath(newTreeData, newPath, {
|
|
18633
|
+
exactMatch: true,
|
|
18634
|
+
returnFirst: true
|
|
18635
|
+
});
|
|
18636
|
+
const addedNode = foundNodes[0];
|
|
18637
|
+
if (addedNode) {
|
|
18638
|
+
updateTreeState({
|
|
18639
|
+
data: newTreeData,
|
|
18640
|
+
selectedKeys: [addedNode.key],
|
|
18641
|
+
expandedKeys: [...treeState.expandedKeys, addedNode.key, node.key],
|
|
18642
|
+
currentPath: addedNode.path,
|
|
18643
|
+
contents: []
|
|
18644
|
+
});
|
|
18475
18645
|
}
|
|
18476
|
-
})
|
|
18477
|
-
|
|
18478
|
-
|
|
18479
|
-
|
|
18480
|
-
setPercent(totalPercent);
|
|
18481
|
-
};
|
|
18646
|
+
} catch (error) {
|
|
18647
|
+
handleError(error, 'CREATE FOLDER');
|
|
18648
|
+
}
|
|
18649
|
+
}, [getTreeStructure, treeState.expandedKeys]);
|
|
18482
18650
|
|
|
18483
|
-
//
|
|
18484
|
-
const
|
|
18485
|
-
|
|
18486
|
-
|
|
18487
|
-
|
|
18488
|
-
|
|
18651
|
+
// 删除文件/文件夹
|
|
18652
|
+
const handleRemove = useCallback(async node => {
|
|
18653
|
+
if (!node.path) return;
|
|
18654
|
+
try {
|
|
18655
|
+
// 执行删除
|
|
18656
|
+
batchOperations ? await removeFolderFile({
|
|
18657
|
+
paths: [{
|
|
18658
|
+
path: pathUtils.replaceRoot(node.path)
|
|
18659
|
+
}]
|
|
18660
|
+
}) : await removeFolderFile({
|
|
18661
|
+
path: pathUtils.replaceRoot(node.path)
|
|
18662
|
+
});
|
|
18489
18663
|
|
|
18490
|
-
|
|
18491
|
-
|
|
18664
|
+
// 检查是否删除的是当前选中的节点
|
|
18665
|
+
const isSelectedNode = treeState.selectedKeys[0] === node.key;
|
|
18666
|
+
const isCurrentPath = pathUtils.isSamePath(treeState.currentPath, node.path);
|
|
18667
|
+
if (isSelectedNode || isCurrentPath) {
|
|
18668
|
+
// 查找父节点
|
|
18669
|
+
const parentPath = pathUtils.getParentPath(node.path);
|
|
18670
|
+
if (parentPath) {
|
|
18671
|
+
// 刷新树结构
|
|
18672
|
+
const newTreeData = await getTreeStructure('');
|
|
18673
|
+
if (!newTreeData) return;
|
|
18674
|
+
|
|
18675
|
+
// 尝试找到父节点
|
|
18676
|
+
const foundParentNodes = findTreeNodeByPath(newTreeData, parentPath, {
|
|
18677
|
+
exactMatch: true,
|
|
18678
|
+
returnFirst: true
|
|
18679
|
+
});
|
|
18680
|
+
const parentNode = foundParentNodes[0];
|
|
18681
|
+
if (parentNode) {
|
|
18682
|
+
// 选中父节点
|
|
18683
|
+
updateTreeState({
|
|
18684
|
+
data: newTreeData,
|
|
18685
|
+
selectedKeys: [parentNode.key],
|
|
18686
|
+
currentPath: parentNode.path,
|
|
18687
|
+
contents: parentNode.contents
|
|
18688
|
+
});
|
|
18689
|
+
} else {
|
|
18690
|
+
// 找不到父节点,选中第一个根节点
|
|
18691
|
+
const firstNode = newTreeData[0];
|
|
18692
|
+
if (firstNode) {
|
|
18693
|
+
updateTreeState({
|
|
18694
|
+
data: newTreeData,
|
|
18695
|
+
selectedKeys: [firstNode.key],
|
|
18696
|
+
currentPath: firstNode.path,
|
|
18697
|
+
contents: firstNode.contents
|
|
18698
|
+
});
|
|
18699
|
+
} else {
|
|
18700
|
+
// 树为空
|
|
18701
|
+
updateTreeState({
|
|
18702
|
+
data: newTreeData,
|
|
18703
|
+
selectedKeys: [],
|
|
18704
|
+
currentPath: '',
|
|
18705
|
+
contents: []
|
|
18706
|
+
});
|
|
18707
|
+
}
|
|
18708
|
+
}
|
|
18709
|
+
} else {
|
|
18710
|
+
// 删除的是根节点,重新初始化
|
|
18711
|
+
await initTreeData();
|
|
18712
|
+
}
|
|
18713
|
+
} else {
|
|
18714
|
+
// 删除的不是当前选中节点,只刷新树结构
|
|
18715
|
+
const newTreeData = await getTreeStructure('');
|
|
18716
|
+
if (newTreeData) {
|
|
18717
|
+
updateTreeState({
|
|
18718
|
+
data: newTreeData
|
|
18719
|
+
});
|
|
18720
|
+
}
|
|
18721
|
+
}
|
|
18722
|
+
} catch (error) {
|
|
18723
|
+
handleError(error, 'REMOVE FOLDER/FILE');
|
|
18724
|
+
}
|
|
18725
|
+
}, [getTreeStructure, initTreeData, treeState.selectedKeys, treeState.currentPath]);
|
|
18726
|
+
|
|
18727
|
+
// 重命名
|
|
18728
|
+
const handleRename = useCallback(async node => {
|
|
18729
|
+
const newPath = pathUtils.getNewPath(node, node.title);
|
|
18730
|
+
if (pathUtils.isSamePath(node.path, newPath)) return false;
|
|
18492
18731
|
try {
|
|
18493
|
-
|
|
18494
|
-
|
|
18495
|
-
|
|
18732
|
+
await renameFolderFile({
|
|
18733
|
+
old_path: pathUtils.replaceRoot(node.path),
|
|
18734
|
+
new_path: pathUtils.replaceRoot(newPath)
|
|
18735
|
+
});
|
|
18496
18736
|
|
|
18497
|
-
|
|
18498
|
-
|
|
18499
|
-
|
|
18500
|
-
|
|
18501
|
-
|
|
18502
|
-
|
|
18503
|
-
|
|
18737
|
+
// 刷新树结构
|
|
18738
|
+
const newTreeData = await getTreeStructure('');
|
|
18739
|
+
if (newTreeData) {
|
|
18740
|
+
updateTreeState({
|
|
18741
|
+
data: newTreeData
|
|
18742
|
+
});
|
|
18743
|
+
}
|
|
18504
18744
|
} catch (error) {
|
|
18505
|
-
|
|
18745
|
+
handleError(error, 'RENAME FOLDER/FILE');
|
|
18506
18746
|
}
|
|
18507
|
-
};
|
|
18508
|
-
const copyFile = () => {
|
|
18509
|
-
setModalVisible(true);
|
|
18510
|
-
};
|
|
18511
|
-
const onContextMenu = (key, item) => {
|
|
18512
|
-
if (key === 'del') removeFile(item.url);
|
|
18513
|
-
if (key === 'download') downloadFile(item.url);
|
|
18514
|
-
if (key === 'copy') copyFile(item.url);
|
|
18515
|
-
};
|
|
18516
|
-
const handleBatchRemove = useCallback(async () => {
|
|
18517
|
-
if (!selectedItems.length) return;
|
|
18518
|
-
modal.confirm({
|
|
18519
|
-
icon: /*#__PURE__*/jsx(ExclamationCircleFilled, {}),
|
|
18520
|
-
title: "Are you sure you want to delete ".concat(selectedItems.length, " files?"),
|
|
18521
|
-
cancelText: "No",
|
|
18522
|
-
okText: "Yes",
|
|
18523
|
-
onOk: async () => {
|
|
18524
|
-
try {
|
|
18525
|
-
// 批量处理所有删除请求
|
|
18526
|
-
await mergedApiConfig.removeFolderFile({
|
|
18527
|
-
paths: selectedItems.map(itemUrl => ({
|
|
18528
|
-
path: itemUrl
|
|
18529
|
-
}))
|
|
18530
|
-
});
|
|
18747
|
+
}, [getTreeStructure]);
|
|
18531
18748
|
|
|
18532
|
-
|
|
18533
|
-
|
|
18534
|
-
|
|
18535
|
-
|
|
18536
|
-
|
|
18537
|
-
|
|
18538
|
-
|
|
18749
|
+
// 刷新树数据
|
|
18750
|
+
const refreshTreeData = useCallback(async () => {
|
|
18751
|
+
try {
|
|
18752
|
+
const newTreeData = await getTreeStructure('');
|
|
18753
|
+
if (!newTreeData) return;
|
|
18754
|
+
|
|
18755
|
+
// 保持当前选中状态
|
|
18756
|
+
const currentPath = treeState.currentPath;
|
|
18757
|
+
if (currentPath) {
|
|
18758
|
+
const foundNodes = findTreeNodeByPath(newTreeData, currentPath, {
|
|
18759
|
+
exactMatch: true,
|
|
18760
|
+
returnFirst: true
|
|
18761
|
+
});
|
|
18762
|
+
const currentNode = foundNodes[0];
|
|
18763
|
+
if (currentNode) {
|
|
18764
|
+
updateTreeState({
|
|
18765
|
+
data: newTreeData,
|
|
18766
|
+
selectedKeys: [currentNode.key],
|
|
18767
|
+
contents: currentNode.contents
|
|
18768
|
+
});
|
|
18769
|
+
} else {
|
|
18770
|
+
// 当前节点不存在,选中第一个节点
|
|
18771
|
+
const firstNode = newTreeData[0];
|
|
18772
|
+
if (firstNode) {
|
|
18773
|
+
updateTreeState({
|
|
18774
|
+
data: newTreeData,
|
|
18775
|
+
selectedKeys: [firstNode.key],
|
|
18776
|
+
currentPath: firstNode.path,
|
|
18777
|
+
contents: firstNode.contents
|
|
18778
|
+
});
|
|
18779
|
+
} else {
|
|
18780
|
+
updateTreeState({
|
|
18781
|
+
data: newTreeData,
|
|
18782
|
+
selectedKeys: [],
|
|
18783
|
+
currentPath: '',
|
|
18784
|
+
contents: []
|
|
18785
|
+
});
|
|
18786
|
+
}
|
|
18539
18787
|
}
|
|
18788
|
+
} else {
|
|
18789
|
+
updateTreeState({
|
|
18790
|
+
data: newTreeData
|
|
18791
|
+
});
|
|
18540
18792
|
}
|
|
18541
|
-
})
|
|
18542
|
-
|
|
18543
|
-
|
|
18544
|
-
|
|
18793
|
+
} catch (error) {
|
|
18794
|
+
handleError(error, 'REFRESH TREE DATA');
|
|
18795
|
+
}
|
|
18796
|
+
}, [getTreeStructure, treeState.currentPath]);
|
|
18797
|
+
|
|
18798
|
+
// 更新文件contents (上传右侧文件或删除右侧文件 成功后的回调函数)
|
|
18799
|
+
const updateFileContents = useCallback(async () => {
|
|
18800
|
+
if (!treeState.currentPath) return;
|
|
18545
18801
|
try {
|
|
18546
|
-
|
|
18547
|
-
|
|
18548
|
-
|
|
18549
|
-
|
|
18550
|
-
|
|
18551
|
-
new_path: newPath
|
|
18802
|
+
const newTreeData = await getTreeStructure('');
|
|
18803
|
+
if (!newTreeData) return;
|
|
18804
|
+
const foundNodes = findTreeNodeByPath(newTreeData, treeState.currentPath, {
|
|
18805
|
+
exactMatch: true,
|
|
18806
|
+
returnFirst: true
|
|
18552
18807
|
});
|
|
18808
|
+
const currentNode = foundNodes[0];
|
|
18809
|
+
if (currentNode) {
|
|
18810
|
+
updateTreeState({
|
|
18811
|
+
contents: currentNode.contents
|
|
18812
|
+
});
|
|
18813
|
+
}
|
|
18814
|
+
} catch (error) {
|
|
18815
|
+
handleError(error, 'UPDATE FILE CONTENTS');
|
|
18816
|
+
}
|
|
18817
|
+
}, [getTreeStructure, treeState.currentPath]);
|
|
18553
18818
|
|
|
18554
|
-
|
|
18555
|
-
|
|
18556
|
-
|
|
18557
|
-
|
|
18558
|
-
|
|
18559
|
-
|
|
18560
|
-
|
|
18561
|
-
// 延迟2s刷新数据
|
|
18562
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
18819
|
+
// 删除文件
|
|
18820
|
+
const removeFile = useCallback(async url => {
|
|
18821
|
+
try {
|
|
18822
|
+
await removeFolderFile({
|
|
18823
|
+
path: url
|
|
18824
|
+
});
|
|
18563
18825
|
await updateFileContents();
|
|
18564
18826
|
} catch (error) {
|
|
18565
|
-
|
|
18566
|
-
} finally {
|
|
18567
|
-
setBatchLoading(false);
|
|
18827
|
+
handleError(error, 'REMOVE FILE');
|
|
18568
18828
|
}
|
|
18569
|
-
}, [
|
|
18570
|
-
|
|
18571
|
-
|
|
18572
|
-
|
|
18573
|
-
|
|
18574
|
-
|
|
18575
|
-
|
|
18576
|
-
|
|
18577
|
-
|
|
18578
|
-
|
|
18579
|
-
|
|
18580
|
-
|
|
18581
|
-
|
|
18582
|
-
|
|
18583
|
-
|
|
18584
|
-
|
|
18585
|
-
|
|
18586
|
-
|
|
18587
|
-
|
|
18588
|
-
|
|
18589
|
-
|
|
18829
|
+
}, [updateFileContents]);
|
|
18830
|
+
const MemoizedTree = useMemo(() => {
|
|
18831
|
+
var _treeState$data;
|
|
18832
|
+
if (!((_treeState$data = treeState.data) !== null && _treeState$data !== void 0 && _treeState$data.length)) {
|
|
18833
|
+
return /*#__PURE__*/jsx(Empty, {
|
|
18834
|
+
image: Empty.PRESENTED_IMAGE_SIMPLE
|
|
18835
|
+
});
|
|
18836
|
+
}
|
|
18837
|
+
return /*#__PURE__*/jsx("div", {
|
|
18838
|
+
style: wrapperStyle,
|
|
18839
|
+
children: /*#__PURE__*/jsx(ConfigProvider, {
|
|
18840
|
+
theme: theme,
|
|
18841
|
+
children: /*#__PURE__*/jsx(Tree, {
|
|
18842
|
+
blockNode: true,
|
|
18843
|
+
showIcon: true,
|
|
18844
|
+
selectedKeys: treeState.selectedKeys,
|
|
18845
|
+
expandedKeys: treeState.expandedKeys,
|
|
18846
|
+
onSelect: onSelect,
|
|
18847
|
+
onExpand: expandable ? onExpand : undefined // 不允许展开时不绑定事件
|
|
18848
|
+
,
|
|
18849
|
+
treeData: treeState.data,
|
|
18850
|
+
titleRender: nodeData => /*#__PURE__*/jsx(TreeTitle$1, {
|
|
18851
|
+
title: nodeData.title,
|
|
18852
|
+
nodeData: nodeData,
|
|
18853
|
+
isEditable: isEditable,
|
|
18854
|
+
handleSave: handleRename,
|
|
18855
|
+
handleDel: handleRemove,
|
|
18856
|
+
handleAdd: handleCreate
|
|
18857
|
+
}),
|
|
18858
|
+
height: height,
|
|
18859
|
+
style: treeStyle
|
|
18860
|
+
})
|
|
18861
|
+
})
|
|
18862
|
+
}, "folder-directory");
|
|
18863
|
+
}, [treeState.data, treeState.selectedKeys, treeState.expandedKeys]);
|
|
18864
|
+
return {
|
|
18865
|
+
directoryTree: MemoizedTree,
|
|
18866
|
+
contents: treeState.contents,
|
|
18867
|
+
currentPath: treeState.currentPath,
|
|
18868
|
+
loading: treeState.loading,
|
|
18869
|
+
originTreeData,
|
|
18870
|
+
updateFileContents,
|
|
18871
|
+
removeFile,
|
|
18872
|
+
refreshTreeData,
|
|
18873
|
+
// 暴露刷新方法
|
|
18874
|
+
fetchFolderData: refreshTreeData // 也可以保留别名
|
|
18590
18875
|
};
|
|
18591
|
-
|
|
18592
|
-
// 创建 URL 构建器
|
|
18593
|
-
const getFullUrl = useMemo(() => {
|
|
18594
|
-
return createUrlBuilder({
|
|
18595
|
-
baseUrl: apiConfig.baseUrl,
|
|
18596
|
-
devBaseUrl: apiConfig.devBaseUrl,
|
|
18597
|
-
isDev: process.env.NODE_ENV === 'development',
|
|
18598
|
-
isBrowser: typeof window !== 'undefined'
|
|
18599
|
-
});
|
|
18600
|
-
}, [apiConfig.baseUrl, apiConfig.devBaseUrl]);
|
|
18601
|
-
return /*#__PURE__*/jsxs("div", {
|
|
18602
|
-
className: "resources-view ".concat(className),
|
|
18603
|
-
style: style,
|
|
18604
|
-
children: [/*#__PURE__*/jsxs("div", {
|
|
18605
|
-
className: "content-container",
|
|
18606
|
-
children: [/*#__PURE__*/jsxs("div", {
|
|
18607
|
-
className: "directory-tree",
|
|
18608
|
-
children: [renderTreeHeader ? renderTreeHeader() : /*#__PURE__*/jsx("div", {
|
|
18609
|
-
className: "search-bar"
|
|
18610
|
-
}), directoryTree]
|
|
18611
|
-
}), /*#__PURE__*/jsxs("div", {
|
|
18612
|
-
className: "folder-contents",
|
|
18613
|
-
children: [/*#__PURE__*/jsxs(Flex, {
|
|
18614
|
-
justify: "center",
|
|
18615
|
-
align: "center",
|
|
18616
|
-
className: "search-bar",
|
|
18617
|
-
children: [mergedFeatures.search && /*#__PURE__*/jsx(Input, {
|
|
18618
|
-
value: keyword,
|
|
18619
|
-
onChange: handleSearchChange,
|
|
18620
|
-
placeholder: searchPlaceholder,
|
|
18621
|
-
prefix: /*#__PURE__*/jsx(SearchOutlined, {}),
|
|
18622
|
-
allowClear: true,
|
|
18623
|
-
className: "search-input"
|
|
18624
|
-
}), mergedFeatures.upload && /*#__PURE__*/jsxs(Fragment, {
|
|
18625
|
-
children: [/*#__PURE__*/jsx(CloudUploadOutlined, {
|
|
18626
|
-
className: "upload-icon",
|
|
18627
|
-
title: "upload",
|
|
18628
|
-
onClick: onTriggerUpload
|
|
18629
|
-
}), /*#__PURE__*/jsx("input", {
|
|
18630
|
-
ref: inputRef,
|
|
18631
|
-
type: "file",
|
|
18632
|
-
onChange: onUploadFile,
|
|
18633
|
-
className: "hidden",
|
|
18634
|
-
accept: acceptFileTypes,
|
|
18635
|
-
multiple: true
|
|
18636
|
-
})]
|
|
18637
|
-
})]
|
|
18638
|
-
}), /*#__PURE__*/jsxs("div", {
|
|
18639
|
-
className: "media-grid-container",
|
|
18640
|
-
onContextMenu: e => e.preventDefault(),
|
|
18641
|
-
children: [renderGridHeader ? renderGridHeader() : filteredContents.length > 0 && mergedFeatures.batchOperations && /*#__PURE__*/jsx("div", {
|
|
18642
|
-
className: "batch-operations",
|
|
18643
|
-
children: /*#__PURE__*/jsxs(Space, {
|
|
18644
|
-
size: "middle",
|
|
18645
|
-
children: [/*#__PURE__*/jsx(Checkbox, {
|
|
18646
|
-
indeterminate: indeterminate,
|
|
18647
|
-
checked: checkAll,
|
|
18648
|
-
onChange: handleSelectAll,
|
|
18649
|
-
children: "Select All"
|
|
18650
|
-
}), /*#__PURE__*/jsx(Button, {
|
|
18651
|
-
type: "primary",
|
|
18652
|
-
disabled: !selectedItems.length,
|
|
18653
|
-
onClick: () => setModalVisible(true),
|
|
18654
|
-
children: "Copy"
|
|
18655
|
-
}), /*#__PURE__*/jsx(Button, {
|
|
18656
|
-
className: "btn-gray",
|
|
18657
|
-
disabled: !selectedItems.length,
|
|
18658
|
-
onClick: handleBatchRemove,
|
|
18659
|
-
children: "Delete"
|
|
18660
|
-
})]
|
|
18661
|
-
})
|
|
18662
|
-
}), /*#__PURE__*/jsx(MediaGrid$1, {
|
|
18663
|
-
items: filteredContents,
|
|
18664
|
-
loading: loading,
|
|
18665
|
-
onContextMenu: mergedFeatures.delete || mergedFeatures.download || mergedFeatures.copy ? onContextMenu : null,
|
|
18666
|
-
selectedKeys: selectedItems,
|
|
18667
|
-
showCheckbox: mergedFeatures.batchOperations,
|
|
18668
|
-
onSelectChange: mergedFeatures.batchOperations ? handleSelectChange : null,
|
|
18669
|
-
gridConfig: mergedFeatures.batchOperations ? {
|
|
18670
|
-
gutter: 0,
|
|
18671
|
-
column: 6
|
|
18672
|
-
} : {
|
|
18673
|
-
gutter: 24,
|
|
18674
|
-
column: 6
|
|
18675
|
-
},
|
|
18676
|
-
features: mergedFeatures,
|
|
18677
|
-
getFullUrl: getFullUrl
|
|
18678
|
-
})]
|
|
18679
|
-
})]
|
|
18680
|
-
})]
|
|
18681
|
-
}), showProgress && /*#__PURE__*/jsx(UploadProgress$1, {
|
|
18682
|
-
percent: percent
|
|
18683
|
-
}), /*#__PURE__*/jsx(SelectFolderPathModal$1, {
|
|
18684
|
-
open: modalVisible,
|
|
18685
|
-
directoryTree: originTreeData,
|
|
18686
|
-
batchLoading: batchLoading,
|
|
18687
|
-
onClose: () => setModalVisible(false),
|
|
18688
|
-
onOk: handleCopyConfirm
|
|
18689
|
-
})]
|
|
18690
|
-
});
|
|
18691
18876
|
};
|
|
18692
|
-
var ResourcesView$1 = ResourcesView;
|
|
18693
18877
|
|
|
18694
18878
|
export { ResourcesView$1 as ResourcesView, useDirectoryTree };
|
|
18695
18879
|
//# sourceMappingURL=index.esm.js.map
|