package com.ruoyi.performance.service.impl;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.util.concurrent.AtomicDouble;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.domain.entity.User;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.performance.dto.PerformanceShiftAddDto;
import com.ruoyi.performance.dto.PerformanceShiftMapDto;
import com.ruoyi.performance.dto.StaffAttendanceDTO;
import com.ruoyi.performance.excel.PerformanceShiftAnnotationTextExcelData;
import com.ruoyi.performance.excel.PerformanceShiftExcelData;
import com.ruoyi.performance.excel.handler.performance.CommentWriteHandler;
import com.ruoyi.performance.mapper.PerformanceShiftMapper;
import com.ruoyi.performance.pojo.PerformanceShift;
import com.ruoyi.performance.pojo.StaffAttendanceTrackingRecord;
import com.ruoyi.performance.service.PerformanceShiftService;
import com.ruoyi.performance.service.StaffAttendanceTrackingRecordService;
import com.ruoyi.performance.vo.StaffAttendanceVO;
import com.ruoyi.system.mapper.UserMapper;
import com.ruoyi.system.service.ISysDictTypeService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.ibatis.annotations.Param;
import org.apache.poi.ss.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
/**
*
* 绩效管理-班次 服务实现类
*
*
* @author 江苏鵷雏网络科技有限公司
* @since 2024-05-08 09:12:04
*/
@Slf4j
@Service
public class PerformanceShiftServiceImpl extends ServiceImpl implements PerformanceShiftService {
@Autowired
private StaffAttendanceTrackingRecordService trackingRecordService;
@Autowired
UserMapper userMapper;
private DateTimeFormatter yyyyMMdd = DateTimeFormatter.ofPattern("yyyy-MM-dd");
private DateTimeFormatter yyyyMMddHHmmss = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private DateTimeFormatter yyyMMStr = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
private final int LIST_MAX_COUNT = 1000;
private static final String morningShiftKeyword = "早";//早班班次关键字
private static final String dayShiftKeyword = "中";//中班班次关键字
private static final String nightShiftKeyword = "夜";//夜班班次关键字
private static final String holidayLeaveKeyword = "休";//休假,调休假班次关键字
private static final String officialTripKeyword = "公";//公差班次关键字
private static final String personalLeaveKeyword = "事";//事假班次关键字
private static final String sickLeaveKeyword = "病";//病假班次关键字
private static final String annualLeaveKeyword = "年";//年假班次关键字
private static final String marriageLeaveKeyword = "婚";//婚假班次关键字
private static final String maternityLeaveKeyword = "产";//产假班次关键字
private static final String bereavementLeaveKeyword = "丧";//丧假班次关键字
private static final List shiftSoreList = Arrays.asList("早","中","夜","休","公","事","病","年","婚","产","丧");
@Transactional(rollbackFor = Exception.class)
@Override
public void performanceShiftAdd(PerformanceShiftAddDto performanceShiftAddDto) {
//1.查询所选周次时间范围内已排班的数据
List shiftList = baseMapper.selectList(Wrappers.lambdaQuery()
.between(ObjectUtils.allNotNull(performanceShiftAddDto.getStartTime(), performanceShiftAddDto.getEndTime()),
PerformanceShift::getWorkTime, performanceShiftAddDto.getStartTime(), performanceShiftAddDto.getEndTime())
.in(!performanceShiftAddDto.getUserIdList().isEmpty(), PerformanceShift::getUserId, performanceShiftAddDto.getUserIdList())
);
List timeList = getLocalDateTimesBetween(performanceShiftAddDto.getStartTime(), performanceShiftAddDto.getEndTime());
//处理选中人员
List newShiftList = new ArrayList<>();
performanceShiftAddDto.getUserIdList().forEach(userId->{
List oldShifts = shiftList.stream().filter(f -> Objects.equals(f.getUserId(), userId)).collect(Collectors.toList());
timeList.forEach(time->{
PerformanceShift performanceShift = oldShifts.stream().filter(f -> f.getWorkTime().isEqual(time)).findFirst().orElse(new PerformanceShift(userId, time));
if(Objects.isNull(performanceShift.getId())||StringUtils.isBlank(performanceShift.getShift())){
performanceShift.setShift(performanceShiftAddDto.getShift());
newShiftList.add(performanceShift);
}
});
if(newShiftList.size()>LIST_MAX_COUNT){
this.saveBatch(newShiftList);
newShiftList.clear();
}
});
if(!newShiftList.isEmpty())this.saveOrUpdateBatch(newShiftList);
}
private List saveMonth (LocalDateTime week,String userId,List list){
LocalDate firstDayOfMonth = week.toLocalDate().withDayOfMonth(1);
LocalDate lastDayOfMonth = week.toLocalDate().with(TemporalAdjusters.lastDayOfMonth());
List localDateTimesBetween = getLocalDateTimesBetween(firstDayOfMonth.atStartOfDay(), lastDayOfMonth.atStartOfDay());
localDateTimesBetween.forEach(i -> {
PerformanceShift performanceShift = new PerformanceShift();
performanceShift.setUserId(Integer.valueOf(userId));
performanceShift.setWorkTime(i);
performanceShift.setShift("");
list.add(performanceShift);
if (list.size() >= 1000) {
baseMapper.insertBatchSomeColumn(list);
list.clear();
}
});
return list;
}
@Override
public Map performanceShift( String time, String userName, String laboratory) {
//查询人员架构
List userList = userMapper.selectUserListByPerformance(false);
List userIdList = userList.stream().map(User::getId).collect(Collectors.toList());
//班次时间范围为上个月的26号到本月的25号
LocalDateTime localDateTime = LocalDateTime.parse(time, yyyyMMddHHmmss);
LocalDate firstDayOfMonth = localDateTime.toLocalDate().minusMonths(1L).withDayOfMonth(26);
LocalDate lastDayOfMonth = localDateTime.toLocalDate().withDayOfMonth(25);
//人员排班详情
List mapIPage = baseMapper.performanceShift(firstDayOfMonth,lastDayOfMonth, userName, laboratory);
Map> groupByUserId = mapIPage.stream().collect(Collectors.groupingBy(PerformanceShiftMapDto::getUserId));
List newRecords = new ArrayList<>();
List timeList = getLocalDateTimesBetween(LocalDateTime.of(firstDayOfMonth, LocalTime.MIN), LocalDateTime.of(lastDayOfMonth, LocalTime.MIN));
groupByUserId.keySet().forEach(key->{
PerformanceShiftMapDto shiftMapDto = new PerformanceShiftMapDto();
List shiftMapDtos = groupByUserId.get(key);
List newShiftMapDtos = new ArrayList<>();
timeList.forEach(t->{
PerformanceShiftMapDto mapDto = shiftMapDtos.stream().filter(s -> t.isEqual(s.getWorkTime())).findFirst().orElse(null);
if(ObjectUtils.isNotEmpty(mapDto)){
newShiftMapDtos.add(mapDto);
}else{
newShiftMapDtos.add(null);
}
});
//统计各班次天数
Map countShift = countShift(shiftMapDtos);
shiftMapDto.setMonthlyAttendance(countShift);
shiftMapDto.setMonthlyAttendanceStr(formateMap(countShift));
shiftMapDto.setList(newShiftMapDtos);
shiftMapDto.setUserName(shiftMapDtos.isEmpty()?"":shiftMapDtos.get(0).getUserName());
shiftMapDto.setUserId(key);
newRecords.add(shiftMapDto);
});
newRecords.sort(Comparator.comparing(r->userIdList.indexOf(r.getUserId())));
Map resultMap = new HashMap<>();
resultMap.put("page", newRecords);
resultMap.put("headerList", getYearHeaderTimeList(firstDayOfMonth,lastDayOfMonth));
return resultMap;
}
public String formateMap(Map map){
List stringList = new ArrayList<>();
map.forEach((k,v)->{
if(shiftSoreList.contains(k)){
stringList.add(k+":"+v);
}
});
return String.join(",",stringList);
}
/**
* 统计班次
* @param shiftMapDtos 班次列表
*/
private Map countShift(List shiftMapDtos){
TreeMap targetMap = new TreeMap<>(Comparator.comparing(shiftSoreList::indexOf));
//汇总早班、中班、夜班、休息、请假、出差的天数,以及总出勤天数
Map groupByShiftName = shiftMapDtos.stream().filter(f-> StringUtils.isNotBlank(f.getShiftName())).collect(Collectors.groupingBy(PerformanceShiftMapDto::getShiftName,Collectors.counting()));
AtomicLong morningShiftCount = new AtomicLong(0);//早班
AtomicLong dayShiftCount = new AtomicLong(0);//中班
AtomicLong nightShiftCount = new AtomicLong(0);//晚班
AtomicLong holidayShiftCount = new AtomicLong(0);//休
AtomicLong totalCount = new AtomicLong(0);//总出勤天数
groupByShiftName.keySet().forEach(key->{
if(key.contains(morningShiftKeyword)){
morningShiftCount.getAndAdd(groupByShiftName.get(key));
totalCount.getAndAdd(groupByShiftName.get(key));
}else if(key.contains(dayShiftKeyword)){
dayShiftCount.getAndAdd(groupByShiftName.get(key));
totalCount.getAndAdd(groupByShiftName.get(key));
}else if(key.contains(nightShiftKeyword)){
nightShiftCount.getAndAdd(groupByShiftName.get(key));
totalCount.getAndAdd(groupByShiftName.get(key));
}else if(key.contains(holidayLeaveKeyword)){
holidayShiftCount.getAndAdd(groupByShiftName.get(key));
}else if(key.contains(officialTripKeyword)){
targetMap.put(key,groupByShiftName.get(key));
totalCount.getAndAdd(groupByShiftName.get(key));
}else{
targetMap.put(key,groupByShiftName.get(key));
}
});
targetMap.put("早",morningShiftCount.get());
targetMap.put("中",dayShiftCount.get());
targetMap.put("夜",nightShiftCount.get());
targetMap.put("休",holidayShiftCount.get());
targetMap.put("totalCount",totalCount.get());
return targetMap;
}
/**
* 班次分页查询:获取月度日期表头列表
* @param firstDayOfMonth
* @param lastDayOfMonth
* @return
*/
private List