Bläddra i källkod

feat: 替换文件功能

ChenYangfan 6 år sedan
förälder
incheckning
f35eb8ca0e

+ 13 - 0
src/App.vue

@@ -6,6 +6,9 @@
       </keep-alive>
     </slide-up-transition>
     <global-message></global-message>
+    <div class="copyright">
+      &copy;2020 Powered by SEECODER 苏ICP备19073881号-1
+    </div>
   </div>
 </template>
 
@@ -84,3 +87,13 @@ export default {
   font-feature-settings: 'liga';
 }
 </style>
+
+<style lang="scss" scoped>
+.copyright {
+  position: fixed;
+  bottom: 8px;
+  right: 12px;
+  font-size: 12px;
+  color: #8a9aaa;
+}
+</style>

+ 1 - 0
src/components/Basic/CButton.vue

@@ -112,6 +112,7 @@ button {
   font-weight: bold;
   box-sizing: border-box;
   transition: .15s;
+  white-space: nowrap;
 
   &:hover {
     background: darken($theme-background-grey, 5);

+ 4 - 1
src/components/Basic/FileUploader.vue

@@ -48,8 +48,11 @@ export default {
   width: 100%;
   height: 40px;
   line-height: 40px;
-  padding: 0 0 0 12px;
+  padding: 0 12px;
   transition: .2s;
+  white-space: nowrap;
+
+  text-overflow:ellipsis;
   .c-icon {
     display: inline-block;
     vertical-align: middle;

+ 2 - 3
src/components/Cards/CourseCard.vue

@@ -61,16 +61,15 @@ export default {
 @import '~@/style/theme.scss';
 
 .course-card {
-  margin: 12px 0;
+  margin: 8px 0;
   padding: 8px 8px 8px 12px;
   // border-left: 4px solid $input-background-color;
   transition: .2s;
   cursor: pointer;
   border-radius: 12px;
-  background-color: lighten($card-background, 3);
 
   &:hover {
-    background: darken($card-background, 2);
+    background: $card-background;
     // border-left: 4px solid $theme-blue;
   }
 }

+ 1 - 1
src/components/Cards/CourseFileCard.vue

@@ -40,7 +40,7 @@ export default {
 @import '~@/style/theme.scss';
 
 .course-file-card {
-  padding: 6px 8px 6px 12px;
+  padding: 2px 8px 2px 12px;
   border-radius: 12px;
   // border-left: 4px solid $input-background-color;
   background-color: white;

+ 1 - 3
src/components/Cards/SlideCard.vue

@@ -77,16 +77,14 @@ export default {
 @import '~@/style/theme.scss';
 
 .slide-card {
-  padding: 6px 8px 6px 12px;
+  padding: 2px 8px 2px 12px;
   border-radius: 12px;
-  // border-left: 4px solid $input-background-color;
   background-color: white;
   transition: .2s;
   cursor: pointer;
 
   &:hover {
     background-color: $card-background;
-    // border-left: 4px solid $theme-blue;
   }
 }
 

+ 31 - 5
src/components/Pagination.vue

@@ -28,8 +28,10 @@
       </c-button>
     </div>
     <div class="mt-16">
-      <c-input v-model="inputPage" class="page-input" @keypress="handlePageInputEvent"></c-input>
-      <span>/ {{ totalPage }}</span>
+      <label>
+        <input v-model="inputPage" class="page-input" @keypress="handlePageInputEvent"/>
+        <span>/ {{ totalPage }}</span>
+      </label>
     </div>
   </div>
 </template>
@@ -38,12 +40,11 @@
 import iconMap from '@/utils/icon-map'
 import CButton from '@/components/Basic/CButton'
 import CIcon from '@/components/Basic/CIcon'
-import CInput from '@/components/Basic/CInput'
 
 const SHOW_PAGE_NUM = 3
 
 export default {
-  components: { CInput, CIcon, CButton },
+  components: { CIcon, CButton },
   props: {
     page: {
       default: 1,
@@ -117,6 +118,31 @@ export default {
 <style lang="scss" scoped>
 @import "~@/style/theme.scss";
 
+// FIXME: 重复代码
+input {
+  box-sizing: border-box;
+  font-size: 16px;
+  font-weight: bold;
+  color: #3a4a5a;
+  background: $input-background-color;
+  border-radius: 8px;
+  border: none;
+  outline: none;
+  width: 100%;
+  height: 40px;
+  line-height: 1.5;
+  padding: 0 12px 0 12px;
+  transition: .2s;
+
+  &:hover {
+    background: $input-hover-background-color;
+  }
+
+  &::placeholder {
+    color: #8a9aaa;
+  }
+}
+
 .pagination-wrapper {
   display: flex;
   flex-wrap: wrap;
@@ -149,7 +175,7 @@ export default {
   margin-right: 8px;
   color: #7a8a9a;
 
-  & + span{
+  & + span {
     color: #5a6a7a;
   }
 }

+ 23 - 7
src/views/quiz/QuizDetail.vue

@@ -6,6 +6,9 @@
         <c-button class="delete-button" :left="12" text theme="red" @click="handleDelete" icon="close">删除测试</c-button>
       </back-title>
       <div class="sub-title">学生提交结果列表</div>
+      <search-bar></search-bar>
+      <pagination @change="handlePageChange" v-show="result && result.length > 0" :page="page" :size="size"
+                  :total-elements="totalElements"></pagination>
       <template v-if="quizDetail.state === QuizState.closed || quizDetail.state === QuizState.ongoing">
         <answer-card @click="handleSelectAnswer(answer)" v-for="answer of result" :key="answer.studentId"
                      :answer="answer"></answer-card>
@@ -27,29 +30,31 @@ import { deleteQuiz, getOneQuiz, getQuizStudentAnswers } from '@/server/quiz'
 import QuizDetailFactory from '@/views/quiz/components/QuizDetailFactory'
 import AnswerCard from '@/components/Cards/AnswerCard'
 import CButton from '@/components/Basic/CButton'
+import Pagination from '@/components/Pagination'
+import SearchBar from '@/components/Basic/SearchBar'
 
 export default {
   name: 'QuizDetail',
-  components: { CButton, AnswerCard, QuizDetailFactory, BackTitle },
+  components: { SearchBar, Pagination, CButton, AnswerCard, QuizDetailFactory, BackTitle },
   data () {
     return {
+      page: 1,
+      size: 12,
+      totalElements: 1,
+
       quizDetail: createDefaultQuiz(),
       result: [],
       showStudentName: '',
       showScore: '',
       showSubmitAt: '',
       showAnswers: [],
+
       QuizState
     }
   },
   created () {
     this.fetchQuizDetail()
-    const { quizId } = this.$route.params
-    getQuizStudentAnswers({ quizId: quizId })
-      .then(res => {
-        this.result = res.data
-      })
-      .catch(err => { this.$setErrorMessage(err.response.data.msg) })
+    this.fetchQuizStudentAnswers({ page: 1 })
   },
   methods: {
     fetchQuizDetail () {
@@ -58,6 +63,14 @@ export default {
         .then(res => (this.quizDetail = res))
         .catch(err => this.$setErrorMessage(err.response.data.msg))
     },
+    fetchQuizStudentAnswers ({ page = this.page }) {
+      const { quizId } = this.$route.params
+      getQuizStudentAnswers({ quizId: quizId })
+        .then(res => {
+          this.result = res.data
+        })
+        .catch(err => { this.$setErrorMessage(err.response.data.msg) })
+    },
     handleSelectAnswer (answer) {
       this.showScore = answer.score
       this.showSubmitAt = answer.submitAt
@@ -74,6 +87,9 @@ export default {
           this.$setErrorMessage(err.response.data.msg)
         })
       }
+    },
+    handlePageChange ({ page }) {
+
     }
   }
 }

+ 57 - 26
src/views/teacher/components/TeacherSlideDetail.vue

@@ -10,14 +10,19 @@
     <show-transition>
       <slide-detail v-if="showMore" :slide="slide"></slide-detail>
     </show-transition>
-    <div class="mb-24"><strong class="">{{slide.name}}</strong></div>
-    <c-button block theme="blue" standout class="mb-12" @click="handleReadSlide" icon="play_arrow" no-bold>浏览课件
-    </c-button>
-    <a :href="slideUrl">
-      <c-button block theme="green" no-bold class="mb-32" icon="cloud_download">
-        下载课件
+    <div class="mb-12 vertical-center">
+      <strong class="slide-name">{{slide.name}}</strong>
+      <c-button text theme="red" :left="8" @click="handleDeleteSlide" icon="close">删除课件</c-button>
+    </div>
+    <div class="vertical-center">
+      <c-button block theme="blue" standout class="mb-12" @click="handleReadSlide" icon="play_arrow" no-bold>浏览课件
       </c-button>
-    </a>
+      <a :href="slideUrl">
+        <c-button text theme="green" :left="8" no-bold class="mb-16" icon="cloud_download">
+          下载
+        </c-button>
+      </a>
+    </div>
     <div class="sub-title">
       课件信息设置
       <c-button :theme="showSettings ? 'blue' : 'normal'" :left="8" text
@@ -28,24 +33,30 @@
     </div>
     <show-transition>
       <div v-if="showSettings">
+        <div class="mb-8">
+          <b>幻灯片状态设置</b>
+        </div>
+        <slide-state-bar :state="this.slide.state" @change-state="handleChangeState"></slide-state-bar>
+        <div v-if="this.slide.state === 'DRAFT'" class="tip mb-32">
+          提示:学生无法查看处于草稿状态的幻灯片,如果希望公开请设置为其他状态
+        </div>
         <div class="mb-8">
           <b>修改课件名称</b>
         </div>
-        <div class="mb-16 modify-slide-name">
+        <div class="mb-16 vertical-center">
           <c-input placeholder="在此输入课件新名称" v-model="newSlideName"></c-input>
           <c-button :left="8" text theme="green" icon="check" @click="handleModifySlideName">确认</c-button>
         </div>
         <div class="mb-8">
-          <b>幻灯片状态设置</b>
+          <b>修改课件文件</b>
         </div>
-        <slide-state-bar :state="this.slide.state" @change-state="handleChangeState"></slide-state-bar>
-        <div v-if="this.slide.state === 'DRAFT'" class="tip mb-32">
-          提示:学生无法查看处于草稿状态的幻灯片,如果希望公开请设置为其他状态
+        <div class="vertical-center mb-16">
+          <file-uploader accept="application/pdf" @change="handleFileChanged" ></file-uploader>
+          <c-button :left="8" text theme="green" icon="file_upload" @click="handleModifyFile">替换</c-button>
         </div>
+        <c-button block theme="blue" class="mb-24" @click="handleQuizSetting" icon="edit">习题设置</c-button>
       </div>
     </show-transition>
-    <c-button block theme="blue" class="mb-16" @click="handleQuizSetting" icon="edit">习题设置</c-button>
-    <c-button block theme="red" class="mb-16" @click="handleDeleteSlide" icon="close">删除课件</c-button>
   </tab-side-component>
 </template>
 
@@ -54,23 +65,34 @@ import TabSideComponent from '@/components/Layouts/TabSideComponent'
 import CButton from '@/components/Basic/CButton'
 import BackTitle from '@/components/Basic/BackTitle'
 import { mapState } from 'vuex'
-import { getSlideUrl, modifySlide, modifySlideState, deleteSlide } from '@/server/slide'
+import { getSlideUrl, modifySlide, modifySlideState, deleteSlide, modifySlideFile } from '@/server/slide'
 import { SET_SLIDE_INFO, SET_SRC } from '@/store/types/pdf-types'
 import SlideDetail from '@/components/Details/SlideDetail'
 import slideStateTranslation from '@/enums/slide-state-translation'
 import CInput from '@/components/Basic/CInput'
 import SlideStateBar from '@/components/Details/SlideStateBar'
 import ShowTransition from '@/animations/ShowTransition'
+import FileUploader from '@/components/Basic/FileUploader'
 
 export default {
-  components: { CInput, BackTitle, CButton, TabSideComponent, SlideDetail, SlideStateBar, ShowTransition },
+  components: {
+    FileUploader,
+    CInput,
+    BackTitle,
+    CButton,
+    TabSideComponent,
+    SlideDetail,
+    SlideStateBar,
+    ShowTransition
+  },
   data () {
     return {
       slideUrl: '',
       slideStateTranslation,
       newSlideName: '',
       showMore: false,
-      showSettings: true
+      showSettings: true,
+      newFile: null
     }
   },
   computed: {
@@ -105,6 +127,10 @@ export default {
       }
     },
     handleModifySlideName () {
+      if (!this.newSlideName) {
+        this.$setInfoMessage('还没有输入新的课件名称')
+        return
+      }
       modifySlide({ id: this.slide.id, name: this.newSlideName }).then(res => {
         this.$setSuccessMessage('修改成功')
         this.$store.commit(SET_SLIDE_INFO, { slideInfo: res })
@@ -120,6 +146,15 @@ export default {
       }).catch(err => {
         this.$setErrorMessage(err.response.data.msg)
       })
+    },
+    handleFileChanged (file) {
+      this.newFile = file || null
+    },
+    handleModifyFile () {
+      this.$setInfoMessage('文件上传中...')
+      modifySlideFile({ id: this.slide.id, file: this.newFile })
+        .then(res => this.$setSuccessMessage('修改课件文件成功'))
+        .catch(err => this.$setErrorMessage(err.response.data.msg))
     }
   }
 }
@@ -144,6 +179,11 @@ export default {
   }
 }
 
+.slide-name {
+  font-size: 18px;
+  color: #6a7a8a;
+}
+
 .sub-title {
   display: flex;
   align-items: center;
@@ -165,15 +205,6 @@ export default {
   color: $theme-red
 }
 
-.modify-slide-name {
-  display: flex;
-  align-items: center;
-
-  .c-input {
-    flex: 1
-  }
-}
-
 .tip {
   color: $theme-red;
   font-size: 12px;