commit
Some checks failed
API接口参数变更检测 / api-param-check (push) Has been cancelled

This commit is contained in:
2026-06-05 16:18:40 +08:00
parent 1ca34c6bb2
commit 3cba3bb74e
4393 changed files with 450030 additions and 103 deletions

View File

@@ -0,0 +1,91 @@
package jnpf.attendance.service;
import jnpf.exception.QueryException;
import jnpf.model.attendance.dto.*;
import jnpf.model.attendance.model.ClockUser;
import jnpf.model.attendance.vo.*;
import jnpf.model.attendance.vo.attendance.ClockInExportVo;
import jnpf.model.common.DateRangeDto;
import java.text.ParseException;
import java.util.List;
/**
* 统计服务
*
* @author shitou
* @date 2023/11/21
*/
public interface AppStatisticsService {
/**
* 获取我的考勤-主页
*
* @param req 筛选条件
* @return AppStatisticsListVo
*/
AppStatisticsListVo getAppHomeData(AppStatisticsListDto req) throws QueryException;
/**
* 获取我的考勤-出勤情况
*
* @param req 筛选条件
* @return List<AppStatisticsRecordVo>
*/
List<AppStatisticsRecordVo> getRecordData(AppStatisticsRecordDto req) throws Exception;
/**
* 获取我的考勤-更多统计-默认
*
* @param req 筛选条件
* @return AppStatisticsMoreVo
*/
AppStatisticsMoreVo getMoreDefaultData(AppStatisticsMoreDto req) throws Exception;
/**
* 获取我的考勤-更多统计-展开
*
* @param req 筛选条件
* @return AppStatisticsMoreInfoVo
*/
AppStatisticsMoreInfoVo getMoreExpandData(AppStatisticsMoreInfoDto req) throws Exception;
/**
* 获取团队考勤-首页
*
* @param req 筛选条件
* @return AppStatisticsTeamListVo
*/
AppStatisticsTeamListVo getTeamHomeData(AppStatisticsTeamListDto req) throws QueryException;
/**
* 获取团队考勤-tab列表数据
*
* @param req 筛选条件
* @return List<AppStatisticsTeamTabVo>
*/
List<AppStatisticsTeamTabVo> getTabListData(AppTeamStatisticsTabDto req);
/**
* 获取团队考勤-团队统计
*
* @param req 筛选条件
* @return AppTeamStatisticsVo
*/
AppTeamStatisticsVo getStatisticsData(AppTeamStatisticsDto req) throws ParseException;
/**
* 获取团队考勤-团队统计-详情列表
*
* @param req 筛选条件
* @return List<AppTeamStatisticsListVo>
*/
List<AppTeamStatisticsListVo> getStatisticsListData(AppTeamStatisticsListDto req) throws ParseException, QueryException;
/**
* 考勤组指定日期考勤打卡及时段
* @param usersByGroupVos 用户id集合
* @param tenantId 租户id
* @param dateRangeDto 日期范围
*/
List<ClockInExportVo> getDayClockInPageListExport(List<ClockInExportVo> usersByGroupVos, DateRangeDto dateRangeDto,String tenantId);
}

View File

@@ -0,0 +1,110 @@
package jnpf.attendance.service;
import jnpf.attendance.annotation.Machine;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.AttendanceMachineManage;
import jnpf.enums.attendance.ActionEnum;
import jnpf.enums.attendance.MachineEnum;
import jnpf.model.attendance.vo.attendance.UserTenantVo;
import jnpf.permission.model.user.PartUserInfoVo;
import java.util.List;
import java.util.Map;
/**
* 考勤机服务
*
* @author yanwenfu
* @create 2023-11-29
*/
public interface AttenceMachineService extends SuperService<AttendanceMachineManage> {
/**
* 发送用户到设备
* @param userId 用户id
* @param sn 设备号
* @param code 厂商编码
*/
void sendUserToMachine(String code, String userId, String sn);
/**
* 发送用户到设备
* @param user 用户信息
* @param sn 设备号
* @param code 厂商编码
*/
void sendUserToMachine(String code, PartUserInfoVo user, String sn);
/**
* 更新考勤机用户信息
* @param sn 设备号
* @param userId 用户id
* @param userName 用户名称
*/
void updateUserInfoByWebsocket(String sn, String userId, String userName);
/**
* 删除人员
* @param sn 设备号
* @param userId 用户id
*/
void deleteUser(String sn, String userId);
/**
* 批量删除人员
* @param sn 设备号
* @param userIds 用户ids
*/
void deleteUserList(String code, String sn, List<String> userIds);
/**
* 更新用户信息
* @param params 参数
* @return java.util.Map<java.lang.String, java.lang.Object>
*/
Map<String, Object> updateUserInfoPhoto(Map<String, Object> params);
/**
* 修改图片
* 此方法用于执行图片的修改操作它可能涉及从一个源获取图片数据,
* 应用一些转换或更新,并将修改后的图片保存回原始位置或新位置
* 具体的实现细节在这个方法内部,包括如何获取、修改和保存图片,
* 依赖于进一步的代码实现
*
* @return String 返回一个字符串可能包含修改后的图片的路径、URL或状态信息
*/
String changeImg();
/**
* 考勤机打卡
* @param sn 设备号
* @param userId 用户id
* @param tenantId 租户id
* java.lang.String
*/
String machineClockIn(String sn, String userId, String tenantId, String clockInId) throws Exception;
/**
* 打卡/更新打卡
* @param sn 设备号
* @param userId 用户id
* @param tenantId 租户id
* @return boolean 是否成功
*/
String clockIn(String sn, String userId, String tenantId);
/**
* 更新用户照片
* @param userId 用户id
* @param photoUrl 照片
*/
void updateKeMiPhoto(String userId, String photoUrl, String tenantId);
/**
* 科密考勤机打卡
* @param userTenant 用户租户信息
* @param devId 设备id
* @param tenantId 租户id
*/
void KeMiClockIn(UserTenantVo userTenant, String devId, String tenantId);
}

View File

@@ -0,0 +1,28 @@
package jnpf.attendance.service;
import jnpf.model.attendance.dto.AttendanceReqDto;
import jnpf.model.attendance.vo.attendance.ClockDataReqVo;
import jnpf.model.attendance.vo.attendance.OvertimeRuleVo;
/**
* 考勤ai服务
*
* @author yanwenfu
* @create 2026-05-07
*/
public interface AttendanceAIService {
/**
* 根据日期查询考勤打卡记录
* @param dto 查询条件
* @return jnpf.model.attendance.vo.attendance.ClockDataReqVo
*/
ClockDataReqVo getClockRecordByDate(AttendanceReqDto dto);
/**
* 查询考勤组加班规则
* @param groupId 考勤组id
* @return jnpf.model.attendance.vo.attendance.OvertimeRuleVo
*/
OvertimeRuleVo getOvertimeRule(String groupId);
}

View File

@@ -0,0 +1,18 @@
package jnpf.attendance.service;
import jnpf.model.attendance.dto.AttendanceApprovalSettingDto;
public interface AttendanceApprovalSettingService {
/**
* 修改考勤组审批配置
* @param attendanceApprovalSettingDto 修改参数
*/
void update(AttendanceApprovalSettingDto attendanceApprovalSettingDto);
/**
* 添加考勤组审批设置模版
* @param groupId 考勤组id
*/
void addTemplateSetting(String groupId);
}

View File

@@ -0,0 +1,337 @@
package jnpf.attendance.service;
import com.github.pagehelper.PageInfo;
import jnpf.base.ActionResult;
import jnpf.entity.attendance.AttendanceApprovalAdminVo;
import jnpf.exception.ApproveException;
import jnpf.exception.HandleException;
import jnpf.exception.WorkFlowException;
import jnpf.model.attendance.dto.*;
import jnpf.model.attendance.vo.*;
import jnpf.model.attendance.vo.attendance.AttendanceToThousandsFacesVo;
import jnpf.model.attendance.vo.attendance.LeaveConsumptionDetailVo;
import jnpf.model.doclibrary.vo.UseDetailVo;
import jnpf.model.workflow.dto.AttendanceBusinessTripApproveOaDto;
import jnpf.model.workflow.dto.AttendanceWorkOvertimeApproveDto;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
public interface AttendanceApproveService {
/**
* 劵使用记录
* @param id 劵id
* @param balanceQueryDto 参数
* @return com.github.pagehelper.PageInfo<jnpf.model.doclibrary.vo.UseDetailVo>
* @author hlp
*/
PageInfo<UseDetailVo> getUseDetail(String id, BalanceQueryDto balanceQueryDto);
/**
* 定时失效劵
* @param tenantId 租户id
* @return java.lang.Boolean
* @author hlp
*/
Boolean invalidationCoupons(String tenantId);
/**
* 加班--开始日期选择后触发接口返回当天及后一天的排班信息
* @param balanceQueryDto 参数
* @return java.util.List<jnpf.model.attendance.vo.UserClassesVo>
* @author hlp
*/
List<UserClassesVo> getClasses(BalanceQueryDto balanceQueryDto);
/**
* 获取加班期间的班次信息
* 此方法旨在根据查询条件获取员工在加班时间段内的班次信息,以便进行相应的考勤和工时计算
* 它通常用于处理加班申请、工时统计等场景,确保加班时间得到正确记录和处理
*
* @param balanceQueryDto 查询条件对象,包含需要查询的员工信息、时间范围等条件
* @return LeaveShiftVo 返回加班期间的班次信息对象包括班次时间、员工ID等关键信息
* @throws HandleException 当查询过程中发生错误时抛出此异常,调用者需要处理该异常
*/
LeaveShiftVo getWorkOverTimeShifts(BalanceQueryDto balanceQueryDto) throws HandleException;
/**
* 获取请假申请时长及设计班次(请假时选择了开始和结束时间后请求该接口)
* @param leaveQueryDto 参数
* @return jnpf.base.ActionResult<jnpf.model.attendance.vo.LeaveShiftVo>
* @author hlp
*/
LeaveShiftVo getLeaveDuration(LeaveQueryDto leaveQueryDto) throws HandleException;
/**
* 请假审批通过后的触发接口
* @param id 审批的唯一id
* @author hlp
*/
void leaveApprove(String id, Integer status, String tenantId, String userId, String userName) throws ApproveException;
/**
* 审核第二个任务项
* 该方法用于执行第二个任务项的检查操作,确保任务符合预期标准
*
* @param taskId 任务项的唯一标识符,用于指定需要检查的任务
* @throws HandleException 如果检查过程中遇到错误或异常情况,则抛出此异常
*/
void checkSeconded(String taskId) throws HandleException;
/**
* 检查工作任务项
* 该方法用于对工作任务项进行检查,以确保其符合既定的工作标准或流程
*
* @param taskId 工作任务项的唯一标识符,用于指定需要检查的任务
* @throws HandleException 如果检查过程中发现异常或错误,则抛出此异常
*/
void checkWork(String taskId) throws HandleException;
/**
* 借调审批
* 该方法用于获取借调审批的管理员信息
*
* @param groupId 组ID标识一个特定的组
* @param type 审批类型,用于区分不同的审批情况
* @return 返回一个包含审批管理员信息的对象
*/
AttendanceApprovalAdminVo getApproveUser(String groupId, Integer type);
/**
* 请假审批
* 该方法用于获取请假审批的管理员信息
*
* @param body 包含审批所需信息的字符串
* @return 返回一个包含审批管理员信息的对象
* @throws HandleException 当处理过程中遇到错误时抛出
* @throws WorkFlowException 当工作流执行过程中遇到错误时抛出
*/
AttendanceApprovalAdminVo getLeaveApproveUser(String body) throws HandleException, WorkFlowException;
/**
* 加班审批
* 该方法用于获取加班审批的管理员信息
*
* @param body 包含审批所需信息的字符串
* @return 返回一个包含审批管理员信息的对象
* @throws Exception 当审批过程中遇到任何错误时抛出
*/
AttendanceApprovalAdminVo getOvertimeApproveUser(String body) throws Exception;
/**
* 补卡审批
* 该方法用于获取补卡审批的管理员信息
*
* @param body 包含审批所需信息的字符串
* @return 返回一个包含审批管理员信息的对象
* @throws Exception 当审批过程中遇到任何错误时抛出
*/
AttendanceApprovalAdminVo getReplacementCardApproveUser(String body) throws Exception;
/**
* 考勤结果变更
* 该方法用于处理考勤结果的变更审批
*
* @param body 包含变更审批所需信息的字符串
* @return 返回一个包含审批管理员信息的对象
* @throws Exception 当审批过程中遇到任何错误时抛出
*/
AttendanceApprovalAdminVo getAttendanceAlter(String body) throws Exception;
/**
* 外勤审批
* 该方法用于获取外勤审批的管理员信息
*
* @return 返回一个包含审批管理员信息的对象
*/
AttendanceApprovalAdminVo getFieldApproval();
/**
* 借调审批
* 该方法用于获取借调审批的管理员列表
*
* @param body 包含审批所需信息的字符串
* @return 返回一个包含审批管理员ID的列表
* @throws Exception 当审批过程中遇到任何错误时抛出
*/
List<String> secondedApproval(String body) throws Exception;
/**
* 2.0已重构 选择了请假类型和请假时间后请求接口
* @param leaveQueryDto 参数
* @return jnpf.model.attendance.vo.UserBalanceVo
* @author hlp
*/
LeaveConsumptionDetailVo getResidueBalance(LeaveQueryDto leaveQueryDto) throws ParseException, HandleException, ApproveException;
/**
* 加班审批通过后请求接口
* @param id 审批的唯一id
* @param status 是否审核通过 0.待审核 2.未通过 1.通过
* @author hlp
*/
void workApprove(String id, Integer status, String tenantId, String userId, String userName) throws ApproveException;
/**
* 借调审批通过后的触发的接口
* @param id 审批的唯一id
* @param departureTime 离岗实际 2023-11-10 10:10
* @param backTime 回岗时间 2023-11-10 10:10
* @param status 是否审核通过 0.待审核 2.未通过 1.通过
* @param tenantId 租户id
* @author hlp
*/
void selfApprove(String id, String departureTime, String backTime, Integer status, String userId, String userName, String tenantId) throws ApproveException, HandleException;
/**
* 审批校验接口
* @param taskId 任务id
* @param type 类型 1.常规补卡审批 2.调整出勤结果审批 3.外勤审批 4.请假审批 5.加班审批 6.借调审批
* @return jnpf.base.ActionResult<java.lang.Object>
* @author hlp
*/
ActionResult<Object> getApprovalAdmin(String taskId, String type);
/**
* 提交时审批校验接口
* @param body 参数
* @param type 类型
*/
ActionResult<Object> submitValidation(String body, String type);
/**
* 提交检查工作的请求给OA系统
* 此方法用于将加班审批的信息提交到OA系统进行处理
*
* @param workOverTime 加班审批的详细信息,包含申请人、加班时间、理由等
* @throws HandleException 当提交过程中发生错误时抛出此异常
*/
void submitCheckWorkForOa(AttendanceWorkOvertimeApproveDto workOverTime) throws HandleException;
/**
* 获取考勤组管理员信息
* @param type 类型
* @param startTime 开始时间
* @param endTime 结束时间
* @return 考勤组管理员信息
*/
AttendanceApprovalAdminVo getGroupAdminInfo(Integer type, Date startTime, Date endTime, String clockInResultId, String selfGroupId) throws HandleException;
/**
* 获取考勤组用户余额
* @param groupId 考勤组
* @param month 年月2024-5-13
* @return jnpf.base.ActionResult<jnpf.model.attendance.vo.UserBalanceVo>
* @author hlp
*/
List<UserBalanceVo> getBalanceDetailS(String groupId, String month);
/**
* 修改外出审批状态
* @param applyId 主键Id
* @param status 是否审核通过 0.待审核 1.通过 2.未通过
*/
void goOutApprove(String applyId, Integer status, String tenantId, String userId, String userName) throws ApproveException;
/**
* 修改出差审批状态
* @param applyId 主键Id
* @param status 是否审核通过 0.待审核 1.通过 2.未通过
*/
void businessTripApprove(String applyId, Integer status, String tenantId, String userId, String userName) throws ApproveException;
/**
* 获取指定优惠余额
* @param userIds 用户id
* @return List<UserBalanceVo>
*/
List<UserBalanceVo> getUsersBalance(List<String> userIds);
/**
* 外出审批
*/
AttendanceApprovalAdminVo getGoOutApproval();
/**
* 出差审批
*/
AttendanceApprovalAdminVo getBusinessTripApproval();
/**
* 每月定时计算用户存休
* @param tenantId 租户id
* @return java.lang.Boolean
*/
Boolean storageRest(String tenantId);
/**
* 发消息通知下一节点审核人 发送Im消息
*/
void sendIm(WorkflowImQueryDto workflowImQueryDto);
/**
* 保存出差审批及校验
*/
ActionResult<Void> createBusinessTrip(AttendanceBusinessTripApproveOaDto approveOaDto);
/**
* 外出审批校验及保存
*/
ActionResult<Void> createGoOutForOa(GoOutApproveForOaDto dto);
/**
* 通过传入的开始结束时间及单位获取时长
*/
ActionResult<Void> getDurationForOa(DurationForOaDto dto);
/**
* 请假审批校验及保存
*/
ActionResult<Void> createLeaveForOa(LeaveApproveForOaDto dto);
/**
* 获取用户所选时间段所在考勤组
*/
ActionResult getUserGroupByTime(GroupOaDto groupOaDto);
/**
* 获取当前分组信息
* 此方法用于获取当前系统或用户所在的分组信息,用于界面展示或其他业务逻辑处理
*
* @return ActionResult 返回一个包含分组信息的操作结果对象
*/
ActionResult getNowGroup();
/**
* 获取出勤到千人面信息
* 此方法用于获取出勤记录中与千人面相关的数据,可能包括出勤时间、地点、人员等信息
*
* @return AttendanceToThousandsFacesVo 返回一个出勤到千人面信息对象,包含详细的出勤和千人面数据
*/
AttendanceToThousandsFacesVo attendanceToThousandsFaces();
/**
* v2.0.1 补丁版本请假审批未排班或休变为排班时触发扣劵的补偿逻辑
*/
void leaveCompensation(String applyId, String userId,String day, BigDecimal balance) throws ApproveException;
}

View File

@@ -0,0 +1,125 @@
package jnpf.attendance.service;
import cn.hutool.json.JSONArray;
import jnpf.base.UserInfo;
import jnpf.base.service.SuperService;
import jnpf.entity.AttendanceGroup;
import jnpf.entity.attendance.AttendanceBaseSetting;
import jnpf.exception.HandleException;
import jnpf.exception.QueryException;
import jnpf.model.attendance.dto.AttendanceBaseSettingDto;
import jnpf.model.attendance.vo.AttendanceBaseSettingVo;
import jnpf.model.attendance.vo.attendance.QuickCheckInVo;
import java.util.List;
import java.util.Map;
/**
* <p>
* 考勤基础设置表 服务类
* </p>
*
* @author ahua
* @since 2023-11-29
*/
public interface AttendanceBaseSettingService extends SuperService<AttendanceBaseSetting> {
/**
* 保存考勤基础设置信息。
*
* @param attendanceBaseSettingDto 考勤基础设置数据传输对象
* @throws HandleException 处理异常
*/
void save(AttendanceBaseSettingDto attendanceBaseSettingDto) throws HandleException;
void hisBaseSetting(Map<String, String> group2orgMap, Map<String, String> org2groupMap);
/**
* 根据考勤组ID获取单个考勤基础设置。
*
* @param groupId 考勤组ID
* @return 考勤基础设置视图对象
*/
AttendanceBaseSettingVo getOne(String groupId);
/**
* 更改考勤基础设置的启用状态。
*
* @param groupId 考勤组ID
* @param enable 启用状态0禁用1启用
* @param attendanceBaseSetting 考勤基础设置视图对象
*/
void changeStatus(String groupId, Integer enable, AttendanceBaseSettingVo attendanceBaseSetting);
/**
* 获取启用的考勤基础设置信息。
*
* @param groupIds 考勤组ID列表
* @return 启用的考勤基础设置映射
*/
Map<String, AttendanceBaseSetting> getEnableBaseSetting(List<String> groupIds);
/**
* 获取所有启用的考勤基础设置信息。
*
* @param groupIds 考勤组ID列表
* @return 所有启用的考勤基础设置映射
*/
Map<String, AttendanceBaseSetting> getEnableBaseSettingAll(List<String> groupIds);
/**
* 获取指定考勤组和考勤组视图列表的启用的考勤基础设置信息。
*
* @param groupIds 考勤组ID列表
* @param attendanceGroupVos 考勤组视图对象列表
* @return 启用的考勤基础设置映射
*/
Map<String, AttendanceBaseSetting> getEnableBaseSetting(List<String> groupIds, List<AttendanceGroup> attendanceGroupVos);
/**
* 初始化考勤基础设置。
*
* @param groupId 考勤组ID
*/
void initBaseSetting(String groupId);
/**
* 查找考勤基础设置信息。
*
* @param groupId 考勤组ID
* @return 考勤基础设置对象
*/
AttendanceBaseSetting findBaseSetting(String groupId);
/**
* 查询用户外勤是否必须拍照
* @param userInfo 用户信息
* @return cn.hutool.json.JSONArray
*/
JSONArray getTakePhotoSetting(UserInfo userInfo) throws QueryException;
/**
* 获取用户当前时间所处考勤组的内勤打卡基础设置
*/
Integer getNowGroupAttendancePhoto();
/**
* 获取用户当前时间所处考勤组是否能外勤打卡
* @param setting 考勤组配置
*/
boolean getFieldClockStatusSelf(AttendanceBaseSetting setting);
/**
* 获取用户当前时间所处考勤组是否能快速打卡
* 和用户当前所处考勤组的基础设置中的是否需要拍照是否需要人脸识别以及App个人设置中的上下班快速打开相关
*/
QuickCheckInVo quickCheckIn();
/**
* 获取用户当前时间所处考勤组是否能外勤打卡
* @param groupId 考勤组
*/
boolean getNeedFace(String groupId);
}

View File

@@ -0,0 +1,119 @@
package jnpf.attendance.service;
import com.github.pagehelper.PageInfo;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.AttendanceBookConfigEntity;
import jnpf.exception.HandleException;
import jnpf.model.attendance.dto.AttendanceBookConfigAddUserDto;
import jnpf.model.attendance.dto.AttendanceBookConfigDto;
import jnpf.model.attendance.dto.AttendanceBookConfigQueryDto;
import jnpf.model.attendance.dto.GetValidUsersDto;
import jnpf.model.attendance.vo.AttendanceBookConfigVo;
import jnpf.model.attendance.vo.AttendanceResultOptionGroupVo;
import jnpf.model.attendance.vo.AttendanceResultOptionVo;
import jnpf.model.attendance.vo.BookConfigCreatorVo;
import jnpf.model.attendance.vo.BookPersonnelVo;
import jnpf.permission.model.user.PartUserInfoVo;
import java.util.List;
/**
* 考勤本配置服务接口
*
* @author Generated
* @create 2026-04-15
*/
public interface AttendanceBookConfigService extends SuperService<AttendanceBookConfigEntity> {
/**
* 新增或更新考勤本配置
* <p>根据DTO中的id判断id为空则新增id不为空则更新</p>
*
* @param configDto 考勤本配置DTO
* @throws HandleException 业务异常
*/
void saveOrUpdateAttendanceBookConfig(AttendanceBookConfigDto configDto) throws HandleException;
/**
* 删除考勤本配置
*
* @param id 考勤本ID
*/
void deleteAttendanceBookConfig(String id);
/**
* 更新启用状态
*
* @param id 考勤本ID
* @throws HandleException 业务异常
*/
void updateEnableStatus(String id) throws HandleException;
/**
* 获取考勤本配置详情
*
* @param id 考勤本ID
* @return 考勤本配置VO
*/
AttendanceBookConfigVo getDetail(String id);
/**
* 分页查询考勤本配置列表
*
* @param queryDto 查询条件
* @return 分页结果
*/
PageInfo<AttendanceBookConfigVo> getPageList(AttendanceBookConfigQueryDto queryDto);
/**
* 增量添加使用范围人员
* <p>向指定考勤本配置的使用范围中增量添加用户列表</p>
*
* @param addUserDto 添加用户DTO
* @throws HandleException 业务异常
*/
void addScopeUsers(AttendanceBookConfigAddUserDto addUserDto) throws HandleException;
/**
* 判断当前登录人是否为考勤本负责人
*
* @param bookConfigId 考勤本配置ID
* @return true-是负责人false-不是负责人
* @throws HandleException 业务异常
*/
boolean isCurrentUserManager(String bookConfigId) throws HandleException;
/**
* 获取指定组织集合及用户集合在当前时间下的所有涉及用户
* <p>查询这些组织和用户在当前时间的有效用户集合,返回完整的用户信息列表</p>
*
* @param dto 查询参数组织ID列表、用户ID列表
* @return 有效用户信息列表
*/
List<PartUserInfoVo> getValidUsers(GetValidUsersDto dto);
/**
* app-获取考勤结果下拉列表(分组返回)
* <p>根据考勤本配置返回可用的考勤状态选项,包括基础考勤状态、外勤结果和该考勤本配置的请假类型</p>
*
* @param bookConfigId 考勤本配置ID
* @return 考勤结果选项分组(考勤结果、外勤结果、假期类型)
* @throws HandleException 业务异常
*/
AttendanceResultOptionGroupVo getAttendanceResultOptions(String bookConfigId) throws HandleException;
/**
* 需求2获取考勤本配置创建人列表
*
* @return 创建人列表
*/
List<BookConfigCreatorVo> getCreatorList();
/**
* 需求3获取考勤本配置人员列表
*
* @param bookConfigId 考勤本配置ID
* @return 人员列表
*/
List<BookPersonnelVo> getBookPersonnelList(String bookConfigId,String month);
}

View File

@@ -0,0 +1,31 @@
package jnpf.attendance.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import jnpf.entity.attendance.AttendanceBookOperationLogEntity;
import jnpf.model.attendance.dto.OperationLogQueryDto;
import jnpf.model.attendance.vo.OperationLogPageVo;
/**
* 考勤本操作日志Service
*
* @author Generated
* @create 2026-04-15
*/
public interface AttendanceBookOperationLogService extends IService<AttendanceBookOperationLogEntity> {
/**
* 记录操作日志
*
* @param entity 操作日志实体
*/
void saveLog(AttendanceBookOperationLogEntity entity);
/**
* 分页查询操作日志
*
* @param queryDto 查询参数
* @return 分页结果
*/
Page<OperationLogPageVo> queryPage(OperationLogQueryDto queryDto);
}

View File

@@ -0,0 +1,106 @@
package jnpf.attendance.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.github.pagehelper.PageInfo;
import jnpf.entity.attendance.AttendanceBookRecordEntity;
import jnpf.model.attendance.dto.AttendanceBookRecordDto;
import jnpf.model.attendance.dto.BatchAttendanceBookRecordDto;
import jnpf.model.attendance.dto.BookRecordDayListDto;
import jnpf.model.attendance.dto.BookRecordMonthListDto;
import jnpf.model.attendance.dto.BookRecordMonthStatisticsDto;
import jnpf.model.attendance.dto.LeaveRemarkSummaryDto;
import jnpf.model.attendance.dto.SchedulesImportDto;
import jnpf.model.attendance.vo.BatchOperationResultVo;
import jnpf.model.attendance.vo.BookRecordDayListVo;
import jnpf.model.attendance.vo.BookRecordMonthListVo;
import jnpf.model.attendance.vo.BookRecordMonthStatisticsVo;
import jnpf.model.attendance.vo.LeaveRemarkSummaryVo;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/**
* 考勤本记录表Service
*
* @author Generated
* @create 2026-04-15
*/
public interface AttendanceBookRecordService extends IService<AttendanceBookRecordEntity> {
/**
* 新增或修改考勤记录Upsert
* 根据考勤本ID、员工ID、考勤日期、时段类型唯一确定一条记录
* 如果记录存在则更新,不存在则新增
*
* @param dto 考勤记录DTO
* @return 记录ID
*/
String saveOrUpdateRecord(AttendanceBookRecordDto dto);
/**
* 获取考勤本月统计数据
*
* @param req 统计请求参数
* @return 本月统计结果(按员工维度,支持分页)
*/
PageInfo<BookRecordMonthStatisticsVo> getMonthStatistics(BookRecordMonthStatisticsDto req);
/**
* 考勤本导入
*
* @param importDto 导入参数
* @throws IOException IO异常
*/
void bookRecordImport(SchedulesImportDto importDto) throws IOException;
/**
* 考勤本导出
*
* @param bookId 考勤本ID
* @param month 月份格式yyyy-MM
*/
void bookRecordExport(String bookId, String month);
/**
* 导出考勤本模板(只有表头,无数据)
*
* @param bookId 考勤本ID
* @param month 月份格式yyyy-MM
*/
void exportTemplate(String bookId, String month, HttpServletResponse response);
/**
* 获取日考勤本列表
* <p>根据考勤本的使用范围获取人员列表,展示指定日期的考勤记录</p>
*
* @param req 查询参数
* @return 日考勤本列表(按员工分组)
*/
List<BookRecordDayListVo> getDayList(BookRecordDayListDto req);
/**
* 获取月考勤本列表
* <p>根据考勤本的使用范围获取人员列表,展示该月所有日期的考勤记录</p>
*
* @param req 查询参数
* @return 月考勤本列表(按员工分组)
*/
List<BookRecordMonthListVo> getMonthList(BookRecordMonthListDto req);
/**
* 需求10批量新增或修改考勤记录
*
* @param dto 批量考勤记录DTO
* @return 批量操作结果
*/
BatchOperationResultVo batchSaveOrUpdateRecord(BatchAttendanceBookRecordDto dto);
/**
* 需求6获取假勤汇总信息包含请假备注和考勤统计
*
* @param dto 统计请求参数
* @return 假勤汇总信息
*/
LeaveRemarkSummaryVo getLeaveAttendanceSummary(LeaveRemarkSummaryDto dto);
}

View File

@@ -0,0 +1,58 @@
package jnpf.attendance.service;
import jnpf.base.UserInfo;
import jnpf.entity.attendance.AttendanceResultRollback;
import jnpf.model.attendance.dto.NoApprovalDto;
import jnpf.model.attendance.vo.ChangeInfoVo;
import java.util.List;
/**
* 考勤变更服务
*
* @author yanwenfu
* @create 2024-11-08
*/
public interface AttendanceChangeService {
/**
* 被变更记录的信息
* @param clockInResultId 结果id
* @return jnpf.model.attendance.vo.ChangeInfoVo
*/
ChangeInfoVo getChangeInfo(String clockInResultId) throws Exception;
/**
* 根据考勤组id及用户id查询过去一年内的变更涉及打卡记录
* @param groupId 考勤组id
* @param userId 用户id
* @return java.util.List<jnpf.model.attendance.vo.ChangeInfoVo>
*/
List<ChangeInfoVo> getChangeInfoList(String groupId, String userId);
/**
* 出勤变更(无需审批)
* @param noApprovalDto 出勤变更参数
*/
void attendanceChangeNoApproval(NoApprovalDto noApprovalDto) throws Exception;
/**
* 出勤变更(需审批)
* @param taskId 审批id
* @param passed 是否通过(0: 否, 1: 是, 2: 撤回)
* @param user 审批人
*/
void attendanceChangeApproval(String taskId, String passed, UserInfo user) throws Exception;
/**
* 出勤变更撤回
* @param clockInResultId 打卡结果id
*/
void rollbackChange(String clockInResultId) throws Exception;
/**
* 查询能否撤回变更
* @param clockInResultId 打卡结果id
* @return java.lang.Integer
*/
Integer getRollbackStatus(String clockInResultId);
}

View File

@@ -0,0 +1,31 @@
package jnpf.attendance.service;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.AttendanceClockInPic;
import jnpf.model.attendance.vo.ClockInPicVo;
import java.util.List;
import java.util.Map;
/**
* 外勤打卡图片服务
*
* @author yanwenfu
* @create 2023-11-21
*/
public interface AttendanceClockInPicService extends SuperService<AttendanceClockInPic> {
/**
* 查询打卡记录的拍照图片集合
*
* @param ids 打卡记录ID
* @return 返回外勤打卡图片集合(键值对)
*/
Map<String, List<AttendanceClockInPic>> getClockInPicByIds(List<String> ids, List<String> appIds);
/**
* 查询外勤打卡图片列表
* @param clockInId 打卡ID
* @return 返回外勤打卡图片集合
*/
List<ClockInPicVo> getClockInPicList(String clockInId);
}

View File

@@ -0,0 +1,29 @@
package jnpf.attendance.service;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.AttendanceClockInResult;
import jnpf.model.attendance.vo.UserDayVo;
import java.util.List;
import java.util.Map;
/**
* 打卡结果服务
*
* @author yanwenfu
* @create 2023-11-29
*/
public interface AttendanceClockInResultService extends SuperService<AttendanceClockInResult> {
/**
* 打卡重新匹配数据库处理
* @param resultList 生成的打卡结果
* @param userDayList 用户日期vo
* @param updateUserId 更新人
*/
void dbMatchDeal(String requestId, List<AttendanceClockInResult> resultList, List<UserDayVo> userDayList, String updateUserId);
void updateOldResultChangeList(Map<String, AttendanceClockInResult> map);
void updateOldResultRepairList(Map<String, AttendanceClockInResult> map);
}

View File

@@ -0,0 +1,306 @@
package jnpf.attendance.service;
import jnpf.base.UserInfo;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.AttendanceClockInResult;
import jnpf.entity.attendance.FtbAttendanceClockIn;
import jnpf.entity.attendance.FtbAttendanceDailyRule;
import jnpf.exception.HandleException;
import jnpf.exception.QueryException;
import jnpf.model.attendance.dto.ClockInDto;
import jnpf.model.attendance.model.DayClockRange;
import jnpf.model.attendance.vo.*;
import jnpf.model.attendance.vo.attendance.ClockInExportVo;
import jnpf.model.common.DateRangeDto;
import org.apache.commons.lang3.tuple.MutablePair;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
/**
* 打卡服务
*
* @author yanwenfu
* @create 2023-11-21
*/
public interface AttendanceClockInService extends SuperService<FtbAttendanceClockIn> {
/**
* 打卡 - 主页
* @param today 日期
* @param userInfo 用户信息
* @param isMainInfo 是否打卡主页(1: 是, 0: 否)
* @return java.util.List<jnpf.model.attendance.vo.GroupInfoVo>
*/
List<GroupInfoVo> getClockInMainInfo(Date today, UserInfo userInfo, Integer isMainInfo) throws Exception;
/**
* 打卡
*
* @param clockInDto 打卡信息
* @return org.apache.commons.lang3.tuple.MutablePair <br> left:打卡结果状态, right:打卡结果id
*/
MutablePair<Integer, String> clockIn(ClockInDto clockInDto) throws Exception;
/**
* 更新打卡记录
* @param clockInDto 更新内容
* @param clockInId 打卡记录id
* @return org.apache.commons.lang3.tuple.MutablePair <br> left:打卡结果状态, right:打卡结果id
*/
MutablePair<Integer, String> updateClockIn(String clockInId, ClockInDto clockInDto) throws Exception;
/**
* 判断本次是否外出打卡
* @param rule 考勤规则
* @param clockInType 上/下班打卡
* @return boolean
*/
boolean getOutsideCheck(AttendanceRuleVo rule, Integer clockInType);
/**
* 变更出勤规则[批量]
* @param userDayList 用户日期列表
* @param user 操作人
*/
void changeAttendanceRuleBatch(List<UserDayVo> userDayList, UserInfo user);
/**
* 查询出勤规则
* @param ruleId 出勤规则id
* @return jnpf.model.attendance.vo.AttendanceRuleVo
*/
AttendanceRuleVo getAttendanceRule(String ruleId) throws HandleException;
/**
* 查询出勤规则[批量]
* @param ruleIds 出勤规则ids
* @return java.util.Map<java.lang.String,jnpf.model.attendance.vo.AttendanceRuleVo>
*/
Map<String, AttendanceRuleVo> getAttendanceRuleBatch(List<String> ruleIds);
/**
* 查询考勤组信息
* @param today 日期
* @param groupId 考勤组id
* @param selfGroupInt 是否自己的考勤组
* @param userInfo 当前登陆用户
* @return jnpf.model.attendance.vo.GroupInfoVo
*/
GroupInfoVo getGroupInfo(Date today, String groupId, int selfGroupInt, UserInfo userInfo) throws QueryException;
/**
* 查询考勤组信息
* @param today 日期
* @param groupId 考勤组id
* @param selfGroupInt 是否自己的考勤组
* @param userInfo 当前登陆用户
* @param isMainInfo 是否主页进入
* @return jnpf.model.attendance.vo.GroupInfoVo
*/
GroupInfoVo getGroupInfo(Date today, String groupId, int selfGroupInt, UserInfo userInfo, Integer isMainInfo) throws QueryException;
/**
* 查询考勤组出勤规则
* @param groupId 考勤组id
* @param userId 用户id
* @return jnpf.model.attendance.vo.GroupRuleVo
*/
GroupRuleVo getGroupRule(String groupId, String userId);
/**
* 能否补卡
* @param day 日期
* @param clockInResult 出勤结果
* @param approvalStatus 审批状态
* @param groupRule 考勤组规则
* @return org.apache.commons.lang3.tuple.MutablePair<java.util.Date, java.util.Date>
*/
MutablePair<Date, Date> couldRepairRecord(Date day, AttendanceClockInResult clockInResult, Integer approvalStatus, GroupRuleVo groupRule) throws Exception;
/**
* 根据日期查询考勤组信息
* @param today 日期
* @param userInfo 当前登陆用户
* @return jnpf.model.attendance.vo.GroupInfoVo
*/
GroupInfoVo getGroupInfoByDate(Date today, UserInfo userInfo) throws QueryException;
/**
* 外勤打卡
* @param approvalCode 审批code
* @param tenantId 租户id
* @param clockInId 打卡id
*/
void outsideClockIn(String approvalCode, String tenantId, String clockInId) throws Exception;
/**
* 外勤打卡审批(通过/不通过/撤回)
* @param applyId 审批id
* @param passed 是否通过(0: 否, 1: 是, 2: 撤回)
* @param userInfo 当前登录人
*/
void approvalOutsideClockIn(String applyId, String passed, UserInfo userInfo) throws Exception;
/**
* 异常打卡审批(通过/不通过/撤回)
* @param applyId 审批id
* @param passed 是否通过(0: 否, 1: 是, 2: 撤回)
* @param userInfo 当前登录人
*/
void approvalUnusualPhoneClockIn(String applyId, String passed, UserInfo userInfo) throws Exception;
/**
* 补卡
* @param applyId 审批id
* @param passed 是否通过(0: 否, 1: 是, 2: 撤回)
* @param tenantId 租户ID
*/
void repairClockIn(String applyId, String passed, String approveUserId, String tenantId) throws Exception;
/**
* 执行缺卡逻辑
* @param tenantId 租户id
* @return java.lang.Boolean
*/
Boolean generateFtbAbsenceRecord(String tenantId);
/**
* 生成上班前打卡提醒
* @param tenantId 租户id
* @return java.lang.Boolean
*/
Boolean generateBeforeWorkRemind(String tenantId);
/**
* 异步处理缺卡
* @param tenantId 租户id
* @param conditionList 需要执行的任务
* @param now 当前时间
*/
CompletableFuture<Void> asyncDeal(String tenantId, String hashKey, List<AbsenceClockInVo> conditionList, String now);
/**
* 可选择的补卡列表
* @param userId 用户id
* @return java.util.List<jnpf.model.attendance.vo.GroupRepairVo>
*/
List<GroupRepairVo> getRepairList(String userId) throws Exception;
/**
* 查询每日出勤及打卡记录
* @param userId 用户id
* @param queryDate 查询日期
* @param currentGroupId 当前考勤组
* @return java.util.List<jnpf.model.attendance.vo.MiniGroupVo>
*/
List<MiniGroupVo> getDailyClockInRecord(String userId, String queryDate, String currentGroupId);
/**
* 出勤变更
* @param applyId 申请id
* @param passed 是否通过(0: 否, 1: 是, 2: 撤回)
* @param approveUserId 审批人id
* @param tenantId 租户ID
*/
void attendanceChange(String applyId, String passed, String approveUserId, String tenantId) throws HandleException;
/**
* 出勤变更(不审批)
* @param clockInResultId 打卡结果id
* @param changeType 变更类型(1: 变更为旷工, 2: 撤销旷工, 3: 变更为正常, 4: 补卡)
*/
void attendanceChangeNoApproval(String clockInResultId, Integer changeType) throws HandleException;
/**
* 查询每日出勤及打卡记录 - v2
* @param userId 用户id
* @param queryDate 查询日期
* @param currentGroupId 当前考勤组id
* @param queryOldData 查看原始数据(1: 是, 0: 否)
* @return jnpf.model.attendance.vo.DailyInfoVo
*/
DailyInfoVo getDailyClockInRecordV2(String userId, String queryDate, String currentGroupId, Integer queryOldData) throws QueryException;
/**
* 获取班次时间
* @param rule 出勤规则
* @param workStatus 上/下班
* @return java.lang.String
*/
String getShiftTimeStr(FtbAttendanceDailyRule rule, int workStatus);
/**
* 生成补卡次数
* @return java.lang.Boolean
*/
Boolean generateRepairNum();
/**
* 生成用户补卡次数记录
* @param groupId 考勤组id
* @param userId 用户id
* @param generateType 生成类型(1: 新增组成员, 2: 借调到新组)
* @return java.lang.Boolean
*/
Boolean generateRepairNumForUser(String groupId, String userId, Integer generateType);
/**
* 判断考勤组是否可以补卡
* @param groupId 考勤组id
* @return jnpf.model.attendance.vo.RepairRuleVo
*/
RepairRuleVo getClockInRepairCheck(String groupId);
/**
* 生成全面维修编号
* 本方法旨在生成一个全面的维修编号,该编号用于唯一标识一次维修事件或记录
* 它可能涉及到复杂的逻辑,如数据库查询、序列生成或其他策略,以确保编号的唯一性和连续性
*
* @return Boolean 表示维修编号是否成功生成true表示成功false表示失败
*/
Boolean generateRepairNumAll();
/**
* 查询每日出勤及打卡记录
* @param userId 用户id
* @param clockRecord 查询日期范围
*/
List<FtbAttendanceClockIn> getDailyClockInRecord(String userId, DayClockRange clockRecord);
/**
* 判定连续动作(排班/旷工)
* @param tenantId 租户id
* @return java.lang.Boolean
*/
Boolean continuousCheck(String tenantId);
/**
* 获取当前考勤组排班
* @param today 日期
* @param userInfo 日期
*/
List<FtbAttendanceDailyRule> getCurrentDailyRuleListOfWithdraw(Date today, UserInfo userInfo);
/**
* 获取当前时间段内考勤组排班
*/
List<FtbAttendanceDailyRule> getCurrentDailyRuleListOfDay(DateRangeDto dateRangeDto, List<ClockInExportVo> usersByGroupVos);
/**
* 生成打卡旷工任务
* @param flag 是否删除redisKey重新生成(1: 是, 0: 否)
* @param tenantId 租户id
* @return java.lang.Boolean
*/
Boolean generateAbsenceTask(Integer flag, String tenantId);
/**
* 查询考勤组审批列表
* @param queryDto 查询条件
* @return java.util.List<jnpf.model.attendance.vo.GroupApprovalVo>
*/
List<GroupApprovalVo> getGroupApprovalList(ApprovalQueryDto queryDto);
}

View File

@@ -0,0 +1,30 @@
package jnpf.attendance.service;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.AttendanceCloudAlbum;
import java.util.List;
/**
* @Description: 考勤云相册
* @Author: shiTou(他是小石头)
* @Date: 2024-10-30 10:26
*/
public interface AttendanceCloudAlbumService extends SuperService<AttendanceCloudAlbum> {
/**
* 查询云相册列表
*
* @return List<String>
*/
List<String> getDataList();
/**
* 保存云相册
*/
void batchSave(List<String> picUrlList);
/**
* 获取登录用户水印
*/
String getUserWatermark();
}

View File

@@ -0,0 +1,14 @@
package jnpf.attendance.service;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.AttendanceConfirmDetails;
/**
* 考勤确认详情
*
* @author shitou
* @email shitou@niujiekeji.com
* @date 2024-11-07 09:33:43
*/
public interface AttendanceConfirmDetailsService extends SuperService<AttendanceConfirmDetails> {
}

View File

@@ -0,0 +1,116 @@
package jnpf.attendance.service;
import com.github.pagehelper.PageInfo;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.AttendanceConfirm;
import jnpf.model.attendance.dto.ConfirmPageListDto;
import jnpf.model.attendance.dto.ConfirmStatisticsDto;
import jnpf.model.attendance.vo.attendance.ConfirmDetailsVo;
import jnpf.model.attendance.vo.attendance.ConfirmPageListVo;
import jnpf.model.attendance.vo.attendance.ConfirmStatisticsVo;
import jnpf.model.thousandsfaces.TodayWorkVo;
import java.util.Date;
import java.util.List;
/**
* 考勤确认
*
* @author shitou
* @email shitou@niujiekeji.com
* @date 2024-11-07 09:33:43
*/
public interface AttendanceConfirmService extends SuperService<AttendanceConfirm> {
/**
* 获取考勤确认默认月份
*
* @return 月份
*/
String getConfirmMonth();
/**
* 考勤确认列表展示
*
* @param dto 筛选条件
* @return 考勤确认列表
*/
PageInfo<ConfirmPageListVo> getPageList(ConfirmPageListDto dto);
/**
* 考勤确认聚合统计
*
* @param dto 筛选条件
* @return 考勤确认列表
*/
ConfirmStatisticsVo getStatistics(ConfirmStatisticsDto dto);
/**
* 考勤确认详情
*
* @param id 确认ID
* @return 考勤确认详情
*/
ConfirmDetailsVo getConfirmDetails(String id);
/**
* 获取App考勤确认详情
*
* @return 考勤确认详情
*/
ConfirmDetailsVo getAppConfirmDetails(String id);
/**
* 自动生成考勤确认数据
*
* @return 生成是否成功
*/
boolean autoCreateConfirm();
/**
* 生成考勤确认数据
*
* @param year 年份
* @param month 月份
* @param startTime 开始时间
* @param slippageResult 逾期是否自动确认
*/
void createConfirm(int year, int month, Date expectedTime, Date startTime, Integer slippageResult);
/**
* 逾期自动确认
*
* @return 逾期自动确认是否成功
*/
boolean confirmAutoSlippage();
/**
* 温馨提示关闭
*
* @param id 考勤确认id
* @return 关闭结果
*/
Boolean tipsClos(String id);
/**
* 温馨提示关闭
*
* @param id 考勤确认id
* @return 关闭结果
*/
Boolean confirmDetailsSubmit(String id);
/**
* App已查看
*
* @param id 考勤确认id
* @return 关闭结果
*/
Boolean look(String id);
/**
* 今日工作-考勤确认列表(0-待确认 1-已确认 2-已逾期)
*
* @return 考勤确认列表
*/
List<TodayWorkVo> getTodayWorkConfirmList();
}

View File

@@ -0,0 +1,31 @@
package jnpf.attendance.service;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.AttendanceConfirmSetting;
import jnpf.model.attendance.dto.ConfirmSettingSubmitDto;
import jnpf.model.attendance.vo.attendance.ConfirmSettingInfoVo;
/**
* 考勤确认设置
*
* @author shitou
* @email shitou@niujiekeji.com
* @date 2024-11-07 09:33:43
*/
public interface AttendanceConfirmSettingService extends SuperService<AttendanceConfirmSetting> {
/**
* 获取考勤确认设置
* @param isNew 是否获取最新配置
* @return 勤确认设置
*/
ConfirmSettingInfoVo getConfirmSetting(Boolean isNew);
/**
* 考勤确认设置提交
*
* @param dto 确认ID
* @return 考勤确认设置提交结果
*/
Boolean confirmSettingSubmit(ConfirmSettingSubmitDto dto);
}

View File

@@ -0,0 +1,35 @@
package jnpf.attendance.service;
import jnpf.base.service.SuperService;
import jnpf.entity.AttendanceCustomizeTable;
import jnpf.model.attendance.vo.attendance.AttendanceCustomizeTableVo;
import jnpf.model.attendance.vo.attendance.CustomizeTableUpdateVo;
import java.util.List;
/**
* <p>
* 考勤-自定义报表设置 服务类
* </p>
*
* @author ahua
* @since 2024-09-03
*/
public interface AttendanceCustomizeTableService extends SuperService<AttendanceCustomizeTable> {
/**
* 根据关键词、状态和类型查询自定义表格列表。
*
* @param keyword 关键词,用于搜索过滤
* @param status 状态,用于筛选设置
* @param type 类型,用于筛选设置
* @return 自定义表格视图对象列表
*/
List<AttendanceCustomizeTableVo> findList(String keyword, Integer status, Integer type);
/**
* 更新自定义表格信息。
*
* @param tableVos 自定义表格数据传输对象列表
*/
void update(CustomizeTableUpdateVo tableVos);
}

View File

@@ -0,0 +1,432 @@
package jnpf.attendance.service;
import jnpf.base.service.SuperService;
import jnpf.entity.AttendanceGroup;
import jnpf.entity.AttendanceGroupUser;
import jnpf.entity.attendance.*;
import jnpf.enums.attendance.AttendanceTypeEnum;
import jnpf.enums.attendance.v2.ClockOutHandleParam;
import jnpf.exception.HandleException;
import jnpf.model.attendance.dto.LineDrawingSchedulesConfigDto;
import jnpf.model.attendance.dto.PeriodConfig;
import jnpf.model.attendance.dto.SchedulesImportDto;
import jnpf.model.attendance.dto.SchedulesSetDto;
import jnpf.model.attendance.dto.UnifiedSchedulesDto;
import jnpf.model.attendance.model.DayClockRange;
import jnpf.model.attendance.vo.*;
import jnpf.model.attendance.vo.attendance.OutOrBusApproveVo;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* <p>
* 考勤组-每日出勤规则 服务类
* </p>
*
* @author ahua
* @since 2023-11-22
*/
public interface AttendanceDailyRuleService extends SuperService<FtbAttendanceDailyRule> {
/**
* 导出指定月份的调度信息
*
* @param groupId 调度组ID用于标识一组调度信息
* @param realName 用户真实姓名,用于过滤特定用户的调度信息
* @param month 指定的月份,格式为"YYYY-MM",用于获取该月的调度信息
* @param userIdList 用户ID列表用于过滤需要导出调度信息的用户
* @param isSchedules 是否包含调度信息的标志,用于指示是否需要导出调度详情
*/
void schedulesExport(String groupId, String workGroupId, String realName, String month, List<String> userIdList, Integer isSchedules);
void hisDailyRule(Map<String, String> group2orgMap, Map<String, String> org2groupMap, Map<String, List<AttendanceGroupUser>> usersMap);
void clockOutHandle(ClockOutHandleParam param);
FtbAttendanceDailyRule workOvertimeNotApprove(ClockOutHandleParam param);
/**
* 根据条件获取排班列表V2版本。
*
* @param groupId 考勤组ID
* @param realName 真实姓名
* @param month 月份
* @param userIdList 用户ID列表
* @param isSchedules 是否排班标识
* @return 排班列表V2版本
*/
List<SchedulesV2Vo> getSchedulesListV2(String groupId, String workGroupId, String realName, String month, List<String> userIdList, Integer isSchedules);
/**
* 根据条件获取排班列表 V2按开始日期、结束日期其它与 {@link #getSchedulesListV2} 一致)
*
* @param startDate 开始日期yyyy-MM-dd
* @param endDate 结束日期yyyy-MM-dd
*/
List<SchedulesV2Vo> getSchedulesListV2ByDateRange(String groupId, String workGroupId, String realName, String startDate, String endDate, List<String> userIdList, Integer isSchedules);
/**
* 按预排班 Redis 草稿({@link jnpf.attendance.schedule.ShiftPlanAssignmentResult#getByEmployee()} JSONkey 为租户 + 草稿 id
* 转换为排班列表 V2 结构;草稿不存在或为空返回空列表。
*
* @param groupId 考勤组 id
* @param startDate 开始日期 yyyy-MM-dd
* @param endDate 结束日期 yyyy-MM-dd
* @param draftId 草稿 idRedis key 第二段)
*/
List<SchedulesV2Vo> getSchedulesListV2ByPreScheduleDraft(
String groupId, String startDate, String endDate, String draftId);
/**
* 根据班次ID列表获取班次名称实体映射。
*
* @param shiftIds 班次ID列表
* @return 班次ID与班次名称实体的映射
*/
Map<String, AttendanceShiftNameEntity> getShiftByShiftIds(List<String> shiftIds);
/**
* 检查指定日期用户是否存在。
*
* @param users 考勤组用户列表
* @param date 日期
* @return 用户存在标识(- 1离组 0未加入 1存在 2借调)
*/
Integer findUserIsExistsStatusByDay(List<AttendanceGroupUser> users, Date date);
/**
* 检查指定日期用户是否存在。
*
* @param users 考勤组用户列表
* @param date 日期
* @return 用户存在标识1存在0不存在
*/
Integer findUserIsExistsByDay(List<AttendanceGroupUser> users, Date date);
/**
* 检查指定日期范围内用户是否存在。
*
* @param users 考勤组用户列表
* @param start 开始日期
* @param end 结束日期
* @return 用户存在标识1存在0不存在
*/
Integer findUserIsExistsByDay(List<AttendanceGroupUser> users, Date start, Date end);
/**
* 检查指定日期范围内用户是否存在。
*
* @param users 考勤组用户列表
* @param start 开始日期
* @param end 结束日期
* @return 用户存在标识1存在0不存在
*/
Map<String, Integer> findUserIsExistsByUserList(List<AttendanceGroupUser> users, Date start, Date end);
/**
* 判断当天内用户的状态, -1为已离 0为未入 1正常 2为全天被借调 3部分被借调 4借调
*
* @param users 考勤组用户列表
* @param date 日期
* @return -1为已离 0为未入 1正常 2为全天被借调 3部分被借调 4借调
*/
Integer isExistStatus(List<AttendanceGroupUser> users, Date date);
/**
* 判断时间范围内用户的状态, -1为已离 0为未入 1正常 2为全天被借调 3部分被借调 4借调
* @param users
* @param start
* @param end
* @return
*/
Integer isExistStatus(List<AttendanceGroupUser> users, Date start, Date end);
/**
* 是否借调不管借调还是被借调只要命中借调时间则返回true
*
* @param users 考勤组用户列表
* @param start 开始日期
* @param end 结束日期
* @return 是否在借调状态
*/
Boolean isInSecondment(List<AttendanceGroupUser> users, Date start, Date end);
/**
* 获取排班规则详情。
*
* @param id 排班规则ID
* @return 排班规则详情
* @throws HandleException 处理异常
*/
ScheduleRuleDetailVo getDetail(String id) throws HandleException;
/**
* 修改固定周期班次设置。
*
* @param groupIds 考勤组ID列表
* @param periodList 周期班次设置列表
* @param enableTime 生效时间
*/
void fixedPeriodChange(List<String> groupIds, AttendanceShiftSettingVo periodList, Date enableTime);
/**
* 添加用户的固定班次规则处理。
*
* @param groupId 考勤组ID
* @param userIds 用户ID列表
*/
void addUserFixedHandle(String groupId, List<String> userIds);
/**
* 添加用户的固定班次规则处理包含租户ID。
*
* @param groupId 考勤组ID
* @param tenantId 租户ID
* @param userIds 用户ID列表
*/
void addUserFixedHandle(String groupId, String tenantId, List<String> userIds);
/**
* 添加节假日日常规则。
*
* @param start 开始日期
* @param end 结束
* @param attendanceGroupVos 考勤组列表
* @param festivalSetting 节假日设置映射
* @param hisFestivalSetting 历史节假日设置实体
**/
void addHolidayDailyRule(Date start, Date end, List<AttendanceGroup> attendanceGroupVos, AttendanceFestivalRules festivalSetting, AttendanceFestivalRules hisFestivalSetting, List<String> newUserIds, List<String> oldUserIds);
/**
* 为自助调度设置时间表
*
* @param shiftId 班次ID用于标识特定的班次
* @return 如果设置成功,返回确认信息;否则返回错误信息
* @throws HandleException 如果设置过程中发生错误,则抛出此异常
*/
String setSchedulesForSelfSchedules(String shiftId) throws HandleException;
/**
* 更新班次配置时设置时间表
*
* @param groupId 组ID用于标识需要更新配置的组
* @param mark 标记,用于指示更新的版本或状态
* @param periodConfigs 时段配置列表,包含需要更新的班次配置信息
* @return 如果设置成功,返回受影响的行数或状态码;否则返回错误信息
* @throws HandleException 如果设置过程中发生错误,则抛出此异常
*/
Integer setSchedulesForShiftConfigUpdate(String groupId, Integer mark, List<PeriodConfig> periodConfigs, List<AttendanceShiftSettingPeriodEntity> periodEntities) throws HandleException;
/**
* 设置排班
*
* @param schedulesSets 排班设置列表
* @return 排班结果字符串
* @throws HandleException 处理异常
**/
String setSchedules(List<SchedulesSetDto> schedulesSets) throws HandleException;
/**
* 初始化固定排班规则。
*
* @param tenantId 租户ID
*/
void initFixedScheduleRule(String tenantId);
void clearGroupRule(String groupId, List<String> userIds);
/**
* 清除考勤组用户集合的考勤规则
*
* @param groupId 考勤组ID
* @param userIds userId集合
*/
void clearGroupRule(String groupId, List<String> userIds, Date departTime, String tenantId);
/**
* 申请验证的日规则处理
*
* @param applyParam 申请参数类
*/
List<DailyRuleResultVo> applyVerifyHandle(ApplyParam applyParam) throws HandleException;
/**
* 申请的日规则处理
*
* @param applyParam 申请参数类
*/
String applyDailyRuleHandle(ApplyParam applyParam) throws HandleException;
/**
* 借调申请日规则处理
*
* @param userIds 借调用户id集合
* @param fromGroupId 原考勤组id
* @param toGroupId 借调考勤组id
* @param start 开始时间
* @param end 结束时间
* @param departureTime 离岗时间
* @param backTime 回岗时间
* @param tenantId
*/
List<DailyRuleResultVo> secondmentDailyRuleHandle(List<String> userIds, String fromGroupId, String toGroupId, Date start, Date end, Date departureTime, Date backTime, String tenantId) throws HandleException;
/**
* 查询用户当日排班信息
*
* @param groupId 群组ID用于识别哪个群组的考勤规则需要查询
* @param userId 用户ID指定查询考勤规则的用户
* @param day 日期,指定查询考勤规则的具体日期
* @return 返回一个包含考勤规则的列表,这些规则适用于指定用户和日期
*/
List<FtbAttendanceDailyRule> getAttendanceDayRulesForStatistic(String groupId, String userId, Date day);
/**
* 获取用户当日可打卡时间范围
* 开始时间如果前一天有夸日班次开始时间就是夸日班次的下班缺卡时间没有就是当日的00:00:00
* 结束时间:当日最后一个班次的下班缺卡时间
*
* @param userId 用户ID指定查询考勤规则的用户
* @param day 日期,指定查询考勤规则的具体日期
* @return 返回一个包含开始时间和结束时间的对象
*/
DayClockRange getDayClockRange(String userId, Date day);
/**
* 获取当天最后一个班次的下班缺卡时间
*
* @param userId 用户ID指定查询考勤规则的用户
* @param day 日期,指定查询考勤规则的具体日期
* @return 返回一个Date对象表示当天最后一个班次的下班缺卡时间
*/
Date getDayEndRuleDeletionDate(String userId, Date day);
List<String> userIsSchedulingOrdinary(List<String> organizeIds);
boolean hasRuleByUserIdAndTime(String userId, Date start, Date end);
/**
* 获取用户当天外出/出差批次号
*
* @param userId 用户ID指定查询考勤规则的用户
* @param groupId 考勤组ID
* @param day 日期,指定查询考勤规则的具体日期
* @param typeEnumList 出勤类型
* @return 返回一个包含外出/出差批次号的列表
*/
List<OutOrBusApproveVo> getUserDayBusAndOutInfo(String userId, String groupId, Date day, List<AttendanceTypeEnum> typeEnumList);
/**
* 获取用户外出出差次数
*
* @param userIds 用户ID指定查询考勤规则的用户
* @param groupIdList 考勤组ID集合
* @param startDate 开始时间
* @param endDate 结束时间
* @param businessTrip 出勤类型
* @return Integer
*/
Map<String, Integer> getUserBusAndOutCount(List<String> userIds, List<String> groupIdList, Date startDate, Date endDate, AttendanceTypeEnum businessTrip);
/**
* 用户是否排班
*
* @param userId 用户ID
* @return boolean true: 是 false: 否
*/
boolean userIsScheduling(String userId);
List<SchedulesV2Vo> schedulesImport(SchedulesImportDto schedulesImportDto) throws IOException;
Map<String, BigDecimal> getUserPublicHoliday(String yearMonth, List<String> userIds);
/**
* 获取最早排班时间
*
* @return Date
*/
Date getEarliestSchedulingDate(Date start);
boolean hasLinearRulesByPeriod(String userId, Date start, Date end);
/**
* 设置划线排班
*
* @param configDto 划线排班配置DTO
* @return 处理结果
* @throws HandleException 处理异常
*/
String setLineDrawingSchedules(LineDrawingSchedulesConfigDto configDto) throws HandleException;
boolean queryLineSchedulingExist(LineDrawingSchedulesConfigDto configDto);
void lineSchedulesExport(String groupId, String workGroupId, String month, List<String> userIdList);
void lineSchedulesImport(SchedulesImportDto schedulesImportDto) throws IOException;
List<LineSchedulesVo> getLineSchedulesList(String groupId, String workGroupId, List<String> dayList, List<String> finalUserIdList);
/**
* 查询单个用户是否划线排班
* @param userId
* @param start
* @param end
* @return
*/
boolean isLineScheduleByUserId(String userId, Date start, Date end);
FtbAttendanceLineSchedulingConfig lineSchedulesConfigFilter(String groupId, List<String> userIds);
@Nullable FtbAttendanceLineSchedulingConfig getFtbAttendanceLineSchedulingConfig(List<String> userIds, FtbAttendanceLineSchedulingConfig lineSchedulingConfig);
/**
* 获取排班
* @param finalStartDate 开始日期
* @param finalEndDate 结束日期
* @return 排班列表
*/
List<CreateDayStatistics> getDayRuleByMonth(LocalDate finalStartDate, LocalDate finalEndDate);
/**
* 查询指定用户指定日期的班次信息,合并展示普班和请假时段
* 请假信息作为班次信息的补充,当班次被请假覆盖时,根据覆盖情况展示时段
*
* @param userId 用户ID
* @param queryDate 查询日期
* @return 用户指定日期时段信息(包含普班和请假)
*/
UserDayShiftInfoVo getUserDayShiftInfo(String userId, Date queryDate);
/**
* 统一排班接口(支持固定排班和划线排班)
*
* @param dto 统一排班DTO
* @return 处理结果消息
* @throws HandleException 处理异常
*/
String setUnifiedSchedules(UnifiedSchedulesDto dto) throws HandleException;
/**
* 查询考勤组近 90 天历史排班:按自然日返回班次及岗位人数;划线排班一人一条,人数为 1
*
* @param groupId 考勤组 id
* @return 每日营业额(预留)、班次及岗位人数列表
*/
List<DayShiftRevenueStatVo> getGroupShiftHistory90Days(String groupId);
/**
* 按自然日查询考勤组所属门店营业额预估
*
* @param groupId 考勤组 id
* @param startTime 开始日期(含)
* @param endTime 结束日期(含)
* @return 按日营业额预估列表
*/
List<DayReceivableRevenueVo> listReceivableRevenueByDay(String groupId, Date startTime, Date endTime);
}

View File

@@ -0,0 +1,536 @@
package jnpf.attendance.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.github.pagehelper.PageInfo;
import jnpf.attendance.dto.*;
import jnpf.base.vo.PageListVO;
import jnpf.entity.attendance.AttendanceDayStatistics;
import jnpf.exception.LoginException;
import jnpf.model.attendance.dto.*;
import jnpf.model.attendance.event.StatisticsBatchClearDto;
import jnpf.model.attendance.event.StatisticsSingleDto;
import jnpf.model.attendance.event.StatisticsSingleHistoryDto;
import jnpf.model.attendance.vo.attendance.*;
import jnpf.permission.vo.v2.user.UserBoundVO;
import org.apache.commons.lang3.tuple.MutablePair;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 考勤日度统计表
*
* @author shitou
* @email shitou@niujiekeji.com
* @date 2024-06-24 09:33:43
*/
public interface AttendanceDayStatisticsService extends IService<AttendanceDayStatistics> {
/**
* 获取有权限的用户列表
*
* @param filterList 筛选条件
* @param startDate 开始时间
* @param endDate 结束时间
* @param userIdsFilter 用户ID
* @param workStatus 用户状态
* @return 用户列表
*/
List<UserBoundVO> getUserIdArr(List<GroupFilterDto> filterList, String startDate, String endDate, List<String> userIdsFilter, String workStatus);
/**
* 获取日度统计数据。
* 根据请求参数DayStatisticsDataDto查询并返回日度统计数据的列表。
*
* @param req 请求参数,包含查询条件等。
* @return 返回日度统计数据的列表List<DayStatisticsDataVo>)。
*/
List<DayStatisticsDataVo> getDayStatisticsData(DayStatisticsDataDto req);
/**
* 获取日度统计数据的分页列表。
* 根据请求参数DayStatisticsPageListDto分页查询并返回日度统计数据的列表。
*
* @param req 请求参数,包含分页信息和查询条件等。
* @return 返回分页的日度统计数据列表PageInfo<DayStatisticsPageListVo>)。
*/
PageInfo<DayStatisticsPageListVo> getDayPageList(DayStatisticsPageListDto req);
/**
* 执行日度统计数据的导出操作。
* 根据请求参数DayStatisticsExportDto生成并导出日度统计数据的文件。
*
* @param req 请求参数,包含导出所需的条件和选项。
*/
void dayDataExport(DayStatisticsExportDto req);
/**
* 获取月度统计数据。
* 根据请求参数MouthStatisticsDataDto查询并返回月度统计数据的列表。
* 注意:方法名中的"Mouth"可能是笔误,应为"Month"。
*
* @param req 请求参数,包含查询条件等。
* @return 返回月度统计数据的列表List<DayStatisticsDataVo>,这里可能是类型复用或错误,通常应为特定的月度数据类型)。
*/
List<DayStatisticsDataVo> getMonthStatisticsData(MouthStatisticsDataDto req);
/**
* 获取月度统计数据的分页列表。
* 根据请求参数MonthStatisticsPageListDto分页查询并返回月度统计数据的列表。
*
* @param req 请求参数,包含分页信息和查询条件等。
* @return 返回分页的月度统计数据列表PageInfo<MonthStatisticsPageListVo>)。
* @throws Exception 抛出异常以处理可能出现的错误情况。
*/
PageInfo<MonthStatisticsPageListVo> getMonthPageList(MonthStatisticsPageListDto req) throws Exception;
/**
* 执行月度统计数据的导出操作。
* 根据请求参数MonthStatisticsExportDto生成并导出月度统计数据的文件。
*
* @param req 请求参数,包含导出所需的条件和选项。
*/
void monthDataExport(MonthStatisticsExportDto req);
/**
* 获取排班格子统计数据。
* 根据请求参数LatticeStatisticsVoDto查询并返回排班格子统计数据。
*
* @param req 请求参数,包含查询条件等。
* @return 返回排班格子统计数据LatticeStatisticsVo
*/
LatticeStatisticsVo getLatticeStatistics(LatticeStatisticsVoDto req);
/**
* 用户加入时生成空白统计数据。
* 当用户加入指定组时,为该用户生成初始的空白统计数据。
*
* @param groupId 组ID指定用户加入的组。
* @param userIds 用户ID列表包含加入组的用户。
*/
void userJoinHandleData(String tenantId, String groupId, List<String> userIds);
/**
* 用户加入时生成空白统计数据。
* 当用户加入指定组时,为该用户生成初始的空白统计数据。
*
* @param date 加入时间
* @param groupId 组ID指定用户加入的组。
* @param userIds 用户ID列表包含加入组的用户。
*/
void userJoinHandleData(String tenantId, Date date, String groupId, List<String> userIds);
/**
* 用户日统计数据初始化。
* 初始化用户日统计数据的相关操作,如重置统计记录等。
*
* @return 返回操作是否成功的布尔值。
*/
Boolean handleDataForJob(String tenantId);
/**
* 批量清除日统计数据。
* 根据给定的组ID、用户ID和日期清除用户的日统计数据。
*
* @param courseEventDTO 批量清除用户日统计数据所需的参数。
*/
void batchStatisticDataClear(StatisticsBatchClearDto courseEventDTO);
/**
* 组织重构考勤数据变更
*
* @param tenantId 租户id
* @param start 开始时间
*/
void regenerateDayData(String tenantId, Date start);
/**
* 处理历史数据
*
* @param tenantId 租户id
* @param start 开始时间
* @param end 结束时间
*/
void processHistoricalData(String tenantId, Date start, Date end);
/**
* 生成用户日统计数据。
*
* @param singleDto 单个用户日统计数据变更参数
*/
void statisticDataChange(StatisticsSingleDto singleDto) throws LoginException;
/**
* 生成用户日统计数据。
*
* @param singleDto 单个用户日统计数据变更参数
*/
void statisticDataChangeHistory(StatisticsSingleHistoryDto singleDto) throws LoginException;
/**
* 发送个人考勤日报通知。
* 根据给定的租户ID发送个人考勤日报通知。
*
* @param tenantId 租户ID。
* @return 返回操作是否成功的布尔值。
*/
Boolean dayStatisticsNotice(String tenantId);
/**
* 发送个人统计月报通知。
* 根据给定的租户ID发送个人统计月报通知。
*
* @param tenantId 租户ID。
* @return 返回操作是否成功的布尔值。
*/
Boolean monthStatisticsNotice(String tenantId);
/**
* 发送连续未排班通知。
* 根据给定的租户ID发送连续未排班通知。
*
* @param tenantId 租户ID。
*/
void consentUnscheduledNotice(String tenantId);
/**
* 发送团队统计月报通知。
* 根据给定的租户ID发送团队统计月报通知。
*
* @param tenantId 租户ID。
* @return 返回操作是否成功的布尔值。
*/
Boolean teamMonthStatisticsNotice(String tenantId);
/**
* 计算考勤组平均工时(实际出勤工时)
*
* @param dto 筛选条件
* @return 考勤平均工时
*/
List<AttendanceCountAvgHoursVo> countAttendanceAvgHours(AttendanceCountAvgHoursDto dto);
/**
* 获取多考勤组月度统计数据
*
* @param dto 筛选条件
* @return 月度统计数据
*/
MonthStatsDetailsVo getAttendanceAvgHoursDetails(MonthStatsDetailsDto dto);
/**
* 获取多考勤组月度人均工时折线图
*
* @param dto 筛选条件
* @return 考勤组月度人均工时折线图
*/
List<MonthStatsPerCapitaVo> getAttendanceMonthPerCapita(MonthStatsDetailsDto dto);
/**
* 获取多考勤组月度日常情况
*
* @param dto 筛选条件
* @return 考勤组月度日常情况
*/
List<MonthStatsDailySituationVo> getAttendanceDailySituation(MonthStatsDetailsDto dto);
/**
* 获取多考勤组月度考勤工时排行
*
* @param dto 筛选条件
* @return 考勤组月度考勤工时排行
*/
List<MonthStatsHoursRankingVo> getAttendanceHoursRanking(MonthStatsDetailsDto dto);
/**
* 获取多考勤组月度全勤情况
*
* @param dto 筛选条件
* @return 考勤组月度出勤情况
*/
List<MonthStatsFullSituationVo> getAttendanceFullSituation(MonthStatsDetailsDto dto);
/**
* 获取多考勤组月度异常情况
*
* @param dto 筛选条件
* @return 考勤组月度异常情况
*/
MonthStatsAbnormalConditionVo getAttendanceAbnormalCondition(MonthStatsDetailsDto dto);
/**
* 获取多考勤组月度加班情况
*
* @param dto 筛选条件
* @return 考勤组月度加班情况
*/
List<MonthStatsOvertimeSituationVo> getAttendanceOvertimeSituation(MonthStatsDetailsDto dto);
/**
* 获取当月考勤确认数据
*
* @param userIds 用户ID列表
* @param month 考勤月份
* @return 考勤组月度加班情况
*/
List<MonthConfirmStatisticsListVo> getConfirmDetailsInfoByMonth(List<String> userIds, String month);
/**
* 考勤封账-分页列表
*
* @param dto 考勤封账分页列表参数
* @return 考勤封账分页列表结果
*/
PageInfo<MonthSealPageListVo> sealPageList(MonthSealPageListDto dto);
/**
* 考勤封账/批量|单个封账
*
* @param dto 考勤封账参数
* @return 考勤封账结果
*/
Boolean sealSubmit(MonthSealSubmitDto dto);
/**
* 考勤封账/解封
* @param dto 用户ID
* @return 解封结果
*/
Boolean unSealSubmit(MonthUnSealSubmitDto dto);
/**
* 批量查询用户在指定月份是否封账
*
* @param userIdList 用户ID集合
* @param month 月份(yyyy-MM)
* @return 是否封账
*/
Map<String, Boolean> selectUserIsSeal(List<String> userIdList, String month);
/**
* 批量查询用户在指定日期范围内是否存在封账记录
*
* @param userIdList 用户ID集合
* @param start 范围开始(含当日)
* @param end 范围结束(含当日)
* @return 是否封账
*/
Map<String, Boolean> selectUserIsSealByDateRange(List<String> userIdList, Date start, Date end);
/**
* 按天查询用户在日期范围内的已封存日期集合(跨月场景使用)
* 返回每个用户已被封存的日期(yyyy-MM-dd)集合,用于在排班视图中按天判断锁定状态
*
* @param userIdList 用户ID集合
* @param start 范围开始(含当日)
* @param end 范围结束(含当日)
* @return userId -> 已封存日期字符串集合(yyyy-MM-dd)
*/
Map<String, Set<String>> selectUserDailySealByDateRange(List<String> userIdList, Date start, Date end);
/**
* 薪酬考勤数据支持(薪酬)
*
* @param dto 薪酬考勤数据支持参数
* @return 薪酬考勤数据支持结果
*/
Map<String, SalaryAttendanceSupportVo> salaryAttendanceSupport(SalaryAttendanceSupportDto dto);
/**
* 考勤统计数据列表(薪酬)
*
* @param dto 考勤统计数据列表参数
* @return 考勤统计数据列表结果
*/
List<DayStatisticsPageListVo> attendanceStaList(SalaryAttendanceSupportDto dto);
/**
* 获取考勤统计数据列表
*
* @param dto 获取考勤统计数据列表参数
* @return 考勤统计数据列表结果
*/
List<DayStatisticsVo> getAttendanceDayStaList(DayStatisticsDto dto);
/**
* 获取考勤组维度统计数据
*
* @param dto 筛选条件
* @return 考勤组维度统计数据
*/
Map<String, List<DateDimensionsRangeVo>> getDimensionsAttendanceCountMap(DimensionsAttendanceCountDto dto);
/**
* 获取考勤组维度统计数据-日维度
*
* @param dto 筛选条件
* @return 考勤组维度统计数据
*/
Map<String, Map<Date, Integer>> getDimensionsAttendanceDayCountMap(DimensionsAttendanceDayCountDto dto);
/**
* 日度计薪统计-分页列表
*
* @param req 筛选条件
* @return 考勤组维度统计数据
*/
PageInfo<DayPayrollStatisticsPageListVo> getDayPayrollPageList(DayPayrollStatisticsPageListDto req);
/**
* 月度计薪统计-分页列表
*
* @param req 筛选条件
* @return 考勤组维度统计数据
*/
PageInfo<MonthPayrollStatisticsPageListVo> getMonthPayrollPageList(MonthPayrollStatisticsPageListDto req) throws Exception;
/**
* 考勤平均工时趋势-分页列表
*
* @param pageDto 筛选条件
* @return 分页列表
*/
PageListVO<AverageTrendPageListVo> averageWorkHoursTrendPageList(PersonnelApiInfoPageListDto pageDto);
/**
* 考勤平均工时趋势-导出
*
* @param response 响应
* @param pageDto 筛选条件
*/
void averageWorkHoursTrendExport(HttpServletResponse response, PersonnelApiInfoPageListDto pageDto) throws Exception;
/**
* 考勤人均工时趋势-分页列表
*
* @param pageDto 筛选条件
* @return 分页列表
*/
PageListVO<PersonnelTrendPageListVo> personWorkHoursTrendPageList(PersonnelApiInfoSinglePageListDto pageDto);
/**
* 考勤人均工时趋势-导出
*
* @param response 响应
* @param pageDto 筛选条件
*/
void personWorkHoursTrendExport(HttpServletResponse response, PersonnelApiInfoSinglePageListDto pageDto) throws Exception;
/**
* 考勤日常情况-分页列表
*
* @param pageDto 筛选条件
* @return 分页列表
*/
PageListVO<DailySituationPageListVo> dailySituationPageList(PersonnelApiInfoSinglePageListDto pageDto);
/**
* 考勤日常情况-导出
*
* @param response 响应
* @param pageDto 筛选条件
*/
void dailySituationExport(HttpServletResponse response, PersonnelApiInfoSinglePageListDto pageDto) throws Exception;
/**
* 考勤工时排行-分页列表
*
* @param pageDto 筛选条件
* @return 分页列表
*/
PageListVO<WorkHoursRankingPageListVo> workHoursRankingPageList(PersonnelApiInfoSinglePageListDto pageDto);
/**
* 考勤工时排行-导出
*
* @param response 响应
* @param pageDto 筛选条件
*/
void workHoursRankingExport(HttpServletResponse response, PersonnelApiInfoSinglePageListDto pageDto) throws Exception;
/**
* 考勤全勤情况-分页列表
*
* @param pageDto 筛选条件
* @return 分页列表
*/
PageListVO<FullAttendanceStatusPageListVo> fullAttendanceStatusPageList(PersonnelApiInfoSinglePageListDto pageDto);
/**
* 考勤全勤情况-导出
*
* @param response 响应
* @param pageDto 筛选条件
*/
void fullAttendanceStatusExport(HttpServletResponse response, PersonnelApiInfoSinglePageListDto pageDto) throws Exception;
/**
* 考勤异常情况-分页列表
*
* @param pageDto 筛选条件
* @return 分页列表
*/
PageListVO<ExceptionSituationPageListVo> exceptionSituationPageList(PersonnelApiInfoSinglePageListDto pageDto);
/**
* 考勤考勤异常情况-导出
*
* @param response 响应
* @param pageDto 筛选条件
*/
void exceptionSituationExport(HttpServletResponse response, PersonnelApiInfoSinglePageListDto pageDto) throws Exception;
/**
* 考勤加班情况-分页列表
*
* @param pageDto 筛选条件
* @return 分页列表
*/
PageListVO<OvertimeSituationPageListVo> overtimeSituationPageList(PersonnelApiInfoSinglePageListDto pageDto);
/**
* 考勤加班情况-导出
*
* @param response 响应
* @param pageDto 筛选条件
*/
void overtimeSituationExport(HttpServletResponse response, PersonnelApiInfoSinglePageListDto pageDto) throws Exception;
/**
* 查询用户考勤统计信息
*
* @param dto 筛选条件
* @return 考勤统计信息
*/
QueryStatisticsInfoVo queryUserStatisticsInfo(QueryStatisticsInfoDto dto);
/**
* 查询考勤组的考勤情况
*
* @param dto 筛选条件
* @return 考勤组维度统计信息
*/
QueryGroupStatisticsVo queryGroupStatistics(QueryGroupStatisticsDto dto);
/**
* 查询用户的加班情况
*
* @param dto 筛选条件
* @return 用户加班信息
*/
QueryUserOvertimeVo queryUserOvertime(QueryStatisticsInfoDto dto);
/**
* 查询用户工作状况
*
* @param dto 筛选条件
* @return Map<用户ID, Map<日期,是否排班>>
*/
Map<String, UserWorkSituationVo> queryUserWorkSituation(UserWorkSituationDto dto);
}

View File

@@ -0,0 +1,88 @@
package jnpf.attendance.service;
import com.github.pagehelper.PageInfo;
import jnpf.entity.attendance.AttendanceFestivalRules;
import jnpf.model.attendance.dto.AttendanceFestivalRulesDto;
import jnpf.model.attendance.dto.FestivalDto;
import jnpf.model.attendance.dto.FestivalRulesQueryDto;
import jnpf.model.attendance.vo.attendance.AttendanceFestivalRulesVo;
import java.util.Date;
import java.util.List;
import java.util.Map;
public interface AttendanceFestivalRulesService {
/**
* 列表
* @param queryDto 查询条件
* @return 列表
*/
PageInfo<AttendanceFestivalRulesVo> getPageList(FestivalRulesQueryDto queryDto);
/**
* 新增
* @param festivalRulesDto 参数
*/
void add(AttendanceFestivalRulesDto festivalRulesDto) throws Exception;
void statutoryUpdate(String year);
/**
* 修改
* @param festivalRulesDto 参数
*/
void update(AttendanceFestivalRulesDto festivalRulesDto) throws Exception;
/**
* 详情
* @param id 主键值
*/
AttendanceFestivalRulesVo detail(String id);
/**
* 删除
* @param id 主键值
*/
void delete(String id);
/**
* 更新状态
* @param festivalRulesDto festivalRulesDto
*/
void updateState(AttendanceFestivalRulesDto festivalRulesDto);
/**
* 检查规则
* @param date 日期
* @param userId 用户ID
* @return boolean
*/
boolean checkFestivalRules(Date date, String userId);
/**
* 批量[多用户]判定日期内是否节假日
* @param date 日期
* @param userIds 用户ID
* @return java.util.Map<java.lang.String,java.util.Map>
*/
Map<String, Map<String, FestivalDto>> checkFestivalRulesBatch(Date date, List<String> userIds);
/**
* 批量检查规则
* @param date 日期
* @param userIds 用户ID列表
* @return boolean
*/
Map<String, Boolean> batchCheckFestivalRules(Date date, List<String> userIds);
/**
* 批量获取用户指定时间区间内的所有节假日
* @param start 开始时间
* @param end 结束时间
* @param userIds 用户ID列表
* @return java.util.Map<java.lang.String,java.util.List<jnpf.entity.attendance.AttendanceFestivalRules>>
*/
Map<String, List<AttendanceFestivalRules>> batchGetFestivalRulesByUserIds(Date start ,Date end, List<String> userIds);
}

View File

@@ -0,0 +1,106 @@
package jnpf.attendance.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import jnpf.entity.AttendanceGroup;
import jnpf.entity.attendance.AttendanceFestivalSettingEntity;
import jnpf.base.service.SuperService;
import jnpf.exception.HandleException;
import jnpf.model.attendance.dto.AttendanceFestivalSettingDto;
import jnpf.model.attendance.vo.AttendanceFestivalSettingVo;
import jnpf.model.attendance.vo.HolidayOptionVo;
import java.util.List;
import java.util.Map;
/**
* <p>
* 考勤配置-节日配置 服务类
* </p>
*
* @author ahua
* @since 2023-11-29
*/
public interface AttendanceFestivalSettingService extends SuperService<AttendanceFestivalSettingEntity> {
/**
* 保存节日设置信息。
*
* @param attendanceFestivalSettingDto 节日设置数据传输对象
* @throws HandleException 处理异常
*/
void save(AttendanceFestivalSettingDto attendanceFestivalSettingDto) throws HandleException;
/**
* 分页查询节日设置信息。
*
* @param groupId 考勤组ID
* @param year 年份
* @param page 页码
* @param size 每页大小
* @return 分页的节日设置视图对象
* @throws HandleException 处理异常
*/
PageDTO<AttendanceFestivalSettingVo> page(String groupId, String year, Integer page, Integer size) throws HandleException;
/**
* 根据ID获取单个节日设置信息。
*
* @param id 节日设置ID
* @return 节日设置视图对象
*/
AttendanceFestivalSettingVo getOne(String id);
/**
* 删除指定的节日设置信息。
*
* @param id 节日设置ID
*/
void del(String id);
/**
* 获取启用状态的节日设置信息。
*
* @param groupIds 考勤组ID列表
* @param attendanceGroupVos 考勤组视图对象列表
* @return 启用的节日设置信息映射
*/
Map<String, List<AttendanceFestivalSettingEntity>> getEnableFestivalSetting(List<String> groupIds, List<AttendanceGroup> attendanceGroupVos);
/**
* 自动授予假期余额。
*/
// void autoGrantBalance();
/**
* 更新法定节日信息。
*
* @param groupId 考勤组ID
* @param year 年份
*/
void statutoryUpdate(String groupId, String year);
/**
* 更新节日设置信息的启用状态。
*
* @param id 节日设置ID
* @param enable 启用状态0禁用1启用
* @throws HandleException 处理异常
*/
void updateStatus(String id, Integer enable) throws HandleException;
/**
* 初始化节日设置。
*
* @param groupId 考勤组ID
*/
void initFestivalSetting(String groupId);
/**
* 获取节日选项列表。
*
* @param groupId 考勤组ID
* @return 节日选项视图对象列表
*/
List<HolidayOptionVo> getHolidayOptions(String groupId);
}

View File

@@ -0,0 +1,16 @@
package jnpf.attendance.service;
import jnpf.entity.attendance.AttendanceFixedClassEntity;
import jnpf.base.service.SuperService;
/**
* <p>
* 固定班关联表 服务类
* </p>
*
* @author ahua
* @since 2024-05-10
*/
public interface AttendanceFixedClassService extends SuperService<AttendanceFixedClassEntity> {
}

View File

@@ -0,0 +1,480 @@
package jnpf.attendance.service;
import jnpf.attendance.dto.AttendanceUserGroupVo;
import jnpf.attendance.dto.AttendanceUserListGroupVO;
import jnpf.base.service.SuperService;
import jnpf.entity.AttendanceGroup;
import jnpf.entity.AttendanceGroupUser;
import jnpf.entity.attendance.AppointPermission;
import jnpf.exception.HandleException;
import jnpf.exception.QueryException;
import jnpf.model.attendance.dto.*;
import jnpf.model.attendance.vo.AttendanceGroupChargeVo;
import jnpf.model.attendance.vo.AttendanceGroupVo;
import jnpf.model.attendance.vo.AttendanceOrgOrGroupVo;
import jnpf.model.attendance.vo.attendance.GroupLockVo;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 打卡服务
*
* @author yanwenfu
* @create 2023-11-21
*/
public interface AttendanceGroupService extends SuperService<AttendanceGroup> {
/**
* 新增考勤组
*/
int save(SaveAttendanceGroupDto saveAttendanceGroupDto) throws Exception;
/**
* 根据用户ID和申请时间范围获取考勤组ID列表
*
* @param userId 用户ID
* @param applyStart 申请开始时间
* @param applyEnd 申请结束时间
* @return java.util.List<java.lang.String> 考勤组ID列表
* @throws HandleException 处理异常
*/
List<String> getGroupIdByUserId(String userId, Date applyStart, Date applyEnd) throws HandleException;
/**
* 根据用户列表和时间范围获取考勤组ID列表
*
* @param users 用户列表
* @param start 开始时间
* @param end 结束时间
* @return java.util.List<java.lang.String> 考勤组ID列表
*/
List<String> getGroupIdByUserId(List<AttendanceGroupUser> users, Date start, Date end);
/**
* 删除考勤组
*
* @param id 考勤组ID
* @param parentId 父考勤组ID
*/
void delete(String id, String parentId);
/**
* 切换考勤组状态
*
* @param dto 考勤组状态DTO
*/
void exchangeGroupStatus(AttendanceGroupStatusDto dto);
/**
* 获取考勤组及其子组ID列表
*
* @param groupId 考勤组ID
* @param settingType 设置类型
* @return java.util.List<java.lang.String> 考勤组ID列表
*/
List<String> getSelfAndChildrenGroupIds(String groupId, Integer settingType);
/**
* 查询本组及(继承)子组考勤组成员
*
* @param groupId 考勤组id
* @return java.util.List<java.lang.String> 考勤组成员列表
*/
List<String> getSelfAndChildrenMembers(String groupId);
/**
* 查询考勤组列表
*
* @param groupName 考勤组名称
* @return java.util.List<AttendanceGroupVo> 考勤组列表
*/
List<AttendanceGroupVo> queryList(String groupName);
/**
* 查询包括已删除的考勤组列表
*
* @param groupIds 考勤组ID列表
* @return java.util.List<AttendanceGroup> 考勤组列表
*/
List<AttendanceGroup> queryListIncludeDeleteByIds(List<String> groupIds);
/**
* 根据ID列表查询考勤组列表
*
* @param groupIds 考勤组ID列表
* @return java.util.List<AttendanceGroup> 考勤组列表
*/
List<AttendanceGroup> queryListByIds(List<String> groupIds);
/**
* 根据所有ID查询考勤组列表
*
* @return java.util.List<AttendanceGroup> 考勤组列表
*/
List<AttendanceGroup> queryAllListByIds();
/**
* 查询我管理的考勤组
*
* @param keyword 搜索关键字
* @return java.util.List<AttendanceGroupVo> 我管理的考勤组列表
*/
List<AttendanceGroupVo> queryManagerGroupList(String keyword);
/**
* 根据考勤组名称模糊查询考勤组列表(带权限控制)
* 返回用户有管理权限的考勤组,支持名称模糊查询
*
* @param groupName 考勤组名称(支持模糊查询)
* @return java.util.List<AttendanceGroupVo> 考勤组列表
*/
List<AttendanceGroupVo> searchGroupByName(String groupName);
/**
* 查询下拉列表考勤组
*
* @return java.util.List<AttendanceGroup> 下拉列表考勤组
*/
List<AttendanceGroup> queryDropList();
/**
* 查询下拉列表考勤组
*
* @return java.util.List<AttendanceGroup> 下拉列表考勤组
*/
AttendanceGroup queryByGroupId(String groupId);
/**
* 查询我的考勤组列表
*
* @return java.util.List<AttendanceGroup> 我的考勤组列表
*/
List<AttendanceGroup> queryMyGroups();
/**
* 考勤组管理 获取我管理的考勤组(树状结构展示)
* @return java.util.List<AttendanceGroupVo> 我管理的考勤组树状列表
*/
List<AttendanceGroupVo> groupManagerList(GroupQueryDto groupQueryDto);
/**
* 获取启用状态的考勤组ID列表
*
* @param groupId 考勤组ID
* @return java.util.List<java.lang.String> 启用状态的考勤组ID列表
*/
List<String> getEnableGroupIds(String groupId);
/**
* 借调开始
*
* @param attendanceSecondedDto 借调信息DTO
* @throws HandleException 处理异常
*/
void secondedStart(AttendanceSecondedDto attendanceSecondedDto) throws HandleException;
/**
* 获取一个默认考勤组
*
* @return AttendanceGroupVo 默认考勤组信息
*/
AttendanceGroupVo getDefaultGroup();
/**
* 切换考勤组
*
* @param groupId 考勤组id
*/
void handoffGroup(String groupId);
/**
* 获取考勤组设置状态
*
* @param groupId 考勤组ID
* @param aFalse 布尔值,表示是否为默认状态
* @return AttendanceGroupStatusDto 考勤组状态DTO
*/
AttendanceGroupStatusDto groupSettingStatus(String groupId, Boolean aFalse);
/**
* 获取我有排班权限的考勤组列表
*
* @return java.util.List<AttendanceGroupVo> 我有排班权限的考勤组列表
*/
List<AttendanceGroupVo> schedulingGroupList();
/**
* 获取我有排班权限的考勤组列表(非固定班次)
*
* @return java.util.List<AttendanceGroupVo> 我有排班权限的考勤组列表(非固定班次)
*/
List<AttendanceGroupVo> schedulingGroupListByNotFixed();
/**
* 获取我有余额管理权限的考勤组列表
*
* @return java.util.List<AttendanceGroupVo> 我有余额管理权限的考勤组列表
*/
List<AttendanceGroupVo> balanceManagement();
/**
* 获取我有借调审批权限的考勤组列表
*
* @return java.util.List<AttendanceGroupVo> 我有借调审批权限的考勤组列表
*/
List<AttendanceGroupVo> secondedApprovalGroupList();
/**
* 获取切换考勤组列表以树结构展示
*
* @return java.util.List<AttendanceGroupVo> 切换考勤组树结构列表
*/
List<AttendanceGroupVo> handoffGroupTreeList();
/**
* 通过组织Id找到组织下的考勤组
*
* @param orgId 组织Id
* @return java.util.List<AttendanceGroupVo> 组织下的考勤组列表
*/
List<AttendanceGroupVo> groupListByOrgId(String orgId);
/**
* 通过考勤组Id获取绑定的组织名称拼接好的
*
* @param groupId 考勤组Id
* @return AttendanceGroupVo 考勤组绑定的组织名称信息
*/
AttendanceGroupVo getGroupBindingOrg(String groupId, String workGroupId);
AttendanceGroupVo getGroupBindingOrgForLine(String groupId, String workGroupId);
/**
* 绑定考勤组的组织
*
* @param attendanceGroupOrgDto 考勤组和组织信息
*/
void updateGroupOrg(AttendanceGroupOrgDto attendanceGroupOrgDto);
/**
* 查询用户所在考勤组
*
* @param userIds 用户ids
* @return java.util.List<AttendanceUserGroupVo> 用户所在考勤组列表
*/
List<AttendanceUserGroupVo> getAttendanceUserGroup(List<String> userIds);
/**
* 锁定考勤组
*
* @param groupId 考勤组id
*/
void lockGroup(String groupId);
void oldDataProcessing(String tenantId);
Map<String, String> batchSaveGroupByOrgIds(String tenantId, List<String> orgIds);
/**
* 获取组织下所有考勤组
*
* @param organizeId 组织ID
* @return java.util.List<AttendanceGroup> 组织下的所有考勤组列表
*/
List<AttendanceGroup> getByOrgId(String organizeId);
/**
* 获取组织下所有考勤组
*
* @param organizeIds 组织ID
* @return java.util.List<AttendanceGroup> 组织下的所有考勤组列表
*/
List<AttendanceGroup> getByOrgIds(List<String> organizeIds);
/**
* 查询用户当前考勤组锁定信息
*
* @param userId 用户id
* @return jnpf.model.attendance.vo.attendance.GroupLockVo 用户当前考勤组锁定信息
* @throws QueryException 查询异常
*/
GroupLockVo getUserCurrentGroupLockInfo(String userId) throws QueryException;
/**
* 查询当前考勤组锁定信息
*
* @param groupId 考勤组id
* @return jnpf.model.attendance.vo.attendance.GroupLockVo 当前考勤组锁定信息
*/
GroupLockVo getGroupLockInfo(String groupId);
/**
* 根据用户ID列表获取考勤组信息
*
* @param userIds 用户ID列表
* @return java.util.List<AttendanceUserListGroupVO> 用户考勤组信息列表
*/
List<AttendanceUserListGroupVO> getAttendanceUserListGroupVO(List<String> userIds);
/**
* 根据组织名称和考勤组名称获取考勤组信息
*
* @param organizeName 组织名称
* @param groupName 考勤组名称
* @return AttendanceGroupVo 考勤组信息
*/
AttendanceGroupVo getAttendanceGroupByNameOrganizeAndGroup(String organizeName, String groupName);
/**
* 获取审批考勤组列表
* @param name 考勤组名称模糊搜索
*/
List<AttendanceGroupVo> viewApprovalGroupList(String name);
/**
* 获取用户管理的考勤组信息
*
* @return java.util.Map<java.lang.String, java.util.List < java.lang.String>> 用户管理的考勤组信息映射表
*/
Map<String, List<String>> userManagerGroupInfo();
/**
* 获取组织下所有考勤组
*
* @param orgIds 组织ID列表
* @return List<AttendanceGroup>
*/
List<AttendanceGroup> getGroupListByOrgIds(List<String> orgIds);
/**
* 查询用户是否拥有指定考勤组的指定权限
* @param permissionCode 参数
*/
boolean appointPermission(AppointPermission permissionCode);
/**
* 获取指定考勤组的设置(是否继承上级)
* @param groupId 考勤组Id
*/
AttendanceGroup getGroupSetting(String groupId);
/**
* V1.9
* 获取我管理的考勤组(树状结构展示)
* @param groupQueryDto 参数
*/
List<AttendanceGroupVo> groupMyManagerList(GroupQueryDto groupQueryDto);
/**
* V1.9
* 获取我管理的考勤组(树状结构展示)排除固定班
*/
List<AttendanceGroupVo> schedulingGroupListByNotFixedNew();
/**
* V1.9
* 切换考勤组查询我管理的考勤组
*/
List<AttendanceGroupVo> handoffGroupTreeListNew();
/**
* V1.9 获取默认考勤组
*/
AttendanceGroupVo getDefaultGroupNew();
/**
* V1.9 获取我管理的考勤组
*/
List<AttendanceGroupVo> schedulingGroupListNew();
/**
* V1.9 余额考勤组列表
*/
List<AttendanceGroupVo> balanceManagementNew();
/**
* V1.9 查询我有借调权限的考勤组管理列表
*/
List<AttendanceGroupVo> secondedApprovalGroupListNew();
/**
* V1.9 获取审批考勤组列表
* @param name 考勤组名称模糊搜索
*/
List<AttendanceGroupVo> viewApprovalGroupListNew(String name);
/**
* 获取指定用户管理的考勤组
* @param userId 用户Id
* @param b 是否排除固定排班
* @return List<String> 考勤组Id
*/
List<String> getGroupIdsByManagePermission(String userId, boolean b);
/**
* 检查调度是否有效
* 此方法用于确定当前调度状态是否允许继续执行或需要停止
* 它不接受任何参数
*
* @return boolean 表示调度是否有效的布尔值如果返回true表示调度可以继续进行
* 如果返回false表示调度需要停止或重新评估
*/
boolean checkScheduling();
/**
* 获取权限组列表
* 此方法用于获取指定职位模块下的权限组列表
*
* @param positionModuleName 职位模块名称
* @return String 返回权限组列表的字符串表示
*/
List<AttendanceGroupVo> getPermissionsGroupList(String positionModuleName);
/**
* 查询考勤组列表(带权限)
* @return java.util.List<jnpf.model.attendance.vo.AttendanceGroupVo>
*/
List<AttendanceGroupVo> queryGroupListNew(String loginUserId, GroupQueryDto groupQueryDto);
/**
* 获取组织(考勤组)列表
* @param keyword 关键字
* @return 组织下的所有考勤组列表
*/
List<AttendanceOrgOrGroupVo> getOrgOrGroupList(String keyword);
/**
* 设置考勤组负责人
*
* @param dto 考勤组负责人信息
* @return Boolean
*/
Boolean setGroupCharge(AttendanceGroupChargeDto dto);
/**
* 获取考勤组负责人信息
*
* @param groupId 考勤组ID
* @return 考勤组负责人信息
*/
AttendanceGroupChargeVo getGroupChargeInfo(String groupId);
/**
* 移除考勤组负责人
*
* @param groupId 考勤组ID
* @param removeUserIds 移除的用户ID列表
*/
void removeManager(String groupId, List<String> removeUserIds);
/**
* 根据用户ID查询当前时间所在考勤组包含借调
*
* @param userId 用户ID
* @return java.util.List<AttendanceGroup> 考勤组列表
*/
List<AttendanceGroup> getUserCurrentGroups(String userId);
}

View File

@@ -0,0 +1,87 @@
package jnpf.attendance.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import jnpf.entity.AttendanceGroup;
import jnpf.entity.attendance.AttendanceHolidaySettingEntity;
import jnpf.base.service.SuperService;
import jnpf.model.attendance.dto.AttendanceHolidaySettingDto;
import jnpf.model.attendance.vo.AttendanceHolidaySettingVo;
import java.util.List;
import java.util.Map;
/**
* <p>
* 考勤配置-假日设置 服务类
* </p>
*
* @author ahua
* @since 2023-11-29
*/
public interface AttendanceHolidaySettingService extends SuperService<AttendanceHolidaySettingEntity> {
/**
* 分页查询假日设置信息。
*
* @param groupId 考勤组ID
* @param name 节假日名称(用于搜索过滤)
* @param paidSalaryEnable 是否计入薪酬标识(用于搜索过滤)
* @param page 页码
* @param size 每页大小
* @return 分页的假日设置视图对象
*/
PageDTO<AttendanceHolidaySettingVo> page(String groupId, String name, Integer paidSalaryEnable, Integer page, Integer size);
/**
* 根据ID获取单个假日设置信息。
*
* @param id 节假日设置ID
* @return 节假日设置视图对象
*/
AttendanceHolidaySettingVo getOne(String id);
/**
* 删除指定的假日设置信息。
*
* @param id 节假日设置ID
*/
void del(String id);
/**
* 初始化假日设置。
*
* @param groupId 考勤组ID
*/
void initHolidaySetting(String groupId);
/**
* 为指定租户自动授予假期余额。
*
* @param tenantId 租户ID
*/
// void autoGrantBalance(String tenantId);
/**
* 获取启用状态的假日设置信息。
*
* @param groupIds 考勤组ID列表
* @param attendanceGroupVos 考勤组视图对象列表
* @return 启用的假日设置信息映射
*/
Map<String, List<AttendanceHolidaySettingEntity>> getEnableFestivalSetting(List<String> groupIds, List<AttendanceGroup> attendanceGroupVos);
/**
* 保存假日设置信息。
*
* @param dto 假日设置数据传输对象
*/
void save(AttendanceHolidaySettingDto dto);
/**
* 更改假日设置信息的启用状态。
*
* @param id 假日设置ID
* @param enable 启用状态0禁用1启用
*/
void changeStatus(String id, Integer enable);
}

View File

@@ -0,0 +1,79 @@
package jnpf.attendance.service;
import com.github.pagehelper.PageInfo;
import jnpf.entity.attendance.AttendanceLeaveType;
import jnpf.exception.ApproveException;
import jnpf.model.attendance.dto.AttendanceLeaveRulesDto;
import jnpf.model.attendance.dto.AttendanceLeaveRulesQueryDto;
import jnpf.model.attendance.vo.attendance.AttendanceLeaveRulesVo;
import jnpf.model.common.PageDto;
import java.util.List;
/**
* @author panpan
*/
public interface AttendanceLeaveRulesService {
/**
* 列表
* @param attendanceLeaveRulesQueryDto 搜索条件
* @return 列表
*/
PageInfo<AttendanceLeaveRulesVo> list(AttendanceLeaveRulesQueryDto attendanceLeaveRulesQueryDto);
/**
* 创建
* @param attendanceLeaveRulesDto 创建参数
*/
void create(AttendanceLeaveRulesDto attendanceLeaveRulesDto) throws Exception;
/**
* 修改
* @param attendanceLeaveRulesDto 修改参数
*/
void update(AttendanceLeaveRulesDto attendanceLeaveRulesDto) throws Exception;
/**
* 详情
* @param id 主键值
*/
AttendanceLeaveRulesVo detail(String id);
/**
* 删除
* @param id 主键值
*/
void delete(String id);
/**
* 修改状态
* @param attendanceLeaveRulesDto 修改参数
*/
void updateState(AttendanceLeaveRulesDto attendanceLeaveRulesDto);
/**
* 获取用户请假列表
* @return 列表
*/
List<AttendanceLeaveRulesVo> getUserLeaveList(List<AttendanceLeaveType> leaveTypes);
/**
* 2.0自动授予请假余额
* @param tenantId 租户ID
*/
void autoGrantBalance(String tenantId);
/**
* 删除假期类型关联的规则
* @param id 假期类型Id
*/
void deleteByTypeId(String id);
/**
* 获取用户请假详情
* @param vo 假期类型
* @return 详情
*/
AttendanceLeaveRulesVo getUserLeaveDetail(AttendanceLeaveType vo,String userId) throws ApproveException;
}

View File

@@ -0,0 +1,52 @@
package jnpf.attendance.service;
import com.baomidou.mybatisplus.extension.service.IService;
import jnpf.entity.attendance.AttendanceLeaveType;
import jnpf.exception.ApproveException;
import jnpf.model.attendance.vo.attendance.AttendanceLeaveRulesVo;
import java.util.List;
/**
* @author panpan
*/
public interface AttendanceLeaveTypeService extends IService<AttendanceLeaveType> {
/**
* 创建或修改假期类型
* @param attendanceLeaveType 创建参数
*/
void typeSaveOrUpdate(AttendanceLeaveType attendanceLeaveType);
/**
* 删除假期类型
* @param id 假期类型 ID
*/
void deleteType(String id);
/**
* 获取用户请假列表
* @return 列表
*/
List<AttendanceLeaveRulesVo> getUserLeaveList();
/**
* 获取用户请假详情
* @param id 假期类型 ID
* @return 详情
*/
AttendanceLeaveRulesVo getUserLeaveDetail(String id,String userId) throws ApproveException;
/**
* 根据假期类型ID列表查询请假类型过滤已删除
* @param holidayIdList 假期类型ID列表
* @return 请假类型列表
*/
List<AttendanceLeaveType> getAttendanceLeaveTypes(List<String> holidayIdList);
/**
* 根据假期类型ID列表查询请假类型包含已删除供考勤结果下拉等场景
*
* @param holidayIdList 假期类型ID列表为空时查询全部
* @return 请假类型列表(含已删除)
*/
List<AttendanceLeaveType> getAttendanceLeaveTypesIncludeDeleted(List<String> holidayIdList);
}

View File

@@ -0,0 +1,27 @@
package jnpf.attendance.service;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.FtbAttendanceLineSchedulingConfig;
/**
* 划线排班配置Service
*
* @author ahua
* @version 2.1
* @copyright 引迈信息技术有限公司https://www.jnpfsoft.com
* @date 2025-12-30
*/
public interface AttendanceLineSchedulingConfigService extends SuperService<FtbAttendanceLineSchedulingConfig> {
/**
* 根据考勤组ID查询划线排班配置
*
* @param groupId 考勤组ID
* @return 划线排班配置
*/
FtbAttendanceLineSchedulingConfig getByGroupId(String groupId);
void noticeLineScheduling(String tenantId);
boolean saveOrUpdateLineSchedulingConfig(FtbAttendanceLineSchedulingConfig config);
}

View File

@@ -0,0 +1,98 @@
package jnpf.attendance.service;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.FtbAttendanceLineSchedulingPayrollHours;
import java.util.Date;
import java.util.List;
/**
* 划线排班计薪工时Service
*
* @author jnpf
* @since 2026-02-27
*/
public interface AttendanceLineSchedulingPayrollHoursService extends SuperService<FtbAttendanceLineSchedulingPayrollHours> {
/**
* 根据用户ID、考勤组ID和日期范围查询计薪工时列表
*
* @param userId 用户ID
* @param groupId 考勤组ID
* @param startDay 开始日期
* @param endDay 结束日期
* @return 计薪工时列表
*/
List<FtbAttendanceLineSchedulingPayrollHours> listByUserIdAndGroupId(String userId, String groupId, Date startDay, Date endDay);
/**
* 根据用户ID列表和日期范围查询计薪工时列表
*
* @param userIds 用户ID列表
* @param groupId 考勤组ID
* @param startDay 开始日期
* @param endDay 结束日期
* @return 计薪工时列表
*/
List<FtbAttendanceLineSchedulingPayrollHours> listByUserIdsAndGroupId(List<String> userIds, String groupId, Date startDay, Date endDay);
/**
* 根据日期范围查询计薪工时列表
*
* @param groupId 考勤组ID
* @param startDay 开始日期
* @param endDay 结束日期
* @return 计薪工时列表
*/
List<FtbAttendanceLineSchedulingPayrollHours> listByGroupId(String groupId, Date startDay, Date endDay);
/**
* 批量保存或更新划线排班计薪工时
*
* @param payrollHoursList 计薪工时列表
* @return 是否成功
*/
boolean saveOrUpdateBatch(List<FtbAttendanceLineSchedulingPayrollHours> payrollHoursList);
/**
* 根据用户ID、考勤组ID和日期删除计薪工时
*
* @param userId 用户ID
* @param groupId 考勤组ID
* @param day 日期
* @return 是否成功
*/
boolean deleteByUserIdAndGroupId(String userId, String groupId, Date day);
/**
* 根据考勤组ID和日期范围删除计薪工时
*
* @param groupId 考勤组ID
* @param startDay 开始日期
* @param endDay 结束日期
* @return 是否成功
*/
boolean deleteByGroupId(String groupId, Date startDay, Date endDay);
FtbAttendanceLineSchedulingPayrollHours listByUserIdsAndDays(String userId, String groupId, Date day);
/**
* 根据用户集合、考勤组ID和时间集合查询计薪工时
*
* @param userIds 用户ID集合
* @param groupId 考勤组ID
* @param days 日期集合
* @return 计薪工时列表
*/
List<FtbAttendanceLineSchedulingPayrollHours> listByUserIdsAndDays(List<String> userIds, String groupId, List<Date> days);
List<FtbAttendanceLineSchedulingPayrollHours> listByUserIdsAndDays(List<String> userIds, List<String> groupIds, List<Date> days);
/**
* 保存划线排班计薪工时集合(先清除后添加)
*
* @param payrollHoursList 计薪工时集合
* @return 是否成功
*/
boolean savePayrollHoursList(List<FtbAttendanceLineSchedulingPayrollHours> payrollHoursList);
}

View File

@@ -0,0 +1,116 @@
package jnpf.attendance.service;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.AttendanceLocationSetting;
import jnpf.exception.HandleException;
import jnpf.model.attendance.dto.AttendanceLocationSettingDto;
import jnpf.model.attendance.dto.SaveForStoreDto;
import jnpf.model.attendance.vo.AttendanceGroupVo;
import jnpf.model.attendance.vo.AttendanceLocationSettingVo;
import java.util.List;
import java.util.Map;
/**
* <p>
* 考勤组-考勤点配置表 服务类
* </p>
*
* @author ahua
* @since 2023-11-29
*/
public interface AttendanceLocationSettingService extends SuperService<AttendanceLocationSetting> {
/**
* 根据考勤组ID和类型查询考勤地点设置列表。
*
* @param groupId 考勤组ID
* @param type 类型(用于筛选设置)
* @return 考勤地点设置视图对象列表
*/
List<AttendanceLocationSettingVo> findList(String groupId, Integer type);
/**
* 根据门店信息保存考勤点数据
* @param saveForStore 存储门店信息
*/
void saveForStore(SaveForStoreDto saveForStore);
/**
* 根据门店id集合删除考勤点信息
* @param saveForStore 存储门店信息
*/
void delForStore(SaveForStoreDto saveForStore);
/**
* 获取当前考勤组考勤点关联门店id
* @param groupId 考勤组ID
* @return 门店id集合
*/
List<String> getStoreIds(String groupId);
/**
* 保存考勤地点设置信息。
*
* @param dto 考勤地点设置数据传输对象
* @throws HandleException 处理异常
*/
void save(AttendanceLocationSettingDto dto) throws HandleException;
/**
* 将单个用户添加到设备上。
*
* @param groupId 考勤组ID
* @param userId 用户ID
*/
void sendSingleUserToMachine(String groupId, String userId);
/**
* 从设备上删除单个用户。
*
* @param groupId 考勤组ID
* @param userId 用户ID
*/
void deleteUserToMachine(String groupId, String userId);
/**
* 初始化考勤地点设置。
*
* @param groupId 考勤组ID
*/
void initLocationSetting(String groupId);
/**
* 获取启用的考勤地点设置信息。
*
* @param groupIds 考勤组ID列表
* @return 启用的考勤地点设置映射
*/
Map<String, List<AttendanceLocationSetting>> getEnableLocationSetting(List<String> groupIds);
/**
* 获取启用的考勤组信息。
*
* @param groupId 考勤组ID
* @return 启用的考勤组视图对象列表
*/
List<AttendanceGroupVo> getEnableGroup(String groupId);
/**
* 删除指定的考勤地点设置信息。
*
* @param id 考勤地点设置ID
*/
void del(String id);
/**
* 更改考勤地点设置的启用状态。
*
* @param groupId 考勤组ID
* @param type 类型(用于区分设置类型)
* @param enable 启用状态0禁用1启用
*/
void changeStatus(String groupId, Integer type, Integer enable);
void hisLocationSetting(Map<String, String> group2orgMap, Map<String, String> org2GroupMap);
}

View File

@@ -0,0 +1,102 @@
package jnpf.attendance.service;
import com.github.pagehelper.PageInfo;
import jnpf.base.vo.PageListVO;
import jnpf.dto.PageDto;
import jnpf.exception.HandleException;
import jnpf.model.attendance.dto.MachineDto;
import jnpf.model.attendance.dto.MachineQueryDto;
import jnpf.model.attendance.dto.MachineUpdateDto;
import jnpf.model.attendance.vo.AttendanceMachineManageVo;
import jnpf.model.attendance.vo.MachineScopeVo;
import jnpf.model.attendance.vo.attendance.GroupMiniVo;
import jnpf.model.attendance.vo.attendance.GroupUserMiniVo;
import jnpf.model.attendance.vo.attendance.LogMiniVo;
import java.util.List;
/**
* 考勤机管理服务
*
* @author yanwenfu
* @create 2024-09-10
*/
public interface AttendanceMachineManageService {
/**
* 考勤机管理 - 考勤组列表
* @param machineId 考勤机id
* @return java.util.List<jnpf.model.attendance.vo.attendance.GroupMiniVo>
*/
List<GroupMiniVo> getGroupList(String machineId);
/**
* 考勤机管理 - 考勤机列表
* @param queryDto 查询条件
* @return jnpf.base.vo.PageListVO<jnpf.model.attendance.vo.AttendanceMachineManageVo>
*/
PageListVO<AttendanceMachineManageVo> getMachineList(MachineQueryDto queryDto);
/**
* 移除考勤机关联的考勤组
*
* @param groupIds 需要移除关联的考勤组
* @param moveTo 移动到哪个考勤组
* @param userIds 需要移动的成员
*/
void removeMachineRelation(List<String> userIds, String moveTo, List<String> groupIds);
/**
* 考勤机管理 - 添加考勤机
* @param machineDto 考勤机信息
*/
void addMachine(MachineDto machineDto) throws HandleException;
/**
* 考勤机管理 - 编辑考勤机
* @param id 考勤机id
* @param machineUpdateDto 考勤机信息
*/
void updateMachine(String id, MachineUpdateDto machineUpdateDto) throws HandleException;
/**
* 考勤机管理 - 移除
* @param id 考勤机id
*/
void deleteMachine(String id) throws HandleException;
/**
* 考勤机管理 - 考勤组成员列表/考勤变更人员查询
* @param groupId 考勤组id
* @return java.util.List<jnpf.model.attendance.vo.attendance.GroupUserMiniVo>
*/
List<GroupUserMiniVo> getGroupUserList(String groupId);
/**
* 考勤机管理 - 人脸库
* @param id 考勤机id
* @return java.util.List<jnpf.model.attendance.vo.attendance.GroupUserMiniVo>
*/
List<GroupUserMiniVo> getMachineMemberList(String id);
/**
* 查询考勤机打卡记录(查往前3个月的数据)
* @param id 考勤机id
* @param pageQuery 分页
* @return com.github.pagehelper.PageInfo<jnpf.model.attendance.vo.attendance.LogMiniVo>
*/
PageInfo<LogMiniVo> getLogList(String id, PageDto pageQuery);
/**
* 同步考勤机成员
* @param id 考勤机id
*/
List<GroupUserMiniVo> syncMachineMemberData(String id);
/**
* 考勤机管理 - 查询考勤机更新信息
* @param id 考勤机id
* @return jnpf.model.attendance.vo.MachineScopeVo
*/
MachineScopeVo getUpdateDetail(String id);
}

View File

@@ -0,0 +1,13 @@
package jnpf.attendance.service;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.AttendanceMachineSync;
/**
* 考勤机同步服务
*
* @author yanwenfu
* @create 2024-10-24
*/
public interface AttendanceMachineSyncService extends SuperService<AttendanceMachineSync> {
}

View File

@@ -0,0 +1,50 @@
package jnpf.attendance.service;
import com.baomidou.mybatisplus.extension.service.IService;
import jnpf.entity.attendance.AttendanceNoticeEntity;
import jnpf.model.attendance.dto.NoticeContentInfoDto;
import jnpf.model.attendance.dto.NoticeSaveDto;
import jnpf.model.attendance.vo.NoticeConfirmListVo;
import jnpf.model.attendance.vo.NoticeContentInfoVo;
/**
* 考勤消息通知
*
* @author shitou
* @email shitou@niujiekeji.com
* @date 2024-08-08 10:49:41
*/
public interface AttendanceNoticeService extends IService<AttendanceNoticeEntity> {
/**
* 获取内容详情
*
* @param req 获取小修内容详情的请求数据传输对象
* @return 返回通知内容信息的值对象
*/
NoticeContentInfoVo getContentInfo(NoticeContentInfoDto req);
/**
* 通知记录存储
*
* @param noticeSaveDto 通知保存的数据传输对象,包含需要保存的通知信息
*/
void noticeSave(NoticeSaveDto noticeSaveDto);
/**
* 消息确认
*
* @param id 需要进行消息确认的通知ID
*/
void noticeConfirm(String id);
/**
* 获取消息确认列表
*
* @param id 用于获取确认列表的通知ID
* @return 返回通知确认列表的值对象
*/
NoticeConfirmListVo getNoticeConfirmList(String id);
}

View File

@@ -0,0 +1,39 @@
package jnpf.attendance.service;
import jnpf.entity.PermissionDict;
import jnpf.exception.HandleException;
import jnpf.model.attendance.dto.SavePermissionDto;
import jnpf.model.attendance.vo.PermissionDictVo;
import java.util.List;
import java.util.Map;
public interface AttendancePermissionDictService {
/**
* 保存字典信息
* @param savePermissionDto 保存参数
*/
void save(SavePermissionDto savePermissionDto) throws HandleException;
/**
* 查询权限字典列表
* @param moduleType 模块类型 1.考勤
* @return List
*/
List<PermissionDictVo> queryPermissionDictList(Integer moduleType);
/**
* 删除权限字典
* @param id 指定Id
*/
void delete(String id);
/**
* 权限字典详情
* @param id 指定Id
* @return PermissionDict
*/
PermissionDict detail(String id);
}

View File

@@ -0,0 +1,16 @@
package jnpf.attendance.service;
import jnpf.entity.attendance.AttendanceQuickTemplateItemEntity;
import jnpf.base.service.SuperService;
/**
* <p>
* 快速模板-单天模板 服务类
* </p>
*
* @author ahua
* @since 2023-11-28
*/
public interface AttendanceQuickTemplateItemService extends SuperService<AttendanceQuickTemplateItemEntity> {
}

View File

@@ -0,0 +1,63 @@
package jnpf.attendance.service;
import jnpf.entity.attendance.AttendanceQuickTemplateEntity;
import jnpf.base.service.SuperService;
import jnpf.model.attendance.dto.QuickTemDto;
import jnpf.model.attendance.dto.QuickTemplateDto;
import jnpf.model.attendance.vo.AttendanceQuickTemplateVo;
import jnpf.model.attendance.vo.attendance.QuickTemVo;
import java.util.List;
/**
* <p>
* 考勤配置-快速模板 服务类
* </p>
*
* @author ahua
* @since 2023-11-28
*/
public interface AttendanceQuickTemplateService extends SuperService<AttendanceQuickTemplateEntity> {
/**
* 根据考勤组ID查询快速模板列表。
*
* @param groupId 考勤组ID
* @return 快速模板视图对象列表
*/
List<AttendanceQuickTemplateVo> findList(String groupId);
/**
* 根据快速模板ID查询单个快速模板。
*
* @param templateId 快速模板ID
* @return 快速模板视图对象
*/
AttendanceQuickTemplateVo findOne(String templateId);
/**
* 保存快速模板信息。
*
* @param dto 快速模板数据传输对象
*/
void save(QuickTemplateDto dto);
/**
* 删除指定的快速模板信息。
*
* @param id 快速模板ID
*/
void del(String id);
/**
* 新版考勤快速排班模板
* @param dto 快速排班信息
*/
void saveOrUpdateNew(QuickTemDto dto);
/**
* 新版考勤快速排班列表
* @param groupId 考勤组Id
*/
List<QuickTemVo> findNewList(String groupId);
}

View File

@@ -0,0 +1,17 @@
package jnpf.attendance.service;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.AttendanceRepair;
/**
* 补卡次数服务
*
* @author yanwenfu
* @create 2024-07-03
*/
public interface AttendanceRepairService extends SuperService<AttendanceRepair> {
AttendanceRepair getAttendanceRepair(String userId, String groupId);
AttendanceRepair getAttendanceRepairByDate(String applyDate, String userId, String groupId);
}

View File

@@ -0,0 +1,30 @@
package jnpf.attendance.service;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.AttendanceSealSetting;
import jnpf.model.attendance.dto.MonthAutoSealSettingDto;
import jnpf.model.attendance.vo.attendance.MonthAutoSealSettingVo;
public interface AttendanceSealSettingService extends SuperService<AttendanceSealSetting> {
/**
* 自动封账设置详情
*
* @return 自动封账设置详情
*/
MonthAutoSealSettingVo getAutoSealSettingInfo();
/**
* 自动封账设置
*
* @param dto 自动封账设置参数
* @return 自动封账设置结果
*/
Boolean autoSealSetting(MonthAutoSealSettingDto dto);
/**
* 考勤封账-自动封账定时器
*
* @return 自动封账结果
*/
Boolean autoSealTimer(String tenantId);
}

View File

@@ -0,0 +1,82 @@
package jnpf.attendance.service;
import com.github.pagehelper.PageInfo;
import jnpf.base.ActionResult;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.AttendanceShiftNameEntity;
import jnpf.exception.HandleException;
import jnpf.model.attendance.dto.FixedClassGroupDto;
import jnpf.model.attendance.dto.ShiftNameDto;
import jnpf.model.attendance.dto.ShiftNameQueryDto;
import jnpf.model.attendance.vo.AttendanceShiftSettingPeriodVo;
import jnpf.model.attendance.vo.SecondmentDateVo;
import jnpf.model.attendance.vo.attendance.FixedClassShiftVo;
import jnpf.model.attendance.vo.attendance.ShiftNameListVo;
import jnpf.model.attendance.vo.attendance.ShiftNameVo;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* @Author huanglinpan
* @Date 2024/5/9 10:06
* @Version 1.0 (版本号)
*/
public interface AttendanceShiftNameSettingService extends SuperService<AttendanceShiftNameEntity> {
/**
* 新增/修改班次名称
* @param dto 班次名称信息
*/
ActionResult save(ShiftNameDto dto);
Boolean fixedPeriodSingleConflict(Date date, List<SecondmentDateVo> list, AttendanceShiftSettingPeriodVo period);
/**
* 起停班次
* @param shiftNameId 班次名称Id
* @param enable 状态1启用 2停用
* @param updateShift 是否修改之前班次1 保持之前班次 2修改之前的班次
*/
ActionResult changeStatus(String shiftNameId, Integer enable, Integer updateShift);
/**
* 删除班次
* @param shiftNameId 班次Id
* @return 删除结果
*/
ActionResult delete(String shiftNameId);
/**
* 获取班次详情
* @param shiftNameId 班次Id
* @return 详情
*/
ShiftNameVo getDetail(String shiftNameId);
/**
* 获取班次详情
* @param shiftIds 班次时段Id
* @return 详情
*/
Map<String, ShiftNameVo> getDetailList(List<String> shiftIds);
/**
* 获取固定排班班次详情
* @param groupId 考勤组
*/
List<FixedClassShiftVo> getFixedClass(String groupId);
/**
* 编辑考勤组固定排班
* @param dto 固定排班对象
*/
ActionResult saveOrUpdateFixedClass(FixedClassGroupDto dto);
/**
* 考勤组班次列表
* @param queryDto 考勤组查询信息
* @return 列表
*/
PageInfo<ShiftNameListVo> getList(ShiftNameQueryDto queryDto) throws HandleException;
}

View File

@@ -0,0 +1,16 @@
package jnpf.attendance.service;
import jnpf.entity.attendance.AttendanceShiftSettingPeriodEntity;
import jnpf.base.service.SuperService;
/**
* <p>
* 考勤组-考勤配置-时段 服务类
* </p>
*
* @author ahua
* @since 2023-11-22
*/
public interface AttendanceShiftSettingPeriodService extends SuperService<AttendanceShiftSettingPeriodEntity> {
}

View File

@@ -0,0 +1,112 @@
package jnpf.attendance.service;
import jnpf.base.service.SuperService;
import jnpf.entity.AttendanceGroup;
import jnpf.entity.attendance.AttendanceShiftSettingEntity;
import jnpf.exception.HandleException;
import jnpf.model.attendance.dto.AttendanceShiftDto;
import jnpf.model.attendance.vo.AttendanceShiftSettingVo;
import jnpf.model.attendance.vo.ShiftPeriodVo;
import java.util.List;
import java.util.Map;
/**
* <p>
* 考勤组配置-考勤配置 服务类
* </p>
*
* @author ahua
* @since 2023-11-22
*/
public interface AttendanceShiftSettingService extends SuperService<AttendanceShiftSettingEntity> {
/**
* 根据考勤组ID和考勤组视图列表获取启用的班次设置信息。
*
* @param groupIds 考勤组ID列表
* @param attendanceGroupVos 考勤组视图对象列表
* @return 启用的班次设置信息映射
*/
Map<String, AttendanceShiftSettingVo> getEnableShiftSetting(List<String> groupIds, List<AttendanceGroup> attendanceGroupVos);
/**
* 初始化班次设置。
*
* @param groupId 考勤组ID
*/
void initShiftSetting(String groupId);
/**
* 根据考勤组ID获取所有班次设置。
*
* @param groupId 考勤组ID
* @return 班次设置视图对象
*/
AttendanceShiftSettingVo findAllByGroupId(String groupId);
/**
* 根据考勤组ID获取单个班次设置。
*
* @param groupId 考勤组ID
* @return 班次设置视图对象
*/
AttendanceShiftSettingVo findByGroupId(String groupId);
/**
* 保存班次设置信息。
*
* @param dto 班次设置数据传输对象
* @throws HandleException 处理异常
*/
void save(AttendanceShiftDto dto) throws HandleException;
/**
* 更改系统类型。
*
* @param groupId 考勤组ID
* @param systemType 系统类型
*/
void changeSystemType(String groupId, Integer systemType);
/**
* 删除指定的班次周期。
*
* @param periodId 班次周期ID
*/
void delPeriod(String periodId);
/**
* 更改班次设置的启用状态。
*
* @param groupId 考勤组ID
* @param enable 启用状态0禁用1启用
* @param byGroupId 班次设置视图对象
*/
void changeStatus(String groupId, Integer enable, AttendanceShiftSettingVo byGroupId);
/**
* 根据考勤组ID获取班次周期列表。
*
* @param groupId 考勤组ID
* @return 班次周期视图对象列表
*/
List<ShiftPeriodVo> periodList(String groupId);
/**
* 智能排班专用:便于区分 §6.1(未取得班次定义)与 §6.2(已取得定义但班次列表为空)。
*
* @return {@code null} — 未取得该考勤组启用班次设置(与「占位空列表」不同);{@link Collections#emptyList()} —
* 已取得设置但未配置班次周期;否则为周期列表。
*/
List<ShiftPeriodVo> periodListForIntelligentSchedule(String groupId);
/**
* 自我排班的班次列表
*
* @return 班次周期视图对象列表
*/
List<ShiftPeriodVo> periodListForSelfScheduling();
void hisShiftSetting(Map<String, String> group2orgMap, Map<String, String> org2GroupMap);
}

View File

@@ -0,0 +1,176 @@
package jnpf.attendance.service;
import jnpf.exception.HandleException;
import jnpf.model.attendance.dto.BatchSaveGroupAdmin;
import jnpf.model.attendance.dto.GroupFilterDto;
import jnpf.model.attendance.dto.SaveGroupAdmin;
import jnpf.model.attendance.dto.SaveSuperAdminDto;
import jnpf.model.attendance.vo.AttendanceManagerDetailVo;
import jnpf.model.attendance.vo.AttendanceUserVo;
import jnpf.model.attendance.vo.CurUserPermissionVo;
import jnpf.model.attendance.vo.permission.ActionPermissionVo;
import jnpf.model.attendance.vo.permission.ApprovalSettingVo;
import jnpf.model.attendance.vo.permission.AttendanceTeamSetVo;
import jnpf.model.attendance.vo.permission.app.ManagerPermissionVo;
import jnpf.model.authority.vo.role.FtbPermissionPositionMenuVO;
import java.util.List;
import java.util.Map;
public interface AttendanceSuperAdminService {
/**
* 添加考勤组考勤管理员
* @param saveSuperAdminDto 保存信息
*/
void add(SaveSuperAdminDto saveSuperAdminDto) throws HandleException;
/**
* 删除超级管理员
* @param userIds 用户id
*/
void delete(List<String> userIds);
/**
* 获取考勤组超级管理员列表
* @return List<AttendanceUserVo>
*/
List<AttendanceUserVo> querySuperAdmin(String name);
/**
* 保存考勤组管理员
* @param saveGroupAdmin 保存信息
*/
void addGroupAdmin(SaveGroupAdmin saveGroupAdmin) throws Exception;
/**
* 批量添加考勤组管理员
* @param batchSaveGroupAdmin 保存信息
*/
void batchAddGroupAdmin(BatchSaveGroupAdmin batchSaveGroupAdmin);
/**
* 修改考勤组管理员权限
* @param saveGroupAdmin 保存信息
*/
void updateGroupAdmin(SaveGroupAdmin saveGroupAdmin);
/**
* 删除考勤组管理员
*/
void deleteGroupAdmin(SaveGroupAdmin saveGroupAdmin);
/**
* 查看考勤组下管理员列表
* @param groupId 考勤组
* @return List<AttendanceGroupAdminVo>
*/
Map<String, Object> listGroupAdmin(String groupId);
/**
* 获取管理员包含当前组管理员、上级子组权限管理员、超级管理员其中key为 -1时超级管理员集合
* @param groupIds 考勤组id集合
* @return Map<String, List < String>> key为 groupId value为管理员userId集合
*/
Map<String, List<String>> queryUserForCurrAndUpChildAndSuper(List<String> groupIds);
/**
* 根据指定条件查询权限信息
* 该方法通过接收群组ID、父权限代码和子权限代码列表作为参数
* 查询并返回一个映射其中键为群组ID值为该群组下匹配指定权限代码的权限列表
*
* @param groupIds 群组ID列表用于指定需要查询权限的群组
* @param parentCodes 父权限代码列表,用于指定需要查询的父权限范围
* @param childCodes 子权限代码列表,用于指定需要查询的子权限范围
* @return 返回一个映射,每个键值对表示一个群组及其对应的权限列表
*/
Map<String, List<String>> queryPermissionBySpecify(List<String> groupIds, List<String> parentCodes, List<String> childCodes);
/**
* 获取当前登录用户权限
* @param groupId 考勤组id
* @return CurUserPermissionVo
*/
CurUserPermissionVo getByUserId(String groupId);
/**
* 是否是考勤超级管理员
* @param userId 用户id
* @return Boolean
*/
Boolean isSuperAdmin(String userId);
/**
* 考勤组管理员详情
* @param groupId 考勤组id
* @param userId 用户id
* @return AttendanceGroupVo
*/
AttendanceManagerDetailVo adminDetail(String groupId, String userId);
/**
* 获取当前用户权限
* @param userId 用户id
* @param levelCodeList 考勤组层级编码
* @param permissionName 权限名称
* @return CurUserPermissionVo
*/
CurUserPermissionVo queryPermissionByUserId(String userId, List<String> levelCodeList, String permissionName);
/**
* 是否有查看权限
* @param groupId 考勤组id
* @return Boolean
*/
Boolean isViewPermission(String groupId);
/**
* 获取操作权限
* @param groupId 考勤组id
* @return ActionPermissionVo
*/
ActionPermissionVo getActionPermission(String groupId);
/**
* 是否是考勤组超级管理员||系统超级管理员
* @return Boolean
*/
Boolean isGlobalSetting();
/**
* 是否是考勤组管理员
* @return ManagerPermissionVo
*/
ManagerPermissionVo isManager();
/**
* 获取考勤组审批设置
* @param groupId 考勤组id
* @param type 审批类型 1.常规补卡审批 2.调整出勤结果审批 3.外勤审批 4.请假审批 5.加班审批
* @return ApprovalSettingVo
*/
ApprovalSettingVo getApprovalSettingInfo(String groupId, Integer type);
/**
* 根据用户id集合查询所属的权限-查询所有权限
* @param userIds 用户id集合
* @return FtbPermissionPositionMenuVO.FtbPermissionPositionMenuInnerVO
*/
List<FtbPermissionPositionMenuVO.FtbPermissionPositionMenuInnerVO> queryPermissionListByUserIds(List<String> userIds);
/**
* 获取考勤组设置
*
* @param dto 考勤组id
* @return AttendanceTeamSetVo
*/
AttendanceTeamSetVo getTeamSet(GroupFilterDto dto);
/**
* 设置月报通知
*
* @param dto 考勤组id
* @return Boolean
*/
Boolean setMonthNotice(GroupFilterDto dto);
}

View File

@@ -0,0 +1,54 @@
package jnpf.attendance.service;
import com.baomidou.mybatisplus.extension.service.IService;
import jnpf.entity.attendance.AttendanceBalanceRecordEntity;
import jnpf.model.attendance.vo.attendance.AttendanceLeaveRulesVo;
import jnpf.model.attendance.vo.attendance.AttendancePublicHolidayBalance;
import jnpf.model.attendance.vo.attendance.LeaveConsumptionDetailVo;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
/**
* @author panpan
* @description 用户余额获取记录表 Service接口
* @version V2.0
*/
public interface AttendanceUserBalanceRecordService extends IService<AttendanceBalanceRecordEntity> {
/**
* 回滚用户余额记录
* @param balanceId 假日类型Idftb_attendance_leave_rules存休时为空
* @param needRetirementLeave 需回滚的数据
* @param leaveName 请假类型名称
* @param isPublicHoliday 是否是公休触发--公休已单独处理日志这边不记录对应的日志
*/
void rollbackUserBalanceRecord(List<AttendancePublicHolidayBalance> needRetirementLeave,String balanceId,String leaveName,boolean isPublicHoliday);
/**
* 需要转存劵的用户余额记录 (存休不能触发)
* @param ruleIds 假日类型Idftb_attendance_leave_rules
* @param userIds 用户id
*/
void needRetirementBalance(List<String> ruleIds,List<String> userIds);
/**
* 请假模拟消费
* @param userLeaveDetail 假日类型对象
* @param userId 用户id
* @param balance 余额
* @return 未抵扣的余额
*/
LeaveConsumptionDetailVo leaveSimulationConsumption(String userId , BigDecimal balance, AttendanceLeaveRulesVo userLeaveDetail) ;
/**
* 请假消费劵
* @param userLeaveDetail 假日类型ftb_attendance_leave_rules存休时为空
* @param userId 用户id
* @param balance 余额
* @return 未抵扣的余额
*/
LeaveConsumptionDetailVo leaveConsumption(String userId , BigDecimal balance, AttendanceLeaveRulesVo userLeaveDetail,Date startTime, Date endTime,String applyId) ;
}

View File

@@ -0,0 +1,86 @@
package jnpf.attendance.service;
import jnpf.entity.attendance.AttendanceLeaveRules;
import jnpf.exception.HandleException;
import jnpf.model.attendance.dto.AttendanceLeaveRulesDto;
import jnpf.model.attendance.dto.AttendanceUserBalanceDto;
import jnpf.model.attendance.dto.AttendanceUserBalanceListQueryDto;
import jnpf.model.attendance.vo.attendance.*;
import java.math.BigDecimal;
import java.util.List;
/**
* @author panpan
*/
public interface AttendanceUserBalanceService {
/**
* 列表
*
* @param queryDto 查询条件
* @return 列表
*/
AttendanceUserBalanceListVo list(AttendanceUserBalanceListQueryDto queryDto) throws HandleException;
/**
* 编辑、批量编辑余额
*
* @param userBalanceDto 余额
*/
void updateUserBalance(AttendanceUserBalanceDto userBalanceDto);
/**
* 获取余额详情
*
* @param userBalanceDto 详情
* @return 详情
*/
AttendanceUserBalanceVo getDetail(AttendanceUserBalanceDto userBalanceDto);
/**
* 获取标题
*
* @param userBalanceDto 标题
* @return 标题
*/
AttendanceUserTitleVo getTitle(AttendanceUserBalanceDto userBalanceDto);
/**
* 修改用户公休余额(公休转存休使用)日志
*
* @param needRetirementLeave 需转存休
*/
void addUserBalances(List<AttendancePublicHolidayBalance> needRetirementLeave);
/**
* 撤销用户公休余额(公休转存休使用) 修改余额及退卷记录
*
* @param needRetirementLeave 需撤销休
*/
void rollbackUserBalance(List<AttendancePublicHolidayBalance> needRetirementLeave);
/**
* 加班触发
*
* @param overtimeInfoList 加班信息
*/
void overTime(List<OvertimeInfoVo> overtimeInfoList, String tenantId);
/**
* 获取指定类型的余额
*
* @param balanceId LeaveBalanceId 类型Id 查询存休时 为null
* @param userId 用户Id
* @param isRetirementLeave 是否统计存休 LeaveBalanceId不为空且对应的假期规则能使用存休抵扣时才为 true
* @return 余额
*/
BigDecimal getTotalBalance(String balanceId, String userId, boolean isRetirementLeave);
}

View File

@@ -0,0 +1,47 @@
package jnpf.attendance.service;
import jnpf.model.attendance.dto.UserFaceDto;
import jnpf.model.attendance.dto.MachineDealDto;
import jnpf.model.attendance.vo.UserFaceVo;
import java.util.List;
/**
* 人脸服务
*
* @author yanwenfu
* @create 2024-04-09
*/
public interface AttendanceUserFaceService {
/**
* 查询用户人脸
* @param userId 用户id
* @return jnpf.model.attendance.vo.UserFaceVo
*/
UserFaceVo getUserFace(String userId);
/**
* 新增用户人脸
* @param userFaceDto 人脸dto
*/
void addUserFace(UserFaceDto userFaceDto);
/**
* 编辑用户人脸
* @param userFaceDto 人脸dto
*/
void updateUserFace(UserFaceDto userFaceDto);
/**
* 删除用户人脸
* @param userId 用户id
*/
void deleteUserFace(String userId);
/**
* 考勤机处理
* @param machineDealDto 考勤机处理参数
*/
List<String> machineDeal(MachineDealDto machineDealDto);
}

View File

@@ -0,0 +1,305 @@
package jnpf.attendance.service;
import jnpf.attendance.dto.GroupUpdateByUserDTO;
import jnpf.base.service.SuperService;
import jnpf.entity.AttendanceGroupUser;
import jnpf.exception.HandleException;
import jnpf.message.model.permission.PermissionRelationOrganizeUserListDTO;
import jnpf.model.attendance.dto.DayStatisticsPageListDto;
import jnpf.model.attendance.dto.GroupUserQueryDto;
import jnpf.model.attendance.dto.JoinUserDto;
import jnpf.model.attendance.dto.UserSortModel;
import jnpf.model.attendance.model.OrganizeUserConsumerDTO;
import jnpf.model.attendance.vo.AttendanceGroupUserVo;
import jnpf.model.attendance.vo.GroupUserLineScheduleVo;
import jnpf.model.attendance.vo.SecondmentDateVo;
import jnpf.model.attendance.vo.attendance.ClockInExportVo;
import jnpf.model.attendance.vo.attendance.JoinGroupVo;
import jnpf.model.common.DateRangeDto;
import jnpf.permission.eum.v2.UserWorkStatusEnums;
import jnpf.permission.vo.v2.user.UserBoundVO;
import org.apache.commons.lang3.tuple.MutablePair;
import java.util.Date;
import java.util.List;
import java.util.Map;
public interface AttendanceUserService extends SuperService<AttendanceGroupUser> {
/**
* 根据考勤组查询成员列表
*
* @param groupId 考勤组ID
* @param name 用户名称
* @param type 用户类型
* @param userIds 用户ID列表
* @return 用户列表
*/
List<AttendanceGroupUserVo> queryUsersByGroupId(String groupId, String name, Integer type, List<String> userIds, Date start,Date end);
List<String> getUserIds(List<String> organizeList, List<String> userIdList, Date start, Date end, Integer scopeOfAdaptation);
List<AttendanceGroupUser> getUserIdsAndGroupIds(List<String> organizeList, List<String> userIdList, Date start, Date end, Integer scopeOfAdaptation);
/**
* 对用户排序模型进行排序
* 该方法用于根据特定的排序规则对用户排序模型对象进行排序操作
* 它改变用户排序模型对象的顺序,以便后续处理或显示时符合预期的排序逻辑
*
* @param userSortModel 用户排序模型对象,包含需要被排序的数据和排序规则
* 这个参数不应为null否则排序操作将抛出异常
*/
void sort(UserSortModel userSortModel);
/**
* 根据用户和考勤组ID列表查询关联信息
*
* @param groupIds 考勤组ID列表
* @return 关联信息列表
*/
List<AttendanceGroupUser> queryByUsersGroupIds(List<String> groupIds);
/**
* 根据所有用户和考勤组ID列表查询关联信息
*
* @param groupIds 考勤组ID列表
* @return 关联信息列表
*/
List<AttendanceGroupUser> queryByAllUsersGroupIds(List<String> groupIds);
/**
* 查询所有用户和考勤组的关联信息
*
* @return 关联信息列表
*/
List<AttendanceGroupUser> queryAll();
/**
* 查询所有非外派人员的考勤组用户信息
* 此方法用于获取系统中所有不属于外派人员的考勤组用户列表它没有接受任何参数,
* 表示将返回数据库中符合条件的所有用户信息
*
* @return 非外派人员的考勤组用户列表如果列表为空,表示没有符合条件的用户
*/
List<AttendanceGroupUser> queryAllForNotSecondment();
/**
* 根据用户ID列表查询用户和考勤组的关联信息
*
* @param userIds 用户ID列表
* @return 关联信息列表
*/
List<AttendanceGroupUser> queryByUsersIds(List<String> userIds);
/**
* 根据用户ID列表查询所有用户的考勤组关联信息
*
* @param userIds 用户ID列表
* @return 关联信息列表
*/
List<AttendanceGroupUser> queryAllByUsersIds(List<String> userIds);
/**
* 根据时间范围、用户ID列表和考勤组ID列表查询用户和考勤组的关联信息
*
* @param start 开始时间
* @param end 结束时间
* @param userIds 用户ID列表
* @param groupIds 考勤组ID列表
* @return 关联信息列表
*/
List<AttendanceGroupUser> queryByUsersAndGroup(Date start, Date end, List<String> userIds, List<String> groupIds);
/**
* 根据时间范围、用户ID列表和考勤组ID列表查询用户和考勤组的关联信息并过滤借调人员
*
* @param start 开始时间
* @param end 结束时间
* @param userIds 用户ID列表
* @param groupIds 考勤组ID列表
* @return 关联信息列表
*/
List<AttendanceGroupUser> queryByUsersAndGroupFilterSecondment(Date start, Date end, List<String> userIds, List<String> groupIds);
List<AttendanceGroupUser> queryByUsersAndGroupFilterSecondment(Date start, Date end, List<String> userIds, List<String> groupIds, Boolean isContainsDeleteGroup);
/**
* 根据用户和小组过滤条件查询特定时间段内的出勤记录
* 此方法主要用于查询属于特定用户组的用户在指定时间范围内的出勤信息,
* 并可以根据需要选择是否包括已删除的小组中的用户
*
* @param start 开始日期,查询范围的起始时间
* @param end 结束日期,查询范围的结束时间
* @param userIds 用户ID列表用于指定需要查询的用户
* @param groupIds 小组ID列表用于指定用户所属的小组
* @param isContainsDeleteGroup 是否包含已删除小组的标志,
* 如果为true则结果中包含属于已删除小组的用户
* 如果为false则结果中不包含属于已删除小组的用户
* @return 返回符合查询条件的出勤记录列表
*/
List<AttendanceGroupUser> getAttendanceGroupUsersOfSecondment(Date start, Date end, List<String> userIds, List<String> groupIds, boolean isContainsDeleteGroup);
List<AttendanceGroupUser> getAttendanceGroupUsers(Date start, Date end, List<AttendanceGroupUser> attendanceGroupUsers);
/**
* 获取借调人员的考勤组信息
*
* @param start 开始时间
* @param end 结束时间
* @param userIds 用户ID列表
* @param groupIds 考勤组ID列表
* @return 考勤组信息列表
*/
List<AttendanceGroupUser> getAttendanceGroupUsersOfSecondment(Date start, Date end, List<String> userIds, List<String> groupIds);
/**
* 查询系统用户列表
*
* @param orgId 组织ID
* @param name 用户名称
* @return 用户列表
*/
List<AttendanceGroupUserVo> querySysUserList(String orgId, String name);
void orgUpdateHandle(List<PermissionRelationOrganizeUserListDTO> userList);
void addUsers(List<PermissionRelationOrganizeUserListDTO> userList, Boolean isOnboarding);
void removeUsers(List<PermissionRelationOrganizeUserListDTO> userList, Boolean isTurnover);
/**
* 用户加入考勤组
*
* @param joinUserDto 加入用户DTO
* @throws HandleException 处理异常
*/
void joinUsers(JoinUserDto joinUserDto) throws HandleException;
/**
* 批量删除用户以发送通知
*
* @param joinUserDto 加入用户DTO
*/
void batchDeleteUsersForSendNotice(JoinUserDto joinUserDto);
/**
* 批量删除考勤组成员
*
* @param joinUserDto 加入用户DTO
*/
void batchDeleteUsers(JoinUserDto joinUserDto);
/**
* 检查用户是否已经加入考勤组
*
* @param userId 用户ID
* @return 考勤组ID列表
* @throws HandleException 处理异常
*/
List<String> checkUserGroup(String userId) throws HandleException;
/**
* 批量获取用户加入考勤组的周期
*
* @param dateRangeDto 日期范围DTO
* @param groupIds 考勤组ID列表
* @param userIds 用户ID列表
* @return 用户周期映射
* @throws Exception 获取异常
*/
Map<String, Map<String, List<String>>> batchGetUserCycleList(DateRangeDto dateRangeDto, List<String> groupIds, List<String> userIds) throws Exception;
/**
* 借调考勤组变动通知
*
* @param tenantId 租户ID
* @return 处理结果
*/
Boolean userGroupUpdateBySecondNotice(String tenantId);
/**
* 花名册考勤组变更
* @param groupUpdateByUserDTO 考勤组变更DTO
*/
void groupUpdateByPersonnel(GroupUpdateByUserDTO groupUpdateByUserDTO);
/**
* 指定考勤组成员列表
*
* @param id 考勤组Id
* @param isPermissions 是否带权限
*/
List<AttendanceGroupUserVo> getGroupUserList(String id, Boolean isPermissions);
/**
* 获取指定考勤组中当前处于借调的用户原本所属考勤组信息
* @param groupId 考勤组Id
*/
List<AttendanceGroupUser> getSelfUsersBeLongToGroup(String groupId);
/**
* 获取指定日期员工所在考勤组集合
* @param groupUserQueryDto 查询参数DTO
*/
List<ClockInExportVo> getUsersDayByGroupIds(GroupUserQueryDto groupUserQueryDto, DayStatisticsPageListDto req);
/**
* 带权限查询指定考勤组及班组人员信息
* @param groupId 考勤组ID
* @param workGroupId 班组ID
* @return 用户信息集合
*/
List<UserBoundVO> getUserBoundVO(String groupId, String workGroupId);
/**
* 批量获取带权限查询指定考勤组及班组人员信息
* @param groupIds 考勤组ID集合
* @param workStatusEnums 用户工作状态枚举集合
* @return 用户信息集合
*/
List<UserBoundVO> batchGetUserBoundVO(List<String> groupIds, List<UserWorkStatusEnums> workStatusEnums);
/**
* 获取用户当前所属考勤组
*/
String getUserNowGroup();
/**
* 根据查询条件和分组信息获取签到导出数据列表
*
* @param groupUserQueryDto 查询条件,包含需要查询的分组用户相关信息
* @param usersByGroupVos 已按分组查询到的用户数据列表,用于进一步处理和生成签到导出数据
* @return 返回一个ClockInExportVo对象的列表包含根据查询条件和分组信息生成的签到导出数据
*/
List<ClockInExportVo> getClockInExportVoList(GroupUserQueryDto groupUserQueryDto, List<ClockInExportVo> usersByGroupVos);
/**
* 检查用户是否已经加入考勤组
* @param userIds 用户ID列表
*/
List<JoinGroupVo> checkUserJoinGroupToObject(String userIds);
/**
* 根据群组ID列表获取用户ID列表
* 本函数旨在通过一组群组ID来收集所有相关的用户ID这些用户ID代表了属于给定群组的所有用户
* 它主要用于需要了解特定群组包含哪些用户的应用场景中
*
* @param groupIds 群组ID列表用于查询相关的用户ID
* @return 包含所有与给定群组相关的用户ID的列表
*/
List<String> getGroupUserIds(List<String> groupIds);
List<AttendanceGroupUserVo> getGroupNowAllUserList(String groupId);
/**
* 按考勤组查询成员列表,并标识每位成员是否允许划线排班
* <p>
* 成员通过 {@link #getAttendanceGroupUsersOfSecondment(Date, Date, List, List)} 拉取,
* 每位成员是否允许划线排班由考勤组划线排班配置(员工类型/工作性质/岗位/指定成员)综合判定,
* 与排班界面 {@code canLineSchedule} 标识的口径保持一致。
*
* @param groupId 考勤组ID
* @return 成员列表,包含 userId、userName、positionId、positionName、canLineSchedule
*/
List<GroupUserLineScheduleVo> listLineScheduleUsersByGroupId(String groupId);
}

View File

@@ -0,0 +1,82 @@
package jnpf.attendance.service;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.AttendanceAppUserSetting;
import jnpf.model.attendance.dto.AppUserSettingQueryDto;
import jnpf.model.attendance.dto.AttendanceAppUserSettingDto;
import jnpf.model.attendance.vo.UserSettingVo;
import java.util.List;
/**
* @Author huanglinpan
* @Date 2024/8/8 10:54
* @Version 1.0 (版本号)
*/
public interface AttendanceUserSettingService extends SuperService<AttendanceAppUserSetting> {
/**
* 修改设置
* @param attendanceAppUserSettingDto 修改设置信息
*/
void saveOrUpdate(AttendanceAppUserSettingDto attendanceAppUserSettingDto);
/**
* 查询设置列表
* @param appUserSettingQueryDto 查询信息
*/
List<UserSettingVo> getList(AppUserSettingQueryDto appUserSettingQueryDto);
/**
* 查询设置列表
* @param associationId 关联Id与类型一起使用个人时表示用户Id考勤组时表示考勤组Id
* @param type 类型 1个人设置2考勤组设置
* @param code 编码
*/
List<UserSettingVo> getSettingList(String associationId, Integer type, String code);
/**
* 查询设置列表
* @param associationId 关联Id与类型一起使用个人时表示用户Id考勤组时表示考勤组Id
* @param type 类型 1个人设置2考勤组设置
* @param code 编码
*/
List<UserSettingVo> getSettingList(List<String> associationId, Integer type, String code);
/**
* 查询设置列表
* @param associationId 关联Id与类型一起使用个人时表示用户Id考勤组时表示考勤组Id
* @param type 类型 1个人设置2考勤组设置
* @param code 编码
*/
List<UserSettingVo> getSettingList(List<String> associationId, Integer type, List<String> code);
/**
* 校验web设置
* @param code 编码
*/
UserSettingVo checkWebSetting(String code);
/**
* 刷新用户定时提醒缓存
* @param userId 用户id
* @param value 值
* @param tenantId 租户id
*/
void refreshRemindRedisCache(String code, String userId, Integer value, String tenantId);
/**
* 批量保存设置
* @param attendanceAppUserSettingDto 保存数据
*/
void saveOrUpdateList(List<AttendanceAppUserSettingDto> attendanceAppUserSettingDto);
/**
* 获取新的用户设置列表
* 本方法用于根据查询条件获取用户设置的列表信息,以便在界面上展示或者进一步处理
*
* @param appUserSettingQueryDto 查询条件对象,包含查询用户设置所需的参数
* @return 返回一个UserSettingVo对象的列表表示查询到的用户设置信息
*/
List<UserSettingVo> getListNew(AppUserSettingQueryDto appUserSettingQueryDto);
}

View File

@@ -0,0 +1,60 @@
package jnpf.attendance.service;
import jnpf.base.UserInfo;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.AttendanceClockInResult;
import jnpf.entity.attendance.AttendanceMachineManage;
import jnpf.entity.attendance.FtbAttendanceDailyRule;
import jnpf.exception.QueryException;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 打卡服务2.0
*
* @author yanwenfu
* @create 2025-09-23
*/
public interface ClockInResultService extends SuperService<AttendanceClockInResult> {
/**
* 查询今天可以打卡的出勤规则
* @param today 日期
* @param userInfo 用户信息
* @return java.util.List<jnpf.entity.attendance.FtbAttendanceDailyRule>
*/
List<FtbAttendanceDailyRule> getTodayRuleList(Date today, UserInfo userInfo);
/**
* 查询所有用户今天可以打卡的出勤规则
* @param today 日期
* @param userId 用户id(有则查单人, 无则查全部)
* @return java.util.List<jnpf.entity.attendance.FtbAttendanceDailyRule>
*/
Map<String, List<FtbAttendanceDailyRule>> getTodayRuleListByUser(Date today, String userId);
/**
* 查询指定用户的出勤规则[批量]
* @param groupedMap k:userId_targetDate v:当日+前一日的出勤规则
* @param userGroupMap 用户考勤组map
* @return java.util.Map<java.lang.String,java.util.List<jnpf.entity.attendance.FtbAttendanceDailyRule>>
*/
Map<String, List<FtbAttendanceDailyRule>> getRuleListByUserDay(Map<String, List<FtbAttendanceDailyRule>> groupedMap, Map<String, List<String>> userGroupMap);
/**
* 清除异常的出勤规则
* @param ruleList 出勤规则列表
* @param userId 用户id
* @return java.util.List<jnpf.entity.attendance.FtbAttendanceDailyRule>
*/
List<FtbAttendanceDailyRule> clearErrorRule(List<FtbAttendanceDailyRule> ruleList, String userId, Date date, List<String> effectGroupIds);
/**
* 获取用户绑定的考勤机
* @param userId 用户id
* @return java.util.List<jnpf.entity.attendance.AttendanceMachineManage>
*/
List<AttendanceMachineManage> getMachineList(String userId, String tenantId);
}

View File

@@ -0,0 +1,13 @@
package jnpf.attendance.service;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.AttendanceCommonSetting;
/**
* 公共配置服务
*
* @author yanwenfu
* @create 2025-09-19
*/
public interface CommonSettingService extends SuperService<AttendanceCommonSetting> {
}

View File

@@ -0,0 +1,27 @@
package jnpf.attendance.service;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.DailyRuleChange;
import java.util.List;
/**
* 出勤规则变更服务
*
* @author yanwenfu
* @create 2026-05-20
*/
public interface DailyRuleChangeService extends SuperService<DailyRuleChange> {
/**
* 出勤规则变更执行
* @return boolean
*/
boolean dailyRuleChangeExecute();
/**
* 批量保存
* @param list 出勤规则变更list
*/
void saveRecordBatch(List<DailyRuleChange> list);
}

View File

@@ -0,0 +1,37 @@
package jnpf.attendance.service;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.AttendanceEnableBalance;
import jnpf.model.attendance.vo.attendance.OvertimeSalaryHoursJsonVo;
import jnpf.model.attendance.vo.attendance.OvertimeSalaryHoursVo;
import java.util.List;
import java.util.Map;
/**
* 加班余额记录[不存休,仅记录]服务
*
* @author yanwenfu
* @create 2025-10-03
*/
public interface EnableBalanceService extends SuperService<AttendanceEnableBalance> {
/**
* 获取加班算薪加班小时数(不计算存休-结算薪酬)
*
* @param startDate 开始时间
* @param endDate 结束时间
* @param userIds 用户ID
* @return 加班算薪加班小时数(
*/
Map<String, OvertimeSalaryHoursVo> getOvertimeSalary(String startDate, String endDate, List<String> userIds);
/**
* 获取加班算薪加班Json小时数(不计算存休-结算薪酬)
*
* @param startDate 开始时间
* @param endDate 结束时间
* @param userIds 用户ID
* @return 加班算薪加班小时数(
*/
List<OvertimeSalaryHoursJsonVo> getOvertimeSalaryJson(String startDate, String endDate, List<String> userIds);
}

View File

@@ -0,0 +1,14 @@
package jnpf.attendance.service;
/**
* @Author huanglinpan
* @Date 2024/7/1 9:16
* @Version 1.0 (版本号)
*/
public interface InitializationService {
/**
* 初始化存休 有效期考勤v1.3版本
*/
Integer storageRest();
}

View File

@@ -0,0 +1,36 @@
package jnpf.attendance.service;
import java.util.List;
import java.util.Map;
/**
* KIPS服务
*
* @author yanwenfu
* @create 2024-04-01
*/
public interface IsPerfMachineService {
/**
* 显示欢迎信息的方法
* 此方法用于向用户展示欢迎信息
*/
void welcome();
/**
* 更新应用配置的方法
* 此方法接受一个参数映射,用于更新应用的配置信息
*
* @param params 包含配置参数的映射,其中键是参数名,值是参数值
*/
void updateApp(Map<String, Object> params);
/**
* 获取所有在线客户端列表的方法
* 此方法用于获取当前所有在线客户端的列表
*
* @return 包含所有在线客户端标识的列表
*/
List<String> getAllOnlineClient();
}

View File

@@ -0,0 +1,47 @@
package jnpf.attendance.service;
import jnpf.base.UserInfo;
import jnpf.enums.attendance.MachineEnum;
import jnpf.permission.model.user.PartUserInfoVo;
import java.util.List;
/**
* 考勤机策略模式
*
* @author yanwenfu
* @create 2024-04-03
*/
public interface MachineStrategy {
/**
* 获取当前上下文相关的机器枚举类型
* 此方法用于提供当前执行环境或上下文有关的机器信息通过返回一个MachineEnum枚举类型
* 可以标准化地表示不同的机器或环境类型,以便于在代码的其他部分根据具体的机器类型执行相应的逻辑
*
* @return MachineEnum 一个枚举类型,表示当前上下文相关的机器类型
*/
MachineEnum getMachine();
/**
* 下发设备到考勤机
* @param userInfo 当前登录用户
* @param user 下发用户
* @param sn 设备码
*/
void addUserToMachine(UserInfo userInfo, PartUserInfoVo user, String sn);
/**
* 删除考勤机中的用户
* @param userInfo 当前登录用户
* @param userIds 删除用户ids
* @param sn 设备码
*/
void deleteUserList(UserInfo userInfo, List<String> userIds, String sn);
/**
* 同步考勤机人脸库
* @param sn 设备码
*/
void syncMachineMember(String sn);
}

View File

@@ -0,0 +1,27 @@
package jnpf.attendance.service;
public interface NoticeService<Execute, PushData> {
/**
* 检查执行流程的前置条件是否满足
*
* @param dto 包含执行流程所需数据的传输对象
* @return 如果前置条件满足则返回true否则返回false
*/
Boolean preconditions(Execute dto);
/**
* 保存数据到存储系统或特定介质
*
* @param dto 包含待保存数据的传输对象
* @return 返回保存操作的结果标识,通常是一个表示成功或失败的字符串
*/
String saveData(Execute dto);
/**
* 推送数据到目标系统或用户
*
* @param dto 包含推送数据和目标信息的传输对象
*/
void push(PushData dto);
}

View File

@@ -0,0 +1,13 @@
package jnpf.attendance.service;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.AttendanceOvertimeRuleDetail;
/**
* 加班规则明细表服务
*
* @author yanwenfu
* @create 2025-09-18
*/
public interface OvertimeRuleDetailService extends SuperService<AttendanceOvertimeRuleDetail> {
}

View File

@@ -0,0 +1,107 @@
package jnpf.attendance.service;
import com.github.pagehelper.PageInfo;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.AttendanceOvertimeRule;
import jnpf.exception.HandleException;
import jnpf.model.attendance.dto.OvertimeRuleDto;
import jnpf.model.attendance.dto.OvertimeRuleQueryDto;
import jnpf.model.attendance.vo.attendance.OvertimeRuleDetailVo;
import jnpf.model.attendance.vo.attendance.OvertimeRulePageVo;
import jnpf.model.attendance.vo.attendance.OvertimeRuleVo;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 加班规则服务
*
* @author yanwenfu
* @create 2025-09-18
*/
public interface OvertimeRuleService extends SuperService<AttendanceOvertimeRule> {
/**
* 新增加班规则
* @param overtimeRuleDto 加班规则dto
*/
void addOvertimeRule(OvertimeRuleDto overtimeRuleDto) throws HandleException;
/**
* 编辑加班规则
* @param id 加班规则id
* @param overtimeRuleDto 加班规则dto
*/
void updateOvertimeRule(String id, OvertimeRuleDto overtimeRuleDto) throws HandleException;
/**
* 删除加班规则
* @param id 加班规则id
*/
void deleteOvertimeRule(String id);
/**
* 禁用/启用加班规则
* @param id 加班规则id
*/
void updateEnableStatus(String id) throws HandleException;
/**
* 查询加班规则详情
* @param id 加班规则id
* @return jnpf.model.attendance.vo.attendance.OvertimeRuleVo
*/
OvertimeRuleVo getDetail(String id);
/**
* 查询启用中的规则详情
* @param ruleId 加班规则id
* @return jnpf.model.attendance.vo.attendance.OvertimeRuleVo
*/
OvertimeRuleVo getActiveDetail(String ruleId);
/**
* 查询生效中的规则详情
* 若attendanceType为null 则 effectRuleDetail为null
* 若节假日/公休日/工作日配置未启用, 则获取到的effectRuleDetail为null
* @param userId 用户id
* @param attendanceType 考勤类型
* @param date 日期
* @return jnpf.model.attendance.vo.attendance.OvertimeRuleVo
*/
OvertimeRuleVo getEffectDetail(String userId, Integer attendanceType, Date date);
/**
* 查询考勤组加班规则
* @param groupId 考勤组id
* @return jnpf.model.attendance.vo.attendance.OvertimeRuleVo
*/
OvertimeRuleVo getGroupOvertimeRule(String groupId);
/**
* 查询[多用户]生效中的规则详情
* 若attendanceType为null 则 effectRuleDetail为null
* 若节假日/公休日/工作日配置未启用, 则获取到的effectRuleDetail为null
* @param userIds 用户ids
* @param date 日期
* @return java.util.Map<java.lang.String,jnpf.model.attendance.vo.attendance.OvertimeRuleVo>
*/
Map<String, OvertimeRuleVo> getEffectDetailByUserList(List<String> userIds, Date date);
/**
* 根据出勤类型获取节假日/公休日/工作日配置
* @param rule 规则
* @param date 日期
* @param attendanceType 出勤类型
* @return jnpf.model.attendance.vo.attendance.OvertimeRuleDetailVo
*/
OvertimeRuleDetailVo getEffectWorkDetail(OvertimeRuleVo rule, Date date, Integer attendanceType);
/**
* 查询加班规则列表(分页)
* @param queryDto 查询条件
* @return com.github.pagehelper.PageInfo<jnpf.model.attendance.vo.attendance.OvertimeRulePageVo>
*/
PageInfo<OvertimeRulePageVo> getPage(OvertimeRuleQueryDto queryDto);
}

View File

@@ -0,0 +1,83 @@
package jnpf.attendance.service;
import com.github.pagehelper.PageInfo;
import jnpf.model.attendance.dto.AttendancePublicHolidayRulesDto;
import jnpf.model.attendance.vo.attendance.AttendancePublicHolidayBalance;
import jnpf.model.attendance.vo.attendance.AttendancePublicHolidayRulesVo;
import jnpf.model.common.PageDto;
import org.apache.ibatis.annotations.Param;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
/**
* @author panpan
*/
public interface PublicHolidayRulesService {
/**
* 公休管理列表
* @param iText 规则名称模糊查询 非必传
* @return
*/
PageInfo<AttendancePublicHolidayRulesVo> list(String iText, PageDto pageDto);
/**
* 新增公休管理
* @param publicHolidayRulesDto 公休管理
*/
void add(AttendancePublicHolidayRulesDto publicHolidayRulesDto) throws Exception;
/**
* 修改公休管理
* @param publicHolidayRulesDto 公休管理
*/
void update(AttendancePublicHolidayRulesDto publicHolidayRulesDto) throws Exception;
/**
* 删除公休管理
* @param id 公休管理Id
*/
AttendancePublicHolidayRulesVo selectOne(String id);
/**
* 删除公休管理
* @param id 公休管理Id
*/
void delete(@Param("id") String id);
/**
* 修改公休管理状态
* @param publicHolidayRulesDto 公休管理
*/
void updateState(AttendancePublicHolidayRulesDto publicHolidayRulesDto);
/**
* 公休余额查询 固定班不会触发
* @param yearMonth 年月格式yyyy-MM
* @param userIds 用户ID列表
* @return 公休余额列表
*/
List<AttendancePublicHolidayBalance> getBalanceList(String yearMonth,List<String> userIds) ;
/**
* 处理公休(封账时调用) 固定班不会触发
*
* @param yearMonth 年月格式yyyy-MM
* @param userIds 用户ID列表
* @param ratioMap 用户出勤换算比
*/
void processPublicHoliday(String yearMonth, List<String> userIds, Map<String, BigDecimal> ratioMap);
/**
* 处理公休(解封时调用)
* @param yearMonth 年月格式yyyy-MM
* @param userIds 用户ID列表
*/
void rollbackPublicHoliday(String yearMonth,List<String> userIds);
}

View File

@@ -0,0 +1,20 @@
package jnpf.attendance.service;
import jnpf.permission.entity.UserEntity;
/**
* RV1109考勤机服务
*
* @author yanwenfu
* @create 2024-04-09
*/
public interface RV1109MachineService {
/**
* 根据用户id查询用户信息
* @param userId 用户id
* @param tenantId 租户id
* @return jnpf.permission.entity.UserEntity
*/
UserEntity getUserInfoById(String userId, String tenantId);
}

View File

@@ -0,0 +1,30 @@
package jnpf.attendance.service;
import jnpf.entity.attendance.FtbAttendanceDailyRule;
import jnpf.model.attendance.vo.DailyRuleResultVo;
import java.util.List;
public abstract class RuleProcessor {
protected RuleProcessor nextRuleProcessor;
public RuleProcessor setNext(RuleProcessor nextRuleProcessor) {
this.nextRuleProcessor=nextRuleProcessor;
return nextRuleProcessor;
}
/**
* 获取下一个规则
* @return 下一个规则
*/
public RuleProcessor getNext(){
return nextRuleProcessor;
}
/**
* 执行规则生成
* @param hisDailyRules 历史规则
* @param currDailyRule 当前新增规则
* @param resultList 异常结果响应
*/
public abstract void ruleArrangementHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> currDailyRule, List<DailyRuleResultVo> resultList);
}

View File

@@ -0,0 +1,42 @@
package jnpf.attendance.service;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.AttendanceRuleScope;
import jnpf.enums.attendance.ScopeBizType;
import jnpf.model.attendance.dto.UserOrgDto;
import java.util.List;
/**
* 适配范围服务
*
* @author yanwenfu
* @create 2025-09-18
*/
public interface RuleScopeService extends SuperService<AttendanceRuleScope> {
/**
* 查询用户生效中的规则
* @param userId 用户id
* @param organizeId 组织id
* @param bizType 业务类型
* @return java.util.List<jnpf.entity.attendance.AttendanceRuleScope>
*/
List<AttendanceRuleScope> selectUserEffectList(String userId, String organizeId, ScopeBizType bizType);
/**
* 查询用户生效中的规则[批量]
* @param userOrgList 用户组织列表
* @param bizType 业务类型
* @param priority 使用优先级(1: 是, 0: 否)
* @return java.util.List<jnpf.entity.attendance.AttendanceRuleScope>
*/
List<AttendanceRuleScope> selectUserEffectListBatch(List<UserOrgDto> userOrgList, ScopeBizType bizType, Integer priority,List<String> leaveTypeIds);
/**
* 查询组织生效中的假期规则[批量]
* @param oldOrganizeId 组织id
* @return java.util.List<jnpf.entity.attendance.AttendanceRuleScope>
*/
List<AttendanceRuleScope> selectOrgEffectListBatch(String oldOrganizeId);
}

View File

@@ -0,0 +1,42 @@
package jnpf.attendance.service;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.FtbScheduleGroupFixedParamEntity;
import jnpf.exception.HandleException;
import jnpf.exception.QueryException;
import jnpf.model.attendance.dto.scheduling.ScheduleGroupRuleConfigDto;
import jnpf.model.attendance.vo.scheduling.ScheduleGroupRuleConfigVo;
/**
* 考勤组智能排班「排班规则配置」:固定排班核心参数与划线排班参数的查询与保存。
*
* <p>以「固定排班核心参数表」({@link FtbScheduleGroupFixedParamEntity}) 为主实体(每考勤组 1:1
* 划线参数由 {@code FtbScheduleGroupDrawingParamMapper} 协同维护。
*
* @author xiaofeng
* @since 2026-05-13
*/
public interface ScheduleGroupRuleConfigService extends SuperService<FtbScheduleGroupFixedParamEntity> {
/**
* 获取排班规则配置。无表记录时子块返回与表 DEFAULT 一致的默认结构。
*
* @param groupId 考勤组 ID
* @return 配置
* @throws HandleException 参数非法
* @throws QueryException 考勤组不存在或已删除
*/
ScheduleGroupRuleConfigVo getRuleConfig(String groupId) throws HandleException, QueryException;
/**
* 保存排班规则配置。事务内对当前考勤组两块参数表按 {@code groupId} upsert。
*
* @param groupId 考勤组 ID与请求体根 {@code groupId} 须一致)
* @param dto 保存请求体(嵌套为 DTO与响应 VO 字段名与取值类型一致
* @return 保存后的配置(等同再查一次)
* @throws HandleException 参数非法 / 业务校验失败
* @throws QueryException 考勤组不存在或已删除
*/
ScheduleGroupRuleConfigVo saveRuleConfig(String groupId, ScheduleGroupRuleConfigDto dto)
throws HandleException, QueryException;
}

View File

@@ -0,0 +1,31 @@
package jnpf.attendance.service;
import jnpf.exception.HandleException;
import jnpf.exception.QueryException;
import jnpf.model.attendance.dto.scheduling.PreScheduleTableQueryDto;
import jnpf.model.attendance.vo.scheduling.PreScheduleTableVo;
/**
* AI 智能排班确认:预排班主表生成与整包保存。
*
* @author xiaofeng
* @create 2026-05-13
*/
public interface SmartPreScheduleService {
/**
* 按日期范围与人效目标生成预排班主表(含行内预览)。
*
* @param dto 查询条件
* @return 主表数据
*/
PreScheduleTableVo buildPreScheduleTable(PreScheduleTableQueryDto dto);
/**
* 按提交主表过滤 Redis 中 byEmployee 并写回,返回 Redis key 可变片段供后续确认落库。
*
* @param vo 含 groupId、rows与生成接口 data 结构一致
* @return redisKeySuffix考勤组:yyyy-MM-dd_yyyy-MM-dd不含租户与固定前缀
*/
String savePreScheduleTable(PreScheduleTableVo vo) throws HandleException, QueryException;
}

View File

@@ -0,0 +1,149 @@
package jnpf.attendance.service;
import jnpf.model.attendance.model.*;
import jnpf.model.attendance.vo.attendance.DayStatisticsQueryVo;
import jnpf.model.common.DateRangeDto;
import jnpf.permission.vo.v2.user.UserBoundVO;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 统计公共方法服务
*
* @author shitou
* @date 2023/11/22
*/
public interface StatisticsUtilService {
/**
* 获取用户考勤情况
*
* @param userId 用户ID
* @param selectDateRangeDto 日期范围
* @param dateArrayList 月日期集合
* @param dayStatisticsQueryVoList 用户日统计数据
* @return List<ClockInfo>
*/
List<ClockInfo> getUserClockDateArrayList(String userId, DateRangeDto selectDateRangeDto,
List<Date> dateArrayList, List<DayStatisticsQueryVo> dayStatisticsQueryVoList);
/**
* 获取请假记录
*
* @param userMap 用户信息
* @param ratioMap 出勤换算比
* @param userIds 用户集合
* @param dateRangeDto 日期范围
* @return 请假记录 Key是用户ID+考勤组ID
*/
Map<String, List<LeaveRecord>> getLeaveMap(Map<String, UserBoundVO> userMap, Map<String, BigDecimal> ratioMap, List<String> userIds, DateRangeDto dateRangeDto);
/**
* 获取迟到记录集合
*
* @param userMap 用户信息
* @param sealMap 用户是否封账
* @param groupIds 考勤组集合
* @param userIds 用户集合
* @param dateRangeDto 筛选时间范围
* @return 迟到记录 Key是用户ID+考勤组ID
*/
Map<String, List<LateRecord>> getLateMap(Map<String, UserBoundVO> userMap, Map<String, Boolean> sealMap, List<String> groupIds, List<String> userIds, DateRangeDto dateRangeDto);
/**
* 获取早退记录集合
*
* @param userMap 用户信息
* @param sealMap 用户是否封账
* @param groupIds 考勤组集合
* @param userIds 用户集合
* @param dateRangeDto 筛选时间范围
* @return 早退记录 Key是用户ID+考勤组ID
*/
Map<String, List<EarlyLeaveRecord>> getEarlyMap(Map<String, UserBoundVO> userMap, Map<String, Boolean> sealMap, List<String> groupIds, List<String> userIds, DateRangeDto dateRangeDto);
/**
* 获取缺卡记录集合
*
* @param userMap 用户信息
* @param sealMap 用户是否封账
* @param groupIds 考勤组集合
* @param userIds 用户集合
* @param dateRangeDto 筛选时间范围
* @return 缺卡记录 Key是用户ID+考勤组ID
*/
Map<String, List<AbsenceCardRecord>> getAbsenceCardMap(Map<String, UserBoundVO> userMap, Map<String, Boolean> sealMap, List<String> groupIds, List<String> userIds, DateRangeDto dateRangeDto);
/**
* 获取缺勤记录集合
*
* @param groupIds 考勤组集合
* @param sealMap 用户是否封账
* @param userIds 用户集合
* @param dateRangeDto 筛选时间范围
* @return 缺勤记录 Key是用户ID+考勤组ID
*/
Map<String, List<AbsenceRecord>> getAbsenceMap(List<String> groupIds, Map<String, Boolean> sealMap, List<String> userIds, DateRangeDto dateRangeDto);
/**
* 获取补卡记录集合
*
* @param groupIds 考勤组集合
* @param userIds 用户集合
* @param dateRangeDto 筛选时间范围
* @return 补卡记录 Key是用户ID+考勤组ID
*/
Map<String, List<MakeUpCardRecord>> getMakeUpCardMap(List<String> groupIds, List<String> userIds, DateRangeDto dateRangeDto);
/**
* 获取外勤记录集合
*
* @param groupIds 考勤组集合
* @param userIds 用户集合
* @param dateRangeDto 筛选时间范围
* @return 外勤记录 Key是用户ID+考勤组ID
*/
Map<String, List<OutworkRecord>> getOutworkRecordList(List<String> groupIds, List<String> userIds, DateRangeDto dateRangeDto);
/**
* 获取加班记录集合
*
* @param groupIds 考勤组集合
* @param userIds 用户集合
* @param dateRangeDto 筛选时间范围
* @return 加班记录 Key是用户ID+考勤组ID
*/
Map<String, List<OvertimeRecord>> getOvertimeRecordList(List<String> groupIds, List<String> userIds, DateRangeDto dateRangeDto);
/**
* 获取借调记录集合
*
* @param groupIds 考勤组集合
* @param userIds 用户集合
* @param dateRangeDto 筛选时间范围
* @return 借调记录 Key是用户ID+考勤组ID
*/
Map<String, List<SecondRecord>> getSecondRecordList(List<String> groupIds, List<String> userIds, DateRangeDto dateRangeDto);
/**
* 获取出差记录集合
*
* @param groupIds 考勤组集合
* @param userIds 用户集合
* @param dateRangeDto 筛选时间范围
* @return 出差记录 Key是用户ID+考勤组ID
*/
Map<String, List<BusOrOutRecord>> getBusRecordList(List<String> groupIds, List<String> userIds, DateRangeDto dateRangeDto);
/**
* 获取外出记录集合
*
* @param ratioMap 考勤组集合
* @param userIds 用户集合
* @param dateRangeDto 筛选时间范围
* @return 外出记录 Key是用户ID+考勤组ID
*/
Map<String, List<BusOrOutRecord>> getOutRecordList(Map<String, BigDecimal> ratioMap, List<String> userIds, DateRangeDto dateRangeDto);
}

View File

@@ -0,0 +1,23 @@
package jnpf.attendance.service;
import jnpf.model.attendance.vo.attendance.GroupShiftTimeVo;
import jnpf.model.attendance.vo.attendance.UserConfigVo;
import java.util.List;
/**
* @Author huanglinpan
* @Date 2024/6/25 9:30
* @Version 1.0 (版本号)
*/
public interface UserConfigService {
/**
* 获取用户app考勤配置
*/
UserConfigVo getUserConfig();
/**
* 修改用户APP考勤配置
*/
void updateUserConfig(UserConfigVo userConfigVo);
}

View File

@@ -0,0 +1,123 @@
package jnpf.attendance.service;
import com.github.pagehelper.PageInfo;
import jnpf.base.UserInfo;
import jnpf.entity.attendance.AttendanceMachineManage;
import jnpf.entity.attendance.AttendanceUserFace;
import jnpf.exception.HandleException;
import jnpf.model.attendance.dto.FaceChangeQueryDto;
import jnpf.model.attendance.dto.FaceQueryDto;
import jnpf.model.attendance.dto.UserDto;
import jnpf.model.attendance.dto.UserFaceDto;
import jnpf.model.attendance.vo.ChangeLogVo;
import jnpf.model.attendance.vo.FaceMiniVo;
import jnpf.model.attendance.vo.UserFaceDetailVo;
import jnpf.model.attendance.vo.UserFaceVo;
import jnpf.model.common.PageDto;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.constraints.NotEmpty;
import java.util.List;
import java.util.Map;
/**
* 人脸识别服务
*
* @author yanwenfu
* @create 2025-04-08
*/
public interface UserFaceService {
/**
* 人脸对比
* @param file 人脸图片
* @param userInfo 用户信息
* @return java.lang.Boolean
*/
Boolean getPhotoCheck(MultipartFile file, UserInfo userInfo) throws HandleException;
/**
* 保存人脸信息
* @param userDto 用户信息
* @param userInfo 登录人信息
* @param faceUrl 人脸url
* @param thumbnailUrl 缩略图url
*/
void saveUserFace(UserDto userDto, UserInfo userInfo, String faceUrl, String thumbnailUrl);
/**
* 清空人脸
* @param userId 用户id
*/
void deleteUserFace(String userId, UserInfo userInfo) throws Exception;
/**
* 查看人脸
* @param userId 用户id
* @return jnpf.model.attendance.vo.UserFaceVo
*/
UserFaceVo getUserFace(String userId);
/**
* 变动记录(分页)
* @param queryDto 查询条件
* @return com.github.pagehelper.PageInfo<jnpf.model.attendance.vo.ChangeLogVo>
*/
PageInfo<ChangeLogVo> getChangeLogPage(FaceChangeQueryDto queryDto);
/**
* 人脸记录(分页)
* @param queryDto 查询条件
* @return com.github.pagehelper.PageInfo<jnpf.model.attendance.vo.UserFaceDetailVo>
*/
PageInfo<UserFaceDetailVo> getUserFacePage(FaceQueryDto queryDto);
Map<String, List<AttendanceMachineManage>> getUserFaceList(List<String> userIds, String tenantId);
/**
* 判断用户是否上传人脸
* @param userId 用户id
* @return java.lang.Boolean
*/
Boolean hasUserFace(String userId);
/**
* 用户人脸信息
* @param userId 用户id
* @return jnpf.model.attendance.vo.FaceMiniVo
*/
FaceMiniVo getUserFaceInfo(String userId);
/**
* 查看人脸详情
* @param id 人脸记录id
* @return jnpf.model.attendance.vo.UserFaceVo
*/
UserFaceVo getUserFaceDetail(String id);
/**
* 初始化人脸
**/
void initializationFace( String tenantId);
/**
* 更新用户人脸信息
* @param userId 用户id
* @param updateUserId 更新人id
*/
AttendanceUserFace updateUserFaceInfo(String userId, String updateUserId);
/**
* 下发到考勤机
* @param userId 用户id
* @return java.lang.Integer
*/
Integer sendToMachine(String userId) throws Exception;
/**
* 更新考勤机返回的状态
* @param userId 用户id
* @param result 1: 成功, 0: 失败
*/
void updateMachineSyncStatus(String userId, Integer result);
}

View File

@@ -0,0 +1,18 @@
package jnpf.attendance.service;
import jnpf.base.UserInfo;
import jnpf.model.attendance.dto.UserDto;
import org.springframework.web.multipart.MultipartFile;
/**
* 人脸服务
*
* @author yanwenfu
* @create 2025-12-11
*/
public interface UserFaceTxService {
Integer uploadUserFace(MultipartFile mFile, UserDto userDto, UserInfo userInfo) throws Exception;
Integer syncUserFaceToMachine(String userId) throws Exception;
}

View File

@@ -0,0 +1,58 @@
package jnpf.attendance.service;
import com.github.pagehelper.PageInfo;
import jnpf.base.service.SuperService;
import jnpf.entity.attendance.AttendanceUserPhone;
import jnpf.model.attendance.dto.CancelPhoneDto;
import jnpf.model.attendance.dto.UsualPhoneDto;
import jnpf.model.attendance.dto.UsualPhoneQueryDto;
import jnpf.model.attendance.dto.UsualPhoneSettingDto;
import jnpf.model.attendance.vo.attendance.UsualPhonePageVo;
/**
* 常用设备服务
*
* @author yanwenfu
* @create 2025-09-18
*/
public interface UsualPhoneService extends SuperService<AttendanceUserPhone> {
/**
* 批量取消绑定
* @param cancelPhoneDto 取消绑定参数
*/
void cancelPhoneBatch(CancelPhoneDto cancelPhoneDto);
/**
* 更新常用手机设置
* @param usualPhoneSettingDto 常用手机设置dto
*/
void updateUsualPhoneSetting(UsualPhoneSettingDto usualPhoneSettingDto);
/**
* 查询常用手机列表(分页)
* @param queryDto 查询条件
* @return com.github.pagehelper.PageInfo<jnpf.model.attendance.vo.attendance.UsualPhonePageVo>
*/
PageInfo<UsualPhonePageVo> getUsualPhonePage(UsualPhoneQueryDto queryDto);
/**
* 新增常用设备
* @param usualPhoneDto 常用设备dto
*/
void addUsualPhone(UsualPhoneDto usualPhoneDto);
/**
* 检查常用设备是否异常
* @param phoneName 手机名称
* @param phoneCode 手机编码
* @return java.lang.Boolean
*/
Boolean checkUsualPhone(String phoneName, String phoneCode);
/**
* 查询常用手机配置
* @return jnpf.model.attendance.dto.UsualPhoneSettingDto
*/
UsualPhoneSettingDto getUsualPhoneSetting();
}

View File

@@ -0,0 +1,100 @@
package jnpf.attendance.service;
import com.github.pagehelper.PageInfo;
import jnpf.base.service.SuperService;
import jnpf.entity.Workstation;
import jnpf.model.attendance.dto.WorkstationQueryDto;
import jnpf.model.attendance.dto.WorkstationSaveDto;
import jnpf.model.attendance.dto.WorkstationUserAddDto;
import jnpf.model.attendance.dto.WorkstationUserRemoveDto;
import jnpf.model.attendance.vo.WorkstationDetailVo;
import jnpf.model.attendance.vo.WorkstationVo;
import jnpf.model.attendance.vo.WorkstationWithUsersVo;
import java.util.Date;
import java.util.List;
/**
* 考勤工作站服务
*
* @author AI Generated
* @create 2026-05-11
*/
public interface WorkstationService extends SuperService<Workstation> {
/**
* 新增工作站
*
* @param dto 工作站保存DTO
*/
void saveWorkstation(WorkstationSaveDto dto);
/**
* 编辑工作站
*
* @param id 工作站ID
* @param dto 工作站保存DTO
*/
void updateWorkstation(String id, WorkstationSaveDto dto);
/**
* 删除工作站
*
* @param id 工作站ID
*/
void deleteWorkstation(String id);
/**
* 查询工作站列表(分页)
*
* @param dto 查询条件(含分页参数)
* @return 工作站分页列表
*/
PageInfo<WorkstationVo> listWorkstations(WorkstationQueryDto dto);
/**
* 添加人员
*
* @param dto 添加人员DTO
*/
void addUsers(WorkstationUserAddDto dto);
/**
* 删除人员
*
* @param dto 删除人员DTO
*/
void removeUser(WorkstationUserRemoveDto dto);
/**
* 查询工作站详情
*
* @param id 工作站ID
* @return 工作站详情
*/
WorkstationDetailVo getDetail(String id);
/**
* 按考勤组查询工作站及其归属员工列表
* <p>
* 工作站归属:考勤组的所属门店({@code orgId})下所有未删除的工作站;
* 工作站员工:考勤组成员通过
* {@code AttendanceUserService#getAttendanceGroupUsersOfSecondment} 拉取(截止 {@code endTime}、含借调过滤),
* 主岗位与工作站岗位一致的自动归属({@code isExtra=false}
* 工作站-人员关联表中显式额外加入的为另加入员工({@code isExtra=true})。
* 每人附带 {@code inGroupDays}{@code [startTime, endTime]} 内在组日)及 {@code canLineSchedule}。
*
* @param groupId 考勤组ID
* @param startTime 查询开始时间(含)
* @param endTime 查询结束时间(含);同时作为成员快照截止时刻
* @return 工作站列表,每个元素包含工作站属性及其员工列表
*/
List<WorkstationWithUsersVo> listWorkstationsByGroupId(String groupId, Date startTime, Date endTime);
/**
* 重置指定工作站人员:仅保留主岗位与工作站岗位一致的默认归属,清除另加入的额外人员。
*
* @param workstationId 工作站ID
*/
void resetWorkstationUsers(String workstationId);
}

View File

@@ -0,0 +1,23 @@
package jnpf.attendance.service.filter;
import jnpf.base.UserInfo;
import jnpf.entity.attendance.FtbAttendanceDailyRule;
/**
* 出勤规则过滤器
*
* @author yanwenfu
* @create 2025-09-25
*/
public interface RuleFilter {
/**
* @param rule 当前 rule
* @param context 上下文(可以放整个 ruleList或者中间结果
* @param userInfo 用户信息
* @return jnpf.attendance.service.filter.RuleFilterResult 是否保留该 rule
*/
RuleFilterResult keepRule(FtbAttendanceDailyRule rule, RuleFilterContext context, UserInfo userInfo);
int getOrder();
}

View File

@@ -0,0 +1,65 @@
package jnpf.attendance.service.filter;
import jnpf.entity.attendance.AttendanceRuleScope;
import jnpf.entity.attendance.FtbAttendanceDailyRule;
import jnpf.model.attendance.vo.attendance.OvertimeRuleDetailVo;
import jnpf.model.attendance.vo.attendance.OvertimeRuleVo;
import jnpf.util.DateDetail;
import lombok.Getter;
import lombok.Setter;
import java.util.*;
import java.util.stream.Collectors;
/**
* 出勤规则过滤器上下文
*
* @author yanwenfu
* @create 2025-09-25
*/
@Getter
@Setter
public class RuleFilterContext {
/** 当前日期 */
private final Date curDate;
// 原始列表 今天最后一个班次 -> 昨天 倒序
private final List<FtbAttendanceDailyRule> ruleList;
// 过滤出的列表
private final List<FtbAttendanceDailyRule> collectList = new ArrayList<>();
// 加班关联的列表
private final Map<String, FtbAttendanceDailyRule> map = new HashMap<>();
// 加班规则map
private final Map<String, OvertimeRuleVo> overtimeMap;
// 加班规则
private OvertimeRuleVo overtimeRule;
// 是否已经查询过加班规则
private Integer hasRuleQuery = 0;
public RuleFilterContext(Date curDate, List<FtbAttendanceDailyRule> ruleList, Map<String, OvertimeRuleVo> overtimeMap) {
ruleList.forEach(v -> {
if (v.getInUnbounded() == null) {
v.setInUnbounded(0);
}
if (v.getOutUnbounded() == null) {
v.setOutUnbounded(0);
}
});
this.curDate = curDate;
this.ruleList = ruleList;
this.overtimeMap = overtimeMap;
}
/**
* 获取最后一个rule
* @return jnpf.entity.attendance.FtbAttendanceDailyRule
*/
public FtbAttendanceDailyRule getYesterdayLastRule() {
return ruleList.stream()
.filter(v -> !DateDetail.getDate2Str(v.getDay(), DateDetail.DF).equals(DateDetail.getDate2Str(new Date(), DateDetail.DF))
&& null != v.getInPoint())
.max(Comparator.comparing(FtbAttendanceDailyRule::getInPoint))
.orElse(null);
}
}

View File

@@ -0,0 +1,35 @@
package jnpf.attendance.service.filter;
import lombok.Getter;
/**
* 出勤规则过滤器结果
*
* @author yanwenfu
* @create 2025-09-25
*/
@Getter
public class RuleFilterResult {
/** 是否保留 */
private final boolean keep;
/** 是否终止责任链 */
private final boolean terminate;
public RuleFilterResult(boolean keep, boolean terminate) {
this.keep = keep;
this.terminate = terminate;
}
public static RuleFilterResult keep() {
return new RuleFilterResult(true, false);
}
public static RuleFilterResult discard() {
return new RuleFilterResult(false, false);
}
public static RuleFilterResult terminate() {
return new RuleFilterResult(false, true);
}
}

View File

@@ -0,0 +1,59 @@
package jnpf.attendance.service.filter.impl;
import jnpf.attendance.service.filter.RuleFilter;
import jnpf.attendance.service.filter.RuleFilterContext;
import jnpf.attendance.service.filter.RuleFilterResult;
import jnpf.base.UserInfo;
import jnpf.entity.attendance.FtbAttendanceDailyRule;
import jnpf.enums.attendance.AttendanceTypeEnum;
import jnpf.util.ConstantUtil;
import jnpf.util.DateDetail;
import org.springframework.stereotype.Component;
/**
* 跨日过滤器
*
* @author yanwenfu
* @create 2025-09-25
*/
@Component
public class CrossDayFilter implements RuleFilter {
@Override
public RuleFilterResult keepRule(FtbAttendanceDailyRule rule, RuleFilterContext context, UserInfo userInfo) {
if (rule.getAttendanceType().equals(AttendanceTypeEnum.LEAVE.getCode())) {
return RuleFilterResult.discard();
}
// 昨日的休不展示
if (rule.getAttendanceType().equals(AttendanceTypeEnum.REST.getCode()) && !DateDetail.checkSameDay(context.getCurDate(), rule.getDay())) {
return RuleFilterResult.discard();
}
// 今日的休
if (DateDetail.checkSameDay(context.getCurDate(), rule.getDay())) {
if (rule.getAttendanceType().equals(AttendanceTypeEnum.DEFAULT.getCode()) || rule.getAttendanceType().equals(AttendanceTypeEnum.REST.getCode())) {
return RuleFilterResult.keep();
}
}
// 上班打卡时间是今天的, 都留下
if (DateDetail.checkSameDay(context.getCurDate(), rule.getInPoint())) {
return RuleFilterResult.keep();
}
// 下班结束时间是今天的, 都留下
if (null != rule.getOutLackPoint() && DateDetail.checkSameDay(context.getCurDate(), rule.getOutLackPoint())) {
if (!DateDetail.checkSameDay(context.getCurDate(), rule.getDay()) && rule.getAttendanceType().equals(ConstantUtil.RULE_TYPE_REST)) {
return RuleFilterResult.discard();
}
return RuleFilterResult.keep();
}
/*if (DateDetail.checkSameDay(rule.getDay(), context.getCurDate())) {
return RuleFilterResult.terminate();
}*/
return RuleFilterResult.discard();
}
@Override
public int getOrder() {
return 3;
}
}

View File

@@ -0,0 +1,55 @@
package jnpf.attendance.service.filter.impl;
import jnpf.attendance.service.filter.RuleFilter;
import jnpf.attendance.service.filter.RuleFilterContext;
import jnpf.attendance.service.filter.RuleFilterResult;
import jnpf.base.UserInfo;
import jnpf.entity.attendance.FtbAttendanceDailyRule;
import jnpf.enums.attendance.AttendanceTypeEnum;
import jnpf.enums.attendance.v2.WorkBoundaryCoverageEnum;
import jnpf.util.DateDetail;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
/**
* 请假过滤器
* 判定需要保留的情况
* @author yanwenfu
* @create 2025-09-25
*/
@Component
public class LeaveFilter implements RuleFilter {
@Override
public RuleFilterResult keepRule(FtbAttendanceDailyRule rule, RuleFilterContext context, UserInfo userInfo) {
if (rule.getAttendanceType().equals(AttendanceTypeEnum.LEAVE.getCode())) {
// 今天的出勤规则如果只有请假, 就返回回去
// 获取当天的所有非休息规则
List<FtbAttendanceDailyRule> sameDayRules = context.getRuleList().stream()
.filter(v -> DateDetail.checkSameDay(context.getCurDate(), v.getDay()))
.filter(v -> !v.getAttendanceType().equals(AttendanceTypeEnum.REST.getCode()))
.collect(Collectors.toList());
// 如果所有非休息规则都是请假,则返回 keep
boolean allLeave = !sameDayRules.isEmpty() &&
sameDayRules.stream().allMatch(v -> v.getAttendanceType().equals(AttendanceTypeEnum.LEAVE.getCode()));
if (allLeave) {
return RuleFilterResult.keep();
}
}
if (WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode() == rule.getInUnbounded() || WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode() == rule.getOutUnbounded()) {
if (DateDetail.checkSameDay(context.getCurDate(), rule.getOutLackPoint()) || DateDetail.checkSameDay(context.getCurDate(), rule.getInPoint())) {
// 当前出勤规则有上/下班请假覆盖 并且 是跨天(昨日跨今日) || 上班时间是今天
return RuleFilterResult.keep();
}
}
return RuleFilterResult.discard();
}
@Override
public int getOrder() {
return 0;
}
}

View File

@@ -0,0 +1,168 @@
package jnpf.attendance.service.filter.impl;
import jnpf.attendance.service.OvertimeRuleService;
import jnpf.attendance.service.filter.RuleFilter;
import jnpf.attendance.service.filter.RuleFilterContext;
import jnpf.attendance.service.filter.RuleFilterResult;
import jnpf.base.UserInfo;
import jnpf.entity.attendance.FtbAttendanceDailyRule;
import jnpf.enums.attendance.AttendanceTypeEnum;
import jnpf.enums.attendance.v2.WorkBoundaryCoverageEnum;
import jnpf.model.attendance.vo.attendance.OvertimeRuleDetailVo;
import jnpf.model.attendance.vo.attendance.OvertimeRuleVo;
import jnpf.util.ConstantUtil;
import jnpf.util.DateDetail;
import jnpf.util.JsonUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* 加班过滤器
*
* @author yanwenfu
* @create 2025-09-25
*/
@Component
public class OvertimeFilter implements RuleFilter {
@Resource
private OvertimeRuleService overtimeRuleService;
@Override
public RuleFilterResult keepRule(FtbAttendanceDailyRule rule, RuleFilterContext context, UserInfo userInfo) {
if (rule.getAttendanceType().equals(AttendanceTypeEnum.WORKOVERTIME.getCode())) {
if (StringUtils.isEmpty(rule.getPeriodInfo())) {
return RuleFilterResult.discard();
}
OvertimeRuleDetailVo ruleDetail;
try {
ruleDetail = JsonUtil.getJsonToBean(rule.getPeriodInfo(), OvertimeRuleDetailVo.class);
if (null == ruleDetail) {
throw new Exception("加班规则异常");
}
} catch (Exception e) {
return RuleFilterResult.discard();
}
// 查询加班规则
rule.setOvertimeRuleDetail(ruleDetail);
// 出勤规则是加班
if (DateDetail.checkSameDay(context.getCurDate(), rule.getInPoint())) {
// 今天的加班
if (rule.getInUnbounded().equals(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode())) {
addMapValue(rule, context);
}
return RuleFilterResult.keep();
}
// 昨天的加班 查询下一个班次
FtbAttendanceDailyRule nextRule = null;
if (rule.getRn() - 1 > 0) {
nextRule = context.getRuleList().get(rule.getRn() - 2);
}
if (null == nextRule || DateDetail.checkSameDay(context.getCurDate(), nextRule.getInPoint())) {
addMapValue(rule, context);
return RuleFilterResult.keep();
}
} else {
OvertimeRuleDetailVo vo = generateOvertimeRuleDetail(context, rule, userInfo);
if (null == vo) {
return RuleFilterResult.discard();
}
// 昨天 或 今天
if (DateDetail.checkSameDay(context.getCurDate(), rule.getDay())) {
// 今天
if (StringUtils.isNotEmpty(vo.getId()) && vo.getCalcMethod().equals(3)) {
if (AttendanceTypeEnum.ORDINARY.getCode().equals(rule.getAttendanceType())) {
if (!DateDetail.checkSameDay(rule.getInPoint(), context.getCurDate())) {
return RuleFilterResult.discard();
}
}
rule.setOvertimeRuleDetail(vo);
rule.setOvertime(ConstantUtil.NUM_TRUE);
return RuleFilterResult.keep();
}
} else {
if (!rule.getAttendanceType().equals(AttendanceTypeEnum.ORDINARY.getCode())) {
return RuleFilterResult.discard();
}
// 昨天 出勤规则不是加班 判定是不是昨天最后一个班次
FtbAttendanceDailyRule lastRule = context.getYesterdayLastRule();
if (null != lastRule && rule.getId().equals(lastRule.getId())) {
if (vo.getCalcMethod().equals(3)) {
rule.setOvertimeRuleDetail(vo);
rule.setOvertime(ConstantUtil.NUM_TRUE);
return RuleFilterResult.keep();
}
}
}
}
return RuleFilterResult.discard();
}
private OvertimeRuleDetailVo generateOvertimeRuleDetail(RuleFilterContext context, FtbAttendanceDailyRule rule, UserInfo userInfo) {
OvertimeRuleVo vo = context.getOvertimeRule();
if (null == vo && context.getHasRuleQuery().equals(ConstantUtil.NUM_TRUE)) {
// 是否已经查询过用户加班规则
return null;
}
if (null == context.getOvertimeMap()) {
return null;
}
FtbAttendanceDailyRule nextRule = null;
if (rule.getRn() - 1 > 0) {
nextRule = context.getRuleList().get(rule.getRn() - 2);
}
Integer attendanceType = getAttendanceType(rule, nextRule);
if (null == vo) {
// 查询用户加班配置
OvertimeRuleVo overtimeRule = context.getOvertimeMap().get(userInfo.getUserId());
context.setOvertimeRule(overtimeRule);
context.setHasRuleQuery(ConstantUtil.NUM_TRUE);
return null == overtimeRule ? null : overtimeRuleService.getEffectWorkDetail(context.getOvertimeRule(), rule.getDay(), attendanceType);
}
return overtimeRuleService.getEffectWorkDetail(context.getOvertimeRule(), rule.getDay(), attendanceType);
}
private Integer getAttendanceType(FtbAttendanceDailyRule rule, FtbAttendanceDailyRule nextRule) {
Integer attendanceType;
if (rule.getAttendanceType().equals(AttendanceTypeEnum.DEFAULT.getCode())) {
return AttendanceTypeEnum.ORDINARY.getCode();
}
if (null == nextRule) {
attendanceType = rule.getAttendanceType();
} else {
// rule 和 nextRule 中有一个休 则出勤类型为休, 否则为工作日
if (rule.getAttendanceType().equals(AttendanceTypeEnum.REST.getCode()) || nextRule.getAttendanceType().equals(AttendanceTypeEnum.REST.getCode())) {
attendanceType = AttendanceTypeEnum.REST.getCode();
} else {
attendanceType = AttendanceTypeEnum.ORDINARY.getCode();
}
}
return attendanceType;
}
private void addMapValue(FtbAttendanceDailyRule rule, RuleFilterContext context) {
// 加班上班有连续
if (rule.getRn() + 1 < context.getRuleList().size()) {
FtbAttendanceDailyRule dailyRule = context.getRuleList().get(rule.getRn());
if (dailyRule.getOutUnbounded().equals(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode())) {
context.getMap().put(rule.getId(), dailyRule);
}
}
// 加班下班有连续
if (rule.getRn() - 1 > 0) {
FtbAttendanceDailyRule dailyRule = context.getRuleList().get(rule.getRn() - 2);
if (dailyRule.getInUnbounded().equals(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode())) {
context.getMap().put(rule.getId(), dailyRule);
}
}
}
@Override
public int getOrder() {
return 2;
}
}

View File

@@ -0,0 +1,48 @@
package jnpf.attendance.service.filter.impl;
import jnpf.attendance.service.filter.RuleFilter;
import jnpf.attendance.service.filter.RuleFilterContext;
import jnpf.attendance.service.filter.RuleFilterResult;
import jnpf.base.UserInfo;
import jnpf.entity.attendance.FtbAttendanceDailyRule;
import jnpf.enums.attendance.v2.WorkBoundaryCoverageEnum;
import jnpf.util.DateDetail;
import org.springframework.stereotype.Component;
/**
* 借调过滤器
*
* @author yanwenfu
* @create 2025-09-25
*/
@Component
public class SecondmentFilter implements RuleFilter {
@Override
public RuleFilterResult keepRule(FtbAttendanceDailyRule rule, RuleFilterContext context, UserInfo userInfo) {
if (null == rule.getOutLackPoint()) {
return RuleFilterResult.discard();
}
boolean dateCheck = DateDetail.checkSameDay(context.getCurDate(), rule.getOutLackPoint()) || DateDetail.checkSameDay(context.getCurDate(), rule.getInPoint());
// rule本身是借调
if (null != rule.getSelfGroup() && rule.getSelfGroup().equals(2)) {
if (dateCheck) {
return RuleFilterResult.keep();
}
}
// 上/下班借调覆盖 并且跨日, 或者上班时间在今日
if (WorkBoundaryCoverageEnum.SECONDMENT_COVERED.getCode() == rule.getInUnbounded() || WorkBoundaryCoverageEnum.SECONDMENT_COVERED.getCode() == rule.getOutUnbounded()) {
if (dateCheck) {
// 当前出勤规则有上/下班借调覆盖 并且 是跨天(昨日跨今日) || 上班时间是今天
return RuleFilterResult.keep();
}
}
return RuleFilterResult.discard();
}
@Override
public int getOrder() {
return 1;
}
}

View File

@@ -0,0 +1,215 @@
package jnpf.attendance.service.handle.chain;
import jnpf.attendance.service.filter.RuleFilter;
import jnpf.attendance.service.filter.RuleFilterContext;
import jnpf.attendance.service.filter.RuleFilterResult;
import jnpf.base.UserInfo;
import jnpf.entity.attendance.AttendanceRuleScope;
import jnpf.entity.attendance.FtbAttendanceDailyRule;
import jnpf.enums.attendance.AttendanceTypeEnum;
import jnpf.enums.attendance.v2.WorkBoundaryCoverageEnum;
import jnpf.model.attendance.vo.attendance.OvertimeRuleVo;
import jnpf.util.ConstantUtil;
import jnpf.util.DateDetail;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.stream.Collectors;
/**
* 出勤规则过滤链执行器
*
* @author yanwenfu
* @create 2025-09-25
*/
@Component
public class RuleFilterChain {
private final List<RuleFilter> filters;
public RuleFilterChain(List<RuleFilter> filters) {
// 按照 getOrder 排序,保证执行顺序
this.filters = filters.stream()
.sorted(Comparator.comparingInt(RuleFilter::getOrder))
.collect(Collectors.toList());
}
/**
* 获取今日可打卡出勤规则+数据填写
* @param curDate 当前日期
* @param ruleList 出勤规则列表(当前+前一天)
* @param map k:用户id, v:加班规则
* @param userInfo 用户信息
* @return java.util.List<jnpf.entity.attendance.FtbAttendanceDailyRule>
*/
public List<FtbAttendanceDailyRule> execute(Date curDate, List<FtbAttendanceDailyRule> ruleList, Map<String, OvertimeRuleVo> map, UserInfo userInfo) {
RuleFilterContext context = new RuleFilterContext(curDate, ruleList, map);
stop : for (FtbAttendanceDailyRule rule : ruleList) {
boolean keep = false;
for (RuleFilter filter : filters) {
RuleFilterResult result = filter.keepRule(rule, context, userInfo);
if (result.isTerminate()) {
// 终止整个责任链
break stop;
}
if (result.isKeep()) {
// 不保留,但继续走
keep = true;
break;
}
}
if (keep) {
context.getCollectList().add(rule);
}
}
// 填值
if (context.getCollectList().isEmpty()) {
return new ArrayList<>();
}
// 去除半天休
List<String> restRuleList = context.getCollectList().stream()
.filter(v -> DateDetail.checkSameDay(context.getCurDate(), v.getDay()) && v.getAttendanceType().equals(AttendanceTypeEnum.REST.getCode()))
.map(FtbAttendanceDailyRule::getId)
.collect(Collectors.toList());
long count = context.getCollectList().stream().filter(v -> DateDetail.checkSameDay(context.getCurDate(), v.getDay())).count();
if (!restRuleList.isEmpty() && count > 1) {
context.getCollectList().removeIf(v -> restRuleList.contains(v.getId()));
}
// 今日所有需要打卡的出勤规则
List<FtbAttendanceDailyRule> addList = new ArrayList<>();
context.getCollectList().forEach(rule -> {
if (rule.getAttendanceType().equals(AttendanceTypeEnum.BUSINESS_TRIP.getCode()) || rule.getAttendanceType().equals(AttendanceTypeEnum.STEP_OUT.getCode())) {
// 外出或出差, 且无班次则设置班次类型为-1
rule.setAttendanceType(AttendanceTypeEnum.DEFAULT.getCode());
rule.setInStepOutType(ConstantUtil.NUM_TRUE);
rule.setOutStepOutType(ConstantUtil.NUM_TRUE);
}
// 普通班次 且 允许无需审批的加班 缺卡时间延后 与加班下班相同
if (rule.getAttendanceType().equals(AttendanceTypeEnum.ORDINARY.getCode()) && rule.getOvertime().equals(ConstantUtil.NUM_TRUE)) {
outLackSet(rule, context);
}
// 请假
if (rule.getInUnbounded().equals(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode())) {
rule.setMsg("请假回岗");
// rule.setInLackPoint(rule.getInPoint());
}
if (rule.getOutUnbounded().equals(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode())) {
rule.setMsg("请假离岗");
// rule.setOutLackPoint(rule.getOutPoint());
}
// 借调
if (rule.getInUnbounded().equals(WorkBoundaryCoverageEnum.SECONDMENT_COVERED.getCode())) {
rule.setInHideStatus(ConstantUtil.STR_TRUE);
// 在这个时间点生成无需打卡 -2
rule.setOnWorkIgnore(true);
rule.setInLackPoint(rule.getInPoint());
}
if (rule.getOutUnbounded().equals(WorkBoundaryCoverageEnum.SECONDMENT_COVERED.getCode())) {
rule.setOutHideStatus(ConstantUtil.STR_TRUE);
// 在这个时间点生成无需打卡 -2
rule.setOffWorkIgnore(true);
rule.setOutLackPoint(rule.getOutPoint());
}
// 加班
if (rule.getInUnbounded().equals(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode())) {
rule.setInHideStatus(ConstantUtil.STR_TRUE);
// 在这个时间点生成无需打卡 -2
rule.setOnWorkIgnore(true);
rule.setClockStartPoint(rule.getInPoint());
rule.setInLackPoint(rule.getInPoint());
setAnother(ConstantUtil.ON_WORK, context, rule, addList);
}
if (rule.getOutUnbounded().equals(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode())) {
rule.setOutHideStatus(ConstantUtil.STR_TRUE);
// 在这个时间点生成无需打卡 -2
rule.setOffWorkIgnore(true);
rule.setOutLackPoint(rule.getOutPoint());
setAnother(ConstantUtil.OFF_WORK, context, rule, addList);
}
// 晚走晚到
if (rule.getInUnbounded().equals(WorkBoundaryCoverageEnum.LATE_LEAVE_LATE_ARRIVE.getCode())) {
// 在这个时间点生成无需打卡 -2
rule.setOnWorkIgnore(true);
}
if (rule.getOutUnbounded().equals(WorkBoundaryCoverageEnum.LATE_LEAVE_LATE_ARRIVE.getCode())) {
// 在这个时间点生成无需打卡 -2
rule.setOffWorkIgnore(true);
}
if (rule.getAttendanceType().equals(AttendanceTypeEnum.WORKOVERTIME.getCode())) {
// 按审批时长申请计算 无需打卡
if (rule.getOvertimeRuleDetail().getCalcMethod().equals(1)) {
rule.setOnWorkIgnore(true);
rule.setOffWorkIgnore(true);
}
// 查询上一个班次的下班时间
inLackSet(rule, context);
// 查询下一个班次的上班时间
outLackSet(rule, context);
}
});
context.getCollectList().addAll(addList);
context.getCollectList().sort(
Comparator.comparing(
FtbAttendanceDailyRule::getInPoint,
Comparator.nullsLast(Comparator.naturalOrder())
)
);
return context.getCollectList();
}
private void outLackSet(FtbAttendanceDailyRule rule, RuleFilterContext context) {
// 加班 或 普班无审批加班
if (null == rule.getOutLackPoint() || (rule.getAttendanceType().equals(AttendanceTypeEnum.ORDINARY.getCode()) && rule.getOvertime().equals(ConstantUtil.NUM_TRUE))) {
if (rule.getRn() - 1 > 0) {
FtbAttendanceDailyRule nextRule = context.getRuleList().get(rule.getRn() - 2);
if (null != nextRule.getInPoint()) {
rule.setOutLackPoint(nextRule.getInPoint());
} else {
if (!DateDetail.checkSameDay(rule.getDay(), context.getCurDate()) && DateDetail.checkSameDay(rule.getOutPoint(), context.getCurDate())) {
// 昨天的班下班时间在今天, 所以缺卡时间最多到今晚24点
rule.setOutLackPoint(DateDetail.endOfDay(rule.getOutPoint()));
} else {
rule.setOutLackPoint(DateDetail.getNextDay(rule.getOutPoint()));
}
}
} else {
// 无下一个班次 暂时设置为24小时后, 明天会重新获取
rule.setOutLackPoint(DateDetail.getNextDay(rule.getOutPoint()));
}
}
}
private void inLackSet(FtbAttendanceDailyRule rule, RuleFilterContext context) {
if (null == rule.getInLackPoint()) {
if (rule.getRn() + 1 < context.getRuleList().size()) {
FtbAttendanceDailyRule dailyRule = context.getRuleList().get(rule.getRn());
rule.setClockStartPoint(null == dailyRule.getOutPoint() ? DateDetail.beginOfDay(rule.getInPoint()) : dailyRule.getOutPoint());
} else {
// 无上一个班次 设置为上班时间的0点
rule.setClockStartPoint(DateDetail.beginOfDay(rule.getInPoint()));
}
rule.setInLackPoint(rule.getOutPoint());
}
}
/**
* 设置无需打卡时间
*/
private void setAnother(Integer workStatus, RuleFilterContext context, FtbAttendanceDailyRule rule, List<FtbAttendanceDailyRule> addList) {
FtbAttendanceDailyRule dailyRule = context.getMap().get(rule.getId());
if (null != dailyRule) {
FtbAttendanceDailyRule r = context.getCollectList().stream().filter(v -> v.getId().equals(dailyRule.getId())).findFirst().orElse(null);
if (null == r) {
if (workStatus.equals(ConstantUtil.ON_WORK)) {
dailyRule.setOutHideStatus(ConstantUtil.STR_TRUE);
dailyRule.setOffWorkIgnore(true);
} else {
dailyRule.setInHideStatus(ConstantUtil.STR_TRUE);
dailyRule.setOnWorkIgnore(true);
}
addList.add(dailyRule);
}
}
}
}

View File

@@ -0,0 +1,214 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import jnpf.attendance.antifreeze.UserAntifreeze;
import jnpf.attendance.service.AttendanceUserSettingService;
import jnpf.base.UserInfo;
import jnpf.constants.AttendanceConstant;
import jnpf.enums.attendance.*;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.ShiftChangModel;
import jnpf.model.attendance.vo.attendance.ApproveBaseImVo;
import jnpf.model.attendance.vo.attendance.ApproveImVo;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.model.attendance.vo.UserSettingVo;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.util.DateDetail;
import jnpf.util.StringUtil;
import jnpf.util.UserProvider;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.*;
/**
* @Author huanglinpan
* @Date 2024/8/12 10:58
* @Version 1.0 (版本号)
*/
@Component(AttendanceConstant.APPROVE)
@Slf4j
public class AttendanceApproveNotice implements AttendanceNotice<ApproveBaseImVo,ApproveImVo>{
@Resource
private AttendanceUserSettingService attendanceUserSettingService;
@Override
public Boolean isPass(ApproveImVo approveImVo) {
if (!approveImVo.getAttendanceNoticeEnum().equals(AttendanceNoticeEnum.APPROVE) && !approveImVo.getAttendanceNoticeEnum().equals(AttendanceNoticeEnum.JOIN_GROUP)) {
return Boolean.FALSE;
}
return Boolean.TRUE;
}
@Override
public List<ApproveBaseImVo> generatingData(ApproveImVo approveImVo) {
List<ApproveBaseImVo> list = new ArrayList<>();
list.add(approveImVo.getApproveBaseImVo());
return list;
}
@Override
public List<String> getRecipient(ApproveImVo approveImVo) {
List<String> list = checkSetting(approveImVo.getUserIds(),UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE.getCode());
if(null != approveImVo.getType() && Objects.equals(AttendanceNoticeEnum.JOIN_GROUP.getCode(), approveImVo.getType())) {
// 处理被借调人信息
return checkSetting(list,UserSettingEnum.ATTENDANCE_SETTING_ATTENDANCE_GROUP_JOIN_LEAVE_REMINDER.getCode());
}
return list;
}
@NotNull
private List<String> checkSetting(List<String> userIds, String code) {
// 校验接收人是否打开配置
List<UserSettingVo> settingList = attendanceUserSettingService.getSettingList(userIds, UserSettingTypeEnum.USER.getCode(), code);
Map<String, UserSettingVo> map = settingList.stream().collect(Collectors.toMap(UserSettingVo::getAssociationId, Function.identity()));
List<String> list = new ArrayList<>();
userIds.forEach(id -> {
UserSettingVo userSettingVo = map.get(id);
if (null == userSettingVo) {
list.add(id);
}else {
// 检查是否打开
if (1 == userSettingVo.getStatus()) {
list.add(id);
}
}
});
return list;
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(ApproveImVo approveImVo, String noticeId) {
ArrayList<JumpUrl> objects = CollUtil.newArrayList();
// 特殊处理借调审批被借调用户看到的URL的参数
log.error("noticeId:{},approveImVo.getApproveBaseImVo().getUrl():{}",noticeId,approveImVo.getApproveBaseImVo().getUrl());
String url = APPROVE_SECONDED_URL.equals(approveImVo.getApproveBaseImVo().getUrl()) ? String.format(APPROVE_SECONDED_URL, noticeId) : approveImVo.getApproveBaseImVo().getUrl();
log.error("url:{}",url);
objects.add(JumpUrl.builder().url(url).urlName(ATTENDANCE_NOTICE_DETAIL_BUTTON_NAME).color(COLOR_BLACK).build());
return SystemNoticeStrategy.builder()
.title(approveImVo.getApproveBaseImVo().getTitle())
.noticeModuleEnum(NoticeModuleEnum.KQ_SP)
.jumpUrls(objects)
.build();
}
@Override
public String getContext(List<ApproveBaseImVo> data) {
if (CollUtil.isEmpty(data)) {
return null;
}
ApproveBaseImVo approveBaseImVo = data.get(0);
// 通过/拒绝的消息有操作者
String startStr = null != approveBaseImVo.getCreateUserName() ? "操作者:" + approveBaseImVo.getCreateUserName() + "</br>": "";
if (Objects.equals(ApprovalSettingTypeEnum.LEAVE.getCode(), approveBaseImVo.getType())){
//开始时间2024年5月16日 16:23
//结束时间2024年5月17日 09:00
// 考勤V1.6 加入请假类型 小时类维持以上不变,天类: 开始时间2024年5月16日 结束时间2024年5月17日 半天类2024年5月16日 上半天 结束时间2024年5月17日 下半天
Integer unit = approveBaseImVo.getUnit();
if (LeaveUnitEnum.HOUR.getCode().equals(unit)){
return startStr +
"开始时间:" + DateUtil.format(approveBaseImVo.getStartTime(), "yyyy-MM-dd HH:mm") + "</br>" +
"结束时间:" + DateUtil.format(approveBaseImVo.getEndTime(), "yyyy-MM-dd HH:mm");
}else if (LeaveUnitEnum.DAY.getCode().equals(unit)){
return startStr +
"开始时间:" + DateUtil.format(approveBaseImVo.getStartTime(), "yyyy-MM-dd") + "</br>" +
"结束时间:" + DateUtil.format(approveBaseImVo.getEndTime(), "yyyy-MM-dd");
}else {
return startStr +
"开始时间:" + DateUtil.format(approveBaseImVo.getStartTime(), "yyyy-MM-dd ") + dayStr(approveBaseImVo.getStartTimeType()) + "</br>" +
"结束时间:" + DateUtil.format(approveBaseImVo.getEndTime(), "yyyy-MM-dd ")+ dayStr(approveBaseImVo.getEndTimeType());
}
}
if (Objects.equals(ApprovalSettingTypeEnum.OVERTIME.getCode(), approveBaseImVo.getType())){
//选择日期2024年5月16日
//开始时间22:00
//结束时间次日08:00
// 结束时间次日处理
StringBuffer end = new StringBuffer();
if (!DateUtil.format(approveBaseImVo.getStartTime(), "yyyy-MM-dd").equals(DateUtil.format(approveBaseImVo.getEndTime(), "yyyy-MM-dd"))){
end.append("次日");
}
end.append(DateUtil.format(approveBaseImVo.getEndTime(), "HH:mm")).append("</br>");
return startStr +
"选择日期:" + DateUtil.format(approveBaseImVo.getStartTime(), "yyyy-MM-dd") + "</br>" +
"开始时间:" + DateUtil.format(approveBaseImVo.getStartTime(), "HH:mm") + "</br>" +
"结束时间:" + end;
}
if (Objects.equals(ApprovalSettingTypeEnum.GO_OUT.getCode(), approveBaseImVo.getType())){
//开始时间2024年5月16日
//结束时间2024年5月17日
//时长2天
return startStr +
"开始时间:" + DateUtil.format(approveBaseImVo.getStartTime(), "yyyy-MM-dd") + "</br>" +
"结束时间:" + DateUtil.format(approveBaseImVo.getEndTime(), "yyyy-MM-dd") + "</br>" +
"时长:" + approveBaseImVo.getDuration();
}
if (Objects.equals(ApprovalSettingTypeEnum.BUSINESS_TRIP.getCode(), approveBaseImVo.getType())){
// 出发地:地点名称地点名称地点名称地点名称
//目的地:地点名称地点名称地点名称地点名称
return startStr +
"出发地:" + approveBaseImVo.getDeparture() + "</br>" +
"目的地:" + approveBaseImVo.getDestination();
}
if (Objects.equals(ApprovalSettingTypeEnum.SECONDED.getCode(), approveBaseImVo.getType())){
//借调开始时间2024年5月16日 16:23
//借调结束时间2024年5月17日 09:00
//借调考勤组:小露测试考勤组
//被借调考勤组:小露验收考勤组
return startStr +
"借调开始时间:" + DateUtil.format(approveBaseImVo.getStartTime(), "yyyy-MM-dd HH:mm") + "</br>" +
"借调结束时间:" + DateUtil.format(approveBaseImVo.getEndTime(), "yyyy-MM-dd HH:mm") + "</br>" +
"借调考勤组:" + approveBaseImVo.getGroupName() + "</br>" +
"被借调考勤组:" + approveBaseImVo.getSecondedGroupName();
}
if (Objects.equals(ApprovalSettingTypeEnum.OUT.getCode(), approveBaseImVo.getType())) {
return startStr
+ "发起时间:" + DateDetail.getDate2Str(approveBaseImVo.getCreateTime(), DateDetail.DF20) + "</br>"
+ "考勤点:" + approveBaseImVo.getAddress();
}
if (Objects.equals(ApprovalSettingTypeEnum.ROUTINE.getCode(), approveBaseImVo.getType())) {
String str = startStr + "补卡时间:" + approveBaseImVo.getRuleTime() + "</br>";
if (StringUtils.isEmpty(startStr)) {
str += "出勤结果:" + approveBaseImVo.getResult();
}
return str;
}
if (Objects.equals(ApprovalSettingTypeEnum.ACTION_RESULT.getCode(), approveBaseImVo.getType())) {
return startStr
+ "变更人员:" + approveBaseImVo.getSecondedUsersName() + "</br>"
+ "变更时间:" + approveBaseImVo.getRuleTime() + "</br>"
+ "出勤结果:" + approveBaseImVo.getAfterResult() + "</br>"
+ "处理结果:" + approveBaseImVo.getResult();
}
return null;
}
private static String dayStr(Integer type) {
if (1 == type){
return "上半天";
}else {
return "下半天";
}
}
}

View File

@@ -0,0 +1,128 @@
package jnpf.attendance.service.handle.notice;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import jnpf.attendance.antifreeze.UserAntifreeze;
import jnpf.attendance.mapper.AttendanceDailyRuleMapper;
import jnpf.constants.AttendanceConstant;
import jnpf.entity.attendance.FtbAttendanceDailyRule;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.model.AttendanceChangeModel;
import jnpf.model.attendance.model.AttendanceChangeNoticeModel;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.util.ConstantUtil;
import jnpf.util.DateDetail;
import jnpf.util.StringUtil;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* 考勤变更(不审批)
*
* @author yanwenfu
* @create 2024-08-16
*/
@Service(value = AttendanceConstant.CHECK_RESULT_CHANGE)
public class AttendanceChangeNotice implements AttendanceNotice<AttendanceChangeModel, AttendanceChangeNoticeModel> {
@Resource
private AttendanceNoticeHandler attendanceNoticeHandler;
@Resource
private AttendanceDailyRuleMapper attendanceDailyRuleMapper;
@Resource
private UserAntifreeze userAntifreeze;
@Override
public Boolean isPass(AttendanceChangeNoticeModel model) {
return attendanceNoticeHandler.checkBeforeCondition(model.getUserId(), UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE,
UserSettingEnum.ATTENDANCE_SETTING_ATTENDANCE_RESULT_CHANGE_REMINDER);
}
@Override
public List<AttendanceChangeModel> generatingData(AttendanceChangeNoticeModel model) {
List<PartUserInfoVo> list = userAntifreeze.getAllByIds(List.of(model.getHandleUserId()), model.getTenantId());
PartUserInfoVo user = list.stream().findFirst().orElse(null);
StringBuilder handelUser = new StringBuilder();
if (Objects.isNull(user)) {
handelUser.append("");
} else {
handelUser.append(user.getRealName()).append("(").append(
StringUtil.isEmpty(user.getOrganizeName()) ? "暂无" : user.getOrganizeName()).append("-").append(
StringUtil.isEmpty(user.getPositionName()) ? "暂无" : user.getPositionName()).append(")");
}
FtbAttendanceDailyRule dailyRule = attendanceDailyRuleMapper.selectById(model.getRuleId());
String changeTime;
if (null == dailyRule) {
changeTime = "--";
} else {
changeTime = model.getClockInType().equals(ConstantUtil.ON_WORK) ? DateDetail.getDate2Str(dailyRule.getInPoint(), DateDetail.DF9) : DateDetail.getDate2Str(dailyRule.getOutPoint(), DateDetail.DF9);
}
AttendanceChangeModel attendanceChangeModel = AttendanceChangeModel.builder()
.handelUser(handelUser.toString())
.changeTime(null == dailyRule ? "--" : changeTime)
.changeResult(getResult(model.getChangeType()))
.build();
return List.of(attendanceChangeModel);
}
private String getResult(Integer changeType) {
// 变更类型(-1: 缺卡, 1: 正常, 2: 迟到, 3: 早退, 99: 撤回变更)
switch (changeType) {
case -1:
return "缺卡";
case 1:
return "正常";
case 2:
return "迟到";
case 3:
return "早退";
case 99:
return "撤回变更";
default:
return "--";
}
}
@Override
public List<String> getRecipient(AttendanceChangeNoticeModel model) {
return List.of(model.getUserId());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(AttendanceChangeNoticeModel model, String noticeId) {
List<JumpUrl> list = new ArrayList<>();
list.add(new JumpUrl(String.format(AttendanceConstant.GROUP_LOCK_URL1, model.getHandleUserId()), AttendanceConstant.GROUP_LOCK_BUTTON_NAME1, AttendanceConstant.COLOR_BLACK,3,"contactInfo", JSON.toJSONString(new JSONObject(){{
put("contactId", model.getHandleUserId());
}})));
return SystemNoticeStrategy.builder()
.title(AttendanceConstant.TITLE_CLOCK_IN_CHANGE)
.noticeModuleEnum(NoticeModuleEnum.CQJG_BD)
.jumpUrls(list)
.build();
}
@Override
public String getContext(List<AttendanceChangeModel> dataList) {
if (null == dataList || dataList.isEmpty()) {
return "";
}
AttendanceChangeModel model = dataList.get(0);
return "操作人:" + model.getHandelUser() + "</br>"
+ "变更记录:" + model.getChangeTime() + "</br>"
+ "变更结果:" + model.getChangeResult();
}
}

View File

@@ -0,0 +1,53 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import jnpf.attendance.antifreeze.UserAntifreeze;
import jnpf.base.UserInfo;
import jnpf.model.attendance.model.AttendanceNoticeModel;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.util.UserProvider;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import java.util.Objects;
/**
*
* @param <T> 作为详情展示及IM消息内容的实体
*/
public interface AttendanceNotice<T, V extends AttendanceNoticeModel> {
/**
* 通过当前通知发送的条件实现(前置条件)
* @param attendanceNoticeModel
* @return
*/
Boolean isPass(V attendanceNoticeModel);
/**
* 生成记录数据用于详情及im消息展示
* @param attendanceNoticeModel 过程数据
* @return
*/
List<T> generatingData(V attendanceNoticeModel);
/**
* 设置接收人
* @param attendanceNoticeModel 过程数据
*/
List<String> getRecipient(V attendanceNoticeModel);
/**
* 设置系统通知策略
* @param attendanceNoticeModel 过程数据
* @return
*/
SystemNoticeStrategy setSystemNoticeStrategy(V attendanceNoticeModel, String noticeId);
/**
* 设置im通知内容部分如需要请使用/br换行
* @param data 详情展示及IM消息内容的实体集合
* @return
*/
String getContext(List<T> data);
}

View File

@@ -0,0 +1,265 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import jnpf.ImRobotApi;
import jnpf.attendance.mapper.AttendanceManagerPermissionMapper;
import jnpf.attendance.service.AttendanceNoticeService;
import jnpf.attendance.service.AttendanceUserService;
import jnpf.attendance.service.AttendanceUserSettingService;
import jnpf.base.ActionResult;
import jnpf.entity.AttendanceGroupUser;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.enums.attendance.UserSettingTypeEnum;
import jnpf.from.*;
import jnpf.model.attendance.dto.NoticeSaveDto;
import jnpf.model.attendance.model.AttendanceNoticeModel;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.NoticeConfirm;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.model.attendance.vo.AttendanceGroupAdminVo;
import jnpf.model.attendance.vo.AttendancePermissionVo;
import jnpf.model.attendance.vo.UserSettingVo;
import jnpf.util.ConstantUtil;
import jnpf.util.RandomUtil;
import jnpf.util.StringUtil;
import jnpf.util.UserProvider;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.*;
@Component
@Slf4j
public class AttendanceNoticeHandler {
@Autowired
private Map<String, AttendanceNotice> attendanceNoticeList;
@Autowired
private AttendanceNoticeService attendanceNoticeService;
@Autowired
private ImRobotApi imRobotApi;
@Autowired
private AttendanceUserSettingService attendanceUserSettingService;
@Resource
private AttendanceManagerPermissionMapper attendanceManagerPermissionMapper;
@Autowired
private AttendanceUserService attendanceUserService;
/**
* 通知发送
* @param attendanceNoticeModel 过程数据
*/
public void send(AttendanceNoticeModel attendanceNoticeModel) {
if (Objects.isNull(attendanceNoticeModel.getAttendanceNoticeEnum())) {
log.error("通知类型未填充");
return;
}
AttendanceNotice notice = attendanceNoticeList.get(attendanceNoticeModel.getAttendanceNoticeEnum().getServiceName());
if (Objects.isNull(notice)) {
log.error("未获取到该通知[{}]具体service实现", attendanceNoticeModel.getAttendanceNoticeEnum().getDesc());
return;
}
if (!notice.isPass(attendanceNoticeModel)) {
log.error("未满足通知[{}]条件,过滤", attendanceNoticeModel.getAttendanceNoticeEnum().getDesc());
return;
}
List<T> data = notice.generatingData(attendanceNoticeModel);
if(CollUtil.isEmpty(data)){
return;
}
List<String> recipientList = notice.getRecipient(attendanceNoticeModel);
if (CollUtil.isEmpty(recipientList)) {
log.error("未获取到该通知[{}]接收人", attendanceNoticeModel.getAttendanceNoticeEnum().getDesc());
return;
}
String noticeId = RandomUtil.uuId();
SystemNoticeStrategy build = notice.setSystemNoticeStrategy(attendanceNoticeModel, noticeId);
Integer isConfirm = Objects.nonNull(build.getIsConfirm()) && build.getIsConfirm() ? 1 : 0;
attendanceNoticeService.noticeSave(NoticeSaveDto.builder()
.dataJson(JSON.toJSONString(data))
.id(noticeId)
.title(build.getTitle())
.isConfirm(isConfirm)
.type(attendanceNoticeModel.getAttendanceNoticeEnum())
.userId(UserProvider.getLoginUserId())
.confirmList(Objects.equals(isConfirm, 0) ? null : JSON.toJSONString(initNoticeConfirm(recipientList)))
.build());
sendNotice(attendanceNoticeModel.getTenantId(), notice.getContext(data), build, isConfirm, recipientList, noticeId, attendanceNoticeModel.getModuleId());
}
private void sendNotice(String tenantId, String context, SystemNoticeStrategy systemNoticeStrategy, Integer isConfirm, List<String> recipientList, String noticeId,String moduleId) {
if (CollUtil.isEmpty(recipientList)) {
log.error("考勤发送系统通知记录id[{}],接收人为空", noticeId);
return;
}
SingleSendRobotNoticeForm form = new SingleSendRobotNoticeForm();
form.setRobotTypeEnum(ImRobotTypeEnum.FTB_XZS);
form.setMessageAttributionRobotMpId(MP_ID);
form.setToUserIds(recipientList);
form.setTenantId(tenantId);
SendRobotNoticeDataForm robotNoticeDataForm = new SendRobotNoticeDataForm();
robotNoticeDataForm.setLogo(ATTENDANCE_APP_LOGO);//固定图片
robotNoticeDataForm.setAppName(systemNoticeStrategy.getNoticeModuleEnum().getMsg());
robotNoticeDataForm.setTitle(systemNoticeStrategy.getTitle());
robotNoticeDataForm.setContent(context);
robotNoticeDataForm.setContentSummary(systemNoticeStrategy.getTitle());
LinkedList<JumpUrlListModel> objects = CollUtil.newLinkedList();
if (Objects.equals(isConfirm, 1)) {
objects.add(JumpUrlListModel.builder()
.displayMethodEnum(JumpUrlListModel.DisplayMethodEnum.FALSE)
.reqMethod(JumpUrlListModel.ReqMethodEnum.GET)
.type(1)
.url(String.format(ATTENDANCE_NOTICE_CONFIRM_LIST_VIEW_URL, noticeId))
.buttonName(ATTENDANCE_NOTICE_CONFIRM_LIST_BUTTON_NAME)
.mpId(MP_ID)
.buttonColor("#1A1A1A")
.build());
objects.add(JumpUrlListModel.builder()
.type(2)
.isConfirm(1)
.confirmButton(ConfirmButton.builder().status(1)
.buttName1("确认收到")
.color1("#3C6DF8")
.url1(String.format(ATTENDANCE_NOTICE_CONFIRM_URL, noticeId))
.buttName2("已收到")
.color2("#D9D9DB")
.url2("")
.build())
.displayMethodEnum(JumpUrlListModel.DisplayMethodEnum.FALSE)
.reqMethod(JumpUrlListModel.ReqMethodEnum.POST)
.buttonName(ATTENDANCE_NOTICE_CONFIRM)
.url("")
.build());
} else {
List<JumpUrl> jumpUrls = systemNoticeStrategy.getJumpUrls();
if (CollUtil.isEmpty(jumpUrls)) {
log.error("考勤发送系统通知记录id[{}],未设置按钮事件", noticeId);
return;
}
int size = jumpUrls.size();
jumpUrls.forEach(jumpUrl -> objects.add(JumpUrlListModel.builder()
.reqMethod(JumpUrlListModel.ReqMethodEnum.GET)
.displayMethodEnum(size > 1 ? JumpUrlListModel.DisplayMethodEnum.FALSE : JumpUrlListModel.DisplayMethodEnum.TRUE)
.type(Objects.isNull(jumpUrl.getType()) ? 1 : jumpUrl.getType())
.url(jumpUrl.getUrl())
.mpId(StringUtil.isNotBlank(jumpUrl.getMpId()) ? jumpUrl.getMpId() : MP_ID)
.buttonName(jumpUrl.getUrlName())
.buttonColor(jumpUrl.getColor())
.nativeUrl(Objects.isNull(jumpUrl.getType()) ? null : NativeUrl.builder()
.page(jumpUrl.getPage())
.param(jumpUrl.getParam())
.build())
.build()));
}
robotNoticeDataForm.setJumpUrlList(objects);
form.setRobotNoticeDataForm(robotNoticeDataForm);
// log.error("打印消息内容form:{}", JSON.toJSONString(form));
ActionResult actionResult = imRobotApi.sendSingleRobotNotice(form);
}
private List<NoticeConfirm> initNoticeConfirm(List<String> recipientList) {
return recipientList.stream().map(userId -> NoticeConfirm.builder().userId(userId).confirmedTime(new Date()).isConfirmed(0).build()).collect(Collectors.toList());
}
public List<String> getRecipientForSelfAndChild(String groupId, Boolean isAdmin) {
List<String> selfAndChildrenGroupIds = CollUtil.newArrayList(groupId);
if (isAdmin) {
List<AttendanceGroupAdminVo> attendanceGroupAdminVos = attendanceManagerPermissionMapper.queryGroupUsers(selfAndChildrenGroupIds);
List<String> adminUserIds = attendanceGroupAdminVos.stream().map(AttendanceGroupAdminVo::getUserId).collect(Collectors.toList());
if (CollUtil.isEmpty(adminUserIds)) {
return Collections.emptyList();
}
return getUserIdsForFilterStatus(adminUserIds, UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE, UserSettingEnum.ATTENDANCE_SETTING_ATTENDANCE_GROUP_RULE_CHANGE_REMINDER);
}
Date date = new Date();
List<AttendanceGroupUser> attendanceGroupUsers = attendanceUserService.queryByUsersAndGroupFilterSecondment(date, date, null, selfAndChildrenGroupIds);
List<String> userIds = attendanceGroupUsers.stream().map(AttendanceGroupUser::getUserId).collect(Collectors.toList());
if (CollUtil.isEmpty(userIds)) {
return Collections.emptyList();
}
List<String> userIdsForFilterStatus = getUserIdsForFilterStatus(userIds, UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE, UserSettingEnum.ATTENDANCE_SETTING_ATTENDANCE_GROUP_RULE_CHANGE_REMINDER);
return userIdsForFilterStatus;
}
/**
* 根据配置多个code来过滤出开关都开启的用户集合
*
* @param userIds
* @param settingCodes
* @return
*/
public List<String> getUserIdsForFilterStatus(List<String> userIds, UserSettingEnum... settingCodes) {
// 判断前置 开启考勤消息提醒 开启极速打卡成功提醒
List<String> userSettingList = new ArrayList<>();
Arrays.stream(settingCodes).forEach(v -> userSettingList.add(v.getCode()));
if (CollUtil.isEmpty(userIds)) {
return Collections.emptyList();
}
List<UserSettingVo> settingList = attendanceUserSettingService.getSettingList(userIds, UserSettingTypeEnum.USER.getCode(), userSettingList);
Map<String, List<UserSettingVo>> collect = settingList.stream().collect(Collectors.groupingBy(UserSettingVo::getAssociationId));
userSettingList.clear();
collect.forEach((userId, settings) -> {
if (settings.stream().allMatch(setting -> Objects.equals(setting.getStatus(), 1))) {
userSettingList.add(userId);
}
});
return userSettingList;
}
public boolean checkBeforeCondition(String userId, UserSettingEnum... settingCodes) {
// 判断前置 开启考勤消息提醒 开启极速打卡成功提醒
List<String> userSettingList = new ArrayList<>();
Arrays.stream(settingCodes).forEach(v -> userSettingList.add(v.getCode()));
if (StringUtil.isEmpty(userId)) {
return false;
}
List<UserSettingVo> settingList = attendanceUserSettingService.getSettingList(List.of(userId), UserSettingTypeEnum.USER.getCode(), userSettingList);
if (null == settingList || settingList.isEmpty()) {
return false;
}
Map<String, UserSettingVo> map = settingList.stream().collect(Collectors.toMap(UserSettingVo::getCode, Function.identity()));
boolean result = true;
for (String code : userSettingList) {
result = checkRule(code, map);
if (!result) {
break;
}
}
return result;
}
private boolean checkRule(String code, Map<String, UserSettingVo> map) {
switch (code) {
case UserSettingEnum.MESSAGE_RECEIVE:
case UserSettingEnum.SPEED_CHECK_SUCCESS_REMINDER:
case UserSettingEnum.MISSING_CHECKIN_REMINDER:
case UserSettingEnum.MISSING_END_WORK_REMINDER:
case UserSettingEnum.CLASS_ABSENCE_REMINDER:
case UserSettingEnum.DAILY_REPORT:
case UserSettingEnum.PERSONAL_MONTHLY_REPORT:
case UserSettingEnum.ATTENDANCE_GROUP_LOCK_UNLOCK_NOTICE:
case UserSettingEnum.CLASS_CHANGE_REMINDER:
case UserSettingEnum.PRE_WORK_REMINDER:
case UserSettingEnum.END_WORK_REMINDER:
case UserSettingEnum.ATTENDANCE_RESULT_CHANGE_REMINDER:
UserSettingVo absenceSetting = map.get(code);
if (null == absenceSetting) {
return false;
} else {
return absenceSetting.getStatus().equals(ConstantUtil.NUM_TRUE);
}
default:
return true;
}
}
}

View File

@@ -0,0 +1,87 @@
package jnpf.attendance.service.handle.notice;
import jnpf.constants.AttendanceConstant;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.model.BeforeClockInModel;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.RemindClockInNoticeModel;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.util.ConstantUtil;
import jnpf.util.DateDetail;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* 打卡前提醒
*
* @author yanwenfu
* @create 2024-08-15
*/
@Service(value = AttendanceConstant.BEFORE_CLOCK_IN)
public class BeforeClockInNotice implements AttendanceNotice<BeforeClockInModel, RemindClockInNoticeModel> {
@Resource
private AttendanceNoticeHandler attendanceNoticeHandler;
@Override
public Boolean isPass(RemindClockInNoticeModel model) {
if (ConstantUtil.ON_WORK.equals(model.getClockInType())) {
return attendanceNoticeHandler.checkBeforeCondition(model.getUserId(), UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE,
UserSettingEnum.ATTENDANCE_SETTING_PRE_WORK_REMINDER);
} else {
return attendanceNoticeHandler.checkBeforeCondition(model.getUserId(), UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE,
UserSettingEnum.ATTENDANCE_SETTING_END_WORK_REMINDER);
}
}
@Override
public List<BeforeClockInModel> generatingData(RemindClockInNoticeModel model) {
BeforeClockInModel beforeClockInModel = BeforeClockInModel.builder()
.workTimeStr(null == model.getWorkTime() ? "--" : DateDetail.getDate2Str(model.getWorkTime(), DateDetail.DF9))
.remark(ConstantUtil.ON_WORK.equals(model.getClockInType()) ? AttendanceConstant.TITLE_BEFORE_ON_WORK : AttendanceConstant.TITLE_BEFORE_OFF_WORK)
.clockInType(model.getClockInType())
.build();
return List.of(beforeClockInModel);
}
@Override
public List<String> getRecipient(RemindClockInNoticeModel model) {
return List.of(model.getUserId());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(RemindClockInNoticeModel model, String noticeId) {
List<JumpUrl> list = new ArrayList<>();
list.add(new JumpUrl(AttendanceConstant.BTN_RULE_URL + "?day=" + DateDetail.getDate2Str(new Date(), DateDetail.DF), AttendanceConstant.BTN_NAME_TO_DETAIL, AttendanceConstant.COLOR_BLACK));
list.add(new JumpUrl(AttendanceConstant.BTN_FAST_UPDATE_URL, AttendanceConstant.BTN_NAME_GO, AttendanceConstant.COLOR_BLUE));
return SystemNoticeStrategy.builder()
.title(ConstantUtil.ON_WORK.equals(model.getClockInType()) ? AttendanceConstant.TITLE_BEFORE_ON_WORK : AttendanceConstant.TITLE_BEFORE_OFF_WORK)
.noticeModuleEnum(NoticeModuleEnum.KQ_DK)
.jumpUrls(list)
.build();
}
@Override
public String getContext(List<BeforeClockInModel> dataList) {
if (null == dataList || dataList.isEmpty()) {
return "";
}
BeforeClockInModel model = dataList.get(0);
if (ConstantUtil.ON_WORK.equals(model.getClockInType())) {
return model.getWorkTimeStr() + " " + AttendanceConstant.TITLE_BEFORE_ON_WORK + "!";
} else {
return model.getWorkTimeStr() + " " + AttendanceConstant.TITLE_BEFORE_OFF_WORK + "!";
}
}
}

View File

@@ -0,0 +1,96 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import jnpf.attendance.antifreeze.UserAntifreeze;
import jnpf.attendance.service.AttendanceGroupService;
import jnpf.attendance.service.AttendanceSuperAdminService;
import jnpf.constants.AttendanceConstant;
import jnpf.entity.AttendanceGroup;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.model.attendance.model.*;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.*;
import static jnpf.constants.AttendancePermissionConstant.MANAGER;
import static jnpf.constants.AttendancePermissionConstant.SCHEDULING;
@Component(AttendanceConstant.CONSEC_UNSCHEDULED)
@Slf4j
public class ConsecUnscheduledNotice implements AttendanceNotice<ConsecUnscheduledModel, ConsecUnscheduledNoticeModel> {
@Autowired
private UserAntifreeze userAntifreeze;
@Autowired
private AttendanceGroupService attendanceGroupService;
@Autowired
private AttendanceSuperAdminService attendanceSuperAdminService;
@Override
public Boolean isPass(ConsecUnscheduledNoticeModel attendanceNoticeModel) {
return Boolean.TRUE;
}
@Override
public List<ConsecUnscheduledModel> generatingData(ConsecUnscheduledNoticeModel attendanceNoticeModel) {
List<ConsecUnscheduledModel> shiftChangModels = CollUtil.newArrayList();
if (CollUtil.isEmpty(attendanceNoticeModel.getUserIds())) {
return shiftChangModels;
}
List<PartUserInfoVo> infoByIds = userAntifreeze.getInfoByIds(attendanceNoticeModel.getUserIds(), attendanceNoticeModel.getTenantId());
if (CollUtil.isEmpty(infoByIds)) {
return shiftChangModels;
}
List<String> collect = infoByIds.stream().map(PartUserInfoVo::getRealName).collect(Collectors.toList());
AttendanceGroup byId = attendanceGroupService.getById(attendanceNoticeModel.getGroupId());
if (Objects.isNull(byId)) {
return shiftChangModels;
}
attendanceNoticeModel.setAttendanceGroup(new AttendanceGroupParam(attendanceNoticeModel.getGroupId(),byId.getGroupName()));
shiftChangModels.add(new ConsecUnscheduledModel(byId.getGroupName(), collect));
return shiftChangModels;
}
@Override
public List<String> getRecipient(ConsecUnscheduledNoticeModel attendanceNoticeModel) {
Map<String, List<String>> stringListMap = attendanceSuperAdminService.queryPermissionBySpecify(CollUtil.newArrayList(attendanceNoticeModel.getGroupId()), List.of(SCHEDULING), List.of(MANAGER));
List<String> orDefault = stringListMap.getOrDefault("-1", CollUtil.newArrayList());
List<String> orDefault1 = stringListMap.getOrDefault(attendanceNoticeModel.getGroupId(), CollUtil.newArrayList());
orDefault.addAll(orDefault1);
return orDefault.stream().distinct().filter(Objects::nonNull).collect(Collectors.toList());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(ConsecUnscheduledNoticeModel attendanceNoticeModel, String noticeId) {
ArrayList<JumpUrl> objects = CollUtil.newArrayList();
objects.add(JumpUrl.builder().url(String.format(BTN_SCHEDULE_URL, JSON.toJSONString(attendanceNoticeModel.getAttendanceGroup()))).urlName(BTN_SCHEDULE_GO).color(COLOR_BLACK).build());
return SystemNoticeStrategy.builder()
.title(ATTENDANCE_NOTICE_CONSEC_UNSCHEDULED_TITLE)
.noticeModuleEnum(NoticeModuleEnum.KQ_PB)
.jumpUrls(objects)
.build();
}
@Override
public String getContext(List<ConsecUnscheduledModel> data) {
if (CollUtil.isEmpty(data)) {
return null;
}
StringBuffer stringBuffer = new StringBuffer();
ConsecUnscheduledModel shiftChangModel = data.stream().findFirst().orElse(null);
stringBuffer.append("考勤组:").append(shiftChangModel.getGroupName()).append("</br>");
List<String> userNames = shiftChangModel.getUserNames();
stringBuffer.append("相关成员:").append(StringUtil.join(userNames.stream().limit(3).collect(Collectors.toList()), "")).append(userNames.size() > 3 ? ("等共计" + userNames.size() + "名成员") : "");
return stringBuffer.toString();
}
}

View File

@@ -0,0 +1,71 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import jnpf.constants.AttendanceConstant;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.model.*;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
/**
* 连续缺勤消息
*
* @author yanwenfu
* @create 2024-08-12
*/
@Service(value = AttendanceConstant.CONSECUTIVE_ABSENCE)
public class ConsecutiveAbsenceNotice implements AttendanceNotice<ConsecutiveAbsenceModel, ConsecutiveAbsenceNoticeModel> {
@Override
public Boolean isPass(ConsecutiveAbsenceNoticeModel model) {
return Boolean.TRUE;
}
@Override
public List<ConsecutiveAbsenceModel> generatingData(ConsecutiveAbsenceNoticeModel model) {
ConsecutiveAbsenceModel consecutiveAbsenceModel = ConsecutiveAbsenceModel.builder()
.groupName(model.getGroupName())
.userName(model.getUserName())
.absenceDate(model.getAbsenceDate())
.absenceDetailModel(model.getAbsenceDetailModel())
.build();
return List.of(consecutiveAbsenceModel);
}
@Override
public List<String> getRecipient(ConsecutiveAbsenceNoticeModel attendanceNoticeModel) {
return attendanceNoticeModel.getToUserList();
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(ConsecutiveAbsenceNoticeModel model, String noticeId) {
List<JumpUrl> list = new ArrayList<>();
list.add(new JumpUrl(String.format(AttendanceConstant.BTN_CONSECUTIVE_ABSENCE_URL, noticeId), AttendanceConstant.BTN_NAME_TO_DETAIL, AttendanceConstant.COLOR_BLACK));
list.add(new JumpUrl(String.format(AttendanceConstant.ADMINISTRATOR_CHANGE_URL2, model.getGroupId()), AttendanceConstant.ADMINISTRATOR_CHANGE_BUTTON_NAME2, AttendanceConstant.COLOR_BLUE));
return SystemNoticeStrategy.builder()
.title(AttendanceConstant.TITLE_CONSECUTIVE_ABSENCE)
.noticeModuleEnum(NoticeModuleEnum.KQ_DK)
.jumpUrls(list)
.build();
}
@Override
public String getContext(List<ConsecutiveAbsenceModel> dataList) {
if (null == dataList || dataList.isEmpty()) {
return "";
}
ConsecutiveAbsenceModel model = dataList.get(0);
return "考勤组:" + model.getGroupName() + "</br>" +
"成员:" + model.getUserName() + "</br>" +
"考勤时间:" + model.getAbsenceDate();
}
}

View File

@@ -0,0 +1,111 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import jnpf.constants.AttendanceConstant;
import jnpf.enums.attendance.AttendanceNoticeEnum;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.model.FastClockInNoticeModel;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.QuickClockInModel;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.util.ConstantUtil;
import jnpf.util.DateDetail;
import jnpf.util.StringUtil;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
/**
* 极速打卡消息
*
* @author yanwenfu
* @create 2024-08-12
*/
@Service(value = AttendanceConstant.FAST_CLOCK_IN)
public class FastClockInNotice implements AttendanceNotice<QuickClockInModel, FastClockInNoticeModel> {
@Resource
private AttendanceNoticeHandler attendanceNoticeHandler;
@Override
public Boolean isPass(FastClockInNoticeModel model) {
return attendanceNoticeHandler.checkBeforeCondition(model.getUserId(), UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE,
UserSettingEnum.ATTENDANCE_SETTING_SPEED_CHECK_SUCCESS_REMINDER);
}
@Override
public List<QuickClockInModel> generatingData(FastClockInNoticeModel model) {
QuickClockInModel quickClockInModel = QuickClockInModel.builder()
.workTimeStr(DateDetail.getDate2Str(model.getWorkTime(), DateDetail.DF9))
.remark(getTitle(model.getAttendanceNoticeEnum()))
.clockInTimeStr(DateDetail.getDate2Str(model.getClockIn().getClockInTime(), DateDetail.DF10))
.clockInMethod(getClockInMethod(model.getClockIn().getDeviceType()))
.clockInAddress(StringUtil.isEmpty(model.getClockIn().getAddress()) ? "--" : model.getClockIn().getAddress())
.build();
return List.of(quickClockInModel);
}
private String getClockInMethod(Integer deviceType) {
switch (deviceType) {
case ConstantUtil.DEVICE_PLACE:
return "GPS地点打卡";
case ConstantUtil.DEVICE_WIFI:
return "WIFI打卡";
case ConstantUtil.DEVICE_MACHINE:
return "考勤机打卡";
default:
return "未知";
}
}
@Override
public List<String> getRecipient(FastClockInNoticeModel attendanceNoticeModel) {
return CollUtil.newArrayList(attendanceNoticeModel.getUserId());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(FastClockInNoticeModel model, String noticeId) {
List<JumpUrl> list = new ArrayList<>();
list.add(new JumpUrl(AttendanceConstant.BTN_FAST_DETAIL_URL, AttendanceConstant.BTN_NAME_TO_DETAIL, AttendanceConstant.COLOR_BLACK));
list.add(new JumpUrl(AttendanceConstant.BTN_FAST_UPDATE_URL, AttendanceConstant.BTN_NAME_FAST_UPDATE, AttendanceConstant.COLOR_BLUE));
return SystemNoticeStrategy.builder()
.title(getTitle(model.getAttendanceNoticeEnum()))
.noticeModuleEnum(NoticeModuleEnum.KQ_DK)
.jumpUrls(list)
.build();
}
private String getTitle(AttendanceNoticeEnum attendanceNoticeEnum) {
String title = "";
if (AttendanceNoticeEnum.CHECK_IN_QUICK.equals(attendanceNoticeEnum)) {
title = AttendanceConstant.ON_WORK;
}
if (AttendanceNoticeEnum.CHECK_OUT_QUICK.equals(attendanceNoticeEnum)) {
title = AttendanceConstant.OFF_WORK;
}
return String.format(AttendanceConstant.TITLE_FAST, title);
}
@Override
public String getContext(List<QuickClockInModel> dataList) {
if (null == dataList || dataList.isEmpty()) {
return "";
}
QuickClockInModel model = dataList.get(0);
return model.getWorkTimeStr() + model.getRemark()+ "!" + "</br>" +
"打卡时间:" + model.getClockInTimeStr() + "</br>" +
"考勤方式:" + model.getClockInMethod() + "</br>" +
"考勤点:" + model.getClockInAddress();
}
}

View File

@@ -0,0 +1,105 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import jnpf.attendance.antifreeze.UserAntifreeze;
import jnpf.base.UserInfo;
import jnpf.constants.AttendanceConstant;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.model.attendance.model.AdminUpdateModel;
import jnpf.model.attendance.model.AdminUpdateNoticeModel;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.util.StringUtil;
import jnpf.util.UserProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import static jnpf.constants.AttendanceConstant.*;
import static jnpf.enums.attendance.UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE;
/**
* 考勤组锁定通知
*/
@Component(AttendanceConstant.ADMINISTRATOR_CHANGE)
public class GroupAdminUpdateNotice implements AttendanceNotice<AdminUpdateModel, AdminUpdateNoticeModel> {
@Autowired
private UserAntifreeze userAntifreeze;
@Resource
private AttendanceNoticeHandler attendanceNoticeHandler;
@Override
public Boolean isPass(AdminUpdateNoticeModel noticeModel) {
return Boolean.TRUE;
}
@Override
public List<AdminUpdateModel> generatingData(AdminUpdateNoticeModel noticeModel) {
return CollUtil.newArrayList(AdminUpdateModel.builder()
.type(noticeModel.getType())
.groupName(noticeModel.getGroupName())
.currentAuthority(noticeModel.getCurrentAuthority())
.sonAuthority(noticeModel.getSonAuthority())
.build());
}
@Override
public List<String> getRecipient(AdminUpdateNoticeModel noticeModel) {
return attendanceNoticeHandler.getUserIdsForFilterStatus(noticeModel.getUserIds(), ATTENDANCE_SETTING_MESSAGE_RECEIVE);
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(AdminUpdateNoticeModel noticeModel, String noticeId) {
UserInfo user = UserProvider.getUser();
ArrayList<JumpUrl> objects = CollUtil.newArrayList();
if (noticeModel.getType().equals(1)) {
objects.add(JumpUrl.builder().url(String.format(ADMINISTRATOR_CHANGE_URL1, noticeId))
.urlName(ADMINISTRATOR_CHANGE_BUTTON_NAME1).color(COLOR_BLACK).build());
objects.add(JumpUrl.builder().url(String.format(ADMINISTRATOR_CHANGE_URL2, noticeModel.getGroupId()))
.urlName(ADMINISTRATOR_CHANGE_BUTTON_NAME2).color(COLOR_BLUE).build());
return SystemNoticeStrategy.builder()
.title(String.format(ADMINISTRATOR_CHANGE_TITLE1, noticeModel.getGroupName()))
.noticeModuleEnum(NoticeModuleEnum.KQZ_GLY_BD)
.jumpUrls(objects)
.build();
} else {
objects.add(new JumpUrl(String.format(AttendanceConstant.GROUP_LOCK_URL1, user.getUserId()), AttendanceConstant.GROUP_LOCK_BUTTON_NAME1, AttendanceConstant.COLOR_BLACK,3,"contactInfo", JSON.toJSONString(new JSONObject(){{
put("contactId", user.getUserId());
}})));
return SystemNoticeStrategy.builder()
.title(String.format(ADMINISTRATOR_CHANGE_TITLE2, noticeModel.getGroupName()))
.noticeModuleEnum(NoticeModuleEnum.KQZ_GLY_BD)
.jumpUrls(objects)
.build();
}
}
@Override
public String getContext(List<AdminUpdateModel> data) {
StringBuffer stringBuffer = new StringBuffer();
AdminUpdateModel lockModel = data.stream().findFirst().orElse(null);
if (lockModel.getType().equals(1)) {
stringBuffer.append("当前考勤组权限:").append(lockModel.getCurrentAuthority());
} else {
UserInfo user = UserProvider.getUser();
List<PartUserInfoVo> allByIds = userAntifreeze.getAllByIds(CollUtil.newArrayList(user.getUserId()), user.getTenantId());
PartUserInfoVo partUserInfoVo = allByIds.stream().findFirst().orElse(null);
if (Objects.isNull(partUserInfoVo)) {
stringBuffer.append("操作人:无</br>");
} else {
stringBuffer.append("操作人:").append(partUserInfoVo.getRealName()).append("(").append(StringUtil.isEmpty(partUserInfoVo.getOrganizeName()) ? "暂无" : partUserInfoVo.getOrganizeName()).append("-").append(StringUtil.isEmpty(partUserInfoVo.getPositionName()) ? "暂无" : partUserInfoVo.getPositionName()).append(")</br>");
}
stringBuffer.append("您已不能再对【").append(lockModel.getGroupName()).append("】进行相应操作(包含查看成员考勤信息,对考勤组规则进行配置,对成员进行排班等操作)。").append("</br>");
}
return stringBuffer.toString();
}
}

View File

@@ -0,0 +1,107 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import jnpf.attendance.antifreeze.UserAntifreeze;
import jnpf.attendance.service.AttendanceUserService;
import jnpf.constants.AttendanceConstant;
import jnpf.entity.AttendanceGroupUser;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.model.AttendanceNoticeModel;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.LockModel;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.*;
/**
* 考勤组锁定通知
*/
@Component(AttendanceConstant.GROUP_LOCK)
public class GroupLockNotice implements AttendanceNotice<LockModel, AttendanceNoticeModel> {
@Autowired
private UserAntifreeze userAntifreeze;
@Resource
private AttendanceUserService attendanceUserService;
@Resource
private AttendanceNoticeHandler attendanceNoticeHandler;
@Override
public Boolean isPass(AttendanceNoticeModel noticeModel) {
return Boolean.TRUE;
}
@Override
public List<LockModel> generatingData(AttendanceNoticeModel noticeModel) {
List<LockModel> data = new ArrayList<>();
List<PartUserInfoVo> allByIds = userAntifreeze.getAllByIds(CollUtil.newArrayList(noticeModel.getUserId()), noticeModel.getTenantId());
PartUserInfoVo partUserInfoVo = allByIds.stream().findFirst().orElse(null);
StringBuffer stringBuffer = new StringBuffer();
if (Objects.isNull(partUserInfoVo)) {
stringBuffer.append("");
} else {
stringBuffer.append(partUserInfoVo.getRealName()).append("(").append(StringUtil.isEmpty(partUserInfoVo.getOrganizeName()) ? "暂无" : partUserInfoVo.getOrganizeName()).append("-").append(StringUtil.isEmpty(partUserInfoVo.getPositionName()) ? "暂无" : partUserInfoVo.getPositionName()).append(")");
}
data.add(LockModel.builder()
.date(new Date())
.userName(stringBuffer.toString())
.build());
return data;
}
@Override
public List<String> getRecipient(AttendanceNoticeModel noticeModel) {
Date date = new Date();
List<AttendanceGroupUser> userList = attendanceUserService.getAttendanceGroupUsersOfSecondment(date, date, null, List.of(noticeModel.getGroupId()));
return CollUtil.isEmpty(userList) ? null : attendanceNoticeHandler.getUserIdsForFilterStatus(
userList.stream().map(AttendanceGroupUser::getUserId).distinct().collect(Collectors.toList()),
UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE,
UserSettingEnum.ATTENDANCE_SETTING_ATTENDANCE_GROUP_LOCK_UNLOCK_NOTICE);
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(AttendanceNoticeModel noticeModel, String noticeId) {
ArrayList<JumpUrl> objects = CollUtil.newArrayList();
objects.add(JumpUrl.builder().url(String.format(GROUP_LOCK_URL1, noticeModel.getUserId()))
.urlName(GROUP_LOCK_BUTTON_NAME1).color(COLOR_BLACK)
.type(3)
.page("contactInfo")
.param(JSON.toJSONString(new JSONObject(){{
put("contactId", noticeModel.getUserId());
}}))
.build());
objects.add(JumpUrl.builder().url(String.format(GROUP_LOCK_URL2, noticeId))
.urlName(GROUP_LOCK_BUTTON_NAME2).color(COLOR_BLUE).build());
return SystemNoticeStrategy.builder()
.title(TITLE_GROUP_LOCK)
.noticeModuleEnum(NoticeModuleEnum.KQZ_SD)
.jumpUrls(objects)
.build();
}
@Override
public String getContext(List<LockModel> data) {
StringBuffer stringBuffer = new StringBuffer();
LockModel lockModel = data.stream().findFirst().orElse(null);
stringBuffer.append("操作人:").append(lockModel.getUserName()).append("</br>");
stringBuffer.append("当前所在考勤组已被管理员锁定,无法再对").append(DateUtil.format(lockModel.getDate(), "yyyy年MM月dd日"))
.append("之前的出勤结果做变更!");
return stringBuffer.toString();
}
}

View File

@@ -0,0 +1,94 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import jnpf.attendance.antifreeze.UserAntifreeze;
import jnpf.attendance.service.AttendanceUserService;
import jnpf.constants.AttendanceConstant;
import jnpf.entity.AttendanceGroupUser;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.model.AttendanceNoticeModel;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.model.attendance.model.UnLockModel;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.*;
/**
* 考勤组解锁通知
*/
@Component(AttendanceConstant.GROUP_UNLOCK)
public class GroupUnLockNotice implements AttendanceNotice<UnLockModel, AttendanceNoticeModel> {
@Autowired
private UserAntifreeze userAntifreeze;
@Resource
private AttendanceUserService attendanceUserService;
@Resource
private AttendanceNoticeHandler attendanceNoticeHandler;
@Override
public Boolean isPass(AttendanceNoticeModel noticeModel) {
return Boolean.TRUE;
}
@Override
public List<UnLockModel> generatingData(AttendanceNoticeModel noticeModel) {
List<UnLockModel> data = new ArrayList<>();
List<PartUserInfoVo> allByIds = userAntifreeze.getAllByIds(CollUtil.newArrayList(noticeModel.getUserId()), noticeModel.getTenantId());
PartUserInfoVo partUserInfoVo = allByIds.stream().findFirst().orElse(null);
StringBuffer stringBuffer = new StringBuffer();
if (Objects.isNull(partUserInfoVo)) {
stringBuffer.append("");
} else {
stringBuffer.append(partUserInfoVo.getRealName()).append("(").append(StringUtil.isEmpty(partUserInfoVo.getOrganizeName()) ? "暂无" : partUserInfoVo.getOrganizeName()).append("-").append(StringUtil.isEmpty(partUserInfoVo.getPositionName()) ? "暂无" : partUserInfoVo.getPositionName()).append(")");
}
data.add(UnLockModel.builder()
.userName(stringBuffer.toString())
.build());
return data;
}
@Override
public List<String> getRecipient(AttendanceNoticeModel noticeModel) {
Date date = new Date();
List<AttendanceGroupUser> userList = attendanceUserService.getAttendanceGroupUsersOfSecondment(date, date, null, List.of(noticeModel.getGroupId()));
return CollUtil.isEmpty(userList) ? null : attendanceNoticeHandler.getUserIdsForFilterStatus(
userList.stream().map(AttendanceGroupUser::getUserId).distinct().collect(Collectors.toList()),
UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE,
UserSettingEnum.ATTENDANCE_SETTING_ATTENDANCE_GROUP_LOCK_UNLOCK_NOTICE);
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(AttendanceNoticeModel noticeModel, String noticeId) {
ArrayList<JumpUrl> objects = CollUtil.newArrayList();
objects.add(JumpUrl.builder().url(String.format(GROUP_UNLOCK_URL, noticeId))
.urlName(GROUP_LOCK_BUTTON_NAME2).color(COLOR_BLACK).build());
return SystemNoticeStrategy.builder()
.title(TITLE_GROUP_UNLOCK)
.noticeModuleEnum(NoticeModuleEnum.KQZ_SD)
.jumpUrls(objects)
.build();
}
@Override
public String getContext(List<UnLockModel> data) {
StringBuffer stringBuffer = new StringBuffer();
UnLockModel unLockModel = data.stream().findFirst().orElse(null);
stringBuffer.append("操作人:").append(unLockModel.getUserName()).append("</br>");
stringBuffer.append("考勤组解锁后可以进行如下操作:");
return stringBuffer.toString();
}
}

View File

@@ -0,0 +1,63 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import jnpf.constants.AttendanceConstant;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.dto.LineDrawingPeriodDto;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.LineShiftChangeNoticeModel;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.*;
@Component(AttendanceConstant.LINE_SHIFT_NOT_SCHEDUING)
@Slf4j
public class LineNotSchedulingAttendanceNotice implements AttendanceNotice<LineDrawingPeriodDto, LineShiftChangeNoticeModel> {
@Autowired
private AttendanceNoticeHandler attendanceNoticeHandler;
@Override
public Boolean isPass(LineShiftChangeNoticeModel attendanceNoticeModel) {
return true;
}
@Override
public List<LineDrawingPeriodDto> generatingData(LineShiftChangeNoticeModel attendanceNoticeModel) {
//查询时段数据
return attendanceNoticeModel.getPeriods();
}
@Override
public List<String> getRecipient(LineShiftChangeNoticeModel attendanceNoticeModel) {
return attendanceNoticeModel.getUserIds().stream().filter(userId -> attendanceNoticeHandler.checkBeforeCondition(userId, UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE)).collect(Collectors.toList());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(LineShiftChangeNoticeModel attendanceNoticeModel, String noticeId) {
ArrayList<JumpUrl> objects = CollUtil.newArrayList();
objects.add(JumpUrl.builder().url(String.format(BTN_LINE_SCHEDULE_URL, JSON.toJSONString(attendanceNoticeModel.getAttendanceGroup())) + "&moduleId=" + attendanceNoticeModel.getModuleId()).urlName(BTN_SCHEDULE_GO).color(COLOR_BLACK).build());
return SystemNoticeStrategy.builder()
.title(ATTENDANCE_NOTICE_LINE_SCHEDULED_TITLE)
.noticeModuleEnum(NoticeModuleEnum.BC_BD)
.jumpUrls(objects)
.build();
}
@Override
public String getContext(List<LineDrawingPeriodDto> data) {
return "提醒通知:请您及时为划线排班人员排班!如已排班,请忽略";
}
}

View File

@@ -0,0 +1,82 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import jnpf.constants.AttendanceConstant;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.dto.LineDrawingPeriodDto;
import jnpf.model.attendance.model.*;
import jnpf.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.*;
@Component(AttendanceConstant.LINE_SHIFT_CHANG)
@Slf4j
public class LineShiftChangAttendanceNotice implements AttendanceNotice<LineDrawingPeriodDto, LineShiftChangeNoticeModel> {
@Autowired
private AttendanceNoticeHandler attendanceNoticeHandler;
@Override
public Boolean isPass(LineShiftChangeNoticeModel attendanceNoticeModel) {
return true;
}
@Override
public List<LineDrawingPeriodDto> generatingData(LineShiftChangeNoticeModel attendanceNoticeModel) {
//查询时段数据
if (CollUtil.isEmpty(attendanceNoticeModel.getPeriods())) {
return List.of(LineDrawingPeriodDto.builder().day(attendanceNoticeModel.getDay()).build());
}
return attendanceNoticeModel.getPeriods();
}
@Override
public List<String> getRecipient(LineShiftChangeNoticeModel attendanceNoticeModel) {
return CollUtil.isEmpty(attendanceNoticeModel.getUserIds()) ? List.of() : attendanceNoticeModel.getUserIds().stream().filter(userId -> attendanceNoticeHandler.checkBeforeCondition(userId, UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE)).collect(Collectors.toList());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(LineShiftChangeNoticeModel attendanceNoticeModel, String noticeId) {
ArrayList<JumpUrl> objects = CollUtil.newArrayList();
boolean hasSchedule = attendanceNoticeModel.getPeriods().stream().anyMatch(vo -> StringUtil.isNotEmpty(vo.getStart()));
if (hasSchedule) {
objects.add(JumpUrl.builder().url(BTN_FAST_UPDATE_URL).urlName(BTN_NAME_GO).color(COLOR_BLACK).build());
} else {
objects.add(JumpUrl.builder().build());
}
return SystemNoticeStrategy.builder()
.title(ATTENDANCE_NOTICE_LINE_SHIFT_CHANGE_TITLE)
.noticeModuleEnum(NoticeModuleEnum.BC_BD)
.jumpUrls(objects)
.build();
}
@Override
public String getContext(List<LineDrawingPeriodDto> data) {
if (CollUtil.isEmpty(data)) {
return null;
}
StringBuilder stringBuffer = new StringBuilder();
String dayStr = data.stream().map(LineDrawingPeriodDto::getDay).distinct().map(day -> DateUtil.format(day, "yyyy年MM月dd日") + "(" + DateUtil.dayOfWeekEnum(day).toChinese() + ")").collect(Collectors.joining(""));
stringBuffer.append("提醒通知:您在").append(dayStr);
if (data.stream().allMatch(vo -> Objects.isNull(vo.getStart()))) {
stringBuffer.append("暂无排班。");
return stringBuffer.toString();
}
if (data.stream().allMatch(vo -> StringUtil.isEmpty(vo.getStart()))) {
stringBuffer.append("的排班已取消。");
return stringBuffer.toString();
}
List<LineDrawingPeriodDto> data1 = data.stream().collect(Collectors.groupingBy(LineDrawingPeriodDto::getDay)).values().stream().findFirst().orElse(List.of());
stringBuffer.append("的排班调整为:").append(data1.stream().sorted(Comparator.comparing(LineDrawingPeriodDto::getStartType).thenComparing(LineDrawingPeriodDto::getStart)).map(vo -> vo.getStart() + "~" + vo.getEnd()).collect(Collectors.joining(""))).append("");
return stringBuffer.toString();
}
}

View File

@@ -0,0 +1,134 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import jnpf.constants.AttendanceConstant;
import jnpf.engine.DataStatisticsApi;
import jnpf.engine.model.flowstatistics.vo.TemplatePagesVo;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.NoClockInModel;
import jnpf.model.attendance.model.NoClockInNoticeModel;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.util.ConstantUtil;
import jnpf.util.DateDetail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* 缺卡/旷工消息服务
*
* @author yanwenfu
* @create 2024-08-13
*/
@Service(value = AttendanceConstant.WORK_MISSING)
public class NoClockInNotice implements AttendanceNotice<NoClockInModel, NoClockInNoticeModel> {
@Resource
private AttendanceNoticeHandler attendanceNoticeHandler;
@Autowired
private DataStatisticsApi dataStatisticsApi;
@Override
public Boolean isPass(NoClockInNoticeModel model) {
// 上班缺卡 下班缺卡 旷工
if (ConstantUtil.NUM_TRUE == model.getAbsence()) {
return attendanceNoticeHandler.checkBeforeCondition(model.getUserId(), UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE,
UserSettingEnum.ATTENDANCE_SETTING_CLASS_ABSENCE_REMINDER);
} else if (ConstantUtil.ON_WORK.equals(model.getClockInType())) {
return attendanceNoticeHandler.checkBeforeCondition(model.getUserId(), UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE,
UserSettingEnum.ATTENDANCE_SETTING_MISSING_CHECKIN_REMINDER);
} else {
return attendanceNoticeHandler.checkBeforeCondition(model.getUserId(), UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE,
UserSettingEnum.ATTENDANCE_SETTING_MISSING_END_WORK_REMINDER);
}
}
@Override
public List<NoClockInModel> generatingData(NoClockInNoticeModel model) {
String workTimeStr;
if (ConstantUtil.NUM_TRUE == model.getAbsence()) {
workTimeStr = DateDetail.getDate2Str(model.getOnWorkTime(), DateDetail.DF9)+ "" + DateDetail.getDate2Str(model.getOffWorkTime(), DateDetail.DF10);
} else if (ConstantUtil.ON_WORK.equals(model.getClockInType())) {
workTimeStr = DateDetail.getDate2Str(model.getOnWorkTime(), DateDetail.DF9);
} else {
workTimeStr = DateDetail.getDate2Str(model.getOffWorkTime(), DateDetail.DF9);
}
NoClockInModel noClockInModel = NoClockInModel.builder()
.workTimeStr(workTimeStr)
.remark(getTitle(model.getAbsence(), model.getClockInType()))
.absence(model.getAbsence())
.clockInType(model.getClockInType())
.build();
return List.of(noClockInModel);
}
private String getTitle(Integer absence, Integer clockInType) {
if (ConstantUtil.NUM_TRUE == absence) {
return AttendanceConstant.TITLE_ABSENCE;
} else if (ConstantUtil.ON_WORK.equals(clockInType)) {
return AttendanceConstant.TITLE_ON_WORK;
} else {
return AttendanceConstant.TITLE_OFF_WORK;
}
}
@Override
public List<String> getRecipient(NoClockInNoticeModel model) {
return List.of(model.getUserId());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(NoClockInNoticeModel model, String noticeId) {
// 查询url需要的参数(补卡审批)
List<TemplatePagesVo> list = dataStatisticsApi.getFeignTemplatePagesByBusinessType(ConstantUtil.REPAIR_TYPE);
String url = "";
if (null != list && !list.isEmpty()) {
TemplatePagesVo template = list.get(0);
JSONObject json = new JSONObject();
// 前端需要回显补卡的记录 所需的json格式
JSONObject data = new JSONObject();
data.set("clockInResultId", model.getClockInResultId());
json.set("interfaceData", data);
json.set("extraData", new JSONObject());
json.set("paramsData", new JSONObject());
JSONObject sourceData = new JSONObject();
sourceData.set("text", model.getClockInType().equals(ConstantUtil.ON_WORK) ? DateDetail.getDateTime2Str(model.getOnWorkTime()) : DateDetail.getDateTime2Str(model.getOffWorkTime()));
json.set("sourceData", sourceData);
json.set("tableData", new JSONArray());
url = String.format(AttendanceConstant.BTN_REPAIR_URL, template.getFlowId(), template.getTemplateId(), json);
}
return SystemNoticeStrategy.builder()
.title(getTitle(model.getAbsence(), model.getClockInType()))
.noticeModuleEnum(NoticeModuleEnum.KQ_DK)
.jumpUrls(List.of(new JumpUrl(url, AttendanceConstant.BTN_NAME_REPAIR, AttendanceConstant.COLOR_BLACK, "__UNI__65CF373")))
.build();
}
@Override
public String getContext(List<NoClockInModel> dataList) {
if (null == dataList || dataList.isEmpty()) {
return "";
}
NoClockInModel model = dataList.get(0);
if (ConstantUtil.NUM_TRUE == model.getAbsence()) {
return model.getWorkTimeStr() + " 上下班均未打卡,计为旷工!";
} else if (ConstantUtil.ON_WORK.equals(model.getClockInType())) {
return model.getWorkTimeStr() + " 上班已缺卡!";
} else {
return model.getWorkTimeStr() + " 下班已缺卡!";
}
}
}

View File

@@ -0,0 +1,132 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import jnpf.attendance.antifreeze.UserAntifreeze;
import jnpf.attendance.mapper.AttendanceManagerPermissionMapper;
import jnpf.attendance.service.AttendanceGroupService;
import jnpf.attendance.service.AttendanceUserService;
import jnpf.base.UserInfo;
import jnpf.constants.AttendanceConstant;
import jnpf.entity.AttendanceGroup;
import jnpf.entity.AttendanceGroupUser;
import jnpf.enums.attendance.AttendanceNoticeEnum;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.model.RuleChangeModel;
import jnpf.model.attendance.model.RuleChangeNoticeModel;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.model.attendance.vo.AttendanceGroupAdminVo;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.util.StringUtil;
import jnpf.util.UserProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.ATTENDANCE_NOTICE_ADMIN_RULE_CHANGE_TITLE;
import static jnpf.constants.AttendanceConstant.ATTENDANCE_NOTICE_RULE_CHANGE_TITLE;
@Component(AttendanceConstant.RULE_CHANGE_RATIO)
public class RuleChangeAttendanceNotice implements AttendanceNotice<RuleChangeModel, RuleChangeNoticeModel> {
@Autowired
private AttendanceGroupService attendanceGroupService;
@Autowired
private AttendanceNoticeHandler attendanceNoticeHandler;
@Autowired
private UserAntifreeze userAntifreeze;
@Override
public Boolean isPass(RuleChangeNoticeModel attendanceNoticeModel) {
return Boolean.TRUE;
}
@Override
public List<RuleChangeModel> generatingData(RuleChangeNoticeModel attendanceNoticeModel) {
String tips = "";
if (Objects.equals(attendanceNoticeModel.getAttendanceNoticeEnum(), AttendanceNoticeEnum.RULE_CHANGE_RATIO)) {
tips = String.format("出勤换算比由%s小时/天改为%s小时/天", attendanceNoticeModel.getOldValue(), attendanceNoticeModel.getNewValue());
}
if (Objects.equals(attendanceNoticeModel.getAttendanceNoticeEnum(), AttendanceNoticeEnum.RULE_CHANGE_FIELD)) {
tips = String.format("外勤打卡已调整为%s外勤打卡", Objects.equals(attendanceNoticeModel.getNewValue(), 1) ? "允许" : "不允许");
}
if (Objects.equals(attendanceNoticeModel.getAttendanceNoticeEnum(), AttendanceNoticeEnum.RULE_CHANGE_CARD_MAKEUP)) {
tips = String.format("补卡规则已调整为%s补卡", Objects.equals(attendanceNoticeModel.getNewValue(), 1) ? "允许" : "不允许");
}
if (Objects.equals(attendanceNoticeModel.getAttendanceNoticeEnum(), AttendanceNoticeEnum.RULE_CHANGE_GPS_SWIFT)) {
tips = String.format("考勤方式已%s使用GPS地点打卡", Objects.equals(attendanceNoticeModel.getNewValue(), 1) ? "允许" : "禁止");
if (Objects.equals(attendanceNoticeModel.getNewValue(), 1)) {
StringBuilder sb = new StringBuilder("</br><span style='font-weight: bold;'>可使用考勤点:</span>").append("</br>");
if (CollUtil.isNotEmpty(attendanceNoticeModel.getAddressList())) {
sb.append(String.join("</br>", attendanceNoticeModel.getAddressList()));
}
tips += sb.toString();
}
}
if (Objects.equals(attendanceNoticeModel.getAttendanceNoticeEnum(), AttendanceNoticeEnum.RULE_CHANGE_WIFI_SWIFT)) {
tips = String.format("考勤方式已%s使用WIFI打卡", Objects.equals(attendanceNoticeModel.getNewValue(), 1) ? "允许" : "不允许");
if (Objects.equals(attendanceNoticeModel.getNewValue(), 1)) {
StringBuilder sb = new StringBuilder("</br><span style='font-weight: bold;'>可使用考勤点:</span>").append("</br>");
if (CollUtil.isNotEmpty(attendanceNoticeModel.getAddressList())) {
sb.append(String.join("", attendanceNoticeModel.getAddressList()));
}
tips += sb.toString();
}
}
if (Objects.equals(attendanceNoticeModel.getAttendanceNoticeEnum(), AttendanceNoticeEnum.RULE_CHANGE_KQJ_SWIFT)) {
tips = String.format("考勤方式已%s使用考勤机打卡", Objects.equals(attendanceNoticeModel.getNewValue(), 1) ? "允许" : "不允许");
if (Objects.equals(attendanceNoticeModel.getNewValue(), 1)) {
StringBuilder sb = new StringBuilder("</br><span style='font-weight: bold;'>可使用考勤点:</span>").append("</br>");
if (CollUtil.isNotEmpty(attendanceNoticeModel.getAddressList())) {
sb.append(String.join("", attendanceNoticeModel.getAddressList()));
}
tips += sb.toString();
}
}
AttendanceGroup byId = attendanceGroupService.getById(attendanceNoticeModel.getGroupId());
return CollUtil.newArrayList(RuleChangeModel.builder()
.groupName(byId.getGroupName())
.tips(tips)
.build());
}
@Override
public List<String> getRecipient(RuleChangeNoticeModel attendanceNoticeModel) {
return attendanceNoticeHandler.getRecipientForSelfAndChild(attendanceNoticeModel.getGroupId(), attendanceNoticeModel.getIsAdmin());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(RuleChangeNoticeModel attendanceNoticeModel, String noticeId) {
return SystemNoticeStrategy.builder()
.noticeModuleEnum(NoticeModuleEnum.KQZ_BD)
.title(attendanceNoticeModel.getIsAdmin() ? ATTENDANCE_NOTICE_ADMIN_RULE_CHANGE_TITLE : ATTENDANCE_NOTICE_RULE_CHANGE_TITLE)
.isConfirm(Boolean.TRUE)
.build();
}
@Override
public String getContext(List<RuleChangeModel> data) {
if (CollUtil.isEmpty(data)) {
return null;
}
UserInfo user = UserProvider.getUser();
List<PartUserInfoVo> allByIds = userAntifreeze.getAllByIds(CollUtil.newArrayList(user.getUserId()), user.getTenantId());
PartUserInfoVo partUserInfoVo = allByIds.stream().findFirst().orElse(null);
StringBuffer stringBuffer = new StringBuffer();
RuleChangeModel ruleChangeModel = data.stream().findFirst().orElse(null);
stringBuffer.append("考勤组:").append(ruleChangeModel.getGroupName()).append("</br>");
if (Objects.isNull(partUserInfoVo)) {
stringBuffer.append("操作人:无</br>");
} else {
stringBuffer.append("操作人:").append(partUserInfoVo.getRealName()).append("(").append(StringUtil.isEmpty(partUserInfoVo.getOrganizeName()) ? "暂无" : partUserInfoVo.getOrganizeName()).append("-").append(StringUtil.isEmpty(partUserInfoVo.getPositionName()) ? "暂无" : partUserInfoVo.getPositionName()).append(")</br>");
}
stringBuffer.append(ruleChangeModel.getTips());
return stringBuffer.toString();
}
}

View File

@@ -0,0 +1,96 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import jnpf.constants.AttendanceConstant;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.model.DaySettlementModel;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.SettlementNoticeModel;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.util.DateUtil;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.*;
/**
* 日统计考勤结算通知
*/
@Component(AttendanceConstant.INDIVIDUAL_DAILY_STATISTICS)
public class SettlementDayNotice implements AttendanceNotice<DaySettlementModel, SettlementNoticeModel> {
@Resource
private AttendanceNoticeHandler attendanceNoticeHandler;
@Override
public Boolean isPass(SettlementNoticeModel settlementNoticeModel) {
return attendanceNoticeHandler.checkBeforeCondition(settlementNoticeModel.getUserId(),
UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE,
UserSettingEnum.ATTENDANCE_SETTING_DAILY_REPORT);
}
@Override
public List<DaySettlementModel> generatingData(SettlementNoticeModel settlementNoticeModel) {
return settlementNoticeModel.getDayNoticeModelList().stream().map(item -> DaySettlementModel.builder()
.groupName(item.getGroupName())
.shiftStr(String.join(" ", item.getShiftList()))
.shiftTimeStr(String.join(" ", item.getShiftTimeList()))
.clockTimeStr(String.join("|", item.getClockTimeList()))
.clockTime(item.getClockTime())
.shouldAttendHours(item.getShouldAttendHours())
.actualAttendHours(item.getActualAttendHours())
.workingHours(item.getWorkingHours())
.lateTimes(item.getLateTimes())
.lateMinutes(item.getLateMinutes())
.earlyLeaveTimes(item.getEarlyLeaveTimes())
.earlyLeaveMinutes(item.getEarlyLeaveMinutes())
.absenceCardTimes(item.getAbsenceCardTimes())
.absenceCardHours(item.getAbsenceCardHours())
.absenceTimes(item.getAbsenceTimes())
.absenceHours(item.getAbsenceHours())
.leaveHours(item.getLeaveHours())
.leaveDays(item.getLeaveDays())
.busDays(item.getBusDays())
.outDays(item.getOutDays())
.outHours(item.getOutHours())
.overtimeHours(item.getOvertimeHours())
.endDate(DateUtil.dateToString(new Date(), "yyyy年MM月dd日HH:mm"))
.build()).collect(Collectors.toList());
}
@Override
public List<String> getRecipient(SettlementNoticeModel settlementNoticeModel) {
return CollUtil.newArrayList(settlementNoticeModel.getUserId());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(SettlementNoticeModel settlementNoticeModel, String noticeId) {
ArrayList<JumpUrl> objects = CollUtil.newArrayList();
objects.add(JumpUrl.builder().url(String.format(INDIVIDUAL_DAILY_STATISTICS_URL1, noticeId))
.urlName(INDIVIDUAL_DAILY_STATISTICS_BUTTON_NAME1).color(COLOR_BLACK).build());
objects.add(JumpUrl.builder().url(INDIVIDUAL_DAILY_STATISTICS_URL2)
.urlName(INDIVIDUAL_DAILY_STATISTICS_BUTTON_NAME2).color(COLOR_BLUE).build());
return SystemNoticeStrategy.builder()
.title(settlementNoticeModel.getTitle())
.noticeModuleEnum(NoticeModuleEnum.GR_RB)
.jumpUrls(objects)
.build();
}
@Override
public String getContext(List<DaySettlementModel> data) {
DaySettlementModel daySettlementModel = data.stream().findFirst().orElse(null);
return "考勤组" + daySettlementModel.getGroupName() + "</br>" +
"当日班次:" + daySettlementModel.getShiftStr() + "</br>" +
"班次时间:" + daySettlementModel.getShiftTimeStr() + "</br>" +
"打卡时间:" + daySettlementModel.getClockTimeStr() + "</br>";
}
}

View File

@@ -0,0 +1,129 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import jnpf.constants.AttendanceConstant;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.MonthSettlementModel;
import jnpf.model.attendance.model.SettlementNoticeModel;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.*;
/**
* 日统计考勤结算通知
*/
@Component(AttendanceConstant.INDIVIDUAL_MONTHLY_STATISTICS)
public class SettlementMonthNotice implements AttendanceNotice<MonthSettlementModel, SettlementNoticeModel> {
@Resource
private AttendanceNoticeHandler attendanceNoticeHandler;
@Override
public Boolean isPass(SettlementNoticeModel settlementNoticeModel) {
return attendanceNoticeHandler.checkBeforeCondition(settlementNoticeModel.getUserId(),
UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE,
UserSettingEnum.ATTENDANCE_SETTING_PERSONAL_MONTHLY_REPORT);
}
@Override
public List<MonthSettlementModel> generatingData(SettlementNoticeModel settlementNoticeModel) {
return settlementNoticeModel.getMonthNoticeModelList().stream().map(item -> MonthSettlementModel.builder()
.cycleDate(item.getCycleDate())
.groupName(item.getGroupName())
.effectiveAttendDays(item.getEffectiveAttendDays())
.leaveDays(item.getLeaveDays())
.leaveHours(item.getLeaveHours())
.lateTimes(item.getLateTimes())
.earlyLeaveTimes(item.getEarlyLeaveTimes())
.absenceCardTimes(item.getAbsenceCardTimes())
.absenceTimes(item.getAbsenceTimes())
.busTimes(item.getBusTimes())
.outTimes(item.getOutTimes())
.overtimeTimes(item.getOvertimeTimes())
.endDate(item.getEndDate())
.build()).collect(Collectors.toList());
}
@Override
public List<String> getRecipient(SettlementNoticeModel settlementNoticeModel) {
return CollUtil.newArrayList(settlementNoticeModel.getUserId());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(SettlementNoticeModel settlementNoticeModel, String noticeId) {
ArrayList<JumpUrl> objects = CollUtil.newArrayList();
objects.add(JumpUrl.builder().url(String.format(INDIVIDUAL_MONTHLY_STATISTICS_URL1, noticeId))
.urlName(INDIVIDUAL_MONTHLY_STATISTICS_BUTTON_NAME1).color(COLOR_BLACK).build());
objects.add(JumpUrl.builder().url(INDIVIDUAL_MONTHLY_STATISTICS_URL2)
.urlName(INDIVIDUAL_MONTHLY_STATISTICS_BUTTON_NAME2).color(COLOR_BLUE).build());
return SystemNoticeStrategy.builder()
.title(settlementNoticeModel.getTitle())
.noticeModuleEnum(NoticeModuleEnum.GR_RB)
.jumpUrls(objects)
.build();
}
@Override
public String getContext(List<MonthSettlementModel> data) {
MonthSettlementModel monthSettlementModel = data.stream().findFirst().orElse(null);
StringBuilder stringBuffer = new StringBuilder();
stringBuffer.append("时间:").append(monthSettlementModel.getCycleDate()).append("</br>");
stringBuffer.append("考勤组:").append(monthSettlementModel.getGroupName()).append("</br>");
stringBuffer.append("出勤情况:").append("</br>");
getTipsStr(monthSettlementModel, stringBuffer);
return stringBuffer.toString();
}
private void getTipsStr(MonthSettlementModel monthSettlementModel, StringBuilder tips) {
if (monthSettlementModel.getEffectiveAttendDays().compareTo(BigDecimal.ZERO) > 0) {
tips.append("出勤天数:").append(monthSettlementModel.getEffectiveAttendDays()).append("天</br>");
} else if (monthSettlementModel.getLeaveDays().compareTo(BigDecimal.ZERO) > 0) {
tips.append("请假天数:").append(getFieldValue(monthSettlementModel.getLeaveDays(), monthSettlementModel.getLeaveHours())).append("</br>");
} else if (monthSettlementModel.getLateTimes() > 0) {
tips.append("迟到次数:").append(monthSettlementModel.getLateTimes()).append("次</br>");
} else if (monthSettlementModel.getEarlyLeaveTimes() > 0) {
tips.append("早退次数:").append(monthSettlementModel.getEarlyLeaveTimes()).append("次</br>");
} else if (monthSettlementModel.getAbsenceCardTimes() > 0) {
tips.append("缺卡次数:").append(monthSettlementModel.getAbsenceCardTimes()).append("次</br>");
} else if (monthSettlementModel.getAbsenceTimes() > 0) {
tips.append("缺勤次数:").append(monthSettlementModel.getAbsenceTimes()).append("次</br>");
} else if (monthSettlementModel.getBusTimes() > 0) {
tips.append("出差次数:").append(monthSettlementModel.getBusTimes()).append("次</br>");
} else if (monthSettlementModel.getOutTimes() > 0) {
tips.append("外出次数:").append(monthSettlementModel.getOutTimes()).append("次</br>");
} else if (monthSettlementModel.getOvertimeTimes() > 0) {
tips.append("加班次数:").append(monthSettlementModel.getOvertimeTimes()).append("次</br>");
}
}
/**
* 生成组合字段值
*
* @param durationDays 时长天数
* @param durationHours 时长小时
* @return 组合字段值
*/
private static String getFieldValue(BigDecimal durationDays, BigDecimal durationHours) {
StringBuilder sb = new StringBuilder();
if (durationDays.compareTo(BigDecimal.ZERO) == 0 && durationHours.compareTo(BigDecimal.ZERO) == 0) {
sb.append("0天");
} else if (durationDays.compareTo(BigDecimal.ZERO) > 0 && durationHours.compareTo(BigDecimal.ZERO) > 0) {
sb.append(durationDays).append("").append(durationHours).append("小时");
} else if (durationDays.compareTo(BigDecimal.ZERO) == 0 && durationHours.compareTo(BigDecimal.ZERO) > 0) {
sb.append(durationHours).append("小时");
} else if (durationDays.compareTo(BigDecimal.ZERO) > 0 && durationHours.compareTo(BigDecimal.ZERO) == 0) {
sb.append(durationDays).append("");
}
return sb.toString();
}
}

View File

@@ -0,0 +1,118 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import com.google.common.collect.Maps;
import jnpf.constants.AttendanceConstant;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.SettlementNoticeModel;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.model.attendance.model.TeamMonthSettlementModel;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.*;
/**
* 日统计考勤结算通知
*/
@Component(AttendanceConstant.TEAM_MONTHLY_STATISTICS)
public class SettlementTeamMonthNotice implements AttendanceNotice<TeamMonthSettlementModel, SettlementNoticeModel> {
@Override
public Boolean isPass(SettlementNoticeModel settlementNoticeModel) {
return Boolean.TRUE;
}
@Override
public List<TeamMonthSettlementModel> generatingData(SettlementNoticeModel settlementNoticeModel) {
return settlementNoticeModel.getTeamMonthNoticeModelList().stream().map(item -> TeamMonthSettlementModel.builder()
.groupName(item.getGroupName())
.normalCount(item.getNormalCount())
.leaveCount(item.getLeaveCount())
.lateCount(item.getLateCount())
.earlyLeaveCount(item.getEarlyLeaveCount())
.absenceCardCount(item.getAbsenceCardCount())
.absenceCount(item.getAbsenceCount())
.busCount(item.getBusCount())
.outCount(item.getOutCount())
.overtimeCount(item.getOvertimeCount())
.endDate(item.getEndDate())
.build()).collect(Collectors.toList());
}
@Override
public List<String> getRecipient(SettlementNoticeModel settlementNoticeModel) {
return CollUtil.newArrayList(settlementNoticeModel.getUserIds());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(SettlementNoticeModel settlementNoticeModel, String noticeId) {
ArrayList<JumpUrl> objects = CollUtil.newArrayList();
objects.add(JumpUrl.builder().url(String.format(TEAM_MONTHLY_STATISTICS_URL1, noticeId))
.urlName(TEAM_MONTHLY_STATISTICS_BUTTON_NAME1).color(COLOR_BLACK).build());
objects.add(JumpUrl.builder().url(TEAM_MONTHLY_STATISTICS_URL2)
.urlName(TEAM_MONTHLY_STATISTICS_BUTTON_NAME2).color(COLOR_BLUE).build());
return SystemNoticeStrategy.builder()
.title(settlementNoticeModel.getTitle())
.noticeModuleEnum(NoticeModuleEnum.GR_RB)
.jumpUrls(objects)
.build();
}
@Override
public String getContext(List<TeamMonthSettlementModel> data) {
TeamMonthSettlementModel teamMonthSettlementModel = data.stream().findFirst().orElse(null);
StringBuilder stringBuffer = new StringBuilder();
stringBuffer.append("考勤组:").append(teamMonthSettlementModel.getGroupName()).append("</br>");
stringBuffer.append("出勤情况:").append("</br>");;
getTipsList(teamMonthSettlementModel, stringBuffer);
return stringBuffer.toString();
}
private void getTipsList(TeamMonthSettlementModel teamMonthSettlementModel, StringBuilder tips) {
LinkedHashMap<String, Integer> map = Maps.newLinkedHashMap();
if (teamMonthSettlementModel.getNormalCount() > 0) {
map.put("正常", teamMonthSettlementModel.getNormalCount());
}
if (teamMonthSettlementModel.getLeaveCount() > 0) {
map.put("请假", teamMonthSettlementModel.getLeaveCount());
}
if (teamMonthSettlementModel.getLateCount() > 0) {
map.put("迟到", teamMonthSettlementModel.getLateCount());
}
if (teamMonthSettlementModel.getEarlyLeaveCount() > 0) {
map.put("早退", teamMonthSettlementModel.getEarlyLeaveCount());
}
if (teamMonthSettlementModel.getAbsenceCardCount() > 0) {
map.put("缺卡", teamMonthSettlementModel.getAbsenceCardCount());
}
if (teamMonthSettlementModel.getAbsenceCount() > 0) {
map.put("旷工", teamMonthSettlementModel.getAbsenceCount());
}
if (teamMonthSettlementModel.getBusCount() > 0) {
map.put("出差", teamMonthSettlementModel.getBusCount());
}
if (teamMonthSettlementModel.getOutCount() > 0) {
map.put("外出", teamMonthSettlementModel.getOutCount());
}
if (teamMonthSettlementModel.getOvertimeCount() > 0) {
map.put("加班", teamMonthSettlementModel.getOvertimeCount());
}
int i = 0;
for (Map.Entry<String, Integer> stringIntegerEntry : map.entrySet()) {
if (i > 1) {
break;
}
tips.append(stringIntegerEntry.getKey()).append("").append(stringIntegerEntry.getValue()).append("人</br>");
i++;
}
}
}

View File

@@ -0,0 +1,173 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jnpf.attendance.antifreeze.UserAntifreeze;
import jnpf.attendance.service.AttendanceShiftNameSettingService;
import jnpf.attendance.service.AttendanceShiftSettingPeriodService;
import jnpf.base.UserInfo;
import jnpf.constants.AttendanceConstant;
import jnpf.entity.attendance.AttendanceShiftNameEntity;
import jnpf.entity.attendance.AttendanceShiftSettingPeriodEntity;
import jnpf.enums.attendance.AttendanceTypeEnum;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.ShiftChangModel;
import jnpf.model.attendance.model.ShiftChangeNoticeModel;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.model.attendance.vo.AttendanceShiftSettingPeriodVo;
import jnpf.model.attendance.vo.DailyRuleResultVo;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.util.StringUtil;
import jnpf.util.UserProvider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.*;
@Component(AttendanceConstant.SHIFT_CHANG)
@Slf4j
public class ShiftChangAttendanceNotice implements AttendanceNotice<ShiftChangModel, ShiftChangeNoticeModel> {
@Autowired
private UserAntifreeze userAntifreeze;
@Autowired
private AttendanceShiftNameSettingService attendanceShiftNameSettingService;
@Autowired
private AttendanceShiftSettingPeriodService attendanceShiftSettingPeriodService;
@Autowired
private AttendanceNoticeHandler attendanceNoticeHandler;
@Override
public Boolean isPass(ShiftChangeNoticeModel attendanceNoticeModel) {
return attendanceNoticeHandler.checkBeforeCondition(attendanceNoticeModel.getUserId(), UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE,
UserSettingEnum.ATTENDANCE_SETTING_CLASS_CHANGE_REMINDER);
}
@Override
public List<ShiftChangModel> generatingData(ShiftChangeNoticeModel attendanceNoticeModel) {
List<ShiftChangModel> shiftChangModels = CollUtil.newArrayList();
//查询时段数据
List<DailyRuleResultVo> dailyRuleResultVos = attendanceNoticeModel.getDailyRuleResultVos();
List<String> collect = dailyRuleResultVos.stream().map(DailyRuleResultVo::getFromShiftId).filter(StringUtil::isNotEmpty).collect(Collectors.toList());
List<String> collect1 = dailyRuleResultVos.stream().map(DailyRuleResultVo::getToShiftId).filter(StringUtil::isNotEmpty).collect(Collectors.toList());
if (CollUtil.isNotEmpty(collect1)) {
collect.addAll(collect1);
}
List<AttendanceShiftSettingPeriodEntity> list1 = CollUtil.isEmpty(collect1) ? CollUtil.newArrayList() : attendanceShiftSettingPeriodService.list(new LambdaQueryWrapper<AttendanceShiftSettingPeriodEntity>()
.in(AttendanceShiftSettingPeriodEntity::getShiftId, collect1).eq(AttendanceShiftSettingPeriodEntity::getDeleteMark, Boolean.FALSE));
List<AttendanceShiftSettingPeriodVo> attendanceShiftSettingPeriodVos = BeanUtil.copyToList(list1, AttendanceShiftSettingPeriodVo.class);
Map<String, List<AttendanceShiftSettingPeriodVo>> periodMap = attendanceShiftSettingPeriodVos.stream().collect(Collectors.groupingBy(AttendanceShiftSettingPeriodVo::getShiftId));
List<AttendanceShiftNameEntity> attendanceShiftNameEntities = CollUtil.isEmpty(collect) ? CollUtil.newArrayList() : attendanceShiftNameSettingService.listByIds(collect);
Map<String, AttendanceShiftNameEntity> shiftMap = attendanceShiftNameEntities.stream().collect(Collectors.toMap(AttendanceShiftNameEntity::getId, entity -> entity));
dailyRuleResultVos.stream().collect(Collectors.groupingBy(DailyRuleResultVo::getDate)).forEach((day, dailyRuleVos) -> {
//旧班次名称
String oldShiftName = "";
//新班次名称
String newShiftName = "";
//新班次时间
String newShift = "";
Map<Integer, List<DailyRuleResultVo>> collect2 = dailyRuleVos.stream()
.sorted(Comparator.comparing(vo -> Objects.isNull(vo.getToSchedulesType()) ? 1 : vo.getToSchedulesType()))
.collect(Collectors.groupingBy(vo -> Objects.isNull(vo.getToSchedulesType()) ? 1 : vo.getToSchedulesType()));
int size = collect2.size();
int i = 0;
for (Map.Entry<Integer, List<DailyRuleResultVo>> stringListEntry : collect2.entrySet()) {
DailyRuleResultVo dailyRuleVo = stringListEntry.getValue().get(0);
AttendanceShiftNameEntity toShiftEntity = shiftMap.getOrDefault(dailyRuleVo.getToShiftId(), null);
newShiftName += (newShiftName.length() > 0 ? " | " : "") + (Objects.equals(dailyRuleVo.getToType(), AttendanceTypeEnum.ORDINARY.getCode()) ? Objects.isNull(toShiftEntity) ? "" : toShiftEntity.getShortName() : Objects.isNull(dailyRuleVo.getToType()) ? "" : AttendanceTypeEnum.getMsg(dailyRuleVo.getToType()));
List<AttendanceShiftSettingPeriodVo> attendanceShiftSettingPeriodVos1 = periodMap.get(dailyRuleVo.getToShiftId());
if (CollUtil.isEmpty(attendanceShiftSettingPeriodVos1) || !Objects.equals(dailyRuleVo.getToType(), AttendanceTypeEnum.ORDINARY.getCode())) {
i++;
continue;
}
if (size < 2) {
for (AttendanceShiftSettingPeriodVo attendanceShiftSettingPeriodVo : attendanceShiftSettingPeriodVos1) {
newShift += (newShift.length() > 0 ? " | " : "") + attendanceShiftSettingPeriodVo.getInPoint() + "" + attendanceShiftSettingPeriodVo.getOutPoint();
}
continue;
}
if (i == 0) {
AttendanceShiftSettingPeriodVo attendanceShiftSettingPeriodVo = attendanceShiftSettingPeriodVos1.stream().findFirst().orElse(null);
newShift = attendanceShiftSettingPeriodVo.getInPoint() + "" + attendanceShiftSettingPeriodVo.getOutPoint();
} else {
AttendanceShiftSettingPeriodVo attendanceShiftSettingPeriodVo = attendanceShiftSettingPeriodVos1.stream().reduce((p1, p2) -> p2).orElse(null);
newShift += (newShift.length() > 0 ? " | " : "") + attendanceShiftSettingPeriodVo.getInPoint() + "" + attendanceShiftSettingPeriodVo.getOutPoint();
}
i++;
}
Map<Integer, List<DailyRuleResultVo>> collect3 = dailyRuleVos.stream()
.sorted(Comparator.comparing(vo -> Objects.isNull(vo.getFromSchedulesType()) ? 1 : vo.getFromSchedulesType()))
.collect(Collectors.groupingBy(vo -> Objects.isNull(vo.getFromSchedulesType()) ? 1 : vo.getFromSchedulesType()));
for (Map.Entry<Integer, List<DailyRuleResultVo>> stringListEntry : collect3.entrySet()) {
DailyRuleResultVo dailyRuleVo = stringListEntry.getValue().stream().findFirst().orElse(null);
if (collect2.containsKey(stringListEntry.getKey())) {
List<DailyRuleResultVo> dailyRuleResultVos1 = collect2.get(stringListEntry.getKey());
List<DailyRuleResultVo> collect4 = dailyRuleResultVos1.stream().filter(result -> StringUtil.equals(result.getToId(), dailyRuleVo.getFromId())).collect(Collectors.toList());
if (CollUtil.isNotEmpty(collect4)) {
continue;
}
}
AttendanceShiftNameEntity fromShiftEntity = shiftMap.getOrDefault(dailyRuleVo.getFromShiftId(), null);
oldShiftName += (oldShiftName.length() > 0 ? " | " : "") + (Objects.equals(dailyRuleVo.getFromType(), AttendanceTypeEnum.ORDINARY.getCode()) && Objects.nonNull(fromShiftEntity) ? fromShiftEntity.getShortName() : Objects.isNull(dailyRuleVo.getFromType()) ? "" : AttendanceTypeEnum.getMsg(dailyRuleVo.getFromType()));
}
shiftChangModels.add(ShiftChangModel.builder().day(day).oldShiftName(oldShiftName).newShiftName(newShiftName).newShift(newShift).build());
});
return shiftChangModels.stream().sorted(Comparator.comparing(ShiftChangModel::getDay)).collect(Collectors.toList());
}
@Override
public List<String> getRecipient(ShiftChangeNoticeModel attendanceNoticeModel) {
return CollUtil.newArrayList(attendanceNoticeModel.getUserId());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(ShiftChangeNoticeModel attendanceNoticeModel, String noticeId) {
ArrayList<JumpUrl> objects = CollUtil.newArrayList();
objects.add(JumpUrl.builder().url(String.format(ATTENDANCE_NOTICE_SHIFT_CHANGE_DETAIL_URL, noticeId)).urlName(ATTENDANCE_NOTICE_DETAIL_BUTTON_NAME).color(COLOR_BLACK).build());
objects.add(JumpUrl.builder().url(ATTENDANCE_NOTICE_CLICK_URL).urlName(ATTENDANCE_NOTICE_TO_CLICK).color(COLOR_BLUE).build());
return SystemNoticeStrategy.builder()
.title(ATTENDANCE_NOTICE_SHIFT_CHANGE_TITLE)
.noticeModuleEnum(NoticeModuleEnum.BC_BD)
.jumpUrls(objects)
.build();
}
@Override
public String getContext(List<ShiftChangModel> data) {
if (CollUtil.isEmpty(data)) {
return null;
}
UserInfo user = UserProvider.getUser();
List<PartUserInfoVo> allByIds = userAntifreeze.getAllByIds(CollUtil.newArrayList(user.getUserId()), user.getTenantId());
if (CollUtil.isEmpty(allByIds)) {
log.error("请求用户服务失败或者未查询到当前用户数据:{}", user.getUserId());
return null;
}
PartUserInfoVo partUserInfoVo = allByIds.stream().findFirst().orElse(null);
StringBuffer stringBuffer = new StringBuffer();
if (Objects.isNull(partUserInfoVo)) {
stringBuffer.append("操作人:无</br>");
} else {
stringBuffer.append("操作人:").append(partUserInfoVo.getRealName()).append("(").append(StringUtil.isEmpty(partUserInfoVo.getOrganizeName()) ? "暂无" : partUserInfoVo.getOrganizeName()).append("-").append(StringUtil.isEmpty(partUserInfoVo.getPositionName()) ? "暂无" : partUserInfoVo.getPositionName()).append(")</br>");
}
if (data.size() > 1) {
stringBuffer.append("变更日期:").append(StringUtil.join(data.stream().map(shiftChangModel1 -> DateUtil.format(shiftChangModel1.getDay(), "yyyy.MM.dd")).collect(Collectors.toList()), "")).append("</br>");
return stringBuffer.toString();
}
ShiftChangModel shiftChangModel = data.stream().findFirst().orElse(null);
stringBuffer.append("变更日期:").append(DateUtil.format(shiftChangModel.getDay(), "yyyy.MM.dd")).append("</br>");
stringBuffer.append("新班次名称:").append(StringUtil.isEmpty(shiftChangModel.getNewShiftName()) ? "" : shiftChangModel.getNewShiftName()).append("</br>");
stringBuffer.append("新班次时间:").append(StringUtil.isEmpty(shiftChangModel.getNewShift()) ? "" : shiftChangModel.getNewShift());
return stringBuffer.toString();
}
}

View File

@@ -0,0 +1,89 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import jnpf.attendance.antifreeze.UserAntifreeze;
import jnpf.attendance.service.AttendanceGroupService;
import jnpf.base.UserInfo;
import jnpf.constants.AttendanceConstant;
import jnpf.entity.AttendanceGroup;
import jnpf.enums.attendance.AttendanceNoticeEnum;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.model.attendance.model.SystemTypeChangeModel;
import jnpf.model.attendance.model.SystemTypeChangeNoticeModel;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.util.StringUtil;
import jnpf.util.UserProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Objects;
import static jnpf.constants.AttendanceConstant.ATTENDANCE_NOTICE_ADMIN_RULE_CHANGE_TITLE;
import static jnpf.constants.AttendanceConstant.ATTENDANCE_NOTICE_RULE_CHANGE_TITLE;
@Component(AttendanceConstant.RULE_CHANGE_SHIFT_SYSTEM)
public class SystemTypeChangeAttendanceNotice implements AttendanceNotice<SystemTypeChangeModel, SystemTypeChangeNoticeModel> {
@Autowired
private AttendanceGroupService attendanceGroupService;
@Autowired
private UserAntifreeze userAntifreeze;
@Autowired
private AttendanceNoticeHandler attendanceNoticeHandler;
@Override
public Boolean isPass(SystemTypeChangeNoticeModel attendanceNoticeModel) {
if (!attendanceNoticeModel.getAttendanceNoticeEnum().equals(AttendanceNoticeEnum.RULE_CHANGE_SHIFT_SYSTEM)) {
return Boolean.FALSE;
}
return Boolean.TRUE;
}
@Override
public List<SystemTypeChangeModel> generatingData(SystemTypeChangeNoticeModel attendanceNoticeModel) {
AttendanceGroup byId = attendanceGroupService.getById(attendanceNoticeModel.getGroupId());
return CollUtil.newArrayList(SystemTypeChangeModel.builder()
.groupName(byId.getGroupName())
.oldSystemType(Objects.equals(attendanceNoticeModel.getSystemType(), 2) ? "固定班制" : "排班制")
.newSystemType(Objects.equals(attendanceNoticeModel.getSystemType(), 1) ? "固定班制" : "排班制")
.build());
}
@Override
public List<String> getRecipient(SystemTypeChangeNoticeModel attendanceNoticeModel) {
return attendanceNoticeHandler.getRecipientForSelfAndChild(attendanceNoticeModel.getGroupId(), attendanceNoticeModel.getIsAdmin());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(SystemTypeChangeNoticeModel attendanceNoticeModel, String noticeId) {
return SystemNoticeStrategy.builder()
.noticeModuleEnum(NoticeModuleEnum.KQZ_BD)
.title(attendanceNoticeModel.getIsAdmin() ? ATTENDANCE_NOTICE_ADMIN_RULE_CHANGE_TITLE : ATTENDANCE_NOTICE_RULE_CHANGE_TITLE)
.isConfirm(Boolean.TRUE)
.build();
}
@Override
public String getContext(List<SystemTypeChangeModel> data) {
if (CollUtil.isEmpty(data)) {
return null;
}
UserInfo user = UserProvider.getUser();
List<PartUserInfoVo> allByIds = userAntifreeze.getAllByIds(CollUtil.newArrayList(user.getUserId()), user.getTenantId());
PartUserInfoVo partUserInfoVo = allByIds.stream().findFirst().orElse(null);
StringBuffer stringBuffer = new StringBuffer();
SystemTypeChangeModel systemTypeChangeModel = data.stream().findFirst().orElse(null);
stringBuffer.append("考勤组:").append(systemTypeChangeModel.getGroupName()).append("</br>");
if (Objects.isNull(partUserInfoVo)) {
stringBuffer.append("操作人:无</br>");
} else {
stringBuffer.append("操作人:").append(partUserInfoVo.getRealName()).append("(").append(StringUtil.isEmpty(partUserInfoVo.getOrganizeName()) ? "暂无" : partUserInfoVo.getOrganizeName()).append("-").append(StringUtil.isEmpty(partUserInfoVo.getPositionName()) ? "暂无" : partUserInfoVo.getPositionName()).append(")</br>");
}
stringBuffer.append("考勤组类型已由").append(systemTypeChangeModel.getOldSystemType()).append("改为").append(systemTypeChangeModel.getNewSystemType());
return stringBuffer.toString();
}
}

View File

@@ -0,0 +1,177 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import jnpf.attendance.antifreeze.UserAntifreeze;
import jnpf.attendance.mapper.AttendanceManagerPermissionMapper;
import jnpf.attendance.service.AttendanceGroupService;
import jnpf.constants.AttendanceConstant;
import jnpf.entity.AttendanceGroup;
import jnpf.enums.attendance.AttendanceNoticeEnum;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.model.attendance.model.UserChangModel;
import jnpf.model.attendance.model.UserChangeNoticeModel;
import jnpf.model.attendance.vo.AttendanceGroupAdminVo;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.util.DateUtil;
import jnpf.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.*;
import static jnpf.enums.attendance.AttendanceNoticeEnum.*;
import static jnpf.enums.attendance.UserSettingEnum.*;
/**
* 考勤组人员变动通知
*/
@Component(AttendanceConstant.JOIN_GROUP)
public class UserChangAttendanceNotice implements AttendanceNotice<UserChangModel, UserChangeNoticeModel> {
@Autowired
private UserAntifreeze userAntifreeze;
@Resource
private AttendanceNoticeHandler attendanceNoticeHandler;
@Resource
private AttendanceManagerPermissionMapper attendanceManagerPermissionMapper;
@Autowired
private AttendanceGroupService attendanceGroupService;
@Override
public Boolean isPass(UserChangeNoticeModel attendanceNoticeModel) {
return Boolean.TRUE;
}
@Override
public List<UserChangModel> generatingData(UserChangeNoticeModel attendanceNoticeModel) {
List<UserChangModel> shiftChangModels = CollUtil.newArrayList();
String tips = "";
AttendanceGroup byId = null;
List<String> realNames = null;
if (Objects.equals(AttendanceNoticeEnum.REMOVE_USER_REMOVE_GROUP, attendanceNoticeModel.getAttendanceNoticeEnum())
|| Objects.equals(AttendanceNoticeEnum.REMOVE_USER, attendanceNoticeModel.getAttendanceNoticeEnum())) {
tips = "请尽快联系管理员加入考勤组,以确保可以使用考勤打卡";
} else {
//获取管理员
List<AttendanceGroupAdminVo> attendanceGroupAdminVos = attendanceManagerPermissionMapper.queryGroupUser(attendanceNoticeModel.getJoinGroupId());
List<String> adminUserIds = attendanceGroupAdminVos.stream().map(AttendanceGroupAdminVo::getUserId).collect(Collectors.toList());
byId = attendanceGroupService.getById(attendanceNoticeModel.getJoinGroupId());
Assert.isFalse(Objects.isNull(byId), "变更考勤组通知,未查询到考勤组信息[{}]", attendanceNoticeModel.getJoinGroupId());
List<PartUserInfoVo> allByIds = CollUtil.isEmpty(adminUserIds) ? CollUtil.newArrayList() : userAntifreeze.getAllByIds(adminUserIds, attendanceNoticeModel.getTenantId());
realNames = allByIds.stream().map(PartUserInfoVo::getRealName).collect(Collectors.toList());
}
shiftChangModels.add(UserChangModel.builder()
.type(attendanceNoticeModel.getAttendanceNoticeEnum().getCode())
.administratorList(CollUtil.isEmpty(realNames) ? "" : StringUtil.join(realNames, ""))
.joinGroup(Objects.isNull(byId) ? "" : byId.getGroupName())
.start(Objects.isNull(attendanceNoticeModel.getStart()) ? "" : DateUtil.dateToString(attendanceNoticeModel.getStart(), "yyyy年MM月dd日 HH:mm"))
.reason(getReason(attendanceNoticeModel.getAttendanceNoticeEnum(), Objects.isNull(byId) ? "" : byId.getGroupName()))
.tips(tips)
.build());
return shiftChangModels;
}
/**
* @param attendanceNoticeEnum
* @param groupName
* @return
*/
private String getReason(AttendanceNoticeEnum attendanceNoticeEnum, String groupName) {
if (Objects.equals(attendanceNoticeEnum, AttendanceNoticeEnum.JOIN_GROUP)) {
return "";
}
if (Objects.equals(attendanceNoticeEnum, AttendanceNoticeEnum.GROUP_CHANGE_REMOVE_JOIN_GROUP)) {
return "原考勤组已解散,已加入新考勤组!";
}
if (Objects.equals(attendanceNoticeEnum, AttendanceNoticeEnum.REMOVE_USER_REMOVE_GROUP)) {
return "原考勤组已解散";
}
if (Objects.equals(attendanceNoticeEnum, AttendanceNoticeEnum.REMOVE_USER)) {
return "已从考勤组中移除";
}
if (Objects.equals(attendanceNoticeEnum, AttendanceNoticeEnum.GROUP_CHANGE_PROMOTION)) {
return String.format("晋升已产生,已加入【%s】", groupName);
}
if (Objects.equals(attendanceNoticeEnum, AttendanceNoticeEnum.GROUP_CHANGE_TRANSFER_POSITION)) {
return String.format("调岗已产生,已加入【%s】", groupName);
}
if (Objects.equals(attendanceNoticeEnum, AttendanceNoticeEnum.GROUP_CHANGE_SECONDMENT)) {
return String.format("借调申请已通过,借调至【%s】", groupName);
}
return "";
}
@Override
public List<String> getRecipient(UserChangeNoticeModel attendanceNoticeModel) {
UserSettingEnum userSettingEnum = AttendanceNoticeEnum.JOIN_GROUP.equals(attendanceNoticeModel.getAttendanceNoticeEnum()) || REMOVE_USER.equals(attendanceNoticeModel.getAttendanceNoticeEnum()) || AttendanceNoticeEnum.REMOVE_USER_REMOVE_GROUP.equals(attendanceNoticeModel.getAttendanceNoticeEnum()) ? ATTENDANCE_SETTING_ATTENDANCE_GROUP_JOIN_LEAVE_REMINDER : ATTENDANCE_SETTING_ATTENDANCE_GROUP_CHANGE_REMINDER;
return attendanceNoticeHandler.getUserIdsForFilterStatus(attendanceNoticeModel.getUserIds(), UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE, userSettingEnum);
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(UserChangeNoticeModel attendanceNoticeModel, String noticeId) {
ArrayList<JumpUrl> objects = CollUtil.newArrayList();
String title = ATTENDANCE_NOTICE_GROUP_CHANGE_TITLE;
if (AttendanceNoticeEnum.JOIN_GROUP.equals(attendanceNoticeModel.getAttendanceNoticeEnum())) {
title = ATTENDANCE_NOTICE_JOIN_GROUP_CHANGE_TITLE;
objects.add(JumpUrl.builder().url(ATTENDANCE_NOTICE_RULE_URL).urlName(ATTENDANCE_NOTICE_DETAIL_BUTTON_NAME).color(COLOR_BLACK).build());
objects.add(JumpUrl.builder().url(ATTENDANCE_NOTICE_CLICK_URL).urlName(ATTENDANCE_NOTICE_TO_CLICK).color(COLOR_BLUE).build());
} else if (REMOVE_USER.equals(attendanceNoticeModel.getAttendanceNoticeEnum())) {
title = ATTENDANCE_NOTICE_REMOVE_USER_TITLE;
objects.add(JumpUrl.builder().url(String.format(ATTENDANCE_NOTICE_GROUP_CHANGES_URL, noticeId)).urlName(ATTENDANCE_NOTICE_DETAIL_BUTTON_NAME).color(COLOR_BLACK).build());
} else if (REMOVE_USER_REMOVE_GROUP.equals(attendanceNoticeModel.getAttendanceNoticeEnum())) {
title = ATTENDANCE_NOTICE_REMOVE_USER_TITLE;
objects.add(JumpUrl.builder().url(String.format(ATTENDANCE_NOTICE_GROUP_CHANGES_URL, noticeId)).urlName(ATTENDANCE_NOTICE_DETAIL_BUTTON_NAME).color(COLOR_BLACK).build());
} else {
objects.add(JumpUrl.builder().url(ATTENDANCE_NOTICE_RULE_URL).urlName(ATTENDANCE_NOTICE_DETAIL_BUTTON_NAME).color(COLOR_BLACK).build());
objects.add(JumpUrl.builder().url(ATTENDANCE_NOTICE_CLICK_URL).urlName(ATTENDANCE_NOTICE_TO_CLICK).color(COLOR_BLUE).build());
}
return SystemNoticeStrategy.builder()
.title(title)
.noticeModuleEnum(NoticeModuleEnum.KQZ_BD)
.jumpUrls(objects)
.build();
}
@Override
public String getContext(List<UserChangModel> data) {
if (CollUtil.isEmpty(data)) {
return null;
}
StringBuffer stringBuffer = new StringBuffer();
UserChangModel shiftChangModel = data.stream().findFirst().orElse(null);
if (StringUtil.isNotEmpty(shiftChangModel.getReason())) {
stringBuffer.append("变动原因:").append(shiftChangModel.getReason()).append("</br>");
}
if (AttendanceNoticeEnum.JOIN_GROUP.getCode().equals(shiftChangModel.getType())) {
stringBuffer.append("加入考勤组:").append(shiftChangModel.getJoinGroup()).append("</br>");
stringBuffer.append("考勤组管理员:").append(StringUtil.isNotEmpty(shiftChangModel.getAdministratorList()) ? shiftChangModel.getAdministratorList() : "暂无管理员").append("</br>");
}
if (AttendanceNoticeEnum.GROUP_CHANGE_REMOVE_JOIN_GROUP.getCode().equals(shiftChangModel.getType())) {
stringBuffer.append("新考勤组:").append(shiftChangModel.getJoinGroup()).append("</br>");
stringBuffer.append("考勤组管理员:").append(StringUtil.isNotEmpty(shiftChangModel.getAdministratorList()) ? shiftChangModel.getAdministratorList() : "暂无管理员").append("</br>");
}
if (AttendanceNoticeEnum.GROUP_CHANGE_SECONDMENT.getCode().equals(shiftChangModel.getType())) {
stringBuffer.append("开始时间:").append(shiftChangModel.getStart()).append("</br>");
}
if (AttendanceNoticeEnum.GROUP_CHANGE_TRANSFER_POSITION.getCode().equals(shiftChangModel.getType())
|| AttendanceNoticeEnum.GROUP_CHANGE_PROMOTION.getCode().equals(shiftChangModel.getType())) {
stringBuffer.append("考勤组管理员:").append(StringUtil.isNotEmpty(shiftChangModel.getAdministratorList()) ? shiftChangModel.getAdministratorList() : "暂无管理员").append("</br>");
}
if (StringUtil.isNotEmpty(shiftChangModel.getTips())) {
stringBuffer.append(shiftChangModel.getTips());
}
return stringBuffer.toString();
}
}

View File

@@ -0,0 +1,328 @@
package jnpf.attendance.service.handle.notification;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import jnpf.attendance.service.AttendanceClockInService;
import jnpf.attendance.service.AttendanceGroupService;
import jnpf.attendance.service.DailyRuleChangeService;
import jnpf.attendance.service.handle.notice.AttendanceNoticeHandler;
import jnpf.base.UserInfo;
import jnpf.constants.MessageTopicConstants;
import jnpf.entity.attendance.DailyRuleChange;
import jnpf.entity.attendance.FtbAttendanceDailyRule;
import jnpf.enums.attendance.AttendanceNoticeEnum;
import jnpf.enums.attendance.AttendanceTypeEnum;
import jnpf.enums.attendance.TriggerSceneEnum;
import jnpf.model.attendance.dto.LineDrawingPeriodDto;
import jnpf.model.attendance.dto.LineDrawingSchedulesConfigDto;
import jnpf.model.attendance.event.StatisticsBatchClearDto;
import jnpf.model.attendance.event.StatisticsSingleDto;
import jnpf.model.attendance.model.LineShiftChangeNoticeModel;
import jnpf.model.attendance.model.ShiftChangeNoticeModel;
import jnpf.model.attendance.model.SystemTypeChangeNoticeModel;
import jnpf.model.attendance.vo.AttendanceShiftSettingVo;
import jnpf.model.attendance.vo.DailyRuleResultVo;
import jnpf.model.attendance.vo.UserDayVo;
import jnpf.util.DateDetail;
import jnpf.util.StringUtil;
import jnpf.util.UserProvider;
import jnpf.util.attendance.DailyRuleUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@Component
@Slf4j
public class AttendanceRuleNotificationHandle {
@Resource
private RocketMQTemplate rocketMqTemplate;
@Autowired
private AttendanceClockInService attendanceClockInService;
@Autowired
private AttendanceNoticeHandler attendanceNoticeHandler;
@Autowired
private DailyRuleChangeService dailyRuleChangeService;
public void notificationHandle(List<DailyRuleResultVo> resultList, String tenantId, Boolean isSync, Boolean isNotificationClock) {
UserInfo user = UserProvider.getUser();
if (StringUtil.isNotNull(tenantId)) {
user.setTenantId(tenantId);
}
if (isSync) {
notificationClockHandleSync(resultList, user, isNotificationClock);
return;
}
notificationMqHandle(resultList, user, isNotificationClock);
}
public void notificationHandle(List<DailyRuleResultVo> resultList, Boolean isSync, Boolean isNotificationClock) {
notificationHandle(resultList, null, isSync, isNotificationClock);
}
public void notificationHandle(List<DailyRuleResultVo> resultList, Boolean isSync) {
notificationHandle(resultList, isSync, Boolean.TRUE);
}
public void notificationHandle(List<DailyRuleResultVo> resultList, String tenantId) {
notificationHandle(resultList, tenantId, Boolean.FALSE, Boolean.TRUE);
}
public void notificationClearHandle(String tenantId, String fromGroupId, List<String> userIds, Date day) {
if (CollUtil.isEmpty(userIds)) {
return;
}
//调用批量清除日统计数据接口s
StatisticsBatchClearDto batchClearDto = StatisticsBatchClearDto.builder()
.tenantId(StringUtil.isEmpty(tenantId) ? UserProvider.getUser().getTenantId() : tenantId)
.groupId(fromGroupId)
.userIdList(userIds)
.startDay(day)
.build();
Message<StatisticsBatchClearDto> clearMessage = MessageBuilder.withPayload(batchClearDto).build();
rocketMqTemplate.syncSend(MessageTopicConstants.ATTENDANCE_STATISTICS_BATCH_CLEAR_TOPIC, clearMessage, 3000L, 2);
}
/**
* 规则变动发送通知
*
* @param resultList 规则变动结果
* @param tenantId 租户id
*/
@Async("threadPoolTaskExecutor")
public void sendSystemNotice(List<DailyRuleResultVo> resultList, String tenantId) {
resultList.stream()
.filter(dailyRuleResultVo -> Objects.nonNull(dailyRuleResultVo.getFromType())
&& (Objects.equals(dailyRuleResultVo.getFromType(), AttendanceTypeEnum.ORDINARY.getCode())
|| Objects.equals(dailyRuleResultVo.getFromType(), AttendanceTypeEnum.REST.getCode())
|| Objects.equals(dailyRuleResultVo.getFromType(), AttendanceTypeEnum.HOLIDAYS.getCode())
|| Objects.equals(dailyRuleResultVo.getFromType(), AttendanceTypeEnum.DEDUCTION_HOLIDAYS.getCode())
|| Objects.equals(dailyRuleResultVo.getFromType(), AttendanceTypeEnum.EXCHANGE_HOLIDAYS.getCode()))
&& (Objects.equals(dailyRuleResultVo.getToType(), AttendanceTypeEnum.ORDINARY.getCode())
|| Objects.equals(dailyRuleResultVo.getToType(), AttendanceTypeEnum.REST.getCode())
|| Objects.equals(dailyRuleResultVo.getToType(), AttendanceTypeEnum.HOLIDAYS.getCode())
|| Objects.equals(dailyRuleResultVo.getToType(), AttendanceTypeEnum.DEDUCTION_HOLIDAYS.getCode())
|| Objects.equals(dailyRuleResultVo.getToType(), AttendanceTypeEnum.EXCHANGE_HOLIDAYS.getCode())
|| Objects.isNull(dailyRuleResultVo.getToType()))).collect(Collectors.groupingBy(DailyRuleResultVo::getUserId))
.forEach((userId, results) -> {
ShiftChangeNoticeModel shiftChangeNoticeModel = new ShiftChangeNoticeModel();
shiftChangeNoticeModel.setTenantId(StringUtil.isEmpty(tenantId) ? UserProvider.getUser().getTenantId() : tenantId);
shiftChangeNoticeModel.setUserId(userId);
shiftChangeNoticeModel.setDailyRuleResultVos(results);
shiftChangeNoticeModel.setAttendanceNoticeEnum(AttendanceNoticeEnum.SHIFT_CHANG);
attendanceNoticeHandler.send(shiftChangeNoticeModel);
});
}
@Async("threadPoolTaskExecutor")
public void sendNoticeBatch(List<String> selfAndChildrenGroupIds, Integer systemType) {
selfAndChildrenGroupIds.forEach(itemGroupId -> sendNotice(itemGroupId, systemType));
}
private void sendNotice(String groupId, Integer systemType) {
SystemTypeChangeNoticeModel systemTypeChangeNoticeModel = new SystemTypeChangeNoticeModel();
systemTypeChangeNoticeModel.setSystemType(systemType);
systemTypeChangeNoticeModel.setGroupId(groupId);
systemTypeChangeNoticeModel.setIsAdmin(Boolean.FALSE);
systemTypeChangeNoticeModel.setTenantId(UserProvider.getUser().getTenantId());
systemTypeChangeNoticeModel.setAttendanceNoticeEnum(AttendanceNoticeEnum.RULE_CHANGE_SHIFT_SYSTEM);
attendanceNoticeHandler.send(systemTypeChangeNoticeModel);
systemTypeChangeNoticeModel.setIsAdmin(Boolean.TRUE);
attendanceNoticeHandler.send(systemTypeChangeNoticeModel);
}
public void sendSystemNoticeForLine(List<DailyRuleResultVo> resultList, LineDrawingSchedulesConfigDto configDto, String tenantId) {
sendSystemNoticeForLine(resultList, configDto, null, tenantId);
}
/**
* 划线排班规则变动发送通知
*
* @param configDto 规则
* @param tenantId 租户id
*/
public void sendSystemNoticeForLine(List<DailyRuleResultVo> resultList, LineDrawingSchedulesConfigDto configDto, List<Date> days, String tenantId) {
LineShiftChangeNoticeModel shiftChangeNoticeModel = new LineShiftChangeNoticeModel();
shiftChangeNoticeModel.setAttendanceNoticeEnum(AttendanceNoticeEnum.LINE_SHIFT_CHANG);
shiftChangeNoticeModel.setTenantId(StringUtil.isEmpty(tenantId) ? UserProvider.getUser().getTenantId() : tenantId);
List<Date> daysList = CollUtil.isNotEmpty(days) ? days : Arrays.stream(StringUtil.split(configDto.getDays(), ",")).map(jnpf.util.DateUtil::stringToDates).collect(Collectors.toList());
Map<String, List<DailyRuleResultVo>> collect = resultList.stream().collect(Collectors.groupingBy(vo -> vo.getUserId() + DateDetail.getDate2Str(vo.getDate(), DateDetail.DF)));
configDto.getUserList()
.forEach(user -> {
List<LineDrawingPeriodDto> periods = user.getPeriods();
if (CollUtil.isEmpty(periods) && CollUtil.isEmpty(resultList)) {
return;
}
if (CollUtil.isNotEmpty(periods) && periods.stream().allMatch(vo -> StringUtil.isNotEmpty(vo.getId()))) {
return;
}
List<LineDrawingPeriodDto> periodList = CollUtil.newArrayList();
List<Date> collect1 = periods.stream().map(LineDrawingPeriodDto::getDay).distinct().sorted().collect(Collectors.toList());
if (CollUtil.isEmpty(collect1)) {
collect1 = daysList;
}
collect1.forEach(day -> {
String key = user.getUserId() + DateDetail.getDate2Str(day, DateDetail.DF);
if (!collect.containsKey(key)) {
return;
}
if (CollUtil.isEmpty(periods)) {
periodList.add(LineDrawingPeriodDto.builder()
.day(day)
.start("")
.build());
return;
}
periodList.addAll(BeanUtil.copyToList(periods, LineDrawingPeriodDto.class).stream().peek(vo -> vo.setDay(day)).collect(Collectors.toList()));
});
if (CollUtil.isEmpty(periodList)) {
return;
}
shiftChangeNoticeModel.setUserIds(List.of(user.getUserId()));
shiftChangeNoticeModel.setPeriods(periodList);
attendanceNoticeHandler.send(shiftChangeNoticeModel);
});
}
/**
* 划线排班规则变动发送通知
*
* @param rules 规则
* @param tenantId 租户id
*/
@Async("threadPoolTaskExecutor")
public void sendSystemNoticeForLine2(List<DailyRuleResultVo> resultList, List<FtbAttendanceDailyRule> rules, String tenantId) {
Map<String, List<DailyRuleResultVo>> collect = resultList.stream().collect(Collectors.groupingBy(vo -> vo.getUserId() + DateDetail.getDate2Str(vo.getDate(), DateDetail.DF)));
LineShiftChangeNoticeModel shiftChangeNoticeModel = new LineShiftChangeNoticeModel();
shiftChangeNoticeModel.setTenantId(StringUtil.isEmpty(tenantId) ? UserProvider.getUser().getTenantId() : tenantId);
shiftChangeNoticeModel.setAttendanceNoticeEnum(AttendanceNoticeEnum.LINE_SHIFT_CHANG);
rules.stream().filter(vo -> Objects.equals(vo.getAttendanceType(), AttendanceTypeEnum.LEAVE.getCode()) || Objects.equals(vo.getAttendanceType(), AttendanceTypeEnum.ORDINARY.getCode())).collect(Collectors.groupingBy(rule -> rule.getUserId() + DateDetail.getDate2Str(rule.getDay(), DateDetail.DF)))
.forEach((key, userRules) -> {
FtbAttendanceDailyRule rule = userRules.stream().findFirst().orElse(null);
if (Objects.isNull(rule)) {
return;
}
if (!collect.containsKey(key)) {
return;
}
DateTime tomorrow = DateUtil.offsetDay(rule.getDay(), 1);
List<DailyRuleResultVo> orDefault = collect.getOrDefault(key, List.of());
boolean isClear = orDefault.stream().allMatch(vo -> Objects.isNull(vo.getType()));
List<LineDrawingPeriodDto> periods = DailyRuleUtil.mergeRules(userRules).stream().map(dayRule -> LineDrawingPeriodDto.builder()
.day(dayRule.getDay())
.startType(dayRule.getInPoint().after(tomorrow) ? 2 : 1)
.start(isClear ? "" : jnpf.util.DateUtil.dateToString(dayRule.getInPoint(), "HH:mm"))
.startType(dayRule.getOutPoint().after(tomorrow) ? 2 : 1)
.end(isClear ? "" : jnpf.util.DateUtil.dateToString(dayRule.getOutPoint(), "HH:mm"))
.build()).collect(Collectors.toList());
shiftChangeNoticeModel.setUserIds(List.of(rule.getUserId()));
shiftChangeNoticeModel.setPeriods(periods);
shiftChangeNoticeModel.setDay(rule.getDay());
attendanceNoticeHandler.send(shiftChangeNoticeModel);
});
}
private void notificationClockHandleSync(List<DailyRuleResultVo> resultList, UserInfo user, boolean isNotificationClock) {
if (isNotificationClock) {
try {
// 出勤变更通知
List<UserDayVo> userDayList = resultList.stream()
.map(vo -> new UserDayVo(user.getTenantId(), vo.getGroupId(), vo.getUserId(), vo.getDate(), DateDetail.getDate2Str(vo.getDate(), DateDetail.DF)))
.collect(Collectors.collectingAndThen(
// 去除重复记录, 冲突时保留第一条
Collectors.toMap(u -> u.getUserId() + "_" + u.getDayStr(), Function.identity(), (existing, replacement) -> existing),
map -> new ArrayList<>(map.values())
));
dailyRuleChangeService.saveRecordBatch(userDayList.stream().map(userDayVo -> new DailyRuleChange(userDayVo.getGroupId(), userDayVo.getUserId(), userDayVo.getDay(), userDayVo.getTenantId())).collect(Collectors.toList()));
attendanceClockInService.changeAttendanceRuleBatch(userDayList, user);
} catch (Exception e) {
log.error("排班通知打卡失败", e);
}
}
//调用批量生成日统计数据接口
Map<String, List<DailyRuleResultVo>> groupMap = resultList.stream().collect(Collectors.groupingBy(DailyRuleResultVo::getGroupId));
groupMap.forEach((groupId, dayList) -> {
Map<Date, List<DailyRuleResultVo>> dayMap = dayList.stream().collect(Collectors.groupingBy(DailyRuleResultVo::getDate));
dayMap.forEach((date, userList) -> {
notificationClearHandle(user.getTenantId(), groupId, userList.stream().filter(vo -> Objects.isNull(vo.getToType())).map(DailyRuleResultVo::getUserId).distinct().collect(Collectors.toList()), date);
notificationStatistics(user.getTenantId(), groupId, date, userList.stream().map(DailyRuleResultVo::getUserId).distinct().collect(Collectors.toList()));
});
});
}
private void notificationMqHandle(List<DailyRuleResultVo> resultList, UserInfo user, boolean isNotificationClock) {
if (isNotificationClock) {
notificationClockMq(resultList, user);
}
//调用批量生成日统计数据接口
Map<String, List<DailyRuleResultVo>> groupMap = resultList.stream().collect(Collectors.groupingBy(DailyRuleResultVo::getGroupId));
groupMap.forEach((groupId, dayList) -> {
Map<Date, List<DailyRuleResultVo>> dayMap = dayList.stream().collect(Collectors.groupingBy(DailyRuleResultVo::getDate));
dayMap.forEach((date, userList) -> {
notificationClearHandle(user.getTenantId(), groupId, userList.stream().filter(vo -> Objects.isNull(vo.getToType())).map(DailyRuleResultVo::getUserId).distinct().collect(Collectors.toList()), date);
notificationStatistics(user.getTenantId(), groupId, date, userList.stream().map(DailyRuleResultVo::getUserId).distinct().collect(Collectors.toList()));
});
});
}
public void notificationClockMq(List<DailyRuleResultVo> resultList, UserInfo user) {
//调用生成日统计数据接口
// 出勤变更通知
List<UserDayVo> userDayList = resultList.stream()
.map(vo -> new UserDayVo(user.getTenantId(), vo.getGroupId(), vo.getUserId(), vo.getDate(), DateDetail.getDate2Str(vo.getDate(), DateDetail.DF)))
.collect(Collectors.collectingAndThen(
// 去除重复记录, 冲突时保留第一条
Collectors.toMap(u -> u.getUserId() + "_" + u.getDayStr(), Function.identity(), (existing, replacement) -> existing),
map -> new ArrayList<>(map.values())
));
Message<List<UserDayVo>> message = MessageBuilder.withPayload(userDayList).build();
try {
dailyRuleChangeService.saveRecordBatch(userDayList.stream().map(userDayVo -> new DailyRuleChange(userDayVo.getGroupId(), userDayVo.getUserId(), userDayVo.getDay(), userDayVo.getTenantId())).collect(Collectors.toList()));
SendResult sendResult = rocketMqTemplate.syncSend(MessageTopicConstants.ATTENDANCE_NOTIFICATION_CLOCK_TOPIC, message, 3000L, 3);
Assert.isFalse(!sendResult.getSendStatus().equals(SendStatus.SEND_OK), "排班通知打卡异常重试");
} catch (Exception e) {
log.error("AttendanceRuleNotificationHandle#notificationClockMq 排班通知打卡异常:{}", JSON.toJSONString(message), e);
throw new RuntimeException("排班通知打卡异常", e);
}
}
public void notificationStatistics(String tenantId, String groupId, Date date, List<String> userList) {
//调用生成日统计数据接口
StatisticsSingleDto courseEventDTO = StatisticsSingleDto.builder()
.tenantId(tenantId)
.groupId(groupId)
.day(date)
.triggerSceneEnum(TriggerSceneEnum.SCHEDULES)
.build();
userList.forEach(item -> {
courseEventDTO.setUserId(item);
Message<StatisticsSingleDto> message = MessageBuilder.withPayload(courseEventDTO).build();
if (StrUtil.isBlank(tenantId) || StrUtil.isBlank(groupId)) {
log.error("AttendanceRuleNotificationHandle#notificationStatistics 触发日统计租户ID或者考勤组ID为空{}", JSON.toJSONString(courseEventDTO));
return;
}
rocketMqTemplate.syncSend(MessageTopicConstants.ATTENDANCE_STATISTICS_SINGLE_TOPIC, message, 3000L, 2);
});
}
}

View File

@@ -0,0 +1,206 @@
package jnpf.attendance.service.handle.notification;
import jnpf.config.CustomTenantUtil;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
@Component
@Slf4j
public class MultiTenantTimeSizeBatchProcessor<T> {
// 租户处理器映射
private final Map<String, TenantBatchHandler<T>> tenantHandlers = new ConcurrentHashMap<>();
// 共享资源管理
private final TenantResourceManager tenantResourceManager;
private final CustomTenantUtil customTenantUtil;
// 定期清理不活跃租户的调度器
private final ScheduledExecutorService cleanupScheduler = Executors.newScheduledThreadPool(1);
public MultiTenantTimeSizeBatchProcessor(
TenantResourceManager tenantResourceManager,
CustomTenantUtil customTenantUtil) {
this.tenantResourceManager = tenantResourceManager;
this.customTenantUtil = customTenantUtil;
// 启动定期清理任务
cleanupScheduler.scheduleAtFixedRate(
this::cleanupInactiveHandlers, 30, 30, TimeUnit.MINUTES);
}
/**
* 添加数据到批处理队列
* @param tenantId 租户ID
* @param data 要处理的数据
*/
public void addData(String tenantId, T data) {
// 获取或创建租户处理器
TenantBatchHandler<T> handler = tenantHandlers.computeIfAbsent(
tenantId,
id -> new TenantBatchHandler<>(id, tenantResourceManager, customTenantUtil)
);
// 添加数据到处理器
handler.addData(data);
}
/**
* 清理不活跃的租户处理器
*/
private void cleanupInactiveHandlers() {
long currentTime = System.currentTimeMillis();
long inactiveThreshold = 30 * 60 * 1000; // 30分钟不活跃
tenantHandlers.entrySet().removeIf(entry -> {
TenantBatchHandler<T> handler = entry.getValue();
if (currentTime - handler.getLastActiveTime() > inactiveThreshold) {
handler.cleanup();
log.info("Cleaned up inactive tenant handler: {}", entry.getKey());
return true;
}
return false;
});
}
@PreDestroy
public void shutdown() {
cleanupScheduler.shutdown();
tenantHandlers.values().forEach(TenantBatchHandler::cleanup);
log.info("MultiTenantTimeSizeBatchProcessor shutdown completed");
}
/**
* 租户专用批处理器 - 实现时间和数量双重触发机制
*/
private static class TenantBatchHandler<T> {
// 数据缓冲区
private final List<T> buffer = new ArrayList<>();
private final Object lock = new Object();
// 定时器管理
private final ScheduledExecutorService scheduler;
private ScheduledFuture<?> currentTimer;
// 租户信息
private final String tenantId;
private final TenantResourceManager tenantResourceManager;
private final CustomTenantUtil customTenantUtil;
@Getter
private volatile long lastActiveTime;
// 批处理配置 - 根据租户规模动态调整
private final int batchSize;
private final long timeInterval;
public TenantBatchHandler(String tenantId,
TenantResourceManager tenantResourceManager,
CustomTenantUtil customTenantUtil) {
this.tenantId = tenantId;
this.tenantResourceManager = tenantResourceManager;
this.customTenantUtil = customTenantUtil;
this.lastActiveTime = System.currentTimeMillis();
// 为小租户优化配置
this.batchSize = 50; // 小批次
this.timeInterval = 3000; // 3秒超时
// 创建专用调度器
this.scheduler = Executors.newSingleThreadScheduledExecutor(
r -> new Thread(r, "tenant-" + tenantId + "-batch-scheduler"));
}
/**
* 添加数据到批处理队列
*/
public void addData(T data) {
synchronized (lock) {
buffer.add(data);
lastActiveTime = System.currentTimeMillis();
// 双重触发机制
if (buffer.size() >= batchSize) {
// 数量触发:达到批次大小立即处理
log.debug("Tenant {} batch triggered by size: {}", tenantId, buffer.size());
processBatch();
} else if (currentTimer == null || currentTimer.isDone()) {
// 时间触发:启动定时器
log.debug("Tenant {} batch timer started", tenantId);
currentTimer = scheduler.schedule(
this::processBatch, timeInterval, TimeUnit.MILLISECONDS);
}
}
}
/**
* 处理批次数据
*/
private void processBatch() {
synchronized (lock) {
if (buffer.isEmpty()) return;
// 获取当前批次数据
List<T> batch = new ArrayList<>(buffer);
buffer.clear();
// 取消当前定时器
if (currentTimer != null && !currentTimer.isDone()) {
currentTimer.cancel(false);
currentTimer = null;
}
// 使用共享线程池异步处理
CompletableFuture.runAsync(() -> {
processData(batch);
}, tenantResourceManager.getSharedThreadPool());
}
}
/**
* 实际数据处理逻辑
*/
private void processData(List<T> data) {
try {
lastActiveTime = System.currentTimeMillis();
// 关键:切换到租户数据库
customTenantUtil.checkOutTenant(tenantId);
// 执行实际的业务处理
executeBatchOperation(data);
} catch (Exception e) {
log.error("Error processing batch for tenant " + tenantId, e);
// 可以添加重试机制或死信队列处理
}
}
/**
* 执行批量数据库操作
*/
private void executeBatchOperation(List<T> data) {
try {
// 批量插入或更新操作
} catch (Exception e) {
log.error("Database operation failed for tenant " + tenantId, e);
throw new RuntimeException("Batch operation failed", e);
}
}
/**
* 清理资源
*/
public void cleanup() {
if (currentTimer != null && !currentTimer.isDone()) {
currentTimer.cancel(true);
}
scheduler.shutdown();
buffer.clear();
}
}
}

Some files were not shown because too many files have changed in this diff Show More