Преглед на файлове

优化sql速度 新增抄送功能 开放部分交叉功能权限

车车 преди 1 месец
родител
ревизия
84c8797df2
променени са 18 файла, в които са добавени 295 реда и са изтрити 12 реда
  1. 1 1
      yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/security/TenantSecurityWebFilter.java
  2. 6 0
      yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/workdesign/workflowwork/vo/MyWorkRespVO.java
  3. 9 0
      yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/workdesign/workflowwork/vo/WorkflowWorkRespVO.java
  4. 9 0
      yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/workdesign/workflowworknode/vo/WorkflowWorkNodeSaveReqVO.java
  5. 8 0
      yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/dal/dataobject/workdesign/WorkflowDesignNodeDO.java
  6. 8 0
      yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/dal/dataobject/workdesign/WorkflowWorkNodeDO.java
  7. 7 2
      yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/service/workdesign/WorkflowDesignNodeServiceImpl.java
  8. 1 1
      yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/service/workdesign/WorkflowWorkHandleServiceImpl.java
  9. 137 2
      yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/service/workdesign/WorkflowWorkNodeServiceImpl.java
  10. 16 1
      yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/service/workdesign/WorkflowWorkServiceImpl.java
  11. 2 2
      yudao-module-iscs/src/main/resources/mapper/LockCabinetMapper.xml
  12. 3 1
      yudao-module-iscs/src/main/resources/mapper/workdesign/WorkflowWorkMapper.xml
  13. 1 1
      yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/PostController.java
  14. 1 1
      yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java
  15. 13 0
      yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/appnotify/AppNotifySendService.java
  16. 42 0
      yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/appnotify/AppNotifySendServiceImpl.java
  17. 14 0
      yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifySendService.java
  18. 17 0
      yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifySendServiceImpl.java

+ 1 - 1
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/security/TenantSecurityWebFilter.java

