vue 試卷控件 彈出模式

代碼

 paperConfig:{
          type:3,
          title: '閱卷',
          visible: true,
          paperData:{
            //試卷ID
            paperId:'1',
            //試卷名稱
            paperName: '測試試卷',
            //考生ID
            examineId:'1000',
            //考生名稱
            examineName: '張三',
            //分數
            score: 80,
            //考試時長
            examDuration: 90,
            //交卷時間
            submissionTime: '2019-11-25 16:30:26',
            //題目集合
            list:[
              {
                //題目類型 1.單選題 2.多選題 3.判斷題 4.填空題 5.簡答題
                type:2, no:1, subject:'以下屬於南方電網員工職業操守中明文規定的有()',totalScore:6,
                answers:[
                  {no:'A',answer:'熱愛祖國、熱愛南網、熱愛崗位'},
                  {no:'B',answer:'遵紀守法、忠於職守、令行禁止'},
                  {no:'C',answer:'客戶至上、誠實守信、優質服務'}
                ],examineAnswer:['A','B'],correctAnswer:['A','B','C'],
                answerAnalysis:'答案解析.......',isHook:2,score:0,
              },
              {
                //題目類型 1.單選題 2.多選題 3.判斷題 4.填空題 5.簡答題
                type:1, no:1, subject:'在生產管理信息系統中,下列操作步驟能正確將工單推進流程的是( )',totalScore:1,
                answers:[
                  {no:'A',answer:'在工具欄中點擊“workflow”標籤'},
                  {no:'B',answer:'在缺陷單界面中點擊“推進流程”按鈕'},
                  {no:'C',answer:'在缺陷單界面中點擊“提交”按鈕'}
                ],examineAnswer:'A',correctAnswer:'B',
                answerAnalysis:'答案解析.......',isHook:2,score:0,
              },
              {
                //題目類型 1.單選題 2.多選題 3.判斷題 4.填空題 5.簡答題
                type:1, no:2, subject:'在營銷系統中查詢客戶有無欠費、餘額及抄表數據接待客戶時應做到哪些最基本的禮儀?',totalScore:5,
                answers:[
                  {no:'A',answer:'起身、微笑、示坐、問候客戶'},
                  {no:'B',answer:'坐着,問候客戶'},
                  {no:'C',answer:'請問需要辦理什麼業務'}
                ],examineAnswer:'A',correctAnswer:'A',
                answerAnalysis:'答案解析.......',isHook:1,score:5,
              },

              {
                //題目類型 1.單選題 2.多選題 3.判斷題 4.填空題 5.簡答題
                type:3, no:1, subject:'記錄一次與人有效溝通的案例',totalScore:10,
                answers:[],examineAnswer:'對',correctAnswer:'對',
                answerAnalysis:'答案解析.......',isHook:1,score:10,
              },
              {
                //題目類型 1.單選題 2.多選題 3.判斷題 4.填空題 5.簡答題
                type:4, no:1, subject:'打招呼的方式一般有()()()()',totalScore:10,
                answers:[],examineAnswer:'寒暄式',correctAnswer:['寒暄式','問候式','致意式','致禮式'],
                answerAnalysis:'答案解析.......',isHook:1,score:10,
              },
              {
                //題目類型 1.單選題 2.多選題 3.判斷題 4.填空題 5.簡答題
                type:5, no:1, subject:'請簡單說一下你對禮儀的認識與理解',totalScore:10,
                answers:[],examineAnswer:'寒暄式',correctAnswer:'',
                answerAnalysis:'答案解析.......',isHook:1,score:10,
              }
            ]
          }
        }

控件

