Compare commits

...

30 Commits

Author SHA1 Message Date
andy
6b18b1651b 1 2026-06-02 14:25:59 +08:00
andy
65eab9985b 1 2026-06-01 08:40:58 +08:00
andy
526bd7473c 钉钉调整 2026-05-04 09:47:02 +08:00
andy
f8a75bb671 修改请假 2026-04-25 13:37:11 +08:00
andy
7d28cb895f 调整 2026-04-25 10:22:43 +08:00
andy
ed6d997c41 Merge branch 'dingding' of https://git.evo-techina.com/hbyt/evo-Financial-pc into dingding 2026-04-24 16:39:57 +08:00
andy
098ab28150 钉钉版本调整 2026-04-24 16:39:25 +08:00
andy
a055d211ff 顶顶推送相关数据获取 2026-04-23 11:55:11 +08:00
andy
1a6b582301 1 2026-04-20 09:22:49 +08:00
andy
3cfd1b63ec 1 2026-04-17 16:10:22 +08:00
andy
04037fca60 1 2026-04-14 15:25:14 +08:00
andy
896ebc9679 处理离职问题 2026-04-06 14:07:31 +08:00
andy
a15b5ec75a Merge branch 'master' into dingding
# Conflicts:
#	evo-admin/src/main/java/com/evo/restaurant/controller/RzRestaurantDetailController.java
2026-04-06 09:16:50 +08:00
andy
a68ae036b6 1 2026-04-06 08:51:00 +08:00
andy
37323443d3 1 2026-04-03 16:49:41 +08:00
andy
76cf1cfc2b 1 2026-04-01 13:41:02 +08:00
andy
fb3c3b44f1 调整 2026-04-01 13:37:07 +08:00
andy
967ea6020b 改版调整 2026-03-31 15:23:55 +08:00
andy
5242b4f3d3 Merge remote-tracking branch 'remotes/origin/master' into dingding 2026-03-28 14:22:13 +08:00
andy
039dc85471 1 2026-03-28 14:18:36 +08:00
andy
13f634ddb8 1 2026-03-28 10:17:27 +08:00
andy
8406cf1eb8 1 2026-03-27 16:03:36 +08:00
andy
5bbd6b02ba 1 2026-03-27 14:50:15 +08:00
andy
8eb0a5a58f 钉钉处理 2026-03-27 10:23:28 +08:00
andy
cb1d56c751 钉钉员工入职离职回调 2026-03-18 13:29:08 +08:00
andy
022bfe4fb4 Merge remote-tracking branch 'remotes/origin/master' into dingding 2026-03-18 09:06:22 +08:00
andy
2002d2a45b 考勤改版调整 2026-03-16 11:55:27 +08:00
andy
6c1c95352d Merge remote-tracking branch 'remotes/origin/master' into dingding 2026-03-09 13:34:46 +08:00
andy
99640b1edc 1 2026-03-09 11:15:28 +08:00
andy
31f481a78b 钉钉相关业务调整 2026-03-07 13:23:41 +08:00
98 changed files with 4150 additions and 478 deletions

View File

@ -17,6 +17,26 @@
<dependencies>
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<!-- 新版 -->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dingtalk</artifactId>
<version>2.2.43</version>
</dependency>
<!-- 旧版 -->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>alibaba-dingtalk-service-sdk</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
@ -223,7 +243,6 @@
<scope>system</scope>
<systemPath>${project.basedir}/src/main/resources/lib/k3cloud-webapi-sdk-java11-v8.2.0.jar</systemPath>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
@ -241,6 +260,12 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<version>3.3.3</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>

View File

@ -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)

View File

@ -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);
}
}

View File

@ -120,5 +120,9 @@ public class RzAttendance extends BaseEntity {
private Date startTime;
@TableField(exist = false)
private Date endTime;
/***
* 补卡扣款
*/
private BigDecimal debiting;
}

View File

@ -76,7 +76,14 @@ public interface PunchTheClockStrategyExchangeProcessor {
return "";
}
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));
}

View File

@ -150,7 +150,6 @@ public class KQDeviceExchangeProcessor implements PunchTheClockStrategyExchangeP
return initMessage(1, "当天已经打过加班卡");
}
//员工考勤记录
RzAttendance attendance = rzAttendanceMapper.queryNowDayAttendanceByStatisticalIdAndDate(Long.valueOf(userId),date);
//如果当前打卡是下班卡, 并且当前员工考勤上班时间为空, 则判定为隔天打下班卡

View File

@ -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>
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);
}

View File

@ -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<RzSpecialAttendance>
{
/**
* 查询加班考勤记录
@ -51,4 +54,6 @@ public interface IRzSpecialAttendanceService
* @return 结果
*/
public int deleteRzSpecialAttendanceById(Long id);
public RzSpecialAttendance selectRzSpecialAttendanceByUserIdAndDate(Long staffId, Date date);
}

View File

@ -141,11 +141,6 @@ public class RzAttendanceDetailServiceImpl extends ServiceImpl<RzAttendanceDetai
data.setIcon(timeLine.icon);
});
return result;
//
// return getBaseMapper().selectListByAttendanceId(new LambdaQueryWrapper<RzAttendanceDetail>().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");

View File

