فهرست منبع

feat: 迭代一功能完成

ChenYangfan 6 سال پیش
والد
کامیت
1494b58270

+ 4 - 0
src/App.vue

@@ -119,6 +119,10 @@ body {
   margin-bottom: 16px;
 }
 
+.mt-8 {
+  margin-top: 8px;
+}
+
 .mt-16 {
   margin-top: 16px;
 }

+ 103 - 6
src/components/CComment.vue

@@ -1,19 +1,68 @@
 <template>
   <div class="comment">
-    <div class="comment-title">主题:{{comment.title}}</div>
-    <div class="comment-content">详情:{{comment.content}}</div>
-    <div class="comment-author">{{createTime}} | 作者:{{comment.userName}} <span class="role">{{role}}</span></div>
-    <div v-if="comment.reply" class="comment-reply">教师回复:{{comment.reply}}</div>
+    <div @click="showActions = !showActions">
+      <div class="comment-title">主题:{{comment.title}}</div>
+      <div class="comment-content">详情:{{comment.content}}</div>
+      <div class="comment-author">{{createTime}} | 作者:{{comment.userName}} <span class="role">{{role}}</span></div>
+      <div v-if="comment.reply" class="comment-reply">
+        <div>教师回复:{{comment.reply.content}}</div>
+        <div class="comment-reply-time">{{replyTime}}</div>
+      </div>
+    </div>
+    <template v-if="showActions && hasActions">
+      <div v-if="isTeacher && !comment.reply" class="mt-8 mb-8">
+        <c-input textarea="true" placeholder="在此输入回复" class="mb-8" v-model="replyContent"></c-input>
+        <c-button class="full-width secondary" @click="handleCreateReply">提交回复</c-button>
+      </div>
+      <template v-if="isTeacher && comment.reply">
+        <c-button class="full-width warning mt-16 mb-8" @click="handleDeleteReply">删除回复</c-button>
+      </template>
+      <c-button v-if="canDelete" class="error full-width mb-8" @click="handleDeleteComment">删除评论</c-button>
+    </template>
+    <div v-if="hasActions" class="icon" @click="showActions = !showActions">
+      {{iconMap[showActions ? 'up' : 'down']}}
+      <span>{{showActions ? '隐藏操作' : '更多操作'}}</span>
+    </div>
   </div>
 </template>
 
 <script>
+import { mapState } from 'vuex'
+import iconMap from '@/utils/icon-map'
+import CButton from '@/components/CButton'
+import CInput from '@/components/CInput'
+import { createReply, removeReply } from '@/server/reply'
+import { removeComment } from '@/server/comment'
+
 export default {
+  components: { CInput, CButton },
   props: ['comment'],
+  data () {
+    return {
+      showActions: false,
+      replyContent: '',
+      iconMap: iconMap
+    }
+  },
   computed: {
+    ...mapState({
+      userInfo: state => state.main.userInfo
+    }),
+    canDelete () {
+      return this.userInfo.id === this.comment.userId
+    },
+    isTeacher () {
+      return this.userInfo.type === 'TEACHER'
+    },
+    hasActions () {
+      return this.isTeacher || this.canDelete
+    },
     createTime () {
       return this.$moment(this.comment.createAt).fromNow()
     },
+    replyTime () {
+      return this.$moment(this.comment.reply.createAt).fromNow()
+    },
     role () {
       if (this.comment.userType === 'TEACHER') {
         return '教师'
@@ -22,6 +71,38 @@ export default {
       }
       return '身份未知'
     }
+  },
+  methods: {
+    handleCreateReply () {
+      createReply({ commentId: this.comment.id, content: this.replyContent }).then(res => {
+        this.$setSuccessMessage('回复成功')
+        this.$emit('need-refresh')
+      }).catch(err => {
+        this.$setErrorMessage(err.response.data.msg)
+      })
+    },
+    handleDeleteReply () {
+      const msg = '确定删除该回复吗:\n\n' + this.comment.reply.content
+      if (confirm(msg)) {
+        removeReply({ replyId: this.comment.reply.id }).then(res => {
+          this.$setSuccessMessage('删除成功')
+          this.$emit('need-refresh')
+        }).catch(err => {
+          this.$setErrorMessage(err.response.data.msg)
+        })
+      }
+    },
+    handleDeleteComment () {
+      const msg = '确定删除该评论吗:\n\n' + '主题:' + this.comment.title
+      if (confirm(msg)) {
+        removeComment({ commentId: this.comment.id }).then(res => {
+          this.$setSuccessMessage('删除成功')
+          this.$emit('need-refresh')
+        }).catch(err => {
+          this.$setErrorMessage(err.response.data.msg)
+        })
+      }
+    }
   }
 }
 </script>
@@ -31,7 +112,7 @@ export default {
 
 .comment {
   width: 100%;
-  padding: 16px 0 24px 0;
+  padding: 16px 0 16px 0;
   font-weight: bold;
 }
 
@@ -48,7 +129,8 @@ export default {
 .comment-author {
   font-size: 14px;
   color: #7a8a9a;
-  margin-bottom: 4px;
+  margin-bottom: 8px;
+
   .role {
     display: inline-block;
     padding: 1px 4px;
@@ -62,5 +144,20 @@ export default {
   font-size: 14px;
   padding: 4px 8px;
   background: $theme-orange-transparent;
+
+  &-time {
+    color: #8a9aaa;
+  }
+}
+
+.icon {
+  font-family: 'iconfont', sans-serif;
+  text-align: center;
+  padding: 4px 0;
+  color: #7a8a9a;
+
+  span {
+    font-size: 12px;
+  }
 }
 </style>

+ 13 - 5
src/components/DiscussionArea.vue

@@ -2,12 +2,16 @@
   <div class="discussion-area">
     <h1 class="title">讨论 & 问答</h1>
     <!--    <discussion-type-bar></discussion-type-bar>-->
-    <write-new-comment @comment-submit="handleCommentSubmit" :placeholder="writingAreaPlaceholder"></write-new-comment>
     <div class="discussion-area-content">
+      <write-new-comment @comment-submit="handleCommentSubmit" :placeholder="writingAreaPlaceholder"></write-new-comment>
       <div class="sub-title mb-8">本页讨论区</div>
+      <div class="no-content-warning" v-if="comments === null || comments.length === 0">
+        本页还没有讨论
+      </div>
       <template v-for="comment of comments">
         <c-comment :key="comment.id" :comment="comment"
-                     :clickHandler="null">
+                   @need-refresh="updateComments"
+        >
         </c-comment>
       </template>
     </div>
@@ -41,10 +45,13 @@ export default {
       slide: state => state.pdf.slideInfo
     }),
     writingAreaPlaceholder () {
-      // if (this.userInfo.type === 'TEACHER') {
       return '写下针对本页的讨论(标题)'
-      // } else {
-      // }
+    }
+  },
+  watch: {
+    currentPage () {
+      console.log(this.currentPage)
+      this.updateComments()
     }
   },
   methods: {
@@ -63,6 +70,7 @@ export default {
         content: comment.content
       }).then(res => {
         this.$setSuccessMessage('您的讨论帖发表成功')
+        this.updateComments()
       })
     }
   }

+ 5 - 0
src/server/course.js

@@ -45,6 +45,11 @@ export function chooseCourse({ courseId, code }) {
     .then(res => {})
 }
 
+export function quitCourse({ courseId }) {
+  return axios
+    .post(useCourseServer('/quit/') + courseId)
+}
+
 export function getCourses({ key = '', page = 0, size = 10, sort = '' }) {
   return axios
     .get(useCourseServer(), {

+ 3 - 4
src/server/reply.js

@@ -8,13 +8,12 @@ export function createReply({ commentId, content }) {
     commentId,
     content
   }
-  axios
+  return axios
     .post(useReplyServer(), data)
     .then(res => res.data)
 }
 
 export function removeReply({ replyId }) {
-  axios
-    .delete('/' + replyId)
-    .then(res => {})
+  return axios
+    .delete(useReplyServer() + '/' + replyId)
 }

+ 1 - 1
src/store/modules/pdf.js

@@ -24,7 +24,7 @@ export default {
       state.slideInfo = {}
     },
     [PREVIOUS_PAGE] (state) {
-      state.currentPage = state.currentPage > 0 ? state.currentPage - 1 : state.currentPage
+      state.currentPage = state.currentPage > 1 ? state.currentPage - 1 : state.currentPage
     },
     [NEXT_PAGE] (state) {
       state.currentPage = state.currentPage < state.totalPages ? state.currentPage + 1 : state.currentPage

+ 3 - 1
src/utils/icon-map.js

@@ -15,7 +15,9 @@ const iconMap = {
   'search': '\ue6a2',
   'upload': '\ue6c8',
   'back': '\ue714',
-  'quiz': '\ue6d1'
+  'quiz': '\ue6d1',
+  'down': '\ue7db',
+  'up': '\ue7d9'
 }
 
 export default iconMap

+ 13 - 1
src/views/student/components/StudentCourseDetail.vue

@@ -8,7 +8,7 @@
       <div>教师:{{course.teacherName}}</div>
     </div>
     <c-button class="secondary full-width mb-16" @click="handleCheckSlideList">点击查看课件列表</c-button>
-    <c-button class="error full-width">退出本课程</c-button>
+    <c-button class="error full-width" @click="handleQuitCourse">退出本课程</c-button>
   </tab-side-component>
 </template>
 
@@ -17,6 +17,7 @@ import TabSideComponent from '@/components/TabSideComponent'
 import CButton from '@/components/CButton'
 import BackTitle from '@/components/BackTitle'
 import { mapState } from 'vuex'
+import { quitCourse } from '@/server/course'
 
 export default {
   components: { BackTitle, CButton, TabSideComponent },
@@ -36,6 +37,17 @@ export default {
   methods: {
     handleCheckSlideList () {
       this.$router.push({ name: 'student-course-slides' })
+    },
+    handleQuitCourse () {
+      const msg = '确定退出本课程吗:\n\n' + this.course.name
+      if (confirm(msg)) {
+        quitCourse({ courseId: this.course.id }).then(res => {
+          this.$setSuccessMessage('退出成功')
+          this.$router.push({ name: 'student-courses' })
+        }).catch(err => {
+          this.$setErrorMessage(err.response.data.msg)
+        })
+      }
     }
   }
 }

+ 1 - 1
src/views/student/components/StudentCourseSlides.vue

@@ -45,7 +45,7 @@ export default {
   },
   methods: {
     init () {
-      studentGetSlidesByCourse({ courseId: this.course.id, sort: 'name' }).then(res => {
+      studentGetSlidesByCourse({ courseId: this.course.id, size: 100, sort: 'name' }).then(res => {
         this.slides = res.data
       }).catch(err => {
         this.$setErrorMessage('获取课程课件列表过程中:' + err.response.data.msg)

+ 4 - 1
src/views/student/tabs/StudentCoursesManager.vue

@@ -57,11 +57,14 @@ export default {
       }).catch(err => {
         this.$setErrorMessage(err.response.data.msg)
       })
+    },
+    $route () {
+      this.updateInfo()
     }
   },
   methods: {
     updateInfo () {
-      studentGetCourses({ sort: 'name' }).then(res => {
+      studentGetCourses({ size: 100, sort: 'name' }).then(res => {
         this.courses = res.data
       }).catch(err => {
         this.$setErrorMessage(err.response.data.msg)

+ 1 - 1
src/views/student/tabs/StudentExplore.vue

@@ -42,7 +42,7 @@ export default {
   },
   methods: {
     updateInfo () {
-      studentGetCourses({ sort: 'name' }).then(res => {
+      studentGetCourses({ size: 100, sort: 'name' }).then(res => {
         this.courses = res.data
       }).catch(err => {
         this.$setErrorMessage(err.response.data.msg)

+ 13 - 2
src/views/teacher/components/TeacherCourseDetail.vue

@@ -13,7 +13,7 @@
       <c-button class="secondary" @click="handleChangeCode">确认修改</c-button>
     </div>
     <c-button class="secondary full-width mb-16" @click="handleCheckSlideList">点击查看课件列表</c-button>
-    <c-button class="error full-width">删除课程</c-button>
+    <c-button class="error full-width" @click="handleDeleteCourse">删除课程</c-button>
   </tab-side-component>
 </template>
 
@@ -23,7 +23,7 @@ import CInput from '@/components/CInput'
 import CButton from '@/components/CButton'
 import BackTitle from '@/components/BackTitle'
 import { mapState } from 'vuex'
-import { modifyCourse } from '@/server/course'
+import { modifyCourse, removeCourse } from '@/server/course'
 
 export default {
   components: { BackTitle, CButton, CInput, TabSideComponent },
@@ -50,6 +50,17 @@ export default {
       }).catch(err => {
         this.$setErrorMessage(err.response.data.msg)
       })
+    },
+    handleDeleteCourse () {
+      const msg = '请谨慎确认:确定删除本课程吗:\n\n' + this.course.name
+      if (confirm(msg)) {
+        removeCourse({ courseId: this.course.id }).then(res => {
+          this.$setSuccessMessage('删除成功')
+          this.$router.push({ name: 'teacher-courses' })
+        }).catch(err => {
+          this.$setErrorMessage(err.response.data.msg)
+        })
+      }
     }
   }
 }

+ 1 - 1
src/views/teacher/components/TeacherCourseSlides.vue

@@ -45,7 +45,7 @@ export default {
   },
   methods: {
     init () {
-      teacherGetSlidesByCourse({ courseId: this.course.id, sort: 'name' }).then(res => {
+      teacherGetSlidesByCourse({ courseId: this.course.id, size: 100, sort: 'name' }).then(res => {
         this.slides = res.data
       }).catch(err => {
         this.slides = []

+ 13 - 2
src/views/teacher/components/TeacherSlideDetail.vue

@@ -19,7 +19,7 @@
     <c-button v-if="nextState" class="warning full-width mb-16" @click="handleToNextState">
       将幻灯片状态设置为:{{slideStateTranslation[nextState]}}
     </c-button>
-    <c-button class="error full-width mb-16">删除课件</c-button>
+    <c-button class="error full-width mb-16" @click="handleDeleteSlide">删除课件</c-button>
   </tab-side-component>
 </template>
 
@@ -28,7 +28,7 @@ import TabSideComponent from '@/components/TabSideComponent'
 import CButton from '@/components/CButton'
 import BackTitle from '@/components/BackTitle'
 import { mapState } from 'vuex'
-import { getSlideUrl, modifySlideState } from '@/server/slide'
+import { getSlideUrl, modifySlideState, removeSlide } from '@/server/slide'
 import { SET_SLIDE_INFO, SET_SRC } from '@/store/types/pdf-types'
 import slideStateTranslation from '@/server/enums/slide-state-translation'
 import getSlideNextState from '@/utils/get-slide-next-state'
@@ -77,6 +77,17 @@ export default {
       }).catch(err => {
         this.$setErrorMessage(err.response.data.msg)
       })
+    },
+    handleDeleteSlide () {
+      const msg = '请谨慎操作:确定删除本课件吗:\n\n课件名称:' + this.slide.name
+      if (confirm(msg)) {
+        removeSlide({ id: this.slide.id }).then(res => {
+          this.$setSuccessMessage('删除成功')
+          this.$router.push({ name: 'teacher-explore' })
+        }).catch(err => {
+          this.$setErrorMessage(err.response.data.msg)
+        })
+      }
     }
   }
 }

+ 2 - 1
src/views/teacher/tabs/CreateSlide.vue

@@ -44,7 +44,7 @@ export default {
     }
   },
   mounted () {
-    teacherGetCourses({ sort: 'name' }).then(res => {
+    teacherGetCourses({ size: 100, sort: 'name' }).then(res => {
       this.courses = res.data
     }).catch(err => {
       this.$setErrorMessage('获取课件列表过程中:' + err.response.data.msg)
@@ -74,6 +74,7 @@ export default {
       }
       createSlide({ courseId: this.selectedCourseId, name: this.slideName, file: this.file }).then(res => {
         this.$setSuccessMessage('创建课件成功!')
+        this.$router.push({ name: 'teacher-explore' })
       }).catch(err => {
         this.$setErrorMessage(err.response.data.msg)
       })

+ 6 - 1
src/views/teacher/tabs/TeacherCoursesManager.vue

@@ -35,9 +35,14 @@ export default {
   activated () {
     this.updateInfo()
   },
+  watch: {
+    $route () {
+      this.updateInfo()
+    }
+  },
   methods: {
     updateInfo () {
-      teacherGetCourses({ sort: 'name' }).then(res => {
+      teacherGetCourses({ size: 100, sort: 'name' }).then(res => {
         this.courses = res.data
       }).catch(err => {
         this.$setErrorMessage('获取课程时:' + err.response.data.msg)

+ 7 - 6
src/views/teacher/tabs/TeacherDiscussion.vue

@@ -3,22 +3,23 @@
     <div class="left">
       <h1 class="title">讨论 & 问答</h1>
       <div class="sub-title">待回答问题</div>
-      <div class="tip"><span>{{iconMap.discussion}}</span> 您有 <span>{{2}}</span> 个问题待回答</div>
-      <discussion-question></discussion-question>
-      <discussion-question></discussion-question>
-      <discussion-question></discussion-question>
+      <div class="no-content-warning">
+        待回答问题部分目前尚未完成 <br>
+        请前往幻灯片阅读界面讨论区查看
+      </div>
       <div class="mb-16"></div>
       <div class="sub-title">热门讨论</div>
+      <div class="no-content-warning">
+        热门讨论部分目前尚未完成
+      </div>
     </div>
   </div>
 </template>
 
 <script>
 import iconMap from '@/utils/icon-map'
-import DiscussionQuestion from '@/components/DiscussionQuestion'
 
 export default {
-  components: { DiscussionQuestion },
   data () {
     return {
       iconMap: iconMap

+ 21 - 10
src/views/teacher/tabs/TeacherExplore.vue

@@ -47,19 +47,30 @@ export default {
       slides: []
     }
   },
+  watch: {
+    $route () {
+      this.updateInfo()
+    }
+  },
   mounted () {
-    teacherGetCourses({ sort: 'createAt' }).then(res => {
-      this.courses = res.data
-    }).catch(err => {
-      this.$setErrorMessage('获取课件时:' + err.response.data.msg)
-    })
-    teacherGetSlides({ size: 1, sort: 'updateAt,desc' }).then(res => {
-      this.slides = res.data
-    }).catch(err => {
-      this.$setErrorMessage(err.response.data.msg)
-    })
+    this.updateInfo()
+  },
+  activated () {
+    this.updateInfo()
   },
   methods: {
+    updateInfo () {
+      teacherGetCourses({ size: 100, sort: 'createAt' }).then(res => {
+        this.courses = res.data
+      }).catch(err => {
+        this.$setErrorMessage('获取课件时:' + err.response.data.msg)
+      })
+      teacherGetSlides({ size: 1, sort: 'updateAt,desc' }).then(res => {
+        this.slides = res.data
+      }).catch(err => {
+        this.$setErrorMessage(err.response.data.msg)
+      })
+    },
     handleToCreateCourse () {
       this.$router.push({ name: 'create-new-course' })
     },