add create a problem.

This commit is contained in:
2023-03-27 18:21:29 +08:00
parent 7f8260d34d
commit 9bc1a1b5b5
12 changed files with 831 additions and 11 deletions

464
package-lock.json generated
View File

@@ -11,6 +11,8 @@
"@element-plus/icons-vue": "^2.1.0", "@element-plus/icons-vue": "^2.1.0",
"@monaco-editor/loader": "^1.3.2", "@monaco-editor/loader": "^1.3.2",
"@vueuse/core": "^9.13.0", "@vueuse/core": "^9.13.0",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^5.1.12",
"axios": "1.3.4", "axios": "1.3.4",
"chart.js": "^4.2.1", "chart.js": "^4.2.1",
"copy-text-to-clipboard": "^3.0.1", "copy-text-to-clipboard": "^3.0.1",
@@ -398,6 +400,17 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/@babel/runtime": {
"version": "7.21.0",
"resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.21.0.tgz",
"integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==",
"dependencies": {
"regenerator-runtime": "^0.13.11"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/standalone": { "node_modules/@babel/standalone": {
"version": "7.21.1", "version": "7.21.1",
"resolved": "https://registry.npmmirror.com/@babel/standalone/-/standalone-7.21.1.tgz", "resolved": "https://registry.npmmirror.com/@babel/standalone/-/standalone-7.21.1.tgz",
@@ -1109,12 +1122,22 @@
} }
} }
}, },
"node_modules/@transloadit/prettier-bytes": {
"version": "0.0.7",
"resolved": "https://registry.npmmirror.com/@transloadit/prettier-bytes/-/prettier-bytes-0.0.7.tgz",
"integrity": "sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA=="
},
"node_modules/@types/estree": { "node_modules/@types/estree": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.0.tgz", "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.0.tgz",
"integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==",
"dev": true "dev": true
}, },
"node_modules/@types/event-emitter": {
"version": "0.3.3",
"resolved": "https://registry.npmmirror.com/@types/event-emitter/-/event-emitter-0.3.3.tgz",
"integrity": "sha512-UfnOK1pIxO7P+EgPRZXD9jMpimd8QEFcEZ5R67R1UhGbv4zghU5+NE7U8M8G9H5Jc8FI51rqDWQs6FtUfq2e/Q=="
},
"node_modules/@types/katex": { "node_modules/@types/katex": {
"version": "0.14.0", "version": "0.14.0",
"resolved": "https://registry.npmmirror.com/@types/katex/-/katex-0.14.0.tgz", "resolved": "https://registry.npmmirror.com/@types/katex/-/katex-0.14.0.tgz",
@@ -1166,6 +1189,56 @@
"resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz", "resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
"integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==" "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ=="
}, },
"node_modules/@uppy/companion-client": {
"version": "2.2.2",
"resolved": "https://registry.npmmirror.com/@uppy/companion-client/-/companion-client-2.2.2.tgz",
"integrity": "sha512-5mTp2iq97/mYSisMaBtFRry6PTgZA6SIL7LePteOV5x0/DxKfrZW3DEiQERJmYpHzy7k8johpm2gHnEKto56Og==",
"dependencies": {
"@uppy/utils": "^4.1.2",
"namespace-emitter": "^2.0.1"
}
},
"node_modules/@uppy/core": {
"version": "2.3.4",
"resolved": "https://registry.npmmirror.com/@uppy/core/-/core-2.3.4.tgz",
"integrity": "sha512-iWAqppC8FD8mMVqewavCz+TNaet6HPXitmGXpGGREGrakZ4FeuWytVdrelydzTdXx6vVKkOmI2FLztGg73sENQ==",
"dependencies": {
"@transloadit/prettier-bytes": "0.0.7",
"@uppy/store-default": "^2.1.1",
"@uppy/utils": "^4.1.3",
"lodash.throttle": "^4.1.1",
"mime-match": "^1.0.2",
"namespace-emitter": "^2.0.1",
"nanoid": "^3.1.25",
"preact": "^10.5.13"
}
},
"node_modules/@uppy/store-default": {
"version": "2.1.1",
"resolved": "https://registry.npmmirror.com/@uppy/store-default/-/store-default-2.1.1.tgz",
"integrity": "sha512-xnpTxvot2SeAwGwbvmJ899ASk5tYXhmZzD/aCFsXePh/v8rNvR2pKlcQUH7cF/y4baUGq3FHO/daKCok/mpKqQ=="
},
"node_modules/@uppy/utils": {
"version": "4.1.3",
"resolved": "https://registry.npmmirror.com/@uppy/utils/-/utils-4.1.3.tgz",
"integrity": "sha512-nTuMvwWYobnJcytDO3t+D6IkVq/Qs4Xv3vyoEZ+Iaf8gegZP+rEyoaFT2CK5XLRMienPyqRqNbIfRuFaOWSIFw==",
"dependencies": {
"lodash.throttle": "^4.1.1"
}
},
"node_modules/@uppy/xhr-upload": {
"version": "2.1.3",
"resolved": "https://registry.npmmirror.com/@uppy/xhr-upload/-/xhr-upload-2.1.3.tgz",
"integrity": "sha512-YWOQ6myBVPs+mhNjfdWsQyMRWUlrDLMoaG7nvf/G6Y3GKZf8AyjFDjvvJ49XWQ+DaZOftGkHmF1uh/DBeGivJQ==",
"dependencies": {
"@uppy/companion-client": "^2.2.2",
"@uppy/utils": "^4.1.2",
"nanoid": "^3.1.25"
},
"peerDependencies": {
"@uppy/core": "^2.3.3"
}
},
"node_modules/@vitejs/plugin-vue": { "node_modules/@vitejs/plugin-vue": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-4.0.0.tgz", "resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-4.0.0.tgz",
@@ -1441,6 +1514,156 @@
} }
} }
}, },
"node_modules/@wangeditor/basic-modules": {
"version": "1.1.7",
"resolved": "https://registry.npmmirror.com/@wangeditor/basic-modules/-/basic-modules-1.1.7.tgz",
"integrity": "sha512-cY9CPkLJaqF05STqfpZKWG4LpxTMeGSIIF1fHvfm/mz+JXatCagjdkbxdikOuKYlxDdeqvOeBmsUBItufDLXZg==",
"dependencies": {
"is-url": "^1.2.4"
},
"peerDependencies": {
"@wangeditor/core": "1.x",
"dom7": "^3.0.0",
"lodash.throttle": "^4.1.1",
"nanoid": "^3.2.0",
"slate": "^0.72.0",
"snabbdom": "^3.1.0"
}
},
"node_modules/@wangeditor/code-highlight": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/@wangeditor/code-highlight/-/code-highlight-1.0.3.tgz",
"integrity": "sha512-iazHwO14XpCuIWJNTQTikqUhGKyqj+dUNWJ9288Oym9M2xMVHvnsOmDU2sgUDWVy+pOLojReMPgXCsvvNlOOhw==",
"dependencies": {
"prismjs": "^1.23.0"
},
"peerDependencies": {
"@wangeditor/core": "1.x",
"dom7": "^3.0.0",
"slate": "^0.72.0",
"snabbdom": "^3.1.0"
}
},
"node_modules/@wangeditor/core": {
"version": "1.1.19",
"resolved": "https://registry.npmmirror.com/@wangeditor/core/-/core-1.1.19.tgz",
"integrity": "sha512-KevkB47+7GhVszyYF2pKGKtCSj/YzmClsD03C3zTt+9SR2XWT5T0e3yQqg8baZpcMvkjs1D8Dv4fk8ok/UaS2Q==",
"dependencies": {
"@types/event-emitter": "^0.3.3",
"event-emitter": "^0.3.5",
"html-void-elements": "^2.0.0",
"i18next": "^20.4.0",
"scroll-into-view-if-needed": "^2.2.28",
"slate-history": "^0.66.0"
},
"peerDependencies": {
"@uppy/core": "^2.1.1",
"@uppy/xhr-upload": "^2.0.3",
"dom7": "^3.0.0",
"is-hotkey": "^0.2.0",
"lodash.camelcase": "^4.3.0",
"lodash.clonedeep": "^4.5.0",
"lodash.debounce": "^4.0.8",
"lodash.foreach": "^4.5.0",
"lodash.isequal": "^4.5.0",
"lodash.throttle": "^4.1.1",
"lodash.toarray": "^4.4.0",
"nanoid": "^3.2.0",
"slate": "^0.72.0",
"snabbdom": "^3.1.0"
}
},
"node_modules/@wangeditor/editor": {
"version": "5.1.23",
"resolved": "https://registry.npmmirror.com/@wangeditor/editor/-/editor-5.1.23.tgz",
"integrity": "sha512-0RxfeVTuK1tktUaPROnCoFfaHVJpRAIE2zdS0mpP+vq1axVQpLjM8+fCvKzqYIkH0Pg+C+44hJpe3VVroSkEuQ==",
"dependencies": {
"@uppy/core": "^2.1.1",
"@uppy/xhr-upload": "^2.0.3",
"@wangeditor/basic-modules": "^1.1.7",
"@wangeditor/code-highlight": "^1.0.3",
"@wangeditor/core": "^1.1.19",
"@wangeditor/list-module": "^1.0.5",
"@wangeditor/table-module": "^1.1.4",
"@wangeditor/upload-image-module": "^1.0.2",
"@wangeditor/video-module": "^1.1.4",
"dom7": "^3.0.0",
"is-hotkey": "^0.2.0",
"lodash.camelcase": "^4.3.0",
"lodash.clonedeep": "^4.5.0",
"lodash.debounce": "^4.0.8",
"lodash.foreach": "^4.5.0",
"lodash.isequal": "^4.5.0",
"lodash.throttle": "^4.1.1",
"lodash.toarray": "^4.4.0",
"nanoid": "^3.2.0",
"slate": "^0.72.0",
"snabbdom": "^3.1.0"
}
},
"node_modules/@wangeditor/editor-for-vue": {
"version": "5.1.12",
"resolved": "https://registry.npmmirror.com/@wangeditor/editor-for-vue/-/editor-for-vue-5.1.12.tgz",
"integrity": "sha512-0Ds3D8I+xnpNWezAeO7HmPRgTfUxHLMd9JKcIw+QzvSmhC5xUHbpCcLU+KLmeBKTR/zffnS5GQo6qi3GhTMJWQ==",
"peerDependencies": {
"@wangeditor/editor": ">=5.1.0",
"vue": "^3.0.5"
}
},
"node_modules/@wangeditor/list-module": {
"version": "1.0.5",
"resolved": "https://registry.npmmirror.com/@wangeditor/list-module/-/list-module-1.0.5.tgz",
"integrity": "sha512-uDuYTP6DVhcYf7mF1pTlmNn5jOb4QtcVhYwSSAkyg09zqxI1qBqsfUnveeDeDqIuptSJhkh81cyxi+MF8sEPOQ==",
"peerDependencies": {
"@wangeditor/core": "1.x",
"dom7": "^3.0.0",
"slate": "^0.72.0",
"snabbdom": "^3.1.0"
}
},
"node_modules/@wangeditor/table-module": {
"version": "1.1.4",
"resolved": "https://registry.npmmirror.com/@wangeditor/table-module/-/table-module-1.1.4.tgz",
"integrity": "sha512-5saanU9xuEocxaemGdNi9t8MCDSucnykEC6jtuiT72kt+/Hhh4nERYx1J20OPsTCCdVr7hIyQenFD1iSRkIQ6w==",
"peerDependencies": {
"@wangeditor/core": "1.x",
"dom7": "^3.0.0",
"lodash.isequal": "^4.5.0",
"lodash.throttle": "^4.1.1",
"nanoid": "^3.2.0",
"slate": "^0.72.0",
"snabbdom": "^3.1.0"
}
},
"node_modules/@wangeditor/upload-image-module": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/@wangeditor/upload-image-module/-/upload-image-module-1.0.2.tgz",
"integrity": "sha512-z81lk/v71OwPDYeQDxj6cVr81aDP90aFuywb8nPD6eQeECtOymrqRODjpO6VGvCVxVck8nUxBHtbxKtjgcwyiA==",
"peerDependencies": {
"@uppy/core": "^2.0.3",
"@uppy/xhr-upload": "^2.0.3",
"@wangeditor/basic-modules": "1.x",
"@wangeditor/core": "1.x",
"dom7": "^3.0.0",
"lodash.foreach": "^4.5.0",
"slate": "^0.72.0",
"snabbdom": "^3.1.0"
}
},
"node_modules/@wangeditor/video-module": {
"version": "1.1.4",
"resolved": "https://registry.npmmirror.com/@wangeditor/video-module/-/video-module-1.1.4.tgz",
"integrity": "sha512-ZdodDPqKQrgx3IwWu4ZiQmXI8EXZ3hm2/fM6E3t5dB8tCaIGWQZhmqd6P5knfkRAd3z2+YRSRbxOGfoRSp/rLg==",
"peerDependencies": {
"@uppy/core": "^2.1.4",
"@uppy/xhr-upload": "^2.0.7",
"@wangeditor/core": "1.x",
"dom7": "^3.0.0",
"nanoid": "^3.2.0",
"slate": "^0.72.0",
"snabbdom": "^3.1.0"
}
},
"node_modules/acorn": { "node_modules/acorn": {
"version": "8.8.2", "version": "8.8.2",
"resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.8.2.tgz", "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.8.2.tgz",
@@ -1719,6 +1942,11 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/compute-scroll-into-view": {
"version": "1.0.20",
"resolved": "https://registry.npmmirror.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz",
"integrity": "sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg=="
},
"node_modules/consola": { "node_modules/consola": {
"version": "2.15.3", "version": "2.15.3",
"resolved": "https://registry.npmmirror.com/consola/-/consola-2.15.3.tgz", "resolved": "https://registry.npmmirror.com/consola/-/consola-2.15.3.tgz",
@@ -1787,6 +2015,15 @@
"resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.0.11.tgz", "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.0.11.tgz",
"integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==" "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw=="
}, },
"node_modules/d": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/d/-/d-1.0.1.tgz",
"integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
"dependencies": {
"es5-ext": "^0.10.50",
"type": "^1.0.1"
}
},
"node_modules/date-fns": { "node_modules/date-fns": {
"version": "2.29.3", "version": "2.29.3",
"resolved": "https://registry.npmmirror.com/date-fns/-/date-fns-2.29.3.tgz", "resolved": "https://registry.npmmirror.com/date-fns/-/date-fns-2.29.3.tgz",
@@ -1873,6 +2110,14 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/dom7": {
"version": "3.0.0",
"resolved": "https://registry.npmmirror.com/dom7/-/dom7-3.0.0.tgz",
"integrity": "sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==",
"dependencies": {
"ssr-window": "^3.0.0-alpha.1"
}
},
"node_modules/dotenv": { "node_modules/dotenv": {
"version": "16.0.3", "version": "16.0.3",
"resolved": "https://registry.npmmirror.com/dotenv/-/dotenv-16.0.3.tgz", "resolved": "https://registry.npmmirror.com/dotenv/-/dotenv-16.0.3.tgz",
@@ -1931,6 +2176,39 @@
"errno": "cli.js" "errno": "cli.js"
} }
}, },
"node_modules/es5-ext": {
"version": "0.10.62",
"resolved": "https://registry.npmmirror.com/es5-ext/-/es5-ext-0.10.62.tgz",
"integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
"hasInstallScript": true,
"dependencies": {
"es6-iterator": "^2.0.3",
"es6-symbol": "^3.1.3",
"next-tick": "^1.1.0"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/es6-iterator": {
"version": "2.0.3",
"resolved": "https://registry.npmmirror.com/es6-iterator/-/es6-iterator-2.0.3.tgz",
"integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
"dependencies": {
"d": "1",
"es5-ext": "^0.10.35",
"es6-symbol": "^3.1.1"
}
},
"node_modules/es6-symbol": {
"version": "3.1.3",
"resolved": "https://registry.npmmirror.com/es6-symbol/-/es6-symbol-3.1.3.tgz",
"integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
"dependencies": {
"d": "^1.0.1",
"ext": "^1.1.2"
}
},
"node_modules/esbuild": { "node_modules/esbuild": {
"version": "0.16.17", "version": "0.16.17",
"resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.16.17.tgz", "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.16.17.tgz",
@@ -2006,6 +2284,15 @@
"resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz", "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
}, },
"node_modules/event-emitter": {
"version": "0.3.5",
"resolved": "https://registry.npmmirror.com/event-emitter/-/event-emitter-0.3.5.tgz",
"integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==",
"dependencies": {
"d": "1",
"es5-ext": "~0.10.14"
}
},
"node_modules/evtd": { "node_modules/evtd": {
"version": "0.2.4", "version": "0.2.4",
"resolved": "https://registry.npmmirror.com/evtd/-/evtd-0.2.4.tgz", "resolved": "https://registry.npmmirror.com/evtd/-/evtd-0.2.4.tgz",
@@ -2031,6 +2318,19 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/ext": {
"version": "1.7.0",
"resolved": "https://registry.npmmirror.com/ext/-/ext-1.7.0.tgz",
"integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==",
"dependencies": {
"type": "^2.7.2"
}
},
"node_modules/ext/node_modules/type": {
"version": "2.7.2",
"resolved": "https://registry.npmmirror.com/type/-/type-2.7.2.tgz",
"integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw=="
},
"node_modules/extend-shallow": { "node_modules/extend-shallow": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmmirror.com/extend-shallow/-/extend-shallow-2.0.1.tgz", "resolved": "https://registry.npmmirror.com/extend-shallow/-/extend-shallow-2.0.1.tgz",
@@ -2350,6 +2650,11 @@
"optional": true, "optional": true,
"peer": true "peer": true
}, },
"node_modules/html-void-elements": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/html-void-elements/-/html-void-elements-2.0.1.tgz",
"integrity": "sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A=="
},
"node_modules/https-proxy-agent": { "node_modules/https-proxy-agent": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", "resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
@@ -2374,6 +2679,14 @@
"node": ">=10.17.0" "node": ">=10.17.0"
} }
}, },
"node_modules/i18next": {
"version": "20.6.1",
"resolved": "https://registry.npmmirror.com/i18next/-/i18next-20.6.1.tgz",
"integrity": "sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A==",
"dependencies": {
"@babel/runtime": "^7.12.0"
}
},
"node_modules/ignore": { "node_modules/ignore": {
"version": "5.2.4", "version": "5.2.4",
"resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.2.4.tgz", "resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.2.4.tgz",
@@ -2385,6 +2698,11 @@
"node": ">= 4" "node": ">= 4"
} }
}, },
"node_modules/immer": {
"version": "9.0.19",
"resolved": "https://registry.npmmirror.com/immer/-/immer-9.0.19.tgz",
"integrity": "sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ=="
},
"node_modules/inherits": { "node_modules/inherits": {
"version": "2.0.4", "version": "2.0.4",
"resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz",
@@ -2456,6 +2774,11 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/is-hotkey": {
"version": "0.2.0",
"resolved": "https://registry.npmmirror.com/is-hotkey/-/is-hotkey-0.2.0.tgz",
"integrity": "sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw=="
},
"node_modules/is-number": { "node_modules/is-number": {
"version": "7.0.0", "version": "7.0.0",
"resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz", "resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz",
@@ -2465,6 +2788,14 @@
"node": ">=0.12.0" "node": ">=0.12.0"
} }
}, },
"node_modules/is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmmirror.com/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-stream": { "node_modules/is-stream": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-2.0.1.tgz", "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-2.0.1.tgz",
@@ -2474,6 +2805,11 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/is-url": {
"version": "1.2.4",
"resolved": "https://registry.npmmirror.com/is-url/-/is-url-1.2.4.tgz",
"integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww=="
},
"node_modules/is-wsl": { "node_modules/is-wsl": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmmirror.com/is-wsl/-/is-wsl-2.2.0.tgz", "resolved": "https://registry.npmmirror.com/is-wsl/-/is-wsl-2.2.0.tgz",
@@ -2637,6 +2973,31 @@
"optional": true, "optional": true,
"peer": true "peer": true
}, },
"node_modules/lodash.camelcase": {
"version": "4.3.0",
"resolved": "https://registry.npmmirror.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
"integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="
},
"node_modules/lodash.clonedeep": {
"version": "4.5.0",
"resolved": "https://registry.npmmirror.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
"integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ=="
},
"node_modules/lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmmirror.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
},
"node_modules/lodash.foreach": {
"version": "4.5.0",
"resolved": "https://registry.npmmirror.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz",
"integrity": "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ=="
},
"node_modules/lodash.isequal": {
"version": "4.5.0",
"resolved": "https://registry.npmmirror.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
},
"node_modules/lodash.template": { "node_modules/lodash.template": {
"version": "4.5.0", "version": "4.5.0",
"resolved": "https://registry.npmmirror.com/lodash.template/-/lodash.template-4.5.0.tgz", "resolved": "https://registry.npmmirror.com/lodash.template/-/lodash.template-4.5.0.tgz",
@@ -2660,6 +3021,16 @@
"lodash._reinterpolate": "^3.0.0" "lodash._reinterpolate": "^3.0.0"
} }
}, },
"node_modules/lodash.throttle": {
"version": "4.1.1",
"resolved": "https://registry.npmmirror.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
"integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ=="
},
"node_modules/lodash.toarray": {
"version": "4.4.0",
"resolved": "https://registry.npmmirror.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz",
"integrity": "sha512-QyffEA3i5dma5q2490+SgCvDN0pXLmRGSyAANuVi0HQ01Pkfr9fuoKQW8wm1wGBnJITs/mS7wQvS6VshUEBFCw=="
},
"node_modules/lru-cache": { "node_modules/lru-cache": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-6.0.0.tgz", "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-6.0.0.tgz",
@@ -2777,6 +3148,14 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/mime-match": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/mime-match/-/mime-match-1.0.2.tgz",
"integrity": "sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==",
"dependencies": {
"wildcard": "^1.1.0"
}
},
"node_modules/mime-types": { "node_modules/mime-types": {
"version": "2.1.35", "version": "2.1.35",
"resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz",
@@ -2931,6 +3310,11 @@
"vue": "^3.0.0" "vue": "^3.0.0"
} }
}, },
"node_modules/namespace-emitter": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/namespace-emitter/-/namespace-emitter-2.0.1.tgz",
"integrity": "sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g=="
},
"node_modules/nanoid": { "node_modules/nanoid": {
"version": "3.3.4", "version": "3.3.4",
"resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.4.tgz", "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.4.tgz",
@@ -2942,6 +3326,11 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
} }
}, },
"node_modules/next-tick": {
"version": "1.1.0",
"resolved": "https://registry.npmmirror.com/next-tick/-/next-tick-1.1.0.tgz",
"integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
},
"node_modules/node-fetch-native": { "node_modules/node-fetch-native": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmmirror.com/node-fetch-native/-/node-fetch-native-1.0.2.tgz", "resolved": "https://registry.npmmirror.com/node-fetch-native/-/node-fetch-native-1.0.2.tgz",
@@ -3173,6 +3562,11 @@
"enhanced-resolve": "^4.1.1" "enhanced-resolve": "^4.1.1"
} }
}, },
"node_modules/preact": {
"version": "10.13.1",
"resolved": "https://registry.npmmirror.com/preact/-/preact-10.13.1.tgz",
"integrity": "sha512-KyoXVDU5OqTpG9LXlB3+y639JAGzl8JSBXLn1J9HTSB3gbKcuInga7bZnXLlxmK94ntTs1EFeZp0lrja2AuBYQ=="
},
"node_modules/prettier": { "node_modules/prettier": {
"version": "2.8.4", "version": "2.8.4",
"resolved": "https://registry.npmmirror.com/prettier/-/prettier-2.8.4.tgz", "resolved": "https://registry.npmmirror.com/prettier/-/prettier-2.8.4.tgz",
@@ -3185,6 +3579,14 @@
"node": ">=10.13.0" "node": ">=10.13.0"
} }
}, },
"node_modules/prismjs": {
"version": "1.29.0",
"resolved": "https://registry.npmmirror.com/prismjs/-/prismjs-1.29.0.tgz",
"integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==",
"engines": {
"node": ">=6"
}
},
"node_modules/process-nextick-args": { "node_modules/process-nextick-args": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "resolved": "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -3254,6 +3656,11 @@
"node": ">=8.10.0" "node": ">=8.10.0"
} }
}, },
"node_modules/regenerator-runtime": {
"version": "0.13.11",
"resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
},
"node_modules/resolve": { "node_modules/resolve": {
"version": "1.22.1", "version": "1.22.1",
"resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.1.tgz", "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.1.tgz",
@@ -3311,6 +3718,14 @@
"optional": true, "optional": true,
"peer": true "peer": true
}, },
"node_modules/scroll-into-view-if-needed": {
"version": "2.2.31",
"resolved": "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz",
"integrity": "sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==",
"dependencies": {
"compute-scroll-into-view": "^1.0.20"
}
},
"node_modules/scule": { "node_modules/scule": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmmirror.com/scule/-/scule-1.0.0.tgz", "resolved": "https://registry.npmmirror.com/scule/-/scule-1.0.0.tgz",
@@ -3402,6 +3817,35 @@
"node": ">=12" "node": ">=12"
} }
}, },
"node_modules/slate": {
"version": "0.72.8",
"resolved": "https://registry.npmmirror.com/slate/-/slate-0.72.8.tgz",
"integrity": "sha512-/nJwTswQgnRurpK+bGJFH1oM7naD5qDmHd89JyiKNT2oOKD8marW0QSBtuFnwEbL5aGCS8AmrhXQgNOsn4osAw==",
"dependencies": {
"immer": "^9.0.6",
"is-plain-object": "^5.0.0",
"tiny-warning": "^1.0.3"
}
},
"node_modules/slate-history": {
"version": "0.66.0",
"resolved": "https://registry.npmmirror.com/slate-history/-/slate-history-0.66.0.tgz",
"integrity": "sha512-6MWpxGQZiMvSINlCbMW43E2YBSVMCMCIwQfBzGssjWw4kb0qfvj0pIdblWNRQZD0hR6WHP+dHHgGSeVdMWzfng==",
"dependencies": {
"is-plain-object": "^5.0.0"
},
"peerDependencies": {
"slate": ">=0.65.3"
}
},
"node_modules/snabbdom": {
"version": "3.5.1",
"resolved": "https://registry.npmmirror.com/snabbdom/-/snabbdom-3.5.1.tgz",
"integrity": "sha512-wHMNIOjkm/YNE5EM3RCbr/+DVgPg6AqQAX1eOxO46zYNvCXjKP5Y865tqQj3EXnaMBjkxmQA5jFuDpDK/dbfiA==",
"engines": {
"node": ">=8.3.0"
}
},
"node_modules/source-map": { "node_modules/source-map": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
@@ -3430,6 +3874,11 @@
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
"dev": true "dev": true
}, },
"node_modules/ssr-window": {
"version": "3.0.0",
"resolved": "https://registry.npmmirror.com/ssr-window/-/ssr-window-3.0.0.tgz",
"integrity": "sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA=="
},
"node_modules/state-local": { "node_modules/state-local": {
"version": "1.0.7", "version": "1.0.7",
"resolved": "https://registry.npmmirror.com/state-local/-/state-local-1.0.7.tgz", "resolved": "https://registry.npmmirror.com/state-local/-/state-local-1.0.7.tgz",
@@ -3557,6 +4006,11 @@
"globrex": "^0.1.2" "globrex": "^0.1.2"
} }
}, },
"node_modules/tiny-warning": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/tiny-warning/-/tiny-warning-1.0.3.tgz",
"integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
},
"node_modules/to-fast-properties": { "node_modules/to-fast-properties": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmmirror.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "resolved": "https://registry.npmmirror.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
@@ -3591,6 +4045,11 @@
"integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==",
"dev": true "dev": true
}, },
"node_modules/type": {
"version": "1.2.0",
"resolved": "https://registry.npmmirror.com/type/-/type-1.2.0.tgz",
"integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg=="
},
"node_modules/typescript": { "node_modules/typescript": {
"version": "4.9.5", "version": "4.9.5",
"resolved": "https://registry.npmmirror.com/typescript/-/typescript-4.9.5.tgz", "resolved": "https://registry.npmmirror.com/typescript/-/typescript-4.9.5.tgz",
@@ -4062,6 +4521,11 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/wildcard": {
"version": "1.1.2",
"resolved": "https://registry.npmmirror.com/wildcard/-/wildcard-1.1.2.tgz",
"integrity": "sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng=="
},
"node_modules/yallist": { "node_modules/yallist": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz",

View File

@@ -13,6 +13,8 @@
"@element-plus/icons-vue": "^2.1.0", "@element-plus/icons-vue": "^2.1.0",
"@monaco-editor/loader": "^1.3.2", "@monaco-editor/loader": "^1.3.2",
"@vueuse/core": "^9.13.0", "@vueuse/core": "^9.13.0",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^5.1.12",
"axios": "1.3.4", "axios": "1.3.4",
"chart.js": "^4.2.1", "chart.js": "^4.2.1",
"copy-text-to-clipboard": "^3.0.1", "copy-text-to-clipboard": "^3.0.1",

View File

@@ -79,3 +79,14 @@ export function getContestList(offset = 0, limit = 10, keyword: string) {
params: { paging: true, offset, limit, keyword }, params: { paging: true, offset, limit, keyword },
}) })
} }
// 上传图片
export async function uploadImage(file: File): Promise<string> {
const form = new window.FormData()
form.append("image", file)
const res: { success: boolean; file_path: string; msg: "Success" } =
await http.post("admin/upload_image", form, {
headers: { "content-type": "multipart/form-data" },
})
return res.success ? res.file_path : ""
}

