|
|
|
@ -1,12 +1,10 @@ |
|
|
|
|
import {ScrollView, Swiper, SwiperItem, Text, View} from "@tarojs/components"; |
|
|
|
|
import {ScrollView, Text, View} from "@tarojs/components"; |
|
|
|
|
import {FC, useEffect, useState} from "react"; |
|
|
|
|
import HVideo from "@/components/video/video"; |
|
|
|
|
import {CurEndParam, curriculum, HourPlayData} from "@/api"; |
|
|
|
|
import {Profile} from '@/store' |
|
|
|
|
import Taro from "@tarojs/taro"; |
|
|
|
|
import Multi from "@/components/topic/multi"; |
|
|
|
|
import Judge from "@/components/topic/judge"; |
|
|
|
|
import ShortAnswer from "@/components/topic/shortAnswer"; |
|
|
|
|
import unique_ident from "@/hooks/unique_ident"; |
|
|
|
|
import MyButton from "@/components/button/MyButton"; |
|
|
|
|
import {formatMinute} from "@/utils/time"; |
|
|
|
@ -21,21 +19,16 @@ interface Props { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let seek: (time: number) => void |
|
|
|
|
let record: boolean[] = [] //答案记录
|
|
|
|
|
const Course: FC<Props> = ({id, courseId, preview, curEnd}) => { |
|
|
|
|
const [breakpoint, setBreakpoint] = useState<number[]>([]) // 断点
|
|
|
|
|
const [show, setShow] = useState(false) // 题
|
|
|
|
|
const [data, setData] = useState<HourPlayData | null>(null) |
|
|
|
|
const [examAll, setExamAll] = useState<Record<number, (ShareSubject | Multi)[]>>([]) // 题库
|
|
|
|
|
const [index, setIndex] = useState(0) |
|
|
|
|
const [time, setTime] = useState<number>(0) // 进入断点的时间
|
|
|
|
|
const [validate, setValidate] = useState(false) // 开启验证
|
|
|
|
|
const [newRecord, setNewRecord] = useState<boolean[]>([]) |
|
|
|
|
const [faultCount, setFaultCount] = useState<Record<number, number> | null>(null) |
|
|
|
|
const [frequency, setFrequency] = useState<number>(1) // 次数
|
|
|
|
|
const [record, setRecord] = useState<boolean[]>([]) // 考题记录
|
|
|
|
|
const [testId, setTestId] = useState<number | null>(null) |
|
|
|
|
const [startRecording, setStartRecording] = useState<CurEndParam | null>(null) // 视频开始记录
|
|
|
|
|
const [topicRecord, setRecord] = useState<number[]>([]) // 考题正确记录
|
|
|
|
|
const {user} = Profile.useContainer() |
|
|
|
|
|
|
|
|
|
async function onEnded() { |
|
|
|
@ -66,9 +59,6 @@ const Course: FC<Props> = ({id, courseId, preview, curEnd}) => { |
|
|
|
|
|
|
|
|
|
/** 进入断点 */ |
|
|
|
|
function onBreakpoint(breakpoint: number) { |
|
|
|
|
if (breakpoint !== time) { |
|
|
|
|
setFrequency(faultCount?.[breakpoint] || 1) |
|
|
|
|
} |
|
|
|
|
setTime(breakpoint) |
|
|
|
|
setShow(true) |
|
|
|
|
} |
|
|
|
@ -82,9 +72,7 @@ const Course: FC<Props> = ({id, courseId, preview, curEnd}) => { |
|
|
|
|
setData(res) |
|
|
|
|
setBreakpoint(res.timeList) |
|
|
|
|
setExamAll(res.hourExamQuestions || []) |
|
|
|
|
setFaultCount(res.fault_count?.[0] || {}) |
|
|
|
|
setTestId(res?.hour_test?.id || null) |
|
|
|
|
setRecord([]) |
|
|
|
|
|
|
|
|
|
setStartRecording({ |
|
|
|
|
duration: 0, |
|
|
|
@ -109,97 +97,39 @@ const Course: FC<Props> = ({id, courseId, preview, curEnd}) => { |
|
|
|
|
getData() |
|
|
|
|
}, [id]) |
|
|
|
|
|
|
|
|
|
/** 统计答案 */ |
|
|
|
|
function onAnswer(isAnswer: boolean) { |
|
|
|
|
record.push(isAnswer) |
|
|
|
|
setNewRecord(record) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function init(show = true) { |
|
|
|
|
record = [] |
|
|
|
|
show && setShow(false) |
|
|
|
|
setValidate(false) |
|
|
|
|
setNewRecord([]) |
|
|
|
|
setRecord([]) |
|
|
|
|
setTime(0) |
|
|
|
|
setIndex(0) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** 再来一次 */ |
|
|
|
|
function onceMore() { |
|
|
|
|
const oldTime: number = time |
|
|
|
|
init(false) |
|
|
|
|
setTimeout(() => { |
|
|
|
|
setTime(oldTime) |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** 重新看 */ |
|
|
|
|
function again() { |
|
|
|
|
if (examAll?.[time]?.length) { |
|
|
|
|
const {id: question_id, question_type} = examAll?.[time]?.[0] |
|
|
|
|
curriculum.answerRecord(id, { |
|
|
|
|
is_pass: false, |
|
|
|
|
user_id: user?.id!, |
|
|
|
|
time: time, |
|
|
|
|
question_id, |
|
|
|
|
question_type |
|
|
|
|
}).then(res => { |
|
|
|
|
seek(res.time) |
|
|
|
|
}) |
|
|
|
|
init() |
|
|
|
|
} |
|
|
|
|
setShow(false) |
|
|
|
|
setIndex(0) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
if (!newRecord.length) return; |
|
|
|
|
setFrequency(frequency - 1) // 减少一次学习记录
|
|
|
|
|
const pass = newRecord.every(d => d) |
|
|
|
|
if (!record.length) return; |
|
|
|
|
const pass = record.every(d => d) |
|
|
|
|
/** 考题正确 */ |
|
|
|
|
if (pass) { |
|
|
|
|
const {id: question_id, question_type} = examAll?.[time]?.[0] |
|
|
|
|
curriculum.answerRecord(id, { |
|
|
|
|
is_pass: pass, |
|
|
|
|
user_id: user?.id!, |
|
|
|
|
time: time, |
|
|
|
|
question_type, |
|
|
|
|
question_id |
|
|
|
|
}).then() |
|
|
|
|
const {id: question_id, question_type} = examAll?.[time]?.[0] |
|
|
|
|
curriculum.answerRecord(id, { |
|
|
|
|
is_pass: pass, |
|
|
|
|
user_id: user?.id!, |
|
|
|
|
time: time, |
|
|
|
|
question_type, |
|
|
|
|
question_id |
|
|
|
|
}).then() |
|
|
|
|
|
|
|
|
|
/** 删除断点 */ |
|
|
|
|
const old: number[] = JSON.parse(JSON.stringify(breakpoint)) |
|
|
|
|
const index = old.indexOf(time) |
|
|
|
|
old.splice(index, 1) |
|
|
|
|
setBreakpoint(old) |
|
|
|
|
|
|
|
|
|
/** 删除断点 */ |
|
|
|
|
const old: number[] = JSON.parse(JSON.stringify(breakpoint)) |
|
|
|
|
const index = old.indexOf(time) |
|
|
|
|
old.splice(index, 1) |
|
|
|
|
setBreakpoint(old) |
|
|
|
|
|
|
|
|
|
setRecord([...topicRecord, time]) |
|
|
|
|
if (pass) { |
|
|
|
|
seek(time) |
|
|
|
|
|
|
|
|
|
Taro.showToast({title: '答题正确', duration: 2000}) |
|
|
|
|
init() |
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
if ((frequency - 1) !== 0) { |
|
|
|
|
Taro.showModal({ |
|
|
|
|
title: '考试未通过', |
|
|
|
|
content: '剩余考试次数:' + (frequency - 1), |
|
|
|
|
confirmText: '重考', |
|
|
|
|
success({confirm}) { |
|
|
|
|
confirm && onceMore() |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
} else { |
|
|
|
|
Taro.showModal({ |
|
|
|
|
title: '考试未通过', |
|
|
|
|
content: '请重新学习', |
|
|
|
|
success({confirm}) { |
|
|
|
|
confirm && again() |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}, [newRecord]) |
|
|
|
|
}, [record]) |
|
|
|
|
|
|
|
|
|
function videoSeek(fn: (time: number) => void) { |
|
|
|
|
seek = fn |
|
|
|
@ -220,73 +150,31 @@ const Course: FC<Props> = ({id, courseId, preview, curEnd}) => { |
|
|
|
|
<CustomPageContainer |
|
|
|
|
show={show} |
|
|
|
|
position='bottom' |
|
|
|
|
onAfterLeave={again} |
|
|
|
|
> |
|
|
|
|
<View> |
|
|
|
|
<View className='text-center mt-2 text-muted'> |
|
|
|
|
<Text className='mr-2'>{formatMinute(time)}考题</Text> |
|
|
|
|
<Text>{index + 1}/{examAll?.[time]?.length}</Text> |
|
|
|
|
</View> |
|
|
|
|
<Swiper |
|
|
|
|
style={{height: "60vh"}} |
|
|
|
|
snapToEdge |
|
|
|
|
current={index} |
|
|
|
|
onChange={(e) => setIndex(e.detail.current ?? index)}> |
|
|
|
|
{examAll?.[time]?.map((d) => |
|
|
|
|
<SwiperItem key={d.id}> |
|
|
|
|
<ScrollView style='height:70vh' scrollY> |
|
|
|
|
{d.question_type === 1 && |
|
|
|
|
<Multi |
|
|
|
|
frequency={frequency} |
|
|
|
|
data={d as Multi} |
|
|
|
|
onAnswer={onAnswer} |
|
|
|
|
validate={validate} |
|
|
|
|
/>} |
|
|
|
|
{d.question_type === 2 && |
|
|
|
|
<Judge |
|
|
|
|
frequency={frequency} |
|
|
|
|
data={d as ShareSubject} |
|
|
|
|
validate={validate} |
|
|
|
|
onAnswer={onAnswer} |
|
|
|
|
/>} |
|
|
|
|
{d.question_type === 3 && |
|
|
|
|
<ShortAnswer |
|
|
|
|
frequency={frequency} |
|
|
|
|
data={d as ShareSubject} |
|
|
|
|
onAnswer={onAnswer} |
|
|
|
|
validate={validate} |
|
|
|
|
/>} |
|
|
|
|
</ScrollView> |
|
|
|
|
</SwiperItem> |
|
|
|
|
)} |
|
|
|
|
</Swiper> |
|
|
|
|
{examAll?.[time]?.slice(0, 1)?.map((d) => |
|
|
|
|
<ScrollView style='height:60vh' scrollY key={d.id}> |
|
|
|
|
{d.question_type === 2 && |
|
|
|
|
<Judge |
|
|
|
|
data={d as ShareSubject} |
|
|
|
|
validate={validate} |
|
|
|
|
onAnswer={(isAnswer) => setRecord([isAnswer])} |
|
|
|
|
/>} |
|
|
|
|
</ScrollView> |
|
|
|
|
)} |
|
|
|
|
<View> |
|
|
|
|
|
|
|
|
|
<View className='upAndDown'> |
|
|
|
|
<View> |
|
|
|
|
{ |
|
|
|
|
index !== 0 && |
|
|
|
|
<MyButton type='default' size='mini' width={150} |
|
|
|
|
onClick={() => setIndex(index - 1)}>上一题</MyButton> |
|
|
|
|
} |
|
|
|
|
</View> |
|
|
|
|
<View> |
|
|
|
|
{ |
|
|
|
|
(index + 1) !== examAll?.[time]?.length && |
|
|
|
|
<MyButton size='mini' width={150} type='default' |
|
|
|
|
onClick={() => setIndex(index + 1)}>下一题</MyButton> |
|
|
|
|
} |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
|
|
|
|
|
<View className='statistics'> |
|
|
|
|
<View>考试次数:{frequency}</View> |
|
|
|
|
{ |
|
|
|
|
(index + 1) === examAll?.[time]?.length && <View> |
|
|
|
|
{!validate && <MyButton width={150} fillet onClick={() => setValidate(true)}>交卷</MyButton>} |
|
|
|
|
{frequency > 0 && validate && <MyButton width={150} fillet onClick={onceMore}>重考</MyButton>} |
|
|
|
|
{frequency === 0 && validate && <MyButton width={150} fillet onClick={again}>重新学习</MyButton>} |
|
|
|
|
</View> |
|
|
|
|
record.length > 0 |
|
|
|
|
? <MyButton fillet onClick={() => { |
|
|
|
|
init(); |
|
|
|
|
seek(time) |
|
|
|
|
}}>关闭</MyButton> |
|
|
|
|
: <MyButton fillet onClick={() => setValidate(true)}>交卷</MyButton> |
|
|
|
|
} |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|