修改答题步骤

main
king 1 year ago
parent ab5241ebbf
commit 77dbdb87c1
  1. 4
      .env
  2. 1
      src/api/curriculum.ts
  3. 2
      src/app.scss
  4. 10
      src/components/topic/judge.tsx
  5. 14
      src/components/topic/multi.tsx
  6. 24
      src/components/topic/shortAnswer.tsx
  7. 11
      src/components/topic/topic.scss
  8. 21
      src/pages/business/hourHistory/hourHistory.tsx
  9. 2
      src/pages/business/videoInfo/components/catalogue.tsx
  10. 93
      src/pages/business/videoInfo/components/course.tsx
  11. 8
      src/pages/business/videoInfo/components/hours.tsx
  12. 7
      src/pages/business/videoInfo/videoInfo.scss
  13. 14
      src/pages/business/videoInfo/videoInfo.tsx
  14. 12
      src/static/css/module.scss

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

@ -10,6 +10,7 @@ export interface CourseDepData {
chapters: Chapters[] chapters: Chapters[]
course: Curriculum course: Curriculum
hours: Hours hours: Hours
duration: number
/** 是否必修 */ /** 是否必修 */
is_required: boolean is_required: boolean
learn_hour_records: LearnHourRecords[] learn_hour_records: LearnHourRecords[]

@ -267,7 +267,7 @@
.text-dark { color: #343a40;} .text-dark { color: #343a40;}
.text-hover-dark{ color: #121416;} .text-hover-dark{ color: #121416;}
.text-body { color: #212529;} .text-body { color: #212529;}
.text-muted { color: #6c757d;} .text-muted { color: #909795;}
/* 圆角 */ /* 圆角 */

@ -1,19 +1,15 @@
import {FC, useEffect, useState} from "react"; import {FC, useEffect, useState} from "react";
import { Radio, RadioGroup, Text, View} from "@tarojs/components"; import { Radio, RadioGroup, Text, View} from "@tarojs/components";
import './topic.scss' import './topic.scss'
import MyButton from "@/components/button/MyButton";
interface Props { interface Props {
data: ShareSubject data: ShareSubject
onAnswer: (isAnswer: boolean) => void onAnswer: (isAnswer: boolean) => void
onUpAndDown?: (index: number) => void
index: number
validate: boolean validate: boolean
frequency?: number frequency?: number
end?: boolean
} }
const Judge: FC<Props> = ({data, onAnswer, onUpAndDown, index, validate, frequency, end}) => { const Judge: FC<Props> = ({data, onAnswer, validate, frequency}) => {
const [rightAnswer, setRightAnswer] = useState<string | null>(null) //答案 const [rightAnswer, setRightAnswer] = useState<string | null>(null) //答案
const rightKey = data.right_answer ? 'correct' : 'error' // 正确答案数组 const rightKey = data.right_answer ? 'correct' : 'error' // 正确答案数组
const [error, setError] = useState(false) const [error, setError] = useState(false)
@ -58,10 +54,6 @@ const Judge: FC<Props> = ({data, onAnswer, onUpAndDown, index, validate, frequen
</Radio> </Radio>
</RadioGroup> </RadioGroup>
{onUpAndDown && <View className='upAndDown'>
{index > 0 && <MyButton size='mini' width={150} onClick={() => onUpAndDown(index - 1)}></MyButton>}
{!end && <MyButton size='mini' width={150} onClick={() => onUpAndDown(index + 1)}></MyButton>}
</View>}
{error && frequency == 0 && <View className='mt-3'> {error && frequency == 0 && <View className='mt-3'>

@ -1,19 +1,15 @@
import {FC, useEffect, useState} from "react"; import {FC, useEffect, useState} from "react";
import {Checkbox, CheckboxGroup, Radio, RadioGroup, Text, View} from "@tarojs/components"; import {Checkbox, CheckboxGroup, Radio, RadioGroup, Text, View} from "@tarojs/components";
import './topic.scss' import './topic.scss'
import MyButton from "@/components/button/MyButton";
interface Props { interface Props {
data: Multi data: Multi
onAnswer: (isAnswer: boolean) => void onAnswer: (isAnswer: boolean) => void
onUpAndDown?: (index: number) => void
index: number
validate: boolean validate: boolean
frequency?: number frequency?: number
end?: boolean
} }
const Multi: FC<Props> = ({data, onAnswer, onUpAndDown, index, validate, frequency, end}) => { const Multi: FC<Props> = ({data, onAnswer, validate, frequency}) => {
const [rightAnswer, setRightAnswer] = useState<string[]>([]) //答案 const [rightAnswer, setRightAnswer] = useState<string[]>([]) //答案
const rightKey = data?.right_answer?.split(',') || [] // 正确答案数组 const rightKey = data?.right_answer?.split(',') || [] // 正确答案数组
@ -46,7 +42,7 @@ const Multi: FC<Props> = ({data, onAnswer, onUpAndDown, index, validate, frequen
return ( return (
<View className='topic'> <View className='topic'>
<View className='mb-3'> <View className='mb-3'>
<Text className={'topicType'}>{data.type ? "多选题" : '单选题'}</Text> <Text className='topicType'>{data.type ? "多选题" : '单选题'}</Text>
<Text>{data.question}</Text> <Text>{data.question}</Text>
</View> </View>
@ -75,12 +71,6 @@ const Multi: FC<Props> = ({data, onAnswer, onUpAndDown, index, validate, frequen
} }
</View> </View>
{onUpAndDown && <View className='upAndDown'>
{index > 0 && <MyButton size='mini' width={150} onClick={() => onUpAndDown?.(index - 1)}></MyButton>}
{!end && <MyButton size='mini' width={150} onClick={() => onUpAndDown?.(index + 1)}></MyButton>}
</View>}
{error && frequency == 0 && <View className='mt-3'> {error && frequency == 0 && <View className='mt-3'>
<View className='right_answer'>{data.right_answer}</View> <View className='right_answer'>{data.right_answer}</View>
<View className='font-weight my-3'></View> <View className='font-weight my-3'></View>

@ -1,30 +1,20 @@
import {Button, Text, Textarea, View} from "@tarojs/components"; import {Text, Textarea, View} from "@tarojs/components";
import {FC, useEffect, useState} from "react"; import {FC, useEffect, useState} from "react";
import Taro from "@tarojs/taro";
import './topic.scss' import './topic.scss'
interface Props { interface Props {
data: ShareSubject data: ShareSubject
onAnswer: (isAnswer: boolean) => void onAnswer: (isAnswer: boolean) => void
onUpAndDown?: (index: number) => void
index: number
validate: boolean validate: boolean
frequency?: number frequency?: number
end?: boolean
} }
const ShortAnswer: FC<Props> = ({data, onAnswer, onUpAndDown, index, validate, frequency, end}) => { const ShortAnswer: FC<Props> = ({data, onAnswer, validate, frequency}) => {
const [value, setValue] = useState<string>('') const [value, setValue] = useState<string>('')
function onBlur() {
if (value.length < 3) {
Taro.showToast({title: '最少3个字', icon: 'error'})
}
}
useEffect(() => { useEffect(() => {
if (validate) { if (validate) {
if (value.length < 3) { if (value.length < 1) {
onAnswer(false) onAnswer(false)
} else { } else {
onAnswer(true) onAnswer(true)
@ -42,17 +32,9 @@ const ShortAnswer: FC<Props> = ({data, onAnswer, onUpAndDown, index, validate, f
<Textarea <Textarea
placeholder='请输入答案' placeholder='请输入答案'
className='Textarea' className='Textarea'
onBlur={onBlur}
maxlength={255} maxlength={255}
onInput={(e) => setValue(e.detail.value)}/> onInput={(e) => setValue(e.detail.value)}/>
<View className='text-muted mt-2'>3</View>
{onUpAndDown && <View className='upAndDown'>
{index > 0 && <Button className='button' onClick={() => onUpAndDown?.(index - 1)}></Button>}
{!end && <Button className='button' onClick={() => onUpAndDown?.(index + 1)}></Button>}
</View>}
{frequency == 0 && <View className='mt-3'> {frequency == 0 && <View className='mt-3'>
<View className='font-weight my-3'></View> <View className='font-weight my-3'></View>

@ -7,10 +7,10 @@
.topicType { .topicType {
display: inline-block; display: inline-block;
background: #45D4A8; background: #45D4A8;
border-radius: 5rpx; border-radius: 10rpx;
color: #fff; color: #fff;
padding: 0 10rpx; padding: 0 10rpx;
font-size: 30rpx; font-size: 26rpx;
margin-right: 20rpx; margin-right: 20rpx;
} }
@ -28,7 +28,8 @@
.statistics { .statistics {
border-top: 1px solid #F5F8F7; border-top: 1px solid #F5F8F7;
padding: 30rpx 0; height: 60rpx;
padding: 20rpx 0;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
@ -36,10 +37,10 @@
.upAndDown { .upAndDown {
display: flex; display: flex;
height: 50rpx;
justify-content: space-between; justify-content: space-between;
position: absolute;
bottom: 20rpx;
width: 100%; width: 100%;
padding: 10rpx 0;
} }

@ -42,8 +42,8 @@ const HourHistory: FC = () => {
<Image className={styles.image} src={cur?.thumb || ''} mode='center'/> <Image className={styles.image} src={cur?.thumb || ''} mode='center'/>
<View className={styles.classHour}>{cur?.class_hour}/{cur?.finished_hour_count || 0}</View> <View className={styles.classHour}>{cur?.class_hour}/{cur?.finished_hour_count || 0}</View>
<View className={styles.title}> <View className={styles.title}>
<View>{cur?.title}</View> <View></View>
<View>{hour?.title}</View> <View>{hour?.title}</View>
</View> </View>
</View> </View>
@ -55,7 +55,7 @@ const HourHistory: FC = () => {
<View>{formatDateTime(new Date(d.start_at), 'MM-dd')}</View> <View>{formatDateTime(new Date(d.start_at), 'MM-dd')}</View>
<Progress <Progress
className={styles.progress} className={styles.progress}
percent={d.duration / (hour?.duration || 0)} percent={Number((d.duration / (hour?.duration || 0)).toFixed(2))}
showInfo showInfo
borderRadius={10} borderRadius={10}
active active
@ -70,21 +70,6 @@ const HourHistory: FC = () => {
: <Empty name='暂无数据'/> : <Empty name='暂无数据'/>
} }
{/*{times.length ? times.map((d, index) =>*/}
{/* <View key={index} className={styles.category}>*/}
{/* <View className={styles.thumb}>*/}
{/* <Image src={d.course.thumb} className={styles.image}/>*/}
{/* <View className={styles.count}>共{d.total_hour_count}节/已学{d.finished_count}节</View>*/}
{/* </View>*/}
{/* <View className={styles.text}>*/}
{/* <View>{d.course.title}</View>*/}
{/* <View className={styles.describe}>*/}
{/* <Text className='mr-4'>观看{formatMinute(d.duration)}</Text>*/}
{/* <Text>学习进度:{(d.finished_count / d.total_hour_count * 100).toFixed(0)}%</Text>*/}
{/* </View>*/}
{/* </View>*/}
{/* </View>) : <Empty name='无历史记录'/>}*/}
</View> </View>
) )
} }

@ -105,7 +105,7 @@ const Catalogue: FC<Props> = ({data, setHors, id, playId}) => {
<View className='py-2 hours'> <View className='py-2 hours'>
{current === 0 && <View className='short_desc'>{data?.course.short_desc || data?.course.title}</View>} {current === 0 && <View className='short_desc'>{data?.course.short_desc || data?.course.title}</View>}
{current === 1 && <View> {current === 1 && <View>
<View className='font-weight'></View> <View className='my-2'></View>
{data?.chapters.length ? Object.values(data?.chapters || {}).map((d, index) => <View> {data?.chapters.length ? Object.values(data?.chapters || {}).map((d, index) => <View>
<Collapse title={`${index + 1}.${d.name}`}> <Collapse title={`${index + 1}.${d.name}`}>
<Hours <Hours

@ -1,4 +1,4 @@
import {ScrollView, Swiper, SwiperItem, View} from "@tarojs/components"; import {ScrollView, Swiper, SwiperItem, Text, View} from "@tarojs/components";
import {FC, useEffect, useState} from "react"; import {FC, useEffect, useState} from "react";
import HVideo from "@/components/video/video"; import HVideo from "@/components/video/video";
import {CurEndParam, curriculum, HourPlayData} from "@/api"; import {CurEndParam, curriculum, HourPlayData} from "@/api";
@ -10,6 +10,7 @@ import ShortAnswer from "@/components/topic/shortAnswer";
import unique_ident from "@/hooks/unique_ident"; import unique_ident from "@/hooks/unique_ident";
import CustomPageContainer from "@/components/custom-page-container/custom-page-container"; import CustomPageContainer from "@/components/custom-page-container/custom-page-container";
import MyButton from "@/components/button/MyButton"; import MyButton from "@/components/button/MyButton";
import {formatMinute} from "@/utils/time";
interface Props { interface Props {
id: number, id: number,
@ -100,28 +101,34 @@ const Course: FC<Props> = ({id, courseId, preview, curEnd}: Props) => {
setNewRecord(record) setNewRecord(record)
} }
function init() { function init(show = true) {
record = [] record = []
setTime(0) show && setShow(false)
setShow(false)
setIndex(0)
setValidate(false) setValidate(false)
setNewRecord([]) setNewRecord([])
setTime(0)
if (process.env.TARO_ENV === 'h5') {
setTimeout(() => {
setIndex(0)
}, 200)
} else {
setIndex(0)
}
} }
/** 再来一次 */ /** 再来一次 */
function onceMore() { function onceMore() {
const oldTime: number = time const oldTime: number = time
init() init(false)
setTimeout(() => { setTimeout(() => {
setShow(true)
setTime(oldTime) setTime(oldTime)
}) })
} }
/** 重新看 */ /** 重新看 */
function again() { function again() {
if (frequency === 0 && show) { if (examAll?.[time]?.length) {
const {id: question_id, question_type} = examAll?.[time]?.[0] const {id: question_id, question_type} = examAll?.[time]?.[0]
curriculum.answerRecord(id, { curriculum.answerRecord(id, {
is_pass: false, is_pass: false,
@ -159,7 +166,24 @@ const Course: FC<Props> = ({id, courseId, preview, curEnd}: Props) => {
seek(time) seek(time)
init() init()
} else { } else {
Taro.showToast({title: '答案错误', icon: 'error', duration: 3000}) 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]) }, [newRecord])
@ -186,18 +210,17 @@ const Course: FC<Props> = ({id, courseId, preview, curEnd}: Props) => {
position='bottom' position='bottom'
round round
onAfterLeave={again} onAfterLeave={again}
onClickOverlay={again}
> >
<View className='text-center mt-2 text-muted'>
<Text className='mr-2'>{formatMinute(time)}</Text>
<Text>{index + 1}/{examAll?.[time]?.length}</Text>
</View>
<Swiper <Swiper
style={{height: "60vh"}} style={{height: "60vh"}}
snapToEdge snapToEdge
current={index} current={index}
onChange={(e) => { onChange={(e) => setIndex(e.detail.current)}>
if ((e.target as any)?.current) { {examAll?.[time]?.map((d) =>
setIndex((e.target as any).current)
}
}}>
{examAll?.[time]?.map((d, index) =>
<SwiperItem key={d.id}> <SwiperItem key={d.id}>
<ScrollView style='height:70vh' scrollY> <ScrollView style='height:70vh' scrollY>
{d.question_type === 1 && {d.question_type === 1 &&
@ -205,42 +228,50 @@ const Course: FC<Props> = ({id, courseId, preview, curEnd}: Props) => {
frequency={frequency} frequency={frequency}
data={d as Multi} data={d as Multi}
onAnswer={onAnswer} onAnswer={onAnswer}
onUpAndDown={(index) => setIndex(index)}
index={index}
validate={validate} validate={validate}
end={index === examAll?.[time].length - 1}
/>} />}
{d.question_type === 2 && {d.question_type === 2 &&
<Judge <Judge
frequency={frequency} frequency={frequency}
onUpAndDown={(index) => setIndex(index)}
index={index}
data={d as ShareSubject} data={d as ShareSubject}
validate={validate} validate={validate}
onAnswer={onAnswer} onAnswer={onAnswer}
end={index === examAll?.[time].length - 1}
/>} />}
{d.question_type === 3 && {d.question_type === 3 &&
<ShortAnswer <ShortAnswer
frequency={frequency} frequency={frequency}
data={d as ShareSubject} data={d as ShareSubject}
onAnswer={onAnswer} onAnswer={onAnswer}
onUpAndDown={(index) => setIndex(index)}
index={index}
validate={validate} validate={validate}
end={index === examAll?.[time].length - 1}
/>} />}
</ScrollView> </ScrollView>
</SwiperItem> </SwiperItem>
)} )}
</Swiper> </Swiper>
<View className='statistics'> <View>
<View>{frequency}</View> <View className='statistics'>
<View>{index + 1}/{examAll?.[time]?.length}</View> <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>
}
{!validate && <MyButton width={150} fillet onClick={() => setValidate(true)}></MyButton>} </View>
{frequency > 0 && validate && <MyButton width={150} fillet onClick={onceMore}></MyButton>} <View className='upAndDown'>
{frequency === 0 && validate && <MyButton width={150} fillet onClick={again}></MyButton>} <View>
{index !== 0 && <MyButton size='mini' width={150} onClick={() => setIndex(index - 1)}></MyButton>}
</View>
<View>
{
(index + 1) !== examAll?.[time]?.length
&& <MyButton size='mini' width={150} onClick={() => setIndex(index + 1)}></MyButton>
}
</View>
</View>
</View> </View>
</CustomPageContainer> </CustomPageContainer>
</View> </View>

@ -53,7 +53,7 @@ const Hours: FC<Props> = ({data, click, learn_hour_records}) => {
} }
if (upId && complete(upId) !== 1) { if (upId && complete(upId) !== 1) {
Taro.showModal({title: '请完成上一个视频'}) Taro.showToast({title: '禁止播放', icon: 'none'})
return return
} }
@ -63,14 +63,14 @@ const Hours: FC<Props> = ({data, click, learn_hour_records}) => {
return ( return (
<> <>
{data?.map((d, index) => {data?.map((d, index) =>
<View className={'hor' + ` ${complete(d.id) ? 'complete' : null}`} <View className={'hor' + ` ${complete(d.id) ? 'complete' : undefined}`}
key={index} key={index}
onClick={() => onClick(d.id, complete(d.id), d, data?.[index - 1]?.id,)}> onClick={() => onClick(d.id, complete(d.id), d, data?.[index - 1]?.id)}>
<Image src={complete(d.id) ? playOk : play} mode="scaleToFill" className='image'/> <Image src={complete(d.id) ? playOk : play} mode="scaleToFill" className='image'/>
<View className='title'> <View className='title'>
<View className='text'> <View className='text'>
<View>{index + 1}.{d.title}</View> <View>{index + 1}.{d.title}</View>
<View className='font-26'>{formatMinute(d.duration)}</View> <View className='font-26 text-muted'>{formatMinute(d.duration)}</View>
{complete(d.id) === 0 && <View className='font-26 text-danger'></View>} {complete(d.id) === 0 && <View className='font-26 text-danger'></View>}
</View> </View>
{ {

@ -26,7 +26,7 @@
background: #fff; background: #fff;
border-radius: 40rpx; border-radius: 40rpx;
padding: 0 24rpx 24rpx; padding: 0 24rpx 24rpx;
margin-top: 20rpx; margin-top: 30rpx;
.short_desc { .short_desc {
color: #606563; color: #606563;
@ -36,8 +36,9 @@
} }
.hor { .hor {
padding: 20px 0; padding: 20rpx 0;
display: flex; display: flex;
color: #323635;
.image { .image {
width: 40rpx; width: 40rpx;
@ -49,7 +50,7 @@
.title { .title {
flex: 1; flex: 1;
width: 710rpx; width: 710rpx;
padding: 0 0 20rpx 20rpx; padding: 0 0 30rpx 20rpx;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
box-sizing: border-box; box-sizing: border-box;

@ -6,6 +6,7 @@ import Catalogue from "./components/catalogue";
import Course from "./components/course"; import Course from "./components/course";
import Taro from "@tarojs/taro"; import Taro from "@tarojs/taro";
import eventsIndex from "@/hooks/eventsIndex"; import eventsIndex from "@/hooks/eventsIndex";
import {formatMinute} from "@/utils/time";
const VideoInfo: FC = () => { const VideoInfo: FC = () => {
const {id, depId} = Taro.getCurrentInstance()?.router?.params as any const {id, depId} = Taro.getCurrentInstance()?.router?.params as any
@ -14,10 +15,6 @@ const VideoInfo: FC = () => {
const [preview, setPreview] = useState(false) const [preview, setPreview] = useState(false)
const [playing, setPlaying] = useState(false) const [playing, setPlaying] = useState(false)
// Taro.useSaveExitState(() => ({
// data: {playId}
// }))
const getData = useCallback(async () => { const getData = useCallback(async () => {
const res = await curriculum.courseDep(id, depId) const res = await curriculum.courseDep(id, depId)
if (res) { if (res) {
@ -110,11 +107,12 @@ const VideoInfo: FC = () => {
<View className='header'> <View className='header'>
<View className='flex justify-between text-muted'> <View className='flex justify-between text-muted'>
<Text className='font-34 text-warning'>{data?.is_required ? '必修' : '选修'}</Text> <Text className='font-34 text-warning'>{data?.is_required ? '必修' : '选修'}</Text>
<Text>{data?.course.class_hour}</Text> <Text className='font-24'>{data?.course.class_hour}</Text>
</View> </View>
<View className='font-weight font-40 my-3'>{data?.course.title}</View> <View className='font-weight font-36 my-2'>{data?.course.title}</View>
<View className='text-muted font-26'> <View className='text-muted font-26 mt-3'>
<Text>{data?.learn_hour_records.length || 0}/{data?.course.class_hour}</Text> <Text className='mr-2'>{formatMinute(data?.duration || 0)}</Text>
<Text>{((data?.learn_hour_records.length || 0) / (data?.course.class_hour || 1) * 100).toFixed(0)}%</Text>
</View> </View>
</View> </View>
<Catalogue data={data} setHors={setHors} id={id} playId={playId}/> <Catalogue data={data} setHors={setHors} id={id} playId={playId}/>

@ -8,17 +8,19 @@ page,
min-height: 100vh; min-height: 100vh;
} }
body {
font-size: 32rpx;
}
.weui-cells_checkbox .weui-check:checked + .weui-icon-checked:before,
.taro-checkbox_checked{
color: #45D4A8 !important;
}
taro-button-core::after { taro-button-core::after {
border: none !important; border: none !important;
} }
body {
font-size: 32rpx;
}
.input { .input {
background: #F5F8F7; background: #F5F8F7;
border-radius: 8px; border-radius: 8px;

Loading…
Cancel
Save