@@ -77,7 +77,7 @@ public class TenantSecurityWebFilter extends ApiRequestFilter {
         if (!isIgnoreUrl(request)) {
             // 2. 如果请求未带租户的编号,不允许访问。
             if (tenantId == null) {
-                log.error("[doFilterInternal][URL({}/{}) 未传递租户编号]", request.getRequestURI(), request.getMethod());
+                log.error("[doFilterInternal][URL({}/{}/{}) 未传递租户编号]", request.getRequestURI(), request.getMethod() ,request.getRemoteAddr());
                 ServletUtils.writeJSON(response, CommonResult.error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                         "请求的租户标识未传递,请进行排查"));
                 return;

+ 6 - 0
yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/workdesign/workflowwork/vo/MyWorkRespVO.java

@@ -58,4 +58,10 @@ public class MyWorkRespVO {
 
     @Schema(description = "节点状态:pending(未开始)、running(执行中)、approved(通过)、rejected(驳回)")
     private String approvalStatus;
+
+    @Schema(description = "节点类型")
+    private String nodeType;
+
+    @Schema(description = "任务进度(1取设备 /解除共锁 2上锁/取设备解锁 3共锁/还设备)")
+    private String nodeProgress;
 }

+ 9 - 0
yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/workdesign/workflowwork/vo/WorkflowWorkRespVO.java

@@ -90,4 +90,13 @@ public class WorkflowWorkRespVO {
     @Schema(description = "解析的节点信息")
     private List<WorkflowWorkNodeRespVO> workflowWorkNodeDOList;
 
+    /**
+     * 抄送部门ID(部门及子部门所有人)
+     */
+    private String copyDeptIds;
+    /**
+     * 抄送人
+     */
+    private String copyUserIds;
+
 }

+ 9 - 0
yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/workdesign/workflowworknode/vo/WorkflowWorkNodeSaveReqVO.java

@@ -58,4 +58,13 @@ public class WorkflowWorkNodeSaveReqVO {
     @Schema(description = "共锁人")
     private String colockPersons;
 
+    /**
+     * 抄送部门ID(部门及子部门所有人)
+     */
+    private String copyDeptIds;
+    /**
+     * 抄送人
+     */
+    private String copyUserIds;
+
 }

+ 8 - 0
yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/dal/dataobject/workdesign/WorkflowDesignNodeDO.java

@@ -102,6 +102,14 @@ public class WorkflowDesignNodeDO extends BaseDO {
      * 被通知人分组ID
      */
     private Long notifyUserGroupId;
+    /**
+     * 抄送部门ID(部门及子部门所有人)
+     */
+    private String copyDeptIds;
+    /**
+     * 抄送人
+     */
+    private String copyUserIds;
     /**
      * 通知时间策略
      */

+ 8 - 0
yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/dal/dataobject/workdesign/WorkflowWorkNodeDO.java

@@ -108,6 +108,14 @@ public class WorkflowWorkNodeDO extends BaseDO {
      * 被通知人分组ID
      */
     private Long notifyUserGroupId;
+    /**
+     * 抄送部门ID(部门及子部门所有人)
+     */
+    private String copyDeptIds;
+    /**
+     * 抄送人
+     */
+    private String copyUserIds;
     /**
      * 通知时间策略
      */

+ 7 - 2
yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/service/workdesign/WorkflowDesignNodeServiceImpl.java

@@ -109,11 +109,14 @@ public class WorkflowDesignNodeServiceImpl extends ServiceImpl<WorkflowDesignNod
                     String messageTemplateCode = node.get("messageTemplateCode") != null ? node.get("messageTemplateCode").asText() : null;
                     String emailTemplateCode = node.get("emailTemplateCode") != null ? node.get("emailTemplateCode").asText() : null;
                     String appTemplateCode = node.get("appTemplateCode") != null ? node.get("appTemplateCode").asText() : null;
+                    String copyDeptIds = node.get("data").get("copyDeptIds") != null ? node.get("data").get("copyDeptIds").asText() : null;
+                    String copyUserIds = node.get("data").get("copyUserIds") != null ? node.get("data").get("copyUserIds").asText() : null;
+
 
                     System.out.printf("节点%d: uuid=%s, nodeName=%s, nodeIcon=%s, 类型=%s, position=%s, data=%s, 标签=%s, 表单=%s, 负责人=%s, 隔离类型=%s, 隔离点=%s, 隔离点Uuid=%s, 上锁人=%s, 共锁人=%s," +
-                                    " 短信=%s, 站内信=%s, 邮件=%s, app消息=%s%n",
+                                    " 短信=%s, 站内信=%s, 邮件=%s, app消息=%s, copyDeptIds=%s , copyUserIds=%s%n",
                             ++index, uuid, nodeName, nodeIcon, type, position, data, remark, formId, workerUserId, isolationType, isolationPoints, isolationNodeUuid, lockPerson, coLockPersons,
-                            smsTemplateCode, messageTemplateCode, emailTemplateCode, appTemplateCode);
+                            smsTemplateCode, messageTemplateCode, emailTemplateCode, appTemplateCode, copyDeptIds, copyUserIds);
                     WorkflowDesignNodeDO workflowDesignNodeDO = new WorkflowDesignNodeDO();
                     workflowDesignNodeDO.setUuid(uuid);
                     workflowDesignNodeDO.setNodeName(nodeName);
@@ -132,6 +135,8 @@ public class WorkflowDesignNodeServiceImpl extends ServiceImpl<WorkflowDesignNod
                     workflowDesignNodeDO.setMessageTemplateCode(messageTemplateCode);
                     workflowDesignNodeDO.setEmailTemplateCode(emailTemplateCode);
                     workflowDesignNodeDO.setAppTemplateCode(appTemplateCode);
+                    workflowDesignNodeDO.setCopyDeptIds(StringUtils.isNotBlank(copyDeptIds) && !"[]".equals(copyDeptIds) ? copyDeptIds : null);
+                    workflowDesignNodeDO.setCopyUserIds(StringUtils.isNotBlank(copyUserIds) && !"[]".equals(copyUserIds) ? copyUserIds : null);
                     // 处理关系字段
                     PcValueVO pcValueVO = pcValueMap.get(uuid);
                     if (pcValueVO != null) {

+ 1 - 1
yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/service/workdesign/WorkflowWorkHandleServiceImpl.java

@@ -326,7 +326,7 @@ public class WorkflowWorkHandleServiceImpl implements WorkflowWorkHandleService
                 .eq(WorkflowWorkNodeUserDO::getNodeId, vo.getNodeId())
                 .eq(WorkflowWorkNodeUserDO::getUserId, adminUserDO.getId())
                 .eq(WorkflowWorkNodeUserDO::getStatus, "1"));
-        Assert.notNull(one, "共锁失败,请勿重复共锁!");
+        Assert.isNull(one, "共锁失败,请勿重复共锁!");
         LocalDateTime now = LocalDateTime.now();
         nodeUserService.update(Wrappers.<WorkflowWorkNodeUserDO>lambdaUpdate()
                 .eq(WorkflowWorkNodeUserDO::getId, nodeUserDO.getId())

+ 137 - 2
yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/service/workdesign/WorkflowWorkNodeServiceImpl.java

@@ -15,8 +15,10 @@ import cn.iocoder.yudao.module.iscs.dal.mysql.workdesign.WorkflowWorkNodeMapper;
 import cn.iocoder.yudao.module.iscs.enums.MessageEnum;
 import cn.iocoder.yudao.module.iscs.enums.WorkTypeEnum;
 import cn.iocoder.yudao.module.iscs.service.isolationpoint.IsolationPointService;
+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.service.appnotify.AppNotifySendService;
+import cn.iocoder.yudao.module.system.service.dept.DeptService;
 import cn.iocoder.yudao.module.system.service.notify.NotifySendService;
 import cn.iocoder.yudao.module.system.service.sms.SmsSendService;
 import cn.iocoder.yudao.module.system.service.user.AdminUserService;
@@ -70,7 +72,8 @@ public class WorkflowWorkNodeServiceImpl extends ServiceImpl<WorkflowWorkNodeMap
     private WorkflowWorkPointService workflowWorkPointService;
     @Resource
     private IsolationPointService isolationPointService;
-
+    @Resource
+    private DeptService deptService;
 
     @Transactional
     @Override
@@ -271,6 +274,7 @@ public class WorkflowWorkNodeServiceImpl extends ServiceImpl<WorkflowWorkNodeMap
     }
 
     private void sendByType(WorkflowWorkNodeDO nodeDO) {
+        ArrayList<Long> longs = new ArrayList<>();
         if (nodeDO.getType().equals(WorkTypeEnum.CREATEJOB.value)) {
             // 创建作业
             WorkflowWorkDO workDO = workflowWorkService.getById(nodeDO.getWorkId());
@@ -279,6 +283,9 @@ public class WorkflowWorkNodeServiceImpl extends ServiceImpl<WorkflowWorkNodeMap
                 Map<String, Object> templateParams = new HashMap<>();
                 templateParams.put("name", user.getNickname());
                 sendMessage(nodeDO, user.getId(), "MESSAGE_001", templateParams);
+                // 抄送
+                longs.add(user.getId());
+                copyMessageSend(nodeDO, longs, "MESSAGE_001", templateParams);
             }
         }
 
@@ -290,6 +297,9 @@ public class WorkflowWorkNodeServiceImpl extends ServiceImpl<WorkflowWorkNodeMap
                     Map<String, Object> templateParams = new HashMap<>();
                     templateParams.put("name", user.getNickname());
                     sendMessage(nodeDO, user.getId(), "MESSAGE_002", templateParams);
+                    // 抄送
+                    longs.add(user.getId());
+                    copyMessageSend(nodeDO, longs, "MESSAGE_002", templateParams);
                 }
             }
         }
