Sfoglia il codice sorgente

Merge branch 'master' of http://47.111.81.118:3000/uskycloud/usky-modules into fu-dev

fuyuchuan 1 mese fa
parent
commit
1ab131f40f
52 ha cambiato i file con 2281 aggiunte e 303 eliminazioni
  1. 3 0
      pom.xml
  2. 19 0
      service-ai/pom.xml
  3. 27 0
      service-ai/service-ai-api/pom.xml
  4. 88 0
      service-ai/service-ai-biz/pom.xml
  5. 40 0
      service-ai/service-ai-biz/src/main/java/com/usky/ai/AIChatApplication.java
  6. 536 0
      service-ai/service-ai-biz/src/main/java/com/usky/ai/controller/web/AiChatController.java
  7. 43 0
      service-ai/service-ai-biz/src/main/java/com/usky/ai/controller/web/AiQuestionController.java
  8. 94 0
      service-ai/service-ai-biz/src/main/java/com/usky/ai/controller/web/AiSessionController.java
  9. 41 0
      service-ai/service-ai-biz/src/main/java/com/usky/ai/mapper/AiQuestionMapper.java
  10. 37 0
      service-ai/service-ai-biz/src/main/java/com/usky/ai/mapper/AiSessionMapper.java
  11. 70 0
      service-ai/service-ai-biz/src/main/java/com/usky/ai/service/AiQuestion.java
  12. 51 0
      service-ai/service-ai-biz/src/main/java/com/usky/ai/service/AiQuestionItem.java
  13. 48 0
      service-ai/service-ai-biz/src/main/java/com/usky/ai/service/AiSession.java
  14. 14 0
      service-ai/service-ai-biz/src/main/java/com/usky/ai/service/config/AiChatConfig.java
  15. 19 0
      service-ai/service-ai-biz/src/main/java/com/usky/ai/service/config/MyGlobalCorsConfig.java
  16. 14 0
      service-ai/service-ai-biz/src/main/java/com/usky/ai/service/config/WebConfig.java
  17. 22 0
      service-ai/service-ai-biz/src/main/java/com/usky/ai/service/vo/AiStreamOutputVO.java
  18. 24 0
      service-ai/service-ai-biz/src/main/resources/bootstrap.yml
  19. 94 0
      service-ai/service-ai-biz/src/main/resources/logback.xml
  20. 149 0
      service-ai/service-ai-biz/src/main/resources/static/dpsk.html
  21. 149 0
      service-ai/service-ai-biz/src/main/resources/static/tyqw.html
  22. 12 0
      service-eg/service-eg-biz/src/main/java/com/usky/eg/domain/EgDevice.java
  23. 2 0
      service-eg/service-eg-biz/src/main/java/com/usky/eg/service/EgDeviceService.java
  24. 51 18
      service-eg/service-eg-biz/src/main/java/com/usky/eg/service/impl/EgDeviceServiceImpl.java
  25. 2 0
      service-eg/service-eg-biz/src/main/resources/mapper/eg/EgDeviceMapper.xml
  26. 51 47
      service-fire/service-fire-biz/src/main/java/com/usky/fire/service/impl/PatrolInspectionPlanSonServiceImpl.java
  27. 1 1
      service-iot/service-iot-biz/src/main/java/com/usky/iot/controller/web/DmpProductInfoController.java
  28. 34 4
      service-iot/service-iot-biz/src/main/java/com/usky/iot/controller/web/PmTimeConfController.java
  29. 21 0
      service-iot/service-iot-biz/src/main/java/com/usky/iot/controller/web/VcDeviceController.java
  30. 5 0
      service-iot/service-iot-biz/src/main/java/com/usky/iot/domain/DmpDeviceType.java
  31. 5 0
      service-iot/service-iot-biz/src/main/java/com/usky/iot/domain/PmTimeConf.java
  32. 1 0
      service-iot/service-iot-biz/src/main/java/com/usky/iot/mapper/BaseFacilityTypeMapper.java
  33. 2 1
      service-iot/service-iot-biz/src/main/java/com/usky/iot/mapper/PmWorkContentMapper.java
  34. 1 1
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/DmpProductInfoService.java
  35. 13 0
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/PmTimeConfService.java
  36. 5 0
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/VcDeviceService.java
  37. 69 0
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/config/DeviceOperate.java
  38. 61 58
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/BaseAlarmServiceImpl.java
  39. 0 1
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/BaseBuildServiceImpl.java
  40. 12 4
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/BaseGgpFacilityServiceImpl.java
  41. 8 45
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/DmpDeviceInfoServiceImpl.java
  42. 106 58
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/DmpProductInfoServiceImpl.java
  43. 11 26
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/PmProjectServiceImpl.java
  44. 79 1
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/PmTimeConfServiceImpl.java
  45. 15 8
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/PmWorkReportServiceImpl.java
  46. 71 3
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/VcDeviceServiceImpl.java
  47. 17 17
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/vo/BaseGgpFacilityExportVo.java
  48. 34 9
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/vo/FacilityImportVo.java
  49. 4 0
      service-iot/service-iot-biz/src/main/resources/mapper/iot/BaseFacilityTypeMapper.xml
  50. 1 0
      service-iot/service-iot-biz/src/main/resources/mapper/iot/DmpDeviceTypeMapper.xml
  51. 3 0
      service-iot/service-iot-biz/src/main/resources/mapper/iot/PmTimeConfMapper.xml
  52. 2 1
      service-iot/service-iot-biz/src/main/resources/mapper/iot/PmWorkContentMapper.xml

+ 3 - 0
pom.xml

@@ -90,6 +90,9 @@
 
     <module>service-oa</module>
 
+
+    <module>service-ai</module>
+
   </modules>
           
   

+ 19 - 0
service-ai/pom.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<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>usky-modules</artifactId>
+        <groupId>com.usky</groupId>
+        <version>0.0.1</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>service-ai</artifactId>
+    <packaging>pom</packaging>
+    <version>0.0.1</version>
+
+    <modules>
+        <module>service-ai-biz</module>
+        <module>service-ai-api</module>
+    </modules>
+</project>

+ 27 - 0
service-ai/service-ai-api/pom.xml

@@ -0,0 +1,27 @@
+<?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>service-ai</artifactId>
+        <groupId>com.usky</groupId>
+        <version>0.0.1</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>service-ai-api</artifactId>
+    <!-- SpringCloud Openfeign -->
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-openfeign</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.usky</groupId>
+            <artifactId>usky-common-core</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>${project.artifactId}</finalName>
+    </build>
+
+</project>

+ 88 - 0
service-ai/service-ai-biz/pom.xml

@@ -0,0 +1,88 @@
+<?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>service-ai</artifactId>
+        <groupId>com.usky</groupId>
+        <version>0.0.1</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>service-ai-biz</artifactId>
+    <dependencies>
+        <dependency>
+            <groupId>com.usky</groupId>
+            <artifactId>common-cloud-starter</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.usky</groupId>
+            <artifactId>service-ai-api</artifactId>
+            <version>0.0.1</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.usky</groupId>
+            <artifactId>ruoyi-common-swagger</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.mybatis.spring.boot</groupId>
+            <artifactId>mybatis-spring-boot-starter</artifactId>
+            <version>2.1.4</version>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+
+        <!-- 阿里dashscope依赖 -->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>dashscope-sdk-java</artifactId>
+            <version>2.14.0</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-simple</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+
+    </dependencies>
+
+    <build>
+        <finalName>${project.artifactId}</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.2.6.RELEASE</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>com.github.shalousun</groupId>
+                <artifactId>smart-doc-maven-plugin</artifactId>
+                <version>2.1.1</version>
+                <configuration>
+                    <!--指定生成文档的使用的配置文件,配置文件放在自己的项目中-->
+                    <configFile>./src/main/resources/smart-doc.json</configFile>
+                    <!--指定项目名称-->
+                    <projectName>test</projectName>
+                    <!--                    <excludes>-->
+                    <!--                        <exclude>com.bizmatics:product-service-provider</exclude>-->
+                    <!--                        <exclude>cn.afterturn:easypoi-web</exclude>-->
+                    <!--                    </excludes>-->
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 40 - 0
service-ai/service-ai-biz/src/main/java/com/usky/ai/AIChatApplication.java

@@ -0,0 +1,40 @@
+package com.usky.ai;
+
+import com.ruoyi.common.swagger.annotation.EnableCustomSwagger2;
+import org.mybatis.spring.annotation.MapperScan;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
+import org.springframework.core.env.Environment;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+@EnableCustomSwagger2
+@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
+@EnableFeignClients(basePackages = {"com.usky"})
+@MapperScan(value = "com.usky.ai.mapper")
+@ComponentScan(basePackages = {"com.usky"})
+@SpringBootApplication
+public class AIChatApplication {
+        private static final Logger LOGGER = LoggerFactory.getLogger(AIChatApplication.class);
+
+        public static void main (String[]args) throws UnknownHostException {
+        ConfigurableApplicationContext application = SpringApplication.run(AIChatApplication.class, args);
+        Environment env = application.getEnvironment();
+        String ip = InetAddress.getLocalHost().getHostAddress();
+        String port = env.getProperty("server.port");
+        String path = env.getProperty("server.servlet.context-path");
+        LOGGER.info("\n----------------------------------------------------------\n\t" +
+                "Application is running! Access URLs:\n\t" +
+                "Local: \t\thttp://localhost:" + port + (null == path ? "" : path) + "/\n\t" +
+                "External: \thttp://" + ip + ":" + port + (null == path ? "" : path) + "/\n\t" +
+                "Api: \t\thttp://" + ip + ":" + port + (null == path ? "" : path) + "/swagger-ui/index.html\n\t" +
+                "----------------------------------------------------------");
+       }
+}

+ 536 - 0
service-ai/service-ai-biz/src/main/java/com/usky/ai/controller/web/AiChatController.java

