Ver Fonte

//更新初始化数据

wyj0522 há 2 semanas atrás
pai
commit
8c0d15bb5c
84 ficheiros alterados com 7086 adições e 1245 exclusões
  1. 30 7
      gm-base-ser/pom.xml
  2. 5 0
      gm-base-ser/src/main/java/com/goomood/es/controller/FileSearchController.java
  3. 8 0
      gm-base-ser/src/main/java/com/goomood/es/service/FileService.java
  4. 115 0
      gm-base-ser/src/main/java/com/goomood/phm/controller/AlsAtlasFileTController.java
  5. 3 0
      gm-base-ser/src/main/java/com/goomood/phm/controller/FaultMonitorController.java
  6. 46 0
      gm-base-ser/src/main/java/com/goomood/phm/controller/FaultStatisticsController.java
  7. 101 0
      gm-base-ser/src/main/java/com/goomood/phm/controller/KGraphClauseController.java
  8. 92 0
      gm-base-ser/src/main/java/com/goomood/phm/controller/KGraphEntityController.java
  9. 138 0
      gm-base-ser/src/main/java/com/goomood/phm/controller/KGraphTaskController.java
  10. 7 0
      gm-base-ser/src/main/java/com/goomood/phm/controller/TechDataController.java
  11. 60 0
      gm-base-ser/src/main/java/com/goomood/phm/domain/AlsAtlasFileT.java
  12. 32 0
      gm-base-ser/src/main/java/com/goomood/phm/domain/BasePO.java
  13. 3 505
      gm-base-ser/src/main/java/com/goomood/phm/domain/FaultMonitor.java
  14. 223 0
      gm-base-ser/src/main/java/com/goomood/phm/domain/FaultMonitorA.java
  15. 67 0
      gm-base-ser/src/main/java/com/goomood/phm/domain/KGraphClause.java
  16. 89 0
      gm-base-ser/src/main/java/com/goomood/phm/domain/KGraphEntity.java
  17. 80 0
      gm-base-ser/src/main/java/com/goomood/phm/domain/KGraphTask.java
  18. 16 0
      gm-base-ser/src/main/java/com/goomood/phm/domain/dto/CataiDTO.java
  19. 36 0
      gm-base-ser/src/main/java/com/goomood/phm/domain/dto/ExtraKGraphTaskDTO.java
  20. 31 0
      gm-base-ser/src/main/java/com/goomood/phm/domain/dto/ExtraKGraphTaskStatusDTO.java
  21. 20 0
      gm-base-ser/src/main/java/com/goomood/phm/domain/dto/ReturnCatAiDTO.java
  22. 25 0
      gm-base-ser/src/main/java/com/goomood/phm/enums/GraphStatus.java
  23. 13 0
      gm-base-ser/src/main/java/com/goomood/phm/mapper/AlsAtlasFileTMapper.java
  24. 26 0
      gm-base-ser/src/main/java/com/goomood/phm/mapper/FaultMonitorAMapper.java
  25. 4 0
      gm-base-ser/src/main/java/com/goomood/phm/mapper/FaultMonitorMapper.java
  26. 9 0
      gm-base-ser/src/main/java/com/goomood/phm/mapper/KGraphClauseMapper.java
  27. 13 0
      gm-base-ser/src/main/java/com/goomood/phm/mapper/KGraphEntityMapper.java
  28. 9 0
      gm-base-ser/src/main/java/com/goomood/phm/mapper/KGraphTaskMapper.java
  29. 3 1
      gm-base-ser/src/main/java/com/goomood/phm/mapper/TechDataMapper.java
  30. 21 0
      gm-base-ser/src/main/java/com/goomood/phm/service/FaultMonitorService.java
  31. 61 0
      gm-base-ser/src/main/java/com/goomood/phm/service/IAlsAtlasFileTService.java
  32. 2 0
      gm-base-ser/src/main/java/com/goomood/phm/service/IFaultMonitorService.java
  33. 47 0
      gm-base-ser/src/main/java/com/goomood/phm/service/IKGraphClauseService.java
  34. 81 0
      gm-base-ser/src/main/java/com/goomood/phm/service/IKGraphEntityService.java
  35. 67 0
      gm-base-ser/src/main/java/com/goomood/phm/service/IKGraphTaskService.java
  36. 9 0
      gm-base-ser/src/main/java/com/goomood/phm/service/ITechDataService.java
  37. 141 0
      gm-base-ser/src/main/java/com/goomood/phm/service/impl/AlsAtlasFileTServiceImpl.java
  38. 102 0
      gm-base-ser/src/main/java/com/goomood/phm/service/impl/FaultMonitorServiceAImpl.java
  39. 31 39
      gm-base-ser/src/main/java/com/goomood/phm/service/impl/FaultMonitorServiceImpl.java
  40. 102 0
      gm-base-ser/src/main/java/com/goomood/phm/service/impl/KGraphClauseServiceImpl.java
  41. 116 0
      gm-base-ser/src/main/java/com/goomood/phm/service/impl/KGraphEntityServiceImpl.java
  42. 280 0
      gm-base-ser/src/main/java/com/goomood/phm/service/impl/KGraphTaskServiceImpl.java
  43. 42 0
      gm-base-ser/src/main/java/com/goomood/phm/service/impl/TechDataServiceImpl.java
  44. 280 0
      gm-base-ser/src/main/java/com/goomood/phm/utils/HttpUtils.java
  45. 62 0
      gm-base-ser/src/main/java/com/goomood/tableConfig/controller/UserTableConfigController.java
  46. 55 0
      gm-base-ser/src/main/java/com/goomood/tableConfig/domain/UserTableConfig.java
  47. 44 0
      gm-base-ser/src/main/java/com/goomood/tableConfig/domain/dto/UserTableConfigDto.java
  48. 46 0
      gm-base-ser/src/main/java/com/goomood/tableConfig/domain/vo/UserTableConfigVo.java
  49. 17 0
      gm-base-ser/src/main/java/com/goomood/tableConfig/mapper/UserTableConfigMapper.java
  50. 33 0
      gm-base-ser/src/main/java/com/goomood/tableConfig/service/IUserTableConfigService.java
  51. 55 0
      gm-base-ser/src/main/java/com/goomood/tableConfig/service/impl/UserTableConfigServiceImpl.java
  52. 1 1
      gm-base-ser/src/main/java/com/goomood/web/controller/common/CommonController.java
  53. 22 12
      gm-base-ser/src/main/resources/application-druid.yml
  54. 16 11
      gm-base-ser/src/main/resources/application.yml
  55. 37 0
      gm-base-ser/src/main/resources/mapper/KGraph/KGraphEntityMapper.xml
  56. 12 0
      gm-base-ser/src/main/resources/mapper/fault/FaultMonitorAMapper.xml
  57. 56 0
      gm-base-ser/src/main/resources/mapper/fault/FaultMonitorMapper.xml
  58. 12 0
      gm-base-ser/src/main/resources/mapper/file/AlsAtlasFileTMapper.xml
  59. 4 3
      gm-common/pom.xml
  60. 2 1
      gm-common/src/main/java/com/goomood/common/utils/http/HttpUtils.java
  61. 0 132
      gm-framework/src/main/java/com/goomood/framework/config/MyBatisConfig.java
  62. 1 1
      gm-framework/src/main/java/com/goomood/framework/config/SecurityConfig.java
  63. 4 0
      gm-system/pom.xml
  64. 1 1
      gm-web/.env.development
  65. 66 0
      gm-web/src/api/als/ERManage.js
  66. 45 0
      gm-web/src/api/als/atlasFile.js
  67. 79 0
      gm-web/src/api/als/entityManage.js
  68. 201 0
      gm-web/src/api/als/knowledgeExtraction.js
  69. 1 0
      gm-web/src/api/chart/index.js
  70. 7 1
      gm-web/src/api/tech/techData.js
  71. BIN
      gm-web/src/assets/logo.png
  72. 30 0
      gm-web/src/utils/enum-data.js
  73. 505 0
      gm-web/src/views/ChatComponent.vue
  74. 324 0
      gm-web/src/views/chat/catAi.vue
  75. 114 0
      gm-web/src/views/components/Charts/graph.vue
  76. 24 0
      gm-web/src/views/components/LTable/index.scss
  77. 706 0
      gm-web/src/views/components/LTable/index.vue
  78. 305 0
      gm-web/src/views/file/index.vue
  79. 79 516
      gm-web/src/views/index.vue
  80. 279 0
      gm-web/src/views/knowledgeExtraction/extractList.vue
  81. 1135 0
      gm-web/src/views/knowledgeExtraction/index.vue
  82. 6 5
      gm-web/src/views/tech/techData/index.vue
  83. 1 1
      gm-web/vue.config.js
  84. 13 8
      pom.xml

+ 30 - 7
gm-base-ser/pom.xml

@@ -17,13 +17,16 @@
 
     <dependencies>
 
-        <!-- spring-boot-devtools -->
+<!--        &lt;!&ndash; spring-boot-devtools &ndash;&gt;-->
+<!--        <dependency>-->
+<!--            <groupId>org.springframework.boot</groupId>-->
+<!--            <artifactId>spring-boot-devtools</artifactId>-->
+<!--            <optional>true</optional> &lt;!&ndash; 表示依赖不会传递 &ndash;&gt;-->
+<!--        </dependency>-->
         <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-devtools</artifactId>
-            <optional>true</optional> <!-- 表示依赖不会传递 -->
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
         </dependency>
-
         <!-- swagger3-->
         <dependency>
             <groupId>io.springfox</groupId>
@@ -48,6 +51,11 @@
             <groupId>com.goomood</groupId>
             <artifactId>gm-framework</artifactId>
         </dependency>
+        <!-- WebClient -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-webflux</artifactId>
+        </dependency>
 
         <!-- 定时任务-->
         <dependency>
@@ -88,6 +96,21 @@
             <artifactId>tika-parsers</artifactId>
             <version>1.28.5</version>
         </dependency>
+        <dependency>
+            <groupId>com.goomood</groupId>
+            <artifactId>gm-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-core</artifactId>
+            <version>3.5.12</version>
+            <scope>compile</scope>
+        </dependency>
 
 
     </dependencies>
@@ -133,8 +156,8 @@
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
                 <configuration>
-                    <source>8</source>
-                    <target>8</target>
+                    <source>9</source>
+                    <target>9</target>
                 </configuration>
             </plugin>
         </plugins>

+ 5 - 0
gm-base-ser/src/main/java/com/goomood/es/controller/FileSearchController.java

@@ -4,6 +4,7 @@ import com.goomood.common.core.domain.AjaxResult;
 import com.goomood.es.dto.DelFIleIndexDto;
 import com.goomood.es.service.FileService;
 import com.goomood.es.service.SearchService;
+import com.goomood.phm.domain.dto.CataiDTO;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
@@ -49,4 +50,8 @@ public class FileSearchController {
         }
         return AjaxResult.success();
     }
+
+
+
+
 }

+ 8 - 0
gm-base-ser/src/main/java/com/goomood/es/service/FileService.java

@@ -4,6 +4,9 @@ import com.goomood.common.config.GooMoodConfig;
 import com.goomood.common.constant.Constants;
 import com.goomood.common.utils.StringUtils;
 import com.goomood.es.dto.DelFIleIndexDto;
+import com.goomood.phm.domain.dto.CataiDTO;
+import com.goomood.phm.utils.HttpUtils;
+import org.apache.commons.lang3.ObjectUtils;
 import org.elasticsearch.ElasticsearchStatusException;
 import org.elasticsearch.action.delete.DeleteRequest;
 import org.elasticsearch.action.index.IndexRequest;
@@ -14,6 +17,7 @@ import org.elasticsearch.client.RequestOptions;
 import org.elasticsearch.client.Response;
 import org.elasticsearch.client.RestHighLevelClient;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 
@@ -43,6 +47,8 @@ public class FileService {
 
 
 
+
+
     /**
      * 读取文件并存储到 Elasticsearch
      *
@@ -262,4 +268,6 @@ public class FileService {
         }
         return null;
     }
+
+
 }

+ 115 - 0
gm-base-ser/src/main/java/com/goomood/phm/controller/AlsAtlasFileTController.java

@@ -0,0 +1,115 @@
+package com.goomood.phm.controller;
+
+import com.goomood.common.annotation.Log;
+import com.goomood.common.core.controller.BaseController;
+import com.goomood.common.core.domain.AjaxResult;
+import com.goomood.common.core.page.TableDataInfo;
+import com.goomood.common.enums.BusinessType;
+import com.goomood.common.utils.poi.ExcelUtil;
+import com.goomood.phm.domain.AlsAtlasFileT;
+import com.goomood.phm.service.IAlsAtlasFileTService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 文件管理Controller
+ */
+@RestController
+@RequestMapping("/als/file")
+public class AlsAtlasFileTController extends BaseController {
+    @Resource
+    private IAlsAtlasFileTService alsAtlasFileTService;
+
+    /**
+     * 查询文件管理列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:file:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(AlsAtlasFileT alsAtlasFileT) {
+        startPage();
+        List<AlsAtlasFileT> list = alsAtlasFileTService.selectAlsAtlasFileTList(alsAtlasFileT);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出文件管理列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:file:export')")
+    @Log(title = "文件管理", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    @ResponseBody
+    public AjaxResult export(AlsAtlasFileT alsAtlasFileT) {
+        List<AlsAtlasFileT> list = alsAtlasFileTService.selectAlsAtlasFileTList(alsAtlasFileT);
+        ExcelUtil<AlsAtlasFileT> util = new ExcelUtil<>(AlsAtlasFileT.class);
+        return util.exportExcel(list, "文件管理数据");
+    }
+
+    /**
+     * 获取文件管理详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('system:file:query')")
+    @PostMapping(value = "/selectOne")
+    public AjaxResult getInfo(@RequestBody AlsAtlasFileT alsAtlasFileT) {
+        return success(alsAtlasFileTService.getById(alsAtlasFileT.getId()));
+    }
+
+    /**
+     * 新增文件管理
+     */
+    @PreAuthorize("@ss.hasPermi('system:file:add')")
+    @Log(title = "文件管理", businessType = BusinessType.INSERT)
+    @PostMapping("add")
+    public AjaxResult add(@RequestBody AlsAtlasFileT alsAtlasFileT) {
+        return toAjax(alsAtlasFileTService.insertAlsAtlasFileT(alsAtlasFileT));
+    }
+
+    /**
+     * 修改文件管理
+     */
+    @PreAuthorize("@ss.hasPermi('system:file:edit')")
+    @Log(title = "文件管理", businessType = BusinessType.UPDATE)
+    @PutMapping("updata")
+    public AjaxResult edit(@RequestBody AlsAtlasFileT alsAtlasFileT) {
+        return toAjax(alsAtlasFileTService.updateAlsAtlasFileT(alsAtlasFileT));
+    }
+
+    /**
+     * 删除文件管理
+     */
+    @PreAuthorize("@ss.hasPermi('system:file:remove')")
+    @Log(title = "文件管理", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable String[] ids) {
+        return toAjax(alsAtlasFileTService.deleteAlsAtlasFileTByIds(ids));
+    }
+
+//    /**
+//     * 导入文件
+//     */
+//    @PreAuthorize("@ss.hasPermi('system:file:import')")
+//    @Log(title = "文件管理", businessType = BusinessType.IMPORT)
+//    @PostMapping("/importData")
+//    @ResponseBody
+//    public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception {
+//        ExcelUtil<AlsAtlasFileT> util = new ExcelUtil<>(AlsAtlasFileT.class);
+//        List<AlsAtlasFileT> fileList = util.importExcel(file.getInputStream());
+//        String operName = getUsername();
+//        String message = alsAtlasFileTService.importFile(fileList, updateSupport, operName);
+//        return AjaxResult.success(message);
+//    }
+
+    /**
+     * 下载导入模板
+     */
+    @GetMapping("/importTemplate")
+    public void importTemplate(HttpServletResponse response) {
+        ExcelUtil<AlsAtlasFileT> util = new ExcelUtil<>(AlsAtlasFileT.class);
+        util.importTemplateExcel(response, "文件管理数据");
+    }
+}

+ 3 - 0
gm-base-ser/src/main/java/com/goomood/phm/controller/FaultMonitorController.java

@@ -1,6 +1,7 @@
 package com.goomood.phm.controller;
 
 import java.util.List;
+import java.util.Map;
 import javax.servlet.http.HttpServletResponse;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -128,4 +129,6 @@ public class FaultMonitorController extends BaseController
         String message = faultMonitorService.importFaultMonitor(faultMonitors);
         return AjaxResult.success(message);
     }
+
+
 }

+ 46 - 0
gm-base-ser/src/main/java/com/goomood/phm/controller/FaultStatisticsController.java

@@ -0,0 +1,46 @@
+package com.goomood.phm.controller;
+
+import com.goomood.common.core.controller.BaseController;
+import com.goomood.common.core.domain.AjaxResult;
+import com.goomood.phm.service.FaultMonitorService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+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.RestController;
+
+import javax.annotation.Resource;
+import java.util.Map;
+
+/**
+ * 故障统计控制器
+ */
+@Api(tags = "故障统计API")
+@RestController
+@RequestMapping("/phm/statistics")
+public class FaultStatisticsController extends BaseController {
+
+    @Resource
+    private FaultMonitorService faultMonitorService;
+
+    /**
+     * 获取近三年下月故障最多的5类部件
+     */
+    @ApiOperation("获取近三年下月故障最多的5类部件")
+    @GetMapping("/top5NextMonth")
+    public AjaxResult getTop5FaultyPartsNextMonthInThreeYears() {
+        Map<String, Long> result = faultMonitorService.getTop5FaultyPartsNextMonthInThreeYears();
+        return success(result);
+    }
+
+    /**
+     * 获取近半年故障最多的5类部件
+     */
+    @ApiOperation("获取近半年故障最多的5类部件")
+    @GetMapping("/top5SixMonths")
+    public AjaxResult getTop5FaultyPartsInSixMonths() {
+        Map<String, Long> result = faultMonitorService.getTop5FaultyPartsInSixMonths();
+        return success(result);
+    }
+}    

+ 101 - 0
gm-base-ser/src/main/java/com/goomood/phm/controller/KGraphClauseController.java

