zengh
2021-07-27 11b43da9a556f9bc971bc3bd32725cfdbf517976
考试系统合并
4 files modified
40 files added
6487 ■■■■■ changed files
package-lock.json 10 ●●●●● patch | view | raw | blame | history
package.json 2 ●●●●● patch | view | raw | blame | history
src/api/applyexam/applyexam.js 120 ●●●●● patch | view | raw | blame | history
src/api/exam/answer.js 124 ●●●●● patch | view | raw | blame | history
src/api/exam/course.js 57 ●●●●● patch | view | raw | blame | history
src/api/exam/exam.js 84 ●●●●● patch | view | raw | blame | history
src/api/exam/examRecord.js 58 ●●●●● patch | view | raw | blame | history
src/api/exam/knowledge.js 18 ●●●●● patch | view | raw | blame | history
src/api/exam/subject.js 74 ●●●●● patch | view | raw | blame | history
src/api/exam/subjectCategory.js 41 ●●●●● patch | view | raw | blame | history
src/api/examapi/applyexam.js 47 ●●●●● patch | view | raw | blame | history
src/api/examapi/examSubjects.js 37 ●●●●● patch | view | raw | blame | history
src/api/examapi/examination.js 39 ●●●●● patch | view | raw | blame | history
src/api/examapi/performance.js 21 ●●●●● patch | view | raw | blame | history
src/api/examapi/subject.js 23 ●●●●● patch | view | raw | blame | history
src/assets/css/_fonts.scss 3 ●●●●● patch | view | raw | blame | history
src/assets/css/_responsive.scss 11 ●●●●● patch | view | raw | blame | history
src/assets/css/_theme_color.scss 29 ●●●●● patch | view | raw | blame | history
src/assets/css/mixin.scss 79 ●●●●● patch | view | raw | blame | history
src/assets/css/style.scss 1084 ●●●●● patch | view | raw | blame | history
src/assets/css/subject.scss 81 ●●●●● patch | view | raw | blame | history
src/assets/css/transition.scss 12 ●●●●● patch | view | raw | blame | history
src/components/Subjects/Choices/index.vue 89 ●●●●● patch | view | raw | blame | history
src/components/Subjects/Judgement/index.vue 81 ●●●●● patch | view | raw | blame | history
src/components/Subjects/MultipleChoices/index.vue 99 ●●●●● patch | view | raw | blame | history
src/components/Subjects/PracticalOperation/index.vue 190 ●●●●● patch | view | raw | blame | history
src/components/Subjects/ShortAnswer/index.vue 73 ●●●●● patch | view | raw | blame | history
src/components/Tinymce/components/editorImage.vue 103 ●●●●● patch | view | raw | blame | history
src/components/Tinymce/index.vue 162 ●●●●● patch | view | raw | blame | history
src/components/Tinymce/plugins.js 7 ●●●●● patch | view | raw | blame | history
src/components/Tinymce/toolbar.js 6 ●●●●● patch | view | raw | blame | history
src/config/env.js 2 ●●● patch | view | raw | blame | history
src/config/iconList.js 11 ●●●●● patch | view | raw | blame | history
src/const/constant.js 10 ●●●●● patch | view | raw | blame | history
src/const/errorCode.js 12 ●●●●● patch | view | raw | blame | history
src/views/applyexam/index.vue 461 ●●●●● patch | view | raw | blame | history
src/views/exam/examSubjects.vue 328 ●●●●● patch | view | raw | blame | history
src/views/exam/examination.vue 478 ●●●●● patch | view | raw | blame | history
src/views/exam/performance.vue 398 ●●●●● patch | view | raw | blame | history
src/views/exam/startexam.vue 388 ●●●●● patch | view | raw | blame | history
src/views/exam/subject.vue 263 ●●●●● patch | view | raw | blame | history
src/views/exam/topicDetails.vue 211 ●●●●● patch | view | raw | blame | history
src/views/singleperformance/index.vue 398 ●●●●● patch | view | raw | blame | history
src/views/startexam/index.vue 663 ●●●●● patch | view | raw | blame | history
package-lock.json
@@ -7471,6 +7471,11 @@
        "commander": "*"
      }
    },
    "moment": {
      "version": "2.29.1",
      "resolved": "https://registry.nlark.com/moment/download/moment-2.29.1.tgz",
      "integrity": "sha1-sr52n6MZQL6e7qZGnAdeNQBvo9M="
    },
    "move-concurrently": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
