Selaa lähdekoodia

Merge branch 'test-merge' of http://219.151.181.73:3000/zhuwei/bladex into test-merge

lvy 1 kuukausi sitten
vanhempi
commit
0bbb7a1c20
30 muutettua tiedostoa jossa 470 lisäystä ja 142 poistoa
  1. 1 0
      blade-common/src/main/java/org/springblade/common/constant/ClientIdConstant.java
  2. 2 1
      blade-common/src/main/java/org/springblade/common/constant/WebsocketMsgConstant.java
  3. 1 1
      blade-ops/blade-resource/src/main/java/org/springblade/resource/builder/oss/OssBuilder.java
  4. 23 0
      blade-service-api/blade-dingding-api/pom.xml
  5. 1 2
      blade-service-api/blade-dingding-api/src/main/java/org/springblade/dingding/vo/MeetingSchedule.java
  6. 0 2
      blade-service-api/blade-dingding-api/src/main/java/org/springblade/dingding/vo/MeetingVo.java
  7. 4 0
      blade-service-api/blade-dingding-api/src/main/java/org/springblade/dingding/vo/ScheduleItem.java
  8. 6 0
      blade-service-api/blade-websocket-api/pom.xml
  9. 7 0
      blade-service-api/blade-websocket-api/src/main/java/org/springblade/websocket/feign/WebSocketClient.java
  10. 12 0
      blade-service-api/blade-websocket-api/src/main/java/org/springblade/websocket/vo/DingDingMsg.java
  11. 5 0
      blade-service-api/blade-websocket-api/src/main/java/org/springblade/websocket/vo/UserInfoVO.java
  12. 3 0
      blade-service/blade-business/src/main/java/org/springblade/business/controller/InformationWriteQueryController.java
  13. 12 0
      blade-service/blade-dingding/pom.xml
  14. 15 1
      blade-service/blade-dingding/src/main/java/org/springblade/dingding/controller/MeetingController.java
  15. 1 0
      blade-service/blade-dingding/src/main/java/org/springblade/dingding/service/MeetingService.java
  16. 213 86
      blade-service/blade-dingding/src/main/java/org/springblade/dingding/service/impl/MeetingServiceImpl.java
  17. 6 1
      blade-service/blade-dingding/src/main/resources/application-dev.yml
  18. 6 1
      blade-service/blade-dingding/src/main/resources/application-prod.yml
  19. 6 1
      blade-service/blade-dingding/src/main/resources/application-test.yml
  20. 7 5
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ExcelTabController.java
  21. 8 2
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/NodeBaseInfoController.java
  22. 1 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/IExcelTabService.java
  23. 31 34
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ExcelTabServiceImpl.java
  24. 1 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsParamServiceImpl.java
  25. 2 2
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreeContractServiceImpl.java
  26. 12 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/utils/RandomNumberHolder.java
  27. 9 0
      blade-service/blade-websocket/pom.xml
  28. 12 0
      blade-service/blade-websocket/src/main/java/org/springblade/websocket/feign/WebSocketClientImpl.java
  29. 62 0
      blade-service/blade-websocket/src/main/java/org/springblade/websocket/service/WebSocketService.java
  30. 1 0
      pom.xml

+ 1 - 0
blade-common/src/main/java/org/springblade/common/constant/ClientIdConstant.java

@@ -10,4 +10,5 @@ public interface ClientIdConstant {
     String METER_ID = "measure";
     String CLIENT_ID = "client";
     String ARCHIVE_ID = "archives";
+    String DINGDING_ID = "dingding";
 }

+ 2 - 1
blade-common/src/main/java/org/springblade/common/constant/WebsocketMsgConstant.java

@@ -18,7 +18,8 @@ public interface WebsocketMsgConstant {
     String MSG_COUNT_DOWN = "msgCountDown";
     //客户端从服务器获取公告
     String GET_MSG = "getMsg";
-
+    //获取会议列表
+    String MSG_MEETING_LIST = "meetingList";
     /**
      * 单个系统标识
      */

+ 1 - 1
blade-ops/blade-resource/src/main/java/org/springblade/resource/builder/oss/OssBuilder.java

@@ -98,7 +98,7 @@ public class OssBuilder {
                 oss.setEndpoint("https://xinan1.zos.ctyun.cn");
             }
         }*/
-		//oss.setEndpoint("https://xinan1.zos.ctyun.cn");
+		oss.setEndpoint("https://xinan1.zos.ctyun.cn");
 		System.out.println("oss111="+oss.getEndpoint());
 		Oss ossCached = ossPool.get(tenantId);
 		OssTemplate template = templatePool.get(tenantId);

+ 23 - 0
blade-service-api/blade-dingding-api/pom.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>blade-service-api</artifactId>
+        <groupId>org.springblade</groupId>
+        <version>2.9.1.RELEASE</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>blade-dingding-api</artifactId>
+    <name>${project.artifactId}</name>
+    <version>${bladex.project.version}</version>
+    <dependencies>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-common</artifactId>
+        </dependency>
+    </dependencies>
+    <packaging>jar</packaging>
+
+</project>

+ 1 - 2
blade-service/blade-dingding/src/main/java/org/springblade/dingding/vo/MeetingSchedule.java → blade-service-api/blade-dingding-api/src/main/java/org/springblade/dingding/vo/MeetingSchedule.java

@@ -7,9 +7,8 @@ import lombok.NoArgsConstructor;
 @Data
 @AllArgsConstructor
 @NoArgsConstructor
-//今日预定场次
 public class MeetingSchedule {
     private String meetingId;
     private String reservationTime; //预约时间
-    private String reservationDept; //预约部门
+    private String reservationDept;
 }

+ 0 - 2
blade-service/blade-dingding/src/main/java/org/springblade/dingding/vo/MeetingVo.java → blade-service-api/blade-dingding-api/src/main/java/org/springblade/dingding/vo/MeetingVo.java

@@ -5,7 +5,6 @@ import lombok.Data;
 import lombok.NoArgsConstructor;
 
 import java.util.List;
-
 @Data
 @AllArgsConstructor
 @NoArgsConstructor
@@ -20,5 +19,4 @@ public class MeetingVo {
     private Integer status; //会议时间 1空闲中 2会议中
     private Integer meetingSession; //今日会议场次
     private List<MeetingSchedule> meetings; //今日预定会议场次详情
-
 }

+ 4 - 0
blade-service/blade-dingding/src/main/java/org/springblade/dingding/vo/ScheduleItem.java → blade-service-api/blade-dingding-api/src/main/java/org/springblade/dingding/vo/ScheduleItem.java

