mirror of
https://github.com/cloudreve/frontend.git
synced 2025-12-25 19:52:48 +00:00
离线下载管理
This commit is contained in:
parent
0589187157
commit
8dfb7fa8d0
|
|
@ -25,7 +25,8 @@
|
|||
"react-router": "^5.1.2",
|
||||
"react-router-dom": "^5.1.2",
|
||||
"react-scripts": "3.2.0",
|
||||
"redux": "^4.0.4"
|
||||
"redux": "^4.0.4",
|
||||
"timeago-react": "^3.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import PageLoading from "./component/Placeholder/PageLoading.js"
|
|||
import TextViewer from "./component/Viewer/Text";
|
||||
import DocViewer from "./component/Viewer/Doc";
|
||||
import SharePreload from "./component/Share/SharePreload";
|
||||
import Download from "./component/Download/Download";
|
||||
|
||||
// Lazy loads
|
||||
const LoginForm = React.lazy(() => import("./component/Login/LoginForm"));
|
||||
|
|
@ -93,6 +94,12 @@ export default function App() {
|
|||
</Suspense>
|
||||
</AuthRoute>
|
||||
|
||||
<AuthRoute path={`${path}aria2`} isLogin={isLogin}>
|
||||
<Suspense fallback={<PageLoading/>}>
|
||||
<Download />
|
||||
</Suspense>
|
||||
</AuthRoute>
|
||||
|
||||
<Route path={`${path}login`}>
|
||||
<Suspense fallback={<PageLoading/>}>
|
||||
<LoginForm />
|
||||
|
|
|
|||
|
|
@ -17,11 +17,11 @@ import {
|
|||
WindowRestore,
|
||||
Android
|
||||
} from "mdi-material-ui";
|
||||
import { toggleSnackbar } from "../actions/index";
|
||||
import { toggleSnackbar } from "../../actions";
|
||||
import axios from "axios";
|
||||
import { sizeToString } from "../untils/index";
|
||||
import { mediaType } from "../config";
|
||||
|
||||
import { sizeToString } from "../../untils";
|
||||
import { mediaType } from "../../config";
|
||||
import API, { baseURL } from "../../middleware/Api";
|
||||
import {
|
||||
withStyles,
|
||||
Card,
|
||||
|
|
@ -31,13 +31,9 @@ import {
|
|||
Button,
|
||||
IconButton
|
||||
} from "@material-ui/core";
|
||||
import DownloadingCard from "./DownloadingCard";
|
||||
|
||||
const styles = theme => ({
|
||||
card: {
|
||||
marginTop: "20px",
|
||||
display: "flex",
|
||||
justifyContent: "space-between"
|
||||
},
|
||||
actions: {
|
||||
display: "flex"
|
||||
},
|
||||
|
|
@ -67,28 +63,6 @@ const styles = theme => ({
|
|||
gird: {
|
||||
marginTop: "30px"
|
||||
},
|
||||
iconContainer: {
|
||||
width: "90px",
|
||||
height: "90px",
|
||||
padding: "29px",
|
||||
marginTop: "6px",
|
||||
paddingLeft: "35px",
|
||||
[theme.breakpoints.down("md")]: {
|
||||
display: "none"
|
||||
}
|
||||
},
|
||||
content: {
|
||||
width: "100%",
|
||||
minWidth: 0
|
||||
},
|
||||
contentSide: {
|
||||
minWidth: 0,
|
||||
paddingTop: "24px",
|
||||
paddingRight: "28px",
|
||||
[theme.breakpoints.down("md")]: {
|
||||
display: "none"
|
||||
}
|
||||
},
|
||||
iconImgBig: {
|
||||
color: "#d32f2f",
|
||||
fontSize: "30px"
|
||||
|
|
@ -204,7 +178,7 @@ const getIcon = (classes, name) => {
|
|||
return iconBig;
|
||||
};
|
||||
|
||||
class DownloadCompoment extends Component {
|
||||
class DownloadComponent extends Component {
|
||||
page = 0;
|
||||
|
||||
state = {
|
||||
|
|
@ -222,21 +196,20 @@ class DownloadCompoment extends Component {
|
|||
this.setState({
|
||||
loading: true
|
||||
});
|
||||
axios
|
||||
.get("/RemoteDownload/FlushUser")
|
||||
API.get("/aria2/downloading")
|
||||
.then(response => {
|
||||
axios.post("/RemoteDownload/ListDownloading").then(response => {
|
||||
this.setState({
|
||||
downloading: response.data,
|
||||
loading: false
|
||||
});
|
||||
this.setState({
|
||||
downloading: response.data,
|
||||
loading: false
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
this.props.toggleSnackbar("top", "right", "加载失败", "error");
|
||||
this.setState({
|
||||
loading: false
|
||||
});
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
error.message,
|
||||
"error"
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -316,70 +289,9 @@ class DownloadCompoment extends Component {
|
|||
<RefreshIcon />
|
||||
</IconButton>
|
||||
</Typography>
|
||||
{this.state.downloading.map(value => {
|
||||
value.percent = !value.hasOwnProperty("completedLength")
|
||||
? 0
|
||||
: value.completedLength / value.totalLength;
|
||||
return (
|
||||
<Card className={classes.card} key={value.id}>
|
||||
<div className={classes.iconContainer}>
|
||||
{getIcon(classes, value.fileName)}
|
||||
</div>
|
||||
<CardContent className={classes.content}>
|
||||
<Typography color="primary" variant="h6" noWrap>
|
||||
{value.fileName}
|
||||
</Typography>
|
||||
<LinearProgress
|
||||
color="secondary"
|
||||
variant="determinate"
|
||||
value={value.percent * 100}
|
||||
/>
|
||||
<Typography
|
||||
variant="subtitle1"
|
||||
color="textSecondary"
|
||||
noWrap
|
||||
>
|
||||
{value.hasOwnProperty(
|
||||
"completedLength"
|
||||
) && (
|
||||
<span>
|
||||
{(value.percent * 100).toFixed(2)}%
|
||||
-{" "}
|
||||
{value.completedLength === "0"
|
||||
? "0Bytes"
|
||||
: sizeToString(
|
||||
value.completedLength
|
||||
)}
|
||||
/
|
||||
{value.totalLength === "0"
|
||||
? "0Bytes"
|
||||
: sizeToString(
|
||||
value.totalLength
|
||||
)}{" "}
|
||||
-{" "}
|
||||
{value.downloadSpeed === "0"
|
||||
? "0B/s"
|
||||
: sizeToString(
|
||||
value.downloadSpeed
|
||||
) + "/s"}
|
||||
</span>
|
||||
)}
|
||||
{!value.hasOwnProperty(
|
||||
"completedLength"
|
||||
) && <span> - </span>}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
<CardContent
|
||||
className={classes.contentSide}
|
||||
onClick={() => this.cancelDownload(value.id)}
|
||||
>
|
||||
<IconButton>
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
})}
|
||||
{this.state.downloading.map((value, k) => (
|
||||
<DownloadingCard key={ k } task={value} />
|
||||
))}
|
||||
<Typography
|
||||
color="textSecondary"
|
||||
variant="h4"
|
||||
|
|
@ -450,6 +362,6 @@ class DownloadCompoment extends Component {
|
|||
const Download = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(DownloadCompoment));
|
||||
)(withStyles(styles)(DownloadComponent));
|
||||
|
||||
export default Download;
|
||||
|
|
@ -0,0 +1,560 @@
|
|||
import React, {useState, useCallback, useEffect} from "react";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
darken,
|
||||
IconButton,
|
||||
lighten,
|
||||
LinearProgress,
|
||||
makeStyles,
|
||||
Typography,
|
||||
useTheme
|
||||
} from "@material-ui/core";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { toggleSnackbar } from "../../actions";
|
||||
import {hex2bin, sizeToString} from "../../untils";
|
||||
import PermMediaIcon from '@material-ui/icons/PermMedia';
|
||||
import TypeIcon from "../FileManager/TypeIcon";
|
||||
import MuiExpansionPanel from "@material-ui/core/ExpansionPanel";
|
||||
import MuiExpansionPanelSummary from "@material-ui/core/ExpansionPanelSummary";
|
||||
import MuiExpansionPanelDetails from "@material-ui/core/ExpansionPanelDetails";
|
||||
import withStyles from "@material-ui/core/styles/withStyles";
|
||||
import Divider from "@material-ui/core/Divider";
|
||||
import { ExpandMore, HighlightOff} from "@material-ui/icons";
|
||||
import classNames from "classnames";
|
||||
import TableRow from "@material-ui/core/TableRow";
|
||||
import TableCell from "@material-ui/core/TableCell";
|
||||
import TableBody from "@material-ui/core/TableBody";
|
||||
import Table from "@material-ui/core/Table";
|
||||
import Badge from "@material-ui/core/Badge";
|
||||
import Tooltip from "@material-ui/core/Tooltip";
|
||||
import API, { baseURL } from "../../middleware/Api";
|
||||
import Button from "@material-ui/core/Button";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import TimeAgo from 'timeago-react';
|
||||
|
||||
const ExpansionPanel = withStyles({
|
||||
root: {
|
||||
maxWidth: "100%",
|
||||
boxShadow: "none",
|
||||
"&:not(:last-child)": {
|
||||
borderBottom: 0
|
||||
},
|
||||
"&:before": {
|
||||
display: "none"
|
||||
},
|
||||
"&$expanded": {}
|
||||
},
|
||||
expanded: {}
|
||||
})(MuiExpansionPanel);
|
||||
|
||||
const ExpansionPanelSummary = withStyles({
|
||||
root: {
|
||||
minHeight: 0,
|
||||
padding: 0,
|
||||
|
||||
"&$expanded": {
|
||||
minHeight: 56
|
||||
}
|
||||
},
|
||||
content: {
|
||||
maxWidth: "100%",
|
||||
margin: 0,
|
||||
display: "flex",
|
||||
"&$expanded": {
|
||||
margin: "0"
|
||||
}
|
||||
},
|
||||
expanded: {}
|
||||
})(MuiExpansionPanelSummary);
|
||||
|
||||
const ExpansionPanelDetails = withStyles(theme => ({
|
||||
root: {
|
||||
display: "block",
|
||||
padding: theme.spacing(0)
|
||||
}
|
||||
}))(MuiExpansionPanelDetails);
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
card: {
|
||||
marginTop: "20px",
|
||||
justifyContent: "space-between"
|
||||
},
|
||||
iconContainer: {
|
||||
width: "90px",
|
||||
height: "96px",
|
||||
padding: " 35px 29px 29px 29px",
|
||||
paddingLeft: "35px",
|
||||
[theme.breakpoints.down("sm")]: {
|
||||
display: "none"
|
||||
}
|
||||
},
|
||||
content: {
|
||||
width: "100%",
|
||||
minWidth: 0,
|
||||
[theme.breakpoints.up("sm")]: {
|
||||
borderInlineStart: "1px " + theme.palette.divider + " solid"
|
||||
}
|
||||
},
|
||||
contentSide: {
|
||||
minWidth: 0,
|
||||
paddingTop: "24px",
|
||||
paddingRight: "28px",
|
||||
[theme.breakpoints.down("sm")]: {
|
||||
display: "none"
|
||||
}
|
||||
},
|
||||
iconBig: {
|
||||
fontSize: "30px"
|
||||
},
|
||||
iconMultiple:{
|
||||
fontSize: "30px",
|
||||
color:"#607D8B",
|
||||
},
|
||||
progress: {
|
||||
marginTop: 8,
|
||||
marginBottom: 4
|
||||
},
|
||||
expand: {
|
||||
transition: ".15s transform ease-in-out"
|
||||
},
|
||||
expanded: {
|
||||
transform: "rotate(180deg)"
|
||||
},
|
||||
subFileName: {
|
||||
display: "flex"
|
||||
},
|
||||
subFileIcon: {
|
||||
marginRight: "20px"
|
||||
},
|
||||
scroll: {
|
||||
overflowY: "auto"
|
||||
},
|
||||
action:{
|
||||
padding:theme.spacing(2),
|
||||
textAlign:"right",
|
||||
},
|
||||
actionButton:{
|
||||
marginLeft: theme.spacing(1),
|
||||
},
|
||||
info:{
|
||||
padding:theme.spacing(2),
|
||||
},
|
||||
infoTitle:{
|
||||
fontWeight:700,
|
||||
},
|
||||
infoValue:{
|
||||
color:theme.palette.text.secondary,
|
||||
},
|
||||
bitmap:{
|
||||
width: "100%",
|
||||
height: "50px",
|
||||
backgroundColor:theme.palette.background.default,
|
||||
}
|
||||
}));
|
||||
|
||||
export default function DownloadingCard(props) {
|
||||
let canvasRef = React.createRef();
|
||||
const classes = useStyles();
|
||||
const theme = useTheme();
|
||||
|
||||
const [expanded, setExpanded] = React.useState("");
|
||||
const [task, setTask] = React.useState(props.task);
|
||||
const [loading, setLoading] = React.useState(false);
|
||||
|
||||
const handleChange = panel => (event, newExpanded) => {
|
||||
setExpanded(newExpanded ? panel : false);
|
||||
};
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const ToggleSnackbar = useCallback(
|
||||
(vertical, horizontal, msg, color) =>
|
||||
dispatch(toggleSnackbar(vertical, horizontal, msg, color)),
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
useEffect(()=>{
|
||||
setTask(props.task);
|
||||
},[props.task]);
|
||||
|
||||
useEffect(()=>{
|
||||
if (task.info.bitfield===""){
|
||||
return
|
||||
}
|
||||
let result = "";
|
||||
task.info.bitfield.match(/.{1,2}/g).forEach(str => {
|
||||
result += hex2bin(str);
|
||||
});
|
||||
const canvas = canvasRef.current;
|
||||
const context = canvas.getContext('2d');
|
||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||
context.strokeStyle = theme.palette.primary.main;
|
||||
for (let i = 0;i<canvas.width;i++){
|
||||
let bit = result[Math.round(((i+1)/canvas.width)*result.length)];
|
||||
bit = bit?bit:result.slice(-1);
|
||||
if(bit === "1"){
|
||||
context.beginPath();
|
||||
context.moveTo(i,0);
|
||||
context.lineTo(i, canvas.height);
|
||||
context.stroke();
|
||||
}
|
||||
}
|
||||
},[task.info.bitfield,theme]);
|
||||
|
||||
const getPercent = (completed, total) => {
|
||||
if (total == 0) {
|
||||
return 0;
|
||||
}
|
||||
return (completed / total) * 100;
|
||||
};
|
||||
|
||||
const deleteFile = (index)=>{
|
||||
setLoading(true);
|
||||
let current = activeFiles();
|
||||
let newIndex = [];
|
||||
let newFiles = [];
|
||||
current.map((v)=>{
|
||||
|
||||
if (v.index !== index && v.selected){
|
||||
newIndex.push(parseInt(v.index));
|
||||
newFiles.push({
|
||||
...v,
|
||||
selected:"true",
|
||||
});
|
||||
}else{
|
||||
newFiles.push({
|
||||
...v,
|
||||
selected:"false",
|
||||
});
|
||||
}
|
||||
});
|
||||
API.put("/aria2/select/"+task.info.gid,{
|
||||
indexes:newIndex,
|
||||
})
|
||||
.then(response => {
|
||||
setTask({
|
||||
...task,
|
||||
info:{
|
||||
...task.info,
|
||||
files:newFiles,
|
||||
}
|
||||
});
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"文件已删除",
|
||||
"success"
|
||||
);
|
||||
})
|
||||
.catch(error => {
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
error.message,
|
||||
"error"
|
||||
);
|
||||
}).finally(()=>{
|
||||
setLoading(false);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
const getDownloadName = useCallback(() => {
|
||||
if (task.info.bittorrent.info.name !== "") {
|
||||
return task.info.bittorrent.info.name;
|
||||
}
|
||||
return task.name === "." ? "[未知]" : task.name;
|
||||
}, [task]);
|
||||
|
||||
const activeFiles = useCallback(() => {
|
||||
return task.info.files.filter((v)=> v.selected==="true");
|
||||
}, [task.info.files]);
|
||||
|
||||
const getIcon = useCallback(() => {
|
||||
if (task.info.bittorrent.mode === "multi") {
|
||||
return (
|
||||
<Badge badgeContent={activeFiles().length} color="secondary">
|
||||
<PermMediaIcon className={classes.iconMultiple}/>
|
||||
</Badge>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<TypeIcon
|
||||
className={classes.iconBig}
|
||||
fileName={getDownloadName(task)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}, [task, classes]);
|
||||
|
||||
return (
|
||||
<Card className={classes.card}>
|
||||
<ExpansionPanel
|
||||
square
|
||||
expanded={expanded === task.info.gid}
|
||||
onChange={handleChange(task.info.gid)}
|
||||
>
|
||||
<ExpansionPanelSummary
|
||||
aria-controls="panel1d-content"
|
||||
id="panel1d-header"
|
||||
>
|
||||
<div className={classes.iconContainer}>{getIcon()}</div>
|
||||
<CardContent className={classes.content}>
|
||||
<Typography color="primary" noWrap>
|
||||
<Tooltip title={getDownloadName()}>
|
||||
<span>
|
||||
{getDownloadName()}</span>
|
||||
</Tooltip>
|
||||
|
||||
</Typography>
|
||||
<LinearProgress
|
||||
color="secondary"
|
||||
variant="determinate"
|
||||
className={classes.progress}
|
||||
value={getPercent(
|
||||
task.downloaded,
|
||||
task.total
|
||||
)}
|
||||
/>
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="textSecondary"
|
||||
noWrap
|
||||
>
|
||||
{task.total > 0 && (
|
||||
<span>
|
||||
{getPercent(
|
||||
task.downloaded,
|
||||
task.total
|
||||
).toFixed(2)}
|
||||
% -{" "}
|
||||
{task.downloaded === 0
|
||||
? "0Bytes"
|
||||
: sizeToString(task.downloaded)}
|
||||
/
|
||||
{task.total === 0
|
||||
? "0Bytes"
|
||||
: sizeToString(task.total)}{" "}
|
||||
-{" "}
|
||||
{task.speed === "0"
|
||||
? "0B/s"
|
||||
: sizeToString(task.speed) + "/s"}
|
||||
</span>
|
||||
)}
|
||||
{task.total === 0 && <span> - </span>}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
<CardContent className={classes.contentSide}>
|
||||
<IconButton>
|
||||
<ExpandMore
|
||||
className={classNames(
|
||||
{
|
||||
[classes.expanded]:
|
||||
expanded === task.info.gid
|
||||
},
|
||||
classes.expand
|
||||
)}
|
||||
/>
|
||||
</IconButton>
|
||||
</CardContent>
|
||||
</ExpansionPanelSummary>
|
||||
<ExpansionPanelDetails>
|
||||
<Divider />
|
||||
<div className={classes.scroll}>
|
||||
<Table size="small">
|
||||
<TableBody>
|
||||
{activeFiles().map((value, key) => {
|
||||
return (
|
||||
<TableRow
|
||||
key={value.index}
|
||||
style={{
|
||||
background:
|
||||
"linear-gradient(to right, " +
|
||||
(theme.palette.type ===
|
||||
"dark"
|
||||
? darken(
|
||||
theme.palette
|
||||
.primary.main,
|
||||
0.4
|
||||
)
|
||||
: lighten(
|
||||
theme.palette
|
||||
.primary.main,
|
||||
0.85
|
||||
)) +
|
||||
" 0%," +
|
||||
(theme.palette.type ===
|
||||
"dark"
|
||||
? darken(
|
||||
theme.palette
|
||||
.primary.main,
|
||||
0.4
|
||||
)
|
||||
: lighten(
|
||||
theme.palette
|
||||
.primary.main,
|
||||
0.85
|
||||
)) +
|
||||
" " +
|
||||
getPercent(
|
||||
value.completedLength,
|
||||
value.length
|
||||
).toFixed(0) +
|
||||
"%," +
|
||||
theme.palette.background
|
||||
.paper +
|
||||
" " +
|
||||
getPercent(
|
||||
value.completedLength,
|
||||
value.length
|
||||
).toFixed(0) +
|
||||
"%," +
|
||||
theme.palette.background
|
||||
.paper +
|
||||
" 100%)"
|
||||
}}
|
||||
>
|
||||
<TableCell
|
||||
component="th"
|
||||
scope="row"
|
||||
>
|
||||
<Typography
|
||||
className={
|
||||
classes.subFileName
|
||||
}
|
||||
>
|
||||
<TypeIcon
|
||||
className={
|
||||
classes.subFileIcon
|
||||
}
|
||||
fileName={value.path}
|
||||
/>
|
||||
{value.path}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
component="th"
|
||||
scope="row"
|
||||
>
|
||||
<Typography noWrap>
|
||||
{" "}
|
||||
{sizeToString(value.length)}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
component="th"
|
||||
scope="row"
|
||||
>
|
||||
<Typography noWrap>
|
||||
{getPercent(
|
||||
value.completedLength,
|
||||
value.length
|
||||
).toFixed(2)}
|
||||
%
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Tooltip title="删除此文件">
|
||||
<IconButton onClick={()=>deleteFile(value.index)} disabled={loading} size={"small"}>
|
||||
<HighlightOff/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<Divider/>
|
||||
</div>
|
||||
<div className={classes.action}>
|
||||
<Button className={classes.actionButton} variant="outlined" color="secondary">
|
||||
选择要下载的文件
|
||||
</Button>
|
||||
<Button className={classes.actionButton} variant="contained" color="secondary">
|
||||
取消任务
|
||||
</Button>
|
||||
</div>
|
||||
<Divider/>
|
||||
<div className={classes.info}>
|
||||
{task.info.bitfield !==""&&<canvas width={"700"} height={"100"} ref={canvasRef} className={classes.bitmap}/>}
|
||||
|
||||
<Grid container >
|
||||
<Grid container xs={12} sm={4} >
|
||||
<Grid item xs={4} className={classes.infoTitle}>
|
||||
更新于:
|
||||
</Grid>
|
||||
<Grid item xs={8} className={classes.infoValue}>
|
||||
<TimeAgo
|
||||
datetime={parseInt(task.update + "000")}
|
||||
locale='zh_CN'
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container xs={12} sm={4} >
|
||||
<Grid item xs={4} className={classes.infoTitle}>
|
||||
上传大小:
|
||||
</Grid>
|
||||
<Grid item xs={8} className={classes.infoValue}>
|
||||
{sizeToString(task.info.uploadLength)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container xs={12} sm={4} >
|
||||
<Grid item xs={4} className={classes.infoTitle}>
|
||||
上传速度:
|
||||
</Grid>
|
||||
<Grid item xs={8} className={classes.infoValue}>
|
||||
{sizeToString(task.info.uploadLength)} / s
|
||||
</Grid>
|
||||
</Grid>
|
||||
{task.info.bittorrent.mode !== ""&&
|
||||
<><Grid container xs={12} sm={8} >
|
||||
<Grid item xs={2} className={classes.infoTitle}>
|
||||
InfoHash:
|
||||
</Grid>
|
||||
<Grid item xs={10} className={classes.infoValue}>
|
||||
{task.info.infoHash}
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container xs={12} sm={4} >
|
||||
<Grid item xs={4} className={classes.infoTitle}>
|
||||
做种者:
|
||||
</Grid>
|
||||
<Grid item xs={8} className={classes.infoValue}>
|
||||
{task.info.numSeeders}
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container xs={12} sm={4} >
|
||||
<Grid item xs={4} className={classes.infoTitle}>
|
||||
做种中:
|
||||
</Grid>
|
||||
<Grid item xs={8} className={classes.infoValue}>
|
||||
{task.info.seeder === "true"?"是":"否"}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</>
|
||||
}
|
||||
<Grid container xs={12} sm={4} >
|
||||
<Grid item xs={4} className={classes.infoTitle}>
|
||||
分片大小:
|
||||
</Grid>
|
||||
<Grid item xs={8} className={classes.infoValue}>
|
||||
{sizeToString(task.info.pieceLength)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container xs={12} sm={4} >
|
||||
<Grid item xs={4} className={classes.infoTitle}>
|
||||
分片数量:
|
||||
</Grid>
|
||||
<Grid item xs={8} className={classes.infoValue}>
|
||||
{task.info.numPieces}
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
</div>
|
||||
</ExpansionPanelDetails>
|
||||
</ExpansionPanel>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
|
@ -411,9 +411,8 @@ class ContextMenuCompoment extends Component {
|
|||
|
||||
{!this.props.isMultiple &&
|
||||
isHomePage &&
|
||||
user.group.allowTorrentDownload &&
|
||||
this.props.withFile &&
|
||||
isTorrent(this.props.selected[0].name) && (
|
||||
user.group.allowRemoteDownload &&
|
||||
this.props.withFile&& (
|
||||
<MenuItem
|
||||
onClick={() =>
|
||||
this.props.openTorrentDownloadDialog()
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import {
|
|||
openLoadingDialog
|
||||
} from "../../actions/index";
|
||||
import PathSelector from "./PathSelector";
|
||||
import axios from "axios";
|
||||
import API, { baseURL } from "../../middleware/Api";
|
||||
import {
|
||||
withStyles,
|
||||
|
|
@ -22,9 +21,6 @@ import {
|
|||
DialogTitle,
|
||||
DialogContentText,
|
||||
CircularProgress,
|
||||
Checkbox,
|
||||
FormControl,
|
||||
FormControlLabel
|
||||
} from "@material-ui/core";
|
||||
import Loading from "../Modals/Loading";
|
||||
import CopyDialog from "../Modals/Copy";
|
||||
|
|
@ -35,6 +31,7 @@ import PurchaseShareDialog from "../Modals/PurchaseShare";
|
|||
import Auth from "../../middleware/Auth";
|
||||
import DecompressDialog from "../Modals/Decompress";
|
||||
import CompressDialog from "../Modals/Compress";
|
||||
import {filePath} from "../../untils";
|
||||
|
||||
const styles = theme => ({
|
||||
wrapper: {
|
||||
|
|
@ -283,48 +280,6 @@ class ModalsCompoment extends Component {
|
|||
});
|
||||
};
|
||||
|
||||
submitShare = e => {
|
||||
e.preventDefault();
|
||||
this.props.setModalsLoading(true);
|
||||
axios
|
||||
.post("/File/Share", {
|
||||
action: "share",
|
||||
item:
|
||||
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,
|
||||
shareType: this.state.secretShare ? "private" : "public",
|
||||
pwd: this.state.sharePwd
|
||||
})
|
||||
.then(response => {
|
||||
if (response.data.result !== "") {
|
||||
this.setState({
|
||||
shareUrl: response.data.result
|
||||
});
|
||||
} else {
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
response.data.result.error,
|
||||
"warning"
|
||||
);
|
||||
}
|
||||
this.props.setModalsLoading(false);
|
||||
})
|
||||
.catch(error => {
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
error.message,
|
||||
"error"
|
||||
);
|
||||
this.props.setModalsLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
submitRemove = e => {
|
||||
e.preventDefault();
|
||||
this.props.setModalsLoading(true);
|
||||
|
|
@ -575,14 +530,11 @@ class ModalsCompoment extends Component {
|
|||
submitTorrentDownload = e => {
|
||||
e.preventDefault();
|
||||
this.props.setModalsLoading(true);
|
||||
axios
|
||||
.post("/RemoteDownload/AddTorrent", {
|
||||
action: "torrentDownload",
|
||||
id: this.props.selected[0].id,
|
||||
savePath: this.state.selectedPath
|
||||
API
|
||||
.post("/aria2/torrent" + filePath(this.props.selected[0]), {
|
||||
dst: this.state.selectedPath === "//" ? "/" : this.state.selectedPath
|
||||
})
|
||||
.then(response => {
|
||||
if (response.data.result.success) {
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
|
|
@ -590,14 +542,6 @@ class ModalsCompoment extends Component {
|
|||
"success"
|
||||
);
|
||||
this.onClose();
|
||||
} else {
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
response.data.result.error,
|
||||
"warning"
|
||||
);
|
||||
}
|
||||
this.props.setModalsLoading(false);
|
||||
})
|
||||
.catch(error => {
|
||||
|
|
@ -614,14 +558,12 @@ class ModalsCompoment extends Component {
|
|||
submitDownload = e => {
|
||||
e.preventDefault();
|
||||
this.props.setModalsLoading(true);
|
||||
axios
|
||||
.post("/RemoteDownload/addUrl", {
|
||||
action: "remoteDownload",
|
||||
API
|
||||
.post("/aria2/url", {
|
||||
url: this.state.downloadURL,
|
||||
path: this.state.selectedPath
|
||||
dst: this.state.selectedPath === "//" ? "/" : this.state.selectedPath
|
||||
})
|
||||
.then(response => {
|
||||
if (response.data.result.success) {
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
|
|
@ -629,14 +571,6 @@ class ModalsCompoment extends Component {
|
|||
"success"
|
||||
);
|
||||
this.onClose();
|
||||
} else {
|
||||
this.props.toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
response.data.result.error,
|
||||
"warning"
|
||||
);
|
||||
}
|
||||
this.props.setModalsLoading(false);
|
||||
})
|
||||
.catch(error => {
|
||||
|
|
|
|||
|
|
@ -528,9 +528,7 @@ class NavbarCompoment extends Component {
|
|||
<ListItem
|
||||
button
|
||||
key="离线下载"
|
||||
onClick={() =>
|
||||
(window.location.href = "/Home/Download")
|
||||
}
|
||||
onClick={() => (this.props.history.push("/aria2?"))}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<DownloadIcon className={classes.iconFix} />
|
||||
|
|
|
|||
|
|
@ -13,9 +13,10 @@ const instance = axios.create({
|
|||
crossDomain: true
|
||||
});
|
||||
|
||||
function AppError(message,code) {
|
||||
function AppError(message,code,error) {
|
||||
this.code = code;
|
||||
this.message = message || '未知错误';
|
||||
this.message += error?(" "+error) : "";
|
||||
this.stack = (new Error()).stack;
|
||||
}
|
||||
AppError.prototype = Object.create(Error.prototype);
|
||||
|
|
@ -35,7 +36,7 @@ instance.interceptors.response.use(
|
|||
Auth.signout();
|
||||
window.location.href = "#/Login";
|
||||
}
|
||||
throw new AppError(response.rawData.msg,response.rawData.code);
|
||||
throw new AppError(response.rawData.msg,response.rawData.code,response.rawData.error);
|
||||
}
|
||||
return response;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
|||
import Navbar from "../component/Navbar/Navbar.js"
|
||||
import AlertBar from "../component/Snackbar"
|
||||
import { createMuiTheme } from '@material-ui/core/styles';
|
||||
import Download from '../component/Download'
|
||||
import Download from '../component/Download/Download'
|
||||
import { CssBaseline, withStyles, MuiThemeProvider } from '@material-ui/core';
|
||||
const theme = createMuiTheme(window.colorTheme);
|
||||
const styles = theme => ({
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
export const sizeToString = bytes => {
|
||||
if (bytes === 0) return "0 B";
|
||||
if (bytes === 0 || bytes==="0") return "0 B";
|
||||
var k = 1024;
|
||||
var sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
||||
var i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
|
|
@ -131,3 +131,7 @@ export function filePath(file) {
|
|||
? file.path + file.name
|
||||
: file.path + "/" + file.name;
|
||||
}
|
||||
|
||||
export function hex2bin(hex){
|
||||
return (parseInt(hex, 16).toString(2)).padStart(8, '0');
|
||||
}
|
||||
12
yarn.lock
12
yarn.lock
|
|
@ -10022,6 +10022,18 @@ thunky@^1.0.2:
|
|||
resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.0.3.tgz#f5df732453407b09191dae73e2a8cc73f381a826"
|
||||
integrity sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow==
|
||||
|
||||
timeago-react@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/timeago-react/-/timeago-react-3.0.0.tgz#777665f768ae0517e71be137fc6287c4d0a6a788"
|
||||
integrity sha512-dO7dBjuRqUSoyt7kLc6UJLvfN5F0JbC2qTqIsjpRFaMXu9bK9PKuWQ3/XD/kPZWGVtwpNimKDpQC3Q2ok8MMSA==
|
||||
dependencies:
|
||||
timeago.js "^4.0.0"
|
||||
|
||||
timeago.js@^4.0.0:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/timeago.js/-/timeago.js-4.0.2.tgz#724e8c8833e3490676c7bb0a75f5daf20e558028"
|
||||
integrity sha512-a7wPxPdVlQL7lqvitHGGRsofhdwtkoSXPGATFuSOA2i1ZNQEPLrGnj68vOp2sOJTCFAQVXPeNMX/GctBaO9L2w==
|
||||
|
||||
timers-browserify@^2.0.4:
|
||||
version "2.0.11"
|
||||
resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.11.tgz#800b1f3eee272e5bc53ee465a04d0e804c31211f"
|
||||
|
|
|
|||
Loading…
Reference in New Issue