wuqun
2 years ago
4 changed files with 422 additions and 0 deletions
@ -0,0 +1,333 @@ |
|||
'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), |
|||
}) |
|||
|
|||
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, |
|||
} |
@ -0,0 +1,62 @@ |
|||
/* eslint-disable*/ |
|||
|
|||
'use strict'; |
|||
|
|||
module.exports = dc => { |
|||
const DataTypes = dc.ORM; |
|||
const sequelize = dc.orm; |
|||
const SalesDistribution = sequelize.define("salesDistribution", { |
|||
id: { |
|||
type: DataTypes.INTEGER, |
|||
allowNull: false, |
|||
defaultValue: null, |
|||
comment: null, |
|||
primaryKey: true, |
|||
field: "id", |
|||
autoIncrement: true, |
|||
unique: "sales_distribution_id_uindex" |
|||
}, |
|||
pepUserId: { |
|||
type: DataTypes.INTEGER, |
|||
allowNull: false, |
|||
defaultValue: null, |
|||
comment: null, |
|||
primaryKey: false, |
|||
field: "pep_user_id", |
|||
autoIncrement: false |
|||
}, |
|||
provinces: { |
|||
type: DataTypes.ARRAY(DataTypes.STRING), |
|||
allowNull: false, |
|||
defaultValue: null, |
|||
comment: null, |
|||
primaryKey: false, |
|||
field: "provinces", |
|||
autoIncrement: false |
|||
}, |
|||
cities: { |
|||
type: DataTypes.ARRAY(DataTypes.STRING), |
|||
allowNull: true, |
|||
defaultValue: null, |
|||
comment: null, |
|||
primaryKey: false, |
|||
field: "cities", |
|||
autoIncrement: false |
|||
}, |
|||
del: { |
|||
type: DataTypes.BOOLEAN, |
|||
allowNull: true, |
|||
defaultValue: null, |
|||
comment: null, |
|||
primaryKey: false, |
|||
field: "del", |
|||
autoIncrement: false |
|||
} |
|||
}, { |
|||
tableName: "sales_distribution", |
|||
comment: "", |
|||
indexes: [] |
|||
}); |
|||
dc.models.SalesDistribution = SalesDistribution; |
|||
return SalesDistribution; |
|||
}; |
@ -0,0 +1,24 @@ |
|||
'use strict'; |
|||
|
|||
const salesDistribution = require('../../controllers/salesDistribution'); |
|||
|
|||
module.exports = function (app, router, opts) { |
|||
|
|||
app.fs.api.logAttr['GET/sales/member/list'] = { content: '查询销售人员列表', visible: true }; |
|||
router.get('/sales/member/list', salesDistribution.salesList); |
|||
|
|||
app.fs.api.logAttr['POST/sales/member/add'] = { content: '添加销售人员信息', visible: true }; |
|||
router.post('/sales/member/add', salesDistribution.add); |
|||
|
|||
app.fs.api.logAttr['PUT/sales/member/modify'] = { content: '编辑销售人员信息', visible: true }; |
|||
router.put('/sales/member/modify', salesDistribution.edit); |
|||
|
|||
app.fs.api.logAttr['DEL/sales/member/del'] = { content: '删除销售人员信息', visible: true }; |
|||
router.del('/sales/member/del', salesDistribution.del); |
|||
|
|||
app.fs.api.logAttr['POST/add/sales/members/bulk'] = { content: '导入销售人员信息', visible: true }; |
|||
router.post('/add/sales/members/bulk', salesDistribution.addSalesMemberBulk); |
|||
|
|||
app.fs.api.logAttr['GET/sales/members/export'] = { content: '导出销售人员信息', visible: true }; |
|||
router.get('/sales/members/export', salesDistribution.exportData); |
|||
}; |
Loading…
Reference in new issue