人力资源
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

334 lines
9.8 KiB

'use strict';
const moment = require('moment')
const fs = require('fs');
async function salesList(ctx) {
try {
const { memberList, packageUserData } = ctx.app.fs.utils
const {
keywordTarget, keyword, limit, page, state,
hiredateStart, hiredateEnd, marital, native, workPlace,
orderBy, orderDirection, placeSearch
} = ctx.query
const userRes = await memberList({
keywordTarget, keyword, limit: '', page: '', state,
hiredateStart, hiredateEnd, marital, native, workPlace,
orderBy, orderDirection,
nowAttendanceTime: true
})
let { packageUser: members } = await packageUserData(userRes, {
state: true,
})
const { models } = ctx.fs.dc;
let res = await models.SalesDistribution.findAndCountAll({
where: { del: false },
offset: Number(page) * Number(limit),
limit: Number(limit),
order: [['id', 'DESC']]
})
let rslt = []
res.rows.map(d => {
let valid = false;
let info = members.find(m => m.pepUserId == d.dataValues.pepUserId);
if (info) {
if (placeSearch) {
let exist1 = d.dataValues.provinces.join(',').indexOf(placeSearch) != -1
let exist2 = d.dataValues.cities.join(',').indexOf(placeSearch) != -1
if (exist1 || exist2) {
valid = true;
}
} else {
valid = true;
}
}
if (valid) {
let item = {
name: info.userName,
userCode: info.userCode,
post: info.userPost,
department: info.departmrnt,
hireDate: info.hiredate,//入职时间
regularDate: info.regularDate,//转正时间
...d.dataValues
}
rslt.push(item);
}
})
ctx.status = 200;
ctx.body = {
count: res.count,
rows: rslt
};
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
async function add(ctx) {
try {
const { models } = ctx.fs.dc;
const { pepUserId, provinces, cities } = ctx.request.body
const existRes = await models.SalesDistribution.findOne({
where: { pepUserId }
})
if (existRes && !existRes.del) {
throw '当前销售人员信息已存在'
}
let storageData = { pepUserId, provinces, cities, del: false }
if (existRes && existRes.del) {
await models.SalesDistribution.update(storageData, {
where: { pepUserId }
})
} else {
await models.SalesDistribution.create(storageData)
}
ctx.status = 204;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
async function edit(ctx) {
try {
const { models } = ctx.fs.dc;
const { pepUserId, provinces, cities } = ctx.request.body
const existRes = await models.SalesDistribution.findOne({
where: { pepUserId }
})
if (!existRes) {
throw '当前销售人员信息不存在'
}
let storageData = { pepUserId, provinces, cities, del: false }
await models.SalesDistribution.update(storageData, {
where: {
pepUserId: pepUserId
}
})
ctx.status = 204;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
async function del(ctx) {
try {
const { models } = ctx.fs.dc;
const { pepUserId } = ctx.query
await models.SalesDistribution.update({
del: true,
}, {
where: {
pepUserId,
}
})
ctx.status = 204;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
async function exportData(ctx) {
try {
const { models } = ctx.fs.dc;
const { clickHouse, opts: { qiniu } } = ctx.app.fs
const { simpleExcelDown, memberList, packageUserData } = ctx.app.fs.utils
const {
keywordTarget, keyword, limit, page, state, keys = '',
hiredateStart, hiredateEnd, marital, native, workPlace,
orderBy, orderDirection,
} = ctx.query
const userRes = await memberList({
keywordTarget, keyword, limit, page, state,
hiredateStart, hiredateEnd, marital, native, workPlace,
orderBy, orderDirection,
nowAttendanceTime: true
})
const tableAttributes = models['Member'].tableAttributes
const optionKeys = keys.split(',')
let { packageUser: exportD, pepUserIds } = await packageUserData(userRes)
let preHeader = [{
title: '员工编号',
key: 'userCode',
}, {
title: '姓名',
key: 'userName',
}]
let header = [].concat(preHeader)
for (let k in tableAttributes) {
const comment = tableAttributes[k].comment
if (k != 'id' && k != 'pepUserId' && comment) {
if ([].includes(k)) {
// 截住不想导出的字段
continue
}
header.push({
title: comment || '-',
key: k,
// index: tableAttributes[k].index,
})
}
}
if (optionKeys.includes('overtimeStatistic')) {
header = header.concat([{
title: '累计加班次数',
key: 'overTimeCount',
}, {
title: '累计加班总时长 / h',
key: 'overTimeDuration',
},])
}
if (optionKeys.includes('vacateStatistic')) {
header = header.concat([{
title: '累计请假次数',
key: 'vacateCount',
}, {
title: '累计请假总时长 / h',
key: 'vacateDuration',
},])
}
// 查询累计加班次数及总时长
const statisticOvertimeRes = await clickHouse.hr.query(`
SELECT
pep_user_id AS pepUserId,
count(id) AS count,
sum(duration) AS duration
FROM
overtime
WHERE pep_user_id IN (${pepUserIds.join(',')})
GROUP BY pep_user_id
`).toPromise()
const statisticVacateRes = await clickHouse.hr.query(`
SELECT
pep_user_id AS pepUserId,
count(id) AS count,
sum(duration) AS duration
FROM
vacate
WHERE pep_user_id IN (${pepUserIds.join(',')})
GROUP BY pep_user_id
`).toPromise()
exportD.forEach(d => {
d.departmrnt = d.departmrnt.map(dep => dep.name).join('、')
d.role = d.role.map(r => r.name).join('、')
d.idPhoto ? d.idPhoto = qiniu.domain + '/' + d.idPhoto : ''
d.vitae ? d.vitae = qiniu.domain + '/' + d.vitae : ''
const corOverTime = statisticOvertimeRes.find(so => so.pepUserId == d.pepUserId)
d.overTimeCount = corOverTime ? corOverTime.count : 0
d.overTimeDuration = corOverTime ? (corOverTime.duration / 3600).toFixed(1) : 0
const corVacate = statisticVacateRes.find(so => so.pepUserId == d.pepUserId)
d.vacateCount = corVacate ? corVacate.count : 0
d.vacateDuration = corVacate ? (corVacate.duration / 3600).toFixed(1) : 0
})
const fileName = `人员信息_${moment().format('YYYYMMDDHHmmss')}` + '.csv'
const filePath = await simpleExcelDown({ data: exportD, header, fileName: fileName })
const fileData = fs.readFileSync(filePath);
ctx.status = 200;
ctx.set('Content-Type', 'application/x-xls');
ctx.set('Content-disposition', 'attachment; filename=' + encodeURI(fileName));
ctx.body = fileData;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
async function addSalesMemberBulk(ctx) {
let errorMsg = { message: '导入销售人员信息失败' };
const transaction = await ctx.fs.dc.orm.transaction();
try {
const models = ctx.fs.dc.models;
const data = ctx.request.body;
let addArr = [];
let editArr = [];
let list = await models.SalesDistribution.findAll({
attributes: ['pepUserId']
});
data.map(d => {
let exist = list.find(m => m.pepUserId == d.pepUserId);//项企的人员编号字段还没有
if (exist) {
editArr.push(d);
} else {
addArr.push(d);
}
})
//处理新增的
if (addArr.length) {
await models.SalesDistribution.bulkCreate(addArr);
}
//处理编辑的
if (editArr.length) {
for (let i in editArr) {
let { pepUserId, provinces, cities, del = false } = editArr[i];
let dataToUpdate = {
provinces,
cities,
del
}
await models.SalesDistribution.update(dataToUpdate, { where: { pepUserId: pepUserId } });
}
}
await transaction.commit();
ctx.status = 204;
} catch (error) {
await transaction.rollback();
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = errorMsg;
}
}
module.exports = {
salesList,
add,
edit,
del,
exportData,
addSalesMemberBulk,
}