@@ -11938,6 +11943,11 @@
      "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
      "dev": true
    },
    "vue2-countdown": {
      "version": "1.0.8",
      "resolved": "https://registry.npm.taobao.org/vue2-countdown/download/vue2-countdown-1.0.8.tgz",
      "integrity": "sha1-4PILava62zPPmcjMPfUdLHfy7zU="
    },
    "vuex": {
      "version": "3.6.2",
      "resolved": "https://registry.npmjs.org/vuex/-/vuex-3.6.2.tgz",
package.json
@@ -21,6 +21,7 @@
    "js-cookie": "^2.2.0",
    "js-md5": "^0.7.3",
    "mockjs": "^1.0.1-beta3",
    "moment": "^2.29.1",
    "node-gyp": "^5.0.6",
    "nprogress": "^0.2.0",
    "portfinder": "^1.0.23",
@@ -29,6 +30,7 @@
    "vue-axios": "^2.1.2",
    "vue-i18n": "^8.7.0",
    "vue-router": "^3.0.1",
    "vue2-countdown": "^1.0.8",
    "vuex": "^3.1.1"
  },
  "devDependencies": {
src/api/applyexam/applyexam.js
New file
@@ -0,0 +1,120 @@
import request from '@/router/axios';
export const getList = (current, size, params, deptId) => {
  return request({
    url: '/api/blade-user/page',
    method: 'get',
    params: {
      ...params,
      current,
      size,
      deptId,
    }
  })
}
export const remove = (ids) => {
  return request({
    url: '/api/blade-user/remove',
    method: 'post',
    params: {
      ids,
    }
  })
}
export const add = (row) => {
  return request({
    url: '/api/blade-user/submit',
    method: 'post',
    data: row
  })
}
export const update = (row) => {
  return request({
    url: '/api/blade-user/update',
    method: 'post',
    data: row
  })
}
export const updatePlatform = (userId, userType, userExt) => {
  return request({
    url: '/api/blade-user/update-platform',
    method: 'post',
    params: {
      userId,
      userType,
      userExt,
    }
  })
}
export const getUser = (id) => {
  return request({
    url: '/api/blade-user/detail',
    method: 'get',
    params: {
      id,
    }
  })
}
export const getUserPlatform = (id) => {
  return request({
    url: '/api/blade-user/platform-detail',
    method: 'get',
    params: {
      id,
    }
  })
}
export const getUserInfo = () => {
  return request({
    url: '/api/blade-user/info',
    method: 'get',
  })
}
export const resetPassword = (userIds) => {
  return request({
    url: '/api/blade-user/reset-password',
    method: 'post',
    params: {
      userIds,
    }
  })
}
export const updatePassword = (oldPassword, newPassword, newPassword1) => {
  return request({
    url: '/api/blade-user/update-password',
    method: 'post',
    params: {
      oldPassword,
      newPassword,
      newPassword1,
    }
  })
}
export const updateInfo = (row) => {
  return request({
    url: '/api/blade-user/update-info',
    method: 'post',
    data: row
  })
}
export const grant = (userIds, roleIds) => {
  return request({
    url: '/api/blade-user/grant',
    method: 'post',
    params: {
      userIds,
      roleIds,
    }
  })
}
src/api/exam/answer.js
New file
@@ -0,0 +1,124 @@
import request from '@/router/axios'
const baseAnswerUrl = '/api/exam/v1/answer/'
export function fetchAnswerList(query) {
  return request({
    url: baseAnswerUrl + 'answerList',
    method: 'get',
    params: query
  })
}
export function getAnswer(id) {
  return request({
    url: baseAnswerUrl + id,
    method: 'get'
  })
}
export function getAnswerInfo(id, query) {
  return request({
    url: baseAnswerUrl + id + '/info',
    method: 'get',
    params: query
  })
}
export function getAnswerListInfo(id, query) {
  return request({
    url: baseAnswerUrl + 'record/' + id + '/answerListInfo',
    method: 'get',
    params: query
  })
}
export function addAnswer(obj) {
  return request({
    url: baseAnswerUrl,
    method: 'post',
    data: obj
  })
}
export function putAnswer(obj) {
  return request({
    url: baseAnswerUrl,
    method: 'put',
    data: obj
  })
}
export function delAnswer(id) {
  return request({
    url: baseAnswerUrl + id,
    method: 'delete'
  })
}
export function save(obj) {
  return request({
    url: baseAnswerUrl + 'save',
    method: 'post',
    data: obj
  })
}
export const saveAndNext = (params) => {
  return request({
    url: '/api/examScore/saveExamScore',
    method: 'post',
    data: {
      // "allGrade": 0,
      "allScore": 200,
      "candidateNo": params.securityId + '  ',
      "company": params.company,
      "examName": params.examName,
      "examResultVOS": params.examResultVOS,
      "examTime": params.examTime,
      "examType": Number(params.examType),
      "learnGrade": 0,
      "papersId": Number(params.papersId),
      "securityName": params.securityName
    }
  })
}
export function anonymousUserSaveAndNext(obj, nextType, nextSubjectId, nextSubjectType) {
  let url = baseAnswerUrl + 'anonymousUser/saveAndNext?nextType=' + nextType
  if (nextSubjectId !== undefined) {
    url += '&nextSubjectId=' + nextSubjectId
  }
  if (nextSubjectType !== undefined) {
    url += '&nextSubjectType=' + nextSubjectType
  }
  return request({
    url: url,
    method: 'post',
    data: obj
  })
}
export function submit(obj) {
  return request({
    url: baseAnswerUrl + 'submit',
    method: 'post',
    data: obj
  })
}
export function anonymousUserSubmit(obj) {
  return request({
    url: baseAnswerUrl + 'anonymousUser/submit',
    method: 'post',
    data: obj
  })
}
export function anonymousUserSubmitAll(obj, examinationId, identifier) {
  return request({
    url: baseAnswerUrl + 'anonymousUser/submitAll/' + examinationId + '?identifier=' + identifier,
    method: 'post',
    data: obj
  })
}
src/api/exam/course.js
New file
@@ -0,0 +1,57 @@
import request from '@/router/axios'
const baseCourseUrl = '/api/exam/v1/course/'
export function courseList (query) {
  return request({
    url: baseCourseUrl + 'courseList',
    method: 'get',
    params: query
  })
}
export function fetchCourseList (query) {
  return request({
    url: baseCourseUrl + 'courseList',
    method: 'get',
    params: query
  })
}
export function getObj (id) {
  return request({
    url: baseCourseUrl + id,
    method: 'get'
  })
}
export function addObj (obj) {
  return request({
    url: baseCourseUrl,
    method: 'post',
    data: obj
  })
}
export function putObj (obj) {
  return request({
    url: baseCourseUrl,
    method: 'put',
    data: obj
  })
}
export function delObj (id) {
  return request({
    url: baseCourseUrl + id,
    method: 'delete'
  })
}
export function delAllObj (obj) {
  return request({
    url: baseCourseUrl + 'deleteAll',
    method: 'post',
    data: obj
  })
}
src/api/exam/exam.js
New file
@@ -0,0 +1,84 @@
import request from '@/router/axios'
const baseExaminationUrl = '/api/exam/v1/examination/'
export function fetchList (query) {
  return request({
    url: baseExaminationUrl + 'examinationList',
    method: 'get',
    params: query
  })
}
export function fetchAllSubjectList (query) {
  return request({
    url: baseExaminationUrl + 'anonymousUser/allSubjectList',
    method: 'get',
    params: query
  })
}
export function getObj (id, query) {
  return request({
    url: baseExaminationUrl + id,
    method: 'get',
    params: query
  })
}
export function anonymousUserGetObj (id, query) {
  return request({
    url: baseExaminationUrl + 'anonymousUser/' + id,
    method: 'get',
    params: query
  })
}
export const getSubjectIds = (param) => {
  return request({
    url: '/api/exampaper/queryPagerSubject/',
    method: 'get',
    params: {
      ...param
    }
  })
}
export function anonymousUserGetSubjectIds (id, query) {
  return request({
    url: baseExaminationUrl + 'anonymousUser/' + id + '/subjectIds',
    method: 'get',
    params: query
  })
}
export function addObj (obj) {
  return request({
    url: baseExaminationUrl,
    method: 'post',
    data: obj
  })
}
export function putObj (obj) {
  return request({
    url: baseExaminationUrl,
    method: 'put',
    data: obj
  })
}
export function delObj (id) {
  return request({
    url: baseExaminationUrl + id,
    method: 'delete'
  })
}
export function delAllObj (obj) {
  return request({
    url: baseExaminationUrl + 'deleteAll',
    method: 'post',
    data: obj
  })
}
src/api/exam/examRecord.js
New file
@@ -0,0 +1,58 @@
import request from '@/router/axios'
const baseExamRecordUrl = '/api/exam/v1/examRecord/'
export function fetchList (query) {
  return request({
    url: baseExamRecordUrl + 'examRecordList',
    method: 'get',
    params: query
  })
}
export function getObj (id, query) {
  return request({
    url: baseExamRecordUrl + id,
    method: 'get',
    params: query
  })
}
export function addObj (obj) {
  return request({
    url: baseExamRecordUrl,
    method: 'post',
    data: obj
  })
}
export function start (obj) {
  return request({
    url: baseExamRecordUrl + 'start',
    method: 'post',
    data: obj
  })
}
export function anonymousUserStart (obj) {
  return request({
    url: baseExamRecordUrl + 'anonymousUser/start',
    method: 'post',
    params: obj
  })
}
export function getCurrentTime () {
  return request({
    url: '/api/exampaper/getdate',
    method: 'get'
  })
}
// 查询成绩详情
export function examRecordDetails (id) {
  return request({
    url: baseExamRecordUrl + id + '/details',
    method: 'get'
  })
}
src/api/exam/knowledge.js
New file
@@ -0,0 +1,18 @@
import request from '@/router/axios'
const baseKnowledgeUrl = '/api/exam/v1/knowledge/'
export function fetchKnowledgeList (query) {
  return request({
    url: baseKnowledgeUrl + 'knowledgeList',
    method: 'get',
    params: query
  })
}
export function getObj (id) {
  return request({
    url: baseKnowledgeUrl + id,
    method: 'get'
  })
}
src/api/exam/subject.js
New file
@@ -0,0 +1,74 @@
import request from '@/router/axios'
const baseSubjectUrl = '/api/exam/v1/subject/'
export function subjectList () {
  return request({
    url: baseSubjectUrl + 'subjectList',
    method: 'get'
  })
}
export function fetchSubjectList (query) {
  return request({
    url: baseSubjectUrl + 'subjectList',
    method: 'get',
    params: query
  })
}
export function getObj (id, query) {
  return request({
    url: baseSubjectUrl + id,
    method: 'get',
    params: query
  })
}
export function addSubject (obj) {
  return request({
    url: baseSubjectUrl,
    method: 'post',
    data: obj
  })
}
export function putSubject (obj) {
  return request({
    url: baseSubjectUrl,
    method: 'put',
    data: obj
  })
}
export function delSubject (id) {
  return request({
    url: baseSubjectUrl + id,
    method: 'delete'
  })
}
export function delAllSubject (obj) {
  return request({
    url: baseSubjectUrl + 'deleteAll',
    method: 'post',
    data: obj
  })
}
export function getSubjectAnswer (obj) {
  return request({
    url: '/api/examSubjectChoices/details',
    method: 'get',
    params: obj
  })
}
export function anonymousUserGetSubjectAnswer (obj) {
  return request({
    url: baseSubjectUrl + 'anonymousUser/subjectAnswer',
    method: 'get',
    params: obj
  })
}
src/api/exam/subjectCategory.js
New file
@@ -0,0 +1,41 @@
import request from '@/router/axios'
const baseSubjectCategoryUrl = '/api/exam/v1/subjectCategory/'
export function fetchTree (query) {
  return request({
    url: baseSubjectCategoryUrl + 'categories',
    method: 'get',
    params: query
  })
}
export function addObj (obj) {
  return request({
    url: baseSubjectCategoryUrl,
    method: 'post',
    data: obj
  })
}
export function getObj (id) {
  return request({
    url: baseSubjectCategoryUrl + id,
    method: 'get'
  })
}
export function delObj (id) {
  return request({
    url: baseSubjectCategoryUrl + id,
    method: 'delete'
  })
}
export function putObj (obj) {
  return request({
    url: baseSubjectCategoryUrl,
    method: 'put',
    data: obj
  })
}
src/api/examapi/applyexam.js
New file
@@ -0,0 +1,47 @@
import request from '@/router/axios';
export const getApplyList = (current, size, params) => {
  return request({
    url: '/api/apply/page',
    method: 'get',
    params: {
      ...params,
      current,
      size
    }
  })
}
export const addApply = (row) => {
  return request({
    url: '/api/apply/submit',
    method: 'post',
    data: row
  })
}
export const remove = (ids) => {
  return request({
    url: '/api/apply/remove',
    method: 'post',
    params: {
      ids,
    }
  })
}
export const getMenu = (id) => {
  return request({
    url: '/api/apply/detail',
    method: 'get',
    params: {
      id,
    }
  })
}
src/api/examapi/examSubjects.js
New file
@@ -0,0 +1,37 @@
import request from '@/router/axios';
export const getPaperList = (current, size, params) => {
  return request({
    url: '/api/examSubjectChoices/getEexPaperChoices',
    method: 'get',
    params: {
      ...params,
      current,
      size
    }
  })
}
export const updatePaper = (row) => {
  return request({
    url: '/api/examSubjectChoices/updateChoicesValue',
    method: 'post',
    params: {
      ...row
    }
  })
}
export const remove = (params) => {
  return request({
    url: '/api/exampaper/UnbindSubject',
    method: 'get',
    params: {
      ...params
    }
  })
}
src/api/examapi/examination.js
New file
@@ -0,0 +1,39 @@
import request from '@/router/axios';
export const getList = (current, size, params) => {
  return request({
    url: '/api/exampaper/page',
    method: 'get',
    params: {
      ...params,
      current,
      size
    }
  })
}
export const remove = (ids) => {
  return request({
    url: '/api/exampaper/remove',
    method: 'post',
    params: {
      ids,
    }
  })
}
export const add = (row) => {
  return request({
    url: '/api/exampaper/submit',
    method: 'post',
    data: row
  })
}
export const update = (row) => {
  return request({
    url: '/api/exampaper/update',
    method: 'post',
    data: row
  })
}
src/api/examapi/performance.js
New file
@@ -0,0 +1,21 @@
import request from '@/router/axios';
export const getList = (current, size, params) => {
  return request({
    url: '/api/examScore/page',
    method: 'get',
    params: {
      ...params,
      current,
      size
    }
  })
}
export const update = (row) => {
  return request({
    url: '/api/examScore/updateExamScore',
    method: 'post',
    data: row
  })
}
src/api/examapi/subject.js
New file
@@ -0,0 +1,23 @@
import request from '@/router/axios';
export const getList = (current, size, params) => {
  return request({
    url: '/api/examSubjectChoices/page',
    method: 'get',
    params: {
      ...params,
      current,
      size
    }
  })
}
export const remove = (ids) => {
  return request({
    url: '/api/examSubjectChoices/remove',
    method: 'post',
    params: {
      ids,
    }
  })
}
src/assets/css/_fonts.scss
New file
@@ -0,0 +1,3 @@
// Fonts
$opensans-font: 'Open Sans', sans-serif;
$raleway-font: 'Raleway', sans-serif;
src/assets/css/_responsive.scss
New file
@@ -0,0 +1,11 @@
$breakpoint-xl: 'only screen and (min-width:1200px)';
$breakpoint-lg: 'only screen and (min-width:992px) and (max-width:1199px)';
$breakpoint-md: 'only screen and (min-width:768px) and (max-width:991px)';
$breakpoint-sm: 'only screen and (min-width:576px) and (max-width:767px)';
$breakpoint-xs: 'only screen and (max-width:767px)';
$breakpoint-xs-landscape: 'only screen and (min-width:480px) and (max-width:767px)';
src/assets/css/_theme_color.scss
New file
@@ -0,0 +1,29 @@
// Heading Color
$heading-color: rgba(0, 0, 0, 0.8);
// Text Color
$text-color: #5a5a5a;
// Default Background
$bg-default: #3762f0;
// Gray Background
$bg-gray: #f7f7f7;
// White Color
$white-color: #ffffff;
// Dark Color
$dark-color: #1b1b1b;
// Border Color
$border-color: #ebebeb;
// Hover Color
$hover-color: #2c56df;
// Footer Color
$footer-color: #252525;
// Border Color
$border-color: #ebebeb;
src/assets/css/mixin.scss
New file
@@ -0,0 +1,79 @@
@mixin wh($w,$h:$w) {
  width: $w;
  height: $h;
}
@mixin trans-duration($time) {
  -webkit-transition-duration: $time;
  transition-duration: $time;
}
@mixin transition($value) {
  -webkit-transition: $value;
  transition: $value;
}
@mixin transform($value) {
  -webkit-transform: $value;
  transform: $value;
}
@mixin animation($value) {
  -webkit-animation: $value;
  animation: $value;
}
@mixin flex-direction($value) {
  -webkit-box-orient: horizontal;
  -webkit-box-direction: reverse;
  -ms-flex-direction: $value;
  flex-direction: $value;
}
@mixin align-items($value) {
  -webkit-box-align: $value;
  -ms-flex-align: $value;
  -ms-grid-row-align: $value;
  align-items: $value;
}
@mixin display-flex($value) {
  display: -webkit-box;
  display: -ms-flexbox;
  display: $value;
}
@mixin justify-content-between {
  -webkit-box-pack: justify;
  -ms-flex-pack: justify;
  justify-content: space-between;
}
@mixin justify-content($value) {
  -webkit-box-pack: center;
  -ms-flex-pack: center;
  justify-content: center;
}
@mixin justify-content-end {
  -webkit-box-pack: end;
  -ms-flex-pack: end;
  justify-content: flex-end;
}
@mixin flex($value) {
  -webkit-box-flex: 0;
  -ms-flex: $value;
  flex: $value;
}
@mixin flex-wrap($value) {
  -ms-flex-wrap: $value;
  flex-wrap: $value;
}
@mixin bg-gradients {
  background: #0d104d;
  background: -webkit-linear-gradient(to right, #0d104d, #28408b);
  background: linear-gradient(to right, #0d104d, #28408b);
}
src/assets/css/style.scss
New file
@@ -0,0 +1,1084 @@
@import 'theme_color';
@import '_fonts';
@import 'mixin';
@import 'responsive';
@import 'transition';
* {
  margin: 0;
  padding: 0;
}
body {
  font-family: $opensans-font;
  font-size: 14px;
  font-weight: 400;
  margin: 0;
}
h1,
h2,
h3,
h4,
h5,
h6 {
  color: $heading-color;
  line-height: 1.3;
  font-weight: 700;
}
p {
  font-family: $raleway-font;
  color: $text-color;
  font-size: 14px;
  line-height: 1.8;
  font-weight: 400;
}
a,
a:hover,
a:focus {
  @include trans-duration(500ms);
  text-decoration: none;
  outline: 0 solid transparent;
  color: $heading-color;
  font-weight: 600;
  font-size: 14px;
}
ul,
ol {
  margin: 0;
  li {
    list-style: none;
  }
}
img {
  height: auto;
  max-width: 100%;
}
.padding-80-0 {
  padding-top: 80px;
  padding-bottom: 0;
}
.mb-80 {
  margin-bottom: 80px;
}
.mb-12 {
  margin-bottom: 12px;
}
.mr-100 {
  margin-right: 100px;
}
.ml-100 {
  margin-left: 100px;
}
.padding-80 {
  padding-top: 80px;
  padding-bottom: 80px;
}
.mb-30 {
  margin-bottom: 30px;
}
.w-100 {
  width: 100%;
}
.justify-content-center {
  @include justify-content(center);
}
.align-items-center {
  @include align-items(center)
}
.d-flex {
  display: -ms-flexbox;
  display: flex;
}
.text-center {
  text-align: center;
}
.fade-enter-active, .fade-leave-active {
  transition: opacity .5s;
}
.fade-enter, .fade-leave-to {
  opacity: 0;
}
.justify-content-between {
  @include justify-content-between
}
.header-area.vue-fixed-header--isFixed {
  position: fixed;
  left: 0;
  top: 0;
  width: 100vw;
}
.header-area {
  z-index: 1500 !important;
  background-color: $white-color;
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.15);
  .clever-main-menu {
    position: relative;
    width: 100%;
    height: 70px;
    .classy-navbar {
      padding: .5em 2em;
      display: flex;
      align-items: center;
      justify-content: space-between!important;
      .nav-brand {
        color: #565656;
        display: inline-block;
        margin-right: 30px;
        font-size: 30px;
        font-weight: 600;
      }
      .nav-brand:focus, .classy-navbar .nav-brand:hover {
        font-size: 26px;
        font-weight: 500;
      }
    }
    .classynav {
      .el-menu--horizontal {
        border-bottom: none;
        .el-menu-item {
          padding: 0 12px;
          display: block;
          border-bottom: none;
        }
        .el-submenu {
          .el-submenu__title {
            border-bottom: none !important;
          }
        }
      }
    }
    .classynav ul li a {
      color: rgba(0, 0, 0, 0.45);
      font-weight: 600;
      @media #{$breakpoint-lg} {
        padding: 0 8px;
      }
      &:hover,
      &:focus {
        color: $heading-color;
      }
    }
    .classy-nav-container a {
      @include trans-duration(500ms);
      color: #232323;
      display: inline-block;
      text-decoration: none;
      outline: 0;
    }
    .search-area {
      position: relative;
      width: 230px;
      height: 40px;
      margin: 0 50px;
      @media #{$breakpoint-lg} {
        width: 170px;
        margin: 0 15px;
      }
      @media #{$breakpoint-md} {
        margin: 15px auto;
      }
      @media #{$breakpoint-xs} {
        margin: 15px auto;
      }
      input {
        width: 100%;
        height: 40px;
        border-radius: 6px;
        border: 1px solid $border-color;
        padding: 0 15px 0 50px;
        font-size: 14px;
        color: rgba(0, 0, 0, 0.35);
        font-weight: 600;
        @include trans-duration(500ms);
        &:focus {
          border: 1px solid rgba(0, 0, 0, 0.5);
        }
      }
    }
  }
}
.classy-nav-container * {
  box-sizing: border-box;
}
.classy-navbar-toggler {
  border: none;
  background-color: transparent;
  cursor: pointer;
  display: none;
}
@media only screen and (min-width: 992px) and (max-width: 1199px) {
  .clever-main-menu .classynav ul li a {
    padding: 0 8px;
  }
}
.clever-main-menu .classynav ul li a:hover, .clever-main-menu .classynav ul li a:focus {
  color: rgba(0, 0, 0, 0.8);
}
@media only screen and (min-width: 992px) and (max-width: 1199px) {
  .clever-main-menu .search-area form {
    width: 170px;
    margin: 0 15px;
  }
}
@media only screen and (min-width: 768px) and (max-width: 991px) {
  .clever-main-menu .search-area form {
    margin: 15px auto;
  }
}
@media only screen and (max-width: 767px) {
  .clever-main-menu .search-area form {
    margin: 15px auto;
  }
}
.classycloseIcon, .dd-trigger {
  position: absolute;
  display: none;
}
.breakpoint-off .classynav {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -ms-flex-align: center;
  align-items: center;
}
.breakpoint-off .classynav, .classy-navbar {
  -webkit-box-align: center;
  -ms-grid-row-align: center;
}
.register-login-area {
  position: relative;
  z-index: 1;
}
.btn:not(:disabled):not(.disabled) {
  cursor: pointer;
}
.register-login-area a {
  position: relative;
  display: inline-block;
  padding: 0 20px;
  height: 40px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 1px;
  font-size: 14px;
  color: #3762f0;
  line-height: 40px;
}
.classy-nav-container a, .classy-nav-container a:focus, .classy-nav-container a:hover {
  @include trans-duration(500ms);
  text-decoration: none;
  outline: 0;
  font-size: 14px;
  font-weight: 400;
}
.btn:not(:disabled):not(.disabled).active, .btn:not(:disabled):not(.disabled):active {
  background-image: none;
}
.btn:not(:disabled):not(.disabled) {
  cursor: pointer;
}
.register-login-area a.active, .register-login-area a:hover, .register-login-area a:focus {
  background-color: #d7e0fc;
  font-weight: 600;
  color: #3762f0;
}
.register-login-area a {
  position: relative;
  display: inline-block;
  padding: 0 20px;
  height: 40px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 1px;
  font-size: 14px;
  color: #3762f0;
  line-height: 40px;
}
.classy-nav-container a, .classy-nav-container a:focus, .classy-nav-container a:hover {
  @include trans-duration(500ms);
  text-decoration: none;
  outline: 0;
  font-size: 14px;
  font-weight: 400;
}
.el-menu-link {
  color: rgba(0, 0, 0, 0.45)!important;
  font-size: 14px;
  padding: 0 20px;
  cursor: pointer;
}
/* 首页 */
.hero-area {
  position: relative;
  z-index: 2;
  width: 100%;
  height: 325px;
  align-items: center!important;
  background-image: url("/static/img/bg-img/bg1.jpg");
  background-attachment: fixed;
  background-position: center center;
  background-size: cover;
  background-repeat: no-repeat;
  ::after {
    background-color: rgba(0, 0, 0, 0.1);
    position: absolute;
    z-index: -1;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    content: "";
  }
  .hero-content {
    text-align: center;
    h2 {
      font-size: 40px;
      margin-bottom: 10px;
      font-weight: 700;
      color: $white-color;
    }
    h4 {
      font-size: 22px;
      margin-bottom: 20px;
      font-weight: 500;
      color: $white-color;
    }
  }
}
.btn:not(:disabled):not(.disabled) {
  cursor: pointer;
}
.clever-btn {
  @include trans-duration(300ms);
  display: inline-block;
  min-width: 160px;
  height: 40px;
  background-color: #3762f0;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 1px;
  font-size: 14px;
  color: $white-color;
  border: 1px solid transparent;
  border-radius: 6px;
  padding: 0 30px;
  line-height: 40px;
  text-align: center;
}
.single-cool-facts-area {
  text-align: center;
  position: relative;
  z-index: 1;
  padding: 30px;
  border: 1px solid #ebebeb;
  border-radius: 6px;
  margin-bottom: 80px !important;
  cursor: pointer;
}
.popular-courses-area {
  position: relative;
  background-repeat: repeat;
  background-image: url(/static/img/core-img/texture.png);
  height: 600px;
}
.section-heading {
  position: relative;
  z-index: 1;
  margin-bottom: 70px;
  text-align: center;
  h3 {
    font-size: 30px;
    margin-bottom: 0;
    @media #{$breakpoint-xs} {
      font-size: 24px;
    }
  }
  &.text-left {
    text-align: left !important;
  }
  &.white {
    h3 {
      color: $white-color;
    }
  }
}
.single-popular-course {
  position: relative;
  z-index: 1;
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15);
  border-radius: 6px;
  background-color: $white-color;
  cursor: pointer;
  img {
    display: block;
    width: 100%;
    border-radius: 6px 6px 0 0;
  }
  .course-content {
    padding: 25px;
    h4 {
      margin-bottom: 5px;
    }
    .meta {
      margin-bottom: 15px;
      span {
        color: rgba(0, 0, 0, 0.4);
        font-size: 5px;
        margin-right: 10px;
      }
      a {
        color: rgba(0, 0, 0, 0.4);
        display: inline-block;
        font-size: 14px;
        font-weight: 400;
        margin-right: 10px;
        &:hover {
          color: #000;
        }
      }
    }
    p {
      margin-bottom: 0;
    }
  }
  .seat-rating-fee {
    display: inline-flex;
    width: 100%;
    height: 40px;
    background-color: $bg-gray;
    border-radius: 0 0 6px 6px;
    .seat-rating {
      font-size: 12px;
      color: rgba(0, 0, 0, 0.3);
      font-weight: 600;
      height: 100%;
      align-items: center;
      div {
        display: inline-block;
        padding: 0 20px;
        border-right: 1px solid $border-color;
        height: 100%;
        line-height: 40px;
      }
      i {
        font-size: 13px;
        color: rgba(0, 0, 0, 0.3);
      }
    }
    .course-fee {
      a {
        display: inline-block;
        width: 70px;
        height: 40px;
        border-radius: 0 0 6px 0;
        background-color: #e3d21b;
        text-align: center;
        line-height: 40px;
        font-size: 12px;
        font-weight: 700;
        text-transform: uppercase;
        color: $white-color;
        letter-spacing: 0.75px;
        &.free {
          background-color: $bg-default;
        }
      }
    }
  }
}
.single-blog-area {
  position: relative;
  z-index: 1;
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15);
  border-radius: 6px;
  cursor: pointer;
  img {
    display: block;
    width: 100%;
    border-radius: 6px 6px 0 0;
  }
  .blog-content {
    padding: 25px;
    .blog-headline {
      display: block;
      h4 {
        margin-bottom: 5px;
        margin-left: -1px;
        @include trans-duration(500ms);
        &:hover,
        &:focus {
          color: $hover-color;
        }
      }
    }
    .meta {
      margin-bottom: 15px;
      span {
        color: rgba(0, 0, 0, 0.4);
        font-size: 5px;
        margin-right: 10px;
      }
      a {
        color: rgba(0, 0, 0, 0.4);
        display: inline-block;
        font-size: 14px;
        font-weight: 400;
        margin-right: 10px;
        @media #{$breakpoint-xs} {
          font-size: 12px;
        }
        &:hover {
          color: #000;
        }
      }
    }
    p {
      margin-bottom: 0;
    }
  }
}
/* 返回顶部 */
.go-top-box {
  background-color: $white-color;
  position: fixed;
  right: 50px;
  bottom: 150px;
  width: 40px;
  height: 40px;
  border-radius: 20px;
  cursor: pointer;
  transition: .3s;
  box-shadow: 0 0 6px rgba(0,0,0,.12);
  z-index: 5;
}
.top-icon {
  color: #409eff;
  display: block !important;
  line-height: 40px !important;
  text-align: center;
  font-size: 18px;
}
.content-container {
  margin-top: 2rem;
  margin-left: 100px;
  margin-right: 100px;
}
.single-course-intro {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 350px;
  .single-course-intro-content {
    width: 425px;
    height: auto;
    padding: 30px;
    background-color: $white-color;
    border-radius: 6px;
    @media #{$breakpoint-xs} {
      width: 280px;
    }
    .ratings {
      margin-bottom: 20px;
      i {
        color: #e3d21b;
        font-size: 13px;
        padding: 0 3px;
        display: inline-block;
      }
    }
    h3 {
      font-size: 30px;
      margin-bottom: 10px;
      @media #{$breakpoint-xs} {
        font-size: 24px;
      }
    }
    .meta {
      margin-bottom: 30px;
      span {
        color: rgba(0, 0, 0, 0.4);
        font-size: 5px;
        margin-right: 10px;
      }
      a {
        color: rgba(0, 0, 0, 0.4);
        display: inline-block;
        font-size: 14px;
        font-weight: 400;
        margin-right: 10px;
        &:hover {
          color: #000;
        }
      }
    }
    .price {
      font-size: 12px;
      text-transform: uppercase;
      color: $bg-default;
      letter-spacing: 0.75px;
      font-weight: 700;
    }
  }
}
.clever-description {
  position: relative;
  z-index: 1;
  .about-course {
    padding: 40px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
    h4 {
      margin-bottom: 20px;
      display: block;
    }
    p {
      font-size: 16px;
      line-height: 1.9;
      &:last-child {
        margin-bottom: 0;
      }
    }
    @media #{$breakpoint-xs} {
      padding: 30px;
    }
  }
  .all-instructors {
    padding: 40px 40px 10px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
    @media #{$breakpoint-xs} {
      padding: 30px 30px 0;
    }
    h4 {
      margin-bottom: 25px;
      display: block;
    }
    .single-instructor {
      position: relative;
      z-index: 1;
      background-color: $bg-gray;
      border-radius: 6px;
      .instructor-thumb {
        @include flex(0 0 80px);
        width: 80px;
        max-width: 80px;
        height: 80px;
      }
      .instructor-info {
        padding-left: 25px;
        h5 {
          font-size: 18px;
          margin-bottom: 5px;
          @media #{$breakpoint-xs} {
            font-size: 14px;
          }
        }
        span {
          font-weight: 400;
          color: rgba(0, 0, 0, 0.4);
          font-size: 14px;
        }
      }
    }
  }
  .clever-faqs {
    padding: 40px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
    h4 {
      margin-bottom: 25px;
      display: block;
    }
    @media #{$breakpoint-xs} {
      padding: 30px;
    }
  }
}
.about-curriculum {
  padding: 40px;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
  h4 {
    margin-bottom: 20px;
    display: block;
  }
  p {
    font-size: 16px;
    line-height: 1.9;
    &:last-child {
      margin-bottom: 0;
    }
  }
  @media #{$breakpoint-xs} {
    padding: 30px;
  }
}
.curriculum-level {
  padding: 40px;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
  h4 {
    margin-bottom: 20px;
    display: block;
  }
  h5 {
    color: rgba(0, 0, 0, 0.6);
    font-size: 18px;
  }
  .curriculum-list {
    li {
      display: block;
      margin-bottom: 10px;
      font-family: $raleway-font;
      font-size: 14px;
      font-weight: 400;
      color: rgba(0, 0, 0, 0.5);
      &:last-child {
        margin-bottom: 0;
      }
      i {
        color: #e3d21b;
        margin-right: 5px;
        display: inline-block;
      }
      ul {
        display: block;
        margin-top: 10px;
        padding-left: 25px;
        li {
          margin-bottom: 0;
          @include display-flex(flex);
          @include justify-content-between;
          padding: 10px 0;
          border-bottom: 1px solid $border-color;
          span {
            span {
              text-decoration: underline;
            }
          }
        }
      }
    }
  }
  @media #{$breakpoint-xs} {
    padding: 30px;
  }
}
.about-review {
  padding: 40px;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
  h4 {
    margin-bottom: 20px;
    display: block;
  }
  p {
    font-size: 16px;
    line-height: 1.9;
    &:last-child {
      margin-bottom: 0;
    }
  }
  @media #{$breakpoint-xs} {
    padding: 30px;
  }
}
.clever-ratings {
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
  @media #{$breakpoint-xs} {
    @include flex-wrap(wrap);
  }
  .total-ratings {
    @include flex(0 0 235px);
    min-width: 235px;
    width: 235px;
    border-right: 1px solid $border-color;
    height: 250px;
    @media #{$breakpoint-xs} {
      @include flex(0 0 100%);
      min-width: 100%;
      width: 100%;
      border-right: none;
      border-bottom: 1px solid $border-color;
    }
    h2 {
      font-size: 60px;
      margin-bottom: 5px;
    }
    .ratings-- {
      margin-bottom: 10px;
      i {
        font-size: 18px;
        display: inline-block;
        padding: 0 5px;
        color: #e3d21b;
      }
    }
    span {
      font-size: 12px;
      color: rgba(0, 0, 0, 0.3);
    }
  }
  .rating-viewer {
    padding: 50px 40px 35px;
    @media #{$breakpoint-xs} {
      padding: 40px 30px 25px;
    }
    span {
      color: rgba(0, 0, 0, 0.3);
      font-size: 12px;
      text-transform: uppercase;
      padding-right: 15px;
      @media #{$breakpoint-lg} {
        padding-right: 5px;
        font-size: 11px;
      }
      @media #{$breakpoint-xs} {
        padding-right: 5px;
        font-size: 11px;
      }
    }
    .progress {
      width: 300px;
      margin-right: 15px;
      height: 10px;
      border-radius: 0;
      background-color: #f1f1f1;
      @media #{$breakpoint-lg} {
        width: 200px;
      }
      @media #{$breakpoint-md} {
        width: 140px;
      }
      @media #{$breakpoint-xs} {
        width: 140px;
      }
      .progress-bar {
        background-color: #b3b3b3;
      }
    }
  }
  .single-review {
    padding: 40px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
    @media #{$breakpoint-xs} {
      padding: 30px;
    }
    p {
      margin-bottom: 0;
    }
    .review-admin {
      .thumb {
        @include flex(0 0 40px);
        max-width: 40px;
        width: 40px;
      }
      .text {
        padding-left: 15px;
        h6 {
          font-size: 14px;
          margin-bottom: 0;
        }
        span {
          font-size: 12px;
          color: rgba(0, 0, 0, 0.4);
        }
      }
    }
    .ratings {
      i {
        font-size: 14px;
        display: inline-block;
        padding: 0 3px;
        color: #e3d21b;
      }
    }
  }
}
.about-members {
  padding: 40px;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
  @media #{$breakpoint-xs} {
    padding: 30px;
  }
  h4 {
    margin-bottom: 20px;
    display: block;
  }
  p {
    font-size: 16px;
    line-height: 1.9;
    &:last-child {
      margin-bottom: 0;
    }
  }
}
.all-instructors {
  padding: 40px 40px 10px;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
  @media #{$breakpoint-xs} {
    padding: 30px 30px 0;
  }
  h4 {
    margin-bottom: 25px;
    display: block;
  }
  .single-instructor {
    position: relative;
    z-index: 1;
    background-color: $bg-gray;
    border-radius: 6px;
    .instructor-thumb {
      @include flex(0 0 80px);
      width: 80px;
      max-width: 80px;
      height: 80px;
    }
    .instructor-info {
      padding-left: 25px;
      h5 {
        font-size: 18px;
        margin-bottom: 5px;
        @media #{$breakpoint-xs} {
          font-size: 14px;
        }
      }
      span {
        font-weight: 400;
        color: rgba(0, 0, 0, 0.4);
        font-size: 14px;
      }
    }
  }
}
.sidebar-widget {
  position: relative;
  z-index: 1;
  padding: 35px 30px;
  border: 1px solid $border-color;
  border-bottom: none;
  &:last-child {
    border-bottom: 1px solid $border-color;
  }
  h4 {
    margin-bottom: 20px;
    font-size: 24px;
    display: block;
  }
  .features-list {
    li {
      @include display-flex(flex);
      @include justify-content-between;
      margin-bottom: 5px;
      h6 {
        color: rgba(0, 0, 0, 0.3);
        font-size: 14px;
        @media #{$breakpoint-xs} {
          font-size: 14px;
        }
        i {
          margin-right: 10px;
        }
      }
    }
  }
  .single--courses {
    position: relative;
    z-index: 1;
    margin-bottom: 20px;
    &:last-child {
      margin-bottom: 0;
    }
    .thumb {
      @include flex(0 0 80px);
      width: 80px;
      max-width: 80px;
      height: 50px;
      border-radius: 6px;
      cursor: pointer;
      img {
        border-radius: 6px;
      }
    }
    .content {
      padding-left: 20px;
      h5 {
        font-size: 18px;
        margin-bottom: 5px;
        color: rgba(0, 0, 0, 0.35);
        @media #{$breakpoint-xs} {
          font-size: 14px;
        }
      }
      h6 {
        font-size: 12px;
        color: #e3d21b;
        margin-bottom: 0;
      }
    }
  }
}
.single-course-content {
  .el-tabs__nav {
    margin-bottom: 20px;
  }
  .el-tabs__active-bar {
    height: 0!important;
  }
  .el-tabs__nav-wrap::after {
    height: 0;
  }
  .el-tab-pane {
    margin: 20px;
  }
  .el-tabs__header {
    margin-left: 30px;
  }
}
src/assets/css/subject.scss
New file
@@ -0,0 +1,81 @@
.subject-exam-title{
  font-size: 18px;
  line-height: 25px;
  padding: 18px 20px;
  border-bottom: 1px solid #DEDEDE;
  margin-bottom: 12px;
}
.subject {
  padding-left: 30px;
  padding-right: 75px;
}
.subject-content{
  margin-top: 18px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-weight: 300;
  background: #fff;
  z-index: 1;
  position: relative;
}
/* 题目 */
.subject-title {
  font-size: 18px;
  line-height: 22px;
  .subject-title-number {
    display: inline-block;
    line-height: 22px;
  }
  .subject-title-content {
    // display: inline-block;
  }
}
.subject-options {
  margin: 0;
  padding: 0;
  list-style: none;
  > li {
    position: relative;
    font-size: 24px;
    .toggle {
      opacity: 0;
      text-align: center;
      width: 35px;
      /* auto, since non-WebKit browsers doesn't support input styling */
      height: auto;
      position: absolute;
      top: 0;
      bottom: 0;
      margin: auto 0;
      border: none;
      /* Mobile Safari */
      -webkit-appearance: none;
      appearance: none;
    }
    .toggle+label {
      background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23ededed%22%20stroke-width%3D%223%22/%3E%3C/svg%3E');
      background-repeat: no-repeat;
      background-position: center left;
      background-size: 30px;
    }
    .toggle:checked+label {
      background-size: 30px;
      background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23bddad5%22%20stroke-width%3D%223%22/%3E%3Cpath%20fill%3D%22%235dc2af%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22/%3E%3C/svg%3E');
    }
    label {
      word-break: break-all;
      padding: 10px 10px 10px 45px;
      display: block;
      line-height: 1.0;
      transition: color 0.4s;
    }
    /* 选项名称 */
    .subject-option-prefix {
      font-size: 16px;
      display: inline-block
    }
  }
}
.subject-answer {
  padding: 16px;
}
src/assets/css/transition.scss
New file
@@ -0,0 +1,12 @@
.fade-transform-leave-active,
.fade-transform-enter-active {
  transition: all .5s;
}
.fade-transform-enter {
  opacity: 0;
  transform: translateY(30px);
}
.fade-transform-leave-to {
  opacity: 0;
  transform: translateY(30px);
}
src/components/Subjects/Choices/index.vue
New file
@@ -0,0 +1,89 @@
<template>
    <div>
        <div class="subject-content">
            <div class="subject-title">
                {{ index }}
                <span class="subject-title-content"
                      v-html="subjectInfo.subjectName" />
                <span class="subject-title-content">
                    (&nbsp;单选题&nbsp;<span v-if="subjectInfo.score !== undefined && subjectInfo.score !== 0">&nbsp;{{subjectInfo.score}}分&nbsp;</span>)
                </span>
            </div>
            <ul class="subject-options"
                v-for="option in options"
                :key="option.id">
                <li class="subject-option">
                    <input class="toggle"
                           type="checkbox"
                           :checked="userAnswer === option.optionName"
                           :id="'option' + option.id"
                           @change="toggleOption(option)">
                    <label :for="'option' + option.id">
                        <span class="subject-option-prefix">{{ option.optionName + '.' }}&nbsp;</span>
                        <span v-html="option.optionContent"
                              class="subject-option-prefix" />
                    </label>
                </li>
            </ul>
        </div>
    </div>