@@ -0,0 +1,536 @@
+package com.usky.ai.controller.web;
+
+import com.alibaba.dashscope.aigc.generation.Generation;
+import com.alibaba.dashscope.aigc.generation.GenerationParam;
+import com.alibaba.dashscope.common.Message;
+import com.alibaba.dashscope.common.Role;
+import com.alibaba.dashscope.exception.ApiException;
+import com.alibaba.dashscope.exception.InputRequiredException;
+import com.alibaba.dashscope.exception.NoApiKeyException;
+import com.alibaba.fastjson.JSONObject;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.usky.ai.mapper.AiQuestionMapper;
+import com.usky.ai.mapper.AiSessionMapper;
+import com.usky.ai.service.AiQuestion;
+import com.usky.ai.service.AiQuestionItem;
+import com.usky.ai.service.AiSession;
+import com.usky.ai.service.vo.AiStreamOutputVO;
+import com.usky.common.core.bean.ApiResult;
+import com.usky.common.security.utils.SecurityUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
+
+import javax.annotation.Resource;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Slf4j
+@RestController
+@RequestMapping("/ai")
+public class AiChatController {
+
+    @Value("${ai.api.key}")
+    private String apiKey;
+
+    @Value("${airole}")
+    private String aiRole;
+
+    @Value("${aliTyqw.model}")
+    private String tyqwModel;
+
+    @Value("${aliDpsk.model}")
+    private String dpskModel;
+
+    @Value("${ai.historyLimit}")
+    private int Limit;
+
+    @Value("${ai.millis}")
+    private int millis;
+
+    @Resource
+    private Generation generation;
+
+    @Autowired
+    private AiQuestionMapper aiQuestionMapper;
+
+    @Autowired
+    private AiSessionMapper aiSessionMapper;
+
+    private final ObjectMapper objectMapper = new ObjectMapper();
+
+    // 阿里百炼通义千问大模型(修改后)
+    @PostMapping(value = "/aliTyqw", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
+    public ResponseEntity<StreamingResponseBody> send1(@RequestBody JSONObject object) throws NoApiKeyException, InputRequiredException {
+        // 获取当前登录用户的信息
+        Long userId = SecurityUtils.getUserId();
+        String userName = SecurityUtils.getLoginUser().getSysUser().getNickName();
+        String sessionId = null;
+        String content = object.get("content").toString();
+
+        // 如果没有传入 sessionId,则创建一个新的会话ID
+        if (object.containsKey("sessionId")) {
+            sessionId = object.get("sessionId").toString();
+        } else {
+            sessionId = java.util.UUID.randomUUID().toString();
+        }
+
+        // 解析 JSON 并提取 "content" 字段的值
+        String questionText = content;
+
+        // 检查是否已经存在相同的 sessionId
+        boolean exists = aiSessionMapper.existsBySessionId(sessionId);
+
+        if (!exists) {
+            // 创建新的 AiSession 实体并存入数据库
+            AiSession aiSession = new AiSession();
+            aiSession.setSessionId(sessionId);
+            aiSession.setUserId(userId);
+            aiSession.setUserName(userName);
+            aiSession.setQuestion(questionText);
+            aiSession.setAskTime(LocalDateTime.now());
+            aiSessionMapper.save(aiSession);
+        }
+
+        // 构建消息列表,包含角色定义、历史对话记录和用户新消息
+        List<Message> messages = new ArrayList<>();
+
+        // 插入角色定义(在对话历史的开头)
+        Message roleDefinition = Message.builder()
+                .role(Role.SYSTEM.getValue()) // 使用系统角色
+                .content(aiRole) // 定义角色的行为和风格
+                .build();
+        messages.add(roleDefinition); // 将角色定义插入到对话历史的开头
+
+        // 从数据库中获取历史对话记录
+        List<AiQuestion> questions = aiQuestionMapper.findQuestionsBySessionId(sessionId);
+
+        // 如果历史记录超过限制,则只取最近的记录
+        if (questions.size() > Limit) {
+            questions = questions.subList(questions.size() - Limit, questions.size());
+        }
+
+        // 将历史对话记录转换为 AiQuestionItem 列表
+        List<AiQuestionItem> itemList = new ArrayList<>();
+        for (AiQuestion question : questions) {
+            AiQuestionItem userItem = new AiQuestionItem("user", question.getQuestion());
+            userItem.setId(question.getId());
+            userItem.setSessionId(question.getSessionId());
+            userItem.setUserId(question.getUserId());
+            userItem.setUserName(question.getUserName());
+            userItem.setAskTime(question.getAskTime());
+
+            AiQuestionItem assistantItem = new AiQuestionItem("assistant", question.getAnswer());
+            assistantItem.setId(question.getId());
+            assistantItem.setSessionId(question.getSessionId());
+            assistantItem.setUserId(question.getUserId());
+            assistantItem.setUserName(question.getUserName());
+            assistantItem.setAskTime(question.getAskTime());
+
+            itemList.add(userItem);
+            itemList.add(assistantItem);
+        }
+
+        // 将 AiQuestionItem 列表转换为消息列表
+        for (AiQuestionItem item : itemList) {
+            Message message = Message.builder()
+                    .role(item.getRole().equals("user") ? Role.USER.getValue() : Role.ASSISTANT.getValue())
+                    .content(item.getContent() != null ? item.getContent() : item.getReasoningContent())
+                    .build();
+            messages.add(message);
+        }
+
+        // 添加用户的新消息
+        Message userMessage = Message.builder()
+                .role(Role.USER.getValue())
+                .content(questionText) // 使用提取的文本
+                .build();
+        messages.add(userMessage);
+
+        // 构建模型调用参数
+        GenerationParam param = GenerationParam.builder()
+                .model(tyqwModel)
+                .messages(messages)
+                .resultFormat(GenerationParam.ResultFormat.MESSAGE)
+                .topP(0.8)
+                .apiKey(apiKey)
+                .incrementalOutput(true) // 开启增量输出
+                .enableSearch(true)  // 联网搜索
+                .build();
+
+        String finalSessionId = sessionId;
+        StringBuilder completeAnswer = new StringBuilder(); // 用于收集完整的回答内容
+        return ResponseEntity.ok()
+                .contentType(MediaType.TEXT_EVENT_STREAM)
+                .body(outputStream -> {
+                    try {
+// 调用流式接口
+                        generation.streamCall(param).blockingForEach(chunk -> {
+                            try {
+                                // 获取每次生成的内容
+                                String partialAnswer = chunk.getOutput().getChoices().get(0).getMessage().getContent();
+
+                                // 检查内容是否为空,如果为空则跳过
+                                if (partialAnswer == null || partialAnswer.trim().isEmpty()) {
+                                    return; // 如果内容为空,直接返回,不进行后续操作
+                                }
+
+                                // 构建输出对象
+                                AiStreamOutputVO aiStreamOutputVO = new AiStreamOutputVO();
+                                aiStreamOutputVO.setSessionId(finalSessionId);
+                                aiStreamOutputVO.setReasoningContent(partialAnswer);
+
+                                // 转换为 JSON 字符串
+                                String newString = objectMapper.writeValueAsString(aiStreamOutputVO);
+
+                                // 写入输出流
+                                outputStream.write(("data: " + newString + "\n\n").getBytes(StandardCharsets.UTF_8));
+                                outputStream.flush(); // 确保立即发送到前端
+
+                                // 累加到完整回答内容中
+                                completeAnswer.append(partialAnswer);
+
+                                // 添加延迟
+                                try {
+                                    Thread.sleep(millis); // 延迟*毫秒
+                                } catch (InterruptedException e) {
+                                    Thread.currentThread().interrupt();
+                                    log.error("Thread interrupted", e);
+                                }
+
+                            } catch (Exception e) {
+                                log.error("Error processing chunk", e);
+                                outputStream.write(("data: Error processing chunk\n\n").getBytes(StandardCharsets.UTF_8));
+                                outputStream.flush();
+                            }
+                        });
+
+                        // 流式接口调用完成后,将完整回答存入数据库
+                        AiQuestion aiQuestion = new AiQuestion();
+                        aiQuestion.setModel(tyqwModel);
+                        aiQuestion.setSessionId(finalSessionId);
+                        aiQuestion.setUserId(userId);
+                        aiQuestion.setUserName(userName);
+                        aiQuestion.setQuestion(questionText);
+                        aiQuestion.setAnswer(completeAnswer.toString());
+                        aiQuestion.setAskTime(LocalDateTime.now());
+                        aiQuestionMapper.save(aiQuestion);
+
+                    } catch (ApiException e) {
+                        log.error("Error processing request", e);
+                        outputStream.write(("data: Error processing request\n\n").getBytes(StandardCharsets.UTF_8));
+                        outputStream.flush();
+                    } catch (NoApiKeyException | InputRequiredException e) {
+                        throw new RuntimeException(e);
+                    }
+                });
+    }
+
+    // 阿里百炼DeepSeek大模型
+    @PostMapping(value = "/aliDeepSeek", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
+    public ResponseEntity<StreamingResponseBody> send2(@RequestBody JSONObject object )throws NoApiKeyException, InputRequiredException {
+        // 获取当前登录用户的信息
+        Long userId = SecurityUtils.getUserId();
+        String userName = SecurityUtils.getLoginUser().getSysUser().getNickName();
+        String sessionId = null;
+        String content = object.get("content").toString();
+
+        // 如果没有传入 sessionId,则创建一个新的会话ID
+        if (object.containsKey("sessionId")) {
+            sessionId = object.get("sessionId").toString();
+        } else {
+            sessionId = java.util.UUID.randomUUID().toString();
+        }
+
+        // 解析 JSON 并提取 "content" 字段的值
+        String questionText = content;
+
+        // 检查是否已经存在相同的 sessionId
+        boolean exists = aiSessionMapper.existsBySessionId(sessionId);
+
+        if (!exists) {
+            // 创建新的 AiSession 实体并存入数据库
+            AiSession aiSession = new AiSession();
+            aiSession.setSessionId(sessionId);
+            aiSession.setUserId(userId);
+            aiSession.setUserName(userName);
+            aiSession.setQuestion(questionText);
+            aiSession.setAskTime(LocalDateTime.now());
+            aiSessionMapper.save(aiSession);
+        }
+
+        // 构建消息列表,包含角色定义、历史对话记录和用户新消息
+        List<Message> messages = new ArrayList<>();
+
+        // 插入角色定义(在对话历史的开头)
+        Message roleDefinition = Message.builder()
+                .role(Role.SYSTEM.getValue()) // 使用系统角色
+                .content(aiRole) // 定义角色的行为和风格
+                .build();
+        messages.add(roleDefinition); // 将角色定义插入到对话历史的开头
+
+        // 从数据库中获取历史对话记录
+        List<AiQuestion> questions = aiQuestionMapper.findQuestionsBySessionId(sessionId);
+
+        // 如果历史记录超过限制,则只取最近的记录
+        if (questions.size() > Limit) {
+            questions = questions.subList(questions.size() - Limit, questions.size());
+        }
+
+        // 将历史对话记录转换为 AiQuestionItem 列表
+        List<AiQuestionItem> itemList = new ArrayList<>();
+        for (AiQuestion question : questions) {
+            AiQuestionItem userItem = new AiQuestionItem("user", question.getQuestion());
+            userItem.setId(question.getId());
+            userItem.setSessionId(question.getSessionId());
+            userItem.setUserId(question.getUserId());
+            userItem.setUserName(question.getUserName());
+            userItem.setAskTime(question.getAskTime());
+
+            AiQuestionItem assistantItem = new AiQuestionItem("assistant", question.getAnswer());
+            assistantItem.setId(question.getId());
+            assistantItem.setSessionId(question.getSessionId());
+            assistantItem.setUserId(question.getUserId());
+            assistantItem.setUserName(question.getUserName());
+            assistantItem.setAskTime(question.getAskTime());
+
+            itemList.add(userItem);
+            itemList.add(assistantItem);
+        }
+
+        // 将 AiQuestionItem 列表转换为消息列表
+        for (AiQuestionItem item : itemList) {
+            Message message = Message.builder()
+                    .role(item.getRole().equals("user") ? Role.USER.getValue() : Role.ASSISTANT.getValue())
+                    .content(item.getContent() != null ? item.getContent() : item.getReasoningContent())
+                    .build();
+            messages.add(message);
+        }
+
+        // 添加用户的新消息
+        Message userMessage = Message.builder()
+                .role(Role.USER.getValue())
+                .content(questionText) // 使用提取的文本
+                .build();
+        messages.add(userMessage);
+
+        // 构建模型调用参数
+        GenerationParam param = GenerationParam.builder()
+                .model(dpskModel)
+                .messages(messages)
+                .resultFormat(GenerationParam.ResultFormat.MESSAGE)
+                .apiKey(apiKey)
+                .incrementalOutput(true) // 开启增量输出[^1^]
+                .build();
+
+        String finalSessionId = sessionId;
+        StringBuilder completeAnswer = new StringBuilder(); // 用于收集完整的回答内容
+        return ResponseEntity.ok()
+                .contentType(MediaType.TEXT_EVENT_STREAM)
+                .body(outputStream -> {
+                    try {
+                        // 调用流式接口
+                        generation.streamCall(param).blockingForEach(chunk -> {
+                            try {
+                                // 获取每次生成的内容
+                                String partialAnswer = chunk.getOutput().getChoices().get(0).getMessage().getContent();
+
+                                // 检查内容是否为空,如果为空则跳过
+                                if (partialAnswer == null || partialAnswer.trim().isEmpty()) {
+                                    return; // 如果内容为空,直接返回,不进行后续操作
+                                }
+
+                                // 构建输出对象
+                                AiStreamOutputVO aiStreamOutputVO = new AiStreamOutputVO();
+                                aiStreamOutputVO.setSessionId(finalSessionId);
+                                aiStreamOutputVO.setReasoningContent(partialAnswer);
+
+                                // 转换为 JSON 字符串
+                                String newString = objectMapper.writeValueAsString(aiStreamOutputVO);
+
+                                // 写入输出流
+                                outputStream.write(("data: " + newString + "\n\n").getBytes(StandardCharsets.UTF_8));
+                                outputStream.flush(); // 确保立即发送到前端
+
+                                // 累加到完整回答内容中
+                                completeAnswer.append(partialAnswer);
+
+                                // 添加延迟
+                                try {
+                                    Thread.sleep(millis); // 延迟*毫秒
+                                } catch (InterruptedException e) {
+                                    Thread.currentThread().interrupt();
+                                    log.error("Thread interrupted", e);
+                                }
+
+                            } catch (Exception e) {
+                                log.error("Error processing chunk", e);
+                                outputStream.write(("data: Error processing chunk\n\n").getBytes(StandardCharsets.UTF_8));
+                                outputStream.flush();
+                            }
+                        });
+
+                        // 流式接口调用完成后,将完整回答存入数据库
+                        AiQuestion aiQuestion = new AiQuestion();
+                        aiQuestion.setModel(dpskModel);
+                        aiQuestion.setSessionId(finalSessionId);
+                        aiQuestion.setUserId(userId);
+                        aiQuestion.setUserName(userName);
+                        aiQuestion.setQuestion(questionText);
+                        aiQuestion.setAnswer(completeAnswer.toString());
+                        aiQuestion.setAskTime(LocalDateTime.now());
+                        aiQuestionMapper.save(aiQuestion);
+
+                    } catch (ApiException e) {
+                        log.error("Error processing request", e);
+                        outputStream.write(("data: Error processing request\n\n").getBytes(StandardCharsets.UTF_8));
+                        outputStream.flush();
+                    } catch (NoApiKeyException | InputRequiredException e) {
+                        throw new RuntimeException(e);
+                    }
+                });
+    }
+
+    @PostMapping(value = "/aliTyqw-test")
+    public ResponseEntity<AiStreamOutputVO> send3(@RequestBody JSONObject object) throws NoApiKeyException, InputRequiredException {
+        // 获取当前登录用户的信息
+        Long userId = SecurityUtils.getUserId();
+        String userName = SecurityUtils.getLoginUser().getSysUser().getNickName();
+        String sessionId = null;
+        String content = object.get("content").toString();
+
+        // 如果没有传入 sessionId,则创建一个新的会话ID
+        if (object.containsKey("sessionId")) {
+            sessionId = object.get("sessionId").toString();
+        } else {
+            sessionId = java.util.UUID.randomUUID().toString();
+        }
+
+        // 解析 JSON 并提取 "content" 字段的值
+        String questionText = content;
+
+        // 检查是否已经存在相同的 sessionId
+        boolean exists = aiSessionMapper.existsBySessionId(sessionId);
+
+        if (!exists) {
+            // 创建新的 AiSession 实体并存入数据库
+            AiSession aiSession = new AiSession();
+            aiSession.setSessionId(sessionId);
+            aiSession.setUserId(userId);
+            aiSession.setUserName(userName);
+            aiSession.setQuestion(questionText);
+            aiSession.setAskTime(LocalDateTime.now());
+            aiSessionMapper.save(aiSession);
+        }
+
+        // 构建消息列表,包含角色定义、历史对话记录和用户新消息
+        List<Message> messages = new ArrayList<>();
+
+        // 插入角色定义(在对话历史的开头)
+        Message roleDefinition = Message.builder()
+                .role(Role.SYSTEM.getValue()) // 使用系统角色
+                .content(aiRole) // 定义角色的行为和风格
+                .build();
+        messages.add(roleDefinition); // 将角色定义插入到对话历史的开头
+
+        // 从数据库中获取历史对话记录
+        List<AiQuestion> questions = aiQuestionMapper.findQuestionsBySessionId(sessionId);
+
+        // 如果历史记录超过限制,则只取最近的记录
+        if (questions.size() > Limit) {
+            questions = questions.subList(questions.size() - Limit, questions.size());
+        }
+
+        // 将历史对话记录转换为 AiQuestionItem 列表
+        List<AiQuestionItem> itemList = new ArrayList<>();
+        for (AiQuestion question : questions) {
+            AiQuestionItem userItem = new AiQuestionItem("user", question.getQuestion());
+            userItem.setId(question.getId());
+            userItem.setSessionId(question.getSessionId());
+            userItem.setUserId(question.getUserId());
+            userItem.setUserName(question.getUserName());
+            userItem.setAskTime(question.getAskTime());
+
+            AiQuestionItem assistantItem = new AiQuestionItem("assistant", question.getAnswer());
+            assistantItem.setId(question.getId());
+            assistantItem.setSessionId(question.getSessionId());
+            assistantItem.setUserId(question.getUserId());
+            assistantItem.setUserName(question.getUserName());
+            assistantItem.setAskTime(question.getAskTime());
+
+            itemList.add(userItem);
+            itemList.add(assistantItem);
+        }
+
+        // 将 AiQuestionItem 列表转换为消息列表
+        for (AiQuestionItem item : itemList) {
+            Message message = Message.builder()
+                    .role(item.getRole().equals("user") ? Role.USER.getValue() : Role.ASSISTANT.getValue())
+                    .content(item.getContent() != null ? item.getContent() : item.getReasoningContent())
+                    .build();
+            messages.add(message);
+        }
+
+        // 添加用户的新消息
+        Message userMessage = Message.builder()
+                .role(Role.USER.getValue())
+                .content(questionText) // 使用提取的文本
+                .build();
+        messages.add(userMessage);
+
+        // 构建模型调用参数
+        GenerationParam param = GenerationParam.builder()
+                .model(tyqwModel)
+                .messages(messages)
+                .resultFormat(GenerationParam.ResultFormat.MESSAGE)
+                .topP(0.8)
+                .apiKey(apiKey)
+                .incrementalOutput(false) // 关闭增量输出
+                .enableSearch(true)  // 联网搜索
+                .build();
+
+        try {
+            // 调用非流式接口
+            String completeAnswer = generation.call(param).getOutput().getChoices().get(0).getMessage().getContent();
+
+            // 将完整回答存入数据库
+            AiQuestion aiQuestion = new AiQuestion();
+            aiQuestion.setModel(tyqwModel);
+            aiQuestion.setSessionId(sessionId);
+            aiQuestion.setUserId(userId);
+            aiQuestion.setUserName(userName);
+            aiQuestion.setQuestion(questionText);
+            aiQuestion.setAnswer(completeAnswer);
+            aiQuestion.setAskTime(LocalDateTime.now());
+            aiQuestionMapper.save(aiQuestion);
+
+            // 构建返回对象
+            AiStreamOutputVO aiStreamOutputVO = new AiStreamOutputVO();
+            aiStreamOutputVO.setSessionId(sessionId);
+            aiStreamOutputVO.setReasoningContent(completeAnswer);
+
+            // 返回完整回答给前端
+            return ResponseEntity.ok(aiStreamOutputVO);
+        } catch (ApiException e) {
+            log.error("Error processing request", e);
+
+            // 构建错误返回对象
+            AiStreamOutputVO aiStreamOutputVO = new AiStreamOutputVO();
+            aiStreamOutputVO.setSessionId(sessionId);
+            aiStreamOutputVO.setReasoningContent("Error processing request");
+
+            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(aiStreamOutputVO);
+        } catch (NoApiKeyException | InputRequiredException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}

+ 43 - 0
service-ai/service-ai-biz/src/main/java/com/usky/ai/controller/web/AiQuestionController.java

@@ -0,0 +1,43 @@
+package com.usky.ai.controller.web;
+
+import com.usky.ai.mapper.AiQuestionMapper;
+import com.usky.ai.service.AiQuestion;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@Slf4j
+@RestController
+@RequestMapping("/questions")
+public class AiQuestionController {
+
+    @Autowired
+    private AiQuestionMapper aiQuestionMapper;
+
+    // 查询所有数据
+    @GetMapping("/all")
+    public List<AiQuestion> getAllQuestions() {
+        return aiQuestionMapper.findAll();
+    }
+
+    // 根据 userId 查询数据
+    @GetMapping("/user/{userId}")
+    public List<AiQuestion> getQuestionsByUserId(@PathVariable Long userId) {
+        return aiQuestionMapper.findByUserId(userId);
+    }
+
+    // 根据 id 删除数据
+    @DeleteMapping("/deleted/{id}")
+    public String deleteQuestion(@PathVariable Long id) {
+        aiQuestionMapper.deleteById(id);
+        return "Question with id " + id + " deleted successfully.";
+    }
+
+    // 根据 sessionId 查询数据
+    @GetMapping("/session/{sessionId}")
+    public List<AiQuestion> getQuestionsBySessionId(@PathVariable String sessionId) {
+        return aiQuestionMapper.findBySessionId(sessionId);
+    }
+}

+ 94 - 0
service-ai/service-ai-biz/src/main/java/com/usky/ai/controller/web/AiSessionController.java

@@ -0,0 +1,94 @@
+package com.usky.ai.controller.web;
+
+import com.usky.ai.mapper.AiQuestionMapper;
+import com.usky.ai.mapper.AiSessionMapper;
+import com.usky.ai.service.AiQuestion;
+import com.usky.ai.service.AiQuestionItem;
+import com.usky.ai.service.AiSession;
+import com.usky.common.core.bean.ApiResult;
+import com.usky.common.security.utils.SecurityUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Slf4j
+@RestController
+@RequestMapping("/session")
+public class AiSessionController {
+
+    @Autowired
+    private AiSessionMapper aiSessionMapper;
+
+    @Autowired
+    private AiQuestionMapper aiQuestionMapper;
+
+    @GetMapping("/all")
+    public List<AiSession> getAllSessions() {
+        return aiSessionMapper.findAll();
+    }
+
+    @GetMapping("/current")
+    public List<AiSession> getCurrentSessions(@RequestHeader("Authorization") String token) {
+        // 解析 token 获取 userId
+        Long userId = SecurityUtils.getUserId();
+        return getSessionsByUserId(userId);
+    }
+
+    public List<AiSession> getSessionsByUserId(Long userId) {
+        List<AiSession> sessions = aiSessionMapper.findByUserId(userId);
+
+        for (AiSession session : sessions) {
+            List<AiQuestion> questions = aiQuestionMapper.findQuestionsBySessionId(session.getSessionId());
+            List<AiQuestionItem> itemList = new ArrayList<>();
+
+            for (AiQuestion question : questions) {
+                AiQuestionItem userItem = new AiQuestionItem("user", question.getQuestion());
+                userItem.setId(question.getId());
+                userItem.setSessionId(question.getSessionId());
+                userItem.setUserId(question.getUserId());
+                userItem.setUserName(question.getUserName());
+                userItem.setAskTime(question.getAskTime());
+                // 不设置 reasoningContent,因为 role 是 user
+
+                itemList.add(userItem);
+
+                AiQuestionItem assistantItem = new AiQuestionItem("assistant", null); // 初始化 content 为 null
+                assistantItem.setId(question.getId());
+                assistantItem.setSessionId(question.getSessionId());
+                assistantItem.setUserId(question.getUserId());
+                assistantItem.setUserName(question.getUserName());
+                assistantItem.setAskTime(question.getAskTime());
+                assistantItem.setReasoningContent(question.getAnswer()); // 设置 reasoningContent
+                // 不设置 content,因为 role 是 assistant
+
+                itemList.add(assistantItem);
+            }
+
+            session.setItemList(itemList);
+        }
+
+        return ApiResult.success(sessions).getData();
+    }
+
+    @PostMapping("/update")
+    public ApiResult updateSession(@RequestBody AiSession aiSession) {
+        aiSessionMapper.updateQuestion(aiSession.getSessionId(), aiSession.getQuestion());
+        return ApiResult.success("更新会话成功");
+    }
+
+    @DeleteMapping("/delete")
+    public ApiResult deleteSession(@RequestParam String sessionId) {
+        try {
+            aiSessionMapper.delete(sessionId);
+            aiQuestionMapper.delete(sessionId);
+            return ApiResult.success("删除会话成功");
+        } catch (Exception e) {
+            // 如果出现异常,可以记录日志或者返回错误信息
+            log.error("删除会话失败", e);
+            return ApiResult.error("删除会话失败");
+        }
+    }
+}

+ 41 - 0
service-ai/service-ai-biz/src/main/java/com/usky/ai/mapper/AiQuestionMapper.java

@@ -0,0 +1,41 @@
+package com.usky.ai.mapper;
+
+import com.usky.ai.service.AiQuestion;
+import org.apache.ibatis.annotations.*;
+
+import java.util.List;
+
+@Mapper
+public interface AiQuestionMapper {
+    @Insert("INSERT INTO ai_questions (model, session_id, user_id, user_name, question, answer, ask_time) " +
+            "VALUES (#{model},  #{sessionId}, #{userId}, #{userName}, #{question}, #{answer}, #{askTime})")
+    void save(AiQuestion aiQuestion);
+
+    // 查询所有数据
+    @Select("SELECT * FROM ai_questions ORDER BY ask_time ASC")
+    List<AiQuestion> findAll();
+
+    // 根据 userId 查询数据
+    @Select("SELECT * FROM ai_questions WHERE user_id = #{userId} ORDER BY ask_time ASC")
+    List<AiQuestion> findByUserId(Long userId);
+
+    // 根据 id 删除数据
+    @Delete("DELETE FROM ai_questions WHERE id = #{id}")
+    void deleteById(Long id);
+
+    // 根据 sessionId 和 userId 查询数据
+    @Select("SELECT * FROM ai_questions WHERE session_id = #{sessionId} AND user_id = #{userId} ORDER BY ask_time ASC")
+    List<AiQuestion> findByUserIdAndSessionId(@Param("sessionId") String sessionId, @Param("userId") Long userId);
+
+    //根据 sessionId查询数据
+    @Select("SELECT * FROM ai_questions WHERE session_id = #{sessionId} ORDER BY ask_time ASC")
+    List<AiQuestion> findBySessionId(String sessionId);
+
+    // 根据 sessionId 查询 ai_questions 表中的数据
+    @Select("SELECT * FROM ai_questions WHERE session_id = #{sessionId} ORDER BY ask_time ASC")
+    List<AiQuestion> findQuestionsBySessionId(String sessionId);
+
+    //标记会话为删除
+    @Update("UPDATE ai_questions SET deleted = true WHERE session_id = #{sessionId}")
+    void delete(String sessionId);
+}

+ 37 - 0
service-ai/service-ai-biz/src/main/java/com/usky/ai/mapper/AiSessionMapper.java

@@ -0,0 +1,37 @@
+package com.usky.ai.mapper;
+
+import com.usky.ai.service.AiQuestion;
+import com.usky.ai.service.AiSession;
+import org.apache.ibatis.annotations.*;
+
+import java.util.List;
+
+@Mapper
+public interface AiSessionMapper {
+    @Insert("INSERT INTO ai_sessions (session_id, user_id, user_name, question, ask_time) " +
+            "VALUES (#{sessionId}, #{userId}, #{userName}, #{question}, #{askTime})")
+    void save(AiSession aiSession);
+
+    //查询所有数据
+    @Select("SELECT * FROM ai_sessions ORDER BY ask_time DESC")
+    List<AiSession> findAll();
+
+    // 根据 user_id 查询未删除的数据
+    @Select("SELECT * FROM ai_sessions WHERE user_id = #{userId} AND deleted = false ORDER BY ask_time DESC")
+    List<AiSession> findByUserId(Long userId);
+
+    // 检查是否存在指定的 session_id 且未删除
+    @Select("SELECT COUNT(*) FROM ai_sessions WHERE session_id = #{sessionId} ORDER BY ask_time DESC")
+    boolean existsBySessionId(String sessionId);
+
+    @Select("SELECT * FROM ai_questions WHERE session_id = #{sessionId} ORDER BY ask_time DESC")
+    List<AiQuestion> findQuestionsBySessionId(String sessionId);
+
+    // 更新会话主题
+    @Update("UPDATE ai_sessions SET question = #{question} WHERE session_id = #{sessionId}")
+    void updateQuestion(@Param("sessionId") String sessionId, @Param("question") String question);
+
+    //标记会话为删除
+    @Update("UPDATE ai_sessions SET deleted = true WHERE session_id = #{sessionId}")
+    void delete(String sessionId);
+}

+ 70 - 0
service-ai/service-ai-biz/src/main/java/com/usky/ai/service/AiQuestion.java

@@ -0,0 +1,70 @@
+package com.usky.ai.service;
+
+import java.time.LocalDateTime;
+
+public class AiQuestion {
+    private Long id;
+    private String model;
+    private String sessionId;
+    private Long userId; // 添加用户ID字段
+    private String userName; // 添加用户名字段
+    private String question;
+    private String answer;
+    private LocalDateTime askTime;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getModel() { return model; }
+
+    public void setModel(String model) { this.model = model; }
+
+    public String getSessionId() { return sessionId; }
+
+    public void setSessionId(String sessionId) { this.sessionId = sessionId; }
+
+    public Long getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Long userId) {
+        this.userId = userId;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public String getQuestion() {
+        return question;
+    }
+
+    public void setQuestion(String question) {
+        this.question = question;
+    }
+
+    public String getAnswer() {
+        return answer;
+    }
+
+    public void setAnswer(String answer) {
+        this.answer = answer;
+    }
+
+    public LocalDateTime getAskTime() {
+        return askTime;
+    }
+
+    public void setAskTime(LocalDateTime askTime) {
+        this.askTime = askTime;
+    }
+}

+ 51 - 0
service-ai/service-ai-biz/src/main/java/com/usky/ai/service/AiQuestionItem.java

@@ -0,0 +1,51 @@
+package com.usky.ai.service;
+
+import java.time.LocalDateTime;
+
+public class AiQuestionItem {
+    private Long id;
+    private String sessionId;
+    private Long userId;
+    private String userName;
+    private String role;
+    private String content;
+    private String reasoningContent;
+    private LocalDateTime askTime;
+
+    public AiQuestionItem(String role, String content) {
+        this.role = role;
+        this.content = content;
+    }
+
+    public Long getId() { return id; }
+
+    public void setId(Long id) { this.id = id; }
+
+    public String getSessionId() { return sessionId; }
+
+    public void setSessionId(String sessionId) { this.sessionId = sessionId; }
+
+    public Long getUserId() { return userId; }
+
+    public void setUserId(Long userId) { this.userId = userId; }
+
+    public String getUserName() { return userName; }
+
+    public void setUserName(String userName) { this.userName = userName; }
+
+    public String getRole() { return role; }
+
+    public void setRole(String role) { this.role = role; }
+
+    public String getContent() { return content; }
+
+    public void setContent(String content) { this.content = content; }
+
+    public String getReasoningContent() { return reasoningContent; }
+
+    public void setReasoningContent(String reasoningContent) { this.reasoningContent = reasoningContent; }
+
+    public LocalDateTime getAskTime() { return askTime; }
+
+    public void setAskTime(LocalDateTime askTime) { this.askTime = askTime; }
+}

+ 48 - 0
service-ai/service-ai-biz/src/main/java/com/usky/ai/service/AiSession.java

@@ -0,0 +1,48 @@
+package com.usky.ai.service;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+public class AiSession {
+
+    private Long id;
+    private String sessionId;
+    private Long userId; // 添加用户ID字段
+    private String userName; // 添加用户名字段
+    private String question;
+    private LocalDateTime askTime;
+    private List<AiQuestionItem> itemList;
+    private boolean deleted; // 添加删除标识字段
+
+    public Long getId() { return id; }
+
+    public void setId(Long id) { this.id = id; }
+
+    public String getSessionId() { return sessionId; }
+
+    public void setSessionId(String sessionId) { this.sessionId = sessionId; }
+
+    public Long getUserId() { return userId; }
+
+    public void setUserId(Long userId) { this.userId = userId; }
+
+    public String getUserName() { return userName; }
+
+    public void setUserName(String userName) { this.userName = userName; }
+
+    public String getQuestion() { return question; }
+
+    public void setQuestion(String question) { this.question = question; }
+
+    public LocalDateTime getAskTime() { return askTime; }
+
+    public void setAskTime(LocalDateTime askTime) { this.askTime = askTime; }
+
+    public List<AiQuestionItem> getItemList() { return itemList; }
+
+    public void setItemList(List<AiQuestionItem> itemList) { this.itemList = itemList; }
+
+    public boolean isDeleted() { return deleted; }
+
+    public void setDeleted(boolean deleted) { this.deleted = deleted; }
+}

+ 14 - 0
service-ai/service-ai-biz/src/main/java/com/usky/ai/service/config/AiChatConfig.java

@@ -0,0 +1,14 @@
+package com.usky.ai.service.config;
+
+import com.alibaba.dashscope.aigc.generation.Generation;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class AiChatConfig {
+
+    @Bean
+    public Generation generation() {
+        return new Generation();
+    }
+}

+ 19 - 0
service-ai/service-ai-biz/src/main/java/com/usky/ai/service/config/MyGlobalCorsConfig.java

@@ -0,0 +1,19 @@
+package com.usky.ai.service.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class MyGlobalCorsConfig implements WebMvcConfigurer {
+
+    @Override
+    public void addCorsMappings(CorsRegistry registry) {
+        registry.addMapping("/**") // 对所有的路径允许跨域请求
+                .allowedOrigins("*") // 允许来自任何源的请求
+                .allowedMethods("GET", "POST", "PUT", "DELETE") // 允许的请求方法
+                .allowedHeaders("*") // 允许的请求头
+                .allowCredentials(false) // 是否允许证书(cookies),根据需要设置
+                .maxAge(3600); // 预检请求的缓存时间(秒)
+    }
+}

+ 14 - 0
service-ai/service-ai-biz/src/main/java/com/usky/ai/service/config/WebConfig.java

@@ -0,0 +1,14 @@
+package com.usky.ai.service.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class WebConfig implements WebMvcConfigurer {
+    @Override
+    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
+        // 设置默认的异步请求超时时间为300秒(单位:毫秒)
+        configurer.setDefaultTimeout(300000);
+    }
+}

+ 22 - 0
service-ai/service-ai-biz/src/main/java/com/usky/ai/service/vo/AiStreamOutputVO.java

@@ -0,0 +1,22 @@
+package com.usky.ai.service.vo;
+
+import lombok.Data;
+
+@Data
+public class AiStreamOutputVO {
+
+    /**
+     * 会话id
+     */
+    private String sessionId;
+
+    /**
+     * 输入内容
+     */
+    private String content;
+
+    /**
+     * 输出内容
+     */
+    private String reasoningContent;
+}

+ 24 - 0
service-ai/service-ai-biz/src/main/resources/bootstrap.yml

@@ -0,0 +1,24 @@
+# Tomcat
+server:
+  port: 9899
+# Spring
+spring: 
+  application:
+    # 应用名称
+    name: service-ai
+  profiles:
+    # 环境配置
+    active: dev
+  cloud:
+    nacos:
+      discovery:
+        # 服务注册地址
+        server-addr: usky-cloud-nacos:8848
+      config:
+        # 配置中心地址
+        server-addr: usky-cloud-nacos:8848
+        # 配置文件格式
+        file-extension: yml
+        # 共享配置
+        shared-configs:
+          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}

+ 94 - 0
service-ai/service-ai-biz/src/main/resources/logback.xml

@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration scan="true" scanPeriod="60 seconds" debug="false">
+    <!-- 日志存放路径 -->
+    <property name="log.path" value="/var/log/uskycloud/service-ai" />
+    <!-- 日志输出格式 -->
+    <property name="log.pattern" value="%d{MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{26}:%line: %msg%n" />
+    <!--    	<property name="log.pattern" value="%gray(%d{MM-dd HH:mm:ss.SSS}) %highlight(%-5level) &#45;&#45; [%gray(%thread)] %cyan(%logger{26}:%line): %msg%n" />-->
+
+
+    <property name="SQL_PACKAGE" value="com.usky.ai.mapper"/>
+
+    <!-- 控制台输出 -->
+    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+    </appender>
+
+    <appender name="file_sql" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}/sql.log</file>
+        <!-- 循环政策:基于时间创建日志文件 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志文件名格式 -->
+            <fileNamePattern>${log.path}/sql.%d{yyyy-MM-dd}.log</fileNamePattern>
+            <!-- 日志最大的历史 60天 -->
+            <maxHistory>3</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+    </appender>
+
+    <!-- 系统日志输出 -->
+    <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}/info.log</file>
+        <!-- 循环政策:基于时间创建日志文件 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志文件名格式 -->
+            <fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
+            <!-- 日志最大的历史 60天 -->
+            <maxHistory>3</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <!-- 过滤的级别 -->
+            <level>INFO</level>
+            <!-- 匹配时的操作:接收(记录) -->
+            <onMatch>ACCEPT</onMatch>
+            <!-- 不匹配时的操作:拒绝(不记录) -->
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}/error.log</file>
+        <!-- 循环政策:基于时间创建日志文件 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志文件名格式 -->
+            <fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
+            <!-- 日志最大的历史 60天 -->
+            <maxHistory>60</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <!-- 过滤的级别 -->
+            <level>ERROR</level>
+            <!-- 匹配时的操作:接收(记录) -->
+            <onMatch>ACCEPT</onMatch>
+            <!-- 不匹配时的操作:拒绝(不记录) -->
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!-- 系统模块日志级别控制  -->
+    <!--	<logger name="com.usky" level="info" />-->
+    <!-- Spring日志级别控制  -->
+    <!--	<logger name="org.springframework" level="warn" />-->
+
+    <logger name="${SQL_PACKAGE}" additivity="false" level="debug">
+        <appender-ref ref="console"/>
+        <appender-ref ref="file_sql"/>
+    </logger>
+
+    <!--系统操作日志-->
+    <root level="info">
+        <appender-ref ref="file_info" />
+        <appender-ref ref="file_error" />
+        <appender-ref ref="console" />
+    </root>
+</configuration>

