You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

456 lines
21 KiB

import React, { Component } from "react";
import { Form, Input, Button, Radio, Checkbox, Select, message } from "antd";
import { dictionary } from "api/dict/index";
import { addQuestion, findIndustry } from "api/question";
import * as XLSX from "xlsx";
// @ts-ignore
import { saveAs } from "file-saver";
import TextArea from "antd/es/input/TextArea";
const { Option } = Select;
interface States {
industryDict: any;
serviceTypeDict: any;
formIds: string[];
questionTypesMap: { [formId: string]: string };
}
class QuestionAdd extends Component<any, States> {
formRef: any;
fileInputRef: any;
constructor(props: any) {
super(props);
this.formRef = React.createRef();
this.fileInputRef = React.createRef();
this.state = {
industryDict: [],
serviceTypeDict: [],
formIds: ["form_0"],
questionTypesMap: { "form_0": "1" }
};
const formValues = {};
formValues[`questionTypes_form_0`] = '1';
this.componentDidMount = () => {
this.formRef.current?.setFieldsValue(formValues);
this.handleFindDict();
};
}
componentDidMount() {
}
// 字典
handleFindDict() {
// 监管行业
findIndustry()
.then((res: any) => {
if (res.data) {
this.setState({ industryDict: res.data });
}
})
.catch(() => {
message.error("获取监管行业字典数据失败,请稍后重试");
});
// AQ服务类型
dictionary("serviceTypeDict")
.then((res) => {
if (res.data) {
this.setState({ serviceTypeDict: res.data });
}
})
.catch(() => {
message.error("获取AQ服务类型字典数据失败,请稍后重试");
});
}
// 题型切换
handleQuestionTypeChange = (formId: string, value: string) => {
const { questionTypesMap } = this.state;
const formValues = {};
formValues[`questionTypes_${formId}`] = value;
this.formRef.current.setFieldsValue(formValues);
this.setState((prevState) => ({
questionTypesMap: {
...prevState.questionTypesMap,
[formId]: value
}
}));
};
// 新增试题
handleAddNewQuestion = () => {
const { formIds } = this.state;
const lastId = formIds[formIds.length - 1];
const lastNumber = parseInt(lastId.split('_')[1], 10);
const newId = `form_${lastNumber + 1}`;
const formValues = {
[`questionTypes_${newId}`]: "1"
};
this.formRef.current.setFieldsValue(formValues);
this.setState((prevState) => ({
formIds: [...prevState.formIds, newId],
questionTypesMap: {
...prevState.questionTypesMap,
[newId]: "1"
}
}));
};
// 删除试题
handleDeleteQuestion = (formId: string) => {
const formValues = {};
const fields = [
"questionTypes",
"industryId",
"serviceTypeId",
"questionContent",
"optionA",
"optionB",
"optionC",
"optionD",
"answer"
];
fields.forEach((field) => {
formValues[`${field}_${formId}`] = undefined;
});
this.formRef.current.setFieldsValue(formValues);
const { questionTypesMap } = this.state;
const newQuestionTypesMap = { ...questionTypesMap };
delete newQuestionTypesMap[formId];
this.setState((prevState) => ({
formIds: prevState.formIds.filter((id) => id!== formId),
questionTypesMap: newQuestionTypesMap
}));
};
// 表单提交
handleSubmit = () => {
this.formRef.current.validateFields().then((values: any) => {
const questions: any = [];
const { formIds } = this.state;
formIds.forEach((formId) => {
let answer = values[`answer_${formId}`];
if (Array.isArray(answer)) {
answer.sort();
answer = answer.join(",");
}
questions.push({
questionTypes: values[`questionTypes_${formId}`],
industryId: values[`industryId_${formId}`],
serviceTypeId: values[`serviceTypeId_${formId}`],
questionContent: values[`questionContent_${formId}`],
optionA: values[`optionA_${formId}`],
optionB: values[`optionB_${formId}`],
optionC: values[`optionC_${formId}`],
optionD: values[`optionD_${formId}`],
answer: answer
});
});
addQuestion(questions).then((res) => {
const success = res["success"];
if (success) {
message.success(`新增成功`);
this.props.history.push("/questionList");
} else {
message.error("新增试题失败,请稍后重试");
}
}).catch(() => {
message.error("新增试题时发生错误,请检查");
});
});
};
// 下载模板
handleDownloadTemplate = () => {
const headers = [
"题型",
"监管行业",
"AQ服务类型",
"题干",
"选项A",
"选项B",
"选项C",
"选项D",
"答案"
];
const ws = XLSX.utils.aoa_to_sheet([headers]);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "试题模板");
const wbOut = XLSX.write(wb, { bookType: "xlsx", type: "array" });
saveAs(new Blob([wbOut], { type: "application/octet-stream" }), "试题模板.xlsx");
};
// 一键导入
handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file) {
const reader = new FileReader();
reader.onload = (event) => {
const data = new Uint8Array(event.target?.result as ArrayBuffer);
const workbook = XLSX.read(data, { type: "array" });
const firstSheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[firstSheetName];
const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
const rows = jsonData.slice(1);
const formValues = {};
const formIds: string[] = [];
const questionTypesMap = {};
if (rows.length === 0) {
message.warn('导入的文件中没有有效数据行');
return;
}
rows.forEach((row: any, index) => {
const formId = `form_${index}`;
formIds.push(formId);
formValues[`questionTypes_${formId}`] = String(row[0]);
formValues[`industryId_${formId}`] = String(row[1]);
formValues[`serviceTypeId_${formId}`] = String(row[2]);
formValues[`questionContent_${formId}`] = String(row[3]);
formValues[`optionA_${formId}`] = String(row[4]);
formValues[`optionB_${formId}`] = String(row[5]);
formValues[`optionC_${formId}`] = String(row[6]);
formValues[`optionD_${formId}`] = String(row[7]);
formValues[`answer_${formId}`] = String(row[8]);
questionTypesMap[formId] = String(row[0]);
});
this.setState({ formIds, questionTypesMap }, () => {
this.formRef.current.setFieldsValue(formValues);
});
};
reader.readAsArrayBuffer(file);
const input = this.fileInputRef.current;
if (input) {
input.value = null;
}
}
};
handleImportClick = () => {
this.fileInputRef.current?.click();
};
render() {
const { industryDict, serviceTypeDict, formIds, questionTypesMap } = this.state;
const handleListQuestion = () => {
this.props.history.push("/questionList");
};
return (
<div className="container">
<div style={{ textAlign: "right" }}>
<Button type="default" style={{ marginRight: 10 }} onClick={this.handleDownloadTemplate}>
</Button>
<Button type="default" onClick={this.handleImportClick}>
</Button>
<input
type="file"
ref={this.fileInputRef}
style={{ display: "none" }}
accept=".xlsx,.xls"
onChange={this.handleFileChange}
/>
</div>
<Form ref={this.formRef} layout="inline">
{formIds.map((formId, index) => (
<div key={formId} style={{ marginBottom: 30 }}>
<div style={{ display: "flex" }}>
<Form.Item name={`questionTypes_${formId}`}>
<Radio.Group
onChange={(e) => this.handleQuestionTypeChange(formId, e.target.value)}
>
<Radio.Button value="1"></Radio.Button>
<Radio.Button value="2"></Radio.Button>
</Radio.Group>
</Form.Item>
<Form.Item
label="监管行业:"
name={`industryId_${formId}`}
rules={[{ required: true, message: "请选择监管行业" }]}
>
<Select
placeholder="请选择监管行业"
style={{ width: 240 }}
allowClear
>
{industryDict && industryDict.length > 0? (
(() => {
let rows = [];
for (let i = 0; i < industryDict.length; i++) {
const item = industryDict[i];
rows.push(
<Option value={item.industryId}>{item.industryName}</Option>
);
}
return rows;
})()
) : (
<Option disabled></Option>
)}
</Select>
</Form.Item>
<Form.Item
label="AQ服务类型:"
name={`serviceTypeId_${formId}`}
rules={[{ required: true, message: "请选择AQ服务类型" }]}
>
<Select
placeholder="请选择AQ服务类型"
style={{ width: 240 }}
allowClear
>
{serviceTypeDict && serviceTypeDict.length > 0? (
(() => {
let rows = [];
for (let i = 0; i < serviceTypeDict.length; i++) {
const item = serviceTypeDict[i];
rows.push(
<Option value={String(item.dictKey)}>{item.dictValue}</Option>
);
}
return rows;
})()
) : (
<Option disabled></Option>
)}
</Select>
</Form.Item>
<Form.Item>
{index > 0 && (
<Button type="link" onClick={() => this.handleDeleteQuestion(formId)}>
X
</Button>
)}
</Form.Item>
</div>
<div style={{ display: "flex" }}>
<Form.Item
label="题干:"
name={`questionContent_${formId}`}
style={{ marginTop: 10 }}
rules={[{ required: true, message: "请输入题干内容" }]}
>
<Input.TextArea
placeholder="请输入题干内容" maxLength={200} showCount
style={{ width: 1100, height: 60 }}
/>
</Form.Item>
</div>
<div style={{ marginTop: 10, marginLeft: 40 }}>
<div style={{ display: "flex" }}>
<Form.Item
name={`answer_${formId}`}
rules={[{ required: true, message: "请选择答案" }]}
>
{questionTypesMap[formId] === "1"? (
<Radio.Group>
<div style={{ display: "flex" }}>
<Radio value="A">A</Radio>
<Form.Item name={`optionA_${formId}`}
rules={[{ required: true, message: "请输入答案" }]}
>
<Input placeholder="请输入答案" style={{ width: 500 }} />
</Form.Item>
<Radio value="B">B</Radio>
<Form.Item name={`optionB_${formId}`}
rules={[{ required: true, message: "请输入答案" }]}
>
<Input placeholder="请输入答案" style={{ width: 500 }} />
</Form.Item>
</div>
<div style={{ display: "flex", marginTop: 10 }}>
<Radio value="C">C</Radio>
<Form.Item name={`optionC_${formId}`}
rules={[{ required: true, message: "请输入答案" }]}
>
<Input placeholder="请输入答案" style={{ width: 500 }} />
</Form.Item>
<Radio value="D">D</Radio>
<Form.Item name={`optionD_${formId}`}
rules={[{ required: true, message: "请输入答案" }]}
>
<Input placeholder="请输入答案" style={{ width: 500 }} />
</Form.Item>
</div>
</Radio.Group>
) : (
<Checkbox.Group>
<div style={{ display: "flex" }}>
<Checkbox value="A">A</Checkbox>
<Form.Item name={`optionA_${formId}`}
rules={[{ required: true, message: "请输入答案" }]}
>
<Input placeholder="请输入答案" style={{ width: 500 }} />
</Form.Item>
<Checkbox value="B">B</Checkbox>
<Form.Item name={`optionB_${formId}`}
rules={[{ required: true, message: "请输入答案" }]}
>
<Input placeholder="请输入答案" style={{ width: 500 }} />
</Form.Item>
</div>
<div style={{ display: "flex", marginTop: 10 }}>
<Checkbox value="C">C</Checkbox>
<Form.Item name={`optionC_${formId}`}
rules={[{ required: true, message: "请输入答案" }]}
>
<Input placeholder="请输入答案" style={{ width: 500 }} />
</Form.Item>
<Checkbox value="D">D</Checkbox>
<Form.Item name={`optionD_${formId}`}
rules={[{ required: true, message: "请输入答案" }]}
>
<Input placeholder="请输入答案" style={{ width: 500 }} />
</Form.Item>
</div>
</Checkbox.Group>
)}
</Form.Item>
</div>
</div>
</div>
))}
</Form>
<div style={{ textAlign: "right" }}>
<Button type="default" onClick={this.handleAddNewQuestion}>
</Button>
</div>
<div style={{
textAlign: "right",
position: "fixed",
bottom: 10,
right: 10,
width: "100%",
zIndex: 1000
}}>
<Button type="default" htmlType="button" onClick={handleListQuestion} style={{ marginRight: 10 }}>
</Button>
<Button type="primary" htmlType="submit" onClick={this.handleSubmit}>
</Button>
</div>
</div>
);
}
}
export default QuestionAdd;