@@ -0,0 +1,101 @@
+package com.goomood.phm.controller;
+
+import com.goomood.common.annotation.Log;
+import com.goomood.common.annotation.RepeatSubmit;
+import com.goomood.common.core.controller.BaseController;
+import com.goomood.common.core.domain.AjaxResult;
+import com.goomood.common.core.page.TableDataInfo;
+import com.goomood.common.enums.BusinessType;
+import com.goomood.phm.domain.KGraphClause;
+import com.goomood.phm.service.IKGraphClauseService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * 知识图谱分句结果Controller
+ *
+ * @author wgk
+ * @date 2025-01-03
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/als/kGraphClause")
+public class KGraphClauseController extends BaseController {
+
+    @Resource
+    private IKGraphClauseService kGraphClauseService;
+
+    /**
+     * 查询知识图谱分句结果列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(KGraphClause po) {
+        startPage();
+        List<KGraphClause> list = kGraphClauseService.selectList(po);
+        return getDataTable(list);
+    }
+    /**
+     * 获取知识图谱分句结果详细信息
+     */
+    @GetMapping(value = "/selectOne/{id}")
+    public AjaxResult getInfo(@PathVariable Long id) {
+        return success(kGraphClauseService.selectById(id));
+    }
+
+    /**
+     * 新增知识图谱分句结果
+     */
+    @RepeatSubmit
+    @PostMapping("/add")
+    public AjaxResult add(@Validated @RequestBody KGraphClause po) {
+        boolean inserted = kGraphClauseService.insert(po);
+        if (!inserted) {
+            return AjaxResult.error("新增知识图谱分句结果记录失败!");
+        }
+        return success();
+    }
+    /**
+     * 新增知识图谱分句结果
+     */
+    @RepeatSubmit()
+    @PostMapping("/saveBatch")
+    public AjaxResult saveBatch(@Valid @RequestBody List<KGraphClause> kGraphClauseList) {
+        boolean inserted = kGraphClauseService.saveBatch(kGraphClauseList);
+        if (!inserted) {
+            return AjaxResult.error("新增知识图谱分句结果记录失败!");
+        }
+        return success();
+    }
+    /**
+     * 修改知识图谱分句结果
+     */
+    @Log(title = "知识图谱分句结果", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping("/update")
+    public AjaxResult edit(@Validated @RequestBody KGraphClause po) {
+        boolean updated = kGraphClauseService.update(po);
+        if (!updated) {
+            return AjaxResult.error("修改知识图谱分句结果记录失败!");
+        }
+        return success();
+    }
+
+    /**
+     * 删除知识图谱分句结果
+     */
+    @Log(title = "知识图谱分句结果", businessType = BusinessType.DELETE)
+    @DeleteMapping("/delete/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids) {
+        boolean deleted = kGraphClauseService.deleteByIds(ids);
+        if (!deleted) {
+            return AjaxResult.error("删除知识图谱分句结果记录失败!");
+        }
+        return success();
+    }
+}

+ 92 - 0
gm-base-ser/src/main/java/com/goomood/phm/controller/KGraphEntityController.java

@@ -0,0 +1,92 @@
+package com.goomood.phm.controller;
+
+import com.goomood.common.annotation.Log;
+import com.goomood.common.annotation.RepeatSubmit;
+import com.goomood.common.core.controller.BaseController;
+import com.goomood.common.core.domain.AjaxResult;
+import com.goomood.common.enums.BusinessType;
+import com.goomood.phm.domain.KGraphEntity;
+import com.goomood.phm.service.IKGraphEntityService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.List;
+
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/als/kGraphEntity")
+public class KGraphEntityController extends BaseController {
+
+    @Resource
+    private IKGraphEntityService kGraphEntityService;
+
+    /**
+     * 查询知识图谱实体关系列表
+     */
+
+    @GetMapping("/list")
+    public AjaxResult list(KGraphEntity po) {
+        return success(kGraphEntityService.selectPage(po));
+    }
+
+    /**
+     * 获取知识图谱实体关系详细信息
+     */
+
+    @GetMapping(value = "/selectOne/{id}")
+    public AjaxResult getInfo(@PathVariable Long id) {
+        return success(kGraphEntityService.selectById(id));
+    }
+    /**
+     * 获取知识图谱实体关系详细信息
+     */
+    @GetMapping(value = "/selectListByTaskId/{id}")
+    public AjaxResult selectListByTaskId(@PathVariable Long id) {
+        return success(kGraphEntityService.selectListByTaskId(id));
+    }
+
+    /**
+     * 新增知识图谱实体关系
+     */
+
+    @Log(title = "知识图谱实体关系", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping("/add")
+    public AjaxResult add(@Validated @RequestBody KGraphEntity po) {
+        kGraphEntityService.insert(po);
+        return success("ok");
+    }
+
+    /**
+     * 新增知识图谱实体关系
+     */
+    @RepeatSubmit()
+    @PostMapping("/saveBatch")
+    public AjaxResult saveBatch(@Valid @RequestBody List<KGraphEntity> kGraphEntityBoList) {
+        return success(kGraphEntityService.saveBatch(kGraphEntityBoList));
+    }
+
+    /**
+     * 修改知识图谱实体关系
+     */
+
+    @Log(title = "知识图谱实体关系", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping("/update")
+    public AjaxResult edit(@Validated @RequestBody KGraphEntity po) {
+        return success(kGraphEntityService.update(po));
+    }
+
+    /**
+     * 删除知识图谱实体关系
+     */
+    @Log(title = "知识图谱实体关系", businessType = BusinessType.DELETE)
+    @DeleteMapping("/delete/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids) {
+        return success(kGraphEntityService.deleteByIds(ids));
+    }
+}

+ 138 - 0
gm-base-ser/src/main/java/com/goomood/phm/controller/KGraphTaskController.java

@@ -0,0 +1,138 @@
+package com.goomood.phm.controller;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.goomood.common.annotation.Log;
+import com.goomood.common.annotation.RepeatSubmit;
+import com.goomood.common.core.controller.BaseController;
+import com.goomood.common.core.domain.AjaxResult;
+import com.goomood.common.core.page.TableDataInfo;
+import com.goomood.common.enums.BusinessType;
+import com.goomood.common.utils.StringUtils;
+import com.goomood.phm.domain.KGraphTask;
+import com.goomood.phm.domain.dto.CataiDTO;
+import com.goomood.phm.domain.dto.ExtraKGraphTaskDTO;
+import com.goomood.phm.domain.dto.ExtraKGraphTaskStatusDTO;
+import com.goomood.phm.service.IKGraphTaskService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.util.ObjectUtils;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.List;
+
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/als/kGraphTask")
+public class KGraphTaskController extends BaseController {
+    @Resource
+    private IKGraphTaskService kGraphTaskService;
+
+
+    /**
+     * 查询知识图谱任务列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(KGraphTask po) {
+        startPage();
+        List<KGraphTask> kGraphTasks = kGraphTaskService.selectPage(po);
+        return getDataTable(kGraphTasks);
+    }
+    /**
+     * 获取知识图谱任务详细信息
+     */
+    @GetMapping(value = "/selectOne/{id}")
+    public AjaxResult getInfo(@PathVariable Long id) {
+        KGraphTask one = kGraphTaskService.selectById(id);
+        return success(one);
+    }
+    /**
+     * 新增知识图谱任务
+     */
+    @Log(title = "知识图谱任务", businessType = BusinessType.INSERT)
+    @RepeatSubmit
+    @PostMapping("/add")
+    public AjaxResult add(@Validated @RequestBody KGraphTask po) {
+        boolean inserted = kGraphTaskService.insert(po);
+        if (!inserted) {
+            return AjaxResult.error("新增知识图谱任务记录失败");
+        }
+        return AjaxResult.success("新增知识图谱任务记录成功");
+    }
+    /**
+     * 运行知识图谱任务
+     */
+    @PostMapping("/pro")
+    public AjaxResult proTask(@RequestBody KGraphTask po) {
+        if (StringUtils.isBlank(po.getTaskType())) {
+            return AjaxResult.error("任务类型不能为空");
+        }
+        if (ObjectUtils.isEmpty(po.getId())) {
+            return AjaxResult.error("任务Id不能为空");
+        }
+        boolean pro = kGraphTaskService.proTask(po);
+        if (!pro) {
+            return AjaxResult.error("执行任务失败!");
+        }
+        return success();
+    }
+
+    /**
+     * 修改知识图谱任务
+     */
+    @Log(title = "知识图谱任务", businessType = BusinessType.UPDATE)
+    @RepeatSubmit
+    @PutMapping("/update")
+    public AjaxResult edit(@Validated @RequestBody KGraphTask po) {
+        boolean updated = kGraphTaskService.update(po);
+        if (!updated) {
+            return AjaxResult.error("修改知识图谱任务记录失败!");
+        }
+        return success();
+    }
+
+    /**
+     * 删除知识图谱任务
+     */
+    @Log(title = "知识图谱任务", businessType = BusinessType.DELETE)
+    @DeleteMapping("/delete/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids) {
+        boolean deleted = kGraphTaskService.deleteByIds(ids);
+        if (!deleted) {
+            return AjaxResult.error("删除知识图谱任务记录失败!");
+        }
+        return success();
+    }
+
+    /**
+     * 结果回调
+     */
+    @PostMapping("/result/callback")
+    public AjaxResult resultCallback(@Valid @RequestBody ExtraKGraphTaskDTO dto) {
+        boolean isCallback = kGraphTaskService.resultCallback(dto);
+        if (!isCallback) {
+            return AjaxResult.error("回调新增结果失败!");
+        }
+        return success();
+    }
+    /**
+     * 状态回调
+     */
+    @PostMapping("/status/callback")
+    public AjaxResult statusCallback(@Valid @RequestBody ExtraKGraphTaskStatusDTO extraKGraphTaskStatusdto) {
+        boolean isCallback = kGraphTaskService.statusCallback(extraKGraphTaskStatusdto);
+        if (!isCallback) {
+            return AjaxResult.error("更新状态失败!");
+        }
+        return success();
+    }
+
+
+    @PostMapping("/catai")
+    public AjaxResult catai(@RequestBody CataiDTO dto){
+        return AjaxResult.success(kGraphTaskService.catai(dto));
+    }
+
+}

+ 7 - 0
gm-base-ser/src/main/java/com/goomood/phm/controller/TechDataController.java

@@ -101,4 +101,11 @@ public class TechDataController extends BaseController
     {
         return toAjax(techDataService.deleteTechDataByIds(ids));
     }
+
+    @Log(title = "下载文件", businessType = BusinessType.OTHER)
+    @PostMapping("/download/{oosId}")
+    public AjaxResult downloadFile(@PathVariable("oosId") Long oosId,HttpServletResponse response)
+    {
+        return toAjax(techDataService.downloadFile(oosId,response));
+    }
 }

+ 60 - 0
gm-base-ser/src/main/java/com/goomood/phm/domain/AlsAtlasFileT.java

@@ -0,0 +1,60 @@
+package com.goomood.phm.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+import com.goomood.common.annotation.Excel;
+import com.goomood.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 文件管理实体类
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("als_atlas_file_t")
+public class AlsAtlasFileT extends BasePO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /** 唯一ID */
+    @TableId
+    @Excel(name = "唯一ID")
+    private String id;
+
+    /** 文件名称 */
+    @Excel(name = "文件名称")
+    @TableField(value = "file_name")
+    private String fileName;
+
+    /** 文件类型 */
+    @Excel(name = "文件类型")
+    @TableField(value = "file_type")
+    private String fileType;
+
+    /** 文件 */
+    @Excel(name = "文件")
+    @TableField(value = "url")
+    private String url;
+
+    /** 状态 */
+    @Excel(name = "状态")
+    @TableField(value = "status")
+    private String status;
+
+
+    /** 删除标识(1删除 0未删除) */
+    @Excel(name = "删除标识", readConverterExp = "1=删除,0=未删除")
+    @TableField(value = "del_flag")
+    private Boolean delFlag;
+
+    /** 乐观锁 */
+    @Excel(name = "乐观锁")
+    @TableField(value = "version")
+    private Integer version;
+
+}

+ 32 - 0
gm-base-ser/src/main/java/com/goomood/phm/domain/BasePO.java

@@ -0,0 +1,32 @@
+package com.goomood.phm.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.goomood.common.annotation.Excel;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class BasePO implements Serializable {
+    /**
+     * 乐观锁
+     */
+
+    private Integer version;
+    /** 创建者 */
+    private String createBy;
+
+    /** 创建时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    /** 更新者 */
+    private String updateBy;
+
+    /** 更新时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "结束时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date updateTime;
+
+}

+ 3 - 505
gm-base-ser/src/main/java/com/goomood/phm/domain/FaultMonitor.java

@@ -4,6 +4,8 @@ import java.sql.Time;
 import java.util.Date;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.goomood.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.Getter;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
 import com.goomood.common.annotation.Excel;
@@ -14,6 +16,7 @@ import com.goomood.common.annotation.Excel;
  * @author goomood
  * @date 2024-11-17
  */
+@Data
 public class FaultMonitor extends BaseEntity
 {
     private static final long serialVersionUID = 1L;
@@ -280,509 +283,4 @@ public class FaultMonitor extends BaseEntity
     /** 监控状态 */
     @Excel(name = "监控状态")
     private String status;
-
-
-    public Long getId() {
-        return id;
-    }
-
-    public void setId(Long id) {
-        this.id = id;
-    }
-
-    public Date getIncidentDate() {
-        return incidentDate;
-    }
-
-    public void setIncidentDate(Date incidentDate) {
-        this.incidentDate = incidentDate;
-    }
-
-    public String getMilitaryRegion() {
-        return militaryRegion;
-    }
-
-    public void setMilitaryRegion(String militaryRegion) {
-        this.militaryRegion = militaryRegion;
-    }
-
-    public String getArmy() {
-        return army;
-    }
-
-    public void setArmy(String army) {
-        this.army = army;
-    }
-
-    public String getDivision() {
-        return division;
-    }
-
-    public void setDivision(String division) {
-        this.division = division;
-    }
-
-    public String getRegiment() {
-        return regiment;
-    }
-
-    public void setRegiment(String regiment) {
-        this.regiment = regiment;
-    }
-
-    public String getSquadron() {
-        return squadron;
-    }
-
-    public void setSquadron(String squadron) {
-        this.squadron = squadron;
-    }
-
-    public String getAircraftNo() {
-        return aircraftNo;
-    }
-
-    public void setAircraftNo(String aircraftNo) {
-        this.aircraftNo = aircraftNo;
-    }
-
-    public String getAircraftType() {
-        return aircraftType;
-    }
-
-    public void setAircraftType(String aircraftType) {
-        this.aircraftType = aircraftType;
-    }
-
-    public String getFactoryNo() {
-        return factoryNo;
-    }
-
-    public void setFactoryNo(String factoryNo) {
-        this.factoryNo = factoryNo;
-    }
-
-    public String getPartCategory() {
-        return partCategory;
-    }
-
-    public void setPartCategory(String partCategory) {
-        this.partCategory = partCategory;
-    }
-
-    public String getPartNo() {
-        return partNo;
-    }
-
-    public void setPartNo(String partNo) {
-        this.partNo = partNo;
-    }
-
-    public String getPartModel() {
-        return partModel;
-    }
-
-    public void setPartModel(String partModel) {
-        this.partModel = partModel;
-    }
-
-    public String getPartName() {
-        return partName;
-    }
-
-    public void setPartName(String partName) {
-        this.partName = partName;
-    }
-
-    public Long getLandingCount() {
-        return landingCount;
-    }
-
-    public void setLandingCount(Long landingCount) {
-        this.landingCount = landingCount;
-    }
-
-    public String getSpecialty() {
-        return specialty;
-    }
-
-    public void setSpecialty(String specialty) {
-        this.specialty = specialty;
-    }
-
-    public String getFaultyPartName() {
-        return faultyPartName;
-    }
-
-    public void setFaultyPartName(String faultyPartName) {
-        this.faultyPartName = faultyPartName;
-    }
-
-    public String getFaultyPartModel() {
-        return faultyPartModel;
-    }
-
-    public void setFaultyPartModel(String faultyPartModel) {
-        this.faultyPartModel = faultyPartModel;
-    }
-
-    public String getFaultyPartNo() {
-        return faultyPartNo;
-    }
-
-    public void setFaultyPartNo(String faultyPartNo) {
-        this.faultyPartNo = faultyPartNo;
-    }
-
-    public String getEngineType() {
-        return engineType;
-    }
-
-    public void setEngineType(String engineType) {
-        this.engineType = engineType;
-    }
-
-    public String getEngineNo() {
-        return engineNo;
-    }
-
-    public void setEngineNo(String engineNo) {
-        this.engineNo = engineNo;
-    }
-
-    public String getEngineSerialNo() {
-        return engineSerialNo;
-    }
-
-    public void setEngineSerialNo(String engineSerialNo) {
-        this.engineSerialNo = engineSerialNo;
-    }
-
-    public String getFaultLocation() {
-        return faultLocation;
-    }
-
-    public void setFaultLocation(String faultLocation) {
-        this.faultLocation = faultLocation;
-    }
-
-    public String getFaultDescription() {
-        return faultDescription;
-    }
-
-    public void setFaultDescription(String faultDescription) {
-        this.faultDescription = faultDescription;
-    }
-
-    public String getFaultLocationSite() {
-        return faultLocationSite;
-    }
-
-    public void setFaultLocationSite(String faultLocationSite) {
-        this.faultLocationSite = faultLocationSite;
-    }
-
-    public String getDetectionTiming() {
-        return detectionTiming;
-    }
-
-    public void setDetectionTiming(String detectionTiming) {
-        this.detectionTiming = detectionTiming;
-    }
-
-    public String getUseSystem() {
-        return useSystem;
-    }
-
-    public void setUseSystem(String useSystem) {
-        this.useSystem = useSystem;
-    }
-
-    public String getTimingType() {
-        return timingType;
-    }
-
-    public void setTimingType(String timingType) {
-        this.timingType = timingType;
-    }
-
-    public String getManufacturer() {
-        return manufacturer;
-    }
-
-    public void setManufacturer(String manufacturer) {
-        this.manufacturer = manufacturer;
-    }
-
-    public String getRepairFacility() {
-        return repairFacility;
-    }
-
-    public void setRepairFacility(String repairFacility) {
-        this.repairFacility = repairFacility;
-    }
-
-    public Time getWorkHoursCurrent() {
-        return workHoursCurrent;
-    }
-
-    public void setWorkHoursCurrent(Time workHoursCurrent) {
-        this.workHoursCurrent = workHoursCurrent;
-    }
-
-    public Time getWorkHoursTotal() {
-        return workHoursTotal;
-    }
-
-    public void setWorkHoursTotal(Time workHoursTotal) {
-        this.workHoursTotal = workHoursTotal;
-    }
-
-    public Time getWorkHoursAfterRepair() {
-        return workHoursAfterRepair;
-    }
-
-    public void setWorkHoursAfterRepair(Time workHoursAfterRepair) {
-        this.workHoursAfterRepair = workHoursAfterRepair;
-    }
-
-    public String getReplacementPartModel() {
-        return replacementPartModel;
-    }
-
-    public void setReplacementPartModel(String replacementPartModel) {
-        this.replacementPartModel = replacementPartModel;
-    }
-
-    public String getReplacementPartNo() {
-        return replacementPartNo;
-    }
-
-    public void setReplacementPartNo(String replacementPartNo) {
-        this.replacementPartNo = replacementPartNo;
-    }
-
-    public String getReplacementManufacturer() {
-        return replacementManufacturer;
-    }
-
-    public void setReplacementManufacturer(String replacementManufacturer) {
-        this.replacementManufacturer = replacementManufacturer;
-    }
-
-    public Time getReplacementWorkHoursTotal() {
-        return replacementWorkHoursTotal;
-    }
-
-    public void setReplacementWorkHoursTotal(Time replacementWorkHoursTotal) {
-        this.replacementWorkHoursTotal = replacementWorkHoursTotal;
-    }
-
-    public String getReplacementRepairFacility() {
-        return replacementRepairFacility;
-    }
-
-    public void setReplacementRepairFacility(String replacementRepairFacility) {
-        this.replacementRepairFacility = replacementRepairFacility;
-    }
-
-    public Time getReplacementHoursAfterRepair() {
-        return replacementHoursAfterRepair;
-    }
-
-    public void setReplacementHoursAfterRepair(Time replacementHoursAfterRepair) {
-        this.replacementHoursAfterRepair = replacementHoursAfterRepair;
-    }
-
-    public String getFaultCode() {
-        return faultCode;
-    }
-
-    public void setFaultCode(String faultCode) {
-        this.faultCode = faultCode;
-    }
-
-    public Date getInstallationDate() {
-        return installationDate;
-    }
-
-    public void setInstallationDate(Date installationDate) {
-        this.installationDate = installationDate;
-    }
-
-    public String getFaultCause() {
-        return faultCause;
-    }
-
-    public void setFaultCause(String faultCause) {
-        this.faultCause = faultCause;
-    }
-
-    public String getFaultNature() {
-        return faultNature;
-    }
-
-    public void setFaultNature(String faultNature) {
-        this.faultNature = faultNature;
-    }
-
-    public String getFaultResponsibility() {
-        return faultResponsibility;
-    }
-
-    public void setFaultResponsibility(String faultResponsibility) {
-        this.faultResponsibility = faultResponsibility;
-    }
-
-    public String getFaultConsequence() {
-        return faultConsequence;
-    }
-
-    public void setFaultConsequence(String faultConsequence) {
-        this.faultConsequence = faultConsequence;
-    }
-
-    public String getHandlingSuggestion() {
-        return handlingSuggestion;
-    }
-
-    public void setHandlingSuggestion(String handlingSuggestion) {
-        this.handlingSuggestion = handlingSuggestion;
-    }
-
-    public Long getImpactCount() {
-        return impactCount;
-    }
-
-    public void setImpactCount(Long impactCount) {
-        this.impactCount = impactCount;
-    }
-
-    public Long getMissedFlightCount() {
-        return missedFlightCount;
-    }
-
-    public void setMissedFlightCount(Long missedFlightCount) {
-        this.missedFlightCount = missedFlightCount;
-    }
-
-    public String getDetectionMethod() {
-        return detectionMethod;
-    }
-
-    public void setDetectionMethod(String detectionMethod) {
-        this.detectionMethod = detectionMethod;
-    }
-
-    public String getDiscoverer() {
-        return discoverer;
-    }
-
-    public void setDiscoverer(String discoverer) {
-        this.discoverer = discoverer;
-    }
-
-    public String getResolutionMethod() {
-        return resolutionMethod;
-    }
-
-    public void setResolutionMethod(String resolutionMethod) {
-        this.resolutionMethod = resolutionMethod;
-    }
-
-    public String getMaintainer() {
-        return maintainer;
-    }
-
-    public void setMaintainer(String maintainer) {
-        this.maintainer = maintainer;
-    }
-
-    public String getReviewer() {
-        return reviewer;
-    }
-
-    public void setReviewer(String reviewer) {
-        this.reviewer = reviewer;
-    }
-
-    public Date getReviewTime() {
-        return reviewTime;
-    }
-
-    public void setReviewTime(Date reviewTime) {
-        this.reviewTime = reviewTime;
-    }
-
-    public Date getResolutionDate() {
-        return resolutionDate;
-    }
-
-    public void setResolutionDate(Date resolutionDate) {
-        this.resolutionDate = resolutionDate;
-    }
-
-    public Time getMaintenanceHours() {
-        return maintenanceHours;
-    }
-
-    public void setMaintenanceHours(Time maintenanceHours) {
-        this.maintenanceHours = maintenanceHours;
-    }
-
-    public Long getMaintenanceStaffCount() {
-        return maintenanceStaffCount;
-    }
-
-    public void setMaintenanceStaffCount(Long maintenanceStaffCount) {
-        this.maintenanceStaffCount = maintenanceStaffCount;
-    }
-
-    public Time getMaintenanceTime() {
-        return maintenanceTime;
-    }
-
-    public void setMaintenanceTime(Time maintenanceTime) {
-        this.maintenanceTime = maintenanceTime;
-    }
-
-    public String getMeritAwarded() {
-        return meritAwarded;
-    }
-
-    public void setMeritAwarded(String meritAwarded) {
-        this.meritAwarded = meritAwarded;
-    }
-
-    public String getTestFlightRequired() {
-        return testFlightRequired;
-    }
-
-    public void setTestFlightRequired(String testFlightRequired) {
-        this.testFlightRequired = testFlightRequired;
-    }
-
-    public String getRemarks() {
-        return remarks;
-    }
-
-    public void setRemarks(String remarks) {
-        this.remarks = remarks;
-    }
-
-    public String getFilePath() {
-        return filePath;
-    }
-
-    public void setFilePath(String filePath) {
-        this.filePath = filePath;
-    }
-
-    public String getStatus() {
-        return status;
-    }
-
-    public void setStatus(String status) {
-        this.status = status;
-    }
 }

+ 223 - 0
gm-base-ser/src/main/java/com/goomood/phm/domain/FaultMonitorA.java

@@ -0,0 +1,223 @@
+package com.goomood.phm.domain;
+
+import java.sql.Time;
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.goomood.common.core.domain.BaseEntity;
+import lombok.Data;
+import nonapi.io.github.classgraph.json.Id;
+
+import java.io.Serializable;
+
+/**
+ * 故障监控对象 fault_monitor
+ */
+@Data
+@TableName("fault_monitor")
+public class FaultMonitorA extends BaseEntity implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /** id */
+    @Id
+    private Long id;
+
+    /** 日期 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date incidentDate;
+
+    /** 战区 */
+    private String militaryRegion;
+
+    /** 军 */
+    private String army;
+
+    /** 师 */
+    private String division;
+
+    /** 团 */
+    private String regiment;
+
+    /** 中队 */
+    private String squadron;
+
+    /** 飞机号 */
+    private String aircraftNo;
+
+    /** 机型 */
+    private String aircraftType;
+
+    /** 出厂号码 */
+    private String factoryNo;
+
+    /** 机件类型 */
+    private String partCategory;
+
+    /** 机件号 */
+    private String partNo;
+
+    /** 机件型别 */
+    private String partModel;
+
+    /** 机件名称 */
+    private String partName;
+
+    /** 起落 */
+    private Long landingCount;
+
+    /** 专业 */
+    private String specialty;
+
+    /** 故障件名称 */
+    private String faultyPartName;
+
+    /** 故障件型别 */
+    private String faultyPartModel;
+
+    /** 故障件号码 */
+    private String faultyPartNo;
+
+    /** 故障件所属发动机型别 */
+    private String engineType;
+
+    /** 故障件所属发动机号码 */
+    private String engineNo;
+
+    /** 故障件所属发动机序号 */
+    private String engineSerialNo;
+
+    /** 故障件位置 */
+    private String faultLocation;
+
+    /** 故障现象 */
+    private String faultDescription;
+
+    /** 故障发生地点 */
+    private String faultLocationSite;
+
+    /** 发现时机 */
+    private String detectionTiming;
+
+    /** 系统 */
+    private String useSystem;
+
+    /** 计时类型 */
+    private String timingType;
+
+    /** 故障件制造厂 */
+    private String manufacturer;
+
+    /** 故障件翻修厂 */
+    private String repairFacility;
+
+    /** 故障件装本机工作时次 */
+    @JsonFormat(pattern = "HH:mm:ss")
+    private Time workHoursCurrent;
+
+    /** 故障件总工作时次 */
+    @JsonFormat(pattern = "HH:mm:ss")
+    private Time workHoursTotal;
+
+    /** 故障件修后时次 */
+    @JsonFormat(pattern = "HH:mm:ss")
+    private Time workHoursAfterRepair;
+
+    /** 故换件型别 */
+    private String replacementPartModel;
+
+    /** 故换件号码 */
+    private String replacementPartNo;
+
+    /** 故换件制造厂 */
+    private String replacementManufacturer;
+
+    /** 故换件总工作时次 */
+    @JsonFormat(pattern = "HH:mm:ss")
+    private Time replacementWorkHoursTotal;
+
+    /** 故换件翻修厂 */
+    private String replacementRepairFacility;
+
+    /** 故换件修后时次 */
+    @JsonFormat(pattern = "HH:mm:ss")
+    private Time replacementHoursAfterRepair;
+
+    /** 故障失常码 */
+    private String faultCode;
+
+    /** 故障件装机日期 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date installationDate;
+
+    /** 故障原因 */
+    private String faultCause;
+
+    /** 故障性质 */
+    private String faultNature;
+
+    /** 故障责任 */
+    private String faultResponsibility;
+
+    /** 故障后果 */
+    private String faultConsequence;
+
+    /** 处理意见 */
+    private String handlingSuggestion;
+
+    /** 影响次数 */
+    private Long impactCount;
+
+    /** 误飞次数 */
+    private Long missedFlightCount;
+
+    /** 判明方法 */
+    private String detectionMethod;
+
+    /** 发现人 */
+    private String discoverer;
+
+    /** 排除方法 */
+    private String resolutionMethod;
+
+    /** 排故人 */
+    private String maintainer;
+
+    /** 审核人 */
+    private String reviewer;
+
+    /** 审核时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date reviewTime;
+
+    /** 排除日期 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date resolutionDate;
+
+    /** 排故工时 */
+    @JsonFormat(pattern = "HH:mm:ss")
+    private Time maintenanceHours;
+
+    /** 排故人数 */
+    private Long maintenanceStaffCount;
+
+    /** 排故时间 */
+    @JsonFormat(pattern = "HH:mm:ss")
+    private Time maintenanceTime;
+
+    /** 是否立功 */
+    private String meritAwarded;
+
+    /** 需要试飞 */
+    private String testFlightRequired;
+
+    /** 备注 */
+    private String remarks;
+
+    /** 文件路径 */
+    private String filePath;
+
+    /** 监控状态 */
+    private String status;
+}    

+ 67 - 0
gm-base-ser/src/main/java/com/goomood/phm/domain/KGraphClause.java

@@ -0,0 +1,67 @@
+package com.goomood.phm.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import com.goomood.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+
+
+/**
+ * 知识图谱分句结果视图对象 als_k_graph_clause_t
+ *
+ * @author wgk
+ * @date 2025-01-03
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("als_k_graph_clause_t")
+public class KGraphClause extends BasePO  {
+//    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 唯一ID
+     */
+    @TableId(value = "id")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long id;
+
+    /**
+     * 任务ID
+     */
+    @TableField("task_id")
+    private Long taskId;
+
+    /**
+     * 分句结果文件
+     */
+    @TableField(value = "clause")
+    private String clause;
+
+    /**
+     * 状态
+     */
+    @TableField(value = "status")
+    private String status;
+
+    /**
+     * 备注
+     */
+    @TableField(value = "remarks")
+    private String remarks;
+
+    /**
+     * 删除标识(1删除 0未删除)
+     */
+    @TableField(value = "del_flag")
+    private Integer delFlag;
+
+
+}

+ 89 - 0
gm-base-ser/src/main/java/com/goomood/phm/domain/KGraphEntity.java

@@ -0,0 +1,89 @@
+package com.goomood.phm.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import com.goomood.common.annotation.Excel;
+import com.goomood.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+
+/**
+ * 知识图谱实体关系视图对象 als_k_graph_entity_t
+ *
+ * @author wgk
+ * @date 2025-01-03
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("als_k_graph_entity_t")
+public class KGraphEntity extends BasePO  {
+    private static final long serialVersionUID = 1L;
+
+    /** 唯一ID */
+    @TableId
+    @Excel(name = "唯一ID")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long id;
+
+    /** 分句ID */
+    @Excel(name = "分句ID")
+    @TableField(value = "clause_id")
+    private Long clauseId;
+
+    /** 头实体 */
+    @Excel(name = "头实体")
+    @TableField(value = "head_entity")
+    private String headEntity;
+
+    /** 头实体类 */
+    @Excel(name = "头实体类")
+    @TableField(value = "head_entity_class")
+    private String headEntityClass;
+
+    /** 关系 */
+    @Excel(name = "关系")
+    @TableField(value = "relation")
+    private String relation;
+
+    /** 尾实体 */
+    @Excel(name = "尾实体")
+    @TableField(value = "tail_entity")
+    private String tailEntity;
+
+    /** 尾实体类 */
+    @Excel(name = "尾实体类")
+    @TableField(value = "tail_entity_class")
+    private String tailEntityClass;
+
+    /** 状态 */
+    @Excel(name = "状态")
+    @TableField(value = "status")
+    private String status;
+
+    /** 备注 */
+    @Excel(name = "备注")
+    @TableField(value = "remarks")
+    private String remarks;
+
+    /** 删除标识(1删除 0未删除) */
+    @Excel(name = "删除标识", readConverterExp = "1=删除,0=未删除")
+    @TableField(value = "del_flag")
+    private Integer delFlag;
+
+    /** 创建人名称 */
+    @Excel(name = "创建人名称")
+    @TableField(exist = false)
+    private String createByName;
+
+    /** 更新人名称 */
+    @Excel(name = "更新人名称")
+    @TableField(exist = false)
+    private String updateByName;
+}

+ 80 - 0
gm-base-ser/src/main/java/com/goomood/phm/domain/KGraphTask.java

@@ -0,0 +1,80 @@
+package com.goomood.phm.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import com.goomood.common.annotation.Excel;
+import com.goomood.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+
+
+/**
+ * 知识图谱任务对象 als_k_graph_task_t
+ *
+ * @author wgk
+ * @date 2025-01-03
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("als_k_graph_task_t")
+public class KGraphTask extends BasePO {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 唯一ID
+     */
+    @TableId(value = "id")
+    @Excel(name = "唯一ID")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long id;
+
+    /**
+     * 任务名称
+     */
+    @TableField("task_name")
+    @Excel(name = "任务名称")
+    private String taskName;
+
+    /**
+     * 任务类型
+     */
+    @TableField("task_type")
+    @Excel(name = "任务类型")
+    private String taskType;
+
+    /**
+     * 原始文件
+     */
+    @TableField("oss_id")
+    @Excel(name = "原始文件")
+    private Long ossId;
+
+    /**
+     * 状态
+     */
+    @TableField("status")
+    @Excel(name = "状态")
+    private String status;
+
+    /**
+     * 备注
+     */
+    @TableField("remarks")
+    @Excel(name = "备注")
+    private String remarks;
+
+    /**
+     * 删除标识(1删除 0未删除)
+     */
+    @TableField("del_flag")
+    @Excel(name = "删除标识(1删除 0未删除)")
+    private Integer delFlag;
+
+
+}

+ 16 - 0
gm-base-ser/src/main/java/com/goomood/phm/domain/dto/CataiDTO.java

@@ -0,0 +1,16 @@
+package com.goomood.phm.domain.dto;
+
+import lombok.Data;
+
+/**
+ * @Author: wyj
+ * @CreateTime: 2025-07-25
+ * @Belongpackage com.goomood.phm.domain.dto
+ */
+@Data
+public class CataiDTO {
+
+    private String userId;
+
+    private String question;
+}

+ 36 - 0
gm-base-ser/src/main/java/com/goomood/phm/domain/dto/ExtraKGraphTaskDTO.java

@@ -0,0 +1,36 @@
+package com.goomood.phm.domain.dto;
+
+import com.goomood.phm.domain.KGraphClause;
+import com.goomood.phm.domain.KGraphEntity;
+import lombok.Data;
+
+import java.util.List;
+@Data
+public class ExtraKGraphTaskDTO {
+
+    /**
+     * 任务id
+     */
+    private Long taskId;
+
+    /**
+     * 文件Id
+     */
+    private Long ossId;
+
+    /**
+     * 任务类型
+     */
+    private String taskType;
+
+    /**
+     * 实体关系记录
+     */
+    private List<KGraphEntity> graphEntityList;
+
+    /**
+     * 分句记录
+     */
+    private List<KGraphClause> graphClauseList;
+
+}

+ 31 - 0
gm-base-ser/src/main/java/com/goomood/phm/domain/dto/ExtraKGraphTaskStatusDTO.java

@@ -0,0 +1,31 @@
+package com.goomood.phm.domain.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * by wyj
+ * @Data 2025-07-21
+ */
+@Data
+public class ExtraKGraphTaskStatusDTO {
+    /**
+     * 任务id
+     */
+    @NotNull(message = "任务id不能为空")
+    private Long taskId;
+
+    /**
+     * 任务类型
+     */
+    @NotBlank(message = "任务类型不能为空")
+    private String taskType;
+
+    /**
+     * 状态
+     */
+    @NotBlank(message = "状态不能为空")
+    private String status;
+}

+ 20 - 0
gm-base-ser/src/main/java/com/goomood/phm/domain/dto/ReturnCatAiDTO.java

@@ -0,0 +1,20 @@
+package com.goomood.phm.domain.dto;
+
+import lombok.Data;
+
+/**
+ * @Author: wyj
+ * @CreateTime: 2025-07-25
+ * @Belongpackage com.goomood.phm.domain.dto
+ */
+
+@Data
+public class ReturnCatAiDTO {
+
+
+    private String user_id;
+    private String answer;
+    private String ossID;
+    private String file_name;
+    private String graph;
+}

+ 25 - 0
gm-base-ser/src/main/java/com/goomood/phm/enums/GraphStatus.java

@@ -0,0 +1,25 @@
+package com.goomood.phm.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 用户状态
+ *
+ * @author wgk
+ */
+@Getter
+@AllArgsConstructor
+public enum GraphStatus {
+    STATUS_0("0", "待分句"),
+    STATUS_1("1", "分句中"),
+    STATUS_2("2", "待抽取"),
+    STATUS_3("3", "抽取中"),
+    STATUS_4("4", "审核中"),
+    STATUS_5("5", "入库中"),
+    STATUS_6("6", "已入库"),
+    STATUS_INVALID("2", "作废"),
+    STATUS_PASS("1", "通过");
+    private final String code;
+    private final String info;
+}

+ 13 - 0
gm-base-ser/src/main/java/com/goomood/phm/mapper/AlsAtlasFileTMapper.java

@@ -0,0 +1,13 @@
+package com.goomood.phm.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.goomood.phm.domain.AlsAtlasFileT;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 文件管理Mapper接口
+ */
+@Mapper
+public interface AlsAtlasFileTMapper extends BaseMapper<AlsAtlasFileT> {
+
+}

+ 26 - 0
gm-base-ser/src/main/java/com/goomood/phm/mapper/FaultMonitorAMapper.java

@@ -0,0 +1,26 @@
+package com.goomood.phm.mapper;
+
+import com.goomood.phm.domain.FaultMonitor;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 故障监控Mapper接口
+ */
+@Mapper
+public interface FaultMonitorAMapper {
+
+    /**
+     * 根据日期范围查询故障记录
+     * @param startDate 开始日期
+     * @param endDate 结束日期
+     * @return 故障记录列表
+     */
+    List<FaultMonitor> findByIncidentDateBetween(
+            @Param("startDate") Date startDate,
+            @Param("endDate") Date endDate
+    );
+}    

+ 4 - 0
gm-base-ser/src/main/java/com/goomood/phm/mapper/FaultMonitorMapper.java

@@ -1,6 +1,8 @@
 package com.goomood.phm.mapper;
 
+import java.util.Date;
 import java.util.List;
+
 import com.goomood.phm.domain.FaultMonitor;
 import org.apache.ibatis.annotations.Param;
 
@@ -67,4 +69,6 @@ public interface FaultMonitorMapper
      * @return
      */
     int countUnprocessedFaults(@Param("status") String status);
+
+
 }

+ 9 - 0
gm-base-ser/src/main/java/com/goomood/phm/mapper/KGraphClauseMapper.java

@@ -0,0 +1,9 @@
+package com.goomood.phm.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.goomood.phm.domain.KGraphClause;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface KGraphClauseMapper extends BaseMapper<KGraphClause> {
+}

+ 13 - 0
gm-base-ser/src/main/java/com/goomood/phm/mapper/KGraphEntityMapper.java

@@ -0,0 +1,13 @@
+package com.goomood.phm.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.goomood.phm.domain.KGraphEntity;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface KGraphEntityMapper extends BaseMapper<KGraphEntity> {
+
+    List<KGraphEntity> selectListByTaskId(Long taskId);
+}

+ 9 - 0
gm-base-ser/src/main/java/com/goomood/phm/mapper/KGraphTaskMapper.java

@@ -0,0 +1,9 @@
+package com.goomood.phm.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.goomood.phm.domain.KGraphTask;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface KGraphTaskMapper extends BaseMapper<KGraphTask> {
+}

+ 3 - 1
gm-base-ser/src/main/java/com/goomood/phm/mapper/TechDataMapper.java

@@ -2,6 +2,7 @@ package com.goomood.phm.mapper;
 
 import java.util.List;
 import com.goomood.phm.domain.TechData;
+import org.apache.ibatis.annotations.Mapper;
 
 /**
  * 技术资料Mapper接口
@@ -9,6 +10,7 @@ import com.goomood.phm.domain.TechData;
  * @author goomood
  * @date 2024-11-16
  */
+@Mapper
 public interface TechDataMapper 
 {
     /**
@@ -17,7 +19,7 @@ public interface TechDataMapper
      * @param id 技术资料主键
      * @return 技术资料
      */
-    public TechData selectTechDataById(Long id);
+     TechData selectTechDataById(Long id);
 
     /**
      * 查询技术资料列表

+ 21 - 0
gm-base-ser/src/main/java/com/goomood/phm/service/FaultMonitorService.java

@@ -0,0 +1,21 @@
+package com.goomood.phm.service;
+
+import java.util.Map;
+
+/**
+ * 故障监控服务接口
+ */
+public interface FaultMonitorService {
+
+    /**
+     * 统计近三年下月发生故障最多的5类部件
+     * @return 部件名称与故障次数的映射
+     */
+    Map<String, Long> getTop5FaultyPartsNextMonthInThreeYears();
+
+    /**
+     * 统计近半年发生故障最多的5类部件
+     * @return 部件名称与故障次数的映射
+     */
+    Map<String, Long> getTop5FaultyPartsInSixMonths();
+}    

+ 61 - 0
gm-base-ser/src/main/java/com/goomood/phm/service/IAlsAtlasFileTService.java

@@ -0,0 +1,61 @@
+package com.goomood.phm.service;
+
+
+import com.goomood.common.core.domain.AjaxResult;
+
+
+import com.goomood.phm.domain.AlsAtlasFileT;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+
+
+/**
+ * 文件管理Service接口
+ */
+public interface IAlsAtlasFileTService  {
+    /**
+     * 查询文件管理列表
+     * 
+     * @param alsAtlasFileT 文件管理
+     * @return 文件管理集合
+     */
+    List<AlsAtlasFileT> selectAlsAtlasFileTList(AlsAtlasFileT alsAtlasFileT);
+    
+    /**
+     * 新增文件管理
+     * 
+     * @param alsAtlasFileT 文件管理
+     * @return 结果
+     */
+    int insertAlsAtlasFileT(AlsAtlasFileT alsAtlasFileT);
+    
+    /**
+     * 修改文件管理
+     * 
+     * @param alsAtlasFileT 文件管理
+     * @return 结果
+     */
+    int updateAlsAtlasFileT(AlsAtlasFileT alsAtlasFileT);
+    
+    /**
+     * 批量删除文件管理
+     * 
+     * @param ids 需要删除的文件ID
+     * @return 结果
+     */
+    int deleteAlsAtlasFileTByIds(String[] ids);
+    
+    /**
+     * 删除文件管理信息
+     * 
+     * @param id 文件ID
+     * @return 结果
+     */
+    int deleteAlsAtlasFileTById(String id);
+
+
+    AlsAtlasFileT getById(String id);
+}

+ 2 - 0
gm-base-ser/src/main/java/com/goomood/phm/service/IFaultMonitorService.java

@@ -1,6 +1,8 @@
 package com.goomood.phm.service;
 
 import java.util.List;
+import java.util.Map;
+
 import com.goomood.phm.domain.FaultMonitor;
 
 /**

+ 47 - 0
gm-base-ser/src/main/java/com/goomood/phm/service/IKGraphClauseService.java

@@ -0,0 +1,47 @@
+package com.goomood.phm.service;
+
+import com.goomood.phm.domain.KGraphClause;
+
+import java.util.List;
+
+public interface IKGraphClauseService {
+
+
+    List<KGraphClause> selectList(KGraphClause po);
+    /**
+     * 修改知识图谱分句结果
+     *
+     * @param po 知识图谱分句结果Bo
+     * @return 结果:true 更新成功,false 更新失败
+     */
+    Boolean update(KGraphClause po);
+    /**
+     * 查询知识图谱分句结果
+     *
+     * @param id 知识图谱分句结果主键
+     * @return 知识图谱分句结果
+     */
+    KGraphClause selectById(Long id);
+    /**
+     * 新增知识图谱分句结果
+     */
+    Boolean saveBatch(List<KGraphClause> graphClauseList);
+    /**
+     * 新增知识图谱分句结果
+     */
+    boolean insert(KGraphClause po);
+    /**
+     * 批量删除知识图谱分句结果
+     *
+     * @param ids 需要删除的知识图谱分句结果主键集合
+     * @return 结果:true 删除成功,false 删除失败
+     */
+    boolean deleteByIds(Long[] ids);
+//    /**
+//     * 新增知识图谱分句结果,前台提供主键值,一般用于导入的场合
+//     *
+//     * @param po 知识图谱分句结果Bo
+//     * @return 结果:true 操作成功,false 操作失败
+//     */
+//    boolean insertWithPk(KGraphClause po);
+}

+ 81 - 0
gm-base-ser/src/main/java/com/goomood/phm/service/IKGraphEntityService.java

@@ -0,0 +1,81 @@
+package com.goomood.phm.service;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.goomood.phm.domain.KGraphEntity;
+
+import java.util.List;
+
+public interface IKGraphEntityService {
+
+    /**
+     * 查询知识图谱实体关系
+     *
+     * @param id 知识图谱实体关系主键
+     * @return 知识图谱实体关系
+     */
+    KGraphEntity selectById(Long id);
+
+    /**
+     * 查询知识图谱实体关系列表
+     *
+     * @param po 知识图谱实体关系Bo
+     * @return 知识图谱实体关系集合
+     */
+    List<KGraphEntity> selectList(KGraphEntity po);
+
+    /**
+     * 查询知识图谱实体关系列表
+     *
+     * @param taskId TaskId
+     * @return 知识图谱实体关系集合
+     */
+    List<KGraphEntity> selectListByTaskId(Long taskId);
+
+    /**
+     * 分页查询知识图谱实体关系列表
+     *
+     * @param kGraphEntityBo 知识图谱实体关系Bo
+     * @return 分页知识图谱实体关系集合
+     */
+    Page<KGraphEntity> selectPage(KGraphEntity kGraphEntityBo);
+
+    /**
+     * 新增知识图谱实体关系
+     *
+     * @param po 知识图谱实体关系Bo
+     * @return 结果:true 操作成功,false 操作失败
+     */
+    void insert(KGraphEntity po);
+
+    /**
+     * 新增知识图谱实体关系
+     *
+     * @param kGraphEntityList 知识图谱实体关系Bo
+     * @return 结果:true 操作成功,false 操作失败
+     */
+    boolean saveBatch(List<KGraphEntity> kGraphEntityList);
+
+    /**
+     * 新增知识图谱实体关系,前台提供主键值,一般用于导入的场合
+     *
+     * @param po 知识图谱实体关系po
+     * @return 结果:true 操作成功,false 操作失败
+     */
+    boolean insertWithPk(KGraphEntity po);
+
+    /**
+     * 修改知识图谱实体关系
+     *
+     * @param po 知识图谱实体关系po
+     * @return 结果:true 更新成功,false 更新失败
+     */
+    boolean update(KGraphEntity po);
+
+    /**
+     * 批量删除知识图谱实体关系
+     *
+     * @param ids 需要删除的知识图谱实体关系主键集合
+     * @return 结果:true 删除成功,false 删除失败
+     */
+    boolean deleteByIds(Long[] ids);
+}

