持续开发习题管理模块,新增ckeditor5富文本组件
This commit is contained in:
		| @@ -10,9 +10,12 @@ | ||||
|     "fix-memory-limit": "cross-env LIMIT=4096 increase-memory-limit" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "@ckeditor/ckeditor5-build-classic": "^36.0.1", | ||||
|     "@ckeditor/ckeditor5-vue": "^4.0.1", | ||||
|     "@element-plus/icons-vue": "^0.2.7", | ||||
|     "ali-oss": "^6.17.1", | ||||
|     "axios": "^0.19.2", | ||||
|     "axl-editor": "^1.0.1", | ||||
|     "core-js": "^3.6.5", | ||||
|     "echarts": "5.3.2", | ||||
|     "element-plus": "2.2.9", | ||||
|   | ||||
							
								
								
									
										12
									
								
								src/api/exercises.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/api/exercises.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| import service from '@/utils/request' | ||||
| const api = { | ||||
|   // 课程api | ||||
|   getExercisesList : data => { | ||||
|     return service({ | ||||
|       url: '/question', | ||||
|       method: 'get', | ||||
|       params:data | ||||
|     }) | ||||
|   } | ||||
| } | ||||
| export default api | ||||
							
								
								
									
										180
									
								
								src/components/richText/ckEditor4.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										180
									
								
								src/components/richText/ckEditor4.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,180 @@ | ||||