</template>
<script>
export default {
    name: 'Choices',
    data () {
        return {
            subjectCount: 0,
            subjectInfo: {
                subjectName: '',
                score: 0
            },
            options: [],
            userAnswer: '',
            index: ''
        }
    },
    methods: {
        getAnswer () {
            return this.userAnswer
        },
        setAnswer (answer) {
            this.userAnswer = answer
        },
        setSubjectInfo (subject, subjectCount, index) {
            this.subjectCount = subjectCount
            this.subjectInfo = subject
            if (subject.hasOwnProperty('examSubjectOptions')) {
                this.options = subject.examSubjectOptions
                console.log(this.options)
            }
            if (subject.hasOwnProperty('answer')) {
                console.log(subject.answer);
                this.setAnswer(subject.answer)
            }
            this.index = index + '.'
            console.log(subject, subjectCount, index, this.options, 5656565656)
        },
        getSubjectInfo () {
            this.subjectInfo.options = this.options
            return this.subjectInfo
        },
        // 选中选项
        toggleOption (option) {
            this.userAnswer = option.optionName
        }
    }
}
</script>
<style lang="scss" scoped>
@import '../../../assets/css/subject.scss';
.subject-options > li label {
    height: 36px;
    line-height: 28px !important;
}
</style>
src/components/Subjects/Judgement/index.vue
New file
@@ -0,0 +1,81 @@
<template>
    <div>
        <div class="subject-content">
            <div class="subject-title">
                {{ index }}
                <span class="subject-title-content"
                      v-html="subjectInfo.subjectName" />
                <span class="subject-title-content">
                    (&nbsp;判断题&nbsp;<span v-if="subjectInfo.score !== undefined && subjectInfo.score !== 0">&nbsp;{{subjectInfo.score}}分&nbsp;</span>)
                </span>
            </div>
            <ul class="subject-options"
                v-for="option in options"
                :key="option.id">
                <li class="subject-option">
                    <input class="toggle"
                           type="checkbox"
                           :checked="userAnswer === option.optionName"
                           :id="'option' + option.id"
                           @change="toggleOption(option)">
                    <label :for="'option' + option.id">
                        <span class="subject-option-prefix">{{ option.optionName }}&nbsp;</span>
                    </label>
                </li>
            </ul>
        </div>
    </div>
</template>
<script>
export default {
    name: 'Judgement',
    data () {
        return {
            subjectCount: 0,
            subjectInfo: {
                subjectName: '',
                score: 0
            },
            options: [
                { id: 1, optionName: '正确' },
                { id: 2, optionName: '错误' }
            ],
            userAnswer: '',
            index: ''
        }
    },
    methods: {
        getAnswer () {
            return this.userAnswer
        },
        setAnswer (answer) {
            this.userAnswer = answer
        },
        setSubjectInfo (subject, subjectCount, index) {
            this.subjectCount = subjectCount
            this.subjectInfo = subject
            if (subject.hasOwnProperty('answer')) {
                this.setAnswer(subject.answer)
            }
            this.index = index + '.'
        },
        getSubjectInfo () {
            this.subjectInfo.options = this.options
            return this.subjectInfo
        },
        // 选中选项
        toggleOption (option) {
            this.userAnswer = option.optionName
        }
    }
}
</script>
<style lang="scss" scoped>
@import '../../../assets/css/subject.scss';
.subject-options > li label {
    height: 36px;
    line-height: 28px !important;
}
</style>
src/components/Subjects/MultipleChoices/index.vue
New file
@@ -0,0 +1,99 @@
<template>
    <div>
        <div class="subject-content">
            <div class="subject-title">
                {{ index }}
                <span class="subject-title-content"
                      v-html="subjectInfo.subjectName" />
                <span class="subject-title-content">
                    (&nbsp;多选题&nbsp;<span v-if="subjectInfo.score !== undefined && subjectInfo.score !== 0">&nbsp;{{subjectInfo.score}}分&nbsp;</span>)
                </span>
            </div>
            <ul class="subject-options"
                v-for="option in options"
                :key="option.id">
                <li class="subject-option">
                    <input class="toggle"
                           type="checkbox"
                           :checked="isChecked(option.optionName)"
                           :id="'option' + option.id"
                           @change="toggleOption($event, option)">
                    <label :for="'option' + option.id">
                        <span class="subject-option-prefix">{{ option.optionName + '.' }}&nbsp;</span>
                        <span v-html="option.optionContent"
                              class="subject-option-prefix" />
                    </label>
                </li>
            </ul>
        </div>
    </div>
</template>
<script>
export default {
    name: 'MultipleChoices',
    data () {
        return {
            subjectCount: 0,
            subjectInfo: {
                subjectName: '',
                score: 0
            },
            options: [],
            userAnswer: [],
            index: ''
        }
    },
    watch: {
    },
    methods: {
        getAnswer () {
            return this.userAnswer.join(',')
        },
        setAnswer (answer) {
            // if (isNotEmpty(answer)) {
            this.userAnswer = answer.split(',')
            // }
        },
        setSubjectInfo (subject, subjectCount, index) {
            this.subjectCount = subjectCount
            this.subjectInfo = subject
            if (subject.hasOwnProperty('examSubjectOptions')) {
                this.options = subject.examSubjectOptions
            }
            if (subject.hasOwnProperty('answer')) {
                this.setAnswer(subject.answer)
            }
            this.index = index + '.'
        },
        getSubjectInfo () {
            this.subjectInfo.options = this.options
            return this.subjectInfo
        },
        // 选中选项
        toggleOption ($event, option) {
            if ($event.target.checked) {
                if (!this.userAnswer.includes(option.optionName)) {
                    this.userAnswer.push(option.optionName)
                }
            } else {
                this.userAnswer.splice(this.userAnswer.findIndex(item => item === option.optionName), 1)
            }
        },
        isChecked (optionName) {
            return this.userAnswer.includes(optionName)
        }
    }
}
</script>
<style lang="scss" scoped>
@import '../../../assets/css/subject.scss';
.subject-options > li label {
    height: 36px;
    line-height: 28px !important;
}
</style>
src/components/Subjects/PracticalOperation/index.vue
New file
@@ -0,0 +1,190 @@
<template>
    <div>
        <div class="subject-content">
            <div class="subject-title">
                {{ index }}
                <span class="subject-title-content"
                      v-html="subjectInfo.subjectName" />
                <span class="subject-title-content">
                    (&nbsp;实操题&nbsp;<span v-if="subjectInfo.score !== undefined && subjectInfo.score !== 0">&nbsp;{{subjectInfo.score}}分&nbsp;</span>)
                </span>
            </div>
            <ul class="subject-options"
                v-for="(option, index) in options"
                :key="option.id">
                <li class="subject-option pbox">
                    <span class="num"
                          @click="selectCheckbox($event, option)"> {{ userAnswer[index].value }} </span>
                    <label :for="'option' + option.id">
                        <span class="subject-option-prefix">{{ option.optionName + '.' }}&nbsp;</span>
                        <span v-html="option.optionContent"
                              class="subject-option-prefix" />
                    </label>
                </li>
            </ul>
        </div>
    </div>
