|
|
@@ -18,7 +18,6 @@ import com.lc.ibps.cloud.provider.GenericProvider;
|
|
|
import com.lc.ibps.org.api.IPartyPositionService;
|
|
|
import com.lc.ibps.org.party.persistence.entity.PartyPositionPo;
|
|
|
import com.lc.ibps.sysdata.dao.UpdateDataTableDao;
|
|
|
-import com.lc.ibps.untils.JsonUtil;
|
|
|
import io.swagger.annotations.ApiParam;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
@@ -26,10 +25,10 @@ import org.springframework.stereotype.Service;
|
|
|
import org.springframework.web.bind.annotation.RequestBody;
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
-import java.util.ArrayList;
|
|
|
-import java.util.HashMap;
|
|
|
-import java.util.List;
|
|
|
-import java.util.Map;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.util.*;
|
|
|
+import java.time.LocalDate;
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
|
* @title: xiexh
|
|
|
@@ -38,6 +37,10 @@ import java.util.Map;
|
|
|
@Service
|
|
|
@Slf4j
|
|
|
public class SwdlServiceImpl extends GenericProvider implements SwdlService {
|
|
|
+ private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
+ private static final String REST_SHIFT = "休息";
|
|
|
+ private static final String NORMAL_STATUS = "正常";
|
|
|
+ private static final String ABNORMAL_STATUS = "异常";
|
|
|
|
|
|
@Autowired
|
|
|
UpdateDataTableDao updateDataTableDao;
|
|
|
@@ -189,7 +192,6 @@ public class SwdlServiceImpl extends GenericProvider implements SwdlService {
|
|
|
int limit = Integer.parseInt(map.get("limit").toString());
|
|
|
int startPage = limit*(pageNo-1);
|
|
|
map.put("startPage",startPage);
|
|
|
-
|
|
|
Map paramMap= getAttendanceMap(map);
|
|
|
List<Map<String,Object>> list = updateDataTableDao.selectAttendanceData(paramMap);
|
|
|
int totalCount = updateDataTableDao.selectAttendanceDataCount(paramMap);
|
|
|
@@ -218,10 +220,17 @@ public class SwdlServiceImpl extends GenericProvider implements SwdlService {
|
|
|
|
|
|
Map paramMap= getAttendanceMap(map);
|
|
|
List<Map<String,Object>> list = updateDataTableDao.selectAttendance2Data(paramMap);
|
|
|
- int totalCount = updateDataTableDao.selectAttendance2DataCount(paramMap);
|
|
|
- APIPageList<Map<String,Object>> pageList = getAPIPageList(list);
|
|
|
+ // int totalCount = updateDataTableDao.selectAttendance2DataCount(paramMap);
|
|
|
+ List<Map<String, Object>> data = calculateAttendance(list);
|
|
|
+ data = data.stream()
|
|
|
+ .sorted(Comparator.comparing(map2 -> (String) map2.get("user_id_")))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ //分页
|
|
|
+ int toIndex = Math.min(startPage + limit, data.size());
|
|
|
+ List<Map<String, Object>> pageData = getPageList(data, startPage, toIndex);
|
|
|
+ APIPageList<Map<String,Object>> pageList = getAPIPageList(pageData);
|
|
|
APIPageResult pageResult = new APIPageResult();
|
|
|
- pageResult.setTotalCount(totalCount);
|
|
|
+ pageResult.setTotalCount(data.size());
|
|
|
pageResult.setLimit(limit);
|
|
|
pageResult.setPage(pageNo);
|
|
|
pageList.setPageResult(pageResult);
|
|
|
@@ -231,6 +240,17 @@ public class SwdlServiceImpl extends GenericProvider implements SwdlService {
|
|
|
}
|
|
|
return result;
|
|
|
}
|
|
|
+
|
|
|
+ private List<Map<String, Object>> getPageList(List<Map<String, Object>> data, int fromIndex, int toIndex) {
|
|
|
+ //防止越界(如 pageNo 太大)
|
|
|
+ if (fromIndex >= data.size()) {
|
|
|
+ fromIndex = 0;
|
|
|
+ toIndex = 0;
|
|
|
+ }
|
|
|
+ List<Map<String, Object>> pagedList = data.subList(fromIndex, toIndex);
|
|
|
+ return pagedList;
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public APIResult queryClassAdjustmentList(
|
|
|
@ApiParam(name = "request", value = "传入查询请求map对象", required = true)
|
|
|
@@ -641,4 +661,258 @@ public class SwdlServiceImpl extends GenericProvider implements SwdlService {
|
|
|
}
|
|
|
return stringObjectHashMap;
|
|
|
}
|
|
|
+ public List<Map<String, Object>> calculateAttendance(List<Map<String, Object>> attendanceRecords) {
|
|
|
+ // 获取当前系统日期
|
|
|
+ String systemDate = LocalDate.now().format(DATE_FORMATTER);
|
|
|
+
|
|
|
+ // 按用户ID分组
|
|
|
+ Map<String, List<Map<String, Object>>> recordsByUser = new HashMap<>();
|
|
|
+ for (Map<String, Object> record : attendanceRecords) {
|
|
|
+ String userId = (String) record.get("user_id_");
|
|
|
+ recordsByUser.computeIfAbsent(userId, k -> new ArrayList<>()).add(record);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 存储每个用户的统计结果(改为List)
|
|
|
+ List<Map<String, Object>> resultList = new ArrayList<>();
|
|
|
+
|
|
|
+ // 遍历每个用户的考勤记录
|
|
|
+ for (Map.Entry<String, List<Map<String, Object>>> userEntry : recordsByUser.entrySet()) {
|
|
|
+ String userId = userEntry.getKey();
|
|
|
+ List<Map<String, Object>> userRecords = userEntry.getValue();
|
|
|
+
|
|
|
+ // 初始化统计指标
|
|
|
+ Map<String, Object> userStats = initUserStats(userRecords);
|
|
|
+ userStats.put("user_id_", userId); // 添加用户ID到结果中
|
|
|
+
|
|
|
+ // 按日期分组
|
|
|
+ Map<String, List<Map<String, Object>>> recordsByDate = new HashMap<>();
|
|
|
+ for (Map<String, Object> record : userRecords) {
|
|
|
+ String date = (String) record.get("ri_qi_");
|
|
|
+ recordsByDate.computeIfAbsent(date, k -> new ArrayList<>()).add(record);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 统计每个日期的数据
|
|
|
+ for (Map.Entry<String, List<Map<String, Object>>> dateEntry : recordsByDate.entrySet()) {//统计天数
|
|
|
+ String date = dateEntry.getKey();
|
|
|
+ List<Map<String, Object>> dateRecords = dateEntry.getValue();//某个日期下的多个班次数据,同时存在早班,晚班等
|
|
|
+
|
|
|
+ boolean isRestDay = false;
|
|
|
+ boolean hasAttendance = false;
|
|
|
+ boolean isNormalDay = true;
|
|
|
+ boolean isAbnormalDay = false;
|
|
|
+ boolean isAbsenteeism = false;//改天是否存在旷工班次
|
|
|
+
|
|
|
+ boolean existAttendanceDay = false;// 非休息班次标记,当天只有有一个非休息班次就统计为true
|
|
|
+ // 比较当前记录日期与系统日期
|
|
|
+ int dateCompare = date.compareTo(systemDate);
|
|
|
+ //应出勤天数过滤,一天需要出勤多个班次只统计为一天
|
|
|
+ Map shouldAttendance = new HashMap<String,Object>();
|
|
|
+ for (Map<String, Object> record : dateRecords) {//统计次数放里面
|
|
|
+ String shiftName = BeanUtils.isNotEmpty("ban_ci_ming_") ? (String) record.get("ban_ci_ming_") : "";
|
|
|
+ String status1 = BeanUtils.isNotEmpty("zhuang_tai_1_") ? (String) record.get("zhuang_tai_1_") : "";
|
|
|
+ String status2 = BeanUtils.isNotEmpty("zhuang_tai_2_") ? (String) record.get("zhuang_tai_2_") : "";
|
|
|
+ String checkIn1 = BeanUtils.isNotEmpty("da_ka_shi_jian_1_") ? (String) record.get("da_ka_shi_jian_1_") : "";
|
|
|
+ String checkIn2 = BeanUtils.isNotEmpty("da_ka_shi_jian_2_") ? (String) record.get("da_ka_shi_jian_2_") : "";
|
|
|
+ String attendanceStatus = BeanUtils.isNotEmpty("kao_qin_zhuang_ta") ? (String) record.get("kao_qin_zhuang_ta") : "";
|
|
|
+ String lateDuration ="";
|
|
|
+ String shiftDuration = "";
|
|
|
+ String workDuration ="";
|
|
|
+ if(BeanUtils.isNotEmpty(record.get("chi_dao_shi_chang"))){
|
|
|
+ lateDuration = record.get("chi_dao_shi_chang").toString();
|
|
|
+ }
|
|
|
+ if(BeanUtils.isNotEmpty(record.get("ban_ci_shi_chang_"))){
|
|
|
+ shiftDuration = record.get("ban_ci_shi_chang_").toString();
|
|
|
+ }
|
|
|
+ if(BeanUtils.isNotEmpty(record.get("gong_zuo_shi_chan"))){
|
|
|
+ workDuration = record.get("gong_zuo_shi_chan").toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 1. 应出勤天数统计(多个班次只有一个不是休息就算应出勤)
|
|
|
+ if (!REST_SHIFT.equals(shiftName) && !shouldAttendance.containsKey(date)) {
|
|
|
+ increment(userStats, "ying_chu_qin_tian_shu", 1);
|
|
|
+ shouldAttendance.put(date,1);
|
|
|
+ existAttendanceDay = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 休息天数统计
|
|
|
+ if (REST_SHIFT.equals(shiftName)) {
|
|
|
+ // increment(userStats, "xiu_xi_tian_shu", 1);
|
|
|
+ isRestDay = true;
|
|
|
+ continue; // 休息日不参与其他统计
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 实际出勤天数统计(有打卡记录)
|
|
|
+ if ((checkIn1 != null && !checkIn1.isEmpty()) ||
|
|
|
+ (checkIn2 != null && !checkIn2.isEmpty())) {
|
|
|
+ hasAttendance = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 异常次数统计(不再把旷工统计到异常里面,只有异常统计为异常)
|
|
|
+ if (dateCompare <= 0) { // 只统计今天及之前的记录
|
|
|
+ if (dateCompare < 0) {
|
|
|
+ // 历史日期
|
|
|
+ //if (status1 == null || status1.isEmpty() || ABNORMAL_STATUS.equals(status1)) {
|
|
|
+ if (ABNORMAL_STATUS.equals(status1)) {
|
|
|
+ increment(userStats, "yi_chang_ci_shu", 1);
|
|
|
+ }
|
|
|
+ //if (status2 == null || status2.isEmpty() || ABNORMAL_STATUS.equals(status2)) {
|
|
|
+ if (ABNORMAL_STATUS.equals(status2)) {
|
|
|
+ increment(userStats, "yi_chang_ci_shu", 1);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 当天日期
|
|
|
+ if (ABNORMAL_STATUS.equals(status1)) {
|
|
|
+ increment(userStats, "yi_chang_ci_shu", 1);
|
|
|
+ }
|
|
|
+ if (ABNORMAL_STATUS.equals(status2)) {
|
|
|
+ increment(userStats, "yi_chang_ci_shu", 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5. 迟到次数统计-上班异常算迟到,提前下班也算迟到(迟到/早退)
|
|
|
+ if (ABNORMAL_STATUS.equals(status1)) {
|
|
|
+ increment(userStats, "chi_dao_ci_shu", 1);
|
|
|
+ }
|
|
|
+ if (ABNORMAL_STATUS.equals(status2)) {
|
|
|
+ increment(userStats, "chi_dao_ci_shu", 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 6. 迟到时长统计
|
|
|
+ if (lateDuration != null && !lateDuration.isEmpty()) {
|
|
|
+ try {
|
|
|
+ double duration = Double.parseDouble(lateDuration);
|
|
|
+ addTo(userStats, "chi_dao_shi_chang", duration);
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ // 忽略格式错误
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 7. 旷工次数统计(只统计历史日期)
|
|
|
+ if (dateCompare < 0) {
|
|
|
+ if (checkIn1 == null || checkIn1.isEmpty()) {
|
|
|
+ increment(userStats, "kuang_gong_ci_shu", 1);
|
|
|
+ isAbsenteeism = true;
|
|
|
+ }
|
|
|
+ if (checkIn2 == null || checkIn2.isEmpty()) {
|
|
|
+ increment(userStats, "kuang_gong_ci_shu", 1);
|
|
|
+ isAbsenteeism = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 8. 班次时长统计,标准工作时长
|
|
|
+ if (shiftDuration != null && !shiftDuration.isEmpty()) {
|
|
|
+ try {
|
|
|
+ //double duration = Double.parseDouble(shiftDuration)/60;
|
|
|
+ double duration = Math.round(Double.parseDouble(shiftDuration)/60);
|
|
|
+ addTo(userStats, "ban_ci_shi_chang", duration);
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ // 忽略格式错误
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 9. 实际工作时长统计
|
|
|
+ if (workDuration != null && !workDuration.isEmpty()) {
|
|
|
+ try {
|
|
|
+ // double duration = Double.parseDouble(workDuration)/60;
|
|
|
+ double duration = Math.round(Double.parseDouble(shiftDuration)/60);
|
|
|
+ addTo(userStats, "gong_zuo_shi_chang", duration);
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ // 忽略格式错误
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 10. 正常/异常天数判断
|
|
|
+ if (dateCompare <= 0) { // 只统计今天及之前的记录
|
|
|
+ if (dateCompare < 0) {
|
|
|
+ // 历史日期
|
|
|
+ if (!NORMAL_STATUS.equals(attendanceStatus)) {
|
|
|
+ isNormalDay = false;
|
|
|
+ isAbnormalDay = true;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 当天日期
|
|
|
+ if (ABNORMAL_STATUS.equals(status1) || ABNORMAL_STATUS.equals(status2)) {
|
|
|
+ isNormalDay = false;
|
|
|
+ isAbnormalDay = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ //(当天不存在正常出勤的班次才能统计为休息)
|
|
|
+ if(!existAttendanceDay && isRestDay){
|
|
|
+ isRestDay = true;
|
|
|
+ }else{
|
|
|
+ isRestDay = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 休息天数统计
|
|
|
+ if (isRestDay) {
|
|
|
+ increment(userStats, "xiu_xi_tian_shu", 1);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 实际出勤天数统计(按日期)
|
|
|
+ if (!isRestDay && hasAttendance) {
|
|
|
+ increment(userStats, "shi_ji_chu_qin_tian_shu", 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 正常天数统计(按日期)
|
|
|
+ if (!isRestDay && isNormalDay && dateCompare <= 0) {
|
|
|
+ increment(userStats, "zheng_chang_tian_shu", 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 异常天数统计(按日期)
|
|
|
+ if (!isRestDay && isAbnormalDay && dateCompare <= 0) {
|
|
|
+ increment(userStats, "yi_chang_tian_shu", 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* //旷工天数
|
|
|
+ if(!isRestDay && existAttendanceDay && isAbsenteeism && dateCompare < 0){
|
|
|
+ increment(userStats, "kuang_gong_tian_shu", 1);
|
|
|
+ }*/
|
|
|
+ }
|
|
|
+ //异常次数需要包含旷工次数,异常天数也需要包含旷工天数
|
|
|
+ int numkgcs = (Integer) userStats.get("kuang_gong_ci_shu");
|
|
|
+ int numyccs = (Integer) userStats.get("yi_chang_ci_shu");
|
|
|
+ int yiChangCiShu = (numkgcs + numyccs);
|
|
|
+ userStats.put("yi_chang_ci_shu",yiChangCiShu);
|
|
|
+ //String yiChangTianShu = userStats.get("yi_chang_tian_shu").toString() + userStats.get("kuang_gong_tian_shu").toString();
|
|
|
+ //userStats.put("yi_chang_tian_shu",yiChangTianShu);
|
|
|
+ // 将用户统计结果添加到List中
|
|
|
+ resultList.add(userStats);
|
|
|
+ }
|
|
|
+
|
|
|
+ return resultList;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Map<String, Object> initUserStats(List<Map<String, Object>> userRecords) {
|
|
|
+ Map<String, Object> stats = new HashMap<>();
|
|
|
+ stats.put("yi_chang_ci_shu", 0);
|
|
|
+ stats.put("chi_dao_ci_shu", 0);
|
|
|
+ stats.put("chi_dao_shi_chang", 0.0);
|
|
|
+ stats.put("kuang_gong_ci_shu", 0);
|
|
|
+ stats.put("ban_ci_shi_chang", 0.0);
|
|
|
+ stats.put("gong_zuo_shi_chang", 0.0);
|
|
|
+ stats.put("ying_chu_qin_tian_shu", 0);
|
|
|
+ stats.put("shi_ji_chu_qin_tian_shu", 0);
|
|
|
+ stats.put("xiu_xi_tian_shu", 0);
|
|
|
+ stats.put("zheng_chang_tian_shu", 0);
|
|
|
+ stats.put("yi_chang_tian_shu", 0);
|
|
|
+ stats.put("user_name_",userRecords.get(0).get("user_name_"));
|
|
|
+ stats.put("pos_name_",userRecords.get(0).get("pos_name_"));
|
|
|
+ stats.put("gong_hao_",userRecords.get(0).get("gong_hao_"));
|
|
|
+ stats.put("kuang_gong_tian_shu", 0);
|
|
|
+ return stats;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void increment(Map<String, Object> stats, String key, int amount) {
|
|
|
+ int current = (int) stats.getOrDefault(key, 0);
|
|
|
+ stats.put(key, current + amount);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void addTo(Map<String, Object> stats, String key, double amount) {
|
|
|
+ double current = (double) stats.getOrDefault(key, 0.0);
|
|
|
+ stats.put(key, current + amount);
|
|
|
+ }
|
|
|
}
|