Browse Source

2025-05-22

unknown 1 month ago
parent
commit
7948fd1265
100 changed files with 1707 additions and 120 deletions
  1. 3 8
      ruoyi-admin/pom.xml
  2. 1 10
      ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
  3. 0 0
      app-admin/src/main/java/com/ruoyi/RuoYiServletInitializer.java
  4. 14 0
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/DataReportController.java
  5. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/DataStatisticsController.java
  6. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/DeadDisposalController.java
  7. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/DistributeBatchController.java
  8. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/DryLossRatioController.java
  9. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/EntranceBatchController.java
  10. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/EntranceInspectionController.java
  11. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/HarmlessTreatmentController.java
  12. 55 36
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/HookBindController.java
  13. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/HookController.java
  14. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/HookRegisterController.java
  15. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/InspectionItemController.java
  16. 87 0
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/MonitorController.java
  17. 184 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/NFIDReadRecordController.java
  18. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/NFIDReaderController.java
  19. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/PigCategoryController.java
  20. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/PigpenController.java
  21. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/PorkOtherProduceController.java
  22. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/PorkSideProduceController.java
  23. 101 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/PorkSideProduceRecordController.java
  24. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/ProductCategoryController.java
  25. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/ProductTraceController.java
  26. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/PurchaserController.java
  27. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/RegionController.java
  28. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/SlaughterBatchController.java
  29. 5 4
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/SlaughterRelationController.java
  30. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/StaffController.java
  31. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/SupplierController.java
  32. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java
  33. 1 1
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
  34. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java
  35. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/monitor/ServerController.java
  36. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java
  37. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java
  38. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java
  39. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java
  40. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java
  41. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java
  42. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java
  43. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java
  44. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
  45. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java
  46. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java
  47. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java
  48. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java
  49. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java
  50. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
  51. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/tool/TestController.java
  52. 0 0
      app-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java
  53. 27 12
      ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/ClientHandler.java
  54. 0 0
      app-admin/src/main/java/com/ruoyi/web/core/nfid/DeviceSessionManager.java
  55. 32 44
      ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/MultiReaderNFIDProcessor.java
  56. 11 4
      ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDFrameParser.java
  57. 0 0
      app-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDRedisData.java
  58. 0 0
      app-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDServer.java
  59. 0 0
      app-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDTestClient.java
  60. 0 0
      app-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDTestClient1.java
  61. 37 0
      app-admin/src/main/java/com/ruoyi/web/core/wvp/ApiResponseParser.java
  62. 107 0
      app-admin/src/main/java/com/ruoyi/web/core/wvp/DeviceHandler.java
  63. 70 0
      app-admin/src/main/java/com/ruoyi/web/core/wvp/JsonParser.java
  64. 127 0
      app-admin/src/main/java/com/ruoyi/web/core/wvp/SessionHandler.java
  65. 38 0
      app-admin/src/main/java/com/ruoyi/web/core/wvp/domain/ApiResponse.java
  66. 612 0
      app-admin/src/main/java/com/ruoyi/web/core/wvp/domain/DeviceChannelExtend.java
  67. 15 0
      app-admin/src/main/java/com/ruoyi/web/core/wvp/domain/DeviceChannelList.java
  68. 170 0
      app-admin/src/main/java/com/ruoyi/web/core/wvp/domain/Login.java
  69. 0 0
      app-admin/src/main/resources/META-INF/spring-devtools.properties
  70. 0 0
      app-admin/src/main/resources/application-druid.yml
  71. 9 0
      ruoyi-admin/src/main/resources/application.yml
  72. 0 0
      app-admin/src/main/resources/banner.txt
  73. 0 0
      app-admin/src/main/resources/i18n/messages.properties
  74. 0 0
      app-admin/src/main/resources/logback.xml
  75. 0 0
      app-admin/src/main/resources/mybatis/mybatis-config.xml
  76. 1 1
      ruoyi-common/pom.xml
  77. 0 0
      app-common/src/main/java/com/ruoyi/common/annotation/Anonymous.java
  78. 0 0
      app-common/src/main/java/com/ruoyi/common/annotation/DataScope.java
  79. 0 0
      app-common/src/main/java/com/ruoyi/common/annotation/DataSource.java
  80. 0 0
      app-common/src/main/java/com/ruoyi/common/annotation/Excel.java
  81. 0 0
      app-common/src/main/java/com/ruoyi/common/annotation/Excels.java
  82. 0 0
      app-common/src/main/java/com/ruoyi/common/annotation/Log.java
  83. 0 0
      app-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java
  84. 0 0
      app-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java
  85. 0 0
      app-common/src/main/java/com/ruoyi/common/annotation/Sensitive.java
  86. 0 0
      app-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java
  87. 0 0
      app-common/src/main/java/com/ruoyi/common/config/serializer/SensitiveJsonSerializer.java
  88. 0 0
      app-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java
  89. 0 0
      app-common/src/main/java/com/ruoyi/common/constant/Constants.java
  90. 0 0
      app-common/src/main/java/com/ruoyi/common/constant/GenConstants.java
  91. 0 0
      app-common/src/main/java/com/ruoyi/common/constant/HttpStatus.java
  92. 0 0
      app-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java
  93. 0 0
      app-common/src/main/java/com/ruoyi/common/constant/UserConstants.java
  94. 0 0
      app-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java
  95. 0 0
      app-common/src/main/java/com/ruoyi/common/core/domain/AjaxResult.java
  96. 0 0
      app-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java
  97. 0 0
      app-common/src/main/java/com/ruoyi/common/core/domain/R.java
  98. 0 0
      app-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java
  99. 0 0
      app-common/src/main/java/com/ruoyi/common/core/domain/TreeSelect.java
  100. 0 0
      ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java

+ 3 - 8
ruoyi-admin/pom.xml

@@ -9,7 +9,7 @@
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <packaging>jar</packaging>
-    <artifactId>ruoyi-admin</artifactId>
+    <artifactId>app-admin</artifactId>
 
     <description>
         web服务入口
@@ -46,20 +46,15 @@
         <!-- 核心模块-->
         <dependency>
             <groupId>com.ruoyi</groupId>
-            <artifactId>ruoyi-framework</artifactId>
+            <artifactId>app-framework</artifactId>
         </dependency>
 
         <!-- 定时任务-->
         <dependency>
             <groupId>com.ruoyi</groupId>
-            <artifactId>ruoyi-quartz</artifactId>
+            <artifactId>app-quartz</artifactId>
         </dependency>
 
-        <!-- 代码生成-->
-        <dependency>
-            <groupId>com.ruoyi</groupId>
-            <artifactId>ruoyi-generator</artifactId>
-        </dependency>
         <!--事件处理-->
         <dependency>
             <groupId>com.lmax</groupId>

+ 1 - 10
ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java

@@ -1,5 +1,6 @@
 package com.ruoyi;
 
+import com.ruoyi.common.server.EnvInputServer;
 import com.ruoyi.web.core.nfid.NFIDServer;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -21,15 +22,5 @@ public class RuoYiApplication
         applicationContext.getBean(NFIDServer.class).start();
         // EnvInputServer
         //applicationContext.getBean(EnvInputServer.class).run();
-        System.out.println("(♥◠‿◠)ノ゙  若依启动成功   ლ(´ڡ`ლ)゙  \n" +
-                " .-------.       ____     __        \n" +
-                " |  _ _   \\      \\   \\   /  /    \n" +
-                " | ( ' )  |       \\  _. /  '       \n" +
-                " |(_ o _) /        _( )_ .'         \n" +
-                " | (_,_).' __  ___(_ o _)'          \n" +
-                " |  |\\ \\  |  ||   |(_,_)'         \n" +
-                " |  | \\ `'   /|   `-'  /           \n" +
-                " |  |  \\    /  \\      /           \n" +
-                " ''-'   `'-'    `-..-'              ");
     }
 }

ruoyi-admin/src/main/java/com/ruoyi/RuoYiServletInitializer.java → app-admin/src/main/java/com/ruoyi/RuoYiServletInitializer.java


+ 14 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/DataReportController.java

@@ -1,9 +1,11 @@
 package com.ruoyi.web.controller.app;
 
 import com.ruoyi.app.DTO.EntranceReportDTO;
+import com.ruoyi.app.DTO.PurchaserProduceTotalDTO;
 import com.ruoyi.app.DTO.SlaughterReportDTO;
 import com.ruoyi.app.domain.request.ReqEntranceReport;
 
+import com.ruoyi.app.domain.request.ReqGetPorkSideProduceRecord;
 import com.ruoyi.app.domain.request.ReqSlaughterReport;
 import com.ruoyi.app.service.IDataReportService;
 
@@ -64,4 +66,16 @@ public class DataReportController extends BaseController {
         List<SlaughterReportDTO> list = dataReportService.selectSlaughterReport(reqSlaughterReport);
         return getDataTable(list);
     }
+
+    /**
+     * 获取称重统计
+     */
+    @PreAuthorize("@ss.hasPermi('app:dataReport:getWeightReport')")
+    @GetMapping(value = "/getWeightReport")
+    public TableDataInfo getWeightReport(ReqGetPorkSideProduceRecord req)
+    {
+        startPage();
+        List<PurchaserProduceTotalDTO> list = dataReportService.selectPurchaserProduceTotal(req);
+        return getDataTable(list);
+    }
 }

ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/DataStatisticsController.java → app-admin/src/main/java/com/ruoyi/web/controller/app/DataStatisticsController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/DeadDisposalController.java → app-admin/src/main/java/com/ruoyi/web/controller/app/DeadDisposalController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/DistributeBatchController.java → app-admin/src/main/java/com/ruoyi/web/controller/app/DistributeBatchController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/DryLossRatioController.java → app-admin/src/main/java/com/ruoyi/web/controller/app/DryLossRatioController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/EntranceBatchController.java → app-admin/src/main/java/com/ruoyi/web/controller/app/EntranceBatchController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/EntranceInspectionController.java → app-admin/src/main/java/com/ruoyi/web/controller/app/EntranceInspectionController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/HarmlessTreatmentController.java → app-admin/src/main/java/com/ruoyi/web/controller/app/HarmlessTreatmentController.java


