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.
		
		
		
		
		
			
		
			
				
					
					
						
							350 lines
						
					
					
						
							15 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							350 lines
						
					
					
						
							15 KiB
						
					
					
				| 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'; | |
| import SalesMemberModal from './salesMemberModal' | |
| import ImportSalersModal from './importSalersModal' | |
| import { IconSearch } from '@douyinfe/semi-icons'; | |
| import { SkeletonScreen } from "$components"; | |
| import '../../style.less' | |
| 
 | |
| const PersonnelDistribution = (props) => { | |
|     const { dispatch, actions } = props | |
|     const { humanAffairs } = actions; | |
|     const [keywordTarget, setKeywordTarget] = useState('dep'); | |
|     const [keyword, setKeyword] = useState('');//搜索内容 | |
|     const [limits, setLimits] = useState()//每页实际条数 | |
|     const [query, setQuery] = useState({ limit: 10, page: 0 }); //页码信息 | |
|     const [modalV, setModalV] = useState(false); | |
|     const [dataToEdit, setDataToEdit] = useState(null); | |
|     const [tableData, setTableData] = useState([]); | |
|     const [importModalV, setImportModalV] = useState(false); | |
|     const page = useRef(query.page); | |
|     function seachValueChange(value) { | |
|         setKeyword(value) | |
|     } | |
| 
 | |
|     useEffect(() => { | |
|         dispatch(humanAffairs.getMemberList()) | |
|         getMemberSearchList() | |
|     }, []); | |
| 
 | |
|     useEffect(() => { | |
|         getMemberSearchList()//查询人员列表 | |
|     }, [query]) | |
| 
 | |
|     function getMemberSearchList() { | |
|         let kt = keywordTarget == 'place' ? '' : keywordTarget; | |
|         let k = keywordTarget == 'place' ? '' : keyword; | |
|         let placeSearch = keywordTarget == 'place' ? keyword : ''; | |
|         dispatch(humanAffairs.getSalesList({ keywordTarget: kt, keyword: k, placeSearch, ...query })).then(r => { | |
|             if (r.success) { | |
|                 setTableData(r.payload?.data?.rows); | |
|                 setLimits(r.payload?.data?.count) | |
|             } | |
|         }) | |
|     } | |
| 
 | |
|     function handleRow(record, index) {// 给偶数行设置斑马纹 | |
|         if (index % 2 === 0) { | |
|             return { | |
|                 style: { | |
|                     background: '#FAFCFF', | |
|                 } | |
|             }; | |
|         } else { | |
|             return {}; | |
|         } | |
|     } | |
| 
 | |
|     const closeAndFetch = () => { | |
|         setModalV(false) | |
|         getMemberSearchList(); | |
|     } | |
| 
 | |
|     const starHeader = (header) => { | |
|         return <div> | |
|             <img src="/assets/images/hrImg/V.png" style={{ width: 14, height: 14 }} /> {header} | |
|         </div> | |
|     } | |
| 
 | |
|     const getMultis = (arrStr) => {//默认展示2个 | |
|         return <div style={{ display: 'flex' }}> | |
|             { | |
|                 arrStr.length ? | |
|                     arrStr.map((ite, idx) => { | |
|                         return ( | |
|                             <div key={idx} style={{ display: 'flex' }}> | |
|                                 {idx < 2 ? | |
|                                     <div style={{ padding: '0px 4px 1px 4px', color: '#FFF', fontSize: 12, background: 'rgba(0,90,189,0.8)', borderRadius: 2, marginRight: 4 }}> | |
|                                         {ite} | |
|                                     </div> : '' | |
|                                 } | |
|                                 { | |
|                                     arrStr.length > 2 && idx == 2 ? | |
|                                         <Tooltip content={arrStr.join(',')} trigger="click" style={{ lineHeight: 2 }}> | |
|                                             <div style={{ padding: '0px 4px 1px 4px ', color: 'rgba(0,90,189,0.8)', fontSize: 12, marginRight: 4, cursor: "pointer" }}> | |
|                                                 +{arrStr.length - 2} | |
|                                             </div> | |
|                                         </Tooltip> | |
|                                         : '' | |
|                                 } | |
|                             </div> | |
|                         ) | |
|                     }) : '-' | |
|             } | |
|         </div> | |
|     } | |
| 
 | |
|     const columns = [{ | |
|         title: '序号', | |
|         dataIndex: 'id', | |
|         key: 'id', | |
|         width: 60, | |
|         render: (text, record, index) => index + 1 | |
|     }, { | |
|         title: starHeader('姓名'), | |
|         dataIndex: 'name', | |
|         key: 'name', | |
|         width: 80 | |
|     }, | |
|     { | |
|         title: starHeader('部门名称'), | |
|         dataIndex: 'department', | |
|         key: 'department', | |
|         width: 200, | |
|         render: (text, r, index) => { | |
|             let arrStr = text.map(t => t.name); | |
|             return getMultis(arrStr); | |
|         } | |
|     }, { | |
|         title: '销售区域(省/直辖市)', | |
|         dataIndex: 'provinces', | |
|         key: 'provinces', | |
|         width: 160, | |
|         render: (text, record, index) => { | |
|             return getMultis(text?.split('、') || []); | |
|         } | |
|     }, { | |
|         title: '销售区域(市)', | |
|         dataIndex: 'cities', | |
|         key: 'cities', | |
|         width: 160, | |
|         render: (text, record, index) => { | |
|             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: 120, | |
|         render: (text, record) => <span>{text || '-'}</span> | |
|     }, { | |
|         title: starHeader('入职时间'), | |
|         dataIndex: 'hireDate', | |
|         key: 'hireDate', | |
|         width: 120, | |
|         render: (text, record) => <span>{text || '-'}</span> | |
|     }, { | |
|         title: starHeader('转正时间'), | |
|         dataIndex: 'regularDate', | |
|         key: 'regularDate', | |
|         width: 120, | |
|         render: (text, record) => <span>{text || '-'}</span> | |
|     }, { | |
|         title: starHeader('工龄'), | |
|         dataIndex: 'workYears', | |
|         key: 'workYears', | |
|         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: 120, | |
|         render: (text, record) => { | |
|             return <div> | |
|                 <span style={{ color: '#1890FF', cursor: 'pointer' }} onClick={() => onEdit(record)}>编辑</span>   | |
|                 <Popconfirm | |
|                     title='提示' content="确认删除该销售人员信息?" position='topLeft' | |
|                     onConfirm={() => confirmDelete(record.pepUserId)} style={{ width: 330 }} | |
|                 > <span style={{ color: '#1890FF', cursor: 'pointer' }}>删除</span></Popconfirm> | |
|             </div> | |
|         } | |
|     }]; | |
| 
 | |
|     const onEdit = (data) => { | |
|         setModalV(true); | |
|         setDataToEdit(data); | |
|     } | |
| 
 | |
|     const confirmDelete = (pepUserId) => { | |
|         dispatch(humanAffairs.delSalesMember({ pepUserId, msg: '删除销售人员信息' })).then(res => { | |
|             if (res.success) { | |
|                 getMemberSearchList(); | |
|             } | |
|         }); | |
|     } | |
|     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> | |
|             <div style={{ color: 'rgba(0,0,0,0.45)', fontSize: 14, margin: '0px 8px' }}>/</div> | |
|             <div style={{ color: 'rgba(0,0,0,0.45)', fontSize: 14 }}>销售统计</div> | |
|             <div style={{ color: '#033C9A', fontSize: 14, margin: '0px 8px' }}>/</div> | |
|             <div style={{ color: '#033C9A', fontSize: 14 }}>销售人员分布</div> | |
|         </div> | |
|         <div style={{ background: '#FFFFFF', boxShadow: '0px 0px 12px 2px rgba(220,222,224,0.2)', borderRadius: 2, padding: '20px 0px 20px 19px ', marginTop: 12 }}> | |
|             <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}> | |
|                 <div style={{ display: 'flex', alignItems: 'baseline' }}> | |
|                     <div style={{ width: 0, height: 20, borderLeft: '3px solid #0F7EFB', borderTop: '3px solid transparent', borderBottom: '3px solid transparent' }}></div> | |
|                     <div style={{ fontFamily: "YouSheBiaoTiHei", fontSize: 24, color: '#033C9A', marginLeft: 8 }}>销售人员分布</div> | |
|                     <div style={{ marginLeft: 6, fontSize: 12, color: '#969799', fontFamily: "DINExp", }}>DISTRIBUTION OF SALES PERSONNEL</div> | |
|                 </div> | |
|             </div> | |
|             <div style={{ margin: '18px 0px' }}> | |
|                 <div style={{ display: 'flex', margin: '16px 0px', justifyContent: 'space-between' }}> | |
|                     <div style={{ display: 'flex' }}> | |
|                         <div style={{ padding: '6px 20px', background: '#0F7EFB', color: '#FFFFFF', fontSize: 14, cursor: "pointer", marginRight: 18 }} | |
|                             onClick={() => { | |
|                                 setModalV(true); | |
|                                 setDataToEdit(null); | |
|                             }}> | |
|                             新增 | |
|                         </div> | |
|                         <div> | |
|                             <Select value={keywordTarget} onChange={setKeywordTarget} style={{ width: 100 }} > | |
|                                 <Select.Option value='dep'>部门</Select.Option> | |
|                                 <Select.Option value='place'>地区</Select.Option> | |
|                             </Select> | |
|                         </div> | |
|                         <div style={{ margin: '0px 18px' }}> | |
|                             <Input suffix={<IconSearch />} | |
|                                 showClear | |
|                                 placeholder='请输入关键词搜索' | |
|                                 value={keyword} | |
|                                 style={{ width: 346 }} | |
|                                 onChange={seachValueChange}> | |
|                             </Input> | |
|                         </div> | |
|                         <Button theme='solid' type='primary' style={{ width: 80, borderRadius: 2, height: 32, background: '#DBECFF', color: '#005ABD' }} | |
|                             onClick={() => { | |
|                                 setQuery({ limit: 10, page: 0 }) | |
|                             }}>查询</Button> | |
|                     </div> | |
|                     <div style={{ display: 'flex', marginRight: 20 }}> | |
|                         <div style={{ padding: '6px 20px', background: '#0F7EFB', color: '#FFFFFF', fontSize: 14, cursor: "pointer" }} | |
|                             onClick={() => { setImportModalV(true); }}> | |
|                             导入 | |
|                         </div> | |
|                         {/* <div style={{ padding: '6px 20px', background: '#00BA85', color: '#FFFFFF', fontSize: 14, marginLeft: 18 }}> | |
|                             导出 | |
|                         </div> */} | |
|                     </div> | |
|                 </div> | |
| 
 | |
|                 <div style={{ border: '1px solid #C7E1FF', background: '#F4F8FF', borderRadius: 2, height: 32, width: 669, padding: '8px 0px 7px 12px', display: 'flex', alignItems: 'center', color: '#0F7EFB', fontSize: 12 }}> | |
|                     <img src="/assets/images/hrImg/!.png" alt="" style={{ width: 14, height: 14, marginRight: 8 }} /> | |
|                     表格中带有认证标识" | |
|                     <img src="/assets/images/hrImg/V.png" alt="" style={{ width: 14, height: 14 }} /> | |
|                     "信息的为系统基础数据,来源于项企PEP、钉钉等系统,其他数据均为导入或自定义数据 | |
|                 </div> | |
| 
 | |
|                 <div style={{ marginTop: 20 }}> | |
|                     <Skeleton | |
|                         // loading={loading} | |
|                         loading={false} | |
|                         active={true} | |
|                         placeholder={SkeletonScreen()} | |
|                     > | |
|                         <Table | |
|                             columns={columns} | |
|                             dataSource={tableData} | |
|                             bordered={false} | |
|                             empty="暂无数据" | |
|                             pagination={false} | |
|                             onChange={({ sorter }) => { | |
|                                 if (sorter.key == 'userCode') { | |
|                                     if (sorter.sortOrder == 'descend') { | |
|                                         setOrder({ orderBy: 'code', orderDirection: 'DESC' }) | |
|                                     } else { | |
|                                         setOrder({ orderBy: 'code', orderDirection: 'ASC' }) | |
|                                     } | |
|                                 } else if (sorter.key == 'age') { | |
|                                     if (sorter.sortOrder == 'descend') { | |
|                                         setOrder({ orderBy: 'age', orderDirection: 'DESC' }) | |
|                                     } else { | |
|                                         setOrder({ orderBy: 'age', orderDirection: 'ASC' }) | |
|                                     } | |
|                                 } else { | |
|                                     if (sorter.sortOrder == 'descend') { | |
|                                         setOrder({ orderBy: 'hiredate', orderDirection: 'DESC' }) | |
|                                     } else { | |
|                                         setOrder({ orderBy: 'hiredate', orderDirection: 'ASC' }) | |
|                                     } | |
|                                 } | |
|                             }} | |
|                             onRow={handleRow} | |
|                             scroll={scroll} | |
|                         /> | |
|                     </Skeleton> | |
|                     <div style={{ | |
|                         display: "flex", | |
|                         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}条信息 | |
|                             </span> | |
|                             <Pagination | |
|                                 total={limits} | |
|                                 showSizeChanger | |
|                                 currentPage={query.page + 1} | |
|                                 pageSizeOpts={[10, 20, 30, 40]} | |
|                                 onChange={(currentPage, pageSize) => { | |
|                                     setQuery({ limit: pageSize, page: currentPage - 1 }); | |
|                                     page.current = currentPage - 1 | |
|                                 }} | |
|                             /> | |
|                         </div> | |
|                     </div> | |
|                 </div> | |
|             </div> | |
|         </div> | |
|         { | |
|             modalV ? <SalesMemberModal | |
|                 dataToEdit={dataToEdit} getMultis={getMultis} | |
|                 close={() => closeAndFetch()} | |
|                 onCancel={() => setModalV(false)} /> : '' | |
|         } | |
|         { | |
|             importModalV ? <ImportSalersModal | |
|                 onCancel={() => { | |
|                     setImportModalV(false); | |
|                     getMemberSearchList(); | |
|                 }} /> : '' | |
|         } | |
|     </div>) | |
| } | |
| 
 | |
| function mapStateToProps(state) { | |
|     const { auth, global, SalesMemberList } = state; | |
|     return { | |
|         user: auth.user, | |
|         actions: global.actions, | |
|         salesMemberList: SalesMemberList.data | |
|     }; | |
| } | |
| 
 | |
| export default connect(mapStateToProps)(PersonnelDistribution); |