From 697beb67c494fb77239c152842f887aa3ddee053 Mon Sep 17 00:00:00 2001 From: zt Date: Wed, 10 Sep 2025 17:34:49 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=9A=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- xinnengyuan/pom.xml | 1 - .../web/controller/AuthController.java | 8 +- .../impl/DesVolumeFileServiceImpl.java | 24 +-- .../job/attendance/AttendanceJobUtil.java | 182 ++++++++++++++++++ .../job/attendance/AttendanceReminderJob.java | 109 +++++++++++ .../project/domain/BusAttendanceRule.java | 9 + .../impl/BusAttendanceRuleServiceImpl.java | 10 +- .../impl/BusAttendanceServiceImpl.java | 6 + 8 files changed, 331 insertions(+), 18 deletions(-) create mode 100644 xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/attendance/AttendanceJobUtil.java create mode 100644 xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/attendance/AttendanceReminderJob.java diff --git a/xinnengyuan/pom.xml b/xinnengyuan/pom.xml index 4499b51c..56b6c6d4 100644 --- a/xinnengyuan/pom.xml +++ b/xinnengyuan/pom.xml @@ -307,7 +307,6 @@ snail-job-client-job-core ${snailjob.version} - org.bouncycastle diff --git a/xinnengyuan/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java b/xinnengyuan/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java index c2fd3709..3c4674d4 100644 --- a/xinnengyuan/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java +++ b/xinnengyuan/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java @@ -107,10 +107,10 @@ public class AuthController { // 登录 LoginVo loginVo = IAuthStrategy.login(body, client, grantType); - Long userId = LoginHelper.getUserId(); - scheduledExecutorService.schedule(() -> { - chatGroupService.createSystem(userId,client.getClientKey()); - }, 5, TimeUnit.SECONDS); +// Long userId = LoginHelper.getUserId(); +// scheduledExecutorService.schedule(() -> { +// chatGroupService.createSystem(userId,client.getClientKey()); +// }, 5, TimeUnit.SECONDS); return R.ok(loginVo); } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/impl/DesVolumeFileServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/impl/DesVolumeFileServiceImpl.java index a799d375..3bc306bf 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/impl/DesVolumeFileServiceImpl.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/impl/DesVolumeFileServiceImpl.java @@ -271,18 +271,18 @@ public class DesVolumeFileServiceImpl extends ServiceImpl existingFiles = baseMapper.selectList(new LambdaQueryWrapper() - .eq(DesVolumeFile::getVolumeCatalogId, req.getVolumeCatalogId()) - .eq(DesVolumeFile::getType, DesVolumeFile.PROCESS) - .orderByDesc(DesVolumeFile::getVersion)); - if (!existingFiles.isEmpty()) { - DesVolumeFile first = existingFiles.getFirst(); - if (!BusinessStatusEnum.FINISH.getStatus().equals(first.getAuditStatus())) { - throw new ServiceException("文件尚未审核完成,请勿重复上传"); - } - } - } +// if (CollectionUtil.isNotEmpty(req.getCancellationIds())) { +// List existingFiles = baseMapper.selectList(new LambdaQueryWrapper() +// .eq(DesVolumeFile::getVolumeCatalogId, req.getVolumeCatalogId()) +// .eq(DesVolumeFile::getType, DesVolumeFile.PROCESS) +// .orderByDesc(DesVolumeFile::getVersion)); +// if (!existingFiles.isEmpty()) { +// DesVolumeFile first = existingFiles.getFirst(); +// if (!BusinessStatusEnum.FINISH.getStatus().equals(first.getAuditStatus())) { +// throw new ServiceException("文件尚未审核完成,请勿重复上传"); +// } +// } +// } } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/attendance/AttendanceJobUtil.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/attendance/AttendanceJobUtil.java new file mode 100644 index 00000000..55742223 --- /dev/null +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/attendance/AttendanceJobUtil.java @@ -0,0 +1,182 @@ +package org.dromara.job.attendance; + +import com.aizuda.snailjob.client.job.core.enums.AllocationAlgorithmEnum; +import com.aizuda.snailjob.client.job.core.enums.TriggerTypeEnum; +import com.aizuda.snailjob.client.job.core.openapi.SnailJobOpenApi; +import com.aizuda.snailjob.common.core.enums.BlockStrategyEnum; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.project.domain.BusAttendanceRule; +import org.dromara.project.domain.BusProject; +import org.dromara.project.service.IBusAttendanceRuleService; +import org.dromara.project.service.IBusProjectService; +import org.springframework.context.annotation.Lazy; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import java.time.LocalTime; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Slf4j +@Component +public class AttendanceJobUtil { + + public static final String CLOCK_IN_REMINDER = "clockInReminder"; + + public static final String CLOCK_OUT_REMINDER = "clockOutReminder"; + + @Resource + private IBusProjectService projectService; + + @Resource + @Lazy + private IBusAttendanceRuleService attendanceRuleService; + + @Async + public void addClusterJob(BusAttendanceRule rule) { + + BusProject project = projectService.getById(rule.getProjectId()); + String projectName = project.getProjectName(); + + String jobName1 = projectName + "上班打卡提醒"; + LocalTime clockInTime = rule.getClockInTime(); + //提前10分钟 + LocalTime clockInReminderTime = clockInTime.minusMinutes(10); + String dailyCron1 = toDailyCron(clockInReminderTime); + + Long execute1 = SnailJobOpenApi.addClusterJob() + .setRouteKey(AllocationAlgorithmEnum.RANDOM) + .setJobName(jobName1) + .setExecutorInfo(CLOCK_IN_REMINDER) + .setExecutorTimeout(30) + .setDescription("add") + .setBlockStrategy(BlockStrategyEnum.DISCARD) + .setMaxRetryTimes(1) + .setTriggerType(TriggerTypeEnum.CRON) + .setTriggerInterval(dailyCron1) + .addArgsStr("projectId", rule.getProjectId()) + .setRetryInterval(3) + .execute(); + rule.setClockInJobId(execute1); + + + String jobName2 = projectName + "下班打卡提醒"; + LocalTime clockOutTime = rule.getClockOutTime(); + //后延10分钟 + LocalTime clockOutReminderTime = clockOutTime.plusMinutes(10); + String dailyCron2 = toDailyCron(clockOutReminderTime); + + + Long execute = SnailJobOpenApi.addClusterJob() + .setRouteKey(AllocationAlgorithmEnum.RANDOM) + .setJobName(jobName2) + .setExecutorInfo(CLOCK_OUT_REMINDER) + .setExecutorTimeout(30) + .setDescription("add") + .setBlockStrategy(BlockStrategyEnum.DISCARD) + .setMaxRetryTimes(1) + .setTriggerType(TriggerTypeEnum.CRON) + .setTriggerInterval(dailyCron2) + .addArgsStr("projectId", rule.getProjectId()) + .setRetryInterval(3) + .execute(); + rule.setClockOutJobId(execute); + + attendanceRuleService.updateById(rule); + } + + + @Async + public void updateClusterJob(Long id) { + BusAttendanceRule rule = attendanceRuleService.getById(id); + BusProject project = projectService.getById(rule.getProjectId()); + String projectName = project.getProjectName(); + + LocalTime clockInTime = rule.getClockInTime(); + //提前10分钟 + LocalTime clockInReminderTime = clockInTime.minusMinutes(10); + String dailyCron1 = toDailyCron(clockInReminderTime); + + if (rule.getClockInJobId() != null) { + SnailJobOpenApi.updateClusterJob(rule.getClockInJobId()) + .setTriggerType(TriggerTypeEnum.CRON) + .setTriggerInterval(dailyCron1) + .execute(); + } else { + String jobName1 = projectName + "上班打卡提醒"; + Long execute = SnailJobOpenApi.addClusterJob() + .setRouteKey(AllocationAlgorithmEnum.RANDOM) + .setJobName(jobName1) + .setExecutorInfo(CLOCK_IN_REMINDER) + .setExecutorTimeout(30) + .setDescription("add") + .setBlockStrategy(BlockStrategyEnum.DISCARD) + .setMaxRetryTimes(1) + .setTriggerType(TriggerTypeEnum.CRON) + .setTriggerInterval(dailyCron1) + .addArgsStr("projectId", rule.getProjectId()) + .setRetryInterval(3) + .execute(); + rule.setClockInJobId(execute); + } + + + LocalTime clockOutTime = rule.getClockOutTime(); + //后延10分钟 + LocalTime clockOutReminderTime = clockOutTime.plusMinutes(10); + String dailyCron2 = toDailyCron(clockOutReminderTime); + + if (rule.getClockOutJobId() != null) { + SnailJobOpenApi.updateClusterJob(rule.getClockOutJobId()) + .setTriggerType(TriggerTypeEnum.CRON) + .setTriggerInterval(dailyCron2) + .execute(); + } else { + String jobName2 = projectName + "下班打卡提醒"; + Long execute = SnailJobOpenApi.addClusterJob() + .setRouteKey(AllocationAlgorithmEnum.RANDOM) + .setJobName(jobName2) + .setExecutorInfo(CLOCK_OUT_REMINDER) + .setExecutorTimeout(30) + .setDescription("add") + .setBlockStrategy(BlockStrategyEnum.DISCARD) + .setMaxRetryTimes(1) + .setTriggerType(TriggerTypeEnum.CRON) + .setTriggerInterval(dailyCron2) + .addArgsStr("projectId", rule.getProjectId()) + .setRetryInterval(3) + .execute(); + rule.setClockOutJobId(execute); + } + attendanceRuleService.updateById(rule); + } + + @Async + public void deleteClusterJob(List rules) { + Set jobIds = rules.stream() + .flatMap(rule -> Stream.of(rule.getClockInJobId(), rule.getClockOutJobId())) // 提取两个 JobId + .filter(Objects::nonNull) // 过滤掉 null 值 + .collect(Collectors.toSet()); // 收集 + rules.stream().map(BusAttendanceRule::getClockInJobId).filter(Objects::nonNull).forEach(jobIds::add); + SnailJobOpenApi.deleteJob(jobIds).execute(); + } + + + /** + * 将LocalTime转换为每天执行的Cron表达式 + * + * @param time 时间 + * @return 每天在指定时间执行的Cron表达式 + */ + public String toDailyCron(LocalTime time) { + int hour = time.getHour(); + int minute = time.getMinute(); + + // Cron格式: 秒 分 时 日 月 周 年(可选) + return String.format("0 %d %d * * ?", minute, hour); + } +} diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/attendance/AttendanceReminderJob.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/attendance/AttendanceReminderJob.java new file mode 100644 index 00000000..dbcee0e1 --- /dev/null +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/attendance/AttendanceReminderJob.java @@ -0,0 +1,109 @@ +package org.dromara.job.attendance; + + +import cn.hutool.json.JSONUtil; +import com.aizuda.snailjob.client.job.core.annotation.JobExecutor; +import com.aizuda.snailjob.client.job.core.dto.JobArgs; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.contractor.domain.SubConstructionUser; +import org.dromara.contractor.service.ISubConstructionUserService; +import org.dromara.project.domain.BusAttendanceRule; +import org.dromara.project.domain.BusProject; +import org.dromara.project.domain.BusUserProjectRelevancy; +import org.dromara.project.service.IBusAttendanceRuleService; +import org.dromara.project.service.IBusProjectService; +import org.dromara.project.service.IBusUserProjectRelevancyService; +import org.dromara.websocket.ChatServerHandler; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +@Slf4j +@Component +public class AttendanceReminderJob { + + @Resource + private IBusUserProjectRelevancyService userProjectRelevancyService; + + @Resource + private ChatServerHandler chatServerHandler; + + @Resource + private IBusProjectService projectService; + + @Resource + private IBusAttendanceRuleService attendanceRuleService; + + @Resource + private ISubConstructionUserService constructionUserService; + + @JobExecutor(name = "clockInReminder") + public void clockInReminder(JobArgs jobArgs) { + Long projectId = JSONUtil.parseObj(jobArgs.getJobParams()).getLong("projectId"); + log.info("项目ID:{},开始执行打卡提醒任务", projectId); + + BusProject project = projectService.getById(projectId); + + BusAttendanceRule rule = attendanceRuleService.getOne(Wrappers.lambdaQuery() + .eq(BusAttendanceRule::getProjectId, projectId) + .last("limit 1") + ); + + if (rule == null || project == null) { + return; + } + + //查询项目下的关联人员 + List relevancyList = userProjectRelevancyService.list(Wrappers.lambdaQuery(BusUserProjectRelevancy.class) + .eq(BusUserProjectRelevancy::getProjectId, projectId)); + String message = String.format("【%s项目】上班打卡提醒!请在 %s 前完成打卡。", + project.getProjectName(), rule.getClockInTime().toString()); + Set collect = relevancyList.stream().map(BusUserProjectRelevancy::getUserId).collect(Collectors.toSet()); + + List list = constructionUserService.list(Wrappers.lambdaQuery(SubConstructionUser.class) + .in(SubConstructionUser::getSysUserId, collect)); + Set list1 = list.stream().map(SubConstructionUser::getSysUserId).collect(Collectors.toSet()); + + for (Long userId : list1) { + chatServerHandler.sendSystemMessageToUser(userId, message); + } + } + + @JobExecutor(name = "clockOutReminder") + public void clockOutReminder(JobArgs jobArgs) { + Long projectId = JSONUtil.parseObj(jobArgs.getJobParams()).getLong("projectId"); + log.info("项目ID:{},开始执行打卡提醒任务", projectId); + + BusProject project = projectService.getById(projectId); + + BusAttendanceRule rule = attendanceRuleService.getOne(Wrappers.lambdaQuery() + .eq(BusAttendanceRule::getProjectId, projectId) + .last("limit 1") + ); + + if (rule == null || project == null) { + return; + } + + //查询项目下的关联人员 + List relevancyList = userProjectRelevancyService.list(Wrappers.lambdaQuery(BusUserProjectRelevancy.class) + .eq(BusUserProjectRelevancy::getProjectId, projectId)); + String message = String.format("【%s项目】下班打卡提醒!请记得完成打卡。", + project.getProjectName()); + Set collect = relevancyList.stream().map(BusUserProjectRelevancy::getUserId).collect(Collectors.toSet()); + + List list = constructionUserService.list(Wrappers.lambdaQuery(SubConstructionUser.class) + .in(SubConstructionUser::getSysUserId, collect)); + Set list1 = list.stream().map(SubConstructionUser::getSysUserId).collect(Collectors.toSet()); + + for (Long userId : list1) { + chatServerHandler.sendSystemMessageToUser(userId, message); + } + } + + +} 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 index 125fa334..b9286e95 100644 --- 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 @@ -92,5 +92,14 @@ public class BusAttendanceRule extends BaseEntity { */ private String type; + /** + * 上班打卡提醒定时任务ID + */ + private Long clockInJobId; + + /** + * 下班打卡提醒定时任务ID + */ + private Long clockOutJobId; } 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 index cf0c57d6..36c6ffdd 100644 --- 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 @@ -10,6 +10,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.dromara.job.attendance.AttendanceJobUtil; import org.springframework.stereotype.Service; import org.dromara.project.domain.bo.BusAttendanceRuleBo; import org.dromara.project.domain.vo.BusAttendanceRuleVo; @@ -35,6 +36,7 @@ public class BusAttendanceRuleServiceImpl extends ServiceImpl 0; + int i = baseMapper.updateById(update); + attendanceJobUtil.updateClusterJob(bo.getId()); + return i> 0; } /** @@ -208,6 +213,9 @@ public class BusAttendanceRuleServiceImpl extends ServiceImpl busAttendanceRules = baseMapper.selectList(Wrappers.lambdaQuery() + .in(BusAttendanceRule::getId, ids)); + attendanceJobUtil.deleteClusterJob(busAttendanceRules); return baseMapper.deleteByIds(ids) > 0; } 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 c1c15829..c0a9dd71 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 @@ -42,6 +42,7 @@ import org.dromara.system.domain.vo.SysOssVo; import org.dromara.system.domain.vo.SysUserVo; import org.dromara.system.service.ISysOssService; import org.dromara.system.service.ISysUserService; +import org.dromara.websocket.ChatServerHandler; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; @@ -92,6 +93,8 @@ public class BusAttendanceServiceImpl extends ServiceImpl ATTENDANCE_STATUS = new HashSet<>(Arrays.asList(BusAttendanceClockStatusEnum.NORMAL.getValue(), BusAttendanceClockStatusEnum.LATE.getValue(), BusAttendanceClockStatusEnum.LEAVEEARLY.getValue())); @@ -303,7 +306,10 @@ public class BusAttendanceServiceImpl extends ServiceImpl