diff --git a/src/Admin.js b/src/Admin.js
index 8b50bd2..e0d7310 100644
--- a/src/Admin.js
+++ b/src/Admin.js
@@ -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() {
+
+
+
+
)}
/>
diff --git a/src/component/Admin/Dashboard.js b/src/component/Admin/Dashboard.js
index 484be53..a6b0aa4 100644
--- a/src/component/Admin/Dashboard.js
+++ b/src/component/Admin/Dashboard.js
@@ -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: ,
path: "policy",
},
+ {
+ title: "从机节点",
+ icon: ,
+ path: "node",
+ },
{
title: "用户组",
icon: ,
diff --git a/src/component/Admin/Node/Node.js b/src/component/Admin/Node/Node.js
new file mode 100644
index 0000000..6cfef3a
--- /dev/null
+++ b/src/component/Admin/Node/Node.js
@@ -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 (
+
+ );
+ }
+ };
+
+ const getFeatureBadge = (node) => {
+ if (node.Aria2Enabled) {
+ return "0";
+ }
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {columns.map((column) => (
+
+ {column.label}
+
+ ))}
+
+
+
+ {nodes.map((row) => (
+
+ {row.ID}
+
+ {row.Name}
+ {getStatusBadge(row.Status)}
+
+ ...
+
+ {getFeatureBadge(row)}
+
+
+
+
+
+ history.push(
+ "/admin/node/edit/" +
+ row.ID
+ )
+ }
+ size={"small"}
+ >
+
+
+
+
+
+ deletePolicy(row.ID)
+ }
+ size={"small"}
+ >
+
+
+
+
+
+ ))}
+
+
+
+ setPage(p + 1)}
+ onChangeRowsPerPage={(e) => {
+ setPageSize(e.target.value);
+ setPage(1);
+ }}
+ />
+
+
+ );
+}