import React from 'react'; import { Link } from 'react-router-dom'; import './index.less'; import LineChart from '@src/components/LineChart'; import BarChart from '@src/components/BarChart'; import PieChart from '@src/components/PieChart'; import Assets from '@src/components/Assets'; import Page from '@src/containers/Page'; import { formatDate, formatPercent, formatSeconds, formatMinute, formatSecond, formatMinuteSecond, getMap } from '@src/services/Tools'; import { Icon, Tooltip } from 'antd'; import { Question } from '../../../stores/question'; import { Button } from '../../../components/Button'; import Tabs from '../../../components/Tabs'; import { Icon as GIcon } from '../../../components/Icon'; import { QuestionDifficult, ExaminationQuestionType, ExaminationSubject, } from '../../../../Constant'; const QuestionDifficultMap = getMap(QuestionDifficult, 'value', 'label'); const QuestionDifficultSort = getMap(QuestionDifficult, 'value', 'sort'); function BarOption3(titles, source, data1, data2, color1, color2) { return { title: [ { text: titles[0], textStyle: { fontSize: 24, fontWeight: 'bold', color: '#686872' }, left: 100, top: 15, }, { text: titles[1], textStyle: { fontSize: 24, fontWeight: 'bold', color: '#686872' }, left: 195, top: 15, }, { text: titles[2], textStyle: { fontSize: 24, fontWeight: 'bold', color: '#686872' }, left: 695, top: 15, }, ], grid: [{ width: 250, x: 200, bottom: 30 }, { width: 250, x: 700, bottom: 30 }], xAxis: [ { gridIndex: 0, show: false, axisTick: { show: false }, axisLine: { show: false }, splitLine: { show: false }, }, { gridIndex: 1, show: false, axisTick: { show: false }, axisLine: { show: false }, splitLine: { show: false }, }, ], yAxis: [ { gridIndex: 0, type: 'category', axisTick: { show: false }, axisLine: { show: false }, splitLine: { show: false }, offset: 15, data: source, axisLabel: { color: '#686872', fontSize: 16 }, }, { gridIndex: 1, type: 'category', axisTick: { show: false }, axisLine: { show: false }, splitLine: { show: false }, axisLabel: { show: false }, }, ], series: [ { type: 'bar', xAxisIndex: 0, yAxisIndex: 0, barWidth: 30, data: data1.map((item, index) => ({ value: item, itemStyle: { color: index % 2 ? color1[0] : color1[1] }, label: { show: true, color: '#303036', align: 'right', position: [360, 5], fontSize: 16, formatter: item, }, })), }, { type: 'bar', xAxisIndex: 1, yAxisIndex: 1, barWidth: 30, data: data2.map((item, index) => ({ value: item, itemStyle: { color: index % 2 ? color2[0] : color2[1] }, label: { show: true, color: '#303036', align: 'right', fontSize: 16, position: [360, 5], formatter: item, }, })), }, ], }; } function BarOption2(title, data, legend, color) { return { title: { text: title, textStyle: { fontSize: 24, fontWeight: 'bold', color: '#686872' }, }, tooltip: { trigger: 'axis', }, legend: { show: legend.length > 1, data: legend, right: 20, }, color, dataset: { source: [['type', ...legend], ...data], }, grid: { left: 30, right: 30, height: 300 }, xAxis: { type: 'category', axisLabel: { color: '#686872' }, axisLine: { lineStyle: { color: '#D1D6DF' } }, }, yAxis: { type: 'value', min: 0, max: 100, axisLabel: { color: '#686872' }, axisLine: { lineStyle: { color: '#D1D6DF' } }, }, series: legend.map(() => ({ type: 'bar', barWidth: 40, })), }; } function lineOption1(title, data, legend, color) { return { title: { text: title, textStyle: { fontSize: 24, fontWeight: 'bold', color: '#686872' }, left: '0', }, tooltip: { trigger: 'axis', }, legend: { show: legend.length > 1, data: legend, right: 20, }, color, grid: { left: 30, right: 30, height: 300 }, xAxis: { type: 'category', axisLabel: { color: '#686872' }, axisLine: { lineStyle: { color: '#D1D6DF' } }, }, yAxis: { type: 'value', min: 0, max: 100, axisLabel: { color: '#686872' }, axisLine: { lineStyle: { color: '#D1D6DF' } }, }, dataset: { source: [['type', ...legend], ...data], }, series: legend.map(() => ({ type: 'line', smooth: true, symbol: 'circle', })), }; } function barOption1(title, value, allValue, avgCorrect, avgIncorrent) { const xAxis1 = [ { gridIndex: 0, type: 'category', axisTick: { show: false }, axisLine: { lineStyle: { color: '#D1D6DF' } }, splitLine: { show: false }, }, { gridIndex: 1, type: 'category', axisTick: { show: false }, axisLine: { lineStyle: { color: '#D1D6DF' } }, splitLine: { show: false }, data: [ { value: 'Avg Time\nCorrect', textStyle: { color: '#686872', fontWeight: '500', fontSize: 14, lineHeight: 20 }, }, { value: 'Avg Time\nIncorrect', textStyle: { color: '#686872', fontWeight: '500', fontSize: 14, lineHeight: 20 }, }, ], }, ]; const xAxis2 = { type: 'category', axisTick: { show: false }, axisLine: { lineStyle: { color: '#D1D6DF' } }, splitLine: { show: false }, }; const yAxis1 = [ { gridIndex: 0, show: false, min: 0, max: 100, axisTick: { show: false }, axisLine: { show: false }, splitLine: { show: false }, }, { gridIndex: 1, show: false, min: 0, max: 100, axisTick: { show: false }, axisLine: { show: false }, splitLine: { show: false }, }, ]; const yAxis2 = { show: false, min: 0, max: 100, axisTick: { show: false }, axisLine: { show: false }, splitLine: { show: false }, }; const data1 = { type: 'bar', barWidth: 50, xAxisIndex: 0, yAxisIndex: 0, data: [ { value, itemStyle: { color: '#7AA7DC' }, label: { show: true, position: 'top', formatter: `{a|${value}}`, rich: { a: { fontSize: 16, fontWeight: 'bold', color: '#686872' } }, }, }, { value: allValue, itemStyle: { color: '#598FCF' }, label: { show: true, position: 'top', formatter: `{a|${allValue}}`, rich: { a: { fontSize: 12, color: '#686872' } }, }, }, ], }; const data2 = { type: 'bar', barWidth: 50, xAxisIndex: 1, yAxisIndex: 1, data: [ { value: avgCorrect, name: 'Avg Time\nCorrect', itemStyle: { color: '#7775CA' }, label: { show: true, position: 'top', formatter: `{a|${avgCorrect}}`, rich: { a: { fontSize: 16, fontWeight: 'bold', color: '#686872' } }, }, }, { value: avgIncorrent, name: 'Avg Time\nIncorrect', itemStyle: { color: '#9396C9' }, label: { show: true, position: 'top', formatter: `{a|${avgIncorrent}}`, rich: { a: { fontSize: 16, fontWeight: 'bold', color: '#686872' } }, }, }, ], }; return { title: [ { text: title, textStyle: { fontSize: 24, fontWeight: 'bold', color: '#686872' }, left: '0', }, { text: 'Avg Time\nTotal', textAlign: 'center', textVerticalAlign: 'middle', textStyle: { color: '#686872', fontWeight: '500', fontSize: 14, lineHeight: 20 }, bottom: '2%', left: '26%', }, ], xAxis: avgCorrect ? xAxis1 : xAxis2, yAxis: avgCorrect ? yAxis1 : yAxis2, grid: avgCorrect ? [{ width: 200, x: 72 }, { width: 350, x: 272 }] : { width: 200, left: '30%' }, series: avgCorrect ? [data1, data2] : [data1], }; } function pieOption1(title, userCorrect, userNumber, totalCorrect, totalNumber) { const value = formatPercent(userCorrect, userNumber); const allValue = formatPercent(totalCorrect, totalNumber); return { title: [ { text: title, textStyle: { fontSize: 24, fontWeight: 'bold', color: '#686872' }, left: '0', }, { text: `${value}%`, textAlign: 'center', textVerticalAlign: 'middle', textStyle: { color: value < 50 ? '#f19057' : '#7AA7DC', fontSize: 45 }, subtext: `${userCorrect}/${userNumber}`, subtextStyle: { color: '#686872', fontSize: 16 }, top: '35%', left: '49%', }, ], series: [ { type: 'pie', radius: ['64%', '70%'], label: { show: false, }, hoverAnimation: false, animation: false, data: [ { value: allValue, itemStyle: { color: '#7775CA' }, label: { show: true, position: 'outside', formatter: `{a|全站用户}:{b|${allValue}%}`, rich: { a: { color: '#686872', fontSize: 16, }, b: { color: '#6865FD', fontSize: 16, }, }, }, }, { value: 100 - allValue, itemStyle: { color: '#e1e1e1' }, emphasis: { itemStyle: { color: '#e1e1e1' } }, }, ], }, { type: 'pie', radius: ['45%', '61%'], label: { show: false, }, hoverAnimation: false, animation: false, data: [ { value, itemStyle: { color: value < 50 ? '#f19057' : '#7AA7DC' } }, { value: 100 - value, itemStyle: { color: '#e1e1e1' }, emphasis: { itemStyle: { color: '#e1e1e1' } } }, ], }, ], }; } function pieOption2(title, value1, value2, value3) { return { title: [ { text: title, textStyle: { fontSize: 24, fontWeight: 'bold', color: '#686872' }, left: '0', }, { text: `${value1 + value2 + value3}`, textAlign: 'center', textVerticalAlign: 'middle', textStyle: { color: '#686872', fontSize: 60 }, subtext: '综合实力', subtextStyle: { color: '#686872', fontSize: 14 }, top: '35%', left: '49.5%', }, ], series: [ { type: 'pie', radius: ['50%', '80%'], startAngle: 30, hoverAnimation: false, animation: false, data: [ { value: value1, itemStyle: { color: '#6865FD' }, label: { position: 'outside', formatter: `{a|逻辑关系} {b|${value1}}`, rich: { a: { color: '#686872', fontSize: 18, }, b: { color: '#6865FD', fontSize: 18, }, }, }, }, { value: value2, itemStyle: { color: '#6EC28D' }, label: { position: 'outside', formatter: `{a|句子结构} {b|${value2}}`, rich: { a: { color: '#686872', fontSize: 18, }, b: { color: '#6EC28D', fontSize: 18, }, }, }, }, { value: value3, itemStyle: { color: '#598FCF' }, label: { position: 'outside', formatter: `{a|阅读速度} {b|${value3}}`, rich: { a: { color: '#686872', fontSize: 18, }, b: { color: '#598FCF', fontSize: 18, }, }, }, }, ], }, ], }; } export default class extends Page { initState() { return { tab: 'main', report: { paperModule: '' } }; } initData() { const { id } = this.params; const { info = '' } = this.state.search; Question.detailReport(id).then(result => { switch (result.paperModule) { case 'sentence': this.refreshSentence(result); break; case 'textbook': this.refreshTextbook(result); break; case 'exercise': this.refreshExercise(result); break; case 'examination': this.refreshExamination(result); break; default: } this.setState({ report: result, paper: result.paper }); }); switch (info) { case 'question': // 题目回顾列表 Question.questionReport(id).then(result => { switch (result.paperModule) { case 'sentence': result = result.map((row) => { row.struct = row.detail.subject && row.detail.predicate && row.detail.object ? 0 : 1; row.logic = row.detail.options ? 0 : 1; row.note = row.note ? 1 : 0; row.collect = row.collect ? 1 : 0; return row; }); break; case 'textbook': case 'exercise': result = result.map((row) => { row.correct = row.isCorrect ? 0 : 1; row.diff = QuestionDifficultSort[row.question.difficult]; row.note = row.note ? 1 : 0; row.collect = row.collect ? 1 : 0; return row; }); this.refreshExercise(result); break; default: } this.setState({ list: result }); }); break; default: break; } } refreshSentence() { const { info = '' } = this.state.search; switch (info) { case 'question': break; default: } } refreshTextbook() { this.refreshExercise(); } refreshExamination() { const { info = '' } = this.state.search; switch (info) { case 'score': break; default: } } refreshExercise() { const { info = '' } = this.state.search; switch (info) { case 'question': break; default: } } questionSort(field) { let { order } = this.state; const { list = [] } = this.state; if (order === field) { order = 'no'; // direction = 'asc'; } else { order = field; // direction = 'desc'; } list.sort((a, b) => { const aValue = a[order]; const bValue = a[order]; if (aValue === bValue) { return a.no < b.no ? -1 : a.no > b.no ? 1 : 0; } return aValue > bValue ? -1 : 1; }); // if (direction === 'desc') { // list.reverse(); // } this.setState({ order, list }); } renderView() { const { report = {}, search = {} } = this.state; const { info } = search; switch (report.paperModule) { case 'sentence': if (info === 'question') { return this.renderSentenceQuestion(); } return this.renderSentence(); case 'textbook': if (info === 'question') { return this.renderExerciseQuestion(); } return this.renderTextbook(); case 'exercise': if (info === 'question') { return this.renderExerciseQuestion(); } return this.renderExercise(); case 'examination': return this.renderExamination(); default: return <div />; } } renderSentence() { const { paper = {}, report = {}, search = {} } = this.state; const { info } = search; const { user } = this.props; return ( <div className="sentence"> <div className="header"> <div className="content"> <div className="title">Report for 「{report.paperModule === 'examination' ? '模考' : '练习'}」{paper.title}</div> <div className="btns"> <Button size="small" radius onClick={() => { linkTo('/'); }}>返回首页</Button> {!info && <Button size="small" radius onClick={() => { linkTo(`/paper/report/${report.id}?info=question`); }}>题目回顾</Button>} {info === 'question' && <Button size="small" radius onClick={() => { linkTo(`/paper/report/${report.id}`); }}>详细报告</Button>} </div> <div className="right"> <div className="text">{user.info.nickname}</div> <div className="desc">练习次数{paper.times}</div> <div className="desc">{formatDate(report.updateTime, 'YYYY-MM-DD HH:mm:ss')}</div> </div> </div> </div> {info === 'question' && this.renderSentenceQuestion()} {!info && this.renderSentenceDetail()} </div> ); } renderTextbook() { return this.renderExercise(); } renderExercise() { const { paper = {}, report = {}, search = {} } = this.state; const { info } = search; const { user } = this.props; return ( <div className="exercise"> <div className="header"> <div className="content"> <div className="title">Report for「练习」{paper.title}</div> <div className="btns"> <Button size="small" radius onClick={() => { linkTo('/'); }}>返回首页</Button> {!info && <Button size="small" radius onClick={() => { linkTo(`/paper/report/${report.id}?info=question`); }}>题目回顾</Button>} {info === 'question' && <Button size="small" radius onClick={() => { linkTo(`/paper/report/${report.id}`); }}>详细报告</Button>} </div> <div className="right"> <div className="text">{user.info.nickname}</div> <div className="desc">练习次数{paper.times}</div> <div className="desc">{formatDate(report.updateTime, 'YYYY-MM-DD HH:mm:ss')}</div> </div> </div> </div> {info === 'question' && this.renderExerciseQuestion()} {!info && this.renderExerciseDetail()} </div> ); } renderExamination() { const { paper = {}, report = {}, search = {} } = this.state; const { info } = search; const { user } = this.props; return ( <div className="examination"> <div className="header"> <div className="content"> <div className="title">Report for 「{report.paperModule === 'examination' ? '模考' : '练习'}」{paper.title}</div> <div className="btns"> <Button size="small" radius onClick={() => { linkTo('/'); }}>返回首页</Button> {!info && <Button size="small" radius onClick={() => { linkTo(`/paper/report/${report.id}?info=score`); }}>成绩单</Button>} {info === 'score' && <Button size="small" radius onClick={() => { linkTo(`/paper/report/${report.id}`); }}>详细报告</Button>} </div> <div className="right"> <div className="text">{user.info.nickname}</div> <div className="desc">练习次数{paper.times}</div> <div className="desc">{formatDate(report.updateTime, 'YYYY-MM-DD HH:mm:ss')}</div> </div> </div> </div> {info === 'score' && this.renderExaminationScore()} {!info && this.renderExaminationDetail()} </div> ); } renderSentenceQuestion() { const { report, list, order } = this.state; return <div className='sentence question'> <div className='header'> <div className='content'> <div className='title'>题目回顾</div> <Button className='back' radius onClick={() => { linkTo(`/paper/report/${report.id}`); }}>返回长难句报告</Button> </div> </div> <div className='body'> <div className='content'> <div className='tip'><Assets name='notice' />点击题目查看详情</div> <table> <thead> <tr> <th>序号</th> <th width='420'>题目</th> <th className="point" onClick={() => { this.questionSort('struct'); }}>句子结构<GIcon name={order === 'struct' ? 'arrow-down' : 'arrow-up'} active={order === 'struct'} /></th> <th className="point" onClick={() => { this.questionSort('logic'); }}>逻辑关系<GIcon name={order === 'logic' ? 'arrow-down' : 'arrow-up'} active={order === 'logic'} /></th> <th className="point" onClick={() => { this.questionSort('userTime'); }}>用时<GIcon name={order === 'userTime' ? 'arrow-down' : 'arrow-up'} active={order === 'userTime'} /></th> <th className="point" onClick={() => { this.questionSort('collect'); }}>收藏<GIcon name={order === 'collect' ? 'arrow-down' : 'arrow-up'} active={order === 'collect'} /></th> <th className="point" onClick={() => { this.questionSort('note'); }}>笔记<GIcon name={order === 'note' ? 'arrow-down' : 'arrow-up'} active={order === 'note'} /></th> </tr> </thead> <tbody> {(list || []).map(row => { return <tr> <td>{row.no}</td> <td> <div className='n'><Link to={`/paper/question/${row.id}`}>{row.questionNo.title}</Link></div> <div className='desc'>{row.question.description}</div> </td> <td><GIcon name={row.detail.subject && row.detail.predicate && row.detail.object ? 'right' : 'error'} noHover /></td> <td><GIcon name={row.detail.options ? 'right' : 'error'} noHover /></td> <td>{formatMinuteSecond(row.userTime)}</td> <td><GIcon name='star' active={row.collect} noHover /></td> <td><GIcon name='note' active={row.note} noHover /></td> </tr>; })} </tbody> </table> </div> </div> </div>; } renderSentenceDetail() { const { report = {} } = this.state; const { detail = {} } = report; return <div> <div className="body"> <div className="content"> <div className="title">完成情况</div> <div className="detail"> <div className="block"> <div className="t1">总耗时</div> <div className="t2">{formatMinute(detail.info.userTime, true)}</div> <div className="t3">min</div> </div> {detail.info.userTime > detail.info.time && <div className="block"> <div className="t1">超出建议用时</div> <div className="t2">{formatMinute(detail.info.userTime - detail.info.time, true)}</div> <div className="t3">min</div> </div>} <div className="line" /> <div className="block"> <div className="t1">完成题目</div> <div className="t2">{detail.info.userNumber}</div> <div className="t3">题</div> </div> {detail.info.userNumber !== detail.info.questionNumber && <div className="block"> <div className="t1">剩余未做</div> <div className="t2">{detail.info.questionNumber || 0 - detail.info.userNumber}</div> <div className="t3">题</div> </div>} </div> </div> </div> <div className="body gray"> <div className="content"> <div className="title">基本情况</div> <div className="block-wrapper"> <div className="block"> <PieChart option={pieOption1('正确率', detail.info.userCorrect, detail.info.userNumber, detail.info.totalCorrect, detail.info.totalNumber)} /> </div> <div className="block"> <BarChart option={barOption1('用时', detail.info.userTime / detail.info.userNumber, detail.info.totalTime / detail.info.totalNumber, detail.info.correctTime, detail.info.incorrectTime)} /> </div> </div> </div> </div> <div className="body"> <div className="content"> <div className="title">能力评估</div> <PieChart option={pieOption2('综合得分', detail.ability.logic, detail.ability.struct, detail.ability.speed)} /> </div> </div> <div className="body gray"> <div className="content t-c"> <Button size="lager" width={200} radius> 继续做题 </Button> </div> </div> </div>; } renderExerciseQuestion() { const { report, list, order } = this.state; return <div className='sentence question'> <div className='header'> <div className='content'> <div className='title'>题目回顾</div> <Button className='back' radius onClick={() => { linkTo(`/paper/report/${report.id}`); }}>返回练习报告</Button> </div> </div> <div className='body'> <div className='content'> <div className='tip'><Assets name='notice' />点击题目查看详情</div> <table> <thead> <tr> <th>序号</th> <th width='340'>题目</th> <th className="point" onClick={() => { this.questionSort('correct'); }}>正误<GIcon name={order === 'correct' ? 'arrow-down' : 'arrow-up'} active={order === 'correct'} /></th> <th className="point" onClick={() => { this.questionSort('diff'); }}>难度<GIcon name={order === 'diff' ? 'arrow-down' : 'arrow-up'} active={order === 'diff'} /></th> <th className="point" onClick={() => { this.questionSort('userTime'); }}>用时<GIcon name={order === 'userTime' ? 'arrow-down' : 'arrow-up'} active={order === 'userTime'} /></th> <th className="point" onClick={() => { this.questionSort('place'); }}>主要考点<GIcon name={order === 'place' ? 'arrow-down' : 'arrow-up'} active={order === 'place'} /></th> <th className="point" onClick={() => { this.questionSort('collect'); }}>收藏<GIcon name={order === 'collect' ? 'arrow-down' : 'arrow-up'} active={order === 'collect'} /></th> <th className="point" onClick={() => { this.questionSort('note'); }}>笔记<GIcon name={order === 'note' ? 'arrow-down' : 'arrow-up'} active={order === 'note'} /></th> </tr> </thead> <tbody> {(list || []).map(row => { return <tr> <td>{row.no}</td> <td> <div className='n'><Link to={`/paper/question/${row.id}`}>{row.questionNo.title}</Link></div> <div className='desc'>{row.question.description}</div> </td> <td><GIcon name={row.isCorrect ? 'right' : 'error'} noHover /></td> <td>{row.question.difficult}</td> <td>{formatMinuteSecond(row.userTime)}</td> <td>{row.question.place}</td> <td><GIcon name='star' active={row.collect} noHover /></td> <td><GIcon name='note' active={row.note} noHover /></td> </tr>; })} </tbody> </table> </div> </div> </div>; } renderExerciseDetail() { const { report = {} } = this.state; let { detail = {} } = report; detail = detail || {}; const { pace = [], info = {}, difficult = [], place = [], limit = {} } = detail; return <div> <div className="body"> <div className="content"> <div className="title">完成情况</div> <div className="detail"> <div className="block"> <div className="t1">总耗时</div> <div className="t2">{formatMinute(info.userTime, true)}</div> <div className="t3">min</div> </div> {info.userTime > info.time && <div className="block"> <div className="t1">超出建议用时</div> <div className="t2">{formatMinute(info.userTime - info.time, true)}</div> <div className="t3">min</div> </div>} <div className="line" /> <div className="block"> <div className="t1">完成题目</div> <div className="t2">{info.userNumber}</div> <div className="t3">题</div> </div> {info.userNumber !== info.questionNumber && <div className="block"> <div className="t1">剩余未做</div> <div className="t2">{info.questionNumber - info.userNumber}</div> <div className="t3">题</div> </div>} </div> </div> </div> <div className="body gray"> <div className="content"> <div className="title">基本情况</div> <div className="block-wrapper"> <div className="block"> <PieChart option={pieOption1('正确率', info.userCorrect, info.userNumber, info.totalCorrect, info.totalNumber)} /> </div> <div className="block"> <BarChart option={barOption1('用时', info.userTime / info.userNumber, info.totalTime / info.totalNumber, info.correctTime, info.incorrectTime)} /> </div> </div> </div> </div> <div className="body"> <div className="content"> <div className="title">PACE</div> <div className="detail-1"> <div className="block"> <div className="t1">平均用时</div> <div dangerouslySetInnerHTML={{ __html: formatSeconds(info.userTime / info.userNumber).replace(/([0-9]+)(m|min|h|hour|s)/g, '<div class="s">$1</div><div class="t3">$2</div>') }} /> </div> <div className="block all"> <div className="t1">全站用户</div> <div dangerouslySetInnerHTML={{ __html: formatSeconds(info.totalTime / info.totalNumber).replace(/([0-9]+)(m|min|h|hour|s)/g, '<div class="s">$1</div><div class="t3">$2</div>') }} /> </div> </div> <LineChart height={400} option={lineOption1( '每题用时情况', pace.map(row => { return [`${row.no}`, row.userTime, row.time]; }), ['我的', '全站'], ['#7AA7DC', '#8684df'], )} /> </div> </div> {report.paperModule !== 'textbook' && <div className="body gray"> <div className="content"> <div className="title">难度分析</div> <div className="detail-1"> <div className="block"> <div className="t1">正确率</div> <div className="t2">{formatPercent(info.userCorrect, info.userNumber, false)}</div> </div> <div className="block all"> <div className="t1">全站用户</div> <div className="t2">90</div> <div className="t3">{formatPercent(info.totalCorrect, info.totalNumber, false)}</div> </div> </div> <BarChart height={400} option={BarOption2( '正确率', difficult.map(row => { return [QuestionDifficultMap[row.key], formatPercent(row.userCorrect, row.userNumber), formatPercent(row.totalCorrect, row.totalNumber)]; }), ['我的', '全站'], ['#8684df', '#5195e5'], )} /> </div> </div>} <div className="body"> <div className="content"> <div className="title">知识体系分析</div> <div className="detail-1"> <div className="block"> <div className="t1">平均用时</div> <div dangerouslySetInnerHTML={{ __html: formatSeconds(info.userTime / info.userNumber).replace(/([0-9]+)(m|min|h|hour|s)/g, '<div class="s">$1</div><div class="t3">$2</div>') }} /> </div> <div className="block all"> <div className="t1">正确率</div> <div className="t2">{formatPercent(info.userCorrect, info.userNumber, false)}</div> </div> </div> <BarChart height={400} option={BarOption3( ['知识点', '正确率分析', '用时分析'], place.map(row => { return row.key; }), place.map(row => { return formatPercent(row.userCorrect, row.userNumber); }), place.map(row => { return row.userTime / row.userNumber; }), ['#7AA7DC', '#BFD4EE'], ['#8684df', '#C3C3E5'], )} /> </div> </div> <div className="body gray"> <div className="content"> <div className="title">实战提醒</div> {info.userTime > info.time && <div className="tip"> <div className="t1">在实战限时情况下,本套题正确率为 </div> <div className="t2">{formatPercent(limit.userCorrect, limit.userNumber)}</div> <Tooltip message="仅统计在建议时间内完成题目正确率情况,更接近实战表现"><Icon type="question-circle" theme="filled" /></Tooltip> </div>} {info.userTime <= info.time && <div className="tip"> <div className="t1">目前的做题速度已达到实战标准!很棒!请继续保持!</div> </div>} </div> </div> <div className="body"> <div className="content t-c"> <Button size="lager" width={200} radius> 继续做题 </Button> </div> </div> </div>; } renderTextbookQuestion() { return this.renderExerciseQuestion(); } renderExaminationDetail() { const { report = {}, tab } = this.state; const { detail = {} } = report; const { subject = {} } = detail; const subjectDetail = tab === 'main' ? null : (subject || {})[tab] || { info: {}, defficlt: [], place: [], pace: [] }; return <div> <div className="body"> <div className="content"> <Tabs type="division" theme="gray" active={tab} space={7} tabs={[ { key: 'main', name: '总览 Overview' }, { key: 'verbal', name: '语文 Verbal' }, { key: 'quant', name: '数学 Quant' }, { key: 'ir', name: '综合推理 IR' }, ]} onChange={(value) => { this.setState({ tab: value }); }} /> {!subjectDetail && <div className="list"> <div className="title">完成情况</div> <div className="detail"> <div className="block"> <div className="t1" /> <div className="t4">Verbal</div> <div className="t4">Quant</div> <div className="t4">IR</div> </div> <div className="block"> <div className="t1">总耗时</div> <div className="t1"> <div className="t2">{formatMinute((subject.verbal || {}).userTime, true)}</div> <div className="t3">min</div> </div> <div className="t1"> <div className="t2">{formatMinute((subject.quant || {}).userTime, true)}</div> <div className="t3">min</div> </div> <div className="t1"> <div className="t2">{formatMinute((subject.ir || {}).userTime, true)}</div> <div className="t3">min</div> </div> </div> <div className="block"> <div className="t1">超出建议用时</div> <div className="t1"> <div className="t2">{formatMinute((subject.verbal || {}).userTime - (subject.verbal || {}).time, true)}</div> <div className="t3">min</div> </div> <div className="t1"> <div className="t2">{formatMinute((subject.quant || {}).userTime - (subject.quant || {}).time, true)}</div> <div className="t3">min</div> </div> <div className="t1"> <div className="t2">{formatMinute((subject.ir || {}).userTime - (subject.ir || {}).time, true)}</div> <div className="t3">min</div> </div> </div> <div className="block"> <div className="t1" /> <div className="t1"> <div className="line" /> </div> <div className="t1"> <div className="line" /> </div> <div className="t1"> <div className="line" /> </div> </div> <div className="block"> <div className="t1">完成题目</div> <div className="t1"> <div className="t2">{(subject.verbal || {}).userNumber}</div> <div className="t3">题</div> </div> <div className="t1"> <div className="t2">{(subject.quant || {}).userNumber}</div> <div className="t3">题</div> </div> <div className="t1"> <div className="t2">{(subject.ir || {}).userNumber}</div> <div className="t3">题</div> </div> </div> <div className="block"> <div className="t1">剩余未做</div> <div className="t1"> <div className="t2">{(subject.verbal || {}).questionNumber - (subject.verbal || {}).userNumber}</div> <div className="t3">题</div> </div> <div className="t1"> <div className="t2">{(subject.quant || {}).questionNumber - (subject.quant || {}).userNumber}</div> <div className="t3">题</div> </div> <div className="t1"> <div className="t2">{(subject.ir || {}).questionNumber - (subject.ir || {}).userNumber}</div> <div className="t3">题</div> </div> </div> </div></div>} {subjectDetail && <div> <div className="title">PACE</div> <div className="detail-1"> <div className="block"> <div className="t1">平均用时</div> <div dangerouslySetInnerHTML={{ __html: formatSeconds(subjectDetail.info.userTime / subjectDetail.info.userNumber).replace(/([0-9]+)(m|min|h|hour|s)/g, '<div class="s">$1</div><div class="t3">$2</div>') }} /> </div> </div> <LineChart height={400} option={lineOption1( '每题用时情况', subjectDetail.pace.map(row => { return [`${row.no}`, row.userTime]; }), ['我的'], ['#A3A8BF'], )} /> <div className="m-b-4" /> <LineChart height={400} option={lineOption1( '累计用时情况', (function (sd) { let userTime = 0; let time = 0; sd.pace.map(row => { userTime += row.userTime; time += row.time; return [`${row.no}`, userTime, time]; }); }(subjectDetail)), ['我的', '建议'], ['#A3A8BF', '#7AA7DC'], )} /> </div>} </div> </div> {!subjectDetail && <div className="body gray"> <div className="content"> <div className="title">成绩单</div> <table> <thead> <tr> <th>Question format</th> <th>Total</th> <th>Correct</th> <th>%Correct</th> <th> Avg Time </th> <th> Avg Time <br /> Correct </th> <th> Avg Time <br /> Incorrect </th> <th> Avg Diff <br /> Correct </th> <th> Avg Diff <br /> Incorrect </th> </tr> </thead> <tbody> {ExaminationQuestionType.map(row => { const typeDetail = detail.type[row.value]; return <tr> <td>{row.long}</td> <td>{typeDetail.info.questionNumber}</td> <td>{typeDetail.info.userCorrect}</td> <td> {formatPercent(typeDetail.info.userCorrect, typeDetail.info.userNumber)} </td> <td> {formatSecond(typeDetail.info.userTime / typeDetail.info.userNumber)} </td> <td> {formatSecond(typeDetail.info.correctTime / typeDetail.info.userCorrect)} </td> <td> {formatSecond(typeDetail.info.incorrectTime / typeDetail.info.userNumber - typeDetail.info.userCorrect)} </td> <td>{typeDetail.info.avgDiffCorrect}</td> <td>{typeDetail.info.avgDiffIncorrect}</td> </tr>; })} </tbody> </table> </div> </div>} {subjectDetail && <div className="body gray"> <div className="content"> <div className="title">基本情况</div> <table> <thead> <tr> <th>%Correct</th> <th>Avg Time</th> <th> Avg Time <br /> Correct </th> <th> Avg Time <br /> Incorrect </th> <th> Avg Diff <br /> Correct </th> <th> Avg Diff <br /> Incorrect </th> </tr> </thead> <tbody> <tr> <td> {formatPercent(subjectDetail.info.userCorrect, subjectDetail.info.userNumber)} <br /> <span>{subjectDetail.info.userCorrect}题/{subjectDetail.info.userNumber}题</span> </td> <td> {formatSecond(subjectDetail.info.userTime / subjectDetail.info.userNumber)} <br /> <span>{formatMinute(subjectDetail.info.userTime)}min/{subjectDetail.info.userNumber}题</span> </td> <td> {formatSecond(subjectDetail.info.correctTime / subjectDetail.info.userCorrect)} <br /> <span>{formatMinute(subjectDetail.info.correctTime)}min/{subjectDetail.info.userCorrect}题</span> </td> <td> {formatSecond(subjectDetail.info.incorrectTime / subjectDetail.info.userNumber - subjectDetail.info.userCorrect)} <br /> <span>{formatMinute(subjectDetail.info.incorrectTime)}min/{subjectDetail.info.userNumber}题</span> </td> <td>{subjectDetail.info.avgDiffCorrect}</td> <td>{subjectDetail.info.avgDiffIncorrect}</td> </tr> </tbody> </table> </div> </div>} {subjectDetail && <div className="body"> <div className="content"> <div className="title">难度分析</div> <BarChart height={400} option={BarOption2( '正确率', subjectDetail.difficult.map(row => { return [QuestionDifficultMap[row.key], formatPercent(row.userCorrect, row.userNumber)]; }), ['我的'], ['#989FC1'], )} /> </div> </div>} {subjectDetail && <div className="body gray"> <div className="content"> <div className="title">知识体系分析</div> <BarChart height={400} option={BarOption3( ['知识点', '正确率分析', '用时分析'], subjectDetail.place.map(row => { return row.key; }), subjectDetail.place.map(row => { return formatPercent(row.userCorrect, row.userNumber); }), subjectDetail.place.map(row => { return row.userTime / row.userNumber; }), ['#92AFD2', '#BFD4EE'], ['#989FC1', '#CCCCDC'], )} /> </div> </div>} </div >; } renderExaminationScore() { const { report = {} } = this.state; const { score } = report; return <div className="body"> <div className="content"> <div className="title">成绩单</div> <table> <thead> <tr> <th>学科</th> <th>分数</th> <th>排名</th> <th>题目</th> </tr> </thead> <tbody> {ExaminationSubject.map(row => { return <tr> <td>{row.long}</td> <td>{row.ignore ? '--' : score[`${row.value}Score`]}</td> <td>{row.ignore ? '--' : score[`${row.value}Rank`]}</td> <td><Button size="small" radius onClick={() => { Question.getDetailByNo(report.id, 1, row.value).then((r) => { linkTo(`/paper/question/${r.id}`); }); }}>回顾</Button></td></tr>; })} <tr> <td>Total</td> <td>{score.totalScore}</td> <td>{score.totalRank}</td> <td><Button size="small" radius onClick={() => { Question.getDetailByNo(report.id, 1).then((r) => { linkTo(`/paper/question/${r.id}`); }); }}>回顾</Button></td></tr>; </tbody> </table> </div> </div>; } }