Compare commits
2 Commits
7f2141e832
...
89124b9ad9
| Author | SHA1 | Date | |
|---|---|---|---|
|
89124b9ad9
|
|||
|
6d2c0d8cb3
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,8 +1,10 @@
|
|||||||
|
/data
|
||||||
/html.html
|
/html.html
|
||||||
/json
|
/json
|
||||||
/hours.json
|
/hours.json
|
||||||
/regular.json
|
/regular.json
|
||||||
/record.json
|
/record.json
|
||||||
|
/store.json
|
||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
# dependencies
|
# dependencies
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ const downloadObjectAsJson = (exportObj: any, exportName: string) => {
|
|||||||
|
|
||||||
const Timetable = ({
|
const Timetable = ({
|
||||||
user,
|
user,
|
||||||
|
isRegular = false,
|
||||||
disableNetwork = false,
|
disableNetwork = false,
|
||||||
disableConflictCheck = false,
|
disableConflictCheck = false,
|
||||||
replaceInputType = "checkbox",
|
replaceInputType = "checkbox",
|
||||||
@@ -126,7 +127,18 @@ const Timetable = ({
|
|||||||
for (const td_index in tr.children) {
|
for (const td_index in tr.children) {
|
||||||
const td: HTMLTableCellElement = tr.children[td_index];
|
const td: HTMLTableCellElement = tr.children[td_index];
|
||||||
if (td.tagName !== "TD") continue;
|
if (td.tagName !== "TD") continue;
|
||||||
|
|
||||||
if (td.getAttribute("bgcolor")?.toUpperCase() !== "#39CEFF") {
|
if (td.getAttribute("bgcolor")?.toUpperCase() !== "#39CEFF") {
|
||||||
|
// const position (assigned by supervisor)
|
||||||
|
if (td?.textContent?.trim() === user) {
|
||||||
|
const constSelected = document.createElement("input");
|
||||||
|
constSelected.setAttribute("type", "checkbox");
|
||||||
|
constSelected.setAttribute("checked", "1");
|
||||||
|
constSelected.setAttribute("disabled", "1");
|
||||||
|
td.innerHTML = "";
|
||||||
|
td.appendChild(constSelected);
|
||||||
|
}
|
||||||
|
|
||||||
row.push(null);
|
row.push(null);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -210,7 +222,7 @@ const Timetable = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (disableNetwork) return;
|
if (disableNetwork || isRegular) return;
|
||||||
|
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
refresh();
|
refresh();
|
||||||
@@ -222,7 +234,7 @@ const Timetable = ({
|
|||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const main = async () => {
|
const main = async () => {
|
||||||
const json = await get("/api/html");
|
const json = await get(isRegular ? "/api/html-regular" : "/api/html");
|
||||||
ref.current.innerHTML = json.html;
|
ref.current.innerHTML = json.html;
|
||||||
handleInput({ target: ref.current });
|
handleInput({ target: ref.current });
|
||||||
refresh();
|
refresh();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
const obj = {
|
const obj = {
|
||||||
begin: false,
|
begin: false,
|
||||||
limit: 2,
|
limit: 2,
|
||||||
token: process.env.TOKEN || "woshimima",
|
token: process.env.TOKEN ?? "woshimima",
|
||||||
};
|
};
|
||||||
export default obj;
|
export default obj;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from "next";
|
|||||||
import { store, html } from "@/store";
|
import { store, html } from "@/store";
|
||||||
import config from "@/config";
|
import config from "@/config";
|
||||||
|
|
||||||
export default function handler(
|
export default async function handler(
|
||||||
req: NextApiRequest,
|
req: NextApiRequest,
|
||||||
res: NextApiResponse<Record<string, string>>
|
res: NextApiResponse<Record<string, string>>
|
||||||
) {
|
) {
|
||||||
@@ -16,5 +16,6 @@ export default function handler(
|
|||||||
const json = req.body;
|
const json = req.body;
|
||||||
store.update(json);
|
store.update(json);
|
||||||
}
|
}
|
||||||
|
await store.save();
|
||||||
res.status(200).json(store.get());
|
res.status(200).json(store.get());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import config from "@/config";
|
|||||||
export default function handler(req: NextApiRequest, res: NextApiResponse) {
|
export default function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
if (req.method === "POST") {
|
if (req.method === "POST") {
|
||||||
if (req.headers.token !== config.token) {
|
if (req.headers.token !== config.token) {
|
||||||
|
console.log("wrong token", req.headers.token, config.token);
|
||||||
res.status(403).json({ error: "wrong token" });
|
res.status(403).json({ error: "wrong token" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
16
pages/api/html-regular.ts
Normal file
16
pages/api/html-regular.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
import { htmlRegular } from "@/store";
|
||||||
|
import config from "@/config";
|
||||||
|
|
||||||
|
export default function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
|
if (req.method === "POST") {
|
||||||
|
if (req.headers.token !== config.token) {
|
||||||
|
res.status(403).json({ error: "wrong token" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
htmlRegular.set(req.body.html);
|
||||||
|
}
|
||||||
|
res.status(200).json({
|
||||||
|
html: htmlRegular.get(),
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ export default function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
if (req.method === "POST") {
|
if (req.method === "POST") {
|
||||||
if (!config.begin) {
|
if (!config.begin) {
|
||||||
res.status(400).json({
|
res.status(400).json({
|
||||||
error: "还没到开时间哦",
|
error: "还没到开始时间哦",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const read = promisify(fs.readFile);
|
|||||||
|
|
||||||
// 索引与工时
|
// 索引与工时
|
||||||
const indexToHour: Record<string, number> = JSON.parse(
|
const indexToHour: Record<string, number> = JSON.parse(
|
||||||
fs.readFileSync("./hours.json", "utf8")
|
fs.readFileSync("./data/hours.json", "utf8")
|
||||||
).selections;
|
).selections;
|
||||||
|
|
||||||
export default async function handler(
|
export default async function handler(
|
||||||
@@ -18,7 +18,7 @@ export default async function handler(
|
|||||||
// 读入全部json文件
|
// 读入全部json文件
|
||||||
// users: {姓名: {坐标: 权重}}
|
// users: {姓名: {坐标: 权重}}
|
||||||
const users: Record<string, Record<string, number>> = {};
|
const users: Record<string, Record<string, number>> = {};
|
||||||
const files = await g("./json/*.json");
|
const files = await g("./data/json/*.json");
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
const jsonStr = await read(file, "utf8");
|
const jsonStr = await read(file, "utf8");
|
||||||
const json: {
|
const json: {
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ import { get, post } from "@/common";
|
|||||||
const ControlPage = () => {
|
const ControlPage = () => {
|
||||||
const [isBegin, setIsBegin] = React.useState(false);
|
const [isBegin, setIsBegin] = React.useState(false);
|
||||||
const [inputLimit, setInputLimit] = React.useState("2");
|
const [inputLimit, setInputLimit] = React.useState("2");
|
||||||
|
const [token, setToken] = React.useState("");
|
||||||
const toggleBegin = async () => {
|
const toggleBegin = async () => {
|
||||||
const json = await post("/api/config", { begin: !isBegin });
|
const json = await post("/api/config", { begin: !isBegin }, { token });
|
||||||
setIsBegin(json.begin);
|
setIsBegin(json.begin);
|
||||||
};
|
};
|
||||||
const refresh = async () => {
|
const refresh = async () => {
|
||||||
@@ -26,9 +27,16 @@ const ControlPage = () => {
|
|||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
</Head>
|
</Head>
|
||||||
<main>
|
<main>
|
||||||
|
<p>
|
||||||
|
<input
|
||||||
|
value={token}
|
||||||
|
onChange={(event) => setToken(event.target.value)}
|
||||||
|
placeholder="Token"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<button onClick={() => toggleBegin()}>
|
<button onClick={() => toggleBegin()}>
|
||||||
{isBegin ? "Begin" : "Pause"}
|
{isBegin ? "Pause" : "Begin"}
|
||||||
</button>
|
</button>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
@@ -40,9 +48,13 @@ const ControlPage = () => {
|
|||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
post("/api/config", {
|
post(
|
||||||
limit: parseInt(inputLimit) || 2,
|
"/api/config",
|
||||||
});
|
{
|
||||||
|
limit: parseInt(inputLimit) || 2,
|
||||||
|
},
|
||||||
|
{ token }
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Set Limit
|
Set Limit
|
||||||
|
|||||||
39
pages/edit-regular.tsx
Normal file
39
pages/edit-regular.tsx
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { get, post } from "@/common";
|
||||||
|
|
||||||
|
const EditPage = () => {
|
||||||
|
const [token, setToken] = React.useState("");
|
||||||
|
const ref = React.useRef();
|
||||||
|
const upload = async () => {
|
||||||
|
const html = ref.current.innerHTML;
|
||||||
|
await post("/api/html-regular", { html }, { token });
|
||||||
|
alert("Upload success");
|
||||||
|
refresh();
|
||||||
|
};
|
||||||
|
const refresh = async () => {
|
||||||
|
const html = await get("/api/html-regular");
|
||||||
|
ref.current.innerHTML = html.html;
|
||||||
|
};
|
||||||
|
React.useEffect(() => {
|
||||||
|
refresh();
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<input
|
||||||
|
value={token}
|
||||||
|
placeholder={"token"}
|
||||||
|
onChange={(event) => setToken(event.target.value)}
|
||||||
|
/>
|
||||||
|
<button onClick={() => upload()}>Upload</button>
|
||||||
|
<div
|
||||||
|
ref={ref}
|
||||||
|
onInput={(event) => {
|
||||||
|
console.log(event.currentTarget.innerHTML);
|
||||||
|
}}
|
||||||
|
contentEditable="true"
|
||||||
|
></div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EditPage;
|
||||||
@@ -22,6 +22,7 @@ const ReportPage = () => {
|
|||||||
disableNetwork={true}
|
disableNetwork={true}
|
||||||
apiRecordEndPoint="/api/regular"
|
apiRecordEndPoint="/api/regular"
|
||||||
openRecordMode={true}
|
openRecordMode={true}
|
||||||
|
isRegular={true}
|
||||||
/>
|
/>
|
||||||
</UserInputWrap>
|
</UserInputWrap>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -27,16 +27,21 @@ class Store {
|
|||||||
}
|
}
|
||||||
public async update(record: Record<string, string>) {
|
public async update(record: Record<string, string>) {
|
||||||
this.record = record;
|
this.record = record;
|
||||||
|
await this.save();
|
||||||
|
}
|
||||||
|
public async save() {
|
||||||
await write(this.filename, JSON.stringify(this.record), "utf8");
|
await write(this.filename, JSON.stringify(this.record), "utf8");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class HTML {
|
class HTML {
|
||||||
html: string;
|
html: string;
|
||||||
constructor() {
|
filename: string;
|
||||||
|
constructor(filename: string) {
|
||||||
|
this.filename = filename;
|
||||||
// load from file
|
// load from file
|
||||||
try {
|
try {
|
||||||
this.html = fs.readFileSync("./html.html", "utf8");
|
this.html = fs.readFileSync(this.filename, "utf8");
|
||||||
} catch {
|
} catch {
|
||||||
this.html = "";
|
this.html = "";
|
||||||
}
|
}
|
||||||
@@ -47,10 +52,11 @@ class HTML {
|
|||||||
public async set(html: string) {
|
public async set(html: string) {
|
||||||
this.html = html;
|
this.html = html;
|
||||||
// store into file
|
// store into file
|
||||||
await write("./html.html", html, "utf8");
|
await write(this.filename, html, "utf8");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const html = new HTML();
|
export const html = new HTML("./data/html.html");
|
||||||
export const store = new Store("store.json");
|
export const htmlRegular = new HTML("./data/html-regular.html");
|
||||||
export const regular = new Store("regular.json");
|
export const store = new Store("./data/store.json");
|
||||||
|
export const regular = new Store("./data/regular.json");
|
||||||
|
|||||||
Reference in New Issue
Block a user