| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147 |
- <template>
- <!-- 查看作答页。路由固定为 /teachingHomework/viewAnswer,不使用地址栏参数 -->
- <div class="homework_view_answer" v-if="homework">
- <!-- 顶部:返回、科目、任务信息 -->
- <div class="answer_header">
- <el-button class="back_btn" @click="goBack">
- <i class="iconfont icon_return"></i>返回
- </el-button>
- <div class="header_main">
- <div class="title_row">
- <span class="subject_badge" :style="{ background: subjectColor }">{{ homework.subjectName }}</span>
- <span class="task_title">{{ taskTitle }}</span>
- </div>
- <div class="meta_row">
- <span>布置教师:{{ homework.teacherName }}</span>
- <span>试题数量:{{ questions.length }}</span>
- </div>
- </div>
- </div>
- <!-- 主体:左侧试题序号,右侧题干/作答/解析 -->
- <div class="answer_body" v-loading="loading">
- <div class="question_nav">
- <div class="nav_title">试题列表</div>
- <div class="nav_group" v-for="group in questionGroups" :key="group.type">
- <div class="group_name">{{ group.name }}</div>
- <div class="num_grid">
- <button
- v-for="item in group.list"
- :key="item.id"
- type="button"
- class="num_btn"
- :class="numClass(item)"
- @click="selectQuestion(item.index)">
- {{ item.index + 1 }}
- </button>
- </div>
- </div>
- </div>
- <div class="question_panel" v-if="currentQuestion">
- <!-- 锚点 tabs:点击滚动到对应区块 -->
- <div class="section_tabs">
- <span
- v-for="tab in sectionTabs"
- :key="tab.key"
- class="section_tab"
- :class="{ active: activeSection === tab.key }"
- @click="scrollToSection(tab.key)">
- {{ tab.label }}
- </span>
- </div>
- <!-- 右侧内容区固定高度,内部滚动 -->
- <div class="question_scroll" ref="scrollBox" @scroll="onScroll">
- <!-- 题干 -->
- <div class="content_section" ref="sectionStem" data-section="stem">
- <div class="q_tags">
- <span class="q_no">{{ currentQuestion.index + 1 }}</span>
- <span class="q_type">{{ currentQuestion.typeName }}</span>
- <span class="q_level">{{ currentQuestion.difficulty }}</span>
- </div>
- <div class="q_stem" v-html="currentQuestion.stem"></div>
- <div v-if="currentQuestion.type === 'single' && hasOptionText" class="q_options">
- <div class="q_option" v-for="opt in currentQuestion.options" :key="opt.key">
- <span class="opt_key">{{ opt.key }}.</span>
- <span>{{ opt.text }}</span>
- </div>
- </div>
- </div>
- <!-- 我的作答(只读) -->
- <div class="content_section" ref="sectionAnswer" data-section="answer">
- <div class="block_box my_answer_box">
- <div class="dock_answer">
- <span class="dock_label">我的作答:</span>
- <span v-if="isSingle" class="dock_sub_no">(1)</span>
- <el-radio-group
- v-if="isJudge"
- class="choice_radio"
- :value="currentJudgeAnswer"
- disabled>
- <el-radio label="T">对</el-radio>
- <el-radio label="F">错</el-radio>
- </el-radio-group>
- <el-checkbox-group
- v-else-if="isSingle"
- class="choice_radio"
- :value="currentUserAnswer"
- disabled>
- <el-checkbox
- v-for="opt in currentQuestion.options"
- :key="opt.key"
- :label="opt.key">
- {{ opt.key }}
- </el-checkbox>
- </el-checkbox-group>
- <div v-else class="photo_list">
- <div
- class="photo_item"
- v-for="(img, imgIndex) in currentPhotos"
- :key="imgIndex">
- <img :src="img" alt="" @click="previewPhoto(imgIndex)">
- </div>
- <span v-if="!currentPhotos.length" class="empty_answer">暂无作答图片</span>
- </div>
- </div>
- </div>
- </div>
- <!-- 答案解析 -->
- <div class="content_section" ref="sectionAnalysis" data-section="analysis">
- <div class="block_box analysis_box">
- <div class="analysis_row">
- <span class="analysis_label">【知识点】</span>
- <div class="knowledge_tags">
- <span
- class="knowledge_tag"
- v-for="(tag, idx) in currentQuestion.knowledgePoints"
- :key="idx">
- {{ tag }}
- </span>
- </div>
- </div>
- <div class="analysis_row" v-if="hasAnalysis">
- <span class="analysis_label" >【 答 案 】</span>
- <div class="analysis_content">
- <span class="correct_answer" v-html="displayCorrectAnswer"></span>
- </div>
- </div>
- <div class="analysis_row" v-if="hasAnalysis" style="margin-top: 0;">
- <span class="analysis_label" >【 详 解 】</span>
- <div class="analysis_content">
- <div class="analysis_text" v-html="currentQuestion.analysis"></div>
- </div>
- </div>
- </div>
- </div>
- </div>
- <!-- 底部操作区固定 -->
- <div class="view_dock">
- <!-- <el-button class="ai_btn" @click="handleAiExplain">AI讲题</el-button> -->
- <div class="dock_actions">
- <el-button
- class="nav_btn"
- :disabled="currentQuestion.index === 0"
- @click="prevQuestion">
- 上一题
- </el-button>
- <el-button
- class="nav_btn"
- :disabled="isLastQuestion"
- @click="nextQuestion">
- 下一题
- </el-button>
- </div>
- </div>
- </div>
- <div v-else-if="!loading" class="empty_panel no_content_data">
- <span>暂无数据</span>
- </div>
- </div>
- <el-image-viewer
- v-if="imgVisible"
- :z-index="9999"
- :initial-index="previewIndex"
- :url-list="currentPhotos"
- :on-close="closePhotoPreview" />
- </div>
- </template>
- <script>
- import ElImageViewer from 'element-ui/packages/image/src/image-viewer';
- // 查看作答状态存 sessionStorage,刷新仍停留本页,地址栏不带参数
- const STORAGE_KEY = 'teachingHomeworkViewAnswer';
- const OPTION_KEYS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
- // 客观题(选择题/判断题)渲染为单选项,其余按主观题作答图片展示
- function isChoiceQuestion(item) {
- return Number(item.isObjective) === 1 || Number(item.isJudge) === 1;
- }
- function buildOptions(item) {
- const count = Number(item.optionsNum) || (Number(item.isJudge) === 1 ? 2 : 4);
- const options = [];
- for (let i = 0; i < count && i < OPTION_KEYS.length; i += 1) {
- options.push({ key: OPTION_KEYS.charAt(i), text: '' });
- }
- return options;
- }
- // 知识点可能是字符串数组,也可能是对象数组,统一收敛成字符串
- // 把接口答案归一化为合法选项 key 数组,兼容 "A,C"、"AC"、"A|C"、["A"] 等格式
- function normalizeChoiceAnswer(value, options) {
- const validKeys = (options || []).map(opt => opt.key);
- let keys = [];
- if (Array.isArray(value)) {
- keys = value;
- } else if (value !== null && value !== undefined && String(value).trim() !== '') {
- keys = String(value).toUpperCase().match(/[A-Z]/g) || [];
- }
- const result = [];
- keys.forEach(key => {
- const k = String(key);
- if (validKeys.indexOf(k) !== -1 && result.indexOf(k) === -1) result.push(k);
- });
- return result;
- }
- // 判断题回显:T 为对,F 为错
- function normalizeJudgeAnswer(value) {
- const text = String(value == null ? '' : value).trim();
- if (text === 'T' || text === 't' || text === '对' || text.toLowerCase() === 'true') return 'T';
- if (text === 'F' || text === 'f' || text === '错' || text.toLowerCase() === 'false') return 'F';
- return '';
- }
- function mapKnowledge(list) {
- if (!Array.isArray(list)) return [];
- return list.map(item => {
- if (item == null) return '';
- if (typeof item === 'string') return item;
- return item.knowledgeName || item.name || item.title || '';
- }).filter(Boolean);
- }
- /**
- * 接口试题数据映射为页面结构
- * type: single 客观题 / photo 主观题
- */
- function mapQuestion(item, index) {
- const judge = Number(item.isJudge) === 1;
- const choice = judge || isChoiceQuestion(item);
- const id = item.homeWorkStuQuesId || item.questionId || index;
- return {
- id,
- questionId: item.questionId,
- homeWorkStuQuesId: item.homeWorkStuQuesId,
- isJudge: judge,
- type: choice ? 'single' : 'photo',
- typeName: item.questionTypeName || (judge ? '判断题' : (choice ? '客观题' : '主观题')),
- groupName: item.questionTypeName || (judge ? '判断题' : (choice ? '客观题' : '主观题')),
- difficulty: item.difficultyName || '',
- stem: item.questionContent || '',
- options: judge ? [] : (choice ? buildOptions(item) : []),
- // 判断题取 T / F,客观题取 ABCD,主观题取作答图片地址
- userAnswer: choice
- ? (item.writeAnswer || '')
- : (Array.isArray(item.writeUrls) ? item.writeUrls : []),
- correctAnswer: item.questionAnswer || '',
- knowledgePoints: mapKnowledge(item.knowledge),
- analysis: item.questionAnalysis || '',
- submitEndTime: item.submitEndTime || '',
- };
- }
- export default {
- name: 'TeachingHomeworkViewAnswer',
- components: {
- ElImageViewer,
- },
- data() {
- return {
- homework: null,
- questions: [],
- loading: false,
- currentIndex: 0,
- activeSection: 'stem',
- sectionTabs: [
- { key: 'stem', label: '题干' },
- { key: 'answer', label: '我的作答' },
- { key: 'analysis', label: '答案解析' },
- ],
- imgVisible: false,
- previewIndex: 0,
- scrollLock: false,
- scrollTimer: null,
- // 点击 tab 滚动结束后的短暂宽限期,忽略残余 scroll 事件对高亮的覆盖
- syncSuppressUntil: 0,
- };
- },
- computed: {
- taskTitle() {
- if (!this.homework) return '';
- const name = this.homework.homeworkName || '';
- const className = this.homework.className || '';
- if (!className || name.indexOf(className) !== -1) return name;
- return `${name} ${className}`;
- },
- subjectColor() {
- const name = (this.homework && this.homework.subjectName) || '';
- return this.$global.getSubjectsName(name, null, 'color');
- },
- // 按接口返回的 questionTypeName 分组,有几种题型就显示几组
- questionGroups() {
- const groups = [];
- this.questions.forEach((item, index) => {
- const name = item.groupName || item.typeName || '其他';
- let group = groups.find(g => g.name === name);
- if (!group) {
- group = { type: name, name, list: [] };
- groups.push(group);
- }
- group.list.push({ ...item, index });
- });
- return groups;
- },
- currentQuestion() {
- const item = this.questions[this.currentIndex];
- if (!item) return null;
- return { ...item, index: this.currentIndex };
- },
- isSingle() {
- return !!(this.currentQuestion && this.currentQuestion.type === 'single');
- },
- // isJudge 为 1 时是判断题,详情只展示对 / 错
- isJudge() {
- return !!(this.currentQuestion && this.currentQuestion.isJudge);
- },
- hasOptionText() {
- const options = (this.currentQuestion && this.currentQuestion.options) || [];
- return options.some(opt => opt.text);
- },
- // 解析为 HTML,空串或 <p><br></p> 这类空标签都视为无内容;仅含公式图片也算有内容
- hasAnalysis() {
- const raw = String((this.currentQuestion && this.currentQuestion.analysis) || '');
- if (/<img[^>]+>/i.test(raw)) return true;
- const text = raw
- .replace(/<[^>]*>/g, '')
- .replace(/ /g, '')
- .trim();
- return text !== '';
- },
- isLastQuestion() {
- return this.currentIndex >= this.questions.length - 1;
- },
- currentUserAnswer() {
- if (!this.currentQuestion || !this.isSingle || this.isJudge) return [];
- return normalizeChoiceAnswer(this.currentQuestion.userAnswer, this.currentQuestion.options);
- },
- // 判断题作答回显:T 选中「对」,F 选中「错」
- currentJudgeAnswer() {
- if (!this.currentQuestion || !this.isJudge) return '';
- return normalizeJudgeAnswer(this.currentQuestion.userAnswer);
- },
- // 判断题标准答案同样把 T / F 显示为对 / 错
- displayCorrectAnswer() {
- const raw = (this.currentQuestion && this.currentQuestion.correctAnswer) || '';
- if (!this.isJudge) return raw;
- const judge = normalizeJudgeAnswer(raw);
- if (judge === 'T') return '对';
- if (judge === 'F') return '错';
- return raw;
- },
- currentPhotos() {
- if (!this.currentQuestion || this.isSingle) return [];
- const val = this.currentQuestion.userAnswer;
- return Array.isArray(val) ? val : [];
- },
- },
- created() {
- this.restoreState();
- },
- beforeDestroy() {
- clearInterval(this.scrollTimer);
- this.persistState();
- },
- methods: {
- // 进入/刷新时恢复;没有作业记录则回列表
- restoreState() {
- let cache = null;
- try {
- cache = JSON.parse(sessionStorage.getItem(STORAGE_KEY) || 'null');
- } catch (e) {
- cache = null;
- }
- if (!cache || !cache.homework) {
- this.$router.replace('/teachingHomework/list');
- return;
- }
- this.homework = cache.homework;
- this.currentIndex = Number(cache.currentIndex) || 0;
- this.activeSection = 'stem';
- this.fetchDetail();
- },
- fetchDetail() {
- const homework = this.homework || {};
- if (!homework.homeWorkStuId && !homework.homeWorkId) {
- this.questions = [];
- return;
- }
- this.loading = true;
- // 参数与作答页一致
- const params = {
- homeWorkStuId: homework.homeWorkStuId,
- homeWorkId: homework.homeWorkId,
- };
- this.$api.teachingHomework.viewHomeWorkWriteDetail(params).then(res => {
- this.applyDetail(res);
- }).catch(err => {
- const body = this.pickBody(err);
- if (body) {
- this.applyDetail(body);
- return;
- }
- this.questions = [];
- }).finally(() => {
- this.loading = false;
- });
- },
- // 公共请求把 code 为 0 的成功响应放进了 reject,这里两种都认
- pickBody(payload) {
- if (!payload) return null;
- if (payload.code === 0 || payload.code === 200) return payload;
- if (payload.data && (payload.data.code === 0 || payload.data.code === 200)) return payload.data;
- if (payload.response) return this.pickBody(payload.response);
- return null;
- },
- applyDetail(res) {
- const detail = this.pickDetail(res);
- this.mergeHomework(detail);
- this.questions = detail.questionDetails.map(mapQuestion);
- if (this.currentIndex < 0 || this.currentIndex >= this.questions.length) {
- this.currentIndex = 0;
- }
- this.activeSection = 'stem';
- this.persistState();
- this.$nextTick(() => {
- const box = this.$refs.scrollBox;
- if (box) box.scrollTop = 0;
- });
- },
- // 详情 data 为作业对象,题目在 questionDetails;兼容旧的题目数组
- pickDetail(res) {
- const data = res && res.data;
- if (Array.isArray(data)) return { questionDetails: data };
- if (data && typeof data === 'object') {
- return {
- ...data,
- questionDetails: Array.isArray(data.questionDetails) ? data.questionDetails : [],
- };
- }
- return { questionDetails: [] };
- },
- // 用详情里的作业信息补齐头部:名称、教师、科目
- mergeHomework(detail) {
- const current = this.homework || {};
- this.homework = {
- ...current,
- homeWorkId: detail.homeWorkId != null ? detail.homeWorkId : current.homeWorkId,
- homeWorkStuId: detail.homeWorkStuId != null ? detail.homeWorkStuId : current.homeWorkStuId,
- homeworkName: detail.homeWorkName || current.homeworkName || '',
- teacherName: detail.createUserName || current.teacherName || '',
- subjectName: detail.courseName || current.subjectName || '',
- courseCode: detail.courseCode != null ? detail.courseCode : current.courseCode,
- endTime: detail.submitEndTime || current.endTime || '',
- questionNum: detail.questionNumber != null ? detail.questionNumber : current.questionNum,
- };
- },
- persistState() {
- if (!this.homework) return;
- sessionStorage.setItem(STORAGE_KEY, JSON.stringify({
- homework: this.homework,
- currentIndex: this.currentIndex,
- }));
- },
- numClass(item) {
- return {
- current: item.index === this.currentIndex,
- };
- },
- selectQuestion(index) {
- clearInterval(this.scrollTimer);
- this.scrollTimer = null;
- this.scrollLock = false;
- this.currentIndex = index;
- this.activeSection = 'stem';
- this.persistState();
- this.$nextTick(() => {
- const box = this.$refs.scrollBox;
- if (box) box.scrollTop = 0;
- });
- },
- prevQuestion() {
- if (this.currentIndex <= 0) return;
- this.selectQuestion(this.currentIndex - 1);
- },
- nextQuestion() {
- if (this.currentIndex >= this.questions.length - 1) return;
- this.selectQuestion(this.currentIndex + 1);
- },
- getSections() {
- return [
- { key: 'stem', el: this.$refs.sectionStem },
- { key: 'answer', el: this.$refs.sectionAnswer },
- { key: 'analysis', el: this.$refs.sectionAnalysis },
- ];
- },
- // 点击 tab 滚动到对应区块
- scrollToSection(key) {
- const box = this.$refs.scrollBox;
- const target = this.getSections().find(item => item.key === key);
- const targetEl = target && target.el;
- if (!targetEl || !box) return;
- this.activeSection = key;
- this.scrollLock = true;
- // 用视口差值 + 当前滚动距离计算目标位置,offsetTop 受 offsetParent 影响会不准
- const distance = targetEl.getBoundingClientRect().top - box.getBoundingClientRect().top;
- // 下方区块高度不足时,目标顶部无法对齐容器顶部,最多只能滚到底部
- const maxScrollTop = box.scrollHeight - box.clientHeight;
- const targetTop = Math.max(0, Math.min(box.scrollTop + distance - 8, maxScrollTop));
- if (typeof box.scrollTo === 'function') {
- box.scrollTo({ top: targetTop, behavior: 'smooth' });
- } else {
- box.scrollTop = targetTop;
- }
- clearInterval(this.scrollTimer);
- // 平滑滚动期间锁定 onScroll 的高亮覆盖;连续两帧位置不变视为滚动结束
- let lastTop = box.scrollTop;
- let stableTicks = 0;
- this.scrollTimer = setInterval(() => {
- const nowTop = box.scrollTop;
- if (Math.abs(nowTop - lastTop) < 1) {
- stableTicks += 1;
- } else {
- stableTicks = 0;
- lastTop = nowTop;
- }
- if (stableTicks >= 2) {
- clearInterval(this.scrollTimer);
- this.scrollTimer = null;
- // 保持用户点击的 tab:下方高度不足停在底部时,按位置重算会误判到后一个区块
- this.activeSection = key;
- // 解锁后宽限 150ms,吞掉滚动停止瞬间的残余 scroll 事件
- this.syncSuppressUntil = Date.now() + 150;
- this.scrollLock = false;
- }
- }, 80);
- },
- // 滚动时同步高亮 tab
- onScroll() {
- if (this.scrollLock) return;
- if (this.syncSuppressUntil && Date.now() < this.syncSuppressUntil) return;
- this.syncActiveSection();
- },
- // 依据各区块相对滚动容器的位置计算当前高亮;滚到底部时高亮最后一个可见区块
- syncActiveSection() {
- const box = this.$refs.scrollBox;
- if (!box) return;
- const boxTop = box.getBoundingClientRect().top;
- const reachedBottom = box.scrollTop + box.clientHeight >= box.scrollHeight - 2;
- let current = 'stem';
- this.getSections().forEach(item => {
- if (!item.el) return;
- const rect = item.el.getBoundingClientRect();
- if (rect.top - boxTop <= 24) {
- current = item.key;
- }
- if (reachedBottom && rect.bottom > boxTop) {
- current = item.key;
- }
- });
- this.activeSection = current;
- },
- previewPhoto(index) {
- this.previewIndex = index;
- this.imgVisible = true;
- },
- closePhotoPreview() {
- this.imgVisible = false;
- },
- handleAiExplain() {
- this.$message.info('AI讲题待对接');
- },
- goBack() {
- this.persistState();
- this.$router.push('/teachingHomework/list');
- },
- },
- };
- </script>
- <style lang="scss" scoped>
- /* 布局、间距、字号、颜色与 answer.vue 保持一致 */
- .homework_view_answer {
- display: flex;
- flex-direction: column;
- width: 100%;
- height: 100%;
- min-width: 0;
- min-height: 0;
- box-sizing: border-box;
- overflow: hidden;
- .answer_header {
- flex-shrink: 0;
- display: flex;
- align-items: flex-start;
- gap: 16px;
- padding: 10px;
- background: #fff;
- border-radius: 10px;
- box-sizing: border-box;
- .back_btn {
- flex-shrink: 0;
- height: 36px;
- padding: 0 12px;
- background: #fff;
- border: 1px solid #DCDFE6;
- color: #666;
- :deep(span) {
- display: inline-flex;
- align-items: center;
- gap: 2px;
- }
- }
- .header_main {
- flex: 1;
- min-width: 0;
- .title_row {
- display: flex;
- align-items: center;
- gap: 10px;
- margin-bottom: 10px;
- margin-top: 6px;
- .subject_badge {
- flex-shrink: 0;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- min-width: 40px;
- height: 25px;
- padding: 0 4px;
- border-radius: 4px;
- color: #fff;
- font-size: 12px;
- line-height: 1;
- }
- .task_title {
- font-size: 16px;
- font-weight: 550;
- color: #333;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- }
- .meta_row {
- display: flex;
- flex-wrap: wrap;
- gap: 16px;
- font-size: 14px;
- color: #999;
- }
- }
- }
- .answer_body {
- flex: 1;
- min-height: 0;
- display: flex;
- gap: 10px;
- margin-top: 10px;
- overflow: hidden;
- .empty_panel {
- flex: 1;
- min-width: 0;
- height: 100%;
- background: #fff;
- border-radius: 10px;
- }
- .question_nav {
- flex-shrink: 0;
- width: 240px;
- height: 100%;
- background: #fff;
- border-radius: 10px;
- box-sizing: border-box;
- overflow-y: auto;
- .nav_title {
- font-size: 14px;
- font-weight: 550;
- color: #333;
- padding: 10px;
- border-bottom: 1px solid #EBEEF5;
- }
- .nav_group {
- padding: 10px;
- & + .nav_group {
- margin-top: 24px;
- }
- .group_name {
- font-size: 14px;
- color: #333;
- font-weight: 550;
- padding-bottom: 12px;
- }
- .num_grid {
- display: grid;
- grid-template-columns: repeat(5, 32px);
- gap: 15px;
- /* 查看作答:未选中灰框,当前题绿底白字 */
- .num_btn {
- width: 32px;
- height: 32px;
- padding: 0;
- border-radius: 4px;
- border: 1px solid #2BC644;
- background: #fff;
- color: #2BC644;
- font-size: 14px;
- cursor: pointer;
- &.current {
- background: #2BC644;
- border-color: #2BC644;
- color: #fff;
- }
- }
- }
- }
- }
- .question_panel {
- flex: 1;
- min-width: 0;
- height: 100%;
- display: flex;
- flex-direction: column;
- background: #fff;
- border-radius: 10px;
- overflow: hidden;
- .section_tabs {
- flex-shrink: 0;
- display: flex;
- align-items: center;
- gap: 20px;
- padding:16px;
- box-sizing: border-box;
- .section_tab {
- position: relative;
- height: 28px;
- line-height: 28px;
- font-size: 14px;
- color: #909399;
- cursor: pointer;
- user-select: none;
- &.active {
- color: #2E64FA;
- font-weight: 550;
- &::after {
- content: '';
- position: absolute;
- left: 0;
- right: 0;
- bottom: 0;
- height: 3px;
- background: #2E64FA;
- border-radius: 1px;
- }
- }
- }
- }
- .question_scroll {
- flex: 1;
- min-height: 0;
- overflow-y: auto;
- padding: 16px;
- box-sizing: border-box;
- .content_section {
- margin-bottom: 20px;
- &:last-child {
- margin-bottom: 0;
- }
- }
- .q_tags {
- display: flex;
- align-items: center;
- gap: 8px;
- margin-bottom: 16px;
- .q_no {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- min-width: 24px;
- height: 24px;
- padding: 0 6px;
- background: #F3F3F3;
- border-radius: 2px;
- font-weight: 550;
- font-size: 14px;
- color: #333333;
- box-sizing: border-box;
- }
- .q_type {
- font-weight: 550;
- font-size: 14px;
- color: #333333;
- }
- .q_level {
- font-weight: 400;
- font-size: 14px;
- color: #90CB75;
- margin-left: 8px;
- }
- }
- .q_stem {
- font-size: 15px;
- line-height: 1.7;
- color: #333;
- :deep(img) {
- max-width: 100%;
- }
- }
- .q_options {
- .q_option {
- display: flex;
- gap: 6px;
- margin-bottom: 10px;
- font-size: 14px;
- color: #333;
- line-height: 1.6;
- .opt_key {
- flex-shrink: 0;
- }
- }
- }
- .block_box {
- padding: 14px 16px;
- background: #F8F8F9;
- border-radius: 10px;
- border: 1px solid #DCDFE6;
- box-sizing: border-box;
- }
- .dock_answer {
- display: flex;
- align-items: center;
- gap: 16px;
- min-height: 36px;
- .dock_label,
- .dock_sub_no {
- flex-shrink: 0;
- display: inline-flex;
- align-items: center;
- height: 20px;
- line-height: 20px;
- font-size: 14px;
- color: #333;
- }
- .choice_radio {
- display: inline-flex;
- align-items: center;
- min-height: 20px;
- gap: 20px;
- :deep(.el-checkbox) {
- margin-right: 0 !important;
- height: 20px;
- display: inline-flex !important;
- align-items: center;
- cursor: default;
- }
- :deep(.el-checkbox__input) {
- display: inline-flex;
- align-items: center;
- height: 16px;
- line-height: 16px;
- cursor: default;
- }
- :deep(.el-checkbox__inner) {
- width: 16px;
- height: 16px;
- border: 1px solid #DCDFE6;
- background: #fff;
- border-radius: 2px;
- cursor: default;
- &::after {
- top: 1px;
- left: 5px;
- width: 3px;
- height: 8px;
- }
- }
- :deep(.el-checkbox__input.is-disabled .el-checkbox__inner) {
- background-color: #fff;
- border-color: #DCDFE6;
- }
- :deep(.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner) {
- background-color: #2E64FA;
- border-color: #2E64FA;
- }
- :deep(.el-checkbox__input.is-disabled + .el-checkbox__label) {
- color: #333;
- cursor: default;
- }
- :deep(.el-checkbox__label) {
- display: inline-flex;
- align-items: center;
- height: 20px;
- padding-left: 8px;
- font-size: 14px;
- color: #333;
- line-height: 20px;
- }
- :deep(.el-radio) {
- margin-right: 0 !important;
- height: 20px;
- display: inline-flex !important;
- align-items: center;
- cursor: default;
- }
- :deep(.el-radio__input) {
- display: inline-flex;
- align-items: center;
- height: 16px;
- line-height: 16px;
- cursor: default;
- }
- :deep(.el-radio__inner) {
- width: 16px;
- height: 16px;
- border: 1px solid #DCDFE6;
- background: #fff;
- cursor: default;
- }
- :deep(.el-radio__input.is-disabled .el-radio__inner) {
- background-color: #fff;
- border-color: #DCDFE6;
- }
- :deep(.el-radio__input.is-disabled.is-checked .el-radio__inner) {
- background-color: #2E64FA;
- border-color: #2E64FA;
- }
- :deep(.el-radio__input.is-disabled.is-checked .el-radio__inner::after) {
- background-color: #fff;
- }
- :deep(.el-radio__input.is-disabled + .el-radio__label),
- :deep(.el-radio__label) {
- padding-left: 8px;
- font-size: 14px;
- color: #333;
- line-height: 20px;
- cursor: default;
- }
- }
- .photo_list {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: 10px;
- min-width: 0;
- .photo_item {
- width: 64px;
- height: 64px;
- border-radius: 4px;
- overflow: hidden;
- background: #fff;
- img {
- width: 100%;
- height: 100%;
- object-fit: cover;
- display: block;
- cursor: zoom-in;
- }
- }
- .empty_answer {
- font-size: 14px;
- color: #999;
- }
- }
- }
- .analysis_box {
- .analysis_row {
- display: flex;
- align-items: flex-start;
- gap: 10px;
- & + .analysis_row {
- margin-top: 14px;
- }
- }
- .analysis_label {
- flex-shrink: 0;
- font-size: 14px;
- font-weight: 550;
- color: #333;
- line-height: 28px;
- }
- .knowledge_tags {
- display: flex;
- flex-wrap: wrap;
- gap: 8px;
- .knowledge_tag {
- display: inline-flex;
- align-items: center;
- height: 28px;
- padding: 0 10px;
- border: 1px solid #2E64FA;
- border-radius: 4px;
- color: #2E64FA;
- font-size: 13px;
- background: #fff;
- box-sizing: border-box;
- }
- }
- .analysis_content {
- flex: 1;
- min-width: 0;
- .correct_answer {
- display: inline-block;
- margin-right: 8px;
- font-size: 14px;
- font-weight: 550;
- color: #333;
- line-height: 28px;
- }
- .analysis_text {
- margin-top: 6px;
- font-size: 14px;
- line-height: 1.7;
- color: #666;
- :deep(img) {
- max-width: 100%;
- vertical-align: middle;
- }
- }
- }
- }
- }
- .view_dock {
- flex-shrink: 0;
- display: flex;
- align-items: center;
- justify-content: flex-start;
- gap: 16px;
- padding: 16px;
- background: #fff;
- box-sizing: border-box;
- .ai_btn {
- height: 36px;
- padding: 0 14px;
- border-radius: 4px;
- border: none;
- background: linear-gradient( 270deg, #6659FF 0%, #9A57FF 60.38%, #F292FF 100%);
- color: #fff;
- // &:hover,
- // &:focus {
- // background: #847BE6;
- // color: #fff;
- // opacity: 0.92;
- // }
- }
- .dock_actions {
- display: flex;
- align-items: center;
- gap: 16px;
- .nav_btn {
- height: 36px;
- padding: 0 14px;
- border-radius: 4px;
- line-height: 34px;
- color: #2E64FA;
- border-color: #2E64FA;
- background: #fff;
- margin:0;
- &.is-disabled,
- &.is-disabled:hover,
- &.is-disabled:focus {
- background: #F3F3F3;
- color: #C0C4CC;
- border: 1px solid #C0C4CC;
- }
- }
- }
- }
- }
- }
- }
- </style>
|