+ 67 - 0
gm-base-ser/src/main/java/com/goomood/phm/service/IKGraphTaskService.java

@@ -0,0 +1,67 @@
+package com.goomood.phm.service;
+
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.goomood.phm.domain.KGraphTask;
+import com.goomood.phm.domain.dto.CataiDTO;
+import com.goomood.phm.domain.dto.ExtraKGraphTaskDTO;
+import com.goomood.phm.domain.dto.ExtraKGraphTaskStatusDTO;
+
+import java.util.List;
+
+/**
+ * 知识图谱任务Service接口
+ *
+ * @author wyj
+ * @date 2025-07-21
+ */
+public interface IKGraphTaskService {
+    /**
+     * 分页查询知识图谱任务列表
+     *
+     * @param po 知识图谱任务Bo
+     * @return 分页知识图谱任务集合
+     */
+    List<KGraphTask> selectPage(KGraphTask po);
+    /**
+     * 查询知识图谱任务
+     *
+     * @param id 知识图谱任务主键
+     * @return 知识图谱任务
+     */
+    KGraphTask selectById(Long id);
+    /**
+     * 新增知识图谱任务
+     *
+     * @param po 知识图谱任务Bo
+     * @return 结果:true 操作成功,false 操作失败
+     */
+    boolean insert(KGraphTask po);
+    /**
+     * 处理任务
+     *
+     * @param po 知识图谱任务Bo
+     * @return 结果:true 操作成功,false 操作失败
+     */
+    boolean proTask(KGraphTask po);
+    /**
+     * 修改知识图谱任务
+     *
+     * @param po 知识图谱任务Bo
+     * @return 结果:true 更新成功,false 更新失败
+     */
+    Boolean update(KGraphTask po);
+    /**
+     * 批量删除知识图谱任务
+     *
+     * @param ids 需要删除的知识图谱任务主键集合
+     * @return 结果:true 删除成功,false 删除失败
+     */
+    boolean deleteByIds(Long[] ids);
+
+    boolean resultCallback(ExtraKGraphTaskDTO dto);
+
+    boolean statusCallback(ExtraKGraphTaskStatusDTO extraKGraphTaskStatusdto);
+
+    Object catai(CataiDTO dto);
+}

+ 9 - 0
gm-base-ser/src/main/java/com/goomood/phm/service/ITechDataService.java

@@ -3,6 +3,8 @@ package com.goomood.phm.service;
 import java.util.List;
 import com.goomood.phm.domain.TechData;
 
+import javax.servlet.http.HttpServletResponse;
+
 /**
  * 技术资料Service接口
  * 
@@ -58,4 +60,11 @@ public interface ITechDataService
      * @return 结果
      */
     public int deleteTechDataById(Long id);
+
+    /**
+     * 根据Id下载对应文件
+     * @param oosId
+     * @return
+     */
+    int downloadFile(Long oosId, HttpServletResponse response);
 }

+ 141 - 0
gm-base-ser/src/main/java/com/goomood/phm/service/impl/AlsAtlasFileTServiceImpl.java

@@ -0,0 +1,141 @@
+package com.goomood.phm.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.goomood.common.core.domain.AjaxResult;
+import com.goomood.common.core.domain.entity.SysUser;
+import com.goomood.common.utils.SecurityUtils;
+import com.goomood.common.utils.StringUtils;
+import com.goomood.phm.domain.AlsAtlasFileT;
+import com.goomood.phm.mapper.AlsAtlasFileTMapper;
+import com.goomood.phm.service.IAlsAtlasFileTService;
+import org.springframework.stereotype.Service;
+import javax.annotation.Resource;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 文件管理Service实现类
+ */
+@Service
+public class AlsAtlasFileTServiceImpl implements IAlsAtlasFileTService {
+    @Resource
+    private AlsAtlasFileTMapper alsAtlasFileTMapper;
+
+    /**
+     * 查询文件管理列表
+     *
+     * @param alsAtlasFileT 文件管理
+     * @return 文件管理
+     */
+    @Override
+    public List<AlsAtlasFileT> selectAlsAtlasFileTList(AlsAtlasFileT alsAtlasFileT) {
+        QueryWrapper<AlsAtlasFileT> wrapper = new QueryWrapper<>();
+        wrapper.lambda().like(StringUtils.isNotEmpty(alsAtlasFileT.getFileName()), AlsAtlasFileT::getFileName, alsAtlasFileT.getFileName())
+                .eq(StringUtils.isNotEmpty(alsAtlasFileT.getFileType()), AlsAtlasFileT::getFileType, alsAtlasFileT.getFileType())
+                .eq(alsAtlasFileT.getUrl() != null, AlsAtlasFileT::getUrl, alsAtlasFileT.getUrl())
+                .eq(StringUtils.isNotEmpty(alsAtlasFileT.getStatus()), AlsAtlasFileT::getStatus, alsAtlasFileT.getStatus())
+                .eq(alsAtlasFileT.getDelFlag() != null, AlsAtlasFileT::getDelFlag, alsAtlasFileT.getDelFlag())
+                .eq(alsAtlasFileT.getCreateBy() != null, AlsAtlasFileT::getCreateBy, alsAtlasFileT.getCreateBy())
+                .ge(alsAtlasFileT.getCreateTime() != null, AlsAtlasFileT::getCreateTime, alsAtlasFileT.getCreateTime())
+                .le(alsAtlasFileT.getUpdateTime() != null, AlsAtlasFileT::getUpdateTime, alsAtlasFileT.getUpdateTime())
+                .orderByDesc(AlsAtlasFileT::getCreateTime);
+        return alsAtlasFileTMapper.selectList(wrapper);
+    }
+
+    /**
+     * 新增文件管理
+     *
+     * @param alsAtlasFileT 文件管理
+     * @return 结果
+     */
+    @Override
+    public int insertAlsAtlasFileT(AlsAtlasFileT alsAtlasFileT) {
+        SysUser user = SecurityUtils.getLoginUser().getUser();
+        alsAtlasFileT.setCreateBy(user.getUserId().toString());
+        alsAtlasFileT.setCreateTime(new Date());
+        alsAtlasFileT.setUpdateBy(user.getUserId().toString());
+        alsAtlasFileT.setUpdateTime(new Date());
+        alsAtlasFileT.setDelFlag(false);
+        alsAtlasFileT.setVersion(1);
+        return alsAtlasFileTMapper.insert(alsAtlasFileT);
+    }
+
+    /**
+     * 修改文件管理
+     *
+     * @param alsAtlasFileT 文件管理
+     * @return 结果
+     */
+    @Override
+    public int updateAlsAtlasFileT(AlsAtlasFileT alsAtlasFileT) {
+        alsAtlasFileT.setUpdateBy(SecurityUtils.getUserId().toString());
+        alsAtlasFileT.setUpdateTime(new Date());
+        return alsAtlasFileTMapper.updateById(alsAtlasFileT);
+    }
+    /**
+     * 批量删除文件管理
+     *
+     * @param ids 需要删除的文件ID数组
+     * @return 结果
+     */
+    @Override
+    public int deleteAlsAtlasFileTByIds(String[] ids) {
+        if (ids == null || ids.length == 0) {
+            return 0;
+        }
+
+        // 获取当前用户ID作为更新人
+        String updateBy = SecurityUtils.getUserId().toString();
+        Date updateTime = new Date();
+
+        // 构建更新条件和更新内容
+        UpdateWrapper<AlsAtlasFileT> updateWrapper = new UpdateWrapper<>();
+        updateWrapper.lambda()
+                .in(AlsAtlasFileT::getId, ids)
+                .set(AlsAtlasFileT::getDelFlag, true)
+                .set(AlsAtlasFileT::getUpdateBy, updateBy)
+                .set(AlsAtlasFileT::getUpdateTime, updateTime);
+
+        // 执行更新操作(逻辑删除)
+        return alsAtlasFileTMapper.update(null, updateWrapper);
+    }
+
+    /**
+     * 删除文件管理
+     *
+     * @param id 需要删除的文件ID
+     * @return 结果
+     */
+    @Override
+    public int deleteAlsAtlasFileTById(String id) {
+        if (StringUtils.isEmpty(id)) {
+            return 0;
+        }
+
+        // 获取当前用户ID作为更新人
+        String updateBy = SecurityUtils.getUserId().toString();
+        Date updateTime = new Date();
+
+        // 构建更新条件和更新内容
+        UpdateWrapper<AlsAtlasFileT> updateWrapper = new UpdateWrapper<>();
+        updateWrapper.lambda()
+                .eq(AlsAtlasFileT::getId, id)
+                .set(AlsAtlasFileT::getDelFlag, true)
+                .set(AlsAtlasFileT::getUpdateBy, updateBy)
+                .set(AlsAtlasFileT::getUpdateTime, updateTime);
+
+        // 执行更新操作(逻辑删除)
+        return alsAtlasFileTMapper.update(null, updateWrapper);
+    }
+
+    @Override
+    public AlsAtlasFileT getById(String id) {
+        QueryWrapper<AlsAtlasFileT> wrapper = new QueryWrapper<>();
+        wrapper.lambda().eq(StringUtils.isNotEmpty(id),AlsAtlasFileT::getId,id);
+        return alsAtlasFileTMapper.selectOne(wrapper);
+    }
+}

+ 102 - 0
gm-base-ser/src/main/java/com/goomood/phm/service/impl/FaultMonitorServiceAImpl.java

@@ -0,0 +1,102 @@
+package com.goomood.phm.service.impl;
+
+import com.goomood.phm.domain.FaultMonitor;
+import com.goomood.phm.mapper.FaultMonitorAMapper;
+import com.goomood.phm.service.FaultMonitorService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 故障监控服务实现
+ */
+@Service
+public class FaultMonitorServiceAImpl implements FaultMonitorService {
+
+    @Resource
+    private FaultMonitorAMapper faultMonitorMapper;
+
+    @Override
+    public Map<String, Long> getTop5FaultyPartsNextMonthInThreeYears() {
+        // 计算关键日期
+        LocalDate currentDate = LocalDate.now();
+        LocalDate nextMonth = currentDate.plusMonths(1);
+        int targetMonth = nextMonth.getMonthValue();
+        
+        // 查询近三年数据
+        List<FaultMonitor> faultMonitors = faultMonitorMapper.findByIncidentDateBetween(
+            toDate(currentDate.minusYears(3)),
+            toDate(currentDate)
+        );
+        
+        return faultMonitors.stream()
+            .filter(fault -> isTargetMonth(fault.getIncidentDate(), targetMonth))
+            .filter(this::isValidFaultPart)
+            .collect(Collectors.groupingBy(
+                FaultMonitor::getFaultyPartName,
+                Collectors.counting()
+            ))
+            .entrySet().stream()
+            .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
+            .limit(5)
+            .collect(Collectors.toMap(
+                Map.Entry::getKey,
+                Map.Entry::getValue,
+                (e1, e2) -> e1,
+                LinkedHashMap::new
+            ));
+    }
+
+    @Override
+    public Map<String, Long> getTop5FaultyPartsInSixMonths() {
+        LocalDate currentDate = LocalDate.now();
+        
+        List<FaultMonitor> faultMonitors = faultMonitorMapper.findByIncidentDateBetween(
+            toDate(currentDate.minusMonths(6)),
+            toDate(currentDate)
+        );
+        
+        return faultMonitors.stream()
+            .filter(this::isValidFaultPart)
+            .collect(Collectors.groupingBy(
+                FaultMonitor::getFaultyPartName,
+                Collectors.counting()
+            ))
+            .entrySet().stream()
+            .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
+            .limit(5)
+            .collect(Collectors.toMap(
+                Map.Entry::getKey,
+                Map.Entry::getValue,
+                (e1, e2) -> e1,
+                LinkedHashMap::new
+            ));
+    }
+    
+    // 辅助方法:Date转LocalDate
+    private LocalDate toLocalDate(Date date) {
+        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
+    }
+    
+    // 辅助方法:LocalDate转Date
+    private Date toDate(LocalDate localDate) {
+        return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
+    }
+    
+    // 检查是否为目标月份的故障
+    private boolean isTargetMonth(Date date, int targetMonth) {
+        if (date == null) return false;
+        return toLocalDate(date).getMonthValue() == targetMonth;
+    }
+    
+    // 验证故障部件有效性
+    private boolean isValidFaultPart(FaultMonitor fault) {
+        return fault != null 
+            && fault.getFaultyPartName() != null 
+            && !fault.getFaultyPartName().trim().isEmpty();
+    }
+}    

+ 31 - 39
gm-base-ser/src/main/java/com/goomood/phm/service/impl/FaultMonitorServiceImpl.java

@@ -17,7 +17,12 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
 
 import javax.validation.Validator;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.util.Date;
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * 故障监控Service业务层处理
@@ -26,8 +31,7 @@ import java.util.List;
  * @date 2024-11-17
  */
 @Service