+ 55 - 36
ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/HookBindController.java

@@ -11,6 +11,7 @@ import com.ruoyi.app.domain.request.ReqHookBindDetail;
 import com.ruoyi.app.domain.request.ReqHookBindList;
 import com.ruoyi.common.utils.DateUtils;
 import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.uuid.IdUtils;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -94,7 +95,7 @@ public class HookBindController extends BaseController
     @GetMapping(value = "/group")
     public AjaxResult getGroupInfo(@Validated ReqHookBindDetail req)
     {
-        return success(hookBindService.selectHookBindByBatch(req.getGroupId()));
+        return success(hookBindService.selectHookBindByBatch(req.getBatchNo()));
     }
 
     /**
@@ -104,7 +105,7 @@ public class HookBindController extends BaseController
     @GetMapping(value = "/detail/{hookNo}")
     public AjaxResult getDetail(@PathVariable("hookNo") String hookNo)
     {
-        return success(hookBindService.selectHookBindDetail(hookNo));
+        return success(hookBindService.selectHookBindOnlyDetail(hookNo));
     }
 
     /**
@@ -129,41 +130,47 @@ public class HookBindController extends BaseController
     @PostMapping("/addBatch")
     public AjaxResult addBatch(@Validated  @RequestBody AddHookBindBatch req)
     {
-        //生成新对象
-        String[] hooks = req.getHookNoList().split(",");
-        List<HookBind> hookBindArr = new ArrayList<>();
-        String batchNo = fastSimpleUUID();
-        //先判断本身数组内是否有重复的
-        Set<String> uniqueIds = new HashSet<>();
-        //未传绑定时间默认当前时间
-        if(req.getBindTime() == null){
-            req.setBindTime(DateUtils.getNowDate());
-        }
-        for(String hook : hooks){
-            //noinspection ConstantConditions  忽略错误的IDEA提示
-            if (!uniqueIds.add(hook)) {
-                return error("新增吊钩批量绑定,本次添加存在相同的吊钩号");
+        try {
+            //生成新对象
+            List<HookBind> hookBindArr = new ArrayList<>();
+            String batchNo = fastSimpleUUID();
+            //先判断本身数组内是否有重复的
+            Set<String> uniqueIds = new HashSet<>();
+
+            for (String hook : req.getHookNoListArr()) {
+                //noinspection ConstantConditions  忽略错误的IDEA提示
+                if (!uniqueIds.add(hook)) {
+                    return error("新增吊钩批量绑定,本次添加存在相同的吊钩号");
+                }
+                HookBind hookBind = new HookBind();
+                hookBind.setBatchNo(batchNo);
+                hookBind.setHookNo(hook);
+                hookBind.setBindTime(req.getBindTime());
+                hookBind.setDistributeBatchId(req.getDistributeBatchId());
+                hookBind.setSlaughterCode(req.getSlaughterCode());
+                hookBind.setCreateTime(DateUtils.getNowDate());
+                hookBind.setCreateBy(getUsername());
+
+                //未传绑定时间默认当前时间
+                if (req.getBindTime() == null) {
+                    hookBind.setBindTime(DateUtils.getNowDate());
+                }else{
+                    hookBind.setBindTime(req.getBindTime());
+                }
+                hookBindArr.add(hookBind);
             }
-            HookBind hookBind = new HookBind();
-            hookBind.setBatchNo(batchNo);
-            hookBind.setHookNo(hook);
-            hookBind.setBindTime(req.getBindTime());
-            hookBind.setDistributeBatchId(req.getDistributeBatchId());
-            hookBind.setSlaughterCode(req.getSlaughterCode());
-            hookBind.setCreateTime(DateUtils.getNowDate());
-            hookBind.setCreateBy(getUsername());
-            hookBindArr.add(hookBind);
-        }
-        //校验数据库的
-        for (HookBind hookBind : hookBindArr) {
+            //校验数据库的
+            for (HookBind hookBind : hookBindArr) {
 
-            HookBind check = hookBindService.checkHookNoUnique(hookBind);
-            if (StringUtils.isNotNull(check))
-            {
-                return error("新增吊钩批量绑定失败,'" + check.getHookNo() + "'同一时间已存在绑定");
+                HookBind check = hookBindService.checkHookNoUnique(hookBind);
+                if (StringUtils.isNotNull(check)) {
+                    return error("新增吊钩批量绑定失败,'" + check.getHookNo() + "'同一时间已存在绑定");
+                }
             }
+            return toAjax(hookBindService.insertHookBindBatch(hookBindArr,req.getHookNoListArr()));
+        }catch(Exception e) {
+                return error("新增吊钩批量绑定失败:"+e.getMessage());
         }
-        return toAjax(hookBindService.insertHookBindBatch(hookBindArr));
     }
 
     /**
@@ -199,9 +206,21 @@ public class HookBindController extends BaseController
     @ApiOperation("删除吊钩绑定")
     @PreAuthorize("@ss.hasPermi('app:hookBind:remove')")
     @Log(title = "吊钩绑定", businessType = BusinessType.DELETE)
-	@DeleteMapping("/{ids}")
-    public AjaxResult remove(@PathVariable String[] ids)
+	@DeleteMapping("/{batchNos}")
+    public AjaxResult remove(@PathVariable String[] batchNos)
+    {
+        return toAjax(hookBindService.deleteHookBindByIds(batchNos));
+    }
+
+    /**
+     * 清除吊钩绑定关系-不删除数据只是将绑定关系设置为未绑定
+     */
+    @ApiOperation("清除吊钩绑定关系")
+    @PreAuthorize("@ss.hasPermi('app:hookBind:clean')")
+    @Log(title = "吊钩绑定", businessType = BusinessType.UPDATE)
+    @PostMapping("/cleanBind")
+    public AjaxResult cleanBind()
     {
-        return toAjax(hookBindService.deleteHookBindByIds(ids));
+        return AjaxResult.success(hookBindService.cleanHookBind());
     }
 }

ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/HookController.java → app-admin/src/main/java/com/ruoyi/web/controller/app/HookController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/HookRegisterController.java → app-admin/src/main/java/com/ruoyi/web/controller/app/HookRegisterController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/InspectionItemController.java → app-admin/src/main/java/com/ruoyi/web/controller/app/InspectionItemController.java


+ 87 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/MonitorController.java

@@ -1,10 +1,17 @@
 package com.ruoyi.web.controller.app;
 
+import java.util.Date;
 import java.util.List;
+import java.util.stream.Collectors;
 import javax.servlet.http.HttpServletResponse;
 
+import com.ruoyi.app.domain.request.ReqMonitorAction;
+import com.ruoyi.web.core.wvp.domain.DeviceChannelExtend;
+import com.ruoyi.common.utils.DateUtils;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
@@ -24,6 +31,7 @@ import com.ruoyi.app.domain.Monitor;
 import com.ruoyi.app.service.IMonitorService;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.web.core.wvp.DeviceHandler;
 
 /**
  * 监控设备Controller
@@ -39,6 +47,10 @@ public class MonitorController extends BaseController
     @Autowired
     private IMonitorService monitorService;
 
+    @Autowired
+    private DeviceHandler deviceHandler;
+
+    public static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);
     /**
      * 查询监控设备列表
      */
@@ -95,6 +107,39 @@ public class MonitorController extends BaseController
     }
 
     /**
+     * 同步监控设备
+     */
+    @ApiOperation("同步监控设备")
+    @PreAuthorize("@ss.hasPermi('app:monitor:sync')")
+    @Log(title = "监控设备", businessType = BusinessType.INSERT)
+    @PostMapping("/sync")
+    public AjaxResult sync()
+    {
+        try {
+            //获取WVP所有的设备通道
+            List<DeviceChannelExtend> channelList = deviceHandler.getDeviceList();
+            Date now = DateUtils.getNowDate();
+            List<Monitor> monitorArr = channelList.stream()
+                    .map(item -> {
+                        Monitor monitor = new Monitor();
+                        monitor.setMonitorName(item.getName());
+                        monitor.setIpAddr(item.getIpAddress());
+                        monitor.setMonitorBrand(item.getManufacture());
+                        monitor.setDeviceId(item.getDeviceId());
+                        monitor.setChannelId(item.getChannelId());
+                        monitor.setCreateTime(now);
+                        monitor.setCreateBy(getUsername());
+                        return monitor;
+                    })
+                    .collect(Collectors.toList());
+            return toAjax(monitorService.syncMonitor(monitorArr));
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return error("同步失败");
+        }
+    }
+
+    /**
      * 修改监控设备
      */
     @ApiOperation("修改监控设备")
@@ -122,4 +167,46 @@ public class MonitorController extends BaseController
     {
         return toAjax(monitorService.deleteMonitorByIds(ids));
     }
+
+    /**
+     * 播放监控设备
+     */
+    @ApiOperation("播放监控设备")
+    @PreAuthorize("@ss.hasPermi('app:monitor:playStart')")
+    @Log(title = "监控设备", businessType = BusinessType.OTHER)
+    @PostMapping("/playStart")
+    public AjaxResult playStart(@Validated @RequestBody ReqMonitorAction req)
+    {
+        try{
+        Object res = deviceHandler.playOrStop(DeviceHandler.VIDEO_PLAY_START,req.getDeviceId(),req.getChannelId());
+            if (res != null){
+                return AjaxResult.success(res);
+            }else{
+                throw new RuntimeException("无视频信息,请重试");
+            }
+        }catch (Exception e){
+            return error("播放失败:"+e.getMessage());
+        }
+    }
+
+    /**
+     * 停止监控设备
+     */
+    @ApiOperation("停止监控设备")
+    @PreAuthorize("@ss.hasPermi('app:monitor:playStop')")
+    @Log(title = "监控设备", businessType = BusinessType.OTHER)
+    @PostMapping("/playStop")
+    public AjaxResult playStop(@Validated @RequestBody ReqMonitorAction req)
+    {
+        try{
+            Object res = deviceHandler.playOrStop(DeviceHandler.VIDEO_PLAY_STOP,req.getDeviceId(),req.getChannelId());
+            if (res != null){
+                return AjaxResult.success(res);
+            }else{
+                throw new RuntimeException("无视频信息,请重试");
+            }
+        }catch (Exception e){
+            return error("停止失败:"+e.getMessage());
+        }
+    }
 }