@@ -302,6 +312,9 @@ public class WorkflowWorkNodeServiceImpl extends ServiceImpl<WorkflowWorkNodeMap
                     Map<String, Object> templateParams = new HashMap<>();
                     templateParams.put("name", user.getNickname());
                     sendMessage(nodeDO, user.getId(), "MESSAGE_003", templateParams);
+                    // 抄送
+                    longs.add(user.getId());
+                    copyMessageSend(nodeDO, longs, "MESSAGE_003", templateParams);
                 }
             }
         }
@@ -314,6 +327,9 @@ public class WorkflowWorkNodeServiceImpl extends ServiceImpl<WorkflowWorkNodeMap
                     Map<String, Object> templateParams = new HashMap<>();
                     templateParams.put("name", user.getNickname());
                     sendMessage(nodeDO, user.getId(), "MESSAGE_007", templateParams);
+                    // 抄送
+                    longs.add(user.getId());
+                    copyMessageSend(nodeDO, longs, "MESSAGE_007", templateParams);
                 }
             }
         }
@@ -341,6 +357,11 @@ public class WorkflowWorkNodeServiceImpl extends ServiceImpl<WorkflowWorkNodeMap
                     sendMessage(nodeDO, adminUserDO.getId(), "MESSAGE_004", templateParams);
                     jtlockerName.append(adminUserDO.getNickname());
                 }
