commit
079c6c5a2b
5 changed files with 325 additions and 4 deletions
@ -0,0 +1,276 @@ |
||||
import React, { useEffect, useState, useRef } from 'react'; |
||||
import { Row, Col, Select, Table, Card } from 'antd'; |
||||
import ReactECharts from 'echarts-for-react'; |
||||
import {examStatisticsInit, getIndustryList} from "api/exam-online/index"; // 修改接口为获取带详情的试卷列表
|
||||
|
||||
const { Option } = Select; |
||||
|
||||
const examTableColumns = [ |
||||
{ |
||||
title: '考试次数', |
||||
dataIndex: 'examTimes', |
||||
key: 'examTimes', |
||||
}, |
||||
{ |
||||
title: '参与人数', |
||||
dataIndex: 'participants', |
||||
key: 'participants', |
||||
}, |
||||
{ |
||||
title: '平均用时(分钟)', |
||||
dataIndex: 'averageTime', |
||||
key: 'averageTime', |
||||
}, |
||||
{ |
||||
title: '合格率', |
||||
dataIndex: 'passRate', |
||||
key: 'passRate', |
||||
}, |
||||
]; |
||||
type initData = { |
||||
questionCount: number; |
||||
paperCount: number; |
||||
examCount: number; |
||||
industryDimensionData: { value: number; name: string }[]; |
||||
aqServiceDimensionData: { value: number; name: string }[]; |
||||
examTableData: { |
||||
key: string; |
||||
examTimes: number; |
||||
participants: number; |
||||
averageTime: number; |
||||
passRate: string; |
||||
}[]; |
||||
scoreDistributionData: { value: number; name: string }[]; |
||||
paperDistributionData: { value: number; name: string }[]; |
||||
}; |
||||
// 模拟题型占比数据
|
||||
const questionTypeDistributionData = [ |
||||
{ value: 25, name: '选择题' }, |
||||
{ value: 25, name: '填空题' }, |
||||
{ value: 25, name: '判断题' }, |
||||
{ value: 25, name: '简答题' }, |
||||
]; |
||||
|
||||
const Dashboard: React.FC = () => { |
||||
const industrySelectRef = useRef<HTMLSelectElement>(null); |
||||
|
||||
// 定义状态来存储从后台获取的数据
|
||||
const [questionCount, setQuestionCount] = useState(0); |
||||
const [paperCount, setPaperCount] = useState(0); |
||||
const [examCount, setExamCount] = useState(0); |
||||
const [industryOptions, setIndustryOptions] = useState<{ value: string; label: string }[]>([]); |
||||
const [industryDimensionData, setIndustryDimensionData] = useState<{ value: number; name: string }[]>([]); |
||||
const [aqServiceDimensionData, setAqServiceDimensionData] = useState<{ value: number; name: string }[]>([]); |
||||
const [examTableData, setExamTableData] = useState<{ |
||||
key: string; |
||||
examTimes: number; |
||||
participants: number; |
||||
averageTime: number; |
||||
passRate: string; |
||||
}[]>([]); |
||||
const [scoreDistributionData, setScoreDistributionData] = useState<{ value: number; name: string }[]>([]); |
||||
const [paperDistributionData, setPaperDistributionData] = useState<{ value: number; name: string }[]>([]); |
||||
|
||||
// 新增状态来控制显示的数据
|
||||
const [showIndustryDimension, setShowIndustryDimension] = useState(true); |
||||
const [showAQServiceDimension, setShowAQServiceDimension] = useState(true); |
||||
|
||||
useEffect(() => { |
||||
// 模拟从后台获取数据
|
||||
const fetchData = async () => { |
||||
try { |
||||
// 获取监管行业列表
|
||||
const industryResponse = await getIndustryList(); |
||||
setIndustryOptions(industryResponse.map((item: any) => ({ value: item.industry_id, label: item.industry_name }))); |
||||
// 这里可以替换为实际的 API 请求
|
||||
const response:initData = await examStatisticsInit(); |
||||
// 更新状态
|
||||
setQuestionCount(response.questionCount); |
||||
setPaperCount(response.paperCount); |
||||
setExamCount(response.examCount); |
||||
|
||||
setIndustryDimensionData(response.industryDimensionData); |
||||
setAqServiceDimensionData(response.aqServiceDimensionData); |
||||
setExamTableData(response.examTableData); |
||||
setScoreDistributionData(response.scoreDistributionData); |
||||
setPaperDistributionData(response.paperDistributionData); |
||||
} catch (error) { |
||||
console.error('数据获取失败:', error); |
||||
} |
||||
}; |
||||
|
||||
fetchData(); |
||||
}, []); |
||||
|
||||
useEffect(() => { |
||||
// 可以在这里添加下拉框选择变化的监听逻辑
|
||||
if (industrySelectRef.current) { |
||||
industrySelectRef.current.addEventListener('change', () => { |
||||
// 处理选择变化逻辑
|
||||
}); |
||||
} |
||||
}, []); |
||||
|
||||
const handleSelectChange = (value: string) => { |
||||
console.log('Selected value:', value); |
||||
if (value === '') { |
||||
// 选择“全部”
|
||||
setShowIndustryDimension(true); |
||||
setShowAQServiceDimension(true); |
||||
} else { |
||||
// 选择其他选项
|
||||
setShowIndustryDimension(false); |
||||
setShowAQServiceDimension(false); |
||||
} |
||||
}; |
||||
|
||||
// 环状图配置项生成函数
|
||||
const getRingChartOption = (data: { value: number; name: string }[]) => ({ |
||||
tooltip: { |
||||
trigger: 'item', |
||||
formatter: '{a} <br/>{b}: {c} ({d}%)', |
||||
}, |
||||
legend: { |
||||
orient: 'vertical', |
||||
right: 10, |
||||
top: 'center', |
||||
data: data.map(item => item.name), |
||||
}, |
||||
series: [ |
||||
{ |
||||
name: '占比', |
||||
type: 'pie', |
||||
radius: ['30%', '50%'], // 设置为环状图
|
||||
center: ['40%', '50%'], |
||||
data, |
||||
}, |
||||
], |
||||
}); |
||||
const getPieChartOption = (data: { value: number; name: string }[]) => ({ |
||||
tooltip: { |
||||
trigger: 'item', |
||||
formatter: '{a} <br/>{b}: {c} ({d}%)', |
||||
}, |
||||
legend: { |
||||
orient: 'vertical', |
||||
right: 10, |
||||
top: 'center', |
||||
data: data.map(item => item.name), |
||||
}, |
||||
series: [ |
||||
{ |
||||
name: '占比', |
||||
type: 'pie', |
||||
radius: '50%', |
||||
center: ['40%', '50%'], |
||||
data, |
||||
}, |
||||
], |
||||
}); |
||||
|
||||
return ( |
||||
<div style={{ padding: 20 }}> |
||||
{/* 第一行:试题数、试卷数、考试次数 */} |
||||
<Row gutter={16}> |
||||
<Col span={8}> |
||||
<div style={{ textAlign: 'center', background: '#DCE4F8', height: 60 }}> |
||||
<p>试题{questionCount}条</p> |
||||
</div> |
||||
</Col> |
||||
<Col span={8}> |
||||
<div style={{ textAlign: 'center', background: '#DCE4F8', height: 60 }}> |
||||
<p>试卷{paperCount}套</p> |
||||
</div> |
||||
</Col> |
||||
<Col span={8}> |
||||
<div style={{ textAlign: 'center', background: '#DCE4F8', height: 60 }}> |
||||
<p>考试{examCount}次</p> |
||||
</div> |
||||
</Col> |
||||
</Row> |
||||
|
||||
{/* 下面分为左右两部分 */} |
||||
<Row gutter={16} style={{ marginTop: 20 }}> |
||||
{/* 左半区:题库情况 */} |
||||
<Col span={12}> |
||||
<Card |
||||
title={( |
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}> |
||||
<span>题库情况</span> |
||||
<span> |
||||
监管行业: |
||||
<Select placeholder="请选择监管行业" onChange={handleSelectChange} style={{ width: 180 }} defaultValue=""> |
||||
<Option key="" value="">全部</Option> |
||||
{industryOptions.map(option => ( |
||||
<Option key={option.value} value={option.value}> |
||||
{option.label} |
||||
</Option> |
||||
))} |
||||
</Select> |
||||
</span> |
||||
</div> |
||||
)} |
||||
> |
||||
{/* 监管行业维度统计环状图 */} |
||||
{showIndustryDimension && ( |
||||
<div style={{ marginBottom: 20 }}> |
||||
<h3>监管行业维度统计</h3> |
||||
<ReactECharts option={getRingChartOption(industryDimensionData)} /> |
||||
</div> |
||||
)} |
||||
{!showIndustryDimension && ( |
||||
<div style={{ marginBottom: 20 }}> |
||||
<h3>AQ 服务类型维度统计</h3> |
||||
<ReactECharts option={getRingChartOption(aqServiceDimensionData)} /> |
||||
</div> |
||||
)} |
||||
<hr style={{ border: '1px solid #e8e8e8', marginBottom: 20 }} /> |
||||
{/* AQ 服务类型维度统计环状图 */} |
||||
{showAQServiceDimension && ( |
||||
<div> |
||||
<h3>AQ 服务类型维度统计</h3> |
||||
<ReactECharts option={getRingChartOption(aqServiceDimensionData)} /> |
||||
</div> |
||||
)} |
||||
{!showAQServiceDimension && ( |
||||
<div> |
||||
<h3>题型占比</h3> |
||||
<ReactECharts option={getRingChartOption(questionTypeDistributionData)} /> |
||||
</div> |
||||
)} |
||||
</Card> |
||||
</Col> |
||||
{/* 右半区:考试情况和试卷情况 */} |
||||
<Col span={12}> |
||||
{/* 考试情况 */} |
||||
<Card |
||||
title={( |
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}> |
||||
<span>考试情况</span> |
||||
<a>{('详情>>')}</a> |
||||
</div> |
||||
)} |
||||
> |
||||
{/* 考试情况表格 */} |
||||
<Table columns={examTableColumns} dataSource={examTableData} pagination={false} /> |
||||
<ReactECharts option={getPieChartOption(scoreDistributionData)} /> |
||||
</Card> |
||||
{/* 试卷情况环状图 */} |
||||
<Card |
||||
title={( |
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}> |
||||
<span>试卷情况</span> |
||||
<a>{('详情>>')}</a> |
||||
</div> |
||||
)} |
||||
style={{ marginTop: 20 }} |
||||
> |
||||
<ReactECharts option={getRingChartOption(paperDistributionData)} /> |
||||
</Card> |
||||
</Col> |
||||
</Row> |
||||
</div> |
||||
); |
||||
}; |
||||
|
||||
export default Dashboard; |
@ -0,0 +1,35 @@ |
||||
import React, { Component } from "react"; |
||||
import Dashboard from "./compoents/ExamStatisticsPage"; |
||||
|
||||
interface States { |
||||
resData: any |
||||
visible: boolean |
||||
title: string |
||||
current: any |
||||
} |
||||
|
||||
class ExamStatistics extends Component<any, States> { |
||||
constructor(props: any) { |
||||
super(props); |
||||
this.state = { |
||||
resData: undefined, |
||||
visible: false, |
||||
title: '新增公告', |
||||
current: {} |
||||
} |
||||
} |
||||
|
||||
componentDidMount() { |
||||
// this.getList()
|
||||
} |
||||
|
||||
render() { |
||||
return ( |
||||
<div className="container"> |
||||
<Dashboard /> |
||||
</div> |
||||
) |
||||
} |
||||
} |
||||
|
||||
export default ExamStatistics; |
Loading…
Reference in new issue