feat:更新训练场模块

This commit is contained in:
2026-07-30 13:08:23 +08:00
parent 78237984ec
commit 280ea9f7d0
21 changed files with 935 additions and 201 deletions

View File

@@ -15,6 +15,7 @@
"dayjs": "^1.11.21",
"element-plus": "^2.14.3",
"filesize": "^11.0.22",
"md-editor-v3": "^6.5.5",
"pinia": "^4.0.2",
"vue": "^3.5.39",
"vue-router": "^5.2.0",

685
pnpm-lock.yaml generated
View File

@@ -26,6 +26,9 @@ importers:
filesize:
specifier: ^11.0.22
version: 11.0.22
md-editor-v3:
specifier: ^6.5.5
version: 6.5.5(vue@3.5.40(typescript@6.0.3))
pinia:
specifier: ^4.0.2
version: 4.0.2(@vue/devtools-api@8.2.1)(typescript@6.0.3)(vue@3.5.40(typescript@6.0.3))
@@ -108,6 +111,96 @@ packages:
resolution: {integrity: sha512-eY+Yn3dCqTGmyiq2QRU66lA5FL8lqqqvecHt0fF3uHONIa7ToYsaCiWV8lOKqAs0Rb2SjixiKFROngnulPtt2g==}
engines: {node: ^22.18.0 || >=24.11.0}
'@codemirror/autocomplete@6.20.3':
resolution: {integrity: sha512-tlosUqb+3BbxCxZdu4tKeRghPFC+QM7q4X5YhKV2eCmPG+1r2F3f4AaSz5sCrFqUtX4Jh20VFTKecl16MgiV9g==}
'@codemirror/commands@6.10.4':
resolution: {integrity: sha512-Ryk9y9T0FFVF0cUGhAknveAyUOl/A1qReTFi+qPKtOh2Z9F4AUBz3XOrYD4ZEgZirdugVzHvd/2/Wcwy5OliTg==}
'@codemirror/lang-angular@0.1.4':
resolution: {integrity: sha512-oap+gsltb/fzdlTQWD6BFF4bSLKcDnlxDsLdePiJpCVNKWXSTAbiiQeYI3UmES+BLAdkmIC1WjyztC1pi/bX4g==}
'@codemirror/lang-cpp@6.0.3':
resolution: {integrity: sha512-URM26M3vunFFn9/sm6rzqrBzDgfWuDixp85uTY49wKudToc2jTHUrKIGGKs+QWND+YLofNNZpxcNGRynFJfvgA==}
'@codemirror/lang-css@6.3.1':
resolution: {integrity: sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==}
'@codemirror/lang-go@6.0.1':
resolution: {integrity: sha512-7fNvbyNylvqCphW9HD6WFnRpcDjr+KXX/FgqXy5H5ZS0eC5edDljukm/yNgYkwTsgp2busdod50AOTIy6Jikfg==}
'@codemirror/lang-html@6.4.11':
resolution: {integrity: sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw==}
'@codemirror/lang-java@6.0.2':
resolution: {integrity: sha512-m5Nt1mQ/cznJY7tMfQTJchmrjdjQ71IDs+55d1GAa8DGaB8JXWsVCkVT284C3RTASaY43YknrK2X3hPO/J3MOQ==}
'@codemirror/lang-javascript@6.2.5':
resolution: {integrity: sha512-zD4e5mS+50htS7F+TYjBPsiIFGanfVqg4HyUz6WNFikgOPf2BgKlx+TQedI1w6n/IqRBVBbBWmGFdLB/7uxO4A==}
'@codemirror/lang-jinja@6.0.1':
resolution: {integrity: sha512-P5kyHLObzjtbGj16h+hyvZTxJhSjBEeSx4wMjbnAf3b0uwTy2+F0zGjMZL4PQOm/mh2eGZ5xUDVZXgwP783Nsw==}
'@codemirror/lang-json@6.0.2':
resolution: {integrity: sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==}
'@codemirror/lang-less@6.0.2':
resolution: {integrity: sha512-EYdQTG22V+KUUk8Qq582g7FMnCZeEHsyuOJisHRft/mQ+ZSZ2w51NupvDUHiqtsOy7It5cHLPGfHQLpMh9bqpQ==}
'@codemirror/lang-liquid@6.3.2':
resolution: {integrity: sha512-6PDVU3ZnfeYyz1at1E/ttorErZvZFXXt1OPhtfe1EZJ2V2iDFa0CwPqPgG5F7NXN0yONGoBogKmFAafKTqlwIw==}
'@codemirror/lang-markdown@6.5.1':
resolution: {integrity: sha512-6re5avCNfyRMIoi3XNjbEfQM1vTeVD3JS3g/Fyegyso/eoANFM71Cyvbb66LDyYtQLMEcRFlzioywCqDo9SlLA==}
'@codemirror/lang-php@6.0.2':
resolution: {integrity: sha512-ZKy2v1n8Fc8oEXj0Th0PUMXzQJ0AIR6TaZU+PbDHExFwdu+guzOA4jmCHS1Nz4vbFezwD7LyBdDnddSJeScMCA==}
'@codemirror/lang-python@6.2.1':
resolution: {integrity: sha512-IRjC8RUBhn9mGR9ywecNhB51yePWCGgvHfY1lWN/Mrp3cKuHr0isDKia+9HnvhiWNnMpbGhWrkhuWOc09exRyw==}
'@codemirror/lang-rust@6.0.2':
resolution: {integrity: sha512-EZaGjCUegtiU7kSMvOfEZpaCReowEf3yNidYu7+vfuGTm9ow4mthAparY5hisJqOHmJowVH3Upu+eJlUji6qqA==}
'@codemirror/lang-sass@6.0.2':
resolution: {integrity: sha512-l/bdzIABvnTo1nzdY6U+kPAC51czYQcOErfzQ9zSm9D8GmNPD0WTW8st/CJwBTPLO8jlrbyvlSEcN20dc4iL0Q==}
'@codemirror/lang-sql@6.10.0':
resolution: {integrity: sha512-6ayPkEd/yRw0XKBx5uAiToSgGECo/GY2NoJIHXIIQh1EVwLuKoU8BP/qK0qH5NLXAbtJRLuT73hx7P9X34iO4w==}
'@codemirror/lang-vue@0.1.3':
resolution: {integrity: sha512-QSKdtYTDRhEHCfo5zOShzxCmqKJvgGrZwDQSdbvCRJ5pRLWBS7pD/8e/tH44aVQT6FKm0t6RVNoSUWHOI5vNug==}
'@codemirror/lang-wast@6.0.2':
resolution: {integrity: sha512-Imi2KTpVGm7TKuUkqyJ5NRmeFWF7aMpNiwHnLQe0x9kmrxElndyH0K6H/gXtWwY6UshMRAhpENsgfpSwsgmC6Q==}
'@codemirror/lang-xml@6.1.0':
resolution: {integrity: sha512-3z0blhicHLfwi2UgkZYRPioSgVTo9PV5GP5ducFH6FaHy0IAJRg+ixj5gTR1gnT/glAIC8xv4w2VL1LoZfs+Jg==}
'@codemirror/lang-yaml@6.1.3':
resolution: {integrity: sha512-AZ8DJBuXGVHybpBQhmZtgew5//4hv3tdkXnr3vDmOUMJRuB6vn/uuwtmTOTlqEaQFg3hQSVeA90NmvIQyUV6FQ==}
'@codemirror/language-data@6.5.2':
resolution: {integrity: sha512-CPkWBKrNS8stYbEU5kwBwTf3JB1kghlbh4FSAwzGW2TEscdeHHH4FGysREW86Mqnj3Qn09s0/6Ea/TutmoTobg==}
'@codemirror/language@6.12.4':
resolution: {integrity: sha512-1q4PaT+o6PbgpkJt4Q8Fv5XJxTy4FUZ4MWETtyiDw3J0Pyr9E2vqcKL+k9wcvjNTIsauxvE7OfmWj3FRPHQ76A==}
'@codemirror/legacy-modes@6.5.3':
resolution: {integrity: sha512-xCsmIzH78MyWkib9jlPaaun57XNkfbMIhagfaZVd0iLTqlpw3jXaIcbZm72MTmmn64eTZpBVNjbyYh+QXnxRsg==}
'@codemirror/lint@6.9.7':
resolution: {integrity: sha512-28/+iWLYxKxsvGYhSYL7zaCZqLz5+FFFDq9tVsvGv9kv8RY4fFAchJ5WX9M3YrrRlTIsECjsXPqeNgnSmNP2dg==}
'@codemirror/search@6.7.1':
resolution: {integrity: sha512-uMe5UO6PamJtSHrXhhHOzSX3ReWtiJrva6GnPMwSOrZtiExb5X5eExhr2OUZQVvdxPsKpY3Ro2mFbQadpPWmHA==}
'@codemirror/state@6.7.1':
resolution: {integrity: sha512-9QzNDgE4EYDnAHfrTlR2lwiPciiOymLtwKK+8yHQzCc7GXhAP9xdEbEJFy2IWB1j9UGUl9BsgMmTo/ImA02T7A==}
'@codemirror/view@6.43.7':
resolution: {integrity: sha512-FZsExxkoxnAN+d9TgqXLg5g4A1oQwzX9WlkOT5i2PKkcW7xx3Bmu0vs90g6fo9Mpdsb/l96dnAraQ8932aO4/g==}
'@ctrl/tinycolor@4.2.0':
resolution: {integrity: sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==}
engines: {node: '>=14'}
@@ -174,6 +267,65 @@ packages:
'@jridgewell/trace-mapping@0.3.31':
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
'@lezer/common@1.5.2':
resolution: {integrity: sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ==}
'@lezer/cpp@1.1.6':
resolution: {integrity: sha512-vh9gWWJOXFVY8HBHK3Twzq8MgwG2iN4GSyzBP9sCGTe37P15x2R14VaBQk0VA0ezTRN1KHYBBsHhvpGZ2Xy/pA==}
'@lezer/css@1.3.4':
resolution: {integrity: sha512-N+tn9tej2hPvyKgHEApMOQfHczDJCwxrRFS3SPn9QjYN+uwHvEDnCgKRrb3mxDYxRS8sKMM8fhC3+lc04Abz5Q==}
'@lezer/go@1.0.1':
resolution: {integrity: sha512-xToRsYxwsgJNHTgNdStpcvmbVuKxTapV0dM0wey1geMMRc9aggoVyKgzYp41D2/vVOx+Ii4hmE206kvxIXBVXQ==}
'@lezer/highlight@1.2.3':
resolution: {integrity: sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==}
'@lezer/html@1.3.13':
resolution: {integrity: sha512-oI7n6NJml729m7pjm9lvLvmXbdoMoi2f+1pwSDJkl9d68zGr7a9Btz8NdHTGQZtW2DA25ybeuv/SyDb9D5tseg==}
'@lezer/java@1.1.3':
resolution: {integrity: sha512-yHquUfujwg6Yu4Fd1GNHCvidIvJwi/1Xu2DaKl/pfWIA2c1oXkVvawH3NyXhCaFx4OdlYBVX5wvz2f7Aoa/4Xw==}
'@lezer/javascript@1.5.4':
resolution: {integrity: sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==}
'@lezer/json@1.0.3':
resolution: {integrity: sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==}
'@lezer/lr@1.4.10':
resolution: {integrity: sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A==}
'@lezer/markdown@1.7.2':
resolution: {integrity: sha512-iTkYvoVcKt3WkeL7qUDyXHONZEwLio4wj8KTNi2dnjQEXBZKMV63BpQrPqfsM+OkvuRbiSTAcycYAsQzLhRNoQ==}
'@lezer/php@1.0.5':
resolution: {integrity: sha512-W7asp9DhM6q0W6DYNwIkLSKOvxlXRrif+UXBMxzsJUuqmhE7oVU+gS3THO4S/Puh7Xzgm858UNaFi6dxTP8dJA==}
'@lezer/python@1.1.19':
resolution: {integrity: sha512-MhQIURHRytsNzP/YXnqpYKW6la6voAH3kyplTOOiCdjyFY6cWWGFVmYVdHIPrElqSDf4iCDktQCockB9FxuhzQ==}
'@lezer/rust@1.0.2':
resolution: {integrity: sha512-Lz5sIPBdF2FUXcWeCu1//ojFAZqzTQNRga0aYv6dYXqJqPfMdCAI0NzajWUd4Xijj1IKJLtjoXRPMvTKWBcqKg==}
'@lezer/sass@1.1.0':
resolution: {integrity: sha512-3mMGdCTUZ/84ArHOuXWQr37pnf7f+Nw9ycPUeKX+wu19b7pSMcZGLbaXwvD2APMBDOGxPmpK/O6S1v1EvLoqgQ==}
'@lezer/xml@1.0.6':
resolution: {integrity: sha512-CdDwirL0OEaStFue/66ZmFSeppuL6Dwjlk8qk153mSQwiSH/Dlri4GNymrNWnUmPl2Um7QfV1FO9KFUyX3Twww==}
'@lezer/yaml@1.0.4':
resolution: {integrity: sha512-2lrrHqxalACEbxIbsjhqGpSW8kWpUKuY6RHgnSAFZa6qK62wvnPxA8hGOwOoDbwHcOFs5M4o27mjGu+P7TvBmw==}
'@lucide/vue@1.27.0':
resolution: {integrity: sha512-LKDEZJ0Uo9UaT4vxBMYVwXeK/0dGcWCTdav1AK/aGD/jYsDPtiVvOgfM7jPlx9BVeyGZ1Uf0aQhHA++rmbe7rw==}
peerDependencies:
vue: '>=3.0.1'
'@marijn/find-cluster-break@1.0.3':
resolution: {integrity: sha512-FY+MKLBoTsLNJF/eLWaOsXGdz6uh3Iu1axjPf6TUq92IYumcTcXWHoS747JARLkcdlJ/Waiaxc5wQfFO8jC6NA==}
'@napi-rs/wasm-runtime@1.1.6':
resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==}
peerDependencies:
@@ -393,12 +545,21 @@ packages:
'@types/json5@0.0.29':
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
'@types/linkify-it@5.0.0':
resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==}
'@types/lodash-es@4.17.12':
resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==}
'@types/lodash@4.17.24':
resolution: {integrity: sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==}
'@types/markdown-it@14.1.2':
resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==}
'@types/mdurl@2.0.0':
resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==}
'@types/node@24.13.3':
resolution: {integrity: sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==}
@@ -466,6 +627,15 @@ packages:
resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
'@vavt/copy2clipboard@1.0.3':
resolution: {integrity: sha512-HtG48r2FBYp9eRvGB3QGmtRBH1zzRRAVvFbGgFstOwz4/DDaNiX0uZc3YVKPydqgOav26pibr9MtoCaWxn7aeA==}
'@vavt/markdown-theme@5.0.2':
resolution: {integrity: sha512-cGYEV2VIUmhT9p8Wua9yXh7sKN1f3cbztTFHlkYyH9SzbpiKUnQrcbDts/0fP6cmvZPOe9SWWsDujmyuHepJdQ==}
'@vavt/util@2.1.2':
resolution: {integrity: sha512-L3UbSJthJwr3wq0x93O5TrCepimrmVZaIl2ciZbeL18G5++gBhJXNhcH7RcVk/6rr3SavWOvwhig0mqRLoR7dw==}
'@vitejs/plugin-vue@6.0.8':
resolution: {integrity: sha512-0ZjgOg7oO6farnNGup7yvoM/YXZV84OZxHAwtflItNa/6zzQyVb5LNxyea3FEKEX2XlagIKzrlH7wwxkKgtiew==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -606,6 +776,9 @@ packages:
argparse@1.0.10:
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
array-buffer-byte-length@1.0.2:
resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==}
engines: {node: '>= 0.4'}
@@ -707,6 +880,9 @@ packages:
resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==}
engines: {node: '>= 20.19.0'}
codemirror@6.0.2:
resolution: {integrity: sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==}
color-convert@1.9.3:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
@@ -724,6 +900,9 @@ packages:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
commander@2.20.3:
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
@@ -733,6 +912,9 @@ packages:
confbox@0.2.4:
resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==}
crelt@1.0.7:
resolution: {integrity: sha512-aK6BbWfhf4U/wCcLHKPJl/xa6VkVstRaPywWtMKGwuOLc/wZTyQYuoxgvZnNsBvv7Kg3YTBQYYBCggcviQczuA==}
cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
@@ -745,6 +927,9 @@ packages:
engines: {node: '>=4'}
hasBin: true
cssfilter@0.0.10:
resolution: {integrity: sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==}
csstype@3.2.3:
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
@@ -827,6 +1012,10 @@ packages:
resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==}
engines: {node: '>=8.6'}
entities@4.5.0:
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
engines: {node: '>=0.12'}
entities@7.0.1:
resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==}
engines: {node: '>=0.12'}
@@ -1442,6 +1631,9 @@ packages:
resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==}
engines: {node: '>= 12.0.0'}
linkify-it@5.0.2:
resolution: {integrity: sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==}
local-pkg@1.2.1:
resolution: {integrity: sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==}
engines: {node: '>=14'}
@@ -1479,10 +1671,37 @@ packages:
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
markdown-it-image-figures@2.1.1:
resolution: {integrity: sha512-mwXSQ2nPeVUzCMIE3HlLvjRioopiqyJLNph0pyx38yf9mpqFDhNGnMpAXF9/A2Xv0oiF2cVyg9xwfF0HNAz05g==}
engines: {node: '>=12.0.0'}
peerDependencies:
markdown-it: '*'
markdown-it-sub@2.0.0:
resolution: {integrity: sha512-iCBKgwCkfQBRg2vApy9vx1C1Tu6D8XYo8NvevI3OlwzBRmiMtsJ2sXupBgEA7PPxiDwNni3qIUkhZ6j5wofDUA==}
markdown-it-sup@2.0.0:
resolution: {integrity: sha512-5VgmdKlkBd8sgXuoDoxMpiU+BiEt3I49GItBzzw7Mxq9CxvnhE/k09HFli09zgfFDRixDQDfDxi0mgBCXtaTvA==}
markdown-it@14.3.0:
resolution: {integrity: sha512-RCEsPjR+sr0x+AuYp601tKTkgFG4YEPLCzHST3cQ/fhlJkqAkz1L2/Qbp1j9qw5SBwQHFBoW8+hoN5xssOF0Tw==}
hasBin: true
math-intrinsics@1.1.0:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
md-editor-v3@6.5.5:
resolution: {integrity: sha512-XXw3TwLFL9C8f1n9z39dZ7T2aYkHA5Vi7IEB3sbkn+9BSi7xohEcHYMD1zV86fLH2KGKStA453jUZcEmZR3XSg==}
peerDependencies:
vue: ^3.5.3
mdurl@2.1.0:
resolution: {integrity: sha512-1+HBaOx0zi/dQWht8rNv9MYf9qqpqL/kxI0hXImU6Y547zM6Sni8BQibt7ifgMcYtQg41ao3Ivd6cnSM86inpg==}
medium-zoom@1.1.0:
resolution: {integrity: sha512-ewyDsp7k4InCUp3jRmwHBRFGyjBimKps/AJLjRSox+2q/2H4p/PNpQf+pwONWlJiOudkBXtbdmVbFjqyybfTmQ==}
memoize-one@6.0.0:
resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==}
@@ -1665,6 +1884,10 @@ packages:
resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==}
engines: {node: '>=10'}
punycode.js@2.3.1:
resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
engines: {node: '>=6'}
punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
@@ -1846,6 +2069,9 @@ packages:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
style-mod@4.1.3:
resolution: {integrity: sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==}
supports-color@5.5.0:
resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
engines: {node: '>=4'}
@@ -1917,6 +2143,9 @@ packages:
engines: {node: '>=14.17'}
hasBin: true
uc.micro@2.1.0:
resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
ufo@1.6.4:
resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==}
@@ -2073,6 +2302,9 @@ packages:
typescript:
optional: true
w3c-keyname@2.2.8:
resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==}
webpack-virtual-modules@0.6.2:
resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==}
@@ -2104,6 +2336,11 @@ packages:
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
xss@1.0.15:
resolution: {integrity: sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==}
engines: {node: '>= 0.10.0'}
hasBin: true
yaml@2.9.0:
resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==}
engines: {node: '>= 14.6'}
@@ -2157,6 +2394,257 @@ snapshots:
'@babel/helper-string-parser': 8.0.0
'@babel/helper-validator-identifier': 8.0.4
'@codemirror/autocomplete@6.20.3':
dependencies:
'@codemirror/language': 6.12.4
'@codemirror/state': 6.7.1
'@codemirror/view': 6.43.7
'@lezer/common': 1.5.2
'@codemirror/commands@6.10.4':
dependencies:
'@codemirror/language': 6.12.4
'@codemirror/state': 6.7.1
'@codemirror/view': 6.43.7
'@lezer/common': 1.5.2
'@codemirror/lang-angular@0.1.4':
dependencies:
'@codemirror/lang-html': 6.4.11
'@codemirror/lang-javascript': 6.2.5
'@codemirror/language': 6.12.4
'@lezer/common': 1.5.2
'@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.10
'@codemirror/lang-cpp@6.0.3':
dependencies:
'@codemirror/language': 6.12.4
'@lezer/cpp': 1.1.6
'@codemirror/lang-css@6.3.1':
dependencies:
'@codemirror/autocomplete': 6.20.3
'@codemirror/language': 6.12.4
'@codemirror/state': 6.7.1
'@lezer/common': 1.5.2
'@lezer/css': 1.3.4
'@codemirror/lang-go@6.0.1':
dependencies:
'@codemirror/autocomplete': 6.20.3
'@codemirror/language': 6.12.4
'@codemirror/state': 6.7.1
'@lezer/common': 1.5.2
'@lezer/go': 1.0.1
'@codemirror/lang-html@6.4.11':
dependencies:
'@codemirror/autocomplete': 6.20.3
'@codemirror/lang-css': 6.3.1
'@codemirror/lang-javascript': 6.2.5
'@codemirror/language': 6.12.4
'@codemirror/state': 6.7.1
'@codemirror/view': 6.43.7
'@lezer/common': 1.5.2
'@lezer/css': 1.3.4
'@lezer/html': 1.3.13
'@codemirror/lang-java@6.0.2':
dependencies:
'@codemirror/language': 6.12.4
'@lezer/java': 1.1.3
'@codemirror/lang-javascript@6.2.5':
dependencies:
'@codemirror/autocomplete': 6.20.3
'@codemirror/language': 6.12.4
'@codemirror/lint': 6.9.7
'@codemirror/state': 6.7.1
'@codemirror/view': 6.43.7
'@lezer/common': 1.5.2
'@lezer/javascript': 1.5.4
'@codemirror/lang-jinja@6.0.1':
dependencies:
'@codemirror/autocomplete': 6.20.3
'@codemirror/lang-html': 6.4.11
'@codemirror/language': 6.12.4
'@codemirror/state': 6.7.1
'@codemirror/view': 6.43.7
'@lezer/common': 1.5.2
'@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.10
'@codemirror/lang-json@6.0.2':
dependencies:
'@codemirror/language': 6.12.4
'@lezer/json': 1.0.3
'@codemirror/lang-less@6.0.2':
dependencies:
'@codemirror/lang-css': 6.3.1
'@codemirror/language': 6.12.4
'@lezer/common': 1.5.2
'@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.10
'@codemirror/lang-liquid@6.3.2':
dependencies:
'@codemirror/autocomplete': 6.20.3
'@codemirror/lang-html': 6.4.11
'@codemirror/language': 6.12.4
'@codemirror/state': 6.7.1
'@codemirror/view': 6.43.7
'@lezer/common': 1.5.2
'@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.10
'@codemirror/lang-markdown@6.5.1':
dependencies:
'@codemirror/autocomplete': 6.20.3
'@codemirror/lang-html': 6.4.11
'@codemirror/language': 6.12.4
'@codemirror/state': 6.7.1
'@codemirror/view': 6.43.7
'@lezer/common': 1.5.2
'@lezer/markdown': 1.7.2
'@codemirror/lang-php@6.0.2':
dependencies:
'@codemirror/lang-html': 6.4.11
'@codemirror/language': 6.12.4
'@codemirror/state': 6.7.1
'@lezer/common': 1.5.2
'@lezer/php': 1.0.5
'@codemirror/lang-python@6.2.1':
dependencies:
'@codemirror/autocomplete': 6.20.3
'@codemirror/language': 6.12.4
'@codemirror/state': 6.7.1
'@lezer/common': 1.5.2
'@lezer/python': 1.1.19
'@codemirror/lang-rust@6.0.2':
dependencies:
'@codemirror/language': 6.12.4
'@lezer/rust': 1.0.2
'@codemirror/lang-sass@6.0.2':
dependencies:
'@codemirror/lang-css': 6.3.1
'@codemirror/language': 6.12.4
'@codemirror/state': 6.7.1
'@lezer/common': 1.5.2
'@lezer/sass': 1.1.0
'@codemirror/lang-sql@6.10.0':
dependencies:
'@codemirror/autocomplete': 6.20.3
'@codemirror/language': 6.12.4
'@codemirror/state': 6.7.1
'@lezer/common': 1.5.2
'@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.10
'@codemirror/lang-vue@0.1.3':
dependencies:
'@codemirror/lang-html': 6.4.11
'@codemirror/lang-javascript': 6.2.5
'@codemirror/language': 6.12.4
'@lezer/common': 1.5.2
'@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.10
'@codemirror/lang-wast@6.0.2':
dependencies:
'@codemirror/language': 6.12.4
'@lezer/common': 1.5.2
'@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.10
'@codemirror/lang-xml@6.1.0':
dependencies:
'@codemirror/autocomplete': 6.20.3
'@codemirror/language': 6.12.4
'@codemirror/state': 6.7.1
'@codemirror/view': 6.43.7
'@lezer/common': 1.5.2
'@lezer/xml': 1.0.6
'@codemirror/lang-yaml@6.1.3':
dependencies:
'@codemirror/autocomplete': 6.20.3
'@codemirror/language': 6.12.4
'@codemirror/state': 6.7.1
'@lezer/common': 1.5.2
'@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.10
'@lezer/yaml': 1.0.4
'@codemirror/language-data@6.5.2':
dependencies:
'@codemirror/lang-angular': 0.1.4
'@codemirror/lang-cpp': 6.0.3
'@codemirror/lang-css': 6.3.1
'@codemirror/lang-go': 6.0.1
'@codemirror/lang-html': 6.4.11
'@codemirror/lang-java': 6.0.2
'@codemirror/lang-javascript': 6.2.5
'@codemirror/lang-jinja': 6.0.1
'@codemirror/lang-json': 6.0.2
'@codemirror/lang-less': 6.0.2
'@codemirror/lang-liquid': 6.3.2
'@codemirror/lang-markdown': 6.5.1
'@codemirror/lang-php': 6.0.2
'@codemirror/lang-python': 6.2.1
'@codemirror/lang-rust': 6.0.2
'@codemirror/lang-sass': 6.0.2
'@codemirror/lang-sql': 6.10.0
'@codemirror/lang-vue': 0.1.3
'@codemirror/lang-wast': 6.0.2
'@codemirror/lang-xml': 6.1.0
'@codemirror/lang-yaml': 6.1.3
'@codemirror/language': 6.12.4
'@codemirror/legacy-modes': 6.5.3
'@codemirror/language@6.12.4':
dependencies:
'@codemirror/state': 6.7.1
'@codemirror/view': 6.43.7
'@lezer/common': 1.5.2
'@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.10
style-mod: 4.1.3
'@codemirror/legacy-modes@6.5.3':
dependencies:
'@codemirror/language': 6.12.4
'@codemirror/lint@6.9.7':
dependencies:
'@codemirror/state': 6.7.1
'@codemirror/view': 6.43.7
crelt: 1.0.7
'@codemirror/search@6.7.1':
dependencies:
'@codemirror/state': 6.7.1
'@codemirror/view': 6.43.7
crelt: 1.0.7
'@codemirror/state@6.7.1':
dependencies:
'@marijn/find-cluster-break': 1.0.3
'@codemirror/view@6.43.7':
dependencies:
'@codemirror/state': 6.7.1
crelt: 1.0.7
style-mod: 4.1.3
w3c-keyname: 2.2.8
'@ctrl/tinycolor@4.2.0': {}
'@element-plus/icons-vue@2.3.2(vue@3.5.40(typescript@6.0.3))':
@@ -2240,6 +2728,105 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.5
'@lezer/common@1.5.2': {}
'@lezer/cpp@1.1.6':
dependencies:
'@lezer/common': 1.5.2
'@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.10
'@lezer/css@1.3.4':
dependencies:
'@lezer/common': 1.5.2
'@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.10
'@lezer/go@1.0.1':
dependencies:
'@lezer/common': 1.5.2
'@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.10
'@lezer/highlight@1.2.3':
dependencies:
'@lezer/common': 1.5.2
'@lezer/html@1.3.13':
dependencies:
'@lezer/common': 1.5.2
'@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.10
'@lezer/java@1.1.3':
dependencies:
'@lezer/common': 1.5.2
'@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.10
'@lezer/javascript@1.5.4':
dependencies:
'@lezer/common': 1.5.2
'@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.10
'@lezer/json@1.0.3':
dependencies:
'@lezer/common': 1.5.2
'@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.10
'@lezer/lr@1.4.10':
dependencies:
'@lezer/common': 1.5.2
'@lezer/markdown@1.7.2':
dependencies:
'@lezer/common': 1.5.2
'@lezer/highlight': 1.2.3
'@lezer/php@1.0.5':
dependencies:
'@lezer/common': 1.5.2
'@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.10
'@lezer/python@1.1.19':
dependencies:
'@lezer/common': 1.5.2
'@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.10
'@lezer/rust@1.0.2':
dependencies:
'@lezer/common': 1.5.2
'@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.10
'@lezer/sass@1.1.0':
dependencies:
'@lezer/common': 1.5.2
'@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.10
'@lezer/xml@1.0.6':
dependencies:
'@lezer/common': 1.5.2
'@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.10
'@lezer/yaml@1.0.4':
dependencies:
'@lezer/common': 1.5.2
'@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.10
'@lucide/vue@1.27.0(vue@3.5.40(typescript@6.0.3))':
dependencies:
vue: 3.5.40(typescript@6.0.3)
'@marijn/find-cluster-break@1.0.3': {}
'@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)':
dependencies:
'@emnapi/core': 1.11.1
@@ -2384,12 +2971,21 @@ snapshots:
'@types/json5@0.0.29': {}
'@types/linkify-it@5.0.0': {}
'@types/lodash-es@4.17.12':
dependencies:
'@types/lodash': 4.17.24
'@types/lodash@4.17.24': {}
'@types/markdown-it@14.1.2':
dependencies:
'@types/linkify-it': 5.0.0
'@types/mdurl': 2.0.0
'@types/mdurl@2.0.0': {}
'@types/node@24.13.3':
dependencies:
undici-types: 7.18.2
@@ -2482,6 +3078,12 @@ snapshots:
'@typescript-eslint/types': 5.62.0
eslint-visitor-keys: 3.4.3
'@vavt/copy2clipboard@1.0.3': {}
'@vavt/markdown-theme@5.0.2': {}
'@vavt/util@2.1.2': {}
'@vitejs/plugin-vue@6.0.8(vite@8.1.5(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.40(typescript@6.0.3))':
dependencies:
'@rolldown/pluginutils': 1.0.1
@@ -2661,6 +3263,8 @@ snapshots:
dependencies:
sprintf-js: 1.0.3
argparse@2.0.1: {}
array-buffer-byte-length@1.0.2:
dependencies:
call-bound: 1.0.4
@@ -2795,6 +3399,16 @@ snapshots:
dependencies:
readdirp: 5.0.0
codemirror@6.0.2:
dependencies:
'@codemirror/autocomplete': 6.20.3
'@codemirror/commands': 6.10.4
'@codemirror/language': 6.12.4
'@codemirror/lint': 6.9.7
'@codemirror/search': 6.7.1
'@codemirror/state': 6.7.1
'@codemirror/view': 6.43.7
color-convert@1.9.3:
dependencies:
color-name: 1.1.3
@@ -2811,12 +3425,16 @@ snapshots:
dependencies:
delayed-stream: 1.0.0
commander@2.20.3: {}
concat-map@0.0.1: {}
confbox@0.1.8: {}
confbox@0.2.4: {}
crelt@1.0.7: {}
cross-spawn@7.0.6:
dependencies:
path-key: 3.1.1
@@ -2827,6 +3445,8 @@ snapshots:
cssesc@3.0.0: {}
cssfilter@0.0.10: {}
csstype@3.2.3: {}
data-view-buffer@1.0.2:
@@ -2919,6 +3539,8 @@ snapshots:
ansi-colors: 4.1.3
strip-ansi: 6.0.1
entities@4.5.0: {}
entities@7.0.1: {}
es-abstract-get@1.0.0:
@@ -3607,6 +4229,10 @@ snapshots:
lightningcss-win32-arm64-msvc: 1.33.0
lightningcss-win32-x64-msvc: 1.33.0
linkify-it@5.0.2:
dependencies:
uc.micro: 2.1.0
local-pkg@1.2.1:
dependencies:
mlly: 1.8.2
@@ -3639,8 +4265,54 @@ snapshots:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
markdown-it-image-figures@2.1.1(markdown-it@14.3.0):
dependencies:
markdown-it: 14.3.0
markdown-it-sub@2.0.0: {}
markdown-it-sup@2.0.0: {}
markdown-it@14.3.0:
dependencies:
argparse: 2.0.1
entities: 4.5.0
linkify-it: 5.0.2
mdurl: 2.1.0
punycode.js: 2.3.1
uc.micro: 2.1.0
math-intrinsics@1.1.0: {}
md-editor-v3@6.5.5(vue@3.5.40(typescript@6.0.3)):
dependencies:
'@codemirror/autocomplete': 6.20.3
'@codemirror/commands': 6.10.4
'@codemirror/lang-markdown': 6.5.1
'@codemirror/language': 6.12.4
'@codemirror/language-data': 6.5.2
'@codemirror/search': 6.7.1
'@codemirror/state': 6.7.1
'@codemirror/view': 6.43.7
'@lezer/highlight': 1.2.3
'@lucide/vue': 1.27.0(vue@3.5.40(typescript@6.0.3))
'@types/markdown-it': 14.1.2
'@vavt/copy2clipboard': 1.0.3
'@vavt/markdown-theme': 5.0.2
'@vavt/util': 2.1.2
codemirror: 6.0.2
markdown-it: 14.3.0
markdown-it-image-figures: 2.1.1(markdown-it@14.3.0)
markdown-it-sub: 2.0.0
markdown-it-sup: 2.0.0
medium-zoom: 1.1.0
vue: 3.5.40(typescript@6.0.3)
xss: 1.0.15
mdurl@2.1.0: {}
medium-zoom@1.1.0: {}
memoize-one@6.0.0: {}
merge2@1.4.1: {}
@@ -3822,6 +4494,8 @@ snapshots:
proxy-from-env@2.1.0: {}
punycode.js@2.3.1: {}
punycode@2.3.1: {}
quansync@0.2.11: {}
@@ -4060,6 +4734,8 @@ snapshots:
strip-json-comments@3.1.1: {}
style-mod@4.1.3: {}
supports-color@5.5.0:
dependencies:
has-flag: 3.0.0
@@ -4147,6 +4823,8 @@ snapshots:
typescript@6.0.3: {}
uc.micro@2.1.0: {}
ufo@1.6.4: {}
unbox-primitive@1.1.0:
@@ -4272,6 +4950,8 @@ snapshots:
optionalDependencies:
typescript: 6.0.3
w3c-keyname@2.2.8: {}
webpack-virtual-modules@0.6.2: {}
which-boxed-primitive@1.1.1:
@@ -4323,4 +5003,9 @@ snapshots:
wrappy@1.0.2: {}
xss@1.0.15:
dependencies:
commander: 2.20.3
cssfilter: 0.0.10
yaml@2.9.0: {}

