考勤打卡接口完成

This commit is contained in:
gaoxiong 2025-07-21 22:46:42 +08:00
parent 054e30c1b8
commit 4ed5025a3a
9 changed files with 324 additions and 1 deletions

View File

@ -116,5 +116,9 @@ public interface Converts {
InspectionReportReportInfo toInspectionReportReportInfo(InspectionReportEntity entity); InspectionReportReportInfo toInspectionReportReportInfo(InspectionReportEntity entity);
List<InspectionReportSchemeInfo> toInspectionReportSchemeInfo(List<CheckSchemeEntity> list); List<InspectionReportSchemeInfo> toInspectionReportSchemeInfo(List<CheckSchemeEntity> list);
AttendanceRecordEntity toAttendanceRecordEntity(AttendanceRecordReq req);
List<AttendanceRecordResp> toAttendanceRecordResp(List<AttendanceRecordEntity> list);
} }

View File

@ -0,0 +1,54 @@
package com.dite.znpt.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.dite.znpt.domain.AuditableEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* @Author: gaoxiong
* @Date: 2025/7/21 20:51
* @Description:
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("attendance_record")
@ApiModel(value="AttendanceRecordEntity对象", description="打卡记录表")
public class AttendanceRecordEntity extends AuditableEntity implements Serializable {
@Serial
private static final long serialVersionUID = 6186237408298557453L;
@ApiModelProperty("考勤记录id")
@TableId(value = "record_id", type = IdType.ASSIGN_UUID)
private String recordId;
@ApiModelProperty("考勤人员")
private String userId;
@ApiModelProperty("记录类型0-上班1-下班2-无效")
private String recordType;
@ApiModelProperty("考勤日期")
private LocalDate attendanceDate;
@ApiModelProperty("打卡时间")
private LocalDateTime recordTime;
@ApiModelProperty("照片")
private String recordImage;
@ApiModelProperty("打卡地点,经纬度")
private String recordPosition;
@ApiModelProperty("打卡地点,中文描述")
private String recordPositionLabel;
}

View File

@ -0,0 +1,34 @@
package com.dite.znpt.domain.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.io.Serial;
import java.io.Serializable;
/**
* @Author: gaoxiong
* @Date: 2025/7/21 21:10
* @Description:
*/
@Data
@ApiModel("考勤记录请求对象")
public class AttendanceRecordReq implements Serializable {
@Serial
private static final long serialVersionUID = 3567864990724491657L;
@NotBlank(message = "打卡照片不能为空")
@ApiModelProperty("打卡照片")
private String recordImage;
@NotBlank(message = "打卡地点不能为空")
@ApiModelProperty("打卡地点,经纬度")
private String recordPosition;
@ApiModelProperty("打卡地点,中文描述")
private String recordPositionLabel;
}

View File

@ -0,0 +1,54 @@
package com.dite.znpt.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* @Author: gaoxiong
* @Date: 2025/7/21 21:11
* @Description:
*/
@Data
@ApiModel("考勤记录响应对象")
public class AttendanceRecordResp implements Serializable {
@Serial
private static final long serialVersionUID = -4158464225924809958L;
@ApiModelProperty("考勤记录id")
private String recordId;
@ApiModelProperty("考勤人员id")
private String userId;
@ApiModelProperty("考勤人员")
private String name;
@ApiModelProperty("记录类型, 0-上班1-下班2-无效")
private String recordType;
@JsonFormat(pattern = "yyyy-MM-dd")
@ApiModelProperty("考勤日期")
private LocalDate attendanceDate;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty("打卡时间")
private LocalDateTime recordTime;
@ApiModelProperty("打卡照片")
private String recordImage;
@ApiModelProperty("打卡地点,经纬度")
private String recordPosition;
@ApiModelProperty("打卡地点,中文描述")
private String recordPositionLabel;
}

View File

@ -0,0 +1,12 @@
package com.dite.znpt.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dite.znpt.domain.entity.AttendanceRecordEntity;
/**
* @Author: gaoxiong
* @Date: 2025/7/21 21:19
* @Description:
*/
public interface AttendanceRecordMapper extends BaseMapper<AttendanceRecordEntity> {
}

View File

@ -0,0 +1,23 @@
package com.dite.znpt.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.dite.znpt.domain.entity.AttendanceRecordEntity;
import com.dite.znpt.domain.vo.AttendanceRecordReq;
import com.dite.znpt.domain.vo.AttendanceRecordResp;
import io.swagger.models.auth.In;
import java.util.List;
/**
* @Author: gaoxiong
* @Date: 2025/7/21 21:20
* @Description:
*/
public interface AttendanceRecordService extends IService<AttendanceRecordEntity> {
void save(AttendanceRecordReq req);
List<AttendanceRecordResp> listToday(String userId);
List<AttendanceRecordResp> listMonth(String userId, Integer year, Integer month);
}

View File

