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
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; |