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