feat(wms): 新增考勤比对功能

- 创建 AttendanceCheckBo 数据传输对象用于考勤比对参数传递
- 定义 IWmsAttendanceCheckService 接口及其实现类
- 创建 WmsAttendanceCheck 实体类存储考勤比对结果数据
- 开发 WmsAttendanceCheckController 提供考勤比对接口
- 实现考勤比对核心逻辑,支持上下班时间段考勤检查
- 集成打卡记录查询和考勤规则应用功能
- 添加考勤状态判断和扣款计算逻辑
- 实现连续旷工天数统计功能
- 创建考勤比对结果的增删改查接口
- 配置 MyBatis 映射文件和 Excel 导出功能
This commit is contained in:
2026-05-12 16:29:54 +08:00
parent 736b786ff9
commit 693de2ad5e
9 changed files with 695 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
package com.klp.controller;
import com.klp.common.annotation.Log;
import com.klp.common.core.controller.BaseController;
import com.klp.common.core.domain.PageQuery;
import com.klp.common.core.domain.R;
import com.klp.common.core.page.TableDataInfo;
import com.klp.common.enums.BusinessType;
import com.klp.domain.bo.AttendanceCheckBo;
import com.klp.domain.bo.WmsAttendanceCheckBo;
import com.klp.domain.vo.WmsAttendanceCheckVo;
import com.klp.service.IWmsAttendanceCheckService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.constraints.NotEmpty;
import java.util.Arrays;
import java.util.List;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/wms/attendanceCheck")
public class WmsAttendanceCheckController extends BaseController {
private final IWmsAttendanceCheckService iWmsAttendanceCheckService;
@GetMapping("/list")
public TableDataInfo<WmsAttendanceCheckVo> list(WmsAttendanceCheckBo bo, PageQuery pageQuery) {
return iWmsAttendanceCheckService.queryPageList(bo, pageQuery);
}
@GetMapping("/{checkId}")
public R<WmsAttendanceCheckVo> getInfo(@PathVariable Long checkId) {
return R.ok(iWmsAttendanceCheckService.queryById(checkId));
}
@Log(title = "考勤比对", businessType = BusinessType.DELETE)
@DeleteMapping("/{checkIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] checkIds) {
return toAjax(iWmsAttendanceCheckService.deleteWithValidByIds(Arrays.asList(checkIds), true));
}
@Log(title = "考勤比对", businessType = BusinessType.INSERT)
@PostMapping("/check")
public R<Void> checkAttendance(@Validated @RequestBody AttendanceCheckBo bo) {
iWmsAttendanceCheckService.checkAttendance(bo);
return R.ok();
}
}

View File

@@ -0,0 +1,54 @@
package com.klp.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("wms_attendance_check")
public class WmsAttendanceCheck extends BaseEntity {
@TableId
private Long checkId;
private Long scheduleId;
private Long userId;
private String employeeName;
private Date workDate;
private Long shiftId;
private String shiftName;
private String shiftType;
private Date p1StartTime;
private Date p1EndTime;
private Date p1FirstCheck;
private Date p1LastCheck;
private Integer p1LateMinutes;
private Integer p1EarlyMinutes;
private String p1Status;
private BigDecimal p1Deduct;
private Date p2StartTime;
private Date p2EndTime;
private Date p2FirstCheck;
private Date p2LastCheck;
private Integer p2LateMinutes;
private Integer p2EarlyMinutes;
private String p2Status;
private BigDecimal p2Deduct;
private String absentType;
private Integer continuousAbsentDays;
private BigDecimal totalDeduct;
private String overallStatus;
private String remark;
@TableLogic
private Integer delFlag;
}

View File

@@ -0,0 +1,19 @@
package com.klp.domain.bo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.util.Date;
@Data
public class AttendanceCheckBo {
@NotNull(message = "开始日期不能为空")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date startDate;
@NotNull(message = "结束日期不能为空")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date endDate;
}

View File

@@ -0,0 +1,20 @@
package com.klp.domain.bo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
@Data
public class WmsAttendanceCheckBo {
private Long userId;
private String employeeName;
private Long shiftId;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date startDate;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date endDate;
}

