Merge branch 'dev' into frx

# Conflicts:
#	yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
This commit is contained in:
furongxin 2024-07-04 18:32:34 +08:00
commit f057d4310e
19 changed files with 598 additions and 99 deletions

View File

@ -49,4 +49,8 @@ public class Constants {
* yyyy-MM-dd格式
*/
public static final DateTimeFormatter REPO_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
/**
* yyyy-MM-dd HH:mm:ss格式
*/
public static final DateTimeFormatter FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
}

View File

@ -77,15 +77,15 @@ public class AttendanceController {
@GetMapping("/getTheAttendanceGroupToWhichTheCurrentlyLoggedInUserBelongsAndWhetherTheyHaveAdministratorRights")
@Operation(summary = "获取当前登陆用户所在考勤组并且是否有管理员权限")
public CommonResult<List<AttendanceGroupSystemVO>> getTheAttendanceGroupToWhichTheCurrentlyLoggedInUserBelongsAndWhetherTheyHaveAdministratorRights() {
List<AttendanceGroupSystemVO> vo = attendanceService.getTheAttendanceGroupToWhichTheCurrentlyLoggedInUserBelongsAndWhetherTheyHaveAdministratorRights();
public CommonResult<List<AttendanceGroupSystemVO>> getTheAttendanceGroupToWhichTheCurrentlyLoggedInUserBelongsAndWhetherTheyHaveAdministratorRights(@RequestParam(name = "allFlag", required = false, defaultValue = "false") Boolean allFlag) {
List<AttendanceGroupSystemVO> vo = attendanceService.getTheAttendanceGroupToWhichTheCurrentlyLoggedInUserBelongsAndWhetherTheyHaveAdministratorRights(allFlag);
return success(vo);
}
@GetMapping("/export-excel")
@PostMapping("/export-excel")
@Operation(summary = "导出考勤报表 Excel")
public void exportAttendanceExcel(@Valid ExportAttendanceExcelDTO dto,
public void exportAttendanceExcel(@RequestBody ExportAttendanceExcelDTO dto,
HttpServletResponse response) {
attendanceService.exportAttendanceExcel(response, dto);
}

View File

@ -17,7 +17,7 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DE
@Accessors(chain = true)
public class ExportAttendanceExcelDTO {
@Schema(description = "报表类型 1月度统计 2每日统计 3打卡记录")
@Schema(description = "报表类型 1月度统计 2每日统计")
private Integer type;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)

View File

@ -7,6 +7,8 @@ import lombok.Data;
public class CalculateNum {
@Schema(description = "总考勤时间")
long totalWorkingHours = 0L;
@Schema(description = "总考勤时间中文")
String totalWorkingHoursStr;
@Schema(description = "总出勤天数")
int totalAttendanceDays = 0;
@Schema(description = "总休息天数")
@ -25,6 +27,10 @@ public class CalculateNum {
String totalEarlyDeparturesTimeStr;
@Schema(description = "缺卡总次数")
int totalMissingCardsNumber = 0;
@Schema(description = "上班缺卡总次数")
int totalUpMissingCardsNumber = 0;
@Schema(description = "下班缺卡总次数")
int totalDownMissingCardsNumber = 0;
@Schema(description = "矿工总天数")
int totalMinerDays = 0;
@Schema(description = "外勤次数")

View File

@ -10,6 +10,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.system.controller.admin.user.dto.UserPageDTO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.*;
import cn.iocoder.yudao.module.system.convert.user.UserConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
@ -18,6 +19,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import cn.iocoder.yudao.module.system.service.dept.PostService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
@ -130,6 +132,15 @@ public class UserController {
return success(UserConvert.INSTANCE.convertSimpleList(list, deptMap));
}
@PostMapping({"/list-all"})
@Operation(summary = "获取用户精简信息列表", description = "只包含被开启的用户,主要用于前端的下拉选项,无数据权限")
@DataPermission(enable = false)
public CommonResult<IPage<UserSimpleRespVO>> getAllUserListByGroupIds(@RequestBody UserPageDTO dto) {
IPage<UserSimpleRespVO> pageResult = userService.getAllUserListByGroupIds(dto);
return success(pageResult);
}
@GetMapping("/get")
@Operation(summary = "获得用户详情")
@Parameter(name = "id", description = "编号", required = true, example = "1024")

View File

@ -0,0 +1,17 @@
package cn.iocoder.yudao.module.system.controller.admin.user.dto;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Data
public class UserPageDTO extends PageParam {
@Schema(description = "考勤组ids")
private List<Long> groupIds;
@Schema(description = "用户名称")
private String name;
@Schema(description = "状态0正常 1停用不传则全部", example = "1")
private Integer status;
}

View File

@ -16,6 +16,8 @@ public class UserSimpleRespVO {
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
private String nickname;
@Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png")
private String avatar;
@Schema(description = "部门ID", example = "我是一个用户")
private Long deptId;

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.attendance.punchrecord;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
@ -138,4 +139,7 @@ public class AttendancePunchRecordDO extends BaseDO {
* 是否已提醒 0否 1是
*/
private Integer remindFlag;
@TableField(exist = false)
private String deptName;
}

View File

@ -5,8 +5,12 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.controller.admin.punchrecord.vo.AttendancePunchRecordPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.punchrecord.AttendancePunchRecordDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.service.attendance.punch.dto.AttendanceOnTheDayDTO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 用户打卡记录 Mapper
@ -35,4 +39,12 @@ public interface AttendancePunchRecordMapper extends BaseMapperX<AttendancePunch
.orderByDesc(AttendancePunchRecordDO::getId));
}
/**
* 统计
*
* @param userList
* @param dateList
* @return
*/
List<AttendancePunchRecordDO> statistics(@Param("userList") List<Long> userList, @Param("dateList") List<String> dateList);
}

View File

@ -3,10 +3,13 @@ package cn.iocoder.yudao.module.system.dal.mysql.user;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.controller.admin.user.dto.UserPageDTO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.factoryUser.FactoryUserPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserRespVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserSimpleRespVO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@ -92,4 +95,13 @@ public interface AdminUserMapper extends BaseMapperX<AdminUserDO> {
List<UserRespVO> selectByDeptIdsFilterGroupUser(@Param("deptIds") Collection<Long> deptIds, @Param("groupId") Long groupId);
List<Long> selectUserByBoss();
/**
* 获取考勤组里所有的用户
*
* @param mpPage
* @param dto
* @return
*/
IPage<UserSimpleRespVO> getAllUserListByGroupIds(@Param("mpPage") IPage mpPage, @Param("dto") UserPageDTO dto);
}

View File

@ -89,7 +89,7 @@ public interface AttendanceService {
*
* @return
*/
List<AttendanceGroupSystemVO> getTheAttendanceGroupToWhichTheCurrentlyLoggedInUserBelongsAndWhetherTheyHaveAdministratorRights();
List<AttendanceGroupSystemVO> getTheAttendanceGroupToWhichTheCurrentlyLoggedInUserBelongsAndWhetherTheyHaveAdministratorRights(Boolean allFlag);
/**
* 获取考勤规则

View File

@ -21,9 +21,11 @@ import cn.iocoder.yudao.module.system.dal.dataobject.attendance.group.Attendance
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupshift.AttendanceGroupShiftDO;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupshiftitem.AttendanceGroupShiftItemDO;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.punchrecord.AttendancePunchRecordDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.attendance.group.AttendanceGroupMapper;
import cn.iocoder.yudao.module.system.dal.mysql.attendance.punchrecord.AttendancePunchRecordMapper;
import cn.iocoder.yudao.module.system.dal.mysql.dept.PostMapper;
import cn.iocoder.yudao.module.system.handler.PunchHandler;
import cn.iocoder.yudao.module.system.service.attendance.group.AttendanceGroupService;
import cn.iocoder.yudao.module.system.service.attendance.groupshift.AttendanceGroupShiftService;
@ -34,6 +36,7 @@ import cn.iocoder.yudao.module.system.service.attendance.punch.dto.AttendanceOnT
import cn.iocoder.yudao.module.system.service.attendance.punchrecord.AttendancePunchRecordService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.extern.slf4j.Slf4j;
@ -44,6 +47,9 @@ import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
@ -85,6 +91,8 @@ public class AttendanceServiceImpl implements AttendanceService {
private AttendanceGroupMapper attendanceGroupMapper;
@Resource
private AttendanceGroupUserService attendanceGroupUserService;
@Resource
private PostMapper postMapper;
// 定义一些常量以提高代码的可读性和可维护性
@ -608,7 +616,6 @@ public class AttendanceServiceImpl implements AttendanceService {
@Override
public TeamAttendanceStatisticsByCycleVO tesmStatisticsByCycle(TeamAttendanceStatisticsByCycleDTO dto) {
TeamAttendanceStatisticsByCycleVO vo = new TeamAttendanceStatisticsByCycleVO();
TeamAttendanceStatisticsByCycleVO.TeamAttendanceStatisticsNumVO teamAttendanceStatisticsNumVO = new TeamAttendanceStatisticsByCycleVO.TeamAttendanceStatisticsNumVO();
//查询考勤组
AttendanceGroupDO attendanceGroupDO = attendanceGroupService.getGroup(dto.getGroupId());
// - 判断当前用户是否有权限查看
@ -750,11 +757,11 @@ public class AttendanceServiceImpl implements AttendanceService {
}
@Override
public List<AttendanceGroupSystemVO> getTheAttendanceGroupToWhichTheCurrentlyLoggedInUserBelongsAndWhetherTheyHaveAdministratorRights() {
public List<AttendanceGroupSystemVO> getTheAttendanceGroupToWhichTheCurrentlyLoggedInUserBelongsAndWhetherTheyHaveAdministratorRights(Boolean allFlag) {
Long userId = getLoginUserId();
List<AttendanceGroupSystemVO> attendanceGroupSystemVOS = new ArrayList<>();
List<AttendanceGroupDO> attendanceGroupDOS = attendanceGroupMapper.selectList(new LambdaQueryWrapper<AttendanceGroupDO>()
.eq(AttendanceGroupDO::getUserId, userId));
.eq(!allFlag, AttendanceGroupDO::getUserId, userId));
if (CollectionUtil.isEmpty(attendanceGroupDOS)) {
return attendanceGroupSystemVOS;
}
@ -792,11 +799,189 @@ public class AttendanceServiceImpl implements AttendanceService {
} else {
userList = adminUserService.getAllList(CommonStatusEnum.ENABLE.getStatus(), null, dto.getTargetIds());
}
// -- 统计
List<String> dateList = DateUtils.betweenDayList(dto.getStartTime(), dto.getEndTime());
if (dto.getType() == 1) {
this.monthlyStatistics(response, userList, dateList);
String hh_mm = LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm"));
String first = CollectionUtil.getFirst(dateList);
String last = CollectionUtil.getLast(dateList);
//查询出数据 -- 时间周期 - 用户列表
List<AttendancePunchRecordDO> list = attendancePunchRecordMapper.statistics(userList.stream().map(AdminUserDO::getId).collect(Collectors.toList()), dateList);
//获取用户列表
Map<Long, AdminUserDO> userMap = new HashMap<>();
if (CollectionUtil.isNotEmpty(userList)) {
userMap = userList.stream().collect(Collectors.toMap(AdminUserDO::getId, Function.identity()));
}
List<PostDO> userPostList = postMapper.selectList();
// 根据id分组
Map<Long, PostDO> postMap = userPostList.stream().collect(Collectors.toMap(PostDO::getId, Function.identity()));
if (dto.getType() == 1) {
String headTitle = String.format("月度汇总 统计日期:%s 至 %s", first, last);
String detailedHead = String.format("月度汇总 统计日期:%s 至 %s %s", first, last, hh_mm);
this.monthlyStatistics(response, userList, dateList, headTitle, detailedHead, list);
} else {
String headTitle = String.format("每日统计 统计日期:%s 至 %s", first, last);
String detailedHead = String.format("报表生成时间:%s %s", last, hh_mm);
this.dayStatistics(response, userMap, postMap, dateList, headTitle, detailedHead, list);
}
}
/**
* 按日导出
*
* @param response
* @param userMap
* @param postMap
* @param dateList
* @param headTitle
* @param detailedHead
* @param list
*/
private void dayStatistics(HttpServletResponse response, Map<Long, AdminUserDO> userMap, Map<Long, PostDO> postMap, List<String> dateList, String headTitle, String detailedHead, List<AttendancePunchRecordDO> list) {
List<List<String>> data = new ArrayList<>();
// -- 根据部门分组 - 根据考勤组分组
Map<Long, List<AttendancePunchRecordDO>> userPunchMap = list.stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getUserId));
// -- 先计算下要循环几次 - 一个用户一个部门一个考勤组一个班次一个日期 最大的打卡次数 -
Map<String, List<AttendancePunchRecordDO>> map = list.stream().collect(Collectors.groupingBy(
a -> a.getUserId() + "_"
+ a.getDeptId() + "_"
+ a.getAttendanceGroupId() + "_"
+ a.getAttendanceGroupShiftId() + "_"
+ a.getDayTime()));
int maxSize = map.values().stream().mapToInt(List::size).max().orElse(0);
// -- 如果膜2大于0
maxSize = (maxSize % 2) > 0 ? maxSize / 2 + 1 : maxSize / 2;
//先根据人员分组 - 再根据部门分组 - 再根据考勤组分组 - 再根据日期分组
long time = System.currentTimeMillis();
for (Map.Entry<Long, List<AttendancePunchRecordDO>> entry : userPunchMap.entrySet()) {
AdminUserDO adminUserDO = userMap.get(entry.getKey());
List<String> postNames = this.getPostNames(adminUserDO, postMap);
Map<Long, List<AttendancePunchRecordDO>> deptMap = entry.getValue().stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getDeptId));
for (Map.Entry<Long, List<AttendancePunchRecordDO>> deptEntry : deptMap.entrySet()) {
Map<Long, List<AttendancePunchRecordDO>> groupMap = deptEntry.getValue().stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getAttendanceGroupId));
for (Map.Entry<Long, List<AttendancePunchRecordDO>> groupEntry : groupMap.entrySet()) {
//按日期分组
Map<String, List<AttendancePunchRecordDO>> dayMap = groupEntry.getValue().stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getDayTime, TreeMap::new, Collectors.toList()));
for (String dateStr : dateList) {
List<AttendancePunchRecordDO> items = dayMap.get(dateStr);
Map<Long, List<AttendancePunchRecordDO>> groupShiftMap = new HashMap<>();
if (CollectionUtil.isNotEmpty(items)) {
groupShiftMap = items.stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getAttendanceGroupShiftId));
} else {
groupShiftMap.put(-1L, Collections.emptyList());
}
for (Map.Entry<Long, List<AttendancePunchRecordDO>> groupShiftEntry : groupShiftMap.entrySet()) {
List<String> row = new ArrayList<>();
row.add(adminUserDO.getNickname());
row.add(groupEntry.getValue().get(0).getAttendanceGroupName());
row.add(groupEntry.getValue().get(0).getDeptName());
row.add(String.join("/", postNames));
row.add(dateStr);
row.add(CollectionUtil.isEmpty(groupShiftEntry.getValue()) ? "休息" : groupShiftEntry.getValue().get(0).getAttendanceGroupShiftName());
Map<Long, List<AttendancePunchRecordDO>> workMap = groupShiftEntry.getValue().stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getAttendanceGroupShiftItemId, TreeMap::new, Collectors.toList()));
// TODO: 2024/7/2 这里可能会有排序问题 具体看数据在调试
for (Map.Entry<Long, List<AttendancePunchRecordDO>> groupShiftItemEntry : workMap.entrySet()) {
for (AttendancePunchRecordDO attendancePunchRecordDO : groupShiftItemEntry.getValue()) {
row.add(attendancePunchRecordDO.getPunchTime() == null ? "/" : attendancePunchRecordDO.getPunchTime().format(Constants.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND));
row.add(this.statusToStr(attendancePunchRecordDO.getStatus()));
}
}
if (maxSize > workMap.entrySet().size()) {
for (int i = 0; i < maxSize - workMap.entrySet().size(); i++) {
row.add("/");
row.add("/");
row.add("/");
row.add("/");
}
}
//工时
String workHour = this.calculateAverageWorkingHour(workMap);
row.add(workHour);
//迟到时长
String beLate = this.calculateBeLate(workMap);
row.add(beLate);
//早退时长
String leaveEarly = this.calculateEarlyDepartures(workMap);
row.add(leaveEarly);
Map<Integer, Integer> missingCardsMap = this.calculateCommuteMissingCardsList(workMap);
row.add(missingCardsMap.get(Constants.ZERO).toString());
row.add(missingCardsMap.get(Constants.ONE).toString());
data.add(row);
}
}
}
}
}
log.info("考勤按日统计耗时:{}", (System.currentTimeMillis() - time));
// 这里 需要指定写用哪个class去写然后写到第一个sheet名字为模板 然后文件流会自动关闭
try {
EasyExcel.write(response.getOutputStream())
.head(generateDailyHead(headTitle, detailedHead, maxSize))
.autoCloseStream(false)
.excelType(ExcelTypeEnum.XLS)
.registerWriteHandler(new CustomCellStyleHandler())
.sheet("考勤统计按日导出")
.doWrite(data);
response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("考勤统计", StandardCharsets.UTF_8.name()));
response.setContentType("application/vnd.ms-excel;charset=UTF-8");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 获取岗位名称
*
* @param adminUserDO
* @param postMap
* @return
*/
private List<String> getPostNames(AdminUserDO adminUserDO, Map<Long, PostDO> postMap) {
if (adminUserDO.getPostIds() != null) {
return adminUserDO.getPostIds().stream()
.map(postMap::get)
.filter(Objects::nonNull)
.map(PostDO::getName)
.collect(Collectors.toList());
}
return Collections.emptyList();
}
/**
* 状态转换
*
* @param status
* @return
*/
private String statusToStr(int status) {
if (status == 0) {
return "正常";
} else if (status == 1) {
return "迟到";
} else if (status == 2) {
return "早退";
} else if (status == 3) {
return "缺卡";
} else if (status == 4) {
return "未打卡";
} else if (status == 5) {
return "补卡";
}
return "";
}
/**
@ -805,37 +990,104 @@ public class AttendanceServiceImpl implements AttendanceService {
* @param response
* @param userList
* @param dateList
* @param headTitle
* @param detailedHead
* @param list
*/
private void monthlyStatistics(HttpServletResponse response, List<AdminUserDO> userList, List<String> dateList) {
//查询出数据 -- 时间周期 - 用户列表
List<AttendancePunchRecordDO> list = attendancePunchRecordMapper.selectList(new LambdaQueryWrapper<AttendancePunchRecordDO>()
.in(AttendancePunchRecordDO::getUserId, userList)
.in(AttendancePunchRecordDO::getDayTime, dateList));
private void monthlyStatistics(HttpServletResponse response, List<AdminUserDO> userList, List<String> dateList, String headTitle, String detailedHead, List<AttendancePunchRecordDO> list) {
List<List<String>> data = new ArrayList<>();
// -- 根据部门分组 - 根据考勤组分组
Map<Long, List<AttendancePunchRecordDO>> userPunchMap = list.stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getUserId));
//获取用户列表
Map<Long, AdminUserDO> userMap = new HashMap<>();
if (CollectionUtil.isNotEmpty(userList)) {
userMap = userList.stream().collect(Collectors.toMap(AdminUserDO::getId, Function.identity()));
}
List<PostDO> userPostList = postMapper.selectList();
// 根据id分组
Map<Long, PostDO> postMap = userPostList.stream().collect(Collectors.toMap(PostDO::getId, Function.identity()));
//先根据人员分组 - 再根据部门分组 - 再根据考勤组分组 - 再根据日期分组
for (Map.Entry<Long, List<AttendancePunchRecordDO>> entry : userPunchMap.entrySet()) {
AdminUserDO adminUserDO = userMap.get(entry.getKey());
List<String> postNames = this.getPostNames(adminUserDO, postMap);
Map<Long, List<AttendancePunchRecordDO>> deptMap = entry.getValue().stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getDeptId));
for (Map.Entry<Long, List<AttendancePunchRecordDO>> deptEntry : deptMap.entrySet()) {
Map<Long, List<AttendancePunchRecordDO>> groupMap = deptEntry.getValue().stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getAttendanceGroupId));
for (Map.Entry<Long, List<AttendancePunchRecordDO>> groupEntry : groupMap.entrySet()) {
CalculateNum calculateNum = new CalculateNum();
//按日期分组
Map<String, List<AttendancePunchRecordDO>> dayMap = groupEntry.getValue().stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getDayTime));
for (Map.Entry<String, List<AttendancePunchRecordDO>> dayEntry : dayMap.entrySet()) {
// -- 按照班次子表分组
Map<Long, List<AttendancePunchRecordDO>> workMap = dayEntry.getValue().stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getAttendanceGroupShiftItemId));
this.calculateAverageWorkingHour(workMap, calculateNum);
// -- 出考勤天数
this.calculateAttendanceDays(dayEntry.getValue(), calculateNum);
// -- 迟到
this.calculateBeLate(workMap, calculateNum);
// -- 早退
this.calculateEarlyDepartures(workMap, calculateNum);
// -- 缺卡
this.calculateCommuteMissingCardsList(workMap, calculateNum);
// -- 旷工
this.calculateMiner(dayEntry.getValue(), calculateNum);
}
//休息天数
this.calculateRestDay(dateList, dayMap.keySet().stream().distinct().collect(Collectors.toList()), calculateNum);
//考勤总时间中文
calculateNum.setTotalWorkingHoursStr(DateUtil.formatBetween(calculateNum.getTotalWorkingHours(), BetweenFormatter.Level.MINUTE));
//迟到总时间中文
calculateNum.setTotalLateArrivalsTimeStr(DateUtil.formatBetween(calculateNum.getTotalLateArrivalsTime(), BetweenFormatter.Level.MINUTE));
//早退总时间中文
calculateNum.setTotalEarlyDeparturesTimeStr(DateUtil.formatBetween(calculateNum.getTotalEarlyDeparturesTime(), BetweenFormatter.Level.MINUTE));
List<String> row = new ArrayList<>();
row.add(adminUserDO.getNickname());
row.add(groupEntry.getValue().get(0).getAttendanceGroupName());
row.add(groupEntry.getValue().get(0).getDeptName());
row.add(String.join("/", postNames));
row.add(String.valueOf(calculateNum.getTotalAttendanceDays()));
row.add(String.valueOf(calculateNum.getTotalRestDays()));
row.add(String.valueOf(calculateNum.getTotalWorkingHoursStr()));
row.add(String.valueOf(calculateNum.getTotalLateArrivalsNumber()));
row.add(String.valueOf(calculateNum.getTotalLateArrivalsTimeStr()));
row.add(String.valueOf(calculateNum.getTotalEarlyDeparturesNumber()));
row.add(String.valueOf(calculateNum.getTotalEarlyDeparturesTimeStr()));
row.add(String.valueOf(calculateNum.getTotalUpMissingCardsNumber()));
row.add(String.valueOf(calculateNum.getTotalDownMissingCardsNumber()));
row.add(String.valueOf(calculateNum.getTotalMinerDays()));
data.add(row);
}
}
}
try {
EasyExcel.write(response.getOutputStream())
.head(generateHead(headTitle, detailedHead))
.autoCloseStream(false)
.excelType(ExcelTypeEnum.XLS)
.registerWriteHandler(new CustomCellStyleHandler())
.sheet("考勤统计按月导出")
.doWrite(data);
response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("考勤统计", StandardCharsets.UTF_8.name()));
response.setContentType("application/vnd.ms-excel;charset=UTF-8");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
String fileName = "/Users/aikai/Downloads/" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去写然后写到第一个sheet名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName)
.head(generateHead())
.registerWriteHandler(new CustomCellStyleHandler())
// .registerWriteHandler(new LoopMergeStrategy())
// .registerWriteHandler(loopMergeStrategy)
.sheet("模板")
.doWrite(generateData());
}
public static List<List<String>> generateHead() {
public static List<List<String>> generateHead(String headTitle, String detailedHead) {
List<List<String>> head = new ArrayList<>();
String headTitle = "月度汇总 统计日期2024-06-01 至 2024-06-13";
String detailedHead = "月度汇总 统计日期2024-06-01 至 2024-06-13 10:48";
head.add(Arrays.asList(headTitle, detailedHead, "姓名", "姓名"));
head.add(Arrays.asList(headTitle, detailedHead, "考勤组", "考勤组"));
head.add(Arrays.asList(headTitle, detailedHead, "部门", "部门"));
head.add(Arrays.asList(headTitle, detailedHead, "工号", "工号"));
head.add(Arrays.asList(headTitle, detailedHead, "职位", "职位"));
head.add(Arrays.asList(headTitle, detailedHead, "出勤天数", "出勤天数"));
head.add(Arrays.asList(headTitle, detailedHead, "休息天数", "休息天数"));
@ -853,70 +1105,48 @@ public class AttendanceServiceImpl implements AttendanceService {
// head.add(Arrays.asList(headTitle, detailedHead, "加班时长-按加班规则计算", "工作日加班"));
// head.add(Arrays.asList(headTitle, detailedHead, "加班时长-按加班规则计算", "休息日加班"));
// head.add(Arrays.asList(headTitle, detailedHead, "加班时长-按加班规则计算", "节假日加班"));
head.add(Arrays.asList(headTitle, detailedHead, "考勤结果", ""));
head.add(Arrays.asList(headTitle, detailedHead, "考勤结果", ""));
head.add(Arrays.asList(headTitle, detailedHead, "考勤结果", "1"));
head.add(Arrays.asList(headTitle, detailedHead, "考勤结果", "2"));
head.add(Arrays.asList(headTitle, detailedHead, "考勤结果", "3"));
head.add(Arrays.asList(headTitle, detailedHead, "考勤结果", "4"));
head.add(Arrays.asList(headTitle, detailedHead, "考勤结果", "5"));
head.add(Arrays.asList(headTitle, detailedHead, "考勤结果", ""));
head.add(Arrays.asList(headTitle, detailedHead, "考勤结果", ""));
// head.add(Arrays.asList(headTitle, detailedHead, "考勤结果", ""));
// head.add(Arrays.asList(headTitle, detailedHead, "考勤结果", ""));
// head.add(Arrays.asList(headTitle, detailedHead, "考勤结果", "1"));
// head.add(Arrays.asList(headTitle, detailedHead, "考勤结果", "2"));
// head.add(Arrays.asList(headTitle, detailedHead, "考勤结果", "3"));
// head.add(Arrays.asList(headTitle, detailedHead, "考勤结果", "4"));
// head.add(Arrays.asList(headTitle, detailedHead, "考勤结果", "5"));
// head.add(Arrays.asList(headTitle, detailedHead, "考勤结果", ""));
// head.add(Arrays.asList(headTitle, detailedHead, "考勤结果", ""));
// 添加更多表头
return head;
}
public static List<List<Object>> generateData() {
List<List<Object>> data = new ArrayList<>();
List<Object> row1 = new ArrayList<>();
row1.add("艾楷");
row1.add("测试考勤");
row1.add("");
row1.add("");
row1.add("");
row1.add("22026829221062585");
row1.add(1);
row1.add(2);
row1.add(3);
row1.add(4);
row1.add(5);
row1.add(6);
row1.add(7);
row1.add(8);
row1.add(9);
row1.add(10);
row1.add(10);
row1.add(12);
// 添加更多数据
List<Object> row2 = new ArrayList<>();
row2.add("谢鸿飞");
row2.add("测试考勤");
row2.add("");
row2.add("");
row2.add("");
row2.add("066557433135769889");
row2.add(1);
row2.add(2);
row2.add(3);
row2.add(4);
row2.add(4);
row2.add(4);
row2.add(4);
row2.add(4);
row2.add(4);
row2.add(4);
row2.add(4);
row2.add(4);
// 添加更多数据
data.add(row1);
data.add(row2);
return data;
public static List<List<String>> generateDailyHead(String headTitle, String detailedHead, int size) {
List<List<String>> head = new ArrayList<>();
head.add(Arrays.asList(headTitle, detailedHead, "姓名", "姓名"));
head.add(Arrays.asList(headTitle, detailedHead, "考勤组", "考勤组"));
head.add(Arrays.asList(headTitle, detailedHead, "部门", "部门"));
head.add(Arrays.asList(headTitle, detailedHead, "职位", "职位"));
head.add(Arrays.asList(headTitle, detailedHead, "日期", "日期"));
head.add(Arrays.asList(headTitle, detailedHead, "班次", "班次"));
for (int i = 1; i <= size; i++) {
head.add(Arrays.asList(headTitle, detailedHead, "上班" + i + "打卡时间", "上班" + i + "打卡时间"));
head.add(Arrays.asList(headTitle, detailedHead, "上班" + i + "打卡结果", "上班" + i + "打卡结果"));
head.add(Arrays.asList(headTitle, detailedHead, "下班" + i + "打卡时间", "下班" + i + "打卡时间"));
head.add(Arrays.asList(headTitle, detailedHead, "下班" + i + "打卡结果", "下班" + i + "打卡结果"));
}
// head.add(Arrays.asList(headTitle, detailedHead, "关联的审批单", "关联的审批单"));
// head.add(Arrays.asList(headTitle, detailedHead, "出勤天数", "出勤天数"));
// head.add(Arrays.asList(headTitle, detailedHead, "休息天数", "休息天数"));
head.add(Arrays.asList(headTitle, detailedHead, "工作时长", "工作时长"));
// head.add(Arrays.asList(headTitle, detailedHead, "迟到次数", "迟到次数"));
head.add(Arrays.asList(headTitle, detailedHead, "迟到时长", "迟到时长"));
// head.add(Arrays.asList(headTitle, detailedHead, "早退次数", "早退次数"));
head.add(Arrays.asList(headTitle, detailedHead, "早退时长", "早退时长"));
head.add(Arrays.asList(headTitle, detailedHead, "上班缺卡次数", "上班缺卡次数"));
head.add(Arrays.asList(headTitle, detailedHead, "下班缺卡次数", "下班缺卡次数"));
// head.add(Arrays.asList(headTitle, detailedHead, "旷工天数", "旷工天数"));
return head;
}
/**
* 外勤计算
*
@ -1012,6 +1242,18 @@ public class AttendanceServiceImpl implements AttendanceService {
return list;
}
/**
* 休息时间计算
*
* @param dateList
* @param attendanceTime
* @param calculateNum
* @return
*/
private void calculateRestDay(List<String> dateList, List<String> attendanceTime, CalculateNum calculateNum) {
List<String> subtract = new ArrayList<>(CollectionUtil.subtract(dateList, attendanceTime));
calculateNum.setTotalRestDays(subtract.size());
}
/**
* @param day
@ -1057,6 +1299,51 @@ public class AttendanceServiceImpl implements AttendanceService {
calculateNum.setTotalMissingCardsNumber(calculateNum.getTotalMissingCardsNumber() + todayMissingCardsNumber);
}
private void calculateCommuteMissingCardsList(Map<Long, List<AttendancePunchRecordDO>> workMap, CalculateNum calculateNum) {
int todayUpMissingCardsNumber = 0;
int todayDownMissingCardsNumber = 0;
for (Map.Entry<Long, List<AttendancePunchRecordDO>> workEntry : workMap.entrySet()) {
if (CollectionUtil.isNotEmpty(workEntry.getValue())) {
// -- 缺卡计算
List<AttendancePunchRecordDO> missingCardsList = workEntry.getValue().stream().filter(a -> AttendanceOnTheDayDTO.PUNCH_STATUS_MISS.equals(a.getStatus())).collect(Collectors.toList());
if (CollectionUtil.isNotEmpty(missingCardsList)) {
long upNum = missingCardsList.stream().filter(a -> Constants.ZERO.equals(a.getWorkType())).count();
long downNum = missingCardsList.stream().filter(a -> Constants.ONE.equals(a.getWorkType())).count();
todayUpMissingCardsNumber += upNum;
todayDownMissingCardsNumber += downNum;
}
}
}
calculateNum.setTotalUpMissingCardsNumber(calculateNum.getTotalUpMissingCardsNumber() + todayUpMissingCardsNumber);
calculateNum.setTotalDownMissingCardsNumber(calculateNum.getTotalDownMissingCardsNumber() + todayDownMissingCardsNumber);
}
/**
* 迟到次数
*
* @param workMap
*/
private Map<Integer, Integer> calculateCommuteMissingCardsList(Map<Long, List<AttendancePunchRecordDO>> workMap) {
int todayUpMissingCardsNumber = 0;
int todayDownMissingCardsNumber = 0;
for (Map.Entry<Long, List<AttendancePunchRecordDO>> workEntry : workMap.entrySet()) {
if (CollectionUtil.isNotEmpty(workEntry.getValue())) {
// -- 缺卡计算
List<AttendancePunchRecordDO> missingCardsList = workEntry.getValue().stream().filter(a -> AttendanceOnTheDayDTO.PUNCH_STATUS_MISS.equals(a.getStatus())).collect(Collectors.toList());
if (CollectionUtil.isNotEmpty(missingCardsList)) {
long upNum = missingCardsList.stream().filter(a -> Constants.ZERO.equals(a.getWorkType())).count();
long downNum = missingCardsList.stream().filter(a -> Constants.ONE.equals(a.getWorkType())).count();
todayUpMissingCardsNumber += upNum;
todayDownMissingCardsNumber += downNum;
}
}
}
Map<Integer, Integer> map = new HashMap<>();
map.put(Constants.ZERO, todayUpMissingCardsNumber);
map.put(Constants.ONE, todayDownMissingCardsNumber);
return map;
}
/**
* 早退计算
*
@ -1111,6 +1398,20 @@ public class AttendanceServiceImpl implements AttendanceService {
calculateNum.setTotalEarlyDeparturesTime(calculateNum.getTotalEarlyDeparturesTime() + todayEarlyDeparturesTime);
}
private String calculateEarlyDepartures(Map<Long, List<AttendancePunchRecordDO>> workMap) {
long todayEarlyDeparturesTime = 0L;
for (Map.Entry<Long, List<AttendancePunchRecordDO>> workEntry : workMap.entrySet()) {
if (CollectionUtil.isNotEmpty(workEntry.getValue())) {
// -- 早退计算
List<AttendancePunchRecordDO> earlyDeparturesList = workEntry.getValue().stream().filter(a -> AttendanceOnTheDayDTO.PUNCH_STATUS_LEAVE_EARLY.equals(a.getStatus())).collect(Collectors.toList());
if (CollectionUtil.isNotEmpty(earlyDeparturesList)) {
todayEarlyDeparturesTime += earlyDeparturesList.stream().mapToLong(AttendancePunchRecordDO::getLeaveEarlyTime).sum();
}
}
}
return DateUtil.formatBetween(todayEarlyDeparturesTime, BetweenFormatter.Level.MINUTE);
}
/**
* 计算迟到
*
@ -1166,6 +1467,26 @@ public class AttendanceServiceImpl implements AttendanceService {
calculateNum.setTotalLateArrivalsTime(calculateNum.getTotalLateArrivalsTime() + todayLateArrivalsTime);
}
/**
* 迟到时长
*
* @param workMap
* @return
*/
private String calculateBeLate(Map<Long, List<AttendancePunchRecordDO>> workMap) {
long todayLateArrivalsTime = 0L;
for (Map.Entry<Long, List<AttendancePunchRecordDO>> workEntry : workMap.entrySet()) {
if (CollectionUtil.isNotEmpty(workEntry.getValue())) {
// -- 迟到计算
List<AttendancePunchRecordDO> beLateList = workEntry.getValue().stream().filter(a -> AttendanceOnTheDayDTO.PUNCH_STATUS_LATE.equals(a.getStatus())).collect(Collectors.toList());
if (CollectionUtil.isNotEmpty(beLateList)) {
todayLateArrivalsTime += beLateList.stream().mapToLong(AttendancePunchRecordDO::getLateTime).sum();
}
}
}
return DateUtil.formatBetween(todayLateArrivalsTime, BetweenFormatter.Level.MINUTE);
}
/**
* 计算考勤工时
*
@ -1184,6 +1505,17 @@ public class AttendanceServiceImpl implements AttendanceService {
return vo;
}
/**
* 计算工时
*
* @param workMap
* @return
*/
private String calculateAverageWorkingHour(Map<Long, List<AttendancePunchRecordDO>> workMap) {
long todayWorkingHours = this.calculateAverageWorkingHourDay(workMap);
return DateUtil.formatBetween(todayWorkingHours, BetweenFormatter.Level.MINUTE);
}
/**
* 计算考勤工时
*
@ -1209,6 +1541,30 @@ public class AttendanceServiceImpl implements AttendanceService {
return todayWorkingHours;
}
/**
* 计算工时 - 当天
*
* @param workMap
* @return
*/
private long calculateAverageWorkingHourDay(Map<Long, List<AttendancePunchRecordDO>> workMap) {
long todayWorkingHours = 0L;
for (Map.Entry<Long, List<AttendancePunchRecordDO>> workEntry : workMap.entrySet()) {
if (CollectionUtil.isNotEmpty(workEntry.getValue())) {
// -- 工时计算 - 有上班和下班两个卡 才计算到工时里面
if (workEntry.getValue().size() >= 2) {
AttendancePunchRecordDO first = CollectionUtil.getFirst(workEntry.getValue());
AttendancePunchRecordDO last = CollectionUtil.getLast(workEntry.getValue());
if (ObjectUtil.isNotEmpty(first.getPunchTime()) && ObjectUtil.isNotEmpty(last.getPunchTime())) {
long time = Math.abs(LocalDateTimeUtil.between(first.getPunchTime(), last.getPunchTime(), ChronoUnit.MILLIS));
todayWorkingHours += time;
}
}
}
}
return todayWorkingHours;
}
/**
* 计算出勤天数

View File

@ -25,7 +25,7 @@ public class CustomCellStyleHandler implements CellWriteHandler {
Workbook workbook = writeSheetHolder.getSheet().getWorkbook();
CellStyle cellStyle = workbook.createCellStyle();
writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), 5120);
writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), 7120);
// 设置水平和垂直居中对齐
cellStyle.setAlignment(HorizontalAlignment.CENTER);
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
@ -44,12 +44,14 @@ public class CustomCellStyleHandler implements CellWriteHandler {
// 头的策略
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
// 背景设置为红色
headWriteCellStyle.setFillForegroundColor(IndexedColors.YELLOW.getIndex());
headWriteCellStyle.setFillForegroundColor(IndexedColors.LIGHT_YELLOW.getIndex());
WriteFont headWriteFont = new WriteFont();
headWriteFont.setFontHeightInPoints((short) 20);
headWriteCellStyle.setWriteFont(headWriteFont);
WriteCellStyle.merge(headWriteCellStyle, cellDataList.get(0).getOrCreateStyle());
}
} else {
}
cell.setCellStyle(cellStyle);
}

View File

@ -3,11 +3,13 @@ package cn.iocoder.yudao.module.system.service.user;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.system.controller.admin.user.dto.UserPageDTO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.factoryUser.FactoryUserPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.*;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import com.baomidou.mybatisplus.core.metadata.IPage;
import javax.validation.Valid;
import java.io.InputStream;
@ -296,4 +298,12 @@ public interface AdminUserService {
* @return
*/
List<AdminUserDO> getAllList(Integer status, Integer type, List<Long> userIds);
/**
* 获取所有人员列表根据考勤组
*
* @param dto
* @return
*/
IPage<UserSimpleRespVO> getAllUserListByGroupIds(UserPageDTO dto);
}

View File

@ -12,7 +12,9 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.string.DTO.IdCardDO;
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
import cn.iocoder.yudao.framework.datapermission.core.util.DataPermissionUtils;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.module.infra.api.file.FileApi;
import cn.iocoder.yudao.module.system.controller.admin.user.dto.UserPageDTO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.factoryUser.FactoryUserPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO;
@ -27,6 +29,7 @@ import cn.iocoder.yudao.module.system.service.dept.PostService;
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
import cn.iocoder.yudao.module.system.service.tenant.TenantService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.common.annotations.VisibleForTesting;
import com.xingyuv.http.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
@ -597,4 +600,9 @@ public class AdminUserServiceImpl implements AdminUserService {
.in(CollectionUtil.isNotEmpty(userIds), AdminUserDO::getId, userIds));
}
@Override
public IPage<UserSimpleRespVO> getAllUserListByGroupIds(UserPageDTO dto) {
return userMapper.getAllUserListByGroupIds(MyBatisUtils.buildPage(dto), dto);
}
}

