考勤机
This commit is contained in:
		| @ -324,9 +324,9 @@ dxf2GeoJson: | ||||
|   file-name: main.exe | ||||
| ys7: | ||||
|   app-key: 3acf9f1a43dc4209841e0893003db0a2 | ||||
|   app-secret: 4bbf3e9394f55d3af6e3af27b2d3db36 | ||||
|   app-secret: 09e29c70ae1161fbc3ce2030fc09ba2e | ||||
|   job: | ||||
|     capture-enabled: false   # 控制是否启用萤石抓拍任务 | ||||
|     capture-enabled: true   # 控制是否启用萤石抓拍任务 | ||||
| # 斯巴达算法 | ||||
| sparta: | ||||
|   url: http://119.3.204.120:8040 | ||||
|  | ||||
| @ -355,7 +355,7 @@ public class MatMaterialsInventoryServiceImpl extends ServiceImpl<MatMaterialsIn | ||||
|         lqw.eq(ObjectUtils.isNotEmpty(number), MatMaterialsInventory::getNumber, number); | ||||
|         lqw.eq(ObjectUtils.isNotEmpty(outPut), MatMaterialsInventory::getOutPut, outPut); | ||||
|         // 排序 | ||||
|         lqw.orderByDesc(MatMaterialsInventory::getCreateTime); | ||||
|         lqw.orderByAsc(MatMaterialsInventory::getCreateTime); | ||||
|         return lqw; | ||||
|     } | ||||
|  | ||||
|  | ||||
| @ -23,7 +23,7 @@ public class DeviceMessageSender { | ||||
|      * @param face   人脸模板地址(HTTP链接) | ||||
|      * @return 异常信息(无异常则返回null) | ||||
|      */ | ||||
|     public static Exception sendPersonnelInformation(String sn, String userId, String name, String face) { | ||||
|     public Boolean sendPersonnelInformation(String sn, String userId, String name, String face) { | ||||
|         try { | ||||
|             // 生成UUID | ||||
|             String sUuid = DeviceWebSocketServer.generateUUIDWithSixRandomDigits(); | ||||
| @ -45,10 +45,10 @@ public class DeviceMessageSender { | ||||
|  | ||||
|             // 发送请求并等待响应(忽略响应结果,只关注是否成功) | ||||
|             DeviceWebSocketServer.sendRequestAndWaitResponse(sn, sUuid, people); | ||||
|             return null; | ||||
|             return true; | ||||
|         } catch (Exception e) { | ||||
|             log.error("下发人员信息失败,SN: {}, UserID: {}", sn, userId, e); | ||||
|             return e; | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -59,7 +59,7 @@ public class DeviceMessageSender { | ||||
|      * @return 响应结果(包含人员信息) | ||||
|      * @throws Exception 发送或接收过程中的异常 | ||||
|      */ | ||||
|     public static KqjEntity.CommonResponse getAllUsers(String sn) throws Exception { | ||||
|     public KqjEntity.CommonResponse getAllUsers(String sn) throws Exception { | ||||
|         // 生成UUID | ||||
|         String sUuid = DeviceWebSocketServer.generateUUIDWithSixRandomDigits(); | ||||
|  | ||||
| @ -87,7 +87,7 @@ public class DeviceMessageSender { | ||||
|      * @return 响应结果 | ||||
|      * @throws Exception 发送或接收过程中的异常 | ||||
|      */ | ||||
|     public static KqjEntity.CommonResponse deleteUser(String sn, String userId) throws Exception { | ||||
|     public KqjEntity.CommonResponse deleteUser(String sn, String userId) throws Exception { | ||||
|         // 生成UUID | ||||
|         String sUuid = DeviceWebSocketServer.generateUUIDWithSixRandomDigits(); | ||||
|  | ||||
| @ -116,7 +116,7 @@ public class DeviceMessageSender { | ||||
|      * @return 响应结果 | ||||
|      * @throws Exception 发送或接收过程中的异常 | ||||
|      */ | ||||
|     public static KqjEntity.CommonResponse batchDeleteUsers(String sn, String[] userIds) throws Exception { | ||||
|     public KqjEntity.CommonResponse batchDeleteUsers(String sn, String[] userIds) throws Exception { | ||||
|         // 生成UUID | ||||
|         String sUuid = DeviceWebSocketServer.generateUUIDWithSixRandomDigits(); | ||||
|  | ||||
| @ -144,7 +144,7 @@ public class DeviceMessageSender { | ||||
|      * @return 响应结果 | ||||
|      * @throws Exception 发送或接收过程中的异常 | ||||
|      */ | ||||
|     public static KqjEntity.CommonResponse deleteAllUsers(String sn) throws Exception { | ||||
|     public KqjEntity.CommonResponse deleteAllUsers(String sn) throws Exception { | ||||
|         // 生成UUID | ||||
|         String sUuid = DeviceWebSocketServer.generateUUIDWithSixRandomDigits(); | ||||
|  | ||||
|  | ||||
| @ -5,6 +5,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; | ||||
| import jakarta.websocket.*; | ||||
| import jakarta.websocket.server.ServerEndpoint; | ||||
| import lombok.extern.log4j.Log4j2; | ||||
| import org.dromara.common.core.utils.SpringUtils; | ||||
| import org.dromara.project.service.IBusAttendanceMachineService; | ||||
| import org.springframework.stereotype.Component; | ||||
|  | ||||
| import java.io.IOException; | ||||
| @ -17,7 +19,6 @@ import java.util.concurrent.CompletableFuture; | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
| import java.util.concurrent.TimeUnit; | ||||
| import java.util.concurrent.TimeoutException; | ||||
| import java.util.concurrent.atomic.AtomicReference; | ||||
|  | ||||
| /** | ||||
|  * WebSocket服务端(设备连接管理、消息处理) | ||||
| @ -28,6 +29,8 @@ import java.util.concurrent.atomic.AtomicReference; | ||||
| @Log4j2 | ||||
| public class DeviceWebSocketServer { | ||||
|  | ||||
|     private final static IBusAttendanceMachineService attendanceMachineService = SpringUtils.getBean(IBusAttendanceMachineService.class); | ||||
|  | ||||
|     // ------------------------------ 常量定义 ------------------------------ | ||||
|     public static final String DECLARE = "declare";     // 设备注册消息 | ||||
|     public static final String PING = "ping";           // 心跳消息 | ||||
| @ -36,7 +39,7 @@ public class DeviceWebSocketServer { | ||||
|  | ||||
|     // ------------------------------ 全局静态存储 ------------------------------ | ||||
|     // JSON序列化工具(单例) | ||||
|     private static final ObjectMapper objectMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);; | ||||
|     private static final ObjectMapper objectMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); | ||||
|     // 设备连接池:key=设备SN,value=设备信息(含Session) | ||||
|     private static final Map<String, KqjEntity.DeviceInfo> connectedDevices = new ConcurrentHashMap<>(); | ||||
|     // 响应通道:key=UUID,value=响应结果容器 | ||||
| @ -212,7 +215,6 @@ public class DeviceWebSocketServer { | ||||
| //        registerFuture.complete(true); // 标记注册成功 | ||||
| //        log.info("设备注册成功,SN: {},IP: {}:{},会话ID: {}", sn, ip, port, session.getId()); | ||||
| //    } | ||||
|  | ||||
|     private void handleRegisterStage(String message, String cmd) throws Exception { | ||||
|         // 非DECLARE消息直接拒绝 | ||||
|         if (!DECLARE.equals(cmd)) { | ||||
| @ -382,6 +384,11 @@ public class DeviceWebSocketServer { | ||||
|             // TODO: 替换为真实的业务服务调用(如Spring Bean注入后调用) | ||||
|             log.info("【业务服务】设备注册,SN: {}", sn); | ||||
|             // 示例:BusAttendanceMachineService.register(sn); | ||||
|             if (attendanceMachineService != null) { | ||||
|                 attendanceMachineService.insertBySn(sn); | ||||
|             } else { | ||||
|                 log.error("IBusAttendanceMachineService 为空,无法进行设备注册"); | ||||
|             } | ||||
|         } catch (Exception e) { | ||||
|             log.error("【业务服务】设备注册失败,SN: {}", sn, e); | ||||
|         } | ||||
| @ -395,6 +402,11 @@ public class DeviceWebSocketServer { | ||||
|             // TODO: 替换为真实的业务服务调用 | ||||
|             log.info("【业务服务】更新设备状态,SN: {},状态: {}", sn, status); | ||||
|             // 示例:BusAttendanceMachineService.changeStatus(sn, status); | ||||
|             if (attendanceMachineService != null) { | ||||
|                 attendanceMachineService.changeStatus(sn, status); | ||||
|             } else { | ||||
|                 log.error("IBusAttendanceMachineService 为空,无法更新设备状态"); | ||||
|             } | ||||
|         } catch (Exception e) { | ||||
|             log.error("【业务服务】更新设备状态失败,SN: {}", sn, e); | ||||
|         } | ||||
|  | ||||
| @ -0,0 +1,94 @@ | ||||
| package org.dromara.project.controller; | ||||
|  | ||||
| import cn.dev33.satoken.annotation.SaCheckPermission; | ||||
| import jakarta.servlet.http.HttpServletResponse; | ||||
| import jakarta.validation.constraints.NotEmpty; | ||||
| import jakarta.validation.constraints.NotNull; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.dromara.common.core.domain.R; | ||||
| import org.dromara.common.excel.utils.ExcelUtil; | ||||
| import org.dromara.common.idempotent.annotation.RepeatSubmit; | ||||
| import org.dromara.common.log.annotation.Log; | ||||
| import org.dromara.common.log.enums.BusinessType; | ||||
| import org.dromara.common.mybatis.core.page.PageQuery; | ||||
| import org.dromara.common.mybatis.core.page.TableDataInfo; | ||||
| import org.dromara.common.web.core.BaseController; | ||||
| import org.dromara.project.domain.dto.attendancemachine.BusAttendanceMachineQueryReq; | ||||
| import org.dromara.project.domain.dto.attendancemachine.BusAttendanceMachineUpdateReq; | ||||
| import org.dromara.project.domain.vo.BusAttendanceMachineVo; | ||||
| import org.dromara.project.service.IBusAttendanceMachineService; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.*; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 考勤机 | ||||
|  * | ||||
|  * @author lilemy | ||||
|  * @date 2025-10-15 | ||||
|  */ | ||||
| @Validated | ||||
| @RequiredArgsConstructor | ||||
| @RestController | ||||
| @RequestMapping("/project/attendanceMachine") | ||||
| public class BusAttendanceMachineController extends BaseController { | ||||
|  | ||||
|     private final IBusAttendanceMachineService busAttendanceMachineService; | ||||
|  | ||||
|     /** | ||||
|      * 查询考勤机列表 | ||||
|      */ | ||||
|     @SaCheckPermission("project:attendanceMachine:list") | ||||
|     @GetMapping("/list") | ||||
|     public TableDataInfo<BusAttendanceMachineVo> list(BusAttendanceMachineQueryReq req, PageQuery pageQuery) { | ||||
|         return busAttendanceMachineService.queryPageList(req, pageQuery); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 导出考勤机列表 | ||||
|      */ | ||||
|     @SaCheckPermission("project:attendanceMachine:export") | ||||
|     @Log(title = "考勤机", businessType = BusinessType.EXPORT) | ||||
|     @PostMapping("/export") | ||||
|     public void export(BusAttendanceMachineQueryReq req, HttpServletResponse response) { | ||||
|         List<BusAttendanceMachineVo> list = busAttendanceMachineService.queryList(req); | ||||
|         ExcelUtil.exportExcel(list, "考勤机", BusAttendanceMachineVo.class, response); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取考勤机详细信息 | ||||
|      * | ||||
|      * @param id 主键 | ||||
|      */ | ||||
|     @SaCheckPermission("project:attendanceMachine:query") | ||||
|     @GetMapping("/{id}") | ||||
|     public R<BusAttendanceMachineVo> getInfo(@NotNull(message = "主键不能为空") | ||||
|                                              @PathVariable Long id) { | ||||
|         return R.ok(busAttendanceMachineService.queryById(id)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 修改考勤机 | ||||
|      */ | ||||
|     @SaCheckPermission("project:attendanceMachine:edit") | ||||
|     @Log(title = "考勤机", businessType = BusinessType.UPDATE) | ||||
|     @RepeatSubmit() | ||||
|     @PutMapping() | ||||
|     public R<Void> edit(@Validated @RequestBody BusAttendanceMachineUpdateReq req) { | ||||
|         return toAjax(busAttendanceMachineService.updateByBo(req)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 删除考勤机 | ||||
|      * | ||||
|      * @param ids 主键串 | ||||
|      */ | ||||
|     @SaCheckPermission("project:attendanceMachine:remove") | ||||
|     @Log(title = "考勤机", businessType = BusinessType.DELETE) | ||||
|     @DeleteMapping("/{ids}") | ||||
|     public R<Void> remove(@NotEmpty(message = "主键不能为空") | ||||
|                           @PathVariable Long[] ids) { | ||||
|         return toAjax(busAttendanceMachineService.deleteWithValidByIds(List.of(ids), true)); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,65 @@ | ||||
| package org.dromara.project.controller; | ||||
|  | ||||
| import cn.dev33.satoken.annotation.SaCheckPermission; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.dromara.common.core.domain.R; | ||||
| import org.dromara.common.idempotent.annotation.RepeatSubmit; | ||||
| import org.dromara.common.log.annotation.Log; | ||||
| import org.dromara.common.log.enums.BusinessType; | ||||
| import org.dromara.common.web.core.BaseController; | ||||
| import org.dromara.project.domain.dto.attendancemachineuser.BusAttendanceMachineSendInfoUserReq; | ||||
| import org.dromara.project.domain.dto.attendancemachineuser.BusAttendanceMachineUserQueryReq; | ||||
| import org.dromara.project.domain.dto.attendancemachineuser.BusAttendanceMachineUserRemoveReq; | ||||
| import org.dromara.project.domain.vo.BusAttendanceMachineUserVo; | ||||
| import org.dromara.project.service.IBusAttendanceMachineUserService; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.*; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 考勤机用户 | ||||
|  * | ||||
|  * @author lilemy | ||||
|  * @date 2025-10-15 | ||||
|  */ | ||||
| @Validated | ||||
| @RequiredArgsConstructor | ||||
| @RestController | ||||
| @RequestMapping("/project/attendanceMachineUser") | ||||
| public class BusAttendanceMachineUserController extends BaseController { | ||||
|  | ||||
|     private final IBusAttendanceMachineUserService busAttendanceMachineUserService; | ||||
|  | ||||
|     /** | ||||
|      * 查询考勤机用户列表 | ||||
|      */ | ||||
|     @SaCheckPermission("project:attendanceMachineUser:list") | ||||
|     @GetMapping("/list") | ||||
|     public R<List<BusAttendanceMachineUserVo>> list(BusAttendanceMachineUserQueryReq req) { | ||||
|         return R.ok(busAttendanceMachineUserService.queryList(req)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 下发用户到考勤机中 | ||||
|      */ | ||||
|     @SaCheckPermission("project:attendanceMachineUser:add") | ||||
|     @Log(title = "考勤机用户", businessType = BusinessType.INSERT) | ||||
|     @RepeatSubmit() | ||||
|     @PostMapping("/send") | ||||
|     public R<String> sendPersonInfo(@Validated @RequestBody BusAttendanceMachineSendInfoUserReq req) { | ||||
|         return R.ok(busAttendanceMachineUserService.sendPersonInfo(req)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 删除考勤机用户 | ||||
|      */ | ||||
|     @SaCheckPermission("project:attendanceMachineUser:remove") | ||||
|     @Log(title = "考勤机用户", businessType = BusinessType.DELETE) | ||||
|     @RepeatSubmit() | ||||
|     @DeleteMapping() | ||||
|     public R<Void> remove(@Validated @RequestBody BusAttendanceMachineUserRemoveReq req) { | ||||
|         return toAjax(busAttendanceMachineUserService.remove(req)); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,65 @@ | ||||
| package org.dromara.project.domain; | ||||
|  | ||||
| import com.baomidou.mybatisplus.annotation.TableId; | ||||
| import com.baomidou.mybatisplus.annotation.TableName; | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
| import java.util.Date; | ||||
|  | ||||
| /** | ||||
|  * 考勤机对象 bus_attendance_machine | ||||
|  * | ||||
|  * @author lilemy | ||||
|  * @date 2025-10-15 | ||||
|  */ | ||||
| @Data | ||||
| @TableName("bus_attendance_machine") | ||||
| public class BusAttendanceMachine implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 主键ID | ||||
|      */ | ||||
|     @TableId(value = "id") | ||||
|     private Long id; | ||||
|  | ||||
|     /** | ||||
|      * 项目ID | ||||
|      */ | ||||
|     private Long projectId; | ||||
|  | ||||
|     /** | ||||
|      * 设备sn | ||||
|      */ | ||||
|     private String sn; | ||||
|  | ||||
|     /** | ||||
|      * 是否在线(0-no 1-yes) | ||||
|      */ | ||||
|     private String status; | ||||
|  | ||||
|     /** | ||||
|      * 班组id,多个逗号分隔 | ||||
|      */ | ||||
|     private String teams; | ||||
|  | ||||
|     /** | ||||
|      * 备注 | ||||
|      */ | ||||
|     private String remark; | ||||
|  | ||||
|     /** | ||||
|      * 创建时间 | ||||
|      */ | ||||
|     private Date createTime; | ||||
|  | ||||
|     /** | ||||
|      * 更新时间 | ||||
|      */ | ||||
|     private Date updateTime; | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,56 @@ | ||||
| package org.dromara.project.domain; | ||||
|  | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
| import java.util.Date; | ||||
|  | ||||
| /** | ||||
|  * 考勤机用户对象 bus_attendance_machine_user | ||||
|  * | ||||
|  * @author lilemy | ||||
|  * @date 2025-10-15 | ||||
|  */ | ||||
| @Data | ||||
| public class BusAttendanceMachineUser implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 主键ID | ||||
|      */ | ||||
|     private Long id; | ||||
|  | ||||
|     /** | ||||
|      * 考勤机主键ID | ||||
|      */ | ||||
|     private Long machineId; | ||||
|  | ||||
|     /** | ||||
|      * 班组ID | ||||
|      */ | ||||
|     private Long teamId; | ||||
|  | ||||
|     /** | ||||
|      * 用户ID | ||||
|      */ | ||||
|     private Long userId; | ||||
|  | ||||
|     /** | ||||
|      * 标识(是否下发) | ||||
|      */ | ||||
|     private Integer identifying; | ||||
|  | ||||
|     /** | ||||
|      * 创建时间 | ||||
|      */ | ||||
|     private Date createTime; | ||||
|  | ||||
|     /** | ||||
|      * 更新时间 | ||||
|      */ | ||||
|     private Date updateTime; | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,37 @@ | ||||
| package org.dromara.project.domain.dto.attendancemachine; | ||||
|  | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * @author lilemy | ||||
|  * @date 2025-10-15 16:18 | ||||
|  */ | ||||
| @Data | ||||
| public class BusAttendanceMachineQueryReq implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 6296359812022907365L; | ||||
|  | ||||
|     /** | ||||
|      * 项目ID | ||||
|      */ | ||||
|     private Long projectId; | ||||
|  | ||||
|     /** | ||||
|      * 设备sn | ||||
|      */ | ||||
|     private String sn; | ||||
|  | ||||
|     /** | ||||
|      * 是否在线(0-no 1-yes) | ||||
|      */ | ||||
|     private String status; | ||||
|  | ||||
|     /** | ||||
|      * 班组id,多个逗号分隔 | ||||
|      */ | ||||
|     private String teams; | ||||
| } | ||||
| @ -0,0 +1,40 @@ | ||||
| package org.dromara.project.domain.dto.attendancemachine; | ||||
|  | ||||
| import jakarta.validation.constraints.NotNull; | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * @author lilemy | ||||
|  * @date 2025-10-15 16:15 | ||||
|  */ | ||||
| @Data | ||||
| public class BusAttendanceMachineUpdateReq implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 4764015594443520162L; | ||||
|  | ||||
|     /** | ||||
|      * 主键ID | ||||
|      */ | ||||
|     @NotNull(message = "主键ID不能为空") | ||||
|     private Long id; | ||||
|  | ||||
|     /** | ||||
|      * 项目ID | ||||
|      */ | ||||
|     @NotNull(message = "项目ID不能为空") | ||||
|     private Long projectId; | ||||
|  | ||||
|     /** | ||||
|      * 班组id,多个逗号分隔 | ||||
|      */ | ||||
|     private String teams; | ||||
|  | ||||
|     /** | ||||
|      * 备注 | ||||
|      */ | ||||
|     private String remark; | ||||
| } | ||||
| @ -0,0 +1,32 @@ | ||||
| package org.dromara.project.domain.dto.attendancemachineuser; | ||||
|  | ||||
| import jakarta.validation.constraints.NotNull; | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * @author lilemy | ||||
|  * @date 2025-10-15 17:43 | ||||
|  */ | ||||
| @Data | ||||
| public class BusAttendanceMachineSendInfoUserReq implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = -6517799483848691652L; | ||||
|  | ||||
|     /** | ||||
|      * 考勤机主键ID | ||||
|      */ | ||||
|     @NotNull(message = "考勤机不能为空") | ||||
|     private Long machineId; | ||||
|  | ||||
|     /** | ||||
|      * 用户ID列表 | ||||
|      */ | ||||
|     @NotNull(message = "用户列表不能为空") | ||||
|     private List<Long> userIds; | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,40 @@ | ||||
| package org.dromara.project.domain.dto.attendancemachineuser; | ||||
|  | ||||
| import jakarta.validation.constraints.NotNull; | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * @author lilemy | ||||
|  * @date 2025-10-15 19:22 | ||||
|  */ | ||||
| @Data | ||||
| public class BusAttendanceMachineUserQueryReq implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = -1629819732452840391L; | ||||
|  | ||||
|     /** | ||||
|      * 考勤机主键ID | ||||
|      */ | ||||
|     @NotNull(message = "考勤机不能为空") | ||||
|     private Long machineId; | ||||
|  | ||||
|     /** | ||||
|      * 班组ID | ||||
|      */ | ||||
|     @NotNull(message = "班组不能为空") | ||||
|     private Long teamId; | ||||
|  | ||||
|     /** | ||||
|      * 用户名称 | ||||
|      */ | ||||
|     private String userName; | ||||
|  | ||||
|     /** | ||||
|      * 标识(是否下发) | ||||
|      */ | ||||
|     private Integer identifying; | ||||
| } | ||||
| @ -0,0 +1,31 @@ | ||||
| package org.dromara.project.domain.dto.attendancemachineuser; | ||||
|  | ||||
| import jakarta.validation.constraints.NotNull; | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * @author lilemy | ||||
|  * @date 2025-10-15 19:56 | ||||
|  */ | ||||
| @Data | ||||
| public class BusAttendanceMachineUserRemoveReq implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = -8880884070612972760L; | ||||
|  | ||||
|     /** | ||||
|      * 考勤机主键ID | ||||
|      */ | ||||
|     @NotNull(message = "考勤机不能为空") | ||||
|     private Long machineId; | ||||
|  | ||||
|     /** | ||||
|      * 用户ID列表 | ||||
|      */ | ||||
|     @NotNull(message = "用户列表不能为空") | ||||
|     private List<Long> userIds; | ||||
| } | ||||
| @ -0,0 +1,46 @@ | ||||
| package org.dromara.project.domain.vo; | ||||
|  | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * 考勤机用户视图对象 bus_attendance_machine_user | ||||
|  * | ||||
|  * @author lilemy | ||||
|  * @date 2025-10-15 | ||||
|  */ | ||||
| @Data | ||||
| public class BusAttendanceMachineUserVo implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 考勤机主键ID | ||||
|      */ | ||||
|     private Long machineId; | ||||
|  | ||||
|     /** | ||||
|      * 班组ID | ||||
|      */ | ||||
|     private Long teamId; | ||||
|  | ||||
|     /** | ||||
|      * 用户ID | ||||
|      */ | ||||
|     private Long userId; | ||||
|  | ||||
|     /** | ||||
|      * 用户名称 | ||||
|      */ | ||||
|     private String userName; | ||||
|  | ||||
|     /** | ||||
|      * 标识(是否下发) | ||||
|      */ | ||||
|     private Integer identifying; | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,87 @@ | ||||
| package org.dromara.project.domain.vo; | ||||
|  | ||||
| import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; | ||||
| import com.alibaba.excel.annotation.ExcelProperty; | ||||
| import io.github.linpeilie.annotations.AutoMapper; | ||||
| import lombok.Data; | ||||
| import org.dromara.common.excel.annotation.ExcelDictFormat; | ||||
| import org.dromara.common.excel.convert.ExcelDictConvert; | ||||
| import org.dromara.common.translation.annotation.Translation; | ||||
| import org.dromara.common.translation.constant.TransConstant; | ||||
| import org.dromara.project.domain.BusAttendanceMachine; | ||||
| import org.dromara.project.domain.vo.projectteam.BusProjectTeamVo; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
| import java.util.Date; | ||||
| import java.util.List; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * 考勤机视图对象 bus_attendance_machine | ||||
|  * | ||||
|  * @author lilemy | ||||
|  * @date 2025-10-15 | ||||
|  */ | ||||
| @Data | ||||
| @ExcelIgnoreUnannotated | ||||
| @AutoMapper(target = BusAttendanceMachine.class) | ||||
| public class BusAttendanceMachineVo implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 主键ID | ||||
|      */ | ||||
|     @ExcelProperty(value = "主键ID") | ||||
|     private Long id; | ||||
|  | ||||
|     /** | ||||
|      * 项目ID | ||||
|      */ | ||||
|     @ExcelProperty(value = "项目ID") | ||||
|     private Long projectId; | ||||
|  | ||||
|     /** | ||||
|      * 项目名称 | ||||
|      */ | ||||
|     @Translation(type = TransConstant.PROJECT_ID_TO_NAME, mapper = "projectId") | ||||
|     private String projectName; | ||||
|  | ||||
|     /** | ||||
|      * 设备sn | ||||
|      */ | ||||
|     @ExcelProperty(value = "设备sn") | ||||
|     private String sn; | ||||
|  | ||||
|     /** | ||||
|      * 是否在线(0-no 1-yes) | ||||
|      */ | ||||
|     @ExcelProperty(value = "是否在线", converter = ExcelDictConvert.class) | ||||
|     @ExcelDictFormat(readConverterExp = "0=-no,1=-yes") | ||||
|     private String status; | ||||
|  | ||||
|     /** | ||||
|      * 班组id,多个逗号分隔 | ||||
|      */ | ||||
|     @ExcelProperty(value = "班组id,多个逗号分隔") | ||||
|     private String teams; | ||||
|  | ||||
|     /** | ||||
|      * 班组列表 | ||||
|      */ | ||||
|     private List<BusProjectTeamVo> teamsList; | ||||
|  | ||||
|     /** | ||||
|      * 备注 | ||||
|      */ | ||||
|     @ExcelProperty(value = "备注") | ||||
|     private String remark; | ||||
|  | ||||
|     /** | ||||
|      * 创建时间 | ||||
|      */ | ||||
|     private Date createTime; | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,15 @@ | ||||
| package org.dromara.project.mapper; | ||||
|  | ||||
| import org.dromara.project.domain.BusAttendanceMachine; | ||||
| import org.dromara.project.domain.vo.BusAttendanceMachineVo; | ||||
| import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; | ||||
|  | ||||
| /** | ||||
|  * 考勤机Mapper接口 | ||||
|  * | ||||
|  * @author lilemy | ||||
|  * @date 2025-10-15 | ||||
|  */ | ||||
| public interface BusAttendanceMachineMapper extends BaseMapperPlus<BusAttendanceMachine, BusAttendanceMachineVo> { | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,78 @@ | ||||
| package org.dromara.project.service; | ||||
|  | ||||
| import com.baomidou.mybatisplus.extension.service.IService; | ||||
| import org.dromara.common.mybatis.core.page.PageQuery; | ||||
| import org.dromara.common.mybatis.core.page.TableDataInfo; | ||||
| import org.dromara.project.domain.BusAttendanceMachine; | ||||
| import org.dromara.project.domain.dto.attendancemachine.BusAttendanceMachineQueryReq; | ||||
| import org.dromara.project.domain.dto.attendancemachine.BusAttendanceMachineUpdateReq; | ||||
| import org.dromara.project.domain.vo.BusAttendanceMachineVo; | ||||
|  | ||||
| import java.util.Collection; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 考勤机Service接口 | ||||
|  * | ||||
|  * @author lilemy | ||||
|  * @date 2025-10-15 | ||||
|  */ | ||||
| public interface IBusAttendanceMachineService extends IService<BusAttendanceMachine> { | ||||
|  | ||||
|     /** | ||||
|      * 查询考勤机 | ||||
|      * | ||||
|      * @param id 主键 | ||||
|      * @return 考勤机 | ||||
|      */ | ||||
|     BusAttendanceMachineVo queryById(Long id); | ||||
|  | ||||
|     /** | ||||
|      * 分页查询考勤机列表 | ||||
|      * | ||||
|      * @param req       查询条件 | ||||
|      * @param pageQuery 分页参数 | ||||
|      * @return 考勤机分页列表 | ||||
|      */ | ||||
|     TableDataInfo<BusAttendanceMachineVo> queryPageList(BusAttendanceMachineQueryReq req, PageQuery pageQuery); | ||||
|  | ||||
|     /** | ||||
|      * 查询符合条件的考勤机列表 | ||||
|      * | ||||
|      * @param req 查询条件 | ||||
|      * @return 考勤机列表 | ||||
|      */ | ||||
|     List<BusAttendanceMachineVo> queryList(BusAttendanceMachineQueryReq req); | ||||
|  | ||||
|     /** | ||||
|      * 根据sn新增考勤机 | ||||
|      * | ||||
|      * @param sn 考勤机sn | ||||
|      */ | ||||
|     void insertBySn(String sn); | ||||
|  | ||||
|     /** | ||||
|      * 修改考勤机 | ||||
|      * | ||||
|      * @param req 考勤机 | ||||
|      * @return 是否修改成功 | ||||
|      */ | ||||
|     Boolean updateByBo(BusAttendanceMachineUpdateReq req); | ||||
|  | ||||
|     /** | ||||
|      * 修改考勤机状态 | ||||
|      * | ||||
|      * @param sn     考勤机sn | ||||
|      * @param status 考勤机状态 | ||||
|      */ | ||||
|     void changeStatus(String sn, String status); | ||||
|  | ||||
|     /** | ||||
|      * 校验并批量删除考勤机信息 | ||||
|      * | ||||
|      * @param ids     待删除的主键集合 | ||||
|      * @param isValid 是否进行有效性校验 | ||||
|      * @return 是否删除成功 | ||||
|      */ | ||||
|     Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid); | ||||
| } | ||||
| @ -0,0 +1,41 @@ | ||||
| package org.dromara.project.service; | ||||
|  | ||||
| import org.dromara.project.domain.dto.attendancemachineuser.BusAttendanceMachineSendInfoUserReq; | ||||
| import org.dromara.project.domain.dto.attendancemachineuser.BusAttendanceMachineUserQueryReq; | ||||
| import org.dromara.project.domain.dto.attendancemachineuser.BusAttendanceMachineUserRemoveReq; | ||||
| import org.dromara.project.domain.vo.BusAttendanceMachineUserVo; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 考勤机用户Service接口 | ||||
|  * | ||||
|  * @author lilemy | ||||
|  * @date 2025-10-15 | ||||
|  */ | ||||
| public interface IBusAttendanceMachineUserService { | ||||
|  | ||||
|     /** | ||||
|      * 查询符合条件的考勤机用户列表 | ||||
|      * | ||||
|      * @param req 查询条件 | ||||
|      * @return 考勤机用户列表 | ||||
|      */ | ||||
|     List<BusAttendanceMachineUserVo> queryList(BusAttendanceMachineUserQueryReq req); | ||||
|  | ||||
|     /** | ||||
|      * 下发用户到考勤机中 | ||||
|      * | ||||
|      * @param req 下发用户参数 | ||||
|      * @return 下发结果 | ||||
|      */ | ||||
|     String sendPersonInfo(BusAttendanceMachineSendInfoUserReq req); | ||||
|  | ||||
|     /** | ||||
|      * 删除考勤机用户 | ||||
|      * | ||||
|      * @param req 删除参数 | ||||
|      * @return 删除结果 | ||||
|      */ | ||||
|     Boolean remove(BusAttendanceMachineUserRemoveReq req); | ||||
| } | ||||
| @ -0,0 +1,266 @@ | ||||
| package org.dromara.project.service.impl; | ||||
|  | ||||
| import cn.hutool.core.collection.CollUtil; | ||||
| import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||||
| import com.baomidou.mybatisplus.core.toolkit.Wrappers; | ||||
| import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||||
| import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | ||||
| import jakarta.annotation.Resource; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.dromara.common.core.constant.HttpStatus; | ||||
| import org.dromara.common.core.exception.ServiceException; | ||||
| import org.dromara.common.core.utils.StringUtils; | ||||
| import org.dromara.common.mybatis.core.page.PageQuery; | ||||
| import org.dromara.common.mybatis.core.page.TableDataInfo; | ||||
| import org.dromara.mobileAttendanceMachine.DeviceMessageSender; | ||||
| import org.dromara.project.domain.BusAttendanceMachine; | ||||
| import org.dromara.project.domain.BusProject; | ||||
| import org.dromara.project.domain.BusProjectTeam; | ||||
| import org.dromara.project.domain.BusProjectTeamMember; | ||||
| import org.dromara.project.domain.dto.attendancemachine.BusAttendanceMachineQueryReq; | ||||
| import org.dromara.project.domain.dto.attendancemachine.BusAttendanceMachineUpdateReq; | ||||
| import org.dromara.project.domain.vo.BusAttendanceMachineVo; | ||||
| import org.dromara.project.domain.vo.projectteam.BusProjectTeamVo; | ||||
| import org.dromara.project.mapper.BusAttendanceMachineMapper; | ||||
| import org.dromara.project.service.IBusAttendanceMachineService; | ||||
| import org.dromara.project.service.IBusProjectService; | ||||
| import org.dromara.project.service.IBusProjectTeamMemberService; | ||||
| import org.dromara.project.service.IBusProjectTeamService; | ||||
| import org.springframework.beans.BeanUtils; | ||||
| import org.springframework.stereotype.Service; | ||||
|  | ||||
| import java.util.Arrays; | ||||
| import java.util.Collection; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.stream.Collectors; | ||||
|  | ||||
| /** | ||||
|  * 考勤机Service业务层处理 | ||||
|  * | ||||
|  * @author lilemy | ||||
|  * @date 2025-10-15 | ||||
|  */ | ||||
| @RequiredArgsConstructor | ||||
| @Service | ||||
| public class BusAttendanceMachineServiceImpl extends ServiceImpl<BusAttendanceMachineMapper, BusAttendanceMachine> | ||||
|     implements IBusAttendanceMachineService { | ||||
|  | ||||
|     @Resource | ||||
|     private IBusProjectService projectService; | ||||
|  | ||||
|     @Resource | ||||
|     private IBusProjectTeamService projectTeamService; | ||||
|  | ||||
|     @Resource | ||||
|     private IBusProjectTeamMemberService projectTeamMemberService; | ||||
|  | ||||
|     @Resource | ||||
|     private DeviceMessageSender deviceMessageSender; | ||||
|  | ||||
|     /** | ||||
|      * 查询考勤机 | ||||
|      * | ||||
|      * @param id 主键 | ||||
|      * @return 考勤机 | ||||
|      */ | ||||
|     @Override | ||||
|     public BusAttendanceMachineVo queryById(Long id) { | ||||
|         return baseMapper.selectVoById(id); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 分页查询考勤机列表 | ||||
|      * | ||||
|      * @param req       查询条件 | ||||
|      * @param pageQuery 分页参数 | ||||
|      * @return 考勤机分页列表 | ||||
|      */ | ||||
|     @Override | ||||
|     public TableDataInfo<BusAttendanceMachineVo> queryPageList(BusAttendanceMachineQueryReq req, PageQuery pageQuery) { | ||||
|         LambdaQueryWrapper<BusAttendanceMachine> lqw = buildQueryWrapper(req); | ||||
|         Page<BusAttendanceMachineVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw); | ||||
|         List<BusAttendanceMachineVo> records = result.getRecords(); | ||||
|         List<Long> teamIds = records.stream() | ||||
|             .map(BusAttendanceMachineVo::getTeams) | ||||
|             .filter(StringUtils::isNotBlank) | ||||
|             .flatMap(team -> Arrays.stream(team.split(","))     // flatMap 展开内部 stream | ||||
|                 .map(Long::parseLong)) | ||||
|             .toList(); | ||||
|         if (CollUtil.isEmpty(teamIds)) { | ||||
|             return TableDataInfo.build(result); | ||||
|         } | ||||
|         List<BusProjectTeam> projectTeams = projectTeamService.listByIds(teamIds); | ||||
|         Map<Long, String> teamMap = projectTeams.stream() | ||||
|             .collect(Collectors.toMap(BusProjectTeam::getId, BusProjectTeam::getTeamName)); | ||||
|         records.forEach(machine -> { | ||||
|             String teams = machine.getTeams(); | ||||
|             if (StringUtils.isNotBlank(teams)) { | ||||
|                 List<Long> t = Arrays.stream(teams.split(",")).map(Long::parseLong).toList(); | ||||
|                 List<BusProjectTeamVo> teamVoList = t.stream().map(teamId -> { | ||||
|                     BusProjectTeamVo vo = new BusProjectTeamVo(); | ||||
|                     vo.setId(teamId); | ||||
|                     vo.setTeamName(teamMap.getOrDefault(teamId, "未命名")); | ||||
|                     return vo; | ||||
|                 }).toList(); | ||||
|                 machine.setTeamsList(teamVoList); | ||||
|             } | ||||
|         }); | ||||
|         result.setRecords(records); | ||||
|         return TableDataInfo.build(result); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 查询符合条件的考勤机列表 | ||||
|      * | ||||
|      * @param req 查询条件 | ||||
|      * @return 考勤机列表 | ||||
|      */ | ||||
|     @Override | ||||
|     public List<BusAttendanceMachineVo> queryList(BusAttendanceMachineQueryReq req) { | ||||
|         LambdaQueryWrapper<BusAttendanceMachine> lqw = buildQueryWrapper(req); | ||||
|         return baseMapper.selectVoList(lqw); | ||||
|     } | ||||
|  | ||||
|     private LambdaQueryWrapper<BusAttendanceMachine> buildQueryWrapper(BusAttendanceMachineQueryReq req) { | ||||
|         LambdaQueryWrapper<BusAttendanceMachine> lqw = Wrappers.lambdaQuery(); | ||||
|         lqw.orderByDesc(BusAttendanceMachine::getId); | ||||
|         lqw.eq(req.getProjectId() != null, BusAttendanceMachine::getProjectId, req.getProjectId()); | ||||
|         lqw.isNull(req.getProjectId() == null, BusAttendanceMachine::getProjectId); | ||||
|         lqw.eq(StringUtils.isNotBlank(req.getSn()), BusAttendanceMachine::getSn, req.getSn()); | ||||
|         lqw.eq(StringUtils.isNotBlank(req.getStatus()), BusAttendanceMachine::getStatus, req.getStatus()); | ||||
|         lqw.like(StringUtils.isNotBlank(req.getTeams()), BusAttendanceMachine::getTeams, req.getTeams()); | ||||
|         return lqw; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 根据sn新增考勤机 | ||||
|      * | ||||
|      * @param sn 考勤机sn | ||||
|      */ | ||||
|     @Override | ||||
|     public void insertBySn(String sn) { | ||||
|         BusAttendanceMachine machine = new BusAttendanceMachine(); | ||||
|         // 判断考勤机是否存在 | ||||
|         BusAttendanceMachine oldMachine = this.lambdaQuery() | ||||
|             .eq(BusAttendanceMachine::getSn, sn) | ||||
|             .one(); | ||||
|         if (oldMachine != null) { | ||||
|             machine.setId(oldMachine.getId()); | ||||
|         } | ||||
|         machine.setSn(sn); | ||||
|         machine.setStatus("1"); | ||||
|         this.saveOrUpdate(machine); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 修改考勤机 | ||||
|      * | ||||
|      * @param req 考勤机 | ||||
|      * @return 是否修改成功 | ||||
|      */ | ||||
|     @Override | ||||
|     public Boolean updateByBo(BusAttendanceMachineUpdateReq req) { | ||||
|         Long id = req.getId(); | ||||
|         BusAttendanceMachine oldMachine = this.getById(id); | ||||
|         if (oldMachine == null) { | ||||
|             throw new ServiceException("考勤机不存在", HttpStatus.NOT_FOUND); | ||||
|         } | ||||
|         BusAttendanceMachine machine = new BusAttendanceMachine(); | ||||
|         BeanUtils.copyProperties(req, machine); | ||||
|         // 判断班组是否属于所选项目 | ||||
|         Long projectId = req.getProjectId(); | ||||
|         BusProject project = projectService.getById(projectId); | ||||
|         if (project == null) { | ||||
|             throw new ServiceException("所选项目不存在", HttpStatus.NOT_FOUND); | ||||
|         } | ||||
|         String teams = req.getTeams(); | ||||
|         if (StringUtils.isBlank(teams) && StringUtils.isBlank(oldMachine.getTeams())) { | ||||
|             throw new ServiceException("请选择班组", HttpStatus.BAD_REQUEST); | ||||
|         } | ||||
|         if (StringUtils.isNotBlank(teams)) { | ||||
|             List<Long> teamIds = Arrays.stream(teams.split(",")) | ||||
|                 .map(Long::parseLong) | ||||
|                 .distinct() | ||||
|                 .toList(); | ||||
|             List<BusProjectTeam> projectTeams = projectTeamService.listByIds(teamIds); | ||||
|             if (projectTeams.size() != teamIds.size()) { | ||||
|                 throw new ServiceException("所选班组不存在", HttpStatus.NOT_FOUND); | ||||
|             } | ||||
|             String oldTeams = oldMachine.getTeams(); | ||||
|             if (StringUtils.isNotBlank(oldTeams)) { | ||||
|                 List<Long> oldTeamIds = Arrays.stream(oldTeams.split(",")) | ||||
|                     .map(Long::parseLong) | ||||
|                     .distinct() | ||||
|                     .toList(); | ||||
|                 // 获取新增的班组ID | ||||
|                 List<Long> added = teamIds.stream() | ||||
|                     .filter(t -> !oldTeamIds.contains(t)) | ||||
|                     .toList(); | ||||
|                 // 获取删除的班组ID | ||||
|                 List<Long> deleted = oldTeamIds.stream() | ||||
|                     .filter(t -> !teamIds.contains(t)) | ||||
|                     .toList(); | ||||
|                 // 删除的班组不为空时,删除考勤机中对应的人数 | ||||
|                 if (CollUtil.isNotEmpty(deleted)) { | ||||
|                     // 获取待删除的班组的所有用户id | ||||
|                     List<Long> userIds = projectTeamMemberService.lambdaQuery() | ||||
|                         .select(BusProjectTeamMember::getMemberId) | ||||
|                         .in(BusProjectTeamMember::getTeamId, deleted) | ||||
|                         .list() | ||||
|                         .stream().map(BusProjectTeamMember::getMemberId).toList(); | ||||
|                     if (CollUtil.isNotEmpty(userIds)) { | ||||
|                         String[] userIdArray = userIds.stream() | ||||
|                             .map(String::valueOf)   // 将 Long 转成 String | ||||
|                             .toArray(String[]::new); | ||||
|                         try { | ||||
|                             deviceMessageSender.batchDeleteUsers(machine.getSn(), userIdArray); | ||||
|                         } catch (Exception e) { | ||||
|                             throw new ServiceException("删除考勤机用户失败", HttpStatus.ERROR); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             projectTeams.forEach(team -> { | ||||
|                 if (!team.getProjectId().equals(projectId)) { | ||||
|                     throw new ServiceException(team.getTeamName() + "不属于所选项目", HttpStatus.BAD_REQUEST); | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|         return this.updateById(machine); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 修改考勤机状态 | ||||
|      * | ||||
|      * @param sn     考勤机sn | ||||
|      * @param status 考勤机状态 | ||||
|      */ | ||||
|     @Override | ||||
|     public void changeStatus(String sn, String status) { | ||||
|         BusAttendanceMachine machine = this.lambdaQuery() | ||||
|             .eq(BusAttendanceMachine::getSn, sn) | ||||
|             .one(); | ||||
|         if (machine == null) { | ||||
|             machine = new BusAttendanceMachine(); | ||||
|             machine.setSn(sn); | ||||
|         } | ||||
|         machine.setStatus(status); | ||||
|         this.saveOrUpdate(machine); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 校验并批量删除考勤机信息 | ||||
|      * | ||||
|      * @param ids     待删除的主键集合 | ||||
|      * @param isValid 是否进行有效性校验 | ||||
|      * @return 是否删除成功 | ||||
|      */ | ||||
|     @Override | ||||
|     public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) { | ||||
|         if (isValid) { | ||||
|             //TODO 做一些业务上的校验,判断是否需要校验 | ||||
|         } | ||||
|         return baseMapper.deleteByIds(ids) > 0; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,163 @@ | ||||
| package org.dromara.project.service.impl; | ||||
|  | ||||
| import cn.hutool.core.collection.CollUtil; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.dromara.common.core.constant.HttpStatus; | ||||
| import org.dromara.common.core.exception.ServiceException; | ||||
| import org.dromara.common.core.utils.StringUtils; | ||||
| import org.dromara.contractor.domain.SubConstructionUser; | ||||
| import org.dromara.contractor.service.ISubConstructionUserService; | ||||
| import org.dromara.mobileAttendanceMachine.DeviceMessageSender; | ||||
| import org.dromara.mobileAttendanceMachine.KqjEntity; | ||||
| import org.dromara.project.domain.BusAttendanceMachine; | ||||
| import org.dromara.project.domain.dto.attendancemachineuser.BusAttendanceMachineSendInfoUserReq; | ||||
| import org.dromara.project.domain.dto.attendancemachineuser.BusAttendanceMachineUserQueryReq; | ||||
| import org.dromara.project.domain.dto.attendancemachineuser.BusAttendanceMachineUserRemoveReq; | ||||
| import org.dromara.project.domain.dto.projectteammember.BusProjectTeamMemberQueryReq; | ||||
| import org.dromara.project.domain.vo.BusAttendanceMachineUserVo; | ||||
| import org.dromara.project.domain.vo.projectteammember.BusProjectTeamMemberVo; | ||||
| import org.dromara.project.service.IBusAttendanceMachineService; | ||||
| import org.dromara.project.service.IBusAttendanceMachineUserService; | ||||
| import org.dromara.project.service.IBusProjectTeamMemberService; | ||||
| import org.springframework.stereotype.Service; | ||||
|  | ||||
| import java.util.Arrays; | ||||
| import java.util.HashSet; | ||||
| import java.util.List; | ||||
| import java.util.Set; | ||||
| import java.util.stream.Collectors; | ||||
|  | ||||
| /** | ||||
|  * 考勤机用户Service业务层处理 | ||||
|  * | ||||
|  * @author lilemy | ||||
|  * @date 2025-10-15 | ||||
|  */ | ||||
| @RequiredArgsConstructor | ||||
| @Service | ||||
| public class BusAttendanceMachineUserServiceImpl implements IBusAttendanceMachineUserService { | ||||
|  | ||||
|     private final IBusAttendanceMachineService attendanceMachineService; | ||||
|  | ||||
|     private final DeviceMessageSender deviceMessageSender; | ||||
|  | ||||
|     private final ISubConstructionUserService constructionUserService; | ||||
|  | ||||
|     private final IBusProjectTeamMemberService projectTeamMemberService; | ||||
|  | ||||
|     /** | ||||
|      * 查询符合条件的考勤机用户列表 | ||||
|      * | ||||
|      * @param req 查询条件 | ||||
|      * @return 考勤机用户列表 | ||||
|      */ | ||||
|     @Override | ||||
|     public List<BusAttendanceMachineUserVo> queryList(BusAttendanceMachineUserQueryReq req) { | ||||
|         BusProjectTeamMemberQueryReq query = new BusProjectTeamMemberQueryReq(); | ||||
|         query.setTeamId(req.getTeamId()); | ||||
|         query.setMemberName(req.getUserName()); | ||||
|         List<BusProjectTeamMemberVo> teamMemberList = projectTeamMemberService.queryList(query); | ||||
|         if (CollUtil.isEmpty(teamMemberList)) { | ||||
|             return CollUtil.newArrayList(); | ||||
|         } | ||||
|         BusAttendanceMachine machine = attendanceMachineService.getById(req.getMachineId()); | ||||
|         if (machine == null) { | ||||
|             throw new ServiceException("考勤机不存在", HttpStatus.NOT_FOUND); | ||||
|         } | ||||
|         // 判断选择班组和考勤机是否一致 | ||||
|         if (StringUtils.isBlank(machine.getTeams())) { | ||||
|             throw new ServiceException("考勤机未绑定班组", HttpStatus.NOT_FOUND); | ||||
|         } | ||||
|         if (!Arrays.stream(machine.getTeams().split(",")) | ||||
|             .map(Long::parseLong) | ||||
|             .collect(Collectors.toSet()).contains(req.getTeamId())) { | ||||
|             throw new ServiceException("所选班组与考勤机不匹配", HttpStatus.NOT_FOUND); | ||||
|         } | ||||
|         // 获取考勤机里的用户 | ||||
|         Set<Long> userIdList = new HashSet<>(); | ||||
|         try { | ||||
|             KqjEntity.CommonResponse response = deviceMessageSender.getAllUsers(machine.getSn()); | ||||
|             int code = response.getData().getCode(); | ||||
|             if (code == 0 || code == 200) { | ||||
|                 String[] userIds = response.getData().getUserIds(); | ||||
|                 userIdList = Arrays.stream(userIds).map(Long::parseLong).collect(Collectors.toSet()); | ||||
|             } | ||||
|         } catch (Exception e) { | ||||
|             throw new ServiceException("获取考勤机用户失败", HttpStatus.ERROR); | ||||
|         } | ||||
|         Set<Long> finalUserIdList = userIdList; | ||||
|         return teamMemberList.stream().map(member -> { | ||||
|             BusAttendanceMachineUserVo vo = new BusAttendanceMachineUserVo(); | ||||
|             vo.setMachineId(req.getMachineId()); | ||||
|             vo.setTeamId(req.getTeamId()); | ||||
|             vo.setUserId(member.getMemberId()); | ||||
|             vo.setUserName(member.getMemberName()); | ||||
|             if (CollUtil.isEmpty(finalUserIdList)) { | ||||
|                 vo.setIdentifying(0); | ||||
|             } else if (finalUserIdList.contains(member.getMemberId())) { | ||||
|                 vo.setIdentifying(1); | ||||
|             } else { | ||||
|                 vo.setIdentifying(0); | ||||
|             } | ||||
|             return vo; | ||||
|         }).toList(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 下发用户到考勤机中 | ||||
|      * | ||||
|      * @param req 下发用户参数 | ||||
|      * @return 下发结果 | ||||
|      */ | ||||
|     @Override | ||||
|     public String sendPersonInfo(BusAttendanceMachineSendInfoUserReq req) { | ||||
|         Long machineId = req.getMachineId(); | ||||
|         List<Long> userIds = req.getUserIds(); | ||||
|         BusAttendanceMachine machine = attendanceMachineService.getById(machineId); | ||||
|         if (machine == null) { | ||||
|             throw new ServiceException("考勤机不存在", HttpStatus.NOT_FOUND); | ||||
|         } | ||||
|         List<SubConstructionUser> userList = constructionUserService.lambdaQuery() | ||||
|             .in(SubConstructionUser::getSysUserId, userIds) | ||||
|             .list(); | ||||
|         // 返回数据 | ||||
|         StringBuilder sb = new StringBuilder(); | ||||
|         sb.append("用户:["); | ||||
|         int count = 0; | ||||
|         for (SubConstructionUser user : userList) { | ||||
|             Boolean result = deviceMessageSender.sendPersonnelInformation(machine.getSn(), | ||||
|                 user.getSysUserId().toString(), user.getUserName(), user.getFacePic()); | ||||
|             if (!result) { | ||||
|                 sb.append(user.getUserName()).append(" "); | ||||
|                 count++; | ||||
|             } | ||||
|         } | ||||
|         sb.append("] 下发失败"); | ||||
|         return count == 0 ? "下发成功" : sb.toString(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 删除考勤机用户 | ||||
|      * | ||||
|      * @param req 删除参数 | ||||
|      * @return 删除结果 | ||||
|      */ | ||||
|     @Override | ||||
|     public Boolean remove(BusAttendanceMachineUserRemoveReq req) { | ||||
|         Long machineId = req.getMachineId(); | ||||
|         List<Long> userIds = req.getUserIds(); | ||||
|         BusAttendanceMachine machine = attendanceMachineService.getById(machineId); | ||||
|         if (machine == null) { | ||||
|             throw new ServiceException("考勤机不存在", HttpStatus.NOT_FOUND); | ||||
|         } | ||||
|         String[] userIdArray = userIds.stream() | ||||
|             .map(String::valueOf)   // 将 Long 转成 String | ||||
|             .toArray(String[]::new); | ||||
|         try { | ||||
|             KqjEntity.CommonResponse response = deviceMessageSender.batchDeleteUsers(machine.getSn(), userIdArray); | ||||
|             return response.getData().getCode() == 0 || response.getData().getCode() == 200; | ||||
|         } catch (Exception e) { | ||||
|             throw new ServiceException("删除考勤机用户失败", HttpStatus.ERROR); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -273,7 +273,7 @@ public class SysUserController extends BaseController { | ||||
|     @Log(title = "用户管理", businessType = BusinessType.UPDATE) | ||||
|     @PutMapping("/resetPwd") | ||||
|     public R<Void> resetPwd(@RequestBody SysUserBo user) { | ||||
|         userService.checkUserAllowed(user.getUserId()); | ||||
| //        userService.checkUserAllowed(user.getUserId()); | ||||
|         userService.checkUserDataScope(user.getUserId()); | ||||
|         user.setPassword(BCrypt.hashpw(user.getPassword())); | ||||
|         return toAjax(userService.resetUserPwd(user.getUserId(), user.getPassword())); | ||||
|  | ||||
| @ -0,0 +1,7 @@ | ||||
| <?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="org.dromara.project.mapper.BusAttendanceMachineMapper"> | ||||
|  | ||||
| </mapper> | ||||
		Reference in New Issue
	
	Block a user