</template>
<script>
export default {
    name: 'MultipleChoices',
    data () {
        return {
            subjectCount: 0,
            subjectInfo: {
                subjectName: '',
                score: 0
            },
            options: [],
            userAnswer: [],
            index: ''
        }
    },
    watch: {
    },
    methods: {
        getAnswer () {
            return this.userAnswer
        },
        setAnswer (answer, option) {
            console.log(answer);
            if (answer != '') {
                this.userAnswer = answer
            } else {
                this.userAnswer = []
                option.forEach(item => {
                    this.userAnswer.push({ key: item.optionName, value: '' })
                })
            }
        },
        setSubjectInfo (subject, subjectCount, index) {
            this.subjectCount = subjectCount
            this.subjectInfo = subject
            if (subject.hasOwnProperty('examSubjectOptions')) {
                this.options = subject.examSubjectOptions
            }
            if (subject.hasOwnProperty('answer')) {
                this.setAnswer(subject.answer, subject.examSubjectOptions)
            }
            this.index = index + '.'
        },
        getSubjectInfo () {
            this.subjectInfo.options = this.options
            return this.subjectInfo
        },
        selectCheckbox ($event, option) {
            var flag = false;
            this.userAnswer.forEach(item => {
                if (item.value != "") {
                    flag = true
                }
            })
            this.userAnswer
            if (flag == true) {
                // 其中最少有一个有值的
                var onlyFlag = false;
                var onlyValue = '';
                var ind = 0;
                this.userAnswer.forEach(item => {
                    if (item.value != '' && item.value > ind) {
                        ind = item.value
                    }
                })
                this.userAnswer.forEach(item => {
                    if (item.key == option.optionName) {
                        if (item.value != '') {
                            onlyValue = item.value
                            onlyFlag = true
                            item.value = ''
                        } else {
                            item.value = ind + 1
                        }
                    }
                })
                this.userAnswer.forEach(item => {
                    if (onlyFlag == true) {
                        if (item.value > onlyValue) {
                            item.value -= 1
                        }
                    }
                })
            } else {
                // 全部都为空
                this.userAnswer.forEach(item => {
                    if (item.key == option.optionName) {
                        item.value = 1
                    }
                })
            }
            console.log(this.userAnswer)
        },
        isChecked (optionName) {
            return this.userAnswer.includes(optionName)
        }
    }
}
</script>
<style lang="scss" scoped>
@import '../../../assets/css/subject.scss';
.pbox .num {
    // margin: 2px;
    // text-align: center;
    // vertical-align: middle;
    // display: inline-block;
    // width: 20px;
    // height: 20px;
    // border: 1px solid #999;
    width: 26px;
    height: 26px;
    position: absolute;
    top: 0;
    bottom: 0;
    margin: auto 0;
    // opacity: 0;
    text-align: center;
    font-size: 18px;
    font-weight: bold;
    border: 1px solid #cfcfcf;
    background-color: #ff9;
    cursor: pointer;
}
.subject-options > li label {
    height: 36px;
    line-height: 28px !important;
}
.pbox.checked {
    border: 1px solid #99f;
    background-color: #ccf;
}
.pbox.checked .num {
    border: 1px solid #ff0;
    background-color: #ff9;
}
</style>
src/components/Subjects/ShortAnswer/index.vue
New file
@@ -0,0 +1,73 @@
<template>
  <div>
    <div class="subject-content">
      <div class="subject-title">
        {{ index }}
        <span class="subject-title-content" v-html="subjectInfo.subjectName"/>
        <span class="subject-title-content" v-if="subjectInfo.score !== undefined && subjectInfo.score !== 0">&nbsp;({{subjectInfo.score}})分</span>
        <div class="subject-tinymce">
          <tinymce ref="editor" :height="height" v-model="userAnswer"/>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import Tinymce from '@/components/Tinymce'
export default {
  name: 'ShortAnswer',
  components: {
    Tinymce
  },
  props: {
    height: {
      type: Number,
      required: false,
      default: 300
    }
  },
  data () {
    return {
      subjectCount: 0,
      subjectInfo: {
        subjectName: '',
        score: 0
      },
      userAnswer: '',
      index: ''
    }
  },
  methods: {
    getAnswer () {
      return this.userAnswer
    },
    setAnswer (answer) {
      this.userAnswer = answer
    },
    setSubjectInfo (subject, subjectCount, index) {
      this.subjectCount = subjectCount
      this.subjectInfo = subject
      if (subject.hasOwnProperty('answer')) {
        this.setAnswer(subject.answer.answer)
      }
      this.index = index + '.'
    },
    getSubjectInfo () {
      return this.subjectInfo
    }
  }
}
</script>
<style lang="scss" scoped>
  @import "../../../assets/css/subject.scss";
  .subject-tinymce {
    margin: 12px;
  }
  .subject-options > li label {
    height: 36px;
    line-height: 28px !important;
}
</style>
src/components/Tinymce/components/editorImage.vue
New file
@@ -0,0 +1,103 @@
<template>
  <div class="upload-container">
    <el-button :style="{background:color,borderColor:color}" icon="el-icon-upload" size="mini" type="primary" @click=" dialogVisible=true">上传图片
    </el-button>
    <el-dialog :visible.sync="dialogVisible">
      <el-upload
        :multiple="true"
        :file-list="fileList"
        :show-file-list="true"
        :on-remove="handleRemove"
        :on-success="handleSuccess"
        :before-upload="beforeUpload"
        class="editor-slide-upload"
        action="https://httpbin.org/post"
        list-type="picture-card">
        <el-button size="small" type="primary">点击上传</el-button>
      </el-upload>
      <el-button @click="dialogVisible = false">取 消</el-button>
      <el-button type="primary" @click="handleSubmit">确 定</el-button>
    </el-dialog>
  </div>
