Przeglądaj źródła

feat:修改编辑作业及课程的文件上传功能以及写作时间限制问题

白白 2 lat temu
rodzic
commit
fd35df7c08

+ 1 - 0
src/apis/assignment.ts

@@ -19,6 +19,7 @@ const assignmentApis = {
         })
     },
     createAssignment(courseId:number, assignmentDTO: AssignmentDTO){
+        console.log(assignmentDTO)
         return axiosInstance.post(`${ASSIGNMENT_PREFIX}`, assignmentDTO, {
             params: {
                 courseId

+ 18 - 0
src/apis/file.ts

@@ -0,0 +1,18 @@
+import axiosInstance from "@/apis/axios.config";
+
+const FILE_PREFIX = "/api/file"
+
+const fileApis = {
+    uploadFile(file) {
+        const formData = new FormData();
+        formData.append('file', file);
+
+        return axiosInstance.post(`${FILE_PREFIX}`, formData, {
+            headers: {
+                'Content-Type': 'multipart/form-data'
+            }
+        });
+    },
+}
+
+export default fileApis

+ 3 - 1
src/apis/index.ts

@@ -6,6 +6,7 @@ import aiApis from "@/apis/ai";
 import engagementApis from "@/apis/engagement";
 import assignmentApis from "@/apis/assignment";
 import courseApis from "@/apis/course";
+import fileApis from "@/apis/file";
 
 
 const apis = {
@@ -16,7 +17,8 @@ const apis = {
     ...aiApis,
     ...dictApis,
     ...assignmentApis,
-    ...courseApis
+    ...courseApis,
+    ...fileApis
 }
 
 // hook

+ 14 - 0
src/types/vo.ts

@@ -77,6 +77,7 @@ export interface IAssignmentTableColumn {
     title: string;
     dataIndex: 'desc' | 'publisher' | 'startDate' | 'endDate' | 'details' | 'writing' | 'assignmentId' | 'teacherId';
     key: 'desc' | 'publisher' | 'startDate' | 'endDate' | 'details' | 'writing' | 'assignmentId' | 'teacherId';
+    width: number
 }
 
 export interface IAssignmentTableItem {
@@ -112,3 +113,16 @@ export interface CourseVO {
     description: string;
 }
 
+export interface CourseDetailVO {
+    courseId: number;
+    courseName: string;
+    teacherIds: number[];
+    teacherNames: string[];
+    courseImages: string[];
+    targetGrade: string;
+    startTime: string;
+    endTime: string;
+    createTime: string;
+    description: string;
+}
+

+ 81 - 2
src/views/CoursePage/CoursePage.vue

@@ -67,6 +67,33 @@
       <el-form-item label="截止时间">
         <el-date-picker v-model="newCourse.endTime" type="datetime" placeholder="截止时间" style="width: 180px"/>
       </el-form-item>
+<!--      <el-form-item label="课程图片">-->
+<!--        <el-upload-->
+<!--            ref="uploadRef"-->
+<!--            drag-->
+<!--            action= "http://127.0.0.1:8080/api/file"-->
+<!--            multiple-->
+<!--            v-model:file-list="fileList"-->
+<!--            :limit="1"-->
+<!--            :on-success="handleSuccess"-->
+<!--            :on-error="handleError"-->
+<!--            :on-exceed="handleExceed"-->
+<!--            :on-change="handleChange"-->
+<!--            list-type="picture-card"-->
+<!--            accept=".png, .jpg"-->
+<!--            :auto-upload="false"-->
+<!--        >-->
+<!--          <el-icon class="el-icon&#45;&#45;upload"><upload-filled /></el-icon>-->
+<!--          <div class="el-upload__text">-->
+<!--            拖拽上传或<em>点击此处上传</em>-->
+<!--          </div>-->
+<!--          <template #tip>-->
+<!--            <div class="el-upload__tip">-->
+<!--              jpg/png 文件不大于 500kb-->
+<!--            </div>-->
+<!--          </template>-->
+<!--        </el-upload>-->
+<!--      </el-form-item>-->
     </el-form>
     <template #footer>
       <div class="dialog-footer">
@@ -82,10 +109,17 @@
   import {useStore} from "@/store";
   import {inject, onMounted, reactive, ref} from "vue";
   import type {CourseVO} from "@/types/vo";
-  import {Refresh, Search, ZoomIn} from "@element-plus/icons-vue";
+  import {Refresh, Search, UploadFilled, ZoomIn} from "@element-plus/icons-vue";
   import router from "@/router";
   import type {CourseDTO} from "@/types/dto";
-  import {ElNotification} from "element-plus";
+  import {
+    ElMessage,
+    ElNotification,
+    type UploadFile,
+    type UploadFiles,
+    type UploadProps,
+    type UploadUserFile
+  } from "element-plus";
   import type {CourseQuery} from "@/types/query";
   import {useFormatDate} from "@/hooks/useFormatDate";
 
@@ -96,6 +130,7 @@
   const role:'teachers' | 'student' = store.user.role === 'STUDENT' ?   'student':'teachers';
 
   let visible = ref(false)
+  let uploadRef = ref()
 
   const queryInfo = reactive({
     pageNow: 1,
@@ -135,6 +170,42 @@
     semester:null,
   })
 
+  // 用于编辑课程展示预览图片
+  const fileList = ref<UploadUserFile[]>([])
+
+  const handleSuccess: UploadProps['onSuccess'] = (response: any, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
+    newCourse.courseImages[0] = response.data
+  }
+
+  const handleError: UploadProps['onError'] = (error: Error, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
+    console.log(error, uploadFile, uploadFiles)
+  }
+
+  const handleExceed = (files, fileList) => {
+    // console.log(files)
+    uploadRef.value.clearFiles()  //清空上传文件(限制一个,所以直接清空即可)
+    const file = files[0]
+    uploadRef.value.handleStart(file)  //重新上传
+  }
+
+  //选择文件
+  const handleChange = (file,fileList) => {
+    // console.log(file)
+    const fileImgType = file.name.match(/\.([^\.]+)$/)[1];  //匹配文件格式(最后一个'.'后的格式)或者匹配file.raw.type
+    const isImageType = ['png','jpg'];
+    const isLt5KB = file.size / 1024  < 500;  //判断图片格式与大小
+    if (isImageType.indexOf(fileImgType)==-1) {
+      ElMessage.error('文件仅支持png、jpg格式')  //限制文件类型
+      uploadRef.value.clearFiles()  //清空上传文件
+      return false;
+    }
+    if (!isLt5KB) {
+      ElMessage.error('文件不能超过500kb!')  //限制文件大小
+      uploadRef.value.clearFiles()  //清空上传文件
+      return false;
+    }
+  }
+
   let courseName = ref('')
   const handleSearch = () => {
     if (role === 'student') {
@@ -170,6 +241,8 @@
   const handleSubmit = () => {
     newCourse.endTime = formatDate(newCourse.endTime)
     newCourse.startTime = formatDate(newCourse.startTime)
+    uploadRef.value.submit()
+    console.log(newCourse)
     apis.createCourse(newCourse)
         .then((res:any) => {
           if(res.data.code===200) {
@@ -275,3 +348,9 @@ export default {
   name: "CoursePage"
 }
 </script>
+
+<style scoped>
+:deep(.el-upload-dragger) {
+  padding: 0px 0px;
+}
+</style>

+ 208 - 22
src/views/CourseSquare/component/CourseDetails/component/CourseHomeworkTable.vue

@@ -10,20 +10,31 @@
     </template>
     <template v-if="props.tableData.length > 0">
       <el-table :data="props.tableData" stripe style="width: 100%" height="100%">
+        <el-table-column type="index"></el-table-column>
         <el-table-column
             v-for="column in props.columns"
+            :key="column.key"
             :prop="column.dataIndex"
             :label="column.title"
+            :width="column.width"
         >
         </el-table-column>
-        <el-table-column label="详情">
+        <el-table-column label="详情" width="60">
           <template #default="scope">
-            <el-button color="#888" circle @click="openEditor(scope.row.descriptionFile, scope.row.assignmentName)"/>
+            <el-button color="#597d3b" circle @click="openEditor(scope.row.descriptionFile, scope.row.assignmentName)">
+              <el-icon :size="18">
+                <Search />
+              </el-icon>
+            </el-button>
           </template>
         </el-table-column>
-        <el-table-column :label="role == 'teachers'? '编辑':'写作'">
+        <el-table-column :label="role == 'teachers'? '编辑':'写作'" width="60">
           <template #default="scope">
-            <el-button color="#888" circle @click="handleFunctionButton(scope.row.assignmentId)" :disabled="props.disabled || isDisabled(scope.row.teacherId)"/>
+            <el-button color="#597d3b" circle @click="handleFunctionButton(scope.row.assignmentId)" :disabled="props.disabled || isDisabled(scope.row.teacherId, scope.row.endDate)">
+              <el-icon :size="18">
+                <Edit />
+              </el-icon>
+            </el-button>
           </template>
         </el-table-column>
       </el-table>
@@ -34,7 +45,7 @@
   </el-card>
 
   <el-dialog v-model="dialogConfig.visible" :title="dialogConfig.title">
-    <el-form :model="newAssignmentInfo">
+    <el-form :model="newAssignmentInfo" label-width="auto">
       <!--      <el-form-item label="课程图片">-->
       <el-form-item label="作业名称">
         <el-input v-model="newAssignmentInfo.assignmentName" placeholder="请输入名称"></el-input>
@@ -42,18 +53,83 @@
       <el-form-item label="作业描述">
         <el-input v-model="newAssignmentInfo.description" placeholder="请输入描述"></el-input>
       </el-form-item>
-      <el-form-item label="描述文件">
-        <el-input v-model="newAssignmentInfo.descriptionFile" placeholder="请输入文件地址"></el-input>
-      </el-form-item>
-      <el-form-item label="课程图片">
-        <el-input v-model="newAssignmentInfo.attachments[0]" placeholder="请输入图片链接"></el-input>
-      </el-form-item>
       <el-form-item label="开始时间">
         <el-date-picker v-model="newAssignmentInfo.startTime" type="datetime" placeholder="截止时间" style="width: 180px"/>
       </el-form-item>
       <el-form-item label="截止时间">
         <el-date-picker v-model="newAssignmentInfo.endTime" type="datetime" placeholder="截止时间" style="width: 180px"/>
       </el-form-item>
+      <el-form-item label="描述文件" v-if="dialogConfig.type == 'edit'">
+        <el-upload
+            ref="uploadDescribeRef"
+            action= "http://127.0.0.1:8080/api/file"
+            multiple
+            v-model:file-list="describeFileList"
+            :limit="1"
+            :on-success="handleDescribeSuccess"
+            :on-error="handleDescribeError"
+            :on-exceed="handleDescribeExceed"
+            :on-change="handleDescribeChange"
+            accept=".doc, .docx"
+            :auto-upload="false"
+        >
+          <el-button type="primary">点击上传</el-button>
+          <template #tip>
+            <div class="el-upload__tip">
+              doc/docx 文件不大于 500kb
+            </div>
+          </template>
+        </el-upload>
+      </el-form-item>
+      <el-form-item label="附件" v-if="dialogConfig.type == 'edit'">
+        <el-upload
+            ref="uploadPictureRef"
+            action= "http://127.0.0.1:8080/api/file"
+            multiple
+            v-model:file-list="pictureFileList"
+            :limit="1"
+            :on-success="handlePictureSuccess"
+            :on-error="handlePictureError"
+            :on-exceed="handlePictureExceed"
+            :on-change="handlePictureChange"
+            accept=".doc, .docx"
+            :auto-upload="false"
+        >
+          <el-button type="primary">点击上传</el-button>
+          <template #tip>
+            <div class="el-upload__tip">
+              doc/docx 文件不大于 500kb
+            </div>
+          </template>
+        </el-upload>
+      </el-form-item>
+<!--      <el-form-item label="作业图片" v-if="dialogConfig.type == 'edit'">-->
+<!--        <el-upload-->
+<!--            ref="uploadPictureRef"-->
+<!--            drag-->
+<!--            action= "http://127.0.0.1:8080/api/file"-->
+<!--            multiple-->
+<!--            v-model:file-list="pictureFileList"-->
+<!--            :limit="1"-->
+<!--            :on-success="handlePictureSuccess"-->
+<!--            :on-error="handlePictureError"-->
+<!--            :on-exceed="handlePictureExceed"-->
+<!--            :on-change="handlePictureChange"-->
+<!--            list-type="picture-card"-->
+<!--            accept=".png, .jpg"-->
+<!--            :auto-upload="false"-->
+<!--        >-->
+<!--          <el-icon class="el-icon&#45;&#45;upload"><upload-filled /></el-icon>-->
+<!--          <div class="el-upload__text">-->
+<!--            拖拽上传或<em>点击此处上传</em>-->
+<!--          </div>-->
+<!--          <template #tip>-->
+<!--            <div class="el-upload__tip">-->
+<!--              jpg/png 文件不大于 500kb-->
+<!--            </div>-->
+<!--          </template>-->
+<!--        </el-upload>-->
+<!--      </el-form-item>-->
     </el-form>
     <template #footer>
       <div class="dialog-footer">
@@ -72,11 +148,18 @@ import {defineProps, inject, onMounted, reactive, ref} from 'vue';
   import router from "@/router";
   import type {AssignmentDTO} from "@/types/dto";
   import useApis from "@/apis";
-  import {ElNotification} from "element-plus";
+  import {
+  ElMessage,
+  ElNotification,
+  type UploadFile,
+  type UploadFiles,
+  type UploadProps,
+  type UploadUserFile
+} from "element-plus";
   import {useFormatDate} from "@/hooks/useFormatDate";
-  import assignment from "@/apis/assignment";
-import ViewsWordEditor from "@/components/ViewsWordEditor/ViewsWordEditor.vue";
-import {useStore} from "@/store";
+  import ViewsWordEditor from "@/components/ViewsWordEditor/ViewsWordEditor.vue";
+  import {useStore} from "@/store";
+  import {Search, Edit, UploadFilled, Plus} from "@element-plus/icons-vue"
 
   const props = defineProps<{
     tableData: IAssignmentTableItem[],
@@ -91,6 +174,81 @@ import {useStore} from "@/store";
   const store = useStore()
   const doRefresh:Function = inject("reload")
   const {formatDate} = useFormatDate()
+  let uploadDescribeRef = ref()
+  let uploadPictureRef = ref()
+
+  // 用于编辑课程展示预览图片
+  const describeFileList = ref<UploadUserFile[]>([])
+  const pictureFileList = ref<UploadUserFile[]>([])
+
+  const handleDescribeSuccess = (response: any, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
+    Object.assign(newAssignmentInfo, {
+      assignmentName: newAssignmentInfo.assignmentName,
+      description: newAssignmentInfo.description,
+      descriptionFile: response.data,
+      attachments: newAssignmentInfo.attachments == null? ['']:newAssignmentInfo.attachments,
+      startTime: newAssignmentInfo.startTime,
+      endTime: newAssignmentInfo.endTime
+    })
+  }
+  const handlePictureSuccess = (response: any, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
+    newAssignmentInfo.attachments[0] = response.data
+  }
+
+  const handleDescribeError: UploadProps['onError'] = (error: Error, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
+    console.log(error, uploadFile, uploadFiles)
+  }
+  const handlePictureError: UploadProps['onError'] = (error: Error, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
+    console.log(error, uploadFile, uploadFiles)
+  }
+
+  const handleDescribeExceed = (files, fileList) => {
+    // console.log(files)
+    uploadDescribeRef.value.clearFiles()  //清空上传文件(限制一个,所以直接清空即可)
+    const file = files[0]
+    uploadDescribeRef.value.handleStart(file)  //重新上传
+  }
+  const handlePictureExceed = (files, fileList) => {
+    // console.log(files)
+    uploadPictureRef.value.clearFiles()  //清空上传文件(限制一个,所以直接清空即可)
+    const file = files[0]
+    uploadPictureRef.value.handleStart(file)  //重新上传
+  }
+
+  //选择文件
+  const handleDescribeChange = (file,fileList) => {
+    // console.log(file)
+    const fileImgType = file.name.match(/\.([^\.]+)$/)[1];  //匹配文件格式(最后一个'.'后的格式)或者匹配file.raw.type
+    const isImageType = ['doc','docx'];
+    const isLt500KB = file.size / 1024  < 500;  //判断图片格式与大小
+    if (isImageType.indexOf(fileImgType)==-1) {
+      ElMessage.error('文件仅支持png、jpg格式')  //限制文件类型
+      uploadDescribeRef.value.clearFiles()  //清空上传文件
+      return false;
+    }
+    if (!isLt500KB) {
+      ElMessage.error('文件不能超过500kb!')  //限制文件大小
+      uploadDescribeRef.value.clearFiles()  //清空上传文件
+      return false;
+    }
+  }
+  const handlePictureChange = (file,fileList) => {
+    // console.log(file)
+    const fileImgType = file.name.match(/\.([^\.]+)$/)[1];  //匹配文件格式(最后一个'.'后的格式)或者匹配file.raw.type
+    // const isImageType = ['png','jpg'];
+    const isImageType = ['doc','docx'];
+    const isLt500KB = file.size / 1024  < 500;  //判断图片格式与大小
+    if (isImageType.indexOf(fileImgType)==-1) {
+      ElMessage.error('文件仅支持png、jpg格式')  //限制文件类型
+      uploadDescribeRef.value.clearFiles()  //清空上传文件
+      return false;
+    }
+    if (!isLt500KB) {
+      ElMessage.error('文件不能超过500kb!')  //限制文件大小
+      uploadDescribeRef.value.clearFiles()  //清空上传文件
+      return false;
+    }
+  }
 
   const dialogConfig = reactive({
     type: "",
@@ -183,6 +341,7 @@ const openEditor = (url: string, title: string) => {
       startTime: assignment.startTime,
       endTime: assignment.endTime
     })
+    // console.log("获取作业信息", newAssignmentInfo)
   }
 
   // 用于记录当前编辑的作业的id
@@ -194,6 +353,7 @@ const openEditor = (url: string, title: string) => {
       apis.getAssignmentById(assignmentId)
           .then((res:any) => {
             setNewAssignmentInfo(res.data.data)
+            // console.log("功能按钮方法内部",newAssignmentInfo)
             IAssignmentId.value = res.data.data.assignmentId
           })
       changeDialog('edit')
@@ -201,17 +361,22 @@ const openEditor = (url: string, title: string) => {
   }
 
   const handleWriting = (assignmentId:number) => {
-    router.push(`/home/assignment/${assignmentId}/edit`);
+    router.push(`/home/homeworkDetail/${assignmentId}`);
     // Location.reload()
   }
 
 
-  const handleSubmit = () => {
+  const handleSubmit = async () => {
+    // console.log("提交方法最开始",newAssignmentInfo)
     newAssignmentInfo.endTime = formatDate(newAssignmentInfo.endTime);
     newAssignmentInfo.startTime = formatDate(newAssignmentInfo.startTime);
+    await uploadDescribeRef.value.submit()
+    await uploadPictureRef.value.submit()
+    // console.log("提交方法,请求前",newAssignmentInfo)
     if(dialogConfig.type === 'add'){
       apis.createAssignment(props.courseId, newAssignmentInfo)
           .then((res) => {
+            console.log("新增作业请求内部",newAssignmentInfo)
             if(res.data.code===200) {
               ElNotification({
                 title: '新增成功',
@@ -224,20 +389,24 @@ const openEditor = (url: string, title: string) => {
               })
             }
             dialogConfig.visible = false
-            cleanNewAssignmentInfo()
-
+            // cleanNewAssignmentInfo()
           })
           .catch((err) => {
             console.log(err)
           })
     } else if(dialogConfig.type === 'edit'){
+      // console.log("编辑作业请求前一刻",newAssignmentInfo)
       apis.updateAssignment(IAssignmentId.value, newAssignmentInfo)
           .then((res:any) => {
+            // console.log("编辑作业请求内部",newAssignmentInfo)
             if(res.data.code===200) {
               ElNotification({
                 title: '修改成功',
                 type: 'success',
               })
+              // console.log("编辑作业请求内部22",newAssignmentInfo)
+              setTimeout(() => apis.updateAssignment(IAssignmentId.value, newAssignmentInfo), 300)
+              // console.log("编辑作业请求内部33",newAssignmentInfo)
             }else {
               ElNotification({
                 title: '修改失败',
@@ -245,7 +414,7 @@ const openEditor = (url: string, title: string) => {
               })
             }
             dialogConfig.visible = false
-            cleanNewAssignmentInfo()
+            // cleanNewAssignmentInfo()
           })
           .catch((err) => {
             console.log(err)
@@ -254,8 +423,15 @@ const openEditor = (url: string, title: string) => {
     doRefresh();
   }
 
-  const isDisabled = (teacherId:string) => {
-    return props.role == 'teachers' && +teacherId != store.user.id;
+  const isDisabled = (teacherId: string, endDate: string) => {
+    if(props.role == 'teachers'){// 是教师且不是作业发布人则禁用
+      if(+teacherId != store.user.id){
+        return true
+      }
+    } else { // 是学生且超时则禁用
+      if(new Date() > new Date(endDate)) return true
+    }
+    return false
   }
 
   onMounted(() => {
@@ -268,3 +444,13 @@ export default {
   name: "CourseHomeworkTable"
 }
 </script>
+
+<style scoped>
+  .el-icon.avatar-uploader-icon {
+    font-size: 28px;
+    color: #8c939d;
+    width: 178px;
+    height: 178px;
+    text-align: center;
+  }
+</style>

+ 109 - 24
src/views/CourseSquare/component/CourseDetails/index.vue

@@ -14,7 +14,7 @@
           {{dataForm.courseName}}
         </div>
         <div class="item">
-          任课老师:{{dataForm.teacherIds?.join(",")}}
+          任课老师:{{dataForm.teacherNames?.join(",")}}
         </div>
         <div class="item">
           目标学生:{{dataForm.targetGrade}}
@@ -28,7 +28,7 @@
             <el-button color="#597d3b" @click="enroll">加入课程</el-button>
           </template>
           <template v-if="showEdit && role == 'teachers'">
-            <el-button color="#597d3b" @click="visible = true">编辑课程</el-button>
+            <el-button color="#597d3b" @click="visible = true; fileList[0] = {name: '壁纸', url: newCourseInfo.courseImages[0]}">编辑课程</el-button>
           </template>
         </div>
       </div>
@@ -50,7 +50,7 @@
   </div>
 
   <el-dialog v-model="visible" title="编辑课程">
-    <el-form :model="newCourseInfo">
+    <el-form :model="newCourseInfo" label-width="auto">
 <!--      <el-form-item label="课程图片">-->
       <el-form-item label="课程名称">
         <el-input v-model="newCourseInfo.courseName" placeholder="请输入名称"></el-input>
@@ -61,9 +61,6 @@
       <el-form-item label="描述">
         <el-input v-model="newCourseInfo.description" placeholder="请输入描述"></el-input>
       </el-form-item>
-      <el-form-item label="课程图片">
-        <el-input v-model="newCourseInfo.courseImages[0]" placeholder="请输入图片链接"></el-input>
-      </el-form-item>
       <el-form-item label="开始时间">
         <el-date-picker v-model="newCourseInfo.startTime" type="datetime" placeholder="截止时间" style="width: 180px"/>
       </el-form-item>
@@ -73,6 +70,36 @@
       <el-form-item label="选课码">
         <el-input v-model="newCourseInfo.enrollCode" placeholder="请输入选课码"></el-input>
       </el-form-item>
+<!--      <el-form-item label="课程图片">-->
+<!--        <el-input v-model="newCourseInfo.courseImages[0]" placeholder="请输入图片链接"></el-input>-->
+<!--      </el-form-item>-->
+      <el-form-item label="课程图片">
+        <el-upload
+            ref="uploadRef"
+            drag
+            action= "http://127.0.0.1:8080/api/file"
+            multiple
+            v-model:file-list="fileList"
+            :limit="1"
+            :on-success="handleSuccess"
+            :on-error="handleError"
+            :on-exceed="handleExceed"
+            :on-change="handleChange"
+            list-type="picture-card"
+            accept=".png, .jpg"
+            :auto-upload="false"
+        >
+          <el-icon class="el-icon--upload"><upload-filled /></el-icon>
+          <div class="el-upload__text">
+            拖拽上传或<em>点击此处上传</em>
+          </div>
+          <template #tip>
+            <div class="el-upload__tip">
+              jpg/png 文件不大于 500kb
+            </div>
+          </template>
+        </el-upload>
+      </el-form-item>
     </el-form>
     <template #footer>
       <div class="dialog-footer">
@@ -85,16 +112,27 @@
 
 <script setup lang="ts">
 import {onMounted, reactive, ref} from 'vue';
-import {ElTabs, ElTabPane, ElTable, ElTableColumn, ElAvatar, ElMessage, ElNotification} from 'element-plus';
+import {
+  ElTabs,
+  ElTabPane,
+  ElTable,
+  ElTableColumn,
+  ElAvatar,
+  ElMessage,
+  ElNotification,
+  type UploadFiles, type UploadFile
+} from 'element-plus';
 import './index.scss'
-import type {CourseVO, IAssignment, IAssignmentTableColumn, IAssignmentTableItem} from "@/types/vo";
+import type {CourseDetailVO, CourseVO, IAssignment, IAssignmentTableColumn, IAssignmentTableItem} from "@/types/vo";
 import {useRoute} from "vue-router";
 import useApis from "@/apis";
 import CourseHomeworkTable from "@/views/CourseSquare/component/CourseDetails/component/CourseHomeworkTable.vue";
 import type {AssignmentQuery} from "@/types/query";
 import {useStore} from "@/store";
 import type {CourseUpdateDTO, EnrollDTO} from "@/types/dto";
-import {useFormatDate} from "@/hooks/useFormatDate";
+import {UploadFilled} from "@element-plus/icons-vue"
+import type { UploadProps, UploadUserFile } from 'element-plus'
+import axiosInstance from "@/apis/axios.config";
 
 const apis = useApis()
 const store = useStore()
@@ -107,12 +145,14 @@ let showCode = ref(true)
 let enrollCode = ref(null)
 let showEdit = ref(false)
 let visible = ref(false)
+let uploadRef = ref()
 
 // 用于展示课程信息
-let dataForm = reactive<CourseVO>({
+let dataForm = reactive<CourseDetailVO>({
   courseId: null,
   courseName: '',
   teacherIds: [],
+  teacherNames: [],
   courseImages: [''],
   targetGrade: '',
   startTime: '',
@@ -148,31 +188,66 @@ const items = ref([
 ]);
 
 const columns = ref<IAssignmentTableColumn[]>([
-  {
-    title: '作业id',
-    dataIndex: 'assignmentId',
-    key: 'assignmentId',
-  },
   {
     title: '作业名称',
     dataIndex: 'desc',
     key: 'desc',
-  },
-  {
-    title: '发布人',
-    dataIndex: 'publisher',
-    key: 'publisher',
+    width: 250
   },
   {
     title: '截止日期',
     dataIndex: 'endDate',
     key: 'endDate',
+    width: 180
+  },
+  {
+    title: '发布人',
+    dataIndex: 'publisher',
+    key: 'publisher',
+    width: 100
   },
 ]);
 
 // 用于展示课程所含的作业
 let homeworkList = ref<IAssignmentTableItem[]>([]);
 
+// 用于编辑课程展示预览图片
+const fileList = ref<UploadUserFile[]>([])
+
+const handleSuccess: UploadProps['onSuccess'] = (response: any, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
+  newCourseInfo.courseImages[0] = response.data
+}
+
+const handleError: UploadProps['onError'] = (error: Error, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
+  console.log(error, uploadFile, uploadFiles)
+}
+
+const handleExceed = (files, fileList) => {
+  // console.log(files)
+  uploadRef.value.clearFiles()  //清空上传文件(限制一个,所以直接清空即可)
+  const file = files[0]
+  uploadRef.value.handleStart(file)  //重新上传
+}
+
+//选择文件
+const handleChange = (file,fileList) => {
+  // console.log(file)
+  const fileImgType = file.name.match(/\.([^\.]+)$/)[1];  //匹配文件格式(最后一个'.'后的格式)或者匹配file.raw.type
+  const isImageType = ['png','jpg'];
+  const isLt5KB = file.size / 1024  < 500;  //判断图片格式与大小
+  if (isImageType.indexOf(fileImgType)==-1) {
+    ElMessage.error('文件仅支持png、jpg格式')  //限制文件类型
+    uploadRef.value.clearFiles()  //清空上传文件
+    return false;
+  }
+  if (!isLt5KB) {
+    ElMessage.error('文件不能超过500kb!')  //限制文件大小
+    uploadRef.value.clearFiles()  //清空上传文件
+    return false;
+  }
+}
+
+
 /*
   用于显示教师姓名
    */
@@ -180,7 +255,7 @@ const processCourses = () => {
   for(let i = 0; i < dataForm.teacherIds.length; i++){
     apis.findUserById(dataForm.teacherIds[i])
         .then((res:any) => {
-          dataForm.teacherIds[i] = res.data.data.records[0].name
+          dataForm.teacherNames[i] = res.data.data.records[0].name
         })
         .catch((err:any) => {
           console.log("错误信息",err)
@@ -221,7 +296,6 @@ const getHomeworkList = () => {
       .then((res: any) => {
         let data = res.data.data.records
         homeworkList.value = convertHomeworkList(data)
-        // TODO
         console.log(homeworkList.value)
         for(let i = 0; i < homeworkList.value.length; i++){
           apis.findUserById(+homeworkList.value[i].publisher)
@@ -347,6 +421,9 @@ function formatDate(date:string) {
 const handleSubmit = () => {
   newCourseInfo.endTime = formatDate(newCourseInfo.endTime)
   newCourseInfo.startTime = formatDate(newCourseInfo.startTime)
+  console.log(uploadRef.value!.submit())
+  console.log(newCourseInfo)
+  // TODO: 更新图片需要更新两次,不知道为什么
   apis.updateCourse(dataForm.courseId, newCourseInfo)
     .then((res:any) => {
       if(res.data.code===200) {
@@ -355,6 +432,11 @@ const handleSubmit = () => {
           type: 'success',
         })
         visible.value = false
+        apis.getCourseByCourseId(dataForm.courseId)
+            .then((res:any) => {
+              console.log(res.data.data.records[0])
+            })
+        setTimeout(() => apis.updateCourse(dataForm.courseId, newCourseInfo), 500)
       }else {
         ElNotification({
           title: '修改失败',
@@ -363,7 +445,7 @@ const handleSubmit = () => {
         visible.value = false
       }
     })
-    .catch((err) => {
+    .catch((err:any) => {
       console.log(err)
     })
 }
@@ -403,5 +485,8 @@ onMounted(() => {
 ::v-deep .el-tabs__active-bar {
   background-color: #597D3B;
 }
-</style>
 
+:deep(.el-upload-dragger) {
+  padding: 0px 0px;
+}
+</style>

+ 1 - 1
src/views/Home/component/Silder/index.vue

@@ -35,7 +35,7 @@
               <div class="slider-tag-item" @click="openEditor(data.assignment.descriptionFile, data.assignment.assignmentName)">作业要求</div>
             </template>
             <template v-if="data.assignment.attachments">
-              <div v-for="(item, index) in data.assignment.attachments" :key="index" class="slider-tag-item" @click="openEditor(item, '附件' + index)">附件{{ index }}</div>
+              <div v-for="(item, index) in data.assignment.attachments" :key="index" class="slider-tag-item" @click="openEditor(item, '附件' + index)">附件{{ index+1 }}</div>
             </template>
           </div>
         </template>

+ 2 - 2
src/views/HomeworkPage/component/HomeworkDetail.vue

@@ -22,7 +22,7 @@
         </div>
         <div class="item">
           <el-link type="primary" @click="console.log('文件下载')">相关文件下载</el-link>
-          <el-button color="#597d3b" size="large" style="margin-left: 660px" @click="handleWriting()">开始写作</el-button>
+          <el-button color="#597d3b" size="large" style="margin-left: 660px" @click="handleWriting()" :disabled="new Date() > new Date(data.endTime)">开始写作</el-button>
         </div>
       </div>
     </div>
@@ -40,7 +40,7 @@
       </div>
       <div>
         <el-input type="textarea" style="width: 100%;margin: 20px 0"></el-input>
-        <el-button color="#597d3b" size="large" style="float: right">发布</el-button>
+        <el-button color="#597d3b" size="large" style="float: right" :disabled="true">发布</el-button>
       </div>
     </div>
   </div>