diff --git a/package.json b/package.json index 3820ebd..403b83e 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "dependencies": { "@material-ui/core": "^4.9.0", "@material-ui/icons": "^4.5.1", - "@material-ui/lab": "^4.0.0-alpha.33", + "@material-ui/lab": "^4.0.0-alpha.42", "axios": "^0.19.0", "classnames": "^2.2.6", "for-editor": "^0.3.5", diff --git a/src/App.js b/src/App.js index a3aa27f..655f577 100644 --- a/src/App.js +++ b/src/App.js @@ -13,16 +13,17 @@ import { import Auth from "./middleware/Auth"; import { CssBaseline, makeStyles, ThemeProvider } from "@material-ui/core"; import PageLoading from "./component/Placeholder/PageLoading.js" -import TextViewer from "./component/Viewer/Text"; -import DocViewer from "./component/Viewer/Doc"; -import SharePreload from "./component/Share/SharePreload"; -import Download from "./component/Download/Download"; -import MyShare from "./component/MyShare"; // Lazy loads const LoginForm = React.lazy(() => import("./component/Login/LoginForm")); const FileManager = React.lazy(() => import ("./component/FileManager/FileManager.js" )); const VideoPreview = React.lazy(() => import ("./component/Viewer/Video.js" )); +const SearchResult = React.lazy(() => import ("./component/Share/SearchResult" )); +const MyShare = React.lazy(() => import ("./component/Share/MyShare")); +const Download = React.lazy(() => import ("./component/Download/Download")); +const SharePreload = React.lazy(() => import ("./component/Share/SharePreload")); +const DocViewer = React.lazy(() => import ("./component/Viewer/Doc")); +const TextViewer = React.lazy(() => import ("./component/Viewer/Text")); export default function App() { const themeConfig = useSelector(state => state.siteConfig.theme); @@ -107,6 +108,12 @@ export default function App() { + + }> + + + + }> diff --git a/src/component/FileManager/ContextMenu.js b/src/component/FileManager/ContextMenu.js index ab24493..809bfe1 100644 --- a/src/component/FileManager/ContextMenu.js +++ b/src/component/FileManager/ContextMenu.js @@ -51,10 +51,15 @@ import Auth from "../../middleware/Auth"; import { Archive, Unarchive } from "@material-ui/icons"; import { openCompressDialog } from "../../actions"; import Menu from "@material-ui/core/Menu"; +import {FolderUpload} from "mdi-material-ui"; const styles = theme => ({ propover: { minWidth: "200px!important" + }, + divider:{ + marginTop:4, + marginBottom:4, } }); @@ -176,9 +181,9 @@ class ContextMenuCompoment extends Component { ); }; - clickUpload = () => { + clickUpload = id => { this.props.changeContextMenu("empty", false); - let uploadButton = document.getElementsByClassName("uploadFileForm")[0]; + let uploadButton = document.getElementsByClassName(id)[0]; if (document.body.contains(uploadButton)) { uploadButton.click(); } else { @@ -296,7 +301,7 @@ class ContextMenuCompoment extends Component { > {this.props.menuType === "empty" && ( <> - + this.clickUpload("uploadFileForm")}> @@ -304,6 +309,14 @@ class ContextMenuCompoment extends Component { 上传文件 + this.clickUpload("uploadFolderForm")}> + + + + + 上传目录 + + {user.group.allowRemoteDownload && ( @@ -319,7 +332,7 @@ class ContextMenuCompoment extends Component { )} - + this.props.openCreateFolderDialog() @@ -346,7 +359,7 @@ class ContextMenuCompoment extends Component { 进入 - {isHomePage && } + {isHomePage && } )} {!this.props.isMultiple && @@ -380,7 +393,7 @@ class ContextMenuCompoment extends Component { 下载 - {isHomePage && } + {isHomePage && } )} @@ -466,7 +479,7 @@ class ContextMenuCompoment extends Component { - 压缩 + 创建压缩文件 )} @@ -479,7 +492,7 @@ class ContextMenuCompoment extends Component { - 分享 + 创建分享链接 )} @@ -532,7 +545,7 @@ class ContextMenuCompoment extends Component { } - + diff --git a/src/component/Share/LockedFile.js b/src/component/Share/LockedFile.js index 64a7558..55f51a3 100644 --- a/src/component/Share/LockedFile.js +++ b/src/component/Share/LockedFile.js @@ -14,6 +14,7 @@ import { TextField, Avatar } from "@material-ui/core"; +import {useLocation, withRouter} from "react-router"; const styles = theme => ({ card: { @@ -53,9 +54,14 @@ const mapDispatchToProps = dispatch => { }; class LockedFileCompoment extends Component { - state = { - pwd: "" - }; + constructor(props) { + super(props); + let query = new URLSearchParams(this.props.location.search); + this.state = { + pwd: query.get("password"), + }; + + } handleChange = name => event => { this.setState({ [name]: event.target.value }); @@ -129,6 +135,6 @@ class LockedFileCompoment extends Component { const LockedFile = connect( mapStateToProps, mapDispatchToProps -)(withStyles(styles)(LockedFileCompoment)); +)(withStyles(styles)(withRouter(LockedFileCompoment))); export default LockedFile; diff --git a/src/component/MyShare.js b/src/component/Share/MyShare.js similarity index 65% rename from src/component/MyShare.js rename to src/component/Share/MyShare.js index d728445..fe9f0d3 100644 --- a/src/component/MyShare.js +++ b/src/component/Share/MyShare.js @@ -1,9 +1,9 @@ import React, { Component } from "react"; import { connect } from "react-redux"; -import { toggleSnackbar } from "../actions/index"; +import { toggleSnackbar } from "../../actions"; import axios from "axios"; import OpenIcon from "@material-ui/icons/OpenInNew"; -import FileIcon from "@material-ui/icons/InsertDriveFile"; +import Pagination from "@material-ui/lab/Pagination"; import FolderIcon from "@material-ui/icons/Folder"; import LockIcon from "@material-ui/icons/Lock"; import UnlockIcon from "@material-ui/icons/LockOpen"; @@ -27,10 +27,16 @@ import { Button, TextField } from "@material-ui/core"; -import API from "../middleware/Api"; -import TypeIcon from "./FileManager/TypeIcon"; +import API from "../../middleware/Api"; +import TypeIcon from "../FileManager/TypeIcon"; import Chip from "@material-ui/core/Chip"; import Divider from "@material-ui/core/Divider"; +import { VisibilityOff, VpnKey } from "@material-ui/icons"; +import Select from "@material-ui/core/Select"; +import MenuItem from "@material-ui/core/MenuItem"; +import FormHelperText from "@material-ui/core/FormHelperText"; +import FormControl from "@material-ui/core/FormControl"; +import {withRouter} from "react-router-dom"; const styles = theme => ({ cardContainer: { @@ -67,13 +73,17 @@ const styles = theme => ({ marginTop: "30px" }, loadMore: { - textAlign: "center", + textAlign: "right", marginTop: "20px", - marginBottom: "20px" + marginBottom: "40px" }, badge: { marginLeft: theme.spacing(1), - height: 17, + height: 17 + }, + orderSelect:{ + textAlign:"right", + marginTop: 5, } }); const mapStateToProps = state => { @@ -91,16 +101,14 @@ const mapDispatchToProps = dispatch => { class MyShareCompoment extends Component { state = { page: 1, + total: 0, shareList: [], - showPwd: null + showPwd: null, + orderBy:"created_at DESC", }; componentDidMount = () => { - this.loadList(1); - }; - - loadMore = () => { - this.loadList(this.state.page + 1); + this.loadList(1,this.state.orderBy); }; showPwd = pwd => { @@ -111,19 +119,17 @@ class MyShareCompoment extends Component { this.setState({ showPwd: null }); }; - removeShare = id => { - axios - .post("/Share/Delete", { - id: id - }) + removeShare = (id) => { + API + .delete("/share/"+id) .then(response => { - if (response.data.error !== 1) { let oldList = this.state.shareList; oldList = oldList.filter(value => { - return value.share_key !== id; + return value.key !== id; }); this.setState({ - shareList: oldList + shareList: oldList, + total:this.state.total-1, }); this.props.toggleSnackbar( "top", @@ -131,41 +137,65 @@ class MyShareCompoment extends Component { "分享已取消", "success" ); - } + if (oldList.length === 0){ + this.loadList(1,this.state.orderBy); + } + }) .catch(error => { - this.props.toggleSnackbar("top", "right", "请求失败", "error"); + this.props.toggleSnackbar("top", "right", error.message, "error"); }); }; changePermission = id => { - axios - .post("/Share/ChangePromission", { - id: id + let newPwd = Math.random() + .toString(36) + .substr(2) + .slice(2, 8); + let oldList = this.state.shareList; + let shareIndex = oldList.findIndex(value => { + return value.key === id; + }); + API + .patch("/share/"+id, { + prop:"password", + value:oldList[shareIndex].password === "" ? newPwd : "", }) .then(response => { - if (response.data.error !== 1) { - let oldList = this.state.shareList; - let shareIndex = oldList.findIndex(value => { - return value.share_key === id; - }); - oldList[shareIndex].type = - oldList[shareIndex].type === "public" - ? "private" - : "public"; - oldList[shareIndex].share_pwd = response.data.newPwd; - this.setState({ - shareList: oldList - }); - } + oldList[shareIndex].password = response.data; + this.setState({ + shareList: oldList + }); }) .catch(error => { - this.props.toggleSnackbar("top", "right", "请求失败", "error"); + this.props.toggleSnackbar("top", "right", error.message, "error"); }); }; - loadList = page => { - API.get("/share?page=" + this.state.page) + changePreviewOption = id => { + let oldList = this.state.shareList; + let shareIndex = oldList.findIndex(value => { + return value.key === id; + }); + API + .patch("/share/"+id, { + prop:"preview_enabled", + value:oldList[shareIndex].preview?"false":"true", + }) + .then(response => { + oldList[shareIndex].preview = response.data; + this.setState({ + shareList: oldList + }); + }) + .catch(error => { + this.props.toggleSnackbar("top", "right", error.message, "error"); + }); + }; + + loadList = (page,orderBy) => { + let order = orderBy.split(" "); + API.get("/share?page=" + page + "&order_by=" + order[0] + "&order=" + order[1]) .then(response => { if (response.data.items.length === 0) { this.props.toggleSnackbar( @@ -176,7 +206,7 @@ class MyShareCompoment extends Component { ); } this.setState({ - page: page, + total: response.data.total, shareList: response.data.items }); }) @@ -185,8 +215,22 @@ class MyShareCompoment extends Component { }); }; + handlePageChange = (event, value) => { + this.setState({ + page: value + }); + this.loadList(value,this.state.orderBy); + }; + + handleOrderChange = event => { + this.setState({ + orderBy:event.target.value, + }); + this.loadList(this.state.page,event.target.value); + }; + isExpired = share => { - return share.expire === 0 || share.remain_downloads === 0; + return share.expire < -1 || share.remain_downloads === 0; }; render() { @@ -194,10 +238,26 @@ class MyShareCompoment extends Component { return (
- - {" "} - 我的分享{" "} - {" "} + + + + + 我的分享 + + + + + + + + {this.state.shareList.map(value => ( {!value.is_dir && ( @@ -265,15 +324,18 @@ class MyShareCompoment extends Component { } /> - + - window.open("/s/" + value.key) + this.props.history.push("/s/"+value.key + (value.password === "" ?"":"?password=" + value.password)) } > @@ -299,23 +361,23 @@ class MyShareCompoment extends Component { title="查看密码" onClick={() => this.showPwd( - value.share_pwd + value.password ) } > - + - )}{" "} + )} {value.password === "" && ( this.changePermission( - value.share_key + value.key ) } > @@ -324,6 +386,27 @@ class MyShareCompoment extends Component { )} + + this.changePreviewOption( + value.key + ) + } + > + + {!value.preview ? ( + + ) : ( + + )} + +
- {" "} +
{" "} ({ + cardContainer: { + padding: theme.spacing(1) + }, + card: { + maxWidth: 400, + margin: "0 auto" + }, + actions: { + display: "flex" + }, + layout: { + width: "auto", + marginTop: "50px", + marginLeft: theme.spacing(3), + marginRight: theme.spacing(3), + [theme.breakpoints.up(1100 + theme.spacing(3) * 2)]: { + width: 1100, + marginLeft: "auto", + marginRight: "auto" + } + }, + shareTitle: { + maxWidth: "200px" + }, + avatarFile: { + backgroundColor: theme.palette.primary.light + }, + avatarFolder: { + backgroundColor: theme.palette.secondary.light + }, + gird: { + marginTop: "30px" + }, + loadMore: { + textAlign: "right", + marginTop: "20px", + marginBottom: "40px" + }, + badge: { + marginLeft: theme.spacing(1), + height: 17 + }, + orderSelect:{ + textAlign:"right", + marginTop: 5, + } +}); +const mapStateToProps = state => { + return {}; +}; + +const mapDispatchToProps = dispatch => { + return { + toggleSnackbar: (vertical, horizontal, msg, color) => { + dispatch(toggleSnackbar(vertical, horizontal, msg, color)); + } + }; +}; + +class SearchComponent extends Component { + state = { + page: 1, + total: 0, + shareList: [], + showPwd: null, + orderBy:"created_at DESC", + }; + + componentDidMount = () => { + this.loadList(1,this.state.orderBy); + }; + + showPwd = pwd => { + this.setState({ showPwd: pwd }); + }; + + handleClose = () => { + this.setState({ showPwd: null }); + }; + + removeShare = (id) => { + API + .delete("/share/"+id) + .then(response => { + let oldList = this.state.shareList; + oldList = oldList.filter(value => { + return value.key !== id; + }); + this.setState({ + shareList: oldList, + total:this.state.total-1, + }); + this.props.toggleSnackbar( + "top", + "right", + "分享已取消", + "success" + ); + if (oldList.length === 0){ + this.loadList(1,this.state.orderBy); + } + + }) + .catch(error => { + this.props.toggleSnackbar("top", "right", error.message, "error"); + }); + }; + + changePermission = id => { + let newPwd = Math.random() + .toString(36) + .substr(2) + .slice(2, 8); + let oldList = this.state.shareList; + let shareIndex = oldList.findIndex(value => { + return value.key === id; + }); + API + .patch("/share/"+id, { + prop:"password", + value:oldList[shareIndex].password === "" ? newPwd : "", + }) + .then(response => { + oldList[shareIndex].password = response.data; + this.setState({ + shareList: oldList + }); + }) + .catch(error => { + this.props.toggleSnackbar("top", "right", error.message, "error"); + }); + }; + + changePreviewOption = id => { + let oldList = this.state.shareList; + let shareIndex = oldList.findIndex(value => { + return value.key === id; + }); + API + .patch("/share/"+id, { + prop:"preview_enabled", + value:oldList[shareIndex].preview?"false":"true", + }) + .then(response => { + oldList[shareIndex].preview = response.data; + this.setState({ + shareList: oldList + }); + }) + .catch(error => { + this.props.toggleSnackbar("top", "right", error.message, "error"); + }); + }; + + loadList = (page,orderBy) => { + let order = orderBy.split(" "); + API.get("/share?page=" + page + "&order_by=" + order[0] + "&order=" + order[1]) + .then(response => { + if (response.data.items.length === 0) { + this.props.toggleSnackbar( + "top", + "right", + "没有更多了", + "info" + ); + } + this.setState({ + total: response.data.total, + shareList: response.data.items + }); + }) + .catch(error => { + this.props.toggleSnackbar("top", "right", "加载失败", "error"); + }); + }; + + handlePageChange = (event, value) => { + this.setState({ + page: value + }); + this.loadList(value,this.state.orderBy); + }; + + handleOrderChange = event => { + this.setState({ + orderBy:event.target.value, + }); + this.loadList(this.state.page,event.target.value); + }; + + isExpired = share => { + return share.expire === 0 || share.remain_downloads === 0; + }; + + render() { + const { classes } = this.props; + + return ( +
+ + + + + 搜索结果 + + + + + + + + + + {this.state.shareList.map(value => ( + + + + {!value.is_dir && ( + + )}{" "} + {value.is_dir && ( + + + + )} +
+ } + title={ + + + {value.source + ? value.source.name + : "[原始对象不存在]"}{" "} + + + } + subheader={ + + {value.create_date} + {this.isExpired(value) && ( + + )} + + } + /> +
+
+ ))} +
+
+ +
{" "} +
+ ); + } +} + +const SearchResult = connect( + mapStateToProps, + mapDispatchToProps +)(withStyles(styles)(withRouter(SearchComponent))); + +export default SearchResult; diff --git a/src/pages/myShare.app.js b/src/pages/myShare.app.js index e0106f0..d21c14a 100644 --- a/src/pages/myShare.app.js +++ b/src/pages/myShare.app.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import Navbar from "../component/Navbar/Navbar.js" import AlertBar from "../component/Snackbar" import { createMuiTheme } from '@material-ui/core/styles'; -import MyShare from '../component/MyShare' +import MyShare from '../component/Share/MyShare' import { CssBaseline, withStyles, MuiThemeProvider } from '@material-ui/core'; const theme = createMuiTheme(window.colorTheme); const styles = theme => ({ diff --git a/yarn.lock b/yarn.lock index 78870c9..de48ccd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1123,15 +1123,16 @@ dependencies: "@babel/runtime" "^7.4.4" -"@material-ui/lab@^4.0.0-alpha.33": - version "4.0.0-alpha.33" - resolved "https://registry.yarnpkg.com/@material-ui/lab/-/lab-4.0.0-alpha.33.tgz#3de96da1e813afcea5a07d56e54ec41cfa636e2c" - integrity sha512-+xttHUZLwH4+yfkB7B5A3pNDtQO27tGftuUxMRDMevNXwQtAB7mgYco34JwMr9kmvESYmacoZReOacJ6rxym/Q== +"@material-ui/lab@^4.0.0-alpha.42": + version "4.0.0-alpha.42" + resolved "https://registry.yarnpkg.com/@material-ui/lab/-/lab-4.0.0-alpha.42.tgz#f8789d3ba39a1e5a13f462d618c2eec53f87ae10" + integrity sha512-JbKEMIXSslh03u6HNU1Pp1VXd9ycJ1dqkI+iQK6yR+Sng2mvMKzJ80GCV5ROXAXwwNnD8zHOopLZNIpTsEAVgQ== dependencies: "@babel/runtime" "^7.4.4" - "@material-ui/utils" "^4.5.2" + "@material-ui/utils" "^4.7.1" clsx "^1.0.4" prop-types "^15.7.2" + react-is "^16.8.0" "@material-ui/styles@^4.9.0": version "4.9.0" @@ -1169,15 +1170,6 @@ resolved "https://registry.yarnpkg.com/@material-ui/types/-/types-5.0.0.tgz#26d6259dc6b39f4c2e1e9aceff7a11e031941741" integrity sha512-UeH2BuKkwDndtMSS0qgx1kCzSMw+ydtj0xx/XbFtxNSTlXydKwzs5gVW5ZKsFlAkwoOOQ9TIsyoCC8hq18tOwg== -"@material-ui/utils@^4.5.2": - version "4.5.2" - resolved "https://registry.yarnpkg.com/@material-ui/utils/-/utils-4.5.2.tgz#4c2fb531d357cf0da8cece53b588dff9b0bde934" - integrity sha512-zhbNfHd1gLa8At6RPDG7uMZubHxbY+LtM6IkSfeWi6Lo4Ax80l62YaN1QmUpO1IvGCkn/j62tQX3yObiQZrJsQ== - dependencies: - "@babel/runtime" "^7.4.4" - prop-types "^15.7.2" - react-is "^16.8.6" - "@material-ui/utils@^4.7.1": version "4.7.1" resolved "https://registry.yarnpkg.com/@material-ui/utils/-/utils-4.7.1.tgz#dc16c7f0d2cd02fbcdd5cfe601fd6863ae3cc652" @@ -8640,7 +8632,7 @@ react-hotkeys@^2.0.0: dependencies: prop-types "^15.6.1" -react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.0, react-is@^16.8.6, react-is@^16.9.0: +react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.0, react-is@^16.9.0: version "16.12.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c" integrity sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==