import { FormControlProps, FormItem, getVariable } from 'amis'; import mammoth from 'mammoth/mammoth.browser'; import React from 'react'; @FormItem({ test: /(^|\/)examimport$/, name: 'examimport', }) export class ExamImportRenderer extends React.Component< FormControlProps, { exam: Array; file: any; } > { constructor(props: FormControlProps) { super(props); this.state = { exam: [], file: '', }; } // word 文件解析方法 parseWord(event: any, organization_id: any, category: any, onChange: any) { const reader = new FileReader(); reader.onload = (e: any) => { const arrayBuffer = e.target.result; const options = { convertImage: mammoth.images.imgElement((image: any) => { return image.read().then((res: any) => { let file = new Blob([res], { type: image.contentType, }); let formData = new FormData(); formData.set('file', file); return this.props.env .fetcher({ url: 'storage/v1/object/exam', method: 'post', dataType: 'form-data', data: formData, }) .then((res) => { return { src: res.data.data.value, }; }); }); }), ignoreEmptyParagraphs: false, }; mammoth .convertToHtml({ arrayBuffer: arrayBuffer }, options) .then((resultObject: any) => { let temp: any[] = []; let local: any[] = []; // 清除粗体、软回车,按空行或题号分割题目,并做 forEach 循环 resultObject.value .replace(/|<\/strong>/g, '') .replace(/
<\/p>/g, '

') .replace(/
/g, '

') .split(/

\s*<\/p>|(?\s*<\/p>)

\d+/g) .forEach((item: any, q_index: any) => { if (item) { // 清除开头的 . 或 、 if (!item.match(/^

/g)) { item = item.replace(/^(\.|、)/g, '

'); } // 建立当前题目的分割序列 let split_series: any[] = []; if (item.search(/

答案:|

答案:/g) > 0) { split_series.push({ pattern: /(

答案:|

答案:)/g, num: item.search(/

答案:|

答案:/g), dict: 'answer', }); } if (item.search(/

答案解析:|

答案解析:/g) > 0) { split_series.push({ pattern: /(

答案解析:|

答案解析:)/g, num: item.search(/

答案解析:|

答案解析:/g), dict: 'analysis', }); } if (item.search(/

难易程度:|

难易程度:/g) > 0) { split_series.push({ pattern: /(

难易程度:|

难易程度:)/g, num: item.search(/

难易程度:|

难易程度:/g), dict: 'difficulty', }); } if (item.search(/

题型:|

题型:/g) > 0) { split_series.push({ pattern: /(

题型:|

题型:)/g, num: item.search(/

题型:|

题型:/g), dict: 'type', }); } // 按分割序列各项在题目中的位置排序,从前到后 split_series = split_series.sort((a, b) => a.num - b.num); let exam = item; let data_item: any = {}; let last_split_item: any = {}; // 按分割序列逐项分割当前题目 split_series.forEach((split_item, index) => { let result = exam.split(split_item.pattern); // 如果是第一项,必定是题干和选项(如有),其他项则为其他信息 if (!index) { // 提取选项 let options = result[0].match( /

[A-Za-z](\.|、).+?<\/p>(?=

[A-Za-z](\.|、)|$)/g ); // 如果有选项则继续分割题干和选项,否则即为题干 if (options) { let title = result[0] .replace(/\n/g, '') .match(/^.+?(?=

[A-Za-z](\.|、))/g)[0] .replace( /(

\d+(\.|、)\{<\/p>)|(?<=

)\d+(\.|、)|(

}<\/p>)/g, '' ) .replace(/(?<=

)\s+|\s+(?=<\/p>)/g, ''); options = options.map((item: any) => { return { key: item.match(/(?<=

)[A-Za-z]/g)[0], label: '

' .concat( item .match(/(?<=\.|、).+<\/p>/g)[0] .replace(/(

{<\/p>)|(

}<\/p>)/g, '') ) .replace(/(?<=

)\s+|\s+(?=<\/p>)/g, ''), is_fixed: false, }; }); // 判断是否有相同的选项 let key_set = new Set(); let key_count = 0; options.forEach((item: any) => { key_set.add(item.key); key_count++; }); if (key_set.size !== key_count) local.push(q_index + 1); data_item.options = options; data_item.title = title; } else { let title = result[0] .replace( /(

\d+(\.|、)\{<\/p>)|(?<=

)\d+(\.|、)|(

}<\/p>)/g, '' ) .replace(/(?<=

)\s+|\s+(?=<\/p>)/g, ''); data_item.title = title; } } else { // 清除 { 、} 和 分割项 data_item[last_split_item.dict] = result[0] .replace(/(

{<\/p>)|(

}<\/p>)/g, '') .replace(last_split_item.pattern, '

') .replace(/(?<=

)\s+|\s+(?=<\/p>)/g, ''); // 如果是答案、题型、难易程度,则清除 DOM 标签,并清除空格 if ( last_split_item.dict === 'answer' || last_split_item.dict === 'type' || last_split_item.dict === 'difficulty' ) { data_item[last_split_item.dict] = data_item[ last_split_item.dict ] .replace(/

|<\/p>/g, '') .replace(/(?<=

)\s+|\s+(?=<\/p>)/g, ''); } } // 最后一项 if (index + 1 === split_series.length) { data_item[split_item.dict] = result[1] .concat(result[2]) .replace(/(

{<\/p>)|(

}<\/p>)/g, '') .replace(split_item.pattern, '

') .replace(/(?<=

)\s+|\s+(?=<\/p>)/g, ''); // 如果是答案、题型、难易程度,则清除 DOM 标签,并清除空格 if ( split_item.dict === 'answer' || split_item.dict === 'type' || split_item.dict === 'difficulty' ) { data_item[split_item.dict] = data_item[split_item.dict] .replace(/

|<\/p>/g, '') .replace(/(?<=

)\s+|\s+(?=<\/p>)/g, ''); } } // 重组分割项和剩余项 exam = result[1].concat(result[2]); // 保留上一次分割的分割项 last_split_item = split_item; }); if (data_item.type === '判断题') { data_item.options = [ { key: '正确', label: '正确', is_fixed: false }, { key: '错误', label: '错误', is_fixed: false }, ]; } data_item.organization_id = organization_id; data_item.category = category; temp.push(data_item); } }); this.setState({ exam: temp, file: '' }); if (!local.length) { onChange(this.state.exam); } else { this.props.env.notify( 'error', `第 ${local.toString()} 题中有重复选项,请修改后重新上传` ); } }); }; if (event.target.files.length !== 0) { reader.readAsArrayBuffer(event.target.files[0]); } } updateValue(event: any) { this.setState({ file: event.target.value }); } render() { const { data, onChange } = this.props; const { exam } = this.state; const organization_id = getVariable(data, 'centre_id'); const category = getVariable(data, 'tree'); return (

{ this.parseWord(event, organization_id, category, onChange); this.updateValue(event); }} />
); } }