feat: 调试练题

This commit is contained in:
秋水浮尘
2024-04-13 23:41:51 +08:00
parent 6734fa72b5
commit f84a199e5c
42 changed files with 734 additions and 1338 deletions

View File

@@ -13,7 +13,7 @@ const MENULIST = [
{ {
key: 'prictiseQuestion', key: 'prictiseQuestion',
title: '练题', title: '练题',
route: '/practice-questions', route: '/practise-questions',
finished: true finished: true
}, },
{ {

View File

@@ -40,16 +40,16 @@ const router = createBrowserRouter([
Component: lazy(() => import('@views/personal-center')) Component: lazy(() => import('@views/personal-center'))
}, },
{ {
path: 'practice-questions', path: 'practise-questions',
Component: lazy(() => import('@views/practise/practice-questions')) Component: lazy(() => import('@views/practise/practise-questions'))
}, },
{ {
path: 'practice-detail/:id', path: 'practise-detail/:setId',
Component: lazy(() => import('@views/practise/practice-details/index1.jsx')) Component: lazy(() => import('@views/practise/practise-details/index.jsx'))
}, },
{ {
path: 'practice-analytic/:id', path: 'practise-analytic/:id',
Component: lazy(() => import('@views/practise/practice-analytic')) Component: lazy(() => import('@views/practise/practise-analytic'))
} }
] ]
} }

View File