+ 149 - 0
service-ai/service-ai-biz/src/main/resources/static/dpsk.html

@@ -0,0 +1,149 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>小天-AI</title>
+    <style>
+        body {
+            font-family: 'Roboto', Arial, sans-serif;
+            margin: 0;
+            padding: 0;
+            background-color: #f4f4f9;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            height: 100vh;
+        }
+        .container {
+            width: 500px;
+            background-color: #fff;
+            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
+            border-radius: 8px;
+            overflow: hidden;
+        }
+        h1 {
+            background-color: #007bff;
+            color: #fff;
+            text-align: center;
+            padding: 15px;
+            margin: 0;
+            font-size: 1.5em;
+        }
+        form {
+            padding: 20px;
+        }
+        label {
+            display: block;
+            margin-bottom: 10px;
+            font-weight: bold;
+        }
+        textarea {
+            width: 100%;
+            height: 100px;
+            border: 1px solid #ccc;
+            border-radius: 4px;
+            padding: 10px;
+            resize: none;
+        }
+        button {
+            width: 100%;
+            padding: 10px;
+            background-color: #007bff;
+            color: #fff;
+            border: none;
+            border-radius: 4px;
+            cursor: pointer;
+            transition: background-color 0.3s ease;
+        }
+        button:hover {
+            background-color: #0056b3;
+        }
+        #response {
+            margin-top: 20px;
+            padding: 10px;
+            background-color: #f9f9f9;
+            border-top: 1px solid #ccc;
+            max-height: 200px;
+            overflow-y: auto;
+            font-family: monospace;
+            white-space: pre-wrap;
+        }
+    </style>
+</head>
+<body>
+<div class="container">
+    <h1>小天-AI</h1>
+    <form id="chatForm">
+        <label for="content">你的问题:</label>
+        <textarea id="content" name="content" placeholder="请输入你的问题在这里..."></textarea>
+        <button type="submit">发送</button>
+    </form>
+    <div id="response"></div>
+    <div id="sessionId" style="margin-top: 10px; font-size: 0.9em; color: #666;"></div>
+</div>
+
+<script>
+    document.getElementById('chatForm').addEventListener('submit', function(event) {
+        event.preventDefault();
+
+        const content = document.getElementById('content').value;
+
+        const requestBody = JSON.stringify({content: content});
+
+        const token = "eyJhbGciOiJIUzUxMiJ9.eyIiOjEwMDMsInVzZXJfaWQiOjIxMywidXNlcl9rZXkiOiJlYzUxODMzNjdmYTk0ODgwOGQwZjEwODEyOWVmNjgwOSIsInVzZXJuYW1lIjoi6LW16YeR6ZuoIn0.zWulXcesI1TRcDmiAHuQ9P2WHDE2l7mDmuunx13TmVl6E5Yvs8nZvu1ddtINdw0lrnnR3Q5lZaRH3mJJTaDhig";
+
+        fetch('/ai/aliDeepSeek', {
+            method: 'POST',
+            headers: {
+                'Content-Type': 'application/json',
+                'Authorization': `Bearer ${token}`
+            },
+            body: requestBody
+        })
+            .then(response => {
+                if (!response.ok) {
+                    throw new Error('Network response was not ok');
+                }
+                return response.text();
+            })
+            .then(data => {
+                document.getElementById('response').innerText = '';
+
+                // 解析数据,提取 reasoningContent
+                const lines = data.split('\n');
+                let responseLines = [];
+
+                for (let line of lines) {
+                    try {
+                        const parsedLine = JSON.parse(line.replace('data: ', '').trim());
+                        if (parsedLine.reasoningContent !== null) {
+                            responseLines.push(parsedLine.reasoningContent);
+                        }
+                    } catch (e) {
+                        console.error('Error parsing line:', e);
+                    }
+                }
+
+                // 将 reasoningContent 的内容拼接成完整字符串
+                const fullResponse = responseLines.join('');
+
+                // 逐字显示响应内容
+                let index = 0;
+                const responseElement = document.getElementById('response');
+                const interval = setInterval(() => {
+                    if (index < fullResponse.length) {
+                        responseElement.innerText += fullResponse[index];
+                        index++;
+                    } else {
+                        clearInterval(interval);
+                    }
+                }, 50);
+            })
+            .catch(error => {
+                document.getElementById('response').innerText = 'Error: ' + error.message;
+            });
+    })
+</script>
+</body>
+</html>

+ 149 - 0
service-ai/service-ai-biz/src/main/resources/static/tyqw.html