@ -0,0 +1,93 @@
package com.dite.znpt.service.impl;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dite.znpt.constant.Constants;
import com.dite.znpt.constant.Message;
import com.dite.znpt.converts.Converts;
import com.dite.znpt.domain.entity.AttendanceRecordEntity;
import com.dite.znpt.domain.entity.UserEntity;
import com.dite.znpt.domain.vo.AttendanceRecordReq;
import com.dite.znpt.domain.vo.AttendanceRecordResp;
import com.dite.znpt.exception.ServiceException;
import com.dite.znpt.mapper.AttendanceRecordMapper;
import com.dite.znpt.service.AttendanceRecordService;
import com.dite.znpt.service.UserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
/**
* @Author: gaoxiong
* @Date: 2025/7/21 21:20
* @Description:
*/
@Service
public class AttendanceRecordServiceImpl extends ServiceImpl<AttendanceRecordMapper, AttendanceRecordEntity> implements AttendanceRecordService {
@Resource
private UserService userService;
@Transactional(rollbackFor = Exception.class)
@Override
public void save(AttendanceRecordReq req) {
AttendanceRecordEntity entity = Converts.INSTANCE.toAttendanceRecordEntity(req);
entity.setUserId(StpUtil.getLoginId().toString());
List<AttendanceRecordEntity> list = this.list(Wrappers.<AttendanceRecordEntity>lambdaQuery()
.eq(AttendanceRecordEntity::getUserId, entity.getUserId())
.eq(AttendanceRecordEntity::getAttendanceDate, LocalDate.now())
.orderByAsc(AttendanceRecordEntity::getCreateTime)
);
if(list.isEmpty()){
entity.setRecordType("0");
}else {
entity.setRecordType("1");
List<AttendanceRecordEntity> invalidRecordList = list.stream().filter(record -> "1".equals(record.getRecordType())).collect(Collectors.toList());
invalidRecordList.forEach(record -> {
record.setRecordType("2");
});
this.updateBatchById(invalidRecordList);
}
this.save(entity);
}
@Override
public List<AttendanceRecordResp> listToday(String userId) {
List<AttendanceRecordResp> list = Converts.INSTANCE.toAttendanceRecordResp(
this.list(Wrappers.<AttendanceRecordEntity>lambdaQuery()
.eq(AttendanceRecordEntity::getUserId, userId)
.eq(AttendanceRecordEntity::getAttendanceDate, LocalDate.now())
.orderByAsc(AttendanceRecordEntity::getCreateTime)
)
);
UserEntity user = userService.getById(userId);
list.forEach(resp -> {
resp.setName(user.getName());
});
return list;
}
@Override
public List<AttendanceRecordResp> listMonth(String userId, Integer year, Integer month) {
LocalDate beginDate = LocalDate.of(year, month, 1);
LocalDate endDate = beginDate.plusMonths(1L);
List<AttendanceRecordResp> list = Converts.INSTANCE.toAttendanceRecordResp(
this.list(Wrappers.<AttendanceRecordEntity>lambdaQuery()
.eq(AttendanceRecordEntity::getUserId, userId)
.ge(AttendanceRecordEntity::getAttendanceDate, beginDate)
.lt(AttendanceRecordEntity::getAttendanceDate, endDate)
.orderByAsc(AttendanceRecordEntity::getCreateTime)
)
);
UserEntity user = userService.getById(userId);
list.forEach(resp -> {
resp.setName(user.getName());
});
return list;
}
}

View File

@ -0,0 +1,49 @@
package com.dite.znpt.web.controller;
import cn.dev33.satoken.stp.StpUtil;
import com.dite.znpt.domain.Result;
import com.dite.znpt.domain.vo.AttendanceRecordReq;
import com.dite.znpt.domain.vo.AttendanceRecordResp;
import com.dite.znpt.service.AttendanceRecordService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
* @Author: gaoxiong
* @Date: 2025/7/21 21:21
* @Description:
*/
@Api(tags = "考勤记录")
@RestController
@RequestMapping("/attendance-record")
public class AttendanceRecordController {
@Resource
private AttendanceRecordService attendanceRecordService;
@ApiOperation(value = "新增考勤记录", httpMethod = "POST")
@PostMapping
public Result<?> add(@Validated @RequestBody AttendanceRecordReq req){
attendanceRecordService.save(req);
return Result.ok();
}
@ApiOperation(value = "查询当天考勤记录", httpMethod = "GET")
@GetMapping("/list-today")
public Result<List<AttendanceRecordResp>> listToday(){
String userId = StpUtil.getLoginId().toString();
return Result.ok(attendanceRecordService.listToday(userId));
}
@ApiOperation(value = "按月份查询指定人员考勤记录", httpMethod = "GET")
@GetMapping("/list-month/{year}/{month}")
public Result<List<AttendanceRecordResp>> listMonth(@PathVariable Integer year, @PathVariable Integer month){
String userId = StpUtil.getLoginId().toString();
return Result.ok(attendanceRecordService.listMonth(userId, year, month));
}
}

View File

@ -25,6 +25,6 @@ spring:
# flowable相关表 # flowable相关表
flowable: flowable:
# true 会对数据库中所有表进行更新操作。如果表不存在,则自动创建(建议开发时使用) # true 会对数据库中所有表进行更新操作。如果表不存在,则自动创建(建议开发时使用)
database-schema-update: true database-schema-update: false
# 关闭定时任务JOB # 关闭定时任务JOB
async-executor-activate: false async-executor-activate: false