2487 lines
63 KiB
Vue
Raw Normal View History

2025-07-22 18:31:50 +08:00
<template>
2025-07-30 19:58:32 +08:00
<view class="questions">
<!-- 头部信息 -->
<view class="test-header" v-if="showCountDown">
<tui-countdown :time="limit_time" borderColor="#FFF" color="#080808" :size="36" :colonSize="36"
@end="endOfTime"></tui-countdown>
</view>
<!-- 题目列表 -->
<view class="card-shadow">
<view class="topic-title">
<view class="topic-title_left">
<!-- 题型 -->
<view class="text-kind">
{{ kindText() }}
</view>
<!-- 收藏 -->
<view class="test-favor" v-if="canCollect">
<tui-icon name="like-fill" color="#f74d54" :size="18" @click="collectDel()"
v-if="list[swiperIndex-1] && list[swiperIndex-1].collected"></tui-icon>
<tui-icon name="like" color="#aaa" :size="18" @click="collectAdd()" v-else></tui-icon>
<view class="tui-fabulous"
:class="{ 'tui-fabulous__active': list[swiperIndex-1] && list[swiperIndex-1].collected }">
<tui-icon name="like-fill" color="#f74d54"></tui-icon>
</view>
</view>
</view>
<!-- 题标 -->
<view class="topic-title_right">
<text class="title-index">{{ swiperIndex }}</text>
/{{ total }}
</view>
</view>
<!-- 防切屏提示 -->
<view class="topic-title" style="font-size: 24rpx;" v-if="isPreventSwitchScreen">
注意当前考试开启了防切屏切屏次数超过{{ switchScreenCount }}次考试将自动结束
</view>
<swiper :current="swiperIndex - 1" @change="swiperChange" class="questions-cont">
<swiper-item v-for="(item, index) in list" :key="index" class="swiper-item">
<view v-if="Math.abs(swiperIndex - 1 - index) <= 30">
<block v-if="index == swiperIndex - 1">
<!-- 材料题标题 -->
<view class="material-title" v-if="item.material_title != undefined">
<view class="material-title-tip">材料</view>
<view v-if="!item.show_full">
<!-- <rich-text :nodes="questionTitle(swiperIndex, item, 'material_title')"></rich-text> -->
<mp-html :content="questionTitle(swiperIndex, item, 'material_title')"></mp-html>
<button @click="showFullMaterialTitle(swiperIndex, item, true)">展开</button>
</view>
<view v-else>
<!-- <rich-text :nodes="questionTitle(swiperIndex, item, 'material_title')"></rich-text> -->
<mp-html :content="questionTitle(swiperIndex, item, 'material_title')"></mp-html>
<button @click="showFullMaterialTitle(swiperIndex, item, false)">收起</button>
</view>
</view>
<!-- 题目视频 -->
<view v-if="item.title_video_url != undefined && item.title_video" class="title-video">
<video id="title-video" class="title-video" :src="item.title_video_url"
:controls="true"></video>
</view>
<!-- 判断单选多选题 -->
<view v-if="item.kind === 'JUDGE' || item.kind === 'SINGLE' || item.kind === 'MULTI'">
<view class="test-main" style="padding-bottom: 20rpx;">
<view class="test-title">
<mp-html :content="item.title"></mp-html>
</view>
<view class="test-cont">
<view class="test-cont-item"
v-for="(optionItem, optionIndex) in item.options_json" :key="optionIndex"
@tap.stop="chooseItem(index, optionIndex, item.kind)"
:class="optionItem.classes ? optionItem.classes : ''">
<view class="key text-cut">
{{ optionItem.key }}
</view>
<view class="cont">
<view class="cont-text">
<block v-if="item.options_img"
v-for="(optionImg, optionImgIndex) in item.options_img"
:key="optionImgIndex">
<image class="image" v-if="optionImg.key == optionItem.key"
@tap.stop="previewImage(optionImg.value)"
:src="optionImg.value" mode="widthFix"></image>
</block>
<view v-if="!isNaN(optionItem.value)">
{{ optionItem.value }}
</view>
<view v-else>
<mp-html :content="optionItem.value"></mp-html>
</view>
<!-- <view>{{ optionItem.value ? optionItem.value : '' }}</view> -->
</view>
<view class="cont-icon">
<view v-if="optionItem.classes">
<text v-if="optionItem.classes.indexOf('true') != -1"
class="cuIcon-check"></text>
<text
v-else-if="optionItem.classes.indexOf('true') == -1 && optionItem.classes.indexOf('active') != -1"
class="cuIcon-close"></text>
</view>
</view>
</view>
</view>
</view>
<view v-if="item.kind === 'MULTI' && mode=='TRAINING'" @click="duoXuanSubmit(optionIndex)"
style="border-radius: 5rpx;width: 100%;height: 90rpx;background-color:#1A73E8;color: #ffffff;text-align: center;line-height: 90rpx;">
提交</view>
</view>
<view class="test-describe" v-if="showAnswer || item.show_answer">
<view class="describe-cont">
<view class="describe-item">
<view class="answer-row">
<view class="text-right-answer">正确答案</view>
<view class="text-right-answer-val">{{ item.answer }}</view>
</view>
</view>
<view class="describe-item" v-if="mode == 'VIEW'">
<view class="answer-row">
<view class="text-right-answer">用户答案</view>
<view class="text-right-answer-val">{{ item.user_answer || '未填写' }}
</view>
</view>
</view>
<view class="describe-item" v-if="pageType == 'WRONG' && item.source">
<view class="answer-row">
<view class="text-right-answer">错题来源</view>
<view class="text-right-answer-val">{{ getSourceText(item.source) }}
</view>
</view>
</view>
</view>
</view>
<view class="test-describe" v-if="showAnswer || item.show_answer">
<view class="describe-cont">
<view>
<view class="text-right-answer text-indent tn-margin-top-sm">答案解析</view>
<view class="explain-content">
<mp-html :content="item.explain" class="explain-content-text"
v-if="item.explain"></mp-html>
<text class="font-size-30" v-else></text>
</view>
</view>
</view>
</view>
</view>
<!-- 填空题 -->
<view v-else-if="item.kind === 'FILL'">
<view class="test-main">
<view class="test-title test-title-fill">
<block v-for="(titleText, titleIndex) in item.title_data" :key="titleIndex">
<view class="test-title-fill-item">{{ titleText }}</view>
<view class="test-title-fill-item">
<!-- #ifdef MP-WEIXIN -->
<input type="text" placeholder="请输入答案" class="fill-input"
v-if="item.title_data && item.title_data.length - 1 != titleIndex"
:class="[item.answer && item.answer[titleIndex] && item.answer[titleIndex].class ? item.answer[titleIndex].class : '']"
:value="setFillInputValue(titleIndex)" :disabled="mode === 'VIEW'"
@change="(e) => changeFillInput(e, titleIndex, swiperIndex)" />
<!-- #endif -->
<!-- #ifdef H5 -->
<input type="text" placeholder="请输入答案" class="fill-input"
v-if="item.title_data && item.title_data.length - 1 != titleIndex"
:class="[item.answer && item.answer[titleIndex] && item.answer[titleIndex].class ? item.answer[titleIndex].class : '']"
:value="setFillInputValue(titleIndex)" :disabled="mode === 'VIEW'"
@blur="(e) => changeFillInput(e, titleIndex, swiperIndex)" />
<!-- #endif -->
</view>
</block>
<view class="test-title-fill-item">{{ getQuestionTitleScore(index, item) }}
</view>
</view>
<view class="test-cont">
<!-- 确认答案按钮 -->
<view class="btn-confirm"
v-if="mode == 'TRAINING' && item.is_answered === false">
<tui-button type="primary" shape="circle" @click="confirmFillAnswer"
width="360rpx" height="60rpx" :size="26" margin="0 auto">确认答案
</tui-button>
</view>
</view>
</view>
<view class="test-describe" v-if="showAnswer || item.show_answer">
<view class="describe-cont">
<view class="describe-item">
<view class="answer-row">
<view class="text-right-answer">正确答案</view>
</view>
</view>
<view class="describe-item pt-0">
<view class="answer-row">
<view class="text-right-answer-val">
<view class="text-right-answer-val-item"
v-for="(answer, answerIndex) in item.answer" :key="answerIndex">
填空位{{ answerIndex + 1 }}{{ answer.answers.join('') }}
</view>
</view>
</view>
</view>
<view class="describe-item" v-if="mode == 'VIEW' && item.user_answer">
<view class="answer-row">
<view class="text-right-answer">用户答案</view>
</view>
</view>
<view class="describe-item pt-0">
<view class="answer-row">
<view class="text-right-answer-val">
<view class="text-right-answer-val-item"
v-for="(answer, answerIndex) in item.user_answer"
:key="answerIndex">
填空位{{ answerIndex + 1 }}{{ answer }}
</view>
</view>
</view>
</view>
<view class="describe-item" v-if="pageType == 'WRONG' && item.source">
<view class="answer-row">
<view class="text-right-answer">错题来源</view>
<view class="text-right-answer-val">{{ getSourceText(item.source) }}
</view>
</view>
</view>
</view>
</view>
<view class="test-describe" v-if="showAnswer || item.show_answer">
<view class="describe-cont">
<view>
<view class="text-right-answer text-indent tn-margin-top-sm">答案解析</view>
<view class="explain-content">
<mp-html :content="item.explain" class="explain-content-text"
v-if="item.explain"></mp-html>
<text class="font-size-30" v-else></text>
</view>
</view>
</view>
</view>
</view>
<!-- 简答题 -->
<view v-else-if="item.kind === 'SHORT'">
<view class="test-main">
<view class="test-title">
<mp-html :content="item.title"
style="font-size: 36rpx; font-weight: bold;"></mp-html>
<!-- <rich-text :nodes="questionTitle(swiperIndex, item)"
2025-07-22 18:31:50 +08:00
style="font-size: 36rpx; font-weight: bold;"></rich-text> -->
2025-07-30 19:58:32 +08:00
</view>
<view class="test-cont">
<!-- 答案输入框 -->
<textarea placeholder="在此输入答案" class="short-input" :maxlength="-1"
:value="setShortInputValue(swiperIndex)" :auto-blur="true"
@blur="(e) => changeShortInput(e, swiperIndex)"
@input="(e) => changeShortInput(e, swiperIndex)" />
<!-- 确认答案按钮 -->
<view class="btn-confirm" v-if="mode == 'TRAINING'">
<tui-button type="primary" shape="circle" @click="confirmShortAnswer"
width="360rpx" height="60rpx" :size="26" margin="0 auto">确认答案
</tui-button>
</view>
</view>
</view>
<!-- <view class="test-describe" v-if="showAnswer || item.show_answer">
2025-07-22 18:31:50 +08:00
<view class="describe-cont">
<view>
<view>
<view class="text-right-answer">正确答案</view>
<text style="color: #1A73E8;margin-left: 30rpx;" v-if="item.answer && item.answer.answer">{{item.answer.answer}}</text>
</view>
<view v-for="(keyword, keywordIndex) in item.answer.config" :key="keywordIndex">
<view :class="[keyword.class]">
关键词{{ keywordIndex + 1 }}{{ keyword.answer }}({{ keyword.score }})
</view>
</view>
</view>
</view>
</view> -->
2025-07-30 19:58:32 +08:00
<view class="test-describe" v-if="showAnswer || item.show_answer">
<view class="describe-cont">
<view class="describe-item">
<view class="answer-row">
<view class="text-right-answer">正确答案</view>
</view>
</view>
<view class="describe-item pt-0">
<view class="answer-row">
<view class="text-right-answer-val">
<view class="text-right-answer-val-item"
v-for="(keyword, keywordIndex) in item.answer.config"
:key="keywordIndex">
<view :class="[keyword.class]">
关键词{{ keywordIndex + 1 }}{{ keyword.answer }}({{ keyword.score }})
</view>
</view>
</view>
</view>
</view>
<view class="describe-item" v-if="mode == 'VIEW' && item.user_answer">
<view class="answer-row">
<view class="text-right-answer">用户答案</view>
</view>
</view>
<view class="describe-item pt-0">
<view class="answer-row">
<view class="text-right-answer-val">
<view class="text-right-answer-val-item"
v-for="(answer, answerIndex) in item.user_answer"
:key="answerIndex">
{{ answer }}
</view>
</view>
</view>
</view>
<view class="describe-item" v-if="pageType == 'WRONG' && item.source">
<view class="answer-row">
<view class="text-right-answer">错题来源</view>
<view class="text-right-answer-val">{{ getSourceText(item.source) }}
</view>
</view>
</view>
</view>
</view>
<view class="test-describe" v-if="showAnswer || item.show_answer">
<view class="describe-cont">
<view>
<view class="text-right-answer text-indent tn-margin-top-sm">答案解析</view>
<view class="explain-content">
<mp-html :content="item.explain" class="explain-content-text"
v-if="item.explain"></mp-html>
<text class="font-size-30" v-else></text>
</view>
</view>
</view>
</view>
</view>
<!-- 解析视频 -->
<view class="explain-video-view"
v-if="(showAnswer || item.show_answer) && item.explain_video_url != undefined && item.explain_video">
<video id="explain-video" class="explain-video" :src="item.explain_video_url"
controls></video>
</view>
</block>
<view style="height: 100rpx;"></view>
</view>
</swiper-item>
</swiper>
</view>
<!-- 底部栏 -->
<!-- :class="mode == 'EXAM' || mode == 'VIEW' ? (canDeleteWrong ? ['col-5'] : ['col-4']) : ['col-3']" -->
<view class="fix-bottom grid text-center bg-white cu-list" :class="[getBottomBarClass()]">
<view url="/pages/index/index" class="cu-item" @click="handleNumberPanel"><!-- v-if="mode != 'TRAINING'" -->
<image src="/static/img/caidan.png"></image>
<text>{{ swiperIndex }}/{{ total }}</text>
</view>
<view url="/pages/index/index" class="cu-item" @tap="prev">
<image src="/static/img/left.png"></image>
<text>上一题</text>
</view>
<view url="/pages/index/index" class="cu-item" @tap="next">
<image src="/static/img/right.png"></image>
<text>下一题</text>
</view>
<view url="/pages/index/index" class="cu-item" @tap="buttonClicked==true?submitShowModal():''"
v-if="mode == 'EXAM'">
<image src="/static/img/jiaojuan.png"></image>
<text>交卷</text>
</view>
<view url="/pages/index/index" class="cu-item" @tap="buttonClicked==true?endTrainShowModal():''"
v-if="mode == 'TRAINING'">
<image src="/static/img/jiaojuan.png"></image>
<text>结束练习</text>
</view>
<view url="/pages/index/index" class="cu-item" @tap="wrongDel()" v-if="mode == 'VIEW' && canDeleteWrong">
<image src="/static/img/delete.png"></image>
<text>删除</text>
</view>
<!-- <view url="/pages/index/index" class="cu-item" @tap="wrongClear()" v-if="mode == 'VIEW' && canDeleteWrong">
2025-07-22 18:31:50 +08:00
<image src="/static/img/round_close.png"></image>
<text>清空</text>
</view> -->
2025-07-30 19:58:32 +08:00
</view>
2025-07-22 18:31:50 +08:00
2025-07-30 19:58:32 +08:00
<!-- 题标 -->
<!-- <view class="fixed-bottom" :class="{ active: showNumberPanel }" @click.stop="handleNumberPanel">
2025-07-22 18:31:50 +08:00
<view class="tibiao" @click.stop>
<scroll-view scroll-y="true" class="tibiao-scroll">
<view class="tibiao-item" v-for="(item, index) in total" :key="index" :class="swiperIndex - 1 == index ? 'selected' : ''"
@click="changeQuestion(index)">
{{ index + 1 }}
</view>
</scroll-view>
</view>
</view> -->
2025-07-30 19:58:32 +08:00
<!-- 题标 -->
<view class="cu-modal bottom-modal fixed-bottom" :class="showNumberPanel?'show':''"
@click.stop="handleNumberPanel">
<view class="cu-dialog tibiao" @click.stop>
<scroll-view scroll-y="true" class="tibiao-scroll">
<view class="tibiao-scroll-list">
<!-- class="tibiao-item" -->
<!-- :class="[getNumberPanelClass(index)]" -->
<!-- :class="swiperIndex - 1 == index ? 'selected' : (list[index] && (list[index].check || list[index].user_answers) ? 'right' : '')" -->
<view :class="['tibiao-item', getNumberPanelClass(index)]" v-for="(item, index) in total"
:key="index" @click="changeQuestion(index)">
{{ index + 1 }}
</view>
</view>
</scroll-view>
</view>
</view>
<!-- 删除错题对话框 -->
<view class="cu-modal" :class="showDeleteDialog?'show':''">
<view class="cu-dialog">
<view class="cu-bar bg-white justify-end">
<view class="content">提示</view>
<view class="action" @tap="hideModal">
<text class="cuIcon-close text-red"></text>
</view>
</view>
<view class="padding-xl">
{{ wrongDeleteType == 'single' ? '确定删除该错题吗?' : '确定清空所有错题吗?' }}
</view>
<view class="cu-bar bg-white justify-end">
<view class="action">
<button class="cu-btn line-primary text-primary" @tap="hideModal">取消</button>
<button class="cu-btn bg-primary margin-left" @tap="confirmDelWrong">确定</button>
</view>
</view>
</view>
</view>
<!-- 结束练习对话框 -->
<tui-modal :show="showEndTrainDialog" @cancel="hideModal" :custom="true">
<view class="tui-modal-custom">
<view class="tui-prompt-title">练习结果</view>
<view class="tui-modal-custom-text">
<view class="">
正确题数
<text class="text-green">{{ trainResult.right }}</text>
</view>
<view class="">
错误题数
<text class="text-red">{{ trainResult.error }}</text>
</view>
<view class="">
未答题数
<text class="text-yellow">{{ trainResult.unchecked }}</text>
</view>
</view>
<view class="tui-flex-box">
<view class="tui-flex-botton-view">
<tui-button margin="0 20rpx 0 0" height="72rpx" :size="28" shape="circle" @click="endTrain">确定退出
</tui-button>
</view>
<view class="tui-flex-botton-view">
<tui-button margin="0 20rpx 0 0" height="72rpx" :size="28" shape="circle" @click="hideModal"
plain>取消
</tui-button>
</view>
</view>
</view>
</tui-modal>
<!-- 悬浮按钮 -->
<tn-fab :btnList="fabBtnList" left="auto" :right="40" :bottom="180" :width="88" :height="88" :iconSize="45"
:zIndex="998" backgroundColor="fab-bg-color" fontColor="#aaa" icon="up" animationType="up" :showMask="false"
:customBtn="true" @click="clickFabItem">
</tn-fab>
<!-- 纠错反馈弹窗 -->
<tn-popup v-model="showCorrection" length="50%" mode="bottom" backgroundColor="#fff" :zIndex="999"
:borderRadius="23" :closeBtn="true" :maskCloseable="false">
<view class="popup-content" :class="{'popup-content--center': mode === 'center'}">
<view class="tn-border-solid-bottom margin-top padding-bottom text-center text-bold"
style="font-size: 30rpx;">
纠错反馈
</view>
<view class="padding">
<tn-checkbox-group @change="correctionTypeChange" activeColor="#1A73E8" :size="28">
<tn-checkbox :labelSize="28" v-model="item.checked" v-for="(item, index) in correctionTypeslist"
:key="index" :name="item.name">{{ item.name }}
</tn-checkbox>
</tn-checkbox-group>
</view>
<view style="padding: 0rpx 20rpx;">
<textarea v-model="correctionRemark" :maxlength="500" placeholder="其他错误,请描述您遇到的问题"
style="background-color: #f3f3f3; padding: 20rpx; width: 100%; height: 150rpx; font-size: 28rpx;">
2025-07-22 18:31:50 +08:00
</textarea>
2025-07-30 19:58:32 +08:00
</view>
<view class="btn-confirm">
<tui-button type="primary" shape="circle" @click="submitCorrection" width="600rpx" height="70rpx"
:size="26" margin="0 auto">提交
</tui-button>
</view>
</view>
</tn-popup>
</view>
2025-07-22 18:31:50 +08:00
</template>
<script>
2025-07-30 19:58:32 +08:00
import correctionApi from "@/common/api/correction.js"
import questionApi from "@/common/api/question.js"
export default {
name: "kz-question",
props: {
/**
* 模式
* EXAM考试模式
* VIEW背题模式
* TRAINING练习模式
*/
mode: {
type: String,
default: 'EXAM'
},
/**
* 页面来源
* PAPER试卷考试
* WRONG错题
* COLLECT收藏
*/
pageType: {
type: String,
default: 'PAPER'
},
// 试卷标题
title: {
type: String,
default: '标题'
},
// 试题集
questions: {
type: Array,
default: () => []
},
// 试题集总数(不传默认获取试题集长度)
questionCount: {
type: Number,
default: 0
},
// 试题集每页条数
pageCount: {
type: Number,
default: 20
},
// 试题集当前页
currentPage: {
type: Number,
default: 1
},
// 考试时间(倒计时)
limit_time: {
type: Number,
default: 0
},
// 考试配置
configs: {
type: Object,
default: () => {}
},
// 允许收藏试题
canCollect: {
type: Boolean,
default: true
},
// 允许删除错题
canDeleteWrong: {
type: Boolean,
default: false
},
// 看题/练题的模式normal=普通模式memory=记忆模式random=随机查询
viewMode: {
type: String,
default: 'normal'
},
/**
* 试卷选题模式
* RANDOM随机模式
* FIX固定模式
*/
paperMode: {
type: String,
default: 'RANDOM'
},
// 防切屏
isPreventSwitchScreen: {
type: Boolean,
default: false
},
// 切屏限制次数
switchScreenCount: {
type: Number,
default: 0
}
},
data() {
return {
// swiper当前下标
swiperIndex: 1,
// 总题数
total: 0,
// 试题集合
list: [],
// 题目面板
showNumberPanel: false,
// 防止交卷按钮点击多次
buttonClicked: true,
// 显示倒计时
showCountDown: false,
// 显示试题答案
showAnswer: false,
// 显示试题分数
showQuestionScore: false,
// 显示正确选择
showRightChoose: false,
// 显示错误选择
showErrorChoose: false,
// 显示结束练习对话框
showEndTrainDialog: false,
// 显示删除错题对话框
showDeleteDialog: false,
// 错题删除类型
wrongDeleteType: 'single',
// 答题开始时间
startTime: 0,
// 即将删除的错题ID
wrongDelId: 0,
// 练习结果
trainResult: {
right: 0,
error: 0,
unchecked: 0,
rightIds: [],
errorIds: []
},
// 记忆模式相关数据
memoryData: {},
// 加载试题次数(以此来判断是否是第一次进入)
loadQuestionCount: 0,
// 延迟加载已加载页码
loadQuestionPage: [1],
// 悬浮按钮列表
fabBtnList: [{
text: '纠错反馈',
bgColor: '#fff',
textColor: '#aaa',
iconColor: '#aaa',
icon: 'edit-form',
iconSize: 45
},
{
text: '清空错题',
bgColor: '#fff',
textColor: '#aaa',
iconColor: '#aaa',
icon: 'clear',
iconSize: 45
}
],
// 纠错反馈弹窗
showCorrection: false,
correctionTypeslist: [],
checkCorrectionTypeslist: [],
correctionRemark: ''
};
},
watch: {
// 加载试题时
questions: function() {
let questionCount = this.questionCount ? this.questionCount : this.questions.length
this.total = questionCount < this.questions.length ? this.questions.length : questionCount
this.list = [...this.questions]
// 材料题处理
this.showFullMaterialTitle(0)
// 填空题处理
this.splitFillTitle(0)
// 初始化模式配置
this.initMode()
// 记忆模式 - 跳转上次题标
this.jumpMemoryQuestion()
}
},
computed: {
// 试题类型
kindText() {
return function() {
return this.list[this.swiperIndex - 1] ? this.list[this.swiperIndex - 1].kind_text : '未知'
}
},
// 试题标题
questionTitle() {
return function(index, item, field = 'title') {
let html = item[field]
// return this.truncatedText(html)
html = this.utils.formatRichText(html)
html += this.getQuestionTitleScore(index, item)
if (field == 'material_title') {
// console.log('material_title show_full', item.show_full)
if (this.list[index] && !this.list[index].show_full) {
// if (!item.show_full) {
// if (!show_full) {
html = this.truncatedText(html)
// console.log('material_title', html)
}
}
return html
}
},
// 试题解析
questionExplain() {
return function(index, item) {
return this.utils.formatRichText(item.explain)
}
},
// 获取试题分数
getQuestionTitleScore() {
return function(index, item) {
if (this.showQuestionScore) {
return '(' + item.score + '分)'
// return '(' + this.getSingleScore(item.kind, item.difficulty, item) + '分)'
}
return ''
}
},
// 截取文本
truncatedText() {
return function(text, maxLength = 100) {
console.log('lllllllllll', text)
if (text.length > maxLength) {
return text.slice(0, maxLength) + '...';
}
return text;
}
},
// 设置填空题答案
setFillInputValue() {
return (titleIndex) => {
let index = this.swiperIndex - 1
if (this.mode == 'VIEW') {
if (this.list[index].answer) {
if (this.list[index].answer[titleIndex].answers != undefined) {
return this.list[index].answer[titleIndex].answers[0]
}
}
} else {
if (this.list[index].user_answers) {
return this.list[index].user_answers[titleIndex]
}
}
return ''
}
},
// 设置简答题答案
setShortInputValue() {
return () => {
let index = this.swiperIndex - 1
if (this.mode == 'VIEW') {
if (this.list[index].answer) {
if (this.list[index].answer.answer != undefined) {
return this.list[index].answer.answer
}
}
} else {
if (this.list[index].user_answers) {
return this.list[index].user_answers
}
}
return ''
}
},
// 设置底部栏样式
getBottomBarClass() {
return () => {
// console.log('getBottomBarClass', this.mode)
let classes = []
if (this.mode == 'EXAM') {
if (this.canDeleteWrong) {
classes = ['col-5']
} else {
classes = ['col-4']
}
} else if (this.mode == 'TRAINING') {
if (this.canDeleteWrong) {
classes = ['col-5']
} else {
classes = ['col-4']
}
} else if (this.mode == 'VIEW') {
if (this.canDeleteWrong) {
classes = ['col-4']
} else {
classes = ['col-3']
}
} else {
classes = ['col-3']
}
return classes
}
},
// 设置答题卡样式
getNumberPanelClass() {
return (index) => {
if (this.swiperIndex - 1 == index) {
return ['selected']
}
let classes = []
let question = this.list[index]
// console.log('getNumberPanelClass question', question)
if (question && question.kind) {
switch (question.kind) {
case 'JUDGE':
case 'SINGLE':
case 'MULTI':
if (question.is_right) {
if (question.is_right == 'right') {
return ['tibiao-right']
} else {
return ['tibiao-error']
}
}
if (question.check) {
return ['tibiao-right']
}
break
case 'FILL':
case 'SHORT':
if (question.user_answers) {
if (question.is_right) {
if (question.is_right == 'right') {
return ['tibiao-right']
} else {
return ['tibiao-error']
}
}
return ['tibiao-right']
}
break
default:
return classes
}
}
return classes
}
},
// 获取错题来源文本
getSourceText() {
return (source) => {
if (source == 'PAPER') {
return '试卷考试'
} else if (source == 'ROOM') {
return '考场考试'
} else if (source == 'TRAINING') {
return '练题模式'
}
}
}
},
methods: {
duoXuanSubmit(index) {
// 获取当前多选题
let questionIndex = this.swiperIndex - 1
let questionItem = this.list[questionIndex]
// 检查是否有选择
if (!questionItem.check) {
uni.showToast({
title: '请先选择答案',
icon: 'none',
duration: 1500
})
return
}
// 显示答案和解析
questionItem.show_answer = true
// 计算答题正确性
let isRight = true
let answer_arr = questionItem.answer.split(',')
let check_arr = questionItem.check.indexOf(',') > 0 ? questionItem.check.split(',') : [questionItem.check]
// 检查选择的答案是否完全正确
if (check_arr.length !== answer_arr.length) {
isRight = false
} else {
for (const check_answer of check_arr) {
if (!answer_arr.includes(check_answer)) {
isRight = false
break
}
}
}
// 设置答题结果
if (isRight) {
questionItem.is_right = 'right'
} else {
questionItem.is_right = 'error'
// 练题模式 - 记录错题
if (this.mode == 'TRAINING') {
questionApi.addQuestionWrong(this, {
question_id: questionItem.id,
source: 'TRAINING',
user_answer: questionItem.check
})
}
}
// 更新选项样式以显示正确答案
questionItem.options_json.forEach((optionItem, optionIndex) => {
questionItem.options_json[optionIndex].classes = questionItem.answer.indexOf(optionItem.key) > -1 ? 'active_true' : (optionItem.click_index ? 'active' : '')
})
// 更新题目数据
this.list[questionIndex] = questionItem
// 强制更新视图
this.$forceUpdate()
},
// 初始化模式配置
initMode(reset = false) {
switch (this.mode) {
// 考试模式
case 'EXAM':
this.showCountDown = true
this.showAnswer = false
this.showQuestionScore = true
this.showRightChoose = false
this.showErrorChoose = false
this.startTime = this.utils.timestamp()
break
// 练习模式
case 'TRAINING':
this.showCountDown = false
this.showAnswer = false
this.showQuestionScore = false
this.showRightChoose = false
this.showErrorChoose = true
break
// 背题模式
case 'VIEW':
this.showCountDown = false
this.showAnswer = true
this.showQuestionScore = false
this.showRightChoose = true
this.showErrorChoose = false
// 显示试题正确的选项
this.list.forEach((item, index) => {
if (item.options_json) {
// console.log('item.options_json', item.options_json)
Array.from(item.options_json).forEach((optionItem, optionIndex) => {
item.options_json[optionIndex].click_index = true
item.options_json[optionIndex].classes = item.answer.indexOf(optionItem
.key) > -1 ? 'active_true' : ''
})
this.list[index] = item
}
})
break
}
},
// 计算试题积分
getSingleScore(kind, difficulty, question) {
if (this.paperde == 'FIX') {
return question.score
}
const configs = this.configs[kind.toLowerCase()];
if (configs && configs['use_difficulty']) {
return configs['difficulty'][difficulty.toLowerCase()]['score'];
}
return configs['score'];
},
// 延迟加载试题
loadQuestion() {
if (this.mode != 'TRAINING' && this.mode != 'VIEW') {
return
}
if (this.viewMode != 'normal') {
return
}
// 取下一页数据
let page = Math.round(this.swiperIndex / this.pageCount) + 1
if (!this.loadQuestionPage.includes(page)) {
this.loadQuestionPage.push(page)
this.$emit('loadQuestion', page)
}
},
// 滑动切题
swiperChange(e, type = '') {
// console.log('swiperChange', this.list.length, this.swiperIndex, e.detail.current)
// 当前题标
this.swiperIndex = e.detail.current + 1
// 材料题处理
this.showFullMaterialTitle(e.detail.current)
// 填空题处理
this.splitFillTitle(e.detail.current)
// 加载题目
this.loadQuestion()
// 记忆模式
this.memoryQuestion()
},
// 上一题
prev() {
if (this.swiperIndex > 1) {
this.swiperIndex--
}
},
// 下一题
next() {
// console.log('next', this.list.length, this.swiperIndex)
if (this.list.length - this.swiperIndex >= 1) {
// 填空题处理
this.splitFillTitle(this.swiperIndex)
this.swiperIndex++
} else {
let title = '没有更多题了~'
if (this.mode == 'EXAM') {
title = '可以交卷了~'
}
uni.showToast({
title: title,
icon: 'none',
duration: 1500
})
}
},
// 选择
chooseItem(questionIndex, optionIndex, kind) {
// 背题模式不让选
if (this.mode == 'VIEW') {
return
}
let questionItem = this.list[questionIndex]
switch (kind) {
// 多选题
case 'MULTI':
questionItem.options_json[optionIndex].click_index = !questionItem.options_json[optionIndex]
.click_index;
//多选 确认按钮
let arr = []
questionItem.options_json.forEach((item, index) => {
if (item.click_index == true) {
arr.push(item.key)
}
})
questionItem.check = arr.join(',')
questionItem.selected = true
break
// 单选/判断
default:
questionItem.options_json.forEach((item, index) => {
questionItem.options_json[index].click_index = false
questionItem.options_json[index].classes = ''
})
questionItem.options_json[optionIndex].click_index = true
questionItem.check = questionItem.options_json[optionIndex].key
questionItem.selected = true
break
}
questionItem.options_json[optionIndex].classes = this.optionChooseClass(questionIndex, optionIndex,
questionItem, questionItem.options_json[optionIndex])
this.list[questionIndex] = questionItem
// #ifdef H5
this.$forceUpdate()
// #endif
// #ifdef APP
this.$forceUpdate()
// #endif
},
// 选项选择样式
optionChooseClass(questionIndex, optionIndex, questionItem, optionItem) {
if (this.showRightChoose) {
let classNames = ''
if ((questionItem.selected && optionItem.code) || (questionItem.kind == 'MULTI' && optionItem
.click_index)) {
classNames = 'active_true'
}
if ((questionItem.kind != 'MULTI' && optionItem.click_index && !optionItem.code) || (questionItem
.kind == 'MULTI' && optionItem.click_index && !optionItem.code && questionItem.selected)) {
classNames += ' active'
}
return classNames
} else {
// 练习模式,选择后显示错误选项
if (this.showErrorChoose) {
let result = ''
switch (questionItem.kind) {
// 多选题
case 'MULTI':
// 多选题在未提交时只显示选择状态,不显示正确答案
if (questionItem.show_answer) {
// 已提交,显示正确答案样式
result = questionItem.answer.indexOf(optionItem.key) > -1 ? 'active_true' : (optionItem.click_index ? 'active' : '')
} else {
// 未提交,只显示选择状态
result = optionItem.click_index ? 'active_true' : ''
}
break
// 单选/判断
default:
// 选择后显示答案和解析
questionItem.show_answer = true
this.list[questionIndex] = questionItem
// 选择正确与否
result = optionItem.key == questionItem.answer ? 'active_true' : 'active'
break
}
// 记录练习结果多选题除外多选题在duoXuanSubmit方法中处理
if (questionItem.kind !== 'MULTI') {
if (result === 'active_true') {
this.list[questionIndex]['is_right'] = 'right'
} else {
this.list[questionIndex]['is_right'] = 'error'
if (this.mode == 'TRAINING') {
// 练题模式 - 记录错题
questionApi.addQuestionWrong(this, {
question_id: questionItem.id,
source: 'TRAINING',
user_answer: questionItem.check
})
}
}
}
return result
} else {
if (optionItem.click_index) {
return 'active_true'
}
}
}
return ''
},
// 获取未答题数量
getUncheckedCount() {
if (this.mode === 'EXAM') {
let unchecked = []
for (let i in this.list) {
let question = this.list[i]
let item = {
id: question.id,
answer: ''
}
switch (question.kind) {
case 'JUDGE':
case 'SINGLE':
case 'MULTI':
if (question.check) {
item.answer = question.check
} else {
unchecked.push({
id: question.id
})
}
break
case 'FILL':
if (question.user_answers) {
item.answer = question.user_answers
} else {
unchecked.push({
id: question.id
})
}
break
case 'SHORT':
if (question.user_answers) {
item.answer = question.user_answers
} else {
unchecked.push({
id: question.id
})
}
break
}
}
return unchecked.length
} else {
let right = 0
let error = 0
let unchecked = 0
for (let i in this.list) {
if (this.list[i].is_right) {
if (this.list[i].is_right == 'right') {
right++
} else {
error++
}
} else {
unchecked++
}
}
// this.trainResult.right = (Array.from(new Set(this.trainResult.rightIds))).length
// this.trainResult.error = (Array.from(new Set(this.trainResult.errorIds))).length
this.trainResult.right = right
this.trainResult.error = error
let count = this.total - this.trainResult.right - this.trainResult.error
return count > 0 ? count : 0;
}
},
// 左下角交卷按钮点击弹窗
submitShowModal() {
this.buttonClicked = false
let unchecked_count = this.getUncheckedCount()
let modal_title = '确认要交卷吗?'
if (unchecked_count > 0) {
modal_title = `还有${unchecked_count}道题未答,` + modal_title
}
uni.showModal({
title: '提示',
content: modal_title,
success: res => {
if (res.confirm) {
this.submit()
} else {
this.buttonClicked = true
}
}
})
},
// 倒计时结束
endOfTime() {
// 非考试模式不处理
if (this.mode != 'EXAM') {
return
}
// 为0时不处理
if (this.limit_time == 0) {
return
}
uni.showToast({
title: '考试时间到,即将自动交卷',
duration: 2500
})
this.buttonClicked = true
setTimeout(() => {
this.submit()
}, 2500)
},
// 交卷
submit() {
let data = {}
let questions = {}
let list = this.list
for (let i in list) {
let item = {}
switch (list[i].kind) {
case 'JUDGE':
case 'SINGLE':
case 'MULTI':
item.id = list[i].id
item.answer = list[i].check ? list[i].check : ''
break
case 'FILL':
item.id = list[i].id
item.answer = list[i].user_answers ? list[i].user_answers : []
break
case 'SHORT':
item.id = list[i].id
item.answer = list[i].user_answers ? list[i].user_answers : ''
break
default:
break
}
// 材料题主题ID
item.material_id = list[i].material_id ? list[i].material_id : 0
questions[i] = item
}
data.start_time = this.startTime
data.questions = questions
this.$emit('submitQuestion', data)
},
// 控制题目面板显示隐藏
handleNumberPanel() {
// if (this.mode == 'TRAINING') {
// return
// }
this.showNumberPanel = !this.showNumberPanel;
},
// 题目面板跳题
async changeQuestion(e, type = '') {
// 题已加载,直接跳
if (e + 1 <= this.list.length) {
// this.swiperIndex = e + 1
this.showNumberPanel = !this.showNumberPanel
this.swiperChange({
detail: {
current: e
}
})
} else {
// 题未加载,一页页加载
let currLastPage = this.loadQuestionPage.at(-1)
let willGetPage = Math.round(e / this.pageCount) + 1
for (var page = currLastPage; page <= willGetPage; page++) {
if (this.loadQuestionPage.includes(page)) {
continue;
}
await new Promise((resolve, reject) => {
this.$emit('loadQuestion', page, () => {
this.loadQuestionPage.push(page)
if (page >= willGetPage) {
setTimeout(() => {
this.changeQuestion(e, 'digui')
}, 1000)
}
resolve()
})
})
}
}
},
// 删除错题
wrongDel(showDialog = true) {
// 弹窗提示
if (showDialog) {
this.showDeleteDialog = true
this.wrongDeleteType = 'single'
return
}
this.hideModal()
// 执行删除
this.http('question/wrongDelete', {
question_id: this.list[this.swiperIndex - 1].id
}, 'get').then(res => {
uni.showToast({
icon: 'none',
title: res.msg
})
if (res.code == 1) {
setTimeout(() => {
this.$emit('refresh')
}, 1200)
}
});
},
// 清空错题
wrongClear(showDialog = true) {
// 弹窗提示
if (showDialog) {
this.showDeleteDialog = true
this.wrongDeleteType = 'all'
return
}
this.hideModal()
// 执行清空
this.http('question/wrongClear', {}).then(res => {
uni.showToast({
icon: 'none',
title: res.msg
})
if (res.code == 1) {
setTimeout(() => {
this.$emit('refresh')
}, 1200)
}
});
},
// 确认删除错题
confirmDelWrong() {
if (this.wrongDeleteType == 'single') {
this.wrongDel(false)
} else if (this.wrongDeleteType == 'all') {
this.wrongClear(false)
}
},
// 隐藏弹窗
hideModal(e) {
this.showDeleteDialog = false
this.showEndTrainDialog = false
this.buttonClicked = true
},
// 添加收藏
collectAdd() {
let id = this.list[this.swiperIndex - 1].id
let index = this.swiperIndex - 1
this.http('question/collectAdd', {
question_id: id
}, 'get').then(res => {
uni.showToast({
icon: 'none',
title: res.msg
})
if (res.code == 1) {
this.list[index]['collected'] = true
this.$forceUpdate()
}
});
},
// 取消收藏
collectDel() {
let id = this.list[this.swiperIndex - 1].id
let index = this.swiperIndex - 1
this.http('question/collectCancel', {
question_id: id
}, 'get').then(res => {
uni.showToast({
icon: 'none',
title: res.msg
})
if (res.code == 1) {
this.list[index]['collected'] = false
this.$forceUpdate()
this.$emit('refresh')
}
});
},
// 结束练习弹窗
endTrainShowModal() {
this.buttonClicked = false
this.trainResult.unchecked = this.getUncheckedCount()
this.showEndTrainDialog = true
},
// 结束练习
endTrain() {
this.utils.goback()
},
// 记忆模式 - 缓存key
getMemoryCacheKey(cate_id) {
return this.mode.toLowerCase() + '-' + cate_id
},
// 记忆当前题目信息
memoryQuestion() {
if (this.viewMode != 'memory') {
return
}
let question = this.list[0]
let data = {
memory_cate_id: question.cate_id,
memory_question_id: question.id,
memory_index: this.swiperIndex
}
this.memoryData = data
// 缓存当前题目信息
let cache_key = this.getMemoryCacheKey(question.cate_id) //this.mode.toLowerCase() + '-' + question.cate_id
this.utils.setData(cache_key, data)
},
// 记忆模式 - 跳转上次题标
jumpMemoryQuestion() {
// 记忆模式且是第一次加载试题
if (this.viewMode == 'memory' && this.loadQuestionCount == 0) {
let cache_key = this.getMemoryCacheKey(this.questions[0].cate_id)
this.memoryData = this.utils.getData(cache_key)
if (this.memoryData) {
// 跳转到上次题标位置
this.swiperIndex = this.memoryData.memory_index
// 填空题处理
this.splitFillTitle(this.swiperIndex - 1)
}
}
},
// 图片预览
previewImage(image) {
uni.previewImage({
current: 0,
urls: [image]
})
},
// 填空题 - 处理题目数据
splitFillTitle(index) {
if (this.list[index] && this.list[index].kind == 'FILL') {
if (!this.list[index].title_data) {
this.list[index]['title_data'] = this.list[index].title.split('______')
}
// 未回答标识
if (!this.list[index].is_answered) {
this.list[index]['is_answered'] = false
}
}
},
// 填空题 - 文本框修改
changeFillInput(e, titleIndex, swiperIndex) {
if (this.mode == 'VIEW') {
return
}
if (!this.list[swiperIndex - 1]['user_answers']) {
this.list[swiperIndex - 1]['user_answers'] = []
}
this.list[swiperIndex - 1].user_answers[titleIndex] = e.target.value
},
// 填空题 - 练习模式 - 确认答案
confirmFillAnswer() {
let index = this.swiperIndex - 1
if (!this.list[index].user_answers || this.list[index].user_answers.length != this.list[index].answer
.length) {
this.utils.toast('请在文本框填写完整的答案')
return
}
let right_count = 0
for (var i = 0; i < this.list[index].user_answers.length; i++) {
let user_answer = this.list[index].user_answers[i]
if (user_answer === '') {
this.utils.toast('第' + (i + 1) + '个文本框未填写答案')
return
}
let is_right = false
for (var j = 0; j < this.list[index].answer[i].answers.length; j++) {
let right_answer = this.list[index].answer[i].answers[j]
if (user_answer === right_answer) {
is_right = true
break
}
}
// 填空题对错 - 文本框样式
this.list[index].answer[i]['class'] = is_right ? 'fill-input-right' : 'fill-input-error'
if (is_right) {
right_count++
}
}
// 练习模式,选择后显示错误选项
if (this.showErrorChoose) {
// 记录练题情况
if (right_count == this.list[index].user_answers.length) {
// this.trainResult.right++
this.list[index]['is_right'] = 'right'
} else {
// this.trainResult.error++
this.list[index]['is_right'] = 'error'
}
}
if (this.mode == 'TRAINING') {
console.log('right_count', right_count, this.list[index].answer.length, this.list[index].user_answers)
// 练题模式 - 记录错题
if (right_count != this.list[index].answer.length) {
questionApi.addQuestionWrong(this, {
question_id: this.list[index].id,
source: 'TRAINING',
user_answer: this.list[index].user_answers
})
}
}
// 显示答案
this.list[index]['show_answer'] = true
// 标记为已回答
this.list[index]['is_answered'] = true
this.$forceUpdate()
},
// 简答题 - 文本框修改
changeShortInput(e, swiperIndex) {
if (this.mode == 'VIEW') {
return
}
if (!this.list[swiperIndex - 1]['user_answers']) {
this.list[swiperIndex - 1]['user_answers'] = ''
}
this.list[swiperIndex - 1].user_answers = e.target.value
},
// 简答题 - 练习模式 - 确认答案
confirmShortAnswer() {
let index = this.swiperIndex - 1
if (!this.list[index].user_answers) {
this.utils.toast('请在文本框填写完整的答案')
return
}
let right_count = 0
// let right_indexes = []
for (var i = 0; i < this.list[index].answer.config.length; i++) {
this.list[index].answer.config[i]['class'] = ''
if (this.list[index].user_answers.indexOf(this.list[index].answer.config[i].answer) > -1) {
right_count++
this.list[index].answer.config[i]['class'] = 'short-input-right'
// right_indexes.push(i)
}
}
if (this.mode == 'TRAINING') {
// 练题模式 - 记录错题
if (right_count != this.list[index].answer.length) {
questionApi.addQuestionWrong(this, {
question_id: this.list[index].id,
source: 'TRAINING',
user_answer: this.list[index].user_answers
})
}
}
// 练习模式,选择后显示错误选项
if (this.showErrorChoose) {
// 记录练题情况
if (right_count > 0) {
// this.trainResult.right++
this.list[index]['is_right'] = 'right'
} else {
// this.trainResult.error++
this.list[index]['is_right'] = 'error'
}
}
// 显示答案
this.list[index]['show_answer'] = true
// 标记为已回答
this.list[index]['is_answered'] = true
this.$forceUpdate()
},
// 材料题 - 处理材料题目数据
showFullMaterialTitle(index, item, status = false) {
if (item && item.material_title != undefined) { // item.kind == 'MATERIAL'
// 未回答标识
if (!item.show_full) {
item['show_full'] = false
if (this.list[index]) {
this.list[index]['show_full'] = false
}
}
item.show_full = status
if (this.list[index]) {
this.list[index].show_full = status
}
// console.log('showFullMaterialTitle', item.show_full)
this.$forceUpdate()
}
},
// 点击悬浮按钮的内容
clickFabItem(e) {
// console.log('clickFabItem', e)
// 错题反馈
if (e.index === 0) {
correctionApi.getCorrectionTypes(this, {}).then(res => {
this.correctionTypeslist = res.data.types
this.showCorrection = true
})
} else if (e.index === 1 && this.canDeleteWrong) {
// 清空错题
this.wrongClear()
}
},
// 纠错反馈类型选择
correctionTypeChange(e) {
// console.log('correctionTypeChange', e)
this.checkCorrectionTypeslist = e
},
// 提交纠错反馈
submitCorrection() {
if (this.checkCorrectionTypeslist.length == 0) {
this.utils.toast('请选择纠错类型')
return
}
let data = {
question_id: this.list[this.swiperIndex - 1].id,
type_names: this.checkCorrectionTypeslist,
remark: this.correctionRemark
}
correctionApi.submitCorrection(this, data).then(res => {
if (res.code) {
this.checkCorrectionTypeslist = []
this.correctionRemark = ''
this.utils.toast(res.msg)
}
this.showCorrection = false
})
}
}
}
2025-07-22 18:31:50 +08:00
</script>
<style lang="less">
2025-07-30 19:58:32 +08:00
page {
height: 100%;
}
.questions {
height: 100%;
position: relative;
.test-header {
width: 100%;
padding: 0 30rpx;
display: flex;
align-items: center;
justify-content: center;
height: 80rpx;
background: #fff;
position: relative;
font-size: 34rpx;
}
.card-shadow {
margin-top: 20rpx;
.topic-title {
font-size: 34rpx;
padding: 30rpx 20rpx;
background: #fff;
border-bottom: 1px solid #f0f0f0;
display: flex;
align-items: center;
justify-content: space-between;
.topic-title_left {
display: flex;
align-items: center;
.text-kind {
font-size: 24rpx;
color: #fff;
background: linear-gradient(135deg, #7892fd, #1A73E8);
padding: 8rpx 10rpx;
border-radius: 15rpx 15rpx 15rpx 0;
margin-right: 20rpx;
}
}
.title-index {
color: #1A73E8;
}
}
.questions-cont {
height: 100vh;
display: flex;
flex-wrap: nowrap;
transition: all 0.5s;
.swiper-item {
width: 100vw;
min-width: 100vw;
max-width: 100vw;
height: 100%;
overflow: auto;
.test-main {
padding: 0 20rpx;
// margin: 40rpx 30rpx;
// margin-bottom: 40rpx;
// border-radius: 8px;
background: #fff;
.test-title {
color: #333;
padding: 20rpx 0;
.text-kind {
font-size: 24rpx;
color: #fff;
background: linear-gradient(135deg, #7892fd, #1A73E8);
padding: 8rpx 10rpx;
border-radius: 15rpx 15rpx 15rpx 0;
}
.test-favor {
position: relative;
color: #aaa;
float: right;
}
.test-favor-fill {
background: #fff;
color: #fbbd08;
float: right;
}
}
.test-title-fill {
width: 100%;
word-wrap: break-word;
word-break: break-all;
display: flex;
flex-wrap: wrap;
}
.test-title-fill-item {
margin: 5px;
}
.test-cont {
display: flex;
flex-direction: column;
padding-bottom: 20rpx;
color: #333333;
.test-cont-item {
padding: 20rpx;
display: flex;
background-color: #f6f6f6;
margin-bottom: 20rpx;
border-radius: 10rpx;
align-items: center;
justify-content: center;
position: relative;
&::after {
background: #333;
content: "";
width: 100%;
height: 100%;
position: absolute;
opacity: 0;
transition: all 0.35s;
}
&:active::after {
opacity: .3;
width: 0%;
transition: 0s;
}
.cont {
flex: 1;
height: 100%;
padding-left: 20rpx;
display: flex;
align-items: center;
justify-content: space-between;
.cont-text {
display: flex;
align-items: center;
flex-wrap: wrap;
flex: 1;
height: 100%;
font-p: 32rpx;
.image {
width: 50%;
height: auto;
margin-right: 20rpx;
}
}
.cont-icon {
width: 40rpx;
margin-left: 20rpx;
color: #1A73E8;
font-size: 36rpx;
}
}
.key {
width: 50rpx;
height: 50rpx;
background-color: #d0d0d0;
border-radius: 50%;
color: #FFFFFF;
display: flex;
align-items: center;
justify-content: center;
}
&.active_true {
background-color: rgba(86, 119, 252, 0.2);
.key {
background-color: #1A73E8;
}
.cont {
.cont-icon {
font-weight: bold;
color: #1A73E8;
}
}
}
&.active {
background-color: rgba(255, 68, 0, 0.2);
.key {
background-color: #ff4400;
}
.cont {
.cont-icon {
font-weight: bold;
color: #ff4400;
}
}
}
}
}
}
.test-describe {
// padding: 0 20rpx;
padding-bottom: 10px;
background-color: #fff;
.describe-title {
height: 48px;
line-height: 48px;
display: flex;
text {
color: #666;
font-size: 12px;
}
image {
width: 14px;
height: 14px;
margin-top: 17px;
margin-left: 3px;
}
}
.describe-cont {
// background: #f5f5f5;
// padding: 12rpx;
display: flex;
flex-direction: column;
font-size: 34rpx;
margin-top: 8rpx;
line-height: 40rpx;
// & > view {
// color: #666;
// font-size: 30rpx;
// background-color: #fff;
// text-indent: 15px;
// margin-bottom: 2rpx;
// // margin-top: 2rpx;
// // border-radius: 10rpx;
// // &:nth-child(3) {
// // font-size: 12px;
// // line-height: 20px;
// // }
// }
}
}
}
}
}
.fixed-bottom {
.tibiao {
background: #fff;
width: 100%;
height: 50vh;
padding: 35rpx !important;
padding-bottom: calc(constant(safe-area-inset-bottom) + 35rpx);
padding-bottom: calc(constant(safe-area-inset-bottom) + 35rpx);
border-radius: 20rpx 20rpx 0 0;
.tibiao-scroll {
height: 100%;
.tibiao-scroll-list {
display: flex;
align-items: center;
flex-wrap: wrap;
.tibiao-item {
height: 100rpx;
width: 100rpx;
border-radius: 50%;
margin-bottom: 30rpx;
border: 1rpx solid #d0d0d0;
display: flex;
align-items: center;
justify-content: center;
margin-right: 45rpx;
&:nth-child(5n) {
margin-right: 0;
}
&.tibiao-right {
background: #4caf50;
color: #fff;
}
&.tibiao-error {
background: #ff4400;
color: #fff;
}
&.selected {
background: #1A73E8;
color: #fff;
}
}
}
}
}
}
}
.cu-list {
width: 100%;
height: 100rpx;
position: fixed;
left: 0;
bottom: 0;
text-align: center;
border-radius: 8px;
}
.cu-list.grid>.cu-item {
padding-top: 5px;
}
.cu-list image {
width: 25px;
height: 25px;
display: inline-block;
margin: 0 auto;
}
// 弹窗
.result {
width: 100%;
height: 100vh;
background: #fff;
padding-top: 10px;
}
.progress_box {
position: relative;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
}
.progress_bg {
position: absolute;
width: 220px;
height: 220px;
}
.progress_bar {
width: 220px;
height: 220px;
}
.progress_txt {
position: absolute;
font-size: 28upx;
color: #999999;
}
.progress_info {
font-size: 36upx;
padding-left: 16upx;
letter-spacing: 2upx;
font-size: 52upx;
color: #333333;
}
.progress_dot {
width: 16upx;
height: 16upx;
border-radius: 50%;
background-color: #fb9126;
}
.table {
width: 90%;
margin: 0 auto;
overflow: hidden;
}
.describe-item {
// height: 70rpx;
padding-top: 20rpx;
text-indent: 30rpx;
}
.flex_1 {
text-align: left;
}
.flex_2 {
text-align: right;
}
.red {
color: #f00;
}
.error {
display: inline-block;
height: 30px;
line-height: 30px;
border-radius: 5px;
padding: 0 10px;
margin-left: 15px;
}
/*收藏 */
.tui-fabulous__box {
position: relative;
}
.tui-fabulous {
position: absolute;
left: 60px;
top: 0;
visibility: hidden;
}
.tui-fabulous__active {
animation: fabulousAni 2s linear;
}
@keyframes fabulousAni {
0% {
transform: translateY(0) scale(0.8);
visibility: visible;
opacity: 1;
}
15% {
transform: translateY(-40px) scale(1.25);
opacity: 1;
}
100% {
transform: translateY(-240px) scale(0.5);
visibility: hidden;
opacity: 0;
}
}
/* 红心收藏效果 */
.cu-list.grid>.cu-item text {
margin-top: 0;
}
.cu-list.grid>.cu-item:after {
border: 0px;
}
.fix-bottom {
bottom: calc(constant(safe-area-inset-bottom) + 30rpx);
bottom: calc(env(safe-area-inset-bottom) + 30rpx);
width: 95%;
position: fixed;
margin: 0 auto;
left: 0;
right: 0;
}
.tui-prompt-title {
padding-bottom: 20rpx;
font-size: 34rpx;
font-weight: bold;
text-align: center;
}
.tui-flex-box {
width: 100%;
display: flex;
align-items: center;
flex-wrap: wrap;
margin-top: 40rpx;
}
.tui-flex-botton-view {
width: 45%;
margin: 0 auto;
}
@keyframes anime {
0% {
background-size: 0% 0%;
}
100% {
background-position: 100% 100%;
}
}
/** 填空题输入框 */
.fill-input {
border: 0px;
border-bottom: 2px solid #1A73E8;
width: 200rpx;
margin: 0 10rpx;
}
.fill-input-right {
border-bottom: 2px solid #4caf50;
}
.fill-input-error {
border-bottom: 2px solid #ff4400;
}
.btn-confirm {
margin-top: 60rpx;
margin-bottom: 20rpx;
}
/** 简答题输入框 */
.short-input {
border: 0px;
border-bottom: 2px solid #1A73E8;
width: 100%;
min-height: 500rpx;
margin: 10rpx;
}
.short-input-right {
color: #4caf50;
}
.short-input-error {
color: #ff4400;
}
.material-title {
background-color: #fff;
padding: 10px;
}
.material-title-tip {
font-size: 36rpx;
font-weight: bold;
}
.title-video {
width: 100%;
min-height: 200px;
pointer-events: auto !important;
}
.explain-video-view {
width: 100%;
min-height: 240px;
background-color: #fff;
padding: 20px 0px;
}
.explain-video {
width: 100%;
min-height: 200px;
pointer-events: auto !important;
}
.fab-bg-color {
background-color: #e6e6e6;
}
textarea::-webkit-input-placeholder {
font-size: 24rpx;
}
textarea:-moz-placeholder {
font-size: 24rpx;
}
textarea::-moz-placeholder {
font-size: 24rpx;
}
textarea::-ms-input-placeholder {
font-size: 24rpx;
}
.text-right-answer {
font-size: 25rpx;
color: #fff;
background: linear-gradient(135deg, #7892fd, #1A73E8);
padding: 8rpx 0rpx;
border-radius: 15rpx 15rpx 15rpx 0;
margin-left: 20rpx;
width: 168rpx;
height: 50rpx;
line-height: 38rpx;
display: inline-block;
}
.text-right-answer-val {
font-size: 28rpx;
color: #1A73E8;
padding: 8rpx 0rpx;
border-radius: 15rpx 15rpx 15rpx 0;
margin-left: 0;
// width: 150rpx;
// height: 50rpx;
line-height: 40rpx;
display: inline-block;
}
.answer-row {
display: flex;
align-items: center;
margin-bottom: 10rpx;
}
.text-indent {
text-indent: 30rpx;
}
.text-user-answer {
font-size: 24rpx;
color: #fff;
background: linear-gradient(135deg, #7892fd, #1A73E8);
padding: 8rpx 0rpx;
border-radius: 15rpx 15rpx 15rpx 0;
margin-left: 20rpx;
width: 168rpx;
// height: 50rpx;
line-height: 38rpx;
display: flex;
align-items: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text {
color: #fff;
font-size: 24rpx;
}
}
.text-right-answer-val-item {
font-size: 28rpx;
color: #1A73E8;
padding: 8rpx 0rpx;
border-radius: 15rpx 15rpx 15rpx 0;
margin-left: 0;
}
.explain-content {
background-color: #fff9e6;
margin: 10rpx 20rpx;
border-radius: 10rpx;
padding: 10rpx;
}
.explain-content-title {
font-size: 32rpx;
font-weight: bold;
margin-bottom: 20rpx;
text-indent: 30rpx;
text {
font-size: 30rpx;
}
}
.explain-content-text {
font-size: 30rpx !important;
color: #333333;
text-indent: 30rpx;
padding: 6rpx;
line-height: 42rpx;
width: 90%;
display: block;
}
.pt-0 {
padding-top: 0 !important;
}
.font-size-30 {
font-size: 30rpx;
}
</style>