style: 新增添加作业库页面;编辑作业库页面;新增关闭顶部广告功能;调整富文本;添加作业库导入页面

This commit is contained in:
QDKF 2025-08-26 18:19:23 +08:00
parent 638e939fe5
commit 541886b6e6
12 changed files with 1734 additions and 137 deletions

569
package-lock.json generated
View File

@ -9,10 +9,14 @@
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"@vicons/ionicons5": "^0.13.0", "@vicons/ionicons5": "^0.13.0",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^5.1.12",
"@wangeditor/plugin-upload-attachment": "^1.1.0",
"axios": "^1.11.0", "axios": "^1.11.0",
"ckplayer": "^3.1.2", "ckplayer": "^3.1.2",
"dplayer": "^1.27.1", "dplayer": "^1.27.1",
"naive-ui": "^2.42.0", "naive-ui": "^2.42.0",
"naive-ui-editor": "^1.0.6",
"pinia": "^3.0.3", "pinia": "^3.0.3",
"quill": "^2.0.3", "quill": "^2.0.3",
"vue": "^3.5.17", "vue": "^3.5.17",
@ -462,6 +466,15 @@
"@babel/core": "^7.0.0-0" "@babel/core": "^7.0.0-0"
} }
}, },
"node_modules/@babel/runtime": {
"version": "7.28.3",
"resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.28.3.tgz",
"integrity": "sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/template": { "node_modules/@babel/template": {
"version": "7.27.2", "version": "7.27.2",
"resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.27.2.tgz", "resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.27.2.tgz",
@ -1400,6 +1413,12 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"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==",
"license": "MIT"
},
"node_modules/@types/dplayer": { "node_modules/@types/dplayer": {
"version": "1.25.5", "version": "1.25.5",
"resolved": "https://registry.npmjs.org/@types/dplayer/-/dplayer-1.25.5.tgz", "resolved": "https://registry.npmjs.org/@types/dplayer/-/dplayer-1.25.5.tgz",
@ -1414,6 +1433,12 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/event-emitter": {
"version": "0.3.5",
"resolved": "https://registry.npmmirror.com/@types/event-emitter/-/event-emitter-0.3.5.tgz",
"integrity": "sha512-zx2/Gg0Eg7gwEiOIIh5w9TrhKKTeQh7CPCOPNc0el4pLSwzebA8SmnHwZs2dWlLONvyulykSwGSQxQHLhjGLvQ==",
"license": "MIT"
},
"node_modules/@types/katex": { "node_modules/@types/katex": {
"version": "0.16.7", "version": "0.16.7",
"resolved": "https://registry.npmmirror.com/@types/katex/-/katex-0.16.7.tgz", "resolved": "https://registry.npmmirror.com/@types/katex/-/katex-0.16.7.tgz",
@ -1445,6 +1470,61 @@
"undici-types": "~7.8.0" "undici-types": "~7.8.0"
} }
}, },
"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==",
"license": "MIT",
"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==",
"license": "MIT",
"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==",
"license": "MIT"
},
"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==",
"license": "MIT",
"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==",
"license": "MIT",
"dependencies": {
"@uppy/companion-client": "^2.2.2",
"@uppy/utils": "^4.1.2",
"nanoid": "^3.1.25"
},
"peerDependencies": {
"@uppy/core": "^2.3.3"
}
},
"node_modules/@vicons/ionicons5": { "node_modules/@vicons/ionicons5": {
"version": "0.13.0", "version": "0.13.0",
"resolved": "https://registry.npmmirror.com/@vicons/ionicons5/-/ionicons5-0.13.0.tgz", "resolved": "https://registry.npmmirror.com/@vicons/ionicons5/-/ionicons5-0.13.0.tgz",
@ -1756,6 +1836,194 @@
"integrity": "sha512-CabR+UN630VnsJO/jHWYBC1YVXyMq94KKp6iF5MQgZJs5I8cmjw6oVMO1oDbtBkENSHSSn/UadWlW/OAgdmKrg==", "integrity": "sha512-CabR+UN630VnsJO/jHWYBC1YVXyMq94KKp6iF5MQgZJs5I8cmjw6oVMO1oDbtBkENSHSSn/UadWlW/OAgdmKrg==",
"license": "MIT" "license": "MIT"
}, },
"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==",
"license": "MIT",
"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==",
"license": "MIT",
"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==",
"license": "MIT",
"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==",
"license": "MIT",
"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==",
"license": "MIT",
"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==",
"license": "MIT",
"peerDependencies": {
"@wangeditor/core": "1.x",
"dom7": "^3.0.0",
"slate": "^0.72.0",
"snabbdom": "^3.1.0"
}
},
"node_modules/@wangeditor/plugin-upload-attachment": {
"version": "1.1.0",
"resolved": "https://registry.npmmirror.com/@wangeditor/plugin-upload-attachment/-/plugin-upload-attachment-1.1.0.tgz",
"integrity": "sha512-K6SsV3Cv1g+Ob1xjRRQ13Sh3lcj3yAa/aXMaKKbaPI76rNZiOpyAGH/iVv5i9enmwbZql01IXpvhK+HtrikVyQ==",
"license": "MIT",
"dependencies": {
"dom7": "^4.0.4"
},
"peerDependencies": {
"@uppy/core": "^2.1.5",
"@wangeditor/editor": ">=5.1.16",
"snabbdom": "^3.3.1"
}
},
"node_modules/@wangeditor/plugin-upload-attachment/node_modules/dom7": {
"version": "4.0.6",
"resolved": "https://registry.npmmirror.com/dom7/-/dom7-4.0.6.tgz",
"integrity": "sha512-emjdpPLhpNubapLFdjNL9tP06Sr+GZkrIHEXLWvOGsytACUrkbeIdjO5g77m00BrHTznnlcNqgmn7pCN192TBA==",
"license": "MIT",
"dependencies": {
"ssr-window": "^4.0.0"
}
},
"node_modules/@wangeditor/plugin-upload-attachment/node_modules/ssr-window": {
"version": "4.0.2",
"resolved": "https://registry.npmmirror.com/ssr-window/-/ssr-window-4.0.2.tgz",
"integrity": "sha512-ISv/Ch+ig7SOtw7G2+qkwfVASzazUnvlDTwypdLoPoySv+6MqlOV10VwPSE6EWkGjhW50lUmghPmpYZXMu/+AQ==",
"license": "MIT"
},
"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==",
"license": "MIT",
"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==",
"license": "MIT",
"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==",
"license": "MIT",
"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/alien-signals": { "node_modules/alien-signals": {
"version": "2.0.5", "version": "2.0.5",
"resolved": "https://registry.npmmirror.com/alien-signals/-/alien-signals-2.0.5.tgz", "resolved": "https://registry.npmmirror.com/alien-signals/-/alien-signals-2.0.5.tgz",
@ -1945,6 +2213,12 @@
"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==",
"license": "MIT"
},
"node_modules/convert-source-map": { "node_modules/convert-source-map": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz", "resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz",
@ -2004,6 +2278,19 @@
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/d": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/d/-/d-1.0.2.tgz",
"integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==",
"license": "ISC",
"dependencies": {
"es5-ext": "^0.10.64",
"type": "^2.7.2"
},
"engines": {
"node": ">=0.12"
}
},
"node_modules/date-fns": { "node_modules/date-fns": {
"version": "3.6.0", "version": "3.6.0",
"resolved": "https://registry.npmmirror.com/date-fns/-/date-fns-3.6.0.tgz", "resolved": "https://registry.npmmirror.com/date-fns/-/date-fns-3.6.0.tgz",
@ -2154,6 +2441,15 @@
"node": ">=0.4.0" "node": ">=0.4.0"
} }
}, },
"node_modules/dom7": {
"version": "3.0.0",
"resolved": "https://registry.npmmirror.com/dom7/-/dom7-3.0.0.tgz",
"integrity": "sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==",
"license": "MIT",
"dependencies": {
"ssr-window": "^3.0.0-alpha.1"
}
},
"node_modules/dplayer": { "node_modules/dplayer": {
"version": "1.27.1", "version": "1.27.1",
"resolved": "https://registry.npmjs.org/dplayer/-/dplayer-1.27.1.tgz", "resolved": "https://registry.npmjs.org/dplayer/-/dplayer-1.27.1.tgz",
@ -2264,6 +2560,46 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/es5-ext": {
"version": "0.10.64",
"resolved": "https://registry.npmmirror.com/es5-ext/-/es5-ext-0.10.64.tgz",
"integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==",
"hasInstallScript": true,
"license": "ISC",
"dependencies": {
"es6-iterator": "^2.0.3",
"es6-symbol": "^3.1.3",
"esniff": "^2.0.1",
"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==",
"license": "MIT",
"dependencies": {
"d": "1",
"es5-ext": "^0.10.35",
"es6-symbol": "^3.1.1"
}
},
"node_modules/es6-symbol": {
"version": "3.1.4",
"resolved": "https://registry.npmmirror.com/es6-symbol/-/es6-symbol-3.1.4.tgz",
"integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==",
"license": "ISC",
"dependencies": {
"d": "^1.0.2",
"ext": "^1.7.0"
},
"engines": {
"node": ">=0.12"
}
},
"node_modules/esbuild": { "node_modules/esbuild": {
"version": "0.25.7", "version": "0.25.7",
"resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.25.7.tgz", "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.25.7.tgz",
@ -2316,12 +2652,37 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/esniff": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/esniff/-/esniff-2.0.1.tgz",
"integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==",
"license": "ISC",
"dependencies": {
"d": "^1.0.1",
"es5-ext": "^0.10.62",
"event-emitter": "^0.3.5",
"type": "^2.7.2"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/estree-walker": { "node_modules/estree-walker": {
"version": "2.0.2", "version": "2.0.2",
"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==",
"license": "MIT" "license": "MIT"
}, },
"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==",
"license": "MIT",
"dependencies": {
"d": "1",
"es5-ext": "~0.10.14"
}
},
"node_modules/eventemitter3": { "node_modules/eventemitter3": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-5.0.1.tgz", "resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-5.0.1.tgz",
@ -2361,6 +2722,15 @@
"url": "https://github.com/sindresorhus/execa?sponsor=1" "url": "https://github.com/sindresorhus/execa?sponsor=1"
} }
}, },
"node_modules/ext": {
"version": "1.7.0",
"resolved": "https://registry.npmmirror.com/ext/-/ext-1.7.0.tgz",
"integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==",
"license": "ISC",
"dependencies": {
"type": "^2.7.2"
}
},
"node_modules/extend": { "node_modules/extend": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmmirror.com/extend/-/extend-3.0.2.tgz", "resolved": "https://registry.npmmirror.com/extend/-/extend-3.0.2.tgz",
@ -2647,6 +3017,16 @@
"integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==",
"license": "MIT" "license": "MIT"
}, },
"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==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/human-signals": { "node_modules/human-signals": {
"version": "8.0.1", "version": "8.0.1",
"resolved": "https://registry.npmmirror.com/human-signals/-/human-signals-8.0.1.tgz", "resolved": "https://registry.npmmirror.com/human-signals/-/human-signals-8.0.1.tgz",
@ -2657,6 +3037,25 @@
"node": ">=18.18.0" "node": ">=18.18.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==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.12.0"
}
},
"node_modules/immer": {
"version": "9.0.21",
"resolved": "https://registry.npmmirror.com/immer/-/immer-9.0.21.tgz",
"integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==",
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/immer"
}
},
"node_modules/is-arguments": { "node_modules/is-arguments": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmmirror.com/is-arguments/-/is-arguments-1.2.0.tgz", "resolved": "https://registry.npmmirror.com/is-arguments/-/is-arguments-1.2.0.tgz",
@ -2705,6 +3104,12 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"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==",
"license": "MIT"
},
"node_modules/is-inside-container": { "node_modules/is-inside-container": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmmirror.com/is-inside-container/-/is-inside-container-1.0.0.tgz", "resolved": "https://registry.npmmirror.com/is-inside-container/-/is-inside-container-1.0.0.tgz",
@ -2737,6 +3142,15 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"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==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-regex": { "node_modules/is-regex": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmmirror.com/is-regex/-/is-regex-1.2.1.tgz", "resolved": "https://registry.npmmirror.com/is-regex/-/is-regex-1.2.1.tgz",
@ -2781,6 +3195,12 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"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==",
"license": "MIT"
},
"node_modules/is-what": { "node_modules/is-what": {
"version": "4.1.16", "version": "4.1.16",
"resolved": "https://registry.npmmirror.com/is-what/-/is-what-4.1.16.tgz", "resolved": "https://registry.npmmirror.com/is-what/-/is-what-4.1.16.tgz",
@ -2881,12 +3301,30 @@
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
"license": "MIT" "license": "MIT"
}, },
"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==",
"license": "MIT"
},
"node_modules/lodash.clonedeep": { "node_modules/lodash.clonedeep": {
"version": "4.5.0", "version": "4.5.0",
"resolved": "https://registry.npmmirror.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", "resolved": "https://registry.npmmirror.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
"integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==",
"license": "MIT" "license": "MIT"
}, },
"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==",
"license": "MIT"
},
"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==",
"license": "MIT"
},
"node_modules/lodash.isequal": { "node_modules/lodash.isequal": {
"version": "4.5.0", "version": "4.5.0",
"resolved": "https://registry.npmmirror.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz", "resolved": "https://registry.npmmirror.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
@ -2894,6 +3332,18 @@
"deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.",
"license": "MIT" "license": "MIT"
}, },
"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==",
"license": "MIT"
},
"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==",
"license": "MIT"
},
"node_modules/lru-cache": { "node_modules/lru-cache": {
"version": "5.1.1", "version": "5.1.1",
"resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz", "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz",
@ -2931,6 +3381,15 @@
"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==",
"license": "ISC",
"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",
@ -3003,6 +3462,26 @@
"vue": "^3.0.0" "vue": "^3.0.0"
} }
}, },
"node_modules/naive-ui-editor": {
"version": "1.0.6",
"resolved": "https://registry.npmmirror.com/naive-ui-editor/-/naive-ui-editor-1.0.6.tgz",
"integrity": "sha512-F27n8C5bcBWroeD654q2Zv0hlLA0JW59p8LQl03XYNNJtLgrd4a8NM3a1hMvRb3C5zkVw2QojsNjoTygYsm0ug==",
"dependencies": {
"vue": "^3.3.4"
},
"peerDependencies": {
"@wangeditor/editor": ">=5.1.23",
"@wangeditor/editor-for-vue": ">=5.1.12",
"naive-ui": ">=2.34.0",
"vue": ">=3.2.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==",
"license": "MIT"
},
"node_modules/nanoid": { "node_modules/nanoid": {
"version": "3.3.11", "version": "3.3.11",
"resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz", "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz",
@ -3021,6 +3500,12 @@
"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==",
"license": "ISC"
},
"node_modules/node-releases": { "node_modules/node-releases": {
"version": "2.0.19", "version": "2.0.19",
"resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.19.tgz", "resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.19.tgz",
@ -3228,6 +3713,16 @@
"node": "^10 || ^12 || >=14" "node": "^10 || ^12 || >=14"
} }
}, },
"node_modules/preact": {
"version": "10.27.1",
"resolved": "https://registry.npmmirror.com/preact/-/preact-10.27.1.tgz",
"integrity": "sha512-V79raXEWch/rbqoNc7nT9E4ep7lu+mI3+sBmfRD4i1M73R3WLYcCtdI0ibxGVf4eQL8ZIz2nFacqEC+rmnOORQ==",
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/preact"
}
},
"node_modules/pretty-ms": { "node_modules/pretty-ms": {
"version": "9.2.0", "version": "9.2.0",
"resolved": "https://registry.npmmirror.com/pretty-ms/-/pretty-ms-9.2.0.tgz", "resolved": "https://registry.npmmirror.com/pretty-ms/-/pretty-ms-9.2.0.tgz",
@ -3244,6 +3739,15 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/prismjs": {
"version": "1.30.0",
"resolved": "https://registry.npmmirror.com/prismjs/-/prismjs-1.30.0.tgz",
"integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/promise-polyfill": { "node_modules/promise-polyfill": {
"version": "8.3.0", "version": "8.3.0",
"resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.3.0.tgz", "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.3.0.tgz",
@ -3364,6 +3868,15 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"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==",
"license": "MIT",
"dependencies": {
"compute-scroll-into-view": "^1.0.20"
}
},
"node_modules/seemly": { "node_modules/seemly": {
"version": "0.3.10", "version": "0.3.10",
"resolved": "https://registry.npmmirror.com/seemly/-/seemly-0.3.10.tgz", "resolved": "https://registry.npmmirror.com/seemly/-/seemly-0.3.10.tgz",
@ -3463,6 +3976,38 @@
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/slate": {
"version": "0.72.8",
"resolved": "https://registry.npmmirror.com/slate/-/slate-0.72.8.tgz",
"integrity": "sha512-/nJwTswQgnRurpK+bGJFH1oM7naD5qDmHd89JyiKNT2oOKD8marW0QSBtuFnwEbL5aGCS8AmrhXQgNOsn4osAw==",
"license": "MIT",
"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==",
"license": "MIT",
"dependencies": {
"is-plain-object": "^5.0.0"
},
"peerDependencies": {
"slate": ">=0.65.3"
}
},
"node_modules/snabbdom": {
"version": "3.6.2",
"resolved": "https://registry.npmmirror.com/snabbdom/-/snabbdom-3.6.2.tgz",
"integrity": "sha512-ig5qOnCDbugFntKi6c7Xlib8bA6xiJVk8O+WdFrV3wxbMqeHO0hXFQC4nAhPVWfZfi8255lcZkNhtIBINCc4+Q==",
"license": "MIT",
"engines": {
"node": ">=12.17.0"
}
},
"node_modules/source-map-js": { "node_modules/source-map-js": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz", "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz",
@ -3481,6 +4026,12 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"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==",
"license": "MIT"
},
"node_modules/strip-final-newline": { "node_modules/strip-final-newline": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmmirror.com/strip-final-newline/-/strip-final-newline-4.0.0.tgz", "resolved": "https://registry.npmmirror.com/strip-final-newline/-/strip-final-newline-4.0.0.tgz",
@ -3506,6 +4057,12 @@
"node": ">=16" "node": ">=16"
} }
}, },
"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==",
"license": "MIT"
},
"node_modules/tinyglobby": { "node_modules/tinyglobby": {
"version": "0.2.14", "version": "0.2.14",
"resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.14.tgz", "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.14.tgz",
@ -3539,6 +4096,12 @@
"integrity": "sha512-M8RGFoKtZ8dF+iwJfAJTOH/SM4KluKOKRJpjCMhI8bG3qB74zrFoArKZ62ll0Fr3mqkMJiQOmWYkdYgDeITYQg==", "integrity": "sha512-M8RGFoKtZ8dF+iwJfAJTOH/SM4KluKOKRJpjCMhI8bG3qB74zrFoArKZ62ll0Fr3mqkMJiQOmWYkdYgDeITYQg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/type": {
"version": "2.7.3",
"resolved": "https://registry.npmmirror.com/type/-/type-2.7.3.tgz",
"integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==",
"license": "ISC"
},
"node_modules/typescript": { "node_modules/typescript": {
"version": "5.8.3", "version": "5.8.3",
"resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.8.3.tgz", "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.8.3.tgz",
@ -3987,6 +4550,12 @@
"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==",
"license": "MIT"
},
"node_modules/wsl-utils": { "node_modules/wsl-utils": {
"version": "0.1.0", "version": "0.1.0",
"resolved": "https://registry.npmmirror.com/wsl-utils/-/wsl-utils-0.1.0.tgz", "resolved": "https://registry.npmmirror.com/wsl-utils/-/wsl-utils-0.1.0.tgz",

View File

@ -14,10 +14,14 @@
}, },
"dependencies": { "dependencies": {
"@vicons/ionicons5": "^0.13.0", "@vicons/ionicons5": "^0.13.0",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^5.1.12",
"@wangeditor/plugin-upload-attachment": "^1.1.0",
"axios": "^1.11.0", "axios": "^1.11.0",
"ckplayer": "^3.1.2", "ckplayer": "^3.1.2",
"dplayer": "^1.27.1", "dplayer": "^1.27.1",
"naive-ui": "^2.42.0", "naive-ui": "^2.42.0",
"naive-ui-editor": "^1.0.6",
"pinia": "^3.0.3", "pinia": "^3.0.3",
"quill": "^2.0.3", "quill": "^2.0.3",
"vue": "^3.5.17", "vue": "^3.5.17",

Binary file not shown.

After

Width:  |  Height:  |  Size: 452 B

View File

@ -0,0 +1,92 @@
<template>
<transition name="fade">
<div v-if="visible" :class="['message', type]" @click="close">
<div class="message-icon">
<img v-if="type === 'success'" src="/images/teacher/upload-succeed.png" alt="success" class="icon-img">
<img v-else src="/images/teacher/upload-fail.png" alt="error" class="icon-img">
</div>
<span class="message-text">{{ message }}</span>
</div>
</transition>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const visible = ref(false)
const message = ref('')
const type = ref<'success' | 'error'>('success')
let timeout: NodeJS.Timeout | null = null
const show = (msg: string, msgType: 'success' | 'error' = 'success', duration = 3000) => {
message.value = msg
type.value = msgType
visible.value = true
if (timeout) {
clearTimeout(timeout)
}
timeout = setTimeout(close, duration)
}
const close = () => {
visible.value = false
}
// 使
defineExpose({
show,
close
})
</script>
<style scoped>
.message {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
align-items: center;
padding: 12px 20px;
border-radius: 4px;
background-color: #4a4a4a;
color: #fff;
z-index: 1000;
min-width: 100px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
cursor: pointer;
}
.message-icon {
margin-right: 12px;
display: flex;
align-items: center;
}
.icon-img {
width: 20px;
height: 20px;
object-fit: contain;
}
.message-text {
font-size: 14px;
line-height: 1.4;
}
.fade-enter-active, .fade-leave-active {
transition: all 0.3s ease;
}
.fade-enter-from {
opacity: 0;
transform: translate(-50%, -50%) scale(0.8);
}
.fade-leave-to {
opacity: 0;
transform: translate(-50%, -50%) scale(0.8);
}
</style>

View File

@ -88,6 +88,7 @@ import {
NPopselect NPopselect
} from 'naive-ui' } from 'naive-ui'
const naive = create({ const naive = create({
components: [ components: [
NButton, NButton,

View File

@ -54,6 +54,8 @@ import GeneralManagement from '@/views/teacher/course/GeneralManagement.vue'
// 作业子组件 // 作业子组件
import HomeworkLibrary from '@/views/teacher/course/HomeworkLibrary.vue' import HomeworkLibrary from '@/views/teacher/course/HomeworkLibrary.vue'
import HomeworkReview from '@/views/teacher/course/HomeworkReview.vue' import HomeworkReview from '@/views/teacher/course/HomeworkReview.vue'
import AddHomework from '@/views/teacher/course/AddHomework.vue'
import HomeworkTemplateImport from '@/views/teacher/course/HomeworkTemplateImport.vue'
// 考试管理组件 // 考试管理组件
import ExamManagement from '@/views/teacher/ExamPages/ExamPage.vue' import ExamManagement from '@/views/teacher/ExamPages/ExamPage.vue'
@ -148,11 +150,23 @@ const routes: RouteRecordRaw[] = [
component: HomeworkLibrary, component: HomeworkLibrary,
meta: { title: '作业库' } meta: { title: '作业库' }
}, },
{
path: 'add-homework',
name: 'AddHomework',
component: AddHomework,
meta: { title: '添加作业' }
},
{ {
path: 'review', path: 'review',
name: 'HomeworkReview', name: 'HomeworkReview',
component: HomeworkReview, component: HomeworkReview,
meta: { title: '批阅作业' } meta: { title: '批阅作业' }
},
{
path: 'template-import',
name: 'HomeworkTemplateImport',
component: HomeworkTemplateImport,
meta: { title: '作业库模板导入' }
} }
] ]
}, },

View File

@ -1,9 +1,9 @@
<template> <template>
<div class="admin-dashboard"> <div class="admin-dashboard">
<!-- 顶部图片 --> <!-- 顶部图片 -->
<div class="top-image-container"> <div class="top-image-container" v-if="showTopImage">
<img src="/images/teacher/顶部.png" alt="顶部图片" class="top-image"> <img src="/images/teacher/顶部.png" alt="顶部图片" class="top-image">
<button class="close-button" @click="handleClose">关闭</button>
</div> </div>
<div class="main-content"> <div class="main-content">
@ -76,13 +76,15 @@
<div class="router-view-container" :class="{ 'full-width': hideSidebar }"> <div class="router-view-container" :class="{ 'full-width': hideSidebar }">
<!-- 面包屑 --> <!-- 面包屑 -->
<div class="breadcrumb"> <div class="breadcrumb">
<span class="breadcrumb-separator"></span> <span class="breadcrumb-side"></span>
<div class="custom-breadcrumb"> <div class="custom-breadcrumb">
<span v-for="(item, index) in breadcrumbItems" :key="index" class="breadcrumb-item" <span v-for="(item, index) in breadcrumbItems" :key="index" class="breadcrumb-item" :class="{
:class="{ 'clickable': index < breadcrumbItems.length - 1, 'last-item': index === breadcrumbItems.length - 1 }" 'clickable': index < breadcrumbItems.length - 1,
@click="index < breadcrumbItems.length - 1 ? handleBreadcrumbClick(item.path) : null"> 'last-item': index === breadcrumbItems.length - 1,
'first-item': index === 0
}" @click="index < breadcrumbItems.length - 1 ? handleBreadcrumbClick(item.path) : null">
{{ item.title }} {{ item.title }}
<span v-if="index < breadcrumbItems.length - 1" class="breadcrumb-separator"> > </span> <span v-if="index < breadcrumbItems.length - 1 && index > 0" class="breadcrumb-separator"> > </span>
</span> </span>
</div> </div>
</div> </div>
@ -107,6 +109,7 @@ console.log(`当前屏幕宽度: ${width}px, 高度: ${height}px`);
const activeNavItem = ref(0); // 0: , 1: , 2: , 3: const activeNavItem = ref(0); // 0: , 1: , 2: , 3:
const activeSubNavItem = ref(''); // const activeSubNavItem = ref(''); //
const examMenuExpanded = ref(false); // const examMenuExpanded = ref(false); //
const showTopImage = ref(true); // /
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
@ -143,6 +146,12 @@ const handleBreadcrumbClick = (path: string) => {
router.push(path); router.push(path);
} }
//
const handleClose = () => {
console.log('关闭按钮被点击');
showTopImage.value = false; //
}
// //
const hideSidebar = computed(() => { const hideSidebar = computed(() => {
const currentPath = route.path const currentPath = route.path
@ -179,16 +188,6 @@ const breadcrumbItems = computed(() => {
path: `/teacher/course-editor/${courseId}` path: `/teacher/course-editor/${courseId}`
} }
); );
breadcrumbs.push(
{
title: '课件管理',
path: currentPath
},
{
title: `课程${courseId}`,
path: `/teacher/course-editor/${courseId}`
}
);
} else if (currentPath.includes('question-bank')) { } else if (currentPath.includes('question-bank')) {
breadcrumbs.push( breadcrumbs.push(
{ {
@ -200,16 +199,6 @@ const breadcrumbItems = computed(() => {
path: `/teacher/course-editor/${courseId}` path: `/teacher/course-editor/${courseId}`
} }
); );
breadcrumbs.push(
{
title: '题库管理',
path: currentPath
},
{
title: `课程${courseId}`,
path: `/teacher/course-editor/${courseId}`
}
);
} else if (currentPath.includes('add-question')) { } else if (currentPath.includes('add-question')) {
breadcrumbs.push( breadcrumbs.push(
{ {
@ -220,10 +209,6 @@ const breadcrumbItems = computed(() => {
title: `课程${courseId}`, title: `课程${courseId}`,
path: `/teacher/course-editor/${courseId}` path: `/teacher/course-editor/${courseId}`
}, },
{
title: `课程${courseId}`,
path: `/teacher/course-editor/${courseId}`
},
{ {
title: '新增试题', title: '新增试题',
path: currentPath path: currentPath
@ -240,14 +225,23 @@ const breadcrumbItems = computed(() => {
path: `/teacher/course-editor/${courseId}` path: `/teacher/course-editor/${courseId}`
} }
); );
} else if (currentPath.includes('template-import')) {
breadcrumbs.push( breadcrumbs.push(
{ {
title: '章节管理', title: '课程管理',
path: currentPath path: '/teacher/course-management'
}, },
{ {
title: `课程${courseId}`, title: `课程${courseId}`,
path: `/teacher/course-editor/${courseId}` path: `/teacher/course-editor/${courseId}`
},
{
title: '作业库',
path: `/teacher/course-editor/${courseId}/homework`
},
{
title: '导入',
path: currentPath
} }
); );
} else if (currentPath.includes('homework')) { } else if (currentPath.includes('homework')) {
@ -261,16 +255,6 @@ const breadcrumbItems = computed(() => {
path: `/teacher/course-editor/${courseId}` path: `/teacher/course-editor/${courseId}`
} }
); );
breadcrumbs.push(
{
title: '作业管理',
path: currentPath
},
{
title: `课程${courseId}`,
path: `/teacher/course-editor/${courseId}`
}
);
} else if (currentPath.includes('practice')) { } else if (currentPath.includes('practice')) {
breadcrumbs.push( breadcrumbs.push(
{ {
@ -303,16 +287,6 @@ const breadcrumbItems = computed(() => {
path: `/teacher/course-editor/${courseId}` path: `/teacher/course-editor/${courseId}`
} }
); );
breadcrumbs.push(
{
title: '证书管理',
path: currentPath
},
{
title: `课程${courseId}`,
path: `/teacher/course-editor/${courseId}`
}
);
} else if (currentPath.includes('discussion')) { } else if (currentPath.includes('discussion')) {
breadcrumbs.push( breadcrumbs.push(
{ {
@ -324,16 +298,6 @@ const breadcrumbItems = computed(() => {
path: `/teacher/course-editor/${courseId}` path: `/teacher/course-editor/${courseId}`
} }
); );
breadcrumbs.push(
{
title: '讨论管理',
path: currentPath
},
{
title: `课程${courseId}`,
path: `/teacher/course-editor/${courseId}`
}
);
} else if (currentPath.includes('statistics')) { } else if (currentPath.includes('statistics')) {
breadcrumbs.push( breadcrumbs.push(
{ {
@ -345,16 +309,6 @@ const breadcrumbItems = computed(() => {
path: `/teacher/course-editor/${courseId}` path: `/teacher/course-editor/${courseId}`
} }
); );
breadcrumbs.push(
{
title: '统计管理',
path: currentPath
},
{
title: `课程${courseId}`,
path: `/teacher/course-editor/${courseId}`
}
);
} else if (currentPath.includes('notification')) { } else if (currentPath.includes('notification')) {
breadcrumbs.push( breadcrumbs.push(
{ {
@ -366,16 +320,6 @@ const breadcrumbItems = computed(() => {
path: `/teacher/course-editor/${courseId}` path: `/teacher/course-editor/${courseId}`
} }
); );
breadcrumbs.push(
{
title: '通知管理',
path: currentPath
},
{
title: `课程${courseId}`,
path: `/teacher/course-editor/${courseId}`
}
);
} else if (currentPath.includes('management')) { } else if (currentPath.includes('management')) {
breadcrumbs.push( breadcrumbs.push(
{ {
@ -387,16 +331,6 @@ const breadcrumbItems = computed(() => {
path: `/teacher/course-editor/${courseId}` path: `/teacher/course-editor/${courseId}`
} }
); );
breadcrumbs.push(
{
title: '综合管理',
path: currentPath
},
{
title: `课程${courseId}`,
path: `/teacher/course-editor/${courseId}`
}
);
} }
console.log('课程编辑器页面面包屑:', breadcrumbs); console.log('课程编辑器页面面包屑:', breadcrumbs);
@ -433,36 +367,6 @@ const breadcrumbItems = computed(() => {
return breadcrumbs; return breadcrumbs;
} }
// >>>>
if (currentPath.includes('chapter-editor-teacher')) {
const courseId = route.params.courseId;
let breadcrumbs = [
{
title: '课程管理',
path: '/teacher/course-management'
},
{
title: '课程管理',
path: '/teacher/course-management'
},
{
title: `课程${courseId}`,
path: `/teacher/course-editor/${courseId}`
},
{
title: '章节',
path: `/teacher/course-editor/${courseId}/chapters`
},
{
title: '章节名称',
path: currentPath
}
];
console.log('章节编辑页面面包屑:', breadcrumbs);
return breadcrumbs;
}
// //
const matchedRoutes = route.matched; const matchedRoutes = route.matched;
let breadcrumbs = matchedRoutes let breadcrumbs = matchedRoutes
@ -523,6 +427,29 @@ const updateActiveNavItem = () => {
overflow: hidden; overflow: hidden;
} }
/* 关闭按钮样式 */
.close-button {
position: absolute;
top: 0;
right: 15px;
width: 30px;
height: 20px;
background-color: #7192DC;
color: white;
border: none;
font-size: 10px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
z-index: 10;
transition: background-color 0.3s ease;
}
.close-button:hover {
background-color: #999999;
}
/* 展开图标样式 */ /* 展开图标样式 */
.expand-icon { .expand-icon {
margin-left: auto; margin-left: auto;
@ -828,6 +755,13 @@ const updateActiveNavItem = () => {
margin-right: 10px; margin-right: 10px;
} }
.breadcrumb-side {
width: 4px;
height: 17px;
background-color: #0288D1;
margin-right: 4px;
}
@media screen and (max-width: 480px) { @media screen and (max-width: 480px) {
.nav-container .nav-item { .nav-container .nav-item {
@ -876,6 +810,12 @@ const updateActiveNavItem = () => {
text-decoration: none; text-decoration: none;
} }
.breadcrumb-item.first-item {
font-size: 16px;
font-weight: 500;
color: #333;
}
.breadcrumb-separator { .breadcrumb-separator {
color: #666; color: #666;
margin: 0 4px; margin: 0 4px;

View File

@ -0,0 +1,654 @@
<template>
<div class="add-homework-container">
<div class="form-container">
<!-- 表单内容 -->
<div class="form-content">
<!-- 上半部分两列布局 -->
<div class="form-row">
<!-- 左列 -->
<div class="form-column">
<!-- 作业名称 -->
<div class="form-item">
<label class="form-label required">作业名称:</label>
<n-input
v-model:value="formData.name"
placeholder="请输入作业名称"
class="form-input"
/>
</div>
<!-- 绑定班级 -->
<div class="form-item">
<label class="form-label required">绑定班级:</label>
<n-select
v-model:value="formData.boundClass"
:options="classOptions"
placeholder="请选择班级"
class="form-input"
/>
</div>
<!-- 作业开始时间 -->
<div class="form-item">
<label class="form-label required">作业开始时间:</label>
<n-date-picker
v-model:value="formData.startTime"
type="datetime"
placeholder="选择时间"
class="form-input"
/>
</div>
<!-- 允许作业补交 -->
<div class="form-item">
<label class="form-label required">允许作业补交:</label>
<div class="toggle-container">
<n-switch
v-model:value="formData.allowLateSubmission"
class="form-toggle"
/>
<span class="toggle-label">允许补交</span>
</div>
</div>
<!-- 补交时间选择器 -->
<div class="form-item" v-if="formData.allowLateSubmission">
<n-date-picker
v-model:value="formData.lateSubmissionTime"
type="datetime"
placeholder="请选择补交时间"
class="form-input"
/>
</div>
</div>
<!-- 右列 -->
<div class="form-column">
<!-- 所属章节 -->
<div class="form-item">
<label class="form-label required">所属章节:</label>
<n-select
v-model:value="formData.chapter"
:options="chapterOptions"
placeholder="请选择所属章节"
class="form-input"
/>
</div>
<!-- 创建人 -->
<div class="form-item">
<label class="form-label required">创建人:</label>
<n-select
v-model:value="formData.creator"
multiple
:options="creatorOptions"
placeholder="请选择创建人"
class="form-input"
/>
</div>
<!-- 作业结束时间 -->
<div class="form-item">
<label class="form-label required">作业结束时间:</label>
<n-date-picker
v-model:value="formData.endTime"
type="datetime"
placeholder="选择时间"
class="form-input"
/>
</div>
</div>
</div>
<!-- 中间部分富文本编辑器 -->
<div class="form-text">
<label class="form-label required">作业内容:</label>
<div class="rich-editor-container">
<div class="editor-container">
<Toolbar
style="border-bottom: 1px solid #ccc"
:editor="editorRef"
:defaultConfig="toolbarConfig"
:mode="mode"
/>
<Editor
style="height: 300px; overflow-y: hidden;"
v-model="formData.content"
:defaultConfig="editorConfig"
:mode="mode"
@onCreated="handleCreated"
/>
</div>
</div>
</div>
<!-- 下半部分设置选项 -->
<div class="form-section">
<!-- 积分设置 -->
<div class="form-item form-integral">
<label class="form-label required">积分设置</label>
<div class="setting-container">
<n-switch
v-model:value="formData.enableScore"
class="form-toggle"
/>
<span class="setting-label">提交可获得</span>
<n-input-number
v-model:value="formData.score"
:min="0"
class="score-input"
:show-button="false"
/>
<span class="setting-label">积分</span>
</div>
</div>
<!-- 督促设置 -->
<div class="form-item">
<label class="form-label required">督促设置</label>
<div class="setting-container">
<n-switch
v-model:value="formData.enableReminder"
class="form-toggle"
/>
<span class="setting-label">作业结束前</span>
<n-input-number
v-model:value="formData.reminderHours"
:min="0"
class="reminder-input"
:show-button="false"
/>
<span class="setting-label">小时发通知提醒未交学生</span>
</div>
</div>
</div>
</div>
<!-- 底部按钮 -->
<div class="form-footer">
<n-button class="cancel-btn" @click="handleCancel">取消</n-button>
<n-button type="primary" class="save-btn" @click="handleSave">{{ isEditMode ? '更新' : '保存' }}</n-button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { reactive, ref, shallowRef, onBeforeUnmount, onMounted, computed } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import {
NInput,
NDatePicker,
NSelect,
NSwitch,
NButton,
NIcon,
NInputNumber,
NDropdown
} from 'naive-ui'
import '@wangeditor/editor/dist/css/style.css'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
const router = useRouter()
const route = useRoute()
//
const isEditMode = computed(() => route.query.mode === 'edit')
const homeworkId = computed(() => route.query.id as string)
// shallowRef
const editorRef = shallowRef()
// HTML
const valueHtml = ref('<p>hello</p>')
// ajax
onMounted(() => {
if (isEditMode.value && homeworkId.value) {
//
loadHomeworkData(homeworkId.value)
} else {
//
setTimeout(() => {
valueHtml.value = '<p>模拟 Ajax 异步设置内容</p>'
}, 1500)
}
})
//
const loadHomeworkData = async (id: string) => {
try {
// API
// API
const mockData = {
name: '示例作业',
boundClass: 'class1',
startTime: '2024-01-01 00:00:00',
endTime: '2024-01-31 23:59:59',
allowLateSubmission: true,
lateSubmissionTime: '2024-02-07 23:59:59',
chapter: 'chapter1',
creator: ['liqinglin', 'zhangsan'],
content: '<p>这是示例作业内容,包含<strong>粗体文字</strong>和<em>斜体文字</em>。</p><p>第二段内容:</p><ul><li>列表项1</li><li>列表项2</li><li>列表项3</li></ul>',
enableScore: true,
score: 10,
enableReminder: true,
reminderHours: 24
}
//
Object.assign(formData, mockData)
valueHtml.value = mockData.content
console.log('作业数据加载成功:', mockData)
} catch (error) {
console.error('加载作业数据失败:', error)
}
}
const toolbarConfig = {}
const editorConfig = { placeholder: '请输入内容...' }
const mode = 'default'
//
onBeforeUnmount(() => {
const editor = editorRef.value
if (editor == null) return
editor.destroy()
})
const handleCreated = (editor: any) => {
editorRef.value = editor // editor
}
//
const formData = reactive({
name: '',
boundClass: null,
startTime: null,
endTime: null,
allowLateSubmission: true,
lateSubmissionTime: null,
chapter: null,
creator: [],
content: '',
enableScore: true,
score: 0,
enableReminder: true,
reminderHours: 0
})
//
const chapterOptions = [
{ label: '第一章 课程介绍', value: 'chapter1' },
{ label: '第二章 基础知识', value: 'chapter2' },
{ label: '第三章 进阶内容', value: 'chapter3' }
]
//
const classOptions = [
{ label: '班级一', value: 'class1' },
{ label: '班级二', value: 'class2' },
{ label: '班级三', value: 'class3' },
{ label: '班级四', value: 'class4' }
]
//
const creatorOptions = [
{ label: '李清林', value: 'liqinglin' },
{ label: '张三', value: 'zhangsan' },
{ label: '李四', value: 'lisi' },
{ label: '王五', value: 'wangwu' },
{ label: '赵六', value: 'zhaoliu' },
{ label: '孙七', value: 'sunqi' },
{ label: '周八', value: 'zhouba' },
{ label: '吴九', value: 'wujiu' },
{ label: '郑十', value: 'zhengshi' }
]
//
const handleCancel = () => {
router.back()
}
//
const handleSave = () => {
if (isEditMode.value) {
console.log('更新作业数据:', formData)
//
} else {
console.log('保存作业数据:', formData)
//
}
router.back()
}
</script>
<style scoped>
.add-homework-container {
min-height: 100vh;
padding-bottom: 80px;
}
.form-container {
background: white;
overflow: hidden;
}
.form-content {
padding: 24px 24px 0 24px;
}
.form-row {
display: flex;
gap: 160px;
margin-bottom: 32px;
}
.form-column {
flex: 1;
display: flex;
flex-direction: column;
gap: 20px;
}
.form-item {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-end;
gap: 10px;
}
.form-text {
display: flex;
flex-direction: row;
justify-content: flex-end;
gap: 10px;
}
.form-integral {
margin-top: 20px;
margin-bottom: 20px;
}
.form-label {
font-size: 14px;
color: #333;
font-weight: 500;
min-width: 100px;
flex-shrink: 0;
text-align: right;
}
.form-label.required::before {
content: '*';
color: #ff4d4f;
margin-right: 4px;
}
.form-input {
flex: 1;
min-width: 0;
}
/* 最简单的输入框高度统一方法 */
.form-input {
height: 42px;
}
/* 强制设置下拉菜单高度 */
.form-input :deep(.n-base-selection) {
--n-height: 42px !important;
height: 42px !important;
}
.form-input :deep(.n-base-selection-label) {
height: 42px !important;
line-height: 42px !important;
}
/* 强制设置时间选择器高度 */
.form-input :deep(.n-input__input) {
height: 42px !important;
}
.form-input :deep(.n-input__input-el) {
height: 42px !important;
line-height: 42px !important;
}
/* 隐藏下拉菜单的加载状态和清除按钮 */
.form-input :deep(.n-base-loading),
.form-input :deep(.n-base-clear) {
display: none !important;
}
/* 隐藏默认下拉箭头 */
.form-input :deep(.n-base-suffix__arrow) {
display: none !important;
}
/* 为所属章节和创建人下拉菜单添加自定义箭头 */
.form-column:last-child .form-item:nth-child(1) .form-input :deep(.n-base-selection),
.form-column:last-child .form-item:nth-child(2) .form-input :deep(.n-base-selection) {
position: relative;
}
.form-column:last-child .form-item:nth-child(1) .form-input :deep(.n-base-selection)::after,
.form-column:last-child .form-item:nth-child(2) .form-input :deep(.n-base-selection)::after {
content: '';
position: absolute;
right: 14px;
top: 50%;
transform: translateY(-50%);
width: 13px;
height: 8px;
background-image: url('/images/teacher/箭头-灰.png');
background-size: contain;
background-repeat: no-repeat;
background-position: center;
pointer-events: none;
z-index: 1;
}
/* 备用选择器 */
.form-column:last-child .form-item:nth-child(1) .form-input :deep(.n-base-selection-input),
.form-column:last-child .form-item:nth-child(2) .form-input :deep(.n-base-selection-input) {
position: relative;
}
.form-column:last-child .form-item:nth-child(1) .form-input :deep(.n-base-selection-input)::after,
.form-column:last-child .form-item:nth-child(2) .form-input :deep(.n-base-selection-input)::after {
content: '';
position: absolute;
right: 8px;
top: 50%;
transform: translateY(-50%);
width: 16px;
height: 16px;
background-image: url('/images/teacher/箭头-灰.png');
background-size: contain;
background-repeat: no-repeat;
background-position: center;
pointer-events: none;
z-index: 1;
}
/* 多选标签样式调整 */
.form-input :deep(.n-tag) {
background-color: #F5F8FB !important;
border: none !important;
color: #666666 !important;
margin-top: 3px;
margin-bottom: 3px;
}
.form-input :deep(.n-tag__content) {
color: #666666 !important;
}
.form-input :deep(.n-tag__border) {
display: none !important;
}
/* 关闭按钮样式调整 */
.form-input :deep(.n-tag__close) {
width: 12px !important;
height: 12px !important;
}
.form-input :deep(.n-tag__close .n-base-icon) {
width: 12px !important;
height: 12px !important;
color: #999 !important;
}
.form-input :deep(.n-tag__close svg) {
width: 12px !important;
height: 12px !important;
}
.form-toggle {
margin-right: 8px;
}
.toggle-container {
display: flex;
align-items: center;
gap: 8px;
flex: 1;
}
.toggle-label {
font-size: 14px;
color: #666;
}
/* 补交时间选择器样式 */
.form-item:has(.n-date-picker[placeholder="请选择补交时间"]) {
padding-left: 100px; /* 占用标签的空间位置 */
}
.form-item:has(.n-date-picker[placeholder="请选择补交时间"]) .form-input {
width: calc(100% - 100px); /* 减去左边距,保持与其他输入框相同宽度 */
}
/* 自定义时间选择器图标 */
.form-input :deep(.n-date-picker-icon svg) {
display: none !important;
}
.form-input :deep(.n-date-picker-icon) {
background-image: url('/images/teacher/日历.png') !important;
background-size: contain !important;
background-repeat: no-repeat !important;
background-position: center !important;
width: 14px !important;
height: 14px !important;
}
.form-section {
margin-bottom: 32px;
}
.rich-editor-container {
flex: 1;
border: 1px solid #D8D8D8;
overflow: hidden;
}
.setting-container {
display: flex;
align-items: center;
gap: 12px;
flex: 1;
}
.setting-label {
font-size: 14px;
color: #666;
}
.score-input,
.reminder-input {
width: 80px;
}
.form-footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
display: flex;
justify-content: flex-end;
gap: 12px;
padding: 20px 24px;
background: #fff;
border-top: 1px solid #e6e6e6;
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1);
z-index: 1000;
}
.cancel-btn {
min-width: 60px;
height: 32px;
border: 1px solid #0288D1;
background: #E2F5FF;
color: #0288D1;
}
.cancel-btn:hover {
border-color: #0277BD;
background: #B3E5FC;
color: #0277BD;
}
.save-btn {
min-width: 60px;
height: 32px;
background: #0288D1;
border-color: #0288D1;
color: white;
}
.save-btn:hover {
background: #0277BD;
border-color: #0277BD;
}
/* 响应式设计 */
@media (max-width: 768px) {
.form-row {
flex-direction: column;
gap: 16px;
}
.form-content {
padding: 16px;
}
.editor-toolbar {
flex-direction: column;
align-items: flex-start;
gap: 12px;
}
.toolbar-group {
border-right: none;
border-bottom: 1px solid #e6e6e6;
padding-bottom: 8px;
width: 100%;
}
.toolbar-group:last-child {
border-bottom: none;
}
}
</style>

View File

@ -19,7 +19,7 @@
<div class="menu-header" @click="toggleHomework"> <div class="menu-header" @click="toggleHomework">
<img src="/images/teacher/作业.png" alt="作业" /> <img src="/images/teacher/作业.png" alt="作业" />
<span>作业</span> <span>作业</span>
<i class="n-base-icon" :class="{ expanded: homeworkExpanded }"> <i class="n-base-icon" :class="{ expanded: homeworkExpanded || shouldExpandHomework }">
<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path <path
d="M5.64645 3.14645C5.45118 3.34171 5.45118 3.65829 5.64645 3.85355L9.79289 8L5.64645 12.1464C5.45118 12.3417 5.45118 12.6583 5.64645 12.8536C5.84171 13.0488 6.15829 13.0488 6.35355 12.8536L10.8536 8.35355C11.0488 8.15829 11.0488 7.84171 10.8536 7.64645L6.35355 3.14645C6.15829 2.95118 5.84171 2.95118 5.64645 3.14645Z" d="M5.64645 3.14645C5.45118 3.34171 5.45118 3.65829 5.64645 3.85355L9.79289 8L5.64645 12.1464C5.45118 12.3417 5.45118 12.6583 5.64645 12.8536C5.84171 13.0488 6.15829 13.0488 6.35355 12.8536L10.8536 8.35355C11.0488 8.15829 11.0488 7.84171 10.8536 7.64645L6.35355 3.14645C6.15829 2.95118 5.84171 2.95118 5.64645 3.14645Z"
@ -27,9 +27,9 @@
</svg> </svg>
</i> </i>
</div> </div>
<div class="submenu" v-show="homeworkExpanded"> <div class="submenu" v-show="homeworkExpanded || shouldExpandHomework">
<router-link :to="`/teacher/course-editor/${courseId}/homework/library`" class="submenu-item" <router-link :to="`/teacher/course-editor/${courseId}/homework/library`" class="submenu-item"
:class="{ active: $route.path.includes('/homework/library') }"> :class="{ active: $route.path.includes('/homework/library') || $route.path.includes('/homework/add-homework') }">
<span>作业库</span> <span>作业库</span>
</router-link> </router-link>
<router-link :to="`/teacher/course-editor/${courseId}/homework/review`" class="submenu-item" <router-link :to="`/teacher/course-editor/${courseId}/homework/review`" class="submenu-item"
@ -120,6 +120,11 @@ const courseId = route.params.id
// //
const homeworkExpanded = ref(false) const homeworkExpanded = ref(false)
//
const shouldExpandHomework = computed(() => {
return route.path.includes('/homework/')
})
// / // /
const toggleHomework = () => { const toggleHomework = () => {
homeworkExpanded.value = !homeworkExpanded.value homeworkExpanded.value = !homeworkExpanded.value
@ -139,10 +144,8 @@ const hideSidebar = computed(() => {
// //
const hideSidebarPaths = [ const hideSidebarPaths = [
'add-question', // 'add-question', //
'edit-question', // 'add-homework', //
'question-preview', // 'template-import'
'bulk-import', //
'question-analysis' //
] ]
// //
@ -276,19 +279,18 @@ const hideSidebar = computed(() => {
} }
.submenu { .submenu {
margin-left: 30px;
margin-bottom: 5px;
} }
.submenu-item { .submenu-item {
display: block; display: block;
padding: 8px 15px; padding: 12px 15px;
margin-bottom: 3px; margin-bottom: 3px;
text-decoration: none; text-decoration: none;
color: #666; color: #666;
font-size: 14px; font-size: 14px;
border-radius: 3px; border-radius: 3px;
transition: all 0.3s ease; transition: all 0.3s ease;
text-align: center;
} }
.submenu-item:hover { .submenu-item:hover {

View File

@ -232,7 +232,7 @@ const filteredFiles = computed(() => {
// //
const getFileIcon = (type: string) => { const getFileIcon = (type: string) => {
const iconMap: { [key: string]: string } = { const iconMap: { [key: string]: string } = {
folder: '/images/activity/file.png', folder: '/images/profile/folder.png',
excel: '/images/activity/xls.png', excel: '/images/activity/xls.png',
word: '/images/activity/wrod.png', word: '/images/activity/wrod.png',
pdf: '/images/activity/pdf.png', pdf: '/images/activity/pdf.png',

View File

@ -3,8 +3,8 @@
<div class="toolbar"> <div class="toolbar">
<h2>作业库</h2> <h2>作业库</h2>
<div class="toolbar-actions"> <div class="toolbar-actions">
<button class="btn btn-primary">添加作业</button> <button class="btn btn-primary" @click="handleAddHomework">添加作业</button>
<button class="btn btn-new">导入</button> <button class="btn btn-new" @click="handleImport">导入</button>
<button class="btn btn-new">导出</button> <button class="btn btn-new">导出</button>
<button class="btn btn-danger">删除</button> <button class="btn btn-danger">删除</button>
<div class="search-box"> <div class="search-box">
@ -63,6 +63,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, h, computed, onMounted, onUnmounted } from 'vue' import { ref, h, computed, onMounted, onUnmounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { NButton, NDropdown, NDataTable, NConfigProvider, zhCN, dateZhCN } from 'naive-ui' import { NButton, NDropdown, NDataTable, NConfigProvider, zhCN, dateZhCN } from 'naive-ui'
import type { DataTableColumns } from 'naive-ui' import type { DataTableColumns } from 'naive-ui'
@ -77,6 +78,10 @@ interface HomeworkItem {
isTop: boolean isTop: boolean
} }
//
const router = useRouter()
const route = useRoute()
// //
const selectedHomework = ref<number[]>([]) const selectedHomework = ref<number[]>([])
@ -392,6 +397,14 @@ const columns = computed((): DataTableColumns<HomeworkItem> => [
// //
const editHomework = (id: number) => { const editHomework = (id: number) => {
console.log('编辑作业:', id) console.log('编辑作业:', id)
// ID
router.push({
path: `/teacher/course-editor/${route.params.id}/homework/add-homework`,
query: {
mode: 'edit',
id: id.toString()
}
})
} }
// //
@ -439,6 +452,16 @@ const toggleTop = (homework: HomeworkItem) => {
console.log('已取消置顶作业:', homework.id) console.log('已取消置顶作业:', homework.id)
} }
} }
const handleAddHomework = () => {
//
router.push(`/teacher/course-editor/${route.params.id}/homework/add-homework`)
}
const handleImport = () => {
//
router.push(`/teacher/course-editor/${route.params.id}/homework/template-import`)
}
</script> </script>
<style scoped> <style scoped>

View File

@ -0,0 +1,298 @@
<template>
<div class="homework-template-import">
<!-- 消息提示组件 -->
<MessageComponent ref="messageRef" />
<!-- 操作按钮区域 -->
<div class="action-buttons">
<button class="btn btn-primary" @click="startImport">
导入
</button>
<button class="btn btn-secondary" @click="downloadTemplate">
下载模板
</button>
</div>
<!-- 文件列表区域 -->
<div class="file-list-section">
<div class="file-item">
<img src="/images/teacher/template.png" alt="template icon" class="file-icon">
<span class="file-name">作业批量导入模板.xlsx</span>
<button class="delete-btn" @click="removeFile">
<img src="/images/teacher/删除.png" alt="delete icon" class="delete-icon-img">
</button>
</div>
<div class="file-item">
<img src="/images/teacher/template.png" alt="file icon" class="file-icon">
<span class="file-name">作业批量导入.xlsx</span>
<button class="delete-btn" @click="removeFile">
<img src="/images/teacher/删除.png" alt="delete icon" class="delete-icon-img">
</button>
</div>
</div>
<!-- 隐藏的文件上传输入 -->
<input
ref="fileInput"
type="file"
accept=".xlsx,.xls"
@change="handleFileSelect"
style="display: none;"
/>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import MessageComponent from '@/components/MessageComponent.vue'
const router = useRouter()
const fileInput = ref<HTMLInputElement>()
const messageRef = ref<InstanceType<typeof MessageComponent>>()
//
const uploadedFile = ref<File | null>(null)
//
const downloadTemplate = () => {
// Excel
const templateData = [
['作业名称*', '所属章节*', '作业类型*', '截止时间', '允许补交', '作业描述'],
['示例作业1', '第一章 绪论', '个人作业', '2024-01-15', '是', '请完成第一章的课后习题'],
['示例作业2', '第二章 基础理论', '小组作业', '2024-01-20', '否', '小组讨论并提交报告']
]
// CSV
const csvContent = templateData.map(row => row.join(',')).join('\n')
const blob = new Blob(['\ufeff' + csvContent], { type: 'text/csv;charset=utf-8;' })
const link = document.createElement('a')
link.href = URL.createObjectURL(blob)
link.download = '作业批量导入模板.xlsx'
link.click()
}
//
const handleFileSelect = (event: Event) => {
const target = event.target as HTMLInputElement
if (target.files && target.files.length > 0) {
uploadedFile.value = target.files[0]
//
startImport()
}
}
//
const removeFile = () => {
uploadedFile.value = null
if (fileInput.value) {
fileInput.value.value = ''
}
}
//
const startImport = async () => {
if (!uploadedFile.value) {
//
fileInput.value?.click()
return
}
try {
//
//
setTimeout(() => {
//
messageRef.value?.show(`${uploadedFile.value?.name} 导入成功`, 'success')
//
uploadedFile.value = null
if (fileInput.value) {
fileInput.value.value = ''
}
}, 1000)
} catch (error) {
//
messageRef.value?.show(`${uploadedFile.value?.name} 导入失败,格式不支持`, 'error')
//
uploadedFile.value = null
if (fileInput.value) {
fileInput.value.value = ''
}
}
}
//
const testMessage = () => {
messageRef.value?.show('测试消息:作业批量导入.xlsx 导入成功', 'success')
}
</script>
<style scoped>
.homework-template-import {
margin: 0 auto;
min-height: 100vh;
background-color: #fff;
}
/* 面包屑导航样式 */
.breadcrumb {
display: flex;
align-items: center;
padding: 20px 0 0 20px;
}
.breadcrumb-separator {
width: 4px;
height: 16px;
background-color: #0C99DA;
margin-right: 8px;
}
.custom-breadcrumb {
display: flex;
align-items: center;
font-size: 14px;
}
.breadcrumb-item {
color: #666;
cursor: pointer;
transition: color 0.3s ease;
}
.breadcrumb-item.clickable:hover {
color: #0C99DA;
text-decoration: underline;
}
.breadcrumb-item.last-item {
color: #999;
cursor: default;
}
.breadcrumb-item.last-item:hover {
color: #999;
text-decoration: none;
}
/* 操作按钮区域 */
.action-buttons {
padding-top: 20px;
margin: 0 0 15px 0;
display: flex;
gap: 15px;
border-bottom: 1.5px solid #F5F7FA;
padding-bottom: 15px;
}
.btn {
padding: 6px 10px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: all 0.3s ease;
min-width: 80px;
}
.btn-primary {
margin-left: 30px;
background: #0288D1;
color: white;
}
.btn-primary:hover {
background: #0288D1;
}
.btn-secondary {
background: white;
color: #0288D1;
border: 1px solid #0288D1;
}
.btn-secondary:hover {
background: #f0f8ff;
}
/* 文件列表区域 */
.file-list-section {
width: fit-content;
max-width: 100%;
overflow: hidden;
padding: 0 0 0 30px;
}
.file-item {
display: flex;
align-items: center;
padding: 6px 16px;
transition: background-color 0.3s ease;
min-width: 215px;
}
.file-item:last-child {
border-bottom: none;
}
.file-item:hover {
background-color: #f5f5f5;
}
.file-item .delete-btn {
opacity: 0;
transition: opacity 0.3s ease;
}
.file-item:hover .delete-btn {
opacity: 1;
}
.file-icon {
width: 16px;
height: 16px;
margin-right: 4px;
object-fit: contain;
}
.file-name {
flex: 1;
font-size: 14px;
color: #333;
white-space: nowrap;
}
.delete-btn {
background: none;
border: none;
cursor: pointer;
padding: 6px;
border-radius: 4px;
transition: background 0.3s ease;
margin-left: 8px;
display: flex;
align-items: center;
justify-content: center;
}
.delete-btn:hover {
background: #f0f0f0;
}
.delete-icon-img {
width: 16px;
height: 16px;
object-fit: contain;
}
</style>