Commit 23b809bd authored by chenshouchao's avatar chenshouchao

feat: 文件删除 文件移动 批量移动联调完成

parent 71dfbc2b
...@@ -39,16 +39,15 @@ class CloudEController { ...@@ -39,16 +39,15 @@ class CloudEController {
if (getLoaclStorageOfKey("userinfo")) { if (getLoaclStorageOfKey("userinfo")) {
url += urlToken(filetoken, projectId); url += urlToken(filetoken, projectId);
} }
axios return axios.get(APIOPTION() + "/delete/" + url, {
.get(APIOPTION() + "/delete/" + url, { headers: headers,
headers: headers, });
}) // .then(function (response) {
.then(function (response) { // console.log(response);
console.log(response); // })
}) // .catch(function (error) {
.catch(function (error) { // console.log(error);
console.log(error); // });
});
} }
} }
// 文件列表 // 文件列表
...@@ -71,43 +70,30 @@ class CloudEController { ...@@ -71,43 +70,30 @@ class CloudEController {
headers: headers, headers: headers,
} }
); );
// axios
// // 查看文件的接口为list(可查看隐藏文件)
// .get(APIOPTION() + "/list" + url + "&showhidden=" + showHide, {
// headers: headers,
// })
// .then(function (response) {
// console.log(response);
// })
// .catch(function (error) {
// console.log(error);
// });
} }
} }
// 文件移动 // 文件树
static JobOutFileListMove(url: any, filetoken: string, projectId: string) { static JobOutFileDirtree(
url: any,
filetoken: string,
projectId: string,
showHide = false,
items?: any
) {
if (ApiUtils.getAuthorizationHeaders(headers)) { if (ApiUtils.getAuthorizationHeaders(headers)) {
headers["Cache-Control"] = "no-cache"; headers["Cache-Control"] = "no-cache";
if (getLoaclStorageOfKey("userinfo")) { if (getLoaclStorageOfKey("userinfo")) {
url += urlToken(filetoken, projectId); url += urlToken(filetoken, projectId);
} }
return axios.get(APIOPTION() + "/download" + url, { return axios.get(
headers: headers, APIOPTION() + "/dirtree" + url + "&showhidden=" + showHide,
}); {
headers: headers,
// axios }
// .get(APIOPTION() + "/download" + url, { );
// headers: headers,
// })
// .then(function (response) {
// console.log(response);
// })
// .catch(function (error) {
// console.log(error);
// });
} }
} }
// // 全局搜索 文件名 // 全局搜索 文件名
static JobSearchFileList( static JobSearchFileList(
url: any, url: any,
base: any, base: any,
...@@ -133,6 +119,18 @@ class CloudEController { ...@@ -133,6 +119,18 @@ class CloudEController {
} }
} }
// 文件移动
// static JobOutFileListMove(url: any, filetoken: string, projectId: string) {
// if (ApiUtils.getAuthorizationHeaders(headers)) {
// headers["Cache-Control"] = "no-cache";
// if (getLoaclStorageOfKey("userinfo")) {
// url += urlToken(filetoken, projectId);
// }
// return axios.get(APIOPTION() + "/download" + url, {
// headers: headers,
// });
// }
// }
// 文件移动 // 文件移动
static JobFileMove( static JobFileMove(
url: any, url: any,
...@@ -147,16 +145,35 @@ class CloudEController { ...@@ -147,16 +145,35 @@ class CloudEController {
headers["originalfilepath"] = encodeURIComponent(original_filepath); headers["originalfilepath"] = encodeURIComponent(original_filepath);
let param = new FormData(); let param = new FormData();
param.append("", value); param.append("", value);
axios return axios.post(APIOPTION() + "/rename" + url, param, {
.post(APIOPTION() + "/rename" + url, param, { headers: headers,
headers: headers, });
}) }
.then((response) => { }
console.log(response);
}) // 文件批量移动
.catch((error) => { static JobFileBatchMove(
console.log(error); url: any,
}); original_filepath: Array<string>,
value: any,
filetoken: string,
projectId: string
) {
if (ApiUtils.getAuthorizationHeaders(headers)) {
url = url + urlToken(filetoken, projectId) + "&batch=true";
headers["Content-Type"] = "multipart/form-data";
// Base64.stringify(Utf8.parse(urls))
// headers["originalfilepath"] = encodeURIComponent(
// original_filepath.join(" ")
// );
headers["originalfilepath"] = Base64.stringify(
Utf8.parse(original_filepath.join(" "))
);
let param = new FormData();
param.append("", value);
return axios.post(APIOPTION() + "/rename" + url, param, {
headers: headers,
});
} }
} }
} }
......
...@@ -3,45 +3,72 @@ import ArrowRightIcon from "@mui/icons-material/ArrowRight"; ...@@ -3,45 +3,72 @@ import ArrowRightIcon from "@mui/icons-material/ArrowRight";
import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown"; import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown";
import TreeItem from "@mui/lab/TreeItem"; import TreeItem from "@mui/lab/TreeItem";
interface TreeItemType {
id: string;
name: string;
subdirs?: readonly TreeItemType[];
}
type MyTreeViewProps = { type MyTreeViewProps = {
treeData: RenderTree; // treeData: RenderTree;
treeData: Array<TreeItemType>;
onNodeFocus?: (event: object, value: string) => void; // 点击某一项的回调 onNodeFocus?: (event: object, value: string) => void; // 点击某一项的回调
onNodeSelect?: (event: object, value: Array<any> | string) => void; // 点击某一项的回调 onNodeSelect?: (event: object, value: Array<any> | string) => void; // 点击某一项的回调
onNodeToggle?: (event: object, nodeIds: Array<any>) => void; // 点击某一项的回调 onNodeToggle?: (event: object, nodeIds: Array<any>) => void; // 点击某一项的回调
renderLabel?: (labelNmae: string) => React.ReactNode; renderLabel?: (labelNmae: string) => React.ReactNode;
treeViewSx?: any; treeViewSx?: any;
defaultExpanded?: Array<string>; defaultExpanded?: Array<string>;
idKey?: string;
idFunc?: (node: any) => string;
}; };
interface RenderTree { interface RenderTree {
id: string | number; id: string | number;
name: string; name: string;
children?: readonly RenderTree[]; subdirs?: readonly RenderTree[];
} }
const MyTreeView = (props: MyTreeViewProps) => { const MyTreeView = (props: MyTreeViewProps) => {
const { const {
treeData, treeData = [],
renderLabel, renderLabel,
treeViewSx, treeViewSx,
onNodeFocus, onNodeFocus,
onNodeSelect, onNodeSelect,
onNodeToggle, onNodeToggle,
defaultExpanded, defaultExpanded,
idKey,
idFunc,
} = props; } = props;
const renderTree = (nodes: RenderTree) => ( const renderTreeObj = (nodes: RenderTree, index: number) => (
<TreeItem <TreeItem
key={nodes.id} key={nodes.id || `${nodes.name}${index}`}
nodeId={String(nodes.id)} nodeId={String(
idFunc ? idFunc(nodes) : nodes.id || `${nodes.name}${index}`
)}
label={renderLabel === undefined ? nodes.name : renderLabel(nodes.name)} label={renderLabel === undefined ? nodes.name : renderLabel(nodes.name)}
> >
{Array.isArray(nodes.children) {Array.isArray(nodes.subdirs)
? nodes.children.map((node) => renderTree(node)) ? nodes.subdirs.map((node, i) => renderTreeObj(node, i))
: null} : null}
</TreeItem> </TreeItem>
); );
// const renderTreeArray = (node: TreeItemType, index: number) => {
// return (
// <TreeItem
// key={node.id || `${node.name}${index}`}
// nodeId={String(node.id)}
// label={renderLabel === undefined ? node.name : renderLabel(node.name)}
// >
// {Array.isArray(node.subdirs)
// ? node.subdirs.map((nodeLi: any, i) => renderTreeArray(nodeLi, i))
// : null}
// </TreeItem>
// );
// };
return ( return (
<TreeView <TreeView
defaultCollapseIcon={<ArrowRightIcon />} defaultCollapseIcon={<ArrowRightIcon />}
...@@ -52,7 +79,14 @@ const MyTreeView = (props: MyTreeViewProps) => { ...@@ -52,7 +79,14 @@ const MyTreeView = (props: MyTreeViewProps) => {
defaultExpanded={defaultExpanded} defaultExpanded={defaultExpanded}
sx={{ ...treeViewSx }} sx={{ ...treeViewSx }}
> >
{renderTree(treeData)} {treeData.length === 0 ? (
<div>暂无数据</div>
) : (
treeData.map((treeItem, index) => {
// return renderTreeArray(treeItem, index);
return renderTreeObj(treeItem, index);
})
)}
</TreeView> </TreeView>
); );
}; };
......
...@@ -49,11 +49,6 @@ const AddFolder = (props: any) => { ...@@ -49,11 +49,6 @@ const AddFolder = (props: any) => {
const handleFileNameChange = (e: any) => { const handleFileNameChange = (e: any) => {
const fileName = e.target.value; const fileName = e.target.value;
setFileName(fileName); setFileName(fileName);
// 1.“格式不正确,必须在30字符以内,仅限大小写字母、数字、中文”
// 2. “文件夹名称不能为空”
// 3. “已存在同名文件夹”
if (!fileName) { if (!fileName) {
setFileNameCheck({ setFileNameCheck({
error: true, error: true,
......
.rootTitle {
border-radius: 4px 4px 0 0;
background-color: rgba(25, 118, 210, 0.08);
/* background-color: rgba(25, 118, 210, 0.5); */
line-height: 44px;
color: rgba(30, 38, 51, 1);
font-size: 14px;
font-weight: 600;
display: flex;
justify-content: flex-start;
align-items: center;
}
.bigFolderIcon {
margin: 0 9px;
}
.treeLabel { .treeLabel {
display: flex; display: flex;
justify-content: flex-start; justify-content: flex-start;
......
import React, { useState, useImperativeHandle } from "react"; import React, {
useState,
useImperativeHandle,
useEffect,
useCallback,
} from "react";
import style from "./index.module.css"; import style from "./index.module.css";
import { TextField } from "@mui/material"; import { TextField } from "@mui/material";
import MyDialog from "@/components/mui/MyDialog"; import MyDialog from "@/components/mui/MyDialog";
import { checkIsNumberLetterChinese } from "@/utils/util"; import { checkIsNumberLetterChinese } from "@/utils/util";
import folderIcon from "@/assets/project/folderIcon.svg"; import folderIcon from "@/assets/project/folderIcon.svg";
import bigFolderIcon from "@/assets/project/bigFolderIcon.svg";
import { useMessage } from "@/components/MySnackbar"; import { useMessage } from "@/components/MySnackbar";
import MyTreeView from "@/components/mui/MyTreeView"; import MyTreeView from "@/components/mui/MyTreeView";
import CloudEController from "@/api/fileserver/CloudEController";
const MoveFile = (props: any) => { const MoveFile = (props: any) => {
const { list } = props; const { path, projectId, fileToken, currentOperateFile, selectIds } = props;
const Message = useMessage(); const Message = useMessage();
let addFolderDialogRef: any = React.createRef(); const [newPath, setNewPath] = useState("");
const [treeData, setTreeData] = useState<any>([]);
const getTree = useCallback(() => {
if (fileToken && projectId) {
return CloudEController.JobOutFileDirtree(
"/",
fileToken,
projectId,
false
)?.then((res) => {
console.log("tree");
console.log(res);
if (Array.isArray(res.data)) {
setTreeData(res.data);
} else {
setTreeData([]);
}
// setTableLoadding(false);
// if (Array.isArray(res.data)) {
// setList(res.data);
// } else {
// setList([]);
// }
});
}
}, [fileToken, projectId]);
// useEffect(() => {
// getTree();
// }, [getTree]);
let moveFileDialogRef: any = React.createRef();
const showDialog = () => { const showDialog = () => {
addFolderDialogRef.current.handleClickOpen(); moveFileDialogRef.current.handleClickOpen();
getTree();
}; };
useImperativeHandle(props.onRef, () => { useImperativeHandle(props.onRef, () => {
...@@ -24,7 +65,46 @@ const MoveFile = (props: any) => { ...@@ -24,7 +65,46 @@ const MoveFile = (props: any) => {
}); });
const handleMoveFileSubmit = () => { const handleMoveFileSubmit = () => {
console.log("submit"); if (newPath) {
if (!currentOperateFile) {
// 批量移动
const oldPaths = selectIds.map((name: any) => {
return `${path}${path === "/" ? "" : "/"}${name}`;
});
CloudEController.JobFileBatchMove(
newPath,
oldPaths,
"",
fileToken,
projectId
)?.then((res) => {
console.log("批量移动");
console.log(res);
});
} else {
const oldPath = `${path}${path === "/" ? "" : "/"}${
currentOperateFile.name
}`;
console.log("submit");
console.log(newPath);
console.log(oldPath);
if (oldPath === newPath) {
Message.info("当前目录和目标目录一致,请重新选择目标目录");
return;
}
CloudEController.JobFileMove(
newPath,
oldPath,
"",
fileToken,
projectId
)?.then((res) => {
console.log(res);
});
}
} else {
Message.error("请选择移动到哪个目录");
}
}; };
const renderLabel = (labelNmae: string) => { const renderLabel = (labelNmae: string) => {
...@@ -36,58 +116,35 @@ const MoveFile = (props: any) => { ...@@ -36,58 +116,35 @@ const MoveFile = (props: any) => {
); );
}; };
const treeData = {
id: 1232,
name: "na567me",
children: [
{
id: 1232358,
name: "nam89e4123",
},
{
id: 1232395,
name: "nam89e32123",
},
{
id: 1232035,
name: "n2am89e123",
},
],
};
const onNodeFocus = (a: any, b: any) => {
console.log("onNodeFocus", a, b);
};
const onNodeSelect = (a: any, b: any) => { const onNodeSelect = (a: any, b: any) => {
console.log("onNodeSelect", a, b); console.log("onNodeSelect", a, b);
}; setNewPath(b);
const onNodeToggle = (a: any, b: any) => {
console.log("onNodeToggle", a, b);
}; };
const moveFileSubmitloading = false; const moveFileSubmitloading = false;
const [fileName, setFileName] = useState("");
const [fileNameCheck, setFileNameCheck] = useState({
error: false,
help: "",
});
const idFunc = (item: any) => {
return `${item.dir.substr(1)}${item.name}`;
};
return ( return (
<MyDialog <MyDialog
handleSubmit={handleMoveFileSubmit} handleSubmit={handleMoveFileSubmit}
onRef={addFolderDialogRef} onRef={moveFileDialogRef}
title="移动至" title="移动至"
submitloading={moveFileSubmitloading} submitloading={moveFileSubmitloading}
> >
<div className={style.rootTitle}>
<img className={style.bigFolderIcon} src={bigFolderIcon} alt="" />
ProjectData
</div>
<MyTreeView <MyTreeView
treeData={treeData} treeData={treeData}
renderLabel={renderLabel} renderLabel={renderLabel}
onNodeFocus={onNodeFocus}
onNodeSelect={onNodeSelect} onNodeSelect={onNodeSelect}
onNodeToggle={onNodeToggle} idFunc={idFunc}
defaultExpanded={[String(treeData.id)]}
treeViewSx={{ treeViewSx={{
width: 400, width: 400,
overflow: "hidden",
}} }}
></MyTreeView> ></MyTreeView>
</MyDialog> </MyDialog>
......
...@@ -3,6 +3,7 @@ import React, { useState, useCallback, useEffect, useMemo } from "react"; ...@@ -3,6 +3,7 @@ import React, { useState, useCallback, useEffect, useMemo } from "react";
import style from "./index.module.css"; import style from "./index.module.css";
import classnames from "classnames"; import classnames from "classnames";
import { Button, InputBase, IconButton, TextField } from "@mui/material"; import { Button, InputBase, IconButton, TextField } from "@mui/material";
import LoadingButton from "@mui/lab/LoadingButton";
import { createTheme, ThemeProvider } from "@mui/material/styles"; import { createTheme, ThemeProvider } from "@mui/material/styles";
import SearchIcon from "@mui/icons-material/Search"; import SearchIcon from "@mui/icons-material/Search";
import RefreshIcon from "@mui/icons-material/Refresh"; import RefreshIcon from "@mui/icons-material/Refresh";
...@@ -23,6 +24,12 @@ import { observer } from "mobx-react-lite"; ...@@ -23,6 +24,12 @@ import { observer } from "mobx-react-lite";
import { useStores } from "@/store"; import { useStores } from "@/store";
import CloudEController from "@/api/fileserver/CloudEController"; import CloudEController from "@/api/fileserver/CloudEController";
import { toJS } from "mobx"; import { toJS } from "mobx";
import moment from "moment";
import Dialog from "@mui/material/Dialog";
import DialogActions from "@mui/material/DialogActions";
import DialogContent from "@mui/material/DialogContent";
import DialogContentText from "@mui/material/DialogContentText";
import DialogTitle from "@mui/material/DialogTitle";
// import TreeView from '@mui/lab/TreeView'; // import TreeView from '@mui/lab/TreeView';
// import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; // import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
// import ChevronRightIcon from '@mui/icons-material/ChevronRight'; // import ChevronRightIcon from '@mui/icons-material/ChevronRight';
...@@ -58,6 +65,10 @@ declare module "@mui/material/Button" { ...@@ -58,6 +65,10 @@ declare module "@mui/material/Button" {
const ProjectData = observer(() => { const ProjectData = observer(() => {
const { currentProjectStore } = useStores(); const { currentProjectStore } = useStores();
const [tableLoadding, setTableLoadding] = useState(false);
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
const [currentOperateFile, setCurrentOperateFile] = useState<any>(null);
const [deleteloading, setDeleteloading] = useState(false);
// const [path, setPath] = useState("/ProjectData"); // const [path, setPath] = useState("/ProjectData");
const [path, setPath] = useState("/"); const [path, setPath] = useState("/");
const showPath = useMemo(() => { const showPath = useMemo(() => {
...@@ -95,6 +106,7 @@ const ProjectData = observer(() => { ...@@ -95,6 +106,7 @@ const ProjectData = observer(() => {
// }, [fileToken, path, projectId]); // }, [fileToken, path, projectId]);
const getList = useCallback(() => { const getList = useCallback(() => {
if (fileToken && projectId) { if (fileToken && projectId) {
setTableLoadding(true);
return CloudEController.JobOutFileList( return CloudEController.JobOutFileList(
path, path,
fileToken, fileToken,
...@@ -102,6 +114,7 @@ const ProjectData = observer(() => { ...@@ -102,6 +114,7 @@ const ProjectData = observer(() => {
false false
)?.then((res) => { )?.then((res) => {
console.log(res); console.log(res);
setTableLoadding(false);
if (Array.isArray(res.data)) { if (Array.isArray(res.data)) {
setList(res.data); setList(res.data);
} else { } else {
...@@ -149,7 +162,10 @@ const ProjectData = observer(() => { ...@@ -149,7 +162,10 @@ const ProjectData = observer(() => {
setPath(`${path}${item.name}`); setPath(`${path}${item.name}`);
}; };
const hanleDeleteFile = (item: any) => {}; const hanleDeleteFile = (item: any) => {
setCurrentOperateFile(item);
setDeleteDialogOpen(true);
};
const renderName = (item: any) => { const renderName = (item: any) => {
if (item.type === "directory") { if (item.type === "directory") {
...@@ -177,7 +193,10 @@ const ProjectData = observer(() => { ...@@ -177,7 +193,10 @@ const ProjectData = observer(() => {
}; };
const renderMtime = (item: any) => { const renderMtime = (item: any) => {
return <span>{item.mtime}</span>; return (
// <span>{moment(new Date(item.mtime)).format("YYYY-MM-DD hh:mm:ss")}</span>
<span>{moment(item.mtime).format("YYYY-MM-DD hh:mm:ss")}</span>
);
}; };
const renderButtons = (item: any) => { const renderButtons = (item: any) => {
...@@ -194,7 +213,7 @@ const ProjectData = observer(() => { ...@@ -194,7 +213,7 @@ const ProjectData = observer(() => {
sx={{ position: "relative", left: "-18px" }} sx={{ position: "relative", left: "-18px" }}
variant="text" variant="text"
size="small" size="small"
onClick={hanleShowMoveFileDialog} onClick={() => hanleShowMoveFileDialog(item)}
> >
移动至 移动至
</Button> </Button>
...@@ -224,7 +243,36 @@ const ProjectData = observer(() => { ...@@ -224,7 +243,36 @@ const ProjectData = observer(() => {
let moveFileRef: any = React.createRef(); let moveFileRef: any = React.createRef();
const hanleShowMoveFileDialog = () => { const hanleShowMoveFileDialog = (item: any) => {
console.log(item);
setCurrentOperateFile(item);
moveFileRef.current.showDialog();
};
const handleDeleteDialogClose = () => {
setDeleteDialogOpen(false);
};
const handleDelete = () => {
const deletePath =
path === "/"
? `${path}${currentOperateFile.name}`
: `${path}/${currentOperateFile.name}`;
CloudEController.JobOutFileDel(
deletePath,
fileToken,
projectId as string
)?.then((res) => {
console.log("handleDelete");
console.log(res);
setDeleteloading(false);
setDeleteDialogOpen(false);
handleRefresh();
});
};
const handleBatchMove = () => {
setCurrentOperateFile(null);
moveFileRef.current.showDialog(); moveFileRef.current.showDialog();
}; };
...@@ -314,23 +362,25 @@ const ProjectData = observer(() => { ...@@ -314,23 +362,25 @@ const ProjectData = observer(() => {
checkboxData={(e: any) => { checkboxData={(e: any) => {
hanldeCheckbox(e); hanldeCheckbox(e);
}} }}
// param="name"
rowHover={true} rowHover={true}
stickyheader={true} stickyheader={true}
rows={list.map((item: any) => ({ rows={list.map((item: any) => ({
...item, ...item,
id: item.name,
name: renderName(item), name: renderName(item),
size: renderSize(item), size: renderSize(item),
mtime: renderMtime(item), mtime: renderMtime(item),
caozuo: renderButtons(item), caozuo: renderButtons(item),
}))} }))}
// load={loadding} load={tableLoadding}
rowsPerPage={"99"} // rowsPerPage={"99"}
headCells={versionsHeadCells} headCells={versionsHeadCells}
nopadding={true} nopadding={true}
footer={false} footer={false}
></Table> ></Table>
</div> </div>
{selectIds.length > 0 && ( {selectIds.length > 1 && (
<div className={style.projectDataStickyBox}> <div className={style.projectDataStickyBox}>
<Button <Button
color="error" color="error"
...@@ -345,11 +395,51 @@ const ProjectData = observer(() => { ...@@ -345,11 +395,51 @@ const ProjectData = observer(() => {
variant="contained" variant="contained"
size="small" size="small"
style={{ marginRight: "24px" }} style={{ marginRight: "24px" }}
onClick={handleBatchMove}
> >
批量移动({selectIds.length} 批量移动({selectIds.length}
</Button> </Button>
</div> </div>
)} )}
<Dialog
open={deleteDialogOpen}
onClose={handleDeleteDialogClose}
aria-labelledby="提示"
aria-describedby="确认要删除吗"
>
<DialogTitle id="alert-dialog-title">{"提示"}</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
确认要删除“{currentOperateFile ? currentOperateFile.name : ""}
”吗?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
onClick={handleDeleteDialogClose}
color="inherit"
variant="contained"
style={{ color: "#1E2633", backgroundColor: "#fff" }}
size="small"
>
取消
</Button>
<LoadingButton
loading={deleteloading}
onClick={handleDelete}
color="primary"
variant="contained"
// style={submitStyle}
size="small"
>
确认
</LoadingButton>
{/* <Button onClick={handleDeleteDialogClose}>取消</Button>
<Button onClick={handleDelete} autoFocus>
确认
</Button> */}
</DialogActions>
</Dialog>
<UpLoaderFile <UpLoaderFile
onRef={UpLoaderFileRef} onRef={UpLoaderFileRef}
path={path} path={path}
...@@ -362,7 +452,14 @@ const ProjectData = observer(() => { ...@@ -362,7 +452,14 @@ const ProjectData = observer(() => {
fileToken={fileToken} fileToken={fileToken}
projectId={projectId} projectId={projectId}
></AddFolder> ></AddFolder>
<MoveFile onRef={moveFileRef} list={list}></MoveFile> <MoveFile
onRef={moveFileRef}
path={path}
fileToken={fileToken}
projectId={projectId}
currentOperateFile={currentOperateFile}
selectIds={selectIds}
></MoveFile>
</div> </div>
</ThemeProvider> </ThemeProvider>
); );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment