Merge branch 'dev' into frx

This commit is contained in:
furongxin 2024-06-25 14:29:48 +08:00
commit 644fc15bc1
29 changed files with 334 additions and 30 deletions

View File

@ -62,7 +62,9 @@ public class DeptDataPermissionRule implements DataPermissionRule {
"work_log_use", "work_log_use",
"work_log_statistics", "work_log_statistics",
"work_log_instance_ext", "work_log_instance_ext",
"bpm_oa_work_task" "bpm_oa_work_task",
"zc_dept_assets",
"zc_dept_assets_in_out_stock"
); );
/** /**

View File

@ -9,6 +9,8 @@ import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import javax.annotation.security.PermitAll;
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿fallbackFactory = @FeignClient(name = ApiConstants.NAME) // TODO 芋艿fallbackFactory =
@Tag(name = "RPC 服务 - 文件") @Tag(name = "RPC 服务 - 文件")
public interface ConfigApi { public interface ConfigApi {
@ -18,6 +20,7 @@ public interface ConfigApi {
@GetMapping(value = "/get-value-by-key") @GetMapping(value = "/get-value-by-key")
@Operation(summary = "根据参数键名查询参数值", description = "不可见的配置,不允许返回给前端") @Operation(summary = "根据参数键名查询参数值", description = "不可见的配置,不允许返回给前端")
@Parameter(name = "key", description = "参数键", required = true, example = "yunai.biz.username") @Parameter(name = "key", description = "参数键", required = true, example = "yunai.biz.username")
@PermitAll
CommonResult<String> getConfigKey(@RequestParam("key") String key); CommonResult<String> getConfigKey(@RequestParam("key") String key);
} }

View File

@ -9,6 +9,8 @@ import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿fallbackFactory = @FeignClient(name = ApiConstants.NAME) // TODO 芋艿fallbackFactory =
@Tag(name = "RPC 服务 - 微信小程序订阅消息发送") @Tag(name = "RPC 服务 - 微信小程序订阅消息发送")
public interface SubscribeMessageSendApi { public interface SubscribeMessageSendApi {
@ -30,4 +32,8 @@ public interface SubscribeMessageSendApi {
@PostMapping(PREFIX + "/send-worklog-comment") @PostMapping(PREFIX + "/send-worklog-comment")
@Operation(summary = "发送日志评论、回复通知") @Operation(summary = "发送日志评论、回复通知")
CommonResult<Long> sendWorkLogComment(@RequestBody SubscribeMessageReqDTO reqDTO); CommonResult<Long> sendWorkLogComment(@RequestBody SubscribeMessageReqDTO reqDTO);
@PostMapping(PREFIX + "/send-punch-reminder")
@Operation(summary = "发送打卡提醒通知")
CommonResult<Long> sendPunchReminder(@RequestBody SubscribeMessageReqDTO reqDTO);
} }

View File

@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.system.api.subscribe.dto.MsgData;
import cn.iocoder.yudao.module.system.api.subscribe.dto.SubscribeMessageReqDTO; import cn.iocoder.yudao.module.system.api.subscribe.dto.SubscribeMessageReqDTO;
import cn.iocoder.yudao.module.system.service.social.SocialClientService; import cn.iocoder.yudao.module.system.service.social.SocialClientService;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@ -22,6 +23,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
*/ */
@RestController // 提供 RESTful API 接口 Feign 调用 @RestController // 提供 RESTful API 接口 Feign 调用
@Validated @Validated
@Slf4j
public class SubscribeMessageSendApiImpl implements SubscribeMessageSendApi { public class SubscribeMessageSendApiImpl implements SubscribeMessageSendApi {
@Resource @Resource
@ -55,6 +57,16 @@ public class SubscribeMessageSendApiImpl implements SubscribeMessageSendApi {
return success(1L); return success(1L);
} }
@Override
public CommonResult<Long> sendPunchReminder(SubscribeMessageReqDTO reqDTO) {
try {
socialClientService.getWxMaService().getMsgService().sendSubscribeMsg(initWxMaSubscribeMessage(reqDTO));
} catch (Exception e) {
log.error("当前用户没有订阅考勤消息:{}", reqDTO.getToUser());
}
return success(1L);
}
private WxMaSubscribeMessage initWxMaSubscribeMessage(SubscribeMessageReqDTO reqDTO) { private WxMaSubscribeMessage initWxMaSubscribeMessage(SubscribeMessageReqDTO reqDTO) {
WxMaSubscribeMessage message = WxMaSubscribeMessage.builder() WxMaSubscribeMessage message = WxMaSubscribeMessage.builder()
.toUser(reqDTO.getToUser()) .toUser(reqDTO.getToUser())

View File

@ -73,7 +73,6 @@ public class AssetsController {
@GetMapping("/page") @GetMapping("/page")
@Operation(summary = "获得资产分页") @Operation(summary = "获得资产分页")
@PreAuthorize("@ss.hasPermission('system:assets:query')")
public CommonResult<PageResult<AssetsRespVO>> getAssetsPage(@Valid AssetsPageReqVO pageReqVO) { public CommonResult<PageResult<AssetsRespVO>> getAssetsPage(@Valid AssetsPageReqVO pageReqVO) {
PageResult<AssetsDO> pageResult = assetsService.getAssetsPage(pageReqVO); PageResult<AssetsDO> pageResult = assetsService.getAssetsPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, AssetsRespVO.class)); return success(BeanUtils.toBean(pageResult, AssetsRespVO.class));

View File

@ -81,7 +81,6 @@ public class AssetsSecondmentController {
@GetMapping("/page") @GetMapping("/page")
@Operation(summary = "获得资产借调分页") @Operation(summary = "获得资产借调分页")
@PreAuthorize("@ss.hasPermission('system:assets-secondment:query')")
public CommonResult<PageResult<AssetsSecondmentRespVO>> getAssetsSecondmentPage(@Valid AssetsSecondmentPageReqVO pageReqVO) { public CommonResult<PageResult<AssetsSecondmentRespVO>> getAssetsSecondmentPage(@Valid AssetsSecondmentPageReqVO pageReqVO) {
PageResult<AssetsSecondmentRespVO> pageResult = assetsSecondmentService.getAssetsSecondmentPage(pageReqVO); PageResult<AssetsSecondmentRespVO> pageResult = assetsSecondmentService.getAssetsSecondmentPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, AssetsSecondmentRespVO.class)); return success(BeanUtils.toBean(pageResult, AssetsSecondmentRespVO.class));

View File

@ -24,6 +24,10 @@ public class AssetsSecondmentRecordRespVO {
@ExcelProperty("资产名称") @ExcelProperty("资产名称")
private String assetsName; private String assetsName;
@Schema(description = "资产编号", example = "13886")
@ExcelProperty("资产编号")
private String assetsNo;
@Schema(description = "使用人id", example = "12905") @Schema(description = "使用人id", example = "12905")
@ExcelProperty("使用人id") @ExcelProperty("使用人id")
private Long useUserId; private Long useUserId;

View File

@ -0,0 +1,16 @@
package cn.iocoder.yudao.module.system.controller.admin.attendance.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class AttendanceWorkDTO {
@Schema(description = "上下班")
private String workTypeStr;
@Schema(description = "内容")
private String data;
}

View File

@ -0,0 +1,53 @@
package cn.iocoder.yudao.module.system.controller.admin.attendance.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class AttendanceExportExcelByCycleVO {
@Schema(description = "用户名称")
private String name;
@Schema(description = "考勤组名称")
private String groupName;
@Schema(description = "部门名称")
private String deptName;
@Schema(description = "职位名称")
private String postName;
@Schema(description = "出勤天数")
private String attendanceDays;
@Schema(description = "休息天数")
private String restDays;
@Schema(description = "工作时长")
private String lengthOfWork;
@Schema(description = "迟到次数")
private String lateNum;
@Schema(description = "迟到时长")
private String lateTime;
@Schema(description = "早退次数")
private String leaveEarlyNum;
@Schema(description = "早退时长")
private String leaveEarlyTime;
@Schema(description = "上班缺卡次数")
private String upMissingCardsNum;
@Schema(description = "下班缺卡次数")
private String downMissingCardsNum;
@Schema(description = "旷工天数")
private String absenteeismNum;
// @Schema(description = "出差时长")
// private String onBusinessTripTime;
// @Schema(description = "加班-审批单统计")
// private String overtimeApprovalOrderStatistics;
@Data
public class OvertimeVO {
@Schema(description = "工作日加班")
private String workingOvertimeOnWorkingDays;
@Schema(description = "休息日加班")
private String workOvertimeOnRestDays;
@Schema(description = "节假日加班")
private String workOvertimeOnHolidays;
}
}

View File

@ -13,6 +13,8 @@ import java.util.List;
@Data @Data
@Accessors(chain = true) @Accessors(chain = true)
public class AttendancePunchPageVO { public class AttendancePunchPageVO {
@Schema(description = "考勤组id")
private Long attendanceGroupId;
@Schema(description = "是否在考勤组 0否 1是") @Schema(description = "是否在考勤组 0否 1是")
private Integer inGroup = 1; private Integer inGroup = 1;
@Schema(description = "当天是否需要考勤 0否 1是") @Schema(description = "当天是否需要考勤 0否 1是")

View File

@ -13,4 +13,6 @@ public class RoleSimpleRespVO {
@Schema(description = "角色名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") @Schema(description = "角色名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
private String name; private String name;
@Schema(description = "角色编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "admin")
private String code;
} }

View File

@ -78,6 +78,9 @@ public class AttendancePunchRecordSaveReqVO {
@Schema(description = "早退时长时间戳") @Schema(description = "早退时长时间戳")
private Long leaveEarlyTime; private Long leaveEarlyTime;
@Schema(description = "加班时长时间戳")
private Long workOvertimeTime;
/** /**
* 打卡类型(0上班卡 1下班卡 2迟到卡 3早退卡 4未到打卡时间) 打卡状态 0正常 1迟到 2早退 3缺卡 4未打卡(还没到打卡时间) 5补卡 * 打卡类型(0上班卡 1下班卡 2迟到卡 3早退卡 4未到打卡时间) 打卡状态 0正常 1迟到 2早退 3缺卡 4未打卡(还没到打卡时间) 5补卡

View File

@ -3,7 +3,9 @@ package cn.iocoder.yudao.module.system.controller.admin.user;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleSimpleRespVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileRespVO; import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileRespVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO; import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO; import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO;
@ -73,6 +75,18 @@ public class UserProfileController {
return success(UserConvert.INSTANCE.convert(user, userRoles, dept, posts, socialUsers)); return success(UserConvert.INSTANCE.convert(user, userRoles, dept, posts, socialUsers));
} }
@GetMapping("/getRoles")
@Operation(summary = "获得登录用户角色信息")
@DataPermission(enable = false) // 关闭数据权限避免只查看自己时查询不到部门
public CommonResult<List<RoleSimpleRespVO>> getRoles() {
// 获得用户基本信息
AdminUserDO user = userService.getUser(getLoginUserId());
// 获得用户角色
List<RoleDO> userRoles = roleService.getRoleListFromCache(permissionService.getUserRoleIdListByUserId(user.getId()));
List<RoleSimpleRespVO> bean = BeanUtils.toBean(userRoles, RoleSimpleRespVO.class);
return success(bean);
}
@PutMapping("/update") @PutMapping("/update")
@Operation(summary = "修改用户个人信息") @Operation(summary = "修改用户个人信息")
public CommonResult<Boolean> updateUserProfile(@Valid @RequestBody UserProfileUpdateReqVO reqVO) { public CommonResult<Boolean> updateUserProfile(@Valid @RequestBody UserProfileUpdateReqVO reqVO) {

View File

@ -124,4 +124,14 @@ public class AttendancePunchRecordDO extends BaseDO {
* 早退时长时间戳 * 早退时长时间戳
*/ */
private Long leaveEarlyTime; private Long leaveEarlyTime;
/**
* 加班时长时间戳
*/
private Long workOvertimeTime;
/**
* 是否已提醒 0否 1是
*/
private Integer remindFlag;
} }

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.system.framework.datapermission.config; package cn.iocoder.yudao.module.system.framework.datapermission.config;
import cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataPermissionRuleCustomizer; import cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataPermissionRuleCustomizer;
import cn.iocoder.yudao.module.system.dal.dataobject.assets.DeptAssetsDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.dataobject.worklog.LogInstanceDO; import cn.iocoder.yudao.module.system.dal.dataobject.worklog.LogInstanceDO;
@ -24,13 +25,13 @@ public class DataPermissionConfiguration {
rule.addDeptColumn(LogUseDO.class, "use_user_dept"); rule.addDeptColumn(LogUseDO.class, "use_user_dept");
rule.addDeptColumn(LogStatisticsDO.class, "dept_id"); rule.addDeptColumn(LogStatisticsDO.class, "dept_id");
rule.addDeptColumn(LogInstanceDO.class, "dept_id"); rule.addDeptColumn(LogInstanceDO.class, "dept_id");
rule.addDeptColumn(DeptAssetsDO.class, "dept_id");
// user // user
rule.addUserColumn(AdminUserDO.class, "id"); rule.addUserColumn(AdminUserDO.class, "id");
rule.addUserColumn(LogUseDO.class, "use_user_id"); rule.addUserColumn(LogUseDO.class, "use_user_id");
rule.addUserColumn(LogStatisticsDO.class, "user_id"); rule.addUserColumn(LogStatisticsDO.class, "user_id");
rule.addUserColumn(LogInstanceDO.class, "start_user_id"); rule.addUserColumn(LogInstanceDO.class, "start_user_id");
}; };
} }

View File

@ -0,0 +1,131 @@
package cn.iocoder.yudao.module.system.job.attendance;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.BetweenFormatter;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.Constants;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import cn.iocoder.yudao.module.system.api.subscribe.SubscribeMessageSendApi;
import cn.iocoder.yudao.module.system.api.subscribe.dto.MsgData;
import cn.iocoder.yudao.module.system.api.subscribe.dto.SubscribeMessageReqDTO;
import cn.iocoder.yudao.module.system.controller.admin.attendance.dto.AttendanceWorkDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.punchrecord.AttendancePunchRecordDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.service.attendance.punchrecord.AttendancePunchRecordService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Component
@Slf4j
public class RemindJob {
@Resource
private AttendancePunchRecordService attendancePunchRecordService;
@Resource
private SubscribeMessageSendApi subscribeMessageSendApi;
@Resource
private AdminUserService adminUserService;
// TODO: 2024/4/22 - 考勤提醒 每10分钟执行一次
@XxlJob("remindJob")
@TenantJob // --- 这个注解 会将租户列表拉出来 完了后逐个租户执行 定时任务需要注意
public ReturnT<String> execute() throws Exception {
// -- 获取当天以及明天的未打卡并且未提醒记录
//未提醒列表
LocalDateTime localDateTime = LocalDateTime.now();
LocalDateTime futureTime = localDateTime.plusMinutes(15);
List<AttendancePunchRecordDO> attendancePunchRecordDOS = attendancePunchRecordService.getNotReminded(localDateTime);
if (attendancePunchRecordDOS.isEmpty()) {
return ReturnT.SUCCESS;
}
//还有10分钟就要上班了别忘记打卡哦
//幸苦一天了研发部全体人员提醒您记得打卡哦
Map<Long, AttendanceWorkDTO> map = new HashMap<>();
//打卡时间 - 15分钟之后是否是 大于打卡时间 - 是的话 - 把用户id拿出来 组装好消息发送
List<AttendancePunchRecordDO> editList = new ArrayList<>();
for (AttendancePunchRecordDO attendancePunchRecordDO : attendancePunchRecordDOS) {
if (attendancePunchRecordDO.getWorkType().equals(Constants.ZERO) && futureTime.isAfter(attendancePunchRecordDO.getShouldPunchTime())) {
AttendanceWorkDTO dto = new AttendanceWorkDTO();
dto.setWorkTypeStr("上班打卡");
dto.setData(String.format("还有%s钟就要上班了别忘记打卡哦",
DateUtil.formatBetween(LocalDateTimeUtil.between(localDateTime, attendancePunchRecordDO.getShouldPunchTime()).toMillis(), BetweenFormatter.Level.MINUTE)));
map.put(attendancePunchRecordDO.getUserId(), dto);
attendancePunchRecordDO.setRemindFlag(Constants.TRUE);
editList.add(attendancePunchRecordDO);
} else if (attendancePunchRecordDO.getWorkType().equals(Constants.ONE) && localDateTime.isAfter(attendancePunchRecordDO.getShouldPunchTime())) {
AttendanceWorkDTO dto = new AttendanceWorkDTO();
dto.setWorkTypeStr("下班打卡");
dto.setData("工作幸苦了,记得打卡哦~");
map.put(attendancePunchRecordDO.getUserId(), dto);
attendancePunchRecordDO.setRemindFlag(Constants.TRUE);
editList.add(attendancePunchRecordDO);
}
}
//获取到所有的用户id
if (MapUtil.isEmpty(map)) {
return ReturnT.SUCCESS;
}
List<Long> userIds = new ArrayList<>(map.keySet());
List<AdminUserDO> userList = adminUserService.getUserList(userIds);
List<AdminUserDO> users = userList.stream().filter(a -> StrUtil.isNotEmpty(a.getOpenId())).collect(Collectors.toList());
String templateId = "5yHyXhrsyqXi8s4hYhvaeMtz9kT5OPvDCe3h6G1T-OE";
List<SubscribeMessageReqDTO> dtos = new ArrayList<>();
for (AdminUserDO user : users) {
AttendanceWorkDTO attendanceWorkDTO = map.get(user.getId());
SubscribeMessageReqDTO dto = new SubscribeMessageReqDTO();
dto.setToUser(user.getOpenId());
dto.setTemplateId(templateId);
MsgData data = new MsgData();
data.setName("thing9");
data.setValue(attendanceWorkDTO.getWorkTypeStr());
dto.addData(data);
data = new MsgData();
data.setName("thing6");
data.setValue(attendanceWorkDTO.getData());
dto.addData(data);
dto.setPage("subPages/attendance/index");
dtos.add(dto);
}
if (CollectionUtil.isNotEmpty(dtos)) {
for (SubscribeMessageReqDTO dto : dtos) {
subscribeMessageSendApi.sendPunchReminder(dto);
}
}
if (CollectionUtil.isNotEmpty(editList)) {
attendancePunchRecordService.batchUpdate(editList);
}
// 返回执行成功
return ReturnT.SUCCESS;
}
}

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.system.job.equipment; package cn.iocoder.yudao.module.system.job.equipment;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManager; import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManager;
import cn.iocoder.yudao.module.system.dal.dataobject.equipment.AttendanceMachineDO; import cn.iocoder.yudao.module.system.dal.dataobject.equipment.AttendanceMachineDO;
@ -32,18 +33,15 @@ public class AttendanceMachineJob {
// 获得所有在线的设备 // 获得所有在线的设备
List<AttendanceMachineDO> attendanceMachineDOS = attendanceMachineService.getListByStatus(); List<AttendanceMachineDO> attendanceMachineDOS = attendanceMachineService.getListByStatus();
for (AttendanceMachineDO reqDO : attendanceMachineDOS) { for (AttendanceMachineDO reqDO : attendanceMachineDOS) {
// redis数据不存在则为离线状态 // redis数据不存在则为离线状态
if (stringRedisTemplate.opsForValue().get(reqDO.getDeviceNo()) == null) { String data = stringRedisTemplate.opsForValue().get(reqDO.getDeviceNo());
if (StrUtil.isEmpty(data)) {
attendanceMachineService.updateAttendanceMachineStatus(reqDO.getDeviceNo(), 0, null); attendanceMachineService.updateAttendanceMachineStatus(reqDO.getDeviceNo(), 0, null);
//同步 删除对应sessionId //同步 删除对应sessionId
WebSocketSessionManager webSocketSessionManager = SpringContentUtils.getBean(WebSocketSessionManager.class); WebSocketSessionManager webSocketSessionManager = SpringContentUtils.getBean(WebSocketSessionManager.class);
webSocketSessionManager.removeSession(webSocketSessionManager.getSessionByDeviceNum(reqDO.getDeviceNo())); webSocketSessionManager.removeSession(webSocketSessionManager.getSessionByDeviceNum(reqDO.getDeviceNo()));
}else { } else {
attendanceMachineService.updateAttendanceMachineStatus(reqDO.getDeviceNo(), 1, data);
attendanceMachineService.updateAttendanceMachineStatus(reqDO.getDeviceNo(), 1, stringRedisTemplate.opsForValue().get(reqDO.getDeviceNo()));
} }
} }
} }

View File

@ -112,11 +112,10 @@ public class DeptAssetsInOutStockServiceImpl implements DeptAssetsInOutStockServ
// - 如果是部门入库 则更新该部门的资产 // - 如果是部门入库 则更新该部门的资产
List<DeptAssetsInOutStockSaveReqVO> stockSaveReqVOS = inOutStockByDeptMap.get(vo.getInDeptId()); List<DeptAssetsInOutStockSaveReqVO> stockSaveReqVOS = inOutStockByDeptMap.get(vo.getInDeptId());
if (!stockSaveReqVOS.isEmpty()) { if (!stockSaveReqVOS.isEmpty()) {
Integer num = 0; Map<Long, Integer> stockSaveMaps = stockSaveReqVOS.stream().collect(Collectors.groupingBy(DeptAssetsInOutStockSaveReqVO::getAssetsId, Collectors.summingInt(DeptAssetsInOutStockSaveReqVO::getNum)));
for (DeptAssetsInOutStockSaveReqVO stockSaveReqVO : stockSaveReqVOS) { for (Map.Entry<Long, Integer> entry : stockSaveMaps.entrySet()) {
num += stockSaveReqVO.getNum(); deptInStockMap.put(vo.getInDeptId() + "_" + entry.getKey(), entry.getValue());
} }
deptInStockMap.put(vo.getInDeptId() + "_" + vo.getAssetsId(), num);
} }
} }
} }

