Files
itsc/pages/time.js

379 lines
9.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {
Container,
Box,
Alert,
Snackbar,
Button,
Stack,
Typography,
TextField,
TableContainer,
Table,
TableHead,
TableRow,
TableCell,
TableBody,
} from "@mui/material";
import { useEffect, useState } from "react";
import { useRouter } from "next/router";
import config from "../next.config";
const prefix = config.basePath ? config.basePath : "";
export default function Time(props) {
const [ranges, setRanges] = useState([]);
const [range, setRange] = useState("");
const [newName, setNewName] = useState("");
const [snackbarError, setSnackbarError] = useState(false);
const [snackbarErrorMessage, setSnackbarErrorMessage] = useState("");
const [snackbarSuccess, setSnackbarSuccess] = useState(false);
const [limit, setLimit] = useState(1);
const [inputedLimit, setInputedLimit] = useState(1);
const [token, setToken] = useState("");
const [stats, setStats] = useState({});
const router = useRouter();
const getStats = () => {
fetch(`${prefix}/api/stats`, {
method: "GET",
})
.then((res) => res.json())
.then((res) => {
setStats(res);
});
};
const setStarted = (started) => {
fetch(`${prefix}/api/time/started`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ token, started }),
})
.then((res) => res.json())
.then((res) => {
if (res.error) {
setSnackbarError(true);
setSnackbarErrorMessage(res.error);
} else {
setSnackbarSuccess(true);
}
});
};
const isAdmin = () => {
if (props.username === "admin") {
return true;
} else {
return false;
}
};
const getLimit = () => {
fetch(`${prefix}/api/time/limit`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then((res) => res.json())
.then((res) => {
setLimit(res.limit);
});
};
const addRange = () => {
fetch(`${prefix}/api/time/ranges`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name: newName,
range,
token,
}),
}).then((res) =>
res.json().then((res) => {
if (res.error) {
setSnackbarError(true);
setSnackbarErrorMessage(res.error);
} else {
setSnackbarSuccess(true);
refreshRanges();
}
})
);
};
const refreshRanges = () => {
getLimit();
getStats();
fetch(`${prefix}/api/time/ranges`)
.then((res) => res.json())
.then((res) => {
if (res.error) {
setSnackbarError(true);
setSnackbarErrorMessage(res.error);
} else {
setRanges(res);
}
});
};
const deleteRange = (id) => {
fetch(`${prefix}/api/time/ranges/${id}`, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ token }),
})
.then((res) => res.json())
.then((res) => {
if (res.error) {
setSnackbarError(true);
setSnackbarErrorMessage(res.error);
} else {
setSnackbarSuccess(true);
refreshRanges();
}
});
};
const updateUsername = (id, username) => {
fetch(`${prefix}/api/time/ranges/${id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ username }),
})
.then((res) => res.json())
.then((res) => {
if (res.error) {
setSnackbarError(true);
setSnackbarErrorMessage(res.error);
refreshRanges();
} else {
setSnackbarSuccess(true);
refreshRanges();
}
});
};
const updateLimit = (limit) => {
fetch(`${prefix}/api/time/limit`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ limit, token }),
})
.then((res) => res.json())
.then((res) => {
if (res.error) {
setSnackbarError(true);
setSnackbarErrorMessage(res.error);
} else {
setSnackbarSuccess(true);
refreshRanges();
}
});
};
useEffect(() => {
if (!props.username) {
router.push("/");
}
});
useEffect(() => {
refreshRanges();
const interval = setInterval(() => {
refreshRanges();
}, 1000);
return () => clearInterval(interval);
}, []);
/*
useEffect(() => {
refreshRanges();
}, []);
*/
return (
<Container>
{isAdmin() && (
<Box>
<Box
sx={{
my: 2,
}}
>
<TextField
label="Token"
value={token}
onChange={(e) => setToken(e.target.value)}
/>
<Box
sx={{
my: 2,
}}
>
<TextField
label="名称"
value={newName}
onChange={(e) => setNewName(e.target.value)}
/>
<TextField
label="时间段"
value={range}
onChange={(e) => setRange(e.target.value)}
placeholder="2022-01-01 00:00:00"
/>
</Box>
<Button
variant="contained"
color="primary"
onClick={() => addRange()}
>
添加
</Button>
<Box
sx={{
my: 2,
}}
>
<TextField
label="每人数量上限"
value={inputedLimit}
onChange={(e) => setInputedLimit(e.target.value)}
/>
<Button
variant="contained"
color="primary"
onClick={() => {
updateLimit(inputedLimit);
}}
>
修改上限
</Button>
<Button
variant="contained"
color="primary"
onClick={() => setStarted(true)}
>
开始
</Button>
<Button
variant="contained"
color="primary"
onClick={() => setStarted(false)}
>
停止
</Button>
</Box>
</Box>
</Box>
)}
<Box
sx={{
display: "flex",
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
}}
>
<Button
sx={{
userSelect: "none",
}}
variant="contained"
color="primary"
onClick={() => refreshRanges()}
>
Refresh
</Button>
<Typography>
当前每人数量上限: {limit}
<br />
服务器负载 (QPS): {stats.apiqps}
</Typography>
</Box>
<TableContainer>
<Table>
<TableHead>
<TableRow>
<TableCell>名称</TableCell>
<TableCell>时间段</TableCell>
<TableCell>操作</TableCell>
</TableRow>
</TableHead>
<TableBody>
{ranges.map((range) => (
<TableRow key={range.id}>
<TableCell>{range.name}</TableCell>
<TableCell>{range.range}</TableCell>
<TableCell>
<Button
sx={{
userSelect: "none",
}}
disabled={range.username !== ""}
variant="contained"
color="primary"
onClick={() => updateUsername(range.id, props.username)}
>
{range.username ? range.username : "抢!"}
</Button>
{isAdmin() && (
<Button
sx={{
userSelect: "none",
}}
variant="contained"
color="secondary"
onClick={() => deleteRange(range.id)}
>
删除
</Button>
)}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
<Snackbar
open={snackbarError}
autoHideDuration={1000}
onClose={() => setSnackbarError(false)}
>
<Alert
variant="filled"
onClose={() => setSnackbarError(false)}
severity="error"
>
{snackbarErrorMessage}
</Alert>
</Snackbar>
<Snackbar
open={snackbarSuccess}
autoHideDuration={1000}
onClose={() => setSnackbarSuccess(false)}
>
<Alert
variant="filled"
onClose={() => setSnackbarSuccess(false)}
severity="success"
>
操作成功
</Alert>
</Snackbar>
</Container>
);
}