Browse Source

(*)业绩汇总表导入导出

master
ww664853070 2 years ago
parent
commit
cf16f24304
  1. 5
      api/app/lib/models/sale.js
  2. 6
      api/app/lib/models/salePerformance.js
  3. 52
      web/client/src/sections/business/constants/index.js
  4. 225
      web/client/src/sections/business/containers/performanceReport/importPerformanceSummaryModal.jsx

5
api/app/lib/models/sale.js

@ -17,11 +17,6 @@ module.exports = dc => {
allowNull: true,
field: "department",
},
sale: {
type: DataTypes.STRING,
allowNull: false,
field: "sale",
},
business: {
type: DataTypes.STRING,
allowNull: true,

6
api/app/lib/models/salePerformance.js

@ -27,10 +27,10 @@ module.exports = dc => {
allowNull: false,
field: "assessment_performance",
},
completion: {
saleName : {
type: DataTypes.STRING,
allowNull: false,
field: "completion ",
field: "sale_name",
},
month: {
type: DataTypes.INTEGER,
@ -56,7 +56,7 @@ module.exports = dc => {
tableName: "sale_performance",
});
const { sale } = dc.models;
sale.hasMany(salePerformance, { foreighKey: 'saleId', targetKey: "id" })
sale.hasMany(salePerformance, { foreighKey: 'saleName', targetKey: "sale" })
dc.models.salePerformance = salePerformance;
return salePerformance;

52
web/client/src/sections/business/constants/index.js

@ -120,3 +120,55 @@ export const achievementColumnKeys = {
repurchase: '复购业务',
isreproduce: '可复制的业务路径',
}
export const performanceSummaryKeys = {
oneAmount:'一月合同金额',
oneActualPerformance:'一月实际业绩',
oneAssessmentPerformance:'一月考核业绩',
oneTask:'一月销售任务',
twoAmount:'二月合同金额',
twoActualPerformance:'二月实际业绩',
twoAssessmentPerformance:'二月考核业绩',
twoTask:'二月销售任务',
threeAmount:'三月合同金额',
threeActualPerformance:'三月实际业绩',
threeAssessmentPerformance:'三月考核业绩',
threeTask:'三月销售任务',
fourAmount:'四月合同金额',
fourActualPerformance:'四月实际业绩',
fourAssessmentPerformance:'四月考核业绩',
fourTask:'四月销售任务',
fiveActualPerformance:'五月实际业绩',
fiveAssessmentPerformance:'五月考核业绩',
fiveTask:'五月销售任务',
fiveAmount:'五月合同金额',
sixAmount:'六月合同金额',
sixActualPerformance:'六月实际业绩',
sixAssessmentPerformance:'六月考核业绩',
sixTask:'六月销售任务',
sevenAmount:'七月合同金额',
sevenActualPerformance:'七月实际业绩',
sevenAssessmentPerformance:'七月考核业绩',
sevenTask:'七月销售任务',
eightAmount:'八月合同金额',
eightActualPerformance:'八月实际业绩',
eightAssessmentPerformance:'八月考核业绩',
eightTask:'八月销售任务',
nineAmount:'九月合同金额',
nineActualPerformance:'九月实际业绩',
nineAssessmentPerformance:'九月考核业绩',
nineTask:'九月销售任务',
tenAmount:'十月合同金额',
tenActualPerformance:'十月实际业绩',
tenAssessmentPerformance:'十月考核业绩',
tenTask:'十月销售任务',
elevenActualPerformance:'十一月实际业绩',
elevenAssessmentPerformance:'十一月考核业绩',
elevenTask:'十一月销售任务',
elevenAmount:'十一月合同金额',
twelveAmount:'十二月合同金额',
twelveActualPerformance:'十二月实际业绩',
twelveAssessmentPerformance:'十二月考核业绩',
twelveTask:'十二月销售任务',
name:'销售人员'
}

225
web/client/src/sections/business/containers/performanceReport/importPerformanceSummaryModal.jsx

@ -0,0 +1,225 @@
'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';
import { performanceSummaryKeys } from '../../constants/index';
//
const ImportPerformanceSummaryModal = props => {
const { dispatch, actions, onCancel } = props;
const { businessManagement } = actions
const [msg, setMsg] = useState('');
const [loading, setLoading] = useState('');
const [postData, setPostData] = useState([]);
//
useEffect(() => {
}, []);
const confirm = () => {
if (postData.length) {
setLoading(true)
dispatch(businessManagement.importAchieveDetails(postData)).then(res => {
if (res.success) {
onCancel()
}
setLoading(false)
})
} else {
Notification.warning({ content: '没有数据可以提交,请上传数据文件', duration: 2 })
}
}
const dldCsvMb = () => {
//
let head = [];
Object.keys(performanceSummaryKeys).map(key => {
head.push(performanceSummaryKeys[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) => {
// //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 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(performanceSummaryKeys).map(key => {
obj[key] = d[performanceSummaryKeys[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)
console.log(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…
Cancel
Save