View File

@ -163,6 +163,7 @@ public class AttendanceServiceImpl implements AttendanceService {
//取绝对值 如果status是负数则变为正数 //取绝对值 如果status是负数则变为正数
.setLateTime(Constants.ONE.equals(status) ? Math.abs(LocalDateTimeUtil.between(dto.getLocalDateTime(), pageVO.getShouldPunchTime(), ChronoUnit.MILLIS)) : 0L) .setLateTime(Constants.ONE.equals(status) ? Math.abs(LocalDateTimeUtil.between(dto.getLocalDateTime(), pageVO.getShouldPunchTime(), ChronoUnit.MILLIS)) : 0L)
.setLeaveEarlyTime(Constants.TWO.equals(status) ? Math.abs(LocalDateTimeUtil.between(dto.getLocalDateTime(), pageVO.getShouldPunchTime(), ChronoUnit.MILLIS)) : 0L) .setLeaveEarlyTime(Constants.TWO.equals(status) ? Math.abs(LocalDateTimeUtil.between(dto.getLocalDateTime(), pageVO.getShouldPunchTime(), ChronoUnit.MILLIS)) : 0L)
.setWorkOvertimeTime(Constants.ZERO.equals(status) && Constants.ONE.equals(pageVO.getPunchType()) ? Math.abs(LocalDateTimeUtil.between(dto.getLocalDateTime(), pageVO.getShouldPunchTime(), ChronoUnit.MILLIS)) : 0L)
.setRemark(dto.getRemark()) .setRemark(dto.getRemark())
.setImage(dto.getImage()) .setImage(dto.getImage())
.setPunchAddress(dto.getPunchAddress()); .setPunchAddress(dto.getPunchAddress());
@ -214,10 +215,17 @@ public class AttendanceServiceImpl implements AttendanceService {
Boolean flag = stringRedisTemplate.hasKey(key); Boolean flag = stringRedisTemplate.hasKey(key);
// 缓存不存在 // 缓存不存在
if (Boolean.FALSE.equals(flag)) { if (Boolean.FALSE.equals(flag)) {
String url = "https://cdn.jsdelivr.net/gh/NateScarlet/holiday-cn@master/" + year + ".json"; String url = "https://timor.tech/api/holiday/year/" + year;
String json = HttpUtil.get(url, 0); String json = HttpUtil.get(url, 3000);
Map<String, String> map = new HashMap<>();
JSONObject jsonObject = JSONUtil.parseObj(json); JSONObject jsonObject = JSONUtil.parseObj(json);
Map<String, String> map = jsonObject.getBeanList("days", HolidayVO.class).stream().collect(Collectors.toMap(HolidayVO::getDate, HolidayVO::getIsOffDay)); Object o = jsonObject.get("holiday");
//将o转为json对象并且循环获取对象中所有的属性
JSONObject data = JSONUtil.parseObj(o);
data.forEach((k, v) -> {
JSONObject item = JSONUtil.parseObj(v);
map.put(item.get("date").toString(), item.get("holiday").toString());
});
stringRedisTemplate.opsForHash().putAll(key, map); stringRedisTemplate.opsForHash().putAll(key, map);
// -- 删除去年的 // -- 删除去年的
String lastKey = "holiday_" + (Integer.parseInt(year) - 1); String lastKey = "holiday_" + (Integer.parseInt(year) - 1);
@ -753,9 +761,6 @@ public class AttendanceServiceImpl implements AttendanceService {
@Override @Override
public void exportAttendanceExcel(HttpServletResponse response, ExportAttendanceExcelDTO dto) { public void exportAttendanceExcel(HttpServletResponse response, ExportAttendanceExcelDTO dto) {
// 导出 Excel
// ExcelUtils.write(response, "考勤组人员.xls", "数据", AttendanceGroupUserRespVO.class,
// BeanUtils.toBean(list, AttendanceGroupUserRespVO.class));
} }
/** /**

View File

@ -234,6 +234,7 @@ public class AttendanceFixedServiceImpl implements AttendanceFixedService, Punch
} }
vo.setAttendanceGroupShiftId(attendanceFixedDO.getAttendanceGroupShiftId()); vo.setAttendanceGroupShiftId(attendanceFixedDO.getAttendanceGroupShiftId());
attendanceService.calculatePunch(dto, vo); attendanceService.calculatePunch(dto, vo);
vo.setAttendanceGroupId(activationGroup.getId());
return vo; return vo;
} }

View File

@ -21,6 +21,7 @@ import cn.iocoder.yudao.module.system.dal.mysql.attendance.groupshiftitem.Attend
import cn.iocoder.yudao.module.system.dal.mysql.attendance.punchrecord.AttendancePunchRecordMapper; import cn.iocoder.yudao.module.system.dal.mysql.attendance.punchrecord.AttendancePunchRecordMapper;
import cn.iocoder.yudao.module.system.dal.mysql.attendance.scheduling.AttendanceSchedulingMapper; import cn.iocoder.yudao.module.system.dal.mysql.attendance.scheduling.AttendanceSchedulingMapper;
import cn.iocoder.yudao.module.system.service.attendance.group.AttendanceGroupService; import cn.iocoder.yudao.module.system.service.attendance.group.AttendanceGroupService;
import cn.iocoder.yudao.module.system.service.attendance.punch.dto.AttendanceOnTheDayDTO;
import cn.iocoder.yudao.module.system.service.attendance.punchrecord.AttendancePunchRecordService; import cn.iocoder.yudao.module.system.service.attendance.punchrecord.AttendancePunchRecordService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
@ -248,7 +249,10 @@ public class AttendanceGroupShiftServiceImpl implements AttendanceGroupShiftServ
// -- 删除当前考勤组预留的考勤记录 // -- 删除当前考勤组预留的考勤记录
attendancePunchRecordMapper.delete(new LambdaQueryWrapper<AttendancePunchRecordDO>() attendancePunchRecordMapper.delete(new LambdaQueryWrapper<AttendancePunchRecordDO>()
.in(AttendancePunchRecordDO::getAttendanceGroupId, groupIds) .in(AttendancePunchRecordDO::getAttendanceGroupId, groupIds)
.eq(AttendancePunchRecordDO::getNextDayFlag, Constants.TRUE)); .and(a -> a.eq(AttendancePunchRecordDO::getNextDayFlag, Constants.TRUE)
.or()
.eq(AttendancePunchRecordDO::getStatus, AttendanceOnTheDayDTO.PUNCH_STATUS_UN_PUNCH))
);
// -- 重新计算 - 插入到redis 和数据中 // -- 重新计算 - 插入到redis 和数据中
attendancePunchRecordService.defaultPersistence(groupIds, LocalDateTime.now()); attendancePunchRecordService.defaultPersistence(groupIds, LocalDateTime.now());
} }

View File

@ -12,6 +12,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupuser.Attend
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.punchrecord.AttendancePunchRecordDO; import cn.iocoder.yudao.module.system.dal.dataobject.attendance.punchrecord.AttendancePunchRecordDO;
import cn.iocoder.yudao.module.system.dal.mysql.attendance.groupuser.AttendanceGroupUserMapper; import cn.iocoder.yudao.module.system.dal.mysql.attendance.groupuser.AttendanceGroupUserMapper;
import cn.iocoder.yudao.module.system.dal.mysql.attendance.punchrecord.AttendancePunchRecordMapper; import cn.iocoder.yudao.module.system.dal.mysql.attendance.punchrecord.AttendancePunchRecordMapper;
import cn.iocoder.yudao.module.system.service.attendance.punch.dto.AttendanceOnTheDayDTO;
import cn.iocoder.yudao.module.system.service.attendance.punchrecord.AttendancePunchRecordService; import cn.iocoder.yudao.module.system.service.attendance.punchrecord.AttendancePunchRecordService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate;
@ -130,7 +131,10 @@ public class AttendanceGroupUserServiceImpl implements AttendanceGroupUserServic
attendancePunchRecordMapper.delete(new LambdaQueryWrapper<AttendancePunchRecordDO>() attendancePunchRecordMapper.delete(new LambdaQueryWrapper<AttendancePunchRecordDO>()
.eq(AttendancePunchRecordDO::getAttendanceGroupId, vo.getAttendanceGroupId()) .eq(AttendancePunchRecordDO::getAttendanceGroupId, vo.getAttendanceGroupId())
.in(AttendancePunchRecordDO::getUserId, vo.getDelUserIds()) .in(AttendancePunchRecordDO::getUserId, vo.getDelUserIds())
.eq(AttendancePunchRecordDO::getNextDayFlag, Constants.TRUE)); .and(a -> a.eq(AttendancePunchRecordDO::getNextDayFlag, Constants.TRUE)
.or()
.eq(AttendancePunchRecordDO::getStatus, AttendanceOnTheDayDTO.PUNCH_STATUS_UN_PUNCH))
);
} }
if (CollectionUtil.isNotEmpty(vo.getSaveUserIds())) { if (CollectionUtil.isNotEmpty(vo.getSaveUserIds())) {
attendancePunchRecordService.defaultPersistence(vo.getAttendanceGroupId(), vo.getSaveUserIds(), LocalDateTime.now()); attendancePunchRecordService.defaultPersistence(vo.getAttendanceGroupId(), vo.getSaveUserIds(), LocalDateTime.now());

View File

@ -68,6 +68,7 @@ public interface AttendancePunchRecordService {
/** /**
* 预设考勤 * 预设考勤
*
* @param groupId * @param groupId
* @param userIds * @param userIds
* @param localDateTime * @param localDateTime
@ -96,4 +97,18 @@ public interface AttendancePunchRecordService {
*/ */
void defaultPersistence(Map<Long, Long> map, Map<Long, AttendanceGroupDO> groupMap, Map<Long, List<Long>> groupUserMap, void defaultPersistence(Map<Long, Long> map, Map<Long, AttendanceGroupDO> groupMap, Map<Long, List<Long>> groupUserMap,
Map<Long, List<AttendanceGroupShiftItemDO>> itemMaps, String time, LocalDateTime localDateTime); Map<Long, List<AttendanceGroupShiftItemDO>> itemMaps, String time, LocalDateTime localDateTime);
/**
* 获取未提醒列表 获取当天的未打卡并且未提醒记录
*
* @return
*/
List<AttendancePunchRecordDO> getNotReminded(LocalDateTime localDateTime);
/**
* 批量更新
*
* @param editList
*/
void batchUpdate(List<AttendancePunchRecordDO> editList);
} }

View File

@ -153,6 +153,7 @@ public class AttendancePunchRecordServiceImpl implements AttendancePunchRecordSe
} }
this.defaultPersistence(attendanceGroupDOS, attendanceGroupUserDOS, localDateTime); this.defaultPersistence(attendanceGroupDOS, attendanceGroupUserDOS, localDateTime);
} }
@Override @Override
public void defaultPersistence(List<AttendanceGroupDO> attendanceGroupDOS, List<AttendanceGroupUserDO> attendanceGroupUserDOS, LocalDateTime localDateTime) { public void defaultPersistence(List<AttendanceGroupDO> attendanceGroupDOS, List<AttendanceGroupUserDO> attendanceGroupUserDOS, LocalDateTime localDateTime) {
// 获取所有考勤组 // 获取所有考勤组
@ -231,6 +232,20 @@ public class AttendancePunchRecordServiceImpl implements AttendancePunchRecordSe
this.saveBatch(attendancePunchRecordDOList); this.saveBatch(attendancePunchRecordDOList);
} }
@Override
public List<AttendancePunchRecordDO> getNotReminded(LocalDateTime localDateTime) {
String targetDayStr = localDateTime.format(Constants.REPO_DATE_FORMAT);
return punchRecordMapper.selectList(new LambdaQueryWrapper<AttendancePunchRecordDO>()
.eq(AttendancePunchRecordDO::getDayTime, targetDayStr)
.eq(AttendancePunchRecordDO::getStatus, AttendanceOnTheDayDTO.PUNCH_STATUS_UN_PUNCH)
.eq(AttendancePunchRecordDO::getRemindFlag, Constants.FALSE));
}
@Override
public void batchUpdate(List<AttendancePunchRecordDO> editList) {
punchRecordMapper.updateBatch(editList);
}
private Map<Long, Long> getAttendanceGroupShiftIdGroupByGroup(List<AttendanceGroupDO> attendanceGroupDOS, LocalDateTime localDateTime) { private Map<Long, Long> getAttendanceGroupShiftIdGroupByGroup(List<AttendanceGroupDO> attendanceGroupDOS, LocalDateTime localDateTime) {
Map<Long, Long> map = new HashMap<>(); Map<Long, Long> map = new HashMap<>();
List<AttendanceGroupDO> fixedList = attendanceGroupDOS.stream().filter(a -> a.getType().equals(1)).collect(Collectors.toList()); List<AttendanceGroupDO> fixedList = attendanceGroupDOS.stream().filter(a -> a.getType().equals(1)).collect(Collectors.toList());

View File

@ -229,6 +229,7 @@ public class AttendanceSchedulingServiceImpl implements AttendanceSchedulingServ
} }
vo.setAttendanceGroupShiftId(attendanceSchedulingDO.getAttendanceGroupShiftId()); vo.setAttendanceGroupShiftId(attendanceSchedulingDO.getAttendanceGroupShiftId());
attendanceService.calculatePunch(dto, vo); attendanceService.calculatePunch(dto, vo);
vo.setAttendanceGroupId(activationGroup.getId());
return vo; return vo;
} }

