考试安排

main
sunhonglei 5 months ago
parent 0288826ad1
commit 1e1aa85a21
  1. 64
      packages/examination/src/api/exam-online/index.tsx
  2. 2
      packages/examination/src/components/contentMain/index.js
  3. 154
      packages/examination/src/views/exam-online/compoents/ExamDetailPage.tsx
  4. 192
      packages/examination/src/views/exam-online/compoents/ExamEditPage.tsx
  5. 193
      packages/examination/src/views/exam-online/compoents/ExamListPage.tsx
  6. 34
      packages/examination/src/views/exam-online/exam-detail.tsx
  7. 105
      packages/examination/src/views/exam-online/exam-edit.tsx

@ -1,5 +1,5 @@
import axios from '../axios'; import axios from '../axios';
//查询
export function getList(obj: any) { export function getList(obj: any) {
return axios({ return axios({
url: '/ex/exam-schedule/select', url: '/ex/exam-schedule/select',
@ -7,7 +7,7 @@ export function getList(obj: any) {
params: obj params: obj
}) })
} }
//新增考试
export function add(obj: any) { export function add(obj: any) {
return axios.post( '/ex/exam-schedule/insert', return axios.post( '/ex/exam-schedule/insert',
obj,{ obj,{
@ -16,25 +16,65 @@ export function add(obj: any) {
} }
}) })
} }
// 编辑的画面初期值检索
export function edit(obj: any) { export function getExamDataById(id:any){
return axios({ return axios({
url: '/ex/exam-edit', url: '/ex/exam-schedule/getExamDataById',
method: 'get', method: 'get',
params: {id:id}
}) })
} }
// 发布与批量发布
export function doPublish(ids: string[]) {
debugger
return axios.post('/ex/exam-schedule/publish', ids, {
headers: {
'Content-Type': 'application/json'
}
})
}
// 删除与批量删除
export function doDelete(ids: string[]) {
return axios.post('/ex/exam-schedule/delete', ids, {
headers: {
'Content-Type': 'application/json'
}
})
}
// 撤回与批量撤回
export function doCancel(ids: string[]) {
return axios.post('/ex/exam-schedule/cancel', ids, {
headers: {
'Content-Type': 'application/json'
}
})
}
// 答题情况
export const getDetail = async(id:any) =>{
const response = await axios({
url: '/ex/exam-schedule/getDetailById',
method: 'get',
params: {id:id}
})
return response.data;
}
// 监管行业下拉列表
export const getIndustryList = async () => { export const getIndustryList = async () => {
const response = await axios.get('/ex/exam-schedule/getIndustry'); const response = await axios.get('/ex/exam-schedule/getIndustry');
return response.data; return response.data;
}; };
// 试卷名称下拉列表(含考试分数,考试时长)
export const getPaperList = async (obj:any) => { export const getPaperListWithDetails = async () => {
const response = await axios.get('/ex/dict/dictionary?code='+obj); const response = await axios.get('/ex/exam-schedule/getPaper');
return response.data;
};
// 试卷状态check
export const paperStatusCheck = async () => {
const response = await axios.get('/ex/exam-schedule/paperStatusCheck');
return response.data; return response.data;
}; };
// 试卷删除状态check
export const getRegionList = async (obj:any) => { export const paperDeleteCheck = async () => {
const response = await axios.get('/ex/dict/dictionary?code='+obj); const response = await axios.get('/ex/exam-schedule/paperDeleteCheck');
return response.data; return response.data;
}; };

