Browse Source

(*)岗位评级导入校验

master
周沫沫历险记 2 years ago
parent
commit
731201073f
  1. 213
      web/client/src/sections/humanAffairs/components/importPositionRating.jsx
  2. 73
      web/client/src/sections/humanAffairs/containers/positionRating.jsx

213
web/client/src/sections/humanAffairs/components/importPositionRating.jsx

@ -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);//jsonexcel
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) => {
//xlsxexcel
//2020/8/1xlsx 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;

73
web/client/src/sections/humanAffairs/containers/positionRating.jsx

@ -5,39 +5,28 @@ import { Table, Button, Pagination, Skeleton, Form, Tooltip } from '@douyinfe/se
import { IconSearch } from '@douyinfe/semi-icons';
import { SkeletonScreen, Setup } from "$components";
import { UserAttribute } from '$utils';
import ImportPositionRatingModal from '../components/importPositionRating';
import '../style.less';
const PositionRating = (props) => {
const { dispatch, actions, history, user, loading, socket, xqMembers } = props
const { dispatch, actions, memberList, history, user, loading, socket, xqMembers } = props
const { humanAffairs } = actions;
const { getMemberList, getPositionRating } = actions.humanAffairs;
const form = useRef();//
let [archivesList, setArchivesList] = useState([]);//
const [setup, setSetup] = useState(false);//
const [setupp, setSetupp] = useState([]);//
const [lookup, setLookup] = useState({});//
const [query, setQuery] = useState({ limit: 10, page: 0 }); //
const [order, setOrder] = useState({ orderBy: 'hiredate', orderDirection: 'DESC' }); //
const [importModal, setImportModal] = useState(false);
const [limits, setLimits] = useState()//
const page = useRef(query.page);//
useEffect(() => {
getMemberSearchList()//
}, [query, order])
getMainList()
}, [query])
function getMemberSearchList() {//
let obj = lookup
if (lookup.entryTime?.length > 1) {
obj.hiredateStart = moment(lookup.entryTime[0]).format('YYYY-MM-DD')
obj.hiredateEnd = moment(lookup.entryTime[1]).format('YYYY-MM-DD')
}
else {
obj.hiredateStart = ''
obj.hiredateEnd = ''
}
dispatch(humanAffairs.getPositionRating({ ...obj, ...query, ...order })).then((res) => {//
function getMainList() {
dispatch(getPositionRating(query)).then((res) => {
if (res.success) {
setArchivesList(res.payload?.data?.rows)
setLimits(res.payload?.data?.count)
@ -120,32 +109,32 @@ const PositionRating = (props) => {
}, {
title: '评级时间',
width: 100,
dataIndex: "time",
key: "time",
dataIndex: "ratingTime",
key: "ratingTime",
render: (_, r, index) => <span>-</span>,
}, {
title: '理论基础测评成绩',
width: 150,
dataIndex: "technicalGrade",
key: "technicalGrade",
dataIndex: "theoryBasicScore",
key: "theoryBasicScore",
render: (_, r, index) => <span>-</span>,
}, {
title: '理论基础测评是否通过(≥60)',
width: 150,
dataIndex: "technicalGrade",
key: "technicalGrade",
dataIndex: "theoryPassed",
key: "theoryPassed",
render: (_, r, index) => <span>-</span>,
}, {
title: '评级总成绩',
width: 150,
dataIndex: "technicalGrade",
key: "technicalGrade",
dataIndex: "totalScore",
key: "totalScore",
render: (_, r, index) => <span>-</span>,
}, {
title: '评级总成绩是否通过(K≥60)',
width: 150,
dataIndex: "technicalGrade",
key: "technicalGrade",
dataIndex: "totalRatingPassed",
key: "totalRatingPassed",
render: (_, r, index) => <span>-</span>,
}, {
title: '技术职级等级',
@ -155,7 +144,6 @@ const PositionRating = (props) => {
render: (_, r, index) => <span>-</span>,
}];
function handleRow(record, index) {//
//
if (index % 2 === 0) {
@ -168,6 +156,12 @@ const PositionRating = (props) => {
return {};
}
}
const handleImportModal = () => {
if (!memberList.length) {
dispatch(getMemberList())//
}
setImportModal(true);
}
const scroll = useMemo(() => ({}), []);
return (
<>
@ -188,6 +182,15 @@ const PositionRating = (props) => {
</div>
</div>
<div style={{ marginRight: 20, marginTop: 18 }}>
<div style={{ display: 'flex', margin: '16px 0px', justifyContent: 'flex-end' }}>
<div style={{ display: 'flex', marginRight: 20 }}>
<div style={{ padding: '6px 20px', background: '#0F7EFB', color: '#FFFFFF', fontSize: 14, cursor: "pointer" }}
onClick={() => { handleImportModal(); }}
>
导入
</div>
</div>
</div>
<div style={{ border: '1px solid #C7E1FF', background: '#F4F8FF', borderRadius: 2, height: 32, width: 669, padding: '8px 0px 7px 12px', display: 'flex', alignItems: 'center', color: '#0F7EFB', fontSize: 12 }}>
<img src="/assets/images/hrImg/!.png" alt="" style={{ width: 14, height: 14, marginRight: 8 }} />
表格中带有认证标识"
@ -260,6 +263,11 @@ const PositionRating = (props) => {
</div>
</div>
</div>
{importModal ?
<ImportPositionRatingModal
memberList={memberList}
onCancel={() => { setImportModal(false) }}
/> : ''}
</div>
</div>
</>
@ -267,13 +275,12 @@ const PositionRating = (props) => {
}
function mapStateToProps(state) {
const { auth, global, MemberSearch, webSocket } = state;
const { auth, global, MemberSearch, MemberList } = state;
return {
// loading: members.isRequesting,
user: auth.user,
actions: global.actions,
xqMembers: MemberSearch.data,
// socket: webSocket.socket
memberList: MemberList.data && MemberList.data.rows || []
};
}

Loading…
Cancel
Save