parent
17e162eed9
commit
2f0bf16bd6
6 changed files with 482 additions and 4 deletions
@ -0,0 +1,243 @@ |
|||||||
|
import React, { useState, useEffect } from 'react'; |
||||||
|
import { Row, Col, Input, Select, Button, Table, Space, Cascader, Modal } from 'antd'; |
||||||
|
import ReactECharts from 'echarts-for-react'; |
||||||
|
import {getExamDetailAnalysisPageList, getIndustryList, getScoreDistribution} from 'api/exam-online/index'; |
||||||
|
import { convertToCascaderData } from "./ExamEditPage"; |
||||||
|
|
||||||
|
const { Option } = Select; |
||||||
|
|
||||||
|
// 定义表格数据项的类型
|
||||||
|
type ExamDataItem = { |
||||||
|
key: string; |
||||||
|
examId: string; |
||||||
|
examName: string; |
||||||
|
paperName: string; |
||||||
|
examArea: string; |
||||||
|
industry: string; |
||||||
|
participants: number; |
||||||
|
averageTime: number; |
||||||
|
passRate: string; |
||||||
|
}; |
||||||
|
|
||||||
|
const ExamDetailAnalysisPage: React.FC = () => { |
||||||
|
const [examName, setExamName] = useState(''); |
||||||
|
const [paperName, setPaperName] = useState(''); |
||||||
|
const [examArea, setExamArea] = useState(''); |
||||||
|
const [industry, setIndustry] = useState(''); |
||||||
|
const [industryOptions, setIndustryOptions] = useState<{ value: string; label: string }[]>([]); |
||||||
|
const [tableData, setTableData] = useState<ExamDataItem[]>([]); |
||||||
|
const [pagination, setPagination] = useState({ |
||||||
|
current: 1, |
||||||
|
pageSize: 10, |
||||||
|
total: tableData.length, |
||||||
|
}); |
||||||
|
const [visible, setVisible] = useState(false); |
||||||
|
const [scoreDistributionData, setScoreDistributionData] = useState<{ value: number; name: string }[]>([]); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
const fetchData = async () => { |
||||||
|
try { |
||||||
|
const industryResponse = await getIndustryList(); |
||||||
|
setIndustryOptions(industryResponse.map((item: any) => ({ value: item.industry_id, label: item.industry_name }))); |
||||||
|
} catch (error) { |
||||||
|
console.error('数据获取失败:', error); |
||||||
|
} |
||||||
|
}; |
||||||
|
fetchData(); |
||||||
|
}, []); |
||||||
|
|
||||||
|
// 将省/市格式的数据转换为数组
|
||||||
|
const convertRegionToArr = (region: string) => { |
||||||
|
return region ? region.split('/') : []; |
||||||
|
}; |
||||||
|
|
||||||
|
// 修改后的 convertArrToRegion 函数
|
||||||
|
const convertArrToRegion = (regionArr: (string | number)[]) => { |
||||||
|
return regionArr.map(value => String(value)).join('/'); |
||||||
|
}; |
||||||
|
|
||||||
|
const handleReset = () => { |
||||||
|
setExamName(''); |
||||||
|
setPaperName(''); |
||||||
|
setExamArea(''); |
||||||
|
setIndustry(''); |
||||||
|
handleSearch(); |
||||||
|
}; |
||||||
|
|
||||||
|
const handleSearch = () => { |
||||||
|
const param = { |
||||||
|
examName:examName, |
||||||
|
paperName:paperName, |
||||||
|
industry:industry, |
||||||
|
examArea:examArea, |
||||||
|
} |
||||||
|
const fetchData = async () => { |
||||||
|
try { |
||||||
|
const resultData = await getExamDetailAnalysisPageList(param) |
||||||
|
setTableData(resultData); |
||||||
|
setPagination({ |
||||||
|
...pagination, |
||||||
|
current: 1, |
||||||
|
total: resultData.length, |
||||||
|
}); |
||||||
|
} catch (error) { |
||||||
|
console.error('数据获取失败:', error); |
||||||
|
} |
||||||
|
}; |
||||||
|
fetchData(); |
||||||
|
}; |
||||||
|
|
||||||
|
const handleTableChange = (newPagination: any) => { |
||||||
|
setPagination(newPagination); |
||||||
|
}; |
||||||
|
|
||||||
|
const handleShowScoreDistribution = async (examId: string) => { |
||||||
|
try { |
||||||
|
const response = await getScoreDistribution(examId); |
||||||
|
setScoreDistributionData(response); |
||||||
|
setVisible(true); |
||||||
|
} catch (error) { |
||||||
|
console.error('获取成绩分布数据失败:', error); |
||||||
|
} |
||||||
|
}; |
||||||
|
const columns = [ |
||||||
|
{ |
||||||
|
title: '序号', |
||||||
|
dataIndex: 'key', |
||||||
|
render: (text: any, record: ExamDataItem, index: number) => (pagination.current - 1) * pagination.pageSize + index + 1, |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: '考试名称', |
||||||
|
dataIndex: 'examName', |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: '试卷名称', |
||||||
|
dataIndex: 'paperName', |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: '考试区域', |
||||||
|
dataIndex: 'examArea', |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: '监管行业', |
||||||
|
dataIndex: 'industry', |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: '参与人数', |
||||||
|
dataIndex: 'participants', |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: '平均用时(分钟)', |
||||||
|
dataIndex: 'averageTime', |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: '合格率', |
||||||
|
dataIndex: 'passRate', |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: '查看', |
||||||
|
dataIndex: 'view', |
||||||
|
// 指定 record 的类型为 ExamDataItem
|
||||||
|
render: (text: any, record: ExamDataItem) => <a onClick={() => handleShowScoreDistribution(record.examId)}>成绩分布</a>, |
||||||
|
}, |
||||||
|
]; |
||||||
|
|
||||||
|
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={5}> |
||||||
|
<span style={{ marginRight: 8 }}>考试名称:</span> |
||||||
|
<Input |
||||||
|
placeholder="考试名称" |
||||||
|
value={examName} |
||||||
|
onChange={(e) => setExamName(e.target.value)} |
||||||
|
style={{ width: 'calc(100% - 100px)' }} // 调整输入框宽度
|
||||||
|
/> |
||||||
|
</Col> |
||||||
|
<Col span={5}> |
||||||
|
<span style={{ marginRight: 8 }}>试卷名称:</span> |
||||||
|
<Input |
||||||
|
placeholder="试卷名称" |
||||||
|
value={paperName} |
||||||
|
onChange={(e) => setPaperName(e.target.value)} |
||||||
|
style={{ width: 'calc(100% - 100px)' }} // 调整输入框宽度
|
||||||
|
/> |
||||||
|
</Col> |
||||||
|
<Col span={5}> |
||||||
|
<span style={{ marginRight: 8 }}>考试区域:</span> |
||||||
|
<Cascader |
||||||
|
options={convertToCascaderData()} |
||||||
|
placeholder="请选择考试区域" |
||||||
|
onChange={(values) => setExamArea(convertArrToRegion(values))} |
||||||
|
style={{ width: 'calc(100% - 100px)' }} // 调整级联选择器宽度
|
||||||
|
/> |
||||||
|
</Col> |
||||||
|
<Col span={5}> |
||||||
|
<span style={{ marginRight: 8 }}>监管行业:</span> |
||||||
|
<Select |
||||||
|
placeholder="监管行业" |
||||||
|
value={industry} |
||||||
|
onChange={(value) => setIndustry(value)} |
||||||
|
style={{ width: 150 }} // 调整下拉框宽度
|
||||||
|
> |
||||||
|
<Option key="" value="">全部</Option> |
||||||
|
{industryOptions.map((option) => ( |
||||||
|
<Option key={option.value} value={option.value}> |
||||||
|
{option.label} |
||||||
|
</Option> |
||||||
|
))} |
||||||
|
</Select> |
||||||
|
</Col> |
||||||
|
<Col span={4}> |
||||||
|
<Space> |
||||||
|
<Button onClick={handleReset}>重置</Button> |
||||||
|
<Button type="primary" onClick={handleSearch}>查询</Button> |
||||||
|
</Space> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
{/* 表格 */} |
||||||
|
<Table |
||||||
|
columns={columns} |
||||||
|
dataSource={tableData} |
||||||
|
pagination={pagination} |
||||||
|
onChange={handleTableChange} |
||||||
|
style={{ marginTop: 20 }} |
||||||
|
/> |
||||||
|
|
||||||
|
<Modal |
||||||
|
title="成绩分布" |
||||||
|
visible={visible} |
||||||
|
onCancel={() => setVisible(false)} |
||||||
|
footer={null} |
||||||
|
width={600} |
||||||
|
> |
||||||
|
<ReactECharts option={getPieChartOption(scoreDistributionData)} /> |
||||||
|
</Modal> |
||||||
|
</div> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
export default ExamDetailAnalysisPage; |
@ -0,0 +1,214 @@ |
|||||||
|
import React, { useState, useEffect } from 'react'; |
||||||
|
import { Row, Col, Input, Select, Button, Table, Space } from 'antd'; |
||||||
|
import { getIndustryList, getPaperAnalysisData } from 'api/exam-online/index'; // 假设的接口导入
|
||||||
|
|
||||||
|
const { Option } = Select; |
||||||
|
|
||||||
|
// 定义表格数据项的类型
|
||||||
|
type PaperAnalysisDataItem = { |
||||||
|
key: string; |
||||||
|
paperId: string; |
||||||
|
paperName: string; |
||||||
|
industry: string; |
||||||
|
useCount: number; |
||||||
|
participantCount: number; |
||||||
|
accuracyRate: string; |
||||||
|
}; |
||||||
|
|
||||||
|
// 模拟数据
|
||||||
|
const mockData: PaperAnalysisDataItem[] = [ |
||||||
|
{ |
||||||
|
key: '1', |
||||||
|
paperId: 'paper1', |
||||||
|
paperName: '试卷1', |
||||||
|
industry: '行业1', |
||||||
|
useCount: 20, |
||||||
|
participantCount: 100, |
||||||
|
accuracyRate: '80%', |
||||||
|
}, |
||||||
|
{ |
||||||
|
key: '2', |
||||||
|
paperId: 'paper2', |
||||||
|
paperName: '试卷2', |
||||||
|
industry: '行业2', |
||||||
|
useCount: 30, |
||||||
|
participantCount: 150, |
||||||
|
accuracyRate: '90%', |
||||||
|
}, |
||||||
|
// 可以添加更多模拟数据
|
||||||
|
]; |
||||||
|
|
||||||
|
const ExamPaperAnalysisPage: React.FC = () => { |
||||||
|
const [paperName, setPaperName] = useState(''); |
||||||
|
const [industry, setIndustry] = useState(''); |
||||||
|
const [industryOptions, setIndustryOptions] = useState<{ value: string; label: string }[]>([]); |
||||||
|
const [tableData, setTableData] = useState(mockData); |
||||||
|
const [pagination, setPagination] = useState({ |
||||||
|
current: 1, |
||||||
|
pageSize: 10, |
||||||
|
total: mockData.length, |
||||||
|
}); |
||||||
|
const [totalCount, setTotalCount] = useState(0); |
||||||
|
const [usedCount, setUsedCount] = useState(0); |
||||||
|
const [disabledCount, setDisabledCount] = useState(0); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
const fetchData = async () => { |
||||||
|
try { |
||||||
|
const industryResponse = await getIndustryList(); |
||||||
|
setIndustryOptions(industryResponse.map((item: any) => ({ value: item.industry_id, label: item.industry_name }))); |
||||||
|
|
||||||
|
const paperAnalysisResponse = await getPaperAnalysisData(); |
||||||
|
setTotalCount(paperAnalysisResponse.totalCount); |
||||||
|
setUsedCount(paperAnalysisResponse.usedCount); |
||||||
|
setDisabledCount(paperAnalysisResponse.disabledCount); |
||||||
|
} catch (error) { |
||||||
|
console.error('数据获取失败:', error); |
||||||
|
} |
||||||
|
}; |
||||||
|
fetchData(); |
||||||
|
}, []); |
||||||
|
|
||||||
|
const handleReset = () => { |
||||||
|
setPaperName(''); |
||||||
|
setIndustry(''); |
||||||
|
setTableData(mockData); |
||||||
|
setPagination({ |
||||||
|
...pagination, |
||||||
|
current: 1, |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
const handleSearch = () => { |
||||||
|
// 这里可以添加实际的筛选逻辑
|
||||||
|
const filteredData = mockData.filter((item) => { |
||||||
|
return ( |
||||||
|
item.paperName.includes(paperName) && |
||||||
|
(industry === '' || item.industry === industry) |
||||||
|
); |
||||||
|
}); |
||||||
|
setTableData(filteredData); |
||||||
|
setPagination({ |
||||||
|
...pagination, |
||||||
|
current: 1, |
||||||
|
total: filteredData.length, |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
const handleTableChange = (newPagination: any) => { |
||||||
|
setPagination(newPagination); |
||||||
|
}; |
||||||
|
|
||||||
|
const columns = [ |
||||||
|
{ |
||||||
|
title: '序号', |
||||||
|
dataIndex: 'key', |
||||||
|
render: (text: any, record: PaperAnalysisDataItem, index: number) => (pagination.current - 1) * pagination.pageSize + index + 1, |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: '试卷名称', |
||||||
|
dataIndex: 'paperName', |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: '监管行业', |
||||||
|
dataIndex: 'industry', |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: '使用次数', |
||||||
|
dataIndex: 'useCount', |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: '参与人数', |
||||||
|
dataIndex: 'participantCount', |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: '准确率', |
||||||
|
dataIndex: 'accuracyRate', |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: '查看', |
||||||
|
dataIndex: 'view', |
||||||
|
render: (text:any, record: PaperAnalysisDataItem) => <a href={`/paper-detail/${record.paperId}`}>详情</a>, |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: 'paperId', |
||||||
|
dataIndex: 'paperId', |
||||||
|
visible: false, // 隐藏列
|
||||||
|
}, |
||||||
|
]; |
||||||
|
|
||||||
|
return ( |
||||||
|
<div style={{ padding: 20 }}> |
||||||
|
{/* 检索条件行 */} |
||||||
|
<Row gutter={16}> |
||||||
|
<Col span={6}> |
||||||
|
<span style={{ marginRight: 8 }}>试卷名称:</span> |
||||||
|
<Input |
||||||
|
placeholder="试卷名称" |
||||||
|
value={paperName} |
||||||
|
onChange={(e) => setPaperName(e.target.value)} |
||||||
|
style={{ width: 'calc(100% - 100px)' }} |
||||||
|
/> |
||||||
|
</Col> |
||||||
|
<Col span={6}> |
||||||
|
<span style={{ marginRight: 8 }}>监管行业:</span> |
||||||
|
<Select |
||||||
|
placeholder="监管行业" |
||||||
|
value={industry} |
||||||
|
onChange={(value) => setIndustry(value)} |
||||||
|
style={{ width: 150 }} |
||||||
|
> |
||||||
|
<Option key="" value="">全部</Option> |
||||||
|
{industryOptions.map((option) => ( |
||||||
|
<Option key={option.value} value={option.value}> |
||||||
|
{option.label} |
||||||
|
</Option> |
||||||
|
))} |
||||||
|
</Select> |
||||||
|
</Col> |
||||||
|
<Col span={4}> |
||||||
|
<Space> |
||||||
|
<Button onClick={handleReset}>重置</Button> |
||||||
|
<Button type="primary" onClick={handleSearch}>查询</Button> |
||||||
|
</Space> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
{/* 试卷数量行 */} |
||||||
|
<Row gutter={16} style={{ marginTop: 20 }}> |
||||||
|
<Col span={6}> |
||||||
|
<div style={{ backgroundColor: '#DCE4F8', padding: 10, textAlign: 'center' }}> |
||||||
|
<span style={{ color: 'black' }}>总计</span> |
||||||
|
<span style={{ color: '#86A3E7' }}>{totalCount}</span> |
||||||
|
<span style={{ color: 'black' }}>套</span> |
||||||
|
</div> |
||||||
|
</Col> |
||||||
|
<Col span={6}> |
||||||
|
<div style={{ backgroundColor: '#DCE4F8', padding: 10, textAlign: 'center' }}> |
||||||
|
<span style={{ color: 'black' }}>已使用</span> |
||||||
|
<span style={{ color: '#86A3E7' }}>{usedCount}</span> |
||||||
|
<span style={{ color: 'black' }}>套</span> |
||||||
|
</div> |
||||||
|
</Col> |
||||||
|
<Col span={6}> |
||||||
|
<div style={{ backgroundColor: '#DCE4F8', padding: 10, textAlign: 'center' }}> |
||||||
|
<span style={{ color: 'black' }}>停用</span> |
||||||
|
<span style={{ color: '#86A3E7' }}>{disabledCount}</span> |
||||||
|
<span style={{ color: 'black' }}>套</span> |
||||||
|
</div> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
{/* 表格 */} |
||||||
|
<div style={{ marginTop: 20 }}> |
||||||
|
<h3>已使用试卷分析</h3> |
||||||
|
<Table |
||||||
|
columns={columns} |
||||||
|
dataSource={tableData} |
||||||
|
pagination={pagination} |
||||||
|
onChange={handleTableChange} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
export default ExamPaperAnalysisPage; |
Loading…
Reference in new issue