View File

@@ -6,3 +6,16 @@ export const queryMistakeListApi = (): Promise<IMistake[]> =>
url: '/study-api/mistake',
method: 'get'
})
export const addMistakeListApi = (data: IMistake[]): Promise<boolean> =>
cloudService({
url: '/study-api/mistake',
method: 'post',
data
})
export const deleteMistakeApi = (id: number): Promise<boolean> =>
cloudService({
url: `/study-api/mistake/${id}`,
method: 'delete'
})

View File

@@ -1,14 +1,5 @@
import { cloudService } from './index'
import type { ILibraryFileQuestion } from '@/types/library.ts'
import type { IPracticeCheck, IPracticeRecord } from '@/types/practice.ts'
export const queryPracticeQuestionByIdApi = (id: number): Promise<ILibraryFileQuestion[]> =>
cloudService({
url: `/study-api/practice/files/${id}`,
method: 'get'
})
import type { IPracticeRecord } from '@/types/practice.ts'
export const queryPracticeRecordApi = (id: number): Promise<IPracticeRecord[]> =>
cloudService({
@@ -16,11 +7,9 @@ export const queryPracticeRecordApi = (id: number): Promise<IPracticeRecord[]> =
method: 'get'
})
export const checkPracticeApi = (id: number,
data: ILibraryFileQuestion[]): Promise<IPracticeCheck[]> =>
export const addPracticeRecordApi = (data: IPracticeRecord): Promise<boolean> =>
cloudService({
url: `/study-api/practice/check/${id}`,
url: '/study-api/practice/record',
method: 'post',
data
})