@ -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<RzAttendanceMapper, RzA
private SendClientService sendClientService;
@Autowired
private SysStaffMapper sysStaffMapper;
@Autowired
private DingShiftGroupMapper dingsShiftGroupMapper;
@Autowired
private DingShiftMapper dingsShiftMapper;
@Resource
private RzAttendanceBatchHandler dataBatchHandler;
private static final String MORNING_CARD_SINGLE = "上班卡(单班制)";
private static final String MORNING_CARD_DOUBLE = "上班卡(双班制)";
@ -479,7 +494,7 @@ public class RzAttendanceServiceImpl extends ServiceImpl<RzAttendanceMapper, RzA
try {
for (SysStaff sysStaff : sysStaffService.selectSysStaffListAll()){
Date date = DateUtils.addDays(new Date(), -1);
RzAttendance beforeAttendance = getBaseMapper().queryNowDayAttendanceByStatisticalIdAndDate(sysStaff.getUserId(), date);
RzAttendance beforeAttendance = queryNowDayAttendanceByStatisticalIdAndDate(sysStaff.getUserId(), date);
if(beforeAttendance.getWorkStartTime() != null && beforeAttendance.getWorkEndTime() == null){
sendAbnormalAttendance(sysStaff, beforeAttendance.getWorkStartTime());
@ -505,8 +520,202 @@ public class RzAttendanceServiceImpl extends ServiceImpl<RzAttendanceMapper, RzA
log.error("查询前一天的打卡情况报错了");
}
}
@Override
@Async("asyncExecutor")
public void dingDing(String dingUserId, String bizId, Long checkTime) {
//此处需要保证, 所有的员工必须存在dingUserId
SysStaff sysStaff = sysStaffMapper.selectSysStaffByDingUserId(dingUserId);//打卡记录信息
if(sysStaff != null){
String result = DingUtils.getListRecord(Collections.asList(dingUserId), DateUtils.parseDateToStr("yyyy-MM-dd", new Date(checkTime))+" 00:00:00", DateUtils.parseDateToStr("yyyy-MM-dd", new Date(checkTime))+" 23:59:59");
System.out.println("打卡结果===>"+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){

View File

@ -171,16 +171,21 @@ public class RzAttendanceStatisticalServiceImpl extends ServiceImpl<RzAttendance
RzAttendanceStatistical rzAttendanceStatistical = getBaseMapper().getRzAttendanceStatisticalByDateAndName(sysStaff.getUserId(),date);
if(StringUtils.isNotNull(rzAttendanceStatistical)){
//判断名称和部门是否一样不一样操作修改
if(!rzAttendanceStatistical.getName().equals(sysStaff.getName()) || rzAttendanceStatistical.getDeptId() != sysStaff.getDeptId()){
//if(!rzAttendanceStatistical.getName().equals(sysStaff.getName()) || rzAttendanceStatistical.getDeptId() != sysStaff.getDeptId()){
if(!rzAttendanceStatistical.getName().equals(sysStaff.getName())){
//修改部门和姓名
rzAttendanceStatistical.setName(sysStaff.getName());
if(rzAttendanceStatistical.getDeptId() == null){
rzAttendanceStatistical.setDeptId(sysStaff.getDeptId());
}
getBaseMapper().updateRzAttendanceStatistical(rzAttendanceStatistical);
//查询考勤详情修改
List<RzAttendance> kq_list = rzAttendanceMapper.queryMonthAttendanceByStaffId(sysStaff.getUserId(),new Date());
//循环修改信息
for (RzAttendance rzAttendance : kq_list) {
if(rzAttendanceStatistical.getDeptId() == null){
rzAttendance.setDeptId(sysStaff.getDeptId());
}
rzAttendance.setName(sysStaff.getName());
rzAttendanceMapper.updateRzAttendance(rzAttendance);
}

View File

@ -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<RzSpecialAttendanceMapper, RzSpecialAttendance> 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);
}
}

View File

@ -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<RzSysParamMapper, RzSysPa
@Override
// @Cacheable(cacheNames = Constants.SYS_RUNNING_PARAMS, key = "#code")
public RzSysParam getRzSysParam(String name, String code, String defVal, String des){
RzSysParam param = getRzSysParam(code);
if(ObjectUtils.isEmpty(param)){
@ -116,7 +118,7 @@ public class RzSysParamServiceImpl extends ServiceImpl<RzSysParamMapper, RzSysPa
return param;
}
@Override
@Cacheable(cacheNames = Constants.SYS_RUNNING_PARAMS, key = "#code")
// @Cacheable(cacheNames = Constants.SYS_RUNNING_PARAMS, key = "#code")
public RzSysParam getRzSysParam(String code){
return getOne(new LambdaQueryWrapper<RzSysParam>().eq(RzSysParam::getParamCode, code));
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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; // 每线程处理条数
}

View File

@ -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";
}

View File

@ -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<InstanceChangeExchangeProcessor> instanceChangeExchangeProcessorList;
@Autowired
List<DingCallBackExchangeProcessor> dingCallBackExchangeProcessorList;
@PostMapping("/ding/clock")
public Map<String, String> dingDingClock(@RequestBody Map<String, Object> 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<String, String> successMap = callbackCrypto.getEncryptedMap("success");
return successMap;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

View File

@ -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<SysStaff> staffList = sysStaffService.list(new LambdaQueryWrapper<SysStaff>().ne(SysStaff::getStatus, -1).isNull(SysStaff::getDingUserId));
List<String> 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<String, String> headers = responseBody.getHeaderSignatureInfo().getHeaders();
URL url = new URL(resourceUrl);
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
if (headers != null) {
for (Map.Entry<String, String> 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<String, Object> 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<String,String> 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)))));
}
/**
* 清洗加班

View File

@ -57,6 +57,8 @@ public class SysDept extends BaseEntity
/** 是否加班 */
private String isOverTime;
private String dingId;
/** 子部门 */
@TableField(exist = false)
private List<SysDept> children = new ArrayList<SysDept>();

View File

@ -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<A, B, C, D> {
void apply(A a, B b, C c, D d);
}

View File

@ -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<String, SysStaff, JSONObject, RzAttendance> calculationAddRzOverTime) {
int batchSize = poolProperties.getBatchSize(); // 50条/线程
AtomicInteger index = new AtomicInteger(0);
List<SysStaff> sysStaffList = sysStaffService.selectSysStaffListAll();
Date firstDate = DateUtils.getMonthFirst(date);
Date endDate = DateUtils.getMonthEnd(date);
// 获取有多少天
List<String> 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<SysStaff> 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<SysStaff> batchData, List<String> dateTimeList, FourParamFunction<String, SysStaff, JSONObject, RzAttendance> calculationAddRzOverTime) {
String threadName = Thread.currentThread().getName();
System.out.println("========================================");
System.out.println(threadName + " 开始处理,条数:" + batchData.size());
//将数据的钉钉钉钉list获取
Map<String, SysStaff> map = batchData.stream().filter(data -> StringUtils.isNotEmpty(data.getDingUserId())).collect(Collectors.toMap(SysStaff::getDingUserId, data -> data));
List<String> 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 + " 处理完成");
}
}

View File

@ -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<String> 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<Long> 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<String> getWebCompany(){
RzSysParam param= paramService.getRzSysParam("外包公司名称", "web_company","WB,LWWB","外包公司, 不扣个税)");
return Collections.asList(param.getParamValue().split(",")).stream().filter(StringUtils::isNotEmpty).collect(Collectors.toList());

View File

@ -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);
}
}

View File

@ -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());

View File

@ -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<String, String> 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<String, String> 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<String, String> resultMap = new HashMap<String, String>();
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<Integer, String> 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> T getFieldValue(Class<?> srcClazz, String fieldName, Object owner, Class<T> dstClazz) throws Exception {
Field field = srcClazz.getDeclaredField(fieldName);
field.setAccessible(true);
return dstClazz.cast(field.get(owner));
}
}

