Commit 23b809bd authored by chenshouchao's avatar chenshouchao

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

parent 71dfbc2b
......@@ -39,16 +39,15 @@ class CloudEController {
if (getLoaclStorageOfKey("userinfo")) {
url += urlToken(filetoken, projectId);
}
axios
.get(APIOPTION() + "/delete/" + url, {
headers: headers,
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
return axios.get(APIOPTION() + "/delete/" + url, {
headers: headers,
});
// .then(function (response) {
// console.log(response);
// })
// .catch(function (error) {
// console.log(error);
// });
}
}
// 文件列表
......@@ -71,43 +70,30 @@ class CloudEController {
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)) {
headers["Cache-Control"] = "no-cache";
if (getLoaclStorageOfKey("userinfo")) {
url += urlToken(filetoken, projectId);
}
return axios.get(APIOPTION() + "/download" + url, {
headers: headers,
});
// axios
// .get(APIOPTION() + "/download" + url, {
// headers: headers,
// })
// .then(function (response) {
// console.log(response);
// })
// .catch(function (error) {
// console.log(error);
// });
return axios.get(
APIOPTION() + "/dirtree" + url + "&showhidden=" + showHide,
{
headers: headers,
}
);
}
}
// // 全局搜索 文件名
// 全局搜索 文件名
static JobSearchFileList(
url: any,
base: any,
......@@ -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(
url: any,
......@@ -147,16 +145,35 @@ class CloudEController {
headers["originalfilepath"] = encodeURIComponent(original_filepath);
let param = new FormData();
param.append("", value);
axios
.post(APIOPTION() + "/rename" + url, param, {
headers: headers,
})
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
});
return axios.post(APIOPTION() + "/rename" + url, param, {
headers: headers,
});
}
}
// 文件批量移动
static JobFileBatchMove(
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";
import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown";
import TreeItem from "@mui/lab/TreeItem";
interface TreeItemType {
id: string;
name: string;
subdirs?: readonly TreeItemType[];
}
type MyTreeViewProps = {
treeData: RenderTree;
// treeData: RenderTree;
treeData: Array<TreeItemType>;
onNodeFocus?: (event: object, value: string) => void; // 点击某一项的回调
onNodeSelect?: (event: object, value: Array<any> | string) => void; // 点击某一项的回调
onNodeToggle?: (event: object, nodeIds: Array<any>) => void; // 点击某一项的回调
renderLabel?: (labelNmae: string) => React.ReactNode;
treeViewSx?: any;
defaultExpanded?: Array<string>;
idKey?: string;
idFunc?: (node: any) => string;
};
interface RenderTree {
id: string | number;
name: string;
children?: readonly RenderTree[];
subdirs?: readonly RenderTree[];
}
const MyTreeView = (props: MyTreeViewProps) => {
const {
treeData,
treeData = [],
renderLabel,
treeViewSx,
onNodeFocus,
onNodeSelect,
onNodeToggle,
defaultExpanded,
idKey,
idFunc,
} = props;
const renderTree = (nodes: RenderTree) => (
const renderTreeObj = (nodes: RenderTree, index: number) => (
<TreeItem
key={nodes.id}
nodeId={String(nodes.id)}
key={nodes.id || `${nodes.name}${index}`}
nodeId={String(
idFunc ? idFunc(nodes) : nodes.id || `${nodes.name}${index}`
)}
label={renderLabel === undefined ? nodes.name : renderLabel(nodes.name)}
>
{Array.isArray(nodes.children)
? nodes.children.map((node) => renderTree(node))
{Array.isArray(nodes.subdirs)
? nodes.subdirs.map((node, i) => renderTreeObj(node, i))
: null}
</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 (
<TreeView
defaultCollapseIcon={<ArrowRightIcon />}
......@@ -52,7 +79,14 @@ const MyTreeView = (props: MyTreeViewProps) => {
defaultExpanded={defaultExpanded}
sx={{ ...treeViewSx }}
>
{renderTree(treeData)}
{treeData.length === 0 ? (
<div>暂无数据</div>
) : (
treeData.map((treeItem, index) => {
// return renderTreeArray(treeItem, index);
return renderTreeObj(treeItem, index);
})
)}
</TreeView>
);
};
......
......@@ -49,11 +49,6 @@ const AddFolder = (props: any) => {
const handleFileNameChange = (e: any) => {
const fileName = e.target.value;
setFileName(fileName);
// 1.“格式不正确,必须在30字符以内,仅限大小写字母、数字、中文”
// 2. “文件夹名称不能为空”
// 3. “已存在同名文件夹”
if (!fileName) {
setFileNameCheck({
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 {
display: flex;
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 { TextField } from "@mui/material";
import MyDialog from "@/components/mui/MyDialog";
import { checkIsNumberLetterChinese } from "@/utils/util";
import folderIcon from "@/assets/project/folderIcon.svg";
import bigFolderIcon from "@/assets/project/bigFolderIcon.svg";
import { useMessage } from "@/components/MySnackbar";
import MyTreeView from "@/components/mui/MyTreeView";
import CloudEController from "@/api/fileserver/CloudEController";
const MoveFile = (props: any) => {
const { list } = props;
const { path, projectId, fileToken, currentOperateFile, selectIds } = props;
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 = () => {
addFolderDialogRef.current.handleClickOpen();
moveFileDialogRef.current.handleClickOpen();
getTree();
};
useImperativeHandle(props.onRef, () => {
......@@ -24,7 +65,46 @@ const MoveFile = (props: any) => {
});
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) => {
......@@ -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) => {
console.log("onNodeSelect", a, b);
};
const onNodeToggle = (a: any, b: any) => {
console.log("onNodeToggle", a, b);
setNewPath(b);
};
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 (
<MyDialog
handleSubmit={handleMoveFileSubmit}
onRef={addFolderDialogRef}
onRef={moveFileDialogRef}
title="移动至"
submitloading={moveFileSubmitloading}
>
<div className={style.rootTitle}>
<img className={style.bigFolderIcon} src={bigFolderIcon} alt="" />
ProjectData
</div>
<MyTreeView
treeData={treeData}
renderLabel={renderLabel}
onNodeFocus={onNodeFocus}
onNodeSelect={onNodeSelect}
onNodeToggle={onNodeToggle}
defaultExpanded={[String(treeData.id)]}
idFunc={idFunc}
treeViewSx={{
width: 400,
overflow: "hidden",
}}
></MyTreeView>
</MyDialog>
......
......@@ -3,6 +3,7 @@ import React, { useState, useCallback, useEffect, useMemo } from "react";
import style from "./index.module.css";
import classnames from "classnames";
import { Button, InputBase, IconButton, TextField } from "@mui/material";
import LoadingButton from "@mui/lab/LoadingButton";
import { createTheme, ThemeProvider } from "@mui/material/styles";
import SearchIcon from "@mui/icons-material/Search";
import RefreshIcon from "@mui/icons-material/Refresh";
......@@ -23,6 +24,12 @@ import { observer } from "mobx-react-lite";
import { useStores } from "@/store";
import CloudEController from "@/api/fileserver/CloudEController";
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 ExpandMoreIcon from '@mui/icons-material/ExpandMore';
// import ChevronRightIcon from '@mui/icons-material/ChevronRight';
......@@ -58,6 +65,10 @@ declare module "@mui/material/Button" {
const ProjectData = observer(() => {
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("/");
const showPath = useMemo(() => {
......@@ -95,6 +106,7 @@ const ProjectData = observer(() => {
// }, [fileToken, path, projectId]);
const getList = useCallback(() => {
if (fileToken && projectId) {
setTableLoadding(true);
return CloudEController.JobOutFileList(
path,
fileToken,
......@@ -102,6 +114,7 @@ const ProjectData = observer(() => {
false
)?.then((res) => {
console.log(res);
setTableLoadding(false);
if (Array.isArray(res.data)) {
setList(res.data);
} else {
......@@ -149,7 +162,10 @@ const ProjectData = observer(() => {
setPath(`${path}${item.name}`);
};
const hanleDeleteFile = (item: any) => {};
const hanleDeleteFile = (item: any) => {
setCurrentOperateFile(item);
setDeleteDialogOpen(true);
};
const renderName = (item: any) => {
if (item.type === "directory") {
......@@ -177,7 +193,10 @@ const ProjectData = observer(() => {
};
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) => {
......@@ -194,7 +213,7 @@ const ProjectData = observer(() => {
sx={{ position: "relative", left: "-18px" }}
variant="text"
size="small"
onClick={hanleShowMoveFileDialog}
onClick={() => hanleShowMoveFileDialog(item)}
>
移动至
</Button>
......@@ -224,7 +243,36 @@ const ProjectData = observer(() => {
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();
};
......@@ -314,23 +362,25 @@ const ProjectData = observer(() => {
checkboxData={(e: any) => {
hanldeCheckbox(e);
}}
// param="name"
rowHover={true}
stickyheader={true}
rows={list.map((item: any) => ({
...item,
id: item.name,
name: renderName(item),
size: renderSize(item),
mtime: renderMtime(item),
caozuo: renderButtons(item),
}))}
// load={loadding}
rowsPerPage={"99"}
load={tableLoadding}
// rowsPerPage={"99"}
headCells={versionsHeadCells}
nopadding={true}
footer={false}
></Table>
</div>
{selectIds.length > 0 && (
{selectIds.length > 1 && (
<div className={style.projectDataStickyBox}>
<Button
color="error"
......@@ -345,11 +395,51 @@ const ProjectData = observer(() => {
variant="contained"
size="small"
style={{ marginRight: "24px" }}
onClick={handleBatchMove}
>
批量移动({selectIds.length}
</Button>
</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
onRef={UpLoaderFileRef}
path={path}
......@@ -362,7 +452,14 @@ const ProjectData = observer(() => {
fileToken={fileToken}
projectId={projectId}
></AddFolder>
<MoveFile onRef={moveFileRef} list={list}></MoveFile>
<MoveFile
onRef={moveFileRef}
path={path}
fileToken={fileToken}
projectId={projectId}
currentOperateFile={currentOperateFile}
selectIds={selectIds}
></MoveFile>
</div>
</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