diff --git a/web/client/src/sections/humanAffairs/actions/index.js b/web/client/src/sections/humanAffairs/actions/index.js
index f75ecde..809f472 100644
--- a/web/client/src/sections/humanAffairs/actions/index.js
+++ b/web/client/src/sections/humanAffairs/actions/index.js
@@ -4,9 +4,11 @@ import * as personnelFiles from './personnelFiles'
import * as employeeInformation from './employeeInformation'
import * as salesDistribution from './salesDistribution'
import * as departmentTrain from './departmentTrain'
+import * as personalTrainRecord from './personalTrainRecord'
export default {
...personnelFiles,
...employeeInformation,
...salesDistribution,
- ...departmentTrain
+ ...departmentTrain,
+ ...personalTrainRecord
}
\ No newline at end of file
diff --git a/web/client/src/sections/humanAffairs/actions/personalTrainRecord.js b/web/client/src/sections/humanAffairs/actions/personalTrainRecord.js
new file mode 100644
index 0000000..277df99
--- /dev/null
+++ b/web/client/src/sections/humanAffairs/actions/personalTrainRecord.js
@@ -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: {},
+// });
+// }
\ No newline at end of file
diff --git a/web/client/src/sections/humanAffairs/containers/importPersonalTrainRecord.jsx b/web/client/src/sections/humanAffairs/containers/importPersonalTrainRecord.jsx
new file mode 100644
index 0000000..1623cfb
--- /dev/null
+++ b/web/client/src/sections/humanAffairs/containers/importPersonalTrainRecord.jsx
@@ -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 (
+