View File

@ -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;
}
}

View File

@ -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 <T> 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<String> 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;
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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<DingGroup> {
public DingGroup selectByDingId(@Param("dingId") String dingId);
}

View File

@ -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> {
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<DingShiftGroup> selectListByShiftId(@Param("shiftId") String shiftId);
}

View File

@ -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<DingShift> {
public DingShift selectByDingId(@Param("dingId") String dingId);
public List<DingShift> selectList(DingShift dingShift);
}

View File

@ -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<String, Object> 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;
}
}

View File

@ -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<GetProcessInstanceResponseBody.GetProcessInstanceResponseBodyResultFormComponentValues> 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<GetProcessInstanceResponseBody.GetProcessInstanceResponseBodyResultFormComponentValues> 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());
}
}

View File

@ -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);
}
}
}

View File

@ -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<RzAttendanceDetail>().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;
}
}
}
}

View File

@ -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<GetProcessInstanceResponseBody.GetProcessInstanceResponseBodyResultFormComponentValues> 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();
}
}
}

View File

@ -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);
}

View File

@ -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<AttendanceApproveStatusChangeExchangeProcessor> 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);
}
}
}
}

View File

@ -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"));
}
}
}
}

View File

@ -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<DingShiftGroup> 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<String, List<DingShiftGroup>> 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);
}
}
}

View File

@ -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<InstanceChangeExchangeProcessor> 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);
}
}
}
}

View File

@ -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());
}
}
}
}

View File

@ -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));
});
}
}
}

View File

@ -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)));
});
}
}
}

View File

@ -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);
}

View File

@ -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<GetProcessInstanceResponseBody.GetProcessInstanceResponseBodyResultFormComponentValues> 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();
}
}
}
}

View File

@ -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<DingGroup> {
public DingGroup selectByDingId(String dingId);
}

View File

@ -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> {
DingShiftGroup selectByGroupIdAndTypeAndCheckTime(String groupId, String shiftId, String type, String checkTime);
int updateCheckTimeByShiftIdAndType(String shiftId, String type, String checkTime);
List<DingShiftGroup> selectListByGroupId(String groupId);
public List<DingShiftGroup> selectList(DingShiftGroup dingShiftGroup);
}

View File

@ -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<DingShift> {
public DingShift selectByDingId(String dingId);
public List<DingShift> selectList(DingShift dingShift);
}

View File

@ -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<DingGroupMapper, DingGroup> implements DingGroupService {
@Override
public DingGroup selectByDingId(String dingId) {
return getBaseMapper().selectByDingId(dingId);
}
}

View File

@ -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<DingShiftGroupMapper, DingShiftGroup> 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<DingShiftGroup> selectListByGroupId(String groupId) {
return list(new LambdaQueryWrapper<DingShiftGroup>().eq(DingShiftGroup::getGroupId, groupId));
}
@Override
public List<DingShiftGroup> selectList(DingShiftGroup dingShiftGroup) {
return getBaseMapper().selectListByShiftId(dingShiftGroup.getShiftId());
}
}

View File

@ -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<DingShiftMapper, DingShift> implements DingShiftService {
@Override
public DingShift selectByDingId(String dingId) {
return getBaseMapper().selectByDingId(dingId);
}
@Override
public List<DingShift> selectList(DingShift dingShift) {
return getBaseMapper().selectList(dingShift);
}
}

View File

@ -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<SalaryVo> util = new ExcelUtilSs<SalaryVo>(SalaryVo.class);
//创建总表
List<SalaryVo> list = new ArrayList<SalaryVo>();
//创建各个公司的数据
List<List<SalaryVo>> lists = new ArrayList<>();
//创建各个部门sheetname集合
List<String> sheetNameList = new ArrayList<>();
//汇总表表头
String title = new SimpleDateFormat("yyyy-MM").format(rzSalaryDetail.getMonth())+"月工资汇总表";
//获取所有的最小独立部门
List<SysDept> dept_list = deptService.queryAllDeptForMin();
//员工工资信息
SalaryVo salaryVo = null;
//工资数据转化的保存
List<SalaryVo> list0 =new ArrayList<SalaryVo>();
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<RzSalaryDetail> 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<SysDictData> 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<RzSalaryDetail> 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<RzSalaryVo> util = new ExcelUtil<>(RzSalaryVo.class);
// List<RzSalaryVo> attendanceList = util.importExcel(file.getInputStream());
// return success(rzSalaryDetailService.importSalesCommissions(attendanceList));
// }
/*
* 导出工资详情列表
*/

View File

@ -198,10 +198,23 @@ public class RzSalaryDetail extends BaseEntity
@TableField(exist = false)
private BigDecimal bjAmount;
//基本工资全薪
@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;
}
@ -630,6 +643,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;
}

View File

@ -70,4 +70,8 @@ public interface RzSalaryDetailMapper extends BaseMapper<RzSalaryDetail>
public List<RzSalaryDetail> selectSalaryDetailByWbFlag(@Param("wbFlag")String wbFlag,@Param("date")Date date);
/**
*/
public Date selectMaxMonthBySysStallId(Long id);
}

View File

@ -105,9 +105,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());
// }

View File

@ -115,7 +115,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);
}
BigDecimal gsj = new BigDecimal(0);
Long totalAllHour = 0l;
@ -128,6 +127,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))));

View File

@ -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<RzSalaryDetail> selectSalaryDetailByWbFlag(String wbFlag,Date date);
AjaxResult export(RzSalaryDetail rzSalaryDetail);
void dimission(SysStaff sysStaff);
}

View File

