feat: 讲解模式新增展开收起
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
This commit is contained in:
parent
adbfc847ec
commit
08eb7248ec
@ -2,10 +2,9 @@
|
|||||||
import { computed, onActivated, onBeforeUnmount, onMounted, ref } from 'vue'
|
import { computed, onActivated, onBeforeUnmount, onMounted, ref } from 'vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
|
||||||
import hud from '#/utils/hud'
|
|
||||||
|
|
||||||
import { taskMgrService } from '#/api/service/question-bank/task-mgr'
|
import { taskMgrService } from '#/api/service/question-bank/task-mgr'
|
||||||
import PaperQuestionItem from '#/components/paper-question-item/index.vue'
|
import PaperQuestionItem from '#/components/paper-question-item/index.vue'
|
||||||
|
import hud from '#/utils/hud'
|
||||||
|
|
||||||
import ViewStudents from './components/viewStudents.vue'
|
import ViewStudents from './components/viewStudents.vue'
|
||||||
|
|
||||||
@ -89,10 +88,10 @@ onActivated(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// ======================== 倒计时 ========================
|
// ======================== 倒计时 ========================
|
||||||
type ExplainPhase = 'detail' | 'countdown' | 'explaining'
|
type ExplainPhase = 'countdown' | 'detail' | 'explaining'
|
||||||
const phase = ref<ExplainPhase>('detail')
|
const phase = ref<ExplainPhase>('detail')
|
||||||
const countdown = ref(3)
|
const countdown = ref(3)
|
||||||
let countdownTimer: ReturnType<typeof setInterval> | null = null
|
let countdownTimer: null | ReturnType<typeof setInterval> = null
|
||||||
|
|
||||||
function startCountdown() {
|
function startCountdown() {
|
||||||
document.documentElement.requestFullscreen?.().catch(() => {})
|
document.documentElement.requestFullscreen?.().catch(() => {})
|
||||||
@ -214,15 +213,23 @@ function resetZoom() {
|
|||||||
const currentIndex = ref(0)
|
const currentIndex = ref(0)
|
||||||
const answerExpanded = ref(false)
|
const answerExpanded = ref(false)
|
||||||
const explanationExpanded = ref(false)
|
const explanationExpanded = ref(false)
|
||||||
|
const answerPanelCollapsed = ref(false)
|
||||||
|
|
||||||
const currentQuestion = computed(() => {
|
const currentQuestion = computed(() => {
|
||||||
return paperDetail.value[currentIndex.value] || null
|
return paperDetail.value[currentIndex.value] || null
|
||||||
})
|
})
|
||||||
|
|
||||||
const hasAnswer = computed(() => Boolean(currentQuestion.value?.xkwTitle?.answer))
|
const hasAnswer = computed(() =>
|
||||||
|
Boolean(currentQuestion.value?.xkwTitle?.answer),
|
||||||
|
)
|
||||||
const hasExplanation = computed(() =>
|
const hasExplanation = computed(() =>
|
||||||
Boolean(currentQuestion.value?.xkwTitle?.explanation),
|
Boolean(currentQuestion.value?.xkwTitle?.explanation),
|
||||||
)
|
)
|
||||||
|
const leftPanelStyle = computed(() => {
|
||||||
|
return answerPanelCollapsed.value
|
||||||
|
? { flex: '1 1 auto' }
|
||||||
|
: { flex: `0 0 ${leftWidth.value}px` }
|
||||||
|
})
|
||||||
|
|
||||||
function getTitleKey(item: any) {
|
function getTitleKey(item: any) {
|
||||||
return (
|
return (
|
||||||
@ -243,6 +250,10 @@ function toggleExplanation() {
|
|||||||
explanationExpanded.value = !explanationExpanded.value
|
explanationExpanded.value = !explanationExpanded.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleAnswerPanel() {
|
||||||
|
answerPanelCollapsed.value = !answerPanelCollapsed.value
|
||||||
|
}
|
||||||
|
|
||||||
async function enterExplaining() {
|
async function enterExplaining() {
|
||||||
initLeftWidth()
|
initLeftWidth()
|
||||||
resetZoom()
|
resetZoom()
|
||||||
@ -294,7 +305,7 @@ function endExplaining() {
|
|||||||
hud.confirm({
|
hud.confirm({
|
||||||
content: '确定要结束讲解吗?',
|
content: '确定要结束讲解吗?',
|
||||||
title: '提示',
|
title: '提示',
|
||||||
zIndex: 999999,
|
zIndex: 999_999,
|
||||||
onConfirm: async () => {
|
onConfirm: async () => {
|
||||||
const lastQuestion = paperDetail.value[paperDetail.value.length - 1]
|
const lastQuestion = paperDetail.value[paperDetail.value.length - 1]
|
||||||
const lastQuestionId = getTitleKey(lastQuestion)
|
const lastQuestionId = getTitleKey(lastQuestion)
|
||||||
@ -422,7 +433,7 @@ async function getTitleStudentInfo(titleId: string, markType: number) {
|
|||||||
@wheel="onZoomWheel"
|
@wheel="onZoomWheel"
|
||||||
>
|
>
|
||||||
<!-- 左侧:题目 -->
|
<!-- 左侧:题目 -->
|
||||||
<div class="explain-left" :style="{ flex: `0 0 ${leftWidth}px` }">
|
<div class="explain-left" :style="leftPanelStyle">
|
||||||
<div class="explain-panel-header">
|
<div class="explain-panel-header">
|
||||||
<span class="panel-title">第 {{ currentIndex + 1 }} 题</span>
|
<span class="panel-title">第 {{ currentIndex + 1 }} 题</span>
|
||||||
</div>
|
</div>
|
||||||
@ -457,10 +468,34 @@ async function getTitleStudentInfo(titleId: string, markType: number) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 拖动分隔条 -->
|
<!-- 拖动分隔条 -->
|
||||||
<div class="resize-handle" @mousedown="onResizeStart"></div>
|
<div
|
||||||
|
class="resize-handle"
|
||||||
|
:class="{ collapsed: answerPanelCollapsed }"
|
||||||
|
@mousedown="!answerPanelCollapsed && onResizeStart($event)"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="answer-panel-toggle"
|
||||||
|
:aria-label="answerPanelCollapsed ? '展开答案解析' : '收起答案解析'"
|
||||||
|
:title="answerPanelCollapsed ? '展开答案解析' : '收起答案解析'"
|
||||||
|
@mousedown.stop
|
||||||
|
@click.stop="toggleAnswerPanel"
|
||||||
|
>
|
||||||
|
<span class="toggle-arrow">
|
||||||
|
{{ answerPanelCollapsed ? '<' : '>' }}
|
||||||
|
</span>
|
||||||
|
<span class="toggle-text">
|
||||||
|
{{ answerPanelCollapsed ? '展开' : '收起' }}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 右侧:答案、解析、统计 -->
|
<!-- 右侧:答案、解析、统计 -->
|
||||||
<div class="explain-right" style="flex: 1; width: 0">
|
<div
|
||||||
|
v-show="!answerPanelCollapsed"
|
||||||
|
class="explain-right"
|
||||||
|
style="flex: 1; width: 0"
|
||||||
|
>
|
||||||
<div class="explain-panel-header">
|
<div class="explain-panel-header">
|
||||||
<span class="panel-title">答案与解析</span>
|
<span class="panel-title">答案与解析</span>
|
||||||
</div>
|
</div>
|
||||||
@ -475,7 +510,9 @@ async function getTitleStudentInfo(titleId: string, markType: number) {
|
|||||||
<latex-text :text="currentQuestion.xkwTitle.answer" />
|
<latex-text :text="currentQuestion.xkwTitle.answer" />
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="answer-analysis-collapsed">
|
<div v-else class="answer-analysis-collapsed">
|
||||||
{{ hasAnswer ? '答案已收起,点击底部“展开答案”查看' : '暂无答案' }}
|
{{
|
||||||
|
hasAnswer ? '答案已收起,点击底部“展开答案”查看' : '暂无答案'
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -491,7 +528,11 @@ async function getTitleStudentInfo(titleId: string, markType: number) {
|
|||||||
<latex-text :text="currentQuestion.xkwTitle.explanation" />
|
<latex-text :text="currentQuestion.xkwTitle.explanation" />
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="answer-analysis-collapsed">
|
<div v-else class="answer-analysis-collapsed">
|
||||||
{{ hasExplanation ? '解析已收起,点击底部“展开解析”查看' : '暂无解析' }}
|
{{
|
||||||
|
hasExplanation
|
||||||
|
? '解析已收起,点击底部“展开解析”查看'
|
||||||
|
: '暂无解析'
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -714,8 +755,12 @@ async function getTitleStudentInfo(titleId: string, markType: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.resize-handle {
|
.resize-handle {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
width: 6px;
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 28px;
|
||||||
cursor: col-resize;
|
cursor: col-resize;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
transition: background 0.2s;
|
transition: background 0.2s;
|
||||||
@ -723,8 +768,72 @@ async function getTitleStudentInfo(titleId: string, markType: number) {
|
|||||||
|
|
||||||
.resize-handle:hover,
|
.resize-handle:hover,
|
||||||
.resize-handle:active {
|
.resize-handle:active {
|
||||||
|
background: #ecf5ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-handle::before {
|
||||||
|
width: 2px;
|
||||||
|
height: 100%;
|
||||||
|
content: '';
|
||||||
|
background: #dcdfe6;
|
||||||
|
border-radius: 2px;
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-handle:hover::before,
|
||||||
|
.resize-handle:active::before {
|
||||||
background: #409eff;
|
background: #409eff;
|
||||||
border-radius: 3px;
|
}
|
||||||
|
|
||||||
|
.resize-handle.collapsed {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.answer-panel-toggle {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
z-index: 2;
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 42px;
|
||||||
|
height: 72px;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #409eff;
|
||||||
|
cursor: pointer;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #d9ecff;
|
||||||
|
border-radius: 21px;
|
||||||
|
box-shadow: 0 2px 10px rgb(64 158 255 / 18%);
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
transition:
|
||||||
|
color 0.2s,
|
||||||
|
background 0.2s,
|
||||||
|
border-color 0.2s,
|
||||||
|
box-shadow 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.answer-panel-toggle:hover,
|
||||||
|
.answer-panel-toggle:focus-visible {
|
||||||
|
color: #fff;
|
||||||
|
background: #409eff;
|
||||||
|
border-color: #409eff;
|
||||||
|
box-shadow: 0 4px 14px rgb(64 158 255 / 28%);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-arrow {
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-text {
|
||||||
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.explain-panel-header {
|
.explain-panel-header {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user