@@ -0,0 +1,149 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>小天-AI</title>
+    <style>
+        body {
+            font-family: 'Roboto', Arial, sans-serif;
+            margin: 0;
+            padding: 0;
+            background-color: #f4f4f9;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            height: 100vh;
+        }
+        .container {
+            width: 500px;
+            background-color: #fff;
+            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
+            border-radius: 8px;
+            overflow: hidden;
+        }
+        h1 {
+            background-color: #007bff;
+            color: #fff;
+            text-align: center;
+            padding: 15px;
+            margin: 0;
+            font-size: 1.5em;
+        }
+        form {
+            padding: 20px;
+        }
+        label {
+            display: block;
+            margin-bottom: 10px;
+            font-weight: bold;
+        }
+        textarea {
+            width: 100%;
+            height: 100px;
+            border: 1px solid #ccc;
+            border-radius: 4px;
+            padding: 10px;
+            resize: none;
+        }
+        button {
+            width: 100%;
+            padding: 10px;
+            background-color: #007bff;
+            color: #fff;
+            border: none;
+            border-radius: 4px;
+            cursor: pointer;
+            transition: background-color 0.3s ease;
+        }
+        button:hover {
+            background-color: #0056b3;
+        }
+        #response {
+            margin-top: 20px;
+            padding: 10px;
+            background-color: #f9f9f9;
+            border-top: 1px solid #ccc;
+            max-height: 200px;
+            overflow-y: auto;
+            font-family: monospace;
+            white-space: pre-wrap;
+        }
+    </style>
+</head>
+<body>
+<div class="container">
+    <h1>小天-AI</h1>
+    <form id="chatForm">
+        <label for="content">你的问题:</label>
+        <textarea id="content" name="content" placeholder="请输入你的问题在这里..."></textarea>
+        <button type="submit">发送</button>
+    </form>
+    <div id="response"></div>
+    <div id="sessionId" style="margin-top: 10px; font-size: 0.9em; color: #666;"></div>
+</div>
+
+<script>
+    document.getElementById('chatForm').addEventListener('submit', function(event) {
+        event.preventDefault();
+
+        const content = document.getElementById('content').value;
+
+        const requestBody = JSON.stringify({content: content});
+
+        const token = "eyJhbGciOiJIUzUxMiJ9.eyIiOjEwMDMsInVzZXJfaWQiOjIxMywidXNlcl9rZXkiOiJlYzUxODMzNjdmYTk0ODgwOGQwZjEwODEyOWVmNjgwOSIsInVzZXJuYW1lIjoi6LW16YeR6ZuoIn0.zWulXcesI1TRcDmiAHuQ9P2WHDE2l7mDmuunx13TmVl6E5Yvs8nZvu1ddtINdw0lrnnR3Q5lZaRH3mJJTaDhig";
+
+        fetch('/ai/aliTyqw', {
+            method: 'POST',
+            headers: {
+                'Content-Type': 'application/json',
+                'Authorization': `Bearer ${token}`
+            },
+            body: requestBody
+        })
+            .then(response => {
+                if (!response.ok) {
+                    throw new Error('Network response was not ok');
+                }
+                return response.text();
+            })
+            .then(data => {
+                document.getElementById('response').innerText = '';
+
+                // 解析数据,提取 reasoningContent
+                const lines = data.split('\n');
+                let responseLines = [];
+
+                for (let line of lines) {
+                    try {
+                        const parsedLine = JSON.parse(line.replace('data: ', '').trim());
+                        if (parsedLine.reasoningContent !== null) {
+                            responseLines.push(parsedLine.reasoningContent);
+                        }
+                    } catch (e) {
+                        console.error('Error parsing line:', e);
+                    }
+                }
+
+                // 将 reasoningContent 的内容拼接成完整字符串
+                const fullResponse = responseLines.join('');
+
+                // 逐字显示响应内容
+                let index = 0;
+                const responseElement = document.getElementById('response');
+                const interval = setInterval(() => {
+                    if (index < fullResponse.length) {
+                        responseElement.innerText += fullResponse[index];
+                        index++;
+                    } else {
+                        clearInterval(interval);
+                    }
+                }, 50);
+            })
+            .catch(error => {
+                document.getElementById('response').innerText = 'Error: ' + error.message;
+            });
+    })
+</script>
+</body>
+</html>

+ 12 - 0
service-eg/service-eg-biz/src/main/java/com/usky/eg/domain/EgDevice.java