View File

@@ -0,0 +1,71 @@
package com.klp.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
@ExcelIgnoreUnannotated
public class WmsAttendanceCheckVo {
private Long checkId;
private Long scheduleId;
private Long userId;
@ExcelProperty(value = "员工姓名")
private String employeeName;
@JsonFormat(pattern = "yyyy-MM-dd")
@ExcelProperty(value = "日期")
private Date workDate;
@ExcelProperty(value = "班次")
private String shiftName;
@JsonFormat(pattern = "HH:mm")
private Date p1StartTime;
@JsonFormat(pattern = "HH:mm")
private Date p1EndTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm")
private Date p1FirstCheck;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm")
private Date p1LastCheck;
@ExcelProperty(value = "上午迟到(分钟)")
private Integer p1LateMinutes;
@ExcelProperty(value = "上午早退(分钟)")
private Integer p1EarlyMinutes;
@ExcelProperty(value = "上午状态")
private String p1Status;
@ExcelProperty(value = "上午扣款")
private BigDecimal p1Deduct;
@JsonFormat(pattern = "HH:mm")
private Date p2StartTime;
@JsonFormat(pattern = "HH:mm")
private Date p2EndTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm")
private Date p2FirstCheck;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm")
private Date p2LastCheck;
@ExcelProperty(value = "下午迟到(分钟)")
private Integer p2LateMinutes;
@ExcelProperty(value = "下午早退(分钟)")
private Integer p2EarlyMinutes;
@ExcelProperty(value = "下午状态")
private String p2Status;
@ExcelProperty(value = "下午扣款")
private BigDecimal p2Deduct;
@ExcelProperty(value = "旷工类型")
private String absentType;
@ExcelProperty(value = "连续旷工天数")
private Integer continuousAbsentDays;
@ExcelProperty(value = "总扣款")
private BigDecimal totalDeduct;
@ExcelProperty(value = "总体状态")
private String overallStatus;
}

View File

@@ -0,0 +1,8 @@
package com.klp.mapper;
import com.klp.common.core.mapper.BaseMapperPlus;
import com.klp.domain.WmsAttendanceCheck;
import com.klp.domain.vo.WmsAttendanceCheckVo;
public interface WmsAttendanceCheckMapper extends BaseMapperPlus<WmsAttendanceCheckMapper, WmsAttendanceCheck, WmsAttendanceCheckVo> {
}

View File

@@ -0,0 +1,23 @@
package com.klp.service;
import com.klp.common.core.page.TableDataInfo;
import com.klp.common.core.domain.PageQuery;
import com.klp.domain.bo.AttendanceCheckBo;
import com.klp.domain.bo.WmsAttendanceCheckBo;
import com.klp.domain.vo.WmsAttendanceCheckVo;
import java.util.Collection;
import java.util.List;
public interface IWmsAttendanceCheckService {
WmsAttendanceCheckVo queryById(Long checkId);
TableDataInfo<WmsAttendanceCheckVo> queryPageList(WmsAttendanceCheckBo bo, PageQuery pageQuery);
List<WmsAttendanceCheckVo> queryList(WmsAttendanceCheckBo bo);
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
void checkAttendance(AttendanceCheckBo bo);
}

View File