View File

@@ -1,7 +1,241 @@
<script setup lang="ts"></script> <script setup lang="ts">
import { SelectOption } from "naive-ui"
import { getProblemTagList } from "~/shared/api"
import TextEditor from "~/shared/TextEditor.vue"
import { unique } from "~/utils/functions"
import { Problem, Tag } from "~/utils/types"
interface AlterProblem {
spj_language: string
spj_code: string
spj_compile_ok: boolean
test_case_id: string
test_case_score: any[]
}
type ExcludeKeys =
| "id"
| "created_by"
| "create_time"
| "last_update_time"
| "my_status"
| "contest"
| "statistic_info"
| "accepted_number"
| "submission_number"
| "total_score"
const message = useMessage()
const problem = reactive<Omit<Problem, ExcludeKeys> & AlterProblem>({
_id: "",
title: "",
description: "",
input_description: "",
output_description: "",
time_limit: 1000,
memory_limit: 64,
difficulty: "Low",
visible: true,
share_submission: false,
tags: [],
languages: ["C", "C++", "Python3"],
template: {},
samples: [{ input: "", output: "" }],
spj: false,
spj_language: "",
spj_code: "",
spj_compile_ok: false,
test_case_id: "",
test_case_score: [],
rule_type: "ACM",
hint: "",
source: "",
io_mode: {
io_mode: "Standard IO",
input: "input.txt",
output: "output.txt",
},
})
const existingTags = shallowRef<Tag[]>([])
const fromExistingTags = shallowRef<string[]>([])
const newTags = shallowRef<string[]>([])
const difficultyOptions: SelectOption[] = [
{ label: "简单", value: "Low" },
{ label: "中等", value: "Med" },
{ label: "困难", value: "High" },
]
const languageOptions = [
{ label: "C", value: "C" },
{ label: "C++", value: "C++" },
{ label: "Python", value: "Python3" },
{ label: "Java", value: "Java" },
{ label: "JS", value: "JavaScript" },
{ label: "Go", value: "Golang" },
]
const tagOptions = computed(() =>
existingTags.value.map((tag) => ({ label: tag.name, value: tag.name }))
)
async function listTags() {
const res = await getProblemTagList()
existingTags.value = res.data
}
function updateNewTags(v: string[]) {
const blanks = []
const uniqueTags = unique(v)
const tags = existingTags.value.map((t) => t.name)
for (let i = 0; i < uniqueTags.length; i++) {
const tag = uniqueTags[i]
if (tags.indexOf(tag) < 0) {
blanks.push(tag)
} else {
message.error("已经存在标签:" + tag)
break
}
}
newTags.value = blanks
}
function addSample() {
problem.samples.push({ input: "", output: "" })
}
function removeSample(index: number) {
problem.samples.splice(index, 1)
}
onMounted(() => {
listTags()
})
watch([fromExistingTags, newTags], (tags) => {
const uniqueTags = unique<string>(tags[0].concat(tags[1]))
problem.tags = uniqueTags
})
</script>
<template> <template>
<div>problem detail</div> <n-form inline label-placement="left">
<n-form-item label="显示编号">
<n-input class="id" v-model:value="problem._id" />
</n-form-item>
<n-form-item label="题目">
<n-input class="titleInput" v-model:value="problem.title" />
</n-form-item>
<n-form-item label="语言">
<n-checkbox-group v-model:value="problem.languages">
<n-space align="center">
<n-checkbox
v-for="(language, index) in languageOptions"
:key="index"
:value="language.value"
:label="language.label"
/>
</n-space>
</n-checkbox-group>
</n-form-item>
</n-form>
<n-form inline label-placement="left">
<n-form-item label="可见">
<n-switch v-model:value="problem.visible" />
</n-form-item>
<n-form-item label="难度">
<n-select
class="difficulty"
:options="difficultyOptions"
v-model:value="problem.difficulty"
/>
</n-form-item>
<n-form-item label="现成的标签">
<n-select
class="tag"
multiple
v-model:value="fromExistingTags"
:options="tagOptions"
/>
</n-form-item>
<n-form-item label="新增的标签">
<n-dynamic-tags v-model:value="newTags" @update:value="updateNewTags" />
</n-form-item>
</n-form>
<TextEditor
v-model:value="problem.description"
title="题目"
:min-height="300"
/>
<TextEditor v-model:value="problem.input_description" title="输入的描述" />
<TextEditor v-model:value="problem.output_description" title="输出的描述" />
<div class="samples" v-for="(sample, index) in problem.samples" :key="index">
<n-space justify="space-between" align="center">
<strong>测试样例 {{ index + 1 }}</strong>
<n-button
tertiary
type="warning"
size="small"
@click="removeSample(index)"
>
删除 {{ index + 1 }}
</n-button>
</n-space>
<n-grid x-gap="20" cols="2">
<n-gi span="1">
<n-space vertical>
<span>输入样例</span>
<n-input type="textarea" v-model:value="sample.input" />
</n-space>
</n-gi>
<n-gi span="1">
<n-space vertical>
<span>输出样例</span>
<n-input type="textarea" v-model:value="sample.output" />
</n-space>
</n-gi>
</n-grid>
</div>
<n-button class="addSamples" tertiary type="primary" @click="addSample">
添加用例
</n-button>
<TextEditor v-model:value="problem.hint" title="提示" />
<n-form>
<n-form-item label="题目的来源">
<n-input
v-model:value="problem.source"
placeholder="(比如来自某道题的改编等,或者网上的资料)"
/>
</n-form-item>
</n-form>
</template> </template>
<style scoped></style> <style scoped>
.id {
width: 100px;
}
.titleInput {
width: 300px;
}
.title {
margin-bottom: 12px;
}
.difficulty {
width: 100px;
}
.tag {
width: 300px;
}
.samples {
margin-bottom: 20px;
}
.addSamples {
width: 100%;
margin-bottom: 20px;
}
</style>

