考勤导出样式调整/请假关联考勤系统

This commit is contained in:
aikai 2024-07-09 15:42:09 +08:00
parent 8078d05095
commit 8b17e6a0b0
12 changed files with 262 additions and 41 deletions

View File

@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.bpm.api.oa;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.bpm.api.oa.vo.BpmOALeaveRpcVO;
import cn.iocoder.yudao.module.bpm.enums.ApiConstants;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿fallbackFactory =
@Tag(name = "RPC 服务 - 流程实例")
public interface BpmOALeaveApi {
String PREFIX = ApiConstants.PREFIX + "/oa/leave";
@GetMapping(PREFIX + "/leaveListByTime")
@Operation(summary = "根据时间获取请假列表")
@Parameter(name = "time", description = "时间格式yyyy-MM-dd", required = true, example = "2024-05-11")
CommonResult<List<BpmOALeaveRpcVO>> getLeaveListByTime(@RequestParam(name = "time") String time);
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.bpm.api.oa.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Data
public class BpmOALeaveRpcVO {
@Schema(description = "请假表单主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id;
@Schema(description = "用户id")
private Long userId;
@Schema(description = "请假的开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "开始时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime startTime;
@Schema(description = "请假的结束时间", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "结束时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime endTime;
@Schema(description = "请假类型-参见 bpm_oa_leave_type 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "请假类型不能为空")
private Integer type;
}

View File

@ -0,0 +1,32 @@
package cn.iocoder.yudao.module.bpm.api.oa;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.bpm.api.oa.vo.BpmOALeaveRpcVO;
import cn.iocoder.yudao.module.bpm.service.oa.BpmOALeaveService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
/**
* Flowable 流程实例 Api 实现类
*
* @author jason
*/
@RestController
@Validated
public class BpmOALeaveApiImpl implements BpmOALeaveApi {
@Resource
private BpmOALeaveService leaveService;
@Override
public CommonResult<List<BpmOALeaveRpcVO>> getLeaveListByTime(String time) {
return success(leaveService.getLeaveListByTime(time));
}
}

View File

@ -0,0 +1,35 @@
package cn.iocoder.yudao.module.bpm.api.oa.vo;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class LeaveVO {
/**
* 请假表单主键
*/
private Long id;
/**
* 申请人的用户编号
* <p>
* 关联 AdminUserDO id 属性
*/
private Long userId;
/**
* 请假类型
*/
private String type;
/**
* 原因
*/
private String reason;
/**
* 开始时间
*/
private LocalDateTime startTime;
/**
* 结束时间
*/
private LocalDateTime endTime;
}

View File

@ -1,11 +1,15 @@
package cn.iocoder.yudao.module.bpm.dal.mysql.oa;
import cn.iocoder.yudao.module.bpm.api.oa.vo.BpmOALeaveRpcVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.leave.BpmOALeavePageReqVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOALeaveDO;
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 org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 请假申请 Mapper
@ -26,4 +30,10 @@ public interface BpmOALeaveMapper extends BaseMapperX<BpmOALeaveDO> {
.orderByDesc(BpmOALeaveDO::getId));
}
/**
*
* @param time
* @return
*/
List<BpmOALeaveRpcVO> getLeaveListByTime(@Param("time") String time);
}

View File

@ -2,11 +2,13 @@ package cn.iocoder.yudao.module.bpm.service.oa;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.bpm.api.oa.vo.BpmOALeaveRpcVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.leave.BpmOALeaveCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.leave.BpmOALeavePageReqVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOALeaveDO;
import javax.validation.Valid;
import java.util.List;
/**
* 请假申请 Service 接口
@ -50,4 +52,10 @@ public interface BpmOALeaveService {
*/
PageResult<BpmOALeaveDO> getLeavePage(Long userId, BpmOALeavePageReqVO pageReqVO);
/**
* 根据时间获取请假列表
* @param time
* @return
*/
List<BpmOALeaveRpcVO> getLeaveListByTime(String time);
}

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.bpm.service.oa;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.bpm.api.oa.vo.BpmOALeaveRpcVO;
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.leave.BpmOALeaveCreateReqVO;
@ -11,6 +12,7 @@ import cn.iocoder.yudao.module.bpm.convert.oa.BpmOALeaveConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOALeaveDO;
import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOALeaveMapper;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
@ -27,7 +29,6 @@ import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_LEAVE_NOT_
* OA 请假申请 Service 实现类
*
* @author jason
*/
@Service
@Validated
@ -43,6 +44,8 @@ public class BpmOALeaveServiceImpl extends BpmOABaseService implements BpmOALeav
@Resource
private BpmProcessInstanceApi processInstanceApi;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Override
@Transactional(rollbackFor = Exception.class)
@ -64,26 +67,42 @@ public class BpmOALeaveServiceImpl extends BpmOABaseService implements BpmOALeav
// 将工作流的编号更新到 OA 请假单中
leaveMapper.updateById(new BpmOALeaveDO().setId(leave.getId()).setProcessInstanceId(processInstanceId));
List<UploadUserFile> fileItems = createReqVO.getFileItems() ;
List<UploadUserFile> fileItems = createReqVO.getFileItems();
//这里的逻辑如果fileItems不为空且有数据那么说明是上传了附件的则需要更工作流文件表对应的实例Id
if (fileItems != null && !fileItems.isEmpty()) {
uploadBpmFileProcessInstanceId(processInstanceId,fileItems) ;
uploadBpmFileProcessInstanceId(processInstanceId, fileItems);
}
return leave.getId();
}
@Override
public void updateLeaveResult(Long id, Integer result) {
validateLeaveExists(id);
BpmOALeaveDO bpmOALeaveDO = validateLeaveExists(id);
leaveMapper.updateById(new BpmOALeaveDO().setId(id).setResult(result));
// -- 如果是通过 - 则判断当前时间是否是请假开始时间前
// -- 如果是的话 先插入到redis中 - (事前请假)
// -- 如果不是 则查询相应的考勤 修改考勤状态 事后请假 - 还需要判断结束时间是否
//
// if (result.equals(BpmProcessInstanceResultEnum.APPROVE.getResult())) {
// if (LocalDateTimeUtil.between(bpmOALeaveDO.getStartTime(), LocalDateTimeUtil.now()).toDays() > 0) {
// // -- 插入到redis中
// LeaveVO leaveVO = new LeaveVO();
// BeanUtil.copyProperties(bpmOALeaveDO, leaveVO);
// stringRedisTemplate.opsForHash().put("leave", bpmOALeaveDO.getUserId().toString(), JSONUtil.toJsonStr(leaveVO));
// } else {
// // -- 查询相应的考勤 修改考勤状态
//
// }
// }
}
private void validateLeaveExists(Long id) {
if (leaveMapper.selectById(id) == null) {
private BpmOALeaveDO validateLeaveExists(Long id) {
BpmOALeaveDO bpmOALeaveDO = leaveMapper.selectById(id);
if (bpmOALeaveDO == null) {
throw exception(OA_LEAVE_NOT_EXISTS);
}
return bpmOALeaveDO;
}
@Override
@ -96,4 +115,9 @@ public class BpmOALeaveServiceImpl extends BpmOABaseService implements BpmOALeav
return leaveMapper.selectPage(userId, pageReqVO);
}
@Override
public List<BpmOALeaveRpcVO> getLeaveListByTime(String time) {
return leaveMapper.getLeaveListByTime(time);
}
}

View File

@ -141,11 +141,9 @@ public class BpmOAReimbursementServiceImpl extends BpmOABaseService implements B
ProcessInstance instance = bpmProcessInstanceService.getProcessInstance(processInstanceId);
if (instance.isEnded()) {
//获得备用金信息
BpmOAImprestDO bpmOAImprestDO = bpmOAImprestMapper.selectOne(BpmOAImprestDO::getReimbursementId, id);
if (bpmOAImprestDO != null) {
//将相应备用金申请状态改为 已报销
bpmOAImprestMapper.updateById(new BpmOAImprestDO().setId(bpmOAImprestDO.getId()).setStatus(BpmOAImprestDO.FLAG_TRUE));
}

View File

@ -0,0 +1,23 @@
<?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="cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOALeaveMapper">
<!--
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
文档可见https://www.iocoder.cn/MyBatis/x-plugins/
-->
<select id="getLeaveListByTime" resultType="cn.iocoder.yudao.module.bpm.api.oa.vo.BpmOALeaveRpcVO">
SELECT
*
FROM
bpm_oa_leave
<where>
result = 2
AND DATE_FORMAT( end_time, '%Y-%m-%d' ) &gt;= #{time}
AND DATE_FORMAT( start_time, '%Y-%m-%d') &lt;= #{time}
</where>
</select>
</mapper>

View File

@ -182,6 +182,11 @@
<version>2.0.0-jdk8-snapshot</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-module-bpm-api</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>

View File

@ -5,14 +5,16 @@ import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import org.apache.poi.ss.usermodel.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class CustomCellStyleHandler implements CellWriteHandler {
private final Map<String, CellStyle> styleCache = new HashMap<>();
@Override
public void afterCellDispose(
WriteSheetHolder writeSheetHolder,
@ -24,36 +26,52 @@ public class CustomCellStyleHandler implements CellWriteHandler {
Boolean isHead) {
Workbook workbook = writeSheetHolder.getSheet().getWorkbook();
CellStyle cellStyle = workbook.createCellStyle();
writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), 7120);
// 设置水平和垂直居中对齐
cellStyle.setAlignment(HorizontalAlignment.CENTER);
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
// 设置不同行的样式
if (isHead) {
if (relativeRowIndex == 0 || relativeRowIndex == 1) {
// 头的策略
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
// 背景设置为红色
headWriteCellStyle.setFillForegroundColor(IndexedColors.TURQUOISE.getIndex());
WriteFont headWriteFont = new WriteFont();
headWriteFont.setFontHeightInPoints((short) 20);
headWriteCellStyle.setWriteFont(headWriteFont);
WriteCellStyle.merge(headWriteCellStyle, cellDataList.get(0).getOrCreateStyle());
} else if (relativeRowIndex == 2 || relativeRowIndex == 3) {
// 头的策略
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
// 背景设置为红色
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 {
}
// 获取或创建样式
CellStyle cellStyle = getOrCreateCellStyle(workbook, isHead, relativeRowIndex, cellDataList);
cell.setCellStyle(cellStyle);
}
}
private CellStyle getOrCreateCellStyle(Workbook workbook, Boolean isHead, Integer relativeRowIndex, List<WriteCellData<?>> cellDataList) {
String key = generateStyleKey(isHead, relativeRowIndex);
if (styleCache.containsKey(key)) {
return styleCache.get(key);
}
CellStyle cellStyle = workbook.createCellStyle();
cellStyle.setAlignment(HorizontalAlignment.CENTER);
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
// if (isHead != null && isHead) {
// setHeaderStyle(workbook, cellStyle, relativeRowIndex, cellDataList);
// }
styleCache.put(key, cellStyle);
return cellStyle;
}
private void setHeaderStyle(Workbook workbook, CellStyle cellStyle, Integer relativeRowIndex, List<WriteCellData<?>> cellDataList) {
if (relativeRowIndex == 0 || relativeRowIndex == 1) {
applyStyle(workbook, cellStyle, IndexedColors.TURQUOISE.getIndex(), (short) 20, cellDataList);
} else if (relativeRowIndex == 2 || relativeRowIndex == 3) {
applyStyle(workbook, cellStyle, IndexedColors.LIGHT_YELLOW.getIndex(), (short) 20, cellDataList);
}
}
private void applyStyle(Workbook workbook, CellStyle cellStyle, short backgroundColor, short fontSize, List<WriteCellData<?>> cellDataList) {
cellStyle.setFillForegroundColor(backgroundColor);
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
Font font = workbook.createFont();
font.setFontHeightInPoints(fontSize);
cellStyle.setFont(font);
cellDataList.get(0).setWriteCellStyle(null);
}
private String generateStyleKey(Boolean isHead, Integer relativeRowIndex) {
return "isHead:" + isHead + ",rowIndex:" + relativeRowIndex;
}
}

View File

@ -71,7 +71,8 @@ public class AttendancePunchRecordServiceImpl implements AttendancePunchRecordSe
private AttendanceGroupMapper attendanceGroupMapper;
@Resource
private AdminUserService adminUserService;
// @Resource
// private BpmOALeaveApi bpmOALeaveApi;
@Override
public Long createPunchRecord(AttendancePunchRecordSaveReqVO createReqVO) {
@ -194,6 +195,18 @@ public class AttendancePunchRecordServiceImpl implements AttendancePunchRecordSe
Map<Long, AdminUserDO> userMap, Map<Long, List<AttendanceGroupShiftItemDO>> itemMaps, String time, LocalDateTime localDateTime) {
List<AttendancePunchRecordDO> attendancePunchRecordDOList = new ArrayList<>();
LocalDateTime nextDayLocalDateTime = LocalDateTimeUtil.offset(localDateTime, 1, ChronoUnit.DAYS);
// -- 查看这天是否有通过的请假单子 / --------------事前请假流程
// List<BpmOALeaveRpcVO> leaveListByTime = bpmOALeaveApi.getLeaveListByTime(time).getCheckedData();
// // 如果有的话怎么处理
// Map<Long, List<BpmOALeaveRpcVO>> leaveMap = leaveListByTime.stream().collect(Collectors.groupingBy(BpmOALeaveRpcVO::getUserId));
// List<BpmOALeaveRpcVO> bpmOALeaveRpcVOS = leaveMap.get(1L);
// for (BpmOALeaveRpcVO bpmOALeaveRpcVO : bpmOALeaveRpcVOS) {
// if (bpmOALeaveRpcVO.getStartTime().isBefore(localDateTime) && bpmOALeaveRpcVO.getEndTime().isAfter(localDateTime)) {
//
// }
// }
for (Map.Entry<Long, Long> entry : map.entrySet()) {
String key = Constants.ATTENDANCE + Constants.UNDERLINE + entry.getKey() + Constants.UNDERLINE; // + 时间
AttendanceGroupDO attendanceGroupDO = groupMap.get(entry.getKey());