Browse Source

(*)销售统计-销售人员分布 api代码暂交

master
wuqun 2 years ago
parent
commit
8c43edbe70
  1. 333
      api/app/lib/controllers/salesDistribution/index.js
  2. 62
      api/app/lib/models/sales_distribution.js
  3. 24
      api/app/lib/routes/salesDistribution/index.js
  4. 3
      api/app/lib/utils/member.js

333
api/app/lib/controllers/salesDistribution/index.js

@ -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,
}

62
api/app/lib/models/sales_distribution.js

@ -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;
};

24
api/app/lib/routes/salesDistribution/index.js

@ -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);
};

3
api/app/lib/utils/member.js

@ -244,6 +244,7 @@ module.exports = function (app, opts) {
hrMember.*, hrMember.*,
user.name AS userName, user.name AS userName,
user.people_code AS userCode, user.people_code AS userCode,
basicDataPost.name AS userPost,
role.name AS roleName, role.name AS roleName,
role.id AS roleId, role.id AS roleId,
department.name AS depName, department.name AS depName,
@ -287,6 +288,8 @@ module.exports = function (app, opts) {
ON ${pepEmis}.user_role.user = user.id ON ${pepEmis}.user_role.user = user.id
LEFT JOIN ${pepEmis}.role AS role LEFT JOIN ${pepEmis}.role AS role
ON ${pepEmis}.role.id = user_role.role ON ${pepEmis}.role.id = user_role.role
LEFT JOIN ${pepEmis}.basicdata_post AS basicDataPost
ON ${pepEmis}.basicdata_post.id = user.post
LEFT JOIN ${pepEmis}.department_user AS department_user LEFT JOIN ${pepEmis}.department_user AS department_user
ON department_user.user = user.id ON department_user.user = user.id
LEFT JOIN ${pepEmis}.department AS department LEFT JOIN ${pepEmis}.department AS department

Loading…
Cancel
Save