Feat: list nodes

This commit is contained in:
HFO4 2021-10-31 09:30:28 +08:00
parent 0ce8d9250e
commit 8fff5d2d26
3 changed files with 248 additions and 0 deletions

View File

@ -32,6 +32,7 @@ import Download from "./component/Admin/Task/Download";
import Task from "./component/Admin/Task/Task";
import Import from "./component/Admin/File/Import";
import Captcha from "./component/Admin/Setting/Captcha";
import Node from "./component/Admin/Node/Node";
const useStyles = makeStyles((theme) => ({
root: {
@ -183,6 +184,10 @@ export default function Admin() {
<Route path={`${path}/task`} exact>
<Task />
</Route>
<Route path={`${path}/node`} exact>
<Node />
</Route>
</Switch>
)}
/>

View File

@ -31,6 +31,7 @@ import {
SettingsEthernet,
Share,
Storage,
Contactless,
} from "@material-ui/icons";
import ChevronLeftIcon from "@material-ui/icons/ChevronLeft";
import ChevronRightIcon from "@material-ui/icons/ChevronRight";
@ -232,6 +233,11 @@ const items = [
icon: <Storage />,
path: "policy",
},
{
title: "从机节点",
icon: <Contactless />,
path: "node",
},
{
title: "用户组",
icon: <Group />,

View File

@ -0,0 +1,237 @@
import React, { useCallback, useEffect, useState } from "react";
import { makeStyles } from "@material-ui/core/styles";
import API from "../../../middleware/Api";
import { useDispatch } from "react-redux";
import { toggleSnackbar } from "../../../actions";
import Paper from "@material-ui/core/Paper";
import Button from "@material-ui/core/Button";
import TableContainer from "@material-ui/core/TableContainer";
import Table from "@material-ui/core/Table";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import TableCell from "@material-ui/core/TableCell";
import TableBody from "@material-ui/core/TableBody";
import TablePagination from "@material-ui/core/TablePagination";
import { useHistory } from "react-router";
import IconButton from "@material-ui/core/IconButton";
import { Delete, Edit } from "@material-ui/icons";
import Tooltip from "@material-ui/core/Tooltip";
import Chip from "@material-ui/core/Chip";
import classNames from "classnames";
const useStyles = makeStyles((theme) => ({
root: {
[theme.breakpoints.up("md")]: {
marginLeft: 100,
},
marginBottom: 40,
},
content: {
padding: theme.spacing(2),
},
container: {
overflowX: "auto",
},
tableContainer: {
marginTop: 16,
},
header: {
display: "flex",
justifyContent: "space-between",
},
disabledBadge: {
marginLeft: theme.spacing(1),
height: 18,
},
disabledCell: {
color: theme.palette.text.disabled,
},
}));
const columns = [
{ id: "#", label: "#", minWidth: 50 },
{ id: "name", label: "名称", minWidth: 170 },
{
id: "status",
label: "当前状态",
minWidth: 50,
},
{
id: "features",
label: "已启用功能",
minWidth: 170,
},
{
id: "action",
label: "操作",
minWidth: 170,
},
];
export default function Node() {
const classes = useStyles();
const [nodes, setNodes] = useState([]);
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(10);
const [total, setTotal] = useState(0);
const history = useHistory();
const dispatch = useDispatch();
const ToggleSnackbar = useCallback(
(vertical, horizontal, msg, color) =>
dispatch(toggleSnackbar(vertical, horizontal, msg, color)),
[dispatch]
);
const loadList = () => {
API.post("/admin/node/list", {
page: page,
page_size: pageSize,
order_by: "id desc",
})
.then((response) => {
setNodes(response.data.items);
setTotal(response.data.total);
})
.catch((error) => {
ToggleSnackbar("top", "right", error.message, "error");
});
};
useEffect(() => {
loadList();
}, [page, pageSize]);
const deletePolicy = (id) => {
API.delete("/admin/group/" + id)
.then(() => {
loadList();
ToggleSnackbar("top", "right", "用户组已删除", "success");
})
.catch((error) => {
ToggleSnackbar("top", "right", error.message, "error");
});
};
const getStatusBadge = (status) => {
if (status === 1) {
return (
<Chip
className={classes.disabledBadge}
size="small"
label="未启用"
/>
);
}
};
const getFeatureBadge = (node) => {
if (node.Aria2Enabled) {
return "0";
}
};
return (
<div>
<div className={classes.header}>
<Button
color={"primary"}
onClick={() => history.push("/admin/node/add")}
variant={"contained"}
>
接入新节点
</Button>
<div className={classes.headerRight}>
<Button
color={"primary"}
onClick={() => loadList()}
variant={"outlined"}
>
刷新
</Button>
</div>
</div>
<Paper square className={classes.tableContainer}>
<TableContainer className={classes.container}>
<Table aria-label="sticky table" size={"small"}>
<TableHead>
<TableRow style={{ height: 52 }}>
{columns.map((column) => (
<TableCell
key={column.id}
align={column.align}
style={{
minWidth: column.minWidthclassNames,
}}
>
{column.label}
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{nodes.map((row) => (
<TableRow hover key={row.ID}>
<TableCell>{row.ID}</TableCell>
<TableCell
className={classNames({
[classes.disabledCell]:
row.Status === 1,
})}
>
{row.Name}
{getStatusBadge(row.Status)}
</TableCell>
<TableCell>...</TableCell>
<TableCell>
{getFeatureBadge(row)}
</TableCell>
<TableCell align={"right"}>
<Tooltip title={"编辑"}>
<IconButton
onClick={() =>
history.push(
"/admin/node/edit/" +
row.ID
)
}
size={"small"}
>
<Edit />
</IconButton>
</Tooltip>
<Tooltip title={"删除"}>
<IconButton
onClick={() =>
deletePolicy(row.ID)
}
size={"small"}
>
<Delete />
</IconButton>
</Tooltip>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
<TablePagination
rowsPerPageOptions={[10, 25, 100]}
component="div"
count={total}
rowsPerPage={pageSize}
page={page - 1}
onChangePage={(e, p) => setPage(p + 1)}
onChangeRowsPerPage={(e) => {
setPageSize(e.target.value);
setPage(1);
}}
/>
</Paper>
</div>
);
}