人力资源
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.
 
 
 
 

449 lines
23 KiB

import React, { useEffect, useState, useRef, useMemo } from 'react';
import { connect } from 'react-redux';
import { Table, Button, Pagination, Skeleton, Form, Tooltip } from '@douyinfe/semi-ui';
import { IconSearch } from '@douyinfe/semi-icons';
import { SkeletonScreen } from "$components";
import '../style.less'
import { Setup } from "$components";
import moment from 'moment'
import { set } from 'nprogress';
const leaveStatistics = (props) => {
const { dispatch, actions, history, user, loading, socket, xqMembers } = props
const { humanAffairs } = actions;
const form = useRef();//表单
let [archivesList, setArchivesList] = useState([]);//人员列表
let [mytypeList, setTypeList] = useState([]);//请假类型列表
const [setup, setSetup] = useState(false);//表格设置是否显现
const [setupp, setSetupp] = useState([]);//实际显示的表格列表
const [lookup, setLookup] = useState({});//搜索
const [query, setQuery] = useState({ limit: 10, page: 0 }); //页码信息
const [order, setOrder] = useState({ orderBy: 'code', orderDirection: 'DESC' }); //页码信息
const [limits, setLimits] = useState()//每页实际条数
const [downloadUrl, setDownloadUrl] = useState('')//下载pdf
const LEAVESTATISTICS = "leaveStatistics";
const page = useRef(query.page);//哪一页
const [tableList, setTableList] = useState([{
title: '展示信息',
list: [
{ name: "姓名", value: "userName" },
{ name: "所属部门", value: "departmrnt" },
{ name: "职位", value: "roleName" },
{ name: "合计请假时长", value: "vacateDayStatisticDuration" },
{ name: "合计请假次数", value: "vacateCount" },
]
}]);//表格属性
useEffect(() => {
localStorage.getItem(LEAVESTATISTICS) == null
? localStorage.setItem(
LEAVESTATISTICS,
JSON.stringify(['userName', 'departmrnt', 'roleName', 'vacateCount', 'vacateDayStatisticDuration'])
)
: "";
getAttendanceVacateTypeList()
}, [])
useEffect(() => {
getAttendanceVacateList()//查询人员列表
}, [query, order])
function getAttendanceVacateList () {//查询人员列表
let obj = lookup
if (lookup.entryTime?.length > 1) {
obj.startDate = moment(lookup.entryTime[0]).format('YYYY-MM-DD')
obj.endDate = moment(lookup.entryTime[1]).format('YYYY-MM-DD')
}
else {
obj.startDate = ''
obj.endDate = ''
}
dispatch(humanAffairs.getAttendanceVacate({ ...obj, ...query, ...order })).then((res) => {//查询人员列表
if (res.success) {
setArchivesList(res.payload?.data?.rows)
setLimits(res.payload?.data?.count)
}
})
}
function getAttendanceVacateTypeList () {
dispatch(humanAffairs.getAttendanceVacateType()).then((res) => {//查询人员列表
if (res.success) {
let myTableList = tableList
for (let i = 0; i < res.payload?.data?.length; i++) {
myTableList[0].list.push({ name: res.payload?.data[i].type, value: res.payload?.data[i].type },)
}
setTypeList(res.payload?.data)
setTableList(myTableList)
attribute(res.payload?.data);
}
})
}
const columns = [
{
title: (
<span>
<img src="/assets/images/hrImg/V.png" alt="" style={{ width: 14, height: 14 }} /> 员工编号
</span>
),
width: 200,
dataIndex: "userCode",
key: "userCode",
sorter: (a, b) => { },
render: (_, r, index) => {
return (r.userCode ? r.userCode : '-');
},
},
];
//获取表格属性设置
function attribute (typeList) {
const arr = localStorage.getItem(LEAVESTATISTICS)
? JSON.parse(localStorage.getItem(LEAVESTATISTICS))
: [];
let column = [
{
title: (
<div>
<img src="/assets/images/hrImg/V.png" alt="" style={{ width: 14, height: 14 }} /> 姓名
</div>
),
width: 100,
dataIndex: "userName",
key: "userName",
render: (_, r, index) => {
return (r.userName ? r.userName : '-');
},
}, {
title: (
<div>
<img src="/assets/images/hrImg/V.png" alt="" style={{ width: 14, height: 14 }} /> 所属部门
</div>
),
width: 200,
dataIndex: "departmrnt",
key: "departmrnt",
render: (_, r, index) => {
return (
<div style={{ display: 'flex' }}>
{
r.departmrnt.map((ite, idx) => {
let departmentsArr = []
for (let i = 0; i < r.departmrnt.length; i++) {
departmentsArr.push(r.departmrnt[i].name)
}
return (
<div key={idx} style={{ display: 'flex' }}>
{idx == 0 ?
(<div style={{ padding: '0px 4px 1px 4px ', color: '#FFFFFF', fontSize: 12, background: 'rgba(0,90,189,0.8)', borderRadius: 2, marginRight: 4 }}>
{ite.name}
</div>) : ('')
}
{
r.departmrnt.length > 1 && idx == 1 ? (
<Tooltip content={departmentsArr.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", }}>
+{r.departmrnt.length - 1}
</div>
</Tooltip>
) : ('')
}
</div>
)
})
}
</div>
)
},
}, {
title: (
<div>
<img src="/assets/images/hrImg/V.png" alt="" style={{ width: 14, height: 14 }} /> 职位
</div>
),
width: 150,
dataIndex: "roleName",
key: "roleName",
render: (_, r, index) => {
return (
<div style={{ display: 'flex', alignItems: 'center' }}>
{
r.role.map((ite, idx) => {
let roleArr = []
for (let i = 0; i < r.role.length; i++) {
roleArr.push(r.role[i].name)
}
return (
<div key={idx} style={{ display: 'flex', alignItems: 'center' }}>
{idx == 0 ?
(ite.name) : ('')
}
{
r.role.length > 1 && idx == 1 ? (
<Tooltip content={roleArr.join(',')} trigger="click" style={{ lineHeight: 2 }}>
<div style={{ color: 'rgba(0,90,189,0.8)', fontSize: 12, marginRight: 4, cursor: "pointer", }}>
+{r.role.length - 1}
</div>
</Tooltip>
) : ('')
}
</div>
)
})
}
</div>);
},
},
];
for (let j = 0; j < typeList.length; j++) {
column.push({
title: (typeList[j].type + '/h'),
width: 160,
dataIndex: typeList[j].type,
key: typeList[j].type,
render: (_, r, index) => {
return (r.vacateStatistic.findIndex(((ev) => {
return ev.type == typeList[j].type
})) !== -1 ? r.vacateStatistic[r.vacateStatistic.findIndex(((ev) => {
return ev.type == typeList[j].type
}))].duration / 3600 : '0')
},
})
}
column.push({
title: '合计请假时长/h',
width: 160,
dataIndex: "vacateDayStatisticDuration",
key: "vacateDayStatisticDuration",
sorter: (a, b) => { },
render: (_, r, index) => {
return (r.vacateDayStatisticDuration ? r.vacateDayStatisticDuration / 3600 : '0')
},
})
column.push({
title: '合计请假次数/次',
width: 160,
dataIndex: "vacateCount",
key: "vacateCount",
sorter: (a, b) => { },
render: (_, r, index) => {
return (r.vacateCount ? r.vacateCount : '0')
},
})
for (let i = 0; i < arr.length; i++) {
let colum = column.filter((item) => {
return item.key === arr[i];
});
columns.splice(i + 2, 0, colum[0]);
}
setSetupp(columns);
}
function handleRow (record, index) {//斑马条纹
// 给偶数行设置斑马纹
if (index % 2 === 0) {
return {
style: {
background: '#FAFCFF',
}
};
} else {
return {};
}
}
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", }}>LEAVE STATISTICS</div>
</div>
</div>
<div style={{ marginRight: 20, marginTop: 18 }}>
<Form
labelPosition="left"
labelAlign="right"
labelWidth="80px"
onValueChange={(values, field) => {
// console.log('values', values);
}}
getFormApi={(formApi) => (form.current = formApi)}
>
<div>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<div style={{ display: 'flex', alignItems: 'center' }}>
<Form.Select
pure
field="keywordTarget"
placeholder="请选择搜索类型"
style={{ width: 200 }}
initValue={"role"}
>
<Form.Select.Option value='role'>职位</Form.Select.Option>
<Form.Select.Option value='dep'>部门</Form.Select.Option>
<Form.Select.Option value='number'>编号</Form.Select.Option>
<Form.Select.Option value='name'>姓名</Form.Select.Option>
</Form.Select>
<Form.Input
suffix={<IconSearch />}
field="keyword"
pure
showClear
style={{ width: 346, marginLeft: 12, marginRight: 12 }}
placeholder="请输入或选择关键词"
/>
<Form.DatePicker
label='时间范围:'
initValue={[moment(new Date()).add(-1, 'y').format('YYYY-MM-DD'), moment(new Date()).format('YYYY-MM-DD')]}
field='entryTime' type="dateRange" density="compact" showClear style={{ width: 370, color: "#F9F9F9" }} />
</div>
<div style={{ display: 'flex', alignItems: 'center' }}>
<div style={{ width: 20, height: 20, cursor: "pointer", marginRight: 15 }}
onClick={() => {
let obj = form.current.getValues()
if (form.current.getValues().entryTime?.length > 1) {
obj.startDate = moment(form.current.getValues().entryTime[0]).format('YYYY-MM-DD')
obj.endDate = moment(form.current.getValues().entryTime[1]).format('YYYY-MM-DD')
}
else {
obj.startDate = ''
obj.endDate = ''
}
setDownloadUrl(`attendance/vacate/export?token=${user.token}&keywordTarget=${obj.keywordTarget ? obj.keywordTarget : ''}&keyword=${obj.keyword ? obj.keyword : ''}&startDate=${obj.startDate}&endDate=${obj.endDate}&limit=${query.limit}&page=${query.page}}`)
}}>
<img src="/assets/images/hrImg/export.png" alt="" style={{ width: '100%', height: '100%' }} />
{
downloadUrl ? <iframe src={`/_api/${downloadUrl}`} style={{ display: 'none' }} /> : ''
}
</div>
<img src="/assets/images/hrImg/newsetup.png" alt="" style={{ width: 20, height: 20, cursor: "pointer", marginRight: 15 }}
onClick={() => setSetup(true)}
/>
<Button theme='solid' type='primary' style={{ width: 80, borderRadius: 2, height: 32, background: '#DBECFF', color: '#005ABD' }}
onClick={() => {
setLookup(form.current.getValues())
setQuery({ limit: 10, page: 0 })
}}>查询</Button>
</div>
</div>
</div>
</Form>
<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={setupp.filter((s) => s)}
dataSource={archivesList}
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 == 'vacateCount') {
if (sorter.sortOrder == 'descend') {
setOrder({ orderBy: 'vacateCount', orderDirection: 'DESC' })
} else {
setOrder({ orderBy: 'vacateCount', orderDirection: 'ASC' })
}
} else {
if (sorter.sortOrder == 'descend') {
setOrder({ orderBy: 'vacateSum', orderDirection: 'DESC' })
} else {
setOrder({ orderBy: 'vacateSum', 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
className="22"
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>
</div>
{setup ? (
<Setup
tableType={LEAVESTATISTICS}
tableList={tableList}
length={5 + mytypeList.length}
close={() => {
setSetup(false);
attribute(mytypeList);
}}
/>
) : (
""
)}
</>
)
}
function mapStateToProps (state) {
const { auth, global, MemberSearch, webSocket } = state;
return {
// loading: members.isRequesting,
user: auth.user,
actions: global.actions,
xqMembers: MemberSearch.data,
// socket: webSocket.socket
};
}
export default connect(mapStateToProps)(leaveStatistics);