Feat: 拖拽至折叠的地址

This commit is contained in:
HFO4 2019-12-02 20:26:00 +08:00
parent 7100604876
commit 1e73c4f0f2
3 changed files with 444 additions and 288 deletions

View File

@ -1,41 +1,61 @@
import React,{useEffect} from "react";
import React, { useEffect,useState } from "react";
import { makeStyles } from "@material-ui/core";
import ShareIcon from '@material-ui/icons/Share'
import NewFolderIcon from '@material-ui/icons/CreateNewFolder'
import RefreshIcon from '@material-ui/icons/Refresh'
import {
Divider,
MenuItem,
ListItemIcon,
} from '@material-ui/core';
import { useDrop } from "react-dnd";
import DropDownItem from "./DropDownItem";
const useStyles = makeStyles(theme => ({
active: {
border: "2px solid " + theme.palette.primary.light
}
}));
export default function DropDown(props){
export default function DropDown(props) {
const classes = useStyles();
let timer;
let first = props.folders.length;
let status = [];
for (let index = 0; index < props.folders.length; index++) {
status[index] = false;
}
const setActiveStatus = (id,value)=>{
status[id] = value;
if (value){
clearTimeout(timer);
}else{
let shouldClose = true;
status.forEach(element => {
if (element){
shouldClose = false;
}
});
if (shouldClose){
if (first<=0){
timer = setTimeout(()=>{
props.onClose();
},100)
}else{
first--;
}
}
}
console.log(status);
}
return (
<>
<MenuItem onClick={()=>props.performAction("refresh")}>
<ListItemIcon><RefreshIcon/></ListItemIcon>
刷新
</MenuItem>
{(props.keywords===null&&window.isHomePage)&&
<div>
<Divider/>
<MenuItem onClick={()=>props.performAction("share")}>
<ListItemIcon><ShareIcon/></ListItemIcon>
分享
</MenuItem>
<MenuItem onClick={()=>props.performAction("newfolder")}>
<ListItemIcon><NewFolderIcon/></ListItemIcon>
创建文件夹
</MenuItem>
</div>
}
{props.folders.map((folder, id) => (
<DropDownItem
path={"/" + props.folders.slice(0, id).join("/")}
navigateTo={props.navigateTo}
id={id}
setActiveStatus = {setActiveStatus}
folder={folder}
/>
))}
</>
);
}
}

View File

@ -0,0 +1,59 @@
import React, { useEffect } from "react";
import { makeStyles } from "@material-ui/core";
import FolderIcon from "@material-ui/icons/Folder";
import {
Divider,
MenuItem,
ListItemIcon,
ListItemText
} from "@material-ui/core";
import { useDrop } from "react-dnd";
import classNames from "classnames";
const useStyles = makeStyles(theme => ({
active: {
border: "2px solid " + theme.palette.primary.light
}
}));
export default function DropDownItem(props) {
const [{ canDrop, isOver }, drop] = useDrop({
accept: "object",
drop: () => {
console.log({
folder: {
id: -1,
path: props.path,
name: props.folder == "/" ? "" : props.folder
}
});
},
collect: monitor => ({
isOver: monitor.isOver(),
canDrop: monitor.canDrop()
})
});
const isActive = canDrop && isOver;
let first = true;
useEffect(() => {
props.setActiveStatus(props.id,isActive);
}, [isActive])
const classes = useStyles();
return (
<MenuItem
ref={drop}
className={classNames({
[classes.active]: isActive
})}
onClick={e => props.navigateTo(e, props.id)}
>
<ListItemIcon>
<FolderIcon />
</ListItemIcon>
<ListItemText primary={props.folder} />
</MenuItem>
);
}

View File

