diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cailiaoshebei/service/impl/BusMaterialbatchdemandplanServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cailiaoshebei/service/impl/BusMaterialbatchdemandplanServiceImpl.java index d0f6f4e5..7e808eb3 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cailiaoshebei/service/impl/BusMaterialbatchdemandplanServiceImpl.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cailiaoshebei/service/impl/BusMaterialbatchdemandplanServiceImpl.java @@ -2,6 +2,7 @@ package org.dromara.cailiaoshebei.service.impl; import cn.hutool.core.bean.BeanUtil; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.dromara.cailiaoshebei.domain.BusCailiaoshebeiPici; import org.dromara.cailiaoshebei.domain.bo.BusMaterialbatchdemandplanAddReq; @@ -19,6 +20,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Lazy; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.context.event.EventListener; diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserAttendanceByDay.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserAttendanceByDay.java index 9035557f..472e4dd4 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserAttendanceByDay.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserAttendanceByDay.java @@ -6,6 +6,7 @@ import lombok.NoArgsConstructor; import org.dromara.project.domain.BusAttendance; import org.dromara.project.domain.enums.BusAttendanceCommuterEnum; +import java.time.LocalDateTime; import java.util.Date; import java.util.List; @@ -21,7 +22,7 @@ public class SubConstructionUserAttendanceByDay { /** * 上班打卡时间 */ - private Date upClockTime; + private LocalDateTime upClockTime; /** * 上班打卡图片id @@ -45,7 +46,7 @@ public class SubConstructionUserAttendanceByDay { /** * 下班打卡时间 */ - private Date downClockTime; + private LocalDateTime downClockTime; public static SubConstructionUserAttendanceByDay build(List attendanceList) { if (attendanceList == null) { @@ -53,12 +54,12 @@ public class SubConstructionUserAttendanceByDay { } SubConstructionUserAttendanceByDay constructionUserAttendanceByDay = new SubConstructionUserAttendanceByDay(); for (BusAttendance attendance : attendanceList) { - if (attendance.getCommuter().equals(BusAttendanceCommuterEnum.CLOCKIN.getValue())) { + if (attendance.getClockType().equals(BusAttendanceCommuterEnum.CLOCKIN.getValue())) { constructionUserAttendanceByDay.setUpClockTime(attendance.getClockTime()); if (attendance.getFacePic() != null) { constructionUserAttendanceByDay.setUpClockPicId(Long.valueOf(attendance.getFacePic())); } - } else if (attendance.getCommuter().equals(BusAttendanceCommuterEnum.CLOCKOUT.getValue())) { + } else if (attendance.getClockType().equals(BusAttendanceCommuterEnum.CLOCKOUT.getValue())) { constructionUserAttendanceByDay.setDownClockTime(attendance.getClockTime()); if (attendance.getFacePic() != null) { constructionUserAttendanceByDay.setDownClockPicId(Long.valueOf(attendance.getFacePic())); diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserAttendanceMonthVo.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserAttendanceMonthVo.java index e8bb4628..bc4f0f9f 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserAttendanceMonthVo.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserAttendanceMonthVo.java @@ -5,6 +5,7 @@ import lombok.Data; import java.io.Serial; import java.io.Serializable; +import java.time.LocalDate; import java.util.Date; /** @@ -28,7 +29,7 @@ public class SubConstructionUserAttendanceMonthVo implements Serializable { @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd", timezone = "GMT+8") - private Date clockDate; + private LocalDate clockDate; /** * 当天打卡状态 diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubConstructionUserServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubConstructionUserServiceImpl.java index 2f993bd7..7941f56d 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubConstructionUserServiceImpl.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubConstructionUserServiceImpl.java @@ -65,6 +65,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; +import java.time.LocalDate; import java.time.YearMonth; import java.util.*; import java.util.stream.Collectors; @@ -196,7 +197,7 @@ public class SubConstructionUserServiceImpl extends ServiceImpl> dateListMap = dateList.stream().collect(Collectors.groupingBy(BusAttendance::getClockDate)); + Map> dateListMap = dateList.stream().collect(Collectors.groupingBy(BusAttendance::getClockDate)); // 获取所有打卡图片id List picIds = dateList.stream().map(BusAttendance::getFacePic).filter(Objects::nonNull).map(Long::valueOf).toList(); Map> ossIdUrlMap = ossService.listByIds(picIds) @@ -224,9 +225,9 @@ public class SubConstructionUserServiceImpl extends ServiceImpl attendanceList = userIdBusAttendanceListMap.get(id); if (CollUtil.isNotEmpty(attendanceList)) { // 1. 按打卡日期分组 - Map> dailyMap = attendanceList.stream() + Map> dailyMap = attendanceList.stream() .collect(Collectors.groupingBy(BusAttendance::getClockDate)); // 2. 对每一天的记录计算状态 for (List dailyList : dailyMap.values()) { @@ -920,9 +921,9 @@ public class SubConstructionUserServiceImpl extends ServiceImpl list; + if (start.isAfter(end)) { + // 跨天情况:查询时间 >= start OR 时间 < end + list = attendanceRuleService.list(Wrappers.lambdaQuery() + .and(wrapper -> wrapper.ge(BusAttendanceRule::getClockInResultTime, start) + .or() + .lt(BusAttendanceRule::getClockInResultTime, end))); + } else { + // 非跨天情况:查询时间 >= start AND 时间 < end + list = attendanceRuleService.list(Wrappers.lambdaQuery() + .ge(BusAttendanceRule::getClockInResultTime, start) + .lt(BusAttendanceRule::getClockInResultTime, end)); + } + + //获取当前日期 + LocalDate date = LocalDate.now(); + List missList = new ArrayList<>(); + for (BusAttendanceRule rule : list) { + LocalTime clockInTime = rule.getClockInTime(); + LocalTime clockInResultTime = rule.getClockInResultTime(); + + //计算考勤日期 + if (start.isAfter(end)) { // 跨天情况 + if (!clockInResultTime.isBefore(start)) { //在前半段 23:55-00:00 + date = date.minusDays(1); + } + if (clockInResultTime.isBefore(end)) { //在后半段 00:00-05:00 + if (clockInTime.isAfter(clockInResultTime)) { + date = date.minusDays(1); + } + } + } else { + if (clockInTime.isAfter(clockInResultTime)) { + date = date.minusDays(1); + } + } + + if(checkSkip(rule,date)){ + continue; + } + + //查询项目下的关联人员 + List relevancyList = userProjectRelevancyService.list(Wrappers.lambdaQuery(BusUserProjectRelevancy.class) + .eq(BusUserProjectRelevancy::getProjectId, rule.getProjectId())); + + //查询当天已打上班卡人员 + List attendanceList = attendanceService.list(Wrappers.lambdaQuery(BusAttendance.class) + .eq(BusAttendance::getClockDate, date) + .eq(BusAttendance::getClockType, BusAttendanceCommuterEnum.CLOCKIN.getValue()) + ); + List attendanceUserIds = attendanceList.stream().map(BusAttendance::getUserId).toList(); + + + for (BusUserProjectRelevancy relevancy : relevancyList) { + + if (attendanceUserIds.contains(relevancy.getUserId())) { + continue; + } + BusAttendance busAttendance = new BusAttendance(); + //todo: 管理人员 项目id是0 + busAttendance.setProjectId(relevancy.getProjectId()); + busAttendance.setUserId(relevancy.getUserId()); + busAttendance.setClockDate(date); + busAttendance.setClockType(BusAttendanceCommuterEnum.CLOCKIN.getValue()); + busAttendance.setClockStatus(BusAttendanceClockStatusEnum.UNCLOCK.getValue()); + + missList.add(busAttendance); + } + + } + + //新增 + if (!missList.isEmpty()) { + attendanceService.saveBatch(missList); + } + } catch (Exception e) { + log.error("执行定时任务:上班缺卡记录生成异常", e); + } + log.info("执行定时任务:上班缺卡记录生成完成"); + } + + @Scheduled(cron = "0 0/10 * * * ?") + public void clockOutMiss() { + log.info("执行定时任务:下班缺卡记录生成"); + + try { + LocalTime now = LocalTime.now(); + // 计算当前窗口范围(如当前时间±5分钟) + LocalTime start = now.minusMinutes(5); + LocalTime end = now.plusMinutes(5); + + // 查询所有在窗口内的截止时间规则 + List list; + if (start.isAfter(end)) { + // 跨天情况:查询时间 >= start OR 时间 < end + list = attendanceRuleService.list(Wrappers.lambdaQuery() + .and(wrapper -> wrapper.ge(BusAttendanceRule::getClockInResultTime, start) + .or() + .lt(BusAttendanceRule::getClockOutResultTime, end))); + } else { + // 非跨天情况:查询时间 >= start AND 时间 < end + list = attendanceRuleService.list(Wrappers.lambdaQuery() + .ge(BusAttendanceRule::getClockInResultTime, start) + .lt(BusAttendanceRule::getClockInResultTime, end)); + } + + //获取当前日期 + LocalDate date = LocalDate.now(); + List missList = new ArrayList<>(); + for (BusAttendanceRule rule : list) { + + LocalTime clockOutTime = rule.getClockOutTime(); + LocalTime clockOutResultTime = rule.getClockOutResultTime(); + + //计算考勤日期 + if (start.isAfter(end)) { // 跨天情况 + if (!clockOutResultTime.isBefore(start)) { //在前半段 23:55-00:00 + date = date.minusDays(1); + } + if (clockOutResultTime.isBefore(end)) { //在后半段 00:00-05:00 + if (clockOutTime.isAfter(clockOutResultTime)) { + date = date.minusDays(1); + } + } + } else { + if (clockOutTime.isAfter(clockOutResultTime)) { + date = date.minusDays(1); + } + if (clockOutTime.isBefore(clockOutResultTime) && rule.getIsNext()) { + date = date.minusDays(1); + } + } + if(checkSkip(rule,date)){ + continue; + } + + //查询项目下的关联人员 + List relevancyList = userProjectRelevancyService.list(Wrappers.lambdaQuery(BusUserProjectRelevancy.class) + .eq(BusUserProjectRelevancy::getProjectId, rule.getProjectId())); + + //查询当天已打下班卡人员 + List attendanceList = attendanceService.list(Wrappers.lambdaQuery(BusAttendance.class) + .eq(BusAttendance::getClockDate, date) + .eq(BusAttendance::getClockType, BusAttendanceCommuterEnum.CLOCKOUT.getValue()) + ); + List attendanceUserIds = attendanceList.stream().map(BusAttendance::getUserId).toList(); + + + for (BusUserProjectRelevancy relevancy : relevancyList) { + + if (attendanceUserIds.contains(relevancy.getUserId())) { + continue; + } + BusAttendance busAttendance = new BusAttendance(); + //todo: 管理人员 项目id是0 + busAttendance.setProjectId(relevancy.getProjectId()); + busAttendance.setUserId(relevancy.getUserId()); + busAttendance.setClockDate(date); + busAttendance.setClockType(BusAttendanceCommuterEnum.CLOCKOUT.getValue()); + busAttendance.setClockStatus(BusAttendanceClockStatusEnum.UNCLOCK.getValue()); + + missList.add(busAttendance); + } + + } + + //新增 + if (!missList.isEmpty()) { + attendanceService.saveBatch(missList); + } + } catch (Exception e) { + log.error("执行定时任务:下班缺卡记录生成异常", e); + } + log.info("执行定时任务:下班缺卡记录生成完成"); + } + + /** + * 检查是否跳过 + */ + public Boolean checkSkip(BusAttendanceRule rule,LocalDate date) { + //项目异常状态 + BusProject byId = projectService.getById(rule.getProjectId()); + if (byId == null || Objects.equals(byId.getStatus(), "1")) { + return true; + } + // 获取星期几(返回DayOfWeek枚举) + DayOfWeek dayOfWeek = date.getDayOfWeek(); + // 方法2:获取数字(1=星期一,7=星期日) + int number = dayOfWeek.getValue(); + + List list = Arrays.asList(rule.getWeekday().split(",")); + if (!list.contains(String.valueOf(number))) { + return true; + } + + return false; + } +} diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/out/controller/OutMonthPlanController.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/out/controller/OutMonthPlanController.java index 243cadcc..26eb7947 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/out/controller/OutMonthPlanController.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/out/controller/OutMonthPlanController.java @@ -125,4 +125,13 @@ public class OutMonthPlanController extends BaseController { return R.ok(outMonthPlanService.isSubmit(id)); } + /** + * 获取该月份3种类型计划产值 + */ + @SaCheckPermission("out:monthPlan:query") + @GetMapping("/monthInfo") + public R> infoByPlanMonth(@NotNull(message = "项目ID不能为空") Long projectId, + @NotNull(message = "计划月份不能为空") String planMonth) { + return R.ok(outMonthPlanService.infoByPlanMonth(projectId,planMonth)); + } } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/out/service/IOutMonthPlanService.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/out/service/IOutMonthPlanService.java index 9dd50186..6eb81068 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/out/service/IOutMonthPlanService.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/out/service/IOutMonthPlanService.java @@ -1,5 +1,6 @@ package org.dromara.out.service; +import jakarta.validation.constraints.NotNull; import org.dromara.out.domain.vo.OutMonthPlanVo; import org.dromara.out.domain.bo.OutMonthPlanBo; import org.dromara.out.domain.OutMonthPlan; @@ -7,6 +8,7 @@ import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.PageQuery; import com.baomidou.mybatisplus.extension.service.IService; +import org.springframework.web.bind.annotation.PathVariable; import java.math.BigDecimal; import java.util.Collection; @@ -89,4 +91,9 @@ public interface IOutMonthPlanService extends IService{ */ BigDecimal getDesignValueByProjectId(Long projectId,String month); + /** + * 根据计划月份查询计划 + */ + List infoByPlanMonth(Long projectId, String planMonth); + } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/out/service/impl/OutConstructionValueServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/out/service/impl/OutConstructionValueServiceImpl.java index 1e5c76d5..ab3e9009 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/out/service/impl/OutConstructionValueServiceImpl.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/out/service/impl/OutConstructionValueServiceImpl.java @@ -62,7 +62,9 @@ public class OutConstructionValueServiceImpl extends ServiceImpl list) { for (OutConstructionValueVo vo : list) { - //查询项目 - BusProjectVo busProjectVo = busProjectService.queryById(vo.getProjectId()); - vo.setProjectName(busProjectVo.getProjectName()); - - //查询方阵以及子项目 - FacMatrixVo facMatrixVo = facMatrixService.queryById(vo.getMatrixId()); - vo.setMatrixName(facMatrixVo.getMatrixName()); - - BusProjectVo busProjectVo1 = busProjectService.queryById(facMatrixVo.getProjectId()); - vo.setSubProjectId(busProjectVo1.getId()); - vo.setSubProjectName(busProjectVo1.getProjectName()); - - //查询分部工程以及分项工程 - PgsProgressCategoryVo pgsProgressCategoryVo = pgsProgressCategoryService.queryById(vo.getProgressCategoryId()); - vo.setProgressCategoryName(pgsProgressCategoryVo.getName()); - - PgsProgressCategoryVo pgsProgressCategoryVo1 = pgsProgressCategoryService.queryById(pgsProgressCategoryVo.getParentId()); - vo.setCategoryId(pgsProgressCategoryVo1.getId()); - vo.setCategoryName(pgsProgressCategoryVo1.getName()); + getName(vo); } } + public void getName(OutConstructionValueVo vo){ + //查询项目 + BusProjectVo busProjectVo = busProjectService.queryById(vo.getProjectId()); + vo.setProjectName(busProjectVo.getProjectName()); + + //查询方阵以及子项目 + FacMatrixVo facMatrixVo = facMatrixService.queryById(vo.getMatrixId()); + vo.setMatrixName(facMatrixVo.getMatrixName()); + + BusProjectVo busProjectVo1 = busProjectService.queryById(facMatrixVo.getProjectId()); + vo.setSubProjectId(busProjectVo1.getId()); + vo.setSubProjectName(busProjectVo1.getProjectName()); + + //查询分部工程以及分项工程 + PgsProgressCategoryVo pgsProgressCategoryVo = pgsProgressCategoryService.queryById(vo.getProgressCategoryId()); + vo.setProgressCategoryName(pgsProgressCategoryVo.getName()); + + PgsProgressCategoryVo pgsProgressCategoryVo1 = pgsProgressCategoryService.queryById(pgsProgressCategoryVo.getParentId()); + vo.setCategoryId(pgsProgressCategoryVo1.getId()); + vo.setCategoryName(pgsProgressCategoryVo1.getName()); + } + /** * 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成,单任务完成等) diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/out/service/impl/OutMonthPlanServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/out/service/impl/OutMonthPlanServiceImpl.java index 18b54722..edb7b85f 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/out/service/impl/OutMonthPlanServiceImpl.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/out/service/impl/OutMonthPlanServiceImpl.java @@ -3,6 +3,7 @@ package org.dromara.out.service.impl; import cn.hutool.core.convert.Convert; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.extern.slf4j.Slf4j; +import org.dromara.cailiaoshebei.service.IBusMaterialsorderService; import org.dromara.common.core.domain.event.ProcessDeleteEvent; import org.dromara.common.core.domain.event.ProcessEvent; import org.dromara.common.core.domain.event.ProcessTaskEvent; @@ -56,6 +57,9 @@ public class OutMonthPlanServiceImpl extends ServiceImpl infoByPlanMonth(Long projectId, String planMonth) { + return baseMapper.selectVoList(Wrappers.lambdaQuery() + .eq(OutMonthPlan::getProjectId, projectId) + .eq(OutMonthPlan::getPlanMonth, planMonth) + ); + } + /** * 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成,单任务完成等) * 正常使用只需#processEvent.flowCode=='leave1' @@ -217,11 +229,13 @@ public class OutMonthPlanServiceImpl extends ServiceImpl { outMonthPlan.setPlanAuditStatus(processEvent.getStatus()); if (processEvent.getSubmit()) { outMonthPlan.setPlanAuditStatus(BusinessStatusEnum.WAITING.getStatus()); } + log.info("月度计划产值审核任务状态改变后{}", outMonthPlan.toString()); }); if(BusinessStatusEnum.FINISH.getStatus().equals(processEvent.getStatus())){ OutMonthPlanAudit outMonthPlanAudit = getOutMonthPlanAudit(outMonthPlans); @@ -267,8 +281,8 @@ public class OutMonthPlanServiceImpl extends ServiceImpl outConstructionValues = constructionValueService.lambdaQuery() diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusAttendanceController.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusAttendanceController.java index d1216dfe..2560375a 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusAttendanceController.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusAttendanceController.java @@ -1,33 +1,32 @@ package org.dromara.project.controller; -import cn.dev33.satoken.annotation.SaCheckPermission; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.validation.constraints.NotNull; -import lombok.RequiredArgsConstructor; -import org.dromara.common.core.domain.R; -import org.dromara.common.excel.utils.ExcelUtil; -import org.dromara.common.log.annotation.Log; -import org.dromara.common.log.enums.BusinessType; -import org.dromara.common.mybatis.core.page.PageQuery; -import org.dromara.common.mybatis.core.page.TableDataInfo; -import org.dromara.common.web.core.BaseController; -import org.dromara.project.domain.dto.attendance.BusAttendanceMonthByUserIdReq; -import org.dromara.project.domain.dto.attendance.BusAttendanceQueryReq; -import org.dromara.project.domain.dto.attendance.BusAttendanceQueryTwoWeekReq; -import org.dromara.project.domain.vo.attendance.BusAttendanceClockDateForTwoWeekVo; -import org.dromara.project.domain.vo.attendance.BusAttendanceMonthByUserIdVo; -import org.dromara.project.domain.vo.attendance.BusAttendanceVo; -import org.dromara.project.service.IBusAttendanceService; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - import java.util.List; +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.project.domain.vo.BusAttendanceVo; +import org.dromara.project.domain.bo.BusAttendanceBo; +import org.dromara.project.service.IBusAttendanceService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + /** * 考勤 * - * @author lilemy - * @date 2025-04-07 + * @author Lion Li + * @date 2025-08-05 */ @Validated @RequiredArgsConstructor @@ -42,26 +41,8 @@ public class BusAttendanceController extends BaseController { */ @SaCheckPermission("project:attendance:list") @GetMapping("/list") - public TableDataInfo list(BusAttendanceQueryReq req, PageQuery pageQuery) { - return busAttendanceService.queryPageList(req, pageQuery); - } - - /** - * 查询近两周考勤列表 - */ - @SaCheckPermission("project:attendance:list") - @GetMapping("/list/clockDate/twoWeek") - public R> listClockDateForTwoWeek(BusAttendanceQueryTwoWeekReq req) { - return R.ok(busAttendanceService.listClockDateForTwoWeek(req)); - } - - /** - * 查询施工人员月份考勤列表 - */ - @SaCheckPermission("project:attendance:list") - @GetMapping("/list/month/byUserId") - public R> listAttendanceMonthListByUserId(BusAttendanceMonthByUserIdReq req) { - return R.ok(busAttendanceService.listAttendanceMonthListByUserId(req)); + public TableDataInfo list(BusAttendanceBo bo, PageQuery pageQuery) { + return busAttendanceService.queryPageList(bo, pageQuery); } /** @@ -70,8 +51,8 @@ public class BusAttendanceController extends BaseController { @SaCheckPermission("project:attendance:export") @Log(title = "考勤", businessType = BusinessType.EXPORT) @PostMapping("/export") - public void export(BusAttendanceQueryReq req, HttpServletResponse response) { - List list = busAttendanceService.queryList(req); + public void export(BusAttendanceBo bo, HttpServletResponse response) { + List list = busAttendanceService.queryList(bo); ExcelUtil.exportExcel(list, "考勤", BusAttendanceVo.class, response); } @@ -83,8 +64,42 @@ public class BusAttendanceController extends BaseController { @SaCheckPermission("project:attendance:query") @GetMapping("/{id}") public R getInfo(@NotNull(message = "主键不能为空") - @PathVariable Long id) { + @PathVariable Long id) { return R.ok(busAttendanceService.queryById(id)); } + /** + * 新增考勤 + */ + @SaCheckPermission("project:attendance:add") + @Log(title = "考勤", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody BusAttendanceBo bo) { + return toAjax(busAttendanceService.insertByBo(bo)); + } + + /** + * 修改考勤 + */ + @SaCheckPermission("project:attendance:edit") + @Log(title = "考勤", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody BusAttendanceBo bo) { + return toAjax(busAttendanceService.updateByBo(bo)); + } + + /** + * 删除考勤 + * + * @param ids 主键串 + */ + @SaCheckPermission("project:attendance:remove") + @Log(title = "考勤", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(busAttendanceService.deleteWithValidByIds(List.of(ids), true)); + } } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusAttendanceRuleController.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusAttendanceRuleController.java new file mode 100644 index 00000000..f1469c49 --- /dev/null +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusAttendanceRuleController.java @@ -0,0 +1,105 @@ +package org.dromara.project.controller; + +import java.util.List; + +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.project.domain.vo.BusAttendanceRuleVo; +import org.dromara.project.domain.bo.BusAttendanceRuleBo; +import org.dromara.project.service.IBusAttendanceRuleService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 考勤打卡规则 + * + * @author Lion Li + * @date 2025-08-05 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/project/attendanceRule") +public class BusAttendanceRuleController extends BaseController { + + private final IBusAttendanceRuleService busAttendanceRuleService; + + /** + * 查询考勤打卡规则列表 + */ + @SaCheckPermission("project:attendanceRule:list") + @GetMapping("/list") + public TableDataInfo list(BusAttendanceRuleBo bo, PageQuery pageQuery) { + return busAttendanceRuleService.queryPageList(bo, pageQuery); + } + + /** + * 导出考勤打卡规则列表 + */ + @SaCheckPermission("project:attendanceRule:export") + @Log(title = "考勤打卡规则", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(BusAttendanceRuleBo bo, HttpServletResponse response) { + List list = busAttendanceRuleService.queryList(bo); + ExcelUtil.exportExcel(list, "考勤打卡规则", BusAttendanceRuleVo.class, response); + } + + /** + * 获取考勤打卡规则详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("project:attendanceRule:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(busAttendanceRuleService.queryById(id)); + } + + /** + * 新增考勤打卡规则 + */ + @SaCheckPermission("project:attendanceRule:add") + @Log(title = "考勤打卡规则", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody BusAttendanceRuleBo bo) { + return toAjax(busAttendanceRuleService.insertByBo(bo)); + } + + /** + * 修改考勤打卡规则 + */ + @SaCheckPermission("project:attendanceRule:edit") + @Log(title = "考勤打卡规则", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody BusAttendanceRuleBo bo) { + return toAjax(busAttendanceRuleService.updateByBo(bo)); + } + + /** + * 删除考勤打卡规则 + * + * @param ids 主键串 + */ + @SaCheckPermission("project:attendanceRule:remove") + @Log(title = "考勤打卡规则", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(busAttendanceRuleService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/app/BusAttendanceAppController.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/app/BusAttendanceAppController.java index 42c7e8fe..dcd9a201 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/app/BusAttendanceAppController.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/app/BusAttendanceAppController.java @@ -1,16 +1,14 @@ package org.dromara.project.controller.app; import jakarta.annotation.Resource; +import jakarta.validation.constraints.NotNull; import org.dromara.common.core.domain.R; import org.dromara.common.satoken.utils.LoginHelper; -import org.dromara.contractor.domain.SubConstructionUser; import org.dromara.contractor.service.ISubConstructionUserService; -import org.dromara.project.domain.dto.attendance.BusAttendanceByDayReq; -import org.dromara.project.domain.dto.attendance.BusAttendanceByMonthReq; -import org.dromara.project.domain.dto.attendance.BusAttendanceMonthByUserIdReq; import org.dromara.project.domain.dto.attendance.BusAttendancePunchCardByFaceReq; -import org.dromara.project.domain.vo.attendance.BusAttendanceMonthByUserIdVo; -import org.dromara.project.domain.vo.attendance.BusAttendanceVo; +import org.dromara.project.domain.vo.BusAttendanceRuleVo; +import org.dromara.project.domain.vo.BusAttendanceVo; +import org.dromara.project.service.IBusAttendanceRuleService; import org.dromara.project.service.IBusAttendanceService; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -26,38 +24,15 @@ import java.util.List; */ @Validated @RestController -@RequestMapping("/app/project/attendance") +@RequestMapping("/app/project/attendance/app") public class BusAttendanceAppController { @Resource private IBusAttendanceService attendanceService; + @Resource - private ISubConstructionUserService constructionUserService; - - /** - * 获取当前登录用户的考勤列表 - * - * @param req 查询参数 - * @return 考勤列表 - */ - @GetMapping("/list/loginUser") - public R> listLoginUser(BusAttendanceByDayReq req) { - return R.ok(attendanceService.getDayByUserId(LoginHelper.getUserId(), req.getClockDate())); - } - - /** - * 获取当前登录用户月份考勤列表 - */ - @GetMapping("/list/month/loginUser") - public R> listAttendanceMonthListByUserId(BusAttendanceByMonthReq req) { - Long userId = LoginHelper.getUserId(); - SubConstructionUser constructionUser = constructionUserService.getBySysUserId(userId); - BusAttendanceMonthByUserIdReq dto = new BusAttendanceMonthByUserIdReq(); - dto.setUserId(constructionUser.getId()); - dto.setClockMonth(req.getClockMonth()); - return R.ok(attendanceService.listAttendanceMonthListByUserId(dto)); - } + private IBusAttendanceRuleService attendanceRuleService; /** * 人脸坐标打卡 @@ -66,4 +41,44 @@ public class BusAttendanceAppController { public R punchCardByFace(@RequestPart("file") MultipartFile file, BusAttendancePunchCardByFaceReq req) { return R.ok(attendanceService.punchCardByFace(file, req)); } + + /** + * 获取考勤打卡规则详细信息 + */ + @GetMapping("/ruleInfo/{projectId}") + public R getInfo(@NotNull(message = "项目不能为空") + @PathVariable Long projectId) { + return R.ok(attendanceRuleService.queryByProjectId(projectId)); + } + + /** + * 查询项目考勤范围列表 + */ + @GetMapping("/punchRangeList/{projectId}") + public R> list(@NotNull @PathVariable("projectId") Long projectId) { + Long userId = LoginHelper.getUserId(); + return R.ok(attendanceService.getPunchRangeByProjectIdAndUserId(projectId, userId)); + } + + /** + * 判断是否在打卡范围内 + */ + @GetMapping("/checkInRange") + public R checkInRange(BusAttendancePunchCardByFaceReq req) { + return R.ok(attendanceService.checkInRange(req)); + } + + /** + * 获取用户当天打卡记录 + */ + @PostMapping("/getTodayAttendance/{projectId}") + public R> getTodayAttendance(@NotNull @PathVariable("projectId") Long projectId){ + return R.ok(attendanceService.getTodayAttendance(projectId)); + + } + + + + + } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusAttendance.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusAttendance.java index 4a00c5d0..b96ce2ea 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusAttendance.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusAttendance.java @@ -1,19 +1,22 @@ package org.dromara.project.domain; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import com.baomidou.mybatisplus.annotation.*; import lombok.Data; import lombok.EqualsAndHashCode; -import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; import java.io.Serial; -import java.util.Date; /** * 考勤对象 bus_attendance * - * @author lilemy - * @date 2025-04-07 + * @author Lion Li + * @date 2025-08-05 */ @Data @EqualsAndHashCode(callSuper = true) @@ -24,7 +27,7 @@ public class BusAttendance extends BaseEntity { private static final long serialVersionUID = 1L; /** - * 主键id + * */ @TableId(value = "id") private Long id; @@ -34,11 +37,6 @@ public class BusAttendance extends BaseEntity { */ private Long userId; - /** - * 人员姓名 - */ - private String userName; - /** * 人脸照 */ @@ -49,50 +47,30 @@ public class BusAttendance extends BaseEntity { */ private Long projectId; - /** - * 上班打卡时间 - */ - private Date clockTime; - /** * 打卡日期 */ - private Date clockDate; + private LocalDate clockDate; /** - * 打卡状态(1正常,2迟到,3早退,4缺勤,5补卡) + * 打卡时间 + */ + private LocalDateTime clockTime; + + /** + * 1正常,2迟到,3早退,4缺勤,5补卡,6请假,7外勤 */ private String clockStatus; /** - * 请假id + * 上下班(1上班2下班) */ - private Long leaveId; + private String clockType; /** - * 代打人员id + * 打卡地点 */ - private Long pinchUserId; - - /** - * 多次打卡时间记录 - */ - private String clockRecord; - - /** - * 上下班(1上班,2下班) - */ - private String commuter; - - /** - * 打卡范围 - */ - private String punchRange; - - /** - * 日薪 - */ - private Long dailyWage; + private String clockLocation; /** * 经度 @@ -104,9 +82,5 @@ public class BusAttendance extends BaseEntity { */ private String lat; - /** - * 备注 - */ - private String remark; } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusAttendanceRule.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusAttendanceRule.java new file mode 100644 index 00000000..125fa334 --- /dev/null +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusAttendanceRule.java @@ -0,0 +1,96 @@ +package org.dromara.project.domain; + +import org.dromara.common.mybatis.core.domain.BaseEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.io.Serial; + +/** + * 考勤打卡规则对象 bus_attendance_rule + * + * @author Lion Li + * @date 2025-08-05 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("bus_attendance_rule") +public class BusAttendanceRule extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 上班打卡时间 + */ + private LocalTime clockInTime; + + /** + * 下班打卡时间 + */ + private LocalTime clockOutTime; + + /** + * 是否次日 + */ + private Boolean isNext; + + /** + * 上班开始打卡时间 + */ + private LocalTime clockInStartTime; + + /** + * 上班结束打卡时间 + */ + private LocalTime clockInEndTime; + + /** + * 下班开始打卡时间 + */ + private LocalTime clockOutStartTime; + + /** + * 下班结束打卡时间 + */ + private LocalTime clockOutEndTime; + + /** + * 上班结果生成时间 + */ + private LocalTime clockInResultTime; + + /** + * 下班结果生成时间 + */ + private LocalTime clockOutResultTime; + + /** + * 工作日 + */ + private String weekday; + + /** + * 1-无限制,2-范围内打卡 + */ + private String type; + + +} diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/bo/BusAttendanceBo.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/bo/BusAttendanceBo.java new file mode 100644 index 00000000..60c38279 --- /dev/null +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/bo/BusAttendanceBo.java @@ -0,0 +1,87 @@ +package org.dromara.project.domain.bo; + +import org.dromara.project.domain.BusAttendance; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 考勤业务对象 bus_attendance + * + * @author Lion Li + * @date 2025-08-05 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = BusAttendance.class, reverseConvertGenerate = false) +public class BusAttendanceBo extends BaseEntity { + + /** + * + */ + @NotNull(message = "不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 人员id + */ + @NotNull(message = "人员id不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long userId; + + /** + * 人脸照 + */ + private String facePic; + + /** + * 项目id + */ + @NotNull(message = "项目id不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long projectId; + + /** + * 打卡日期 + */ + private LocalDate clockDate; + + /** + * 打卡时间 + */ + private LocalDateTime clockTime; + + /** + * 1正常,2迟到,3早退,4缺勤,5补卡,6请假,7外勤 + */ + private String clockStatus; + + /** + * 上下班(1上班2下班) + */ + private String clockType; + + /** + * 打卡地点 + */ + private String clockLocation; + + /** + * 经度 + */ + private String lng; + + /** + * 纬度 + */ + private String lat; + + +} diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/bo/BusAttendanceRuleBo.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/bo/BusAttendanceRuleBo.java new file mode 100644 index 00000000..377ba7f8 --- /dev/null +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/bo/BusAttendanceRuleBo.java @@ -0,0 +1,98 @@ +package org.dromara.project.domain.bo; + +import org.dromara.project.domain.BusAttendanceRule; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 考勤打卡规则业务对象 bus_attendance_rule + * + * @author Lion Li + * @date 2025-08-05 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = BusAttendanceRule.class, reverseConvertGenerate = false) +public class BusAttendanceRuleBo extends BaseEntity { + + /** + * + */ + @NotNull(message = "不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 项目id + */ + @NotNull(message = "项目id不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long projectId; + + /** + * 上班打卡时间 + */ + @NotNull(message = "上班打卡时间不能为空", groups = { AddGroup.class, EditGroup.class }) + private LocalTime clockInTime; + + /** + * 下班打卡时间 + */ + @NotNull(message = "下班打卡时间不能为空", groups = { AddGroup.class, EditGroup.class }) + private LocalTime clockOutTime; + + /** + * 是否次日 + */ + private Boolean isNext; + + /** + * 上班开始打卡时间 + */ + private LocalTime clockInStartTime; + + /** + * 上班结束打卡时间 + */ + private LocalTime clockInEndTime; + + /** + * 下班开始打卡时间 + */ + private LocalTime clockOutStartTime; + + /** + * 下班结束打卡时间 + */ + private LocalTime clockOutEndTime; + + /** + * 上班结果生成时间 + */ + private LocalTime clockInResultTime; + + /** + * 下班结果生成时间 + */ + private LocalTime clockOutResultTime; + + /** + * 工作日 + */ + private String weekday; + + /** + * 1-无限制,2-范围内打卡 + */ + private String type; + + +} diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/bo/BusProjectPunchrangeBo.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/bo/BusProjectPunchrangeBo.java index 1343070f..7dab778d 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/bo/BusProjectPunchrangeBo.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/bo/BusProjectPunchrangeBo.java @@ -1,5 +1,6 @@ package org.dromara.project.domain.bo; +import lombok.Builder; import org.dromara.project.domain.BusProjectPunchrange; import org.dromara.common.mybatis.core.domain.BaseEntity; import org.dromara.common.core.validate.AddGroup; @@ -21,7 +22,7 @@ import jakarta.validation.constraints.*; public class BusProjectPunchrangeBo extends BaseEntity { /** - * + * */ @NotNull(message = "不能为空", groups = { EditGroup.class }) private Long id; diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/attendance/BusAttendancePunchCardByFaceReq.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/attendance/BusAttendancePunchCardByFaceReq.java index 7aa27822..92969171 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/attendance/BusAttendancePunchCardByFaceReq.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/attendance/BusAttendancePunchCardByFaceReq.java @@ -1,6 +1,7 @@ package org.dromara.project.domain.dto.attendance; import lombok.Data; +import org.springframework.web.multipart.MultipartFile; import java.io.Serial; import java.io.Serializable; @@ -25,4 +26,14 @@ public class BusAttendancePunchCardByFaceReq implements Serializable { */ private String lat; + /** + * 地名 + */ + private String locationName; + + /** + * 项目Id + */ + private Long projectId; + } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/BusAttendanceRuleVo.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/BusAttendanceRuleVo.java new file mode 100644 index 00000000..eabbe2ee --- /dev/null +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/BusAttendanceRuleVo.java @@ -0,0 +1,113 @@ +package org.dromara.project.domain.vo; + +import java.time.LocalTime; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.dromara.project.domain.BusAttendanceRule; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 考勤打卡规则视图对象 bus_attendance_rule + * + * @author Lion Li + * @date 2025-08-05 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = BusAttendanceRule.class) +public class BusAttendanceRuleVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @ExcelProperty(value = "") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 上班打卡时间 + */ + @ExcelProperty(value = "上班打卡时间") + private LocalTime clockInTime; + + /** + * 下班打卡时间 + */ + @ExcelProperty(value = "下班打卡时间") + private LocalTime clockOutTime; + + /** + * 是否次日 + */ + @ExcelProperty(value = "是否次日") + private Boolean isNext; + + /** + * 上班开始打卡时间 + */ + @ExcelProperty(value = "上班开始打卡时间") + private LocalTime clockInStartTime; + + /** + * 上班结束打卡时间 + */ + @ExcelProperty(value = "上班结束打卡时间") + private LocalTime clockInEndTime; + + /** + * 下班开始打卡时间 + */ + @ExcelProperty(value = "下班开始打卡时间") + private LocalTime clockOutStartTime; + + /** + * 下班结束打卡时间 + */ + @ExcelProperty(value = "下班结束打卡时间") + private LocalTime clockOutEndTime; + + /** + * 上班结果生成时间 + */ + @ExcelProperty(value = "上班结果生成时间") + private LocalTime clockInResultTime; + + /** + * 下班结果生成时间 + */ + @ExcelProperty(value = "下班结果生成时间") + private LocalTime clockOutResultTime; + + /** + * 工作日 + */ + @ExcelProperty(value = "工作日") + private String weekday; + + /** + * 1-无限制,2-范围内打卡 + */ + @ExcelProperty(value = "1-无限制,2-范围内打卡") + private String type; + + +} diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/attendance/BusAttendanceVo.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/BusAttendanceVo.java similarity index 51% rename from xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/attendance/BusAttendanceVo.java rename to xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/BusAttendanceVo.java index 5e57cee7..2cb9f728 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/attendance/BusAttendanceVo.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/BusAttendanceVo.java @@ -1,24 +1,28 @@ -package org.dromara.project.domain.vo.attendance; +package org.dromara.project.domain.vo; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.dromara.project.domain.BusAttendance; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; -import com.fasterxml.jackson.annotation.JsonFormat; -import io.github.linpeilie.annotations.AutoMapper; -import lombok.Data; import org.dromara.common.excel.annotation.ExcelDictFormat; import org.dromara.common.excel.convert.ExcelDictConvert; -import org.dromara.project.domain.BusAttendance; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; import java.io.Serial; import java.io.Serializable; import java.util.Date; + /** * 考勤视图对象 bus_attendance * - * @author lilemy - * @date 2025-04-07 + * @author Lion Li + * @date 2025-08-05 */ @Data @ExcelIgnoreUnannotated @@ -29,36 +33,21 @@ public class BusAttendanceVo implements Serializable { private static final long serialVersionUID = 1L; /** - * 主键id + * */ + @ExcelProperty(value = "") private Long id; /** * 人员id */ + @ExcelProperty(value = "人员id") private Long userId; - /** - * 人员姓名 - */ - @ExcelProperty(value = "人员姓名") - private String userName; - - /** - * 班组id - */ - private Long teamId; - - /** - * 工种 - */ - @ExcelProperty(value = "工种", converter = ExcelDictConvert.class) - @ExcelDictFormat(dictType = "type_of_work") - private String typeOfWork; - /** * 人脸照 */ + @ExcelProperty(value = "人脸照") private String facePic; /** @@ -67,57 +56,36 @@ public class BusAttendanceVo implements Serializable { @ExcelProperty(value = "项目id") private Long projectId; + /** + * 打卡日期 + */ + @ExcelProperty(value = "打卡日期") + private LocalDate clockDate; + /** * 打卡时间 */ @ExcelProperty(value = "打卡时间") - private Date clockTime; + private LocalDateTime clockTime; /** - * 打卡日期 + * 1正常,2迟到,3早退,4缺勤,5补卡,6请假,7外勤 */ - @JsonFormat(shape = JsonFormat.Shape.STRING, - pattern = "yyyy-MM-dd", - timezone = "GMT+8") - @ExcelProperty(value = "打卡日期") - private Date clockDate; - - /** - * 打卡状态(1正常,2迟到,3早退,4缺勤,5补卡) - */ - @ExcelProperty(value = "打卡状态", converter = ExcelDictConvert.class) - @ExcelDictFormat(dictType = "clock_status_type") + @ExcelProperty(value = "1正常,2迟到,3早退,4缺勤,5补卡,6请假,7外勤") private String clockStatus; /** - * 代打人员id - */ - private Long pinchUserId; - - /** - * 多次打卡时间记录 - */ - @ExcelProperty(value = "多次打卡时间记录") - private String clockRecord; - - /** - * 上下班(1上班,2下班) + * 上下班(1上班2下班) */ @ExcelProperty(value = "上下班", converter = ExcelDictConvert.class) - @ExcelDictFormat(dictType = "commuter_type") - private String commuter; + @ExcelDictFormat(readConverterExp = "1=上班2下班") + private String clockType; /** - * 打卡范围 + * 打卡地点 */ - @ExcelProperty(value = "打卡范围") - private String punchRange; - - /** - * 日薪 - */ - @ExcelProperty(value = "日薪") - private Long dailyWage; + @ExcelProperty(value = "打卡地点") + private String clockLocation; /** * 经度 @@ -131,10 +99,5 @@ public class BusAttendanceVo implements Serializable { @ExcelProperty(value = "纬度") private String lat; - /** - * 备注 - */ - @ExcelProperty(value = "备注") - private String remark; } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/attendance/BusAttendanceListByDay.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/attendance/BusAttendanceListByDay.java index f89c3211..29ac1f47 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/attendance/BusAttendanceListByDay.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/attendance/BusAttendanceListByDay.java @@ -5,6 +5,8 @@ import lombok.Data; import lombok.NoArgsConstructor; import org.dromara.project.domain.BusAttendance; +import java.time.LocalDate; +import java.time.LocalDateTime; import java.util.Date; /** @@ -19,12 +21,12 @@ public class BusAttendanceListByDay { /** * 上下班(1上班,2下班) */ - private String commuter; + private String clockType; /** * 打卡时间 */ - private Date clockTime; + private LocalDateTime clockTime; /** * 打卡状态(1正常,2迟到,3早退,4缺勤,5补卡) @@ -36,7 +38,7 @@ public class BusAttendanceListByDay { return null; } BusAttendanceListByDay attendanceListByDay = new BusAttendanceListByDay(); - attendanceListByDay.setCommuter(attendance.getCommuter()); + attendanceListByDay.setClockType(attendance.getClockType()); attendanceListByDay.setClockTime(attendance.getClockTime()); attendanceListByDay.setClockStatus(attendance.getClockStatus()); return attendanceListByDay; diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusAttendanceMapper.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusAttendanceMapper.java index b15b1e47..a9a886fa 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusAttendanceMapper.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusAttendanceMapper.java @@ -1,14 +1,14 @@ package org.dromara.project.mapper; import org.dromara.project.domain.BusAttendance; -import org.dromara.project.domain.vo.attendance.BusAttendanceVo; +import org.dromara.project.domain.vo.BusAttendanceVo; import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; /** * 考勤Mapper接口 * - * @author lilemy - * @date 2025-04-07 + * @author Lion Li + * @date 2025-08-05 */ public interface BusAttendanceMapper extends BaseMapperPlus { diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusAttendanceRuleMapper.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusAttendanceRuleMapper.java new file mode 100644 index 00000000..944c9679 --- /dev/null +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusAttendanceRuleMapper.java @@ -0,0 +1,15 @@ +package org.dromara.project.mapper; + +import org.dromara.project.domain.BusAttendanceRule; +import org.dromara.project.domain.vo.BusAttendanceRuleVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 考勤打卡规则Mapper接口 + * + * @author Lion Li + * @date 2025-08-05 + */ +public interface BusAttendanceRuleMapper extends BaseMapperPlus { + +} diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusAttendanceRuleService.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusAttendanceRuleService.java new file mode 100644 index 00000000..fcbb4236 --- /dev/null +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusAttendanceRuleService.java @@ -0,0 +1,75 @@ +package org.dromara.project.service; + +import org.dromara.project.domain.vo.BusAttendanceRuleVo; +import org.dromara.project.domain.bo.BusAttendanceRuleBo; +import org.dromara.project.domain.BusAttendanceRule; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import com.baomidou.mybatisplus.extension.service.IService; +import java.util.Collection; +import java.util.List; + +/** + * 考勤打卡规则Service接口 + * + * @author Lion Li + * @date 2025-08-05 + */ +public interface IBusAttendanceRuleService extends IService{ + + /** + * 查询考勤打卡规则 + * + * @param id 主键 + * @return 考勤打卡规则 + */ + BusAttendanceRuleVo queryById(Long id); + + /** + * 分页查询考勤打卡规则列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 考勤打卡规则分页列表 + */ + TableDataInfo queryPageList(BusAttendanceRuleBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的考勤打卡规则列表 + * + * @param bo 查询条件 + * @return 考勤打卡规则列表 + */ + List queryList(BusAttendanceRuleBo bo); + + /** + * 新增考勤打卡规则 + * + * @param bo 考勤打卡规则 + * @return 是否新增成功 + */ + Boolean insertByBo(BusAttendanceRuleBo bo); + + /** + * 修改考勤打卡规则 + * + * @param bo 考勤打卡规则 + * @return 是否修改成功 + */ + Boolean updateByBo(BusAttendanceRuleBo bo); + + /** + * 校验并批量删除考勤打卡规则信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 根据项目id查询 + */ + BusAttendanceRuleVo queryByProjectId(Long projectId); +} diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusAttendanceService.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusAttendanceService.java index bd38ba02..295e8683 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusAttendanceService.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusAttendanceService.java @@ -1,30 +1,25 @@ package org.dromara.project.service; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.IService; -import org.dromara.common.mybatis.core.page.PageQuery; -import org.dromara.common.mybatis.core.page.TableDataInfo; -import org.dromara.project.domain.BusAttendance; -import org.dromara.project.domain.dto.attendance.BusAttendanceMonthByUserIdReq; import org.dromara.project.domain.dto.attendance.BusAttendancePunchCardByFaceReq; -import org.dromara.project.domain.dto.attendance.BusAttendanceQueryReq; -import org.dromara.project.domain.dto.attendance.BusAttendanceQueryTwoWeekReq; -import org.dromara.project.domain.vo.attendance.BusAttendanceClockDateForTwoWeekVo; -import org.dromara.project.domain.vo.attendance.BusAttendanceMonthByUserIdVo; -import org.dromara.project.domain.vo.attendance.BusAttendanceVo; +import org.dromara.project.domain.vo.BusAttendanceVo; +import org.dromara.project.domain.bo.BusAttendanceBo; +import org.dromara.project.domain.BusAttendance; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import com.baomidou.mybatisplus.extension.service.IService; import org.springframework.web.multipart.MultipartFile; -import java.util.Date; +import java.util.Collection; import java.util.List; /** * 考勤Service接口 * - * @author lilemy - * @date 2025-04-07 + * @author Lion Li + * @date 2025-08-05 */ -public interface IBusAttendanceService extends IService { +public interface IBusAttendanceService extends IService{ /** * 查询考勤 @@ -37,76 +32,45 @@ public interface IBusAttendanceService extends IService { /** * 分页查询考勤列表 * - * @param req 查询条件 + * @param bo 查询条件 * @param pageQuery 分页参数 * @return 考勤分页列表 */ - TableDataInfo queryPageList(BusAttendanceQueryReq req, PageQuery pageQuery); - - /** - * 查询两周内的考勤列表 - * - * @param req 查询条件 - * @return 考勤列表 - */ - List listClockDateForTwoWeek(BusAttendanceQueryTwoWeekReq req); - - /** - * 查询用户每月考勤列表 - * - * @param req 查询条件 - * @return 考勤列表 - */ - List listAttendanceMonthListByUserId(BusAttendanceMonthByUserIdReq req); + TableDataInfo queryPageList(BusAttendanceBo bo, PageQuery pageQuery); /** * 查询符合条件的考勤列表 * - * @param req 查询条件 + * @param bo 查询条件 * @return 考勤列表 */ - List queryList(BusAttendanceQueryReq req); + List queryList(BusAttendanceBo bo); /** - * 根据项目id查询出勤人列表 + * 新增考勤 * - * @param projectId 项目id - * @return 出勤人列表 + * @param bo 考勤 + * @return 是否新增成功 */ - List listAttendancePeopleByProjectId(Long projectId); + Boolean insertByBo(BusAttendanceBo bo); /** - * 获取考勤视图对象 + * 修改考勤 * - * @param attendance 考勤对象 - * @return 考勤视图对象 + * @param bo 考勤 + * @return 是否修改成功 */ - BusAttendanceVo getVo(BusAttendance attendance); + Boolean updateByBo(BusAttendanceBo bo); /** - * 获取考勤查询条件封装 + * 校验并批量删除考勤信息 * - * @param req 查询条件 - * @return 查询条件封装 + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 */ - LambdaQueryWrapper buildQueryWrapper(BusAttendanceQueryReq req); + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); - /** - * 获取考勤分页对象视图 - * - * @param attendancePage 考勤分页对象 - * @return 考勤分页对象视图 - */ - Page getVoPage(Page attendancePage); - - /** - * 根据系统用户id和日期查询考勤 - * - * @param userId 用户id - * @param clockDate 日期 - * @return 考勤 - */ - List getDayByUserId(Long userId, Date clockDate); /** * 人脸打卡 @@ -117,4 +81,31 @@ public interface IBusAttendanceService extends IService { */ Boolean punchCardByFace(MultipartFile file, BusAttendancePunchCardByFaceReq req); + + /** + * 根据项目id查询出勤人列表 + * + * @param projectId 项目id + * @return 出勤人列表 + */ + List listAttendancePeopleByProjectId(Long projectId); + + + /** + * 根据项目id和人员ID找到打卡范围 + * + * @param projectId 项目id + * @return 打卡范围 + */ + List getPunchRangeByProjectIdAndUserId(Long projectId, Long userId); + + /** + * 判断是否在打卡范围内 + */ + Boolean checkInRange(BusAttendancePunchCardByFaceReq req); + + /** + * 获取用户当天打卡记录 + */ + List getTodayAttendance(Long projectId); } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusAttendanceRuleServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusAttendanceRuleServiceImpl.java new file mode 100644 index 00000000..f425d4b1 --- /dev/null +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusAttendanceRuleServiceImpl.java @@ -0,0 +1,218 @@ +package org.dromara.project.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.dromara.project.domain.bo.BusAttendanceRuleBo; +import org.dromara.project.domain.vo.BusAttendanceRuleVo; +import org.dromara.project.domain.BusAttendanceRule; +import org.dromara.project.mapper.BusAttendanceRuleMapper; +import org.dromara.project.service.IBusAttendanceRuleService; + +import java.time.LocalTime; +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 考勤打卡规则Service业务层处理 + * + * @author Lion Li + * @date 2025-08-05 + */ +@RequiredArgsConstructor +@Service +public class BusAttendanceRuleServiceImpl extends ServiceImpl + implements IBusAttendanceRuleService { + + private final BusAttendanceRuleMapper baseMapper; + + /** + * 查询考勤打卡规则 + * + * @param id 主键 + * @return 考勤打卡规则 + */ + @Override + public BusAttendanceRuleVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + /** + * 分页查询考勤打卡规则列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 考勤打卡规则分页列表 + */ + @Override + public TableDataInfo queryPageList(BusAttendanceRuleBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的考勤打卡规则列表 + * + * @param bo 查询条件 + * @return 考勤打卡规则列表 + */ + @Override + public List queryList(BusAttendanceRuleBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(BusAttendanceRuleBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(BusAttendanceRule::getId); + lqw.eq(bo.getProjectId() != null, BusAttendanceRule::getProjectId, bo.getProjectId()); + lqw.eq(bo.getClockInTime() != null, BusAttendanceRule::getClockInTime, bo.getClockInTime()); + lqw.eq(bo.getClockOutTime() != null, BusAttendanceRule::getClockOutTime, bo.getClockOutTime()); + lqw.eq(bo.getIsNext() != null, BusAttendanceRule::getIsNext, bo.getIsNext()); + lqw.eq(bo.getClockInStartTime() != null, BusAttendanceRule::getClockInStartTime, bo.getClockInStartTime()); + lqw.eq(bo.getClockInEndTime() != null, BusAttendanceRule::getClockInEndTime, bo.getClockInEndTime()); + lqw.eq(bo.getClockOutStartTime() != null, BusAttendanceRule::getClockOutStartTime, bo.getClockOutStartTime()); + lqw.eq(bo.getClockOutEndTime() != null, BusAttendanceRule::getClockOutEndTime, bo.getClockOutEndTime()); + lqw.eq(bo.getClockInResultTime() != null, BusAttendanceRule::getClockInResultTime, bo.getClockInResultTime()); + lqw.eq(bo.getClockOutResultTime() != null, BusAttendanceRule::getClockOutResultTime, bo.getClockOutResultTime()); + lqw.eq(StringUtils.isNotBlank(bo.getWeekday()), BusAttendanceRule::getWeekday, bo.getWeekday()); + lqw.eq(StringUtils.isNotBlank(bo.getType()), BusAttendanceRule::getType, bo.getType()); + return lqw; + } + + /** + * 新增考勤打卡规则 + * + * @param bo 考勤打卡规则 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(BusAttendanceRuleBo bo) { + BusAttendanceRule add = MapstructUtils.convert(bo, BusAttendanceRule.class); + validEntityBeforeSave(add); + setResultTime(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改考勤打卡规则 + * + * @param bo 考勤打卡规则 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(BusAttendanceRuleBo bo) { + BusAttendanceRule update = MapstructUtils.convert(bo, BusAttendanceRule.class); + validEntityBeforeSave(update); + setResultTime(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(BusAttendanceRule entity) { + //TODO 做一些数据校验,如唯一约束 + //暂时一个项目一个打卡规则 + List busAttendanceRules = baseMapper.selectList(Wrappers.lambdaQuery() + .eq(BusAttendanceRule::getProjectId, entity.getProjectId()) + .ne(entity.getId() != null, BusAttendanceRule::getId, entity.getId()) + ); + if (!busAttendanceRules.isEmpty()) { + throw new ServiceException("该项目已存在打卡规则"); + } + } + + + private void setResultTime(BusAttendanceRule entity) { + if (entity.getClockInEndTime() != null) { + entity.setClockInResultTime(entity.getClockInEndTime()); + } else { + // 计算上班时间和下班时间中间的时间 + + LocalTime clockInTime = entity.getClockInTime(); + LocalTime clockOutTime = entity.getClockOutTime(); + + // 如果下班时间是次日,则加24小时 + long clockInSeconds = clockInTime.toSecondOfDay(); + long clockOutSeconds = clockOutTime.toSecondOfDay(); + + if (Boolean.TRUE.equals(entity.getIsNext())) { + clockOutSeconds += 24 * 60 * 60; // 加24小时的秒数 + } + + // 计算中间时间(秒) + long midSeconds = (clockInSeconds + clockOutSeconds) / 2; + + // 如果超过24小时,则需要处理跨天情况 + if (midSeconds >= 24 * 60 * 60) { + midSeconds -= 24 * 60 * 60; + } + + // 转换回LocalTime + LocalTime midTime = java.time.LocalTime.ofSecondOfDay(midSeconds); + entity.setClockInResultTime(midTime); + + } + + if (entity.getClockOutTime() != null) { + entity.setClockOutResultTime(entity.getClockOutEndTime()); + } else { + // 计算下班时间和第二天上班时间的中间时间 + java.time.LocalTime clockOutTime = entity.getClockOutTime(); + java.time.LocalTime clockInTime = entity.getClockInTime(); + + // 计算下班时间到次日上班时间的中间点 + long clockOutSeconds = clockOutTime.toSecondOfDay(); + long clockInNextDaySeconds = clockInTime.toSecondOfDay() + 24 * 60 * 60; // 次日上班时间 + + // 计算中间时间 + long midSeconds = (clockOutSeconds + clockInNextDaySeconds) / 2; + + // 转换为当天时间(如果超过24小时) + if (midSeconds >= 24 * 60 * 60) { + midSeconds -= 24 * 60 * 60; + } + + java.time.LocalTime midTime = java.time.LocalTime.ofSecondOfDay(midSeconds); + entity.setClockOutResultTime(midTime); + + } + } + + /** + * 校验并批量删除考勤打卡规则信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } + + @Override + public BusAttendanceRuleVo queryByProjectId(Long projectId) { + return baseMapper.selectVoOne(Wrappers.lambdaQuery() + .eq(BusAttendanceRule::getProjectId, projectId)); + } +} diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusAttendanceServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusAttendanceServiceImpl.java index e1f6aa81..2a92f246 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusAttendanceServiceImpl.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusAttendanceServiceImpl.java @@ -1,88 +1,97 @@ package org.dromara.project.service.impl; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.date.DateUtil; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import jakarta.annotation.Resource; -import org.dromara.common.core.constant.DateConstant; -import org.dromara.common.core.constant.HttpStatus; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.R; import org.dromara.common.core.enums.FormatsType; import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.utils.DateUtils; -import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.MapstructUtils; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.domain.GeoPoint; -import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.utils.JSTUtil; import org.dromara.contractor.domain.SubConstructionUser; import org.dromara.contractor.service.ISubConstructionUserService; -import org.dromara.project.domain.BusAttendance; -import org.dromara.project.domain.BusProject; -import org.dromara.project.domain.BusProjectPunchrange; -import org.dromara.project.domain.BusProjectTeamMember; -import org.dromara.project.domain.dto.attendance.BusAttendanceMonthByUserIdReq; +import org.dromara.project.domain.*; +import org.dromara.project.domain.bo.BusProjectPunchrangeBo; import org.dromara.project.domain.dto.attendance.BusAttendancePunchCardByFaceReq; -import org.dromara.project.domain.dto.attendance.BusAttendanceQueryReq; -import org.dromara.project.domain.dto.attendance.BusAttendanceQueryTwoWeekReq; import org.dromara.project.domain.enums.BusAttendanceClockStatusEnum; import org.dromara.project.domain.enums.BusAttendanceCommuterEnum; -import org.dromara.project.domain.enums.BusAttendanceStatusEnum; -import org.dromara.project.domain.vo.attendance.BusAttendanceClockDateForTwoWeekVo; -import org.dromara.project.domain.vo.attendance.BusAttendanceListByDay; -import org.dromara.project.domain.vo.attendance.BusAttendanceMonthByUserIdVo; -import org.dromara.project.domain.vo.attendance.BusAttendanceVo; -import org.dromara.project.mapper.BusAttendanceMapper; +import org.dromara.project.domain.vo.BusAttendanceRuleVo; +import org.dromara.project.domain.vo.BusProjectPunchrangeVo; import org.dromara.project.service.*; import org.dromara.system.domain.vo.SysOssVo; import org.dromara.system.service.ISysOssService; -import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; +import org.dromara.project.domain.bo.BusAttendanceBo; +import org.dromara.project.domain.vo.BusAttendanceVo; +import org.dromara.project.mapper.BusAttendanceMapper; import org.springframework.web.multipart.MultipartFile; +import org.dromara.common.core.constant.HttpStatus; import java.time.LocalDate; +import java.time.LocalDateTime; import java.time.LocalTime; -import java.time.YearMonth; import java.time.ZoneId; import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; import java.util.*; import java.util.stream.Collectors; /** * 考勤Service业务层处理 * - * @author lilemy - * @date 2025-04-07 + * @author Lion Li + * @date 2025-08-05 */ +@RequiredArgsConstructor @Service -public class BusAttendanceServiceImpl extends ServiceImpl - implements IBusAttendanceService { +@Slf4j +public class BusAttendanceServiceImpl extends ServiceImpl implements IBusAttendanceService { - @Resource - private ISysOssService ossService; + private final BusAttendanceMapper baseMapper; - @Resource - private IBusProjectService projectService; + private final ISysOssService ossService; - @Resource - private IBusProjectPunchrangeService projectPunchrangeService; - @Resource - private IBusProjectTeamMemberService projectTeamMemberService; + private final IBusProjectService projectService; - @Resource - private ISubConstructionUserService constructionUserService; - @Resource - private IBusConstructionBlacklistService constructionBlacklistService; + private final IBusProjectPunchrangeService projectPunchrangeService; + + + private final IBusProjectTeamMemberService projectTeamMemberService; + + + private final ISubConstructionUserService constructionUserService; + + + private final IBusConstructionBlacklistService constructionBlacklistService; + + private final IBusAttendanceRuleService attendanceRuleService; + + private final IBusUserProjectRelevancyService userProjectRelevancyService; + + private final IBusProjectTeamService projectTeamService; + // 出勤状态(正常、迟到、早退) private static final Set ATTENDANCE_STATUS = new HashSet<>(Arrays.asList(BusAttendanceClockStatusEnum.NORMAL.getValue(), BusAttendanceClockStatusEnum.LATE.getValue(), BusAttendanceClockStatusEnum.LEAVEEARLY.getValue())); + /** * 查询考勤 * @@ -91,354 +100,102 @@ public class BusAttendanceServiceImpl extends ServiceImpl queryPageList(BusAttendanceQueryReq req, PageQuery pageQuery) { - Page result = this.page(pageQuery.build(), buildQueryWrapper(req)); - return TableDataInfo.build(this.getVoPage(result)); - } - - /** - * 查询两周内的考勤列表 - * - * @param req 查询条件 - * @return 考勤列表 - */ - @Override - public List listClockDateForTwoWeek(BusAttendanceQueryTwoWeekReq req) { - Long projectId = req.getProjectId(); - if (projectService.getById(projectId) == null) { - throw new ServiceException("项目信息不存在", HttpStatus.NOT_FOUND); - } - // 1. 处理日期区间 - Date clockDate = req.getClockDate(); - LocalDate startLocal; - LocalDate endLocal; - if (clockDate != null) { - // 检查 clockDate 不能大于当前日期 - if (DateUtil.compare(clockDate, new Date()) > 0) { - throw new ServiceException("日期不能大于当前日期", HttpStatus.BAD_REQUEST); - } - // 以传入的 clockDate 为结束日期 - endLocal = clockDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); - } else { - // 如果未传入,则以当前日期为结束日期 - endLocal = LocalDate.now(); - } - // 计算开始日期为结束日期减两周 - startLocal = endLocal.minusWeeks(2); - // 如果数据库中的 clockDate 只存储日期(时分秒置为 00:00:00),直接转换即可 - Date startDate = Date.from(startLocal.atStartOfDay(ZoneId.systemDefault()).toInstant()); - Date endDate = Date.from(endLocal.atStartOfDay(ZoneId.systemDefault()).toInstant()); - // 构造查询条件 clockDate 在 [startDate, endDate] 区间内 - LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); - lqw.eq(BusAttendance::getProjectId, projectId) - .eq(StringUtils.isNotEmpty(req.getUserName()), BusAttendance::getUserName, req.getUserName()) - .between(BusAttendance::getClockDate, startDate, endDate) - .orderByDesc(BusAttendance::getClockDate); - // 获取黑名单用户列表 - List blackList = constructionBlacklistService.queryIdListByProjectId(projectId); - // 构建查询用户相关信息查询条件 - List userIdList = constructionUserService.lambdaQuery() - .eq(SubConstructionUser::getProjectId, projectId) - .eq(req.getTeamId() != null, SubConstructionUser::getTeamId, req.getTeamId()) - .eq(req.getTypeOfWork() != null, SubConstructionUser::getTypeOfWork, req.getTypeOfWork()) - .notIn(CollUtil.isNotEmpty(blackList), SubConstructionUser::getId, blackList) - .list().stream().map(SubConstructionUser::getId).toList(); - lqw.in(CollUtil.isNotEmpty(userIdList), BusAttendance::getUserId, userIdList); - Map> dateListMap = this.list(lqw) - .stream().collect(Collectors.groupingBy(BusAttendance::getClockDate)); - // 遍历每个日期,计算考勤状态 - List respList = new ArrayList<>(); - // 遍历从两周前到今天的所有日期 - for (LocalDate localDate = startLocal; !localDate.isAfter(endLocal); localDate = localDate.plusDays(1)) { - BusAttendanceClockDateForTwoWeekVo resp = new BusAttendanceClockDateForTwoWeekVo(); - // 转换为 Date 类型(时分秒为 00:00:00) - Date currentDate = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant()); - resp.setClockDate(currentDate); - int attendance = 0; - int halfAttendance = 0; - int absenteeism = 0; - int leave = 0; - // 获取当天的考勤记录(可能为 null) - List attendanceList = dateListMap.getOrDefault(currentDate, Collections.emptyList()); - // 按用户分组考勤记录 - Map> userAttendanceMap = attendanceList.stream() - .collect(Collectors.groupingBy(BusAttendance::getUserId)); - if (CollUtil.isNotEmpty(userAttendanceMap)) { - for (List userAttendanceList : userAttendanceMap.values()) { - String clockInStatus = null; - String clockOutStatus = null; - String clockAllDayStatus = null; - // 遍历同一用户的考勤记录,分别获取上下班状态 - for (BusAttendance a : userAttendanceList) { - if (BusAttendanceCommuterEnum.CLOCKIN.getValue().equals(a.getCommuter())) { - clockInStatus = a.getClockStatus(); - } else if (BusAttendanceCommuterEnum.CLOCKOUT.getValue().equals(a.getCommuter())) { - clockOutStatus = a.getClockStatus(); - } else if (BusAttendanceCommuterEnum.ALLDAY.getValue().equals(a.getCommuter())) { - clockAllDayStatus = a.getClockStatus(); - } - } - // 统计考勤状态 - if (BusAttendanceClockStatusEnum.LEAVE.getValue().equals(clockAllDayStatus)) { - leave++; - } else if ((BusAttendanceClockStatusEnum.NORMAL.getValue().equals(clockInStatus) - || BusAttendanceClockStatusEnum.REISSUE.getValue().equals(clockInStatus)) - && (BusAttendanceClockStatusEnum.NORMAL.getValue().equals(clockOutStatus) - || BusAttendanceClockStatusEnum.REISSUE.getValue().equals(clockOutStatus))) { - attendance++; - } else if (BusAttendanceClockStatusEnum.UNCLOCK.getValue().equals(clockInStatus) - && BusAttendanceClockStatusEnum.UNCLOCK.getValue().equals(clockOutStatus)) { - absenteeism++; - } else if (BusAttendanceClockStatusEnum.UNCLOCK.getValue().equals(clockInStatus) - || BusAttendanceClockStatusEnum.UNCLOCK.getValue().equals(clockOutStatus)) { - halfAttendance++; - } - } - } - resp.setAttendance(attendance); - resp.setHalfAttendance(halfAttendance); - resp.setAbsenteeism(absenteeism); - resp.setLeave(leave); - respList.add(resp); - } - // 按打卡日期正序排列 - respList.sort(Comparator.comparing(BusAttendanceClockDateForTwoWeekVo::getClockDate)); - return respList; - } - - /** - * 查询用户每月考勤列表 - * - * @param req 查询条件 - * @return 考勤列表 - */ - @Override - public List listAttendanceMonthListByUserId(BusAttendanceMonthByUserIdReq req) { - Long userId = req.getUserId(); - String clockMonth = req.getClockMonth(); - if (constructionUserService.getById(userId) == null) { - throw new ServiceException("施工人员信息不存在", HttpStatus.NOT_FOUND); - } - // 解析月份 - YearMonth yearMonth; - if (StringUtils.isNotBlank(clockMonth)) { - // 校验月份格式 - if (!DateConstant.YEAR_MONTH_PATTERN.matcher(clockMonth).matches()) { - throw new ServiceException("月份格式不正确", HttpStatus.BAD_REQUEST); - } - yearMonth = YearMonth.parse(clockMonth); - } else { - // 如果月份为空,则默认查询当前月份 - yearMonth = YearMonth.now(); - } - // 计算当月第一天 / 最后一天 - Date start = DateUtils.toDate(yearMonth.atDay(1)); - Date end = DateUtils.toDate(yearMonth.atEndOfMonth()); - // 查询当月考勤记录 - Map> dateListMap = this.lambdaQuery() - .eq(BusAttendance::getUserId, userId) - .between(BusAttendance::getClockDate, start, end) - .list() - .stream().collect(Collectors.groupingBy(BusAttendance::getClockDate)); - // 遍历每天,计算考勤状态 - List respList = new ArrayList<>(); - dateListMap.forEach((date, attendanceList) -> { - BusAttendanceMonthByUserIdVo resp = new BusAttendanceMonthByUserIdVo(); - resp.setId(userId); - resp.setClockDate(date); - List attendanceListByDayList = new ArrayList<>(); - String clockInStatus = null; - String clockOutStatus = null; - String clockAllDayStatus = null; - String status; - for (BusAttendance attendance : attendanceList) { - // 获取考勤记录 - BusAttendanceListByDay day = BusAttendanceListByDay.build(attendance); - attendanceListByDayList.add(day); - // 获取上下班状态 - if (BusAttendanceCommuterEnum.CLOCKIN.getValue().equals(attendance.getCommuter())) { - clockInStatus = attendance.getClockStatus(); - } else if (BusAttendanceCommuterEnum.CLOCKOUT.getValue().equals(attendance.getCommuter())) { - clockOutStatus = attendance.getClockStatus(); - } else { - clockAllDayStatus = attendance.getClockStatus(); - } - } - // 统计当天考勤状态 - if (BusAttendanceClockStatusEnum.LEAVE.getValue().equals(clockAllDayStatus)) { - return; - } else if (BusAttendanceClockStatusEnum.NORMAL.getValue().equals(clockInStatus) - && BusAttendanceClockStatusEnum.NORMAL.getValue().equals(clockOutStatus)) { - status = BusAttendanceStatusEnum.NORMAL.getValue(); - } else if (BusAttendanceClockStatusEnum.REISSUE.getValue().equals(clockInStatus) - || BusAttendanceClockStatusEnum.REISSUE.getValue().equals(clockOutStatus)) { - status = BusAttendanceStatusEnum.REISSUE.getValue(); - } else { - status = BusAttendanceStatusEnum.ERROR.getValue(); - } - resp.setStatus(status); - resp.setAttendanceList(attendanceListByDayList); - respList.add(resp); - }); - // 按打卡日期正序排列 - respList.sort(Comparator.comparing(BusAttendanceMonthByUserIdVo::getClockDate)); - return respList; + public TableDataInfo queryPageList(BusAttendanceBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); } /** * 查询符合条件的考勤列表 * - * @param req 查询条件 + * @param bo 查询条件 * @return 考勤列表 */ @Override - public List queryList(BusAttendanceQueryReq req) { - LambdaQueryWrapper lqw = buildQueryWrapper(req); - return this.list(lqw).stream().map(this::getVo).toList(); + public List queryList(BusAttendanceBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); } - /** - * 根据项目id查询出勤人列表 - * - * @param projectId 项目id - * @return 出勤人列表 - */ - @Override - public List listAttendancePeopleByProjectId(Long projectId) { - // 今天所有用户的打卡记录 - List attendanceList = this.lambdaQuery() - .eq(BusAttendance::getProjectId, projectId) - .eq(BusAttendance::getClockDate, DateUtils.dateTimeNow(FormatsType.YYYY_MM_DD)) - .list(); - if (CollUtil.isEmpty(attendanceList)) { - return List.of(); - } - Map> attendanceMap = attendanceList.stream() - .collect(Collectors.groupingBy(BusAttendance::getUserId)); - List attendedUserIds = new ArrayList<>(); - for (Map.Entry> entry : attendanceMap.entrySet()) { - Long userId = entry.getKey(); - List records = entry.getValue(); - // 要求必须有2条打卡记录 - if (records.size() != 2) { - continue; - } - boolean allValid = records.stream() - .allMatch(record -> ATTENDANCE_STATUS.contains(record.getClockStatus())); - if (allValid) { - attendedUserIds.add(userId); - } - } - return attendedUserIds; - } - - /** - * 获取考勤视图对象 - * - * @param attendance 考勤对象 - * @return 考勤视图对象 - */ - @Override - public BusAttendanceVo getVo(BusAttendance attendance) { - // 对象转封装类 - BusAttendanceVo attendanceVo = new BusAttendanceVo(); - if (attendance == null) { - return attendanceVo; - } - BeanUtils.copyProperties(attendance, attendanceVo); - return attendanceVo; - } - - /** - * 获取考勤查询条件封装 - * - * @param req 查询条件 - * @return 查询条件封装 - */ - @Override - public LambdaQueryWrapper buildQueryWrapper(BusAttendanceQueryReq req) { - LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); - if (req == null) { - return lqw; - } - String userName = req.getUserName(); - Long projectId = req.getProjectId(); - Long teamId = req.getTeamId(); - String clockStatus = req.getClockStatus(); - Date clockDate = req.getClockDate(); - // 联表查询 - if (ObjectUtils.isNotEmpty(teamId)) { - List projectTeamMemberList = projectTeamMemberService.lambdaQuery() - .eq(BusProjectTeamMember::getTeamId, teamId).list(); - List userIdList = projectTeamMemberList.stream().map(BusProjectTeamMember::getMemberId).toList(); - lqw.in(BusAttendance::getUserId, userIdList); - } - // 模糊查询 - lqw.like(StringUtils.isNotBlank(userName), BusAttendance::getUserName, userName); - // 精确查询 - lqw.eq(ObjectUtils.isNotEmpty(projectId), BusAttendance::getProjectId, projectId); - lqw.eq(StringUtils.isNotBlank(clockStatus), BusAttendance::getClockStatus, clockStatus); - lqw.eq(ObjectUtils.isNotEmpty(clockDate), BusAttendance::getClockDate, clockDate); - // 不包含请假的考勤记录 - lqw.ne(BusAttendance::getClockStatus, BusAttendanceClockStatusEnum.LEAVE.getValue()); + private LambdaQueryWrapper buildQueryWrapper(BusAttendanceBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(BusAttendance::getId); + lqw.eq(bo.getUserId() != null, BusAttendance::getUserId, bo.getUserId()); + lqw.eq(StringUtils.isNotBlank(bo.getFacePic()), BusAttendance::getFacePic, bo.getFacePic()); + lqw.eq(bo.getProjectId() != null, BusAttendance::getProjectId, bo.getProjectId()); + lqw.eq(bo.getClockDate() != null, BusAttendance::getClockDate, bo.getClockDate()); + lqw.eq(bo.getClockTime() != null, BusAttendance::getClockTime, bo.getClockTime()); + lqw.eq(StringUtils.isNotBlank(bo.getClockStatus()), BusAttendance::getClockStatus, bo.getClockStatus()); + lqw.eq(StringUtils.isNotBlank(bo.getClockType()), BusAttendance::getClockType, bo.getClockType()); + lqw.eq(StringUtils.isNotBlank(bo.getClockLocation()), BusAttendance::getClockLocation, bo.getClockLocation()); + lqw.eq(StringUtils.isNotBlank(bo.getLng()), BusAttendance::getLng, bo.getLng()); + lqw.eq(StringUtils.isNotBlank(bo.getLat()), BusAttendance::getLat, bo.getLat()); return lqw; } /** - * 获取考勤分页对象视图 + * 新增考勤 * - * @param attendancePage 考勤分页对象 - * @return 考勤分页对象视图 + * @param bo 考勤 + * @return 是否新增成功 */ @Override - public Page getVoPage(Page attendancePage) { - List attendanceList = attendancePage.getRecords(); - Page attendanceVoPage = new Page<>( - attendancePage.getCurrent(), - attendancePage.getSize(), - attendancePage.getTotal() - ); - if (CollUtil.isEmpty(attendanceList)) { - return attendanceVoPage; + public Boolean insertByBo(BusAttendanceBo bo) { + BusAttendance add = MapstructUtils.convert(bo, BusAttendance.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); } - List attendanceVoList = attendanceList.stream().map(this::getVo).toList(); - attendanceVoPage.setRecords(attendanceVoList); - return attendanceVoPage; + return flag; } /** - * 根据系统用户id和日期查询考勤 + * 修改考勤 * - * @param userId 用户id - * @param clockDate 日期 - * @return 考勤 + * @param bo 考勤 + * @return 是否修改成功 */ @Override - public List getDayByUserId(Long userId, Date clockDate) { - SubConstructionUser constructionUser = constructionUserService.getBySysUserId(userId); - // 当日期未指定时,默认为今天 - if (clockDate == null) { - clockDate = DateUtils.parseDateTime(FormatsType.YYYY_MM_DD, DateUtils.getDate()); + public Boolean updateByBo(BusAttendanceBo bo) { + BusAttendance update = MapstructUtils.convert(bo, BusAttendance.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(BusAttendance entity) { + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除考勤信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 } - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(BusAttendance::getUserId, constructionUser.getId()) - .eq(BusAttendance::getClockDate, clockDate); - return this.list(queryWrapper).stream().map(this::getVo).toList(); + return baseMapper.deleteByIds(ids) > 0; } /** @@ -454,22 +211,15 @@ public class BusAttendanceServiceImpl extends ServiceImpl punchranges = projectPunchrangeService.lambdaQuery() - .eq(BusProjectPunchrange::getProjectId, projectId) - .list(); - if (CollUtil.isEmpty(punchranges)) { - throw new ServiceException("项目未配置考勤范围", HttpStatus.BAD_REQUEST); - } - List punchRangeList = punchranges.stream().map(BusProjectPunchrange::getPunchRange).toList(); - List matchingRange = JSTUtil.findMatchingRange(lat, lng, punchRangeList); - if (matchingRange == null) { - throw new ServiceException("打卡位置不在范围内", HttpStatus.BAD_REQUEST); - } + constructionBlacklistService.validUserInBlacklist(constructionUser.getId(), req.getProjectId()); + // 进行人脸比对 Boolean result = constructionUserService.faceComparison(file); if (!result) { throw new ServiceException("人脸识别失败,请重新识别", HttpStatus.BAD_REQUEST); } - // 判断打卡状态 - String punchRange = project.getPunchRange(); - if (punchRange == null) { - throw new ServiceException("未设置打卡时间范围", HttpStatus.BAD_REQUEST); + + //打卡规则 + BusAttendanceRuleVo busAttendanceRuleVo = attendanceRuleService.queryByProjectId(req.getProjectId()); + + if (busAttendanceRuleVo == null) { + throw new ServiceException("未设置打卡规则", HttpStatus.BAD_REQUEST); } - String[] time = punchRange.split(","); - // 解析字符串为 LocalTime - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm"); - LocalTime startTime = LocalTime.parse(time[0], formatter); - LocalTime endTime = LocalTime.parse(time[1], formatter); - Date date = Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant()); + + // 考勤时间 + //确定考勤日期 + LocalDate localDate = calculateAttendanceDate(now, busAttendanceRuleVo); + // 判断当前用户打卡状态 List attendances = this.lambdaQuery() .eq(BusAttendance::getUserId, userId) - .eq(BusAttendance::getClockDate, date) + .eq(BusAttendance::getClockDate, localDate) .list(); BusAttendance attendance = new BusAttendance(); if (CollUtil.isEmpty(attendances)) { // 上班打卡 - attendance.setCommuter(BusAttendanceCommuterEnum.CLOCKIN.getValue()); - // 上传人脸照 - SysOssVo upload = ossService.upload(file); - attendance.setFacePic(upload.getOssId().toString()); + attendance.setClockType(BusAttendanceCommuterEnum.CLOCKIN.getValue()); // 判断是否为迟到 - if (now.isAfter(startTime)) { + if (isLate(now, busAttendanceRuleVo)) { attendance.setClockStatus(BusAttendanceClockStatusEnum.LATE.getValue()); } else { attendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue()); } - } else if (attendances.size() == 1 && attendances.getFirst().getCommuter().equals(BusAttendanceCommuterEnum.CLOCKIN.getValue())) { + } else if (attendances.size() == 1) { // 下班打卡 - attendance.setCommuter(BusAttendanceCommuterEnum.CLOCKOUT.getValue()); + attendance.setClockType(BusAttendanceCommuterEnum.CLOCKOUT.getValue()); // 判断是否为早退 - if (now.isBefore(endTime)) { + if (isLeaveEarly(now, busAttendanceRuleVo)) { attendance.setClockStatus(BusAttendanceClockStatusEnum.LEAVEEARLY.getValue()); } else { attendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue()); @@ -543,19 +279,185 @@ public class BusAttendanceServiceImpl extends ServiceImpl listAttendancePeopleByProjectId(Long projectId) { + // 今天所有用户的打卡记录 + List attendanceList = this.lambdaQuery() + .eq(BusAttendance::getProjectId, projectId) + .eq(BusAttendance::getClockDate, LocalDate.now()) + .list(); + if (CollUtil.isEmpty(attendanceList)) { + return List.of(); + } + Map> attendanceMap = attendanceList.stream() + .collect(Collectors.groupingBy(BusAttendance::getUserId)); + List attendedUserIds = new ArrayList<>(); + for (Map.Entry> entry : attendanceMap.entrySet()) { + Long userId = entry.getKey(); + List records = entry.getValue(); + + boolean allValid = records.stream() + .allMatch(record -> ATTENDANCE_STATUS.contains(record.getClockStatus())); + if (allValid) { + attendedUserIds.add(userId); + } + } + return attendedUserIds; + } + + + @Override + public List getPunchRangeByProjectIdAndUserId(Long projectId, Long userId) { + BusUserProjectRelevancy relevancy = userProjectRelevancyService.getOne(Wrappers.lambdaQuery(BusUserProjectRelevancy.class) + .eq(BusUserProjectRelevancy::getUserId, userId) + .eq(BusUserProjectRelevancy::getProjectId, projectId) + .last("limit 1")); + if (relevancy == null) { + throw new ServiceException("当前用户未加入项目", HttpStatus.BAD_REQUEST); + } + //判断是否是管理员 管理员返回项目全部打卡范围,施工人员返回班组打卡范围 + boolean isAdmin = "2".equals(relevancy.getUserType()); + List rangeIds = new ArrayList<>(); + if (!isAdmin) { + BusProjectTeamMember one = projectTeamMemberService.getOne(Wrappers.lambdaQuery(BusProjectTeamMember.class) + .eq(BusProjectTeamMember::getMemberId, userId) + .eq(BusProjectTeamMember::getProjectId, projectId) + .last("limit 1")); + if (one == null) { + throw new ServiceException("当前用户未加入班组", HttpStatus.BAD_REQUEST); + } + BusProjectTeam team = projectTeamService.getById(one.getTeamId()); + try { + JSONArray jsonArray = JSONUtil.parseArray(team.getPunchRange()); + rangeIds = jsonArray.toList(Long.class); + } catch (Exception e) { + + } + } + return projectPunchrangeService.lambdaQuery() + .in(CollectionUtil.isNotEmpty(rangeIds), BusProjectPunchrange::getId, rangeIds) + .eq(BusProjectPunchrange::getProjectId, projectId) + .list() + .stream() + .map(BusProjectPunchrange::getPunchRange) + .toList(); + } + + @Override + public Boolean checkInRange(BusAttendancePunchCardByFaceReq req) { + // 获取当前用户 + Long userId = LoginHelper.getUserId(); + List punchRangeList = getPunchRangeByProjectIdAndUserId(req.getProjectId(), userId); + if (CollUtil.isEmpty(punchRangeList)) { + throw new ServiceException("项目未配置考勤范围", HttpStatus.BAD_REQUEST); + } + List matchingRange = JSTUtil.findMatchingRange(req.getLat(), req.getLng(), punchRangeList); + return matchingRange != null; + } + + @Override + public List getTodayAttendance( Long projectId) { + + Long userId = LoginHelper.getUserId(); + BusAttendanceRuleVo busAttendanceRuleVo = attendanceRuleService.queryByProjectId(projectId); + + if (busAttendanceRuleVo == null) { + return List.of(); + } + + // 考勤时间 + //确定考勤日期 + LocalDate localDate = calculateAttendanceDate(LocalDateTime.now(), busAttendanceRuleVo); + + return baseMapper.selectVoList(new LambdaQueryWrapper() + .eq(BusAttendance::getUserId, userId) + .eq(BusAttendance::getClockDate, localDate) + ); + } + + /** + * 计算打卡时间归属的考勤日(关键:解决跨天场景的日期映射) + */ + private LocalDate calculateAttendanceDate(LocalDateTime checkTime, BusAttendanceRuleVo vo) { + LocalTime clockInTime = vo.getClockInTime(); + LocalTime clockOutResultTime = vo.getClockOutResultTime(); + + + //一共有四个节点即 上班-上下中间-下班-下上中间-第二天上班 + // 下上中间 就是日期分割点 + + // 跨天场景:以切换小时为界(如3点) + LocalDateTime checkDateSwitchPoint = LocalDateTime.of(checkTime.toLocalDate(), clockOutResultTime); + + if (clockOutResultTime.isBefore(clockInTime)) { + return checkTime.isBefore(checkDateSwitchPoint) + ? checkTime.toLocalDate().minusDays(1) + : checkTime.toLocalDate(); + } + if (clockOutResultTime.isAfter(clockInTime)) { + return checkTime.isBefore(checkDateSwitchPoint) + ? checkTime.toLocalDate() + : checkTime.toLocalDate().plusDays(1); + } + return null; + } + + /** + * 判断是否迟到 + */ + private Boolean isLate(LocalDateTime checkTime, BusAttendanceRuleVo vo) { + + long clockInSeconds = vo.getClockInTime().toSecondOfDay(); + long clockInResultSeconds = vo.getClockInResultTime().toSecondOfDay(); + + + if (vo.getClockInResultTime().isBefore(vo.getClockInTime())) { + clockInResultSeconds += 24 * 60 * 60; // 加24小时的秒数 + } + + + long localTime = checkTime.toLocalTime().toSecondOfDay(); + + return localTime > clockInSeconds && localTime < clockInResultSeconds; + } + + /** + * 判断是否早退 + */ + private Boolean isLeaveEarly(LocalDateTime checkTime, BusAttendanceRuleVo vo) { + long clockOutSeconds = vo.getClockOutTime().toSecondOfDay(); + long clockOutResultSeconds = vo.getClockOutResultTime().toSecondOfDay(); + + if (vo.getClockOutResultTime().isBefore(vo.getClockOutTime())) { + clockOutResultSeconds += 24 * 60 * 60; // 加24小时的秒数 + } + + + long localTime = checkTime.toLocalTime().toSecondOfDay(); + + return !(localTime > clockOutSeconds && localTime < clockOutResultSeconds); + + } + } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusLeaveServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusLeaveServiceImpl.java index 32681119..04e24845 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusLeaveServiceImpl.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusLeaveServiceImpl.java @@ -217,18 +217,18 @@ public class BusLeaveServiceImpl extends ServiceImpl Long projectId = oldLeave.getProjectId(); // 遍历每一天 List attendanceList = new ArrayList<>(); - for (long i = 0; i < day; i++) { - BusAttendance attendance = new BusAttendance(); - attendance.setUserId(userId); - attendance.setUserName(userName); - attendance.setProjectId(projectId); - Date date = DateUtils.addDays(startTime, (int) i); - attendance.setLeaveId(id); - attendance.setClockDate(date); - attendance.setClockStatus(BusAttendanceClockStatusEnum.LEAVE.getValue()); - attendance.setCommuter(BusAttendanceCommuterEnum.ALLDAY.getValue()); - attendanceList.add(attendance); - } +// for (long i = 0; i < day; i++) { +// BusAttendance attendance = new BusAttendance(); +// attendance.setUserId(userId); +// attendance.setUserName(userName); +// attendance.setProjectId(projectId); +// Date date = DateUtils.addDays(startTime, (int) i); +// attendance.setLeaveId(id); +// attendance.setClockDate(date); +// attendance.setClockStatus(BusAttendanceClockStatusEnum.LEAVE.getValue()); +// attendance.setCommuter(BusAttendanceCommuterEnum.ALLDAY.getValue()); +// attendanceList.add(attendance); +// } boolean saveBatch = attendanceService.saveBatch(attendanceList); if (!saveBatch) { throw new ServiceException("更新考勤记录失败", HttpStatus.ERROR); diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusReissueCardServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusReissueCardServiceImpl.java index ddeddc8f..dae9aef3 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusReissueCardServiceImpl.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusReissueCardServiceImpl.java @@ -99,59 +99,59 @@ public class BusReissueCardServiceImpl extends ServiceImpl + + + +