Browse Source

新增考试做题页面的内容、修改考试详情页面与考试主页

yellowtaotao 4 years ago
parent
commit
6d9858dd4b

+ 11 - 3
src/views/home/exam/page-exam-item-detail.vue

@@ -4,10 +4,10 @@
     <div class="exam-item-detial-div">
       <div class="exam-item-detial">
         <div class="exam-item-detial-title">{{ examItemData.title }}</div>
-        <div class="exam-item-detial-describe">
+        <div class="exam-item-detial-txt">
           考试时间:{{ examItemData.examTime }}
         </div>
-        <div class="exam-item-detial-describe">
+        <div class="exam-item-detial-txt">
           考试时长:{{ examItemData.examTimeMins }}
         </div>
         <div class="exam-item-detial-describe">
@@ -89,12 +89,20 @@ export default {
         border-bottom: 1px solid #e4e8eb;
         line-height: 2rem;
         text-align: center;
-        font-size: 0.65rem;
+        font-size: 0.7rem;
         font-weight: bold;
         color: #000;
       }
+      .exam-item-detial-txt {
+        margin-top: 0.5rem;
+        font-size: 0.65rem;
+      }
       .exam-item-detial-describe {
         margin-top: 0.5rem;
+        font-size: 0.65rem;
+        span {
+          letter-spacing: 0.2rem;
+        }
       }
     }
   }

+ 447 - 40
src/views/home/exam/page-exam-item-doing.vue

@@ -5,29 +5,102 @@
     <div class="exam-question-countdown">
       <span>剩余考试时间:{{ timeDiff }}</span>
     </div>
-    <!-- 题序 -->
-    <div></div>
+    <!-- 题序盒子 -->
+    <div class="exam-question-list">
+      <!-- 辅助间隙,样式问题 -->
+      <div class="exam-question-start">st</div>
+      <!-- 题序 -->
+      <div
+        :class="{
+          'exam-question-item': true,
+          'exam-question-item-on': answerIndex === index,
+          'exam-question-item-down': examQuestionList[index].userAnswer.length
+        }"
+        v-for="(item, index) in examQuestionList"
+        :key="index"
+        @click="handleExamQuestionItemFun(item, index)"
+      >
+        <div>{{ index + 1 }}</div>
+      </div>
+      <!-- 辅助间隙,样式问题 -->
+      <div class="exam-question-end">en</div>
+    </div>
     <!-- 题目卡片 -->
     <div class="exam-question-div">
       <div class="exam-question-card">
-        <div class="exam-question-title">题目标题</div>
-        <div class="exam-question-options">
-          <div class="exam-question-button-box">
-            <van-button
-              class="exam-question-button"
-              type="primary"
-              color="#FE6347"
-              @click="handleSureFun"
-              >确定</van-button
-            >
-            <van-button
-              class="exam-question-button"
-              type="primary"
-              color="#FE6347"
-              @click="handleSubmitFun"
-              >交卷</van-button
+        <!-- 标题、分数、题页 -->
+        <div class="exam-question-head">
+          <div class="exam-question-head-left">
+            <div class="exam-question-head-left-icon"></div>
+            <div class="exam-question-head-left-txt">
+              {{ examQuestionList[answerIndex].typeTxt || "undefind" }}
+            </div>
+            <span class="exam-question-head-left-txt"
+              >{{ examQuestionList[answerIndex].grade || "undefind" }} 分</span
             >
           </div>
