mirror of
https://github.com/ZeroCatDev/Classworks.git
synced 2025-12-07 13:03:59 +00:00
初步添加ea2
This commit is contained in:
parent
0dceb0c278
commit
b9efaee7ee
4
.gitignore
vendored
4
.gitignore
vendored
@ -170,4 +170,6 @@ dist
|
||||
|
||||
# Vite 临时文件
|
||||
vite.config.*.timestamp-*.mjs
|
||||
*.timestamp-*
|
||||
*.timestamp-*
|
||||
|
||||
kv-admin
|
||||
@ -10,6 +10,8 @@
|
||||
"lint": "eslint . --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@examaware-cs/core": "^1.0.0",
|
||||
"@examaware-cs/player": "^1.0.2",
|
||||
"@mdi/font": "7.4.47",
|
||||
"@microsoft/clarity": "^1.0.0",
|
||||
"axios": "^1.11.0",
|
||||
@ -19,6 +21,7 @@
|
||||
"pinyin-pro": "^3.27.0",
|
||||
"ratelimit-header-parser": "^0.1.0",
|
||||
"roboto-fontface": "*",
|
||||
"tdesign-vue-next": "^1.17.1",
|
||||
"typewriter-effect": "^2.21.0",
|
||||
"uuid": "^9.0.1",
|
||||
"vue": "^3.5.20",
|
||||
|
||||
135
pnpm-lock.yaml
generated
135
pnpm-lock.yaml
generated
@ -8,6 +8,12 @@ importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
'@examaware-cs/core':
|
||||
specifier: ^1.0.0
|
||||
version: 1.0.0
|
||||
'@examaware-cs/player':
|
||||
specifier: ^1.0.2
|
||||
version: 1.0.2(tdesign-vue-next@1.17.1(vue@3.5.20))(vue@3.5.20)
|
||||
'@mdi/font':
|
||||
specifier: 7.4.47
|
||||
version: 7.4.47
|
||||
@ -35,6 +41,9 @@ importers:
|
||||
roboto-fontface:
|
||||
specifier: '*'
|
||||
version: 0.10.0
|
||||
tdesign-vue-next:
|
||||
specifier: ^1.17.1
|
||||
version: 1.17.1(vue@3.5.20)
|
||||
typewriter-effect:
|
||||
specifier: ^2.21.0
|
||||
version: 2.21.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
@ -816,6 +825,15 @@ packages:
|
||||
resolution: {integrity: sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@examaware-cs/core@1.0.0':
|
||||
resolution: {integrity: sha512-JSnyYe4/wpKfoPdA1CVNjLyBSpFSL+H/rKTZlbJyFCymtBRlXthzswKzLCwioyw7y/C3lioUFXLJ2g+CwDnS6w==}
|
||||
|
||||
'@examaware-cs/player@1.0.2':
|
||||
resolution: {integrity: sha512-Fid58JL0X5TP/O3DNp8QY0B5B8Svv1I8Qi8AObw5HK571/UU6/ri1YQS03ujxt6yupzd7qhiX+7C7EO4nLglJg==}
|
||||
peerDependencies:
|
||||
tdesign-vue-next: ^1.15.5
|
||||
vue: ^3.0.0
|
||||
|
||||
'@humanfs/core@0.19.1':
|
||||
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
|
||||
engines: {node: '>=18.18.0'}
|
||||
@ -1062,6 +1080,9 @@ packages:
|
||||
resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
|
||||
'@popperjs/core@2.11.8':
|
||||
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
|
||||
|
||||
'@quansync/fs@0.1.2':
|
||||
resolution: {integrity: sha512-ezIadUb1aFhwJLd++WVqVpi9rnlX8vnd4ju7saPhwLHJN1mJgOv0puePTGV+FbtSnWtwoHDT8lAm4kagDZmpCg==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
@ -1236,12 +1257,27 @@ packages:
|
||||
'@types/json5@0.0.29':
|
||||
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
|
||||
|
||||
'@types/lodash-es@4.17.12':
|
||||
resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==}
|
||||
|
||||
'@types/lodash@4.17.20':
|
||||
resolution: {integrity: sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==}
|
||||
|
||||
'@types/resolve@1.20.2':
|
||||
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
|
||||
|
||||
'@types/sortablejs@1.15.8':
|
||||
resolution: {integrity: sha512-b79830lW+RZfwaztgs1aVPgbasJ8e7AXtZYHTELNXZPsERt4ymJdjV4OccDbHQAvHrCcFpbF78jkm0R6h/pZVg==}
|
||||
|
||||
'@types/tinycolor2@1.4.6':
|
||||
resolution: {integrity: sha512-iEN8J0BoMnsWBqjVbWH/c0G0Hh7O21lpR2/+PrvAVgWdzL7eexIFm4JN/Wn10PTcmNdtS6U67r499mlWMXOxNw==}
|
||||
|
||||
'@types/trusted-types@2.0.7':
|
||||
resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
|
||||
|
||||
'@types/validator@13.15.3':
|
||||
resolution: {integrity: sha512-7bcUmDyS6PN3EuD9SlGGOxM77F8WLVsrwkxyWxKnxzmXoequ6c7741QBrANq6htVRGOITJ7z72mTP6Z4XyuG+Q==}
|
||||
|
||||
'@vite-pwa/assets-generator@1.0.0':
|
||||
resolution: {integrity: sha512-tWRF/tsqGkND5+dDVnJz7DzQkIRjtTRRYvA3y6l4FwTwK47OK72p1X7ResSz6T7PimIZMuFd+arsB8NRIG+Sww==}
|
||||
engines: {node: '>=16.14.0'}
|
||||
@ -1611,6 +1647,9 @@ packages:
|
||||
resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
dayjs@1.11.18:
|
||||
resolution: {integrity: sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==}
|
||||
|
||||
debug@3.2.7:
|
||||
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
|
||||
peerDependencies:
|
||||
@ -2413,6 +2452,9 @@ packages:
|
||||
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
lodash-es@4.17.21:
|
||||
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
|
||||
|
||||
lodash.debounce@4.0.8:
|
||||
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
|
||||
|
||||
@ -2475,6 +2517,9 @@ packages:
|
||||
minimist@1.2.8:
|
||||
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
|
||||
|
||||
misans@4.1.0:
|
||||
resolution: {integrity: sha512-CcIRrIVhnt+OpGXvw1Q8llGBVAy5P2mdov/kJ0gGa81sJ0RY7mZp2fNAt2ySTCeZos+wo7ZnzDZxl1In//7FdA==}
|
||||
|
||||
mitt@3.0.1:
|
||||
resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
|
||||
|
||||
@ -2542,6 +2587,9 @@ packages:
|
||||
resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
ogl@1.0.11:
|
||||
resolution: {integrity: sha512-kUpC154AFfxi16pmZUK4jk3J+8zxwTWGPo03EoYA8QPbzikHoaC82n6pNTbd+oEaJonaE8aPWBlX7ad9zrqLsA==}
|
||||
|
||||
once@1.4.0:
|
||||
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
|
||||
|
||||
@ -2993,12 +3041,18 @@ packages:
|
||||
resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
simple-keyboard@3.8.85:
|
||||
resolution: {integrity: sha512-ewZgPgisKsRsBpBW8wfOoR/fn4ApxD6lhhfw6u354fLAM6fHnkJLOHs8o1q5S/zhJQF0sSDPoIO0EojveNylfQ==}
|
||||
|
||||
simple-swizzle@0.2.2:
|
||||
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
|
||||
|
||||
smob@1.5.0:
|
||||
resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==}
|
||||
|
||||
sortablejs@1.15.6:
|
||||
resolution: {integrity: sha512-aNfiuwMEpfBM/CN6LY0ibyhxPfPbyFeBTYJKCvzkJ2GkUpazIt3H+QIPAMHwqQ7tMKaHz1Qj+rJJCqljnf4p3A==}
|
||||
|
||||
source-map-js@1.2.1:
|
||||
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -3089,6 +3143,17 @@ packages:
|
||||
resolution: {integrity: sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==}
|
||||
engines: {node: '>=16.0.0'}
|
||||
|
||||
tdesign-icons-vue-next@0.4.1:
|
||||
resolution: {integrity: sha512-uDPuTLRORnGcTyVGNoentNaK4V+ZcBmhYwcY3KqDaQQ5rrPeLMxu0ZVmgOEf0JtF2QZiqAxY7vodNEiLUdoRKA==}
|
||||
peerDependencies:
|
||||
vue: ^3.0.0
|
||||
|
||||
tdesign-vue-next@1.17.1:
|
||||
resolution: {integrity: sha512-rqRPHSfPn5Y7Nxffa9Q6JumPguc+K2YfcaaxrvyYkZIQwCQ8Fwi2rhh6KpgQud2SAPMP/N1SxfIvYJVS5Lyu8Q==}
|
||||
engines: {node: '>= 18'}
|
||||
peerDependencies:
|
||||
vue: '>=3.1.0'
|
||||
|
||||
temp-dir@2.0.0:
|
||||
resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==}
|
||||
engines: {node: '>=8'}
|
||||
@ -3102,6 +3167,9 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
tinycolor2@1.6.0:
|
||||
resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==}
|
||||
|
||||
tinyglobby@0.2.12:
|
||||
resolution: {integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
@ -3291,6 +3359,10 @@ packages:
|
||||
resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
|
||||
hasBin: true
|
||||
|
||||
validator@13.15.15:
|
||||
resolution: {integrity: sha512-BgWVbCI72aIQy937xbawcs+hrVaN/CZ2UwutgaJ36hGqRrLNM+f5LUT/YPRbo8IV/ASeFzXszezV+y2+rq3l8A==}
|
||||
engines: {node: '>= 0.10'}
|
||||
|
||||
varint@6.0.0:
|
||||
resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==}
|
||||
|
||||
@ -4288,6 +4360,17 @@ snapshots:
|
||||
dependencies:
|
||||
levn: 0.4.1
|
||||
|
||||
'@examaware-cs/core@1.0.0': {}
|
||||
|
||||
'@examaware-cs/player@1.0.2(tdesign-vue-next@1.17.1(vue@3.5.20))(vue@3.5.20)':
|
||||
dependencies:
|
||||
'@examaware-cs/core': 1.0.0
|
||||
misans: 4.1.0
|
||||
ogl: 1.0.11
|
||||
simple-keyboard: 3.8.85
|
||||
tdesign-vue-next: 1.17.1(vue@3.5.20)
|
||||
vue: 3.5.20
|
||||
|
||||
'@humanfs/core@0.19.1': {}
|
||||
|
||||
'@humanfs/node@0.16.6':
|
||||
@ -4475,6 +4558,8 @@ snapshots:
|
||||
'@parcel/watcher-win32-x64': 2.5.1
|
||||
optional: true
|
||||
|
||||
'@popperjs/core@2.11.8': {}
|
||||
|
||||
'@quansync/fs@0.1.2':
|
||||
dependencies:
|
||||
quansync: 0.2.10
|
||||
@ -4606,10 +4691,22 @@ snapshots:
|
||||
|
||||
'@types/json5@0.0.29': {}
|
||||
|
||||
'@types/lodash-es@4.17.12':
|
||||
dependencies:
|
||||
'@types/lodash': 4.17.20
|
||||
|
||||
'@types/lodash@4.17.20': {}
|
||||
|
||||
'@types/resolve@1.20.2': {}
|
||||
|
||||
'@types/sortablejs@1.15.8': {}
|
||||
|
||||
'@types/tinycolor2@1.4.6': {}
|
||||
|
||||
'@types/trusted-types@2.0.7': {}
|
||||
|
||||
'@types/validator@13.15.3': {}
|
||||
|
||||
'@vite-pwa/assets-generator@1.0.0':
|
||||
dependencies:
|
||||
cac: 6.7.14
|
||||
@ -5086,6 +5183,8 @@ snapshots:
|
||||
es-errors: 1.3.0
|
||||
is-data-view: 1.0.2
|
||||
|
||||
dayjs@1.11.18: {}
|
||||
|
||||
debug@3.2.7:
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
@ -6036,6 +6135,8 @@ snapshots:
|
||||
dependencies:
|
||||
p-locate: 5.0.0
|
||||
|
||||
lodash-es@4.17.21: {}
|
||||
|
||||
lodash.debounce@4.0.8: {}
|
||||
|
||||
lodash.merge@4.6.2: {}
|
||||
@ -6093,6 +6194,8 @@ snapshots:
|
||||
|
||||
minimist@1.2.8: {}
|
||||
|
||||
misans@4.1.0: {}
|
||||
|
||||
mitt@3.0.1: {}
|
||||
|
||||
mlly@1.7.4:
|
||||
@ -6162,6 +6265,8 @@ snapshots:
|
||||
define-properties: 1.2.1
|
||||
es-object-atoms: 1.0.0
|
||||
|
||||
ogl@1.0.11: {}
|
||||
|
||||
once@1.4.0:
|
||||
dependencies:
|
||||
wrappy: 1.0.2
|
||||
@ -6653,12 +6758,16 @@ snapshots:
|
||||
side-channel-map: 1.0.1
|
||||
side-channel-weakmap: 1.0.2
|
||||
|
||||
simple-keyboard@3.8.85: {}
|
||||
|
||||
simple-swizzle@0.2.2:
|
||||
dependencies:
|
||||
is-arrayish: 0.3.2
|
||||
|
||||
smob@1.5.0: {}
|
||||
|
||||
sortablejs@1.15.6: {}
|
||||
|
||||
source-map-js@1.2.1: {}
|
||||
|
||||
source-map-support@0.5.21:
|
||||
@ -6764,6 +6873,28 @@ snapshots:
|
||||
|
||||
sync-message-port@1.1.3: {}
|
||||
|
||||
tdesign-icons-vue-next@0.4.1(vue@3.5.20):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.27.0
|
||||
vue: 3.5.20
|
||||
|
||||
tdesign-vue-next@1.17.1(vue@3.5.20):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.27.0
|
||||
'@popperjs/core': 2.11.8
|
||||
'@types/lodash-es': 4.17.12
|
||||
'@types/sortablejs': 1.15.8
|
||||
'@types/tinycolor2': 1.4.6
|
||||
'@types/validator': 13.15.3
|
||||
dayjs: 1.11.18
|
||||
lodash-es: 4.17.21
|
||||
mitt: 3.0.1
|
||||
sortablejs: 1.15.6
|
||||
tdesign-icons-vue-next: 0.4.1(vue@3.5.20)
|
||||
tinycolor2: 1.6.0
|
||||
validator: 13.15.15
|
||||
vue: 3.5.20
|
||||
|
||||
temp-dir@2.0.0: {}
|
||||
|
||||
tempy@0.6.0:
|
||||
@ -6780,6 +6911,8 @@ snapshots:
|
||||
commander: 2.20.3
|
||||
source-map-support: 0.5.21
|
||||
|
||||
tinycolor2@1.6.0: {}
|
||||
|
||||
tinyglobby@0.2.12:
|
||||
dependencies:
|
||||
fdir: 6.4.3(picomatch@4.0.2)
|
||||
@ -7027,6 +7160,8 @@ snapshots:
|
||||
|
||||
uuid@9.0.1: {}
|
||||
|
||||
validator@13.15.15: {}
|
||||
|
||||
varint@6.0.0: {}
|
||||
|
||||
vite-plugin-pwa@1.0.3(@vite-pwa/assets-generator@1.0.0)(vite@5.4.17(sass-embedded@1.86.3)(sass@1.86.3)(terser@5.39.0))(workbox-build@7.3.0)(workbox-window@7.3.0):
|
||||
|
||||
BIN
src/assets/fonts/TCloudNumberVF.ttf
Normal file
BIN
src/assets/fonts/TCloudNumberVF.ttf
Normal file
Binary file not shown.
@ -1073,6 +1073,8 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 确认删除配置
|
||||
*/
|
||||
|
||||
@ -225,7 +225,7 @@
|
||||
|
||||
<script>
|
||||
import { openDB } from "idb";
|
||||
import axios from "@/axios/axios";
|
||||
import axios from "@/assets/fonts/axios/axios";
|
||||
import { getSetting, setSetting } from "@/utils/settings";
|
||||
|
||||
export default {
|
||||
@ -237,7 +237,7 @@ export default {
|
||||
migrationType: "server",
|
||||
serverUrl: "",
|
||||
targetStorage: "kv-server",
|
||||
targetServerUrl: "https://kv.wuyuan.dev",
|
||||
targetServerUrl: "https://kv-service.wuyuan.dev",
|
||||
startDate: this.getDateString(
|
||||
new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)
|
||||
), // 30 days ago
|
||||
|
||||
@ -74,7 +74,7 @@
|
||||
<br/><br/>Classworks KV 的全域管理员是 <a href="https://wuyuan.dev" target="_blank">孙悟元</a></v-card-text
|
||||
><v-card-actions
|
||||
><v-btn
|
||||
href="https://kv.wuyuan.dev"
|
||||
href="https://kv.houlang.cloud"
|
||||
class="text-none"
|
||||
append-icon="mdi-open-in-new"
|
||||
target="_blank"
|
||||
|
||||
@ -15,6 +15,9 @@ import GlobalMessage from '@/components/GlobalMessage.vue'
|
||||
import { createApp } from 'vue'
|
||||
import Clarity from '@microsoft/clarity';
|
||||
const projectId = "rhp8uqoc3l"
|
||||
import TDesign from 'tdesign-vue-next'
|
||||
import 'tdesign-vue-next/es/style/index.css'
|
||||
import '@examaware-cs/player/dist/player.css'
|
||||
|
||||
Clarity.init(projectId);
|
||||
import messageService from './utils/message';
|
||||
@ -22,7 +25,7 @@ import messageService from './utils/message';
|
||||
const app = createApp(App)
|
||||
|
||||
registerPlugins(app)
|
||||
|
||||
app.use(TDesign)
|
||||
app.use(messageService);
|
||||
|
||||
app.component('GlobalMessage', GlobalMessage)
|
||||
|
||||
79
src/pages/exam-editor/[id].vue
Normal file
79
src/pages/exam-editor/[id].vue
Normal file
@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<v-container class="pa-0">
|
||||
<v-app-bar elevation="1">
|
||||
<template #prepend>
|
||||
<v-btn
|
||||
icon="mdi-arrow-left"
|
||||
variant="text"
|
||||
@click="$router.back()"
|
||||
/>
|
||||
</template>
|
||||
<v-app-bar-title class="text-h6">
|
||||
编辑考试配置
|
||||
</v-app-bar-title>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="success"
|
||||
variant="outlined"
|
||||
prepend-icon="mdi-content-save"
|
||||
:loading="saving"
|
||||
@click="save"
|
||||
>
|
||||
保存
|
||||
</v-btn>
|
||||
</v-app-bar>
|
||||
|
||||
<v-container
|
||||
class="py-4"
|
||||
style="max-width: 1200px"
|
||||
>
|
||||
<ExamConfigEditor
|
||||
v-if="id"
|
||||
ref="editor"
|
||||
:config-id="id"
|
||||
@saved="onSaved"
|
||||
@error="onError"
|
||||
/>
|
||||
</v-container>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ExamConfigEditor from '@/components/ExamConfigEditor.vue'
|
||||
|
||||
export default {
|
||||
name: 'ExamEditorPage',
|
||||
components: { ExamConfigEditor },
|
||||
data() {
|
||||
return {
|
||||
id: this.$route.params.id,
|
||||
saving: false,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'$route.params.id'(val) {
|
||||
this.id = val
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async save() {
|
||||
if (!this.$refs.editor) return
|
||||
this.saving = true
|
||||
try {
|
||||
await this.$refs.editor.saveConfig()
|
||||
} finally {
|
||||
this.saving = false
|
||||
}
|
||||
},
|
||||
onSaved() {
|
||||
// 轻提示
|
||||
this.$toast?.success?.('保存成功')
|
||||
},
|
||||
onError(msg) {
|
||||
this.$toast?.error?.(msg || '保存失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
216
src/pages/exam-player.vue
Normal file
216
src/pages/exam-player.vue
Normal file
@ -0,0 +1,216 @@
|
||||
<template>
|
||||
<v-alert
|
||||
v-if="error"
|
||||
type="error"
|
||||
variant="tonal"
|
||||
border="start"
|
||||
class="mb-4"
|
||||
closable
|
||||
@click:close="error = ''"
|
||||
>
|
||||
{{ error }}
|
||||
</v-alert>
|
||||
|
||||
<v-skeleton-loader v-if="loading" type="article" />
|
||||
|
||||
<div v-else-if="!config">
|
||||
<v-alert type="warning" variant="tonal" border="start">
|
||||
缺少配置,请通过 URL 参数 id 或 url 传入配置。
|
||||
</v-alert>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<div class="player" ref="playerRef">
|
||||
<ExamPlayer
|
||||
v-model:room-number="roomNumberLocal"
|
||||
:exam-config="config"
|
||||
:config="playerConfigObj"
|
||||
:show-action-bar="true"
|
||||
:time-sync-status="'电脑时间'"
|
||||
@exit="exit()"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, computed, onMounted, watch } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import dataProvider from "@/utils/dataProvider";
|
||||
import { ExamPlayer } from "@examaware-cs/player";
|
||||
|
||||
export default {
|
||||
name: "ExamPlayerPage",
|
||||
components: { ExamPlayer },
|
||||
setup() {
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const loading = ref(true);
|
||||
const error = ref("");
|
||||
const config = ref(null);
|
||||
|
||||
// 播放器配置:支持从查询参数读取考场号
|
||||
const roomNumber = computed(() => {
|
||||
return (route.query.roomNumber || route.query.room || "01") + "";
|
||||
});
|
||||
const roomNumberLocal = ref(roomNumber.value);
|
||||
const playerConfigObj = computed(() => ({
|
||||
roomNumber: roomNumberLocal.value,
|
||||
timeSync: true,
|
||||
refreshInterval: 1000,
|
||||
fullscreen: false,
|
||||
}));
|
||||
|
||||
async function loadConfig() {
|
||||
loading.value = true;
|
||||
error.value = "";
|
||||
config.value = null;
|
||||
try {
|
||||
const url = route.query.url || route.query.configUrl;
|
||||
const id = route.query.id;
|
||||
|
||||
if (url) {
|
||||
const resp = await fetch(url);
|
||||
if (!resp.ok) throw new Error("拉取配置失败: " + resp.status);
|
||||
const json = await resp.json();
|
||||
config.value = normalizeConfig(json);
|
||||
} else if (id) {
|
||||
const data = await dataProvider.loadData(`es_${id}`);
|
||||
if (!data) throw new Error("未找到该配置");
|
||||
config.value = normalizeConfig(data);
|
||||
} else {
|
||||
// 没有参数
|
||||
config.value = null;
|
||||
}
|
||||
// ExamPlayer 组件会自行响应传入的 exam-config
|
||||
} catch (e) {
|
||||
error.value = e?.message || String(e);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function exit() {
|
||||
// 返回上一页
|
||||
router.push("/");
|
||||
}
|
||||
|
||||
function normalizeConfig(raw) {
|
||||
// 保障字段存在与正确类型
|
||||
return {
|
||||
examName: raw?.examName || "未命名考试",
|
||||
message: raw?.message || "",
|
||||
// ExamAware 需要 examInfos: { name, start, end, alertTime? }
|
||||
examInfos: Array.isArray(raw?.examInfos)
|
||||
? raw.examInfos.map((i) => ({
|
||||
name: i?.name || "未命名科目",
|
||||
start: i?.start || "",
|
||||
end: i?.end || "",
|
||||
alertTime: typeof i?.alertTime === "number" ? i.alertTime : 15,
|
||||
}))
|
||||
: [],
|
||||
};
|
||||
}
|
||||
|
||||
onMounted(loadConfig);
|
||||
watch(
|
||||
() => [
|
||||
route.query.id,
|
||||
route.query.url,
|
||||
route.query.configUrl,
|
||||
route.query.room,
|
||||
route.query.roomNumber,
|
||||
],
|
||||
loadConfig
|
||||
);
|
||||
watch(roomNumber, (v) => {
|
||||
roomNumberLocal.value = v;
|
||||
});
|
||||
|
||||
return {
|
||||
loading,
|
||||
error,
|
||||
config,
|
||||
roomNumberLocal,
|
||||
playerConfigObj,
|
||||
exit,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
/* 自定义字体定义 */
|
||||
@font-face {
|
||||
font-family: "TCloudNumber";
|
||||
src: url("../assets/fonts/TCloudNumberVF.ttf") format("truetype-variations"),
|
||||
url("../assets/fonts/TCloudNumberVF.ttf") format("truetype");
|
||||
font-weight: 100 900;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#app {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: "MiSans", MiSans, -apple-system, BlinkMacSystemFont, "Segoe UI",
|
||||
Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans",
|
||||
"PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
|
||||
}
|
||||
|
||||
/* 设置主题为深色 */
|
||||
html {
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--td-bg-color-page, #0a0a0a);
|
||||
color: var(--td-text-color-primary, #ffffff);
|
||||
}
|
||||
|
||||
/* 通用样式 */
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
margin: 0;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* 确保 TDesign 组件样式正常工作 */
|
||||
.t-button {
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
/* 自定义滚动条样式 */
|
||||
::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: var(--td-bg-color-container, #1a1a1a);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--td-bg-color-component, #333333);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--td-bg-color-component-hover, #444444);
|
||||
}
|
||||
</style>
|
||||
@ -44,4 +44,4 @@ export const getNamespaceInfo = async () => {
|
||||
} catch (error) {
|
||||
throw new Error(error.response?.data?.message || "获取命名空间信息失败");
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@ -23,7 +23,6 @@ export const kvServerProvider = {
|
||||
async loadNamespaceInfo() {
|
||||
try {
|
||||
// 使用 Classworks Cloud 或者用户配置的服务器域名
|
||||
const provider = getSetting("server.provider");
|
||||
const serverUrl = getSetting("server.domain");
|
||||
|
||||
const res = await axios.get(`${serverUrl}/kv/_info`, {
|
||||
|
||||
@ -7,6 +7,7 @@ import Vue from '@vitejs/plugin-vue'
|
||||
import VueRouter from 'unplugin-vue-router/vite'
|
||||
import Vuetify, { transformAssetUrls } from 'vite-plugin-vuetify'
|
||||
import { VitePWA } from 'vite-plugin-pwa'
|
||||
import { TDesignResolver } from 'unplugin-vue-components/resolvers'
|
||||
|
||||
// Utilities
|
||||
import { defineConfig } from 'vite'
|
||||
@ -154,7 +155,13 @@ export default defineConfig({
|
||||
configFile: 'src/styles/settings.scss',
|
||||
},
|
||||
}),
|
||||
Components(),
|
||||
Components({
|
||||
resolvers: [
|
||||
TDesignResolver({
|
||||
library: 'vue-next'
|
||||
})
|
||||
]
|
||||
}),
|
||||
Fonts({
|
||||
google: {
|
||||
families: [{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user