View File

@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
@ -279,15 +280,19 @@ public class LogStatisticsServiceImpl implements LogStatisticsService {
LogRuleDO logRuleDO = logRuleService.getLogRuleByFormId(dto.getFormId());
// 判断开始时间是否当天 / 是否本周
boolean flag = false;
Date begin = DateUtil.parse(dto.getBeginTime(), "yyyy-MM-dd").toJdkDate();
List<LogStatisticsDetailsVO> logStatisticsDOS = new ArrayList<>();
Date thisDate = new Date();
if (logRuleDO.getType() == 1) {
flag = DateUtil.isSameDay(begin, thisDate);
} else if (logRuleDO.getType() == 2) {
flag = DateUtil.isSameWeek(begin, thisDate, true);
List<String> dateList = new ArrayList<>();
if (ObjectUtil.isNotEmpty(dto.getBeginTime())) {
Date begin = DateUtil.parse(dto.getBeginTime(), "yyyy-MM-dd").toJdkDate();
Date thisDate = new Date();
if (logRuleDO.getType() == 1) {
flag = DateUtil.isSameDay(begin, thisDate);
} else if (logRuleDO.getType() == 2) {
flag = DateUtil.isSameWeek(begin, thisDate, true);
}
dateList = DateUtils.betweenDayStrList(dto.getBeginTime(), dto.getEndTime());
}
List<String> dateList = DateUtils.betweenDayStrList(dto.getBeginTime(), dto.getEndTime());
// 这里将区间转换为具体的日期 因为mysql BETWEEN 会导致索引失效
if (flag) {
logStatisticsDOS = logStatisticsMapper.getCurrentStatistics(dto.getFormId(), dateList);

View File

@ -9,4 +9,27 @@
文档可见https://www.iocoder.cn/MyBatis/x-plugins/
-->
<select id="statistics"
resultType="cn.iocoder.yudao.module.system.dal.dataobject.attendance.punchrecord.AttendancePunchRecordDO">
select
a.*,
b.name as deptName
from kq_attendance_punch_record a
left join system_dept as b on a.dept_id = b.id
<where>
a.deleted = 0
<if test="userList != null and userList.size() > 0">
and a.user_id in
<foreach collection="userList" item="userId" separator="," open="(" close=")">
#{userId}
</foreach>
</if>
<if test="dateList != null and dateList.size() > 0">
and a.day_time in
<foreach collection="dateList" item="dayTime" separator="," open="(" close=")">
#{dayTime}
</foreach>
</if>
</where>
</select>
</mapper>

View File

@ -54,4 +54,31 @@
</foreach>
and not exists(select id from kq_attendance_group_user where user_id = a.id and attendance_group_id != #{groupId} and deleted = 0)
</select>
<select id="getAllUserListByGroupIds"
resultType="cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserSimpleRespVO">
select a.id,
a.nickname,
a.avatar,
a.dept_id,
c.name deptName
from system_users as a
left join kq_attendance_group_user b on a.id = b.user_id
left join system_dept as c on a.dept_id = c.id
<where>
a.deleted = 0 and b.deleted = 0
<if test="dto.groupIds != null and dto.groupIds.size() > 0">
and b.attendance_group_id in
<foreach collection="dto.groupIds" item="groupId" open="(" close=")" separator=",">
#{groupId}
</foreach>
</if>
<if test="dto.name != null and dto.name != ''">
and a.nickname like concat('%', #{dto.name}, '%')
</if>
<if test="dto.status != null">
and a.status = #{dto.status}
</if>
</where>
</select>
</mapper>