3
src/components.d.ts vendored
View File

@@ -21,12 +21,15 @@ declare module '@vue/runtime-core' {
NAvatar: typeof import('naive-ui')['NAvatar'] NAvatar: typeof import('naive-ui')['NAvatar']
NButton: typeof import('naive-ui')['NButton'] NButton: typeof import('naive-ui')['NButton']
NCard: typeof import('naive-ui')['NCard'] NCard: typeof import('naive-ui')['NCard']
NCheckbox: typeof import('naive-ui')['NCheckbox']
NCheckboxGroup: typeof import('naive-ui')['NCheckboxGroup']
NCode: typeof import('naive-ui')['NCode'] NCode: typeof import('naive-ui')['NCode']
NConfigProvider: typeof import('naive-ui')['NConfigProvider'] NConfigProvider: typeof import('naive-ui')['NConfigProvider']
NDataTable: typeof import('naive-ui')['NDataTable'] NDataTable: typeof import('naive-ui')['NDataTable']
NDescriptions: typeof import('naive-ui')['NDescriptions'] NDescriptions: typeof import('naive-ui')['NDescriptions']
NDescriptionsItem: typeof import('naive-ui')['NDescriptionsItem'] NDescriptionsItem: typeof import('naive-ui')['NDescriptionsItem']
NDropdown: typeof import('naive-ui')['NDropdown'] NDropdown: typeof import('naive-ui')['NDropdown']
NDynamicTags: typeof import('naive-ui')['NDynamicTags']
NEmpty: typeof import('naive-ui')['NEmpty'] NEmpty: typeof import('naive-ui')['NEmpty']
NForm: typeof import('naive-ui')['NForm'] NForm: typeof import('naive-ui')['NForm']
NFormItem: typeof import('naive-ui')['NFormItem'] NFormItem: typeof import('naive-ui')['NFormItem']

View File

@@ -51,10 +51,6 @@ export async function getProblemList(
} }
} }
export function getProblemTagList() {
return http.get("problem/tags")
}
export function getRandomProblemID() { export function getRandomProblemID() {
return http.get("pickone") return http.get("pickone")
} }