+          <div class="exam-question-head-right">
+            <span class="exam-question-head-right-now">{{
+              answerIndex + 1
+            }}</span>
+            <span>/</span>
+            <span>{{ examQuestionList.length }}</span>
+          </div>
+        </div>
+        <!-- 描述 -->
+        <div class="exam-question-describe">
+          {{ examQuestionList[answerIndex].describe }}
+        </div>
+        <!-- 答题列表 -->
+        <!-- 单选题、多选题的选项区域 -->
+        <div
+          v-if="
+            examQuestionList[answerIndex].type === questionType.singleChoice ||
+              examQuestionList[answerIndex].type === questionType.multipleChoice
+          "
+          class="exam-question-options"
+        >
+          <div
+            v-for="(item, index) in examQuestionList[answerIndex].options"
+            :key="index"
+            :class="{
+              'exam-question-options-item': true,
+              'exam-question-options-item-checked': answerValue.includes(item)
+            }"
+            @click="handleExamQuestionOptionsItemFun(item)"
+          >
+            {{ formatQuestionIndex(index) }}. {{ item }}
+          </div>
+        </div>
+        <!-- 填空题的答题区域 -->
+        <div
+          v-if="examQuestionList[answerIndex].type === questionType.gapFilling"
+          class="exam-question-gapFilling"
+        >
+          <textarea
+            ref="questionInputRef"
+            v-model="inputValue"
+            maxlength="200"
+            rows="5"
+            @change="handleExamQuestionOptionsItemFun(inputValue)"
+          />
+        </div>
+        <div class="exam-question-button-box">
+          <van-button
+            class="exam-question-button"
+            type="primary"
+            color="#FE6347"
+            @click="handleSureFun"
+            >确定</van-button
+          >
+          <van-button
+            v-if="answerIndex + 1 === examQuestionList.length"
+            class="exam-question-button"
+            type="primary"
+            color="#FE6347"
+            @click="handleSubmitFun"
+            >交卷</van-button
+          >
         </div>
       </div>
     </div>
@@ -36,15 +109,24 @@
 
 <script>
 import { mapState } from "vuex";
