@ -21,9 +21,11 @@ import cn.iocoder.yudao.module.system.dal.dataobject.attendance.group.Attendance
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupshift.AttendanceGroupShiftDO ;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupshiftitem.AttendanceGroupShiftItemDO ;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.punchrecord.AttendancePunchRecordDO ;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO ;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO ;
import cn.iocoder.yudao.module.system.dal.mysql.attendance.group.AttendanceGroupMapper ;
import cn.iocoder.yudao.module.system.dal.mysql.attendance.punchrecord.AttendancePunchRecordMapper ;
import cn.iocoder.yudao.module.system.dal.mysql.dept.PostMapper ;
import cn.iocoder.yudao.module.system.handler.PunchHandler ;
import cn.iocoder.yudao.module.system.service.attendance.group.AttendanceGroupService ;
import cn.iocoder.yudao.module.system.service.attendance.groupshift.AttendanceGroupShiftService ;
@ -34,6 +36,7 @@ import cn.iocoder.yudao.module.system.service.attendance.punch.dto.AttendanceOnT
import cn.iocoder.yudao.module.system.service.attendance.punchrecord.AttendancePunchRecordService ;
import cn.iocoder.yudao.module.system.service.user.AdminUserService ;
import com.alibaba.excel.EasyExcel ;
import com.alibaba.excel.support.ExcelTypeEnum ;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper ;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper ;
import lombok.extern.slf4j.Slf4j ;
@ -44,6 +47,9 @@ import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource ;
import javax.servlet.http.HttpServletResponse ;
import java.io.IOException ;
import java.net.URLEncoder ;
import java.nio.charset.StandardCharsets ;
import java.time.LocalDateTime ;
import java.time.ZoneId ;
import java.time.format.DateTimeFormatter ;
@ -85,6 +91,8 @@ public class AttendanceServiceImpl implements AttendanceService {
private AttendanceGroupMapper attendanceGroupMapper ;
@Resource
private AttendanceGroupUserService attendanceGroupUserService ;
@Resource
private PostMapper postMapper ;
/ / 定义一些常量以提高代码的可读性和可维护性
@ -608,7 +616,6 @@ public class AttendanceServiceImpl implements AttendanceService {
@Override
public TeamAttendanceStatisticsByCycleVO tesmStatisticsByCycle ( TeamAttendanceStatisticsByCycleDTO dto ) {
TeamAttendanceStatisticsByCycleVO vo = new TeamAttendanceStatisticsByCycleVO ( ) ;
TeamAttendanceStatisticsByCycleVO . TeamAttendanceStatisticsNumVO teamAttendanceStatisticsNumVO = new TeamAttendanceStatisticsByCycleVO . TeamAttendanceStatisticsNumVO ( ) ;
/ / 查询考勤组
AttendanceGroupDO attendanceGroupDO = attendanceGroupService . getGroup ( dto . getGroupId ( ) ) ;
/ / - 判断当前用户是否有权限查看
@ -792,11 +799,189 @@ public class AttendanceServiceImpl implements AttendanceService {
} else {
userList = adminUserService . getAllList ( CommonStatusEnum . ENABLE . getStatus ( ) , null , dto . getTargetIds ( ) ) ;
}
/ / - - 统计
List < String > dateList = DateUtils . betweenDayList ( dto . getStartTime ( ) , dto . getEndTime ( ) ) ;
if ( dto . getType ( ) = = 1 ) {
this . monthlyStatistics ( response , userList , dateList ) ;
String hh_mm = LocalDateTime . now ( ) . format ( DateTimeFormatter . ofPattern ( " HH:mm " ) ) ;
String first = CollectionUtil . getFirst ( dateList ) ;
String last = CollectionUtil . getLast ( dateList ) ;
/ / 查询出数据 - - 时间周期 - 用户列表
List < AttendancePunchRecordDO > list = attendancePunchRecordMapper . statistics ( userList . stream ( ) . map ( AdminUserDO : : getId ) . collect ( Collectors . toList ( ) ) , dateList ) ;
/ / 获取用户列表
Map < Long , AdminUserDO > userMap = new HashMap < > ( ) ;
if ( CollectionUtil . isNotEmpty ( userList ) ) {
userMap = userList . stream ( ) . collect ( Collectors . toMap ( AdminUserDO : : getId , Function . identity ( ) ) ) ;
}
List < PostDO > userPostList = postMapper . selectList ( ) ;
/ / 根据id分组
Map < Long , PostDO > postMap = userPostList . stream ( ) . collect ( Collectors . toMap ( PostDO : : getId , Function . identity ( ) ) ) ;
if ( dto . getType ( ) = = 1 ) {
String headTitle = String . format ( " 月度汇总 统计日期:%s 至 %s " , first , last ) ;
String detailedHead = String . format ( " 月度汇总 统计日期:%s 至 %s %s " , first , last , hh_mm ) ;
this . monthlyStatistics ( response , userList , dateList , headTitle , detailedHead , list ) ;
} else {
String headTitle = String . format ( " 每日统计 统计日期:%s 至 %s " , first , last ) ;
String detailedHead = String . format ( " 报表生成时间:%s %s " , last , hh_mm ) ;
this . dayStatistics ( response , userMap , postMap , dateList , headTitle , detailedHead , list ) ;
}
}
/ * *
* 按日导出
*
* @param response
* @param userMap
* @param postMap
* @param dateList
* @param headTitle
* @param detailedHead
* @param list
* /
private void dayStatistics ( HttpServletResponse response , Map < Long , AdminUserDO > userMap , Map < Long , PostDO > postMap , List < String > dateList , String headTitle , String detailedHead , List < AttendancePunchRecordDO > list ) {
List < List < String > > data = new ArrayList < > ( ) ;
/ / - - 根据部门分组 - 根据考勤组分组
Map < Long , List < AttendancePunchRecordDO > > userPunchMap = list . stream ( ) . collect ( Collectors . groupingBy ( AttendancePunchRecordDO : : getUserId ) ) ;
/ / - - 先计算下要循环几次 - 一个用户一个部门一个考勤组一个班次一个日期 最大的打卡次数 -
Map < String , List < AttendancePunchRecordDO > > map = list . stream ( ) . collect ( Collectors . groupingBy (
a - > a . getUserId ( ) + " _ "
+ a . getDeptId ( ) + " _ "
+ a . getAttendanceGroupId ( ) + " _ "
+ a . getAttendanceGroupShiftId ( ) + " _ "
+ a . getDayTime ( ) ) ) ;
int maxSize = map . values ( ) . stream ( ) . mapToInt ( List : : size ) . max ( ) . orElse ( 0 ) ;
/ / - - 如果膜2大于0
maxSize = ( maxSize % 2 ) > 0 ? maxSize / 2 + 1 : maxSize / 2 ;
/ / 先根据人员分组 - 再根据部门分组 - 再根据考勤组分组 - 再根据日期分组
long time = System . currentTimeMillis ( ) ;
for ( Map . Entry < Long , List < AttendancePunchRecordDO > > entry : userPunchMap . entrySet ( ) ) {
AdminUserDO adminUserDO = userMap . get ( entry . getKey ( ) ) ;
List < String > postNames = this . getPostNames ( adminUserDO , postMap ) ;
Map < Long , List < AttendancePunchRecordDO > > deptMap = entry . getValue ( ) . stream ( ) . collect ( Collectors . groupingBy ( AttendancePunchRecordDO : : getDeptId ) ) ;
for ( Map . Entry < Long , List < AttendancePunchRecordDO > > deptEntry : deptMap . entrySet ( ) ) {
Map < Long , List < AttendancePunchRecordDO > > groupMap = deptEntry . getValue ( ) . stream ( ) . collect ( Collectors . groupingBy ( AttendancePunchRecordDO : : getAttendanceGroupId ) ) ;
for ( Map . Entry < Long , List < AttendancePunchRecordDO > > groupEntry : groupMap . entrySet ( ) ) {
/ / 按日期分组
Map < String , List < AttendancePunchRecordDO > > dayMap = groupEntry . getValue ( ) . stream ( ) . collect ( Collectors . groupingBy ( AttendancePunchRecordDO : : getDayTime , TreeMap : : new , Collectors . toList ( ) ) ) ;
for ( String dateStr : dateList ) {
List < AttendancePunchRecordDO > items = dayMap . get ( dateStr ) ;
Map < Long , List < AttendancePunchRecordDO > > groupShiftMap = new HashMap < > ( ) ;
if ( CollectionUtil . isNotEmpty ( items ) ) {
groupShiftMap = items . stream ( ) . collect ( Collectors . groupingBy ( AttendancePunchRecordDO : : getAttendanceGroupShiftId ) ) ;
} else {
groupShiftMap . put ( - 1L , Collections . emptyList ( ) ) ;
}
for ( Map . Entry < Long , List < AttendancePunchRecordDO > > groupShiftEntry : groupShiftMap . entrySet ( ) ) {
List < String > row = new ArrayList < > ( ) ;
row . add ( adminUserDO . getNickname ( ) ) ;
row . add ( groupEntry . getValue ( ) . get ( 0 ) . getAttendanceGroupName ( ) ) ;
row . add ( groupEntry . getValue ( ) . get ( 0 ) . getDeptName ( ) ) ;
row . add ( String . join ( " / " , postNames ) ) ;
row . add ( dateStr ) ;
row . add ( CollectionUtil . isEmpty ( groupShiftEntry . getValue ( ) ) ? " 休息 " : groupShiftEntry . getValue ( ) . get ( 0 ) . getAttendanceGroupShiftName ( ) ) ;
Map < Long , List < AttendancePunchRecordDO > > workMap = groupShiftEntry . getValue ( ) . stream ( ) . collect ( Collectors . groupingBy ( AttendancePunchRecordDO : : getAttendanceGroupShiftItemId , TreeMap : : new , Collectors . toList ( ) ) ) ;
/ / TODO : 2024 / 7 / 2 这里可能会有排序问题 具体看数据在调试
for ( Map . Entry < Long , List < AttendancePunchRecordDO > > groupShiftItemEntry : workMap . entrySet ( ) ) {
for ( AttendancePunchRecordDO attendancePunchRecordDO : groupShiftItemEntry . getValue ( ) ) {
row . add ( attendancePunchRecordDO . getPunchTime ( ) = = null ? " / " : attendancePunchRecordDO . getPunchTime ( ) . format ( Constants . FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND ) ) ;
row . add ( this . statusToStr ( attendancePunchRecordDO . getStatus ( ) ) ) ;
}
}
if ( maxSize > workMap . entrySet ( ) . size ( ) ) {
for ( int i = 0 ; i < maxSize - workMap . entrySet ( ) . size ( ) ; i + + ) {
row . add ( " / " ) ;
row . add ( " / " ) ;
row . add ( " / " ) ;
row . add ( " / " ) ;
}
}
/ / 工时
String workHour = this . calculateAverageWorkingHour ( workMap ) ;
row . add ( workHour ) ;
/ / 迟到时长
String beLate = this . calculateBeLate ( workMap ) ;
row . add ( beLate ) ;
/ / 早退时长
String leaveEarly = this . calculateEarlyDepartures ( workMap ) ;
row . add ( leaveEarly ) ;
Map < Integer , Integer > missingCardsMap = this . calculateCommuteMissingCardsList ( workMap ) ;
row . add ( missingCardsMap . get ( Constants . ZERO ) . toString ( ) ) ;
row . add ( missingCardsMap . get ( Constants . ONE ) . toString ( ) ) ;
data . add ( row ) ;
}
}
}
}
}
log . info ( " 考勤按日统计耗时:{} " , ( System . currentTimeMillis ( ) - time ) ) ;
/ / 这里 需要指定写用哪个class去写 , 然后写到第一个sheet , 名字为模板 然后文件流会自动关闭
try {
EasyExcel . write ( response . getOutputStream ( ) )
. head ( generateDailyHead ( headTitle , detailedHead , maxSize ) )
. autoCloseStream ( false )
. excelType ( ExcelTypeEnum . XLS )
. registerWriteHandler ( new CustomCellStyleHandler ( ) )
. sheet ( " 考勤统计按日导出 " )
. doWrite ( data ) ;
response . addHeader ( " Content-Disposition " , " attachment;filename= " + URLEncoder . encode ( " 考勤统计 " , StandardCharsets . UTF_8 . name ( ) ) ) ;
response . setContentType ( " application/vnd.ms-excel;charset=UTF-8 " ) ;
} catch ( IOException e ) {
throw new RuntimeException ( e ) ;
}
}
/ * *
* 获取岗位名称
*
* @param adminUserDO
* @param postMap
* @return
* /
private List < String > getPostNames ( AdminUserDO adminUserDO , Map < Long , PostDO > postMap ) {
if ( adminUserDO . getPostIds ( ) ! = null ) {
return adminUserDO . getPostIds ( ) . stream ( )
. map ( postMap : : get )
. filter ( Objects : : nonNull )
. map ( PostDO : : getName )
. collect ( Collectors . toList ( ) ) ;
}
return Collections . emptyList ( ) ;
}
/ * *
* 状态转换
*
* @param status
* @return
* /
private String statusToStr ( int status ) {
if ( status = = 0 ) {
return " 正常 " ;
} else if ( status = = 1 ) {
return " 迟到 " ;
} else if ( status = = 2 ) {
return " 早退 " ;
} else if ( status = = 3 ) {
return " 缺卡 " ;
} else if ( status = = 4 ) {
return " 未打卡 " ;
} else if ( status = = 5 ) {
return " 补卡 " ;
}
return " " ;
}
/ * *
@ -805,37 +990,104 @@ public class AttendanceServiceImpl implements AttendanceService {
* @param response
* @param userList
* @param dateList
* @param headTitle
* @param detailedHead
* @param list
* /
private void monthlyStatistics ( HttpServletResponse response , List < AdminUserDO > userList , List < String > dateList ) {
/ / 查询出数据 - - 时间周期 - 用户列表
List < AttendancePunchRecordDO > list = attendancePunchRecordMapper . selectList ( new LambdaQueryWrapper < AttendancePunchRecordDO > ( )
. in ( AttendancePunchRecordDO : : getUserId , userList )
. in ( AttendancePunchRecordDO : : getDayTime , dateList ) ) ;
private void monthlyStatistics ( HttpServletResponse response , List < AdminUserDO > userList , List < String > dateList , String headTitle , String detailedHead , List < AttendancePunchRecordDO > list ) {
List < List < String > > data = new ArrayList < > ( ) ;
/ / - - 根据部门分组 - 根据考勤组分组
Map < Long , List < AttendancePunchRecordDO > > userPunchMap = list . stream ( ) . collect ( Collectors . groupingBy ( AttendancePunchRecordDO : : getUserId ) ) ;
/ / 获取用户列表
Map < Long , AdminUserDO > userMap = new HashMap < > ( ) ;
if ( CollectionUtil . isNotEmpty ( userList ) ) {
userMap = userList . stream ( ) . collect ( Collectors . toMap ( AdminUserDO : : getId , Function . identity ( ) ) ) ;
}
List < PostDO > userPostList = postMapper . selectList ( ) ;
/ / 根据id分组
Map < Long , PostDO > postMap = userPostList . stream ( ) . collect ( Collectors . toMap ( PostDO : : getId , Function . identity ( ) ) ) ;
/ / 先根据人员分组 - 再根据部门分组 - 再根据考勤组分组 - 再根据日期分组
for ( Map . Entry < Long , List < AttendancePunchRecordDO > > entry : userPunchMap . entrySet ( ) ) {
AdminUserDO adminUserDO = userMap . get ( entry . getKey ( ) ) ;
List < String > postNames = this . getPostNames ( adminUserDO , postMap ) ;
Map < Long , List < AttendancePunchRecordDO > > deptMap = entry . getValue ( ) . stream ( ) . collect ( Collectors . groupingBy ( AttendancePunchRecordDO : : getDeptId ) ) ;
for ( Map . Entry < Long , List < AttendancePunchRecordDO > > deptEntry : deptMap . entrySet ( ) ) {
Map < Long , List < AttendancePunchRecordDO > > groupMap = deptEntry . getValue ( ) . stream ( ) . collect ( Collectors . groupingBy ( AttendancePunchRecordDO : : getAttendanceGroupId ) ) ;
for ( Map . Entry < Long , List < AttendancePunchRecordDO > > groupEntry : groupMap . entrySet ( ) ) {
CalculateNum calculateNum = new CalculateNum ( ) ;
/ / 按日期分组
Map < String , List < AttendancePunchRecordDO > > dayMap = groupEntry . getValue ( ) . stream ( ) . collect ( Collectors . groupingBy ( AttendancePunchRecordDO : : getDayTime ) ) ;
for ( Map . Entry < String , List < AttendancePunchRecordDO > > dayEntry : dayMap . entrySet ( ) ) {
/ / - - 按照班次子表分组
Map < Long , List < AttendancePunchRecordDO > > workMap = dayEntry . getValue ( ) . stream ( ) . collect ( Collectors . groupingBy ( AttendancePunchRecordDO : : getAttendanceGroupShiftItemId ) ) ;
this . calculateAverageWorkingHour ( workMap , calculateNum ) ;
/ / - - 出考勤天数
this . calculateAttendanceDays ( dayEntry . getValue ( ) , calculateNum ) ;
/ / - - 迟到
this . calculateBeLate ( workMap , calculateNum ) ;
/ / - - 早退
this . calculateEarlyDepartures ( workMap , calculateNum ) ;
/ / - - 缺卡
this . calculateCommuteMissingCardsList ( workMap , calculateNum ) ;
/ / - - 旷工
this . calculateMiner ( dayEntry . getValue ( ) , calculateNum ) ;
}
/ / 休息天数
this . calculateRestDay ( dateList , dayMap . keySet ( ) . stream ( ) . distinct ( ) . collect ( Collectors . toList ( ) ) , calculateNum ) ;
/ / 考勤总时间中文
calculateNum . setTotalWorkingHoursStr ( DateUtil . formatBetween ( calculateNum . getTotalWorkingHours ( ) , BetweenFormatter . Level . MINUTE ) ) ;
/ / 迟到总时间中文
calculateNum . setTotalLateArrivalsTimeStr ( DateUtil . formatBetween ( calculateNum . getTotalLateArrivalsTime ( ) , BetweenFormatter . Level . MINUTE ) ) ;
/ / 早退总时间中文
calculateNum . setTotalEarlyDeparturesTimeStr ( DateUtil . formatBetween ( calculateNum . getTotalEarlyDeparturesTime ( ) , BetweenFormatter . Level . MINUTE ) ) ;
List < String > row = new ArrayList < > ( ) ;
row . add ( adminUserDO . getNickname ( ) ) ;
row . add ( groupEntry . getValue ( ) . get ( 0 ) . getAttendanceGroupName ( ) ) ;
row . add ( groupEntry . getValue ( ) . get ( 0 ) . getDeptName ( ) ) ;
row . add ( String . join ( " / " , postNames ) ) ;
row . add ( String . valueOf ( calculateNum . getTotalAttendanceDays ( ) ) ) ;
row . add ( String . valueOf ( calculateNum . getTotalRestDays ( ) ) ) ;
row . add ( String . valueOf ( calculateNum . getTotalWorkingHoursStr ( ) ) ) ;
row . add ( String . valueOf ( calculateNum . getTotalLateArrivalsNumber ( ) ) ) ;
row . add ( String . valueOf ( calculateNum . getTotalLateArrivalsTimeStr ( ) ) ) ;
row . add ( String . valueOf ( calculateNum . getTotalEarlyDeparturesNumber ( ) ) ) ;
row . add ( String . valueOf ( calculateNum . getTotalEarlyDeparturesTimeStr ( ) ) ) ;
row . add ( String . valueOf ( calculateNum . getTotalUpMissingCardsNumber ( ) ) ) ;
row . add ( String . valueOf ( calculateNum . getTotalDownMissingCardsNumber ( ) ) ) ;
row . add ( String . valueOf ( calculateNum . getTotalMinerDays ( ) ) ) ;
data . add ( row ) ;
}
}
}
try {
EasyExcel . write ( response . getOutputStream ( ) )
. head ( generateHead ( headTitle , detailedHead ) )
. autoCloseStream ( false )
. excelType ( ExcelTypeEnum . XLS )
. registerWriteHandler ( new CustomCellStyleHandler ( ) )
. sheet ( " 考勤统计按月导出 " )
. doWrite ( data ) ;
response . addHeader ( " Content-Disposition " , " attachment;filename= " + URLEncoder . encode ( " 考勤统计 " , StandardCharsets . UTF_8 . name ( ) ) ) ;
response . setContentType ( " application/vnd.ms-excel;charset=UTF-8 " ) ;
} catch ( IOException e ) {
throw new RuntimeException ( e ) ;
}
}
public static void main ( String [ ] args ) {
String fileName = " /Users/aikai/Downloads/ " + System . currentTimeMillis ( ) + " .xlsx " ;
/ / 这里 需要指定写用哪个class去写 , 然后写到第一个sheet , 名字为模板 然后文件流会自动关闭
EasyExcel . write ( fileName )
. head ( generateHead ( ) )
. registerWriteHandler ( new CustomCellStyleHandler ( ) )
/ / . registerWriteHandler ( new LoopMergeStrategy ( ) )
/ / . registerWriteHandler ( loopMergeStrategy )
. sheet ( " 模板 " )
. doWrite ( generateData ( ) ) ;
}
public static List < List < String > > generateHead ( ) {
public static List < List < String > > generateHead ( String headTitle , String detailedHead ) {
List < List < String > > head = new ArrayList < > ( ) ;
String headTitle = " 月度汇总 统计日期: 2024-06-01 至 2024-06-13 " ;
String detailedHead = " 月度汇总 统计日期: 2024-06-01 至 2024-06-13 10:48 " ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 姓名 " , " 姓名 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 考勤组 " , " 考勤组 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 部门 " , " 部门 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 工号 " , " 工号 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 职位 " , " 职位 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 出勤天数 " , " 出勤天数 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 休息天数 " , " 休息天数 " ) ) ;
@ -853,70 +1105,48 @@ public class AttendanceServiceImpl implements AttendanceService {
/ / head . add ( Arrays . asList ( headTitle , detailedHead , " 加班时长-按加班规则计算 " , " 工作日加班 " ) ) ;
/ / head . add ( Arrays . asList ( headTitle , detailedHead , " 加班时长-按加班规则计算 " , " 休息日加班 " ) ) ;
/ / head . add ( Arrays . asList ( headTitle , detailedHead , " 加班时长-按加班规则计算 " , " 节假日加班 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 考勤结果 " , " 六 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 考勤结果 " , " 日 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 考勤结果 " , " 1 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 考勤结果 " , " 2 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 考勤结果 " , " 3 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 考勤结果 " , " 4 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 考勤结果 " , " 5 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 考勤结果 " , " 六 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 考勤结果 " , " 日 " ) ) ;
/ / head . add ( Arrays . asList ( headTitle , detailedHead , " 考勤结果 " , " 六 " ) ) ;
/ / head . add ( Arrays . asList ( headTitle , detailedHead , " 考勤结果 " , " 日 " ) ) ;
/ / head . add ( Arrays . asList ( headTitle , detailedHead , " 考勤结果 " , " 1 " ) ) ;
/ / head . add ( Arrays . asList ( headTitle , detailedHead , " 考勤结果 " , " 2 " ) ) ;
/ / head . add ( Arrays . asList ( headTitle , detailedHead , " 考勤结果 " , " 3 " ) ) ;
/ / head . add ( Arrays . asList ( headTitle , detailedHead , " 考勤结果 " , " 4 " ) ) ;
/ / head . add ( Arrays . asList ( headTitle , detailedHead , " 考勤结果 " , " 5 " ) ) ;
/ / head . add ( Arrays . asList ( headTitle , detailedHead , " 考勤结果 " , " 六 " ) ) ;
/ / head . add ( Arrays . asList ( headTitle , detailedHead , " 考勤结果 " , " 日 " ) ) ;
/ / 添加更多表头
return head ;
}
public static List < List < Object > > generateData ( ) {
List < List < Object > > data = new ArrayList < > ( ) ;
List < Object > row1 = new ArrayList < > ( ) ;
row1 . add ( " 艾楷 " ) ;
row1 . add ( " 测试考勤 " ) ;
row1 . add ( " " ) ;
row1 . add ( " " ) ;
row1 . add ( " " ) ;
row1 . add ( " 22026829221062585 " ) ;
row1 . add ( 1 ) ;
row1 . add ( 2 ) ;
row1 . add ( 3 ) ;
row1 . add ( 4 ) ;
row1 . add ( 5 ) ;
row1 . add ( 6 ) ;
row1 . add ( 7 ) ;
row1 . add ( 8 ) ;
row1 . add ( 9 ) ;
row1 . add ( 10 ) ;
row1 . add ( 10 ) ;
row1 . add ( 12 ) ;
/ / 添加更多数据
List < Object > row2 = new ArrayList < > ( ) ;
row2 . add ( " 谢鸿飞 " ) ;
row2 . add ( " 测试考勤 " ) ;
row2 . add ( " " ) ;
row2 . add ( " " ) ;
row2 . add ( " " ) ;
row2 . add ( " 066557433135769889 " ) ;
row2 . add ( 1 ) ;
row2 . add ( 2 ) ;
row2 . add ( 3 ) ;
row2 . add ( 4 ) ;
row2 . add ( 4 ) ;
row2 . add ( 4 ) ;
row2 . add ( 4 ) ;
row2 . add ( 4 ) ;
row2 . add ( 4 ) ;
row2 . add ( 4 ) ;
row2 . add ( 4 ) ;
row2 . add ( 4 ) ;
/ / 添加更多数据
data . add ( row1 ) ;
data . add ( row2 ) ;
return data ;
public static List < List < String > > generateDailyHead ( String headTitle , String detailedHead , int size ) {
List < List < String > > head = new ArrayList < > ( ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 姓名 " , " 姓名 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 考勤组 " , " 考勤组 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 部门 " , " 部门 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 职位 " , " 职位 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 日期 " , " 日期 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 班次 " , " 班次 " ) ) ;
for ( int i = 1 ; i < = size ; i + + ) {
head . add ( Arrays . asList ( headTitle , detailedHead , " 上班 " + i + " 打卡时间 " , " 上班 " + i + " 打卡时间 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 上班 " + i + " 打卡结果 " , " 上班 " + i + " 打卡结果 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 下班 " + i + " 打卡时间 " , " 下班 " + i + " 打卡时间 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 下班 " + i + " 打卡结果 " , " 下班 " + i + " 打卡结果 " ) ) ;
}
/ / head . add ( Arrays . asList ( headTitle , detailedHead , " 关联的审批单 " , " 关联的审批单 " ) ) ;
/ / head . add ( Arrays . asList ( headTitle , detailedHead , " 出勤天数 " , " 出勤天数 " ) ) ;
/ / head . add ( Arrays . asList ( headTitle , detailedHead , " 休息天数 " , " 休息天数 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 工作时长 " , " 工作时长 " ) ) ;
/ / head . add ( Arrays . asList ( headTitle , detailedHead , " 迟到次数 " , " 迟到次数 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 迟到时长 " , " 迟到时长 " ) ) ;
/ / head . add ( Arrays . asList ( headTitle , detailedHead , " 早退次数 " , " 早退次数 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 早退时长 " , " 早退时长 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 上班缺卡次数 " , " 上班缺卡次数 " ) ) ;
head . add ( Arrays . asList ( headTitle , detailedHead , " 下班缺卡次数 " , " 下班缺卡次数 " ) ) ;
/ / head . add ( Arrays . asList ( headTitle , detailedHead , " 旷工天数 " , " 旷工天数 " ) ) ;
return head ;
}
/ * *
* 外勤计算
*
@ -1012,6 +1242,18 @@ public class AttendanceServiceImpl implements AttendanceService {
return list ;
}
/ * *
* 休息时间计算
*
* @param dateList
* @param attendanceTime
* @param calculateNum
* @return
* /
private void calculateRestDay ( List < String > dateList , List < String > attendanceTime , CalculateNum calculateNum ) {
List < String > subtract = new ArrayList < > ( CollectionUtil . subtract ( dateList , attendanceTime ) ) ;
calculateNum . setTotalRestDays ( subtract . size ( ) ) ;
}
/ * *
* @param day
@ -1057,6 +1299,51 @@ public class AttendanceServiceImpl implements AttendanceService {
calculateNum . setTotalMissingCardsNumber ( calculateNum . getTotalMissingCardsNumber ( ) + todayMissingCardsNumber ) ;
}
private void calculateCommuteMissingCardsList ( Map < Long , List < AttendancePunchRecordDO > > workMap , CalculateNum calculateNum ) {
int todayUpMissingCardsNumber = 0 ;
int todayDownMissingCardsNumber = 0 ;
for ( Map . Entry < Long , List < AttendancePunchRecordDO > > workEntry : workMap . entrySet ( ) ) {
if ( CollectionUtil . isNotEmpty ( workEntry . getValue ( ) ) ) {
/ / - - 缺卡计算
List < AttendancePunchRecordDO > missingCardsList = workEntry . getValue ( ) . stream ( ) . filter ( a - > AttendanceOnTheDayDTO . PUNCH_STATUS_MISS . equals ( a . getStatus ( ) ) ) . collect ( Collectors . toList ( ) ) ;
if ( CollectionUtil . isNotEmpty ( missingCardsList ) ) {
long upNum = missingCardsList . stream ( ) . filter ( a - > Constants . ZERO . equals ( a . getWorkType ( ) ) ) . count ( ) ;
long downNum = missingCardsList . stream ( ) . filter ( a - > Constants . ONE . equals ( a . getWorkType ( ) ) ) . count ( ) ;
todayUpMissingCardsNumber + = upNum ;
todayDownMissingCardsNumber + = downNum ;
}
}
}
calculateNum . setTotalUpMissingCardsNumber ( calculateNum . getTotalUpMissingCardsNumber ( ) + todayUpMissingCardsNumber ) ;
calculateNum . setTotalDownMissingCardsNumber ( calculateNum . getTotalDownMissingCardsNumber ( ) + todayDownMissingCardsNumber ) ;
}
/ * *
* 迟到次数
*
* @param workMap
* /
private Map < Integer , Integer > calculateCommuteMissingCardsList ( Map < Long , List < AttendancePunchRecordDO > > workMap ) {
int todayUpMissingCardsNumber = 0 ;
int todayDownMissingCardsNumber = 0 ;
for ( Map . Entry < Long , List < AttendancePunchRecordDO > > workEntry : workMap . entrySet ( ) ) {
if ( CollectionUtil . isNotEmpty ( workEntry . getValue ( ) ) ) {
/ / - - 缺卡计算
List < AttendancePunchRecordDO > missingCardsList = workEntry . getValue ( ) . stream ( ) . filter ( a - > AttendanceOnTheDayDTO . PUNCH_STATUS_MISS . equals ( a . getStatus ( ) ) ) . collect ( Collectors . toList ( ) ) ;
if ( CollectionUtil . isNotEmpty ( missingCardsList ) ) {
long upNum = missingCardsList . stream ( ) . filter ( a - > Constants . ZERO . equals ( a . getWorkType ( ) ) ) . count ( ) ;
long downNum = missingCardsList . stream ( ) . filter ( a - > Constants . ONE . equals ( a . getWorkType ( ) ) ) . count ( ) ;
todayUpMissingCardsNumber + = upNum ;
todayDownMissingCardsNumber + = downNum ;
}
}
}
Map < Integer , Integer > map = new HashMap < > ( ) ;
map . put ( Constants . ZERO , todayUpMissingCardsNumber ) ;
map . put ( Constants . ONE , todayDownMissingCardsNumber ) ;
return map ;
}
/ * *
* 早退计算
*
@ -1111,6 +1398,20 @@ public class AttendanceServiceImpl implements AttendanceService {
calculateNum . setTotalEarlyDeparturesTime ( calculateNum . getTotalEarlyDeparturesTime ( ) + todayEarlyDeparturesTime ) ;
}
private String calculateEarlyDepartures ( Map < Long , List < AttendancePunchRecordDO > > workMap ) {
long todayEarlyDeparturesTime = 0L ;
for ( Map . Entry < Long , List < AttendancePunchRecordDO > > workEntry : workMap . entrySet ( ) ) {
if ( CollectionUtil . isNotEmpty ( workEntry . getValue ( ) ) ) {
/ / - - 早退计算
List < AttendancePunchRecordDO > earlyDeparturesList = workEntry . getValue ( ) . stream ( ) . filter ( a - > AttendanceOnTheDayDTO . PUNCH_STATUS_LEAVE_EARLY . equals ( a . getStatus ( ) ) ) . collect ( Collectors . toList ( ) ) ;
if ( CollectionUtil . isNotEmpty ( earlyDeparturesList ) ) {
todayEarlyDeparturesTime + = earlyDeparturesList . stream ( ) . mapToLong ( AttendancePunchRecordDO : : getLeaveEarlyTime ) . sum ( ) ;
}
}
}
return DateUtil . formatBetween ( todayEarlyDeparturesTime , BetweenFormatter . Level . MINUTE ) ;
}
/ * *
* 计算迟到
*
@ -1166,6 +1467,26 @@ public class AttendanceServiceImpl implements AttendanceService {
calculateNum . setTotalLateArrivalsTime ( calculateNum . getTotalLateArrivalsTime ( ) + todayLateArrivalsTime ) ;
}
/ * *
* 迟到时长
*
* @param workMap
* @return
* /
private String calculateBeLate ( Map < Long , List < AttendancePunchRecordDO > > workMap ) {
long todayLateArrivalsTime = 0L ;
for ( Map . Entry < Long , List < AttendancePunchRecordDO > > workEntry : workMap . entrySet ( ) ) {
if ( CollectionUtil . isNotEmpty ( workEntry . getValue ( ) ) ) {
/ / - - 迟到计算
List < AttendancePunchRecordDO > beLateList = workEntry . getValue ( ) . stream ( ) . filter ( a - > AttendanceOnTheDayDTO . PUNCH_STATUS_LATE . equals ( a . getStatus ( ) ) ) . collect ( Collectors . toList ( ) ) ;
if ( CollectionUtil . isNotEmpty ( beLateList ) ) {
todayLateArrivalsTime + = beLateList . stream ( ) . mapToLong ( AttendancePunchRecordDO : : getLateTime ) . sum ( ) ;
}
}
}
return DateUtil . formatBetween ( todayLateArrivalsTime , BetweenFormatter . Level . MINUTE ) ;
}
/ * *
* 计算考勤工时
*
@ -1184,6 +1505,17 @@ public class AttendanceServiceImpl implements AttendanceService {
return vo ;
}
/ * *
* 计算工时
*
* @param workMap
* @return
* /
private String calculateAverageWorkingHour ( Map < Long , List < AttendancePunchRecordDO > > workMap ) {
long todayWorkingHours = this . calculateAverageWorkingHourDay ( workMap ) ;
return DateUtil . formatBetween ( todayWorkingHours , BetweenFormatter . Level . MINUTE ) ;
}
/ * *
* 计算考勤工时
*
@ -1209,6 +1541,30 @@ public class AttendanceServiceImpl implements AttendanceService {
return todayWorkingHours ;
}
/ * *
* 计算工时 - 当天
*
* @param workMap
* @return
* /
private long calculateAverageWorkingHourDay ( Map < Long , List < AttendancePunchRecordDO > > workMap ) {
long todayWorkingHours = 0L ;
for ( Map . Entry < Long , List < AttendancePunchRecordDO > > workEntry : workMap . entrySet ( ) ) {
if ( CollectionUtil . isNotEmpty ( workEntry . getValue ( ) ) ) {
/ / - - 工时计算 - 有上班和下班两个卡 才计算到工时里面
if ( workEntry . getValue ( ) . size ( ) > = 2 ) {
AttendancePunchRecordDO first = CollectionUtil . getFirst ( workEntry . getValue ( ) ) ;
AttendancePunchRecordDO last = CollectionUtil . getLast ( workEntry . getValue ( ) ) ;
if ( ObjectUtil . isNotEmpty ( first . getPunchTime ( ) ) & & ObjectUtil . isNotEmpty ( last . getPunchTime ( ) ) ) {
long time = Math . abs ( LocalDateTimeUtil . between ( first . getPunchTime ( ) , last . getPunchTime ( ) , ChronoUnit . MILLIS ) ) ;
todayWorkingHours + = time ;
}
}
}
}
return todayWorkingHours ;
}
/ * *
* 计算出勤天数