</template>
<script>
// import { getToken } from 'api/qiniu'
export default {
  name: 'EditorSlideUpload',
  props: {
    color: {
      type: String,
      default: '#1890ff'
    }
  },
  data () {
    return {
      dialogVisible: false,
      listObj: {},
      fileList: []
    }
  },
  methods: {
    checkAllSuccess () {
      return Object.keys(this.listObj).every(item => this.listObj[item].hasSuccess)
    },
    handleSubmit () {
      const arr = Object.keys(this.listObj).map(v => this.listObj[v])
      if (!this.checkAllSuccess()) {
        this.$message('请等待所有图片上传成功 或 出现了网络问题,请刷新页面重新上传!')
        return
      }
      this.$emit('successCBK', arr)
      this.listObj = {}
      this.fileList = []
      this.dialogVisible = false
    },
    handleSuccess (response, file) {
      const uid = file.uid
      const objKeyArr = Object.keys(this.listObj)
      for (let i = 0, len = objKeyArr.length; i < len; i++) {
        if (this.listObj[objKeyArr[i]].uid === uid) {
          this.listObj[objKeyArr[i]].url = response.files.file
          this.listObj[objKeyArr[i]].hasSuccess = true
          return
        }
      }
    },
    handleRemove (file) {
      const uid = file.uid
      const objKeyArr = Object.keys(this.listObj)
      for (let i = 0, len = objKeyArr.length; i < len; i++) {
        if (this.listObj[objKeyArr[i]].uid === uid) {
          delete this.listObj[objKeyArr[i]]
          return
        }
      }
    },
    beforeUpload (file) {
      const _self = this
      const _URL = window.URL || window.webkitURL
      const fileName = file.uid
      this.listObj[fileName] = {}
      return new Promise((resolve, reject) => {
        const img = new Image()
        img.src = _URL.createObjectURL(file)
        img.onload = function () {
          _self.listObj[fileName] = { hasSuccess: false, uid: file.uid, width: this.width, height: this.height }
        }
        resolve(true)
      })
    }
  }
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.editor-slide-upload {
  margin-bottom: 20px;
  /deep/ .el-upload--picture-card {
    width: 100%;
  }
}
</style>
src/components/Tinymce/index.vue
New file
@@ -0,0 +1,162 @@
<template>
  <div :class="{fullscreen:fullscreen}" class="tinymce-container editor-container">
    <textarea :id="tinymceId" class="tinymce-textarea"/>
  </div>
</template>
<script>
import editorImage from './components/editorImage'
import plugins from './plugins'
import toolbar from './toolbar'
export default {
  name: 'Tinymce',
  components: { editorImage },
  props: {
    id: {
      type: String,
      default: function () {
        return 'vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
      }
    },
    value: {
      type: String,
      default: ''
    },
    toolbar: {
      type: Array,
      required: false,
      default () {
        return []
      }
    },
    menubar: {
      type: String,
      default: 'file edit insert view format table'
    },
    height: {
      type: Number,
      required: false,
      default: 360
    }
  },
  data () {
    return {
      hasChange: false,
      hasInit: false,
      tinymceId: this.id,
      fullscreen: false,
      languageTypeList: {
        'en': 'en',
        'zh': 'zh_CN'
      }
    }
  },
  computed: {
    language () {
      return this.languageTypeList['zh']
    }
  },
  watch: {
    value (val) {
      if (!this.hasChange && this.hasInit) {
        this.$nextTick(() =>
          window.tinymce.get(this.tinymceId).setContent(val || ''))
      }
    },
    language () {
      this.destroyTinymce()
      this.$nextTick(() => this.initTinymce())
    }
  },
  mounted () {
    this.initTinymce()
  },
  activated () {
    this.initTinymce()
  },
  deactivated () {
    this.destroyTinymce()
  },
  destroyed () {
    this.destroyTinymce()
  },
  methods: {
    initTinymce () {
      const _this = this
      window.tinymce.init({
        language: this.language,
        selector: `#${this.tinymceId}`,
        height: this.height,
        body_class: 'panel-body ',
        object_resizing: false,
        toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
        menubar: this.menubar,
        plugins: plugins,
        end_container_on_empty_block: true,
        powerpaste_word_import: 'clean',
        code_dialog_height: 450,
        code_dialog_width: 1000,
        advlist_bullet_styles: 'square',
        advlist_number_styles: 'default',
        imagetools_cors_hosts: ['www.tinymce.com', 'codepen.io'],
        default_link_target: '_blank',
        link_title: false,
        nonbreaking_force_tab: true, // inserting nonbreaking space &nbsp; need Nonbreaking Space Plugin
        init_instance_callback: editor => {
          if (_this.value) {
            editor.setContent(_this.value)
          }
          _this.hasInit = true
          editor.on('NodeChange Change KeyUp SetContent', () => {
            this.hasChange = true
            this.$emit('input', editor.getContent())
          })
        },
        setup (editor) {
          editor.on('FullscreenStateChanged', (e) => {
            _this.fullscreen = e.state
          })
        }
      })
    },
    destroyTinymce () {
      if (window.tinymce.get(this.tinymceId)) {
        window.tinymce.get(this.tinymceId).destroy()
      }
    },
    setContent (value) {
      window.tinymce.get(this.tinymceId).setContent(value)
    },
    getContent () {
      return window.tinymce.get(this.tinymceId).getContent()
    }
  }
}
</script>
<style scoped>
.tinymce-container {
  position: relative;
}
.tinymce-container>>>.mce-fullscreen {
  z-index: 10000;
}
.tinymce-textarea {
  visibility: hidden;
  z-index: -1;
}
.editor-custom-btn-container {
  position: absolute;
  right: 4px;
  top: 4px;
  /*z-index: 2005;*/
}
.fullscreen .editor-custom-btn-container {
  z-index: 10000;
  position: fixed;
}
.editor-upload-btn {
  display: inline-block;
}
</style>
src/components/Tinymce/plugins.js
New file
@@ -0,0 +1,7 @@
// Any plugins you want to use has to be imported
// Detail plugins list see https://www.tinymce.com/docs/plugins/
// Custom builds see https://www.tinymce.com/download/custom-builds/
const plugins = ['advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools importcss insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount']
export default plugins
src/components/Tinymce/toolbar.js
New file
@@ -0,0 +1,6 @@
// Here is a list of the toolbar
// Detail list see https://www.tinymce.com/docs/advanced/editor-control-identifiers/#toolbarcontrols
const toolbar = ['bold italic underline strikethrough alignleft aligncenter alignright outdent indent  blockquote undo redo removeformat subscript superscript code codesample', 'hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen']
export default toolbar
src/config/env.js
@@ -1,5 +1,5 @@
// 阿里矢量图标库配置
let iconfontVersion = ['567566_pwc3oottzol'];
let iconfontVersion = ['567566_pwc3oottzol', '2680691_r9wggg2tnk'];
let iconfontUrl = `//at.alicdn.com/t/font_$key.css`;
let baseUrl = '';
src/config/iconList.js
@@ -66,6 +66,17 @@
      "iconfont iconicon_add",
      "iconfont icongithub",
      "iconfont icongitee2",
      "iconfont icon-baoming",
      "iconfont icon-tiku",
      "iconfont icon-duoxiaoliankaokaowuguanli",
      "iconfont icon-kaoshi",
      "iconfont icon-shijuan",
      "iconfont icon-chengji",
    ]
  },
  {
src/const/constant.js
New file
@@ -0,0 +1,10 @@
export const nextSubjectType = {
  last: 1,
  next: 0,
  current: 2
}
export const answerType = {
  'true': 'right',
  'false': 'incorrect'
}
src/const/errorCode.js
New file
@@ -0,0 +1,12 @@
export default {
  '478': '验证码错误,请重新输入',
  '479': '验证码已过期,请重新输入',
  '401': '当前操作没有权限',
  '403': '当前操作没有权限',
  '400': '用户名不存在或密码错误',
  '500': '服务器内部错误,请反馈给管理员',
  '4015': '服务不可用',
  '4020': '验证码错误',
  '4026': '验证码已过期,请重新获取',
  'default': '系统未知错误,请反馈给管理员'
}
src/views/applyexam/index.vue
New file
@@ -0,0 +1,461 @@
/*
 * @Author: Morpheus
 * @Date: 2021-07-05 16:31:54
 * @Last Modified by: Morpheus
 * @Last Modified time: 2021-07-19 19:39:45
 * menu-name 报名考试
 */
<template>
    <el-row class="morpheus-box">
        <el-col :span="24">
            <el-card>
                <div class="exam-card-body">
                    <avue-crud v-model="obj"
                               class="company-box"
                               :option="questionBankOption"
                               :search.sync="questionBankSearch"
                               :table-loading="questionBankLoading"
                               :data="questionBankData"
                               ref="questionBankCrud"
                               :page.sync="questionBankPage"
                               @on-load="questionBankOnLoad"
                               @selection-change="questionBankSelectionChange"
                               @search-change="questionBankSearchChange"
                               @search-reset="questionBankSearchReset"
                               @current-change="questionBankCurrentChange"
                               @size-change="questionBankSizeChange"
                               @row-save="questionBankRowSave"
                               @row-del="questionBankRowDel">
                        <!-- 自定义按钮 -->
                        <!-- <template slot="menuLeft">
                            <el-button type="danger"
                                       size="mini"
                                       icon="el-icon-delete"
                                       plain
                                       @click="handleDelete">新增
                            </el-button>
                            <el-button type="danger"
                                       size="mini"
                                       icon="el-icon-delete"
                                       plain
                                       @click="handleDelete">删除
                            </el-button>
                            <el-button type="danger"
                                       size="mini"
                                       icon="el-icon-delete"
                                       plain
                                       @click="handleDelete">导出
                            </el-button>
                        </template> -->
                        <template slot="menuLeft">
                            <el-button type="danger"
                                       size="small"
                                       icon="el-icon-delete"
                                       @click="questionBankHandleDelete">删 除
                            </el-button>
                        </template>
                    </avue-crud>
                </div>
            </el-card>
        </el-col>
    </el-row>
</template>
<script>
import {
    getApplyList,
    addApply,
    remove
} from "@/api/examapi/applyexam";
import { mapState } from 'vuex'
export default {
    data () {
        return {
            obj: {
                name: '张三',
            },
            questionBankOption: {
                // 操作栏多余按钮去除
                delBtn: true,
                editBtn: false,
                addBtn: true,
                selection: true,
                menu: true,
                // 导出按钮
                excelBtn: true,
                viewBtn: false,
                // title: '题库',
                align: 'center',
                height: 'auto',
                calcHeight: 80,
                tip: false,
                searchShow: true,
                searchMenuSpan: 4,
                index: true,
                indexLabel: '序号',
                //dialogType: 'drawer',
                dialogClickModal: false,
                // 操作栏宽度
                menuWidth: 286,
                column: [
                    {
                        label: "保安姓名",
                        prop: "name",
                        type: 'tree',
                        dicUrl: '',
                        search: true,
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: true,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        props: {
                            label: "title",
                            value: "id",
                        },
                        rules: [{
                            required: true,
                            message: "请选择保安姓名",
                            trigger: "blur"
                        }]
                    },
                    {
                        label: "试卷名称",
                        prop: "examName",
                        type: 'tree',
                        dicUrl: '/api/exampaper/page-tree',
                        // search: true,
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: true,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        props: {
                            label: "examName",
                            value: "id",
                        },
                        rules: [{
                            required: true,
                            message: "请选择试卷名称",
                            trigger: "blur"
                        }],
                        width: 220
                    },
                    {
                        label: "所属公司",
                        prop: "deptName",
                        search: true,
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: false,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: true,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        rules: [{
                            required: true,
                            message: "请选择所属公司",
                            trigger: "blur"
                        }],
                        width: 220
                    },
                    {
                        label: "准考证号",
                        prop: "candidateNo",
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: false,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: false,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        rules: [{
                            required: true,
                            message: "请选择准考证号",
                            trigger: "blur"
                        }]
                    },
                    {
                        label: "试卷分数",
                        prop: "paperScore",
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: false,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: true,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false
                    },
                    {
                        label: "报名时间",
                        prop: "applyTime",
                        type: "datetime",
                        // span: 24,
                        format: 'yyyy-MM-dd HH:mm:ss',
                        valueFormat: 'yyyy-MM-dd HH:mm:ss',
                        // 表单新增时是否禁止
                        addDisabled: true,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: true,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        value: (new Date().getFullYear() + '-' + (new Date().getMonth() + 1 < 10
                            ? "0" + (new Date().getMonth() + 1)
                            : new Date().getMonth() + 1) + '-' + (new Date().getDate() < 10
                                ? "0" + new Date().getDate()
                                : new Date().getDate()) + ' ' + (new Date().getHours() < 10
                                    ? "0" + new Date().getHours()
                                    : new Date().getHours()) + ':' + (new Date().getMinutes() < 10
                                        ? "0" + new Date().getMinutes()
                                        : new Date().getMinutes()) + ':' + (new Date().getSeconds() < 10
                                            ? "0" + new Date().getSeconds()
                                            : new Date().getSeconds())),
                        width: 250
                    },
                    {
                        label: "考试时间",
                        prop: "examTime",
                        type: "datetime",
                        // span: 24,
                        format: 'yyyy-MM-dd HH:mm:ss',
                        valueFormat: 'yyyy-MM-dd HH:mm:ss',
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: false,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: false,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        width: 250
                    }
                ]
            },
            questionBankSearch: {},
            questionBankLoading: true,
            questionBankData: [
            ],
            questionBankPage: {
                pageSize: 10,
                currentPage: 1,
                total: 16
            },
            questionBankQuery: {},
            questionBankSelectionList: [],
        }
    },
    watch: {
        "form.examname": {
            // form是表单或者表格绑定的数据集,v-model='form'
            handler (val) {
                if (val) {
                    //地址截取,从县/区开始截取,并且取从县区第一个出现的位置开始
                    var address = val.formattedAddress.toString();
                    if (address.search("县") != -1) {
                        this.form.address = address.substring(
                            address.indexOf("县") + 1,
                            address.length
                        );
                    }
                    if (address.search("区") != -1) {
                        this.form.address = address.substring(
                            address.indexOf("区") + 1,
                            address.length
                        );
                    }
                }
            },
            immediate: true,
        },
    },
    created () {
      console.log(this.userInfo)
      if (this.userInfo.role_name.indexOf('ksxtadmin') != -1) {
        this.questionBankOption.column[0].dicUrl = "/api/blade-system/dept/lazy-tree-user?parentId="
      } else {
        this.questionBankOption.column[0].dicUrl = "/api/blade-system/dept/lazy-tree-user?parentId=" + this.userInfo.dept_id
      }
    },
    mounted () {
    },
    computed: {
        ...mapState({
            userInfo: state => state.user.userInfo
        }),
        ids () {
            let ids = [];
            this.questionBankSelectionList.forEach(ele => {
                ids.push(ele.id);
            });
            return ids.join(",");
        },
    },
    methods: {
        questionBankOnLoad (page, params = {}) {
            this.questionBankLoading = false;
            getApplyList(page.currentPage, page.pageSize, Object.assign(params, this.questionBankQuery)).then(res => {
                const data = res.data.data;
                this.questionBankPage.total = data.total;
                this.questionBankData = data.records;
                this.questionBankLoading = false;
                this.questionBankSelectionClear();
            });
        },
        questionBankSelectionClear () {
            this.questionBankSelectionList = [];
            this.$refs.questionBankCrud.toggleSelection();
        },
        questionBankSelectionChange (list) {
            this.questionBankSelectionList = list;
        },
        questionBankSearchChange (params, done) {
            this.questionBankQuery = params;
            this.questionBankPage.currentPage = 1;
            this.questionBankOnLoad(this.questionBankPage, params);
            done();
        },
        questionBankSearchReset () {
            this.questionBankQuery = {};
            this.questionBankOnLoad(this.questionBankPage);
        },
        questionBankCurrentChange (currentPage) {
            this.questionBankPage.currentPage = currentPage;
        },
        questionBankSizeChange (pageSize) {
            this.questionBankPage.pageSize = pageSize;
        },
        // 新增
        questionBankRowSave (row, done, loading) {
            addApply({ userId: row.name, examId: row.examName, applyTime: row.applyTime }).then(() => {
                this.questionBankOnLoad(this.questionBankPage);
                this.$message({
                    type: "success",
                    message: "操作成功!"
                });
                done();
            }, error => {
                window.console.log(error);
                loading();
            });
        },
        questionBankRowDel (row) {
            this.$confirm("确定将选择数据删除?", {
                confirmButtonText: "确定",
                cancelButtonText: "取消",
                type: "warning"
            })
                .then(() => {
                    return remove(row.id);
                })
                .then(() => {
                    this.questionBankOnLoad(this.questionBankPage);
                    this.$message({
                        type: "success",
                        message: "操作成功!"
                    });
                });
        },
        questionBankHandleDelete () {
            if (this.questionBankSelectionList.length === 0) {
                this.$message.warning("请选择至少一条数据");
                return;
            }
            this.$confirm("确定将选择数据删除?", {
                confirmButtonText: "确定",
                cancelButtonText: "取消",
                type: "warning"
            })
                .then(() => {
                    return remove(this.ids);
                })
                .then(() => {
                    this.questionBankOnLoad(this.questionBankPage);
                    this.$message({
                        type: "success",
                        message: "操作成功!"
                    });
                    this.$refs.questionBankCrud.toggleSelection();
                });
        },
    }
}
</script>
<style lang="scss" scoped>
</style>
src/views/exam/examSubjects.vue
New file
@@ -0,0 +1,328 @@
/*
 * @Author: Morpheus
 * @Date: 2021-07-05 16:31:54
 * @Last Modified by: Morpheus
 * @Last Modified time: 2021-07-18 15:47:06
 * menu-name 题目管理
 */
<template>
    <el-row class="morpheus-box">
        <el-col :span="24">
            <el-card>
                <div class="exam-card-body">
                    <avue-crud v-model="obj"
                               class="company-box"
                               :option="questionBankOption"
                               :search.sync="questionBankSearch"
                               :table-loading="questionBankLoading"
                               :data="questionBankData"
                               ref="questionBankCrud"
                               :page.sync="questionBankPage"
                               @on-load="questionBankOnLoad"
                               @selection-change="questionBankSelectionChange"
                               @search-change="questionBankSearchChange"
                               @search-reset="questionBankSearchReset"
                               @current-change="questionBankCurrentChange"
                               @size-change="questionBankSizeChange"
                               @row-save="questionBankRowSave"
                               @row-update="questionBankRowUpdate"
                               @row-del="questionBankRowDel">
                        <!-- 自定义按钮 -->
                        <!-- <template slot="menuLeft">
                            <el-button type="danger"
                                       size="mini"
                                       icon="el-icon-delete"
                                       plain
                                       @click="handleDelete">新增
                            </el-button>
                            <el-button type="danger"
                                       size="mini"
                                       icon="el-icon-delete"
                                       plain
                                       @click="handleDelete">删除
                            </el-button>
                            <el-button type="danger"
                                       size="mini"
                                       icon="el-icon-delete"
                                       plain
                                       @click="handleDelete">导出
                            </el-button>
                        </template> -->
                        <template slot-scope="{row}"
                                  slot="examstate">
                            <el-tag>{{row.examstate == 0 ? '已发布' : '草稿'}}</el-tag>
                        </template>
                        <!-- <template slot="menu">
                            <el-button type="text"
                                       size="mini"
                                       icon="el-icon-delete"
                                       @click="questionBankHandleDel">删除
                            </el-button>
                        </template> -->
                    </avue-crud>
                </div>
            </el-card>
        </el-col>
    </el-row>
</template>
<script>
import {
    getPaperList,
    updatePaper,
    remove
} from "@/api/examapi/examSubjects";
export default {
    data () {
        var validatePass = (rule, value, callback) => {
            console.log(value)
            if (value == undefined || value == '') {
                callback(new Error('请输入分数'));
                return;
            } else if (value !== '' && isNaN(value) == true) {
                callback(new Error('请输入数字'));
            } else if (value <= 0) {
                callback(new Error('分数设置请大于0'));
            } else {
                callback();
            }
        };
        return {
            obj: {
                name: '张三',
            },
            questionBankOption: {
                // 操作栏多余按钮去除
                delBtn: true,
                editBtn: true,
                addBtn: false,
                selection: false,
                // 导出按钮
                excelBtn: false,
                viewBtn: false,
                align: 'center',
                height: 'auto',
                calcHeight: 80,
                tip: false,
                searchShow: true,
                searchMenuSpan: 4,
                index: true,
                  indexLabel: '序号',
                //dialogType: 'drawer',
                dialogClickModal: false,
                // 操作栏宽度
                menu: true,
                menuWidth: 180,
                column: [
                    {
                        label: "题目名称",
                        prop: "subjectName",
                        span: 24,
                        search: true,
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: true,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        row: true,
                        rules: [{
                            required: true,
                            message: "请输入考试名称",
                            trigger: "blur"
                        }]
                    },
                    {
                        label: "题目类型",
                        prop: "choicesType",
                        type: "select",
                        search: true,
                        searchSpan: 4,
                        searchLabelWidth: 80,
                        value: 0,
                        dicData: [{
                            label: '单选题',
                            value: 0
                        }, {
                            label: '多选题',
                            value: 1,
                        }, {
                            label: '判断题',
                            value: 2,
                        }],
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: true,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        width: 106
                    },
                    {
                        label: "分值",
                        prop: "score",
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: false,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        rules: [{ validator: validatePass, required: true, trigger: 'blur' }],
                        width: 106
                    }
                ]
            },
            questionBankSearch: {},
            questionBankLoading: true,
            questionBankData: [],
            questionBankPage: {
                pageSize: 10,
                currentPage: 1,
                total: 16
            },
            questionBankQuery: {},
            questionBankSelectionList: [],
        }
    },
    created () {
    },
    mounted () {
    },
    methods: {
        questionBankOnLoad (page, params = {}) {
            this.questionBankLoading = false;
            this.questionBankQuery.id = this.$route.query.id;
            getPaperList(page.currentPage, page.pageSize, Object.assign(params, this.questionBankQuery)).then(res => {
                const data = res.data.data;
                this.questionBankPage.total = data.total;
                this.questionBankData = data.records;
                this.questionBankLoading = false;
                this.questionBankSelectionClear();
            });
        },
        questionBankSelectionClear () {
            this.questionBankSelectionList = [];
            this.$refs.questionBankCrud.toggleSelection();
        },
        questionBankSelectionChange (list) {
            this.questionBankSelectionList = list;
        },
        questionBankSearchChange (params, done) {
            this.questionBankQuery = params;
            this.questionBankPage.currentPage = 1;
            this.questionBankOnLoad(this.questionBankPage, params);
            done();
        },
        questionBankSearchReset () {
            this.questionBankQuery = {};
            this.questionBankOnLoad(this.questionBankPage);
        },
        questionBankCurrentChange (currentPage) {
            this.questionBankPage.currentPage = currentPage;
        },
        questionBankSizeChange (pageSize) {
            this.questionBankPage.pageSize = pageSize;
        },
        questionBankRowDel (row) {
            this.$confirm("确定将选择数据删除?", {
                confirmButtonText: "确定",
                cancelButtonText: "取消",
                type: "warning"
            })
                .then(() => {
                    return remove({ paperid: this.$route.query.id, subjectid: row.id });
                })
                .then(() => {
                    this.questionBankOnLoad(this.questionBankPage);
                    this.$message({
                        type: "success",
                        message: "操作成功!"
                    });
                });
        },
        questionBankRowSave (row, done, loading) {
            console.log(row, 898989);
            add(row).then(() => {
                this.initFlag = false;
                this.onLoad(this.page);
                this.$message({
                    type: "success",
                    message: "操作成功!"
                });
                done();
            }, error => {
                window.console.log(error);
                loading();
            });
        },
        questionBankRowUpdate (row, index, done, loading) {
            updatePaper({ value: row.score, id: row.id }).then(() => {
                this.questionBankOnLoad(this.questionBankPage);
                this.$message({
                    type: "success",
                    message: "操作成功!"
                });
                done();
            }, error => {
                window.console.log(error);
                loading();
            });
        },
    }
}
</script>
<style lang="scss" scoped>
</style>
src/views/exam/examination.vue
New file
@@ -0,0 +1,478 @@
/*
 * @Author: Morpheus
 * @Date: 2021-07-05 16:31:54
 * @Last Modified by: Morpheus
 * @Last Modified time: 2021-07-18 17:11:18
 * menu-name 试卷管理
 */
<template>
    <el-row class="morpheus-box">
        <el-col :span="24">
            <el-card>
                <div class="exam-card-body">
                    <avue-crud v-model="form"
                               class="company-box"
                               :option="questionBankOption"
                               :search.sync="questionBankSearch"
                               :table-loading="questionBankLoading"
                               :data="questionBankData"
                               ref="questionBankCrud"
                               :page.sync="questionBankPage"
                               @on-load="questionBankOnLoad"
                               @selection-change="questionBankSelectionChange"
                               @search-change="questionBankSearchChange"
                               @search-reset="questionBankSearchReset"
                               @current-change="questionBankCurrentChange"
                               @size-change="questionBankSizeChange"
                               @row-save="questionBankRowSave"
                               @row-update="questionBankRowUpdate"
                               @row-del="questionBankRowDel">
                        <!-- 自定义按钮 -->
                        <!-- <template slot="menuLeft">
                            <el-button type="danger"
                                       size="mini"
                                       icon="el-icon-delete"
                                       plain
                                       @click="handleDelete">新增
                            </el-button>
                            <el-button type="danger"
                                       size="mini"
                                       icon="el-icon-delete"
                                       plain
                                       @click="handleDelete">删除
                            </el-button>
                            <el-button type="danger"
                                       size="mini"
                                       icon="el-icon-delete"
                                       plain
                                       @click="handleDelete">导出
                            </el-button>
                        </template> -->
                        <template slot="menuLeft">
                            <el-button type="danger"
                                       size="small"
                                       icon="el-icon-delete"
                                       @click="questionBankHandleDelete">删 除
                            </el-button>
                        </template>
                        <template slot-scope="{row}"
                                  slot="examStatus">
                            <el-tag>{{row.examStatus == 0 ? '已发布' : '草稿'}}</el-tag>
                        </template>
                        <template slot-scope="{row}"
                                  slot="menu">
                            <el-button type="text"
                                       size="mini"
                                       icon="el-icon-document"
                                       @click="subjectManagement(row)">题目管理
                            </el-button>
                        </template>
                    </avue-crud>
                </div>
            </el-card>
        </el-col>
    </el-row>
</template>
<script>
import {
    getList,
    add,
    remove,
    update
} from "@/api/examapi/examination";
export default {
    data () {
        var validatePass = (rule, value, callback) => {
            console.log(value)
            if (value == undefined || value == '') {
                callback(new Error('请输入分数'));
                return;
            } else if (value !== '' && isNaN(value) == true) {
                callback(new Error('请输入数字'));
            } else if (value <= 0) {
                callback(new Error('分数设置请大于0'));
            } else {
                callback();
            }
        };
        return {
            form: {},
            questionBankOption: {
                // 操作栏多余按钮去除
                delBtn: true,
                editBtn: true,
                addBtn: true,
                selection: true,
                menu: true,
                // 导出按钮
                excelBtn: false,
                viewBtn: true,
                // title: '题库',
                align: 'center',
                height: 'auto',
                calcHeight: 80,
                tip: false,
                searchShow: true,
                searchMenuSpan: 4,
                index: true,
                indexLabel: '序号',
                //dialogType: 'drawer',
                dialogClickModal: false,
                // 操作栏宽度
                menuWidth: 284,
                labelWidth: 140,
                column: [
                    {
                        label: "试卷名称",
                        prop: "examName",
                        search: true,
                        searchSpan: 4,
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: true,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        rules: [{
                            required: true,
                            message: "请输入试卷名称",
                            trigger: "blur"
                        }]
                    },
                    {
                        label: "试卷分数",
                        prop: "totalScore",
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: false,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        rules: [{ validator: validatePass, required: true, trigger: 'blur' }],
                        width: 100
                    },
                    {
                        label: "考试时间",
                        prop: "examTime",
                        type: "daterange",
                        // span: 24,
                        format: 'yyyy-MM-dd HH:mm:ss',
                        valueFormat: 'yyyy-MM-dd HH:mm:ss',
                        startPlaceholder: '考试开始时间',
                        endPlaceholder: '考试结束时间',
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: false,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        // display: false,
                        hide: true,
                        rules: [{
                            required: true,
                            message: "请选择考试时间",
                            trigger: "blur"
                        }],
                        width: 250
                    },
                    {
                        label: "考试开始时间",
                        prop: "startTime",
                        type: "datetime",
                        // span: 24,
                        format: 'yyyy-MM-dd HH:mm:ss',
                        valueFormat: 'yyyy-MM-dd HH:mm:ss',
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: false,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: false,
                        // 表单编辑时是否可见
                        editDisplay: false,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        width: 180
                    },
                    {
                        label: "考试结束时间",
                        prop: "endTime",
                        type: "datetime",
                        // span: 24,
                        format: 'yyyy-MM-dd HH:mm:ss',
                        valueFormat: 'yyyy-MM-dd HH:mm:ss',
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: false,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: false,
                        // 表单编辑时是否可见
                        editDisplay: false,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        width: 180
                    },
                    {
                        label: "创建人",
                        prop: "creator",
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: true,
                        // 表单新增时是否可见
                        addDisplay: false,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: true,
                        // 表单编辑时是否可见
                        editDisplay: false,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        hide: true,
                        display: false,
                    },
                    {
                        label: "备注",
                        prop: "remark",
                        span: 24,
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: false,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false
                    },
                    {
                        label: "注意事项",
                        prop: "examAttention",
                        type: "textarea",
                        span: 24,
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: false,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        width: 240
                    },
                ]
            },
            questionBankSearch: {},
            questionBankLoading: true,
            questionBankData: [
            ],
            questionBankPage: {
                pageSize: 10,
                currentPage: 1,
                total: 16
            },
            questionBankQuery: {},
            questionBankSelectionList: [],
        }
    },
    created () {
    },
    mounted () {
    },
    computed: {
        ids () {
            let ids = [];
            this.questionBankSelectionList.forEach(ele => {
                ids.push(ele.id);
            });
            return ids.join(",");
        },
    },
    watch: {
    },
    methods: {
        questionBankOnLoad (page, params = {}) {
            this.questionBankLoading = false;
            getList(page.currentPage, page.pageSize, Object.assign(params, this.questionBankQuery)).then(res => {
                const data = res.data.data;
                this.questionBankPage.total = data.total;
                this.questionBankData = data.records;
                this.questionBankLoading = false;
                this.questionBankSelectionClear();
            });
        },
        questionBankSelectionClear () {
            this.questionBankSelectionList = [];
            this.$refs.questionBankCrud.toggleSelection();
        },
        questionBankSelectionChange (list) {
            this.questionBankSelectionList = list;
        },
        questionBankSearchChange (params, done) {
            this.questionBankQuery = params;
            this.questionBankPage.currentPage = 1;
            this.questionBankOnLoad(this.questionBankPage, params);
            done();
        },
        questionBankSearchReset () {
            this.questionBankQuery = {};
            this.questionBankOnLoad(this.questionBankPage);
        },
        questionBankCurrentChange (currentPage) {
            this.questionBankPage.currentPage = currentPage;
        },
        questionBankSizeChange (pageSize) {
            this.questionBankPage.pageSize = pageSize;
        },
        // 新增
        questionBankRowSave (row, done, loading) {
            row.startTime = row.examTime[0]
            row.endTime = row.examTime[1]
            row.examTime = JSON.stringify(row.examTime)
            add(row).then(() => {
                this.questionBankOnLoad(this.questionBankPage);
                this.$message({
                    type: "success",
                    message: "操作成功!"
                });
                done();
            }, error => {
                window.console.log(error);
                loading();
            });
        },
        questionBankRowUpdate (row, index, done, loading) {
            if (Array.isArray(row.examTime) != true) {
                row.examTime = row.examTime.split(",")
            }
            row.startTime = row.examTime[0]
            row.endTime = row.examTime[1]
            row.examTime = JSON.stringify(row.examTime)
            update(row).then(() => {
                this.questionBankOnLoad(this.questionBankPage);
                this.$message({
                    type: "success",
                    message: "操作成功!"
                });
                done();
            }, error => {
                window.console.log(error);
                loading();
            });
        },
        questionBankRowDel (row) {
            this.$confirm("确定将选择数据删除?", {
                confirmButtonText: "确定",
                cancelButtonText: "取消",
                type: "warning"
            })
                .then(() => {
                    return remove(row.id);
                })
                .then(() => {
                    this.questionBankOnLoad(this.questionBankPage);
                    this.$message({
                        type: "success",
                        message: "操作成功!"
                    });
                });
        },
        questionBankHandleDelete () {
            if (this.questionBankSelectionList.length === 0) {
                this.$message.warning("请选择至少一条数据");
                return;
            }
            this.$confirm("确定将选择数据删除?", {
                confirmButtonText: "确定",
                cancelButtonText: "取消",
                type: "warning"
            })
                .then(() => {
                    return remove(this.ids);
                })
                .then(() => {
                    this.questionBankOnLoad(this.questionBankPage);
                    this.$message({
                        type: "success",
                        message: "操作成功!"
                    });
                    this.$refs.questionBankCrud.toggleSelection();
                });
        },
        subjectManagement (row) {
            this.$router.push({
                path: `/exam/subjects/${row.id}`,
                query: row
            })
        }
    }
}
</script>
<style lang="scss" scoped>
</style>
src/views/exam/performance.vue
New file
@@ -0,0 +1,398 @@
/*
 * @Author: Morpheus
 * @Date: 2021-07-05 16:31:54
 * @Last Modified by: Morpheus
 * @Last Modified time: 2021-07-18 19:44:47
 * menu-name 成绩管理
 */
<template>
    <el-row class="morpheus-box">
        <el-col :span="24">
            <el-card>
                <div class="exam-card-body">
                    <avue-crud v-model="obj"
                               class="company-box"
                               :option="questionBankOption"
                               :search.sync="questionBankSearch"
                               :table-loading="questionBankLoading"
                               :data="questionBankData"
                               ref="questionBankCrud"
                               :page.sync="questionBankPage"
                               @on-load="questionBankOnLoad"
                               @selection-change="questionBankSelectionChange"
                               @search-change="questionBankSearchChange"
                               @search-reset="questionBankSearchReset"
                               @current-change="questionBankCurrentChange"
                               @size-change="questionBankSizeChange"
                               @row-update="questionBankRowUpdate">
                        <template slot-scope="{ row }"
                                  slot="learnGrade">
                            {{ row.learnGrade == -1 ? "暂未录入" : row.learnGrade }}
                        </template>
                        <!-- 自定义按钮 -->
                        <!-- <template slot="menuLeft">
                            <el-button type="danger"
                                       size="mini"
                                       icon="el-icon-delete"
                                       plain
                                       @click="handleDelete">新增
                            </el-button>
                            <el-button type="danger"
                                       size="mini"
                                       icon="el-icon-delete"
                                       plain
                                       @click="handleDelete">删除
                            </el-button>
                            <el-button type="danger"
                                       size="mini"
                                       icon="el-icon-delete"
                                       plain
                                       @click="handleDelete">导出
                            </el-button>
                        </template> -->
                    </avue-crud>
                </div>
            </el-card>
        </el-col>
    </el-row>
</template>
<script>
import {
    getList,
    update
} from "@/api/examapi/performance";
export default {
    data () {
        var validatePass = (rule, value, callback) => {
            console.log(value)
            if (value == undefined || value == '') {
                callback(new Error('请输入实操成绩'));
                return;
            } else if (value !== '' && isNaN(value) == true) {
                callback(new Error('请输入数字'));
            } else if (value <= 0) {
                callback(new Error('分数设置请大于0'));
            } else if (value > 100) {
                callback(new Error('分数设置请小于100'));
            } else {
                callback();
            }
        };
        return {
            obj: {
                name: '张三',
            },
            questionBankOption: {
                // 操作栏多余按钮去除
                delBtn: false,
                editBtn: true,
                addBtn: false,
                selection: false,
                // 导出按钮
                excelBtn: true,
                excelBtnText: '成绩导出',
                viewBtn: true,
                title: '成绩',
                align: 'center',
                height: 'auto',
                calcHeight: 80,
                tip: false,
                searchShow: true,
                searchMenuSpan: 4,
                index: true,
                indexLabel: '序号',
                //dialogType: 'drawer',
                dialogClickModal: false,
                // 操作栏宽度
                menu: true,
                menuWidth: 136,
                labelWidth: 120,
                column: [
                    {
                        label: "试卷名称",
                        prop: "examName",
                        search: true,
                        searchSpan: 4,
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: true,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        rules: [{
                            required: true,
                            message: "请输入试卷名称",
                            trigger: "blur"
                        }]
                    },
                    {
                        label: "保安姓名",
                        prop: "securityName",
                        search: true,
                        searchSpan: 4,
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: true,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        rules: [{
                            required: true,
                            message: "请输入保安姓名",
                            trigger: "blur"
                        }]
                    },
                    {
                        label: "所属公司",
                        prop: "company",
                        search: true,
                        searchSpan: 4,
                        dicUrl: '/api/blade-system/dept/tree',
                        props: {
                            label: "title",
                            value: "id",
                        },
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: true,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        rules: [{
                            required: true,
                            message: "请输入所属公司",
                            trigger: "blur"
                        }]
                    },
                    {
                        label: "考试时间",
                        prop: "examTime",
                        type: "datetime",
                        // span: 24,
                        format: 'yyyy-MM-dd HH:mm:ss',
                        valueFormat: 'yyyy-MM-dd HH:mm:ss',
                        width: 250,
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: true,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                    },
                    {
                        label: "理论成绩",
                        prop: "theoryGrade",
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: true,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                    },
                    {
                        label: "实操成绩",
                        prop: "learnGrade",
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: false,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        rules: [{ validator: validatePass, required: true, trigger: 'blur' }],
                    },
                    {
                        label: "总成绩",
                        prop: "allGrade",
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: true,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        rules: [{
                            required: true,
                            message: "请输入考试名称",
                            trigger: "blur"
                        }]
                    },
                    {
                        label: "是否合格",
                        prop: "qualified",
                        type: 'select',
                        slot: true,
                        search: true,
                        searchSpan: 4,
                        dicData: [{
                            label: '合格',
                            value: 0
                        }, {
                            label: '不合格',
                            value: 1,
                        }, {
                            label: '暂未录实操成绩',
                            value: 2,
                        }],
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: true,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        rules: [{
                            required: true,
                            message: "请输入考试名称",
                            trigger: "blur"
                        }]
                    },
                ]
            },
            questionBankSearch: {},
            questionBankLoading: true,
            questionBankData: [
            ],
            questionBankPage: {
                pageSize: 10,
                currentPage: 1,
                total: 16
            },
            questionBankQuery: {},
            questionBankSelectionList: [],
        }
    },
    created () {
    },
    mounted () {
    },
    methods: {
        questionBankOnLoad (page, params = {}) {
            this.questionBankLoading = false;
            getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
                const data = res.data.data;
                this.questionBankPage.total = data.total;
                this.questionBankData = data.records;
                this.questionBankLoading = false;
                this.questionBankSelectionClear();
            });
        },
        questionBankSelectionClear () {
            this.questionBankSelectionList = [];
            this.$refs.questionBankCrud.toggleSelection();
        },
        questionBankSelectionChange (list) {
            this.questionBankSelectionList = list;
        },
        questionBankSearchChange (params, done) {
            this.questionBankQuery = params;
            this.questionBankPage.currentPage = 1;
            this.questionBankOnLoad(this.questionBankPage, params);
            done();
        },
        questionBankSearchReset () {
            this.questionBankQuery = {};
            this.questionBankOnLoad(this.questionBankPage);
        },
        questionBankCurrentChange (currentPage) {
            this.questionBankPage.currentPage = currentPage;
        },
        questionBankSizeChange (pageSize) {
            this.questionBankPage.pageSize = pageSize;
        },
        questionBankRowUpdate (row, index, done, loading) {
            update({ theoryGrade: row.theoryGrade, learnGrade: row.learnGrade, id: row.id }).then(() => {
                this.questionBankOnLoad(this.questionBankPage);
                this.$message({
                    type: "success",
                    message: "操作成功!"
                });
                done();
            }, error => {
                window.console.log(error);
                loading();
            });
        },
    }
}
</script>
<style lang="scss" scoped>
</style>
src/views/exam/startexam.vue
New file
@@ -0,0 +1,388 @@
/*
 * @Author: Morpheus
 * @Date: 2021-07-05 16:31:54
 * @Last Modified by: Morpheus
 * @Last Modified time: 2021-07-18 17:09:52
 * menu-name 考试管理
 */