+import { Dialog } from "vant";
 export default {
-  name: "page-exam-question-",
+  name: "page-exam-item-doing",
   components: {},
   data() {
     return {
-      examItemData: {}, // 当前考试的信息
+      questionType: {
+        singleChoice: 1, // 单选题
+        multipleChoice: 2, // 多选题
+        gapFilling: 3 // 填空题
+      }, // 试题类型
       startTimeSeconds: null, // 考试开始时间的信息
       timeDiff: "00:00:00", // 距离考试结束的时间
-      interval: null // 计时器
+      interval: null, // 计时器
+      examQuestionList: [], // 试题列表
+      answerIndex: null, // 当前试题的下标索引
+      answerValue: [], // 当前试题的所答
+      inputValue: "" // 填空题时输入框的值
     };
   },
   created() {
@@ -55,13 +137,7 @@ export default {
       clearInterval(this.interval); // 销毁前清空计时器
     }
   },
-  watch: {
-    timeDiff(val) {
-      if (val === "00:00:00") {
-        console.log("结束了");
-      }
-    }
-  },
+  watch: {},
   computed: {
     ...mapState({
       examItem: state => state.exam.examItem
@@ -71,21 +147,163 @@ export default {
     // 初始化数据信息
     initDataFun() {
       console.log("考试信息:", this.examItem);
-      if (!this.examItem) {
-        return;
-      }
+      // if (!this.examItem) {
+      //   return;
+      // }
       this.getExamItemQuestionsListFun(); // 查询:当前考试的信息
-      this.getExamTimeFun(); // 获取:当前时间及考试限时
-      this.setIntervalFun(); // 设置:倒计时定时器
+      // this.getExamTimeFun(); // 获取:当前时间及考试限时
+      // this.setIntervalFun(); // 设置:倒计时定时器
     },
     // 查询:当前考试的信息
     getExamItemQuestionsListFun() {
       // TODO...
-      this.examItemData = [{ id: 1 }];
+      let httpResultData = [
+        {
+          id: 1,
+          type: 1,
+          grade: 1,
+          options: ["选项一", "选项二", "选项三"],
+          result: ["选项一"],
+          describe: "这里是描述(选项一)"
+        },
+        {
+          id: 2,
+          type: 1,
+          grade: 2,
+          options: ["选项一", "选项二", "选项三", "选项四"],
+          result: ["选项一"],
+          describe: "这里是描述,这里是描述,这里是描述(选项一)"
+        },
+        {
+          id: 3,
+          type: 2,
+          grade: 3,
+          options: ["选项一", "选项二", "选项三", "选项四"],
+          result: ["选项一", "选项二"],
+          describe:
+            "这里是描述,这里是描述,这里是描述,这里是描述,这里是描述(选项一、选项二)"
+        },
+        {
+          id: 4,
+          type: 2,
+          grade: 3,
+          options: ["选项一", "选项二", "选项三", "选项四"],
+          result: ["选项一", "选项二", "选项三"],
+          describe:
+            "这里是描述,这里是描述,这里是描述,这里是描述,这里是描述(选项一、选项二、选项三)"
+        },
+        {
+          id: 5,
+          type: 3,
+          grade: 4,
+          options: [],
+          result: [1],
+          describe:
+            "这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述(1)"
+        },
+        {
+          id: 6,
+          type: 1,
+          grade: 1,
+          options: ["选项一", "选项二", "选项三"],
+          result: ["选项一"],
+          describe: "这里是描述(选项一)"
+        },
+        {
+          id: 7,
+          type: 1,
+          grade: 2,
+          options: ["选项一", "选项二", "选项三", "选项四"],
+          result: ["选项一"],
+          describe: "这里是描述,这里是描述,这里是描述(选项一)"
+        },
+        {
+          id: 8,
+          type: 2,
+          grade: 3,
+          options: ["选项一", "选项二", "选项三", "选项四"],
+          result: ["选项一", "选项二"],
+          describe:
+            "这里是描述,这里是描述,这里是描述,这里是描述,这里是描述(选项一、选项二)"
+        },
+        {
+          id: 9,
+          type: 2,
+          grade: 3,
+          options: ["选项一", "选项二", "选项三", "选项四"],
+          result: ["选项一", "选项二", "选项三"],
+          describe:
+            "这里是描述,这里是描述,这里是描述,这里是描述,这里是描述(选项一、选项二、选项三)"
+        },
+        {
+          id: 10,
+          type: 3,
+          grade: 4,
+          options: [],
+          result: [1],
+          describe:
+            "这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述(1)"
+        },
+        {
+          id: 11,
+          type: 1,
+          grade: 1,
+          options: ["选项一", "选项二", "选项三"],
+          result: ["选项一"],
+          describe: "这里是描述(选项一)"
+        },
+        {
+          id: 12,
+          type: 1,
+          grade: 2,
+          options: ["选项一", "选项二", "选项三", "选项四"],
+          result: ["选项一"],
+          describe: "这里是描述,这里是描述,这里是描述(选项一)"
+        },
+        {
+          id: 13,
+          type: 2,
+          grade: 3,
+          options: ["选项一", "选项二", "选项三", "选项四"],
+          result: ["选项一", "选项二"],
+          describe:
+            "这里是描述,这里是描述,这里是描述,这里是描述,这里是描述(选项一、选项二)"
+        },
+        {
+          id: 14,
+          type: 2,
+          grade: 3,
+          options: ["选项一", "选项二", "选项三", "选项四"],
+          result: ["选项一", "选项二", "选项三"],
+          describe:
+            "这里是描述,这里是描述,这里是描述,这里是描述,这里是描述(选项一、选项二、选项三)"
+        },
+        {
+          id: 15,
+          type: 3,
+          grade: 4,
+          options: [],
+          result: [1],
+          describe:
+            "这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述(1)"
+        }
+      ];
+      this.examQuestionList = this.setPersonDataFun(httpResultData);
+      this.handleExamQuestionItemFun(this.examQuestionList[0], 0); // 设置第一题开始
+    },
+    // 方法:过滤试题的类型,添加用户作答的字段
+    setPersonDataFun(httpResultData) {
+      httpResultData.forEach(item => {
+        item.typeTxt = this.formatQuestionType(item.type);
+        item.userAnswer = [];
+      });
+      return httpResultData;
     },
     // 获取:当前时间及考试限时
     getExamTimeFun() {
-      let tarTime = this.timeEvent(this.examItem.examTimeMins);
+      let tarTime = this.getTimeHoursMinuteSecondsFun(
+        this.examItem.examTimeMins
+      );
       let curTime = new Date();
       // 在当前时间curTime变量上加上小时
       let addHour = curTime.setHours(curTime.getHours() + tarTime.hours);
@@ -103,7 +321,7 @@ export default {
       this.startTimeSeconds = curTime.getTime();
     },
     // 方法:分别获取时 分 秒
-    timeEvent(e) {
+    getTimeHoursMinuteSecondsFun(e) {
       let time = e;
       let len = time.split(":");
       if (len.length === 3) {
@@ -155,10 +373,101 @@ export default {
         }
       }, 1000);
     },
+    // 方法:过滤试题的类型
+    formatQuestionType(type) {
+      let typeTxt = "";
+      switch (type) {
+        case this.questionType.singleChoice:
+          typeTxt = "单选题";
+          break;
+        case this.questionType.multipleChoice:
+          typeTxt = "多选题";
+          break;
+        case this.questionType.gapFilling:
+          typeTxt = "填空题";
+          break;
+        default:
+          break;
+      }
+      return typeTxt;
+    },
+    // 方法:过滤选项的编号
+    formatQuestionIndex(index) {
+      return String.fromCharCode(index + 65);
+    },
+    // 操作:点击了某个题序
+    handleExamQuestionItemFun(item, index) {
+      if (this.answerIndex === index) {
+        return;
+      }
+      this.answerIndex = index;
+      switch (this.examQuestionList[this.answerIndex].type) {
+        case this.questionType.singleChoice:
+        case this.questionType.multipleChoice:
+          this.answerValue = [
+            ...new Set(this.examQuestionList[this.answerIndex].userAnswer)
+          ];
+          break;
+        case this.questionType.gapFilling:
+          this.answerValue = [
+            ...new Set(this.examQuestionList[this.answerIndex].userAnswer)
+          ];
+          this.inputValue = this.answerValue[0] || "";
+          break;
+        default:
+          break;
+      }
+    },
+    // 操作:作答了某个选项
+    handleExamQuestionOptionsItemFun(value) {
+      let answerQuestionType = this.examQuestionList[this.answerIndex].type;
+      switch (answerQuestionType) {
+        // 单选题
+        case this.questionType.singleChoice:
+          this.answerValue = [value];
+          break;
+        // 多选题
+        case this.questionType.multipleChoice:
+          // 遍历所答的数组,看是否有重复的
+          let repetitiveIndex = null;
+          for (let i = 0; i < this.answerValue.length; i++) {
+            let it = this.answerValue[i];
+            if (value === it) {
+              repetitiveIndex = i;
+              break;
+            }
+          }
+          // 如果有重复的就移除
+          if (repetitiveIndex !== null) {
+            this.answerValue.splice(repetitiveIndex, 1);
+          } else {
+            this.answerValue.push(value);
+          }
+          break;
+        // 填空题
+        case this.questionType.gapFilling:
+          this.$refs.questionInputRef.blur(); // 清除input的焦点
+          this.answerValue = [value];
+          break;
+        default:
+          break;
+      }
+    },
     // 操作:确定
-    handleSureFun() {},
+    handleSureFun() {
+      this.examQuestionList[this.answerIndex].userAnswer = this.answerValue;
+    },
     // 操作:交卷
-    handleSubmitFun() {}
+    handleSubmitFun() {
+      Dialog.confirm({
+        title: "温馨提示",
+        message: "确认交卷?"
+      })
+        .then(() => {
+          // TODO...
+        })
+        .catch(() => {});
+    }
   }
 };
 </script>
@@ -176,20 +485,118 @@ export default {
     display: flex;
     justify-content: flex-end;
     align-items: center;
+    padding: 0 0.5rem;
+    font-size: 0.65rem;
     span {
       color: #666;
     }
   }
+  .exam-question-list {
+    display: flex;
+    flex-wrap: nowrap;
+    overflow-x: scroll;
+    overflow-y: hidden;
+    padding: 0.25rem 0;
+    background-color: #fff;
+    .exam-question-start {
+      width: 0.2rem;
+      height: 100%;
+      color: #fff;
+    }
+    .exam-question-end {
+      width: 1em;
+      height: 1.5rem;
+      color: #fff;
+    }
+    .exam-question-item {
+      margin-left: 0.3rem;
+      background-color: #f3f3f3;
+      border: 1px solid transparent;
+      > div {
+        width: 1.25rem;
+        height: 1.5rem;
+        text-align: center;
+        line-height: 1.5rem;
+      }
+    }
+    .exam-question-item-down {
+      background-color: #f8e7d7;
+    }
+    .exam-question-item-on {
+      border-color: #fe6347;
+      color: #fe6347;
+    }
+  }
   .exam-question-div {
     padding: 0.5rem 0.5rem;
     .exam-question-card {
-      padding: 0 0.5rem 0.5rem;
+      padding: 0.5rem 0.5rem;
       background-color: #fff;
       border-radius: 4px;
       box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.16);
-      .exam-question-title {
+      .exam-question-head {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        flex-wrap: nowrap;
+        border-bottom: 1px solid #fe6347;
+        padding-bottom: 0.25rem;
+        height: 1.25rem;
+        font-size: 0.65rem;
+        .exam-question-head-left {
+          display: flex;
+          align-items: center;
+          flex-wrap: nowrap;
+          .exam-question-head-left-icon {
+            width: 0.25rem;
+            height: 1rem;
+            background-color: #fe6347;
+          }
+          .exam-question-head-left-txt {
+            margin-left: 0.25rem;
+            font-weight: bold;
+          }
+        }
+        .exam-question-head-right {
+          span {
+            color: #666;
+          }
+          .exam-question-head-right-now {
+            font-weight: bold;
+            color: #000;
+          }
+        }
+      }
+      .exam-question-describe {
+        padding: 0.5rem 0;
+        font-size: 0.65rem;
       }
       .exam-question-options {
+        .exam-question-options-item {
+          width: 100%;
+          padding: 0.5rem 0.25rem;
+          background-color: #f3f3f3;
+          margin-bottom: 0.5rem;
+          border: 1px solid transparent;
+        }
+        .exam-question-options-item-checked {
+          border-color: #fe6347;
+          color: #fe6347;
+        }
+      }
+      .exam-question-gapFilling {
+        padding-top: 0.5rem;
+        textarea {
+          width: 100%;
+          padding: 0.25rem 0.25rem;
+          background-color: #f3f3f3;
+          margin-bottom: 0.5rem;
+          border: 1px solid transparent;
+          &:active,
+          &:focus {
+            border-color: #fe6347;
+          }
+        }
       }
       .exam-question-button-box {
         display: flex;

+ 8 - 2
src/views/home/exam/page-exam.vue

@@ -12,7 +12,9 @@
         <div class="exam-item-describe">
           考试时长:{{ item.examTimeMinsTxt }}
         </div>
-        <div class="exam-item-describe">考试描述:{{ item.examDescribe }}</div>
+        <div class="exam-item-describe">
+          考试描述:<span>{{ item.examDescribe }}</span>
+        </div>
       </div>
     </div>
   </div>
@@ -49,7 +51,8 @@ export default {
           examTime: "",
           examTimeMins: "17:31:40",
           examTimeMinsTxt: "17小时31分钟40秒",
-          examDescribe: "可以回家做"
+          examDescribe:
+            "可以回家做,可以回家做,可以回家做,可以回家做,可以回家做,可以回家做,可以回家做,可以回家做"
         },
         {
           id: 3,
@@ -115,6 +118,9 @@ export default {
       }
       .exam-item-describe {
         margin-top: 0.5rem;
+        span {
+          letter-spacing: 0.2rem;
+        }
       }
     }
   }