huminmin
4 天以前 cd3cb071ebad82444f92575577e6975dae07d383
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
package com.ruoyi.staff.service.impl;
 
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.project.system.domain.SysDept;
import com.ruoyi.project.system.mapper.SysDeptMapper;
import com.ruoyi.project.system.service.ISysDictDataService;
import com.ruoyi.staff.dto.PersonalAttendanceRecordsDto;
import com.ruoyi.staff.mapper.StaffOnJobMapper;
import com.ruoyi.staff.pojo.PersonalAttendanceRecords;
import com.ruoyi.staff.mapper.PersonalAttendanceRecordsMapper;
import com.ruoyi.staff.pojo.StaffOnJob;
import com.ruoyi.staff.service.PersonalAttendanceRecordsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
 
/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 芯导软件(江苏)有限公司
 * @since 2026-02-09 01:20:07
 */
@Service
public class PersonalAttendanceRecordsServiceImpl extends ServiceImpl<PersonalAttendanceRecordsMapper, PersonalAttendanceRecords> implements PersonalAttendanceRecordsService {
    @Autowired
    private PersonalAttendanceRecordsMapper personalAttendanceRecordsMapper;
 
    @Autowired
    private StaffOnJobMapper staffOnJobMapper;
 
    @Autowired
    private ISysDictDataService dictDataService;
 
