add raw data for radar
Some checks failed
Deploy / deploy (push) Has been cancelled

This commit is contained in:
2026-01-04 09:19:40 +08:00
parent a4ebf245c4
commit fab689ffdf
8 changed files with 551 additions and 399 deletions

188
package-lock.json generated
View File

@@ -40,11 +40,11 @@
"vue-router": "^4.6.4",
"y-codemirror.next": "^0.3.5",
"y-webrtc": "^10.3.0",
"yjs": "^13.6.28"
"yjs": "^13.6.29"
},
"devDependencies": {
"@iconify/vue": "^5.0.0",
"@rsbuild/core": "^1.6.15",
"@rsbuild/core": "^1.7.1",
"@rsbuild/plugin-vue": "^1.2.2",
"@types/canvas-confetti": "^1.9.0",
"@types/node": "^25.0.3",
@@ -581,9 +581,9 @@
}
},
"node_modules/@emnapi/core": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz",
"integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==",
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.0.tgz",
"integrity": "sha512-ryJnSmj4UhrGLZZPJ6PKVb4wNPAIkW6iyLy+0TRwazd3L1u0wzMe8RfqevAh2HbcSkoeLiSYnOVDOys4JSGYyg==",
"dev": true,
"license": "MIT",
"optional": true,
@@ -593,9 +593,9 @@
}
},
"node_modules/@emnapi/runtime": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz",
"integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==",
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.0.tgz",
"integrity": "sha512-Z82FDl1ByxqPEPrAYYeTQVlx2FSHPe1qwX465c+96IRS3fTdSYRoJcRxg3g2fEG5I69z1dSEWQlNRRr0/677mg==",
"dev": true,
"license": "MIT",
"optional": true,
@@ -923,62 +923,62 @@
}
},
"node_modules/@module-federation/error-codes": {
"version": "0.21.6",
"resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-0.21.6.tgz",
"integrity": "sha512-MLJUCQ05KnoVl8xd6xs9a5g2/8U+eWmVxg7xiBMeR0+7OjdWUbHwcwgVFatRIwSZvFgKHfWEiI7wsU1q1XbTRQ==",
"version": "0.22.0",
"resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-0.22.0.tgz",
"integrity": "sha512-xF9SjnEy7vTdx+xekjPCV5cIHOGCkdn3pIxo9vU7gEZMIw0SvAEdsy6Uh17xaCpm8V0FWvR0SZoK9Ik6jGOaug==",
"dev": true,
"license": "MIT"
},
"node_modules/@module-federation/runtime": {
"version": "0.21.6",
"resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.21.6.tgz",
"integrity": "sha512-+caXwaQqwTNh+CQqyb4mZmXq7iEemRDrTZQGD+zyeH454JAYnJ3s/3oDFizdH6245pk+NiqDyOOkHzzFQorKhQ==",
"version": "0.22.0",
"resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.22.0.tgz",
"integrity": "sha512-38g5iPju2tPC3KHMPxRKmy4k4onNp6ypFPS1eKGsNLUkXgHsPMBFqAjDw96iEcjri91BrahG4XcdyKi97xZzlA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@module-federation/error-codes": "0.21.6",
"@module-federation/runtime-core": "0.21.6",
"@module-federation/sdk": "0.21.6"
"@module-federation/error-codes": "0.22.0",
"@module-federation/runtime-core": "0.22.0",
"@module-federation/sdk": "0.22.0"
}
},
"node_modules/@module-federation/runtime-core": {
"version": "0.21.6",
"resolved": "https://registry.npmjs.org/@module-federation/runtime-core/-/runtime-core-0.21.6.tgz",
"integrity": "sha512-5Hd1Y5qp5lU/aTiK66lidMlM/4ji2gr3EXAtJdreJzkY+bKcI5+21GRcliZ4RAkICmvdxQU5PHPL71XmNc7Lsw==",
"version": "0.22.0",
"resolved": "https://registry.npmjs.org/@module-federation/runtime-core/-/runtime-core-0.22.0.tgz",
"integrity": "sha512-GR1TcD6/s7zqItfhC87zAp30PqzvceoeDGYTgF3Vx2TXvsfDrhP6Qw9T4vudDQL3uJRne6t7CzdT29YyVxlgIA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@module-federation/error-codes": "0.21.6",
"@module-federation/sdk": "0.21.6"
"@module-federation/error-codes": "0.22.0",
"@module-federation/sdk": "0.22.0"
}
},
"node_modules/@module-federation/runtime-tools": {
"version": "0.21.6",
"resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-0.21.6.tgz",
"integrity": "sha512-fnP+ZOZTFeBGiTAnxve+axGmiYn2D60h86nUISXjXClK3LUY1krUfPgf6MaD4YDJ4i51OGXZWPekeMe16pkd8Q==",
"version": "0.22.0",
"resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-0.22.0.tgz",
"integrity": "sha512-4ScUJ/aUfEernb+4PbLdhM/c60VHl698Gn1gY21m9vyC1Ucn69fPCA1y2EwcCB7IItseRMoNhdcWQnzt/OPCNA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@module-federation/runtime": "0.21.6",
"@module-federation/webpack-bundler-runtime": "0.21.6"
"@module-federation/runtime": "0.22.0",
"@module-federation/webpack-bundler-runtime": "0.22.0"
}
},
"node_modules/@module-federation/sdk": {
"version": "0.21.6",
"resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.21.6.tgz",
"integrity": "sha512-x6hARETb8iqHVhEsQBysuWpznNZViUh84qV2yE7AD+g7uIzHKiYdoWqj10posbo5XKf/147qgWDzKZoKoEP2dw==",
"version": "0.22.0",
"resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.22.0.tgz",
"integrity": "sha512-x4aFNBKn2KVQRuNVC5A7SnrSCSqyfIWmm1DvubjbO9iKFe7ith5niw8dqSFBekYBg2Fwy+eMg4sEFNVvCAdo6g==",
"dev": true,
"license": "MIT"
},
"node_modules/@module-federation/webpack-bundler-runtime": {
"version": "0.21.6",
"resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-0.21.6.tgz",
"integrity": "sha512-7zIp3LrcWbhGuFDTUMLJ2FJvcwjlddqhWGxi/MW3ur1a+HaO8v5tF2nl+vElKmbG1DFLU/52l3PElVcWf/YcsQ==",
"version": "0.22.0",
"resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-0.22.0.tgz",
"integrity": "sha512-aM8gCqXu+/4wBmJtVeMeeMN5guw3chf+2i6HajKtQv7SJfxV/f4IyNQJUeUQu9HfiAZHjqtMV5Lvq/Lvh8LdyA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@module-federation/runtime": "0.21.6",
"@module-federation/sdk": "0.21.6"
"@module-federation/runtime": "0.22.0",
"@module-federation/sdk": "0.22.0"
}
},
"node_modules/@napi-rs/wasm-runtime": {
@@ -995,16 +995,16 @@
}
},
"node_modules/@rsbuild/core": {
"version": "1.6.15",
"resolved": "https://registry.npmjs.org/@rsbuild/core/-/core-1.6.15.tgz",
"integrity": "sha512-LvoOF53PL6zXgdzEhgnnP51S4FseDFH1bHrobK4EK6zZX/tN8qgf5tdlmN7h4OkMv/Qs1oUfvj0QcLWSstnnvA==",
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/@rsbuild/core/-/core-1.7.1.tgz",
"integrity": "sha512-ULIE/Qh+Ne80Pm/aUPbRHUvwvIzpap07jYNFB47azI8w5Q3sDEC4Gn574jsluT/42iNDsZTFADRBog9FEvtN9Q==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@rspack/core": "1.6.8",
"@rspack/core": "1.7.0",
"@rspack/lite-tapable": "~1.1.0",
"@swc/helpers": "^0.5.17",
"@swc/helpers": "^0.5.18",
"core-js": "~3.47.0",
"jiti": "^2.6.1"
},
@@ -1030,28 +1030,28 @@
}
},
"node_modules/@rspack/binding": {
"version": "1.6.8",
"resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.6.8.tgz",
"integrity": "sha512-lUeL4mbwGo+nqRKqFDCm9vH2jv9FNMVt1X8jqayWRcOCPlj/2UVMEFgqjR7Pp2vlvnTKq//31KbDBJmDZq31RQ==",
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.7.0.tgz",
"integrity": "sha512-xO+pZKG2dvU9CuRTTi+DcCc4p+CZhBJlvuYikBja/0a62cTntQV2PWV+/xU1a6Vbo89yNz158LR05nvjtKVwTw==",
"dev": true,
"license": "MIT",
"optionalDependencies": {
"@rspack/binding-darwin-arm64": "1.6.8",
"@rspack/binding-darwin-x64": "1.6.8",
"@rspack/binding-linux-arm64-gnu": "1.6.8",
"@rspack/binding-linux-arm64-musl": "1.6.8",
"@rspack/binding-linux-x64-gnu": "1.6.8",
"@rspack/binding-linux-x64-musl": "1.6.8",
"@rspack/binding-wasm32-wasi": "1.6.8",
"@rspack/binding-win32-arm64-msvc": "1.6.8",
"@rspack/binding-win32-ia32-msvc": "1.6.8",
"@rspack/binding-win32-x64-msvc": "1.6.8"
"@rspack/binding-darwin-arm64": "1.7.0",
"@rspack/binding-darwin-x64": "1.7.0",
"@rspack/binding-linux-arm64-gnu": "1.7.0",
"@rspack/binding-linux-arm64-musl": "1.7.0",
"@rspack/binding-linux-x64-gnu": "1.7.0",
"@rspack/binding-linux-x64-musl": "1.7.0",
"@rspack/binding-wasm32-wasi": "1.7.0",
"@rspack/binding-win32-arm64-msvc": "1.7.0",
"@rspack/binding-win32-ia32-msvc": "1.7.0",
"@rspack/binding-win32-x64-msvc": "1.7.0"
}
},
"node_modules/@rspack/binding-darwin-arm64": {
"version": "1.6.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.6.8.tgz",
"integrity": "sha512-e8CTQtzaeGnf+BIzR7wRMUwKfIg0jd/sxMRc1Vd0bCMHBhSN9EsGoMuJJaKeRrSmy2nwMCNWHIG+TvT1CEKg+A==",
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.7.0.tgz",
"integrity": "sha512-HMYrhvVh3sMRBXl6cSI2JqsvlHJKQ42qX+Sw4qbj7LeZBN6Gv4GjfL3cXRLUTdO37FOC0uLEUYgxVXetx/Y4sA==",
"cpu": [
"arm64"
],
@@ -1063,9 +1063,9 @@
]
},
"node_modules/@rspack/binding-darwin-x64": {
"version": "1.6.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.6.8.tgz",
"integrity": "sha512-ku1XpTEPt6Za11zhpFWhfwrTQogcgi9RJrOUVC4FESiPO9aKyd4hJ+JiPgLY0MZOqsptK6vEAgOip+uDVXrCpg==",
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.7.0.tgz",
"integrity": "sha512-R/SoR04ySmHPqoIBGC+SjP9zRGjL1fS908mdwBvQ1RfFinKu7a/o/5rxH/vxUUsVQrHCyX+o7YXpfWq9xpvyQA==",
"cpu": [
"x64"
],
@@ -1077,9 +1077,9 @@
]
},
"node_modules/@rspack/binding-linux-arm64-gnu": {
"version": "1.6.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.6.8.tgz",
"integrity": "sha512-fvZX6xZPvBT8qipSpvkKMX5M7yd2BSpZNCZXcefw6gA3uC7LI3gu+er0LrDXY1PtPzVuHTyDx+abwWpagV3PiQ==",
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.7.0.tgz",
"integrity": "sha512-jDCcso++qshu58+Iuo6oiL0XKuX04lDugL0qwrWHW8SS/EjZ2rc1J3yQx+XDW0PCQsfI2c9ji0IOW56PzW1hXQ==",
"cpu": [
"arm64"
],
@@ -1091,9 +1091,9 @@
]
},
"node_modules/@rspack/binding-linux-arm64-musl": {
"version": "1.6.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.6.8.tgz",
"integrity": "sha512-++XMKcMNrt59HcFBLnRaJcn70k3X0GwkAegZBVpel8xYIAgvoXT5+L8P1ExId/yTFxqedaz8DbcxQnNmMozviw==",
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.7.0.tgz",
"integrity": "sha512-0W49s0SQQhr3hZ8Zd7Auyf2pv4OTBr6wQhgWUQ6XeeMEjB16KpAVypSK5Jpn1ON0v9jAPLdod+a255rz8/f3kg==",
"cpu": [
"arm64"
],
@@ -1105,9 +1105,9 @@
]
},
"node_modules/@rspack/binding-linux-x64-gnu": {
"version": "1.6.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.6.8.tgz",
"integrity": "sha512-tv3BWkTE1TndfX+DsE1rSTg8fBevCxujNZ3MlfZ22Wfy9x1FMXTJlWG8VIOXmaaJ1wUHzv8S7cE2YUUJ2LuiCg==",
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.7.0.tgz",
"integrity": "sha512-oFjzjTD1MmG0ucAaP0Wyg9eobrsnFwZjEHa7LwyzWDRBeC3GWAF9T04Bqd6Ba6DgASGzU0BjEJcUpjvtXxO95Q==",
"cpu": [
"x64"
],
@@ -1119,9 +1119,9 @@
]
},
"node_modules/@rspack/binding-linux-x64-musl": {
"version": "1.6.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-1.6.8.tgz",
"integrity": "sha512-DCGgZ5/in1O3FjHWqXnDsncRy+48cMhfuUAAUyl0yDj1NpsZu9pP+xfGLvGcQTiYrVl7IH9Aojf1eShP/77WGA==",
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-1.7.0.tgz",
"integrity": "sha512-MNGslPLOsurdwOcoo6r0u8mLpw1ADar3hkx67WzwwMqYnem/Ky0aANJC2JvQHPC22mu01gCOukHYyEaUFTxcuw==",
"cpu": [
"x64"
],
@@ -1133,9 +1133,9 @@
]
},
"node_modules/@rspack/binding-wasm32-wasi": {
"version": "1.6.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-1.6.8.tgz",
"integrity": "sha512-VUwdhl/lI4m6o1OGCZ9JwtMjTV/yLY5VZTQdEPKb40JMTlmZ5MBlr5xk7ByaXXYHr6I+qnqEm73iMKQvg6iknw==",
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-1.7.0.tgz",
"integrity": "sha512-eaZzkGpxzVESmaX/UALMiQO+eNppe/i1VWQksGRfdoUu0rILqr/YDjsWFTcpbI9Dt3fg2kshHawBHxfwtxHcZQ==",
"cpu": [
"wasm32"
],
@@ -1147,9 +1147,9 @@
}
},
"node_modules/@rspack/binding-win32-arm64-msvc": {
"version": "1.6.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.6.8.tgz",
"integrity": "sha512-23YX7zlOZlub+nPGDBUzktb4D5D6ETUAluKjXEeHIZ9m7fSlEYBnGL66YE+3t1DHXGd0OqsdwlvrNGcyo6EXDQ==",
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.7.0.tgz",
"integrity": "sha512-XFg4l7sOhupnpG0soOfzYLeF2cgpSJMenmjmdzd9y06CotTyVId0hNoS7y+A7hEP8XGf3YPbdiUL5UDp6+DRBA==",
"cpu": [
"arm64"
],
@@ -1161,9 +1161,9 @@
]
},
"node_modules/@rspack/binding-win32-ia32-msvc": {
"version": "1.6.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.6.8.tgz",
"integrity": "sha512-cFgRE3APxrY4AEdooVk2LtipwNNT/9mrnjdC5lVbsIsz+SxvGbZR231bxDJEqP15+RJOaD07FO1sIjINFqXMEg==",
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.7.0.tgz",
"integrity": "sha512-eWt2XV6la/c0IlU/18RlhQsqwHGShSypwA3kt4s/dpfOK0YB1h4f0fYeUZuvj2X0MIoJQGhMofMrgA35/IcAcw==",
"cpu": [
"ia32"
],
@@ -1175,9 +1175,9 @@
]
},
"node_modules/@rspack/binding-win32-x64-msvc": {
"version": "1.6.8",
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.6.8.tgz",
"integrity": "sha512-cIuhVsZYd3o3Neo1JSAhJYw6BDvlxaBoqvgwRkG1rs0ExFmEmgYyG7ip9pFKnKNWph/tmW3rDYypmEfjs1is7g==",
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.7.0.tgz",
"integrity": "sha512-LOL5G8rfbAwlmusx+t98r9QzuGRz+L9Bg+8s5s6K/Qe64iemcNIuxGr5QLVq1jLa0SGNTeog4N21pAzlkWh4jw==",
"cpu": [
"x64"
],
@@ -1189,14 +1189,14 @@
]
},
"node_modules/@rspack/core": {
"version": "1.6.8",
"resolved": "https://registry.npmjs.org/@rspack/core/-/core-1.6.8.tgz",
"integrity": "sha512-FolcIAH5FW4J2FET+qwjd1kNeFbCkd0VLuIHO0thyolEjaPSxw5qxG67DA7BZGm6PVcoiSgPLks1DL6eZ8c+fA==",
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/@rspack/core/-/core-1.7.0.tgz",
"integrity": "sha512-uDxPQsPh/+2DnOISuKnUiXZ9M0y2G1BOsI0IesxPJGp42ME2QW7axbJfUqD3bwp4bi3RN2zqh56NgxU/XETQvA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@module-federation/runtime-tools": "0.21.6",
"@rspack/binding": "1.6.8",
"@module-federation/runtime-tools": "0.22.0",
"@rspack/binding": "1.7.0",
"@rspack/lite-tapable": "1.1.0"
},
"engines": {
@@ -1219,9 +1219,9 @@
"license": "MIT"
},
"node_modules/@swc/helpers": {
"version": "0.5.17",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz",
"integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==",
"version": "0.5.18",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.18.tgz",
"integrity": "sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
@@ -6022,9 +6022,9 @@
}
},
"node_modules/yjs": {
"version": "13.6.28",
"resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.28.tgz",
"integrity": "sha512-EgnDOXs8+hBVm6mq3/S89Kiwzh5JRbn7w2wXwbrMRyKy/8dOFsLvuIfC+x19ZdtaDc0tA9rQmdZzbqqNHG44wA==",
"version": "13.6.29",
"resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.29.tgz",
"integrity": "sha512-kHqDPdltoXH+X4w1lVmMtddE3Oeqq48nM40FD5ojTd8xYhQpzIDcfE2keMSU5bAgRPJBe225WTUdyUgj1DtbiQ==",
"license": "MIT",
"peer": true,
"dependencies": {

View File

@@ -42,11 +42,11 @@
"vue-router": "^4.6.4",
"y-codemirror.next": "^0.3.5",
"y-webrtc": "^10.3.0",
"yjs": "^13.6.28"
"yjs": "^13.6.29"
},
"devDependencies": {
"@iconify/vue": "^5.0.0",
"@rsbuild/core": "^1.6.15",
"@rsbuild/core": "^1.7.1",
"@rsbuild/plugin-vue": "^1.2.2",
"@types/canvas-confetti": "^1.9.0",
"@types/node": "^25.0.3",

View File

@@ -143,7 +143,11 @@ export function getActivityRank(start: string) {
})
}
export function getClassRank(offset: number, limit: number, grade?: number | null) {
export function getClassRank(
offset: number,
limit: number,
grade?: number | null,
) {
return http.get("class_rank", {
params: { offset, limit, grade },
})
@@ -155,7 +159,11 @@ export function getUserClassRank(offset: number, limit: number) {
})
}
export function getClassPK(classNames: string[], startTime?: string, endTime?: string) {
export function getClassPK(
classNames: string[],
startTime?: string,
endTime?: string,
) {
const payload: any = {
class_name: classNames,
}

View File

@@ -118,4 +118,3 @@ onMounted(init)
/>
</n-flex>
</template>

View File

@@ -384,6 +384,14 @@ const radarChartData = computed(() => {
const datasets = comparisons.value.map((c, index) => {
const color = getClassColor(index)
const rawData = [
c.total_ac,
c.avg_ac,
c.median_ac,
c.excellent_rate,
c.pass_rate,
c.active_rate,
]
return {
label: c.class_name,
data: [
@@ -394,6 +402,7 @@ const radarChartData = computed(() => {
c.pass_rate,
c.active_rate,
],
rawData,
backgroundColor: color.bg,
borderColor: color.border,
borderWidth: 2,
@@ -466,6 +475,28 @@ const radarChartOptions = {
legend: {
position: "bottom" as const,
},
tooltip: {
callbacks: {
label: function (context: any) {
const dataset = context.dataset as any
const rawValue = dataset?.rawData?.[context.dataIndex]
const metric = context.label || ""
const isRate = context.dataIndex >= 3
if (rawValue === undefined || rawValue === null) {
return `${dataset.label || ""}: ${context.parsed.r?.toFixed(2) ?? ""}`
}
const formatted = Number.isFinite(rawValue)
? isRate
? rawValue.toFixed(1)
: Number.isInteger(rawValue)
? rawValue.toString()
: rawValue.toFixed(2)
: String(rawValue)
const suffix = isRate ? "%" : ""
return `${dataset.label || ""} - ${metric}: ${formatted}${suffix}`
},
},
},
},
scales: {
r: {
@@ -485,7 +516,10 @@ const radarChartOptions = {
<n-h2 style="margin-bottom: 0">班级PK</n-h2>
<n-flex :wrap="false" align="flex-start" :size="16">
<n-form-item label="选择班级至少2个" style="width: 300px; margin-bottom: 0">
<n-form-item
label="选择班级至少2个"
style="width: 300px; margin-bottom: 0"
>
<n-select
v-model:value="selectedClasses"
:options="classOptions"
@@ -494,7 +528,10 @@ const radarChartOptions = {
/>
</n-form-item>
<n-form-item label="时间段(可选)" style="width: 200px; margin-bottom: 0">
<n-form-item
label="时间段(可选)"
style="width: 200px; margin-bottom: 0"
>
<n-select
v-model:value="duration"
:options="timeRangeOptions"
@@ -504,7 +541,12 @@ const radarChartOptions = {
/>
</n-form-item>
<n-button type="primary" @click="compare" :loading="loading" style="margin-top: 26px">
<n-button
type="primary"
@click="compare"
:loading="loading"
style="margin-top: 26px"
>
开始PK
</n-button>
</n-flex>
@@ -516,7 +558,10 @@ const radarChartOptions = {
:x-gap="16"
:y-gap="16"
>
<n-gi v-for="(classData, index) in comparisons" :key="classData.class_name">
<n-gi
v-for="(classData, index) in comparisons"
:key="classData.class_name"
>
<n-card
:title="classData.class_name"
:bordered="true"
@@ -544,7 +589,12 @@ const radarChartOptions = {
<!-- AC核心指标 - 突出显示便于横向对比 -->
<n-grid :cols="5" :x-gap="8" responsive="screen">
<n-gi>
<n-statistic label="总AC数" :value="classData.total_ac" size="large" class="stat-total-ac">
<n-statistic
label="总AC数"
:value="classData.total_ac"
size="large"
class="stat-total-ac"
>
<template #suffix>
<Icon icon="streamline-emojis:raised-fist-1" width="20" />
</template>
@@ -603,43 +653,71 @@ const radarChartOptions = {
<n-divider style="margin: 12px 0" />
<!-- 详细统计 - 紧凑布局统一格式 -->
<n-descriptions bordered :column="2" size="small" label-placement="left">
<n-descriptions
bordered
:column="2"
size="small"
label-placement="left"
>
<!-- 分位数统计 -->
<n-descriptions-item label="第一四分位数(Q1)">
<span style="color: #9254de; font-weight: 500">{{ classData.q1_ac.toFixed(2) }}</span>
<span style="color: #9254de; font-weight: 500">{{
classData.q1_ac.toFixed(2)
}}</span>
</n-descriptions-item>
<n-descriptions-item label="第三四分位数(Q3)">
<span style="color: #f759ab; font-weight: 500">{{ classData.q3_ac.toFixed(2) }}</span>
<span style="color: #f759ab; font-weight: 500">{{
classData.q3_ac.toFixed(2)
}}</span>
</n-descriptions-item>
<n-descriptions-item label="四分位距(IQR)">
<span style="color: #13c2c2; font-weight: 500">{{ classData.iqr.toFixed(2) }}</span>
<span style="color: #13c2c2; font-weight: 500">{{
classData.iqr.toFixed(2)
}}</span>
</n-descriptions-item>
<n-descriptions-item label="标准差">
<span style="color: #fa8c16; font-weight: 500">{{ classData.std_dev.toFixed(2) }}</span>
<span style="color: #fa8c16; font-weight: 500">{{
classData.std_dev.toFixed(2)
}}</span>
</n-descriptions-item>
<!-- 分层统计 -->
<n-descriptions-item label="前10名平均">
<span style="color: #cf1322; font-weight: 600">{{ classData.top_10_avg.toFixed(2) }}</span>
<span style="color: #cf1322; font-weight: 600">{{
classData.top_10_avg.toFixed(2)
}}</span>
</n-descriptions-item>
<n-descriptions-item label="后10名平均">
<span style="color: #096dd9; font-weight: 500">{{ classData.bottom_10_avg.toFixed(2) }}</span>
<span style="color: #096dd9; font-weight: 500">{{
classData.bottom_10_avg.toFixed(2)
}}</span>
</n-descriptions-item>
<n-descriptions-item label="前25%平均">
<span style="color: #f5222d; font-weight: 600">{{ classData.top_25_avg.toFixed(2) }}</span>
<span style="color: #f5222d; font-weight: 600">{{
classData.top_25_avg.toFixed(2)
}}</span>
</n-descriptions-item>
<n-descriptions-item label="后25%平均">
<span style="color: #531dab; font-weight: 500">{{ classData.bottom_25_avg.toFixed(2) }}</span>
<span style="color: #531dab; font-weight: 500">{{
classData.bottom_25_avg.toFixed(2)
}}</span>
</n-descriptions-item>
<!-- 人数 -->
<n-descriptions-item label="人数">
<span style="color: #1890ff; font-weight: 600">{{ classData.user_count }}</span>
<span style="color: #1890ff; font-weight: 600">{{
classData.user_count
}}</span>
</n-descriptions-item>
</n-descriptions>
<!-- 比率统计 - 使用进度条图表 -->
<n-card size="small" title="比率统计" embedded style="margin-top: 12px">
<n-card
size="small"
title="比率统计"
embedded
style="margin-top: 12px"
>
<n-space vertical :size="10">
<n-progress
type="line"
@@ -680,22 +758,37 @@ const radarChartOptions = {
<template
v-if="hasTimeRange && classData.recent_total_ac !== undefined"
>
<n-descriptions bordered :column="2" size="small" label-placement="left" style="margin-top: 12px">
<n-descriptions
bordered
:column="2"
size="small"
label-placement="left"
style="margin-top: 12px"
>
<n-descriptions-item label="时间段总AC">
<span style="color: #ff7875; font-weight: 600">{{ classData.recent_total_ac }}</span>
<span style="color: #ff7875; font-weight: 600">{{
classData.recent_total_ac
}}</span>
</n-descriptions-item>
<n-descriptions-item label="时间段平均AC">
<span style="color: #73d13d; font-weight: 600">{{ classData.recent_avg_ac?.toFixed(2) }}</span>
<span style="color: #73d13d; font-weight: 600">{{
classData.recent_avg_ac?.toFixed(2)
}}</span>
</n-descriptions-item>
<n-descriptions-item label="时间段中位数AC">
<span style="color: #ffc53d; font-weight: 600">{{ classData.recent_median_ac?.toFixed(2) }}</span>
<span style="color: #ffc53d; font-weight: 600">{{
classData.recent_median_ac?.toFixed(2)
}}</span>
</n-descriptions-item>
<n-descriptions-item label="时间段前10名平均">
<span style="color: #ff4d4f; font-weight: 600">{{ classData.recent_top_10_avg?.toFixed(2) }}</span>
<span style="color: #ff4d4f; font-weight: 600">{{
classData.recent_top_10_avg?.toFixed(2)
}}</span>
</n-descriptions-item>
<n-descriptions-item label="活跃学生数" :span="2">
<span style="color: #1890ff; font-weight: 600">{{ classData.recent_active_count }}</span>
<span style="color: #1890ff; font-weight: 600">{{
classData.recent_active_count
}}</span>
</n-descriptions-item>
</n-descriptions>
</template>
@@ -827,7 +920,11 @@ const radarChartOptions = {
</template>
<!-- 对比表格 -->
<n-card v-if="comparisons.length > 0" title="对比表格" style="margin-top: 20px">
<n-card
v-if="comparisons.length > 0"
title="对比表格"
style="margin-top: 20px"
>
<n-data-table
:data="comparisons"
:columns="[
@@ -842,48 +939,93 @@ const radarChartOptions = {
title: '人数',
key: 'user_count',
width: 80,
render: (row) => h('span', { style: { color: '#1890ff', fontWeight: '600' } }, row.user_count),
render: (row) =>
h(
'span',
{ style: { color: '#1890ff', fontWeight: '600' } },
row.user_count,
),
},
{
title: '总AC数',
key: 'total_ac',
width: 100,
render: (row) => h('span', { style: { color: '#ff4d4f', fontWeight: '600' } }, row.total_ac),
render: (row) =>
h(
'span',
{ style: { color: '#ff4d4f', fontWeight: '600' } },
row.total_ac,
),
},
{
title: '平均AC',
key: 'avg_ac',
render: (row) => h('span', { style: { color: '#52c41a', fontWeight: '600' } }, row.avg_ac.toFixed(2)),
render: (row) =>
h(
'span',
{ style: { color: '#52c41a', fontWeight: '600' } },
row.avg_ac.toFixed(2),
),
},
{
title: '中位数AC',
key: 'median_ac',
render: (row) => h('span', { style: { color: '#fa8c16', fontWeight: '600' } }, row.median_ac.toFixed(2)),
render: (row) =>
h(
'span',
{ style: { color: '#fa8c16', fontWeight: '600' } },
row.median_ac.toFixed(2),
),
},
{
title: '前10名平均',
key: 'top_10_avg',
render: (row) => h('span', { style: { color: '#cf1322', fontWeight: '600' } }, row.top_10_avg.toFixed(2)),
render: (row) =>
h(
'span',
{ style: { color: '#cf1322', fontWeight: '600' } },
row.top_10_avg.toFixed(2),
),
},
{
title: '后10名平均',
key: 'bottom_10_avg',
render: (row) => h('span', { style: { color: '#096dd9', fontWeight: '500' } }, row.bottom_10_avg.toFixed(2)),
render: (row) =>
h(
'span',
{ style: { color: '#096dd9', fontWeight: '500' } },
row.bottom_10_avg.toFixed(2),
),
},
{
title: '优秀率',
key: 'excellent_rate',
render: (row) => h('span', { style: { color: '#faad14', fontWeight: '600' } }, row.excellent_rate.toFixed(1) + '%'),
render: (row) =>
h(
'span',
{ style: { color: '#faad14', fontWeight: '600' } },
row.excellent_rate.toFixed(1) + '%',
),
},
{
title: '及格率',
key: 'pass_rate',
render: (row) => h('span', { style: { color: '#52c41a', fontWeight: '600' } }, row.pass_rate.toFixed(1) + '%'),
render: (row) =>
h(
'span',
{ style: { color: '#52c41a', fontWeight: '600' } },
row.pass_rate.toFixed(1) + '%',
),
},
{
title: '参与度',
key: 'active_rate',
render: (row) => h('span', { style: { color: '#1890ff', fontWeight: '600' } }, row.active_rate.toFixed(1) + '%'),
render: (row) =>
h(
'span',
{ style: { color: '#1890ff', fontWeight: '600' } },
row.active_rate.toFixed(1) + '%',
),
},
]"
/>
@@ -946,4 +1088,3 @@ const radarChartOptions = {
font-weight: 600;
}
</style>

View File

@@ -136,7 +136,11 @@ const menus = computed<MenuOption[]>(() => [
},
{
label: () =>
h(RouterLink, { to: "/class/my-rank" }, { default: () => "我的排名" }),
h(
RouterLink,
{ to: "/class/my-rank" },
{ default: () => "我的排名" },
),
key: "my-rank",
show: userStore.isAuthed,
},