diff --git a/package.json b/package.json index 5e92824..9f448e2 100644 --- a/package.json +++ b/package.json @@ -12,17 +12,17 @@ "dependencies": { "@mdi/font": "7.4.47", "@microsoft/clarity": "^1.0.0", - "axios": "^1.8.4", - "idb": "^8.0.2", - "js-base64": "^3.7.7", + "axios": "^1.11.0", + "idb": "^8.0.3", + "js-base64": "^3.7.8", "js-yaml": "^4.1.0", - "pinyin-pro": "^3.26.0", + "pinyin-pro": "^3.27.0", "ratelimit-header-parser": "^0.1.0", "roboto-fontface": "*", "typewriter-effect": "^2.21.0", "uuid": "^9.0.1", - "vue": "^3.4.31", - "vuetify": "^3.8.0" + "vue": "^3.5.20", + "vuetify": "^3.9.6" }, "devDependencies": { "@eslint/js": "^9.14.0", @@ -34,7 +34,7 @@ "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^6.4.0", "eslint-plugin-vue": "^9.30.0", - "pinia": "^3.0.1", + "pinia": "^3.0.3", "sass": "1.86.3", "sass-embedded": "^1.86.3", "unplugin-auto-import": "^19.1.2", @@ -42,9 +42,9 @@ "unplugin-vue-components": "^28.4.1", "unplugin-vue-router": "^0.12.0", "vite": "^5.4.17", - "vite-plugin-pwa": "^1.0.0", + "vite-plugin-pwa": "^1.0.3", "vite-plugin-vue-layouts": "^0.11.0", - "vite-plugin-vuetify": "^2.1.1", - "vue-router": "^4.5.0" + "vite-plugin-vuetify": "^2.1.2", + "vue-router": "^4.5.1" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cf9c05b..a33e1e1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,20 +15,20 @@ importers: specifier: ^1.0.0 version: 1.0.0 axios: - specifier: ^1.8.4 - version: 1.8.4 + specifier: ^1.11.0 + version: 1.11.0 idb: - specifier: ^8.0.2 - version: 8.0.2 + specifier: ^8.0.3 + version: 8.0.3 js-base64: - specifier: ^3.7.7 - version: 3.7.7 + specifier: ^3.7.8 + version: 3.7.8 js-yaml: specifier: ^4.1.0 version: 4.1.0 pinyin-pro: - specifier: ^3.26.0 - version: 3.26.0 + specifier: ^3.27.0 + version: 3.27.0 ratelimit-header-parser: specifier: ^0.1.0 version: 0.1.0 @@ -42,11 +42,11 @@ importers: specifier: ^9.0.1 version: 9.0.1 vue: - specifier: ^3.4.31 - version: 3.5.13 + specifier: ^3.5.20 + version: 3.5.20 vuetify: - specifier: ^3.8.0 - version: 3.8.0(vite-plugin-vuetify@2.1.1)(vue@3.5.13) + specifier: ^3.9.6 + version: 3.9.6(vite-plugin-vuetify@2.1.2)(vue@3.5.20) devDependencies: '@eslint/js': specifier: ^9.14.0 @@ -56,7 +56,7 @@ importers: version: 1.0.0 '@vitejs/plugin-vue': specifier: ^5.2.3 - version: 5.2.3(vite@5.4.17(sass-embedded@1.86.3)(sass@1.86.3)(terser@5.39.0))(vue@3.5.13) + version: 5.2.3(vite@5.4.17(sass-embedded@1.86.3)(sass@1.86.3)(terser@5.39.0))(vue@3.5.20) eslint: specifier: ^9.14.0 version: 9.15.0(jiti@2.4.2) @@ -76,8 +76,8 @@ importers: specifier: ^9.30.0 version: 9.31.0(eslint@9.15.0(jiti@2.4.2)) pinia: - specifier: ^3.0.1 - version: 3.0.1(vue@3.5.13) + specifier: ^3.0.3 + version: 3.0.3(vue@3.5.20) sass: specifier: 1.86.3 version: 1.86.3 @@ -92,25 +92,25 @@ importers: version: 1.3.1(vite@5.4.17(sass-embedded@1.86.3)(sass@1.86.3)(terser@5.39.0)) unplugin-vue-components: specifier: ^28.4.1 - version: 28.4.1(@babel/parser@7.27.0)(vue@3.5.13) + version: 28.4.1(@babel/parser@7.28.3)(vue@3.5.20) unplugin-vue-router: specifier: ^0.12.0 - version: 0.12.0(vue-router@4.5.0(vue@3.5.13))(vue@3.5.13) + version: 0.12.0(vue-router@4.5.1(vue@3.5.20))(vue@3.5.20) vite: specifier: ^5.4.17 version: 5.4.17(sass-embedded@1.86.3)(sass@1.86.3)(terser@5.39.0) vite-plugin-pwa: - specifier: ^1.0.0 - version: 1.0.0(@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) + specifier: ^1.0.3 + version: 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) vite-plugin-vue-layouts: specifier: ^0.11.0 - version: 0.11.0(vite@5.4.17(sass-embedded@1.86.3)(sass@1.86.3)(terser@5.39.0))(vue-router@4.5.0(vue@3.5.13))(vue@3.5.13) + version: 0.11.0(vite@5.4.17(sass-embedded@1.86.3)(sass@1.86.3)(terser@5.39.0))(vue-router@4.5.1(vue@3.5.20))(vue@3.5.20) vite-plugin-vuetify: - specifier: ^2.1.1 - version: 2.1.1(vite@5.4.17(sass-embedded@1.86.3)(sass@1.86.3)(terser@5.39.0))(vue@3.5.13)(vuetify@3.8.0) + specifier: ^2.1.2 + version: 2.1.2(vite@5.4.17(sass-embedded@1.86.3)(sass@1.86.3)(terser@5.39.0))(vue@3.5.20)(vuetify@3.9.6) vue-router: - specifier: ^4.5.0 - version: 4.5.0(vue@3.5.13) + specifier: ^4.5.1 + version: 4.5.1(vue@3.5.20) packages: @@ -207,10 +207,18 @@ packages: resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.25.9': resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.27.1': + resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.25.9': resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} engines: {node: '>=6.9.0'} @@ -233,6 +241,11 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + '@babel/parser@7.28.3': + resolution: {integrity: sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9': resolution: {integrity: sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==} engines: {node: '>=6.9.0'} @@ -618,6 +631,10 @@ packages: resolution: {integrity: sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==} engines: {node: '>=6.9.0'} + '@babel/types@7.28.2': + resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==} + engines: {node: '>=6.9.0'} + '@bufbuild/protobuf@2.2.2': resolution: {integrity: sha512-UNtPCbrwrenpmrXuRwn9jYpPoweNXj8X5sMvYgsqYyaH8jQ6LfUJSk3dJLnBK+6sfYPrF4iAIo5sd5HQ+tg75A==} @@ -1249,15 +1266,27 @@ packages: '@vue/compiler-core@3.5.13': resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==} + '@vue/compiler-core@3.5.20': + resolution: {integrity: sha512-8TWXUyiqFd3GmP4JTX9hbiTFRwYHgVL/vr3cqhr4YQ258+9FADwvj7golk2sWNGHR67QgmCZ8gz80nQcMokhwg==} + '@vue/compiler-dom@3.5.13': resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==} + '@vue/compiler-dom@3.5.20': + resolution: {integrity: sha512-whB44M59XKjqUEYOMPYU0ijUV0G+4fdrHVKDe32abNdX/kJe1NUEMqsi4cwzXa9kyM9w5S8WqFsrfo1ogtBZGQ==} + '@vue/compiler-sfc@3.5.13': resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==} + '@vue/compiler-sfc@3.5.20': + resolution: {integrity: sha512-SFcxapQc0/feWiSBfkGsa1v4DOrnMAQSYuvDMpEaxbpH5dKbnEM5KobSNSgU+1MbHCl+9ftm7oQWxvwDB6iBfw==} + '@vue/compiler-ssr@3.5.13': resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==} + '@vue/compiler-ssr@3.5.20': + resolution: {integrity: sha512-RSl5XAMc5YFUXpDQi+UQDdVjH9FnEpLDHIALg5J0ITHxkEzJ8uQLlo7CIbjPYqmZtt6w0TsIPbo1izYXwDG7JA==} + '@vue/devtools-api@6.6.4': resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} @@ -1270,25 +1299,28 @@ packages: '@vue/devtools-shared@7.7.2': resolution: {integrity: sha512-uBFxnp8gwW2vD6FrJB8JZLUzVb6PNRG0B0jBnHsOH8uKyva2qINY8PTF5Te4QlTbMDqU5K6qtJDr6cNsKWhbOA==} - '@vue/reactivity@3.5.13': - resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==} + '@vue/reactivity@3.5.20': + resolution: {integrity: sha512-hS8l8x4cl1fmZpSQX/NXlqWKARqEsNmfkwOIYqtR2F616NGfsLUm0G6FQBK6uDKUCVyi1YOL8Xmt/RkZcd/jYQ==} - '@vue/runtime-core@3.5.13': - resolution: {integrity: sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==} + '@vue/runtime-core@3.5.20': + resolution: {integrity: sha512-vyQRiH5uSZlOa+4I/t4Qw/SsD/gbth0SW2J7oMeVlMFMAmsG1rwDD6ok0VMmjXY3eI0iHNSSOBilEDW98PLRKw==} - '@vue/runtime-dom@3.5.13': - resolution: {integrity: sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==} + '@vue/runtime-dom@3.5.20': + resolution: {integrity: sha512-KBHzPld/Djw3im0CQ7tGCpgRedryIn4CcAl047EhFTCCPT2xFf4e8j6WeKLgEEoqPSl9TYqShc3Q6tpWpz/Xgw==} - '@vue/server-renderer@3.5.13': - resolution: {integrity: sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==} + '@vue/server-renderer@3.5.20': + resolution: {integrity: sha512-HthAS0lZJDH21HFJBVNTtx+ULcIbJQRpjSVomVjfyPkFSpCwvsPTA+jIzOaUm3Hrqx36ozBHePztQFg6pj5aKg==} peerDependencies: - vue: 3.5.13 + vue: 3.5.20 '@vue/shared@3.5.13': resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} - '@vuetify/loader-shared@2.1.0': - resolution: {integrity: sha512-dNE6Ceym9ijFsmJKB7YGW0cxs7xbYV8+1LjU6jd4P14xOt/ji4Igtgzt0rJFbxu+ZhAzqz853lhB0z8V9Dy9cQ==} + '@vue/shared@3.5.20': + resolution: {integrity: sha512-SoRGP596KU/ig6TfgkCMbXkr4YJ91n/QSdMuqeP5r3hVIYA3CPHUBCc7Skak0EAKV+5lL4KyIh61VA/pK1CIAA==} + + '@vuetify/loader-shared@2.1.1': + resolution: {integrity: sha512-jSZTzTYaoiv8iwonFCVZQ0YYX/M+Uyl4ng+C4egMJT0Hcmh9gIxJL89qfZICDeo3g0IhqrvipW2FFKKRDMtVcA==} peerDependencies: vue: ^3.0.0 vuetify: ^3.0.0 @@ -1387,8 +1419,8 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - axios@1.8.4: - resolution: {integrity: sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==} + axios@1.11.0: + resolution: {integrity: sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==} babel-plugin-polyfill-corejs2@0.4.13: resolution: {integrity: sha512-3sX/eOms8kd3q2KZ6DAhKPc0dgm525Gqq5NtWKZ7QYYZEv57OQ54KtblzJzH1lQF/eQxO8KjWGIK9IPUJNus5g==} @@ -1943,8 +1975,8 @@ packages: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} - form-data@4.0.1: - resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} + form-data@4.0.4: + resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} engines: {node: '>= 6'} fs-extra@9.1.0: @@ -2084,8 +2116,8 @@ packages: idb@7.1.1: resolution: {integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==} - idb@8.0.2: - resolution: {integrity: sha512-CX70rYhx7GDDQzwwQMDwF6kDRQi5vVs6khHUumDrMecBylKkwvZ8HWvKV08AGb7VbpoGCWUQ4aHzNDgoUiOIUg==} + idb@8.0.3: + resolution: {integrity: sha512-LtwtVyVYO5BqRvcsKuB2iUMnHwPVByPCXFXOpuU96IZPPoPN6xjOGxZQ74pgSVVLQWtUOYgyeL4GE98BY5D3wg==} ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} @@ -2308,8 +2340,8 @@ packages: resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} hasBin: true - js-base64@3.7.7: - resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==} + js-base64@3.7.8: + resolution: {integrity: sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==} js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -2571,8 +2603,8 @@ packages: resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} engines: {node: '>=12'} - pinia@3.0.1: - resolution: {integrity: sha512-WXglsDzztOTH6IfcJ99ltYZin2mY8XZCXujkYWVIJlBjqsP6ST7zw+Aarh63E1cDVYeyUcPCxPHzJpEOmzB6Wg==} + pinia@3.0.3: + resolution: {integrity: sha512-ttXO/InUULUXkMHpTdp9Fj4hLpD/2AoJdmAbAeW2yu1iy1k+pkFekQXw5VpC0/5p51IOR/jDaDRfRWRnMMsGOA==} peerDependencies: typescript: '>=4.4.4' vue: ^2.7.0 || ^3.5.11 @@ -2580,8 +2612,8 @@ packages: typescript: optional: true - pinyin-pro@3.26.0: - resolution: {integrity: sha512-HcBZZb0pvm0/JkPhZHWA5Hqp2cWHXrrW/WrV+OtaYYM+kf35ffvZppIUuGmyuQ7gDr1JDJKMkbEE+GN0wfMoGg==} + pinyin-pro@3.27.0: + resolution: {integrity: sha512-Osdgjwe7Rm17N2paDMM47yW+jUIUH3+0RGo8QP39ZTLpTaJVDK0T58hOLaMQJbcMmAebVuK2ePunTEVEx1clNQ==} pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} @@ -2605,6 +2637,10 @@ packages: resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} engines: {node: ^10 || ^12 || >=14} + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -2977,6 +3013,7 @@ packages: source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} + deprecated: The work that was done in this beta branch won't be included in future versions sourcemap-codec@1.4.8: resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} @@ -3257,12 +3294,12 @@ packages: varint@6.0.0: resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} - vite-plugin-pwa@1.0.0: - resolution: {integrity: sha512-X77jo0AOd5OcxmWj3WnVti8n7Kw2tBgV1c8MCXFclrSlDV23ePzv2eTDIALXI2Qo6nJ5pZJeZAuX0AawvRfoeA==} + vite-plugin-pwa@1.0.3: + resolution: {integrity: sha512-/OpqIpUldALGxcsEnv/ekQiQ5xHkQ53wcoN5ewX4jiIDNGs3W+eNcI1WYZeyOLmzoEjg09D7aX0O89YGjen1aw==} engines: {node: '>=16.0.0'} peerDependencies: '@vite-pwa/assets-generator': ^1.0.0 - vite: ^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 + vite: ^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 workbox-build: ^7.3.0 workbox-window: ^7.3.0 peerDependenciesMeta: @@ -3276,8 +3313,8 @@ packages: vue: ^3.2.4 vue-router: ^4.0.11 - vite-plugin-vuetify@2.1.1: - resolution: {integrity: sha512-Pb7bKhQH8qPMzURmEGq2aIqCJkruFNsyf1NcrrtnjsOIkqJPMcBbiP0oJoO8/uAmyB5W/1JTbbUEsyXdMM0QHQ==} + vite-plugin-vuetify@2.1.2: + resolution: {integrity: sha512-I/wd6QS+DO6lHmuGoi1UTyvvBTQ2KDzQZ9oowJQEJ6OcjWfJnscYXx2ptm6S7fJSASuZT8jGRBL3LV4oS3LpaA==} engines: {node: ^18.0.0 || >=20.0.0} peerDependencies: vite: '>=5' @@ -3321,21 +3358,21 @@ packages: peerDependencies: eslint: '>=6.0.0' - vue-router@4.5.0: - resolution: {integrity: sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==} + vue-router@4.5.1: + resolution: {integrity: sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw==} peerDependencies: vue: ^3.2.0 - vue@3.5.13: - resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==} + vue@3.5.20: + resolution: {integrity: sha512-2sBz0x/wis5TkF1XZ2vH25zWq3G1bFEPOfkBcx2ikowmphoQsPH6X0V3mmPCXA2K1N/XGTnifVyDQP4GfDDeQw==} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true - vuetify@3.8.0: - resolution: {integrity: sha512-ROC0Xq2G/25ZyUpQMhaynMyXZBJY1WbOGlqOB810yubp8hfY8RlrOw+mzXJonOq6jylCY32muQ9xiJF1JPTLVA==} + vuetify@3.9.6: + resolution: {integrity: sha512-jNs2yLYiM50kE16gBu58xmnh9t/MOvgnYcNvmLNps6TLq9rPvjTNFm2k2jWfe69hGg0gQf+MFXXDkf65fxi9gg==} engines: {node: ^12.20 || >=14.13} peerDependencies: typescript: '>=4.7' @@ -3475,7 +3512,7 @@ snapshots: '@babel/code-frame@7.26.2': dependencies: - '@babel/helper-validator-identifier': 7.25.9 + '@babel/helper-validator-identifier': 7.27.1 js-tokens: 4.0.0 picocolors: 1.1.1 @@ -3489,10 +3526,10 @@ snapshots: '@babel/helper-compilation-targets': 7.27.0 '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.10) '@babel/helpers': 7.27.0 - '@babel/parser': 7.27.0 + '@babel/parser': 7.28.3 '@babel/template': 7.27.0 '@babel/traverse': 7.27.0 - '@babel/types': 7.27.0 + '@babel/types': 7.28.2 convert-source-map: 2.0.0 debug: 4.4.0 gensync: 1.0.0-beta.2 @@ -3503,15 +3540,15 @@ snapshots: '@babel/generator@7.27.0': dependencies: - '@babel/parser': 7.27.0 - '@babel/types': 7.27.0 + '@babel/parser': 7.28.3 + '@babel/types': 7.28.2 '@jridgewell/gen-mapping': 0.3.8 '@jridgewell/trace-mapping': 0.3.25 jsesc: 3.1.0 '@babel/helper-annotate-as-pure@7.25.9': dependencies: - '@babel/types': 7.27.0 + '@babel/types': 7.28.2 '@babel/helper-compilation-targets@7.27.0': dependencies: @@ -3555,14 +3592,14 @@ snapshots: '@babel/helper-member-expression-to-functions@7.25.9': dependencies: '@babel/traverse': 7.27.0 - '@babel/types': 7.27.0 + '@babel/types': 7.28.2 transitivePeerDependencies: - supports-color '@babel/helper-module-imports@7.25.9': dependencies: '@babel/traverse': 7.27.0 - '@babel/types': 7.27.0 + '@babel/types': 7.28.2 transitivePeerDependencies: - supports-color @@ -3570,14 +3607,14 @@ snapshots: dependencies: '@babel/core': 7.26.10 '@babel/helper-module-imports': 7.25.9 - '@babel/helper-validator-identifier': 7.25.9 + '@babel/helper-validator-identifier': 7.27.1 '@babel/traverse': 7.27.0 transitivePeerDependencies: - supports-color '@babel/helper-optimise-call-expression@7.25.9': dependencies: - '@babel/types': 7.27.0 + '@babel/types': 7.28.2 '@babel/helper-plugin-utils@7.26.5': {} @@ -3602,28 +3639,32 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers@7.25.9': dependencies: '@babel/traverse': 7.27.0 - '@babel/types': 7.27.0 + '@babel/types': 7.28.2 transitivePeerDependencies: - supports-color '@babel/helper-string-parser@7.25.9': {} + '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-validator-identifier@7.25.9': {} + '@babel/helper-validator-identifier@7.27.1': {} + '@babel/helper-validator-option@7.25.9': {} '@babel/helper-wrap-function@7.25.9': dependencies: '@babel/template': 7.27.0 '@babel/traverse': 7.27.0 - '@babel/types': 7.27.0 + '@babel/types': 7.28.2 transitivePeerDependencies: - supports-color '@babel/helpers@7.27.0': dependencies: '@babel/template': 7.27.0 - '@babel/types': 7.27.0 + '@babel/types': 7.28.2 '@babel/parser@7.26.2': dependencies: @@ -3633,6 +3674,10 @@ snapshots: dependencies: '@babel/types': 7.27.0 + '@babel/parser@7.28.3': + dependencies: + '@babel/types': 7.28.2 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 @@ -3850,7 +3895,7 @@ snapshots: '@babel/core': 7.26.10 '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.10) '@babel/helper-plugin-utils': 7.26.5 - '@babel/helper-validator-identifier': 7.25.9 + '@babel/helper-validator-identifier': 7.27.1 '@babel/traverse': 7.27.0 transitivePeerDependencies: - supports-color @@ -4086,7 +4131,7 @@ snapshots: dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/types': 7.27.0 + '@babel/types': 7.28.2 esutils: 2.0.3 '@babel/runtime@7.27.0': @@ -4096,16 +4141,16 @@ snapshots: '@babel/template@7.27.0': dependencies: '@babel/code-frame': 7.26.2 - '@babel/parser': 7.27.0 - '@babel/types': 7.27.0 + '@babel/parser': 7.28.3 + '@babel/types': 7.28.2 '@babel/traverse@7.27.0': dependencies: '@babel/code-frame': 7.26.2 '@babel/generator': 7.27.0 - '@babel/parser': 7.27.0 + '@babel/parser': 7.28.3 '@babel/template': 7.27.0 - '@babel/types': 7.27.0 + '@babel/types': 7.28.2 debug: 4.4.0 globals: 11.12.0 transitivePeerDependencies: @@ -4121,6 +4166,11 @@ snapshots: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 + '@babel/types@7.28.2': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@bufbuild/protobuf@2.2.2': {} '@canvas/image-data@1.0.0': {} @@ -4569,12 +4619,12 @@ snapshots: sharp-ico: 0.1.5 unconfig: 7.3.1 - '@vitejs/plugin-vue@5.2.3(vite@5.4.17(sass-embedded@1.86.3)(sass@1.86.3)(terser@5.39.0))(vue@3.5.13)': + '@vitejs/plugin-vue@5.2.3(vite@5.4.17(sass-embedded@1.86.3)(sass@1.86.3)(terser@5.39.0))(vue@3.5.20)': dependencies: vite: 5.4.17(sass-embedded@1.86.3)(sass@1.86.3)(terser@5.39.0) - vue: 3.5.13 + vue: 3.5.20 - '@vue-macros/common@1.16.1(vue@3.5.13)': + '@vue-macros/common@1.16.1(vue@3.5.20)': dependencies: '@vue/compiler-sfc': 3.5.13 ast-kit: 1.4.2 @@ -4583,7 +4633,7 @@ snapshots: pathe: 2.0.3 picomatch: 4.0.2 optionalDependencies: - vue: 3.5.13 + vue: 3.5.20 '@vue/compiler-core@3.5.13': dependencies: @@ -4593,11 +4643,24 @@ snapshots: estree-walker: 2.0.2 source-map-js: 1.2.1 + '@vue/compiler-core@3.5.20': + dependencies: + '@babel/parser': 7.28.3 + '@vue/shared': 3.5.20 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + '@vue/compiler-dom@3.5.13': dependencies: '@vue/compiler-core': 3.5.13 '@vue/shared': 3.5.13 + '@vue/compiler-dom@3.5.20': + dependencies: + '@vue/compiler-core': 3.5.20 + '@vue/shared': 3.5.20 + '@vue/compiler-sfc@3.5.13': dependencies: '@babel/parser': 7.26.2 @@ -4610,11 +4673,28 @@ snapshots: postcss: 8.4.49 source-map-js: 1.2.1 + '@vue/compiler-sfc@3.5.20': + dependencies: + '@babel/parser': 7.28.3 + '@vue/compiler-core': 3.5.20 + '@vue/compiler-dom': 3.5.20 + '@vue/compiler-ssr': 3.5.20 + '@vue/shared': 3.5.20 + estree-walker: 2.0.2 + magic-string: 0.30.17 + postcss: 8.5.6 + source-map-js: 1.2.1 + '@vue/compiler-ssr@3.5.13': dependencies: '@vue/compiler-dom': 3.5.13 '@vue/shared': 3.5.13 + '@vue/compiler-ssr@3.5.20': + dependencies: + '@vue/compiler-dom': 3.5.20 + '@vue/shared': 3.5.20 + '@vue/devtools-api@6.6.4': {} '@vue/devtools-api@7.7.2': @@ -4635,35 +4715,37 @@ snapshots: dependencies: rfdc: 1.4.1 - '@vue/reactivity@3.5.13': + '@vue/reactivity@3.5.20': dependencies: - '@vue/shared': 3.5.13 + '@vue/shared': 3.5.20 - '@vue/runtime-core@3.5.13': + '@vue/runtime-core@3.5.20': dependencies: - '@vue/reactivity': 3.5.13 - '@vue/shared': 3.5.13 + '@vue/reactivity': 3.5.20 + '@vue/shared': 3.5.20 - '@vue/runtime-dom@3.5.13': + '@vue/runtime-dom@3.5.20': dependencies: - '@vue/reactivity': 3.5.13 - '@vue/runtime-core': 3.5.13 - '@vue/shared': 3.5.13 + '@vue/reactivity': 3.5.20 + '@vue/runtime-core': 3.5.20 + '@vue/shared': 3.5.20 csstype: 3.1.3 - '@vue/server-renderer@3.5.13(vue@3.5.13)': + '@vue/server-renderer@3.5.20(vue@3.5.20)': dependencies: - '@vue/compiler-ssr': 3.5.13 - '@vue/shared': 3.5.13 - vue: 3.5.13 + '@vue/compiler-ssr': 3.5.20 + '@vue/shared': 3.5.20 + vue: 3.5.20 '@vue/shared@3.5.13': {} - '@vuetify/loader-shared@2.1.0(vue@3.5.13)(vuetify@3.8.0)': + '@vue/shared@3.5.20': {} + + '@vuetify/loader-shared@2.1.1(vue@3.5.20)(vuetify@3.9.6)': dependencies: upath: 2.0.1 - vue: 3.5.13 - vuetify: 3.8.0(vite-plugin-vuetify@2.1.1)(vue@3.5.13) + vue: 3.5.20 + vuetify: 3.9.6(vite-plugin-vuetify@2.1.2)(vue@3.5.20) acorn-jsx@5.3.2(acorn@8.14.0): dependencies: @@ -4788,10 +4870,10 @@ snapshots: dependencies: possible-typed-array-names: 1.0.0 - axios@1.8.4: + axios@1.11.0: dependencies: follow-redirects: 1.15.9 - form-data: 4.0.1 + form-data: 4.0.4 proxy-from-env: 1.1.0 transitivePeerDependencies: - debug @@ -5516,10 +5598,12 @@ snapshots: dependencies: is-callable: 1.2.7 - form-data@4.0.1: + form-data@4.0.4: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 mime-types: 2.1.35 fs-extra@9.1.0: @@ -5670,7 +5754,7 @@ snapshots: idb@7.1.1: {} - idb@8.0.2: {} + idb@8.0.3: {} ignore@5.3.2: {} @@ -5893,7 +5977,7 @@ snapshots: jiti@2.4.2: {} - js-base64@3.7.7: {} + js-base64@3.7.8: {} js-tokens@4.0.0: {} @@ -6131,12 +6215,12 @@ snapshots: picomatch@4.0.2: {} - pinia@3.0.1(vue@3.5.13): + pinia@3.0.3(vue@3.5.20): dependencies: '@vue/devtools-api': 7.7.2 - vue: 3.5.13 + vue: 3.5.20 - pinyin-pro@3.26.0: {} + pinyin-pro@3.27.0: {} pkg-types@1.3.1: dependencies: @@ -6169,6 +6253,12 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + prelude-ls@1.2.1: {} pretty-bytes@5.6.0: {} @@ -6871,7 +6961,7 @@ snapshots: pathe: 2.0.3 picomatch: 4.0.2 - unplugin-vue-components@28.4.1(@babel/parser@7.27.0)(vue@3.5.13): + unplugin-vue-components@28.4.1(@babel/parser@7.28.3)(vue@3.5.20): dependencies: chokidar: 3.6.0 debug: 4.4.0 @@ -6881,16 +6971,16 @@ snapshots: tinyglobby: 0.2.12 unplugin: 2.2.2 unplugin-utils: 0.2.4 - vue: 3.5.13 + vue: 3.5.20 optionalDependencies: - '@babel/parser': 7.27.0 + '@babel/parser': 7.28.3 transitivePeerDependencies: - supports-color - unplugin-vue-router@0.12.0(vue-router@4.5.0(vue@3.5.13))(vue@3.5.13): + unplugin-vue-router@0.12.0(vue-router@4.5.1(vue@3.5.20))(vue@3.5.20): dependencies: '@babel/types': 7.27.0 - '@vue-macros/common': 1.16.1(vue@3.5.13) + '@vue-macros/common': 1.16.1(vue@3.5.20) ast-walker-scope: 0.6.2 chokidar: 4.0.3 fast-glob: 3.3.3 @@ -6905,7 +6995,7 @@ snapshots: unplugin-utils: 0.2.4 yaml: 2.7.1 optionalDependencies: - vue-router: 4.5.0(vue@3.5.13) + vue-router: 4.5.1(vue@3.5.20) transitivePeerDependencies: - vue @@ -6939,9 +7029,9 @@ snapshots: varint@6.0.0: {} - vite-plugin-pwa@1.0.0(@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): + 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): dependencies: - debug: 4.3.7 + debug: 4.4.0 pretty-bytes: 6.1.1 tinyglobby: 0.2.12 vite: 5.4.17(sass-embedded@1.86.3)(sass@1.86.3)(terser@5.39.0) @@ -6952,24 +7042,24 @@ snapshots: transitivePeerDependencies: - supports-color - vite-plugin-vue-layouts@0.11.0(vite@5.4.17(sass-embedded@1.86.3)(sass@1.86.3)(terser@5.39.0))(vue-router@4.5.0(vue@3.5.13))(vue@3.5.13): + vite-plugin-vue-layouts@0.11.0(vite@5.4.17(sass-embedded@1.86.3)(sass@1.86.3)(terser@5.39.0))(vue-router@4.5.1(vue@3.5.20))(vue@3.5.20): dependencies: debug: 4.3.7 fast-glob: 3.3.2 vite: 5.4.17(sass-embedded@1.86.3)(sass@1.86.3)(terser@5.39.0) - vue: 3.5.13 - vue-router: 4.5.0(vue@3.5.13) + vue: 3.5.20 + vue-router: 4.5.1(vue@3.5.20) transitivePeerDependencies: - supports-color - vite-plugin-vuetify@2.1.1(vite@5.4.17(sass-embedded@1.86.3)(sass@1.86.3)(terser@5.39.0))(vue@3.5.13)(vuetify@3.8.0): + vite-plugin-vuetify@2.1.2(vite@5.4.17(sass-embedded@1.86.3)(sass@1.86.3)(terser@5.39.0))(vue@3.5.20)(vuetify@3.9.6): dependencies: - '@vuetify/loader-shared': 2.1.0(vue@3.5.13)(vuetify@3.8.0) - debug: 4.3.7 + '@vuetify/loader-shared': 2.1.1(vue@3.5.20)(vuetify@3.9.6) + debug: 4.4.0 upath: 2.0.1 vite: 5.4.17(sass-embedded@1.86.3)(sass@1.86.3)(terser@5.39.0) - vue: 3.5.13 - vuetify: 3.8.0(vite-plugin-vuetify@2.1.1)(vue@3.5.13) + vue: 3.5.20 + vuetify: 3.9.6(vite-plugin-vuetify@2.1.2)(vue@3.5.20) transitivePeerDependencies: - supports-color @@ -6997,24 +7087,24 @@ snapshots: transitivePeerDependencies: - supports-color - vue-router@4.5.0(vue@3.5.13): + vue-router@4.5.1(vue@3.5.20): dependencies: '@vue/devtools-api': 6.6.4 - vue: 3.5.13 + vue: 3.5.20 - vue@3.5.13: + vue@3.5.20: dependencies: - '@vue/compiler-dom': 3.5.13 - '@vue/compiler-sfc': 3.5.13 - '@vue/runtime-dom': 3.5.13 - '@vue/server-renderer': 3.5.13(vue@3.5.13) - '@vue/shared': 3.5.13 + '@vue/compiler-dom': 3.5.20 + '@vue/compiler-sfc': 3.5.20 + '@vue/runtime-dom': 3.5.20 + '@vue/server-renderer': 3.5.20(vue@3.5.20) + '@vue/shared': 3.5.20 - vuetify@3.8.0(vite-plugin-vuetify@2.1.1)(vue@3.5.13): + vuetify@3.9.6(vite-plugin-vuetify@2.1.2)(vue@3.5.20): dependencies: - vue: 3.5.13 + vue: 3.5.20 optionalDependencies: - vite-plugin-vuetify: 2.1.1(vite@5.4.17(sass-embedded@1.86.3)(sass@1.86.3)(terser@5.39.0))(vue@3.5.13)(vuetify@3.8.0) + vite-plugin-vuetify: 2.1.2(vite@5.4.17(sass-embedded@1.86.3)(sass@1.86.3)(terser@5.39.0))(vue@3.5.20)(vuetify@3.9.6) webidl-conversions@4.0.2: {} diff --git a/src/components/ExamConfigEditor.vue b/src/components/ExamConfigEditor.vue new file mode 100644 index 0000000..a7cf125 --- /dev/null +++ b/src/components/ExamConfigEditor.vue @@ -0,0 +1,1202 @@ + + + + + + mdi-alert-circle + {{ error }} + + + + + + + mdi-check-circle + {{ success }} + + + + + + + 配置验证失败,请检查以下问题: + + + + + mdi-circle-small + + {{ error }} + + + + + + + + + + + + + + + + 打开 ExamSchedule + + + + 请先完善配置信息后再打开 + + + + 删除配置 + + 预览 + 编辑 + + + + + + + + {{ localConfig.examName || "未设置考试名称" }} + + + {{ localConfig.message || "未设置考试提示" }} + + + mdi-home + 考场:{{ localConfig.room }} + + + + + + + + + mdi-book-open-page-variant + {{ examInfo.name || "未设置科目" }} + + + + + + mdi-clock-start + 开始时间 + + + {{ examInfo.startFormatted || examInfo.start || "未设置" }} + + + + + mdi-clock-end + 结束时间 + + + {{ examInfo.endFormatted || examInfo.end || "未设置" }} + + + + + + + + + + mdi-calendar-blank + + 暂无考试科目安排 + + 点击上方"添加科目"按钮开始配置考试时间表 + + + mdi-plus + 立即添加 + + + + + + + mdi-code-json + JSON配置预览 + + + 复制 + + + + + + + + {{ formattedJson }} + + + + + + + + + + + + mdi-information + 基本信息 + + + + + + + + + + + + + + + + mdi-plus + {{ tip }} + + + + mdi-lightbulb-outline + 点击上方选项快速添加常用考试提示 + + + + + + + + mdi-format-list-bulleted + 考试科目安排 + + + 添加科目 + + + + + + + + + + + + + + + + + + 选择开始时间 + + + + + + + + + + + + + + + 取消 + + + 确定 + + + + + + + + + + + + + 选择结束时间 + + + + + + + + + + + + + + + 取消 + + + 确定 + + + + + + + + mdi-delete + + + mdi-arrow-up + + + mdi-arrow-down + + + + + + + + + mdi-book-plus + + + 暂无考试科目,点击"添加科目"按钮开始添加 + + + 添加科目 + + + + + + + + + + + mdi-delete-alert + 确认删除配置 + + + 确定要删除配置 {{ localConfig.examName || `配置 ${configId}` }} 吗? + 此操作不可撤销,将会删除所有相关数据 + + + + + 取消 + + + 删除 + + + + + + + + + + diff --git a/src/components/settings/cards/DisplaySettingsCard.vue b/src/components/settings/cards/DisplaySettingsCard.vue index 198facf..b22db37 100644 --- a/src/components/settings/cards/DisplaySettingsCard.vue +++ b/src/components/settings/cards/DisplaySettingsCard.vue @@ -22,7 +22,8 @@ - + + diff --git a/src/components/settings/cards/KvDatabaseCard.vue b/src/components/settings/cards/KvDatabaseCard.vue index bf46db5..24ec47a 100644 --- a/src/components/settings/cards/KvDatabaseCard.vue +++ b/src/components/settings/cards/KvDatabaseCard.vue @@ -82,6 +82,13 @@ @click="editItem(item)" title="编辑" /> + + + + + + + 获取云端访问地址 + + + + + + 键名: {{ selectedCloudItem.key }} + + + + + {{ cloudUrlError }} + + + + 云端地址获取成功 + + + + 数据已从本地迁移到云端 + + + + 云端配置已自动设置 + + + + + + + + + + + 高级选项 + + + + + + + 重新获取 + + + + + + + + + + 关闭 + + + + 在新窗口打开 + + + + + @@ -289,11 +390,22 @@ export default { editDialog: false, deleteDialog: false, createDialog: false, + cloudUrlDialog: false, // 选中的项目 selectedItem: null, editingItem: null, itemToDelete: null, + selectedCloudItem: null, + + // 云端地址相关 + gettingCloudUrl: false, + cloudUrlResult: null, + cloudUrlError: null, + cloudUrlOptions: { + migrateFromLocal: true, + autoConfigureCloud: true + }, // 编辑数据 editingData: '', @@ -597,6 +709,67 @@ export default { } catch (error) { this.$message.error('复制失败', error.message); } + }, + + async getCloudUrl(item) { + this.selectedCloudItem = item; + this.cloudUrlResult = null; + this.cloudUrlError = null; + this.cloudUrlDialog = true; + + await this.fetchCloudUrl(); + }, + + async fetchCloudUrl() { + if (!this.selectedCloudItem) return; + + this.gettingCloudUrl = true; + this.cloudUrlError = null; + + try { + const result = await dataProvider.getKeyCloudUrl( + this.selectedCloudItem.key, + this.cloudUrlOptions + ); + + if (result.success) { + this.cloudUrlResult = result; + this.$message.success('云端地址获取成功'); + } else { + this.cloudUrlError = result.error?.message || '获取云端地址失败'; + this.$message.error('获取失败', this.cloudUrlError); + } + } catch (error) { + this.cloudUrlError = error.message || '获取云端地址时发生错误'; + this.$message.error('获取失败', this.cloudUrlError); + } finally { + this.gettingCloudUrl = false; + } + }, + + async refreshCloudUrl() { + await this.fetchCloudUrl(); + }, + + async copyCloudUrl() { + if (!this.cloudUrlResult?.url) return; + + try { + await navigator.clipboard.writeText(this.cloudUrlResult.url); + this.$message.success('云端地址已复制到剪贴板'); + } catch (error) { + this.$message.error('复制失败', error.message); + } + }, + + openCloudUrl() { + if (!this.cloudUrlResult?.url) return; + + try { + window.open(this.cloudUrlResult.url, '_blank'); + } catch (error) { + this.$message.error('打开链接失败', error.message); + } } } }; diff --git a/src/pages/examschedule.vue b/src/pages/examschedule.vue new file mode 100644 index 0000000..a28cfff --- /dev/null +++ b/src/pages/examschedule.vue @@ -0,0 +1,611 @@ + + + + + + + mdi-calendar-check + 考试看板 + + + 不只是考试看板。 + + + + + + mdi-alert-circle + {{ error }} + + + + + + + mdi-check-circle + {{ success }} + + + + + + + + 新建配置 + + + 刷新 + + + + {{ configs.length }} 个配置 + + + + + + + + + + + + + + mdi-format-list-bulleted + 配置列表 + + + + + + mdi-calendar-text + + + + + {{ config.examName || `配置 ${config.id}` }} + + + + mdi-information-outline + {{ config.message || '无描述' }} + + + mdi-book-multiple + {{ config.examInfos ? config.examInfos.length : 0 }} 堂考试 + + + + + + + mdi-pencil + + + + mdi-eye + + + + + + + + + + + + + + mdi-calendar-blank + + 暂无配置 + + 点击"新建配置"按钮创建您的第一个考试配置 + + + 新建配置 + + + + + + + + + + + + + mdi-rename-box + 重命名配置 + + + + + + + + 取消 + + + 确认 + + + + + + + + + + mdi-pencil + 编辑考试配置 + + + ID: {{ editingConfig.id }} + + + + mdi-close + + + + + + + + 关闭 + + + + 保存配置 + + + + + + + + + + diff --git a/src/pages/index.vue b/src/pages/index.vue index cb032d3..1e53538 100644 --- a/src/pages/index.vue +++ b/src/pages/index.vue @@ -116,6 +116,16 @@ > 随机点名 + + 考试看板 + data; @@ -44,7 +44,7 @@ export default { * @param {number} options.limit - 每页返回的记录数,默认为 100 * @param {number} options.skip - 跳过的记录数,默认为 0 * @returns {Promise} 包含键名列表和分页信息的响应对象 - * + * * 使用示例: * ```javascript * // 获取前10个键名 @@ -53,14 +53,14 @@ export default { * console.log('键名列表:', result.keys); * console.log('总数:', result.total_rows); * } - * + * * // 获取第二页数据(跳过前10个) * const page2 = await dataProvider.loadKeys({ limit: 10, skip: 10 }); - * + * * // 按键名降序排列 * const sorted = await dataProvider.loadKeys({ sortDir: 'desc' }); * ``` - * + * * 返回值格式: * ```javascript * { @@ -86,8 +86,189 @@ export default { return kvLocalProvider.loadKeys(options); } }, + + /** + * 获取键的云端访问地址,并处理本地到云端的数据迁移 + * + * 功能说明: + * 1. 如果用户选择本地存储,则将本地键数据读取并存储到云端 + * 2. 如果云端配置为空或错误则自动改成classworksCloudDefaults的配置 + * 3. 根据网站验证情况(私有则添加token,公开或受保护则不需要)拼接键的get路径并返回 + * + * @param {string} key - 要获取地址的键名 + * @param {Object} options - 选项配置 + * @param {boolean} options.migrateFromLocal - 是否从本地迁移数据到云端,默认为true + * @param {boolean} options.autoConfigureCloud - 是否自动配置云端默认设置,默认为true + * @returns {Promise} 包含键访问地址和操作结果的响应对象 + * + * 使用示例: + * ```javascript + * import dataProvider from '@/utils/dataProvider'; + * + * // 基本用法:获取键的云端地址并自动迁移本地数据 + * const result = await dataProvider.getKeyCloudUrl('exam_configs'); + * if (result.success) { + * console.log('云端访问地址:', result.url); + * console.log('是否已迁移数据:', result.migrated); + * console.log('是否自动配置:', result.configured); + * } else { + * console.error('获取失败:', result.error.message); + * } + * + * // 仅获取地址,不迁移数据 + * const urlOnly = await dataProvider.getKeyCloudUrl('my_data', { + * migrateFromLocal: false + * }); + * + * // 不自动配置云端设置 + * const noAutoConfig = await dataProvider.getKeyCloudUrl('my_data', { + * autoConfigureCloud: false + * }); + * ``` + * + * 传入参数示例: + * ```javascript + * // 参数1: key (必需) + * 'exam_configs' // 字符串类型的键名 + * + * // 参数2: options (可选) + * { + * migrateFromLocal: true, // 是否迁移本地数据 + * autoConfigureCloud: true // 是否自动配置云端 + * } + * ``` + * + * 返回值格式: + * ```javascript + * // 成功时返回: + * { + * success: true, + * url: "https://kv.wuyuan.dev/device-uuid-123/exam_configs?token=abc123", // 私有访问时包含token + * migrated: true, // 是否成功迁移了本地数据 + * configured: false // 是否自动配置了云端设置 + * } + * + * // 公开访问时返回: + * { + * success: true, + * url: "https://kv.wuyuan.dev/device-uuid-123/exam_configs", // 公开访问不包含token + * migrated: false, + * configured: true + * } + * + * // 失败时返回: + * { + * success: false, + * error: { + * code: "CLOUD_URL_ERROR", + * message: "获取键云端地址失败" + * } + * } + * ``` + */ + async getKeyCloudUrl(key, options = {}) { + const { + migrateFromLocal = true, + autoConfigureCloud = true + } = options; + + try { + let serverUrl = getSetting("server.domain"); + let siteKey = getSetting("server.siteKey"); + const machineId = getSetting("device.uuid"); + let configured = false; + + // 检查云端配置是否为空或错误,如果是则使用默认配置 + if (!serverUrl || !machineId) { + if (autoConfigureCloud) { + // 使用classworksCloudDefaults配置 + const classworksCloudDefaults = { + "server.domain": "https://kv.wuyuan.dev", + "server.siteKey": "", + }; + + if (!serverUrl) { + setSetting("server.domain", classworksCloudDefaults["server.domain"]); + serverUrl = classworksCloudDefaults["server.domain"]; + configured = true; + } + + if (!siteKey) { + setSetting("server.siteKey", classworksCloudDefaults["server.siteKey"]); + siteKey = classworksCloudDefaults["server.siteKey"]; + } + + // 设置provider为classworkscloud + setSetting("server.provider", "classworkscloud"); + } else { + return formatError("云端配置无效,请检查服务器域名和设备UUID", "CONFIG_ERROR"); + } + } + + let migrated = false; + + // 如果需要迁移本地数据到云端 + if (migrateFromLocal) { + try { + // 尝试从本地读取数据 + const localData = await kvLocalProvider.loadData(key); + + // 如果本地有数据且不是错误响应 + if (localData && localData.success !== false) { + // 检查云端是否已有数据 + const cloudData = await kvServerProvider.loadData(key); + + // 如果云端没有数据,则迁移本地数据 + if (cloudData && cloudData.success === false && cloudData.error?.code === "NOT_FOUND") { + const saveResult = await kvServerProvider.saveData(key, localData); + if (saveResult && saveResult.success !== false) { + migrated = true; + console.log(`已成功将键 ${key} 的数据从本地迁移到云端`); + } + } + } + } catch (error) { + console.warn(`迁移键 ${key} 的数据时出错:`, error); + // 迁移失败不影响URL生成,继续执行 + } + } + + // 构建云端访问URL + let url = `${serverUrl}/${machineId}/${key}`; + + // 根据网站验证情况添加token参数 + const namespaceInfo = await kvServerProvider.loadNamespaceInfo(); + if (namespaceInfo && namespaceInfo.success !== false) { + const { accessType } = namespaceInfo; + + // 如果是私有访问,添加token参数 + if (accessType === 'private' && siteKey) { + const urlObj = new URL(url); + urlObj.searchParams.set('token', siteKey); + url = urlObj.toString(); + } + // 公开或受保护访问不需要token参数 + } + + return { + success: true, + url, + migrated, + configured + }; + + } catch (error) { + console.error('获取键云端地址时出错:', error); + return formatError( + error.message || "获取键云端地址失败", + "CLOUD_URL_ERROR" + ); + } + }, }; + + export const ErrorCodes = { NOT_FOUND: "数据不存在", NETWORK_ERROR: "网络连接失败", @@ -96,5 +277,6 @@ export const ErrorCodes = { CONFIG_ERROR: "配置错误", PERMISSION_DENIED: "无权限访问", UNAUTHORIZED: "认证失败", + CLOUD_URL_ERROR: "云端地址获取失败", UNKNOWN_ERROR: "未知错误", }; diff --git a/src/utils/providers/kvLocalProvider.js b/src/utils/providers/kvLocalProvider.js index b1dd3ff..4417964 100644 --- a/src/utils/providers/kvLocalProvider.js +++ b/src/utils/providers/kvLocalProvider.js @@ -55,7 +55,7 @@ export const kvLocalProvider = { * @param {number} options.limit - 每页返回的记录数,默认为 100 * @param {number} options.skip - 跳过的记录数,默认为 0 * @returns {Promise} 包含键名列表和分页信息的响应对象 - * + * * 返回值示例: * { * keys: ["key1", "key2", "key3"], @@ -73,18 +73,16 @@ export const kvLocalProvider = { const db = await initDB(); const transaction = db.transaction(["kv"], "readonly"); const store = transaction.objectStore("kv"); - + // 获取所有键名 const allKeys = await store.getAllKeys(); - + // 设置默认参数 const { - sortBy = "key", sortDir = "asc", limit = 100, skip = 0 } = options; - // 排序键名(本地存储只支持按键名排序) const sortedKeys = allKeys.sort((a, b) => { if (sortDir === "desc") { @@ -92,11 +90,11 @@ export const kvLocalProvider = { } return a.localeCompare(b); }); - + // 应用分页 const totalRows = sortedKeys.length; const paginatedKeys = sortedKeys.slice(skip, skip + limit); - + // 构建响应数据 const responseData = { keys: paginatedKeys, @@ -108,7 +106,7 @@ export const kvLocalProvider = { }, load_more: null // 本地存储不需要分页URL }; - + return formatResponse(responseData); } catch (error) { return formatError("获取本地键名列表失败:" + error.message); diff --git a/src/utils/settings.js b/src/utils/settings.js index 301fc9c..816f1a2 100644 --- a/src/utils/settings.js +++ b/src/utils/settings.js @@ -170,6 +170,13 @@ const settingsDefinitions = { description: "是否显示列表卡片", icon: "mdi-list-box", }, + "display.showExamScheduleButton": { + type: "boolean", + default: true, + description: "是否显示考试看板", + icon: "mdi-calendar-check", + // 控制是否在主页显示考试看板按钮,指向考试安排页面 + }, // 服务器设置(合并了数据提供者设置) "server.domain": { type: "string",
{{ formattedJson }}
+ 暂无考试科目,点击"添加科目"按钮开始添加 +
{{ selectedCloudItem.key }}
+ 点击"新建配置"按钮创建您的第一个考试配置 +