View File

@@ -3,10 +3,11 @@ import { useUserStore } from "~/shared/store/user"
import { filterEmptyValue, getTagColor } from "utils/functions" import { filterEmptyValue, getTagColor } from "utils/functions"
import { ProblemFiltered } from "utils/types" import { ProblemFiltered } from "utils/types"
import { isDesktop } from "~/shared/composables/breakpoints" import { isDesktop } from "~/shared/composables/breakpoints"
import { getProblemList, getProblemTagList, getRandomProblemID } from "oj/api" import { getProblemList, getRandomProblemID } from "oj/api"
import Pagination from "~/shared/Pagination.vue" import Pagination from "~/shared/Pagination.vue"
import { DataTableColumn, NSpace, NTag } from "naive-ui" import { DataTableColumn, NSpace, NTag } from "naive-ui"
import ProblemStatus from "./components/ProblemStatus.vue" import ProblemStatus from "./components/ProblemStatus.vue"
import { getProblemTagList } from "~/shared/api"
interface Tag { interface Tag {
id: number id: number

91
src/shared/TextEditor.vue Normal file
View File

@@ -0,0 +1,91 @@
<script setup lang="ts">
import "@wangeditor/editor/dist/css/style.css"
import { IDomEditor, IEditorConfig, IToolbarConfig } from "@wangeditor/editor"
import { Editor, Toolbar } from "@wangeditor/editor-for-vue"
import { uploadImage } from "../admin/api"
interface Props {
value: string
title: string
minHeight?: number
}
type InsertFnType = (url: string, alt: string, href: string) => void
const props = withDefaults(defineProps<Props>(), {
minHeight: 0,
})
const emit = defineEmits(["update:value"])
const message = useMessage()
const rawHtml = ref(props.value)
watch(rawHtml, () => emit("update:value", rawHtml.value))
const editorRef = shallowRef<IDomEditor>()
const toolbarConfig: Partial<IToolbarConfig> = {
excludeKeys: ["todo", "insertVideo", "insertTable", "fullScreen"],
}
const editorConfig: Partial<IEditorConfig> = {
scroll: false,
MENU_CONF: {
uploadImage: { customUpload },
},
}
onBeforeUnmount(() => {
const editor = editorRef.value
if (editor) editor.destroy()
})
function handleCreated(editor: IDomEditor) {
editorRef.value = editor
}
async function customUpload(file: File, insertFn: InsertFnType) {
const path = await uploadImage(file)
if (!path) {
message.error("图片上传失败")
return
}
const url = path
const alt = "图片"
const href = ""
insertFn(url, alt, href)
}
</script>
<template>
<div class="title" v-if="props.title">{{ props.title }}</div>
<div class="editorWrapper">
<Toolbar
class="toolbar"
:editor="editorRef"
:defaultConfig="toolbarConfig"
mode="simple"
/>
<Editor
:style="{ minHeight: props.minHeight + 'px' }"
v-model="rawHtml"
:defaultConfig="editorConfig"
mode="simple"
@onCreated="handleCreated"
/>
</div>
</template>
<style scoped>
.title {
margin-bottom: 12px;
}
.toolbar {
border-bottom: 1px solid #ddd;
}
.editorWrapper {
border: 1px solid #ddd;
margin-bottom: 20px;
}
</style>

View File

@@ -1,5 +1,5 @@
import http from "utils/http" import http from "utils/http"
import { Profile } from "~/utils/types" import { Profile, Tag } from "~/utils/types"
export function login(data: { username: string; password: string }) { export function login(data: { username: string; password: string }) {
return http.post("login", data) return http.post("login", data)
@@ -12,3 +12,7 @@ export function logout() {
export function getProfile(username: string = "") { export function getProfile(username: string = "") {
return http.get<Profile>("profile", { params: { username } }) return http.get<Profile>("profile", { params: { username } })
} }
export function getProblemTagList() {
return http.get<Tag[]>("problem/tags")
}

View File

@@ -110,7 +110,7 @@ onMounted(async () => {
<n-layout-sider width="160" bordered :native-scrollbar="false"> <n-layout-sider width="160" bordered :native-scrollbar="false">
<n-menu :options="options" :value="active" /> <n-menu :options="options" :value="active" />
</n-layout-sider> </n-layout-sider>
<n-layout-content content-style="padding: 16px"> <n-layout-content content-style="padding: 16px; min-width: 600px">
<router-view></router-view> <router-view></router-view>
</n-layout-content> </n-layout-content>
</n-layout> </n-layout>

View File

@@ -129,3 +129,12 @@ export function getUserRole(role: User["admin_type"]): {
} }
return obj return obj
} }
export function unique<T>(arr: T[]) {
return arr.reduce((prev: T[], curr: T) => {
if (!prev.includes(curr)) {
prev.push(curr)
}
return prev
}, [])
}

View File

@@ -67,6 +67,11 @@ interface SampleUser {
real_name: string | null real_name: string | null
} }
export interface Tag {
id: number
name: string
}
export interface Problem { export interface Problem {
_id: string _id: string
id: number id: number
@@ -93,7 +98,7 @@ export interface Problem {
io_mode: string io_mode: string
} }
spj: boolean spj: boolean
spj_language: null spj_language: string
rule_type: string rule_type: string
difficulty: "Low" | "Mid" | "High" difficulty: "Low" | "Mid" | "High"
source: string source: string