From 2f0bf16bd6e093b63671c277d6b7af0506d940e6 Mon Sep 17 00:00:00 2001 From: sunhonglei Date: Fri, 7 Mar 2025 17:53:03 +0800 Subject: [PATCH] =?UTF-8?q?=E8=80=83=E8=AF=95=E7=BB=9F=E8=AE=A1=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../examination/src/api/exam-online/index.tsx | 19 ++ .../src/components/contentMain/index.js | 4 +- .../compoents/ExamDetailAnalysisPage.tsx | 243 ++++++++++++++++++ .../compoents/ExamPaperAnalysisPage.tsx | 214 +++++++++++++++ .../exam-online/exam-detail-analysis.tsx | 3 +- .../views/exam-online/exam-paper-analysis.tsx | 3 +- 6 files changed, 482 insertions(+), 4 deletions(-) create mode 100644 packages/examination/src/views/exam-online/compoents/ExamDetailAnalysisPage.tsx create mode 100644 packages/examination/src/views/exam-online/compoents/ExamPaperAnalysisPage.tsx diff --git a/packages/examination/src/api/exam-online/index.tsx b/packages/examination/src/api/exam-online/index.tsx index 1ab6847..dd9682c 100644 --- a/packages/examination/src/api/exam-online/index.tsx +++ b/packages/examination/src/api/exam-online/index.tsx @@ -90,3 +90,22 @@ export const examStatisticsChange = async (id:string) => { }); return response.data; }; + +export const getScoreDistribution = async (id:string) => { + const response = await axios.get('/ex/exam-statistics/getScoreDistribution',{ + params:{id:id} + }); + return response.data; +}; + +export const getExamDetailAnalysisPageList = async (obj:any) => { + const response = await axios.get('/ex/exam-statistics/getExamDetailAnalysisPageList',{ + params:obj + }); + return response.data; +}; + +export const getPaperAnalysisData = async () => { + const response = await axios.get('/ex/exam-statistics/getPaperAnalysisData'); + return response.data; +}; \ No newline at end of file diff --git a/packages/examination/src/components/contentMain/index.js b/packages/examination/src/components/contentMain/index.js index b0ce1b9..45d56d9 100644 --- a/packages/examination/src/components/contentMain/index.js +++ b/packages/examination/src/components/contentMain/index.js @@ -34,7 +34,7 @@ import QuestionUp from 'views/question/questionUp'; import ExamPaperList from 'views/examPaper/examPaperList'; import ExamDetailAnalysis from "../../views/exam-online/exam-detail-analysis"; import ExamPaperAnalysis from "../../views/exam-online/exam-paper-analysis"; -import ExamPaperAdd from 'views/examPaper/examPaperAdd'; +// import ExamPaperAdd from 'views/examPaper/examPaperAdd'; class ContentMain extends Component { @@ -64,7 +64,7 @@ class ContentMain extends Component { - + {/**/} diff --git a/packages/examination/src/views/exam-online/compoents/ExamDetailAnalysisPage.tsx b/packages/examination/src/views/exam-online/compoents/ExamDetailAnalysisPage.tsx new file mode 100644 index 0000000..5ab1621 --- /dev/null +++ b/packages/examination/src/views/exam-online/compoents/ExamDetailAnalysisPage.tsx @@ -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([]); + 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) => handleShowScoreDistribution(record.examId)}>成绩分布, + }, + ]; + + const getPieChartOption = (data: { value: number; name: string }[]) => ({ + tooltip: { + trigger: 'item', + formatter: '{a}
{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 ( +
+ {/* 检索条件行 */} + + + 考试名称: + setExamName(e.target.value)} + style={{ width: 'calc(100% - 100px)' }} // 调整输入框宽度 + /> + + + 试卷名称: + setPaperName(e.target.value)} + style={{ width: 'calc(100% - 100px)' }} // 调整输入框宽度 + /> + + + 考试区域: + setExamArea(convertArrToRegion(values))} + style={{ width: 'calc(100% - 100px)' }} // 调整级联选择器宽度 + /> + + + 监管行业: + + + + + + + + + + {/* 表格 */} + + + setVisible(false)} + footer={null} + width={600} + > + + + + ); +}; + +export default ExamDetailAnalysisPage; \ No newline at end of file diff --git a/packages/examination/src/views/exam-online/compoents/ExamPaperAnalysisPage.tsx b/packages/examination/src/views/exam-online/compoents/ExamPaperAnalysisPage.tsx new file mode 100644 index 0000000..31e9fc2 --- /dev/null +++ b/packages/examination/src/views/exam-online/compoents/ExamPaperAnalysisPage.tsx @@ -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) => 详情, + }, + { + title: 'paperId', + dataIndex: 'paperId', + visible: false, // 隐藏列 + }, + ]; + + return ( +
+ {/* 检索条件行 */} + +
+ 试卷名称: + setPaperName(e.target.value)} + style={{ width: 'calc(100% - 100px)' }} + /> + + + 监管行业: + + + + + + + + + + {/* 试卷数量行 */} + + +
+ 总计 + {totalCount} + +
+ + +
+ 已使用 + {usedCount} + +
+ + +
+ 停用 + {disabledCount} + +
+ + + {/* 表格 */} +
+

已使用试卷分析

+
+ + + ); +}; + +export default ExamPaperAnalysisPage; \ No newline at end of file diff --git a/packages/examination/src/views/exam-online/exam-detail-analysis.tsx b/packages/examination/src/views/exam-online/exam-detail-analysis.tsx index fffff8b..f31d04c 100644 --- a/packages/examination/src/views/exam-online/exam-detail-analysis.tsx +++ b/packages/examination/src/views/exam-online/exam-detail-analysis.tsx @@ -1,5 +1,6 @@ import React, { Component } from "react"; import ExamEditPage from "./compoents/ExamEditPage"; +import ExamDetailAnalysisPage from "./compoents/ExamDetailAnalysisPage"; interface States { resData: any visible: boolean @@ -25,7 +26,7 @@ class ExamDetailAnalysis extends Component { render() { return (
- +
) } diff --git a/packages/examination/src/views/exam-online/exam-paper-analysis.tsx b/packages/examination/src/views/exam-online/exam-paper-analysis.tsx index b341da0..db7529e 100644 --- a/packages/examination/src/views/exam-online/exam-paper-analysis.tsx +++ b/packages/examination/src/views/exam-online/exam-paper-analysis.tsx @@ -1,5 +1,6 @@ import React, { Component } from "react"; import ExamEditPage from "./compoents/ExamEditPage"; +import ExamPaperAnalysisPage from "./compoents/ExamPaperAnalysisPage"; interface States { resData: any visible: boolean @@ -25,7 +26,7 @@ class ExamPaperAnalysis extends Component { render() { return (
- +
) }