后端考勤:增加课次学员考勤名册查询
This commit is contained in:
1 parent
b716e55ac7
commit
18b8a07f55
4 files changed
+354
No files matched your search
+11
@@ -3,6 +3,7 @@ package com.ruoyi.web.controller.train;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
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.PutMapping;
|
||||
@@ -70,4 +71,14 @@ public class AttendanceController extends BaseController
|
||||
attendanceAppService.adjust(checkinId, dto, SecurityUtils.getUsername());
|
||||
return success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询课次学员考勤名册 (纯只读,供培训管理员点名签到)。
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('train:attendance:list')")
|
||||
@GetMapping("/lessons/{lessonId}/roster")
|
||||
public AjaxResult getLessonRoster(@PathVariable Long lessonId)
|
||||
{
|
||||
return success(attendanceAppService.getLessonRoster(lessonId));
|
||||
}
|
||||
}
|
||||
+227
@@ -0,0 +1,227 @@
|
||||
package com.ruoyi.train.domain.vo;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
/**
|
||||
* 课次学员考勤名册对象 (Attendance Lesson Roster VO)
|
||||
* 供培训管理员在业务端查看课次应到学员并完成首次签到。
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-09-21
|
||||
*/
|
||||
public class AttendanceLessonRosterVO implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 参训档案ID */
|
||||
private Long enrollmentId;
|
||||
|
||||
/** 课次ID */
|
||||
private Long lessonId;
|
||||
|
||||
/** 学员ID/工号 */
|
||||
private String studentId;
|
||||
|
||||
/** 学员姓名 */
|
||||
private String studentName;
|
||||
|
||||
/** 性别 */
|
||||
private String gender;
|
||||
|
||||
/** 所属部门/机构 */
|
||||
private String deptName;
|
||||
|
||||
/** 脱敏手机号 */
|
||||
private String phoneMasked;
|
||||
|
||||
/** 参训状态 (0:待报到, 1:已报到, 2:请假, 3:放弃, 4:已完成) */
|
||||
private Integer enrollmentStatus;
|
||||
|
||||
/** 考勤打卡记录ID (未打卡为null) */
|
||||
private Long checkinId;
|
||||
|
||||
/** 签到方式 (1:人脸, 2:刷卡, 3:扫码, 4:教师/管理代签,未打卡为null) */
|
||||
private Integer checkinWay;
|
||||
|
||||
/** 考勤状态 (0:缺勤, 1:正常, 2:迟到, 3:早退, 4:请假,未打卡为null) */
|
||||
private Integer attendanceStatus;
|
||||
|
||||
/** 签到时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date signInTime;
|
||||
|
||||
/** 签退时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date signOutTime;
|
||||
|
||||
/** 是否允许签到 (尚未产生签到事实且参训有效) */
|
||||
private Boolean canSignIn;
|
||||
|
||||
/** 是否允许签退 (已签到且未签退) */
|
||||
private Boolean canSignOut;
|
||||
|
||||
/** 是否允许调整 (已有考勤记录) */
|
||||
private Boolean canAdjust;
|
||||
|
||||
public Long getEnrollmentId()
|
||||
{
|
||||
return enrollmentId;
|
||||
}
|
||||
|
||||
public void setEnrollmentId(Long enrollmentId)
|
||||
{
|
||||
this.enrollmentId = enrollmentId;
|
||||
}
|
||||
|
||||
public Long getLessonId()
|
||||
{
|
||||
return lessonId;
|
||||
}
|
||||
|
||||
public void setLessonId(Long lessonId)
|
||||
{
|
||||
this.lessonId = lessonId;
|
||||
}
|
||||
|
||||
public String getStudentId()
|
||||
{
|
||||
return studentId;
|
||||
}
|
||||
|
||||
public void setStudentId(String studentId)
|
||||
{
|
||||
this.studentId = studentId;
|
||||
}
|
||||
|
||||
public String getStudentName()
|
||||
{
|
||||
return studentName;
|
||||
}
|
||||
|
||||
public void setStudentName(String studentName)
|
||||
{
|
||||
this.studentName = studentName;
|
||||
}
|
||||
|
||||
public String getGender()
|
||||
{
|
||||
return gender;
|
||||
}
|
||||
|
||||
public void setGender(String gender)
|
||||
{
|
||||
this.gender = gender;
|
||||
}
|
||||
|
||||
public String getDeptName()
|
||||
{
|
||||
return deptName;
|
||||
}
|
||||
|
||||
public void setDeptName(String deptName)
|
||||
{
|
||||
this.deptName = deptName;
|
||||
}
|
||||
|
||||
public String getPhoneMasked()
|
||||
{
|
||||
return phoneMasked;
|
||||
}
|
||||
|
||||
public void setPhoneMasked(String phoneMasked)
|
||||
{
|
||||
this.phoneMasked = phoneMasked;
|
||||
}
|
||||
|
||||
public Integer getEnrollmentStatus()
|
||||
{
|
||||
return enrollmentStatus;
|
||||
}
|
||||
|
||||
public void setEnrollmentStatus(Integer enrollmentStatus)
|
||||
{
|
||||
this.enrollmentStatus = enrollmentStatus;
|
||||
}
|
||||
|
||||
public Long getCheckinId()
|
||||
{
|
||||
return checkinId;
|
||||
}
|
||||
|
||||
public void setCheckinId(Long checkinId)
|
||||
{
|
||||
this.checkinId = checkinId;
|
||||
}
|
||||
|
||||
public Integer getCheckinWay()
|
||||
{
|
||||
return checkinWay;
|
||||
}
|
||||
|
||||
public void setCheckinWay(Integer checkinWay)
|
||||
{
|
||||
this.checkinWay = checkinWay;
|
||||
}
|
||||
|
||||
public Integer getAttendanceStatus()
|
||||
{
|
||||
return attendanceStatus;
|
||||
}
|
||||
|
||||
public void setAttendanceStatus(Integer attendanceStatus)
|
||||
{
|
||||
this.attendanceStatus = attendanceStatus;
|
||||
}
|
||||
|
||||
public Date getSignInTime()
|
||||
{
|
||||
return signInTime;
|
||||
}
|
||||
|
||||
public void setSignInTime(Date signInTime)
|
||||
{
|
||||
this.signInTime = signInTime;
|
||||
}
|
||||
|
||||
public Date getSignOutTime()
|
||||
{
|
||||
return signOutTime;
|
||||
}
|
||||
|
||||
public void setSignOutTime(Date signOutTime)
|
||||
{
|
||||
this.signOutTime = signOutTime;
|
||||
}
|
||||
|
||||
public Boolean getCanSignIn()
|
||||
{
|
||||
return canSignIn;
|
||||
}
|
||||
|
||||
public void setCanSignIn(Boolean canSignIn)
|
||||
{
|
||||
this.canSignIn = canSignIn;
|
||||
}
|
||||
|
||||
public Boolean getCanSignOut()
|
||||
{
|
||||
return canSignOut;
|
||||
}
|
||||
|
||||
public void setCanSignOut(Boolean canSignOut)
|
||||
{
|
||||
this.canSignOut = canSignOut;
|
||||
}
|
||||
|
||||
public Boolean getCanAdjust()
|
||||
{
|
||||
return canAdjust;
|
||||
}
|
||||
|
||||
public void setCanAdjust(Boolean canAdjust)
|
||||
{
|
||||
this.canAdjust = canAdjust;
|
||||
}
|
||||
}
|
||||
@@ -37,4 +37,12 @@ public interface AttendanceAppService
|
||||
* @param operator 操作人
|
||||
*/
|
||||
void adjust(Long checkinId, AttendanceAdjustDTO dto, String operator);
|
||||
|
||||
/**
|
||||
* 查询课次学员考勤名册 (纯只读,供培训管理员点名签到)。
|
||||
*
|
||||
* @param lessonId 课次ID
|
||||
* @return 考勤名册列表
|
||||
*/
|
||||
java.util.List<com.ruoyi.train.domain.vo.AttendanceLessonRosterVO> getLessonRoster(Long lessonId);
|
||||
}
|
||||
+108
@@ -1,6 +1,10 @@
|
||||
package com.ruoyi.train.service.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -17,6 +21,9 @@ import com.ruoyi.train.domain.TrainStudentCheckin;
|
||||
import com.ruoyi.train.domain.dto.AttendanceAdjustDTO;
|
||||
import com.ruoyi.train.domain.dto.AttendanceSignInDTO;
|
||||
import com.ruoyi.train.domain.dto.AttendanceSignOutDTO;
|
||||
import com.ruoyi.train.domain.query.EnrollmentQuery;
|
||||
import com.ruoyi.train.domain.vo.AttendanceLessonRosterVO;
|
||||
import com.ruoyi.train.domain.vo.EnrollmentItemVO;
|
||||
import com.ruoyi.train.mapper.TrainEnrollmentMapper;
|
||||
import com.ruoyi.train.mapper.TrainLessonMapper;
|
||||
import com.ruoyi.train.mapper.TrainPlanCourseMapper;
|
||||
@@ -231,4 +238,105 @@ public class AttendanceAppServiceImpl implements AttendanceAppService
|
||||
|
||||
trainStudentCheckinMapper.updateTrainStudentCheckin(checkin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AttendanceLessonRosterVO> getLessonRoster(Long lessonId)
|
||||
{
|
||||
if (lessonId == null)
|
||||
{
|
||||
throw new ServiceException("课次ID不能为空", 400);
|
||||
}
|
||||
|
||||
TrainLesson lesson = trainLessonMapper.selectTrainLessonById(lessonId);
|
||||
if (lesson == null)
|
||||
{
|
||||
throw new ServiceException(AttendanceErrorCode.LESSON_NOT_FOUND_MESSAGE, AttendanceErrorCode.LESSON_NOT_FOUND);
|
||||
}
|
||||
|
||||
TrainPlanCourse planCourse = trainPlanCourseMapper.selectTrainPlanCourseById(lesson.getPlanCourseId());
|
||||
if (planCourse == null || planCourse.getPlanId() == null)
|
||||
{
|
||||
throw new ServiceException("课次未关联有效的培训课程计划", 400);
|
||||
}
|
||||
|
||||
EnrollmentQuery query = new EnrollmentQuery();
|
||||
query.setPlanId(planCourse.getPlanId());
|
||||
List<EnrollmentItemVO> enrollments = trainEnrollmentMapper.selectEnrollmentItemList(query);
|
||||
|
||||
List<TrainStudentCheckin> checkins = trainStudentCheckinMapper.selectCheckinsByLessonId(lessonId);
|
||||
Map<Long, TrainStudentCheckin> checkinMap = new HashMap<>();
|
||||
if (checkins != null)
|
||||
{
|
||||
for (TrainStudentCheckin c : checkins)
|
||||
{
|
||||
if (c.getEnrollmentId() != null)
|
||||
{
|
||||
checkinMap.put(c.getEnrollmentId(), c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<AttendanceLessonRosterVO> roster = new ArrayList<>();
|
||||
if (enrollments != null)
|
||||
{
|
||||
for (EnrollmentItemVO item : enrollments)
|
||||
{
|
||||
// 排除已放弃参训学员 (STATUS_ABANDONED = 3)
|
||||
if (item.getEnrollmentStatus() != null && item.getEnrollmentStatus() == EnrollmentErrorCode.STATUS_ABANDONED)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
AttendanceLessonRosterVO vo = new AttendanceLessonRosterVO();
|
||||
vo.setEnrollmentId(item.getEnrollmentId());
|
||||
vo.setLessonId(lessonId);
|
||||
vo.setStudentId(item.getStudentId());
|
||||
vo.setStudentName(item.getStudentName());
|
||||
vo.setGender(item.getGender());
|
||||
vo.setDeptName(item.getOrgName());
|
||||
vo.setPhoneMasked(maskPhone(item.getPhone()));
|
||||
vo.setEnrollmentStatus(item.getEnrollmentStatus());
|
||||
|
||||
TrainStudentCheckin c = checkinMap.get(item.getEnrollmentId());
|
||||
if (c != null)
|
||||
{
|
||||
vo.setCheckinId(c.getCheckinId());
|
||||
vo.setCheckinWay(c.getCheckinWay());
|
||||
vo.setAttendanceStatus(c.getAttendanceStatus());
|
||||
vo.setSignInTime(c.getSignInTime());
|
||||
vo.setSignOutTime(c.getSignOutTime());
|
||||
// 仅当已有记录但未打签到时间时允许补签;已有签到时间则禁止重复签到
|
||||
vo.setCanSignIn(c.getSignInTime() == null);
|
||||
vo.setCanSignOut(c.getSignInTime() != null && c.getSignOutTime() == null);
|
||||
vo.setCanAdjust(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
vo.setCheckinId(null);
|
||||
vo.setCheckinWay(null);
|
||||
vo.setAttendanceStatus(null);
|
||||
vo.setSignInTime(null);
|
||||
vo.setSignOutTime(null);
|
||||
vo.setCanSignIn(true);
|
||||
vo.setCanSignOut(false);
|
||||
vo.setCanAdjust(false);
|
||||
}
|
||||
roster.add(vo);
|
||||
}
|
||||
}
|
||||
return roster;
|
||||
}
|
||||
|
||||
private String maskPhone(String phone)
|
||||
{
|
||||
if (phone == null || phone.length() < 7)
|
||||
{
|
||||
return phone;
|
||||
}
|
||||
if (phone.length() == 11)
|
||||
{
|
||||
return phone.substring(0, 3) + "****" + phone.substring(7);
|
||||
}
|
||||
return phone.substring(0, 2) + "****" + phone.substring(phone.length() - 2);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user