@ -141,15 +141,46 @@ public class RzSalaryDetailServiceImpl extends ServiceImpl<RzSalaryDetailMapper,
Map<Long, Boolean> overTimeMap = deptMapper.selectList(new LambdaQueryWrapper<SysDept>().eq(SysDept::getDelFlag, Constants.DELETE_FLAG_0).select(SysDept::getIsOverTime, SysDept::getDeptId)).stream().collect(Collectors.toMap(SysDept::getDeptId,d->"0".equals(d.getIsOverTime())));
for (SysStaff sysStaff : st_list) {
calculation(sysStaff, rzSalaryDetail.getMonth(), overTimeMap, 1);
}
//关闭日志记录
ParamUtils.updateLogOperation(false);
return AjaxResult.success();
}
@Override
public void dimission(SysStaff sysStaff) {
Map<Long, Boolean> overTimeMap = deptMapper.selectList(new LambdaQueryWrapper<SysDept>().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();
}
//进行离职工资计算操作
while (date.compareTo(sysStaff.getQuitDate()) < 1){
calculation(sysStaff, date, overTimeMap ,2);
date = DateUtils.addMonths(date, 1);
}
}
public static void main(String[] args) {
System.out.println(DateUtils.parseDate("2025-05-21").compareTo(DateUtils.parseDate("2025-05-21 12:21:21")));
}
public void calculation(SysStaff sysStaff, Date date, Map<Long, Boolean> overTimeMap, Integer type){
RzSalaryDetail newRzSalaryDetail = new RzSalaryDetail();
newRzSalaryDetail.setMonth(rzSalaryDetail.getMonth());
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(), rzSalaryDetail.getMonth());
RzAttendanceStatistical attendanceStatistical = rzAttendanceStatisticalMapper.getRzAttendanceStatisticalByDateAndName(sysStaff.getUserId(), date);
//查询员工详情
SysStaffDetail sysStaffDetail = sysStaffDetailMapper.selectSysStaffDetailByStaffId(sysStaff.getUserId());
@ -160,12 +191,6 @@ public class RzSalaryDetailServiceImpl extends ServiceImpl<RzSalaryDetailMapper,
}
}
}
//关闭日志记录
ParamUtils.updateLogOperation(false);
return AjaxResult.success();
}
/**

View File

@ -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()

View File

@ -49,7 +49,8 @@ public class RzLeaveDetail extends BaseEntity
private String remarks;
private String delFlag;
//钉钉审批id
private String processInstanceId;
/***
* 扩展字段
*/

View File

@ -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;
/** 删除标识 */

View File

@ -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<RzLeaveDetail>
*/
Long selectLeaveHourByUserIdAndDateAndType(@Param("userId") Long userId,@Param("date") Date date, @Param("type") Long type);
RzLeaveDetail selectRzLeaveDetailByProcessInstanceId(@Param("processInstanceId") String processInstanceId);
}

View File

@ -51,4 +51,10 @@ public interface RzLeaveMapper extends BaseMapper<RzLeave>
* @return
*/
public RzLeave queryRzLeaveByDateAndUserId(@Param("userId") Long userId, @Param("date") Date date);
/**
* 根据员工ID和时间查询请假统计
* @return
*/
public RzLeave queryRzLeaveByUserId(@Param("userId") Long userId);
}

View File

@ -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);
}

View File

@ -59,4 +59,12 @@ public interface IRzLeaveService
public List<RzLeaveDetail> listLeaveDetails(RzLeave rzLeave);
List<RzLeave> selectRzLeaveListByDate(RzLeave rzLeave);
/**
* 根据员工
*
* @param userId 员工id
* @return 请假管理
*/
public RzLeave selectRzLeaveByUserId(Long userId);
}

View File

@ -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<RzOverTimeDetail>
{
/**
* 查询加班详情

View File

@ -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<RzOverTime>
{
/**
* 查询加班管理
@ -60,4 +64,10 @@ public interface IRzOverTimeService
* @return
*/
public List<RzOverTimeDetail> 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);
}

View File

@ -89,11 +89,11 @@ public class RzLeaveDetailServiceImpl extends ServiceImpl<RzLeaveDetailMapper, R
//根据员工姓名查询
RzLeave rzLeave = rzLeaveMapper.selectRzLeaveById(rzLeaveDetail.getLeaveId());
//验证调休
if(Long.valueOf(55).equals(rzLeaveDetail.getType())){
if(!autoLeavedNumber(rzLeave.getUserId(),rzLeaveDetail.getLeaveStartTime(),rzLeaveDetail.getLeaveHour())){
return AjaxResult.error("当前人员的加班时长不足抵扣调休时长!!");
}
}
// if(Long.valueOf(55).equals(rzLeaveDetail.getType())){
// if(!autoLeavedNumber(rzLeave.getUserId(),rzLeaveDetail.getLeaveStartTime(),rzLeaveDetail.getLeaveHour())){
// return AjaxResult.error("当前人员的加班时长不足抵扣调休时长!!");
// }
// }
rzLeaveDetail.setDelFlag(Constants.DELETE_FLAG_0);
if(getBaseMapper().insert(rzLeaveDetail) < 1){
return AjaxResult.error("请假详情新增失败");
@ -394,6 +394,11 @@ public class RzLeaveDetailServiceImpl extends ServiceImpl<RzLeaveDetailMapper, R
return rzLeaveDetail;
}
@Override
public RzLeaveDetail selectRzLeaveDetailByProcessInstanceId(String processInstanceId) {
return getBaseMapper().selectRzLeaveDetailByProcessInstanceId(processInstanceId);
}
public RzLeaveDetail leaveHour(RzLeaveDetail rzLeaveDetail) {
if(rzLeaveDetail.getType() == null || rzLeaveDetail.getLeaveStartTime() == null){
return rzLeaveDetail;

View File

@ -2,6 +2,7 @@ package com.evo.personnelMatters.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.evo.common.annotation.DataScope;
import com.evo.common.constant.Constants;
import com.evo.common.core.domain.AjaxResult;
@ -29,7 +30,7 @@ import java.util.List;
* @date 2024-08-03
*/
@Service
public class RzLeaveServiceImpl implements IRzLeaveService
public class RzLeaveServiceImpl extends ServiceImpl<RzLeaveMapper, RzLeave> 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);
}
}

View File

