mirror of
https://github.com/cloudreve/frontend.git
synced 2025-12-26 04:02:47 +00:00
Style: format all codes with prettier
This commit is contained in:
parent
2cebcb3711
commit
397bf4569c
20
src/App.js
20
src/App.js
|
|
@ -30,7 +30,9 @@ import ResetForm from "./component/Login/ResetForm";
|
|||
import Reset from "./component/Login/Reset";
|
||||
import PageLoading from "./component/Placeholder/PageLoading";
|
||||
import CodeViewer from "./component/Viewer/Code";
|
||||
const PDFViewer = React.lazy(() => import(/* webpackChunkName: "pdf" */ "./component/Viewer/PDF"));
|
||||
const PDFViewer = React.lazy(() =>
|
||||
import(/* webpackChunkName: "pdf" */ "./component/Viewer/PDF")
|
||||
);
|
||||
|
||||
export default function App() {
|
||||
const themeConfig = useSelector(state => state.siteConfig.theme);
|
||||
|
|
@ -101,10 +103,7 @@ export default function App() {
|
|||
<FileManager />
|
||||
</AuthRoute>
|
||||
|
||||
<AuthRoute
|
||||
path={`${path}video`}
|
||||
isLogin={isLogin}
|
||||
>
|
||||
<AuthRoute path={`${path}video`} isLogin={isLogin}>
|
||||
<VideoPreview />
|
||||
</AuthRoute>
|
||||
|
||||
|
|
@ -117,7 +116,7 @@ export default function App() {
|
|||
</AuthRoute>
|
||||
|
||||
<AuthRoute path={`${path}pdf`} isLogin={isLogin}>
|
||||
<Suspense fallback={<PageLoading/>}>
|
||||
<Suspense fallback={<PageLoading />}>
|
||||
<PDFViewer />
|
||||
</Suspense>
|
||||
</AuthRoute>
|
||||
|
|
@ -137,11 +136,8 @@ export default function App() {
|
|||
<Route path={`${path}search`} isLogin={isLogin}>
|
||||
<SearchResult />
|
||||
</Route>
|
||||
|
||||
<Route
|
||||
path={`${path}setting`}
|
||||
isLogin={isLogin}
|
||||
>
|
||||
|
||||
<Route path={`${path}setting`} isLogin={isLogin}>
|
||||
<UserSetting />
|
||||
</Route>
|
||||
|
||||
|
|
@ -197,7 +193,7 @@ export default function App() {
|
|||
</Route>
|
||||
|
||||
<Route path={`${path}s/:id/pdf(/)*`}>
|
||||
<Suspense fallback={<PageLoading/>}>
|
||||
<Suspense fallback={<PageLoading />}>
|
||||
<PDFViewer />
|
||||
</Suspense>
|
||||
</Route>
|
||||
|
|
|
|||
|
|
@ -1,30 +1,30 @@
|
|||
export * from './explorer'
|
||||
export * from "./explorer";
|
||||
|
||||
export const setNavigator = (path, navigatorLoading) => {
|
||||
return {
|
||||
type: 'SET_NAVIGATOR',
|
||||
path,
|
||||
navigatorLoading
|
||||
}
|
||||
}
|
||||
return {
|
||||
type: "SET_NAVIGATOR",
|
||||
path,
|
||||
navigatorLoading
|
||||
};
|
||||
};
|
||||
|
||||
export const navigateTo = path => {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState()
|
||||
const navigatorLoading = path !== state.navigator.path
|
||||
dispatch(setNavigator(path, navigatorLoading))
|
||||
}
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const navigatorLoading = path !== state.navigator.path;
|
||||
dispatch(setNavigator(path, navigatorLoading));
|
||||
};
|
||||
};
|
||||
|
||||
export const navigateUp = () => {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState()
|
||||
const pathSplit = state.navigator.path.split("/");
|
||||
pathSplit.pop();
|
||||
const newPath = pathSplit.length===1? "/":pathSplit.join("/");
|
||||
const navigatorLoading = newPath !== state.navigator.path
|
||||
dispatch(setNavigator(newPath, navigatorLoading))
|
||||
}
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const pathSplit = state.navigator.path.split("/");
|
||||
pathSplit.pop();
|
||||
const newPath = pathSplit.length === 1 ? "/" : pathSplit.join("/");
|
||||
const navigatorLoading = newPath !== state.navigator.path;
|
||||
dispatch(setNavigator(newPath, navigatorLoading));
|
||||
};
|
||||
};
|
||||
|
||||
export const drawerToggleAction = open => {
|
||||
|
|
@ -34,11 +34,11 @@ export const drawerToggleAction = open => {
|
|||
};
|
||||
};
|
||||
|
||||
export const dragAndDrop = (source,target) => {
|
||||
export const dragAndDrop = (source, target) => {
|
||||
return {
|
||||
type: "DRAG_AND_DROP",
|
||||
source: source,
|
||||
target: target,
|
||||
target: target
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -49,9 +49,9 @@ export const changeViewMethod = method => {
|
|||
};
|
||||
};
|
||||
|
||||
export const toggleDaylightMode = ()=>{
|
||||
export const toggleDaylightMode = () => {
|
||||
return {
|
||||
type: "TOGGLE_DAYLIGHT_MODE",
|
||||
type: "TOGGLE_DAYLIGHT_MODE"
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -110,10 +110,10 @@ export const openRenameDialog = () => {
|
|||
};
|
||||
};
|
||||
|
||||
export const openResaveDialog = (key) => {
|
||||
export const openResaveDialog = key => {
|
||||
return {
|
||||
type: "OPEN_RESAVE_DIALOG",
|
||||
key:key,
|
||||
key: key
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -135,21 +135,20 @@ export const openShareDialog = () => {
|
|||
};
|
||||
};
|
||||
|
||||
export const applyThemes = (theme)=>{
|
||||
export const applyThemes = theme => {
|
||||
return {
|
||||
type:'APPLY_THEME',
|
||||
theme:theme,
|
||||
type: "APPLY_THEME",
|
||||
theme: theme
|
||||
};
|
||||
};
|
||||
|
||||
export const setSessionStatus = (status)=>{
|
||||
export const setSessionStatus = status => {
|
||||
return {
|
||||
type:'SET_SESSION_STATUS',
|
||||
status:status,
|
||||
type: "SET_SESSION_STATUS",
|
||||
status: status
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
export const openMusicDialog = () => {
|
||||
return {
|
||||
type: "OPEN_MUSIC_DIALOG"
|
||||
|
|
@ -192,11 +191,11 @@ export const openCopyDialog = () => {
|
|||
};
|
||||
};
|
||||
|
||||
export const openLoadingDialog = (text) => {
|
||||
export const openLoadingDialog = text => {
|
||||
return {
|
||||
type: "OPEN_LOADING_DIALOG",
|
||||
text: text,
|
||||
}
|
||||
text: text
|
||||
};
|
||||
};
|
||||
|
||||
export const closeAllModals = () => {
|
||||
|
|
@ -265,4 +264,4 @@ export const setSiteConfig = config => {
|
|||
type: "SET_SITE_CONFIG",
|
||||
config: config
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,23 +8,34 @@ import React, { useCallback, useState } from "react";
|
|||
import { useDispatch } from "react-redux";
|
||||
import { toggleSnackbar } from "../../../actions";
|
||||
|
||||
const unitTransform = (v)=>{
|
||||
if(v<1024){
|
||||
return [Math.round(v),1]
|
||||
const unitTransform = v => {
|
||||
if (v < 1024) {
|
||||
return [Math.round(v), 1];
|
||||
}
|
||||
if(v<1024*1024){
|
||||
return [Math.round(v/1024),1024]
|
||||
if (v < 1024 * 1024) {
|
||||
return [Math.round(v / 1024), 1024];
|
||||
}
|
||||
if(v<1024*1024*1024){
|
||||
return [Math.round(v/(1024*1024)),1024*1024]
|
||||
if (v < 1024 * 1024 * 1024) {
|
||||
return [Math.round(v / (1024 * 1024)), 1024 * 1024];
|
||||
}
|
||||
if(v<1024*1024*1024*1024){
|
||||
return [Math.round(v/(1024*1024*1024)),1024*1024*1024]
|
||||
if (v < 1024 * 1024 * 1024 * 1024) {
|
||||
return [Math.round(v / (1024 * 1024 * 1024)), 1024 * 1024 * 1024];
|
||||
}
|
||||
return [Math.round(v/(1024*1024*1024*1024)),1024*1024*1024*1024]
|
||||
}
|
||||
return [
|
||||
Math.round(v / (1024 * 1024 * 1024 * 1024)),
|
||||
1024 * 1024 * 1024 * 1024
|
||||
];
|
||||
};
|
||||
|
||||
export default function SizeInput({onChange,min,value,required,label,max,suffix}){
|
||||
export default function SizeInput({
|
||||
onChange,
|
||||
min,
|
||||
value,
|
||||
required,
|
||||
label,
|
||||
max,
|
||||
suffix
|
||||
}) {
|
||||
const dispatch = useDispatch();
|
||||
const ToggleSnackbar = useCallback(
|
||||
(vertical, horizontal, msg, color) =>
|
||||
|
|
@ -32,67 +43,86 @@ export default function SizeInput({onChange,min,value,required,label,max,suffix}
|
|||
[dispatch]
|
||||
);
|
||||
|
||||
|
||||
const [unit,setUnit] = useState(1);
|
||||
const [unit, setUnit] = useState(1);
|
||||
let first = true;
|
||||
|
||||
const transform = useCallback(()=>{
|
||||
const transform = useCallback(() => {
|
||||
const res = unitTransform(value);
|
||||
if(first && value !== 0){
|
||||
if (first && value !== 0) {
|
||||
setUnit(res[1]);
|
||||
first = false;
|
||||
}
|
||||
return res;
|
||||
},[value]);
|
||||
}, [value]);
|
||||
|
||||
return (
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
{label}
|
||||
</InputLabel>
|
||||
<InputLabel htmlFor="component-helper">{label}</InputLabel>
|
||||
<Input
|
||||
style={{width:200,}}
|
||||
style={{ width: 200 }}
|
||||
value={transform()[0]}
|
||||
type={"number"}
|
||||
inputProps={{min:min,step:1}}
|
||||
onChange={e=>{
|
||||
if (e.target.value * unit < max){
|
||||
inputProps={{ min: min, step: 1 }}
|
||||
onChange={e => {
|
||||
if (e.target.value * unit < max) {
|
||||
onChange({
|
||||
target:{value:(e.target.value * unit).toString()}
|
||||
})
|
||||
}else{
|
||||
ToggleSnackbar("top", "right", "超出最大尺寸限制", "warning");
|
||||
target: {
|
||||
value: (e.target.value * unit).toString()
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"超出最大尺寸限制",
|
||||
"warning"
|
||||
);
|
||||
}
|
||||
|
||||
}}
|
||||
required = {required}
|
||||
required={required}
|
||||
endAdornment={
|
||||
<InputAdornment position="end">
|
||||
<Select
|
||||
labelId="demo-simple-select-label"
|
||||
id="demo-simple-select"
|
||||
value={unit}
|
||||
onChange={(e)=>{
|
||||
if (transform()[0] * e.target.value < max){
|
||||
onChange={e => {
|
||||
if (transform()[0] * e.target.value < max) {
|
||||
onChange({
|
||||
target:{value:(transform()[0] * e.target.value).toString()}
|
||||
})
|
||||
target: {
|
||||
value: (
|
||||
transform()[0] * e.target.value
|
||||
).toString()
|
||||
}
|
||||
});
|
||||
setUnit(e.target.value);
|
||||
}else{
|
||||
ToggleSnackbar("top", "right", "超出最大尺寸限制", "warning");
|
||||
} else {
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"超出最大尺寸限制",
|
||||
"warning"
|
||||
);
|
||||
}
|
||||
|
||||
}}
|
||||
>
|
||||
<MenuItem value={1}>B{suffix && suffix}</MenuItem>
|
||||
<MenuItem value={1024}>KB{suffix && suffix}</MenuItem>
|
||||
<MenuItem value={1024*1024}>MB{suffix && suffix}</MenuItem>
|
||||
<MenuItem value={1024*1024*1024}>GB{suffix && suffix}</MenuItem>
|
||||
<MenuItem value={1024*1024*1024*1024}>TB{suffix && suffix}</MenuItem>
|
||||
<MenuItem value={1024}>
|
||||
KB{suffix && suffix}
|
||||
</MenuItem>
|
||||
<MenuItem value={1024 * 1024}>
|
||||
MB{suffix && suffix}
|
||||
</MenuItem>
|
||||
<MenuItem value={1024 * 1024 * 1024}>
|
||||
GB{suffix && suffix}
|
||||
</MenuItem>
|
||||
<MenuItem value={1024 * 1024 * 1024 * 1024}>
|
||||
TB{suffix && suffix}
|
||||
</MenuItem>
|
||||
</Select>
|
||||
</InputAdornment>
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,24 @@ import ListItemText from "@material-ui/core/ListItemText";
|
|||
import { lighten, makeStyles, useTheme } from "@material-ui/core/styles";
|
||||
import Toolbar from "@material-ui/core/Toolbar";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import { Assignment, CloudDownload, Contacts, Group, Home, Image, InsertDriveFile, Language, ListAlt, Mail, Palette, Person, Settings, SettingsEthernet, Share, Storage } from "@material-ui/icons";
|
||||
import {
|
||||
Assignment,
|
||||
CloudDownload,
|
||||
Contacts,
|
||||
Group,
|
||||
Home,
|
||||
Image,
|
||||
InsertDriveFile,
|
||||
Language,
|
||||
ListAlt,
|
||||
Mail,
|
||||
Palette,
|
||||
Person,
|
||||
Settings,
|
||||
SettingsEthernet,
|
||||
Share,
|
||||
Storage
|
||||
} from "@material-ui/icons";
|
||||
import ChevronLeftIcon from "@material-ui/icons/ChevronLeft";
|
||||
import ChevronRightIcon from "@material-ui/icons/ChevronRight";
|
||||
import MenuIcon from "@material-ui/icons/Menu";
|
||||
|
|
@ -139,21 +156,21 @@ const useStyles = makeStyles(theme => ({
|
|||
},
|
||||
subMenu: {
|
||||
backgroundColor: theme.palette.background.default,
|
||||
paddingTop:0,
|
||||
paddingBottom:0,
|
||||
paddingTop: 0,
|
||||
paddingBottom: 0
|
||||
},
|
||||
active: {
|
||||
backgroundColor: lighten(theme.palette.primary.main, 0.8),
|
||||
color: theme.palette.primary.main,
|
||||
"&:hover":{
|
||||
backgroundColor: lighten(theme.palette.primary.main, 0.7),
|
||||
},
|
||||
"&:hover": {
|
||||
backgroundColor: lighten(theme.palette.primary.main, 0.7)
|
||||
}
|
||||
},
|
||||
activeText:{
|
||||
fontWeight: 500,
|
||||
activeText: {
|
||||
fontWeight: 500
|
||||
},
|
||||
activeIcon:{
|
||||
color: theme.palette.primary.main,
|
||||
activeIcon: {
|
||||
color: theme.palette.primary.main
|
||||
}
|
||||
}));
|
||||
|
||||
|
|
@ -201,7 +218,7 @@ const items = [
|
|||
title: "图像处理",
|
||||
path: "image",
|
||||
icon: <Image />
|
||||
},
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -242,9 +259,9 @@ const items = [
|
|||
title: "常规任务",
|
||||
path: "task",
|
||||
icon: <ListAlt />
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
export default function Dashboard({ content }) {
|
||||
|
|
@ -339,19 +356,29 @@ export default function Dashboard({ content }) {
|
|||
}
|
||||
button
|
||||
className={clsx({
|
||||
[classes.active]:
|
||||
location.pathname.startsWith("/admin/" + item.path)
|
||||
[classes.active]: location.pathname.startsWith(
|
||||
"/admin/" + item.path
|
||||
)
|
||||
})}
|
||||
key={item.title}
|
||||
>
|
||||
<ListItemIcon className={clsx({
|
||||
[classes.activeIcon]:
|
||||
location.pathname.startsWith("/admin/" + item.path)
|
||||
})}>{item.icon}</ListItemIcon>
|
||||
<ListItemText className={clsx({
|
||||
[classes.activeText]:
|
||||
location.pathname.startsWith("/admin/" + item.path)
|
||||
})} primary={item.title} />
|
||||
<ListItemIcon
|
||||
className={clsx({
|
||||
[classes.activeIcon]: location.pathname.startsWith(
|
||||
"/admin/" + item.path
|
||||
)
|
||||
})}
|
||||
>
|
||||
{item.icon}
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
className={clsx({
|
||||
[classes.activeText]: location.pathname.startsWith(
|
||||
"/admin/" + item.path
|
||||
)
|
||||
})}
|
||||
primary={item.title}
|
||||
/>
|
||||
</ListItem>
|
||||
);
|
||||
}
|
||||
|
|
@ -384,16 +411,20 @@ export default function Dashboard({ content }) {
|
|||
}
|
||||
className={clsx({
|
||||
[classes.sub]: open,
|
||||
[classes.active]:
|
||||
location.pathname.startsWith("/admin/" + sub.path)
|
||||
[classes.active]: location.pathname.startsWith(
|
||||
"/admin/" + sub.path
|
||||
)
|
||||
})}
|
||||
button
|
||||
key={sub.title}
|
||||
>
|
||||
<ListItemIcon className={clsx({
|
||||
[classes.activeIcon]:
|
||||
location.pathname.startsWith("/admin/" + sub.path)
|
||||
})}>
|
||||
<ListItemIcon
|
||||
className={clsx({
|
||||
[classes.activeIcon]: location.pathname.startsWith(
|
||||
"/admin/" + sub.path
|
||||
)
|
||||
})}
|
||||
>
|
||||
{sub.icon}
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
|
|
|
|||
|
|
@ -63,11 +63,11 @@ export default function AddGroup({ open, onClose, onSubmit }) {
|
|||
|
||||
const submit = e => {
|
||||
e.preventDefault();
|
||||
const groupCopy = {...group};
|
||||
const groupCopy = { ...group };
|
||||
groupCopy.time = parseInt(groupCopy.time) * 86400;
|
||||
groupCopy.price = parseInt(groupCopy.price) * 100;
|
||||
groupCopy.score = parseInt(groupCopy.score);
|
||||
groupCopy.id = (new Date()).valueOf();
|
||||
groupCopy.id = new Date().valueOf();
|
||||
groupCopy.des = groupCopy.des.split("\n");
|
||||
onSubmit(groupCopy);
|
||||
};
|
||||
|
|
@ -218,7 +218,9 @@ export default function AddGroup({ open, onClose, onSubmit }) {
|
|||
control={
|
||||
<Switch
|
||||
checked={group.highlight}
|
||||
onChange={handleCheckChange("highlight")}
|
||||
onChange={handleCheckChange(
|
||||
"highlight"
|
||||
)}
|
||||
/>
|
||||
}
|
||||
label="突出展示"
|
||||
|
|
|
|||
|
|
@ -10,16 +10,15 @@ import Input from "@material-ui/core/Input";
|
|||
import FormHelperText from "@material-ui/core/FormHelperText";
|
||||
import FormControl from "@material-ui/core/FormControl";
|
||||
import SizeInput from "../Common/SizeInput";
|
||||
import {makeStyles} from "@material-ui/core/styles";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
|
||||
formContainer: {
|
||||
margin:"8px 0 8px 0",
|
||||
margin: "8px 0 8px 0"
|
||||
}
|
||||
}));
|
||||
|
||||
export default function AddPack({ open, onClose,onSubmit }) {
|
||||
export default function AddPack({ open, onClose, onSubmit }) {
|
||||
const classes = useStyles();
|
||||
const [pack, setPack] = useState({
|
||||
name: "",
|
||||
|
|
@ -38,14 +37,14 @@ export default function AddPack({ open, onClose,onSubmit }) {
|
|||
|
||||
const submit = e => {
|
||||
e.preventDefault();
|
||||
const packCopy = {...pack};
|
||||
const packCopy = { ...pack };
|
||||
packCopy.size = parseInt(packCopy.size);
|
||||
packCopy.time = parseInt(packCopy.time) * 86400;
|
||||
packCopy.price = parseInt(packCopy.price) * 100;
|
||||
packCopy.score = parseInt(packCopy.score);
|
||||
packCopy.id = (new Date()).valueOf();
|
||||
packCopy.id = new Date().valueOf();
|
||||
onSubmit(packCopy);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
|
|
@ -99,8 +98,8 @@ export default function AddPack({ open, onClose,onSubmit }) {
|
|||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min:1,
|
||||
step:1
|
||||
min: 1,
|
||||
step: 1
|
||||
}}
|
||||
value={pack.time}
|
||||
onChange={handleChange("time")}
|
||||
|
|
@ -120,8 +119,8 @@ export default function AddPack({ open, onClose,onSubmit }) {
|
|||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min:0.01,
|
||||
step:0.01
|
||||
min: 0.01,
|
||||
step: 0.01
|
||||
}}
|
||||
value={pack.price}
|
||||
onChange={handleChange("price")}
|
||||
|
|
@ -141,19 +140,19 @@ export default function AddPack({ open, onClose,onSubmit }) {
|
|||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min:0,
|
||||
step:1
|
||||
min: 0,
|
||||
step: 1
|
||||
}}
|
||||
value={pack.score}
|
||||
onChange={handleChange("score")}
|
||||
required
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
使用积分购买时的价格,填写为 0 表示不能使用积分购买
|
||||
使用积分购买时的价格,填写为 0
|
||||
表示不能使用积分购买
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
|
|
|
|||
|
|
@ -17,20 +17,19 @@ import { toggleSnackbar } from "../../../actions";
|
|||
import API from "../../../middleware/Api";
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
|
||||
formContainer: {
|
||||
margin:"8px 0 8px 0",
|
||||
margin: "8px 0 8px 0"
|
||||
}
|
||||
}));
|
||||
|
||||
export default function AddRedeem({ open, onClose,products ,onSuccess}) {
|
||||
export default function AddRedeem({ open, onClose, products, onSuccess }) {
|
||||
const classes = useStyles();
|
||||
const [input, setInput] = useState({
|
||||
num:1,
|
||||
id:0,
|
||||
time:1,
|
||||
num: 1,
|
||||
id: 0,
|
||||
time: 1
|
||||
});
|
||||
const [loading,setLoading] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const ToggleSnackbar = useCallback(
|
||||
|
|
@ -52,13 +51,13 @@ export default function AddRedeem({ open, onClose,products ,onSuccess}) {
|
|||
input.num = parseInt(input.num);
|
||||
input.id = parseInt(input.id);
|
||||
input.time = parseInt(input.time);
|
||||
input.type=2;
|
||||
for (let i=0;i<products.length;i++){
|
||||
if (products[i].id === input.id){
|
||||
if(products[i].group_id !== undefined){
|
||||
input.type = 1
|
||||
}else{
|
||||
input.type = 0
|
||||
input.type = 2;
|
||||
for (let i = 0; i < products.length; i++) {
|
||||
if (products[i].id === input.id) {
|
||||
if (products[i].group_id !== undefined) {
|
||||
input.type = 1;
|
||||
} else {
|
||||
input.type = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -71,10 +70,10 @@ export default function AddRedeem({ open, onClose,products ,onSuccess}) {
|
|||
})
|
||||
.catch(error => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
}).then(()=>{
|
||||
})
|
||||
.then(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
@ -97,9 +96,9 @@ export default function AddRedeem({ open, onClose,products ,onSuccess}) {
|
|||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
step:1,
|
||||
min:1,
|
||||
max:100,
|
||||
step: 1,
|
||||
min: 1,
|
||||
max: 100
|
||||
}}
|
||||
value={input.num}
|
||||
onChange={handleChange("num")}
|
||||
|
|
@ -118,12 +117,18 @@ export default function AddRedeem({ open, onClose,products ,onSuccess}) {
|
|||
</InputLabel>
|
||||
<Select
|
||||
value={input.id}
|
||||
onChange={e=>{
|
||||
handleChange("id")(e)
|
||||
onChange={e => {
|
||||
handleChange("id")(e);
|
||||
}}
|
||||
>
|
||||
{products.map(v=>(
|
||||
<MenuItem key={v.id} value={v.id} data-type={"1"}>{v.name}</MenuItem>
|
||||
{products.map(v => (
|
||||
<MenuItem
|
||||
key={v.id}
|
||||
value={v.id}
|
||||
data-type={"1"}
|
||||
>
|
||||
{v.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
<MenuItem value={0}>积分</MenuItem>
|
||||
</Select>
|
||||
|
|
@ -138,8 +143,8 @@ export default function AddRedeem({ open, onClose,products ,onSuccess}) {
|
|||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
step:1,
|
||||
min:1,
|
||||
step: 1,
|
||||
min: 1
|
||||
}}
|
||||
value={input.time}
|
||||
onChange={handleChange("time")}
|
||||
|
|
@ -150,12 +155,14 @@ export default function AddRedeem({ open, onClose,products ,onSuccess}) {
|
|||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button disabled={loading} onClick={onClose} color="default">
|
||||
<Button
|
||||
disabled={loading}
|
||||
onClick={onClose}
|
||||
color="default"
|
||||
>
|
||||
取消
|
||||
</Button>
|
||||
<Button disabled={loading} type={"submit"} color="primary">
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import DialogActions from "@material-ui/core/DialogActions";
|
|||
import Button from "@material-ui/core/Button";
|
||||
import Dialog from "@material-ui/core/Dialog";
|
||||
|
||||
export default function AlertDialog({title, msg, open, onClose }) {
|
||||
export default function AlertDialog({ title, msg, open, onClose }) {
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
|
|
@ -15,14 +15,10 @@ export default function AlertDialog({title, msg, open, onClose }) {
|
|||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">
|
||||
{title}
|
||||
</DialogTitle>
|
||||
<DialogTitle id="alert-dialog-title">{title}</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText id="alert-dialog-description">
|
||||
<Typography>
|
||||
{msg}
|
||||
</Typography>
|
||||
<Typography>{msg}</Typography>
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ const useStyles = makeStyles(theme => ({
|
|||
}
|
||||
}));
|
||||
|
||||
export default function CreateTheme({ open, onClose,onSubmit }) {
|
||||
export default function CreateTheme({ open, onClose, onSubmit }) {
|
||||
const classes = useStyles();
|
||||
const [theme, setTheme] = useState({
|
||||
palette: {
|
||||
|
|
@ -121,7 +121,7 @@ export default function CreateTheme({ open, onClose,onSubmit }) {
|
|||
"#9c27b0"
|
||||
]}
|
||||
color={theme.palette.primary.main}
|
||||
onChangeComplete={(c) => {
|
||||
onChangeComplete={c => {
|
||||
setTheme({
|
||||
...theme,
|
||||
palette: {
|
||||
|
|
@ -197,7 +197,7 @@ export default function CreateTheme({ open, onClose,onSubmit }) {
|
|||
"#d500f9"
|
||||
]}
|
||||
color={theme.palette.secondary.main}
|
||||
onChangeComplete={(c) => {
|
||||
onChangeComplete={c => {
|
||||
setTheme({
|
||||
...theme,
|
||||
palette: {
|
||||
|
|
@ -235,7 +235,7 @@ export default function CreateTheme({ open, onClose,onSubmit }) {
|
|||
<div className={classes.picker}>
|
||||
<CompactPicker
|
||||
color={theme.palette.primary.contrastText}
|
||||
onChangeComplete={(c) => {
|
||||
onChangeComplete={c => {
|
||||
setTheme({
|
||||
...theme,
|
||||
palette: {
|
||||
|
|
@ -273,7 +273,7 @@ export default function CreateTheme({ open, onClose,onSubmit }) {
|
|||
<div className={classes.picker}>
|
||||
<CompactPicker
|
||||
color={theme.palette.secondary.contrastText}
|
||||
onChangeComplete={(c) => {
|
||||
onChangeComplete={c => {
|
||||
setTheme({
|
||||
...theme,
|
||||
palette: {
|
||||
|
|
@ -339,7 +339,7 @@ export default function CreateTheme({ open, onClose,onSubmit }) {
|
|||
<Button onClick={onClose} color="default">
|
||||
取消
|
||||
</Button>
|
||||
<Button onClick={()=>onSubmit(theme)} color="primary">
|
||||
<Button onClick={() => onSubmit(theme)} color="primary">
|
||||
创建
|
||||
</Button>
|
||||
</DialogActions>
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@ import { useDispatch } from "react-redux";
|
|||
import { toggleSnackbar } from "../../../actions";
|
||||
import API from "../../../middleware/Api";
|
||||
|
||||
export default function FileFilter({setFilter,setSearch,open, onClose }) {
|
||||
const [input,setInput] = useState({
|
||||
policy_id:"all",
|
||||
user_id:"",
|
||||
export default function FileFilter({ setFilter, setSearch, open, onClose }) {
|
||||
const [input, setInput] = useState({
|
||||
policy_id: "all",
|
||||
user_id: ""
|
||||
});
|
||||
const [policies,setPolicies] = useState([]);
|
||||
const [keywords,setKeywords] = useState("");
|
||||
const [policies, setPolicies] = useState([]);
|
||||
const [keywords, setKeywords] = useState("");
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const ToggleSnackbar = useCallback(
|
||||
|
|
@ -29,10 +29,10 @@ export default function FileFilter({setFilter,setSearch,open, onClose }) {
|
|||
);
|
||||
|
||||
const handleChange = name => event => {
|
||||
setInput({...input,[name]:event.target.value})
|
||||
}
|
||||
setInput({ ...input, [name]: event.target.value });
|
||||
};
|
||||
|
||||
useEffect(()=>{
|
||||
useEffect(() => {
|
||||
API.post("/admin/policy/list", {
|
||||
page: 1,
|
||||
page_size: 10000,
|
||||
|
|
@ -45,25 +45,25 @@ export default function FileFilter({setFilter,setSearch,open, onClose }) {
|
|||
.catch(error => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
});
|
||||
},[])
|
||||
}, []);
|
||||
|
||||
const submit = () => {
|
||||
const res = {};
|
||||
Object.keys(input).forEach(v=>{
|
||||
if(input[v] !== "all" && input[v] !== ""){
|
||||
Object.keys(input).forEach(v => {
|
||||
if (input[v] !== "all" && input[v] !== "") {
|
||||
res[v] = input[v];
|
||||
}
|
||||
})
|
||||
});
|
||||
setFilter(res);
|
||||
if (keywords !== ""){
|
||||
if (keywords !== "") {
|
||||
setSearch({
|
||||
name:keywords,
|
||||
name: keywords
|
||||
});
|
||||
}else{
|
||||
} else {
|
||||
setSearch({});
|
||||
}
|
||||
onClose();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
|
|
@ -74,12 +74,12 @@ export default function FileFilter({setFilter,setSearch,open, onClose }) {
|
|||
fullWidth
|
||||
maxWidth={"xs"}
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">
|
||||
过滤条件
|
||||
</DialogTitle>
|
||||
<DialogTitle id="alert-dialog-title">过滤条件</DialogTitle>
|
||||
<DialogContent>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel id="demo-simple-select-label">存储策略</InputLabel>
|
||||
<InputLabel id="demo-simple-select-label">
|
||||
存储策略
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId="demo-simple-select-label"
|
||||
id="demo-simple-select"
|
||||
|
|
@ -92,21 +92,28 @@ export default function FileFilter({setFilter,setSearch,open, onClose }) {
|
|||
return null;
|
||||
}
|
||||
return (
|
||||
<MenuItem
|
||||
key={v.ID}
|
||||
value={v.ID.toString()}
|
||||
>
|
||||
<MenuItem key={v.ID} value={v.ID.toString()}>
|
||||
{v.Name}
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl fullWidth style={{marginTop:16}}>
|
||||
<TextField value={input.user_id} onChange={handleChange("user_id")} id="standard-basic" label="上传者ID" />
|
||||
<FormControl fullWidth style={{ marginTop: 16 }}>
|
||||
<TextField
|
||||
value={input.user_id}
|
||||
onChange={handleChange("user_id")}
|
||||
id="standard-basic"
|
||||
label="上传者ID"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl fullWidth style={{marginTop:16}}>
|
||||
<TextField value={keywords} onChange={e=>setKeywords(e.target.value)} id="standard-basic" label="搜索 文件名" />
|
||||
<FormControl fullWidth style={{ marginTop: 16 }}>
|
||||
<TextField
|
||||
value={keywords}
|
||||
onChange={e => setKeywords(e.target.value)}
|
||||
id="standard-basic"
|
||||
label="搜索 文件名"
|
||||
/>
|
||||
</FormControl>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import TableHead from "@material-ui/core/TableHead";
|
|||
import TableRow from "@material-ui/core/TableRow";
|
||||
import React from "react";
|
||||
|
||||
export default function MagicVar({isFile, open, onClose, isSlave }) {
|
||||
export default function MagicVar({ isFile, open, onClose, isSlave }) {
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
|
|
@ -20,7 +20,7 @@ export default function MagicVar({isFile, open, onClose, isSlave }) {
|
|||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">
|
||||
{isFile?"文件名魔法变量":"路径魔法变量"}
|
||||
{isFile ? "文件名魔法变量" : "路径魔法变量"}
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<TableContainer>
|
||||
|
|
@ -34,77 +34,113 @@ export default function MagicVar({isFile, open, onClose, isSlave }) {
|
|||
</TableHead>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell component="th" scope="row">{"{randomkey16}"}</TableCell>
|
||||
<TableCell component="th" scope="row">
|
||||
{"{randomkey16}"}
|
||||
</TableCell>
|
||||
<TableCell>16位随机字符</TableCell>
|
||||
<TableCell>N6IimT5XZP324ACK</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell component="th" scope="row">{"{randomkey8}"}</TableCell>
|
||||
<TableCell component="th" scope="row">
|
||||
{"{randomkey8}"}
|
||||
</TableCell>
|
||||
<TableCell>8位随机字符</TableCell>
|
||||
<TableCell>gWz78q30</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell component="th" scope="row">{"{timestamp}"}</TableCell>
|
||||
<TableCell component="th" scope="row">
|
||||
{"{timestamp}"}
|
||||
</TableCell>
|
||||
<TableCell>秒级时间戳</TableCell>
|
||||
<TableCell>1582692933</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell component="th" scope="row">{"{timestamp_nano}"}</TableCell>
|
||||
<TableCell component="th" scope="row">
|
||||
{"{timestamp_nano}"}
|
||||
</TableCell>
|
||||
<TableCell>纳秒级时间戳</TableCell>
|
||||
<TableCell>1582692933231834600</TableCell>
|
||||
</TableRow>
|
||||
{!isSlave && <TableRow>
|
||||
<TableCell component="th" scope="row">{"{uid}"}</TableCell>
|
||||
<TableCell>用户ID</TableCell>
|
||||
<TableCell>1</TableCell>
|
||||
</TableRow>}
|
||||
{isFile && <TableRow>
|
||||
<TableCell component="th" scope="row">{"{originname}"}</TableCell>
|
||||
<TableCell>原始文件名</TableCell>
|
||||
<TableCell>MyPico.mp4</TableCell>
|
||||
</TableRow>}
|
||||
{!isFile && !isSlave && <TableRow>
|
||||
<TableCell component="th" scope="row">{"{path}"}</TableCell>
|
||||
<TableCell>用户上传路径</TableCell>
|
||||
<TableCell>/我的文件/学习资料/</TableCell>
|
||||
</TableRow>}
|
||||
{!isSlave && (
|
||||
<TableRow>
|
||||
<TableCell component="th" scope="row">
|
||||
{"{uid}"}
|
||||
</TableCell>
|
||||
<TableCell>用户ID</TableCell>
|
||||
<TableCell>1</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
{isFile && (
|
||||
<TableRow>
|
||||
<TableCell component="th" scope="row">
|
||||
{"{originname}"}
|
||||
</TableCell>
|
||||
<TableCell>原始文件名</TableCell>
|
||||
<TableCell>MyPico.mp4</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
{!isFile && !isSlave && (
|
||||
<TableRow>
|
||||
<TableCell component="th" scope="row">
|
||||
{"{path}"}
|
||||
</TableCell>
|
||||
<TableCell>用户上传路径</TableCell>
|
||||
<TableCell>/我的文件/学习资料/</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
<TableRow>
|
||||
<TableCell component="th" scope="row">{"{date}"}</TableCell>
|
||||
<TableCell component="th" scope="row">
|
||||
{"{date}"}
|
||||
</TableCell>
|
||||
<TableCell>日期</TableCell>
|
||||
<TableCell>20060102</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell component="th" scope="row">{"{datetime}"}</TableCell>
|
||||
<TableCell component="th" scope="row">
|
||||
{"{datetime}"}
|
||||
</TableCell>
|
||||
<TableCell>日期时间</TableCell>
|
||||
<TableCell>20060102150405</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell component="th" scope="row">{"{year}"}</TableCell>
|
||||
<TableCell component="th" scope="row">
|
||||
{"{year}"}
|
||||
</TableCell>
|
||||
<TableCell>年份</TableCell>
|
||||
<TableCell>2006</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell component="th" scope="row">{"{month}"}</TableCell>
|
||||
<TableCell component="th" scope="row">
|
||||
{"{month}"}
|
||||
</TableCell>
|
||||
<TableCell>月份</TableCell>
|
||||
<TableCell>01</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell component="th" scope="row">{"{day}"}</TableCell>
|
||||
<TableCell component="th" scope="row">
|
||||
{"{day}"}
|
||||
</TableCell>
|
||||
<TableCell>日</TableCell>
|
||||
<TableCell>02</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell component="th" scope="row">{"{hour}"}</TableCell>
|
||||
<TableCell component="th" scope="row">
|
||||
{"{hour}"}
|
||||
</TableCell>
|
||||
<TableCell>小时</TableCell>
|
||||
<TableCell>15</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell component="th" scope="row">{"{minute}"}</TableCell>
|
||||
<TableCell component="th" scope="row">
|
||||
{"{minute}"}
|
||||
</TableCell>
|
||||
<TableCell>分钟</TableCell>
|
||||
<TableCell>04</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell component="th" scope="row">{"{second}"}</TableCell>
|
||||
<TableCell component="th" scope="row">
|
||||
{"{second}"}
|
||||
</TableCell>
|
||||
<TableCell>秒</TableCell>
|
||||
<TableCell>05</TableCell>
|
||||
</TableRow>
|
||||
|
|
|
|||
|
|
@ -10,34 +10,34 @@ import Select from "@material-ui/core/Select";
|
|||
import TextField from "@material-ui/core/TextField";
|
||||
import React, { useState } from "react";
|
||||
|
||||
export default function ShareFilter({setFilter,setSearch,open, onClose }) {
|
||||
const [input,setInput] = useState({
|
||||
is_dir:"all",
|
||||
user_id:"",
|
||||
export default function ShareFilter({ setFilter, setSearch, open, onClose }) {
|
||||
const [input, setInput] = useState({
|
||||
is_dir: "all",
|
||||
user_id: ""
|
||||
});
|
||||
const [keywords,setKeywords] = useState("");
|
||||
const [keywords, setKeywords] = useState("");
|
||||
|
||||
const handleChange = name => event => {
|
||||
setInput({...input,[name]:event.target.value})
|
||||
}
|
||||
setInput({ ...input, [name]: event.target.value });
|
||||
};
|
||||
|
||||
const submit = () => {
|
||||
const res = {};
|
||||
Object.keys(input).forEach(v=>{
|
||||
if(input[v] !== "all" && input[v] !== ""){
|
||||
Object.keys(input).forEach(v => {
|
||||
if (input[v] !== "all" && input[v] !== "") {
|
||||
res[v] = input[v];
|
||||
}
|
||||
})
|
||||
});
|
||||
setFilter(res);
|
||||
if (keywords !== ""){
|
||||
if (keywords !== "") {
|
||||
setSearch({
|
||||
source_name:keywords,
|
||||
source_name: keywords
|
||||
});
|
||||
}else{
|
||||
} else {
|
||||
setSearch({});
|
||||
}
|
||||
onClose();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
|
|
@ -48,12 +48,12 @@ export default function ShareFilter({setFilter,setSearch,open, onClose }) {
|
|||
fullWidth
|
||||
maxWidth={"xs"}
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">
|
||||
过滤条件
|
||||
</DialogTitle>
|
||||
<DialogTitle id="alert-dialog-title">过滤条件</DialogTitle>
|
||||
<DialogContent>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel id="demo-simple-select-label">源文件类型</InputLabel>
|
||||
<InputLabel id="demo-simple-select-label">
|
||||
源文件类型
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId="demo-simple-select-label"
|
||||
id="demo-simple-select"
|
||||
|
|
@ -65,11 +65,21 @@ export default function ShareFilter({setFilter,setSearch,open, onClose }) {
|
|||
<MenuItem value={"0"}>文件</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl fullWidth style={{marginTop:16}}>
|
||||
<TextField value={input.user_id} onChange={handleChange("user_id")} id="standard-basic" label="上传者ID" />
|
||||
<FormControl fullWidth style={{ marginTop: 16 }}>
|
||||
<TextField
|
||||
value={input.user_id}
|
||||
onChange={handleChange("user_id")}
|
||||
id="standard-basic"
|
||||
label="上传者ID"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl fullWidth style={{marginTop:16}}>
|
||||
<TextField value={keywords} onChange={e=>setKeywords(e.target.value)} id="standard-basic" label="搜索 文件名" />
|
||||
<FormControl fullWidth style={{ marginTop: 16 }}>
|
||||
<TextField
|
||||
value={keywords}
|
||||
onChange={e => setKeywords(e.target.value)}
|
||||
id="standard-basic"
|
||||
label="搜索 文件名"
|
||||
/>
|
||||
</FormControl>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@ import { useDispatch } from "react-redux";
|
|||
import { toggleSnackbar } from "../../../actions";
|
||||
import API from "../../../middleware/Api";
|
||||
|
||||
export default function UserFilter({setFilter,setSearch,open, onClose }) {
|
||||
const [input,setInput] = useState({
|
||||
group_id:"all",
|
||||
status:"all",
|
||||
export default function UserFilter({ setFilter, setSearch, open, onClose }) {
|
||||
const [input, setInput] = useState({
|
||||
group_id: "all",
|
||||
status: "all"
|
||||
});
|
||||
const [groups,setGroups] = useState([]);
|
||||
const [keywords,setKeywords] = useState("");
|
||||
const [groups, setGroups] = useState([]);
|
||||
const [keywords, setKeywords] = useState("");
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const ToggleSnackbar = useCallback(
|
||||
|
|
@ -29,10 +29,10 @@ export default function UserFilter({setFilter,setSearch,open, onClose }) {
|
|||
);
|
||||
|
||||
const handleChange = name => event => {
|
||||
setInput({...input,[name]:event.target.value})
|
||||
}
|
||||
setInput({ ...input, [name]: event.target.value });
|
||||
};
|
||||
|
||||
useEffect(()=>{
|
||||
useEffect(() => {
|
||||
API.get("/admin/groups")
|
||||
.then(response => {
|
||||
setGroups(response.data);
|
||||
|
|
@ -40,26 +40,26 @@ export default function UserFilter({setFilter,setSearch,open, onClose }) {
|
|||
.catch(error => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
});
|
||||
},[])
|
||||
}, []);
|
||||
|
||||
const submit = () => {
|
||||
const res = {};
|
||||
Object.keys(input).forEach(v=>{
|
||||
if(input[v] !== "all"){
|
||||
Object.keys(input).forEach(v => {
|
||||
if (input[v] !== "all") {
|
||||
res[v] = input[v];
|
||||
}
|
||||
})
|
||||
});
|
||||
setFilter(res);
|
||||
if (keywords !== ""){
|
||||
if (keywords !== "") {
|
||||
setSearch({
|
||||
nick:keywords,
|
||||
email:keywords,
|
||||
nick: keywords,
|
||||
email: keywords
|
||||
});
|
||||
}else{
|
||||
} else {
|
||||
setSearch({});
|
||||
}
|
||||
onClose();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
|
|
@ -70,12 +70,12 @@ export default function UserFilter({setFilter,setSearch,open, onClose }) {
|
|||
fullWidth
|
||||
maxWidth={"xs"}
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">
|
||||
过滤条件
|
||||
</DialogTitle>
|
||||
<DialogTitle id="alert-dialog-title">过滤条件</DialogTitle>
|
||||
<DialogContent>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel id="demo-simple-select-label">用户组</InputLabel>
|
||||
<InputLabel id="demo-simple-select-label">
|
||||
用户组
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId="demo-simple-select-label"
|
||||
id="demo-simple-select"
|
||||
|
|
@ -88,18 +88,17 @@ export default function UserFilter({setFilter,setSearch,open, onClose }) {
|
|||
return null;
|
||||
}
|
||||
return (
|
||||
<MenuItem
|
||||
key={v.ID}
|
||||
value={v.ID.toString()}
|
||||
>
|
||||
<MenuItem key={v.ID} value={v.ID.toString()}>
|
||||
{v.Name}
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl fullWidth style={{marginTop:16}}>
|
||||
<InputLabel id="demo-simple-select-label">用户状态</InputLabel>
|
||||
<FormControl fullWidth style={{ marginTop: 16 }}>
|
||||
<InputLabel id="demo-simple-select-label">
|
||||
用户状态
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId="demo-simple-select-label"
|
||||
id="demo-simple-select"
|
||||
|
|
@ -113,8 +112,13 @@ export default function UserFilter({setFilter,setSearch,open, onClose }) {
|
|||
<MenuItem value={"3"}>超额使用被封禁</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl fullWidth style={{marginTop:16}}>
|
||||
<TextField value={keywords} onChange={e=>setKeywords(e.target.value)} id="standard-basic" label="搜索 昵称 / 用户名" />
|
||||
<FormControl fullWidth style={{ marginTop: 16 }}>
|
||||
<TextField
|
||||
value={keywords}
|
||||
onChange={e => setKeywords(e.target.value)}
|
||||
id="standard-basic"
|
||||
label="搜索 昵称 / 用户名"
|
||||
/>
|
||||
</FormControl>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import React, {useCallback, useEffect, useState} from "react";
|
||||
import {useParams} from "react-router";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { useParams } from "react-router";
|
||||
import API from "../../../middleware/Api";
|
||||
import {useDispatch} from "react-redux";
|
||||
import {toggleSnackbar} from "../../../actions";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { toggleSnackbar } from "../../../actions";
|
||||
import GroupForm from "./GroupForm";
|
||||
|
||||
export default function EditGroupPreload( ) {
|
||||
const [group,setGroup] = useState({});
|
||||
export default function EditGroupPreload() {
|
||||
const [group, setGroup] = useState({});
|
||||
|
||||
const {id } = useParams();
|
||||
const { id } = useParams();
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const ToggleSnackbar = useCallback(
|
||||
|
|
@ -17,14 +17,13 @@ export default function EditGroupPreload( ) {
|
|||
[dispatch]
|
||||
);
|
||||
|
||||
|
||||
useEffect(()=>{
|
||||
useEffect(() => {
|
||||
setGroup({});
|
||||
API.get("/admin/group/" + id)
|
||||
.then(response => {
|
||||
// 布尔值转换
|
||||
["ShareEnabled", "WebDAVEnabled"].forEach(v => {
|
||||
response.data[v] = response.data[v]?"true":"false";
|
||||
response.data[v] = response.data[v] ? "true" : "false";
|
||||
});
|
||||
[
|
||||
"archive_download",
|
||||
|
|
@ -33,8 +32,11 @@ export default function EditGroupPreload( ) {
|
|||
"share_download",
|
||||
"aria2"
|
||||
].forEach(v => {
|
||||
if (response.data.OptionsSerialized[v] !== undefined){
|
||||
response.data.OptionsSerialized[v] = response.data.OptionsSerialized[v]?"true":"false";
|
||||
if (response.data.OptionsSerialized[v] !== undefined) {
|
||||
response.data.OptionsSerialized[v] = response.data
|
||||
.OptionsSerialized[v]
|
||||
? "true"
|
||||
: "false";
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -42,40 +44,41 @@ export default function EditGroupPreload( ) {
|
|||
["MaxStorage", "SpeedLimit"].forEach(v => {
|
||||
response.data[v] = response.data[v].toString();
|
||||
});
|
||||
[
|
||||
"compress_size",
|
||||
"decompress_size",
|
||||
].forEach(v => {
|
||||
if (response.data.OptionsSerialized[v] !== undefined){
|
||||
response.data.OptionsSerialized[v] = response.data.OptionsSerialized[v].toString();
|
||||
["compress_size", "decompress_size"].forEach(v => {
|
||||
if (response.data.OptionsSerialized[v] !== undefined) {
|
||||
response.data.OptionsSerialized[
|
||||
v
|
||||
] = response.data.OptionsSerialized[v].toString();
|
||||
}
|
||||
});
|
||||
response.data.PolicyList = response.data.PolicyList[0];
|
||||
|
||||
// JSON转换
|
||||
if(response.data.OptionsSerialized.aria2_options === undefined){
|
||||
response.data.OptionsSerialized.aria2_options = "{}"
|
||||
}else{
|
||||
if (
|
||||
response.data.OptionsSerialized.aria2_options === undefined
|
||||
) {
|
||||
response.data.OptionsSerialized.aria2_options = "{}";
|
||||
} else {
|
||||
try {
|
||||
response.data.OptionsSerialized.aria2_options = JSON.stringify(response.data.OptionsSerialized.aria2_options);
|
||||
}catch (e) {
|
||||
ToggleSnackbar("top", "right", "Aria2 设置项格式错误", "warning");
|
||||
response.data.OptionsSerialized.aria2_options = JSON.stringify(
|
||||
response.data.OptionsSerialized.aria2_options
|
||||
);
|
||||
} catch (e) {
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"Aria2 设置项格式错误",
|
||||
"warning"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
setGroup(response.data);
|
||||
})
|
||||
.catch(error => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
});
|
||||
},[id]);
|
||||
}, [id]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{group.ID !== undefined &&
|
||||
<GroupForm group={group}/>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
return <div>{group.ID !== undefined && <GroupForm group={group} />}</div>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,6 @@ function useQuery() {
|
|||
return new URLSearchParams(useLocation().search);
|
||||
}
|
||||
|
||||
|
||||
export default function Group() {
|
||||
const classes = useStyles();
|
||||
const [groups, setGroups] = useState([]);
|
||||
|
|
@ -91,37 +90,41 @@ export default function Group() {
|
|||
);
|
||||
|
||||
const loadList = () => {
|
||||
API.post("/admin/group/list", {
|
||||
page: page,
|
||||
page_size: pageSize,
|
||||
order_by: "id desc",
|
||||
})
|
||||
.then(response => {
|
||||
setGroups(response.data.items);
|
||||
setStatics(response.data.statics);
|
||||
setTotal(response.data.total);
|
||||
setPolicies(response.data.policies);
|
||||
})
|
||||
.catch(error => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
});
|
||||
API.post("/admin/group/list", {
|
||||
page: page,
|
||||
page_size: pageSize,
|
||||
order_by: "id desc"
|
||||
})
|
||||
.then(response => {
|
||||
setGroups(response.data.items);
|
||||
setStatics(response.data.statics);
|
||||
setTotal(response.data.total);
|
||||
setPolicies(response.data.policies);
|
||||
})
|
||||
.catch(error => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(()=>{
|
||||
if(query.get("code") === "0"){
|
||||
useEffect(() => {
|
||||
if (query.get("code") === "0") {
|
||||
ToggleSnackbar("top", "right", "授权成功", "success");
|
||||
}else if (query.get("msg") && query.get("msg")!==""){
|
||||
ToggleSnackbar("top", "right", query.get("msg") + ", "+ query.get("err"), "warning");
|
||||
} else if (query.get("msg") && query.get("msg") !== "") {
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
query.get("msg") + ", " + query.get("err"),
|
||||
"warning"
|
||||
);
|
||||
}
|
||||
|
||||
},[location])
|
||||
}, [location]);
|
||||
|
||||
useEffect(() => {
|
||||
loadList();
|
||||
}, [page, pageSize]);
|
||||
|
||||
const deletePolicy = (id) =>{
|
||||
API.delete("/admin/group/" + id,)
|
||||
const deletePolicy = id => {
|
||||
API.delete("/admin/group/" + id)
|
||||
.then(() => {
|
||||
loadList();
|
||||
ToggleSnackbar("top", "right", "用户组已删除", "success");
|
||||
|
|
@ -129,7 +132,7 @@ export default function Group() {
|
|||
.catch(error => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
|
@ -156,7 +159,7 @@ export default function Group() {
|
|||
<TableContainer className={classes.container}>
|
||||
<Table aria-label="sticky table" size={"small"}>
|
||||
<TableHead>
|
||||
<TableRow style={{height:52}}>
|
||||
<TableRow style={{ height: 52 }}>
|
||||
{columns.map(column => (
|
||||
<TableCell
|
||||
key={column.id}
|
||||
|
|
@ -174,16 +177,20 @@ export default function Group() {
|
|||
<TableCell>{row.ID}</TableCell>
|
||||
<TableCell>{row.Name}</TableCell>
|
||||
<TableCell>
|
||||
{row.PolicyList !== null && row.PolicyList.map((pid,key)=>{
|
||||
let res = "";
|
||||
if (policies[pid]){
|
||||
res += policies[pid].Name;
|
||||
}
|
||||
if (key !== row.PolicyList.length-1){
|
||||
res += " / ";
|
||||
}
|
||||
return res
|
||||
})}
|
||||
{row.PolicyList !== null &&
|
||||
row.PolicyList.map((pid, key) => {
|
||||
let res = "";
|
||||
if (policies[pid]) {
|
||||
res += policies[pid].Name;
|
||||
}
|
||||
if (
|
||||
key !==
|
||||
row.PolicyList.length - 1
|
||||
) {
|
||||
res += " / ";
|
||||
}
|
||||
return res;
|
||||
})}
|
||||
</TableCell>
|
||||
<TableCell align={"right"}>
|
||||
{statics[row.ID] !== undefined &&
|
||||
|
|
@ -195,16 +202,28 @@ export default function Group() {
|
|||
</TableCell>
|
||||
<TableCell align={"right"}>
|
||||
<Tooltip title={"删除"}>
|
||||
<IconButton onClick={()=>deletePolicy(row.ID)} size={"small"}>
|
||||
<Delete/>
|
||||
<IconButton
|
||||
onClick={() =>
|
||||
deletePolicy(row.ID)
|
||||
}
|
||||
size={"small"}
|
||||
>
|
||||
<Delete />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title={"编辑"}>
|
||||
<IconButton onClick={()=>history.push("/admin/group/edit/" + row.ID)} size={"small"}>
|
||||
<Edit/>
|
||||
<IconButton
|
||||
onClick={() =>
|
||||
history.push(
|
||||
"/admin/group/edit/" +
|
||||
row.ID
|
||||
)
|
||||
}
|
||||
size={"small"}
|
||||
>
|
||||
<Edit />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -152,8 +152,9 @@ export default function GroupForm(props) {
|
|||
"share_download",
|
||||
"aria2"
|
||||
].forEach(v => {
|
||||
if (groupCopy.OptionsSerialized[v] !== undefined){
|
||||
groupCopy.OptionsSerialized[v] = groupCopy.OptionsSerialized[v] === "true";
|
||||
if (groupCopy.OptionsSerialized[v] !== undefined) {
|
||||
groupCopy.OptionsSerialized[v] =
|
||||
groupCopy.OptionsSerialized[v] === "true";
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -161,19 +162,20 @@ export default function GroupForm(props) {
|
|||
["MaxStorage", "SpeedLimit"].forEach(v => {
|
||||
groupCopy[v] = parseInt(groupCopy[v]);
|
||||
});
|
||||
[
|
||||
"compress_size",
|
||||
"decompress_size",
|
||||
].forEach(v => {
|
||||
if (groupCopy.OptionsSerialized[v] !== undefined){
|
||||
groupCopy.OptionsSerialized[v] = parseInt(groupCopy.OptionsSerialized[v]);
|
||||
["compress_size", "decompress_size"].forEach(v => {
|
||||
if (groupCopy.OptionsSerialized[v] !== undefined) {
|
||||
groupCopy.OptionsSerialized[v] = parseInt(
|
||||
groupCopy.OptionsSerialized[v]
|
||||
);
|
||||
}
|
||||
});
|
||||
groupCopy.PolicyList = [parseInt(groupCopy.PolicyList)];
|
||||
// JSON转换
|
||||
try {
|
||||
groupCopy.OptionsSerialized.aria2_options = JSON.parse(groupCopy.OptionsSerialized.aria2_options);
|
||||
}catch (e) {
|
||||
groupCopy.OptionsSerialized.aria2_options = JSON.parse(
|
||||
groupCopy.OptionsSerialized.aria2_options
|
||||
);
|
||||
} catch (e) {
|
||||
ToggleSnackbar("top", "right", "Aria2 设置项格式错误", "warning");
|
||||
return;
|
||||
}
|
||||
|
|
@ -184,7 +186,12 @@ export default function GroupForm(props) {
|
|||
})
|
||||
.then(() => {
|
||||
history.push("/admin/group");
|
||||
ToggleSnackbar("top", "right", "用户组已"+ (props.group ? "保存" : "添加"), "success");
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"用户组已" + (props.group ? "保存" : "添加"),
|
||||
"success"
|
||||
);
|
||||
})
|
||||
.catch(error => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
|
|
@ -192,7 +199,6 @@ export default function GroupForm(props) {
|
|||
.then(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
@ -205,68 +211,71 @@ export default function GroupForm(props) {
|
|||
</Typography>
|
||||
|
||||
<div className={classes.formContainer}>
|
||||
{group.ID !== 3 && (
|
||||
<>
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
用户组名
|
||||
</InputLabel>
|
||||
<Input
|
||||
value={group.Name}
|
||||
onChange={handleChange("Name")}
|
||||
required
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
用户组的名称
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
{group.ID !== 3 && <>
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
用户组名
|
||||
</InputLabel>
|
||||
<Input
|
||||
value={group.Name}
|
||||
onChange={handleChange("Name")}
|
||||
required
|
||||
/>
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
存储策略
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId="demo-mutiple-chip-label"
|
||||
id="demo-mutiple-chip"
|
||||
value={group.PolicyList}
|
||||
onChange={handleChange(
|
||||
"PolicyList"
|
||||
)}
|
||||
input={
|
||||
<Input id="select-multiple-chip" />
|
||||
}
|
||||
>
|
||||
{Object.keys(policies).map(pid => (
|
||||
<MenuItem key={pid} value={pid}>
|
||||
{policies[pid]}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<FormHelperText id="component-helper-text">
|
||||
指定用户组的存储策略。
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<SizeInput
|
||||
value={group.MaxStorage}
|
||||
onChange={handleChange(
|
||||
"MaxStorage"
|
||||
)}
|
||||
min={0}
|
||||
max={9223372036854775807}
|
||||
label={"初始容量"}
|
||||
required
|
||||
/>
|
||||
</FormControl>
|
||||
<FormHelperText id="component-helper-text">
|
||||
用户组的名称
|
||||
用户组下的用户初始可用最大容量
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
存储策略
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId="demo-mutiple-chip-label"
|
||||
id="demo-mutiple-chip"
|
||||
value={group.PolicyList}
|
||||
onChange={handleChange("PolicyList")}
|
||||
input={<Input id="select-multiple-chip" />}
|
||||
>
|
||||
{Object.keys(policies).map(pid => (
|
||||
<MenuItem
|
||||
key={pid}
|
||||
value={pid}
|
||||
>
|
||||
{policies[pid]}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<FormHelperText id="component-helper-text">
|
||||
指定用户组的存储策略。
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<SizeInput
|
||||
value={group.MaxStorage}
|
||||
onChange={handleChange("MaxStorage")}
|
||||
min={0}
|
||||
max={9223372036854775807}
|
||||
label={"初始容量"}
|
||||
required
|
||||
/>
|
||||
</FormControl>
|
||||
<FormHelperText id="component-helper-text">
|
||||
用户组下的用户初始可用最大容量
|
||||
</FormHelperText>
|
||||
</div>
|
||||
</>}
|
||||
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
|
|
@ -286,27 +295,29 @@ export default function GroupForm(props) {
|
|||
</FormHelperText>
|
||||
</div>
|
||||
|
||||
{group.ID !== 3 && <div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={
|
||||
group.ShareEnabled === "true"
|
||||
}
|
||||
onChange={handleCheckChange(
|
||||
"ShareEnabled"
|
||||
)}
|
||||
/>
|
||||
}
|
||||
label="允许创建分享"
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
关闭后,用户无法创建分享链接
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>}
|
||||
|
||||
{group.ID !== 3 && (
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={
|
||||
group.ShareEnabled ===
|
||||
"true"
|
||||
}
|
||||
onChange={handleCheckChange(
|
||||
"ShareEnabled"
|
||||
)}
|
||||
/>
|
||||
}
|
||||
label="允许创建分享"
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
关闭后,用户无法创建分享链接
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
|
|
@ -330,26 +341,30 @@ export default function GroupForm(props) {
|
|||
</FormControl>
|
||||
</div>
|
||||
|
||||
{group.ID !== 3 && <div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={
|
||||
group.WebDAVEnabled === "true"
|
||||
}
|
||||
onChange={handleCheckChange(
|
||||
"WebDAVEnabled"
|
||||
)}
|
||||
/>
|
||||
}
|
||||
label="WebDAV"
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
关闭后,用户无法通过 WebDAV 协议连接至网盘
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>}
|
||||
{group.ID !== 3 && (
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={
|
||||
group.WebDAVEnabled ===
|
||||
"true"
|
||||
}
|
||||
onChange={handleCheckChange(
|
||||
"WebDAVEnabled"
|
||||
)}
|
||||
/>
|
||||
}
|
||||
label="WebDAV"
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
关闭后,用户无法通过 WebDAV
|
||||
协议连接至网盘
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
|
|
@ -374,28 +389,29 @@ export default function GroupForm(props) {
|
|||
</FormControl>
|
||||
</div>
|
||||
|
||||
{group.ID !== 3 && <div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={
|
||||
group.OptionsSerialized
|
||||
.aria2 === "true"
|
||||
}
|
||||
onChange={handleOptionCheckChange(
|
||||
"aria2"
|
||||
)}
|
||||
/>
|
||||
}
|
||||
label="离线下载"
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
是否允许用户创建离线下载任务
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>}
|
||||
|
||||
{group.ID !== 3 && (
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={
|
||||
group.OptionsSerialized
|
||||
.aria2 === "true"
|
||||
}
|
||||
onChange={handleOptionCheckChange(
|
||||
"aria2"
|
||||
)}
|
||||
/>
|
||||
}
|
||||
label="离线下载"
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
是否允许用户创建离线下载任务
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Collapse in={group.OptionsSerialized.aria2 === "true"}>
|
||||
<div className={classes.form}>
|
||||
|
|
@ -445,27 +461,29 @@ export default function GroupForm(props) {
|
|||
</FormControl>
|
||||
</div>
|
||||
|
||||
{group.ID !== 3 && <div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={
|
||||
group.OptionsSerialized
|
||||
.archive_task === "true"
|
||||
}
|
||||
onChange={handleOptionCheckChange(
|
||||
"archive_task"
|
||||
)}
|
||||
/>
|
||||
}
|
||||
label="压缩/解压缩 任务"
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
是否用户创建 压缩/解压缩 任务
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>}
|
||||
{group.ID !== 3 && (
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={
|
||||
group.OptionsSerialized
|
||||
.archive_task === "true"
|
||||
}
|
||||
onChange={handleOptionCheckChange(
|
||||
"archive_task"
|
||||
)}
|
||||
/>
|
||||
}
|
||||
label="压缩/解压缩 任务"
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
是否用户创建 压缩/解压缩 任务
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Collapse
|
||||
in={group.OptionsSerialized.archive_task === "true"}
|
||||
|
|
|
|||
|
|
@ -17,11 +17,31 @@ import ListItemText from "@material-ui/core/ListItemText";
|
|||
import Paper from "@material-ui/core/Paper";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import { Description, Favorite, FileCopy, Forum, GitHub, Home, Launch, Lock, People, Public, Telegram } from "@material-ui/icons";
|
||||
import {
|
||||
Description,
|
||||
Favorite,
|
||||
FileCopy,
|
||||
Forum,
|
||||
GitHub,
|
||||
Home,
|
||||
Launch,
|
||||
Lock,
|
||||
People,
|
||||
Public,
|
||||
Telegram
|
||||
} from "@material-ui/icons";
|
||||
import axios from "axios";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { CartesianGrid, Legend, Line, LineChart, Tooltip, XAxis, YAxis } from "recharts";
|
||||
import {
|
||||
CartesianGrid,
|
||||
Legend,
|
||||
Line,
|
||||
LineChart,
|
||||
Tooltip,
|
||||
XAxis,
|
||||
YAxis
|
||||
} from "recharts";
|
||||
import ResponsiveContainer from "recharts/lib/component/ResponsiveContainer";
|
||||
import TimeAgo from "timeago-react";
|
||||
import { toggleSnackbar } from "../../actions";
|
||||
|
|
@ -98,13 +118,15 @@ export default function Index() {
|
|||
[dispatch]
|
||||
);
|
||||
|
||||
const ResetSiteURL = ()=>{
|
||||
const ResetSiteURL = () => {
|
||||
setOpen(false);
|
||||
API.patch("/admin/setting",{
|
||||
options:[{
|
||||
key:"siteURL",
|
||||
value:window.location.origin,
|
||||
}],
|
||||
API.patch("/admin/setting", {
|
||||
options: [
|
||||
{
|
||||
key: "siteURL",
|
||||
value: window.location.origin
|
||||
}
|
||||
]
|
||||
})
|
||||
.then(() => {
|
||||
setSiteURL(window.location.origin);
|
||||
|
|
@ -113,7 +135,7 @@ export default function Index() {
|
|||
.catch(error => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
API.get("/admin/summary")
|
||||
|
|
@ -136,7 +158,10 @@ export default function Index() {
|
|||
});
|
||||
setVersion(response.data.version);
|
||||
setSiteURL(response.data.siteURL);
|
||||
if (response.data.siteURL === "" || response.data.siteURL !== window.location.origin){
|
||||
if (
|
||||
response.data.siteURL === "" ||
|
||||
response.data.siteURL !== window.location.origin
|
||||
) {
|
||||
setOpen(true);
|
||||
}
|
||||
})
|
||||
|
|
@ -165,27 +190,36 @@ export default function Index() {
|
|||
<Grid container spacing={3}>
|
||||
<Dialog
|
||||
open={open}
|
||||
onClose={()=>setOpen(false)}
|
||||
onClose={() => setOpen(false)}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">{"确定站点URL设置"}</DialogTitle>
|
||||
<DialogTitle id="alert-dialog-title">
|
||||
{"确定站点URL设置"}
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText id="alert-dialog-description">
|
||||
<Typography>
|
||||
{siteURL === "" && "您尚未设定站点URL,是否要将其设定为当前的 "+ window.location.origin + " ?"}
|
||||
{siteURL !== "" && "您设置的站点URL与当前实际不一致,是否要将其设定为当前的 "+ window.location.origin + " ?"}
|
||||
{siteURL === "" &&
|
||||
"您尚未设定站点URL,是否要将其设定为当前的 " +
|
||||
window.location.origin +
|
||||
" ?"}
|
||||
{siteURL !== "" &&
|
||||
"您设置的站点URL与当前实际不一致,是否要将其设定为当前的 " +
|
||||
window.location.origin +
|
||||
" ?"}
|
||||
</Typography>
|
||||
<Typography>
|
||||
此设置非常重要,请确保其与您站点的实际地址一致。你可以在 参数设置 - 站点信息 中更改此设置。
|
||||
此设置非常重要,请确保其与您站点的实际地址一致。你可以在
|
||||
参数设置 - 站点信息 中更改此设置。
|
||||
</Typography>
|
||||
</DialogContentText>
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={()=>setOpen(false)} color="default">
|
||||
<Button onClick={() => setOpen(false)} color="default">
|
||||
忽略
|
||||
</Button>
|
||||
<Button onClick={()=>ResetSiteURL()} color="primary">
|
||||
<Button onClick={() => ResetSiteURL()} color="primary">
|
||||
更改
|
||||
</Button>
|
||||
</DialogActions>
|
||||
|
|
@ -294,7 +328,10 @@ export default function Index() {
|
|||
Cloudreve
|
||||
</Typography>
|
||||
<Typography className={classes.version}>
|
||||
{version.backend} {version.is_pro === "true" && <Chip size="small" label="Pro" />}
|
||||
{version.backend}{" "}
|
||||
{version.is_pro === "true" && (
|
||||
<Chip size="small" label="Pro" />
|
||||
)}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -334,9 +371,7 @@ export default function Index() {
|
|||
<ListItem
|
||||
button
|
||||
onClick={() =>
|
||||
window.open(
|
||||
"https://docs.cloudreve.org/"
|
||||
)
|
||||
window.open("https://docs.cloudreve.org/")
|
||||
}
|
||||
>
|
||||
<ListItemIcon>
|
||||
|
|
@ -385,7 +420,7 @@ export default function Index() {
|
|||
)
|
||||
}
|
||||
>
|
||||
<ListItemIcon style={{color:"#ff789d"}}>
|
||||
<ListItemIcon style={{ color: "#ff789d" }}>
|
||||
<Favorite />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="捐助开发者" />
|
||||
|
|
@ -400,58 +435,72 @@ export default function Index() {
|
|||
<Grid item xs={12} md={8} lg={9}>
|
||||
<Paper className={classes.paper}>
|
||||
<List>
|
||||
{news && news.map((v) => (
|
||||
<>
|
||||
<ListItem button alignItems="flex-start"
|
||||
onClick={()=>window.open("https://forum.cloudreve.org/d/" + v.id)}
|
||||
>
|
||||
<ListItemAvatar>
|
||||
<Avatar
|
||||
alt="Travis Howard"
|
||||
src={
|
||||
newsUsers[
|
||||
v.relationships.startUser
|
||||
.data.id
|
||||
] &&
|
||||
newsUsers[
|
||||
v.relationships.startUser
|
||||
.data.id
|
||||
].avatarUrl
|
||||
}
|
||||
/>
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={v.attributes.title}
|
||||
secondary={
|
||||
<React.Fragment>
|
||||
<Typography
|
||||
component="span"
|
||||
variant="body2"
|
||||
className={classes.inline}
|
||||
color="textPrimary"
|
||||
>
|
||||
{newsUsers[
|
||||
{news &&
|
||||
news.map(v => (
|
||||
<>
|
||||
<ListItem
|
||||
button
|
||||
alignItems="flex-start"
|
||||
onClick={() =>
|
||||
window.open(
|
||||
"https://forum.cloudreve.org/d/" +
|
||||
v.id
|
||||
)
|
||||
}
|
||||
>
|
||||
<ListItemAvatar>
|
||||
<Avatar
|
||||
alt="Travis Howard"
|
||||
src={
|
||||
newsUsers[
|
||||
v.relationships
|
||||
.startUser.data.id
|
||||
] &&
|
||||
newsUsers[
|
||||
newsUsers[
|
||||
v.relationships
|
||||
.startUser.data.id
|
||||
].avatarUrl
|
||||
}
|
||||
/>
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={v.attributes.title}
|
||||
secondary={
|
||||
<React.Fragment>
|
||||
<Typography
|
||||
component="span"
|
||||
variant="body2"
|
||||
className={
|
||||
classes.inline
|
||||
}
|
||||
color="textPrimary"
|
||||
>
|
||||
{newsUsers[
|
||||
v.relationships
|
||||
.startUser.data
|
||||
.id
|
||||
].username}{" "}
|
||||
</Typography>
|
||||
发表于{" "}
|
||||
<TimeAgo
|
||||
datetime={v.attributes.startTime}
|
||||
locale='zh_CN'
|
||||
/>
|
||||
</React.Fragment>
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
<Divider />
|
||||
</>
|
||||
))}
|
||||
] &&
|
||||
newsUsers[
|
||||
v.relationships
|
||||
.startUser
|
||||
.data.id
|
||||
].username}{" "}
|
||||
</Typography>
|
||||
发表于{" "}
|
||||
<TimeAgo
|
||||
datetime={
|
||||
v.attributes
|
||||
.startTime
|
||||
}
|
||||
locale="zh_CN"
|
||||
/>
|
||||
</React.Fragment>
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
<Divider />
|
||||
</>
|
||||
))}
|
||||
</List>
|
||||
</Paper>
|
||||
</Grid>
|
||||
|
|
|
|||
|
|
@ -20,11 +20,10 @@ const useStyles = makeStyles(theme => ({
|
|||
},
|
||||
content: {
|
||||
padding: theme.spacing(2)
|
||||
},
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
export default function AddPolicyParent( ) {
|
||||
export default function AddPolicyParent() {
|
||||
const classes = useStyles();
|
||||
|
||||
const { type } = useParams();
|
||||
|
|
@ -32,14 +31,14 @@ export default function AddPolicyParent( ) {
|
|||
return (
|
||||
<div>
|
||||
<Paper square className={classes.content}>
|
||||
{type==="local"&&<LocalGuide/>}
|
||||
{type==="remote"&&<RemoteGuide/>}
|
||||
{type==="qiniu"&&<QiniuGuide/>}
|
||||
{type==="oss"&&<OSSGuide/>}
|
||||
{type==="upyun"&&<UpyunGuide/>}
|
||||
{type==="cos"&&<COSGuide/>}
|
||||
{type==="onedrive"&&<OneDriveGuide/>}
|
||||
{type==="s3"&&(<S3Guide/>)}
|
||||
{type === "local" && <LocalGuide />}
|
||||
{type === "remote" && <RemoteGuide />}
|
||||
{type === "qiniu" && <QiniuGuide />}
|
||||
{type === "oss" && <OSSGuide />}
|
||||
{type === "upyun" && <UpyunGuide />}
|
||||
{type === "cos" && <COSGuide />}
|
||||
{type === "onedrive" && <OneDriveGuide />}
|
||||
{type === "s3" && <S3Guide />}
|
||||
</Paper>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -24,16 +24,15 @@ const useStyles = makeStyles(theme => ({
|
|||
},
|
||||
content: {
|
||||
padding: theme.spacing(2)
|
||||
},
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
export default function EditPolicyPreload( ) {
|
||||
export default function EditPolicyPreload() {
|
||||
const classes = useStyles();
|
||||
const [type,setType] = useState("");
|
||||
const [policy,setPolicy] = useState({});
|
||||
const [type, setType] = useState("");
|
||||
const [policy, setPolicy] = useState({});
|
||||
|
||||
const { mode,id } = useParams();
|
||||
const { mode, id } = useParams();
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const ToggleSnackbar = useCallback(
|
||||
|
|
@ -42,46 +41,52 @@ export default function EditPolicyPreload( ) {
|
|||
[dispatch]
|
||||
);
|
||||
|
||||
|
||||
useEffect(()=>{
|
||||
useEffect(() => {
|
||||
setType("");
|
||||
API.get("/admin/policy/" + id)
|
||||
.then(response => {
|
||||
response.data.IsOriginLinkEnable = response.data.IsOriginLinkEnable ? "true" : "false";
|
||||
response.data.AutoRename = response.data.AutoRename ? "true" : "false";
|
||||
response.data.MaxSize = response.data.MaxSize.toString();
|
||||
response.data.IsPrivate = response.data.IsPrivate ? "true" : "false";
|
||||
response.data.OptionsSerialized.file_type =
|
||||
response.data.OptionsSerialized.file_type ?
|
||||
response.data.OptionsSerialized.file_type.join(","):
|
||||
"";
|
||||
response.data.IsOriginLinkEnable = response.data
|
||||
.IsOriginLinkEnable
|
||||
? "true"
|
||||
: "false";
|
||||
response.data.AutoRename = response.data.AutoRename
|
||||
? "true"
|
||||
: "false";
|
||||
response.data.MaxSize = response.data.MaxSize.toString();
|
||||
response.data.IsPrivate = response.data.IsPrivate
|
||||
? "true"
|
||||
: "false";
|
||||
response.data.OptionsSerialized.file_type = response.data
|
||||
.OptionsSerialized.file_type
|
||||
? response.data.OptionsSerialized.file_type.join(",")
|
||||
: "";
|
||||
setPolicy(response.data);
|
||||
setType(response.data.Type);
|
||||
})
|
||||
.catch(error => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
});
|
||||
},[id]);
|
||||
}, [id]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Paper square className={classes.content}>
|
||||
{mode === "guide" &&
|
||||
{mode === "guide" && (
|
||||
<>
|
||||
{type==="local"&&<LocalGuide policy={policy}/>}
|
||||
{type==="remote"&&<RemoteGuide policy={policy}/>}
|
||||
{type==="qiniu"&&<QiniuGuide policy={policy}/>}
|
||||
{type==="oss"&&<OSSGuide policy={policy}/>}
|
||||
{type==="upyun"&&<UpyunGuide policy={policy}/>}
|
||||
{type==="cos"&&<COSGuide policy={policy}/>}
|
||||
{type==="onedrive"&&<OneDriveGuide policy={policy}/>}
|
||||
{type==="s3"&&<S3Guide policy={policy}/>}
|
||||
{type === "local" && <LocalGuide policy={policy} />}
|
||||
{type === "remote" && <RemoteGuide policy={policy} />}
|
||||
{type === "qiniu" && <QiniuGuide policy={policy} />}
|
||||
{type === "oss" && <OSSGuide policy={policy} />}
|
||||
{type === "upyun" && <UpyunGuide policy={policy} />}
|
||||
{type === "cos" && <COSGuide policy={policy} />}
|
||||
{type === "onedrive" && (
|
||||
<OneDriveGuide policy={policy} />
|
||||
)}
|
||||
{type === "s3" && <S3Guide policy={policy} />}
|
||||
</>
|
||||
}
|
||||
)}
|
||||
|
||||
{mode === "pro" && type !== "" &&
|
||||
<EditPro policy={policy}/>
|
||||
}
|
||||
{mode === "pro" && type !== "" && <EditPro policy={policy} />}
|
||||
</Paper>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -67,16 +67,17 @@ const useStyles = makeStyles(theme => ({
|
|||
marginRight: theme.spacing(1)
|
||||
},
|
||||
viewButtonLabel: { textTransform: "none" },
|
||||
"@global":{
|
||||
"code":{
|
||||
"@global": {
|
||||
code: {
|
||||
color: "rgba(0, 0, 0, 0.87)",
|
||||
display: "inline-block",
|
||||
padding: "2px 6px",
|
||||
fontFamily:" Consolas, \"Liberation Mono\", Menlo, Courier, monospace",
|
||||
fontFamily:
|
||||
' Consolas, "Liberation Mono", Menlo, Courier, monospace',
|
||||
borderRadius: "2px",
|
||||
backgroundColor: "rgba(255,229,100,0.1)",
|
||||
},
|
||||
},
|
||||
backgroundColor: "rgba(255,229,100,0.1)"
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
const steps = [
|
||||
|
|
@ -119,25 +120,31 @@ export default function COSGuide(props) {
|
|||
const [skipped, setSkipped] = React.useState(new Set());
|
||||
const [magicVar, setMagicVar] = useState("");
|
||||
const [useCDN, setUseCDN] = useState("false");
|
||||
const [policy, setPolicy] = useState(props.policy?props.policy:{
|
||||
Type: "cos",
|
||||
Name: "",
|
||||
SecretKey: "",
|
||||
AccessKey: "",
|
||||
BaseURL: "",
|
||||
Server: "",
|
||||
IsPrivate: "true",
|
||||
DirNameRule: "uploads/{year}/{month}/{day}",
|
||||
AutoRename: "true",
|
||||
FileNameRule: "{randomkey8}_{originname}",
|
||||
IsOriginLinkEnable: "false",
|
||||
MaxSize: "0",
|
||||
OptionsSerialized: {
|
||||
file_type: "",
|
||||
}
|
||||
});
|
||||
const [policyID,setPolicyID] = useState(props.policy?props.policy.ID:0);
|
||||
const [region,setRegion] = useState("ap-chengdu");
|
||||
const [policy, setPolicy] = useState(
|
||||
props.policy
|
||||
? props.policy
|
||||
: {
|
||||
Type: "cos",
|
||||
Name: "",
|
||||
SecretKey: "",
|
||||
AccessKey: "",
|
||||
BaseURL: "",
|
||||
Server: "",
|
||||
IsPrivate: "true",
|
||||
DirNameRule: "uploads/{year}/{month}/{day}",
|
||||
AutoRename: "true",
|
||||
FileNameRule: "{randomkey8}_{originname}",
|
||||
IsOriginLinkEnable: "false",
|
||||
MaxSize: "0",
|
||||
OptionsSerialized: {
|
||||
file_type: ""
|
||||
}
|
||||
}
|
||||
);
|
||||
const [policyID, setPolicyID] = useState(
|
||||
props.policy ? props.policy.ID : 0
|
||||
);
|
||||
const [region, setRegion] = useState("ap-chengdu");
|
||||
|
||||
const handleChange = name => event => {
|
||||
setPolicy({
|
||||
|
|
@ -174,8 +181,8 @@ export default function COSGuide(props) {
|
|||
const policyCopy = { ...policy };
|
||||
policyCopy.OptionsSerialized = { ...policyCopy.OptionsSerialized };
|
||||
|
||||
if (useCDN === "false"){
|
||||
policyCopy.BaseURL = policy.Server
|
||||
if (useCDN === "false") {
|
||||
policyCopy.BaseURL = policy.Server;
|
||||
}
|
||||
|
||||
// 类型转换
|
||||
|
|
@ -198,7 +205,12 @@ export default function COSGuide(props) {
|
|||
policy: policyCopy
|
||||
})
|
||||
.then(response => {
|
||||
ToggleSnackbar("top", "right", "存储策略已"+ (props.policy ? "保存" : "添加"), "success");
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"存储策略已" + (props.policy ? "保存" : "添加"),
|
||||
"success"
|
||||
);
|
||||
setActiveStep(4);
|
||||
setPolicyID(response.data);
|
||||
})
|
||||
|
|
@ -212,7 +224,7 @@ export default function COSGuide(props) {
|
|||
setLoading(false);
|
||||
};
|
||||
|
||||
const createCORS = ()=>{
|
||||
const createCORS = () => {
|
||||
setLoading(true);
|
||||
API.post("/admin/policy/cors", {
|
||||
id: policyID
|
||||
|
|
@ -227,14 +239,13 @@ export default function COSGuide(props) {
|
|||
.then(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
const creatCallback = ()=>{
|
||||
const creatCallback = () => {
|
||||
setLoading(true);
|
||||
API.post("/admin/policy/scf", {
|
||||
id: policyID,
|
||||
region:region,
|
||||
region: region
|
||||
})
|
||||
.then(() => {
|
||||
ToggleSnackbar("top", "right", "回调云函数已添加", "success");
|
||||
|
|
@ -246,11 +257,13 @@ export default function COSGuide(props) {
|
|||
.then(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Typography variant={"h6"}>{props.policy ? "修改" : "添加"} 腾讯云 COS 存储策略</Typography>
|
||||
<Typography variant={"h6"}>
|
||||
{props.policy ? "修改" : "添加"} 腾讯云 COS 存储策略
|
||||
</Typography>
|
||||
<Stepper activeStep={activeStep}>
|
||||
{steps.map((label, index) => {
|
||||
const stepProps = {};
|
||||
|
|
@ -279,15 +292,15 @@ export default function COSGuide(props) {
|
|||
setActiveStep(1);
|
||||
}}
|
||||
>
|
||||
|
||||
<div className={classes.subStepContainer}>
|
||||
<div className={classes.stepNumberContainer}>
|
||||
<div className={classes.stepNumber}>0</div>
|
||||
</div>
|
||||
<div className={classes.subStepContent}>
|
||||
<Typography variant={"body2"}>
|
||||
在使用 腾讯云 COS 储策略前,请确保您在 参数设置 - 站点信息
|
||||
- 站点URL 中填写的 地址与实际相符,并且
|
||||
在使用 腾讯云 COS 储策略前,请确保您在 参数设置
|
||||
- 站点信息 - 站点URL 中填写的
|
||||
地址与实际相符,并且
|
||||
<strong>能够被外网正常访问</strong>。
|
||||
</Typography>
|
||||
</div>
|
||||
|
|
@ -301,7 +314,9 @@ export default function COSGuide(props) {
|
|||
<Typography variant={"body2"}>
|
||||
前往
|
||||
<Link
|
||||
href={"https://console.cloud.tencent.com/cos5"}
|
||||
href={
|
||||
"https://console.cloud.tencent.com/cos5"
|
||||
}
|
||||
target={"_blank"}
|
||||
>
|
||||
COS 管理控制台
|
||||
|
|
@ -317,7 +332,8 @@ export default function COSGuide(props) {
|
|||
</div>
|
||||
<div className={classes.subStepContent}>
|
||||
<Typography variant={"body2"}>
|
||||
转到所创建存储桶的基础配置页面,将<code>空间名称</code>填写在下方:
|
||||
转到所创建存储桶的基础配置页面,将
|
||||
<code>空间名称</code>填写在下方:
|
||||
</Typography>
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
|
|
@ -326,8 +342,9 @@ export default function COSGuide(props) {
|
|||
</InputLabel>
|
||||
<Input
|
||||
inputProps={{
|
||||
pattern:"[a-z0-9-]+-[0-9]+",
|
||||
title:"空间名格式不正确, 举例:ccc-1252109809"
|
||||
pattern: "[a-z0-9-]+-[0-9]+",
|
||||
title:
|
||||
"空间名格式不正确, 举例:ccc-1252109809"
|
||||
}}
|
||||
required
|
||||
value={policy.BucketName}
|
||||
|
|
@ -382,8 +399,9 @@ export default function COSGuide(props) {
|
|||
</div>
|
||||
<div className={classes.subStepContent}>
|
||||
<Typography variant={"body2"}>
|
||||
转到所创建 Bucket 的基础配置,填写<code>基本信息</code>栏目下
|
||||
给出的 <code>访问域名</code>
|
||||
转到所创建 Bucket 的基础配置,填写
|
||||
<code>基本信息</code>栏目下 给出的{" "}
|
||||
<code>访问域名</code>
|
||||
</Typography>
|
||||
<div className={classes.form}>
|
||||
<DomainInput
|
||||
|
|
@ -409,8 +427,8 @@ export default function COSGuide(props) {
|
|||
<RadioGroup
|
||||
required
|
||||
value={useCDN}
|
||||
onChange={e=>{
|
||||
setUseCDN(e.target.value)
|
||||
onChange={e => {
|
||||
setUseCDN(e.target.value);
|
||||
}}
|
||||
row
|
||||
>
|
||||
|
|
@ -442,11 +460,17 @@ export default function COSGuide(props) {
|
|||
<div className={classes.subStepContent}>
|
||||
<Typography variant={"body2"}>
|
||||
前往
|
||||
<Link href={"https://console.cloud.tencent.com/cdn/access/guid"} target={"_blank"}>
|
||||
<Link
|
||||
href={
|
||||
"https://console.cloud.tencent.com/cdn/access/guid"
|
||||
}
|
||||
target={"_blank"}
|
||||
>
|
||||
腾讯云 CDN 管理控制台
|
||||
</Link>
|
||||
创建 CDN 加速域名,并设定源站为刚创建的 COS 存储桶。在下方填写
|
||||
CDN 加速域名,并选择是否使用 HTTPS:
|
||||
创建 CDN 加速域名,并设定源站为刚创建的 COS
|
||||
存储桶。在下方填写 CDN
|
||||
加速域名,并选择是否使用 HTTPS:
|
||||
</Typography>
|
||||
<div className={classes.form}>
|
||||
<DomainInput
|
||||
|
|
@ -462,17 +486,24 @@ export default function COSGuide(props) {
|
|||
|
||||
<div className={classes.subStepContainer}>
|
||||
<div className={classes.stepNumberContainer}>
|
||||
<div className={classes.stepNumber}>{getNumber(6,[
|
||||
useCDN === "true"
|
||||
])}</div>
|
||||
<div className={classes.stepNumber}>
|
||||
{getNumber(6, [useCDN === "true"])}
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes.subStepContent}>
|
||||
<Typography variant={"body2"}>
|
||||
在腾讯云
|
||||
<Link href={"https://console.cloud.tencent.com/cam/capi"} target={"_blank"}>
|
||||
<Link
|
||||
href={
|
||||
"https://console.cloud.tencent.com/cam/capi"
|
||||
}
|
||||
target={"_blank"}
|
||||
>
|
||||
访问密钥
|
||||
</Link>
|
||||
页面获取 一对访问密钥,并填写在下方。请确保这对密钥拥有 COS 和 SCF 服务的访问权限。
|
||||
页面获取
|
||||
一对访问密钥,并填写在下方。请确保这对密钥拥有
|
||||
COS 和 SCF 服务的访问权限。
|
||||
</Typography>
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
|
|
@ -482,8 +513,8 @@ export default function COSGuide(props) {
|
|||
<Input
|
||||
required
|
||||
inputProps={{
|
||||
pattern:"\\S+" ,
|
||||
title:"不能含有空格"
|
||||
pattern: "\\S+",
|
||||
title: "不能含有空格"
|
||||
}}
|
||||
value={policy.AccessKey}
|
||||
onChange={handleChange("AccessKey")}
|
||||
|
|
@ -498,8 +529,8 @@ export default function COSGuide(props) {
|
|||
<Input
|
||||
required
|
||||
inputProps={{
|
||||
pattern:"\\S+" ,
|
||||
title:"不能含有空格"
|
||||
pattern: "\\S+",
|
||||
title: "不能含有空格"
|
||||
}}
|
||||
value={policy.SecretKey}
|
||||
onChange={handleChange("SecretKey")}
|
||||
|
|
@ -511,9 +542,9 @@ export default function COSGuide(props) {
|
|||
|
||||
<div className={classes.subStepContainer}>
|
||||
<div className={classes.stepNumberContainer}>
|
||||
<div className={classes.stepNumber}>{getNumber(7,[
|
||||
useCDN === "true"
|
||||
])}</div>
|
||||
<div className={classes.stepNumber}>
|
||||
{getNumber(7, [useCDN === "true"])}
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes.subStepContent}>
|
||||
<Typography variant={"body2"}>
|
||||
|
|
@ -567,9 +598,9 @@ export default function COSGuide(props) {
|
|||
可用魔法变量可参考{" "}
|
||||
<Link
|
||||
color={"secondary"}
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
setMagicVar("path")
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
setMagicVar("path");
|
||||
}}
|
||||
>
|
||||
路径魔法变量列表
|
||||
|
|
@ -602,9 +633,9 @@ export default function COSGuide(props) {
|
|||
可用魔法变量可参考{" "}
|
||||
<Link
|
||||
color={"secondary"}
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
setMagicVar("file")
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
setMagicVar("file");
|
||||
}}
|
||||
>
|
||||
文件名魔法变量列表
|
||||
|
|
@ -703,14 +734,22 @@ export default function COSGuide(props) {
|
|||
<RadioGroup
|
||||
required
|
||||
value={policy.IsOriginLinkEnable}
|
||||
onChange={e=>{
|
||||
if (policy.IsPrivate === "true" && e.target.value==="true"){
|
||||
ToggleSnackbar("top", "right","私有空间无法开启此功能", "warning");
|
||||
return
|
||||
onChange={e => {
|
||||
if (
|
||||
policy.IsPrivate === "true" &&
|
||||
e.target.value === "true"
|
||||
) {
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"私有空间无法开启此功能",
|
||||
"warning"
|
||||
);
|
||||
return;
|
||||
}
|
||||
handleChange(
|
||||
"IsOriginLinkEnable"
|
||||
)(e)
|
||||
handleChange("IsOriginLinkEnable")(
|
||||
e
|
||||
);
|
||||
}}
|
||||
row
|
||||
>
|
||||
|
|
@ -755,10 +794,7 @@ export default function COSGuide(props) {
|
|||
)}
|
||||
|
||||
{activeStep === 3 && (
|
||||
<form
|
||||
className={classes.stepContent}
|
||||
onSubmit={submitPolicy}
|
||||
>
|
||||
<form className={classes.stepContent} onSubmit={submitPolicy}>
|
||||
<div className={classes.subStepContainer}>
|
||||
<div className={classes.stepNumberContainer}>
|
||||
<div className={classes.stepNumber}>1</div>
|
||||
|
|
@ -952,11 +988,13 @@ export default function COSGuide(props) {
|
|||
{activeStep === 4 && (
|
||||
<form className={classes.stepContent}>
|
||||
<div className={classes.subStepContainer}>
|
||||
<div className={classes.stepNumberContainer}/>
|
||||
<div className={classes.stepNumberContainer} />
|
||||
<div className={classes.subStepContent}>
|
||||
<Typography variant={"body2"}>
|
||||
COS 存储桶 需要正确配置跨域策略后才能使用 Web 端上传文件,Cloudreve
|
||||
可以帮您自动设置,您也可以参考文档步骤手动设置。如果您已设置过此 Bucket 的跨域策略,此步骤可以跳过。
|
||||
COS 存储桶 需要正确配置跨域策略后才能使用 Web
|
||||
端上传文件,Cloudreve
|
||||
可以帮您自动设置,您也可以参考文档步骤手动设置。如果您已设置过此
|
||||
Bucket 的跨域策略,此步骤可以跳过。
|
||||
</Typography>
|
||||
<div className={classes.form}>
|
||||
<Button
|
||||
|
|
@ -964,7 +1002,7 @@ export default function COSGuide(props) {
|
|||
color={"secondary"}
|
||||
variant={"contained"}
|
||||
className={classes.button}
|
||||
onClick={()=>createCORS()}
|
||||
onClick={() => createCORS()}
|
||||
classes={{ label: classes.viewButtonLabel }}
|
||||
>
|
||||
让 Cloudreve 帮我设置
|
||||
|
|
@ -976,16 +1014,18 @@ export default function COSGuide(props) {
|
|||
<Button
|
||||
color={"default"}
|
||||
className={classes.button}
|
||||
onClick={()=>{
|
||||
setActiveStep(prevActiveStep => prevActiveStep + 1);
|
||||
onClick={() => {
|
||||
setActiveStep(
|
||||
prevActiveStep => prevActiveStep + 1
|
||||
);
|
||||
setSkipped(prevSkipped => {
|
||||
const newSkipped = new Set(prevSkipped.values());
|
||||
const newSkipped = new Set(
|
||||
prevSkipped.values()
|
||||
);
|
||||
newSkipped.add(activeStep);
|
||||
return newSkipped;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}}
|
||||
>
|
||||
跳过
|
||||
</Button>{" "}
|
||||
|
|
@ -996,16 +1036,28 @@ export default function COSGuide(props) {
|
|||
{activeStep === 5 && (
|
||||
<form className={classes.stepContent}>
|
||||
<div className={classes.subStepContainer}>
|
||||
<div className={classes.stepNumberContainer}/>
|
||||
<div className={classes.stepNumberContainer} />
|
||||
<div className={classes.subStepContent}>
|
||||
<Typography variant={"body2"}>
|
||||
COS 存储桶 客户端直传需要借助腾讯云的
|
||||
<Link href={"https://console.cloud.tencent.com/scf/index?rid=16"} target={"_blank"}>云函数</Link>
|
||||
产品以确保上传回调可控。如果您打算将此存储策略自用,或者分配给可信赖用户组,此步骤可以跳过。
|
||||
如果是作为公有使用,请务必创建回调云函数。<br/><br/>
|
||||
<Link
|
||||
href={
|
||||
"https://console.cloud.tencent.com/scf/index?rid=16"
|
||||
}
|
||||
target={"_blank"}
|
||||
>
|
||||
云函数
|
||||
</Link>
|
||||
产品以确保上传回调可控。如果您打算将此存储策略自用,或者分配给可信赖用户组,此步骤可以跳过。
|
||||
如果是作为公有使用,请务必创建回调云函数。
|
||||
<br />
|
||||
<br />
|
||||
</Typography>
|
||||
<Typography variant={"body2"}>
|
||||
Cloudreve 可以尝试帮你自动创建回调云函数,请选择
|
||||
COS 存储桶 所在地域后继续。
|
||||
创建可能会花费数秒钟,请耐心等待。创建前请确保您的腾讯云账号已开启云函数服务。
|
||||
</Typography>
|
||||
<Typography variant={"body2"}>Cloudreve 可以尝试帮你自动创建回调云函数,请选择 COS 存储桶 所在地域后继续。
|
||||
创建可能会花费数秒钟,请耐心等待。创建前请确保您的腾讯云账号已开启云函数服务。</Typography>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl>
|
||||
|
|
@ -1014,19 +1066,41 @@ export default function COSGuide(props) {
|
|||
</InputLabel>
|
||||
<Select
|
||||
value={region}
|
||||
onChange={e=>setRegion(e.target.value)}
|
||||
onChange={e =>
|
||||
setRegion(e.target.value)
|
||||
}
|
||||
required
|
||||
>
|
||||
<MenuItem value={"ap-beijing"}>华北地区(北京)</MenuItem>
|
||||
<MenuItem value={"ap-chengdu"}>西南地区(成都)</MenuItem>
|
||||
<MenuItem value={"ap-guangzhou"}>华南地区(广州)</MenuItem>
|
||||
<MenuItem value={"ap-guangzhou-open"}>华南地区(广州Open)</MenuItem>
|
||||
<MenuItem value={"ap-hongkong"}>港澳台地区(中国香港)</MenuItem>
|
||||
<MenuItem value={"ap-mumbai"}>亚太南部(孟买)</MenuItem>
|
||||
<MenuItem value={"ap-shanghai"}>华东地区(上海)</MenuItem>
|
||||
<MenuItem value={"ap-singapore"}>亚太东南(新加坡)</MenuItem>
|
||||
<MenuItem value={"na-siliconvalley"}>美国西部(硅谷)</MenuItem>
|
||||
<MenuItem value={"na-toronto"}>北美地区(多伦多)</MenuItem>
|
||||
<MenuItem value={"ap-beijing"}>
|
||||
华北地区(北京)
|
||||
</MenuItem>
|
||||
<MenuItem value={"ap-chengdu"}>
|
||||
西南地区(成都)
|
||||
</MenuItem>
|
||||
<MenuItem value={"ap-guangzhou"}>
|
||||
华南地区(广州)
|
||||
</MenuItem>
|
||||
<MenuItem value={"ap-guangzhou-open"}>
|
||||
华南地区(广州Open)
|
||||
</MenuItem>
|
||||
<MenuItem value={"ap-hongkong"}>
|
||||
港澳台地区(中国香港)
|
||||
</MenuItem>
|
||||
<MenuItem value={"ap-mumbai"}>
|
||||
亚太南部(孟买)
|
||||
</MenuItem>
|
||||
<MenuItem value={"ap-shanghai"}>
|
||||
华东地区(上海)
|
||||
</MenuItem>
|
||||
<MenuItem value={"ap-singapore"}>
|
||||
亚太东南(新加坡)
|
||||
</MenuItem>
|
||||
<MenuItem value={"na-siliconvalley"}>
|
||||
美国西部(硅谷)
|
||||
</MenuItem>
|
||||
<MenuItem value={"na-toronto"}>
|
||||
北美地区(多伦多)
|
||||
</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
|
@ -1037,7 +1111,7 @@ export default function COSGuide(props) {
|
|||
color={"secondary"}
|
||||
variant={"contained"}
|
||||
className={classes.button}
|
||||
onClick={()=>creatCallback()}
|
||||
onClick={() => creatCallback()}
|
||||
classes={{ label: classes.viewButtonLabel }}
|
||||
>
|
||||
让 Cloudreve 帮我创建
|
||||
|
|
@ -1049,16 +1123,18 @@ export default function COSGuide(props) {
|
|||
<Button
|
||||
color={"default"}
|
||||
className={classes.button}
|
||||
onClick={()=>{
|
||||
setActiveStep(prevActiveStep => prevActiveStep + 1);
|
||||
onClick={() => {
|
||||
setActiveStep(
|
||||
prevActiveStep => prevActiveStep + 1
|
||||
);
|
||||
setSkipped(prevSkipped => {
|
||||
const newSkipped = new Set(prevSkipped.values());
|
||||
const newSkipped = new Set(
|
||||
prevSkipped.values()
|
||||
);
|
||||
newSkipped.add(activeStep);
|
||||
return newSkipped;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}}
|
||||
>
|
||||
跳过
|
||||
</Button>{" "}
|
||||
|
|
@ -1069,7 +1145,9 @@ export default function COSGuide(props) {
|
|||
{activeStep === 6 && (
|
||||
<>
|
||||
<form className={classes.stepContent}>
|
||||
<Typography>存储策略已{props.policy ? "保存" : "添加"}!</Typography>
|
||||
<Typography>
|
||||
存储策略已{props.policy ? "保存" : "添加"}!
|
||||
</Typography>
|
||||
<Typography variant={"body2"} color={"textSecondary"}>
|
||||
要使用此存储策略,请到用户组管理页面,为相应用户组绑定此存储策略。
|
||||
</Typography>
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ export default function LocalGuide(props) {
|
|||
FileNameRule: "{randomkey8}_{originname}",
|
||||
IsOriginLinkEnable: "false",
|
||||
BaseURL: "",
|
||||
IsPrivate:"true",
|
||||
IsPrivate: "true",
|
||||
MaxSize: "0",
|
||||
OptionsSerialized: {
|
||||
file_type: ""
|
||||
|
|
@ -249,9 +249,9 @@ export default function LocalGuide(props) {
|
|||
可用魔法变量可参考{" "}
|
||||
<Link
|
||||
color={"secondary"}
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
setMagicVar("path")
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
setMagicVar("path");
|
||||
}}
|
||||
>
|
||||
路径魔法变量列表
|
||||
|
|
@ -284,9 +284,9 @@ export default function LocalGuide(props) {
|
|||
可用魔法变量可参考{" "}
|
||||
<Link
|
||||
color={"secondary"}
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
setMagicVar("file")
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
setMagicVar("file");
|
||||
}}
|
||||
>
|
||||
文件名魔法变量列表
|
||||
|
|
|
|||
|
|
@ -95,26 +95,30 @@ export default function RemoteGuide(props) {
|
|||
|
||||
const [activeStep, setActiveStep] = useState(0);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [skipped,] = React.useState(new Set());
|
||||
const [skipped] = React.useState(new Set());
|
||||
const [magicVar, setMagicVar] = useState("");
|
||||
// const [useCDN, setUseCDN] = useState("false");
|
||||
const [policy, setPolicy] = useState(props.policy?props.policy:{
|
||||
Type: "qiniu",
|
||||
Name: "",
|
||||
SecretKey: "",
|
||||
AccessKey: "",
|
||||
BaseURL: "",
|
||||
IsPrivate: "true",
|
||||
DirNameRule: "uploads/{year}/{month}/{day}",
|
||||
AutoRename: "true",
|
||||
FileNameRule: "{randomkey8}_{originname}",
|
||||
IsOriginLinkEnable: "false",
|
||||
MaxSize: "0",
|
||||
OptionsSerialized: {
|
||||
file_type: "",
|
||||
mimetype:"",
|
||||
}
|
||||
});
|
||||
const [policy, setPolicy] = useState(
|
||||
props.policy
|
||||
? props.policy
|
||||
: {
|
||||
Type: "qiniu",
|
||||
Name: "",
|
||||
SecretKey: "",
|
||||
AccessKey: "",
|
||||
BaseURL: "",
|
||||
IsPrivate: "true",
|
||||
DirNameRule: "uploads/{year}/{month}/{day}",
|
||||
AutoRename: "true",
|
||||
FileNameRule: "{randomkey8}_{originname}",
|
||||
IsOriginLinkEnable: "false",
|
||||
MaxSize: "0",
|
||||
OptionsSerialized: {
|
||||
file_type: "",
|
||||
mimetype: ""
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const handleChange = name => event => {
|
||||
setPolicy({
|
||||
|
|
@ -171,7 +175,12 @@ export default function RemoteGuide(props) {
|
|||
policy: policyCopy
|
||||
})
|
||||
.then(() => {
|
||||
ToggleSnackbar("top", "right", "存储策略已"+ (props.policy ? "保存" : "添加"), "success");
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"存储策略已" + (props.policy ? "保存" : "添加"),
|
||||
"success"
|
||||
);
|
||||
setActiveStep(5);
|
||||
})
|
||||
.catch(error => {
|
||||
|
|
@ -186,7 +195,9 @@ export default function RemoteGuide(props) {
|
|||
|
||||
return (
|
||||
<div>
|
||||
<Typography variant={"h6"}>{props.policy ? "修改" : "添加"} 七牛 存储策略</Typography>
|
||||
<Typography variant={"h6"}>
|
||||
{props.policy ? "修改" : "添加"} 七牛 存储策略
|
||||
</Typography>
|
||||
<Stepper activeStep={activeStep}>
|
||||
{steps.map((label, index) => {
|
||||
const stepProps = {};
|
||||
|
|
@ -215,15 +226,14 @@ export default function RemoteGuide(props) {
|
|||
setActiveStep(1);
|
||||
}}
|
||||
>
|
||||
|
||||
<div className={classes.subStepContainer}>
|
||||
<div className={classes.stepNumberContainer}>
|
||||
<div className={classes.stepNumber}>0</div>
|
||||
</div>
|
||||
<div className={classes.subStepContent}>
|
||||
<Typography variant={"body2"}>
|
||||
在使用七牛存储策略前,请确保您在 参数设置 - 站点信息
|
||||
- 站点URL 中填写的 地址与实际相符,并且
|
||||
在使用七牛存储策略前,请确保您在 参数设置 -
|
||||
站点信息 - 站点URL 中填写的 地址与实际相符,并且
|
||||
<strong>能够被外网正常访问</strong>。
|
||||
</Typography>
|
||||
</div>
|
||||
|
|
@ -394,9 +404,9 @@ export default function RemoteGuide(props) {
|
|||
可用魔法变量可参考{" "}
|
||||
<Link
|
||||
color={"secondary"}
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
setMagicVar("path")
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
setMagicVar("path");
|
||||
}}
|
||||
>
|
||||
路径魔法变量列表
|
||||
|
|
@ -429,9 +439,9 @@ export default function RemoteGuide(props) {
|
|||
可用魔法变量可参考{" "}
|
||||
<Link
|
||||
color={"secondary"}
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
setMagicVar("file")
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
setMagicVar("file");
|
||||
}}
|
||||
>
|
||||
文件名魔法变量列表
|
||||
|
|
@ -530,14 +540,22 @@ export default function RemoteGuide(props) {
|
|||
<RadioGroup
|
||||
required
|
||||
value={policy.IsOriginLinkEnable}
|
||||
onChange={e=>{
|
||||
if (policy.IsPrivate === "true" && e.target.value==="true"){
|
||||
ToggleSnackbar("top", "right","私有空间无法开启此功能", "warning");
|
||||
return
|
||||
onChange={e => {
|
||||
if (
|
||||
policy.IsPrivate === "true" &&
|
||||
e.target.value === "true"
|
||||
) {
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"私有空间无法开启此功能",
|
||||
"warning"
|
||||
);
|
||||
return;
|
||||
}
|
||||
handleChange(
|
||||
"IsOriginLinkEnable"
|
||||
)(e)
|
||||
handleChange("IsOriginLinkEnable")(
|
||||
e
|
||||
);
|
||||
}}
|
||||
row
|
||||
>
|
||||
|
|
@ -762,9 +780,9 @@ export default function RemoteGuide(props) {
|
|||
<div className={classes.subStepContainer}>
|
||||
<div className={classes.stepNumberContainer}>
|
||||
<div className={classes.stepNumber}>
|
||||
{getNumber(3,[
|
||||
{getNumber(3, [
|
||||
policy.MaxSize !== "0",
|
||||
policy.OptionsSerialized.file_type !== "",
|
||||
policy.OptionsSerialized.file_type !== ""
|
||||
])}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -789,8 +807,7 @@ export default function RemoteGuide(props) {
|
|||
...policy,
|
||||
OptionsSerialized: {
|
||||
...policy.OptionsSerialized,
|
||||
mimetype:
|
||||
"image/*"
|
||||
mimetype: "image/*"
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
|
@ -829,16 +846,18 @@ export default function RemoteGuide(props) {
|
|||
<div className={classes.subStepContainer}>
|
||||
<div className={classes.stepNumberContainer}>
|
||||
<div className={classes.stepNumber}>
|
||||
{getNumber(4,[
|
||||
{getNumber(4, [
|
||||
policy.MaxSize !== "0",
|
||||
policy.OptionsSerialized.file_type !== "",
|
||||
policy.OptionsSerialized.file_type !==
|
||||
""
|
||||
])}
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes.subStepContent}>
|
||||
<Typography variant={"body2"}>
|
||||
输入允许上传的 MimeType,多个请以半角逗号 ,
|
||||
隔开。七牛服务器会侦测文件内容以判断 MimeType,再用判断值跟指定值进行匹配,匹配成功则允许上传
|
||||
隔开。七牛服务器会侦测文件内容以判断
|
||||
MimeType,再用判断值跟指定值进行匹配,匹配成功则允许上传
|
||||
</Typography>
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
|
|
@ -925,7 +944,9 @@ export default function RemoteGuide(props) {
|
|||
{activeStep === 5 && (
|
||||
<>
|
||||
<form className={classes.stepContent}>
|
||||
<Typography>存储策略已{props.policy ? "保存" : "添加"}!</Typography>
|
||||
<Typography>
|
||||
存储策略已{props.policy ? "保存" : "添加"}!
|
||||
</Typography>
|
||||
<Typography variant={"body2"} color={"textSecondary"}>
|
||||
要使用此存储策略,请到用户组管理页面,为相应用户组绑定此存储策略。
|
||||
</Typography>
|
||||
|
|
|
|||
|
|
@ -39,13 +39,13 @@ const useStyles = makeStyles(theme => ({
|
|||
subStepContainer: {
|
||||
display: "flex",
|
||||
marginBottom: 20,
|
||||
padding:10,
|
||||
padding: 10,
|
||||
transition: theme.transitions.create("background-color", {
|
||||
easing: theme.transitions.easing.sharp,
|
||||
duration: theme.transitions.duration.leavingScreen
|
||||
}),
|
||||
"&:focus-within":{
|
||||
backgroundColor:theme.palette.background.default,
|
||||
"&:focus-within": {
|
||||
backgroundColor: theme.palette.background.default
|
||||
}
|
||||
},
|
||||
stepNumber: {
|
||||
|
|
@ -57,35 +57,35 @@ const useStyles = makeStyles(theme => ({
|
|||
borderRadius: " 50%"
|
||||
},
|
||||
stepNumberContainer: {
|
||||
marginRight: 10,
|
||||
marginRight: 10
|
||||
},
|
||||
stepFooter:{
|
||||
marginTop: 32,
|
||||
stepFooter: {
|
||||
marginTop: 32
|
||||
},
|
||||
button: {
|
||||
marginRight: theme.spacing(1),
|
||||
marginRight: theme.spacing(1)
|
||||
},
|
||||
"@global":{
|
||||
"code":{
|
||||
"@global": {
|
||||
code: {
|
||||
color: "rgba(0, 0, 0, 0.87)",
|
||||
display: "inline-block",
|
||||
padding: "2px 6px",
|
||||
fontSize: "14px",
|
||||
fontFamily:" Consolas, \"Liberation Mono\", Menlo, Courier, monospace",
|
||||
fontFamily:
|
||||
' Consolas, "Liberation Mono", Menlo, Courier, monospace',
|
||||
borderRadius: "2px",
|
||||
backgroundColor: "rgba(255,229,100,0.1)",
|
||||
backgroundColor: "rgba(255,229,100,0.1)"
|
||||
},
|
||||
"pre":{
|
||||
pre: {
|
||||
margin: "24px 0",
|
||||
padding: "12px 18px",
|
||||
overflow: "auto",
|
||||
direction: "ltr",
|
||||
borderRadius: "4px",
|
||||
backgroundColor: "#272c34",
|
||||
color:"#fff",
|
||||
color: "#fff"
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
}));
|
||||
|
||||
const steps = [
|
||||
|
|
@ -117,25 +117,29 @@ export default function RemoteGuide(props) {
|
|||
|
||||
const [activeStep, setActiveStep] = useState(0);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [skipped,] = React.useState(new Set());
|
||||
const [magicVar,setMagicVar] = useState("");
|
||||
const [useCDN,setUseCDN] = useState("false");
|
||||
const [policy, setPolicy] = useState(props.policy?props.policy:{
|
||||
Type:"remote",
|
||||
Name:"",
|
||||
Server:"https://example.com:5212",
|
||||
SecretKey:randomStr(64),
|
||||
DirNameRule: "uploads/{year}/{month}/{day}",
|
||||
AutoRename: "true",
|
||||
FileNameRule: "{randomkey8}_{originname}",
|
||||
IsOriginLinkEnable:"false",
|
||||
BaseURL:"",
|
||||
IsPrivate:"true",
|
||||
MaxSize:"0",
|
||||
OptionsSerialized:{
|
||||
file_type:"",
|
||||
},
|
||||
});
|
||||
const [skipped] = React.useState(new Set());
|
||||
const [magicVar, setMagicVar] = useState("");
|
||||
const [useCDN, setUseCDN] = useState("false");
|
||||
const [policy, setPolicy] = useState(
|
||||
props.policy
|
||||
? props.policy
|
||||
: {
|
||||
Type: "remote",
|
||||
Name: "",
|
||||
Server: "https://example.com:5212",
|
||||
SecretKey: randomStr(64),
|
||||
DirNameRule: "uploads/{year}/{month}/{day}",
|
||||
AutoRename: "true",
|
||||
FileNameRule: "{randomkey8}_{originname}",
|
||||
IsOriginLinkEnable: "false",
|
||||
BaseURL: "",
|
||||
IsPrivate: "true",
|
||||
MaxSize: "0",
|
||||
OptionsSerialized: {
|
||||
file_type: ""
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const handleChange = name => event => {
|
||||
setPolicy({
|
||||
|
|
@ -147,10 +151,10 @@ export default function RemoteGuide(props) {
|
|||
const handleOptionChange = name => event => {
|
||||
setPolicy({
|
||||
...policy,
|
||||
OptionsSerialized:{
|
||||
OptionsSerialized: {
|
||||
...policy.OptionsSerialized,
|
||||
[name]: event.target.value
|
||||
},
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -165,13 +169,13 @@ export default function RemoteGuide(props) {
|
|||
[dispatch]
|
||||
);
|
||||
|
||||
const testSlave = ()=>{
|
||||
const testSlave = () => {
|
||||
setLoading(true);
|
||||
|
||||
// 测试路径是否可用
|
||||
API.post("/admin/policy/test/slave", {
|
||||
server: policy.Server,
|
||||
secret:policy.SecretKey,
|
||||
secret: policy.SecretKey
|
||||
})
|
||||
.then(() => {
|
||||
ToggleSnackbar("top", "right", "通信正常", "success");
|
||||
|
|
@ -188,21 +192,27 @@ export default function RemoteGuide(props) {
|
|||
e.preventDefault();
|
||||
setLoading(true);
|
||||
|
||||
const policyCopy = {...policy};
|
||||
policyCopy.OptionsSerialized = {...policyCopy.OptionsSerialized};
|
||||
const policyCopy = { ...policy };
|
||||
policyCopy.OptionsSerialized = { ...policyCopy.OptionsSerialized };
|
||||
|
||||
// 处理存储策略
|
||||
if (useCDN === "false" || policy.IsOriginLinkEnable === "false"){
|
||||
policyCopy.BaseURL = ""
|
||||
if (useCDN === "false" || policy.IsOriginLinkEnable === "false") {
|
||||
policyCopy.BaseURL = "";
|
||||
}
|
||||
|
||||
// 类型转换
|
||||
policyCopy.AutoRename = policyCopy.AutoRename === "true";
|
||||
policyCopy.IsOriginLinkEnable = policyCopy.IsOriginLinkEnable === "true";
|
||||
policyCopy.IsOriginLinkEnable =
|
||||
policyCopy.IsOriginLinkEnable === "true";
|
||||
policyCopy.MaxSize = parseInt(policyCopy.MaxSize);
|
||||
policyCopy.IsPrivate = policyCopy.IsPrivate === "true";
|
||||
policyCopy.OptionsSerialized.file_type = policyCopy.OptionsSerialized.file_type.split(",");
|
||||
if (policyCopy.OptionsSerialized.file_type.length === 1 && policyCopy.OptionsSerialized.file_type[0] === ""){
|
||||
policyCopy.OptionsSerialized.file_type = policyCopy.OptionsSerialized.file_type.split(
|
||||
","
|
||||
);
|
||||
if (
|
||||
policyCopy.OptionsSerialized.file_type.length === 1 &&
|
||||
policyCopy.OptionsSerialized.file_type[0] === ""
|
||||
) {
|
||||
policyCopy.OptionsSerialized.file_type = [];
|
||||
}
|
||||
|
||||
|
|
@ -210,7 +220,12 @@ export default function RemoteGuide(props) {
|
|||
policy: policyCopy
|
||||
})
|
||||
.then(() => {
|
||||
ToggleSnackbar("top", "right", "存储策略已" + (props.policy ? "保存" : "添加"), "success");
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"存储策略已" + (props.policy ? "保存" : "添加"),
|
||||
"success"
|
||||
);
|
||||
setActiveStep(5);
|
||||
})
|
||||
.catch(error => {
|
||||
|
|
@ -221,12 +236,13 @@ export default function RemoteGuide(props) {
|
|||
});
|
||||
|
||||
setLoading(false);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Typography variant={"h6"}>{props.policy ? "修改" : "添加"}从机存储策略</Typography>
|
||||
<Typography variant={"h6"}>
|
||||
{props.policy ? "修改" : "添加"}从机存储策略
|
||||
</Typography>
|
||||
<Stepper activeStep={activeStep}>
|
||||
{steps.map((label, index) => {
|
||||
const stepProps = {};
|
||||
|
|
@ -250,14 +266,14 @@ export default function RemoteGuide(props) {
|
|||
{activeStep === 0 && (
|
||||
<form
|
||||
className={classes.stepContent}
|
||||
onSubmit={e=>{
|
||||
onSubmit={e => {
|
||||
e.preventDefault();
|
||||
setActiveStep(1);
|
||||
}}
|
||||
>
|
||||
<Alert severity="info" style={{marginBottom:10,}}>
|
||||
从机存储策略允许你使用同样运行了 Cloudreve 的服务器作为存储端,
|
||||
用户上传下载流量通过 HTTP 直传。
|
||||
<Alert severity="info" style={{ marginBottom: 10 }}>
|
||||
从机存储策略允许你使用同样运行了 Cloudreve
|
||||
的服务器作为存储端, 用户上传下载流量通过 HTTP 直传。
|
||||
</Alert>
|
||||
|
||||
<div className={classes.subStepContainer}>
|
||||
|
|
@ -266,7 +282,8 @@ export default function RemoteGuide(props) {
|
|||
</div>
|
||||
<div className={classes.subStepContent}>
|
||||
<Typography variant={"body2"}>
|
||||
将和主站相同版本的 Cloudreve 程序拷贝至要作为从机的服务器上。
|
||||
将和主站相同版本的 Cloudreve
|
||||
程序拷贝至要作为从机的服务器上。
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -288,7 +305,7 @@ export default function RemoteGuide(props) {
|
|||
<Input
|
||||
required
|
||||
inputProps={{
|
||||
minlength:64,
|
||||
minlength: 64
|
||||
}}
|
||||
value={policy.SecretKey}
|
||||
onChange={handleChange("SecretKey")}
|
||||
|
|
@ -304,23 +321,33 @@ export default function RemoteGuide(props) {
|
|||
</div>
|
||||
<div className={classes.subStepContent}>
|
||||
<Typography variant={"body2"}>
|
||||
修改从机配置文件。<br/>在从机端 Cloudreve 的同级目录下新建
|
||||
<code>conf.ini</code>文件,填入从机配置,启动/重启从机端 Cloudreve。
|
||||
修改从机配置文件。
|
||||
<br />
|
||||
在从机端 Cloudreve 的同级目录下新建
|
||||
<code>conf.ini</code>
|
||||
文件,填入从机配置,启动/重启从机端 Cloudreve。
|
||||
以下为一个可供参考的配置例子,其中密钥部分已帮您填写为上一步所生成的。
|
||||
</Typography>
|
||||
<pre>
|
||||
[System]<br/>
|
||||
Mode = slave<br/>
|
||||
Listen = :5212<br/>
|
||||
<br/>
|
||||
[Slave]<br/>
|
||||
Secret = {policy.SecretKey}<br/>
|
||||
<br/>
|
||||
[CORS]<br/>
|
||||
AllowOrigins = *<br/>
|
||||
AllowMethods = OPTIONS,GET,POST<br/>
|
||||
AllowHeaders = *<br/>
|
||||
</pre>
|
||||
<pre>
|
||||
[System]
|
||||
<br />
|
||||
Mode = slave
|
||||
<br />
|
||||
Listen = :5212
|
||||
<br />
|
||||
<br />
|
||||
[Slave]
|
||||
<br />
|
||||
Secret = {policy.SecretKey}
|
||||
<br />
|
||||
<br />
|
||||
[CORS]
|
||||
<br />
|
||||
AllowOrigins = *<br />
|
||||
AllowMethods = OPTIONS,GET,POST
|
||||
<br />
|
||||
AllowHeaders = *<br />
|
||||
</pre>
|
||||
<Typography variant={"body2"}>
|
||||
从机端配置文件格式大致与主站端相同,区别在于:
|
||||
<ul>
|
||||
|
|
@ -331,11 +358,15 @@ export default function RemoteGuide(props) {
|
|||
字段必须更改为<code>slave</code>
|
||||
</li>
|
||||
<li>
|
||||
必须指定<code>Slave</code>分区下的<code>Secret</code>
|
||||
必须指定<code>Slave</code>分区下的
|
||||
<code>Secret</code>
|
||||
字段,其值为第二步里填写或生成的密钥。
|
||||
</li>
|
||||
<li>必须启动跨域配置,即<code>CORS</code>字段的内容,
|
||||
具体可参考上文范例或官方文档。如果配置不正确,用户将无法通过 Web 端向从机上传文件。
|
||||
<li>
|
||||
必须启动跨域配置,即<code>CORS</code>
|
||||
字段的内容,
|
||||
具体可参考上文范例或官方文档。如果配置不正确,用户将无法通过
|
||||
Web 端向从机上传文件。
|
||||
</li>
|
||||
</ul>
|
||||
</Typography>
|
||||
|
|
@ -348,8 +379,11 @@ export default function RemoteGuide(props) {
|
|||
</div>
|
||||
<div className={classes.subStepContent}>
|
||||
<Typography variant={"body2"}>
|
||||
填写从机地址。<br/>
|
||||
如果主站启用了 HTTPS,从机也需要启用,并在下方填入 HTTPS 协议的地址。
|
||||
填写从机地址。
|
||||
<br />
|
||||
如果主站启用了
|
||||
HTTPS,从机也需要启用,并在下方填入 HTTPS
|
||||
协议的地址。
|
||||
</Typography>
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
|
|
@ -379,7 +413,7 @@ export default function RemoteGuide(props) {
|
|||
<div className={classes.form}>
|
||||
<Button
|
||||
disabled={loading}
|
||||
onClick={()=>testSlave()}
|
||||
onClick={() => testSlave()}
|
||||
variant={"outlined"}
|
||||
color={"primary"}
|
||||
>
|
||||
|
|
@ -399,14 +433,13 @@ export default function RemoteGuide(props) {
|
|||
下一步
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
)}
|
||||
|
||||
{activeStep === 1 && (
|
||||
<form
|
||||
className={classes.stepContent}
|
||||
onSubmit={e=> {
|
||||
onSubmit={e => {
|
||||
e.preventDefault();
|
||||
setActiveStep(2);
|
||||
}}
|
||||
|
|
@ -418,13 +451,14 @@ export default function RemoteGuide(props) {
|
|||
<div className={classes.subStepContent}>
|
||||
<Typography variant={"body2"}>
|
||||
请在下方输入文件的存储目录路径,可以为绝对路径或相对路径(相对于
|
||||
从机的 Cloudreve)。路径中可以使用魔法变量,文件在上传时会自动替换这些变量为相应值;
|
||||
从机的
|
||||
Cloudreve)。路径中可以使用魔法变量,文件在上传时会自动替换这些变量为相应值;
|
||||
可用魔法变量可参考{" "}
|
||||
<Link
|
||||
color={"secondary"}
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
setMagicVar("path")
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
setMagicVar("path");
|
||||
}}
|
||||
>
|
||||
路径魔法变量列表
|
||||
|
|
@ -457,9 +491,9 @@ export default function RemoteGuide(props) {
|
|||
可用魔法变量可参考{" "}
|
||||
<Link
|
||||
color={"secondary"}
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
setMagicVar("file")
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
setMagicVar("file");
|
||||
}}
|
||||
>
|
||||
文件名魔法变量列表
|
||||
|
|
@ -500,7 +534,9 @@ export default function RemoteGuide(props) {
|
|||
命名规则
|
||||
</InputLabel>
|
||||
<Input
|
||||
required={policy.AutoRename === "true"}
|
||||
required={
|
||||
policy.AutoRename === "true"
|
||||
}
|
||||
value={policy.FileNameRule}
|
||||
onChange={handleChange(
|
||||
"FileNameRule"
|
||||
|
|
@ -516,7 +552,7 @@ export default function RemoteGuide(props) {
|
|||
<Button
|
||||
color={"default"}
|
||||
className={classes.button}
|
||||
onClick={()=> setActiveStep(0)}
|
||||
onClick={() => setActiveStep(0)}
|
||||
>
|
||||
上一步
|
||||
</Button>
|
||||
|
|
@ -535,9 +571,9 @@ export default function RemoteGuide(props) {
|
|||
{activeStep === 2 && (
|
||||
<form
|
||||
className={classes.stepContent}
|
||||
onSubmit={e=> {
|
||||
onSubmit={e => {
|
||||
e.preventDefault();
|
||||
setActiveStep(3);
|
||||
setActiveStep(3);
|
||||
}}
|
||||
>
|
||||
<div className={classes.subStepContainer}>
|
||||
|
|
@ -590,7 +626,8 @@ export default function RemoteGuide(props) {
|
|||
<Typography variant={"body2"}>
|
||||
是否要对下载/直链使用 CDN?
|
||||
<br />
|
||||
开启后,用户访问文件时的 URL 中的域名部分会被替换为 CDN 域名。
|
||||
开启后,用户访问文件时的 URL
|
||||
中的域名部分会被替换为 CDN 域名。
|
||||
</Typography>
|
||||
|
||||
<div className={classes.form}>
|
||||
|
|
@ -598,14 +635,16 @@ export default function RemoteGuide(props) {
|
|||
<RadioGroup
|
||||
required
|
||||
value={useCDN}
|
||||
onChange={e=>{
|
||||
if (e.target.value === "false"){
|
||||
onChange={e => {
|
||||
if (
|
||||
e.target.value === "false"
|
||||
) {
|
||||
setPolicy({
|
||||
...policy,
|
||||
BaseURL: ""
|
||||
});
|
||||
}
|
||||
setUseCDN(e.target.value)
|
||||
setUseCDN(e.target.value);
|
||||
}}
|
||||
row
|
||||
>
|
||||
|
|
@ -626,7 +665,6 @@ export default function RemoteGuide(props) {
|
|||
</RadioGroup>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -644,26 +682,26 @@ export default function RemoteGuide(props) {
|
|||
<DomainInput
|
||||
value={policy.BaseURL}
|
||||
onChange={handleChange("BaseURL")}
|
||||
required={policy.IsOriginLinkEnable === "true" && useCDN === "true"}
|
||||
required={
|
||||
policy.IsOriginLinkEnable ===
|
||||
"true" && useCDN === "true"
|
||||
}
|
||||
label={"CDN 前缀"}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</Collapse>
|
||||
|
||||
</Collapse>
|
||||
|
||||
<div className={classes.stepFooter}>
|
||||
<Button
|
||||
color={"default"}
|
||||
className={classes.button}
|
||||
onClick={()=> setActiveStep(1)}
|
||||
onClick={() => setActiveStep(1)}
|
||||
>
|
||||
上一步
|
||||
</Button>
|
||||
{" "}
|
||||
</Button>{" "}
|
||||
<Button
|
||||
disabled={loading}
|
||||
type={"submit"}
|
||||
|
|
@ -673,18 +711,17 @@ export default function RemoteGuide(props) {
|
|||
下一步
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
)}
|
||||
|
||||
{activeStep === 3 && (
|
||||
<form className={classes.stepContent}
|
||||
onSubmit={e=> {
|
||||
e.preventDefault();
|
||||
setActiveStep(4)
|
||||
}}
|
||||
<form
|
||||
className={classes.stepContent}
|
||||
onSubmit={e => {
|
||||
e.preventDefault();
|
||||
setActiveStep(4);
|
||||
}}
|
||||
>
|
||||
|
||||
<div className={classes.subStepContainer}>
|
||||
<div className={classes.stepNumberContainer}>
|
||||
<div className={classes.stepNumber}>1</div>
|
||||
|
|
@ -698,17 +735,21 @@ export default function RemoteGuide(props) {
|
|||
<FormControl required component="fieldset">
|
||||
<RadioGroup
|
||||
required
|
||||
value={policy.MaxSize === "0" ? "false" : "true"}
|
||||
onChange={e=>{
|
||||
if(e.target.value === "true"){
|
||||
value={
|
||||
policy.MaxSize === "0"
|
||||
? "false"
|
||||
: "true"
|
||||
}
|
||||
onChange={e => {
|
||||
if (e.target.value === "true") {
|
||||
setPolicy({
|
||||
...policy,
|
||||
MaxSize: "10485760",
|
||||
MaxSize: "10485760"
|
||||
});
|
||||
}else{
|
||||
} else {
|
||||
setPolicy({
|
||||
...policy,
|
||||
MaxSize: "0",
|
||||
MaxSize: "0"
|
||||
});
|
||||
}
|
||||
}}
|
||||
|
|
@ -752,15 +793,15 @@ export default function RemoteGuide(props) {
|
|||
label={"单文件大小限制"}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</Collapse>
|
||||
|
||||
<div className={classes.subStepContainer}>
|
||||
<div className={classes.stepNumberContainer}>
|
||||
<div className={classes.stepNumber}>{policy.MaxSize !== "0" ? "3" : "2"}</div>
|
||||
<div className={classes.stepNumber}>
|
||||
{policy.MaxSize !== "0" ? "3" : "2"}
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes.subStepContent}>
|
||||
<Typography variant={"body2"}>
|
||||
|
|
@ -771,23 +812,29 @@ export default function RemoteGuide(props) {
|
|||
<FormControl required component="fieldset">
|
||||
<RadioGroup
|
||||
required
|
||||
value={policy.OptionsSerialized.file_type === "" ? "false" : "true"}
|
||||
onChange={e=>{
|
||||
if(e.target.value === "true"){
|
||||
value={
|
||||
policy.OptionsSerialized
|
||||
.file_type === ""
|
||||
? "false"
|
||||
: "true"
|
||||
}
|
||||
onChange={e => {
|
||||
if (e.target.value === "true") {
|
||||
setPolicy({
|
||||
...policy,
|
||||
OptionsSerialized: {
|
||||
...policy.OptionsSerialized,
|
||||
file_type:"jpg,png,mp4,zip,rar",
|
||||
},
|
||||
file_type:
|
||||
"jpg,png,mp4,zip,rar"
|
||||
}
|
||||
});
|
||||
}else{
|
||||
} else {
|
||||
setPolicy({
|
||||
...policy,
|
||||
OptionsSerialized: {
|
||||
...policy.OptionsSerialized,
|
||||
file_type:"",
|
||||
},
|
||||
file_type: ""
|
||||
}
|
||||
});
|
||||
}
|
||||
}}
|
||||
|
|
@ -816,11 +863,14 @@ export default function RemoteGuide(props) {
|
|||
<Collapse in={policy.OptionsSerialized.file_type !== ""}>
|
||||
<div className={classes.subStepContainer}>
|
||||
<div className={classes.stepNumberContainer}>
|
||||
<div className={classes.stepNumber}>{policy.MaxSize !== "0" ? "4" : "3"}</div>
|
||||
<div className={classes.stepNumber}>
|
||||
{policy.MaxSize !== "0" ? "4" : "3"}
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes.subStepContent}>
|
||||
<Typography variant={"body2"}>
|
||||
输入允许上传的文件扩展名,多个请以半角逗号 , 隔开
|
||||
输入允许上传的文件扩展名,多个请以半角逗号 ,
|
||||
隔开
|
||||
</Typography>
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
|
|
@ -828,28 +878,28 @@ export default function RemoteGuide(props) {
|
|||
扩展名列表
|
||||
</InputLabel>
|
||||
<Input
|
||||
value={policy.OptionsSerialized.file_type}
|
||||
value={
|
||||
policy.OptionsSerialized
|
||||
.file_type
|
||||
}
|
||||
onChange={handleOptionChange(
|
||||
"file_type"
|
||||
)}
|
||||
/>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</Collapse>
|
||||
|
||||
<div className={classes.stepFooter}>
|
||||
<Button
|
||||
color={"default"}
|
||||
className={classes.button}
|
||||
onClick={()=> setActiveStep(2)}
|
||||
onClick={() => setActiveStep(2)}
|
||||
>
|
||||
上一步
|
||||
</Button>
|
||||
{" "}
|
||||
</Button>{" "}
|
||||
<Button
|
||||
disabled={loading}
|
||||
type={"submit"}
|
||||
|
|
@ -859,16 +909,13 @@ export default function RemoteGuide(props) {
|
|||
下一步
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
)}
|
||||
|
||||
{activeStep === 4 && (
|
||||
<form className={classes.stepContent} onSubmit={submitPolicy}>
|
||||
<div className={classes.subStepContainer}>
|
||||
<div className={classes.stepNumberContainer}>
|
||||
|
||||
</div>
|
||||
<div className={classes.stepNumberContainer}></div>
|
||||
<div className={classes.subStepContent}>
|
||||
<Typography variant={"body2"}>
|
||||
最后一步,为此存储策略命名:
|
||||
|
|
@ -891,11 +938,10 @@ export default function RemoteGuide(props) {
|
|||
<Button
|
||||
color={"default"}
|
||||
className={classes.button}
|
||||
onClick={()=> setActiveStep(3)}
|
||||
onClick={() => setActiveStep(3)}
|
||||
>
|
||||
上一步
|
||||
</Button>
|
||||
{" "}
|
||||
</Button>{" "}
|
||||
<Button
|
||||
disabled={loading}
|
||||
type={"submit"}
|
||||
|
|
@ -905,31 +951,30 @@ export default function RemoteGuide(props) {
|
|||
完成
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
)}
|
||||
|
||||
{activeStep === 5 && (
|
||||
<>
|
||||
<form className={classes.stepContent}>
|
||||
<Typography>
|
||||
存储策略已{props.policy ? "保存" : "添加"}!
|
||||
</Typography>
|
||||
<Typography variant={"body2"} color={"textSecondary"}>
|
||||
要使用此存储策略,请到用户组管理页面,为相应用户组绑定此存储策略。
|
||||
</Typography>
|
||||
</form>
|
||||
<form className={classes.stepContent}>
|
||||
<Typography>
|
||||
存储策略已{props.policy ? "保存" : "添加"}!
|
||||
</Typography>
|
||||
<Typography variant={"body2"} color={"textSecondary"}>
|
||||
要使用此存储策略,请到用户组管理页面,为相应用户组绑定此存储策略。
|
||||
</Typography>
|
||||
</form>
|
||||
<div className={classes.stepFooter}>
|
||||
<Button
|
||||
color={"primary"}
|
||||
className={classes.button}
|
||||
onClick={()=> history.push("/admin/policy")}
|
||||
onClick={() => history.push("/admin/policy")}
|
||||
>
|
||||
返回存储策略列表
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
<MagicVar
|
||||
open={magicVar === "file"}
|
||||
|
|
|
|||
|
|
@ -118,29 +118,29 @@ const steps = [
|
|||
];
|
||||
|
||||
const regions = {
|
||||
"us-east-2":"US East (Ohio)",
|
||||
"us-east-1":"US East (N. Virginia)",
|
||||
"us-west-1":"US West (N. California)",
|
||||
"us-west-2":"US West (Oregon)",
|
||||
"af-south-1":"Africa (Cape Town)",
|
||||
"ap-east-1":"Asia Pacific (Hong Kong)",
|
||||
"ap-south-1":"Asia Pacific (Mumbai)",
|
||||
"ap-northeast-3":"Asia Pacific (Osaka-Local)",
|
||||
"ap-northeast-2":"Asia Pacific (Seoul)",
|
||||
"ap-southeast-1":"Asia Pacific (Singapore)",
|
||||
"ap-southeast-2":"Asia Pacific (Sydney)",
|
||||
"ap-northeast-1":"Asia Pacific (Tokyo)",
|
||||
"ca-central-1":"Canada (Central)",
|
||||
"cn-north-1":"China (Beijing)",
|
||||
"cn-northwest-1":"China (Ningxia)",
|
||||
"eu-central-1":"Europe (Frankfurt)",
|
||||
"eu-west-1":"Europe (Ireland)",
|
||||
"eu-west-2":"Europe (London)",
|
||||
"eu-south-1":"Europe (Milan)",
|
||||
"eu-west-3":"Europe (Paris)",
|
||||
"eu-north-1":"Europe (Stockholm)",
|
||||
"me-south-1":"Middle East (Bahrain)",
|
||||
"sa-east-1":"South America (São Paulo)",
|
||||
"us-east-2": "US East (Ohio)",
|
||||
"us-east-1": "US East (N. Virginia)",
|
||||
"us-west-1": "US West (N. California)",
|
||||
"us-west-2": "US West (Oregon)",
|
||||
"af-south-1": "Africa (Cape Town)",
|
||||
"ap-east-1": "Asia Pacific (Hong Kong)",
|
||||
"ap-south-1": "Asia Pacific (Mumbai)",
|
||||
"ap-northeast-3": "Asia Pacific (Osaka-Local)",
|
||||
"ap-northeast-2": "Asia Pacific (Seoul)",
|
||||
"ap-southeast-1": "Asia Pacific (Singapore)",
|
||||
"ap-southeast-2": "Asia Pacific (Sydney)",
|
||||
"ap-northeast-1": "Asia Pacific (Tokyo)",
|
||||
"ca-central-1": "Canada (Central)",
|
||||
"cn-north-1": "China (Beijing)",
|
||||
"cn-northwest-1": "China (Ningxia)",
|
||||
"eu-central-1": "Europe (Frankfurt)",
|
||||
"eu-west-1": "Europe (Ireland)",
|
||||
"eu-west-2": "Europe (London)",
|
||||
"eu-south-1": "Europe (Milan)",
|
||||
"eu-west-3": "Europe (Paris)",
|
||||
"eu-north-1": "Europe (Stockholm)",
|
||||
"me-south-1": "Middle East (Bahrain)",
|
||||
"sa-east-1": "South America (São Paulo)"
|
||||
};
|
||||
|
||||
export default function S3Guide(props) {
|
||||
|
|
@ -171,7 +171,7 @@ export default function S3Guide(props) {
|
|||
MaxSize: "0",
|
||||
OptionsSerialized: {
|
||||
file_type: "",
|
||||
region: "us-east-2",
|
||||
region: "us-east-2"
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
@ -278,9 +278,11 @@ export default function S3Guide(props) {
|
|||
<div>
|
||||
<AlertDialog
|
||||
open={alertOpen}
|
||||
onClose={()=>setAlertOpen(false)}
|
||||
onClose={() => setAlertOpen(false)}
|
||||
title={"警告"}
|
||||
msg={"S3 类型存储策略目前仅可用于自己使用,或者是给受信任的用户组使用。"}
|
||||
msg={
|
||||
"S3 类型存储策略目前仅可用于自己使用,或者是给受信任的用户组使用。"
|
||||
}
|
||||
/>
|
||||
<Typography variant={"h6"}>
|
||||
{props.policy ? "修改" : "添加"} Amazon S3 存储策略
|
||||
|
|
@ -436,9 +438,11 @@ export default function S3Guide(props) {
|
|||
freeSolo
|
||||
value={policy.OptionsSerialized.region}
|
||||
onInputChange={(_, value) =>
|
||||
handleOptionChange("region")({target:{value:value}})
|
||||
handleOptionChange("region")({
|
||||
target: { value: value }
|
||||
})
|
||||
}
|
||||
renderOption={(option) => (
|
||||
renderOption={option => (
|
||||
<React.Fragment>
|
||||
{regions[option]}
|
||||
</React.Fragment>
|
||||
|
|
|
|||
|
|
@ -94,25 +94,29 @@ export default function UpyunGuide(props) {
|
|||
|
||||
const [activeStep, setActiveStep] = useState(0);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [skipped,] = React.useState(new Set());
|
||||
const [skipped] = React.useState(new Set());
|
||||
const [magicVar, setMagicVar] = useState("");
|
||||
const [policy, setPolicy] = useState(props.policy?props.policy:{
|
||||
Type: "upyun",
|
||||
Name: "",
|
||||
SecretKey: "",
|
||||
AccessKey: "",
|
||||
BaseURL: "",
|
||||
IsPrivate: "false",
|
||||
DirNameRule: "uploads/{year}/{month}/{day}",
|
||||
AutoRename: "true",
|
||||
FileNameRule: "{randomkey8}_{originname}",
|
||||
IsOriginLinkEnable: "false",
|
||||
MaxSize: "0",
|
||||
OptionsSerialized: {
|
||||
file_type: "",
|
||||
token:"",
|
||||
}
|
||||
});
|
||||
const [policy, setPolicy] = useState(
|
||||
props.policy
|
||||
? props.policy
|
||||
: {
|
||||
Type: "upyun",
|
||||
Name: "",
|
||||
SecretKey: "",
|
||||
AccessKey: "",
|
||||
BaseURL: "",
|
||||
IsPrivate: "false",
|
||||
DirNameRule: "uploads/{year}/{month}/{day}",
|
||||
AutoRename: "true",
|
||||
FileNameRule: "{randomkey8}_{originname}",
|
||||
IsOriginLinkEnable: "false",
|
||||
MaxSize: "0",
|
||||
OptionsSerialized: {
|
||||
file_type: "",
|
||||
token: ""
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const handleChange = name => event => {
|
||||
setPolicy({
|
||||
|
|
@ -169,7 +173,12 @@ export default function UpyunGuide(props) {
|
|||
policy: policyCopy
|
||||
})
|
||||
.then(() => {
|
||||
ToggleSnackbar("top", "right", "存储策略已"+ (props.policy ? "保存" : "添加"), "success");
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"存储策略已" + (props.policy ? "保存" : "添加"),
|
||||
"success"
|
||||
);
|
||||
setActiveStep(5);
|
||||
})
|
||||
.catch(error => {
|
||||
|
|
@ -184,7 +193,9 @@ export default function UpyunGuide(props) {
|
|||
|
||||
return (
|
||||
<div>
|
||||
<Typography variant={"h6"}>{props.policy ? "修改" : "添加"} 又拍云 存储策略</Typography>
|
||||
<Typography variant={"h6"}>
|
||||
{props.policy ? "修改" : "添加"} 又拍云 存储策略
|
||||
</Typography>
|
||||
<Stepper activeStep={activeStep}>
|
||||
{steps.map((label, index) => {
|
||||
const stepProps = {};
|
||||
|
|
@ -213,15 +224,14 @@ export default function UpyunGuide(props) {
|
|||
setActiveStep(1);
|
||||
}}
|
||||
>
|
||||
|
||||
<div className={classes.subStepContainer}>
|
||||
<div className={classes.stepNumberContainer}>
|
||||
<div className={classes.stepNumber}>0</div>
|
||||
</div>
|
||||
<div className={classes.subStepContent}>
|
||||
<Typography variant={"body2"}>
|
||||
在使用又拍云存储策略前,请确保您在 参数设置 - 站点信息
|
||||
- 站点URL 中填写的 地址与实际相符,并且
|
||||
在使用又拍云存储策略前,请确保您在 参数设置 -
|
||||
站点信息 - 站点URL 中填写的 地址与实际相符,并且
|
||||
<strong>能够被外网正常访问</strong>。
|
||||
</Typography>
|
||||
</div>
|
||||
|
|
@ -235,7 +245,9 @@ export default function UpyunGuide(props) {
|
|||
<Typography variant={"body2"}>
|
||||
前往
|
||||
<Link
|
||||
href={"https://console.upyun.com/services/create/file/"}
|
||||
href={
|
||||
"https://console.upyun.com/services/create/file/"
|
||||
}
|
||||
target={"_blank"}
|
||||
>
|
||||
又拍云面板
|
||||
|
|
@ -309,7 +321,8 @@ export default function UpyunGuide(props) {
|
|||
</div>
|
||||
<div className={classes.subStepContent}>
|
||||
<Typography variant={"body2"}>
|
||||
填写为云存储服务绑定的域名,并根据实际情况选择是否使用 HTTPS:
|
||||
填写为云存储服务绑定的域名,并根据实际情况选择是否使用
|
||||
HTTPS:
|
||||
</Typography>
|
||||
<div className={classes.form}>
|
||||
<DomainInput
|
||||
|
|
@ -328,8 +341,10 @@ export default function UpyunGuide(props) {
|
|||
</div>
|
||||
<div className={classes.subStepContent}>
|
||||
<Typography variant={"body2"}>
|
||||
此步骤可保持默认并跳过,但是强烈建议您跟随此步骤操作。<br/>
|
||||
前往所创建云存储服务的 功能配置 面板,转到 访问配置 选项卡,开启 Token 防盗链并设定密码。
|
||||
此步骤可保持默认并跳过,但是强烈建议您跟随此步骤操作。
|
||||
<br />
|
||||
前往所创建云存储服务的 功能配置 面板,转到
|
||||
访问配置 选项卡,开启 Token 防盗链并设定密码。
|
||||
</Typography>
|
||||
<div className={classes.form}>
|
||||
<FormControl required component="fieldset">
|
||||
|
|
@ -362,9 +377,7 @@ export default function UpyunGuide(props) {
|
|||
<Collapse in={policy.IsPrivate === "true"}>
|
||||
<div className={classes.subStepContainer}>
|
||||
<div className={classes.stepNumberContainer}>
|
||||
<div className={classes.stepNumber}>
|
||||
6
|
||||
</div>
|
||||
<div className={classes.stepNumber}>6</div>
|
||||
</div>
|
||||
<div className={classes.subStepContent}>
|
||||
<Typography variant={"body2"}>
|
||||
|
|
@ -377,13 +390,14 @@ export default function UpyunGuide(props) {
|
|||
</InputLabel>
|
||||
<Input
|
||||
value={
|
||||
policy.OptionsSerialized
|
||||
.token
|
||||
policy.OptionsSerialized.token
|
||||
}
|
||||
onChange={handleOptionChange(
|
||||
"token"
|
||||
)}
|
||||
required={policy.IsPrivate === "true"}
|
||||
required={
|
||||
policy.IsPrivate === "true"
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
|
@ -391,7 +405,6 @@ export default function UpyunGuide(props) {
|
|||
</div>
|
||||
</Collapse>
|
||||
|
||||
|
||||
<div className={classes.stepFooter}>
|
||||
<Button
|
||||
disabled={loading}
|
||||
|
|
@ -425,9 +438,9 @@ export default function UpyunGuide(props) {
|
|||
可用魔法变量可参考{" "}
|
||||
<Link
|
||||
color={"secondary"}
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
setMagicVar("path")
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
setMagicVar("path");
|
||||
}}
|
||||
>
|
||||
路径魔法变量列表
|
||||
|
|
@ -460,9 +473,9 @@ export default function UpyunGuide(props) {
|
|||
可用魔法变量可参考{" "}
|
||||
<Link
|
||||
color={"secondary"}
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
setMagicVar("file")
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
setMagicVar("file");
|
||||
}}
|
||||
>
|
||||
文件名魔法变量列表
|
||||
|
|
@ -561,14 +574,22 @@ export default function UpyunGuide(props) {
|
|||
<RadioGroup
|
||||
required
|
||||
value={policy.IsOriginLinkEnable}
|
||||
onChange={e=>{
|
||||
if (policy.IsPrivate === "true" && e.target.value==="true"){
|
||||
ToggleSnackbar("top", "right","开启 Token 防盗链后无法使用直链功能", "warning");
|
||||
return
|
||||
onChange={e => {
|
||||
if (
|
||||
policy.IsPrivate === "true" &&
|
||||
e.target.value === "true"
|
||||
) {
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"开启 Token 防盗链后无法使用直链功能",
|
||||
"warning"
|
||||
);
|
||||
return;
|
||||
}
|
||||
handleChange(
|
||||
"IsOriginLinkEnable"
|
||||
)(e)
|
||||
handleChange("IsOriginLinkEnable")(
|
||||
e
|
||||
);
|
||||
}}
|
||||
row
|
||||
>
|
||||
|
|
@ -855,7 +876,9 @@ export default function UpyunGuide(props) {
|
|||
{activeStep === 5 && (
|
||||
<>
|
||||
<form className={classes.stepContent}>
|
||||
<Typography>存储策略已{props.policy ? "保存" : "添加"}!</Typography>
|
||||
<Typography>
|
||||
存储策略已{props.policy ? "保存" : "添加"}!
|
||||
</Typography>
|
||||
<Typography variant={"body2"} color={"textSecondary"}>
|
||||
要使用此存储策略,请到用户组管理页面,为相应用户组绑定此存储策略。
|
||||
</Typography>
|
||||
|
|
|
|||
|
|
@ -74,7 +74,6 @@ function useQuery() {
|
|||
return new URLSearchParams(useLocation().search);
|
||||
}
|
||||
|
||||
|
||||
export default function Policy() {
|
||||
const classes = useStyles();
|
||||
// const [loading, setLoading] = useState(false);
|
||||
|
|
@ -108,38 +107,42 @@ export default function Policy() {
|
|||
[dispatch]
|
||||
);
|
||||
|
||||
useEffect(()=>{
|
||||
if(query.get("code") === "0"){
|
||||
useEffect(() => {
|
||||
if (query.get("code") === "0") {
|
||||
ToggleSnackbar("top", "right", "授权成功", "success");
|
||||
}else if (query.get("msg") && query.get("msg")!==""){
|
||||
ToggleSnackbar("top", "right", query.get("msg") + ", "+ query.get("err"), "warning");
|
||||
} else if (query.get("msg") && query.get("msg") !== "") {
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
query.get("msg") + ", " + query.get("err"),
|
||||
"warning"
|
||||
);
|
||||
}
|
||||
|
||||
},[location])
|
||||
}, [location]);
|
||||
|
||||
const loadList = () => {
|
||||
API.post("/admin/policy/list", {
|
||||
page: page,
|
||||
page_size: pageSize,
|
||||
order_by: "id desc",
|
||||
conditions: filter === "all" ? {} : { type: filter }
|
||||
})
|
||||
.then(response => {
|
||||
setPolicies(response.data.items);
|
||||
setStatics(response.data.statics);
|
||||
setTotal(response.data.total);
|
||||
})
|
||||
.catch(error => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
});
|
||||
API.post("/admin/policy/list", {
|
||||
page: page,
|
||||
page_size: pageSize,
|
||||
order_by: "id desc",
|
||||
conditions: filter === "all" ? {} : { type: filter }
|
||||
})
|
||||
.then(response => {
|
||||
setPolicies(response.data.items);
|
||||
setStatics(response.data.statics);
|
||||
setTotal(response.data.total);
|
||||
})
|
||||
.catch(error => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadList();
|
||||
}, [page, pageSize,filter]);
|
||||
}, [page, pageSize, filter]);
|
||||
|
||||
const deletePolicy = (id) =>{
|
||||
API.delete("/admin/policy/" + id,)
|
||||
const deletePolicy = id => {
|
||||
API.delete("/admin/policy/" + id)
|
||||
.then(() => {
|
||||
loadList();
|
||||
ToggleSnackbar("top", "right", "存储策略已删除", "success");
|
||||
|
|
@ -147,7 +150,7 @@ export default function Policy() {
|
|||
.catch(error => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const open = Boolean(anchorEl);
|
||||
|
||||
|
|
@ -165,10 +168,10 @@ export default function Policy() {
|
|||
<div className={classes.headerRight}>
|
||||
<Select
|
||||
style={{
|
||||
marginRight:8,
|
||||
marginRight: 8
|
||||
}}
|
||||
value={filter}
|
||||
onChange={e=>setFilter(e.target.value)}
|
||||
onChange={e => setFilter(e.target.value)}
|
||||
>
|
||||
<MenuItem value={"all"}>全部</MenuItem>
|
||||
<MenuItem value={"local"}>本机</MenuItem>
|
||||
|
|
@ -194,7 +197,7 @@ export default function Policy() {
|
|||
<TableContainer className={classes.container}>
|
||||
<Table aria-label="sticky table" size={"small"}>
|
||||
<TableHead>
|
||||
<TableRow style={{height:52}}>
|
||||
<TableRow style={{ height: 52 }}>
|
||||
{columns.map(column => (
|
||||
<TableCell
|
||||
key={column.id}
|
||||
|
|
@ -226,19 +229,26 @@ export default function Policy() {
|
|||
</TableCell>
|
||||
<TableCell align={"right"}>
|
||||
<Tooltip title={"删除"}>
|
||||
<IconButton onClick={()=>deletePolicy(row.ID)} size={"small"}>
|
||||
<Delete/>
|
||||
<IconButton
|
||||
onClick={() =>
|
||||
deletePolicy(row.ID)
|
||||
}
|
||||
size={"small"}
|
||||
>
|
||||
<Delete />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title={"编辑"}>
|
||||
<IconButton onClick={(e)=>{
|
||||
setEditID(row.ID)
|
||||
handleClick(e)
|
||||
}} size={"small"}>
|
||||
<Edit/>
|
||||
<IconButton
|
||||
onClick={e => {
|
||||
setEditID(row.ID);
|
||||
handleClick(e);
|
||||
}}
|
||||
size={"small"}
|
||||
>
|
||||
<Edit />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
|
|
@ -264,14 +274,22 @@ export default function Policy() {
|
|||
onClose={handleClose}
|
||||
keepMounted
|
||||
>
|
||||
<MenuItem onClick={e=>{
|
||||
handleClose(e);
|
||||
history.push("/admin/policy/edit/pro/"+editID);
|
||||
}}>专家模式编辑</MenuItem>
|
||||
<MenuItem onClick={e=>{
|
||||
handleClose(e);
|
||||
history.push("/admin/policy/edit/guide/"+editID);
|
||||
}}>向导模式编辑</MenuItem>
|
||||
<MenuItem
|
||||
onClick={e => {
|
||||
handleClose(e);
|
||||
history.push("/admin/policy/edit/pro/" + editID);
|
||||
}}
|
||||
>
|
||||
专家模式编辑
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={e => {
|
||||
handleClose(e);
|
||||
history.push("/admin/policy/edit/guide/" + editID);
|
||||
}}
|
||||
>
|
||||
向导模式编辑
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -320,7 +320,8 @@ export default function Access() {
|
|||
target={"_blank"}
|
||||
>
|
||||
应用管理页面
|
||||
</Link>{" "}获取到的的 秘钥
|
||||
</Link>{" "}
|
||||
获取到的的 秘钥
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -152,7 +152,9 @@ export default function Aria2() {
|
|||
Aria2 的配置文件中开启 RPC
|
||||
服务。更多信息及指引请参考文档的{" "}
|
||||
<Link
|
||||
href={"https://docs.cloudreve.org/use/aria2"}
|
||||
href={
|
||||
"https://docs.cloudreve.org/use/aria2"
|
||||
}
|
||||
target={"_blank"}
|
||||
>
|
||||
离线下载
|
||||
|
|
|
|||
|
|
@ -36,18 +36,18 @@ export default function ImageSetting() {
|
|||
const classes = useStyles();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [options, setOptions] = useState({
|
||||
gravatar_server:"",
|
||||
avatar_path:"",
|
||||
avatar_size:"",
|
||||
avatar_size_l:"",
|
||||
avatar_size_m:"",
|
||||
avatar_size_s:"",
|
||||
thumb_width:"",
|
||||
thumb_height:"",
|
||||
captcha_height:"1",
|
||||
captcha_width:"1",
|
||||
captcha_mode:"3",
|
||||
captcha_CaptchaLen:"",
|
||||
gravatar_server: "",
|
||||
avatar_path: "",
|
||||
avatar_size: "",
|
||||
avatar_size_l: "",
|
||||
avatar_size_m: "",
|
||||
avatar_size_s: "",
|
||||
thumb_width: "",
|
||||
thumb_height: "",
|
||||
captcha_height: "1",
|
||||
captcha_width: "1",
|
||||
captcha_mode: "3",
|
||||
captcha_CaptchaLen: ""
|
||||
});
|
||||
|
||||
const handleChange = name => event => {
|
||||
|
|
@ -77,34 +77,33 @@ export default function ImageSetting() {
|
|||
// eslint-disable-next-line
|
||||
}, []);
|
||||
|
||||
|
||||
const submit = e => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
const option = [];
|
||||
Object.keys(options).forEach(k=>{
|
||||
Object.keys(options).forEach(k => {
|
||||
option.push({
|
||||
key:k,
|
||||
value:options[k],
|
||||
key: k,
|
||||
value: options[k]
|
||||
});
|
||||
})
|
||||
API.patch("/admin/setting",{
|
||||
options:option,
|
||||
});
|
||||
API.patch("/admin/setting", {
|
||||
options: option
|
||||
})
|
||||
.then(() => {
|
||||
ToggleSnackbar("top", "right", "设置已更改", "success");
|
||||
})
|
||||
.catch(error => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
}).then(()=>{
|
||||
})
|
||||
.then(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<form onSubmit={submit}>
|
||||
|
||||
<div className={classes.root}>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
头像
|
||||
|
|
@ -167,8 +166,8 @@ export default function ImageSetting() {
|
|||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min:1,
|
||||
step:1,
|
||||
min: 1,
|
||||
step: 1
|
||||
}}
|
||||
value={options.avatar_size_s}
|
||||
onChange={handleChange("avatar_size_s")}
|
||||
|
|
@ -185,8 +184,8 @@ export default function ImageSetting() {
|
|||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min:1,
|
||||
step:1,
|
||||
min: 1,
|
||||
step: 1
|
||||
}}
|
||||
value={options.avatar_size_m}
|
||||
onChange={handleChange("avatar_size_m")}
|
||||
|
|
@ -203,8 +202,8 @@ export default function ImageSetting() {
|
|||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min:1,
|
||||
step:1,
|
||||
min: 1,
|
||||
step: 1
|
||||
}}
|
||||
value={options.avatar_size_l}
|
||||
onChange={handleChange("avatar_size_l")}
|
||||
|
|
@ -212,7 +211,6 @@ export default function ImageSetting() {
|
|||
/>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -230,8 +228,8 @@ export default function ImageSetting() {
|
|||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min:1,
|
||||
step:1,
|
||||
min: 1,
|
||||
step: 1
|
||||
}}
|
||||
value={options.thumb_width}
|
||||
onChange={handleChange("thumb_width")}
|
||||
|
|
@ -250,8 +248,8 @@ export default function ImageSetting() {
|
|||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min:1,
|
||||
step:1,
|
||||
min: 1,
|
||||
step: 1
|
||||
}}
|
||||
value={options.thumb_height}
|
||||
onChange={handleChange("thumb_height")}
|
||||
|
|
@ -260,7 +258,6 @@ export default function ImageSetting() {
|
|||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className={classes.root}>
|
||||
|
|
@ -276,8 +273,8 @@ export default function ImageSetting() {
|
|||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min:1,
|
||||
step:1,
|
||||
min: 1,
|
||||
step: 1
|
||||
}}
|
||||
value={options.captcha_width}
|
||||
onChange={handleChange("captcha_width")}
|
||||
|
|
@ -294,8 +291,8 @@ export default function ImageSetting() {
|
|||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min:1,
|
||||
step:1,
|
||||
min: 1,
|
||||
step: 1
|
||||
}}
|
||||
value={options.captcha_height}
|
||||
onChange={handleChange("captcha_height")}
|
||||
|
|
@ -324,7 +321,6 @@ export default function ImageSetting() {
|
|||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ export default function Mail() {
|
|||
replyTo: "",
|
||||
smtpUser: "",
|
||||
smtpPass: "",
|
||||
smtpEncryption:"",
|
||||
smtpEncryption: "",
|
||||
mail_keepalive: "30",
|
||||
mail_activation_template: "",
|
||||
mail_reset_pwd_template: ""
|
||||
|
|
@ -254,7 +254,7 @@ export default function Mail() {
|
|||
SMTP 端口
|
||||
</InputLabel>
|
||||
<Input
|
||||
inputProps={{ min: 1 ,step:1}}
|
||||
inputProps={{ min: 1, step: 1 }}
|
||||
type={"number"}
|
||||
value={options.smtpPort}
|
||||
onChange={handleChange("smtpPort")}
|
||||
|
|
@ -342,7 +342,7 @@ export default function Mail() {
|
|||
SMTP 连接有效期 (秒)
|
||||
</InputLabel>
|
||||
<Input
|
||||
inputProps={{ min: 1 ,step:1}}
|
||||
inputProps={{ min: 1, step: 1 }}
|
||||
type={"number"}
|
||||
value={options.mail_keepalive}
|
||||
onChange={handleChange("mail_keepalive")}
|
||||
|
|
@ -363,7 +363,6 @@ export default function Mail() {
|
|||
</Typography>
|
||||
|
||||
<div className={classes.formContainer}>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
|
|
@ -403,7 +402,6 @@ export default function Mail() {
|
|||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -76,28 +76,28 @@ export default function SiteInformation() {
|
|||
// eslint-disable-next-line
|
||||
}, []);
|
||||
|
||||
|
||||
const submit = e => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
const option = [];
|
||||
Object.keys(options).forEach(k=>{
|
||||
Object.keys(options).forEach(k => {
|
||||
option.push({
|
||||
key:k,
|
||||
value:options[k],
|
||||
key: k,
|
||||
value: options[k]
|
||||
});
|
||||
})
|
||||
API.patch("/admin/setting",{
|
||||
options:option,
|
||||
});
|
||||
API.patch("/admin/setting", {
|
||||
options: option
|
||||
})
|
||||
.then(() => {
|
||||
ToggleSnackbar("top", "right", "设置已更改", "success");
|
||||
})
|
||||
.catch(error => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
}).then(()=>{
|
||||
})
|
||||
.then(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
@ -254,7 +254,6 @@ export default function SiteInformation() {
|
|||
value={options.pwa_display}
|
||||
onChange={handleChange("pwa_display")}
|
||||
>
|
||||
|
||||
<MenuItem value={"fullscreen"}>
|
||||
fullscreen
|
||||
</MenuItem>
|
||||
|
|
|
|||
|
|
@ -56,9 +56,9 @@ export default function Theme() {
|
|||
const [theme, setTheme] = useState({});
|
||||
const [options, setOptions] = useState({
|
||||
themes: "{}",
|
||||
defaultTheme:"",
|
||||
home_view_method:"icon",
|
||||
share_view_method:"list",
|
||||
defaultTheme: "",
|
||||
home_view_method: "icon",
|
||||
share_view_method: "list"
|
||||
});
|
||||
const [themeConfig, setThemeConfig] = useState({});
|
||||
const [themeConfigError, setThemeConfigError] = useState({});
|
||||
|
|
@ -72,39 +72,44 @@ export default function Theme() {
|
|||
);
|
||||
|
||||
const deleteTheme = color => {
|
||||
if(color === options.defaultTheme){
|
||||
if (color === options.defaultTheme) {
|
||||
ToggleSnackbar("top", "right", "不能删除默认配色", "warning");
|
||||
return
|
||||
return;
|
||||
}
|
||||
if (Object.keys(theme).length <=1){
|
||||
if (Object.keys(theme).length <= 1) {
|
||||
ToggleSnackbar("top", "right", "请至少保留一个配色方案", "warning");
|
||||
return
|
||||
return;
|
||||
}
|
||||
const themeCopy = {...theme};
|
||||
const themeCopy = { ...theme };
|
||||
delete themeCopy[color];
|
||||
const resStr = JSON.stringify(themeCopy);
|
||||
setOptions({
|
||||
...options,
|
||||
themes:resStr,
|
||||
})
|
||||
}
|
||||
themes: resStr
|
||||
});
|
||||
};
|
||||
|
||||
const addTheme = newTheme => {
|
||||
setCreate(false);
|
||||
if (theme[newTheme.palette.primary.main] !== undefined){
|
||||
ToggleSnackbar("top", "right", "主色调不能与已有配色重复", "warning");
|
||||
return
|
||||
if (theme[newTheme.palette.primary.main] !== undefined) {
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"主色调不能与已有配色重复",
|
||||
"warning"
|
||||
);
|
||||
return;
|
||||
}
|
||||
const res = {
|
||||
...theme,
|
||||
[newTheme.palette.primary.main]:newTheme,
|
||||
[newTheme.palette.primary.main]: newTheme
|
||||
};
|
||||
const resStr = JSON.stringify(res);
|
||||
setOptions({
|
||||
...options,
|
||||
themes:resStr,
|
||||
})
|
||||
}
|
||||
themes: resStr
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const res = JSON.parse(options.themes);
|
||||
|
|
@ -165,7 +170,6 @@ export default function Theme() {
|
|||
return (
|
||||
<div>
|
||||
<form onSubmit={submit}>
|
||||
|
||||
<div className={classes.root}>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
主题配色
|
||||
|
|
@ -236,14 +240,31 @@ export default function Theme() {
|
|||
const res = JSON.parse(
|
||||
e.target.value
|
||||
);
|
||||
if(
|
||||
!('palette' in res) ||
|
||||
!('primary' in res.palette) ||
|
||||
!('main' in res.palette.primary) ||
|
||||
!('secondary' in res.palette) ||
|
||||
!('main' in res.palette.secondary)
|
||||
){
|
||||
throw e
|
||||
if (
|
||||
!(
|
||||
"palette" in
|
||||
res
|
||||
) ||
|
||||
!(
|
||||
"primary" in
|
||||
res.palette
|
||||
) ||
|
||||
!(
|
||||
"main" in
|
||||
res.palette
|
||||
.primary
|
||||
) ||
|
||||
!(
|
||||
"secondary" in
|
||||
res.palette
|
||||
) ||
|
||||
!(
|
||||
"main" in
|
||||
res.palette
|
||||
.secondary
|
||||
)
|
||||
) {
|
||||
throw e;
|
||||
}
|
||||
setTheme({
|
||||
...theme,
|
||||
|
|
@ -267,7 +288,11 @@ export default function Theme() {
|
|||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<IconButton onClick={()=>deleteTheme(k)}>
|
||||
<IconButton
|
||||
onClick={() =>
|
||||
deleteTheme(k)
|
||||
}
|
||||
>
|
||||
<Delete />
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
|
|
@ -279,17 +304,19 @@ export default function Theme() {
|
|||
<Button
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
style={{marginTop:8}}
|
||||
onClick={()=>setCreate(true)}
|
||||
style={{ marginTop: 8 }}
|
||||
onClick={() => setCreate(true)}
|
||||
>
|
||||
新建配色方案
|
||||
</Button>
|
||||
</div>
|
||||
<Alert severity="info" style={{marginTop:8}}>
|
||||
<Alert severity="info" style={{ marginTop: 8 }}>
|
||||
<Typography variant="body2">
|
||||
完整的配置项可在 {" "}
|
||||
完整的配置项可在{" "}
|
||||
<Link
|
||||
href={"https://material-ui.com/zh/customization/default-theme/"}
|
||||
href={
|
||||
"https://material-ui.com/zh/customization/default-theme/"
|
||||
}
|
||||
target={"_blank"}
|
||||
>
|
||||
默认主题 - Material-UI
|
||||
|
|
@ -297,7 +324,6 @@ export default function Theme() {
|
|||
查阅。
|
||||
</Typography>
|
||||
</Alert>
|
||||
|
||||
</div>
|
||||
|
||||
<div className={classes.form}>
|
||||
|
|
@ -309,7 +335,7 @@ export default function Theme() {
|
|||
value={options.defaultTheme}
|
||||
onChange={handleChange("defaultTheme")}
|
||||
>
|
||||
{Object.keys(theme).map(k=>(
|
||||
{Object.keys(theme).map(k => (
|
||||
<MenuItem key={k} value={k}>
|
||||
<div
|
||||
className={
|
||||
|
|
@ -319,24 +345,18 @@ export default function Theme() {
|
|||
<div
|
||||
style={{
|
||||
backgroundColor:
|
||||
theme[k].palette
|
||||
.primary
|
||||
.main
|
||||
theme[k].palette
|
||||
.primary.main
|
||||
}}
|
||||
className={
|
||||
classes.colorDot
|
||||
}
|
||||
className={classes.colorDot}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
backgroundColor:
|
||||
theme[k].palette
|
||||
.secondary
|
||||
.main
|
||||
theme[k].palette
|
||||
.secondary.main
|
||||
}}
|
||||
className={
|
||||
classes.colorDot
|
||||
}
|
||||
className={classes.colorDot}
|
||||
/>
|
||||
</div>
|
||||
</MenuItem>
|
||||
|
|
@ -347,7 +367,6 @@ export default function Theme() {
|
|||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -368,7 +387,9 @@ export default function Theme() {
|
|||
required
|
||||
>
|
||||
<MenuItem value={"icon"}>大图标</MenuItem>
|
||||
<MenuItem value={"smallIcon"}>小图标</MenuItem>
|
||||
<MenuItem value={"smallIcon"}>
|
||||
小图标
|
||||
</MenuItem>
|
||||
<MenuItem value={"list"}>列表</MenuItem>
|
||||
</Select>
|
||||
<FormHelperText id="component-helper-text">
|
||||
|
|
@ -390,7 +411,9 @@ export default function Theme() {
|
|||
required
|
||||
>
|
||||
<MenuItem value={"icon"}>大图标</MenuItem>
|
||||
<MenuItem value={"smallIcon"}>小图标</MenuItem>
|
||||
<MenuItem value={"smallIcon"}>
|
||||
小图标
|
||||
</MenuItem>
|
||||
<MenuItem value={"list"}>列表</MenuItem>
|
||||
</Select>
|
||||
<FormHelperText id="component-helper-text">
|
||||
|
|
@ -399,7 +422,6 @@ export default function Theme() {
|
|||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className={classes.root}>
|
||||
|
|
@ -414,7 +436,11 @@ export default function Theme() {
|
|||
</div>
|
||||
</form>
|
||||
|
||||
<CreateTheme onSubmit={addTheme} open={create} onClose={()=>setCreate(false)}/>
|
||||
<CreateTheme
|
||||
onSubmit={addTheme}
|
||||
open={create}
|
||||
onClose={() => setCreate(false)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,26 +37,26 @@ export default function UploadDownload() {
|
|||
const [loading, setLoading] = useState(false);
|
||||
const [options, setOptions] = useState({
|
||||
max_worker_num: "1",
|
||||
max_parallel_transfer:"1",
|
||||
temp_path:"",
|
||||
maxEditSize:"0",
|
||||
onedrive_chunk_retries:"0",
|
||||
archive_timeout:"0",
|
||||
download_timeout:"0",
|
||||
preview_timeout:"0",
|
||||
doc_preview_timeout:"0",
|
||||
upload_credential_timeout:"0",
|
||||
upload_session_timeout:"0",
|
||||
slave_api_timeout:"0",
|
||||
onedrive_monitor_timeout:"0",
|
||||
share_download_session_timeout:"0",
|
||||
onedrive_callback_check:"0",
|
||||
reset_after_upload_failed:"0",
|
||||
onedrive_source_timeout:"0",
|
||||
max_parallel_transfer: "1",
|
||||
temp_path: "",
|
||||
maxEditSize: "0",
|
||||
onedrive_chunk_retries: "0",
|
||||
archive_timeout: "0",
|
||||
download_timeout: "0",
|
||||
preview_timeout: "0",
|
||||
doc_preview_timeout: "0",
|
||||
upload_credential_timeout: "0",
|
||||
upload_session_timeout: "0",
|
||||
slave_api_timeout: "0",
|
||||
onedrive_monitor_timeout: "0",
|
||||
share_download_session_timeout: "0",
|
||||
onedrive_callback_check: "0",
|
||||
reset_after_upload_failed: "0",
|
||||
onedrive_source_timeout: "0"
|
||||
});
|
||||
|
||||
const handleCheckChange = name => event => {
|
||||
const value= event.target.checked ? "1" : "0";
|
||||
const value = event.target.checked ? "1" : "0";
|
||||
setOptions({
|
||||
...options,
|
||||
[name]: value
|
||||
|
|
@ -90,57 +90,56 @@ export default function UploadDownload() {
|
|||
// eslint-disable-next-line
|
||||
}, []);
|
||||
|
||||
|
||||
const submit = e => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
const option = [];
|
||||
Object.keys(options).forEach(k=>{
|
||||
Object.keys(options).forEach(k => {
|
||||
option.push({
|
||||
key:k,
|
||||
value:options[k],
|
||||
key: k,
|
||||
value: options[k]
|
||||
});
|
||||
})
|
||||
API.patch("/admin/setting",{
|
||||
options:option,
|
||||
});
|
||||
API.patch("/admin/setting", {
|
||||
options: option
|
||||
})
|
||||
.then(() => {
|
||||
ToggleSnackbar("top", "right", "设置已更改", "success");
|
||||
})
|
||||
.catch(error => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
}).then(()=>{
|
||||
})
|
||||
.then(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<form onSubmit={submit}>
|
||||
|
||||
<div className={classes.root}>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
存储与传输
|
||||
</Typography>
|
||||
<div className={classes.formContainer}>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl >
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
Worker 数量
|
||||
</InputLabel>
|
||||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min:1,
|
||||
step:1,
|
||||
min: 1,
|
||||
step: 1
|
||||
}}
|
||||
value={options.max_worker_num}
|
||||
onChange={handleChange("max_worker_num")}
|
||||
required
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
任务队列最多并行执行的任务数,保存后需要重启 Cloudreve 生效
|
||||
任务队列最多并行执行的任务数,保存后需要重启
|
||||
Cloudreve 生效
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
|
@ -153,11 +152,13 @@ export default function UploadDownload() {
|
|||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min:1,
|
||||
step:1,
|
||||
min: 1,
|
||||
step: 1
|
||||
}}
|
||||
value={options.max_parallel_transfer}
|
||||
onChange={handleChange("max_parallel_transfer")}
|
||||
onChange={handleChange(
|
||||
"max_parallel_transfer"
|
||||
)}
|
||||
required
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
|
|
@ -199,22 +200,25 @@ export default function UploadDownload() {
|
|||
</div>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl >
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
OneDrive 分片错误重试
|
||||
</InputLabel>
|
||||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min:0,
|
||||
step:1,
|
||||
min: 0,
|
||||
step: 1
|
||||
}}
|
||||
value={options.onedrive_chunk_retries}
|
||||
onChange={handleChange("onedrive_chunk_retries")}
|
||||
onChange={handleChange(
|
||||
"onedrive_chunk_retries"
|
||||
)}
|
||||
required
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
OneDrive 存储策略分片上传失败后重试的最大次数,只适用于服务端上传或中转
|
||||
OneDrive
|
||||
存储策略分片上传失败后重试的最大次数,只适用于服务端上传或中转
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
|
@ -225,7 +229,8 @@ export default function UploadDownload() {
|
|||
control={
|
||||
<Switch
|
||||
checked={
|
||||
options.reset_after_upload_failed === "1"
|
||||
options.reset_after_upload_failed ===
|
||||
"1"
|
||||
}
|
||||
onChange={handleCheckChange(
|
||||
"reset_after_upload_failed"
|
||||
|
|
@ -239,7 +244,6 @@ export default function UploadDownload() {
|
|||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -249,17 +253,16 @@ export default function UploadDownload() {
|
|||
</Typography>
|
||||
|
||||
<div className={classes.formContainer}>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl >
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
打包下载
|
||||
</InputLabel>
|
||||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min:1,
|
||||
step:1,
|
||||
min: 1,
|
||||
step: 1
|
||||
}}
|
||||
value={options.archive_timeout}
|
||||
onChange={handleChange("archive_timeout")}
|
||||
|
|
@ -269,15 +272,15 @@ export default function UploadDownload() {
|
|||
</div>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl >
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
下载会话
|
||||
</InputLabel>
|
||||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min:1,
|
||||
step:1,
|
||||
min: 1,
|
||||
step: 1
|
||||
}}
|
||||
value={options.download_timeout}
|
||||
onChange={handleChange("download_timeout")}
|
||||
|
|
@ -287,15 +290,15 @@ export default function UploadDownload() {
|
|||
</div>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl >
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
预览链接
|
||||
</InputLabel>
|
||||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min:1,
|
||||
step:1,
|
||||
min: 1,
|
||||
step: 1
|
||||
}}
|
||||
value={options.preview_timeout}
|
||||
onChange={handleChange("preview_timeout")}
|
||||
|
|
@ -305,54 +308,60 @@ export default function UploadDownload() {
|
|||
</div>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl >
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
Office 文档预览连接
|
||||
</InputLabel>
|
||||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min:1,
|
||||
step:1,
|
||||
min: 1,
|
||||
step: 1
|
||||
}}
|
||||
value={options.doc_preview_timeout}
|
||||
onChange={handleChange("doc_preview_timeout")}
|
||||
onChange={handleChange(
|
||||
"doc_preview_timeout"
|
||||
)}
|
||||
required
|
||||
/>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl >
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
上传凭证
|
||||
</InputLabel>
|
||||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min:1,
|
||||
step:1,
|
||||
min: 1,
|
||||
step: 1
|
||||
}}
|
||||
value={options.upload_credential_timeout}
|
||||
onChange={handleChange("upload_credential_timeout")}
|
||||
onChange={handleChange(
|
||||
"upload_credential_timeout"
|
||||
)}
|
||||
required
|
||||
/>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl >
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
上传会话
|
||||
</InputLabel>
|
||||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min:1,
|
||||
step:1,
|
||||
min: 1,
|
||||
step: 1
|
||||
}}
|
||||
value={options.upload_session_timeout}
|
||||
onChange={handleChange("upload_session_timeout")}
|
||||
onChange={handleChange(
|
||||
"upload_session_timeout"
|
||||
)}
|
||||
required
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
|
|
@ -362,15 +371,15 @@ export default function UploadDownload() {
|
|||
</div>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl >
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
从机API请求
|
||||
</InputLabel>
|
||||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min:1,
|
||||
step:1,
|
||||
min: 1,
|
||||
step: 1
|
||||
}}
|
||||
value={options.slave_api_timeout}
|
||||
onChange={handleChange("slave_api_timeout")}
|
||||
|
|
@ -380,18 +389,22 @@ export default function UploadDownload() {
|
|||
</div>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl >
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
分享下载会话
|
||||
</InputLabel>
|
||||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min:1,
|
||||
step:1,
|
||||
min: 1,
|
||||
step: 1
|
||||
}}
|
||||
value={options.share_download_session_timeout}
|
||||
onChange={handleChange("share_download_session_timeout")}
|
||||
value={
|
||||
options.share_download_session_timeout
|
||||
}
|
||||
onChange={handleChange(
|
||||
"share_download_session_timeout"
|
||||
)}
|
||||
required
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
|
|
@ -401,69 +414,77 @@ export default function UploadDownload() {
|
|||
</div>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl >
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
OneDrive 客户端上传监控间隔
|
||||
</InputLabel>
|
||||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min:1,
|
||||
step:1,
|
||||
min: 1,
|
||||
step: 1
|
||||
}}
|
||||
value={options.onedrive_monitor_timeout}
|
||||
onChange={handleChange("onedrive_monitor_timeout")}
|
||||
onChange={handleChange(
|
||||
"onedrive_monitor_timeout"
|
||||
)}
|
||||
required
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
每间隔所设定时间,Cloudreve 会向 OneDrive 请求检查客户端上传情况已确保客户端上传可控
|
||||
每间隔所设定时间,Cloudreve 会向 OneDrive
|
||||
请求检查客户端上传情况已确保客户端上传可控
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl >
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
OneDrive 回调等待
|
||||
</InputLabel>
|
||||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min:1,
|
||||
step:1,
|
||||
min: 1,
|
||||
step: 1
|
||||
}}
|
||||
value={options.onedrive_callback_check}
|
||||
onChange={handleChange("onedrive_callback_check")}
|
||||
onChange={handleChange(
|
||||
"onedrive_callback_check"
|
||||
)}
|
||||
required
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
OneDrive 客户端上传完成后,等待回调的最大时间,如果超出会被认为上传失败
|
||||
OneDrive
|
||||
客户端上传完成后,等待回调的最大时间,如果超出会被认为上传失败
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl >
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
OneDrive 下载请求缓存
|
||||
</InputLabel>
|
||||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min:1,
|
||||
max:3659,
|
||||
step:1,
|
||||
min: 1,
|
||||
max: 3659,
|
||||
step: 1
|
||||
}}
|
||||
value={options.onedrive_source_timeout}
|
||||
onChange={handleChange("onedrive_source_timeout")}
|
||||
onChange={handleChange(
|
||||
"onedrive_source_timeout"
|
||||
)}
|
||||
required
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
OneDrive 获取文件下载 URL 后可将结果缓存,减轻热门文件下载API请求频率
|
||||
OneDrive 获取文件下载 URL
|
||||
后可将结果缓存,减轻热门文件下载API请求频率
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import React, {useCallback, useEffect, useState} from "react";
|
||||
import {useParams} from "react-router";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { useParams } from "react-router";
|
||||
import API from "../../../middleware/Api";
|
||||
import {useDispatch} from "react-redux";
|
||||
import {toggleSnackbar} from "../../../actions";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { toggleSnackbar } from "../../../actions";
|
||||
import UserForm from "./UserForm";
|
||||
|
||||
export default function EditUserPreload( ) {
|
||||
const [user,setUser] = useState({});
|
||||
export default function EditUserPreload() {
|
||||
const [user, setUser] = useState({});
|
||||
|
||||
const {id } = useParams();
|
||||
const { id } = useParams();
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const ToggleSnackbar = useCallback(
|
||||
|
|
@ -17,8 +17,7 @@ export default function EditUserPreload( ) {
|
|||
[dispatch]
|
||||
);
|
||||
|
||||
|
||||
useEffect(()=>{
|
||||
useEffect(() => {
|
||||
setUser({});
|
||||
API.get("/admin/user/" + id)
|
||||
.then(response => {
|
||||
|
|
@ -31,13 +30,7 @@ export default function EditUserPreload( ) {
|
|||
.catch(error => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
});
|
||||
},[id]);
|
||||
}, [id]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{user.ID !== undefined &&
|
||||
<UserForm user={user}/>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
return <div>{user.ID !== undefined && <UserForm user={user} />}</div>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ export default function UserForm(props) {
|
|||
Nick: "",
|
||||
Password: "", // 为空时只读
|
||||
Status: "0", // 转换类型
|
||||
GroupID: "2", // 转换类型
|
||||
GroupID: "2" // 转换类型
|
||||
}
|
||||
);
|
||||
const [groups, setGroups] = useState([]);
|
||||
|
|
@ -76,21 +76,26 @@ export default function UserForm(props) {
|
|||
|
||||
const submit = e => {
|
||||
e.preventDefault();
|
||||
const userCopy = {...user};
|
||||
const userCopy = { ...user };
|
||||
|
||||
// 整型转换
|
||||
["Status", "GroupID","Score"].forEach(v => {
|
||||
["Status", "GroupID", "Score"].forEach(v => {
|
||||
userCopy[v] = parseInt(userCopy[v]);
|
||||
});
|
||||
|
||||
setLoading(true);
|
||||
API.post("/admin/user", {
|
||||
user: userCopy,
|
||||
password:userCopy.Password,
|
||||
password: userCopy.Password
|
||||
})
|
||||
.then(() => {
|
||||
history.push("/admin/user");
|
||||
ToggleSnackbar("top", "right", "用户已"+ (props.user ? "保存" : "添加"), "success");
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"用户已" + (props.user ? "保存" : "添加"),
|
||||
"success"
|
||||
);
|
||||
})
|
||||
.catch(error => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
|
|
@ -110,7 +115,6 @@ export default function UserForm(props) {
|
|||
</Typography>
|
||||
|
||||
<div className={classes.formContainer}>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
|
|
@ -162,9 +166,7 @@ export default function UserForm(props) {
|
|||
</InputLabel>
|
||||
<Select
|
||||
value={user.GroupID}
|
||||
onChange={handleChange(
|
||||
"GroupID"
|
||||
)}
|
||||
onChange={handleChange("GroupID")}
|
||||
required
|
||||
>
|
||||
{groups.map(v => {
|
||||
|
|
@ -194,19 +196,18 @@ export default function UserForm(props) {
|
|||
</InputLabel>
|
||||
<Select
|
||||
value={user.Status}
|
||||
onChange={handleChange(
|
||||
"Status"
|
||||
)}
|
||||
onChange={handleChange("Status")}
|
||||
required
|
||||
>
|
||||
<MenuItem value={"0"}>正常</MenuItem>
|
||||
<MenuItem value={"1"}>未激活</MenuItem>
|
||||
<MenuItem value={"2"}>被封禁</MenuItem>
|
||||
<MenuItem value={"3"}>超额使用被封禁</MenuItem>
|
||||
<MenuItem value={"3"}>
|
||||
超额使用被封禁
|
||||
</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes.root}>
|
||||
|
|
|
|||
|
|
@ -1,148 +1,153 @@
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux'
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { connect } from "react-redux";
|
||||
import {} from "../../actions";
|
||||
import classNames from "classnames";
|
||||
import ErrorIcon from "@material-ui/icons/Error";
|
||||
import InfoIcon from "@material-ui/icons/Info";
|
||||
import CloseIcon from "@material-ui/icons/Close";
|
||||
import CheckCircleIcon from "@material-ui/icons/CheckCircle";
|
||||
import WarningIcon from "@material-ui/icons/Warning";
|
||||
|
||||
import { green, amber } from "@material-ui/core/colors";
|
||||
|
||||
import {
|
||||
} from "../../actions"
|
||||
import classNames from 'classnames';
|
||||
import ErrorIcon from '@material-ui/icons/Error';
|
||||
import InfoIcon from '@material-ui/icons/Info';
|
||||
import CloseIcon from '@material-ui/icons/Close';
|
||||
import CheckCircleIcon from '@material-ui/icons/CheckCircle';
|
||||
import WarningIcon from '@material-ui/icons/Warning';
|
||||
|
||||
import { green, amber } from '@material-ui/core/colors';
|
||||
|
||||
import { withStyles, SnackbarContent, Snackbar, IconButton } from '@material-ui/core';
|
||||
withStyles,
|
||||
SnackbarContent,
|
||||
Snackbar,
|
||||
IconButton
|
||||
} from "@material-ui/core";
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
snackbar:state.viewUpdate.snackbar,
|
||||
}
|
||||
}
|
||||
snackbar: state.viewUpdate.snackbar
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = () => {
|
||||
return {
|
||||
}
|
||||
}
|
||||
return {};
|
||||
};
|
||||
|
||||
const variantIcon = {
|
||||
success: CheckCircleIcon,
|
||||
warning: WarningIcon,
|
||||
error: ErrorIcon,
|
||||
info: InfoIcon,
|
||||
};
|
||||
info: InfoIcon
|
||||
};
|
||||
|
||||
const styles1 = theme => ({
|
||||
success: {
|
||||
backgroundColor: green[600],
|
||||
},
|
||||
error: {
|
||||
backgroundColor: theme.palette.error.dark,
|
||||
},
|
||||
info: {
|
||||
backgroundColor: theme.palette.primary.dark,
|
||||
},
|
||||
warning: {
|
||||
backgroundColor: amber[700],
|
||||
},
|
||||
icon: {
|
||||
fontSize: 20,
|
||||
},
|
||||
iconVariant: {
|
||||
backgroundColor: green[600]
|
||||
},
|
||||
error: {
|
||||
backgroundColor: theme.palette.error.dark
|
||||
},
|
||||
info: {
|
||||
backgroundColor: theme.palette.primary.dark
|
||||
},
|
||||
warning: {
|
||||
backgroundColor: amber[700]
|
||||
},
|
||||
icon: {
|
||||
fontSize: 20
|
||||
},
|
||||
iconVariant: {
|
||||
opacity: 0.9,
|
||||
marginRight: theme.spacing(1),
|
||||
},
|
||||
message: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
},
|
||||
})
|
||||
marginRight: theme.spacing(1)
|
||||
},
|
||||
message: {
|
||||
display: "flex",
|
||||
alignItems: "center"
|
||||
}
|
||||
});
|
||||
|
||||
function MySnackbarContent(props) {
|
||||
const { classes, className, message, onClose, variant, ...other } = props;
|
||||
const Icon = variantIcon[variant];
|
||||
|
||||
|
||||
return (
|
||||
<SnackbarContent
|
||||
className={classNames(classes[variant], className)}
|
||||
aria-describedby="client-snackbar"
|
||||
message={
|
||||
<span id="client-snackbar" className={classes.message}>
|
||||
<Icon className={classNames(classes.icon, classes.iconVariant)} />
|
||||
{message}
|
||||
</span>
|
||||
}
|
||||
action={[
|
||||
<IconButton
|
||||
key="close"
|
||||
aria-label="Close"
|
||||
color="inherit"
|
||||
className={classes.close}
|
||||
onClick={onClose}
|
||||
>
|
||||
<CloseIcon className={classes.icon} />
|
||||
</IconButton>,
|
||||
]}
|
||||
{...other}
|
||||
/>
|
||||
<SnackbarContent
|
||||
className={classNames(classes[variant], className)}
|
||||
aria-describedby="client-snackbar"
|
||||
message={
|
||||
<span id="client-snackbar" className={classes.message}>
|
||||
<Icon
|
||||
className={classNames(
|
||||
classes.icon,
|
||||
classes.iconVariant
|
||||
)}
|
||||
/>
|
||||
{message}
|
||||
</span>
|
||||
}
|
||||
action={[
|
||||
<IconButton
|
||||
key="close"
|
||||
aria-label="Close"
|
||||
color="inherit"
|
||||
className={classes.close}
|
||||
onClick={onClose}
|
||||
>
|
||||
<CloseIcon className={classes.icon} />
|
||||
</IconButton>
|
||||
]}
|
||||
{...other}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
MySnackbarContent.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
className: PropTypes.string,
|
||||
message: PropTypes.node,
|
||||
onClose: PropTypes.func,
|
||||
variant: PropTypes.oneOf(['success', 'warning', 'error', 'info']).isRequired,
|
||||
classes: PropTypes.object.isRequired,
|
||||
className: PropTypes.string,
|
||||
message: PropTypes.node,
|
||||
onClose: PropTypes.func,
|
||||
variant: PropTypes.oneOf(["success", "warning", "error", "info"]).isRequired
|
||||
};
|
||||
|
||||
const MySnackbarContentWrapper = withStyles(styles1)(MySnackbarContent);
|
||||
const styles = theme => ({
|
||||
margin: {
|
||||
margin: theme.spacing(1),
|
||||
},
|
||||
})
|
||||
margin: theme.spacing(1)
|
||||
}
|
||||
});
|
||||
class SnackbarCompoment extends Component {
|
||||
state = {
|
||||
open: false
|
||||
};
|
||||
|
||||
state={
|
||||
open:false,
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps = (nextProps)=>{
|
||||
if(nextProps.snackbar.toggle !== this.props.snackbar.toggle){
|
||||
this.setState({open:true});
|
||||
UNSAFE_componentWillReceiveProps = nextProps => {
|
||||
if (nextProps.snackbar.toggle !== this.props.snackbar.toggle) {
|
||||
this.setState({ open: true });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handleClose = () => {
|
||||
this.setState({ open: false });
|
||||
};
|
||||
|
||||
handleClose= ()=>{
|
||||
this.setState({open:false});
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return (
|
||||
<Snackbar
|
||||
anchorOrigin={{
|
||||
vertical: this.props.snackbar.vertical,
|
||||
horizontal: this.props.snackbar.horizontal,
|
||||
}}
|
||||
open={this.state.open}
|
||||
autoHideDuration={6000}
|
||||
onClose={this.handleClose}
|
||||
>
|
||||
<MySnackbarContentWrapper
|
||||
anchorOrigin={{
|
||||
vertical: this.props.snackbar.vertical,
|
||||
horizontal: this.props.snackbar.horizontal
|
||||
}}
|
||||
open={this.state.open}
|
||||
autoHideDuration={6000}
|
||||
onClose={this.handleClose}
|
||||
variant={this.props.snackbar.color}
|
||||
message={this.props.snackbar.msg}
|
||||
/>
|
||||
</Snackbar>
|
||||
>
|
||||
<MySnackbarContentWrapper
|
||||
onClose={this.handleClose}
|
||||
variant={this.props.snackbar.color}
|
||||
message={this.props.snackbar.msg}
|
||||
/>
|
||||
</Snackbar>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const AlertBar = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)( withStyles(styles)(SnackbarCompoment))
|
||||
)(withStyles(styles)(SnackbarCompoment));
|
||||
|
||||
export default AlertBar
|
||||
export default AlertBar;
|
||||
|
|
|
|||
|
|
@ -16,11 +16,10 @@ const useStyles = makeStyles(() => ({
|
|||
left: "auto",
|
||||
zIndex: 5,
|
||||
position: "fixed"
|
||||
},
|
||||
}
|
||||
}));
|
||||
|
||||
export default function RemoteDownloadButton() {
|
||||
|
||||
const classes = useStyles();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
|
|
@ -29,19 +28,18 @@ export default function RemoteDownloadButton() {
|
|||
[dispatch]
|
||||
);
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<Modals/>
|
||||
<AutoHidden enable>
|
||||
<Fab
|
||||
className={classes.fab}
|
||||
color="secondary"
|
||||
onClick={()=>OpenRemoteDownloadDialog()}
|
||||
>
|
||||
<Add/>
|
||||
</Fab>
|
||||
</AutoHidden>
|
||||
</>
|
||||
<Modals />
|
||||
<AutoHidden enable>
|
||||
<Fab
|
||||
className={classes.fab}
|
||||
color="secondary"
|
||||
onClick={() => OpenRemoteDownloadDialog()}
|
||||
>
|
||||
<Add />
|
||||
</Fab>
|
||||
</AutoHidden>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import Zoom from "@material-ui/core/Zoom";
|
||||
|
||||
|
||||
function AutoHidden ({ children, enable }){
|
||||
function AutoHidden({ children, enable }) {
|
||||
const [hidden, setHidden] = useState(false);
|
||||
|
||||
let prev = window.scrollY;
|
||||
|
|
@ -10,33 +9,29 @@ function AutoHidden ({ children, enable }){
|
|||
const show = 50;
|
||||
|
||||
useEffect(() => {
|
||||
const handleNavigation = (e) => {
|
||||
const handleNavigation = e => {
|
||||
const window = e.currentTarget;
|
||||
|
||||
if (prev > window.scrollY) {
|
||||
if (lastUpdate - window.scrollY > show){
|
||||
if (lastUpdate - window.scrollY > show) {
|
||||
lastUpdate = window.scrollY;
|
||||
setHidden(false);
|
||||
}
|
||||
} else if (prev < window.scrollY) {
|
||||
if (window.scrollY - lastUpdate > show){
|
||||
if (window.scrollY - lastUpdate > show) {
|
||||
lastUpdate = window.scrollY;
|
||||
setHidden(true);
|
||||
}
|
||||
}
|
||||
prev = window.scrollY;
|
||||
};
|
||||
if (enable){
|
||||
window.addEventListener('scroll', e => handleNavigation(e));
|
||||
if (enable) {
|
||||
window.addEventListener("scroll", e => handleNavigation(e));
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
}, [enable])
|
||||
}, [enable]);
|
||||
|
||||
return (
|
||||
<Zoom in={!hidden}>
|
||||
{children}
|
||||
</Zoom>
|
||||
)
|
||||
return <Zoom in={!hidden}>{children}</Zoom>;
|
||||
}
|
||||
|
||||
export default AutoHidden
|
||||
export default AutoHidden;
|
||||
|
|
|
|||
|
|
@ -5,12 +5,16 @@ import SpeedDialIcon from "@material-ui/lab/SpeedDialIcon";
|
|||
import SpeedDialAction from "@material-ui/lab/SpeedDialAction";
|
||||
import CreateNewFolderIcon from "@material-ui/icons/CreateNewFolder";
|
||||
import PublishIcon from "@material-ui/icons/Publish";
|
||||
import { openCreateFileDialog, openCreateFolderDialog, toggleSnackbar } from "../../actions";
|
||||
import {useDispatch} from "react-redux";
|
||||
import {
|
||||
openCreateFileDialog,
|
||||
openCreateFolderDialog,
|
||||
toggleSnackbar
|
||||
} from "../../actions";
|
||||
import { useDispatch } from "react-redux";
|
||||
import AutoHidden from "./AutoHidden";
|
||||
import statusHelper from "../../utils/page"
|
||||
import statusHelper from "../../utils/page";
|
||||
import Backdrop from "@material-ui/core/Backdrop";
|
||||
import {FolderUpload,FilePlus} from "mdi-material-ui";
|
||||
import { FolderUpload, FilePlus } from "mdi-material-ui";
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
fab: {
|
||||
|
|
@ -29,11 +33,11 @@ const useStyles = makeStyles(() => ({
|
|||
zIndex: 9999,
|
||||
right: 7
|
||||
},
|
||||
'@global': {
|
||||
'.MuiSpeedDialAction-staticTooltipLabel': {
|
||||
width:100,
|
||||
},
|
||||
},
|
||||
"@global": {
|
||||
".MuiSpeedDialAction-staticTooltipLabel": {
|
||||
width: 100
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
export default function UploadButton(props) {
|
||||
|
|
@ -49,13 +53,11 @@ export default function UploadButton(props) {
|
|||
[dispatch]
|
||||
);
|
||||
const OpenNewFolderDialog = useCallback(
|
||||
() =>
|
||||
dispatch(openCreateFolderDialog()),
|
||||
() => dispatch(openCreateFolderDialog()),
|
||||
[dispatch]
|
||||
);
|
||||
const OpenNewFileDialog = useCallback(
|
||||
() =>
|
||||
dispatch(openCreateFileDialog()),
|
||||
() => dispatch(openCreateFileDialog()),
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
|
|
@ -63,20 +65,13 @@ export default function UploadButton(props) {
|
|||
setQueued(props.Queued);
|
||||
}, [props.Queued]);
|
||||
|
||||
const openUpload = id =>{
|
||||
const uploadButton = document.getElementsByClassName(
|
||||
id
|
||||
)[0];
|
||||
if (document.body.contains(uploadButton)) {
|
||||
uploadButton.click();
|
||||
} else {
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"上传组件还未加载完成",
|
||||
"warning"
|
||||
);
|
||||
}
|
||||
const openUpload = id => {
|
||||
const uploadButton = document.getElementsByClassName(id)[0];
|
||||
if (document.body.contains(uploadButton)) {
|
||||
uploadButton.click();
|
||||
} else {
|
||||
ToggleSnackbar("top", "right", "上传组件还未加载完成", "warning");
|
||||
}
|
||||
};
|
||||
const uploadClicked = () => {
|
||||
if (open) {
|
||||
|
|
@ -112,44 +107,58 @@ export default function UploadButton(props) {
|
|||
ariaLabel="SpeedDial openIcon example"
|
||||
hidden={false}
|
||||
tooltipTitle="上传文件"
|
||||
icon={<SpeedDialIcon openIcon={!statusHelper.isMobile()&&<PublishIcon />} />}
|
||||
icon={
|
||||
<SpeedDialIcon
|
||||
openIcon={
|
||||
!statusHelper.isMobile() && <PublishIcon />
|
||||
}
|
||||
/>
|
||||
}
|
||||
onClose={handleClose}
|
||||
FabProps={{
|
||||
onClick: () => !statusHelper.isMobile() && uploadClicked(),
|
||||
color: "secondary",
|
||||
onClick: () =>
|
||||
!statusHelper.isMobile() && uploadClicked(),
|
||||
color: "secondary"
|
||||
}}
|
||||
onOpen={handleOpen}
|
||||
open={open}
|
||||
>
|
||||
{statusHelper.isMobile() && <SpeedDialAction
|
||||
key="UploadFile"
|
||||
icon={<PublishIcon />}
|
||||
tooltipOpen
|
||||
tooltipTitle="上传文件"
|
||||
onClick= {() => uploadClicked()}
|
||||
title={"上传文件"}/>}
|
||||
{!statusHelper.isMobile() && <SpeedDialAction
|
||||
key="UploadFolder"
|
||||
icon={<FolderUpload />}
|
||||
tooltipOpen
|
||||
tooltipTitle="上传目录"
|
||||
onClick= {() => openUpload("uploadFolderForm")}
|
||||
title={"上传目录"}/>}
|
||||
{statusHelper.isMobile() && (
|
||||
<SpeedDialAction
|
||||
key="UploadFile"
|
||||
icon={<PublishIcon />}
|
||||
tooltipOpen
|
||||
tooltipTitle="上传文件"
|
||||
onClick={() => uploadClicked()}
|
||||
title={"上传文件"}
|
||||
/>
|
||||
)}
|
||||
{!statusHelper.isMobile() && (
|
||||
<SpeedDialAction
|
||||
key="UploadFolder"
|
||||
icon={<FolderUpload />}
|
||||
tooltipOpen
|
||||
tooltipTitle="上传目录"
|
||||
onClick={() => openUpload("uploadFolderForm")}
|
||||
title={"上传目录"}
|
||||
/>
|
||||
)}
|
||||
<SpeedDialAction
|
||||
key="NewFolder"
|
||||
icon={<CreateNewFolderIcon />}
|
||||
tooltipOpen
|
||||
tooltipTitle="新建目录"
|
||||
onClick= {() => OpenNewFolderDialog()}
|
||||
title={"新建目录"}/>
|
||||
onClick={() => OpenNewFolderDialog()}
|
||||
title={"新建目录"}
|
||||
/>
|
||||
<SpeedDialAction
|
||||
key="NewFile"
|
||||
icon={<FilePlus />}
|
||||
tooltipOpen
|
||||
tooltipTitle="新建文件"
|
||||
onClick= {() => OpenNewFileDialog()}
|
||||
title={"新建文件"}/>
|
||||
|
||||
onClick={() => OpenNewFileDialog()}
|
||||
title={"新建文件"}
|
||||
/>
|
||||
</SpeedDial>
|
||||
</Badge>
|
||||
</AutoHidden>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React from "react";
|
||||
import { makeStyles } from "@material-ui/core";
|
||||
import SaveIcon from "@material-ui/icons/Save";
|
||||
import CheckIcon from '@material-ui/icons/Check';
|
||||
import CheckIcon from "@material-ui/icons/Check";
|
||||
import AutoHidden from "./AutoHidden";
|
||||
import statusHelper from "../../utils/page";
|
||||
import Fab from "@material-ui/core/Fab";
|
||||
|
|
@ -40,16 +40,16 @@ const useStyles = makeStyles(theme => ({
|
|||
},
|
||||
buttonSuccess: {
|
||||
backgroundColor: green[500],
|
||||
'&:hover': {
|
||||
backgroundColor: green[700],
|
||||
},
|
||||
},
|
||||
"&:hover": {
|
||||
backgroundColor: green[700]
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
export default function SaveButton(props) {
|
||||
const classes = useStyles();
|
||||
const buttonClassname = clsx({
|
||||
[classes.buttonSuccess]: props.status==="success",
|
||||
[classes.buttonSuccess]: props.status === "success"
|
||||
});
|
||||
|
||||
return (
|
||||
|
|
@ -64,14 +64,19 @@ export default function SaveButton(props) {
|
|||
disabled={props.status === "loading"}
|
||||
aria-label="add"
|
||||
>
|
||||
{props.status==="success" ? <CheckIcon /> : <SaveIcon />}
|
||||
{props.status === "success" ? (
|
||||
<CheckIcon />
|
||||
) : (
|
||||
<SaveIcon />
|
||||
)}
|
||||
</Fab>
|
||||
</Tooltip>
|
||||
{props.status === "loading"&&<CircularProgress
|
||||
size={68}
|
||||
className={classes.fabProgress}
|
||||
/>}
|
||||
|
||||
{props.status === "loading" && (
|
||||
<CircularProgress
|
||||
size={68}
|
||||
className={classes.fabProgress}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</AutoHidden>
|
||||
|
|
|
|||
|
|
@ -53,8 +53,8 @@ const styles = theme => ({
|
|||
marginTop: "20px",
|
||||
marginBottom: "20px"
|
||||
},
|
||||
margin:{
|
||||
marginTop:theme.spacing(2),
|
||||
margin: {
|
||||
marginTop: theme.spacing(2)
|
||||
}
|
||||
});
|
||||
const mapStateToProps = () => {
|
||||
|
|
@ -101,8 +101,11 @@ class DownloadComponent extends Component {
|
|||
});
|
||||
// 设定自动更新
|
||||
clearTimeout(this.interval);
|
||||
if(response.data.length > 0){
|
||||
this.interval = setTimeout(this.loadDownloading,1000 * response.data[0].interval);
|
||||
if (response.data.length > 0) {
|
||||
this.interval = setTimeout(
|
||||
this.loadDownloading,
|
||||
1000 * response.data[0].interval
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
|
|
@ -119,11 +122,13 @@ class DownloadComponent extends Component {
|
|||
this.setState({
|
||||
loading: true
|
||||
});
|
||||
API
|
||||
.get("/aria2/finished?page=" + ++this.page)
|
||||
API.get("/aria2/finished?page=" + ++this.page)
|
||||
.then(response => {
|
||||
this.setState({
|
||||
finishedList: [...this.state.finishedList,...response.data],
|
||||
finishedList: [
|
||||
...this.state.finishedList,
|
||||
...response.data
|
||||
],
|
||||
loading: false,
|
||||
continue: response.data.length >= 10
|
||||
});
|
||||
|
|
@ -142,7 +147,7 @@ class DownloadComponent extends Component {
|
|||
|
||||
return (
|
||||
<div className={classes.layout}>
|
||||
{user.group.allowRemoteDownload&& <RemoteDownloadButton/>}
|
||||
{user.group.allowRemoteDownload && <RemoteDownloadButton />}
|
||||
<Typography
|
||||
color="textSecondary"
|
||||
variant="h4"
|
||||
|
|
@ -157,7 +162,7 @@ class DownloadComponent extends Component {
|
|||
</IconButton>
|
||||
</Typography>
|
||||
{this.state.downloading.map((value, k) => (
|
||||
<DownloadingCard key={ k } task={value} />
|
||||
<DownloadingCard key={k} task={value} />
|
||||
))}
|
||||
<Typography
|
||||
color="textSecondary"
|
||||
|
|
@ -169,12 +174,9 @@ class DownloadComponent extends Component {
|
|||
<div className={classes.loadMore}>
|
||||
{this.state.finishedList.map((value, k) => {
|
||||
if (value.files) {
|
||||
return (
|
||||
<FinishedCard key={k} task={value}/>
|
||||
)
|
||||
return <FinishedCard key={k} task={value} />;
|
||||
}
|
||||
return null
|
||||
|
||||
return null;
|
||||
})}
|
||||
<Button
|
||||
size="large"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,10 @@
|
|||
import { Divider, ListItemIcon, MenuItem, Typography, withStyles } from "@material-ui/core";
|
||||
import {
|
||||
Divider,
|
||||
ListItemIcon,
|
||||
MenuItem,
|
||||
Typography,
|
||||
withStyles
|
||||
} from "@material-ui/core";
|
||||
import Menu from "@material-ui/core/Menu";
|
||||
import { Archive, Unarchive } from "@material-ui/icons";
|
||||
import RenameIcon from "@material-ui/icons/BorderColor";
|
||||
|
|
@ -12,27 +18,49 @@ import MoveIcon from "@material-ui/icons/Input";
|
|||
import LinkIcon from "@material-ui/icons/InsertLink";
|
||||
import OpenIcon from "@material-ui/icons/OpenInNew";
|
||||
import ShareIcon from "@material-ui/icons/Share";
|
||||
import { FolderUpload, MagnetOn ,FilePlus} from "mdi-material-ui";
|
||||
import { FolderUpload, MagnetOn, FilePlus } from "mdi-material-ui";
|
||||
import PropTypes from "prop-types";
|
||||
import React, { Component } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { withRouter } from "react-router-dom";
|
||||
import { openCompressDialog,openCreateFileDialog ,refreshFileList} from "../../actions";
|
||||
import { changeContextMenu, navigateTo, openCopyDialog, openCreateFolderDialog, openDecompressDialog, openGetSourceDialog, openLoadingDialog, openMoveDialog, openMusicDialog, openRemoteDownloadDialog, openRemoveDialog, openRenameDialog, openShareDialog, openTorrentDownloadDialog, setNavigatorLoadingStatus, setSelectedTarget, showImgPreivew, toggleSnackbar } from "../../actions/index";
|
||||
import {
|
||||
openCompressDialog,
|
||||
openCreateFileDialog,
|
||||
refreshFileList
|
||||
} from "../../actions";
|
||||
import {
|
||||
changeContextMenu,
|
||||
navigateTo,
|
||||
openCopyDialog,
|
||||
openCreateFolderDialog,
|
||||
openDecompressDialog,
|
||||
openGetSourceDialog,
|
||||
openLoadingDialog,
|
||||
openMoveDialog,
|
||||
openMusicDialog,
|
||||
openRemoteDownloadDialog,
|
||||
openRemoveDialog,
|
||||
openRenameDialog,
|
||||
openShareDialog,
|
||||
openTorrentDownloadDialog,
|
||||
setNavigatorLoadingStatus,
|
||||
setSelectedTarget,
|
||||
showImgPreivew,
|
||||
toggleSnackbar
|
||||
} from "../../actions/index";
|
||||
import { isCompressFile, isPreviewable, isTorrent } from "../../config";
|
||||
import Auth from "../../middleware/Auth";
|
||||
import { allowSharePreview } from "../../utils/index";
|
||||
import pathHelper from "../../utils/page";
|
||||
import RefreshIcon from "@material-ui/icons/Refresh";
|
||||
|
||||
|
||||
const styles = () => ({
|
||||
propover: {
|
||||
minWidth: "200px!important"
|
||||
},
|
||||
divider:{
|
||||
marginTop:4,
|
||||
marginBottom:4,
|
||||
divider: {
|
||||
marginTop: 4,
|
||||
marginBottom: 4
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -45,7 +73,7 @@ const mapStateToProps = state => {
|
|||
withFile: state.explorer.selectProps.withFile,
|
||||
path: state.navigator.path,
|
||||
selected: state.explorer.selected,
|
||||
keywords: state.explorer.keywords,
|
||||
keywords: state.explorer.keywords
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -113,7 +141,7 @@ const mapDispatchToProps = dispatch => {
|
|||
},
|
||||
refreshFileList: () => {
|
||||
dispatch(refreshFileList());
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -195,8 +223,8 @@ class ContextMenuCompoment extends Component {
|
|||
this.props.selected[0].path === "/"
|
||||
? this.props.selected[0].path + this.props.selected[0].name
|
||||
: this.props.selected[0].path +
|
||||
"/" +
|
||||
this.props.selected[0].name;
|
||||
"/" +
|
||||
this.props.selected[0].name;
|
||||
switch (isPreviewable(this.props.selected[0].name)) {
|
||||
case "img":
|
||||
this.props.showImgPreivew(this.props.selected[0]);
|
||||
|
|
@ -205,15 +233,18 @@ class ContextMenuCompoment extends Component {
|
|||
if (isShare) {
|
||||
this.props.history.push(
|
||||
this.props.selected[0].key +
|
||||
"/doc?name=" +
|
||||
encodeURIComponent(this.props.selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
"/doc?name=" +
|
||||
encodeURIComponent(this.props.selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.props.history.push(
|
||||
"/doc?p=" + encodeURIComponent(previewPath) + "&id=" + this.props.selected[0].id
|
||||
"/doc?p=" +
|
||||
encodeURIComponent(previewPath) +
|
||||
"&id=" +
|
||||
this.props.selected[0].id
|
||||
);
|
||||
return;
|
||||
case "audio":
|
||||
|
|
@ -223,60 +254,72 @@ class ContextMenuCompoment extends Component {
|
|||
if (isShare) {
|
||||
this.props.history.push(
|
||||
this.props.selected[0].key +
|
||||
"/video?name=" +
|
||||
encodeURIComponent(this.props.selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
"/video?name=" +
|
||||
encodeURIComponent(this.props.selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.props.history.push(
|
||||
"/video?p=" + encodeURIComponent(previewPath) + "&id=" + this.props.selected[0].id
|
||||
"/video?p=" +
|
||||
encodeURIComponent(previewPath) +
|
||||
"&id=" +
|
||||
this.props.selected[0].id
|
||||
);
|
||||
return;
|
||||
case "pdf":
|
||||
if (isShare) {
|
||||
this.props.history.push(
|
||||
this.props.selected[0].key +
|
||||
"/pdf?name=" +
|
||||
encodeURIComponent(this.props.selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
"/pdf?name=" +
|
||||
encodeURIComponent(this.props.selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.props.history.push(
|
||||
"/pdf?p=" + encodeURIComponent(previewPath) + "&id=" + this.props.selected[0].id
|
||||
"/pdf?p=" +
|
||||
encodeURIComponent(previewPath) +
|
||||
"&id=" +
|
||||
this.props.selected[0].id
|
||||
);
|
||||
return;
|
||||
case "edit":
|
||||
if (isShare) {
|
||||
this.props.history.push(
|
||||
this.props.selected[0].key +
|
||||
"/text?name=" +
|
||||
encodeURIComponent(this.props.selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
"/text?name=" +
|
||||
encodeURIComponent(this.props.selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.props.history.push(
|
||||
"/text?p=" + encodeURIComponent(previewPath) + "&id=" + this.props.selected[0].id
|
||||
"/text?p=" +
|
||||
encodeURIComponent(previewPath) +
|
||||
"&id=" +
|
||||
this.props.selected[0].id
|
||||
);
|
||||
return;
|
||||
case "code":
|
||||
if (isShare) {
|
||||
this.props.history.push(
|
||||
this.props.selected[0].key +
|
||||
"/code?name=" +
|
||||
encodeURIComponent(this.props.selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
"/code?name=" +
|
||||
encodeURIComponent(this.props.selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.props.history.push(
|
||||
"/code?p=" + encodeURIComponent(previewPath) + "&id=" + this.props.selected[0].id
|
||||
"/code?p=" +
|
||||
encodeURIComponent(previewPath) +
|
||||
"&id=" +
|
||||
this.props.selected[0].id
|
||||
);
|
||||
return;
|
||||
default:
|
||||
|
|
@ -310,21 +353,26 @@ class ContextMenuCompoment extends Component {
|
|||
>
|
||||
{this.props.menuType === "empty" && (
|
||||
<div>
|
||||
<MenuItem onClick={()=>{
|
||||
this.props.refreshFileList();
|
||||
this.props.changeContextMenu(this.props.menuType, false)
|
||||
}
|
||||
|
||||
}>
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
this.props.refreshFileList();
|
||||
this.props.changeContextMenu(
|
||||
this.props.menuType,
|
||||
false
|
||||
);
|
||||
}}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<RefreshIcon />
|
||||
</ListItemIcon>
|
||||
<Typography variant="inherit">
|
||||
刷新
|
||||
</Typography>
|
||||
<Typography variant="inherit">刷新</Typography>
|
||||
</MenuItem>
|
||||
<Divider className={classes.divider}/>
|
||||
<MenuItem onClick={()=>this.clickUpload("uploadFileForm")}>
|
||||
<Divider className={classes.divider} />
|
||||
<MenuItem
|
||||
onClick={() =>
|
||||
this.clickUpload("uploadFileForm")
|
||||
}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<UploadIcon />
|
||||
</ListItemIcon>
|
||||
|
|
@ -332,7 +380,11 @@ class ContextMenuCompoment extends Component {
|
|||
上传文件
|
||||
</Typography>
|
||||
</MenuItem>
|
||||
<MenuItem onClick={()=>this.clickUpload("uploadFolderForm")}>
|
||||
<MenuItem
|
||||
onClick={() =>
|
||||
this.clickUpload("uploadFolderForm")
|
||||
}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<FolderUpload />
|
||||
</ListItemIcon>
|
||||
|
|
@ -355,7 +407,7 @@ class ContextMenuCompoment extends Component {
|
|||
</MenuItem>
|
||||
)}
|
||||
|
||||
<Divider className={classes.divider}/>
|
||||
<Divider className={classes.divider} />
|
||||
<MenuItem
|
||||
onClick={() =>
|
||||
this.props.openCreateFolderDialog()
|
||||
|
|
@ -394,7 +446,9 @@ class ContextMenuCompoment extends Component {
|
|||
进入
|
||||
</Typography>
|
||||
</MenuItem>
|
||||
{isHomePage && <Divider className={classes.divider} />}
|
||||
{isHomePage && (
|
||||
<Divider className={classes.divider} />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{!this.props.isMultiple &&
|
||||
|
|
@ -428,7 +482,9 @@ class ContextMenuCompoment extends Component {
|
|||
下载
|
||||
</Typography>
|
||||
</MenuItem>
|
||||
{isHomePage && <Divider className={classes.divider} />}
|
||||
{isHomePage && (
|
||||
<Divider className={classes.divider} />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
@ -546,7 +602,7 @@ class ContextMenuCompoment extends Component {
|
|||
重命名
|
||||
</Typography>
|
||||
</MenuItem>
|
||||
{this.props.keywords === "" &&
|
||||
{this.props.keywords === "" && (
|
||||
<MenuItem
|
||||
onClick={() =>
|
||||
this.props.openCopyDialog()
|
||||
|
|
@ -559,13 +615,12 @@ class ContextMenuCompoment extends Component {
|
|||
复制
|
||||
</Typography>
|
||||
</MenuItem>
|
||||
}
|
||||
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{isHomePage && (
|
||||
<div>
|
||||
{this.props.keywords === "" &&
|
||||
{this.props.keywords === "" && (
|
||||
<MenuItem
|
||||
onClick={() =>
|
||||
this.props.openMoveDialog()
|
||||
|
|
@ -578,7 +633,7 @@ class ContextMenuCompoment extends Component {
|
|||
移动
|
||||
</Typography>
|
||||
</MenuItem>
|
||||
}
|
||||
)}
|
||||
|
||||
<Divider className={classes.divider} />
|
||||
<MenuItem
|
||||
|
|
|
|||
|
|
@ -1,74 +1,78 @@
|
|||
import React from 'react'
|
||||
import { useDragLayer } from 'react-dnd'
|
||||
import Preview from './Preview'
|
||||
import React from "react";
|
||||
import { useDragLayer } from "react-dnd";
|
||||
import Preview from "./Preview";
|
||||
const layerStyles = {
|
||||
position: 'fixed',
|
||||
pointerEvents: 'none',
|
||||
zIndex: 100,
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
}
|
||||
position: "fixed",
|
||||
pointerEvents: "none",
|
||||
zIndex: 100,
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: "100%",
|
||||
height: "100%"
|
||||
};
|
||||
function snapToGrid(x, y) {
|
||||
const snappedX = Math.round(x / 32) * 32
|
||||
const snappedY = Math.round(y / 32) * 32
|
||||
return [snappedX, snappedY]
|
||||
const snappedX = Math.round(x / 32) * 32;
|
||||
const snappedY = Math.round(y / 32) * 32;
|
||||
return [snappedX, snappedY];
|
||||
}
|
||||
function getItemStyles(initialOffset, currentOffset, isSnapToGrid) {
|
||||
if (!initialOffset || !currentOffset) {
|
||||
return {
|
||||
display: 'none',
|
||||
if (!initialOffset || !currentOffset) {
|
||||
return {
|
||||
display: "none"
|
||||
};
|
||||
}
|
||||
}
|
||||
let { x, y } = currentOffset
|
||||
if (isSnapToGrid) {
|
||||
x -= initialOffset.x
|
||||
y -= initialOffset.y
|
||||
;[x, y] = snapToGrid(x, y)
|
||||
x += initialOffset.x
|
||||
y += initialOffset.y
|
||||
}
|
||||
const transform = `translate(${x}px, ${y}px)`
|
||||
return {
|
||||
transform,
|
||||
WebkitTransform: transform,
|
||||
opacity:y>200?1:0.4,
|
||||
}
|
||||
let { x, y } = currentOffset;
|
||||
if (isSnapToGrid) {
|
||||
x -= initialOffset.x;
|
||||
y -= initialOffset.y;
|
||||
[x, y] = snapToGrid(x, y);
|
||||
x += initialOffset.x;
|
||||
y += initialOffset.y;
|
||||
}
|
||||
const transform = `translate(${x}px, ${y}px)`;
|
||||
return {
|
||||
transform,
|
||||
WebkitTransform: transform,
|
||||
opacity: y > 200 ? 1 : 0.4
|
||||
};
|
||||
}
|
||||
const CustomDragLayer = props => {
|
||||
const {
|
||||
itemType,
|
||||
isDragging,
|
||||
item,
|
||||
initialOffset,
|
||||
currentOffset,
|
||||
} = useDragLayer(monitor => ({
|
||||
item: monitor.getItem(),
|
||||
itemType: monitor.getItemType(),
|
||||
initialOffset: monitor.getInitialSourceClientOffset(),
|
||||
currentOffset: monitor.getSourceClientOffset(),
|
||||
isDragging: monitor.isDragging(),
|
||||
}))
|
||||
function renderItem() {
|
||||
switch (itemType) {
|
||||
case "object":
|
||||
return <Preview object={item.object} />
|
||||
default:
|
||||
return null
|
||||
const {
|
||||
itemType,
|
||||
isDragging,
|
||||
item,
|
||||
initialOffset,
|
||||
currentOffset
|
||||
} = useDragLayer(monitor => ({
|
||||
item: monitor.getItem(),
|
||||
itemType: monitor.getItemType(),
|
||||
initialOffset: monitor.getInitialSourceClientOffset(),
|
||||
currentOffset: monitor.getSourceClientOffset(),
|
||||
isDragging: monitor.isDragging()
|
||||
}));
|
||||
function renderItem() {
|
||||
switch (itemType) {
|
||||
case "object":
|
||||
return <Preview object={item.object} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isDragging) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<div style={layerStyles}>
|
||||
<div
|
||||
style={getItemStyles(initialOffset, currentOffset, props.snapToGrid)}
|
||||
>
|
||||
{renderItem()}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default CustomDragLayer
|
||||
if (!isDragging) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div style={layerStyles}>
|
||||
<div
|
||||
style={getItemStyles(
|
||||
initialOffset,
|
||||
currentOffset,
|
||||
props.snapToGrid
|
||||
)}
|
||||
>
|
||||
{renderItem()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default CustomDragLayer;
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
import React from "react";
|
||||
import { useDrop } from "react-dnd";
|
||||
import Folder from "../Folder"
|
||||
export default function FolderDropWarpper({ folder}) {
|
||||
import Folder from "../Folder";
|
||||
export default function FolderDropWarpper({ folder }) {
|
||||
const [{ canDrop, isOver }, drop] = useDrop({
|
||||
accept: "object",
|
||||
drop: () => ({ folder }),
|
||||
collect: monitor => ({
|
||||
isOver: monitor.isOver(),
|
||||
canDrop: (monitor.canDrop())
|
||||
canDrop: monitor.canDrop()
|
||||
})
|
||||
});
|
||||
const isActive = canDrop && isOver;
|
||||
return (
|
||||
<div ref={drop}>
|
||||
<Folder folder={folder} isActive={isActive}/></div>
|
||||
<Folder folder={folder} isActive={isActive} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -5,21 +5,21 @@ import { useSelector } from "react-redux";
|
|||
import { makeStyles } from "@material-ui/core";
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
dragging:{
|
||||
width:"200px",
|
||||
dragging: {
|
||||
width: "200px"
|
||||
},
|
||||
cardDragged: {
|
||||
position: "absolute",
|
||||
"transform-origin": "bottom left",
|
||||
},
|
||||
"transform-origin": "bottom left"
|
||||
}
|
||||
}));
|
||||
|
||||
const diliverIcon = (object,viewMethod,classes)=>{
|
||||
const diliverIcon = (object, viewMethod, classes) => {
|
||||
return (
|
||||
<>
|
||||
{object.type === "dir" && viewMethod !== "list" && (
|
||||
<div className={classes.dragging}>
|
||||
<SmallIcon file={object} />
|
||||
<SmallIcon file={object} />
|
||||
</div>
|
||||
)}
|
||||
{object.type === "file" && viewMethod === "icon" && (
|
||||
|
|
@ -27,15 +27,14 @@ const diliverIcon = (object,viewMethod,classes)=>{
|
|||
<FileIcon file={object} />
|
||||
</div>
|
||||
)}
|
||||
{object.type === "file" &&
|
||||
viewMethod === "smallIcon" && (
|
||||
<div className={classes.dragging}>
|
||||
{object.type === "file" && viewMethod === "smallIcon" && (
|
||||
<div className={classes.dragging}>
|
||||
<SmallIcon file={object} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const Preview = props => {
|
||||
const selected = useSelector(state => state.explorer.selected);
|
||||
|
|
@ -45,22 +44,24 @@ const Preview = props => {
|
|||
const classes = useStyles();
|
||||
return (
|
||||
<>
|
||||
{selected.length === 0 && diliverIcon(props.object,viewMethod,classes)}
|
||||
{selected.length>0&&<>
|
||||
{selected.slice(0, 3).map((card, i) => (
|
||||
<div
|
||||
key={card.id}
|
||||
className={classes.cardDragged}
|
||||
style={{
|
||||
zIndex: selected.length - i,
|
||||
transform: `rotateZ(${-i * 2.5}deg)`,
|
||||
}}
|
||||
>
|
||||
{diliverIcon(card,viewMethod,classes)}
|
||||
</div>
|
||||
))}
|
||||
{selected.length === 0 &&
|
||||
diliverIcon(props.object, viewMethod, classes)}
|
||||
{selected.length > 0 && (
|
||||
<>
|
||||
{selected.slice(0, 3).map((card, i) => (
|
||||
<div
|
||||
key={card.id}
|
||||
className={classes.cardDragged}
|
||||
style={{
|
||||
zIndex: selected.length - i,
|
||||
transform: `rotateZ(${-i * 2.5}deg)`
|
||||
}}
|
||||
>
|
||||
{diliverIcon(card, viewMethod, classes)}
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
}
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,15 @@
|
|||
import { CircularProgress, Grid, Paper, Table, TableBody, TableCell, TableHead, TableRow, Typography, withStyles } from "@material-ui/core";
|
||||
import {
|
||||
CircularProgress,
|
||||
Grid,
|
||||
Paper,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableRow,
|
||||
Typography,
|
||||
withStyles
|
||||
} from "@material-ui/core";
|
||||
import TableSortLabel from "@material-ui/core/TableSortLabel";
|
||||
import SadIcon from "@material-ui/icons/SentimentVeryDissatisfied";
|
||||
import EmptyIcon from "@material-ui/icons/Unarchive";
|
||||
|
|
@ -8,8 +19,14 @@ import React, { Component } from "react";
|
|||
import { configure, GlobalHotKeys } from "react-hotkeys";
|
||||
import { connect } from "react-redux";
|
||||
import { withRouter } from "react-router-dom";
|
||||
import { changeContextMenu, navigateTo, navigateUp, openRemoveDialog, setSelectedTarget } from "../../actions/index";
|
||||
import explorer from "../../redux/explorer"
|
||||
import {
|
||||
changeContextMenu,
|
||||
navigateTo,
|
||||
navigateUp,
|
||||
openRemoveDialog,
|
||||
setSelectedTarget
|
||||
} from "../../actions/index";
|
||||
import explorer from "../../redux/explorer";
|
||||
import { isMac } from "../../utils";
|
||||
import pathHelper from "../../utils/page";
|
||||
import ContextMenu from "./ContextMenu";
|
||||
|
|
@ -161,7 +178,7 @@ class ExplorerCompoment extends Component {
|
|||
super();
|
||||
this.keyMap = {
|
||||
DELETE_FILE: "del",
|
||||
SELECT_ALL: `${isMac() ? 'command' : 'ctrl'}+a`
|
||||
SELECT_ALL: `${isMac() ? "command" : "ctrl"}+a`
|
||||
};
|
||||
|
||||
this.handlers = {
|
||||
|
|
@ -187,8 +204,8 @@ class ExplorerCompoment extends Component {
|
|||
};
|
||||
|
||||
configure({
|
||||
ignoreTags: ['input', 'select', 'textarea'],
|
||||
})
|
||||
ignoreTags: ["input", "select", "textarea"]
|
||||
});
|
||||
}
|
||||
|
||||
contextMenu = e => {
|
||||
|
|
@ -218,236 +235,198 @@ class ExplorerCompoment extends Component {
|
|||
const { classes } = this.props;
|
||||
const isHomePage = pathHelper.isHomePage(this.props.location.pathname);
|
||||
|
||||
const showView = !this.props.loading && (this.props.dirList.length !== 0 ||
|
||||
this.props.fileList.length !== 0)
|
||||
const showView =
|
||||
!this.props.loading &&
|
||||
(this.props.dirList.length !== 0 ||
|
||||
this.props.fileList.length !== 0);
|
||||
const listView = (
|
||||
<Table className={classes.table}>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<TableSortLabel
|
||||
active={
|
||||
this.props.sortMethod ===
|
||||
"namePos" ||
|
||||
this.props.sortMethod ===
|
||||
"nameRev"
|
||||
}
|
||||
direction={
|
||||
this.props.sortMethod ===
|
||||
"namePos"
|
||||
? "asc"
|
||||
: "des"
|
||||
}
|
||||
onClick={() => {
|
||||
this.props.changeSort(
|
||||
this.props.sortMethod ===
|
||||
"namePos"
|
||||
? "nameRev"
|
||||
: "namePos"
|
||||
);
|
||||
}}
|
||||
>
|
||||
名称
|
||||
{this.props.sortMethod ===
|
||||
"namePos" ||
|
||||
this.props.sortMethod ===
|
||||
"nameRev" ? (
|
||||
<span
|
||||
className={
|
||||
classes.visuallyHidden
|
||||
}
|
||||
>
|
||||
{this.props.sortMethod ===
|
||||
"nameRev"
|
||||
? "sorted descending"
|
||||
: "sorted ascending"}
|
||||
</span>
|
||||
) : null}
|
||||
</TableSortLabel>
|
||||
</TableCell>
|
||||
<TableCell className={classes.hideAuto}>
|
||||
<TableSortLabel
|
||||
active={
|
||||
this.props.sortMethod ===
|
||||
"sizePos" ||
|
||||
this.props.sortMethod ===
|
||||
"sizeRes"
|
||||
}
|
||||
direction={
|
||||
this.props.sortMethod ===
|
||||
"sizePos"
|
||||
? "asc"
|
||||
: "des"
|
||||
}
|
||||
onClick={() => {
|
||||
this.props.changeSort(
|
||||
this.props.sortMethod ===
|
||||
"sizePos"
|
||||
? "sizeRes"
|
||||
: "sizePos"
|
||||
);
|
||||
}}
|
||||
>
|
||||
大小
|
||||
{this.props.sortMethod ===
|
||||
"sizePos" ||
|
||||
this.props.sortMethod ===
|
||||
"sizeRes" ? (
|
||||
<span
|
||||
className={
|
||||
classes.visuallyHidden
|
||||
}
|
||||
>
|
||||
{this.props.sortMethod ===
|
||||
"sizeRes"
|
||||
? "sorted descending"
|
||||
: "sorted ascending"}
|
||||
</span>
|
||||
) : null}
|
||||
</TableSortLabel>
|
||||
</TableCell>
|
||||
<TableCell className={classes.hideAuto}>
|
||||
<TableSortLabel
|
||||
active={
|
||||
this.props.sortMethod ===
|
||||
"timePos" ||
|
||||
this.props.sortMethod ===
|
||||
"timeRev"
|
||||
}
|
||||
direction={
|
||||
this.props.sortMethod ===
|
||||
"timePos"
|
||||
? "asc"
|
||||
: "des"
|
||||
}
|
||||
onClick={() => {
|
||||
this.props.changeSort(
|
||||
this.props.sortMethod ===
|
||||
"timePos"
|
||||
? "timeRev"
|
||||
: "timePos"
|
||||
);
|
||||
}}
|
||||
>
|
||||
日期
|
||||
{this.props.sortMethod ===
|
||||
"timePos" ||
|
||||
this.props.sortMethod ===
|
||||
"timeRev" ? (
|
||||
<span
|
||||
className={
|
||||
classes.visuallyHidden
|
||||
}
|
||||
>
|
||||
{this.props.sortMethod ===
|
||||
"sizeRes"
|
||||
? "sorted descending"
|
||||
: "sorted ascending"}
|
||||
</span>
|
||||
) : null}
|
||||
</TableSortLabel>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{pathHelper.isMobile() &&
|
||||
this.props.path !== "/" && (
|
||||
<ObjectIcon
|
||||
file={{
|
||||
type: "up",
|
||||
name: "上级目录"
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{this.props.dirList.map((value, index) => (
|
||||
<ObjectIcon key={value.id} file={value} index={index}/>
|
||||
))}
|
||||
{this.props.fileList.map((value, index) => (
|
||||
<ObjectIcon key={value.id} file={value} index={index}/>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
)
|
||||
<Table className={classes.table}>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<TableSortLabel
|
||||
active={
|
||||
this.props.sortMethod === "namePos" ||
|
||||
this.props.sortMethod === "nameRev"
|
||||
}
|
||||
direction={
|
||||
this.props.sortMethod === "namePos"
|
||||
? "asc"
|
||||
: "des"
|
||||
}
|
||||
onClick={() => {
|
||||
this.props.changeSort(
|
||||
this.props.sortMethod === "namePos"
|
||||
? "nameRev"
|
||||
: "namePos"
|
||||
);
|
||||
}}
|
||||
>
|
||||
名称
|
||||
{this.props.sortMethod === "namePos" ||
|
||||
this.props.sortMethod === "nameRev" ? (
|
||||
<span className={classes.visuallyHidden}>
|
||||
{this.props.sortMethod === "nameRev"
|
||||
? "sorted descending"
|
||||
: "sorted ascending"}
|
||||
</span>
|
||||
) : null}
|
||||
</TableSortLabel>
|
||||
</TableCell>
|
||||
<TableCell className={classes.hideAuto}>
|
||||
<TableSortLabel
|
||||
active={
|
||||
this.props.sortMethod === "sizePos" ||
|
||||
this.props.sortMethod === "sizeRes"
|
||||
}
|
||||
direction={
|
||||
this.props.sortMethod === "sizePos"
|
||||
? "asc"
|
||||
: "des"
|
||||
}
|
||||
onClick={() => {
|
||||
this.props.changeSort(
|
||||
this.props.sortMethod === "sizePos"
|
||||
? "sizeRes"
|
||||
: "sizePos"
|
||||
);
|
||||
}}
|
||||
>
|
||||
大小
|
||||
{this.props.sortMethod === "sizePos" ||
|
||||
this.props.sortMethod === "sizeRes" ? (
|
||||
<span className={classes.visuallyHidden}>
|
||||
{this.props.sortMethod === "sizeRes"
|
||||
? "sorted descending"
|
||||
: "sorted ascending"}
|
||||
</span>
|
||||
) : null}
|
||||
</TableSortLabel>
|
||||
</TableCell>
|
||||
<TableCell className={classes.hideAuto}>
|
||||
<TableSortLabel
|
||||
active={
|
||||
this.props.sortMethod === "timePos" ||
|
||||
this.props.sortMethod === "timeRev"
|
||||
}
|
||||
direction={
|
||||
this.props.sortMethod === "timePos"
|
||||
? "asc"
|
||||
: "des"
|
||||
}
|
||||
onClick={() => {
|
||||
this.props.changeSort(
|
||||
this.props.sortMethod === "timePos"
|
||||
? "timeRev"
|
||||
: "timePos"
|
||||
);
|
||||
}}
|
||||
>
|
||||
日期
|
||||
{this.props.sortMethod === "timePos" ||
|
||||
this.props.sortMethod === "timeRev" ? (
|
||||
<span className={classes.visuallyHidden}>
|
||||
{this.props.sortMethod === "sizeRes"
|
||||
? "sorted descending"
|
||||
: "sorted ascending"}
|
||||
</span>
|
||||
) : null}
|
||||
</TableSortLabel>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{pathHelper.isMobile() && this.props.path !== "/" && (
|
||||
<ObjectIcon
|
||||
file={{
|
||||
type: "up",
|
||||
name: "上级目录"
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{this.props.dirList.map((value, index) => (
|
||||
<ObjectIcon key={value.id} file={value} index={index} />
|
||||
))}
|
||||
{this.props.fileList.map((value, index) => (
|
||||
<ObjectIcon key={value.id} file={value} index={index} />
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
);
|
||||
|
||||
const normalView = (
|
||||
<div className={classes.flexFix}>
|
||||
{this.props.dirList.length !== 0 &&
|
||||
(
|
||||
<>
|
||||
<Typography
|
||||
data-clickAway={"true"}
|
||||
variant="body2"
|
||||
className={classes.typeHeader}
|
||||
>
|
||||
文件夹
|
||||
</Typography>
|
||||
<Grid
|
||||
data-clickAway={"true"}
|
||||
container
|
||||
spacing={0}
|
||||
alignItems="flex-start"
|
||||
>
|
||||
{this.props.dirList.map(
|
||||
(value, index) => (
|
||||
<Grid
|
||||
key={value.id}
|
||||
item
|
||||
xs={6}
|
||||
md={3}
|
||||
sm={4}
|
||||
lg={2}
|
||||
>
|
||||
<ObjectIcon
|
||||
key={value.id}
|
||||
file={value}
|
||||
index={index}
|
||||
/>
|
||||
</Grid>
|
||||
)
|
||||
)}
|
||||
</Grid>
|
||||
</>
|
||||
)}
|
||||
{this.props.fileList.length !== 0 &&
|
||||
(
|
||||
<>
|
||||
<Typography
|
||||
data-clickAway={"true"}
|
||||
variant="body2"
|
||||
className={classes.typeHeader}
|
||||
>
|
||||
文件
|
||||
</Typography>
|
||||
<Grid
|
||||
data-clickAway={"true"}
|
||||
container
|
||||
spacing={0}
|
||||
alignItems="flex-start"
|
||||
>
|
||||
{this.props.fileList.map(
|
||||
(value, index) => (
|
||||
<Grid
|
||||
key={value.id}
|
||||
item
|
||||
xs={6}
|
||||
md={3}
|
||||
sm={4}
|
||||
lg={2}
|
||||
>
|
||||
<ObjectIcon
|
||||
key={value.id}
|
||||
index={index}
|
||||
file={value}
|
||||
/>
|
||||
</Grid>
|
||||
)
|
||||
)}
|
||||
</Grid>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
const view = this.props.viewMethod === "list" ? listView : normalView
|
||||
<div className={classes.flexFix}>
|
||||
{this.props.dirList.length !== 0 && (
|
||||
<>
|
||||
<Typography
|
||||
data-clickAway={"true"}
|
||||
variant="body2"
|
||||
className={classes.typeHeader}
|
||||
>
|
||||
文件夹
|
||||
</Typography>
|
||||
<Grid
|
||||
data-clickAway={"true"}
|
||||
container
|
||||
spacing={0}
|
||||
alignItems="flex-start"
|
||||
>
|
||||
{this.props.dirList.map((value, index) => (
|
||||
<Grid
|
||||
key={value.id}
|
||||
item
|
||||
xs={6}
|
||||
md={3}
|
||||
sm={4}
|
||||
lg={2}
|
||||
>
|
||||
<ObjectIcon
|
||||
key={value.id}
|
||||
file={value}
|
||||
index={index}
|
||||
/>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</>
|
||||
)}
|
||||
{this.props.fileList.length !== 0 && (
|
||||
<>
|
||||
<Typography
|
||||
data-clickAway={"true"}
|
||||
variant="body2"
|
||||
className={classes.typeHeader}
|
||||
>
|
||||
文件
|
||||
</Typography>
|
||||
<Grid
|
||||
data-clickAway={"true"}
|
||||
container
|
||||
spacing={0}
|
||||
alignItems="flex-start"
|
||||
>
|
||||
{this.props.fileList.map((value, index) => (
|
||||
<Grid
|
||||
key={value.id}
|
||||
item
|
||||
xs={6}
|
||||
md={3}
|
||||
sm={4}
|
||||
lg={2}
|
||||
>
|
||||
<ObjectIcon
|
||||
key={value.id}
|
||||
index={index}
|
||||
file={value}
|
||||
/>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
const view = this.props.viewMethod === "list" ? listView : normalView;
|
||||
return (
|
||||
<div
|
||||
onContextMenu={this.contextMenu}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,10 @@
|
|||
import { ButtonBase, Divider, Tooltip, Typography, withStyles } from "@material-ui/core";
|
||||
import {
|
||||
ButtonBase,
|
||||
Divider,
|
||||
Tooltip,
|
||||
Typography,
|
||||
withStyles
|
||||
} from "@material-ui/core";
|
||||
import { lighten } from "@material-ui/core/styles";
|
||||
import classNames from "classnames";
|
||||
import PropTypes from "prop-types";
|
||||
|
|
@ -95,7 +101,7 @@ const styles = theme => ({
|
|||
backgroundColor: theme.palette.background.paper,
|
||||
borderRadius: "90%",
|
||||
paddingTop: "2px",
|
||||
color: theme.palette.text.secondary,
|
||||
color: theme.palette.text.secondary
|
||||
},
|
||||
hide: {
|
||||
display: "none"
|
||||
|
|
|
|||
|
|
@ -1,17 +1,22 @@
|
|||
import React, { Component } from 'react'
|
||||
import { DndProvider } from 'react-dnd'
|
||||
import HTML5Backend from 'react-dnd-html5-backend'
|
||||
import { connect } from "react-redux"
|
||||
import { withRouter } from "react-router-dom"
|
||||
import { closeAllModals, navigateTo, setSelectedTarget, toggleSnackbar } from "../../actions"
|
||||
import React, { Component } from "react";
|
||||
import { DndProvider } from "react-dnd";
|
||||
import HTML5Backend from "react-dnd-html5-backend";
|
||||
import { connect } from "react-redux";
|
||||
import { withRouter } from "react-router-dom";
|
||||
import {
|
||||
closeAllModals,
|
||||
navigateTo,
|
||||
setSelectedTarget,
|
||||
toggleSnackbar
|
||||
} from "../../actions";
|
||||
import { changeSubTitle } from "../../redux/viewUpdate/action";
|
||||
import pathHelper from "../../utils/page"
|
||||
import DragLayer from "./DnD/DragLayer"
|
||||
import Explorer from "./Explorer"
|
||||
import Modals from "./Modals"
|
||||
import Navigator from "./Navigator/Navigator"
|
||||
import pathHelper from "../../utils/page";
|
||||
import DragLayer from "./DnD/DragLayer";
|
||||
import Explorer from "./Explorer";
|
||||
import Modals from "./Modals";
|
||||
import Navigator from "./Navigator/Navigator";
|
||||
|
||||
const mapStateToProps = ()=>({});
|
||||
const mapStateToProps = () => ({});
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
|
|
@ -27,14 +32,14 @@ const mapDispatchToProps = dispatch => {
|
|||
closeAllModals: () => {
|
||||
dispatch(closeAllModals());
|
||||
},
|
||||
navigateTo:path=>{
|
||||
navigateTo: path => {
|
||||
dispatch(navigateTo(path));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class FileManager extends Component {
|
||||
constructor(props){
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.image = React.createRef();
|
||||
}
|
||||
|
|
@ -45,28 +50,28 @@ class FileManager extends Component {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (pathHelper.isHomePage(this.props.location.pathname)){
|
||||
if (pathHelper.isHomePage(this.props.location.pathname)) {
|
||||
this.props.changeSubTitle(null);
|
||||
}
|
||||
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
<Modals share={this.props.share}/>
|
||||
<Navigator isShare={this.props.isShare} share={this.props.share}/>
|
||||
<Explorer share={this.props.share}/>
|
||||
<DragLayer/>
|
||||
</DndProvider>
|
||||
<Modals share={this.props.share} />
|
||||
<Navigator
|
||||
isShare={this.props.isShare}
|
||||
share={this.props.share}
|
||||
/>
|
||||
<Explorer share={this.props.share} />
|
||||
<DragLayer />
|
||||
</DndProvider>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
FileManager.propTypes = {
|
||||
};
|
||||
FileManager.propTypes = {};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)((withRouter(FileManager)));
|
||||
)(withRouter(FileManager));
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import React from "react";
|
||||
import React from "react";
|
||||
import FolderIcon from "@material-ui/icons/Folder";
|
||||
import classNames from "classnames";
|
||||
import { ButtonBase, Typography, Tooltip, makeStyles } from "@material-ui/core";
|
||||
import { useSelector } from "react-redux";
|
||||
import {lighten} from "@material-ui/core/styles";
|
||||
import { lighten } from "@material-ui/core/styles";
|
||||
const useStyles = makeStyles(theme => ({
|
||||
container: {
|
||||
padding: "7px"
|
||||
|
|
@ -46,7 +46,7 @@ const useStyles = makeStyles(theme => ({
|
|||
backgroundColor: theme.palette.background.paper,
|
||||
borderRadius: "90%",
|
||||
paddingTop: "2px",
|
||||
color: theme.palette.text.secondary,
|
||||
color: theme.palette.text.secondary
|
||||
},
|
||||
folderNameSelected: {
|
||||
color:
|
||||
|
|
@ -65,12 +65,12 @@ const useStyles = makeStyles(theme => ({
|
|||
overflow: "hidden",
|
||||
marginRight: "20px"
|
||||
},
|
||||
active:{
|
||||
border: "2px solid " + theme.palette.primary.light,
|
||||
},
|
||||
active: {
|
||||
border: "2px solid " + theme.palette.primary.light
|
||||
}
|
||||
}));
|
||||
|
||||
export default function Folder({ folder,isActive }) {
|
||||
export default function Folder({ folder, isActive }) {
|
||||
const selected = useSelector(state => state.explorer.selected);
|
||||
|
||||
const classes = useStyles();
|
||||
|
|
@ -87,9 +87,9 @@ export default function Folder({ folder,isActive }) {
|
|||
{
|
||||
[classes.selected]: isSelected,
|
||||
[classes.notSelected]: !isSelected,
|
||||
[classes.active]: isActive,
|
||||
[classes.active]: isActive
|
||||
},
|
||||
classes.button,
|
||||
classes.button
|
||||
)}
|
||||
>
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ import { showImgPreivew } from "../../actions/index";
|
|||
import { imgPreviewSuffix } from "../../config";
|
||||
import { withStyles } from "@material-ui/core";
|
||||
import pathHelper from "../../utils/page";
|
||||
import {withRouter} from "react-router";
|
||||
import {PhotoSlider} from "react-photo-view";
|
||||
import 'react-photo-view/dist/index.css';
|
||||
import { withRouter } from "react-router";
|
||||
import { PhotoSlider } from "react-photo-view";
|
||||
import "react-photo-view/dist/index.css";
|
||||
import * as explorer from "../../redux/explorer/reducer";
|
||||
|
||||
const styles = () => ({});
|
||||
|
|
@ -39,21 +39,22 @@ class ImagPreviewComponent extends Component {
|
|||
const items = [];
|
||||
let firstOne = 0;
|
||||
if (nextProps.first.id !== "") {
|
||||
if (pathHelper.isSharePage(this.props.location.pathname) && !nextProps.first.path){
|
||||
if (
|
||||
pathHelper.isSharePage(this.props.location.pathname) &&
|
||||
!nextProps.first.path
|
||||
) {
|
||||
const newImg = {
|
||||
intro: nextProps.first.name,
|
||||
src:
|
||||
baseURL +
|
||||
"/share/preview/" +nextProps.first.key
|
||||
src: baseURL + "/share/preview/" + nextProps.first.key
|
||||
};
|
||||
firstOne = 0;
|
||||
items.push(newImg);
|
||||
this.setState({
|
||||
photoIndex:firstOne,
|
||||
photoIndex: firstOne,
|
||||
items: items,
|
||||
isOpen: true
|
||||
});
|
||||
return
|
||||
return;
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
nextProps.other.map(value => {
|
||||
|
|
@ -63,21 +64,22 @@ class ImagPreviewComponent extends Component {
|
|||
.toLowerCase();
|
||||
if (imgPreviewSuffix.indexOf(fileType) !== -1) {
|
||||
let src = "";
|
||||
if (pathHelper.isSharePage(this.props.location.pathname)){
|
||||
src = baseURL +
|
||||
"/share/preview/" + value.key
|
||||
src = src + "?path=" + encodeURIComponent( (value.path === "/"
|
||||
? value.path + value.name
|
||||
: value.path + "/" + value.name))
|
||||
|
||||
}else{
|
||||
src = baseURL +
|
||||
"/file/preview/" +
|
||||
value.id
|
||||
if (pathHelper.isSharePage(this.props.location.pathname)) {
|
||||
src = baseURL + "/share/preview/" + value.key;
|
||||
src =
|
||||
src +
|
||||
"?path=" +
|
||||
encodeURIComponent(
|
||||
value.path === "/"
|
||||
? value.path + value.name
|
||||
: value.path + "/" + value.name
|
||||
);
|
||||
} else {
|
||||
src = baseURL + "/file/preview/" + value.id;
|
||||
}
|
||||
const newImg = {
|
||||
intro: value.name,
|
||||
src:src,
|
||||
src: src
|
||||
};
|
||||
if (
|
||||
value.path === nextProps.first.path &&
|
||||
|
|
@ -89,7 +91,7 @@ class ImagPreviewComponent extends Component {
|
|||
}
|
||||
});
|
||||
this.setState({
|
||||
photoIndex:firstOne,
|
||||
photoIndex: firstOne,
|
||||
items: items,
|
||||
isOpen: true
|
||||
});
|
||||
|
|
@ -104,22 +106,23 @@ class ImagPreviewComponent extends Component {
|
|||
};
|
||||
|
||||
render() {
|
||||
const { photoIndex, isOpen,items } = this.state;
|
||||
const { photoIndex, isOpen, items } = this.state;
|
||||
|
||||
return (
|
||||
<div>
|
||||
{isOpen && (<PhotoSlider
|
||||
images={items}
|
||||
visible={isOpen}
|
||||
onClose={() => this.handleClose()}
|
||||
index={photoIndex}
|
||||
onIndexChange={(n) =>
|
||||
this.setState({
|
||||
photoIndex: n,
|
||||
})
|
||||
}
|
||||
|
||||
/>)}
|
||||
{isOpen && (
|
||||
<PhotoSlider
|
||||
images={items}
|
||||
visible={isOpen}
|
||||
onClose={() => this.handleClose()}
|
||||
index={photoIndex}
|
||||
onIndexChange={n =>
|
||||
this.setState({
|
||||
photoIndex: n
|
||||
})
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { withStyles } from "@material-ui/core";
|
|||
import Lightbox from "react-image-lightbox";
|
||||
import "react-image-lightbox/style.css";
|
||||
import pathHelper from "../../utils/page";
|
||||
import {withRouter} from "react-router";
|
||||
import { withRouter } from "react-router";
|
||||
|
||||
const styles = () => ({});
|
||||
|
||||
|
|
@ -38,21 +38,22 @@ class ImgPreviewCompoment extends Component {
|
|||
const items = [];
|
||||
let firstOne = 0;
|
||||
if (nextProps.first !== null) {
|
||||
if (pathHelper.isSharePage(this.props.location.pathname) && !nextProps.first.path){
|
||||
if (
|
||||
pathHelper.isSharePage(this.props.location.pathname) &&
|
||||
!nextProps.first.path
|
||||
) {
|
||||
const newImg = {
|
||||
title: nextProps.first.name,
|
||||
src:
|
||||
baseURL +
|
||||
"/share/preview/" +nextProps.first.key
|
||||
src: baseURL + "/share/preview/" + nextProps.first.key
|
||||
};
|
||||
firstOne = 0;
|
||||
items.push(newImg);
|
||||
this.setState({
|
||||
photoIndex:firstOne,
|
||||
photoIndex: firstOne,
|
||||
items: items,
|
||||
isOpen: true
|
||||
});
|
||||
return
|
||||
return;
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
nextProps.other.map(value => {
|
||||
|
|
@ -62,21 +63,22 @@ class ImgPreviewCompoment extends Component {
|
|||
.toLowerCase();
|
||||
if (imgPreviewSuffix.indexOf(fileType) !== -1) {
|
||||
let src = "";
|
||||
if (pathHelper.isSharePage(this.props.location.pathname)){
|
||||
src = baseURL +
|
||||
"/share/preview/" + value.key
|
||||
src = src + "?path=" + encodeURIComponent( (value.path === "/"
|
||||
? value.path + value.name
|
||||
: value.path + "/" + value.name))
|
||||
|
||||
}else{
|
||||
src = baseURL +
|
||||
"/file/preview/" +
|
||||
value.id
|
||||
if (pathHelper.isSharePage(this.props.location.pathname)) {
|
||||
src = baseURL + "/share/preview/" + value.key;
|
||||
src =
|
||||
src +
|
||||
"?path=" +
|
||||
encodeURIComponent(
|
||||
value.path === "/"
|
||||
? value.path + value.name
|
||||
: value.path + "/" + value.name
|
||||
);
|
||||
} else {
|
||||
src = baseURL + "/file/preview/" + value.id;
|
||||
}
|
||||
const newImg = {
|
||||
title: value.name,
|
||||
src:src,
|
||||
src: src
|
||||
};
|
||||
if (
|
||||
value.path === nextProps.first.path &&
|
||||
|
|
@ -88,7 +90,7 @@ class ImgPreviewCompoment extends Component {
|
|||
}
|
||||
});
|
||||
this.setState({
|
||||
photoIndex:firstOne,
|
||||
photoIndex: firstOne,
|
||||
items: items,
|
||||
isOpen: true
|
||||
});
|
||||
|
|
@ -103,34 +105,42 @@ class ImgPreviewCompoment extends Component {
|
|||
};
|
||||
|
||||
render() {
|
||||
const { photoIndex, isOpen,items } = this.state;
|
||||
const { photoIndex, isOpen, items } = this.state;
|
||||
|
||||
return (
|
||||
<div>
|
||||
{isOpen && (<Lightbox
|
||||
mainSrc={items[photoIndex].src}
|
||||
nextSrc={items[(photoIndex + 1) % items.length].src}
|
||||
prevSrc={items[(photoIndex + items.length - 1) % items.length].src}
|
||||
onCloseRequest={() => this.handleClose()}
|
||||
imageLoadErrorMessage = "无法加载此图像"
|
||||
imageCrossOrigin = "anonymous"
|
||||
imageTitle = {items[photoIndex].title}
|
||||
onMovePrevRequest={() =>
|
||||
this.setState({
|
||||
photoIndex: (photoIndex + items.length - 1) % items.length,
|
||||
})
|
||||
}
|
||||
reactModalStyle={{
|
||||
overlay:{
|
||||
zIndex:10000
|
||||
},
|
||||
}}
|
||||
onMoveNextRequest={() =>
|
||||
this.setState({
|
||||
photoIndex: (photoIndex + 1) % items.length,
|
||||
})
|
||||
}
|
||||
/>)}
|
||||
{isOpen && (
|
||||
<Lightbox
|
||||
mainSrc={items[photoIndex].src}
|
||||
nextSrc={items[(photoIndex + 1) % items.length].src}
|
||||
prevSrc={
|
||||
items[
|
||||
(photoIndex + items.length - 1) % items.length
|
||||
].src
|
||||
}
|
||||
onCloseRequest={() => this.handleClose()}
|
||||
imageLoadErrorMessage="无法加载此图像"
|
||||
imageCrossOrigin="anonymous"
|
||||
imageTitle={items[photoIndex].title}
|
||||
onMovePrevRequest={() =>
|
||||
this.setState({
|
||||
photoIndex:
|
||||
(photoIndex + items.length - 1) %
|
||||
items.length
|
||||
})
|
||||
}
|
||||
reactModalStyle={{
|
||||
overlay: {
|
||||
zIndex: 10000
|
||||
}
|
||||
}}
|
||||
onMoveNextRequest={() =>
|
||||
this.setState({
|
||||
photoIndex: (photoIndex + 1) % items.length
|
||||
})
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import {
|
|||
DialogContent,
|
||||
DialogTitle,
|
||||
DialogContentText,
|
||||
CircularProgress,
|
||||
CircularProgress
|
||||
} from "@material-ui/core";
|
||||
import Loading from "../Modals/Loading";
|
||||
import CopyDialog from "../Modals/Copy";
|
||||
|
|
@ -100,7 +100,7 @@ class ModalsCompoment extends Component {
|
|||
downloadURL: "",
|
||||
remoteDownloadPathSelect: false,
|
||||
source: "",
|
||||
purchaseCallback:null,
|
||||
purchaseCallback: null
|
||||
};
|
||||
|
||||
handleInputChange = e => {
|
||||
|
|
@ -121,17 +121,25 @@ class ModalsCompoment extends Component {
|
|||
// 打包下载
|
||||
if (nextProps.loading === true) {
|
||||
if (nextProps.loadingText === "打包中...") {
|
||||
if (pathHelper.isSharePage(this.props.location.pathname) && this.props.share && this.props.share.score > 0){
|
||||
if (
|
||||
pathHelper.isSharePage(this.props.location.pathname) &&
|
||||
this.props.share &&
|
||||
this.props.share.score > 0
|
||||
) {
|
||||
this.scoreHandler(this.archiveDownload);
|
||||
return
|
||||
return;
|
||||
}
|
||||
this.archiveDownload();
|
||||
} else if (nextProps.loadingText === "获取下载地址...") {
|
||||
if (pathHelper.isSharePage(this.props.location.pathname) && this.props.share && this.props.share.score > 0){
|
||||
if (
|
||||
pathHelper.isSharePage(this.props.location.pathname) &&
|
||||
this.props.share &&
|
||||
this.props.share.score > 0
|
||||
) {
|
||||
this.scoreHandler(this.Download);
|
||||
return
|
||||
return;
|
||||
}
|
||||
this.Download();
|
||||
this.Download();
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
|
@ -165,9 +173,9 @@ class ModalsCompoment extends Component {
|
|||
}
|
||||
};
|
||||
|
||||
scoreHandler = callback =>{
|
||||
callback();
|
||||
}
|
||||
scoreHandler = callback => {
|
||||
callback();
|
||||
};
|
||||
|
||||
Download = () => {
|
||||
let reqURL = "";
|
||||
|
|
@ -176,8 +184,8 @@ class ModalsCompoment extends Component {
|
|||
this.props.selected[0].path === "/"
|
||||
? this.props.selected[0].path + this.props.selected[0].name
|
||||
: this.props.selected[0].path +
|
||||
"/" +
|
||||
this.props.selected[0].name;
|
||||
"/" +
|
||||
this.props.selected[0].name;
|
||||
reqURL =
|
||||
"/share/download/" +
|
||||
this.props.selected[0].key +
|
||||
|
|
@ -213,7 +221,7 @@ class ModalsCompoment extends Component {
|
|||
} else {
|
||||
items.push(value.id);
|
||||
}
|
||||
return null
|
||||
return null;
|
||||
});
|
||||
|
||||
let reqURL = "/file/archive";
|
||||
|
|
@ -221,13 +229,9 @@ class ModalsCompoment extends Component {
|
|||
items: items,
|
||||
dirs: dirs
|
||||
};
|
||||
if (pathHelper.isSharePage(
|
||||
this.props.location.pathname
|
||||
)) {
|
||||
reqURL =
|
||||
"/share/archive/" +
|
||||
window.shareInfo.key;
|
||||
postBody["path"] = this.props.selected[0].path
|
||||
if (pathHelper.isSharePage(this.props.location.pathname)) {
|
||||
reqURL = "/share/archive/" + window.shareInfo.key;
|
||||
postBody["path"] = this.props.selected[0].path;
|
||||
}
|
||||
|
||||
API.post(reqURL, postBody)
|
||||
|
|
@ -279,7 +283,7 @@ class ModalsCompoment extends Component {
|
|||
.then(response => {
|
||||
if (response.rawData.code === 0) {
|
||||
this.onClose();
|
||||
setTimeout(this.props.refreshFileList,500);
|
||||
setTimeout(this.props.refreshFileList, 500);
|
||||
} else {
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
|
|
@ -401,10 +405,10 @@ class ModalsCompoment extends Component {
|
|||
|
||||
// 检查重名
|
||||
if (
|
||||
this.props.dirList.findIndex((value) => {
|
||||
this.props.dirList.findIndex(value => {
|
||||
return value.name === newName;
|
||||
}) !== -1 ||
|
||||
this.props.fileList.findIndex((value) => {
|
||||
this.props.fileList.findIndex(value => {
|
||||
return value.name === newName;
|
||||
}) !== -1
|
||||
) {
|
||||
|
|
@ -442,7 +446,7 @@ class ModalsCompoment extends Component {
|
|||
e.preventDefault();
|
||||
this.props.setModalsLoading(true);
|
||||
if (
|
||||
this.props.dirList.findIndex((value) => {
|
||||
this.props.dirList.findIndex(value => {
|
||||
return value.name === this.state.newFolderName;
|
||||
}) !== -1
|
||||
) {
|
||||
|
|
@ -483,7 +487,7 @@ class ModalsCompoment extends Component {
|
|||
e.preventDefault();
|
||||
this.props.setModalsLoading(true);
|
||||
if (
|
||||
this.props.dirList.findIndex((value) => {
|
||||
this.props.dirList.findIndex(value => {
|
||||
return value.name === this.state.newFileName;
|
||||
}) !== -1
|
||||
) {
|
||||
|
|
@ -523,18 +527,18 @@ class ModalsCompoment extends Component {
|
|||
submitTorrentDownload = e => {
|
||||
e.preventDefault();
|
||||
this.props.setModalsLoading(true);
|
||||
API
|
||||
.post("/aria2/torrent/" + this.props.selected[0].id, {
|
||||
dst: this.state.selectedPath === "//" ? "/" : this.state.selectedPath
|
||||
})
|
||||
API.post("/aria2/torrent/" + this.props.selected[0].id, {
|
||||
dst:
|
||||
this.state.selectedPath === "//" ? "/" : this.state.selectedPath
|
||||
})
|
||||
.then(() => {
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"任务已创建",
|
||||
"success"
|
||||
);
|
||||
this.onClose();
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"任务已创建",
|
||||
"success"
|
||||
);
|
||||
this.onClose();
|
||||
this.props.setModalsLoading(false);
|
||||
})
|
||||
.catch(error => {
|
||||
|
|
@ -551,19 +555,19 @@ class ModalsCompoment extends Component {
|
|||
submitDownload = e => {
|
||||
e.preventDefault();
|
||||
this.props.setModalsLoading(true);
|
||||
API
|
||||
.post("/aria2/url", {
|
||||
url: this.state.downloadURL,
|
||||
dst: this.state.selectedPath === "//" ? "/" : this.state.selectedPath
|
||||
})
|
||||
API.post("/aria2/url", {
|
||||
url: this.state.downloadURL,
|
||||
dst:
|
||||
this.state.selectedPath === "//" ? "/" : this.state.selectedPath
|
||||
})
|
||||
.then(() => {
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"任务已创建",
|
||||
"success"
|
||||
);
|
||||
this.onClose();
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"任务已创建",
|
||||
"success"
|
||||
);
|
||||
this.onClose();
|
||||
this.props.setModalsLoading(false);
|
||||
})
|
||||
.catch(error => {
|
||||
|
|
@ -607,7 +611,7 @@ class ModalsCompoment extends Component {
|
|||
downloadURL: "",
|
||||
shareUrl: "",
|
||||
remoteDownloadPathSelect: false,
|
||||
source: "",
|
||||
source: ""
|
||||
});
|
||||
this.newNameSuffix = "";
|
||||
this.props.closeAllModals();
|
||||
|
|
@ -930,7 +934,7 @@ class ModalsCompoment extends Component {
|
|||
: "")
|
||||
: baseURL +
|
||||
"/file/preview/" +
|
||||
this.props.selected[0].id
|
||||
this.props.selected[0].id
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,41 +1,37 @@
|
|||
import React from "react";
|
||||
import DropDownItem from "./DropDownItem";
|
||||
|
||||
|
||||
export default function DropDown(props) {
|
||||
|
||||
let timer;
|
||||
let first = props.folders.length;
|
||||
const status = [];
|
||||
for (let index = 0; index < props.folders.length; index++) {
|
||||
status[index] = false;
|
||||
|
||||
}
|
||||
|
||||
const setActiveStatus = (id,value)=>{
|
||||
const setActiveStatus = (id, value) => {
|
||||
status[id] = value;
|
||||
if (value){
|
||||
if (value) {
|
||||
clearTimeout(timer);
|
||||
}else{
|
||||
} else {
|
||||
let shouldClose = true;
|
||||
status.forEach(element => {
|
||||
if (element){
|
||||
if (element) {
|
||||
shouldClose = false;
|
||||
}
|
||||
});
|
||||
if (shouldClose){
|
||||
if (first<=0){
|
||||
timer = setTimeout(()=>{
|
||||
if (shouldClose) {
|
||||
if (first <= 0) {
|
||||
timer = setTimeout(() => {
|
||||
props.onClose();
|
||||
},100)
|
||||
}else{
|
||||
}, 100);
|
||||
} else {
|
||||
first--;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
console.log(status);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -45,7 +41,7 @@ export default function DropDown(props) {
|
|||
path={"/" + props.folders.slice(0, id).join("/")}
|
||||
navigateTo={props.navigateTo}
|
||||
id={id}
|
||||
setActiveStatus = {setActiveStatus}
|
||||
setActiveStatus={setActiveStatus}
|
||||
folder={folder}
|
||||
/>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,7 @@
|
|||
import React, { useEffect } from "react";
|
||||
import { makeStyles } from "@material-ui/core";
|
||||
import FolderIcon from "@material-ui/icons/Folder";
|
||||
import {
|
||||
MenuItem,
|
||||
ListItemIcon,
|
||||
ListItemText
|
||||
} from "@material-ui/core";
|
||||
import { MenuItem, ListItemIcon, ListItemText } from "@material-ui/core";
|
||||
import { useDrop } from "react-dnd";
|
||||
import classNames from "classnames";
|
||||
|
||||
|
|
@ -36,9 +32,9 @@ export default function DropDownItem(props) {
|
|||
const isActive = canDrop && isOver;
|
||||
|
||||
useEffect(() => {
|
||||
props.setActiveStatus(props.id,isActive);
|
||||
props.setActiveStatus(props.id, isActive);
|
||||
// eslint-disable-next-line
|
||||
}, [isActive])
|
||||
}, [isActive]);
|
||||
|
||||
const classes = useStyles();
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -21,9 +21,11 @@ import {
|
|||
openCreateFolderDialog,
|
||||
openShareDialog,
|
||||
drawerToggleAction,
|
||||
setShareUserPopover, openResaveDialog, openCompressDialog
|
||||
setShareUserPopover,
|
||||
openResaveDialog,
|
||||
openCompressDialog
|
||||
} from "../../../actions/index";
|
||||
import explorer from "../../../redux/explorer"
|
||||
import explorer from "../../../redux/explorer";
|
||||
import API from "../../../middleware/Api";
|
||||
import { setCookie, setGetParameter, fixUrlHash } from "../../../utils/index";
|
||||
import {
|
||||
|
|
@ -40,11 +42,10 @@ import pathHelper from "../../../utils/page";
|
|||
import classNames from "classnames";
|
||||
import Auth from "../../../middleware/Auth";
|
||||
import Avatar from "@material-ui/core/Avatar";
|
||||
import {Archive} from "@material-ui/icons";
|
||||
import { Archive } from "@material-ui/icons";
|
||||
import { FilePlus } from "mdi-material-ui";
|
||||
import { openCreateFileDialog } from "../../../actions";
|
||||
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
path: state.navigator.path,
|
||||
|
|
@ -100,12 +101,12 @@ const mapDispatchToProps = dispatch => {
|
|||
setShareUserPopover: e => {
|
||||
dispatch(setShareUserPopover(e));
|
||||
},
|
||||
openResave: (key) => {
|
||||
openResave: key => {
|
||||
dispatch(openResaveDialog(key));
|
||||
},
|
||||
openCompressDialog: ()=>{
|
||||
dispatch(openCompressDialog())
|
||||
},
|
||||
openCompressDialog: () => {
|
||||
dispatch(openCompressDialog());
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -182,7 +183,7 @@ class NavigatorComponent extends Component {
|
|||
componentDidMount = () => {
|
||||
const url = new URL(fixUrlHash(window.location.href));
|
||||
const c = url.searchParams.get("path");
|
||||
this.renderPath(c === null ? "/":c);
|
||||
this.renderPath(c === null ? "/" : c);
|
||||
|
||||
if (!this.props.isShare) {
|
||||
// 如果是在个人文件管理页,首次加载时打开侧边栏
|
||||
|
|
@ -330,7 +331,7 @@ class NavigatorComponent extends Component {
|
|||
const presentPath = this.props.path.split("/");
|
||||
const newTarget = [
|
||||
{
|
||||
id:this.currentID,
|
||||
id: this.currentID,
|
||||
type: "dir",
|
||||
name: presentPath.pop(),
|
||||
path: presentPath.length === 1 ? "/" : presentPath.join("/")
|
||||
|
|
@ -384,7 +385,7 @@ class NavigatorComponent extends Component {
|
|||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
const isHomePage = pathHelper.isHomePage(this.props.location.pathname);
|
||||
const isHomePage = pathHelper.isHomePage(this.props.location.pathname);
|
||||
const user = Auth.GetUser();
|
||||
|
||||
const presentFolderMenu = (
|
||||
|
|
@ -401,45 +402,42 @@ class NavigatorComponent extends Component {
|
|||
</ListItemIcon>
|
||||
刷新
|
||||
</MenuItem>
|
||||
{this.props.keywords === "" &&
|
||||
isHomePage && (
|
||||
<div>
|
||||
<Divider />
|
||||
{this.props.keywords === "" && isHomePage && (
|
||||
<div>
|
||||
<Divider />
|
||||
<MenuItem onClick={() => this.performAction("share")}>
|
||||
<ListItemIcon>
|
||||
<ShareIcon />
|
||||
</ListItemIcon>
|
||||
分享
|
||||
</MenuItem>
|
||||
{user.group.compress && (
|
||||
<MenuItem
|
||||
onClick={() => this.performAction("share")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<ShareIcon />
|
||||
</ListItemIcon>
|
||||
分享
|
||||
</MenuItem>
|
||||
{user.group.compress && <MenuItem
|
||||
onClick={() => this.performAction("compress")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<Archive />
|
||||
</ListItemIcon>
|
||||
压缩
|
||||
</MenuItem>}
|
||||
<Divider />
|
||||
<MenuItem
|
||||
onClick={() => this.performAction("newfolder")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<NewFolderIcon />
|
||||
</ListItemIcon>
|
||||
创建文件夹
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={() => this.performAction("newFile")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<FilePlus />
|
||||
</ListItemIcon>
|
||||
创建文件
|
||||
</MenuItem>
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
<Divider />
|
||||
<MenuItem
|
||||
onClick={() => this.performAction("newfolder")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<NewFolderIcon />
|
||||
</ListItemIcon>
|
||||
创建文件夹
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => this.performAction("newFile")}>
|
||||
<ListItemIcon>
|
||||
<FilePlus />
|
||||
</ListItemIcon>
|
||||
创建文件
|
||||
</MenuItem>
|
||||
</div>
|
||||
)}
|
||||
</Menu>
|
||||
);
|
||||
|
||||
|
|
@ -614,7 +612,11 @@ class NavigatorComponent extends Component {
|
|||
>
|
||||
<Avatar
|
||||
style={{ height: 23, width: 23 }}
|
||||
src={"/api/v3/user/avatar/"+this.props.share.creator.key + "/s"}
|
||||
src={
|
||||
"/api/v3/user/avatar/" +
|
||||
this.props.share.creator.key +
|
||||
"/s"
|
||||
}
|
||||
/>
|
||||
</IconButton>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React,{useEffect} from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import ExpandMore from "@material-ui/icons/ExpandMore";
|
||||
import { Button } from "@material-ui/core";
|
||||
import { makeStyles } from "@material-ui/core";
|
||||
|
|
@ -13,14 +13,14 @@ const useStyles = makeStyles(theme => ({
|
|||
active: {
|
||||
border: "2px solid " + theme.palette.primary.light
|
||||
},
|
||||
button:{
|
||||
textTransform: "none",
|
||||
button: {
|
||||
textTransform: "none"
|
||||
}
|
||||
}));
|
||||
|
||||
export default function PathButton(props) {
|
||||
const inputRef = React.useRef(null)
|
||||
|
||||
const inputRef = React.useRef(null);
|
||||
|
||||
const [{ canDrop, isOver }, drop] = useDrop({
|
||||
accept: "object",
|
||||
drop: () => {
|
||||
|
|
@ -45,35 +45,36 @@ export default function PathButton(props) {
|
|||
const isActive = canDrop && isOver;
|
||||
|
||||
useEffect(() => {
|
||||
if(props.more && isActive){
|
||||
if (props.more && isActive) {
|
||||
inputRef.current.click();
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
}, [isActive])
|
||||
}, [isActive]);
|
||||
|
||||
const classes = useStyles();
|
||||
return (
|
||||
|
||||
<span onClick={props.onClick} ref={inputRef} >
|
||||
<Button
|
||||
ref={drop}
|
||||
className={classNames({
|
||||
[classes.active]: isActive
|
||||
},classes.button)}
|
||||
component="span"
|
||||
title={props.title}
|
||||
>
|
||||
{props.more && <MoreIcon />}
|
||||
{!props.more && (
|
||||
<>
|
||||
{props.folder}
|
||||
{props.last && (
|
||||
<ExpandMore className={classes.expandMore} />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
<span onClick={props.onClick} ref={inputRef}>
|
||||
<Button
|
||||
ref={drop}
|
||||
className={classNames(
|
||||
{
|
||||
[classes.active]: isActive
|
||||
},
|
||||
classes.button
|
||||
)}
|
||||
component="span"
|
||||
title={props.title}
|
||||
>
|
||||
{props.more && <MoreIcon />}
|
||||
{!props.more && (
|
||||
<>
|
||||
{props.folder}
|
||||
{props.last && (
|
||||
<ExpandMore className={classes.expandMore} />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</span>
|
||||
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,12 +99,12 @@ export default function ObjectIcon(props) {
|
|||
};
|
||||
|
||||
const selectFile = e => {
|
||||
dispatch(selectFileAction(props.file, e, props.index))
|
||||
dispatch(selectFileAction(props.file, e, props.index));
|
||||
};
|
||||
const enterFolder = () => {
|
||||
NavitateTo(
|
||||
path === "/" ? path + props.file.name : path + "/" + props.file.name
|
||||
);
|
||||
NavitateTo(
|
||||
path === "/" ? path + props.file.name : path + "/" + props.file.name
|
||||
);
|
||||
};
|
||||
const handleClick = e => {
|
||||
if (props.file.type === "up") {
|
||||
|
|
@ -156,18 +156,18 @@ export default function ObjectIcon(props) {
|
|||
if (isShare) {
|
||||
history.push(
|
||||
selected[0].key +
|
||||
"/doc?name=" +
|
||||
encodeURIComponent(selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
"/doc?name=" +
|
||||
encodeURIComponent(selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
);
|
||||
return;
|
||||
}
|
||||
history.push(
|
||||
"/doc?p=" +
|
||||
encodeURIComponent(previewPath) +
|
||||
"&id=" +
|
||||
selected[0].id
|
||||
encodeURIComponent(previewPath) +
|
||||
"&id=" +
|
||||
selected[0].id
|
||||
);
|
||||
return;
|
||||
case "audio":
|
||||
|
|
@ -177,58 +177,73 @@ export default function ObjectIcon(props) {
|
|||
if (isShare) {
|
||||
history.push(
|
||||
selected[0].key +
|
||||
"/video?name=" +
|
||||
encodeURIComponent(selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
"/video?name=" +
|
||||
encodeURIComponent(selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
);
|
||||
return;
|
||||
}
|
||||
history.push(
|
||||
"/video?p=" +
|
||||
encodeURIComponent(previewPath) +
|
||||
"&id=" +
|
||||
selected[0].id
|
||||
encodeURIComponent(previewPath) +
|
||||
"&id=" +
|
||||
selected[0].id
|
||||
);
|
||||
return;
|
||||
case "edit":
|
||||
if (isShare) {
|
||||
history.push(
|
||||
selected[0].key +
|
||||
"/text?name=" +
|
||||
encodeURIComponent(selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
"/text?name=" +
|
||||
encodeURIComponent(selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
);
|
||||
return;
|
||||
}
|
||||
history.push("/text?p=" + encodeURIComponent(previewPath) + "&id=" + selected[0].id);
|
||||
history.push(
|
||||
"/text?p=" +
|
||||
encodeURIComponent(previewPath) +
|
||||
"&id=" +
|
||||
selected[0].id
|
||||
);
|
||||
return;
|
||||
case "pdf":
|
||||
if (isShare) {
|
||||
history.push(
|
||||
selected[0].key +
|
||||
"/pdf?name=" +
|
||||
encodeURIComponent(selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
"/pdf?name=" +
|
||||
encodeURIComponent(selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
);
|
||||
return;
|
||||
}
|
||||
history.push("/pdf?p=" + encodeURIComponent(previewPath) + "&id=" + selected[0].id);
|
||||
history.push(
|
||||
"/pdf?p=" +
|
||||
encodeURIComponent(previewPath) +
|
||||
"&id=" +
|
||||
selected[0].id
|
||||
);
|
||||
return;
|
||||
case "code":
|
||||
if (isShare) {
|
||||
history.push(
|
||||
selected[0].key +
|
||||
"/code?name=" +
|
||||
encodeURIComponent(selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
"/code?name=" +
|
||||
encodeURIComponent(selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
);
|
||||
return;
|
||||
}
|
||||
history.push("/code?p=" + encodeURIComponent(previewPath) + "&id=" + selected[0].id);
|
||||
history.push(
|
||||
"/code?p=" +
|
||||
encodeURIComponent(previewPath) +
|
||||
"&id=" +
|
||||
selected[0].id
|
||||
);
|
||||
return;
|
||||
default:
|
||||
OpenLoadingDialog("获取下载地址...");
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types';
|
||||
import FolderIcon from '@material-ui/icons/Folder'
|
||||
import RightIcon from "@material-ui/icons/KeyboardArrowRight"
|
||||
import UpIcon from "@material-ui/icons/ArrowUpward"
|
||||
import { connect } from 'react-redux'
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
toggleSnackbar,
|
||||
} from "../../actions/index"
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import FolderIcon from "@material-ui/icons/Folder";
|
||||
import RightIcon from "@material-ui/icons/KeyboardArrowRight";
|
||||
import UpIcon from "@material-ui/icons/ArrowUpward";
|
||||
import { connect } from "react-redux";
|
||||
import classNames from "classnames";
|
||||
import { toggleSnackbar } from "../../actions/index";
|
||||
|
||||
import {
|
||||
MenuList,
|
||||
|
|
@ -16,130 +14,162 @@ import {
|
|||
ListItemIcon,
|
||||
ListItemText,
|
||||
withStyles,
|
||||
ListItemSecondaryAction,
|
||||
} from '@material-ui/core';
|
||||
import API from '../../middleware/Api'
|
||||
ListItemSecondaryAction
|
||||
} from "@material-ui/core";
|
||||
import API from "../../middleware/Api";
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
keywords: state.explorer.keywords,
|
||||
}
|
||||
}
|
||||
keywords: state.explorer.keywords
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
toggleSnackbar:(vertical,horizontal,msg,color)=>{
|
||||
dispatch(toggleSnackbar(vertical,horizontal,msg,color))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
toggleSnackbar: (vertical, horizontal, msg, color) => {
|
||||
dispatch(toggleSnackbar(vertical, horizontal, msg, color));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const styles = theme => ({
|
||||
iconWhite:{
|
||||
color: theme.palette.common.white,
|
||||
iconWhite: {
|
||||
color: theme.palette.common.white
|
||||
},
|
||||
selected: {
|
||||
backgroundColor: theme.palette.primary.main+"!important",
|
||||
'& $primary, & $icon': {
|
||||
color: theme.palette.common.white,
|
||||
},
|
||||
},
|
||||
backgroundColor: theme.palette.primary.main + "!important",
|
||||
"& $primary, & $icon": {
|
||||
color: theme.palette.common.white
|
||||
}
|
||||
},
|
||||
primary: {},
|
||||
icon: {},
|
||||
buttonIcon:{},
|
||||
selector:{
|
||||
minWidth: "300px",
|
||||
buttonIcon: {},
|
||||
selector: {
|
||||
minWidth: "300px"
|
||||
},
|
||||
container:{
|
||||
container: {
|
||||
maxHeight: "330px",
|
||||
overflowY:" auto",
|
||||
overflowY: " auto"
|
||||
}
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
class PathSelectorCompoment extends Component {
|
||||
|
||||
state = {
|
||||
presentPath:"/",
|
||||
dirList:[],
|
||||
selectedTarget:null,
|
||||
}
|
||||
presentPath: "/",
|
||||
dirList: [],
|
||||
selectedTarget: null
|
||||
};
|
||||
|
||||
componentDidMount= ()=>{
|
||||
componentDidMount = () => {
|
||||
const toBeLoad = this.props.presentPath;
|
||||
this.enterFolder(this.props.keywords === "" ? toBeLoad : "/");
|
||||
}
|
||||
};
|
||||
|
||||
back = ()=>{
|
||||
back = () => {
|
||||
const paths = this.state.presentPath.split("/");
|
||||
paths.pop();
|
||||
const toBeLoad = paths.join("/");
|
||||
this.enterFolder(toBeLoad===""?"/":toBeLoad);
|
||||
}
|
||||
this.enterFolder(toBeLoad === "" ? "/" : toBeLoad);
|
||||
};
|
||||
|
||||
enterFolder = (toBeLoad)=>{
|
||||
API.get((this.props.api ? this.props.api : '/directory')+encodeURIComponent(toBeLoad),)
|
||||
.then( (response)=> {
|
||||
const dirList = response.data.objects.filter( (x)=> {
|
||||
return (x.type === "dir" && (this.props.selected.findIndex((value)=>{
|
||||
return (value.name === x.name )&&(value.path === x.path);
|
||||
}))===-1);
|
||||
});
|
||||
if(toBeLoad ==="/"){
|
||||
dirList.unshift({name:"/",path:""})
|
||||
}
|
||||
this.setState({
|
||||
presentPath:toBeLoad,
|
||||
dirList:dirList,
|
||||
selectedTarget:null,
|
||||
enterFolder = toBeLoad => {
|
||||
API.get(
|
||||
(this.props.api ? this.props.api : "/directory") +
|
||||
encodeURIComponent(toBeLoad)
|
||||
)
|
||||
.then(response => {
|
||||
const dirList = response.data.objects.filter(x => {
|
||||
return (
|
||||
x.type === "dir" &&
|
||||
this.props.selected.findIndex(value => {
|
||||
return (
|
||||
value.name === x.name && value.path === x.path
|
||||
);
|
||||
}) === -1
|
||||
);
|
||||
});
|
||||
if (toBeLoad === "/") {
|
||||
dirList.unshift({ name: "/", path: "" });
|
||||
}
|
||||
this.setState({
|
||||
presentPath: toBeLoad,
|
||||
dirList: dirList,
|
||||
selectedTarget: null
|
||||
});
|
||||
})
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right",error.message,"warning");
|
||||
});
|
||||
}
|
||||
.catch(error => {
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
error.message,
|
||||
"warning"
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
handleSelect = (index) =>{
|
||||
this.setState({selectedTarget:index});
|
||||
handleSelect = index => {
|
||||
this.setState({ selectedTarget: index });
|
||||
this.props.onSelect(this.state.dirList[index]);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
|
||||
const { classes} = this.props;
|
||||
const { classes } = this.props;
|
||||
|
||||
return (
|
||||
<div className={classes.container}>
|
||||
<MenuList className={classes.selector}>
|
||||
{this.state.presentPath!=="/"&&
|
||||
<MenuItem onClick={this.back}>
|
||||
<ListItemIcon >
|
||||
<UpIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="返回上一层" />
|
||||
</MenuItem>
|
||||
}
|
||||
{this.state.dirList.map((value,index)=>(
|
||||
<MenuItem classes={{
|
||||
selected:classes.selected
|
||||
}} key={index} selected={this.state.selectedTarget === index} onClick={()=>this.handleSelect(index)}>
|
||||
<ListItemIcon className={classes.icon}>
|
||||
<FolderIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText classes={{ primary: classes.primary }} primary={value.name} />
|
||||
{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>}
|
||||
</MenuItem>
|
||||
))}
|
||||
|
||||
</MenuList>
|
||||
|
||||
<MenuList className={classes.selector}>
|
||||
{this.state.presentPath !== "/" && (
|
||||
<MenuItem onClick={this.back}>
|
||||
<ListItemIcon>
|
||||
<UpIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="返回上一层" />
|
||||
</MenuItem>
|
||||
)}
|
||||
{this.state.dirList.map((value, index) => (
|
||||
<MenuItem
|
||||
classes={{
|
||||
selected: classes.selected
|
||||
}}
|
||||
key={index}
|
||||
selected={this.state.selectedTarget === index}
|
||||
onClick={() => this.handleSelect(index)}
|
||||
>
|
||||
<ListItemIcon className={classes.icon}>
|
||||
<FolderIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
classes={{ primary: classes.primary }}
|
||||
primary={value.name}
|
||||
/>
|
||||
{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>
|
||||
)}
|
||||
</MenuItem>
|
||||
))}
|
||||
</MenuList>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -147,12 +177,11 @@ class PathSelectorCompoment extends Component {
|
|||
|
||||
PathSelectorCompoment.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
presentPath:PropTypes.string.isRequired,
|
||||
selected:PropTypes.array.isRequired,
|
||||
presentPath: PropTypes.string.isRequired,
|
||||
selected: PropTypes.array.isRequired
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
|
||||
)(withStyles(styles)(PathSelectorCompoment))
|
||||
)(withStyles(styles)(PathSelectorCompoment));
|
||||
|
|
|
|||
|
|
@ -1,43 +1,44 @@
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux'
|
||||
import classNames from 'classnames';
|
||||
import { withStyles, ButtonBase, Typography, Tooltip } from '@material-ui/core';
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { connect } from "react-redux";
|
||||
import classNames from "classnames";
|
||||
import { withStyles, ButtonBase, Typography, Tooltip } from "@material-ui/core";
|
||||
import TypeIcon from "./TypeIcon";
|
||||
import {lighten} from "@material-ui/core/styles";
|
||||
import { lighten } from "@material-ui/core/styles";
|
||||
|
||||
const styles = theme => ({
|
||||
container: {
|
||||
padding: "7px",
|
||||
padding: "7px"
|
||||
},
|
||||
|
||||
selected: {
|
||||
"&:hover": {
|
||||
border: "1px solid #d0d0d0",
|
||||
border: "1px solid #d0d0d0"
|
||||
},
|
||||
backgroundColor:
|
||||
theme.palette.type === "dark"
|
||||
? "#fff"
|
||||
: lighten(theme.palette.primary.main,0.8),
|
||||
: lighten(theme.palette.primary.main, 0.8)
|
||||
},
|
||||
notSelected: {
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.background.default,
|
||||
border: "1px solid #d0d0d0",
|
||||
border: "1px solid #d0d0d0"
|
||||
},
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
backgroundColor: theme.palette.background.paper
|
||||
},
|
||||
|
||||
button: {
|
||||
height: "50px",
|
||||
border: "1px solid "+theme.palette.divider,
|
||||
border: "1px solid " + theme.palette.divider,
|
||||
width: "100%",
|
||||
borderRadius: "6px",
|
||||
boxSizing: "border-box",
|
||||
transition: "background-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,border 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms",
|
||||
transition:
|
||||
"background-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,border 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms",
|
||||
display: "flex",
|
||||
justifyContent: "left",
|
||||
alignItems: "initial",
|
||||
alignItems: "initial"
|
||||
},
|
||||
icon: {
|
||||
margin: "10px 10px 10px 16px",
|
||||
|
|
@ -46,83 +47,94 @@ const styles = theme => ({
|
|||
backgroundColor: theme.palette.background.paper,
|
||||
borderRadius: "90%",
|
||||
paddingTop: "2px",
|
||||
color: theme.palette.text.secondary,
|
||||
color: theme.palette.text.secondary
|
||||
},
|
||||
folderNameSelected: {
|
||||
color: theme.palette.type === "dark" ? theme.palette.background.paper : theme.palette.primary.dark,
|
||||
fontWeight: "500",
|
||||
color:
|
||||
theme.palette.type === "dark"
|
||||
? theme.palette.background.paper
|
||||
: theme.palette.primary.dark,
|
||||
fontWeight: "500"
|
||||
},
|
||||
folderNameNotSelected: {
|
||||
color: theme.palette.text.secondary,
|
||||
color: theme.palette.text.secondary
|
||||
},
|
||||
folderName: {
|
||||
marginTop: "15px",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
marginRight: "20px",
|
||||
},
|
||||
})
|
||||
marginRight: "20px"
|
||||
}
|
||||
});
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
selected: state.explorer.selected,
|
||||
}
|
||||
}
|
||||
selected: state.explorer.selected
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = () => {
|
||||
return {
|
||||
}
|
||||
}
|
||||
return {};
|
||||
};
|
||||
|
||||
class SmallIconCompoment extends Component {
|
||||
|
||||
state = {
|
||||
}
|
||||
|
||||
state = {};
|
||||
|
||||
render() {
|
||||
|
||||
const { classes } = this.props;
|
||||
|
||||
const isSelected = (this.props.selected.findIndex((value) => {
|
||||
return value === this.props.file;
|
||||
})) !== -1;
|
||||
const isSelected =
|
||||
this.props.selected.findIndex(value => {
|
||||
return value === this.props.file;
|
||||
}) !== -1;
|
||||
|
||||
return (
|
||||
<ButtonBase
|
||||
focusRipple
|
||||
className={classNames({
|
||||
<ButtonBase
|
||||
focusRipple
|
||||
className={classNames(
|
||||
{
|
||||
[classes.selected]: isSelected,
|
||||
[classes.notSelected]: !isSelected,
|
||||
}, classes.button)}
|
||||
>
|
||||
<div className={classNames(classes.icon, {
|
||||
[classes.notSelected]: !isSelected
|
||||
},
|
||||
classes.button
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={classNames(classes.icon, {
|
||||
[classes.iconSelected]: isSelected,
|
||||
[classes.iconNotSelected]: !isSelected,
|
||||
})}><TypeIcon fileName={this.props.file.name}/></div>
|
||||
<Tooltip title={this.props.file.name} aria-label={this.props.file.name}>
|
||||
<Typography className={classNames(classes.folderName, {
|
||||
[classes.iconNotSelected]: !isSelected
|
||||
})}
|
||||
>
|
||||
<TypeIcon fileName={this.props.file.name} />
|
||||
</div>
|
||||
<Tooltip
|
||||
title={this.props.file.name}
|
||||
aria-label={this.props.file.name}
|
||||
>
|
||||
<Typography
|
||||
className={classNames(classes.folderName, {
|
||||
[classes.folderNameSelected]: isSelected,
|
||||
[classes.folderNameNotSelected]: !isSelected,
|
||||
[classes.folderNameNotSelected]: !isSelected
|
||||
})}
|
||||
variant="body2"
|
||||
>{this.props.file.name}</Typography>
|
||||
</Tooltip>
|
||||
</ButtonBase>
|
||||
>
|
||||
{this.props.file.name}
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
</ButtonBase>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SmallIconCompoment.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
file: PropTypes.object.isRequired,
|
||||
file: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
|
||||
const SmallIcon = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(SmallIconCompoment))
|
||||
)(withStyles(styles)(SmallIconCompoment));
|
||||
|
||||
export default SmallIcon
|
||||
export default SmallIcon;
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ import classNames from "classnames";
|
|||
import { sizeToString } from "../../utils/index";
|
||||
import { withStyles, TableCell, TableRow, Typography } from "@material-ui/core";
|
||||
import TypeIcon from "./TypeIcon";
|
||||
import {lighten} from "@material-ui/core/styles";
|
||||
import { lighten } from "@material-ui/core/styles";
|
||||
import pathHelper from "../../utils/page";
|
||||
import {withRouter} from "react-router";
|
||||
import KeyboardReturnIcon from '@material-ui/icons/KeyboardReturn';
|
||||
import { withRouter } from "react-router";
|
||||
import KeyboardReturnIcon from "@material-ui/icons/KeyboardReturn";
|
||||
|
||||
const styles = theme => ({
|
||||
selected: {
|
||||
|
|
@ -18,20 +18,20 @@ const styles = theme => ({
|
|||
backgroundColor:
|
||||
theme.palette.type === "dark"
|
||||
? theme.palette.background.paper
|
||||
: lighten(theme.palette.primary.main,0.8),
|
||||
: lighten(theme.palette.primary.main, 0.8)
|
||||
},
|
||||
|
||||
selectedShared: {
|
||||
"&:hover": {},
|
||||
backgroundColor:
|
||||
theme.palette.type === "dark"
|
||||
? lighten(theme.palette.background.paper,0.15)
|
||||
: lighten(theme.palette.primary.main,0.8),
|
||||
? lighten(theme.palette.background.paper, 0.15)
|
||||
: lighten(theme.palette.primary.main, 0.8)
|
||||
},
|
||||
|
||||
notSelected: {
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.background.default,
|
||||
backgroundColor: theme.palette.background.default
|
||||
}
|
||||
},
|
||||
icon: {
|
||||
|
|
@ -39,12 +39,13 @@ const styles = theme => ({
|
|||
marginRight: "20px",
|
||||
color: theme.palette.text.secondary
|
||||
},
|
||||
tableIcon:{
|
||||
tableIcon: {
|
||||
marginRight: "20px",
|
||||
verticalAlign: "middle",
|
||||
verticalAlign: "middle"
|
||||
},
|
||||
folderNameSelected: {
|
||||
color: theme.palette.type === "dark" ? "#fff" : theme.palette.primary.dark,
|
||||
color:
|
||||
theme.palette.type === "dark" ? "#fff" : theme.palette.primary.dark,
|
||||
fontWeight: "500",
|
||||
userSelect: "none"
|
||||
},
|
||||
|
|
@ -54,7 +55,7 @@ const styles = theme => ({
|
|||
},
|
||||
folderName: {
|
||||
marginRight: "20px",
|
||||
display: "flex",
|
||||
display: "flex"
|
||||
},
|
||||
hideAuto: {
|
||||
[theme.breakpoints.down("sm")]: {
|
||||
|
|
@ -86,10 +87,15 @@ class TableRowCompoment extends Component {
|
|||
let icon;
|
||||
if (this.props.file.type === "dir") {
|
||||
icon = <FolderIcon className={classes.icon} />;
|
||||
}else if (this.props.file.type === "up"){
|
||||
icon = <KeyboardReturnIcon className={classes.icon}/>
|
||||
} else if (this.props.file.type === "up") {
|
||||
icon = <KeyboardReturnIcon className={classes.icon} />;
|
||||
} else {
|
||||
icon = <TypeIcon className={classes.tableIcon} fileName={this.props.file.name}/>
|
||||
icon = (
|
||||
<TypeIcon
|
||||
className={classes.tableIcon}
|
||||
fileName={this.props.file.name}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const isSelected =
|
||||
|
|
@ -102,15 +108,17 @@ class TableRowCompoment extends Component {
|
|||
onContextMenu={this.props.contextMenu}
|
||||
onClick={this.props.handleClick}
|
||||
onDoubleClick={this.props.handleDoubleClick.bind(this)}
|
||||
className={classNames(
|
||||
{
|
||||
[classes.selected]: isSelected&&!isShare,
|
||||
[classes.selectedShared]: isSelected&&isShare,
|
||||
[classes.notSelected]: !isSelected
|
||||
}
|
||||
)}
|
||||
className={classNames({
|
||||
[classes.selected]: isSelected && !isShare,
|
||||
[classes.selectedShared]: isSelected && isShare,
|
||||
[classes.notSelected]: !isSelected
|
||||
})}
|
||||
>
|
||||
<TableCell component="th" scope="row" className={classes.tableRow}>
|
||||
<TableCell
|
||||
component="th"
|
||||
scope="row"
|
||||
className={classes.tableRow}
|
||||
>
|
||||
<Typography
|
||||
variant="body2"
|
||||
className={classNames(classes.folderName, {
|
||||
|
|
@ -122,7 +130,9 @@ class TableRowCompoment extends Component {
|
|||
{this.props.file.name}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell className={classNames(classes.hideAuto,classes.tableRow)}>
|
||||
<TableCell
|
||||
className={classNames(classes.hideAuto, classes.tableRow)}
|
||||
>
|
||||
<Typography
|
||||
variant="body2"
|
||||
className={classNames(classes.folderName, {
|
||||
|
|
@ -131,11 +141,14 @@ class TableRowCompoment extends Component {
|
|||
})}
|
||||
>
|
||||
{" "}
|
||||
{this.props.file.type !== "dir" &&this.props.file.type !== "up"&&
|
||||
{this.props.file.type !== "dir" &&
|
||||
this.props.file.type !== "up" &&
|
||||
sizeToString(this.props.file.size)}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell className={classNames(classes.hideAuto,classes.tableRow)}>
|
||||
<TableCell
|
||||
className={classNames(classes.hideAuto, classes.tableRow)}
|
||||
>
|
||||
<Typography
|
||||
variant="body2"
|
||||
className={classNames(classes.folderName, {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,13 @@ import {
|
|||
Android,
|
||||
FileExcelBox,
|
||||
FilePowerpointBox,
|
||||
FileWordBox, LanguageC, LanguageCpp, LanguageGo, LanguageJavascript, LanguagePhp, LanguagePython,
|
||||
FileWordBox,
|
||||
LanguageC,
|
||||
LanguageCpp,
|
||||
LanguageGo,
|
||||
LanguageJavascript,
|
||||
LanguagePhp,
|
||||
LanguagePython,
|
||||
MagnetOn,
|
||||
ScriptText,
|
||||
WindowRestore,
|
||||
|
|
@ -80,22 +86,22 @@ const icons = {
|
|||
color: "#16b3da",
|
||||
icon: LanguageGo
|
||||
},
|
||||
python:{
|
||||
python: {
|
||||
color: "#3776ab",
|
||||
icon: LanguagePython
|
||||
},
|
||||
c:{
|
||||
c: {
|
||||
color: "#a8b9cc",
|
||||
icon: LanguageC,
|
||||
icon: LanguageC
|
||||
},
|
||||
cpp:{
|
||||
cpp: {
|
||||
color: "#004482",
|
||||
icon: LanguageCpp,
|
||||
icon: LanguageCpp
|
||||
},
|
||||
js:{
|
||||
js: {
|
||||
color: "#f4d003",
|
||||
icon: LanguageJavascript,
|
||||
},
|
||||
icon: LanguageJavascript
|
||||
}
|
||||
};
|
||||
|
||||
const getColor = (theme, color) =>
|
||||
|
|
@ -133,7 +139,7 @@ const TypeIcon = props => {
|
|||
>
|
||||
<IconComponent
|
||||
style={{
|
||||
color: theme.palette.background.paper,
|
||||
color: theme.palette.background.paper
|
||||
}}
|
||||
/>
|
||||
</Avatar>
|
||||
|
|
|
|||
|
|
@ -1,19 +1,12 @@
|
|||
import React, { useCallback, useState, useEffect } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { makeStyles } from "@material-ui/core";
|
||||
import {
|
||||
toggleSnackbar,
|
||||
} from "../../actions/index";
|
||||
import { toggleSnackbar } from "../../actions/index";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import API from "../../middleware/Api";
|
||||
import {
|
||||
Button,
|
||||
Paper,
|
||||
Avatar,
|
||||
Typography
|
||||
} from "@material-ui/core";
|
||||
import { Button, Paper, Avatar, Typography } from "@material-ui/core";
|
||||
import EmailIcon from "@material-ui/icons/EmailOutlined";
|
||||
import {useLocation} from "react-router";
|
||||
import { useLocation } from "react-router";
|
||||
const useStyles = makeStyles(theme => ({
|
||||
layout: {
|
||||
width: "auto",
|
||||
|
|
@ -42,7 +35,7 @@ const useStyles = makeStyles(theme => ({
|
|||
},
|
||||
submit: {
|
||||
marginTop: theme.spacing(3)
|
||||
},
|
||||
}
|
||||
}));
|
||||
|
||||
function useQuery() {
|
||||
|
|
@ -53,8 +46,8 @@ function Activation() {
|
|||
const query = useQuery();
|
||||
const location = useLocation();
|
||||
|
||||
const [success,setSuccess] = useState(false);
|
||||
const [email,setEmail] = useState("");
|
||||
const [success, setSuccess] = useState(false);
|
||||
const [email, setEmail] = useState("");
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const ToggleSnackbar = useCallback(
|
||||
|
|
@ -66,10 +59,10 @@ function Activation() {
|
|||
|
||||
const classes = useStyles();
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
API.get("/user/activate/" + query.get("id") + "?sign=" + query.get("sign"))
|
||||
API.get(
|
||||
"/user/activate/" + query.get("id") + "?sign=" + query.get("sign")
|
||||
)
|
||||
.then(response => {
|
||||
setEmail(response.data);
|
||||
setSuccess(true);
|
||||
|
|
@ -83,28 +76,29 @@ function Activation() {
|
|||
|
||||
return (
|
||||
<div className={classes.layout}>
|
||||
{success && <Paper className={classes.paper}>
|
||||
<Avatar className={classes.avatar}>
|
||||
<EmailIcon />
|
||||
</Avatar>
|
||||
<Typography component="h1" variant="h5">
|
||||
激活成功
|
||||
</Typography>
|
||||
<Typography style={{marginTop:"20px"}}>您的账号已被成功激活。</Typography>
|
||||
<Button
|
||||
type="submit"
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="primary"
|
||||
className={classes.submit}
|
||||
onClick={()=>history.push("/login?username="+email)}
|
||||
>
|
||||
返回登录
|
||||
</Button>
|
||||
|
||||
</Paper>}
|
||||
|
||||
|
||||
{success && (
|
||||
<Paper className={classes.paper}>
|
||||
<Avatar className={classes.avatar}>
|
||||
<EmailIcon />
|
||||
</Avatar>
|
||||
<Typography component="h1" variant="h5">
|
||||
激活成功
|
||||
</Typography>
|
||||
<Typography style={{ marginTop: "20px" }}>
|
||||
您的账号已被成功激活。
|
||||
</Typography>
|
||||
<Button
|
||||
type="submit"
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="primary"
|
||||
className={classes.submit}
|
||||
onClick={() => history.push("/login?username=" + email)}
|
||||
>
|
||||
返回登录
|
||||
</Button>
|
||||
</Paper>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,5 +11,5 @@ function getURL() {
|
|||
|
||||
export default makeAsyncScriptLoader(getURL, {
|
||||
callbackName,
|
||||
globalName,
|
||||
})(ReCAPTCHA);
|
||||
globalName
|
||||
})(ReCAPTCHA);
|
||||
|
|
|
|||
|
|
@ -57,7 +57,11 @@ export default class ReCAPTCHA extends React.Component {
|
|||
}
|
||||
|
||||
explicitRender() {
|
||||
if (this.props.grecaptcha && this.props.grecaptcha.render && this._widgetId === undefined) {
|
||||
if (
|
||||
this.props.grecaptcha &&
|
||||
this.props.grecaptcha.render &&
|
||||
this._widgetId === undefined
|
||||
) {
|
||||
const wrapper = document.createElement("div");
|
||||
this._widgetId = this.props.grecaptcha.render(wrapper, {
|
||||
sitekey: this.props.sitekey,
|
||||
|
|
@ -70,11 +74,15 @@ export default class ReCAPTCHA extends React.Component {
|
|||
size: this.props.size,
|
||||
stoken: this.props.stoken,
|
||||
hl: this.props.hl,
|
||||
badge: this.props.badge,
|
||||
badge: this.props.badge
|
||||
});
|
||||
this.captcha.appendChild(wrapper);
|
||||
}
|
||||
if (this._executeRequested && this.props.grecaptcha && this._widgetId !== undefined) {
|
||||
if (
|
||||
this._executeRequested &&
|
||||
this.props.grecaptcha &&
|
||||
this._widgetId !== undefined
|
||||
) {
|
||||
this._executeRequested = false;
|
||||
this.execute();
|
||||
}
|
||||
|
|
@ -152,7 +160,7 @@ ReCAPTCHA.propTypes = {
|
|||
size: PropTypes.oneOf(["compact", "normal", "invisible"]),
|
||||
stoken: PropTypes.string,
|
||||
hl: PropTypes.string,
|
||||
badge: PropTypes.oneOf(["bottomright", "bottomleft", "inline"]),
|
||||
badge: PropTypes.oneOf(["bottomright", "bottomleft", "inline"])
|
||||
};
|
||||
ReCAPTCHA.defaultProps = {
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
|
|
@ -161,5 +169,5 @@ ReCAPTCHA.defaultProps = {
|
|||
type: "image",
|
||||
tabindex: 0,
|
||||
size: "normal",
|
||||
badge: "bottomright",
|
||||
};
|
||||
badge: "bottomright"
|
||||
};
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ const useStyles = makeStyles(theme => ({
|
|||
display: "flex",
|
||||
width: "100%",
|
||||
justifyContent: "space-between"
|
||||
},
|
||||
}
|
||||
}));
|
||||
|
||||
function useQuery() {
|
||||
|
|
@ -68,9 +68,9 @@ function ResetForm() {
|
|||
const handleInputChange = name => e => {
|
||||
setInput({
|
||||
...input,
|
||||
[name]:e.target.value
|
||||
})
|
||||
}
|
||||
[name]: e.target.value
|
||||
});
|
||||
};
|
||||
const dispatch = useDispatch();
|
||||
const ToggleSnackbar = useCallback(
|
||||
(vertical, horizontal, msg, color) =>
|
||||
|
|
@ -81,15 +81,15 @@ function ResetForm() {
|
|||
|
||||
const submit = e => {
|
||||
e.preventDefault();
|
||||
if (input.password !== input.password_repeat){
|
||||
if (input.password !== input.password_repeat) {
|
||||
ToggleSnackbar("top", "right", "两次密码输入不一致", "warning");
|
||||
return
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
API.patch("/user/reset", {
|
||||
secret: query.get("sign"),
|
||||
id: query.get("id"),
|
||||
Password: input.password,
|
||||
Password: input.password
|
||||
})
|
||||
.then(() => {
|
||||
setLoading(false);
|
||||
|
|
@ -100,7 +100,7 @@ function ResetForm() {
|
|||
setLoading(false);
|
||||
ToggleSnackbar("top", "right", error.message, "warning");
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import React, { Component } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import KeyIcon from '@material-ui/icons/VpnKeyOutlined';
|
||||
import { toggleSnackbar, } from "../../actions/index"
|
||||
import axios from 'axios'
|
||||
import React, { Component } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import KeyIcon from "@material-ui/icons/VpnKeyOutlined";
|
||||
import { toggleSnackbar } from "../../actions/index";
|
||||
import axios from "axios";
|
||||
|
||||
import {
|
||||
withStyles,
|
||||
|
|
@ -14,120 +14,138 @@ import {
|
|||
InputLabel,
|
||||
Paper,
|
||||
Avatar,
|
||||
Typography,
|
||||
} from '@material-ui/core';
|
||||
Typography
|
||||
} from "@material-ui/core";
|
||||
|
||||
const styles = theme => ({
|
||||
layout: {
|
||||
width: 'auto',
|
||||
marginTop: '110px',
|
||||
width: "auto",
|
||||
marginTop: "110px",
|
||||
marginLeft: theme.spacing(3),
|
||||
marginRight: theme.spacing(3),
|
||||
[theme.breakpoints.up(1100 + theme.spacing(3) * 2)]: {
|
||||
width: 400,
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
},
|
||||
marginLeft: "auto",
|
||||
marginRight: "auto"
|
||||
}
|
||||
},
|
||||
paper: {
|
||||
marginTop: theme.spacing(8),
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
padding: `${theme.spacing(2)}px ${theme.spacing(3)}px ${theme.spacing(3)}px`,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
padding: `${theme.spacing(2)}px ${theme.spacing(3)}px ${theme.spacing(
|
||||
3
|
||||
)}px`
|
||||
},
|
||||
avatar: {
|
||||
margin: theme.spacing(1),
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
backgroundColor: theme.palette.secondary.main
|
||||
},
|
||||
form: {
|
||||
width: '100%', // Fix IE 11 issue.
|
||||
marginTop: theme.spacing(1),
|
||||
width: "100%", // Fix IE 11 issue.
|
||||
marginTop: theme.spacing(1)
|
||||
},
|
||||
submit: {
|
||||
marginTop: theme.spacing(3),
|
||||
marginTop: theme.spacing(3)
|
||||
},
|
||||
link: {
|
||||
marginTop: "10px",
|
||||
display:"flex",
|
||||
display: "flex",
|
||||
width: "100%",
|
||||
justifyContent: "space-between",
|
||||
justifyContent: "space-between"
|
||||
},
|
||||
captchaContainer:{
|
||||
display:"flex",
|
||||
captchaContainer: {
|
||||
display: "flex",
|
||||
marginTop: "10px",
|
||||
[theme.breakpoints.down("sm")]: {
|
||||
display: "block",
|
||||
},
|
||||
display: "block"
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
const mapStateToProps = () => {
|
||||
return {
|
||||
}
|
||||
}
|
||||
return {};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
toggleSnackbar: (vertical, horizontal, msg, color) => {
|
||||
dispatch(toggleSnackbar(vertical, horizontal, msg, color))
|
||||
},
|
||||
}
|
||||
}
|
||||
dispatch(toggleSnackbar(vertical, horizontal, msg, color));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class ResetPwdFormCompoment extends Component {
|
||||
state = {
|
||||
pwd: "",
|
||||
pwdRepeat: "",
|
||||
loading: false
|
||||
};
|
||||
|
||||
state={
|
||||
pwd:"",
|
||||
pwdRepeat:"",
|
||||
loading:false,
|
||||
}
|
||||
|
||||
login = e=>{
|
||||
login = e => {
|
||||
e.preventDefault();
|
||||
if(this.state.pwdRepeat !== this.state.pwd){
|
||||
this.props.toggleSnackbar("top","right","两次密码输入不一致","warning");
|
||||
if (this.state.pwdRepeat !== this.state.pwd) {
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"两次密码输入不一致",
|
||||
"warning"
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
loading:true,
|
||||
loading: true
|
||||
});
|
||||
axios.post('/Member/Reset',{
|
||||
pwd:this.state.pwd,
|
||||
key:window.resetKey,
|
||||
}).then( (response)=> {
|
||||
if(response.data.code!=="200"){
|
||||
axios
|
||||
.post("/Member/Reset", {
|
||||
pwd: this.state.pwd,
|
||||
key: window.resetKey
|
||||
})
|
||||
.then(response => {
|
||||
if (response.data.code !== "200") {
|
||||
this.setState({
|
||||
loading: false
|
||||
});
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
response.data.message,
|
||||
"warning"
|
||||
);
|
||||
} else {
|
||||
this.setState({
|
||||
loading: false,
|
||||
pwd: "",
|
||||
pwdRepeat: ""
|
||||
});
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"密码重设成功",
|
||||
"success"
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
this.setState({
|
||||
loading:false,
|
||||
loading: false
|
||||
});
|
||||
this.props.toggleSnackbar("top","right",response.data.message,"warning");
|
||||
}else{
|
||||
this.setState({
|
||||
loading:false,
|
||||
pwd:"",
|
||||
pwdRepeat:"",
|
||||
});
|
||||
this.props.toggleSnackbar("top","right","密码重设成功","success");
|
||||
}
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.setState({
|
||||
loading:false,
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
error.message,
|
||||
"error"
|
||||
);
|
||||
});
|
||||
this.props.toggleSnackbar("top","right",error.message,"error");
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
handleChange = name => event => {
|
||||
this.setState({ [name]: event.target.value });
|
||||
};
|
||||
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
|
||||
|
||||
return (
|
||||
<div className={classes.layout}>
|
||||
<Paper className={classes.paper}>
|
||||
|
|
@ -140,25 +158,27 @@ class ResetPwdFormCompoment extends Component {
|
|||
<form className={classes.form} onSubmit={this.login}>
|
||||
<FormControl margin="normal" required fullWidth>
|
||||
<InputLabel htmlFor="email">新密码</InputLabel>
|
||||
<Input
|
||||
id="pwd"
|
||||
type="password"
|
||||
name="pwd"
|
||||
onChange={this.handleChange("pwd")}
|
||||
autoComplete
|
||||
value={this.state.pwd}
|
||||
autoFocus />
|
||||
<Input
|
||||
id="pwd"
|
||||
type="password"
|
||||
name="pwd"
|
||||
onChange={this.handleChange("pwd")}
|
||||
autoComplete
|
||||
value={this.state.pwd}
|
||||
autoFocus
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl margin="normal" required fullWidth>
|
||||
<InputLabel htmlFor="email">重复新密码</InputLabel>
|
||||
<Input
|
||||
id="pwdRepeat"
|
||||
type="password"
|
||||
name="pwdRepeat"
|
||||
onChange={this.handleChange("pwdRepeat")}
|
||||
autoComplete
|
||||
value={this.state.pwdRepeat}
|
||||
autoFocus />
|
||||
<Input
|
||||
id="pwdRepeat"
|
||||
type="password"
|
||||
name="pwdRepeat"
|
||||
onChange={this.handleChange("pwdRepeat")}
|
||||
autoComplete
|
||||
value={this.state.pwdRepeat}
|
||||
autoFocus
|
||||
/>
|
||||
</FormControl>
|
||||
<Button
|
||||
type="submit"
|
||||
|
|
@ -169,30 +189,26 @@ class ResetPwdFormCompoment extends Component {
|
|||
className={classes.submit}
|
||||
>
|
||||
重设密码
|
||||
</Button> </form> <Divider/>
|
||||
<div className={classes.link}>
|
||||
<div>
|
||||
<Link href={"/Login"}>
|
||||
返回登录
|
||||
</Link>
|
||||
</div>
|
||||
<div>
|
||||
<Link href={"/SignUp"}>
|
||||
注册账号
|
||||
</Link>
|
||||
</div>
|
||||
</Button>{" "}
|
||||
</form>{" "}
|
||||
<Divider />
|
||||
<div className={classes.link}>
|
||||
<div>
|
||||
<Link href={"/Login"}>返回登录</Link>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Link href={"/SignUp"}>注册账号</Link>
|
||||
</div>
|
||||
</div>
|
||||
</Paper>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const ResetPwdForm = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(ResetPwdFormCompoment))
|
||||
)(withStyles(styles)(ResetPwdFormCompoment));
|
||||
|
||||
export default ResetPwdForm
|
||||
export default ResetPwdForm;
|
||||
|
|
|
|||
|
|
@ -8,9 +8,7 @@ import {
|
|||
DialogTitle,
|
||||
CircularProgress
|
||||
} from "@material-ui/core";
|
||||
import {
|
||||
toggleSnackbar,
|
||||
} from "../../actions/index";
|
||||
import { toggleSnackbar } from "../../actions/index";
|
||||
import PathSelector from "../FileManager/PathSelector";
|
||||
import { useDispatch } from "react-redux";
|
||||
import API from "../../middleware/Api";
|
||||
|
|
@ -35,7 +33,7 @@ import {
|
|||
RhombusOutline,
|
||||
Square,
|
||||
SquareOutline,
|
||||
Triangle,
|
||||
Triangle
|
||||
} from "mdi-material-ui";
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
|
|
@ -148,12 +146,12 @@ export default function AddTag(props) {
|
|||
[dispatch]
|
||||
);
|
||||
|
||||
const submitNewLink = ()=>{
|
||||
const submitNewLink = () => {
|
||||
setLoading(true);
|
||||
|
||||
API.post("/tag/link", {
|
||||
path: input.path,
|
||||
name:input.tagName
|
||||
name: input.tagName
|
||||
})
|
||||
.then(response => {
|
||||
setLoading(false);
|
||||
|
|
@ -161,7 +159,7 @@ export default function AddTag(props) {
|
|||
props.onSuccess({
|
||||
type: 1,
|
||||
name: input.tagName,
|
||||
expression:input.path,
|
||||
expression: input.path,
|
||||
color: theme.palette.text.secondary,
|
||||
icon: "FolderHeartOutline",
|
||||
id: response.data
|
||||
|
|
@ -173,7 +171,7 @@ export default function AddTag(props) {
|
|||
.then(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const submitNewTag = () => {
|
||||
setLoading(true);
|
||||
|
|
@ -203,19 +201,19 @@ export default function AddTag(props) {
|
|||
});
|
||||
};
|
||||
const submit = () => {
|
||||
if (value === 0) {
|
||||
submitNewTag();
|
||||
}else{
|
||||
submitNewLink();
|
||||
}
|
||||
if (value === 0) {
|
||||
submitNewTag();
|
||||
} else {
|
||||
submitNewLink();
|
||||
}
|
||||
};
|
||||
const selectPath = ()=>{
|
||||
const selectPath = () => {
|
||||
setInput({
|
||||
...input,
|
||||
path: selectedPath === "//" ? "/" : selectedPath
|
||||
});
|
||||
setPathSelectDialog(false);
|
||||
}
|
||||
};
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
|
|
@ -232,13 +230,21 @@ export default function AddTag(props) {
|
|||
aria-labelledby="form-dialog-title"
|
||||
>
|
||||
<DialogTitle id="form-dialog-title">选择目录</DialogTitle>
|
||||
<PathSelector presentPath="/" selected={[]} onSelect={setMoveTarget} />
|
||||
<PathSelector
|
||||
presentPath="/"
|
||||
selected={[]}
|
||||
onSelect={setMoveTarget}
|
||||
/>
|
||||
|
||||
<DialogActions>
|
||||
<Button onClick={() => setPathSelectDialog(false)}>
|
||||
取消
|
||||
</Button>
|
||||
<Button onClick={selectPath} color="primary" disabled={selectedPath === ""}>
|
||||
<Button
|
||||
onClick={selectPath}
|
||||
color="primary"
|
||||
disabled={selectedPath === ""}
|
||||
>
|
||||
确定
|
||||
</Button>
|
||||
</DialogActions>
|
||||
|
|
@ -355,7 +361,7 @@ export default function AddTag(props) {
|
|||
className={classes.textField}
|
||||
/>
|
||||
<Button
|
||||
onClick={()=>setPathSelectDialog(true)}
|
||||
onClick={() => setPathSelectDialog(true)}
|
||||
style={{
|
||||
marginLeft: theme.spacing(1),
|
||||
alignSelf: "flex-end"
|
||||
|
|
@ -379,8 +385,8 @@ export default function AddTag(props) {
|
|||
(value === 0 &&
|
||||
(input.filename === "" ||
|
||||
input.tagName === "")) ||
|
||||
(value === 1 && (input.tagName === "" ||
|
||||
input.path === ""))
|
||||
(value === 1 &&
|
||||
(input.tagName === "" || input.path === ""))
|
||||
}
|
||||
>
|
||||
确定
|
||||
|
|
|
|||
|
|
@ -9,10 +9,7 @@ import {
|
|||
DialogContentText,
|
||||
CircularProgress
|
||||
} from "@material-ui/core";
|
||||
import {
|
||||
toggleSnackbar,
|
||||
setModalsLoading,
|
||||
} from "../../actions/index";
|
||||
import { toggleSnackbar, setModalsLoading } from "../../actions/index";
|
||||
import PathSelector from "../FileManager/PathSelector";
|
||||
import { useDispatch } from "react-redux";
|
||||
import API from "../../middleware/Api";
|
||||
|
|
@ -21,7 +18,7 @@ import TextField from "@material-ui/core/TextField";
|
|||
const useStyles = makeStyles(theme => ({
|
||||
contentFix: {
|
||||
padding: "10px 24px 0px 24px",
|
||||
backgroundColor:theme.palette.background.default,
|
||||
backgroundColor: theme.palette.background.default
|
||||
},
|
||||
wrapper: {
|
||||
margin: theme.spacing(1),
|
||||
|
|
@ -85,11 +82,11 @@ export default function CompressDialog(props) {
|
|||
});
|
||||
|
||||
API.post("/file/compress", {
|
||||
src:{
|
||||
dirs:dirs,
|
||||
items:items,
|
||||
src: {
|
||||
dirs: dirs,
|
||||
items: items
|
||||
},
|
||||
name:fileName,
|
||||
name: fileName,
|
||||
dst: selectedPath === "//" ? "/" : selectedPath
|
||||
})
|
||||
.then(() => {
|
||||
|
|
@ -121,7 +118,14 @@ export default function CompressDialog(props) {
|
|||
{selectedPath !== "" && (
|
||||
<DialogContent className={classes.contentFix}>
|
||||
<DialogContentText>
|
||||
<TextField onChange={e=>setFileName(e.target.value)} value={fileName} fullWidth autoFocus id="standard-basic" label="压缩文件名" />
|
||||
<TextField
|
||||
onChange={e => setFileName(e.target.value)}
|
||||
value={fileName}
|
||||
fullWidth
|
||||
autoFocus
|
||||
id="standard-basic"
|
||||
label="压缩文件名"
|
||||
/>
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
)}
|
||||
|
|
@ -131,7 +135,11 @@ export default function CompressDialog(props) {
|
|||
<Button
|
||||
onClick={submitMove}
|
||||
color="primary"
|
||||
disabled={selectedPath === "" || fileName ==="" || props.modalsLoading}
|
||||
disabled={
|
||||
selectedPath === "" ||
|
||||
fileName === "" ||
|
||||
props.modalsLoading
|
||||
}
|
||||
>
|
||||
确定
|
||||
{props.modalsLoading && (
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import {
|
|||
import {
|
||||
toggleSnackbar,
|
||||
setModalsLoading,
|
||||
refreshFileList,
|
||||
refreshFileList
|
||||
} from "../../actions/index";
|
||||
import PathSelector from "../FileManager/PathSelector";
|
||||
import { useDispatch } from "react-redux";
|
||||
|
|
|
|||
|
|
@ -120,12 +120,12 @@ export default function CreatShare(props) {
|
|||
password: "",
|
||||
downloads: 1,
|
||||
expires: 24 * 3600,
|
||||
showPassword: false,
|
||||
showPassword: false
|
||||
});
|
||||
const [shareOption, setShareOption] = React.useState({
|
||||
password: false,
|
||||
expire: false,
|
||||
preview:true,
|
||||
preview: true
|
||||
});
|
||||
|
||||
const handleChange = prop => event => {
|
||||
|
|
@ -180,10 +180,9 @@ export default function CreatShare(props) {
|
|||
|
||||
const onClose = () => {
|
||||
props.onClose();
|
||||
setTimeout(()=>{
|
||||
setTimeout(() => {
|
||||
setShareURL("");
|
||||
},500)
|
||||
|
||||
}, 500);
|
||||
};
|
||||
|
||||
const submitShare = e => {
|
||||
|
|
@ -195,7 +194,7 @@ export default function CreatShare(props) {
|
|||
password: values.password,
|
||||
downloads: shareOption.expire ? values.downloads : -1,
|
||||
expire: values.expires,
|
||||
preview:shareOption.preview,
|
||||
preview: shareOption.preview
|
||||
};
|
||||
|
||||
API.post("/share", submitFormBody)
|
||||
|
|
@ -205,11 +204,11 @@ export default function CreatShare(props) {
|
|||
password: "",
|
||||
downloads: 1,
|
||||
expires: 24 * 3600,
|
||||
showPassword: false,
|
||||
showPassword: false
|
||||
});
|
||||
setShareOption({
|
||||
password: false,
|
||||
expire: false,
|
||||
expire: false
|
||||
});
|
||||
props.setModalsLoading(false);
|
||||
})
|
||||
|
|
@ -412,7 +411,9 @@ export default function CreatShare(props) {
|
|||
</ListItem>
|
||||
</ExpansionPanelSummary>
|
||||
<ExpansionPanelDetails>
|
||||
<Typography>是否允许在分享页面预览文件内容</Typography>
|
||||
<Typography>
|
||||
是否允许在分享页面预览文件内容
|
||||
</Typography>
|
||||
</ExpansionPanelDetails>
|
||||
</ExpansionPanel>
|
||||
</List>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, {useState} from "react";
|
||||
import React, { useState } from "react";
|
||||
import { makeStyles } from "@material-ui/core";
|
||||
import { Dialog } from "@material-ui/core";
|
||||
import DialogTitle from "@material-ui/core/DialogTitle";
|
||||
|
|
@ -15,7 +15,7 @@ const useStyles = makeStyles(theme => ({
|
|||
formIcon: {
|
||||
marginTop: 21,
|
||||
marginRight: 19,
|
||||
color:theme.palette.text.secondary,
|
||||
color: theme.palette.text.secondary
|
||||
},
|
||||
input: {
|
||||
width: 250
|
||||
|
|
@ -54,17 +54,17 @@ export default function CreateWebDAVAccount(props) {
|
|||
const handleInputChange = name => e => {
|
||||
setValue({
|
||||
...value,
|
||||
[name]: e.target.value,
|
||||
[name]: e.target.value
|
||||
});
|
||||
};
|
||||
|
||||
const selectPath = ()=>{
|
||||
const selectPath = () => {
|
||||
setValue({
|
||||
...value,
|
||||
path: selectedPath === "//" ? "/" : selectedPath
|
||||
});
|
||||
setPathSelectDialog(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
|
|
@ -78,13 +78,21 @@ export default function CreateWebDAVAccount(props) {
|
|||
aria-labelledby="form-dialog-title"
|
||||
>
|
||||
<DialogTitle id="form-dialog-title">选择目录</DialogTitle>
|
||||
<PathSelector presentPath="/" selected={[]} onSelect={setMoveTarget} />
|
||||
<PathSelector
|
||||
presentPath="/"
|
||||
selected={[]}
|
||||
onSelect={setMoveTarget}
|
||||
/>
|
||||
|
||||
<DialogActions>
|
||||
<Button onClick={() => setPathSelectDialog(false)}>
|
||||
取消
|
||||
</Button>
|
||||
<Button onClick={selectPath} color="primary" disabled={selectedPath === ""}>
|
||||
<Button
|
||||
onClick={selectPath}
|
||||
color="primary"
|
||||
disabled={selectedPath === ""}
|
||||
>
|
||||
确定
|
||||
</Button>
|
||||
</DialogActions>
|
||||
|
|
@ -115,7 +123,11 @@ export default function CreateWebDAVAccount(props) {
|
|||
label="相对根目录"
|
||||
/>
|
||||
<br />
|
||||
<Button className={classes.button} color="primary" onClick={()=>setPathSelectDialog(true)}>
|
||||
<Button
|
||||
className={classes.button}
|
||||
color="primary"
|
||||
onClick={() => setPathSelectDialog(true)}
|
||||
>
|
||||
选择目录
|
||||
</Button>
|
||||
</div>
|
||||
|
|
@ -124,7 +136,11 @@ export default function CreateWebDAVAccount(props) {
|
|||
</div>
|
||||
<DialogActions>
|
||||
<Button onClick={props.onClose}>取消</Button>
|
||||
<Button disabled={value.path === "" || value.name === ""} color="primary" onClick={()=>props.callback(value)}>
|
||||
<Button
|
||||
disabled={value.path === "" || value.name === ""}
|
||||
color="primary"
|
||||
onClick={() => props.callback(value)}
|
||||
>
|
||||
确定
|
||||
</Button>
|
||||
</DialogActions>
|
||||
|
|
|
|||
|
|
@ -9,14 +9,11 @@ import {
|
|||
DialogContentText,
|
||||
CircularProgress
|
||||
} from "@material-ui/core";
|
||||
import {
|
||||
toggleSnackbar,
|
||||
setModalsLoading,
|
||||
} from "../../actions/index";
|
||||
import { toggleSnackbar, setModalsLoading } from "../../actions/index";
|
||||
import PathSelector from "../FileManager/PathSelector";
|
||||
import { useDispatch } from "react-redux";
|
||||
import API from "../../middleware/Api";
|
||||
import {filePath} from "../../utils";
|
||||
import { filePath } from "../../utils";
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
contentFix: {
|
||||
|
|
@ -68,7 +65,7 @@ export default function DecompressDialog(props) {
|
|||
}
|
||||
SetModalsLoading(true);
|
||||
API.post("/file/decompress", {
|
||||
src:filePath(props.selected[0]),
|
||||
src: filePath(props.selected[0]),
|
||||
dst: selectedPath === "//" ? "/" : selectedPath
|
||||
})
|
||||
.then(() => {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ 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";
|
||||
import {useSelector} from "react-redux";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
const useStyles = makeStyles({
|
||||
avatar: {
|
||||
|
|
@ -23,24 +23,17 @@ const useStyles = makeStyles({
|
|||
|
||||
export default function LoadingDialog() {
|
||||
const classes = useStyles();
|
||||
const open = useSelector(
|
||||
state => state.viewUpdate.modals.loading,
|
||||
);
|
||||
const text = useSelector(
|
||||
state => state.viewUpdate.modals.loadingText,
|
||||
);
|
||||
|
||||
const open = useSelector(state => state.viewUpdate.modals.loading);
|
||||
const text = useSelector(state => state.viewUpdate.modals.loadingText);
|
||||
|
||||
return (
|
||||
<Dialog aria-labelledby="simple-dialog-title" open={open}>
|
||||
<DialogContent>
|
||||
<DialogContentText className={classes.loadingContainer}>
|
||||
<CircularProgress color="secondary" />
|
||||
<div className={classes.loading}>
|
||||
{text}
|
||||
</div>
|
||||
<div className={classes.loading}>{text}</div>
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, {useState, useEffect} from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { makeStyles } from "@material-ui/core";
|
||||
import {
|
||||
Button,
|
||||
|
|
@ -29,35 +29,37 @@ const useStyles = makeStyles(theme => ({
|
|||
marginTop: -12,
|
||||
marginLeft: -12
|
||||
},
|
||||
content:{
|
||||
padding:0,
|
||||
content: {
|
||||
padding: 0
|
||||
}
|
||||
}));
|
||||
|
||||
export default function SelectFileDialog(props) {
|
||||
const [files,setFiles] = useState(props.files);
|
||||
const [files, setFiles] = useState(props.files);
|
||||
|
||||
useEffect(()=>{
|
||||
useEffect(() => {
|
||||
setFiles(props.files);
|
||||
},[props.files]);
|
||||
}, [props.files]);
|
||||
|
||||
|
||||
const handleChange = index => event =>{
|
||||
const handleChange = index => event => {
|
||||
const filesCopy = [...files];
|
||||
// eslint-disable-next-line
|
||||
filesCopy.map((v,k)=>{
|
||||
if (v.index === index){
|
||||
filesCopy[k] = {...filesCopy[k],selected:event.target.checked ? "true" : "false"};
|
||||
filesCopy.map((v, k) => {
|
||||
if (v.index === index) {
|
||||
filesCopy[k] = {
|
||||
...filesCopy[k],
|
||||
selected: event.target.checked ? "true" : "false"
|
||||
};
|
||||
}
|
||||
});
|
||||
setFiles(filesCopy);
|
||||
};
|
||||
|
||||
const submit = () =>{
|
||||
const submit = () => {
|
||||
const index = [];
|
||||
// eslint-disable-next-line
|
||||
files.map(v=>{
|
||||
if(v.selected === "true"){
|
||||
files.map(v => {
|
||||
if (v.selected === "true") {
|
||||
index.push(parseInt(v.index));
|
||||
}
|
||||
});
|
||||
|
|
@ -77,25 +79,30 @@ export default function SelectFileDialog(props) {
|
|||
{files.map((v, k) => {
|
||||
return (
|
||||
<MenuItem key={k}>
|
||||
<FormGroup row>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
onChange={handleChange(v.index)}
|
||||
checked={v.selected === "true"}
|
||||
value="checkedA"
|
||||
/>
|
||||
}
|
||||
label={v.path}
|
||||
/>
|
||||
</FormGroup></MenuItem>
|
||||
<FormGroup row>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
onChange={handleChange(v.index)}
|
||||
checked={v.selected === "true"}
|
||||
value="checkedA"
|
||||
/>
|
||||
}
|
||||
label={v.path}
|
||||
/>
|
||||
</FormGroup>
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={props.onClose}>取消</Button>
|
||||
<div className={classes.wrapper}>
|
||||
<Button color="primary" onClick={submit} disabled={props.modalsLoading}>
|
||||
<Button
|
||||
color="primary"
|
||||
onClick={submit}
|
||||
disabled={props.modalsLoading}
|
||||
>
|
||||
确定
|
||||
{props.modalsLoading && (
|
||||
<CircularProgress
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ import classNames from "classnames";
|
|||
|
||||
const useStyles = makeStyles(() => ({
|
||||
icon: {
|
||||
color: 'rgb(255, 255, 255)',
|
||||
opacity: "0.54",
|
||||
},
|
||||
color: "rgb(255, 255, 255)",
|
||||
opacity: "0.54"
|
||||
}
|
||||
}));
|
||||
|
||||
const DarkModeSwitcher = ({ position }) => {
|
||||
|
|
@ -24,8 +24,8 @@ const DarkModeSwitcher = ({ position }) => {
|
|||
const isDayLight = (ThemeType && ThemeType === "light") || !ThemeType;
|
||||
const isDark = ThemeType && ThemeType === "dark";
|
||||
const toggleMode = () => {
|
||||
Auth.SetPreference("theme_mode",isDayLight?"dark":"light");
|
||||
ToggleThemeMode();
|
||||
Auth.SetPreference("theme_mode", isDayLight ? "dark" : "light");
|
||||
ToggleThemeMode();
|
||||
};
|
||||
const classes = useStyles();
|
||||
return (
|
||||
|
|
@ -35,9 +35,11 @@ const DarkModeSwitcher = ({ position }) => {
|
|||
>
|
||||
<IconButton
|
||||
className={classNames({
|
||||
[classes.icon]: "left" === position,
|
||||
[classes.icon]: "left" === position
|
||||
})}
|
||||
onClick={toggleMode} color="inherit">
|
||||
onClick={toggleMode}
|
||||
color="inherit"
|
||||
>
|
||||
{isDayLight && <NightIcon />}
|
||||
{isDark && <DayIcon />}
|
||||
</IconButton>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, {useCallback, useState, Suspense} from "react";
|
||||
import React, { useCallback, useState, Suspense } from "react";
|
||||
import {
|
||||
Divider,
|
||||
List,
|
||||
|
|
@ -8,7 +8,7 @@ import {
|
|||
makeStyles,
|
||||
withStyles
|
||||
} from "@material-ui/core";
|
||||
import { Clear, KeyboardArrowRight} from "@material-ui/icons";
|
||||
import { Clear, KeyboardArrowRight } from "@material-ui/icons";
|
||||
import classNames from "classnames";
|
||||
import FolderShared from "@material-ui/icons/FolderShared";
|
||||
import UploadIcon from "@material-ui/icons/CloudUpload";
|
||||
|
|
@ -106,12 +106,11 @@ const useStyles = makeStyles(theme => ({
|
|||
subMenu: {
|
||||
marginLeft: theme.spacing(2)
|
||||
},
|
||||
overFlow:{
|
||||
overFlow: {
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
textOverflow: "ellipsis"
|
||||
}
|
||||
|
||||
}));
|
||||
|
||||
const icons = {
|
||||
|
|
@ -132,7 +131,7 @@ const icons = {
|
|||
FolderHeartOutline: FolderHeartOutline
|
||||
};
|
||||
|
||||
const AddTag = React.lazy(() => import ("../Modals/AddTag" ));
|
||||
const AddTag = React.lazy(() => import("../Modals/AddTag"));
|
||||
|
||||
export default function FileTag() {
|
||||
const classes = useStyles();
|
||||
|
|
@ -143,9 +142,11 @@ export default function FileTag() {
|
|||
const isHomePage = pathHelper.isHomePage(location.pathname);
|
||||
|
||||
const [tagOpen, setTagOpen] = useState(true);
|
||||
const [addTagModal,setAddTagModal] = useState(false);
|
||||
const [tagHover,setTagHover] = useState(null);
|
||||
const [tags,setTags] = useState(Auth.GetUser().tags?Auth.GetUser().tags:[]);
|
||||
const [addTagModal, setAddTagModal] = useState(false);
|
||||
const [tagHover, setTagHover] = useState(null);
|
||||
const [tags, setTags] = useState(
|
||||
Auth.GetUser().tags ? Auth.GetUser().tags : []
|
||||
);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const SearchMyFile = useCallback(k => dispatch(searchMyFile(k)), [
|
||||
|
|
@ -159,7 +160,6 @@ export default function FileTag() {
|
|||
[dispatch]
|
||||
);
|
||||
|
||||
|
||||
const getIcon = (icon, color) => {
|
||||
if (icons[icon]) {
|
||||
const IconComponent = icons[icon];
|
||||
|
|
@ -179,19 +179,21 @@ export default function FileTag() {
|
|||
return <Circle className={[classes.iconFix]} />;
|
||||
};
|
||||
|
||||
const submitSuccess = tag =>{
|
||||
const newTags = [...tags,tag];
|
||||
const submitSuccess = tag => {
|
||||
const newTags = [...tags, tag];
|
||||
setTags(newTags);
|
||||
const user = Auth.GetUser();
|
||||
user.tags = newTags;
|
||||
Auth.SetUser(user);
|
||||
};
|
||||
|
||||
const submitDelete = id =>{
|
||||
API.delete("/tag/"+id)
|
||||
const submitDelete = id => {
|
||||
API.delete("/tag/" + id)
|
||||
.then(() => {
|
||||
const newTags = tags.filter((v)=>{return v.id !== id});
|
||||
setTags(newTags)
|
||||
const newTags = tags.filter(v => {
|
||||
return v.id !== id;
|
||||
});
|
||||
setTags(newTags);
|
||||
const user = Auth.GetUser();
|
||||
user.tags = newTags;
|
||||
Auth.SetUser(user);
|
||||
|
|
@ -204,131 +206,136 @@ export default function FileTag() {
|
|||
return (
|
||||
<>
|
||||
<Suspense fallback={""}>
|
||||
<AddTag onSuccess={submitSuccess} open={addTagModal} onClose={()=>setAddTagModal(false)}/>
|
||||
<AddTag
|
||||
onSuccess={submitSuccess}
|
||||
open={addTagModal}
|
||||
onClose={() => setAddTagModal(false)}
|
||||
/>
|
||||
</Suspense>
|
||||
<ExpansionPanel
|
||||
square
|
||||
expanded={tagOpen && isHomePage}
|
||||
onChange={() => isHomePage && setTagOpen(!tagOpen)}
|
||||
>
|
||||
<ExpansionPanelSummary
|
||||
aria-controls="panel1d-content"
|
||||
id="panel1d-header"
|
||||
<ExpansionPanel
|
||||
square
|
||||
expanded={tagOpen && isHomePage}
|
||||
onChange={() => isHomePage && setTagOpen(!tagOpen)}
|
||||
>
|
||||
<ListItem
|
||||
button
|
||||
key="我的文件"
|
||||
onClick={() =>
|
||||
!isHomePage && history.push("/home?path=%2F")
|
||||
}
|
||||
<ExpansionPanelSummary
|
||||
aria-controls="panel1d-content"
|
||||
id="panel1d-header"
|
||||
>
|
||||
<ListItemIcon>
|
||||
<KeyboardArrowRight
|
||||
className={classNames(
|
||||
{
|
||||
[classes.expanded]: tagOpen && isHomePage,
|
||||
[classes.iconFix]: true
|
||||
},
|
||||
classes.expand
|
||||
)}
|
||||
/>
|
||||
{!(tagOpen && isHomePage) && (
|
||||
<FolderShared className={classes.iconFix} />
|
||||
)}
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="我的文件" />
|
||||
</ListItem>
|
||||
<Divider />
|
||||
</ExpansionPanelSummary>
|
||||
|
||||
<ExpansionPanelDetails>
|
||||
<List onMouseLeave={()=>setTagHover(null)}>
|
||||
<ListItem
|
||||
button
|
||||
id="pickfiles"
|
||||
className={classes.hiddenButton}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<UploadIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText />
|
||||
</ListItem>
|
||||
<ListItem
|
||||
button
|
||||
id="pickfolder"
|
||||
className={classes.hiddenButton}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<UploadIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText />
|
||||
</ListItem>
|
||||
{[
|
||||
{
|
||||
key: "视频",
|
||||
id: "video",
|
||||
icon: (
|
||||
<VideoIcon
|
||||
className={[
|
||||
classes.iconFix,
|
||||
classes.iconVideo
|
||||
]}
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "图片",
|
||||
id: "image",
|
||||
icon: (
|
||||
<ImageIcon
|
||||
className={[
|
||||
classes.iconFix,
|
||||
classes.iconImg
|
||||
]}
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "音频",
|
||||
id: "audio",
|
||||
icon: (
|
||||
<MusicIcon
|
||||
className={[
|
||||
classes.iconFix,
|
||||
classes.iconAudio
|
||||
]}
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "文档",
|
||||
id: "doc",
|
||||
icon: (
|
||||
<DocIcon
|
||||
className={[
|
||||
classes.iconFix,
|
||||
classes.iconDoc
|
||||
]}
|
||||
/>
|
||||
)
|
||||
key="我的文件"
|
||||
onClick={() =>
|
||||
!isHomePage && history.push("/home?path=%2F")
|
||||
}
|
||||
].map(v => (
|
||||
>
|
||||
<ListItemIcon>
|
||||
<KeyboardArrowRight
|
||||
className={classNames(
|
||||
{
|
||||
[classes.expanded]:
|
||||
tagOpen && isHomePage,
|
||||
[classes.iconFix]: true
|
||||
},
|
||||
classes.expand
|
||||
)}
|
||||
/>
|
||||
{!(tagOpen && isHomePage) && (
|
||||
<FolderShared className={classes.iconFix} />
|
||||
)}
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="我的文件" />
|
||||
</ListItem>
|
||||
<Divider />
|
||||
</ExpansionPanelSummary>
|
||||
|
||||
<ExpansionPanelDetails>
|
||||
<List onMouseLeave={() => setTagHover(null)}>
|
||||
<ListItem
|
||||
button
|
||||
key={v.key}
|
||||
onClick={() => SearchMyFile(v.id + "/internal")}
|
||||
id="pickfiles"
|
||||
className={classes.hiddenButton}
|
||||
>
|
||||
<ListItemIcon className={classes.subMenu}>
|
||||
{v.icon}
|
||||
<ListItemIcon>
|
||||
<UploadIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={v.key} />
|
||||
<ListItemText />
|
||||
</ListItem>
|
||||
))}
|
||||
{tags.map(v => (
|
||||
<ListItem
|
||||
button
|
||||
id="pickfolder"
|
||||
className={classes.hiddenButton}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<UploadIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText />
|
||||
</ListItem>
|
||||
{[
|
||||
{
|
||||
key: "视频",
|
||||
id: "video",
|
||||
icon: (
|
||||
<VideoIcon
|
||||
className={[
|
||||
classes.iconFix,
|
||||
classes.iconVideo
|
||||
]}
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "图片",
|
||||
id: "image",
|
||||
icon: (
|
||||
<ImageIcon
|
||||
className={[
|
||||
classes.iconFix,
|
||||
classes.iconImg
|
||||
]}
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "音频",
|
||||
id: "audio",
|
||||
icon: (
|
||||
<MusicIcon
|
||||
className={[
|
||||
classes.iconFix,
|
||||
classes.iconAudio
|
||||
]}
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "文档",
|
||||
id: "doc",
|
||||
icon: (
|
||||
<DocIcon
|
||||
className={[
|
||||
classes.iconFix,
|
||||
classes.iconDoc
|
||||
]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
].map(v => (
|
||||
<ListItem
|
||||
button
|
||||
key={v.key}
|
||||
onClick={() => SearchMyFile(v.id + "/internal")}
|
||||
>
|
||||
<ListItemIcon className={classes.subMenu}>
|
||||
{v.icon}
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={v.key} />
|
||||
</ListItem>
|
||||
))}
|
||||
{tags.map(v => (
|
||||
<ListItem
|
||||
button
|
||||
key={v.id}
|
||||
onMouseEnter={()=>setTagHover(v.id)}
|
||||
onMouseEnter={() => setTagHover(v.id)}
|
||||
onClick={() => {
|
||||
if (v.type === 0) {
|
||||
SearchMyFile("tag/" + v.id);
|
||||
|
|
@ -345,26 +352,37 @@ export default function FileTag() {
|
|||
v.type === 0 ? v.color : null
|
||||
)}
|
||||
</ListItemIcon>
|
||||
<ListItemText className={classes.overFlow} primary={v.name} />
|
||||
<ListItemText
|
||||
className={classes.overFlow}
|
||||
primary={v.name}
|
||||
/>
|
||||
|
||||
{tagHover === v.id && <ListItemSecondaryAction onClick={()=>submitDelete(v.id)}>
|
||||
<IconButton size={"small"} edge="end" aria-label="delete">
|
||||
{tagHover === v.id && (
|
||||
<ListItemSecondaryAction
|
||||
onClick={() => submitDelete(v.id)}
|
||||
>
|
||||
<IconButton
|
||||
size={"small"}
|
||||
edge="end"
|
||||
aria-label="delete"
|
||||
>
|
||||
<Clear />
|
||||
</IconButton>
|
||||
</ListItemSecondaryAction>}
|
||||
</ListItemSecondaryAction>
|
||||
)}
|
||||
</ListItem>
|
||||
))}
|
||||
|
||||
<ListItem button onClick={()=>setAddTagModal(true)}>
|
||||
<ListItemIcon className={classes.subMenu}>
|
||||
<TagPlus className={classes.iconFix} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={"添加标签..."} />
|
||||
</ListItem>
|
||||
</List>{" "}
|
||||
<Divider />
|
||||
</ExpansionPanelDetails>
|
||||
</ExpansionPanel>
|
||||
</>
|
||||
<ListItem button onClick={() => setAddTagModal(true)}>
|
||||
<ListItemIcon className={classes.subMenu}>
|
||||
<TagPlus className={classes.iconFix} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={"添加标签..."} />
|
||||
</ListItem>
|
||||
</List>{" "}
|
||||
<Divider />
|
||||
</ExpansionPanelDetails>
|
||||
</ExpansionPanel>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ import FileTag from "./FileTags";
|
|||
import { Assignment, Devices, Settings } from "@material-ui/icons";
|
||||
import Divider from "@material-ui/core/Divider";
|
||||
|
||||
vhCheck()
|
||||
vhCheck();
|
||||
const drawerWidth = 240;
|
||||
const drawerWidthMobile = 270;
|
||||
|
||||
|
|
@ -365,15 +365,18 @@ class NavbarCompoment extends Component {
|
|||
if (isShare) {
|
||||
this.props.history.push(
|
||||
this.props.selected[0].key +
|
||||
"/doc?name=" +
|
||||
encodeURIComponent(this.props.selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
"/doc?name=" +
|
||||
encodeURIComponent(this.props.selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.props.history.push(
|
||||
"/doc?p=" + encodeURIComponent(previewPath) + "&id=" + this.props.selected[0].id
|
||||
"/doc?p=" +
|
||||
encodeURIComponent(previewPath) +
|
||||
"&id=" +
|
||||
this.props.selected[0].id
|
||||
);
|
||||
return;
|
||||
case "audio":
|
||||
|
|
@ -383,60 +386,72 @@ class NavbarCompoment extends Component {
|
|||
if (isShare) {
|
||||
this.props.history.push(
|
||||
this.props.selected[0].key +
|
||||
"/video?name=" +
|
||||
encodeURIComponent(this.props.selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
"/video?name=" +
|
||||
encodeURIComponent(this.props.selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.props.history.push(
|
||||
"/video?p=" +encodeURIComponent(previewPath) + "&id=" + this.props.selected[0].id
|
||||
"/video?p=" +
|
||||
encodeURIComponent(previewPath) +
|
||||
"&id=" +
|
||||
this.props.selected[0].id
|
||||
);
|
||||
return;
|
||||
case "edit":
|
||||
if (isShare) {
|
||||
this.props.history.push(
|
||||
this.props.selected[0].key +
|
||||
"/text?name=" +
|
||||
encodeURIComponent(this.props.selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
"/text?name=" +
|
||||
encodeURIComponent(this.props.selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.props.history.push(
|
||||
"/text?p=" + encodeURIComponent(previewPath) + "&id=" + this.props.selected[0].id
|
||||
"/text?p=" +
|
||||
encodeURIComponent(previewPath) +
|
||||
"&id=" +
|
||||
this.props.selected[0].id
|
||||
);
|
||||
return;
|
||||
case "pdf":
|
||||
if (isShare) {
|
||||
this.props.history.push(
|
||||
this.props.selected[0].key +
|
||||
"/pdf?name=" +
|
||||
encodeURIComponent(this.props.selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
"/pdf?name=" +
|
||||
encodeURIComponent(this.props.selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.props.history.push(
|
||||
"/pdf?p=" + encodeURIComponent(previewPath) + "&id=" + this.props.selected[0].id
|
||||
"/pdf?p=" +
|
||||
encodeURIComponent(previewPath) +
|
||||
"&id=" +
|
||||
this.props.selected[0].id
|
||||
);
|
||||
return;
|
||||
case "code":
|
||||
if (isShare) {
|
||||
this.props.history.push(
|
||||
this.props.selected[0].key +
|
||||
"/code?name=" +
|
||||
encodeURIComponent(this.props.selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
"/code?name=" +
|
||||
encodeURIComponent(this.props.selected[0].name) +
|
||||
"&share_path=" +
|
||||
encodeURIComponent(previewPath)
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.props.history.push(
|
||||
"/code?p=" + encodeURIComponent(previewPath) + "&id=" + this.props.selected[0].id
|
||||
"/code?p=" +
|
||||
encodeURIComponent(previewPath) +
|
||||
"&id=" +
|
||||
this.props.selected[0].id
|
||||
);
|
||||
return;
|
||||
default:
|
||||
|
|
@ -568,7 +583,7 @@ class NavbarCompoment extends Component {
|
|||
|
||||
{pathHelper.isMobile() && (
|
||||
<>
|
||||
<Divider/>
|
||||
<Divider />
|
||||
<List>
|
||||
<ListItem
|
||||
button
|
||||
|
|
@ -591,7 +606,9 @@ class NavbarCompoment extends Component {
|
|||
onClick={this.signOut}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<LogoutVariant className={classes.iconFix} />
|
||||
<LogoutVariant
|
||||
className={classes.iconFix}
|
||||
/>
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="退出登录" />
|
||||
</ListItem>
|
||||
|
|
@ -736,8 +753,13 @@ class NavbarCompoment extends Component {
|
|||
!(
|
||||
!this.props.isMultiple && this.props.withFile
|
||||
) && (
|
||||
<Typography variant="h6" color="inherit" noWrap
|
||||
onClick={() => {this.props.history.push("/")}}
|
||||
<Typography
|
||||
variant="h6"
|
||||
color="inherit"
|
||||
noWrap
|
||||
onClick={() => {
|
||||
this.props.history.push("/");
|
||||
}}
|
||||
>
|
||||
{this.props.subTitle
|
||||
? this.props.subTitle
|
||||
|
|
@ -799,8 +821,7 @@ class NavbarCompoment extends Component {
|
|||
(isHomePage || isSharePage) && (
|
||||
<div className={classes.sectionForFile}>
|
||||
{!this.props.isMultiple &&
|
||||
this.props.withFile
|
||||
&&
|
||||
this.props.withFile &&
|
||||
isPreviewable(
|
||||
this.props.selected[0].name
|
||||
) && (
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ import {
|
|||
ListItemText,
|
||||
Typography
|
||||
} from "@material-ui/core";
|
||||
import {withRouter} from "react-router";
|
||||
import { withRouter } from "react-router";
|
||||
import pathHelper from "../../utils/page";
|
||||
import {HotKeys,configure} from "react-hotkeys";
|
||||
import { HotKeys, configure } from "react-hotkeys";
|
||||
|
||||
configure({
|
||||
ignoreTags:[],
|
||||
ignoreTags: []
|
||||
});
|
||||
|
||||
const mapStateToProps = () => {
|
||||
|
|
@ -91,11 +91,10 @@ const styles = theme => ({
|
|||
});
|
||||
|
||||
const keyMap = {
|
||||
SEARCH: "enter",
|
||||
SEARCH: "enter"
|
||||
};
|
||||
|
||||
class SearchBarCompoment extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
|
|
@ -104,15 +103,15 @@ class SearchBarCompoment extends Component {
|
|||
};
|
||||
}
|
||||
|
||||
handlers={
|
||||
SEARCH:(e)=>{
|
||||
if(pathHelper.isHomePage(this.props.location.pathname)){
|
||||
handlers = {
|
||||
SEARCH: e => {
|
||||
if (pathHelper.isHomePage(this.props.location.pathname)) {
|
||||
this.searchMyFile();
|
||||
}else{
|
||||
} else {
|
||||
this.searchShare();
|
||||
}
|
||||
e.target.blur();
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
handleChange = event => {
|
||||
|
|
@ -131,14 +130,15 @@ class SearchBarCompoment extends Component {
|
|||
};
|
||||
|
||||
searchMyFile = () => {
|
||||
this.props.searchMyFile("keywords/"+this.input);
|
||||
this.props.searchMyFile("keywords/" + this.input);
|
||||
};
|
||||
|
||||
searchShare = () => {
|
||||
this.props.history.push("/search?keywords="+encodeURIComponent(this.input));
|
||||
this.props.history.push(
|
||||
"/search?keywords=" + encodeURIComponent(this.input)
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
const { anchorEl } = this.state;
|
||||
|
|
@ -146,22 +146,22 @@ class SearchBarCompoment extends Component {
|
|||
const isHomePage = pathHelper.isHomePage(this.props.location.pathname);
|
||||
|
||||
return (
|
||||
<div className={classes.search}>
|
||||
<div className={classes.search}>
|
||||
<div className={classes.searchIcon}>
|
||||
<SearchIcon />
|
||||
</div>
|
||||
<HotKeys keyMap={keyMap} handlers={this.handlers}>
|
||||
<InputBase
|
||||
placeholder="搜索..."
|
||||
classes={{
|
||||
root: classes.inputRoot,
|
||||
input: classes.inputInput
|
||||
}}
|
||||
onChange={this.handleChange}
|
||||
onBlur={this.cancelSuggest}
|
||||
value={this.state.input}
|
||||
/>
|
||||
</HotKeys>
|
||||
<HotKeys keyMap={keyMap} handlers={this.handlers}>
|
||||
<InputBase
|
||||
placeholder="搜索..."
|
||||
classes={{
|
||||
root: classes.inputRoot,
|
||||
input: classes.inputInput
|
||||
}}
|
||||
onChange={this.handleChange}
|
||||
onBlur={this.cancelSuggest}
|
||||
value={this.state.input}
|
||||
/>
|
||||
</HotKeys>
|
||||
<Popper
|
||||
id={id}
|
||||
open={this.state.input !== ""}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import {
|
|||
ListItemIcon,
|
||||
ListItemText,
|
||||
List,
|
||||
Hidden,
|
||||
Hidden
|
||||
} from "@material-ui/core";
|
||||
const drawerWidth = 240;
|
||||
const styles = theme => ({
|
||||
|
|
|
|||
|
|
@ -8,7 +8,11 @@ import {
|
|||
AccountArrowRight,
|
||||
AccountPlus
|
||||
} from "mdi-material-ui";
|
||||
import {setSessionStatus, setUserPopover, toggleSnackbar} from "../../actions";
|
||||
import {
|
||||
setSessionStatus,
|
||||
setUserPopover,
|
||||
toggleSnackbar
|
||||
} from "../../actions";
|
||||
import { withRouter } from "react-router-dom";
|
||||
import Auth from "../../middleware/Auth";
|
||||
import {
|
||||
|
|
@ -38,9 +42,9 @@ const mapDispatchToProps = dispatch => {
|
|||
toggleSnackbar: (vertical, horizontal, msg, color) => {
|
||||
dispatch(toggleSnackbar(vertical, horizontal, msg, color));
|
||||
},
|
||||
setSessionStatus:status=>{
|
||||
setSessionStatus: status => {
|
||||
dispatch(setSessionStatus(status));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
const styles = () => ({
|
||||
|
|
@ -106,7 +110,9 @@ class UserAvatarPopoverCompoment extends Component {
|
|||
render() {
|
||||
const { classes } = this.props;
|
||||
const user = Auth.GetUser();
|
||||
const isAdminPage = pathHelper.isAdminPage(this.props.location.pathname);
|
||||
const isAdminPage = pathHelper.isAdminPage(
|
||||
this.props.location.pathname
|
||||
);
|
||||
|
||||
return (
|
||||
<Popover
|
||||
|
|
@ -125,17 +131,17 @@ class UserAvatarPopoverCompoment extends Component {
|
|||
{!Auth.Check() && (
|
||||
<div className={classes.visitorMenu}>
|
||||
<Divider />
|
||||
<MenuItem onClick={() =>
|
||||
this.props.history.push("/login")
|
||||
}>
|
||||
<MenuItem
|
||||
onClick={() => this.props.history.push("/login")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<AccountArrowRight />
|
||||
</ListItemIcon>
|
||||
登录
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() =>
|
||||
this.props.history.push("/signup")
|
||||
}>
|
||||
<MenuItem
|
||||
onClick={() => this.props.history.push("/signup")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<AccountPlus />
|
||||
</ListItemIcon>
|
||||
|
|
@ -149,16 +155,20 @@ class UserAvatarPopoverCompoment extends Component {
|
|||
<div className={classes.largeAvatarContainer}>
|
||||
<Avatar
|
||||
className={classes.largeAvatar}
|
||||
src={"/api/v3/user/avatar/"+user.id + "/l"}
|
||||
src={
|
||||
"/api/v3/user/avatar/" + user.id + "/l"
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className={classes.info}>
|
||||
<Typography noWrap>{user.nickname}</Typography>
|
||||
<Typography color="textSecondary"
|
||||
style={{
|
||||
fontSize: "0.875rem",
|
||||
}}
|
||||
noWrap>
|
||||
<Typography
|
||||
color="textSecondary"
|
||||
style={{
|
||||
fontSize: "0.875rem"
|
||||
}}
|
||||
noWrap
|
||||
>
|
||||
{user.user_name}
|
||||
</Typography>
|
||||
<Chip
|
||||
|
|
@ -174,33 +184,33 @@ class UserAvatarPopoverCompoment extends Component {
|
|||
</div>
|
||||
<div>
|
||||
<Divider />
|
||||
{!isAdminPage && <MenuItem
|
||||
style={{
|
||||
padding:" 11px 16px 11px 16px",
|
||||
}}
|
||||
onClick={() =>{
|
||||
this.handleClose();
|
||||
this.props.history.push("/profile/"+user.id);
|
||||
}
|
||||
|
||||
}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<HomeAccount />
|
||||
</ListItemIcon>
|
||||
个人主页
|
||||
</MenuItem>}
|
||||
{!isAdminPage && (
|
||||
<MenuItem
|
||||
style={{
|
||||
padding: " 11px 16px 11px 16px"
|
||||
}}
|
||||
onClick={() => {
|
||||
this.handleClose();
|
||||
this.props.history.push(
|
||||
"/profile/" + user.id
|
||||
);
|
||||
}}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<HomeAccount />
|
||||
</ListItemIcon>
|
||||
个人主页
|
||||
</MenuItem>
|
||||
)}
|
||||
{user.group.id === 1 && (
|
||||
<MenuItem
|
||||
style={{
|
||||
padding:" 11px 16px 11px 16px",
|
||||
padding: " 11px 16px 11px 16px"
|
||||
}}
|
||||
onClick={() =>{
|
||||
onClick={() => {
|
||||
this.handleClose();
|
||||
this.props.history.push("/admin/home");
|
||||
}
|
||||
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<DesktopMacDashboard />
|
||||
|
|
@ -209,9 +219,12 @@ class UserAvatarPopoverCompoment extends Component {
|
|||
</MenuItem>
|
||||
)}
|
||||
|
||||
<MenuItem style={{
|
||||
padding:" 11px 16px 11px 16px",
|
||||
}} onClick={this.sigOut}>
|
||||
<MenuItem
|
||||
style={{
|
||||
padding: " 11px 16px 11px 16px"
|
||||
}}
|
||||
onClick={this.sigOut}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<LogoutVariant />
|
||||
</ListItemIcon>
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ import { connect } from "react-redux";
|
|||
import { setUserPopover } from "../../actions";
|
||||
import { withStyles, Typography } from "@material-ui/core";
|
||||
import Auth from "../../middleware/Auth";
|
||||
import DarkModeSwitcher from "./DarkModeSwitcher"
|
||||
import DarkModeSwitcher from "./DarkModeSwitcher";
|
||||
import Avatar from "@material-ui/core/Avatar";
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
isLogin:state.viewUpdate.isLogin,
|
||||
isLogin: state.viewUpdate.isLogin
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -76,12 +76,12 @@ const styles = theme => ({
|
|||
flexAvatar: {
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "end",
|
||||
alignItems: "end"
|
||||
},
|
||||
groupName: {
|
||||
marginLeft: "10px",
|
||||
color: "#ffffff",
|
||||
opacity: "0.54",
|
||||
opacity: "0.54"
|
||||
},
|
||||
storageCircle: {
|
||||
width: "200px"
|
||||
|
|
@ -101,13 +101,11 @@ class UserInfoCompoment extends Component {
|
|||
return (
|
||||
<div className={classes.userNav}>
|
||||
<div className={classes.flexAvatar}>
|
||||
{ /* eslint-disable-next-line */}
|
||||
{/* eslint-disable-next-line */}
|
||||
<a onClick={this.showUserInfo} className={classes.avatar}>
|
||||
{isLogin && (
|
||||
<Avatar
|
||||
src={
|
||||
"/api/v3/user/avatar/"+user.id + "/l"
|
||||
}
|
||||
src={"/api/v3/user/avatar/" + user.id + "/l"}
|
||||
className={classes.avatarImg}
|
||||
/>
|
||||
)}
|
||||
|
|
@ -118,7 +116,7 @@ class UserInfoCompoment extends Component {
|
|||
/>
|
||||
)}
|
||||
</a>
|
||||
<DarkModeSwitcher position="left"/>
|
||||
<DarkModeSwitcher position="left" />
|
||||
</div>
|
||||
<div className={classes.storageCircle}>
|
||||
<Typography
|
||||
|
|
@ -126,7 +124,7 @@ class UserInfoCompoment extends Component {
|
|||
component="h2"
|
||||
noWrap
|
||||
>
|
||||
{isLogin?user.nickname:"未登录"}
|
||||
{isLogin ? user.nickname : "未登录"}
|
||||
</Typography>
|
||||
<Typography
|
||||
className={classes.groupName}
|
||||
|
|
@ -134,7 +132,7 @@ class UserInfoCompoment extends Component {
|
|||
color="textSecondary"
|
||||
noWrap
|
||||
>
|
||||
{isLogin?user.group.name:"游客"}
|
||||
{isLogin ? user.group.name : "游客"}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
import React from "react"
|
||||
import ContentLoader from "react-content-loader"
|
||||
import React from "react";
|
||||
import ContentLoader from "react-content-loader";
|
||||
|
||||
const MyLoader = () => (
|
||||
<ContentLoader
|
||||
height={80}
|
||||
width={200}
|
||||
speed={2}
|
||||
primaryColor="#f3f3f3"
|
||||
secondaryColor="#e4e4e4"
|
||||
<ContentLoader
|
||||
height={80}
|
||||
width={200}
|
||||
speed={2}
|
||||
primaryColor="#f3f3f3"
|
||||
secondaryColor="#e4e4e4"
|
||||
>
|
||||
<rect x="4" y="4" rx="7" ry="7" width="392" height="116" />
|
||||
<rect x="4" y="4" rx="7" ry="7" width="392" height="116" />
|
||||
</ContentLoader>
|
||||
)
|
||||
);
|
||||
|
||||
function captchaPlacholder (){
|
||||
return (<MyLoader />)
|
||||
function captchaPlacholder() {
|
||||
return <MyLoader />;
|
||||
}
|
||||
|
||||
export default captchaPlacholder
|
||||
export default captchaPlacholder;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React from "react";
|
||||
import React from "react";
|
||||
|
||||
class ErrorBoundary extends React.Component {
|
||||
constructor(props) {
|
||||
|
|
@ -25,4 +25,4 @@ class ErrorBoundary extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default ErrorBoundary
|
||||
export default ErrorBoundary;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React from "react";
|
||||
import { Facebook } from "react-content-loader";
|
||||
import { Facebook } from "react-content-loader";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
|
|
@ -14,9 +14,7 @@ const useStyles = makeStyles(theme => ({
|
|||
}));
|
||||
|
||||
const MyLoader = props => {
|
||||
return (
|
||||
<Facebook className={props.className} />
|
||||
);
|
||||
return <Facebook className={props.className} />;
|
||||
};
|
||||
|
||||
function PageLoading() {
|
||||
|
|
|
|||
|
|
@ -1,33 +1,28 @@
|
|||
import React from "react"
|
||||
import { Code } from "react-content-loader"
|
||||
import {makeStyles} from "@material-ui/core/styles";
|
||||
import React from "react";
|
||||
import { Code } from "react-content-loader";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
loader:{
|
||||
loader: {
|
||||
width: "70%",
|
||||
padding: 40,
|
||||
[theme.breakpoints.down("md")]: {
|
||||
width: "100%",
|
||||
padding: 10,
|
||||
},
|
||||
},
|
||||
padding: 10
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
const MyLoader = props => <Code className={props.className} />;
|
||||
|
||||
const MyLoader = (props) => (
|
||||
<Code className={props.className}/>
|
||||
)
|
||||
|
||||
function TextLoading (){
|
||||
|
||||
function TextLoading() {
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<MyLoader className={classes.loader}/>
|
||||
<MyLoader className={classes.loader} />
|
||||
</div>
|
||||
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default TextLoading
|
||||
export default TextLoading;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import React, { useState, useCallback } from "react";
|
||||
import {
|
||||
Button, Dialog,
|
||||
Button,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
|
|
@ -17,9 +18,9 @@ import {
|
|||
import { useDispatch } from "react-redux";
|
||||
import { toggleSnackbar } from "../../actions";
|
||||
import RightIcon from "@material-ui/icons/KeyboardArrowRight";
|
||||
import {Add, Fingerprint, HighlightOff} from "@material-ui/icons";
|
||||
import { Add, Fingerprint, HighlightOff } from "@material-ui/icons";
|
||||
import API from "../../middleware/Api";
|
||||
import {bufferDecode, bufferEncode} from "../../utils";
|
||||
import { bufferDecode, bufferEncode } from "../../utils";
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
sectionTitle: {
|
||||
|
|
@ -46,8 +47,8 @@ const useStyles = makeStyles(theme => ({
|
|||
}));
|
||||
|
||||
export default function Authn(props) {
|
||||
const [selected,setSelected] = useState("");
|
||||
const [confirm,setConfirm] = useState(false);
|
||||
const [selected, setSelected] = useState("");
|
||||
const [confirm, setConfirm] = useState(false);
|
||||
const dispatch = useDispatch();
|
||||
const ToggleSnackbar = useCallback(
|
||||
(vertical, horizontal, msg, color) =>
|
||||
|
|
@ -57,41 +58,27 @@ export default function Authn(props) {
|
|||
|
||||
const deleteCredential = id => {
|
||||
API.patch("/user/setting/authn", {
|
||||
id:id,
|
||||
id: id
|
||||
})
|
||||
.then(() => {
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"凭证已删除",
|
||||
"success"
|
||||
);
|
||||
props.remove(id)
|
||||
ToggleSnackbar("top", "right", "凭证已删除", "success");
|
||||
props.remove(id);
|
||||
})
|
||||
.catch(error => {
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
error.message,
|
||||
"error"
|
||||
);
|
||||
}).then(()=>{
|
||||
setConfirm(false);
|
||||
});
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
})
|
||||
.then(() => {
|
||||
setConfirm(false);
|
||||
});
|
||||
};
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
const addCredential = () =>{
|
||||
if (!navigator.credentials){
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"当前浏览器或环境不支持",
|
||||
"warning"
|
||||
);
|
||||
const addCredential = () => {
|
||||
if (!navigator.credentials) {
|
||||
ToggleSnackbar("top", "right", "当前浏览器或环境不支持", "warning");
|
||||
|
||||
return
|
||||
return;
|
||||
}
|
||||
API.put("/user/authn", {})
|
||||
.then(response => {
|
||||
|
|
@ -112,7 +99,7 @@ export default function Authn(props) {
|
|||
) {
|
||||
credentialCreationOptions.publicKey.excludeCredentials[
|
||||
i
|
||||
].id = bufferDecode(
|
||||
].id = bufferDecode(
|
||||
credentialCreationOptions.publicKey
|
||||
.excludeCredentials[i].id
|
||||
);
|
||||
|
|
@ -142,41 +129,28 @@ export default function Authn(props) {
|
|||
})
|
||||
.then(response => {
|
||||
props.add(response.data);
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"验证器已添加",
|
||||
"success"
|
||||
);
|
||||
ToggleSnackbar("top", "right", "验证器已添加", "success");
|
||||
return;
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error);
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
error.message,
|
||||
"error"
|
||||
);
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
<Dialog
|
||||
open={confirm}
|
||||
onClose={()=>setConfirm(false)}
|
||||
>
|
||||
<Dialog open={confirm} onClose={() => setConfirm(false)}>
|
||||
<DialogTitle>删除凭证</DialogTitle>
|
||||
<DialogContent>
|
||||
确定要吊销这个凭证吗?
|
||||
</DialogContent>
|
||||
<DialogContent>确定要吊销这个凭证吗?</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={()=>setConfirm(false)} color="default">
|
||||
<Button onClick={() => setConfirm(false)} color="default">
|
||||
取消
|
||||
</Button>
|
||||
<Button onClick={()=>deleteCredential(selected)} color="primary">
|
||||
<Button
|
||||
onClick={() => deleteCredential(selected)}
|
||||
color="primary"
|
||||
>
|
||||
确定
|
||||
</Button>
|
||||
</DialogActions>
|
||||
|
|
@ -187,32 +161,36 @@ export default function Authn(props) {
|
|||
</Typography>
|
||||
<Paper>
|
||||
<List className={classes.desenList}>
|
||||
{props.list.map((v) => (
|
||||
{props.list.map(v => (
|
||||
<>
|
||||
<ListItem button
|
||||
style={{
|
||||
paddingRight:60,
|
||||
}}
|
||||
onClick={()=>{
|
||||
setConfirm(true);
|
||||
setSelected(v.id);
|
||||
}}>
|
||||
<ListItem
|
||||
button
|
||||
style={{
|
||||
paddingRight: 60
|
||||
}}
|
||||
onClick={() => {
|
||||
setConfirm(true);
|
||||
setSelected(v.id);
|
||||
}}
|
||||
>
|
||||
<ListItemIcon className={classes.iconFix}>
|
||||
<Fingerprint />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={v.fingerprint} />
|
||||
|
||||
<ListItemSecondaryAction
|
||||
onClick={()=>deleteCredential(v.id)}
|
||||
onClick={() => deleteCredential(v.id)}
|
||||
className={classes.flexContainer}
|
||||
>
|
||||
<HighlightOff className={classes.rightIcon} />
|
||||
<HighlightOff
|
||||
className={classes.rightIcon}
|
||||
/>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
<Divider />
|
||||
</>
|
||||
))}
|
||||
<ListItem button onClick={()=>addCredential()}>
|
||||
<ListItem button onClick={() => addCredential()}>
|
||||
<ListItemIcon className={classes.iconFix}>
|
||||
<Add />
|
||||
</ListItemIcon>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import {
|
|||
TableRow,
|
||||
Grid
|
||||
} from "@material-ui/core";
|
||||
import {withRouter} from "react-router";
|
||||
import { withRouter } from "react-router";
|
||||
import Pagination from "@material-ui/lab/Pagination";
|
||||
|
||||
const styles = theme => ({
|
||||
|
|
@ -83,7 +83,7 @@ const styles = theme => ({
|
|||
marginTop: "1px",
|
||||
fontSize: "25px",
|
||||
color: "#ffffff",
|
||||
opacity: "0.81",
|
||||
opacity: "0.81"
|
||||
},
|
||||
th: {
|
||||
minWidth: "106px"
|
||||
|
|
@ -97,7 +97,7 @@ const styles = theme => ({
|
|||
cursor: "pointer"
|
||||
},
|
||||
navigator: {
|
||||
padding:theme.spacing(2),
|
||||
padding: theme.spacing(2)
|
||||
},
|
||||
pageInfo: {
|
||||
marginTop: "14px",
|
||||
|
|
@ -110,8 +110,8 @@ const styles = theme => ({
|
|||
infoContainer: {
|
||||
marginTop: "30px"
|
||||
},
|
||||
tableContainer:{
|
||||
overflowX:"auto",
|
||||
tableContainer: {
|
||||
overflowX: "auto"
|
||||
}
|
||||
});
|
||||
const mapStateToProps = () => {
|
||||
|
|
@ -131,8 +131,8 @@ class ProfileCompoment extends Component {
|
|||
listType: 0,
|
||||
shareList: [],
|
||||
page: 1,
|
||||
user:null,
|
||||
total:0,
|
||||
user: null,
|
||||
total: 0
|
||||
};
|
||||
|
||||
handleChange = (event, listType) => {
|
||||
|
|
@ -148,18 +148,29 @@ class ProfileCompoment extends Component {
|
|||
this.loadList(1, "default");
|
||||
};
|
||||
|
||||
loadList = (page,order) => {
|
||||
API
|
||||
.get("/user/profile/" + this.props.match.params.id + "?page=" + page + "&type=" + order)
|
||||
loadList = (page, order) => {
|
||||
API.get(
|
||||
"/user/profile/" +
|
||||
this.props.match.params.id +
|
||||
"?page=" +
|
||||
page +
|
||||
"&type=" +
|
||||
order
|
||||
)
|
||||
.then(response => {
|
||||
this.setState({
|
||||
shareList: response.data.items,
|
||||
user:response.data.user,
|
||||
total:response.data.total,
|
||||
user: response.data.user,
|
||||
total: response.data.total
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
this.props.toggleSnackbar("top", "right", error.message, "error");
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
error.message,
|
||||
"error"
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -182,17 +193,17 @@ class ProfileCompoment extends Component {
|
|||
|
||||
return (
|
||||
<div className={classes.layout}>
|
||||
{this.state.user === null &&
|
||||
<div></div>
|
||||
}
|
||||
{this.state.user !== null &&
|
||||
{this.state.user === null && <div></div>}
|
||||
{this.state.user !== null && (
|
||||
<Paper square>
|
||||
<div className={classes.userNav}>
|
||||
<div>
|
||||
<Avatar
|
||||
className={classes.avatarContainer}
|
||||
src={
|
||||
"/api/v3/user/avatar/"+this.state.user.id + "/l"
|
||||
"/api/v3/user/avatar/" +
|
||||
this.state.user.id +
|
||||
"/l"
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -303,88 +314,109 @@ class ProfileCompoment extends Component {
|
|||
this.state.listType === 1) && (
|
||||
<div>
|
||||
<div className={classes.tableContainer}>
|
||||
<Table className={classes.table}>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>文件名</TableCell>
|
||||
<TableCell
|
||||
className={classes.mobileHide}
|
||||
>
|
||||
分享日期
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className={[
|
||||
classes.th,
|
||||
classes.mobileHide
|
||||
]}
|
||||
>
|
||||
下载次数
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className={[
|
||||
classes.th,
|
||||
classes.mobileHide
|
||||
]}
|
||||
>
|
||||
浏览次数
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{this.state.shareList.map((row,id) => (
|
||||
<TableRow
|
||||
key={id}
|
||||
className={classes.tableLink}
|
||||
onClick={() =>
|
||||
this.props.history.push(
|
||||
"/s/" + row.key
|
||||
)
|
||||
}
|
||||
>
|
||||
<TableCell>
|
||||
<Typography>
|
||||
{row.source?row.source.name:"[已失效]"}
|
||||
</Typography>
|
||||
<Table className={classes.table}>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>文件名</TableCell>
|
||||
<TableCell
|
||||
className={
|
||||
classes.mobileHide
|
||||
}
|
||||
>
|
||||
分享日期
|
||||
</TableCell>
|
||||
<TableCell
|
||||
nowrap={"nowrap"}
|
||||
className={classes.mobileHide}
|
||||
className={[
|
||||
classes.th,
|
||||
classes.mobileHide
|
||||
]}
|
||||
>
|
||||
{row.create_date}
|
||||
下载次数
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className={classes.mobileHide}
|
||||
className={[
|
||||
classes.th,
|
||||
classes.mobileHide
|
||||
]}
|
||||
>
|
||||
{row.downloads}
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className={classes.mobileHide}
|
||||
>
|
||||
{row.views}
|
||||
浏览次数
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{this.state.shareList.map(
|
||||
(row, id) => (
|
||||
<TableRow
|
||||
key={id}
|
||||
className={
|
||||
classes.tableLink
|
||||
}
|
||||
onClick={() =>
|
||||
this.props.history.push(
|
||||
"/s/" + row.key
|
||||
)
|
||||
}
|
||||
>
|
||||
<TableCell>
|
||||
<Typography>
|
||||
{row.source
|
||||
? row.source
|
||||
.name
|
||||
: "[已失效]"}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
nowrap={"nowrap"}
|
||||
className={
|
||||
classes.mobileHide
|
||||
}
|
||||
>
|
||||
{row.create_date}
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className={
|
||||
classes.mobileHide
|
||||
}
|
||||
>
|
||||
{row.downloads}
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className={
|
||||
classes.mobileHide
|
||||
}
|
||||
>
|
||||
{row.views}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
{this.state.shareList.length !== 0 &&
|
||||
this.state.listType === 0 && (
|
||||
<div className={classes.navigator}>
|
||||
<Pagination
|
||||
count={Math.ceil(this.state.total / 10)}
|
||||
onChange={(e,v)=>this.loadList(
|
||||
v,
|
||||
this.state.listType === 0 ? "default" : "hot"
|
||||
)}
|
||||
color="secondary"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
this.state.listType === 0 && (
|
||||
<div className={classes.navigator}>
|
||||
<Pagination
|
||||
count={Math.ceil(
|
||||
this.state.total / 10
|
||||
)}
|
||||
onChange={(e, v) =>
|
||||
this.loadList(
|
||||
v,
|
||||
this.state.listType ===
|
||||
0
|
||||
? "default"
|
||||
: "hot"
|
||||
)
|
||||
}
|
||||
color="secondary"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Paper>
|
||||
}
|
||||
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import TableCell from "@material-ui/core/TableCell";
|
|||
import TableBody from "@material-ui/core/TableBody";
|
||||
import API from "../../middleware/Api";
|
||||
import TimeAgo from "timeago-react";
|
||||
import {getTaskProgress, getTaskStatus, getTaskType} from "../../config";
|
||||
import { getTaskProgress, getTaskStatus, getTaskType } from "../../config";
|
||||
import Pagination from "@material-ui/lab/Pagination";
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
|
|
@ -28,7 +28,7 @@ const useStyles = makeStyles(theme => ({
|
|||
},
|
||||
content: {
|
||||
marginTop: theme.spacing(4),
|
||||
overflowX:"auto",
|
||||
overflowX: "auto"
|
||||
},
|
||||
cardContent: {
|
||||
padding: theme.spacing(2)
|
||||
|
|
@ -39,11 +39,11 @@ const useStyles = makeStyles(theme => ({
|
|||
create: {
|
||||
marginTop: theme.spacing(2)
|
||||
},
|
||||
noWrap:{
|
||||
wordBreak: "keepAll",
|
||||
noWrap: {
|
||||
wordBreak: "keepAll"
|
||||
},
|
||||
footer:{
|
||||
padding:theme.spacing(2),
|
||||
footer: {
|
||||
padding: theme.spacing(2)
|
||||
}
|
||||
}));
|
||||
|
||||
|
|
@ -60,33 +60,32 @@ export default function Tasks() {
|
|||
);
|
||||
|
||||
const loadList = page => {
|
||||
API.get("/user/setting/tasks?page=" + page)
|
||||
.then(response => {
|
||||
setTasks(response.data.tasks);
|
||||
setTotal(response.data.total);
|
||||
})
|
||||
.catch(error => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
});
|
||||
API.get("/user/setting/tasks?page=" + page)
|
||||
.then(response => {
|
||||
setTasks(response.data.tasks);
|
||||
setTotal(response.data.total);
|
||||
})
|
||||
.catch(error => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
loadList(page);
|
||||
// eslint-disable-next-line
|
||||
}, [page]);
|
||||
|
||||
const getError = error => {
|
||||
if (error === ""){
|
||||
return "-"
|
||||
if (error === "") {
|
||||
return "-";
|
||||
}
|
||||
try {
|
||||
const res = JSON.parse(error)
|
||||
return res.msg
|
||||
}catch (e) {
|
||||
return "未知"
|
||||
const res = JSON.parse(error);
|
||||
return res.msg;
|
||||
} catch (e) {
|
||||
return "未知";
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
|
|
@ -100,16 +99,26 @@ export default function Tasks() {
|
|||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell nowrap="nowrap">创建于</TableCell>
|
||||
<TableCell nowrap="nowrap" align="right">任务类型</TableCell>
|
||||
<TableCell nowrap="nowrap" align="right">状态</TableCell>
|
||||
<TableCell nowrap="nowrap" align="right">最后进度</TableCell>
|
||||
<TableCell nowrap="nowrap" align="right">
|
||||
任务类型
|
||||
</TableCell>
|
||||
<TableCell nowrap="nowrap" align="right">
|
||||
状态
|
||||
</TableCell>
|
||||
<TableCell nowrap="nowrap" align="right">
|
||||
最后进度
|
||||
</TableCell>
|
||||
<TableCell nowrap="nowrap">错误信息</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{tasks.map((row, id) => (
|
||||
<TableRow key={id}>
|
||||
<TableCell nowrap="nowrap" component="th" scope="row">
|
||||
<TableCell
|
||||
nowrap="nowrap"
|
||||
component="th"
|
||||
scope="row"
|
||||
>
|
||||
<TimeAgo
|
||||
datetime={row.create_date}
|
||||
locale="zh_CN"
|
||||
|
|
@ -118,22 +127,25 @@ export default function Tasks() {
|
|||
<TableCell nowrap="nowrap" align="right">
|
||||
{getTaskType(row.type)}
|
||||
</TableCell>
|
||||
<TableCell nowrap="nowrap" align="right">{getTaskStatus(row.status)}</TableCell>
|
||||
<TableCell nowrap="nowrap" align="right">
|
||||
{getTaskProgress(row.type,row.progress)}
|
||||
{getTaskStatus(row.status)}
|
||||
</TableCell>
|
||||
<TableCell nowrap="nowrap" align="right">
|
||||
{getTaskProgress(row.type, row.progress)}
|
||||
</TableCell>
|
||||
<TableCell className={classes.noWrap}>
|
||||
{getError(row.error)}
|
||||
</TableCell>
|
||||
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<div className={classes.footer}>
|
||||
<Pagination count={Math.ceil(total / 10)}
|
||||
onChange={(e,v)=>setPage(v)}
|
||||
color="secondary"/>
|
||||
<Pagination
|
||||
count={Math.ceil(total / 10)}
|
||||
onChange={(e, v) => setPage(v)}
|
||||
color="secondary"
|
||||
/>
|
||||
</div>
|
||||
</Paper>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,12 @@ import NickIcon from "@material-ui/icons/PermContactCalendar";
|
|||
import LockIcon from "@material-ui/icons/Lock";
|
||||
import VerifyIcon from "@material-ui/icons/VpnKey";
|
||||
import ColorIcon from "@material-ui/icons/Palette";
|
||||
import {applyThemes, changeViewMethod, toggleDaylightMode, toggleSnackbar} from "../../actions";
|
||||
import {
|
||||
applyThemes,
|
||||
changeViewMethod,
|
||||
toggleDaylightMode,
|
||||
toggleSnackbar
|
||||
} from "../../actions";
|
||||
import axios from "axios";
|
||||
import FingerprintIcon from "@material-ui/icons/Fingerprint";
|
||||
import ToggleButton from "@material-ui/lab/ToggleButton";
|
||||
|
|
@ -43,7 +48,7 @@ import API from "../../middleware/Api";
|
|||
import Auth from "../../middleware/Auth";
|
||||
import { withRouter } from "react-router";
|
||||
import QRCode from "qrcode-react";
|
||||
import {Brightness3, ListAlt, PermContactCalendar} from "@material-ui/icons";
|
||||
import { Brightness3, ListAlt, PermContactCalendar } from "@material-ui/icons";
|
||||
import { transformTime } from "../../utils";
|
||||
import Authn from "./Authn";
|
||||
|
||||
|
|
@ -136,18 +141,18 @@ const styles = theme => ({
|
|||
paddingText: {
|
||||
paddingRight: theme.spacing(2)
|
||||
},
|
||||
qrcode:{
|
||||
qrcode: {
|
||||
width: 128,
|
||||
marginTop: 16,
|
||||
marginRight: 16,
|
||||
},
|
||||
marginRight: 16
|
||||
}
|
||||
});
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
title: state.siteConfig.title,
|
||||
authn:state.siteConfig.authn,
|
||||
viewMethod: state.viewUpdate.explorerViewMethod,
|
||||
authn: state.siteConfig.authn,
|
||||
viewMethod: state.viewUpdate.explorerViewMethod
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -156,15 +161,15 @@ const mapDispatchToProps = dispatch => {
|
|||
toggleSnackbar: (vertical, horizontal, msg, color) => {
|
||||
dispatch(toggleSnackbar(vertical, horizontal, msg, color));
|
||||
},
|
||||
applyThemes: (color) => {
|
||||
applyThemes: color => {
|
||||
dispatch(applyThemes(color));
|
||||
},
|
||||
toggleDaylightMode:()=>{
|
||||
dispatch(toggleDaylightMode())
|
||||
toggleDaylightMode: () => {
|
||||
dispatch(toggleDaylightMode());
|
||||
},
|
||||
changeView: method => {
|
||||
dispatch(changeViewMethod(method));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -208,7 +213,7 @@ class UserSettingCompoment extends Component {
|
|||
two_fa_secret: "",
|
||||
prefer_theme: "",
|
||||
themes: {},
|
||||
authn:[],
|
||||
authn: []
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -432,10 +437,9 @@ class UserSettingCompoment extends Component {
|
|||
this.setState({
|
||||
loading: "changeTheme"
|
||||
});
|
||||
API
|
||||
.patch("/user/setting/theme", {
|
||||
theme: this.state.chosenTheme
|
||||
})
|
||||
API.patch("/user/setting/theme", {
|
||||
theme: this.state.chosenTheme
|
||||
})
|
||||
.then(() => {
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
|
|
@ -507,7 +511,7 @@ class UserSettingCompoment extends Component {
|
|||
};
|
||||
|
||||
init2FA = () => {
|
||||
if (this.state.settings.two_factor){
|
||||
if (this.state.settings.two_factor) {
|
||||
this.setState({ twoFactor: true });
|
||||
return;
|
||||
}
|
||||
|
|
@ -515,7 +519,7 @@ class UserSettingCompoment extends Component {
|
|||
.then(response => {
|
||||
this.setState({
|
||||
two_fa_secret: response.data,
|
||||
twoFactor: true,
|
||||
twoFactor: true
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
|
|
@ -533,8 +537,8 @@ class UserSettingCompoment extends Component {
|
|||
loading: "twoFactor"
|
||||
});
|
||||
API.patch("/user/setting/2fa", {
|
||||
code: this.state.authCode
|
||||
})
|
||||
code: this.state.authCode
|
||||
})
|
||||
.then(() => {
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
|
|
@ -544,9 +548,9 @@ class UserSettingCompoment extends Component {
|
|||
);
|
||||
this.setState({
|
||||
loading: "",
|
||||
settings:{
|
||||
settings: {
|
||||
...this.state.settings,
|
||||
two_factor:!this.state.settings.two_factor,
|
||||
two_factor: !this.state.settings.two_factor
|
||||
}
|
||||
});
|
||||
this.handleClose();
|
||||
|
|
@ -570,17 +574,17 @@ class UserSettingCompoment extends Component {
|
|||
|
||||
handleAlignment = (event, chosenTheme) => this.setState({ chosenTheme });
|
||||
|
||||
toggleThemeMode = (current) => {
|
||||
if (current !== null){
|
||||
toggleThemeMode = current => {
|
||||
if (current !== null) {
|
||||
this.props.toggleDaylightMode();
|
||||
Auth.SetPreference("theme_mode",null);
|
||||
Auth.SetPreference("theme_mode", null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
const user = Auth.GetUser();
|
||||
const dark = Auth.GetPreference("theme_mode")
|
||||
const dark = Auth.GetPreference("theme_mode");
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
|
@ -675,9 +679,7 @@ class UserSettingCompoment extends Component {
|
|||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
<Divider />
|
||||
<ListItem
|
||||
button
|
||||
>
|
||||
<ListItem button>
|
||||
<ListItemIcon className={classes.iconFix}>
|
||||
<GroupIcon />
|
||||
</ListItemIcon>
|
||||
|
|
@ -779,30 +781,29 @@ class UserSettingCompoment extends Component {
|
|||
|
||||
<Authn
|
||||
list={this.state.settings.authn}
|
||||
add = {
|
||||
(credential)=>{
|
||||
this.setState({
|
||||
settings:{
|
||||
...this.state.settings,
|
||||
authn: [...this.state.settings.authn,credential],
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
remove={
|
||||
(id)=>{
|
||||
let credentials = [...this.state.settings.authn];
|
||||
credentials = credentials.filter((v)=>{
|
||||
return v.id !== id
|
||||
})
|
||||
this.setState({
|
||||
settings:{
|
||||
...this.state.settings,
|
||||
authn: credentials,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
add={credential => {
|
||||
this.setState({
|
||||
settings: {
|
||||
...this.state.settings,
|
||||
authn: [
|
||||
...this.state.settings.authn,
|
||||
credential
|
||||
]
|
||||
}
|
||||
});
|
||||
}}
|
||||
remove={id => {
|
||||
let credentials = [...this.state.settings.authn];
|
||||
credentials = credentials.filter(v => {
|
||||
return v.id !== id;
|
||||
});
|
||||
this.setState({
|
||||
settings: {
|
||||
...this.state.settings,
|
||||
authn: credentials
|
||||
}
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
<Typography
|
||||
|
|
@ -831,8 +832,11 @@ class UserSettingCompoment extends Component {
|
|||
<div className={classes.secondColor}></div>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
<Divider/>
|
||||
<ListItem button onClick={()=>this.toggleThemeMode(dark)}>
|
||||
<Divider />
|
||||
<ListItem
|
||||
button
|
||||
onClick={() => this.toggleThemeMode(dark)}
|
||||
>
|
||||
<ListItemIcon className={classes.iconFix}>
|
||||
<Brightness3 />
|
||||
</ListItemIcon>
|
||||
|
|
@ -845,18 +849,22 @@ class UserSettingCompoment extends Component {
|
|||
className={classes.infoTextWithIcon}
|
||||
color="textSecondary"
|
||||
>
|
||||
{dark&&(dark==="dark"
|
||||
? "偏好开启"
|
||||
: "偏好关闭")}
|
||||
{dark === null&&"跟随系统"}
|
||||
{dark &&
|
||||
(dark === "dark"
|
||||
? "偏好开启"
|
||||
: "偏好关闭")}
|
||||
{dark === null && "跟随系统"}
|
||||
</Typography>
|
||||
<RightIcon
|
||||
className={classes.rightIconWithText}
|
||||
/>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
<Divider/>
|
||||
<ListItem button onClick={()=>this.toggleViewMethod()}>
|
||||
<Divider />
|
||||
<ListItem
|
||||
button
|
||||
onClick={() => this.toggleViewMethod()}
|
||||
>
|
||||
<ListItemIcon className={classes.iconFix}>
|
||||
<ListAlt />
|
||||
</ListItemIcon>
|
||||
|
|
@ -869,9 +877,12 @@ class UserSettingCompoment extends Component {
|
|||
className={classes.infoTextWithIcon}
|
||||
color="textSecondary"
|
||||
>
|
||||
{this.props.viewMethod === "icon" && "大图标"}
|
||||
{this.props.viewMethod === "list" && "列表"}
|
||||
{this.props.viewMethod === "smallIcon" && "小图标"}
|
||||
{this.props.viewMethod === "icon" &&
|
||||
"大图标"}
|
||||
{this.props.viewMethod === "list" &&
|
||||
"列表"}
|
||||
{this.props.viewMethod ===
|
||||
"smallIcon" && "小图标"}
|
||||
</Typography>
|
||||
<RightIcon
|
||||
className={classes.rightIconWithText}
|
||||
|
|
@ -1101,26 +1112,36 @@ class UserSettingCompoment extends Component {
|
|||
</DialogActions>
|
||||
</Dialog>
|
||||
<Dialog open={this.state.twoFactor} onClose={this.handleClose}>
|
||||
<DialogTitle>{this.state.settings.two_factor?"关闭":"启用"}二步验证</DialogTitle>
|
||||
<DialogTitle>
|
||||
{this.state.settings.two_factor ? "关闭" : "启用"}
|
||||
二步验证
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<div className={classes.flexContainerResponse}>
|
||||
|
||||
{!this.state.settings.two_factor && <div className={classes.qrcode}><QRCode
|
||||
value={
|
||||
"otpauth://totp/" +
|
||||
this.props.title +
|
||||
"?secret=" +
|
||||
this.state.two_fa_secret
|
||||
}
|
||||
/></div>}
|
||||
{!this.state.settings.two_factor && (
|
||||
<div className={classes.qrcode}>
|
||||
<QRCode
|
||||
value={
|
||||
"otpauth://totp/" +
|
||||
this.props.title +
|
||||
"?secret=" +
|
||||
this.state.two_fa_secret
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className={classes.desText}>
|
||||
{!this.state.settings.two_factor && <Typography>
|
||||
请使用任意二步验证APP或者支持二步验证的密码管理软件扫描左侧二维码添加本站。扫描完成后请填写二步验证APP给出的6位验证码以开启二步验证。
|
||||
</Typography>}
|
||||
{this.state.settings.two_factor && <Typography>
|
||||
请验证当前二步验证代码。
|
||||
</Typography>}
|
||||
{!this.state.settings.two_factor && (
|
||||
<Typography>
|
||||
请使用任意二步验证APP或者支持二步验证的密码管理软件扫描左侧二维码添加本站。扫描完成后请填写二步验证APP给出的6位验证码以开启二步验证。
|
||||
</Typography>
|
||||
)}
|
||||
{this.state.settings.two_factor && (
|
||||
<Typography>
|
||||
请验证当前二步验证代码。
|
||||
</Typography>
|
||||
)}
|
||||
<TextField
|
||||
id="standard-name"
|
||||
label="6位验证码"
|
||||
|
|
@ -1147,7 +1168,8 @@ class UserSettingCompoment extends Component {
|
|||
this.state.authCode === ""
|
||||
}
|
||||
>
|
||||
{this.state.settings.two_factor?"关闭":"启用"}二步验证
|
||||
{this.state.settings.two_factor ? "关闭" : "启用"}
|
||||
二步验证
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
|
|
@ -1199,10 +1221,7 @@ class UserSettingCompoment extends Component {
|
|||
<TextField
|
||||
id="standard-name"
|
||||
className={classes.textField}
|
||||
value={
|
||||
window.location.origin +
|
||||
"/dav"
|
||||
}
|
||||
value={window.location.origin + "/dav"}
|
||||
margin="normal"
|
||||
autoFocus
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -58,8 +58,8 @@ export default function WebDAV() {
|
|||
dispatch(toggleSnackbar(vertical, horizontal, msg, color)),
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const loadList = () =>{
|
||||
|
||||
const loadList = () => {
|
||||
API.get("/webdav/accounts")
|
||||
.then(response => {
|
||||
setAccounts(response.data.accounts);
|
||||
|
|
@ -67,10 +67,10 @@ export default function WebDAV() {
|
|||
.catch(error => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
});
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
loadList();
|
||||
// eslint-disable-next-line
|
||||
loadList();
|
||||
// eslint-disable-next-line
|
||||
}, []);
|
||||
|
||||
const deleteAccount = id => {
|
||||
|
|
@ -138,7 +138,9 @@ export default function WebDAV() {
|
|||
{tab === 0 && (
|
||||
<div>
|
||||
<Alert severity="info">
|
||||
WebDAV的地址为:{window.location.origin + "/dav"};登陆用户名统一为:{user.user_name}{" "}
|
||||
WebDAV的地址为:
|
||||
{window.location.origin + "/dav"}
|
||||
;登陆用户名统一为:{user.user_name}{" "}
|
||||
;密码为所创建账号的密码。
|
||||
</Alert>
|
||||
<TableContainer className={classes.tableContainer}>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import {
|
|||
TextField,
|
||||
Avatar
|
||||
} from "@material-ui/core";
|
||||
import { withRouter} from "react-router";
|
||||
import { withRouter } from "react-router";
|
||||
|
||||
const styles = theme => ({
|
||||
card: {
|
||||
|
|
@ -57,9 +57,8 @@ class LockedFileCompoment extends Component {
|
|||
super(props);
|
||||
const query = new URLSearchParams(this.props.location.search);
|
||||
this.state = {
|
||||
pwd: query.get("password"),
|
||||
pwd: query.get("password")
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
handleChange = name => event => {
|
||||
|
|
@ -85,7 +84,9 @@ class LockedFileCompoment extends Component {
|
|||
<Avatar
|
||||
aria-label="Recipe"
|
||||
src={
|
||||
"/api/v3/user/avatar/"+this.props.share.creator.key + "/l"
|
||||
"/api/v3/user/avatar/" +
|
||||
this.props.share.creator.key +
|
||||
"/l"
|
||||
}
|
||||
/>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ import { VisibilityOff, VpnKey } from "@material-ui/icons";
|
|||
import Select from "@material-ui/core/Select";
|
||||
import MenuItem from "@material-ui/core/MenuItem";
|
||||
import FormControl from "@material-ui/core/FormControl";
|
||||
import {withRouter} from "react-router-dom";
|
||||
import { withRouter } from "react-router-dom";
|
||||
|
||||
const styles = theme => ({
|
||||
cardContainer: {
|
||||
|
|
@ -79,9 +79,9 @@ const styles = theme => ({
|
|||
marginLeft: theme.spacing(1),
|
||||
height: 17
|
||||
},
|
||||
orderSelect:{
|
||||
textAlign:"right",
|
||||
marginTop: 5,
|
||||
orderSelect: {
|
||||
textAlign: "right",
|
||||
marginTop: 5
|
||||
}
|
||||
});
|
||||
const mapStateToProps = () => {
|
||||
|
|
@ -102,11 +102,11 @@ class MyShareCompoment extends Component {
|
|||
total: 0,
|
||||
shareList: [],
|
||||
showPwd: null,
|
||||
orderBy:"created_at DESC",
|
||||
orderBy: "created_at DESC"
|
||||
};
|
||||
|
||||
componentDidMount = () => {
|
||||
this.loadList(1,this.state.orderBy);
|
||||
this.loadList(1, this.state.orderBy);
|
||||
};
|
||||
|
||||
showPwd = pwd => {
|
||||
|
|
@ -117,31 +117,34 @@ class MyShareCompoment extends Component {
|
|||
this.setState({ showPwd: null });
|
||||
};
|
||||
|
||||
removeShare = (id) => {
|
||||
API
|
||||
.delete("/share/"+id)
|
||||
removeShare = id => {
|
||||
API.delete("/share/" + id)
|
||||
.then(() => {
|
||||
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);
|
||||
}
|
||||
|
||||
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");
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
error.message,
|
||||
"error"
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -154,11 +157,10 @@ class MyShareCompoment extends Component {
|
|||
const shareIndex = oldList.findIndex(value => {
|
||||
return value.key === id;
|
||||
});
|
||||
API
|
||||
.patch("/share/"+id, {
|
||||
prop:"password",
|
||||
value:oldList[shareIndex].password === "" ? newPwd : "",
|
||||
})
|
||||
API.patch("/share/" + id, {
|
||||
prop: "password",
|
||||
value: oldList[shareIndex].password === "" ? newPwd : ""
|
||||
})
|
||||
.then(response => {
|
||||
oldList[shareIndex].password = response.data;
|
||||
this.setState({
|
||||
|
|
@ -166,7 +168,12 @@ class MyShareCompoment extends Component {
|
|||
});
|
||||
})
|
||||
.catch(error => {
|
||||
this.props.toggleSnackbar("top", "right", error.message, "error");
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
error.message,
|
||||
"error"
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -175,11 +182,10 @@ class MyShareCompoment extends Component {
|
|||
const shareIndex = oldList.findIndex(value => {
|
||||
return value.key === id;
|
||||
});
|
||||
API
|
||||
.patch("/share/"+id, {
|
||||
prop:"preview_enabled",
|
||||
value:oldList[shareIndex].preview?"false":"true",
|
||||
})
|
||||
API.patch("/share/" + id, {
|
||||
prop: "preview_enabled",
|
||||
value: oldList[shareIndex].preview ? "false" : "true"
|
||||
})
|
||||
.then(response => {
|
||||
oldList[shareIndex].preview = response.data;
|
||||
this.setState({
|
||||
|
|
@ -187,13 +193,25 @@ class MyShareCompoment extends Component {
|
|||
});
|
||||
})
|
||||
.catch(error => {
|
||||
this.props.toggleSnackbar("top", "right", error.message, "error");
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
error.message,
|
||||
"error"
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
loadList = (page,orderBy) => {
|
||||
loadList = (page, orderBy) => {
|
||||
const order = orderBy.split(" ");
|
||||
API.get("/share?page=" + page + "&order_by=" + order[0] + "&order=" + order[1])
|
||||
API.get(
|
||||
"/share?page=" +
|
||||
page +
|
||||
"&order_by=" +
|
||||
order[0] +
|
||||
"&order=" +
|
||||
order[1]
|
||||
)
|
||||
.then(response => {
|
||||
if (response.data.items.length === 0) {
|
||||
this.props.toggleSnackbar(
|
||||
|
|
@ -217,14 +235,14 @@ class MyShareCompoment extends Component {
|
|||
this.setState({
|
||||
page: value
|
||||
});
|
||||
this.loadList(value,this.state.orderBy);
|
||||
this.loadList(value, this.state.orderBy);
|
||||
};
|
||||
|
||||
handleOrderChange = event => {
|
||||
handleOrderChange = event => {
|
||||
this.setState({
|
||||
orderBy:event.target.value,
|
||||
orderBy: event.target.value
|
||||
});
|
||||
this.loadList(this.state.page,event.target.value);
|
||||
this.loadList(this.state.page, event.target.value);
|
||||
};
|
||||
|
||||
isExpired = share => {
|
||||
|
|
@ -239,19 +257,34 @@ class MyShareCompoment extends Component {
|
|||
<Grid container>
|
||||
<Grid sm={6} xs={6}>
|
||||
<Typography color="textSecondary" variant="h4">
|
||||
|
||||
我的分享
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid sm={6} xs={6} className={classes.orderSelect}>
|
||||
<FormControl>
|
||||
<Select color={"secondary"} onChange={this.handleOrderChange} value={this.state.orderBy}>
|
||||
<MenuItem value={"created_at DESC"}>创建日期由晚到早</MenuItem>
|
||||
<MenuItem value={"created_at ASC"}>创建日期由早到晚</MenuItem>
|
||||
<MenuItem value={"downloads DESC"}>下载次数由大到小</MenuItem>
|
||||
<MenuItem value={"downloads ASC"}>下载次数由小到大</MenuItem>
|
||||
<MenuItem value={"views DESC"}>浏览次数由大到小</MenuItem>
|
||||
<MenuItem value={"views ASC"}>浏览次数由小到大</MenuItem>
|
||||
<Select
|
||||
color={"secondary"}
|
||||
onChange={this.handleOrderChange}
|
||||
value={this.state.orderBy}
|
||||
>
|
||||
<MenuItem value={"created_at DESC"}>
|
||||
创建日期由晚到早
|
||||
</MenuItem>
|
||||
<MenuItem value={"created_at ASC"}>
|
||||
创建日期由早到晚
|
||||
</MenuItem>
|
||||
<MenuItem value={"downloads DESC"}>
|
||||
下载次数由大到小
|
||||
</MenuItem>
|
||||
<MenuItem value={"downloads ASC"}>
|
||||
下载次数由小到大
|
||||
</MenuItem>
|
||||
<MenuItem value={"views DESC"}>
|
||||
浏览次数由大到小
|
||||
</MenuItem>
|
||||
<MenuItem value={"views ASC"}>
|
||||
浏览次数由小到大
|
||||
</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
|
|
@ -333,7 +366,14 @@ class MyShareCompoment extends Component {
|
|||
<Tooltip placement="top" title="打开">
|
||||
<IconButton
|
||||
onClick={() =>
|
||||
this.props.history.push("/s/"+value.key + (value.password === "" ?"":"?password=" + value.password))
|
||||
this.props.history.push(
|
||||
"/s/" +
|
||||
value.key +
|
||||
(value.password === ""
|
||||
? ""
|
||||
: "?password=" +
|
||||
value.password)
|
||||
)
|
||||
}
|
||||
>
|
||||
<OpenIcon />
|
||||
|
|
@ -358,9 +398,7 @@ class MyShareCompoment extends Component {
|
|||
placement="top"
|
||||
title="查看密码"
|
||||
onClick={() =>
|
||||
this.showPwd(
|
||||
value.password
|
||||
)
|
||||
this.showPwd(value.password)
|
||||
}
|
||||
>
|
||||
<IconButton>
|
||||
|
|
@ -374,9 +412,7 @@ class MyShareCompoment extends Component {
|
|||
placement="top"
|
||||
title="变更为私密分享"
|
||||
onClick={() =>
|
||||
this.changePermission(
|
||||
value.key
|
||||
)
|
||||
this.changePermission(value.key)
|
||||
}
|
||||
>
|
||||
<IconButton>
|
||||
|
|
@ -392,9 +428,7 @@ class MyShareCompoment extends Component {
|
|||
: "允许预览"
|
||||
}
|
||||
onClick={() =>
|
||||
this.changePreviewOption(
|
||||
value.key
|
||||
)
|
||||
this.changePreviewOption(value.key)
|
||||
}
|
||||
>
|
||||
<IconButton>
|
||||
|
|
@ -423,10 +457,10 @@ class MyShareCompoment extends Component {
|
|||
</Grid>
|
||||
<div className={classes.loadMore}>
|
||||
<Pagination
|
||||
count={Math.ceil(this.state.total / 18)}
|
||||
onChange={this.handlePageChange}
|
||||
color="secondary"
|
||||
/>
|
||||
count={Math.ceil(this.state.total / 18)}
|
||||
onChange={this.handlePageChange}
|
||||
color="secondary"
|
||||
/>
|
||||
</div>{" "}
|
||||
<Dialog
|
||||
open={this.state.showPwd !== null}
|
||||
|
|
|
|||
|
|
@ -1,35 +1,32 @@
|
|||
import React from "react";
|
||||
import SentimentVeryDissatisfiedIcon from '@material-ui/icons/SentimentVeryDissatisfied';
|
||||
import {lighten, makeStyles} from "@material-ui/core/styles";
|
||||
import SentimentVeryDissatisfiedIcon from "@material-ui/icons/SentimentVeryDissatisfied";
|
||||
import { lighten, makeStyles } from "@material-ui/core/styles";
|
||||
|
||||
const useStyles = makeStyles(theme=>({
|
||||
icon:{
|
||||
fontSize: "160px",
|
||||
const useStyles = makeStyles(theme => ({
|
||||
icon: {
|
||||
fontSize: "160px"
|
||||
},
|
||||
emptyContainer: {
|
||||
bottom: "0",
|
||||
height: "300px",
|
||||
margin: "50px auto",
|
||||
width: "300px",
|
||||
color: lighten(theme.palette.text.disabled,0.4),
|
||||
color: lighten(theme.palette.text.disabled, 0.4),
|
||||
textAlign: "center",
|
||||
paddingTop: "20px"
|
||||
},
|
||||
emptyInfoBig: {
|
||||
fontSize: "25px",
|
||||
color: lighten(theme.palette.text.disabled,0.4),
|
||||
},
|
||||
color: lighten(theme.palette.text.disabled, 0.4)
|
||||
}
|
||||
}));
|
||||
|
||||
export default function Notice(props) {
|
||||
const classes = useStyles();
|
||||
return (
|
||||
<div className={classes.emptyContainer}>
|
||||
<SentimentVeryDissatisfiedIcon className={classes.icon}/>
|
||||
<div className={classes.emptyInfoBig}>
|
||||
{props.msg}
|
||||
</div>
|
||||
<SentimentVeryDissatisfiedIcon className={classes.icon} />
|
||||
<div className={classes.emptyInfoBig}>{props.msg}</div>
|
||||
</div>
|
||||
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { makeStyles, useTheme } from "@material-ui/core/styles";
|
||||
import { makeStyles, useTheme } from "@material-ui/core/styles";
|
||||
import { MenuBook } from "@material-ui/icons";
|
||||
import { Typography } from "@material-ui/core";
|
||||
import Divider from "@material-ui/core/Divider";
|
||||
|
|
@ -14,8 +14,8 @@ const useStyles = makeStyles(theme => ({
|
|||
readMeContainer: {
|
||||
marginTop: 30,
|
||||
[theme.breakpoints.down("sm")]: {
|
||||
marginTop: theme.spacing(2),
|
||||
},
|
||||
marginTop: theme.spacing(2)
|
||||
}
|
||||
},
|
||||
readMeHeader: {
|
||||
padding: "10px 16px",
|
||||
|
|
@ -44,18 +44,24 @@ const useStyles = makeStyles(theme => ({
|
|||
},
|
||||
".for-container .for-markdown-preview pre": {
|
||||
backgroundColor: theme.palette.background.default + "!important",
|
||||
color: theme.palette.type ==="dark"?"#fff !important":"rgba(0, 0, 0, 0.87);!important",
|
||||
color:
|
||||
theme.palette.type === "dark"
|
||||
? "#fff !important"
|
||||
: "rgba(0, 0, 0, 0.87);!important"
|
||||
},
|
||||
|
||||
".for-container .for-markdown-preview code": {
|
||||
backgroundColor: theme.palette.background.default + "!important"
|
||||
},
|
||||
".for-container .for-markdown-preview a": {
|
||||
color: theme.palette.type==="dark"?"#67aeff !important":"#0366d6 !important",
|
||||
},
|
||||
".for-container .for-markdown-preview table th":{
|
||||
backgroundColor: theme.palette.background.default + "!important",
|
||||
color:
|
||||
theme.palette.type === "dark"
|
||||
? "#67aeff !important"
|
||||
: "#0366d6 !important"
|
||||
},
|
||||
".for-container .for-markdown-preview table th": {
|
||||
backgroundColor: theme.palette.background.default + "!important"
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { toggleSnackbar } from "../../actions";
|
||||
import OpenIcon from "@material-ui/icons/OpenInNew";
|
||||
import Pagination from "@material-ui/lab/Pagination";
|
||||
|
|
@ -12,14 +12,14 @@ import {
|
|||
CardHeader,
|
||||
Typography,
|
||||
Grid,
|
||||
IconButton,
|
||||
IconButton
|
||||
} from "@material-ui/core";
|
||||
import API from "../../middleware/Api";
|
||||
import TypeIcon from "../FileManager/TypeIcon";
|
||||
import Select from "@material-ui/core/Select";
|
||||
import MenuItem from "@material-ui/core/MenuItem";
|
||||
import FormControl from "@material-ui/core/FormControl";
|
||||
import {useHistory} from "react-router-dom";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import { useLocation } from "react-router";
|
||||
import TimeAgo from "timeago-react";
|
||||
|
|
@ -126,13 +126,13 @@ export default function SearchResult() {
|
|||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const keywords = query.get("keywords");
|
||||
if (keywords) {
|
||||
search(keywords, page, orderBy);
|
||||
} else {
|
||||
ToggleSnackbar("top", "right", "请输入搜索关键词", "warning");
|
||||
}
|
||||
}, [location]);
|
||||
const keywords = query.get("keywords");
|
||||
if (keywords) {
|
||||
search(keywords, page, orderBy);
|
||||
} else {
|
||||
ToggleSnackbar("top", "right", "请输入搜索关键词", "warning");
|
||||
}
|
||||
}, [location]);
|
||||
|
||||
const handlePageChange = (event, value) => {
|
||||
setPage(value);
|
||||
|
|
@ -219,10 +219,7 @@ export default function SearchResult() {
|
|||
<Tooltip placement="top" title="打开">
|
||||
<IconButton
|
||||
onClick={() =>
|
||||
history.push(
|
||||
"/s/" +
|
||||
value.key
|
||||
)
|
||||
history.push("/s/" + value.key)
|
||||
}
|
||||
>
|
||||
<OpenIcon />
|
||||
|
|
@ -248,10 +245,15 @@ export default function SearchResult() {
|
|||
</Typography>
|
||||
</Tooltip>
|
||||
}
|
||||
subheader={<span>分享于{" "}<TimeAgo
|
||||
datetime={value.create_date}
|
||||
locale="zh_CN"
|
||||
/></span>}
|
||||
subheader={
|
||||
<span>
|
||||
分享于{" "}
|
||||
<TimeAgo
|
||||
datetime={value.create_date}
|
||||
locale="zh_CN"
|
||||
/>
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
</Card>
|
||||
</Grid>
|
||||
|
|
|
|||
|
|
@ -41,12 +41,12 @@ export default function SharePreload() {
|
|||
} else {
|
||||
SetSubTitle();
|
||||
}
|
||||
}, [share,SetSubTitle,ToggleSnackbar]);
|
||||
}, [share, SetSubTitle, ToggleSnackbar]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
SetSubTitle();
|
||||
}
|
||||
};
|
||||
// eslint-disable-next-line
|
||||
}, []);
|
||||
|
||||
|
|
@ -69,12 +69,12 @@ export default function SharePreload() {
|
|||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
}
|
||||
});
|
||||
}, [id, password,ToggleSnackbar]);
|
||||
}, [id, password, ToggleSnackbar]);
|
||||
|
||||
return (
|
||||
<Suspense fallback={<PageLoading />}>
|
||||
{share === undefined && <PageLoading />}
|
||||
{share === null && <Notice msg={"分享不存在或已过期"}/>}
|
||||
{share === null && <Notice msg={"分享不存在或已过期"} />}
|
||||
{share && share.locked && (
|
||||
<LockedFile
|
||||
loading={loading}
|
||||
|
|
@ -82,8 +82,12 @@ export default function SharePreload() {
|
|||
share={share}
|
||||
/>
|
||||
)}
|
||||
{share&&!share.locked&&!share.is_dir&&<SharedFile share={share}/>}
|
||||
{share&&!share.locked&&share.is_dir&&<SharedFolder share={share}/>}
|
||||
{share && !share.locked && !share.is_dir && (
|
||||
<SharedFile share={share} />
|
||||
)}
|
||||
{share && !share.locked && share.is_dir && (
|
||||
<SharedFolder share={share} />
|
||||
)}
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ import React, { Component } from "react";
|
|||
import { connect } from "react-redux";
|
||||
import { sizeToString, vhCheck } from "../../utils";
|
||||
import {
|
||||
openMusicDialog, openResaveDialog,
|
||||
openMusicDialog,
|
||||
openResaveDialog,
|
||||
setSelectedTarget,
|
||||
showImgPreivew,
|
||||
toggleSnackbar
|
||||
|
|
@ -17,8 +18,7 @@ import { withRouter } from "react-router-dom";
|
|||
import Creator from "./Creator";
|
||||
import pathHelper from "../../utils/page";
|
||||
|
||||
|
||||
vhCheck()
|
||||
vhCheck();
|
||||
const styles = theme => ({
|
||||
layout: {
|
||||
width: "auto",
|
||||
|
|
@ -113,9 +113,9 @@ const mapDispatchToProps = dispatch => {
|
|||
showImgPreivew: first => {
|
||||
dispatch(showImgPreivew(first));
|
||||
},
|
||||
openResave: (key) => {
|
||||
openResave: key => {
|
||||
dispatch(openResaveDialog(key));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -156,8 +156,8 @@ class SharedFileCompoment extends Component {
|
|||
case "msDoc":
|
||||
this.props.history.push(
|
||||
this.props.share.key +
|
||||
"/doc?name=" +
|
||||
encodeURIComponent(this.props.share.source.name)
|
||||
"/doc?name=" +
|
||||
encodeURIComponent(this.props.share.source.name)
|
||||
);
|
||||
return;
|
||||
case "audio":
|
||||
|
|
@ -177,20 +177,26 @@ class SharedFileCompoment extends Component {
|
|||
);
|
||||
return;
|
||||
case "edit":
|
||||
this.props.history.push(this.props.share.key +
|
||||
"/text?name=" +
|
||||
encodeURIComponent(this.props.share.source.name));
|
||||
return
|
||||
this.props.history.push(
|
||||
this.props.share.key +
|
||||
"/text?name=" +
|
||||
encodeURIComponent(this.props.share.source.name)
|
||||
);
|
||||
return;
|
||||
case "pdf":
|
||||
this.props.history.push(this.props.share.key +
|
||||
"/pdf?name=" +
|
||||
encodeURIComponent(this.props.share.source.name));
|
||||
return
|
||||
this.props.history.push(
|
||||
this.props.share.key +
|
||||
"/pdf?name=" +
|
||||
encodeURIComponent(this.props.share.source.name)
|
||||
);
|
||||
return;
|
||||
case "code":
|
||||
this.props.history.push(this.props.share.key +
|
||||
"/code?name=" +
|
||||
encodeURIComponent(this.props.share.source.name));
|
||||
return
|
||||
this.props.history.push(
|
||||
this.props.share.key +
|
||||
"/code?name=" +
|
||||
encodeURIComponent(this.props.share.source.name)
|
||||
);
|
||||
return;
|
||||
default:
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
|
|
@ -237,7 +243,7 @@ class SharedFileCompoment extends Component {
|
|||
<Modals />
|
||||
<ImgPreview />
|
||||
<div className={classes.box}>
|
||||
<Creator share={this.props.share}/>
|
||||
<Creator share={this.props.share} />
|
||||
<Divider />
|
||||
<div className={classes.boxContent}>
|
||||
<TypeIcon
|
||||
|
|
@ -258,18 +264,17 @@ class SharedFileCompoment extends Component {
|
|||
<div className={classes.boxFooter}>
|
||||
<div className={classes.actionLeft}>
|
||||
{this.props.share.preview && (
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
onClick={this.scoreHandle(this.preview)}
|
||||
disabled={this.state.loading}
|
||||
>
|
||||
预览
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
onClick={this.scoreHandle(this.preview)}
|
||||
disabled={this.state.loading}
|
||||
>
|
||||
预览
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
<div className={classes.actions}>
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
|
|
|
|||
|
|
@ -71,8 +71,8 @@ const styles = theme => ({
|
|||
left: 0,
|
||||
top: 0
|
||||
},
|
||||
fileName:{
|
||||
wordBreak: "break-all",
|
||||
fileName: {
|
||||
wordBreak: "break-all"
|
||||
}
|
||||
});
|
||||
class FileList extends Component {
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
// import React from 'react'
|
||||
// import React from 'react'
|
||||
|
|
|
|||
|
|
@ -40,10 +40,10 @@ const useStyles = makeStyles(theme => ({
|
|||
}
|
||||
},
|
||||
formControl: {
|
||||
margin: "8px 16px 8px 16px",
|
||||
margin: "8px 16px 8px 16px"
|
||||
},
|
||||
toobar:{
|
||||
textAlign:"right",
|
||||
toobar: {
|
||||
textAlign: "right"
|
||||
}
|
||||
}));
|
||||
|
||||
|
|
@ -145,9 +145,11 @@ export default function CodeViewer() {
|
|||
onChange={e => setSuffix(e.target.value)}
|
||||
>
|
||||
{Array.from(
|
||||
new Set(Object.keys(codePreviewSuffix).map(k=>{
|
||||
return codePreviewSuffix[k]
|
||||
}))
|
||||
new Set(
|
||||
Object.keys(codePreviewSuffix).map(k => {
|
||||
return codePreviewSuffix[k];
|
||||
})
|
||||
)
|
||||
).map((extension, index) => (
|
||||
<MenuItem value={extension} key={index}>
|
||||
{extension}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue