Browse Source

feat: 教师课件、课程、PDF浏览逻辑初步完成(元宵快乐!)

ChenYangfan 6 năm trước cách đây
mục cha
commit
92d30c87f8

+ 21 - 1
src/App.vue

@@ -10,7 +10,17 @@ import GlobalMessage from '@/components/GlobalMessage'
 
 export default {
   components: { GlobalMessage },
-  mounted () {}
+  created () {
+    // 在页面加载时读取sessionStorage里的状态信息
+    if (sessionStorage.getItem('store')) {
+      this.$store.replaceState(Object.assign({}, this.$store.state, JSON.parse(sessionStorage.getItem('store'))))
+    }
+
+    // 在页面刷新时将vuex里的信息保存到sessionStorage里
+    window.addEventListener('beforeunload', () => {
+      sessionStorage.setItem('store', JSON.stringify(this.$store.state))
+    })
+  }
 }
 </script>
 
@@ -53,6 +63,11 @@ body {
   font-size: 20px;
   font-weight: bold;
   padding: 12px 0;
+  height: 120px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+
   .no-content-warning-tip {
     padding: 24px 0;
   }
@@ -87,9 +102,14 @@ body {
   margin-bottom: 16px;
 }
 
+.mt-16 {
+  margin-top: 16px;
+}
+
 .mb-24 {
   margin-bottom: 24px;
 }
+
 .mb-32 {
   margin-bottom: 32px;
 }

+ 4 - 4
src/components/CourseCard.vue

@@ -11,7 +11,7 @@ export default {
   props: ['index', 'clickHandler', 'course'],
   methods: {
     handleClick () {
-      this.clickHandler(123)
+      this.clickHandler(this.course.id)
     }
   }
 }
@@ -22,7 +22,7 @@ export default {
 
 .course-card {
   font-weight: bold;
-  padding: 12px 8px 12px 16px;
+  padding: 8px 8px 8px 16px;
   border-left: 4px solid $input-background-color;
   transition: .2s;
   cursor: pointer;
@@ -36,7 +36,7 @@ export default {
 
 .course-card-title {
   font-size: 16px;
-  margin-bottom: 8px;
+  margin-bottom: 6px;
   position: relative;
 
   &::before {
@@ -57,7 +57,7 @@ export default {
 .course-card-bio {
   font-size: 14px;
   color: #6a7a8a;
-  margin-bottom: 8px;
+  margin-bottom: 6px;
 }
 
 .course-card-teacher {

+ 1 - 1
src/components/DiscussionArea.vue

@@ -25,7 +25,7 @@ export default {
   padding: 0 24px;
 }
 
-@media (max-width: 600px) {
+@media (max-width: 500px) {
   .discussion-area {
     padding: 0;
     min-width: unset;

+ 4 - 4
src/components/SlideCard.vue

@@ -25,8 +25,8 @@ export default {
     }
   },
   methods: {
-    handleClick (slideId) {
-      this.clickHandler(slideId)
+    handleClick () {
+      this.clickHandler(this.slide)
     }
   }
 }
@@ -51,13 +51,13 @@ export default {
 
 .slide-card-title {
   font-size: 16px;
-  margin-bottom: 6px;
+  margin-bottom: 4px;
 }
 
 .slide-card-time, .slide-card-course {
   font-size: 14px;
   color: #6a7a8a;
-  margin-bottom: 6px;
+  margin-bottom: 4px;
 }
 
 .slide-card-teacher {

+ 2 - 2
src/router/index.js

@@ -21,7 +21,7 @@ const routes = [{
   name: 'register',
   component: () => import('../views/register/Register.vue')
 }, {
-  path: '/pdf-reader/:id',
+  path: '/pdf-reader',
   name: 'pdf-reader',
   component: () => import('../views/reader/PdfReader.vue')
 }, {
@@ -42,7 +42,7 @@ const routes = [{
       name: 'teacher-course-slides',
       component: () => import('../views/teacher/components/TeacherCourseSlides.vue')
     }, {
-      path: 'slide-detail/:slideId',
+      path: 'slide-detail',
       name: 'teacher-explore-slide-detail',
       component: () => import('../views/teacher/components/TeacherSlideDetail.vue')
     }]

+ 9 - 2
src/store/modules/pdf.js

@@ -2,13 +2,14 @@ import {
   NEXT_PAGE,
   PREVIOUS_PAGE,
   RESET,
-  SET_CURRENT_PAGE, SET_SCREEN_SHOT,
-  SET_SRC, SET_TOTAL_PAGES, TOGGLE_SHOW_DISCUSSION, USE_SCREEN_SHOT
+  SET_CURRENT_PAGE, SET_SCREEN_SHOT, SET_SLIDE_INFO,
+  SET_SRC, SET_TOTAL_PAGES, TOGGLE_SHOW_DISCUSSION, UNSET_SLIDE_INFO, USE_SCREEN_SHOT
 } from '@/store/types/pdf-types'
 
 export default {
   state: {
     src: '',
+    slideInfo: {},
     totalPages: 0,
     currentPage: 1,
     showDiscussion: true,
@@ -16,6 +17,12 @@ export default {
   },
 
   mutations: {
+    [SET_SLIDE_INFO] (state, payload) {
+      state.slideInfo = payload.slideInfo
+    },
+    [UNSET_SLIDE_INFO] (state) {
+      state.slideInfo = {}
+    },
     [PREVIOUS_PAGE] (state) {
       state.currentPage = state.currentPage > 0 ? state.currentPage - 1 : state.currentPage
     },

+ 2 - 0
src/store/types/pdf-types.js

@@ -7,3 +7,5 @@ export const NEXT_PAGE = 'nextPage'
 export const PREVIOUS_PAGE = 'previousPage'
 export const SET_SCREEN_SHOT = 'getScreenShot'
 export const USE_SCREEN_SHOT = 'useScreenShot'
+export const SET_SLIDE_INFO = 'setSlideInfo'
+export const UNSET_SLIDE_INFO = 'unsetSlideInfo'

+ 1 - 1
src/style/reset.scss

@@ -70,5 +70,5 @@ a {
 }
 
 a:hover {
-  text-decoration: underline;
+  text-decoration: none;
 }

+ 13 - 8
src/views/reader/PdfReader.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="pdf-reader">
     <div class="pdf-wrapper">
-      <back-title>编程基础 II - 可计算性</back-title>
+      <back-title>{{slide.name}}</back-title>
       <pdf-viewer></pdf-viewer>
     </div>
     <discussion-area
@@ -14,22 +14,17 @@
 <script>
 import PdfViewer from '@/components/PDF/PdfViewer'
 import { mapState } from 'vuex'
-import { SET_SRC } from '@/store/types/pdf-types'
 import BackTitle from '@/components/BackTitle'
 import DiscussionArea from '@/components/DiscussionArea'
 
-const src = 'http://seec-helper-pdf.oss-cn-hangzhou.aliyuncs.com/test.pdf?OSSAccessKeyId=LTAI4Fi1qmL4iuhH8t7G7r2H&Expires=1584224806&Signature=hi3UaVAMkKCSERdUYEuTeGGCd%2Bg%3D'
-
 export default {
   components: { DiscussionArea, BackTitle, PdfViewer },
   computed: {
     ...mapState({
       src: state => state.pdf.src,
+      slide: state => state.pdf.slideInfo,
       showDiscussion: state => state.pdf.showDiscussion
     })
-  },
-  beforeCreate () {
-    this.$store.commit(SET_SRC, { src })
   }
 }
 </script>
@@ -54,10 +49,20 @@ export default {
   padding: 0 24px;
 }
 
+.back-title {
+  margin-bottom: 16px;
+}
+
+@media (max-width: 1000px) {
+  .back-title {
+    padding: 0;
+  }
+}
+
 @media (max-width: 600px) {
   .back-title {
-    margin-top: 16px;
     padding: 0 24px;
+    margin-top: 16px;
   }
 }
 

+ 0 - 2
src/views/shared/UserHomeLayout.vue

@@ -96,7 +96,6 @@ export default {
     padding: 24px 18px;
     display: flex;
     flex-direction: column;
-    align-items: center;
     justify-content: center;
 
     .tab-icon-button {
@@ -106,7 +105,6 @@ export default {
 
   .tab-container {
     display: flex;
-    align-items: center;
     padding: 24px 18px;
     max-width: 800px;
   }

+ 0 - 1
src/views/shared/tab-common.scss

@@ -17,7 +17,6 @@
 
 .complex-tab {
   display: flex;
-  align-items: center;
 }
 
 

+ 38 - 8
src/views/teacher/components/TeacherCourseSlides.vue

@@ -2,11 +2,14 @@
   <tab-side-component>
     <back-title>{{'软件工程与计算 I'}}</back-title>
     <div class="sub-title">课件列表</div>
-    <slide-card :click-handler="handleSlideCardClick"></slide-card>
-    <slide-card :click-handler="handleSlideCardClick"></slide-card>
-    <slide-card :click-handler="handleSlideCardClick"></slide-card>
-    <br>
-    <c-button class="full-width secondary" @click="handleToManager">管理本课程</c-button>
+    <div class="no-content-warning" v-if="!slides || slides.length === 0">
+      <div class="no-content-warning-tip">本课程尚无课件~</div>
+      <c-button class="full-width secondary" @click="handleToCreateCourse">去创建课件</c-button>
+    </div>
+    <template v-for="slide of slides">
+      <slide-card :key="slide.id" :slide="slide" :click-handler="handleSlideCardClick"></slide-card>
+    </template>
+    <c-button class="full-width secondary mt-16" @click="handleToManager">管理本课程</c-button>
   </tab-side-component>
 </template>
 
@@ -15,20 +18,43 @@ import TabSideComponent from '@/components/TabSideComponent'
 import BackTitle from '@/components/BackTitle'
 import SlideCard from '@/components/SlideCard'
 import CButton from '@/components/CButton'
+import { teacherGetSlidesByCourse } from '@/server/slide'
+import { SET_SLIDE_INFO } from '@/store/types/pdf-types'
 
 export default {
   components: { CButton, SlideCard, BackTitle, TabSideComponent },
   data () {
     return {
-      courseId: this.$route.params.courseId
+      courseId: this.$route.params.courseId,
+      slides: []
     }
   },
+  watch: {
+    $route () {
+      this.courseId = this.$route.params.courseId
+      this.init()
+    }
+  },
+  mounted () {
+    this.init()
+  },
   methods: {
-    handleSlideCardClick (slideId) {
-      this.$router.push({ name: 'teacher-explore-slide-detail', params: { slideId: slideId } })
+    init () {
+      teacherGetSlidesByCourse({ courseId: this.courseId, sort: 'name' }).then(res => {
+        this.slides = res.data
+      }).catch(err => {
+        this.$setErrorMessage('获取课程课件列表过程中:' + err.response.data.msg)
+      })
+    },
+    handleSlideCardClick (slide) {
+      this.$store.commit(SET_SLIDE_INFO, { slideInfo: slide })
+      this.$router.push({ name: 'teacher-explore-slide-detail' })
     },
     handleToManager () {
       this.$router.push({ name: 'teacher-course-detail', params: { courseId: this.courseId } })
+    },
+    handleToCreateCourse () {
+      this.$router.push({ name: 'create-slide', params: { courseId: this.courseId } })
     }
   }
 }
@@ -38,4 +64,8 @@ export default {
 .c-input {
   margin-bottom: 24px;
 }
+
+.no-content-warning {
+  height: unset;
+}
 </style>

+ 54 - 10
src/views/teacher/components/TeacherSlideDetail.vue

@@ -1,15 +1,20 @@
 <template>
   <tab-side-component>
     <back-title>课件详情</back-title>
-    <div class="sub-title">浏览课件</div>
+    <div class="detail">
+      <div>课件名称:{{slide.name}}</div>
+      <div>所属课程:{{slide.courseName}}</div>
+      <div>创建时间:{{createTime}}</div>
+      <div>最后更新:{{updateTime}}</div>
+      <div>总页面数:{{slide.pages}} 页</div>
+    </div>
     <c-button class="full-width mb-16" @click="handleReadSlide">浏览课件</c-button>
-    <c-button class="full-width secondary mb-24" @click="handleQuizSetting">查看习题答题情况</c-button>
-    <div class="sub-title">课件设置</div>
-<!--    <div class="re-upload-wrapper">-->
-<!--      <file-uploader placeholder="选取文件重新上传"/>-->
-<!--      <c-button class="secondary">确认修改</c-button>-->
-<!--    </div>-->
-    <c-button class="secondary full-width mb-16" @click="handleQuizSetting">设置课件习题</c-button>
+    <a :href="slideUrl">
+      <c-button class="full-width mb-16 secondary">
+        下载课件
+      </c-button>
+    </a>
+    <c-button class="full-width secondary mb-16" @click="handleQuizSetting">习题设置 & 习题完成统计</c-button>
     <c-button class="error full-width mb-16">删除课件</c-button>
   </tab-side-component>
 </template>
@@ -18,17 +23,39 @@
 import TabSideComponent from '@/components/TabSideComponent'
 import CButton from '@/components/CButton'
 import BackTitle from '@/components/BackTitle'
+import { mapState } from 'vuex'
+import { getSlideUrl } from '@/server/slide'
+import { SET_SRC } from '@/store/types/pdf-types'
 
 export default {
   components: { BackTitle, CButton, TabSideComponent },
   data () {
     return {
-      slideId: this.$route.params.slideId
+      slideUrl: ''
     }
   },
+  computed: {
+    ...mapState({
+      slide: state => state.pdf.slideInfo
+    }),
+    updateTime () {
+      return this.$moment(this.slide.updateAt).fromNow()
+    },
+    createTime () {
+      return this.$moment(this.slide.createAt).fromNow()
+    }
+  },
+  mounted () {
+    getSlideUrl({ slideId: this.slide.id }).then(res => {
+      this.slideUrl = res
+      this.$store.commit(SET_SRC, { src: res })
+    }).catch(err => {
+      this.$setErrorMessage('获取课件链接的过程中:' + err.response.data.msg)
+    })
+  },
   methods: {
     handleReadSlide () {
-      this.$router.push({ name: 'pdf-reader', params: { id: '123' } })
+      this.$router.push({ name: 'pdf-reader', params: { slide: this.slide } })
     },
     handleQuizSetting () {
       this.$router.push({ name: 'teacher-quiz-setting', params: { slideId: '123' } })
@@ -40,6 +67,23 @@ export default {
 <style lang="scss" scoped>
 @import '~@/style/theme.scss';
 
+.detail {
+  font-weight: bold;
+  font-size: 14px;
+  margin-bottom: 24px;
+  color: #7a8a9a;
+
+  div {
+    margin-top: 2px;
+
+  }
+
+  div:not(:last-child) {
+    border-bottom: 1px dashed #aabaca;
+    padding-bottom: 2px;
+  }
+}
+
 .sub-title {
   margin-bottom: 24px;
 }

+ 5 - 4
src/views/teacher/tabs/TeacherExplore.vue

@@ -35,6 +35,7 @@ import CourseCard from '@/components/CourseCard'
 import { teacherGetSlides } from '@/server/slide'
 import { teacherGetCourses } from '@/server/course'
 import CButton from '@/components/CButton'
+import { SET_SLIDE_INFO } from '@/store/types/pdf-types'
 
 export default {
   components: { CButton, CourseCard, SlideCard, SearchBar },
@@ -50,7 +51,7 @@ export default {
     }).catch(err => {
       this.$setErrorMessage('获取课件时:' + err.response.data.msg)
     })
-    teacherGetSlides({ size: 2, sort: 'updateAt,desc' }).then(res => {
+    teacherGetSlides({ size: 1, sort: 'updateAt,desc' }).then(res => {
       this.slides = res.data
     }).catch(err => {
       this.$setErrorMessage(err.response.data.msg)
@@ -60,11 +61,11 @@ export default {
     handleToCreateCourse () {
       this.$router.push({ name: 'create-new-course' })
     },
-    handleSlideCardClick (slideId) {
-      this.$router.push({ name: 'teacher-explore-slide-detail', params: { slideId: slideId } })
+    handleSlideCardClick (slide) {
+      this.$store.commit(SET_SLIDE_INFO, { slideInfo: slide })
+      this.$router.push({ name: 'teacher-explore-slide-detail' })
     },
     handleCourseCardClick (courseId) {
-      // todo
       this.$router.push({ name: 'teacher-course-slides', params: { courseId: courseId } })
     }
   }