考勤改版调整
This commit is contained in:
parent
6c1c95352d
commit
2002d2a45b
@ -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));
|
||||
}
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
package com.evo.attendance.service;
|
||||
|
||||
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;
|
||||
@ -64,4 +66,8 @@ public interface IRzAttendanceService extends IService<RzAttendance>
|
||||
public void sendAbnormalAttendance();
|
||||
|
||||
public void dingDing(String dingUserId, String bizId);
|
||||
|
||||
void addRzOverTime(String result, SysStaff sysStaff, DingShiftGroup dingsShiftGroup, String checkType, Date formatWorkDate, Date formatUserCheckTime, String timeResult, String remark );
|
||||
|
||||
public RzAttendance queryNowDayAttendanceByStatisticalIdAndDate(Long staffId, Date date);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -16,13 +16,17 @@ 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.*;
|
||||
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.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;
|
||||
@ -55,6 +59,8 @@ public class RzAttendanceServiceImpl extends ServiceImpl<RzAttendanceMapper, RzA
|
||||
@Resource
|
||||
private ISysStaffService sysStaffService;
|
||||
@Resource
|
||||
private IRzOverTimeService rzOverTimeService;
|
||||
@Resource
|
||||
private IEqImagesService eqImagesService;
|
||||
@Resource
|
||||
private RzAttendanceDetailService rzAttendanceDetailService;
|
||||
@ -489,7 +495,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());
|
||||
|
||||
@ -524,7 +530,8 @@ public class RzAttendanceServiceImpl extends ServiceImpl<RzAttendanceMapper, RzA
|
||||
String result = DingUtils.getListRecord(Collections.asList(dingUserId), DateUtils.parseDateToStr("yyyy-MM-dd", new Date())+" 00:00:00", DateUtils.parseDateToStr("yyyy-MM-dd", new Date())+" 23:59:59");
|
||||
System.out.println("打卡结果===>"+result);
|
||||
JSONObject resultJson = JSON.parseObject(result);
|
||||
if(Integer.valueOf(0).equals(resultJson.getInteger("errcode"))) try {
|
||||
if(Integer.valueOf(0).equals(resultJson.getInteger("errcode")))
|
||||
try {
|
||||
{
|
||||
JSONArray jsonArray = resultJson.getJSONArray("recordresult");
|
||||
for (int i = 0; i < jsonArray.size(); i++) {
|
||||
@ -538,8 +545,6 @@ public class RzAttendanceServiceImpl extends ServiceImpl<RzAttendanceMapper, RzA
|
||||
Long planCheckTime = ob.getLong("planCheckTime");
|
||||
// 格式化:先转Date对象,再格式化
|
||||
String formatPlanCheckTime = DateUtils.parseDateToStr("HH:mm:ss", new Date(planCheckTime));
|
||||
DingShiftGroup dingsShiftGroup = dingsShiftGroupMapper.selectByGroupIdAndTypeAndCheckTime(groupId, checkType, formatPlanCheckTime);
|
||||
if(dingsShiftGroup != null){
|
||||
//用户打卡时间
|
||||
Long userCheckTime = ob.getLong("userCheckTime");
|
||||
//工作时间 (这里指的是哪一天的卡)
|
||||
@ -555,14 +560,36 @@ public class RzAttendanceServiceImpl extends ServiceImpl<RzAttendanceMapper, RzA
|
||||
*/
|
||||
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);
|
||||
|
||||
/* DingShiftGroup dingsShiftGroup = dingsShiftGroupMapper.selectByGroupIdAndTypeAndCheckTime(groupId, checkType, formatPlanCheckTime);
|
||||
if(dingsShiftGroup != null){
|
||||
//用户打卡时间
|
||||
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));
|
||||
|
||||
//通过打卡类型, classId, 和排班打卡时间, 获取工作时长
|
||||
//通过班次id拿到工作时长
|
||||
DingShift dingsShift = dingsShiftMapper.selectOne(new LambdaQueryWrapper<DingShift>().eq(DingShift::getDingId, dingsShiftGroup.getShiftId()));
|
||||
DingShift dingsShift = dingsShiftMapper.selectByDingId(dingsShiftGroup.getShiftId());
|
||||
//通过workDate 获取哪一天的卡
|
||||
RzAttendance attendance = getBaseMapper().queryNowDayAttendanceByStatisticalIdAndDate(sysStaff.getUserId(),formatWorkDate);
|
||||
RzAttendance attendance = queryNowDayAttendanceByStatisticalIdAndDate(sysStaff.getUserId(),formatWorkDate);
|
||||
//生成打卡记录
|
||||
rzAttendanceDetailService.addDetail(attendance, ("OnDuty".equals(checkType) ? "上班卡" : "下班卡"), "/", formatUserCheckTime, "钉钉打卡", "");
|
||||
//上班
|
||||
@ -599,12 +626,15 @@ public class RzAttendanceServiceImpl extends ServiceImpl<RzAttendanceMapper, RzA
|
||||
//检查是否开启加班
|
||||
if(dingsShift.getOvertimeWork()){
|
||||
//如果开启了加班
|
||||
Long hours = (userCheckTime - attendance.getWorkStartTime().getTime())/1000/60/60;
|
||||
new BigDecimal(hours).subtract(new BigDecimal(dingsShift.getWorkHour())).subtract(BigDecimal.valueOf(1)).subtract(new BigDecimal(String.valueOf(DataUtils.findDefaultValue(dingsShift.getDeductionHour(), 0))));
|
||||
// BigDecimal hours = new BigDecimal(((userCheckTime - attendance.getWorkStartTime().getTime())/1000/60/60)).subtract(new BigDecimal(dingsShift.getWorkHour())).subtract(BigDecimal.valueOf(1)).subtract(new BigDecimal(String.valueOf(DataUtils.findDefaultValue(dingsShift.getDeductionHour(), 0))));
|
||||
//使用排班下班时间作为加班开始时间
|
||||
rzOverTimeService.overTimeCard(sysStaff, DateUtils.parseDate(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", new Date(planCheckTime)), "yyyy-MM-dd HH:mm:ss"));
|
||||
//员工打卡时间作为加班下班时间
|
||||
rzOverTimeService.overTimeOffDutyCard(sysStaff, formatUserCheckTime, "/");
|
||||
}
|
||||
}else{
|
||||
log.info("未找到相关考勤班次数据, 疑似加班打卡=====>>>>> {}", result);
|
||||
}
|
||||
}*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -616,6 +646,64 @@ public class RzAttendanceServiceImpl extends ServiceImpl<RzAttendanceMapper, RzA
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRzOverTime(String result, SysStaff sysStaff, DingShiftGroup dingsShiftGroup, String checkType, Date formatWorkDate, Date formatUserCheckTime, String timeResult, String remark){
|
||||
if(dingsShiftGroup != null){
|
||||
//通过打卡类型, classId, 和排班打卡时间, 获取工作时长
|
||||
//通过班次id拿到工作时长
|
||||
DingShift dingsShift = dingsShiftMapper.selectByDingId(dingsShiftGroup.getShiftId());
|
||||
//通过workDate 获取哪一天的卡
|
||||
RzAttendance 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)){
|
||||
attendance.setWorkSum(BigDecimal.valueOf(dingsShift.getWorkHour()));
|
||||
}else{
|
||||
//早退需要计算工时
|
||||
Long hours = (attendance.getWorkEndTime().getTime() - attendance.getWorkStartTime().getTime())/1000/60/60;
|
||||
attendance.setWorkSum(BigDecimal.valueOf(hours));
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@Async
|
||||
protected void sendAbnormalAttendance(SysStaff sysStaff, Date date){
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,23 +1,21 @@
|
||||
package com.evo.common.controller;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.evo.attendance.processor.impl.KQDeviceExchangeProcessor;
|
||||
import com.evo.attendance.service.IRzAttendanceService;
|
||||
import com.evo.common.core.controller.BaseController;
|
||||
import com.evo.common.utils.StringUtils;
|
||||
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.scheduling.annotation.Async;
|
||||
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 javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -36,7 +34,10 @@ 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));
|
||||
@ -53,34 +54,52 @@ public class CallbackController extends BaseController {
|
||||
// 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)) {
|
||||
// 测试回调url的正确性
|
||||
log.info("测试回调url的正确性");
|
||||
} 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)) {
|
||||
|
||||
|
||||
// 处理通讯录用户增加事件
|
||||
}else if ("user_add_org".equals(eventType)) {
|
||||
// 处理通讯录用户增加事件
|
||||
log.info("发生了:" + eventType + "事件");
|
||||
|
||||
|
||||
} else {
|
||||
// 添加其他已注册的
|
||||
log.info("发生了:" + 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");
|
||||
|
||||
@ -215,6 +215,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);
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package com.evo.ding;
|
||||
|
||||
import com.aliyun.dingtalkoauth2_1_0.Client;
|
||||
import com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest;
|
||||
import com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenResponse;
|
||||
import com.aliyun.dingtalkworkflow_1_0.models.GetProcessInstanceResponseBody;
|
||||
@ -38,17 +37,23 @@ public class DingUtils {
|
||||
this.redisCache = redisCache;
|
||||
}
|
||||
|
||||
private static Client createClient() throws Exception {
|
||||
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";
|
||||
return new Client(config);
|
||||
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);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static String getAccessToken() throws Exception {
|
||||
String token = redisCache.getCacheObject(ACCESS_TOKEN_KEY);
|
||||
if(StringUtils.isEmpty(token)){
|
||||
Client client = createClient();
|
||||
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);
|
||||
@ -168,20 +173,15 @@ public class DingUtils {
|
||||
return "";
|
||||
}
|
||||
|
||||
public static com.aliyun.dingtalkworkflow_1_0.Client createClient1() throws Exception {
|
||||
com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config();
|
||||
config.protocol = "https";
|
||||
config.regionId = "central";
|
||||
return new com.aliyun.dingtalkworkflow_1_0.Client(config);
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* 获取审批详情
|
||||
* @param processInstanceId 审批示例id
|
||||
*/
|
||||
public static GetProcessInstanceResponseBody.GetProcessInstanceResponseBodyResult getProcessInstanceInfo(String processInstanceId) throws Exception {
|
||||
|
||||
com.aliyun.dingtalkworkflow_1_0.Client client = DingUtils.createClient1();
|
||||
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();
|
||||
@ -201,7 +201,30 @@ public class DingUtils {
|
||||
}
|
||||
|
||||
}
|
||||
} 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 "";
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.evo.ding.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
@ -16,6 +17,7 @@ import java.io.Serializable;
|
||||
public class DingShift implements Serializable {
|
||||
|
||||
/** 主键 */
|
||||
@TableId
|
||||
private Long id;
|
||||
/** 班次名称 */
|
||||
public String name;
|
||||
|
||||
@ -2,6 +2,8 @@ package com.evo.ding.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.evo.ding.domain.DingShift;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
/**
|
||||
* DingsShiftGroupMapper
|
||||
@ -13,5 +15,5 @@ import com.evo.ding.domain.DingShift;
|
||||
*/
|
||||
public interface DingShiftMapper extends BaseMapper<DingShift> {
|
||||
|
||||
|
||||
public DingShift selectByDingId(@Param("dingId") String dingId);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
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.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";
|
||||
|
||||
boolean accept(String approveType, String result, String status);
|
||||
|
||||
void exchange(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());
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,89 @@
|
||||
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.core.domain.entity.SysDictData;
|
||||
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.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(GetProcessInstanceResponseBody.GetProcessInstanceResponseBodyResult json) {
|
||||
try {
|
||||
SysStaff sysStaff = getSysStaffByDingUserId(json.getOriginatorUserId());
|
||||
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);
|
||||
rzLeaveDetail.setLeaveHour(extValueJson.getInteger("durationInHour"));
|
||||
rzLeaveDetail.setRemarks("钉钉"+tag);
|
||||
getIRzLeaveDetailService().insertRzLeaveDetail(rzLeaveDetail);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("执行钉钉 -[请假审批]-回调出现异常, 异常原因为:{}", e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,118 @@
|
||||
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 APPROVE_TYPE_OVERTIME.equals(approveType.toUpperCase()) && APPROVE_STATUS.equals(status.toUpperCase()) && APPROVE_RESULT.equals(result.toUpperCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void exchange(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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
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_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";
|
||||
|
||||
boolean accept(String eventType);
|
||||
|
||||
void exchange(JSONObject json);
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
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);
|
||||
for (AttendanceApproveStatusChangeExchangeProcessor processor : approveStatusChangeExchangeProcessorList) {
|
||||
if (processor.accept(json.getString("approveType"), result.getResult(), result.getStatus())) {
|
||||
processor.exchange(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,77 @@
|
||||
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.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"), checkType, formatPlanCheckTime);
|
||||
Date date= DateUtils.parseDate(bkTime, "yyyy-MM-dd HH:mm");
|
||||
//生成补卡记录信息
|
||||
getIRzAttendanceService().addRzOverTime(json.toString(), sysStaff, dingsShiftGroup, checkType, date, date, "/", "钉钉补卡-"+bkYi);
|
||||
}
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
log.info("补卡出现错误, 为在本地找到班次数据, 错误信息为:{}, 回调信息为: {}", e.getMessage(), json.toString());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
package com.evo.ding.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.evo.ding.domain.DingShiftGroup;
|
||||
|
||||
/**
|
||||
* 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 type, String checkTime);
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package com.evo.ding.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.evo.ding.domain.DingShift;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package com.evo.ding.service.impl;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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 type, String checkTime) {
|
||||
return getBaseMapper().selectByGroupIdAndTypeAndCheckTime(groupId, type, checkTime);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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>
|
||||
{
|
||||
/**
|
||||
* 查询加班详情
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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, "打卡成功");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -108,13 +108,18 @@ 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);
|
||||
}
|
||||
|
||||
@ -117,4 +117,9 @@ public class SysDictDataServiceImpl extends ServiceImpl<SysDictDataMapper, SysDi
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SysDictData> selectDictDataListByType(String type) {
|
||||
return getBaseMapper().selectDictDataByType(type);
|
||||
}
|
||||
}
|
||||
|
||||
@ -838,4 +838,9 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
86
evo-admin/src/main/resources/mapper/ding/DingShiftMapper.xml
Normal file
86
evo-admin/src/main/resources/mapper/ding/DingShiftMapper.xml
Normal file
@ -0,0 +1,86 @@
|
||||
<?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" />
|
||||
<result property="overtimeWork" column="overtime_Work" />
|
||||
<result property="deductionHour" column="deduction_Hour" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectVo">
|
||||
select id, name, ding_Id, work_Hour, overtime_Work, deduction_Hour from ding_shift
|
||||
</sql>
|
||||
|
||||
<select id="selectByDingId" resultMap="DingShiftResult">
|
||||
<include refid="selectVo"/>
|
||||
where ding_id = #{dingId}
|
||||
</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>-->
|
||||
<!-- <!– 根据名称查询信息 –>-->
|
||||
<!-- <select id="selectEqButtonByName" parameterType="String" resultMap="EqButtonResult">-->
|
||||
<!-- <include refid="selectEqButtonVo"/>-->
|
||||
<!-- where del_flag = '0' and name = #{name}-->
|
||||
<!-- </select>-->
|
||||
</mapper>
|
||||
@ -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>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user