You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

1000 lines
31 KiB

<template>
<div class="index" v-loading="loading || submiting">
<div class="top">
<div class="item">
<p class="names">{{ curStage.stageName }}:{{ curStage.paperName }}</p>
<div class="count m-l-30">
阶段剩余时间
<span>{{ counterVal.day }}</span>天
<span>{{ counterVal.hour }}</span>小时
<span>{{ counterVal.minutes }}</span>分
<span>{{ counterVal.seconds }}</span>秒
</div>
</div>
<div class="item">
<div class="count m-r-30">
用时
<span>{{ timeSum.day }}</span>天
<span>{{ timeSum.hour }}</span>小时
<span>{{ timeSum.minutes }}</span>分
<span>{{ timeSum.seconds }}</span>秒
</div>
<el-button class="submit" :loading="submiting" :disabled="submited" @click="confirmSubmit">提交</el-button>
<img class="exit" src="@/assets/img/exit.svg" alt="" @click="close">
</div>
</div>
<div class="wrap">
<div class="left">
<h6 class="title">答题卡</h6>
<div class="progress">
<p class="fs-14">答题进度</p>
<el-progress class="m-t-5 m-b-5" :percentage="progress" :format="progressFormat"></el-progress>
<p>共{{ form.questionCount }}题,满分{{ form.score }}分</p>
</div>
<div v-if="form.paperOutline" class="type-wrap">
<template v-for="(item, i) in form.paperOutline">
<div
v-if="item.examQuestions.length && (!sheetStatus || item.examQuestions.some(e => (sheetStatus === 1 && !e.answered) || (sheetStatus === 2 && e.answered) || (sheetStatus === 3 && e.partAnswer) || (sheetStatus === 4 && e.sign)))"
:key="i" class="type">
<h6 class="stem">{{ arabicToChinese(i + 1) }}、{{ item.outlineName }}(本题共{{ item.questionNum }}小题,共{{
item.targetScore }}分)</h6>
<ul class="serials">
<template v-for="(ques, j) in item.examQuestions">
<li
v-if="!sheetStatus || (sheetStatus === 1 && !ques.answered) || (sheetStatus === 2 && ques.answered) || (sheetStatus === 3 && ques.partAnswer) || (sheetStatus === 4 && ques.sign)"
:key="j" :class="{ answered: ques.answered, partAnswer: ques.partAnswer }"
@click="scrollToQues(ques, item)">
<img v-if="ques.sign" class="tag" src="@/assets/img/tag-active.svg" alt="">
{{ j + 1 }}
</li>
</template>
</ul>
</div>
</template>
</div>
<ul class="status-filter">
<li :class="{ active: sheetStatus === 1 }" @click="filterStatus(1)">未作答</li>
<li :class="{ active: sheetStatus === 2 }" @click="filterStatus(2)">已作答</li>
<li :class="{ active: sheetStatus === 3 }" @click="filterStatus(3)">部分已作答</li>
<li :class="{ active: sheetStatus === 4 }" @click="filterStatus(4)"><img class="tag"
src="@/assets/img/tag-active.svg" alt=""> 已标记</li>
</ul>
</div>
<ul v-if="form.paperOutline" class="ques-wrap" id="quesWrap">
<li v-for="(item, i) in form.paperOutline" :key="i">
<div class="outline">
{{ arabicToChinese(i + 1) }}{{ item.outlineName }}本题共{{ item.questionNum }}小题{{
item.targetScore }}
<img :class="['shrink', { active: item.shrink }]" src="@/assets/img/shrink.svg" alt=""
@click="item.shrink = !item.shrink">
</div>
<div :class="['ques', { hide: item.shrink }]">
<div v-for="(ques, j) in item.examQuestions" :key="j" class="item" :id="'ques' + ques.id">
<div class="stem-wrap">
<div class="labels">
<span class="label">{{ j + 1 }} / {{ item.questionNum }}</span>
<span class="label">{{ item.questionTypeName }}</span>
</div>
<div class="stem html-parse" :id="'stem' + ques.id" v-html="ques.stem"></div>
<p>({{ ques.score }}分)</p>
<img class="tag" :src="require('@/assets/img/' + (ques.sign ? 'tag-active' : 'tag') + '.svg')" alt=""
@click="ques.sign = ques.sign ? 0 : 1">
</div>
<!-- 单选、多选、判断的选项 -->
<template
v-if="item.questionType !== 'fill_blank' && item.questionType !== 'essay' && ques.questionAnswerVersionsList">
<div v-for="(opt, j) in ques.questionAnswerVersionsList" :key="j" class="opt">
<el-checkbox v-if="item.questionType === 'multiple_choice'" v-model="opt.answer" :true-label="1"
@change="mulChange(ques)"></el-checkbox>
<el-radio v-else v-model="opt.answer" tabindex="-1" :true-label="1" :label="1"
@change="singleChange(ques, j)"></el-radio>
<span>{{ numToLetter(j) }}.&nbsp;</span>
<div class="text html-parse" v-html="opt.optionText"></div>
</div>
</template>
<!-- 简答题需要展示题干文件及富文本 -->
<template v-if="item.questionType === 'essay'">
<div v-if="ques.stemAttachment" class="m-b-20">
<el-link class="m-r-10" type="primary" @click="preview(ques.stemAttachment)">{{ ques.fileName ||
ques.stemAttachment }}</el-link>
<el-button type="primary" size="mini" round
@click="download(ques.fileName || ques.stemAttachment, ques.stemAttachment)">下载</el-button>
</div>
<UeditorPlus v-if="ques.richTextStatus" :ref="'essayAnswer' + ques.id" v-model="ques.answer"
@ready="editor => essayAnswerReady(editor, ques)" />
<div v-if="ques.allowAttachment" class="m-t-20">
<el-upload style="max-width: 700px;" accept=".csv,.xlsx,.xls,.docx,.doc,.pdf,.jpg,.png,.zip,.rar,.7z"
:before-upload="beforeUpload" :on-remove="e => handleRemove(ques)" :on-error="uploadError"
:before-remove="beforeRemove" :on-preview="handlePreview" :limit="1" action="#"
:on-exceed="handleExceed" :file-list="ques.fileList" :http-request="e => handleRequest(e, ques)">
<el-button type="primary" plain>上传文件</el-button>
</el-upload>
<div v-if="ques.uploadInstructions" class="flex m-t-10 fs-12">
<span>上传要求说明:</span>
<div class="html-parse" v-html="ques.uploadInstructions"></div>
</div>
</div>
</template>
</div>
</div>
</li>
</ul>
</div>
<el-dialog title="图片预览" :visible.sync="previewImgVisible" width="800px" :close-on-click-modal="false">
<el-image style="max-width: 100px; max-height: 100px" :src="previewImg" :preview-src-list="[previewImg]">
</el-image>
</el-dialog>
<PdfDia :key="pdfVisible" :visible.sync="pdfVisible" :src.sync="pdfSrc" />
</div>
</template>
<script>
import Util from '@/libs/util'
import Setting from "@/setting"
import QuesConst from '@/const/ques'
import TestPaperConst from '@/const/testPaper'
import _ from 'lodash'
import Upload from '@/components/upload'
import UeditorPlus from '@/components/ueditorPlus'
import PdfDia from '@/components/pdf'
import Bus from '@/libs/bus'
import OSS from 'ali-oss'
import OssConfig from '@/components/upload/config.js'
import Oss from '@/components/upload/upload.js'
export default {
components: {
Upload, UeditorPlus, PdfDia
},
data () {
return {
loading: false,
per: 2, // 项目权限(0、练习 1、考核 2、竞赛)
questionTypes: QuesConst.questionTypes,
numToLetter: Util.numToLetter,
arabicToChinese: Util.arabicToChinese,
headers: {
token: Util.local.get(Setting.tokenKey)
},
token: Util.local.get(Setting.tokenKey),
id: +this.$route.query.id, // 赛事id
stageId: +this.$route.query.stageId,
teamId: this.$route.query.teamId || '',
entryTime: '',
curStage: {
stageName: '',
paperName: '',
},
timer: null,
counterTimer: null,
countVal: 0,
// 倒计时
counterVal: {
day: 0,
seconds: 0,
minutes: 0,
hour: 0,
},
timeSumVal: 0,
// 用时
timeSum: {
day: 0,
seconds: 0,
minutes: 0,
hour: 0,
},
totalAnswered: 0,
progress: 0,
sheetStatus: '',
form: {
questionCount: 0,
},
submiting: false,
submited: false,
warned: 0,
quesWrapWidth: 0,
previewImgVisible: false,
previewImg: '',
pdfVisible: false,
pdfSrc: '',
client: null,
};
},
mounted () {
this.$once('hook:beforeDestroy', function () {
clearInterval(this.counterTimer)
})
// websocket实时刷新
Bus.$on('matchSocket', () => {
this.getCompetition()
})
this.getCompetition(1)
this.initOss()
},
methods: {
// 获取竞赛信息
async getCompetition (load) {
if (load) this.loading = true
const { competition } = await this.$post(`${this.api.getCompetition}?competitionId=${this.id}`)
const stages = competition.contentList
if (stages) {
const stage = stages.find(e => e.stageId === this.stageId)
const item = competition.competitionStage.find(e => e.stageId === this.stageId)
if (item) {
stage.stageName = item.stageName
stage.resultAnnouncementTime = item.resultAnnouncementTime
}
this.curStage = stage
const endTime = new Date(stage.endTime)
const now = await Util.getNow()
// 如果已经结束
if (now >= endTime) {
this.loading = false
this.submit(1, 1)
} else { // 没结束,则显示倒计时
this.countVal = (endTime - now) / 1000
load && this.getPaper(now)
}
}
},
// 获取试卷详情
async getPaper (now) {
try {
const { paperId, stageId } = this.curStage
if (paperId) {
// 试卷详情
const { examPaper } = await this.$get(this.api.examPaperDetails, { id: paperId })
// 缓存,如果有,则全部回显到页面上
const { examSubmitReq: cache } = await this.$post(this.api.getExamPaperCache, {
competitionId: this.id,
paperId,
stageId
})
let cacheQues = []
if (cache) {
this.entryTime = new Date(cache.startTime)
this.timeSumVal = (now - new Date(cache.startTime)) / 1000
cacheQues = cache.examSubmitJudgeList
} else {
this.entryTime = now
}
this.startCount()
const r = examPaper
const paper = r.paperOutline
const types = this.questionTypes
paper.map(e => {
const type = e.questionType
e.questionTypeName = types.find(n => n.id === type).name
e.shrink = false
e.examQuestions.map(n => {
Object.assign(n, n.question)
const curQues = cacheQues.find(m => m.outlineId === e.outlineId && m.questionVersionId === n.questionVersionId) // 缓存里的试题
n.sign = curQues ? curQues.sign : 0
const opts = n.questionAnswerVersionsList
if (type !== 'fill_blank' && type !== 'essay' && opts) { // 选择题
opts.map(m => {
m.answer = curQues && curQues.answer && curQues.answer.length && curQues.answer.some(n => n == m.optionNumber) ? 1 : 0
})
if (opts.some(m => m.answer)) n.answered = 1
} else if (type === 'fill_blank') { // 填空题
n.fills = curQues && curQues.answer && curQues.answer.length && curQues.answer.some(m => m) ? curQues.answer : ''
let { answerData } = opts[0]
if (answerData) answerData = JSON.parse(answerData)
n.answered = n.fills && answerData && answerData.length === n.fills.filter(m => m).length ? 1 : 0
n.partAnswer = n.fills && answerData && answerData.length !== n.fills.filter(m => m).length ? 1 : 0
n.stem = this.getQuesStem(n)
} else if (type === 'essay') { // 简答题
n.answer = type === 'essay' && curQues ? curQues.answerContent : ''
n.attachmentName = curQues ? curQues.attachmentName : ''
n.attachmentUrl = curQues ? curQues.attachmentUrl : ''
n.fileList = []
if (n.attachmentUrl) {
n.fileList = [{
name: n.attachmentName,
url: n.attachmentUrl
}]
}
// 附件
const url = n.attachmentUrl
if (url) {
n.uploadList = [{
name: n.attachmentName || url,
url
}]
}
if (n.answer || url) n.answered = 1
}
})
})
this.form = r
this.loading = false
// 给填空题的每个空监听input事件,用以显示已作答状态
this.$nextTick(() => {
cache || this.submit(0) // 如果没有缓存,则先缓存一次(只是为了缓存进入时间,因为只有在每个小题答题后才会调缓存接口,所以只能第一次进入就缓存一次进入时间)
paper.map(e => {
e.examQuestions.map(n => {
if (e.questionType === 'fill_blank') {
const stem = document.querySelector(`#stem` + n.id)
if (stem) {
const inputs = stem.querySelectorAll('.fill-input')
if (inputs) {
for (const e of inputs) {
e.addEventListener('input', () => {
const answers = []
let hasFillLen = 0
for (const e of inputs) {
const val = e.innerText
if (val) hasFillLen++
answers.push(val)
}
n.fills = answers
n.answered = hasFillLen === inputs.length ? 1 : 0
n.partAnswer = hasFillLen && hasFillLen !== inputs.length ? 1 : 0
clearTimeout(this.timer)
this.timer = setTimeout(() => {
this.submit(0)
this.calcProgress()
}, 500)
})
}
}
}
}
})
})
this.calcProgress()
})
}
} catch (e) {
this.loading = false
}
},
// 计时器
handleCounter (counterTime, isCount) {
let leave1 = counterTime % (24 * 3600) //计算天数后剩余的毫秒数
let leave2 = leave1 % 3600 //计算小时数后剩余的毫秒数
let leave3 = leave2 % 60 //计算分钟数后剩余的毫秒数
let day = Math.floor(counterTime / (24 * 3600)) //计算相差天数
let hour = Math.floor(leave1 / 3600) //计算相差小时
let minutes = Math.floor(leave2 / 60) //计算相差分钟
let seconds = Math.round(leave3) //计算相差秒
day = this.timeFormat(day)
hour = this.timeFormat(hour)
minutes = this.timeFormat(minutes)
seconds = this.timeFormat(seconds)
const count = this[isCount ? 'counterVal' : 'timeSum']
count.day = day
count.hour = hour
count.minutes = minutes
count.seconds = seconds
},
// 计时前的判断
counter (counterTime) {
if (counterTime <= 0) {
if (this.per) { // 竞赛/考核
clearInterval(this.counterTimer)
this.submit(1, 1)
} else {
this.handleCounter(counterTime, 1)
}
} else {
// 剩15分钟时要提示
if (counterTime === 900) {
this.warned || this.$alert(`请注意,${this.per == 2 ? '比赛' : '考核'}还剩15分钟,请尽快完成答题并提交试卷。`, '提示', {
confirmButtonText: '确定',
type: 'warning'
})
this.warned = 1
}
this.handleCounter(counterTime, 1)
}
},
// 启动倒计时
startCount () {
clearInterval(this.counterTimer)
this.counterTimer = setInterval(() => {
this.counter(this.per ? this.countVal-- : this.countVal++)
this.timeSumVal >= 0 && this.handleCounter(this.timeSumVal++)
}, 1000)
},
timeFormat (param) {
return param < 10 ? '0' + param : param
},
// 计算答题进度
calcProgress () {
let answered = 0
this.form.paperOutline.map(e => {
answered += e.examQuestions.filter(n => n.answered).length
})
this.totalAnswered = answered
this.progress = +(answered / this.form.questionCount * 100).toFixed(1)
},
// 答题进度格式
progressFormat (e) {
return this.totalAnswered + '/' + this.form.questionCount
},
scrollToSmooth (position, duration) {
let startTime = Date.now()
function scroll () {
let now = Date.now()
let progress = Math.min(1, (now - startTime) / duration)
document.querySelector('#quesWrap').scrollTo(0, position * progress)
if (progress < 1) {
window.requestAnimationFrame(scroll)
}
}
window.requestAnimationFrame(scroll)
},
// 答题卡题目点击滚动
scrollToQues (e, item) {
item.shrink = false
const el = document.querySelector('#ques' + e.id)
this.$nextTick(() => {
el && this.scrollToSmooth(el.offsetTop - document.querySelector('#quesWrap').offsetTop, 200)
})
},
// 答题卡筛选
filterStatus (e) {
this.sheetStatus = this.sheetStatus === e ? '' : e
},
// 处理题干显示
getQuesStem (ques) {
let { stem } = ques
if (ques.questionType === 'fill_blank') { // 填空题
let { fills } = ques
const regex = /<span class="gapfilling-span" data-id="(.*?)">______<\/span>/g
let match
let index = 0 // 用于跟踪索引
let result = stem
while ((match = regex.exec(stem)) !== null) {
const newInput = `<span contenteditable placeholder="(${index + 1})" class="fill-input">${fills && fills.length ? fills[index] : ''}</span>`
result = result.replace(match[0], newInput)
index++
}
return result
} else {
return stem
}
},
preventAllKeyPress (event) {
// 阻止所有键盘事件
event.preventDefault();
},
// 单选题回调
singleChange (ques, j) {
ques.questionAnswerVersionsList.map(e => {
e.answer = 0
})
ques.questionAnswerVersionsList[j].answer = 1
ques.answered = 1
this.calcProgress()
this.submit(0)
},
// 多选题回调
mulChange (ques) {
ques.answered = ques.questionAnswerVersionsList.some(e => e.answer)
this.calcProgress()
this.submit(0)
},
// 简答题富文本加载完毕回调
essayAnswerReady (editor, ques) {
editor.ques = ques
editor.addListener('contentChange', () => {
const content = editor.getContent()
ques.answered = content ? 1 : 0
ques.answers = content
clearTimeout(this.timer)
this.timer = setTimeout(() => {
this.submit(0)
this.calcProgress()
}, 500)
})
ques.answer && editor.setContent(ques.answer)
},
// 预览附件
preview (url) {
const ext = url.split('.').pop()
if (Util.isDoc(ext)) {
window.open('https://view.officeapps.live.com/op/view.aspx?src=' + url)
} else if (Util.isImg(ext)) {
this.previewImgVisible = true
this.previewImg = url
} else if (ext === 'pdf') {
this.pdfVisible = true
this.pdfSrc = url
}
},
// 下载附件
download (name, url) {
Util.downloadFile(name, url)
},
async initOss () {
const o = await OssConfig()
this.client = new OSS(o.config)
},
// 附件上传前
beforeUpload (file) {
const oversize = file.size / 1024 / 1024 < 50
if (!oversize) Util.warningMsg('请上传小于50M的文件!')
if (oversize) {
return true
} else {
return false
}
},
// 自定义上传
async handleRequest (e, ques) {
const { file } = e
try {
ques.fileList = []
const { name } = await this.client.multipartUpload(Date.now() + '.' + Util.getFileExt(file.name), file)
const url = 'https://huoran.oss-cn-shenzhen.aliyuncs.com/' + name
ques.fileList = [{
name: file.name,
url
}]
ques.attachmentName = file.name
ques.attachmentUrl = url
this.submit(0)
} catch (e) { }
},
handlePreview ({ url }) {
this.preview(url)
},
uploadError () {
this.$message({
message: "上传出错,请重试!",
type: "error",
center: true
})
},
beforeRemove (file) {
return this.$confirm(`确定移除 ${file.name}`);
},
handleExceed () {
Util.warningMsg(`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!`);
},
handleRemove (ques) {
Oss.del(ques.attachmentUrl)
ques.fileList = []
ques.attachmentName = ''
ques.attachmentUrl = ''
this.submit(0)
},
// 解析富文本加载完毕回调
answerAnalysisReady (editor) {
this.answerAnalysis && editor.setContent(this.answerAnalysis)
},
// 提交询问
async confirmSubmit () {
if (this.submiting) return false
let msg = '此操作将视为结束答题,确认要提交吗?'
for (const e of this.form.paperOutline) {
if (e.examQuestions.some(n => !n.answered)) {
msg = '还有试题未答完,确认要提交吗?'
break
}
}
try {
await this.$confirm(msg, '提示', {
// confirmButtonText: '确定',
// cancelButtonText: '取消',
type: 'warning',
closeOnClickModal: false
})
this.submit(1)
} catch (e) { }
},
// 提交
async submit (isSubmit, autoSubmit) {
if (isSubmit && this.submiting) return false
try {
if (isSubmit) this.submiting = true
const form = _.cloneDeep(this.form)
const { entryTime, curStage } = this
const ques = []
form.paperOutline.map(e => {
const type = e.questionType
e.examQuestions.map(n => {
let answer = []
let answerContent = ''
if (type !== 'fill_blank' && type !== 'essay') { // 选择题
answer = n.questionAnswerVersionsList.filter(m => m.answer).map(m => m.optionNumber)
} else if (type === 'essay') { // 简答题
if (n.answers) answerContent = n.answers
} else { // 填空题
answer = n.fills || []
}
ques.push({
answer,
answerContent,
attachmentName: n.attachmentName,
attachmentUrl: n.attachmentUrl,
outlineId: e.outlineId,
questionType: type,
questionVersionId: n.questionVersionId,
serialNumber: n.serialNumber,
setScore: n.score,
sign: n.sign,
})
})
})
const data = {
competitionId: this.id,
stageId: curStage.stageId,
teamId: this.teamId,
startTime: Util.formatDate('yyyy-MM-dd hh:mm:ss', entryTime), // 取页面进入的时间
totalScore: form.score,
paperId: curStage.paperId,
examSubmitJudgeList: ques,
}
const now = isSubmit ? await Util.getNow() : new Date()
const submitTime = Util.formatDate('yyyy-MM-dd hh:mm:ss', now)
data.endTime = this.per ? curStage.endTime : submitTime
data.submitTime = submitTime
data.timeSum = Math.ceil((now - entryTime) / 60000) // 计算实验用时(分钟),向上取整
// 缓存跟提交接口的参数一样
await this.$post(this.api[isSubmit ? 'submitTheExamPaper' : 'examPaperRecordCache'], data)
if (isSubmit) {
window.opener && window.opener.location.reload()
clearInterval(this.counterTimer)
this.submiting = false
this.submited = true
// 如果是时间到了自动提交,则提交完不弹框,直接关闭页面
if (autoSubmit) {
this.$alert(`${this.per == 2 ? '竞赛' : '考核'}时间已到,系统已自动交卷`, '提示', {
confirmButtonText: '确定',
type: 'warning',
callback: _ => {
this.close()
}
})
} else {
// 如果是竞赛,并且勾选了公布成绩详情的选项,则弹框提示
if (this.id) {
const time = curStage.resultAnnouncementTime
const msg =
time === 0 ? '提交成功!成绩将在比赛结束后公布,请前往参赛信息模块查看' : time > 0 ? `提交成功!成绩将在比赛结束后${time}小时公布,请前往参赛信息模块查看` : '提交成功';
this.$alert(msg, '提示', {
confirmButtonText: '确定',
type: 'success',
callback: () => {
this.close()
}
})
} else {
this.$message.success('提交成功!')
}
}
}
} catch (e) {
this.submiting = false
}
},
close () {
window.close()
},
}
};
</script>
<style lang="scss" scoped>
.top {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 20px;
color: #fff;
background-color: #5786fc;
.item {
display: inline-flex;
align-items: center;
}
.names {
font-size: 18px;
font-weight: 600;
}
.submit {
width: 106px;
font-size: 15px;
}
.exit {
margin-left: 20px;
cursor: pointer;
&:hover {
opacity: .9;
}
}
}
/deep/.wrap {
display: flex;
padding: 15px;
.left {
width: 293px;
margin-right: 15px;
background-color: #fff;
.title {
padding: 10px 0;
font-size: 16px;
text-align: center;
color: #333;
}
.progress {
padding: 10px;
color: #5a5a5a;
background-color: #d4e9ff;
}
.type-wrap {
max-height: calc(100vh - 297px);
padding: 10px;
overflow: auto;
.type {
margin-bottom: 20px;
}
.stem {
font-size: 15px;
color: #333;
}
}
.serials {
display: flex;
flex-wrap: wrap;
margin-top: 5px;
li {
position: relative;
width: 30px;
margin: 7px 9px;
font-size: 13px;
text-align: center;
line-height: 30px;
color: #505050;
border: 1px solid #d3d3d3;
cursor: pointer;
&:hover {
opacity: .9;
}
&.answered {
color: #fff;
background-color: #66b2ff;
border-color: #66b2ff;
}
&.partAnswer {
border-color: #66b2ff;
}
}
.tag {
position: absolute;
top: -2px;
left: -4px;
}
}
.status-filter {
display: flex;
justify-content: space-between;
padding: 10px;
border-top: 1px solid #e5e5e5;
li {
display: inline-flex;
align-items: center;
padding: 0 3px;
font-size: 12px;
color: #333;
cursor: pointer;
border: 1px solid transparent;
&:not(:last-child):before {
content: '';
width: 13px;
height: 13px;
margin-right: 5px;
border: 1px solid #ccc;
}
&:nth-child(2):before {
background-color: #56aaff;
border: 0;
}
&:nth-child(3):before {
border-color: #56aaff;
}
&.active {
font-weight: 600;
color: #007eff;
border-color: #007eff;
&:last-child {
color: #d81e06;
border-color: #d81e06;
}
}
}
}
}
.ques-wrap {
width: calc(100% - 308px);
height: calc(100vh - 128px);
background-color: #fff;
overflow: auto;
outline: none;
&>li {
margin-bottom: 15px;
}
.outline {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 15px;
font-size: 15px;
font-weight: 600;
color: #333;
background-color: #e8f0ff;
}
.shrink {
cursor: pointer;
transition: .5s;
&.active {
transform: rotate(180deg);
}
}
.ques {
max-height: none;
padding: 15px;
margin-bottom: 15px;
transition: all 1.5s;
overflow: hidden;
&.hide {
max-height: 10px;
}
}
.item:not(:last-child) {
padding-bottom: 15px;
margin-bottom: 15px;
border-bottom: 1px dashed #e1e1e1;
}
.stem-wrap {
display: flex;
align-items: baseline;
margin-bottom: 10px;
}
img {
max-width: 100%;
}
.tag {
margin-left: 10px;
cursor: pointer;
&:hover {
opacity: .9;
}
}
.labels {
display: inline-flex;
align-items: center;
}
.label {
padding: 3px 5px;
margin-right: 10px;
font-size: 12px;
line-height: 1;
color: $main-color;
white-space: nowrap;
border: 1px solid;
border-radius: 2px;
}
.stem {
max-width: calc(100% - 197px);
}
.fill-input {
position: relative;
display: inline;
min-width: 50px;
height: 28px;
padding: 3px;
margin: 0 10px;
font-size: 14px;
line-height: 28px;
color: #333;
border: 0;
border-bottom: 1px solid #DCDEE0;
outline: none;
&:empty {
display: inline-block;
width: 3em;
}
}
.opt {
display: flex;
flex-wrap: wrap;
align-items: baseline;
padding-left: 10px;
margin-bottom: 5px;
font-size: 14px;
color: #707070;
line-height: 1.6;
.el-radio,
.el-checkbox {
margin-right: 15px;
}
.el-radio__label {
display: none;
}
.text {
max-width: calc(100% - 48px);
}
}
}
}
</style>