@@ -123,6 +123,18 @@ public class EgDevice implements Serializable {
      */
     private String openMode;
 
+    /**
+     * 密码
+     */
+    private String password;
+
+    /**
+     * 工作状态
+     */
+    private String workStatus;
+
+    /**
+
     /**
      * 用户人脸信息记录
      */

+ 2 - 0
service-eg/service-eg-biz/src/main/java/com/usky/eg/service/EgDeviceService.java

@@ -31,5 +31,7 @@ public interface EgDeviceService extends CrudService<EgDevice> {
 
     boolean checkNameUnique(EgDevice egDevice);
 
+    boolean checkDeviceNameUnique(EgDevice egDevice);
+
     Map<String,Object> control(String productCode, String deviceUuid, String commandCode, String commandValue, String domain, Long userId, String userName);
 }

+ 51 - 18
service-eg/service-eg-biz/src/main/java/com/usky/eg/service/impl/EgDeviceServiceImpl.java

@@ -74,7 +74,8 @@ public class EgDeviceServiceImpl extends AbstractCrudService<EgDeviceMapper, EgD
         if(page.getRecords().size() > 0){
 
             LambdaQueryWrapper<MeetingFace> meetingFaceQuery = Wrappers.lambdaQuery();
-            meetingFaceQuery.eq(MeetingFace::getTenantId,tenantId);
+            meetingFaceQuery.select(MeetingFace::getFid,MeetingFace::getCreateTime,MeetingFace::getVefNum,MeetingFace::getFaceName,MeetingFace::getRemark,MeetingFace::getFaceStatus,MeetingFace::getCardNum,MeetingFace::getBindDevice,MeetingFace::getDeptId,MeetingFace::getTenantId,MeetingFace::getUserId)
+                    .eq(MeetingFace::getTenantId,tenantId);
             List<MeetingFace> meetingAllFaceList = meetingFaceMapper.selectList(meetingFaceQuery);
 
             for (int i = 0; i < page.getRecords().size(); i++) {
@@ -105,24 +106,27 @@ public class EgDeviceServiceImpl extends AbstractCrudService<EgDeviceMapper, EgD
         long userId = SecurityUtils.getUserId();
         //人员设备权限校验,校验通过,可以下发命令控制设备
         Integer fid = baseMapper.getMeetingFaceData(userId);
-        if(fid == null){
-            throw new BusinessException("人脸卡号信息未注册");
-        }
+//        if(fid == null){
+//            throw new BusinessException("人脸卡号信息未注册");
+//        }
         Integer[] deviceFid = baseMapper.getMeetingFaceDeviceList(fid);
-        if(deviceFid.length == 0){
-            throw new BusinessException("人员未绑定设备,请检查");
-        }
+//        if(deviceFid.length == 0){
+//            throw new BusinessException("人员未绑定设备,请检查");
+//        }
 
         IPage<EgDevice> page = new Page<>(requestVO.getCurrent(),requestVO.getSize());
-        LambdaQueryWrapper<EgDevice> queryWrapper = Wrappers.lambdaQuery();
-        queryWrapper.like(StringUtils.isNotBlank(requestVO.getDeviceName()),EgDevice::getDeviceName,requestVO.getDeviceName())
-                .like(StringUtils.isNotBlank(requestVO.getInstallAddress()),EgDevice::getInstallAddress,requestVO.getInstallAddress())
-                .eq(null != requestVO.getServiceStatus(),EgDevice::getServiceStatus,requestVO.getServiceStatus())
-                .eq(null != requestVO.getId(),EgDevice::getId,requestVO.getId())
-                .in(EgDevice::getId,deviceFid)
-                .eq(EgDevice::getTenantId,SecurityUtils.getTenantId())
-                .orderByDesc(EgDevice::getId);
-        page = this.page(page,queryWrapper);
+        if(deviceFid.length > 0){
+            LambdaQueryWrapper<EgDevice> queryWrapper = Wrappers.lambdaQuery();
+            queryWrapper.like(StringUtils.isNotBlank(requestVO.getDeviceName()),EgDevice::getDeviceName,requestVO.getDeviceName())
+                    .like(StringUtils.isNotBlank(requestVO.getInstallAddress()),EgDevice::getInstallAddress,requestVO.getInstallAddress())
+                    .eq(null != requestVO.getServiceStatus(),EgDevice::getServiceStatus,requestVO.getServiceStatus())
+                    .eq(null != requestVO.getId(),EgDevice::getId,requestVO.getId())
+                    .in(EgDevice::getId,deviceFid)
+                    .eq(EgDevice::getTenantId,SecurityUtils.getTenantId())
+                    .orderByDesc(EgDevice::getId);
+            page = this.page(page,queryWrapper);
+        }
+
 
         return new CommonPage<>(page.getRecords(),page.getTotal(),requestVO.getSize(),requestVO.getCurrent());
     }
@@ -132,6 +136,9 @@ public class EgDeviceServiceImpl extends AbstractCrudService<EgDeviceMapper, EgD
         if(checkNameUnique(egDevice)){
             throw new BusinessException("新增门禁门号设备'"+egDevice.getDeviceId()+","+egDevice.getEgNumber()+"'失败,设备已存在");
         }
+        if(checkDeviceNameUnique(egDevice)){
+            throw new BusinessException("新增门禁设备'"+egDevice.getDeviceName()+"'失败,设备已存在");
+        }
 
         egDevice.setDeviceUuid(UUIDUtils.uuid());
         egDevice.setCreateBy(SecurityUtils.getUsername());
@@ -154,10 +161,18 @@ public class EgDeviceServiceImpl extends AbstractCrudService<EgDeviceMapper, EgD
     }
 
     @Override
-    public void update(EgDevice egDevice){
+    public void update(EgDevice egDevice) {
+
+        EgDevice one = this.getById(egDevice.getId());
+        egDevice.setBindFace(one.getBindFace());
+
+
         if(checkNameUnique(egDevice)){
             throw new BusinessException("修改门禁门号设备'"+egDevice.getDeviceId()+","+egDevice.getEgNumber()+"'失败,设备已存在");
         }
+        if(checkDeviceNameUnique(egDevice)){
+            throw new BusinessException("新增门禁设备'"+egDevice.getDeviceName()+"'失败,设备已存在");
+        }
 
         egDevice.setUpdateBy(SecurityUtils.getUsername());
         egDevice.setUpdateTime(LocalDateTime.now());
@@ -165,9 +180,10 @@ public class EgDeviceServiceImpl extends AbstractCrudService<EgDeviceMapper, EgD
         this.updateById(egDevice);
 
         String[] fids = new String[0];
-        egDeviceMapper.deleteMeetingFaceDevice(egDevice.getId());
         if(Objects.nonNull(egDevice.getBindFace()) || StringUtils.isNotBlank(egDevice.getBindFace())){
             fids = egDevice.getBindFace().split(",");
+
+            egDeviceMapper.deleteMeetingFaceDevice(egDevice.getId());
         }
         if(fids.length > 0){
             for (int i = 0; i < fids.length; i++) {
@@ -178,9 +194,16 @@ public class EgDeviceServiceImpl extends AbstractCrudService<EgDeviceMapper, EgD
 
     @Override
     public void attachUpdate(EgDevice egDevice){
+
+        EgDevice one = this.getById(egDevice.getId());
+        egDevice.setBindFace(one.getBindFace());
+
         if(checkNameUnique(egDevice)){
             throw new BusinessException("更新门禁设备附加功能'"+egDevice.getDeviceId()+"'失败,设备已存在");
         }
+        if(checkDeviceNameUnique(egDevice)){
+            throw new BusinessException("新增门禁设备'"+egDevice.getDeviceName()+"'失败,设备已存在");
+        }
 
         egDevice.setUpdateBy(SecurityUtils.getUsername());
         egDevice.setUpdateTime(LocalDateTime.now());
@@ -216,6 +239,16 @@ public class EgDeviceServiceImpl extends AbstractCrudService<EgDeviceMapper, EgD
         return null != one && !Objects.equals(one.getId(),id);
     }
 
+    @Override
+    public boolean checkDeviceNameUnique(EgDevice egDevice){
+        Integer id = null == egDevice.getId() ? -1 : egDevice.getId();
+        LambdaQueryWrapper<EgDevice> queryWrapper = Wrappers.lambdaQuery();
+        queryWrapper.eq(EgDevice::getDeviceName,egDevice.getDeviceName())
+                .eq(EgDevice::getTenantId, SecurityUtils.getTenantId());
+        EgDevice one = this.getOne(queryWrapper);
+        return null != one && !Objects.equals(one.getId(),id);
+    }
+
     @Override
     public Map<String,Object> control(String productCode, String deviceUuid, String commandCode, String commandValue, String domain, Long userId, String userName){
         Integer tenantId;

+ 2 - 0
service-eg/service-eg-biz/src/main/resources/mapper/eg/EgDeviceMapper.xml

@@ -23,6 +23,8 @@
         <result column="img_path" property="imgPath" />
         <result column="remark" property="remark" />
         <result column="open_mode" property="openMode" />
+        <result column="password" property="password" />
+        <result column="work_status" property="workStatus" />
     </resultMap>
     <insert id="insertMeetingFaceDevice" parameterType="integer">
         insert into meeting_face_device (face_id,device_id) value (#{fid}, #{egDeviceId});

+ 51 - 47
service-fire/service-fire-biz/src/main/java/com/usky/fire/service/impl/PatrolInspectionPlanSonServiceImpl.java

@@ -110,9 +110,9 @@ public class PatrolInspectionPlanSonServiceImpl extends AbstractCrudService<Patr
         }
 
         Map<String, Object> map = new HashMap<>();
-        map.put("planSonCount", planSonCount);//巡检任务总数
-        map.put("patrolledCount", patrolledCount);//已巡检任务
-        map.put("undetectedCount", undetectedCount);//漏检任务
+        map.put("planSonCount", planSonCount);// 巡检任务总数
+        map.put("patrolledCount", patrolledCount);// 已巡检任务
+        map.put("undetectedCount", undetectedCount);// 漏检任务
         return map;
     }
 
@@ -298,8 +298,8 @@ public class PatrolInspectionPlanSonServiceImpl extends AbstractCrudService<Patr
          * 巡检时间判断
          * */
         LocalDateTime now = LocalDateTime.now();
-        LocalDateTime inspectionDateTime = LocalDateTime.parse(planSonList.get(0).getInspectionDate() +" "+ planSonList.get(0).getStartTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
-        LocalDateTime inspectionDateTime1 = LocalDateTime.parse(planSonList.get(0).getInspectionDate() +" "+ planSonList.get(0).getEndTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+        LocalDateTime inspectionDateTime = LocalDateTime.parse(planSonList.get(0).getInspectionDate() + " " + planSonList.get(0).getStartTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+        LocalDateTime inspectionDateTime1 = LocalDateTime.parse(planSonList.get(0).getInspectionDate() + " " + planSonList.get(0).getEndTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
         if (inspectionDateTime.isAfter(now)) {
             PatrolInspectionEvent patrolInspectionEvent = new PatrolInspectionEvent();
             patrolInspectionEvent.setEventName("早到");
@@ -311,7 +311,7 @@ public class PatrolInspectionPlanSonServiceImpl extends AbstractCrudService<Patr
             patrolInspectionEvent.setCreateTime(LocalDateTime.now());
             patrolInspectionEventService.add(patrolInspectionEvent);
             throw new BusinessException("计划未开始,不可巡检");
-        } else if (now.isAfter(inspectionDateTime1)){
+        } else if (now.isAfter(inspectionDateTime1)) {
             PatrolInspectionEvent patrolInspectionEvent = new PatrolInspectionEvent();
             patrolInspectionEvent.setEventName("迟到");
             patrolInspectionEvent.setEventType(34);
@@ -372,9 +372,13 @@ public class PatrolInspectionPlanSonServiceImpl extends AbstractCrudService<Patr
             patrolInspectionRecordPictureService.save(recordPictureList.get(i));
         }
 
-        for (int i = 0; i < recordOptionList.size(); i++) {
-            recordOptionList.get(i).setRecordId(recordId);
-            patrolInspectionRecordOptionService.save(recordOptionList.get(i));
+        if (recordOptionList != null && !recordOptionList.isEmpty()) {
+            for (int i = 0; i < recordOptionList.size(); i++) {
+                recordOptionList.get(i).setRecordId(recordId);
+                patrolInspectionRecordOptionService.save(recordOptionList.get(i));
+            }
+        } else {
+            throw new BusinessException("请选择或填写巡检内容!");
         }
 
         LambdaQueryWrapper<PatrolInspectionPlanSiteSon> queryWrapperTwo = Wrappers.lambdaQuery();
@@ -399,46 +403,46 @@ public class PatrolInspectionPlanSonServiceImpl extends AbstractCrudService<Patr
     }
 
     @Override
-    public void addPatrolInspectionAbnormalData(){
+    public void addPatrolInspectionAbnormalData() {
         LOGGER.info("巡检漏检定时任务 begin");
         DateTimeFormatter df1 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
         String datetime1 = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
         String datetime2 = LocalDateTime.now().minusHours(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
 
-        List<PatrolInspectionPlanSon> list = patrolInspectionPlanSonMapper.selectInspectionPlanSonData(datetime1,datetime2);
-        if(list.size() <=0){
+        List<PatrolInspectionPlanSon> list = patrolInspectionPlanSonMapper.selectInspectionPlanSonData(datetime1, datetime2);
+        if (list.size() <= 0) {
             LOGGER.info("当前时间向前一小时没有漏检记录");
-        }else{
+        } else {
             List<Integer> sonIdlist = new ArrayList<>();
             for (int i = 0; i < list.size(); i++) {
                 sonIdlist.add(list.get(i).getId());
             }
             LambdaQueryWrapper<PatrolInspectionPlanSiteSon> queryWrapper = Wrappers.lambdaQuery();
-            queryWrapper.in(PatrolInspectionPlanSiteSon::getPlanId,sonIdlist)
-                    .eq(PatrolInspectionPlanSiteSon::getInspectionStatus,1);
+            queryWrapper.in(PatrolInspectionPlanSiteSon::getPlanId, sonIdlist)
+                    .eq(PatrolInspectionPlanSiteSon::getInspectionStatus, 1);
             List<PatrolInspectionPlanSiteSon> siteSonList = patrolInspectionPlanSiteSonService.list(queryWrapper);
-            if(CollectionUtils.isNotEmpty(siteSonList)){
+            if (CollectionUtils.isNotEmpty(siteSonList)) {
                 List<Integer> siteIdList = new ArrayList<>();
                 List<Integer> noSonIdList = new ArrayList<>();
                 for (int i = 0; i < siteSonList.size(); i++) {
                     siteIdList.add(siteSonList.get(i).getSiteId());
                     noSonIdList.add(siteSonList.get(i).getPlanId());
                 }
-                //获取巡检地点
+                // 获取巡检地点
                 LOGGER.info("获取巡检地点");
                 LambdaQueryWrapper<PatrolInspectionSite> queryWrapper1 = Wrappers.lambdaQuery();
-                if(CollectionUtils.isNotEmpty(siteIdList)){
-                    queryWrapper1.in(PatrolInspectionSite::getId,siteIdList)
-                            .eq(PatrolInspectionSite::getEnable,1);
+                if (CollectionUtils.isNotEmpty(siteIdList)) {
+                    queryWrapper1.in(PatrolInspectionSite::getId, siteIdList)
+                            .eq(PatrolInspectionSite::getEnable, 1);
                 }
                 List<PatrolInspectionSite> siteList = patrolInspectionSiteService.list(queryWrapper1);
-                if(siteList.size() <= 0){
+                if (siteList.size() <= 0) {
                     LOGGER.info("查询巡检地点记录为空");
                 }
-                //获取巡检子计划
+                // 获取巡检子计划
                 LambdaQueryWrapper<PatrolInspectionPlanSon> planSonQueryWrapper = Wrappers.lambdaQuery();
-                if(CollectionUtils.isNotEmpty(noSonIdList)){
-                    planSonQueryWrapper.in(PatrolInspectionPlanSon::getId,noSonIdList);
+                if (CollectionUtils.isNotEmpty(noSonIdList)) {
+                    planSonQueryWrapper.in(PatrolInspectionPlanSon::getId, noSonIdList);
                 }
                 List<PatrolInspectionPlanSon> noPlanSonList = this.list(planSonQueryWrapper);
                 List<Integer> planIdList = new ArrayList<>();
@@ -450,27 +454,27 @@ public class PatrolInspectionPlanSonServiceImpl extends AbstractCrudService<Patr
                     areaList.add(noPlanSonList.get(i).getAreaId());
                 }
 
-                //获取巡检计划
+                // 获取巡检计划
                 List<PatrolInspectionPlan> noPlanIdList = patrolInspectionPlanMapper.selectNoPlanList(planIdList);
-                //获取巡检人员
+                // 获取巡检人员
                 LOGGER.info("获取巡检人员");
                 LambdaQueryWrapper<PatrolInspectionPersonnel> personnelQueryWrapper = Wrappers.lambdaQuery();
-                if(CollectionUtils.isNotEmpty(personnelList)){
-                    personnelQueryWrapper.in(PatrolInspectionPersonnel::getId,personnelList)
-                            .eq(PatrolInspectionPersonnel::getEnable,1);
+                if (CollectionUtils.isNotEmpty(personnelList)) {
+                    personnelQueryWrapper.in(PatrolInspectionPersonnel::getId, personnelList)
+                            .eq(PatrolInspectionPersonnel::getEnable, 1);
                 }
                 List<PatrolInspectionPersonnel> inspectionPersonnelList = patrolInspectionPersonnelService.list(personnelQueryWrapper);
-                if(inspectionPersonnelList.size() <= 0){
+                if (inspectionPersonnelList.size() <= 0) {
                     LOGGER.info("巡检人员信息不存在");
                 }
-                //获取巡检区域
+                // 获取巡检区域
                 LambdaQueryWrapper<PatrolInspectionArea> queryWrapperOne = Wrappers.lambdaQuery();
-                if(CollectionUtils.isNotEmpty(areaList)){
+                if (CollectionUtils.isNotEmpty(areaList)) {
                     queryWrapperOne.in(PatrolInspectionArea::getId, areaList)
-                            .eq(PatrolInspectionArea::getEnable,1);
+                            .eq(PatrolInspectionArea::getEnable, 1);
                 }
                 List<PatrolInspectionArea> areaInfoList = patrolInspectionAreaService.list(queryWrapperOne);
-                if(areaInfoList.size() <= 0){
+                if (areaInfoList.size() <= 0) {
                     LOGGER.info("巡检区域不存在");
                 }
 
@@ -479,7 +483,7 @@ public class PatrolInspectionPlanSonServiceImpl extends AbstractCrudService<Patr
                     Integer siteId = siteSonList.get(i).getSiteId();
                     Integer planSonId = siteSonList.get(i).getPlanId();
                     for (int j = 0; j < siteList.size(); j++) {
-                        if(siteId.equals(siteList.get(j).getId())){
+                        if (siteId.equals(siteList.get(j).getId())) {
                             patrolInspectionAbnormal.setSiteNubmber(siteList.get(j).getSiteNubmber());
                             patrolInspectionAbnormal.setSiteType(siteList.get(j).getSiteType());
                             patrolInspectionAbnormal.setSiteName(siteList.get(j).getSiteName());
@@ -492,7 +496,7 @@ public class PatrolInspectionPlanSonServiceImpl extends AbstractCrudService<Patr
                     }
 
                     for (int j = 0; j < noPlanSonList.size(); j++) {
-                        if(planSonId.equals(noPlanSonList.get(j).getId())){
+                        if (planSonId.equals(noPlanSonList.get(j).getId())) {
                             patrolInspectionAbnormal.setPlanId(noPlanSonList.get(j).getPlanId());
                             patrolInspectionAbnormal.setPlanSonId(noPlanSonList.get(j).getId());
                             patrolInspectionAbnormal.setTenantId(noPlanSonList.get(j).getTenantId());
@@ -513,14 +517,14 @@ public class PatrolInspectionPlanSonServiceImpl extends AbstractCrudService<Patr
 
                             Integer noAreaId = noPlanSonList.get(j).getAreaId();
                             for (int k = 0; k < areaInfoList.size(); k++) {
-                                if(noAreaId.equals(areaInfoList.get(k).getId())){
+                                if (noAreaId.equals(areaInfoList.get(k).getId())) {
                                     patrolInspectionAbnormal.setAreaName(areaInfoList.get(k).getAreaName());
                                     break;
                                 }
                             }
                             Integer noPersonnelId = noPlanSonList.get(j).getPersonnelId();
                             for (int k = 0; k < inspectionPersonnelList.size(); k++) {
-                                if(noPersonnelId.equals(inspectionPersonnelList.get(k).getId())){
+                                if (noPersonnelId.equals(inspectionPersonnelList.get(k).getId())) {
                                     patrolInspectionAbnormal.setName(inspectionPersonnelList.get(k).getFullName());
                                     patrolInspectionAbnormal.setPhone(inspectionPersonnelList.get(k).getPhoneNumber());
                                     break;
@@ -528,7 +532,7 @@ public class PatrolInspectionPlanSonServiceImpl extends AbstractCrudService<Patr
                             }
                             Integer planId = noPlanSonList.get(j).getPlanId();
                             for (int k = 0; k < noPlanIdList.size(); k++) {
-                                if(planId.equals(noPlanIdList.get(k).getId())){
+                                if (planId.equals(noPlanIdList.get(k).getId())) {
                                     patrolInspectionAbnormal.setRouteId(noPlanIdList.get(k).getRouteId());
                                     break;
                                 }
@@ -969,7 +973,7 @@ public class PatrolInspectionPlanSonServiceImpl extends AbstractCrudService<Patr
             for (int i = 0; i < planSonList.size(); i++) {
                 planSonidList.add(planSonList.get(i).getId());
             }
-            //巡检计划名称查询
+            // 巡检计划名称查询
             LambdaQueryWrapper<PatrolInspectionPlan> queryWrapperOne = Wrappers.lambdaQuery();
 //            queryWrapperOne.eq(PatrolInspectionPlan::getTenantId, SecurityUtils.getTenantId());
 //            queryWrapperOne.eq(PatrolInspectionPlan::getEnable, 1);
@@ -979,8 +983,8 @@ public class PatrolInspectionPlanSonServiceImpl extends AbstractCrudService<Patr
             }
 
             List<PatrolInspectionPlan> planList = patrolInspectionPlanMapper.selectList(queryWrapperOne);
-            List<DataCountVo> patrolledSiteCountList = this.planSiteSonCount(planSonidList, 2);//已巡检地点数量
-            List<DataCountVo> undetectedSiteCountList = this.planSiteSonCount(planSonidList, 1);//漏检地点数量
+            List<DataCountVo> patrolledSiteCountList = this.planSiteSonCount(planSonidList, 2);// 已巡检地点数量
+            List<DataCountVo> undetectedSiteCountList = this.planSiteSonCount(planSonidList, 1);// 漏检地点数量
             for (int i = 0; i < planSonList.size(); i++) {
                 PatrolInspectionPlanSonVo patrolInspectionPlanSonVo = new PatrolInspectionPlanSonVo();
                 patrolInspectionPlanSonVo.setId(planSonList.get(i).getId());
@@ -994,7 +998,7 @@ public class PatrolInspectionPlanSonServiceImpl extends AbstractCrudService<Patr
                 patrolInspectionPlanSonVo.setInspectionDate(planSonList.get(i).getInspectionDate());
                 patrolInspectionPlanSonVo.setPatrolledSiteCount(0);
                 patrolInspectionPlanSonVo.setUndetectedSiteCount(0);
-                //计划名称
+                // 计划名称
                 for (int j = 0; j < planList.size(); j++) {
                     if (planSonList.get(i).getPlanId().equals(planList.get(j).getId())) {
                         patrolInspectionPlanSonVo.setPlanId(planList.get(j).getId());
@@ -1005,7 +1009,7 @@ public class PatrolInspectionPlanSonServiceImpl extends AbstractCrudService<Patr
                 Date currentTime = new Date();
                 Date endTime = null;
                 if (planSonList.get(i).getPlanType() == 1) {
-                    //获取结束日期时间
+                    // 获取结束日期时间
                     LocalDate inspectionDate = planSonList.get(i).getInspectionDate();
                     String inspectionDateOne = df1.format(inspectionDate);
                     String inspectionDateTwo = inspectionDateOne + " " + planSonList.get(i).getEndTime();
@@ -1015,14 +1019,14 @@ public class PatrolInspectionPlanSonServiceImpl extends AbstractCrudService<Patr
                     }
 
                 } else {
-                    //获取结束日期时间
+                    // 获取结束日期时间
                     LocalDate endDate = planSonList.get(i).getEndDate();
                     String endDateOne = df1.format(endDate) + " 23:59:59";
                     try {
                         endTime = formatter.parse(endDateOne);
                     } catch (Exception e) {
                     }
-                    //计划类型描述
+                    // 计划类型描述
                     String planCycleName = null;
                     if (planSonList.get(i).getPlanCycle() == 1) {
                         planCycleName = "(日)";
@@ -1035,7 +1039,7 @@ public class PatrolInspectionPlanSonServiceImpl extends AbstractCrudService<Patr
                     }
                     patrolInspectionPlanSonVo.setPlanTypeDescribe("按次计划" + planCycleName);
                 }
-                //判断计划状态
+                // 判断计划状态
                 int status = endTime.compareTo(currentTime);
                 if (status == -1) {
                     if (planSonList.get(i).getCompletion() == 100) {

+ 1 - 1
service-iot/service-iot-biz/src/main/java/com/usky/iot/controller/web/DmpProductInfoController.java

@@ -34,7 +34,7 @@ public class DmpProductInfoController {
      * @return
      */
     @PostMapping
-    public ApiResult<Void> add(@RequestBody DmpProductInfo dmpProductInfo){
+    public ApiResult<Void> add(@RequestBody List<DmpProductInfo> dmpProductInfo){
         dmpProductInfoService.add(dmpProductInfo);
         return ApiResult.success();
     }

+ 34 - 4
service-iot/service-iot-biz/src/main/java/com/usky/iot/controller/web/PmTimeConfController.java

@@ -2,6 +2,8 @@ package com.usky.iot.controller.web;
 
 
 import com.usky.common.core.bean.CommonPage;
+import com.usky.common.log.annotation.Log;
+import com.usky.common.log.enums.BusinessType;
 import com.usky.common.security.utils.SecurityUtils;
 import com.usky.iot.domain.PmTimeConf;
 import com.usky.iot.domain.PmWorkReport;
@@ -9,12 +11,9 @@ import com.usky.iot.service.PmTimeConfService;
 import com.usky.iot.service.vo.PmSubmitCountResponseVO;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.*;
 
 import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
 
 import java.time.LocalDate;
 import java.time.LocalDateTime;
@@ -85,5 +84,36 @@ public class PmTimeConfController {
         return pmTimeConfService.getTimeConf(tenantId);
     }
 
+    /**
+     * 添加配置时间
+     * @param pmTimeConf 配置时间
+     */
+    @Log(title = "新增配置时间", businessType = BusinessType.INSERT)
+    @PostMapping("/addTimeConf")
+    public void addTimeConf(@RequestBody PmTimeConf pmTimeConf) {
+        pmTimeConfService.addOrUpdateTimeConf(pmTimeConf);
+    }
+
+    /**
+     * 修改配置时间
+     * @param pmTimeConf 配置时间
+     */
+    @Log(title = "修改配置时间", businessType = BusinessType.UPDATE)
+    @PutMapping("/updateTimeConf")
+    public void updateTimeConf(@RequestBody PmTimeConf pmTimeConf) {
+        pmTimeConfService.addOrUpdateTimeConf(pmTimeConf);
+    }
+
+    /**
+     * 打开或关闭提醒
+     * @param isOpen 是否开启 0:关闭 1:开启
+     * @param id 配置id
+     */
+    @PutMapping("/isOpen")
+    public void isOpen(@RequestParam(value = "isOpen") Integer isOpen,
+                       @RequestParam(value = "id") Integer id) {
+        pmTimeConfService.isOpen(isOpen, id);
+    }
+
 }
 

+ 21 - 0
service-iot/service-iot-biz/src/main/java/com/usky/iot/controller/web/VcDeviceController.java

@@ -5,10 +5,13 @@ import com.usky.common.core.bean.ApiResult;
 import com.usky.common.core.bean.CommonPage;
 import com.usky.iot.domain.BaseGgpFacility;
 import com.usky.iot.domain.VcDevice;
+import com.usky.iot.domain.VcStream;
 import com.usky.iot.service.VcDeviceService;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.web.bind.annotation.*;
 
+import javax.annotation.Resource;
 import java.util.List;
 
 /**
@@ -56,6 +59,24 @@ public class VcDeviceController {
         return ApiResult.success(vcDeviceService.pageList(videoNumber, videoName, groupId, pageNum, pageSize));
     }
 
+    /**
+     * 实时拉取摄像头视频流
+     * @param deviceUuid
+     * @return
+     */
+    @GetMapping("getVcDeviceVideo")
+    public ApiResult<String> getVcDeviceVideo(@RequestParam(value = "deviceUuid") String deviceUuid) {
+        return ApiResult.success(vcDeviceService.getVcDeviceVideo(deviceUuid));
+    }
+
+    /**
+     * 停止拉取摄像头视频流
+     */
+    @GetMapping("stopDeviceVideo")
+    public void stopDeviceVideo(){
+        vcDeviceService.stopDeviceVideo();
+    }
+
     /**
      * 新增
      * @param vcDevice

+ 5 - 0
service-iot/service-iot-biz/src/main/java/com/usky/iot/domain/DmpDeviceType.java

@@ -87,5 +87,10 @@ public class DmpDeviceType implements Serializable {
      */
     private LocalDateTime updatedTime;
 
+    /**
+     * 命令字段
+     */
+    private String commandField;
+
 
 }

+ 5 - 0
service-iot/service-iot-biz/src/main/java/com/usky/iot/domain/PmTimeConf.java

@@ -83,5 +83,10 @@ public class PmTimeConf implements Serializable {
      */
     private Integer tenantId;
 
+    /**
+     * 通知人
+     */
+    private String notifier;
+
 
 }

+ 1 - 0
service-iot/service-iot-biz/src/main/java/com/usky/iot/mapper/BaseFacilityTypeMapper.java

@@ -19,6 +19,7 @@ import java.util.List;
 @Repository
 public interface BaseFacilityTypeMapper extends CrudMapper<BaseFacilityType> {
     List<BaseGgpFacilityTypeNumVO> typeNumList(@Param("tenantId") Integer tenantId);
+    List<BaseGgpFacilityTypeNumVO> facilitTypeNumList();
     List<BaseGgpFacilityTypeNumVO> typeNormalNumList(@Param("tenantId") Integer tenantId);
     List<BaseGgpFacilityTypeNumVO> typeUpkeepNumList(@Param("tenantId") Integer tenantId);
     List<BaseGgpFacilityTypeNumVO> typeCloseNumList(@Param("tenantId") Integer tenantId);

+ 2 - 1
service-iot/service-iot-biz/src/main/java/com/usky/iot/mapper/PmWorkContentMapper.java

@@ -27,7 +27,8 @@ public interface PmWorkContentMapper extends CrudMapper<PmWorkContent> {
 
     List<PmProjectWorkTimeVo> workTimeCount(@Param("startTime") LocalDateTime startTime,
                                             @Param("endTime") LocalDateTime endTime,
-                                            @Param("userId") Long userId);
+                                            @Param("userId") Long userId,
+                                            @Param("tenantId") Integer tenantId);
 
 /*    List<WorkHoursStatisticsVO> workHoursStatistics(@Param("startTime") LocalDate startTime,
                                                     @Param("endTime") LocalDate endTime,

+ 1 - 1
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/DmpProductInfoService.java

@@ -19,7 +19,7 @@ import java.util.Map;
 public interface DmpProductInfoService extends CrudService<DmpProductInfo> {
 
 
-    void add(DmpProductInfo dmpProductInfo);
+    void add(List<DmpProductInfo> dmpProductInfo);
 
     void update(DmpProductInfo dmpProductInfo);
 

+ 13 - 0
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/PmTimeConfService.java

@@ -42,4 +42,17 @@ public interface PmTimeConfService extends CrudService<PmTimeConf> {
      * @return
      */
     public PmTimeConf getTimeConf(Integer tenantId);
+
+    /**
+     * 添加或修改报告统计时间配置
+     * @param pmTimeConf
+     */
+    public void addOrUpdateTimeConf(PmTimeConf pmTimeConf);
+
+    /**
+     * 获取迟交报告
+     * @param isOpen 是否开启(0:关闭,1:开启)
+     * @param id 配置id
+     */
+    void isOpen(Integer isOpen, Integer id);
 }

+ 5 - 0
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/VcDeviceService.java

@@ -4,6 +4,7 @@ import com.usky.common.core.bean.CommonPage;
 import com.usky.iot.domain.BaseGgpFacility;
 import com.usky.iot.domain.VcDevice;
 import com.usky.common.mybatis.core.CrudService;
+import org.springframework.web.bind.annotation.RequestBody;
 
 import java.util.List;
 
@@ -20,6 +21,10 @@ public interface VcDeviceService extends CrudService<VcDevice> {
 
     CommonPage<VcDevice> pageList(String videoNumber, String videoName, Integer groupId ,Integer pageNum, Integer pageSize);
 
+    String getVcDeviceVideo(String deviceUuid);
+
+    void stopDeviceVideo();
+
     boolean add(VcDevice vcDevice);
 
     void update(VcDevice vcDevice);

+ 69 - 0
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/config/DeviceOperate.java

@@ -0,0 +1,69 @@
+package com.usky.iot.service.config;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.usky.backend.domain.StatusVO;
+import com.usky.common.core.bean.ApiResult;
+import com.usky.demo.RemoteTsdbProxyService;
+import com.usky.iot.domain.BaseAlarm;
+import com.usky.iot.domain.DmpDeviceInfo;
+import com.usky.iot.domain.DmpDeviceStatus;
+import com.usky.iot.mapper.DmpDeviceStatusMapper;
+import com.usky.iot.service.BaseAlarmService;
+import com.usky.iot.service.DmpDeviceStatusService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.Async;
+
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+@Slf4j
+@Configuration
+public class DeviceOperate {
+    @Autowired
+    private RemoteTsdbProxyService remoteTsdbProxyService;
+
+    @Autowired
+    DmpDeviceStatusService dmpDeviceStatusService;
+
+    @Async
+    public void updateDeviceStatus(){
+        log.info("定时同步设备状态数据 start");
+        ApiResult<List<Map<String,Object>>> list = remoteTsdbProxyService.getAllDeviceRealTime();
+        List<Map<String,Object>> dataList = list.getData();
+        if(CollectionUtils.isNotEmpty(dataList)){
+            for(int i=0;i<dataList.size();i++){
+                String deviceuuid = dataList.get(i).get("deviceuuid").toString();
+                LocalDateTime lTime = Instant.ofEpochMilli(Long.valueOf(dataList.get(i).get("time").toString())).atZone(ZoneOffset.ofHours(8)).toLocalDateTime();
+                String date =  lTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+                String currentDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+                LambdaUpdateWrapper<DmpDeviceStatus> updateWrapper = Wrappers.lambdaUpdate();
+                if(date.equals(currentDate)){
+                    updateWrapper.set(DmpDeviceStatus::getDeviceStatus,1)  //设备在线
+                            .set(DmpDeviceStatus::getLastOnlineTime,lTime)
+                            .eq(DmpDeviceStatus::getDeviceUuid,deviceuuid);
+
+                }else{
+                    updateWrapper.set(DmpDeviceStatus::getDeviceStatus,2)  //设备离线
+                            .set(DmpDeviceStatus::getLastOnlineTime,lTime)
+                            .eq(DmpDeviceStatus::getDeviceUuid,deviceuuid);
+
+                }
+                dmpDeviceStatusService.update(updateWrapper);
+
+            }
+
+        }
+        log.info("定时同步设备状态数据 end");
+    }
+}

+ 61 - 58
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/BaseAlarmServiceImpl.java

@@ -30,6 +30,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
@@ -624,9 +625,67 @@ public class BaseAlarmServiceImpl extends AbstractCrudService<BaseAlarmMapper, B
         }
     }
 
+    @Async
+    public void deviceAlarm(List<StatusVO> list, List<DmpDeviceInfo> devInfoList, List<BaseAlarm> baseUnAlarmList){
+        log.info("定时同步设备告警数据 start");
+        if(CollectionUtils.isNotEmpty(devInfoList)){
+            for(int i=0;i<list.size();i++){
+                String currentDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+                if(Objects.nonNull(list.get(i).getTime()) && currentDate.equals(list.get(i).getTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))){
+                    //设备离线告警恢复在线自动默认处理
+                    if(CollectionUtils.isNotEmpty(baseUnAlarmList)){
+                        for(int j=0;j<baseUnAlarmList.size();j++){
+                            if(list.get(i).getDeviceId().equals(baseUnAlarmList.get(j).getDeviceId()) && list.get(i).getProductCode().equals(baseUnAlarmList.get(j).getProductCode())){
+                                LambdaUpdateWrapper<BaseAlarm> updateWrapper1 = Wrappers.lambdaUpdate();
+                                updateWrapper1.set(BaseAlarm::getHandleStatus,1)
+                                        .set(BaseAlarm::getHandleBy,"YT_admin")
+                                        .set(BaseAlarm::getHandleTime,LocalDateTime.now())
+                                        .eq(BaseAlarm::getDeviceId,list.get(i).getDeviceId())
+                                        .eq(BaseAlarm::getHandleStatus,0)
+                                        .eq(BaseAlarm::getProductCode,list.get(i).getProductCode());
+                                this.update(updateWrapper1);
+                                break;
+                            }
+                        }
+                    }
+
+                }else{
+
+                    for(int j=0;j<devInfoList.size();j++){
+                        if(list.get(i).getDeviceId().equals(devInfoList.get(j).getDeviceId()) && list.get(i).getProductCode().equals(devInfoList.get(j).getProductCode())){
+                            int count = 0;
+                            for(int k=0;k<baseUnAlarmList.size();k++){
+                                if(list.get(i).getDeviceId().equals(baseUnAlarmList.get(k).getDeviceId()) && list.get(i).getProductCode().equals(baseUnAlarmList.get(k).getProductCode())){
+                                    count++;
+                                }
+                            }
+                            if(count == 0){
+                                BaseAlarm baseAlarm = new BaseAlarm();
+                                baseAlarm.setDeviceId(list.get(i).getDeviceId());
+                                baseAlarm.setAlarmTime(LocalDateTime.parse(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH"))+":00:00",DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+                                baseAlarm.setAlarmType("001");
+                                baseAlarm.setAlarmObject(devInfoList.get(j).getDeviceName());
+                                baseAlarm.setAlarmData("");
+                                baseAlarm.setAlarmAttribute("离线告警");
+                                baseAlarm.setAlarmContent("设备离线告警");
+                                baseAlarm.setAlarmGrade(1);
+
+                                baseAlarm.setAlarmAddress(devInfoList.get(j).getInstallAddress());
+                                baseAlarm.setProductCode(devInfoList.get(j).getProductCode());
+                                this.add(baseAlarm);
+                            }
+                            break;
+                        }
+                    }
+
+                }
+            }
+        }
+        log.info("定时同步设备告警数据 end");
+    }
+
     @Override
     public void deviceOffLineAlarm(){
-        log.info("定时同步设备告警数据 start");
         List<StatusVO> list = new ArrayList<>();
         List<String> devList = new ArrayList<>();
         LambdaQueryWrapper<DmpDeviceStatus> queryWrapper = Wrappers.lambdaQuery();
@@ -646,69 +705,13 @@ public class BaseAlarmServiceImpl extends AbstractCrudService<BaseAlarmMapper, B
         if(CollectionUtils.isNotEmpty(list)){
             List<DmpDeviceInfo> devInfoList = new ArrayList<>();
             List<BaseAlarm> baseUnAlarmList = new ArrayList<>();
-//            List<BaseAlarm> baseAlarmList = new ArrayList<>();
             if(devList.size() > 0) {
                 devInfoList = baseMapper.getDeviceInfoList(devList);
                 baseUnAlarmList = baseMapper.getUnDeviceAlarmList(devList);
-//                baseAlarmList = baseMapper.getDeviceAlarmList(devList);
-            }
-
-            if(CollectionUtils.isNotEmpty(devInfoList)){
-                for(int i=0;i<list.size();i++){
-                    String currentDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
-                    if(Objects.nonNull(list.get(i).getTime()) && currentDate.equals(list.get(i).getTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))){
-                        //设备离线告警恢复在线自动默认处理
-                        if(CollectionUtils.isNotEmpty(baseUnAlarmList)){
-                            for(int j=0;j<baseUnAlarmList.size();j++){
-                                if(list.get(i).getDeviceId().equals(baseUnAlarmList.get(j).getDeviceId()) && list.get(i).getProductCode().equals(baseUnAlarmList.get(j).getProductCode())){
-                                    LambdaUpdateWrapper<BaseAlarm> updateWrapper1 = Wrappers.lambdaUpdate();
-                                    updateWrapper1.set(BaseAlarm::getHandleStatus,1)
-                                            .set(BaseAlarm::getHandleBy,"YT_admin")
-                                            .set(BaseAlarm::getHandleTime,LocalDateTime.now())
-                                            .eq(BaseAlarm::getDeviceId,list.get(i).getDeviceId())
-                                            .eq(BaseAlarm::getHandleStatus,0)
-                                            .eq(BaseAlarm::getProductCode,list.get(i).getProductCode());
-                                    this.update(updateWrapper1);
-                                    break;
-                                }
-                            }
-                        }
-
-                    }else{
-
-                        for(int j=0;j<devInfoList.size();j++){
-                            if(list.get(i).getDeviceId().equals(devInfoList.get(j).getDeviceId()) && list.get(i).getProductCode().equals(devInfoList.get(j).getProductCode())){
-                                int count = 0;
-                                for(int k=0;k<baseUnAlarmList.size();k++){
-                                    if(list.get(i).getDeviceId().equals(baseUnAlarmList.get(k).getDeviceId()) && list.get(i).getProductCode().equals(baseUnAlarmList.get(k).getProductCode())){
-                                        count++;
-                                    }
-                                }
-                                if(count == 0){
-                                    BaseAlarm baseAlarm = new BaseAlarm();
-                                    baseAlarm.setDeviceId(list.get(i).getDeviceId());
-                                    baseAlarm.setAlarmTime(LocalDateTime.parse(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH"))+":00:00",DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
-                                    baseAlarm.setAlarmType("001");
-                                    baseAlarm.setAlarmObject(devInfoList.get(j).getDeviceName());
-                                    baseAlarm.setAlarmData("");
-                                    baseAlarm.setAlarmAttribute("离线告警");
-                                    baseAlarm.setAlarmContent("设备离线告警");
-                                    baseAlarm.setAlarmGrade(1);
-
-                                    baseAlarm.setAlarmAddress(devInfoList.get(j).getInstallAddress());
-                                    baseAlarm.setProductCode(devInfoList.get(j).getProductCode());
-                                    this.add(baseAlarm);
-                                }
-                                break;
-                            }
-                        }
-
-                    }
-                }
             }
 
+            this.deviceAlarm(list,devInfoList,baseUnAlarmList);
         }
-        log.info("定时同步设备告警数据 end");
     }
 
     @Override

+ 0 - 1
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/BaseBuildServiceImpl.java

@@ -22,7 +22,6 @@ import com.usky.iot.service.vo.BuildFacilityStatusVO;
 import org.apache.tomcat.jni.Local;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
-import sun.security.util.Length;
 
 import java.text.SimpleDateFormat;
 import java.time.LocalDateTime;

+ 12 - 4
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/BaseGgpFacilityServiceImpl.java

@@ -149,13 +149,11 @@ public class BaseGgpFacilityServiceImpl extends AbstractCrudService<BaseGgpFacil
         if (CollectionUtils.isNotEmpty(baseGgpFacilityList)) {
             for (int i = 0; i < baseGgpFacilityList.size(); i++) {
                 BaseGgpFacilityExportVo baseGgpFacilityExportVo = new BaseGgpFacilityExportVo();
-                baseGgpFacilityExportVo.setXh(i + 1);
-                baseGgpFacilityExportVo.setId(baseGgpFacilityList.get(i).getId());
                 baseGgpFacilityExportVo.setFacilityNum(baseGgpFacilityList.get(i).getFacilityNum());
                 baseGgpFacilityExportVo.setFacilityType("未知");
                 if (CollectionUtils.isNotEmpty(typeList)) {
                     for (int j = 0; j < typeList.size(); j++) {
-                        if (baseGgpFacilityList.get(i).getFacilityType().equals(typeList.get(j).getId())) {
+                        if (baseGgpFacilityList.get(i).getFacilityType().equals(typeList.get(j).getTypeCode())) {
                             baseGgpFacilityExportVo.setFacilityType(typeList.get(j).getTypeName());
                         }
                     }
@@ -166,7 +164,9 @@ public class BaseGgpFacilityServiceImpl extends AbstractCrudService<BaseGgpFacil
                 baseGgpFacilityExportVo.setImagesUrl(baseGgpFacilityList.get(i).getImagesUrl());
                 baseGgpFacilityExportVo.setContact(baseGgpFacilityList.get(i).getContact());
                 baseGgpFacilityExportVo.setContactPhone(baseGgpFacilityList.get(i).getContactPhone());
-                baseGgpFacilityExportVo.setStatus(baseGgpFacilityList.get(i).getFacilityStatus());
+                baseGgpFacilityExportVo.setFacilityStatus(baseGgpFacilityList.get(i).getFacilityStatus());
+                baseGgpFacilityExportVo.setLongitude(baseGgpFacilityList.get(i).getLongitude());
+                baseGgpFacilityExportVo.setLatitude(baseGgpFacilityList.get(i).getLatitude());
                 baseGgpFacilityExportVo.setCreateTime(baseGgpFacilityList.get(i).getCreateTime().format(df));
                 list.add(baseGgpFacilityExportVo);
             }
@@ -435,6 +435,14 @@ public class BaseGgpFacilityServiceImpl extends AbstractCrudService<BaseGgpFacil
                 int rot=3;
                 for (FacilityImportVo facilityImportVo:facilityImportVos) {
                     BaseGgpFacility baseGgpFacility = BeanMapperUtils.map(facilityImportVo, BaseGgpFacility.class);
+                    List<BaseGgpFacilityTypeNumVO> typeList = baseFacilityTypeMapper.facilitTypeNumList();
+                    if (CollectionUtils.isNotEmpty(typeList)) {
+                        for (int j = 0; j < typeList.size(); j++) {
+                            if (baseGgpFacility.getFacilityType().equals(typeList.get(j).getTypeName())) {
+                                baseGgpFacility.setFacilityType(typeList.get(j).getTypeCode());
+                            }
+                        }
+                    }
                     if (StringUtils.isBlank(baseGgpFacility.getFacilityType())||StringUtils.isBlank(baseGgpFacility.getFacilityName())||StringUtils.isBlank(baseGgpFacility.getAddress())||StringUtils.isBlank(baseGgpFacility.getLatitude())||StringUtils.isBlank(baseGgpFacility.getLongitude())){
 
                         String tmp = ",第"+rot+"行数据导入失败,必填字段不能为空";

+ 8 - 45
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/DmpDeviceInfoServiceImpl.java

@@ -40,16 +40,17 @@ import com.usky.iot.service.BaseFacilityDeviceService;
 import com.usky.iot.service.DmpDeviceInfoService;
 import com.usky.iot.service.DmpDeviceStatusService;
 import com.usky.iot.service.DmpProductAttributeService;
+import com.usky.iot.service.config.DeviceOperate;
 import com.usky.iot.service.enums.TopicInfo;
 import com.usky.iot.service.vo.*;
 import com.usky.transfer.RemoteTransferService;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.poi.ss.usermodel.Workbook;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.interceptor.TransactionAspectSupport;
 import org.springframework.web.multipart.MultipartFile;
-import sun.net.dns.ResolverConfiguration;
 
 import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletResponse;
@@ -97,6 +98,9 @@ public class DmpDeviceInfoServiceImpl extends AbstractCrudService<DmpDeviceInfoM
 	@Autowired
     private DmpProductAttributeMapper dmpProductAttributeMapper;
 
+    @Autowired
+    private DeviceOperate deviceOperate;
+
     private static final String ALARM_HTTP_URL = "/service-alarm/baseAlarm/alarmInfo";
 
 
@@ -425,50 +429,9 @@ public class DmpDeviceInfoServiceImpl extends AbstractCrudService<DmpDeviceInfoM
 
     @Override
     public void deviceStatus(){
-        log.info("定时同步设备状态数据 start");
-        LastInnerQueryVO queryVO = new LastInnerQueryVO();
-        List<String> deviceuuidList = new ArrayList<>();
-        LambdaQueryWrapper<DmpDeviceInfo> queryWrapper = Wrappers.lambdaQuery();
-        queryWrapper.select(DmpDeviceInfo::getDeviceUuid)
-                .eq(DmpDeviceInfo::getDeleteFlag,0)
-                .ne(DmpDeviceInfo::getServiceStatus,3)
-                .orderByDesc(DmpDeviceInfo::getId);
-        List<DmpDeviceInfo> devList = this.list(queryWrapper);
-        if(CollectionUtils.isNotEmpty(devList)){
-            int count = devList.size();
-            for (int i = 0; i < devList.size(); i++) {
-                deviceuuidList.add(devList.get(i).getDeviceUuid());
-            }
-        }
-        queryVO.setDeviceuuid(deviceuuidList);
-
-        List<LastInnerResultVO> list = remoteTsdbProxyService.last(queryVO);
-        if(CollectionUtils.isNotEmpty(list)){
-            for(int i=0;i<list.size();i++){
-                if(Objects.nonNull(list.get(i).getMetrics())){
-                    String deviceuuid = list.get(i).getDeviceuuid();
-                    LocalDateTime lTime = Instant.ofEpochMilli(Long.valueOf(list.get(i).getMetrics().get("time").toString())).atZone(ZoneOffset.ofHours(8)).toLocalDateTime();
-                    String date =  lTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
-                    String currentDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
-                    LambdaUpdateWrapper<DmpDeviceStatus> updateWrapper = Wrappers.lambdaUpdate();
-                    if(date.equals(currentDate)){
-                        updateWrapper.set(DmpDeviceStatus::getDeviceStatus,1)  //设备在线
-                                .set(DmpDeviceStatus::getLastOnlineTime,lTime)
-                                .eq(DmpDeviceStatus::getDeviceUuid,deviceuuid);
-
-                    }else{
-                        updateWrapper.set(DmpDeviceStatus::getDeviceStatus,2)  //设备离线
-                                .set(DmpDeviceStatus::getLastOnlineTime,lTime)
-                                .eq(DmpDeviceStatus::getDeviceUuid,deviceuuid);
-
-                    }
-                    dmpDeviceStatusService.update(updateWrapper);
-                }
-
-            }
-
-        }
-        log.info("定时同步设备状态数据 end");
+        log.info("设备状态 start");
+        deviceOperate.updateDeviceStatus();
+        log.info("设备状态 end");
     }
 
     @Override

+ 106 - 58
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/DmpProductInfoServiceImpl.java

@@ -58,72 +58,120 @@ public class DmpProductInfoServiceImpl extends AbstractCrudService<DmpProductInf
     @Autowired
     private RemoteTransferService remoteTransferService;
 
+    @Autowired
+    private DmpProductCommandService dmpProductCommandService;
+
     @Override
-    public void add(DmpProductInfo dmpProductInfo) {
-        if (checkNameUnique(dmpProductInfo)){
-            throw new BusinessException("新增产品信息'" + dmpProductInfo.getProductCode() + "'失败,产品信息已存在");
+    public void add(List<DmpProductInfo> dmpProductInfo) {
+        if (CollectionUtils.isEmpty(dmpProductInfo)) {
+            throw new BusinessException("数据不能为空");
         }
-        int deviceType = dmpProductInfo.getDeviceType();
-        LambdaQueryWrapper<DmpDeviceType> queryWrapper = Wrappers.lambdaQuery();
-        queryWrapper.select(DmpDeviceType::getDataField)
-                .eq(DmpDeviceType::getTypeCode,deviceType);
-        DmpDeviceType one  = dmpDeviceTypeService.getOne(queryWrapper);
-        String dd = one.getDataField();
-        if (StringUtils.isBlank(dd) || dd.length() == 0){
-            throw new BusinessException("新增产品信息'" + dmpProductInfo.getProductCode() + "'失败,设备类型缺少属性");
-        }
-
-        QueryWrapper<DmpProductInfo> query = Wrappers.query();
-        query.select("max(id) as id");
-        DmpProductInfo info1 = this.getOne(query);
-        int id = info1.getId()+1;
-        String productCode = String.format("%03d",deviceType)+"_"+String.format("%04d",id);
-        dmpProductInfo.setProductCode(productCode);
 
-        dmpProductInfo.setCreatedBy(SecurityUtils.getUsername());
-        dmpProductInfo.setCreatedTime(new Date());
-        dmpProductInfo.setDeleteFlag(0);
-        dmpProductInfo.setTenantId(SecurityUtils.getTenantId());
-        this.save(dmpProductInfo);
+        for (int k = 0; k < dmpProductInfo.size(); k++) {
+            if (checkNameUnique(dmpProductInfo.get(k))){
+                throw new BusinessException("新增产品信息'" + dmpProductInfo.get(k).getProductCode() + "'失败,产品信息已存在");
+            }
+            int deviceType = dmpProductInfo.get(k).getDeviceType();
+            LambdaQueryWrapper<DmpDeviceType> queryWrapper = Wrappers.lambdaQuery();
+            queryWrapper.select(DmpDeviceType::getDataField,DmpDeviceType::getCommandField)
+                    .eq(DmpDeviceType::getTypeCode,deviceType);
+            DmpDeviceType one  = dmpDeviceTypeService.getOne(queryWrapper);
+            String dd = one.getDataField();
+            if (StringUtils.isBlank(dd) || dd.length() == 0){
+                throw new BusinessException("新增产品信息'" + dmpProductInfo.get(k).getProductCode() + "'失败,设备类型缺少属性");
+            }
 
-        remoteTransferService.deleteProductCache();
+            QueryWrapper<DmpProductInfo> query = Wrappers.query();
+            query.select("max(id) as id");
+            DmpProductInfo info1 = this.getOne(query);
+            int id = info1.getId()+1;
+            String productCode = String.format("%03d",deviceType)+"_"+id;
+            dmpProductInfo.get(k).setProductCode(productCode);
+
+            dmpProductInfo.get(k).setCreatedBy(SecurityUtils.getUsername());
+            dmpProductInfo.get(k).setCreatedTime(new Date());
+            dmpProductInfo.get(k).setDeleteFlag(0);
+            dmpProductInfo.get(k).setTenantId(SecurityUtils.getTenantId());
+            this.save(dmpProductInfo.get(k));
+
+            remoteTransferService.deleteProductCache();
+
+            int productId = dmpProductInfo.get(k).getId();
+            if(null != one){
+                if(Objects.nonNull(one.getDataField())){
+                    String dataField = one.getDataField();
+                    JSONArray array = new JSONArray();
+                    array =  JSONArray.parseArray(dataField);
+                    if(array.size()>0){
+                        for(int i=0;i<array.size();i++){
+                            JSONObject obj = JSONObject.parseObject(array.getString(i));
+                            String attribute_name = obj.getString("attribute_name");
+                            String attribute_code = obj.getString("attribute_code");
+                            int attribute_port = obj.getInteger("attribute_port");
+                            int data_type = obj.getInteger("data_type");
+                            int attribute_length = obj.getInteger("attribute_length");
+                            String attribute_unit = obj.getString("attribute_unit");
+                            int maximum = obj.getInteger("maximum");
+                            int minimum = obj.getInteger("minimum");
+
+                            DmpProductAttribute dmpProductAttribute = new DmpProductAttribute();
+                            dmpProductAttribute.setProductId(productId);
+                            dmpProductAttribute.setAttributeName(attribute_name);
+                            dmpProductAttribute.setAttributeCode(attribute_code);
+                            dmpProductAttribute.setAttributePort(attribute_port);
+                            dmpProductAttribute.setAttributeType(1);
+                            dmpProductAttribute.setDataType(data_type);
+                            dmpProductAttribute.setAttributeLength(attribute_length);
+                            dmpProductAttribute.setAttributeUnit(attribute_unit);
+                            dmpProductAttribute.setMaximum(BigDecimal.valueOf(maximum));
+                            dmpProductAttribute.setMinimum(BigDecimal.valueOf(minimum));
+                            dmpProductAttribute.setDeleteFlag(0);
+                            dmpProductAttribute.setCreatedBy(SecurityUtils.getUsername());
+                            dmpProductAttribute.setCreatedTime(new Date());
+                            dmpProductAttribute.setTenantId(SecurityUtils.getTenantId());
+                            dmpProductAttributeService.save(dmpProductAttribute);
+                        }
+                    }
+                }
 
-        int productId = dmpProductInfo.getId();
-        if(null != one){
-            String dataField = one.getDataField();
-            JSONArray array = new JSONArray();
-            array =  JSONArray.parseArray(dataField);
-            if(array.size()>0){
-                for(int i=0;i<array.size();i++){
-                    JSONObject obj = JSONObject.parseObject(array.getString(i));
-                    String attribute_name = obj.getString("attribute_name");
-                    String attribute_code = obj.getString("attribute_code");
-                    int attribute_port = obj.getInteger("attribute_port");
-                    int data_type = obj.getInteger("data_type");
-                    int attribute_length = obj.getInteger("attribute_length");
-                    String attribute_unit = obj.getString("attribute_unit");
-                    int maximum = obj.getInteger("maximum");
-                    int minimum = obj.getInteger("minimum");
-
-                    DmpProductAttribute dmpProductAttribute = new DmpProductAttribute();
-                    dmpProductAttribute.setProductId(productId);
-                    dmpProductAttribute.setAttributeName(attribute_name);
-                    dmpProductAttribute.setAttributeCode(attribute_code);
-                    dmpProductAttribute.setAttributePort(attribute_port);
-                    dmpProductAttribute.setAttributeType(1);
-                    dmpProductAttribute.setDataType(data_type);
-                    dmpProductAttribute.setAttributeLength(attribute_length);
-                    dmpProductAttribute.setAttributeUnit(attribute_unit);
-                    dmpProductAttribute.setMaximum(BigDecimal.valueOf(maximum));
-                    dmpProductAttribute.setMinimum(BigDecimal.valueOf(minimum));
-                    dmpProductAttribute.setDeleteFlag(0);
-                    dmpProductAttribute.setCreatedBy(SecurityUtils.getUsername());
-                    dmpProductAttribute.setCreatedTime(new Date());
-                    dmpProductAttribute.setTenantId(SecurityUtils.getTenantId());
-                    dmpProductAttributeService.save(dmpProductAttribute);
+                if(Objects.nonNull(one.getCommandField())){
+                    String commandField = one.getCommandField();
+                    JSONArray array = JSONArray.parseArray(commandField);
+                    if(array.size()>0){
+                        for(int i=0;i<array.size();i++){
+                            JSONObject obj = JSONObject.parseObject(array.getString(i));
+                            String command_name = obj.getString("command_name");
+                            String command_code = obj.getString("command_code");
+                            int data_type = obj.getInteger("data_type");
+
+                            DmpProductCommand dmpProductCommand = new DmpProductCommand();
+                            dmpProductCommand.setProductCode(productCode);
+                            dmpProductCommand.setCommandName(command_name);
+                            dmpProductCommand.setCommandCode(command_code);
+                            dmpProductCommand.setDataType(data_type);
+                            if(!(obj.getString("command_dict")).equals("")){
+                                dmpProductCommand.setCommandDict(obj.getString("command_dict"));
+                            }
+                            if(!(obj.getString("command_unit")).equals("")){
+                                dmpProductCommand.setCommandUnit(obj.getString("command_unit"));
+                            }
+                            if(!(obj.getString("maximum")).equals("")){
+                                dmpProductCommand.setMaximum(BigDecimal.valueOf(Long.parseLong(obj.getString("maximum"))));
+                            }
+                            if(!(obj.getString("minimum")).equals("")){
+                                dmpProductCommand.setMinimum(BigDecimal.valueOf(Long.parseLong(obj.getString("minimum"))));
+                            }
+                            dmpProductCommand.setDeleteFlag(0);
+                            dmpProductCommand.setCreatedBy(SecurityUtils.getUsername());
+                            dmpProductCommand.setCreatedTime(LocalDateTime.now());
+                            dmpProductCommand.setTenantId(SecurityUtils.getTenantId());
+                            dmpProductCommandService.save(dmpProductCommand);
+                        }
+                    }
                 }
             }
         }
+
     }
 
     @Override

+ 11 - 26
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/PmProjectServiceImpl.java

@@ -75,7 +75,7 @@ public class PmProjectServiceImpl extends AbstractCrudService<PmProjectMapper, P
         String projectName = project.getProjectName();
         if (StringUtils.isBlank(projectName)) {
             throw new BusinessException("项目名称不能为空!");
-        }else if (projectName.length() > 50) {
+        } else if (projectName.length() > 50) {
             throw new BusinessException("项目名称长度不能超过50个字符!");
         }
 
@@ -88,7 +88,7 @@ public class PmProjectServiceImpl extends AbstractCrudService<PmProjectMapper, P
         Integer projectType = project.getProjectType();
         if (projectType == null) {
             throw new BusinessException("项目类型不能为空且");
-        }else if (projectType < 1 || projectType > 6) {
+        } else if (projectType < 1 || projectType > 6) {
             throw new BusinessException("项目类型传参有误!");
         }
 
@@ -96,7 +96,7 @@ public class PmProjectServiceImpl extends AbstractCrudService<PmProjectMapper, P
         Integer projectStatus = project.getProjectStatus();
         if (projectStatus == null) {
             throw new BusinessException("项目状态不能为空且!");
-        }else if (projectStatus < 1 || projectStatus > 5) {
+        } else if (projectStatus < 1 || projectStatus > 5) {
             throw new BusinessException("项目状态传参有误!");
         }
 
@@ -249,43 +249,26 @@ public class PmProjectServiceImpl extends AbstractCrudService<PmProjectMapper, P
 
         LambdaQueryWrapper<PmProject> lambdaQuery = Wrappers.lambdaQuery();
         lambdaQuery.eq(PmProject::getTenantId, tenantId)
-                .eq(PmProject::getDelFlag, 0)
-                .eq(visibleRange != null, PmProject::getVisibleRange, visibleRange);
+                .eq(PmProject::getDelFlag, 0);
 
         if (projectId != null && projectId != 0) {
             lambdaQuery.eq(PmProject::getId, projectId);
-            page = this.page(page, lambdaQuery);
-            return new CommonPage<>(page.getRecords(), page.getTotal(), pageSize, pageNum);
         }
 
         switch (projectAscription) {
             case 0:
-                if (StringUtils.isNotBlank(projectName) || projectType != null || projectStatus != null) {
-                    lambdaQuery.eq(PmProject::getDelFlag, 0)
-                            .like(StringUtils.isNotBlank(projectName), PmProject::getProjectName, projectName)
-                            .eq(projectType != null, PmProject::getProjectType, projectType)
-                            .eq(projectStatus != null, PmProject::getProjectStatus, projectStatus)
+                if (visibleRange == null) {
+                    lambdaQuery.and(wrapper -> wrapper
                             .and(qw -> qw
                                     .eq(PmProject::getProjectHead, userId)
                                     .or()
                                     .apply("FIND_IN_SET('" + userId + "', project_member) > 0")
                                     .or()
-                                    .eq(PmProject::getCreateBy, username));
-                }
-                if (visibleRange == null) {
-                    lambdaQuery.eq(PmProject::getDelFlag, 0)
-                            .and(wrapper -> wrapper
-                                    .eq(PmProject::getVisibleRange, 2)
-                                    .and(qw -> qw
-                                            .eq(PmProject::getProjectHead, userId)
-                                            .or()
-                                            .apply("FIND_IN_SET('" + userId + "', project_member) > 0")
-                                            .or()
-                                            .eq(PmProject::getCreateBy, username))
+                                    .eq(PmProject::getCreateBy, username)
                             )
                             .or()
                             .eq(PmProject::getVisibleRange, 1)
-                            .eq(PmProject::getDelFlag, 0);
+                    );
                 } else if (visibleRange == 2) {
                     lambdaQuery.and(wrapper -> wrapper
                             .eq(PmProject::getProjectHead, userId)
@@ -314,7 +297,9 @@ public class PmProjectServiceImpl extends AbstractCrudService<PmProjectMapper, P
             default:
                 throw new BusinessException("查询项目列表参数错误");
         }
-        lambdaQuery.orderByDesc(PmProject::getCreateTime);
+
+        lambdaQuery.eq(visibleRange != null, PmProject::getVisibleRange, visibleRange)
+                .orderByDesc(PmProject::getCreateTime);
         List<PmProject> pmProjects = pmProjectMapper.selectList(lambdaQuery);
         if (pmProjects.isEmpty()) {
             return new CommonPage<>(pmProjects, 0, pageSize, pageNum);

+ 79 - 1
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/PmTimeConfServiceImpl.java

@@ -15,6 +15,7 @@ import com.usky.common.mybatis.core.AbstractCrudService;
 import com.usky.iot.service.vo.PmReportReadersVO;
 import com.usky.iot.service.vo.PmSubmitCountResponseVO;
 import com.usky.system.domain.SysUser;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -289,7 +290,8 @@ public class PmTimeConfServiceImpl extends AbstractCrudService<PmTimeConfMapper,
 
         LambdaQueryWrapper<PmWorkReport> reportQuery = new LambdaQueryWrapper<>();
         reportQuery.eq(PmWorkReport::getTenantId, tenantId)
-                .eq(PmWorkReport::getReportDate, countDate);
+                .eq(PmWorkReport::getReportDate, countDate)
+                .eq(PmWorkReport::getReportStatus, 1);
         switch (queryType) {
             // 按时提交
             case 0:
@@ -312,6 +314,82 @@ public class PmTimeConfServiceImpl extends AbstractCrudService<PmTimeConfMapper,
         return pmTimeConfMapper.selectOne(timeConfQuery);
     }
 
+    @Override
+    public void addOrUpdateTimeConf(PmTimeConf pmTimeConf) {
+        String username = SecurityUtils.getUsername();
+        Long deptId = SecurityUtils.getLoginUser().getSysUser().getDeptId();
+        LocalDateTime now = LocalDateTime.now();
+        if (pmTimeConf.getId() == null) {
+            Integer tenantId = SecurityUtils.getTenantId();
+            verificationTimeConf(pmTimeConf);
+            pmTimeConf.setTenantId(tenantId);
+            pmTimeConf.setCreateBy(username);
+            pmTimeConf.setCreateTime(now);
+            pmTimeConf.setDeptId(deptId);
+            pmTimeConfMapper.insert(pmTimeConf);
+        } else {
+            verificationTimeConf(pmTimeConf);
+            pmTimeConf.setUpdateBy(username);
+            pmTimeConf.setUpdateTime(now);
+            pmTimeConfMapper.updateById(pmTimeConf);
+        }
+    }
+
+    @Override
+    public void isOpen(Integer isOpen, Integer id) {
+        Long userId = SecurityUtils.getUserId();
+        String username = SecurityUtils.getUsername();
+        LocalDateTime now = LocalDateTime.now();
+        PmTimeConf pmTimeConf = pmTimeConfMapper.selectById(id);
+        if (pmTimeConf == null){
+            throw new BusinessException("配置不存在!联系管理员后重试");
+        }
+
+        if (isOpen == 1) {
+            pmTimeConf.setNotifier(pmTimeConf.getNotifier() + "," + userId);
+        } else if (isOpen == 0) {
+            pmTimeConf.setNotifier(pmTimeConf.getNotifier().replace("," + userId, ""));
+        } else {
+            throw new BusinessException("参数异常,报告提醒开关操作失败!");
+        }
+
+        pmTimeConf.setUpdateBy(username);
+        pmTimeConf.setUpdateTime(now);
+        pmTimeConfMapper.updateById(pmTimeConf);
+    }
+
+    private void verificationTimeConf(PmTimeConf pmTimeConf) {
+        if (StringUtils.isBlank(pmTimeConf.getConfName())) {
+            throw new BusinessException("配置名称不能为空!");
+        } else if (pmTimeConf.getConfName().length() > 64) {
+            throw new BusinessException("配置名称长度不能超过64个字符!");
+        }
+
+        if (StringUtils.isBlank(pmTimeConf.getConfType())) {
+            throw new BusinessException("配置类型不能为空!");
+        } else if (pmTimeConf.getConfType().length() > 64) {
+            throw new BusinessException("配置类型长度不能超过64个字符!");
+        }
+
+        if (pmTimeConf.getStartTime() == null) {
+            throw new BusinessException("开始时间不能为空!");
+        } else if (pmTimeConf.getStartTime().isAfter(pmTimeConf.getEndTime())) {
+            throw new BusinessException("开始时间不能大于结束时间!");
+        }
+
+        if (pmTimeConf.getEndTime() == null) {
+            throw new BusinessException("结束时间不能为空!");
+        } else if (pmTimeConf.getEndTime().isBefore(pmTimeConf.getStartTime())) {
+            throw new BusinessException("结束时间不能小于开始时间!");
+        }
+
+        if (pmTimeConf.getOnTime() == null) {
+            throw new BusinessException("准时时间不能为空!");
+        } else if (pmTimeConf.getOnTime().isBefore(pmTimeConf.getStartTime()) || pmTimeConf.getOnTime().isAfter(pmTimeConf.getEndTime())) {
+            throw new BusinessException("准时时间必须在开始时间和结束时间之间!");
+        }
+    }
+
     // 查询用户信息
     private List<SysUser> users(Integer tenantId) {
         LambdaQueryWrapper<SysUser> userQuery = new LambdaQueryWrapper<>();

+ 15 - 8
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/PmWorkReportServiceImpl.java

@@ -95,6 +95,9 @@ public class PmWorkReportServiceImpl extends AbstractCrudService<PmWorkReportMap
      */
     @Override
     public List<Map<String, List<PmWorkReport>>> weekWork(String startDate, String endDate, Integer reportId) {
+        Long userId = SecurityUtils.getUserId();
+        Integer tenantId = SecurityUtils.getTenantId();
+
         List<Map<String, List<PmWorkReport>>> returnList = new ArrayList<>();
         List<PmWorkReport> report = new ArrayList<>();
         Map<String, List<PmWorkReport>> weekData = new HashMap<>();
@@ -114,9 +117,10 @@ public class PmWorkReportServiceImpl extends AbstractCrudService<PmWorkReportMap
             dates.add(tempDate);
             tempDate = tempDate.plusDays(1);
         }
+
         // 返回最新的一条数据给前端填充
         LambdaQueryWrapper<PmWorkReport> wrapper2 = Wrappers.lambdaQuery();
-        wrapper2.eq(PmWorkReport::getSubmitterId, SecurityUtils.getUserId())
+        wrapper2.eq(PmWorkReport::getSubmitterId, userId)
                 .orderByDesc(PmWorkReport::getSubmitDate)
                 .last("LIMIT 1");
         report = baseMapper.selectList(wrapper2);
@@ -127,9 +131,11 @@ public class PmWorkReportServiceImpl extends AbstractCrudService<PmWorkReportMap
             List<PmWorkContent> contents1 = pmWorkContentMapper.selectList(wrapper);
             report.get(0).setWorkContents(contents1);
         }
+
         // 固定返回七条数据,没有内容也要设置时间给前端渲染
         LambdaQueryWrapper<PmWorkReport> queryWrapperR = Wrappers.lambdaQuery();
-        queryWrapperR.eq(PmWorkReport::getSubmitterId, SecurityUtils.getUserId())
+        queryWrapperR.eq(PmWorkReport::getTenantId, tenantId)
+    .eq(PmWorkReport::getSubmitterId, userId)
                 .between(reportId == 0, PmWorkReport::getReportDate, startDate1, endDate1)
                 .eq(reportId != 0, PmWorkReport::getId, reportId)
                 .orderByAsc(PmWorkReport::getReportDate);
@@ -174,7 +180,7 @@ public class PmWorkReportServiceImpl extends AbstractCrudService<PmWorkReportMap
         if (reports.size() == 7 || reportId != 0) {
             weekData.put("weekData", reports);
             LambdaQueryWrapper<PmWorkReport> wrapper1 = Wrappers.lambdaQuery();
-            wrapper1.eq(PmWorkReport::getSubmitterId, SecurityUtils.getUserId())
+            wrapper1.eq(PmWorkReport::getSubmitterId, userId)
                     .orderByDesc(PmWorkReport::getReportDate)
                     .last("LIMIT 1");
             report = this.list(wrapper1);
@@ -421,13 +427,14 @@ public class PmWorkReportServiceImpl extends AbstractCrudService<PmWorkReportMap
                 }
             } else {
                 rp.setId(rid);
-                rp.setCcTo(ccTo);
                 rp.setCoordinateWork(pmWorkReport.getCoordinateWork());
                 rp.setTomorrowPlan(pmWorkReport.getTomorrowPlan());
                 rp.setUpdateBy(userName);
                 rp.setUpdateTime(dateTime);
+                rp.setTotalHours(totalWorkTime);
                 rp.setIsRegularlySend(pmWorkReport.getIsRegularlySend());
-                rp.setSendDingTalk(pmWorkReport.getSendDingTalk());
+                rp.setReportFile(pmWorkReport.getReportFile());
+                rp.setReportImage(pmWorkReport.getReportImage());
                 pmWorkReportMapper.updateById(rp);
 
                 pmWorkContentService.deleteContent(rid);
@@ -498,7 +505,7 @@ public class PmWorkReportServiceImpl extends AbstractCrudService<PmWorkReportMap
         LocalDateTime endTime = stringLocalDateTimeMap.get("end");
         BigDecimal totalWorkTime = BigDecimal.ZERO;
 
-        List<PmProjectWorkTimeVo> week = pmWorkContentMapper.workTimeCount(startTime, endTime, SecurityUtils.getUserId());
+        List<PmProjectWorkTimeVo> week = pmWorkContentMapper.workTimeCount(startTime, endTime, SecurityUtils.getUserId(), SecurityUtils.getTenantId());
         if (week.isEmpty()) {
             projectTotalWorkTimeVo.setTotalWorkTime(totalWorkTime);
             projectTotalWorkTimeVo.setProjectWorkTime(week);
@@ -759,7 +766,7 @@ public class PmWorkReportServiceImpl extends AbstractCrudService<PmWorkReportMap
                 .eq(SysUser::getStatus, 0)
                 .eq(SysUser::getDelFlag, 0)
                 .notIn(!userIds.isEmpty(), SysUser::getUserId, userIds);
-        userIds =  sysUserMapper.selectList(userQueryWrapper).stream().map(SysUser::getUserId).collect(Collectors.toList());
+        userIds = sysUserMapper.selectList(userQueryWrapper).stream().map(SysUser::getUserId).collect(Collectors.toList());
 
         JSONObject jsonObject = new JSONObject();
         jsonObject.put("infoTitle", INFO_TITLE);
@@ -774,7 +781,7 @@ public class PmWorkReportServiceImpl extends AbstractCrudService<PmWorkReportMap
         try {
             remoteMceService.addMce(jsonObject.toString());
         } catch (Exception e) {
-            throw new BusinessException("报告提醒通知失败" + e);
+            log.error("报告提醒通知推送消息中心异常" + e);
         }
     }
 }

+ 71 - 3
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/VcDeviceServiceImpl.java

@@ -6,16 +6,20 @@ import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.usky.common.core.bean.CommonPage;
+import com.usky.common.core.exception.BusinessException;
 import com.usky.common.security.utils.SecurityUtils;
-import com.usky.iot.domain.BaseFacilityDevice;
-import com.usky.iot.domain.BaseGgpFacility;
 import com.usky.iot.domain.VcDevice;
 import com.usky.iot.mapper.VcDeviceMapper;
 import com.usky.iot.service.VcDeviceService;
 import com.usky.common.mybatis.core.AbstractCrudService;
-import com.usky.iot.service.vo.BaseFacilityDeviceVO;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
 import java.time.LocalDateTime;
 import java.util.List;
 
@@ -27,8 +31,15 @@ import java.util.List;
  * @author han
  * @since 2024-10-22
  */
+@Slf4j
 @Service
 public class VcDeviceServiceImpl extends AbstractCrudService<VcDeviceMapper, VcDevice> implements VcDeviceService {
+
+    @Value("${vc.rtmp-ip}")
+    private String rtmpIp;
+
+    Process process = null;
+
     @Override
     public List<VcDevice> VcDeviceList(Integer groupId){
         LambdaQueryWrapper<VcDevice> queryWrapper = Wrappers.lambdaQuery();
@@ -51,6 +62,63 @@ public class VcDeviceServiceImpl extends AbstractCrudService<VcDeviceMapper, VcD
         return new CommonPage<>(page.getRecords(),page.getTotal(),page.getCurrent(),page.getSize());
     }
 
+    @Override
+    public String getVcDeviceVideo(String deviceUuid){
+        LambdaQueryWrapper<VcDevice> lambdaQuery = Wrappers.lambdaQuery();
+        lambdaQuery.like(StringUtils.isNotBlank(deviceUuid),VcDevice::getVideoNumber,deviceUuid)
+                .eq(VcDevice::getDelFlag,0);
+        VcDevice one = this.getOne(lambdaQuery);
+        if(one==null){
+            throw new BusinessException("未查询到设备信息");
+        }
+        String accountNumber = one.getAccountNumber();
+        String videoPassword = one.getVideoPassword();
+        String videoIp = one.getVideoIp();
+        String videoPort = one.getVideoPort().toString();
+        String command = "ffmpeg -i rtsp://"+accountNumber+":"+videoPassword+"@"+videoIp+":"+videoPort+" -vcodec copy -acodec aac -ar 44100 -c:v libx264 -preset ultrafast -tune zerolatency -strict -2 -ac 1 -r 30 -s 1280x720 -q 10 -f flv -hls_time 1 -hls_list_size 3 -hls_flags delete_segments rtmp://"+rtmpIp+":1935/hls/"+deviceUuid;
+        System.out.println(command);
+
+        try {
+            log.info("【begin】实时拉取摄像头数据流 "+command);
+            // 创建 ProcessBuilder 实例
+            ProcessBuilder processBuilder = new ProcessBuilder(command.split(" "));
+            // 启动进程
+            process = processBuilder.start();
+
+            new Thread(() -> {
+                try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
+                    String line;
+                    while ((line = reader.readLine()) != null) {
+                        System.out.println(line);
+                    }
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }).start();
+
+            String repDeviceVideo = rtmpIp+":80/hls/"+deviceUuid+".m3u8";
+            return repDeviceVideo;
+
+
+        } catch (IOException e) {
+            e.printStackTrace();
+            return null;
+        }
+
+    }
+
+    @Override
+    public void stopDeviceVideo() {
+        if (process != null && process.isAlive()) {
+            process.destroy();
+            try {
+                process.waitFor();
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
     @Override
     public boolean add(VcDevice vcDevice){
         vcDevice.setCreateBy(SecurityUtils.getUsername());

+ 17 - 17
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/vo/BaseGgpFacilityExportVo.java

@@ -24,18 +24,6 @@ public class BaseGgpFacilityExportVo implements Serializable {
 
     private static final long serialVersionUID = 1L;
 
-    /**
-     * 主键ID
-     */
-    @TableId(value = "id", type = IdType.AUTO)
-    private Integer id;
-
-    /**
-     * 序号
-     */
-    @Excel(name = "序号")
-    private Integer xh;
-
     /**
      * 设施编号
      */
@@ -61,7 +49,7 @@ public class BaseGgpFacilityExportVo implements Serializable {
     private String address;
 
     /**
-     * 图片地址URL
+     * 设施图片
      */
     @Excel(name = "设施图片")
     private String imagesUrl;
@@ -73,19 +61,31 @@ public class BaseGgpFacilityExportVo implements Serializable {
     private String contact;
 
     /**
-     * 联系方式
+     * 联系电话
      */
-    @Excel(name = "联系方式")
+    @Excel(name = "联系电话")
     private String contactPhone;
 
     /**
      * 设施状态
      */
     @Excel(name = "设施状态", readConverterExp = "0=正常,1=维修,2=关闭")
-    private Integer status;
+    private Integer facilityStatus;
+
+    /**
+     * 经度
+     */
+    @Excel(name = "经度")
+    private String longitude;
+
+    /**
+     * 维度
+     */
+    @Excel(name = "维度")
+    private String latitude;
 
     /**
-     * 开始时间
+     * 创建时间
      */
     @Excel(name = "创建时间")
     private String createTime;

+ 34 - 9
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/vo/FacilityImportVo.java

@@ -1,8 +1,12 @@
 package com.usky.iot.service.vo;
 
-import cn.afterturn.easypoi.excel.annotation.Excel;
 
+import cn.afterturn.easypoi.excel.annotation.Excel;
+import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.time.LocalDateTime;
 
 /**
  * <p>
@@ -13,24 +17,38 @@ import lombok.Data;
  * @since 2023-07-27
  */
 @Data
+@EqualsAndHashCode(callSuper = false)
 public class FacilityImportVo{
+    /**
+     * 设施编号
+     */
+    @Excel(name = "设施编号")
+    private String facilityNum;
+
     /**
      * 设施类型(必填)
      */
-    @Excel(name = "设施类型(必填)")
+    @Excel(name = "设施类型")
     private String facilityType;
 
     /**
      * 设施名称(必填)
      */
-    @Excel(name = "设施名称(必填)")
+    @Excel(name = "设施名称")
     private String facilityName;
 
     /**
      * 设施地址(必填)
      */
-    @Excel(name = "设施地址(必填)")
+    @Excel(name = "设施地址")
     private String address;
+
+    /**
+     * 设施图片
+     */
+    @Excel(name = "设施图片")
+    private String imagesUrl;
+
     /**
      * 联系人
      */
@@ -44,21 +62,28 @@ public class FacilityImportVo{
     private String contactPhone;
 
     /**
-     * 备注
+     * 设施状态
      */
-    @Excel(name = "备注")
-    private String facilityDesc;
+    @Excel(name = "设施状态",replace = {"正常_0", "维修_1", "关闭_2"})
+    private Integer facilityStatus;
 
     /**
      * 经度(必填)
      */
-    @Excel(name = "经度(必填)")
+    @Excel(name = "经度")
     private String longitude;
 
     /**
      * 维度(必填)
      */
-    @Excel(name = "维度(必填)")
+    @Excel(name = "维度")
     private String latitude;
 
+    /**
+     * 创建时间
+     */
+    @Excel(name = "创建时间")
+    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime createTime;
+
 }

+ 4 - 0
service-iot/service-iot-biz/src/main/resources/mapper/iot/BaseFacilityTypeMapper.xml

@@ -32,6 +32,10 @@
         </where>
         GROUP BY d.id
     </select>
+    <select id="facilitTypeNumList" resultType="com.usky.iot.service.vo.BaseGgpFacilityTypeNumVO">
+        SELECT d.id,d.type_name as typeName,d.type_code as typeCode,d.type_img as typeImg
+        FROM base_facility_type d
+    </select>
     <select id="typeNormalNumList" resultType="com.usky.iot.service.vo.BaseGgpFacilityTypeNumVO">
         SELECT d.id,IF(facility_type IS NULL,0,COUNT(*)) AS
         normalFacilityNum

+ 1 - 0
service-iot/service-iot-biz/src/main/resources/mapper/iot/DmpDeviceTypeMapper.xml

@@ -17,6 +17,7 @@
         <result column="created_time" property="createdTime" />
         <result column="updated_by" property="updatedBy" />
         <result column="updated_time" property="updatedTime" />
+        <result column="command_field" property="commandField" />
     </resultMap>
     <select id="getProductInfo" resultType="com.usky.iot.domain.DmpProductInfo">
         select

+ 3 - 0
service-iot/service-iot-biz/src/main/resources/mapper/iot/PmTimeConfMapper.xml

@@ -14,6 +14,9 @@
         <result column="update_time" property="updateTime" />
         <result column="dept_id" property="deptId" />
         <result column="tenant_id" property="tenantId" />
+        <result column="conf_name" property="confName" />
+        <result column="conf_type" property="confType" />
+        <result column="notifier" property="notifier" />
     </resultMap>
 
 </mapper>

+ 2 - 1
service-iot/service-iot-biz/src/main/resources/mapper/iot/PmWorkContentMapper.xml

@@ -21,9 +21,10 @@
     <select id="workTimeCount" resultType="com.usky.iot.service.vo.PmProjectWorkTimeVo">
         SELECT pc.project_name, SUM(pc.work_time) as workTime
         FROM pm_work_content pc
-            JOIN pm_work_report pr ON pc.report_id = pr.id
+                 JOIN pm_work_report pr ON pc.report_id = pr.id
         WHERE pr.submitter_id = #{userId}
           AND pr.report_date BETWEEN #{startTime} AND #{endTime}
+          AND pr.tenant_id = #{tenantId}
         GROUP BY pc.project_name
     </select>