判断题 && 取消答题次数和容错

main
king 1 year ago
parent 223ef62419
commit 702cee4693
  1. 4
      .env
  2. 2
      src/api/curriculum.ts
  3. 9
      src/components/topic/judge.tsx
  4. 5
      src/components/topic/multi.tsx
  5. 7
      src/components/topic/shortAnswer.tsx
  6. 3
      src/components/topic/topic.scss
  7. 13
      src/components/video/video.tsx
  8. 186
      src/pages/business/videoInfo/components/course.tsx
  9. 2
      types/topic.d.ts

@ -1,5 +1,5 @@
#TARO_APP_API=https://yjx.dev.yaojiankang.top
TARO_APP_API=https://playedu.yaojiankang.top
TARO_APP_API=https://yjx.dev.yaojiankang.top
#TARO_APP_API=https://playedu.yaojiankang.top
TARO_APP_LGOIN=true

@ -28,8 +28,6 @@ export interface HourPlayData {
url: string
/** 断点题 */
hourExamQuestions: Record<number, (ShareSubject | Multi)[]>
/** 次数 */
fault_count: Record<number, number>[]
/** 断点 */
timeList: number[]
hour_test?: { id: number }

@ -6,10 +6,9 @@ interface Props {
data: ShareSubject
onAnswer: (isAnswer: boolean) => void
validate: boolean
frequency?: number
}
const Judge: FC<Props> = ({data, onAnswer, validate, frequency}) => {
const Judge: FC<Props> = ({data, onAnswer, validate}) => {
const [rightAnswer, setRightAnswer] = useState<string | null>(null) //答案
const rightKey = data.right_answer === 'true' ? 'correct' : 'error' // 正确答案数组
const [error, setError] = useState(false)
@ -43,19 +42,19 @@ const Judge: FC<Props> = ({data, onAnswer, validate, frequency}) => {
color={validate ? 'correct' !== rightKey ? 'red' : '#45d4a8' : '#45d4a8'}
disabled={validate ? 'correct' !== rightAnswer : false}
>
<Text></Text>
<Text>{data.right_value}</Text>
</Radio>
<Radio
value={'error'}
color={validate ? 'error' !== rightKey ? 'red' : '#45d4a8' : '#45d4a8'}
disabled={validate ? 'error' !== rightAnswer : false}
className='option'>
<Text></Text>
<Text>{data.error_value}</Text>
</Radio>
</RadioGroup>
{error && frequency == 0 && <View className='mt-3'>
{error && <View className='mt-3'>
<View className='right_answer'>{data.right_answer ? '正确' : '错误'}</View>
<View className='font-weight my-3'></View>
<View>{data.analysis}</View>

@ -6,10 +6,9 @@ interface Props {
data: Multi
onAnswer: (isAnswer: boolean) => void
validate: boolean
frequency?: number
}
const Multi: FC<Props> = ({data, onAnswer, validate, frequency}) => {
const Multi: FC<Props> = ({data, onAnswer, validate}) => {
const [rightAnswer, setRightAnswer] = useState<string[]>([]) //答案
const rightKey = data?.right_answer?.split(',') || [] // 正确答案数组
@ -90,7 +89,7 @@ const Multi: FC<Props> = ({data, onAnswer, validate, frequency}) => {
}
</View>
{error && frequency == 0 && <View className='mt-3'>
{error && <View className='mt-3'>
<View className='right_answer'>{data.right_answer}</View>
<View className='font-weight my-3'></View>
<View>{data.analysis}</View>

@ -6,10 +6,9 @@ interface Props {
data: ShareSubject
onAnswer: (isAnswer: boolean) => void
validate: boolean
frequency?: number
}
const ShortAnswer: FC<Props> = ({data, onAnswer, validate, frequency}) => {
const ShortAnswer: FC<Props> = ({data, onAnswer, validate}) => {
const [value, setValue] = useState<string>('')
useEffect(() => {
@ -36,10 +35,10 @@ const ShortAnswer: FC<Props> = ({data, onAnswer, validate, frequency}) => {
onInput={(e) => setValue(e.detail.value)}/>
{frequency == 0 && <View className='mt-3'>
<View className='mt-3'>
<View className='font-weight my-3'></View>
<View>{data.analysis}</View>
</View>}
</View>
</View>
)

@ -35,9 +35,6 @@
border-top: 1px solid #F5F8F7;
height: 60rpx;
padding: 20rpx 0;
display: flex;
align-items: center;
justify-content: space-between;
}
.upAndDown {

@ -41,7 +41,6 @@ const HVideo: FC<HVideoOptions> = (opt: HVideoOptions) => {
/** 判断是否进入断点 */
opt.breakpoint.forEach(d => {
if (time < d + deviation && time > d - deviation) {
video?.pause()
video?.seek(d - deviation)
if (process.env.TARO_ENV === 'h5') {
@ -51,17 +50,6 @@ const HVideo: FC<HVideoOptions> = (opt: HVideoOptions) => {
}
}
video?.exitFullScreen()
// if (opt.preview) {
// Taro.showModal({
// title: '是否答题',
// success({confirm, cancel}) {
// confirm && opt.onBreakpoint(d)
// cancel && video?.play()
// }
// })
// return;
// }
opt.onBreakpoint(d)
return
}
@ -131,7 +119,6 @@ const HVideo: FC<HVideoOptions> = (opt: HVideoOptions) => {
onPlay={onPlay}
onPause={onPause}
/>
{/*<View style={{position: 'absolute', top: '100px', color: '#fff'}}>1221</View>*/}
</>
)
}

@ -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>

2
types/topic.d.ts vendored

@ -8,6 +8,8 @@ interface ShareSubject {
analysis: string //课题解析
course_id: number
hour_id: number
right_value:string
error_value:string
}
/** 选择题 */

Loading…
Cancel
Save