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.
230 lines
11 KiB
230 lines
11 KiB
'use strict';
|
|
import React, { useState, useEffect } from 'react';
|
|
import { connect } from 'react-redux';
|
|
import { Modal, Form, Button, Notification } from '@douyinfe/semi-ui';
|
|
import { IconUpload } from '@douyinfe/semi-icons';
|
|
import XLSX from 'xlsx';
|
|
import moment from 'moment';
|
|
|
|
//下载模板和上传文件读取
|
|
const ImportModal = props => {
|
|
const { dispatch, actions, user, onCancel } = props
|
|
const { humanAffairs } = actions;
|
|
const [msg, setMsg] = useState('')
|
|
const [loading, setLoading] = useState('')
|
|
const [postData, setPostData] = useState([])
|
|
//初始化
|
|
useEffect(() => {
|
|
|
|
}, []);
|
|
|
|
const confirm = () => {
|
|
if (postData.length) {
|
|
setLoading(true)
|
|
dispatch(humanAffairs.importDepartmentTrainRecord(postData)).then(res => {
|
|
if (res.success) {
|
|
onCancel()
|
|
}
|
|
setLoading(false)
|
|
})
|
|
} else {
|
|
Notification.warning({ content: '没有数据可以提交,请上传数据文件', duration: 2 })
|
|
}
|
|
}
|
|
|
|
const download = () => {
|
|
const head = [["部门", "实际培训类型", "培训时间", "培训内容", "培训针对人群", "培训讲师", "培训方式", "考核形式", "培训时长"]];
|
|
let sheetName = '部门培训台账';
|
|
let workbook = { SheetNames: [sheetName], Sheets: {} };
|
|
workbook.Sheets[sheetName] = XLSX.utils.aoa_to_sheet(head);//json转excel
|
|
workbook.Sheets[sheetName]['!cols'] = [
|
|
{ wch: 12 }, { wch: 12 }, { wch: 15 }, { wch: 20 }, { wch: 12 },
|
|
{ wch: 10 }, { wch: 10 }, { wch: 10 }, { wch: 10 }];
|
|
let wopts = { bookType: 'xlsx', type: 'buffer' };// 生成excel的配置项
|
|
XLSX.writeFile(workbook, '部门培训记录导入模板.xlsx', wopts);
|
|
}
|
|
const error = (msg) => {
|
|
setMsg(msg)
|
|
onError({ message: msg })
|
|
}
|
|
|
|
const getFileBlob = (url) => {
|
|
return new Promise((resolve, reject) => {
|
|
let request = new XMLHttpRequest()
|
|
request.open("GET", url, true)
|
|
request.responseType = "blob"
|
|
request.onreadystatechange = e => {
|
|
if (request.readyState == 4) {
|
|
if (request.status == 200) {
|
|
if (window.FileReader) {
|
|
let reader = new FileReader();
|
|
reader.readAsBinaryString(request.response);
|
|
reader.onload = event => {
|
|
try {
|
|
const { result } = event.target;
|
|
// 以二进制流方式读取得到整份excel表格对象
|
|
const workbook = XLSX.read(result, {
|
|
type: "binary",
|
|
cellDates: true,//设为true,将天数的时间戳转为时间格式
|
|
codepage: 936//解决了乱码问题
|
|
});
|
|
let data = []; // 存储获取到的数据
|
|
// 遍历每张工作表进行读取(这里默认只读取第一张表)
|
|
for (const sheet in workbook.Sheets) {
|
|
if (workbook.Sheets.hasOwnProperty(sheet)) {
|
|
data = data.concat(XLSX.utils.sheet_to_json(workbook.Sheets[sheet]));
|
|
}
|
|
}
|
|
resolve(data);//导出数据
|
|
} catch (e) {
|
|
reject("失败");
|
|
error(`文件解析失败,请检查编码格式`)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
request.send();
|
|
})
|
|
}
|
|
const judgeNull = (value) => {
|
|
return value ? String(value).trim().replace(/\s*/g, "") : null;
|
|
}
|
|
|
|
const changeTime = (v) => {
|
|
//注意的点:xlsx将excel中的时间内容解析后,会小一天
|
|
//如2020/8/1,xlsx会解析成 Fri Jul 31 2020 23:59:17 GMT+0800 小了43秒
|
|
let a = new Date(v);
|
|
a.setTime(a.getTime() + 43 * 1000);
|
|
return a;
|
|
}
|
|
return (
|
|
<Modal
|
|
title="导入" visible={true}
|
|
onOk={confirm} width={620}
|
|
confirmLoading={loading}
|
|
onCancel={() => {
|
|
setMsg('')
|
|
setLoading(false)
|
|
setPostData([])
|
|
onCancel()
|
|
}}
|
|
>
|
|
<div style={{ borderBottom: '1px solid #DCDEE0', margin: '0px -24px' }}></div>
|
|
<Form>
|
|
<Form.Upload
|
|
label={'部门培训记录'} labelPosition='left'
|
|
action={'/'} accept={'.xlsx'}
|
|
maxSize={204800} limit={1}
|
|
onRemove={(currentFile, fileList, fileItem) => {
|
|
setMsg('');
|
|
setPostData([]);
|
|
}}
|
|
customRequest={(data) => {
|
|
const { file, onSuccess, onError } = data
|
|
getFileBlob(file.url).then(res => {
|
|
if (res.length > 1000) {
|
|
error('一次性上传数据行数应小于1000行,请分批上传')
|
|
return
|
|
}
|
|
if (!res.length) {
|
|
error('请填写至少一行数据')
|
|
return
|
|
}
|
|
let postData = [];
|
|
let ymdhms = /([0-9]{3}[1-9]|[0-9][1-9][0-9]2022-01-07 19:29:33|[0-9]2022-01-07 19:29:33[1-9][0-9]|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8])))([ ])([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])/;
|
|
for (let i = 0; i < res.length; i++) {
|
|
let d = res[i];
|
|
let departmentName = judgeNull(d['部门']);
|
|
let trainingType = judgeNull(d['实际培训类型']);
|
|
let trainDate = d['培训时间'];
|
|
let trainContent = judgeNull(d['培训内容']);
|
|
let trainWho = judgeNull(d['培训针对人群']);
|
|
let trainer = judgeNull(d['培训讲师']);
|
|
let trainMethod = judgeNull(d['培训方式']);
|
|
let appraisalMethod = judgeNull(d['考核形式']);
|
|
let trainTime = judgeNull(d['培训时长']);
|
|
if (!departmentName) {
|
|
error(`第${i + 2}行【部门】为空,请填写`)
|
|
return
|
|
}
|
|
if (user.allDepartment && user.allDepartment.departments) {
|
|
let dept = user.allDepartment.departments.find(d => !d.delete && d.name === departmentName);
|
|
if (dept) {
|
|
departmentName = dept.name;
|
|
} else {
|
|
error(`第${i + 2}行【部门】数据有误,请确认后重新填写`)
|
|
return
|
|
}
|
|
}
|
|
if (!trainingType) {
|
|
error(`第${i + 2}行【实际培训类型】为空,请填写`)
|
|
return
|
|
}
|
|
if (!trainDate) {
|
|
error(`第${i + 2}行【培训时间】为空,请填写`)
|
|
return
|
|
}
|
|
if (trainDate instanceof Date) {
|
|
trainDate = moment(trainDate).format("YYYY-MM-DD HH:mm:ss");
|
|
if (!ymdhms.test(trainDate)) {
|
|
error(`第${i + 2}行【培训时间】填写错误,请填写yyyy/mm/dd hh:mm格式`)
|
|
return
|
|
}
|
|
} else {
|
|
error(`第${i + 2}行【培训时间】填写错误,请确认后重新填写`)
|
|
return
|
|
}
|
|
trainDate = changeTime(trainDate);
|
|
|
|
if (!trainContent) {
|
|
error(`第${i + 2}行【培训内容】为空,请填写`)
|
|
return
|
|
}
|
|
if (!trainMethod) {
|
|
error(`第${i + 2}行【培训方式】为空,请填写`)
|
|
return
|
|
}
|
|
if (!appraisalMethod) {
|
|
error(`第${i + 2}行【考核形式】为空,请填写`)
|
|
return
|
|
}
|
|
if (!trainTime) {
|
|
error(`第${i + 2}行【培训时长】为空,请填写`)
|
|
return
|
|
}
|
|
postData.push({
|
|
departmentName, trainingType, trainDate, trainContent,
|
|
trainWho: trainWho || '', trainer: trainer || '',
|
|
trainMethod, appraisalMethod, trainTime, origin: 'import'
|
|
})
|
|
}
|
|
setPostData(postData)
|
|
let msg = '文件解析完成,点击确定按钮上传保存!'
|
|
setMsg(msg)
|
|
onSuccess({ message: msg })
|
|
})
|
|
}}>
|
|
<Button icon={<IconUpload />} theme="light">
|
|
请选择文件
|
|
</Button>
|
|
</Form.Upload>
|
|
<span>{msg}</span>
|
|
<div style={{ color: '#ccc' }}>最大不超过200M,导入文件需与
|
|
<span onClick={() => download()} style={{ cursor: 'pointer', color: '#0066FF' }}>导入模板</span>
|
|
一致</div>
|
|
</Form>
|
|
</Modal >
|
|
)
|
|
}
|
|
|
|
function mapStateToProps(state) {
|
|
const { auth, global } = state;
|
|
return {
|
|
user: auth.user,
|
|
actions: global.actions,
|
|
}
|
|
}
|
|
|
|
export default connect(mapStateToProps)(ImportModal);
|