<template>
    <el-row class="morpheus-box">
        <el-col :span="24">
            <el-card>
                <div class="exam-card-body">
                    <avue-crud v-model="form"
                               class="company-box"
                               :option="questionBankOption"
                               :search.sync="questionBankSearch"
                               :table-loading="questionBankLoading"
                               :data="questionBankData"
                               ref="questionBankCrud"
                               :page.sync="questionBankPage"
                               @on-load="questionBankOnLoad"
                               @selection-change="questionBankSelectionChange"
                               @search-change="questionBankSearchChange"
                               @search-reset="questionBankSearchReset"
                               @current-change="questionBankCurrentChange"
                               @size-change="questionBankSizeChange">
                        <!-- 自定义按钮 -->
                        <!-- <template slot="menuLeft">
                            <el-button type="danger"
                                       size="mini"
                                       icon="el-icon-delete"
                                       plain
                                       @click="handleDelete">新增
                            </el-button>
                            <el-button type="danger"
                                       size="mini"
                                       icon="el-icon-delete"
                                       plain
                                       @click="handleDelete">删除
                            </el-button>
                            <el-button type="danger"
                                       size="mini"
                                       icon="el-icon-delete"
                                       plain
                                       @click="handleDelete">导出
                            </el-button>
                        </template> -->
                        <template slot-scope="{row}"
                                  slot="examStatus">
                            <el-tag>{{row.examStatus == 0 ? '已发布' : '草稿'}}</el-tag>
                        </template>
                        <template slot-scope="{row}"
                                  slot="menu">
                            <el-button type="text"
                                       size="mini"
                                       icon="icon-kaoshi"
                                       class="start-kaoshi"
                                       @click="startExam(row)">开始考试
                            </el-button>
                        </template>
                    </avue-crud>
                </div>
            </el-card>
        </el-col>
    </el-row>
</template>
<script>
import {
    getList,
} from "@/api/examapi/examination";
export default {
    data () {
        var validatePass = (rule, value, callback) => {
            console.log(value)
            if (value == undefined || value == '') {
                callback(new Error('请输入分数'));
                return;
            } else if (value !== '' && isNaN(value) == true) {
                callback(new Error('请输入数字'));
            } else if (value <= 0) {
                callback(new Error('分数设置请大于0'));
            } else {
                callback();
            }
        };
        return {
            form: {},
            questionBankOption: {
                // 操作栏多余按钮去除
                delBtn: false,
                editBtn: false,
                addBtn: false,
                selection: false,
                menu: true,
                // 导出按钮
                excelBtn: false,
                viewBtn: true,
                // title: '题库',
                align: 'center',
                height: 'auto',
                calcHeight: 80,
                tip: false,
                searchShow: true,
                searchMenuSpan: 4,
                index: true,
                indexLabel: '序号',
                //dialogType: 'drawer',
                dialogClickModal: false,
                // 操作栏宽度
                menuWidth: 246,
                labelWidth: 140,
                column: [
                    {
                        label: "试卷名称",
                        prop: "examName",
                        search: true,
                        searchSpan: 4,
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: true,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        rules: [{
                            required: true,
                            message: "请输入试卷名称",
                            trigger: "blur"
                        }]
                    },
                    {
                        label: "试卷分数",
                        prop: "totalScore",
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: false,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        rules: [{ validator: validatePass, required: true, trigger: 'blur' }],
                        width: 100
                    },
                    {
                        label: "考试时间",
                        prop: "examTime",
                        type: "daterange",
                        // span: 24,
                        format: 'yyyy-MM-dd HH:mm:ss',
                        valueFormat: 'yyyy-MM-dd HH:mm:ss',
                        startPlaceholder: '考试开始时间',
                        endPlaceholder: '考试结束时间',
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: false,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        // display: false,
                        hide: true,
                        rules: [{
                            required: true,
                            message: "请选择考试时间",
                            trigger: "blur"
                        }],
                        width: 250
                    },
                    {
                        label: "考试开始时间",
                        prop: "startTime",
                        type: "datetime",
                        // span: 24,
                        format: 'yyyy-MM-dd HH:mm:ss',
                        valueFormat: 'yyyy-MM-dd HH:mm:ss',
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: false,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: false,
                        // 表单编辑时是否可见
                        editDisplay: false,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        width: 180
                    },
                    {
                        label: "考试结束时间",
                        prop: "endTime",
                        type: "datetime",
                        // span: 24,
                        format: 'yyyy-MM-dd HH:mm:ss',
                        valueFormat: 'yyyy-MM-dd HH:mm:ss',
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: false,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: false,
                        // 表单编辑时是否可见
                        editDisplay: false,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        width: 180
                    },
                    {
                        label: "创建人",
                        prop: "creator",
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: true,
                        // 表单新增时是否可见
                        addDisplay: false,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: true,
                        // 表单编辑时是否可见
                        editDisplay: false,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        hide: true,
                        display: false,
                    },
                    {
                        label: "备注",
                        prop: "remark",
                        span: 24,
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: false,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false
                    },
                    {
                        label: "注意事项",
                        prop: "examAttention",
                        type: "textarea",
                        span: 24,
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: false,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        width: 240
                    },
                ]
            },
            questionBankSearch: {},
            questionBankLoading: true,
            questionBankData: [
            ],
            questionBankPage: {
                pageSize: 10,
                currentPage: 1,
                total: 16
            },
            questionBankQuery: {},
            questionBankSelectionList: [],
        }
    },
    created () {
    },
    mounted () {
    },
    computed: {
        ids () {
            let ids = [];
            this.questionBankSelectionList.forEach(ele => {
                ids.push(ele.id);
            });
            return ids.join(",");
        },
    },
    watch: {
    },
    methods: {
        questionBankOnLoad (page, params = {}) {
            this.questionBankLoading = false;
            getList(page.currentPage, page.pageSize, Object.assign(params, this.questionBankQuery)).then(res => {
                const data = res.data.data;
                this.questionBankPage.total = data.total;
                this.questionBankData = data.records;
                this.questionBankLoading = false;
                this.questionBankSelectionClear();
            });
        },
        questionBankSelectionClear () {
            this.questionBankSelectionList = [];
            this.$refs.questionBankCrud.toggleSelection();
        },
        questionBankSelectionChange (list) {
            this.questionBankSelectionList = list;
        },
        questionBankSearchChange (params, done) {
            this.questionBankQuery = params;
            this.questionBankPage.currentPage = 1;
            this.questionBankOnLoad(this.questionBankPage, params);
            done();
        },
        questionBankSearchReset () {
            this.questionBankQuery = {};
            this.questionBankOnLoad(this.questionBankPage);
        },
        questionBankCurrentChange (currentPage) {
            this.questionBankPage.currentPage = currentPage;
        },
        questionBankSizeChange (pageSize) {
            this.questionBankPage.pageSize = pageSize;
        },
        startExam (row) {
            this.$router.push({
                path: `/startexam/${row.id}`,
                query: row
            })
        }
    }
}
</script>
<style lang="scss" scoped>
</style>
src/views/exam/subject.vue
New file
@@ -0,0 +1,263 @@
/*
 * @Author: Morpheus
 * @Date: 2021-07-05 16:31:54
 * @Last Modified by: Morpheus
 * @Last Modified time: 2021-07-18 16:04:26
 * menu-name 题库查询
 */