<template>
  <el-dialog
    :title="title"
    :visible.sync="visible"
    :width="this.width+'px'"
    :close-on-click-modal="false"
    :close-on-press-escape="false"
    @opened="initPage"
  >
    <div class="paper-main" :style="'height:'+this.height+'px;'">
      <div class="paper-header">
        <el-form label-position="top" label-width="100px" :model="tempDataSource" style="padding-top:0px; ">
          <el-row>
            <el-col :span="4" :offset="1">
              <el-form-item label="試卷">
                {{dataSource.paperName}}
              </el-form-item>
            </el-col>
            <el-col :span="4">
              <el-form-item label="考生">
                {{dataSource.examineName}}
              </el-form-item>
            </el-col>
            <el-col :span="4">
              <el-form-item label="分數" v-if="this.type===2 || this.type===3">
                {{dataSource.score}}
              </el-form-item>
            </el-col>
            <el-col :span="4">
              <el-form-item label="考試時長">
                {{dataSource.examDuration}}分
              </el-form-item>
            </el-col>
            <el-col :span="4" v-if="this.type===1">
              <el-form-item label="倒計時間">
                <span class="downTime">{{hour? hourString+':'+minuteString+':'+secondString : minuteString+':'+secondString}}</span>
              </el-form-item>
            </el-col>
            <el-col :span="4">
              <el-form-item label="交卷時間" v-if="this.type===2 || this.type===3">
                {{dataSource.submissionTime}}
              </el-form-item>
            </el-col>
          </el-row>
        </el-form>
      </div>
      <div ref="paperLeft" class="paper-left">
        <div class="paper-title">
          <h1><i class="el-icon-s-grid"></i>答題卡</h1>
        </div>
        <el-collapse v-model="answerCardActiveName">
          <el-collapse-item v-for="item in convertDatas"   :name="item.code" >
            <template slot="title">
              <h2>{{item.name}}</h2><spn>共{{item.count}}題</spn>
            </template>
            <el-button  class="answer-button" circle size="small" v-for="index of item.count" :id="'answer'+item.code+index"  @click.native="jump(item.code+index)">{{index}}</el-button>
          </el-collapse-item>
        </el-collapse>
      </div>
      <div ref="paperContent" class="paper-content">
        <div class="subject" v-for="item in convertDatas">
          <div class="subject-title" >
            <h2>{{item.name}}</h2><spn>(共 {{item.count}} 題,合計 {{item.totalScore}} 分)</spn>
          </div>
          <el-card class="box-card" v-for="(sub,index) in item.childs" :id="item.code+(index+1)">
            <div slot="header" class="clearfix">
              <el-tag effect="dark"> {{sub.no}} </el-tag>
              <span>{{sub.type===4?'':sub.subject}}</span>
              <span>({{sub.totalScore}}分)</span>
              <div v-if="type===2 || type===3" style="float: right; padding: 3px 0">
                <el-radio-group v-model="sub.isHook">
                  <el-radio-button :disabled="disabledRead" :label="1"  @change.native="isHookButtionCheck(sub)"><i class="el-icon-check"/></el-radio-button>
                  <el-radio-button :disabled="disabledRead" :label="2"  @change.native="isHookButtionCheck(sub)"><i class="el-icon-close"/></el-radio-button>
                </el-radio-group>
                <div v-if="sub.type===1 ||sub.type===2||sub.type===3" style="display: inline;">
                  <el-input :disabled="true" v-model="sub.score" style="width:50px" ></el-input><span>分</span>
                </div>
                <div v-else style="display: inline;">
                  <el-input :disabled="disabledRead" v-model="sub.score" style="width:50px" ></el-input><span>分</span>
                </div>

              </div>
            </div>
            <el-radio-group v-if="sub.type===1" v-model="sub.examineAnswer">
              <el-radio :disabled="disabledAnswer" v-for="o in sub.answers"  :label="o.no" class="answer-radio" @change="answerButtionCheck($event,item,sub)">{{o.no}}.{{o.answer}}</el-radio>
            </el-radio-group>
            <el-checkbox-group v-if="sub.type===2" v-model="sub.examineAnswer">
              <el-checkbox :disabled="disabledAnswer" v-for="o in sub.answers" :label="o.no" class="answer-checkbox" @change="answerButtionCheck($event,item,sub)">{{o.no}}.{{o.answer}}</el-checkbox>
            </el-checkbox-group>
            <el-radio-group v-if="sub.type===3" v-model="sub.examineAnswer">
              <el-radio :disabled="disabledAnswer" label="對" class="answer-radio" @change="answerButtionCheck($event,item,sub)">對</el-radio>
              <el-radio :disabled="disabledAnswer" label="錯" class="answer-radio" @change="answerButtionCheck($event,item,sub)">錯</el-radio>
            </el-radio-group>
            <div v-if="sub.type===4">
                <template v-for="(subject,subindex) in sub.subjectList">
                  <span v-if="subject" style="margin-right: 5px;">{{subject}}</span>
                  <el-input v-else :disabled="disabledAnswer" v-model="sub.newExamineAnswer[subindex]" style="width: 150px;margin-right: 5px;" @blur="answerButtionCheck($event,item,sub)"> </el-input>
                </template>
            </div>
            <el-input :disabled="disabledAnswer"  v-if="sub.type===5" type="textarea" :rows="10"  v-model="sub.examineAnswer" resize="none" maxlength="2000" @blur="answerButtionCheck($event,item,sub)"> </el-input>
            <div v-if="type!==1" class="subject-remark">
              <!--<div class="item">-->
                <!--<span class="title">考生答案:</span>-->
                <!--<span>{{converAnswerStr(sub.examineAnswer)}}</span>-->
              <!--</div>-->
              <div class="item">
                <span class="title">正確答案:</span>
                <span>{{converAnswerStr(sub.correctAnswer)}}</span>
              </div>
              <div class="item">
                <span class="title">答案解析:</span>
                <span>{{sub.answerAnalysis}}</span>
              </div>
            </div>
          </el-card>
        </div>
      </div>
    </div>
    <span slot="footer" v-if="type===1 || type===2">
      <el-button v-if="type===1" type="success" @click.native="btnClick('handPaper')">交卷</el-button>
      <el-button v-if="type===2" type="success" @click.native="btnClick('readPaper')">閱卷</el-button>
      <el-button v-if="type===2" type="success" @click.native="btnClick('readPaperUpper')">上一個</el-button>
      <el-button v-if="type===2" type="success" @click.native="btnClick('readPaperNext')">下一個</el-button>
    </span>
  </el-dialog>
