seeder-st2110-components 1.2.4 → 1.2.5
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 +569 -4
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +566 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -668,6 +668,571 @@ const useSystemOperations = function () {
|
|
|
668
668
|
};
|
|
669
669
|
};
|
|
670
670
|
|
|
671
|
+
const PopoverContent = /*#__PURE__*/react.forwardRef((_ref, ref) => {
|
|
672
|
+
let {
|
|
673
|
+
onClose,
|
|
674
|
+
onConfirm
|
|
675
|
+
} = _ref;
|
|
676
|
+
const [value, setValue] = react.useState('');
|
|
677
|
+
const handleConfirm = react.useCallback(() => {
|
|
678
|
+
onConfirm(value, () => setValue(''));
|
|
679
|
+
}, [confirm, value]);
|
|
680
|
+
const handleKeyDown = react.useCallback(e => {
|
|
681
|
+
if (e.key === 'Enter') {
|
|
682
|
+
handleConfirm();
|
|
683
|
+
}
|
|
684
|
+
}, [handleConfirm]);
|
|
685
|
+
return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
686
|
+
children: [/*#__PURE__*/jsxRuntime.jsx(antd.Form.Item, {
|
|
687
|
+
label: "Folder Name",
|
|
688
|
+
style: {
|
|
689
|
+
marginBottom: 8
|
|
690
|
+
},
|
|
691
|
+
children: /*#__PURE__*/jsxRuntime.jsx(antd.Input, {
|
|
692
|
+
ref: ref,
|
|
693
|
+
value: value,
|
|
694
|
+
onChange: e => setValue(e.target.value),
|
|
695
|
+
onKeyDown: handleKeyDown,
|
|
696
|
+
size: "small",
|
|
697
|
+
style: {
|
|
698
|
+
width: 120
|
|
699
|
+
},
|
|
700
|
+
autoFocus: true
|
|
701
|
+
})
|
|
702
|
+
}), /*#__PURE__*/jsxRuntime.jsxs(antd.Flex, {
|
|
703
|
+
justify: "flex-end",
|
|
704
|
+
gap: "small",
|
|
705
|
+
children: [/*#__PURE__*/jsxRuntime.jsx(antd.Button, {
|
|
706
|
+
type: "default",
|
|
707
|
+
size: "small",
|
|
708
|
+
onClick: onClose,
|
|
709
|
+
children: "Close"
|
|
710
|
+
}), /*#__PURE__*/jsxRuntime.jsx(antd.Button, {
|
|
711
|
+
type: "primary",
|
|
712
|
+
size: "small",
|
|
713
|
+
onClick: handleConfirm,
|
|
714
|
+
children: "OK"
|
|
715
|
+
})]
|
|
716
|
+
})]
|
|
717
|
+
});
|
|
718
|
+
});
|
|
719
|
+
const EditablePopover = _ref2 => {
|
|
720
|
+
let {
|
|
721
|
+
children,
|
|
722
|
+
add
|
|
723
|
+
} = _ref2;
|
|
724
|
+
const inputRef = react.useRef(null);
|
|
725
|
+
const [open, setOpen] = react.useState(false);
|
|
726
|
+
react.useEffect(() => {
|
|
727
|
+
if (open && inputRef.current) {
|
|
728
|
+
const timer = setTimeout(() => {
|
|
729
|
+
inputRef.current?.focus();
|
|
730
|
+
}, 100);
|
|
731
|
+
return () => clearTimeout(timer);
|
|
732
|
+
}
|
|
733
|
+
}, [open]);
|
|
734
|
+
|
|
735
|
+
// 使用 open 属性控制浮层显示
|
|
736
|
+
const hide = react.useCallback(() => {
|
|
737
|
+
setOpen(false);
|
|
738
|
+
}, []);
|
|
739
|
+
const handleConfirm = react.useCallback((newTitle, callback) => {
|
|
740
|
+
add(newTitle);
|
|
741
|
+
callback?.();
|
|
742
|
+
hide();
|
|
743
|
+
}, [add, hide]);
|
|
744
|
+
const handleOpenChange = react.useCallback(newOpen => {
|
|
745
|
+
setOpen(newOpen);
|
|
746
|
+
}, []);
|
|
747
|
+
return /*#__PURE__*/jsxRuntime.jsx(antd.Popover, {
|
|
748
|
+
content: /*#__PURE__*/jsxRuntime.jsx(PopoverContent, {
|
|
749
|
+
ref: inputRef,
|
|
750
|
+
onClose: hide,
|
|
751
|
+
onConfirm: handleConfirm
|
|
752
|
+
}),
|
|
753
|
+
trigger: "click",
|
|
754
|
+
open: open,
|
|
755
|
+
onOpenChange: handleOpenChange,
|
|
756
|
+
destroyOnHidden: true,
|
|
757
|
+
children: children
|
|
758
|
+
});
|
|
759
|
+
};
|
|
760
|
+
var EditablePopover$1 = /*#__PURE__*/react.memo(EditablePopover);
|
|
761
|
+
|
|
762
|
+
const EditableContext = /*#__PURE__*/react.createContext(null);
|
|
763
|
+
const TreeTitle = _ref => {
|
|
764
|
+
let {
|
|
765
|
+
...props
|
|
766
|
+
} = _ref;
|
|
767
|
+
const [form] = antd.Form.useForm();
|
|
768
|
+
return /*#__PURE__*/jsxRuntime.jsx(antd.Form, {
|
|
769
|
+
form: form,
|
|
770
|
+
component: false,
|
|
771
|
+
children: /*#__PURE__*/jsxRuntime.jsx(EditableContext.Provider, {
|
|
772
|
+
value: form,
|
|
773
|
+
children: /*#__PURE__*/jsxRuntime.jsx(TreeTitleNode, {
|
|
774
|
+
...props
|
|
775
|
+
})
|
|
776
|
+
})
|
|
777
|
+
});
|
|
778
|
+
};
|
|
779
|
+
const TreeTitleNode = _ref2 => {
|
|
780
|
+
let {
|
|
781
|
+
title,
|
|
782
|
+
nodeData,
|
|
783
|
+
handleSave,
|
|
784
|
+
handleDel,
|
|
785
|
+
handleAdd
|
|
786
|
+
} = _ref2;
|
|
787
|
+
const [editing, setEditing] = react.useState(false);
|
|
788
|
+
const inputRef = react.useRef(null);
|
|
789
|
+
const form = react.useContext(EditableContext);
|
|
790
|
+
react.useEffect(() => {
|
|
791
|
+
if (editing) {
|
|
792
|
+
inputRef.current?.focus();
|
|
793
|
+
}
|
|
794
|
+
}, [editing]);
|
|
795
|
+
const toggleEdit = react.useCallback(() => {
|
|
796
|
+
setEditing(prev => !prev);
|
|
797
|
+
form.setFieldsValue({
|
|
798
|
+
[nodeData.title]: nodeData.title
|
|
799
|
+
});
|
|
800
|
+
}, [form, nodeData.title]);
|
|
801
|
+
const save = react.useCallback(async () => {
|
|
802
|
+
try {
|
|
803
|
+
const values = await form.validateFields();
|
|
804
|
+
toggleEdit();
|
|
805
|
+
handleSave({
|
|
806
|
+
...nodeData,
|
|
807
|
+
title: values[nodeData.title]
|
|
808
|
+
});
|
|
809
|
+
} catch (errInfo) {
|
|
810
|
+
console.error('Save failed:', errInfo);
|
|
811
|
+
}
|
|
812
|
+
}, [form, toggleEdit, handleSave, nodeData]);
|
|
813
|
+
|
|
814
|
+
// 新建文件夹
|
|
815
|
+
// 修改文件/文件夹
|
|
816
|
+
// 删除文件/文件夹
|
|
817
|
+
const renderIconNode = react.useCallback(() => {
|
|
818
|
+
return /*#__PURE__*/jsxRuntime.jsxs("span", {
|
|
819
|
+
className: "icon-node",
|
|
820
|
+
onClick: e => e.stopPropagation(),
|
|
821
|
+
children: [/*#__PURE__*/jsxRuntime.jsx(EditablePopover$1, {
|
|
822
|
+
add: newTitle => handleAdd(nodeData, newTitle),
|
|
823
|
+
children: /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
824
|
+
className: "px-1",
|
|
825
|
+
title: "create",
|
|
826
|
+
children: /*#__PURE__*/jsxRuntime.jsx("i", {
|
|
827
|
+
className: "iconfont icon-jia"
|
|
828
|
+
})
|
|
829
|
+
})
|
|
830
|
+
}), !nodeData.isRoot && /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
831
|
+
children: [/*#__PURE__*/jsxRuntime.jsx("div", {
|
|
832
|
+
className: "px-1",
|
|
833
|
+
onClick: toggleEdit,
|
|
834
|
+
title: "edit",
|
|
835
|
+
children: /*#__PURE__*/jsxRuntime.jsx("i", {
|
|
836
|
+
className: "iconfont icon-bianji"
|
|
837
|
+
})
|
|
838
|
+
}), /*#__PURE__*/jsxRuntime.jsx(antd.Popconfirm, {
|
|
839
|
+
title: "Confirm to delete?",
|
|
840
|
+
onConfirm: () => handleDel(nodeData),
|
|
841
|
+
okText: "Yes",
|
|
842
|
+
cancelText: "No",
|
|
843
|
+
children: /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
844
|
+
className: "px-1",
|
|
845
|
+
title: "delete",
|
|
846
|
+
children: /*#__PURE__*/jsxRuntime.jsx("i", {
|
|
847
|
+
className: "iconfont icon-jian"
|
|
848
|
+
})
|
|
849
|
+
})
|
|
850
|
+
})]
|
|
851
|
+
})]
|
|
852
|
+
});
|
|
853
|
+
}, [handleAdd, nodeData, title, toggleEdit, handleDel]);
|
|
854
|
+
const renderChildNode = react.useCallback(() => {
|
|
855
|
+
return editing ? /*#__PURE__*/jsxRuntime.jsx(antd.Form.Item, {
|
|
856
|
+
style: {
|
|
857
|
+
margin: 0,
|
|
858
|
+
width: "100%"
|
|
859
|
+
},
|
|
860
|
+
name: nodeData.title,
|
|
861
|
+
children: /*#__PURE__*/jsxRuntime.jsx(antd.Input, {
|
|
862
|
+
ref: inputRef,
|
|
863
|
+
onPressEnter: save,
|
|
864
|
+
onBlur: save,
|
|
865
|
+
autoComplete: "off",
|
|
866
|
+
size: "small"
|
|
867
|
+
})
|
|
868
|
+
}) : /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
869
|
+
children: [/*#__PURE__*/jsxRuntime.jsx(antd.Typography.Text, {
|
|
870
|
+
ellipsis: true,
|
|
871
|
+
style: {
|
|
872
|
+
width: "75%"
|
|
873
|
+
},
|
|
874
|
+
children: title
|
|
875
|
+
}), renderIconNode()]
|
|
876
|
+
});
|
|
877
|
+
}, [editing, nodeData.title, save, title, renderIconNode]);
|
|
878
|
+
return /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
879
|
+
className: "tree-title",
|
|
880
|
+
children: renderChildNode()
|
|
881
|
+
});
|
|
882
|
+
};
|
|
883
|
+
var TreeTitle$1 = /*#__PURE__*/react.memo(TreeTitle);
|
|
884
|
+
|
|
885
|
+
const replaceRootPath = path => {
|
|
886
|
+
if (typeof path !== 'string') return '';
|
|
887
|
+
return path.startsWith('root/') ? path.slice(5) : path;
|
|
888
|
+
};
|
|
889
|
+
|
|
890
|
+
/**
|
|
891
|
+
* 递归转换目录结构为树形结构
|
|
892
|
+
* @param {Array} data - 原始数据
|
|
893
|
+
* @param {string} [basePath='0'] - 基础路径
|
|
894
|
+
* @param {string} [parentRoute] - 父级路由路径
|
|
895
|
+
* @returns {Array} 转换后的树形结构
|
|
896
|
+
*/
|
|
897
|
+
const buildDirectoryTree = function (data) {
|
|
898
|
+
let basePath = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '0';
|
|
899
|
+
let parentRoute = arguments.length > 2 ? arguments[2] : undefined;
|
|
900
|
+
if (!Array.isArray(data)) return [];
|
|
901
|
+
return data.reduce((acc, item, index) => {
|
|
902
|
+
// 跳过文件类型,只处理目录
|
|
903
|
+
if (item.type === 'file') return acc;
|
|
904
|
+
const title = parentRoute ? item.name : item.sd_index || item.name;
|
|
905
|
+
const key = `${basePath}-${index}`;
|
|
906
|
+
const currentPath = parentRoute ? `${parentRoute}/${title}` : item.path || title;
|
|
907
|
+
const treeNode = {
|
|
908
|
+
title,
|
|
909
|
+
// 文件/文件夹名称
|
|
910
|
+
key,
|
|
911
|
+
icon: _ref => {
|
|
912
|
+
let {
|
|
913
|
+
expanded
|
|
914
|
+
} = _ref;
|
|
915
|
+
return expanded ? /*#__PURE__*/jsxRuntime.jsx(icons.FolderOpenOutlined, {}) : /*#__PURE__*/jsxRuntime.jsx(icons.FolderOutlined, {});
|
|
916
|
+
},
|
|
917
|
+
children: [],
|
|
918
|
+
isLeaf: false,
|
|
919
|
+
isRoot: Boolean(item.sd_index),
|
|
920
|
+
path: currentPath,
|
|
921
|
+
contents: (item.contents || []).filter(content => content.type === 'file'),
|
|
922
|
+
rawData: item // 保留原始数据
|
|
923
|
+
};
|
|
924
|
+
|
|
925
|
+
// 递归处理子目录
|
|
926
|
+
if (Array.isArray(item.contents) && item.contents.length > 0) {
|
|
927
|
+
treeNode.children = buildDirectoryTree(item.contents.filter(content => content.type !== 'file'), key, currentPath);
|
|
928
|
+
}
|
|
929
|
+
acc.push(treeNode);
|
|
930
|
+
return acc;
|
|
931
|
+
}, []);
|
|
932
|
+
};
|
|
933
|
+
|
|
934
|
+
/**
|
|
935
|
+
* 查找树中指定key的节点
|
|
936
|
+
* @param {Array} treeData - 树数据
|
|
937
|
+
* @param {string} targetKey - 要查找的key
|
|
938
|
+
* @returns {Array} 包含匹配节点的数组
|
|
939
|
+
*/
|
|
940
|
+
const findTreeNode = (treeData, targetKey) => {
|
|
941
|
+
if (!Array.isArray(treeData) || typeof targetKey !== 'string') return [];
|
|
942
|
+
const result = [];
|
|
943
|
+
const stack = [...treeData];
|
|
944
|
+
while (stack.length) {
|
|
945
|
+
const node = stack.pop();
|
|
946
|
+
if (node.key === targetKey) {
|
|
947
|
+
result.push(node);
|
|
948
|
+
// 如果只需要第一个匹配项,可以在这里break
|
|
949
|
+
}
|
|
950
|
+
if (Array.isArray(node.children)) {
|
|
951
|
+
stack.push(...node.children);
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
return result;
|
|
955
|
+
};
|
|
956
|
+
|
|
957
|
+
/**
|
|
958
|
+
* 获取树中所有节点的keys
|
|
959
|
+
* @param {Array} treeData - 树数据
|
|
960
|
+
* @returns {Array} 包含所有节点keys的数组
|
|
961
|
+
*/
|
|
962
|
+
const getAllNodeKeys = treeData => {
|
|
963
|
+
if (!Array.isArray(treeData)) return [];
|
|
964
|
+
const keys = [];
|
|
965
|
+
const stack = [...treeData];
|
|
966
|
+
while (stack.length) {
|
|
967
|
+
const node = stack.pop();
|
|
968
|
+
if (node.key != null) {
|
|
969
|
+
keys.push(node.key);
|
|
970
|
+
}
|
|
971
|
+
if (Array.isArray(node.children)) {
|
|
972
|
+
stack.push(...node.children);
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
return keys;
|
|
976
|
+
};
|
|
977
|
+
|
|
978
|
+
const useDirectoryTree = _ref => {
|
|
979
|
+
let {
|
|
980
|
+
getFolderData,
|
|
981
|
+
createFolder,
|
|
982
|
+
removeFolderFile,
|
|
983
|
+
renameFolderFile,
|
|
984
|
+
height = 760,
|
|
985
|
+
theme = {
|
|
986
|
+
components: {
|
|
987
|
+
Tree: {
|
|
988
|
+
titleHeight: 30
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
} = _ref;
|
|
993
|
+
const [treeState, setTreeState] = react.useState({
|
|
994
|
+
data: [],
|
|
995
|
+
selectedKeys: [],
|
|
996
|
+
expandedKeys: [],
|
|
997
|
+
currentPath: "",
|
|
998
|
+
contents: [],
|
|
999
|
+
loading: false
|
|
1000
|
+
});
|
|
1001
|
+
const [originTreeData, setOriginTreeData] = react.useState([]);
|
|
1002
|
+
const updateTreeState = partialState => {
|
|
1003
|
+
setTreeState(prev => ({
|
|
1004
|
+
...prev,
|
|
1005
|
+
...partialState
|
|
1006
|
+
}));
|
|
1007
|
+
};
|
|
1008
|
+
|
|
1009
|
+
// 错误处理
|
|
1010
|
+
const handleError = (error, operation) => {
|
|
1011
|
+
console.error(`${operation} ERROR`, error);
|
|
1012
|
+
// 可以添加通知等统一错误处理
|
|
1013
|
+
};
|
|
1014
|
+
|
|
1015
|
+
// 路径处理工具
|
|
1016
|
+
const pathUtils = {
|
|
1017
|
+
replaceRoot: path => replaceRootPath(path),
|
|
1018
|
+
getNewPath: (node, newTitle) => {
|
|
1019
|
+
const arr = node.path.split('/');
|
|
1020
|
+
arr[arr.length - 1] = newTitle;
|
|
1021
|
+
return arr.join('/');
|
|
1022
|
+
},
|
|
1023
|
+
isSamePath: (path1, path2) => {
|
|
1024
|
+
return pathUtils.replaceRoot(path1) === pathUtils.replaceRoot(path2);
|
|
1025
|
+
}
|
|
1026
|
+
};
|
|
1027
|
+
|
|
1028
|
+
// 节点查找工具
|
|
1029
|
+
const nodeUtils = {
|
|
1030
|
+
findNode: (treeData, key) => {
|
|
1031
|
+
return findTreeNode(treeData, key);
|
|
1032
|
+
}
|
|
1033
|
+
};
|
|
1034
|
+
|
|
1035
|
+
// 获取文件夹数据 文件夹名称为空时返回根目录数据
|
|
1036
|
+
const fetchFolderData = react.useCallback(async function () {
|
|
1037
|
+
let initialization = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
|
1038
|
+
try {
|
|
1039
|
+
const data = await getFolderData({
|
|
1040
|
+
folder: ""
|
|
1041
|
+
});
|
|
1042
|
+
if (!data?.directoryTree) {
|
|
1043
|
+
return null;
|
|
1044
|
+
}
|
|
1045
|
+
setOriginTreeData(data.directoryTree);
|
|
1046
|
+
|
|
1047
|
+
// 构建根节点并生成树结构
|
|
1048
|
+
const rootNode = {
|
|
1049
|
+
name: 'root',
|
|
1050
|
+
type: 'directory',
|
|
1051
|
+
contents: data.directoryTree
|
|
1052
|
+
};
|
|
1053
|
+
// 递归生成treenodes
|
|
1054
|
+
const treeNodes = buildDirectoryTree([rootNode]);
|
|
1055
|
+
const rootChildren = treeNodes[0]?.children || [];
|
|
1056
|
+
if (!rootChildren.length) {
|
|
1057
|
+
return null;
|
|
1058
|
+
}
|
|
1059
|
+
const firstChild = rootChildren[0];
|
|
1060
|
+
const newState = {
|
|
1061
|
+
data: rootChildren,
|
|
1062
|
+
...(initialization && {
|
|
1063
|
+
selectedKeys: [firstChild?.key],
|
|
1064
|
+
expandedKeys: getAllNodeKeys(rootChildren),
|
|
1065
|
+
currentPath: firstChild?.path,
|
|
1066
|
+
contents: firstChild?.contents || []
|
|
1067
|
+
})
|
|
1068
|
+
};
|
|
1069
|
+
updateTreeState(newState);
|
|
1070
|
+
return rootChildren;
|
|
1071
|
+
} catch (error) {
|
|
1072
|
+
handleError(error, 'GET FOLDER DATA');
|
|
1073
|
+
}
|
|
1074
|
+
}, []);
|
|
1075
|
+
|
|
1076
|
+
// 初始化数据
|
|
1077
|
+
react.useEffect(() => {
|
|
1078
|
+
fetchFolderData(true);
|
|
1079
|
+
}, [fetchFolderData]);
|
|
1080
|
+
|
|
1081
|
+
// 创建文件夹
|
|
1082
|
+
const handleCreate = react.useCallback(async (node, newTitle) => {
|
|
1083
|
+
if (!newTitle?.trim()) return false;
|
|
1084
|
+
try {
|
|
1085
|
+
const path = pathUtils.replaceRoot(`${node.path}/${newTitle}`);
|
|
1086
|
+
await createFolder({
|
|
1087
|
+
path
|
|
1088
|
+
});
|
|
1089
|
+
const newTreeData = await fetchFolderData();
|
|
1090
|
+
|
|
1091
|
+
// 找到新增节点的父节点
|
|
1092
|
+
const parentNode = nodeUtils.findNode(newTreeData, node.key);
|
|
1093
|
+
if (parentNode?.[0]?.children) {
|
|
1094
|
+
// 通过 path 找到新增节点,得到新增节点的key
|
|
1095
|
+
const addedNode = parentNode[0].children.find(ch => pathUtils.isSamePath(ch.path, `root/${newTitle}`));
|
|
1096
|
+
if (addedNode) {
|
|
1097
|
+
updateTreeState({
|
|
1098
|
+
expandedKeys: [...treeState.expandedKeys, addedNode.key, parentNode[0].key]
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
} catch (error) {
|
|
1103
|
+
handleError(error, 'CREATE FOLDER');
|
|
1104
|
+
}
|
|
1105
|
+
}, [fetchFolderData, treeState.expandedKeys]);
|
|
1106
|
+
|
|
1107
|
+
// 删除文件/文件夹
|
|
1108
|
+
const handleRemove = react.useCallback(async node => {
|
|
1109
|
+
if (!node.path) return;
|
|
1110
|
+
try {
|
|
1111
|
+
await removeFolderFile({
|
|
1112
|
+
paths: [{
|
|
1113
|
+
path: pathUtils.replaceRoot(node.path)
|
|
1114
|
+
}]
|
|
1115
|
+
});
|
|
1116
|
+
// 如果删除的是当前选中节点,则重新初始化
|
|
1117
|
+
const shouldReinitialize = treeState.selectedKeys[0] === node.key;
|
|
1118
|
+
await fetchFolderData(shouldReinitialize);
|
|
1119
|
+
} catch (error) {
|
|
1120
|
+
handleError(error, 'REMOVE FOLDER/FILE');
|
|
1121
|
+
}
|
|
1122
|
+
}, [fetchFolderData, treeState.selectedKeys]);
|
|
1123
|
+
|
|
1124
|
+
// 修改文件/文件夹
|
|
1125
|
+
const handleRename = react.useCallback(async node => {
|
|
1126
|
+
const newPath = pathUtils.getNewPath(node, node.title);
|
|
1127
|
+
if (pathUtils.isSamePath(node.path, newPath)) return false;
|
|
1128
|
+
try {
|
|
1129
|
+
await renameFolderFile({
|
|
1130
|
+
old_path: pathUtils.replaceRoot(node.path),
|
|
1131
|
+
new_path: pathUtils.replaceRoot(newPath)
|
|
1132
|
+
});
|
|
1133
|
+
await fetchFolderData();
|
|
1134
|
+
} catch (error) {
|
|
1135
|
+
handleError(error, 'RENAME FOLDER/FILE');
|
|
1136
|
+
}
|
|
1137
|
+
}, [fetchFolderData]);
|
|
1138
|
+
|
|
1139
|
+
// 选择节点
|
|
1140
|
+
const onSelect = react.useCallback(async (keys, info) => {
|
|
1141
|
+
if (!keys.length || keys[0] === treeState.selectedKeys[0] && pathUtils.isSamePath(info.node.path, treeState.currentPath)) return;
|
|
1142
|
+
updateTreeState({
|
|
1143
|
+
selectedKeys: keys,
|
|
1144
|
+
currentPath: info.node.path,
|
|
1145
|
+
loading: true
|
|
1146
|
+
});
|
|
1147
|
+
try {
|
|
1148
|
+
// 模拟延迟加载
|
|
1149
|
+
// eslint-disable-next-line no-promise-executor-return
|
|
1150
|
+
await new Promise(resolve => setTimeout(resolve, 300));
|
|
1151
|
+
updateTreeState({
|
|
1152
|
+
contents: info.node.contents,
|
|
1153
|
+
loading: false
|
|
1154
|
+
});
|
|
1155
|
+
} catch (error) {
|
|
1156
|
+
handleError(error, 'SELECT NODE');
|
|
1157
|
+
updateTreeState({
|
|
1158
|
+
loading: false
|
|
1159
|
+
});
|
|
1160
|
+
}
|
|
1161
|
+
}, [treeState.selectedKeys, treeState.currentPath]);
|
|
1162
|
+
|
|
1163
|
+
// 展开节点
|
|
1164
|
+
const onExpand = react.useCallback(keys => {
|
|
1165
|
+
updateTreeState({
|
|
1166
|
+
expandedKeys: keys
|
|
1167
|
+
});
|
|
1168
|
+
}, []);
|
|
1169
|
+
|
|
1170
|
+
// 上传右侧文件或删除右侧文件 成功后的回调函数
|
|
1171
|
+
const updateFileContents = react.useCallback(async () => {
|
|
1172
|
+
// 找到当前选中的节点,更新当前节点的 contents
|
|
1173
|
+
const newTreeData = await fetchFolderData();
|
|
1174
|
+
const selectedNode = nodeUtils.findNode(newTreeData, treeState.selectedKeys[0]);
|
|
1175
|
+
if (selectedNode?.[0]) {
|
|
1176
|
+
updateTreeState({
|
|
1177
|
+
contents: selectedNode[0].contents
|
|
1178
|
+
});
|
|
1179
|
+
}
|
|
1180
|
+
}, [fetchFolderData, treeState.selectedKeys]);
|
|
1181
|
+
|
|
1182
|
+
// 删除文件
|
|
1183
|
+
const removeFile = react.useCallback(async url => {
|
|
1184
|
+
try {
|
|
1185
|
+
await removeFolderFile({
|
|
1186
|
+
path: url
|
|
1187
|
+
});
|
|
1188
|
+
await updateFileContents();
|
|
1189
|
+
} catch (error) {
|
|
1190
|
+
handleError(error, 'REMOVE FILE');
|
|
1191
|
+
}
|
|
1192
|
+
}, [updateFileContents]);
|
|
1193
|
+
const MemoizedTree = react.useMemo(() => {
|
|
1194
|
+
if (!treeState.data?.length) {
|
|
1195
|
+
return /*#__PURE__*/jsxRuntime.jsx(antd.Empty, {
|
|
1196
|
+
image: antd.Empty.PRESENTED_IMAGE_SIMPLE
|
|
1197
|
+
});
|
|
1198
|
+
}
|
|
1199
|
+
return /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
1200
|
+
style: {
|
|
1201
|
+
paddingTop: 16
|
|
1202
|
+
},
|
|
1203
|
+
children: /*#__PURE__*/jsxRuntime.jsx(antd.ConfigProvider, {
|
|
1204
|
+
theme: theme,
|
|
1205
|
+
children: /*#__PURE__*/jsxRuntime.jsx(antd.Tree, {
|
|
1206
|
+
blockNode: true,
|
|
1207
|
+
showIcon: true,
|
|
1208
|
+
selectedKeys: treeState.selectedKeys,
|
|
1209
|
+
expandedKeys: treeState.expandedKeys,
|
|
1210
|
+
onSelect: onSelect,
|
|
1211
|
+
onExpand: onExpand,
|
|
1212
|
+
treeData: treeState.data,
|
|
1213
|
+
titleRender: nodeData => /*#__PURE__*/jsxRuntime.jsx(TreeTitle$1, {
|
|
1214
|
+
title: nodeData.title,
|
|
1215
|
+
nodeData: nodeData,
|
|
1216
|
+
handleSave: handleRename,
|
|
1217
|
+
handleDel: handleRemove,
|
|
1218
|
+
handleAdd: handleCreate
|
|
1219
|
+
}),
|
|
1220
|
+
height: height
|
|
1221
|
+
})
|
|
1222
|
+
})
|
|
1223
|
+
}, "folder-directory");
|
|
1224
|
+
}, [treeState.data, treeState.selectedKeys, treeState.expandedKeys]);
|
|
1225
|
+
return {
|
|
1226
|
+
directoryTree: MemoizedTree,
|
|
1227
|
+
contents,
|
|
1228
|
+
currentPath,
|
|
1229
|
+
updateFileContents,
|
|
1230
|
+
removeFile,
|
|
1231
|
+
loading,
|
|
1232
|
+
originTreeData
|
|
1233
|
+
};
|
|
1234
|
+
};
|
|
1235
|
+
|
|
671
1236
|
const UpgradeManager = _ref => {
|
|
672
1237
|
let {
|
|
673
1238
|
menuItems = [],
|
|
@@ -2618,6 +3183,7 @@ exports.PtpModal = PtpModal$1;
|
|
|
2618
3183
|
exports.SystemOperations = SystemOperations;
|
|
2619
3184
|
exports.UpgradeManager = UpgradeManager;
|
|
2620
3185
|
exports.useAuth = useAuth;
|
|
3186
|
+
exports.useDirectoryTree = useDirectoryTree;
|
|
2621
3187
|
exports.useHardwareUsage = useHardwareUsage;
|
|
2622
3188
|
exports.useHardwareWebSocket = useHardwareWebSocket;
|
|
2623
3189
|
exports.useSystemOperations = useSystemOperations;
|