|
|
|
@ -179,19 +179,102 @@ public class ClockinServiceImpl implements IClockinService { |
|
|
|
public Result<?> clockInTotal(ClockInTotalReq clockInTotalReq) { |
|
|
|
Map<String, Object> map = new HashMap<>(); |
|
|
|
HanHaiMember hanHaiMember = shiroRealm.checkUserTokenIsEffectHanHaiAccount(clockInTotalReq.getToken()); |
|
|
|
ClockinTeamLog clockinTeamLog = clockinTeamLogService.lambdaQuery() |
|
|
|
.eq(ClockinTeamLog::getDelFlag, 0) |
|
|
|
.eq(ClockinTeamLog::getUserId, hanHaiMember.getId()) |
|
|
|
.one(); |
|
|
|
ClockInProject clockInProject = clockInProjectService.lambdaQuery() |
|
|
|
.eq(ClockInProject::getDelFlag, 0) |
|
|
|
.eq(ClockInProject::getTeamId, clockinTeamLog.getTeamId()) |
|
|
|
.one(); |
|
|
|
|
|
|
|
|
|
|
|
// 解析日期参数,获取月份信息 |
|
|
|
Date date = new Date(); |
|
|
|
if(StringUtils.isNotBlank(clockInTotalReq.getDate())){ |
|
|
|
date = DateUtils2.getDate(clockInTotalReq.getDate()); |
|
|
|
} |
|
|
|
|
|
|
|
// 计算当月的开始日期和结束日期 |
|
|
|
Date monthStartDate = DateUtils2.beforeXFirstDayOfMonth(date); // 当月第一天 00:00:00 |
|
|
|
Date monthEndDate = DateUtils2.currentXDayOfMonth(date); // 当月最后一天 23:59:59 |
|
|
|
|
|
|
|
// 从用户在该月份的打卡记录中获取项目ID |
|
|
|
List<ClockinLog> monthClockinLogList = clockinLogService.lambdaQuery() |
|
|
|
.eq(ClockinLog::getDelFlag, 0) |
|
|
|
.eq(ClockinLog::getUserId, hanHaiMember.getId()) |
|
|
|
.ge(ClockinLog::getClockInTime, monthStartDate) |
|
|
|
.le(ClockinLog::getClockInTime, monthEndDate) |
|
|
|
.list(); |
|
|
|
|
|
|
|
if(monthClockinLogList == null || monthClockinLogList.isEmpty()){ |
|
|
|
// 如果该月份没有打卡记录,返回空数据 |
|
|
|
map.put("date", new ArrayList<>()); |
|
|
|
map.put("normal", 0); |
|
|
|
map.put("noCard", 0); |
|
|
|
map.put("abnormal", 0); |
|
|
|
return Result.OK(map); |
|
|
|
} |
|
|
|
|
|
|
|
// 从打卡记录中提取项目ID(去重) |
|
|
|
Set<String> projectIdSet = new HashSet<>(); |
|
|
|
for(ClockinLog log : monthClockinLogList){ |
|
|
|
if(StringUtils.isNotBlank(log.getProjectId())){ |
|
|
|
projectIdSet.add(log.getProjectId()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if(projectIdSet.isEmpty()){ |
|
|
|
// 如果没有有效的项目ID,返回空数据 |
|
|
|
map.put("date", new ArrayList<>()); |
|
|
|
map.put("normal", 0); |
|
|
|
map.put("noCard", 0); |
|
|
|
map.put("abnormal", 0); |
|
|
|
return Result.OK(map); |
|
|
|
} |
|
|
|
|
|
|
|
// 根据项目ID直接查询项目信息 |
|
|
|
List<ClockInProject> clockInProjectList = clockInProjectService.lambdaQuery() |
|
|
|
.eq(ClockInProject::getDelFlag, 0) |
|
|
|
.in(ClockInProject::getId, projectIdSet) |
|
|
|
.list(); |
|
|
|
|
|
|
|
if(clockInProjectList == null || clockInProjectList.isEmpty()){ |
|
|
|
// 如果项目不存在,返回空数据 |
|
|
|
map.put("date", new ArrayList<>()); |
|
|
|
map.put("normal", 0); |
|
|
|
map.put("noCard", 0); |
|
|
|
map.put("abnormal", 0); |
|
|
|
return Result.OK(map); |
|
|
|
} |
|
|
|
|
|
|
|
// 构建项目ID到项目的映射 |
|
|
|
Map<String, ClockInProject> projectMap = new HashMap<>(); |
|
|
|
for(ClockInProject project : clockInProjectList){ |
|
|
|
projectMap.put(project.getId(), project); |
|
|
|
} |
|
|
|
|
|
|
|
// 预先加载所有项目的时区信息,避免在循环中重复查询 |
|
|
|
Set<String> timeZoneIdSet = new HashSet<>(); |
|
|
|
for(ClockInProject project : clockInProjectList){ |
|
|
|
if(StringUtils.isNotBlank(project.getTimeZone())){ |
|
|
|
timeZoneIdSet.add(project.getTimeZone()); |
|
|
|
} |
|
|
|
} |
|
|
|
Map<String, ClockInTimeZone> timeZoneMap = new HashMap<>(); |
|
|
|
if(!timeZoneIdSet.isEmpty()){ |
|
|
|
List<ClockInTimeZone> timeZoneList = clockInTimeZoneService.lambdaQuery() |
|
|
|
.in(ClockInTimeZone::getId, timeZoneIdSet) |
|
|
|
.list(); |
|
|
|
for(ClockInTimeZone timeZone : timeZoneList){ |
|
|
|
timeZoneMap.put(timeZone.getId(), timeZone); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 将月份的打卡记录按日期分组,格式:yyyy-MM-dd -> List<ClockinLog> |
|
|
|
Map<String, List<ClockinLog>> dateLogMap = new HashMap<>(); |
|
|
|
for(ClockinLog log : monthClockinLogList){ |
|
|
|
Date clockInTime = log.getClockInTime(); |
|
|
|
if(clockInTime != null){ |
|
|
|
String dateStr = DateUtils2.getDateString(clockInTime, "yyyy-MM-dd"); |
|
|
|
dateLogMap.computeIfAbsent(dateStr, k -> new ArrayList<>()).add(log); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 用户在该月份有打卡记录 |
|
|
|
boolean hasAnyClockInRecord = true; |
|
|
|
|
|
|
|
String nowDay2 = DateUtils2.getNowDay2(DateUtils2.currentXDayOfMonth(date)); |
|
|
|
Integer n = Integer.parseInt(nowDay2); |
|
|
|
String yyyymm = DateUtils2.getYYYYMM(date); |
|
|
|
@ -203,8 +286,8 @@ public class ClockinServiceImpl implements IClockinService { |
|
|
|
//未打卡 |
|
|
|
Integer abnormal = 0; |
|
|
|
Long todayDate = DateUtils2.getTodayTwelve(); |
|
|
|
|
|
|
|
for (int i = 1;i <= n;i++){ |
|
|
|
|
|
|
|
ClockInTotalResp clockInTotalResp = new ClockInTotalResp(); |
|
|
|
String dd = i+""; |
|
|
|
if(i < 10){ |
|
|
|
@ -223,28 +306,110 @@ public class ClockinServiceImpl implements IClockinService { |
|
|
|
if(DayOfWeek.SATURDAY.equals(localDateTime.getDayOfWeek()) || DayOfWeek.SUNDAY.equals(localDateTime.getDayOfWeek())){ |
|
|
|
type = 1; |
|
|
|
} |
|
|
|
List<ClockInProjectItem> clockInProjectItemList = clockInProjectItemService.lambdaQuery() |
|
|
|
.eq(ClockInProjectItem::getDelFlag, 0) |
|
|
|
.eq(ClockInProjectItem::getType,type) |
|
|
|
.eq(ClockInProjectItem::getProjectId, clockInProject.getId()) |
|
|
|
.list(); |
|
|
|
Integer clockInTotal = clockinLogService.getClockInTotal(hanHaiMember.getId(), yyyymmdd); |
|
|
|
|
|
|
|
// 从已查询的打卡记录中获取当天的打卡记录 |
|
|
|
List<ClockinLog> clockinLogList = dateLogMap.getOrDefault(yyyymmdd, new ArrayList<>()); |
|
|
|
|
|
|
|
// 按项目分组统计打卡记录 |
|
|
|
Map<String, List<ClockinLog>> projectLogMap = new HashMap<>(); |
|
|
|
for(ClockinLog log : clockinLogList){ |
|
|
|
String projectId = log.getProjectId(); |
|
|
|
if(StringUtils.isNotBlank(projectId)){ |
|
|
|
projectLogMap.computeIfAbsent(projectId, k -> new ArrayList<>()).add(log); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 计算应该打卡的总次数和实际打卡的总次数 |
|
|
|
int totalExpectedCount = 0; // 应该打卡的总次数 |
|
|
|
int totalActualCount = clockinLogList.size(); // 实际打卡的总次数 |
|
|
|
|
|
|
|
// 遍历所有项目,确保所有项目都被统计 |
|
|
|
for(ClockInProject project : clockInProjectList){ |
|
|
|
if(StringUtils.isBlank(project.getTimeZone())){ |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
// 从缓存中获取项目的时区信息 |
|
|
|
ClockInTimeZone clockInTimeZone = timeZoneMap.get(project.getTimeZone()); |
|
|
|
if(clockInTimeZone == null){ |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
// 根据项目时区判断该日期是工作日还是周末 |
|
|
|
try { |
|
|
|
// 将日期转换为项目时区的日期时间 |
|
|
|
LocalDateTime dateTime = LocalDateTime.of( |
|
|
|
localDateTime.getYear(), |
|
|
|
localDateTime.getMonthValue(), |
|
|
|
localDateTime.getDayOfMonth(), |
|
|
|
0, 0, 0 |
|
|
|
); |
|
|
|
ZonedDateTime systemZonedDateTime = dateTime.atZone(ZoneId.systemDefault()); |
|
|
|
ZonedDateTime projectZonedDateTime = systemZonedDateTime.withZoneSameInstant(ZoneId.of(clockInTimeZone.getTimeZone())); |
|
|
|
LocalDateTime projectLocalDateTime = projectZonedDateTime.toLocalDateTime(); |
|
|
|
|
|
|
|
Integer projectType = 0; |
|
|
|
DayOfWeek dayOfWeek = projectLocalDateTime.getDayOfWeek(); |
|
|
|
if(DayOfWeek.SATURDAY.equals(dayOfWeek) || DayOfWeek.SUNDAY.equals(dayOfWeek)){ |
|
|
|
projectType = 1; |
|
|
|
} |
|
|
|
|
|
|
|
// 获取该项目在这一天应该打卡的次数 |
|
|
|
List<ClockInProjectItem> clockInProjectItemList = clockInProjectItemService.lambdaQuery() |
|
|
|
.eq(ClockInProjectItem::getDelFlag, 0) |
|
|
|
.eq(ClockInProjectItem::getType, projectType) |
|
|
|
.eq(ClockInProjectItem::getProjectId, project.getId()) |
|
|
|
.list(); |
|
|
|
|
|
|
|
totalExpectedCount += clockInProjectItemList.size(); |
|
|
|
} catch (Exception e) { |
|
|
|
log.error("处理项目时区失败, projectId: {}, timeZone: {}", project.getId(), project.getTimeZone(), e); |
|
|
|
// 如果时区转换失败,使用系统时区的类型 |
|
|
|
List<ClockInProjectItem> clockInProjectItemList = clockInProjectItemService.lambdaQuery() |
|
|
|
.eq(ClockInProjectItem::getDelFlag, 0) |
|
|
|
.eq(ClockInProjectItem::getType, type) |
|
|
|
.eq(ClockInProjectItem::getProjectId, project.getId()) |
|
|
|
.list(); |
|
|
|
totalExpectedCount += clockInProjectItemList.size(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
clockInTotalResp.setDate(yyyymmdd); |
|
|
|
|
|
|
|
if(clockInTotal == 0){// 2未打卡 |
|
|
|
|
|
|
|
abnormal = abnormal+1; |
|
|
|
|
|
|
|
clockInTotalResp.setType(2); |
|
|
|
}else if(clockInTotal<clockInProjectItemList.size()){ |
|
|
|
|
|
|
|
// 如果用户在这一天没有任何打卡记录,判断是否为未打卡 |
|
|
|
if(totalActualCount == 0){ |
|
|
|
// 如果用户有打卡记录(在其他日期),且应该打卡次数大于0,则认为未打卡 |
|
|
|
if(hasAnyClockInRecord && totalExpectedCount > 0){ |
|
|
|
abnormal = abnormal+1; |
|
|
|
clockInTotalResp.setType(2); |
|
|
|
clockInTotalResp.setNum(totalExpectedCount); |
|
|
|
clockInTotalResps.add(clockInTotalResp); |
|
|
|
} else if(totalExpectedCount == 0){ |
|
|
|
// 如果不需要打卡,跳过这一天的统计 |
|
|
|
continue; |
|
|
|
} else { |
|
|
|
abnormal = abnormal+1; |
|
|
|
clockInTotalResp.setType(2); |
|
|
|
clockInTotalResp.setNum(totalExpectedCount); |
|
|
|
clockInTotalResps.add(clockInTotalResp); |
|
|
|
} |
|
|
|
} else if(totalExpectedCount == 0){ |
|
|
|
// 如果有打卡记录但没有应该打卡的次数(可能是数据异常),标记为正常 |
|
|
|
clockInTotalResp.setType(0); |
|
|
|
normal = normal+1; |
|
|
|
clockInTotalResp.setNum(0); |
|
|
|
clockInTotalResps.add(clockInTotalResp); |
|
|
|
} else if(totalActualCount < totalExpectedCount){ |
|
|
|
clockInTotalResp.setType(1); |
|
|
|
noCard = noCard+1; |
|
|
|
}else{//0正常 |
|
|
|
clockInTotalResp.setNum(totalExpectedCount - totalActualCount); |
|
|
|
clockInTotalResps.add(clockInTotalResp); |
|
|
|
} else { |
|
|
|
clockInTotalResp.setType(0); |
|
|
|
normal = normal+1; |
|
|
|
clockInTotalResp.setNum(0); |
|
|
|
clockInTotalResps.add(clockInTotalResp); |
|
|
|
} |
|
|
|
clockInTotalResp.setNum(clockInProjectItemList.size()-clockInTotal); |
|
|
|
clockInTotalResps.add(clockInTotalResp); |
|
|
|
} |
|
|
|
map.put("date",clockInTotalResps); |
|
|
|
map.put("normal",normal); |
|
|
|
|