From 5f6fc4216be7ddde07d7b5b5242cf46ac5f2fb5c Mon Sep 17 00:00:00 2001 From: andy <1042025947@qq.com> Date: Mon, 29 Jun 2026 14:36:00 +0800 Subject: [PATCH] =?UTF-8?q?=E9=92=89=E9=92=89=E4=B8=9A=E5=8A=A1=E8=9E=8D?= =?UTF-8?q?=E5=90=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- evo-admin/pom.xml | 27 +- .../src/main/java/com/evo/EvoApplication.java | 2 + .../controller/RzAttendanceController.java | 13 + .../evo/attendance/domain/RzAttendance.java | 4 + ...unchTheClockStrategyExchangeProcessor.java | 9 +- .../impl/KQDeviceExchangeProcessor.java | 1 - .../service/IRzAttendanceService.java | 16 +- .../service/IRzSpecialAttendanceService.java | 7 +- .../impl/RzAttendanceDetailServiceImpl.java | 5 - .../service/impl/RzAttendanceServiceImpl.java | 219 +++++++++- .../RzAttendanceStatisticalServiceImpl.java | 11 +- .../impl/RzSpecialAttendanceServiceImpl.java | 8 +- .../service/impl/RzSysParamServiceImpl.java | 4 +- .../com/evo/common/async/AsyncConfig.java | 52 +++ .../thread/DynamicThreadPoolConfig.java | 73 ++++ .../config/thread/ThreadPoolManager.java | 39 ++ .../config/thread/ThreadPoolProperties.java | 26 ++ .../com/evo/common/constant/Constants.java | 5 + .../common/controller/CallbackController.java | 113 +++++ .../evo/common/controller/TestController.java | 219 +++++++++- .../common/core/domain/entity/SysDept.java | 2 + .../common/function/FourParamFunction.java | 14 + .../thread/RzAttendanceBatchHandler.java | 119 ++++++ .../java/com/evo/common/utils/ParamUtils.java | 29 +- .../com/evo/common/utils/SecurityUtils.java | 7 +- .../com/evo/common/utils/http/HttpUtils.java | 69 ++- .../java/com/evo/ding/DingCallbackCrypto.java | 400 ++++++++++++++++++ .../java/com/evo/ding/DingGlobalParams.java | 91 ++++ .../src/main/java/com/evo/ding/DingUtils.java | 316 ++++++++++++++ .../java/com/evo/ding/domain/DingGroup.java | 25 ++ .../java/com/evo/ding/domain/DingShift.java | 33 ++ .../com/evo/ding/domain/DingShiftGroup.java | 35 ++ .../com/evo/ding/mapper/DingGroupMapper.java | 19 + .../evo/ding/mapper/DingShiftGroupMapper.java | 24 ++ .../com/evo/ding/mapper/DingShiftMapper.java | 24 ++ .../processor/DingBasicExchangeProcessor.java | 108 +++++ ...eApproveStatusChangeExchangeProcessor.java | 60 +++ .../ApproveStatusLeaveExchangeProcessor.java | 127 ++++++ .../ApproveStatusOutExchangeProcessor.java | 127 ++++++ ...pproveStatusOvertimeExchangeProcessor.java | 119 ++++++ .../DingCallBackExchangeProcessor.java | 37 ++ ...kApproveStatusChangeExchangeProcessor.java | 49 +++ ...gCallBackCheckRecordExchangeProcessor.java | 44 ++ ...gCallBackGroupChangeExchangeProcessor.java | 113 +++++ ...llBackInstanceChangeExchangeProcessor.java | 41 ++ ...gCallBackShiftChangeExchangeProcessor.java | 69 +++ ...gCallBackUseLeaveOrgExchangeProcessor.java | 41 ++ ...ngCallBackUserAddOrgExchangeProcessor.java | 44 ++ .../InstanceChangeExchangeProcessor.java | 32 ++ ...ceChangeRechargeCardExchangeProcessor.java | 78 ++++ .../evo/ding/service/DingGroupService.java | 18 + .../ding/service/DingShiftGroupService.java | 26 ++ .../evo/ding/service/DingShiftService.java | 22 + .../service/impl/DingGroupServiceImpl.java | 26 ++ .../impl/DingShiftGroupServiceImpl.java | 41 ++ .../service/impl/DingShiftServiceImpl.java | 33 ++ .../controller/RzSalaryDetailController.java | 400 ------------------ .../evo/finance/domain/RzSalaryDetail.java | 21 + .../finance/mapper/RzSalaryDetailMapper.java | 4 + ...yCalculationStrategyExchangeProcessor.java | 5 +- ...onthlySalaryStrategyExchangeProcessor.java | 15 +- .../service/IRzSalaryDetailService.java | 3 + .../impl/RzSalaryDetailServiceImpl.java | 76 +++- .../evo/framework/config/SecurityConfig.java | 2 + .../domain/RzLeaveDetail.java | 3 +- .../personnelMatters/domain/RzOverTime.java | 2 + .../mapper/RzLeaveDetailMapper.java | 2 + .../mapper/RzLeaveMapper.java | 6 + .../service/IRzLeaveDetailService.java | 3 + .../service/IRzLeaveService.java | 8 + .../service/IRzOverTimeDetailService.java | 3 +- .../service/IRzOverTimeService.java | 12 +- .../impl/RzLeaveDetailServiceImpl.java | 15 +- .../service/impl/RzLeaveServiceImpl.java | 8 +- .../impl/RzOverTimeDetailServiceImpl.java | 3 +- .../service/impl/RzOverTimeServiceImpl.java | 77 ++++ .../RzRestaurantDetailController.java | 7 +- .../RzRestaurantStatisticsServiceImpl.java | 4 +- .../system/controller/ShiftController.java | 55 +++ .../system/controller/SysStaffController.java | 9 + .../java/com/evo/system/domain/SysStaff.java | 4 + .../com/evo/system/mapper/SysDeptMapper.java | 5 + .../com/evo/system/mapper/SysStaffMapper.java | 10 + .../system/service/ISysDictDataService.java | 10 +- .../evo/system/service/ISysStaffService.java | 26 +- .../service/impl/SysDictDataServiceImpl.java | 5 + .../service/impl/SysStaffServiceImpl.java | 206 ++++++++- .../src/main/resources/application-dev.yml | 2 +- .../src/main/resources/application-local.yml | 4 +- evo-admin/src/main/resources/application.yml | 25 ++ .../resources/mapper/ding/DingGroupMapper.xml | 21 + .../mapper/ding/DingShiftGroupMapper.xml | 107 +++++ .../resources/mapper/ding/DingShiftMapper.xml | 94 ++++ .../mapper/finance/RzSalaryDetailMapper.xml | 14 +- .../personnelMatters/RzLeaveDetailMapper.xml | 5 +- .../mapper/personnelMatters/RzLeaveMapper.xml | 6 + .../resources/mapper/system/SysDeptMapper.xml | 20 +- .../mapper/system/SysStaffMapper.xml | 23 +- 98 files changed, 4167 insertions(+), 478 deletions(-) create mode 100644 evo-admin/src/main/java/com/evo/common/async/AsyncConfig.java create mode 100644 evo-admin/src/main/java/com/evo/common/config/thread/DynamicThreadPoolConfig.java create mode 100644 evo-admin/src/main/java/com/evo/common/config/thread/ThreadPoolManager.java create mode 100644 evo-admin/src/main/java/com/evo/common/config/thread/ThreadPoolProperties.java create mode 100644 evo-admin/src/main/java/com/evo/common/controller/CallbackController.java create mode 100644 evo-admin/src/main/java/com/evo/common/function/FourParamFunction.java create mode 100644 evo-admin/src/main/java/com/evo/common/handler/thread/RzAttendanceBatchHandler.java create mode 100644 evo-admin/src/main/java/com/evo/ding/DingCallbackCrypto.java create mode 100644 evo-admin/src/main/java/com/evo/ding/DingGlobalParams.java create mode 100644 evo-admin/src/main/java/com/evo/ding/DingUtils.java create mode 100644 evo-admin/src/main/java/com/evo/ding/domain/DingGroup.java create mode 100644 evo-admin/src/main/java/com/evo/ding/domain/DingShift.java create mode 100644 evo-admin/src/main/java/com/evo/ding/domain/DingShiftGroup.java create mode 100644 evo-admin/src/main/java/com/evo/ding/mapper/DingGroupMapper.java create mode 100644 evo-admin/src/main/java/com/evo/ding/mapper/DingShiftGroupMapper.java create mode 100644 evo-admin/src/main/java/com/evo/ding/mapper/DingShiftMapper.java create mode 100644 evo-admin/src/main/java/com/evo/ding/processor/DingBasicExchangeProcessor.java create mode 100644 evo-admin/src/main/java/com/evo/ding/processor/approveStatus/AttendanceApproveStatusChangeExchangeProcessor.java create mode 100644 evo-admin/src/main/java/com/evo/ding/processor/approveStatus/impl/ApproveStatusLeaveExchangeProcessor.java create mode 100644 evo-admin/src/main/java/com/evo/ding/processor/approveStatus/impl/ApproveStatusOutExchangeProcessor.java create mode 100644 evo-admin/src/main/java/com/evo/ding/processor/approveStatus/impl/ApproveStatusOvertimeExchangeProcessor.java create mode 100644 evo-admin/src/main/java/com/evo/ding/processor/callback/DingCallBackExchangeProcessor.java create mode 100644 evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackApproveStatusChangeExchangeProcessor.java create mode 100644 evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackCheckRecordExchangeProcessor.java create mode 100644 evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackGroupChangeExchangeProcessor.java create mode 100644 evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackInstanceChangeExchangeProcessor.java create mode 100644 evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackShiftChangeExchangeProcessor.java create mode 100644 evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackUseLeaveOrgExchangeProcessor.java create mode 100644 evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackUserAddOrgExchangeProcessor.java create mode 100644 evo-admin/src/main/java/com/evo/ding/processor/instance/InstanceChangeExchangeProcessor.java create mode 100644 evo-admin/src/main/java/com/evo/ding/processor/instance/impl/InstanceChangeRechargeCardExchangeProcessor.java create mode 100644 evo-admin/src/main/java/com/evo/ding/service/DingGroupService.java create mode 100644 evo-admin/src/main/java/com/evo/ding/service/DingShiftGroupService.java create mode 100644 evo-admin/src/main/java/com/evo/ding/service/DingShiftService.java create mode 100644 evo-admin/src/main/java/com/evo/ding/service/impl/DingGroupServiceImpl.java create mode 100644 evo-admin/src/main/java/com/evo/ding/service/impl/DingShiftGroupServiceImpl.java create mode 100644 evo-admin/src/main/java/com/evo/ding/service/impl/DingShiftServiceImpl.java create mode 100644 evo-admin/src/main/java/com/evo/system/controller/ShiftController.java create mode 100644 evo-admin/src/main/resources/mapper/ding/DingGroupMapper.xml create mode 100644 evo-admin/src/main/resources/mapper/ding/DingShiftGroupMapper.xml create mode 100644 evo-admin/src/main/resources/mapper/ding/DingShiftMapper.xml diff --git a/evo-admin/pom.xml b/evo-admin/pom.xml index 170d4fc..dbd11ca 100644 --- a/evo-admin/pom.xml +++ b/evo-admin/pom.xml @@ -17,6 +17,26 @@ + + com.github.ulisesbocchio + jasypt-spring-boot-starter + 3.0.5 + + + + + + com.aliyun + dingtalk + 2.2.43 + + + + com.aliyun + alibaba-dingtalk-service-sdk + 2.0.0 + + com.baomidou mybatis-plus-boot-starter @@ -223,7 +243,6 @@ system ${project.basedir}/src/main/resources/lib/k3cloud-webapi-sdk-java11-v8.2.0.jar - com.google.code.gson gson @@ -241,6 +260,12 @@ org.springframework.boot spring-boot-starter-thymeleaf + + org.springframework.boot + spring-boot-test + 3.3.3 + test + diff --git a/evo-admin/src/main/java/com/evo/EvoApplication.java b/evo-admin/src/main/java/com/evo/EvoApplication.java index d9284f8..d39027e 100644 --- a/evo-admin/src/main/java/com/evo/EvoApplication.java +++ b/evo-admin/src/main/java/com/evo/EvoApplication.java @@ -4,6 +4,7 @@ import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; /** @@ -14,6 +15,7 @@ import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) @EnableScheduling @MapperScan({"com.evo.**.mapper.**.**"}) +@EnableAsync // 开启异步支持 public class EvoApplication { public static void main(String[] args) diff --git a/evo-admin/src/main/java/com/evo/attendance/controller/RzAttendanceController.java b/evo-admin/src/main/java/com/evo/attendance/controller/RzAttendanceController.java index 2ed910c..c4dde46 100644 --- a/evo-admin/src/main/java/com/evo/attendance/controller/RzAttendanceController.java +++ b/evo-admin/src/main/java/com/evo/attendance/controller/RzAttendanceController.java @@ -125,4 +125,17 @@ public class RzAttendanceController extends BaseController { return success(rzAttendanceDetailService.selectListByAttendanceId(id)); } + + @Log(title = "考勤记录重新抓取", businessType = BusinessType.UPDATE) + @GetMapping(value = "/load/{id}") + public AjaxResult loadAttendance(@PathVariable("id") Long id){ + return success(rzAttendanceService.loadAttendance(id)); + } + + @Log(title = "考勤记录全部重新抓取", businessType = BusinessType.UPDATE) + @PutMapping(value = "/load/all") + public AjaxResult loadAllAttendance(@RequestBody RzAttendance rzAttendance) + { + return rzAttendanceService.loadAllAttendance(rzAttendance); + } } diff --git a/evo-admin/src/main/java/com/evo/attendance/domain/RzAttendance.java b/evo-admin/src/main/java/com/evo/attendance/domain/RzAttendance.java index 4644bbc..995421d 100644 --- a/evo-admin/src/main/java/com/evo/attendance/domain/RzAttendance.java +++ b/evo-admin/src/main/java/com/evo/attendance/domain/RzAttendance.java @@ -120,5 +120,9 @@ public class RzAttendance extends BaseEntity { private Date startTime; @TableField(exist = false) private Date endTime; + /*** + * 补卡扣款 + */ + private BigDecimal debiting; } diff --git a/evo-admin/src/main/java/com/evo/attendance/processor/PunchTheClockStrategyExchangeProcessor.java b/evo-admin/src/main/java/com/evo/attendance/processor/PunchTheClockStrategyExchangeProcessor.java index 2112b4c..e2b55c6 100644 --- a/evo-admin/src/main/java/com/evo/attendance/processor/PunchTheClockStrategyExchangeProcessor.java +++ b/evo-admin/src/main/java/com/evo/attendance/processor/PunchTheClockStrategyExchangeProcessor.java @@ -76,7 +76,14 @@ public interface PunchTheClockStrategyExchangeProcessor { return ""; } - default String initMessage(Integer result, String meg){ + + + default String initMessage(Integer result, String meg){ + //需要返回的对象, 默认失败 + return initStaticMessage(result, meg); + } + + static String initStaticMessage(Integer result, String meg){ //需要返回的对象, 默认失败 return JSONObject.toJSONString(new RzAttendanceVo(result, meg, null)); } diff --git a/evo-admin/src/main/java/com/evo/attendance/processor/impl/KQDeviceExchangeProcessor.java b/evo-admin/src/main/java/com/evo/attendance/processor/impl/KQDeviceExchangeProcessor.java index cc48fe5..dc2d716 100644 --- a/evo-admin/src/main/java/com/evo/attendance/processor/impl/KQDeviceExchangeProcessor.java +++ b/evo-admin/src/main/java/com/evo/attendance/processor/impl/KQDeviceExchangeProcessor.java @@ -150,7 +150,6 @@ public class KQDeviceExchangeProcessor implements PunchTheClockStrategyExchangeP return initMessage(1, "当天已经打过加班卡"); } - //员工考勤记录 RzAttendance attendance = rzAttendanceMapper.queryNowDayAttendanceByStatisticalIdAndDate(Long.valueOf(userId),date); //如果当前打卡是下班卡, 并且当前员工考勤上班时间为空, 则判定为隔天打下班卡 diff --git a/evo-admin/src/main/java/com/evo/attendance/service/IRzAttendanceService.java b/evo-admin/src/main/java/com/evo/attendance/service/IRzAttendanceService.java index 34938e6..8ffc453 100644 --- a/evo-admin/src/main/java/com/evo/attendance/service/IRzAttendanceService.java +++ b/evo-admin/src/main/java/com/evo/attendance/service/IRzAttendanceService.java @@ -1,9 +1,12 @@ package com.evo.attendance.service; +import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.extension.service.IService; +import com.evo.attendance.domain.RzAttendance; import com.evo.attendance.domain.vo.RzAttendanceDetailVO; import com.evo.common.core.domain.AjaxResult; -import com.evo.attendance.domain.RzAttendance; +import com.evo.ding.domain.DingShiftGroup; +import com.evo.system.domain.SysStaff; import java.util.Date; import java.util.List; @@ -62,4 +65,15 @@ public interface IRzAttendanceService extends IService RzAttendance selectRzAttendanceBySfIdAndNameAndTime(Long userId, String employeeName, String replacementTime,Boolean isAttendance); public void sendAbnormalAttendance(); + + public void dingDing(String dingUserId, String bizId, Long checkTime); + + void addRzOverTime(String result, SysStaff sysStaff, DingShiftGroup dingsShiftGroup, String checkType, Date formatWorkDate, Date formatUserCheckTime, String timeResult, String remark, Double debiting, RzAttendance attendance); + + public RzAttendance queryNowDayAttendanceByStatisticalIdAndDate(Long staffId, Date date); + + public RzAttendance loadAttendance(Long id); + + public AjaxResult loadAllAttendance(RzAttendance rzAttendance); + } diff --git a/evo-admin/src/main/java/com/evo/attendance/service/IRzSpecialAttendanceService.java b/evo-admin/src/main/java/com/evo/attendance/service/IRzSpecialAttendanceService.java index 0e9a2da..7be6ba1 100644 --- a/evo-admin/src/main/java/com/evo/attendance/service/IRzSpecialAttendanceService.java +++ b/evo-admin/src/main/java/com/evo/attendance/service/IRzSpecialAttendanceService.java @@ -1,7 +1,10 @@ package com.evo.attendance.service; +import com.baomidou.mybatisplus.extension.service.IService; import com.evo.attendance.domain.RzSpecialAttendance; +import org.apache.ibatis.annotations.Param; +import java.util.Date; import java.util.List; /** @@ -10,7 +13,7 @@ import java.util.List; * @author evo * @date 2025-04-15 */ -public interface IRzSpecialAttendanceService +public interface IRzSpecialAttendanceService extends IService { /** * 查询加班考勤记录 @@ -51,4 +54,6 @@ public interface IRzSpecialAttendanceService * @return 结果 */ public int deleteRzSpecialAttendanceById(Long id); + + public RzSpecialAttendance selectRzSpecialAttendanceByUserIdAndDate(Long staffId, Date date); } diff --git a/evo-admin/src/main/java/com/evo/attendance/service/impl/RzAttendanceDetailServiceImpl.java b/evo-admin/src/main/java/com/evo/attendance/service/impl/RzAttendanceDetailServiceImpl.java index 1beca89..bf6a8a4 100644 --- a/evo-admin/src/main/java/com/evo/attendance/service/impl/RzAttendanceDetailServiceImpl.java +++ b/evo-admin/src/main/java/com/evo/attendance/service/impl/RzAttendanceDetailServiceImpl.java @@ -141,11 +141,6 @@ public class RzAttendanceDetailServiceImpl extends ServiceImpl().eq(RzAttendanceDetail::getAttendanceId, attId) -// .select(RzAttendanceDetail::getButtonType, RzAttendanceDetail::getPhoto, RzAttendanceDetail::getDateTime,RzAttendanceDetail::getDelFlag)).stream().map(data ->{ -// return new RzAttendanceDetailTimeLineVO(data.getButtonType(), data.getPhoto(), DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss",data.getDateTime()), data.getDelFlag()); -// }).collect(Collectors.toList()); } SimpleDateFormat sdfd = new SimpleDateFormat("yyyy-MM-dd"); diff --git a/evo-admin/src/main/java/com/evo/attendance/service/impl/RzAttendanceServiceImpl.java b/evo-admin/src/main/java/com/evo/attendance/service/impl/RzAttendanceServiceImpl.java index 4b69aef..65c4a19 100644 --- a/evo-admin/src/main/java/com/evo/attendance/service/impl/RzAttendanceServiceImpl.java +++ b/evo-admin/src/main/java/com/evo/attendance/service/impl/RzAttendanceServiceImpl.java @@ -1,5 +1,8 @@ package com.evo.attendance.service.impl; +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; @@ -13,11 +16,15 @@ import com.evo.attendance.service.RzAttendanceDetailService; import com.evo.common.annotation.DataScope; import com.evo.common.core.domain.AjaxResult; import com.evo.common.core.domain.entity.SysDept; -import com.evo.common.utils.Collections; -import com.evo.common.utils.DateUtils; -import com.evo.common.utils.SecurityUtils; -import com.evo.common.utils.StringUtils; +import com.evo.common.handler.thread.RzAttendanceBatchHandler; +import com.evo.common.utils.*; +import com.evo.ding.DingUtils; +import com.evo.ding.domain.DingShift; +import com.evo.ding.domain.DingShiftGroup; +import com.evo.ding.mapper.DingShiftGroupMapper; +import com.evo.ding.mapper.DingShiftMapper; import com.evo.equipment.service.IEqImagesService; +import com.evo.personnelMatters.service.IRzOverTimeService; import com.evo.system.domain.SysStaff; import com.evo.system.mapper.SysDeptMapper; import com.evo.system.mapper.SysStaffMapper; @@ -31,6 +38,7 @@ import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.math.BigDecimal; import java.text.SimpleDateFormat; +import java.time.Instant; import java.util.Date; import java.util.List; import java.util.Map; @@ -56,6 +64,13 @@ public class RzAttendanceServiceImpl extends ServiceImpl"+result); + JSONObject resultJson = JSON.parseObject(result); + if(Integer.valueOf(0).equals(resultJson.getInteger("errcode"))) + try { + { + JSONArray jsonArray = resultJson.getJSONArray("recordresult"); + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject ob = jsonArray.getJSONObject(i); + if(bizId.equals(ob.getString("bizId"))){ + calculationAddRzOverTime(result, sysStaff, ob, null); +// //打卡类型 +// String checkType = ob.getString("checkType"); +// //考勤组 +// String groupId = ob.getString("groupId"); +// //排班时间 +// Long planCheckTime = ob.getLong("planCheckTime"); +// // 格式化:先转Date对象,再格式化 +// String formatPlanCheckTime = DateUtils.parseDateToStr("HH:mm:ss", new Date(planCheckTime)); +// //用户打卡时间 +// Long userCheckTime = ob.getLong("userCheckTime"); +// //工作时间 (这里指的是哪一天的卡) +// Long workDate = ob.getLong("workDate"); +// /*** +// * 打卡结果 +// * Normal:正常 +// * Early:早退 +// * Late:迟到 +// * SeriousLate:严重迟到 +// * Absenteeism:旷工迟到 +// * NotSigned:未打卡 +// */ +// String timeResult = ob.getString("timeResult"); +// +// Date formatWorkDate = Date.from(Instant.ofEpochMilli(workDate)); +// Date formatUserCheckTime = Date.from(Instant.ofEpochMilli(userCheckTime)); +// DingShiftGroup dingsShiftGroup = dingsShiftGroupMapper.selectByGroupIdAndTypeAndCheckTime(groupId, checkType, formatPlanCheckTime); +// addRzOverTime(result, sysStaff, dingsShiftGroup, checkType, formatWorkDate, formatUserCheckTime, timeResult, null, 0d); + break; + } + } + } + } catch (Exception e) { + e.printStackTrace(); + log.error("处理钉钉打卡出现异常, 异常原因是==>>{}, 打卡结果是=====>>>>> {}", e.getMessage(), result); + } + } + } + @Override + public void addRzOverTime(String result, SysStaff sysStaff, DingShiftGroup dingsShiftGroup, String checkType, Date formatWorkDate, Date formatUserCheckTime, String timeResult, String remark, Double debiting,RzAttendance attendance){ + if(dingsShiftGroup != null){ + //通过打卡类型, classId, 和排班打卡时间, 获取工作时长 + //通过班次id拿到工作时长 + DingShift dingsShift = dingsShiftMapper.selectByDingId(dingsShiftGroup.getShiftId()); + //通过workDate 获取哪一天的卡 + if(attendance == null){ + attendance = queryNowDayAttendanceByStatisticalIdAndDate(sysStaff.getUserId(),formatWorkDate); + } + //生成打卡记录 + rzAttendanceDetailService.addDetail(attendance, ("OnDuty".equals(checkType) ? "上班卡" : "下班卡"), "/", formatUserCheckTime, StringUtils.isEmpty(remark) ? "钉钉打卡" : remark, ""); + //上班 + if("OnDuty".equals(checkType)){ + attendance.setRules("上班卡"); + attendance.setWorkStartTime(formatUserCheckTime); + if(!"Normal".equals(timeResult)){ + attendance.setYcsFlag("1"); + } + }else if("OffDuty".equals(checkType)){ + attendance.setWorkEndTime(formatUserCheckTime); + if("Normal".equals(timeResult) && !"1".equals(attendance.getYcsFlag()) && attendance.getWorkStartTime() != null){ + attendance.setWorkSum(BigDecimal.valueOf(dingsShift.getWorkHour())); + }else{ + //早退需要计算工时 + if(attendance.getWorkStartTime() != null){ + Long hours = (attendance.getWorkEndTime().getTime() - attendance.getWorkStartTime().getTime())/1000/60/60; + attendance.setWorkSum((BigDecimal.valueOf(dingsShift.getWorkHour()).compareTo(BigDecimal.valueOf(hours)) < 0) ? BigDecimal.valueOf(dingsShift.getWorkHour()) : BigDecimal.valueOf(hours)); + }else { + attendance.setWorkSum(DataUtils.DEFAULT_VALUE); + } + if(!"Normal".equals(timeResult)){ + attendance.setYcxFlag("1"); + } + } + }else{ + log.error("钉钉打卡=====>>>>>>>>>>>>>>>>>> 出现未知打卡类型, 当前打卡类型"); + //终止继续执行 + return; + } + //判断打卡时间, 添加夜班次数 打卡时间在晚上7点以后 + if(dingsShift.getWorkHour() == 12 && attendance.getWorkSum().intValue() >= 12 && attendance.getWorkStartTime()!= null && attendance.getWorkStartTime().getHours() > 12){ + attendance.setNightNumber(1); + //必须是8小时倒班制or单班制, 并且工作时长>=8小时, 并且 上班打开时间在12点至21点 算作中班 -- 2026-02-04 因1月份张克龙中班考勤问题, 刘杰面谈 + }else if(dingsShift.getWorkHour() == 8 && attendance.getWorkSum().intValue() >= 8 && attendance.getWorkStartTime() != null && attendance.getWorkStartTime().getHours() >= 12 && attendance.getWorkStartTime().getHours() < 21){ + attendance.setMiddleShiftNumber(1); + } + //记录补卡扣款 + attendance.setDebiting(DataUtils.findDefaultValue(attendance.getDebiting(), DataUtils.DEFAULT_VALUE).add(new BigDecimal(DataUtils.findDefaultValue(debiting, 0d)))); + getBaseMapper().updateRzAttendance(attendance); + //检查是否开启加班, 所有的加班调整为, 扫脸打卡 +// if(dingsShift.getOvertimeWork()){ +// //使用排班下班时间作为加班开始时间 +// rzOverTimeService.overTimeCard(sysStaff, DateUtils.parseDate(DateUtils.parseDateToStr("yyyy-MM-dd", formatWorkDate)+" "+ dingsShiftGroup.getCheckTime())); +// //员工打卡时间作为加班下班时间 +// rzOverTimeService.overTimeOffDutyCard(sysStaff, formatUserCheckTime, "/"); +// } + }else{ + log.info("钉钉回调打卡信息=====>>>>> {}", result); + } + } + @Override + public RzAttendance queryNowDayAttendanceByStatisticalIdAndDate(Long staffId, Date date) { + return getBaseMapper().queryNowDayAttendanceByStatisticalIdAndDate(staffId,date); + } + + @Override + public RzAttendance loadAttendance(Long id) { + RzAttendance attendance = getById(id); + SysStaff sysStaff = sysStaffMapper.selectById(attendance.getStaffId()); + if(StringUtils.isNotEmpty(sysStaff.getDingUserId())){ + String result = DingUtils.getListRecord(Collections.asList(sysStaff.getDingUserId()), DateUtils.parseDateToStr("yyyy-MM-dd", attendance.getAttendanceDate())+" 00:00:00", DateUtils.parseDateToStr("yyyy-MM-dd", attendance.getAttendanceDate())+" 23:59:59"); + JSONObject resultJson = JSON.parseObject(result); + if(Integer.valueOf(0).equals(resultJson.getInteger("errcode"))) + try { + JSONArray jsonArray = resultJson.getJSONArray("recordresult"); + JSONObject onDutyObject = (JSONObject) jsonArray.stream().filter(data -> "OnDuty".equals(((JSONObject)data).getString("checkType"))).findFirst().orElse(null); + if(onDutyObject != null){ + calculationAddRzOverTime(result, sysStaff, onDutyObject, attendance); + } + JSONObject offDutyObject = (JSONObject) jsonArray.stream().filter(data -> "OffDuty".equals(((JSONObject)data).getString("checkType"))).findFirst().orElse(null); + if(offDutyObject != null){ + calculationAddRzOverTime(result, sysStaff, offDutyObject, attendance); + } + } catch (Exception e) { + e.printStackTrace(); + log.error("重新抓取钉钉考勤结果异常, 异常原因是==>>{}, 打卡结果是=====>>>>> {}", e.getMessage(), result); + } + } + return attendance; + } + + @Override + public AjaxResult loadAllAttendance(RzAttendance rzAttendance) { + if (StringUtils.isNull(rzAttendance.getAttendanceDate())) { + return AjaxResult.error("请选择需要重新抓取的月份!!"); + } + dataBatchHandler.batchProcess(rzAttendance.getAttendanceDate(), (result, sysStaff, ob, attendance) -> { + // 调用你当前 ServiceImpl 里的方法 + try { + this.calculationAddRzOverTime(result, sysStaff, ob, attendance); + } catch (Exception e) { + e.printStackTrace(); + log.error("刷新用户===>>{}, 出现异常, 异常原因为====>{}", JSONObject.toJSONString(sysStaff), e.getMessage()); + } + }); + return null; + } + + public void calculationAddRzOverTime(String result ,SysStaff sysStaff, JSONObject ob, RzAttendance attendance){ + //打卡类型 + String checkType = ob.getString("checkType"); + //考勤组 + String groupId = ob.getString("groupId"); + // + String shiftId = ob.getString("classId"); + //排班时间 + Long planCheckTime = ob.getLong("planCheckTime"); + // 格式化:先转Date对象,再格式化 + String formatPlanCheckTime = DateUtils.parseDateToStr("HH:mm:ss", new Date(planCheckTime)); + //用户打卡时间 + Long userCheckTime = ob.getLong("userCheckTime"); + //工作时间 (这里指的是哪一天的卡) + Long workDate = ob.getLong("workDate"); + /*** + * 打卡结果 + * Normal:正常 + * Early:早退 + * Late:迟到 + * SeriousLate:严重迟到 + * Absenteeism:旷工迟到 + * NotSigned:未打卡 + */ + String timeResult = ob.getString("timeResult"); + + Date formatWorkDate = Date.from(Instant.ofEpochMilli(workDate)); + Date formatUserCheckTime = Date.from(Instant.ofEpochMilli(userCheckTime)); + DingShiftGroup dingsShiftGroup = dingsShiftGroupMapper.selectByGroupIdAndTypeAndCheckTime(groupId, shiftId, checkType, formatPlanCheckTime); + addRzOverTime(result, sysStaff, dingsShiftGroup, checkType, formatWorkDate, formatUserCheckTime, timeResult, null, 0d, attendance); + } @Async protected void sendAbnormalAttendance(SysStaff sysStaff, Date date){ diff --git a/evo-admin/src/main/java/com/evo/attendance/service/impl/RzAttendanceStatisticalServiceImpl.java b/evo-admin/src/main/java/com/evo/attendance/service/impl/RzAttendanceStatisticalServiceImpl.java index 0e52e0c..f690e8b 100644 --- a/evo-admin/src/main/java/com/evo/attendance/service/impl/RzAttendanceStatisticalServiceImpl.java +++ b/evo-admin/src/main/java/com/evo/attendance/service/impl/RzAttendanceStatisticalServiceImpl.java @@ -171,16 +171,21 @@ public class RzAttendanceStatisticalServiceImpl extends ServiceImpl kq_list = rzAttendanceMapper.queryMonthAttendanceByStaffId(sysStaff.getUserId(),new Date()); //循环修改信息 for (RzAttendance rzAttendance : kq_list) { - rzAttendance.setDeptId(sysStaff.getDeptId()); + if(rzAttendanceStatistical.getDeptId() == null){ + rzAttendance.setDeptId(sysStaff.getDeptId()); + } rzAttendance.setName(sysStaff.getName()); rzAttendanceMapper.updateRzAttendance(rzAttendance); } diff --git a/evo-admin/src/main/java/com/evo/attendance/service/impl/RzSpecialAttendanceServiceImpl.java b/evo-admin/src/main/java/com/evo/attendance/service/impl/RzSpecialAttendanceServiceImpl.java index dcdd65a..1df5206 100644 --- a/evo-admin/src/main/java/com/evo/attendance/service/impl/RzSpecialAttendanceServiceImpl.java +++ b/evo-admin/src/main/java/com/evo/attendance/service/impl/RzSpecialAttendanceServiceImpl.java @@ -4,6 +4,7 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.evo.attendance.domain.RzAttendanceStatistical; import com.evo.attendance.domain.RzSpecialAttendance; import com.evo.attendance.domain.RzSpecialOverTime; @@ -23,7 +24,7 @@ import javax.annotation.Resource; * @date 2025-04-15 */ @Service -public class RzSpecialAttendanceServiceImpl implements IRzSpecialAttendanceService +public class RzSpecialAttendanceServiceImpl extends ServiceImpl implements IRzSpecialAttendanceService { @Resource private RzSpecialAttendanceMapper rzSpecialAttendanceMapper; @@ -131,4 +132,9 @@ public class RzSpecialAttendanceServiceImpl implements IRzSpecialAttendanceServi rzAttendanceStatistical.setOverTimeHours(rzAttendanceStatistical.getOverTimeHours().subtract(rzSpecialAttendance.getWorkHours())); return rzAttendanceStatisticalMapper.updateRzAttendanceStatistical(rzAttendanceStatistical); } + + @Override + public RzSpecialAttendance selectRzSpecialAttendanceByUserIdAndDate(Long staffId, Date date) { + return getBaseMapper().selectRzSpecialAttendanceByUserIdAndDate(staffId, date); + } } diff --git a/evo-admin/src/main/java/com/evo/attendance/service/impl/RzSysParamServiceImpl.java b/evo-admin/src/main/java/com/evo/attendance/service/impl/RzSysParamServiceImpl.java index 58bacfa..135e187 100644 --- a/evo-admin/src/main/java/com/evo/attendance/service/impl/RzSysParamServiceImpl.java +++ b/evo-admin/src/main/java/com/evo/attendance/service/impl/RzSysParamServiceImpl.java @@ -4,6 +4,7 @@ import java.util.List; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.evo.common.constant.CacheConstants; import com.evo.common.utils.DateUtils; import com.evo.common.utils.SecurityUtils; import com.evo.equipment.constant.Constants; @@ -103,6 +104,7 @@ public class RzSysParamServiceImpl extends ServiceImpl().eq(RzSysParam::getParamCode, code)); } diff --git a/evo-admin/src/main/java/com/evo/common/async/AsyncConfig.java b/evo-admin/src/main/java/com/evo/common/async/AsyncConfig.java new file mode 100644 index 0000000..ab7a14d --- /dev/null +++ b/evo-admin/src/main/java/com/evo/common/async/AsyncConfig.java @@ -0,0 +1,52 @@ +package com.evo.common.async; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; +/** + * AsyncConfig + * + * @author andy.shi + * @ClassName:AsyncConfig + * @date: 2026年03月05日 8:48 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@Configuration +//@EnableAsync +public class AsyncConfig { + + @Value("${yt.async.corePoolSize:'5'}") + private Integer corePoolSize; + @Value("${yt.async.maxPoolSize:'10'}") + private Integer maxPoolSize; + @Value("${yt.async.queueCapacity:'20'}") + private Integer queueCapacity; + @Value("${yt.async.keepAliveSeconds:'60'}") + private Integer keepAliveSeconds; + + + @Bean("asyncExecutor") // 自定义线程池名称 + public Executor asyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + // 核心线程数 + executor.setCorePoolSize(corePoolSize); + // 最大线程数 + executor.setMaxPoolSize(maxPoolSize); + // 队列容量 + executor.setQueueCapacity(queueCapacity); + // 线程空闲超时时间 + executor.setKeepAliveSeconds(keepAliveSeconds); + // 线程名称前缀 + executor.setThreadNamePrefix("async-thread-"); + // 拒绝策略(队列满+最大线程数满时的处理方式) + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + // 初始化 + executor.initialize(); + return executor; + } +} diff --git a/evo-admin/src/main/java/com/evo/common/config/thread/DynamicThreadPoolConfig.java b/evo-admin/src/main/java/com/evo/common/config/thread/DynamicThreadPoolConfig.java new file mode 100644 index 0000000..06e3cca --- /dev/null +++ b/evo-admin/src/main/java/com/evo/common/config/thread/DynamicThreadPoolConfig.java @@ -0,0 +1,73 @@ +package com.evo.common.config.thread; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicLong; +/** + * SpringBoot 动态安全线程池(生产级) + * @ClassName:DynamicThreadPoolConfig + * @date: 2026年04月25日 15:00 + * @author: andy.shi + * @contact: 17330188597 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@Configuration +public class DynamicThreadPoolConfig { + + private final ThreadPoolProperties poolProperties; + + public DynamicThreadPoolConfig(ThreadPoolProperties poolProperties) { + this.poolProperties = poolProperties; + } + + @Bean(name = "dataBatchThreadPool") + public ThreadPoolTaskExecutor dataBatchThreadPool() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + + // 基础配置 + executor.setCorePoolSize(poolProperties.getCorePoolSize()); + executor.setMaxPoolSize(poolProperties.getMaxPoolSize()); + executor.setQueueCapacity(poolProperties.getQueueCapacity()); + executor.setKeepAliveSeconds(poolProperties.getKeepAliveSeconds()); + executor.setThreadNamePrefix(poolProperties.getThreadNamePrefix()); + + // 核心线程允许超时回收 + executor.setAllowCoreThreadTimeOut(true); + + // 自定义线程工厂(异常捕获) + executor.setThreadFactory(new ThreadFactory() { + private final AtomicLong num = new AtomicLong(1); + + @Override + public Thread newThread(Runnable r) { + Thread thread = new Thread(r); + thread.setName(poolProperties.getThreadNamePrefix() + num.getAndIncrement()); + thread.setDaemon(true); + thread.setUncaughtExceptionHandler((t, e) -> + System.err.println("线程异常:" + t.getName() + "," + e.getMessage()) + ); + return thread; + } + }); + + // 拒绝策略:阻塞入队,不丢任务 + executor.setRejectedExecutionHandler((r, e) -> { + if (!e.isShutdown()) { + try { + e.getQueue().put(r); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + } + } + }); + + // 优雅关闭 + executor.setWaitForTasksToCompleteOnShutdown(true); + executor.setAwaitTerminationSeconds(60); + executor.initialize(); + return executor; + } +} \ No newline at end of file diff --git a/evo-admin/src/main/java/com/evo/common/config/thread/ThreadPoolManager.java b/evo-admin/src/main/java/com/evo/common/config/thread/ThreadPoolManager.java new file mode 100644 index 0000000..65f853f --- /dev/null +++ b/evo-admin/src/main/java/com/evo/common/config/thread/ThreadPoolManager.java @@ -0,0 +1,39 @@ +package com.evo.common.config.thread; + +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.stereotype.Component; +import javax.annotation.Resource; +/** + * 线程池工具类(静态调用) + * @ClassName:ThreadPoolManager + * @date: 2026年04月25日 15:02 + * @author: andy.shi + * @contact: 17330188597 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ + +@Component +public class ThreadPoolManager { + + private static ThreadPoolTaskExecutor executor; + + @Resource(name = "dataBatchThreadPool") + public void setExecutor(ThreadPoolTaskExecutor executor) { + ThreadPoolManager.executor = executor; + } + + // 提交任务 + public static void execute(Runnable task) { + executor.execute(task); + } + + // 动态修改核心线程 + public static void setCorePoolSize(int size) { + executor.setCorePoolSize(size); + } + + // 动态修改最大线程 + public static void setMaxPoolSize(int size) { + executor.setMaxPoolSize(size); + } +} \ No newline at end of file diff --git a/evo-admin/src/main/java/com/evo/common/config/thread/ThreadPoolProperties.java b/evo-admin/src/main/java/com/evo/common/config/thread/ThreadPoolProperties.java new file mode 100644 index 0000000..42900cd --- /dev/null +++ b/evo-admin/src/main/java/com/evo/common/config/thread/ThreadPoolProperties.java @@ -0,0 +1,26 @@ +package com.evo.common.config.thread; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * @desc: + * @ClassName:ThreadPoolProperties + * @date: 2026年04月25日 14:57 + * @author: andy.shi + * @contact: 17330188597 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ + +@Data +@Component +@ConfigurationProperties(prefix = "thread.pool") +public class ThreadPoolProperties { + private Integer corePoolSize; + private Integer maxPoolSize; + private Integer keepAliveSeconds; + private Integer queueCapacity; + private String threadNamePrefix; + private Integer batchSize; // 每线程处理条数 +} \ No newline at end of file diff --git a/evo-admin/src/main/java/com/evo/common/constant/Constants.java b/evo-admin/src/main/java/com/evo/common/constant/Constants.java index 2a395ac..62f6e59 100644 --- a/evo-admin/src/main/java/com/evo/common/constant/Constants.java +++ b/evo-admin/src/main/java/com/evo/common/constant/Constants.java @@ -133,4 +133,9 @@ public class Constants public static final BigDecimal DAY_WORK_HOUR = new BigDecimal(8); + + public static final String SOURCE_PT = "1"; + public static final String SOURCE_DING = "2"; + + } diff --git a/evo-admin/src/main/java/com/evo/common/controller/CallbackController.java b/evo-admin/src/main/java/com/evo/common/controller/CallbackController.java new file mode 100644 index 0000000..dd36a58 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/common/controller/CallbackController.java @@ -0,0 +1,113 @@ +package com.evo.common.controller; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.evo.attendance.service.IRzAttendanceService; +import com.evo.common.core.controller.BaseController; +import com.evo.ding.DingGlobalParams; +import com.evo.ding.DingCallbackCrypto; +import com.evo.ding.processor.instance.InstanceChangeExchangeProcessor; +import com.evo.ding.processor.callback.DingCallBackExchangeProcessor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.Map; + +/** + * CallbackController + * + * @author andy.shi + * @ClassName:CallbackController + * @date: 2026年03月04日 11:27 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@RestController +@RequestMapping("/callback") +@Slf4j +public class CallbackController extends BaseController { + + + @Autowired + IRzAttendanceService rzAttendanceService; + @Autowired + List instanceChangeExchangeProcessorList; + @Autowired + List dingCallBackExchangeProcessorList; + @PostMapping("/ding/clock") + public Map dingDingClock(@RequestBody Map params){ + System.out.println(JSONObject.toJSONString(params)); + try { + // 1. 从http请求中获取加解密参数 + + // 2. 使用加解密类型 + // 2、调用订阅事件接口订阅的事件为企业级事件推送,此时OWNER_KEY为:开发者后台应用的Client ID(原企业内部应用 appKey ) + DingCallbackCrypto callbackCrypto = new DingCallbackCrypto(DingGlobalParams.getToken(), DingGlobalParams.getAesKey(), DingGlobalParams.getClientId()); + String encryptMsg = String.valueOf(params.get("encrypt")); + String decryptMsg = callbackCrypto.getDecryptMsg(String.valueOf(params.get("msg_signature")), String.valueOf(params.get("timestamp")), String.valueOf(params.get("nonce")), encryptMsg); + + System.out.println("==============>"+decryptMsg); + // 3. 反序列化回调事件json数据 + JSONObject eventJson = JSON.parseObject(decryptMsg); + String eventType = eventJson.getString("EventType"); + log.info("发生了:" + eventType + "事件"); + for (DingCallBackExchangeProcessor processor : dingCallBackExchangeProcessorList) { + if (processor.accept(eventType)) { + processor.exchange(eventJson); + } + } + + // 4. 根据EventType分类处理 +// if ("check_url".equals(eventType)) { +// log.info("打卡回调"); +// } else if ("attendance_check_record".equals(eventType)) { //打卡推送 +// JSONArray dataList = eventJson.getJSONArray("DataList"); +// if(dataList!= null && dataList.size() > 0){ +// JSONObject jsonObject = dataList.getJSONObject(0); +// String userId = jsonObject.getString("userId"); +// if(StringUtils.isNotEmpty(userId)){ +// rzAttendanceService.dingDing(userId, jsonObject.getString("bizId")); +// } +// } +// //审批实例订阅 +// }else if ("bpms_instance_change".equals(eventType)) { +// log.info("审批实例订阅回调"); +// for (InstanceChangeExchangeProcessor processor : instanceChangeExchangeProcessorList) { +// if (processor.accept(eventJson.getString("processCode"))) { +// processor.exchange(eventJson); +// } +// } +// // 审批任务订阅 +// }else if ("bpms_task_change".equals(eventType)) { +// log.info("审批任务订阅回调"); +// // 处理通讯录用户增加事件 +// }else if ("attendance_approve_status_change".equals(eventType)) { +// log.info("请假、加班、出差、外出状态变更事件"); +// +// +// +// // 处理通讯录用户增加事件 +// }else if ("user_add_org".equals(eventType)) { +// // 处理通讯录用户增加事件 +// log.info("发生了:" + eventType + "事件"); +// +// +// } else { +// // 添加其他已注册的 +// log.info("发生了:" + eventType + "事件"); +// } + + // 5. 返回success的加密数据 + Map successMap = callbackCrypto.getEncryptedMap("success"); + return successMap; + + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/evo-admin/src/main/java/com/evo/common/controller/TestController.java b/evo-admin/src/main/java/com/evo/common/controller/TestController.java index cb862c8..c982c10 100644 --- a/evo-admin/src/main/java/com/evo/common/controller/TestController.java +++ b/evo-admin/src/main/java/com/evo/common/controller/TestController.java @@ -3,6 +3,7 @@ package com.evo.common.controller; import cn.hutool.core.date.DateUtil; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; +import com.aliyun.dingtalkstorage_1_0.models.GetFileUploadInfoResponseBody; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.evo.attendance.service.IRzAttendanceService; import com.evo.attendance.service.IRzAttendanceStatisticalService; @@ -11,6 +12,8 @@ import com.evo.common.config.Global; import com.evo.common.constant.Constants; import com.evo.common.core.domain.AjaxResult; import com.evo.common.utils.Collections; +import com.evo.common.utils.http.HttpUtils; +import com.evo.ding.DingUtils; import com.evo.personnelMatters.mapper.RzOverTimeDetailMapper; import com.evo.personnelMatters.mapper.RzOverTimeMapper; import com.evo.restaurant.service.IRzRestaurantStatisticsService; @@ -20,21 +23,27 @@ import com.evo.wechat.TemplateMessageUtil; import com.evo.wechat.dto.AbnormalAttendanceTemplate; import com.evo.wechat.dto.MessageTemplate; import com.evo.wechat.service.GZHAccessTokenService; -import org.springframework.stereotype.Controller; +import org.apache.ibatis.annotations.Param; +import org.jasypt.encryption.StringEncryptor; import org.springframework.ui.Model; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; +import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; @@ -67,6 +76,208 @@ public class TestController { private RzAttendanceDetailService rzAttendanceDetailService; @Resource private GZHAccessTokenService gzhAccessTokenService; + @Resource + private StringEncryptor stringEncryptor; + /** + * 清洗加班 + */ + @GetMapping("/dept") + public AjaxResult dept(Long deptId) throws ParseException { + return AjaxResult.success(""); + } + + /** + * 清洗加班 + */ + @GetMapping("/user") + public AjaxResult user(String phone) throws ParseException { + return AjaxResult.success(DingUtils.getUserIdByPhoto(phone)); + } + + + + /** + * 清洗加班 + */ + @GetMapping("/aes") + public void aes() throws ParseException { + // 1. 解密用户名(去掉ENC()) + String usernameCipher = "QpRNGkSzaeihXTOqXCqXCdAgTTBTOD8M"; + String usernamePlain = stringEncryptor.decrypt(usernameCipher); + System.out.println("解密后的用户名:" + usernamePlain); + + // 2. 解密密码(去掉ENC()) + String passwordCipher = "c5Sf+6DNzIgtVm2BoHLFmJqnsTJhqRQd721fQ5HXFEY="; + String passwordPlain = stringEncryptor.decrypt(passwordCipher); + System.out.println("解密后的密码:" + passwordPlain); + } + + + @GetMapping("/buildUser") + public AjaxResult buildUser() throws ParseException { + List staffList = sysStaffService.list(new LambdaQueryWrapper().ne(SysStaff::getStatus, -1).isNull(SysStaff::getDingUserId)); + List notDingDing = Collections.emptyList(); + if(Collections.isNotEmpty(staffList)){ + staffList.stream().forEach(data ->{ + String result = DingUtils.getUserIdByPhoto(data.getPhone()); + JSONObject resObject = JSON.parseObject(result); + if(Integer.valueOf(0).equals(resObject.getInteger("errcode"))){ + JSONObject dingRes = resObject.getJSONObject("result"); + String userId = dingRes.getString("userid"); + data.setDingUserId(userId); + }else{ + notDingDing.add(data.getName()); + } + }); + } + sysStaffService.updateBatchById(staffList); + if(Collections.isNotEmpty(notDingDing)){ + return AjaxResult.success("部分更新失败, 未找到钉钉数据, 人员名单如下: "+ String.join(",", notDingDing)); + } + return AjaxResult.success("更新完成"); + } + + + + /** + * 上传 + */ + @GetMapping("/update") + public void testUpload(@Param("file") MultipartFile filePath) throws Exception { + GetFileUploadInfoResponseBody responseBody = DingUtils.resourceUrls(); + // 从接口返回信息中拿到url + String resourceUrl = responseBody.getHeaderSignatureInfo().getResourceUrls().get(0); + // 从接口返回信息中拿到headers + Map headers = responseBody.getHeaderSignatureInfo().getHeaders(); + URL url = new URL(resourceUrl); + HttpURLConnection connection = (HttpURLConnection)url.openConnection(); + if (headers != null) { + for (Map.Entry entry : headers.entrySet()) { + connection.setRequestProperty(entry.getKey(), entry.getValue()); + } + } + connection.setDoOutput(true); + connection.setRequestMethod("PUT"); + connection.setUseCaches(false); + connection.setReadTimeout(10000); + connection.setConnectTimeout(10000); + connection.connect(); + OutputStream out = connection.getOutputStream(); + InputStream is = filePath.getInputStream(); + byte[] b =new byte[1024]; + int temp; + while ((temp=is.read(b))!=-1){ + out.write(b,0,temp); + } + out.flush(); + out.close(); + int responseCode = connection.getResponseCode(); + connection.disconnect(); + if (responseCode == 200) { + System.out.println("上传成功"); + } else { + System.out.println("上传失败"); + } + + + + } + + + + + + /** + * 清洗加班 + */ + @GetMapping("/testAdapterSend") + public AjaxResult testSend() throws ParseException { + RestTemplate restTemplate = new RestTemplate(); + MultiValueMap params = new LinkedMultiValueMap<>(); +// // 文件 +// File file = new File("D:\\andy\\车辆管理.png"); +//// File file1 = new File("D:\\andy\\index.ts"); +// FileSystemResource resource = new FileSystemResource(file); +//// FileSystemResource resource1 = new FileSystemResource(file1); +// params.add("files", resource); +//// params.add("files", resource1); +// StringBuilder markdownMsg = new StringBuilder(); +// markdownMsg.append("### 🚀 安全库存提醒\n\n") +// .append("今日暂无安全库存预警数据。\n\n"); +// // 只显示前三个安全库存数据 +// markdownMsg.append("**物料编号: ").append("123321").append("**\n") +// .append("- 物料名称: ").append("测试测试567").append("\n") +// .append("- 预计可用量: ").append("200").append("\n") +// .append("- 即时库存: ").append("100").append("\n") +// .append("- 最大库存: ").append("50").append("\n") +// .append("- 创建时间: ").append(DateUtil.formatDateTime(new Date())).append("\n") +// .append("---\n"); // 添加分隔线 +// // 添加总数汇总 +// markdownMsg.append("**总数汇总**\n") +// .append("- 今日安全库存预警数据总数: **").append(50).append("**\n"); +// +// +// +// +// {"month":"sendMarkdownAndFileToUser","robotCode":"dinge794oclijuyxsyub","clientId":"dinge794oclijuyxsyub","clientSecret":"4ryzLl48I8ghhKqEMPCwablFqbs6PCmadqfDAPFWBNuIEBMJvPFQg-XHAe2oH2Fe","recipientType":"code","users":["00312","00150"],"title":"消息通知测试","content":"消息正文内容。。。。。。。。"} + + Map dataMap = Collections.emptyMap(); + dataMap.put("month", "sendMarkdownAndFileToUser"); + dataMap.put("robotCode","dinge794oclijuyxsyub"); + dataMap.put("clientId", "dinge794oclijuyxsyub"); + dataMap.put("clientSecret", "4ryzLl48I8ghhKqEMPCwablFqbs6PCmadqfDAPFWBNuIEBMJvPFQg-XHAe2oH2Fe"); + dataMap.put("recipientType", "code");//00146 + dataMap.put("users", JSON.toJSONString(Collections.asList("00312","00150"))); + dataMap.put("title", "消息通知测试"); + dataMap.put("content", "消息正文内容。。。。。。。。"); +// +//// dataMap.put("parameterTypes", JSON.toJSONString(Collections.asList("java.lang.String","java.lang.String"))); +//// dataMap.put("parameters", JSON.toJSONString(Collections.asList("test测试",markdownMsg.toString()))); +// //推送数据类型 + params.add("data", JSON.toJSONString(dataMap)); +// + String url = "http://localhost:8089/ding/send"; + return AjaxResult.success(restTemplate.postForObject(url, params, String.class)); +// + + //String data = "{\"FormId\":\"BD_Empinfo\",\"FieldKeys\":\"FID\",\"FilterString\":[{\"Left\":\"\",\"FieldName\":\"FStaffNumber\",\"Compare\":\"17\",\"Value\":\"00046\",\"Right\":\"\",\"Logic\":0}],\"OrderString\":\"\",\"TopRowCount\":0,\"StartRow\":0,\"Limit\":2000,\"SubSystemId\":\"\"}"; +// +// String data = "{\n" + +// " \"FormId\" : \"PRD_MO\",\n" + +// " \"FieldKeys\" : \"F_HBYT_SCLH,FBillNo,FWorkShopID.FName,FMaterialId.FNumber,FMaterialName,FPlanStartDate,FPlanFinishDate,FPickMtrlStatus\",\n" + +// " \"FilterString\" : [ {\n" + +// " \"FieldName\" : \"FStatus\",\n" + +// " \"Compare\" : \"105\",\n" + +// " \"Value\" : \"4\",\n" + +// " \"Left\" : \"\",\n" + +// " \"Right\" : \"\",\n" + +// " \"Logic\" : 0\n" + +// " }, {\n" + +// " \"FieldName\" : \"FPickMtrlStatus\",\n" + +// " \"Compare\" : \"29\",\n" + +// " \"Value\" : \"1\",\n" + +// " \"Left\" : \"\",\n" + +// " \"Right\" : \"\",\n" + +// " \"Logic\" : 0\n" + +// " }, {\n" + +// " \"FieldName\" : \"F_HBYT_SCLH\",\n" + +// " \"Compare\" : \"67\",\n" + +// " \"Value\" : \"QB-26-163-XCL\",\n" + +// " \"Left\" : \"\",\n" + +// " \"Right\" : \"\",\n" + +// " \"Logic\" : 0\n" + +// " } ],\n" + +// " \"OrderString\" : \"\",\n" + +// " \"TopRowCount\" : 0,\n" + +// " \"StartRow\" : 0,\n" + +// " \"Limit\" : 10000,\n" + +// " \"SubSystemId\" : \"\"\n" + +// "}"; +// +// return AjaxResult.success(HttpUtils.sendPost("http://localhost:8089/distribution/kingdee/send", JSONObject.toJSONString( +// Collections.asMap("fromId","PRD_MO", "month","billQuery", "parameterTypes",Collections.asList(String.class),"data",Collections.asMap("123",data))))); + } + /** * 清洗加班 diff --git a/evo-admin/src/main/java/com/evo/common/core/domain/entity/SysDept.java b/evo-admin/src/main/java/com/evo/common/core/domain/entity/SysDept.java index ede1e15..70dfc67 100644 --- a/evo-admin/src/main/java/com/evo/common/core/domain/entity/SysDept.java +++ b/evo-admin/src/main/java/com/evo/common/core/domain/entity/SysDept.java @@ -60,6 +60,8 @@ public class SysDept extends BaseEntity /** 是否加班 */ private String isShowFinancial; + private String dingId; + /** 子部门 */ @TableField(exist = false) private List children = new ArrayList(); diff --git a/evo-admin/src/main/java/com/evo/common/function/FourParamFunction.java b/evo-admin/src/main/java/com/evo/common/function/FourParamFunction.java new file mode 100644 index 0000000..f13ad0b --- /dev/null +++ b/evo-admin/src/main/java/com/evo/common/function/FourParamFunction.java @@ -0,0 +1,14 @@ +package com.evo.common.function; + +/** + * @desc: 四参数 + * @ClassName:FourParamFunction + * @date: 2026年04月27日 11:46 + * @author: andy.shi + * @contact: 17330188597 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@FunctionalInterface +public interface FourParamFunction { + void apply(A a, B b, C c, D d); +} \ No newline at end of file diff --git a/evo-admin/src/main/java/com/evo/common/handler/thread/RzAttendanceBatchHandler.java b/evo-admin/src/main/java/com/evo/common/handler/thread/RzAttendanceBatchHandler.java new file mode 100644 index 0000000..8871b3c --- /dev/null +++ b/evo-admin/src/main/java/com/evo/common/handler/thread/RzAttendanceBatchHandler.java @@ -0,0 +1,119 @@ +package com.evo.common.handler.thread; +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import com.evo.attendance.domain.RzAttendance; +import com.evo.common.config.thread.ThreadPoolManager; +import com.evo.common.config.thread.ThreadPoolProperties; +import com.evo.common.function.FourParamFunction; +import com.evo.common.utils.Collections; +import com.evo.common.utils.DateUtils; +import com.evo.common.utils.StringUtils; +import com.evo.ding.DingUtils; +import com.evo.system.domain.SysStaff; +import com.evo.system.service.ISysStaffService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 考勤 批量数据处理器 每个线程 固定处理 50 条数据 + * @ClassName:DataBatchHandler + * @date: 2026年04月25日 15:01 + * @author: andy.shi + * @contact: 17330188597 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ + +@Slf4j +@Component +public class RzAttendanceBatchHandler { + + private final ThreadPoolProperties poolProperties; + + @Autowired + private ISysStaffService sysStaffService; + + public RzAttendanceBatchHandler(ThreadPoolProperties poolProperties) { + this.poolProperties = poolProperties; + } + + /** + * 批量处理任务(自动分片,每片50条) + */ + public void batchProcess(Date date, FourParamFunction calculationAddRzOverTime) { + int batchSize = poolProperties.getBatchSize(); // 50条/线程 + AtomicInteger index = new AtomicInteger(0); + List sysStaffList = sysStaffService.selectSysStaffListAll(); + + Date firstDate = DateUtils.getMonthFirst(date); + Date endDate = DateUtils.getMonthEnd(date); + // 获取有多少天 + List dateTimeList = new ArrayList<>(); + + while (firstDate.compareTo(endDate)<=0) { + dateTimeList.add(DateUtils.parseDateToStr("yyyy-MM-dd", firstDate)); + firstDate = DateUtils.addDays(firstDate, 1); + } + + + // 循环分片提交任务 + while (index.get() < sysStaffList.size()) { + int start = index.getAndAdd(batchSize); + int end = Math.min(start + batchSize, sysStaffList.size()); + + List batchData = sysStaffList.subList(start, end); + + // 提交到线程池,一个线程处理这 50 条 + ThreadPoolManager.execute(() -> { + try { + handleBatchData(batchData, dateTimeList, calculationAddRzOverTime); + } catch (Exception e) { + System.err.println("批量处理异常:" + e.getMessage()); + } + }); + } + } + + /** + * 真正业务:单个线程处理 50 条数据 + */ + private void handleBatchData(List batchData, List dateTimeList, FourParamFunction calculationAddRzOverTime) { + String threadName = Thread.currentThread().getName(); + System.out.println("========================================"); + System.out.println(threadName + " 开始处理,条数:" + batchData.size()); + //将数据的钉钉钉钉list获取 + Map map = batchData.stream().filter(data -> StringUtils.isNotEmpty(data.getDingUserId())).collect(Collectors.toMap(SysStaff::getDingUserId, data -> data)); + List dingUserIds = map.keySet().stream().collect(Collectors.toList()); + System.out.println("==================="+JSONObject.toJSONString(dingUserIds)); + for (String date : dateTimeList){ + String result = DingUtils.getListRecord(dingUserIds, date+" 00:00:00", date+" 23:59:59"); + JSONObject resultJson = JSON.parseObject(result); + if(Integer.valueOf(0).equals(resultJson.getInteger("errcode"))){ + try { + JSONArray jsonArray = resultJson.getJSONArray("recordresult"); + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject object = jsonArray.getJSONObject(i); + calculationAddRzOverTime.apply(result, map.get(object.getString("userId")), object, null); + } + } catch (Exception e) { + e.printStackTrace(); + log.error("重新抓取钉钉考勤结果异常, 抓取用户为====>>>{}, 异常原因是==>>{}, 打卡结果是=====>>>>> {}", JSONObject.toJSONString(dingUserIds), e.getMessage(), result); + } + } + + } + System.out.println(threadName + " 处理完成"); + } + +} diff --git a/evo-admin/src/main/java/com/evo/common/utils/ParamUtils.java b/evo-admin/src/main/java/com/evo/common/utils/ParamUtils.java index 49af078..99317d2 100644 --- a/evo-admin/src/main/java/com/evo/common/utils/ParamUtils.java +++ b/evo-admin/src/main/java/com/evo/common/utils/ParamUtils.java @@ -76,6 +76,17 @@ public class ParamUtils { return Double.valueOf(param.getParamValue()); } + /*** + * 获取补卡单次扣款 + * @return + */ + public static Double getDebiting(){ + RzSysParam param= paramService.getRzSysParam("补卡单次扣款", "recharge_card_debiting","2","单次补卡扣款"); + return Double.valueOf(param.getParamValue()); + } + + + /*** * 获取餐厅的开放时间 * @return @@ -122,7 +133,7 @@ public class ParamUtils { * @return */ public static List getInternDailyWage(){ - RzSysParam param= paramService.getRzSysParam("实习生不住宿的日薪人员名单", "intern_not_accommodation","乔克俭","实习生不住宿的日薪人员名单"); + RzSysParam param= paramService.getRzSysParam("实习生不住宿的日薪人员名单", "intern_daily_wage","乔克俭","实习生不住宿的日薪人员名单"); return Collections.asList(param.getParamValue().split(",")); } @@ -215,6 +226,9 @@ public class ParamUtils { public static JSONObject getDeviceOverTimeRules(String sn){ if(StringUtils.isEmpty(sn)) return null; RzSysParam param= paramService.getRzSysParam("特殊加班的考勤规则", "device_over_time_rules","{\"ET74336\":{\"minHour\":2, \"maxHour\":3,\"endMealTime\":\"19:00\"}}","特殊加班的考勤规则, minHour:最小加班时长. maxHour: 最大加班时长, endMealTime: 餐厅闭厅时间"); + if(param == null){ + return getDefaultMaxOverTime(); + } JSONObject jsonObject = JSONObject.parseObject(param.getParamValue()); JSONObject rules = jsonObject.getJSONObject(sn); return (ObjectUtils.isEmpty(rules) ? getDefaultMaxOverTime(): rules); @@ -299,14 +313,13 @@ public class ParamUtils { return false; } //检查格式, 如果格式不匹配, 输出日志, 直接返回true - if(!Pattern.compile("").matcher(checkDate).matches()){ + if(!Pattern.compile("^\\d{4}-\\d{2}-\\d{2}$").matcher(checkDate).matches()){ log.error("当前检查日期{}, 不符合检查规则", checkDate); return false; } //检查是否为假期 return getHoliddayList(Integer.valueOf(checkDate.substring(0,4)), 0).contains(checkDate); } - /*** * 获取假期范围 0 全部 1法休 2 公休 * @param year @@ -332,6 +345,16 @@ public class ParamUtils { return Collections.asList(param.getParamValue().split(",")).stream().filter(StringUtils::isNotEmpty).map(Long::valueOf).collect(Collectors.toList()); } + /*** + * 获取基本工资全新的假期 + * @return + */ + public static List getBasicFullPaidLeave(){ + RzSysParam param= paramService.getRzSysParam("基本薪全薪发放的假期", "basic_full_paid_leave","58","基本薪全薪发放的假期; 58-陪产假"); + return Collections.asList(param.getParamValue().split(",")).stream().filter(StringUtils::isNotEmpty).map(Long::valueOf).collect(Collectors.toList()); + } + + public static List getWebCompany(){ RzSysParam param= paramService.getRzSysParam("外包公司名称", "web_company","WB,LWWB","外包公司, 不扣个税)"); return Collections.asList(param.getParamValue().split(",")).stream().filter(StringUtils::isNotEmpty).collect(Collectors.toList()); diff --git a/evo-admin/src/main/java/com/evo/common/utils/SecurityUtils.java b/evo-admin/src/main/java/com/evo/common/utils/SecurityUtils.java index 63b0e5b..705c5f5 100644 --- a/evo-admin/src/main/java/com/evo/common/utils/SecurityUtils.java +++ b/evo-admin/src/main/java/com/evo/common/utils/SecurityUtils.java @@ -3,6 +3,8 @@ package com.evo.common.utils; import java.util.Collection; import java.util.List; import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @@ -18,6 +20,7 @@ import com.evo.common.exception.ServiceException; * * @author evo */ +@Slf4j public class SecurityUtils { @@ -62,7 +65,9 @@ public class SecurityUtils } catch (Exception e) { - throw new ServiceException("获取用户账户异常", HttpStatus.UNAUTHORIZED); + log.error("获取用户账户异常", HttpStatus.UNAUTHORIZED); + return "system"; +// throw new ServiceException("获取用户账户异常", HttpStatus.UNAUTHORIZED); } } diff --git a/evo-admin/src/main/java/com/evo/common/utils/http/HttpUtils.java b/evo-admin/src/main/java/com/evo/common/utils/http/HttpUtils.java index 93935e1..aaaba66 100644 --- a/evo-admin/src/main/java/com/evo/common/utils/http/HttpUtils.java +++ b/evo-admin/src/main/java/com/evo/common/utils/http/HttpUtils.java @@ -138,7 +138,74 @@ public class HttpUtils conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"); conn.setRequestProperty("Accept-Charset", "UTF-8"); - conn.setRequestProperty("contentType", "UTF-8"); + //conn.setRequestProperty("contentType", "UTF-8"); + conn.setRequestProperty("Content-Type", "application/json;charset=utf-8"); + + conn.setDoOutput(true); + conn.setDoInput(true); + out = new PrintWriter(conn.getOutputStream()); + out.print(param); + out.flush(); + in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8)); + String line; + while ((line = in.readLine()) != null) + { + result.append(line); + } + log.info("recv - {}", result); + } + catch (ConnectException e) + { + log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e); + } + catch (SocketTimeoutException e) + { + log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e); + } + catch (IOException e) + { + log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e); + } + catch (Exception e) + { + log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e); + } + finally + { + try + { + if (out != null) + { + out.close(); + } + if (in != null) + { + in.close(); + } + } + catch (IOException ex) + { + log.error("调用in.close Exception, url=" + url + ",param=" + param, ex); + } + } + return result.toString(); + } + + public static String sendPost(String url, String param, String contentType) { + PrintWriter out = null; + BufferedReader in = null; + StringBuilder result = new StringBuilder(); + try + { + log.info("sendPost - {}", url); + URL realUrl = new URL(url); + URLConnection conn = realUrl.openConnection(); + conn.setRequestProperty("accept", "*/*"); + conn.setRequestProperty("connection", "Keep-Alive"); + conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"); + conn.setRequestProperty("Accept-Charset", "UTF-8"); + conn.setRequestProperty("Content-Type", contentType); + conn.setDoOutput(true); conn.setDoInput(true); out = new PrintWriter(conn.getOutputStream()); diff --git a/evo-admin/src/main/java/com/evo/ding/DingCallbackCrypto.java b/evo-admin/src/main/java/com/evo/ding/DingCallbackCrypto.java new file mode 100644 index 0000000..9de042a --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/DingCallbackCrypto.java @@ -0,0 +1,400 @@ +package com.evo.ding; + +/** + * DingCallbackCrypto + * + * @author andy.shi + * @ClassName:DingCallbackCrypto + * @date: 2026年03月04日 11:55 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ + +import com.alibaba.fastjson2.JSON; +import org.apache.commons.codec.binary.Base64; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.io.ByteArrayOutputStream; +import java.lang.reflect.Field; +import java.nio.charset.Charset; +import java.security.MessageDigest; +import java.security.Permission; +import java.security.PermissionCollection; +import java.security.Security; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + +public class DingCallbackCrypto { + + private static final Charset CHARSET = Charset.forName("utf-8"); + private static final Base64 base64 = new Base64(); + private byte[] aesKey; + private String token; + private String corpId; + /** + * ask getPaddingBytes key固定长度 + **/ + private static final Integer AES_ENCODE_KEY_LENGTH = 43; + /** + * 加密随机字符串字节长度 + **/ + private static final Integer RANDOM_LENGTH = 16; + + /** + * 构造函数 + * + * @param token 钉钉开放平台上,开发者设置的token + * @param encodingAesKey 钉钉开放台上,开发者设置的EncodingAESKey + * @param corpId 企业自建应用-事件订阅, 使用appKey + * 企业自建应用-注册回调地址, 使用corpId + * 第三方企业应用, 使用suiteKey + * + * @throws DingTalkEncryptException 执行失败,请查看该异常的错误码和具体的错误信息 + */ + public DingCallbackCrypto(String token, String encodingAesKey, String corpId) throws DingTalkEncryptException { + if (null == encodingAesKey || encodingAesKey.length() != AES_ENCODE_KEY_LENGTH) { + throw new DingTalkEncryptException(DingTalkEncryptException.AES_KEY_ILLEGAL); + } + this.token = token; + this.corpId = corpId; + aesKey = Base64.decodeBase64(encodingAesKey + "="); + } + + public Map getEncryptedMap(String plaintext) throws DingTalkEncryptException { + return getEncryptedMap(plaintext, System.currentTimeMillis(), Utils.getRandomStr(16)); + } + + /** + * 将和钉钉开放平台同步的消息体加密,返回加密Map + * + * @param plaintext 传递的消息体明文 + * @param timeStamp 时间戳 + * @param nonce 随机字符串 + * @return + * @throws DingTalkEncryptException + */ + public Map getEncryptedMap(String plaintext, Long timeStamp, String nonce) + throws DingTalkEncryptException { + if (null == plaintext) { + throw new DingTalkEncryptException(DingTalkEncryptException.ENCRYPTION_PLAINTEXT_ILLEGAL); + } + if (null == timeStamp) { + throw new DingTalkEncryptException(DingTalkEncryptException.ENCRYPTION_TIMESTAMP_ILLEGAL); + } + if (null == nonce) { + throw new DingTalkEncryptException(DingTalkEncryptException.ENCRYPTION_NONCE_ILLEGAL); + } + // 加密 + String encrypt = encrypt(Utils.getRandomStr(RANDOM_LENGTH), plaintext); + String signature = getSignature(token, String.valueOf(timeStamp), nonce, encrypt); + Map resultMap = new HashMap(); + resultMap.put("msg_signature", signature); + resultMap.put("encrypt", encrypt); + resultMap.put("timeStamp", String.valueOf(timeStamp)); + resultMap.put("nonce", nonce); + return resultMap; + } + + /** + * 密文解密 + * + * @param msgSignature 签名串 + * @param timeStamp 时间戳 + * @param nonce 随机串 + * @param encryptMsg 密文 + * @return 解密后的原文 + * @throws DingTalkEncryptException + */ + public String getDecryptMsg(String msgSignature, String timeStamp, String nonce, String encryptMsg) + throws DingTalkEncryptException { + //校验签名 + String signature = getSignature(token, timeStamp, nonce, encryptMsg); + if (!signature.equals(msgSignature)) { + throw new DingTalkEncryptException(DingTalkEncryptException.COMPUTE_SIGNATURE_ERROR); + } + // 解密 + String result = decrypt(encryptMsg); + return result; + } + + /* + * 对明文加密. + * @param text 需要加密的明文 + * @return 加密后base64编码的字符串 + */ + private String encrypt(String random, String plaintext) throws DingTalkEncryptException { + try { + byte[] randomBytes = random.getBytes(CHARSET); + byte[] plainTextBytes = plaintext.getBytes(CHARSET); + byte[] lengthByte = Utils.int2Bytes(plainTextBytes.length); + byte[] corpidBytes = corpId.getBytes(CHARSET); + ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + byteStream.write(randomBytes); + byteStream.write(lengthByte); + byteStream.write(plainTextBytes); + byteStream.write(corpidBytes); + byte[] padBytes = PKCS7Padding.getPaddingBytes(byteStream.size()); + byteStream.write(padBytes); + byte[] unencrypted = byteStream.toByteArray(); + byteStream.close(); + Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); + SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES"); + IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16); + cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv); + byte[] encrypted = cipher.doFinal(unencrypted); + String result = base64.encodeToString(encrypted); + return result; + } catch (Exception e) { + throw new DingTalkEncryptException(DingTalkEncryptException.COMPUTE_ENCRYPT_TEXT_ERROR); + } + } + + /* + * 对密文进行解密. + * @param text 需要解密的密文 + * @return 解密得到的明文 + */ + private String decrypt(String text) throws DingTalkEncryptException { + byte[] originalArr; + try { + // 设置解密模式为AES的CBC模式 + Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); + SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES"); + IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16)); + cipher.init(Cipher.DECRYPT_MODE, keySpec, iv); + // 使用BASE64对密文进行解码 + byte[] encrypted = Base64.decodeBase64(text); + // 解密 + originalArr = cipher.doFinal(encrypted); + } catch (Exception e) { + throw new DingTalkEncryptException(DingTalkEncryptException.COMPUTE_DECRYPT_TEXT_ERROR); + } + + String plainText; + String fromCorpid; + try { + // 去除补位字符 + byte[] bytes = PKCS7Padding.removePaddingBytes(originalArr); + // 分离16位随机字符串,网络字节序和corpId + byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20); + int plainTextLegth = Utils.bytes2int(networkOrder); + plainText = new String(Arrays.copyOfRange(bytes, 20, 20 + plainTextLegth), CHARSET); + fromCorpid = new String(Arrays.copyOfRange(bytes, 20 + plainTextLegth, bytes.length), CHARSET); + } catch (Exception e) { + throw new DingTalkEncryptException(DingTalkEncryptException.COMPUTE_DECRYPT_TEXT_LENGTH_ERROR); + } + + // corpid不相同的情况 + if (!fromCorpid.equals(corpId)) { + throw new DingTalkEncryptException(DingTalkEncryptException.COMPUTE_DECRYPT_TEXT_CORPID_ERROR); + } + return plainText; + } + + /** + * 数字签名 + * + * @param token isv token + * @param timestamp 时间戳 + * @param nonce 随机串 + * @param encrypt 加密文本 + * @return + * @throws DingTalkEncryptException + */ + public String getSignature(String token, String timestamp, String nonce, String encrypt) + throws DingTalkEncryptException { + try { + String[] array = new String[] {token, timestamp, nonce, encrypt}; + Arrays.sort(array); + System.out.println(JSON.toJSONString(array)); + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < 4; i++) { + sb.append(array[i]); + } + String str = sb.toString(); + System.out.println(str); + MessageDigest md = MessageDigest.getInstance("SHA-1"); + md.update(str.getBytes()); + byte[] digest = md.digest(); + + StringBuffer hexstr = new StringBuffer(); + String shaHex = ""; + for (int i = 0; i < digest.length; i++) { + shaHex = Integer.toHexString(digest[i] & 0xFF); + if (shaHex.length() < 2) { + hexstr.append(0); + } + hexstr.append(shaHex); + } + return hexstr.toString(); + } catch (Exception e) { + throw new DingTalkEncryptException(DingTalkEncryptException.COMPUTE_SIGNATURE_ERROR); + } + } + + public static class Utils { + public Utils() { + } + + public static String getRandomStr(int count) { + String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + Random random = new Random(); + StringBuffer sb = new StringBuffer(); + + for (int i = 0; i < count; ++i) { + int number = random.nextInt(base.length()); + sb.append(base.charAt(number)); + } + + return sb.toString(); + } + + public static byte[] int2Bytes(int count) { + byte[] byteArr = new byte[] {(byte)(count >> 24 & 255), (byte)(count >> 16 & 255), (byte)(count >> 8 & 255), + (byte)(count & 255)}; + return byteArr; + } + + public static int bytes2int(byte[] byteArr) { + int count = 0; + + for (int i = 0; i < 4; ++i) { + count <<= 8; + count |= byteArr[i] & 255; + } + + return count; + } + } + + public static class PKCS7Padding { + private static final Charset CHARSET = Charset.forName("utf-8"); + private static final int BLOCK_SIZE = 32; + + public PKCS7Padding() { + } + + public static byte[] getPaddingBytes(int count) { + int amountToPad = 32 - count % 32; + if (amountToPad == 0) { + amountToPad = 32; + } + + char padChr = chr(amountToPad); + String tmp = new String(); + + for (int index = 0; index < amountToPad; ++index) { + tmp = tmp + padChr; + } + + return tmp.getBytes(CHARSET); + } + + public static byte[] removePaddingBytes(byte[] decrypted) { + int pad = decrypted[decrypted.length - 1]; + if (pad < 1 || pad > 32) { + pad = 0; + } + + return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad); + } + + private static char chr(int a) { + byte target = (byte)(a & 255); + return (char)target; + } + } + + public static class DingTalkEncryptException extends Exception { + public static final int SUCCESS = 0; + public static final int ENCRYPTION_PLAINTEXT_ILLEGAL = 900001; + public static final int ENCRYPTION_TIMESTAMP_ILLEGAL = 900002; + public static final int ENCRYPTION_NONCE_ILLEGAL = 900003; + public static final int AES_KEY_ILLEGAL = 900004; + public static final int SIGNATURE_NOT_MATCH = 900005; + public static final int COMPUTE_SIGNATURE_ERROR = 900006; + public static final int COMPUTE_ENCRYPT_TEXT_ERROR = 900007; + public static final int COMPUTE_DECRYPT_TEXT_ERROR = 900008; + public static final int COMPUTE_DECRYPT_TEXT_LENGTH_ERROR = 900009; + public static final int COMPUTE_DECRYPT_TEXT_CORPID_ERROR = 900010; + private static Map msgMap = new HashMap(); + private Integer code; + + static { + msgMap.put(0, "成功"); + msgMap.put(900001, "加密明文文本非法"); + msgMap.put(900002, "加密时间戳参数非法"); + msgMap.put(900003, "加密随机字符串参数非法"); + msgMap.put(900005, "签名不匹配"); + msgMap.put(900006, "签名计算失败"); + msgMap.put(900004, "不合法的aes key"); + msgMap.put(900007, "计算加密文字错误"); + msgMap.put(900008, "计算解密文字错误"); + msgMap.put(900009, "计算解密文字长度不匹配"); + msgMap.put(900010, "计算解密文字corpid不匹配"); + } + + public Integer getCode() { + return this.code; + } + + public DingTalkEncryptException(Integer exceptionCode) { + super((String)msgMap.get(exceptionCode)); + this.code = exceptionCode; + } + } + static { + try { + Security.setProperty("crypto.policy", "limited"); + RemoveCryptographyRestrictions(); + } catch (Exception var1) { + } + + } + private static void RemoveCryptographyRestrictions() throws Exception { + Class jceSecurity = getClazz("javax.crypto.JceSecurity"); + Class cryptoPermissions = getClazz("javax.crypto.CryptoPermissions"); + Class cryptoAllPermission = getClazz("javax.crypto.CryptoAllPermission"); + if (jceSecurity != null) { + setFinalStaticValue(jceSecurity, "isRestricted", false); + PermissionCollection defaultPolicy = (PermissionCollection)getFieldValue(jceSecurity, "defaultPolicy", (Object)null, PermissionCollection.class); + if (cryptoPermissions != null) { + Map map = (Map)getFieldValue(cryptoPermissions, "perms", defaultPolicy, Map.class); + map.clear(); + } + + if (cryptoAllPermission != null) { + Permission permission = (Permission)getFieldValue(cryptoAllPermission, "INSTANCE", (Object)null, Permission.class); + defaultPolicy.add(permission); + } + } + + } + private static Class getClazz(String className) { + Class clazz = null; + + try { + clazz = Class.forName(className); + } catch (Exception var3) { + } + + return clazz; + } + private static void setFinalStaticValue(Class srcClazz, String fieldName, Object newValue) throws Exception { + Field field = srcClazz.getDeclaredField(fieldName); + field.setAccessible(true); + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + modifiersField.setInt(field, field.getModifiers() & -17); + field.set((Object)null, newValue); + } + private static T getFieldValue(Class srcClazz, String fieldName, Object owner, Class dstClazz) throws Exception { + Field field = srcClazz.getDeclaredField(fieldName); + field.setAccessible(true); + return dstClazz.cast(field.get(owner)); + } + +} \ No newline at end of file diff --git a/evo-admin/src/main/java/com/evo/ding/DingGlobalParams.java b/evo-admin/src/main/java/com/evo/ding/DingGlobalParams.java new file mode 100644 index 0000000..f2f3283 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/DingGlobalParams.java @@ -0,0 +1,91 @@ +package com.evo.ding; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * DingBase + * + * @author andy.shi + * @ClassName:DingBase + * @date: 2026年03月02日 8:48 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@Data +@Component +@ConfigurationProperties(prefix = "ding") +public class DingGlobalParams { + + public static String baseUrl; + + public static String url; + + public static String clientId; + + public static String clientSecret; + + public static String aesKey; + + public static String token; + + public static String corpId; + + + public static String getBaseUrl() { + return baseUrl; + } + + public void setBaseUrl(String baseUrl) { + DingGlobalParams.baseUrl = baseUrl; + } + + public static String getCorpId() { + return corpId; + } + + public void setCorpId(String corpId) { + DingGlobalParams.corpId = corpId; + } + + public static String getAesKey() { + return aesKey; + } + + public void setAesKey(String aesKey) { + DingGlobalParams.aesKey = aesKey; + } + + public static String getToken() { + return token; + } + + public void setToken(String token) { + DingGlobalParams.token = token; + } + + public static String getUrl() { + return url; + } + + public void setUrl(String url) { + DingGlobalParams.url = url; + } + + public static String getClientId() { + return DingGlobalParams.clientId; + } + + public void setClientId(String clientId) { + DingGlobalParams.clientId = clientId; + } + + public static String getClientSecret() { + return clientSecret; + } + + + public void setClientSecret(String clientSecret) { + DingGlobalParams.clientSecret = clientSecret; + } +} diff --git a/evo-admin/src/main/java/com/evo/ding/DingUtils.java b/evo-admin/src/main/java/com/evo/ding/DingUtils.java new file mode 100644 index 0000000..493ec8b --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/DingUtils.java @@ -0,0 +1,316 @@ +package com.evo.ding; + +import com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest; +import com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenResponse; +import com.aliyun.dingtalkstorage_1_0.models.GetFileUploadInfoResponseBody; +import com.aliyun.dingtalkworkflow_1_0.models.GetProcessInstanceResponseBody; +import com.aliyun.tea.TeaException; +import com.dingtalk.api.DefaultDingTalkClient; +import com.dingtalk.api.DingTalkClient; +import com.dingtalk.api.request.*; +import com.dingtalk.api.response.*; +import com.evo.common.core.redis.RedisCache; +import com.evo.common.utils.StringUtils; +import com.taobao.api.ApiException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * DingUtils + * + * @author andy.shi + * @ClassName:DingUtils + * @date: 2026年03月02日 8:54 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@Service +@Slf4j +public class DingUtils { + + private static RedisCache redisCache; + + private static String ACCESS_TOKEN_KEY = "ding_access_token"; + + @Autowired + public DingUtils(RedisCache redisCache) { + this.redisCache = redisCache; + } + + public static com.aliyun.teaopenapi.Client client(Class t) throws Exception { + com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config(); + config.protocol = "https"; + config.regionId = "central"; + if(t == com.aliyun.dingtalkoauth2_1_0.Client.class){ + return new com.aliyun.dingtalkoauth2_1_0.Client(config); + }else if(t == com.aliyun.dingtalkworkflow_1_0.Client.class){ + return new com.aliyun.dingtalkworkflow_1_0.Client(config); + }else if(t == com.aliyun.dingtalkstorage_1_0.Client.class){ + return new com.aliyun.dingtalkstorage_1_0.Client(config); + } + return null; + } + + + public static String getAccessToken() throws Exception { + String token = redisCache.getCacheObject(ACCESS_TOKEN_KEY); + if(StringUtils.isEmpty(token)){ + com.aliyun.dingtalkoauth2_1_0.Client client = (com.aliyun.dingtalkoauth2_1_0.Client) client(com.aliyun.dingtalkoauth2_1_0.Client.class); + GetAccessTokenRequest getAccessTokenRequest = new GetAccessTokenRequest().setAppKey(DingGlobalParams.getClientId()).setAppSecret(DingGlobalParams.getClientSecret()); + try { + GetAccessTokenResponse res = client.getAccessToken(getAccessTokenRequest); + token = res.getBody().getAccessToken(); + //7200s- 10s,防止出现读取不超时, 请求超时 + redisCache.setCacheObject(ACCESS_TOKEN_KEY, token, res.getBody().getExpireIn()-10); + } catch (TeaException err) { + if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) { + // err 中含有 code 和 message 属性,可帮助开发定位问题 + log.error("获取token出现 TeaException 异常, 异常编码{}, 异常原因{}", err.getCode(), err.getMessage()); + } + } catch (Exception _err) { + TeaException err = new TeaException(_err.getMessage(), _err); + if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) { + // err 中含有 code 和 message 属性,可帮助开发定位问题 + log.error("获取token出现 Exception 异常, 异常编码{}, 异常原因{}", err.getCode(), err.getMessage()); + } + } + + } + return token; + } + + //根据手机号获取用户id + public static String getUserIdByPhoto(String photo){ + try { + DingTalkClient client = new DefaultDingTalkClient(DingGlobalParams.getUrl()+"v2/user/getbymobile"); + OapiV2UserGetbymobileRequest req = new OapiV2UserGetbymobileRequest(); + req.setMobile(photo); + OapiV2UserGetbymobileResponse rsp = client.execute(req, getAccessToken()); + return rsp.getBody(); + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + //根据手机号获取用户id + public static String getUserInfoByUserId(String userId){ + try { + DingTalkClient client = new DefaultDingTalkClient(DingGlobalParams.getUrl()+"v2/user/get"); + OapiV2UserGetRequest req = new OapiV2UserGetRequest(); + req.setUserid(userId); + OapiV2UserGetResponse rsp = client.execute(req, getAccessToken()); + return rsp.getBody(); + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + /*** + * 获取班次信息 + * + */ + public static String getShift(){ + try { + DingTalkClient client = new DefaultDingTalkClient(DingGlobalParams.getUrl()+"attendance/shift/list"); + OapiAttendanceShiftListRequest req = new OapiAttendanceShiftListRequest(); + req.setOpUserId("03491015494921375480"); + OapiAttendanceShiftListResponse rsp = client.execute(req, getAccessToken()); + return rsp.getBody(); + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + public static OapiAttendanceShiftQueryResponse.TopShiftVo getShiftDetail(Long id){ + try { + DingTalkClient client = new DefaultDingTalkClient(DingGlobalParams.getBaseUrl()+"topapi/attendance/shift/query"); + OapiAttendanceShiftQueryRequest req = new OapiAttendanceShiftQueryRequest(); + req.setOpUserId("03491015494921375480"); + req.setShiftId(id); + OapiAttendanceShiftQueryResponse rsp = client.execute(req, getAccessToken()); + return rsp.getResult(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public static OapiAttendanceGroupQueryResponse.TopSimpleGroupVO getGroupDetail(Long id){ + try { + DingTalkClient client = new DefaultDingTalkClient(DingGlobalParams.getBaseUrl()+"topapi/attendance/group/query"); + OapiAttendanceGroupQueryRequest req = new OapiAttendanceGroupQueryRequest(); + req.setOpUserId("03491015494921375480"); + req.setGroupId(id); + OapiAttendanceGroupQueryResponse rsp = client.execute(req, getAccessToken()); + return rsp.getResult(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /*** + * 获取考勤组信息 + * + */ + public static String getAttendanceGroupList(){ + try { + DingTalkClient client = new DefaultDingTalkClient(DingGlobalParams.getUrl()+"attendance/getsimplegroups"); + OapiAttendanceGetsimplegroupsRequest req = new OapiAttendanceGetsimplegroupsRequest(); + OapiAttendanceGetsimplegroupsResponse rsp = client.execute(req, getAccessToken()); + return rsp.getBody(); + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + + /*** + * 获取打卡详情 + * @param dingUserIds 钉钉userId + * @param checkDateFrom 开始时间 yyyy-MM-dd HH:mm:ss + * @param checkDateTo 结束时间 yyyy-MM-dd HH:mm:ss + */ + public static String getListRecord(List dingUserIds, String checkDateFrom, String checkDateTo){ + try { + DingTalkClient client = new DefaultDingTalkClient(DingGlobalParams.getBaseUrl()+"attendance/listRecord"); + OapiAttendanceListRecordRequest req = new OapiAttendanceListRecordRequest(); + req.setUserIds(dingUserIds); + req.setCheckDateFrom(checkDateFrom); + req.setCheckDateTo(checkDateTo); + req.setIsI18n(false); + OapiAttendanceListRecordResponse rsp = client.execute(req, getAccessToken()); + System.out.println(rsp.getBody()); + return rsp.getBody(); + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + + + /*** + * 获取审批详情 + * @param processInstanceId 审批示例id + */ + public static GetProcessInstanceResponseBody.GetProcessInstanceResponseBodyResult getProcessInstanceInfo(String processInstanceId){ + try { + com.aliyun.dingtalkworkflow_1_0.Client client = (com.aliyun.dingtalkworkflow_1_0.Client) client(com.aliyun.dingtalkworkflow_1_0.Client.class); + com.aliyun.dingtalkworkflow_1_0.models.GetProcessInstanceHeaders getProcessInstanceHeaders = new com.aliyun.dingtalkworkflow_1_0.models.GetProcessInstanceHeaders(); + getProcessInstanceHeaders.xAcsDingtalkAccessToken = getAccessToken(); + com.aliyun.dingtalkworkflow_1_0.models.GetProcessInstanceRequest getProcessInstanceRequest = new com.aliyun.dingtalkworkflow_1_0.models.GetProcessInstanceRequest(); + getProcessInstanceRequest.setProcessInstanceId(processInstanceId); + try { + return client.getProcessInstanceWithOptions(getProcessInstanceRequest, getProcessInstanceHeaders, new com.aliyun.teautil.models.RuntimeOptions()).getBody().getResult(); + } catch (TeaException err) { + if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) { + // err 中含有 code 和 message 属性,可帮助开发定位问题 + log.error("获取token出现 TeaException 异常, 异常编码{}, 异常原因{}", err.getCode(), err.getMessage()); + } + } catch (Exception _err) { + TeaException err = new TeaException(_err.getMessage(), _err); + if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) { + // err 中含有 code 和 message 属性,可帮助开发定位问题 + log.error("获取token出现 Exception 异常, 异常编码{}, 异常原因{}", err.getCode(), err.getMessage()); + } + + } + } catch (Exception e) { + log.error("=============>>> 获取审批实例出现异常, 异常原因为: {}", e.getMessage()); + e.printStackTrace(); + } + return null; + } + + /*** + * 获取排班详情 + * @param userId + * @param planId + * @return + */ + public static String getPlanInfo(String userId, String planId){ + try { + DingTalkClient client = new DefaultDingTalkClient(DingGlobalParams.getBaseUrl()+"attendance/schedule/result/listbyids"); + OapiAttendanceScheduleResultListbyidsRequest req = new OapiAttendanceScheduleResultListbyidsRequest(); + req.setOpUserId(userId); + req.setScheduleIds(planId); + OapiAttendanceScheduleResultListbyidsResponse rsp = client.execute(req, getAccessToken()); + return rsp.getBody(); + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + + public static String getDeptInfo(Long deptId){ + try { + DingTalkClient client = new DefaultDingTalkClient(DingGlobalParams.getUrl()+"v2/department/get"); + OapiV2DepartmentGetRequest req = new OapiV2DepartmentGetRequest(); + req.setDeptId(deptId); + OapiV2DepartmentGetResponse rsp = client.execute(req, getAccessToken()); + return rsp.getBody(); + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + + public static GetFileUploadInfoResponseBody resourceUrls() { + + try { + com.aliyun.dingtalkstorage_1_0.Client client = (com.aliyun.dingtalkstorage_1_0.Client) client(com.aliyun.dingtalkstorage_1_0.Client.class); + com.aliyun.dingtalkstorage_1_0.models.GetFileUploadInfoHeaders getFileUploadInfoHeaders = new com.aliyun.dingtalkstorage_1_0.models.GetFileUploadInfoHeaders(); + getFileUploadInfoHeaders.xAcsDingtalkAccessToken = getAccessToken(); + com.aliyun.dingtalkstorage_1_0.models.GetFileUploadInfoRequest getFileUploadInfoRequest = new com.aliyun.dingtalkstorage_1_0.models.GetFileUploadInfoRequest(); + getFileUploadInfoRequest.setUnionId("IQ4KFIKVugR3UYfNOii5VzwiEiE"); + getFileUploadInfoRequest.setProtocol("HEADER_SIGNATURE"); + return client.getFileUploadInfoWithOptions("28629173113", getFileUploadInfoRequest, getFileUploadInfoHeaders, new com.aliyun.teautil.models.RuntimeOptions()).getBody(); + } catch (TeaException err) { + if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) { + // err 中含有 code 和 message 属性,可帮助开发定位问题 + log.error("获取resourceUrls出现 TeaException 异常, 异常编码{}, 异常原因{}", err.getCode(), err.getMessage()); + } + + } catch (Exception _err) { + TeaException err = new TeaException(_err.getMessage(), _err); + if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) { + // err 中含有 code 和 message 属性,可帮助开发定位问题 + log.error("获取resourceUrls出现 Exception 异常, 异常编码{}, 异常原因{}", err.getCode(), err.getMessage()); + + } + } + return null; + } + + + + + + + + + + + + + + + + + + + + + + + + +} diff --git a/evo-admin/src/main/java/com/evo/ding/domain/DingGroup.java b/evo-admin/src/main/java/com/evo/ding/domain/DingGroup.java new file mode 100644 index 0000000..0816658 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/domain/DingGroup.java @@ -0,0 +1,25 @@ +package com.evo.ding.domain; + +import lombok.Data; + +import java.io.Serializable; + +/** + * DingsShift + * + * @author andy.shi + * @ClassName:DingsShift + * @date: 2026年03月04日 13:50 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@Data +public class DingGroup implements Serializable { + + /** 主键 */ + private Long id; + /** 班次名称 */ + public String name; + /** 钉钉的班次id */ + public String dingId; + +} diff --git a/evo-admin/src/main/java/com/evo/ding/domain/DingShift.java b/evo-admin/src/main/java/com/evo/ding/domain/DingShift.java new file mode 100644 index 0000000..1d98439 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/domain/DingShift.java @@ -0,0 +1,33 @@ +package com.evo.ding.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; + +import java.io.Serializable; + +/** + * DingsShift + * + * @author andy.shi + * @ClassName:DingsShift + * @date: 2026年03月04日 13:50 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@Data +public class DingShift implements Serializable { + + /** 主键 */ + @TableId + private Long id; + /** 班次名称 */ + public String name; + /** 钉钉的班次id */ + public String dingId; + /** 工作时长 */ + public Integer workHour; + /** 上班基准时间节点 */ + public String onDutyCheckTime; + /** 下班基准时间节点 */ + public String offDutyCheckTime; + +} diff --git a/evo-admin/src/main/java/com/evo/ding/domain/DingShiftGroup.java b/evo-admin/src/main/java/com/evo/ding/domain/DingShiftGroup.java new file mode 100644 index 0000000..475e7e6 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/domain/DingShiftGroup.java @@ -0,0 +1,35 @@ +package com.evo.ding.domain; + +import com.baomidou.mybatisplus.annotation.TableField; +import lombok.Data; + +import java.io.Serializable; + +/** + * DingsShift + * + * @author andy.shi + * @ClassName:DingsShift + * @date: 2026年03月04日 13:50 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@Data +public class DingShiftGroup implements Serializable { + + /** 主键 */ + private Long id; + /** 钉钉的groupId */ + public String groupId; + /** 钉钉的班次id */ + public String shiftId; + /** type 打卡类型 */ + public String type; + /** type 打卡类型 */ + public String checkTime; + + @TableField(exist = false) + private String shiftName; + @TableField(exist = false) + private String groupName; + +} diff --git a/evo-admin/src/main/java/com/evo/ding/mapper/DingGroupMapper.java b/evo-admin/src/main/java/com/evo/ding/mapper/DingGroupMapper.java new file mode 100644 index 0000000..42d3334 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/mapper/DingGroupMapper.java @@ -0,0 +1,19 @@ +package com.evo.ding.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.evo.ding.domain.DingGroup; +import com.evo.ding.domain.DingShift; +import org.apache.ibatis.annotations.Param; + +/** + * DingGroupMapper + * + * @author andy.shi + * @ClassName:DingsShiftGroupMapper + * @date: 2026年03月05日 14:47 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +public interface DingGroupMapper extends BaseMapper { + + public DingGroup selectByDingId(@Param("dingId") String dingId); +} diff --git a/evo-admin/src/main/java/com/evo/ding/mapper/DingShiftGroupMapper.java b/evo-admin/src/main/java/com/evo/ding/mapper/DingShiftGroupMapper.java new file mode 100644 index 0000000..c047dd4 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/mapper/DingShiftGroupMapper.java @@ -0,0 +1,24 @@ +package com.evo.ding.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.evo.ding.domain.DingShiftGroup; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * DingsShiftGroupMapper + * + * @author andy.shi + * @ClassName:DingsShiftGroupMapper + * @date: 2026年03月05日 14:47 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +public interface DingShiftGroupMapper extends BaseMapper { + + DingShiftGroup selectByGroupIdAndTypeAndCheckTime(@Param("groupId") String groupId, @Param("shiftId")String shiftId, @Param("type") String type, @Param("checkTime") String checkTime); + + int updateCheckTimeByShiftIdAndType(@Param("shiftId")String shiftId, @Param("type")String type, @Param("checkTime")String checkTime); + + List selectListByShiftId(@Param("shiftId") String shiftId); +} diff --git a/evo-admin/src/main/java/com/evo/ding/mapper/DingShiftMapper.java b/evo-admin/src/main/java/com/evo/ding/mapper/DingShiftMapper.java new file mode 100644 index 0000000..3b3d258 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/mapper/DingShiftMapper.java @@ -0,0 +1,24 @@ +package com.evo.ding.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.evo.ding.domain.DingShift; +import com.evo.system.domain.SysStaff; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + * DingsShiftGroupMapper + * + * @author andy.shi + * @ClassName:DingsShiftGroupMapper + * @date: 2026年03月05日 14:47 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +public interface DingShiftMapper extends BaseMapper { + + public DingShift selectByDingId(@Param("dingId") String dingId); + + public List selectList(DingShift dingShift); +} diff --git a/evo-admin/src/main/java/com/evo/ding/processor/DingBasicExchangeProcessor.java b/evo-admin/src/main/java/com/evo/ding/processor/DingBasicExchangeProcessor.java new file mode 100644 index 0000000..929bd43 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/processor/DingBasicExchangeProcessor.java @@ -0,0 +1,108 @@ +package com.evo.ding.processor; + +import com.evo.attendance.service.IRzAttendanceService; +import com.evo.attendance.service.RzAttendanceDetailService; +import com.evo.common.utils.Collections; +import com.evo.common.utils.spring.SpringUtils; +import com.evo.ding.service.DingShiftGroupService; +import com.evo.ding.service.DingShiftService; +import com.evo.personnelMatters.service.IRzLeaveDetailService; +import com.evo.personnelMatters.service.IRzLeaveService; +import com.evo.personnelMatters.service.IRzOverTimeDetailService; +import com.evo.personnelMatters.service.IRzOverTimeService; +import com.evo.system.domain.SysStaff; +import com.evo.system.service.ISysStaffService; + +import java.util.Map; + +/** + * 钉钉回调基础类型 DingBaseExchangeProcessor + * + * @author andy.shi + * @ClassName:DingBaseExchangeProcessor + * @date: 2026年03月12日 11:05 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +public interface DingBasicExchangeProcessor { + + final Map p = Collections.emptyMap(); + //审批状态 + String APPROVE_STATUS = "COMPLETED"; + + String APPROVE_RESULT = "AGREE"; + + default ISysStaffService getISysStaffService(){ + if(!p.containsKey("sysStaffService")){ + p.put("sysStaffService", SpringUtils.getBean(ISysStaffService.class)); + } + return (ISysStaffService)p.get("sysStaffService"); + } + + default IRzAttendanceService getIRzAttendanceService(){ + if(!p.containsKey("rzAttendanceService")){ + p.put("rzAttendanceService", SpringUtils.getBean(IRzAttendanceService.class)); + } + return (IRzAttendanceService)p.get("rzAttendanceService"); + } + + default RzAttendanceDetailService getRzAttendanceDetailService(){ + if(!p.containsKey("rzAttendanceDetailService")){ + p.put("rzAttendanceDetailService", SpringUtils.getBean(RzAttendanceDetailService.class)); + } + return (RzAttendanceDetailService)p.get("rzAttendanceDetailService"); + } + + default IRzOverTimeService getIRzOverTimeService(){ + if(!p.containsKey("rzOverTimeService")){ + p.put("rzOverTimeService", SpringUtils.getBean(IRzOverTimeService.class)); + } + return (IRzOverTimeService)p.get("rzOverTimeService"); + } + + default IRzOverTimeDetailService getIRzOverTimeDetailService(){ + if(!p.containsKey("rzOverTimeDetailService")){ + p.put("rzOverTimeDetailService", SpringUtils.getBean(IRzOverTimeDetailService.class)); + } + return (IRzOverTimeDetailService)p.get("rzOverTimeDetailService"); + } + + default DingShiftService getDingShiftService(){ + if(!p.containsKey("dingShiftService")){ + p.put("dingShiftService", SpringUtils.getBean(DingShiftService.class)); + } + return (DingShiftService)p.get("dingShiftService"); + } + + default DingShiftGroupService getDingShiftGroupService(){ + if(!p.containsKey("dingShiftGroupService")){ + p.put("dingShiftGroupService", SpringUtils.getBean(DingShiftGroupService.class)); + } + return (DingShiftGroupService)p.get("dingShiftGroupService"); + } + + default IRzLeaveService getIRzLeaveService(){ + if(!p.containsKey("rzLeaveService")){ + p.put("rzLeaveService", SpringUtils.getBean(IRzLeaveService.class)); + } + return (IRzLeaveService)p.get("rzLeaveService"); + } + + default IRzLeaveDetailService getIRzLeaveDetailService(){ + if(!p.containsKey("rzLeaveDetailService")){ + p.put("rzLeaveDetailService", SpringUtils.getBean(IRzLeaveDetailService.class)); + } + return (IRzLeaveDetailService)p.get("rzLeaveDetailService"); + } + + + + + + default SysStaff getSysStaffByDingUserId(String dingUserId){ + SysStaff sysStaff = getISysStaffService().selectSysStaffByDingUserId(dingUserId); + if(sysStaff == null){ + throw new RuntimeException("未查询到用户信息, 用户的DingUserId为:"+dingUserId); + } + return sysStaff; + } +} diff --git a/evo-admin/src/main/java/com/evo/ding/processor/approveStatus/AttendanceApproveStatusChangeExchangeProcessor.java b/evo-admin/src/main/java/com/evo/ding/processor/approveStatus/AttendanceApproveStatusChangeExchangeProcessor.java new file mode 100644 index 0000000..83db63e --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/processor/approveStatus/AttendanceApproveStatusChangeExchangeProcessor.java @@ -0,0 +1,60 @@ +package com.evo.ding.processor.approveStatus; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import com.aliyun.dingtalkworkflow_1_0.models.GetProcessInstanceResponseBody; +import com.evo.ding.processor.DingBasicExchangeProcessor; +import com.evo.system.domain.SysStaff; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Field; +import java.util.List; + +/** + * 请假、加班、出差、外出状态变更事件 回调 InstanceChangeExchangeProcessor + * + * @author andy.shi + * @ClassName:InstanceChangeExchangeProcessor + * @date: 2026年03月09日 15:25 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ + +public interface AttendanceApproveStatusChangeExchangeProcessor extends DingBasicExchangeProcessor { + + Logger logger = LoggerFactory.getLogger(AttendanceApproveStatusChangeExchangeProcessor.class); + //请假 + String APPROVE_TYPE_LEAVE = "LEAVE"; + //加班 + String APPROVE_TYPE_OVERTIME = "OVERTIME"; + //请假 + String APPROVE_TYPE_OUT = "OUT"; + //撤销 + String BIZ_ACTION_REVOKE = "REVOKE"; + + boolean accept(String approveType, String result, String status); + + void exchange(String processInstanceId, GetProcessInstanceResponseBody.GetProcessInstanceResponseBodyResult json); + + default JSONObject getExtValue(GetProcessInstanceResponseBody.GetProcessInstanceResponseBodyResult json, String componentType) { + List formComponentValueList = json.getFormComponentValues(); + GetProcessInstanceResponseBody.GetProcessInstanceResponseBodyResultFormComponentValues formComponentValue = formComponentValueList.stream().filter(data -> componentType.equals(data.getComponentType())).findAny().orElse(null); + if(formComponentValue != null){ + return JSON.parseObject(formComponentValue.getExtValue()); + } + throw new RuntimeException("未查询到相关审批信息, 审批类型为:"+componentType+"; 参数信息为: "+ json.toString()); + } + + default JSONArray getValue(GetProcessInstanceResponseBody.GetProcessInstanceResponseBodyResult json, String componentType) { + List formComponentValueList = json.getFormComponentValues(); + GetProcessInstanceResponseBody.GetProcessInstanceResponseBodyResultFormComponentValues formComponentValue = formComponentValueList.stream().filter(data -> componentType.equals(data.getComponentType())).findAny().orElse(null); + if(formComponentValue != null){ + return JSON.parseArray(formComponentValue.getValue()); + } + throw new RuntimeException("未查询到相关审批信息, 审批类型为:"+componentType+"; 参数信息为: "+ json.toString()); + } + + + +} diff --git a/evo-admin/src/main/java/com/evo/ding/processor/approveStatus/impl/ApproveStatusLeaveExchangeProcessor.java b/evo-admin/src/main/java/com/evo/ding/processor/approveStatus/impl/ApproveStatusLeaveExchangeProcessor.java new file mode 100644 index 0000000..8757420 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/processor/approveStatus/impl/ApproveStatusLeaveExchangeProcessor.java @@ -0,0 +1,127 @@ +package com.evo.ding.processor.approveStatus.impl; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import com.aliyun.dingtalkworkflow_1_0.models.GetProcessInstanceResponseBody; +import com.evo.common.constant.Constants; +import com.evo.common.core.domain.entity.SysDictData; +import com.evo.common.utils.DataUtils; +import com.evo.common.utils.StringUtils; +import com.evo.ding.processor.approveStatus.AttendanceApproveStatusChangeExchangeProcessor; +import com.evo.personnelMatters.domain.RzLeave; +import com.evo.personnelMatters.domain.RzLeaveDetail; +import com.evo.system.domain.SysStaff; +import com.evo.system.service.ISysDictDataService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * 请假事件处理 ApproveStatusLeaveExchangeProcessor + * + * @author andy.shi + * @ClassName:ApproveStatusLeaveExchangeProcessor + * @date: 2026年03月12日 13:32 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@Slf4j +@Service +public class ApproveStatusLeaveExchangeProcessor implements AttendanceApproveStatusChangeExchangeProcessor { + + @Autowired + ISysDictDataService sysDictDataService; + + @Override + public boolean accept(String approveType, String result, String status) { + return APPROVE_TYPE_LEAVE.equals(approveType.toUpperCase()) && APPROVE_STATUS.equals(status.toUpperCase()) && APPROVE_RESULT.equals(result.toUpperCase()); + } + + @Override + public void exchange(String processInstanceId, GetProcessInstanceResponseBody.GetProcessInstanceResponseBodyResult json) { + try { + + //如果是撤销, 执行撤销 + if(BIZ_ACTION_REVOKE.equals(json.getBizAction())){ + revoke(processInstanceId); + }else{ + leave(processInstanceId, getSysStaffByDingUserId(json.getOriginatorUserId()), json); + } + } catch (Exception e) { + log.error("执行钉钉 -["+(BIZ_ACTION_REVOKE.equals(json.getBizAction()) ? "撤销" : "请假")+"审批]-回调出现异常, 异常原因为:{}", e.getMessage()); + e.printStackTrace(); + } + + } + + + /*** + * 撤销假期 + * @param processInstanceId 钉钉审批单详情 + */ + public void revoke(String processInstanceId){ + RzLeaveDetail rzLeaveDetail = getIRzLeaveDetailService().selectRzLeaveDetailByProcessInstanceId(processInstanceId); + if(rzLeaveDetail != null){ + getIRzLeaveDetailService().deleteRzLeaveDetailById(rzLeaveDetail.getId()); + } + } + + /*** + * 请假 + * @param processInstanceId 钉钉审批单详情 + * @param sysStaff 平台用户 + * @param json 请求数据信息 + */ + public void leave(String processInstanceId, SysStaff sysStaff, GetProcessInstanceResponseBody.GetProcessInstanceResponseBodyResult json) { + + JSONObject extValueJson = getExtValue(json, "DDHolidayField"); + //解析假期类型 + JSONObject extension = JSON.parseObject(extValueJson.getString("extension")); + //查询假期类型 + String tag = extension.getString("tag"); + SysDictData sysDictData = sysDictDataService.selectDictDataListByType("holidays_type").stream().filter(data-> StringUtils.equals(data.getDictLabel(),tag)).findFirst().orElse(null); + if(sysDictData != null){ + //假期类型的code + Long dictCode = sysDictData.getDictCode(); + JSONArray detailList = extValueJson.getJSONArray("detailList"); + Date beginTime = null; + Date endTime = null; + //如果大于1 证明是多天请假, 需要排序 + if(detailList.size() > 1){ + detailList.sort((a,b)->{ + return ((JSONObject) a).getLong("workDate").compareTo(((JSONObject) b).getLong("workDate")); + }); + //获取第一天 + beginTime = new Date(detailList.getJSONObject(0).getJSONObject("approveInfo").getLong("fromTime")); + //获取最后一天 + endTime = new Date(detailList.getJSONObject(detailList.size()-1).getJSONObject("approveInfo").getLong("toTime")); + }else{ + //只请一天假 + JSONObject approveInfo = detailList.getJSONObject(0).getJSONObject("approveInfo"); + beginTime = new Date(approveInfo.getLong("fromTime")); + //获取最后一天 + endTime = new Date(approveInfo.getLong("toTime")); + } + + RzLeave rzLeave = getIRzLeaveService().selectRzLeaveByUserId(sysStaff.getUserId()); + RzLeaveDetail rzLeaveDetail = new RzLeaveDetail(); + rzLeaveDetail.setName(sysStaff.getName()); + rzLeaveDetail.setLeaveStartTime(beginTime); + rzLeaveDetail.setLeaveEndTime(endTime); + rzLeaveDetail.setLeaveId(rzLeave.getId()); + rzLeaveDetail.setType(dictCode); +// if("调休".equals(tag)){ + rzLeaveDetail.setLeaveHour(new BigDecimal(extValueJson.getDouble("durationInDay")).multiply(Constants.DAY_WORK_HOUR).intValue()); +// }else{ +// rzLeaveDetail.setLeaveHour(extValueJson.getInteger("durationInHour")); +// } + rzLeaveDetail.setRemarks("钉钉"+tag); + rzLeaveDetail.setProcessInstanceId(processInstanceId); + getIRzLeaveDetailService().insertRzLeaveDetail(rzLeaveDetail); + } + } + +} diff --git a/evo-admin/src/main/java/com/evo/ding/processor/approveStatus/impl/ApproveStatusOutExchangeProcessor.java b/evo-admin/src/main/java/com/evo/ding/processor/approveStatus/impl/ApproveStatusOutExchangeProcessor.java new file mode 100644 index 0000000..ce53ebe --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/processor/approveStatus/impl/ApproveStatusOutExchangeProcessor.java @@ -0,0 +1,127 @@ +package com.evo.ding.processor.approveStatus.impl; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import com.aliyun.dingtalkworkflow_1_0.models.GetProcessInstanceResponseBody; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.evo.attendance.domain.RzAttendance; +import com.evo.attendance.domain.RzAttendanceDetail; +import com.evo.attendance.mapper.RzAttendanceMapper; +import com.evo.attendance.service.IRzAttendanceService; +import com.evo.attendance.service.RzAttendanceDetailService; +import com.evo.common.core.domain.entity.SysDictData; +import com.evo.common.utils.ParamUtils; +import com.evo.common.utils.StringUtils; +import com.evo.ding.processor.approveStatus.AttendanceApproveStatusChangeExchangeProcessor; +import com.evo.personnelMatters.domain.RzLeave; +import com.evo.personnelMatters.domain.RzLeaveDetail; +import com.evo.system.domain.SysStaff; +import com.evo.system.service.ISysDictDataService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.time.Instant; +import java.util.Date; + +/** + * 出差事件处理 ApproveStatusOutExchangeProcessor + * + * @author andy.shi + * @ClassName:ApproveStatusLeaveExchangeProcessor + * @date: 2026年03月12日 13:32 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@Slf4j +@Service +public class ApproveStatusOutExchangeProcessor implements AttendanceApproveStatusChangeExchangeProcessor { + + @Resource + private RzAttendanceMapper rzAttendanceMapper; + @Resource + private RzAttendanceDetailService rzAttendanceDetailService; + + @Override + public boolean accept(String approveType, String result, String status) { + return APPROVE_TYPE_OUT.equals(approveType.toUpperCase()) && APPROVE_STATUS.equals(status.toUpperCase()) && APPROVE_RESULT.equals(result.toUpperCase()); + } + + @Override + public void exchange(String processInstanceId, GetProcessInstanceResponseBody.GetProcessInstanceResponseBodyResult json) { + try { + rzAttendance(json, BIZ_ACTION_REVOKE.equals(json.getBizAction())); + } catch (Exception e) { + log.error("执行钉钉 -[出差审批]-回调出现异常, 异常原因为:{}", e.getMessage()); + e.printStackTrace(); + } + + } + /*** + * + * @param json 审批单数据 + * @param isRevoke 是否为撤回 + */ + public void rzAttendance(GetProcessInstanceResponseBody.GetProcessInstanceResponseBodyResult json, Boolean isRevoke){ + SysStaff sysStaff = getSysStaffByDingUserId(json.getOriginatorUserId()); + //出差 + JSONArray valueJson = getValue(json, "TableField"); + JSONObject jsonObject = valueJson.getJSONObject(0); + JSONArray rowValue = jsonObject.getJSONArray("rowValue"); + for (int i = 0; i < rowValue.size(); i++) { + JSONObject rowValueObject = rowValue.getJSONObject(i); + if ("duration".equals(rowValueObject.getString("bizAlias"))) { + JSONObject extendValue = rowValueObject.getJSONObject("extendValue"); + JSONArray detailList = extendValue.getJSONArray("detailList"); + for (int j = 0; j < detailList.size(); j++) { + JSONObject detailObject = detailList.getJSONObject(j); + Date formatWorkDate = Date.from(Instant.ofEpochMilli(detailObject.getLong("workDate"))); + //检查是否为假期, 如果为假期, 不做记录, 只记录不是假期的数据, 假期的外出, 需要提交加班审批 + if (!ParamUtils.checkHoliday(formatWorkDate)) { + JSONObject classInfo = detailObject.getJSONObject("classInfo"); + JSONObject section = classInfo.getJSONArray("sections").getJSONObject(0); + Long startTime = section.getLong("startTime"); + Long endTime = section.getLong("endTime"); + Integer durationInHour = detailObject.getJSONObject("approveInfo").getInteger("durationInHour"); + Date formatStartTime = Date.from(Instant.ofEpochMilli(startTime)); + Date formatEndTime = Date.from(Instant.ofEpochMilli(endTime)); + //通过workDate 获取哪一天的卡 + RzAttendance attendance = rzAttendanceMapper.queryNowDayAttendanceByStatisticalIdAndDate(sysStaff.getUserId(), formatStartTime); + if(isRevoke){ + //清除打卡记录 + rzAttendanceDetailService.remove(new LambdaQueryWrapper().eq(RzAttendanceDetail::getAttendanceId, attendance.getId())); + //重置打卡信息 + attendance.setRules(""); + attendance.setWorkStartTime(null); + attendance.setWorkEndTime(null); + attendance.setWorkSum(BigDecimal.valueOf(0)); + attendance.setNightNumber(0); + attendance.setMiddleShiftNumber(0); + }else{ + //生成打卡记录 + rzAttendanceDetailService.addDetail(attendance, "上班卡", "/", formatStartTime, "出差自动打卡", ""); + rzAttendanceDetailService.addDetail(attendance, "下班卡", "/", formatEndTime, "出差自动打卡", ""); + //上班 + attendance.setRules("上班卡"); + attendance.setWorkStartTime(formatStartTime); + attendance.setWorkEndTime(formatEndTime); + attendance.setWorkSum(BigDecimal.valueOf(durationInHour)); + if (attendance.getWorkSum().intValue() >= 12 && attendance.getWorkStartTime() != null && attendance.getWorkStartTime().getHours() > 12) { + attendance.setNightNumber(1); + } else if (attendance.getWorkSum().intValue() >= 8 && attendance.getWorkStartTime() != null && attendance.getWorkStartTime().getHours() >= 12 && attendance.getWorkStartTime().getHours() < 21) { + attendance.setMiddleShiftNumber(1); + } + } + + rzAttendanceMapper.updateRzAttendance(attendance); + } + } + break; + } + } + } + + +} diff --git a/evo-admin/src/main/java/com/evo/ding/processor/approveStatus/impl/ApproveStatusOvertimeExchangeProcessor.java b/evo-admin/src/main/java/com/evo/ding/processor/approveStatus/impl/ApproveStatusOvertimeExchangeProcessor.java new file mode 100644 index 0000000..52a7106 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/processor/approveStatus/impl/ApproveStatusOvertimeExchangeProcessor.java @@ -0,0 +1,119 @@ +package com.evo.ding.processor.approveStatus.impl; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import com.aliyun.dingtalkworkflow_1_0.models.GetProcessInstanceResponseBody; +import com.evo.attendance.domain.RzAttendanceStatistical; +import com.evo.attendance.domain.RzSpecialAttendance; +import com.evo.attendance.domain.RzSpecialOverTime; +import com.evo.attendance.mapper.RzAttendanceStatisticalMapper; +import com.evo.attendance.mapper.RzSpecialAttendanceMapper; +import com.evo.attendance.mapper.RzSpecialOverTimeMapper; +import com.evo.attendance.service.IRzAttendanceStatisticalService; +import com.evo.attendance.service.IRzSpecialAttendanceService; +import com.evo.common.core.domain.entity.SysDictData; +import com.evo.common.utils.DataUtils; +import com.evo.common.utils.DateUtils; +import com.evo.common.utils.StringUtils; +import com.evo.ding.processor.approveStatus.AttendanceApproveStatusChangeExchangeProcessor; +import com.evo.personnelMatters.domain.RzLeave; +import com.evo.personnelMatters.domain.RzLeaveDetail; +import com.evo.system.domain.SysStaff; +import com.evo.system.service.ISysDictDataService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.ObjectUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + +/** + *加班事件处理 ApproveStatusOvertimeExchangeProcessor + * + * @author andy.shi + * @ClassName:ApproveStatusLeaveExchangeProcessor + * @date: 2026年03月12日 13:32 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@Slf4j +@Service +public class ApproveStatusOvertimeExchangeProcessor implements AttendanceApproveStatusChangeExchangeProcessor { + + @Autowired + IRzSpecialAttendanceService rzSpecialAttendanceService; + @Resource + private RzSpecialOverTimeMapper rzSpecialOverTimeMapper; + @Resource + private RzAttendanceStatisticalMapper rzAttendanceStatisticalMapper; + + @Override + public boolean accept(String approveType, String result, String status) { + //加班不在对接 + return false; //APPROVE_TYPE_OVERTIME.equals(approveType.toUpperCase()) && APPROVE_STATUS.equals(status.toUpperCase()) && APPROVE_RESULT.equals(result.toUpperCase()); + } + + @Override + @Transactional + public void exchange(String processInstanceId, GetProcessInstanceResponseBody.GetProcessInstanceResponseBodyResult result) { + try { + SysStaff sysStaff = getSysStaffByDingUserId(result.getOriginatorUserId()); + List formComponentValueList = result.getFormComponentValues(); + GetProcessInstanceResponseBody.GetProcessInstanceResponseBodyResultFormComponentValues startComponentValue = formComponentValueList.stream().filter(data -> "开始时间".equals(data.getName())).findAny().orElse(null); + GetProcessInstanceResponseBody.GetProcessInstanceResponseBodyResultFormComponentValues endValue = formComponentValueList.stream().filter(data -> "结束时间".equals(data.getName())).findAny().orElse(null); + GetProcessInstanceResponseBody.GetProcessInstanceResponseBodyResultFormComponentValues durationValue = formComponentValueList.stream().filter(data -> "时长".equals(data.getName())).findAny().orElse(null); + if(startComponentValue != null && endValue != null && durationValue != null){ + Date startDate = DateUtils.parseDate(startComponentValue.getValue(), "yyyy-MM-dd HH:mm"); + Date endDate = DateUtils.parseDate(endValue.getValue(), "yyyy-MM-dd HH:mm"); + BigDecimal duration = new BigDecimal(durationValue.getValue()); + //获取加班详情数据 + RzSpecialAttendance rzSpecialAttendance = rzSpecialAttendanceService.selectRzSpecialAttendanceByUserIdAndDate(sysStaff.getUserId(), startDate); + //如果没有, 则新增 + if(rzSpecialAttendance == null){ + rzSpecialAttendance = new RzSpecialAttendance(); + rzSpecialAttendance.setAttendanceDate(startDate); + rzSpecialAttendance.setStaffId(sysStaff.getUserId()); + rzSpecialAttendance.setName(sysStaff.getName()); + rzSpecialAttendance.setDeptId(sysStaff.getDeptId()); + rzSpecialAttendance.setDelFlag("0"); + rzSpecialAttendance.setCreateBy("admin"); + rzSpecialAttendance.setCreateTime(new Date()); + } + rzSpecialAttendance.setWorkStartTime(startDate); + rzSpecialAttendance.setWorkEndTime(endDate); + rzSpecialAttendance.setWorkHours(duration); + rzSpecialAttendanceService.saveOrUpdate(rzSpecialAttendance); + + //获取加班统计数据 + RzSpecialOverTime rzSpecialOverTime = rzSpecialOverTimeMapper.selectRzSpecialOverTimeByUserIdAndDate(rzSpecialAttendance.getStaffId(),rzSpecialAttendance.getAttendanceDate()); + if(ObjectUtils.isEmpty(rzSpecialOverTime)){ + rzSpecialOverTime = new RzSpecialOverTime(); + rzSpecialOverTime.setUserId(sysStaff.getUserId()); + rzSpecialOverTime.setName(sysStaff.getName()); + rzSpecialOverTime.setDeptId(sysStaff.getDeptId()); + rzSpecialOverTime.setDelFlag("0"); + rzSpecialOverTime.setOverDate(startDate); + rzSpecialOverTime.setCreateTime(new Date()); + rzSpecialOverTime.setCreateBy("admin"); + rzSpecialOverTimeMapper.insertRzSpecialOverTime(rzSpecialOverTime); + } + if(DataUtils.DEFAULT_VALUE.compareTo(rzSpecialAttendance.getWorkHours()) != 0){ + rzSpecialOverTime.setSickHours(DataUtils.findDefaultValue(rzSpecialOverTime.getSickHours(), new BigDecimal(0)).add(rzSpecialAttendance.getWorkHours())); + rzSpecialOverTimeMapper.updateRzSpecialOverTime(rzSpecialOverTime); + //更新加班统计 + RzAttendanceStatistical rzAttendanceStatistical = rzAttendanceStatisticalMapper.getRzAttendanceStatisticalByDateAndName(rzSpecialAttendance.getStaffId(),rzSpecialAttendance.getAttendanceDate()); + rzAttendanceStatistical.setOverTimeHours(DataUtils.findDefaultValue(rzAttendanceStatistical.getOverTimeHours(), new BigDecimal(0)).add(rzSpecialAttendance.getWorkHours())); + rzAttendanceStatisticalMapper.updateRzAttendanceStatistical(rzAttendanceStatistical); + } + } + } catch (Exception e) { + log.error("执行钉钉 -[加班审批]-回调出现异常, 异常原因为:{}", e.getMessage()); + e.printStackTrace(); + } + + } +} diff --git a/evo-admin/src/main/java/com/evo/ding/processor/callback/DingCallBackExchangeProcessor.java b/evo-admin/src/main/java/com/evo/ding/processor/callback/DingCallBackExchangeProcessor.java new file mode 100644 index 0000000..ca7ab11 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/processor/callback/DingCallBackExchangeProcessor.java @@ -0,0 +1,37 @@ +package com.evo.ding.processor.callback; + +import com.alibaba.fastjson2.JSONObject; + +/** + * 钉钉回调入口 DingCallBackExchangeProcessor + * + * @author andy.shi + * @ClassName:DingCallBackExchanageProcessor + * @date: 2026年03月12日 8:49 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +public interface DingCallBackExchangeProcessor { + + //入职 + static final String EVENT_TYPE_USER_ADD_ORG = "user_add_org"; + //离职 + static final String EVENT_TYPE_USER_LEAVE_ORG = "user_leave_org"; + //打卡 + static final String EVENT_TYPE_CHECK_RECORD = "attendance_check_record"; + //审批实例订阅-> 补卡 + static final String EVENT_TYPE_INSTANCE_CHANGE = "bpms_instance_change"; + //请假、加班、出差、外出状态变更事件 + static final String EVENT_TYPE_APPROVE_STATUS_CHANGE = "attendance_approve_status_change"; + //班制调整 + static final String EVENT_TYPE_ATTEND_SHIFT_CHANGE = "attend_shift_change"; + //考勤组调整 + static final String EVENT_TYPE_ATTEND_GROUP_CHANGE = "attend_group_change"; + + + + boolean accept(String eventType); + + void exchange(JSONObject json); + + +} diff --git a/evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackApproveStatusChangeExchangeProcessor.java b/evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackApproveStatusChangeExchangeProcessor.java new file mode 100644 index 0000000..3fe2417 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackApproveStatusChangeExchangeProcessor.java @@ -0,0 +1,49 @@ +package com.evo.ding.processor.callback.impl; + +import com.alibaba.fastjson2.JSONObject; +import com.aliyun.dingtalkworkflow_1_0.models.GetProcessInstanceResponseBody; +import com.evo.ding.DingUtils; +import com.evo.ding.processor.approveStatus.AttendanceApproveStatusChangeExchangeProcessor; +import com.evo.ding.processor.instance.InstanceChangeExchangeProcessor; +import com.evo.ding.processor.callback.DingCallBackExchangeProcessor; +import com.evo.system.domain.SysStaff; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 请假、加班、出差、外出状态变更事件 DingCallBackInstanceChangeExchangeProcessor + * + * @author andy.shi + * @ClassName:DingCallBackCheckRecordExchangeProcessor + * @date: 2026年03月12日 9:02 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@Slf4j +@Service +public class DingCallBackApproveStatusChangeExchangeProcessor implements DingCallBackExchangeProcessor { + + @Autowired + List approveStatusChangeExchangeProcessorList; + + @Override + public boolean accept(String eventType) { + return EVENT_TYPE_APPROVE_STATUS_CHANGE.equals(eventType); + } + + @Override + public void exchange(JSONObject json) { + log.info("请假、加班、出差、外出状态变更事件 回调 ========================>>>{}", json.toString()); + //获取审批示例id + String processInstanceId = json.getString("processInstanceId"); + GetProcessInstanceResponseBody.GetProcessInstanceResponseBodyResult result = DingUtils.getProcessInstanceInfo(processInstanceId); + System.out.println(JSONObject.toJSONString(result)); + for (AttendanceApproveStatusChangeExchangeProcessor processor : approveStatusChangeExchangeProcessorList) { + if (processor.accept(json.getString("approveType"), result.getResult(), result.getStatus())) { + processor.exchange(processInstanceId, result); + } + } + } +} diff --git a/evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackCheckRecordExchangeProcessor.java b/evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackCheckRecordExchangeProcessor.java new file mode 100644 index 0000000..2d05c89 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackCheckRecordExchangeProcessor.java @@ -0,0 +1,44 @@ +package com.evo.ding.processor.callback.impl; + +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import com.evo.attendance.service.IRzAttendanceService; +import com.evo.common.utils.StringUtils; +import com.evo.ding.processor.callback.DingCallBackExchangeProcessor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 员工打开回调 DingCallBackCheckRecordExchangeProcessor + * + * @author andy.shi + * @ClassName:DingCallBackCheckRecordExchangeProcessor + * @date: 2026年03月12日 9:02 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@Slf4j +@Service +public class DingCallBackCheckRecordExchangeProcessor implements DingCallBackExchangeProcessor { + + @Autowired + IRzAttendanceService rzAttendanceService; + + @Override + public boolean accept(String eventType) { + return EVENT_TYPE_CHECK_RECORD.equals(eventType); + } + + @Override + public void exchange(JSONObject json) { + log.info("钉钉 打卡回调========================>>>{}", json.toString()); + JSONArray dataList = json.getJSONArray("DataList"); + if(dataList!= null && dataList.size() > 0){ + JSONObject jsonObject = dataList.getJSONObject(0); + String userId = jsonObject.getString("userId"); + if(StringUtils.isNotEmpty(userId)){ + rzAttendanceService.dingDing(userId, jsonObject.getString("bizId"), jsonObject.getLong("checkTime")); + } + } + } +} diff --git a/evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackGroupChangeExchangeProcessor.java b/evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackGroupChangeExchangeProcessor.java new file mode 100644 index 0000000..d01f23d --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackGroupChangeExchangeProcessor.java @@ -0,0 +1,113 @@ +package com.evo.ding.processor.callback.impl; + +import com.alibaba.fastjson2.JSONObject; +import com.dingtalk.api.response.OapiAttendanceGroupQueryResponse; +import com.dingtalk.api.response.OapiAttendanceShiftQueryResponse; +import com.evo.common.utils.Collections; +import com.evo.common.utils.DateUtils; +import com.evo.ding.DingUtils; +import com.evo.ding.domain.DingGroup; +import com.evo.ding.domain.DingShift; +import com.evo.ding.domain.DingShiftGroup; +import com.evo.ding.processor.callback.DingCallBackExchangeProcessor; +import com.evo.ding.service.DingGroupService; +import com.evo.ding.service.DingShiftGroupService; +import com.evo.ding.service.DingShiftService; +import io.swagger.models.auth.In; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * 考勤组信息调整 DingCallBackGroupChangeExchangeProcessor + * @author andy.shi + * @ClassName:DingCallBackCheckRecordExchangeProcessor + * @date: 2026年03月12日 9:02 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@Slf4j +@Service +public class DingCallBackGroupChangeExchangeProcessor implements DingCallBackExchangeProcessor { + + @Autowired + DingGroupService dingGroupService; + + @Autowired + DingShiftService dingShiftService; + + @Autowired + DingShiftGroupService dingShiftGroupService; + + @Override + public boolean accept(String eventType) { + return EVENT_TYPE_ATTEND_GROUP_CHANGE.equals(eventType); + } + + @Override + public void exchange(JSONObject json) { + log.info("钉钉 班制调整回调========================>>>{}", json.toString()); + OapiAttendanceGroupQueryResponse.TopSimpleGroupVO groupDetail = DingUtils.getGroupDetail(json.getLong("id")); + if(groupDetail != null){ + String groupDingId = String.valueOf(groupDetail.getId()); + DingGroup dingGroup = dingGroupService.selectByDingId(groupDingId); + if(dingGroup == null){ + dingGroup = new DingGroup(); + } + dingGroup.setName(groupDetail.getName()); + dingGroup.setDingId(groupDingId); + dingGroupService.saveOrUpdate(dingGroup); + + //获取现在所有的数据 + List dingShiftGroupList = dingShiftGroupService.selectListByGroupId(groupDingId); + //如果返回为空, 旧数据不为空, 直接清除 + if(Collections.isEmpty(groupDetail.getShiftIds()) && Collections.isNotEmpty(dingShiftGroupList)){ + dingShiftGroupService.removeByIds(dingShiftGroupList); + }else if(Collections.isNotEmpty(groupDetail.getShiftIds()) && Collections.isEmpty(dingShiftGroupList)){ + //更新绑定信息 + for (Long shiftId : groupDetail.getShiftIds()) { + crateDingShiftGroup(groupDingId, String.valueOf(shiftId)); + } + }else if(Collections.isNotEmpty(groupDetail.getShiftIds()) && Collections.isNotEmpty(dingShiftGroupList)){ + Map> map = dingShiftGroupList.stream().collect(Collectors.groupingBy(DingShiftGroup::getShiftId)); + for (Long shiftId : groupDetail.getShiftIds()) { + String strShiftId = String.valueOf(shiftId); + if(map.containsKey(strShiftId)){ + DingShift dingShift = dingShiftService.selectByDingId(strShiftId); + for (DingShiftGroup dingShiftGroup : map.get(strShiftId)){ + dingShiftGroup.setCheckTime(("OnDuty".equals(dingShiftGroup.getType()) ? dingShift.getOnDutyCheckTime() : dingShift.getOffDutyCheckTime())); + dingShiftGroupService.updateById(dingShiftGroup); + } + map.remove(strShiftId); + }else{ + crateDingShiftGroup(groupDingId, String.valueOf(shiftId)); + } + } + //如果还存在, 需要删除 + if(Collections.isNotEmpty(map)){ + dingShiftGroupService.removeByIds(map.values().stream().filter(Objects::nonNull).flatMap(Collection::stream).collect(Collectors.toList())); + } + } + } + } + public void crateDingShiftGroup(String groupId, String shiftId){ + DingShift dingShift = dingShiftService.selectByDingId(shiftId); + //直接更新上班, 下班 + for (int i = 0; i < 2; i++) { + DingShiftGroup dingShiftGroup = new DingShiftGroup(); + dingShiftGroup.setGroupId(groupId); + dingShiftGroup.setShiftId(String.valueOf(shiftId)); + dingShiftGroup.setType(i == 0 ? "OnDuty" : "OffDuty"); + if(dingShift != null){ + dingShiftGroup.setCheckTime(i == 0 ? dingShift.getOnDutyCheckTime() : dingShift.getOffDutyCheckTime()); + } + dingShiftGroupService.save(dingShiftGroup); + } + } +} diff --git a/evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackInstanceChangeExchangeProcessor.java b/evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackInstanceChangeExchangeProcessor.java new file mode 100644 index 0000000..a401827 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackInstanceChangeExchangeProcessor.java @@ -0,0 +1,41 @@ +package com.evo.ding.processor.callback.impl; + +import com.alibaba.fastjson2.JSONObject; +import com.evo.ding.processor.instance.InstanceChangeExchangeProcessor; +import com.evo.ding.processor.callback.DingCallBackExchangeProcessor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 审批实例订阅 DingCallBackInstanceChangeExchangeProcessor + * + * @author andy.shi + * @ClassName:DingCallBackCheckRecordExchangeProcessor + * @date: 2026年03月12日 9:02 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@Slf4j +@Service +public class DingCallBackInstanceChangeExchangeProcessor implements DingCallBackExchangeProcessor { + + @Autowired + List instanceChangeExchangeProcessorList; + + @Override + public boolean accept(String eventType) { + return EVENT_TYPE_INSTANCE_CHANGE.equals(eventType); + } + + @Override + public void exchange(JSONObject json) { + log.info("审批实例订阅回调========================>>>{}", json.toString()); + for (InstanceChangeExchangeProcessor processor : instanceChangeExchangeProcessorList) { + if (processor.accept(json.getString("processCode"))) { + processor.exchange(json); + } + } + } +} diff --git a/evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackShiftChangeExchangeProcessor.java b/evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackShiftChangeExchangeProcessor.java new file mode 100644 index 0000000..d9a1939 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackShiftChangeExchangeProcessor.java @@ -0,0 +1,69 @@ +package com.evo.ding.processor.callback.impl; + +import com.alibaba.fastjson2.JSONObject; +import com.dingtalk.api.response.OapiAttendanceShiftQueryResponse; +import com.evo.common.utils.DateUtils; +import com.evo.ding.DingUtils; +import com.evo.ding.domain.DingShift; +import com.evo.ding.processor.callback.DingCallBackExchangeProcessor; +import com.evo.ding.service.DingShiftGroupService; +import com.evo.ding.service.DingShiftService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; + +/** + * 班制信息调整 DingCallBackShiftChangeExchangeProcessor + * @author andy.shi + * @ClassName:DingCallBackCheckRecordExchangeProcessor + * @date: 2026年03月12日 9:02 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@Slf4j +@Service +public class DingCallBackShiftChangeExchangeProcessor implements DingCallBackExchangeProcessor { + + @Autowired + DingShiftService dingShiftService; + + @Autowired + DingShiftGroupService dingShiftGroupService; + + @Override + public boolean accept(String eventType) { + return EVENT_TYPE_ATTEND_SHIFT_CHANGE.equals(eventType); + } + + @Override + public void exchange(JSONObject json) { + log.info("钉钉 班制调整回调========================>>>{}", json.toString()); + OapiAttendanceShiftQueryResponse.TopShiftVo shiftDetail = DingUtils.getShiftDetail(json.getLong("id")); + if(shiftDetail != null){ + String shiftDingId = String.valueOf(shiftDetail.getId()); + DingShift dingShift = dingShiftService.selectByDingId(shiftDingId); + //获取工作时长 + OapiAttendanceShiftQueryResponse.TopShiftSettingVo topShiftSettingVo = shiftDetail.getShiftSetting(); + + OapiAttendanceShiftQueryResponse.TopSectionVo topSectionVo = shiftDetail.getSections().get(0); + OapiAttendanceShiftQueryResponse.TopPunchVo newOnDutyTopPunchVo = topSectionVo.getPunches().stream().filter(data -> data.getCheckType().equals("OnDuty")).findAny().orElse(null); + OapiAttendanceShiftQueryResponse.TopPunchVo newOffDutyTopPunchVo = topSectionVo.getPunches().stream().filter(data -> data.getCheckType().equals("OffDuty")).findAny().orElse(null); + //如果不存在班制, 创建新的班制 + if(dingShift == null){ + //如果本地不存在, 直接创建新的 + dingShift = new DingShift(); + dingShift.setName(shiftDetail.getName()); + dingShift.setDingId(shiftDingId); + } + dingShift.setWorkHour(new BigDecimal(topShiftSettingVo.getWorkTimeMinutes()).divide(new BigDecimal(60), 2, java.math.BigDecimal.ROUND_HALF_UP).intValue()); + dingShift.setOnDutyCheckTime(DateUtils.parseDateToStr("HH:mm:ss",newOnDutyTopPunchVo.getCheckTime())); + dingShift.setOffDutyCheckTime(DateUtils.parseDateToStr("HH:mm:ss",newOffDutyTopPunchVo.getCheckTime())); + //通过三目判定, 如果id为空, 则走保存,如果存在id 则更新 + if((dingShift.getId() == null ? dingShiftService.save(dingShift) : dingShiftService.updateById(dingShift))){ + dingShiftGroupService.updateCheckTimeByShiftIdAndType(shiftDingId, newOnDutyTopPunchVo.getCheckType(), dingShift.getOnDutyCheckTime()); + dingShiftGroupService.updateCheckTimeByShiftIdAndType(shiftDingId, newOffDutyTopPunchVo.getCheckType(), dingShift.getOffDutyCheckTime()); + } + } + } +} diff --git a/evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackUseLeaveOrgExchangeProcessor.java b/evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackUseLeaveOrgExchangeProcessor.java new file mode 100644 index 0000000..4430eb7 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackUseLeaveOrgExchangeProcessor.java @@ -0,0 +1,41 @@ +package com.evo.ding.processor.callback.impl; + +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import com.evo.ding.processor.callback.DingCallBackExchangeProcessor; +import com.evo.system.service.ISysStaffService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 员工离职 DingCallBackUseLeaveOrgExchangeProcessor + * + * @author andy.shi + * @ClassName:DingCallBackUseLeaveOrgExchangeProcessor + * @date: 2026年03月12日 9:02 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@Slf4j +@Service +public class DingCallBackUseLeaveOrgExchangeProcessor implements DingCallBackExchangeProcessor { + + @Autowired + ISysStaffService sysStaffService; + + @Override + public boolean accept(String eventType) { + return EVENT_TYPE_USER_LEAVE_ORG.equals(eventType); + } + + @Override + public void exchange(JSONObject json) { + log.info("钉钉 员工离职========================>>>{}", json.toString()); + JSONArray dataList = json.getJSONArray("userId"); + if(dataList!= null && dataList.size() > 0){ + dataList.forEach(data->{ + sysStaffService.sysStaffLeaveByDingUserId(String.valueOf(data)); + }); + } + } +} diff --git a/evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackUserAddOrgExchangeProcessor.java b/evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackUserAddOrgExchangeProcessor.java new file mode 100644 index 0000000..642e0c1 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/processor/callback/impl/DingCallBackUserAddOrgExchangeProcessor.java @@ -0,0 +1,44 @@ +package com.evo.ding.processor.callback.impl; + +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import com.evo.attendance.service.IRzAttendanceService; +import com.evo.common.utils.StringUtils; +import com.evo.ding.DingUtils; +import com.evo.ding.processor.callback.DingCallBackExchangeProcessor; +import com.evo.system.service.ISysStaffService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 员工入职 DingCallBackUserAddOrgExchangeProcessor + * + * @author andy.shi + * @ClassName:DingCallBackUserAddOrgExchangeProcessor + * @date: 2026年03月12日 9:02 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@Slf4j +@Service +public class DingCallBackUserAddOrgExchangeProcessor implements DingCallBackExchangeProcessor { + + @Autowired + ISysStaffService sysStaffService; + + @Override + public boolean accept(String eventType) { + return EVENT_TYPE_USER_ADD_ORG.equals(eventType); + } + + @Override + public void exchange(JSONObject json) { + log.info("钉钉 新增员工========================>>>{}", json.toString()); + JSONArray dataList = json.getJSONArray("UserId"); + if(dataList!= null && dataList.size() > 0){ + dataList.forEach(data->{ + sysStaffService.insertSysStaffByDingDing(DingUtils.getUserInfoByUserId(String.valueOf(data))); + }); + } + } +} diff --git a/evo-admin/src/main/java/com/evo/ding/processor/instance/InstanceChangeExchangeProcessor.java b/evo-admin/src/main/java/com/evo/ding/processor/instance/InstanceChangeExchangeProcessor.java new file mode 100644 index 0000000..3b2af57 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/processor/instance/InstanceChangeExchangeProcessor.java @@ -0,0 +1,32 @@ +package com.evo.ding.processor.instance; + +import com.alibaba.fastjson2.JSONObject; +import com.evo.ding.processor.DingBasicExchangeProcessor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 钉钉审批实例回调处理接口 InstanceChangeExchangeProcessor + * + * @author andy.shi + * @ClassName:InstanceChangeExchangeProcessor + * @date: 2026年03月09日 15:25 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ + +public interface InstanceChangeExchangeProcessor extends DingBasicExchangeProcessor { + + Logger logger = LoggerFactory.getLogger(InstanceChangeExchangeProcessor.class); + + //补卡 + static final String PROCESS_CODE_RECHARGE_CARD = "PROC-19617D02-F632-402E-9ACD-134CC47E462F"; + + boolean accept(String processCode); + + void exchange(JSONObject json); + + + + + +} diff --git a/evo-admin/src/main/java/com/evo/ding/processor/instance/impl/InstanceChangeRechargeCardExchangeProcessor.java b/evo-admin/src/main/java/com/evo/ding/processor/instance/impl/InstanceChangeRechargeCardExchangeProcessor.java new file mode 100644 index 0000000..4d8c36c --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/processor/instance/impl/InstanceChangeRechargeCardExchangeProcessor.java @@ -0,0 +1,78 @@ +package com.evo.ding.processor.instance.impl; + +import com.alibaba.fastjson2.JSONObject; +import com.aliyun.dingtalkworkflow_1_0.models.GetProcessInstanceResponseBody; +import com.evo.common.utils.DateUtils; +import com.evo.common.utils.ParamUtils; +import com.evo.common.utils.StringUtils; +import com.evo.ding.DingUtils; +import com.evo.ding.domain.DingShiftGroup; +import com.evo.ding.processor.instance.InstanceChangeExchangeProcessor; +import com.evo.system.domain.SysStaff; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.text.ParseException; +import java.util.Date; +import java.util.List; + +/** + * 钉钉补卡接口回调 InstanceChangeRechargeCardExchangeProcessor + * + * @author andy.shi + * @ClassName:InstanceChangeRechargeCardExchangeProcessor + * @date: 2026年03月10日 10:24 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@Slf4j +@Service +public class InstanceChangeRechargeCardExchangeProcessor implements InstanceChangeExchangeProcessor { + + @Override + public boolean accept(String processCode) { + return InstanceChangeExchangeProcessor.PROCESS_CODE_RECHARGE_CARD.equals(processCode); + } + @Override + public void exchange(JSONObject json) { + //获取审批示例id + String processInstanceId = json.getString("processInstanceId"); + GetProcessInstanceResponseBody.GetProcessInstanceResponseBodyResult result = DingUtils.getProcessInstanceInfo(processInstanceId); + //根据操作人id, 获取user + SysStaff sysStaff = getSysStaffByDingUserId(result.getOriginatorUserId()); + if(sysStaff != null){ + List resultFormValues = result.getFormComponentValues(); + //补卡时间 + String bkTime = resultFormValues.stream().filter(data-> "补卡时间".equals(data.getName()) && StringUtils.isNotEmpty(data.getValue())).findFirst().get().getValue(); + String extValue = resultFormValues.stream().filter(data-> "补卡时间".equals(data.getName()) && StringUtils.isNotEmpty(data.getExtValue())).findFirst().get().getExtValue(); + //补卡类型 + String bkType = resultFormValues.stream().filter(data-> "补卡类型".equals(data.getName()) && StringUtils.isNotEmpty(data.getValue())).findFirst().get().getValue(); + //补卡原因 + String bkYi = resultFormValues.stream().filter(data-> "补卡原因".equals(data.getName()) && StringUtils.isNotEmpty(data.getValue())).findFirst().get().getValue(); + //获取补卡班次 + String checkType = "上班卡".equals(bkType) ? "OnDuty" : "OffDuty"; + DingShiftGroup dingsShiftGroup = null; + try { + if(StringUtils.isNotEmpty(extValue)){ + JSONObject js = JSONObject.parseObject(extValue); + String planId = js.getString("planId"); + String s = DingUtils.getPlanInfo(result.getOriginatorUserId(), planId); + JSONObject planResult = JSONObject.parseObject(s); + if(Integer.valueOf(0).equals(planResult.getInteger("errcode"))){ + JSONObject planResultObject = planResult.getJSONArray("result").getJSONObject(0); + String formatPlanCheckTime = DateUtils.parseDateToStr("HH:mm:ss", new Date(planResultObject.getString("plan_check_time"))); + dingsShiftGroup = getDingShiftGroupService().selectByGroupIdAndTypeAndCheckTime(planResultObject.getString("group_id"), planResultObject.getString("class_id"), checkType, formatPlanCheckTime); + Date date= DateUtils.parseDate(bkTime, "yyyy-MM-dd HH:mm"); + //生成补卡记录信息 + getIRzAttendanceService().addRzOverTime(json.toString(), sysStaff, dingsShiftGroup, checkType, date, date, "/", "钉钉补卡-"+bkYi, ParamUtils.getDebiting(), null); + } + } + } catch (ParseException e) { + log.info("补卡出现错误, 为在本地找到班次数据, 错误信息为:{}, 回调信息为: {}", e.getMessage(), json.toString()); + e.printStackTrace(); + } + } + } +} + + + diff --git a/evo-admin/src/main/java/com/evo/ding/service/DingGroupService.java b/evo-admin/src/main/java/com/evo/ding/service/DingGroupService.java new file mode 100644 index 0000000..7f236e2 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/service/DingGroupService.java @@ -0,0 +1,18 @@ +package com.evo.ding.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.evo.ding.domain.DingGroup; +import com.evo.ding.domain.DingShift; + +/** + * DingsShiftService + * + * @author andy.shi + * @ClassName:DingsShiftService + * @date: 2026年03月11日 15:55 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +public interface DingGroupService extends IService { + + public DingGroup selectByDingId(String dingId); +} diff --git a/evo-admin/src/main/java/com/evo/ding/service/DingShiftGroupService.java b/evo-admin/src/main/java/com/evo/ding/service/DingShiftGroupService.java new file mode 100644 index 0000000..6c95875 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/service/DingShiftGroupService.java @@ -0,0 +1,26 @@ +package com.evo.ding.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.evo.ding.domain.DingShift; +import com.evo.ding.domain.DingShiftGroup; + +import java.util.List; + +/** + * DingShiftGroupService + * + * @author andy.shi + * @ClassName:DingShiftGroupService + * @date: 2026年03月11日 15:48 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +public interface DingShiftGroupService extends IService { + + DingShiftGroup selectByGroupIdAndTypeAndCheckTime(String groupId, String shiftId, String type, String checkTime); + + int updateCheckTimeByShiftIdAndType(String shiftId, String type, String checkTime); + + List selectListByGroupId(String groupId); + + public List selectList(DingShiftGroup dingShiftGroup); +} diff --git a/evo-admin/src/main/java/com/evo/ding/service/DingShiftService.java b/evo-admin/src/main/java/com/evo/ding/service/DingShiftService.java new file mode 100644 index 0000000..950c4fc --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/service/DingShiftService.java @@ -0,0 +1,22 @@ +package com.evo.ding.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.evo.ding.domain.DingShift; +import com.evo.system.domain.SysStaff; + +import java.util.List; + +/** + * DingsShiftService + * + * @author andy.shi + * @ClassName:DingsShiftService + * @date: 2026年03月11日 15:55 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +public interface DingShiftService extends IService { + + public DingShift selectByDingId(String dingId); + + public List selectList(DingShift dingShift); +} diff --git a/evo-admin/src/main/java/com/evo/ding/service/impl/DingGroupServiceImpl.java b/evo-admin/src/main/java/com/evo/ding/service/impl/DingGroupServiceImpl.java new file mode 100644 index 0000000..39f6e9a --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/service/impl/DingGroupServiceImpl.java @@ -0,0 +1,26 @@ +package com.evo.ding.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.evo.ding.domain.DingGroup; +import com.evo.ding.domain.DingShift; +import com.evo.ding.mapper.DingGroupMapper; +import com.evo.ding.mapper.DingShiftMapper; +import com.evo.ding.service.DingGroupService; +import com.evo.ding.service.DingShiftService; +import org.springframework.stereotype.Service; + +/** + * DingShiftGroupServiceImpl + * + * @author andy.shi + * @ClassName:DingShiftGroupServiceImpl + * @date: 2026年03月11日 15:49 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@Service +public class DingGroupServiceImpl extends ServiceImpl implements DingGroupService { + @Override + public DingGroup selectByDingId(String dingId) { + return getBaseMapper().selectByDingId(dingId); + } +} diff --git a/evo-admin/src/main/java/com/evo/ding/service/impl/DingShiftGroupServiceImpl.java b/evo-admin/src/main/java/com/evo/ding/service/impl/DingShiftGroupServiceImpl.java new file mode 100644 index 0000000..db9f5b2 --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/service/impl/DingShiftGroupServiceImpl.java @@ -0,0 +1,41 @@ +package com.evo.ding.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.evo.ding.domain.DingShiftGroup; +import com.evo.ding.mapper.DingShiftGroupMapper; +import com.evo.ding.service.DingShiftGroupService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * DingShiftGroupServiceImpl + * + * @author andy.shi + * @ClassName:DingShiftGroupServiceImpl + * @date: 2026年03月11日 15:49 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@Service +public class DingShiftGroupServiceImpl extends ServiceImpl implements DingShiftGroupService { + @Override + public DingShiftGroup selectByGroupIdAndTypeAndCheckTime(String groupId, String shiftId, String type, String checkTime) { + return getBaseMapper().selectByGroupIdAndTypeAndCheckTime(groupId, shiftId, type, checkTime); + } + + @Override + public int updateCheckTimeByShiftIdAndType(String shiftId, String type, String checkTime) { + return getBaseMapper().updateCheckTimeByShiftIdAndType(shiftId, type, checkTime); + } + + @Override + public List selectListByGroupId(String groupId) { + return list(new LambdaQueryWrapper().eq(DingShiftGroup::getGroupId, groupId)); + } + + @Override + public List selectList(DingShiftGroup dingShiftGroup) { + return getBaseMapper().selectListByShiftId(dingShiftGroup.getShiftId()); + } +} diff --git a/evo-admin/src/main/java/com/evo/ding/service/impl/DingShiftServiceImpl.java b/evo-admin/src/main/java/com/evo/ding/service/impl/DingShiftServiceImpl.java new file mode 100644 index 0000000..8e4cabc --- /dev/null +++ b/evo-admin/src/main/java/com/evo/ding/service/impl/DingShiftServiceImpl.java @@ -0,0 +1,33 @@ +package com.evo.ding.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.evo.ding.domain.DingShift; +import com.evo.ding.domain.DingShiftGroup; +import com.evo.ding.mapper.DingShiftGroupMapper; +import com.evo.ding.mapper.DingShiftMapper; +import com.evo.ding.service.DingShiftGroupService; +import com.evo.ding.service.DingShiftService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * DingShiftGroupServiceImpl + * + * @author andy.shi + * @ClassName:DingShiftGroupServiceImpl + * @date: 2026年03月11日 15:49 + * @remark: 开发人员联系方式 1042025947@qq.com/微信同步 + */ +@Service +public class DingShiftServiceImpl extends ServiceImpl implements DingShiftService { + @Override + public DingShift selectByDingId(String dingId) { + return getBaseMapper().selectByDingId(dingId); + } + + @Override + public List selectList(DingShift dingShift) { + return getBaseMapper().selectList(dingShift); + } +} diff --git a/evo-admin/src/main/java/com/evo/finance/controller/RzSalaryDetailController.java b/evo-admin/src/main/java/com/evo/finance/controller/RzSalaryDetailController.java index ae85ef3..7a1df85 100644 --- a/evo-admin/src/main/java/com/evo/finance/controller/RzSalaryDetailController.java +++ b/evo-admin/src/main/java/com/evo/finance/controller/RzSalaryDetailController.java @@ -42,9 +42,6 @@ public class RzSalaryDetailController extends BaseController private IRzSalaryDetailService rzSalaryDetailService; @Autowired private ISysDeptService deptService; //部门 - @Resource - private SysDictDataMapper sysDictDataMapper; //数据字典 - /** * 查询工资详情列表 */ @@ -101,403 +98,6 @@ public class RzSalaryDetailController extends BaseController return toAjax(rzSalaryDetailService.deleteRzSalaryDetailById(id)); } - /** - * 导出工资详情列表 - */ - @PreAuthorize("@ss.hasPermi('finance:financeDetail:export')") - @Log(title = "工资详情", businessType = BusinessType.EXPORT) - @PostMapping("/export1") - public AjaxResult export1(RzSalaryDetail rzSalaryDetail) - { - ExcelUtilSs util = new ExcelUtilSs(SalaryVo.class); - //创建总表 - List list = new ArrayList(); - //创建各个公司的数据 - List> lists = new ArrayList<>(); - //创建各个部门sheetname集合 - List sheetNameList = new ArrayList<>(); - //汇总表表头 - String title = new SimpleDateFormat("yyyy-MM").format(rzSalaryDetail.getMonth())+"月工资汇总表"; - //获取所有的最小独立部门 - List dept_list = deptService.queryAllDeptForMin(); - //员工工资信息 - SalaryVo salaryVo = null; - //工资数据转化的保存 - List list0 =new ArrayList(); - for (SysDept sysDept : dept_list) { - sheetNameList.add(sysDept.getDeptName()); - //部门小计 - SalaryVo xj_salaryVo = new SalaryVo(); -// xj_salaryVo.setBasicSalary(new BigDecimal("0.00")); - xj_salaryVo.setName("小计:"); - //查询部门下的数据 - List pay_list = rzSalaryDetailService.selectSalaryDetailByDeptId(sysDept.getDeptId(),rzSalaryDetail.getMonth()); - for (RzSalaryDetail salaryDetail : pay_list) { - salaryVo = new SalaryVo(); -// xj_salaryVo.setBasicSalary(xj_salaryVo.getBasicSalary().add(salaryDetail.getBasicSalary())); -// if(StringUtils.isNull(xj_salaryVo.getOvertimeSalary())){ -// xj_salaryVo.setOvertimeSalary(new BigDecimal("0.00")); -// } -// xj_salaryVo.setOvertimeSalary(xj_salaryVo.getOvertimeSalary().add(salaryDetail.getOvertimeSalary())); -// if(StringUtils.isNull(xj_salaryVo.getLevelSubsidies())){ -// xj_salaryVo.setLevelSubsidies(new BigDecimal("0.00")); -// } - xj_salaryVo.setLevelSubsidies(xj_salaryVo.getLevelSubsidies().add(salaryDetail.getLevelSubsidies())); - if(StringUtils.isNull(xj_salaryVo.getContractSubsidies())){ - xj_salaryVo.setContractSubsidies(new BigDecimal("0.00")); - } - xj_salaryVo.setContractSubsidies(xj_salaryVo.getContractSubsidies().add(salaryDetail.getContractSubsidies())); - if(StringUtils.isNull(xj_salaryVo.getSenioritySalary())){ - xj_salaryVo.setSenioritySalary(new BigDecimal("0.00")); - } - xj_salaryVo.setSenioritySalary(xj_salaryVo.getSenioritySalary().add(salaryDetail.getSenioritySalary())); - if(StringUtils.isNull(xj_salaryVo.getSocialSubsidies())){ - xj_salaryVo.setSocialSubsidies(new BigDecimal("0.00")); - } -// xj_salaryVo.setSocialSubsidies(xj_salaryVo.getSocialSubsidies().add(salaryDetail.getSocialSubsidies())); -// if(StringUtils.isNull(xj_salaryVo.getFullSubsidies())){ -// xj_salaryVo.setFullSubsidies(new BigDecimal("0.00")); -// } -// xj_salaryVo.setFullSubsidies(xj_salaryVo.getFullSubsidies().add(salaryDetail.getFullSubsidies())); -// if(StringUtils.isNull(xj_salaryVo.getNightSubsidies())){ -// xj_salaryVo.setNightSubsidies(new BigDecimal("0.00")); -// } - xj_salaryVo.setNightSubsidies(xj_salaryVo.getNightSubsidies().add(salaryDetail.getNightSubsidies())); - if(StringUtils.isNull(xj_salaryVo.getDinnerSubsidies())){ - xj_salaryVo.setDinnerSubsidies(new BigDecimal("0.00")); - } - xj_salaryVo.setDinnerSubsidies(xj_salaryVo.getDinnerSubsidies().add(salaryDetail.getDinnerSubsidies())); - if(StringUtils.isNull(xj_salaryVo.getSubsidyOrBonus())){ - xj_salaryVo.setSubsidyOrBonus(new BigDecimal("0.00")); - } - xj_salaryVo.setSubsidyOrBonus(xj_salaryVo.getSubsidyOrBonus().add(salaryDetail.getSubsidyOrBonus())); - if(StringUtils.isNull(xj_salaryVo.getAbsenteeismSalary())){ - xj_salaryVo.setAbsenteeismSalary(new BigDecimal("0.00")); - } - xj_salaryVo.setAbsenteeismSalary(xj_salaryVo.getAbsenteeismSalary().add(salaryDetail.getAbsenteeismSalary())); - if(StringUtils.isNull(xj_salaryVo.getAbsenteeismSubsidies())){ - xj_salaryVo.setAbsenteeismSubsidies(new BigDecimal("0.00")); - } - xj_salaryVo.setAbsenteeismSubsidies(xj_salaryVo.getAbsenteeismSubsidies().add(salaryDetail.getAbsenteeismSubsidies())); - if(StringUtils.isNull(xj_salaryVo.getMealFee())){ - xj_salaryVo.setMealFee(new BigDecimal("0.00")); - } - xj_salaryVo.setMealFee(xj_salaryVo.getMealFee().add(salaryDetail.getMealFee())); - if(StringUtils.isNull(xj_salaryVo.getDeductions())){ - xj_salaryVo.setDeductions(new BigDecimal("0.00")); - } - xj_salaryVo.setDeductions(xj_salaryVo.getDeductions().add(salaryDetail.getDeductions())); - if(StringUtils.isNull(xj_salaryVo.getSalary())){ - xj_salaryVo.setSalary(new BigDecimal("0.00")); - } - xj_salaryVo.setSalary(xj_salaryVo.getSalary().add(salaryDetail.getSalary())); - if(StringUtils.isNull(xj_salaryVo.getPayInsurance())){ - xj_salaryVo.setPayInsurance(new BigDecimal("0.00")); - } - xj_salaryVo.setPayInsurance(xj_salaryVo.getPayInsurance().add(salaryDetail.getPayInsurance())); - if(StringUtils.isNull(xj_salaryVo.getSalaryBeforeTax())){ - xj_salaryVo.setSalaryBeforeTax(new BigDecimal("0.00")); - } - xj_salaryVo.setSalaryBeforeTax(xj_salaryVo.getSalaryBeforeTax().add(salaryDetail.getSalaryBeforeTax())); - if(StringUtils.isNull(xj_salaryVo.getTotalWages())){ - xj_salaryVo.setTotalWages(new BigDecimal("0.00")); - } - xj_salaryVo.setTotalWages(xj_salaryVo.getTotalWages().add(salaryDetail.getTotalWages())); - if(StringUtils.isNull(xj_salaryVo.getAnnualExemptionAmount())){ - xj_salaryVo.setAnnualExemptionAmount(new BigDecimal("0.00")); - } - xj_salaryVo.setAnnualExemptionAmount(xj_salaryVo.getAnnualExemptionAmount().add(salaryDetail.getAnnualExemptionAmount())); - if(StringUtils.isNull(xj_salaryVo.getSpecialDeduction())){ - xj_salaryVo.setSpecialDeduction(new BigDecimal("0.00")); - } - xj_salaryVo.setSpecialDeduction(xj_salaryVo.getSpecialDeduction().add(salaryDetail.getSpecialDeduction())); - if(StringUtils.isNull(xj_salaryVo.getSlowDownTheDeduction())){ - xj_salaryVo.setSlowDownTheDeduction(new BigDecimal("0.00")); - } - xj_salaryVo.setSlowDownTheDeduction(xj_salaryVo.getSlowDownTheDeduction().add(salaryDetail.getSlowDownTheDeduction())); - if(StringUtils.isNull(xj_salaryVo.getAggregatePersonalIncomeTax())){ - xj_salaryVo.setAggregatePersonalIncomeTax(new BigDecimal("0.00")); - } - xj_salaryVo.setAggregatePersonalIncomeTax(xj_salaryVo.getAggregatePersonalIncomeTax().add(salaryDetail.getAggregatePersonalIncomeTax())); - if(StringUtils.isNull(xj_salaryVo.getTaxPayable())){ - xj_salaryVo.setTaxPayable(new BigDecimal("0.00")); - } - xj_salaryVo.setTaxPayable(xj_salaryVo.getTaxPayable().add(salaryDetail.getTaxPayable())); - if(StringUtils.isNull(xj_salaryVo.getNetPayroll())){ - xj_salaryVo.setNetPayroll(new BigDecimal("0.00")); - } - xj_salaryVo.setNetPayroll(xj_salaryVo.getNetPayroll().add(salaryDetail.getNetPayroll())); - BeanUtils.copyProperties(salaryDetail, salaryVo); - salaryVo.setDeptName(sysDept.getDeptName()); - list0.add(salaryVo); - } - list0.add(xj_salaryVo); - lists.add(list0); - list.add(xj_salaryVo); - } - //计算伊特总计数据 - SalaryVo gj_salaryVo = new SalaryVo(); - for (SalaryVo salaryVoz : list) { -// if(StringUtils.isNull(gj_salaryVo.getBasicSalary())){ -// gj_salaryVo.setBasicSalary(new BigDecimal("0.00")); -// } -// gj_salaryVo.setBasicSalary(gj_salaryVo.getBasicSalary().add(salaryVoz.getBasicSalary())); -// if(StringUtils.isNull(gj_salaryVo.getOvertimeSalary())){ -// gj_salaryVo.setOvertimeSalary(new BigDecimal("0.00")); -// } -// gj_salaryVo.setOvertimeSalary(gj_salaryVo.getOvertimeSalary().add(DataUtils.findDefaultValue(salaryVoz.getOvertimeSalary(), DataUtils.DEFAULT_VALUE))); -// if(StringUtils.isNull(gj_salaryVo.getLevelSubsidies())){ -// gj_salaryVo.setLevelSubsidies(new BigDecimal("0.00")); -// } - gj_salaryVo.setLevelSubsidies(gj_salaryVo.getLevelSubsidies().add(DataUtils.findDefaultValue(salaryVoz.getLevelSubsidies(), DataUtils.DEFAULT_VALUE))); - if(StringUtils.isNull(gj_salaryVo.getContractSubsidies())){ - gj_salaryVo.setContractSubsidies(new BigDecimal("0.00")); - } - gj_salaryVo.setContractSubsidies(gj_salaryVo.getContractSubsidies().add(DataUtils.findDefaultValue(salaryVoz.getContractSubsidies(), DataUtils.DEFAULT_VALUE))); - if(StringUtils.isNull(gj_salaryVo.getSenioritySalary())){ - gj_salaryVo.setSenioritySalary(new BigDecimal("0.00")); - } - gj_salaryVo.setSenioritySalary(gj_salaryVo.getSenioritySalary().add(DataUtils.findDefaultValue(salaryVoz.getSenioritySalary(), DataUtils.DEFAULT_VALUE))); - if(StringUtils.isNull(gj_salaryVo.getSocialSubsidies())){ - gj_salaryVo.setSocialSubsidies(new BigDecimal("0.00")); - } -// gj_salaryVo.setSocialSubsidies(gj_salaryVo.getSocialSubsidies().add(DataUtils.findDefaultValue(salaryVoz.getSocialSubsidies(), DataUtils.DEFAULT_VALUE))); -// if(StringUtils.isNull(gj_salaryVo.getFullSubsidies())){ -// gj_salaryVo.setFullSubsidies(new BigDecimal("0.00")); -// } -// gj_salaryVo.setFullSubsidies(gj_salaryVo.getFullSubsidies().add(DataUtils.findDefaultValue(salaryVoz.getFullSubsidies(), DataUtils.DEFAULT_VALUE))); -// if(StringUtils.isNull(gj_salaryVo.getNightSubsidies())){ -// gj_salaryVo.setNightSubsidies(new BigDecimal("0.00")); -// } - gj_salaryVo.setNightSubsidies(gj_salaryVo.getNightSubsidies().add(DataUtils.findDefaultValue(salaryVoz.getNightSubsidies(), DataUtils.DEFAULT_VALUE))); - if(StringUtils.isNull(gj_salaryVo.getDinnerSubsidies())){ - gj_salaryVo.setDinnerSubsidies(new BigDecimal("0.00")); - } - gj_salaryVo.setDinnerSubsidies(gj_salaryVo.getDinnerSubsidies().add(DataUtils.findDefaultValue(salaryVoz.getDinnerSubsidies(), DataUtils.DEFAULT_VALUE))); - if(StringUtils.isNull(gj_salaryVo.getSubsidyOrBonus())){ - gj_salaryVo.setSubsidyOrBonus(new BigDecimal("0.00")); - } - gj_salaryVo.setSubsidyOrBonus(gj_salaryVo.getSubsidyOrBonus().add(DataUtils.findDefaultValue(salaryVoz.getSubsidyOrBonus(), DataUtils.DEFAULT_VALUE))); - if(StringUtils.isNull(gj_salaryVo.getAbsenteeismSalary())){ - gj_salaryVo.setAbsenteeismSalary(new BigDecimal("0.00")); - } - gj_salaryVo.setAbsenteeismSalary(gj_salaryVo.getAbsenteeismSalary().add(DataUtils.findDefaultValue(salaryVoz.getAbsenteeismSalary(), DataUtils.DEFAULT_VALUE))); - if(StringUtils.isNull(gj_salaryVo.getAbsenteeismSubsidies())){ - gj_salaryVo.setAbsenteeismSubsidies(new BigDecimal("0.00")); - } - gj_salaryVo.setAbsenteeismSubsidies(gj_salaryVo.getAbsenteeismSubsidies().add(DataUtils.findDefaultValue(salaryVoz.getAbsenteeismSubsidies(), DataUtils.DEFAULT_VALUE))); - if(StringUtils.isNull(gj_salaryVo.getMealFee())){ - gj_salaryVo.setMealFee(new BigDecimal("0.00")); - } - gj_salaryVo.setMealFee(gj_salaryVo.getMealFee().add(DataUtils.findDefaultValue(salaryVoz.getMealFee(), DataUtils.DEFAULT_VALUE))); - if(StringUtils.isNull(gj_salaryVo.getDeductions())){ - gj_salaryVo.setDeductions(new BigDecimal("0.00")); - } - gj_salaryVo.setDeductions(gj_salaryVo.getDeductions().add(DataUtils.findDefaultValue(salaryVoz.getDeductions(), DataUtils.DEFAULT_VALUE))); - if(StringUtils.isNull(gj_salaryVo.getSalary())){ - gj_salaryVo.setSalary(new BigDecimal("0.00")); - } - gj_salaryVo.setSalary(gj_salaryVo.getSalary().add(DataUtils.findDefaultValue(salaryVoz.getSalary(), DataUtils.DEFAULT_VALUE))); - if(StringUtils.isNull(gj_salaryVo.getPayInsurance())){ - gj_salaryVo.setPayInsurance(new BigDecimal("0.00")); - } - gj_salaryVo.setPayInsurance(gj_salaryVo.getPayInsurance().add(DataUtils.findDefaultValue(salaryVoz.getPayInsurance(), DataUtils.DEFAULT_VALUE))); - if(StringUtils.isNull(gj_salaryVo.getSalaryBeforeTax())){ - gj_salaryVo.setSalaryBeforeTax(new BigDecimal("0.00")); - } - gj_salaryVo.setSalaryBeforeTax(gj_salaryVo.getSalaryBeforeTax().add(DataUtils.findDefaultValue(salaryVoz.getSalaryBeforeTax(), DataUtils.DEFAULT_VALUE))); - if(StringUtils.isNull(gj_salaryVo.getTotalWages())){ - gj_salaryVo.setTotalWages(new BigDecimal("0.00")); - } - gj_salaryVo.setTotalWages(gj_salaryVo.getTotalWages().add(DataUtils.findDefaultValue(salaryVoz.getTotalWages(), DataUtils.DEFAULT_VALUE))); - if(StringUtils.isNull(gj_salaryVo.getAnnualExemptionAmount())){ - gj_salaryVo.setAnnualExemptionAmount(new BigDecimal("0.00")); - } - gj_salaryVo.setAnnualExemptionAmount(gj_salaryVo.getAnnualExemptionAmount().add(DataUtils.findDefaultValue(salaryVoz.getAnnualExemptionAmount(), DataUtils.DEFAULT_VALUE))); - if(StringUtils.isNull(gj_salaryVo.getSpecialDeduction())){ - gj_salaryVo.setSpecialDeduction(new BigDecimal("0.00")); - } - gj_salaryVo.setSpecialDeduction(gj_salaryVo.getSpecialDeduction().add(DataUtils.findDefaultValue(salaryVoz.getSpecialDeduction(), DataUtils.DEFAULT_VALUE))); - if(StringUtils.isNull(gj_salaryVo.getSlowDownTheDeduction())){ - gj_salaryVo.setSlowDownTheDeduction(new BigDecimal("0.00")); - } - gj_salaryVo.setSlowDownTheDeduction(gj_salaryVo.getSlowDownTheDeduction().add(DataUtils.findDefaultValue(salaryVoz.getSlowDownTheDeduction(), DataUtils.DEFAULT_VALUE))); - if(StringUtils.isNull(gj_salaryVo.getAggregatePersonalIncomeTax())){ - gj_salaryVo.setAggregatePersonalIncomeTax(new BigDecimal("0.00")); - } - gj_salaryVo.setAggregatePersonalIncomeTax(gj_salaryVo.getAggregatePersonalIncomeTax().add(DataUtils.findDefaultValue(salaryVoz.getAggregatePersonalIncomeTax(), DataUtils.DEFAULT_VALUE))); - if(StringUtils.isNull(gj_salaryVo.getTaxPayable())){ - gj_salaryVo.setTaxPayable(new BigDecimal("0.00")); - } - gj_salaryVo.setTaxPayable(gj_salaryVo.getTaxPayable().add(DataUtils.findDefaultValue(salaryVoz.getTaxPayable(), DataUtils.DEFAULT_VALUE))); - if(StringUtils.isNull(gj_salaryVo.getNetPayroll())){ - gj_salaryVo.setNetPayroll(new BigDecimal("0.00")); - } - gj_salaryVo.setNetPayroll(gj_salaryVo.getNetPayroll().add(DataUtils.findDefaultValue(salaryVoz.getNetPayroll(), DataUtils.DEFAULT_VALUE))); - } - gj_salaryVo.setName("伊特总计:"); - list.add(gj_salaryVo); - - //创建总表的对象 - SalaryVo payRollZong = new SalaryVo(); - payRollZong.setName("总计:"); - BeanUtils.copyProperties(gj_salaryVo, payRollZong); - //查询非伊特数据 - List cy_list = sysDictDataMapper.selectDictDataByType(Constants.SYS_COMPANY); - for (SysDictData sysDictData : cy_list) { - if(!"YT".equals(sysDictData.getDictValue())){ - sheetNameList.add(sysDictData.getDictLabel()); - //部门小计 - SalaryVo xj_salaryVo = new SalaryVo(); - xj_salaryVo.setName("小计:"); - //查询非伊特下的数据 - List f_list = rzSalaryDetailService.selectSalaryDetailByWbFlag(sysDictData.getDictValue(),rzSalaryDetail.getMonth()); - for (RzSalaryDetail salaryDetail : f_list) { - salaryVo = new SalaryVo(); -// if(StringUtils.isNull(xj_salaryVo.getBasicSalary())){ -// xj_salaryVo.setBasicSalary(new BigDecimal("0.00")); -// } -// xj_salaryVo.setBasicSalary(xj_salaryVo.getBasicSalary().add(salaryDetail.getBasicSalary())); -// if(StringUtils.isNull(xj_salaryVo.getOvertimeSalary())){ -// xj_salaryVo.setOvertimeSalary(new BigDecimal("0.00")); -// } -// xj_salaryVo.setOvertimeSalary(xj_salaryVo.getOvertimeSalary().add(salaryDetail.getOvertimeSalary())); -// if(StringUtils.isNull(xj_salaryVo.getLevelSubsidies())){ -// xj_salaryVo.setLevelSubsidies(new BigDecimal("0.00")); -// } - xj_salaryVo.setLevelSubsidies(xj_salaryVo.getLevelSubsidies().add(salaryDetail.getLevelSubsidies())); - if(StringUtils.isNull(xj_salaryVo.getContractSubsidies())){ - xj_salaryVo.setContractSubsidies(new BigDecimal("0.00")); - } - xj_salaryVo.setContractSubsidies(xj_salaryVo.getContractSubsidies().add(salaryDetail.getContractSubsidies())); - if(StringUtils.isNull(xj_salaryVo.getSenioritySalary())){ - xj_salaryVo.setSenioritySalary(new BigDecimal("0.00")); - } - xj_salaryVo.setSenioritySalary(xj_salaryVo.getSenioritySalary().add(salaryDetail.getSenioritySalary())); - if(StringUtils.isNull(xj_salaryVo.getSocialSubsidies())){ - xj_salaryVo.setSocialSubsidies(new BigDecimal("0.00")); - } -// xj_salaryVo.setSocialSubsidies(xj_salaryVo.getSocialSubsidies().add(salaryDetail.getSocialSubsidies())); -// if(StringUtils.isNull(xj_salaryVo.getFullSubsidies())){ -// xj_salaryVo.setFullSubsidies(new BigDecimal("0.00")); -// } -// xj_salaryVo.setFullSubsidies(xj_salaryVo.getFullSubsidies().add(salaryDetail.getFullSubsidies())); -// if(StringUtils.isNull(xj_salaryVo.getNightSubsidies())){ -// xj_salaryVo.setNightSubsidies(new BigDecimal("0.00")); -// } - xj_salaryVo.setNightSubsidies(xj_salaryVo.getNightSubsidies().add(salaryDetail.getNightSubsidies())); - if(StringUtils.isNull(xj_salaryVo.getDinnerSubsidies())){ - xj_salaryVo.setDinnerSubsidies(new BigDecimal("0.00")); - } - xj_salaryVo.setDinnerSubsidies(xj_salaryVo.getDinnerSubsidies().add(salaryDetail.getDinnerSubsidies())); - if(StringUtils.isNull(xj_salaryVo.getSubsidyOrBonus())){ - xj_salaryVo.setSubsidyOrBonus(new BigDecimal("0.00")); - } - xj_salaryVo.setSubsidyOrBonus(xj_salaryVo.getSubsidyOrBonus().add(salaryDetail.getSubsidyOrBonus())); - if(StringUtils.isNull(xj_salaryVo.getAbsenteeismSalary())){ - xj_salaryVo.setAbsenteeismSalary(new BigDecimal("0.00")); - } - xj_salaryVo.setAbsenteeismSalary(xj_salaryVo.getAbsenteeismSalary().add(salaryDetail.getAbsenteeismSalary())); - if(StringUtils.isNull(xj_salaryVo.getAbsenteeismSubsidies())){ - xj_salaryVo.setAbsenteeismSubsidies(new BigDecimal("0.00")); - } - xj_salaryVo.setAbsenteeismSubsidies(xj_salaryVo.getAbsenteeismSubsidies().add(salaryDetail.getAbsenteeismSubsidies())); - if(StringUtils.isNull(xj_salaryVo.getMealFee())){ - xj_salaryVo.setMealFee(new BigDecimal("0.00")); - } - xj_salaryVo.setMealFee(xj_salaryVo.getMealFee().add(salaryDetail.getMealFee())); - if(StringUtils.isNull(xj_salaryVo.getDeductions())){ - xj_salaryVo.setDeductions(new BigDecimal("0.00")); - } - xj_salaryVo.setDeductions(xj_salaryVo.getDeductions().add(salaryDetail.getDeductions())); - if(StringUtils.isNull(xj_salaryVo.getSalary())){ - xj_salaryVo.setSalary(new BigDecimal("0.00")); - } - xj_salaryVo.setSalary(xj_salaryVo.getSalary().add(salaryDetail.getSalary())); - if(StringUtils.isNull(xj_salaryVo.getPayInsurance())){ - xj_salaryVo.setPayInsurance(new BigDecimal("0.00")); - } - xj_salaryVo.setPayInsurance(xj_salaryVo.getPayInsurance().add(salaryDetail.getPayInsurance())); - if(StringUtils.isNull(xj_salaryVo.getSalaryBeforeTax())){ - xj_salaryVo.setSalaryBeforeTax(new BigDecimal("0.00")); - } - xj_salaryVo.setSalaryBeforeTax(xj_salaryVo.getSalaryBeforeTax().add(salaryDetail.getSalaryBeforeTax())); - if(StringUtils.isNull(xj_salaryVo.getTotalWages())){ - xj_salaryVo.setTotalWages(new BigDecimal("0.00")); - } - xj_salaryVo.setTotalWages(xj_salaryVo.getTotalWages().add(salaryDetail.getTotalWages())); - if(StringUtils.isNull(xj_salaryVo.getAnnualExemptionAmount())){ - xj_salaryVo.setAnnualExemptionAmount(new BigDecimal("0.00")); - } - xj_salaryVo.setAnnualExemptionAmount(xj_salaryVo.getAnnualExemptionAmount().add(salaryDetail.getAnnualExemptionAmount())); - if(StringUtils.isNull(xj_salaryVo.getSpecialDeduction())){ - xj_salaryVo.setSpecialDeduction(new BigDecimal("0.00")); - } - xj_salaryVo.setSpecialDeduction(xj_salaryVo.getSpecialDeduction().add(salaryDetail.getSpecialDeduction())); - if(StringUtils.isNull(xj_salaryVo.getSlowDownTheDeduction())){ - xj_salaryVo.setSlowDownTheDeduction(new BigDecimal("0.00")); - } - xj_salaryVo.setSlowDownTheDeduction(xj_salaryVo.getSlowDownTheDeduction().add(salaryDetail.getSlowDownTheDeduction())); - if(StringUtils.isNull(xj_salaryVo.getAggregatePersonalIncomeTax())){ - xj_salaryVo.setAggregatePersonalIncomeTax(new BigDecimal("0.00")); - } - xj_salaryVo.setAggregatePersonalIncomeTax(xj_salaryVo.getAggregatePersonalIncomeTax().add(salaryDetail.getAggregatePersonalIncomeTax())); - if(StringUtils.isNull(xj_salaryVo.getTaxPayable())){ - xj_salaryVo.setTaxPayable(new BigDecimal("0.00")); - } - xj_salaryVo.setTaxPayable(xj_salaryVo.getTaxPayable().add(salaryDetail.getTaxPayable())); - if(StringUtils.isNull(xj_salaryVo.getNetPayroll())){ - xj_salaryVo.setNetPayroll(new BigDecimal("0.00")); - } - xj_salaryVo.setNetPayroll(xj_salaryVo.getNetPayroll().add(salaryDetail.getNetPayroll())); - BeanUtils.copyProperties(salaryDetail, salaryVo); - salaryVo.setDeptName(deptService.selectDeptById(salaryDetail.getDeptId()).getDeptName()); - list0.add(salaryVo); - } - list.add(xj_salaryVo); -// payRollZong.setBasicSalary(DataUtils.findDefaultValue(xj_salaryVo.getBasicSalary(), DataUtils.DEFAULT_VALUE).add(DataUtils.findDefaultValue(payRollZong.getBasicSalary(), DataUtils.DEFAULT_VALUE))); -// payRollZong.setOvertimeSalary(DataUtils.findDefaultValue(xj_salaryVo.getOvertimeSalary(), DataUtils.DEFAULT_VALUE).add(DataUtils.findDefaultValue(payRollZong.getOvertimeSalary(), DataUtils.DEFAULT_VALUE))); - payRollZong.setLevelSubsidies(DataUtils.findDefaultValue(xj_salaryVo.getLevelSubsidies(), DataUtils.DEFAULT_VALUE).add(DataUtils.findDefaultValue(payRollZong.getLevelSubsidies(), DataUtils.DEFAULT_VALUE))); - payRollZong.setContractSubsidies(DataUtils.findDefaultValue(xj_salaryVo.getContractSubsidies(), DataUtils.DEFAULT_VALUE).add(DataUtils.findDefaultValue(payRollZong.getContractSubsidies(), DataUtils.DEFAULT_VALUE))); - payRollZong.setSenioritySalary(DataUtils.findDefaultValue(xj_salaryVo.getSenioritySalary(), DataUtils.DEFAULT_VALUE).add(DataUtils.findDefaultValue(payRollZong.getSenioritySalary(), DataUtils.DEFAULT_VALUE))); - payRollZong.setSocialSubsidies(DataUtils.findDefaultValue(xj_salaryVo.getSocialSubsidies(), DataUtils.DEFAULT_VALUE).add(DataUtils.findDefaultValue(payRollZong.getSocialSubsidies(), DataUtils.DEFAULT_VALUE))); -// payRollZong.setFullSubsidies(DataUtils.findDefaultValue(xj_salaryVo.getFullSubsidies(), DataUtils.DEFAULT_VALUE).add(DataUtils.findDefaultValue(payRollZong.getFullSubsidies(), DataUtils.DEFAULT_VALUE))); - payRollZong.setNightSubsidies(DataUtils.findDefaultValue(xj_salaryVo.getNightSubsidies(), DataUtils.DEFAULT_VALUE).add(DataUtils.findDefaultValue(payRollZong.getNightSubsidies(), DataUtils.DEFAULT_VALUE))); - payRollZong.setDinnerSubsidies(DataUtils.findDefaultValue(xj_salaryVo.getDinnerSubsidies(), DataUtils.DEFAULT_VALUE).add(DataUtils.findDefaultValue(payRollZong.getDinnerSubsidies(), DataUtils.DEFAULT_VALUE))); - payRollZong.setSubsidyOrBonus(DataUtils.findDefaultValue(xj_salaryVo.getSubsidyOrBonus(), DataUtils.DEFAULT_VALUE).add(DataUtils.findDefaultValue(payRollZong.getSubsidyOrBonus(), DataUtils.DEFAULT_VALUE))); - payRollZong.setAbsenteeismSalary(DataUtils.findDefaultValue(xj_salaryVo.getAbsenteeismSalary(), DataUtils.DEFAULT_VALUE).add(DataUtils.findDefaultValue(payRollZong.getAbsenteeismSalary(), DataUtils.DEFAULT_VALUE))); - payRollZong.setAbsenteeismSubsidies(DataUtils.findDefaultValue(xj_salaryVo.getAbsenteeismSubsidies(), DataUtils.DEFAULT_VALUE).add(DataUtils.findDefaultValue(payRollZong.getAbsenteeismSubsidies(), DataUtils.DEFAULT_VALUE))); - payRollZong.setMealFee(DataUtils.findDefaultValue(xj_salaryVo.getMealFee(), DataUtils.DEFAULT_VALUE).add(DataUtils.findDefaultValue(payRollZong.getMealFee(), DataUtils.DEFAULT_VALUE))); - payRollZong.setDeductions(DataUtils.findDefaultValue(xj_salaryVo.getDeductions(), DataUtils.DEFAULT_VALUE).add(DataUtils.findDefaultValue(payRollZong.getDeductions(), DataUtils.DEFAULT_VALUE))); - payRollZong.setSalary(DataUtils.findDefaultValue(xj_salaryVo.getSalary(), DataUtils.DEFAULT_VALUE).add(DataUtils.findDefaultValue(payRollZong.getSalary(), DataUtils.DEFAULT_VALUE))); - payRollZong.setPayInsurance(DataUtils.findDefaultValue(xj_salaryVo.getPayInsurance(), DataUtils.DEFAULT_VALUE).add(DataUtils.findDefaultValue(payRollZong.getPayInsurance(), DataUtils.DEFAULT_VALUE))); - payRollZong.setSalaryBeforeTax(DataUtils.findDefaultValue(xj_salaryVo.getSalaryBeforeTax(), DataUtils.DEFAULT_VALUE).add(DataUtils.findDefaultValue(payRollZong.getSalaryBeforeTax(), DataUtils.DEFAULT_VALUE))); - payRollZong.setTotalWages(DataUtils.findDefaultValue(xj_salaryVo.getTotalWages(), DataUtils.DEFAULT_VALUE).add(DataUtils.findDefaultValue(payRollZong.getTotalWages(), DataUtils.DEFAULT_VALUE))); - payRollZong.setAnnualExemptionAmount(DataUtils.findDefaultValue(xj_salaryVo.getAnnualExemptionAmount(), DataUtils.DEFAULT_VALUE).add(DataUtils.findDefaultValue(payRollZong.getAnnualExemptionAmount(), DataUtils.DEFAULT_VALUE))); - payRollZong.setSpecialDeduction(DataUtils.findDefaultValue(xj_salaryVo.getSpecialDeduction(), DataUtils.DEFAULT_VALUE).add(DataUtils.findDefaultValue(payRollZong.getSpecialDeduction(), DataUtils.DEFAULT_VALUE))); - payRollZong.setSlowDownTheDeduction(DataUtils.findDefaultValue(xj_salaryVo.getSlowDownTheDeduction(), DataUtils.DEFAULT_VALUE).add(DataUtils.findDefaultValue(payRollZong.getSlowDownTheDeduction(), DataUtils.DEFAULT_VALUE))); - payRollZong.setAggregatePersonalIncomeTax(DataUtils.findDefaultValue(xj_salaryVo.getAggregatePersonalIncomeTax(), DataUtils.DEFAULT_VALUE).add(DataUtils.findDefaultValue(payRollZong.getAggregatePersonalIncomeTax(), DataUtils.DEFAULT_VALUE))); - payRollZong.setTaxPayable(DataUtils.findDefaultValue(xj_salaryVo.getTaxPayable(), DataUtils.DEFAULT_VALUE).add(DataUtils.findDefaultValue(payRollZong.getTaxPayable(), DataUtils.DEFAULT_VALUE))); - payRollZong.setNetPayroll(DataUtils.findDefaultValue(xj_salaryVo.getNetPayroll(), DataUtils.DEFAULT_VALUE).add(DataUtils.findDefaultValue(payRollZong.getNetPayroll(), DataUtils.DEFAULT_VALUE))); - } - } - list.add(payRollZong); - //表尾 - String footer = "制表: "+"审核: "+"经理签字: "+"总经理签字: "; - return util.exportExcel(list,lists,"总表",sheetNameList,title,footer); - } - /** - * 导入销售提成 - */ -// @PreAuthorize("@ss.hasPermi('finance:financeDetail:importSalesCommissions')") -// @Log(title = "导入销售提成", businessType = BusinessType.IMPORT) -// @PostMapping("/importSalesCommissions") -// public AjaxResult importSalesCommissions(MultipartFile file) throws Exception -// { -// ExcelUtil util = new ExcelUtil<>(RzSalaryVo.class); -// List attendanceList = util.importExcel(file.getInputStream()); -// return success(rzSalaryDetailService.importSalesCommissions(attendanceList)); -// } /* * 导出工资详情列表 */ diff --git a/evo-admin/src/main/java/com/evo/finance/domain/RzSalaryDetail.java b/evo-admin/src/main/java/com/evo/finance/domain/RzSalaryDetail.java index b67e6c0..b5dbe63 100644 --- a/evo-admin/src/main/java/com/evo/finance/domain/RzSalaryDetail.java +++ b/evo-admin/src/main/java/com/evo/finance/domain/RzSalaryDetail.java @@ -203,10 +203,23 @@ public class RzSalaryDetail extends BaseEntity */ @TableField(exist = false) private BigDecimal kjAmount; + //基本工资全薪 + @TableField(exist = false) + private BigDecimal basicAmount; /** 删除标识 */ private String delFlag; + private Integer type; + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + public BigDecimal getSalesCommission() { return salesCommission; } @@ -635,6 +648,14 @@ public class RzSalaryDetail extends BaseEntity this.bjAmount = bjAmount; } + public BigDecimal getBasicAmount() { + return basicAmount; + } + + public void setBasicAmount(BigDecimal basicAmount) { + this.basicAmount = basicAmount; + } + public BigDecimal getSocialSecurityDeduction() { return socialSecurityDeduction; } diff --git a/evo-admin/src/main/java/com/evo/finance/mapper/RzSalaryDetailMapper.java b/evo-admin/src/main/java/com/evo/finance/mapper/RzSalaryDetailMapper.java index 06366e7..88e5fae 100644 --- a/evo-admin/src/main/java/com/evo/finance/mapper/RzSalaryDetailMapper.java +++ b/evo-admin/src/main/java/com/evo/finance/mapper/RzSalaryDetailMapper.java @@ -78,4 +78,8 @@ public interface RzSalaryDetailMapper extends BaseMapper public List selectSalaryDetailByWbFlag(@Param("wbFlag")String wbFlag,@Param("date")Date date); + /** + */ + public Date selectMaxMonthBySysStallId(Long id); + } diff --git a/evo-admin/src/main/java/com/evo/finance/processor/SalaryCalculationStrategyExchangeProcessor.java b/evo-admin/src/main/java/com/evo/finance/processor/SalaryCalculationStrategyExchangeProcessor.java index 9de07e1..acfcf89 100644 --- a/evo-admin/src/main/java/com/evo/finance/processor/SalaryCalculationStrategyExchangeProcessor.java +++ b/evo-admin/src/main/java/com/evo/finance/processor/SalaryCalculationStrategyExchangeProcessor.java @@ -111,9 +111,10 @@ public interface SalaryCalculationStrategyExchangeProcessor { rzSalaryDetail.setSalary(rzSalaryDetail.getMonthSalary().add(isMonth ? rzSalaryDetail.getOvertimeSalary() : DataUtils.DEFAULT_VALUE).add(rzSalaryDetail.getNightSubsidies()).add(rzSalaryDetail.getMiddleSubsidies()).add(rzSalaryDetail.getDinnerSubsidies()) .add(DataUtils.findDefaultValue(rzSalaryDetail.getFullSubsidies(), DataUtils.DEFAULT_VALUE)).add(rzSalaryDetail.getLevelSubsidies()).add(rzSalaryDetail.getContractSubsidies()).add(rzSalaryDetail.getSocialSubsidies()) .add(rzSalaryDetail.getSenioritySalary()).add(rzSalaryDetail.getSubsidyOrBonus()).add(rzSalaryDetail.getSalesCommission()) - .subtract(rzSalaryDetail.getAbsenteeismSubsidies()).subtract(rzSalaryDetail.getDeductions()).subtract(rzSalaryDetail.getAbsenteeismSalary()).add(DataUtils.findDefaultValue(rzSalaryDetail.getBjAmount(), DataUtils.DEFAULT_VALUE))); + .subtract(rzSalaryDetail.getAbsenteeismSubsidies()).subtract(rzSalaryDetail.getDeductions()).subtract(rzSalaryDetail.getAbsenteeismSalary()).add(DataUtils.findDefaultValue(rzSalaryDetail.getBjAmount(), DataUtils.DEFAULT_VALUE)) + .add(DataUtils.findDefaultValue(rzSalaryDetail.getBasicAmount(), DataUtils.DEFAULT_VALUE))); //.subtract(rzSalaryDetail.getMealFee()) - //如果当前人员不打卡 则需要扣减缺勤工资 + //如果当前人员不打卡 则需要扣减缺勤工资setBasicAmount // if("否".equals(sysStaff.getClockIn())){ // rzSalaryDetail.setSalary(rzSalaryDetail.getSalary()); // } diff --git a/evo-admin/src/main/java/com/evo/finance/processor/impl/MonthlySalaryStrategyExchangeProcessor.java b/evo-admin/src/main/java/com/evo/finance/processor/impl/MonthlySalaryStrategyExchangeProcessor.java index 0858e8a..2e35b2b 100644 --- a/evo-admin/src/main/java/com/evo/finance/processor/impl/MonthlySalaryStrategyExchangeProcessor.java +++ b/evo-admin/src/main/java/com/evo/finance/processor/impl/MonthlySalaryStrategyExchangeProcessor.java @@ -119,7 +119,6 @@ public class MonthlySalaryStrategyExchangeProcessor implements SalaryCalculation BigDecimal gs = rzSalaryDetail.getBasicSalary().multiply(new BigDecimal(Constants.SUBSIDY_PERIOD)).divide(new BigDecimal(ParamUtils.getMonthWorkDayNum(DateUtils.getYear(rzSalaryDetail.getMonth()), DateUtils.getMonth(rzSalaryDetail.getMonth()))),2, RoundingMode.HALF_UP).multiply(new BigDecimal(total8Hour).divide(Constants.DAY_WORK_HOUR,2,RoundingMode.HALF_UP)); // rzSalaryDetail.setMonthSalary(rzSalaryDetail.getMonthSalary().add(gs)); rzSalaryDetail.setBjAmount(gs); - } if(sysStaff.getName().equals("史国臣")){ System.out.println("11111"); @@ -154,6 +153,20 @@ public class MonthlySalaryStrategyExchangeProcessor implements SalaryCalculation } } } + //获取所有的基本薪资 + Long totalBasicHour = 0l; + for (Long type: ParamUtils.getBasicFullPaidLeave()) { + Long hour = rzLeaveDetailMapper.selectLeaveHourByUserIdAndDateAndType(sysStaff.getUserId(), rzSalaryDetail.getMonth(), type); + if(hour.compareTo(0l)> 0){ + totalBasicHour = totalBasicHour+hour; + } + } + if(totalBasicHour.compareTo(0l)> 0){ + //存在工伤假, 需要计算 + BigDecimal basicAmount = rzSalaryDetail.getBasicSalary().divide(new BigDecimal(ParamUtils.getMonthWorkDayNum(DateUtils.getYear(rzSalaryDetail.getMonth()), DateUtils.getMonth(rzSalaryDetail.getMonth()))),2, RoundingMode.HALF_UP).multiply(new BigDecimal(totalBasicHour).divide(Constants.DAY_WORK_HOUR,2,RoundingMode.HALF_UP)); + rzSalaryDetail.setBasicAmount(basicAmount); + } + // if(totalAllHour.compareTo(0l)> 0){ // //存在工伤假, 需要计算 // rzSalaryDetail.setMonthSalary(rzSalaryDetail.getMonthSalary().add(workHourPrice.multiply(new BigDecimal(totalAllHour)))); diff --git a/evo-admin/src/main/java/com/evo/finance/service/IRzSalaryDetailService.java b/evo-admin/src/main/java/com/evo/finance/service/IRzSalaryDetailService.java index 4af9520..6b7d6c4 100644 --- a/evo-admin/src/main/java/com/evo/finance/service/IRzSalaryDetailService.java +++ b/evo-admin/src/main/java/com/evo/finance/service/IRzSalaryDetailService.java @@ -6,6 +6,7 @@ import java.util.List; import com.evo.attendance.domain.vo.RzSalaryVo; import com.evo.common.core.domain.AjaxResult; import com.evo.finance.domain.RzSalaryDetail; +import com.evo.system.domain.SysStaff; import org.apache.ibatis.annotations.Param; /** @@ -69,4 +70,6 @@ public interface IRzSalaryDetailService public List selectSalaryDetailByWbFlag(String wbFlag,Date date); AjaxResult export(RzSalaryDetail rzSalaryDetail); + + void dimission(SysStaff sysStaff); } diff --git a/evo-admin/src/main/java/com/evo/finance/service/impl/RzSalaryDetailServiceImpl.java b/evo-admin/src/main/java/com/evo/finance/service/impl/RzSalaryDetailServiceImpl.java index a99e089..986ead4 100644 --- a/evo-admin/src/main/java/com/evo/finance/service/impl/RzSalaryDetailServiceImpl.java +++ b/evo-admin/src/main/java/com/evo/finance/service/impl/RzSalaryDetailServiceImpl.java @@ -142,23 +142,26 @@ public class RzSalaryDetailServiceImpl extends ServiceImpl overTimeMap = deptMapper.selectList(new LambdaQueryWrapper().eq(SysDept::getDelFlag, Constants.DELETE_FLAG_0).select(SysDept::getIsOverTime, SysDept::getDeptId)).stream().collect(Collectors.toMap(SysDept::getDeptId,d->"0".equals(d.getIsOverTime()))); List> salaryInfoMapList = Collections.emptyList(); for (SysStaff sysStaff : st_list) { - RzSalaryDetail newRzSalaryDetail = new RzSalaryDetail(); - newRzSalaryDetail.setMonth(rzSalaryDetail.getMonth()); - newRzSalaryDetail.setStaffId(sysStaff.getUserId()); //员工ID - newRzSalaryDetail.setDeptId(sysStaff.getDeptId()); //部门 - newRzSalaryDetail.setName(sysStaff.getName()); //姓名 - newRzSalaryDetail.setWbFlag(sysStaff.getCompanyName()); //公司 - newRzSalaryDetail.setDelFlag(Constants.DELETE_FLAG_0); - //查询考勤统计 - RzAttendanceStatistical attendanceStatistical = rzAttendanceStatisticalMapper.getRzAttendanceStatisticalByDateAndName(sysStaff.getUserId(), rzSalaryDetail.getMonth()); - //查询员工详情 - SysStaffDetail sysStaffDetail = sysStaffDetailMapper.selectSysStaffDetailByStaffId(sysStaff.getUserId()); - Map salaryCalculationExchangeProcessorMap = applicationContext.getBeansOfType(SalaryCalculationStrategyExchangeProcessor.class); - for (SalaryCalculationStrategyExchangeProcessor processor : salaryCalculationExchangeProcessorMap.values()) { - if (processor.accept(sysStaffDetail)) { - processor.exchangeSalaryCalculation(sysStaff, sysStaffDetail, newRzSalaryDetail, attendanceStatistical, overTimeMap, salaryInfoMapList); - } - } +//<<<<<<< HEAD +// RzSalaryDetail newRzSalaryDetail = new RzSalaryDetail(); +// newRzSalaryDetail.setMonth(rzSalaryDetail.getMonth()); +// newRzSalaryDetail.setStaffId(sysStaff.getUserId()); //员工ID +// newRzSalaryDetail.setDeptId(sysStaff.getDeptId()); //部门 +// newRzSalaryDetail.setName(sysStaff.getName()); //姓名 +// newRzSalaryDetail.setWbFlag(sysStaff.getCompanyName()); //公司 +// newRzSalaryDetail.setDelFlag(Constants.DELETE_FLAG_0); +// //查询考勤统计 +// RzAttendanceStatistical attendanceStatistical = rzAttendanceStatisticalMapper.getRzAttendanceStatisticalByDateAndName(sysStaff.getUserId(), rzSalaryDetail.getMonth()); +// //查询员工详情 +// SysStaffDetail sysStaffDetail = sysStaffDetailMapper.selectSysStaffDetailByStaffId(sysStaff.getUserId()); +// Map salaryCalculationExchangeProcessorMap = applicationContext.getBeansOfType(SalaryCalculationStrategyExchangeProcessor.class); +// for (SalaryCalculationStrategyExchangeProcessor processor : salaryCalculationExchangeProcessorMap.values()) { +// if (processor.accept(sysStaffDetail)) { +// processor.exchangeSalaryCalculation(sysStaff, sysStaffDetail, newRzSalaryDetail, attendanceStatistical, overTimeMap, salaryInfoMapList); +// } +// } +//======= + calculation(sysStaff, rzSalaryDetail.getMonth(), overTimeMap, 1, salaryInfoMapList); } rzSalaryStatistics.setSalaryInfo(JSON.toJSONString(salaryInfoMapList)); rzSalaryStatisticsMapper.updateById(rzSalaryStatistics); @@ -168,6 +171,45 @@ public class RzSalaryDetailServiceImpl extends ServiceImpl overTimeMap = deptMapper.selectList(new LambdaQueryWrapper().eq(SysDept::getDelFlag, Constants.DELETE_FLAG_0).select(SysDept::getIsOverTime, SysDept::getDeptId)).stream().collect(Collectors.toMap(SysDept::getDeptId,d->"0".equals(d.getIsOverTime()))); + Date date = getBaseMapper().selectMaxMonthBySysStallId(sysStaff.getUserId()); + //如果为空, 入职时间-1个月 作为起始时间 + if(date != null){ + date = DateUtils.addMonths(date, 1); + }else{ + date = sysStaff.getEmploymentDate(); + } + List> salaryInfoMapList = Collections.emptyList(); + //进行离职工资计算操作 + while (date.compareTo(sysStaff.getQuitDate()) < 1){ + calculation(sysStaff, date, overTimeMap ,2, salaryInfoMapList); + date = DateUtils.addMonths(date, 1); + } + } + + public void calculation(SysStaff sysStaff, Date date, Map overTimeMap, Integer type,List> salaryInfoMapList){ + RzSalaryDetail newRzSalaryDetail = new RzSalaryDetail(); + newRzSalaryDetail.setMonth(date); + newRzSalaryDetail.setStaffId(sysStaff.getUserId()); //员工ID + newRzSalaryDetail.setDeptId(sysStaff.getDeptId()); //部门 + newRzSalaryDetail.setName(sysStaff.getName()); //姓名 + newRzSalaryDetail.setWbFlag(sysStaff.getCompanyName()); //公司 + newRzSalaryDetail.setDelFlag(Constants.DELETE_FLAG_0); + newRzSalaryDetail.setType(type); + //查询考勤统计 + RzAttendanceStatistical attendanceStatistical = rzAttendanceStatisticalMapper.getRzAttendanceStatisticalByDateAndName(sysStaff.getUserId(), date); + //查询员工详情 + SysStaffDetail sysStaffDetail = sysStaffDetailMapper.selectSysStaffDetailByStaffId(sysStaff.getUserId()); + + Map salaryCalculationExchangeProcessorMap = applicationContext.getBeansOfType(SalaryCalculationStrategyExchangeProcessor.class); + for (SalaryCalculationStrategyExchangeProcessor processor : salaryCalculationExchangeProcessorMap.values()) { + if (processor.accept(sysStaffDetail)) { + processor.exchangeSalaryCalculation(sysStaff, sysStaffDetail, newRzSalaryDetail, attendanceStatistical, overTimeMap, salaryInfoMapList); + } + } + } /** diff --git a/evo-admin/src/main/java/com/evo/framework/config/SecurityConfig.java b/evo-admin/src/main/java/com/evo/framework/config/SecurityConfig.java index 254268a..8271636 100644 --- a/evo-admin/src/main/java/com/evo/framework/config/SecurityConfig.java +++ b/evo-admin/src/main/java/com/evo/framework/config/SecurityConfig.java @@ -119,6 +119,8 @@ public class SecurityConfig .antMatchers("/wechat/**").permitAll() .antMatchers("/websocket/**").permitAll() .antMatchers("/test/**").permitAll() + .antMatchers("/system/staff/tree/getDingUserId").permitAll() + .antMatchers("/callback/**/**").permitAll() .antMatchers("/api/v1/verify_user").permitAll() .antMatchers("/api/v1/record/face").permitAll() .antMatchers("/api/v2/verify_user_yt").permitAll() diff --git a/evo-admin/src/main/java/com/evo/personnelMatters/domain/RzLeaveDetail.java b/evo-admin/src/main/java/com/evo/personnelMatters/domain/RzLeaveDetail.java index 5d8371a..e2b6592 100644 --- a/evo-admin/src/main/java/com/evo/personnelMatters/domain/RzLeaveDetail.java +++ b/evo-admin/src/main/java/com/evo/personnelMatters/domain/RzLeaveDetail.java @@ -49,7 +49,8 @@ public class RzLeaveDetail extends BaseEntity private String remarks; private String delFlag; - + //钉钉审批id + private String processInstanceId; /*** * 扩展字段 */ diff --git a/evo-admin/src/main/java/com/evo/personnelMatters/domain/RzOverTime.java b/evo-admin/src/main/java/com/evo/personnelMatters/domain/RzOverTime.java index 49c8eca..7a15037 100644 --- a/evo-admin/src/main/java/com/evo/personnelMatters/domain/RzOverTime.java +++ b/evo-admin/src/main/java/com/evo/personnelMatters/domain/RzOverTime.java @@ -29,6 +29,7 @@ public class RzOverTime extends BaseEntity /** 部门ID */ private Long deptId; @Excel(name = "部门") + @TableField(exist = false) private String deptName; private Long userId; @@ -46,6 +47,7 @@ public class RzOverTime extends BaseEntity @Excel(name = "加班总时长") private BigDecimal overHours; @Excel(name = "调休总时长") + @TableField(exist = false) private BigDecimal taskHours; /** 删除标识 */ diff --git a/evo-admin/src/main/java/com/evo/personnelMatters/mapper/RzLeaveDetailMapper.java b/evo-admin/src/main/java/com/evo/personnelMatters/mapper/RzLeaveDetailMapper.java index 776f227..ab75898 100644 --- a/evo-admin/src/main/java/com/evo/personnelMatters/mapper/RzLeaveDetailMapper.java +++ b/evo-admin/src/main/java/com/evo/personnelMatters/mapper/RzLeaveDetailMapper.java @@ -1,6 +1,7 @@ package com.evo.personnelMatters.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.evo.personnelMatters.domain.RzLeave; import com.evo.personnelMatters.domain.RzLeaveDetail; import org.apache.ibatis.annotations.Param; @@ -84,4 +85,5 @@ public interface RzLeaveDetailMapper extends BaseMapper */ Long selectLeaveHourByUserIdAndDateAndType(@Param("userId") Long userId,@Param("date") Date date, @Param("type") Long type); + RzLeaveDetail selectRzLeaveDetailByProcessInstanceId(@Param("processInstanceId") String processInstanceId); } diff --git a/evo-admin/src/main/java/com/evo/personnelMatters/mapper/RzLeaveMapper.java b/evo-admin/src/main/java/com/evo/personnelMatters/mapper/RzLeaveMapper.java index ec4bbc4..6eec94d 100644 --- a/evo-admin/src/main/java/com/evo/personnelMatters/mapper/RzLeaveMapper.java +++ b/evo-admin/src/main/java/com/evo/personnelMatters/mapper/RzLeaveMapper.java @@ -51,4 +51,10 @@ public interface RzLeaveMapper extends BaseMapper * @return */ public RzLeave queryRzLeaveByDateAndUserId(@Param("userId") Long userId, @Param("date") Date date); + + /** + * 根据员工ID和时间查询请假统计 + * @return + */ + public RzLeave queryRzLeaveByUserId(@Param("userId") Long userId); } diff --git a/evo-admin/src/main/java/com/evo/personnelMatters/service/IRzLeaveDetailService.java b/evo-admin/src/main/java/com/evo/personnelMatters/service/IRzLeaveDetailService.java index 4a4aa02..74d7a01 100644 --- a/evo-admin/src/main/java/com/evo/personnelMatters/service/IRzLeaveDetailService.java +++ b/evo-admin/src/main/java/com/evo/personnelMatters/service/IRzLeaveDetailService.java @@ -1,6 +1,7 @@ package com.evo.personnelMatters.service; import com.evo.common.core.domain.AjaxResult; +import com.evo.personnelMatters.domain.RzLeave; import com.evo.personnelMatters.domain.RzLeaveDetail; import java.util.List; @@ -52,4 +53,6 @@ public interface IRzLeaveDetailService public AjaxResult deleteRzLeaveDetailById(Long id); public RzLeaveDetail calculationLeaveHour(RzLeaveDetail rzLeaveDetail); + + public RzLeaveDetail selectRzLeaveDetailByProcessInstanceId(String processInstanceId); } diff --git a/evo-admin/src/main/java/com/evo/personnelMatters/service/IRzLeaveService.java b/evo-admin/src/main/java/com/evo/personnelMatters/service/IRzLeaveService.java index ba69bc1..7cce1ea 100644 --- a/evo-admin/src/main/java/com/evo/personnelMatters/service/IRzLeaveService.java +++ b/evo-admin/src/main/java/com/evo/personnelMatters/service/IRzLeaveService.java @@ -59,4 +59,12 @@ public interface IRzLeaveService public List listLeaveDetails(RzLeave rzLeave); List selectRzLeaveListByDate(RzLeave rzLeave); + + /** + * 根据员工 + * + * @param userId 员工id + * @return 请假管理 + */ + public RzLeave selectRzLeaveByUserId(Long userId); } diff --git a/evo-admin/src/main/java/com/evo/personnelMatters/service/IRzOverTimeDetailService.java b/evo-admin/src/main/java/com/evo/personnelMatters/service/IRzOverTimeDetailService.java index f28c8e3..3852f15 100644 --- a/evo-admin/src/main/java/com/evo/personnelMatters/service/IRzOverTimeDetailService.java +++ b/evo-admin/src/main/java/com/evo/personnelMatters/service/IRzOverTimeDetailService.java @@ -1,5 +1,6 @@ package com.evo.personnelMatters.service; +import com.baomidou.mybatisplus.extension.service.IService; import com.evo.common.core.domain.AjaxResult; import com.evo.personnelMatters.domain.RzOverTimeDetail; @@ -11,7 +12,7 @@ import java.util.List; * @author chenyj * @date 2024-09-09 */ -public interface IRzOverTimeDetailService +public interface IRzOverTimeDetailService extends IService { /** * 查询加班详情 diff --git a/evo-admin/src/main/java/com/evo/personnelMatters/service/IRzOverTimeService.java b/evo-admin/src/main/java/com/evo/personnelMatters/service/IRzOverTimeService.java index fee067e..aa71bb2 100644 --- a/evo-admin/src/main/java/com/evo/personnelMatters/service/IRzOverTimeService.java +++ b/evo-admin/src/main/java/com/evo/personnelMatters/service/IRzOverTimeService.java @@ -1,9 +1,13 @@ package com.evo.personnelMatters.service; +import com.baomidou.mybatisplus.extension.service.IService; import com.evo.common.core.domain.AjaxResult; import com.evo.personnelMatters.domain.RzOverTime; import com.evo.personnelMatters.domain.RzOverTimeDetail; +import com.evo.system.domain.SysStaff; +import org.apache.ibatis.annotations.Param; +import java.util.Date; import java.util.List; /** @@ -12,7 +16,7 @@ import java.util.List; * @author chenyj * @date 2024-09-03 */ -public interface IRzOverTimeService +public interface IRzOverTimeService extends IService { /** * 查询加班管理 @@ -60,4 +64,10 @@ public interface IRzOverTimeService * @return */ public List selectRzOverTimeDetailListByUserIdAndMonth(RzOverTime rzOverTime); + + public RzOverTime selectRzOverTimeByNameAndMonth(Long userId, Date overTimeMonth); + + public String overTimeCard(SysStaff sysStaff, Date overTimeMonth); + + public String overTimeOffDutyCard(SysStaff sysStaff , Date date, String sn); } diff --git a/evo-admin/src/main/java/com/evo/personnelMatters/service/impl/RzLeaveDetailServiceImpl.java b/evo-admin/src/main/java/com/evo/personnelMatters/service/impl/RzLeaveDetailServiceImpl.java index e57cf8d..c9ac9b3 100644 --- a/evo-admin/src/main/java/com/evo/personnelMatters/service/impl/RzLeaveDetailServiceImpl.java +++ b/evo-admin/src/main/java/com/evo/personnelMatters/service/impl/RzLeaveDetailServiceImpl.java @@ -89,11 +89,11 @@ public class RzLeaveDetailServiceImpl extends ServiceImpl implements IRzLeaveService { @Resource private RzLeaveMapper rzLeaveMapper; @@ -160,4 +161,9 @@ public class RzLeaveServiceImpl implements IRzLeaveService wa.like(StringUtils.isNotBlank(rzLeave.getDeptName()),RzLeave::getDeptName,rzLeave.getDeptName()); return rzLeaveMapper.selectList(wa); } + + @Override + public RzLeave selectRzLeaveByUserId(Long userId) { + return getBaseMapper().queryRzLeaveByUserId(userId); + } } diff --git a/evo-admin/src/main/java/com/evo/personnelMatters/service/impl/RzOverTimeDetailServiceImpl.java b/evo-admin/src/main/java/com/evo/personnelMatters/service/impl/RzOverTimeDetailServiceImpl.java index 93f9dfa..f0f9c07 100644 --- a/evo-admin/src/main/java/com/evo/personnelMatters/service/impl/RzOverTimeDetailServiceImpl.java +++ b/evo-admin/src/main/java/com/evo/personnelMatters/service/impl/RzOverTimeDetailServiceImpl.java @@ -1,5 +1,6 @@ package com.evo.personnelMatters.service.impl; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.evo.attendance.domain.RzAttendance; import com.evo.attendance.domain.RzAttendanceDetail; import com.evo.attendance.mapper.RzAttendanceDetailMapper; @@ -34,7 +35,7 @@ import java.util.List; * @date 2024-09-09 */ @Service -public class RzOverTimeDetailServiceImpl implements IRzOverTimeDetailService +public class RzOverTimeDetailServiceImpl extends ServiceImpl implements IRzOverTimeDetailService { @Resource private RzOverTimeDetailMapper rzOverTimeDetailMapper; diff --git a/evo-admin/src/main/java/com/evo/personnelMatters/service/impl/RzOverTimeServiceImpl.java b/evo-admin/src/main/java/com/evo/personnelMatters/service/impl/RzOverTimeServiceImpl.java index 7c0d477..bab685e 100644 --- a/evo-admin/src/main/java/com/evo/personnelMatters/service/impl/RzOverTimeServiceImpl.java +++ b/evo-admin/src/main/java/com/evo/personnelMatters/service/impl/RzOverTimeServiceImpl.java @@ -1,9 +1,12 @@ package com.evo.personnelMatters.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.evo.attendance.processor.KqUtils; +import com.evo.attendance.processor.PunchTheClockStrategyExchangeProcessor; import com.evo.common.annotation.DataScope; import com.evo.common.constant.Constants; import com.evo.common.core.domain.AjaxResult; +import com.evo.common.utils.DataUtils; import com.evo.common.utils.DateUtils; import com.evo.common.utils.SecurityUtils; import com.evo.common.utils.StringUtils; @@ -15,10 +18,12 @@ import com.evo.personnelMatters.service.IRzOverTimeService; import com.evo.system.domain.SysStaff; import com.evo.system.mapper.SysDeptMapper; import com.evo.system.mapper.SysStaffMapper; +import org.apache.commons.lang3.ObjectUtils; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.math.BigDecimal; import java.util.ArrayList; +import java.util.Date; import java.util.List; /** @@ -151,5 +156,77 @@ public class RzOverTimeServiceImpl extends ServiceImpl list = dingShiftService.selectList(dingShift); + return getDataTable(list); + } + + /** + * 查询考勤组信息 + */ + @GetMapping("/group/list") + public TableDataInfo list(DingShiftGroup dingShiftGroup){ + startPage(); + List list = dingShiftGroupService.selectList(dingShiftGroup); + return getDataTable(list); + } + +} diff --git a/evo-admin/src/main/java/com/evo/system/controller/SysStaffController.java b/evo-admin/src/main/java/com/evo/system/controller/SysStaffController.java index 0abac71..4d58e11 100644 --- a/evo-admin/src/main/java/com/evo/system/controller/SysStaffController.java +++ b/evo-admin/src/main/java/com/evo/system/controller/SysStaffController.java @@ -11,6 +11,7 @@ import com.evo.common.utils.poi.ExcelUtil; import com.evo.system.domain.SysStaff; import com.evo.system.domain.vo.SysStaffVo; import com.evo.system.service.ISysStaffService; +import org.apache.ibatis.annotations.Param; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @@ -184,4 +185,12 @@ public class SysStaffController extends BaseController { return sysStaffService.reEmployment(userId); } + +// @Log(title = "员工管理-离职员工重新入职", businessType = BusinessType.OTHER) + @GetMapping("/tree/getDingUserId") + public AjaxResult getDingUserId(@RequestParam("userName") String userName) throws Exception + { + return sysStaffService.getDingUserId(userName); + } + } diff --git a/evo-admin/src/main/java/com/evo/system/domain/SysStaff.java b/evo-admin/src/main/java/com/evo/system/domain/SysStaff.java index edb0339..07ce0b6 100644 --- a/evo-admin/src/main/java/com/evo/system/domain/SysStaff.java +++ b/evo-admin/src/main/java/com/evo/system/domain/SysStaff.java @@ -215,6 +215,10 @@ public class SysStaff extends BaseEntity private String extended; + private String dingUserId; + //数据来源 1 平台, 2 钉钉 + private String source; + public List getSubsidyList() { if(Collections.isEmpty(subsidyList) && StringUtils.isNotEmpty(subsidys)){ subsidyList = Collections.asList(subsidys.split(",")).stream().map(Long::valueOf).collect(Collectors.toList()); diff --git a/evo-admin/src/main/java/com/evo/system/mapper/SysDeptMapper.java b/evo-admin/src/main/java/com/evo/system/mapper/SysDeptMapper.java index 9826fc8..a5784fb 100644 --- a/evo-admin/src/main/java/com/evo/system/mapper/SysDeptMapper.java +++ b/evo-admin/src/main/java/com/evo/system/mapper/SysDeptMapper.java @@ -129,4 +129,9 @@ public interface SysDeptMapper extends BaseMapper * @return 结果 */ public int updateDeptForLeader(SysDept dept); + + + public SysDept selectByDingDeptId(String dingId); + + public SysDept selectByName(String name); } diff --git a/evo-admin/src/main/java/com/evo/system/mapper/SysStaffMapper.java b/evo-admin/src/main/java/com/evo/system/mapper/SysStaffMapper.java index f3d49cb..16e7c71 100644 --- a/evo-admin/src/main/java/com/evo/system/mapper/SysStaffMapper.java +++ b/evo-admin/src/main/java/com/evo/system/mapper/SysStaffMapper.java @@ -94,4 +94,14 @@ s * @return */ SysStaff selectLeaderSysStaffByDeptId(Long deptId); + /** + * 查询员工管理 + * + * @param dingUserId 员工管理主键 + * @return 员工管理 + */ + public SysStaff selectSysStaffByDingUserId(String dingUserId); + + SysStaff getDingUserId(@Param("userName") String userName); + } diff --git a/evo-admin/src/main/java/com/evo/system/service/ISysDictDataService.java b/evo-admin/src/main/java/com/evo/system/service/ISysDictDataService.java index 68c0211..0de081f 100644 --- a/evo-admin/src/main/java/com/evo/system/service/ISysDictDataService.java +++ b/evo-admin/src/main/java/com/evo/system/service/ISysDictDataService.java @@ -8,8 +8,7 @@ import com.evo.common.core.domain.entity.SysDictData; * * @author evo */ -public interface ISysDictDataService -{ +public interface ISysDictDataService { /** * 根据条件分页查询字典数据 * @@ -66,4 +65,11 @@ public interface ISysDictDataService * @return 结果 */ public int updateDictData(SysDictData dictData); + + /** + * 根据条件分页查询字典数据 + * + * @return 字典数据集合信息 + */ + public List selectDictDataListByType(String type); } diff --git a/evo-admin/src/main/java/com/evo/system/service/ISysStaffService.java b/evo-admin/src/main/java/com/evo/system/service/ISysStaffService.java index 3884ae2..d6a1b0d 100644 --- a/evo-admin/src/main/java/com/evo/system/service/ISysStaffService.java +++ b/evo-admin/src/main/java/com/evo/system/service/ISysStaffService.java @@ -39,6 +39,13 @@ public interface ISysStaffService extends IService * @return 结果 */ public AjaxResult insertSysStaff(SysStaff sysStaff); + /** + * 新增员工管理 + * + * @param result 员工管理 + * @return 结果 + */ + public void insertSysStaffByDingDing(String dingUserInfo); /** * 修改员工管理 * @@ -108,13 +115,26 @@ public interface ISysStaffService extends IService * @param userId 重新入职员工Id */ AjaxResult reEmployment(Long userId); - - - /*** * 数据导出 * @param response * @param sysStaff */ void exportInfo(HttpServletResponse response, SysStaff sysStaff); + + /** + * 根据钉钉id 查询员工信息 + * + * @param dingUserId 钉钉userId + * @return 员工管理 + */ + public SysStaff selectSysStaffByDingUserId(String dingUserId); + + /*** + * 根据钉钉的用户id做用户离职 + * @param dingUserId + */ + public void sysStaffLeaveByDingUserId(String dingUserId); + + AjaxResult getDingUserId(String userName); } diff --git a/evo-admin/src/main/java/com/evo/system/service/impl/SysDictDataServiceImpl.java b/evo-admin/src/main/java/com/evo/system/service/impl/SysDictDataServiceImpl.java index b1368dd..71479d5 100644 --- a/evo-admin/src/main/java/com/evo/system/service/impl/SysDictDataServiceImpl.java +++ b/evo-admin/src/main/java/com/evo/system/service/impl/SysDictDataServiceImpl.java @@ -117,4 +117,9 @@ public class SysDictDataServiceImpl extends ServiceImpl selectDictDataListByType(String type) { + return getBaseMapper().selectDictDataByType(type); + } } diff --git a/evo-admin/src/main/java/com/evo/system/service/impl/SysStaffServiceImpl.java b/evo-admin/src/main/java/com/evo/system/service/impl/SysStaffServiceImpl.java index f7b6c26..02e0929 100644 --- a/evo-admin/src/main/java/com/evo/system/service/impl/SysStaffServiceImpl.java +++ b/evo-admin/src/main/java/com/evo/system/service/impl/SysStaffServiceImpl.java @@ -3,9 +3,12 @@ package com.evo.system.service.impl; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.evo.attendance.domain.RzAttendanceStatistical; import com.evo.attendance.domain.vo.RzSalaryVo; import com.evo.attendance.service.IRzAttendanceStatisticalService; import com.evo.common.annotation.DataScope; @@ -18,7 +21,11 @@ import com.evo.common.utils.*; import com.evo.common.utils.Collections; import com.evo.common.utils.bean.BeanUtils; import com.evo.common.utils.poi.ExcelUtil1; +import com.evo.ding.DingUtils; import com.evo.equipment.service.IEqSnDetailService; +import com.evo.finance.domain.RzSalaryDetail; +import com.evo.finance.processor.SalaryCalculationStrategyExchangeProcessor; +import com.evo.finance.service.IRzSalaryDetailService; import com.evo.kingdeeUtils.KingdeeRequestUtils; import com.evo.kingdeeUtils.kenum.KingdeeParamsEnum; import com.evo.personnelMatters.domain.RzSubsidyInfo; @@ -34,6 +41,7 @@ import com.evo.system.mapper.SysStaffMapper; import com.evo.system.service.ISysStaffService; import com.evo.system.service.RzUploadService; import com.evo.system.utils.SubsidyCalculationUtils; +import com.fasterxml.jackson.annotation.JsonFormat; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; @@ -80,6 +88,8 @@ public class SysStaffServiceImpl extends ServiceImpl i private IEqSnDetailService eqSnDetailService;//设备信息 @Resource private RzSubsidyInfoMapper rzSubsidyInfoMapper; + @Resource + IRzSalaryDetailService rzSalaryDetailService; /** * 查询员工管理 * @@ -148,7 +158,7 @@ public class SysStaffServiceImpl extends ServiceImpl i sysStaff.setCreateTime(DateUtils.getNowDate()); sysStaff.setCreateBy(SecurityUtils.getUsername()); sysStaff.setDelFlag(Constants.DELETE_FLAG_0); - + sysStaff.setSource(Constants.SOURCE_PT); if(CollectionUtils.isNotEmpty(sysStaff.getSubsidyList())){ sysStaff.setSubsidys(sysStaff.getSubsidyList().stream().map(String::valueOf).collect(Collectors.joining(","))); } @@ -179,6 +189,78 @@ public class SysStaffServiceImpl extends ServiceImpl i return AjaxResult.success(); } + @Override + public void insertSysStaffByDingDing(String dingUserInfo) { + + JSONObject dingResult = JSONObject.parseObject(dingUserInfo); + JSONObject result = dingResult.getJSONObject("result"); + String mobile = result.getString("mobile"); + String name = result.getString("name"); + //钉钉推送, 只能通过名称+手机号核查是否存在. 如果录入过, 改为重新入职 + SysStaff sysStaff = getOne(new LambdaQueryWrapper().eq(SysStaff::getPhone, mobile).eq(SysStaff::getName,name), false); + if(sysStaff != null){ + //如果用户不为空, 并且状态为离职 + if(sysStaff.getStatus().equals("-1")){ + //重新做员工入职 + if(StringUtils.isEmpty(sysStaff.getDingUserId())){ + sysStaff.setDingUserId(result.getString("userid")); + getBaseMapper().updateById(sysStaff); + } + //做员工重新入职 + reEmployment(sysStaff.getUserId()); + } + //不为空, 还不是离职. 不做处理, 当前员工已经存在 + log.info("当前员工信息已经存在, 无法再次入库, 钉钉返回员工信息为{}", dingUserInfo); + return; + } + //解析部门信息 + JSONArray deptIds = result.getJSONArray("leader_in_dept"); + Long deptId = 1l; + if(deptIds.size() > 0){ + String dingDeptId= deptIds.getJSONObject(0).getString("dept_id"); + String deptIdAncestors = findDeptId(dingDeptId); + deptId = Long.valueOf(deptIdAncestors.split("_")[0]); + } + + + //创建新的用户 + sysStaff = new SysStaff(); + sysStaff.setName(name); + sysStaff.setPhone(mobile); + sysStaff.setDingUserId(dingResult.getString("userid")); + sysStaff.setDeptId(deptId); + + //员工编码 + sysStaff.setCode(getCodeByCompanyName()); + sysStaff.setEmploymentDate(new Date()); + sysStaff.setWorkerTerm(1l); + sysStaff.setSeniority(0l); + sysStaff.setCompanyName("YT"); + sysStaff.setIsLeader("否"); + sysStaff.setSex("0"); + sysStaff.setLevel("10"); + sysStaff.setRegularDate(DateUtils.addMonths(sysStaff.getEmploymentDate(),1)); + sysStaff.setContractStart(sysStaff.getEmploymentDate()); + sysStaff.setContractEnd(DateUtils.addYears(sysStaff.getEmploymentDate(), 1)); + sysStaff.setDingUserId(result.getString("userid")); + sysStaff.setStatus(Constants.JOB_STATIS_0); + sysStaff.setCreateTime(DateUtils.getNowDate()); + sysStaff.setCreateBy("admin-钉钉推送"); + sysStaff.setDelFlag(Constants.DELETE_FLAG_0); + sysStaff.setSource(Constants.SOURCE_DING); + + int i = getBaseMapper().insertSysStaff(sysStaff); + if(i < 1){ + log.error("员工添加失败, 钉钉数据:{}",dingUserInfo); + return; + } + //员工详情 + createStaffDetail(sysStaff); + //打卡统计,打卡详情 + rzAttendanceStatisticalService.createRzAttendance(sysStaff, Collections.emptyList(), null); + //处理餐饮信息 + rzRestaurantStatisticsService.createRestaurantStatistics(sysStaff, DateUtils.getNowDate()); + } private void initCheckDevice(SysStaff sysStaff){ //如果文件Id不为空, 则需要更新打卡设备信息, 完成后, 同步更新图片的业务Id数据 @@ -209,6 +291,41 @@ public class SysStaffServiceImpl extends ServiceImpl i } } + public String findDeptId(String dingDeptId){ + SysDept dept = deptMapper.selectByDingDeptId(dingDeptId); + if(dept == null){ + String deptResult = DingUtils.getDeptInfo(Long.valueOf(dingDeptId)); + JSONObject deptObject = JSONObject.parseObject(deptResult).getJSONObject("result"); + String deptName = deptObject.getString("name"); + dept = deptMapper.selectByName(deptName); + dept.setDingId(dingDeptId); + deptMapper.updateById(dept); + if(dept != null){ + return dept.getDeptId()+"_"+dept.getAncestors(); + }else{ + Long parentId = deptObject.getLong("parent_id"); + String parentIdStr = "1_"; + if(parentId != 1){ + parentIdStr = findDeptId(String.valueOf(parentId)); + } + String[] idArrays = parentIdStr.split("_"); + dept = new SysDept(); + dept.setParentId(Long.valueOf(idArrays[0])); + dept.setAncestors(idArrays[1]+","+idArrays[0]); + dept.setDeptName(deptName); + dept.setStatus("0"); + dept.setDelFlag("0"); + dept.setIsOverTime("0"); + dept.setDingId(dingDeptId); + deptMapper.insert(dept); + return dept.getDeptId()+"_"+dept.getAncestors(); + } + }else { + return dept.getDeptId()+"_"+dept.getAncestors(); + } + } + + /** * 创建员工详情信息 * @param sysStaff @@ -237,6 +354,13 @@ public class SysStaffServiceImpl extends ServiceImpl i public AjaxResult updateSysStaff(SysStaff sysStaff) { + if(StringUtils.isNotEmpty(sysStaff.getSource()) && sysStaff.getSource().equals(Constants.SOURCE_DING) && StringUtils.isEmpty(sysStaff.getSex())){ + //根据省份证确定性别和年龄 + sysStaff.setAge(Long.parseLong(new SimpleDateFormat("yyyy").format(new Date())) - Long.parseLong(sysStaff.getIdCard().substring(6,10))); + //性别 + sysStaff.setSex((Integer.parseInt(sysStaff.getIdCard().substring(16,17)) % 2 == 0) ? "1" : "0"); + } + if(CollectionUtils.isNotEmpty(sysStaff.getSubsidyList())){ sysStaff.setSubsidys(sysStaff.getSubsidyList().stream().map(String::valueOf).collect(Collectors.joining(","))); } @@ -249,6 +373,8 @@ public class SysStaffServiceImpl extends ServiceImpl i if(StringUtils.isNotNull(sysStaff.getQuitDate())){ //离职时间小于当前,说明离职了 if(sysStaff.getQuitDate().getTime() < DateUtils.getNowDate().getTime()){ + //记录原始状态 + String oldStatus = sysStaff.getStatus(); sysStaff.setStatus("-1"); int i = getBaseMapper().updateSysStaff(sysStaff); if(i < 1){ @@ -258,6 +384,11 @@ public class SysStaffServiceImpl extends ServiceImpl i if(StringUtils.isNotEmpty(sysStaff.getCode())){ KingdeeRequestUtils.employeeDisabled(Collections.asMap("userCode","\""+sysStaff.getCode()+"\"")); } + + //如果走离职, 需要实时计算出工资 + //还原原始状态, 用于计算离职工资 + sysStaff.setStatus(oldStatus); + rzSalaryDetailService.dimission(sysStaff); return AjaxResult.success(); } } @@ -357,6 +488,32 @@ public class SysStaffServiceImpl extends ServiceImpl i // } return AjaxResult.success(); } + +// /*** +// * 员工离职计算 +// * @param sysStaff +// */ +// void dimission(SysStaff sysStaff){ +// +// RzSalaryDetail newRzSalaryDetail = new RzSalaryDetail(); +// newRzSalaryDetail.setMonth(rzSalaryDetail.getMonth()); +// newRzSalaryDetail.setStaffId(sysStaff.getUserId()); //员工ID +// newRzSalaryDetail.setDeptId(sysStaff.getDeptId()); //部门 +// newRzSalaryDetail.setName(sysStaff.getName()); //姓名 +// newRzSalaryDetail.setWbFlag(sysStaff.getCompanyName()); //公司 +// newRzSalaryDetail.setDelFlag(Constants.DELETE_FLAG_0); +// //查询考勤统计 +// RzAttendanceStatistical attendanceStatistical = rzAttendanceStatisticalMapper.getRzAttendanceStatisticalByDateAndName(sysStaff.getUserId(), rzSalaryDetail.getMonth()); +// //查询员工详情 +// SysStaffDetail sysStaffDetail = sysStaffDetailMapper.selectSysStaffDetailByStaffId(sysStaff.getUserId()); +// +// Map salaryCalculationExchangeProcessorMap = applicationContext.getBeansOfType(SalaryCalculationStrategyExchangeProcessor.class); +// for (SalaryCalculationStrategyExchangeProcessor processor : salaryCalculationExchangeProcessorMap.values()) { +// if (processor.accept(sysStaffDetail)) { +// processor.exchangeSalaryCalculation(sysStaff, sysStaffDetail, newRzSalaryDetail, attendanceStatistical, overTimeMap); +// } +// } +//} /** * 删除员工管理信息 * @@ -820,6 +977,13 @@ public class SysStaffServiceImpl extends ServiceImpl i @Override public void exportInfo(HttpServletResponse response, SysStaff sysStaff) { List res_list = new ArrayList(); + //查询所有的部门信息 + List sysDepts = deptMapper.selectList(new LambdaQueryWrapper().eq(SysDept::getDelFlag, 0)); + Map deptMaps = Collections.emptyMap(); + + for (SysDept dept : sysDepts){ + deptMaps.put(dept.getDeptId(), getAllParentName(sysDepts, dept.getDeptId(), Collections.emptyList())); + } //查询员工信息 List yg_list = getBaseMapper().selectSysStaffList(sysStaff); List userIds = yg_list.stream().map(SysStaff::getUserId).collect(Collectors.toList()); @@ -829,6 +993,7 @@ public class SysStaffServiceImpl extends ServiceImpl i for (SysStaff staff : yg_list) { SysStaffVo sysStaffVo = new SysStaffVo(); BeanUtils.copyProperties(staff,sysStaffVo); + sysStaffVo.setDeptName(DataUtils.findDefaultValue(deptMaps.get(staff.getDeptId()), staff.getDeptName())); //根据员工信息查询详情信息 SysStaffDetail sysStaffDetail = SubsidyCalculationUtils.subsidyCalculation(staff,detailMap.get(staff.getUserId()), subsidyList); BeanUtils.copyProperties(sysStaffDetail,sysStaffVo); @@ -838,4 +1003,43 @@ public class SysStaffServiceImpl extends ServiceImpl i ExcelUtil1 util = new ExcelUtil1(SysStaffVo.class); util.exportExcel(response, res_list, "员工信息"); } + + @Override + public SysStaff selectSysStaffByDingUserId(String dingUserId) { + return getBaseMapper().selectSysStaffByDingUserId(dingUserId); + } + + @Override + public void sysStaffLeaveByDingUserId(String dingUserId) { + SysStaff sysStaff = selectSysStaffByDingUserId(dingUserId); + //减去一分钟, 防止离职失败 + sysStaff.setQuitDate(DateUtils.addMinutes(new Date(), -1)); + updateSysStaff(sysStaff); + } + + @Override + public AjaxResult getDingUserId(String userName) { + SysStaff sysStaff = baseMapper.getDingUserId(userName); + if(sysStaff == null){ + return AjaxResult.error("钉钉UserId不存在"); + } + return AjaxResult.success(JSONObject.parseObject(JSONObject.toJSONString(sysStaff))); + } + + + public String getAllParentName(List sysDepts, Long parentId, List allParentNames){ + for (SysDept sysDept : sysDepts){ + if(sysDept.getDeptId().equals(parentId)){ + allParentNames.add(sysDept.getDeptName()); + if(sysDept.getParentId() != null){ + return getAllParentName(sysDepts, sysDept.getParentId(), allParentNames); + } + } + } + java.util.Collections.reverse(allParentNames); + return String.join("-", allParentNames); + } + } + + diff --git a/evo-admin/src/main/resources/application-dev.yml b/evo-admin/src/main/resources/application-dev.yml index 400bfe9..d1d3599 100644 --- a/evo-admin/src/main/resources/application-dev.yml +++ b/evo-admin/src/main/resources/application-dev.yml @@ -7,7 +7,7 @@ spring: # 热部署开关 redis: # 地址 - host: 192.168.5.232 + host: localhost # 端口,默认为6379 port: 6379 # 数据库索引 diff --git a/evo-admin/src/main/resources/application-local.yml b/evo-admin/src/main/resources/application-local.yml index 2d422ac..57e972b 100644 --- a/evo-admin/src/main/resources/application-local.yml +++ b/evo-admin/src/main/resources/application-local.yml @@ -11,7 +11,7 @@ spring: # 端口,默认为6379 port: 6379 # 数据库索引 - database: 0 + database: 2 # 密码 password: hbyt2025 # 连接超时时间 @@ -32,7 +32,7 @@ spring: druid: # 主库数据源 master: - url: jdbc:mysql://localhost:3306/evo_cw_dev?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + url: jdbc:mysql://localhost:3306/evo_cw_dev_ding?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 username: root password: hbyt123456 #username: root diff --git a/evo-admin/src/main/resources/application.yml b/evo-admin/src/main/resources/application.yml index c8aa6aa..6ff1cfb 100644 --- a/evo-admin/src/main/resources/application.yml +++ b/evo-admin/src/main/resources/application.yml @@ -115,3 +115,28 @@ yt: appid: wx268e32962db19f5f app-secret: 84a6065165ec82862c5e03a010a6dc6c abnormal-attendance-template-id: z9sy-38K-iC5MAWHbxcxwg1c-9oNTFWeCOoy6B6zdKY + async: + corePoolSize: 15 + maxPoolSize: 30 + queueCapacity: 60 + keepAliveSeconds: 60 +ding: + base_url: https://oapi.dingtalk.com/ + url: ${ding.base_url}topapi/ + client_id: dingoilfezillv76k3mm + client_secret: _UsKmEIidy8U-VDxhb11-qxSGwg4JZqretet4zV5YYTF39lH1DLig5kIlQx4pMfd + aes_key: gCywKzw8AyGfnnh5SkIaRNnVSLzKka0mYjzrODqRzqD + token: J0kSLkXOVMqI3PSSrF1YS16r2pwpExzyEFDGl68SNbf + corp_id: dinga5c6eeb2f797ecdbf5bf40eda33b7ba0 + + + +# 动态线程池配置 +thread: + pool: + core-pool-size: 5 # 核心线程 + max-pool-size: 20 # 最大线程 + keep-alive-seconds: 60 # 空闲回收时间 + queue-capacity: 500 # 队列容量 + thread-name-prefix: "data-handle-pool-" + batch-size: 50 # 每个线程处理50条数据 \ No newline at end of file diff --git a/evo-admin/src/main/resources/mapper/ding/DingGroupMapper.xml b/evo-admin/src/main/resources/mapper/ding/DingGroupMapper.xml new file mode 100644 index 0000000..9cbb020 --- /dev/null +++ b/evo-admin/src/main/resources/mapper/ding/DingGroupMapper.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + select id, name, ding_Id, group_key from ding_group + + + diff --git a/evo-admin/src/main/resources/mapper/ding/DingShiftGroupMapper.xml b/evo-admin/src/main/resources/mapper/ding/DingShiftGroupMapper.xml new file mode 100644 index 0000000..b329b29 --- /dev/null +++ b/evo-admin/src/main/resources/mapper/ding/DingShiftGroupMapper.xml @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + select id, group_id, shift_id, type, check_time from ding_shift_group + + + + + + update ding_shift_group set check_time = #{checkTime} where shift_id=#{shiftId} and type = #{type} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/evo-admin/src/main/resources/mapper/ding/DingShiftMapper.xml b/evo-admin/src/main/resources/mapper/ding/DingShiftMapper.xml new file mode 100644 index 0000000..0d99066 --- /dev/null +++ b/evo-admin/src/main/resources/mapper/ding/DingShiftMapper.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + select id, name, ding_Id, work_Hour, on_duty_check_time, off_duty_check_time from ding_shift + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/evo-admin/src/main/resources/mapper/finance/RzSalaryDetailMapper.xml b/evo-admin/src/main/resources/mapper/finance/RzSalaryDetailMapper.xml index 7aa69fb..ecc8d6c 100644 --- a/evo-admin/src/main/resources/mapper/finance/RzSalaryDetailMapper.xml +++ b/evo-admin/src/main/resources/mapper/finance/RzSalaryDetailMapper.xml @@ -65,14 +65,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" maternity_insurance, unemployment_insurance, accumulation_fund, salary_before_tax, total_wages, annual_exemption_amount, special_deduction, taxable_income, tax_rate, slow_down_the_deduction, aggregate_personal_income_tax, aggregate_tax, tax_payable, net_payroll, remarks, del_flag, create_by, create_time, update_by, update_time, sales_commission, middle_subsidies, - social_security_deduction + social_security_deduction, type from rz_salary_detail + + + + diff --git a/evo-admin/src/main/resources/mapper/personnelMatters/RzLeaveDetailMapper.xml b/evo-admin/src/main/resources/mapper/personnelMatters/RzLeaveDetailMapper.xml index ea0d6fb..8b9b741 100644 --- a/evo-admin/src/main/resources/mapper/personnelMatters/RzLeaveDetailMapper.xml +++ b/evo-admin/src/main/resources/mapper/personnelMatters/RzLeaveDetailMapper.xml @@ -125,7 +125,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" where ld.del_flag = '0' and ld.type = #{type} and l.user_id=#{userId} and JSON_EXTRACT(extension,CONCAT('$.',CONCAT("month",DATE_FORMAT(#{date},'%m'))))=DATE_FORMAT(#{date},'%Y-%m') - + diff --git a/evo-admin/src/main/resources/mapper/personnelMatters/RzLeaveMapper.xml b/evo-admin/src/main/resources/mapper/personnelMatters/RzLeaveMapper.xml index 5a863be..34e0a1c 100644 --- a/evo-admin/src/main/resources/mapper/personnelMatters/RzLeaveMapper.xml +++ b/evo-admin/src/main/resources/mapper/personnelMatters/RzLeaveMapper.xml @@ -116,4 +116,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" where del_flag = '0' and DATE_FORMAT( leave_date, '%Y%m' ) = DATE_FORMAT( #{date} , '%Y%m' ) and user_id = #{userId} + + + diff --git a/evo-admin/src/main/resources/mapper/system/SysDeptMapper.xml b/evo-admin/src/main/resources/mapper/system/SysDeptMapper.xml index 2eb5769..6088bb0 100644 --- a/evo-admin/src/main/resources/mapper/system/SysDeptMapper.xml +++ b/evo-admin/src/main/resources/mapper/system/SysDeptMapper.xml @@ -23,7 +23,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.leader, d.phone,d.status, d.del_flag,d.is_over_time, d.is_show_financial, d.create_by, d.create_time + select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.leader, d.phone,d.status, d.del_flag,d.is_over_time, d.is_show_financial, d.create_by, d.create_time, d.ding_id from sys_dept d @@ -105,6 +105,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" is_over_time, is_show_financial, create_by, + ding_id, + create_time )values( #{deptId}, @@ -117,6 +119,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{isOverTime}, #{isShowFinancial}, #{createBy}, + #{dingId}, sysdate() ) @@ -133,6 +136,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" is_over_time = #{isOverTime}, is_show_financial = #{isShowFinancial}, update_by = #{updateBy}, + ding_id = #{dingId}, update_time = sysdate() where dept_id = #{deptId} @@ -171,6 +175,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" where dept_id not in (select parent_id from sys_dept) and del_flag = '0' + + + + + + + + + + + + + +