ソースを参照

refactor(style): add more style about quiz

WuXinyu 6 年 前
コミット
b9eed2d471

+ 104 - 0
src/components/Cards/QuizCard.vue

@@ -0,0 +1,104 @@
+<template>
+  <router-link tag="div" class="quiz-card" :to="navPath">
+    <div class="quiz-card-title">
+      <c-icon theme="green" :left="-2" :right="6" :size="18">edit</c-icon>
+      {{quiz.name || '暂无课程名称'}}
+    </div>
+    <show-transition-small>
+      <div v-if="!hideCourseName" class="quiz-card-row">{{ quiz.course && quiz.course.name }}</div>
+    </show-transition-small>
+    <show-transition-small>
+      <div v-if="!hideSlideName" class="quiz-card-row">{{ quiz.slide && quiz.slide.name }}</div>
+    </show-transition-small>
+    <show-transition-small>
+      <div v-if="!hideQuizTime" class="quiz-card-row">测试时间:{{ SlideStateTranslation[quiz.quizTime] }}</div>
+    </show-transition-small>
+    <show-transition-small>
+      <div v-if="!hideQuizState" class="quiz-card-row">测试状态:{{ QuizStateNaming[quiz.state] }}</div>
+    </show-transition-small>
+  </router-link>
+</template>
+
+<script>
+import CIcon from '@/components/Basic/CIcon'
+import ShowTransitionSmall from '@/animations/ShowTransitionSmall'
+import SlideStateTranslation from '@/server/enums/slide-state-translation'
+import { QuizStateNaming } from '@/server/enums/quiz-state'
+
+export default {
+  name: 'QuizCard',
+  components: { CIcon, ShowTransitionSmall },
+  props: {
+    clickHandler: {
+      type: Function,
+      default: () => {}
+    },
+    quiz: {
+      type: Object,
+      default: () => ({})
+    },
+    navPath: {
+      type: Object,
+      default: () => ({})
+    },
+    hideQuizTime: {
+      type: Boolean,
+      default: false
+    },
+    hideQuizState: {
+      type: Boolean,
+      default: false
+    },
+    hideCourseName: {
+      type: Boolean,
+      default: false
+    },
+    hideSlideName: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+      SlideStateTranslation,
+      QuizStateNaming
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  @import '~@/style/theme.scss';
+
+  .quiz-card {
+    margin: 12px 0;
+    padding: 8px 8px 8px 16px;
+    // border-left: 4px solid $input-background-color;
+    transition: .2s;
+    cursor: pointer;
+    border-radius: 12px;
+    background-color: $card-background;
+
+    &:hover {
+      background: darken($card-background, 5);
+      // border-left: 4px solid $theme-blue;
+    }
+  }
+
+  .quiz-card-title {
+    font-size: 16px;
+    display: flex;
+    align-items: center;
+    position: relative;
+    line-height: 1.8;
+  }
+
+  .quiz-card-row {
+    font-size: 14px;
+    color: #6a7a8a;
+  }
+
+  .c-icon {
+    transform: scale(1.3);
+  }
+</style>

+ 6 - 9
src/views/quiz/QuizView.vue

@@ -1,14 +1,10 @@
 <template>
   <tab-side-component>
     <back-title>具体课件的测验(学生)</back-title>
-    <div v-for="item in quizList" :key="item.id">
-      <div>{{ item.name }}</div>
-      <div>测试时间:{{ SlideStateTranslation[item.quizTime] }}</div>
-      <div>测试状态:{{ QuizStateNaming[item.state] }}</div>
-      <router-link :to="{ name: 'student-quiz-detail', params: { quizId: item.id }}">
-        <button>详情</button>
-      </router-link>
-    </div>
+    <quiz-card
+      v-for="item in quizList" :key="item.id"
+      :nav-path="{ name: 'student-quiz-detail', params: { quizId: item.id } }"
+      :quiz="item" hide-quiz-state hide-quiz-time />
   </tab-side-component>
 </template>
 
@@ -18,9 +14,10 @@ import SlideStateTranslation from '@/server/enums/slide-state-translation'
 import { QuizStateNaming } from '@/server/enums/quiz-state'
 import { getQuizList } from '@/server/quiz'
 import TabSideComponent from '@/components/Layouts/TabSideComponent'
+import QuizCard from '@/components/Cards/QuizCard'
 export default {
   name: 'QuizView',
-  components: { TabSideComponent, BackTitle },
+  components: { QuizCard, TabSideComponent, BackTitle },
   data() {
     return {
       quizList: [],

+ 0 - 1
src/views/quiz/components/ChoiceQuestionDetail.vue

@@ -1,6 +1,5 @@
 <template>
   <div>
-    <div v-if="!isEmpty(value.pass)">{{ value.pass ? '回答正确' : '回答错误' }}</div>
     <editor-section title="题干">
       <markdown-section :raw="value.stem"/>
     </editor-section>

+ 1 - 1
src/views/quiz/components/EditorSection.vue

@@ -19,7 +19,7 @@ export default {
 
 <style lang="scss" scoped>
 h3 {
-  font-size: 18px;
+  font-size: 14px;
   color: #5a6a7a;
 }
 </style>

+ 24 - 4
src/views/quiz/components/QuizDetailFactory.vue

@@ -1,9 +1,14 @@
 <template>
   <div>
+    <div v-if="quizDetail.state === QuizState.closed" class="quiz-info">测试得分:{{ Math.floor(100 * (passQuestionNums / totalQuestionNums)) }} 分</div>
     <div class="quiz-info">测试时间:{{ SlideStateTranslation[quizDetail.quizTime] }}</div>
     <div class="quiz-info">测试状态:{{ QuizStateNaming[quizDetail.state] }}</div>
     <div class="mt-32 mb-32" :key="item.id" v-for="(item, index) in quizDetail.questions">
-      <div class="index">题号:{{ index + 1 }}</div>
+      <div class="index">题号:{{ index + 1 }}
+        <c-icon v-if="!isEmpty(item.pass)"
+                :theme="item.pass ? 'green' : 'red'">
+          {{ item.pass ? 'check' : 'close' }}
+        </c-icon></div>
       <question-detail-factory :question="item" />
     </div>
   </div>
@@ -13,11 +18,13 @@
 import { createDefaultQuiz } from '@/views/quiz/utils/default'
 import SlideStateTranslation from '@/server/enums/slide-state-translation'
 import QuestionKind from '@/server/enums/question-kind'
-import { QuizStateNaming } from '@/server/enums/quiz-state'
+import { QuizStateNaming, QuizState } from '@/server/enums/quiz-state'
 import QuestionDetailFactory from '@/views/quiz/components/QuestionDetailFactory'
+import { isEmpty } from '@/utils/types'
+import CIcon from '@/components/Basic/CIcon'
 
 export default {
-  components: { QuestionDetailFactory },
+  components: { CIcon, QuestionDetailFactory },
   props: {
     quizDetail: {
       type: Object,
@@ -29,15 +36,28 @@ export default {
 
       SlideStateTranslation,
       QuestionKind,
+      QuizState,
       QuizStateNaming
     }
+  },
+  computed: {
+    totalQuestionNums() {
+      return this.quizDetail?.questions?.length ?? 0
+    },
+    passQuestionNums() {
+      return this.quizDetail?.questions?.filter(item => item.pass).length
+    }
+  },
+  methods: {
+    isEmpty
   }
 }
 </script>
 <style lang="scss" scoped>
 @import "~@/style/theme.scss";
 .quiz-info {
-  margin: 12px 0;
+  margin: 8px 0;
+  color: #7a8a9a;
 }
 .index {
   color: $theme-blue;

+ 0 - 1
src/views/quiz/components/TrueFalseQuestionDetail.vue

@@ -1,6 +1,5 @@
 <template>
   <div>
-    <div v-if="!isEmpty(value.pass)">{{ value.pass ? "回答正确" : "回答错误" }}</div>
     <editor-section title="题干">
       <markdown-section :raw="value.stem" />
     </editor-section>

+ 52 - 22
src/views/student/components/StudentDoQuiz.vue

@@ -1,29 +1,33 @@
 <template>
-  <div>
+  <div class="do-quiz">
     <back-title>{{ quiz.name }}</back-title>
     <form @submit.prevent="handleFormSubmit">
-      <button>提交</button>
-      <div :key="question.id" v-for="(question, index) in quiz.questions">
-        <div>{{ index + 1 }}.</div>
-        <markdown-section :raw="question.stem" />
-        <div v-if="question.kind === QuestionKind.choice">
-          <label :key="index" v-for="(item, index) in question.options">
-            <input v-model="question.studentAnswer" type="radio" :value="index" />
-            <markdown-section style="display: inline" :raw="item" />
-          </label>
-        </div>
-        <div v-else-if="question.kind === QuestionKind.trueOrFalse">
-          <label>
-            <input v-model="question.studentAnswer" type="radio" :value="true" />
-            √
-          </label>
-          <label>
-            <input v-model="question.studentAnswer" type="radio" :value="false" />
-            ×
-          </label>
+      <c-button class="mb-16" theme="green" block>提交</c-button>
+      <div class="quiz-list mb-16" :key="question.id" v-for="(question, index) in quiz.questions">
+        <div class="quiz-list__index">{{ index + 1 }}.</div>
+        <div>
+          <markdown-section :raw="question.stem" />
+          <div v-if="question.kind === QuestionKind.choice">
+            <label class="option" :key="index" v-for="(item, index) in question.options">
+              <input v-model="question.studentAnswer" type="radio" :value="index" />
+              {{ index }}.
+              <markdown-section style="display: inline" :raw="item" />
+            </label>
+          </div>
+          <div v-else-if="question.kind === QuestionKind.trueOrFalse">
+            <label class="option">
+              <input v-model="question.studentAnswer" type="radio" :value="true" />
+              √
+            </label>
+            <label class="option">
+              <input v-model="question.studentAnswer" type="radio" :value="false" />
+              ×
+            </label>
+          </div>
         </div>
+
       </div>
-      <button>提交</button>
+      <c-button class="mb-16" theme="green" block>提交</c-button>
     </form>
   </div>
 </template>
@@ -33,10 +37,11 @@ import { getQuizById, submitQuiz } from '@/server/quiz'
 import { createDefaultQuiz } from '@/views/quiz/utils/default'
 import QuestionKind from '@/server/enums/question-kind'
 import MarkdownSection from '@/views/quiz/components/MarkdownSection'
+import CButton from '@/components/Basic/CButton'
 
 export default {
   name: 'StudentDoQuiz',
-  components: { MarkdownSection, BackTitle },
+  components: { CButton, MarkdownSection, BackTitle },
   data() {
     return {
       quiz: createDefaultQuiz(),
@@ -79,3 +84,28 @@ export default {
   }
 }
 </script>
+
+<style lang="scss" scoped>
+  .do-quiz {
+    margin: 0 auto;
+    max-width: 1100px;
+    padding: 64px 24px;
+  }
+  .quiz-list{
+    display: flex;
+
+    &__index{
+      margin-right: 16px;
+    }
+
+    .option{
+      display: flex;
+      align-items: center;
+      margin-top: 8px;
+
+      input{
+        margin-right: 4px;
+      }
+    }
+  }
+</style>

+ 4 - 7
src/views/student/components/StudentQuizDetail.vue

@@ -1,13 +1,9 @@
 <template>
   <tab-side-component>
     <back-title>{{quiz.name}}</back-title>
-    <router-link v-if="quiz.state === QuizState.ongoing" :to="`${$route.path}/do-quiz`">
-      <button>做题</button>
+    <router-link v-if="quiz.state === QuizState.ongoing" :to="{ name: 'student-do-quiz', params: { quizId: quiz.id}}">
+      <c-button class="mb-16" theme="green" icon="edit" block>做题</c-button>
     </router-link>
-    <div v-if="quiz.state === QuizState.closed">
-      <div>正确:{{passQuestionNums}} 题</div>
-      <div>总共:{{totalQuestionNums}} 题</div>
-    </div>
     <quiz-detail-factory :quiz-detail="quiz" />
   </tab-side-component>
 </template>
@@ -19,10 +15,11 @@ import { getQuizById } from '@/server/quiz'
 import QuizDetailFactory from '@/views/quiz/components/QuizDetailFactory'
 import { QuizState } from '@/server/enums/quiz-state'
 import { createDefaultQuiz } from '@/views/quiz/utils/default'
+import CButton from '@/components/Basic/CButton'
 
 export default {
   name: 'StudentQuizDetail',
-  components: { QuizDetailFactory, TabSideComponent, BackTitle },
+  components: { CButton, QuizDetailFactory, TabSideComponent, BackTitle },
   data() {
     return {
       quiz: createDefaultQuiz(),

+ 10 - 11
src/views/student/tabs/StudentQuiz.vue

@@ -3,17 +3,15 @@
     <div class="left">
       <h1 class="title">课程测验 <c-tag theme="green">学生</c-tag></h1>
       <div class="sub-title">待完成的测验</div>
-      <router-link :key="quiz.id" :to="`/student/quiz/${quiz.id}`" v-for="quiz in ongoingQuizzes">
-        <div>{{ quiz.name }}</div>
-        <div>{{ quiz.course && quiz.course.name }}</div>
-        <div>{{ quiz.slide && quiz.slide.name }}</div>
-      </router-link>
+      <quiz-card
+        :key="quiz.id" v-for="quiz in ongoingQuizzes"
+        :nav-path="{ name: 'student-quiz-detail', params: { quizId: quiz.id } }"
+        :quiz="quiz" hide-quiz-state hide-quiz-time />
       <div class="sub-title">已完成的测验 & 结果</div>
-      <router-link :key="quiz.id" :to="`/student/quiz/${quiz.id}`" v-for="quiz in closedQuizzes">
-        <div>{{ quiz.name }}</div>
-        <div>{{ quiz.course && quiz.course.name }}</div>
-        <div>{{ quiz.slide && quiz.slide.name }}</div>
-      </router-link>
+      <quiz-card
+        :key="quiz.id" v-for="quiz in closedQuizzes"
+        :nav-path="{ name: 'student-quiz-detail', params: { quizId: quiz.id } }"
+        :quiz="quiz" hide-quiz-state hide-quiz-time />
     </div>
     <router-view />
   </div>
@@ -23,9 +21,10 @@
 import { getQuizList } from '@/server/quiz'
 import { QuizState } from '@/server/enums/quiz-state'
 import CTag from '@/components/Basic/CTag'
+import QuizCard from '@/components/Cards/QuizCard'
 
 export default {
-  components: { CTag },
+  components: { QuizCard, CTag },
   data() {
     return {
       ongoingQuizzes: [],