wenlele 2 years ago
parent
commit
469474ac67
  1. 4
      api/.vscode/launch.json
  2. 8
      api/app/lib/controllers/attendance/index.js
  3. 15
      api/app/lib/controllers/auth/index.js
  4. 27
      api/app/lib/controllers/salesDistribution/index.js
  5. 9
      api/app/lib/models/sales_distribution.js
  6. 4
      doc/scripts/PEP V3.0.0/schema/1.sales_distribution_modify.sql
  7. 4
      web/client/src/sections/humanAffairs/containers/salersDistribution/constans.jsx
  8. 25
      web/client/src/sections/humanAffairs/containers/salersDistribution/importSalersModal.js
  9. 35
      web/client/src/sections/humanAffairs/containers/salersDistribution/personnelDistribution.jsx
  10. 45
      web/client/src/sections/humanAffairs/containers/salersDistribution/salesMemberModal.js

4
api/.vscode/launch.json

@ -19,9 +19,9 @@
"-g postgres://postgres:123@10.8.30.166:5432/hr-dev",
"--redisHost 10.8.30.112",
"--redisPort 6379",
// "--apiEmisUrl http://10.8.30.112:14000",
"--apiEmisUrl http://10.8.30.112:14000",
//
"--apiEmisUrl http://10.8.30.161:1111",
// "--apiEmisUrl http://10.8.30.161:1111",
"--qnak XuDgkao6cL0HidoMAPnA5OB10Mc_Ew08mpIfRJK5",
"--qnsk yewcieZLzKZuDfig0wLZ9if9jKp2P_1jd3CMJPSa",
"--qnbkt dev-hr",

8
api/app/lib/controllers/attendance/index.js

