Feat: 拖拽移动

This commit is contained in:
HFO4 2019-12-01 20:00:32 +08:00
parent 457809008d
commit 3c84e7f782
8 changed files with 141 additions and 34 deletions

View File

@ -18,6 +18,14 @@ export const drawerToggleAction = open => {
};
};
export const dragAndDrop = (source,target) => {
return {
type: "DRAG_AND_DROP",
source: source,
target: target,
};
};
export const changeViewMethod = method => {
return {
type: "CHANGE_VIEW_METHOD",

View File

@ -32,6 +32,9 @@ import OpenIcon from '@material-ui/icons/OpenInNew'
import {MagnetOn} from 'mdi-material-ui'
import {baseURL} from "../../middleware/Api"
import { withStyles, Popover, Typography, MenuList, MenuItem, Divider, ListItemIcon } from '@material-ui/core';
import pathHelper from "../../untils/page"
import {withRouter} from 'react-router-dom'
import Auth from "../../middleware/Auth"
const styles = theme => ({
propover:{
@ -164,14 +167,14 @@ class ContextMenuCompoment extends Component {
window.open(window.apiURL.preview+"/?action=preview&path="+encodeURIComponent(previewPath));
return;
case 'video':
if(window.isSharePage){
if(pathHelper.isSharePage(this.props.location.pathname)){
window.location.href=("/Viewer/Video?share=true&shareKey="+window.shareInfo.shareId+"&path="+encodeURIComponent(previewPath));
return;
}
window.location.href=("/Viewer/Video?&path="+encodeURIComponent(previewPath));
return;
case 'edit':
if(window.isSharePage){
if(pathHelper.isSharePage(this.props.location.pathname)){
window.location.href=("/Viewer/Markdown?share=true&shareKey="+window.shareInfo.shareId+"&path="+encodeURIComponent(previewPath));
return;
}
@ -211,7 +214,7 @@ class ContextMenuCompoment extends Component {
</ListItemIcon>
<Typography variant="inherit">上传文件</Typography>
</MenuItem>
{window.uploadConfig.allowRemoteDownload==="1"&&
{Auth.GetUser().group.allowRemoteDownload&&
<MenuItem onClick={()=>this.props.openRemoteDownloadDialog()}>
<ListItemIcon>
<DownloadIcon/>
@ -261,7 +264,7 @@ class ContextMenuCompoment extends Component {
</MenuItem>
}
{(!this.props.isMultiple&&this.props.withFile&&(window.uploadConfig.allowSource==="1"))&&
{(!this.props.isMultiple&&this.props.withFile&&(Auth.GetUser().policy.allowSource))&&
<MenuItem onClick={()=>this.props.openGetSourceDialog()}>
<ListItemIcon>
<LinkIcon/>
@ -270,7 +273,7 @@ class ContextMenuCompoment extends Component {
</MenuItem>
}
{(!this.props.isMultiple&&window.isHomePage&&(window.uploadConfig.allowTorrentDownload==="1")&&this.props.withFile&&isTorrent(this.props.selected[0].name))&&
{(!this.props.isMultiple&&pathHelper.isHomePage(this.props.location.pathname)&&(Auth.GetUser().group.allowTorrentDownload)&&this.props.withFile&&isTorrent(this.props.selected[0].name))&&
<MenuItem onClick={()=>this.props.openTorrentDownloadDialog()}>
<ListItemIcon>
<MagnetOn/>
@ -279,7 +282,7 @@ class ContextMenuCompoment extends Component {
</MenuItem>
}
{(!this.props.isMultiple &&window.isHomePage)&&
{(!this.props.isMultiple && pathHelper.isHomePage(this.props.location.pathname))&&
<MenuItem onClick={()=>this.props.openShareDialog()}>
<ListItemIcon>
<ShareIcon/>
@ -288,7 +291,7 @@ class ContextMenuCompoment extends Component {
</MenuItem>
}
{(!this.props.isMultiple&&window.isHomePage)&&
{(!this.props.isMultiple&&pathHelper.isHomePage(this.props.location.pathname))&&
<MenuItem onClick={()=>this.props.openRenameDialog() }>
<ListItemIcon>
<RenameIcon/>
@ -296,7 +299,7 @@ class ContextMenuCompoment extends Component {
<Typography variant="inherit">重命名</Typography>
</MenuItem>
}
{window.isHomePage&&<div>
{pathHelper.isHomePage(this.props.location.pathname)&&<div>
<MenuItem onClick={()=>this.props.openMoveDialog() }>
<ListItemIcon>
<MoveIcon/>
@ -331,6 +334,6 @@ ContextMenuCompoment.propTypes = {
const ContextMenu = connect(
mapStateToProps,
mapDispatchToProps
)( withStyles(styles)(ContextMenuCompoment))
)( withStyles(styles)(withRouter(ContextMenuCompoment)))
export default ContextMenu

View File

@ -25,6 +25,7 @@ import {
FormControl,
FormControlLabel,
} from '@material-ui/core';
import Loading from "../Modals/Loading"
const styles = theme => ({
wrapper: {
@ -58,6 +59,9 @@ const mapStateToProps = state => {
modalsLoading:state.viewUpdate.modalsLoading,
dirList:state.explorer.dirList,
fileList:state.explorer.fileList,
dndSignale:state.explorer.dndSignal,
dndTarget:state.explorer.dndTarget,
dndSource:state.explorer.dndSource,
}
}
@ -95,7 +99,9 @@ class ModalsCompoment extends Component {
downloadURL:"",
remoteDownloadPathSelect:false,
source:"",
dialogLoading:false,
}
handleInputChange = (e)=>{
this.setState({
@ -106,6 +112,9 @@ class ModalsCompoment extends Component {
newNameSuffix = "";
componentWillReceiveProps = (nextProps)=>{
if(this.props.dndSignale!==nextProps.dndSignale){
this.dragMove(nextProps.dndSource,nextProps.dndTarget);
}
if(this.props.modalsStatus.rename!==nextProps.modalsStatus.rename){
let name = nextProps.selected[0].name.split(".");
if(name.length>1){
@ -178,7 +187,7 @@ class ModalsCompoment extends Component {
this.onClose();
this.props.refreshFileList();
}else{
this.props.toggleSnackbar("top","right",response.data.result.error,"warning");
this.props.toggleSnackbar("top","right",response.rawData.msg,"warning");
}
this.props.setModalsLoading(false);
this.props.refreshStorage();
@ -186,7 +195,6 @@ class ModalsCompoment extends Component {
.catch((error) =>{
this.props.toggleSnackbar("top","right",error.message ,"error");
this.props.setModalsLoading(false);
});
}
@ -212,38 +220,63 @@ class ModalsCompoment extends Component {
}
submitMove = e =>{
e.preventDefault();
if (e!=null){
e.preventDefault();
}
this.props.setModalsLoading(true);
let dirs=[],items = [];
// eslint-disable-next-line
this.props.selected.map((value)=>{
if(value.type==="dir"){
dirs.push(value.path === "/" ? value.path+value.name:value.path+"/"+value.name);
dirs.push(value.name);
}else{
items.push(value.path === "/" ? value.path+value.name:value.path+"/"+value.name);
items.push(value.name);
}
});
axios.post('/File/Move', {
API.patch('/object', {
action: 'move',
items: items,
dirs:dirs,
newPath:this.state.selectedPath === "//"?"/":this.state.selectedPath,
src_dir:this.props.selected[0].path,
src:{
dirs:dirs,
items: items,
},
dst:this.DragSelectedPath?this.DragSelectedPath:(this.state.selectedPath === "//"?"/":this.state.selectedPath),
})
.then( (response)=> {
if(response.data.result.success){
this.onClose();
this.props.refreshFileList();
}else{
this.props.toggleSnackbar("top","right",response.data.result.error,"warning");
}
this.onClose();
this.props.refreshFileList();
this.props.setModalsLoading(false);
})
.catch((error) =>{
this.props.toggleSnackbar("top","right",error.message ,"error");
this.props.setModalsLoading(false);
}).finally(()=>{
this.setState({
dialogLoading:false,
});
});
}
dragMove = (source,target) =>{
if (this.props.selected.length==0){
this.props.selected[0] = source
}
let doMove = true;
this.props.selected.map((value)=>{
if(value.id===target.id && value.type==target.type){
doMove = false;
}
});
if (doMove){
this.DragSelectedPath = target.path=="/"?(target.path+target.name):(target.path+"/"+target.name);
this.setState({
dialogLoading:true,
});
this.submitMove();
}
}
submitRename = e =>{
e.preventDefault();
this.props.setModalsLoading(true);
@ -396,6 +429,7 @@ class ModalsCompoment extends Component {
return (
<div>
<Loading open={this.state.dialogLoading} />
<Dialog
open={this.props.modalsStatus.getSource}
onClose={this.onClose}

View File

@ -9,7 +9,8 @@ import {
navitateTo,
showImgPreivew,
openMusicDialog,
toggleSnackbar
toggleSnackbar,
dragAndDrop
} from "../../actions/index";
import statusHelper from "../../untils/page"
import FileIcon from "./FileIcon";
@ -82,6 +83,11 @@ export default function ObjectIcon(props) {
dispatch(toggleSnackbar(vertical, horizontal, msg, color)),
[dispatch]
);
const DragAndDrop = useCallback(
(source, target) =>
dispatch(dragAndDrop(source, target)),
[dispatch]
);
const classes = useStyles();
@ -208,8 +214,9 @@ export default function ObjectIcon(props) {
end: (item, monitor) => {
const dropResult = monitor.getDropResult();
if (item && dropResult) {
alert(`drop`);
console.log(item.object,dropResult.folder);
if (item.object.id != dropResult.folder.id){
DragAndDrop(item.object,dropResult.folder);
}
}
},
canDrag: () =>{

View File

@ -19,6 +19,8 @@ import {
withStyles,
ListItemSecondaryAction,
} from '@material-ui/core';
import API from '../../middleware/Api'
import { Api } from 'mdi-material-ui';
const mapStateToProps = state => {
return {
@ -78,12 +80,9 @@ class PathSelectorCompoment extends Component {
}
enterFolder = (toBeLoad)=>{
axios.post('/File/ListFile', {
action: 'list',
path: toBeLoad,
})
API.get('/directory'+toBeLoad,)
.then( (response)=> {
var dirList = response.data.result.filter( (x)=> {
var dirList = response.data.filter( (x)=> {
return (x.type === "dir" && (this.props.selected.findIndex((value)=>{
return (value.name === x.name )&&(value.path === x.path);
}))===-1);
@ -130,13 +129,13 @@ class PathSelectorCompoment extends Component {
<FolderIcon />
</ListItemIcon>
<ListItemText classes={{ primary: classes.primary }} primary={value.name} />
<ListItemSecondaryAction className={classes.buttonIcon}>
{value.name!=="/"&&<ListItemSecondaryAction className={classes.buttonIcon}>
<IconButton className={classNames({
[classes.iconWhite]:this.state.selectedTarget === index,
})} onClick={()=>this.enterFolder(value.path === "/"?value.path+value.name:value.path+"/"+value.name)}>
<RightIcon />
</IconButton>
</ListItemSecondaryAction>
</ListItemSecondaryAction>}
</MenuItem>
))}

View File

@ -0,0 +1,45 @@
import React from 'react';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/core/styles';
import CircularProgress from '@material-ui/core/CircularProgress';
import DialogContent from '@material-ui/core/DialogContent';
import Dialog from '@material-ui/core/Dialog';
import DialogContentText from '@material-ui/core/DialogContentText';
import { blue } from '@material-ui/core/colors';
const emails = ['username@gmail.com', 'user02@gmail.com'];
const useStyles = makeStyles({
avatar: {
backgroundColor: blue[100],
color: blue[600],
},
loadingContainer:{
display:"flex",
},
loading:{
marginTop: 10,
marginLeft: 20,
}
});
export default function LoadingDialog(props) {
const classes = useStyles();
const { open } = props;
return (
<Dialog aria-labelledby="simple-dialog-title" open={open}>
<DialogContent>
<DialogContentText className={classes.loadingContainer}><CircularProgress color="secondary" />
<div className={classes.loading}>处理中...</div>
</DialogContentText>
</DialogContent>
</Dialog>
);
}
LoadingDialog.propTypes = {
open: PropTypes.bool.isRequired,
};

View File

@ -92,6 +92,9 @@ const defaultStatus = InitSiteConfig({
}
},
explorer: {
dndSignal:false,
dndTarget:null,
dndSource:null,
fileList: [],
dirList: [],
selected: [],

View File

@ -64,6 +64,14 @@ const cloudreveApp = (state = [], action) => {
contextType:action.menuType,
}),
});
case 'DRAG_AND_DROP':
return Object.assign({}, state, {
explorer: Object.assign({}, state.explorer, {
dndSignal: !state.explorer.dndSignal,
dndTarget:action.target,
dndSource:action.source,
}),
});
case 'SET_NAVIGATOR_LOADING_STATUE':
return Object.assign({}, state, {
viewUpdate: Object.assign({}, state.viewUpdate, {