@ -26,6 +26,7 @@ import ExamEdit from "../../views/exam-online/exam-edit"; // demo list
import Customer from 'views/statistical/list'; import Customer from 'views/statistical/list';
import CustomerDetail from 'views/statistical/detail'; import CustomerDetail from 'views/statistical/detail';
import ExamDetail from "../../views/exam-online/exam-detail";
class ContentMain extends Component { class ContentMain extends Component {
render() { render() {
@ -46,6 +47,7 @@ class ContentMain extends Component {
<Route exact path='/exam-schedule' component={ ExamSchedule }/> <Route exact path='/exam-schedule' component={ ExamSchedule }/>
<Route exact path='/exam-add' component={ ExamAdd }/> <Route exact path='/exam-add' component={ ExamAdd }/>
<Route exact path='/exam-edit' component={ ExamEdit }/> <Route exact path='/exam-edit' component={ ExamEdit }/>
<Route exact path='/exam-detail' component={ ExamDetail }/>
<Redirect exact from='/' to='/home'/> <Redirect exact from='/' to='/home'/>
</Switch> </Switch>
</div> </div>

@ -0,0 +1,154 @@
import React, { useEffect, useState } from 'react';
import { Table, Button } from 'antd';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { getDetail } from "api/exam-online/index";
import ESBreadcrumbComponent from "./ESBreadcrumbComponent";
// 定义考试参与情况数据类型,移除 serialNumber 字段
type ExamParticipationItem = {
key: string;
name: string;
phoneNumber: string;
score: number;
wrongQuestionIds: string;
};
// 定义考试答题情况数据类型,移除 serialNumber 字段
type ExamAnswerItem = {
key: string;
questionNumber: string;
wrongPeopleCount: number;
wrongPeopleRatio: string;
};
// 定义 API 返回的数据类型
type DetailResponse = {
examParticipation: ExamParticipationItem[];
examAnswer: ExamAnswerItem[];
};
// 考试参与情况表格列定义
const examParticipationColumns: Array<{
title: string;
dataIndex?: keyof ExamParticipationItem;
key: string;
render?: (text: any, record: ExamParticipationItem, index: number) => React.ReactNode;
}> = [
{
title: '序号',
key: 'serialNumber',
render: (_, __, index) => index + 1
},
{
title: '姓名',
dataIndex: 'name',
key: 'name',
},
{
title: '手机号',
dataIndex: 'phoneNumber',
key: 'phoneNumber',
},
{
title: '成绩',
dataIndex: 'score',
key: 'score',
},
{
title: '错题编号',
dataIndex: 'wrongQuestionIds',
key: 'wrongQuestionIds',
render: (wrongQuestionIds)=>{
if(!wrongQuestionIds) {
return "-";
}else{
return wrongQuestionIds;
}
}
},
];
// 考试答题情况表格列定义
const examAnswerColumns: Array<{
title: string;
dataIndex?: keyof ExamAnswerItem;
key: string;
render?: (text: any, record: ExamAnswerItem, index: number) => React.ReactNode;
}> = [
{
title: '序号',
key: 'serialNumber',
render: (_, __, index) => index + 1
},
{
title: '题目号',
dataIndex: 'questionNumber',
key: 'questionNumber',
},
{
title: '错题人数',
dataIndex: 'wrongPeopleCount',
key: 'wrongPeopleCount',
},
{
title: '错题人数占比',
dataIndex: 'wrongPeopleRatio',
key: 'wrongPeopleRatio',
render: (wrongPeopleRatio)=>{
return wrongPeopleRatio+'%'
}
},
];
const ExamStatisticsPage: React.FC<RouteComponentProps> = ({ history }) => {
const [examParticipationData, setExamParticipationData] = useState<ExamParticipationItem[]>([]);
const [examAnswerData, setExamAnswerData] = useState<ExamAnswerItem[]>([]);
useEffect(() => {
const fetchData = async () => {
try {
const examId = sessionStorage.getItem('examId');
sessionStorage.removeItem('examId');
// 调用 getDetail 方法进行初始化检索
const response = await getDetail(examId);
// 从 AxiosResponse 中提取 data 部分
const data = response as DetailResponse;
// 假设返回的数据结构包含 examParticipation 和 examAnswer 两个字段
setExamParticipationData(data.examParticipation);
setExamAnswerData(data.examAnswer);
} catch (error) {
console.error('数据加载失败:', error);
}
};
fetchData();
}, []);
return (
<div style={{ padding: 20 }}>
<ESBreadcrumbComponent currentText="答题情况" />
{/* 考试参与情况部分 */}
<h2></h2>
<Table
columns={examParticipationColumns}
dataSource={examParticipationData}
pagination={false}
/>
{/* 考试答题情况部分 */}
<h2 style={{ marginTop: 20 }}></h2>
<Table
columns={examAnswerColumns}
dataSource={examAnswerData}
pagination={false}
/>
{/* 返回按钮 */}
<div style={{ marginTop: 20, textAlign: 'right' }}>
<Button onClick={() => history.push('/exam-schedule')}></Button>
</div>
</div>
);
};
export default withRouter(ExamStatisticsPage);

@ -1,26 +1,27 @@
import React, { useRef, useEffect, useState } from 'react'; import React, { useRef, useEffect, useState } from 'react';
// @ts-ignore // @ts-ignore
import {Form, Input, Select, DatePicker, Space, ColProps, Button, Cascader, DefaultOptionType} from 'antd'; import { Form, Input, Select, DatePicker, Space, ColProps, Button, Cascader, DefaultOptionType, Rule } from 'antd';
import type { FormProps, FormInstance } from 'antd'; import type { FormProps, FormInstance } from 'antd';
import ESBreadcrumbComponent from './ESBreadcrumbComponent'; // 引入面包屑组件 import ESBreadcrumbComponent from './ESBreadcrumbComponent'; // 引入面包屑组件
import { withRouter, RouteComponentProps } from 'react-router-dom'; // 引入 withRouter 和 RouteComponentProps import { withRouter, RouteComponentProps } from 'react-router-dom'; // 引入 withRouter 和 RouteComponentProps
import { getList, add, edit, getIndustryList, getPaperList } from "api/exam-online/index"; import { add, getIndustryList, getPaperListWithDetails } from "api/exam-online/index"; // 修改接口为获取带详情的试卷列表
import { provice } from './city.js'; // 引入省市县数据 import { provice } from './city.js'; // 引入省市县数据
import moment, { Moment } from 'moment'; // 引入 moment
const { Option } = Select; const { Option } = Select;
// 定义表单数据的类型 // 定义表单数据的类型
interface ExamBasicInfo { export interface ExamBasicInfo {
examId: string; examId: string;
examName: string; examName: string;
regulatoryIndustry: string; regulatedIndustry: string | number;
paperName: string; paperId: string;
examScore: string; examScore: string;
examDuration: string; examDuration: string;
examRegion: string[]; // 修改为数组类型,用于存储级联选择的值 examRegion: string | string[];
examValidTime: Date | null; validFrom: Moment | null;
examInvalidTime: Date | null; validTo: Moment | null;
contentDescription: string; remark: string;
} }
// 定义组件的 Props 类型 // 定义组件的 Props 类型
@ -33,7 +34,11 @@ interface ExamBasicInfoFormProps extends FormProps {
interface PropsWithRouter extends ExamBasicInfoFormProps, RouteComponentProps {} interface PropsWithRouter extends ExamBasicInfoFormProps, RouteComponentProps {}
export const convertToCascaderData = (): DefaultOptionType[] => { export const convertToCascaderData = (): DefaultOptionType[] => {
return provice.map(item => { const allRegionOption: DefaultOptionType = {
value: '全区域',
label: '全区域'
};
const provinceOptions = provice.map(item => {
const province: DefaultOptionType = { const province: DefaultOptionType = {
value: item.name, value: item.name,
label: item.name, label: item.name,
@ -44,18 +49,58 @@ export const convertToCascaderData = (): DefaultOptionType[] => {
}; };
return province; return province;
}); });
return [allRegionOption, ...provinceOptions];
};
// 日期格式化函数,支持 Moment 类型
const formatDate = (date: Moment | null | string): string | null => {
if (!date) return null;
if (typeof date === 'string') {
date = moment(date);
if (!date.isValid()) {
return null;
} }
}
const year = date.year();
const month = String(date.month() + 1).padStart(2, '0');
const day = String(date.date()).padStart(2, '0');
return `${year}-${month}-${day}`;
};
// 将省/市格式的数据转换为数组
const convertRegionToArr = (region: string) => {
return region ? region.split('/') : [];
};
// 将数组转换为省/市格式的字符串
const convertArrToRegion = (regionArr: string[]) => {
return regionArr.join('/');
};
const ExamBasicInfoForm: React.FC<PropsWithRouter> = (props) => { const ExamBasicInfoForm: React.FC<PropsWithRouter> = (props) => {
const { isEdit, initialFormData = {} as ExamBasicInfo, history } = props; const { isEdit, initialFormData = {} as ExamBasicInfo, history } = props;
const formRef = useRef<FormInstance<ExamBasicInfo>>(null); const formRef = useRef<FormInstance<ExamBasicInfo>>(null);
const [industryOptions, setIndustryOptions] = useState<{ value: string; label: string }[]>([]); const [industryOptions, setIndustryOptions] = useState<{ value: string | number; label: string }[]>([]);
const [paperOptions, setPaperOptions] = useState<{ value: string; label: string }[]>([]); const [allPaperOptions, setAllPaperOptions] = useState<{ value: string; label: string; examScore: string; examDuration: string; regulatedIndustry: string | number }[]>([]);
const [paperOptions, setPaperOptions] = useState<{ value: string; label: string; examScore: string; examDuration: string }[]>([]);
const [isDataLoaded, setIsDataLoaded] = useState(false);
const onFinish = async (values: ExamBasicInfo) => { const onFinish = async (values: ExamBasicInfo) => {
const { examRegion, validFrom, validTo, ...otherValues } = values;
// 处理 examRegion 转换为省/市 格式
const formattedRegion = Array.isArray(examRegion) ? convertArrToRegion(examRegion) : examRegion;
// 格式化日期
const formattedValidFrom = formatDate(validFrom);
const formattedValidTo = formatDate(validTo);
const formattedValues = {
...otherValues,
examRegion: formattedRegion,
validFrom: formattedValidFrom,
validTo: formattedValidTo
};
try { try {
// 调用 add 方法将数据发送到后台 // 调用 add 方法将数据发送到后台
const response = await add(values); const response = await add(formattedValues);
console.log('数据登录成功:', response); console.log('数据登录成功:', response);
// 登录成功后迁移到 /exam-schedule 页面 // 登录成功后迁移到 /exam-schedule 页面
history.push("/exam-schedule"); history.push("/exam-schedule");
@ -96,9 +141,17 @@ const ExamBasicInfoForm: React.FC<PropsWithRouter> = (props) => {
const industryResponse = await getIndustryList(); const industryResponse = await getIndustryList();
setIndustryOptions(industryResponse.map((item: any) => ({ value: item.industry_id, label: item.industry_name }))); setIndustryOptions(industryResponse.map((item: any) => ({ value: item.industry_id, label: item.industry_name })));
// 获取试卷列表 // 获取带详情的试卷列表
// const paperResponse = await getPaperList(); const paperResponse = await getPaperListWithDetails();
// setPaperOptions(paperResponse.map(item => ({ value: item, label: item }))); setAllPaperOptions(paperResponse.map((item: any) => ({
value: item.paper_id,
label: item.paper_name,
examScore: item.total_score,
examDuration: item.exam_duration,
regulatedIndustry: item.regulatory_industry // 假设接口返回的试卷数据包含监管行业信息
})));
setIsDataLoaded(true);
} catch (error) { } catch (error) {
console.error('数据加载失败:', error); console.error('数据加载失败:', error);
} }
@ -107,6 +160,77 @@ const ExamBasicInfoForm: React.FC<PropsWithRouter> = (props) => {
fetchData(); fetchData();
}, []); }, []);
useEffect(() => {
if (isDataLoaded) {
const initialIndustry = initialFormData.regulatedIndustry;
if (String(initialIndustry) === '') {
setPaperOptions(allPaperOptions);
} else if (initialIndustry) {
const filteredPapers = allPaperOptions.filter(paper => String(paper.regulatedIndustry) === String(initialIndustry));
setPaperOptions(filteredPapers);
} else {
setPaperOptions(allPaperOptions);
}
if (formRef.current) {
formRef.current.setFieldsValue({
examId: initialFormData.examId || '',
examName: initialFormData.examName || '',
examRegion: typeof initialFormData.examRegion === "string" ? convertRegionToArr(initialFormData.examRegion) : initialFormData.examRegion,
validFrom: initialFormData.validFrom || null,
validTo: initialFormData.validTo || null,
remark: initialFormData.remark || '',
});
// 设置监管行业的值
const selectedIndustry = industryOptions.find(option => String(option.value) === String(initialFormData.regulatedIndustry));
if (selectedIndustry) {
formRef.current.setFieldsValue({ regulatedIndustry: selectedIndustry.value });
} else {
formRef.current.setFieldsValue({ regulatedIndustry: '' });
}
// 设置试卷名称
formRef.current.setFieldsValue({ paperId: initialFormData.paperId || '' });
// 触发 handlePaperChange 函数更新考试分值和考试时长
handlePaperChange(initialFormData.paperId);
}
}
}, [isDataLoaded, allPaperOptions, initialFormData, industryOptions]);
const handleIndustryChange = (value: string | number) => {
if (String(value) === '') {
setPaperOptions(allPaperOptions);
} else {
const filteredPapers = allPaperOptions.filter(paper => String(paper.regulatedIndustry) === String(value));
setPaperOptions(filteredPapers);
}
if (formRef.current) {
formRef.current.setFieldsValue({ paperId: '' }); // 清空试卷选择
}
};
const handlePaperChange = (value: string) => {
const selectedPaper = allPaperOptions.find(paper => String(paper.value) === String(value));
if (selectedPaper && formRef.current) {
// 更新表单中的考试分值和考试时长
formRef.current.setFieldsValue({
examScore: selectedPaper.examScore,
examDuration: selectedPaper.examDuration
});
}
};
// 自定义验证函数:检查考试失效时间不得小于考试有效时间
const validateValidTo = (rule: Rule, value: Moment | null) => {
const validFrom = formRef.current?.getFieldValue('validFrom');
if (validFrom && value && value.isBefore(validFrom)) {
return Promise.reject(new Error('考试失效时间不得小于考试有效时间'));
}
return Promise.resolve();
};
return ( return (
<div> <div>
{/* 添加面包屑组件 */} {/* 添加面包屑组件 */}
@ -117,18 +241,6 @@ const ExamBasicInfoForm: React.FC<PropsWithRouter> = (props) => {
{...props} {...props}
name="examBasicInfo" name="examBasicInfo"
onFinish={onFinish} onFinish={onFinish}
initialValues={{
examId: initialFormData.examId || '',
examName: initialFormData.examName || '',
regulatoryIndustry: initialFormData.regulatoryIndustry || '',
paperName: initialFormData.paperName || '',
examScore: initialFormData.examScore || '',
examDuration: initialFormData.examDuration || '',
examRegion: initialFormData.examRegion || [], // 初始化 examRegion 为数组
examValidTime: initialFormData.examValidTime || null,
examInvalidTime: initialFormData.examInvalidTime || null,
contentDescription: initialFormData.contentDescription || '',
}}
autoComplete="off" autoComplete="off"
labelCol={labelCol} labelCol={labelCol}
wrapperCol={wrapperCol} wrapperCol={wrapperCol}
@ -151,15 +263,12 @@ const ExamBasicInfoForm: React.FC<PropsWithRouter> = (props) => {
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="监管行业" label="监管行业"
name="regulatoryIndustry" name="regulatedIndustry"
rules={[ rules={[]}
{ required
required: true,
message: '请选择监管行业',
},
]}
> >
<Select placeholder="请选择监管行业"> <Select placeholder="请选择监管行业" onChange={handleIndustryChange}>
<Option key="" value=""></Option>
{industryOptions.map(option => ( {industryOptions.map(option => (
<Option key={option.value} value={option.value}> <Option key={option.value} value={option.value}>
{option.label} {option.label}
@ -169,7 +278,7 @@ const ExamBasicInfoForm: React.FC<PropsWithRouter> = (props) => {
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="试卷名称" label="试卷名称"
name="paperName" name="paperId"
rules={[ rules={[
{ {
required: true, required: true,
@ -177,7 +286,7 @@ const ExamBasicInfoForm: React.FC<PropsWithRouter> = (props) => {
}, },
]} ]}
> >
<Select placeholder="请选择试卷名称"> <Select placeholder="请选择试卷名称" onChange={handlePaperChange}>
{paperOptions.map(option => ( {paperOptions.map(option => (
<Option key={option.value} value={option.value}> <Option key={option.value} value={option.value}>
{option.label} {option.label}
@ -208,7 +317,7 @@ const ExamBasicInfoForm: React.FC<PropsWithRouter> = (props) => {
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="考试有效时间" label="考试有效时间"
name="examValidTime" name="validFrom"
rules={[ rules={[
{ {
required: true, required: true,
@ -220,19 +329,20 @@ const ExamBasicInfoForm: React.FC<PropsWithRouter> = (props) => {
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="考试失效时间" label="考试失效时间"
name="examInvalidTime" name="validTo"
rules={[ rules={[
{ {
required: true, required: true,
message: '请选择考试失效时间', message: '请选择考试失效时间',
}, },
{ validator: validateValidTo }
]} ]}
> >
<DatePicker /> <DatePicker />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="内容描述" label="内容描述"
name="contentDescription" name="remark"
> >
<Input.TextArea rows={4} /> <Input.TextArea rows={4} />
</Form.Item> </Form.Item>

@ -1,8 +1,8 @@
import React, { useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Table, Input, Button, Select, DatePicker, Modal, Checkbox } from 'antd'; import { Table, Input, Button, Select, DatePicker, Modal, Checkbox, message } from 'antd';
import { Link, withRouter } from 'react-router-dom'; import { Link, withRouter } from 'react-router-dom';
import moment, { Moment } from 'moment'; // 引入 moment import moment, { Moment } from 'moment'; // 引入 moment
import { getList, add, edit } from "api/exam-online/index"; import { getList, doDelete, doCancel, doPublish, getIndustryList } from "api/exam-online/index";
const { Option } = Select; const { Option } = Select;
@ -27,13 +27,30 @@ const ExamListPage = ({ history }: { history: any }) => {
validTime: null as Moment | null, // 修改为 Moment 类型 validTime: null as Moment | null, // 修改为 Moment 类型
}); });
const [selectedRows, setSelectedRows] = useState<number[]>([]); const [selectedRows, setSelectedRows] = useState<number[]>([]);
const [examList, setExamList] = useState<Exam[]>([]); // 初始化为空数组 const [industryOptions, setIndustryOptions] = useState<{ value: string | number; label: string }[]>([]);
const [allExamList, setAllExamList] = useState<Exam[]>([]); // 存储所有数据
const [currentPageExamList, setCurrentPageExamList] = useState<Exam[]>([]); // 存储当前页数据
const [pagination, setPagination] = useState({ const [pagination, setPagination] = useState({
current: 1, current: 1,
pageSize: 10, pageSize: 10,
total: 0, total: 0,
}); });
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);
}
};
handleReset();
fetchData();
}, []);
// 重置按钮
const handleReset = () => { const handleReset = () => {
setSearchForm({ setSearchForm({
examName: '', examName: '',
@ -45,6 +62,7 @@ const ExamListPage = ({ history }: { history: any }) => {
handleSearch(); handleSearch();
}; };
// 查询
const handleSearch = async (page = 1) => { const handleSearch = async (page = 1) => {
try { try {
// 构建请求参数 // 构建请求参数
@ -52,64 +70,104 @@ const ExamListPage = ({ history }: { history: any }) => {
examName: searchForm.examName, examName: searchForm.examName,
paperName: searchForm.paperName, paperName: searchForm.paperName,
regulatedIndustry: searchForm.regulatedIndustry, regulatedIndustry: searchForm.regulatedIndustry,
validDate: searchForm.validTime ? searchForm.validTime.format('YYYY-MM-DD') : '', // 使用 moment 的 format 方法 validDate: searchForm.validTime ? searchForm.validTime.format('YYYY-MM-DD') : '' // 使用 moment 的 format 方法
page: page,
pageSize: pagination.pageSize,
}; };
// 调用 getList 方法向后端发送请求 // 调用 getList 方法向后端发送请求
const response = await getList(params); const response = await getList(params);
// 假设后端返回的数据结构为 { data: Exam[]; total: number } // 假设后端返回的数据结构为 { data: Exam[]; total: number }
const data = response.data; const data = response.data;
setExamList(data.data); setAllExamList(data.data);
const startIndex = (page - 1) * pagination.pageSize;
const endIndex = startIndex + pagination.pageSize;
setCurrentPageExamList(data.data.slice(startIndex, endIndex));
setPagination({ ...pagination, current: page, total: data.total }); setPagination({ ...pagination, current: page, total: data.total });
} catch (error) { } catch (error) {
console.error('查询出错:', error); console.error('查询出错:', error);
} }
}; };
const handleDeleteSelected = () => { // 批量删除
// 实现删除选中数据的逻辑 const handleDeleteSelected = async () => {
const newExamList = examList.filter((exam) => !selectedRows.includes(exam.examId)); const ids = selectedRows.map((value) => { return String(value) });
setExamList(newExamList); const res = await doDelete(ids);
setSelectedRows([]); if (!res) {
return;
}
research();
}; };
const handleWithdrawSelected = () => { // 批量撤回
// 实现撤回选中数据的逻辑 const handleWithdrawSelected = async () => {
const newExamList: Exam[] = examList.map((exam) => { const selectedExams = currentPageExamList.filter(exam => selectedRows.includes(exam.examId));
if (selectedRows.includes(exam.examId) && exam.publishStatus === 1) { const hasWithdrawn = selectedExams.some(exam => exam.publishStatus === 0 || exam.publishStatus === 2);
return { ...exam, publishStatus: 2 }; // 修正为 publishStatus
if (hasWithdrawn) {
const confirm = window.confirm('选中数据当中有无法撤回的数据,是否继续');
if (!confirm) {
return;
}
}
// 筛选出可以撤回的数据
const validExams = selectedExams.filter(exam => exam.publishStatus === 1);
const validIds = validExams.map(exam => String(exam.examId));
if (validIds.length > 0) {
const res = await doCancel(validIds);
if (!res) {
return;
}
research();
} }
return exam;
});
setExamList(newExamList);
setSelectedRows([]);
}; };
const handlePublishSelected = () => { // 批量发布
// 实现发布选中数据的逻辑 const handlePublishSelected = async () => {
const newExamList: Exam[] = examList.map((exam) => { const selectedExams = currentPageExamList.filter(exam => selectedRows.includes(exam.examId));
if (selectedRows.includes(exam.examId) && exam.publishStatus === 0) { const hasPublishedOrWithdrawn = selectedExams.some(exam => exam.publishStatus === 1 || exam.publishStatus === 2);
return { ...exam, publishStatus: 1 }; // 修正为 publishStatus
if (hasPublishedOrWithdrawn) {
const confirm = window.confirm('选中数据当中有无法发布的数据,是否继续');
if (!confirm) {
return;
}
}
// 筛选出可以发布的数据
const validExams = selectedExams.filter(exam => exam.publishStatus === 0);
const validIds = validExams.map(exam => String(exam.examId));
if (validIds.length > 0) {
const res = await doPublish(validIds);
if (!res) {
return;
}
research();
} }
return exam;
});
setExamList(newExamList);
setSelectedRows([]);
}; };
// 新增考试
const handleAddExam = () => { const handleAddExam = () => {
// 实现新增考试跳转逻辑 // 实现新增考试跳转逻辑
history.push('/exam-add'); history.push('/exam-add');
console.log('跳转到新增考试页面'); console.log('跳转到新增考试页面');
}; };
// 编辑
const handleEdit = (examId: number) => { const handleEdit = (examId: number) => {
sessionStorage.setItem('examId', String(examId));
history.push('/exam-edit');
// 实现编辑跳转逻辑 // 实现编辑跳转逻辑
console.log('跳转到编辑页面,examId:', examId); console.log('跳转到编辑页面,examId:', examId);
}; };
const handleDetail = (examId: number)=>{
sessionStorage.setItem('examId', String(examId));
history.push('/exam-detail');
console.log('跳转到答题情况,examId:', examId);
}
const [qrCodeVisible, setQrCodeVisible] = useState(false); const [qrCodeVisible, setQrCodeVisible] = useState(false);
const [qrCodeData, setQrCodeData] = useState(''); const [qrCodeData, setQrCodeData] = useState('');
@ -119,45 +177,55 @@ const ExamListPage = ({ history }: { history: any }) => {
setQrCodeVisible(true); setQrCodeVisible(true);
}; };
const handlePublishSingle = (examId: number) => { // 发布
// 实现单条数据发布逻辑 const handlePublishSingle = async (examId: number) => {
const newExamList: Exam[] = examList.map((exam) => { const ids = [String(examId)];
if (exam.examId === examId && exam.publishStatus === 0) { const res = await doPublish(ids);
return { ...exam, publishStatus: 1 }; // 修正为 publishStatus if (!res) {
return;
} }
return exam; research();
});
setExamList(newExamList);
}; };
const handleWithdrawSingle = (examId: number) => { // 撤回
// 实现单条数据撤回逻辑 const handleWithdrawSingle = async (examId: number) => {
const newExamList: Exam[] = examList.map((exam) => { const ids = [String(examId)];
if (exam.examId === examId && exam.publishStatus === 1) { const res = await doCancel(ids);
return { ...exam, publishStatus: 2 }; // 修正为 publishStatus if (!res) {
return;
} }
return exam; research();
});
setExamList(newExamList);
}; };
const handleDeleteSingle = (examId: number) => { // 删除
// 实现单条数据删除逻辑 const handleDeleteSingle = async (examId: number) => {
const newExamList = examList.filter((exam) => exam.examId !== examId); const ids = [String(examId)];
setExamList(newExamList); const res = await doDelete(ids);
if (!res) {
return;
}
research();
}; };
// 页面重新查询
const research = () => {
handleSearch(pagination.current);
}
// 处理全选和取消全选 // 处理全选和取消全选
const handleSelectAll = (checked: boolean) => { const handleSelectAll = (checked: boolean) => {
if (checked) { if (checked) {
setSelectedRows(examList.map((exam) => exam.examId)); // 确保 currentPageExamList 有数据
if (currentPageExamList.length > 0) {
setSelectedRows(currentPageExamList.map((exam) => exam.examId));
}
} else { } else {
setSelectedRows([]); setSelectedRows([]);
} }
}; };
// 判断是否全选 // 判断是否全选
const isAllSelected = examList.length > 0 && selectedRows.length === examList.length; const isAllSelected = currentPageExamList.length > 0 && selectedRows.length === currentPageExamList.length;
const columns = [ const columns = [
{ {
@ -193,7 +261,7 @@ const ExamListPage = ({ history }: { history: any }) => {
dataIndex: 'examName', dataIndex: 'examName',
key: 'examName', key: 'examName',
render: (text: string, record: Exam) => ( render: (text: string, record: Exam) => (
<Link to={`/exam-detail/${record.examId}`}>{text}</Link> <a onClick={() => handleDetail(record.examId)}>{text}</a>
), ),
}, },
{ {
@ -231,7 +299,6 @@ const ExamListPage = ({ history }: { history: any }) => {
dataIndex: 'publishStatus', dataIndex: 'publishStatus',
key: 'publishStatus', key: 'publishStatus',
render: (publishStatus: 0 | 1 | 2) => { render: (publishStatus: 0 | 1 | 2) => {
console.log(publishStatus)
switch (publishStatus) { switch (publishStatus) {
case 0: case 0:
return '待发布'; return '待发布';
@ -281,6 +348,8 @@ const ExamListPage = ({ history }: { history: any }) => {
const handleTableChange = (pagination: any) => { const handleTableChange = (pagination: any) => {
setPagination(pagination); setPagination(pagination);
// 清空选中状态
setSelectedRows([]);
handleSearch(pagination.current); handleSearch(pagination.current);
}; };
@ -311,10 +380,12 @@ const ExamListPage = ({ history }: { history: any }) => {
} }
style={{ width: 150, marginRight: 8 }} style={{ width: 150, marginRight: 8 }}
> >
<Option value=""></Option> <Option key="" value=""></Option>
<Option value="行业1">1</Option> {industryOptions.map(option => (
<Option value="行业2">2</Option> <Option key={option.value} value={option.value}>
{/* 可以添加更多选项 */} {option.label}
</Option>
))}
</Select> </Select>
<DatePicker <DatePicker
value={searchForm.validTime} // 使用 Moment 类型 value={searchForm.validTime} // 使用 Moment 类型
@ -335,7 +406,7 @@ const ExamListPage = ({ history }: { history: any }) => {
<Button onClick={handleWithdrawSelected} style={{ marginLeft: 8 }}> <Button onClick={handleWithdrawSelected} style={{ marginLeft: 8 }}>
</Button> </Button>
<Button onClick={handlePublishSelected} type="primary" style={{ marginLeft: 8 }}> <Button onClick={handlePublishSelected} style={{ marginLeft: 8 }}>
</Button> </Button>
<Button onClick={handleAddExam} type="primary" style={{ marginLeft: 8 }}> <Button onClick={handleAddExam} type="primary" style={{ marginLeft: 8 }}>
@ -344,7 +415,7 @@ const ExamListPage = ({ history }: { history: any }) => {
</div> </div>
<Table <Table
columns={columns} columns={columns}
dataSource={examList} dataSource={currentPageExamList}
rowKey="examId" rowKey="examId"
pagination={pagination} pagination={pagination}
onChange={handleTableChange} onChange={handleTableChange}

@ -0,0 +1,34 @@
import React, { Component } from "react";
import ExamDetailPage from "./compoents/ExamDetailPage";
interface States {
resData: any
visible: boolean
title: string
current: any
}
class ExamDetail 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">
<ExamDetailPage/>
</div>
)
}
}
export default ExamDetail;

@ -1,34 +1,107 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import ExamEditPage from "./compoents/ExamEditPage"; import ExamEditPage from "./compoents/ExamEditPage";
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { getExamDataById } from "api/exam-online/index";
import { ExamBasicInfo } from './compoents/ExamEditPage';
import moment, { Moment } from 'moment';
// 定义 Params 类型
interface Params {
examId: string;
}
// 定义 location.state 的类型
interface LocationState {
data?: number;
}
// 定义状态类型,使用 ExamBasicInfo 接口
interface States { interface States {
resData: any initialFormData: ExamBasicInfo;
visible: boolean isLoading: boolean;
title: string }
current: any
// 扩展 RouteComponentProps 以包含自定义的 location.state 类型
interface CustomRouteComponentProps extends RouteComponentProps<Params> {
location: {
state: LocationState;
pathname: string;
search: string;
hash: string;
};
} }
class ExamEdit extends Component<any, States> { class ExamEdit extends Component<CustomRouteComponentProps, States> {
constructor(props: any) { constructor(props: CustomRouteComponentProps) {
super(props); super(props);
this.state = { this.state = {
resData: undefined, initialFormData: {
visible: false, examId: '',
title: '', examName: '',
current: {} regulatedIndustry: '',
paperId: '',
examScore: '',
examDuration: '',
examRegion: '',
validFrom: null,
validTo: null,
remark: ''
},
isLoading: true
};
} }
async componentDidMount() {
// 尝试从 sessionStorage 中获取 examId
const storedExamId = sessionStorage.getItem('examId');
const examId = storedExamId;
if(storedExamId){
sessionStorage.removeItem('examId');
} }
componentDidMount() { try {
// this.getList() const response = await getExamDataById(examId);
const newInitFormData: ExamBasicInfo = {
examId: response.data.examId,
examName: response.data.examName,
regulatedIndustry: response.data.regulatedIndustry,
paperId: response.data.paperId,
examScore: response.data.examScore,
examDuration: response.data.examDuration,
examRegion: response.data.examRegion,
validFrom: response.data.validFrom ? moment(response.data.validFrom) : null,
validTo: response.data.validTo ? moment(response.data.validTo) : null,
remark: response.data.remark
};
console.log('Received examId:', examId);
this.setState({
initialFormData: newInitFormData,
isLoading: false
});
} catch (error) {
console.error('获取考试数据失败:', error);
this.setState({
isLoading: false
});
}
} }
render() { render() {
const { isLoading, initialFormData } = this.state;
if (isLoading) {
return <div>...</div>;
}
return ( return (
<div className="container"> <div className="container">
<ExamEditPage isEdit={true}/> <ExamEditPage isEdit={true} initialFormData={initialFormData} />
</div> </div>
) );
} }
} }
export default ExamEdit; export default withRouter(ExamEdit);
Loading…
Cancel
Save