@@ -1,8 +1,12 @@
 package org.springblade.dingding.vo;
 
+import lombok.AllArgsConstructor;
 import lombok.Data;
+import lombok.NoArgsConstructor;
 
 @Data
+@AllArgsConstructor
+@NoArgsConstructor
 public class ScheduleItem {
     private String eventId;
     private String status;

+ 6 - 0
blade-service-api/blade-websocket-api/pom.xml

@@ -20,6 +20,12 @@
             <groupId>org.springblade</groupId>
             <artifactId>blade-common</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-dingding-api</artifactId>
+            <version>2.9.1.RELEASE</version>
+            <scope>compile</scope>
+        </dependency>
     </dependencies>
 
     <properties>

+ 7 - 0
blade-service-api/blade-websocket-api/src/main/java/org/springblade/websocket/feign/WebSocketClient.java

@@ -1,11 +1,15 @@
 package org.springblade.websocket.feign;
 
 import org.springblade.common.constant.LauncherConstant;
+import org.springblade.dingding.vo.MeetingVo;
+import org.springblade.websocket.vo.MsgVO;
 import org.springblade.websocket.vo.SystMsgVO;
 import org.springblade.websocket.vo.UserInfoVO;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.*;
 
+import java.util.List;
+
 /**
  * @Param
  * @Author wangwl
@@ -25,4 +29,7 @@ public interface WebSocketClient {
      */
     @PostMapping(value = "/socket/sendSystemMsg")
     void sendSystemMsg(@RequestBody SystMsgVO vo);
+
+    @PostMapping(value = "/socket/sendDingDingMsg")
+    void sendDingDingMsg(@RequestBody UserInfoVO vo);
 }

+ 12 - 0
blade-service-api/blade-websocket-api/src/main/java/org/springblade/websocket/vo/DingDingMsg.java

@@ -0,0 +1,12 @@
+package org.springblade.websocket.vo;
+
+import lombok.Data;
+import org.springblade.dingding.vo.MeetingVo;
+
+import java.util.List;
+
+@Data
+public class DingDingMsg {
+    private String msgType;
+    private List<MeetingVo> data;
+}

+ 5 - 0
blade-service-api/blade-websocket-api/src/main/java/org/springblade/websocket/vo/UserInfoVO.java