@ -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<RzOverTimeDetailMapper, RzOverTimeDetail> implements IRzOverTimeDetailService
{
@Resource
private RzOverTimeDetailMapper rzOverTimeDetailMapper;

View File

@ -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<RzOverTimeMapper, RzOverT
return res_list;
}
@Override
public RzOverTime selectRzOverTimeByNameAndMonth(Long userId, Date overTimeMonth) {
return getBaseMapper().selectRzOverTimeByNameAndMonth(userId, overTimeMonth);
}
@Override
public String overTimeCard(SysStaff sysStaff, Date overTimeMonth) {
//判断打卡月是否统计过加班
RzOverTime rzOverTime = getBaseMapper().selectRzOverTimeByNameAndMonth(sysStaff.getUserId(),overTimeMonth);
if(rzOverTime == null){
rzOverTime = new RzOverTime();
rzOverTime.setUserId(sysStaff.getUserId());
rzOverTime.setOverHours(new BigDecimal("0.0"));
rzOverTime.setDeptId(sysStaff.getDeptId());
rzOverTime.setName(sysStaff.getName());
rzOverTime.setOverTimeMonth(overTimeMonth);
if(getBaseMapper().insert(rzOverTime) < 1){
return PunchTheClockStrategyExchangeProcessor.initStaticMessage(1, "打卡失败");
}
}
RzOverTimeDetail rzOverTimeDetail = new RzOverTimeDetail();
rzOverTimeDetail.setOverTimeId(rzOverTime.getId());
rzOverTimeDetail.setOverTimeStart(overTimeMonth);
rzOverTimeDetail.setName(sysStaff.getName());
rzOverTimeDetail.setDelFlag(Constants.DELETE_FLAG_0);
rzOverTimeDetail.setCreateBy("admin");
rzOverTimeDetail.setCreateTime(DateUtils.getNowDate());
return (rzOverTimeDetailMapper.insert(rzOverTimeDetail) < 1) ? PunchTheClockStrategyExchangeProcessor.initStaticMessage(1, "打卡失败") : PunchTheClockStrategyExchangeProcessor.initStaticMessage(0, "打卡成功");
}
@Override
public String overTimeOffDutyCard(SysStaff sysStaff, Date date, String sn) {
//修改加班打卡记录 根据员工ID和时间查找 统计数据
RzOverTime rzOverTime = getBaseMapper().selectRzOverTimeByNameAndMonth(sysStaff.getUserId(),date);
//如果没有加班汇总, 生成一条新的
if(ObjectUtils.isEmpty(rzOverTime)){
rzOverTime = new RzOverTime();
rzOverTime.setUserId(sysStaff.getUserId());
rzOverTime.setDeptId(sysStaff.getDeptId());
rzOverTime.setName(sysStaff.getName());
rzOverTime.setOverTimeMonth(date);
rzOverTime.setOverHours(DataUtils.DEFAULT_VALUE);
rzOverTime.setDelFlag(Constants.DELETE_FLAG_0);
rzOverTime.setCreateBy("admin");
rzOverTime.setCreateTime(new Date());
getBaseMapper().insert(rzOverTime);
}
//查找加班详情 加班统计ID和加班开始时间
RzOverTimeDetail rzOverTimeDetail = rzOverTimeDetailMapper.queryRzOverTimeDetailByDateAndOverId(rzOverTime.getId(),date);
if(ObjectUtils.isEmpty(rzOverTimeDetail)){
//特殊情况, 会存在过12点的情况, 这时候需要核查下前一天没有下班的加班数据
rzOverTimeDetail = rzOverTimeDetailMapper.queryRzOverTimeDetailByDateAndOverIdAndOverTimeEndIsNull(rzOverTime.getId(), DateUtils.addDays(date,-1));
//如果前一天也为空
if(ObjectUtils.isEmpty(rzOverTimeDetail)){
return PunchTheClockStrategyExchangeProcessor.initStaticMessage(1, "未找到当天的加班信息, 请补卡");
}
}
rzOverTimeDetail.setOverTimeEnd(date);
//计算加班时长 分钟
KqUtils.calculateOverTimeHours(rzOverTimeDetail, sysStaff.getUserId(), sn);
if(rzOverTimeDetailMapper.updateRzOverTimeDetail(rzOverTimeDetail) < 1){
return PunchTheClockStrategyExchangeProcessor.initStaticMessage(1, "打卡失败");
}
//加班修改统计
rzOverTime.setOverHours(rzOverTime.getOverHours().add(rzOverTimeDetail.getOverTimeHours()));
if(getBaseMapper().updateRzOverTime(rzOverTime) < 1){
return PunchTheClockStrategyExchangeProcessor.initStaticMessage(1, "打卡失败");
}
return PunchTheClockStrategyExchangeProcessor.initStaticMessage(0, "打卡成功");
}
}

View File

@ -25,6 +25,7 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
@ -41,9 +42,9 @@ import java.util.List;
@RequestMapping("/api/v2")
public class RzRestaurantDetailController extends BaseController
{
@Autowired
@Resource
private IRzRestaurantDetailService rzRestaurantDetailService;
@Autowired
@Resource
private ISysStaffService sysStaffService;
/**
* 查询餐饮详情列表

View File

@ -244,7 +244,9 @@ public class RzRestaurantStatisticsServiceImpl extends ServiceImpl<RzRestaurantS
private void create(Long staffId, Long deptId, String name, Date date){
RzRestaurantStatistics rzRestaurantStatistics = getBaseMapper().selectRzRestaurantStatisticsByUserIdAndDate(staffId,date);
if(StringUtils.isNotNull(rzRestaurantStatistics)){
if(rzRestaurantStatistics.getDeptId() == null){
rzRestaurantStatistics.setDeptId(deptId);
}
rzRestaurantStatistics.setName(name);
getBaseMapper().updateRzRestaurantStatistics(rzRestaurantStatistics);
return;

View File

@ -0,0 +1,55 @@
package com.evo.system.controller;
import com.evo.common.core.controller.BaseController;
import com.evo.common.core.page.TableDataInfo;
import com.evo.ding.domain.DingShift;
import com.evo.ding.domain.DingShiftGroup;
import com.evo.ding.service.DingShiftGroupService;
import com.evo.ding.service.DingShiftService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
/**
* ShiftController
*
* @author andy.shi
* @ClassName:ShiftContriller
* @date: 2026年03月27日 9:18
* @remark: 开发人员联系方式 1042025947@qq.com/微信同步
*/
@RestController
@RequestMapping("/system/shift")
public class ShiftController extends BaseController {
@Resource
private DingShiftService dingShiftService;
@Resource
private DingShiftGroupService dingShiftGroupService;
/**
* 查询班次信息
*/
@PreAuthorize("@ss.hasPermi('system:shift:list')")
@GetMapping("/list")
public TableDataInfo list(DingShift dingShift){
startPage();
List<DingShift> list = dingShiftService.selectList(dingShift);
return getDataTable(list);
}
/**
* 查询考勤组信息
*/
@GetMapping("/group/list")
public TableDataInfo list(DingShiftGroup dingShiftGroup){
startPage();
List<DingShiftGroup> list = dingShiftGroupService.selectList(dingShiftGroup);
return getDataTable(list);
}
}

View File

@ -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);
}
}

View File

@ -215,6 +215,10 @@ public class SysStaff extends BaseEntity
private String extended;
private String dingUserId;
//数据来源 1 平台, 2 钉钉
private String source;
public List<Long> getSubsidyList() {
if(Collections.isEmpty(subsidyList) && StringUtils.isNotEmpty(subsidys)){
subsidyList = Collections.asList(subsidys.split(",")).stream().map(Long::valueOf).collect(Collectors.toList());

View File

@ -129,4 +129,9 @@ public interface SysDeptMapper extends BaseMapper<SysDept>
* @return 结果
*/
public int updateDeptForLeader(SysDept dept);
public SysDept selectByDingDeptId(String dingId);
public SysDept selectByName(String name);
}

View File

@ -94,4 +94,14 @@ s * @return
*/
SysStaff selectLeaderSysStaffByDeptId(Long deptId);
/**
* 查询员工管理
*
* @param dingUserId 员工管理主键
* @return 员工管理
*/
public SysStaff selectSysStaffByDingUserId(String dingUserId);
SysStaff getDingUserId(@Param("userName") String userName);
}