+                // 抄送
+                longs.addAll(jtlockerIds);
+                Map<String, Object> templateParams = new HashMap<>();
+                templateParams.put("name", "");
+                copyMessageSend(nodeDO, longs, "MESSAGE_004", templateParams);
             }
             // 上锁人归还钥匙
             if (!jtlockerIds.isEmpty() && StringUtils.isNotBlank(nodeProgress) && "2".equals(nodeProgress)) {
@@ -351,10 +372,15 @@ public class WorkflowWorkNodeServiceImpl extends ServiceImpl<WorkflowWorkNodeMap
                     sendMessage(nodeDO, adminUserDO.getId(), "MESSAGE_011", templateParams);
                     jtlockerName.append(adminUserDO.getNickname());
                 }
+                // 抄送
+                longs.addAll(jtlockerIds);
+                Map<String, Object> templateParams = new HashMap<>();
+                templateParams.put("name", "");
+                copyMessageSend(nodeDO, longs, "MESSAGE_011", templateParams);
             }
             // 共锁人
             List<Long> jtcolockerIds = nodeUserDOList.stream().filter(o -> "jtcolocker".equals(o.getType())).map(WorkflowWorkNodeUserDO::getUserId).toList();
-            if (!jtcolockerIds.isEmpty()  && StringUtils.isNotBlank(nodeProgress) && "3".equals(nodeProgress)) {
+            if (!jtcolockerIds.isEmpty() && StringUtils.isNotBlank(nodeProgress) && "3".equals(nodeProgress)) {
                 List<AdminUserDO> userList = adminUserService.getUserList(jtcolockerIds);
                 for (AdminUserDO adminUserDO : userList) {
                     // 发送
@@ -363,6 +389,11 @@ public class WorkflowWorkNodeServiceImpl extends ServiceImpl<WorkflowWorkNodeMap
                     templateParams.put("user", jtlockerName);
                     sendMessage(nodeDO, adminUserDO.getId(), "MESSAGE_008", templateParams);
                 }
+                // 抄送
+                longs.addAll(jtcolockerIds);
+                Map<String, Object> templateParams = new HashMap<>();
+                templateParams.put("name", "");
+                copyMessageSend(nodeDO, longs, "MESSAGE_008", templateParams);
             }
         }
 
@@ -388,6 +419,11 @@ public class WorkflowWorkNodeServiceImpl extends ServiceImpl<WorkflowWorkNodeMap
                         sendMessage(nodeDO, adminUserDO.getId(), "MESSAGE_009", templateParams);
                         jtcolockerName.append(adminUserDO.getNickname());
                     }
+                    // 抄送
+                    longs.addAll(jtcolockerIds);
+                    Map<String, Object> templateParams = new HashMap<>();
+                    templateParams.put("name", "");
+                    copyMessageSend(nodeDO, longs, "MESSAGE_009", templateParams);
                 }
                 // 上锁人
                 List<Long> jtlockerIds = nodeUserDOList.stream().filter(o -> "jtlocker".equals(o.getType())).map(WorkflowWorkNodeUserDO::getUserId).toList();
@@ -400,6 +436,12 @@ public class WorkflowWorkNodeServiceImpl extends ServiceImpl<WorkflowWorkNodeMap
                         templateParams.put("names", jtcolockerName);
                         sendMessage(nodeDO, adminUserDO.getId(), "MESSAGE_005", templateParams);
                     }
