mirror of
https://github.com/cloudreve/frontend.git
synced 2025-12-25 19:52:48 +00:00
Feat: 拖拽移动
This commit is contained in:
parent
457809008d
commit
3c84e7f782
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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: () =>{
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
))}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
@ -92,6 +92,9 @@ const defaultStatus = InitSiteConfig({
|
|||
}
|
||||
},
|
||||
explorer: {
|
||||
dndSignal:false,
|
||||
dndTarget:null,
|
||||
dndSource:null,
|
||||
fileList: [],
|
||||
dirList: [],
|
||||
selected: [],
|
||||
|
|
|
|||
|
|
@ -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, {
|
||||
|
|
|
|||
Loading…
Reference in New Issue