    @Autowired
    private SysDeptMapper sysDeptMapper;
 
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int add(PersonalAttendanceRecords personalAttendanceRecords) {
        // 当前时间
        LocalDate currentDate = LocalDate.now();
 
        // 首先根据用户ID查询员工信息
        QueryWrapper<StaffOnJob> staffQueryWrapper = new QueryWrapper<>();
        staffQueryWrapper.eq("staff_no", SecurityUtils.getUsername());
        StaffOnJob staffOnJob = staffOnJobMapper.selectOne(staffQueryWrapper);
        if (staffOnJob == null) {
            throw new BaseException("当前用户没有对应的员工信息");
        }
 
        // 根据员工ID和当前日期查询打卡记录
        QueryWrapper<PersonalAttendanceRecords> attendanceQueryWrapper = new QueryWrapper<>();
        attendanceQueryWrapper.eq("staff_on_job_id", staffOnJob.getId())
                .eq("date", currentDate);
        PersonalAttendanceRecords attendanceRecord = personalAttendanceRecordsMapper.selectOne(attendanceQueryWrapper);
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm");
        // 根据字典设置的考勤时间判断迟到早退
        if (attendanceRecord == null) {
            // 不存在打卡记录,创建新记录
            personalAttendanceRecords.setStaffOnJobId(staffOnJob.getId());
            personalAttendanceRecords.setDate(currentDate);
            personalAttendanceRecords.setWorkStartAt(LocalDateTime.now());
            personalAttendanceRecords.setStatus(determineAttendanceStatus(personalAttendanceRecords.getWorkStartAt(), true));
            personalAttendanceRecords.setRemark(personalAttendanceRecords.getRemark());
            personalAttendanceRecords.setTenantId(staffOnJob.getTenantId());
            return personalAttendanceRecordsMapper.insert(personalAttendanceRecords);
        } else {
            if (attendanceRecord.getWorkEndAt() == null) {
                // 更新工作结束时间和工作时长
                attendanceRecord.setWorkEndAt(LocalDateTime.now());
                // 计算工作时长(精确到分钟,保留2位小数)
                LocalDateTime startTime = attendanceRecord.getWorkStartAt();
                LocalDateTime endTime = attendanceRecord.getWorkEndAt();
                // 计算两个时间之间的分钟数
                long totalMinutes = java.time.Duration.between(startTime, endTime).toMinutes();
                BigDecimal workHours = BigDecimal.valueOf(totalMinutes)
                        .divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);
                attendanceRecord.setWorkHours(workHours);
                // 更新考勤状态
                attendanceRecord.setStatus(determineAttendanceStatus(attendanceRecord.getWorkEndAt(), false));
                return personalAttendanceRecordsMapper.updateById(attendanceRecord);
            } else {
                throw new BaseException("您已经打过卡了,无需重复打卡!!!");
            }
        }
    }
 
    // 根据实际时间和是否上班时间判断考勤状态
    // 0 正常 1 迟到 2 早退
    private byte determineAttendanceStatus(LocalDateTime actualTime, boolean isStart) {
        try {
            // 获取考勤时间配置
            String dictType = "sys_work_time"; // 考勤时间字典类型
            String timeConfig;
 
            if (isStart) {
                // 上班时间配置,默认为09:00
                timeConfig = dictDataService.selectDictLabel(dictType, "work_start_time");
                if (timeConfig == null || timeConfig.trim().isEmpty()) {
                    timeConfig = "09:00";
                }
            } else {
                // 下班时间配置,默认为18:00
                timeConfig = dictDataService.selectDictLabel(dictType, "work_end_time");
                if (timeConfig == null || timeConfig.trim().isEmpty()) {
                    timeConfig = "18:00";
                }
            }
 
            // 解析标准时间
            String[] timeParts = timeConfig.split(":");
            int standardHour = Integer.parseInt(timeParts[0]);
            int standardMinute = Integer.parseInt(timeParts[1]);
 
            // 获取实际时间的时分
            int actualHour = actualTime.getHour();
            int actualMinute = actualTime.getMinute();
 
            // 判断状态
            if (isStart) {
                // 上班打卡:超过标准时间算迟到
                if (actualHour > standardHour || (actualHour == standardHour && actualMinute > standardMinute)) {
                    return 1; // 迟到
                }
            } else {
                // 下班打卡:早于标准时间算早退
                if (actualHour < standardHour || (actualHour == standardHour && actualMinute < standardMinute)) {
                    return 2; // 早退
                }
            }
 
            return 0; // 正常
 
        } catch (Exception e) {
            // 如果获取配置失败,默认返回正常状态
            log.warn("获取考勤时间配置失败,使用默认状态:" + e.getMessage());
            return 0;
        }
    }
 
    @Override
    public IPage<PersonalAttendanceRecordsDto> listPage(Page page, PersonalAttendanceRecordsDto personalAttendanceRecordsDto) {
        return personalAttendanceRecordsMapper.listPage(page,personalAttendanceRecordsDto);
    }
 
    @Override
    public PersonalAttendanceRecordsDto todayInfo(PersonalAttendanceRecordsDto personalAttendanceRecordsDto) {
        // 获取当前日期
        LocalDate currentDate = LocalDate.now();
 
        // 首先根据用户ID查询员工信息
        QueryWrapper<StaffOnJob> staffQueryWrapper = new QueryWrapper<>();
        staffQueryWrapper.eq("staff_no", SecurityUtils.getUsername());
        StaffOnJob staffOnJob = staffOnJobMapper.selectOne(staffQueryWrapper);
 
        if (staffOnJob == null) {
            return null; // 当前用户没有对应的员工信息
        }
 
        // 根据员工ID和当前日期查询打卡记录
        QueryWrapper<PersonalAttendanceRecords> attendanceQueryWrapper = new QueryWrapper<>();
        attendanceQueryWrapper.eq("staff_on_job_id", staffOnJob.getId())
                .eq("date", currentDate);
        PersonalAttendanceRecords attendanceRecord = personalAttendanceRecordsMapper.selectOne(attendanceQueryWrapper);
 
        // 返回参数
        PersonalAttendanceRecordsDto resultDto = new PersonalAttendanceRecordsDto();
 
        if (attendanceRecord != null) {
            // 如果有打卡记录,复制打卡记录信息
            BeanUtils.copyProperties(attendanceRecord, resultDto);
        }
 
        // 员工相关信息
        resultDto.setStaffName(staffOnJob.getStaffName());
        resultDto.setStaffNo(staffOnJob.getStaffNo());
        resultDto.setDeptId(staffOnJob.getSysDeptId() != null ? staffOnJob.getSysDeptId() : null);
        SysDept dept = sysDeptMapper.selectDeptById(staffOnJob.getSysDeptId());
        resultDto.setDeptName(dept != null ? dept.getDeptName() : null);
 
        return resultDto;
    }
}