排班工具
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,3 +1,6 @@
|
||||
/html.html
|
||||
/json
|
||||
/hours.json
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from "react";
|
||||
import { get, post } from "@/common";
|
||||
import { collection } from "@/store";
|
||||
|
||||
interface Conflicts {
|
||||
[index: string]: HTMLInputElement[];
|
||||
@@ -15,7 +16,24 @@ const indexToElement: IndexToElement = {};
|
||||
const conflicts: Conflicts = {};
|
||||
const marks: (HTMLInputElement | null)[][] = [];
|
||||
|
||||
const Timetable = ({ user }) => {
|
||||
const downloadObjectAsJson = (exportObj: any, exportName: string) => {
|
||||
const dataStr =
|
||||
"data:text/json;charset=utf-8," +
|
||||
encodeURIComponent(JSON.stringify(exportObj));
|
||||
const downloadAnchorNode = document.createElement("a");
|
||||
downloadAnchorNode.setAttribute("href", dataStr);
|
||||
downloadAnchorNode.setAttribute("download", `${exportName}.json`);
|
||||
document.body.appendChild(downloadAnchorNode); // required for firefox
|
||||
downloadAnchorNode.click();
|
||||
downloadAnchorNode.remove();
|
||||
};
|
||||
|
||||
const Timetable = ({
|
||||
user,
|
||||
disableNetwork = false,
|
||||
disableConflictCheck = false,
|
||||
replaceInputType = "checkbox",
|
||||
}) => {
|
||||
const [editable, setEditable] = React.useState(true);
|
||||
const ref = React.useRef();
|
||||
|
||||
@@ -23,6 +41,8 @@ const Timetable = ({ user }) => {
|
||||
const target: HTMLInputElement = event.target;
|
||||
console.log("select", target.name, target.checked);
|
||||
|
||||
if (disableConflictCheck) return;
|
||||
|
||||
const changedInputs: any = [];
|
||||
// find whether there are checked input in conflict
|
||||
for (const input of conflicts[target.name]) {
|
||||
@@ -47,6 +67,9 @@ const Timetable = ({ user }) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (disableNetwork) return;
|
||||
|
||||
// post request
|
||||
const json = await post("/api/record", {
|
||||
name: target.name,
|
||||
@@ -74,11 +97,12 @@ const Timetable = ({ user }) => {
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log(target.innerHTML);
|
||||
|
||||
// turn off editable
|
||||
setEditable(false);
|
||||
|
||||
// empty marks
|
||||
marks.length = 0;
|
||||
|
||||
const table = target.children[0];
|
||||
table.setAttribute("border", "1");
|
||||
|
||||
@@ -105,7 +129,7 @@ const Timetable = ({ user }) => {
|
||||
|
||||
// mount click event
|
||||
const input = document.createElement("input");
|
||||
input.setAttribute("type", "checkbox");
|
||||
input.setAttribute("type", replaceInputType);
|
||||
input.onchange = handleSelect;
|
||||
input.name = index;
|
||||
td.innerHTML = "";
|
||||
@@ -115,6 +139,7 @@ const Timetable = ({ user }) => {
|
||||
row.push(input);
|
||||
}
|
||||
marks.push(row);
|
||||
// console.log("marks", marks);
|
||||
}
|
||||
|
||||
// resolve conflicts
|
||||
@@ -156,13 +181,15 @@ const Timetable = ({ user }) => {
|
||||
}
|
||||
};
|
||||
React.useEffect(() => {
|
||||
if (disableNetwork) return;
|
||||
|
||||
const interval = setInterval(() => {
|
||||
refresh();
|
||||
}, 1000);
|
||||
return () => {
|
||||
clearInterval(interval);
|
||||
};
|
||||
});
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
const main = async () => {
|
||||
@@ -176,7 +203,27 @@ const Timetable = ({ user }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<button onClick={refresh}>Test</button>
|
||||
<button
|
||||
onClick={async () => {
|
||||
console.log("download marks", marks);
|
||||
const data = {
|
||||
user,
|
||||
selections: {},
|
||||
};
|
||||
for (const row of marks) {
|
||||
for (const input of row) {
|
||||
if (input === null) continue;
|
||||
if (input.value !== "") {
|
||||
data.selections[input.name] = parseFloat(input.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(data);
|
||||
downloadObjectAsJson(data, user);
|
||||
}}
|
||||
>
|
||||
DownloadSelection
|
||||
</button>
|
||||
<span>Login as {user}</span>
|
||||
<div
|
||||
ref={ref}
|
||||
@@ -186,6 +233,7 @@ const Timetable = ({ user }) => {
|
||||
}}
|
||||
onInput={handleInput}
|
||||
></div>
|
||||
<div style={{ display: "none" }} id="download-dom"></div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
406
package-lock.json
generated
406
package-lock.json
generated
@@ -9,12 +9,15 @@
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@next/font": "13.1.6",
|
||||
"@types/glob": "^8.0.1",
|
||||
"@types/node": "18.11.18",
|
||||
"@types/react": "18.0.27",
|
||||
"@types/react-dom": "18.0.10",
|
||||
"esbuild": "^0.17.5",
|
||||
"eslint": "8.33.0",
|
||||
"eslint-config-next": "13.1.6",
|
||||
"glob": "^8.1.0",
|
||||
"mongodb": "5.0",
|
||||
"next": "13.1.6",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
@@ -420,6 +423,22 @@
|
||||
"glob": "7.1.7"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/eslint-plugin-next/node_modules/glob": {
|
||||
"version": "7.1.7",
|
||||
"resolved": "https://registry.npmmirror.com/glob/-/glob-7.1.7.tgz",
|
||||
"integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.0.4",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/font": {
|
||||
"version": "13.1.6",
|
||||
"resolved": "https://registry.npmmirror.com/@next/font/-/font-13.1.6.tgz",
|
||||
@@ -681,11 +700,25 @@
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/glob": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/@types/glob/-/glob-8.0.1.tgz",
|
||||
"integrity": "sha512-8bVUjXZvJacUFkJXHdyZ9iH1Eaj5V7I8c4NdH5sQJsdXkqT4CA5Dhb4yb4VE/3asyx4L9ayZr1NIhTsWHczmMw==",
|
||||
"dependencies": {
|
||||
"@types/minimatch": "^5.1.2",
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/json5": {
|
||||
"version": "0.0.29",
|
||||
"resolved": "https://registry.npmmirror.com/@types/json5/-/json5-0.0.29.tgz",
|
||||
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="
|
||||
},
|
||||
"node_modules/@types/minimatch": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/@types/minimatch/-/minimatch-5.1.2.tgz",
|
||||
"integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA=="
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "18.11.18",
|
||||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-18.11.18.tgz",
|
||||
@@ -719,6 +752,20 @@
|
||||
"resolved": "https://registry.npmmirror.com/@types/scheduler/-/scheduler-0.16.2.tgz",
|
||||
"integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
|
||||
},
|
||||
"node_modules/@types/webidl-conversions": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
|
||||
"integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog=="
|
||||
},
|
||||
"node_modules/@types/whatwg-url": {
|
||||
"version": "8.2.2",
|
||||
"resolved": "https://registry.npmmirror.com/@types/whatwg-url/-/whatwg-url-8.2.2.tgz",
|
||||
"integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==",
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"@types/webidl-conversions": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "5.50.0",
|
||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-5.50.0.tgz",
|
||||
@@ -974,6 +1021,14 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/bson": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/bson/-/bson-5.0.0.tgz",
|
||||
"integrity": "sha512-EL2KpZdyhshyyptj6pnQfnFKPoncD9KwZYvgmj/FXQiOUU1HWTHWmBOP4TZXU3YzStcI5qgpIl68YnMo16s26A==",
|
||||
"engines": {
|
||||
"node": ">=14.20.1"
|
||||
}
|
||||
},
|
||||
"node_modules/call-bind": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.2.tgz",
|
||||
@@ -1882,19 +1937,18 @@
|
||||
"integrity": "sha512-YCcF28IqSay3fqpIu5y3Krg/utCBHBeoflkZyHj/QcqI2nrLPC3ZegS9CmIo+hJb8K7aiGsuUl7PwWVjNG2HQQ=="
|
||||
},
|
||||
"node_modules/glob": {
|
||||
"version": "7.1.7",
|
||||
"resolved": "https://registry.npmmirror.com/glob/-/glob-7.1.7.tgz",
|
||||
"integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/glob/-/glob-8.1.0.tgz",
|
||||
"integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.0.4",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
"minimatch": "^5.0.1",
|
||||
"once": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/glob-parent": {
|
||||
@@ -1908,6 +1962,25 @@
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/glob/node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/glob/node_modules/minimatch": {
|
||||
"version": "5.1.6",
|
||||
"resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-5.1.6.tgz",
|
||||
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/globals": {
|
||||
"version": "13.20.0",
|
||||
"resolved": "https://registry.npmmirror.com/globals/-/globals-13.20.0.tgz",
|
||||
@@ -2088,6 +2161,11 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/ip": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/ip/-/ip-2.0.0.tgz",
|
||||
"integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ=="
|
||||
},
|
||||
"node_modules/is-arguments": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/is-arguments/-/is-arguments-1.1.1.tgz",
|
||||
@@ -2449,6 +2527,12 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/memory-pager": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmmirror.com/memory-pager/-/memory-pager-1.5.0.tgz",
|
||||
"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/merge2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz",
|
||||
@@ -2485,6 +2569,47 @@
|
||||
"resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.7.tgz",
|
||||
"integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g=="
|
||||
},
|
||||
"node_modules/mongodb": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/mongodb/-/mongodb-5.0.1.tgz",
|
||||
"integrity": "sha512-KpjtY+NWFmcic6UDYEdfn768ZTuKyv7CRaui7ZSd6q/0/o1AURMC7KygTUwB1Cl8V10Pe5NiP+Y2eBMCDs/ygQ==",
|
||||
"dependencies": {
|
||||
"bson": "^5.0.0",
|
||||
"mongodb-connection-string-url": "^2.6.0",
|
||||
"socks": "^2.7.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.20.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"saslprep": "^1.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@aws-sdk/credential-providers": "^3.201.0",
|
||||
"mongodb-client-encryption": "^2.3.0",
|
||||
"snappy": "^7.2.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@aws-sdk/credential-providers": {
|
||||
"optional": true
|
||||
},
|
||||
"mongodb-client-encryption": {
|
||||
"optional": true
|
||||
},
|
||||
"snappy": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/mongodb-connection-string-url": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmmirror.com/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz",
|
||||
"integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==",
|
||||
"dependencies": {
|
||||
"@types/whatwg-url": "^8.2.1",
|
||||
"whatwg-url": "^11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz",
|
||||
@@ -2911,6 +3036,22 @@
|
||||
"rimraf": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/rimraf/node_modules/glob": {
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz",
|
||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.1.1",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/run-parallel": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||
@@ -2929,6 +3070,18 @@
|
||||
"is-regex": "^1.1.4"
|
||||
}
|
||||
},
|
||||
"node_modules/saslprep": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/saslprep/-/saslprep-1.0.3.tgz",
|
||||
"integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"sparse-bitfield": "^3.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.23.0",
|
||||
"resolved": "https://registry.npmmirror.com/scheduler/-/scheduler-0.23.0.tgz",
|
||||
@@ -2988,6 +3141,28 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/smart-buffer": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/smart-buffer/-/smart-buffer-4.2.0.tgz",
|
||||
"integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
|
||||
"engines": {
|
||||
"node": ">= 6.0.0",
|
||||
"npm": ">= 3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/socks": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmmirror.com/socks/-/socks-2.7.1.tgz",
|
||||
"integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==",
|
||||
"dependencies": {
|
||||
"ip": "^2.0.0",
|
||||
"smart-buffer": "^4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.13.0",
|
||||
"npm": ">= 3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.0.2.tgz",
|
||||
@@ -2996,6 +3171,15 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sparse-bitfield": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
|
||||
"integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"memory-pager": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/stop-iteration-iterator": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz",
|
||||
@@ -3155,6 +3339,17 @@
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/tr46/-/tr46-3.0.0.tgz",
|
||||
"integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==",
|
||||
"dependencies": {
|
||||
"punycode": "^2.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/tsconfig-paths": {
|
||||
"version": "3.14.1",
|
||||
"resolved": "https://registry.npmmirror.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
|
||||
@@ -3250,6 +3445,26 @@
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
|
||||
"integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-11.0.0.tgz",
|
||||
"integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==",
|
||||
"dependencies": {
|
||||
"tr46": "^3.0.0",
|
||||
"webidl-conversions": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz",
|
||||
@@ -3518,6 +3733,21 @@
|
||||
"integrity": "sha512-o7cauUYsXjzSJkay8wKjpKJf2uLzlggCsGUkPu3lP09Pv97jYlekTC20KJrjQKmSv5DXV0R/uks2ZXhqjNkqAw==",
|
||||
"requires": {
|
||||
"glob": "7.1.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"glob": {
|
||||
"version": "7.1.7",
|
||||
"resolved": "https://registry.npmmirror.com/glob/-/glob-7.1.7.tgz",
|
||||
"integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.0.4",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@next/font": {
|
||||
@@ -3652,11 +3882,25 @@
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"@types/glob": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/@types/glob/-/glob-8.0.1.tgz",
|
||||
"integrity": "sha512-8bVUjXZvJacUFkJXHdyZ9iH1Eaj5V7I8c4NdH5sQJsdXkqT4CA5Dhb4yb4VE/3asyx4L9ayZr1NIhTsWHczmMw==",
|
||||
"requires": {
|
||||
"@types/minimatch": "^5.1.2",
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/json5": {
|
||||
"version": "0.0.29",
|
||||
"resolved": "https://registry.npmmirror.com/@types/json5/-/json5-0.0.29.tgz",
|
||||
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="
|
||||
},
|
||||
"@types/minimatch": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/@types/minimatch/-/minimatch-5.1.2.tgz",
|
||||
"integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA=="
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "18.11.18",
|
||||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-18.11.18.tgz",
|
||||
@@ -3690,6 +3934,20 @@
|
||||
"resolved": "https://registry.npmmirror.com/@types/scheduler/-/scheduler-0.16.2.tgz",
|
||||
"integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
|
||||
},
|
||||
"@types/webidl-conversions": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
|
||||
"integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog=="
|
||||
},
|
||||
"@types/whatwg-url": {
|
||||
"version": "8.2.2",
|
||||
"resolved": "https://registry.npmmirror.com/@types/whatwg-url/-/whatwg-url-8.2.2.tgz",
|
||||
"integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==",
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"@types/webidl-conversions": "*"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/parser": {
|
||||
"version": "5.50.0",
|
||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-5.50.0.tgz",
|
||||
@@ -3882,6 +4140,11 @@
|
||||
"fill-range": "^7.0.1"
|
||||
}
|
||||
},
|
||||
"bson": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/bson/-/bson-5.0.0.tgz",
|
||||
"integrity": "sha512-EL2KpZdyhshyyptj6pnQfnFKPoncD9KwZYvgmj/FXQiOUU1HWTHWmBOP4TZXU3YzStcI5qgpIl68YnMo16s26A=="
|
||||
},
|
||||
"call-bind": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.2.tgz",
|
||||
@@ -4621,16 +4884,33 @@
|
||||
"integrity": "sha512-YCcF28IqSay3fqpIu5y3Krg/utCBHBeoflkZyHj/QcqI2nrLPC3ZegS9CmIo+hJb8K7aiGsuUl7PwWVjNG2HQQ=="
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.7",
|
||||
"resolved": "https://registry.npmmirror.com/glob/-/glob-7.1.7.tgz",
|
||||
"integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/glob/-/glob-8.1.0.tgz",
|
||||
"integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.0.4",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
"minimatch": "^5.0.1",
|
||||
"once": "^1.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "5.1.6",
|
||||
"resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-5.1.6.tgz",
|
||||
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
|
||||
"requires": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"glob-parent": {
|
||||
@@ -4785,6 +5065,11 @@
|
||||
"side-channel": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"ip": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/ip/-/ip-2.0.0.tgz",
|
||||
"integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ=="
|
||||
},
|
||||
"is-arguments": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/is-arguments/-/is-arguments-1.1.1.tgz",
|
||||
@@ -5074,6 +5359,12 @@
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"memory-pager": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmmirror.com/memory-pager/-/memory-pager-1.5.0.tgz",
|
||||
"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
|
||||
"optional": true
|
||||
},
|
||||
"merge2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz",
|
||||
@@ -5101,6 +5392,26 @@
|
||||
"resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.7.tgz",
|
||||
"integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g=="
|
||||
},
|
||||
"mongodb": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/mongodb/-/mongodb-5.0.1.tgz",
|
||||
"integrity": "sha512-KpjtY+NWFmcic6UDYEdfn768ZTuKyv7CRaui7ZSd6q/0/o1AURMC7KygTUwB1Cl8V10Pe5NiP+Y2eBMCDs/ygQ==",
|
||||
"requires": {
|
||||
"bson": "^5.0.0",
|
||||
"mongodb-connection-string-url": "^2.6.0",
|
||||
"saslprep": "^1.0.3",
|
||||
"socks": "^2.7.1"
|
||||
}
|
||||
},
|
||||
"mongodb-connection-string-url": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmmirror.com/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz",
|
||||
"integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==",
|
||||
"requires": {
|
||||
"@types/whatwg-url": "^8.2.1",
|
||||
"whatwg-url": "^11.0.0"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz",
|
||||
@@ -5408,6 +5719,21 @@
|
||||
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||
"requires": {
|
||||
"glob": "^7.1.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"glob": {
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz",
|
||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.1.1",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"run-parallel": {
|
||||
@@ -5428,6 +5754,15 @@
|
||||
"is-regex": "^1.1.4"
|
||||
}
|
||||
},
|
||||
"saslprep": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/saslprep/-/saslprep-1.0.3.tgz",
|
||||
"integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"sparse-bitfield": "^3.0.3"
|
||||
}
|
||||
},
|
||||
"scheduler": {
|
||||
"version": "0.23.0",
|
||||
"resolved": "https://registry.npmmirror.com/scheduler/-/scheduler-0.23.0.tgz",
|
||||
@@ -5472,11 +5807,34 @@
|
||||
"resolved": "https://registry.npmmirror.com/slash/-/slash-3.0.0.tgz",
|
||||
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="
|
||||
},
|
||||
"smart-buffer": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/smart-buffer/-/smart-buffer-4.2.0.tgz",
|
||||
"integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="
|
||||
},
|
||||
"socks": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmmirror.com/socks/-/socks-2.7.1.tgz",
|
||||
"integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==",
|
||||
"requires": {
|
||||
"ip": "^2.0.0",
|
||||
"smart-buffer": "^4.2.0"
|
||||
}
|
||||
},
|
||||
"source-map-js": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.0.2.tgz",
|
||||
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw=="
|
||||
},
|
||||
"sparse-bitfield": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
|
||||
"integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"memory-pager": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"stop-iteration-iterator": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz",
|
||||
@@ -5595,6 +5953,14 @@
|
||||
"is-number": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"tr46": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/tr46/-/tr46-3.0.0.tgz",
|
||||
"integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==",
|
||||
"requires": {
|
||||
"punycode": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"tsconfig-paths": {
|
||||
"version": "3.14.1",
|
||||
"resolved": "https://registry.npmmirror.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
|
||||
@@ -5673,6 +6039,20 @@
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"webidl-conversions": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
|
||||
"integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="
|
||||
},
|
||||
"whatwg-url": {
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-11.0.0.tgz",
|
||||
"integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==",
|
||||
"requires": {
|
||||
"tr46": "^3.0.0",
|
||||
"webidl-conversions": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz",
|
||||
|
||||
@@ -11,12 +11,15 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@next/font": "13.1.6",
|
||||
"@types/glob": "^8.0.1",
|
||||
"@types/node": "18.11.18",
|
||||
"@types/react": "18.0.27",
|
||||
"@types/react-dom": "18.0.10",
|
||||
"esbuild": "^0.17.5",
|
||||
"eslint": "8.33.0",
|
||||
"eslint-config-next": "13.1.6",
|
||||
"glob": "^8.1.0",
|
||||
"mongodb": "5.0",
|
||||
"next": "13.1.6",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
|
||||
101
pages/api/tool.ts
Normal file
101
pages/api/tool.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import fs from "fs";
|
||||
import { store, html } from "@/store";
|
||||
import glob from "glob";
|
||||
import { promisify } from "util";
|
||||
const g = promisify(glob);
|
||||
const read = promisify(fs.readFile);
|
||||
|
||||
// 索引与工时
|
||||
const indexToHour: Record<string, number> = JSON.parse(
|
||||
fs.readFileSync("./hours.json", "utf8")
|
||||
).selections;
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse<Record<string, string>>
|
||||
) {
|
||||
// 读入全部json文件
|
||||
// users: {姓名: {坐标: 权重}}
|
||||
const users: Record<string, Record<string, number>> = {};
|
||||
const files = await g("./json/*.json");
|
||||
for (const file of files) {
|
||||
const jsonStr = await read(file, "utf8");
|
||||
const json: {
|
||||
user: string;
|
||||
selections: Record<string, number>;
|
||||
} = JSON.parse(jsonStr);
|
||||
|
||||
// Normalization
|
||||
// 使用 标准分数 算法 z = (x - mean) / std
|
||||
const { selections } = json;
|
||||
const nums = Object.values(selections);
|
||||
const mean = nums.reduce((a, b) => a + b) / nums.length;
|
||||
const std = Math.sqrt(
|
||||
nums.map((x) => Math.pow(x - mean, 2)).reduce((a, b) => a + b) /
|
||||
nums.length
|
||||
);
|
||||
const normalizedNums = nums.map((x) => (std === 0 ? 0 : (x - mean) / std));
|
||||
for (const index in selections) {
|
||||
selections[index] = std === 0 ? 0 : (selections[index] - mean) / std;
|
||||
}
|
||||
users[json.user] = selections;
|
||||
}
|
||||
// 计算每一个格子有多少人选择
|
||||
// counts: {坐标: {姓名: 权重}}
|
||||
const counts: Record<string, Record<string, Record<string, number>>> = {};
|
||||
for (const user in users) {
|
||||
for (const select in users[user]) {
|
||||
if (counts[select] === undefined) counts[select] = {};
|
||||
counts[select][user] = users[user];
|
||||
}
|
||||
}
|
||||
|
||||
// 构造返回数据, key 为 坐标,value 为姓名
|
||||
const resp: Record<string, string> = {};
|
||||
|
||||
// 找到选择数量最少的格子
|
||||
// sortable: [[坐标, 选择人数]]
|
||||
// 如果遇到选择数量相同的格子,随机打乱顺序进行迭代
|
||||
const sortable: [string, number][] = [];
|
||||
for (const index in counts) {
|
||||
sortable.push([index, Object.keys(counts[index]).length]);
|
||||
}
|
||||
sortable.sort((a, b) => a[1] - b[1] || Math.random() - 0.5);
|
||||
|
||||
// 记录这个人的出现次数,还有这个人的工时总数
|
||||
const hoursCount: Record<string, number> = {};
|
||||
|
||||
for (const [smallestIndex, _] of sortable) {
|
||||
// console.log("smallestIndex", smallestIndex);
|
||||
// console.log("cell", counts[smallestIndex]);
|
||||
// 找到格子里权重最低的人选 [姓名, 小时数, 出现次数, 权重]
|
||||
const weightList: [string, number, number][] = [];
|
||||
for (const user in counts[smallestIndex]) {
|
||||
weightList.push([
|
||||
user,
|
||||
hoursCount[user] || 0,
|
||||
counts[smallestIndex][user][smallestIndex],
|
||||
]);
|
||||
}
|
||||
weightList.sort((a, b) => a[1] - b[1] || a[2] - b[2]);
|
||||
// console.log("weightList", weightList);
|
||||
const theChoosenUser = weightList[0][0];
|
||||
// console.log("theChoosenUser", theChoosenUser);
|
||||
// 记录结果
|
||||
resp[smallestIndex] = theChoosenUser;
|
||||
hoursCount[theChoosenUser] =
|
||||
(hoursCount[theChoosenUser] || 0) + indexToHour[smallestIndex];
|
||||
}
|
||||
// console.log("hoursCount", hoursCount);
|
||||
|
||||
const sortedHoursCount: [string, number][] = [];
|
||||
for (const user in hoursCount) {
|
||||
sortedHoursCount.push([user, hoursCount[user]]);
|
||||
}
|
||||
sortedHoursCount.sort((a, b) => a[1] - b[1]);
|
||||
console.log("sortedHoursCount", sortedHoursCount);
|
||||
console.log("sortedHoursCount.length", sortedHoursCount.length);
|
||||
|
||||
res.status(200).json(resp);
|
||||
}
|
||||
50
pages/report-tool.tsx
Normal file
50
pages/report-tool.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
import React from "react";
|
||||
import Head from "next/head";
|
||||
|
||||
const ReportPage = () => {
|
||||
const ref = React.useRef();
|
||||
const getReport = async () => {
|
||||
const resp = await fetch("/api/html").then((resp) => resp.json());
|
||||
ref.current.innerHTML = resp.html;
|
||||
const json: Record<string, string> = await fetch("/api/tool").then(
|
||||
(resp) => resp.json()
|
||||
);
|
||||
const table = ref.current.children[0];
|
||||
const tbody = table.children[table.children.length - 1];
|
||||
for (const tr_index in tbody.children) {
|
||||
const tr = tbody.children[tr_index];
|
||||
for (const td_index in tr.children) {
|
||||
const td = tr.children[td_index];
|
||||
if (td.tagName !== "TD") continue;
|
||||
const index = `${tr_index},${td_index}`;
|
||||
if (json[index] === undefined) continue;
|
||||
td.innerHTML = json[index];
|
||||
}
|
||||
}
|
||||
};
|
||||
React.useEffect(() => {
|
||||
getReport();
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Create Next App</title>
|
||||
<meta name="description" content="Generated by create next app" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
<main>
|
||||
<button onClick={async () => getReport()}>Refresh</button>
|
||||
<div
|
||||
ref={ref}
|
||||
onInput={(event) => {
|
||||
console.log(event.currentTarget.innerHTML);
|
||||
}}
|
||||
contentEditable="true"
|
||||
></div>
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ReportPage;
|
||||
55
pages/tool.tsx
Normal file
55
pages/tool.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import React from "react";
|
||||
import Head from "next/head";
|
||||
import Timetable from "@/components/Timetable";
|
||||
|
||||
export default function Home() {
|
||||
const [user, setUser] = React.useState("");
|
||||
const [begin, setBegin] = React.useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
setUser(localStorage.getItem("user") || "");
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Create Next App</title>
|
||||
<meta name="description" content="Generated by create next app" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
<main>
|
||||
{!begin && (
|
||||
<div>
|
||||
<input
|
||||
placeholder="在这输你的名字"
|
||||
value={user}
|
||||
onChange={(event) => setUser(event.target.value)}
|
||||
/>
|
||||
<button
|
||||
onClick={() => {
|
||||
if (user.trim() === "") {
|
||||
alert("姓名不能为空");
|
||||
return;
|
||||
}
|
||||
setUser(user.trim());
|
||||
setBegin(true);
|
||||
localStorage.setItem("user", user);
|
||||
}}
|
||||
>
|
||||
Login
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{begin && (
|
||||
<Timetable
|
||||
user={user}
|
||||
disableConflictCheck={true}
|
||||
disableNetwork={true}
|
||||
replaceInputType={"number"}
|
||||
/>
|
||||
)}
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,3 +1,10 @@
|
||||
import fs from "fs";
|
||||
import { MongoClient } from "mongodb";
|
||||
import util from "util";
|
||||
|
||||
const write = util.promisify(fs.writeFile);
|
||||
const read = util.promisify(fs.readFile);
|
||||
|
||||
class Store {
|
||||
record: Record<string, string>;
|
||||
constructor() {
|
||||
@@ -27,13 +34,20 @@ class Store {
|
||||
class HTML {
|
||||
html: string;
|
||||
constructor() {
|
||||
this.html = "";
|
||||
// load from file
|
||||
try {
|
||||
this.html = fs.readFileSync("./html.html", "utf8");
|
||||
} catch {
|
||||
this.html = "";
|
||||
}
|
||||
}
|
||||
public get() {
|
||||
return this.html;
|
||||
}
|
||||
public set(html) {
|
||||
public async set(html: string) {
|
||||
this.html = html;
|
||||
// store into file
|
||||
await write("./html.html", html, "utf8");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user