@@ -1,312 +0,0 @@
import AnalysisAtlas from '@components/analysis-atlas'
import { splicingQuery } from '@utils'
import req from '@utils/request'
import { Button, Spin } from 'antd'
import React, { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { ApiName, ModuleName } from '../../constant'
import RecommendList from '../recommend-list'
import './index.less'
const AssessmentReport = props => {
const navigate = useNavigate()
const [title, setTitle] = useState('测试试卷')
const [correctSubject, setCorrectSubject] = useState('3')
const [spinning, setSpinning] = useState(false)
const [recommendSetList, setRecommendSetList] = useState([])
const [skill, setSkill] = useState([
{
name: '名称1',
star: 50
},
{
name: '名称2',
star: 70
},
{
name: '名称3',
star: 90
},
{
name: '名称4',
star: 80
}
])
useEffect(() => {}, [])
/**
* 答案解析-获得评估报告
*/
const getReport = async () => {
const { practiceId } = this.props
let params = {
practiceId: practiceId
}
await req({
method: 'post',
data: params,
url: ApiName.getReport
})
.then(res => {
if (res?.data) {
let list = res.data.skill || []
let len = res.data.skill.length
if (len === 1) {
let l1 = [
{ name: res.data.skill[0].name + ' ', star: res.data.skill[0].star },
{
name: ' ' + res.data.skill[0].name + ' ',
star: res.data.skill[0].star
}
]
list = list.concat(l1)
} else if (len === 2) {
let l1 = [{ name: res.data.skill[1].name + ' ', star: res.data.skill[1].star }]
list = list.concat(l1)
}
this.setState({
isLoading: false,
title: res.data.title,
correctSubject: res.data.correctSubject,
recommendSetList: res.data.recommendSetList,
skill: list
})
}
})
.catch(err => console.log(err))
}
/**
* 练习其他技能
*/
const onChangePracticeOther = () => {
// this.props.history.push('/practice-questions')
navigate('/practice-questions')
}
/**
* 查看答案解析
*/
const onChangeAnswerAnalysis = () => {
props.onHandleAnswerAnalysis && props.onHandleAnswerAnalysis(ModuleName.analysis)
}
/**
* 点击推荐套题
* @param {*} setId
* @returns
*/
const onChangeSetId = setId => {
this.props.history.push(
splicingQuery('/practice-details', {
setId
})
)
}
return (
<Spin spinning={spinning}>
<div className='assessment-report-box'>
<div className='assessment-report-top'>
<div className='assessment-report-main'>
{/* <div className="assessment-report-defen">
<img src={ImgObj.defen} className="assessment-report-defen-icon" />
得分12
</div> */}
<div className='assessment-report-item'>试卷{title}</div>
<div className='assessment-report-item'>正确题数{correctSubject}</div>
<Button
className='assessment-report-submit'
type='primary'
onClick={onChangePracticeOther}
>
练习其他技能
</Button>
</div>
<div className='assessment-report-tupu'>
<div className='assessment-report-tupu-tip'>你的技能图谱</div>
<div className='assessment-report-tupu-content'>
<AnalysisAtlas
aliasStr='正确率'
atlasList={skill || []}
atlasMin={-25}
atlasWidth={200}
atlasHeight={200}
/>
</div>
</div>
</div>
{recommendSetList?.length > 0 && (
<RecommendList recommendSetList={recommendSetList} onHandleSetId={onChangeSetId} />
)}
<div className='assessment-report-answer-analysis'>
<Button
className='assessment-report-answer-btn'
type='primary'
onClick={onChangeAnswerAnalysis}
>
查看答案解析
</Button>
</div>
</div>
</Spin>
)
}
// class AssessmentReport extends Component {
// constructor(props) {
// super(props)
// this.state = {
// correctSubject: '3',
// recommendSetList: [],
// skill: [
// {
// name: '名称1',
// star: 50
// },
// {
// name: '名称2',
// star: 70
// },
// {
// name: '名称3',
// star: 90
// },
// {
// name: '名称4',
// star: 80
// }
// ],
// title: '测试试卷',
// isLoading: false
// }
// }
// componentDidMount() {
// this.getReport()
// }
// /**
// * 答案解析-获得评估报告
// */
// getReport = async () => {
// const { practiceId } = this.props
// let params = {
// practiceId: practiceId
// }
// await req({
// method: 'post',
// data: params,
// url: ApiName.getReport
// })
// .then(res => {
// if (res?.data) {
// let list = res.data.skill || []
// let len = res.data.skill.length
// if (len === 1) {
// let l1 = [
// { name: res.data.skill[0].name + ' ', star: res.data.skill[0].star },
// {
// name: ' ' + res.data.skill[0].name + ' ',
// star: res.data.skill[0].star
// }
// ]
// list = list.concat(l1)
// } else if (len === 2) {
// let l1 = [{ name: res.data.skill[1].name + ' ', star: res.data.skill[1].star }]
// list = list.concat(l1)
// }
// this.setState({
// isLoading: false,
// title: res.data.title,
// correctSubject: res.data.correctSubject,
// recommendSetList: res.data.recommendSetList,
// skill: list
// })
// }
// })
// .catch(err => console.log(err))
// }
// /**
// * 练习其他技能
// */
// onChangePracticeOther = () => {
// this.props.history.push('/practice-questions')
// }
// /**
// * 查看答案解析
// */
// onChangeAnswerAnalysis = () => {
// this.props.onHandleAnswerAnalysis && this.props.onHandleAnswerAnalysis(ModuleName.analysis)
// }
// /**
// * 点击推荐套题
// * @param {*} setId
// * @returns
// */
// onChangeSetId = setId => {
// this.props.history.push(
// splicingQuery('/practice-details', {
// setId
// })
// )
// }
// render() {
// const { correctSubject, recommendSetList, skill, title, isLoading } = this.state
// return (
// <Spin spinning={isLoading}>
// <div className='assessment-report-box'>
// <div className='assessment-report-top'>
// <div className='assessment-report-main'>
// {/* <div className="assessment-report-defen">
// <img src={ImgObj.defen} className="assessment-report-defen-icon" />
// 得分12
// </div> */}
// <div className='assessment-report-item'>试卷:{title}</div>
// <div className='assessment-report-item'>正确题数:{correctSubject}</div>
// <Button
// className='assessment-report-submit'
// type='primary'
// onClick={this.onChangePracticeOther}
// >
// 练习其他技能
// </Button>
// </div>
// <div className='assessment-report-tupu'>
// <div className='assessment-report-tupu-tip'>你的技能图谱</div>
// <div className='assessment-report-tupu-content'>
// <AnalysisAtlas
// aliasStr='正确率'
// atlasList={skill || []}
// atlasMin={-25}
// atlasWidth={200}
// atlasHeight={200}
// />
// </div>
// </div>
// </div>
// {recommendSetList?.length > 0 && (
// <RecommendList recommendSetList={recommendSetList} onHandleSetId={this.onChangeSetId} />
// )}
// <div className='assessment-report-answer-analysis'>
// <Button
// className='assessment-report-answer-btn'
// type='primary'
// onClick={this.onChangeAnswerAnalysis}
// >
// 查看答案解析
// </Button>
// </div>
// </div>
// </Spin>
// )
// }
// }
export default AssessmentReport

View File

@@ -1,53 +0,0 @@
export const ModuleName = {
/**
* 评估报告
*/
assessment: 'assessment',
/**
* 答案解析
*/
analysis: 'analysis',
};
export const ImgObj = {
defen: 'https://img10.360buyimg.com/imagetools/jfs/t1/197806/1/18639/2369/61a095a8E09f4e860/493d753073a4a9fa.png',
};
export const ApiName = {
/**
* 获得评价
*/
getReport: '/admin/practice/detail/getReport',
/**
* 答案详情
*/
getSubjectDetail: '/admin/practice/detail/getSubjectDetail',
/**
* 获得题号
*/
getScoreDetail: 'admin/practice/detail/getScoreDetail',
};
/**
* id对应字母
*/
export const IdKeyLetterKey = {
1: 'A',
2: 'B',
3: 'C',
4: 'D',
5: 'E',
6: 'F',
7: 'G',
8: 'H',
};
/**
* 推荐对应的背景图
*/
export const RecommendBackImg = {
0: 'https://img11.360buyimg.com/imagetools/jfs/t1/202713/11/17151/312/61a5dea1E5623fea6/2922d716cae01b28.png',
1: 'https://img10.360buyimg.com/imagetools/jfs/t1/142359/35/22866/2975/61a5dea0E3fcd563c/78ee45555dd19cda.png',
2: 'https://img13.360buyimg.com/imagetools/jfs/t1/161380/34/26207/1078/61a5dea0E7824463e/4e18f74e8c6439ad.png',
3: 'https://img14.360buyimg.com/imagetools/jfs/t1/160815/15/27226/880/61a5e1e6E152b08b7/fb698b8321d08246.png',
};

View File

@@ -1,69 +0,0 @@
import { Tabs } from 'antd'
import React, { Component } from 'react'
import AnswerAnalysis from './components/answer-analysis'
import AssessmentReport from './components/assessment-report'
import { ModuleName } from './constant'
import './index.less'
const { TabPane } = Tabs
const practiceAnalyticTabList = [
{ tab: '评估报告', key: ModuleName.assessment },
{ tab: '答案解析', key: ModuleName.analysis }
]
export default class PracticeAnalytic extends Component {
constructor(props) {
super(props)
this.state = { currentKey: ModuleName.assessment }
}
/**
* 切换card tab
* @param {*} key
*/
onTabChange = key => {
this.setState({ currentKey: key })
}
render() {
const { currentKey } = this.state
console.log(this.props)
// const urlParams = queryParse(this.props.location.search)
// if (!urlParams.practiceId) {
// return null
// }
return (
<div className='practice-analytic-box'>
<Tabs
size='default'
type='card'
style={{ width: '100%' }}
activeKey={currentKey}
defaultActiveKey={currentKey}
tabBarStyle={{
height: '41px',
background: '#fff',
borderBottom: '1px solid #1890ff',
margin: 0
}}
onChange={key => {
this.onTabChange(key, 'key')
}}
>
{practiceAnalyticTabList.map(item => {
return <TabPane tab={item.tab} key={item.key}></TabPane>
})}
</Tabs>
{currentKey == ModuleName.assessment ? (
<AssessmentReport
onHandleAnswerAnalysis={key => {
this.onTabChange(key, 'key')
}}
practiceId={1}
/>
) : (
<AnswerAnalysis practiceId={1} />
)}
</div>
)
}
}

View File

@@ -1,43 +0,0 @@
export const mark = {
0: '标记一下',
1: '已标记',
};
export const collection = {
0: '未收藏',
1: '已收藏',
};
export const quetionsType = {
1: '单选题',
2: '多选题',
3: '判断题',
};
export const ApiName = {
/**
* 获取练习题目
*/
getSubjects: '/admin/practice/set/getSubjects',
/**
* 获取练习题目详情
*/
getPracticeSubject: '/admin/practice/set/getPracticeSubject',
/**
* 交卷
*/
submitSubject: '/admin/practice/detail/submit',
};
export const ImgObj = {
stop: 'https://img10.360buyimg.com/imagetools/jfs/t1/206561/1/10729/2819/619f783cE77dd49ed/54eb1fc4b3144a97.png',
run: 'https://img11.360buyimg.com/imagetools/jfs/t1/161735/6/25253/2598/619f783cEa897a673/fbf4e8c05d40feb5.png',
info: 'https://img13.360buyimg.com/imagetools/jfs/t1/217399/4/5733/2641/619f7b91E0894649e/2f6353fe0d35fb46.png',
questionMark:
'https://img12.360buyimg.com/imagetools/jfs/t1/201809/8/16630/2674/61a04963E92475548/ede8a7f006113cae.png',
mark: 'https://img12.360buyimg.com/imagetools/jfs/t1/207329/30/11079/2474/61a70ad0E64730d1c/ed75ee746fb33926.png',
advanceTip:
'https://img11.360buyimg.com/imagetools/jfs/t1/161028/16/25609/6746/61a08d83E06659dfa/e6418acdab948134.png',
};

View File

@@ -1,511 +0,0 @@
import Timer from '@components/timerCom/FlipClock'
import { getCurrentTime, splicingQuery } from '@utils'
import req from '@utils/request'
import { Checkbox, Modal, Radio } from 'antd'
import _ from 'lodash'
import React, { Component } from 'react'
import PracticeAction from './components/practice-action'
import PracticeAdvance from './components/practice-advance'
import PracticePaging from './components/practice-paging'
import { ApiName, ImgObj, quetionsType } from './constant'
import './index.less'
export default class PracticeDetails extends Component {
constructor(props) {
super(props)
this.state = {
isMark: 0, // 是否标记
isCollection: 0,
currentActive: '',
subjectList: [], // 总题目列表
subjectObject: {}, //题目
currentIndex: 0,
isShowAdvanOverceBox: false,
isShowStopBox: false
}
}
timerRef = React.createRef()
subjectTitle = ''
singleLength = 0
multipleLength = 0
judgeLength = 0
setId = ''
componentDidMount() {
// const urlParams = queryParse(this.props.location.search)
// this.setId = urlParams.setId
this.getSubjectList()
this.timerRef.current.run()
// window.addEventListener('beforeunload', this.listener);
}
componentWillUnmount() {
// window.addEventListener('beforeunload', this.listener);
}
//监听屏幕刷新,关闭默认事件,界面没有动,不会拦截
listener = ev => {
ev.preventDefault()
ev.returnValue = ''
}
/**
* 获得题目列表
*/
getSubjectList = () => {
let params = {
setId: this.setId
}
this.subjectTitle = '热门题目练习'
this.singleLength = 1
this.multipleLength = 1
this.judgeLength = 1
const list = [
{
subjectType: 1,
subjectId: 1
},
{
subjectType: 2,
subjectId: 2
},
{
subjectType: 3,
subjectId: 3
}
]
this.setState({
subjectList: [...list]
})
_.set(list, [0, 'active'], true)
this.getPracticeSubject(list[0], list, 0, [])
// req({
// method: 'post',
// data: params,
// url: ApiName.getSubjects
// })
// .then(res => {
// if (res.data && res.data?.subjectList?.length > 0) {
// let list = res.data.subjectList
// this.singleLength =
// list?.length > 0 ? list.filter(item => item.subjectType === 1).length : 0
// this.multipleLength =
// list?.length > 0 ? list.filter(item => item.subjectType === 2).length : 0
// this.judgeLength =
// list?.length > 0 ? list.filter(item => item.subjectType === 3).length : 0
// this.subjectTitle = res.data?.title || '' // 总题目列表
// this.getPracticeSubject(list[0], list, 0, [])
// }
// })
// .catch(err => console.log(err))
}
/**
* 获得题目详情
* @param {*} item 选择的项
* @param {*} subjectList 题目列表
* @param {*} index 选择的下标
* @param {*} activeList 选中的列表
* @param {*} isMark 是否被标记
*/
getPracticeSubject = (item, subjectList, index, activeList, isMark = 0) => {
let params = {
subjectId: item.subjectId,
subjectType: item.subjectType
}
const optionList =
item.subjectType === 3
? [
{
optionContent: '正确',
optionType: 1
},
{
optionContent: '错误',
optionType: 0
}
]
: [
{
optionType: 1,
optionContent: '<p>题目答案1</p>'
},
{
optionType: 2,
optionContent: '<p>题目答案2</p>'
},
{
optionType: 3,
optionContent: '<p>题目答案3</p>'
}
]
return this.setState({
currentIndex: index,
currentActive: item.subjectType === 2 ? activeList : activeList[0],
subjectObject: {
subjectName: '题干内容',
subjectType: item.subjectType,
optionList,
// subjectList: subjectList,
// currentIndex: index,
// currentActive: item.sub??jectType === 2 ? activeList : activeList[0],
isMark: isMark
}
})
req({
method: 'post',
data: params,
url: ApiName.getPracticeSubject
})
.then(res => {
if (res.data) {
let subjectObject = res.data
if (item.subjectType === 3) {
subjectObject.optionList = [
{
optionContent: '正确',
optionType: 1
},
{
optionContent: '错误',
optionType: 0
}
]
}
this.setState({
subjectObject: res.data,
subjectList: subjectList,
currentIndex: index,
currentActive: item.subjectType === 2 ? activeList : activeList[0],
isMark: isMark
})
}
})
.catch(err => console.log(err))
}
/**
* 选择单选
* @param {*} e
* @returns
*/
onChangeRadio = e => () => {
let { currentIndex, subjectList } = this.state
_.set(subjectList, [currentIndex, 'activeList'], [e])
this.setState({
currentActive: e,
subjectList
})
}
/**
* 选择多选
* @param {*} e
* @returns
*/
onChangeCheck = e => {
let { currentIndex, subjectList } = this.state
_.set(subjectList, [currentIndex, 'activeList'], e)
this.setState({
currentActive: e,
subjectList
})
}
/**
* 暂停计时
*/
onChangeStop = () => {
this.setState({ isShowStopBox: true })
this.timerRef.current.stop()
}
/**
* 标记一下
*/
onChangeMark = () => {
let { currentIndex, subjectList, subjectObject } = this.state
let flag = 1
if (subjectList[currentIndex]?.isMark) {
flag = 0
}
_.set(subjectList, [currentIndex, 'isMark'], flag)
this.setState({
subjectList,
isMark: flag,
subjectObject
})
}
/**
* 选择答题卡
* @param {*} index
* @param {*} item
* @returns
*/
onChangePaging = index => {
let { currentIndex } = this.state
// 如果点击当前题目直接return
if (currentIndex === index) {
return
}
this.changeData(index)
}
/**
* 交卷
*/
onChangeOver = () => {
const { subjectList } = this.state
let answerDetails = []
subjectList.forEach(item => {
let obj = {
subjectId: item.subjectId,
subjectType: item.subjectType,
answerContents: []
}
if (item?.activeList && item?.activeList?.length > 0) {
obj.answerContents = item.activeList
}
answerDetails.push(obj)
})
let params = {
setId: this.setId,
timeUse: this.timerRef.current.getUseTime(),
submitTime: getCurrentTime(),
answerDetails: answerDetails
}
req({
method: 'post',
data: params,
url: ApiName.submitSubject
})
.then(res => {
if (res.data && res.data.practiceId) {
//关闭定时器
this.timerRef.current.end()
this.props.history.replace(
splicingQuery('/practice-analytic', {
practiceId: res.data.practiceId
})
)
}
})
.catch(err => console.log(err))
}
/**
* 提前交卷弹框-直接交卷
*/
onHandleSubmitModal = () => {
this.onChangeOver()
}
/**
* 提前交卷弹框-继续做题
*/
onHandleCancelModal = () => {
this.setState({ isShowAdvanOverceBox: false })
}
/**
* 提前交卷
*/
onChangeAdvanceOver = () => {
this.setState({
isShowAdvanOverceBox: true
})
}
/**
* 下一题
* @returns
*/
onChangeNext = () => {
let { currentIndex } = this.state
currentIndex += 1
this.changeData(currentIndex)
}
/**
* 改变数据
* @param {*} index 当前点击下标
*/
changeData = index => {
let { subjectList } = this.state
let subObj = subjectList[index]
let activeList = [] // 多选 选中的答案项
let isMark = 0 // 是否被标记
// 将其他item设置为未选中
subjectList.forEach(item => {
item.active = false
})
_.set(subjectList, [index, 'active'], true)
// if当前选择的有选答案则直接显示出来
if (subObj?.activeList?.length > 0) {
activeList = subObj?.activeList
}
// if当前已被标记则直接显示出来
if (subObj?.isMark == 1) {
isMark = 1
}
this.getPracticeSubject(subObj, subjectList, index, activeList, isMark)
}
/**
* 暂停弹框-继续做题
*/
onChangeSubmitModal = () => {
this.timerRef.current.run()
this.setState({ isShowStopBox: false })
}
/**
* 暂停弹框-再次再做
*/
onChangeCancelModal = () => {
this.props.history.goBack()
}
render() {
const {
isMark,
isCollection,
currentIndex,
currentActive,
subjectList,
subjectObject,
isShowAdvanOverceBox,
isShowStopBox
} = this.state
const isLast = currentIndex === subjectList?.length - 1
// 获得已答的题目个数
const noAnswerNum =
subjectList.filter(item => item.activeList && item.activeList.length > 0).length || 0
return (
<div className='details-container'>
<div className='container-box'>
<div className='container-box-title'>
<div className='title-title'>{this.subjectTitle}</div>
<div className='title-time'>
<div className='title-timer-img' onClick={this.onChangeStop}>
<img src={isShowStopBox ? ImgObj.stop : ImgObj.run} className='title-timer-icon' />
</div>
<Timer ref={this.timerRef} />
</div>
</div>
<div className='details-question-number'>
<div className='question-number-number'>
{currentIndex + 1}/{subjectList?.length}
</div>
<img src={ImgObj.questionMark} className='question-number-mark' />
<div className='question-number-type'>[{quetionsType[subjectObject.subjectType]}]</div>
</div>
<div className='practice-main'>
<div className='practice-text'>
<div className='practice-question'>{subjectObject.subjectName}</div>
{subjectObject.subjectType === 2 ? (
<Checkbox.Group
className='practice-answer-list'
onChange={this.onChangeCheck}
value={currentActive || []}
key={currentIndex}
>
{subjectObject?.optionList?.length > 0 &&
subjectObject?.optionList.map(item => {
return (
<Checkbox
key={item.optionType}
className={`practice-answer-item ${
currentActive.includes(item.optionType)
? 'practice-answer-item-active'
: ''
}`}
value={item.optionType}
>
<div
dangerouslySetInnerHTML={{
__html: item.optionContent
}}
></div>
</Checkbox>
)
})}
</Checkbox.Group>
) : (
<Radio.Group
className='practice-answer-list'
value={currentActive}
key={currentIndex}
>
{subjectObject?.optionList?.length > 0 &&
subjectObject?.optionList.map(item => {
return (
<Radio
key={item.optionType}
onClick={this.onChangeRadio(item.optionType)}
className={`practice-answer-item ${
currentActive === item.optionType ? 'practice-answer-item-active' : ''
}`}
value={item.optionType}
>
<div
dangerouslySetInnerHTML={{
__html: item.optionContent
}}
></div>
</Radio>
)
})}
</Radio.Group>
)}
</div>
<PracticeAction
isLast={isLast}
isMark={isMark}
onHandleMark={this.onChangeMark}
onHandleOver={this.onChangeOver}
onHandleAdvanceOver={this.onChangeAdvanceOver}
onHandleNext={this.onChangeNext}
/>
</div>
<PracticePaging
subjectList={subjectList}
onHandlePaging={this.onChangePaging}
singleLength={this.singleLength}
multipleLength={this.multipleLength}
judgeLength={this.judgeLength}
/>
</div>
<PracticeAdvance
isShowModalBox={isShowAdvanOverceBox}
onHandleSubmitModal={this.onHandleSubmitModal}
onHandleCancelModal={this.onHandleCancelModal}
/>
<Modal
closable={false}
maskClosable={false}
style={{ padding: 20 }}
open={isShowStopBox}
onOk={this.onChangeSubmitModal}
onCancel={this.onChangeCancelModal}
okText='继续做题'
cancelText='下次再做'
>
<div style={{ padding: 40 }}>
<img src={ImgObj.info} className='details-container-box-info' />
休息一下吧{subjectList?.length}道题还剩
{subjectList?.length - noAnswerNum}道没做哦
</div>
</Modal>
</div>
)
}
}

View File

@@ -1,24 +0,0 @@
.front-box {
.ant-descriptions-title {
display: flex;
justify-content: space-between;
font-size: 18px;
color: rgba(51, 51, 51, 0.7);
}
.ant-checkbox-wrapper {
font-size: 14px;
color: rgba(51, 51, 51, 0.5);
}
.box {
display: flex;
width: 1200px;
.box1 {
flex: 1;
}
.box2 {
flex: 1;
// float: right;
text-align: right;
}
}
}

View File

@@ -1,90 +0,0 @@
import req from '@utils/request'
import { Card, Checkbox, Descriptions } from 'antd'
import { useEffect, useState } from 'react'
const apiName = {
/**
* 查询大类
*/
queryPrimaryCategory: '/category/queryPrimaryCategory',
// 查询分类及标签
queryCategoryAndLabel: '/category/queryCategoryAndLabel'
}
const PracticeHome = () => {
const [primaryList, setPrimaryList] = useState<Record<string, any>[]>([])
const [cateAndLabelList, setCateAndLabelList] = useState<Record<string, any>[]>([])
const [currentPrimaryId, setCurrentPrimaryId] = useState()
const queryPrimaryList = () => {
req({
method: 'post',
url: apiName.queryPrimaryCategory,
data: { categoryType: 1 }
})
.then((res: Record<string, any>) => {
if (res.data && res.data.length > 0) {
setCurrentPrimaryId(res.data[0].id)
setPrimaryList([...res.data].map(t => ({ tab: t.categoryName, key: t.id })))
}
})
.catch(err => {
console.log(err)
})
}
useEffect(() => {
queryPrimaryList()
}, [])
const getCategoryAndLabel = () => {
req({
method: 'post',
url: apiName.queryCategoryAndLabel,
data: { id: currentPrimaryId }
})
.then(res => {
if (res.data && res.data.length > 0) {
res.data = res.data.map(item => {
return {
...item,
children: item.labelDTOList.map(t => ({ label: t.labelName, value: t.id }))
}
})
setCateAndLabelList([...res.data])
}
})
.catch(err => {
console.log(err)
})
}
useEffect(() => {
if (currentPrimaryId) {
getCategoryAndLabel()
}
}, [currentPrimaryId])
return (
<div>
<Card tabList={primaryList}>
{cateAndLabelList.map(item => {
return (
<Descriptions title={item.categoryName} extra={<Checkbox></Checkbox>}>
<Descriptions.Item label=''>
<Checkbox.Group
// value={secondItem.activeList}
options={item.children}
// onChange={this.onChange(secondIndex)}
/>
</Descriptions.Item>
</Descriptions>
)
})}
</Card>
</div>
)
}
export default PracticeHome

View File

@@ -32,11 +32,14 @@ export default class AnswerAnalysis extends Component {
let params = { let params = {
practiceId: practiceId practiceId: practiceId
} }
req({ req(
{
method: 'post', method: 'post',
data: params, data: params,
url: ApiName.getScoreDetail url: ApiName.getScoreDetail
}) },
'/practice'
)
.then(res => { .then(res => {
if (res?.data && res?.data?.length > 0) { if (res?.data && res?.data?.length > 0) {
this.setState( this.setState(
@@ -64,11 +67,14 @@ export default class AnswerAnalysis extends Component {
subjectId: subjectItem.subjectId, subjectId: subjectItem.subjectId,
subjectType: subjectItem.subjectType subjectType: subjectItem.subjectType
} }
JDreq({ req(
{
method: 'post', method: 'post',
data: params, data: params,
url: ApiName.getSubjectDetail url: ApiName.getSubjectDetail
}) },
'/practice'
)
.then(res => { .then(res => {
if (res.data) { if (res.data) {
let respondAnswer = res.data.respondAnswer let respondAnswer = res.data.respondAnswer

View File

@@ -0,0 +1,138 @@
import AnalysisAtlas from '@components/analysis-atlas'
import { splicingQuery } from '@utils'
import req from '@utils/request'
import { Button, Spin } from 'antd'
import React, { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { ApiName, ModuleName } from '../../constant'
import RecommendList from '../recommend-list'
import './index.less'
const AssessmentReport = props => {
const navigate = useNavigate()
const [title, setTitle] = useState('测试试卷')
const [correctSubject, setCorrectSubject] = useState('3')
const [spinning, setSpinning] = useState(false)
const [recommendSetList, setRecommendSetList] = useState([])
const [skill, setSkill] = useState([])
useEffect(() => {
getReport()
}, [props.practiceId])
/**
* 答案解析-获得评估报告
*/
const getReport = async () => {
const { practiceId } = props
let params = {
practiceId
}
await req(
{
method: 'post',
data: params,
url: ApiName.getReport
},
'/practice'
)
.then(res => {
if (res?.data) {
const { skill, correctSubject, title } = res.data
let list = skill || []
let len = skill.length
if (len === 1) {
let l1 = [
{ name: skill[0].name + ' ', star: skill[0].star },
{
name: ' ' + skill[0].name + ' ',
star: skill[0].star
}
]
list = list.concat(l1)
} else if (len === 2) {
let l1 = [{ name: skill[1].name + ' ', star: skill[1].star }]
list = list.concat(l1)
}
setSkill(list)
setCorrectSubject(correctSubject)
setTitle(title)
}
})
.catch(err => console.log(err))
}
/**
* 练习其他技能
*/
const onChangePracticeOther = () => {
navigate('/practise-questions')
}
/**
* 查看答案解析
*/
const onChangeAnswerAnalysis = () => {
props.onHandleAnswerAnalysis && props.onHandleAnswerAnalysis(ModuleName.analysis)
}
/**
* 点击推荐套题
* @param {*} setId
* @returns
*/
const onChangeSetId = setId => {
this.props.history.push(
splicingQuery('/practise-details', {
setId
})
)
}
return (
<Spin spinning={spinning}>
<div className='assessment-report-box'>
<div className='assessment-report-top'>
<div className='assessment-report-main'>
<div className='assessment-report-item'>试卷{title}</div>
<div className='assessment-report-item'>正确题数{correctSubject}</div>
<Button
className='assessment-report-submit'
type='primary'
onClick={onChangePracticeOther}
>
练习其他技能
</Button>
</div>
<div className='assessment-report-tupu'>
<div className='assessment-report-tupu-tip'>你的技能图谱</div>
<div className='assessment-report-tupu-content'>
<AnalysisAtlas
aliasStr='正确率'
atlasList={skill || []}
atlasMin={-25}
atlasWidth={200}
atlasHeight={200}
/>
</div>
</div>
</div>
{recommendSetList?.length > 0 && (
<RecommendList recommendSetList={recommendSetList} onHandleSetId={onChangeSetId} />
)}
<div className='assessment-report-answer-analysis'>
<Button
className='assessment-report-answer-btn'
type='primary'
onClick={onChangeAnswerAnalysis}
>
查看答案解析
</Button>
</div>
</div>
</Spin>
)
}
export default AssessmentReport

View File

@@ -0,0 +1,54 @@
export const ModuleName = {
/**
* 评估报告
*/
assessment: 'assessment',
/**
* 答案解析
*/
analysis: 'analysis'
}
export const ImgObj = {
defen:
'https://img10.360buyimg.com/imagetools/jfs/t1/197806/1/18639/2369/61a095a8E09f4e860/493d753073a4a9fa.png'
}
export const ApiName = {
/**
* 获得评价
*/
getReport: '/practice/detail/getReport',
/**
* 答案详情
*/
getSubjectDetail: '/practice/detail/getSubjectDetail',
/**
* 获得题号
*/
getScoreDetail: '/practice/detail/getScoreDetail'
}
/**
* id对应字母
*/
export const IdKeyLetterKey = {
1: 'A',
2: 'B',
3: 'C',
4: 'D',
5: 'E',
6: 'F',
7: 'G',
8: 'H'
}
/**
* 推荐对应的背景图
*/
export const RecommendBackImg = {
0: 'https://img11.360buyimg.com/imagetools/jfs/t1/202713/11/17151/312/61a5dea1E5623fea6/2922d716cae01b28.png',
1: 'https://img10.360buyimg.com/imagetools/jfs/t1/142359/35/22866/2975/61a5dea0E3fcd563c/78ee45555dd19cda.png',
2: 'https://img13.360buyimg.com/imagetools/jfs/t1/161380/34/26207/1078/61a5dea0E7824463e/4e18f74e8c6439ad.png',
3: 'https://img14.360buyimg.com/imagetools/jfs/t1/160815/15/27226/880/61a5e1e6E152b08b7/fb698b8321d08246.png'
}

View File

@@ -0,0 +1,56 @@
import { Tabs } from 'antd'
import React, { useState } from 'react'
import { useParams } from 'react-router-dom'
import AnswerAnalysis from './components/answer-analysis'
import AssessmentReport from './components/assessment-report'
import { ModuleName } from './constant'
import './index.less'
const { TabPane } = Tabs
const practiceAnalyticTabList = [
{ tab: '评估报告', key: ModuleName.assessment },
{ tab: '答案解析', key: ModuleName.analysis }
]
const PracticeAnalytic = () => {
const [currentKey, setCurrentKey] = useState(ModuleName.assessment)
const { id } = useParams()
/**
* 切换card tab
* @param {*} key
*/
const onTabChange = key => {
setCurrentKey(key)
}
return (
<div className='practice-analytic-box'>
<Tabs
size='default'
type='card'
style={{ width: '100%' }}
activeKey={currentKey}
defaultActiveKey={currentKey}
tabBarStyle={{
height: '41px',
background: '#fff',
borderBottom: '1px solid #1890ff',
margin: 0
}}
onChange={onTabChange}
>
{practiceAnalyticTabList.map(item => {
return <TabPane tab={item.tab} key={item.key}></TabPane>
})}
</Tabs>
{currentKey == ModuleName.assessment ? (
<AssessmentReport onHandleAnswerAnalysis={onTabChange} practiceId={id} />
) : (
<AnswerAnalysis practiceId={id} />
)}
</div>
)
}
export default PracticeAnalytic

View File

@@ -1,6 +1,6 @@
.practice-analytic-box { .practice-analytic-box {
margin: 0 auto; margin: 0 auto;
width: 1430px; width: 1200px;
border: 1px solid #e0e0e0; border: 1px solid #e0e0e0;
overflow-y: auto; overflow-y: auto;
.ant-tabs.ant-tabs-card .ant-tabs-card-bar .ant-tabs-tab { .ant-tabs.ant-tabs-card .ant-tabs-card-bar .ant-tabs-tab {

View File

@@ -0,0 +1,55 @@
export const mark = {
0: '标记一下',
1: '已标记'
}
export const collection = {
0: '未收藏',
1: '已收藏'
}
export enum Type {
/**单选 */
Single = 1,
Multiple,
Judge
}
export const quetionsType = {
[Type.Single]: '单选题',
[Type.Multiple]: '多选题',
[Type.Judge]: '判断题'
}
export const ApiName = {
/**
* 获取练习题目
*/
getSubjects: '/practice/set/getSubjects',
/**
* 获取练习题目详情
*/
getPracticeSubject: '/practice/set/getPracticeSubject',
/**
* 单个题目提交
* */
submitSubject: '/practice/detail/submitSubject',
/**
* 交卷
*/
submit: '/practice/detail/submit'
}
export const ImgObj = {
stop: 'https://img10.360buyimg.com/imagetools/jfs/t1/206561/1/10729/2819/619f783cE77dd49ed/54eb1fc4b3144a97.png',
run: 'https://img11.360buyimg.com/imagetools/jfs/t1/161735/6/25253/2598/619f783cEa897a673/fbf4e8c05d40feb5.png',
info: 'https://img13.360buyimg.com/imagetools/jfs/t1/217399/4/5733/2641/619f7b91E0894649e/2f6353fe0d35fb46.png',
questionMark:
'https://img12.360buyimg.com/imagetools/jfs/t1/201809/8/16630/2674/61a04963E92475548/ede8a7f006113cae.png',
mark: 'https://img12.360buyimg.com/imagetools/jfs/t1/207329/30/11079/2474/61a70ad0E64730d1c/ed75ee746fb33926.png',
advanceTip:
'https://img11.360buyimg.com/imagetools/jfs/t1/161028/16/25609/6746/61a08d83E06659dfa/e6418acdab948134.png'
}

View File

@@ -1,18 +1,19 @@
import Timer from '@components/timerCom/FlipClock' import Timer from '@components/timerCom/FlipClock'
import { getCurrentTime } from '@utils'
import req from '@utils/request' import req from '@utils/request'
import { Checkbox, Modal, Radio } from 'antd' import { Checkbox, Modal, Radio } from 'antd'
import _ from 'lodash' import _ from 'lodash'
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom' import { useNavigate, useParams } from 'react-router-dom'
import PracticeAction from './components/practice-action' import PracticeAction from './components/practise-action'
import PracticeAdvance from './components/practice-advance' import PracticeAdvance from './components/practise-advance'
import PracticePaging from './components/practice-paging' import PracticePaging from './components/practise-paging'
import { ApiName, ImgObj, quetionsType } from './constant' import { ApiName, ImgObj, quetionsType } from './constant'
import './index.less' import './index.less'
const PracticeDetails = props => { const PracticeDetails = props => {
const navigate = useNavigate() const navigate = useNavigate()
const { setId } = useParams()
const [isMark, setIsMark] = useState(0) // const [isMark, setIsMark] = useState(0) //
const [currentActive, setCurrentActive] = useState('') const [currentActive, setCurrentActive] = useState('')
const [subjectList, setSubjectList] = useState([]) const [subjectList, setSubjectList] = useState([])
@@ -20,13 +21,15 @@ const PracticeDetails = props => {
const [currentIndex, setCurrentIndex] = useState(0) const [currentIndex, setCurrentIndex] = useState(0)
const [isShowAdvanOverceBox, setIsShowAdvanOverceBox] = useState(false) const [isShowAdvanOverceBox, setIsShowAdvanOverceBox] = useState(false)
const [isShowStopBox, setIsShowStopBox] = useState(false) const [isShowStopBox, setIsShowStopBox] = useState(false)
const [subjectInfo, setSubjectInfo] = useState({
practiceId: null,
subjectTitle: '热门题目练习',
singleLength: 0,
multipleLength: 0,
judgeLength: 0
})
const timerRef = React.createRef() const timerRef = React.createRef()
let subjectTitle = ''
let singleLength = 0
let multipleLength = 0
let judgeLength = 0
const setId = ''
const isLast = currentIndex === subjectList?.length - 1 const isLast = currentIndex === subjectList?.length - 1
@@ -35,49 +38,30 @@ const PracticeDetails = props => {
*/ */
const getSubjectList = () => { const getSubjectList = () => {
let params = { let params = {
setId: setId setId
} }
subjectTitle = '热门题目练习' req(
singleLength = 1
multipleLength = 1
judgeLength = 1
const list = [
{ {
subjectType: 1, method: 'post',
subjectId: 1, data: params,
active: true url: ApiName.getSubjects
}, },
{ '/practice'
subjectType: 2, )
subjectId: 2 .then(res => {
}, if (res.data && res.data?.subjectList?.length > 0) {
{ const { subjectList, title, practiceId } = res.data
subjectType: 3, setSubjectInfo({
subjectId: 3 practiceId,
subjectTitle: title,
singleLength: subjectList.filter(item => item.subjectType === 1).length,
multipleLength: subjectList.filter(item => item.subjectType === 2).length,
judgeLength: subjectList.filter(item => item.subjectType === 3).length
})
getPracticeSubject(subjectList[0], subjectList, 0, [])
} }
] })
setSubjectList([...list]) .catch(err => console.log(err))
// _.set(list, [0, 'active'], true)
getPracticeSubject(list[0], list, 0, [])
// req({
// method: 'post',
// data: params,
// url: ApiName.getSubjects
// })
// .then(res => {
// if (res.data && res.data?.subjectList?.length > 0) {
// let list = res.data.subjectList
// singleLength =
// list?.length > 0 ? list.filter(item => item.subjectType === 1).length : 0
// multipleLength =
// list?.length > 0 ? list.filter(item => item.subjectType === 2).length : 0
// judgeLength =
// list?.length > 0 ? list.filter(item => item.subjectType === 3).length : 0
// subjectTitle = res.data?.title || '' //
// getPracticeSubject(list[0], list, 0, [])
// }
// })
// .catch(err => console.log(err))
} }
useEffect(() => { useEffect(() => {
@@ -98,55 +82,18 @@ const PracticeDetails = props => {
subjectId: item.subjectId, subjectId: item.subjectId,
subjectType: item.subjectType subjectType: item.subjectType
} }
req(
const optionList =
item.subjectType === 3
? [
{ {
optionContent: '正确',
optionType: 1
},
{
optionContent: '错误',
optionType: 0
}
]
: [
{
optionType: 1,
optionContent: '<p>题目答案1</p>'
},
{
optionType: 2,
optionContent: '<p>题目答案2</p>'
},
{
optionType: 3,
optionContent: '<p>题目答案3</p>'
}
]
setCurrentActive(item.subjectType === 2 ? activeList : activeList[0])
setCurrentIndex(index)
setSubjectObject({
subjectName: '题干内容',
subjectType: item.subjectType,
optionList,
// subjectList: subjectList,
// currentIndex: index,
// currentActive: item.sub??jectType === 2 ? activeList : activeList[0],
isMark: isMark
})
return
req({
method: 'post', method: 'post',
data: params, data: params,
url: ApiName.getPracticeSubject url: ApiName.getPracticeSubject
}) },
'/practice'
)
.then(res => { .then(res => {
if (res.data) { if (res.data) {
let subjectObject = res.data let subjectObject = res.data
if (item.subjectType === 3) { if (subjectObject.subjectType === 3) {
subjectObject.optionList = [ subjectObject.optionList = [
{ {
optionContent: '正确', optionContent: '正确',
@@ -158,13 +105,10 @@ const PracticeDetails = props => {
} }
] ]
} }
setState({ setCurrentActive(subjectObject.subjectType === 2 ? activeList : activeList[0])
subjectObject: res.data, setCurrentIndex(index)
subjectList: subjectList, setSubjectObject({ ...subjectObject, isMark })
currentIndex: index, setSubjectList(subjectList)
currentActive: item.subjectType === 2 ? activeList : activeList[0],
isMark: isMark
})
} }
}) })
.catch(err => console.log(err)) .catch(err => console.log(err))
@@ -188,7 +132,6 @@ const PracticeDetails = props => {
* @returns * @returns
*/ */
const onChangeCheck = e => { const onChangeCheck = e => {
// let { currentIndex, subjectList } = state
const list = [...subjectList] const list = [...subjectList]
_.set(list, [currentIndex, 'activeList'], e) _.set(list, [currentIndex, 'activeList'], e)
setCurrentActive(e) setCurrentActive(e)
@@ -199,7 +142,6 @@ const PracticeDetails = props => {
* 暂停计时 * 暂停计时
*/ */
const onChangeStop = () => { const onChangeStop = () => {
// setState({ isShowStopBox: true })
setIsShowStopBox(true) setIsShowStopBox(true)
timerRef.current.stop() timerRef.current.stop()
} }
@@ -237,43 +179,28 @@ const PracticeDetails = props => {
*/ */
const onChangeOver = () => { const onChangeOver = () => {
timerRef.current.end() timerRef.current.end()
navigate('/practice-analytic/1', { replace: true }) let params = {
// const list = [...subjectList] setId,
// let answerDetails = [] practiceId: subjectInfo.practiceId,
// list.forEach(item => { timeUse: timerRef.current.getUseTime(),
// let obj = { submitTime: getCurrentTime()
// subjectId: item.subjectId, }
// subjectType: item.subjectType, req(
// answerContents: [] {
// } method: 'post',
// if (item?.activeList && item?.activeList?.length > 0) { data: params,
// obj.answerContents = item.activeList url: ApiName.submit
// } },
// answerDetails.push(obj) '/practice'
// }) )
// let params = { .then(res => {
// setId: setId, if (res.success) {
// timeUse: timerRef.current.getUseTime(), //
// submitTime: getCurrentTime(), timerRef.current.end()
// answerDetails: answerDetails navigate('/practise-analytic/' + subjectInfo.practiceId, { replace: true })
// } }
// req({ })
// method: 'post', .catch(err => console.log(err))
// data: params,
// url: ApiName.submitSubject
// })
// .then(res => {
// if (res.data && res.data.practiceId) {
// //
// timerRef.current.end()
// props.history.replace(
// splicingQuery('/practice-analytic', {
// practiceId: res.data.practiceId
// })
// )
// }
// })
// .catch(err => console.log(err))
} }
/** /**
@@ -288,8 +215,6 @@ const PracticeDetails = props => {
*/ */
const onHandleCancelModal = () => { const onHandleCancelModal = () => {
setIsShowAdvanOverceBox(false) setIsShowAdvanOverceBox(false)
// setState({ isShowAdvanOverceBox: false })
} }
/** /**
@@ -297,9 +222,6 @@ const PracticeDetails = props => {
*/ */
const onChangeAdvanceOver = () => { const onChangeAdvanceOver = () => {
setIsShowAdvanOverceBox(true) setIsShowAdvanOverceBox(true)
// setState({
// isShowAdvanOverceBox: true
// })
} }
/** /**
@@ -307,8 +229,28 @@ const PracticeDetails = props => {
* @returns * @returns
*/ */
const onChangeNext = () => { const onChangeNext = () => {
// let { currentIndex } = state console.log(subjectList)
// currentIndex += 1 const { subjectId, subjectType, activeList } = subjectList[currentIndex]
let params = {
practiceId: subjectInfo.practiceId,
timeUse: timerRef.current.getUseTime(),
subjectId: subjectId,
subjectType: subjectType,
answerContents: activeList
}
req(
{
method: 'post',
data: params,
url: ApiName.submitSubject
},
'/practice'
)
.then(res => {
console.log(res)
})
.catch(err => console.log(err))
setCurrentIndex(currentIndex + 1) setCurrentIndex(currentIndex + 1)
changeData(currentIndex + 1) changeData(currentIndex + 1)
} }
@@ -318,7 +260,6 @@ const PracticeDetails = props => {
* @param {*} index 当前点击下标 * @param {*} index 当前点击下标
*/ */
const changeData = index => { const changeData = index => {
// let { subjectList } = state
const list = [...subjectList] const list = [...subjectList]
let subObj = list[index] let subObj = list[index]
let activeList = [] // let activeList = [] //
@@ -349,14 +290,12 @@ const PracticeDetails = props => {
const onChangeSubmitModal = () => { const onChangeSubmitModal = () => {
timerRef.current.run() timerRef.current.run()
setIsShowStopBox(false) setIsShowStopBox(false)
// setState({ isShowStopBox: false })
} }
/** /**
* 暂停弹框-再次再做 * 暂停弹框-再次再做
*/ */
const onChangeCancelModal = () => { const onChangeCancelModal = () => {
// props.history.goBack()
navigate(-1) navigate(-1)
} }
@@ -367,7 +306,7 @@ const PracticeDetails = props => {
<div className='details-container'> <div className='details-container'>
<div className='container-box'> <div className='container-box'>
<div className='container-box-title'> <div className='container-box-title'>
<div className='title-title'>{subjectTitle}</div> <div className='title-title'>{subjectInfo.subjectTitle}</div>
<div className='title-time'> <div className='title-time'>
<div className='title-timer-img' onClick={onChangeStop}> <div className='title-timer-img' onClick={onChangeStop}>
<img src={isShowStopBox ? ImgObj.stop : ImgObj.run} className='title-timer-icon' /> <img src={isShowStopBox ? ImgObj.stop : ImgObj.run} className='title-timer-icon' />
@@ -453,9 +392,9 @@ const PracticeDetails = props => {
<PracticePaging <PracticePaging
subjectList={subjectList} subjectList={subjectList}
onHandlePaging={onChangePaging} onHandlePaging={onChangePaging}
singleLength={singleLength} singleLength={subjectInfo.singleLength}
multipleLength={multipleLength} multipleLength={subjectInfo.multipleLength}
judgeLength={judgeLength} judgeLength={subjectInfo.judgeLength}
/> />
</div> </div>
<PracticeAdvance <PracticeAdvance

View File

@@ -85,7 +85,7 @@ class FrontEnd extends Component {
.then(res => { .then(res => {
if (res.data) { if (res.data) {
this.props.history.push( this.props.history.push(
splicingQuery('/practice-details', { splicingQuery('/practise-details', {
setId: res.data.setId setId: res.data.setId
}) })
) )

View File

@@ -0,0 +1,4 @@
.bottom-btn {
text-align: right;
margin-top: 50px;
}

View File

@@ -0,0 +1,138 @@
import req from '@utils/request'
import { Button, Card, Checkbox, Descriptions } from 'antd'
import type { CardTabListType } from 'antd/es/card'
import { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import './index.less'
const apiName = {
/**
* 查询专项练习
*/
getSpecialPracticeContent: '/practice/set/getSpecialPracticeContent',
/**
* 开始练习
*/
addPractice: 'practice/set/addPractice'
}
const PracticeHome = () => {
const navigate = useNavigate()
const [primaryList, setPrimaryList] = useState<CardTabListType[]>([])
const [dataList, setDataList] = useState([])
const [currentCateId, setCurrentCateId] = useState()
const [checkedInfo, setCheckedInfo] = useState({})
const getContent = () => {
req(
{
method: 'post',
url: apiName.getSpecialPracticeContent
},
'/practice'
).then((res: any) => {
if (res.success && res.data) {
setPrimaryList(
res.data.map(t => ({ tab: t.primaryCategoryName, key: t.primaryCategoryId }))
)
setDataList(
res.data[0].categoryList.map(item => {
return {
...item,
children: item.labelList.map(t => ({ label: t.labelName, value: t.assembleId }))
}
})
)
setCurrentCateId(res.data[0].primaryCategoryId)
}
})
}
useEffect(() => {
getContent()
}, [])
const onCheckAllChange = (e: any, categoryId: number) => {
const checked = e.target.checked
const checkedInfoNew = { ...checkedInfo }
checkedInfoNew[categoryId] = checked
? dataList.filter(t => t.categoryId === categoryId)[0].children.map(t => t.value)
: []
setCheckedInfo({ ...checkedInfoNew })
}
const changeItem = (id, value) => {
setCheckedInfo({
...checkedInfo,
[id]: value
})
}
const startPractice = () => {
console.log(checkedInfo)
const params = {
assembleIds: Object.values(checkedInfo).flat()
}
req(
{
method: 'post',
url: apiName.addPractice,
data: params
},
'/practice'
).then(res => {
if (res.success && res.data) {
navigate('/practise-detail/' + res.data.setId)
}
})
}
return (
<div>
<Card tabList={primaryList}>
{dataList.map((item: { categoryName: string; categoryId: number; children: any[] }) => {
return (
<Descriptions
title={item.categoryName}
extra={
<Checkbox
onChange={e => onCheckAllChange(e, item.categoryId)}
checked={checkedInfo?.[item.categoryId]?.length === item.children.length}
indeterminate={
checkedInfo?.[item.categoryId]?.length > 0 &&
checkedInfo?.[item.categoryId]?.length < item.children.length
}
>
</Checkbox>
}
key={item.categoryId}
>
<Descriptions.Item>
<Checkbox.Group
value={checkedInfo[item.categoryId]}
options={item.children}
onChange={value => changeItem(item.categoryId, value)}
/>
</Descriptions.Item>
</Descriptions>
)
})}
</Card>
<div className='bottom-btn'>
<Button
onClick={startPractice}
type='primary'
shape='round'
size='large'
disabled={Object.values(checkedInfo).flat().length === 0}
>
</Button>
</div>
</div>
)
}
export default PracticeHome

View File

@@ -1,8 +1,8 @@
// import req from '@utils/request' // import req from '@utils/request'
import { Card, Input, Pagination, Spin, Tooltip } from 'antd' import req from '@utils/request'
import React, { useState } from 'react' import { Card, Empty, Input, Pagination, Spin, Tooltip } from 'antd'
import React, { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import './index.less' import './index.less'
const { Search } = Input const { Search } = Input
@@ -23,53 +23,51 @@ const tabList = [
] ]
const PaperView = props => { const PaperView = props => {
const { type } = props
const navigate = useNavigate() const navigate = useNavigate()
const [spinning, setSpinning] = useState(false) const [spinning, setSpinning] = useState(false)
const [paperList, setPaperList] = useState([ const [paperList, setPaperList] = useState([])
{
setId: 1,
setName: '测试试卷',
setHeat: 1,
setDesc: '描述'
}
])
const [orderType, setOrderType] = useState(0) const [orderType, setOrderType] = useState(0)
const [setId, setSetId] = useState(0)
const [pageInfo, setPageInfo] = useState({ const [pageInfo, setPageInfo] = useState({
total: 0, total: 0,
pageIndex: 1 pageIndex: 1
}) })
const [searchText, setSearchText] = useState('') const [searchText, setSearchText] = useState('')
useEffect(() => {
getPreSetContent()
}, [props.type])
const getPreSetContent = () => { const getPreSetContent = () => {
// const { menuId, menuType } = this.props let api = '/practice/set/getPreSetContent'
// const { orderType, searchText } = this.state if (type === 'unfinish') {
// let params = { api = '/practice/set/getUnCompletePractice'
// menuId: menuId, }
// menuType: menuType, let params = {
// orderType: orderType, pageInfo: {
// pageInfo: { pageNo: pageInfo.pageIndex,
// pageIndex: this.pageIndex, pageSize: 8
// pageSize: 8 }
// }, }
// setName: searchText req(
// } {
// req({ method: 'post',
// method: 'post', data: params,
// data: params, url: api
// url: 'admin/practice/set/getPreSetContent' },
// }) '/practice'
// .then(res => { )
// if (res.data.pageList && res.data.pageList?.length > 0) { .then(res => {
// this.setState({ if (res.success) {
// paperList: res.data.pageList, setPageInfo({
// total: res.data.pageInfo.total, ...pageInfo,
// isShowSpin: false, total: res.data.total
// setId: res.data.pageList.setId })
// }) setPaperList(res.data.result || [])
// } }
// }) })
// .catch(err => console.log(err)) .catch(err => console.log(err))
} }
const onTabChange = key => { const onTabChange = key => {
@@ -83,7 +81,7 @@ const PaperView = props => {
}) })
} }
const handleJump = setId => navigate('/practice-detail/' + setId) const handleJump = setId => navigate('/practise-detail/' + setId)
const onSearch = value => { const onSearch = value => {
setSearchText(value) setSearchText(value)
@@ -108,7 +106,7 @@ const PaperView = props => {
onTabChange={onTabChange} onTabChange={onTabChange}
> >
<div className='ant-card-body'> <div className='ant-card-body'>
{paperList?.length > 0 && {paperList?.length > 0 ? (
paperList.map((item, index) => { paperList.map((item, index) => {
return ( return (
<div <div
@@ -127,7 +125,10 @@ const PaperView = props => {
</div> </div>
</div> </div>
) )
})} })
) : (
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
)}
</div> </div>
</Card> </Card>
</div> </div>

View File

@@ -0,0 +1,65 @@
import type { GetProp, MenuProps } from 'antd'
import { Menu } from 'antd'
import { useState } from 'react'
import FrontEnd from './components/front-end/index1'
import PaperEnd from './components/paper-end'
import './index.less'
type MenuItem = GetProp<MenuProps, 'items'>[number]
function getItem(
label: React.ReactNode,
key?: React.Key | null,
icon?: React.ReactNode,
children?: MenuItem[]
): MenuItem {
return {
key,
icon,
children,
label
} as MenuItem
}
const PracticeQuestions = () => {
const [selectKeys, setSelectKeys] = useState(['1'])
const menuItems = [
getItem('专项练习', '1'),
getItem('模拟套卷', '2', '', [getItem('后端', '2-1'), getItem('前端', '2-2')]),
getItem('我未完成', '3')
]
const clickMenu = ({ key }: { key: string }) => {
setSelectKeys([key])
}
const renderPage = () => {
const pageMap = {
'1': <FrontEnd />,
'2-1': <PaperEnd type='backend' />,
'2-2': <PaperEnd />,
'3': <PaperEnd type='unfinish' />
}
return pageMap[selectKeys[0]]
}
return (
<div className='practice-questions-container'>
<div className='practice-questions-menu'>
<Menu
style={{ width: 200 }}
selectedKeys={selectKeys}
defaultOpenKeys={['2']}
mode='inline'
items={menuItems}
onClick={clickMenu}
/>
</div>
<div className='practice-questions-box'>{renderPage()}</div>
</div>
)
}
export default PracticeQuestions

View File

@@ -8,12 +8,37 @@ import './index.less'
const { SubMenu } = Menu const { SubMenu } = Menu
function getItem(label, key, icon, children) {
return {
key,
icon,
children,
label
}
}
export default class PracticeQuestions extends Component { export default class PracticeQuestions extends Component {
constructor(props) { constructor(props) {
super(props) super(props)
this.state = { this.state = {
currentKey: '', // menu currentKey: '1', // menu
subMenuList: [] subMenuList: [
{
title: '模拟套卷',
menuId: '1',
menuType: 1
},
{
title: '模拟套卷',
detailVOS: [
{
menuName: '后端',
menuId: '10',
menuType: 2
}
]
}
]
} }
} }
@@ -28,7 +53,7 @@ export default class PracticeQuestions extends Component {
currentKeyFirstMenuType = 1 currentKeyFirstMenuType = 1
componentDidMount() { componentDidMount() {
this.getPracticeMenu() // this.getPracticeMenu()
} }
/** /**
@@ -123,7 +148,7 @@ export default class PracticeQuestions extends Component {
title={subMenuItem.title} title={subMenuItem.title}
icon={<MailOutlined />} icon={<MailOutlined />}
> >
{subMenuItem?.detailVOS?.length > 0 && {subMenuItem?.detailVOS?.length > 0 ? (
subMenuItem?.detailVOS?.map(menuItem => { subMenuItem?.detailVOS?.map(menuItem => {
return ( return (
<Menu.Item key={menuItem.menuId}> <Menu.Item key={menuItem.menuId}>
@@ -131,7 +156,13 @@ export default class PracticeQuestions extends Component {
{menuItem.menuName} {menuItem.menuName}
</Menu.Item> </Menu.Item>
) )
})} })
) : (
<Menu.Item key={subMenuItem.menuId}>
{/* {subMenuItem.menuType == 1 ? 'GRADE ' : ''} */}
{/* {subMenuItem.menuName} */}
</Menu.Item>
)}
</SubMenu> </SubMenu>
) )
})} })}

View File

@@ -22,7 +22,7 @@ const ContributionList = props => {
url: apiName.getContributeList url: apiName.getContributeList
}) })
.then(res => { .then(res => {
if (res.data && res.data.length > 0) { if (res.success && res.data) {
setLoading(false) setLoading(false)
setContributionList(res.data) setContributionList(res.data)
} else { } else {

View File

@@ -1,7 +1,6 @@
import req from '@utils/request' import req from '@utils/request'
import React, { Component, Fragment } from 'react' import React, { Component, Fragment } from 'react'
import { RankingType, apiName } from '../../constant' import { RankingType, apiName } from '../../constant'
import { mockRankingModuleList } from '../../mock'
import RankingBox from '../ranking-box' import RankingBox from '../ranking-box'
// import {} from 'react-router-dom' // import {} from 'react-router-dom'
@@ -9,26 +8,29 @@ class PracticeList extends Component {
constructor(props) { constructor(props) {
super(props) super(props)
this.state = { this.state = {
contributionList: mockRankingModuleList[0].rankingList, contributionList: [],
contributeType: 0, contributeType: 0,
isLoading: false isLoading: false
} }
} }
componentDidMount() { componentDidMount() {
// this.getPracticeRankList() this.getPracticeRankList()
} }
/** /**
* 获得练习榜 * 获得练习榜
*/ */
getPracticeRankList() { getPracticeRankList() {
req({ req(
{
method: 'post', method: 'post',
url: apiName.getPracticeRankList url: apiName.getPracticeRankList
}) },
'/practice'
)
.then(res => { .then(res => {
if (res.data && res.data.length > 0) { if (res.success && res.data) {
this.setState({ this.setState({
contributionList: res.data, contributionList: res.data,
isLoading: false isLoading: false
@@ -58,7 +60,7 @@ class PracticeList extends Component {
* 去练题 * 去练题
*/ */
onChangeJump = () => { onChangeJump = () => {
window.open('/practice-questions', '_blank') window.open('/practise-questions', '_blank')
} }
render() { render() {

View File

@@ -50,6 +50,8 @@ export default function RankingBox(props) {
// 获得当前下标的数据 // 获得当前下标的数据
let rankingList = contributionList || [] let rankingList = contributionList || []
console.log(rankingList, 'rank list ')
return ( return (
<div className='ranking-list-box'> <div className='ranking-list-box'>
<div className='ranking-list-header'> <div className='ranking-list-header'>

View File

@@ -13,9 +13,12 @@ export const apiName = {
getSubjectPage: '/getSubjectPage', getSubjectPage: '/getSubjectPage',
/** /**
* 练题排行 * 贡献
*/ */
getContributeList: '/getContributeList' getContributeList: '/getContributeList',
// 练题榜
getPracticeRankList: '/practice/detail/getPracticeRankList'
} }
/** /**

View File

@@ -4,7 +4,7 @@ import QuestionList from '@components/question-list'
import req from '@utils/request' import req from '@utils/request'
import { memo, useEffect, useState } from 'react' import { memo, useEffect, useState } from 'react'
import ContributionList from './components/contribution-list' import ContributionList from './components/contribution-list'
import PracticeList from './components/practice-list' import PracticeList from './components/practise-list'
import { apiName } from './constant' import { apiName } from './constant'
import './index.less' import './index.less'

View File

@@ -44,6 +44,10 @@ export default ({ mode }) => {
'/oss': { '/oss': {
target: env.VITE_API_HOST, target: env.VITE_API_HOST,
changeOrigin: true changeOrigin: true
},
'/practice': {
target: env.VITE_API_HOST,
changeOrigin: true
} }
} }
} }