提交 bf03f0ee authored 作者: 王鹏飞's avatar 王鹏飞

chore: 修改创建课程页面

上级 a3c488f0
...@@ -81,6 +81,8 @@ ...@@ -81,6 +81,8 @@
"refThrottled": true, "refThrottled": true,
"refWithControl": true, "refWithControl": true,
"resolveComponent": true, "resolveComponent": true,
"resolveRef": true,
"resolveUnref": true,
"shallowReactive": true, "shallowReactive": true,
"shallowReadonly": true, "shallowReadonly": true,
"shallowRef": true, "shallowRef": true,
...@@ -108,6 +110,7 @@ ...@@ -108,6 +110,7 @@
"useAttrs": true, "useAttrs": true,
"useBase64": true, "useBase64": true,
"useBattery": true, "useBattery": true,
"useBluetooth": true,
"useBreakpoints": true, "useBreakpoints": true,
"useBroadcastChannel": true, "useBroadcastChannel": true,
"useBrowserLocation": true, "useBrowserLocation": true,
...@@ -146,6 +149,7 @@ ...@@ -146,6 +149,7 @@
"useEyeDropper": true, "useEyeDropper": true,
"useFavicon": true, "useFavicon": true,
"useFetch": true, "useFetch": true,
"useFileDialog": true,
"useFileSystemAccess": true, "useFileSystemAccess": true,
"useFocus": true, "useFocus": true,
"useFocusWithin": true, "useFocusWithin": true,
...@@ -154,6 +158,7 @@ ...@@ -154,6 +158,7 @@
"useGamepad": true, "useGamepad": true,
"useGeolocation": true, "useGeolocation": true,
"useIdle": true, "useIdle": true,
"useImage": true,
"useInfiniteScroll": true, "useInfiniteScroll": true,
"useIntersectionObserver": true, "useIntersectionObserver": true,
"useInterval": true, "useInterval": true,
...@@ -175,6 +180,7 @@ ...@@ -175,6 +180,7 @@
"useNavigatorLanguage": true, "useNavigatorLanguage": true,
"useNetwork": true, "useNetwork": true,
"useNow": true, "useNow": true,
"useObjectUrl": true,
"useOffsetPagination": true, "useOffsetPagination": true,
"useOnline": true, "useOnline": true,
"usePageLeave": true, "usePageLeave": true,
...@@ -200,12 +206,14 @@ ...@@ -200,12 +206,14 @@
"useSlots": true, "useSlots": true,
"useSpeechRecognition": true, "useSpeechRecognition": true,
"useSpeechSynthesis": true, "useSpeechSynthesis": true,
"useStepper": true,
"useStorage": true, "useStorage": true,
"useStorageAsync": true, "useStorageAsync": true,
"useStyleTag": true, "useStyleTag": true,
"useSwipe": true, "useSwipe": true,
"useTemplateRefsList": true, "useTemplateRefsList": true,
"useTextSelection": true, "useTextSelection": true,
"useTextareaAutosize": true,
"useThrottle": true, "useThrottle": true,
"useThrottleFn": true, "useThrottleFn": true,
"useThrottledRefHistory": true, "useThrottledRefHistory": true,
...@@ -232,6 +240,7 @@ ...@@ -232,6 +240,7 @@
"useWindowScroll": true, "useWindowScroll": true,
"useWindowSize": true, "useWindowSize": true,
"watch": true, "watch": true,
"watchArray": true,
"watchAtMost": true, "watchAtMost": true,
"watchDebounced": true, "watchDebounced": true,
"watchEffect": true, "watchEffect": true,
...@@ -241,6 +250,7 @@ ...@@ -241,6 +250,7 @@
"watchPostEffect": true, "watchPostEffect": true,
"watchSyncEffect": true, "watchSyncEffect": true,
"watchThrottled": true, "watchThrottled": true,
"watchTriggerable": true,
"watchWithFilter": true, "watchWithFilter": true,
"whenever": true "whenever": true
} }
......
...@@ -82,6 +82,8 @@ declare global { ...@@ -82,6 +82,8 @@ declare global {
const refThrottled: typeof import('@vueuse/core')['refThrottled'] const refThrottled: typeof import('@vueuse/core')['refThrottled']
const refWithControl: typeof import('@vueuse/core')['refWithControl'] const refWithControl: typeof import('@vueuse/core')['refWithControl']
const resolveComponent: typeof import('vue')['resolveComponent'] const resolveComponent: typeof import('vue')['resolveComponent']
const resolveRef: typeof import('@vueuse/core')['resolveRef']
const resolveUnref: typeof import('@vueuse/core')['resolveUnref']
const shallowReactive: typeof import('vue')['shallowReactive'] const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly'] const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef'] const shallowRef: typeof import('vue')['shallowRef']
...@@ -109,6 +111,7 @@ declare global { ...@@ -109,6 +111,7 @@ declare global {
const useAttrs: typeof import('vue')['useAttrs'] const useAttrs: typeof import('vue')['useAttrs']
const useBase64: typeof import('@vueuse/core')['useBase64'] const useBase64: typeof import('@vueuse/core')['useBase64']
const useBattery: typeof import('@vueuse/core')['useBattery'] const useBattery: typeof import('@vueuse/core')['useBattery']
const useBluetooth: typeof import('@vueuse/core')['useBluetooth']
const useBreakpoints: typeof import('@vueuse/core')['useBreakpoints'] const useBreakpoints: typeof import('@vueuse/core')['useBreakpoints']
const useBroadcastChannel: typeof import('@vueuse/core')['useBroadcastChannel'] const useBroadcastChannel: typeof import('@vueuse/core')['useBroadcastChannel']
const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation'] const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation']
...@@ -147,6 +150,7 @@ declare global { ...@@ -147,6 +150,7 @@ declare global {
const useEyeDropper: typeof import('@vueuse/core')['useEyeDropper'] const useEyeDropper: typeof import('@vueuse/core')['useEyeDropper']
const useFavicon: typeof import('@vueuse/core')['useFavicon'] const useFavicon: typeof import('@vueuse/core')['useFavicon']
const useFetch: typeof import('@vueuse/core')['useFetch'] const useFetch: typeof import('@vueuse/core')['useFetch']
const useFileDialog: typeof import('@vueuse/core')['useFileDialog']
const useFileSystemAccess: typeof import('@vueuse/core')['useFileSystemAccess'] const useFileSystemAccess: typeof import('@vueuse/core')['useFileSystemAccess']
const useFocus: typeof import('@vueuse/core')['useFocus'] const useFocus: typeof import('@vueuse/core')['useFocus']
const useFocusWithin: typeof import('@vueuse/core')['useFocusWithin'] const useFocusWithin: typeof import('@vueuse/core')['useFocusWithin']
...@@ -155,6 +159,7 @@ declare global { ...@@ -155,6 +159,7 @@ declare global {
const useGamepad: typeof import('@vueuse/core')['useGamepad'] const useGamepad: typeof import('@vueuse/core')['useGamepad']
const useGeolocation: typeof import('@vueuse/core')['useGeolocation'] const useGeolocation: typeof import('@vueuse/core')['useGeolocation']
const useIdle: typeof import('@vueuse/core')['useIdle'] const useIdle: typeof import('@vueuse/core')['useIdle']
const useImage: typeof import('@vueuse/core')['useImage']
const useInfiniteScroll: typeof import('@vueuse/core')['useInfiniteScroll'] const useInfiniteScroll: typeof import('@vueuse/core')['useInfiniteScroll']
const useIntersectionObserver: typeof import('@vueuse/core')['useIntersectionObserver'] const useIntersectionObserver: typeof import('@vueuse/core')['useIntersectionObserver']
const useInterval: typeof import('@vueuse/core')['useInterval'] const useInterval: typeof import('@vueuse/core')['useInterval']
...@@ -176,6 +181,7 @@ declare global { ...@@ -176,6 +181,7 @@ declare global {
const useNavigatorLanguage: typeof import('@vueuse/core')['useNavigatorLanguage'] const useNavigatorLanguage: typeof import('@vueuse/core')['useNavigatorLanguage']
const useNetwork: typeof import('@vueuse/core')['useNetwork'] const useNetwork: typeof import('@vueuse/core')['useNetwork']
const useNow: typeof import('@vueuse/core')['useNow'] const useNow: typeof import('@vueuse/core')['useNow']
const useObjectUrl: typeof import('@vueuse/core')['useObjectUrl']
const useOffsetPagination: typeof import('@vueuse/core')['useOffsetPagination'] const useOffsetPagination: typeof import('@vueuse/core')['useOffsetPagination']
const useOnline: typeof import('@vueuse/core')['useOnline'] const useOnline: typeof import('@vueuse/core')['useOnline']
const usePageLeave: typeof import('@vueuse/core')['usePageLeave'] const usePageLeave: typeof import('@vueuse/core')['usePageLeave']
...@@ -201,12 +207,14 @@ declare global { ...@@ -201,12 +207,14 @@ declare global {
const useSlots: typeof import('vue')['useSlots'] const useSlots: typeof import('vue')['useSlots']
const useSpeechRecognition: typeof import('@vueuse/core')['useSpeechRecognition'] const useSpeechRecognition: typeof import('@vueuse/core')['useSpeechRecognition']
const useSpeechSynthesis: typeof import('@vueuse/core')['useSpeechSynthesis'] const useSpeechSynthesis: typeof import('@vueuse/core')['useSpeechSynthesis']
const useStepper: typeof import('@vueuse/core')['useStepper']
const useStorage: typeof import('@vueuse/core')['useStorage'] const useStorage: typeof import('@vueuse/core')['useStorage']
const useStorageAsync: typeof import('@vueuse/core')['useStorageAsync'] const useStorageAsync: typeof import('@vueuse/core')['useStorageAsync']
const useStyleTag: typeof import('@vueuse/core')['useStyleTag'] const useStyleTag: typeof import('@vueuse/core')['useStyleTag']
const useSwipe: typeof import('@vueuse/core')['useSwipe'] const useSwipe: typeof import('@vueuse/core')['useSwipe']
const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList'] const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList']
const useTextSelection: typeof import('@vueuse/core')['useTextSelection'] const useTextSelection: typeof import('@vueuse/core')['useTextSelection']
const useTextareaAutosize: typeof import('@vueuse/core')['useTextareaAutosize']
const useThrottle: typeof import('@vueuse/core')['useThrottle'] const useThrottle: typeof import('@vueuse/core')['useThrottle']
const useThrottleFn: typeof import('@vueuse/core')['useThrottleFn'] const useThrottleFn: typeof import('@vueuse/core')['useThrottleFn']
const useThrottledRefHistory: typeof import('@vueuse/core')['useThrottledRefHistory'] const useThrottledRefHistory: typeof import('@vueuse/core')['useThrottledRefHistory']
...@@ -233,6 +241,7 @@ declare global { ...@@ -233,6 +241,7 @@ declare global {
const useWindowScroll: typeof import('@vueuse/core')['useWindowScroll'] const useWindowScroll: typeof import('@vueuse/core')['useWindowScroll']
const useWindowSize: typeof import('@vueuse/core')['useWindowSize'] const useWindowSize: typeof import('@vueuse/core')['useWindowSize']
const watch: typeof import('vue')['watch'] const watch: typeof import('vue')['watch']
const watchArray: typeof import('@vueuse/core')['watchArray']
const watchAtMost: typeof import('@vueuse/core')['watchAtMost'] const watchAtMost: typeof import('@vueuse/core')['watchAtMost']
const watchDebounced: typeof import('@vueuse/core')['watchDebounced'] const watchDebounced: typeof import('@vueuse/core')['watchDebounced']
const watchEffect: typeof import('vue')['watchEffect'] const watchEffect: typeof import('vue')['watchEffect']
...@@ -242,6 +251,7 @@ declare global { ...@@ -242,6 +251,7 @@ declare global {
const watchPostEffect: typeof import('vue')['watchPostEffect'] const watchPostEffect: typeof import('vue')['watchPostEffect']
const watchSyncEffect: typeof import('vue')['watchSyncEffect'] const watchSyncEffect: typeof import('vue')['watchSyncEffect']
const watchThrottled: typeof import('@vueuse/core')['watchThrottled'] const watchThrottled: typeof import('@vueuse/core')['watchThrottled']
const watchTriggerable: typeof import('@vueuse/core')['watchTriggerable']
const watchWithFilter: typeof import('@vueuse/core')['watchWithFilter'] const watchWithFilter: typeof import('@vueuse/core')['watchWithFilter']
const whenever: typeof import('@vueuse/core')['whenever'] const whenever: typeof import('@vueuse/core')['whenever']
} }
...@@ -12,8 +12,10 @@ ...@@ -12,8 +12,10 @@
"@tinymce/tinymce-vue": "^5.0.0", "@tinymce/tinymce-vue": "^5.0.0",
"axios": "^0.27.2", "axios": "^0.27.2",
"blueimp-md5": "^2.19.0", "blueimp-md5": "^2.19.0",
"dayjs": "^1.11.3",
"echarts": "^5.3.2", "echarts": "^5.3.2",
"element-plus": "^2.2.5", "element-plus": "^2.2.9",
"lodash-es": "^4.17.21",
"pinia": "^2.0.14", "pinia": "^2.0.14",
"qs": "^6.10.5", "qs": "^6.10.5",
"sortablejs": "^1.15.0", "sortablejs": "^1.15.0",
...@@ -188,9 +190,9 @@ ...@@ -188,9 +190,9 @@
} }
}, },
"node_modules/@element-plus/icons-vue": { "node_modules/@element-plus/icons-vue": {
"version": "2.0.5", "version": "2.0.6",
"resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.0.5.tgz", "resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.0.6.tgz",
"integrity": "sha512-jvNWyKcdvPvMDLTWjghrPY+bYHKqh7hbAFIPe+HWR073zilzt33csREzmKx3VwhdlJUW5u0nCqN+0rwI8jlH+w==", "integrity": "sha512-lPpG8hYkjL/Z97DH5Ei6w6o22Z4YdNglWCNYOPcB33JCF2A4wye6HFgSI7hEt9zdLyxlSpiqtgf9XcYU+m5mew==",
"peerDependencies": { "peerDependencies": {
"vue": "^3.2.0" "vue": "^3.2.0"
} }
...@@ -216,16 +218,16 @@ ...@@ -216,16 +218,16 @@
} }
}, },
"node_modules/@floating-ui/core": { "node_modules/@floating-ui/core": {
"version": "0.7.2", "version": "0.7.3",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.2.tgz", "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.3.tgz",
"integrity": "sha512-FRVAkSNU/vGXLIsgbggcs70GkXKEOXgBBbNpYPNHSaKsCAMMd00NrjbtKTesxkdv9xm9N3+XiDlcFGY6WnatBg==" "integrity": "sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg=="
}, },
"node_modules/@floating-ui/dom": { "node_modules/@floating-ui/dom": {
"version": "0.5.2", "version": "0.5.4",
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.2.tgz", "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.4.tgz",
"integrity": "sha512-z1DnEa7F3d8Fm/eXSbii8UEGpcjZGkQaYYUI0WpEVgD3vBfebDW8j/3ysusxonuMexoigA+A3b/fYH7sEqiwyg==", "integrity": "sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==",
"dependencies": { "dependencies": {
"@floating-ui/core": "^0.7.2" "@floating-ui/core": "^0.7.3"
} }
}, },
"node_modules/@humanwhocodes/config-array": { "node_modules/@humanwhocodes/config-array": {
...@@ -375,6 +377,11 @@ ...@@ -375,6 +377,11 @@
"integrity": "sha512-C3064MH72iEfeGCYEGCt7FCxXoAXaMPG0QPnstcxvPmbl54erpISu06d++FY37Smja64iWy5L8wOyHHBghWbJQ==", "integrity": "sha512-C3064MH72iEfeGCYEGCt7FCxXoAXaMPG0QPnstcxvPmbl54erpISu06d++FY37Smja64iWy5L8wOyHHBghWbJQ==",
"dev": true "dev": true
}, },
"node_modules/@types/web-bluetooth": {
"version": "0.0.14",
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.14.tgz",
"integrity": "sha512-5d2RhCard1nQUC3aHcq/gHzWYO6K0WJmAbjO7mQJgCQKtZpgXxv1rOM6O/dBDhDYYVutk1sciOgNSe+5YyfM8A=="
},
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
"version": "5.26.0", "version": "5.26.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.26.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.26.0.tgz",
...@@ -799,12 +806,13 @@ ...@@ -799,12 +806,13 @@
} }
}, },
"node_modules/@vueuse/core": { "node_modules/@vueuse/core": {
"version": "8.6.0", "version": "8.9.0",
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-8.6.0.tgz", "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-8.9.0.tgz",
"integrity": "sha512-VirzExCm/N+QdrEWT7J4uSrvJ5hquKIAU9alQ37kUvIJk9XxCLxmfRnmekYc1kz2+6BnoyuKYXVmrMV351CB4w==", "integrity": "sha512-eKWehF6gsiLYxnYM/1xgDu16bKED7AWvkk56JIFNQes8OKgktr3Jc1wUy8UWIulrnwCXICUu9YUo+Wkq4r2JNw==",
"dependencies": { "dependencies": {
"@vueuse/metadata": "8.6.0", "@types/web-bluetooth": "^0.0.14",
"@vueuse/shared": "8.6.0", "@vueuse/metadata": "8.9.0",
"@vueuse/shared": "8.9.0",
"vue-demi": "*" "vue-demi": "*"
}, },
"funding": { "funding": {
...@@ -824,9 +832,9 @@ ...@@ -824,9 +832,9 @@
} }
}, },
"node_modules/@vueuse/core/node_modules/@vueuse/shared": { "node_modules/@vueuse/core/node_modules/@vueuse/shared": {
"version": "8.6.0", "version": "8.9.0",
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-8.6.0.tgz", "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-8.9.0.tgz",
"integrity": "sha512-Y/IVywZo7IfEoSSEtCYpkVEmPV7pU35mEIxV7PbD/D3ly18B3mEsBaPbtDkNM/QP3zAZ5mn4nEkOfddX4uwuIA==", "integrity": "sha512-Pmu3Fopk/JJjN8b90uQuFrVCc/RPcSA/0zDFRTyn3YIhoB5ESna/1Sac5WZxK+n82g/ERXHHQTetGI9yxEdPfA==",
"dependencies": { "dependencies": {
"vue-demi": "*" "vue-demi": "*"
}, },
...@@ -847,9 +855,9 @@ ...@@ -847,9 +855,9 @@
} }
}, },
"node_modules/@vueuse/core/node_modules/vue-demi": { "node_modules/@vueuse/core/node_modules/vue-demi": {
"version": "0.13.1", "version": "0.13.2",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.1.tgz", "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.2.tgz",
"integrity": "sha512-xmkJ56koG3ptpLnpgmIzk9/4nFf4CqduSJbUM0OdPoU87NwRuZ6x49OLhjSa/fC15fV+5CbEnrxU4oyE022svg==", "integrity": "sha512-41ukrclEbMddAyP7PvxMSYqnOSzPV6r7GNnyTSKSCNTaz19GehxmTiXyP9kwHSUv2+Dr6hHqiUiF7L1VAw2KdQ==",
"hasInstallScript": true, "hasInstallScript": true,
"bin": { "bin": {
"vue-demi-fix": "bin/vue-demi-fix.js", "vue-demi-fix": "bin/vue-demi-fix.js",
...@@ -872,9 +880,9 @@ ...@@ -872,9 +880,9 @@
} }
}, },
"node_modules/@vueuse/metadata": { "node_modules/@vueuse/metadata": {
"version": "8.6.0", "version": "8.9.0",
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-8.6.0.tgz", "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-8.9.0.tgz",
"integrity": "sha512-F+CKPvaExsm7QgRr8y+ZNJFwXasn89rs5wth/HeX9lJ1q8XEt+HJ16Q5Sxh4rfG5YSKXrStveVge8TKvPjMjFA==", "integrity": "sha512-pjkIbQgJPRUrxK5/iXVKQFGC+OhJ+Vd6fhBsdwgj+NNJEHUotRliYymwdvhnEke/o+kkulT0xMvoK19nyPoiMw==",
"funding": { "funding": {
"url": "https://github.com/sponsors/antfu" "url": "https://github.com/sponsors/antfu"
} }
...@@ -1131,9 +1139,9 @@ ...@@ -1131,9 +1139,9 @@
"dev": true "dev": true
}, },
"node_modules/async-validator": { "node_modules/async-validator": {
"version": "4.1.1", "version": "4.2.5",
"resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.1.1.tgz", "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
"integrity": "sha512-p4DO/JXwjs8klJyJL8Q2oM4ks5fUTze/h5k10oPPKMiLe1fj3G1QMzPHNmN1Py4ycOk7WlO2DcGXv1qiESJCZA==" "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg=="
}, },
"node_modules/asynckit": { "node_modules/asynckit": {
"version": "0.4.0", "version": "0.4.0",
...@@ -1560,18 +1568,18 @@ ...@@ -1560,18 +1568,18 @@
"dev": true "dev": true
}, },
"node_modules/element-plus": { "node_modules/element-plus": {
"version": "2.2.5", "version": "2.2.9",
"resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.2.5.tgz", "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.2.9.tgz",
"integrity": "sha512-Kl0yn/PQca5YQo3M3NPBP4Xl71NQuMtDx5zNXZGVyl5FjdMujXiFB9SXKYGDUCgFU3d/Rl14vB4Fpmcl2Iz+Hw==", "integrity": "sha512-jYbL0JkCdv95rkT6trZJjCAizLPySa0qcd2cgq+57SKQnCZAcNDDq4GbTuFRnNavdoeCJnuM3HIficTIUpsMOQ==",
"dependencies": { "dependencies": {
"@ctrl/tinycolor": "^3.4.1", "@ctrl/tinycolor": "^3.4.1",
"@element-plus/icons-vue": "^2.0.5", "@element-plus/icons-vue": "^2.0.6",
"@floating-ui/dom": "^0.5.2", "@floating-ui/dom": "^0.5.4",
"@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7", "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7",
"@types/lodash": "^4.14.182", "@types/lodash": "^4.14.182",
"@types/lodash-es": "^4.17.6", "@types/lodash-es": "^4.17.6",
"@vueuse/core": "^8.6.0", "@vueuse/core": "^8.7.5",
"async-validator": "^4.1.1", "async-validator": "^4.2.5",
"dayjs": "^1.11.3", "dayjs": "^1.11.3",
"escape-html": "^1.0.3", "escape-html": "^1.0.3",
"lodash": "^4.17.21", "lodash": "^4.17.21",
...@@ -5096,9 +5104,9 @@ ...@@ -5096,9 +5104,9 @@
"integrity": "sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw==" "integrity": "sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw=="
}, },
"@element-plus/icons-vue": { "@element-plus/icons-vue": {
"version": "2.0.5", "version": "2.0.6",
"resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.0.5.tgz", "resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.0.6.tgz",
"integrity": "sha512-jvNWyKcdvPvMDLTWjghrPY+bYHKqh7hbAFIPe+HWR073zilzt33csREzmKx3VwhdlJUW5u0nCqN+0rwI8jlH+w==", "integrity": "sha512-lPpG8hYkjL/Z97DH5Ei6w6o22Z4YdNglWCNYOPcB33JCF2A4wye6HFgSI7hEt9zdLyxlSpiqtgf9XcYU+m5mew==",
"requires": {} "requires": {}
}, },
"@eslint/eslintrc": { "@eslint/eslintrc": {
...@@ -5119,16 +5127,16 @@ ...@@ -5119,16 +5127,16 @@
} }
}, },
"@floating-ui/core": { "@floating-ui/core": {
"version": "0.7.2", "version": "0.7.3",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.2.tgz", "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.3.tgz",
"integrity": "sha512-FRVAkSNU/vGXLIsgbggcs70GkXKEOXgBBbNpYPNHSaKsCAMMd00NrjbtKTesxkdv9xm9N3+XiDlcFGY6WnatBg==" "integrity": "sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg=="
}, },
"@floating-ui/dom": { "@floating-ui/dom": {
"version": "0.5.2", "version": "0.5.4",
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.2.tgz", "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.4.tgz",
"integrity": "sha512-z1DnEa7F3d8Fm/eXSbii8UEGpcjZGkQaYYUI0WpEVgD3vBfebDW8j/3ysusxonuMexoigA+A3b/fYH7sEqiwyg==", "integrity": "sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==",
"requires": { "requires": {
"@floating-ui/core": "^0.7.2" "@floating-ui/core": "^0.7.3"
} }
}, },
"@humanwhocodes/config-array": { "@humanwhocodes/config-array": {
...@@ -5252,6 +5260,11 @@ ...@@ -5252,6 +5260,11 @@
"integrity": "sha512-C3064MH72iEfeGCYEGCt7FCxXoAXaMPG0QPnstcxvPmbl54erpISu06d++FY37Smja64iWy5L8wOyHHBghWbJQ==", "integrity": "sha512-C3064MH72iEfeGCYEGCt7FCxXoAXaMPG0QPnstcxvPmbl54erpISu06d++FY37Smja64iWy5L8wOyHHBghWbJQ==",
"dev": true "dev": true
}, },
"@types/web-bluetooth": {
"version": "0.0.14",
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.14.tgz",
"integrity": "sha512-5d2RhCard1nQUC3aHcq/gHzWYO6K0WJmAbjO7mQJgCQKtZpgXxv1rOM6O/dBDhDYYVutk1sciOgNSe+5YyfM8A=="
},
"@typescript-eslint/eslint-plugin": { "@typescript-eslint/eslint-plugin": {
"version": "5.26.0", "version": "5.26.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.26.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.26.0.tgz",
...@@ -5553,35 +5566,36 @@ ...@@ -5553,35 +5566,36 @@
"requires": {} "requires": {}
}, },
"@vueuse/core": { "@vueuse/core": {
"version": "8.6.0", "version": "8.9.0",
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-8.6.0.tgz", "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-8.9.0.tgz",
"integrity": "sha512-VirzExCm/N+QdrEWT7J4uSrvJ5hquKIAU9alQ37kUvIJk9XxCLxmfRnmekYc1kz2+6BnoyuKYXVmrMV351CB4w==", "integrity": "sha512-eKWehF6gsiLYxnYM/1xgDu16bKED7AWvkk56JIFNQes8OKgktr3Jc1wUy8UWIulrnwCXICUu9YUo+Wkq4r2JNw==",
"requires": { "requires": {
"@vueuse/metadata": "8.6.0", "@types/web-bluetooth": "^0.0.14",
"@vueuse/shared": "8.6.0", "@vueuse/metadata": "8.9.0",
"@vueuse/shared": "8.9.0",
"vue-demi": "*" "vue-demi": "*"
}, },
"dependencies": { "dependencies": {
"@vueuse/shared": { "@vueuse/shared": {
"version": "8.6.0", "version": "8.9.0",
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-8.6.0.tgz", "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-8.9.0.tgz",
"integrity": "sha512-Y/IVywZo7IfEoSSEtCYpkVEmPV7pU35mEIxV7PbD/D3ly18B3mEsBaPbtDkNM/QP3zAZ5mn4nEkOfddX4uwuIA==", "integrity": "sha512-Pmu3Fopk/JJjN8b90uQuFrVCc/RPcSA/0zDFRTyn3YIhoB5ESna/1Sac5WZxK+n82g/ERXHHQTetGI9yxEdPfA==",
"requires": { "requires": {
"vue-demi": "*" "vue-demi": "*"
} }
}, },
"vue-demi": { "vue-demi": {
"version": "0.13.1", "version": "0.13.2",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.1.tgz", "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.2.tgz",
"integrity": "sha512-xmkJ56koG3ptpLnpgmIzk9/4nFf4CqduSJbUM0OdPoU87NwRuZ6x49OLhjSa/fC15fV+5CbEnrxU4oyE022svg==", "integrity": "sha512-41ukrclEbMddAyP7PvxMSYqnOSzPV6r7GNnyTSKSCNTaz19GehxmTiXyP9kwHSUv2+Dr6hHqiUiF7L1VAw2KdQ==",
"requires": {} "requires": {}
} }
} }
}, },
"@vueuse/metadata": { "@vueuse/metadata": {
"version": "8.6.0", "version": "8.9.0",
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-8.6.0.tgz", "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-8.9.0.tgz",
"integrity": "sha512-F+CKPvaExsm7QgRr8y+ZNJFwXasn89rs5wth/HeX9lJ1q8XEt+HJ16Q5Sxh4rfG5YSKXrStveVge8TKvPjMjFA==" "integrity": "sha512-pjkIbQgJPRUrxK5/iXVKQFGC+OhJ+Vd6fhBsdwgj+NNJEHUotRliYymwdvhnEke/o+kkulT0xMvoK19nyPoiMw=="
}, },
"@xmldom/xmldom": { "@xmldom/xmldom": {
"version": "0.7.5", "version": "0.7.5",
...@@ -5781,9 +5795,9 @@ ...@@ -5781,9 +5795,9 @@
} }
}, },
"async-validator": { "async-validator": {
"version": "4.1.1", "version": "4.2.5",
"resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.1.1.tgz", "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
"integrity": "sha512-p4DO/JXwjs8klJyJL8Q2oM4ks5fUTze/h5k10oPPKMiLe1fj3G1QMzPHNmN1Py4ycOk7WlO2DcGXv1qiESJCZA==" "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg=="
}, },
"asynckit": { "asynckit": {
"version": "0.4.0", "version": "0.4.0",
...@@ -6118,18 +6132,18 @@ ...@@ -6118,18 +6132,18 @@
"dev": true "dev": true
}, },
"element-plus": { "element-plus": {
"version": "2.2.5", "version": "2.2.9",
"resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.2.5.tgz", "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.2.9.tgz",
"integrity": "sha512-Kl0yn/PQca5YQo3M3NPBP4Xl71NQuMtDx5zNXZGVyl5FjdMujXiFB9SXKYGDUCgFU3d/Rl14vB4Fpmcl2Iz+Hw==", "integrity": "sha512-jYbL0JkCdv95rkT6trZJjCAizLPySa0qcd2cgq+57SKQnCZAcNDDq4GbTuFRnNavdoeCJnuM3HIficTIUpsMOQ==",
"requires": { "requires": {
"@ctrl/tinycolor": "^3.4.1", "@ctrl/tinycolor": "^3.4.1",
"@element-plus/icons-vue": "^2.0.5", "@element-plus/icons-vue": "^2.0.6",
"@floating-ui/dom": "^0.5.2", "@floating-ui/dom": "^0.5.4",
"@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7", "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7",
"@types/lodash": "^4.14.182", "@types/lodash": "^4.14.182",
"@types/lodash-es": "^4.17.6", "@types/lodash-es": "^4.17.6",
"@vueuse/core": "^8.6.0", "@vueuse/core": "^8.7.5",
"async-validator": "^4.1.1", "async-validator": "^4.2.5",
"dayjs": "^1.11.3", "dayjs": "^1.11.3",
"escape-html": "^1.0.3", "escape-html": "^1.0.3",
"lodash": "^4.17.21", "lodash": "^4.17.21",
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
"build": "vue-tsc --noEmit && vite build --mode prod && npm run deploy", "build": "vue-tsc --noEmit && vite build --mode prod && npm run deploy",
"build:test": "vue-tsc --noEmit && vite build --mode test", "build:test": "vue-tsc --noEmit && vite build --mode test",
"build:pre": "vue-tsc --noEmit && vite build --mode pre", "build:pre": "vue-tsc --noEmit && vite build --mode pre",
"preview": "vite preview --port 5050", "preview": "vite preview --port 4173",
"typecheck": "vue-tsc --noEmit", "typecheck": "vue-tsc --noEmit",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore", "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"deploy": "node ./deploy.js" "deploy": "node ./deploy.js"
...@@ -17,8 +17,10 @@ ...@@ -17,8 +17,10 @@
"@tinymce/tinymce-vue": "^5.0.0", "@tinymce/tinymce-vue": "^5.0.0",
"axios": "^0.27.2", "axios": "^0.27.2",
"blueimp-md5": "^2.19.0", "blueimp-md5": "^2.19.0",
"dayjs": "^1.11.3",
"echarts": "^5.3.2", "echarts": "^5.3.2",
"element-plus": "^2.2.5", "element-plus": "^2.2.9",
"lodash-es": "^4.17.21",
"pinia": "^2.0.14", "pinia": "^2.0.14",
"qs": "^6.10.5", "qs": "^6.10.5",
"sortablejs": "^1.15.0", "sortablejs": "^1.15.0",
......
...@@ -75,7 +75,7 @@ function genNavClassName(data: IMenuItem) { ...@@ -75,7 +75,7 @@ function genNavClassName(data: IMenuItem) {
.app-header { .app-header {
position: sticky; position: sticky;
top: 0; top: 0;
z-index: 1000; z-index: 2001;
padding: 0 20px; padding: 0 20px;
display: flex; display: flex;
align-items: center; align-items: center;
......
...@@ -37,8 +37,8 @@ export function updateCourse(data: any) { ...@@ -37,8 +37,8 @@ export function updateCourse(data: any) {
} }
// 获取封面列表 // 获取封面列表
export function getCoverList() { export function getCoverList(params: { type: string }) {
return httpRequest.get('/api/resource/v1/util/get-cover-list') return httpRequest.get('/api/resource/v1/util/get-cover-list', { params })
} }
// 获取课程详情 // 获取课程详情
......
...@@ -36,8 +36,8 @@ const swiperChange = (type?: string) => { ...@@ -36,8 +36,8 @@ const swiperChange = (type?: string) => {
type === 'prev' ? swiper.value.prev() : swiper.value.next() type === 'prev' ? swiper.value.prev() : swiper.value.next()
} }
// 获取封面 // 获取封面
getCoverList().then(res => { getCoverList({ type: '2' }).then(res => {
const filtersData = res.data.list.filter((i: any) => i.type === '1') const filtersData = res.data.list
let index = 0 let index = 0
while (index < filtersData.length) { while (index < filtersData.length) {
swiperCovers.push(filtersData.slice(index, (index += 8))) swiperCovers.push(filtersData.slice(index, (index += 8)))
......
<script setup lang="ts"> <script setup lang="ts">
import { searchLecturer } from '../../api' import { searchLecturer } from '../../api'
import type { Lecturer } from '../../types'
import { uniqBy } from 'lodash-es'
interface Props {
modelValue: Lecturer[]
}
const emit = defineEmits(['change']) const props = withDefaults(defineProps<Props>(), { modelValue: () => [] })
const emit = defineEmits<{
const props = defineProps({ (e: 'update:modelValue', modelValue: Lecturer[]): void
data: { }>()
type: Array
}
})
// table回显的值
// let lecturerList: any = ref([])
const listOptions = computed(() => { const listOptions = computed(() => {
return { return {
columns: [ columns: [
{ label: '头像', slots: 'table-avatar', align: 'center' }, { label: '头像', slots: 'table-avatar', align: 'center' },
{ label: '姓名', prop: 'name', align: 'center' }, { label: '姓名', prop: 'name', align: 'center' },
// { label: '职位', prop: 'title', align: 'center' },
// { label: '机构', prop: 'office', align: 'center' },
{ label: '简介', slots: 'table-summarize', align: 'center' }, { label: '简介', slots: 'table-summarize', align: 'center' },
{ label: '操作', slots: 'table-operate', align: 'center' } { label: '操作', slots: 'table-operate', align: 'center' }
], ],
data: allLecturers.value.filter((item: any) => lecturerValue.value.find((i: any) => i === item.id)) data: props.modelValue
} }
}) })
// 讲师弹窗 // 弹窗
const dialogVisible = ref(false) const dialogVisible = ref(false)
// 选中的值
const selectList = ref<Lecturer[]>([])
interface ListItem {
name: string
id: string
}
const options = ref<ListItem[]>([])
const loading = ref(false)
// 所有被搜索出来的值
const allLecturers: any = ref([])
// 讲师选中的值
const lecturerValue = ref([])
// 远程搜索 // 远程搜索
const loading = ref(false)
const options = ref<Lecturer[]>([])
const remoteMethod = (query: string) => { const remoteMethod = (query: string) => {
if (query) { if (!query) return
loading.value = true loading.value = true
searchLecturer({ name: query, 'per-page': '100' }).then((res: any) => { searchLecturer({ name: query, 'per-page': '100' }).then((res: any) => {
loading.value = false loading.value = false
options.value = res.data.list options.value = res.data.list
options.value.forEach((item: any) => { })
const findItem = allLecturers.value.find((cItem: any) => cItem.id === item.id)
if (!findItem) {
allLecturers.value.push(item)
}
})
})
} else {
options.value = []
}
} }
watch( watch(
() => props.data, dialogVisible,
value => { () => {
if (value?.length) { // 清空已选数据
const list: any = value.map((item: any) => { selectList.value = []
return item.id
})
lecturerValue.value = list
allLecturers.value = value
options.value = value as []
}
}, },
{ immediate: true } { immediate: true }
) )
// 删除讲师 // 删除
const removeLectuter = (id: string) => { const handelRemove = (id: string) => {
const index = lecturerValue.value.findIndex((ids: string) => ids === id) emit(
lecturerValue.value.splice(index, 1) 'update:modelValue',
changeData() props.modelValue.filter((item: any) => item.id !== id)
)
} }
const changeData = () => { // 确认
emit('change', lecturerValue.value) const handlePrimary = () => {
const list = [...selectList.value, ...props.modelValue]
// 去重
emit('update:modelValue', uniqBy(list, 'id'))
dialogVisible.value = false
} }
</script> </script>
...@@ -95,32 +77,32 @@ const changeData = () => { ...@@ -95,32 +77,32 @@ const changeData = () => {
<div v-html="row.summarize"></div> <div v-html="row.summarize"></div>
</template> </template>
<template #table-operate="{ row }"> <template #table-operate="{ row }">
<el-button plain @click="removeLectuter(row.id)">删除</el-button> <el-button plain @click="handelRemove(row.id)">删除</el-button>
</template> </template>
</AppList> </AppList>
<el-dialog v-model="dialogVisible" width="400px" title="添加讲师"> <el-dialog v-model="dialogVisible" width="400px" title="添加讲师">
<div style="display: flex; justify-content: center"> <div style="display: flex; justify-content: center">
讲师姓名: 讲师姓名:
<el-select <el-select
@change="changeData" v-model="selectList"
v-model="lecturerValue"
multiple multiple
filterable filterable
remote remote
reserve-keyword
placeholder="请输入讲师姓名" placeholder="请输入讲师姓名"
value-key="id"
:reserve-keyword="false"
:remote-method="remoteMethod" :remote-method="remoteMethod"
:loading="loading" :loading="loading"
style="flex: 1"
> >
<el-option v-for="item in options" :key="item.id" :label="item.name" :value="item.id" /> <el-option v-for="item in options" :key="item.id" :label="item.name" :value="item" />
</el-select> </el-select>
</div> </div>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button type="primary" @click="dialogVisible = false">确认</el-button> <el-button type="primary" @click="handlePrimary">确认</el-button>
</span> </span>
</template> </template>
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
<style lang="scss"></style>
<script setup lang="ts"> <script setup lang="ts">
import { searchLive } from '../../api' import { searchLive } from '../../api'
import type { Live } from '../../types'
import { uniqBy } from 'lodash-es'
import dayjs from 'dayjs'
const emit = defineEmits(['change']) interface Props {
modelValue: Live[]
const add0 = (m: number) => {
return m < 10 ? '0' + m : m
}
const format = (n: number) => {
const time = new Date(n)
const y = time.getFullYear()
const m = time.getMonth() + 1
const d = time.getDate()
const h = time.getHours()
const mm = time.getMinutes()
const s = time.getSeconds()
return y + '-' + add0(m) + '-' + add0(d) + ' ' + add0(h) + ':' + add0(mm) + ':' + add0(s)
} }
const props = withDefaults(defineProps<Props>(), { modelValue: () => [] })
const props = defineProps({ const emit = defineEmits<{
data: { (e: 'update:modelValue', modelValue: Live[]): void
type: Array }>()
}
})
const listOptions = computed(() => { const listOptions = computed(() => {
return { return {
...@@ -32,88 +21,64 @@ const listOptions = computed(() => { ...@@ -32,88 +21,64 @@ const listOptions = computed(() => {
label: '开始时间', label: '开始时间',
prop: 'start_time', prop: 'start_time',
align: 'center', align: 'center',
computed({ row }: any) { computed({ row }: { row: Live }) {
if (row.start_time === undefined) { return row.start_time ? dayjs(row.start_time * 1000).format('YYYY-MM-DD HH:mm:ss') : '-'
return '-'
} else {
return format(parseInt(row.start_time) * 1000)
}
} }
}, },
{ {
label: '结束时间', label: '结束时间',
prop: 'end_time', prop: 'end_time',
align: 'center', align: 'center',
computed({ row }: any) { computed({ row }: { row: Live }) {
if (row.end_time === undefined) { return row.start_time ? dayjs(row.end_time * 1000).format('YYYY-MM-DD HH:mm:ss') : '-'
return '-'
} else {
return format(parseInt(row.end_time) * 1000)
}
} }
}, },
{ label: '操作', slots: 'table-operate', align: 'center' } { label: '操作', slots: 'table-operate', align: 'center' }
], ],
data: allLecturers.value.filter((item: any) => lecturerValue.value.find((i: any) => i === item.id)) data: props.modelValue
} }
}) })
// 直播弹窗 // 弹窗
const dialogVisible = ref(false) const dialogVisible = ref(false)
// 选中的值
const selectList = ref<Live[]>([])
interface ListItem {
subject: string
id: string
}
const options = ref<ListItem[]>([])
const loading = ref(false)
// 所有被搜索出来的值
const allLecturers: any = ref([])
// 直播选中的值
const lecturerValue = ref([])
// 远程搜索 // 远程搜索
const loading = ref(false)
const options = ref<Live[]>([])
const remoteMethod = (query: string) => { const remoteMethod = (query: string) => {
if (query) { if (!query) return
loading.value = true loading.value = true
searchLive({ name: query, 'per-page': '100' }).then((res: any) => { searchLive({ name: query, 'per-page': '100' }).then((res: any) => {
loading.value = false loading.value = false
options.value = res.data.list options.value = res.data.list
options.value.forEach((item: any) => { })
const findItem = allLecturers.value.find((cItem: any) => cItem.id === item.id)
if (!findItem) {
allLecturers.value.push(item)
}
})
})
} else {
options.value = []
}
} }
watch( watch(
() => props.data, dialogVisible,
value => { () => {
if (value?.length) { // 清空已选数据
const list: any = value.map((item: any) => { selectList.value = []
return item.id
})
lecturerValue.value = list
allLecturers.value = value
options.value = value as []
}
}, },
{ immediate: true } { immediate: true }
) )
// 删除直播 // 删除
const removeLectuter = (id: string) => { const handleRemove = (id: string) => {
const index = lecturerValue.value.findIndex((ids: string) => ids === id) emit(
lecturerValue.value.splice(index, 1) 'update:modelValue',
changeData() props.modelValue.filter((item: any) => item.id !== id)
)
} }
const changeData = () => { // 确认
emit('change', lecturerValue.value) const handlePrimary = () => {
const list = [...selectList.value, ...props.modelValue]
// 去重
emit('update:modelValue', uniqBy(list, 'id'))
dialogVisible.value = false
} }
</script> </script>
...@@ -128,32 +93,32 @@ const changeData = () => { ...@@ -128,32 +93,32 @@ const changeData = () => {
<div v-html="row.summarize"></div> <div v-html="row.summarize"></div>
</template> </template>
<template #table-operate="{ row }"> <template #table-operate="{ row }">
<el-button plain @click="removeLectuter(row.id)">删除</el-button> <el-button plain @click="handleRemove(row.id)">删除</el-button>
</template> </template>
</AppList> </AppList>
<el-dialog v-model="dialogVisible" width="400px" title="添加直播"> <el-dialog v-model="dialogVisible" width="400px" title="添加直播">
<div style="display: flex; justify-content: center"> <div style="display: flex; justify-content: center">
直播会议号: 直播会议号:
<el-select <el-select
@change="changeData" v-model="selectList"
v-model="lecturerValue"
multiple multiple
filterable filterable
remote remote
reserve-keyword
placeholder="会议主题或者会议code" placeholder="会议主题或者会议code"
value-key="id"
:reserve-keyword="false"
:remote-method="remoteMethod" :remote-method="remoteMethod"
:loading="loading" :loading="loading"
style="flex: 1"
> >
<el-option v-for="item in options" :key="item.id" :label="item.subject" :value="item.id" /> <el-option v-for="item in options" :key="item.id" :label="item.subject" :value="item" />
</el-select> </el-select>
</div> </div>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button type="primary" @click="dialogVisible = false">确认</el-button> <el-button type="primary" @click="handlePrimary">确认</el-button>
</span> </span>
</template> </template>
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
<style lang="scss"></style>
export interface Lecturer {
avatar: string
id: string
name: string
summarize: string
}
export interface Live {
id: string
join_url: string
meeting_code: string
meeting_id: string
meeting_type: number
start_time: number
end_time: number
subject: string
}
...@@ -13,14 +13,11 @@ import AddExam from '../components/stepOneComponents/AddExam.vue' ...@@ -13,14 +13,11 @@ import AddExam from '../components/stepOneComponents/AddExam.vue'
// 添加直播 // 添加直播
import AddLive from '../components/stepOneComponents/AddLive.vue' import AddLive from '../components/stepOneComponents/AddLive.vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import type { FormInstance, FormRules } from 'element-plus'
const store = useMapStore() const store = useMapStore()
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
// const router = useRouter()
const id = route.query.id as string const id = route.query.id as string
// is 编辑 新建 // is 编辑 新建
...@@ -44,29 +41,38 @@ const electiveType = computed<ICourseList[]>(() => { ...@@ -44,29 +41,38 @@ const electiveType = computed<ICourseList[]>(() => {
// 下拉选择tree 视频分类 // 下拉选择tree 视频分类
let { list: selectTree } = useGetCategoryList() let { list: selectTree } = useGetCategoryList()
const defaultProps = { const defaultProps = { children: 'children', label: 'category_name', value: 'id' }
children: 'children',
label: 'category_name',
value: 'id'
}
// form // form
let form = $ref<Record<string, any>>({ const form = reactive<Record<string, any>>({
name: '',
online_type: '',
elective_type: '',
classification: '',
credit: '',
source: '2', source: '2',
cover: 'https://webapp-pub.oss-cn-beijing.aliyuncs.com/center_resource/course-cover.png' cover: 'https://webapp-pub.oss-cn-beijing.aliyuncs.com/center_resource/course-cover.png',
lecturer_id: '',
represent: '',
essay: '',
previous_preparation: '',
target: '',
exam_id: '',
live_id: ''
}) })
// 表单验证 // 表单验证
const rules = { const rules = reactive<FormRules>({
name: [{ required: true, message: '请输入标题' }], name: [{ required: true, message: '请输入标题' }],
online_type: [{ required: true, message: '请选择类型' }], online_type: [{ required: true, message: '请选择课程类型' }],
elective_type: [{ required: true, message: '请选择类型' }], elective_type: [{ required: true, message: '请选择选课类型' }],
classification: [{ required: true, message: '请选择分类' }], classification: [{ required: true, message: '请选择课程分类' }],
credit: [{ required: true, message: '请输入学分' }], credit: [
lecturer_id: [{ required: true, message: '' }], { required: true, message: '请输入学分' },
exam_id: [{ required: true, message: '' }], { pattern: /\d/, message: '请输入数字' }
live_id: [{ required: true, message: '' }] ],
} lecturer_id: [{ required: true, message: '请添加课程讲师' }]
})
// 课程封面dialog // 课程封面dialog
const dialogVisible = ref(false) const dialogVisible = ref(false)
...@@ -75,11 +81,6 @@ const coverChange = (url: string) => { ...@@ -75,11 +81,6 @@ const coverChange = (url: string) => {
form.cover = url form.cover = url
} }
// 选择讲师
const changeLecturer = (data: any) => {
form.lecturer_id = data.toString()
}
// 选择考试 // 选择考试
const changeExam = (data: any) => { const changeExam = (data: any) => {
console.log(data, 'data') console.log(data, 'data')
...@@ -88,104 +89,96 @@ const changeExam = (data: any) => { ...@@ -88,104 +89,96 @@ const changeExam = (data: any) => {
return item.id return item.id
}) })
.toString() .toString()
console.log(form.exam_id, 'data')
}
// 选择直播
const changeLive = (data: any) => {
form.live_id = data.toString()
} }
// 讲师数据回显
const lecturerList: any = ref([])
// 考试数据回显 // 考试数据回显
const examList: any = ref([]) const examList: any = ref([])
// 考试数据回显
const liveList: any = ref([]) // 获取详情
// 编辑数据回显 let loading = $ref<boolean>(false)
if (isUpdate) { function fetchDetail() {
getCourseDetails({ id: id }).then((res: any) => { loading = true
form = res.data getCourseDetails({ id }).then((res: any) => {
lecturerList.value = res.data.lecturers Object.assign(form, res.data)
examList.value = res.data.examinations examList.value = res.data.examinations
liveList.value = res.data.meetings loading = false
form.lecturer_id = setDefaultData(lecturerList.value)
form.exam_id = setDefaultData(examList.value)
form.live_id = setDefaultData(liveList.value)
}) })
} }
const setDefaultData = (data: object[]) => { onMounted(() => {
const container: any = [] isUpdate && fetchDetail()
data.forEach((item: any) => { })
container.push(item.id)
}) watchEffect(() => {
return container.toString() form.lecturer_id = setDefaultData(form.lecturers)
form.exam_id = setDefaultData(examList.value)
form.live_id = setDefaultData(form.meetings)
})
function setDefaultData(data: any[] = []) {
return data.map((item: any) => item.id).join()
} }
const ruleFormRef = $ref<FormInstance>()
const ruleFormRef2 = $ref<FormInstance>()
// 第一步保存后的id // 提交
const stepOneId = ref() function handleSubmit() {
// 新建课件 Promise.all([ruleFormRef.validate(), ruleFormRef2.validate()])
const createCourseForm = () => { .then(() => {
if (form.lecturer_id === '') { isUpdate ? handleUpdate() : handleCreate()
ElMessage.warning('请添加讲师')
return
}
if (isUpdate) {
updateCourse(form).then((res: any) => {
if (res.code === 0) {
// 操作第二部
stepOneId.value = res.data.id
router.push({
path: '/course/update-course/stepTwo',
query: {
id: stepOneId.value,
isEditCourse: '1'
}
})
}
}) })
} else { .catch(() => {
createCourse(form).then((res: any) => { ElMessage.error('请检查表单是否填写完整')
if (res.code === 0) {
// 操作第二部
stepOneId.value = res.data.id
router.push({
path: '/course/update-course/stepTwo',
query: {
id: stepOneId.value,
isEditCourse: '0'
}
})
}
}) })
} }
// 创建课程
function handleCreate() {
createCourse(form).then((res: any) => {
if (res.code === 0) {
// 操作第二部
router.push({
path: '/course/update-course/stepTwo',
query: { id: res.data.id, isEditCourse: '0' }
})
}
})
}
// 修改课程
function handleUpdate() {
updateCourse(form).then((res: any) => {
if (res.code === 0) {
// 操作第二部
router.push({
path: '/course/update-course/stepTwo',
query: { id: res.data.id, isEditCourse: '1' }
})
}
})
} }
</script> </script>
<template> <template>
<AppCard :title="isUpdate ? '编辑课程' : '新建课程'"> <AppCard :title="isUpdate ? '编辑课程' : '新建课程'" v-loading="loading">
<!-- 基本信息 --> <!-- 基本信息 -->
<div class="update-course-info"> <div class="update-course-info">
<div style="display: flex"> <div style="display: flex">
<div class="cover" :style="`background-image: url(${form.cover})`"> <div class="cover" :style="`background-image: url(${form.cover})`">
<div class="upload-btn" @click="dialogVisible = true">添加封面</div> <div class="upload-btn" @click="dialogVisible = true">添加封面</div>
</div> </div>
<el-form ref="ruleFormRef" :model="form" :rules="rules" style="width: 50%"> <el-form ref="ruleFormRef2" :model="form" :rules="rules" style="width: 50%" label-suffix=":">
<el-form-item label="课程名称" prop="name"> <el-form-item label="课程名称" prop="name">
<el-input v-model="form.name" maxlength="40" /> <el-input v-model="form.name" maxlength="40" />
</el-form-item> </el-form-item>
<el-form-item label="课程类型" prop="online_type"> <el-form-item label="课程类型" prop="online_type">
<el-radio-group v-model="form.online_type"> <el-radio-group v-model="form.online_type">
<el-radio :key="item.value" :label="item.value" v-for="item in courseType">{{ item.label }}</el-radio> <el-radio :key="item.value" :label="item.value" v-for="item in courseType">{{ item.label }}</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="选课类型" prop="elective_type"> <el-form-item label="选课类型" prop="elective_type">
<el-radio-group v-model="form.elective_type"> <el-radio-group v-model="form.elective_type">
<el-radio :key="item.value" :label="item.value" v-for="item in electiveType">{{ item.label }}</el-radio> <el-radio :key="item.value" :label="item.value" v-for="item in electiveType">{{ item.label }}</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="课程分类" prop="classification"> <el-form-item label="课程分类" prop="classification">
<el-tree-select <el-tree-select
:render-after-expand="false" :render-after-expand="false"
:props="defaultProps" :props="defaultProps"
...@@ -194,8 +187,8 @@ const createCourseForm = () => { ...@@ -194,8 +187,8 @@ const createCourseForm = () => {
:data="selectTree" :data="selectTree"
/> />
</el-form-item> </el-form-item>
<el-form-item label="课程学分" prop="credit"> <el-form-item label="课程学分" prop="credit">
<el-input v-model="form.credit" maxlength="2" /> <el-input v-model="form.credit" maxlength="3" />
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div>
...@@ -204,36 +197,37 @@ const createCourseForm = () => { ...@@ -204,36 +197,37 @@ const createCourseForm = () => {
label-position="top" label-position="top"
:model="form" :model="form"
:rules="rules" :rules="rules"
label-suffix=":"
style="width: 100%; margin-top: 30px" style="width: 100%; margin-top: 30px"
> >
<el-form-item label="课程讲师" prop="lecturer_id"> <el-form-item label="课程讲师" prop="lecturer_id">
<!-- 添加讲师 --> <!-- 添加讲师 -->
<AddLecturer :data="lecturerList" @change="changeLecturer" style="width: 100%"></AddLecturer> <AddLecturer v-model="form.lecturers" style="width: 100%"></AddLecturer>
</el-form-item> </el-form-item>
<el-form-item label="课程简介与描述"> <el-form-item label="课程简介与描述">
<v-editor v-model="form.represent" class="editor" :height="200"></v-editor> <v-editor v-model="form.represent" class="editor" :height="200"></v-editor>
</el-form-item> </el-form-item>
<el-form-item label="课程小论文"> <el-form-item label="课程小论文">
<v-editor v-model="form.essay" class="editor" :height="200"></v-editor> <v-editor v-model="form.essay" class="editor" :height="200"></v-editor>
</el-form-item> </el-form-item>
<el-form-item label="前期准备与预备知识"> <el-form-item label="前期准备与预备知识">
<v-editor v-model="form.previous_preparation" class="editor" :height="200"></v-editor> <v-editor v-model="form.previous_preparation" class="editor" :height="200"></v-editor>
</el-form-item> </el-form-item>
<el-form-item label="授课目标"> <el-form-item label="授课目标">
<v-editor v-model="form.target" class="editor" :height="200"></v-editor> <v-editor v-model="form.target" class="editor" :height="200"></v-editor>
</el-form-item> </el-form-item>
<el-form-item label="课程考试" prop="exam_id"> <el-form-item label="课程考试" prop="exam_id">
<!-- 添加考试 --> <!-- 添加考试 -->
<AddExam :data="examList" @change="changeExam" style="width: 100%"></AddExam> <AddExam :data="examList" @change="changeExam" style="width: 100%"></AddExam>
</el-form-item> </el-form-item>
<el-form-item label="周期性直播" prop="live_id"> <el-form-item label="周期性直播" prop="live_id">
<!-- 添加直播 --> <!-- 添加直播 -->
<AddLive :data="liveList" @change="changeLive" style="width: 100%"></AddLive> <AddLive v-model="form.meetings" style="width: 100%"></AddLive>
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div>
<div class="btn-box" style="display: flex; justify-content: center"> <div class="btn-box" style="display: flex; justify-content: center">
<el-button type="primary" @click="createCourseForm">下一步</el-button> <el-button type="primary" @click="handleSubmit">下一步</el-button>
</div> </div>
<!-- 添加封面 --> <!-- 添加封面 -->
<AddCourseCover @change="coverChange" v-model:dialogVisible="dialogVisible"></AddCourseCover> <AddCourseCover @change="coverChange" v-model:dialogVisible="dialogVisible"></AddCourseCover>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论