+                    // 抄送
+                    longs.addAll(jtlockerIds);
+                    Map<String, Object> templateParams = new HashMap<>();
+                    templateParams.put("name", "");
+                    templateParams.put("names", jtcolockerName);
+                    copyMessageSend(nodeDO, longs, "MESSAGE_005", templateParams);
                 }
                 // 上锁人归还硬件
                 if (!jtlockerIds.isEmpty() && StringUtils.isNotBlank(nodeProgress) && "3".equals(nodeProgress)) {
@@ -411,6 +453,12 @@ public class WorkflowWorkNodeServiceImpl extends ServiceImpl<WorkflowWorkNodeMap
                         templateParams.put("names", jtcolockerName);
                         sendMessage(nodeDO, adminUserDO.getId(), "MESSAGE_012", templateParams);
                     }
+                    // 抄送
+                    longs.addAll(jtlockerIds);
+                    Map<String, Object> templateParams = new HashMap<>();
+                    templateParams.put("name", "");
+                    templateParams.put("names", jtcolockerName);
+                    copyMessageSend(nodeDO, longs, "MESSAGE_012", templateParams);
                 }
             }
         }
@@ -435,6 +483,9 @@ public class WorkflowWorkNodeServiceImpl extends ServiceImpl<WorkflowWorkNodeMap
                     Map<String, Object> templateParams = new HashMap<>();
                     templateParams.put("name", user.getNickname());
                     sendMessage(nodeDO, user.getId(), "MESSAGE_006", templateParams);
+                    // 抄送
+                    longs.add(user.getId());
+                    copyMessageSend(nodeDO, longs, "MESSAGE_006", templateParams);
                 }
             }
         }
@@ -481,6 +532,90 @@ public class WorkflowWorkNodeServiceImpl extends ServiceImpl<WorkflowWorkNodeMap
 
     }
 