View File

@@ -0,0 +1,17 @@
<template>
<el-dialog v-model="libraryStore.fileContentDialogVisible"
title="查看资料" width="80%"
center destroy-on-close
class="common-dialog">
<MdPreview :modelValue="libraryStore.currentFile.content"/>
</el-dialog>
</template>
<script setup lang="ts">
import { useLibraryStore } from '@/stores/library.ts'
import { MdPreview } from 'md-editor-v3'
import 'md-editor-v3/lib/preview.css'
const libraryStore = useLibraryStore()
</script>

View File

@@ -6,7 +6,6 @@
<el-steps :active="libraryStore.activeStep" align-center>
<el-step title="上传资料" :icon="Upload" />
<el-step title="确认资料" :icon="Document " />
<el-step title="生成题库" :icon="MagicStick" />
</el-steps>
<el-form ref="libraryFileFormRef" v-if="libraryStore.activeStep === 1"
@@ -58,56 +57,14 @@
:content="libraryStore.currentFile.content"
contentType="html" theme="snow"/>
<div v-if="libraryStore.activeStep === 3" class="generate-question">
<div class="generate-action">
<el-button type="primary" @click="generateQuestion">
{{ libraryStore.hasGenerateQuestion ? '重新生成' : '生成题库' }}
</el-button>
<span v-if="libraryStore.hasGenerateQuestion">
{{ libraryStore.currentFile.questions.length }} 道题目
</span>
</div>
<div v-if="libraryStore.hasGenerateQuestion" class="question-list">
<el-card v-for="(q, index) in libraryStore.currentFile.questions"
:key="q.id" class="question-card">
<div class="question-title">
{{ index + 1 }}.
{{ q.type === 'single' ? '单选' : '多选' }}
{{ q.question }}
</div>
<div class="question-options">
<div v-for="(opt, i) in q.options" :key="i" style="line-height: 1.8">
{{ String.fromCharCode(65 + i) }}. {{ opt }}
</div>
</div>
<div class="question-answer">
正确答案{{ q.answer.join('、') }}
</div>
<div class="question-action">
<el-button type="danger" size="small"
@click="libraryStore.currentFile.questions.splice(index, 1)">
删除
</el-button>
</div>
</el-card>
</div>
<div v-else v-html="libraryStore.questionContent" />
</div>
<template #footer>
<el-button @click="libraryStore.fileDialogVisible = false">取消</el-button>
<el-button type="primary" @click="previousClick"
:disabled="libraryStore.activeStep === 1">上一步</el-button>
<el-button type="primary" @click="nextClick"
:disabled="libraryStore.activeStep === 3">下一步</el-button>
:disabled="libraryStore.activeStep === 2">下一步</el-button>
<el-button type="primary" @click="submitForm()"
:disabled="libraryStore.activeStep !== 3">确认</el-button>
:disabled="libraryStore.activeStep !== 2">确认</el-button>
</template>
</el-dialog>
</template>
@@ -116,12 +73,12 @@
import { ref } from 'vue'
import { useLibraryStore } from '@/stores/library.ts'
import { ElLoading, ElMessage, type FormInstance, type UploadRequestOptions } from 'element-plus'
import { Document, MagicStick, Upload, UploadFilled } from '@element-plus/icons-vue'
import { Document, Upload, UploadFilled } from '@element-plus/icons-vue'
import { QuillEditor } from '@vueup/vue-quill'
import '@vueup/vue-quill/dist/vue-quill.snow.css'
import { uploadLibraryFileApi } from '@/apis/library.ts'
import { getModuleOptions } from '@/utils/libraryUtil.ts'
import { getFileExtension, getFileHashName } from '@/utils/file.ts'
import { getFileExtension, getFileHashName } from '@/utils/fileUtil.ts'
const libraryStore = useLibraryStore()
const libraryFileFormRef = ref<FormInstance>()
@@ -154,7 +111,7 @@ const nextClick = async () => {
}
}
if (libraryStore.activeStep < 3) {
if (libraryStore.activeStep < 2) {
libraryStore.activeStep++
}
}
@@ -190,62 +147,12 @@ const upload = async (options: UploadRequestOptions) => {
}
}
const generateQuestion = async () => {
if (!libraryStore.currentFile.content) {
ElMessage.error('请先上传资料')
return
}
libraryStore.questionContent = ''
libraryStore.hasGenerateQuestion = false
const loading = ElLoading.service({
lock: true,
text: '题库生成中 请等待',
background: 'rgba(0, 0, 0, 0.7)'
})
try {
const response = await fetch('/study-api/library/question', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
message: libraryStore.currentFile.content
})
})
if (!response.body) {
throw new Error('未获取到响应流')
}
const reader = response.body.getReader()
const decoder = new TextDecoder('utf-8')
while (true) {
const { value, done } = await reader.read()
if (done) break
libraryStore.questionContent += decoder.decode(value, { stream: true })
}
ElMessage.success('生成完成')
libraryStore.hasGenerateQuestion = true
libraryStore.currentFile.questions = JSON.parse(libraryStore.questionContent)
} catch (error) {
console.log(error)
ElMessage.error('生成失败 请联系管理员')
} finally {
loading.close()
}
}
const submitForm = async () => {
if (libraryStore.currentFile.questions.length > 0) {
if (libraryStore.currentFile.content) {
await libraryStore.handleFileApi(libraryStore.currentFile)
} else {
ElMessage.error('请先生成题库')
ElMessage.error('请先上传文件')
}
}
</script>

View File

@@ -3,8 +3,7 @@
<library-filter v-if="filterLibraryFileList.length"/>
<div v-for="file in filterLibraryFileList" :key="file.id" class="file-card card-item">
<div class="file-info">
<div class="file-info" @click="viewContentClick(file)">
<div class="file-icon" :class="file.type === 'image' ? 'icon-image' : 'icon-pdf'">
<el-icon v-if="file.type === 'image'" ><Picture /></el-icon>
<el-icon v-else><Document /></el-icon>
@@ -42,11 +41,15 @@ const filterLibraryFileList = computed(() => {
return libraryStore.fileList.filter((item) => item.subject === subject && item.module === module)
})
const viewContentClick = async (file: ILibraryFile) => {
await libraryStore.queryFileById(file.id)
libraryStore.fileContentDialogVisible = true
}
const editClick = async (file: ILibraryFile) => {
await libraryStore.queryFileById(file.id)
libraryStore.fileApiType = 'UPDATE'
libraryStore.activeStep = 1
libraryStore.hasGenerateQuestion = true
libraryStore.fileDialogVisible = true
}
</script>

View File

@@ -35,50 +35,77 @@
</div>
</div>
<div v-if="practiceStore.hasStart" class="question-action">
<el-button type="success" @click="submitAnswerClick">
{{ practiceStore.hasSubmit ? '重新练习' : '提交答案' }}
</el-button>
<div v-if="!practiceStore.hasSubmit" class="question-action">
<el-button type="success" @click="submitAnswerClick">提交答案</el-button>
</div>
</div>
</template>
<script setup lang="ts">
import { usePracticeStore } from '@/stores/practice.ts'
import { ElLoading, ElMessage } from 'element-plus'
import { useLibraryStore } from '@/stores/library.ts'
import { useMistakeStore } from '@/stores/mistake.ts'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getMistakeList, isAnswerCorrect, optLetter } from '@/utils/practiceUtil.ts'
import type { IMistake } from '@/types/mistake.ts'
const practiceStore = usePracticeStore()
const optLetter = (index: number): string => {
return String.fromCharCode(65 + index)
}
const libraryStore = useLibraryStore()
const mistakeStore = useMistakeStore()
const submitAnswerClick = async () => {
if (practiceStore.hasSubmit) {
practiceStore.hasSubmit = false
practiceStore.checkList = []
await practiceStore.queryQuestionById()
if (practiceStore.questionList.find((item) => item.select.length === 0)) {
ElMessage.error('还有未完成的题目')
} else {
practiceStore.hasSubmit = true
if (practiceStore.questionList.find((item) => item.select.length === 0)) {
ElMessage.error('还有未完成的题目')
return
}
practiceStore.checkList = practiceStore.questionList.map((q) => ({
id: q.id,
answer: q.answer,
select: q.select,
isCorrect: isAnswerCorrect(q.answer, q.select)
}))
await addPracticeRecord()
await addMistakeList()
const loading = ElLoading.service({
lock: true,
text: '答案提交中 请等待',
background: 'rgba(0, 0, 0, 0.7)'
})
try {
await practiceStore.checkQuestion()
ElMessage.success('提交成功')
} catch (error) {
console.log(error)
ElMessage.error('提交失败 请联系管理员')
} finally {
loading.close()
}
const { totalCount, correctCount, wrongCount } = practiceStore.currentRecord
await ElMessageBox.alert(
`${totalCount} 题 · 正确 ${correctCount} · 错误 ${wrongCount}`,
'训练结果',
{
confirmButtonText: '确认'
}
)
}
}
const addPracticeRecord = async () => {
const totalCount = practiceStore.checkList.length
const correctCount = practiceStore.checkList.filter((c) => c.isCorrect).length
practiceStore.currentRecord = {
libraryFileId: libraryStore.currentFile.id,
totalCount,
correctCount,
wrongCount: totalCount - correctCount
}
await practiceStore.addRecord()
}
const addMistakeList = async () => {
const mistakeList = getMistakeList(practiceStore.questionList, practiceStore.checkList)
mistakeStore.currentMistakes = []
mistakeList.forEach((item) => {
const mistake:IMistake = {
answer: item.answer,
module: libraryStore.currentFile.module,
name: libraryStore.currentFile.name,
options: item.options,
question: item.question,
subject: libraryStore.currentFile.subject,
type: item.type
}
mistakeStore.currentMistakes.push(mistake)
})
await mistakeStore.addMistakeList()
}
</script>

View File

@@ -3,7 +3,7 @@
<!-- 侧边栏 -->
<el-aside :width="isCollapse ? '64px' : '150px'" class="aside">
<!-- Logo -->
<div class="logo">
<div class="logo" @click="refreshClick">
<span v-if="!isCollapse">🧠 智能学习助手</span>
<span v-else>🧠</span>
</div>
@@ -63,7 +63,7 @@
<!-- 用户信息 -->
<el-dropdown>
<el-avatar :size="32" class="avatar"></el-avatar>
<el-avatar :size="32" class="avatar"></el-avatar>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>个人中心</el-dropdown-item>
@@ -89,23 +89,24 @@
<script setup lang="ts">
import { ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useRoute } from 'vue-router'
import { ElMessageBox } from 'element-plus'
import { Reading, Aim, EditPen, Notebook, DataLine, Fold, Expand, Bell } from '@element-plus/icons-vue'
const route = useRoute()
const router = useRouter()
const isCollapse = ref(false)
const refreshClick = () => {
location.reload()
}
// 退出登录
const handleLogout = () => {
ElMessageBox.confirm('确定要退出登录吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
router.push('/login')
}).catch(() => {})
})
}
</script>
@@ -129,6 +130,7 @@ const handleLogout = () => {
font-weight: 600;
color: #14b8a6;
border-bottom: 1px solid #e2e8f0;
cursor: pointer;
}
.side-menu {

View File

@@ -29,12 +29,11 @@ export const useLibraryStore = defineStore('library', {
} as ILibraryFile,
fileDetailDialogVisible: false,
fileDialogVisible: false,
hasGenerateQuestion: false,
fileContentDialogVisible: false,
fileApiType: 'ADD' as IHandleApi,
subjectOptions: [] as IOptions[],
moduleOptions: [] as IOptions[],
activeStep: 1,
questionContent: ''
activeStep: 1
}),
actions: {
async queryFileList() {
@@ -80,8 +79,7 @@ export const useLibraryStore = defineStore('library', {
subject: '',
uploadTime: '',
type: '',
content: '',
questions: []
content: ''
}
}
}

View File

@@ -1,14 +1,21 @@
import { defineStore } from 'pinia'
import type { IMistake } from '@/types/mistake.ts'
import { queryMistakeListApi } from '@/apis/mistake.ts'
import { addMistakeListApi, deleteMistakeApi, queryMistakeListApi } from '@/apis/mistake.ts'
export const useMistakeStore = defineStore('mistake', {
state: () => ({
mistakeList: [] as IMistake[]
mistakeList: [] as IMistake[],
currentMistakes: [] as IMistake[]
}),
actions: {
async queryMistakeList() {
this.mistakeList = await queryMistakeListApi()
},
async addMistakeList() {
await addMistakeListApi(this.currentMistakes)
},
async deleteMistakeById(id: number) {
await deleteMistakeApi(id)
}
}
})

View File

@@ -1,26 +1,26 @@
import { defineStore } from 'pinia'
import type { ILibraryFileQuestion } from '@/types/library.ts'
import { checkPracticeApi, queryPracticeQuestionByIdApi, queryPracticeRecordApi } from '@/apis/practice.ts'
import { addPracticeRecordApi, queryPracticeRecordApi } from '@/apis/practice.ts'
import type { IPracticeCheck, IPracticeRecord } from '@/types/practice.ts'
import type { IQuestion } from '@/types/question.ts'
export const usePracticeStore = defineStore('practice', {
state: () => ({
hasStart: false,
hasSubmit: false,
libraryFileId: 0,
questionList: [] as ILibraryFileQuestion[],
hasGenerateQuestion: false,
questionContent: '',
questionList: [] as IQuestion[],
recordList: [] as IPracticeRecord[],
checkList: [] as IPracticeCheck[]
checkList: [] as IPracticeCheck[],
currentRecord: {} as IPracticeRecord
}),
actions: {
async queryQuestionById() {
this.questionList = await queryPracticeQuestionByIdApi(this.libraryFileId)
},
async queryRecord() {
this.recordList = await queryPracticeRecordApi(this.libraryFileId)
},
async checkQuestion() {
this.checkList = await checkPracticeApi(this.libraryFileId, this.questionList)
async addRecord() {
await addPracticeRecordApi(this.currentRecord)
}
}
})

View File

@@ -1,12 +1,3 @@
export interface ILibraryFileQuestion {
id: number;
type: string;
question: string;
options: string[];
answer: string[];
select: string[];
}
export interface ILibraryFile {
id: number;
subject: string;
@@ -16,5 +7,4 @@ export interface ILibraryFile {
uploadTime: string;
type: string;
content: string;
questions: ILibraryFileQuestion[];
}

View File

@@ -1,5 +1,5 @@
export interface IMistake {
id: number;
id?: number;
subject: string;
module: string;
name: string;
@@ -7,5 +7,4 @@ export interface IMistake {
question: string;
options: string[];
answer: string[];
wrongCount: number;
}

View File

@@ -6,10 +6,10 @@ export interface IPracticeCheck {
}
export interface IPracticeRecord {
id: number;
id?: number;
libraryFileId:number;
totalCount: number;
correctCount: number;
wrongCount: number;
createTime: string;
createTime?: string;
}

8
src/types/question.ts Normal file
View File

@@ -0,0 +1,8 @@
export interface IQuestion {
id: number;
type: string;
question: string;
options: string[];
answer: string[];
select: string[];
}

28
src/utils/practiceUtil.ts Normal file
View File

@@ -0,0 +1,28 @@
import type { IPracticeCheck } from '@/types/practice.ts'
import type { IQuestion } from '@/types/question.ts'
export const isAnswerCorrect = (answer: string[], select: string[]): boolean => {
const normAnswer = Array.from(new Set(answer)).sort()
const normSelect = Array.from(new Set(select)).sort()
if (normAnswer.length !== normSelect.length) {
return false
}
return normAnswer.every((v, i) => v === normSelect[i])
}
export const optLetter = (index: number): string => {
return String.fromCharCode(65 + index)
}
export const getMistakeList = (questions: IQuestion[],
checks: IPracticeCheck[]): IQuestion[] => {
const checkMap = new Map<number, IPracticeCheck>()
checks.forEach((c) => checkMap.set(c.id, c))
return questions.filter((q) => {
const check = checkMap.get(q.id)
return !check || !check.isCorrect
})
}

View File

@@ -11,12 +11,15 @@
<library-file-list />
<library-file-dialog />
<library-file-content-dialog />
</div>
</template>
<script setup lang="ts">
import LibraryFileList from '@/components/Library/LibraryFileList.vue'
import LibraryFileDialog from '@/components/Library/LibraryFileDialog.vue'
import LibraryFileContentDialog from '@/components/Library/LibraryFileContentDialog.vue'
import { useLibraryStore } from '@/stores/library.ts'
import { Plus } from '@element-plus/icons-vue'
import { onMounted } from 'vue'

View File

@@ -9,15 +9,11 @@
<div class="mistake-record">
<div v-if="mistakeStore.mistakeList.length" class="mistake-list">
<el-card
v-for="item in mistakeStore.mistakeList"
:key="item.id"
class="mistake-card"
shadow="never"
>
<el-card v-for="item in mistakeStore.mistakeList"
:key="item.id" class="mistake-card" shadow="never">
<div class="library">
<el-tag type="primary" effect="dark">{{ item.subject }} · {{ item.module }}</el-tag>
<el-tag type="danger" effect="dark"> {{ item.wrongCount }} </el-tag>
<el-button type="success" size="small" @click="deleteClick(item.id)">已掌握</el-button>
</div>
<div class="question">{{ item.question }}</div>
@@ -25,7 +21,7 @@
<div class="option-list">
<div v-for="(opt, index) in item.options" :key="index" class="option"
:class="optionClass(item, index)">
{{ letter(index) }}{{ opt }}
{{ optLetter(index) }}{{ opt }}
</div>
</div>
</el-card>
@@ -39,6 +35,9 @@
<script setup lang="ts">
import { onMounted } from 'vue'
import { useMistakeStore } from '@/stores/mistake.ts'
import { optLetter } from '@/utils/practiceUtil.ts'
import type { IMistake } from '@/types/mistake.ts'
import { ElMessageBox } from 'element-plus'
const mistakeStore = useMistakeStore()
@@ -46,15 +45,24 @@ onMounted(async () => {
await mistakeStore.queryMistakeList()
})
const letter = (i: number) => String.fromCharCode(65 + i)
const optionClass = (item: any, index: number) => {
const optionClass = (item: IMistake, index: number) => {
const letters = ['A', 'B', 'C', 'D']
const isCorrect = item.answer.includes(letters[index])
return {
correct: isCorrect
}
}
const deleteClick = (id: number) => {
ElMessageBox.confirm('确定已掌握该错题?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
await mistakeStore.deleteMistakeById(id)
await mistakeStore.queryMistakeList()
})
}
</script>
<style lang="scss">
@@ -62,7 +70,6 @@ const optionClass = (item: any, index: number) => {
display: flex;
flex-direction: column;
gap: 16px;
padding: 16px;
background: #f7f8fa;
}

View File

@@ -7,8 +7,9 @@
</div>
<div class="view-action">
<el-button v-if="!practiceStore.hasStart" type="primary" :icon="Aim"
@click="startPracticeClick">开始练习</el-button>
<el-button type="primary" :icon="Aim" @click="startPracticeClick">
{{ practiceStore.hasStart ? '重新练习' : '开始练习' }}
</el-button>
</div>
</div>
@@ -28,6 +29,7 @@ import { onMounted, watch } from 'vue'
import { useLibraryStore } from '@/stores/library'
import { usePracticeStore } from '@/stores/practice.ts'
import { Aim } from '@element-plus/icons-vue'
import { ElLoading, ElMessage } from 'element-plus'
const libraryStore = useLibraryStore()
const practiceStore = usePracticeStore()
@@ -49,16 +51,64 @@ watch(() => libraryStore.selectedModule, async () => {
const { id } = fileList[0]
practiceStore.libraryFileId = id
await practiceStore.queryRecord()
await practiceStore.queryQuestionById()
}
}, {
immediate: true
})
const startPracticeClick = () => {
const startPracticeClick = async () => {
await libraryStore.queryFileById(practiceStore.libraryFileId)
await generateQuestion()
practiceStore.hasStart = true
practiceStore.hasSubmit = false
practiceStore.checkList = []
}
const generateQuestion = async () => {
practiceStore.questionContent = ''
practiceStore.hasGenerateQuestion = false
const loading = ElLoading.service({
lock: true,
text: '题库生成中 请等待',
background: 'rgba(0, 0, 0, 0.7)'
})
try {
const response = await fetch('/study-api/library/question', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
message: libraryStore.currentFile.content
})
})
if (!response.body) {
throw new Error('未获取到响应流')
}
const reader = response.body.getReader()
const decoder = new TextDecoder('utf-8')
while (true) {
const { value, done } = await reader.read()
if (done) break
practiceStore.questionContent += decoder.decode(value, { stream: true })
}
ElMessage.success('生成完成')
practiceStore.hasGenerateQuestion = true
practiceStore.questionList = JSON.parse(practiceStore.questionContent)
} catch (error) {
console.log(error)
ElMessage.error('生成失败 请联系管理员')
} finally {
loading.close()
}
}
</script>
<style lang="scss">