558 lines
14 KiB
Vue
558 lines
14 KiB
Vue
<script setup lang="ts">
|
||
import { useRouter, useRoute } from 'vue-router'
|
||
import RoundSplit from '@/page/subject/freeStudy/views/textbookDetail/RoundSplit.vue'
|
||
import LoadIcon from '@/page/system/mailbox/components/LoadIcon.vue'
|
||
import VideoFullBox from '@/page/subject/components/VideoFullBox/index.vue'
|
||
import homeWorkApi from '@/api/system/homeWork'
|
||
import { debounce, useAudio } from '@/hooks'
|
||
import { subjectStore } from '@/stores'
|
||
import { resource_type_analogy, resource_type_wrong_book } from '@/page/subject/doWork'
|
||
// import { userStore } from '@/stores';
|
||
|
||
const router = useRouter()
|
||
const route = useRoute()
|
||
// const { userInfo } = userStore();
|
||
|
||
const subjectId = ref(2)
|
||
const { getSubjectAllList } = subjectStore()
|
||
const { subjectList } = toRefs(subjectStore())
|
||
const subjectComputed = computed(() =>
|
||
subjectList.value.map(({ id, name }: anyObj) => ({ value: id, label: name })),
|
||
)
|
||
|
||
const subjectiveFlag = ref<0 | 1>(1)
|
||
const subjectiveConfig = reactive([
|
||
{ value: 1, label: '客观题' },
|
||
{ value: 0, label: '主观题' },
|
||
])
|
||
|
||
const correctFlag = ref<0 | 1>(0)
|
||
const correctConfig = reactive([
|
||
{ value: 0, label: '未订正' },
|
||
{ value: 1, label: '已订正' },
|
||
])
|
||
const unCorrectNum = ref(0)
|
||
async function getCorrectConfig() {
|
||
const { data: res } = await homeWorkApi.getWrongNum({
|
||
subjectId: subjectId.value,
|
||
subjectiveFlag: subjectiveFlag.value,
|
||
})
|
||
|
||
unCorrectNum.value = res.data.unCorrectNum
|
||
correctConfig[0].label = `未订正 ${res.data.unCorrectNum > 999 ? '999+' : res.data.unCorrectNum}题`
|
||
correctConfig[1].label = `已订正 ${res.data.correctNum > 999 ? '999+' : res.data.correctNum}题`
|
||
}
|
||
|
||
// 列表
|
||
const list = ref<anyObj[]>([])
|
||
const page = reactive({
|
||
size: 10,
|
||
current: 1,
|
||
total: 0,
|
||
})
|
||
const loading = ref(false)
|
||
|
||
async function getList() {
|
||
const { data: res } = await homeWorkApi.getWrongList({
|
||
subjectId: subjectId.value,
|
||
subjectiveFlag: subjectiveFlag.value,
|
||
correctFlag: correctFlag.value,
|
||
...page,
|
||
})
|
||
|
||
if (res.code !== 200) return
|
||
list.value.push(...(res.rows || []))
|
||
page.total = res.total
|
||
}
|
||
|
||
const scrollBoxRef = ref()
|
||
async function handleScroll(event: any) {
|
||
if (list.value.length >= page.total) return
|
||
if (loading.value) return
|
||
if (event.target.scrollTop + event.target.offsetHeight >= scrollBoxRef.value?.offsetHeight - 50) {
|
||
page.current++
|
||
try {
|
||
loading.value = true
|
||
await getList()
|
||
} catch {
|
||
page.current--
|
||
}
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
const debounceScroll = debounce(handleScroll, 200, false)
|
||
|
||
const pageLoading = ref(false)
|
||
const emptyText = ref('暂无错题')
|
||
|
||
// 初始化列表
|
||
async function initList(pageSize = 0) {
|
||
if (pageLoading.value) return
|
||
pageLoading.value = true
|
||
list.value = []
|
||
page.current = 1
|
||
pageSize && (page.size = pageSize)
|
||
|
||
try {
|
||
await getList()
|
||
emptyText.value = correctFlag.value ? '暂无已订正错题' : '暂无未订正错题'
|
||
} catch {
|
||
emptyText.value = '网络出问题了啦~'
|
||
}
|
||
pageLoading.value = false
|
||
}
|
||
|
||
async function init(size = 0) {
|
||
getCorrectConfig()
|
||
await initList(size)
|
||
}
|
||
|
||
/*
|
||
** 音频
|
||
*/
|
||
// 播放器
|
||
let player: anyObj = {}
|
||
const activeAudio = ref('')
|
||
function handlePlay(item: anyObj) {
|
||
activeAudio.value = item.subjectTitleVo.id
|
||
player.src = item.subjectTitleVo.voiceUrl
|
||
player.play()
|
||
}
|
||
|
||
// 举一反三
|
||
function startTrain(item: anyObj) {
|
||
router.push({
|
||
path: '/subject/doWork',
|
||
query: {
|
||
resourceType: resource_type_analogy,
|
||
subjectId: subjectId.value,
|
||
titleId: item.id,
|
||
isHomework: resource_type_analogy,
|
||
},
|
||
})
|
||
}
|
||
const debounceStartTrain = debounce(startTrain, 500)
|
||
|
||
function handleStart() {
|
||
if (unCorrectNum.value <= 1) {
|
||
handleDiaOK()
|
||
} else {
|
||
showDia.value = true
|
||
}
|
||
}
|
||
|
||
// 订正错题弹窗
|
||
const showDia = ref(false)
|
||
const correctId = ref<string>('') // 被订正的主观题id
|
||
const correctNum = ref(1)
|
||
async function handleDiaOK() {
|
||
if (!correctId.value) {
|
||
router.push({
|
||
path: '/subject/doWork',
|
||
query: {
|
||
resourceType: resource_type_wrong_book,
|
||
num: correctNum.value,
|
||
subjectId: subjectId.value,
|
||
isHomework: resource_type_wrong_book,
|
||
},
|
||
})
|
||
} else {
|
||
await homeWorkApi.errorEdition(correctId.value)
|
||
await init(list.value.length)
|
||
showDia.value = false
|
||
page.size = 10
|
||
}
|
||
}
|
||
function changeCorrectNum(type: 0 | 1) {
|
||
if (type) {
|
||
if (correctNum.value >= 10) return
|
||
correctNum.value++
|
||
} else {
|
||
if (correctNum.value <= 1) return
|
||
correctNum.value--
|
||
}
|
||
}
|
||
|
||
// 主观题订正错题
|
||
function handleCorrection(item: anyObj) {
|
||
correctId.value = item.userErrorEditionId
|
||
showDia.value = true
|
||
}
|
||
|
||
function handleDiaClosed() {
|
||
correctId.value = ''
|
||
}
|
||
|
||
// 视频播放器
|
||
const videoDia = reactive<anyObj>({
|
||
show: false,
|
||
knowledge: {},
|
||
})
|
||
function playVideo(item: anyObj) {
|
||
// videoDia.videoList = list;
|
||
videoDia.show = true
|
||
videoDia.knowledge.id = item.id
|
||
videoDia.knowledge.name = item.name
|
||
}
|
||
|
||
// 图片预览弹窗
|
||
const imgDia = reactive({
|
||
show: false,
|
||
url: '',
|
||
})
|
||
function handleShow(url: string) {
|
||
imgDia.show = true
|
||
imgDia.url = url
|
||
}
|
||
|
||
onMounted(async () => {
|
||
player = useAudio({
|
||
autoplay: false,
|
||
})
|
||
if (subjectList.value?.length <= 0) {
|
||
await getSubjectAllList()
|
||
}
|
||
subjectId.value = subjectComputed.value[0].value
|
||
})
|
||
|
||
onActivated(async () => {
|
||
if (route.meta.subjectId) {
|
||
subjectId.value = Number(route.meta.subjectId as string)
|
||
}
|
||
|
||
pageLoading.value = false
|
||
loading.value = false
|
||
activeAudio.value = ''
|
||
correctFlag.value = 0
|
||
subjectiveFlag.value = 1
|
||
showDia.value = false
|
||
correctNum.value = 1
|
||
init()
|
||
})
|
||
|
||
onDeactivated(() => {
|
||
showDia.value = false
|
||
player.pause?.()
|
||
})
|
||
|
||
onUnmounted(() => {
|
||
player.destroy()
|
||
})
|
||
</script>
|
||
<template>
|
||
<div class="wrong-book">
|
||
<div class="top">
|
||
<BackBar leftText="错题本" />
|
||
|
||
<div class="top-select-tab">
|
||
<SelectTab v-model="subjectiveFlag" :dataList="subjectiveConfig" @change="init"></SelectTab>
|
||
</div>
|
||
<div class="top-select">
|
||
<Select v-model="subjectId" :selectList="subjectComputed" @selectChange="init"></Select>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="main">
|
||
<div class="main-top">
|
||
<div class="main-top-select">
|
||
<SelectTab v-model="correctFlag" :dataList="correctConfig" @change="initList"></SelectTab>
|
||
</div>
|
||
</div>
|
||
<RoundSplit :length="88"></RoundSplit>
|
||
<div class="main-box">
|
||
<template v-if="list.length">
|
||
<div class="main-list hidden_scroll" @scroll="debounceScroll">
|
||
<div ref="scrollBoxRef" class="scroll-box QuesItemBox">
|
||
<template v-for="i in list" :key="i.id">
|
||
<WrongQuesItem
|
||
:correctFlag="correctFlag"
|
||
:subjectiveFlag="subjectiveFlag"
|
||
:data="i"
|
||
:time="i.createTime"
|
||
:activeAudio="activeAudio"
|
||
@startTrain="debounceStartTrain(i)"
|
||
@play="handlePlay(i)"
|
||
@playVideo="playVideo"
|
||
@showPic="handleShow"
|
||
>
|
||
<template #customBtn>
|
||
<Btn
|
||
v-if="subjectiveFlag === 1"
|
||
class="custom-btn"
|
||
width="192"
|
||
height="64"
|
||
size="32"
|
||
@click="debounceStartTrain(i)"
|
||
>
|
||
举一反三
|
||
</Btn>
|
||
<Btn
|
||
v-else-if="subjectiveFlag === 0 && correctFlag === 0"
|
||
class="custom-btn"
|
||
width="192"
|
||
height="64"
|
||
size="32"
|
||
@click="handleCorrection(i)"
|
||
>
|
||
订正错题
|
||
</Btn>
|
||
<div v-else></div>
|
||
</template>
|
||
</WrongQuesItem>
|
||
</template>
|
||
</div>
|
||
</div>
|
||
<LoadIcon v-if="loading" class="load-icon"></LoadIcon>
|
||
</template>
|
||
<Empty
|
||
v-else
|
||
class="empty"
|
||
:type="pageLoading ? 'loading' : 'learn'"
|
||
:content="emptyText"
|
||
></Empty>
|
||
</div>
|
||
</div>
|
||
<Btn
|
||
v-if="unCorrectNum && subjectiveFlag === 1"
|
||
class="start_train-btn"
|
||
type="success"
|
||
width="232"
|
||
height="80"
|
||
@click="handleStart"
|
||
>
|
||
订正错题
|
||
</Btn>
|
||
<mj-dialog
|
||
v-model="showDia"
|
||
hide-cancel
|
||
:ok-text="!correctId ? '开始' : '确定'"
|
||
title="订正错题"
|
||
:ok="handleDiaOK"
|
||
:closed="handleDiaClosed"
|
||
>
|
||
<div class="dia_body">
|
||
<template v-if="!correctId">
|
||
<div class="dia_body-title">系统将从您的错题本中随机选择题目</div>
|
||
<div class="dia_body-slider">
|
||
<div class="dia_body-slider-box">
|
||
<Icon name="slider_btn_reduce" width="56" @click="changeCorrectNum(0)"></Icon>
|
||
<el-slider
|
||
v-model="correctNum"
|
||
:show-tooltip="false"
|
||
:step="1"
|
||
:max="unCorrectNum > 10 ? 10 : unCorrectNum"
|
||
:min="1"
|
||
></el-slider>
|
||
<Icon name="slider_btn_add" width="56" @click="changeCorrectNum(1)"></Icon>
|
||
</div>
|
||
|
||
<div class="dia_body-slider-text">
|
||
数量:{{ correctNum }}/{{ unCorrectNum > 10 ? 10 : unCorrectNum }}
|
||
</div>
|
||
</div>
|
||
</template>
|
||
<template v-else>
|
||
<div class="dia_body-title text">请确认该题已掌握,订正后将移动至 【已订正】模块</div>
|
||
</template>
|
||
</div>
|
||
</mj-dialog>
|
||
<VideoFullBox
|
||
v-model:show="videoDia.show"
|
||
:knowledge="videoDia.knowledge"
|
||
:data="{
|
||
subjectId,
|
||
resourceType: 2,
|
||
origin: 2,
|
||
}"
|
||
></VideoFullBox>
|
||
<ImgView v-model="imgDia.show" :url="imgDia.url"></ImgView>
|
||
</div>
|
||
</template>
|
||
<style scoped lang="scss">
|
||
.wrong-book {
|
||
@include main_bg;
|
||
position: relative;
|
||
width: 100vw;
|
||
height: 100%;
|
||
overflow: hidden;
|
||
box-sizing: border-box;
|
||
line-height: 1.5;
|
||
|
||
// @include hidden_scroll;
|
||
.top {
|
||
width: 100%;
|
||
padding: 2.67vh 64px 0;
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
z-index: 1;
|
||
margin-bottom: 2vh;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
z-index: auto;
|
||
&-select-tab {
|
||
flex: 1;
|
||
margin-left: 62px;
|
||
:deep(.select-list) {
|
||
width: 968px;
|
||
.data-item {
|
||
min-width: 50%;
|
||
&.active {
|
||
background: linear-gradient(269deg, #86e6ff 2.25%, #9effda 51.93%, #5fdcfd 99.65%);
|
||
backdrop-filter: blur(3px);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.main {
|
||
position: relative;
|
||
margin: 11.33vh auto 0;
|
||
background-size: 100%;
|
||
width: 1792px;
|
||
height: 86vh;
|
||
// padding: 91px 24px 24px;
|
||
|
||
&-top {
|
||
width: 100%;
|
||
height: 8.5vh;
|
||
border-radius: 1.67vh;
|
||
background: linear-gradient(269deg, #86e6ff 2.25%, #9effda 51.93%, #5fdcfd 99.65%);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
padding: 0 32px;
|
||
&-select {
|
||
:deep(.select-list) {
|
||
border-radius: 4.5vh;
|
||
.data-item {
|
||
min-width: 258px;
|
||
width: 50%;
|
||
border-radius: 4.5vh;
|
||
&.active {
|
||
background: linear-gradient(90deg, #86e6ff 0%, #9effda 50%, #86e6ff 100%);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
.round-split {
|
||
position: absolute;
|
||
width: calc(100% - 50px);
|
||
left: 50%;
|
||
transform: translate(-50%);
|
||
// z-index: 1;
|
||
top: 7.92vh;
|
||
:deep(.dot) {
|
||
background: linear-gradient(180deg, #798498 0%, #a1b1cb 100%);
|
||
}
|
||
}
|
||
&-box {
|
||
height: calc(100% - 110px);
|
||
border-radius: 1.67vh;
|
||
background: linear-gradient(180deg, #f0faff 0%, #fafdff 100%);
|
||
padding: 2.67vh;
|
||
}
|
||
&-list {
|
||
height: 100%;
|
||
// margin: 0 32px;
|
||
// .scroll-box {
|
||
// height: 100%;
|
||
//}
|
||
.custom-btn {
|
||
min-height: 5.67vh;
|
||
margin-left: 24px;
|
||
border-radius: 4.42vh;
|
||
border: 0.17vh solid #fff;
|
||
box-shadow: 0 0.17vh 0.17vh 0 rgba(0, 0, 0, 0.25);
|
||
color: $font-color;
|
||
.x-icon {
|
||
margin-left: 16px;
|
||
transform: rotate(180deg);
|
||
}
|
||
}
|
||
}
|
||
.custom_load_icon {
|
||
position: absolute;
|
||
bottom: 3.17vh;
|
||
left: 50%;
|
||
transform: translate(-50%);
|
||
}
|
||
.empty {
|
||
height: 75vh;
|
||
}
|
||
}
|
||
.start_train-btn {
|
||
position: absolute;
|
||
bottom: 13.33vh;
|
||
right: -35px;
|
||
z-index: 100;
|
||
:deep(.x-button-text) {
|
||
transform: translate(-8px);
|
||
}
|
||
}
|
||
}
|
||
.dia_body {
|
||
// height: 392px;
|
||
padding: 3.33vh 0;
|
||
text-align: center;
|
||
color: $font-color;
|
||
line-height: 1.5;
|
||
&-title {
|
||
text-align: center;
|
||
font-family: $font-special;
|
||
font-size: 2.67vh;
|
||
&.text {
|
||
width: 510px;
|
||
margin: 4.17vh auto 0;
|
||
}
|
||
}
|
||
&-slider {
|
||
margin-top: 3.33vh;
|
||
&-box {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 0 24px;
|
||
.x-icon {
|
||
margin: 0 32px;
|
||
flex-shrink: 0;
|
||
}
|
||
}
|
||
:deep(.el-slider) {
|
||
height: 4.67vh;
|
||
.el-slider__runway {
|
||
height: 3vh;
|
||
background: #9a9ea0;
|
||
border-radius: 2.5vh;
|
||
}
|
||
.el-slider__bar {
|
||
height: 3vh;
|
||
border-radius: 2.5vh;
|
||
background: linear-gradient(249deg, #4de798 26.9%, #a2fb6e 79.86%);
|
||
}
|
||
.el-slider__button-wrapper {
|
||
width: 56px;
|
||
height: 4.67vh;
|
||
background: radial-gradient(189.06% 189.06% at 49.22% 50.78%, #fff 0%, #becadf 100%);
|
||
border-radius: 50%;
|
||
filter: drop-shadow(0px 3.5px 3.5px rgba(0, 0, 0, 0.15));
|
||
top: -0.83vh;
|
||
}
|
||
.el-slider__button {
|
||
width: 56px;
|
||
height: 4.67vh;
|
||
border: none;
|
||
}
|
||
}
|
||
&-text {
|
||
margin-top: 1.33vh;
|
||
font-family: OPPOSans;
|
||
font-size: 2vh;
|
||
}
|
||
}
|
||
}
|
||
</style>
|