+    private void copyMessageSend(WorkflowWorkNodeDO nodeDO, List<Long> removeUserIds, String templateKey, Map<String, Object> templateParams) {
+
+        Set<Long> allUserIds = new HashSet<>();
+
+        // 解析抄送参数,如果部门参数有效,开始发送抄送
+        Set<Long> deptIds = convertStringToLongList(nodeDO.getCopyDeptIds());
+        if (!deptIds.isEmpty()) {
+            // 1.获取部门下所有的子部门
+            List<DeptDO> childDeptList = deptService.getChildDeptList(deptIds);
+            if (!childDeptList.isEmpty()) {
+                Set<Long> childDeptIds = childDeptList.stream().map(DeptDO::getId).collect(Collectors.toSet());
+                // 子母合并
+                deptIds.addAll(childDeptIds);
+            }
+            // 2.获取部门下所有的成员
+            allUserIds = adminUserService.getUserListByDeptIds(deptIds).stream().map(AdminUserDO::getId).collect(Collectors.toSet());
+        }
+
+        // 解析抄送参数,如果人员参数有效,开始发送抄送
+        Set<Long> userIds = convertStringToLongList(nodeDO.getCopyUserIds());
+        if (!userIds.isEmpty()) {
+            allUserIds.addAll(userIds);
+        }
+
+
+        if (!allUserIds.isEmpty()) {
+            // 排除自己
+            // removeUserIds.forEach(allUserIds::remove);
+            // 3.开始抄送给上面人员
+            if (StringUtils.isNotBlank(nodeDO.getMessageTemplateCode()) && "true".equals(nodeDO.getMessageTemplateCode())) {
+                // 站内信
+                try {
+                    for (Long userId : allUserIds) {
+                        notifySendService.sendSingleNotifyToAdminCopy(userId, Objects.requireNonNull(MessageEnum.getByKey(templateKey)).znx, templateParams, 0);
+                    }
+                } catch (Exception e) {
+                    log.error("站内信发送失败----------" + e.getMessage());
+                }
+            }
+            if (StringUtils.isNotBlank(nodeDO.getAppTemplateCode()) && "true".equals(nodeDO.getAppTemplateCode())) {
+                // app
+                try {
+                    for (Long userId : allUserIds) {
+                        appNotifySendService.sendSingleAppNotifyToAdminCopy(userId, Objects.requireNonNull(MessageEnum.getByKey(templateKey)).znx, templateParams);
+                    }
+                } catch (Exception e) {
+                    log.error("app消息发送失败----------" + e.getMessage());
+                }
+            }
+        }
+
+
+    }
+
+    /**
+     * 将逗号分隔的数字字符串转换为 List<Long>
+     *
+     * @param numStr 逗号分隔的数字字符串(如 "1,34,3245,564")
+     * @return 转换后的 List<Long>
+     */
+    public static Set<Long> convertStringToLongList(String numStr) {
+        // 空值/空字符串处理
+        if (numStr == null || numStr.trim().isEmpty()) {
+            return new HashSet<>();
+        }
+
+        // 方式1:Stream流(简洁,Java 8+ 支持)
+        Set<Long> result = Arrays.stream(numStr.split(",")) // 按逗号分割字符串
+                .map(String::trim) // 去除每个元素的首尾空格(处理如 "1, 34 , 3245" 这种情况)
+                .filter(s -> !s.isEmpty()) // 过滤分割后可能出现的空字符串(如 ",1,34," 分割后的空元素)
+                .map(s -> {
+                    // 异常处理:防止非数字字符串导致转换失败
+                    try {
+                        return Long.parseLong(s);
+                    } catch (NumberFormatException e) {
+                        System.out.println("忽略无效数字:" + s + ",原因:" + e.getMessage());
+                        return null;
+                    }
+                })
+                .filter(java.util.Objects::nonNull) // 过滤转换失败的 null 值
+                .collect(Collectors.toSet());
+        return result;
+    }
+
 
     @Override
     public PageResult<MyWorkRespVO> getMyNodePage(WorkflowWorkNodePageReqVO vo) {

+ 16 - 1
yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/service/workdesign/WorkflowWorkServiceImpl.java

@@ -218,7 +218,7 @@ public class WorkflowWorkServiceImpl extends ServiceImpl<WorkflowWorkMapper, Wor
         PageResult<WorkflowWorkDO> workflowWorkDOPageResult = workflowWorkMapper.selectPage(pageReqVO);
         PageResult<WorkflowWorkRespVO> bean = BeanUtils.toBean(workflowWorkDOPageResult, WorkflowWorkRespVO.class);
         // 查询当前节点
-        for (WorkflowWorkRespVO workflowWorkRespVO : bean.getList()) {
+        /*for (WorkflowWorkRespVO workflowWorkRespVO : bean.getList()) {
             List<WorkflowWorkNodeDO> list = workflowWorkNodeService.list(Wrappers.<WorkflowWorkNodeDO>lambdaQuery()
                     .eq(WorkflowWorkNodeDO::getWorkId, workflowWorkRespVO.getId())
                     .eq(WorkflowWorkNodeDO::getApprovalStatus, "running"));
@@ -226,7 +226,22 @@ public class WorkflowWorkServiceImpl extends ServiceImpl<WorkflowWorkMapper, Wor
                 String currentNodeName = list.stream().filter(o -> StringUtils.isNotBlank(o.getNodeName())).map(WorkflowWorkNodeDO::getNodeName).collect(Collectors.joining(","));
                 workflowWorkRespVO.setCurrentNodeName(currentNodeName);
             }
+        }*/
+        // 优化《查询当前节点》sql响应速度
+        if (!bean.getList().isEmpty()) {
+            List<Long> workIds = bean.getList().stream().map(WorkflowWorkRespVO::getId).toList();
+            List<WorkflowWorkNodeDO> list = workflowWorkNodeService.list(Wrappers.<WorkflowWorkNodeDO>lambdaQuery()
+                    .in(WorkflowWorkNodeDO::getWorkId, workIds)
+                    .eq(WorkflowWorkNodeDO::getApprovalStatus, "running"));
+            if (!list.isEmpty()) {
+                for (WorkflowWorkRespVO workflowWorkRespVO : bean.getList()) {
+                    String currentNodeName = list.stream().filter(o -> StringUtils.isNotBlank(o.getNodeName()) && workflowWorkRespVO.getId().equals(o.getWorkId()))
+                            .map(WorkflowWorkNodeDO::getNodeName).collect(Collectors.joining(","));
+                    workflowWorkRespVO.setCurrentNodeName(currentNodeName);
+                }
+            }
         }
+
         return bean;
     }
 

+ 2 - 2
yudao-module-iscs/src/main/resources/mapper/LockCabinetMapper.xml

@@ -13,10 +13,10 @@
             resultType="cn.iocoder.yudao.module.iscs.controller.admin.lockcabinet.vo.LockCabinetRespVO">
         SELECT
         c.*,
-        w.workstation_name
+        w.name as workstation_name
         FROM
         isc_lock_cabinet c
-        LEFT JOIN isc_workstation w ON w.id = c.workstation_id
+        LEFT JOIN system_post w ON w.id = c.workstation_id
         <where>
             c.deleted = 0
             <if test="vo.cabinetName != null and vo.cabinetName != ''">

+ 3 - 1
yudao-module-iscs/src/main/resources/mapper/workdesign/WorkflowWorkMapper.xml

@@ -25,7 +25,9 @@
         work_node.start_time as work_time,
         work_node.id as current_node_id,
         work_node.node_name as current_node_name,
-        work_node.approval_status
+        work_node.approval_status,
+        work_node.type as node_type,
+        work_node.node_progress
         FROM
         isc_workflow_work_node work_node
         left join isc_workflow_work ww on ww.id = work_node.work_id

+ 1 - 1
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/PostController.java

@@ -85,7 +85,7 @@ public class PostController {
 
     @GetMapping("/page")
     @Operation(summary = "获得岗位分页列表")
-    @PreAuthorize("@ss.hasPermission('system:post:query')")
+    // @PreAuthorize("@ss.hasPermission('system:post:query')")
     public CommonResult<PageResult<PostRespVO>> getPostPage(@Validated PostPageReqVO pageReqVO) {
         PageResult<PostDO> pageResult = postService.getPostPage(pageReqVO);
         return success(BeanUtils.toBean(pageResult, PostRespVO.class));

+ 1 - 1
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java

@@ -187,7 +187,7 @@ public class UserController {
             @Parameter(name = "file", description = "Excel 文件", required = true),
             @Parameter(name = "updateSupport", description = "是否支持更新,默认为 false", example = "true")
     })
-    @PreAuthorize("@ss.hasPermission('system:user:import')")
+    // @PreAuthorize("@ss.hasPermission('system:user:import')")
     public CommonResult<UserImportRespVO> importExcel(@RequestParam("file") MultipartFile file,
                                                       @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport) throws Exception {
         List<UserImportExcelVO> list = ExcelUtils.read(file, UserImportExcelVO.class);

+ 13 - 0
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/appnotify/AppNotifySendService.java

@@ -22,4 +22,17 @@ public interface AppNotifySendService {
     Long sendSingleAppNotifyToAdmin(Long userId,
                                  String templateCode, Map<String, Object> templateParams);
 
+    /**
+     * 发送单条站内信给管理后台的用户(抄送)
+     *
+     * 在 mobile 为空时,使用 userId 加载对应管理员的手机号
+     *
+     * @param userId 用户编号
+     * @param templateCode 短信模板编号
+     * @param templateParams 短信模板参数
+     * @return 发送日志编号
+     */
+    Long sendSingleAppNotifyToAdminCopy(Long userId,
+                                    String templateCode, Map<String, Object> templateParams);
+
 }

+ 42 - 0
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/appnotify/AppNotifySendServiceImpl.java

@@ -139,6 +139,48 @@ public class AppNotifySendServiceImpl implements AppNotifySendService {
         }
     }
 
+    @Override
+    public Long sendSingleAppNotifyToAdminCopy(Long userId, String templateCode, Map<String, Object> templateParams) {
+        // 1. 第一步:根据用户ID查询绑定的设备ID(需替换为业务系统实际查询逻辑)
+        // 说明:设备ID是App端集成阿里云推送SDK后上报的唯一设备标识
+        Set<String> deviceIds = getDeviceIdByUserId(userId);
+        if (deviceIds.isEmpty()) {
+            log.error("发送单用户App通知失败:用户{}未绑定任何设备ID,无法推送", userId);
+            return null;
+        }
+
+        // 2. 第二步:通过notifyId获取站内信已经发送的消息,进行消息复制发送
+        NotifyMessageDO notifyMessage = getMessageByNotify(userId, templateCode, templateParams);
+
+        try {
+            // 3. 第三步:创建阿里云ACS客户端(修复Push类找不到的兼容方案)
+            IAcsClient client = createAcsClient();
+
+            // 4. 第四步:构建单设备推送请求(封装Android/iOS双端配置)
+            // PushRequest pushRequest = buildAllDevicePushRequest("博士安全", notifyMessage.getTemplateContent());
+            for (String deviceId : deviceIds) {
+                PushRequest pushRequest = buildSingleDevicePushRequest(deviceId, "博士安全", "[抄送]" + notifyMessage.getTemplateContent());
+                // 5. 第五步:发送推送请求,调用阿里云Push接口
+                PushResponse response = client.getAcsResponse(pushRequest);
+
+                // 6. 第六步:解析返回结果,记录日志并返回消息ID
+                String requestId = response.getRequestId(); // 阿里云请求唯一标识(用于排查问题)
+                String messageId = response.getMessageId(); // 推送消息唯一标识(用于查询推送状态)
+                log.info("单用户App推送成功:userId={}, requestId={}, messageId={}", userId, requestId, messageId);
+            }
+            // 注意:若messageId是字符串格式(如含字母),需调整返回类型为String
+            return 1L;
+        } catch (ServerException e) {
+            // 服务端异常:阿里云接口返回错误(如AppKey无效、额度不足)
+            log.error("单用户App推送失败(阿里云服务端错误):userId={}, templateCode={}", userId, templateCode, e);
+            return null;
+        } catch (ClientException e) {
+            // 客户端异常:本地配置/网络/参数错误(如AccessKey错误、地域ID无效)
+            log.error("单用户App推送失败(客户端错误):userId={}, templateCode={}", userId, templateCode, e);
+            return null;
+        }
+    }
+
     /**
      * 通用推送方法:推送给全部用户(全量广播)
      *

+ 14 - 0
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifySendService.java

@@ -25,6 +25,20 @@ public interface NotifySendService {
      */
     Long sendSingleNotifyToAdmin(Long userId,
                                  String templateCode, Map<String, Object> templateParams, Integer type);
+
+    /**
+     * 发送单条站内信给管理后台的用户(抄送)
+     *
+     * 在 mobile 为空时,使用 userId 加载对应管理员的手机号
+     *
+     * @param userId 用户编号
+     * @param templateCode 短信模板编号
+     * @param templateParams 短信模板参数
+     * @param type 类型
+     * @return 发送日志编号
+     */
+    Long sendSingleNotifyToAdminCopy(Long userId,
+                                 String templateCode, Map<String, Object> templateParams, Integer type);
     /**
      * 发送单条站内信给用户 APP 的用户
      *

+ 17 - 0
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifySendServiceImpl.java

@@ -38,6 +38,23 @@ public class NotifySendServiceImpl implements NotifySendService {
         return sendSingleNotify(userId, UserTypeEnum.ADMIN.getValue(), templateCode, templateParams, type);
     }
 
+    @Override
+    public Long sendSingleNotifyToAdminCopy(Long userId, String templateCode, Map<String, Object> templateParams, Integer type) {
+        Integer userType = UserTypeEnum.ADMIN.getValue();
+        // 校验模版
+        NotifyTemplateDO template = validateNotifyTemplate(templateCode);
+        if (Objects.equals(template.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
+            log.info("[sendSingleNotify][模版({})已经关闭,无法给用户({}/{})发送]", templateCode, userId, userType);
+            return null;
+        }
+        // 校验参数
+        validateTemplateParams(template, templateParams);
+
+        // 发送站内信
+        String content = "[抄送]" + notifyTemplateService.formatNotifyTemplateContent(template.getContent(), templateParams);
+        return notifyMessageService.createNotifyMessage(userId, userType, template, content, templateParams, type);
+    }
+
     @Override
     public Long sendSingleNotifyToMember(Long userId, String templateCode, Map<String, Object> templateParams, Integer type) {
         return sendSingleNotify(userId, UserTypeEnum.MEMBER.getValue(), templateCode, templateParams, type);