<template>
    <el-row class="morpheus-box">
        <el-col :span="24">
            <el-card>
                <div class="exam-card-body">
                    <avue-crud class="company-box"
                               :option="questionBankOption"
                               :search.sync="questionBankSearch"
                               :table-loading="questionBankLoading"
                               :data="questionBankData"
                               ref="questionBankCrud"
                               :page.sync="questionBankPage"
                               @on-load="questionBankOnLoad"
                               @selection-change="questionBankSelectionChange"
                               @search-change="questionBankSearchChange"
                               @search-reset="questionBankSearchReset"
                               @current-change="questionBankCurrentChange"
                               @size-change="questionBankSizeChange"
                               @row-del="questionBankHandleDel">
                        <template slot="menuLeft">
                            <el-button type="danger"
                                       size="small"
                                       icon="el-icon-delete"
                                       @click="questionBankHandleDelete">删 除
                            </el-button>
                        </template>
                    </avue-crud>
                </div>
            </el-card>
        </el-col>
    </el-row>
</template>
<script>
import {
    getList,
    remove,
} from "@/api/examapi/subject";
export default {
    data () {
        return {
            questionBankOption: {
                // 操作栏多余按钮去除
                delBtn: true,
                editBtn: false,
                addBtn: false,
                selection: true,
                menu: true,
                // 导出按钮
                excelBtn: true,
                excelBtnText: '题库导出',
                title: '题库',
                align: 'center',
                height: 'auto',
                calcHeight: 80,
                tip: false,
                searchShow: true,
                searchMenuSpan: 4,
                index: true,
                indexLabel: '序号',
                viewBtn: true,
                //dialogType: 'drawer',
                dialogClickModal: false,
                // 操作栏宽度
                menuWidth: 226,
                column: [
                    {
                        label: "题目名称",
                        prop: "subjectName",
                        search: true,
                        slot: true,
                    },
                    {
                        label: "题目类型",
                        prop: "choicesType",
                        search: true,
                        type: "select",
                        dicData: [{
                            label: '单选题',
                            value: 0
                        }, {
                            label: '多选题',
                            value: 1,
                        }, {
                            label: '判断题',
                            value: 2,
                        }],
                        slot: true,
                        width: 96,
                    },
                    {
                        label: "题目分值",
                        prop: "score",
                        slot: true,
                        width: 96,
                    },
                    {
                        label: "参考答案",
                        prop: "answer",
                        slot: true,
                        width: 96,
                    },
                    {
                        label: "创建人",
                        prop: "creator",
                        slot: true,
                        width: 96,
                    },
                    {
                        label: "创建时间",
                        prop: "createDate",
                        slot: true,
                        width: 130,
                    },
                    {
                        label: "修改人",
                        prop: "modifier",
                        slot: true,
                        width: 96,
                    },
                    {
                        label: "修改时间",
                        prop: "modifyDate",
                        slot: true,
                        width: 130,
                    }
                ]
            },
            questionBankSearch: {},
            questionBankLoading: true,
            questionBankData: [
            ],
            questionBankPage: {
                pageSize: 10,
                currentPage: 1,
                total: 16
            },
            questionBankQuery: {},
            questionBankSelectionList: [],
        }
    },
    created () {
    },
    mounted () {
    },
     computed: {
        ids () {
            let ids = [];
            this.questionBankSelectionList.forEach(ele => {
                ids.push(ele.id);
            });
            return ids.join(",");
        },
    },
    methods: {
        questionBankOnLoad (page, params = {}) {
            this.questionBankLoading = false;
            getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
                const data = res.data.data;
                this.questionBankPage.total = data.total;
                this.questionBankData = data.records;
                this.questionBankLoading = false;
                this.questionBankSelectionClear();
            });
        },
        questionBankSelectionClear () {
            this.questionBankSelectionList = [];
            this.$refs.questionBankCrud.toggleSelection();
        },
        questionBankSelectionChange (list) {
            this.questionBankSelectionList = list;
        },
        questionBankSearchChange (params, done) {
            this.questionBankQuery = params;
            this.questionBankPage.currentPage = 1;
            this.questionBankOnLoad(this.questionBankPage, params);
            done();
        },
        questionBankSearchReset () {
            this.questionBankQuery = {};
            this.questionBankOnLoad(this.questionBankPage);
        },
        questionBankCurrentChange (currentPage) {
            this.questionBankPage.currentPage = currentPage;
        },
        questionBankSizeChange (pageSize) {
            this.questionBankPage.pageSize = pageSize;
        },
        questionBankHandleDel (row) {
            this.$confirm("确定将选择数据删除?", {
                confirmButtonText: "确定",
                cancelButtonText: "取消",
                type: "warning"
            })
                .then(() => {
                    return remove(row.id);
                })
                .then(() => {
                    this.questionBankOnLoad(this.questionBankPage);
                    this.$message({
                        type: "success",
                        message: "操作成功!"
                    });
                });
        },
        questionBankHandleDelete () {
            if (this.questionBankSelectionList.length === 0) {
                this.$message.warning("请选择至少一条数据");
                return;
            }
            this.$confirm("确定将选择数据删除?", {
                confirmButtonText: "确定",
                cancelButtonText: "取消",
                type: "warning"
            })
                .then(() => {
                    return remove(this.ids);
                })
                .then(() => {
                    this.questionBankOnLoad(this.questionBankPage);
                    this.$message({
                        type: "success",
                        message: "操作成功!"
                    });
                    this.$refs.questionBankCrud.toggleSelection();
                });
        },
    }
}
</script>
<style lang="scss" scoped>
</style>
src/views/exam/topicDetails.vue
New file
@@ -0,0 +1,211 @@
/*
 * @Author: Morpheus
 * @Date: 2021-07-13 11:19:28
 * @Last Modified by: Morpheus
 * @Last Modified time: 2021-07-15 16:40:40
 */
<template>
    <div class="app-container">
        <el-tabs v-model="activeName"
                 @tab-click="handleClick">
            <el-tab-pane label="单选题"
                         name="first">
                <div>
                    <el-row>
                        <el-col :span="12">
                        </el-col>
                    </el-row>
                </div>
                <avue-form v-model="form"
                           :option="option">
                    <template slot-scope="scope"
                              slot="text">
                        <div>
                            <el-input v-model="form.text"
                                      placeholder="这里是自定的表单"></el-input>
                        </div>
                    </template>
                    <template slot-scope="scope"
                              slot="rate">
                        <div>
                            <avue-rate v-model="form.rate"></avue-rate>
                        </div>
                    </template>
                    <template slot="provinceType"
                              slot-scope="{item,value,label}">
                        <span>{{ item }}</span>
                    </template>
                </avue-form>
            </el-tab-pane>
            <el-tab-pane label="多选题"
                         name="second">多选题</el-tab-pane>
            <el-tab-pane label="判断题"
                         name="third">判断题</el-tab-pane>
        </el-tabs>
    </div>
</template>
<script>
export default {
    data () {
        return {
            activeName: 'first',
            rateObj: {
                state: '一般',
                value: 4
            },
            tempSubject: {
            },
            dialogStatus: '',
            dialogStatusType: {
            },
            subjectsType:
                '',
            form: {
                text: '',
                rate: 4
            },
            option: {
                labelWidth: 120,
                column: [
                    {
                        label: '分值',
                        prop: 'text',
                        formslot: true,
                        labelslot: true,
                        errorslot: true,
                        rules: [{
                            required: true,
                            message: "请输入姓名",
                            trigger: "blur"
                        }]
                    },
                    {
                        label: '难度',
                        prop: 'rate',
                        formslot: true,
                        labelslot: true,
                    },
                    {
                        label: "参考答案",
                        prop: "sex",
                        span: 6,
                        type: "radio",
                        dicData: [{
                            label: 'A',
                            value: 0
                        }, {
                            label: 'B',
                            value: 1
                        }, {
                            label: 'C',
                            value: 2
                        }, {
                            label: 'D',
                            value: 3
                        }],
                        errorslot: true,
                        rules: [{
                            required: true,
                            message: "请选择答案",
                            trigger: "blur"
                        }],
                        mock: {
                            type: 'dic'
                        }
                    },
                    {
                        type: 'ueditor',
                        component: 'AvueUeditor',
                        label: '题目名称',
                        span: 24,
                        display: true,
                        action: '',
                        oss: '',
                        props: {},
                        ali: {},
                        qiniu: {},
                        prop: 'titleName',
                        rules: [{
                            required: true,
                            message: "请输入题目名称",
                            trigger: "blur"
                        }],
                    },
                    {
                        label: '',
                        labelWidth: 40,
                        prop: 'divider',
                        component: 'elDivider',//ele分割线
                        span: 24,
                        event: {
                            click: () => {
                                this.$message.success('点击方法')
                            },
                        },
                        params: {
                            html: '<h2 style="font-size: 16px; font-weight: normal"> 选项列表 </h2>',
                            contentPosition: "center",
                        }
                    },
                    {
                        label: "题目名称",
                        prop: "content",
                        component: 'AvueUeditor',
                        options: {
                            action: '/api/blade-resource/oss/endpoint/put-file',
                            props: {
                                res: "data",
                                url: "link",
                            }
                        },
                        hide: true,
                        minRows: 6,
                        span: 24,
                        rules: [{
                            required: true,
                            message: "请输入题目名称",
                            trigger: "blur"
                        }],
                    }
                ]
            }
        }
    },
    methods: {
        handleTabChange () { },
        handleSelectSubject () { },
        dialogSubjectFormVisible () { },
        createSubjectData () { },
        updateSubjectData () { },
        updateAndAddSubjectData () { },
        handleClick (tab, event) {
            console.log(tab, event);
        }
    }
}
</script>
<style lang="scss" scoped>
.dialog-footer {
    margin-top: 20px;
}
</style>
src/views/singleperformance/index.vue
New file
@@ -0,0 +1,398 @@
/*
 * @Author: Morpheus
 * @Date: 2021-07-05 16:31:54
 * @Last Modified by: Morpheus
 * @Last Modified time: 2021-07-18 21:02:10
 * menu-name 成绩管理
 */
<template>
    <el-row class="morpheus-box">
        <el-col :span="24">
            <el-card>
                <div class="exam-card-body">
                    <avue-crud v-model="obj"
                               class="company-box"
                               :option="questionBankOption"
                               :search.sync="questionBankSearch"
                               :table-loading="questionBankLoading"
                               :data="questionBankData"
                               ref="questionBankCrud"
                               :page.sync="questionBankPage"
                               @on-load="questionBankOnLoad"
                               @selection-change="questionBankSelectionChange"
                               @search-change="questionBankSearchChange"
                               @search-reset="questionBankSearchReset"
                               @current-change="questionBankCurrentChange"
                               @size-change="questionBankSizeChange"
                               @row-update="questionBankRowUpdate">
                        <template slot-scope="{ row }"
                                  slot="learnGrade">
                            {{ row.learnGrade == -1 ? "暂未录入" : row.learnGrade }}
                        </template>
                        <!-- 自定义按钮 -->
                        <!-- <template slot="menuLeft">
                            <el-button type="danger"
                                       size="mini"
                                       icon="el-icon-delete"
                                       plain
                                       @click="handleDelete">新增
                            </el-button>
                            <el-button type="danger"
                                       size="mini"
                                       icon="el-icon-delete"
                                       plain
                                       @click="handleDelete">删除
                            </el-button>
                            <el-button type="danger"
                                       size="mini"
                                       icon="el-icon-delete"
                                       plain
                                       @click="handleDelete">导出
                            </el-button>
                        </template> -->
                    </avue-crud>
                </div>
            </el-card>
        </el-col>
    </el-row>