@ -29,7 +29,9 @@ async function overtimeStatistic (ctx) {
})
returnD.forEach(u => {
u.overtimeStatistic = sumRes.filter(s => s.pepUserId == u.pepUserId)
let overtimeStatistic = sumRes.filter(s => s.pepUserId == u.pepUserId)
u.overtimeDuration = overtimeStatistic.reduce((sum, os) => sum + os.duration, 0)
u.overtimeStatistic = overtimeStatistic
})
ctx.status = 200;
ctx.body = {
@ -204,7 +206,9 @@ async function vacateStatistic (ctx) {
})
returnD.forEach(u => {
u.vacateStatistic = sumRes.filter(s => s.pepUserId == u.pepUserId)
let vacateStatistic = sumRes.filter(s => s.pepUserId == u.pepUserId)
u.vacateDuration = vacateStatistic.reduce((sum, vs) => sum + vs.duration, 0)
u.vacateStatistic = vacateStatistic
})
ctx.status = 200;
ctx.body = {

15
api/app/lib/controllers/auth/index.js

@ -10,9 +10,18 @@ async function login (ctx, next) {
const models = ctx.fs.dc.models;
const params = ctx.request.body;
const emisLoginRes = await ctx.app.fs.emisRequest.post('login', {
data: params
})
let emisLoginRes = null
if (params.username && params.password) {
emisLoginRes = await ctx.app.fs.emisRequest.post('login', {
data: { ...params, code: 'HR' }
})
} else if (params.token) {
emisLoginRes = await ctx.app.fs.emisRequest.get('user-info', {
query: {
token: params.token, code: 'HR'
}
})
}
if (!emisLoginRes) {
throw "无此用户,请使用正确的登录信息"

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

@ -47,20 +47,7 @@ async function salesList(ctx) {
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,
@ -71,10 +58,7 @@ async function salesList(ctx) {
...d.dataValues
}
rslt.push(item);
//}
})
// let end = Number(page) * Number(limit) + Number(limit)
// let arr = rslt.slice(Number(page) * Number(limit), end)
ctx.status = 200;
ctx.body = {
count: res.count,
@ -92,7 +76,7 @@ async function salesList(ctx) {
async function add(ctx) {
try {
const { models } = ctx.fs.dc;
const { pepUserId, provinces, cities } = ctx.request.body
const { pepUserId, provinces, cities, businessLines } = ctx.request.body
const existRes = await models.SalesDistribution.findOne({
where: { pepUserId }
@ -102,7 +86,7 @@ async function add(ctx) {
throw '当前销售人员信息已存在'
}
let storageData = { pepUserId, provinces, cities, del: false }
let storageData = { pepUserId, provinces, cities, businessLines, del: false }
if (existRes && existRes.del) {
await models.SalesDistribution.update(storageData, {
where: { pepUserId }
@ -123,7 +107,7 @@ async function add(ctx) {
async function edit(ctx) {
try {
const { models } = ctx.fs.dc;
const { pepUserId, provinces, cities } = ctx.request.body
const { pepUserId, provinces, cities, businessLines } = ctx.request.body
const existRes = await models.SalesDistribution.findOne({
where: { pepUserId }
@ -133,7 +117,7 @@ async function edit(ctx) {
throw '当前销售人员信息不存在'
}
let storageData = { pepUserId, provinces, cities, del: false }
let storageData = { pepUserId, provinces, cities, businessLines, del: false }
await models.SalesDistribution.update(storageData, {
where: {
@ -321,11 +305,12 @@ async function addSalesMemberBulk(ctx) {
//处理编辑的
if (editArr.length) {
for (let i in editArr) {
let { pepUserId, provinces, cities, del = false } = editArr[i];
let { pepUserId, provinces, cities, businessLines, del = false } = editArr[i];
let dataToUpdate = {
provinces,
cities,
businessLines,
del
}
await models.SalesDistribution.update(dataToUpdate, { where: { pepUserId: pepUserId } });

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

@ -51,6 +51,15 @@ module.exports = dc => {
primaryKey: false,
field: "del",
autoIncrement: false
},
businessLines: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
comment: null,
primaryKey: false,
field: "business_lines",
autoIncrement: false
}
}, {
tableName: "sales_distribution",

4
doc/scripts/PEP V3.0.0/schema/1.sales_distribution_modify.sql

@ -0,0 +1,4 @@
alter table sales_distribution
add "business_lines" text;

4
web/client/src/sections/humanAffairs/containers/salersDistribution/constans.jsx

@ -0,0 +1,4 @@
export const businessLinesConst = ['市政', '地灾', '水利', '智慧城市', '工地',
'环保', '安防', '产品投标', '交通', '矿山', '产品线']

25
web/client/src/sections/humanAffairs/containers/salersDistribution/importSalersModal.js

@ -4,6 +4,7 @@ import { connect } from 'react-redux';
import { Modal, Form, Button, Notification } from '@douyinfe/semi-ui';
import { IconUpload } from '@douyinfe/semi-icons';
import cityData from '../../components/city.json';
import { businessLinesConst } from './constans'
import XLSX from 'xlsx'
//下载模板和上传文件读取
const ImportSalersModal = props => {
@ -38,7 +39,7 @@ const ImportSalersModal = props => {
const dldCsvMb = () => {
//表头
let head = "员工编号,姓名,销售区域(省/直辖市),销售区域(市)\n"
let head = "员工编号,姓名,销售区域(省/直辖市),销售区域(市),业务线\n"
//数据
//let data = 1 + ',' + 2 + ',' + 3 + ',' + 4 + ',' + 5
let templateCsv = "data:text/csv;charset=utf-8,\ufeff" + head;
@ -142,6 +143,19 @@ const ImportSalersModal = props => {
return !noMark;
}
const judgeLines = (businessLines) => {
if (!businessLines) {//可以不填
return true;
}
let noMark = 0;
businessLines?.split('、')?.map(p => {
if (businessLinesConst.indexOf(p) == -1) {
noMark++
}
})
return !noMark;
}
const judgeNull = (value) => {
return value ? String(value).trim().replace(/\s*/g, "") : null;
}
@ -191,6 +205,7 @@ const ImportSalersModal = props => {
let name = judgeNull(d['姓名']);
let provinces = judgeNull(d['销售区域(省/直辖市)']);
let cities = judgeNull(d['销售区域(市)']);
let businessLines = judgeNull(d['业务线']);
if (!number) {//人员编号不为空,唯一,字母和数字
error(`${i + 2}行人员编号为空,请填写`)
return
@ -226,9 +241,14 @@ const ImportSalersModal = props => {
error(`${i + 2}行销售区域(市)错误`)
return
}
let bValid = judgeLines(businessLines);
if (!bValid) {
error(`${i + 2}行业务线错误`)
return
}
postData.push({
pepUserId: rzExist.pepUserId, name, number,
provinces: provinces || '', cities: cities || '',
provinces: provinces || '', cities: cities || '', businessLines: businessLines || '',
del: false
})
}
@ -252,6 +272,7 @@ const ImportSalersModal = props => {
<div>姓名必填若与员工编号对应的项企用户姓名不同将以项企数据为准</div>
<div>销售区域/直辖市必填省或直辖市顿号隔开北京市江西省江苏省</div>
<div>销售区域非必填归属所填省的地级市顿号隔开南昌市镇江市</div>
<div>业务线非必填顿号隔开智慧城市工地</div>
</div>
</Form>
</Modal >

35
web/client/src/sections/humanAffairs/containers/salersDistribution/personnelDistribution.jsx

@ -1,4 +1,4 @@
import React, { useEffect, useRef, useState } from 'react';
import React, { useEffect, useRef, useState, useMemo } from 'react';
import { connect } from 'react-redux';
import moment from 'moment'
import { Select, Input, Button, Popconfirm, Radio, Tooltip, Table, Pagination, Skeleton } from '@douyinfe/semi-ui';
@ -100,19 +100,19 @@ const PersonnelDistribution = (props) => {
title: '序号',
dataIndex: 'id',
key: 'id',
width: '5%',
width: 60,
render: (text, record, index) => index + 1
}, {
title: starHeader('姓名'),
dataIndex: 'name',
key: 'name',
width: '5%'
width: 80
},
{
title: starHeader('部门名称'),
dataIndex: 'department',
key: 'department',
width: '18%',
width: 200,
render: (text, r, index) => {
let arrStr = text.map(t => t.name);
return getMultis(arrStr);
@ -121,7 +121,7 @@ const PersonnelDistribution = (props) => {
title: '销售区域(省/直辖市)',
dataIndex: 'provinces',
key: 'provinces',
width: '15%',
width: 160,
render: (text, record, index) => {
return getMultis(text?.split('、') || []);
}
@ -129,40 +129,48 @@ const PersonnelDistribution = (props) => {
title: '销售区域(市)',
dataIndex: 'cities',
key: 'cities',
width: '15%',
width: 160,
render: (text, record, index) => {
return getMultis(text?.split('、') || []);
return text ? getMultis(text?.split('、') || []) : '-';
}
}, {
title: '业务线',
dataIndex: 'businessLines',
key: 'businessLines',
width: 140,
render: (text, record, index) => {
return text ? getMultis(text?.split('、') || []) : '-';
}
}, {
title: starHeader('岗位'),
dataIndex: 'post',
key: 'post',
width: '11%',
width: 120,
render: (text, record) => <span>{text || '-'}</span>
}, {
title: starHeader('入职时间'),
dataIndex: 'hireDate',
key: 'hireDate',
width: '8%',
width: 120,
render: (text, record) => <span>{text || '-'}</span>
}, {
title: starHeader('转正时间'),
dataIndex: 'regularDate',
key: 'regularDate',
width: '8%',
width: 120,
render: (text, record) => <span>{text || '-'}</span>
}, {
title: starHeader('工龄'),
dataIndex: 'workYears',
key: 'workYears',
width: '5%',
width: 120,
render: (_, r, index) => {
return (r.hireDate ? <span style={{ color: '#1890FF' }}>{String(moment(new Date()).diff(r.hireDate, 'years', true)).substring(0, 3) + '年'}</span> : '-')
},
}, {
title: '操作',
dataIndex: 'action',
width: '10%',
width: 120,
render: (text, record) => {
return <div>
<span style={{ color: '#1890FF', cursor: 'pointer' }} onClick={() => onEdit(record)}>编辑</span>&nbsp;&nbsp;
@ -186,7 +194,7 @@ const PersonnelDistribution = (props) => {
}
});
}
const scroll = useMemo(() => ({}), []);
return (<div style={{ padding: '0px 12px' }}>
<div style={{ display: 'flex' }}>
<div style={{ color: 'rgba(0,0,0,0.45)', fontSize: 14 }}>招聘</div>
@ -294,6 +302,7 @@ const PersonnelDistribution = (props) => {
justifyContent: "space-between",
padding: "20px 20px",
}}>
<div></div>
<div style={{ display: 'flex', }}>
<span style={{ lineHeight: "30px", fontSize: 13, color: 'rgba(0,90,189,0.8)' }}>
{limits}条信息

45
web/client/src/sections/humanAffairs/containers/salersDistribution/salesMemberModal.js

@ -3,10 +3,12 @@ import moment from 'moment';
import { connect } from "react-redux";
import { Select, Modal, Form, Notification } from "@douyinfe/semi-ui";
import cityData from '../../components/city.json';
import { businessLinesConst } from './constans'
const SalesMemberModal = (props) => {
const { dispatch, actions, user, meetingList, onConfirm, getMultis, onCancel, close, rzMembers, dataToEdit } = props;
const { humanAffairs } = actions;
const form = useRef();//表单
const [lineOptions, setLineOptions] = useState([]);
const [options, setOptions] = useState([]);
const [cityOptions, setCityOptions] = useState([]);
const [peoplePro, setPeoplePro] = useState({}); //人员信息
@ -18,6 +20,14 @@ const SalesMemberModal = (props) => {
</Select.Option>
})
setOptions(optionItems);
let lineOptions = businessLinesConst.map((l, index) => {
return <Select.Option value={l} key={index}>
{l}
</Select.Option>
})
setLineOptions(lineOptions);
if (dataToEdit) {
setPeoplePro(dataToEdit);
onChange(dataToEdit.provinces?.split('、') || []);//市options
@ -59,6 +69,7 @@ const SalesMemberModal = (props) => {
if (values.userCode == peoplePro.userCode) {
values.provinces = values.provinces.join('、')
values.cities = values.cities.join('、')
values.businessLines = values.businessLines.join('、')
if (dataToEdit) {
dispatch(humanAffairs.editSalesMember({ pepUserId: peoplePro.pepUserId, msg: '编辑销售人员信息', ...values })).then((res) => {
if (res.success) {
@ -163,14 +174,6 @@ const SalesMemberModal = (props) => {
</div>
}
// const handleDeselect = (value) => {//删除
// let ranges = cityData.find(td => td.name == value)?.children || []
// if (ranges) {
// let formList = form.current.getValues().cities;
// }
// }
const onClear = () => {
form.current.setValue('cities', [])
}
@ -212,36 +215,36 @@ const SalesMemberModal = (props) => {
placeholder='请选择销售区域(省/直辖市)'
multiple filter
style={{ width: '100%' }}
// optionFilterProp='children'
// getPopupContainer={triggerNode => triggerNode.parentNode}
// filterOption={(input, option) => option.props.children
// .toLowerCase().indexOf(input.toLowerCase()) >= 0}
// value={selectedKeys || []}
onClear={() => onClear()}
onChange={value => onChange(value)}
//onDeselect={value => handleDeselect(value)}
maxTagCount={5}
>
{options}
</Form.Select>
<Form.Select
initValue={dataToEdit?.cities || []}
initValue={dataToEdit?.cities ? dataToEdit?.cities?.split('、') : []}
label="销售区域(市)"
field='cities'
showClear
placeholder='请选择销售区域(市)'
multiple filter
style={{ width: '100%' }}
// optionFilterProp='children'
// getPopupContainer={triggerNode => triggerNode.parentNode}
// filterOption={(input, option) => option.props.children
// .toLowerCase().indexOf(input.toLowerCase()) >= 0}
// value={selectedKeys || []}
//onDeselect={value => handleDeselect(value)}
maxTagCount={5}
>
{cityOptions}
</Form.Select>
<Form.Select
initValue={dataToEdit?.businessLines ? dataToEdit?.businessLines?.split('、') : []}
label="业务线"
field='businessLines'
showClear
placeholder='请选择业务线'
multiple filter
style={{ width: '100%' }}
maxTagCount={5}
>
{lineOptions}
</Form.Select>
</Form>
</Modal>
)

Loading…
Cancel
Save