| <template> | ||||
|   <div id="app-ckeditor"> | ||||
|     <ckeditor | ||||
|       v-model="editorData2" | ||||
|       :config="editorConfig" | ||||
|       @ready="logEvent('ready', $event)" | ||||
|     /> | ||||
|   </div> | ||||
| </template> | ||||
| <!--<script src="/node_modules/ckeditor4/ckeditor.js"></script>--> | ||||
| <!--<script src="/node_modules/ckeditor4-vue/dist/ckeditor.js"></script>--> | ||||
| <!--<script src="https://cdn.ckeditor.com/4.19.1/standard-all/ckeditor.js"></script>--> | ||||
| <script> | ||||
| // import { MyCustomUploadAdapterPlugin } from "@/components/richText/customUploadAdapter"; | ||||
| import { getToken } from '@/utils/auth' | ||||
| export default { | ||||
|   name: 'ckEditor4', | ||||
|   model: { | ||||
|     prop: 'content', | ||||
|     event: 'change' | ||||
|   }, | ||||
|   props: ['modelValue', 'content'], | ||||
|   emits: ['update:modelValue'], | ||||
|   data() { | ||||
|     return { | ||||
|       img_url:'', | ||||
|       events: [], | ||||
|       // editorUrl: "https://xxx/ckeditor/ckeditor.js", | ||||
|       editorConfig: { | ||||
|         extraPlugins: 'uploadimage,image2', | ||||
|         uploadUrl: 'https://apiwx.twzxjy.com/api/v1/public/uploadFile?command=QuickUpload&type=Files&responseType=json', | ||||
|         filebrowserBrowseUrl: 'https://apiwx.twzxjy.com/api/v1/public/uploadFile', | ||||
|         filebrowserImageBrowseUrl: 'https://apiwx.twzxjy.com/api/v1/public/uploadFile?type=Images', | ||||
|         filebrowserUploadUrl: 'https://apiwx.twzxjy.com/api/v1/public/uploadFile?command=QuickUpload&type=Files', | ||||
|         filebrowserImageUploadUrl: 'https://apiwx.twzxjy.com/api/v1/public/uploadFile', | ||||
|         imageUploadUrl: 'https://apiwx.twzxjy.com/api/v1/public/uploadFile', | ||||
|  | ||||
|         fileTools_requestHeaders: { | ||||
|           'Authorization': 'Bearer ' + getToken() | ||||
|         }, | ||||
|         image2_alignClasses: ['image-align-left', 'image-align-center', 'image-align-right'], | ||||
|         image2_disableResizer: true, | ||||
|         removeButtons: 'PasteFromWord' | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     editorData: { | ||||
|       get() { | ||||
|         return this.modelValue | ||||
|       }, | ||||
|       set(value) { | ||||
|         console.log(value) | ||||
|         this.$emit('update:modelValue', value) | ||||
|       } | ||||
|     }, | ||||
|     editorData2: { | ||||
|       get() { | ||||
|         return this.content | ||||
|  | ||||
|       }, | ||||
|       set(value) { | ||||
|         this.$emit('change', value) | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   watch: { | ||||
|     // editorData(val1) { | ||||
|     //   console.log(val1) | ||||
|     // } | ||||
|   }, | ||||
|   created() { | ||||
|     this.getScript() | ||||
|   }, | ||||
|   methods: { | ||||
|     getScript() { | ||||
|       const script = document.createElement('script') | ||||
|       script.type = 'text/javascript' | ||||
|       script.src = '/node_modules/ckeditor4/ckeditor.js' | ||||
|       document.getElementsByTagName('head')[0].appendChild(script) | ||||
|     }, | ||||
|     logEvent: function(eventName, event) { | ||||
|       const _this = this | ||||
|       // console.log(event) | ||||
|       // 上传请求 | ||||
|       event.on( 'fileUploadRequest', async evt => { | ||||
|         console.log(evt) | ||||
|         var fileLoader = evt.data.fileLoader; | ||||
|         // let formData = new FormData(); | ||||
|         // let xhr = fileLoader.xhr; | ||||
|         // xhr.setRequestHeader( 'Authorization', 'Bearer ' + getToken() ); | ||||
|         // xhr.open( 'POST', fileLoader.uploadUrl, true ); | ||||
|         // formData.append( 'multipartFile', fileLoader.file); | ||||
|         // fileLoader.xhr.send( formData ); | ||||
|  | ||||
|  | ||||
|         // 测试 | ||||
|           const xhr_ = new XMLHttpRequest() | ||||
|           xhr_.onreadystatechange=function() | ||||
|           { | ||||
|               if (xhr_.readyState==4 && xhr_.status==200) | ||||
|               { | ||||
|                 // console.log(xhr_) | ||||
|                 _this.img_url = xhr_.response.data.full_path | ||||
|                 // var data = evt.data; | ||||
|                 // data.url = res_url | ||||
|                 // 用官方的方法进行访问 | ||||
|                 let xhr = fileLoader.xhr; | ||||
|                 xhr.open( 'POST', fileLoader.uploadUrl, true ); | ||||
|                 xhr.setRequestHeader('Authorization', 'Bearer ' + getToken()) | ||||
|                 let formData = new FormData(); | ||||
|                 formData.append( 'multipartFile', fileLoader.file); | ||||
|                 fileLoader.xhr.send( formData ); | ||||
|               } | ||||
|           } | ||||
|           xhr_.open('POST', fileLoader.uploadUrl, true) | ||||
|           xhr_.setRequestHeader('Authorization', 'Bearer ' + getToken()) | ||||
|           xhr_.responseType = 'json' | ||||
|  | ||||
|           const data = new FormData(); | ||||
|           // 上传参数就根据后端的处理而设置了 | ||||
|           data.append( 'file', fileLoader.file ); | ||||
|           xhr_.send(data); | ||||
|  | ||||
|         // 测试结束 | ||||
|  | ||||
|         // Prevented the default behavior. | ||||
|         evt.stop() | ||||
|       }) | ||||
|       // 回调 | ||||
|       event.on( 'fileUploadResponse', async evt => { | ||||
|         console.log(evt) | ||||
|         evt.stop(); | ||||
|         evt.data.url = _this.img_url | ||||
|         // var data = evt.data; | ||||
|         // let xhr = data.fileLoader.xhr; | ||||
|         // let response = xhr.responseText; | ||||
|         // let imgUrl = JSON.parse(response).data; | ||||
|         // if(!imgUrl){ | ||||
|         //     data.message = imgUrl   // 这是失败alert提示信息 | ||||
|         //     evt.cancel(); | ||||
|         // }else{ | ||||
|         //     data.url = imgUrl   // 返回到“图像信息”那里的URL框里面 | ||||
|         // } | ||||
|       }) | ||||
|       // if (this.events.length > 19) { | ||||
|       //   this.events.pop() | ||||
|       // } | ||||
|       // | ||||
|       // const eventData = { | ||||
|       //   name: eventName, | ||||
|       //   timestamp: this.getCurrentTimestamp() | ||||
|       // } | ||||
|       // | ||||
|       // this.events.unshift(eventData) | ||||
|  | ||||
|       // console.log(eventData.timestamp, eventData.name, event) | ||||
|     }, | ||||
|  | ||||
|     getCurrentTimestamp: function() { | ||||
|       return new Intl.DateTimeFormat('en', { | ||||
|         hour12: false, | ||||
|         hour: '2-digit', | ||||
|         minute: '2-digit', | ||||
|         second: '2-digit' | ||||
|       }).format(new Date()) | ||||
|     }, | ||||
|  | ||||
|     clearEventsLog: function() { | ||||
|       this.events = [] | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| <style> | ||||
| .ck-editor__main{ | ||||
|   max-height: 350px; | ||||
|   overflow: scroll; | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										53
									
								
								src/components/richText/ckEditor5.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/components/richText/ckEditor5.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| <template> | ||||
|     <div id="editor-box"> | ||||
|         <ckeditor :editor="editor" v-model="value" :config="editorConfig"  @ready="logEvent('ready', $event)"></ckeditor> | ||||
|     </div> | ||||
| </template> | ||||
|  | ||||
| <script > | ||||
|     // import ClassicEditor from '@ckeditor/ckeditor5-build-classic'; | ||||
|     import ClassicEditor from 'axl-editor'; | ||||
|     import { MyCustomUploadAdapterPlugin } from '@/components/richText/customUploadAdapter' | ||||
|     // import {ref,onMounted } from 'vue' | ||||
|     export default { | ||||
|         name: 'editor-box', | ||||
|         props: ['modelValue','content'], | ||||
|         emits: ['update:modelValue'], | ||||
|         data() { | ||||
|             return { | ||||
|                 editor: ClassicEditor, | ||||
|                 editorData: '<p>Content of the editor.</p>', | ||||
|                 editorConfig: { | ||||
|                     // The configuration of the editor. | ||||
|                   // uploadUrl: 'https://apiwx.twzxjy.com/api/v1/public/uploadFile?command=QuickUpload&type=Files&responseType=json', | ||||
|                   // simpleUpload:{ | ||||
|                   //     uploadUrl: 'https://apiwx.twzxjy.com/api/v1/public/uploadFile?command=QuickUpload&type=Files&responseType=json', | ||||
|                   // } | ||||
|                   extraPlugins:[MyCustomUploadAdapterPlugin] | ||||
|                 } | ||||
|             }; | ||||
|         }, | ||||
|        computed: { | ||||
|           value: { | ||||
|             get() { | ||||
|               return this.modelValue | ||||
|             }, | ||||
|             set(value) { | ||||
|               this.$emit('update:modelValue', value) | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         methods:{ | ||||
|           logEvent(eventName, event){ | ||||
|             const _this = this | ||||
|             console.log(eventName) | ||||
|             // event.on( 'fileUploadRequest', async evt => { | ||||
|             //   console.log(evt) | ||||
|             // }) | ||||
|           }, | ||||
|         } | ||||
|     } | ||||
|     // const name = ref(ClassicEditor) | ||||
|     // const editorData = ref('<p>Content of the editor.</p>') | ||||
|     // const editorConfig = ref({}) | ||||
| </script> | ||||
							
								
								
									
										146
									
								
								src/components/richText/customUploadAdapter.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								src/components/richText/customUploadAdapter.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,146 @@ | ||||
| /** | ||||
|  * 图片压缩处理,转换为等比的高800px的图像 | ||||
|  * @params file File类型的图片文件 | ||||
|  * @return Promise<file> 返回一个promise,值为一个压缩后的图片文件 | ||||
|  */ | ||||
| import { getToken } from '@/utils/auth' | ||||
| function imgCutdown(file) { | ||||
|   return new Promise((resolve) => { | ||||
|     const render = new FileReader(); | ||||
|     render.onload = function(progress) { | ||||
|       const target = progress.target; | ||||
|       if (!target) return; | ||||
|  | ||||
|       const reuslt = target.result; | ||||
|       if (typeof reuslt === "string") { | ||||
|         const image = new Image(); | ||||
|         image.src = reuslt; | ||||
|         image.onload = function() { | ||||
|           const h = 800; | ||||
|           const rate = h / image.height; | ||||
|           const canvas = document.createElement("canvas"); | ||||
|           const context = canvas.getContext("2d"); | ||||
|           if (!context) return; | ||||
|           canvas.width = image.width * rate; | ||||
|           canvas.height = h; | ||||
|           context.drawImage( | ||||
|             image, | ||||
|             0, | ||||
|             0, | ||||
|             image.width, | ||||
|             image.height, | ||||
|             0, | ||||
|             0, | ||||
|             canvas.width, | ||||
|             canvas.height | ||||
|           ); | ||||
|           canvas.toBlob( | ||||
|             function(b) { | ||||
|               const file = new File([b], "pic", { | ||||
|                 type: "image/jpeg", | ||||
|               }); | ||||
|               resolve(file); | ||||
|             }, | ||||
|             "image/jpeg", | ||||
|             0.5 | ||||
|           ); | ||||
|         }; | ||||
|       } | ||||
|     }; | ||||
|     render.readAsDataURL(file); | ||||
|   }); | ||||
| } | ||||
|  | ||||
| // 上传图片的地址,我这里使用的是vue的环境变量,也可以直接写死 | ||||
| // const uploadUrl = `${process.env.VUE_APP_HOST}image/upload.do`; | ||||
| // const uploadUrl = `https://192.168.1.23:8000/api/v1/public/uploadFile` | ||||
| const uploadUrl = `https://apiwx.twzxjy.com/api/v1/public/uploadFile` | ||||
|  | ||||
| // 自定义适配器类 | ||||
| class MyUploadAdapter { | ||||
|   constructor(loader) { | ||||
|     this.loader = loader | ||||
|   } | ||||
|  | ||||
|   upload() { | ||||
|     return this.loader.file.then( | ||||
|       (file) => | ||||
|         new Promise((resolve, reject) => { | ||||
|           this._initRequest(); | ||||
|           this._initListeners(resolve, reject, file); | ||||
|           this._sendRequest(file); | ||||
|         }) | ||||
|     ) | ||||
|   } | ||||
|  | ||||
|   abort() { | ||||
|     if (this.xhr) { | ||||
|       this.xhr.abort(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   _initRequest() { | ||||
|     const xhr = (this.xhr = new XMLHttpRequest()) | ||||
|  | ||||
|     xhr.open('POST', uploadUrl, true) | ||||
|     xhr.setRequestHeader('Authorization', 'Bearer ' + getToken()) | ||||
|     xhr.responseType = 'json' | ||||
|   } | ||||
|  | ||||
|   _initListeners(resolve, reject, file) { | ||||
|     const xhr = this.xhr | ||||
|     const loader = this.loader | ||||
|     const genericErrorText = `Couldn't upload file: ${file.name}.` | ||||
|  | ||||
|     xhr.addEventListener('error', () => reject(genericErrorText)) | ||||
|     xhr.addEventListener('abort', () => reject()) | ||||
|     xhr.addEventListener('load', () => { | ||||
|       const response = xhr.response | ||||
|  | ||||
|       if (!response || response.error) { | ||||
|         return reject( | ||||
|           response && response.error ? response.error.message : genericErrorText | ||||
|         ) | ||||
|       } | ||||
|       console.log(response) | ||||
|  | ||||
|       resolve({ | ||||
|         default: response.data.path, | ||||
|       }) | ||||
|     }) | ||||
|  | ||||
|     if (xhr.upload) { | ||||
|       xhr.upload.addEventListener('progress', (evt) => { | ||||
|         if (evt.lengthComputable) { | ||||
|           loader.uploadTotal = evt.total | ||||
|           loader.uploaded = evt.loaded | ||||
|         } | ||||
|       }) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   async _sendRequest(file) { | ||||
|     const data = new FormData(); | ||||
| 	// 判断如果上传图片大于1M,则进行压缩处理 | ||||
|     // if (file.size > 1000 * 1024) { | ||||
|     //   file = await imgCutdown(file); | ||||
|     // } | ||||
|  | ||||
| 	// 上传参数就根据后端的处理而设置了 | ||||
|     // data.append("file", file); | ||||
|     // data.append("name", file.name); | ||||
|     // data.append("group", "pic"); | ||||
|     data.append( 'file', file ); | ||||
|     this.xhr.send(data); | ||||
|   } | ||||
| } | ||||
|  | ||||
| function MyCustomUploadAdapterPlugin(editor) { | ||||
|   editor.plugins.get("FileRepository").createUploadAdapter = (loader) => { | ||||
|     return new MyUploadAdapter(loader); | ||||
|   }; | ||||
| } | ||||
| export { | ||||
|     MyUploadAdapter, | ||||
|     MyCustomUploadAdapterPlugin | ||||
| } | ||||
| @@ -13,6 +13,7 @@ import auth from '@/directive/auth' | ||||
| import { store } from '@/pinia' | ||||
| import App from './App.vue' | ||||
| import { initDom } from './utils/positionToCode' | ||||
| import CKEditor from '@ckeditor/ckeditor5-vue' | ||||
| initDom() | ||||
| /** | ||||
|  * @description 导入加载进度条,防止首屏加载时间过长,用户等待 | ||||
| @@ -31,6 +32,7 @@ const app = createApp(App) | ||||
| app.config.productionTip = false | ||||
|  | ||||
| app | ||||
|   .use(CKEditor) | ||||
|   .use(run) | ||||
|   .use(store) | ||||
|   .use(auth) | ||||
|   | ||||
| @@ -11,6 +11,56 @@ const custom = { | ||||
|       } | ||||
|     } | ||||
|     return arr | ||||
|   }, | ||||
|   getExercisesTypeList() { | ||||
|     return [ | ||||
|       { | ||||
|         label: '单选题', | ||||
|         value2:'single', | ||||
|         value:1 | ||||
|       }, | ||||
|       { | ||||
|         label: '多选题', | ||||
|         value2:'mutil', | ||||
|         value:2 | ||||
|       }, | ||||
|       { | ||||
|         label: '判断题', | ||||
|         value2:'judge', | ||||
|         value:3 | ||||
|       }, | ||||
|       { | ||||
|         label: '填空题', | ||||
|         value2:'application', | ||||
|         value:4 | ||||
|       }, | ||||
|       { | ||||
|         label: '选填题', | ||||
|         value2:'application', | ||||
|         value:5 | ||||
|       } | ||||
|     ] | ||||
|   }, | ||||
|   getExercisesTypeName(type) { | ||||
|     let name = '' | ||||
|     switch (type){ | ||||
|       case 1: | ||||
|         name = '单选题'; | ||||
|         break; | ||||
|       case 2: | ||||
|         name = '多选题'; | ||||
|         break; | ||||
|       case 3: | ||||
|         name = '判断题'; | ||||
|         break; | ||||
|       case 4: | ||||
|         name = '填空题'; | ||||
|         break; | ||||
|       case 5: | ||||
|         name = '选填题'; | ||||
|         break; | ||||
|     } | ||||
|     return name | ||||
|   } | ||||
| } | ||||
| export default custom | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| <script setup> | ||||
| // 引入依赖 | ||||
| // import _ from 'lodash' | ||||
| import api from '@/api/course' | ||||
| import com_api from '@/api/common' | ||||
| import custom from '@/utils/custom' | ||||
| @@ -16,7 +17,7 @@ import chapterCom from '../components/chapter.vue' | ||||
| const path = ref(import.meta.env.VITE_BASE_API) | ||||
| const course_id = ref(0) | ||||
| const active = ref(0) | ||||
| const form = ref({status:1}) | ||||
| const form = ref({status:1,is_boutique:-1,is_audition:-1}) | ||||
| const subjectParams = ref({ | ||||
|     pageIndex:1, | ||||
|     pageSize:100, | ||||
| @@ -30,6 +31,7 @@ const rules = ref({ | ||||
| const ruleFormRef = ref(null) | ||||
| const chapter_info = ref([]) | ||||
| const current_subject = ref('') | ||||
| const isChange = ref(false) | ||||
| // 生命周期 | ||||
| onMounted(() => { | ||||
|   course_id.value = route.params.course_id || 0 | ||||
| @@ -40,15 +42,14 @@ onMounted(() => { | ||||
| }) | ||||
| provide('subjectList', subjectList) | ||||
| provide('current_subject', current_subject) | ||||
| // 方法 | ||||
| async function getCourseInfo() { // 获取课程信息 | ||||
|   const res = await api.getCourse({id:course_id.value}) | ||||
|   if(res.code === 0) { | ||||
|     chapter_info.value = res.data.course_ware_json | ||||
|     form.value = res.data.course | ||||
|     console.log(form.value) | ||||
|   } | ||||
| } | ||||
| // 方法 | ||||
| function stepChangeFunc(type) { | ||||
|   switch (type) { | ||||
|     case 1: // 上一步 | ||||
| @@ -56,7 +57,13 @@ function stepChangeFunc(type) { | ||||
|       break; | ||||
|     case 2: // 下一步 | ||||
|         if(active.value == 0) { // 保存第一步的信息 | ||||
|           submitForm(ruleFormRef.value) | ||||
|           console.log(isChange.value) | ||||
|           if(isChange.value){ | ||||
|             submitForm(ruleFormRef.value) | ||||
|           } | ||||
|           else{ | ||||
|             active.value += 1 | ||||
|           } | ||||
|         } | ||||
|         else{ | ||||
|           active.value +=1 | ||||
| @@ -144,6 +151,7 @@ async function uploadAction(file){//图片上传 非oss | ||||
|     } | ||||
| function handleAvatarSuccess(res) { | ||||
|   form.value.cover = res.data.file.url | ||||
|   handlerChange() | ||||
| } | ||||
| function beforeAvatarUpload(file) { | ||||
|   const isLt05M = file.size / 1024 / 1024 < 20 | ||||
| @@ -159,6 +167,10 @@ function beforeAvatarUpload(file) { | ||||
| function onSubmit() { | ||||
|   router.push({name:'courseManage'}) | ||||
| } | ||||
| function handlerChange(e) { | ||||
|   // console.log(e) | ||||
|   isChange.value = true | ||||
| } | ||||
| </script> | ||||
| <template> | ||||
|   <div> | ||||
| @@ -174,10 +186,10 @@ function onSubmit() { | ||||
|       <!--      step1--> | ||||
|       <el-form ref="ruleFormRef" v-if="active == 0" :model="form" :rules="rules" label-width="120px" style="width: 50%"> | ||||
|         <el-form-item label="课程名称" prop="name"> | ||||
|           <el-input placeholder="请输入课程名称" v-model="form.name" /> | ||||
|           <el-input placeholder="请输入课程名称" v-model="form.name" @change="handlerChange" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="课程分类" prop="subject"> | ||||
|           <el-select v-model="form.subject" placeholder="请选择"> | ||||
|           <el-select v-model="form.subject" placeholder="请选择" @change="handlerChange"> | ||||
|             <el-option | ||||
|               v-for="item in subjectList" | ||||
|               :key="item.id" | ||||
| @@ -200,19 +212,19 @@ function onSubmit() { | ||||
|           </el-upload> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="价格" prop="price"> | ||||
|           <el-input placeholder="请输入课程价格" type="number" v-model="form.price" /> | ||||
|           <el-input @change="handlerChange" placeholder="请输入课程价格" type="number" v-model="form.price" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="课程简介"> | ||||
|           <el-input v-model="form.intro" type="textarea" /> | ||||
|           <el-input @change="handlerChange" v-model="form.intro" type="textarea" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="包含试听"> | ||||
|           <el-switch v-model="form.is_audition" active-text="是" inactive-text="否" :active-value="1" :inactive-value="-1"  /> | ||||
|           <el-switch @change="handlerChange" v-model="form.is_audition" active-text="是" inactive-text="否" :active-value="1" :inactive-value="-1"  /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="设置精品"> | ||||
|           <el-switch v-model="form.is_boutique" active-text="是" inactive-text="否" :active-value="1" :inactive-value="-1"  /> | ||||
|           <el-switch @change="handlerChange" v-model="form.is_boutique" active-text="是" inactive-text="否" :active-value="1" :inactive-value="-1"  /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="课程状态"> | ||||
|           <el-switch v-model="form.status" active-text="上架" inactive-text="下架" :active-value="1" :inactive-value="-1"  /> | ||||
|           <el-switch @change="handlerChange" v-model="form.status" active-text="上架" inactive-text="下架" :active-value="1" :inactive-value="-1"  /> | ||||
|         </el-form-item> | ||||
|         <el-form-item style="display: none"> | ||||
|           <el-button type="primary" @click="submitForm(ruleFormRef)"> | ||||
|   | ||||
| @@ -19,7 +19,8 @@ const router = useRouter() | ||||
| const route = useRoute() | ||||
| import { useUserStore } from '@/pinia/modules/user' | ||||
| const userStore = useUserStore() | ||||
| import exercisesCom from '../components/mediaPool.vue' | ||||
| import mediaCom from '../components/mediaPool.vue' | ||||
| import exercisesCom from '../components/exercisesPool.vue' | ||||
| const props = defineProps(['course_id','chapter_info']) | ||||
| const emit = defineEmits(['reload']) | ||||
| import UploadCommon from '@/components/upload/common.vue' | ||||
| @@ -34,7 +35,8 @@ const chapter_data = ref([]) | ||||
| const dialogChapterChildVisible = ref(false) | ||||
| const chapterChildForm = ref({}) | ||||
| const chapterChildRules = ref({ | ||||
|   name: [{ required: true, message: '请输入章节名称', trigger: 'blur' }] | ||||
|   name: [{ required: true, message: '请输入章节名称', trigger: 'blur' }], | ||||
|   price: [{ required: true, message: '请输入章节价格', trigger: 'blur' }] | ||||
| }) | ||||
| const dialogChapterTitle = ref('') | ||||
| const dialogChapterChildTitle = ref('') | ||||
| @@ -118,7 +120,8 @@ async function enterChapterDialog() { // 提交大章节 | ||||
| function addChapterchildFunc(item) { // 打开新增子章节窗口 | ||||
|   dialogChapterChildTitle.value = '新增子章节' | ||||
|   // current_chapter.value = item | ||||
|   chapterChildForm.value = {pid:item.id} | ||||
|   console.log(item.course_chapter_id) | ||||
|   chapterChildForm.value = {pid:item.course_chapter_id} | ||||
|   dialogChapterChildVisible.value = true | ||||
| } | ||||
| function editChapterChildFunc(item,main_index) { // 打开编辑子章节窗口 | ||||
| @@ -203,20 +206,22 @@ function openExercisesWinFunc() { // 打开媒体库 | ||||
|         </div> | ||||
|         <!--表格数据--> | ||||
|         <div class="lb-table-part" style="margin-bottom: 20px"> | ||||
|           <el-table :data="item.children" > | ||||
|             <el-table-column align="left" label="id" width="60" prop="id" /> | ||||
|           <el-table :data="item.course_sub" > | ||||
|             <el-table-column align="left" label="ID" width="60" prop="course_chapter_id" /> | ||||
|             <el-table-column align="left" label="子章节名称" min-width="60" prop="name" /> | ||||
|             <el-table-column align="left" label="课件名称" min-width="60" prop="url_name" /> | ||||
|  | ||||
|             <el-table-column align="left" label="章节习题" min-width="60" prop="is_contain_exercise"> | ||||
|               <template #default="scope"> | ||||
|                 {{scope.row.is_contain_exercise === 0?'未添加习题':scope.row.is_contain_exercise}} | ||||
|               </template> | ||||
|             </el-table-column> | ||||
|             <el-table-column align="left" label="是否免费" min-width="60"> | ||||
|               <template #default="scope"> | ||||
|                 {{scope.row.is_free === 1? '是':'否'}} | ||||
|               </template> | ||||
|             </el-table-column> | ||||
|             <el-table-column align="left" label="章节价格" min-width="60" prop="price" /> | ||||
|             <!--            <el-table-column align="left" label="是否免费" min-width="60">--> | ||||
|             <!--              <template #default="scope">--> | ||||
|             <!--                {{scope.row.is_free === 1? '是':'否'}}--> | ||||
|             <!--              </template>--> | ||||
|             <!--            </el-table-column>--> | ||||
|             <el-table-column align="left" label="是否展示" min-width="60"> | ||||
|               <template #default="scope"> | ||||
|                 {{scope.row.is_show === 1? '是':'否'}} | ||||
| @@ -280,11 +285,15 @@ function openExercisesWinFunc() { // 打开媒体库 | ||||
|           <!--            class="upload-btn"--> | ||||
|           <!--            @on-success="getFilePath"--> | ||||
|           <!--          />--> | ||||
|           <exercises-com @on-success="getFilePath" :url_name="chapterChildForm.url_name" /> | ||||
|           <media-com @on-success="getFilePath" :url_name="chapterChildForm.url_name" /> | ||||
|           <!--          <el-button size="small" type="primary" @click="openExercisesWinFunc">点击上传</el-button>--> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="习题管理"> | ||||
|           <el-button size="small" @click="chooseChapterChildExercises">添加习题</el-button> | ||||
|           <!--          <el-button size="small" @click="chooseChapterChildExercises">添加习题</el-button>--> | ||||
|           <exercises-com @on-success="getFilePath" :url_name="chapterChildForm.url_name" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="章节价格" prop="price"> | ||||
|           <el-input type="number" v-model="chapterChildForm.price" placeholder="输入章节价格" autocomplete="off" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="章节排序" prop="sort"> | ||||
|           <el-input v-model="chapterChildForm.sort" placeholder="输入整数,排序越小越靠前展示" autocomplete="off" /> | ||||
|   | ||||
							
								
								
									
										103
									
								
								src/view/course/components/exercisesPool.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								src/view/course/components/exercisesPool.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | ||||
| <script setup> | ||||
| // 引入依赖 | ||||
| // import api from '@/api/course' | ||||
| // import com_api from '@/api/common' | ||||
| // import custom from '@/utils/custom' | ||||
| // import WarningBar from '@/components/warningBar/warningBar.vue' | ||||
| import {ref,onMounted,watch,inject  } from 'vue' | ||||
| import { ElMessage, ElMessageBox } from 'element-plus' | ||||
| import { useRouter, useRoute } from 'vue-router' | ||||
| const router = useRouter() | ||||
| const route = useRoute() | ||||
| import { useUserStore } from '@/pinia/modules/user' | ||||
| const userStore = useUserStore() | ||||
| // import chapterCom from '../components/chapter.vue' | ||||
| const props = defineProps(['url_name']) | ||||
| const emit = defineEmits(['on-success']) | ||||
| import { clients, getNowDate } from '@/utils' | ||||
| import custom from '@/utils/custom' | ||||
| // import { getToken } from '@/utils/auth' | ||||
| // 变量 | ||||
| // const headers = ref({ Authorization: 'Bearer ' + getToken() }) | ||||
| const drawer = ref(false) | ||||
| const queryParams =ref({ | ||||
|   pageIndex:1, | ||||
|   pageSize:10, | ||||
|   content:'', | ||||
|   subject:'', | ||||
|   subject_type:'' | ||||
| }) | ||||
| const typeList = custom.getExercisesTypeList() | ||||
| // 生命周期 | ||||
| const subjectList = inject('subjectList') | ||||
| const current_subject = inject('current_subject') | ||||
| onMounted(() => { | ||||
|   // console.log(headers.value) | ||||
| }) | ||||
|  | ||||
| // 方法 | ||||
| function chooseChapterChildExercises() { | ||||
|   drawer.value = true | ||||
| } | ||||
| function onSubmit() { | ||||
|  | ||||
| } | ||||
| function onReset() { | ||||
|   queryParams.value = { | ||||
|     pageIndex:1, | ||||
|     pageSize:10, | ||||
|     name:'' | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| <template> | ||||
|   <div> | ||||
|     <el-button size="small" @click="chooseChapterChildExercises">添加习题</el-button> | ||||
|     <div v-if="url_name">{{url_name}}</div> | ||||
|     <el-drawer v-model="drawer" title="媒体库" size="60%"> | ||||
|       <div class="drawer-section"> | ||||
|         <!--      搜索框--> | ||||
|         <div class="search-box"> | ||||
|           <el-form ref="searchForm" :inline="true" :model="queryParams"> | ||||
|             <el-form-item label="题目"> | ||||
|               <el-input v-model="queryParams.content" placeholder="请输入" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="课程分类"> | ||||
|               <el-select v-model="queryParams.subject" clearable placeholder="请选择"> | ||||
|                 <el-option | ||||
|                   v-for="item in subjectList" | ||||
|                   :key="item.id" | ||||
|                   :label="item.name" | ||||
|                   :value="item.id" | ||||
|                 /> | ||||
|               </el-select> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="题目类型"> | ||||
|               <el-select v-model="queryParams.subject_type" clearable placeholder="请选择"> | ||||
|                 <el-option | ||||
|                   v-for="item in typeList" | ||||
|                   :key="item.value" | ||||
|                   :label="item.label" | ||||
|                   :value="item.value" | ||||
|                 /> | ||||
|               </el-select> | ||||
|             </el-form-item> | ||||
|             <el-form-item> | ||||
|               <el-button size="small" type="primary" icon="search" @click="onSubmit">查询</el-button> | ||||
|               <el-button size="small" icon="refresh" @click="onReset">重置</el-button> | ||||
|             </el-form-item> | ||||
|           </el-form> | ||||
|         </div> | ||||
|         <!--      数据列表--> | ||||
|         <div class="list-box"> | ||||
|  | ||||
|         </div> | ||||
|       </div> | ||||
|     </el-drawer> | ||||
|   </div> | ||||
| </template> | ||||
| <style scoped> | ||||
|   .drawer-section{ | ||||
|     padding: 10px; | ||||
|   } | ||||
| </style> | ||||
| @@ -45,7 +45,7 @@ async function getSubjectList() { | ||||
|     subjectList.value = res.data.records | ||||
|     total.value = res.data.total | ||||
|     subjectList.value = addTreeFormatSubject(subjectList.value) | ||||
|     console.log(subjectList.value) | ||||
|     // console.log(subjectList.value) | ||||
|   } | ||||
| } | ||||
| function addTreeFormatSubject(data) { | ||||
|   | ||||
							
								
								
									
										332
									
								
								src/view/exercisesManage/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										332
									
								
								src/view/exercisesManage/index.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,332 @@ | ||||
|  | ||||
| <script setup> | ||||
| // 引入依赖 | ||||
| import api from '@/api/exercises' | ||||
| import capi from '@/api/course' | ||||
| import custom from '@/utils/custom' | ||||
| // import { toSQLLine } from '@/utils/stringFun' | ||||
| import WarningBar from '@/components/warningBar/warningBar.vue' | ||||
| import ckEditor from '@/components/richText/ckEditor5.vue' | ||||
| import {ref,onMounted } from 'vue' | ||||
| import { ElMessage, ElMessageBox } from 'element-plus' | ||||
| import { useRouter, useRoute } from 'vue-router' | ||||
| const router = useRouter() | ||||
| const route = useRoute() | ||||
| // 变量 | ||||
| const typeList = custom.getExercisesTypeList() | ||||
| const queryParams = ref({ | ||||
|   teacherId:0, | ||||
|   page:1, | ||||
|   pageSize:10, | ||||
|   name:'', | ||||
|   type:'', | ||||
|   subject:'' | ||||
| }) | ||||
| const subjectParams = ref({ | ||||
|     pageIndex:1, | ||||
|     pageSize:100, | ||||
| }) | ||||
| const tableData = ref([]) | ||||
| const subjectList = ref([]) | ||||
| const deleteVisible = ref(false) | ||||
| const course_ids = ref([]) | ||||
| const total = ref(0) | ||||
| const dialogFormVisible = ref(false) | ||||
| const dialogTitle = ref('') | ||||
| const form =ref({}) | ||||
| const rules = ref({ | ||||
|   name: [{ required: true, message: '请输入课程名称', trigger: 'blur' }] | ||||
| }) | ||||
| const course_id = ref(0) | ||||
| const content = ref(null) | ||||
| const options = ref(null) | ||||
| // 生命周期 | ||||
| onMounted(() => { | ||||
|   getExercisesList() | ||||
|   getSubject() | ||||
| }) | ||||
| // 方法 | ||||
| async function getExercisesList() { | ||||
|   const res = await api.getExercisesList(queryParams.value) | ||||
|   if(res.code === 0) { | ||||
|     tableData.value = res.data.records | ||||
|   } | ||||
| } | ||||
| async function getSubject(){ // 获取课程分类 | ||||
|   const res = await capi.getSubjectList(subjectParams.value) | ||||
|   if(res.code === 0) { | ||||
|     subjectList.value = custom.getStdSubject(res.data.records) | ||||
|     // console.log(subjectList.value) | ||||
|   } | ||||
| } | ||||
| function onSubmit() { | ||||
|   getExercisesList() | ||||
| } | ||||
| const onReset = () => { | ||||
|   queryParams.value = { | ||||
|     pageIndex:1, | ||||
|     pageSize:10, | ||||
|     name:'', | ||||
|     status:'', | ||||
|     subject:'' | ||||
|   } | ||||
| } | ||||
| function openDialog(type) { | ||||
|   // let params = {} | ||||
|   switch (type){ | ||||
|     case 'add': | ||||
|       dialogTitle.value = '新增习题' | ||||
|         form.value = {} | ||||
|       break; | ||||
|     case 'edit': | ||||
|       // params.course_id = course_id.value | ||||
|       dialogTitle.value = '编辑习题' | ||||
|       break; | ||||
|   } | ||||
|   dialogFormVisible.value = true | ||||
|   // router.push({name:'addCourse',params}) | ||||
| } | ||||
| async function onDelete() { | ||||
|   console.log(course_ids.value) | ||||
|   const ids = course_ids.value.map(item => item.course_id) | ||||
|   const res = await api.delCourse({ ids }) | ||||
|   if (res.code === 0) { | ||||
|     ElMessage({ | ||||
|       type: 'success', | ||||
|       message: res.msg | ||||
|     }) | ||||
|     // if (tableData.value.length === ids.length && page.value > 1) { | ||||
|     //   page.value-- | ||||
|     // } | ||||
|     deleteVisible.value = false | ||||
|     getExercisesList() | ||||
|   } | ||||
| } | ||||
| const handleSelectionChange = (val) => { | ||||
|   // console.log(val) | ||||
|   course_ids.value = val | ||||
| } | ||||
| function editCourseFunc(row) { | ||||
|   course_id.value = row.course_id | ||||
|   form.value = row | ||||
|   // console.log(JSON.parse(row.question)) | ||||
|   content.value = JSON.parse(row.question).title | ||||
|   options.value =   JSON.parse(row.question).option | ||||
|   openDialog('edit') | ||||
|   console.log(JSON.parse(row.question)) | ||||
| } | ||||
| function deleteCourseFunc(row) { | ||||
|   ElMessageBox.confirm('此操作将永久删除该数据, 是否继续?', '提示', { | ||||
|     confirmButtonText: '确定', | ||||
|     cancelButtonText: '取消', | ||||
|     type: 'warning' | ||||
|   }) | ||||
|   .then(async() => { | ||||
|     const res = await api.delCourse({ | ||||
|           ids:[row.course_id] | ||||
|     }) | ||||
|     if (res.code === 0) { | ||||
|       ElMessage({ | ||||
|         type: 'success', | ||||
|         message: '删除成功!' | ||||
|       }) | ||||
|       // if (tableData.value.length === 1 && page.value > 1) { | ||||
|       //   page.value-- | ||||
|       // } | ||||
|       getExercisesList() | ||||
|     } | ||||
|   },() => { | ||||
|   }) | ||||
| } | ||||
| function handleCurrentChange(val) { | ||||
|   queryParams.value.pageIndex = val | ||||
|   getExercisesList() | ||||
| } | ||||
| function handleSizeChange(val) { | ||||
|   queryParams.value.pageSize = val | ||||
|   getExercisesList() | ||||
| } | ||||
| function closeDialog(){ | ||||
|   dialogFormVisible.value = false | ||||
| } | ||||
| function enterDialog() { | ||||
|   console.log(content.value) | ||||
| } | ||||
| function viewCourseFunc(row) { // 查看课程 | ||||
|   router.push({name:'viewCourse',params:{course_id:row.course_id}}) | ||||
| } | ||||
| function getExercisesName(row) { | ||||
|   // console.log(JSON.parse(row.question)) | ||||
|   return JSON.parse(row.question).title | ||||
| } | ||||
| </script> | ||||
| <template> | ||||
|   <div> | ||||
|     <!--    搜索框--> | ||||
|     <div class="gva-search-box"> | ||||
|       <el-form ref="searchForm" :inline="true" :model="queryParams"> | ||||
|         <el-form-item label="题目名称"> | ||||
|           <el-input v-model="queryParams.name" placeholder="根据题目名称进行查询" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="课程分类"> | ||||
|           <el-select v-model="queryParams.subject" clearable placeholder="请选择"> | ||||
|             <el-option | ||||
|               v-for="item in subjectList" | ||||
|               :key="item.id" | ||||
|               :label="item.name" | ||||
|               :value="item.name" | ||||
|             /> | ||||
|           </el-select> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="题型"> | ||||
|           <el-select v-model="queryParams.type" clearable placeholder="请选择"> | ||||
|             <el-option | ||||
|               v-for="item in typeList" | ||||
|               :key="item.value" | ||||
|               :label="item.label" | ||||
|               :value="item.value" | ||||
|             /> | ||||
|           </el-select> | ||||
|         </el-form-item> | ||||
|         <el-form-item> | ||||
|           <el-button size="small" type="primary" icon="search" @click="onSubmit">查询</el-button> | ||||
|           <el-button size="small" icon="refresh" @click="onReset">重置</el-button> | ||||
|         </el-form-item> | ||||
|       </el-form> | ||||
|     </div> | ||||
|     <!--    表格数据--> | ||||
|     <div class="gva-table-box"> | ||||
|       <!--      批量操作--> | ||||
|       <div class="gva-btn-list"> | ||||
|         <el-button size="small" type="primary" icon="plus" @click="openDialog('add')">新增</el-button> | ||||
|         <el-popover v-model="deleteVisible" placement="top" width="160"> | ||||
|           <p>确定要删除吗?</p> | ||||
|           <div style="text-align: right; margin-top: 8px;"> | ||||
|             <el-button size="small" type="primary" link @click="deleteVisible = false">取消</el-button> | ||||
|             <el-button size="small" type="primary" @click="onDelete">确定</el-button> | ||||
|           </div> | ||||
|           <template #reference> | ||||
|             <el-button icon="delete" size="small" type="danger" :disabled="!course_ids.length" style="margin-left: 10px;" @click="deleteVisible = true">删除</el-button> | ||||
|           </template> | ||||
|         </el-popover> | ||||
|       </div> | ||||
|       <!--      数据列表--> | ||||
|       <el-table :data="tableData" @selection-change="handleSelectionChange"> | ||||
|         <el-table-column | ||||
|           type="selection" | ||||
|           width="55" | ||||
|         /> | ||||
|         <el-table-column align="left" label="ID" min-width="60" prop="question_id" sortable="custom" /> | ||||
|         <el-table-column align="left" label="题型" min-width="150" prop="name" > | ||||
|           <template #default="scope"> | ||||
|             {{custom.getExercisesTypeName(scope.row.type)}} | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column align="left" label="科目" min-width="150" prop="subject" /> | ||||
|         <el-table-column align="left" label="题目" min-width="150" > | ||||
|           <template #default="scope"> | ||||
|             <!--            {{getExercisesName(scope.row)}}--> | ||||
|             <div v-html="getExercisesName(scope.row)"></div> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column align="left" label="创建者" min-width="150" prop="teacher_id" /> | ||||
|         <el-table-column align="left" label="创建时间" min-width="150" prop="createdAt" /> | ||||
|         <el-table-column align="left" fixed="right" label="操作" width="200"> | ||||
|           <template #default="scope"> | ||||
|             <!--            <el-button--> | ||||
|             <!--              icon="view"--> | ||||
|             <!--              size="small"--> | ||||
|             <!--              type="primary"--> | ||||
|             <!--              link--> | ||||
|             <!--              @click="viewCourseFunc(scope.row)"--> | ||||
|             <!--            >查看</el-button>--> | ||||
|             <el-button | ||||
|               icon="edit" | ||||
|               size="small" | ||||
|               type="primary" | ||||
|               link | ||||
|               @click="editCourseFunc(scope.row)" | ||||
|             >编辑</el-button> | ||||
|             <el-button | ||||
|               icon="delete" | ||||
|               size="small" | ||||
|               type="danger" | ||||
|               link | ||||
|               @click="deleteCourseFunc(scope.row)" | ||||
|             >删除</el-button> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </el-table> | ||||
|       <div class="gva-pagination"> | ||||
|         <el-pagination | ||||
|           :current-page="queryParams.pageIndex" | ||||
|           :page-size="queryParams.pageSize" | ||||
|           :page-sizes="[10, 30, 50, 100]" | ||||
|           :total="total" | ||||
|           layout="total, sizes, prev, pager, next, jumper" | ||||
|           @current-change="handleCurrentChange" | ||||
|           @size-change="handleSizeChange" | ||||
|         /> | ||||
|       </div> | ||||
|  | ||||
|     </div> | ||||
|     <el-dialog v-model="dialogFormVisible" :before-close="closeDialog" :title="dialogTitle"> | ||||
|       <el-form ref="apiForm" :model="form" :rules="rules" label-width="80px"> | ||||
|         <el-form-item label="科目" prop="subject"> | ||||
|           <el-select v-model="form.subject" clearable placeholder="请选择"> | ||||
|             <el-option | ||||
|               v-for="item in subjectList" | ||||
|               :key="item.id" | ||||
|               :label="item.name" | ||||
|               :value="item.id" | ||||
|             /> | ||||
|           </el-select> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="题型" prop="type"> | ||||
|           <el-select v-model="form.type" clearable placeholder="请选择"> | ||||
|             <el-option | ||||
|               v-for="item in typeList" | ||||
|               :key="item.value" | ||||
|               :label="item.label" | ||||
|               :value="item.value" | ||||
|             /> | ||||
|           </el-select> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="题目内容" > | ||||
|           <ckEditor v-model="content" :content="content" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="分值" > | ||||
|           <el-input v-model="form.score" placeholder="请输入分值" /> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="答案" > | ||||
|           <!--          <el-input v-model="form.score" placeholder="请输入分值" />--> | ||||
|           <view class="options-box" v-if="options"> | ||||
|             <view class="option-item"> | ||||
|               <ckEditor v-model="content" :content="content" /> | ||||
|               <el-icon><Minus /></el-icon> | ||||
|             </view> | ||||
|           </view> | ||||
|           <el-button>添加答案</el-button> | ||||
|         </el-form-item> | ||||
|  | ||||
|       </el-form> | ||||
|       <template #footer> | ||||
|         <div class="dialog-footer"> | ||||
|           <el-button size="small" @click="closeDialog">取 消</el-button> | ||||
|           <el-button size="small" type="primary" @click="enterDialog">确 定</el-button> | ||||
|         </div> | ||||
|       </template> | ||||
|     </el-dialog> | ||||
|   </div> | ||||
| </template> | ||||
| <style scoped lang="scss"> | ||||
|   .button-box { | ||||
|     padding: 10px 20px; | ||||
|     .el-button { | ||||
|       float: right; | ||||
|     } | ||||
|   } | ||||
|   .warning { | ||||
|     color: #dc143c; | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										9497
									
								
								yarn-error.log
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9497
									
								
								yarn-error.log
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Reference in New Issue
	
	Block a user