View File

@ -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<SysDictData> selectDictDataListByType(String type);
}

View File

@ -39,6 +39,13 @@ public interface ISysStaffService extends IService<SysStaff>
* @return 结果
*/
public AjaxResult insertSysStaff(SysStaff sysStaff);
/**
* 新增员工管理
*
* @param result 员工管理
* @return 结果
*/
public void insertSysStaffByDingDing(String dingUserInfo);
/**
* 修改员工管理
*
@ -108,13 +115,26 @@ public interface ISysStaffService extends IService<SysStaff>
* @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);
}

View File

@ -117,4 +117,9 @@ public class SysDictDataServiceImpl extends ServiceImpl<SysDictDataMapper, SysDi
}
return row;
}
@Override
public List<SysDictData> selectDictDataListByType(String type) {
return getBaseMapper().selectDictDataByType(type);
}
}

View File

@ -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<SysStaffMapper, SysStaff> i
private IEqSnDetailService eqSnDetailService;//设备信息
@Resource
private RzSubsidyInfoMapper rzSubsidyInfoMapper;
@Resource
IRzSalaryDetailService rzSalaryDetailService;
/**
* 查询员工管理
*
@ -148,7 +158,7 @@ public class SysStaffServiceImpl extends ServiceImpl<SysStaffMapper, SysStaff> 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<SysStaffMapper, SysStaff> 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<SysStaff>().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<SysStaffMapper, SysStaff> 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<SysStaffMapper, SysStaff> 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<SysStaffMapper, SysStaff> 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<SysStaffMapper, SysStaff> 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<SysStaffMapper, SysStaff> 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<String, SalaryCalculationStrategyExchangeProcessor> 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<SysStaffMapper, SysStaff> i
@Override
public void exportInfo(HttpServletResponse response, SysStaff sysStaff) {
List<SysStaffVo> res_list = new ArrayList<SysStaffVo>();
//查询所有的部门信息
List<SysDept> sysDepts = deptMapper.selectList(new LambdaQueryWrapper<SysDept>().eq(SysDept::getDelFlag, 0));
Map<Long, String> deptMaps = Collections.emptyMap();
for (SysDept dept : sysDepts){
deptMaps.put(dept.getDeptId(), getAllParentName(sysDepts, dept.getDeptId(), Collections.emptyList()));
}
//查询员工信息
List<SysStaff> yg_list = getBaseMapper().selectSysStaffList(sysStaff);
List<Long> userIds = yg_list.stream().map(SysStaff::getUserId).collect(Collectors.toList());
@ -829,6 +993,7 @@ public class SysStaffServiceImpl extends ServiceImpl<SysStaffMapper, SysStaff> 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<SysStaffMapper, SysStaff> i
ExcelUtil1<SysStaffVo> util = new ExcelUtil1<SysStaffVo>(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<SysDept> sysDepts, Long parentId, List<String> 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);
}
}

View File

@ -7,7 +7,7 @@ spring:
# 热部署开关
redis:
# 地址
host: 192.168.5.232
host: localhost
# 端口默认为6379
port: 6379
# 数据库索引

View File

@ -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

View File

@ -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条数据

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.evo.ding.mapper.DingGroupMapper">
<resultMap type="DingGroup" id="DingGroupResult">
<result property="id" column="id" />
<result property="name" column="name" />
<result property="dingId" column="ding_Id" />
<result property="groupKey" column="group_key" />
</resultMap>
<sql id="selectVo">
select id, name, ding_Id, group_key from ding_group
</sql>
<select id="selectByDingId" resultMap="DingGroupResult">
<include refid="selectVo"/>
where ding_id = #{dingId}
</select>
</mapper>

View File

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.evo.ding.mapper.DingShiftGroupMapper">
<resultMap type="DingShiftGroup" id="DingShiftGroupResult">
<result property="id" column="id" />
<result property="num" column="num" />
<result property="name" column="name" />
<result property="image" column="image" />
<result property="delFlag" column="del_flag" />
<result property="remarks" column="remarks" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
</resultMap>
<sql id="selectVo">
select id, group_id, shift_id, type, check_time from ding_shift_group
</sql>
<select id="selectByGroupIdAndTypeAndCheckTime" resultMap="DingShiftGroupResult">
<include refid="selectVo"/>
where group_id =#{groupId} and shift_id = #{shiftId} and type = #{type} and check_time = #{checkTime}
</select>
<update id="updateCheckTimeByShiftIdAndType">
update ding_shift_group set check_time = #{checkTime} where shift_id=#{shiftId} and type = #{type}
</update>
<select id="selectListByShiftId" resultMap="DingShiftGroupResult">
select
dsg.id, dsg.group_id, dsg.shift_id, dsg.type, dsg.check_time,
ds.name as shiftName,
dg.name as groupName
from ding_shift_group dsg
left join ding_shift ds on ds.ding_id = dsg.shift_id
left join ding_group dg on dg.ding_id = dsg.group_id
<where>
dsg.shift_id = #{shiftId}
</where>
</select>
<!-- <select id="selectEqButtonList" parameterType="EqButton" resultMap="EqButtonResult">-->
<!-- <include refid="selectEqButtonVo"/>-->
<!-- <where>-->
<!-- del_flag = '0'-->
<!-- <if test="name != null and name != ''"> and name like concat('%', #{name}, '%')</if>-->
<!-- </where>-->
<!-- order by num asc-->
<!-- </select>-->
<!-- <select id="selectEqButtonById" parameterType="Long" resultMap="EqButtonResult">-->
<!-- <include refid="selectEqButtonVo"/>-->
<!-- where id = #{id}-->
<!-- </select>-->
<!-- <insert id="insertEqButton" parameterType="EqButton" useGeneratedKeys="true" keyProperty="id">-->
<!-- insert into eq_button-->
<!-- <trim prefix="(" suffix=")" suffixOverrides=",">-->
<!-- <if test="num != null">num,</if>-->
<!-- <if test="name != null">name,</if>-->
<!-- <if test="image != null">image,</if>-->
<!-- <if test="delFlag != null">del_flag,</if>-->
<!-- <if test="remarks != null">remarks,</if>-->
<!-- <if test="createBy != null">create_by,</if>-->
<!-- <if test="createTime != null">create_time,</if>-->
<!-- <if test="updateBy != null">update_by,</if>-->
<!-- <if test="updateTime != null">update_time,</if>-->
<!-- </trim>-->
<!-- <trim prefix="values (" suffix=")" suffixOverrides=",">-->
<!-- <if test="num != null">#{num},</if>-->
<!-- <if test="name != null">#{name},</if>-->
<!-- <if test="image != null">#{image},</if>-->
<!-- <if test="delFlag != null">#{delFlag},</if>-->
<!-- <if test="remarks != null">#{remarks},</if>-->
<!-- <if test="createBy != null">#{createBy},</if>-->
<!-- <if test="createTime != null">#{createTime},</if>-->
<!-- <if test="updateBy != null">#{updateBy},</if>-->
<!-- <if test="updateTime != null">#{updateTime},</if>-->
<!-- </trim>-->
<!-- </insert>-->
<!-- <update id="updateEqButton" parameterType="EqButton">-->
<!-- update eq_button-->
<!-- <trim prefix="SET" suffixOverrides=",">-->
<!-- <if test="num != null">num = #{num},</if>-->
<!-- <if test="name != null">name = #{name},</if>-->
<!-- <if test="image != null">image = #{image},</if>-->
<!-- <if test="delFlag != null">del_flag = #{delFlag},</if>-->
<!-- <if test="remarks != null">remarks = #{remarks},</if>-->
<!-- <if test="createBy != null">create_by = #{createBy},</if>-->
<!-- <if test="createTime != null">create_time = #{createTime},</if>-->
<!-- <if test="updateBy != null">update_by = #{updateBy},</if>-->
<!-- <if test="updateTime != null">update_time = #{updateTime},</if>-->
<!-- </trim>-->
<!-- where id = #{id}-->
<!-- </update>-->
<!-- &lt;!&ndash; 根据名称查询信息 &ndash;&gt;-->
<!-- <select id="selectEqButtonByName" parameterType="String" resultMap="EqButtonResult">-->
<!-- <include refid="selectEqButtonVo"/>-->
<!-- where del_flag = '0' and name = #{name}-->
<!-- </select>-->
</mapper>

View File

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.evo.ding.mapper.DingShiftMapper">
<resultMap type="DingShift" id="DingShiftResult">
<result property="id" column="id" />
<result property="name" column="name" />
<result property="dingId" column="ding_Id" />
<result property="workHour" column="work_Hour" />
</resultMap>
<sql id="selectVo">
select id, name, ding_Id, work_Hour, on_duty_check_time, off_duty_check_time from ding_shift
</sql>
<select id="selectByDingId" resultMap="DingShiftResult">
<include refid="selectVo"/>
where ding_id = #{dingId}
</select>
<select id="selectList" parameterType="com.evo.ding.domain.DingShift" resultMap="DingShiftResult">
<include refid="selectVo"/>
<where>
<if test="name != null and name != ''"> name like concat('%', #{name}, '%')</if>
</where>
</select>
<!-- <select id="selectEqButtonList" parameterType="EqButton" resultMap="EqButtonResult">-->
<!-- <include refid="selectEqButtonVo"/>-->
<!-- <where>-->
<!-- del_flag = '0'-->
<!-- <if test="name != null and name != ''"> and name like concat('%', #{name}, '%')</if>-->
<!-- </where>-->
<!-- order by num asc-->
<!-- </select>-->
<!-- <select id="selectEqButtonById" parameterType="Long" resultMap="EqButtonResult">-->
<!-- <include refid="selectEqButtonVo"/>-->
<!-- where id = #{id}-->
<!-- </select>-->
<!-- <insert id="insertEqButton" parameterType="EqButton" useGeneratedKeys="true" keyProperty="id">-->
<!-- insert into eq_button-->
<!-- <trim prefix="(" suffix=")" suffixOverrides=",">-->
<!-- <if test="num != null">num,</if>-->
<!-- <if test="name != null">name,</if>-->
<!-- <if test="image != null">image,</if>-->
<!-- <if test="delFlag != null">del_flag,</if>-->
<!-- <if test="remarks != null">remarks,</if>-->
<!-- <if test="createBy != null">create_by,</if>-->
<!-- <if test="createTime != null">create_time,</if>-->
<!-- <if test="updateBy != null">update_by,</if>-->
<!-- <if test="updateTime != null">update_time,</if>-->
<!-- </trim>-->
<!-- <trim prefix="values (" suffix=")" suffixOverrides=",">-->
<!-- <if test="num != null">#{num},</if>-->
<!-- <if test="name != null">#{name},</if>-->
<!-- <if test="image != null">#{image},</if>-->
<!-- <if test="delFlag != null">#{delFlag},</if>-->
<!-- <if test="remarks != null">#{remarks},</if>-->
<!-- <if test="createBy != null">#{createBy},</if>-->
<!-- <if test="createTime != null">#{createTime},</if>-->
<!-- <if test="updateBy != null">#{updateBy},</if>-->
<!-- <if test="updateTime != null">#{updateTime},</if>-->
<!-- </trim>-->
<!-- </insert>-->
<!-- <update id="updateEqButton" parameterType="EqButton">-->
<!-- update eq_button-->
<!-- <trim prefix="SET" suffixOverrides=",">-->
<!-- <if test="num != null">num = #{num},</if>-->
<!-- <if test="name != null">name = #{name},</if>-->
<!-- <if test="image != null">image = #{image},</if>-->
<!-- <if test="delFlag != null">del_flag = #{delFlag},</if>-->
<!-- <if test="remarks != null">remarks = #{remarks},</if>-->
<!-- <if test="createBy != null">create_by = #{createBy},</if>-->
<!-- <if test="createTime != null">create_time = #{createTime},</if>-->
<!-- <if test="updateBy != null">update_by = #{updateBy},</if>-->
<!-- <if test="updateTime != null">update_time = #{updateTime},</if>-->
<!-- </trim>-->
<!-- where id = #{id}-->
<!-- </update>-->
<!-- &lt;!&ndash; 根据名称查询信息 &ndash;&gt;-->
<!-- <select id="selectEqButtonByName" parameterType="String" resultMap="EqButtonResult">-->
<!-- <include refid="selectEqButtonVo"/>-->
<!-- where del_flag = '0' and name = #{name}-->
<!-- </select>-->
</mapper>

View File

@ -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
</sql>
<select id="selectRzSalaryDetailList" parameterType="RzSalaryDetail" resultMap="RzSalaryDetailResult">
<include refid="selectRzSalaryDetailVo"/>
<where>
del_flag = '0'
del_flag = '0' and type=#{type}
<if test="name != null and name != ''"> and name like concat('%', #{name}, '%')</if>
<if test="month != null "> and DATE_FORMAT( month, '%Y%m' ) = DATE_FORMAT( #{month} , '%Y%m' )</if>
<if test="deptId != null "> and dept_id = #{deptId}</if>
@ -136,7 +136,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="updateBy != null">update_by,</if>
<if test="updateTime != null">update_time,</if>
<if test="socialSecurityDeduction != null">social_security_deduction,</if>
<if test="type != null">type,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="staffId != null">#{staffId},</if>
@ -188,6 +188,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="updateBy != null">#{updateBy},</if>
<if test="updateTime != null">#{updateTime},</if>
<if test="socialSecurityDeduction != null">#{socialSecurityDeduction},</if>
<if test="type != null">#{type},</if>
</trim>
</insert>
@ -243,6 +244,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="updateBy != null">update_by = #{updateBy},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
<if test="socialSecurityDeduction != null">social_security_deduction = #{socialSecurityDeduction},</if>
<if test="type != null">type = #{type},</if>
</trim>
where id = #{id}
</update>
@ -266,4 +268,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<include refid="selectRzSalaryDetailVo"/>
where del_flag = '0' and DATE_FORMAT( month, '%Y%m' ) = DATE_FORMAT( #{date} , '%Y%m' ) and wb_flag = #{wbFlag} order by dept_id
</select>
<select id="selectMaxMonthBySysStallId" resultType="java.util.Date">
select max(rsd.month) from rz_salary_detail rsd where rsd.del_flag = '0' and rsd.type='1' and rsd.staff_id=#{staffId}
</select>
</mapper>

View File

@ -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')
</select>
<select id="selectRzLeaveDetailByProcessInstanceId" resultMap="RzLeaveDetailResult">
<include refid="selectRzLeaveDetailVo"/>
where del_flag = '0' and process_instance_id = #{processInstanceId} limit 1
</select>
</mapper>

View File

@ -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}
</select>
<select id="queryRzLeaveByUserId" resultMap="RzLeaveResult">
<include refid="selectRzLeaveVo"/>
where del_flag = '0' and user_id = #{userId} order by create_time desc limit 1
</select>
</mapper>

View File

@ -22,7 +22,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<sql id="selectDeptVo">
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.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.create_by, d.create_time, d.ding_id
from sys_dept d
</sql>
@ -100,6 +100,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="status != null">status,</if>
<if test="isOverTime != null">is_over_time,</if>
<if test="createBy != null and createBy != ''">create_by,</if>
<if test="dingId != null ">ding_id,</if>
create_time
)values(
<if test="deptId != null and deptId != 0">#{deptId},</if>
@ -111,6 +113,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="status != null">#{status},</if>
<if test="isOverTime != null">#{isOverTime},</if>
<if test="createBy != null and createBy != ''">#{createBy},</if>
<if test="dingId != null ">#{dingId},</if>
sysdate()
)
</insert>
@ -126,6 +129,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="status != null and status != ''">status = #{status},</if>
<if test="isOverTime != null">is_over_time = #{isOverTime},</if>
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
<if test="dingId != null ">ding_id = #{dingId},</if>
update_time = sysdate()
</set>
where dept_id = #{deptId}
@ -164,6 +168,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<include refid="selectDeptVo"/>
where dept_id not in (select parent_id from sys_dept) and del_flag = '0'
</select>
<select id="selectByDingDeptId" resultMap="SysDeptResult">
<include refid="selectDeptVo"/>
where ding_id =#{dingId}
</select>
<select id="selectByName" resultMap="SysDeptResult">
<include refid="selectDeptVo"/>
where dept_name =#{name} and del_flag = '0'
</select>
<!-- 根据部门ID递归查询其所有的子集 -->
<select id="queryDeptsByDeptId" parameterType="Long" resultMap="SysDeptResult">
WITH recursive dept AS (

View File

@ -50,6 +50,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="imageUrl" column="image_url" />
<result property="timeClock" column="time_clock" />
<result property="extended" column="extended" />
<result property="dingUserId" column="ding_user_id" />
<result property="source" column="source" />
<result property="dingUserId" column="ding_user_id" />
</resultMap>
<sql id="selectSysStaffVo">
@ -58,7 +62,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
quit_date, contract_start, contract_end, contract_type, social_type, seniority, is_overtime_pay,
zs_flag, secrecy, injury, insurance, introducer, clock_in, status,
wages_ratio_date, remarks, del_flag, create_by, create_time, update_by,
update_time, image_url,time_clock,subsidys, job_code, extended, openid
update_time, image_url,time_clock,subsidys, job_code, extended, openid, ding_user_id, source
from sys_staff
</sql>
@ -88,6 +92,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</where>
</select>
<select id="selectSysStaffByDingUserId" parameterType="String" resultMap="SysStaffResult">
<include refid="selectSysStaffVo"/>
where ding_user_id = #{dingUserId}
</select>
<select id="selectSysStaffByUserId" parameterType="Long" resultMap="SysStaffResult">
<include refid="selectSysStaffVo"/>
where user_id = #{userId}
@ -143,6 +152,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="jobCode != null">job_code,</if>
<if test="extended != null and extended != ''">extended,</if>
<if test="openid != null">openid,</if>
<if test="source != null">source,</if>
<if test="dingUserId != null">ding_user_id,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
@ -193,6 +204,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="jobCode != null">#{jobCode},</if>
<if test="extended != null and extended != ''">#{extended},</if>
<if test="openid != null">#{openid},</if>
<if test="source != null">#{source},</if>
<if test="dingUserId != null">#{dingUserId},</if>
</trim>
</insert>
@ -246,6 +259,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="jobCode != null">job_Code=#{jobCode},</if>
<if test="extended != null and extended != ''">extended=#{extended},</if>
<if test="openid != null">openid=#{openid},</if>
<if test="dingUserId != null">ding_user_id= #{dingUserId},</if>
</trim>
where user_id = #{userId}
</update>
@ -299,4 +313,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<include refid="selectSysStaffVo"/>
where del_flag = '0' and status != '-1' and dept_id = #{deptId} and is_leader='是' limit 1
</select>
<select id="getDingUserId" resultMap="SysStaffResult">
<include refid="selectSysStaffVo"/>
where (name=#{userName} or code = #{userName})
</select>
</mapper>