</template>

<script>
  export default {
    name: 'examinationPaper',
    props: {
      // 標題
      title: {
        type: String
      },
      // 是否顯示
      visible: {
        type: Boolean
      },
      //試卷類型  1 試卷-考試 2 試卷-閱卷 3 試卷-查看
      type: {
        type: Number,
        default: 1
      },
      //數據源
      dataSource: {
        type: Object,
        default: () => {
          return {
            //試卷名稱
            paperName: '',
            //考生名稱
            examineName: '',
            //分數
            score: null,
            //考試時長(分鐘)
            examDuration: null,
            //交卷時間
            submissionTime: '',
            //擴展數據
            extData:{},
            //題目集合
            list: [
              {
                //題目類型 1.單選題 2.多選題 3.判斷題 4.填空題 5.簡答題
                type: null,
                //題號
                no: null,
                //題目
                subject: '',
                //題目總分
                totalScore: null,
                //答案集合
                answers: [
                  {
                    //答案序號
                    no: '',
                    //答案
                    answer: ''
                  }
                ],
                //考生答案
                examineAnswer: null,//1.單選題 '' 2.多選題 ['1','2'] 3.判斷題 '' 4.填空題  ['1','2'] 5.簡答題 ''
                //正確答案
                correctAnswer: null,//1.單選題 '' 2.多選題 ['1','2'] 3.判斷題 '' 4.填空題  ['1','2'] 5.簡答題 ''
                //答案解析
                answerAnalysis: '',
                //是否對錯  1.對 2.錯
                isHook: null,
                //得分
                score: null
              }
            ]
          }
        }
      },
    },
    data() {
      return {
        //倒計小時
        hour: '',
        //倒計分鐘
        minute: '',
        //倒計秒
        second: '',
        //計時器
        promiseTimer: '',
        //數據源
        tempDataSource: {},
        //答題卡激活項
        answerCardActiveName: [],
        //組裝後數據集
        convertDatas: [],
        //禁止答題
        disabledAnswer: false,
        //禁止閱卷
        disabledRead: false,
        //寬度
        width:0,
        //高度
        height:0,

      }
    },
    watch: {
      dataSource(newValue, oldValue) {
        Object.assign(this.tempDataSource, newValue)

        this.convertData()
      }
    },
    created() {

      Object.assign(this.tempDataSource, this.dataSource)
      if(!this.tempDataSource.list)this.tempDataSource.list=[]
      this.convertData()
      if (this.type === 2) {
        this.disabledAnswer = true
      }
      if (this.type === 3) {
        this.disabledAnswer = true
        this.disabledRead = true
      }
    },
    computed: {
      hourString() {
        return this.hour < 10 ? '0' + this.hour : '' + this.hour
      },
      minuteString() {
        return this.minute < 10 ? '0' + this.minute : '' + this.minute
      },
      secondString() {
        return this.second < 10 ? '0' + this.second : '' + this.second
      }
    },
    mounted() {
      let vue =this;
      vue.getClientWidth();
      vue. getClientHeight();
      window.addEventListener('resize', function() {
        vue.getClientWidth();
        vue. getClientHeight();
      })
    },
    methods: {

      /**界面寬度 */
      getClientWidth() {
        this.width= window.document.body.clientWidth - 40
      },

      /**界面高度 */
      getClientHeight() {
        this.height= (window.document.body.clientHeight - 160)
      },
      /**
       * 頁面加載
       */
      initPage() {
        if (this.type === 1) {
          let remainTime = this.dataSource.examDuration * 60
          if (remainTime > 0) {
            this.hour = Math.floor((remainTime / 3600) % 24)
            this.minute = Math.floor((remainTime / 60) % 60)
            this.second = Math.floor(remainTime % 60)
            this.countDowm()
          }
        }

        if (this.type === 2 || this.type === 3) {
          this.convertDatas.forEach(t => {
            t.childs.forEach(c => {
              this.answerButtionCheck(c.examineAnswer, t, c)
            })
          })
        }

      },
      /**
       * 按鈕點擊事件
       */
      btnClick(type) {
        console.log(this.tempDataSource)
        debugger
        this.tempDataSource.list.forEach(t=>{
          if(t.type===4)
          {
            t.subjectList = t.subject.split('{}')
            t.examineAnswer=[]
            t.newExamineAnswer.forEach(e=>{
              if(e)
              {
                t.examineAnswer.push(e)
              }
            })
            // delete t.newExamineAnswer
            // delete t.subjectList

          }
        })
        switch (type) {
          //交卷
          case 'handPaper':
            this.$emit('PaperHand', this.tempDataSource)
            break
          //閱卷
          case 'readPaper':
            this.$emit('paperRead', this.tempDataSource)
            break
          //閱卷 上一個
          case 'readPaperUpper':
            this.$emit('paperReadUpper')
            break
          //閱卷 下一個
          case 'readPaperNext':
            this.$emit('paperReadNext')
            break
        }
      },
      /**
       * 錨點定位
       */
      jump(postion) {
        let jump = this.$refs.paperContent.querySelectorAll('#' + postion)
        // 獲取需要滾動的距離
        let total = jump[0].offsetTop
        //實現form錨點定位
        this.$refs.paperContent.scrollTop = jump[0].offsetTop
      },
      /**
       *對錯選擇
       */
      isHookButtionCheck(val) {
        if (val.type === 1 || val.type === 2 || val.type === 3) {
          if (val.isHook === 1) {
            val.score = val.totalScore
          }
          if (val.isHook === 2) {
            val.score = 0
          }
        }
      },
      /**
       *答題卡選中
       */
      answerButtionCheck(value, parent, child) {
        let answerId = 'answer' + parent.code + child.no
        let but = this.$refs.paperLeft.querySelectorAll('#' + answerId)
        if (but.length > 0) {
          if (but[0].className.indexOf('answer-button-check') > -1) {
            if(child.examineAnswer instanceof Array)
            {
              let t=false;
              child.examineAnswer.forEach(e=>{
                 if(e){t=true}
              })
              if(!t)
              {
                but[0].classList.remove('answer-button-check')
              }
            }
            else{
              if (!child.examineAnswer) {
                but[0].classList.remove('answer-button-check')
              }
            }
          } else {
            if(child.examineAnswer instanceof Array)
            {
              let t=false;
              child.examineAnswer.forEach(e=>{
                if(e){t=true}
              })
              if(t)
              {
                but[0].classList.add('answer-button-check')
              }
            }
            else{
              if (child.examineAnswer) {
                but[0].classList.add('answer-button-check')
              }
            }
          }

        }
      },
      /**
       * 轉換答案
       */
      converAnswerStr(answer) {
        if (answer instanceof Array) {
          return answer.join('  ')
        }
        return answer
      },
      /**
       * 轉換數據
       */
      convertData() {
        let sorted = this.groupBy(this.tempDataSource.list, function(item) {
          return [item.type]
        })
        this.convertDatas = []
        this.answerCardActiveName = []
        this.orderBy(sorted, 'key', 'asc')
        sorted.forEach(item => {
          let totalScore = 0
          item.value.forEach(t => {
            totalScore += t.totalScore
          })
          switch (item.key) {
            case '[1]':
              this.convertDatas.push({
                name: '單選題',
                code: 'Single',
                count: item.value.length,
                totalScore: totalScore,
                childs: item.value
              })
              this.answerCardActiveName.push('Single')
              break
            case '[2]':
              this.convertDatas.push({
                name: '多選題',
                code: 'Multiple',
                count: item.value.length,
                totalScore: totalScore,
                childs: item.value
              })
              this.answerCardActiveName.push('Multiple')
              break
            case '[3]':
              this.convertDatas.push({
                name: '判斷題',
                code: 'Judgment',
                count: item.value.length,
                totalScore: totalScore,
                childs: item.value
              })
              this.answerCardActiveName.push('Judgment')
              break
            case '[4]':
              item.value.forEach(t=>{
                t.subjectList = t.subject.replace('{}','∷{}∷').split('∷')
                t.newExamineAnswer=[]
                let index=0;
                t.subjectList.forEach(e=>{
                    if(e)
                    {
                       t.newExamineAnswer.push("")
                    }
                    else{
                      t.newExamineAnswer.push(t.examineAnswer[index])
                      index++
                    }
                });

              })

              this.convertDatas.push({
                name: '填空題',
                code: 'Blank',
                count: item.value.length,
                totalScore: totalScore,
                childs: item.value,
              })
              this.answerCardActiveName.push('Blank')
              break
            case '[5]':
              this.convertDatas.push({
                name: '簡答題',
                code: 'Answer',
                count: item.value.length,
                totalScore: totalScore,
                childs: item.value
              })
              this.answerCardActiveName.push('Answer')
              break
          }

        })

      },
      /**
       * 排序
       * @param {} datas 數組
       * @param {} col 列
       * @param {} type 類型 desc,asc
       * @returns {}
       */
      orderBy(datas, col, type) {
        let m
        for (let i = 0; i < datas.length; i++) {
          for (let k = 0; k < datas.length; k++) {
            if (type === 'asc') {
              if (datas[i][col] < datas[k][col]) {
                m = datas[k]
                datas[k] = datas[i]
                datas[i] = m
              }
            } else if (type === 'desc') {
              if (datas[i][col] > datas[k][col]) {
                m = datas[k]
                datas[k] = datas[i]
                datas[i] = m
              }
            }
          }
        }
        return datas
      },
      /**
       * 分組
       * @param array 數據集
       * @param f 函數
       * let sorted = groupBy(list, function(item){ return [item.name];});
       */
      groupBy(array, f) {
        const groups = {}
        const keyValues = []
        array.forEach(function(o) {
          const group = JSON.stringify(f(o))
          groups[group] = groups[group] || []
          groups[group].push(o)
        })
        Object.keys(groups).map(function(group) {
          return keyValues.push({ key: group, value: groups[group] })
        })
        return keyValues
      },
      /**
       * 倒計時
       */
      countDowm() {
        let self = this
        clearInterval(this.promiseTimer)
        this.promiseTimer = setInterval(function() {
          if (self.hour === 0 && self.minute === 0 && self.second === 0) {
            self.disabledAnswer = true
          }
          if (self.hour === 0) {
            if (self.minute !== 0 && self.second === 0) {
              self.second = 59
              self.minute -= 1
            } else if (self.minute === 0 && self.second === 0) {
              self.second = 0
              self.$emit('countDowmEnd', true)
              clearInterval(self.promiseTimer)
            } else {
              self.second -= 1
            }
          } else {
            if (self.minute !== 0 && self.second === 0) {
              self.second = 59
              self.minute -= 1
            } else if (self.minute === 0 && self.second === 0) {
              self.hour -= 1
              self.minute = 59
              self.second = 59
            } else {
              self.second -= 1
            }
          }
        }, 1000)
      }
    }

  }