-public class FaultMonitorServiceImpl implements IFaultMonitorService 
-{
+public class FaultMonitorServiceImpl implements IFaultMonitorService {
     @Autowired
     private FaultMonitorMapper faultMonitorMapper;
 
@@ -40,38 +44,35 @@ public class FaultMonitorServiceImpl implements IFaultMonitorService
 
     /**
      * 查询故障监控
-     * 
+     *
      * @param id 故障监控主键
      * @return 故障监控
      */
     @Override
-    public FaultMonitor selectFaultMonitorById(Long id)
-    {
+    public FaultMonitor selectFaultMonitorById(Long id) {
         return faultMonitorMapper.selectFaultMonitorById(id);
     }
 
     /**
      * 查询故障监控列表
-     * 
+     *
      * @param faultMonitor 故障监控
      * @return 故障监控
      */
     @Override
-    public List<FaultMonitor> selectFaultMonitorList(FaultMonitor faultMonitor)
-    {
+    public List<FaultMonitor> selectFaultMonitorList(FaultMonitor faultMonitor) {
         return faultMonitorMapper.selectFaultMonitorList(faultMonitor);
     }
 
     /**
      * 新增故障监控
-     * 
+     *
      * @param faultMonitor 故障监控
      * @return 结果
      */
     @Override
     @Transactional(readOnly = false)
-    public int insertFaultMonitor(FaultMonitor faultMonitor)
-    {
+    public int insertFaultMonitor(FaultMonitor faultMonitor) {
         faultMonitor.setCreateTime(DateUtils.getNowDate());
         int res = faultMonitorMapper.insertFaultMonitor(faultMonitor);
         saveFaultRecord(faultMonitor);
@@ -80,16 +81,15 @@ public class FaultMonitorServiceImpl implements IFaultMonitorService
 
     /**
      * 修改故障监控
-     * 
+     *
      * @param faultMonitor 故障监控
      * @return 结果
      */
     @Override
     @Transactional(readOnly = false)
-    public int updateFaultMonitor(FaultMonitor faultMonitor)
-    {
+    public int updateFaultMonitor(FaultMonitor faultMonitor) {
         faultMonitor.setUpdateTime(DateUtils.getNowDate());
-        int res =  faultMonitorMapper.updateFaultMonitor(faultMonitor);
+        int res = faultMonitorMapper.updateFaultMonitor(faultMonitor);
         FaultMonitor entity = this.selectFaultMonitorById(faultMonitor.getId());
         saveFaultRecord(entity);
         return res;
@@ -97,38 +97,37 @@ public class FaultMonitorServiceImpl implements IFaultMonitorService
 
     /**
      * 批量删除故障监控
-     * 
+     *
      * @param ids 需要删除的故障监控主键
      * @return 结果
      */
     @Override
-    public int deleteFaultMonitorByIds(Long[] ids)
-    {
+    public int deleteFaultMonitorByIds(Long[] ids) {
         return faultMonitorMapper.deleteFaultMonitorByIds(ids);
     }
 
     /**
      * 删除故障监控信息
-     * 
+     *
      * @param id 故障监控主键
      * @return 结果
      */
     @Override
-    public int deleteFaultMonitorById(Long id)
-    {
+    public int deleteFaultMonitorById(Long id) {
         return faultMonitorMapper.deleteFaultMonitorById(id);
     }
 
 
     /**
      * 更新故障记录
+     *
      * @param faultMonitor
      * @return
      */
-    public int saveFaultRecord(FaultMonitor faultMonitor){
-        if(StringUtils.isNotEmpty(faultMonitor.getStatus()) && faultMonitor.getStatus().equals(PhmConstants.FAULT_STATUS_CLOSED)){
+    public int saveFaultRecord(FaultMonitor faultMonitor) {
+        if (StringUtils.isNotEmpty(faultMonitor.getStatus()) && faultMonitor.getStatus().equals(PhmConstants.FAULT_STATUS_CLOSED)) {
             FaultRecord faultRecord = new FaultRecord();
-            BeanUtils.copyProperties(faultMonitor,faultRecord,"id");
+            BeanUtils.copyProperties(faultMonitor, faultRecord, "id");
             return faultRecordService.insertFaultRecord(faultRecord);
         }
         return 0;
@@ -143,13 +142,13 @@ public class FaultMonitorServiceImpl implements IFaultMonitorService
 
     /**
      * 导入接口
+     *
      * @param faultMonitors
      * @return
      */
     @Override
-    public String importFaultMonitor(List<FaultMonitor> faultMonitors){
-        if (CollectionUtils.isEmpty(faultMonitors))
-        {
+    public String importFaultMonitor(List<FaultMonitor> faultMonitors) {
+        if (CollectionUtils.isEmpty(faultMonitors)) {
             throw new ServiceException("导入故障监控数据不能为空!");
         }
 
@@ -157,30 +156,23 @@ public class FaultMonitorServiceImpl implements IFaultMonitorService
         int failureNum = 0;
         StringBuilder successMsg = new StringBuilder();
         StringBuilder failureMsg = new StringBuilder();
-        for (FaultMonitor monitor : faultMonitors)
-        {
-            try
-            {
+        for (FaultMonitor monitor : faultMonitors) {
+            try {
                 BeanValidators.validateWithException(validator, monitor);
                 monitor.setStatus(PhmConstants.FAULT_STATUS_OPEN);
                 this.insertFaultMonitor(monitor);
                 successNum++;
                 successMsg.append("<br/>" + successNum + "、故障监控 " + monitor.getFaultyPartName() + " 导入成功");
-            }
-            catch (Exception e)
-            {
+            } catch (Exception e) {
                 failureNum++;
                 String msg = "<br/>" + failureNum + "、故障监控 " + monitor.getFaultyPartName() + " 导入失败:";
                 failureMsg.append(msg + e.getMessage());
             }
         }
-        if (failureNum > 0)
-        {
+        if (failureNum > 0) {
             failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
             throw new ServiceException(failureMsg.toString());
-        }
-        else
-        {
+        } else {
             successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
         }
         return successMsg.toString();

+ 102 - 0
gm-base-ser/src/main/java/com/goomood/phm/service/impl/KGraphClauseServiceImpl.java

@@ -0,0 +1,102 @@
+package com.goomood.phm.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.goomood.common.utils.StringUtils;
+import com.goomood.phm.domain.KGraphClause;
+import com.goomood.phm.mapper.KGraphClauseMapper;
+import com.goomood.phm.service.IKGraphClauseService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.Arrays;
+import java.util.List;
+
+@Service
+@Slf4j
+public class KGraphClauseServiceImpl implements IKGraphClauseService {
+    @Resource
+    private KGraphClauseMapper kGraphClauseMapper;
+
+    /**
+     * 查询知识图谱分句结果列表
+     *
+     * @param po 知识图谱分句结果Bo
+     * @return 知识图谱分句结果集合
+     */
+    @Override
+    public List<KGraphClause> selectList(KGraphClause po) {
+        QueryWrapper<KGraphClause> wrapper = new QueryWrapper<>();
+        wrapper.lambda().eq(ObjectUtils.isNotEmpty(po.getId()),KGraphClause::getId,po.getId())
+                .eq(ObjectUtils.isNotEmpty(po.getTaskId()), KGraphClause::getTaskId, po.getTaskId())
+                .like(ObjectUtils.isNotEmpty(po.getStatus()),KGraphClause::getStatus,po.getStatus());
+        List<KGraphClause> list = kGraphClauseMapper.selectList(wrapper);
+        return list;
+    }
+    /**
+     * 修改知识图谱分句结果
+     *
+     * @param po 知识图谱分句结果Bo
+     * @return 结果:true 更新成功,false 更新失败
+     */
+    @Override
+    public Boolean update(KGraphClause po) {
+        if (ObjectUtils.isNotEmpty(po) && ObjectUtils.isNotEmpty(po.getId())) {
+            kGraphClauseMapper.updateById(po);
+        }
+        return true;
+    }
+    /**
+     * 查询知识图谱分句结果
+     *
+     * @param id 知识图谱分句结果主键
+     * @return 知识图谱分句结果
+     */
+    @Override
+    public KGraphClause selectById(Long id) {
+        return  kGraphClauseMapper.selectById(id);
+    }
+
+    @Override
+    public Boolean saveBatch(List<KGraphClause> graphClauseList) {
+        kGraphClauseMapper.insert(graphClauseList, 100);
+        return true;
+    }
+    /**
+     * 新增知识图谱分句结果
+     *
+     * @param po 知识图谱分句结果Bo
+     * @return 结果:true 操作成功,false 操作失败
+     */
+    @Override
+    public boolean insert(KGraphClause po) {
+        int insert = kGraphClauseMapper.insert(po);
+        return insert>0;
+    }
+    /**
+     * 批量删除知识图谱分句结果
+     *
+     * @param ids 需要删除的知识图谱分句结果主键集合
+     * @return 结果:true 删除成功,false 删除失败
+     */
+    @Transactional
+    @Override
+    public boolean deleteByIds(Long[] ids) {
+        kGraphClauseMapper.deleteByIds(Arrays.asList(ids));
+        return false;
+    }
+
+//    /**
+//     * 新增知识图谱分句结果,前台提供主键值,一般用于导入的场合
+//     *
+//     * @param po 知识图谱分句结果Bo
+//     * @return 结果:true 操作成功,false 操作失败
+//     */
+//    @Override
+//    public boolean insertWithPk(KGraphClause po) {
+//        //前台传来主键值
+//        return kGraphClauseMapper.insertWithPk(kGraphClause) > 0;
+//    }
+}

+ 116 - 0
gm-base-ser/src/main/java/com/goomood/phm/service/impl/KGraphEntityServiceImpl.java

@@ -0,0 +1,116 @@
+package com.goomood.phm.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.goomood.common.utils.StringUtils;
+import com.goomood.phm.domain.KGraphEntity;
+import com.goomood.phm.mapper.KGraphEntityMapper;
+import com.goomood.phm.service.IKGraphEntityService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+@Service
+@Slf4j
+public class KGraphEntityServiceImpl  implements IKGraphEntityService {
+    @Resource
+    private KGraphEntityMapper kGraphEntityMapper;
+
+
+    /**
+     * 构建知识图谱实体关系查询条件
+     */
+    public static QueryWrapper<KGraphEntity> buildQueryWrapper(KGraphEntity query) {
+        QueryWrapper<KGraphEntity> wrapper = new QueryWrapper<>();
+
+        // 基本查询条件
+        wrapper.eq(query.getId() != null, "id", query.getId())
+                .eq(query.getClauseId() != null, "clause_id", query.getClauseId())
+                .like(StringUtils.isNotEmpty(query.getHeadEntity()), "head_entity", query.getHeadEntity())
+                .like(StringUtils.isNotEmpty(query.getHeadEntityClass()), "head_entity_class", query.getHeadEntityClass())
+                .like(StringUtils.isNotEmpty(query.getRelation()), "relation", query.getRelation())
+                .like(StringUtils.isNotEmpty(query.getTailEntity()), "tail_entity", query.getTailEntity())
+                .like(StringUtils.isNotEmpty(query.getTailEntityClass()), "tail_entity_class", query.getTailEntityClass())
+                .eq(ObjectUtils.isNotEmpty(query.getStatus()), "status", query.getStatus())
+                .eq(query.getDelFlag() != null, "del_flag", query.getDelFlag());
+
+        // 时间范围查询(示例:创建时间)
+        if (query.getCreateTime() != null) {
+            // 假设前端传入的是开始时间
+            wrapper.ge("create_time", query.getCreateTime());
+        }
+        if (query.getUpdateTime() != null) {
+            // 假设前端传入的是结束时间
+            wrapper.le("update_time", query.getUpdateTime());
+        }
+
+        // 排序条件(默认按创建时间降序)
+        wrapper.orderByDesc("create_time");
+
+        return wrapper;
+    }
+    /**
+     * 查询知识图谱实体关系
+     *
+     * @param id 知识图谱实体关系主键
+     * @return 知识图谱实体关系
+     */
+    @Override
+    public KGraphEntity selectById(Long id) {
+        return kGraphEntityMapper.selectById(id);
+    }
+
+    @Override
+    public List<KGraphEntity> selectList(KGraphEntity po) {
+        return kGraphEntityMapper.selectList(buildQueryWrapper(po));
+    }
+
+    @Override
+    public List<KGraphEntity> selectListByTaskId(Long taskId) {
+        return  kGraphEntityMapper.selectListByTaskId(taskId);
+    }
+    /**
+     * 分页查询知识图谱实体关系列表
+     *
+     * @param po 知识图谱实体关系Bo
+     * @return 分页知识图谱实体关系集合
+     */
+    @Override
+    public Page<KGraphEntity> selectPage(KGraphEntity po) {
+        Page<KGraphEntity> kGraphEntityPage = kGraphEntityMapper.selectPage(new Page<>(), buildQueryWrapper(po));
+        return kGraphEntityPage;
+    }
+    /**
+     * 新增知识图谱实体关系
+     *
+     * @param po 知识图谱实体关系Bo
+     * @return 结果:true 操作成功,false 操作失败
+     */
+    @Override
+    public void insert(KGraphEntity po) {
+         kGraphEntityMapper.insert(po);
+    }
+
+    @Override
+    public boolean saveBatch(List<KGraphEntity> kGraphEntityList) {
+        return false;
+    }
+
+    @Override
+    public boolean insertWithPk(KGraphEntity po) {
+        return false;
+    }
+
+    @Override
+    public boolean update(KGraphEntity po) {
+        return false;
+    }
+
+    @Override
+    public boolean deleteByIds(Long[] ids) {
+        return false;
+    }
+}

+ 280 - 0
gm-base-ser/src/main/java/com/goomood/phm/service/impl/KGraphTaskServiceImpl.java

@@ -0,0 +1,280 @@
+package com.goomood.phm.service.impl;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.goomood.common.constant.Constants;
+import com.goomood.common.exception.ServiceException;
+import com.goomood.common.utils.StringUtils;
+
+import com.goomood.framework.config.ServerConfig;
+import com.goomood.phm.domain.KGraphClause;
+import com.goomood.phm.domain.KGraphEntity;
+import com.goomood.phm.domain.KGraphTask;
+import com.goomood.phm.domain.TechData;
+import com.goomood.phm.domain.dto.CataiDTO;
+import com.goomood.phm.domain.dto.ExtraKGraphTaskDTO;
+import com.goomood.phm.domain.dto.ExtraKGraphTaskStatusDTO;
+import com.goomood.phm.domain.dto.ReturnCatAiDTO;
+import com.goomood.phm.enums.GraphStatus;
+import com.goomood.phm.mapper.KGraphTaskMapper;
+import com.goomood.phm.mapper.TechDataMapper;
+import com.goomood.phm.service.IKGraphClauseService;
+import com.goomood.phm.service.IKGraphEntityService;
+import com.goomood.phm.service.IKGraphTaskService;
+import com.goomood.phm.utils.HttpUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.util.*;
+
+/**
+ * 知识图谱任务Service业务层处理
+ *
+ * @author wyj
+ * @date 2025-07-21
+ */
+@Service
+@Slf4j
+public class KGraphTaskServiceImpl implements IKGraphTaskService {
+    @Resource
+    private KGraphTaskMapper kGraphTaskMapper;
+    @Resource
+    private IKGraphClauseService kGraphClauseService;
+    @Resource
+    private IKGraphEntityService kGraphEntityService;
+    @Resource
+    private TechDataMapper techDataMapper;
+    @Resource
+    private ServerConfig serverConfig;
+
+    @Value("${kgqa.ask-url}")
+    private String askUrl;
+
+    @Value("${kgqa.clause-url}")
+    private String clauseUrl;
+
+    @Value("${kgqa.extract-url}")
+    private String extractUrl;
+    //
+    @Value("${kgqa.storage-url}")
+    private String storageUrl;
+    @Value("${server.port:8080}")
+    private Long port;
+    /**
+     * 分页查询知识图谱任务列表
+     *
+     * @param po 知识图谱任务Bo
+     * @return 分页知识图谱任务集合
+     */
+    @Override
+    public List<KGraphTask> selectPage(KGraphTask po) {
+        QueryWrapper<KGraphTask> wrapper = new QueryWrapper<>();
+        List<KGraphTask> kGraphTasks = kGraphTaskMapper.selectList(wrapper);
+        return kGraphTasks;
+    }
+    /**
+     * 查询知识图谱任务
+     *
+     * @param id 知识图谱任务主键
+     * @return 知识图谱任务
+     */
+    @Override
+    public KGraphTask selectById(Long id) {
+        return kGraphTaskMapper.selectById(id);
+    }
+    /**
+     * 新增知识图谱任务
+     *
+     * @param po 知识图谱任务Bo
+     * @return 结果:true 操作成功,false 操作失败
+     */
+    @Override
+    public boolean insert(KGraphTask po) {
+        int rows = kGraphTaskMapper.insert(po);
+        return rows > 0;
+    }
+    public static String getIpAddress() {
+        try {
+            //从网卡中获取IP
+            Enumeration<NetworkInterface> allNetInterfaces = NetworkInterface.getNetworkInterfaces();
+            InetAddress ip;
+            while (allNetInterfaces.hasMoreElements()) {
+                NetworkInterface netInterface = allNetInterfaces.nextElement();
+                //用于排除回送接口,非虚拟网卡,未在使用中的网络接口
+                if (!netInterface.isLoopback() && !netInterface.isVirtual() && netInterface.isUp()) {
+                    //返回和网络接口绑定的所有IP地址
+                    Enumeration<InetAddress> addresses = netInterface.getInetAddresses();
+                    while (addresses.hasMoreElements()) {
+                        ip = addresses.nextElement();
+                        if (ip instanceof Inet4Address) {
+                            return ip.getHostAddress();
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            log.info("IP地址获取失败{}", e.getMessage());
+        }
+        return "127.0.0.1";
+    }
+    /**
+     * 处理任务
+     *
+     * @param po 知识图谱任务Bo
+     * @return 结果:true 操作成功,false 操作失败
+     */
+    @Override
+    public boolean proTask(KGraphTask po ) {
+        log.info("进入处理:{}", po.getTaskType());
+        KGraphTask kGraphTaskVo = this.selectById(po.getId());
+        Long ossId = kGraphTaskVo.getOssId();
+        TechData techData = techDataMapper.selectTechDataById(ossId);
+        String  filePath = Constants.HTTP + getIpAddress() + ":" + port  + techData.getFilePath();
+        if(ObjectUtils.isEmpty(kGraphTaskVo)) {
+            throw new ServiceException("任务为空,请核实任务ID");
+        }
+        String result;
+        JSONObject jsonObject;
+        ExtraKGraphTaskDTO extraGraphTaskVo = new ExtraKGraphTaskDTO();
+        switch (po.getTaskType()) {
+            case "0":
+                updateStatus(po, kGraphTaskVo.getVersion(), GraphStatus.STATUS_1.getCode());
+                // 知识图谱执行分句
+                Map<String, Object> map = new HashMap<>();
+                map.put("filePath", filePath);
+                map.put("taskId", po.getId());
+                result = HttpUtils.postJson(clauseUrl, map);
+                jsonObject = JSON.parseObject(result);
+                if (!StringUtils.equals("200", jsonObject.getString("code"))) {
+                    throw new ServiceException(jsonObject.getString("msg"));
+                }
+                break;
+            case "2":
+                updateStatus(po, kGraphTaskVo.getVersion(), GraphStatus.STATUS_3.getCode());
+                // 知识图谱抽取
+                KGraphClause kGraphClauseBo = new KGraphClause();
+                kGraphClauseBo.setTaskId(po.getId());
+                List<KGraphClause> graphClauseVos = kGraphClauseService.selectList(kGraphClauseBo);
+                extraGraphTaskVo.setTaskId(po.getId());
+                extraGraphTaskVo.setGraphClauseList(graphClauseVos);
+                result = HttpUtils.postJson(extractUrl, extraGraphTaskVo);
+                jsonObject = JSON.parseObject(result);
+                if (!StringUtils.equals("200", jsonObject.getString("code"))) {
+                    throw new ServiceException(jsonObject.getString("msg"));
+                }
+                kGraphClauseBo.setStatus(GraphStatus.STATUS_3.getCode());
+                kGraphClauseService.update(kGraphClauseBo);
+                break;
+            case "4":
+                updateStatus(po, kGraphTaskVo.getVersion(), GraphStatus.STATUS_5.getCode());
+                // 知识图谱入库
+                List<KGraphEntity> graphEntityVos = kGraphEntityService.selectListByTaskId(po.getId());
+                extraGraphTaskVo.setTaskId(po.getId());
+                extraGraphTaskVo.setOssId(ossId);
+                extraGraphTaskVo.setGraphEntityList(graphEntityVos);
+                result = HttpUtils.postJson(storageUrl, extraGraphTaskVo);
+                jsonObject = JSON.parseObject(result);
+                if (!StringUtils.equals("200", jsonObject.getString("code"))) {
+                    throw new ServiceException(jsonObject.getString("msg"));
+                }
+                break;
+            default:
+                throw new ServiceException("任务类型错误");
+        }
+        return true;
+    }
+
+    /**
+     * 修改任务状态
+     * @param po
+     * @param version
+     * @param status
+     */
+    private void updateStatus(KGraphTask po, Integer version, String status) {
+        po.setVersion(version);
+        this.update(po);
+    }
+
+    /**
+     * 修改任务信息状态
+     * @param po
+     */
+    @Override
+    public Boolean update(KGraphTask po){
+        if (ObjectUtils.isNotEmpty(po) && ObjectUtils.isNotEmpty(po.getId())){
+            kGraphTaskMapper.updateById(po);
+        }
+       return false;
+    }
+
+    @Override
+    public boolean deleteByIds(Long[] ids) {
+        int i = kGraphTaskMapper.deleteBatchIds(Arrays.asList(ids));
+        return i>1;
+    }
+
+    @Override
+    public boolean resultCallback(ExtraKGraphTaskDTO dto) {
+        if(ObjectUtils.isNotEmpty(dto.getGraphEntityList())){
+            KGraphTask kGraphTaskVo = this.selectById(dto.getTaskId());
+            KGraphTask kGraphTaskBo = new KGraphTask();
+            kGraphTaskBo.setId(dto.getTaskId());
+            kGraphTaskBo.setVersion(kGraphTaskVo.getVersion());
+            kGraphTaskBo.setStatus(StringUtils.equals(dto.getTaskType(), "1") ? GraphStatus.STATUS_2.getCode() : GraphStatus.STATUS_4.getCode());
+            return this.update(kGraphTaskBo);
+        }
+        if (StringUtils.equals(dto.getTaskType(), "1")) {
+            boolean isSave = kGraphClauseService.saveBatch(dto.getGraphClauseList());
+            if (!isSave) {
+                return false;
+            }
+
+        } else if (StringUtils.equals(dto.getTaskType(), "2")) {
+            boolean isSave = kGraphEntityService.saveBatch(dto.getGraphEntityList());
+            if (!isSave) {
+                return false;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean statusCallback(ExtraKGraphTaskStatusDTO extraKGraphTaskStatusDTO) {
+        KGraphTask kGraphTaskVo = this.selectById(extraKGraphTaskStatusDTO.getTaskId());
+        KGraphTask po = new KGraphTask();
+        po.setId(extraKGraphTaskStatusDTO.getTaskId());
+        po.setVersion(kGraphTaskVo.getVersion());
+        po.setStatus(extraKGraphTaskStatusDTO.getStatus());
+        return this.update(po);
+    }
+
+    public Object catai(CataiDTO dto) {
+        ReturnCatAiDTO returnCatAiDTO = new ReturnCatAiDTO();
+        if (ObjectUtils.isNotEmpty(dto)){
+            String returnData = HttpUtils.postJson(askUrl, dto);
+            JSONObject jsonObject = JSON.parseObject(returnData);
+            if(jsonObject.get("code").equals(200)){ // 假设code是数字类型
+                JSONObject data = jsonObject.getJSONObject("data");
+                if (data != null) {
+                    returnCatAiDTO.setUser_id(data.getString("user_id"));
+                    returnCatAiDTO.setAnswer(data.getString("answer"));
+                    returnCatAiDTO.setOssID(data.getString("ossID"));
+                    returnCatAiDTO.setFile_name(data.getString("file_name"));
+                    returnCatAiDTO.setGraph(data.getString("graph"));
+                }
+                return returnCatAiDTO;
+            } else {
+                throw new ServiceException(jsonObject.getString("msg"));
+            }
+        }
+        return false;
+    }
+}

+ 42 - 0
gm-base-ser/src/main/java/com/goomood/phm/service/impl/TechDataServiceImpl.java

@@ -2,16 +2,27 @@ package com.goomood.phm.service.impl;
 
 import java.io.IOException;
 import java.util.List;
+
+import com.goomood.common.constant.Constants;
 import com.goomood.common.utils.DateUtils;
 import com.goomood.common.utils.StringUtils;
+import com.goomood.common.utils.file.FileUtils;
 import com.goomood.es.service.FileService;
+import com.goomood.framework.config.ServerConfig;
 import com.goomood.phm.utils.PhmConstants;
+import com.goomood.web.controller.common.CommonController;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
 import org.springframework.stereotype.Service;
 import com.goomood.phm.mapper.TechDataMapper;
 import com.goomood.phm.domain.TechData;
 import com.goomood.phm.service.ITechDataService;
 
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+
+import static com.goomood.framework.datasource.DynamicDataSourceContextHolder.log;
+
 /**
  * 技术资料Service业务层处理
  * 
@@ -124,4 +135,35 @@ public class TechDataServiceImpl implements ITechDataService
 
         return techDataMapper.deleteTechDataById(id);
     }
+    @Resource
+    private ServerConfig serverConfig;
+    @Resource
+    private CommonController commonService;
+    @Override
+    public int downloadFile(Long oosId, HttpServletResponse response) {
+        TechData techData = this.selectTechDataById(oosId);
+//        String  filePath = serverConfig.getUrl() + techData.getFilePath();
+        commonService.fileDownload(techData.getFilePath(),false,response);
+        System.out.println(techData.getFilePath());
+        resourceDownload(techData.getFilePath(),response);
+        return 0;
+    }
+    public void resourceDownload(String resource, HttpServletResponse response) {
+        try {
+            if (!FileUtils.checkAllowDownload(resource)) {
+                throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", resource));
+            }
+//            // 本地资源路径
+//            String localPath = EcoConfig.getProfile();
+//            // 数据库资源地址
+//            String downloadPath = localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX);
+            // 下载名称
+            String downloadName = StringUtils.substringAfterLast(resource, "/");
+            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
+            FileUtils.setAttachmentResponseHeader(response, downloadName);
+            FileUtils.writeBytes(resource, response.getOutputStream());
+        } catch (Exception e) {
+            log.error("下载文件失败", e);
+        }
+    }
 }

+ 280 - 0
gm-base-ser/src/main/java/com/goomood/phm/utils/HttpUtils.java

@@ -0,0 +1,280 @@
+package com.goomood.phm.utils;
+
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.netty.channel.ChannelOption;
+import io.netty.handler.timeout.ReadTimeoutHandler;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.MediaType;
+import org.springframework.http.client.reactive.ClientHttpConnector;
+import org.springframework.http.client.reactive.ReactorClientHttpConnector;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.reactive.function.client.WebClient;
+import org.springframework.web.reactive.function.client.ClientResponse;
+import org.springframework.web.reactive.function.client.ExchangeStrategies;
+import reactor.core.publisher.Mono;
+import org.springframework.web.reactive.function.BodyInserters;
+import reactor.netty.http.client.HttpClient;
+import java.time.Duration;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @Description: HttpUtils
+ * @Author: GaoKun Wang
+ * @Date: 2024/7/30
+ */
+@Slf4j
+public class HttpUtils {
+    private static final Integer DEFAULT_CONNECT_TIMEOUT = 3000;
+
+    private static final Integer DEFAULT_REQUEST_TIMEOUT = 50000;
+
+    private static final Integer MAX_IN_MEMORY_SIZE = 100 * 1024 * 1024;
+
+    /**
+     * get请求解析成字符串
+     *
+     * @param url url
+     * @return java.lang.String
+     */
+    public static ClientResponse getResponse(String url) {
+        Mono<ClientResponse> resp = createWebClientWithConnectAndReadTimeOuts().get().uri(url).exchangeToMono(Mono::just);
+        return resp.block();
+    }
+
+    /**
+     * get请求,解析成对象
+     *
+     * @param url     url
+     * @param tClass  class
+     * @param headers 请求头
+     * @return T
+     */
+    public static <T> T get(String url, Class<T> tClass, Map<String, String> headers) {
+        Mono<T> resp = createWebClientWithConnectAndReadTimeOuts().get().uri(url).headers(t -> t.setAll(headers))
+            .retrieve().bodyToMono(tClass).timeout(Duration.ofMillis(DEFAULT_REQUEST_TIMEOUT));
+        return resp.block();
+    }
+
+    /**
+     * get请求,解析成对象
+     *
+     * @param url     url
+     * @param headers 请求头
+     * @return T
+     */
+    public static String get(String url, Map<String, String> headers) {
+        Mono<String> resp = createWebClientWithConnectAndReadTimeOuts().get().uri(url).headers(t -> t.setAll(headers))
+            .retrieve().bodyToMono(String.class).timeout(Duration.ofMillis(DEFAULT_REQUEST_TIMEOUT));
+        return resp.block();
+    }
+
+    /**
+     * get请求,解析成对象
+     *
+     * @param scheme  协议 http/https
+     * @param host    host
+     * @param obj     query params
+     * @param headers 请求头
+     * @return T
+     */
+    public static String get(String scheme, String host, String path, Object obj, Map<String, String> headers) {
+        Mono<String> resp = createWebClientWithConnectAndReadTimeOuts().get()
+            .uri(uriBuilder -> uriBuilder.scheme(scheme).host(host).path(path).queryParams(getRequestParamMapByObj(obj))
+                .build())
+            .headers(t -> t.setAll(headers)).retrieve().bodyToMono(String.class)
+            .timeout(Duration.ofMillis(DEFAULT_REQUEST_TIMEOUT));
+        return resp.block();
+    }
+
+    /**
+     * get请求,解析成对象
+     *
+     * @param url    url
+     * @param tClass class
+     * @return T
+     */
+    public static <T> T get(String url, Object obj, Class<T> tClass) {
+        Mono<T> resp = createWebClientWithConnectAndReadTimeOuts().get()
+            .uri(uriBuilder -> uriBuilder.path(url).queryParams(getRequestParamMapByObj(obj)).build()).retrieve()
+            .bodyToMono(tClass).timeout(Duration.ofMillis(DEFAULT_REQUEST_TIMEOUT));
+        return resp.block();
+    }
+
+    /**
+     * get请求,解析成对象
+     *
+     * @param url    url
+     * @param tClass class
+     * @return T
+     */
+    public static <T> T get(String url, Class<T> tClass) {
+        Mono<T> resp = createWebClientWithConnectAndReadTimeOuts().get().uri(url).retrieve().bodyToMono(tClass)
+            .timeout(Duration.ofMillis(DEFAULT_REQUEST_TIMEOUT));
+        return resp.block();
+    }
+
+    /**
+     * get请求解析成字符串
+     *
+     * @param url url
+     * @return java.lang.String
+     */
+    public static String get(String url) {
+        Mono<String> resp = createWebClientWithConnectAndReadTimeOuts().get().uri(url).retrieve()
+            .bodyToMono(String.class).timeout(Duration.ofMillis(DEFAULT_REQUEST_TIMEOUT));
+        return resp.block();
+    }
+
+    /**
+     * post表单请求返回对象
+     *
+     * @param url    url
+     * @param params 请求参数
+     * @param tClass 返回对象
+     * @return T
+     */
+    public static <T> T post(String url, Map<String, String> params, Class<T> tClass) {
+        MultiValueMap<String, String> formData = getRequestParamMap(params);
+        Mono<T> resp = createWebClientWithConnectAndReadTimeOuts().post().uri(url)
+            .contentType(MediaType.APPLICATION_FORM_URLENCODED).body(BodyInserters.fromFormData(formData)).retrieve()
+            .bodyToMono(tClass).timeout(Duration.ofMillis(DEFAULT_REQUEST_TIMEOUT));
+        return resp.block();
+    }
+
+    /**
+     * post表单请求返回字符串
+     *
+     * @param url    url
+     * @param params 请求参数
+     * @return java.lang.String
+     */
+    public static String post(String url, Map<String, String> params) {
+        MultiValueMap<String, String> formData = getRequestParamMap(params);
+        Mono<String> resp = createWebClientWithConnectAndReadTimeOuts().post().uri(url)
+            .contentType(MediaType.APPLICATION_FORM_URLENCODED).body(BodyInserters.fromFormData(formData)).retrieve()
+            .bodyToMono(String.class).timeout(Duration.ofMillis(DEFAULT_REQUEST_TIMEOUT));
+        return resp.block();
+    }
+
+    /**
+     * post json请求结果解析成对象
+     *
+     * @param url      url
+     * @param jsonBody 请求body,可以是对象或者是map
+     * @param tClass   解析对象
+     * @return T
+     */
+    public static <T> T postJson(String url, Object jsonBody, Class<T> tClass) {
+        Mono<T> resp = createWebClientWithConnectAndReadTimeOuts().post().uri(url)
+            .contentType(MediaType.APPLICATION_JSON).body(Mono.just(jsonBody), Object.class).retrieve()
+            .bodyToMono(tClass).timeout(Duration.ofMillis(DEFAULT_REQUEST_TIMEOUT));
+        return resp.block();
+    }
+
+    /**
+     * post json请求结果解析成对象
+     *
+     * @param url      url
+     * @param jsonBody 请求body,可以是对象或者是map
+     * @param tClass   解析对象
+     * @return T
+     */
+    public static <T> T postJson(String url, Map<String, String> headers, Object jsonBody, Class<T> tClass) {
+        Mono<T> resp =
+            createWebClientWithConnectAndReadTimeOuts().post().uri(url).contentType(MediaType.APPLICATION_JSON)
+                .headers(t -> t.setAll(headers)).body(Mono.just(jsonBody), Object.class).retrieve().bodyToMono(tClass)
+                .timeout(Duration.ofMillis(DEFAULT_REQUEST_TIMEOUT));
+        return resp.block();
+    }
+
+    /**
+     * post json请求结果解析成字符串
+     *
+     * @param url      url
+     * @param jsonBody 请求body,可以是对象或者是map
+     * @return java.lang.String
+     */
+    public static String postJson(String url, Object jsonBody) {
+        log.info("请求参数:{}", JSONObject.parseObject(JSON.toJSONString(jsonBody)));
+        Mono<String> resp = createWebClientWithConnectAndReadTimeOuts().post().uri(url)
+            .contentType(MediaType.APPLICATION_JSON).body(Mono.just(jsonBody), Object.class).retrieve()
+            .bodyToMono(String.class).timeout(Duration.ofMillis(DEFAULT_REQUEST_TIMEOUT));
+        return resp.block();
+    }
+
+    /**
+     * post json请求结果解析成字符串
+     *
+     * @param url      url
+     * @param jsonBody 请求body,可以是对象或者是map
+     * @return java.lang.String
+     */
+    public static String postJson(String url, Map<String, String> headers, Object jsonBody) {
+        Mono<String> resp =
+            createWebClientWithConnectAndReadTimeOuts().post().uri(url).contentType(MediaType.APPLICATION_JSON)
+                .headers(t -> t.setAll(headers)).body(Mono.just(jsonBody), Object.class).retrieve()
+                .bodyToMono(String.class).timeout(Duration.ofMillis(DEFAULT_REQUEST_TIMEOUT));
+        return resp.block();
+    }
+
+    public static <T> T postRawJson(String url, String jsonBody, Class<T> tClass) {
+        Mono<T> resp = createWebClientWithConnectAndReadTimeOuts().post().uri(url)
+            .contentType(MediaType.APPLICATION_JSON).body(BodyInserters.fromValue(jsonBody)).retrieve()
+            .bodyToMono(tClass).timeout(Duration.ofMillis(DEFAULT_REQUEST_TIMEOUT));
+
+        return resp.block();
+    }
+
+    public static String postRawJson(String url, String jsonBody) {
+        Mono<String> resp = createWebClientWithConnectAndReadTimeOuts().post().uri(url)
+            .contentType(MediaType.APPLICATION_JSON).body(BodyInserters.fromValue(jsonBody)).retrieve()
+            .bodyToMono(String.class).timeout(Duration.ofMillis(DEFAULT_REQUEST_TIMEOUT));
+
+        return resp.block();
+    }
+
+    private static WebClient createWebClientWithConnectAndReadTimeOuts() {
+        // 创建 reactor netty HTTP client
+        HttpClient httpClient = HttpClient.create().option(ChannelOption.CONNECT_TIMEOUT_MILLIS, DEFAULT_CONNECT_TIMEOUT).doOnConnected(connection ->
+            connection.addHandlerLast(new ReadTimeoutHandler(DEFAULT_REQUEST_TIMEOUT, TimeUnit.MILLISECONDS))
+        );
+        // 使用上述 HTTP 客户端创建客户端 HTTP 连接器
+        ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);
+        // 使用此配置的 HTTP 连接器构建 Web 客户端
+        return WebClient.builder()
+            .exchangeStrategies(ExchangeStrategies.builder()
+                .codecs(
+                    clientCodecConfigurer -> clientCodecConfigurer.defaultCodecs().maxInMemorySize(MAX_IN_MEMORY_SIZE))
+                .build())
+            .clientConnector(connector).build();
+    }
+
+    private static MultiValueMap<String, String> getRequestParamMap(Map<String, String> params) {
+        MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
+        for (Map.Entry<String, String> entry : params.entrySet()) {
+            queryParams.add(entry.getKey(), entry.getValue());
+        }
+        return queryParams;
+    }
+
+    private static MultiValueMap<String, String> getRequestParamMapByObj(Object obj) {
+        ObjectMapper objectMapper = new ObjectMapper();
+        Map<String, Object> map = objectMapper.convertValue(obj, new TypeReference<>() {
+        });
+        MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
+        for (Map.Entry<String, Object> entry : map.entrySet()) {
+            if (Objects.isNull(entry.getValue())) {
+                continue;
+            }
+            queryParams.add(entry.getKey(), String.valueOf(entry.getValue()));
+        }
+        return queryParams;
+    }
+}

+ 62 - 0
gm-base-ser/src/main/java/com/goomood/tableConfig/controller/UserTableConfigController.java

@@ -0,0 +1,62 @@
+package com.goomood.tableConfig.controller;
+
+
+import com.goomood.common.core.domain.AjaxResult;
+import com.goomood.tableConfig.domain.UserTableConfig;
+import com.goomood.tableConfig.service.IUserTableConfigService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import static com.goomood.common.core.domain.AjaxResult.success;
+
+/**
+ * 前端控制器
+ *
+ * @author zuoyou
+ * @since 2025-03-03
+ */
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/tableConfig/userTableConfig")
+public class UserTableConfigController {
+
+    private final IUserTableConfigService configService;
+
+    /**
+     * 获取用户配置
+     *
+     * @return
+     */
+    @PostMapping("getUserTableConfig")
+    public AjaxResult getUserTableConfig(@RequestBody UserTableConfig config) {
+        UserTableConfig userTableConfig = configService.getUserTableConfig(config);
+        return  success(userTableConfig);
+    }
+
+    /**
+     * 修改用户配置
+     *
+     * @param config
+     * @return
+     */
+    @PostMapping("save")
+    public AjaxResult save(@RequestBody UserTableConfig config) {
+        configService.saveUserTableConfig(config);
+        return success();
+    }
+
+    /**
+     * 初始化用户配置
+     *
+     * @param config
+     * @return
+     */
+    @PostMapping("initUserTableConfig")
+    public AjaxResult initUserTableConfig(@RequestBody UserTableConfig config) {
+        configService.initUserTableConfig(config);
+        return success();
+    }
+}

+ 55 - 0
gm-base-ser/src/main/java/com/goomood/tableConfig/domain/UserTableConfig.java

@@ -0,0 +1,55 @@
+package com.goomood.tableConfig.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 用户表格配置表
+ *
+ * @author zuoyou
+ * @since 2025-03-03
+ */
+@Getter
+@Setter
+@TableName("user_table_config")
+public class UserTableConfig implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @TableId(value = "id")
+    private String id;
+
+    /**
+     * 用户ID
+     */
+    @TableField(value = "user_id")
+    private String userId;
+
+    /**
+     * 表格名称
+     */
+    @TableField(value = "table_name")
+    private String tableName;
+
+    /**
+     * 列配置信息(JSON存储)
+     */
+    @TableField(value = "column_config")
+    private String columnConfig;
+
+    /**
+     * 更新时间
+     */
+    @TableField(value = "update_time")
+    private Date updateTime;
+}

+ 44 - 0
gm-base-ser/src/main/java/com/goomood/tableConfig/domain/dto/UserTableConfigDto.java

@@ -0,0 +1,44 @@
+package com.goomood.tableConfig.domain.dto;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @author zuoyou
+ * @since 2025-03-03
+ */
+
+@Getter
+@Setter
+public class UserTableConfigDto implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    private String id;
+
+    /**
+     * 用户ID
+     */
+    private String userId;
+
+    /**
+     * 表格名称
+     */
+    private String tableName;
+
+    /**
+     * 列配置信息(JSON存储)
+     */
+    private String columnConfig;
+
+    /**
+     * 更新时间
+     */
+    private Date updateTime;
+}

+ 46 - 0
gm-base-ser/src/main/java/com/goomood/tableConfig/domain/vo/UserTableConfigVo.java

@@ -0,0 +1,46 @@
+package com.goomood.tableConfig.domain.vo;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+*
+*
+* @author zuoyou
+* @since 2025-03-03
+*/
+
+@Getter
+@Setter
+public class UserTableConfigVo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 主键ID
+    */
+    private String id;
+
+    /**
+    * 用户ID
+    */
+    private String userId;
+
+    /**
+    * 表格名称
+    */
+    private String tableName;
+
+    /**
+    * 列配置信息(JSON存储)
+    */
+    private String columnConfig;
+
+    /**
+    * 更新时间
+    */
+    private Date updateTime;
+}

+ 17 - 0
gm-base-ser/src/main/java/com/goomood/tableConfig/mapper/UserTableConfigMapper.java

@@ -0,0 +1,17 @@
+package com.goomood.tableConfig.mapper;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.goomood.tableConfig.domain.UserTableConfig;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ *  Mapper 接口
+ *
+ * @author zuoyou
+ * @since 2025-03-03
+ */
+@Mapper
+public interface UserTableConfigMapper extends BaseMapper<UserTableConfig> {
+
+}

+ 33 - 0
gm-base-ser/src/main/java/com/goomood/tableConfig/service/IUserTableConfigService.java

@@ -0,0 +1,33 @@
+package com.goomood.tableConfig.service;
+
+import com.goomood.tableConfig.domain.UserTableConfig;
+
+/**
+ *  服务类
+ *
+ * @author zuoyou
+ * @since 2025-03-03
+ */
+public interface IUserTableConfigService {
+
+    /**
+     * 获取用户配置
+     * @param config
+     * @return
+     */
+    UserTableConfig getUserTableConfig(UserTableConfig config);
+
+    /**
+     * 获取用户配置
+     * @param config
+     * @return
+     */
+    void saveUserTableConfig(UserTableConfig config);
+
+    /**
+     * 初始化用户配置
+     * @param config
+     * @return
+     */
+    void initUserTableConfig(UserTableConfig config);
+}

+ 55 - 0
gm-base-ser/src/main/java/com/goomood/tableConfig/service/impl/UserTableConfigServiceImpl.java

@@ -0,0 +1,55 @@
+package com.goomood.tableConfig.service.impl;
+
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+
+import com.goomood.common.core.domain.model.LoginUser;
+import com.goomood.common.utils.SecurityUtils;
+import com.goomood.common.utils.StringUtils;
+import com.goomood.tableConfig.domain.UserTableConfig;
+import com.goomood.tableConfig.mapper.UserTableConfigMapper;
+import com.goomood.tableConfig.service.IUserTableConfigService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+/**
+ * 服务实现类
+ *
+ * @author zuoyou
+ * @since 2025-03-03
+ */
+@Service
+@RequiredArgsConstructor
+public class UserTableConfigServiceImpl implements IUserTableConfigService {
+    @Resource
+    private UserTableConfigMapper userTableConfigMapper;
+
+    @Override
+    public UserTableConfig getUserTableConfig(UserTableConfig config) {
+        String tableName = config.getTableName();
+        if (StringUtils.isEmpty(tableName)) {
+            throw new RuntimeException("表名不能为空!");
+        }
+        // 获取当前登录用户
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        config.setUserId(loginUser.getUserId().toString());
+        UserTableConfig userTableConfig = userTableConfigMapper.selectOne(Wrappers.lambdaQuery(UserTableConfig.class)
+                .eq(UserTableConfig::getUserId, config.getUserId())
+                .eq(UserTableConfig::getTableName, config.getTableName()));
+        return userTableConfig;
+    }
+
+    @Override
+    public void saveUserTableConfig(UserTableConfig config) {
+        userTableConfigMapper.insertOrUpdate(config);
+    }
+
+    @Override
+    public void initUserTableConfig(UserTableConfig config) {
+        UserTableConfig userTableConfig = this.getUserTableConfig(config);
+        if (userTableConfig != null) {
+            userTableConfigMapper.deleteById(userTableConfig.getId());
+        }
+    }
+}

+ 1 - 1
gm-base-ser/src/main/java/com/goomood/web/controller/common/CommonController.java

@@ -44,7 +44,7 @@ public class CommonController
      * @param delete 是否删除
      */
     @GetMapping("/download")
-    public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request)
+    public void fileDownload(String fileName, Boolean delete, HttpServletResponse response)
     {
         try
         {

+ 22 - 12
gm-base-ser/src/main/resources/application-druid.yml

@@ -3,23 +3,26 @@ spring:
     datasource:
         type: com.alibaba.druid.pool.DruidDataSource
         driverClassName: com.mysql.cj.jdbc.Driver
+        url: jdbc:mysql://8.152.223.50:3306/gdphm?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+        username: root
+        password: 54e8bd452af93c4c
         druid:
             # 主库数据源
             # 主库数据源
-            master:
+#            master:
 #                url: jdbc:mysql://localhost:3306/gdphm?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
 #                username: root
 #                password: 123456
-                url: jdbc:mysql://101.126.133.7:9006/gdphm?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
-                username: root
-                password: 404cf3eae29df38f
-            # 从库数据源
-            slave:
-                # 从数据源开关/默认关闭
-                enabled: false
-                url: 
-                username: 
-                password: 
+#                url: jdbc:mysql://localhost:3306/gdphm?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+#                username: root
+#                password: 123456
+#            # 从库数据源
+#            slave:
+#                # 从数据源开关/默认关闭
+#                enabled: false
+#                url:
+#                username:
+#                password:
             # 初始连接数
             initialSize: 5
             # 最小连接池数量
@@ -62,4 +65,11 @@ spring:
                     merge-sql: true
                 wall:
                     config:
-                        multi-statement-allow: true
+                        multi-statement-allow: true
+            default-auto-commit: true
+## 知识图谱
+kgqa:
+    ask-url: http://192.168.0.4:7074/kgqa/ask # kgqa问答接口
+    clause-url: http://192.168.0.4:7070/kgqa/split_sentence # kgqa分句接口
+    extract-url: http://192.168.0.4:7071/kgqa/extract # kgqa抽取接口
+    storage-url: http://192.168.0.4:7072/kgqa/storage # kgqa存储接口

+ 16 - 11
gm-base-ser/src/main/resources/application.yml

@@ -20,7 +20,7 @@ goomood:
 # 开发环境配置
 server:
   # 服务器的HTTP端口,默认为8080
-  port: 8080
+  port: 8085
   servlet:
     # 应用的访问路径
     context-path: /
@@ -75,7 +75,7 @@ spring:
   devtools:
     restart:
       # 热部署开关
-      enabled: true
+      enabled: false
   cache:
     # 指定缓存类型 ehcache 本地缓存 redis 缓存
     type: ehcache
@@ -99,20 +99,25 @@ token:
   expireTime: 30
 
 # MyBatis配置
-mybatis:
-  # 搜索指定包别名
-  typeAliasesPackage: com.goomood.**.domain
-  # 配置mapper的扫描,找到所有的mapper.xml映射文件
-  mapperLocations: classpath*:mapper/**/*Mapper.xml
-  # 加载全局的配置文件
-  configLocation: classpath:mybatis/mybatis-config.xml
-
+mybatis-plus:
+  mapper-locations: classpath*:mapper/**/*.xml
+  type-aliases-package: com.goomood.**.domain
+  global-config:
+    db-config:
+      update-strategy: not_null
+      logic-strategy: not_null
+  configuration:
+    # hump show
+    map-underscore-to-camel-case: true
+    # add sql log
+    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+    jdbc-type-for-null: null
+    cache-enabled: false
 # PageHelper分页插件
 pagehelper:
   helperDialect: mysql
   supportMethodsArguments: true
   params: count=countSql
-
 # Swagger配置
 swagger:
   # 是否开启swagger

+ 37 - 0
gm-base-ser/src/main/resources/mapper/KGraph/KGraphEntityMapper.xml

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.goomood.phm.mapper.KGraphEntityMapper">
+    <resultMap type="com.goomood.phm.domain.KGraphEntity" id="ResultDataModel">
+        <result property="id" column="id"/>
+        <result property="clauseId" column="clause_id"/>
+        <result property="headEntity" column="head_entity"/>
+        <result property="headEntityClass" column="head_entity_class"/>
+        <result property="relation" column="relation"/>
+        <result property="tailEntity" column="tail_entity"/>
+        <result property="tailEntity" column="tail_entity_class"/>
+        <result property="status" column="status"/>
+        <result property="remark" column="remark"/>
+        <result property="createBy" column="create_by"/>
+        <result property="createTime" column="create_time"/>
+        <result property="updateBy" column="update_by"/>
+        <result property="updateTime" column="update_time"/>
+    </resultMap>
+
+    <select id="selectListByTaskId" resultMap="ResultDataModel">
+        SELECT
+            e.head_entity,
+            e.head_entity_class,
+            e.relation,
+            e.tail_entity,
+            e.tail_entity_class
+        FROM
+            als_k_graph_entity_t e
+                JOIN
+            als_k_graph_clause_t c ON e.clause_id = c.id
+        WHERE
+            c.task_id = #{taskId}
+          AND c.status = 1
+    </select>
+</mapper>

+ 12 - 0
gm-base-ser/src/main/resources/mapper/fault/FaultMonitorAMapper.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.goomood.phm.mapper.FaultMonitorAMapper">
+
+    <!-- 根据日期范围查询故障记录 -->
+    <select id="findByIncidentDateBetween" resultType="com.goomood.phm.domain.FaultMonitorA">
+        SELECT * FROM fault_monitor
+        WHERE incident_date BETWEEN #{startDate} AND #{endDate}
+    </select>
+
+</mapper>    

+ 56 - 0
gm-base-ser/src/main/resources/mapper/fault/FaultMonitorMapper.xml

@@ -322,4 +322,60 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             status = #{status}
           AND incident_date >= DATE_SUB(CURDATE(), INTERVAL 3 MONTH)
     </select>
+
+
+
+
+    <!-- 查询近三年下月发生故障的部件统计 -->
+    <select id="getFaultyPartsNextMonthInThreeYears" resultType="map">
+        SELECT
+            faulty_part_name AS partName,
+            COUNT(*) AS faultCount
+        FROM
+            fault_monitor
+        WHERE
+            YEAR(incident_date) BETWEEN YEAR(CURRENT_DATE - INTERVAL 3 YEAR) AND YEAR(CURRENT_DATE)
+          AND MONTH(incident_date) = MONTH(CURRENT_DATE + INTERVAL 1 MONTH)
+          AND faulty_part_name IS NOT NULL
+        GROUP BY
+            faulty_part_name
+        ORDER BY
+            faultCount DESC
+            LIMIT 5
+    </select>
+
+    <!-- 查询近半年发生故障的部件统计 -->
+    <select id="getFaultyPartsInSixMonths" resultType="map">
+        SELECT
+            faulty_part_name AS partName,
+            COUNT(*) AS faultCount
+        FROM
+            fault_monitor
+        WHERE
+            incident_date >= DATE_SUB(CURRENT_DATE, INTERVAL 6 MONTH)
+          AND faulty_part_name IS NOT NULL
+        GROUP BY
+            faulty_part_name
+        ORDER BY
+            faultCount DESC
+            LIMIT 5
+    </select>
+
+    <!-- 统计特定月份的故障部件 (辅助查询) -->
+    <select id="countFaultyPartsByMonth" resultType="com.goomood.phm.domain.FaultMonitorA">
+        SELECT
+            faulty_part_name AS partName,
+            COUNT(*) AS faultCount
+        FROM
+            fault_monitor
+        WHERE
+            YEAR(incident_date) = #{year}
+          AND MONTH(incident_date) = #{month}
+          AND faulty_part_name IS NOT NULL
+        GROUP BY
+            faulty_part_name
+        ORDER BY
+            faultCount DESC
+    </select>
+    <select id="findByIncidentDateBetween" resultType="com.goomood.phm.domain.FaultMonitorA"></select>
 </mapper>

+ 12 - 0
gm-base-ser/src/main/resources/mapper/file/AlsAtlasFileTMapper.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.goomood.phm.mapper.AlsAtlasFileTMapper">
+    <resultMap type="com.goomood.phm.domain.AlsAtlasFileT" id="ResultDataModel">
+        <result property="remark" column="remark"/>
+        <result property="createTime" column="create_time"/>
+        <result property="updateBy" column="update_by"/>
+        <result property="updateTime" column="update_time"/>
+    </resultMap>
+</mapper>

+ 4 - 3
gm-common/pom.xml

@@ -40,13 +40,11 @@
             <groupId>com.github.pagehelper</groupId>
             <artifactId>pagehelper-spring-boot-starter</artifactId>
         </dependency>
-
         <!-- 自定义验证注解 -->
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-validation</artifactId>
         </dependency>
-
         <!--常用工具类 -->
         <dependency>
             <groupId>org.apache.commons</groupId>
@@ -58,7 +56,10 @@
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-databind</artifactId>
         </dependency>
-        
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+        </dependency>
         <!-- 动态数据源 -->
 		<dependency>
 			<groupId>com.baomidou</groupId>

+ 2 - 1
gm-common/src/main/java/com/goomood/common/utils/http/HttpUtils.java

@@ -132,13 +132,14 @@ public class HttpUtils
         try
         {
             log.info("sendPost - {}", url);
+            log.info("param==========={}", param);
             URL realUrl = new URL(url);
             URLConnection conn = realUrl.openConnection();
             conn.setRequestProperty("accept", "*/*");
             conn.setRequestProperty("connection", "Keep-Alive");
             conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
             conn.setRequestProperty("Accept-Charset", "utf-8");
-            conn.setRequestProperty("contentType", "utf-8");
+            conn.setRequestProperty("contentType", "application/json");
             conn.setDoOutput(true);
             conn.setDoInput(true);
             out = new PrintWriter(conn.getOutputStream());

+ 0 - 132
gm-framework/src/main/java/com/goomood/framework/config/MyBatisConfig.java

@@ -1,132 +0,0 @@
-package com.goomood.framework.config;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import javax.sql.DataSource;
-import org.apache.ibatis.io.VFS;
-import org.apache.ibatis.session.SqlSessionFactory;
-import org.mybatis.spring.SqlSessionFactoryBean;
-import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.core.env.Environment;
-import org.springframework.core.io.DefaultResourceLoader;
-import org.springframework.core.io.Resource;
-import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
-import org.springframework.core.io.support.ResourcePatternResolver;
-import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
-import org.springframework.core.type.classreading.MetadataReader;
-import org.springframework.core.type.classreading.MetadataReaderFactory;
-import org.springframework.util.ClassUtils;
-import com.goomood.common.utils.StringUtils;
-
-/**
- * Mybatis支持*匹配扫描包
- * 
- * @author goomood
- */
-@Configuration
-public class MyBatisConfig
-{
-    @Autowired
-    private Environment env;
-
-    static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
-
-    public static String setTypeAliasesPackage(String typeAliasesPackage)
-    {
-        ResourcePatternResolver resolver = (ResourcePatternResolver) new PathMatchingResourcePatternResolver();
-        MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver);
-        List<String> allResult = new ArrayList<String>();
-        try
-        {
-            for (String aliasesPackage : typeAliasesPackage.split(","))
-            {
-                List<String> result = new ArrayList<String>();
-                aliasesPackage = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
-                        + ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + "/" + DEFAULT_RESOURCE_PATTERN;
-                Resource[] resources = resolver.getResources(aliasesPackage);
-                if (resources != null && resources.length > 0)
-                {
-                    MetadataReader metadataReader = null;
-                    for (Resource resource : resources)
-                    {
-                        if (resource.isReadable())
-                        {
-                            metadataReader = metadataReaderFactory.getMetadataReader(resource);
-                            try
-                            {
-                                result.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage().getName());
-                            }
-                            catch (ClassNotFoundException e)
-                            {
-                                e.printStackTrace();
-                            }
-                        }
-                    }
-                }
-                if (result.size() > 0)
-                {
-                    HashSet<String> hashResult = new HashSet<String>(result);
-                    allResult.addAll(hashResult);
-                }
-            }
-            if (allResult.size() > 0)
-            {
-                typeAliasesPackage = String.join(",", (String[]) allResult.toArray(new String[0]));
-            }
-            else
-            {
-                throw new RuntimeException("mybatis typeAliasesPackage 路径扫描错误,参数typeAliasesPackage:" + typeAliasesPackage + "未找到任何包");
-            }
-        }
-        catch (IOException e)
-        {
-            e.printStackTrace();
-        }
-        return typeAliasesPackage;
-    }
-
-    public Resource[] resolveMapperLocations(String[] mapperLocations)
-    {
-        ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
-        List<Resource> resources = new ArrayList<Resource>();
-        if (mapperLocations != null)
-        {
-            for (String mapperLocation : mapperLocations)
-            {
-                try
-                {
-                    Resource[] mappers = resourceResolver.getResources(mapperLocation);
-                    resources.addAll(Arrays.asList(mappers));
-                }
-                catch (IOException e)
-                {
-                    // ignore
-                }
-            }
-        }
-        return resources.toArray(new Resource[resources.size()]);
-    }
-
-    @Bean
-    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception
-    {
-        String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage");
-        String mapperLocations = env.getProperty("mybatis.mapperLocations");
-        String configLocation = env.getProperty("mybatis.configLocation");
-        typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);
-        VFS.addImplClass(SpringBootVFS.class);
-
-        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
-        sessionFactory.setDataSource(dataSource);
-        sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
-        sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ",")));
-        sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
-        return sessionFactory.getObject();
-    }
-}

+ 1 - 1
gm-framework/src/main/java/com/goomood/framework/config/SecurityConfig.java

@@ -114,7 +114,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
                 .antMatchers("/login", "/register", "/captchaImage").permitAll()
                 // 静态资源,可匿名访问
                 .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
-                .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
+                .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**","/tech/techData/download","/als/kGraphTask/result/callback","/als/kGraphTask/status/callback").permitAll()
                 // 除上面外的所有请求全部需要鉴权认证
                 .anyRequest().authenticated()
                 .and()

+ 4 - 0
gm-system/pom.xml

@@ -22,6 +22,10 @@
             <groupId>com.goomood</groupId>
             <artifactId>gm-common</artifactId>
         </dependency>
+        <dependency>
+            <groupId>jakarta.validation</groupId>
+            <artifactId>jakarta.validation-api</artifactId>
+        </dependency>
 
     </dependencies>
 

+ 1 - 1
gm-web/.env.development

@@ -5,7 +5,7 @@ VUE_APP_TITLE = 飞机供电系统PHM软件
 ENV = 'development'
 
 # 管理系统/开发环境
-VUE_APP_BASE_API = 'http://localhost:8080'
+VUE_APP_BASE_API = 'http://localhost:8085'
 #VUE_APP_BASE_API = 'http://122.51.221.211:8080'
 # 路由懒加载
 VUE_CLI_BABEL_TRANSPILE_MODULES = true

+ 66 - 0
gm-web/src/api/als/ERManage.js

@@ -0,0 +1,66 @@
+import request from '@/utils/request'
+
+/**
+ * 查询所有三元组
+ * @param {Object} data - 请求参数
+ * @returns {Promise} - 返回请求Promise
+ */
+export function getERList(data) {
+  return request({
+    url: '/kgqa/relation/getAllTriples',
+    method: 'get',
+    data: data
+  })
+}
+
+/**
+ * 查询数据库中目前已经有的关系
+ * @param {Object} data - 请求参数
+ * @returns {Promise} - 返回请求Promise
+ */
+export function getAllRelationClass(data) {
+  return request({
+    url: '/kgqa/relation/getAllRelationClass',
+    method: 'get',
+    data: data
+  })
+}
+
+/**
+ * 新增关系
+ * @param {Object} data - 请求参数
+ * @returns {Promise} - 返回请求Promise
+ */
+export function addRelation(data) {
+  return request({
+    url: '/kgqa/relation/Add',
+    method: 'post',
+    data: data
+  })
+}
+
+/**
+ * 修改关系
+ * @param {Object} data - 请求参数
+ * @returns {Promise} - 返回请求Promise
+ */
+export function updateRelation(data) {
+  return request({
+    url: '/kgqa/relation/Update',
+    method: 'post',
+    data: data
+  })
+}
+
+/**
+ * 删除关系
+ * @param {Object} data - 请求参数
+ * @returns {Promise} - 返回请求Promise
+ */
+export function deleteRelation(data) {
+  return request({
+    url: '/kgqa/relation/Delete',
+    method: 'post',
+    data: data
+  })
+}

+ 45 - 0
gm-web/src/api/als/atlasFile.js

@@ -0,0 +1,45 @@
+import request from '@/utils/request'
+
+// 查询故障案例列表
+export function listFile(query) {
+  return request({
+    url: '/als/file/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询故障案例详细
+export function getFile(data) {
+  return request({
+    url: '/als/file/selectOne',
+    method: 'post',
+    data:data
+  })
+}
+
+// 新增故障案例
+export function addFile(data) {
+  return request({
+    url: '/als/file/add',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改故障案例
+export function updateFile(data) {
+  return request({
+    url: '/als/file/updata',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除故障案例
+export function delFile(id) {
+  return request({
+    url: '/als/file/delete' + id,
+    method: 'delete'
+  })
+}

+ 79 - 0
gm-web/src/api/als/entityManage.js

@@ -0,0 +1,79 @@
+import request from '@/utils/request'
+
+/**
+ * 查询所有实体
+ * @param {Object} data - 请求参数
+ * @returns {Promise} - 请求Promise对象
+ */
+export function getEntityList(data) {
+  return request({
+    url: '/kgqa/entity/getAllEntities',
+    method: 'get',
+    data: data
+  })
+}
+
+/**
+ * 获取图数据库中的所有实体类名称
+ * @param {Object} data - 请求参数(可选,若有参数可传入)
+ * @returns {Promise} - 请求Promise对象
+ */
+export function getAllEntityClass(data) {
+  return request({
+    url: '/kgqa/entity/getAllEntityClass',
+    method: 'get',
+    data: data // 保留data参数位,方便后续扩展传参
+  })
+}
+
+/**
+ * 新增实体结点
+ * @param {Object} data - 实体结点信息
+ * @returns {Promise} - 请求Promise对象
+ */
+export function addEntity(data) {
+  return request({
+    url: '/kgqa/entity/add',
+    method: 'post',
+    data: data
+  })
+}
+
+/**
+ * 修改实体结点
+ * @param {Object} data - 待修改的实体结点信息
+ * @returns {Promise} - 请求Promise对象
+ */
+export function updateEntity(data) {
+  return request({
+    url: '/kgqa/entity/update',
+    method: 'post',
+    data: data
+  })
+}
+
+/**
+ * 查询实体结点
+ * @param {Object} data - 查询条件参数
+ * @returns {Promise} - 请求Promise对象
+ */
+export function checkEntity(data) {
+  return request({
+    url: '/kgqa/entity/Check',
+    method: 'post',
+    data: data
+  })
+}
+
+/**
+ * 删除实体结点
+ * @param {Object} data - 包含删除条件的参数(如实体ID等)
+ * @returns {Promise} - 请求Promise对象
+ */
+export function deleteEntity(data) {
+  return request({
+    url: '/kgqa/entity/delete',
+    method: 'post',
+    data: data
+  })
+}

+ 201 - 0
gm-web/src/api/als/knowledgeExtraction.js

@@ -0,0 +1,201 @@
+import request from '@/utils/request'
+
+/**
+ * 查看抽取任务列表
+ * @param {Object} data - 请求参数
+ * @returns {Promise} - 返回请求Promise
+ */
+export function getTaskList(data) {
+  return request({
+    url: '/als/kGraphTask/list',
+    method: 'get',
+    data: data
+  })
+}
+
+/**
+ * 新增任务
+ * @param {Object} data - 请求参数
+ * @returns {Promise} - 返回请求Promise
+ */
+export function addTask(data) {
+  return request({
+    url: '/als/kGraphTask/add',
+    method: 'post',
+    data: data
+  })
+}
+
+/**
+ * 修改任务
+ * @param {Object} data - 请求参数
+ * @returns {Promise} - 返回请求Promise
+ */
+export function updateTask(data) {
+  return request({
+    url: '/als/kGraphTask/update',
+    method: 'put',
+    data: data
+  })
+}
+
+/**
+ * 删除任务
+ * @param {string|number} id - 任务ID
+ * @returns {Promise} - 返回请求Promise
+ */
+export function removeTask(id) {
+  return request({
+    url: `/als/kGraphTask/delete/${id}`,
+    method: 'delete'
+  })
+}
+
+/**
+ * 获取文件信息
+ * @param {string|number} id - 任务ID
+ * @returns {Promise} - 返回请求Promise
+ */
+export function getTaskInfo(id) {
+  return request({
+    url: `/als/kGraphTask/selectOne/${id}`,
+    method: 'get'
+  })
+}
+
+/**
+ * 执行知识图谱的类型
+ * @param {Object} data - 请求参数
+ * @returns {Promise} - 返回请求Promise
+ */
+export function taskPro(data) {
+  return request({
+    url: '/als/kGraphTask/pro',
+    method: 'post',
+    data: data
+  })
+}
+
+/**
+ * 获取分句列表
+ * @param {Object} data - 请求参数
+ * @returns {Promise} - 返回请求Promise
+ */
+export function getClauseList(data) {
+  return request({
+    url: '/als/kGraphClause/list',
+    method: 'get',
+    data: data
+  })
+}
+
+/**
+ * 获取分句详细信息
+ * @param {string|number} id - 分句ID
+ * @returns {Promise} - 返回请求Promise
+ */
+export function getClauseInfo(id) {
+  return request({
+    url: `/als/kGraphClause/selectOne/${id}`,
+    method: 'get'
+  })
+}
+
+/**
+ * 删除分句
+ * @param {string|number} id - 分句ID
+ * @returns {Promise} - 返回请求Promise
+ */
+export function removeClause(id) {
+  return request({
+    url: `/als/kGraphClause/delete/${id}`,
+    method: 'delete'
+  })
+}
+
+/**
+ * 修改分句
+ * @param {Object} data - 请求参数
+ * @returns {Promise} - 返回请求Promise
+ */
+export function updateClause(data) {
+  return request({
+    url: '/als/kGraphClause/update',
+    method: 'put',
+    data: data
+  })
+}
+
+/**
+ * 获取抽取列表
+ * @param {Object} data - 请求参数
+ * @returns {Promise} - 返回请求Promise
+ */
+export function getExtractList(data) {
+  return request({
+    url: '/als/kGraphEntity/list',
+    method: 'get',
+    data: data
+  })
+}
+
+/**
+ * 修改抽取结果
+ * @param {Object} data - 请求参数
+ * @returns {Promise} - 返回请求Promise
+ */
+export function updateExtractInfo(data) {
+  return request({
+    url: '/als/kGraphEntity/update',
+    method: 'put',
+    data: data
+  })
+}
+
+/**
+ * 删除抽取结果
+ * @param {string|number} id - 抽取结果ID
+ * @returns {Promise} - 返回请求Promise
+ */
+export function removeExtractInfo(id) {
+  return request({
+    url: `/als/kGraphEntity/selectOne/${id}`,
+    method: 'delete'
+  })
+}
+
+/**
+ * 新增实体关系
+ * @param {Object} data - 请求参数
+ * @returns {Promise} - 返回请求Promise
+ */
+export function addER(data) {
+  return request({
+    url: '/als/kGraphEntity/add',
+    method: 'post',
+    data: data
+  })
+}
+
+/**
+ * 获取图谱可视化
+ * @param {Object} data - 请求参数
+ * @returns {Promise} - 返回请求Promise
+ */
+export function getVisually(data) {
+  return request({
+    url: '/kgqa/ossId/show',
+    method: 'post',
+    data: data
+  })
+}
+
+
+// 获取专业
+export function aiforData(data) {
+  return request({
+    url: '/als/kGraphTask/catai',
+    method: 'post',
+    data: data
+  })
+}

+ 1 - 0
gm-web/src/api/chart/index.js

@@ -42,3 +42,4 @@ export function getSpecialties(query) {
     params: query
   })
 }
+

+ 7 - 1
gm-web/src/api/tech/techData.js

@@ -35,6 +35,13 @@ export function updateTechData(data) {
   })
 }
 
+// 删除技术资料
+export function download(id) {
+  return request({
+    url: '/tech/techData/download/' + id,
+    method: 'post'
+  })
+}
 // 删除技术资料
 export function delTechData(id) {
   return request({
@@ -42,7 +49,6 @@ export function delTechData(id) {
     method: 'delete'
   })
 }
-
 // 删除上传文件
 export function deleteFile(data) {
   return request({

BIN
gm-web/src/assets/logo.png


+ 30 - 0
gm-web/src/utils/enum-data.js

@@ -0,0 +1,30 @@
+import Vue from 'vue'
+
+// 证件类型 columns
+export const agloModelList = [
+  { key: '1', name: '去噪' },
+  { key: '2', name: '扩充' },
+  { key: '3', name: '补全' },
+  { key: '4', name: '虚警抑制' },
+  { key: '5', name: '故障诊断' },
+  { key: '6', name: '退化评估' }
+]
+
+// 抽取状态
+export const extractStatusss = [
+  { key: '0', name: '待分句', colorType: 'info-state' },
+  { key: '1', name: '分句中', colorType: 'info-state' },
+  { key: '2', name: '待抽取', colorType: 'warning-state' },
+  { key: '3', name: '抽取中', colorType: 'warning-state' },
+  { key: '4', name: '审核中', colorType: 'danger-state' },
+  { key: '5', name: '入库中', colorType: 'danger-state' },
+  { key: '6', name: '已入库', colorType: 'success-state' }
+]
+
+const enumData = {
+  agloModelList,
+  extractStatusss
+}
+
+// 第一种方法: 集体导出 并注入到全局变量
+window.enumData = Vue.prototype.$enumData = enumData

+ 505 - 0
gm-web/src/views/ChatComponent.vue

@@ -0,0 +1,505 @@
+<template>
+  <div class="chat-container">
+    <div class="chat-box" ref="chatBox">
+      <div v-for="(message, index) in messages" :key="index" :class="[
+          'chat-message',
+          message.isUser ? 'user-message' : 'incoming-message',
+        ]">
+        <div class="header-user" v-if="message.isUser">
+          <div class="avatar-wrapper" :class="message.isUser ? 'user-avatar' : ''">
+            <img src="@/assets/logo/logo.png" alt="avatar" class="avatar" />
+          </div>
+          <div class="user-name">用户</div>
+        </div>
+        <div class="header" v-else>
+          <div class="avatar-wrapper" :class="message.isUser ? 'user-avatar' : ''">
+            <img src="@/assets/logo/logo.png" alt="avatar" class="avatar" />
+          </div>
+          <div class="user-name">系统</div>
+        </div>
+        <div class="message-table" v-if="message.isTable">
+          <div v-if="message.isTable" class="message-table-box">
+            <div v-for="(device, index) in message.tableData" :key="index" v-if="message.tableData.length > 0">
+              <div class="flex-title">
+                <el-link class="name" title="点击下载文件" :underline="false" @click="downloadFile(device.fileUrl)">{{
+                    getFileNameBeforeLastUnderscore(device.fileName)
+                  }}</el-link>
+                <div>
+                  <el-link type="primary" class="link" :underline="false" @click="openFile(device.fileUrl)">预览&nbsp;
+                  </el-link>
+
+                  <el-link type="primary" class="link" style="margin-left:5px" :underline="false"
+                    @click="handleDetail(device)">详情</el-link>
+                </div>
+              </div>
+              <el-link type="primary" :underline="false" class="link">[{{
+                  device.belongType === "tech"? "技术资料" : device.belongType === "fault"? "故障记录": "故障案例"
+                }}]</el-link>
+              <div class="content" v-html="device.attachment.content"
+                :style="{ maxHeight: '60px', overflowY: 'hidden' }"></div>
+            </div>
+            <div v-if="message.tableData == null">无对应数据,请重新查询</div>
+          </div>
+          <div v-if="message.time" class="message-time">{{ message.time }}</div>
+        </div>
+        <div class="message-content" v-else>
+          <div class="message-text">
+            <span>{{ message.displayedText }}</span>
+          </div>
+          <div v-if="message.time" class="message-time">{{ message.time }}</div>
+        </div>
+      </div>
+    </div>
+
+    <div class="input-box">
+      <input type="text" v-model="inputMessage" @keyup.enter="sendMessage" placeholder="输入您的消息..." />
+      <el-button @click="sendMessage" :disabled="loading" class="send-btn">
+        <i class="el-icon-s-promotion"></i>发送
+      </el-button>
+    </div>
+    <TechDialog ref="techDialog" :showFlag="teachShowFlag" @close="handleDialogClose" :belongId="belongId" />
+    <FaultDialog :showFlag="faultShowFlag" @close="handleFaultClose" :belongId="belongId" />
+    <FaultCaseDialog :showFlag="caseShowFlag" @close="handleCaseClose" :belongId="belongId" />
+    <!-- 文件预览对话框 -->
+    <el-dialog title="文件预览" :visible.sync="open" width="70%" append-to-body :before-close="handleBeforeClose">
+      <div style="max-height: 70vh; overflow: auto ;">
+        <FilePreview :fileUrl="fileUrl" />
+      </div>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="cancel">关 闭</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { getSearchData, getWarning } from "@/api/search";
+import {
+  listFaultSetting,
+  getFaultSetting,
+  delFaultSetting,
+  addFaultSetting,
+  updateFaultSetting,
+} from "@/api/fault/faultSetting";
+
+import TechDialog from './comp/techDialog.vue'
+import FaultDialog from './comp/faultDialog.vue'
+import FaultCaseDialog from './comp/faultCaseDialog.vue'
+import FilePreview from "@/components/Preview/index.vue";
+
+export default {
+  name: 'ChatComponent',
+  components: {
+    TechDialog,
+    FaultDialog,
+    FaultCaseDialog,
+    FilePreview
+  },
+  data() {
+    return {
+      inputMessage: "",
+      messages: [], // 消息列表
+      teachShowFlag: false,
+      caseShowFlag: false,
+      recordShowFlag: false,
+      faultShowFlag: false,
+      belongId: '',
+      loading: false,
+      url: '',
+      open: false, // 是否显示预览弹窗
+      fileUrl: '' // 预览文件路径
+    };
+  },
+  created() {
+    // 可以通过props控制是否初始化时获取警告信息
+    if (this.autoLoadWarning) {
+      this.getWarning();
+    }
+  },
+  props: {
+    // 是否自动加载警告信息
+    autoLoadWarning: {
+      type: Boolean,
+      default: true
+    }
+  },
+  methods: {
+    getWarning() {
+      getFaultSetting(1).then((response) => {
+        var setting = response.data;
+        // 三月未处理故障
+        if (setting.threeMonthOpen == "true") {
+          var index = 0;
+          getWarning().then((response) => {
+            index = response.data;
+            if (index > 0) {
+              this.$notify({
+                title: "监控提示",
+                message: "有 " + index + " 条故障监控未处理,请及时处理!",
+                type: "warning",
+              });
+            }
+          });
+        }
+      });
+    },
+    handleDetail(device) {
+      this.belongId = device.belongId
+      if (device.belongType == "tech") {
+        this.teachShowFlag = true
+      } else if (device.belongType == 'case') {
+        this.caseShowFlag = true
+      } else {
+        this.faultShowFlag = true
+      }
+    },
+    handleDialogClose() {
+      this.teachShowFlag = false;
+    },
+    handleCaseClose() {
+      this.caseShowFlag = false;
+    },
+    handleFaultClose() {
+      this.faultShowFlag = false;
+    },
+    handleRecordDialogClose() {
+      this.recordShowFlag = false;
+    },
+    downloadFile(fileUrl) {
+      const baseUrl = process.env.VUE_APP_BASE_API;
+      const fullUrl = baseUrl + fileUrl;
+      this.createloadFile(fullUrl);
+    },
+    openFile(fileUrl) {
+      this.open = false; // 关闭弹窗
+      this.fileUrl = ""; // 清空旧的 fileUrl
+      this.$nextTick(() => {
+        const baseUrl = process.env.VUE_APP_BASE_API;
+        const fullUrl = new URL(fileUrl, baseUrl).toString(); // 合并URL
+        this.fileUrl = fullUrl; // 设置新的 fileUrl
+        this.open = true; // 打开弹窗
+        console.log("打开文件路径:", this.fileUrl);
+      });
+    },
+    handleBeforeClose(done) {
+      this.fileUrl = "";
+      this.open = false;
+    },
+    cancel() {
+      this.fileUrl = "";
+      this.open = false;
+    },
+    createloadFile(fileUrl) {
+      // 创建一个隐藏的 <a> 标签
+      fetch(fileUrl)
+        .then((response) => {
+          if (!response.ok) {
+            throw new Error("Network response was not ok");
+          }
+          return response.blob();
+        })
+        .then((blob) => {
+          const link = document.createElement("a");
+          link.href = URL.createObjectURL(blob);
+          link.download = decodeURIComponent(fileUrl.split("/").pop());
+          link.click();
+          URL.revokeObjectURL(link.href);
+        })
+        .catch((error) => {
+          console.error("文件下载失败:", error);
+        });
+    },
+    getFileNameBeforeLastUnderscore(fileName) {
+      const lastUnderscoreIndex = fileName.lastIndexOf("_");
+      if (lastUnderscoreIndex === -1) {
+        return fileName;
+      }
+      return fileName.slice(0, lastUnderscoreIndex);
+    },
+    // 获取设备信息并合并为一条表格消息
+    getList() {
+      this.loading = true;
+      const params = {
+        keyword: this.inputMessage,
+      };
+
+      getSearchData(params).then((response) => {
+        let deviceInfoList = response.data;
+
+        // 确保每个item都有attachment和content字段
+        deviceInfoList.forEach(item => {
+          if (!item.hasOwnProperty('attachment')) {
+            item.attachment = {};
+          }
+          if (!item.attachment.hasOwnProperty('content')) {
+            item.attachment.content = '该文件是空文件';
+          }
+        });
+
+        this.inputMessage = "";
+
+        // 构造表格数据的消息对象
+        const tableMessage = {
+          isUser: false,
+          isTable: true,
+          tableData: this.textLines(deviceInfoList),
+          time: new Date().toLocaleTimeString(),
+        };
+        this.loading = false;
+
+        // 将表格消息添加到消息列表
+        this.messages.push(tableMessage);
+        this.scrollToBottom();
+      }).catch(() => {
+        const tableMessage = {
+          isUser: false,
+          isTable: true,
+          tableData: this.textLines([]),
+          time: new Date().toLocaleTimeString(),
+        };
+        this.messages.push(tableMessage);
+        this.loading = false;
+      });
+    },
+    textLines(dataArray) {
+      if (dataArray == "") {
+        return [];
+      } else {
+        return dataArray.map((item) => {
+          if (item.attachment && item.attachment.content) {
+            // 替换换行符为<br>标签
+            item.attachment.content = item.attachment.content.replace(
+              /\r?\n/g,
+              "<br>"
+            );
+          }
+          return item;
+        });
+      }
+    },
+    // 发送消息
+    sendMessage() {
+      if (this.inputMessage.trim() !== "") {
+        const currentTime = new Date().toLocaleTimeString();
+
+        // 添加用户消息
+        this.messages.push({
+          text: this.inputMessage,
+          isUser: true,
+          time: currentTime,
+          displayedText: this.inputMessage,
+        });
+
+        this.scrollToBottom();
+
+        // 调用getList获取并展示设备信息
+        this.getList();
+      }
+    },
+    // 滚动到底部
+    scrollToBottom() {
+      this.$nextTick(() => {
+        const chatBox = this.$refs.chatBox;
+        chatBox.scrollTop = chatBox.scrollHeight;
+      });
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.chat-container {
+  width: 100%;
+  height: 100%;
+  margin: 0;
+  padding: 0;
+  display: flex;
+  flex-direction: column;
+  position: relative;
+  font-family: Arial, sans-serif;
+}
+
+.chat-box {
+  flex: 1;
+  overflow-y: auto;
+  padding: 20px;
+  background-color: #ffffff;
+  display: flex;
+  flex-direction: column;
+  margin-bottom: 100px;
+  border-radius: 10px;
+}
+
+.chat-message {
+  margin-bottom: 20px;
+  display: flex;
+  max-width: 70%;
+  flex-direction: column;
+}
+
+.user-message {
+  align-self: flex-end;
+  flex-direction: column;
+}
+
+.incoming-message {
+  align-self: flex-start;
+}
+
+.avatar-wrapper {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 40px;
+  height: 40px;
+  border-radius: 50%;
+  background: linear-gradient(135deg,
+      #f09433,
+      #e6683c,
+      #dc2743,
+      #cc2366,
+      #bc1888,
+      #e1306c);
+  padding: 3px;
+  margin-bottom: 5px;
+}
+
+.user-avatar {
+  align-self: flex-end;
+  margin-right: 0;
+  margin-top: 5px;
+}
+
+.avatar {
+  width: 36px;
+  height: 36px;
+  border-radius: 50%;
+  background-color: #fff;
+}
+
+.message-content {
+  background-color: #e0e0e0;
+  padding: 12px;
+  border-radius: 12px;
+  max-width: 100%;
+  word-wrap: break-word;
+  position: relative;
+  margin-top: 5px;
+}
+
+.user-message .message-content {
+  background-color: #007bff;
+  color: white;
+}
+
+.message-time {
+  font-size: 12px;
+  color: #aaa;
+  margin-top: 5px;
+  text-align: right;
+}
+
+.message-table {
+  margin-top: 5px;
+  background: #fff;
+  border: 3px solid #f1efef;
+  border-radius: 12px;
+  padding: 24px;
+  background: #f0f0f0;
+
+  .message-table-box>div {
+    background: #fff;
+    margin-bottom: 24px;
+    padding: 12px 24px;
+    overflow: hidden;
+
+    .name {
+      margin-bottom: 6px;
+      font-size: 18px;
+    }
+
+    .link {
+      margin-bottom: 10px;
+      font-size: 14px;
+    }
+
+    .content {
+      font-size: 12px;
+      color: #868585;
+    }
+  }
+}
+
+.input-box {
+  position: fixed;
+  bottom: 3%;
+  left: 55%;
+  transform: translateX(-50%);
+  width: 60%;
+  display: flex;
+  align-items: center;
+  padding: 30px;
+  height: 100px;
+  background-color: #ffffff;
+  box-shadow: 0 -2px 15px rgba(0, 0, 0, 0.1);
+  border-radius: 30px;
+}
+
+input[type="text"] {
+  flex: 1;
+  padding: 12px;
+  font-size: 14px;
+  border: none;
+  border-radius: 20px;
+  margin-right: 10px;
+  background-color: #f0f0f0;
+}
+
+.send-btn {
+  padding: 10px;
+  background-color: #007bff;
+  color: white;
+  border: none;
+  border-radius: 15%;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.send-btn:hover {
+  background-color: #0056b3;
+}
+
+.header {
+  display: flex;
+  align-items: center;
+
+  .user-name {
+    margin-left: 10px;
+    font-size: 14px;
+    color: #313131;
+  }
+}
+
+.header-user {
+  display: flex;
+  align-items: center;
+
+  .user-name {
+    margin-left: 10px;
+    font-size: 14px;
+    color: #313131;
+  }
+}
+
+.flex-title {
+  display: flex;
+  justify-content: space-between;
+}
+
+.dialog-footer {
+  display: flex;
+  justify-content: flex-end;
+}
+</style>

+ 324 - 0
gm-web/src/views/chat/catAi.vue

@@ -0,0 +1,324 @@
+<template>
+  <div class="chat-container">
+    <div class="chat-box" ref="chatBox">
+      <!-- 消息列表 -->
+      <div v-for="(message, index) in messages" :key="index" :class="[
+          'chat-message',
+          message.isUser ? 'user-message' : 'incoming-message',
+        ]">
+        <!-- 用户消息头部 -->
+        <div class="header-user" v-if="message.isUser">
+          <div class="avatar-wrapper user-avatar">
+            <img src="@/assets/logo/logo.png" alt="用户头像" class="avatar" />
+          </div>
+          <div class="user-name">用户</div>
+        </div>
+
+        <!-- 系统消息头部 -->
+        <div class="header" v-else>
+          <div class="avatar-wrapper">
+            <img src="@/assets/logo/logo.png" alt="系统头像" class="avatar" />
+          </div>
+          <div class="user-name">系统</div>
+        </div>
+
+        <!-- 普通文本消息内容 -->
+        <div class="message-content">
+          <div class="message-text">
+            <span>{{ message.displayedText }}</span>
+          </div>
+          <div v-if="message.time" class="message-time">{{ message.time }}</div>
+        </div>
+      </div>
+    </div>
+
+    <!-- 输入区域 -->
+    <div class="input-box">
+      <input
+        type="text"
+        v-model="inputMessage"
+        @keyup.enter="sendMessage"
+        placeholder="输入您的消息..."
+        :disabled="loading"
+      />
+      <el-button @click="sendMessage" :disabled="loading" class="send-btn">
+        <i class="el-icon-s-promotion"></i>发送
+      </el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+// 导入接口请求工具
+import { aiforData } from "@/api/als/knowledgeExtraction"; // 需自行创建此接口文件
+
+export default {
+  name: 'ChatAssistant',
+  components: {
+    // 保持组件结构一致,如需文件预览等功能可在此导入
+  },
+  data() {
+    return {
+      inputMessage: "",       // 输入框内容
+      messages: [],           // 消息列表
+      loading: false,         // 加载状态
+      userId: "admin"         // 用户ID,可根据实际情况从登录信息获取
+    };
+  },
+  methods: {
+    /**
+     * 发送消息
+     */
+    sendMessage() {
+      // 验证输入内容
+      if (this.inputMessage.trim() === "" || this.loading) {
+        return;
+      }
+
+      const currentTime = this.formatTime(new Date());
+
+      // 添加用户消息到列表
+      this.messages.push({
+        isUser: true,
+        displayedText: this.inputMessage.trim(),
+        time: currentTime
+      });
+
+      // 清空输入框并滚动到底部
+      this.inputMessage = "";
+      this.scrollToBottom();
+
+      // 调用接口获取回复
+      this.getAssistantReply();
+    },
+
+    /**
+     * 调用接口获取助手回复
+     */
+    getAssistantReply() {
+      this.loading = true;
+
+      // 构造请求参数
+      const params = {
+        question: this.messages[this.messages.length - 1].displayedText,
+        userId: this.userId
+      };
+
+      // 调用聊天接口
+      aiforData(params)
+        .then(response => {
+          // 处理接口返回
+          if (response.code === 200 && response.data) {
+            this.addSystemMessage(response.data.answer);
+          } else {
+            this.addSystemMessage("抱歉,未能获取到有效回复,请稍后再试");
+          }
+        })
+        .catch(error => {
+          console.error("请求失败:", error);
+          this.addSystemMessage("请求失败,请检查网络连接");
+        })
+        .finally(() => {
+          this.loading = false;
+        });
+    },
+
+    /**
+     * 添加系统回复消息
+     * @param {string} content - 回复内容
+     */
+    addSystemMessage(content) {
+      const currentTime = this.formatTime(new Date());
+
+      this.messages.push({
+        isUser: false,
+        displayedText: content,
+        time: currentTime
+      });
+
+      this.scrollToBottom();
+    },
+
+    /**
+     * 滚动到最新消息位置
+     */
+    scrollToBottom() {
+      this.$nextTick(() => {
+        const chatBox = this.$refs.chatBox;
+        if (chatBox) {
+          chatBox.scrollTop = chatBox.scrollHeight;
+        }
+      });
+    },
+
+    /**
+     * 格式化时间显示
+     * @param {Date} date - 日期对象
+     * @returns {string} 格式化后的时间字符串
+     */
+    formatTime(date) {
+      return date.toLocaleTimeString([], {
+        hour: '2-digit',
+        minute: '2-digit',
+        second: '2-digit'
+      });
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+/* 保持原有样式不变,确保视觉一致性 */
+.chat-container {
+  width: 100%;
+  height: 100%;
+  margin: 0;
+  padding: 0;
+  display: flex;
+  flex-direction: column;
+  position: relative;
+  font-family: Arial, sans-serif;
+}
+
+.chat-box {
+  flex: 1;
+  overflow-y: auto;
+  padding: 20px;
+  background-color: #ffffff;
+  display: flex;
+  flex-direction: column;
+  margin-bottom: 100px;
+  border-radius: 10px;
+}
+
+.chat-message {
+  margin-bottom: 20px;
+  display: flex;
+  max-width: 70%;
+  flex-direction: column;
+}
+
+.user-message {
+  align-self: flex-end;
+  flex-direction: column;
+}
+
+.incoming-message {
+  align-self: flex-start;
+}
+
+.avatar-wrapper {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 40px;
+  height: 40px;
+  border-radius: 50%;
+  background: linear-gradient(135deg,
+    #f09433,
+    #e6683c,
+    #dc2743,
+    #cc2366,
+    #bc1888,
+    #e1306c);
+  padding: 3px;
+  margin-bottom: 5px;
+}
+
+.user-avatar {
+  align-self: flex-end;
+  margin-right: 0;
+  margin-top: 5px;
+}
+
+.avatar {
+  width: 36px;
+  height: 36px;
+  border-radius: 50%;
+  background-color: #fff;
+}
+
+.message-content {
+  background-color: #e0e0e0;
+  padding: 12px;
+  border-radius: 12px;
+  max-width: 100%;
+  word-wrap: break-word;
+  position: relative;
+  margin-top: 5px;
+}
+
+.user-message .message-content {
+  background-color: #007bff;
+  color: white;
+}
+
+.message-time {
+  font-size: 12px;
+  color: #aaa;
+  margin-top: 5px;
+  text-align: right;
+}
+
+.input-box {
+  position: fixed;
+  bottom: 3%;
+  left: 50%;
+  transform: translateX(-50%);
+  width: 60%;
+  display: flex;
+  align-items: center;
+  padding: 30px;
+  height: 100px;
+  background-color: #ffffff;
+  box-shadow: 0 -2px 15px rgba(0, 0, 0, 0.1);
+  border-radius: 30px;
+}
+
+input[type="text"] {
+  flex: 1;
+  padding: 12px;
+  font-size: 14px;
+  border: none;
+  border-radius: 20px;
+  margin-right: 10px;
+  background-color: #f0f0f0;
+}
+
+input[type="text"]:disabled {
+  background-color: #f5f5f5;
+  cursor: not-allowed;
+}
+
+.send-btn {
+  padding: 10px;
+  background-color: #007bff;
+  color: white;
+  border: none;
+  border-radius: 15%;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.send-btn:hover:not(:disabled) {
+  background-color: #0056b3;
+}
+
+.send-btn:disabled {
+  background-color: #cccccc;
+  cursor: not-allowed;
+}
+
+.header, .header-user {
+  display: flex;
+  align-items: center;
+
+  .user-name {
+    margin-left: 10px;
+    font-size: 14px;
+    color: #313131;
+  }
+}
+</style>

+ 114 - 0
gm-web/src/views/components/Charts/graph.vue

@@ -0,0 +1,114 @@
+<template>
+  <div ref="chart" class="chart" :style="{ width: width + 'px', height: height + 'px' }"></div>
+</template>
+
+<script>
+import * as echarts from 'echarts'
+
+export default {
+  name: 'Graph',
+  props: {
+    // 图表宽度
+    width: {
+      type: Number,
+      default: 600
+    },
+    // 图表高度
+    height: {
+      type: Number,
+      default: 300
+    },
+    // 关系图数据
+    graphData: {
+      type: Object,
+      required: true
+    }
+  },
+  data() {
+    return {
+      chartInstance: null
+    }
+  },
+  watch: {
+    graphData: {
+      handler(newVal) {
+        if (this.chartInstance) {
+          this.setOptions()
+        }
+      },
+      deep: true
+    }
+  },
+  mounted() {
+    this.initChart()
+  },
+  beforeDestroy() {
+    if (this.chartInstance) {
+      this.chartInstance.dispose()
+    }
+  },
+  methods: {
+    initChart() {
+      this.chartInstance = echarts.init(this.$refs.chart)
+      this.setOptions()
+    },
+    setOptions() {
+      const options = {
+        title: {},
+        tooltip: {},
+        legend: {},
+        animationDurationUpdate: 1500,
+        animationEasingUpdate: 'quinticInOut',
+        series: [
+          {
+            type: 'graph',
+            layout: 'force',
+            // 设置节点符号为矩形
+            // symbol: 'rect',
+            // symbolSize: (value) => {
+            //   if (!value || !value.name) {
+            //     return [80, 30] // 返回默认大小
+            //   }
+            //   // 根据节点名称长度或其他属性来确定大小
+            //   const textSize = value.name.length * 10 // 假设每增加一个字符宽度增加10px
+            //   return [textSize, 30]
+            // },
+            symbolSize: 50,
+            roam: true,
+            draggable: true,
+            label: {
+              show: true
+            },
+            edgeSymbol: ['circle', 'arrow'],
+            edgeSymbolSize: [4, 10],
+            edgeLabel: {
+              show: true,
+              formatter: '{c}',
+              position: 'middle',
+              fontSize: 14,
+              color: '#333'
+            },
+            // edgeLabel: {
+            //   fontSize: 20
+            // },
+            data: this.graphData.data,
+            links: this.graphData.links,
+            categories: this.graphData.categories,
+            force: {
+              repulsion: 1500
+            }
+          }
+        ]
+      }
+      this.chartInstance.setOption(options)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.chart {
+  background-color: aliceblue;
+  border-radius: 10px;
+}
+</style>

+ 24 - 0
gm-web/src/views/components/LTable/index.scss

@@ -0,0 +1,24 @@
+.w-img {
+  box-sizing: border-box;
+  border: 1px solid #fff;
+  border-radius: 8px;
+  width: 64px;
+  height: 64px;
+  margin: 10px 0;
+}
+
+::v-deep .el-table__cell .el-input__inner {
+  height: 23px !important;
+}
+::v-deep .el-table__cell .el-input {
+  width: 80%;
+}
+
+.el-table-edit-text i {
+  margin-right: 10px;
+  color: #34d9ff;
+}
+
+.el-table-edit-text {
+  cursor: pointer;
+}

+ 706 - 0
gm-web/src/views/components/LTable/index.vue

@@ -0,0 +1,706 @@
+<template>
+  <div class="table-page">
+    <!-- 添加列设置按钮 -->
+    <div class="table-settings" v-if="showColumnSetting">
+      <el-button type="text" @click="showColumnSettings"> <i class="el-icon-setting"></i> 列设置 </el-button>
+    </div>
+
+    <el-table
+      :key="renderKey"
+      ref="elTablet"
+      :row-key="getRowKey"
+      v-loading="options.loading"
+      :data="dataSource"
+      :max-height="options.maxHeight"
+      :height="options.height"
+      :stripe="options.stripe"
+      :border="options.border"
+      @select="handleSelect"
+      @select-all="selectAll"
+      @row-click="handleRowClick"
+      @selection-change="handleSelectionChange"
+      @current-change="handleCurrentChange"
+      @header-dragend="handleHeaderDragend"
+      highlight-current-row
+      default-expand-all
+      :cell-style="cellStyle"
+      :header-cell-style="{ color: '#515a6e', background: '#f5f5f5' }"
+      :tree-props="options.treeProps"
+      :row-style="{ cursor: options.cursor || '' }"
+      :resizable="true"
+      :fit="true"
+    >
+      <!--selection选择框-->
+      <el-table-column v-if="options.mutiSelect" type="selection" :reserve-selection="true" style="width: 50px" align="center"> </el-table-column>
+      <!--序号-->
+      <el-table-column v-if="options.index" label="序号" type="index" width="100" align="center"> </el-table-column>
+      <!--数据列-->
+      <template v-for="(column, index) in localTableColumns">
+        <el-table-column :key="index" :prop="column.prop" :label="column.label" :align="column.align || 'center'" :width="column.width" :fixed="column.fixed" show-overflow-tooltip v-if="!column.isHidden">
+          <template slot-scope="scope">
+            <!--  含有click函数 -->
+            <template v-if="column.onClick && !column.edit">
+              <span @click.stop="column.onClick(scope.row, scope.$index, scope)">{{ scope.row[column.prop] }}</span>
+            </template>
+
+            <!-- 带编辑功能列 -->
+            <template v-else-if="column.edit">
+              <!-- 编辑状态 -->
+              <template v-if="scope.row[scope.column.property + 'isShow']">
+                <el-input :ref="scope.column.property" @blur="handleEditBlur(column, scope)" v-model="scope.row[column.prop]"></el-input>
+              </template>
+
+              <!-- 非编辑状态  -->
+              <template v-else>
+                <span class="el-table-edit-text" @click="editCell(scope.row, scope.column)"><i class="el-icon-edit"></i>{{ scope.row[column.prop] }}</span>
+              </template>
+            </template>
+
+            <!-- 含有render函数 -->
+            <template v-else-if="column.render">
+              <RenderDom :row="scope.row" :index="index" :render="column.render" />
+            </template>
+
+            <!-- 有img图片显示 -->
+            <template v-else-if="column.img">
+              <img v-if="scope.row[column.prop] && scope.row[column.prop].length > 0" :src="scope.row[column.prop][0]" class="w-img" alt="加载失败" />
+              <img v-else :src="logo" class="w-img" alt="加载失败" />
+            </template>
+
+            <!-- 字典展示 -->
+            <template v-else-if="column.dictData">
+              <span>{{ scope.row[column.prop] | dictFind(dictData, column.dictData, column.dictLabel, column.dictValue) }}</span>
+            </template>
+
+            <!-- 没有render函数且没有图片要显示 -->
+            <template v-else>
+              <span>{{ scope.row[column.prop] }}</span>
+            </template>
+            <!-- button 操作按钮  btn.statusKey 判断启用的字段 | btn.disableKey 判断禁用的值 | disableKey在启用和禁用时相反-->
+            <!-- 禁用分两种情况   一种是 disableKey  disableKey 是指状态值是 disableKey 的时候禁用 -->
+            <!-- 另一种是 unDisableKey  unDisableKey 是指状态值不是 unDisableKey 的时候禁用 -->
+            <!-- btn.isChildShow 控制子级是否显示,isParentShow控制父级是否显示  -->
+            <!--  v-show="hasChildren(scope.row, btn.showType)" -->
+            <template v-if="column.button">
+              <template v-for="(btn, i) in column.group">
+                <el-button
+                  v-show="hasChildren(scope.row, btn.showType)"
+                  v-if="btn.statusKey"
+                  :key="i"
+                  :type="btn.type"
+                  :round="btn.round"
+                  :size="btn.size || 'mini'"
+                  :icon="btn.icon"
+                  :plain="btn.plain"
+                  @click.stop="btn.onClick(scope.row, scope.$index, scope)"
+                  :disabled="unDisabled(scope.row[btn.statusKey], btn.unDisableKey, btn.disableKey)"
+                  >{{ btn.name }}</el-button
+                >
+                <el-button
+                  v-show="hasChildren(scope.row, btn.showType)"
+                  v-if="!btn.statusKey"
+                  :key="i"
+                  :type="btn.type"
+                  :round="btn.round"
+                  :size="btn.size || 'mini'"
+                  :icon="btn.icon"
+                  :plain="btn.plain"
+                  @click.stop="btn.onClick(scope.row, scope.$index, scope)"
+                  :disabled="btn.isDisabled"
+                  >{{ btn.name }}</el-button
+                >
+              </template>
+            </template>
+
+            <!-- slot 你可以其他常用项 -->
+          </template>
+        </el-table-column>
+      </template>
+    </el-table>
+
+    <!-- 分页 -->
+    <el-pagination
+      v-if="pagination"
+      background
+      :total="pagination.total"
+      :page-size="pagination.pageSize"
+      :page-sizes="[10, 20, 30, 40, 50]"
+      layout="sizes,total, prev, pager, next, jumper"
+      @size-change="handleSizeChange"
+      @current-change="handleIndexChange"
+      style="padding: 20px; text-align: center"
+    ></el-pagination>
+
+    <!-- 添加列设置弹窗 -->
+    <el-dialog v-if="showColumnSetting" title="列设置" :visible.sync="columnSettingsVisible" width="500px">
+      <div class="dialog-header">
+        <el-checkbox v-model="showAllColumns" @change="toggleAllColumns">全选</el-checkbox>
+        <el-button type="text" @click="handleInitConfig">初始化配置</el-button>
+      </div>
+      <el-divider></el-divider>
+      <draggable v-model="localColumns" handle=".drag-handle" @end="handleDragEnd">
+        <div v-for="(col, index) in localColumns" :key="index" class="column-item">
+          <i class="el-icon-rank drag-handle"></i>
+          <el-checkbox v-model="col.isShow" @change="handleColumnChange">
+            {{ col.label }}
+          </el-checkbox>
+        </div>
+      </draggable>
+      <span slot="footer">
+        <el-button @click="columnSettingsVisible = false">取消</el-button>
+        <el-button type="primary" @click="saveColumnSettings">确定</el-button>
+      </span>
+    </el-dialog>
+  </div>
+</template>
+<script>
+import { deepClone } from '@/utils'
+import draggable from 'vuedraggable'
+import request from '@/utils/request'
+
+export default {
+  name: 'LTable',
+  components: {
+    RenderDom: {
+      functional: true,
+      props: {
+        row: Object,
+        render: Function,
+        index: Number,
+        column: {
+          type: Object,
+          default: null
+        }
+      },
+
+      render: (h, data) => {
+        const params = {
+          row: data.props.row,
+          index: data.props.index
+        }
+
+        if (data.props.column) params.column = data.props.column
+        return data.props.render(h, params)
+      }
+    },
+    draggable
+  },
+  props: {
+    dictData: Object, //字典对象
+    dataSource: Array, // table内容数据
+    options: Object, // 表格参数控制 maxHeight、stripe 等等...
+    columns: Array, // 表头
+    fetch: {
+      type: Function,
+      default: function () {}
+    }, // 获取数据的函数
+    pagination: Object, // 分页,不传则不显示
+    typeTable: String,
+    defaultFetch: {
+      type: Boolean,
+      default: true
+    },
+    RowKey: {
+      type: String,
+      default: 'id'
+    },
+    tableId: {
+      // 表格唯一标识,用于保存和获取表格配置,为空时使用当前组件路径
+      type: String,
+      required: false, // 改为非必填
+      default: '' // 默认为空字符串
+    },
+    showColumnSetting: {
+      type: Boolean,
+      required: false,
+      default: true // 默认显示
+    }
+  },
+  computed: {
+    unDisabled() {
+      return function (val, unDisableKey, disableKey) {
+        if (unDisableKey || unDisableKey === 0) {
+          if (typeof unDisableKey == 'object') {
+            return !unDisableKey.includes(Number(val))
+          } else {
+            return val != unDisableKey
+          }
+        }
+        if (disableKey) {
+          if (typeof disableKey == 'object') {
+            return disableKey.includes(Number(val))
+          } else {
+            return val == disableKey
+          }
+        }
+      }
+    }
+  },
+  data() {
+    return {
+      oldCellData: null,
+      renderKey: Math.random(),
+      logo: require('@/assets/logo.png'),
+      checkedKeys: false,
+      editStatusMap: {},
+      columnSettingsVisible: false, // 控制列设置弹窗的显示/隐藏
+      localColumns: [], // 用于列设置弹窗
+      localTableColumns: [], // 用于实际表格渲染
+      showAllColumns: true,
+      currentTableId: ''
+    }
+  },
+  filters: {
+    dictFind(v, dictData, dictName, dictLabel, dictValue) {
+      const item = dictData[dictName].find((e) => e[dictValue] == v)
+      return item ? item[dictLabel] : v
+    }
+  },
+  created() {
+    // 初始化本地表格数据
+    this.localTableColumns = this.columns.map((col) => ({
+      ...col,
+      isHidden: false
+    }))
+    this.initTableId()
+
+    if (this.defaultFetch) {
+      this.options.initTable && this.fetch()
+    } else {
+      this.options.initTable
+    }
+    this.initColumnSettings()
+  },
+  methods: {
+    /**
+     * 初始化表格ID
+     * 使用父组件路由路径和当前组件name生成唯一标识
+     */
+    initTableId() {
+      if (this.tableId) {
+        this.currentTableId = this.tableId
+      } else {
+        // 获取父组件实例
+        const parent = this.$parent
+        let parentPath = ''
+
+        // 获取父组件的路由路径
+        if (parent && parent.$route) {
+          parentPath = parent.$route.path
+        }
+
+        // 获取当前组件的name
+        const componentName = parent.$options.name || ''
+
+        // 生成唯一标识:父组件路径-组件名称-索引
+        let instanceId = `${parentPath}-${componentName}`
+
+        // 如果同一个父组件中有多个相同的表格组件,添加索引区分
+        if (parent) {
+          const siblings = parent.$children.filter((child) => child.$options.name === componentName)
+          const index = siblings.indexOf(this)
+          if (index > 0) {
+            instanceId += `-${index}`
+          }
+        }
+
+        this.currentTableId = instanceId
+          .replace(/^\//, '') // 移除开头的斜杠
+          .replace(/\//g, '-') // 将路径分隔符替换为横杠
+          .replace(/[^a-zA-Z0-9\-_]/g, '-') // 只保留字母、数字、横杠和下划线
+          .replace(/\-+/g, '-') // 将多个连续横杠替换为单个
+          .replace(/^\-|\-$/g, '') // 移除首尾的横杠
+          .toLowerCase() // 转为小写
+      }
+
+      // console.log('当前表格ID:', this.currentTableId)
+    },
+    hasChildren(row, showType) {
+      //父级显示
+      if (showType && showType == '0') {
+        //父级判断
+        if (row.parentId == null || row.parentId == '') {
+          return true
+        } else {
+          return false
+        }
+      }
+      //子级显示
+      else if (showType && showType == '1') {
+        //父级判断
+        if ((row.parentId == null || row.parentId == '') && row.children && row.children.length > 0) {
+          return false
+        } else {
+          return true
+        }
+      } else {
+        return true
+      }
+    },
+    editCell(row, column) {
+      this.oldCellData = deepClone(row)
+      this.$set(row, column.property + 'isShow', true)
+      this.$nextTick(() => {
+        this.$refs[column.property][0] && this.$refs[column.property][0].focus()
+      })
+    },
+
+    handleEditBlur(column, scope) {
+      scope.row[scope.column.property + 'isShow'] = false
+      column.onChange(scope, this.oldCellData)
+    },
+
+    // table 文本颜色
+    cellStyle(row, column, rowIndex, columnIndex) {
+      if (row.column.label == '当前状态' && row.row.status == 1) {
+        return 'color:#0ED1AA'
+      } else if (row.column.label == '当前状态' && row.row.status == 2) {
+        return 'color:#F3384F'
+      }
+    },
+
+    // pageSize 改变时触发事件
+    handleSizeChange(size) {
+      this.pagination.pageSize = size || 10
+      this.fetch()
+    },
+    // currentPage 改变时触发事件
+    handleIndexChange(current) {
+      this.pagination.pageIndex = current
+      this.fetch()
+    },
+
+    handleSelect(selectRows, targetRow) {
+      // 选中
+      if (this.isObjectInArray(targetRow, selectRows)) {
+        this.select(targetRow.children || [], true)
+      } else {
+        if (targetRow.children && targetRow.children.length) {
+          let newTargetRow = this.flattenArray(targetRow.children)
+          // 两个都选中 1个选中1个未选择 两个都未选中
+          if (newTargetRow.every((itemB) => selectRows.some((itemA) => this.isEqual(itemA, itemB)))) {
+            this.select(targetRow.children, false)
+          } else {
+            this.select(targetRow.children, true)
+            this.$refs.elTablet.toggleRowSelection(targetRow, true)
+          }
+        }
+      }
+    },
+
+    // 多选框选择变化触发事件
+    handleSelectionChange(selection) {
+      this.$emit('selection-change', selection)
+    },
+
+    // 单选框
+    handleCurrentChange(selection) {
+      this.$emit('current-change', selection)
+    },
+
+    // 点击table某一行时触发事件
+    handleRowClick(row, event, column) {
+      this.$emit('handleRowClick', row, event, column)
+    },
+
+    // 翻页时,记住上一页的勾选标识
+    getRowKey(row) {
+      return this.options.treeProps ? (this.options.rowKey ? row[this.options.rowKey] : row.id || row.value || row.avmatCategoriesCode) : null
+    },
+
+    // 控制 table 子级 全选
+    selectAll(selection) {
+      this.checkedKeys = !this.checkedKeys
+      this.select(this.dataSource, this.checkedKeys)
+      this.$emit('select-all', selection)
+    },
+
+    toggleRowSelection(row, toggle) {
+      this.$refs.elTablet.toggleRowSelection(row, toggle)
+    },
+    // 控制 table 子级 全选
+    select(d, c) {
+      d.forEach((row) => {
+        this.$refs.elTablet.toggleRowSelection(row, c)
+        if (row.children && row.children.length > 0) {
+          this.select(row.children, c)
+        }
+      })
+    },
+    // 设定某一行为选中行
+    setCurrentRow(row) {
+      this.$refs.elTablet.setCurrentRow(row)
+    },
+
+    clearSelection() {
+      this.checkedKeys = false
+      this.$refs.elTablet.clearSelection()
+    },
+    isObjectInArray(obj, arr) {
+      return arr.some((item) => {
+        return Object.keys(obj).every((key) => {
+          return obj[key] === item[key]
+        })
+      })
+    },
+    isEqual(objA, objB) {
+      return JSON.stringify(objA) === JSON.stringify(objB)
+    },
+    flattenArray(arr) {
+      return [].concat(...arr.map((item) => (Array.isArray(item.children) ? this.flattenArray(item.children) : item)))
+    },
+    /**
+     * 初始化列设置
+     * 从后端获取用户保存的表格配置
+     */
+    async initColumnSettings() {
+      try {
+        const response = await request({
+          url: '/tableConfig/userTableConfig/getUserTableConfig',
+          method: 'post',
+          data: {  tableName: this.currentTableId }
+        })
+        // const response = await post('/tableConfig/userTableConfig/getUserTableConfig', {
+        //   tableName: this.currentTableId
+        // })
+
+        if (response.data) {
+          const columnConfig = JSON.parse(response.data.columnConfig)
+
+          // 更新 localColumns 和 localTableColumns
+          this.localColumns = this.columns.map((col) => {
+            const savedCol = columnConfig.columns.find((c) => c.prop === col.prop)
+            return {
+              ...col,
+              isShow: savedCol ? savedCol.isShow : true,
+              width: savedCol ? savedCol.width : col.width
+            }
+          })
+
+          // 更新表格显示列
+          this.updateTableColumns()
+        } else {
+          // 没有保存的配置,使用默认配置
+          this.localColumns = this.columns.map((col) => ({
+            ...col,
+            isShow: true
+          }))
+          this.localTableColumns = [...this.columns]
+        }
+
+        this.$nextTick(() => {
+          this.renderKey = Math.random()
+        })
+      } catch (error) {
+        console.error('获取表格配置失败:', error)
+        // 使用默认配置
+        this.localColumns = this.columns.map((col) => ({
+          ...col,
+          isShow: true
+        }))
+        this.localTableColumns = [...this.columns]
+      }
+    },
+
+    /**
+     * 显示列设置弹窗
+     */
+    showColumnSettings() {
+      this.columnSettingsVisible = true
+      this.checkShowAllStatus()
+    },
+
+    /**
+     * 切换全选状态
+     * @param {Boolean} val - 是否全选
+     */
+    toggleAllColumns(val) {
+      this.localColumns.forEach((col) => {
+        col.isShow = val
+      })
+    },
+
+    /**
+     * 处理单个列显示状态变化
+     */
+    handleColumnChange() {
+      this.checkShowAllStatus()
+    },
+
+    /**
+     * 检查是否所有列都被选中,更新全选状态
+     */
+    checkShowAllStatus() {
+      this.showAllColumns = this.localColumns.every((col) => col.isShow)
+    },
+
+    /**
+     * 处理拖拽排序完成事件
+     * 仅更新 localColumns 的顺序,不立即应用到表格
+     */
+    handleDragEnd() {
+      // 拖拽排序时只记录新的顺序,不立即更新表格显示
+      console.log('列顺序已更改,点击确定后生效')
+    },
+
+    /**
+     * 保存列设置到后端
+     * 包括列的显示状态、顺序和宽度
+     */
+    async saveColumnSettings() {
+      const columnConfig = {
+        columns: this.localColumns.map(({ prop, isShow, width }, index) => ({
+          prop,
+          isShow,
+          width,
+          order: index
+        }))
+      }
+
+      try {
+        await request({
+          url: '/tableConfig/userTableConfig/save',
+          method: 'post',
+          data: { tableName: this.currentTableId,
+            columnConfig: JSON.stringify(columnConfig) }
+        })
+        // await post('/tableConfig/userTableConfig/save', {
+        //   tableName: this.currentTableId,
+        //   columnConfig: JSON.stringify(columnConfig)
+        // })
+
+        // 更新表格显示列
+        this.updateTableColumns()
+
+        this.columnSettingsVisible = false
+        this.$nextTick(() => {
+          this.renderKey = Math.random()
+        })
+
+        this.$message.success('配置保存成功')
+      } catch (error) {
+        console.error('保存表格配置失败:', error)
+        this.$message.error('配置保存失败')
+      }
+    },
+
+    /**
+     * 初始化列配置
+     * 重置为系统默认配置
+     */
+    async handleInitConfig() {
+      try {
+        await this.$confirm('确定要初始化列配置吗?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+        await request({
+          url: '/tableConfig/userTableConfig/initUserTableConfig',
+          method: 'post',
+          data: { tableName: this.currentTableId }
+        })
+        // await post('/tableConfig/userTableConfig/initUserTableConfig', {
+        //   tableName: this.currentTableId
+        // })
+
+        // 重新获取配置
+        await this.initColumnSettings()
+
+        this.$message.success('初始化配置成功')
+      } catch (error) {
+        if (error !== 'cancel') {
+          // 排除取消操作的错误
+          console.error('初始化配置失败:', error)
+          this.$message.error('初始化配置失败')
+        }
+      }
+    },
+
+    // 新增方法:根据 localColumns 更新表格显示列
+    updateTableColumns() {
+      this.localTableColumns = this.localColumns.map((col) => ({
+        ...col,
+        isHidden: !col.isShow
+      }))
+    },
+
+    /**
+     * 处理列宽拖动结束事件
+     * @param {Number} newWidth - 新的宽度
+     * @param {Number} oldWidth - 旧的宽度
+     * @param {Object} column - 列对象
+     */
+    handleHeaderDragend(newWidth, oldWidth, column) {
+      // 如果宽度没有变化,不处理
+      if (newWidth === oldWidth) return
+
+      // 更新本地配置
+      const targetColumn = this.localColumns.find((col) => col.prop === column.property)
+      if (targetColumn) {
+        targetColumn.width = newWidth
+      }
+
+      // 更新表格显示列
+      this.updateTableColumns()
+
+      // 保存到后台
+      this.saveColumnSettings()
+    }
+  },
+  // 可选:添加 watch 来监听原始 columns 的变化
+  watch: {
+    columns: {
+      handler(newColumns) {
+        // 当原始列变化时,更新本地列
+        this.localTableColumns = newColumns.map((col) => ({
+          ...col,
+          isHidden: false
+        }))
+      },
+      deep: true
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+@import './index.scss';
+
+.table-settings {
+  margin-bottom: 10px;
+  text-align: right;
+}
+
+.column-item {
+  display: flex;
+  align-items: center;
+  padding: 8px;
+  border-bottom: 1px solid #ebeef5;
+
+  .drag-handle {
+    cursor: move; // 显示移动光标
+    margin-right: 10px;
+    color: #909399;
+  }
+}
+
+.table-page {
+  .el-table {
+    // 添加过渡效果使宽度变化更平滑
+    ::v-deep .el-table__header-wrapper,
+    ::v-deep .el-table__body-wrapper {
+      th,
+      td {
+        transition: width 0.2s;
+      }
+    }
+  }
+}
+
+.dialog-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 0 5px;
+}
+</style>

+ 305 - 0
gm-web/src/views/file/index.vue

@@ -0,0 +1,305 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="文件名称" prop="fileName">
+        <el-input
+          v-model="queryParams.fileName"
+          placeholder="请输入文件名称"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="文件类型" prop="fileType">
+        <el-input
+          v-model="queryParams.fileType"
+          placeholder="请输入文件类型"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-input
+          v-model="queryParams.status"
+          placeholder="请输入状态"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['file:manage:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['file:manage:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['file:manage:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['file:manage:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="fileList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+
+      <el-table-column label="文件名称" align="center" prop="fileName" />
+      <el-table-column label="文件类型" align="center" prop="fileType" >
+        <template slot-scope="scope">
+          <dict-tag :options="dict.type.als_file_types" :value="scope.row.fileType" />
+        </template>
+      </el-table-column>
+      <el-table-column label="文件编号" align="center" prop="id" />
+      <el-table-column label="备注" align="center" prop="remarks" />
+      <el-table-column label="操作" align="center" >
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['file:manage:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['file:manage:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改文件管理对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="文件名称" prop="fileName">
+          <el-input v-model="form.fileName" placeholder="请输入文件名称" />
+        </el-form-item>
+        <el-form-item label="文件类型" prop="fileType">
+          <el-select v-model="form.fileType" placeholder="请选择文件类型" style="width: 100%;">
+            <el-option v-for="dict in dict.type.als_file_types" :key="dict.value" :label="dict.label"
+                       :value="dict.value"></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="文件" prop="url">
+          <PHMuploder v-model="form.url" :limit="1"  :isShowTip="true" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remarks">
+          <el-input v-model="form.remarks" type="textarea" placeholder="请输入备注内容" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listFile, getFile, delFile, addFile, updateFile } from "@/api/als/atlasFile";
+import PHMuploder from '@/components/FileUpload/upload.vue'
+export default {
+  name: "FileManage",
+  components: {
+    PHMuploder
+  },
+  dicts: ['als_file_types'],
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 文件管理表格数据
+      fileList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        fileName: null,
+        fileType: null,
+        status: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        fileName: [
+          { required: true, message: "文件名称不能为空", trigger: "blur" }
+        ],
+        fileType: [
+          { required: true, message: "文件类型不能为空", trigger: "blur" }
+        ],
+        ossId: [
+          { required: true, message: "文件OSS ID不能为空", trigger: "blur" }
+        ],
+        status: [
+          { required: true, message: "状态不能为空", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询文件管理列表 */
+    getList() {
+      this.loading = true;
+      listFile(this.queryParams).then(response => {
+        this.fileList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        fileName: null,
+        fileType: null,
+        ossId: null,
+        status: null,
+        remarks: null,
+        tenantId: null,
+        delFlag: null,
+        version: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加文件管理";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getFile({id:id}).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改文件管理";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateFile(this.form).then(response => {
+              this.$modal.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addFile(this.form).then(response => {
+              this.$modal.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$modal.confirm('是否确认删除文件管理编号为"' + ids + '"的数据项?').then(function() {
+        return delFile(ids);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download('file/manage/export', {
+        ...this.queryParams
+      }, `file_${new Date().getTime()}.xlsx`)
+    }
+  }
+};
+</script>

+ 79 - 516
gm-web/src/views/index.vue

@@ -1,529 +1,92 @@
 <template>
-  <div class="chat-container">
-    <div class="chat-box" ref="chatBox">
-      <div v-for="(message, index) in messages" :key="index" :class="[
-          'chat-message',
-          message.isUser ? 'user-message' : 'incoming-message',
-        ]">
-        <div class="header-user" v-if="message.isUser">
-          <div class="avatar-wrapper" :class="message.isUser ? 'user-avatar' : ''">
-            <img src="@/assets/logo/logo.png" alt="avatar" class="avatar" />
-          </div>
-          <div class="user-name">用户</div>
+  <div class="main-container_app">
+    <el-tabs type="border-card" v-model="activeName" @tab-click="handleTabClick">
+      <el-tab-pane label="智能问答" name="chat">
+        <div class="tab-content_app">
+          <ChatComponent :autoLoadWarning="true" />
         </div>
-        <div class="header" v-else>
-          <div class="avatar-wrapper" :class="message.isUser ? 'user-avatar' : ''">
-            <img src="@/assets/logo/logo.png" alt="avatar" class="avatar" />
-          </div>
-          <div class="user-name">系统</div>
+      </el-tab-pane>
+      <el-tab-pane label="智能AI" name="chatAI">
+        <div class="tab-content_app">
+         <cat-ai/>
         </div>
-        <div class="message-table" v-if="message.isTable">
-          <div v-if="message.isTable" class="message-table-box">
-            <div v-for="(device, index) in message.tableData" :key="index" v-if="message.tableData.length > 0">
-              <div class="flex-title">
-                <el-link class="name" title="点击下载文件" :underline="false" @click="downloadFile(device.fileUrl)">{{
-                    getFileNameBeforeLastUnderscore(device.fileName)
-                  }}</el-link>
-                <div>
-                  <el-link type="primary" class="link" :underline="false" @click="openFile(device.fileUrl)">预览&nbsp;
-                  </el-link>
-
-                  <el-link type="primary" class="link" style="margin-left:5px" :underline="false"
-                    @click="handleDetail(device)">详情</el-link>
-                </div>
-              </div>
-              <el-link type="primary" :underline="false" class="link">[{{
-                  device.belongType === "tech"? "技术资料" : device.belongType === "fault"? "故障记录": "故障案例"
-                }}]</el-link>
-              <div class="content" v-html="device.attachment.content"
-                :style="{ maxHeight: '60px', overflowY: 'hidden' }"></div>
-            </div>
-            <div v-if="message.tableData == null">无对应数据,请重新查询</div>
-          </div>
-          <div v-if="message.time" class="message-time">{{ message.time }}</div>
+      </el-tab-pane>
+      <el-tab-pane label="文件管理" name="statistics">
+        <div class="tab-content_app">
+        <file-view></file-view>
         </div>
-        <div class="message-content" v-else>
-          <div class="message-text">
-            <!-- 如果是表格内容,则渲染表格 -->
-            <!-- 普通文本消息 -->
-            <span>{{ message.displayedText }}</span>
-          </div>
-          <div v-if="message.time" class="message-time">{{ message.time }}</div>
+      </el-tab-pane>
+      <el-tab-pane label="知识抽取" name="settings">
+        <div class="tab-content_app">
+          <KnowledgeExtraction/>
         </div>
-      </div>
-    </div>
-
-    <div class="input-box">
-      <input type="text" v-model="inputMessage" @keyup.enter="sendMessage" placeholder="输入您的消息..." />
-      <el-button @click="sendMessage" :disabled="loading" class="send-btn">
-        <i class="el-icon-s-promotion"></i>发送
-      </el-button>
-    </div>
-    <TechDialog ref="techDialog" :showFlag="teachShowFlag" @close="handleDialogClose" :belongId="belongId" />
-    <FaultDialog :showFlag="faultShowFlag" @close="handleFaultClose" :belongId="belongId" />
-    <FaultCaseDialog :showFlag="caseShowFlag" @close="handleCaseClose" :belongId="belongId" />
-    <!-- 添加或修改资料类型对话框 -->
-    <el-dialog title="文件预览" :visible.sync="open" width="70%" append-to-body :before-close="handleBeforeClose">
-      <div style="max-height: 70vh; overflow: auto ;">
-        <FilePreview :fileUrl="fileUrl" />
-      </div>
-      <div slot="footer" class="dialog-footer">
-        <el-button @click="cancel">关  闭</el-button>
-      </div>
-    </el-dialog>
+      </el-tab-pane>
+    </el-tabs>
   </div>
-
 </template>
 
 <script>
-  import {
-    getSearchData,
-    getWarning
-  } from "@/api/search";
-  import {
-    listFaultSetting,
-    getFaultSetting,
-    delFaultSetting,
-    addFaultSetting,
-    updateFaultSetting,
-  } from "@/api/fault/faultSetting";
-
-  import TechDialog from './comp/techDialog.vue'
-  import FaultDialog from './comp/faultDialog.vue'
-  import FaultCaseDialog from './comp/faultCaseDialog.vue'
-  import DocumentPreview from "@/components/Preview/index.vue";
-
-  import FilePreview from "@/components/Preview/index.vue";
-  export default {
-    components: {
-      'TechDialog': TechDialog,
-      'FaultDialog': FaultDialog,
-      'FaultCaseDialog': FaultCaseDialog,
-      FilePreview
-    },
-    data() {
-      return {
-        inputMessage: "",
-        messages: [], // 消息列表
-        teachShowFlag: false,
-        caseShowFlag: false,
-        recordShowFlag: false,
-        faultShowFlag: false,
-        belongId: '',
-        loading: false,
-        url: '',
-        // 是否显示弹出层
-        open: false,
-      };
-    },
-    created() {
-      // this.getWarning();
-    },
-    methods: {
-      getWarning() {
-        getFaultSetting(1).then((response) => {
-          var setting = response.data;
-          //三月未处理故障
-          if (setting.threeMonthOpen == "true") {
-            var index = 0;
-            getWarning().then((response) => {
-              index = response.data;
-              if (index > 0) {
-                this.$notify({
-                  title: "监控提示",
-                  message: "有 " + index + " 条故障监控未处理,请及时处理!",
-                  type: "warning",
-                });
-              }
-            });
-          }
-        });
-      },
-      handleDetail(device) {
-        this.belongId = device.belongId
-        if (device.belongType == "tech") {
-          this.teachShowFlag = true
-        } else if (device.belongType == 'case') {
-          this.caseShowFlag = true
-        } else {
-          this.faultShowFlag = true
-
-        }
-      },
-      handleDialogClose() {
-        this.teachShowFlag = false;
-      },
-      handleCaseClose() {
-        this.caseShowFlag = false;
-      },
-      handleFaultClose() {
-        this.faultShowFlag = false;
-      },
-      handleRecordDialogClose() {
-        this.recordShowFlag = false;
-      },
-      downloadFile(fileUrl) {
-        const baseUrl = process.env.VUE_APP_BASE_API;
-        const fullUrl = baseUrl + fileUrl;
-        this.createloadFile(fullUrl);
-      },
-      openFile(fileUrl) {
-        this.open = false; // 关闭弹窗
-        this.fileUrl = ""; // 清空旧的 fileUrl
-        this.$nextTick(() => {
-          const baseUrl = process.env.VUE_APP_BASE_API;
-          const fullUrl = new URL(fileUrl, baseUrl).toString(); // 将 baseUrl 和 fileUrl 合并
-          this.fileUrl = fullUrl; // 设置新的 fileUrl
-          this.open = true; // 打开弹窗
-          console.log("打开文件路径:", this.fileUrl); // 打印调试信息
-        });
-      },
-      handleBeforeClose(done) {
-        this.fileUrl = ""; // 清空旧的 fileUrl
-        this.open = false; // 关闭弹窗
-      },
-      // 取消按钮
-      cancel() {
-        this.fileUrl = ""; // 清空旧的 fileUrl
-        this.open = false;
-      },
-      createloadFile(fileUrl) {
-        // 创建一个隐藏的 <a> 标签
-        fetch(fileUrl)
-          .then((response) => {
-            if (!response.ok) {
-              throw new Error("Network response was not ok");
-            }
-            return response.blob(); // 将响应转换为 Blob 对象
-          })
-          .then((blob) => {
-            // 创建下载链接
-            const link = document.createElement("a");
-            link.href = URL.createObjectURL(blob);
-
-            // 设置下载文件名(从 URL 提取)
-            link.download = decodeURIComponent(fileUrl.split("/").pop());
-
-            // 触发点击
-            link.click();
-
-            // 释放 Blob 对象 URL
-            URL.revokeObjectURL(link.href);
-          })
-          .catch((error) => {
-            console.error("文件下载失败:", error);
-          });
-      },
-      getFileNameBeforeLastUnderscore(fileName) {
-        const lastUnderscoreIndex = fileName.lastIndexOf("_"); // 找到最后一个下划线的位置
-        if (lastUnderscoreIndex === -1) {
-          return fileName; // 如果没有下划线,直接返回整个文件名
-        }
-        return fileName.slice(0, lastUnderscoreIndex); // 截取从开头到最后一个下划线之前的部分
-      },
-      // 获取设备信息并合并为一条表格消息
-      getList() {
-        this.loading = true;
-        const params = {
-          keyword: this.inputMessage,
-        };
-
-        getSearchData(params).then((response) => {
-          let deviceInfoList = response.data;
-
-          // 遍历 deviceInfoList,确保每个 item 都有 attachment 和 content 字段
-          deviceInfoList.forEach(item => {
-            if (!item.hasOwnProperty('attachment')) {
-              item.attachment = {}; // 如果没有 attachment 字段,添加一个空对象
-            }
-            if (!item.attachment.hasOwnProperty('content')) {
-              item.attachment.content = '该文件是空文件'; // 如果没有 content 字段,添加默认内容
-            }
-          });
-
-          this.inputMessage = "";
-
-          // 构造表格数据的消息对象
-          const tableMessage = {
-            isUser: false,
-            isTable: true, // 标识这是表格消息
-            tableData: this.textLines(deviceInfoList),
-            time: new Date().toLocaleTimeString(),
-          };
-          this.loading = false;
-
-          // 将表格消息添加到消息列表
-          this.messages.push(tableMessage);
-          this.scrollToBottom();
-        }).catch(() => {
-          const tableMessage = {
-            isUser: false,
-            isTable: true, // 标识这是表格消息
-            tableData: this.textLines([]),
-            time: new Date().toLocaleTimeString(),
-          };
-          this.messages.push(tableMessage);
-          this.loading = false;
-        });
-      },
-      textLines(dataArray) {
-        if (dataArray == "") {} else {
-          return dataArray.map((item) => {
-            if (item.attachment && item.attachment.content) {
-              // 替换换行符为 <br> 标签
-              item.attachment.content = item.attachment.content.replace(
-                /\r?\n/g,
-                "<br>"
-              );
-            }
-            return item;
-          });
-        }
-      },
-      // 发送消息
-      sendMessage() {
-        if (this.inputMessage.trim() !== "") {
-          const currentTime = new Date().toLocaleTimeString();
-
-          // 添加用户消息
-          this.messages.push({
-            text: this.inputMessage,
-            isUser: true,
-            time: currentTime,
-            displayedText: this.inputMessage,
-          });
-
-          // this.inputMessage = ""; // 清空输入框
-          this.scrollToBottom();
-
-          // 每次发送消息后调用 getList 并展示设备信息
-          this.getList();
-        }
-      },
-      // 滚动到底部
-      scrollToBottom() {
-        this.$nextTick(() => {
-          const chatBox = this.$refs.chatBox;
-          chatBox.scrollTop = chatBox.scrollHeight;
-        });
-      },
-    },
-  };
-</script>
-
-<style lang="scss" scoped>
-  .chat-container {
-    width: 100%;
-    height: 90vh;
-    margin: 0;
-    padding: 0;
-    display: flex;
-    flex-direction: column;
-    position: relative;
-    font-family: Arial, sans-serif;
-  }
-
-  .chat-box {
-    flex: 1;
-    overflow-y: auto;
-    padding: 20px;
-    background-color: #ffffff;
-    display: flex;
-    flex-direction: column;
-    margin-bottom: 100px;
-    border-radius: 10px;
-  }
-
-  .chat-message {
-    margin-bottom: 20px;
-    display: flex;
-    max-width: 70%;
-    flex-direction: column;
-  }
-
-  .user-message {
-    align-self: flex-end;
-    flex-direction: column;
-  }
-
-  .incoming-message {
-    align-self: flex-start;
-  }
-
-  .avatar-wrapper {
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    width: 40px;
-    height: 40px;
-    border-radius: 50%;
-    background: linear-gradient(135deg,
-        #f09433,
-        #e6683c,
-        #dc2743,
-        #cc2366,
-        #bc1888,
-        #e1306c);
-    padding: 3px;
-    margin-bottom: 5px;
-  }
-
-  .user-avatar {
-    align-self: flex-end;
-    margin-right: 0;
-    margin-top: 5px;
-  }
-
-  .avatar {
-    width: 36px;
-    height: 36px;
-    border-radius: 50%;
-    background-color: #fff;
-  }
-
-  .message-content {
-    background-color: #e0e0e0;
-    padding: 12px;
-    border-radius: 12px;
-    max-width: 100%;
-    word-wrap: break-word;
-    position: relative;
-    margin-top: 5px;
-  }
-
-  .user-message .message-content {
-    background-color: #007bff;
-    color: white;
-  }
-
-  .message-time {
-    font-size: 12px;
-    color: #aaa;
-    margin-top: 5px;
-    text-align: right;
-  }
-
-  .message-table {
-    margin-top: 5px;
-    background: #fff;
-    border: 3px solid #f1efef;
-    border-radius: 12px;
-    padding: 24px;
-    background: #f0f0f0;
-
-    .message-table-box>div {
-      background: #fff;
-      // min-width: 600px;
-      margin-bottom: 24px;
-      padding: 12px 24px;
-      overflow: hidden;
-
-      .name {
-        margin-bottom: 6px;
-        font-size: 18px;
-      }
-
-      .link {
-        margin-bottom: 10px;
-        font-size: 14px;
-      }
-
-      .content {
-        font-size: 12px;
-        color: #868585;
-      }
+import ChatComponent from './ChatComponent.vue';
+import FileView from '@/views/file'
+import KnowledgeExtraction from '@/views/knowledgeExtraction/index.vue'
+import CatAi from '@/views/chat/catAi.vue'
+export default {
+  name: 'MainPage',
+  components: {
+    ChatComponent,
+    FileView,
+    KnowledgeExtraction,
+    CatAi
+  },
+  data() {
+    return {
+      activeName: 'chat'
+    };
+  },
+  methods: {
+    handleTabClick(tab, event) {
+      console.log('切换到标签页: ', tab.name);
     }
   }
+};
+</script>
 
-  .message-table th,
-  .message-table td {
-    border: 1px solid #ddd;
-    padding: 8px;
-    text-align: left;
-  }
-
-  .message-table th {
-    background-color: #f4f4f4;
-    font-weight: bold;
-  }
-
-  .input-box {
-    position: fixed;
-    bottom: 3%;
-    left: 55%;
-    transform: translateX(-50%);
-    width: 60%;
-    display: flex;
-    align-items: center;
-    padding: 30px;
-    height: 100px;
-    background-color: #ffffff;
-    box-shadow: 0 -2px 15px rgba(0, 0, 0, 0.1);
-    border-radius: 30px;
-  }
-
-  input[type="text"] {
-    flex: 1;
-    padding: 12px;
-    font-size: 14px;
-    border: none;
-    border-radius: 20px;
-    margin-right: 10px;
-    background-color: #f0f0f0;
-  }
-
-  .send-btn {
-    padding: 10px;
-    background-color: #007bff;
-    color: white;
-    border: none;
-    border-radius: 15%;
-    cursor: pointer;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-  }
-
-  .send-btn:hover {
-    background-color: #0056b3;
-  }
-
-  .send-icon {
-    width: 20px;
-    height: 20px;
-    fill: white;
-  }
-
-  .header {
-    display: flex;
-    align-items: center;
-
-    .user-name {
-      margin-left: 10px;
-      font-size: 14px;
-      color: #313131;
-    }
-  }
-
-  .header-user {
-    display: flex;
-    align-items: center;
-
-    .user-name {
-      margin-left: 10px;
-      font-size: 14px;
-      color: #313131;
-    }
-  }
-
-  .flex-title {
-    display: flex;
-    justify-content: space-between;
-  }
-
-
-  .dialog-footer {
-    display: flex;
-    justify-content: flex-end;
-  }
+<style lang="scss" scoped>
+html, body, #app {
+  height: 100%;
+  margin: 0;
+  padding: 0;
+}
+
+.main-container_app {
+  width: 100%;
+  height: 100%;
+  box-sizing: border-box;
+}
+
+.tab-content_app {
+  width: 100%;
+  height: calc(100vh - 56px); // 使用视口高度计算
+  box-sizing: border-box;
+  background-color: #fff;
+  border-radius: 0 0 4px 4px;
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+}
+
+.el-tabs--border-card {
+  height: 100%;
+  border: none;
+}
+
+.el-tabs--border-card > .el-tabs__content {
+  padding: 0;
+  height: calc(100% - 42px); // 减去标签页标题高度
+}
+::v-deep .el-tabs--border-card > .el-tabs__content {
+  padding: 0 !important;
+}
+// 确保智能问答组件在标签页中占满空间
+::v-deep .tab-content_app >>> .chat-container {
+  height: 100%;
+}
 </style>

+ 279 - 0
gm-web/src/views/knowledgeExtraction/extractList.vue

@@ -0,0 +1,279 @@
+<template>
+  <div class="view-table-content">
+    <div style="width: 100%">
+      <div style="width: 80%; margin-left: 10%">
+        <!-- 分句、抽取、审核、入库 -->
+        <el-steps :active="active" finish-status="success" process-status="finish">
+          <!-- 需要判断分句中、抽取中、。。。。 -->
+          <el-step title="分句"></el-step>
+          <el-step title="抽取"></el-step>
+          <el-step title="审核"></el-step>
+          <el-step title="入库"></el-step>
+        </el-steps>
+      </div>
+      <div class="view-dataType-title-btn" style="float: right; margin: 10px">
+        <el-button v-if="active === 0" type="primary">返 回</el-button>
+        <el-button style="margin-right: 300px" v-if="active === 0" type="warning" @click="handleClause">分 句</el-button>
+        <el-button v-if="active === 1" type="warning" @click="handleExtract">抽 取</el-button>
+        <div style="clear: both"></div>
+      </div>
+      <div class="view-dataType-table">
+        <div v-if="active === 0" style="width: 500px; margin: 50px 0px 0px 300px">
+          <el-form ref="taskFormRef" disabled :model="taskForm" label-width="80px">
+            <el-form-item label="任务名称" prop="taskName">
+              <el-input v-model="taskForm.taskName" />
+            </el-form-item>
+            <el-form-item label="抽取文件" prop="fileName">
+              <el-input v-model="taskForm.fileName" />
+            </el-form-item>
+          </el-form>
+        </div>
+
+        <LTable ref="table" v-if="active === 1" @selection-change="selection" :defaultFetch="false" :fetch="fetch" :columns="clauseColumns" :dataSource="clauseTableData" :options="clauseOptions" :pagination="clauseTableRequset"></LTable>
+      </div>
+      <!-- 添加或修改模型信息对话框 -->
+      <el-dialog :title="clauseDialogTitle" :visible.sync="clauseDialogVisible" width="600px" :before-close="handleClauseClose">
+        <el-form ref="clauseFormRef" :model="clauseForm" label-width="80px">
+          <el-form-item label="内容" prop="content">
+            <el-input type="textarea" :rows="2" v-model="clauseForm.content" />
+          </el-form-item>
+        </el-form>
+
+        <span slot="footer" class="dialog-footer">
+          <el-button @click="handleClauseClose">取 消</el-button>
+          <el-button type="primary" @click="clauseSubmit">确 定</el-button>
+        </span>
+      </el-dialog>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getTaskListAPI, addTaskAPI, getTaskInfoAPI, getClauseListAPI, updateClauseAPI, removeClauseAPI } from '@/api/als/knowledgeExtraction'
+import { listFile } from '@/api/als/atlasFile'
+// import { getOssIdDataAPI } from '@/api/als/algorithm'
+import { deepClone, debounce } from '@/utils'
+
+export default {
+  name: 'ExtractList',
+  components: {},
+  data() {
+    // 这里存放数据
+    return {
+      dialogTitle: '新增',
+      dialogVisible: false,
+      clauseDialogTitle: '编辑',
+      clauseDialogVisible: false,
+      keyWordData: '',
+      searchValue: '',
+      clauseColumns: [
+        {
+          prop: 'content',
+          label: '内容'
+        },
+        {
+          prop: 'status',
+          label: '状态',
+          width: '240px',
+          render: (h, params) => {
+            return h('span', { class: 'success-state' }, '已分句')
+          }
+        },
+        {
+          button: true,
+          label: '操作',
+          width: '240px',
+          group: [
+            {
+              name: '编辑',
+              type: 'text',
+              round: false,
+              plain: false,
+              onClick: (row, index, scope) => {
+                this.clauseHandUpdate(row)
+              }
+            },
+            {
+              name: '删除',
+              type: 'text',
+              round: false,
+              plain: false,
+              onClick: (row, index, scope) => {
+                this.clauseRemove([row])
+              }
+            }
+          ]
+        }
+      ],
+      clauseOptions: {
+        stripe: false, // 斑马纹
+        mutiSelect: false, // 多选框
+        index: true, // 显示序号, 多选则 mutiSelect
+        loading: false, // 表格动画
+        initTable: false, // 是否一挂载就加载数据
+        border: true,
+        height: 'calc(100vh - 335px)'
+      },
+      tableCheckItems: [],
+      clauseTableData: [{ content: 'XXXXXXXXX水水水水水水水' }, { content: 'mmmmmmmmmmmAAAAAAAAAAA' }],
+      clauseTableRequset: {
+        total: 0,
+        pageIndex: 1,
+        pageSize: 20,
+        searchValue: ''
+      },
+      form: {
+        id: '',
+        file: ''
+      },
+      debounceFn: debounce(this.fetch, 500),
+      fileList: [],
+      extractId: '',
+      active: 0,
+      taskForm: {
+        id: '',
+        taskName: '任务名称',
+        fileName: '抽取文件'
+      },
+      clauseForm: {
+        content: ''
+      }
+    }
+  },
+  watch: {
+    keyWord() {
+      this.clauseTableRequset.pageIndex = 1
+      this.debounceFn()
+    }
+  },
+  mounted() {
+    this.extractId = this.$route.query.id
+    this.getAtlasFileAPI()
+  },
+  methods: {
+    async getAtlasFileAPI(params) {
+      const {
+        data: { list, total }
+      } = await listFile()
+      this.fileList = list
+    },
+
+    async removeknowledgeExtractionAPI(params) {
+      try {
+        const { code } = await removeknowledgeExtraction(params)
+        if (code === 200) {
+          this.$message({
+            type: 'success',
+            message: '操作成功!'
+          })
+          await this.getknowledgeExtractionAPI()
+          this.handleClose()
+        }
+      } catch (error) {}
+    },
+
+    async getknowledgeExtractionAPI(params) {
+      if (this.$refs.table) this.$refs.table.clearSelection()
+      const { keyWord } = this
+      const { pageSize, pageIndex } = this.clauseTableRequset
+      const {
+        data: { list, total }
+      } = await getknowledgeExtraction({ pageSize, pageNum: pageIndex, ...params })
+      this.clauseTableData = list
+      this.clauseTableRequset.total = total
+    },
+
+    fetch() {
+      this.getknowledgeExtractionAPI()
+    },
+
+    async searchClick() {
+      this.getknowledgeExtractionAPI({ name: keyWordData })
+    },
+
+    async updateknowledgeExtractionAPI() {
+      try {
+        const { code } = await updateknowledgeExtraction({ ...this.clauseForm })
+        if (code === 200) {
+          this.$message({
+            type: 'success',
+            message: '操作成功!'
+          })
+          this.handleClose()
+          this.getknowledgeExtractionAPI()
+        }
+      } catch (error) {}
+    },
+
+    openDialog() {
+      this.dialogTitle = '新增'
+      this.clauseDialogVisible = true
+    },
+
+    handleClose() {
+      this.taskForm = {
+        id: '',
+        taskName: '',
+        fileName: ''
+      }
+    },
+
+    handleClauseClose() {
+      this.clauseDialogVisible = false
+      this.clauseForm = {
+        content: ''
+      }
+    },
+
+    handleClause() {
+      // 调用分句接口
+      this.active = 1
+    },
+
+    handleExtract() {
+      // 调用抽取
+      this.active = 2
+    },
+
+    clauseHandUpdate(row) {
+      this.clauseDialogTitle = '编辑'
+      this.clauseForm = deepClone(row)
+      this.clauseDialogVisible = true
+    },
+
+    clauseSubmit() {
+      switch (this.clauseDialogTitle) {
+        case '编辑':
+          // this.updateknowledgeExtractionAPI()
+          break
+      }
+    },
+
+    selection(val) {
+      this.tableCheckItems = val
+    },
+
+    clauseRemove(row) {
+      this.$confirm('是否删除该数据', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          this.removeknowledgeExtractionAPI(row.map((e) => e.id))
+        })
+        .catch(() => {})
+    },
+
+   /** async handleFile() {
+      const res = await getOssIdDataAPI(this.form.file)
+      console.log('res', res)
+      const res =await getknowledgeExtraction()
+    },**/
+    checkExtractList() {}
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+</style>

+ 1135 - 0
gm-web/src/views/knowledgeExtraction/index.vue

@@ -0,0 +1,1135 @@
+<template>
+  <div class="view-table-content">
+    <div style="width: 100%">
+      <div class="view-dataType-title">
+        <div class="view-dataType-title-btn">
+          <el-button type="success" @click="openDialog()">新增抽取任务</el-button>
+          <el-button type="warning" @click="remove(tableCheckItems)" :disabled="tableCheckItems.length === 0">删除</el-button>
+        </div>
+        <div class="view-dataType-title-search">
+          <el-input placeholder="请输入任务名称" v-model="keyWordData" class="input1">
+            <el-button slot="append" icon="el-icon-search" @click="searchClick"></el-button>
+          </el-input>
+        </div>
+      </div>
+      <div class="view-dataType-table">
+        <LTable ref="table" @selection-change="selection" :defaultFetch="false" :fetch="fetch" :columns="columns" :dataSource="tableData" :options="options" :pagination="tableRequest"></LTable>
+      </div>
+      <!-- 添加或修改抽取任务对话框 -->
+      <el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="600px" :before-close="handleClose">
+        <el-form ref="form" :model="form" label-width="80px" :rules="rules">
+          <el-form-item label="任务名称" prop="taskName">
+            <el-input v-model="form.taskName" placeholder="请输入任务名称" />
+          </el-form-item>
+          <el-form-item label="选择抽取文件" label-width="110px" prop="ossId">
+            <el-select v-model="form.ossId" placeholder="请选择文件">
+              <el-option v-for="item in optionFileList" :key="item.id" :label="item.dataTitle" :value="item.id" />
+            </el-select>
+          </el-form-item>
+        </el-form>
+
+        <span slot="footer" class="dialog-footer">
+          <el-button @click="handleClose">取 消</el-button>
+          <el-button type="primary" @click="submit">确 定</el-button>
+        </span>
+      </el-dialog>
+      <el-dialog title="详情" :visible.sync="detailDialogVisible" top="10vh" width="90%" :before-close="detailHandleClose">
+        <div style="width: 80%; margin-left: 10%">
+          <!-- 分句、抽取、审核、入库 -->
+          <el-steps :active="active" finish-status="success" process-status="finish">
+            <!-- 需要判断分句中、抽取中、。。。。 -->
+            <el-step :title="zeroTitle"></el-step>
+            <el-step :title="oneTitle"></el-step>
+            <el-step :title="twoTitle"></el-step>
+            <el-step :title="threeTitle"></el-step>
+          </el-steps>
+        </div>
+        <div class="view-dataType-table">
+          <div v-if="active === 0" style="width: 500px; margin: 50px 0px 0px 300px">
+            <el-form ref="taskFormRef" disabled :model="taskForm" label-width="80px">
+              <el-form-item label="任务名称" prop="taskName">
+                <el-input v-model="taskForm.taskName" />
+              </el-form-item>
+              <el-form-item label="抽取文件" prop="ossId">
+                <!-- <el-input v-model="taskForm.ossId" /> -->
+                <el-select v-model="taskForm.ossId" placeholder="请选择文件">
+                  <el-option v-for="item in optionFileList" :key="item.id" :label="item.dataTitle" :value="item.id" />
+                </el-select>
+              </el-form-item>
+            </el-form>
+          </div>
+
+          <LTable
+            ref="clauseTableRef"
+            v-if="active === 1 || active === 2"
+            @selection-change="clauseSelection"
+            :defaultFetch="false"
+            :fetch="clauseFetch"
+            :showColumnSetting="false"
+            :columns="clauseColumns"
+            :dataSource="clauseTableData"
+            :options="clauseOptions"
+            :pagination="clauseTableRequest"
+          ></LTable>
+          <graphECharts v-if="active === 3" style="margin: 0 auto" :width="1400" :height="500" :graphData="graphData" class="charts"></graphECharts>
+          <!-- <LTable ref="extractTable" v-if="active === 2" @selection-change="extractSelection" :defaultFetch="false" :fetch="fetch" :columns="extractColumns" :dataSource="extractTableData" :options="extractOptions" :pagination="extractTableRequest"></LTable> -->
+        </div>
+
+        <el-dialog width="50%" title="详情" :visible.sync="clauseDialogVisible" :before-close="clauseHandleClose" append-to-body>
+          <el-form ref="clauseFormRef" :model="clauseForm" label-width="80px">
+            <el-form-item label="内容" prop="clause">
+              <el-input type="textarea" :rows="7" v-model="clauseForm.clause" placeholder="请输入内容" />
+            </el-form-item>
+          </el-form>
+
+          <div slot="footer" class="dialog-footer">
+            <el-button @click="clauseDialogVisible = false">取 消</el-button>
+            <el-button type="primary" @click="clauseSubmit">确 定</el-button>
+          </div>
+        </el-dialog>
+
+        <el-dialog width="80%" title="抽取详情" :visible.sync="extractDialogVisible" :before-close="extractHandleClose" append-to-body>
+          <div class="content">
+            <div class="left">
+              <p>{{ extractData.content }}</p>
+            </div>
+            <div class="right">
+              <LTable
+                ref="extractDetailTableRef"
+                :showColumnSetting="false"
+                :defaultFetch="false"
+                :fetch="extractDetailFetch"
+                :columns="extractDetailColumns"
+                :dataSource="extractData.extractDetailTable"
+                :pagination="extractDetailRequest"
+                :options="extractDetailOptions"
+              ></LTable>
+            </div>
+          </div>
+          <div slot="footer" class="dialog-footer">
+            <el-button type="success" @click="addER">新增实体关系</el-button>
+            <el-button @click="handleCancel">作 废</el-button>
+            <el-button type="primary" @click="passThrough">通 过</el-button>
+          </div>
+        </el-dialog>
+        <span slot="footer" class="dialog-footer">
+          <!-- <el-button @click="handleClose">取 消</el-button> -->
+          <el-button type="primary" v-if="active === 0 && zeroTitle !== '分句中'" :loading="clauseLoading" @click="handleClause">分 句</el-button>
+          <el-button type="primary" v-if="active === 1 && oneTitle !== '抽取中'" :loading="extractLoading" @click="handleExtract">抽 取</el-button>
+          <el-button type="primary" v-if="active === 2 && oneTitle !== '入库中'" :loading="storageLoading" @click="handleStorage">入 库</el-button>
+        </span>
+      </el-dialog>
+
+      <el-dialog width="30%" title="增加实体关系" :visible.sync="addERDialogVisible" :before-close="addERHandleClose" append-to-body>
+        <el-form ref="addERFormRef" :model="addERForm" label-width="80px">
+          <el-form-item label="头实体" prop="headEntity">
+            <el-input v-model="addERForm.headEntity" placeholder="请输入内容" />
+          </el-form-item>
+          <el-form-item label="头实体类" prop="headEntityClass">
+            <!-- <el-input  v-model="addERForm.headEntityClass" placeholder="请输入内容" /> -->
+            <el-select v-model="addERForm.headEntityClass" placeholder="请选择实体类型">
+              <el-option v-for="(item, index) in entityClassList" :key="index" :label="item" :value="item" />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="关系" prop="relation">
+            <!-- <el-input  v-model="addERForm.relation" placeholder="请输入内容" /> -->
+            <el-select v-model="addERForm.relation" placeholder="请选择实体类型">
+              <el-option v-for="(item, index) in relationClassList" :key="index" :label="item" :value="item" />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="尾实体" prop="tailEntity">
+            <el-input v-model="addERForm.tailEntity" placeholder="请输入内容" />
+          </el-form-item>
+          <el-form-item label="尾实体类" prop="tailEntityClass">
+            <el-select v-model="addERForm.tailEntityClass" placeholder="请选择实体类型">
+              <el-option v-for="(item, index) in entityClassList" :key="index" :label="item" :value="item" />
+            </el-select>
+          </el-form-item>
+        </el-form>
+
+        <div slot="footer" class="dialog-footer">
+          <el-button @click="addERHandleClose">取 消</el-button>
+          <el-button type="primary" @click="addERSubmit">确 定</el-button>
+        </div>
+      </el-dialog>
+    </div>
+  </div>
+</template>
+
+<script>
+import {extractStatusss} from '@/utils/enum-data'
+import { listTechData, download, delTechData, addTechData, updateTechData } from "@/api/tech/techData";
+import { getTaskList, addTask, updateTask, removeTask, taskPro, getVisually, removeClause, updateClause, getClauseList, getExtractList, updateExtractInfo, removeExtractInfo, addER } from '@/api/als/knowledgeExtraction'
+import { getAllEntityClass } from '@/api/als/entityManage'
+import { getAllRelationClass } from '@/api/als/ERManage'
+import graphECharts from '@/views/components/Charts/graph.vue'
+
+import { getAtlasFile } from '@/api/als/atlasFile'
+// import { getOssIdDataAPI } from '@/api/als/algorithm'
+import { deepClone, debounce } from '@/utils'
+import LTable from '@/views/components/LTable/index.vue'
+
+export default {
+  name: 'KnowledgeExtraction',
+  components: { LTable, graphECharts },
+  data() {
+    // 这里存放数据
+    return {
+      dialogTitle: '新增',
+      dialogVisible: false,
+      detailDialogVisible: false,
+      clauseDialogVisible: false,
+      extractDialogVisible: false,
+      addERDialogVisible: false,
+      clauseLoading: false,
+      extractLoading: false,
+      storageLoading: false,
+      keyWordData: '',
+      searchValue: '',
+      rules: {
+        taskName: [{ required: true, message: '任务名称不能为空', trigger: 'blur' }],
+        ossId: [{ required: true, message: '抽取文件不能为空', trigger: 'change' }]
+      },
+      columns: [
+        {
+          prop: 'taskName',
+          label: '任务名称'
+        },
+        {
+          prop: 'ossId',
+          label: '文件',
+          render: (h, params) => {
+            const matchedItem = this.fileList.find((item) => params.row.ossId.trim() === item.ossId.trim())
+            if (matchedItem) {
+              return h('span', matchedItem.fileName)
+            } else {
+              return h('span', {}, '')
+            }
+          }
+        },
+        {
+          prop: 'status',
+          label: '状态',
+          render: (h, params) => {
+            const matchedItem = extractStatusss.find((item) => params.row.status === item.key)
+            if (matchedItem) {
+              return h('span', matchedItem.name)
+              // return h('span', { class: matchedItem.colorType }, matchedItem.name)
+            } else {
+              return h('span', {}, '')
+            }
+          }
+        },
+        {
+          button: true,
+          label: '操作',
+          width: '240px',
+          group: [
+            {
+              name: '查看',
+              type: 'text',
+              round: false,
+              plain: false,
+              onClick: (row, index, scope) => {
+                this.checkProcess(row)
+              }
+            },
+            {
+              name: '编辑',
+              type: 'text',
+              round: false,
+              plain: false,
+              onClick: (row, index, scope) => {
+                this.handUpdate(row)
+              }
+            },
+            {
+              name: '删除',
+              type: 'text',
+              round: false,
+              plain: false,
+              onClick: (row, index, scope) => {
+                this.remove([row])
+              }
+            }
+          ]
+        }
+      ],
+      options: {
+        stripe: false, // 斑马纹
+        mutiSelect: true, // 多选框
+        index: false, // 显示序号, 多选则 mutiSelect
+        loading: false, // 表格动画
+        initTable: false, // 是否一挂载就加载数据
+        border: true,
+        height: 'calc(100vh - 300px)'
+      },
+      tableCheckItems: [],
+      tableData: [],
+      tableRequest: {
+        total: 0,
+        pageIndex: 1,
+        pageSize: 20,
+        searchValue: ''
+      },
+      clauseColumns: [
+        {
+          prop: 'clause',
+          label: '内容'
+        },
+        {
+          prop: 'status',
+          label: '状态',
+          width: '240px',
+          render: (h, params) => {
+            if (params.row.status === '0') {
+              return h('span', { class: 'danger-state' }, '未审核')
+            } else if (params.row.status === '1') {
+              return h('span', { class: 'success-state' }, '通过')
+            } else if (params.row.status === '2') {
+              return h('span', { class: 'warning-state' }, '作废')
+            }
+          }
+        },
+        // {
+        //   prop: 'statusKey',
+        //   label: '状态',
+        //   width: '240px',
+        //   render: (h, params) => {
+        //     // if (params.row.status !== ' ') {
+        //     //   if (params.row.status == '0') {
+        //     //     return h('span', { class: 'danger-state' }, '未审核')
+        //     //   } else if (params.row.status == '1') {
+        //     //     return h('span', { class: 'success-state' }, '通过')
+        //     //   } else if (params.row.status == '2') {
+        //     //     return h('span', { class: 'warning-state' }, '作废')
+        //     //   }
+        //     // } else {
+        //     const matchedItem = this.$enumData.extractStatus.find((item) => params.row.statusKey === item.key)
+        //     if (matchedItem) {
+        //       return h('span', { class: 'success-state' }, matchedItem.name)
+        //       // return h('span', { class: matchedItem.colorType }, matchedItem.name)
+        //     } else {
+        //       return h('span', {}, '')
+        //     }
+        //     // }
+        //   }
+        // },
+        {
+          button: true,
+          label: '操作',
+          width: '240px',
+          group: [
+            {
+              name: '编辑',
+              type: 'text',
+              statusKey: 'statusKey',
+              disableKey: [3, 4],
+              round: false,
+              plain: false,
+              onClick: (row, index, scope) => {
+                this.clauseHandUpdate(row)
+              }
+            },
+            {
+              name: '删除',
+              type: 'text',
+              statusKey: 'statusKey',
+              disableKey: [3, 4],
+              round: false,
+              plain: false,
+              onClick: (row, index, scope) => {
+                this.clauseRemove([row])
+              }
+            },
+            {
+              name: '查看抽取结果',
+              type: 'text',
+              statusKey: 'statusKey',
+              unDisableKey: '4',
+              round: false,
+              plain: false,
+              onClick: (row, index, scope) => {
+                // this.getExtractListAPI({ clauseId: row.id })
+                this.checkExtractResult(row)
+              }
+            }
+          ]
+        }
+      ],
+      clauseOptions: {
+        stripe: false, // 斑马纹
+        mutiSelect: false, // 多选框
+        index: true, // 显示序号, 多选则 mutiSelect
+        loading: false, // 表格动画
+        initTable: false, // 是否一挂载就加载数据
+        border: true,
+        height: 'calc(100vh - 470px)'
+      },
+      clauseTableCheckItems: [],
+      clauseTableData: [],
+      clauseTableRequest: {
+        total: 0,
+        pageIndex: 1,
+        pageSize: 20,
+        searchValue: ''
+      },
+      form: {
+        id: '',
+        taskName: '',
+        ossId: ''
+      },
+      taskForm: {
+        id: '',
+        ossId: '',
+        status: '',
+        taskName: '',
+        fileName: '',
+        taskType: ''
+      },
+      debounceFn: debounce(this.fetch, 500),
+      fileList: [],
+      active: 0,
+      clauseForm: {
+        id: '',
+        taskId: '',
+        clause: '',
+        status: ''
+      },
+      extractData: {
+        content: '',
+        extractDetailTable: []
+      },
+      extractDetailColumns: [
+        {
+          prop: 'headEntity',
+          label: '头实体',
+          edit: true,
+          editStatus: false,
+          onChange: (scope, oldRow) => {
+            const { row } = scope
+            if (oldRow.headEntity === row.headEntity) return
+            this.updateExtractInfoAPI(row)
+          }
+        },
+        {
+          prop: 'headEntityClass',
+          label: '头实体类',
+          edit: true,
+          editStatus: false,
+          onChange: (scope, oldRow) => {
+            const { row } = scope
+            if (oldRow.headEntity === row.headEntityClass) return
+            this.updateExtractInfoAPI(row)
+          }
+        },
+        {
+          prop: 'relation',
+          label: '关系',
+          edit: true,
+          editStatus: false,
+          onChange: (scope, oldRow) => {
+            const { row } = scope
+            if (oldRow.headEntity === row.relation) return
+            this.updateExtractInfoAPI(row)
+          }
+        },
+        {
+          prop: 'tailEntity',
+          label: '尾实体',
+          edit: true,
+          editStatus: false,
+          onChange: (scope, oldRow) => {
+            const { row } = scope
+            if (oldRow.headEntity === row.tailEntity) return
+            this.updateExtractInfoAPI(row)
+          }
+        },
+        {
+          prop: 'tailEntityClass',
+          label: '尾实体类',
+          edit: true,
+          editStatus: false,
+          onChange: (scope, oldRow) => {
+            const { row } = scope
+            if (oldRow.headEntity === row.tailEntityClass) return
+            this.updateExtractInfoAPI(row)
+          }
+        },
+        {
+          button: true,
+          label: '操作',
+          width: '120px',
+          group: [
+            {
+              name: '删除',
+              type: 'text',
+              round: false,
+              plain: false,
+              onClick: (row, index, scope) => {
+                this.removeExtractDetail([row])
+              }
+            }
+          ]
+        }
+      ],
+      extractDetailOptions: {
+        stripe: false, // 斑马纹
+        mutiSelect: false, // 多选框
+        index: true, // 显示序号, 多选则 mutiSelect
+        loading: false, // 表格动画
+        initTable: false, // 是否一挂载就加载数据
+        border: true,
+        height: '450px'
+      },
+      extractDetailRequest: {
+        total: 0,
+        pageIndex: 1,
+        pageSize: 20,
+        searchValue: ''
+      },
+      // extractDetailTableData: [{ content: 'qqq' }, { content: 'www' }, { content: 'eee' }]
+      zeroTitle: '分句',
+      oneTitle: '抽取',
+      twoTitle: '审核',
+      threeTitle: '入库',
+      taskStatus: null,
+      optionFileList:[],
+      entityClassList: [],
+      relationClassList: [],
+      addERForm: {
+        clauseId: '',
+        headEntity: '',
+        headEntityClass: '',
+        relation: '',
+        tailEntity: '',
+        tailEntityClass: ''
+      },
+      graphData: {}
+    }
+  },
+  watch: {
+    keyWord() {
+      this.tableRequest.pageIndex = 1
+      this.debounceFn()
+    }
+  },
+  mounted() {
+    this.init()
+
+  },
+  methods: {
+    init() {
+      download(2)
+      this.getTaskListAPI()
+      this.getAtlasFileAPI()
+      this.getEntityClassAPI()
+      this.getAllRelationClassAPI()
+
+    },
+    infoOptions(){
+      listTechData().then(response => {
+        this.optionFileList = response.rows;
+        console.log('logData',this.optionFileList)
+      });
+    },
+    async getAtlasFileAPI(params) {
+      try {
+        const {
+          data: { list, total }
+        } = await getAtlasFile()
+        this.fileList = list
+      } catch (error) {}
+    },
+
+    async getEntityClassAPI(params) {
+      try {
+        const {
+          data: { dataList }
+        } = await getAllEntityClass()
+        dataList.forEach((item) => {
+          this.entityClassList.push(item.name)
+        })
+      } catch (error) {}
+    },
+
+    async getAllRelationClassAPI(params) {
+      try {
+        const {
+          data: { dataList }
+        } = await getAllRelationClass()
+        dataList.forEach((item) => {
+          this.relationClassList.push(item.name)
+        })
+      } catch (error) {}
+    },
+
+    async removeTaskAPI(params) {
+      try {
+        const { code } = await removeTask(params)
+        if (code === 200) {
+          this.$message({
+            type: 'success',
+            message: '操作成功!'
+          })
+          await this.getTaskListAPI()
+          this.handleClose()
+        }
+      } catch (error) {}
+    },
+
+    async removeClauseAPI(params) {
+      try {
+        const { code } = await removeClause(params)
+        if (code === 200) {
+          this.$message({
+            type: 'success',
+            message: '操作成功!'
+          })
+          await this.getClauseListAPI({ taskId: this.taskForm.id })
+          this.clauseHandleClose()
+        }
+      } catch (error) {}
+    },
+
+    async getTaskListAPI(params) {
+      if (this.$refs.table) this.$refs.table.clearSelection()
+      const { keyWord } = this
+      const { pageSize, pageIndex } = this.tableRequest
+      await getTaskList({ pageSize, pageNum: pageIndex, ...params }).then(res=>{
+        this.tableData= res.rows
+        this.tableRequest.total= res.total
+      })
+    },
+
+    async getClauseListAPI(params) {
+      if (this.$refs.clauseTableRef) this.$refs.clauseTableRef.clearSelection()
+      const { keyWord } = this
+      const { pageSize, pageIndex } = this.clauseTableRequest
+      await getClauseList({ pageSize, pageNum: pageIndex, ...params }).then(res=>{
+        this.clauseTableRequest.total = res.total
+        this.clauseTableData = res.rows.map((el) => {
+          return { ...el, statusKey: this.taskStatus }
+        })
+      })
+    },
+
+    async getExtractListAPI(params) {
+      if (this.$refs.extractDetailTableRef) this.$refs.extractDetailTableRef.clearSelection()
+      const { keyWord } = this
+      const { pageSize, pageIndex } = this.extractDetailRequest
+      await getExtractList({ pageSize, pageNum: pageIndex, ...params }).then(res=>{
+        this.extractData.extractDetailTable = res.rows;
+        this.extractDetailRequest.total = res.total
+      })
+    },
+
+    fetch() {
+      this.getTaskListAPI()
+    },
+
+    clauseFetch() {
+      this.getClauseListAPI({ taskId: this.taskForm.id })
+    },
+
+    extractDetailFetch() {
+      this.getExtractListAPI({ clauseId: this.clauseForm.id })
+    },
+
+    async searchClick() {
+      await this.getTaskListAPI({ taskName: this.keyWordData })
+    },
+
+    async addTaskAPI() {
+      try {
+        delete this.form.aircaftModelName
+        const { code } = await addTask({ ...this.form })
+        if (code === 200) {
+          this.$message({
+            type: 'success',
+            message: '操作成功!'
+          })
+          this.handleClose()
+          await this.getTaskListAPI()
+        }
+      } catch (error) {}
+    },
+
+    async updateTaskAPI() {
+      try {
+        const { code } = await updateTask({ ...this.form })
+        if (code === 200) {
+          this.$message({
+            type: 'success',
+            message: '操作成功!'
+          })
+          this.handleClose()
+          await this.getTaskListAPI()
+        }
+      } catch (error) {}
+    },
+
+    async updateClauseAPI() {
+      try {
+        const { code } = await updateClause({ ...this.clauseForm })
+        if (code === 200) {
+          this.$message({
+            type: 'success',
+            message: '操作成功!'
+          })
+          this.clauseHandleClose()
+          this.extractHandleClose()
+          await this.getClauseListAPI({ taskId: this.taskForm.id })
+        }
+      } catch (error) {}
+    },
+
+    openDialog() {
+      this.dialogTitle = '新增'
+      this.infoOptions()
+      this.dialogVisible = true
+
+    },
+
+    handleClose() {
+      this.dialogVisible = false
+      this.form = {
+        id: '',
+        taskName: '',
+        ossId: ''
+      }
+    },
+
+    handUpdate(row) {
+      this.dialogTitle = '编辑'
+      this.form = deepClone(row)
+      this.dialogVisible = true
+    },
+
+    // 分句编辑
+    clauseHandUpdate(row) {
+      this.clauseForm = deepClone(row)
+      this.clauseDialogVisible = true
+    },
+
+    // 查看抽取结果
+    checkExtractResult(row) {
+      this.extractData.content = row.clause
+      this.clauseForm = deepClone(row)
+      this.getExtractListAPI({ clauseId: row.id })
+      this.extractDialogVisible = true
+    },
+
+    // 表格更新抽取结果
+    async updateExtractInfoAPI(row) {
+      if (this.handleVerify(row)) {
+        try {
+          console.log('row', row)
+          const { code } = await updateExtractInfo({ ...row })
+          if (code === 200) {
+            this.$message({
+              type: 'success',
+              message: '操作成功!'
+            })
+            // this.clauseHandleClose()
+            // this.getClauseListAPI({ taskId: this.taskForm.id })
+            this.getExtractListAPI({ clauseId: this.clauseForm.id })
+          }
+        } catch (error) {}
+      }fen
+    },
+
+    // 校验实体关系
+    handleVerify(data) {
+      const { headEntity, headEntityClass, relation, tailEntity, tailEntityClass } = data
+      let str = this.extractData.content
+      if (str.indexOf(headEntity) === -1 || str.indexOf(tailEntity) === -1) {
+        this.extractDetailFetch()
+        this.$message({
+          type: 'warning',
+          message: '实体与文本中匹配有误,请重新输入'
+        })
+        return false
+      }
+      if (!this.entityClassList.includes(headEntityClass) || !this.entityClassList.includes(tailEntityClass)) {
+        this.extractDetailFetch()
+        this.$message({
+          type: 'warning',
+          message: `实体类有误,请重新输入。目前实体类有<${this.entityClassList}>`,
+          duration: 5000
+        })
+        return false
+      }
+
+      if (!this.relationClassList.includes(relation)) {
+        this.extractDetailFetch()
+        this.$message({
+          type: 'warning',
+          message: `关系有误,请重新输入。目前关系有<${this.relationClassList}>`,
+          duration: 5000
+        })
+        return false
+      }
+      return true
+    },
+
+    // 新增实体关系
+    addER() {
+      this.addERDialogVisible = true
+    },
+
+    async addERSubmit() {
+      if (this.handleVerify(this.addERForm)) {
+        try {
+          this.addERForm.clauseId = this.clauseForm.id
+          const { code } = await addER({ ...this.addERForm })
+          if (code === 200) {
+            this.$message({
+              type: 'success',
+              message: '操作成功!'
+            })
+            this.addERHandleClose()
+            this.getExtractListAPI({ clauseId: this.clauseForm.id })
+          }
+        } catch (error) {}
+      }
+    },
+
+    // 作废
+    handleCancel() {
+      this.clauseForm.status = 2
+      this.$confirm('是否将该抽取结果作废?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          // this.removeTaskAPI(row.map((e) => e.id))
+          this.updateClauseAPI()
+        })
+        .catch(() => {})
+    },
+
+    // 通过
+    passThrough() {
+      this.clauseForm.status = 1
+      this.updateClauseAPI()
+    },
+
+    submit() {
+      this.$refs.form.validate((valid) => {
+        if (valid) {
+          switch (this.dialogTitle) {
+            case '编辑':
+              this.updateTaskAPI()
+
+              break
+            case '新增':
+              this.addTaskAPI()
+              break
+          }
+        }
+      })
+    },
+
+    clauseSubmit() {
+      this.updateClauseAPI()
+    },
+
+    extractSubmit() {
+      // this.updateClauseAPI()
+    },
+
+    selection(val) {
+      this.tableCheckItems = val
+    },
+
+    clauseSelection(val) {
+      this.clauseTableCheckItems = val
+    },
+
+    // extractSelection(val) {
+    //   this.extractTableCheckItems = val
+    // },
+
+    remove(row) {
+      this.$confirm('是否删除该数据', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          this.removeTaskAPI(row.map((e) => e.id))
+        })
+        .catch(() => {})
+    },
+
+    removeExtractDetail(row) {
+      console.log('row', row)
+      this.$confirm('是否删除该条实体关系', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          this.removeExtractInfoAPI(row.map((e) => e.id))
+        })
+        .catch(() => {})
+    },
+
+    async removeExtractInfoAPI(params) {
+      try {
+        const { code } = await removeExtractInfo(params)
+        if (code === 200) {
+          this.$message({
+            type: 'success',
+            message: '操作成功!'
+          })
+          await this.getExtractListAPI({ clauseId: this.clauseForm.id })
+        }
+      } catch (error) {}
+    },
+
+    clauseRemove(row) {
+      this.$confirm('是否删除该数据', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          this.removeClauseAPI(row.map((e) => e.id))
+        })
+        .catch(() => {})
+    },
+
+    checkProcess(row) {
+      this.taskStatus = row.status
+      this.taskForm = deepClone(row)
+      switch (this.taskStatus) {
+        case '0':
+          this.active = 0
+          this.zeroTitle = '待分句'
+          break
+        case '1':
+          this.active = 0
+          this.zeroTitle = '分句中'
+          break
+        case '2':
+          this.active = 1
+          this.zeroTitle = '分句'
+          this.getClauseListAPI({ taskId: row.id })
+          this.oneTitle = '待抽取'
+          break
+        case '3':
+          this.active = 1
+          this.oneTitle = '抽取中'
+          this.getClauseListAPI({ taskId: row.id })
+          break
+        case '4':
+          this.active = 2
+          this.oneTitle = '抽取'
+          this.getClauseListAPI({ taskId: row.id })
+          this.twoTitle = '审核中'
+          break
+        case '5':
+          this.active = 2
+          this.getClauseListAPI({ taskId: row.id })
+          this.twoTitle = '入库中'
+          break
+        case '6':
+          this.twoTitle = '审核'
+          this.threeTitle = '已入库'
+          this.getVisuallyAPI(row)
+          this.active = 3
+          break
+
+        default:
+          break
+      }
+      this.detailDialogVisible = true
+    },
+
+    async getVisuallyAPI(row) {
+      try {
+        const { code, data } = await getVisually({ ossId: row.ossId })
+        if (code === 200) {
+          // const newData = this.handleData(JSON.parse(data))
+          // console.log('newData', newData)
+          const categories = []
+          data.data.forEach((node) => {
+            const flag = categories.find((item) => {
+              return item.name === node.category
+            })
+            if (!flag) {
+              categories.push({ name: node.category })
+            }
+          })
+          data.categories = categories
+          this.graphData = data
+          console.log('this.graphData', this.graphData)
+        }
+      } catch (error) {}
+    },
+
+    handleData(data) {
+      if (data) {
+        // const newData = eval('(' + data + ')')
+        // data.data = graphData
+        const categories = []
+        data.data.forEach((node) => {
+          const flag = categories.find((item) => {
+            return item.name === node.category
+          })
+          if (!flag) {
+            categories.push({ name: node.category })
+          }
+        })
+        data.categories = categories
+      }
+      return data
+    },
+
+    detailHandleClose() {
+      this.detailDialogVisible = false
+      this.taskForm = {
+        id: '',
+        ossId: '',
+        status: '',
+        taskName: '',
+        fileName: '',
+        taskType: ''
+      }
+      this.clauseForm = {
+        id: '',
+        taskId: '',
+        clause: '',
+        status: ''
+      }
+    },
+
+    clauseHandleClose() {
+      this.clauseDialogVisible = false
+      this.clauseForm = {
+        id: '',
+        taskId: '',
+        clause: '',
+        status: ''
+      }
+    },
+
+    extractHandleClose() {
+      this.extractDialogVisible = false
+      this.extractData = {
+        content: '',
+        extractDetailTable: []
+      }
+    },
+
+    addERHandleClose() {
+      this.addERDialogVisible = false
+      this.addERForm = {
+        clauseId: '',
+        headEntity: '',
+        headEntityClass: '',
+        relation: '',
+        tailEntity: '',
+        tailEntityClass: ''
+      }
+    },
+
+    async handleClause() {
+      this.clauseLoading = true
+      this.taskForm.taskType = 0
+      try {
+        const { code } = await taskPro(this.taskForm)
+        if (code === 200) {
+          this.$message({
+            type: 'success',
+            message: '文件开始分句中,稍后刷新页面查看进度',
+            duration: 5000
+          })
+          this.getTaskListAPI()
+          this.detailDialogVisible = false
+          this.clauseLoading = false
+          this.active = 1
+        }
+      } catch (error) {
+        this.clauseLoading = false
+        this.$message({
+          type: 'warning',
+          message: '接口错误请联系管理员'
+        })
+      }
+    },
+
+    async handleExtract() {
+      this.extractLoading = true
+      this.taskForm.taskType = 2
+      try {
+        const { code } = await taskPro(this.taskForm)
+        if (code === 200) {
+          this.$message({
+            type: 'success',
+            message: '文件开始抽取中,稍后刷新页面查看进度',
+            duration: 5000
+          })
+          this.getTaskListAPI()
+          this.detailDialogVisible = false
+          this.extractLoading = false
+          this.active = 2
+        }
+      } catch (error) {
+        this.extractLoading = false
+        this.$message({
+          type: 'warning',
+          message: '接口错误请联系管理员'
+        })
+      }
+    },
+
+    async handleStorage() {
+      this.storageLoading = true
+      this.taskForm.taskType = 4
+      try {
+        const { code } = await taskPro(this.taskForm)
+        if (code === 200) {
+          this.$message({
+            type: 'success',
+            message: '文件开始入库中,稍后刷新页面查看进度',
+            duration: 5000
+          })
+          this.getTaskListAPI()
+          this.detailDialogVisible = false
+          this.storageLoading = false
+          this.active = 2
+        }
+      } catch (error) {
+        this.storageLoading = false
+        this.$message({
+          type: 'warning',
+          message: '接口错误请联系管理员'
+        })
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.content {
+  width: 100%;
+  height: 500px;
+  display: flex;
+  .left {
+    width: 30%;
+    padding: 20px;
+    // font-size: 1.1rem;
+    color: white;
+    border-right: 1px solid #eeeeee;
+    overflow: hidden;
+  }
+  .right {
+    width: 70%;
+  }
+}
+</style>

+ 6 - 5
gm-web/src/views/tech/techData/index.vue

@@ -110,7 +110,7 @@
     </el-row>
     <el-row :gutter="20" class="table-box">
       <el-col :span="4" class="tree-box">
-        
+
         <el-tree :data="techTypeList" :props="defaultProps" @node-click="handleNodeClick" default-expand-all></el-tree>
       </el-col>
       <el-col :span="20">
@@ -171,7 +171,7 @@
         </el-form-item>
           </el-col>
         </el-row>
-        
+
         <el-row :gutter="10">
           <el-col :span="8">
             <el-form-item label="关键字" prop="dataKeyword">
@@ -189,7 +189,7 @@
         </el-form-item>
           </el-col>
         </el-row>
-       
+
         <el-row :gutter="20">
           <el-col :span="8">
             <el-form-item label="专业" prop="dataSpeciality">
@@ -198,7 +198,7 @@
           </el-col>
           <el-col :span="8">
             <el-form-item label="文件" prop="filePath">
-          <file-upload v-model="form.filePath" :belongType="belongType" :belongId="belongId"/>
+          <file-upload :file-type="fileType" v-model="form.filePath" :belongType="belongType" :belongId="belongId"/>
         </el-form-item>
           </el-col>
           <el-col :span="8">
@@ -207,7 +207,7 @@
         </el-form-item>
           </el-col>
         </el-row>
-        
+
         <el-row :gutter="20">
           <el-col :span="8">
             <el-form-item label="描述" prop="dataDescription">
@@ -235,6 +235,7 @@ export default {
   components: { FileUpload,Treeselect },
   data() {
     return {
+      fileType:["doc","txt"],
       // 遮罩层
       loading: true,
       // 选中数组

+ 1 - 1
gm-web/vue.config.js

@@ -36,7 +36,7 @@ module.exports = {
       // detail: https://cli.vuejs.org/config/#devserver-proxy
       [process.env.VUE_APP_BASE_API]: {
         //target: `http://122.51.221.211:8080`,
-        target: `http://localhost:8080`,
+        target: `http://localhost:8085`,
         changeOrigin: true,
         pathRewrite: {
           ['^' + process.env.VUE_APP_BASE_API]: ''

+ 13 - 8
pom.xml

@@ -31,12 +31,24 @@
         <velocity.version>2.3</velocity.version>
         <jwt.version>0.9.1</jwt.version>
         <elasticsearch.version>7.17.0</elasticsearch.version>
+
+        <mybatis-plus-version>3.5.12</mybatis-plus-version>
+        <lombok-version>1.18.12</lombok-version>
     </properties>
 
     <!-- 依赖声明 -->
     <dependencyManagement>
         <dependencies>
-
+            <dependency>
+                <groupId>com.baomidou</groupId>
+                <artifactId>mybatis-plus-boot-starter</artifactId>
+                <version>${mybatis-plus-version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.projectlombok</groupId>
+                <artifactId>lombok</artifactId>
+                <version>${lombok-version}</version>
+            </dependency>
             <!-- SpringFramework的依赖配置-->
             <dependency>
                 <groupId>org.springframework</groupId>
@@ -201,13 +213,6 @@
                 <artifactId>ehcache</artifactId>
                 <version>2.10.5</version>
             </dependency>
-
-            <dependency>
-                <groupId>cn.hutool</groupId>
-                <artifactId>hutool-all</artifactId>
-                <version>5.8.16</version>
-            </dependency>
-
         </dependencies>
     </dependencyManagement>