@@ -0,0 +1,398 @@
package com.klp.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.klp.common.core.domain.PageQuery;
import com.klp.common.core.page.TableDataInfo;
import com.klp.common.utils.StringUtils;
import com.klp.domain.AttendanceRecords;
import com.klp.domain.WmsAttendanceCheck;
import com.klp.domain.WmsAttendanceRule;
import com.klp.domain.bo.AttendanceCheckBo;
import com.klp.domain.bo.AttendanceRecordsBo;
import com.klp.domain.bo.WmsAttendanceCheckBo;
import com.klp.domain.bo.WmsAttendanceScheduleBo;
import com.klp.domain.vo.AttendanceRecordsVo;
import com.klp.domain.vo.WmsAttendanceCheckVo;
import com.klp.domain.vo.WmsAttendanceScheduleVo;
import com.klp.mapper.WmsAttendanceCheckMapper;
import com.klp.mapper.WmsAttendanceRuleMapper;
import com.klp.service.IAttendanceRecordsService;
import com.klp.service.IWmsAttendanceCheckService;
import com.klp.service.IWmsAttendanceScheduleService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
@RequiredArgsConstructor
@Service
public class WmsAttendanceCheckServiceImpl implements IWmsAttendanceCheckService {
private final WmsAttendanceCheckMapper baseMapper;
private final IWmsAttendanceScheduleService scheduleService;
private final IAttendanceRecordsService attendanceRecordsService;
private final WmsAttendanceRuleMapper ruleMapper;
@Override
public WmsAttendanceCheckVo queryById(Long checkId) {
return baseMapper.selectVoById(checkId);
}
@Override
public TableDataInfo<WmsAttendanceCheckVo> queryPageList(WmsAttendanceCheckBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<WmsAttendanceCheck> lqw = buildQueryWrapper(bo);
Page<WmsAttendanceCheckVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
@Override
public List<WmsAttendanceCheckVo> queryList(WmsAttendanceCheckBo bo) {
LambdaQueryWrapper<WmsAttendanceCheck> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
return baseMapper.deleteBatchIds(ids) > 0;
}
private LambdaQueryWrapper<WmsAttendanceCheck> buildQueryWrapper(WmsAttendanceCheckBo bo) {
LambdaQueryWrapper<WmsAttendanceCheck> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getUserId() != null, WmsAttendanceCheck::getUserId, bo.getUserId());
lqw.like(StringUtils.isNotBlank(bo.getEmployeeName()), WmsAttendanceCheck::getEmployeeName, bo.getEmployeeName());
lqw.eq(bo.getShiftId() != null, WmsAttendanceCheck::getShiftId, bo.getShiftId());
lqw.ge(bo.getStartDate() != null, WmsAttendanceCheck::getWorkDate, bo.getStartDate());
lqw.le(bo.getEndDate() != null, WmsAttendanceCheck::getWorkDate, bo.getEndDate());
lqw.orderByDesc(WmsAttendanceCheck::getWorkDate);
return lqw;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void checkAttendance(AttendanceCheckBo bo) {
WmsAttendanceScheduleBo scheduleBo = new WmsAttendanceScheduleBo();
scheduleBo.setStartDate(bo.getStartDate());
scheduleBo.setEndDate(bo.getEndDate());
List<WmsAttendanceScheduleVo> schedules = scheduleService.queryList(scheduleBo);
if (schedules.isEmpty()) {
return;
}
WmsAttendanceRule rule = getActiveRule();
LocalDate startLocal = toLocalDate(bo.getStartDate());
LocalDate endLocal = toLocalDate(bo.getEndDate());
for (WmsAttendanceScheduleVo schedule : schedules) {
if (schedule.getEmployeeName() == null || schedule.getShiftStartTime() == null) {
continue;
}
// 获取该员工该日期的所有打卡记录
List<AttendanceRecords> records = getRecords(schedule.getEmployeeName(), schedule.getWorkDate());
WmsAttendanceCheck check = buildCheck(schedule, rule, records);
// 删除已有的比对结果
baseMapper.delete(Wrappers.<WmsAttendanceCheck>lambdaQuery()
.eq(WmsAttendanceCheck::getScheduleId, schedule.getScheduleId()));
baseMapper.insert(check);
}
// 更新连续旷工天数
updateContinuousAbsent(startLocal, endLocal);
}
private WmsAttendanceRule getActiveRule() {
LambdaQueryWrapper<WmsAttendanceRule> wrapper = Wrappers.lambdaQuery();
wrapper.eq(WmsAttendanceRule::getDelFlag, 0);
wrapper.last("LIMIT 1");
WmsAttendanceRule rule = ruleMapper.selectOne(wrapper);
if (rule == null) {
rule = new WmsAttendanceRule();
rule.setLateWarn(3L);
rule.setLate1(5L);
rule.setLate2(15L);
rule.setDeduct1(new BigDecimal("10"));
rule.setDeduct2(new BigDecimal("30"));
rule.setAbsentHalfDay(15L);
rule.setContinuousAbsentDays(3L);
}
return rule;
}
private List<AttendanceRecords> getRecords(String employeeName, Date workDate) {
AttendanceRecordsBo recordsBo = new AttendanceRecordsBo();
recordsBo.setEname(employeeName);
LocalDate ld = toLocalDate(workDate);
recordsBo.setChecktimeStart(toDate(ld.atStartOfDay()));
recordsBo.setChecktimeEnd(toDate(ld.atTime(LocalTime.of(23, 59, 59))));
List<AttendanceRecordsVo> voList = attendanceRecordsService.queryList(recordsBo);
return voList.stream()
.map(v -> {
AttendanceRecords r = new AttendanceRecords();
r.setId(v.getId());
r.setEname(v.getEname());
r.setChecktime(v.getChecktime());
return r;
})
.sorted(Comparator.comparing(AttendanceRecords::getChecktime))
.collect(Collectors.toList());
}
private WmsAttendanceCheck buildCheck(WmsAttendanceScheduleVo schedule, WmsAttendanceRule rule, List<AttendanceRecords> records) {
WmsAttendanceCheck check = new WmsAttendanceCheck();
check.setScheduleId(schedule.getScheduleId());
check.setUserId(schedule.getUserId());
check.setEmployeeName(schedule.getEmployeeName());
check.setWorkDate(schedule.getWorkDate());
check.setShiftId(schedule.getShiftId());
check.setShiftName(schedule.getShiftName());
check.setShiftType(schedule.getShiftType());
boolean hasPeriod2 = schedule.getShiftStartTime2() != null && schedule.getShiftEndTime2() != null;
if (records.isEmpty()) {
check.setOverallStatus("absent_full");
check.setAbsentType("full_day");
return check;
}
List<LocalTime> checkTimes = records.stream()
.map(r -> toLocalDateTime(r.getChecktime()).toLocalTime())
.collect(Collectors.toList());
if (hasPeriod2) {
// 正常班次:按时间中点划分上下午
LocalTime p1End = toLocalTime(schedule.getShiftEndTime());
LocalTime p2Start = toLocalTime(schedule.getShiftStartTime2());
LocalTime split = LocalTime.of(
(p1End.getHour() + p2Start.getHour()) / 2,
(p1End.getMinute() + p2Start.getMinute()) / 2);
List<LocalTime> period1Times = new ArrayList<>();
List<LocalTime> period2Times = new ArrayList<>();
for (LocalTime t : checkTimes) {
if (t.isBefore(split)) {
period1Times.add(t);
} else {
period2Times.add(t);
}
}
check.setP1StartTime(schedule.getShiftStartTime());
check.setP1EndTime(schedule.getShiftEndTime());
checkPeriod(check, rule, 1, period1Times, schedule.getShiftStartTime(), schedule.getShiftEndTime(), records);
check.setP2StartTime(schedule.getShiftStartTime2());
check.setP2EndTime(schedule.getShiftEndTime2());
checkPeriod(check, rule, 2, period2Times, schedule.getShiftStartTime2(), schedule.getShiftEndTime2(), records);
} else {
// 倒班:全天一个时段
check.setP1StartTime(schedule.getShiftStartTime());
check.setP1EndTime(schedule.getShiftEndTime());
checkPeriod(check, rule, 1, checkTimes, schedule.getShiftStartTime(), schedule.getShiftEndTime(), records);
}
// 总体判定
calculateOverall(check, rule);
return check;
}
private void checkPeriod(WmsAttendanceCheck check, WmsAttendanceRule rule, int period,
List<LocalTime> periodTimes, Date expectedStart, Date expectedEnd,
List<AttendanceRecords> allRecords) {
if (periodTimes.isEmpty()) {
if (period == 1) {
check.setP1Status("missed");
} else {
check.setP2Status("missed");
}
return;
}
LocalTime expStart = toLocalTime(expectedStart);
LocalTime expEnd = toLocalTime(expectedEnd);
LocalTime firstCheck = periodTimes.get(0);
LocalTime lastCheck = periodTimes.get(periodTimes.size() - 1);
int lateMinutes = 0;
int earlyMinutes = 0;
BigDecimal deduct = BigDecimal.ZERO;
String status = "normal";
// 迟到判定:最早打卡 vs 理论上班时间
if (firstCheck.isAfter(expStart)) {
lateMinutes = (int) Duration.between(expStart, firstCheck).toMinutes();
if (lateMinutes > rule.getAbsentHalfDay()) {
status = "absent_half";
} else if (lateMinutes > rule.getLate2()) {
status = "absent_half";
} else if (lateMinutes > rule.getLate1()) {
status = "late_2";
deduct = deduct.add(rule.getDeduct2());
} else if (lateMinutes > rule.getLateWarn()) {
status = "late_1";
deduct = deduct.add(rule.getDeduct1());
} else {
status = "late_warn";
}
}
// 早退判定:最晚打卡 vs 理论下班时间
if (lastCheck.isBefore(expEnd)) {
int min = (int) Duration.between(lastCheck, expEnd).toMinutes();
if (min > rule.getAbsentHalfDay()) {
status = maxSeverity(status, "absent_half");
earlyMinutes = min;
} else if (min > rule.getLate2()) {
status = maxSeverity(status, "absent_half");
earlyMinutes = min;
} else if (min > rule.getLate1()) {
status = maxSeverity(status, "early_2");
deduct = deduct.add(rule.getDeduct2());
earlyMinutes = min;
} else if (min > rule.getLateWarn()) {
status = maxSeverity(status, "early_1");
deduct = deduct.add(rule.getDeduct1());
earlyMinutes = min;
} else {
if ("normal".equals(status)) {
status = "early_warn";
}
earlyMinutes = min;
}
}
// 找到对应的打卡时间
for (AttendanceRecords r : allRecords) {
LocalTime ct = toLocalDateTime(r.getChecktime()).toLocalTime();
if (ct.equals(firstCheck)) {
if (period == 1) check.setP1FirstCheck(r.getChecktime());
else check.setP2FirstCheck(r.getChecktime());
}
if (ct.equals(lastCheck)) {
if (period == 1) check.setP1LastCheck(r.getChecktime());
else check.setP2LastCheck(r.getChecktime());
}
}
if (period == 1) {
check.setP1LateMinutes(lateMinutes);
check.setP1EarlyMinutes(earlyMinutes);
check.setP1Status(status);
check.setP1Deduct(deduct);
} else {
check.setP2LateMinutes(lateMinutes);
check.setP2EarlyMinutes(earlyMinutes);
check.setP2Status(status);
check.setP2Deduct(deduct);
}
}
private String maxSeverity(String a, String b) {
List<String> severity = java.util.Arrays.asList("normal", "late_warn", "early_warn", "late_1", "early_1", "late_2", "early_2", "absent_half");
int ai = severity.indexOf(a);
int bi = severity.indexOf(b);
return severity.get(Math.max(ai, bi));
}
private void calculateOverall(WmsAttendanceCheck check, WmsAttendanceRule rule) {
BigDecimal total = BigDecimal.ZERO;
boolean hasAbsentHalf = false;
if (check.getP1Deduct() != null) total = total.add(check.getP1Deduct());
if (check.getP2Deduct() != null) total = total.add(check.getP2Deduct());
check.setTotalDeduct(total);
if ("absent_half".equals(check.getP1Status()) || "absent_half".equals(check.getP2Status())) {
hasAbsentHalf = true;
}
if ("missed".equals(check.getP1Status()) && check.getP2StartTime() != null && "missed".equals(check.getP2Status())) {
check.setAbsentType("full_day");
check.setOverallStatus("absent_full");
return;
}
if (check.getP1StartTime() == null && check.getP2StartTime() == null) {
check.setAbsentType("full_day");
check.setOverallStatus("absent_full");
return;
}
if (hasAbsentHalf) {
check.setAbsentType("half_day");
check.setOverallStatus("absent_half");
return;
}
boolean abnormal = !"normal".equals(check.getP1Status()) || (check.getP2Status() != null && !"normal".equals(check.getP2Status()));
check.setOverallStatus(abnormal ? "abnormal" : "normal");
}
private void updateContinuousAbsent(LocalDate startDate, LocalDate endDate) {
List<WmsAttendanceCheck> checks = baseMapper.selectList(Wrappers.<WmsAttendanceCheck>lambdaQuery()
.ge(WmsAttendanceCheck::getWorkDate, toDate(startDate.atStartOfDay()))
.le(WmsAttendanceCheck::getWorkDate, toDate(endDate.atTime(LocalTime.of(23, 59, 59))))
.eq(WmsAttendanceCheck::getDelFlag, 0));
for (WmsAttendanceCheck check : checks) {
if (check.getAbsentType() != null) {
int continuous = countContinuousAbsent(check.getUserId(), toLocalDate(check.getWorkDate()));
check.setContinuousAbsentDays(continuous);
baseMapper.updateById(check);
}
}
}
private int countContinuousAbsent(Long userId, LocalDate workDate) {
int count = 0;
LocalDate date = workDate.minusDays(1);
while (true) {
WmsAttendanceCheck prev = baseMapper.selectOne(Wrappers.<WmsAttendanceCheck>lambdaQuery()
.eq(WmsAttendanceCheck::getUserId, userId)
.eq(WmsAttendanceCheck::getWorkDate, toDate(date.atStartOfDay()))
.eq(WmsAttendanceCheck::getDelFlag, 0));
if (prev != null && prev.getAbsentType() != null) {
count++;
date = date.minusDays(1);
} else {
break;
}
}
return count;
}
private static LocalDate toLocalDate(Date date) {
return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
}
private static LocalTime toLocalTime(Date date) {
if (date == null) return null;
return date.toInstant().atZone(ZoneId.systemDefault()).toLocalTime();
}
private static LocalDateTime toLocalDateTime(Date date) {
if (date == null) return null;
return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
}
private static Date toDate(LocalDateTime ldt) {
return Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
}
}

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.klp.mapper.WmsAttendanceCheckMapper">
<resultMap type="com.klp.domain.WmsAttendanceCheck" id="WmsAttendanceCheckResult">
<result property="checkId" column="check_id"/>
<result property="scheduleId" column="schedule_id"/>
<result property="userId" column="user_id"/>
<result property="employeeName" column="employee_name"/>
<result property="workDate" column="work_date"/>
<result property="shiftId" column="shift_id"/>
<result property="shiftName" column="shift_name"/>
<result property="shiftType" column="shift_type"/>
<result property="p1StartTime" column="p1_start_time"/>
<result property="p1EndTime" column="p1_end_time"/>
<result property="p1FirstCheck" column="p1_first_check"/>
<result property="p1LastCheck" column="p1_last_check"/>
<result property="p1LateMinutes" column="p1_late_minutes"/>
<result property="p1EarlyMinutes" column="p1_early_minutes"/>
<result property="p1Status" column="p1_status"/>
<result property="p1Deduct" column="p1_deduct"/>
<result property="p2StartTime" column="p2_start_time"/>
<result property="p2EndTime" column="p2_end_time"/>
<result property="p2FirstCheck" column="p2_first_check"/>
<result property="p2LastCheck" column="p2_last_check"/>
<result property="p2LateMinutes" column="p2_late_minutes"/>
<result property="p2EarlyMinutes" column="p2_early_minutes"/>
<result property="p2Status" column="p2_status"/>
<result property="p2Deduct" column="p2_deduct"/>
<result property="absentType" column="absent_type"/>
<result property="continuousAbsentDays" column="continuous_absent_days"/>
<result property="totalDeduct" column="total_deduct"/>
<result property="overallStatus" column="overall_status"/>
<result property="remark" column="remark"/>
<result property="delFlag" column="del_flag"/>
<result property="createBy" column="create_by"/>
<result property="updateBy" column="update_by"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
</resultMap>
</mapper>