View File

@ -111,10 +111,9 @@ public class AttendanceMachineServiceImpl implements AttendanceMachineService {
@Override @Override
public void updateAttendanceMachineStatus(String deviceNo, Integer status, String dateTime) { public void updateAttendanceMachineStatus(String deviceNo, Integer status, String dateTime) {
AttendanceMachineDO updateDO = new AttendanceMachineDO(); AttendanceMachineDO updateDO = new AttendanceMachineDO();
updateDO.setStatus(status); updateDO.setStatus(status);
updateDO.setUpdater(getLoginUserId().toString()); // updateDO.setUpdater(getLoginUserId().toString());
if (status == 1) { if (status == 1) {
updateDO.setRequestTime(LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); updateDO.setRequestTime(LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
} }
@ -130,7 +129,7 @@ public class AttendanceMachineServiceImpl implements AttendanceMachineService {
if (attendanceMachineDO == null) { if (attendanceMachineDO == null) {
throw exception(ATTENDANCE_MACHINE_NOT_EXISTS); throw exception(ATTENDANCE_MACHINE_NOT_EXISTS);
}else { } else {
if (!passwordEncoder.matches(updateReqVO.getOldPassword(), attendanceMachineDO.getPassword())) { if (!passwordEncoder.matches(updateReqVO.getOldPassword(), attendanceMachineDO.getPassword())) {
@ -221,7 +220,7 @@ public class AttendanceMachineServiceImpl implements AttendanceMachineService {
deviceNo = new ArrayList<>(); deviceNo = new ArrayList<>();
deviceNo.add(addReqVO.getDeviceNo()); deviceNo.add(addReqVO.getDeviceNo());
}else { } else {
if (!deviceNo.contains(addReqVO.getDeviceNo())) { if (!deviceNo.contains(addReqVO.getDeviceNo())) {
@ -232,7 +231,7 @@ public class AttendanceMachineServiceImpl implements AttendanceMachineService {
//设备 用户绑定设备 //设备 用户绑定设备
data.setAttendanceMachineNos(deviceNo); data.setAttendanceMachineNos(deviceNo);
}); });
}else if (addReqVO.getMethod() == 1) { } else if (addReqVO.getMethod() == 1) {
usersExtDO.forEach(data -> { usersExtDO.forEach(data -> {

View File

@ -35,6 +35,7 @@
SELECT SELECT
a.id, a.id,
a.util, a.util,
a.assets_no,
a.item_json, a.item_json,
a.name, a.name,
a.amount, a.amount,
@ -57,6 +58,9 @@
<if test="reqVO.assetsNo != null and reqVO.assetsNo != ''"> <if test="reqVO.assetsNo != null and reqVO.assetsNo != ''">
and a.assets_no like concat('%', #{reqVO.keyWord}, '%') and a.assets_no like concat('%', #{reqVO.keyWord}, '%')
</if> </if>
<if test="reqVO.typeId != null">
and a.type_id = #{reqVO.typeId}
</if>
<if test="reqVO.keyWord != null and reqVO.keyWord != ''"> <if test="reqVO.keyWord != null and reqVO.keyWord != ''">
and ( and (
a.name like concat('%', #{reqVO.keyWord}, '%') a.name like concat('%', #{reqVO.keyWord}, '%')

View File

@ -14,6 +14,7 @@
SELECT a.id, SELECT a.id,
a.assets_id, a.assets_id,
b.name as assetsName, b.name as assetsName,
b.assets_no as assetsNo,
a.use_user_id, a.use_user_id,
c.nickname as useUserName, c.nickname as useUserName,
a.use_dept_id, a.use_dept_id,
@ -36,6 +37,7 @@
left join system_users as d on a.principal_user_id = d.id left join system_users as d on a.principal_user_id = d.id
left join system_dept as e on a.use_dept_id = e.id left join system_dept as e on a.use_dept_id = e.id
<where> <where>
a.deleted = 0
<if test="vo.useUserId != null"> <if test="vo.useUserId != null">
and a.use_user_id = #{vo.useUserId} and a.use_user_id = #{vo.useUserId}
</if> </if>
@ -65,7 +67,7 @@
and a.create_time &lt;= #{vo.createTime[1]} and a.create_time &lt;= #{vo.createTime[1]}
</if> </if>
</if> </if>
order by a.create_time desc
</where> </where>
order by a.create_time desc
</select> </select>
</mapper> </mapper>

View File

@ -63,7 +63,7 @@ public class FactoryInfoSaveReqVO {
private BigDecimal lat; private BigDecimal lat;
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "状态不能为空") // @NotNull(message = "状态不能为空")
private Integer status; private Integer status;
@Schema(description = "负责人编号", example = "126") @Schema(description = "负责人编号", example = "126")