</template>
<script>
import {
    getList,
    update
} from "@/api/examapi/performance";
export default {
    data () {
        var validatePass = (rule, value, callback) => {
            console.log(value)
            if (value == undefined || value == '') {
                callback(new Error('请输入实操成绩'));
                return;
            } else if (value !== '' && isNaN(value) == true) {
                callback(new Error('请输入数字'));
            } else if (value <= 0) {
                callback(new Error('分数设置请大于0'));
            } else if (value > 100) {
                callback(new Error('分数设置请小于100'));
            } else {
                callback();
            }
        };
        return {
            obj: {
                name: '张三',
            },
            questionBankOption: {
                // 操作栏多余按钮去除
                delBtn: false,
                editBtn: true,
                addBtn: false,
                selection: false,
                // 导出按钮
                excelBtn: true,
                excelBtnText: '成绩导出',
                viewBtn: true,
                title: '成绩',
                align: 'center',
                height: 'auto',
                calcHeight: 80,
                tip: false,
                searchShow: true,
                searchMenuSpan: 4,
                index: true,
                indexLabel: '序号',
                //dialogType: 'drawer',
                dialogClickModal: false,
                // 操作栏宽度
                menu: false,
                menuWidth: 136,
                labelWidth: 120,
                column: [
                    {
                        label: "试卷名称",
                        prop: "examName",
                        search: true,
                        searchSpan: 4,
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: true,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        rules: [{
                            required: true,
                            message: "请输入试卷名称",
                            trigger: "blur"
                        }]
                    },
                    {
                        label: "保安姓名",
                        prop: "securityName",
                        search: true,
                        searchSpan: 4,
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: true,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        rules: [{
                            required: true,
                            message: "请输入保安姓名",
                            trigger: "blur"
                        }]
                    },
                    {
                        label: "所属公司",
                        prop: "company",
                        search: true,
                        searchSpan: 4,
                        dicUrl: '/api/blade-system/dept/tree',
                        props: {
                            label: "title",
                            value: "id",
                        },
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: true,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        rules: [{
                            required: true,
                            message: "请输入所属公司",
                            trigger: "blur"
                        }]
                    },
                    {
                        label: "考试时间",
                        prop: "examTime",
                        type: "datetime",
                        // span: 24,
                        format: 'yyyy-MM-dd HH:mm:ss',
                        valueFormat: 'yyyy-MM-dd HH:mm:ss',
                        width: 250,
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: true,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                    },
                    {
                        label: "理论成绩",
                        prop: "theoryGrade",
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: true,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                    },
                    {
                        label: "实操成绩",
                        prop: "learnGrade",
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: false,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        rules: [{ validator: validatePass, required: true, trigger: 'blur' }],
                    },
                    {
                        label: "总成绩",
                        prop: "allGrade",
                        slot: true,
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: true,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        rules: [{
                            required: true,
                            message: "请输入考试名称",
                            trigger: "blur"
                        }]
                    },
                    {
                        label: "是否合格",
                        prop: "qualified",
                        type: 'select',
                        slot: true,
                        search: true,
                        searchSpan: 4,
                        dicData: [{
                            label: '合格',
                            value: 0
                        }, {
                            label: '不合格',
                            value: 1,
                        }, {
                            label: '暂未录实操成绩',
                            value: 2,
                        }],
                        // 表单新增时是否禁止
                        addDisabled: false,
                        // 表单新增时是否可见
                        addDisplay: true,
                        // 表单新增时是否为查看模式
                        addDetail: false,
                        // 表单编辑时是否禁止
                        editDisabled: true,
                        // 表单编辑时是否可见
                        editDisplay: true,
                        // 表单编辑时是否为查看模式
                        editDetail: false,
                        rules: [{
                            required: true,
                            message: "请输入考试名称",
                            trigger: "blur"
                        }]
                    },
                ]
            },
            questionBankSearch: {},
            questionBankLoading: true,
            questionBankData: [
            ],
            questionBankPage: {
                pageSize: 10,
                currentPage: 1,
                total: 16
            },
            questionBankQuery: {},
            questionBankSelectionList: [],
        }
    },
    created () {
    },
    mounted () {
    },
    methods: {
        questionBankOnLoad (page, params = {}) {
            this.questionBankLoading = false;
            getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
                const data = res.data.data;
                this.questionBankPage.total = data.total;
                this.questionBankData = data.records;
                this.questionBankLoading = false;
                this.questionBankSelectionClear();
            });
        },
        questionBankSelectionClear () {
            this.questionBankSelectionList = [];
            this.$refs.questionBankCrud.toggleSelection();
        },
        questionBankSelectionChange (list) {
            this.questionBankSelectionList = list;
        },
        questionBankSearchChange (params, done) {
            this.questionBankQuery = params;
            this.questionBankPage.currentPage = 1;
            this.questionBankOnLoad(this.questionBankPage, params);
            done();
        },
        questionBankSearchReset () {
            this.questionBankQuery = {};
            this.questionBankOnLoad(this.questionBankPage);
        },
        questionBankCurrentChange (currentPage) {
            this.questionBankPage.currentPage = currentPage;
        },
        questionBankSizeChange (pageSize) {
            this.questionBankPage.pageSize = pageSize;
        },
        questionBankRowUpdate (row, index, done, loading) {
            update({ theoryGrade: row.theoryGrade, learnGrade: row.learnGrade, id: row.id }).then(() => {
                this.questionBankOnLoad(this.questionBankPage);
                this.$message({
                    type: "success",
                    message: "操作成功!"
                });
                done();
            }, error => {
                window.console.log(error);
                loading();
            });
        },
    }
}
</script>
<style lang="scss" scoped>
</style>
src/views/startexam/index.vue
New file
@@ -0,0 +1,663 @@
<template>
    <el-row class="morpheus-box">
        <el-col :span="24">
            <el-card>
                <div class="exam-card-body">
                    <div class="subject-box">
                        <el-row :gutter="30">
                            <el-col :span="5">
                                <div class="tool-bar">
                                    <div class="time-remain">
                                        剩余时间:
                                        <div class="time">
                                            <count-down v-on:start_callback="countDownS_cb(1)"
                                                        v-on:end_callback="countDownE_cb(1)"
                                                        :current-time="currentTime"
                                                        :start-time="startTime"
                                                        :end-time="endTime"
                                                        :tip-text="'距离考试开始'"
                                                        :tip-text-end="'距离考试结束'"
                                                        :end-text="'考试结束'"
                                                        :hourTxt="':'"
                                                        :minutesTxt="':'"
                                                        :secondsTxt="''">
                                            </count-down>
                                        </div>
                                    </div>
                                    <div class="current-progress">
                                        当前进度: {{subjectIndex}}/{{subjectIds.length}}
                                    </div>
                                    <div class="answer-card">
                                        <el-button type="text"
                                                   icon="el-icon-date"
                                                   @click="answerCard">答题卡</el-button>
                                    </div>
                                    <el-button type="success"
                                               icon="el-icon-date"
                                               @click="submitExam"
                                               v-bind:disabled="disableSubmit">提交</el-button>
                                </div>
                            </el-col>
                            <el-col :span="18">
                                <div class="subject-box-card">
                                    <div class="subject-exam-title">{{exam.examinationName}}(共{{subjectIds.length}}题,合计{{exam.totalScore}}分)</div>
                                    <!-- 题目内容 -->
                                    <choices ref="choices"
                                             v-show="this.query.type === 0" />
                                    <multiple-choices ref="multipleChoices"
                                                      v-show="this.query.type === 1" />
                                    <judgement ref="judgement"
                                               v-show="this.query.type === 2" />
                                    <practical-operation ref="practicalOperation"
                                                         v-show="this.query.type === 3" />
                                    <short-answer ref="shortAnswer"
                                                  v-show="this.query.type === 4" />
                                    <div class="subject-buttons"
                                         v-if="query.subjectId !== ''">
                                        <el-button plain
                                                   @click="last"
                                                   :loading="loadingLast">上一题</el-button>
                                        <el-button plain
                                                   @click="next"
                                                   :loading="loadingNext">下一题</el-button>
                                        <el-button type="success"
                                                   @click="submitExam"
                                                   v-bind:disabled="disableSubmit">提交</el-button>
                                    </div>
                                </div>
                            </el-col>
                        </el-row>
                        <el-dialog title="答题卡"
                                   :visible.sync="dialogVisible"
                                   width="50%"
                                   top="10vh"
                                   :modal='false'
                                   center>
                            <div class="answer-card-title">{{exam.examinationName}}(共{{subjectIds.length}}题,合计{{exam.totalScore}}分)</div>
                            <div class="answer-card-split"></div>
                            <el-row class="answer-card-content">
                                <el-button :class="{ 'answered': subjectIds[index].answered }"
                                           circle
                                           v-for="(value, index) in subjectIds"
                                           :key="index"
                                           @click="toSubject(value.everyID, value.type, index)">&nbsp;{{index + 1}}&nbsp;</el-button>
                            </el-row>
                        </el-dialog>
                    </div>
                </div>
            </el-card>
        </el-col>
    </el-row>
</template>
<script>
import { mapState } from 'vuex'
import CountDown from 'vue2-countdown'
import { saveAndNext } from '@/api/exam/answer'
import { getSubjectIds } from '@/api/exam/exam'
import { getCurrentTime } from '@/api/exam/examRecord'
import { getSubjectAnswer } from '@/api/exam/subject'
import moment from 'moment'
import { messageSuccess, messageFail, messageWarn, isNotEmpty } from '@/util/util'
import Tinymce from '@/components/Tinymce'
import Choices from '@/components/Subjects/Choices'
import MultipleChoices from '@/components/Subjects/MultipleChoices'
import PracticalOperation from '@/components/Subjects/PracticalOperation'
// import ShortAnswer from '@/components/Subjects/ShortAnswer'
import Judgement from '@/components/Subjects/Judgement'
import { nextSubjectType } from '@/const/constant'
export default {
    components: {
        CountDown,
        Tinymce,
        Choices,
        MultipleChoices,
        PracticalOperation,
        Judgement,
        // ShortAnswer,
    },
    data () {
        return {
            loadingLast: false,
            loadingNext: false,
            currentTime: 0,
            startTime: 0,
            endTime: 0,
            disableSubmit: true,
            subjectIndex: 1,
            query: {
                examinationId: undefined,
                examRecordId: undefined,
                subjectId: undefined,
                userId: undefined,
                type: 0
            },
            subject: {},
            answer: '',
            dialogVisible: false,
            subjectIds: [],
            subjectStartTime: undefined,
            exam: {
                id: '590969316204220416',
                creator: 'admin',
                createDate: 1560939664000,
                modifier: 'preview',
                modifyDate: 1609835214000,
                delFlag: 0,
                examinationName: '',
                startTime: null,
                endTime: null,
                totalScore: 50,
                status: 0,
                remark: '全国计算机统考练习题10道',
                newRecord: false
            },
            firstFlag: true
        }
    },
    computed: {
        ...mapState({
            userInfo: state => state.user.userInfo
        })
    },
    created () {
        const examInfo = this.$route.params.id
        if (isNotEmpty(examInfo)) {
            // 试卷ID
            this.query.examinationId = this.$route.params.id
            // 考场ID
            this.query.examRecordId = this.userInfo.user_id
            this.query.userId = this.userInfo.user_id
            this.exam.id = this.userInfo.user_id + '' + this.$route.params.id
            this.exam.examinationName = this.$route.query.examName
            this.exam.startTime = this.$route.query.startTime
            this.exam.endTime = this.$route.query.endTime
            this.exam.totalScore = this.$route.query.totalScore
            this.exam.status = this.$route.query.examStatus
            this.exam.remark = this.$route.query.remark
            this.validateExamTime()
        }
    },
    methods: {
        countDownS_cb: function () {
            messageSuccess(this, '考试开始')
        },
        validateExamTime () {
            getCurrentTime().then(response => {
                const currentTime = moment(response.data.data)
                if (currentTime.isAfter(this.exam.endTime)) {
                    messageWarn(this, '考试已结束')
                } else if (currentTime.isBefore(this.exam.startTime)) {
                    messageWarn(this, '考试未开始')
                } else {
                    this.startExam()
                    const current = currentTime.valueOf()
                    this.currentTime = current
                    this.startTime = current
                    this.subjectStartTime = current
                    this.endTime = moment(this.exam.endTime).valueOf()
                    this.disableSubmit = false
                }
            }).catch(() => {
                messageFail(this, '开始考试失败!15')
            })
        },
        startExam () {
            // 获取题目ID列表
            getSubjectIds({ id: this.query.examinationId }).then(subjectResponse => {
                const subjectData = subjectResponse.data.data.examExaminationSubjects
                if (subjectData.length > 0) {
                    for (let i = 0; i < subjectData.length; i++) {
                        const { examSubjectChoices } = subjectData[i]
                        this.subjectIds.push({
                            subjectId: subjectResponse.data.data.id,
                            everyID: examSubjectChoices.id,
                            type: examSubjectChoices.choicesType,
                            index: i + 1,
                            answered: false,
                            answer: examSubjectChoices.answer,
                            score: examSubjectChoices.score
                        })
                    }
                    this.query.type = parseInt(this.subjectIds[0].type)
                    // 准考证号
                    this.query.subjectId = this.subjectIds[0].everyID
                    this.updateSubjectIndex()
                    // 获取当前题目信息
                    getSubjectAnswer({
                        id: this.subjectIds[0].everyID,
                    }).then(response => {
                        if (isNotEmpty(response.data.data)) {
                            this.setSubjectInfo(response.data.data)
                        }
                    }).catch(() => {
                        messageFail(this, '获取题目失败!')
                    })
                }
            }).catch(() => {
                messageFail(this, '开始考试失败!4646549888*8*')
            })
        },
        countDownE_cb: function () {
            messageWarn(this, '考试结束')
            this.disableSubmit = true
        },
        last () {
            for (let i = 0; i < this.subjectIds.length; i++) {
                if (this.subjectIds[i].everyID == this.query.subjectId) {
                    this.subjectIds[i].answer = this.getAnswer()
                    this.markAnswered(this.subjectIds[i].answer, i)
                    if (i === 0) {
                        messageSuccess(this, '已经是第一题了')
                        break
                    }
                    let { everyID, type, index } = this.subjectIds[--i]
                    this.subjectIndex = index
                    this.saveCurrentSubjectAndGetNextSubject(nextSubjectType.last, everyID, type)
                    break
                }
            }
        },
        next () {
            for (let i = 0; i < this.subjectIds.length; i++) {
                if (this.subjectIds[i].everyID == this.query.subjectId) {
                    this.subjectIds[i].answer = this.getAnswer()
                    this.markAnswered(this.subjectIds[i].answer, i)
                    if (i === this.subjectIds.length - 1) {
                        messageSuccess(this, '已经是最后一题了')
                        break
                    }
                    let { everyID, index } = this.subjectIds[++i]
                    this.subjectIndex = index
                    this.saveCurrentSubjectAndGetNextSubject(nextSubjectType.next, everyID)
                    break
                }
            }
        },
        // 保存当前题目,同时根据序号加载下一题
        saveCurrentSubjectAndGetNextSubject (nextType, nextSubjectId) {
            this.startLoading(nextType)
            getSubjectAnswer({ id: nextSubjectId }).then(response => {
                if (response.data.data !== null) {
                    // 保存成功后更新答题卡状态
                    const subject = response.data.data
                    const { id, choicesType } = subject
                    this.query.subjectId = id
                    this.query.type = choicesType
                    for (let i = 0; i < this.subjectIds.length; i++) {
                        if (this.subjectIds[i].everyID == nextSubjectId) {
                            subject.answer = this.subjectIds[i].answer
                            break
                        }
                    }
                    this.setSubjectInfo(subject)
                    // store.dispatch('SetSubjectInfo', subject).then(() => { })
                }
                // 更新时间
                getCurrentTime().then(response => {
                    this.subjectStartTime = moment(response.data.data)
                })
                this.endLoading(nextType)
            }).catch((error) => {
                console.log(error)
                messageFail(this, '获取题目失败')
                this.endLoading(nextType)
            })
        },
        markAnswered (answer, index) {
            if (answer && answer !== null) {
                this.subjectIds[index].answered = true
            }
        },
        // 答题卡
        answerCard () {
            this.dialogVisible = true
        },
        // 跳转题目
        toSubject (everyID, type, index) {
            var ind = this.subjectIndex;
            if (this.firstFlag == false) {
                ind = this.subjectIndex;
            } else {
                ind = this.subjectIndex - 1;
            }
            this.subjectIds[ind].answer = this.getAnswer()
            this.markAnswered(this.subjectIds[ind].answer, ind)
            this.subjectIndex = index + 1
            this.firstFlag = true;
            // 保存当前题目,同时加载下一题
            this.saveCurrentSubjectAndGetNextSubject(nextSubjectType.next, everyID, type)
            this.dialogVisible = false
        },
        // 提交
        submitExam () {
            var ind = this.subjectIndex;
            if (this.firstFlag == false) {
                ind = this.subjectIndex;
            } else {
                ind = this.subjectIndex - 1;
            }
            this.subjectIds[ind].answer = this.getAnswer()
            this.markAnswered(this.subjectIds[ind].answer, ind)
            this.$confirm('确定要提交吗?', '提示', {
                confirmButtonText: '确定',
                cancelButtonText: '取消',
                type: 'warning'
            }).then(() => {
                this.disableSubmit = true
                this.doSubmitExam()
            }).catch(() => {
            })
        },
        doSubmitExam () {
            var obj = {
                examName: this.$route.query.examName,
                securityName: this.userInfo.user_name,
                securityId: this.userInfo.user_id,
                allScore: this.$route.query.totalScore,
                company: this.userInfo.dept_id,
                examTime: this.$route.query.startTime,
                papersId: this.$route.query.id,
                examEndTime: this.$route.query.endTime,
                examResultVOS: null
            }
            var arr = []
            this.subjectIds.forEach((item) => {
                if (item.type == 3) {
                    var str = ''
                    if (item.answer.length > 0) {
                        item.answer.forEach(it => {
                            if (it.value != '') {
                                str += it.value + ','
                            }
                        })
                        var a = str.substr(0, str.length - 1);
                        arr.push(
                            {
                                "subjectChoicesId": item.everyID,
                                "value": a,
                                "grade": item.score
                            }
                        )
                    }
                } else {
                    arr.push(
                        {
                            "subjectChoicesId": item.everyID,
                            "value": item.answer,
                            "grade": item.score
                        }
                    )
                }
            })
            obj.examResultVOS = arr
            saveAndNext(obj).then(response => {
                messageSuccess(this, '提交成功')
                if (response) {
                    this.$store.commit("DEL_TAG", this.$store.state.tags.tag);
                    this.$router.push({
                        path: `/singleperformance/index`,
                    });
                }
            }).catch(() => {
                this.disableSubmit = false
                messageFail(this, '提交题目失败')
            })
        },
        // 选中选项
        toggleOption (answer) {
            this.answer = answer
        },
        // 根据题目类型返回填写的答案
        getAnswer () {
            const ref = this.getSubjectRef()
            if (isNotEmpty(ref)) {
                const answer = ref.getAnswer()
                this.answer = answer
                return answer
                // {
                //     id: answerId,
                //     userId: this.userInfo.id,
                //     examinationId: this.query.examinationId,
                //     examRecordId: this.query.examRecordId,
                //     subjectId: this.query.subjectId,
                //     answer: answer,
                //     type: this.query.type,
                //     startTime: this.subjectStartTime
                // }
            }
            return {}
        },
        // 获取题目索引
        getSubjectIndex (targetId) {
            for (let subject of this.subjectIds) {
                let { subjectId, index } = subject
                if (subjectId === targetId) {
                    return index
                }
            }
            return 1
        },
        // 更新题目索引
        updateSubjectIndex () {
            this.subjectIndex = this.getSubjectIndex(this.query.subjectId)
        },
        startLoading (nextType) {
            if (nextType === nextSubjectType.next) {
                this.loadingNext = true
            } else if (nextType === nextSubjectType.last) {
                this.loadingLast = true
            } else {
                this.loadingNext = true
            }
        },
        endLoading (nextType) {
            if (nextType === nextSubjectType.next) {
                this.loadingNext = false
            } else if (nextType === nextSubjectType.last) {
                this.loadingLast = false
            } else {
                this.loadingNext = false
            }
        },
        getSubjectRef () {
            let ref
            switch (this.query.type) {
                case 0:
                    ref = this.$refs.choices
                    break
                case 1:
                    ref = this.$refs.multipleChoices
                    break
                case 2:
                    ref = this.$refs.judgement
                    break
                case 3:
                    ref = this.$refs.practicalOperation
                    break
                case 4:
                    ref = this.$refs.shortAnswer
                    break
            }
            return ref
        },
        setSubjectInfo (subject) {
            const ref = this.getSubjectRef()
            if (isNotEmpty(ref)) {
                try {
                    ref.setSubjectInfo(subject, this.subjectIds.length, this.subjectIndex)
                } catch (error) {
                    console.error(error)
                }
            }
        }
    }
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style lang="scss" rel="stylesheet/scss" scoped>
.subject-box {
    margin-top: 50px;
    margin-left: 20px;
}
.subject-box-card {
    width: 80%;
    margin-bottom: 30px;
    min-height: 400px;
}
.subject-buttons {
    text-align: right;
}
.tool-bar {
    margin-left: 20px;
}
.time-remain .time {
    display: inline-block;
    font-size: 18px;
    line-height: 22px;
    color: #ff0000;
    font-weight: 400;
}
/* 答题卡 */
.answer-card-title {
    font-size: 13px;
    color: #3a3e51;
    line-height: 17px;
    padding: 10px 0;
}
.answer-card-split {
    width: 100%;
    border-bottom: 1px solid #e6e6e6;
}
.answer-card-content {
    padding-bottom: 10px;
    font-size: 0;
    margin-right: -15px;
    > button {
        margin-top: 5px;
    }
}
.answered {
    background-color: greenyellow;
}
</style>