@ -1,13 +1,15 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types';
import { connect } from 'react-redux'
import {withRouter} from 'react-router-dom'
import RightIcon from '@material-ui/icons/KeyboardArrowRight'
import ViewListIcon from '@material-ui/icons/ViewList'
import ViewModuleIcon from '@material-ui/icons/ViewModule'
import ViewSmallIcon from '@material-ui/icons/ViewComfy'
import TextTotateVerticalIcon from '@material-ui/icons/TextRotateVertical'
import FolderIcon from '@material-ui/icons/Folder'
import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { withRouter } from "react-router-dom";
import RightIcon from "@material-ui/icons/KeyboardArrowRight";
import ViewListIcon from "@material-ui/icons/ViewList";
import ViewModuleIcon from "@material-ui/icons/ViewModule";
import ViewSmallIcon from "@material-ui/icons/ViewComfy";
import TextTotateVerticalIcon from "@material-ui/icons/TextRotateVertical";
import ShareIcon from "@material-ui/icons/Share";
import NewFolderIcon from "@material-ui/icons/CreateNewFolder";
import RefreshIcon from "@material-ui/icons/Refresh";
import {
navitateTo,
navitateUp,
@ -20,10 +22,10 @@ import {
setSelectedTarget,
openCreateFolderDialog,
openShareDialog,
drawerToggleAction,
} from "../../../actions/index"
import API from '../../../middleware/Api'
import {setCookie,setGetParameter,fixUrlHash} from "../../../untils/index"
drawerToggleAction
} from "../../../actions/index";
import API from "../../../middleware/Api";
import { setCookie, setGetParameter, fixUrlHash } from "../../../untils/index";
import {
withStyles,
Divider,
@ -31,66 +33,65 @@ import {
MenuItem,
ListItemIcon,
ListItemText,
IconButton,
} from '@material-ui/core';
import PathButton from "./PathButton"
import DropDown from "./DropDown"
IconButton
} from "@material-ui/core";
import PathButton from "./PathButton";
import DropDown from "./DropDown";
import pathHelper from "../../../untils/page"
const mapStateToProps = state => {
return {
path: state.navigator.path,
refresh: state.navigator.refresh,
drawerDesktopOpen:state.viewUpdate.open,
viewMethod:state.viewUpdate.explorerViewMethod,
keywords:state.explorer.keywords,
sortMethod:state.viewUpdate.sortMethod,
}
}
path: state.navigator.path,
refresh: state.navigator.refresh,
drawerDesktopOpen: state.viewUpdate.open,
viewMethod: state.viewUpdate.explorerViewMethod,
keywords: state.explorer.keywords,
sortMethod: state.viewUpdate.sortMethod
};
};
const mapDispatchToProps = dispatch => {
return {
navigateToPath: path => {
dispatch(navitateTo(path))
dispatch(navitateTo(path));
},
navitateUp:()=>{
dispatch(navitateUp())
navitateUp: () => {
dispatch(navitateUp());
},
changeView:method=>{
dispatch(changeViewMethod(method))
changeView: method => {
dispatch(changeViewMethod(method));
},
changeSort:method=>{
dispatch(changeSortMethod(method))
changeSort: method => {
dispatch(changeSortMethod(method));
},
setNavigatorError:(status,msg)=>{
dispatch(setNavigatorError(status,msg))
setNavigatorError: (status, msg) => {
dispatch(setNavigatorError(status, msg));
},
updateFileList:list=>{
dispatch(updateFileList(list))
updateFileList: list => {
dispatch(updateFileList(list));
},
setNavigatorLoadingStatus:status=>{
dispatch(setNavigatorLoadingStatus(status))
setNavigatorLoadingStatus: status => {
dispatch(setNavigatorLoadingStatus(status));
},
refreshFileList:()=>{
dispatch(refreshFileList())
refreshFileList: () => {
dispatch(refreshFileList());
},
setSelectedTarget:(target)=>{
dispatch(setSelectedTarget(target))
setSelectedTarget: target => {
dispatch(setSelectedTarget(target));
},
openCreateFolderDialog:()=>{
dispatch(openCreateFolderDialog())
openCreateFolderDialog: () => {
dispatch(openCreateFolderDialog());
},
openShareDialog:()=>{
dispatch(openShareDialog())
openShareDialog: () => {
dispatch(openShareDialog());
},
handleDesktopToggle: open => {
dispatch(drawerToggleAction(open))
},
}
}
dispatch(drawerToggleAction(open));
}
};
};
const delay = (ms) => new Promise(
(resolve) => setTimeout(resolve, ms)
);
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
const sortOptions = [
"文件名称正序",
@ -98,194 +99,206 @@ const sortOptions = [
"上传时间正序",
"上传时间到序",
"文件大小正序",
"文件大小倒序",
"文件大小倒序"
];
const styles = theme => ({
container:{
[theme.breakpoints.down('xs')]: {
display:"none",
container: {
[theme.breakpoints.down("xs")]: {
display: "none"
},
height:"48px",
overflow:"hidden",
backgroundColor:theme.palette.background.paper,
height: "48px",
overflow: "hidden",
backgroundColor: theme.palette.background.paper
},
navigatorContainer:{
"display": "flex",
"justifyContent": "space-between",
navigatorContainer: {
display: "flex",
justifyContent: "space-between"
},
nav:{
height:"47px",
padding:"5px 15px",
display:"flex",
nav: {
height: "47px",
padding: "5px 15px",
display: "flex"
},
optionContainer:{
optionContainer: {
paddingTop: "6px",
marginRight:"10px",
marginRight: "10px"
},
rightIcon:{
rightIcon: {
marginTop: "6px",
verticalAlign: "top",
color:"#868686",
color: "#868686"
},
expandMore:{
color:"#8d8d8d",
expandMore: {
color: "#8d8d8d"
},
sideButton:{
padding:"8px",
marginRight:"5px",
sideButton: {
padding: "8px",
marginRight: "5px"
}
})
});
class NavigatorCompoment extends Component {
keywords = null;
state = {
hidden:false,
hiddenFolders:[],
folders:[],
hidden: false,
hiddenFolders: [],
folders: [],
anchorEl: null,
hiddenMode:false,
anchorHidden:null,
anchorSort:null,
selectedIndex:0,
}
hiddenMode: false,
anchorHidden: null,
anchorSort: null,
selectedIndex: 0
};
constructor(props) {
super(props);
this.element = React.createRef();
}
componentDidMount = ()=>{
componentDidMount = () => {
this.renderPath();
// 如果是在个人文件管理页,首次加载时打开侧边栏
this.props.handleDesktopToggle(true);
// 后退操作时重新导航
window.onpopstate = (event)=>{
window.onpopstate = event => {
var url = new URL(fixUrlHash(window.location.href));
var c = url.searchParams.get("path");
if(c!==null&&c!==this.props.path){
if (c !== null && c !== this.props.path) {
this.props.navigateToPath(c);
}
};
}
};
renderPath = (path=null)=>{
this.props.setNavigatorError(false,null);
renderPath = (path = null) => {
this.props.setNavigatorError(false, null);
this.setState({
folders:path!==null?path.substr(1).split("/"):this.props.path.substr(1).split("/"),
folders:
path !== null
? path.substr(1).split("/")
: this.props.path.substr(1).split("/")
});
var newPath = path!==null?path:this.props.path;
var apiURL = this.keywords===null?'/directory':'/File/SearchFile';
newPath = this.keywords===null?newPath:this.keywords;
API.get(apiURL+newPath,)
.then( (response)=> {
this.props.updateFileList(response.data);
this.props.setNavigatorLoadingStatus(false);
let pathTemp = (path!==null?path.substr(1).split("/"):this.props.path.substr(1).split("/")).join(",");
setCookie("path_tmp",encodeURIComponent(pathTemp),1);
if(this.keywords===null){
setGetParameter("path",encodeURIComponent(newPath));
}
})
.catch((error) =>{
this.props.setNavigatorError(true,error);
});
this.checkOverFlow(true);
}
var newPath = path !== null ? path : this.props.path;
var apiURL = this.keywords === null ? "/directory" : "/File/SearchFile";
newPath = this.keywords === null ? newPath : this.keywords;
API.get(apiURL + newPath)
.then(response => {
this.props.updateFileList(response.data);
this.props.setNavigatorLoadingStatus(false);
let pathTemp = (path !== null
? path.substr(1).split("/")
: this.props.path.substr(1).split("/")
).join(",");
setCookie("path_tmp", encodeURIComponent(pathTemp), 1);
if (this.keywords === null) {
setGetParameter("path", encodeURIComponent(newPath));
}
})
.catch(error => {
this.props.setNavigatorError(true, error);
});
this.checkOverFlow(true);
};
redresh = (path) => {
redresh = path => {
this.props.setNavigatorLoadingStatus(true);
this.props.setNavigatorError(false,"error");
this.props.setNavigatorError(false, "error");
this.renderPath(path);
}
};
componentWillReceiveProps = (nextProps)=>{
if(this.props.keywords!==nextProps.keywords){
this.keywords=nextProps.keywords
componentWillReceiveProps = nextProps => {
if (this.props.keywords !== nextProps.keywords) {
this.keywords = nextProps.keywords;
}
if(this.props.path !== nextProps.path){
if (this.props.path !== nextProps.path) {
this.renderPath(nextProps.path);
}
if(this.props.refresh !== nextProps.refresh){
this.redresh(nextProps.path);
if (this.props.refresh !== nextProps.refresh) {
this.redresh(nextProps.path);
}
};
}
componentDidUpdate = (prevProps,prevStates)=>{
if(this.state.folders !== prevStates.folders){
componentDidUpdate = (prevProps, prevStates) => {
if (this.state.folders !== prevStates.folders) {
this.checkOverFlow(true);
}
if(this.props.drawerDesktopOpen !== prevProps.drawerDesktopOpen){
if (this.props.drawerDesktopOpen !== prevProps.drawerDesktopOpen) {
delay(500).then(() => this.checkOverFlow());
}
}
};
checkOverFlow = (force)=>{
if (this.overflowInitLock && !force){
checkOverFlow = force => {
if (this.overflowInitLock && !force) {
return;
}
if (this.element.current !== null){
const hasOverflowingChildren = this.element.current.offsetHeight < this.element.current.scrollHeight ||
this.element.current.offsetWidth < this.element.current.scrollWidth;
if(hasOverflowingChildren){
if (this.element.current !== null) {
const hasOverflowingChildren =
this.element.current.offsetHeight <
this.element.current.scrollHeight ||
this.element.current.offsetWidth <
this.element.current.scrollWidth;
if (hasOverflowingChildren) {
this.overflowInitLock = true;
this.setState({hiddenMode:true});
this.setState({ hiddenMode: true });
}
if(!hasOverflowingChildren && this.state.hiddenMode){
this.setState({hiddenMode:false});
if (!hasOverflowingChildren && this.state.hiddenMode) {
this.setState({ hiddenMode: false });
}
}
}
navigateTo=(event,id)=> {
if (id === this.state.folders.length-1){
};
navigateTo = (event, id) => {
if (id === this.state.folders.length - 1) {
//最后一个路径
this.setState({ anchorEl: event.currentTarget });
return;
}else if(id===-1 && this.state.folders.length === 1 && this.state.folders[0] === ""){
} else if (
id === -1 &&
this.state.folders.length === 1 &&
this.state.folders[0] === ""
) {
this.props.refreshFileList();
this.handleClose();
this.handleClose();
return;
}else if (id === -1){
} else if (id === -1) {
this.props.navigateToPath("/");
this.handleClose();
return;
}else{
this.props.navigateToPath("/"+this.state.folders.slice(0,id+1).join("/"));
} else {
this.props.navigateToPath(
"/" + this.state.folders.slice(0, id + 1).join("/")
);
this.handleClose();
}
}
handleClose = () => {
this.setState({ anchorEl: null ,anchorHidden:null,anchorSort:null});
};
showHiddenPath = (e) => {
this.setState({ anchorHidden: e.currentTarget });
}
handleClose = () => {
this.setState({ anchorEl: null, anchorHidden: null, anchorSort: null });
};
showSortOptions = (e) => {
showHiddenPath = e => {
this.setState({ anchorHidden: e.currentTarget });
};
showSortOptions = e => {
this.setState({ anchorSort: e.currentTarget });
}
};
performAction = e => {
this.handleClose();
if(e==="refresh"){
if (e === "refresh") {
this.redresh();
return;
}
let presentPath = this.props.path.split("/");
let newTarget = [{
type:"dir",
name:presentPath.pop(),
path:presentPath.length===1?"/":presentPath.join("/"),
}];
let newTarget = [
{
type: "dir",
name: presentPath.pop(),
path: presentPath.length === 1 ? "/" : presentPath.join("/")
}
];
//this.props.navitateUp();
switch (e) {
case "share":
@ -298,57 +311,88 @@ class NavigatorCompoment extends Component {
default:
break;
}
}
};
toggleViewMethod = () => {
this.props.changeView(this.props.viewMethod==="icon"?"list":(this.props.viewMethod==="list"?"smallIcon":"icon"));
}
this.props.changeView(
this.props.viewMethod === "icon"
? "list"
: this.props.viewMethod === "list"
? "smallIcon"
: "icon"
);
};
handleMenuItemClick = (e,index) => {
handleMenuItemClick = (e, index) => {
this.setState({ selectedIndex: index, anchorEl: null });
let optionsTable = {
0:"namePos",
1:"nameRev",
2:"timePos",
3:"timeRev",
4:"sizePos",
5:"sizeRes",
0: "namePos",
1: "nameRev",
2: "timePos",
3: "timeRev",
4: "sizePos",
5: "sizeRes"
};
this.props.changeSort(optionsTable[index]);
this.handleClose();
this.props.refreshFileList();
}
};
render() {
const { classes } = this.props;
const { classes} = this.props;
let presentFolderMenu = (<Menu
id="presentFolderMenu"
anchorEl={this.state.anchorEl}
open={Boolean(this.state.anchorEl)}
onClose={this.handleClose}
disableAutoFocusItem={true}
let presentFolderMenu = (
<Menu
id="presentFolderMenu"
anchorEl={this.state.anchorEl}
open={Boolean(this.state.anchorEl)}
onClose={this.handleClose}
disableAutoFocusItem={true}
>
<DropDown keywords={this.props.keywords} performAction = {this.performAction}/>
</Menu>);
<MenuItem onClick={() => this.performAction("refresh")}>
<ListItemIcon>
<RefreshIcon />
</ListItemIcon>
刷新
</MenuItem>
{this.props.keywords === null && pathHelper.isHomePage(this.props.location.pathname) && (
<div>
<Divider />
<MenuItem onClick={() => this.performAction("share")}>
<ListItemIcon>
<ShareIcon />
</ListItemIcon>
分享
</MenuItem>
<MenuItem
onClick={() => this.performAction("newfolder")}
>
<ListItemIcon>
<NewFolderIcon />
</ListItemIcon>
创建文件夹
</MenuItem>
</div>
)}
</Menu>
);
return (
<div className={classes.container}>
<div className={classes.container}>
<div className={classes.navigatorContainer}>
<div className={classes.nav} ref={this.element}>
<span>
<PathButton folder="/" path="/" onClick={(e)=>this.navigateTo(e,-1)} />
<RightIcon className={classes.rightIcon}/>
<PathButton
folder="/"
path="/"
onClick={e => this.navigateTo(e, -1)}
/>
<RightIcon className={classes.rightIcon} />
</span>
{this.state.hiddenMode &&
{this.state.hiddenMode && (
<span>
<PathButton
<PathButton
more
title="显示路径"
onClick={this.showHiddenPath}
@ -360,69 +404,100 @@ class NavigatorCompoment extends Component {
onClose={this.handleClose}
disableAutoFocusItem={true}
>
{this.state.folders.slice(0,-1).map((folder,id)=>(
<MenuItem onClick={(e)=>this.navigateTo(e,id)}>
<ListItemIcon>
<FolderIcon />
</ListItemIcon>
<ListItemText primary={folder} />
</MenuItem>
))}
<DropDown onClose={this.handleClose} folders={this.state.folders.slice(0, -1)} navigateTo = {this.navigateTo}/>
</Menu>
<RightIcon className={classes.rightIcon}/>
<RightIcon className={classes.rightIcon} />
{/* <Button component="span" onClick={(e)=>this.navigateTo(e,this.state.folders.length-1)}>
{this.state.folders.slice(-1)}
<ExpandMore className={classes.expandMore}/>
</Button> */}
<PathButton
folder={this.state.folders.slice(-1)}
path={"/"+this.state.folders.slice(0,-1).join("/")}
<PathButton
folder={this.state.folders.slice(-1)}
path={
"/" +
this.state.folders
.slice(0, -1)
.join("/")
}
last={true}
onClick={(e)=>this.navigateTo(e,this.state.folders.length-1)}
onClick={e =>
this.navigateTo(
e,
this.state.folders.length - 1
)
}
/>
{presentFolderMenu}
{presentFolderMenu}
</span>
}
{!this.state.hiddenMode && this.state.folders.map((folder,id,folders)=>(
<span key={id}>
{folder !=="" &&
<span>
<PathButton
folder={folder}
path={"/"+folders.slice(0,id).join("/")}
last={id === folders.length-1}
onClick={(e)=>this.navigateTo(e,id)}
/>
{(id === folders.length-1) &&
presentFolderMenu
}
{(id !== folders.length-1) && <RightIcon className={classes.rightIcon}/>}
</span>
}
</span>
))}
)}
{!this.state.hiddenMode &&
this.state.folders.map((folder, id, folders) => (
<span key={id}>
{folder !== "" && (
<span>
<PathButton
folder={folder}
path={
"/" +
folders
.slice(0, id)
.join("/")
}
last={id === folders.length - 1}
onClick={e =>
this.navigateTo(e, id)
}
/>
{id === folders.length - 1 &&
presentFolderMenu}
{id !== folders.length - 1 && (
<RightIcon
className={
classes.rightIcon
}
/>
)}
</span>
)}
</span>
))}
</div>
<div className={classes.optionContainer}>
{(this.props.viewMethod === "icon")&&
<IconButton title="列表展示" className={classes.sideButton} onClick={this.toggleViewMethod}>
{this.props.viewMethod === "icon" && (
<IconButton
title="列表展示"
className={classes.sideButton}
onClick={this.toggleViewMethod}
>
<ViewListIcon fontSize="small" />
</IconButton>
}
{(this.props.viewMethod === "list")&&
<IconButton title="小图标展示" className={classes.sideButton} onClick={this.toggleViewMethod}>
)}
{this.props.viewMethod === "list" && (
<IconButton
title="小图标展示"
className={classes.sideButton}
onClick={this.toggleViewMethod}
>
<ViewSmallIcon fontSize="small" />
</IconButton>
}
)}
{(this.props.viewMethod === "smallIcon")&&
<IconButton title="大图标展示" className={classes.sideButton} onClick={this.toggleViewMethod}>
{this.props.viewMethod === "smallIcon" && (
<IconButton
title="大图标展示"
className={classes.sideButton}
onClick={this.toggleViewMethod}
>
<ViewModuleIcon fontSize="small" />
</IconButton>
}
<IconButton title="排序方式" className={classes.sideButton} onClick={this.showSortOptions}>
)}
<IconButton
title="排序方式"
className={classes.sideButton}
onClick={this.showSortOptions}
>
<TextTotateVerticalIcon fontSize="small" />
</IconButton>
<Menu
@ -431,34 +506,36 @@ class NavigatorCompoment extends Component {
open={Boolean(this.state.anchorSort)}
onClose={this.handleClose}
>
{sortOptions.map((option, index) => (
<MenuItem
key={option}
selected={index === this.state.selectedIndex}
onClick={event => this.handleMenuItemClick(event, index)}
>
{option}
</MenuItem>
))}
{sortOptions.map((option, index) => (
<MenuItem
key={option}
selected={
index === this.state.selectedIndex
}
onClick={event =>
this.handleMenuItemClick(event, index)
}
>
{option}
</MenuItem>
))}
</Menu>
</div>
</div>
<Divider/>
</div>
<Divider />
</div>
);
}
}
NavigatorCompoment.propTypes = {
classes: PropTypes.object.isRequired,
path:PropTypes.string.isRequired,
path: PropTypes.string.isRequired
};
const Navigator = connect(
mapStateToProps,
mapDispatchToProps
)( withStyles(styles)(withRouter(NavigatorCompoment)))
)(withStyles(styles)(withRouter(NavigatorCompoment)));
export default Navigator
export default Navigator;