</script>

<style scoped>
  .paper-main {
    overflow: hidden
  }

  .paper-header {
    width: 100%;
    height: 60px;
    background-color: #f7f7f7;
    z-index: 1000;
    box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .1);
    -webkit-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .1);
  }

  .paper-left {
    position: absolute;
    padding: 10px;
    top: 115px;
    bottom: 50px;
    width: 300px;
    overflow-x: hidden;
    overflow-y: auto;
    border: 1px solid #e4e4e4;
    border-top: none;
  }

  .paper-content {
    position: absolute;
    left: 305px;
    top: 115px;
    right: 10px;
    bottom: 50px;
    overflow-x: hidden;
    overflow-y: auto;
    box-sizing: border-box;
    padding: 10px;
    border: 1px solid #e4e4e4;
    border-top: none;
  }

  .paper-title {
    padding-left: 10px;
    width: 100%;
    height: 45px;
    line-height: 45px;
    background: #f7f7f7;
  }

  .paper-title h1 {
    font-size: 1.2em;
    margin: 0;
  }

  .downTime {
    color: rgb(230, 93, 110);
    font-size: 16px;
    font-weight: bold;
  }

  .answer-button {
    padding: 0px;
    color: #0a0a0a;
    background-color: #ffffff;
    border-color: #e4e4e4;
    margin-left: 10px;
    width: 30px;
    height: 30px;
  }

  .answer-button:hover {
    background: #ecf1ef;
    border-color: #e4e4e4;
    color: #0a0a0a;
  }

  .answer-button-check {
    background: #13ce66;
    border-color: #30B08F;
  }

  .answer-radio {
    display: list-item;
    margin: 5px 0px;
  }

  .answer-checkbox {
    display: list-item;
    margin: 5px 0px;
  }

  .subject-title {
    padding-left: 10px;
    width: 100%;
    height: 45px;
    line-height: 45px;
    background: #f7f7f7;
    box-shadow: 0 1px 1px 0 rgba(0, 0, 0, .1);
    -webkit-box-shadow: 0 1px 1px 0 rgba(0, 0, 0, .1);
  }

  .subject-title h2 {
    font-size: 16px;
    display: inline-block;
  }

  .subject-title span {
    font-size: 16px;
    display: inline-block;
  }

  .subject-remark {
    margin-top: 10px;
    background: #f7f7f7;
  }

  .subject-remark .item {
    display: block;
    padding: 5px;
  }

  .subject-remark .title {
    font-weight: bold;
  }

  .el-radio >>> .el-radio__input.is-checked .el-radio__inner {
    background-color: #13ce66;
    border-color: #13ce66;
  }

  .el-radio-button >>> .el-radio-button__inner {
    padding: 10px;
  }

  .el-collapse-item h2 {
    width: 150px;
    font-size: 14px;
    display: inline-block;
  }

  .el-form--label-top >>> .el-form-item__label {
    float: none;
    display: inline-block;
    text-align: left;
    padding: 0px;
  }

  .el-card {
    margin: 10px;
  }

  .el-card >>> .el-card__header {
    background-color: #ffffff;
    padding: 0px 10px;
    line-height: 35px;
    font-size: 16px;
  }

  .el-card >>> .el-card__body {
    padding: 5px 20px;
  }
</style>


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章