5 changed files with 320 additions and 26 deletions
			
			
		@ -0,0 +1,72 @@ | 
				
			|||
'use strict'; | 
				
			|||
 | 
				
			|||
import { ApiTable, basicAction } from '$utils' | 
				
			|||
 | 
				
			|||
export function personalTrainRecordAll(values) { | 
				
			|||
    return dispatch => basicAction({ | 
				
			|||
        type: 'post', | 
				
			|||
        dispatch: dispatch, | 
				
			|||
        actionType: 'SALES_MEMBER_BULK_ADD', | 
				
			|||
        url: ApiTable.addSalesMemberBulk, | 
				
			|||
        data: values, | 
				
			|||
        msg: { option: '导入销售人员信息' }, | 
				
			|||
    }); | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export function getPersonalTrainRecord(query) {//查询
 | 
				
			|||
    return (dispatch) => basicAction({ | 
				
			|||
        type: "get", | 
				
			|||
        dispatch: dispatch, | 
				
			|||
        actionType: "GET_PERSONAL_TRAIN_RECORD_LIST", | 
				
			|||
        query: query, | 
				
			|||
        url: `${ApiTable.getPersonalTrainRecord}`, | 
				
			|||
        msg: { option: "查询个人培训记录列表" }, | 
				
			|||
        reducer: { name: "personalTrainRecordList", params: { noClear: true } }, | 
				
			|||
    }); | 
				
			|||
} | 
				
			|||
// export function delSalesMember(data) {//删除
 | 
				
			|||
//     let msg = ''
 | 
				
			|||
//     if (data) {
 | 
				
			|||
//         msg = data.msg
 | 
				
			|||
//     }
 | 
				
			|||
//     return (dispatch) =>
 | 
				
			|||
//         basicAction({
 | 
				
			|||
//             type: "del",
 | 
				
			|||
//             query: data,
 | 
				
			|||
//             dispatch: dispatch,
 | 
				
			|||
//             actionType: "DEL_SALES_MEMBER",
 | 
				
			|||
//             url: `${ApiTable.delSalesMember}`,
 | 
				
			|||
//             msg: { option: msg }, //删除
 | 
				
			|||
//             reducer: {},
 | 
				
			|||
//         });
 | 
				
			|||
// }
 | 
				
			|||
 | 
				
			|||
// export function getMemberExport(query) {//导出员工信息
 | 
				
			|||
//     return (dispatch) => basicAction({
 | 
				
			|||
//         type: "get",
 | 
				
			|||
//         dispatch: dispatch,
 | 
				
			|||
//         actionType: "GET_MemberEXPORT",
 | 
				
			|||
//         query: query,
 | 
				
			|||
//         url: `${ApiTable.getMemberExport}`,
 | 
				
			|||
//         msg: { option: "导出员工信息" },
 | 
				
			|||
//         reducer: { name: "MemberExport", params: { noClear: true } },
 | 
				
			|||
//     });
 | 
				
			|||
// }
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
// export function editSalesMember(data) {//更新
 | 
				
			|||
//     let msg = ''
 | 
				
			|||
//     if (data) {
 | 
				
			|||
//         msg = data.msg
 | 
				
			|||
//     }
 | 
				
			|||
//     return (dispatch) =>
 | 
				
			|||
//         basicAction({
 | 
				
			|||
//             type: "put",
 | 
				
			|||
//             dispatch: dispatch,
 | 
				
			|||
//             data,
 | 
				
			|||
//             actionType: "PUT_SALES_MEMBER",
 | 
				
			|||
//             url: `${ApiTable.editSalesMember}`,
 | 
				
			|||
//             msg: { option: msg }, //更新
 | 
				
			|||
//             reducer: {},
 | 
				
			|||
//         });
 | 
				
			|||
// }
 | 
				
			|||
@ -0,0 +1,222 @@ | 
				
			|||
'use strict'; | 
				
			|||
import React, { useState, useEffect } from 'react'; | 
				
			|||
import { connect } from 'react-redux'; | 
				
			|||
import moment from 'moment'; | 
				
			|||
import { Modal, Form, Button, Notification } from '@douyinfe/semi-ui'; | 
				
			|||
import { IconUpload } from '@douyinfe/semi-icons'; | 
				
			|||
import XLSX from 'xlsx' | 
				
			|||
//下载模板和上传文件读取 | 
				
			|||
const ImportPerformanceSummaryModal = props => { | 
				
			|||
    const { dispatch, actions, onCancel } = props; | 
				
			|||
    const { businessManagement } = actions | 
				
			|||
    const [msg, setMsg] = useState(''); | 
				
			|||
    const [loading, setLoading] = useState(''); | 
				
			|||
    const [postData, setPostData] = useState([]); | 
				
			|||
    let personalTrainRecord = { index: '序号', personalName: '姓名', departmentName: '部门', trainingType: '培训类型', topic: '课程主题', trainer: '培训讲师', trainDate: '培训时间', trainTime: '培训时长', trainMethod: '培训方式', attendanceScore: '考勤分数', appraisalMethod: '考核形式', appraisalScore: '考核分数', totalScore: '总分' } | 
				
			|||
    //初始化 | 
				
			|||
     | 
				
			|||
    const confirm = () => { | 
				
			|||
        if (postData.length) { | 
				
			|||
            setLoading(true) | 
				
			|||
            // dispatch(businessManagement.importSalePerformance(postData)).then(res => { | 
				
			|||
            //     if (res.success) { | 
				
			|||
            //         onCancel() | 
				
			|||
            //     } | 
				
			|||
            //     setLoading(false) | 
				
			|||
            // }) | 
				
			|||
        } else { | 
				
			|||
            Notification.warning({ content: '没有数据可以提交,请上传数据文件', duration: 2 }) | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    const dldCsvMb = () => { | 
				
			|||
        //表头 | 
				
			|||
        let head = []; | 
				
			|||
        Object.keys(personalTrainRecord).map(key => { | 
				
			|||
            head.push(personalTrainRecord[key]); | 
				
			|||
        }) | 
				
			|||
        head = head.join(',') + "\n"; | 
				
			|||
        //数据 | 
				
			|||
        //let data = 1 + ',' + 2 + ',' + 3 + ',' + 4 + ',' + 5 | 
				
			|||
        let templateCsv = "data:text/csv;charset=utf-8,\ufeff" + head; | 
				
			|||
        //创建一个a标签 | 
				
			|||
        let link = document.createElement("a"); | 
				
			|||
        //为a标签设置属性 | 
				
			|||
        link.setAttribute("href", templateCsv); | 
				
			|||
        link.setAttribute("download", "个人培训记录表模板.csv"); | 
				
			|||
        //点击a标签 | 
				
			|||
        link.click(); | 
				
			|||
    } | 
				
			|||
    const download = () => { | 
				
			|||
        dldCsvMb(); | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    const fileLimit = '.csv'; | 
				
			|||
 | 
				
			|||
    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 judgeNull = (value) => { | 
				
			|||
    //     return value ? String(value).trim().replace(/\s*/g, "") : null; | 
				
			|||
    // } | 
				
			|||
 | 
				
			|||
    // const judgeNullTime = (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 v ? a : null; | 
				
			|||
    // } | 
				
			|||
 | 
				
			|||
    const judgeTimeValid = (time) => { | 
				
			|||
        let valid = true; | 
				
			|||
        if (!time) { | 
				
			|||
            return valid;//可以不填 | 
				
			|||
        } | 
				
			|||
        const ymd = /^((19|20)[0-9]{2})[\/\-]((0[1-9])|(1[0-2]))[\/\-]((0[1-9])|((1|2)[0-9])|(3[0-1]))$/;//年月日 | 
				
			|||
        if (time instanceof Date) { | 
				
			|||
            let timeStr = moment(time).format('YYYY/MM/DD'); | 
				
			|||
            if (!ymd.test(timeStr)) { | 
				
			|||
                valid = false; | 
				
			|||
            } | 
				
			|||
        } else { | 
				
			|||
            valid = false; | 
				
			|||
        } | 
				
			|||
        return valid; | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    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={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 = []; | 
				
			|||
                            let zzsPattern = /^[+]{0,1}(\d+)$/;//正整数 | 
				
			|||
                            for (let i = 0; i < res.length; i++) { | 
				
			|||
                                let d = res[i]; | 
				
			|||
                                let obj = {}; | 
				
			|||
                                Object.keys(personalTrainRecord).map(key => { | 
				
			|||
                                    obj[key] = d[personalTrainRecord[key]] || null; | 
				
			|||
                                    //} | 
				
			|||
                                }) | 
				
			|||
                                let tValid = judgeTimeValid(obj.recConDate); | 
				
			|||
                                // if (!tValid) { | 
				
			|||
                                //     error(`第${i + 2}行【收到合同日期】错误,请填写yyyy/mm/dd格式`) | 
				
			|||
                                //     return | 
				
			|||
                                // } | 
				
			|||
 | 
				
			|||
                                // if (obj.isApproval && ['是', '否'].indexOf(obj.isApproval) == -1) { | 
				
			|||
                                //     error(`第${i + 2}行【价格是否特批】错误,请填写是或否`) | 
				
			|||
                                //     return | 
				
			|||
                                // } | 
				
			|||
                                // //复购次数 正整数 | 
				
			|||
                                // if (obj.repurchaseCount && !zzsPattern.test(obj.repurchaseCount)) { | 
				
			|||
                                //     error(`第${i + 2}行【复购次数】填写错误,需要为非负整数`) | 
				
			|||
                                //     return | 
				
			|||
                                // } | 
				
			|||
 | 
				
			|||
                                // if (obj.reproducible && ['是', '否'].indexOf(obj.reproducible) == -1) { | 
				
			|||
                                //     error(`第${i + 2}行【是否可复制的业务路径】错误,请填写是或否`) | 
				
			|||
                                //     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 > | 
				
			|||
    ) | 
				
			|||
} | 
				
			|||
 | 
				
			|||
function mapStateToProps(state) { | 
				
			|||
    const { auth, global } = state; | 
				
			|||
    return { | 
				
			|||
        user: auth.user, | 
				
			|||
        actions: global.actions, | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default connect(mapStateToProps)(ImportPerformanceSummaryModal); | 
				
			|||
					Loading…
					
					
				
		Reference in new issue