+ 184 - 0
app-admin/src/main/java/com/ruoyi/web/controller/app/NFIDReadRecordController.java

@@ -0,0 +1,184 @@
+package com.ruoyi.web.controller.app;
+
+
+import com.ruoyi.app.DTO.NFIDReadGroupDTO;
+import com.ruoyi.app.domain.NFIDReadRecord;
+import com.ruoyi.app.domain.NFIDReaderEvent;
+import com.ruoyi.app.domain.request.ReqValidNFIDRecord;
+import com.ruoyi.app.service.INFIDReadRecordService;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.context.event.EventListener;
+import org.springframework.http.MediaType;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+
+/**
+ * nfid识别记录Controller
+ *
+ */
+@Api("nfid识别记录信息管理")
+@RestController
+@RequestMapping("/app/NFIDReadRecord")
+public class NFIDReadRecordController extends BaseController
+{
+    @Autowired
+    private INFIDReadRecordService NFIDReadRecordService;
+
+    // 存储所有客户端的 SSE 连接(Key: 客户端ID,Value: SseEmitter)
+    private final Map<String, SseEmitter> emitters = new ConcurrentHashMap<>();
+
+    private final ApplicationEventPublisher eventPublisher;
+
+    // 注入事件发布器
+    public NFIDReadRecordController(ApplicationEventPublisher eventPublisher) {
+        this.eventPublisher = eventPublisher;
+    }
+
+
+    public static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);
+
+    /**
+     * 查询nfid识别记录列表
+     */
+    @ApiOperation("查询nfid识别记录列表")
+    @PreAuthorize("@ss.hasPermi('app:NFIDReadRecord:list')")
+    @GetMapping("/list")
+    public TableDataInfo list()
+    {
+        startPage();
+        List<NFIDReadRecord> list = NFIDReadRecordService.selectNFIDReadRecordList();
+        return getDataTable(list);
+    }
+
+    /**
+     * 查询nfid识别记录分组结果
+     */
+    @ApiOperation("查询nfid识别记录分组结果")
+    @PreAuthorize("@ss.hasPermi('app:NFIDReadRecord:list')")
+    @GetMapping("/groupList")
+    public AjaxResult groupList()
+    {
+        List<NFIDReadGroupDTO> list = NFIDReadRecordService.selectNFIDReadByGroup();
+        return success(list);
+    }
+
+    /**
+     * 查询nfid识别记录分组详情清单
+     */
+    @ApiOperation("查询nfid识别记录分组详情清单")
+    @PreAuthorize("@ss.hasPermi('app:NFIDReadRecord:list')")
+    @GetMapping("/groupDetail")
+    public AjaxResult groupDetail(ReqValidNFIDRecord req)
+    {
+        List<NFIDReadRecord> list = NFIDReadRecordService.selectNFIDReadRecordListByGroup(req);
+        return success(list);
+    }
+
+    /**
+     * 查询可用的nfid识别记录列表
+     */
+    @ApiOperation("查询可用的nfid识别记录列表")
+    @PreAuthorize("@ss.hasPermi('app:NFIDReadRecord:list')")
+    @GetMapping("/validList")
+    public AjaxResult validList(ReqValidNFIDRecord req)
+    {
+        List<NFIDReadRecord> list = NFIDReadRecordService.selectValidNFIDReadRecord(req);
+        return success(list);
+
+    }
+
+    /**
+     * 新增nfid识别记录
+     */
+    @ApiOperation("新增nfid识别记录")
+    @PreAuthorize("@ss.hasPermi('app:NFIDReadRecord:add')")
+    @Log(title = "nfid识别记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated  @RequestBody NFIDReadRecord record)
+    {
+
+        return toAjax(NFIDReadRecordService.insertNFIDReadRecord(record));
+    }
+
+    /**
+     * 客户端订阅识别记录数据
+     */
+    @GetMapping(value = "/subscribe/{clientId}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
+    public SseEmitter subscribe(@PathVariable String clientId) {
+            SseEmitter emitter = new SseEmitter(30_000L); // 超时时间 30 秒
+            emitters.put(clientId, emitter);
+            //定期发送心跳
+            ExecutorService executor = Executors.newSingleThreadExecutor();
+            executor.execute(() -> {
+                try {
+                    while (true) {
+                        emitter.send(SseEmitter.event()
+                                .comment("ping") // 心跳消息
+                                .reconnectTime(5000)); // 重连时间建议
+                        Thread.sleep(10_000); // 每10秒一次心跳
+                    }
+                } catch (Exception e) {
+                    emitter.completeWithError(e);
+                }
+            });
+            // 监听连接断开
+            emitter.onCompletion(() -> emitters.remove(clientId));
+            emitter.onTimeout(() -> emitters.remove(clientId));
+
+            return emitter;
+    }
+
+    /**
+     * 客户端主动取消订阅
+     */
+    @PostMapping("/unsubscribe/{clientId}")
+    public void unsubscribe(@PathVariable String clientId) {
+        SseEmitter emitter = emitters.get(clientId);
+        if (emitter != null) {
+            emitter.complete();
+            emitters.remove(clientId);
+        }
+    }
+
+    // 监听设备数据事件并广播
+    @EventListener
+    public void handleReaderData(NFIDReaderEvent event) {
+        NFIDReadRecord data = event.getData();
+        System.out.println(data);
+        emitters.forEach((clientId, emitter) -> {
+
+            try {
+                emitter.send(SseEmitter.event()
+                        .data(data)
+                        .id(String.valueOf(data.getId()))
+                        .name("reader-data"));
+            } catch (IOException e) {
+                emitter.completeWithError(e);
+                emitters.remove(clientId);
+            }
+        });
+    }
+
+
+}

ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/NFIDReaderController.java → app-admin/src/main/java/com/ruoyi/web/controller/app/NFIDReaderController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/PigCategoryController.java → app-admin/src/main/java/com/ruoyi/web/controller/app/PigCategoryController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/PigpenController.java → app-admin/src/main/java/com/ruoyi/web/controller/app/PigpenController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/PorkOtherProduceController.java → app-admin/src/main/java/com/ruoyi/web/controller/app/PorkOtherProduceController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/PorkSideProduceController.java → app-admin/src/main/java/com/ruoyi/web/controller/app/PorkSideProduceController.java


+ 101 - 0
app-admin/src/main/java/com/ruoyi/web/controller/app/PorkSideProduceRecordController.java

@@ -0,0 +1,101 @@
+package com.ruoyi.web.controller.app;
+
+import com.ruoyi.app.DTO.HookBindDetailDTO;
+import com.ruoyi.app.DTO.PorkSideProduceRecordDTO;
+import com.ruoyi.app.domain.PorkSideProduceRecord;
+import com.ruoyi.app.domain.request.ReqGetPorkSideProduceRecord;
+import com.ruoyi.app.service.IHookBindService;
+import com.ruoyi.app.service.IPorkSideProduceRecordService;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.DateUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 白条生产录入记录Controller
+ * 
+ * @author coede
+ * @date 2025-05-09
+ */
+@Api("白条生产录入记录信息管理")
+@RestController
+@RequestMapping("/app/porkSideProduceRecord")
+public class PorkSideProduceRecordController extends BaseController
+{
+    @Autowired
+    private IPorkSideProduceRecordService PorkSideProduceRecordService;
+
+    /**
+     * 查询白条生产录入记录列表
+     */
+    @ApiOperation("查询白条生产录入记录列表")
+    @PreAuthorize("@ss.hasPermi('app:porkSideProduceRecord:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(ReqGetPorkSideProduceRecord req)
+    {
+        startPage();
+        List<PorkSideProduceRecordDTO> list = PorkSideProduceRecordService.selectPorkSideProduceRecordList(req);
+        return getDataTable(list);
+    }
+
+    /**
+     * 获取白条生产录入记录详细信息
+     */
+    @ApiOperation("获取白条生产录入记录详细信息")
+    @PreAuthorize("@ss.hasPermi('app:porkSideProduceRecord:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return success(PorkSideProduceRecordService.selectPorkSideProduceRecordById(id));
+    }
+
+    /**
+     * 新增白条生产录入记录
+     */
+    @ApiOperation("新增白条生产录入记录")
+    @PreAuthorize("@ss.hasPermi('app:porkSideProduceRecord:add')")
+    @Log(title = "白条生产录入记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody PorkSideProduceRecord req)
+    {
+        req.setProductName(PorkSideProduceRecord.DEFAULT_NAME);
+        req.setProduceTime(DateUtils.getNowDate());
+        req.setCreateBy(getUsername());
+        return toAjax(PorkSideProduceRecordService.insertPorkSideProduceRecord(req));
+    }
+
+    /**
+     * 修改白条生产录入记录
+     */
+    @ApiOperation("修改白条生产录入记录")
+    @PreAuthorize("@ss.hasPermi('app:porkSideProduceRecord:edit')")
+    @Log(title = "白条生产录入记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody PorkSideProduceRecord PorkSideProduceRecord)
+    {
+        PorkSideProduceRecord.setUpdateBy(getUsername());
+        return toAjax(PorkSideProduceRecordService.updatePorkSideProduceRecord(PorkSideProduceRecord));
+    }
+
+    /**
+     * 删除白条生产录入记录
+     */
+    @ApiOperation("删除白条生产录入记录")
+    @PreAuthorize("@ss.hasPermi('app:porkSideProduceRecord:remove')")
+    @Log(title = "白条生产录入记录", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(PorkSideProduceRecordService.deletePorkSideProduceRecordByIds(ids));
+    }
+}

ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/ProductCategoryController.java → app-admin/src/main/java/com/ruoyi/web/controller/app/ProductCategoryController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/ProductTraceController.java → app-admin/src/main/java/com/ruoyi/web/controller/app/ProductTraceController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/PurchaserController.java → app-admin/src/main/java/com/ruoyi/web/controller/app/PurchaserController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/RegionController.java → app-admin/src/main/java/com/ruoyi/web/controller/app/RegionController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/SlaughterBatchController.java → app-admin/src/main/java/com/ruoyi/web/controller/app/SlaughterBatchController.java


+ 5 - 4
ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/SlaughterRelationController.java

@@ -11,6 +11,7 @@ import com.ruoyi.app.domain.Purchaser;
 import com.ruoyi.app.domain.request.AddSlaughterRelationBatch;
 import com.ruoyi.app.domain.request.ExportSlaughterRelation;
 import com.ruoyi.app.domain.request.ReqGetSlaughterRelation;
+import com.ruoyi.app.domain.request.ReqSlaughterRelation;
 import com.ruoyi.app.domain.response.RespGetSlaughterRelation;
 import com.ruoyi.common.utils.DateUtils;
 import com.ruoyi.common.utils.StringUtils;
@@ -67,10 +68,10 @@ public class SlaughterRelationController extends BaseController
      */
     @ApiOperation("查询血码关系列表")
     @GetMapping("/list")
-    public TableDataInfo list(SlaughterRelation slaughterRelation)
+    public TableDataInfo list(ReqSlaughterRelation req)
     {
         startPage();
-        List<SlaughterRelation> list = slaughterRelationService.selectSlaughterRelationList(slaughterRelation);
+        List<SlaughterRelation> list = slaughterRelationService.selectSlaughterRelationList(req);
         return getDataTable(list);
     }
 
@@ -216,10 +217,10 @@ public class SlaughterRelationController extends BaseController
      */
     @ApiOperation("查询全部血码关系列表")
     @GetMapping("/optionselect")
-    public AjaxResult optionselect(SlaughterRelation slaughterRelation)
+    public AjaxResult optionselect(ReqSlaughterRelation req)
     {
 
-        List<SlaughterRelation> list = slaughterRelationService.selectSlaughterRelationList(slaughterRelation);
+        List<SlaughterRelation> list = slaughterRelationService.selectSlaughterRelationList(req);
         return success(list);
     }
 }

ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/StaffController.java → app-admin/src/main/java/com/ruoyi/web/controller/app/StaffController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/SupplierController.java → app-admin/src/main/java/com/ruoyi/web/controller/app/SupplierController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java → app-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java


+ 1 - 1
ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java

@@ -105,7 +105,7 @@ public class CommonController
     }
 
     /**
-     * 通用上传请求(单个)
+     * 上传PDF文件并解析
      */
     @PostMapping("/uploadAndParse")
     public AjaxResult uploadAndParse(MultipartFile file) throws Exception

ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java → app-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/ServerController.java → app-admin/src/main/java/com/ruoyi/web/controller/monitor/ServerController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java → app-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java → app-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java → app-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java → app-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java → app-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java → app-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java → app-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java → app-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java → app-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java → app-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java → app-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java → app-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java → app-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java → app-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java → app-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java


ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/TestController.java → app-admin/src/main/java/com/ruoyi/web/controller/tool/TestController.java


ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java → app-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java


+ 27 - 12
ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/ClientHandler.java

@@ -32,6 +32,8 @@ public class ClientHandler extends ChannelInboundHandlerAdapter {
 
         // 识别器连接后发送读取识别器设备信息指令
         ByteBuf handshake = Unpooled.wrappedBuffer(HexUtil.hexToBytes("5A000101000000DCE5"));
+        //识别器连接后发送读取标签指令
+        sendReadResponseFrame(ctx);
         ctx.writeAndFlush(handshake);
     }
 
@@ -47,23 +49,29 @@ public class ClientHandler extends ChannelInboundHandlerAdapter {
 
             if (!frames.isEmpty()) {
                 // 处理帧
-                processFrames(ctx, frames);
+                processFrames(ctx, frames,bytes);
             }
         } finally {
             ReferenceCountUtil.release(msg); // 释放ByteBuf
         }
     }
 
-    private void processFrames(ChannelHandlerContext ctx, List<NFIDFrameParser.NFIDFrame> frames) {
+    private void processFrames(ChannelHandlerContext ctx, List<NFIDFrameParser.NFIDFrame> frames,byte[] bytes) {
         for (NFIDFrameParser.NFIDFrame frame : frames) {
             // 记录接收到的帧
-            System.out.println("Received frame: " + frame);
-
-            // 检查是否需要响应
-            if (NFIDFrameParser.isResponseRequiredFrame(frame)) {
-                //发送读取指令
-                sendResponseFrame(ctx);
+           //System.out.println("Received frame: " + frame);
+
+//            // 检查是否可以发送读取
+//            if (NFIDFrameParser.isReadResponseRequiredFrame(frame)) {
+//                //发送读取指令
+//                sendReadResponseFrame(ctx);
+//            }
+            // 检查是否需要发送连接状态确认的响应
+            if (NFIDFrameParser.isStatusResponseRequiredFrame(frame)) {
+                //发送响应指令
+                sendStatusResponseFrame(ctx,bytes);
             }
+
             // 检查是否读写器信息帧
             if (NFIDFrameParser.isDeviceInfoFrame(frame)) {
                 // 首次连接时注册设备
@@ -87,6 +95,7 @@ public class ClientHandler extends ChannelInboundHandlerAdapter {
                 if (params != null && params.size() > 0) {
                     String reader =  DeviceSessionManager.getDeviceId(ctx.channel());
                     if (reader !=null && !reader.equals("")) {
+//                        System.out.println("天线:"+ctx.channel().id().asLongText());
                         processor.receiveTag(tag, reader);
                     }
                 }
@@ -97,12 +106,18 @@ public class ClientHandler extends ChannelInboundHandlerAdapter {
        // frameHandler.handleFrames(frames, ctx);
     }
 
-    //向读写器发送指令
-    private void sendResponseFrame(ChannelHandlerContext ctx) {
+    //向读写器发送读取指令
+    private void sendReadResponseFrame(ChannelHandlerContext ctx) {
         int index = responseIndex.getAndUpdate(i -> i < 4 ? i + 1 : 1);
-        byte[] response = NFIDFrameParser.generateResponseFrame(index);
+        byte[] response = NFIDFrameParser.generateReadResponseFrame(index);
         ctx.writeAndFlush(Unpooled.wrappedBuffer(response));
-        System.out.println("Sent response frame with index: " + index);
+        System.out.println("Sent read response frame with index: " + index);
+    }
+
+    //向读写器发送状态确认指令
+    private void sendStatusResponseFrame(ChannelHandlerContext ctx,byte[] bytes) {
+        ctx.writeAndFlush(Unpooled.wrappedBuffer(bytes));
+       // System.out.println("Sent status confirm response frame" );
     }
 
     @Override

ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/DeviceSessionManager.java → app-admin/src/main/java/com/ruoyi/web/core/nfid/DeviceSessionManager.java


+ 32 - 44
ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/MultiReaderNFIDProcessor.java

@@ -8,11 +8,9 @@ import com.lmax.disruptor.dsl.ProducerType;
 import com.ruoyi.app.DTO.HookBindBatchListDTO;
 import com.ruoyi.app.DTO.HookBindDetailDTO;
 import com.ruoyi.app.domain.HookBind;
+import com.ruoyi.app.domain.NFIDReadRecord;
 import com.ruoyi.app.domain.PorkSideProduce;
-import com.ruoyi.app.service.IHookBindService;
-import com.ruoyi.app.service.IHookRegisterService;
-import com.ruoyi.app.service.INFIDReaderService;
-import com.ruoyi.app.service.IPorkSideProduceService;
+import com.ruoyi.app.service.*;
 import com.ruoyi.common.utils.DateUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.dao.DataAccessException;
@@ -33,12 +31,12 @@ import javax.annotation.PreDestroy;
 public class MultiReaderNFIDProcessor {
     // 配置参数
     private static final int BUFFER_FLUSH_SIZE = 200;
-    private static final long BUFFER_FLUSH_INTERVAL_MS = 3000;
-    private static final long TAG_EXPIRY_MS = 30000;
+    private static final long BUFFER_FLUSH_INTERVAL_MS = 1000;
+    private static final long TAG_EXPIRY_MS = 6*60*60*1000;
     private static final int DISRUPTOR_BUFFER_SIZE = 1024 * 8;
 
     @Autowired
-    private RedisTemplate<String,String> redisTemplate;
+    private RedisTemplate redisTemplate;
 
     @Autowired
     private IHookRegisterService hookRegisterService;
@@ -50,6 +48,9 @@ public class MultiReaderNFIDProcessor {
     private IHookBindService hookBindService;
 
     @Autowired
+    private INFIDReadRecordService NFIDReadRecordService;
+
+    @Autowired
     private IPorkSideProduceService porkSideProduceService;
 
     @PreDestroy
@@ -60,7 +61,6 @@ public class MultiReaderNFIDProcessor {
     }
 
     // 数据结构
-    private final ConcurrentHashMap<String, ReaderInfo> readers = new ConcurrentHashMap<>();
     //private final ConcurrentHashMap<String, Long> localCache;
     private final Cache<String, Long> localCache = Caffeine.newBuilder()
             .maximumSize(100_000)
@@ -77,15 +77,6 @@ public class MultiReaderNFIDProcessor {
     // 按阶段分组缓冲区
     private final ConcurrentMap<String, List<TagRecord>> batchBuffers = new ConcurrentHashMap<>();
 
-
-    // 数据模型
-    private static class ReaderInfo {
-        String readerId;
-        String readerName;
-        long lastActiveTime;
-        // 其他识别器元数据...
-    }
-
     private static class TagEvent {
         String tagId;
         String readerId;
@@ -145,19 +136,13 @@ public class MultiReaderNFIDProcessor {
         } finally {
             ringBuffer.publish(sequence);
         }
-
-        // 更新识别器活跃状态
-        ReaderInfo reader = readers.get(readerId);
-        if (reader != null) {
-            reader.lastActiveTime = System.currentTimeMillis();
-        }
     }
 
     /**
      * 处理标签事件
      */
     private void handleEvent(TagEvent event, long sequence, boolean endOfBatch) {
-        System.out.println("处理标签事件");
+        //System.out.println("处理标签事件");
         String compositeKey = event.readerId + ":" + event.tagId;
         long now = System.currentTimeMillis();
 
@@ -165,7 +150,7 @@ public class MultiReaderNFIDProcessor {
         Long lastSeen = localCache.getIfPresent(compositeKey);
         if (lastSeen != null && (now - lastSeen) < TAG_EXPIRY_MS) {
 
-            System.out.println("检查本地缓存");
+           // System.out.println("检查本地缓存");
             return;
         }
 
@@ -173,9 +158,9 @@ public class MultiReaderNFIDProcessor {
         String redisKey = redisCachePrefix + event.readerId;
         try {
             Boolean exists = redisTemplate.opsForHash().hasKey(redisKey, event.tagId);
-            System.out.println(redisKey+"-"+event.tagId);
+           // System.out.println(redisKey+"-"+event.tagId);
             if (exists != null && exists) {
-                System.out.println("保存"+compositeKey);
+               // System.out.println("保存"+compositeKey);
                 localCache.put(compositeKey, now);
                 return;
             }
@@ -187,7 +172,7 @@ public class MultiReaderNFIDProcessor {
         localCache.put(compositeKey, now);
 
         // 准备批量记录
-        System.out.println("准备批量记录");
+       // System.out.println("准备批量记录");
 
 
         // 更新Redis缓存
@@ -215,7 +200,7 @@ public class MultiReaderNFIDProcessor {
     }
 
     private void updateRedisCache(String readerId, String tagId, long timestamp) {
-        System.out.println("更新Redis缓存");
+       // System.out.println("更新Redis缓存");
         String redisKey = redisCachePrefix + readerId;
         try  {
             redisTemplate.opsForHash().put(redisKey, tagId, String.valueOf(timestamp));
@@ -268,18 +253,19 @@ public class MultiReaderNFIDProcessor {
     }
     //吊钩绑定
     private void saveBind(List<TagRecord> records) {
+        //2025-05-008修改逻辑,产品需求吊钩绑定识别不直接添加绑定记录,改为先添加识别记录,在吊钩绑定页面收到选择识别记录
         //生成新对象
-        List<HookBind> hookBinds = records.stream()
+        List<NFIDReadRecord> recordList = records.stream()
                 .map(item -> {
-                    HookBind hookBind = new HookBind();
-                    hookBind.setHookNo(hookRegisterService.selectHookNoByEpcNo(item.tagId));
-                    hookBind.setDeviceSerial(item.readerId);
-                    hookBind.setCreateTime(item.detectionTime);
-                    hookBind.setIsBind(HookBind.NOT_BIND);
-                    return hookBind;
+                    NFIDReadRecord record = new NFIDReadRecord();
+                    record.setEpcNo(item.tagId);
+                    record.setHookNo(hookRegisterService.selectHookNoByEpcNo(item.tagId));
+                    record.setDeviceSerial(item.readerId);
+                    record.setCreateTime(item.detectionTime);
+                    return record;
                 })
                 .collect(Collectors.toList());
-        hookBindService.insertHookBindBatch(hookBinds);
+        NFIDReadRecordService.insertNFIDReadRecordBatch(recordList);
     }
 
     //白条称重
@@ -288,18 +274,20 @@ public class MultiReaderNFIDProcessor {
         List<PorkSideProduce> porkSideProduces = records.stream()
                 .map(item -> {
                     PorkSideProduce porkSideProduce = new PorkSideProduce();
+                    porkSideProduce.setEpcNo(item.tagId);
                     porkSideProduce.setHookNo(hookRegisterService.selectHookNoByEpcNo(item.tagId));
                     porkSideProduce.setDeviceSerial(item.readerId);
                     porkSideProduce.setProduceTime(item.detectionTime);
                     porkSideProduce.setCreateTime(item.detectionTime);
                     porkSideProduce.setProductName(PorkSideProduce.DEFAULT_NAME);
 
-                    //获取吊钩绑定关联信息
-                    HookBindDetailDTO hookBindDetail = hookBindService.selectHookBindDetail(porkSideProduce.getHookNo());
-                    porkSideProduce.setEntranceBatchId(hookBindDetail.getEntranceBatchId());
-                    porkSideProduce.setDistributeBatchId(hookBindDetail.getDistributeBatchId());
-                    porkSideProduce.setSlaughterCode(hookBindDetail.getSlaughterCode());
-
+                    if(!Objects.equals(porkSideProduce.getHookNo(), "")){
+                        //获取吊钩绑定关联信息
+                        HookBindDetailDTO hookBindDetail = hookBindService.selectHookBindDetail(porkSideProduce.getHookNo());
+                        porkSideProduce.setEntranceBatchId(hookBindDetail.getEntranceBatchId());
+                        porkSideProduce.setDistributeBatchId(hookBindDetail.getDistributeBatchId());
+                        porkSideProduce.setSlaughterCode(hookBindDetail.getSlaughterCode());
+                    }
                     return porkSideProduce;
                 })
                 .collect(Collectors.toList());
@@ -309,7 +297,7 @@ public class MultiReaderNFIDProcessor {
      * 清理过期缓存
      */
     private void cleanExpiredCache() {
-        System.out.println("清理过期缓存");
+       // System.out.println("清理过期缓存");
         long now = System.currentTimeMillis();
 
         // 清理本地缓存

+ 11 - 4
ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDFrameParser.java

@@ -24,19 +24,25 @@ public class NFIDFrameParser {
 
     // 添加帧类型判断方法
     //判断是否待读取
-    public static boolean isResponseRequiredFrame(NFIDFrame frame) {
+    public static boolean isReadResponseRequiredFrame(NFIDFrame frame) {
         // 判断条件:数据长度在9-20字节之间
         return frame.getDataLength() >= 9 && frame.getDataLength() < 20;
     }
 
     // 添加响应帧生成方法
-    public static byte[] generateResponseFrame(int index) {
+    public static byte[] generateReadResponseFrame(int index) {
         // 5A0001021000080000000X01020006ED08
         // 其中X是1-4的循环索引
         String hexStr = String.format("5A0001021000080000000%d01020006ED08", index);
         return HexUtil.hexToBytes(hexStr);
     }
 
+    //判断是否为链接状态确认信息
+    public static boolean isStatusResponseRequiredFrame(NFIDFrame frame) {
+        // 判断条件:数据长度在4字节
+        return frame.getDataLength() == 4;
+    }
+
     // 判断是否为读写器信息
     public static boolean isDeviceInfoFrame(NFIDFrame frame) {
         // 判断条件:数据长度在70-90字节之间
@@ -45,8 +51,9 @@ public class NFIDFrameParser {
 
     // 判断是否为标签信息
     public static boolean isTagInfoFrame(NFIDFrame frame) {
-        // 判断条件:数据长度在24字节
-        return frame.getDataLength() == 24;
+        // 判断条件:数据长度
+        List<Parameter> parameters = frame.getParameters();
+        return parameters.size() == 1 && parameters.get(0).getLength() == 12;
     }
 
     /**

ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDRedisData.java → app-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDRedisData.java


ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDServer.java → app-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDServer.java


ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDTestClient.java → app-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDTestClient.java


ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDTestClient1.java → app-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDTestClient1.java


+ 37 - 0
app-admin/src/main/java/com/ruoyi/web/core/wvp/ApiResponseParser.java

@@ -0,0 +1,37 @@
+package com.ruoyi.web.core.wvp;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.ruoyi.web.core.wvp.domain.ApiResponse;
+
+public class ApiResponseParser {
+    private static final ObjectMapper objectMapper = new ObjectMapper();
+
+    /**
+     * 解析完整ApiResponse,包含状态码和消息
+     * @param json JSON字符串
+     * @param dataType data字段的类型
+     * @return 完整的ApiResponse对象
+     */
+    public static <T> ApiResponse<T> parseFullResponse(String json, Class<T> dataType) throws Exception {
+        // 构建包含泛型信息的JavaType
+        JavaType javaType = objectMapper.getTypeFactory()
+                .constructParametricType(ApiResponse.class, dataType);
+
+        return objectMapper.readValue(json, javaType);
+    }
+
+    /**
+     * 使用TypeReference处理复杂嵌套类型
+     * @param json JSON字符串
+     * @param typeReference 类型引用
+     * @return 完整的ApiResponse对象
+     */
+    public static <T> ApiResponse<T> parseFullResponse(
+            String json,
+            TypeReference<ApiResponse<T>> typeReference) throws Exception {
+
+        return objectMapper.readValue(json, typeReference);
+    }
+}

+ 107 - 0
app-admin/src/main/java/com/ruoyi/web/core/wvp/DeviceHandler.java

@@ -0,0 +1,107 @@
+package com.ruoyi.web.core.wvp;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.ruoyi.common.utils.spring.SpringUtils;
+import com.ruoyi.web.core.nfid.MultiReaderNFIDProcessor;
+import com.ruoyi.web.core.wvp.domain.ApiResponse;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.http.HttpResponse;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.web.core.wvp.domain.DeviceChannelExtend;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.net.HttpURLConnection;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static com.ruoyi.common.utils.http.HttpUtils.*;
+
+@Component
+public class DeviceHandler {
+    @Value(value = "${wvp.addr}")
+    private String addr;
+
+    private final SessionHandler sessionHandler = SpringUtils.getBean(SessionHandler.class);
+
+    public static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);
+
+    public static final String VIDEO_PLAY_START = "start";
+
+    public static final String VIDEO_PLAY_STOP = "stop";
+
+    //播放
+    public Object playOrStop(String type,String deviceId,String channelId) throws Exception{
+            String url= addr+ "/api/play/"+type+"/" + deviceId + "/" + channelId;
+            Map<String, String> headers = new HashMap<>();
+            String token = sessionHandler.getToken();
+            if (StringUtils.isNotEmpty(token)) {
+                headers.put("access-token", sessionHandler.getToken());
+            }else{
+                throw new RuntimeException("登录WVP失败");
+            }
+            HttpResponse response = sendHttpGet(url, StringUtils.EMPTY, Constants.UTF8,headers);
+            if(response.getStatusCode() == HttpURLConnection.HTTP_OK){
+                // 处理响应
+                ApiResponse<Object> apiResponse = JsonParser.parseWithJavaType(response.getContent(), Object.class);
+
+                if (apiResponse.getCode()!=null && apiResponse.getCode() ==0) {
+                    return apiResponse.getData();
+                } else {
+                    throw new RuntimeException(apiResponse.getMsg());
+                }
+            }else if (response.getStatusCode() == HttpURLConnection.HTTP_UNAUTHORIZED){
+                //是否重新登录
+                if (sessionHandler.needRelogin()){
+                    //重新登录
+                    sessionHandler.refreshToken();
+                }
+            }
+            return null;
+    }
+
+    //设备清单
+    public List<DeviceChannelExtend> getDeviceList() throws Exception {
+        try {
+            String url= addr+ "/api/device/query/allChannels";
+            Map<String, String> headers = new HashMap<>();
+            String token = sessionHandler.getToken();
+            if (StringUtils.isNotEmpty(token)) {
+                headers.put("access-token", sessionHandler.getToken());
+            }else{
+                throw new RuntimeException("登录WVP失败");
+            }
+            HttpResponse response = sendHttpGet(url, StringUtils.EMPTY, Constants.UTF8,headers);
+            if(response.getStatusCode() == HttpURLConnection.HTTP_OK){
+                TypeReference<ApiResponse<List<DeviceChannelExtend>>> typeRef =
+                        new TypeReference<ApiResponse<List<DeviceChannelExtend>>>() {};
+                // 处理响应
+                ApiResponse<List<DeviceChannelExtend>> apiResponse = ApiResponseParser.parseFullResponse(response.getContent(), typeRef);
+
+                if (apiResponse.getCode()!=null && apiResponse.getCode() ==0) {
+                    return apiResponse.getData();
+                } else {
+                    throw new RuntimeException(apiResponse.getMsg());
+                }
+            }else if (response.getStatusCode() == HttpURLConnection.HTTP_UNAUTHORIZED){
+                //是否重新登录
+                if (sessionHandler.needRelogin()){
+                    //重新登录
+                    sessionHandler.refreshToken();
+                }
+                throw new Exception("重新登录");
+            }
+
+        }catch (Exception e){
+            log.error("请求失败: " + e.getMessage());
+            throw e;
+        }
+        return new ArrayList<>();
+    }
+}

+ 70 - 0
app-admin/src/main/java/com/ruoyi/web/core/wvp/JsonParser.java

@@ -0,0 +1,70 @@
+package com.ruoyi.web.core.wvp;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.ruoyi.web.core.wvp.domain.ApiResponse;
+
+import java.util.List;
+import java.util.Map;
+
+public class JsonParser {
+    private static final ObjectMapper objectMapper = new ObjectMapper();
+
+    // 方法1: 使用TypeReference
+    public static <T> ApiResponse<T> parseWithTypeReference(String json, Class<T> dataType) {
+        try {
+            JavaType type = objectMapper.getTypeFactory()
+                    .constructParametricType(ApiResponse.class, dataType);
+            return objectMapper.readValue(json, type);
+        } catch (Exception e) {
+            throw new RuntimeException("JSON解析失败: " + json, e);
+        }
+    }
+
+    // 通用解析方法
+    public static <T> ApiResponse<T> parseResponse(String json, JavaType dataType) {
+        try {
+            JavaType responseType = objectMapper.getTypeFactory()
+                    .constructParametricType(ApiResponse.class, dataType);
+            return objectMapper.readValue(json, responseType);
+        } catch (Exception e) {
+            throw new RuntimeException("JSON解析失败", e);
+        }
+    }
+    // 解析为指定类型的便捷方法
+    public static <T> ApiResponse<T> parseToTypedResponse(String json, Class<T> dataType) {
+        return parseResponse(json, objectMapper.getTypeFactory().constructType(dataType));
+    }
+
+    // 方法2: 使用JavaType
+    public static <T> ApiResponse<T> parseWithJavaType(String json, Class<T> dataType) {
+        try {
+            JavaType javaType = objectMapper.getTypeFactory()
+                    .constructParametricType(ApiResponse.class, dataType);
+            return objectMapper.readValue(json, javaType);
+        } catch (Exception e) {
+            throw new RuntimeException("JSON解析失败", e);
+        }
+    }
+
+    // 方法3: 处理嵌套泛型(如List<T>)
+    public static <T> ApiResponse<List<T>> parseListResponse(String json, Class<T> elementType) {
+        try {
+            JavaType elementJavaType = objectMapper.getTypeFactory()
+                    .constructType(elementType);
+            JavaType listType = objectMapper.getTypeFactory()
+                    .constructCollectionType(List.class, elementType);
+            JavaType responseType = objectMapper.getTypeFactory()
+                    .constructParametricType(ApiResponse.class, listType);
+            return objectMapper.readValue(json, responseType);
+        } catch (Exception e) {
+            throw new RuntimeException("JSON解析失败", e);
+        }
+    }
+
+    // 转换为Map
+    public static Map<String, Object> parseJsonToMap(String json) throws Exception {
+        return objectMapper.readValue(json, new TypeReference<Map<String, Object>>() {});
+    }
+}

+ 127 - 0
app-admin/src/main/java/com/ruoyi/web/core/wvp/SessionHandler.java

@@ -0,0 +1,127 @@
+package com.ruoyi.web.core.wvp;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.http.HttpResponse;
+import com.ruoyi.web.core.wvp.domain.ApiResponse;
+import com.ruoyi.web.core.wvp.domain.Login;
+import com.ruoyi.common.core.redis.RedisCache;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.net.HttpURLConnection;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import static com.ruoyi.common.utils.http.HttpUtils.sendHttpGet;
+
+@Component
+public class SessionHandler {
+    @Autowired
+    private RedisCache redisCache;
+
+    @Value(value = "${wvp.addr}")
+    private String addr;
+
+    @Value(value = "${wvp.username}")
+    private String username;
+
+    @Value(value = "${wvp.password}")
+    private String password;
+
+    private final String WVP_TOKEN = "WVP_TOKEN";
+
+    //token有效期 10分钟
+    private final Integer WVP_TOKEN_EXPIRATION = 10;
+
+    public final Logger log = LoggerFactory.getLogger(ExcelUtil.class);
+
+    private long lastLoginTime;
+
+    public SessionHandler(){
+        // 启动定时任务
+        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
+        scheduler.scheduleAtFixedRate(
+                this::loginWVP,
+                1,
+                20*60,
+                TimeUnit.SECONDS
+        );
+    }
+
+    //登录WVP
+    private String loginWVP() {
+        try {
+            String url= addr+ "/api/user/login?username="+username+"&password="+hashPassword(password);
+            HttpResponse response = sendHttpGet(url, StringUtils.EMPTY, Constants.UTF8,new HashMap<>());
+
+            if(response.getStatusCode() == HttpURLConnection.HTTP_OK) {
+                // 处理响应
+                ApiResponse<Login> apiResponse = ApiResponseParser.parseFullResponse(response.getContent(), Login.class);
+                if (apiResponse.getCode() != null && apiResponse.getCode() == 0) {
+                    Login loginInfo = apiResponse.getData();
+                    redisCache.setCacheObject(WVP_TOKEN, loginInfo.getAccessToken(), WVP_TOKEN_EXPIRATION, TimeUnit.MINUTES);
+                    lastLoginTime = System.currentTimeMillis();
+                    return loginInfo.getAccessToken();
+                } else {
+                    throw new RuntimeException(apiResponse.getMsg());
+                }
+            }else{
+                throw new RuntimeException("登录失败");
+            }
+        }catch (Exception e){
+           log.error("请求失败: " + e.getMessage());
+        }
+        return null;
+    }
+
+    public long getLastLoginTime(){
+        return lastLoginTime;
+    }
+
+    public String getToken(){
+        String token =  redisCache.getCacheObject(WVP_TOKEN);
+        if (token == null) {
+           return loginWVP();
+        }
+        return token;
+    }
+
+    public boolean needRelogin(){
+        return  (System.currentTimeMillis() - lastLoginTime > WVP_TOKEN_EXPIRATION*60*1000);
+    }
+
+    public String refreshToken(){
+        redisCache.deleteObject(WVP_TOKEN);
+        return loginWVP();
+    }
+
+    private static String hashPassword(String password) {
+        try {
+            // MD5
+            MessageDigest digest = MessageDigest.getInstance("MD5");
+            byte[] hashBytes = digest.digest(password.getBytes(StandardCharsets.UTF_8));
+
+            // byte数组转成16进制的字符串
+            StringBuilder hexString = new StringBuilder();
+            for (byte b : hashBytes) {
+                String hex = Integer.toHexString(0xff & b);
+                if (hex.length() == 1) {
+                    hexString.append('0');
+                }
+                hexString.append(hex);
+            }
+            return hexString.toString();
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException("MD5 algorithm not found", e);
+        }
+    }
+}

+ 38 - 0
app-admin/src/main/java/com/ruoyi/web/core/wvp/domain/ApiResponse.java

@@ -0,0 +1,38 @@
+package com.ruoyi.web.core.wvp.domain;
+
+import org.apache.poi.ss.formula.functions.T;
+
+public class ApiResponse<T> {
+    private Integer code;
+    private T data;
+    private String msg;
+    public void setCode(Integer code)
+    {
+        this.code = code;
+    }
+
+    public Integer getCode()
+    {
+        return code;
+    }
+
+    public void setData(T data)
+    {
+        this.data = data;
+    }
+
+    public T getData()
+    {
+        return data;
+    }
+
+    public void setMsg(String msg)
+    {
+        this.msg = msg;
+    }
+
+    public String getMsg()
+    {
+        return msg;
+    }
+}

+ 612 - 0
app-admin/src/main/java/com/ruoyi/web/core/wvp/domain/DeviceChannelExtend.java

@@ -0,0 +1,612 @@
+package com.ruoyi.web.core.wvp.domain;
+
+public class DeviceChannelExtend {
+
+    /**
+     * 数据库自增ID
+     */
+    private int id;
+
+    /**
+     * 通道id
+     */
+    private String channelId;
+
+    /**
+     * 设备id
+     */
+    private String deviceId;
+
+    /**
+     * 通道名
+     */
+    private String name;
+
+    private String deviceName;
+
+    private boolean deviceOnline;
+
+    /**
+     * 生产厂商
+     */
+    private String manufacture;
+
+    /**
+     * 型号
+     */
+    private String model;
+
+    /**
+     * 设备归属
+     */
+    private String owner;
+
+    /**
+     * 行政区域
+     */
+    private String civilCode;
+
+    /**
+     * 警区
+     */
+    private String block;
+
+    /**
+     * 安装地址
+     */
+    private String address;
+
+    /**
+     * 是否有子设备 1有, 0没有
+     */
+    private int parental;
+
+    /**
+     * 父级id
+     */
+    private String parentId;
+
+    /**
+     * 信令安全模式  缺省为0; 0:不采用; 2: S/MIME签名方式; 3: S/ MIME加密签名同时采用方式; 4:数字摘要方式
+     */
+    private int safetyWay;
+
+    /**
+     * 注册方式 缺省为1;1:符合IETFRFC3261标准的认证注册模 式; 2:基于口令的双向认证注册模式; 3:基于数字证书的双向认证注册模式
+     */
+    private int registerWay;
+
+    /**
+     * 证书序列号
+     */
+    private String certNum;
+
+    /**
+     * 证书有效标识 缺省为0;证书有效标识:0:无效1: 有效
+     */
+    private int certifiable;
+
+    /**
+     * 证书无效原因码
+     */
+    private int errCode;
+
+    /**
+     * 证书终止有效期
+     */
+    private String endTime;
+
+    /**
+     * 保密属性 缺省为0; 0:不涉密, 1:涉密
+     */
+    private String secrecy;
+
+    /**
+     * IP地址
+     */
+    private String ipAddress;
+
+    /**
+     * 端口号
+     */
+    private int port;
+
+    /**
+     * 密码
+     */
+    private String password;
+
+    /**
+     * 云台类型
+     */
+    private int PTZType;
+
+    /**
+     * 云台类型描述字符串
+     */
+    private String PTZTypeText;
+
+    /**
+     * 创建时间
+     */
+    private String createTime;
+
+    /**
+     * 更新时间
+     */
+    private String updateTime;
+
+    /**
+     * 在线/离线
+     * 1在线,0离线
+     * 默认在线
+     * 信令:
+     * <Status>ON</Status>
+     * <Status>OFF</Status>
+     * 遇到过NVR下的IPC下发信令可以推流, 但是 Status 响应 OFF
+     */
+    private String status;
+
+    /**
+     * 经度
+     */
+    private double longitude;
+
+    /**
+     * 纬度
+     */
+    private double latitude;
+
+    /**
+     * 经度 GCJ02
+     */
+    private double longitudeGcj02;
+
+    /**
+     * 纬度 GCJ02
+     */
+    private double latitudeGcj02;
+
+    /**
+     * 经度 WGS84
+     */
+    private double longitudeWgs84;
+
+    /**
+     * 纬度 WGS84
+     */
+    private double latitudeWgs84;
+
+    /**
+     * 子设备数
+     */
+    private int subCount;
+
+    /**
+     * 流唯一编号,存在表示正在直播
+     */
+    private String streamId;
+
+    /**
+     *  是否含有音频
+     */
+    private boolean hasAudio;
+
+    /**
+     * 标记通道的类型,0->国标通道 1->直播流通道 2->业务分组/虚拟组织/行政区划
+     */
+    private int channelType;
+
+    /**
+     * 业务分组
+     */
+    private String businessGroupId;
+
+    /**
+     * GPS的更新时间
+     */
+    private String gpsTime;
+
+    // Constructors
+    public DeviceChannelExtend() {
+    }
+
+    public DeviceChannelExtend(String channelId, String deviceId, String name) {
+        this.channelId = channelId;
+        this.deviceId = deviceId;
+        this.name = name;
+    }
+
+    // Getters and Setters
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    public String getChannelId() {
+        return channelId;
+    }
+
+    public void setChannelId(String channelId) {
+        this.channelId = channelId;
+    }
+
+    public String getDeviceId() {
+        return deviceId;
+    }
+
+    public void setDeviceId(String deviceId) {
+        this.deviceId = deviceId;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public boolean isDeviceOnline() {
+        return deviceOnline;
+    }
+
+    public void setDeviceOnline(boolean deviceOnline) {
+        this.deviceOnline = deviceOnline;
+    }
+
+    public String getManufacture() {
+        return manufacture;
+    }
+
+    public void setManufacture(String manufacture) {
+        this.manufacture = manufacture;
+    }
+
+    public String getModel() {
+        return model;
+    }
+
+    public void setModel(String model) {
+        this.model = model;
+    }
+
+    public String getOwner() {
+        return owner;
+    }
+
+    public void setOwner(String owner) {
+        this.owner = owner;
+    }
+
+    public String getCivilCode() {
+        return civilCode;
+    }
+
+    public void setCivilCode(String civilCode) {
+        this.civilCode = civilCode;
+    }
+
+    public String getBlock() {
+        return block;
+    }
+
+    public void setBlock(String block) {
+        this.block = block;
+    }
+
+    public String getAddress() {
+        return address;
+    }
+
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    public int getParental() {
+        return parental;
+    }
+
+    public void setParental(int parental) {
+        this.parental = parental;
+    }
+
+    public String getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(String parentId) {
+        this.parentId = parentId;
+    }
+
+    public int getSafetyWay() {
+        return safetyWay;
+    }
+
+    public void setSafetyWay(int safetyWay) {
+        this.safetyWay = safetyWay;
+    }
+
+    public int getRegisterWay() {
+        return registerWay;
+    }
+
+    public void setRegisterWay(int registerWay) {
+        this.registerWay = registerWay;
+    }
+
+    public String getCertNum() {
+        return certNum;
+    }
+
+    public void setCertNum(String certNum) {
+        this.certNum = certNum;
+    }
+
+    public int getCertifiable() {
+        return certifiable;
+    }
+
+    public void setCertifiable(int certifiable) {
+        this.certifiable = certifiable;
+    }
+
+    public int getErrCode() {
+        return errCode;
+    }
+
+    public void setErrCode(int errCode) {
+        this.errCode = errCode;
+    }
+
+    public String getEndTime() {
+        return endTime;
+    }
+
+    public void setEndTime(String endTime) {
+        this.endTime = endTime;
+    }
+
+    public String getSecrecy() {
+        return secrecy;
+    }
+
+    public void setSecrecy(String secrecy) {
+        this.secrecy = secrecy;
+    }
+
+    public String getIpAddress() {
+        return ipAddress;
+    }
+
+    public void setIpAddress(String ipAddress) {
+        this.ipAddress = ipAddress;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public int getPTZType() {
+        return PTZType;
+    }
+
+    public void setPTZType(int PTZType) {
+        this.PTZType = PTZType;
+        switch (PTZType) {
+            case 0:
+                this.PTZTypeText = "未知";
+                break;
+            case 1:
+                this.PTZTypeText = "球机";
+                break;
+            case 2:
+                this.PTZTypeText = "半球";
+                break;
+            case 3:
+                this.PTZTypeText = "固定枪机";
+                break;
+            case 4:
+                this.PTZTypeText = "遥控枪机";
+                break;
+        }
+    }
+
+    public String getPTZTypeText() {
+        return PTZTypeText;
+    }
+
+    public void setPTZTypeText(String PTZTypeText) {
+        this.PTZTypeText = PTZTypeText;
+    }
+
+    public String getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(String createTime) {
+        this.createTime = createTime;
+    }
+
+    public String getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(String updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public double getLongitude() {
+        return longitude;
+    }
+
+    public void setLongitude(double longitude) {
+        this.longitude = longitude;
+    }
+
+    public double getLatitude() {
+        return latitude;
+    }
+
+    public void setLatitude(double latitude) {
+        this.latitude = latitude;
+    }
+
+    public double getLongitudeGcj02() {
+        return longitudeGcj02;
+    }
+
+    public void setLongitudeGcj02(double longitudeGcj02) {
+        this.longitudeGcj02 = longitudeGcj02;
+    }
+
+    public double getLatitudeGcj02() {
+        return latitudeGcj02;
+    }
+
+    public void setLatitudeGcj02(double latitudeGcj02) {
+        this.latitudeGcj02 = latitudeGcj02;
+    }
+
+    public double getLongitudeWgs84() {
+        return longitudeWgs84;
+    }
+
+    public void setLongitudeWgs84(double longitudeWgs84) {
+        this.longitudeWgs84 = longitudeWgs84;
+    }
+
+    public double getLatitudeWgs84() {
+        return latitudeWgs84;
+    }
+
+    public void setLatitudeWgs84(double latitudeWgs84) {
+        this.latitudeWgs84 = latitudeWgs84;
+    }
+
+    public int getSubCount() {
+        return subCount;
+    }
+
+    public void setSubCount(int subCount) {
+        this.subCount = subCount;
+    }
+
+    public String getStreamId() {
+        return streamId;
+    }
+
+    public void setStreamId(String streamId) {
+        this.streamId = streamId;
+    }
+
+    public boolean isHasAudio() {
+        return hasAudio;
+    }
+
+    public void setHasAudio(boolean hasAudio) {
+        this.hasAudio = hasAudio;
+    }
+
+    public int getChannelType() {
+        return channelType;
+    }
+
+    public void setChannelType(int channelType) {
+        this.channelType = channelType;
+    }
+
+    public String getBusinessGroupId() {
+        return businessGroupId;
+    }
+
+    public void setBusinessGroupId(String businessGroupId) {
+        this.businessGroupId = businessGroupId;
+    }
+
+    public String getGpsTime() {
+        return gpsTime;
+    }
+
+    public void setGpsTime(String gpsTime) {
+        this.gpsTime = gpsTime;
+    }
+
+    @Override
+    public String toString() {
+        return "DeviceChannelExtend{" +
+                "id=" + id +
+                ", channelId='" + channelId + '\'' +
+                ", deviceId='" + deviceId + '\'' +
+                ", name='" + name + '\'' +
+                ", deviceName='" + deviceName + '\'' +
+                ", deviceOnline=" + deviceOnline +
+                ", manufacture='" + manufacture + '\'' +
+                ", model='" + model + '\'' +
+                ", owner='" + owner + '\'' +
+                ", civilCode='" + civilCode + '\'' +
+                ", block='" + block + '\'' +
+                ", address='" + address + '\'' +
+                ", parental=" + parental +
+                ", parentId='" + parentId + '\'' +
+                ", safetyWay=" + safetyWay +
+                ", registerWay=" + registerWay +
+                ", certNum='" + certNum + '\'' +
+                ", certifiable=" + certifiable +
+                ", errCode=" + errCode +
+                ", endTime='" + endTime + '\'' +
+                ", secrecy='" + secrecy + '\'' +
+                ", ipAddress='" + ipAddress + '\'' +
+                ", port=" + port +
+                ", password='" + password + '\'' +
+                ", PTZType=" + PTZType +
+                ", PTZTypeText='" + PTZTypeText + '\'' +
+                ", createTime='" + createTime + '\'' +
+                ", updateTime='" + updateTime + '\'' +
+                ", status='" + status + '\'' +
+                ", longitude=" + longitude +
+                ", latitude=" + latitude +
+                ", longitudeGcj02=" + longitudeGcj02 +
+                ", latitudeGcj02=" + latitudeGcj02 +
+                ", longitudeWgs84=" + longitudeWgs84 +
+                ", latitudeWgs84=" + latitudeWgs84 +
+                ", subCount=" + subCount +
+                ", streamId='" + streamId + '\'' +
+                ", hasAudio=" + hasAudio +
+                ", channelType=" + channelType +
+                ", businessGroupId='" + businessGroupId + '\'' +
+                ", gpsTime='" + gpsTime + '\'' +
+                '}';
+    }
+}

+ 15 - 0
app-admin/src/main/java/com/ruoyi/web/core/wvp/domain/DeviceChannelList.java

@@ -0,0 +1,15 @@
+package com.ruoyi.web.core.wvp.domain;
+
+import java.util.List;
+
+public class DeviceChannelList {
+    private List<DeviceChannelExtend> channelList;
+
+    public List<DeviceChannelExtend> getChannelList() {
+        return channelList;
+    }
+
+    public void setChannelList(List<DeviceChannelExtend> channelList) {
+        this.channelList = channelList;
+    }
+}

+ 170 - 0
app-admin/src/main/java/com/ruoyi/web/core/wvp/domain/Login.java

@@ -0,0 +1,170 @@
+package com.ruoyi.web.core.wvp.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import java.util.Date;
+
+public class Login {
+    private String accessToken;
+    private String serverId;
+    private Long id;
+    private Boolean enabled;
+    private String pushKey;
+    private Role role;
+    private String username;
+    private Boolean accountNonExpired;
+    private Boolean accountNonLocked;
+    private Boolean credentialsNonExpired;
+    private String password;
+    private Object authorities;
+
+    // getters and setters
+    public String getAccessToken() {
+        return accessToken;
+    }
+
+    public void setAccessToken(String accessToken) {
+        this.accessToken = accessToken;
+    }
+
+    public String getServerId() {
+        return serverId;
+    }
+
+    public void setServerId(String serverId) {
+        this.serverId = serverId;
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Boolean getEnabled() {
+        return enabled;
+    }
+
+    public void setEnabled(Boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    public String getPushKey() {
+        return pushKey;
+    }
+
+    public void setPushKey(String pushKey) {
+        this.pushKey = pushKey;
+    }
+
+    public Role getRole() {
+        return role;
+    }
+
+    public void setRole(Role role) {
+        this.role = role;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public Boolean getAccountNonExpired() {
+        return accountNonExpired;
+    }
+
+    public void setAccountNonExpired(Boolean accountNonExpired) {
+        this.accountNonExpired = accountNonExpired;
+    }
+
+    public Boolean getAccountNonLocked() {
+        return accountNonLocked;
+    }
+
+    public void setAccountNonLocked(Boolean accountNonLocked) {
+        this.accountNonLocked = accountNonLocked;
+    }
+
+    public Boolean getCredentialsNonExpired() {
+        return credentialsNonExpired;
+    }
+
+    public void setCredentialsNonExpired(Boolean credentialsNonExpired) {
+        this.credentialsNonExpired = credentialsNonExpired;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public Object getAuthorities() {
+        return authorities;
+    }
+
+    public void setAuthorities(Object authorities) {
+        this.authorities = authorities;
+    }
+
+    // Role内部类
+    public static class Role {
+        private Long id;
+        private String name;
+        private String authority;
+
+        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+        private Date createTime;
+
+        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+        private Date updateTime;
+
+        // getters and setters
+        public Long getId() {
+            return id;
+        }
+
+        public void setId(Long id) {
+            this.id = id;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public String getAuthority() {
+            return authority;
+        }
+
+        public void setAuthority(String authority) {
+            this.authority = authority;
+        }
+
+        public Date getCreateTime() {
+            return createTime;
+        }
+
+        public void setCreateTime(Date createTime) {
+            this.createTime = createTime;
+        }
+
+        public Date getUpdateTime() {
+            return updateTime;
+        }
+
+        public void setUpdateTime(Date updateTime) {
+            this.updateTime = updateTime;
+        }
+    }
+}

ruoyi-admin/src/main/resources/META-INF/spring-devtools.properties → app-admin/src/main/resources/META-INF/spring-devtools.properties


ruoyi-admin/src/main/resources/application-druid.yml → app-admin/src/main/resources/application-druid.yml


+ 9 - 0
ruoyi-admin/src/main/resources/application.yml

@@ -129,3 +129,12 @@ xss:
   excludes: /system/notice
   # 匹配链接
   urlPatterns: /system/*,/monitor/*,/tool/*
+
+#WVP配置
+wvp:
+  #地址
+  addr: http://101.66.246.132:18080
+  #用户名
+  username: admin
+  #密码
+  password: admin

ruoyi-admin/src/main/resources/banner.txt → app-admin/src/main/resources/banner.txt


ruoyi-admin/src/main/resources/i18n/messages.properties → app-admin/src/main/resources/i18n/messages.properties


ruoyi-admin/src/main/resources/logback.xml → app-admin/src/main/resources/logback.xml


ruoyi-admin/src/main/resources/mybatis/mybatis-config.xml → app-admin/src/main/resources/mybatis/mybatis-config.xml


+ 1 - 1
ruoyi-common/pom.xml

@@ -9,7 +9,7 @@
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
-    <artifactId>ruoyi-common</artifactId>
+    <artifactId>app-common</artifactId>
 
     <description>
         common通用工具

ruoyi-common/src/main/java/com/ruoyi/common/annotation/Anonymous.java → app-common/src/main/java/com/ruoyi/common/annotation/Anonymous.java


ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScope.java → app-common/src/main/java/com/ruoyi/common/annotation/DataScope.java


ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java → app-common/src/main/java/com/ruoyi/common/annotation/DataSource.java


ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java → app-common/src/main/java/com/ruoyi/common/annotation/Excel.java


ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excels.java → app-common/src/main/java/com/ruoyi/common/annotation/Excels.java


ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java → app-common/src/main/java/com/ruoyi/common/annotation/Log.java


ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java → app-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java


ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java → app-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java


ruoyi-common/src/main/java/com/ruoyi/common/annotation/Sensitive.java → app-common/src/main/java/com/ruoyi/common/annotation/Sensitive.java


ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java → app-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java


ruoyi-common/src/main/java/com/ruoyi/common/config/serializer/SensitiveJsonSerializer.java → app-common/src/main/java/com/ruoyi/common/config/serializer/SensitiveJsonSerializer.java


ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java → app-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java


ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java → app-common/src/main/java/com/ruoyi/common/constant/Constants.java


ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java → app-common/src/main/java/com/ruoyi/common/constant/GenConstants.java


ruoyi-common/src/main/java/com/ruoyi/common/constant/HttpStatus.java → app-common/src/main/java/com/ruoyi/common/constant/HttpStatus.java


ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java → app-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java


ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java → app-common/src/main/java/com/ruoyi/common/constant/UserConstants.java


ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java → app-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java


ruoyi-common/src/main/java/com/ruoyi/common/core/domain/AjaxResult.java → app-common/src/main/java/com/ruoyi/common/core/domain/AjaxResult.java


ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java → app-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java


ruoyi-common/src/main/java/com/ruoyi/common/core/domain/R.java → app-common/src/main/java/com/ruoyi/common/core/domain/R.java


ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java → app-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java


ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeSelect.java → app-common/src/main/java/com/ruoyi/common/core/domain/TreeSelect.java


+ 0 - 0
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java


Some files were not shown because too many files changed in this diff