@@ -2,8 +2,10 @@ package org.springblade.websocket.vo;
 
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
+import org.springblade.dingding.vo.MeetingVo;
 
 import java.io.Serializable;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -32,6 +34,9 @@ public class UserInfoVO implements Serializable {
     @ApiModelProperty("公告类型1维护2普通,拼接字符串")
     private String msgType;
 
+    @ApiModelProperty("数据信息")
+    private List<MeetingVo> object;
+
     public UserInfoVO() {
     }
 

+ 3 - 0
blade-service/blade-business/src/main/java/org/springblade/business/controller/InformationWriteQueryController.java

@@ -252,6 +252,9 @@ public class InformationWriteQueryController extends BladeController {
                     }
                 }
                 if(contract!=null&&contract.getMajorDataType()!=null&&contract.getMajorDataType()==4){
+                    if(result==null){
+                        result="";
+                    }
                     if(query.getClassify()!=null&&query.getClassify()==1&&StringUtils.isNotEmpty(sgSuffix)){
                         result=result+sgSuffix;
                         if(!query.getName().equals(result)){

+ 12 - 0
blade-service/blade-dingding/pom.xml

@@ -30,6 +30,18 @@
             <groupId>org.springblade</groupId>
             <artifactId>blade-starter-swagger</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-dingding-api</artifactId>
+            <version>2.9.1.RELEASE</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-websocket-api</artifactId>
+            <version>2.9.1.RELEASE</version>
+            <scope>compile</scope>
+        </dependency>
     </dependencies>
 
 </project>

+ 15 - 1
blade-service/blade-dingding/src/main/java/org/springblade/dingding/controller/MeetingController.java

@@ -2,7 +2,6 @@ package org.springblade.dingding.controller;
 
 import io.swagger.annotations.Api;
 import lombok.AllArgsConstructor;
-import lombok.extern.java.Log;
 import org.springblade.core.boot.ctrl.BladeController;
 import org.springblade.core.tool.api.R;
 import org.springblade.dingding.service.MeetingService;
@@ -22,6 +21,21 @@ public class MeetingController extends BladeController {
 
   private final MeetingService meetingService;
 
+
+
+  // 定时任务方法 - 排除日志切面拦截
+  @Scheduled(cron = "0 * * * * ?")
+  // 如果项目支持@Log注解,可以使用:
+  // @Log(ignore = true)
+  public void scheduledMeetingInfo() {
+    try {
+      meetingService.getMeetingInfo();
+      System.out.println("定时任务执行完成");
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+
   @GetMapping("/getMeetingInfo")
   public R<List<MeetingVo>> getMeetingInfo(){
     return R.data(meetingService.getMeetingInfo());

+ 1 - 0
blade-service/blade-dingding/src/main/java/org/springblade/dingding/service/MeetingService.java

@@ -1,5 +1,6 @@
 package org.springblade.dingding.service;
 
+import org.springblade.core.tool.api.R;
 import org.springblade.dingding.vo.MeetingVo;
 
 import java.util.List;

+ 213 - 86
blade-service/blade-dingding/src/main/java/org/springblade/dingding/service/impl/MeetingServiceImpl.java

@@ -1,5 +1,6 @@
 package org.springblade.dingding.service.impl;
 
+import cn.hutool.system.UserInfo;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
@@ -7,23 +8,29 @@ import com.alibaba.nacos.shaded.com.google.gson.JsonElement;
 import com.alibaba.nacos.shaded.com.google.gson.JsonObject;
 import com.alibaba.nacos.shaded.com.google.gson.JsonParser;
 import com.fasterxml.jackson.databind.ObjectMapper;
-import org.apache.commons.lang.StringUtils;
+import org.apache.http.client.config.RequestConfig;
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.client.HttpClientBuilder;
 import org.apache.http.util.EntityUtils;
+import org.springblade.common.constant.WebsocketMsgConstant;
 import org.springblade.core.log.exception.ServiceException;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.jackson.JsonUtil;
 import org.springblade.dingding.service.MeetingService;
 import org.springblade.dingding.vo.MeetingSchedule;
 import org.springblade.dingding.vo.MeetingVo;
 import org.springblade.dingding.vo.ScheduleItem;
+import org.springblade.websocket.feign.WebSocketClient;
+import org.springblade.websocket.vo.MsgVO;
+import org.springblade.websocket.vo.UserInfoVO;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.*;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
-import org.springframework.web.client.HttpClientErrorException;
-import org.springframework.web.client.HttpServerErrorException;
 import org.springframework.web.client.RestTemplate;
 import org.springframework.web.util.UriComponentsBuilder;
 
@@ -37,6 +44,9 @@ import java.time.ZonedDateTime;
 import java.time.format.DateTimeFormatter;
 import java.time.format.TextStyle;
 import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 @Service
@@ -46,96 +56,216 @@ public class MeetingServiceImpl implements MeetingService {
     private static final String APP_KEY = "ding6mvrzcxcbdggel0h";
     private static final String APP_SECRET = "TctTp-Qmyh9r20bdeHcLWZ8qfxSEP8R29qo53GZH2elWV-yDZMqgqFKEjp5PtlXZ";
     private static final String USER_ID = "01141506681633389467";
+    @Autowired
+    private  WebSocketClient webSocketClient;
+
+    // 缓存用户信息,避免重复调用
+    private final Map<String, Object> userInfoCache = new ConcurrentHashMap<>();
+    private final Map<String, String> departmentCache = new ConcurrentHashMap<>();
+
+    // 创建带超时配置的HttpClient
+    private CloseableHttpClient createHttpClientWithTimeout() {
+        RequestConfig config = RequestConfig.custom()
+                .setConnectTimeout(10000) // 10秒连接超时
+                .setSocketTimeout(15000)   // 15秒socket超时
+                .build();
+
+        return HttpClientBuilder.create()
+                .setDefaultRequestConfig(config)
+                .build();
+    }
 
 
 
     @Override
     public  List<MeetingVo> getMeetingInfo() {
-        List<MeetingVo> vos=new ArrayList<>();
-        String accessToken = getAccessToken();
-        String unionId = (String) getUserInfo(accessToken,"unionid",USER_ID);
-        String meetingsJson = getMeetings(accessToken, unionId);
+        long startTime = System.currentTimeMillis();
+        try {
+            String accessToken = getAccessToken();
+            String unionId = (String) getUserInfo(accessToken, "unionid", USER_ID);
+            String meetingsJson = getMeetings(accessToken, unionId);
+
+            List<MeetingVo> vos = parseMeetingRooms(meetingsJson);
+            if (vos.isEmpty()) {
+                return vos;
+            }
+
+            // 准备时间范围参数
+            String[] timeRange = getTodayTimeRange();
+
+            // 并行处理每个会议室
+            List<CompletableFuture<Void>> futures = vos.stream()
+                    .map(vo -> processMeetingRoomAsync(vo, accessToken, unionId, timeRange[0], timeRange[1]))
+                    .collect(Collectors.toList());
+
+            // 等待所有完成,设置超时
+            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
+                    .get(25, TimeUnit.SECONDS);
+            // 25秒总超时
+            if(!vos.isEmpty()){
+                UserInfoVO vo = new UserInfoVO();
+                vo.setSystem("dingding");
+                vo.setContractId(1L);
+                vo.setMsgType("dingding");
+                vo.setUserId(1L);
+                vo.setProjectId(1L);
+                vo.setObject( vos);
+                webSocketClient.sendDingDingMsg(vo);
+            }
+            return vos;
+        } catch (Exception e) {
+            throw new ServiceException("获取会议室信息失败: " + e.getMessage());
+        } finally {
+            long duration = System.currentTimeMillis() - startTime;
+            System.out.println("getMeetingInfo执行耗时: " + duration + "ms");
+        }
+    }
+
+    private String[] getTodayTimeRange() {
+        LocalDateTime startOfDay = LocalDateTime.now().with(LocalTime.MIDNIGHT);
+        ZonedDateTime startOfDayZoned = startOfDay.atZone(ZoneId.systemDefault());
+        String startTime = startOfDayZoned.withZoneSameInstant(ZoneId.of("UTC"))
+                .format(DateTimeFormatter.ISO_INSTANT);
+
+        LocalDateTime endOfDay = LocalDateTime.now().with(LocalTime.MAX);
+        ZonedDateTime endOfDayZoned = endOfDay.atZone(ZoneId.systemDefault());
+        String endTime = endOfDayZoned.withZoneSameInstant(ZoneId.of("UTC"))
+                .format(DateTimeFormatter.ISO_INSTANT);
+
+        return new String[]{startTime, endTime};
+    }
+    private List<MeetingVo> parseMeetingRooms(String meetingsJson) {
+        List<MeetingVo> vos = new ArrayList<>();
         try {
-            // 解析JSON字符串
-            com.alibaba.fastjson.JSONObject jsonObject = JSON.parseObject(meetingsJson);
-            // 获取result数组
+            JSONObject jsonObject = JSON.parseObject(meetingsJson);
             JSONArray resultArray = jsonObject.getJSONArray("result");
-            // 遍历数组,提取roomId和roomName
+
             for (int i = 0; i < resultArray.size(); i++) {
-                MeetingVo vo=new MeetingVo();
                 JSONObject roomObject = resultArray.getJSONObject(i);
-                String roomId = roomObject.getString("roomId");
-                String roomName = roomObject.getString("roomName");
-                vo.setRoomId(roomId);
-                vo.setFixedData(roomName);
+                MeetingVo vo = new MeetingVo();
+                vo.setRoomId(roomObject.getString("roomId"));
+                vo.setFixedData(roomObject.getString("roomName"));
+                vo.setStatus(1); // 默认状态
                 vos.add(vo);
             }
-            LocalDateTime startOfDay = LocalDateTime.now().with(LocalTime.MIDNIGHT);
-            ZonedDateTime startOfDayZoned = startOfDay.atZone(ZoneId.systemDefault());
-            String startTime=startOfDayZoned.withZoneSameInstant(ZoneId.of("UTC"))
-                    .format(DateTimeFormatter.ISO_INSTANT);
-            LocalDateTime endOfDay = LocalDateTime.now().with(LocalTime.MAX);
-            ZonedDateTime endOfDayZoned = endOfDay.atZone(ZoneId.systemDefault());
-            String endTime= endOfDayZoned.withZoneSameInstant(ZoneId.of("UTC"))
-                    .format(DateTimeFormatter.ISO_INSTANT);
-            for (MeetingVo vo : vos) {
-                String[] roomIds = new String[]{vo.getRoomId()};
-                String meetingHistory = getMeetingHistory(accessToken, unionId,roomIds,startTime,endTime);
-                List<ScheduleItem> scheduleItems = parseScheduleItemsWithStream(meetingHistory);
-                List<MeetingSchedule>list=new ArrayList<>();
-                if(!scheduleItems.isEmpty()){
-                    //循环查出预定的会议是否正在进行
-                    for (ScheduleItem item : scheduleItems) {
-                        String stringStartDateTime = extractTimeFromDateTime(item.getStartDateTime());
-                        String stringEndDateTime = extractTimeFromDateTime(item.getEndDateTime());
-                        //正在进行的会议
-                        if(isCurrentTimeInRange(item.getStartDateTime(),item.getEndDateTime())){
-                            String meetingList = getMeetingList(item.getOrganizerId(), accessToken);
-                            JSONObject meetingListjsonObject = JSON.parseObject(meetingList);
-                            JSONArray onGoingConfIdList = meetingListjsonObject.getJSONArray("onGoingConfIdList");
-                            String tatil = getMeetingDetail(accessToken, onGoingConfIdList.getString(0));
-                            String userID = getUserID(accessToken, item.getOrganizerId());
-                            Object o = getUserInfo(accessToken, "dept_id_list", userID);
-                            List<String> deptIdList = JSON.parseArray(o.toString(), String.class);
-                            String departmentInfo = getDepartmentInfo(accessToken, deptIdList.get(0));
-                            vo.setMeetingTheme(tatil);
-                            vo.setMeetingDept(departmentInfo);
-                            String name = (String)getUserInfo(accessToken, "name", userID);
-                            vo.setMeetingBooker(name);
-                            vo.setMeetingTime(formatDateTimeRangeWithFormatter(item.getStartDateTime(),item.getEndDateTime()));
-                            String allUser = getAllUser(onGoingConfIdList.getString(0), accessToken);
-                            vo.setParticipants(allUser);
-                            if(StringUtils.isNotEmpty(allUser)){
-                                vo.setStatus(2);
-                                break;
-                            }
-                        }
-                        //今日预约的会议
-                        MeetingSchedule schedule = new MeetingSchedule();
-                        String userID = getUserID(accessToken, item.getOrganizerId());
-                        Object o = getUserInfo(accessToken, "dept_id_list", userID);
-                        List<String> deptIdList = JSON.parseArray(o.toString(), String.class);
-                        String departmentInfo = getDepartmentInfo(accessToken, deptIdList.get(0));
-                        schedule.setReservationTime(stringStartDateTime+"~"+stringEndDateTime);
-                        schedule.setReservationDept(departmentInfo);
-                        vo.setStatus(1);
-                        list.add(schedule);
-                    }
-                }else {
-                    vo.setStatus(1);
+        } catch (Exception e) {
+            System.err.println("解析会议室列表失败: " + e.getMessage());
+        }
+        return vos;
+    }
+    @Async
+    protected CompletableFuture<Void> processMeetingRoomAsync(MeetingVo vo, String accessToken,
+                                                              String unionId, String startTime, String endTime) {
+        return CompletableFuture.runAsync(() -> {
+            try {
+                processMeetingRoom(vo, accessToken, unionId, startTime, endTime);
+            } catch (Exception e) {
+                System.err.println("处理会议室 " + vo.getFixedData() + " 失败: " + e.getMessage());
+                // 设置默认值,避免影响其他会议室
+                vo.setStatus(1);
+                vo.setMeetings(new ArrayList<>());
+                vo.setMeetingSession(0);
+            }
+        });
+    }
+    private void processMeetingRoom(MeetingVo vo, String accessToken, String unionId,
+                                    String startTime, String endTime) {
+        String[] roomIds = new String[]{vo.getRoomId()};
+        String meetingHistory = getMeetingHistory(accessToken, unionId, roomIds, startTime, endTime);
+        List<ScheduleItem> scheduleItems = parseScheduleItemsWithStream(meetingHistory);
+
+        List<MeetingSchedule> meetings = new ArrayList<>();
+        boolean hasOngoingMeeting = false;
+
+        for (ScheduleItem item : scheduleItems) {
+            if (hasOngoingMeeting) {
+                break; // 如果已经有进行中的会议,跳过后续处理
+            }
+
+            if (isCurrentTimeInRange(item.getStartDateTime(), item.getEndDateTime())) {
+                // 处理进行中的会议
+                processOngoingMeeting(vo, item, accessToken);
+                hasOngoingMeeting = true;
+            } else {
+                // 处理预约的会议
+                MeetingSchedule schedule = processScheduledMeeting(item, accessToken);
+                if (schedule != null) {
+                    meetings.add(schedule);
+                }
+            }
+        }
+
+        vo.setMeetings(meetings);
+        vo.setMeetingSession(meetings.size());
+        if (!hasOngoingMeeting) {
+            vo.setStatus(1);
+        }
+    }
+
+    private void processOngoingMeeting(MeetingVo vo, ScheduleItem item, String accessToken) {
+        try {
+            vo.setStatus(2);
+
+            String meetingList = getMeetingList(item.getOrganizerId(), accessToken);
+            JSONObject meetingListJson = JSON.parseObject(meetingList);
+            JSONArray onGoingConfIdList = meetingListJson.getJSONArray("onGoingConfIdList");
+
+            if (onGoingConfIdList != null && !onGoingConfIdList.isEmpty()) {
+                String conferenceId = onGoingConfIdList.getString(0);
+                String meetingTitle = getMeetingDetail(accessToken, conferenceId);
+                vo.setMeetingTheme(meetingTitle);
+
+                String allUsers = getAllUser(conferenceId, accessToken);
+                vo.setParticipants(allUsers);
+            }
+
+            String userId = getUserID(accessToken, item.getOrganizerId());
+            String userName = (String) getUserInfo(accessToken, "name", userId);
+            vo.setMeetingBooker(userName);
+
+            Object deptInfo = getUserInfo(accessToken, "dept_id_list", userId);
+            if (deptInfo != null) {
+                List<String> deptIdList = JSON.parseArray(deptInfo.toString(), String.class);
+                if (!deptIdList.isEmpty()) {
+                    String departmentName = getDepartmentInfo(accessToken, deptIdList.get(0));
+                    vo.setMeetingDept(departmentName);
                 }
-                vo.setMeetingSession(list.size());
-                vo.setMeetings(list);
             }
+
+            vo.setMeetingTime(formatDateTimeRangeWithFormatter(item.getStartDateTime(), item.getEndDateTime()));
+
         } catch (Exception e) {
-            e.printStackTrace();
+            System.err.println("处理进行中会议失败: " + e.getMessage());
+            vo.setStatus(1); // 出错时回退到预约状态
         }
-        return vos;
+    }
+    private MeetingSchedule processScheduledMeeting(ScheduleItem item, String accessToken) {
+        try {
+            String startTime = extractTimeFromDateTime(item.getStartDateTime());
+            String endTime = extractTimeFromDateTime(item.getEndDateTime());
+
+            String userId = getUserID(accessToken, item.getOrganizerId());
+            Object deptInfo = getUserInfo(accessToken, "dept_id_list", userId);
+
+            if (deptInfo != null) {
+                List<String> deptIdList = JSON.parseArray(deptInfo.toString(), String.class);
+                if (!deptIdList.isEmpty()) {
+                    String departmentName = getDepartmentInfo(accessToken, deptIdList.get(0));
+
+                    MeetingSchedule schedule = new MeetingSchedule();
+                    schedule.setReservationTime(startTime + "~" + endTime);
+                    schedule.setReservationDept(departmentName);
+                    return schedule;
+                }
+            }
+        } catch (Exception e) {
+            System.err.println("处理预约会议失败: " + e.getMessage());
+        }
+        return null;
     }
 
-   public String getAllUser(String CONFERENCE_ID,String ACCESS_TOKEN){
-       CloseableHttpClient httpClient = HttpClients.createDefault();
-       try {
+    public String getAllUser(String CONFERENCE_ID,String ACCESS_TOKEN){
+       try(CloseableHttpClient httpClient = createHttpClientWithTimeout()) {
            // 构建请求 URL
            StringBuilder urlBuilder = new StringBuilder("https://api.dingtalk.com/v1.0/conference/videoConferences/")
                    .append(CONFERENCE_ID)
@@ -153,13 +283,13 @@ public class MeetingServiceImpl implements MeetingService {
                // 获取memberModelMap
                JSONArray memberModels = jsonObject.getJSONArray("memberModels");
                Set<String> set=new HashSet<>();
-               if(!memberModels.isEmpty()){
+               if(memberModels!=null&&!memberModels.isEmpty()){
                    for (int i = 0; i < memberModels.size(); i++) {
                        JSONObject memberModel = memberModels.getJSONObject(i);
                        String userNick = memberModel.getString("userNick");
                        set.add(userNick);
                    }
-                   return String.join(",",set);
+                   return String.join("",set);
                }else {
                    return "";
                }
@@ -219,8 +349,7 @@ public class MeetingServiceImpl implements MeetingService {
     }
 
     public String getMeetingList(String UNION_ID, String ACCESS_TOKEN){
-        CloseableHttpClient httpClient = HttpClients.createDefault();
-        try {
+        try(CloseableHttpClient httpClient = createHttpClientWithTimeout()) {
             // 构建请求 URL
             String url = "https://api.dingtalk.com/v1.0/conference/users/lists?unionId=" + UNION_ID;
             HttpGet httpGet = new HttpGet(url);
@@ -246,8 +375,7 @@ public class MeetingServiceImpl implements MeetingService {
     }
 
     public String getMeetingDetail(String ACCESS_TOKEN,String CONFERENCE_ID){
-        CloseableHttpClient httpClient = HttpClients.createDefault();
-        try {
+        try(CloseableHttpClient httpClient = createHttpClientWithTimeout()) {
             // 构建请求 URL,包含会议 ID
             String url = "https://api.dingtalk.com/v1.0/conference/videoConferences/" + CONFERENCE_ID;
             HttpGet httpGet = new HttpGet(url);
@@ -276,8 +404,7 @@ public class MeetingServiceImpl implements MeetingService {
     }
 
     public  String getUserID(String ACCESS_TOKEN,String UNION_ID) throws Exception {
-        CloseableHttpClient httpClient = HttpClients.createDefault();
-        try {
+        try(CloseableHttpClient httpClient = createHttpClientWithTimeout()) {
             // 构建请求 URL,包含 access_token 和 unionid 参数
             String url = "https://oapi.dingtalk.com/user/getUseridByUnionid?access_token=" + ACCESS_TOKEN + "&unionid=" + UNION_ID;
             HttpGet httpGet = new HttpGet(url);
@@ -330,7 +457,7 @@ public class MeetingServiceImpl implements MeetingService {
      * 查询部门信息
      */
     public String getDepartmentInfo(String accessToken, String deptId) throws Exception {
-        CloseableHttpClient httpClient = HttpClients.createDefault();
+        CloseableHttpClient httpClient = createHttpClientWithTimeout();
         String url = "https://oapi.dingtalk.com/topapi/v2/department/get?access_token=" + accessToken;
 
         HttpPost httpPost = new HttpPost(url);

+ 6 - 1
blade-service/blade-dingding/src/main/resources/application-dev.yml

@@ -1,7 +1,12 @@
 #服务器端口
 server:
   port: 9120
-
+  task:
+    execution:
+      pool:
+        core-size: 10
+        max-size: 20
+        queue-capacity: 100
 #数据源配置
 spring:
   datasource:

+ 6 - 1
blade-service/blade-dingding/src/main/resources/application-prod.yml

@@ -1,7 +1,12 @@
 #服务器端口
 server:
   port: 9120
-
+  task:
+    execution:
+      pool:
+        core-size: 10
+        max-size: 20
+        queue-capacity: 100
 #数据源配置
 spring:
   datasource:

+ 6 - 1
blade-service/blade-dingding/src/main/resources/application-test.yml

@@ -1,7 +1,12 @@
 #服务器端口
 server:
   port: 9120
-
+  task:
+    execution:
+      pool:
+        core-size: 10
+        max-size: 20
+        queue-capacity: 100
 #数据源配置
 spring:
   datasource:

+ 7 - 5
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ExcelTabController.java

@@ -2096,8 +2096,10 @@ public class ExcelTabController extends BladeController {
     @PostMapping("/save_buss_data")
     @ApiOperationSupport(order = 13)
     @ApiOperation(value = "填报页面数据保存", notes = "填报页面数据保存")
-    public R saveBussData2(@Valid @RequestBody JSONObject dataInfo) throws Exception {
-
+    public R saveBussData2(@Valid @RequestBody JSONObject dataInfo,Boolean flag) throws Exception {
+        if(flag==null){
+            flag=true;
+        }
         ExecutionTime executionTime = new ExecutionTime();
         executionTime.info("----计划开始----");
         JSONArray dataArray = new JSONArray();
@@ -2158,7 +2160,7 @@ public class ExcelTabController extends BladeController {
         }
 
         //保存数据到数据库
-        R<Object> result = this.excelTabService.saveOrUpdateInfo(tableInfoList,singnType);
+        R<Object> result = this.excelTabService.saveOrUpdateInfo(tableInfoList,singnType,flag);
         RandomNumberHolder.RandomTemplateTypeclear();
         RandomNumberHolder.RandomWbsTreeContractclear();
         executionTime.info("----数据保存结束----");
@@ -2432,7 +2434,7 @@ public class ExcelTabController extends BladeController {
         //公式填充
         this.excelTabService.formulaFillData(tableInfoList, Long.parseLong(nodeId), ExecuteType.INSPECTION);
         //保存数据到数据库
-        R<Object> result = this.excelTabService.saveOrUpdateInfo(tableInfoList,"");
+        R<Object> result = this.excelTabService.saveOrUpdateInfo(tableInfoList,"",true);
         if (!result.isSuccess()) {
             R.fail(result.getMsg());
             return;
@@ -4808,7 +4810,7 @@ public class ExcelTabController extends BladeController {
                     js.put("signType", "1");
                 }*/
 
-                this.saveBussData2(js);
+                this.saveBussData2(js,true);
             }
         } catch (Exception e) {
             return null;

+ 8 - 2
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/NodeBaseInfoController.java

@@ -37,6 +37,7 @@ import org.springblade.core.tool.utils.Func;
 import org.springblade.manager.entity.WbsTreeContract;
 import org.springblade.manager.service.IExcelTabService;
 import org.springblade.manager.service.IWbsTreeContractService;
+import org.springblade.manager.utils.RandomNumberHolder;
 import org.springblade.manager.vo.AppWbsTreeContractVO;
 import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
@@ -158,7 +159,12 @@ public class NodeBaseInfoController extends BladeController {
                 this.synPDFInfo(wbsTreeContract.get(0).getContractId(), nodeBaseInfo.getNodeId()+"", "2", wbsTreeContract.get(0).getProjectId(),dataMap2);
             }
         }
-        return R.status(update);
+        String logMessage = RandomNumberHolder.getLogMessage();
+        RandomNumberHolder.clearLogMessage();
+        if(StringUtils.isNotEmpty(logMessage)){
+            return R.success("保存成功,表单"+logMessage+" 刷新失败");
+        }
+        return R.success("保存成功");
 	}
 
 
@@ -214,7 +220,7 @@ public class NodeBaseInfoController extends BladeController {
                 }
                 js2.put("orderList", array);
                 js.put("dataInfo", js2);
-                controller.saveBussData2(js);
+                controller.saveBussData2(js,false);
         } catch (Exception e) {
             return null;
         }

+ 1 - 1
blade-service/blade-manager/src/main/java/org/springblade/manager/service/IExcelTabService.java

@@ -108,7 +108,7 @@ public interface IExcelTabService extends BaseService<ExcelTab> {
     /**
      * 结果信息持久化
      */
-    R<Object> saveOrUpdateInfo(List<TableInfo> tableInfoList,String singType) throws SQLException;
+    R<Object> saveOrUpdateInfo(List<TableInfo> tableInfoList,String singType,Boolean flag) throws SQLException;
 
     Map<String, String> getTablbCols(String pkeyid, String colkey) throws FileNotFoundException;
 

+ 31 - 34
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ExcelTabServiceImpl.java

@@ -1318,7 +1318,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
     }
 
     @Override
-    public R<Object> saveOrUpdateInfo(List<TableInfo> tableInfoList,String sigType) {
+    public R<Object> saveOrUpdateInfo(List<TableInfo> tableInfoList,String sigType,Boolean flag) {
         List<TableInfo> tableInfoList2 = new ArrayList<>();
         String fileName1="";
         if (ListUtils.isNotEmpty(tableInfoList)) {
@@ -1330,6 +1330,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
                 for (TableInfo tableInfo : tableInfoList) {
                     WbsTreeContract wbsTreeContract = wbsTreeContractService.getBaseMapper().selectOne(Wrappers.<WbsTreeContract>query().lambda()
                             .eq(WbsTreeContract::getPKeyId, tableInfo.getPkeyId()));
+                    StringBuilder tableName = new StringBuilder("");
                     if (wbsTreeContract == null) {
                         continue;
                     }
@@ -1402,13 +1403,18 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
 
                         transactionManager1.commit(transactionStatus);
                     } catch (Exception e) {
-                        transactionManager1.rollback(transactionStatus);
-                        log.append(e.getMessage()).append("@@");
-                        e.printStackTrace();
-                        return R.fail(reason(e.getMessage()));
+                        //是否回滚
+                        if(flag){
+                            transactionManager1.rollback(transactionStatus);
+                            log.append(e.getMessage()).append("@@");
+                            e.printStackTrace();
+                            return R.fail(reason(e.getMessage()));
+                        }else {
+                            tableName.append(wbsTreeContract.getNodeName()+",");
+                            RandomNumberHolder.setLogMessage(tableName.toString());
+                        }
                     }
                 }
-
                 //获取节点
                 WbsTreeContract wbsTreeContract = this.wbsTreeContractService.getOne(Wrappers.<WbsTreeContract>lambdaQuery().eq(WbsTreeContract::getPKeyId, tableInfoList.get(0).getPkeyId()));
                 WbsTreeContract wbsTreeContractByP = wbsTreeContractService.getBaseMapper().selectOne(Wrappers.<WbsTreeContract>query().lambda()
@@ -5613,6 +5619,14 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
             SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
             format= simpleDateFormat.format(mobilizationDate);
         }
+        String jingchang;
+        if(StringUtils.isNotEmpty(format)&&StringUtils.isNotEmpty(representativeCount)){
+            jingchang=format+"/"+representativeCount;
+        } else if (StringUtils.isNotEmpty(format)&&StringUtils.isEmpty(representativeCount)) {
+            jingchang=format;
+        }else {
+            jingchang=representativeCount;
+        }
         setFirstData(doc,"批号",sampleInfo.getBatchNumber(),reData,isCancelList);
         setFirstData(doc,"生产批号",sampleInfo.getBatchNumber(),reData,isCancelList);
         setFirstData(doc,"生产厂家",sampleInfo.getSupplierUnit(),reData,isCancelList);
@@ -5642,7 +5656,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
         setFirstData(doc,"用途(使用在何工程部位)",sampleInfo.getProposedPosition(),reData,isCancelList);
         setFirstData(doc,"成型日期",null,reData,isCancelList);
        // setFirstData(doc,"试件编号",sampleInfo.getSpecificationNumber(),reData,isCancel,isCancelList);
-        setFirstData(doc,"进场日期代表数量",format+"/"+representativeCount+calculationUnit,reData,isCancelList);
+        setFirstData(doc,"进场日期/ 代表数量",jingchang,reData,isCancelList);
         setFirstData(doc,"材料进场日期",format,reData,isCancelList);
 
         if(entrustInfo != null){
@@ -5720,12 +5734,10 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
      * @param reData
      */
     private static void  setFirstData(Document doc, String elementValue,Object value,Map<String, Object> reData,List<String> isCancelList) {
-
         if(value==null){
             value="";
         }
         Elements select = doc.select("[placeholderxx=" + elementValue + "]");
-
         if(select.isEmpty()){//没找到加上:继续找
             String elementValueNew = elementValue + ":";
             select = doc.select("[placeholderxx=" + elementValueNew + "]");
@@ -5733,53 +5745,38 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
         if(select.isEmpty()){// 以传入的参数为结尾 继续找
             select = doc.select("[placeholderxx$=" + elementValue + "]");
         }
-
         if (!select.isEmpty()) {//找到元素后  获取输入框
-
             Element textareaElement = select.stream().filter(element -> element.tagName().equals("el-input")).findFirst().orElse(null);
             if( (elementValue.contains("时间") || elementValue.contains("日期")) && textareaElement == null){//特殊处理日期 没有id属性获取keyName
                 textareaElement = select.first();
                 String keyName = textareaElement.attr("keyName");
                 if(ObjectUtil.isNotEmpty(value)){
-                    reData.put(keyName, value);
+                    if(!reData.containsKey(keyName)||reData.get(keyName)==null||reData.get(keyName).equals("")){
+                        reData.put(keyName, value);
+                    }
                 }
-
                 return ;
             }
             if(textareaElement != null){//正常情况
                 String id = textareaElement.attr("id");
                 isCancelList.add(id);
                 if(ObjectUtil.isNotEmpty(value)){
-                    reData.put(id, value);
+                    if(!reData.containsKey(id)||reData.get(id)==null||reData.get(id).equals("")){
+                        reData.put(id, value);
+                    }
                 }
             }
-
         } else {// 没有找到 可能格式不同 换一种方式找
             Elements select2 = doc.select("[titlexx$="+elementValue+"]");
-            if(select2.isEmpty()){//还是没找到  进入特殊情况
-                if(elementValue.equals("进场日期代表数量")){
-                    Elements select1 = doc.select("[titlexx=\"进场日期/ 代表数量\"]");
-                    Element textareaElement = select1.stream().filter(element -> element.tagName().equals("el-input")).findFirst().orElse(null);
-                    if(textareaElement != null){
-                        List<Node> nodes = textareaElement.childNodes();
-                        Node node = nodes.get(1);
-                        String id = node.attributes().get("id");
-                        if(ObjectUtil.isNotEmpty(value)){
-                            reData.put(id, value);
-                        }
-
-                    }
-                }else {
-                    System.out.println("没有找到[" + elementValue + "]的元素");
-                }
-            }else {
-                //另一种方式找到后 获取id的值并赋值到map
+            if(!select2.isEmpty()){
                 Element textareaElement = select2.first();
                 if(textareaElement != null){//正常情况
                     String id = textareaElement.attr("id");
                     isCancelList.add(id);
                     if(ObjectUtil.isNotEmpty(value)){
-                        reData.put(id, value);
+                        if(!reData.containsKey(id)||reData.get(id)==null||reData.get(id).equals("")){
+                            reData.put(id, value);
+                        }
                     }
                 }
             }

+ 1 - 1
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsParamServiceImpl.java

@@ -246,7 +246,7 @@ public class WbsParamServiceImpl extends BaseServiceImpl<WbsParamMapper, WbsPara
                         result.add(param);
                     }
                     //如果是全局的也加进去
-                    if(param.getNameType()==1){
+                    if(param.getNameType()!=null&&param.getNameType()==1){
                         result.add(param);
                     }
                 }

+ 2 - 2
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreeContractServiceImpl.java

@@ -4812,11 +4812,11 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
                     childContract.setAncestors(ancestors);
                     //wbsTreeContractMapper.updateAncestorsPid(ancestorsPId,ancestors,childContract.getPKeyId());
                 }
-                this.saveBatch(childContracts);
+                this.updateBatchById(childContracts);
             }
             //this.wbsTreeContractMapper.updateWbsTreeAncestors(contract);
         }
-        this.saveBatch(list);
+        this.updateBatchById(list);
         String ids = dto.getLeftPkeyIds().stream().map(id -> id + "").collect(Collectors.joining(","));
         this.wbsTreeContractStatisticsClient.updateAncestors(ids);
         return R.success("操作成功");

+ 12 - 1
blade-service/blade-manager/src/main/java/org/springblade/manager/utils/RandomNumberHolder.java

@@ -9,7 +9,8 @@ public class RandomNumberHolder {
         private static final ThreadLocal<HashMap<Long,String>> randomNumberThreadLocal = new ThreadLocal<>();
         private static final ThreadLocal<Integer> randomTemplateTypeThreadLocal = new ThreadLocal<>();
         private static final ThreadLocal<List<WbsTreeContract>> randomWbsTreeContractThreadLocal = new ThreadLocal<>();
-    private static final ThreadLocal<Long> randomTrialSelfInspectionRecordGroupId = new ThreadLocal<>();
+        private static final ThreadLocal<Long> randomTrialSelfInspectionRecordGroupId = new ThreadLocal<>();
+        private static final ThreadLocal<String> LogMessage =new ThreadLocal<>();
 
     public static void setRandomNumber(HashMap<Long,String> map) {
         randomNumberThreadLocal.set(map);
@@ -57,5 +58,15 @@ public class RandomNumberHolder {
     public static void clearTrialSelfInspectionRecordGroupId() {
         randomTrialSelfInspectionRecordGroupId.remove();
     }
+
+    public static String getLogMessage() {
+    	return LogMessage.get();
+    }
+    public static void setLogMessage(String logMessage) {
+    	LogMessage.set(logMessage);
+    }
+    public static void clearLogMessage() {
+    	LogMessage.remove();
+    }
 }
 

+ 9 - 0
blade-service/blade-websocket/pom.xml

@@ -35,6 +35,11 @@
             <artifactId>blade-manager-api</artifactId>
             <version>${bladex.project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-dingding-api</artifactId>
+            <version>${bladex.project.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.springblade</groupId>
             <artifactId>blade-business-api</artifactId>
@@ -58,6 +63,10 @@
                 </exclusion>
             </exclusions>
         </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-mapper-asl</artifactId>
+        </dependency>
     </dependencies>
 
     <properties>

+ 12 - 0
blade-service/blade-websocket/src/main/java/org/springblade/websocket/feign/WebSocketClientImpl.java

@@ -1,11 +1,16 @@
 package org.springblade.websocket.feign;
 
 import lombok.AllArgsConstructor;
+import org.springblade.dingding.vo.MeetingVo;
 import org.springblade.websocket.service.WebSocketService;
+import org.springblade.websocket.vo.MsgVO;
 import org.springblade.websocket.vo.SystMsgVO;
 import org.springblade.websocket.vo.UserInfoVO;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.util.List;
+
 /**
  * @Param
  * @Author wangwl
@@ -25,4 +30,11 @@ public class WebSocketClientImpl implements WebSocketClient{
     public void sendSystemMsg(SystMsgVO vo) {
         socketService.sendSystemMsg(vo);
     }
+
+    @Override
+    public void sendDingDingMsg(UserInfoVO vo) {
+        socketService.sendDingDingMsg(vo);
+    }
+
+
 }

+ 62 - 0
blade-service/blade-websocket/src/main/java/org/springblade/websocket/service/WebSocketService.java

@@ -2,6 +2,8 @@ package org.springblade.websocket.service;
 
 import io.undertow.websockets.jsr.UndertowSession;
 import lombok.Data;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.map.ObjectMapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springblade.business.feign.BusinessWebSocketClient;
@@ -9,10 +11,12 @@ import org.springblade.common.constant.ClientIdConstant;
 import org.springblade.common.constant.WebsocketMsgConstant;
 import org.springblade.core.tool.api.R;
 import org.springblade.core.tool.jackson.JsonUtil;
+import org.springblade.dingding.vo.MeetingVo;
 import org.springblade.feign.ArchiveWebSocketClient;
 import org.springblade.manager.feign.ManagerWebSocketClient;
 import org.springblade.meter.feign.MeterWebSocketClient;
 import org.springblade.websocket.entity.WebSocketClientInfo;
+import org.springblade.websocket.vo.DingDingMsg;
 import org.springblade.websocket.vo.MsgVO;
 import org.springblade.websocket.vo.SystMsgVO;
 import org.springblade.websocket.vo.UserInfoVO;
@@ -48,6 +52,8 @@ public class WebSocketService implements ApplicationContextAware {
     /** 后台*/
     private static ManagerWebSocketClient managerWebSocketClient;
 
+    private static final ObjectMapper objectMapper = new ObjectMapper();
+
     @Override
     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
         WebSocketService.meterWebSocketClient = applicationContext.getBean(MeterWebSocketClient.class);
@@ -76,6 +82,8 @@ public class WebSocketService implements ApplicationContextAware {
     private static Set<Session> clientSystemSessions = new CopyOnWriteArraySet<>();
     /** 档案系统session集合*/
     private static Set<Session> archivesSystemSessions = new CopyOnWriteArraySet<>();
+    /** 档案系统session集合*/
+    private static Set<Session> dingdingSystemSessions = new CopyOnWriteArraySet<>();
 
 //    /** 更新公告推送记录*/
 //    private static Set<UserSingleVO> updateMsgPushUsers = new HashSet<>();
@@ -156,6 +164,9 @@ public class WebSocketService implements ApplicationContextAware {
                 case ClientIdConstant.CLIENT_ID:
                     clientSystemSessions.add(session);
                     break;
+                case ClientIdConstant.DINGDING_ID:
+                    dingdingSystemSessions.add(session);
+                    break;
                 default:
                     log.error("未知的系统登录:"+system);
             }
@@ -186,6 +197,9 @@ public class WebSocketService implements ApplicationContextAware {
                 case ClientIdConstant.ARCHIVE_ID:
                     archivesSystemSessions.remove(session);
                     break;
+                case ClientIdConstant.DINGDING_ID:
+                    dingdingSystemSessions.remove(session);
+                    break;
                 default:
                     log.error("未知的系统退出:"+system);
             }
@@ -253,6 +267,10 @@ public class WebSocketService implements ApplicationContextAware {
         }
     }
 
+
+
+
+
     /**
      *  推送指定的系统的所有在线用户
      */
@@ -401,4 +419,48 @@ public class WebSocketService implements ApplicationContextAware {
         WebSocketService.onlineLinkCount--;
     }
 
+    public void sendDingDingMsg(UserInfoVO vo) {
+        List<Session> sessions = userInfoMap.get(vo);
+        if(sessions != null && sessions.size() > 0){
+            /** 此处不能使用普通集合,否则在推送消息时,当前用户又开启一个页面,集合发生变化迭代器会报错ConcurrentModificationException*/
+            for (Session s : sessions) {
+                if (s == null){
+                    continue;
+                }
+                RemoteEndpoint.Basic basicRemote = s.getBasicRemote();
+                /** 推送消息时可能因为nginx配置的连接时间,或者用户刚好断开连接,
+                 * 导致通道关闭,但是数组中使用的是快照,还存在这个连接,此时跳过推送给这个窗口*/
+                if (basicRemote != null){
+                    try {
+                        DingDingMsg dingMsg = new DingDingMsg();
+                        dingMsg.setMsgType(vo.getMsgType());
+                        dingMsg.setData(vo.getObject());
+                        // 将对象序列化为JSON字符串再发送
+                        String message = toJsonMessage(R.data(dingMsg));
+                        basicRemote.sendText(message);
+                    } catch (Exception e) {
+                        log.error(vo.getUserId()+"推送消息失败,消息内容["+ vo.getMsg()+"],原因:"+e.getMessage());
+                    }
+                }
+            }
+        }
+    }
+    public static String toJsonMessage(Object object) {
+        if (object == null) {
+            return "";
+        }
+
+        if (object instanceof String) {
+            return (String) object;
+        }
+
+        try {
+            return objectMapper.writeValueAsString(object);
+        } catch (JsonProcessingException e) {
+            log.error("对象序列化为JSON失败: {}", e.getMessage());
+            return object.toString();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
 }

+ 1 - 0
pom.xml

@@ -42,6 +42,7 @@
         <module>blade-service-api</module>
         <module>blade-service/blade-repair</module>
         <module>blade-service/blade-dingding</module>
+        <module>blade-service-api/blade-dingding-api</module>
     </modules>
 
     <dependencyManagement>