周沫沫历险记
2 years ago
2 changed files with 253 additions and 33 deletions
@ -0,0 +1,213 @@ |
|||
'use strict'; |
|||
import React, { useState, useEffect } from 'react'; |
|||
import { Modal, Form, Button, Notification, Toast } from '@douyinfe/semi-ui'; |
|||
import { IconUpload } from '@douyinfe/semi-icons'; |
|||
import XLSX from 'xlsx'; |
|||
|
|||
const IMPORT_FIELD = { |
|||
userCode: { label: "员工编号" }, |
|||
ratingTime: { label: "评级时间" }, |
|||
theoryBasicScore: { label: "理论基础测评成绩" }, |
|||
theoryPassed: { label: "理论基础测评是否通过(≥60)" }, |
|||
totalScore: { label: "评级总成绩" }, |
|||
totalRatingPassed: { label: "评级总成绩是否通过(K≥60)" }, |
|||
technicalGrade: { label: "技术职级等级" } |
|||
} |
|||
const SHEETNAME = "岗位评级"; |
|||
|
|||
const ImportPositionRatingModal = props => { |
|||
const { onCancel, user, memberList } = props; |
|||
const [msg, setMsg] = useState(''); |
|||
const [loading, setLoading] = useState(''); |
|||
const [postData, setPostData] = useState([]); |
|||
const fileLimit = '.xlsx'; |
|||
//初始化 |
|||
|
|||
const confirm = () => { |
|||
if (postData.length) { |
|||
setLoading(true) |
|||
// dispatch(postAllPersonalTrainRecord(postData)).then(res => { |
|||
// if (res.success) { |
|||
// onCancel() |
|||
// dispatch(getPersonalTrainRecord(query)) |
|||
// } |
|||
// setLoading(false) |
|||
// }) |
|||
} else { |
|||
Notification.warning({ content: '没有数据可以提交,请上传数据文件', duration: 2 }) |
|||
} |
|||
} |
|||
|
|||
const download = () => { |
|||
const head = [Object.keys(IMPORT_FIELD).map(key => IMPORT_FIELD[key].label)]; |
|||
let workbook = { SheetNames: [SHEETNAME], Sheets: {} }; |
|||
workbook.Sheets[SHEETNAME] = XLSX.utils.aoa_to_sheet(head);//json转excel |
|||
workbook.Sheets[SHEETNAME]['!cols'] = [ |
|||
{ wch: 13 }, { wch: 12 }, { wch: 18 }, { wch: 30 }, { wch: 11 }, |
|||
{ wch: 30 }, { wch: 13 }]; |
|||
let wopts = { bookType: 'xlsx', type: 'buffer' };// 生成excel的配置项 |
|||
XLSX.writeFile(workbook, `${SHEETNAME}导入模板.xlsx`, wopts); |
|||
} |
|||
|
|||
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("失败"); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
request.send(); |
|||
}) |
|||
} |
|||
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} |
|||
confirmLoading={loading} |
|||
onCancel={() => { |
|||
setMsg('') |
|||
setLoading(false) |
|||
setPostData([]) |
|||
onCancel() |
|||
}} |
|||
> |
|||
<div style={{ borderBottom: '1px solid #DCDEE0', margin: '0px -24px' }}></div> |
|||
<Form> |
|||
<Form.Upload |
|||
label={SHEETNAME} |
|||
labelPosition='left' |
|||
action={'/'} |
|||
accept={fileLimit} |
|||
maxSize={200} |
|||
limit={1} |
|||
onRemove={(currentFile, fileList, fileItem) => { |
|||
setMsg(''); |
|||
setPostData([]); |
|||
}} |
|||
customRequest={(data) => { |
|||
const { file, onSuccess, onError } = data |
|||
getFileBlob(file.url).then(res => { |
|||
|
|||
const error = (msg) => { |
|||
setMsg(msg) |
|||
onError({ message: msg }) |
|||
} |
|||
if (res.length > 1000) { |
|||
error('一次性上传数据行数应小于1000行,请分批上传') |
|||
return |
|||
} |
|||
if (!res.length) { |
|||
error('请填写至少一行数据') |
|||
return |
|||
} |
|||
let postData = []; |
|||
for (let i = 0; i < res.length; i++) { |
|||
let d = res[i]; |
|||
let obj = {}; |
|||
|
|||
Object.keys(IMPORT_FIELD).map(key => { |
|||
obj[key] = d[IMPORT_FIELD[key].label] || null; |
|||
}) |
|||
let errmsg = null; |
|||
for (let item in obj) { |
|||
if (!obj[item]) { |
|||
errmsg = `第${i + 2}行【${IMPORT_FIELD[item].label}】为空,请填写`; |
|||
break; |
|||
} else { |
|||
if ("userCode" == item) { |
|||
const member = memberList.find(m => m.userCode == obj.userCode); |
|||
if (!member) { |
|||
errmsg = `第${i + 2}行【${IMPORT_FIELD[item].label}】${obj.userCode}未匹配到数据,请检查该员工是否添加`; |
|||
break; |
|||
} else if (postData.find(m => m.userCode == obj.userCode)) { |
|||
errmsg = `第${i + 2}行【${IMPORT_FIELD[item].label}】${obj.userCode}已存在,请检查`; |
|||
break; |
|||
} else { |
|||
obj.pepUserId = member.pepUserId; |
|||
} |
|||
} |
|||
else if (["theoryPassed", "totalRatingPassed"].includes(item)) { |
|||
if (!["是", "否"].includes(obj[item])) { |
|||
errmsg = `第${i + 2}行【${IMPORT_FIELD[item].label}】不合法,请修改`; |
|||
break; |
|||
} |
|||
} |
|||
else if ("ratingTime" == item) { |
|||
if (obj.ratingTime.toString().match(/^(\d{1,4})(-|.|\/)(\d{1,2})\2(\d{1,2})$/)) { |
|||
obj["ratingTime"] = changeTime(obj.ratingTime); |
|||
} else { |
|||
errmsg = `第${i + 2}行【${IMPORT_FIELD[item].label}】不合法,请修改`; |
|||
break; |
|||
} |
|||
} else if (["theoryBasicScore", "totalScore"].includes(item)) { |
|||
if (isNaN(obj[item])) { |
|||
errmsg = `第${i + 2}行【${IMPORT_FIELD[item].label}】不合法,请修改`; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
if (errmsg) { |
|||
error(errmsg); |
|||
return |
|||
} |
|||
postData.push(obj); |
|||
} |
|||
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 > |
|||
) |
|||
} |
|||
|
|||
export default ImportPositionRatingModal; |
Loading…
Reference in new issue