浏览代码

测试版本04-22

unknown 2 月之前
父节点
当前提交
ef2fbf5d37
共有 100 个文件被更改,包括 3602 次插入337 次删除
  1. 12 0
      ruoyi-admin/pom.xml
  2. 7 2
      ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
  3. 26 16
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/DataStatisticsController.java
  4. 0 2
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/DeadDisposalController.java
  5. 29 7
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/DistributeBatchController.java
  6. 17 13
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/DryLossRatioController.java
  7. 13 0
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/EntranceBatchController.java
  8. 8 2
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/HarmlessTreatmentController.java
  9. 28 18
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/HookBindController.java
  10. 2 6
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/HookController.java
  11. 128 0
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/HookRegisterController.java
  12. 37 14
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/InspectionItemController.java
  13. 8 0
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/MonitorController.java
  14. 16 0
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/NFIDReaderController.java
  15. 2 2
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/PigCategoryController.java
  16. 2 2
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/PigpenController.java
  17. 4 5
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/PorkOtherProduceController.java
  18. 18 1
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/PorkSideProduceController.java
  19. 2 4
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/ProductCategoryController.java
  20. 27 4
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/PurchaserController.java
  21. 8 4
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/RegionController.java
  22. 5 2
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/SlaughterBatchController.java
  23. 8 7
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/SlaughterRelationController.java
  24. 14 1
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/StaffController.java
  25. 21 6
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/SupplierController.java
  26. 59 4
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
  27. 2 3
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java
  28. 2 11
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java
  29. 17 24
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
  30. 143 0
      ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/ClientHandler.java
  31. 44 0
      ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/DeviceSessionManager.java
  32. 360 0
      ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/MultiReaderNFIDProcessor.java
  33. 315 0
      ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDFrameParser.java
  34. 26 0
      ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDRedisData.java
  35. 66 0
      ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDServer.java
  36. 246 0
      ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDTestClient.java
  37. 246 0
      ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDTestClient1.java
  38. 1 1
      ruoyi-admin/src/main/resources/application-druid.yml
  39. 4 4
      ruoyi-admin/src/main/resources/application.yml
  40. 62 0
      ruoyi-common/pom.xml
  41. 1 1
      ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java
  42. 15 0
      ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java
  43. 0 7
      ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java
  44. 1 4
      ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java
  45. 14 42
      ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
  46. 1 16
      ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java
  47. 67 0
      ruoyi-common/src/main/java/com/ruoyi/common/server/EnvInputServer.java
  48. 251 0
      ruoyi-common/src/main/java/com/ruoyi/common/server/EnvInputServerHandler.java
  49. 55 0
      ruoyi-common/src/main/java/com/ruoyi/common/utils/ConvertUtil.java
  50. 61 0
      ruoyi-common/src/main/java/com/ruoyi/common/utils/FindUtil.java
  51. 27 0
      ruoyi-common/src/main/java/com/ruoyi/common/utils/HexUtil.java
  52. 51 0
      ruoyi-common/src/main/java/com/ruoyi/common/utils/ModBusUtils.java
  53. 21 0
      ruoyi-common/src/main/java/com/ruoyi/common/utils/NumberUtil.java
  54. 159 0
      ruoyi-common/src/main/java/com/ruoyi/common/utils/PdfParseUtil.java
  55. 16 0
      ruoyi-common/src/main/java/com/ruoyi/common/utils/QRCodeUtil.java
  56. 0 15
      ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java
  57. 6 3
      ruoyi-common/src/main/java/com/ruoyi/common/utils/TimeUtil.java
  58. 21 0
      ruoyi-common/src/main/java/com/ruoyi/common/utils/jsonUtil.java
  59. 47 6
      ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
  60. 0 8
      ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java
  61. 0 4
      ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java
  62. 18 0
      ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java
  63. 1 1
      ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
  64. 1 1
      ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java
  65. 33 0
      ruoyi-system/src/main/java/com/ruoyi/app/DTO/DailyEntranceAmountDTO.java
  66. 3 0
      ruoyi-system/src/main/java/com/ruoyi/app/DTO/EntranceReportDTO.java
  67. 24 0
      ruoyi-system/src/main/java/com/ruoyi/app/DTO/HookBindBatchListDTO.java
  68. 1 0
      ruoyi-system/src/main/java/com/ruoyi/app/DTO/PorkProduceDTO.java
  69. 4 0
      ruoyi-system/src/main/java/com/ruoyi/app/DTO/ProductTraceDTO.java
  70. 4 0
      ruoyi-system/src/main/java/com/ruoyi/app/DTO/SlaughterBatchDTO.java
  71. 61 0
      ruoyi-system/src/main/java/com/ruoyi/app/DTO/SlaughterRelationDTO.java
  72. 4 0
      ruoyi-system/src/main/java/com/ruoyi/app/DTO/SlaughterReportDTO.java
  73. 49 0
      ruoyi-system/src/main/java/com/ruoyi/app/DTO/ValidSlaughterCodeDTO.java
  74. 3 0
      ruoyi-system/src/main/java/com/ruoyi/app/domain/DeadDisposal.java
  75. 7 7
      ruoyi-system/src/main/java/com/ruoyi/app/domain/DistributeBatch.java
  76. 21 21
      ruoyi-system/src/main/java/com/ruoyi/app/domain/DryLossRatio.java
  77. 65 0
      ruoyi-system/src/main/java/com/ruoyi/app/domain/EntranceBatch.java
  78. 7 0
      ruoyi-system/src/main/java/com/ruoyi/app/domain/EntranceInspection.java
  79. 13 0
      ruoyi-system/src/main/java/com/ruoyi/app/domain/HarmlessTreatment.java
  80. 4 3
      ruoyi-system/src/main/java/com/ruoyi/app/domain/Hook.java
  81. 22 0
      ruoyi-system/src/main/java/com/ruoyi/app/domain/HookBind.java
  82. 93 0
      ruoyi-system/src/main/java/com/ruoyi/app/domain/HookRegister.java
  83. 3 0
      ruoyi-system/src/main/java/com/ruoyi/app/domain/InspectionItem.java
  84. 12 0
      ruoyi-system/src/main/java/com/ruoyi/app/domain/Monitor.java
  85. 116 0
      ruoyi-system/src/main/java/com/ruoyi/app/domain/NFIDReader.java
  86. 4 2
      ruoyi-system/src/main/java/com/ruoyi/app/domain/PigCategory.java
  87. 5 1
      ruoyi-system/src/main/java/com/ruoyi/app/domain/Pigpen.java
  88. 13 2
      ruoyi-system/src/main/java/com/ruoyi/app/domain/PorkOtherProduce.java
  89. 2 2
      ruoyi-system/src/main/java/com/ruoyi/app/domain/PorkRedoffalProduce.java
  90. 18 2
      ruoyi-system/src/main/java/com/ruoyi/app/domain/PorkSideProduce.java
  91. 2 2
      ruoyi-system/src/main/java/com/ruoyi/app/domain/PorkWhiteoffalProduce.java
  92. 2 0
      ruoyi-system/src/main/java/com/ruoyi/app/domain/ProductCategory.java
  93. 26 2
      ruoyi-system/src/main/java/com/ruoyi/app/domain/Purchaser.java
  94. 5 0
      ruoyi-system/src/main/java/com/ruoyi/app/domain/Region.java
  95. 9 2
      ruoyi-system/src/main/java/com/ruoyi/app/domain/SlaughterBatch.java
  96. 4 3
      ruoyi-system/src/main/java/com/ruoyi/app/domain/SlaughterRelation.java
  97. 25 12
      ruoyi-system/src/main/java/com/ruoyi/app/domain/Staff.java
  98. 46 0
      ruoyi-system/src/main/java/com/ruoyi/app/domain/StaffPost.java
  99. 23 3
      ruoyi-system/src/main/java/com/ruoyi/app/domain/Supplier.java
  100. 0 0
      ruoyi-system/src/main/java/com/ruoyi/app/domain/request/AddHookBindBatch.java

+ 12 - 0
ruoyi-admin/pom.xml

@@ -60,7 +60,19 @@
             <groupId>com.ruoyi</groupId>
             <artifactId>ruoyi-generator</artifactId>
         </dependency>
+        <!--事件处理-->
+        <dependency>
+            <groupId>com.lmax</groupId>
+            <artifactId>disruptor</artifactId>
+            <version>3.4.4</version> <!-- 检查最新版本 -->
+        </dependency>
 
+        <!--内存缓存-->
+        <dependency>
+            <groupId>com.github.ben-manes.caffeine</groupId>
+            <artifactId>caffeine</artifactId>
+            <version>2.9.3</version>
+        </dependency>
     </dependencies>
 
     <build>

+ 7 - 2
ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java

@@ -1,8 +1,10 @@
 package com.ruoyi;
 
+import com.ruoyi.web.core.nfid.NFIDServer;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.context.ApplicationContext;
 
 /**
  * 启动程序
@@ -12,10 +14,13 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
 @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
 public class RuoYiApplication
 {
-    public static void main(String[] args)
+    public static void main(String[] args) throws Exception
     {
         // System.setProperty("spring.devtools.restart.enabled", "false");
-        SpringApplication.run(RuoYiApplication.class, args);
+        ApplicationContext applicationContext = SpringApplication.run(RuoYiApplication.class, args);
+        applicationContext.getBean(NFIDServer.class).start();
+        // EnvInputServer
+        //applicationContext.getBean(EnvInputServer.class).run();
         System.out.println("(♥◠‿◠)ノ゙  若依启动成功   ლ(´ڡ`ლ)゙  \n" +
                 " .-------.       ____     __        \n" +
                 " |  _ _   \\      \\   \\   /  /    \n" +

+ 26 - 16
ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/DataStatisticsController.java

@@ -28,7 +28,7 @@ public class DataStatisticsController extends BaseController
     /**
      * 获取生产指标信息
      */
-    @PreAuthorize("@ss.hasPermi('app:statistics:getGrodIndicator')")
+    @PreAuthorize("@ss.hasPermi('app:statistics:entrance')")
     @GetMapping(value = "/getGrodIndicator")
     public AjaxResult getProdIndicator(@Validated TimeRangeParam timeRangeParam)
     {
@@ -39,7 +39,7 @@ public class DataStatisticsController extends BaseController
     /**
      * 获取供应商供应数量前五排名
      */
-    @PreAuthorize("@ss.hasPermi('app:statistics:getSupplierRank')")
+    @PreAuthorize("@ss.hasPermi('app:statistics:entrance')")
     @GetMapping(value = "/getSupplierRank")
     public AjaxResult getSupplierRank(@Validated TimeRangeParam timeRangeParam)
     {
@@ -50,7 +50,7 @@ public class DataStatisticsController extends BaseController
     /**
      * 获取肉商接收数量前五排名
      */
-    @PreAuthorize("@ss.hasPermi('app:statistics:getPurchaserRank')")
+    @PreAuthorize("@ss.hasPermi('app:statistics:entrance')")
     @GetMapping(value = "/getPurchaserRank")
     public AjaxResult getPurchaserRank(@Validated TimeRangeParam timeRangeParam)
     {
@@ -61,7 +61,7 @@ public class DataStatisticsController extends BaseController
     /**
      * 根据时间范围获取不同产地供应商供应数量
      */
-    @PreAuthorize("@ss.hasPermi('app:statistics:getOriginAmount')")
+    @PreAuthorize("@ss.hasPermi('app:statistics:entrance')")
     @GetMapping(value = "/getOriginAmount")
     public AjaxResult getOriginAmount(@Validated TimeRangeParam timeRangeParam)
     {
@@ -72,7 +72,7 @@ public class DataStatisticsController extends BaseController
     /**
      * 根据时间范围获取不同去向肉商销售数量
      */
-    @PreAuthorize("@ss.hasPermi('app:statistics:getSaleAmount')")
+    @PreAuthorize("@ss.hasPermi('app:statistics:entrance')")
     @GetMapping(value = "/getSaleAmount")
     public AjaxResult getSaleAmount(@Validated TimeRangeParam timeRangeParam)
     {
@@ -81,9 +81,9 @@ public class DataStatisticsController extends BaseController
     }
 
     /**
-     * 根据时间范围获取不同去向肉商销售数量
+     * 根据时间范围获取入场检验统计数量
      */
-    @PreAuthorize("@ss.hasPermi('app:statistics:getHarmlessAmount')")
+    @PreAuthorize("@ss.hasPermi('app:statistics:entrance')")
     @GetMapping(value = "/getHarmlessAmount")
     public AjaxResult getHarmlessAmount(@Validated TimeRangeParam timeRangeParam)
     {
@@ -94,7 +94,7 @@ public class DataStatisticsController extends BaseController
     /**
      * 根据获取指定时间范围内每日累计计划屠宰
      */
-    @PreAuthorize("@ss.hasPermi('app:statistics:getEntranceAmountWithTime')")
+    @PreAuthorize("@ss.hasPermi('app:statistics:entrance')")
     @GetMapping(value = "/getEntranceAmountWithTime")
     public AjaxResult getEntranceAmountWithTime(@Validated TimeRangeParam timeRangeParam)
     {
@@ -104,7 +104,7 @@ public class DataStatisticsController extends BaseController
     /**
      * 获取产出指标信息
      */
-    @PreAuthorize("@ss.hasPermi('app:statistics:getOutputIndicator')")
+    @PreAuthorize("@ss.hasPermi('app:statistics:output')")
     @GetMapping(value = "/getOutputIndicator")
     public AjaxResult getOutputIndicator(@Validated TimeRangeParam timeRangeParam)
     {
@@ -114,7 +114,7 @@ public class DataStatisticsController extends BaseController
     /**
      * 获取白条重量统计
      */
-    @PreAuthorize("@ss.hasPermi('app:statistics:getSideWeight')")
+    @PreAuthorize("@ss.hasPermi('app:statistics:output')")
     @GetMapping(value = "/getSideWeight")
     public AjaxResult getSideWeight(@Validated TimeRangeParam timeRangeParam)
     {
@@ -124,7 +124,7 @@ public class DataStatisticsController extends BaseController
     /**
      * 获取其他产品重量统计
      */
-    @PreAuthorize("@ss.hasPermi('app:statistics:getOtherProductWeight')")
+    @PreAuthorize("@ss.hasPermi('app:statistics:output')")
     @GetMapping(value = "/getOtherProductWeight")
     public AjaxResult getOtherProductWeight(@Validated SearchTimeRangeParam searchTimeRangeParam)
     {
@@ -134,7 +134,7 @@ public class DataStatisticsController extends BaseController
     /**
      * 获取今日昨日统计
      */
-    @PreAuthorize("@ss.hasPermi('app:statistics:getLatelyIndicator')")
+    @PreAuthorize("@ss.hasPermi('app:statistics:output')")
     @GetMapping(value = "/getLastestIndicator")
     public AjaxResult getLatelyIndicator()
     {
@@ -142,9 +142,9 @@ public class DataStatisticsController extends BaseController
     }
 
     /**
-     * 获取近七天每日订单量
+     * 获取近七天每日分销订单量
      */
-    @PreAuthorize("@ss.hasPermi('app:statistics:getWeekEntranceCount')")
+    @PreAuthorize("@ss.hasPermi('app:statistics:output')")
     @GetMapping(value = "/getWeekEntranceCount")
     public AjaxResult getWeekEntranceCount()
     {
@@ -152,9 +152,19 @@ public class DataStatisticsController extends BaseController
     }
 
     /**
+     * 获取近七天每日分销订单量
+     */
+    @PreAuthorize("@ss.hasPermi('app:statistics:output')")
+    @GetMapping(value = "/getWeekDistributeCount")
+    public AjaxResult getWeekDistributeCount()
+    {
+        return success(dataStatisticsService.getWeekDistributeCount());
+    }
+
+    /**
      * 获取各部位重量对比情况
      */
-    @PreAuthorize("@ss.hasPermi('app:statistics:getPorkPartWeight')")
+    @PreAuthorize("@ss.hasPermi('app:statistics:output')")
     @GetMapping(value = "/getPorkPartWeight")
     public AjaxResult getPorkPartWeight()
     {
@@ -164,7 +174,7 @@ public class DataStatisticsController extends BaseController
     /**
      * 获取产地/去向对比情况
      */
-    @PreAuthorize("@ss.hasPermi('app:statistics:getPlaceAmount')")
+    @PreAuthorize("@ss.hasPermi('app:statistics:output')")
     @GetMapping(value = "/getPlaceAmount")
     public AjaxResult getPlaceAmount()
     {

+ 0 - 2
ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/DeadDisposalController.java

@@ -40,7 +40,6 @@ public class DeadDisposalController extends BaseController
     /**
      * 查询死淘处理方式列表
      */
-    @PreAuthorize("@ss.hasPermi('app:disposal:list')")
     @GetMapping("/list")
     public TableDataInfo list(DeadDisposal deadDisposal)
     {
@@ -65,7 +64,6 @@ public class DeadDisposalController extends BaseController
     /**
      * 获取死淘处理方式详细信息
      */
-    @PreAuthorize("@ss.hasPermi('app:disposal:query')")
     @GetMapping(value = "/{id}")
     public AjaxResult getInfo(@PathVariable("id") Long id)
     {

+ 29 - 7
ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/DistributeBatchController.java

@@ -7,9 +7,11 @@ import java.util.stream.Collectors;
 import javax.servlet.http.HttpServletResponse;
 
 import com.ruoyi.app.DTO.ValidDistributeListDTO;
+import com.ruoyi.app.DTO.ValidSlaughterCodeDTO;
 import com.ruoyi.app.domain.Purchaser;
 import com.ruoyi.app.domain.request.AddDistributeBatch;
 import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.NumberUtil;
 import com.ruoyi.common.utils.StringUtils;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -62,11 +64,9 @@ public class DistributeBatchController extends BaseController
 
     /**
      * 查询指定血码还未关闭的分销批次,也就是可以继续绑吊钩,
-     * 通过判断关联屠宰批次是否填商肉品和动物合格证号,
-     * 如果都填上,则认为屠宰或者分销已经完成了
+     * 通过判断24小时内的分销批次
      */
     @ApiOperation("血码可用批次")
-    @PreAuthorize("@ss.hasPermi('app:distributeBatch:list')")
     @GetMapping("/getValidList")
     public AjaxResult getValidList(DistributeBatch distributeBatch)
     {
@@ -76,6 +76,18 @@ public class DistributeBatchController extends BaseController
     }
 
     /**
+     * 获取存在未完成(24小时内)的分销批次的血码
+     */
+    @ApiOperation("可用血码")
+    @GetMapping("/getValidCodeList")
+    public AjaxResult getValidCodeList()
+    {
+
+        List<ValidSlaughterCodeDTO> list = distributeBatchService.selectValidCode();
+        return success(list);
+    }
+
+    /**
      * 导出分销批次列表
      */
     @ApiOperation("导出分销批次列表")
@@ -109,8 +121,9 @@ public class DistributeBatchController extends BaseController
     @PostMapping
     public AjaxResult add(@Validated @RequestBody DistributeBatch distributeBatch)
     {
-        //判断分销数量是否超过批次实际数量
-
+        if(!distributeBatchService.checkTotalLessThanAmount(distributeBatch)){
+            return error("新增分销批次失败,分销数量输入错误");
+        }
         distributeBatch.setCreateBy(getUsername());
         return toAjax(distributeBatchService.insertDistributeBatch(distributeBatch));
     }
@@ -142,8 +155,9 @@ public class DistributeBatchController extends BaseController
             }
         }
         //校验数据库的
+        int add = 0;
         for (DistributeBatch distribute : distributeArr) {
-
+            add += NumberUtil.getIntValue(distribute.getAmount());
             DistributeBatch check = distributeBatchService.checkPurchaserUnique(distribute);
             if (StringUtils.isNotNull(check))
             {
@@ -152,7 +166,12 @@ public class DistributeBatchController extends BaseController
             }
         }
         //判断分销数量是否超过批次实际数量
-
+        DistributeBatch distributeBuild = new DistributeBatch();
+        distributeBuild.setEntranceBatchId(req.getEntranceBatchId());
+        distributeBuild.setAmount(add);
+        if(!distributeBatchService.checkTotalLessThanAmount(distributeBuild)){
+            return error("新增分销批次失败,分销数量输入错误");
+        }
         return toAjax(distributeBatchService.insertDistributeBatchByBatch(distributeArr));
     }
 
@@ -172,6 +191,9 @@ public class DistributeBatchController extends BaseController
             return error("修改分销批次失败,该批次下肉商'" + purchaser.getPurchaserName() + "'已存在");
         }
         //判断分销数量是否超过批次实际数量
+        if(!distributeBatchService.checkTotalLessThanAmount(distributeBatch)){
+            return error("修改分销批次失败,分销数量输入错误");
+        }
 
         distributeBatch.setUpdateBy(getUsername());
         return toAjax(distributeBatchService.updateDistributeBatch(distributeBatch));

+ 17 - 13
ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/DryLossRatioController.java

@@ -41,10 +41,12 @@ public class DryLossRatioController extends BaseController
     /**
      * 查询干损比例列表
      */
-    @PreAuthorize("@ss.hasPermi('app:ratio:list')")
     @GetMapping("/list")
     public TableDataInfo list(DryLossRatio dryLossRatio)
     {
+        if(dryLossRatio.getStartTime() != null){
+            dryLossRatio.setStartTime("2025-"+dryLossRatio.getStartTime()+" 00:00:00");
+        }
         startPage();
         List<DryLossRatio> list = dryLossRatioService.selectDryLossRatioList(dryLossRatio);
         return getDataTable(list);
@@ -66,7 +68,6 @@ public class DryLossRatioController extends BaseController
     /**
      * 获取干损比例详细信息
      */
-    @PreAuthorize("@ss.hasPermi('app:ratio:query')")
     @GetMapping(value = "/{id}")
     public AjaxResult getInfo(@PathVariable("id") Long id)
     {
@@ -81,13 +82,15 @@ public class DryLossRatioController extends BaseController
     @PostMapping
     public AjaxResult add(@Validated @RequestBody DryLossRatio dryLossRatio)
     {
-       if(!dryLossRatio.getStartTime().before(dryLossRatio.getEndTime())){
-           return error("开始时间必须早于结束时间");
-       }
+//       if(!dryLossRatio.getStartTime().before(dryLossRatio.getEndTime())){
+//           return error("开始时间必须早于结束时间");
+//       }
+        ////拼凑成完整的时间字段且年份固定,数据库采用时间字段方便比较
+        dryLossRatio.setStartTime("2025-"+dryLossRatio.getStartTime()+" 00:00:00");
         String ids = dryLossRatioService.checkTimeOverLap(dryLossRatio);
-        if (ids != null && ids != "")
+        if (ids != null && !ids.isEmpty())
         {
-            return error("新增干损比例失败,已存在ID为:‘" + ids + "’时间范围重叠的干损比例");
+            return error("新增干损比例失败,已存在ID为:‘" + ids + "’列表中存在时间范围重叠的干损比例");
         }
         dryLossRatio.setCreateBy(getUsername());
         return toAjax(dryLossRatioService.insertDryLossRatio(dryLossRatio));
@@ -101,13 +104,15 @@ public class DryLossRatioController extends BaseController
     @PutMapping
     public AjaxResult edit(@Validated @RequestBody DryLossRatio dryLossRatio)
     {
-        if(!dryLossRatio.getStartTime().before(dryLossRatio.getEndTime())){
-            return error("开始时间必须早于结束时间");
-        }
+//        if(!dryLossRatio.getStartTime().before(dryLossRatio.getEndTime())){
+//            return error("开始时间必须早于结束时间");
+//        }
+        //拼凑成完整的时间字段且年份固定,数据库采用时间字段方便比较
+        dryLossRatio.setStartTime("2025-"+dryLossRatio.getStartTime()+" 00:00:00");
         String ids = dryLossRatioService.checkTimeOverLap(dryLossRatio);
-        if (ids != null && ids != "")
+        if (ids != null && !ids.isEmpty())
         {
-            return error("修改干损比例,已存在ID为:‘" + ids + "’时间范围重叠的干损比例");
+            return error("修改干损比例,已存在ID为:‘" + ids + "’列表中存在时间范围重叠的干损比例");
         }
         dryLossRatio.setUpdateBy(getUsername());
         return toAjax(dryLossRatioService.updateDryLossRatio(dryLossRatio));
@@ -127,7 +132,6 @@ public class DryLossRatioController extends BaseController
     /**
      * 获取满足当前时间的干损比
      */
-    @PreAuthorize("@ss.hasPermi('app:ratio:query')")
     @GetMapping(value = "/getFit")
     public AjaxResult getFit()
     {

+ 13 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/EntranceBatchController.java

@@ -78,6 +78,13 @@ public class EntranceBatchController extends BaseController
     @PostMapping
     public AjaxResult add(@Validated @RequestBody EntranceBatch entranceBatch)
     {
+        if (entranceBatch.getAnimalCertNo()!=null && !entranceBatch.getAnimalCertNo().isEmpty()){
+            if (!entranceBatchService.checkAnimalCertNoUnique(entranceBatch))
+            {
+                return error("新增入场批次失败,列表中存在重复的检疫证号");
+            }
+        }
+
         entranceBatch.setCreateBy(getUsername());
         return toAjax(entranceBatchService.insertEntranceBatch(entranceBatch));
     }
@@ -90,6 +97,12 @@ public class EntranceBatchController extends BaseController
     @PutMapping
     public AjaxResult edit(@Validated @RequestBody EntranceBatch entranceBatch)
     {
+        if (entranceBatch.getAnimalCertNo()!=null && !entranceBatch.getAnimalCertNo().isEmpty()){
+            if (!entranceBatchService.checkAnimalCertNoUnique(entranceBatch))
+            {
+                return error("修改入场批次失败,列表中存在重复的检疫证号");
+            }
+        }
         entranceBatch.setUpdateBy(getUsername());
         return toAjax(entranceBatchService.updateEntranceBatch(entranceBatch));
     }

+ 8 - 2
ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/HarmlessTreatmentController.java

@@ -38,7 +38,6 @@ public class HarmlessTreatmentController extends BaseController
     /**
      * 查询无害化处理列表
      */
-    @PreAuthorize("@ss.hasPermi('app:harmlessTreatment:list')")
     @GetMapping("/list")
     public TableDataInfo list(HarmlessTreatment harmlessTreatment)
     {
@@ -63,7 +62,6 @@ public class HarmlessTreatmentController extends BaseController
     /**
      * 获取无害化处理详细信息
      */
-    @PreAuthorize("@ss.hasPermi('app:harmlessTreatment:query')")
     @GetMapping(value = "/{id}")
     public AjaxResult getInfo(@PathVariable("id") Long id)
     {
@@ -78,6 +76,10 @@ public class HarmlessTreatmentController extends BaseController
     @PostMapping
     public AjaxResult add(@Validated  @RequestBody HarmlessTreatment harmlessTreatment)
     {
+        //判断全部数量是否超出了入场数量
+        if(!harmlessTreatmentService.checkTotalLessThanAmount(harmlessTreatment)){
+            return error("新增无害化处理失败,病死头数、病害头数或急宰头数输入错误");
+        }
         harmlessTreatment.setCreateBy(getUsername());
         return toAjax(harmlessTreatmentService.insertHarmlessTreatment(harmlessTreatment));
     }
@@ -90,6 +92,10 @@ public class HarmlessTreatmentController extends BaseController
     @PutMapping
     public AjaxResult edit(@Validated @RequestBody HarmlessTreatment harmlessTreatment)
     {
+        //判断全部数量是否超出了入场数量
+        if(!harmlessTreatmentService.checkTotalLessThanAmount(harmlessTreatment)){
+            return error("修改无害化处理失败,病死头数、病害头数或急宰头数输入错误");
+        }
         harmlessTreatment.setUpdateBy(getUsername());
         return toAjax(harmlessTreatmentService.updateHarmlessTreatment(harmlessTreatment));
     }

+ 28 - 18
ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/HookBindController.java

@@ -1,14 +1,14 @@
 package com.ruoyi.web.controller.app;
 
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
 
 import javax.servlet.http.HttpServletResponse;
 
+import com.ruoyi.app.DTO.HookBindBatchListDTO;
 import com.ruoyi.app.domain.request.AddHookBindBatch;
 import com.ruoyi.app.domain.request.EditHookBindBatch;
+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 io.swagger.annotations.Api;
@@ -53,7 +53,6 @@ public class HookBindController extends BaseController
      * 查询吊钩绑定列表
      */
     @ApiOperation("查询吊钩绑定列表")
-    @PreAuthorize("@ss.hasPermi('app:hookBind:list')")
     @GetMapping("/list")
     public TableDataInfo list(HookBind hookBind)
     {
@@ -66,12 +65,11 @@ public class HookBindController extends BaseController
      * 按批次查询吊钩绑定列表
      */
     @ApiOperation("按批次查询吊钩绑定列表")
-    @PreAuthorize("@ss.hasPermi('app:hookBind:list')")
     @GetMapping("/batchList")
-    public TableDataInfo batchList(HookBind hookBind)
+    public TableDataInfo batchList(ReqHookBindList req)
     {
         startPage();
-        List<HookBind> list = hookBindService.selectHookBindListByBatch(hookBind);
+        List<HookBindBatchListDTO> list = hookBindService.selectHookBindListByBatch(req);
         return getDataTable(list);
     }
 
@@ -93,18 +91,16 @@ public class HookBindController extends BaseController
      * 获取吊钩绑定详细信息
      */
     @ApiOperation("获取吊钩绑定详细信息")
-    @PreAuthorize("@ss.hasPermi('app:hookBind:query')")
-    @GetMapping(value = "/{batchNo}")
-    public AjaxResult getInfo(@PathVariable("batchNo") String batchNo)
+    @GetMapping(value = "/group")
+    public AjaxResult getGroupInfo(@Validated ReqHookBindDetail req)
     {
-        return success(hookBindService.selectHookBindByBatch(batchNo));
+        return success(hookBindService.selectHookBindByBatch(req.getGroupId()));
     }
 
     /**
      * 获取吊钩绑定详细信息
      */
     @ApiOperation("获取吊钩绑定详细信息")
-    @PreAuthorize("@ss.hasPermi('app:hookBind:query')")
     @GetMapping(value = "/detail/{hookNo}")
     public AjaxResult getDetail(@PathVariable("hookNo") String hookNo)
     {
@@ -139,6 +135,10 @@ public class HookBindController extends BaseController
         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)) {
@@ -173,17 +173,27 @@ public class HookBindController extends BaseController
     @PreAuthorize("@ss.hasPermi('app:hookBind:edit')")
     @Log(title = "吊钩绑定", businessType = BusinessType.UPDATE)
     @PutMapping
-    public AjaxResult edit(@Validated @RequestBody EditHookBindBatch req)
+    public AjaxResult edit(@Validated @RequestBody HookBind hookBind)
     {
-        HookBind hookBind = new HookBind();
-        hookBind.setBatchNo(req.getBatchNo());
-        hookBind.setSlaughterCode(req.getSlaughterCode());
-        hookBind.setDistributeBatchId(req.getDistributeBatchId());
+
         hookBind.setUpdateBy(getUsername());
         return toAjax(hookBindService.updateHookBind(hookBind));
     }
 
     /**
+     * 批量修改吊钩绑定
+     */
+    @ApiOperation("批量修改吊钩绑定")
+    @PreAuthorize("@ss.hasPermi('app:hookBind:edit')")
+    @Log(title = "吊钩绑定", businessType = BusinessType.UPDATE)
+    @PostMapping("/editBatch")
+    public AjaxResult editBatch(@Validated @RequestBody EditHookBindBatch req)
+    {
+        req.setUpdateBy(getUsername());
+        return toAjax(hookBindService.updateHookBindBatch(req));
+    }
+
+    /**
      * 删除吊钩绑定
      */
     @ApiOperation("删除吊钩绑定")

+ 2 - 6
ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/HookController.java

@@ -38,7 +38,6 @@ public class HookController extends BaseController
     /**
      * 查询吊钩列表
      */
-    @PreAuthorize("@ss.hasPermi('app:hook:list')")
     @GetMapping("/list")
     public TableDataInfo list(Hook hook)
     {
@@ -50,7 +49,6 @@ public class HookController extends BaseController
     /**
      * 导出吊钩列表
      */
-    @PreAuthorize("@ss.hasPermi('app:hook:export')")
     @Log(title = "吊钩", businessType = BusinessType.EXPORT)
     @PostMapping("/export")
     public void export(HttpServletResponse response, Hook hook)
@@ -63,7 +61,6 @@ public class HookController extends BaseController
     /**
      * 获取吊钩详细信息
      */
-    @PreAuthorize("@ss.hasPermi('app:hook:query')")
     @GetMapping(value = "/{id}")
     public AjaxResult getInfo(@PathVariable("id") Long id)
     {
@@ -80,7 +77,7 @@ public class HookController extends BaseController
     {
         if (!hookService.checkHookNameUnique(hook))
         {
-            return error("新增吊钩'" + hook.getHookName() + "'失败,吊钩类型已存在");
+            return error("新增吊钩'" + hook.getHookName() + "'失败,列表中存在重复的吊钩类型");
         }
         hook.setCreateBy(getUsername());
         return toAjax(hookService.insertHook(hook));
@@ -96,7 +93,7 @@ public class HookController extends BaseController
     {
         if (!hookService.checkHookNameUnique(hook))
         {
-            return error("修改吊钩'" + hook.getHookName() + "'失败,吊钩类型已存在");
+            return error("修改吊钩'" + hook.getHookName() + "'失败,列表中存在重复的吊钩类型");
         }
         hook.setUpdateBy(getUsername());
         return toAjax(hookService.updateHook(hook));
@@ -116,7 +113,6 @@ public class HookController extends BaseController
     /**
      * 吊钩选择
      */
-    @PreAuthorize("@ss.hasPermi('app:hook:list')")
     @GetMapping("/optionselect")
     public AjaxResult optionselect()
     {

+ 128 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/HookRegisterController.java

@@ -0,0 +1,128 @@
+package com.ruoyi.web.controller.app;
+
+import com.ruoyi.app.domain.HookRegister;
+import com.ruoyi.app.domain.request.ReqHookRegister;
+import com.ruoyi.app.service.IHookRegisterService;
+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.poi.ExcelUtil;
+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 javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 吊钩注册Controller
+ * 
+ * @author coede
+ * @date 2025-03-19
+ */
+@RestController
+@RequestMapping("/app/hookRegister")
+public class HookRegisterController extends BaseController
+{
+    @Autowired
+    private IHookRegisterService hookRegisterService;
+
+    /**
+     * 查询吊钩注册列表
+     */
+    @PreAuthorize("@ss.hasPermi('app:hookRegister:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(ReqHookRegister req)
+    {
+        startPage();
+        List<HookRegister> list = hookRegisterService.selectHookRegisterList(req);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出吊钩注册列表
+     */
+    @PreAuthorize("@ss.hasPermi('app:hookRegister:export')")
+    @Log(title = "吊钩注册", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, ReqHookRegister req)
+    {
+        List<HookRegister> list = hookRegisterService.selectHookRegisterList(req);
+        ExcelUtil<HookRegister> util = new ExcelUtil<HookRegister>(HookRegister.class);
+        util.exportExcel(response, list, "吊钩注册数据");
+    }
+
+    /**
+     * 获取吊钩注册详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('app:hookRegister:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return success(hookRegisterService.selectHookRegisterById(id));
+    }
+
+    /**
+     * 新增吊钩注册
+     */
+    @PreAuthorize("@ss.hasPermi('app:hookRegister:add')")
+    @Log(title = "吊钩注册", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody HookRegister hookRegister)
+    {
+        if (!hookRegisterService.checkHookNoUnique(hookRegister))
+        {
+            return error("新增吊钩注册'" + hookRegister.getHookNo() + "'失败,列表中存在重复的吊钩编号");
+        }
+        if (!hookRegisterService.checkEpcNoUnique(hookRegister))
+        {
+            return error("新增吊钩注册'" + hookRegister.getEpcNo() + "'失败,列表中存在重复的芯片编号");
+        }
+        hookRegister.setCreateBy(getUsername());
+        return toAjax(hookRegisterService.insertHookRegister(hookRegister));
+    }
+
+    /**
+     * 修改吊钩注册
+     */
+    @PreAuthorize("@ss.hasPermi('app:hookRegister:edit')")
+    @Log(title = "吊钩注册", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody HookRegister hookRegister)
+    {
+        if (!hookRegisterService.checkHookNoUnique(hookRegister))
+        {
+            return error("修改吊钩注册'" + hookRegister.getHookNo() + "'失败,列表中存在重复的吊钩编号");
+        }
+        if (!hookRegisterService.checkEpcNoUnique(hookRegister))
+        {
+            return error("修改吊钩注册'" + hookRegister.getEpcNo() + "'失败,列表中存在重复的芯片编号");
+        }
+        hookRegister.setUpdateBy(getUsername());
+        return toAjax(hookRegisterService.updateHookRegister(hookRegister));
+    }
+
+    /**
+     * 删除吊钩注册
+     */
+    @PreAuthorize("@ss.hasPermi('app:hookRegister:remove')")
+    @Log(title = "吊钩注册", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(hookRegisterService.deleteHookRegisterByIds(ids));
+    }
+
+    /**
+     * 获取选择框列表
+     */
+    @GetMapping("/optionselect")
+    public AjaxResult optionselect()
+    {
+        List<HookRegister> list = hookRegisterService.selectHookRegisterList(new ReqHookRegister());
+        return success(list);
+    }
+}

+ 37 - 14
ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/InspectionItemController.java

@@ -3,8 +3,9 @@ package com.ruoyi.web.controller.app;
 import java.util.List;
 import javax.servlet.http.HttpServletResponse;
 
-import com.ruoyi.app.domain.Pigpen;
-import com.ruoyi.app.domain.Supplier;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.ruoyi.common.utils.jsonUtil;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
@@ -41,7 +42,6 @@ public class InspectionItemController extends BaseController
     /**
      * 查询检查项目列表
      */
-    @PreAuthorize("@ss.hasPermi('app:inspectionItem:list')")
     @GetMapping("/list")
     public TableDataInfo list(InspectionItem inspectionItem)
     {
@@ -66,7 +66,6 @@ public class InspectionItemController extends BaseController
     /**
      * 获取检查项目详细信息
      */
-    @PreAuthorize("@ss.hasPermi('app:inspectionItem:query')")
     @GetMapping(value = "/{id}")
     public AjaxResult getInfo(@PathVariable("id") Long id)
     {
@@ -81,12 +80,25 @@ public class InspectionItemController extends BaseController
     @PostMapping
     public AjaxResult add(@Validated  @RequestBody InspectionItem inspectionItem)
     {
-        if (!inspectionItemService.checkItemNameUnique(inspectionItem))
-        {
-            return error("新增检查项目'" + inspectionItem.getItemName() + "'失败,项目名称已存在");
+        ObjectMapper mapper = new ObjectMapper();
+        try {
+            JsonNode jsonArray = mapper.readTree(inspectionItem.getResult());
+            String fieldToCheck = "name";
+            if (jsonUtil.checkForDuplicateFields(jsonArray, fieldToCheck))
+            {
+                return error("新增检查项目'" + inspectionItem.getItemName() + "'失败,本次添加中存在重复的检查结果");
+            }
+            if (!inspectionItemService.checkItemNameUnique(inspectionItem))
+            {
+                return error("新增检查项目'" + inspectionItem.getItemName() + "'失败,列表中存在重复的项目名称");
+            }
+            inspectionItem.setCreateBy(getUsername());
+            return toAjax(inspectionItemService.insertInspectionItem(inspectionItem));
+        } catch (Exception e) {
+            return error("新增检查项目'" + inspectionItem.getItemName() + "'失败,错误的检查结果格式");
         }
-        inspectionItem.setCreateBy(getUsername());
-        return toAjax(inspectionItemService.insertInspectionItem(inspectionItem));
+
+
     }
 
     /**
@@ -97,12 +109,23 @@ public class InspectionItemController extends BaseController
     @PutMapping
     public AjaxResult edit(@Validated @RequestBody InspectionItem inspectionItem)
     {
-        if (!inspectionItemService.checkItemNameUnique(inspectionItem))
-        {
-            return error("修改检查项目'" + inspectionItem.getItemName() + "'失败,项目名称已存在");
+        ObjectMapper mapper = new ObjectMapper();
+        try {
+            JsonNode jsonArray = mapper.readTree(inspectionItem.getResult());
+            String fieldToCheck = "name";
+            if (jsonUtil.checkForDuplicateFields(jsonArray, fieldToCheck))
+            {
+                return error("修改检查项目'" + inspectionItem.getItemName() + "'失败,本次添加中存在重复的检查结果");
+            }
+            if (!inspectionItemService.checkItemNameUnique(inspectionItem))
+            {
+                return error("修改检查项目'" + inspectionItem.getItemName() + "'失败,列表中存在重复的项目名称");
+            }
+            inspectionItem.setUpdateBy(getUsername());
+            return toAjax(inspectionItemService.insertInspectionItem(inspectionItem));
+        } catch (Exception e) {
+            return error("修改检查项目'" + inspectionItem.getItemName() + "'失败,错误的检查结果格式");
         }
-        inspectionItem.setUpdateBy(getUsername());
-        return toAjax(inspectionItemService.updateInspectionItem(inspectionItem));
     }
 
     /**

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

@@ -86,6 +86,10 @@ public class MonitorController extends BaseController
     @PostMapping
     public AjaxResult add(@Validated  @RequestBody Monitor monitor)
     {
+        if (!monitorService.checkMonitorNameUnique(monitor))
+        {
+            return error("新增监控设备'" + monitor.getMonitorName() + "'失败,列表中存在重复的监控名称");
+        }
         monitor.setCreateBy(getUsername());
         return toAjax(monitorService.insertMonitor(monitor));
     }
@@ -99,6 +103,10 @@ public class MonitorController extends BaseController
     @PutMapping
     public AjaxResult edit(@Validated @RequestBody Monitor monitor)
     {
+        if (!monitorService.checkMonitorNameUnique(monitor))
+        {
+            return error("修改监控设备'" + monitor.getMonitorName() + "'失败,列表中存在重复的监控名称");
+        }
         monitor.setUpdateBy(getUsername());
         return toAjax(monitorService.updateMonitor(monitor));
     }

+ 16 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/NFIDReaderController.java

@@ -0,0 +1,16 @@
+package com.ruoyi.web.controller.app;
+
+import com.ruoyi.app.service.INFIDReaderService;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.system.service.ISysConfigService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/app/NFIDReader")
+public class NFIDReaderController extends BaseController {
+    @Autowired
+    private INFIDReaderService NFIDReaderService;
+
+}

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

@@ -80,7 +80,7 @@ public class PigCategoryController extends BaseController
     {
         if (!pigCategoryService.checkCategoryNameUnique(pigCategory))
         {
-            return error("新增生猪分类'" + pigCategory.getCategoryName() + "'失败,分类名称已存在");
+            return error("新增生猪品种'" + pigCategory.getCategoryName() + "'失败,列表中存在重复的品种名称");
         }
         pigCategory.setCreateBy(getUsername());
         return toAjax(pigCategoryService.insertPigCategory(pigCategory));
@@ -96,7 +96,7 @@ public class PigCategoryController extends BaseController
     {
         if (!pigCategoryService.checkCategoryNameUnique(pigCategory))
         {
-            return error("修改生猪分类'" + pigCategory.getCategoryName() + "'失败,分类名称已存在");
+            return error("修改生猪品种'" + pigCategory.getCategoryName() + "'失败,列表中存在重复的品种名称");
         }
         pigCategory.setUpdateBy(getUsername());
         return toAjax(pigCategoryService.updatePigCategory(pigCategory));

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

@@ -82,7 +82,7 @@ public class PigpenController extends BaseController
     {
         if (!pigpenService.checkPigpenNameUnique(pigpen))
         {
-            return error("新增待宰圈'" + pigpen.getPigpenName() + "'失败,待宰圈号已存在");
+            return error("新增待宰圈'" + pigpen.getPigpenName() + "'失败,列表中存在重复的待宰圈号");
         }
         pigpen.setCreateBy(getUsername());
         return toAjax(pigpenService.insertPigpen(pigpen));
@@ -98,7 +98,7 @@ public class PigpenController extends BaseController
     {
         if (!pigpenService.checkPigpenNameUnique(pigpen))
         {
-            return error("修改待宰圈'" + pigpen.getPigpenName() + "'失败,待宰圈号已存在");
+            return error("修改待宰圈'" + pigpen.getPigpenName() + "'失败,列表中存在重复的待宰圈号");
         }
         pigpen.setUpdateBy(getUsername());
         return toAjax(pigpenService.updatePigpen(pigpen));

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

@@ -59,8 +59,7 @@ public class PorkOtherProduceController extends BaseController
     /**
      * 获取猪头生产记录详细信息
      */
-    @ApiOperation("查询其他生产记录列表")
-    @PreAuthorize("@ss.hasPermi('app:porkOtherProduce:query')")
+    @ApiOperation("获取猪头生产记录详细信息")
     @GetMapping(value = "/{id}")
     public AjaxResult getInfo(@PathVariable("id") Long id)
     {
@@ -70,7 +69,7 @@ public class PorkOtherProduceController extends BaseController
     /**
      * 新增猪头生产记录
      */
-    @ApiOperation("查询其他生产记录列表")
+    @ApiOperation("新增猪头生产记录")
     @PreAuthorize("@ss.hasPermi('app:porkOtherProduce:add')")
     @Log(title = "其他生产记录", businessType = BusinessType.INSERT)
     @PostMapping
@@ -83,7 +82,7 @@ public class PorkOtherProduceController extends BaseController
     /**
      * 修改猪头生产记录
      */
-    @ApiOperation("查询其他生产记录列表")
+    @ApiOperation("修改猪头生产记录")
     @PreAuthorize("@ss.hasPermi('app:porkOtherProduce:edit')")
     @Log(title = "其他生产记录", businessType = BusinessType.UPDATE)
     @PutMapping
@@ -96,7 +95,7 @@ public class PorkOtherProduceController extends BaseController
     /**
      * 删除猪头生产记录
      */
-    @ApiOperation("查询其他生产记录列表")
+    @ApiOperation("删除猪头生产记录")
     @PreAuthorize("@ss.hasPermi('app:porkOtherProduce:remove')")
     @Log(title = "其他生产记录", businessType = BusinessType.DELETE)
 	@DeleteMapping("/{ids}")

+ 18 - 1
ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/PorkSideProduceController.java

@@ -3,8 +3,13 @@ package com.ruoyi.web.controller.app;
 import java.util.List;
 import javax.servlet.http.HttpServletResponse;
 
+import com.ruoyi.app.DTO.HookBindDetailDTO;
 import com.ruoyi.app.DTO.PorkSideProduceDTO;
+import com.ruoyi.app.domain.HookBind;
+import com.ruoyi.app.domain.request.AddPorkSideProduce;
 import com.ruoyi.app.domain.request.ReqGetPorkSideProduce;
+import com.ruoyi.app.service.IHookBindService;
+import com.ruoyi.common.utils.DateUtils;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -41,6 +46,9 @@ public class PorkSideProduceController extends BaseController
     @Autowired
     private IPorkSideProduceService porkSideProduceService;
 
+    @Autowired
+    private IHookBindService hookBindService;
+
     /**
      * 查询白条生产记录列表
      */
@@ -72,8 +80,17 @@ public class PorkSideProduceController extends BaseController
     @PreAuthorize("@ss.hasPermi('app:porkSideProduce:add')")
     @Log(title = "白条生产记录", businessType = BusinessType.INSERT)
     @PostMapping
-    public AjaxResult add(@Validated @RequestBody PorkSideProduce porkSideProduce)
+    public AjaxResult add(@Validated @RequestBody AddPorkSideProduce req)
     {
+        HookBindDetailDTO hookBind = hookBindService.selectHookBindDetail(req.getHookNo());
+
+        PorkSideProduce porkSideProduce = new PorkSideProduce();
+        porkSideProduce.setProductName(PorkSideProduce.DEFAULT_NAME);
+        porkSideProduce.setProduceTime(DateUtils.getNowDate());
+        porkSideProduce.setHookNo(req.getHookNo());
+        porkSideProduce.setSlaughterCode(hookBind.getSlaughterCode());
+        porkSideProduce.setDistributeBatchId(hookBind.getDistributeBatchId());
+        porkSideProduce.setEntranceBatchId(hookBind.getEntranceBatchId());
         porkSideProduce.setCreateBy(getUsername());
         return toAjax(porkSideProduceService.insertPorkSideProduce(porkSideProduce));
     }

+ 2 - 4
ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/ProductCategoryController.java

@@ -40,7 +40,6 @@ public class ProductCategoryController extends BaseController
     /**
      * 查询产品分类列表
      */
-    @PreAuthorize("@ss.hasPermi('app:productCategory:list')")
     @GetMapping("/list")
     public TableDataInfo list(ProductCategory productCategory)
     {
@@ -65,7 +64,6 @@ public class ProductCategoryController extends BaseController
     /**
      * 获取产品分类详细信息
      */
-    @PreAuthorize("@ss.hasPermi('app:productCategory:query')")
     @GetMapping(value = "/{id}")
     public AjaxResult getInfo(@PathVariable("id") Long id)
     {
@@ -82,7 +80,7 @@ public class ProductCategoryController extends BaseController
     {
         if (!productCategoryService.checkProductNameUnique(productCategory))
         {
-            return error("新增产品分类'" + productCategory.getProductName() + "'失败,产品名称已存在");
+            return error("新增产品分类'" + productCategory.getProductName() + "'失败,列表中存在重复的产品名称");
         }
         productCategory.setCreateBy(getUsername());
         return toAjax(productCategoryService.insertProductCategory(productCategory));
@@ -98,7 +96,7 @@ public class ProductCategoryController extends BaseController
     {
         if (!productCategoryService.checkProductNameUnique(productCategory))
         {
-            return error("修改产品分类'" + productCategory.getProductName() + "'失败,产品名称已存在");
+            return error("修改产品分类'" + productCategory.getProductName() + "'失败,列表中存在重复的产品名称");
         }
         productCategory.setUpdateBy(getUsername());
         return toAjax(productCategoryService.updateProductCategory(productCategory));

+ 27 - 4
ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/PurchaserController.java

@@ -4,6 +4,7 @@ import java.util.List;
 import javax.servlet.http.HttpServletResponse;
 
 import com.ruoyi.app.domain.Supplier;
+import com.ruoyi.app.domain.request.ReqPurchaser;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -44,9 +45,8 @@ public class PurchaserController extends BaseController
      * 查询肉商列表
      */
     @ApiOperation("查询肉商列表")
-    @PreAuthorize("@ss.hasPermi('app:purchaser:list')")
     @GetMapping("/list")
-    public TableDataInfo list(Purchaser purchaser)
+    public TableDataInfo list(ReqPurchaser purchaser)
     {
         startPage();
         List<Purchaser> list = purchaserService.selectPurchaserList(purchaser);
@@ -70,7 +70,7 @@ public class PurchaserController extends BaseController
     @PreAuthorize("@ss.hasPermi('app:purchaser:export')")
     @Log(title = "肉商", businessType = BusinessType.EXPORT)
     @PostMapping("/export")
-    public void export(HttpServletResponse response, Purchaser purchaser)
+    public void export(HttpServletResponse response, ReqPurchaser purchaser)
     {
         List<Purchaser> list = purchaserService.selectPurchaserList(purchaser);
         ExcelUtil<Purchaser> util = new ExcelUtil<Purchaser>(Purchaser.class);
@@ -81,7 +81,6 @@ public class PurchaserController extends BaseController
      * 获取肉商详细信息
      */
     @ApiOperation("获取肉商详细信息")
-    @PreAuthorize("@ss.hasPermi('app:purchaser:query')")
     @GetMapping(value = "/{id}")
     public AjaxResult getInfo(@PathVariable("id") Long id)
     {
@@ -97,6 +96,18 @@ public class PurchaserController extends BaseController
     @PostMapping
     public AjaxResult add(@Validated @RequestBody Purchaser purchaser)
     {
+        if (!purchaserService.checkPurchaserNoUnique(purchaser))
+        {
+            return error("新增肉商'" + purchaser.getPurchaserName() + "'失败,列表中存在重复的肉商编号");
+        }
+        if (!purchaserService.checkPurchaserNameUnique(purchaser))
+        {
+            return error("新增肉商'" + purchaser.getPurchaserName() + "'失败,列表中存在重复的肉商名称");
+        }
+        if (!purchaserService.checkIDNumberUnique(purchaser))
+        {
+            return error("新增肉商'" + purchaser.getPurchaserName() + "'失败,列表中存在重复的身份证号");
+        }
         purchaser.setCreateBy(getUsername());
         return toAjax(purchaserService.insertPurchaser(purchaser));
     }
@@ -110,6 +121,18 @@ public class PurchaserController extends BaseController
     @PutMapping
     public AjaxResult edit(@Validated @RequestBody Purchaser purchaser)
     {
+        if (!purchaserService.checkPurchaserNoUnique(purchaser))
+        {
+            return error("修改肉商'" + purchaser.getPurchaserName() + "'失败,列表中存在重复的肉商编号");
+        }
+        if (!purchaserService.checkPurchaserNameUnique(purchaser))
+        {
+            return error("修改肉商'" + purchaser.getPurchaserName() + "'失败,列表中存在重复的肉商名称");
+        }
+        if (!purchaserService.checkIDNumberUnique(purchaser))
+        {
+            return error("修改肉商'" + purchaser.getPurchaserName() + "'失败,列表中存在重复的身份证号");
+        }
         purchaser.setUpdateBy(getUsername());
         return toAjax(purchaserService.updatePurchaser(purchaser));
     }

+ 8 - 4
ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/RegionController.java

@@ -44,7 +44,6 @@ public class RegionController extends BaseController
      * 查询区域列表
      */
     @ApiOperation("查询区域列表")
-    @PreAuthorize("@ss.hasPermi('app:region:list')")
     @GetMapping("/list")
     public TableDataInfo list(Region region)
     {
@@ -71,7 +70,6 @@ public class RegionController extends BaseController
      * 获取区域详细信息
      */
     @ApiOperation("获取区域详细信息")
-    @PreAuthorize("@ss.hasPermi('app:region:query')")
     @GetMapping(value = "/{id}")
     public AjaxResult getInfo(@PathVariable("id") Long id)
     {
@@ -87,6 +85,10 @@ public class RegionController extends BaseController
     @PostMapping
     public AjaxResult add(@Validated  @RequestBody Region region)
     {
+        if (!regionService.checkRegionNameUnique(region))
+        {
+            return error("新增区域'" + region.getRegionName() + "'失败,列表中存在重复的区域名称");
+        }
         region.setCreateBy(getUsername());
         return toAjax(regionService.insertRegion(region));
     }
@@ -100,6 +102,10 @@ public class RegionController extends BaseController
     @PutMapping
     public AjaxResult edit(@Validated @RequestBody Region region)
     {
+        if (!regionService.checkRegionNameUnique(region))
+        {
+            return error("修改区域'" + region.getRegionName() + "'失败,列表中存在重复的区域名称");
+        }
         region.setUpdateBy(getUsername());
         return toAjax(regionService.updateRegion(region));
     }
@@ -120,7 +126,6 @@ public class RegionController extends BaseController
      * 查询区域选择
      */
     @ApiOperation("查询区域选择")
-    @PreAuthorize("@ss.hasPermi('app:region:list')")
     @GetMapping("/optionselect")
     public AjaxResult optionselect()
     {
@@ -133,7 +138,6 @@ public class RegionController extends BaseController
      * 查询区域设备树
      */
     @ApiOperation("查询区域设备树")
-    @PreAuthorize("@ss.hasPermi('app:region:list')")
     @GetMapping("/treeList")
     public AjaxResult treeList(Region region)
     {

+ 5 - 2
ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/SlaughterBatchController.java

@@ -7,6 +7,7 @@ import com.ruoyi.app.DTO.SlaughterBatchDTO;
 import com.ruoyi.app.domain.request.ReqSlaughterBatch;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PutMapping;
@@ -65,8 +66,9 @@ public class SlaughterBatchController extends BaseController
     @PreAuthorize("@ss.hasPermi('app:slaughterBatch:add')")
     @Log(title = "屠宰批次", businessType = BusinessType.INSERT)
     @PostMapping
-    public AjaxResult add(@RequestBody SlaughterBatch slaughterBatch)
+    public AjaxResult add(@Validated @RequestBody SlaughterBatch slaughterBatch)
     {
+        slaughterBatch.setCreateBy(getUsername());
         return toAjax(slaughterBatchService.insertSlaughterBatch(slaughterBatch));
     }
 
@@ -76,8 +78,9 @@ public class SlaughterBatchController extends BaseController
     @PreAuthorize("@ss.hasPermi('app:slaughterBatch:edit')")
     @Log(title = "屠宰批次", businessType = BusinessType.UPDATE)
     @PutMapping
-    public AjaxResult edit(@RequestBody SlaughterBatch slaughterBatch)
+    public AjaxResult edit(@Validated  @RequestBody SlaughterBatch slaughterBatch)
     {
+        slaughterBatch.setUpdateBy(getUsername());
         return toAjax(slaughterBatchService.updateSlaughterBatch(slaughterBatch));
     }
 

+ 8 - 7
ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/SlaughterRelationController.java

@@ -6,8 +6,10 @@ import java.util.Set;
 import java.util.stream.Collectors;
 import javax.servlet.http.HttpServletResponse;
 
+import com.ruoyi.app.DTO.SlaughterRelationDTO;
 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.response.RespGetSlaughterRelation;
 import com.ruoyi.common.utils.DateUtils;
@@ -52,7 +54,6 @@ public class SlaughterRelationController extends BaseController
      * 供应商血码数量列表
      */
     @ApiOperation("供应商血码数量列表")
-    @PreAuthorize("@ss.hasPermi('app:slaughterRelation:list')")
     @GetMapping("/supplierList")
     public TableDataInfo supplierList(ReqGetSlaughterRelation req)
     {
@@ -65,7 +66,6 @@ public class SlaughterRelationController extends BaseController
      * 查询血码关系列表
      */
     @ApiOperation("查询血码关系列表")
-    @PreAuthorize("@ss.hasPermi('app:slaughterRelation:list')")
     @GetMapping("/list")
     public TableDataInfo list(SlaughterRelation slaughterRelation)
     {
@@ -81,10 +81,11 @@ public class SlaughterRelationController extends BaseController
     @PreAuthorize("@ss.hasPermi('app:slaughterRelation:export')")
     @Log(title = "血码关系", businessType = BusinessType.EXPORT)
     @PostMapping("/export")
-    public void export(HttpServletResponse response, SlaughterRelation slaughterRelation)
+    public void export(HttpServletResponse response, ExportSlaughterRelation req)
     {
-        List<SlaughterRelation> list = slaughterRelationService.selectSlaughterRelationList(slaughterRelation);
-        ExcelUtil<SlaughterRelation> util = new ExcelUtil<SlaughterRelation>(SlaughterRelation.class);
+        List<SlaughterRelationDTO> list = slaughterRelationService.exportSlaughterRelationList(req);
+        list.forEach(item -> item.setQrcode(item.getSlaughterCode()));
+        ExcelUtil<SlaughterRelationDTO> util = new ExcelUtil<>(SlaughterRelationDTO.class);
         util.exportExcel(response, list, "血码关系数据");
     }
 
@@ -150,12 +151,12 @@ public class SlaughterRelationController extends BaseController
             String key = String.valueOf(relation.getPurchaserId());
             //noinspection ConstantConditions  忽略错误的IDEA提示
             if (!uniqueIds.add(key)) {
-                return error("新增血码关系失败,本次添加存在相同的肉商");
+                return error("新增血码关系失败,存在同一肉商配置多个血码的情况");
             }
             String code = relation.getSlaughterCode();
             //noinspection ConstantConditions  忽略错误的IDEA提示
             if (!uniqueCodes.add(code)) {
-                return error("新增血码关系失败,本次添加存在相同的血码");
+                return error("新增血码关系失败,存在多个肉商配置同一血码的情况");
             }
         }
         //校验数据库的

+ 14 - 1
ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/StaffController.java

@@ -2,6 +2,9 @@ package com.ruoyi.web.controller.app;
 
 import java.util.List;
 import javax.servlet.http.HttpServletResponse;
+
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.system.service.ISysPostService;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
@@ -35,6 +38,9 @@ public class StaffController extends BaseController
     @Autowired
     private IStaffService staffService;
 
+    @Autowired
+    private ISysPostService sysPostService;
+
     /**
      * 查询人员列表
      */
@@ -67,7 +73,14 @@ public class StaffController extends BaseController
     @GetMapping(value = "/{id}")
     public AjaxResult getInfo(@PathVariable("id") Long id)
     {
-        return success(staffService.selectStaffById(id));
+        AjaxResult ajax = AjaxResult.success();
+        if (StringUtils.isNotNull(id))
+        {
+            Staff staff = staffService.selectStaffById(id);
+            ajax.put(AjaxResult.DATA_TAG, staff);
+            ajax.put("postIds", sysPostService.selectPostListByStaffId(id));
+        }
+        return ajax;
     }
 
     /**

+ 21 - 6
ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/SupplierController.java

@@ -3,6 +3,7 @@ package com.ruoyi.web.controller.app;
 import java.util.List;
 import javax.servlet.http.HttpServletResponse;
 
+import com.ruoyi.app.domain.request.ReqSupplierList;
 import com.ruoyi.system.domain.SysPost;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -44,12 +45,11 @@ public class SupplierController extends BaseController
      * 查询供应商列表
      */
     @ApiOperation("查询供应商列表")
-    @PreAuthorize("@ss.hasPermi('app:supplier:list')")
     @GetMapping("/list")
-    public TableDataInfo list(Supplier supplier)
+    public TableDataInfo list(ReqSupplierList req)
     {
         startPage();
-        List<Supplier> list = supplierService.selectSupplierList(supplier);
+        List<Supplier> list = supplierService.selectSupplierList(req);
         return getDataTable(list);
     }
 
@@ -70,9 +70,9 @@ public class SupplierController extends BaseController
     @PreAuthorize("@ss.hasPermi('app:supplier:export')")
     @Log(title = "供应商", businessType = BusinessType.EXPORT)
     @PostMapping("/export")
-    public void export(HttpServletResponse response, Supplier supplier)
+    public void export(HttpServletResponse response, ReqSupplierList req)
     {
-        List<Supplier> list = supplierService.selectSupplierList(supplier);
+        List<Supplier> list = supplierService.selectSupplierList(req);
         ExcelUtil<Supplier> util = new ExcelUtil<Supplier>(Supplier.class);
         util.exportExcel(response, list, "供应商数据");
     }
@@ -81,7 +81,6 @@ public class SupplierController extends BaseController
      * 获取供应商详细信息
      */
     @ApiOperation("获取供应商详细信息")
-    @PreAuthorize("@ss.hasPermi('app:supplier:query')")
     @GetMapping(value = "/{id}")
     public AjaxResult getInfo(@PathVariable("id") Long id)
     {
@@ -97,6 +96,14 @@ public class SupplierController extends BaseController
     @PostMapping
     public AjaxResult add(@Validated  @RequestBody Supplier supplier)
     {
+        if (!supplierService.checkSupplierNameUnique(supplier))
+        {
+            return error("新增供应商'" + supplier.getSupplierName() + "'失败,列表中存在重复的供应商名称");
+        }
+        if (!supplierService.checkSupplierNoUnique(supplier))
+        {
+            return error("新增供应商'" + supplier.getSupplierName() + "'失败,列表中存在重复的供应商编号");
+        }
         supplier.setCreateBy(getUsername());
         return toAjax(supplierService.insertSupplier(supplier));
     }
@@ -110,6 +117,14 @@ public class SupplierController extends BaseController
     @PutMapping
     public AjaxResult edit(@Validated @RequestBody Supplier supplier)
     {
+        if (!supplierService.checkSupplierNameUnique(supplier))
+        {
+            return error("修改供应商'" + supplier.getSupplierName() + "'失败,列表中存在重复的供应商名称");
+        }
+        if (!supplierService.checkSupplierNoUnique(supplier))
+        {
+            return error("修改供应商'" + supplier.getSupplierName() + "'失败,列表中存在重复的供应商编号");
+        }
         supplier.setUpdateBy(getUsername());
         return toAjax(supplierService.updateSupplier(supplier));
     }

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

@@ -1,17 +1,22 @@
 package com.ruoyi.web.controller.common;
 
+import java.io.File;
+import java.nio.file.Files;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+
+import com.alibaba.fastjson2.JSON;
+import com.ruoyi.common.utils.PdfParseUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 import com.ruoyi.common.config.RuoYiConfig;
 import com.ruoyi.common.constant.Constants;
@@ -21,6 +26,10 @@ import com.ruoyi.common.utils.file.FileUploadUtils;
 import com.ruoyi.common.utils.file.FileUtils;
 import com.ruoyi.framework.config.ServerConfig;
 
+import technology.tabula.*;
+import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;
+import org.apache.pdfbox.pdmodel.PDDocument;
+
 /**
  * 通用请求处理
  * 
@@ -96,6 +105,43 @@ public class CommonController
     }
 
     /**
+     * 通用上传请求(单个)
+     */
+    @PostMapping("/uploadAndParse")
+    public AjaxResult uploadAndParse(MultipartFile file) throws Exception
+    {
+        //验证文件
+        if (file.isEmpty()) {
+            return AjaxResult.error("请上传PDF文件");
+        }
+
+        if (!"application/pdf".equals(file.getContentType())) {
+            return AjaxResult.error("仅支持PDF文件");
+        }
+        try
+        {
+            // 上传文件路径
+            String filePath = RuoYiConfig.getUploadPath();
+            // 上传并返回新文件名称
+            String fileName = FileUploadUtils.upload(filePath, file);
+            String url = serverConfig.getUrl() + fileName;
+            //解析
+            Map<String, Object>  detail = PdfParseUtil.extractPdfContent(file);
+            AjaxResult ajax = AjaxResult.success();
+            ajax.put("detail", detail);
+            ajax.put("url", url);
+            ajax.put("fileName", fileName);
+            ajax.put("newFileName", FileUtils.getName(fileName));
+            ajax.put("originalFilename", file.getOriginalFilename());
+            return ajax;
+        }
+        catch (Exception e)
+        {
+            return AjaxResult.error(e.getMessage());
+        }
+    }
+
+    /**
      * 通用上传请求(多个)
      */
     @PostMapping("/uploads")
@@ -160,4 +206,13 @@ public class CommonController
             log.error("下载文件失败", e);
         }
     }
+
+    @PostMapping("/addBatch")
+    public ResponseEntity<Map<String, Object>> addBatch(@RequestBody Map<String, Object> params) {
+        System.out.println(JSON.toJSONString(params));
+        Map<String, Object> response = new HashMap<>();
+        response.put("resultCode", 0);
+        response.put("resultMsg", "success");
+        return ResponseEntity.ok(response);
+    }
 }

+ 2 - 3
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java

@@ -37,7 +37,6 @@ public class SysPostController extends BaseController
     /**
      * 获取岗位列表
      */
-    @PreAuthorize("@ss.hasPermi('system:post:list')")
     @GetMapping("/list")
     public TableDataInfo list(SysPost post)
     {
@@ -76,7 +75,7 @@ public class SysPostController extends BaseController
     {
         if (!postService.checkPostNameUnique(post))
         {
-            return error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在");
+            return error("新增岗位'" + post.getPostName() + "'失败,列表中存在重复的岗位名称");
         }
         post.setCreateBy(getUsername());
         return toAjax(postService.insertPost(post));
@@ -92,7 +91,7 @@ public class SysPostController extends BaseController
     {
         if (!postService.checkPostNameUnique(post))
         {
-            return error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在");
+            return error("修改岗位'" + post.getPostName() + "'失败,列表中存在重复的岗位名称");
         }
         post.setUpdateBy(getUsername());
         return toAjax(postService.updatePost(post));

+ 2 - 11
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java

@@ -55,7 +55,6 @@ public class SysRoleController extends BaseController
     @Autowired
     private ISysDeptService deptService;
 
-    @PreAuthorize("@ss.hasPermi('system:role:list')")
     @GetMapping("/list")
     public TableDataInfo list(SysRole role)
     {
@@ -95,11 +94,7 @@ public class SysRoleController extends BaseController
     {
         if (!roleService.checkRoleNameUnique(role))
         {
-            return error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在");
-        }
-        else if (!roleService.checkRoleKeyUnique(role))
-        {
-            return error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在");
+            return error("新增角色'" + role.getRoleName() + "'失败,列表中存在重复的角色名称");
         }
         role.setCreateBy(getUsername());
         return toAjax(roleService.insertRole(role));
@@ -118,11 +113,7 @@ public class SysRoleController extends BaseController
         roleService.checkRoleDataScope(role.getRoleId());
         if (!roleService.checkRoleNameUnique(role))
         {
-            return error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在");
-        }
-        else if (!roleService.checkRoleKeyUnique(role))
-        {
-            return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在");
+            return error("修改角色'" + role.getRoleName() + "'失败,列表中存在重复的角色名称");
         }
         role.setUpdateBy(getUsername());
         

+ 17 - 24
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java

@@ -3,6 +3,8 @@ package com.ruoyi.web.controller.system;
 import java.util.List;
 import java.util.stream.Collectors;
 import javax.servlet.http.HttpServletResponse;
+
+import com.ruoyi.app.domain.request.EditSysUser;
 import org.apache.commons.lang3.ArrayUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -56,7 +58,6 @@ public class SysUserController extends BaseController
     /**
      * 获取用户列表
      */
-    @PreAuthorize("@ss.hasPermi('system:user:list')")
     @GetMapping("/list")
     public TableDataInfo list(SysUser user)
     {
@@ -106,13 +107,13 @@ public class SysUserController extends BaseController
         {
             userService.checkUserDataScope(userId);
             SysUser sysUser = userService.selectUserById(userId);
+            if(StringUtils.isNotEmpty(sysUser.getRoles()) && !sysUser.getRoles().isEmpty()){
+                sysUser.setRoleId(sysUser.getRoles().get(0).getRoleId());
+            }
             ajax.put(AjaxResult.DATA_TAG, sysUser);
-            ajax.put("postIds", postService.selectPostListByUserId(userId));
-            ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList()));
         }
         List<SysRole> roles = roleService.selectRoleAll();
         ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
-        ajax.put("posts", postService.selectPostAll());
         return ajax;
     }
 
@@ -124,20 +125,11 @@ public class SysUserController extends BaseController
     @PostMapping
     public AjaxResult add(@Validated @RequestBody SysUser user)
     {
-        deptService.checkDeptDataScope(user.getDeptId());
         roleService.checkRoleDataScope(user.getRoleIds());
         if (!userService.checkUserNameUnique(user))
         {
             return error("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
         }
-        else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
-        {
-            return error("新增用户'" + user.getUserName() + "'失败,手机号码已存在");
-        }
-        else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
-        {
-            return error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在");
-        }
         user.setCreateBy(getUsername());
         user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
         return toAjax(userService.insertUser(user));
@@ -149,24 +141,25 @@ public class SysUserController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:user:edit')")
     @Log(title = "用户管理", businessType = BusinessType.UPDATE)
     @PutMapping
-    public AjaxResult edit(@Validated @RequestBody SysUser user)
+    public AjaxResult edit(@Validated @RequestBody EditSysUser req)
     {
+        SysUser user = new SysUser();
+        user.setUserId(req.getUserId());
+        user.setUserName(req.getUserName());
+        user.setNickName(req.getNickName());
+        user.setEmail(req.getEmail());
+        user.setPhonenumber(req.getPhonenumber());
+        user.setSex(req.getSex());
+        user.setAvatar(req.getAvatar());
+        user.setStatus(req.getStatus());
+        user.setRoleId(req.getRoleId());
         userService.checkUserAllowed(user);
         userService.checkUserDataScope(user.getUserId());
-        deptService.checkDeptDataScope(user.getDeptId());
-        roleService.checkRoleDataScope(user.getRoleIds());
+        roleService.checkRoleDataScope(user.getRoleId());
         if (!userService.checkUserNameUnique(user))
         {
             return error("修改用户'" + user.getUserName() + "'失败,登录账号已存在");
         }
-        else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
-        {
-            return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
-        }
-        else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
-        {
-            return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
-        }
         user.setUpdateBy(getUsername());
         return toAjax(userService.updateUser(user));
     }

+ 143 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/ClientHandler.java

@@ -0,0 +1,143 @@
+package com.ruoyi.web.core.nfid;
+
+import com.ruoyi.app.domain.NFIDReader;
+import com.ruoyi.app.service.INFIDReaderService;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.HexUtil;
+import com.ruoyi.common.utils.spring.SpringUtils;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.util.ReferenceCountUtil;
+import org.springframework.stereotype.Component;
+
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@Component
+public class ClientHandler extends ChannelInboundHandlerAdapter {
+
+
+    private INFIDReaderService NFIDReaderService = SpringUtils.getBean(INFIDReaderService.class);
+
+    private final AtomicInteger responseIndex = new AtomicInteger(1);
+
+    private MultiReaderNFIDProcessor processor = SpringUtils.getBean(MultiReaderNFIDProcessor.class);
+
+    @Override
+    public void channelActive(ChannelHandlerContext ctx) {
+        System.out.println("Client connected: " + ctx.channel().remoteAddress());
+
+        // 识别器连接后发送读取识别器设备信息指令
+        ByteBuf handshake = Unpooled.wrappedBuffer(HexUtil.hexToBytes("5A000101000000DCE5"));
+        ctx.writeAndFlush(handshake);
+    }
+
+    @Override
+    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+        try {
+            ByteBuf byteBuf = (ByteBuf) msg;
+            byte[] bytes = new byte[byteBuf.readableBytes()];
+            byteBuf.readBytes(bytes);
+
+            // 解析帧
+            List<NFIDFrameParser.NFIDFrame> frames = NFIDFrameParser.parseFrames(bytes);
+
+            if (!frames.isEmpty()) {
+                // 处理帧
+                processFrames(ctx, frames);
+            }
+        } finally {
+            ReferenceCountUtil.release(msg); // 释放ByteBuf
+        }
+    }
+
+    private void processFrames(ChannelHandlerContext ctx, List<NFIDFrameParser.NFIDFrame> frames) {
+        for (NFIDFrameParser.NFIDFrame frame : frames) {
+            // 记录接收到的帧
+            System.out.println("Received frame: " + frame);
+
+            // 检查是否需要响应
+            if (NFIDFrameParser.isResponseRequiredFrame(frame)) {
+                //发送读取指令
+                sendResponseFrame(ctx);
+            }
+            // 检查是否读写器信息帧
+            if (NFIDFrameParser.isDeviceInfoFrame(frame)) {
+                // 首次连接时注册设备
+                //if(!DeviceSessionManager.contains(ctx.channel())) {
+                    //读取设备序列号
+                    List<NFIDFrameParser.Parameter> params = frame.getParameters();
+                    if (params != null && params.size() > 0) {
+                        //字节转换成ascii
+                        String DeviceId = new String(params.get(0).getValue(), StandardCharsets.US_ASCII);
+                        DeviceSessionManager.registerDevice(ctx.channel(), DeviceId);
+                        //更新识别器状态
+                        updateNFIDReader(ctx,NFIDReader.STATUS_INLINE);
+                    }
+                //}
+            }
+            //检查是否为标签数据
+            if (NFIDFrameParser.isTagInfoFrame(frame)) {
+                List<NFIDFrameParser.Parameter> params = frame.getParameters();
+                String tag = HexUtil.bytesToHex(params.get(0).getValue());
+                //System.out.println("Tag: " + tag);
+                if (params != null && params.size() > 0) {
+                    String reader =  DeviceSessionManager.getDeviceId(ctx.channel());
+                    if (reader !=null && !reader.equals("")) {
+                        processor.receiveTag(tag, reader);
+                    }
+                }
+            }
+        }
+
+        // 通知帧处理器
+       // frameHandler.handleFrames(frames, ctx);
+    }
+
+    //向读写器发送指令
+    private void sendResponseFrame(ChannelHandlerContext ctx) {
+        int index = responseIndex.getAndUpdate(i -> i < 4 ? i + 1 : 1);
+        byte[] response = NFIDFrameParser.generateResponseFrame(index);
+        ctx.writeAndFlush(Unpooled.wrappedBuffer(response));
+        System.out.println("Sent response frame with index: " + index);
+    }
+
+    @Override
+    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
+        System.out.println("Client disconnected: " + ctx.channel().remoteAddress());
+
+        //更新识别器状态
+        updateNFIDReader(ctx,NFIDReader.STATUS_OFFLINE);
+
+        //断开则取消注册
+        DeviceSessionManager.unregister(ctx.channel());
+        ctx.fireChannelInactive();
+    }
+
+    @Override
+    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+        System.err.println("Error in client handler: " + cause.getMessage());
+
+        //更新识别器状态
+        updateNFIDReader(ctx,NFIDReader.STATUS_ERROR);
+
+        ctx.close();
+    }
+
+    //更新识别器
+    private int updateNFIDReader(ChannelHandlerContext ctx, String status){
+        NFIDReader NFIDReader = new NFIDReader();
+        String deviceId = DeviceSessionManager.getDeviceId(ctx.channel());
+        if(deviceId == null || deviceId.isEmpty()){
+            return 0;
+        }
+        NFIDReader.setDeviceSerial(deviceId);
+        NFIDReader.setLastActiveTime(DateUtils.getNowDate());
+        NFIDReader.setStatus(status);
+        return NFIDReaderService.updateNFIDReaderBySerial(NFIDReader);
+    }
+
+}

+ 44 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/DeviceSessionManager.java

@@ -0,0 +1,44 @@
+package com.ruoyi.web.core.nfid;
+
+import io.netty.channel.Channel;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+public class DeviceSessionManager {
+    private static final ConcurrentHashMap<String, String> channelToDeviceMap = new ConcurrentHashMap<>();
+    private static final ConcurrentHashMap<String, Channel> deviceToChannelMap = new ConcurrentHashMap<>();
+
+    /**
+     * 检查Channel是否已注册设备
+     * @param channel Netty Channel对象
+     * @return 如果已注册返回true,否则返回false
+     */
+    public static boolean contains(Channel channel) {
+        return channelToDeviceMap.containsKey(channel.id().asLongText());
+    }
+
+    // 注册设备连接
+    public static void registerDevice(Channel channel, String deviceId) {
+        String channelId = channel.id().asLongText();
+        channelToDeviceMap.put(channelId, deviceId);
+        deviceToChannelMap.put(deviceId, channel);
+    }
+
+    // 获取设备ID
+    public static String getDeviceId(Channel channel) {
+        return channelToDeviceMap.get(channel.id().asLongText());
+    }
+
+    // 获取设备Channel
+    public static Channel getDeviceChannel(String deviceId) {
+        return deviceToChannelMap.get(deviceId);
+    }
+
+    /**
+     * 取消Channel的注册
+     * @param channel Netty Channel对象
+     */
+    public static void unregister(Channel channel) {
+        channelToDeviceMap.remove(channel.id().asLongText());
+    }
+}

+ 360 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/MultiReaderNFIDProcessor.java

@@ -0,0 +1,360 @@
+package com.ruoyi.web.core.nfid;
+
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
+import com.lmax.disruptor.*;
+import com.lmax.disruptor.dsl.Disruptor;
+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.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.common.utils.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DataAccessException;
+import org.springframework.data.redis.core.RedisOperations;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.SessionCallback;
+import org.springframework.stereotype.Component;
+import java.util.*;
+import java.util.concurrent.*;
+import java.sql.*;
+import java.util.stream.Collectors;
+
+import com.ruoyi.app.domain.NFIDReader;
+
+import javax.annotation.PreDestroy;
+
+@Component
+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 int DISRUPTOR_BUFFER_SIZE = 1024 * 8;
+
+    @Autowired
+    private RedisTemplate<String,String> redisTemplate;
+
+    @Autowired
+    private IHookRegisterService hookRegisterService;
+
+    @Autowired
+    private INFIDReaderService NFIDReaderService;
+
+    @Autowired
+    private IHookBindService hookBindService;
+
+    @Autowired
+    private IPorkSideProduceService porkSideProduceService;
+
+    @PreDestroy
+    public void destroy()
+    {
+        disruptor.shutdown();
+        flushAllBuffers();
+    }
+
+    // 数据结构
+    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)
+            .expireAfterWrite(TAG_EXPIRY_MS, TimeUnit.MILLISECONDS)
+            .build();
+    private final String redisCachePrefix = "nfid:reader:"; // 按识别器分组的缓存
+
+    // Disruptor相关
+    private final Disruptor<TagEvent> disruptor;
+    private final RingBuffer<TagEvent> ringBuffer;
+
+    // 批量处理
+    private final List<TagRecord> batchBuffer = Collections.synchronizedList(new ArrayList<>());
+    // 按阶段分组缓冲区
+    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;
+        long timestamp;
+
+        void set(String tagId, String readerId, long timestamp) {
+            this.tagId = tagId;
+            this.readerId = readerId;
+            this.timestamp = timestamp;
+        }
+    }
+
+    private static class TagRecord {
+        String tagId;
+        String readerId;
+        Timestamp detectionTime;
+    }
+
+    public MultiReaderNFIDProcessor() {
+
+        // 初始化Disruptor
+        ExecutorService disruptorExecutor = Executors.newSingleThreadExecutor();
+        this.disruptor = new Disruptor<>(
+                TagEvent::new,
+                DISRUPTOR_BUFFER_SIZE,
+                disruptorExecutor,
+                ProducerType.MULTI,
+                new SleepingWaitStrategy()
+        );
+
+        // 设置事件处理器
+        disruptor.handleEventsWith(this::handleEvent);
+        this.ringBuffer = disruptor.start();
+
+        // 启动定时任务
+        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
+        scheduler.scheduleAtFixedRate(
+                this::flushAllBuffers,
+                BUFFER_FLUSH_INTERVAL_MS,
+                BUFFER_FLUSH_INTERVAL_MS,
+                TimeUnit.MILLISECONDS
+        );
+        scheduler.scheduleAtFixedRate(
+                this::cleanExpiredCache,
+                1, 1, TimeUnit.MINUTES
+        );
+    }
+
+    /**
+     * 接收标签数据(带识别器ID)
+     */
+    public void receiveTag(String tagId, String readerId) {
+        long sequence = ringBuffer.next();
+        try {
+            TagEvent event = ringBuffer.get(sequence);
+            event.set(tagId, readerId, System.currentTimeMillis());
+        } 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("处理标签事件");
+        String compositeKey = event.readerId + ":" + event.tagId;
+        long now = System.currentTimeMillis();
+
+        // 1. 检查本地缓存
+        Long lastSeen = localCache.getIfPresent(compositeKey);
+        if (lastSeen != null && (now - lastSeen) < TAG_EXPIRY_MS) {
+
+            System.out.println("检查本地缓存");
+            return;
+        }
+
+        // 2. 检查Redis缓存
+        String redisKey = redisCachePrefix + event.readerId;
+        try {
+            Boolean exists = redisTemplate.opsForHash().hasKey(redisKey, event.tagId);
+            System.out.println(redisKey+"-"+event.tagId);
+            if (exists != null && exists) {
+                System.out.println("保存"+compositeKey);
+                localCache.put(compositeKey, now);
+                return;
+            }
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
+        }
+
+        // 新标签,加入处理流程
+        localCache.put(compositeKey, now);
+
+        // 准备批量记录
+        System.out.println("准备批量记录");
+
+
+        // 更新Redis缓存
+        updateRedisCache(event.readerId, event.tagId, now);
+
+        String batchName = getReaderType(event.readerId);
+
+        TagRecord record = new TagRecord();
+        record.tagId = event.tagId;
+        record.readerId = event.readerId;
+        record.detectionTime = new Timestamp(event.timestamp);
+        batchBuffer.add(record);
+
+        // 添加到对应表的缓冲区
+        batchBuffers.computeIfAbsent(batchName, k -> new ArrayList<>())
+                .add(record);
+        // 检查批量大小
+        if (batchBuffers.get(batchName).size() >= BUFFER_FLUSH_SIZE) {
+            flushBuffer(batchName);
+        }
+    }
+
+    private String getReaderType(String deviceSerial){
+       return NFIDReaderService.selectNFIDReaderSpotByKey(deviceSerial);
+    }
+
+    private void updateRedisCache(String readerId, String tagId, long timestamp) {
+        System.out.println("更新Redis缓存");
+        String redisKey = redisCachePrefix + readerId;
+        try  {
+            redisTemplate.opsForHash().put(redisKey, tagId, String.valueOf(timestamp));
+
+            redisTemplate.expire(redisKey, TAG_EXPIRY_MS / 1000, TimeUnit.SECONDS);
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
+        }
+    }
+
+    //刷新全部
+    private void flushAllBuffers() {
+        Set<String> batchNames;
+        synchronized (batchBuffers) {
+            batchNames = new HashSet<>(batchBuffers.keySet());
+        }
+
+        for (String batchName : batchNames) {
+            flushBuffer(batchName);
+        }
+    }
+
+    /**
+     * 批量写入数据库
+     */
+    private void flushBuffer(String batchName) {
+        List<TagRecord> records;
+        synchronized (batchBuffers) {
+            records = new ArrayList<>(batchBuffers.getOrDefault(batchName, Collections.emptyList()));
+            batchBuffers.remove(batchName);
+        }
+
+        if (records.isEmpty()) return;
+
+        try {
+            if(Objects.equals(batchName, NFIDReader.BIND_SPOT)){
+                //吊钩绑定
+                saveBind(records);
+            }else if(Objects.equals(batchName, NFIDReader.WEIGHT_SPOT)){
+                //白条称重
+                saveWeight(records);
+            }else{
+                throw new Exception("未知点位类型:"+batchName);
+            }
+
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
+
+        }
+    }
+    //吊钩绑定
+    private void saveBind(List<TagRecord> records) {
+        //生成新对象
+        List<HookBind> hookBinds = 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;
+                })
+                .collect(Collectors.toList());
+        hookBindService.insertHookBindBatch(hookBinds);
+    }
+
+    //白条称重
+    private void saveWeight(List<TagRecord> records) {
+        //生成新对象
+        List<PorkSideProduce> porkSideProduces = records.stream()
+                .map(item -> {
+                    PorkSideProduce porkSideProduce = new PorkSideProduce();
+                    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());
+
+                    return porkSideProduce;
+                })
+                .collect(Collectors.toList());
+        porkSideProduceService.insertPorkSideProduceBatch(porkSideProduces);
+    }
+    /**
+     * 清理过期缓存
+     */
+    private void cleanExpiredCache() {
+        System.out.println("清理过期缓存");
+        long now = System.currentTimeMillis();
+
+        // 清理本地缓存
+        localCache.asMap().entrySet().removeIf(entry ->
+                (now - entry.getValue()) >= TAG_EXPIRY_MS
+        );
+
+        // 清理Redis缓存
+        try{
+            // 获取所有识别器缓存键
+            // 获取所有匹配的keys
+            Set<String> readerKeys = redisTemplate.keys(redisCachePrefix + "*");
+
+            if (readerKeys != null) {  // keys可能返回null
+                for (String key : readerKeys) {
+                    // 获取整个hash
+                    Map<Object, Object> tags = redisTemplate.opsForHash().entries(key);
+
+                    // 过滤过期的entry
+                    tags.entrySet().removeIf(entry -> {
+                        long timestamp = Long.parseLong(entry.getValue().toString());
+                        return (now - timestamp) >= TAG_EXPIRY_MS;
+                    });
+
+                    // 执行事务操作
+                    redisTemplate.execute(new SessionCallback<Object>() {
+                       @Override
+                        public Object execute(RedisOperations operations) throws DataAccessException {
+                            operations.watch(key);
+                            operations.multi();
+
+                            if (tags.isEmpty()) {
+                                operations.delete(key);
+                            } else {
+                                operations.opsForHash().putAll(key, tags);
+                                operations.expire(key, TAG_EXPIRY_MS / 1000, TimeUnit.SECONDS);
+                            }
+
+                            return operations.exec();
+                        }
+                    });
+                }
+            }
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
+        }
+    }
+}

+ 315 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDFrameParser.java

@@ -0,0 +1,315 @@
+package com.ruoyi.web.core.nfid;
+
+import com.ruoyi.common.utils.HexUtil;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.List;
+
+public class NFIDFrameParser {
+
+    // 帧头标识
+    public static final byte FRAME_HEADER = (byte) 0x5A;
+
+    // 最大数据长度
+    private static final int MAX_DATA_LENGTH = 1024;
+
+    // 最小帧长度(帧头1 + 控制字4 + 长度2 + 校验2 = 9字节)
+    private static final int MIN_FRAME_LENGTH = 9;
+
+    // CRC16-CCITT多项式(X16 + X15 + X2 + 1)
+    private static final int CRC16_POLY = 0x1021;
+    private static final int CRC16_INIT = 0x0000;
+
+    // 添加帧类型判断方法
+    //判断是否待读取
+    public static boolean isResponseRequiredFrame(NFIDFrame frame) {
+        // 判断条件:数据长度在9-20字节之间
+        return frame.getDataLength() >= 9 && frame.getDataLength() < 20;
+    }
+
+    // 添加响应帧生成方法
+    public static byte[] generateResponseFrame(int index) {
+        // 5A0001021000080000000X01020006ED08
+        // 其中X是1-4的循环索引
+        String hexStr = String.format("5A0001021000080000000%d01020006ED08", index);
+        return HexUtil.hexToBytes(hexStr);
+    }
+
+    // 判断是否为读写器信息
+    public static boolean isDeviceInfoFrame(NFIDFrame frame) {
+        // 判断条件:数据长度在70-90字节之间
+        return frame.getDataLength() >= 70;
+    }
+
+    // 判断是否为标签信息
+    public static boolean isTagInfoFrame(NFIDFrame frame) {
+        // 判断条件:数据长度在24字节
+        return frame.getDataLength() == 24;
+    }
+
+    /**
+     * 解析接收到的数据
+     * @param data 接收到的原始字节数组
+     * @return 解析出的完整帧列表
+     */
+    public static List<NFIDFrame> parseFrames(byte[] data) {
+        List<NFIDFrame> frames = new ArrayList<>();
+        ByteBuffer buffer = ByteBuffer.wrap(data).order(ByteOrder.BIG_ENDIAN);
+
+        while (buffer.remaining() >= MIN_FRAME_LENGTH) {
+            // 查找帧头
+            int startPos = buffer.position();
+            if (buffer.get() != FRAME_HEADER) {
+                continue; // 不是帧头,继续查找
+            }
+
+            // 标记帧开始位置
+            int frameStart = startPos;
+
+            try {
+                // 读取控制字(4字节)
+                int controlWord = buffer.getInt();
+
+                // 检查RS485标志位(假设第31位是RS485标志位)
+                boolean hasRS485Address = (controlWord & 0x80000000) != 0;
+
+                // 读取设备地址(如果有)
+                byte deviceAddress = 0;
+                if (hasRS485Address) {
+                    if (buffer.remaining() < 1) {
+                        break; // 数据不足
+                    }
+                    deviceAddress = buffer.get();
+                }
+
+                // 读取数据长度(2字节)
+                if (buffer.remaining() < 2) {
+                    break; // 数据不足
+                }
+                int dataLength = buffer.getShort() & 0xFFFF;
+
+                // 检查数据长度是否合法
+                if (dataLength > MAX_DATA_LENGTH) {
+                    // 非法长度,跳过这个帧头
+                    buffer.position(frameStart + 1);
+                    continue;
+                }
+
+                // 检查是否有足够的数据(数据 + 校验码)
+                if (buffer.remaining() < dataLength + 2) {
+                    break; // 数据不足
+                }
+
+                // 读取数据内容
+                byte[] frameData = new byte[dataLength];
+                buffer.get(frameData);
+
+                // 读取校验码
+                int receivedChecksum = buffer.getShort() & 0xFFFF;
+
+                // 计算校验范围(从控制字到数据结束)
+                int checksumStart = frameStart + 1;
+                int checksumEnd = frameStart + 1 + (hasRS485Address ? 5 : 4) + 2 + dataLength;
+                byte[] checksumData = new byte[checksumEnd - checksumStart];
+                System.arraycopy(data, checksumStart, checksumData, 0, checksumData.length);
+
+                // 计算CRC校验
+                int calculatedChecksum = calculateCRC16(checksumData);
+
+                // 校验通过则添加到结果列表
+                if (receivedChecksum == calculatedChecksum) {
+                    NFIDFrame frame = new NFIDFrame();
+                    frame.setControlWord(controlWord);
+                    frame.setHasRS485Address(hasRS485Address);
+                    frame.setDeviceAddress(deviceAddress);
+                    frame.setDataLength(dataLength);
+                    frame.setData(frameData);
+                    frame.setChecksum(receivedChecksum);
+                    frames.add(frame);
+                } else {
+                    // 校验失败,跳过这个帧头继续查找
+                    buffer.position(frameStart + 1);
+                }
+
+            } catch (Exception e) {
+                // 发生异常,跳过这个帧头继续查找
+                buffer.position(frameStart + 1);
+            }
+        }
+
+        return frames;
+    }
+
+    /**
+     * 计算CRC16-CCITT校验值
+     * @param data 要计算的数据
+     * @return CRC16校验值
+     */
+    private static int calculateCRC16(byte[] data) {
+        int crc = CRC16_INIT;
+
+        for (byte b : data) {
+            crc ^= (b & 0xFF) << 8;
+            for (int i = 0; i < 8; i++) {
+                if ((crc & 0x8000) != 0) {
+                    crc = (crc << 1) ^ CRC16_POLY;
+                } else {
+                    crc <<= 1;
+                }
+                crc &= 0xFFFF; // 确保保持16位
+            }
+        }
+
+        return crc;
+    }
+    public static List<Parameter> parseParameters(byte[] data) {
+
+        List<Parameter> parameters = new ArrayList<>();
+        ByteBuffer buffer = ByteBuffer.wrap(data).order(ByteOrder.BIG_ENDIAN);
+
+        while (buffer.remaining() > 0) {
+            // 读取参数长度(2字节)
+            if (buffer.remaining() < 2) break;
+            int paramLength = buffer.getShort() & 0xFFFF;
+            //System.out.println(paramLength);
+            // 检查是否有足够的数据
+            if (buffer.remaining() < paramLength) break;
+
+            // 读取参数内容
+            byte[] paramValue = new byte[paramLength];
+            buffer.get(paramValue);
+           // System.out.println(bytesToHex(paramValue));
+            parameters.add(new Parameter( paramLength, paramValue));
+        }
+
+        return parameters;
+    }
+
+    /**
+     * 参数数据结构
+     */
+    public static class Parameter {
+        private final int length;
+        private final byte[] value;
+
+        public Parameter(int length, byte[] value) {
+
+            this.length = length;
+            this.value = value;
+        }
+
+
+        public int getLength() {
+            return length;
+        }
+
+        public byte[] getValue() {
+            return value;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("Parameter{ Length=%d, Value=%s}",
+                    length, HexUtil.bytesToHex(value));
+        }
+
+    }
+    /**
+     * NFID帧数据结构
+     */
+    public static class NFIDFrame {
+        private int controlWord;         // 协议控制字(4字节)
+        private boolean hasRS485Address;  // 是否有RS485地址
+        private byte deviceAddress;       // 串行设备地址(1字节)
+        private int dataLength;           // 数据长度(2字节)
+        private byte[] data;              // 数据参数(N字节)
+        private int checksum;            // 校验码(2字节)
+
+        private List<Parameter> parameters; // 新增参数列表
+        // getters and setters
+
+        public List<Parameter> getParameters() {
+            if (parameters == null && data != null) {
+                parameters = parseParameters(data);
+            }
+            return parameters;
+        }
+
+        public int getControlWord() {
+            return controlWord;
+        }
+
+        public void setControlWord(int controlWord) {
+            this.controlWord = controlWord;
+        }
+
+        public boolean isHasRS485Address() {
+            return hasRS485Address;
+        }
+
+        public void setHasRS485Address(boolean hasRS485Address) {
+            this.hasRS485Address = hasRS485Address;
+        }
+
+        public byte getDeviceAddress() {
+            return deviceAddress;
+        }
+
+        public void setDeviceAddress(byte deviceAddress) {
+            this.deviceAddress = deviceAddress;
+        }
+
+        public int getDataLength() {
+            return dataLength;
+        }
+
+        public void setDataLength(int dataLength) {
+            this.dataLength = dataLength;
+        }
+
+        public byte[] getData() {
+            return data;
+        }
+
+        public void setData(byte[] data) {
+            this.data = data;
+        }
+
+        public int getChecksum() {
+            return checksum;
+        }
+
+        public void setChecksum(int checksum) {
+            this.checksum = checksum;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("NFIDFrame{\n");
+            sb.append("  controlWord=0x").append(Integer.toHexString(controlWord)).append("\n");
+            sb.append("  hasRS485Address=").append(hasRS485Address).append("\n");
+            if (hasRS485Address) {
+                sb.append("  deviceAddress=0x").append(String.format("%02X", deviceAddress & 0xFF)).append("\n");
+            }
+            sb.append("  dataLength=").append(dataLength).append("\n");
+            sb.append("  checksum=0x").append(String.format("%04X", checksum)).append("\n");
+
+            // 添加参数信息
+            List<Parameter> params = getParameters();
+            if (!params.isEmpty()) {
+                sb.append("  parameters=[\n");
+                for (Parameter param : params) {
+                    sb.append("    ").append(param).append("\n");
+                }
+                sb.append("  ]\n");
+            }
+
+            sb.append("}");
+            return sb.toString();
+        }
+
+    }
+}

+ 26 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDRedisData.java

@@ -0,0 +1,26 @@
+package com.ruoyi.web.core.nfid;
+
+import java.time.Instant;
+
+public class NFIDRedisData {
+    private String paramValue;
+    private Instant readTime;
+
+    public NFIDRedisData(String paramValue, Instant readTime) {
+        this.paramValue = paramValue;
+        this.readTime = readTime;
+    }
+
+    public String getParamValue() {
+        return paramValue;
+    }
+    public void setParamValue(String paramValue) {
+        this.paramValue = paramValue;
+    }
+    public Instant getReadTime() {
+        return readTime;
+    }
+    public void setReadTime(Instant readTime) {
+        this.readTime = readTime;
+    }
+}

+ 66 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDServer.java

@@ -0,0 +1,66 @@
+package com.ruoyi.web.core.nfid;
+
+import com.ruoyi.common.utils.spring.SpringUtils;
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.*;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class NFIDServer {
+    private final int port = 3729;
+   // private final NFIDFrameHandler frameHandler;
+    private EventLoopGroup bossGroup;
+    private EventLoopGroup workerGroup;
+
+//    @Autowired
+//    private ClientHandler clientHandler;
+
+//    public NFIDServer(int port) {
+//        this.port = port;
+//       // this.frameHandler = frameHandler;
+//    }
+
+    public void start() throws Exception {
+        bossGroup = new NioEventLoopGroup(1);
+        workerGroup = new NioEventLoopGroup();
+
+        try {
+            ServerBootstrap b = new ServerBootstrap();
+            b.group(bossGroup, workerGroup)
+                    .channel(NioServerSocketChannel.class)
+                    .childHandler(new ChannelInitializer<SocketChannel>() {
+                        @Override
+                        protected void initChannel(SocketChannel ch) {
+                            ch.pipeline().addLast(new ClientHandler());
+                        }
+                    })
+                    .option(ChannelOption.SO_BACKLOG, 128)
+                    .childOption(ChannelOption.SO_KEEPALIVE, true);
+
+            ChannelFuture f = b.bind(port).sync();
+            System.out.println("NFID Server started on port " + port);
+            f.channel().closeFuture().sync();
+        } finally {
+            stop();
+        }
+    }
+
+    public void stop() {
+        if (workerGroup != null) {
+            workerGroup.shutdownGracefully();
+        }
+        if (bossGroup != null) {
+            bossGroup.shutdownGracefully();
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        // 启动服务器
+        NFIDServer server = new NFIDServer();
+        server.start();
+    }
+}

+ 246 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDTestClient.java

@@ -0,0 +1,246 @@
+package com.ruoyi.web.core.nfid;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.*;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.timeout.IdleState;
+import io.netty.handler.timeout.IdleStateEvent;
+import io.netty.handler.timeout.IdleStateHandler;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+
+public class NFIDTestClient {
+    private static final String HOST = "localhost";
+    private static final int PORT = 3729;
+    private static final int HEARTBEAT_INTERVAL = 30; // 秒
+    private static final int RECONNECT_DELAY = 5; // 重试间隔(秒)
+
+    // 测试帧数据
+    private static final List<byte[]> TEST_FRAMES = Arrays.asList(
+            hexStringToByteArray("5A000112000018000C00010000F04EE845D972D375340002013D08000DE3AA3482"),
+            hexStringToByteArray("5A000112000018000CE28068940000502F57B4B649300002010D08000DE3AAF63F"),
+            hexStringToByteArray("5A000112000018000C2C14F77EF04EE845D974502A340002012C08000DE3AA7930"),
+            hexStringToByteArray("5A00010100004B00145238303038303030303230323030303030303038000001A1000C4A756E203130203230323000010011000002000E56312E30305F323031393036303903000A323032302D30362D31308FC5")
+    );
+
+    // 心跳帧
+    private static final byte[] HEARTBEAT_FRAME = hexStringToByteArray("5A00000001000000000000");
+
+    // 测试模式枚举
+    private enum TestMode {
+        NORMAL,      // 正常发送
+        STICKY,      // 粘包模式
+        SPLIT,       // 拆包模式
+        MIXED        // 混合模式
+    }
+
+    private static TestMode currentMode = TestMode.MIXED; // 默认使用混合模式
+
+    public static void main(String[] args) throws Exception {
+        if (args.length > 0) {
+            currentMode = TestMode.valueOf(args[0].toUpperCase());
+        }
+        System.out.println("Starting NFID test client in " + currentMode + " mode");
+
+        EventLoopGroup group = new NioEventLoopGroup();
+        Bootstrap bootstrap = createBootstrap(group);
+        connect(bootstrap, 0);
+    }
+
+    private static Bootstrap createBootstrap(EventLoopGroup group) {
+        Bootstrap b = new Bootstrap();
+        b.group(group)
+                .channel(NioSocketChannel.class)
+                .handler(new ChannelInitializer<SocketChannel>() {
+                    @Override
+                    protected void initChannel(SocketChannel ch) {
+                        ch.pipeline()
+                                .addLast(new IdleStateHandler(0, HEARTBEAT_INTERVAL, 0, TimeUnit.SECONDS))
+                                .addLast(new HeartbeatHandler())
+                                .addLast(new FrameSenderHandler())
+                                .addLast(new ResponseHandler());
+                    }
+                });
+        return b;
+    }
+
+    private static void connect(Bootstrap bootstrap, int attempt) {
+        bootstrap.connect(HOST, PORT).addListener(new ChannelFutureListener() {
+            @Override
+            public void operationComplete(ChannelFuture future) throws Exception {
+                if (future.isSuccess()) {
+                    System.out.println("Connected to NFID server at " + HOST + ":" + PORT);
+                    Channel channel = future.channel();
+
+                    channel.closeFuture().addListener(closeFuture -> {
+                        System.out.println("Connection lost, attempting to reconnect...");
+                        scheduleReconnect(bootstrap);
+                    });
+
+                } else {
+                    System.err.println("Connection attempt " + (attempt + 1) + " failed: " + future.cause().getMessage());
+                    scheduleReconnect(bootstrap);
+                }
+            }
+        });
+    }
+
+    private static void scheduleReconnect(Bootstrap bootstrap) {
+        bootstrap.config().group().schedule(() -> {
+            System.out.println("Reconnecting...");
+            connect(bootstrap, 0);
+        }, RECONNECT_DELAY, TimeUnit.SECONDS);
+    }
+
+    /**
+     * 心跳处理器
+     */
+    private static class HeartbeatHandler extends ChannelInboundHandlerAdapter {
+        @Override
+        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
+            if (evt instanceof IdleStateEvent) {
+                IdleStateEvent e = (IdleStateEvent) evt;
+                if (e.state() == IdleState.WRITER_IDLE) {
+                    ctx.writeAndFlush(Unpooled.wrappedBuffer(HEARTBEAT_FRAME));
+                    System.out.println("Sent heartbeat at " + System.currentTimeMillis());
+                }
+            }
+        }
+    }
+
+    /**
+     * 数据帧发送处理器
+     */
+    private static class FrameSenderHandler extends ChannelInboundHandlerAdapter {
+        private final Random random = new Random();
+        private final int MIN_INTERVAL = 500; // 1秒
+        private final int MAX_INTERVAL = 1500; // 3秒
+
+        @Override
+        public void channelActive(ChannelHandlerContext ctx) {
+            System.out.println("Channel active, starting frame sender in " + currentMode + " mode");
+            scheduleSendFrame(ctx);
+        }
+
+        private void scheduleSendFrame(ChannelHandlerContext ctx) {
+            if (!ctx.channel().isActive()) return;
+
+            int delay = MIN_INTERVAL + random.nextInt(MAX_INTERVAL - MIN_INTERVAL);
+            ctx.executor().schedule(() -> {
+                if (ctx.channel().isActive()) {
+                    sendFrameAccordingToMode(ctx);
+                    scheduleSendFrame(ctx);
+                }
+            }, delay, TimeUnit.MILLISECONDS);
+        }
+
+        private void sendFrameAccordingToMode(ChannelHandlerContext ctx) {
+            switch (currentMode) {
+                case NORMAL:
+                    sendNormalFrame(ctx);
+                    break;
+                case STICKY:
+                    sendStickyPackets(ctx);
+                    break;
+                case SPLIT:
+                    sendSplitFrame(ctx);
+                    break;
+                case MIXED:
+                    if (random.nextBoolean()) {
+                        sendNormalFrame(ctx);
+                    } else if (random.nextBoolean()) {
+                        sendStickyPackets(ctx);
+                    } else {
+                        sendSplitFrame(ctx);
+                    }
+                    break;
+            }
+        }
+
+        private void sendNormalFrame(ChannelHandlerContext ctx) {
+            byte[] frame = TEST_FRAMES.get(random.nextInt(TEST_FRAMES.size()));
+            ctx.writeAndFlush(Unpooled.wrappedBuffer(frame));
+            System.out.println("[NORMAL] Sent single frame: " + bytesToHex(frame));
+        }
+
+        private void sendStickyPackets(ChannelHandlerContext ctx) {
+            // 随机合并2-4个帧一起发送
+            int frameCount = 2 + random.nextInt(3);
+            ByteBuf buffer = ctx.alloc().buffer();
+
+            for (int i = 0; i < frameCount; i++) {
+                byte[] frame = TEST_FRAMES.get(random.nextInt(TEST_FRAMES.size()));
+                buffer.writeBytes(frame);
+                System.out.println("[STICKY] Adding frame " + (i+1) + ": " + bytesToHex(frame));
+            }
+
+            ctx.writeAndFlush(buffer);
+            System.out.println("[STICKY] Sent " + frameCount + " frames as sticky packet");
+        }
+
+        private void sendSplitFrame(ChannelHandlerContext ctx) {
+            byte[] frame = TEST_FRAMES.get(random.nextInt(TEST_FRAMES.size()));
+            int splitPoint = 5 + random.nextInt(frame.length - 10); // 确保分割点在中间
+
+            byte[] part1 = Arrays.copyOfRange(frame, 0, splitPoint);
+            byte[] part2 = Arrays.copyOfRange(frame, splitPoint, frame.length);
+
+            System.out.println("[SPLIT] Splitting frame at position " + splitPoint +
+                    " (total length: " + frame.length + ")");
+
+            // 发送第一部分
+            ctx.writeAndFlush(Unpooled.wrappedBuffer(part1));
+            System.out.println("[SPLIT] Sent first part: " + bytesToHex(part1));
+
+            // 延迟发送第二部分
+            ctx.executor().schedule(() -> {
+                if (ctx.channel().isActive()) {
+                    ctx.writeAndFlush(Unpooled.wrappedBuffer(part2));
+                    System.out.println("[SPLIT] Sent second part: " + bytesToHex(part2));
+                }
+            }, 100 + random.nextInt(400), TimeUnit.MILLISECONDS); // 100-500ms延迟
+        }
+    }
+
+    /**
+     * 响应处理器
+     */
+    private static class ResponseHandler extends SimpleChannelInboundHandler<Object> {
+        @Override
+        protected void channelRead0(ChannelHandlerContext ctx, Object msg) {
+            System.out.println("Received server response: " + msg);
+        }
+
+        @Override
+        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
+            System.err.println("Connection error: " + cause.getMessage());
+            ctx.close();
+        }
+    }
+
+    // 辅助方法
+    private static byte[] hexStringToByteArray(String s) {
+        int len = s.length();
+        byte[] data = new byte[len / 2];
+        for (int i = 0; i < len; i += 2) {
+            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+                    + Character.digit(s.charAt(i+1), 16));
+        }
+        return data;
+    }
+
+    private static String bytesToHex(byte[] bytes) {
+        StringBuilder sb = new StringBuilder();
+        for (byte b : bytes) {
+            sb.append(String.format("%02X ", b));
+        }
+        return sb.toString().trim();
+    }
+}

+ 246 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDTestClient1.java

@@ -0,0 +1,246 @@
+package com.ruoyi.web.core.nfid;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.*;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.timeout.IdleState;
+import io.netty.handler.timeout.IdleStateEvent;
+import io.netty.handler.timeout.IdleStateHandler;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+
+public class NFIDTestClient1 {
+    private static final String HOST = "localhost";
+    private static final int PORT = 3729;
+    private static final int HEARTBEAT_INTERVAL = 30; // 秒
+    private static final int RECONNECT_DELAY = 5; // 重试间隔(秒)
+
+    // 测试帧数据
+    private static final List<byte[]> TEST_FRAMES = Arrays.asList(
+            hexStringToByteArray("5A000112000018000C00010000F04EE845D972D375340002013D08000DE3AA3482"),
+            hexStringToByteArray("5A000112000018000CE28068940000502F57B4B649300002010D08000DE3AAF63F"),
+            hexStringToByteArray("5A000112000018000C2C14F77EF04EE845D974502A340002012C08000DE3AA7930"),
+            hexStringToByteArray("5A00010100004B00145238303038303030303230323030303030303038000001A1000C4A756E203130203230323000010011000002000E56312E30305F323031393036303903000A323032302D30362D31308FC5")
+    );
+
+    // 心跳帧
+    private static final byte[] HEARTBEAT_FRAME = hexStringToByteArray("5A00000001000000000000");
+
+    // 测试模式枚举
+    private enum TestMode {
+        NORMAL,      // 正常发送
+        STICKY,      // 粘包模式
+        SPLIT,       // 拆包模式
+        MIXED        // 混合模式
+    }
+
+    private static TestMode currentMode = TestMode.MIXED; // 默认使用混合模式
+
+    public static void main(String[] args) throws Exception {
+        if (args.length > 0) {
+            currentMode = TestMode.valueOf(args[0].toUpperCase());
+        }
+        System.out.println("Starting NFID test client in " + currentMode + " mode");
+
+        EventLoopGroup group = new NioEventLoopGroup();
+        Bootstrap bootstrap = createBootstrap(group);
+        connect(bootstrap, 0);
+    }
+
+    private static Bootstrap createBootstrap(EventLoopGroup group) {
+        Bootstrap b = new Bootstrap();
+        b.group(group)
+                .channel(NioSocketChannel.class)
+                .handler(new ChannelInitializer<SocketChannel>() {
+                    @Override
+                    protected void initChannel(SocketChannel ch) {
+                        ch.pipeline()
+                                .addLast(new IdleStateHandler(0, HEARTBEAT_INTERVAL, 0, TimeUnit.SECONDS))
+                                .addLast(new HeartbeatHandler())
+                                .addLast(new FrameSenderHandler())
+                                .addLast(new ResponseHandler());
+                    }
+                });
+        return b;
+    }
+
+    private static void connect(Bootstrap bootstrap, int attempt) {
+        bootstrap.connect(HOST, PORT).addListener(new ChannelFutureListener() {
+            @Override
+            public void operationComplete(ChannelFuture future) throws Exception {
+                if (future.isSuccess()) {
+                    System.out.println("Connected to NFID server at " + HOST + ":" + PORT);
+                    Channel channel = future.channel();
+
+                    channel.closeFuture().addListener(closeFuture -> {
+                        System.out.println("Connection lost, attempting to reconnect...");
+                        scheduleReconnect(bootstrap);
+                    });
+
+                } else {
+                    System.err.println("Connection attempt " + (attempt + 1) + " failed: " + future.cause().getMessage());
+                    scheduleReconnect(bootstrap);
+                }
+            }
+        });
+    }
+
+    private static void scheduleReconnect(Bootstrap bootstrap) {
+        bootstrap.config().group().schedule(() -> {
+            System.out.println("Reconnecting...");
+            connect(bootstrap, 0);
+        }, RECONNECT_DELAY, TimeUnit.SECONDS);
+    }
+
+    /**
+     * 心跳处理器
+     */
+    private static class HeartbeatHandler extends ChannelInboundHandlerAdapter {
+        @Override
+        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
+            if (evt instanceof IdleStateEvent) {
+                IdleStateEvent e = (IdleStateEvent) evt;
+                if (e.state() == IdleState.WRITER_IDLE) {
+                    ctx.writeAndFlush(Unpooled.wrappedBuffer(HEARTBEAT_FRAME));
+                    System.out.println("Sent heartbeat at " + System.currentTimeMillis());
+                }
+            }
+        }
+    }
+
+    /**
+     * 数据帧发送处理器
+     */
+    private static class FrameSenderHandler extends ChannelInboundHandlerAdapter {
+        private final Random random = new Random();
+        private final int MIN_INTERVAL = 500; // 1秒
+        private final int MAX_INTERVAL = 1500; // 3秒
+
+        @Override
+        public void channelActive(ChannelHandlerContext ctx) {
+            System.out.println("Channel active, starting frame sender in " + currentMode + " mode");
+            scheduleSendFrame(ctx);
+        }
+
+        private void scheduleSendFrame(ChannelHandlerContext ctx) {
+            if (!ctx.channel().isActive()) return;
+
+            int delay = MIN_INTERVAL + random.nextInt(MAX_INTERVAL - MIN_INTERVAL);
+            ctx.executor().schedule(() -> {
+                if (ctx.channel().isActive()) {
+                    sendFrameAccordingToMode(ctx);
+                    scheduleSendFrame(ctx);
+                }
+            }, delay, TimeUnit.MILLISECONDS);
+        }
+
+        private void sendFrameAccordingToMode(ChannelHandlerContext ctx) {
+            switch (currentMode) {
+                case NORMAL:
+                    sendNormalFrame(ctx);
+                    break;
+                case STICKY:
+                    sendStickyPackets(ctx);
+                    break;
+                case SPLIT:
+                    sendSplitFrame(ctx);
+                    break;
+                case MIXED:
+                    if (random.nextBoolean()) {
+                        sendNormalFrame(ctx);
+                    } else if (random.nextBoolean()) {
+                        sendStickyPackets(ctx);
+                    } else {
+                        sendSplitFrame(ctx);
+                    }
+                    break;
+            }
+        }
+
+        private void sendNormalFrame(ChannelHandlerContext ctx) {
+            byte[] frame = TEST_FRAMES.get(random.nextInt(TEST_FRAMES.size()));
+            ctx.writeAndFlush(Unpooled.wrappedBuffer(frame));
+            System.out.println("[NORMAL] Sent single frame: " + bytesToHex(frame));
+        }
+
+        private void sendStickyPackets(ChannelHandlerContext ctx) {
+            // 随机合并2-4个帧一起发送
+            int frameCount = 2 + random.nextInt(3);
+            ByteBuf buffer = ctx.alloc().buffer();
+
+            for (int i = 0; i < frameCount; i++) {
+                byte[] frame = TEST_FRAMES.get(random.nextInt(TEST_FRAMES.size()));
+                buffer.writeBytes(frame);
+                System.out.println("[STICKY] Adding frame " + (i+1) + ": " + bytesToHex(frame));
+            }
+
+            ctx.writeAndFlush(buffer);
+            System.out.println("[STICKY] Sent " + frameCount + " frames as sticky packet");
+        }
+
+        private void sendSplitFrame(ChannelHandlerContext ctx) {
+            byte[] frame = TEST_FRAMES.get(random.nextInt(TEST_FRAMES.size()));
+            int splitPoint = 5 + random.nextInt(frame.length - 10); // 确保分割点在中间
+
+            byte[] part1 = Arrays.copyOfRange(frame, 0, splitPoint);
+            byte[] part2 = Arrays.copyOfRange(frame, splitPoint, frame.length);
+
+            System.out.println("[SPLIT] Splitting frame at position " + splitPoint +
+                    " (total length: " + frame.length + ")");
+
+            // 发送第一部分
+            ctx.writeAndFlush(Unpooled.wrappedBuffer(part1));
+            System.out.println("[SPLIT] Sent first part: " + bytesToHex(part1));
+
+            // 延迟发送第二部分
+            ctx.executor().schedule(() -> {
+                if (ctx.channel().isActive()) {
+                    ctx.writeAndFlush(Unpooled.wrappedBuffer(part2));
+                    System.out.println("[SPLIT] Sent second part: " + bytesToHex(part2));
+                }
+            }, 100 + random.nextInt(400), TimeUnit.MILLISECONDS); // 100-500ms延迟
+        }
+    }
+
+    /**
+     * 响应处理器
+     */
+    private static class ResponseHandler extends SimpleChannelInboundHandler<Object> {
+        @Override
+        protected void channelRead0(ChannelHandlerContext ctx, Object msg) {
+            System.out.println("Received server response: " + msg);
+        }
+
+        @Override
+        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
+            System.err.println("Connection error: " + cause.getMessage());
+            ctx.close();
+        }
+    }
+
+    // 辅助方法
+    private static byte[] hexStringToByteArray(String s) {
+        int len = s.length();
+        byte[] data = new byte[len / 2];
+        for (int i = 0; i < len; i += 2) {
+            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+                    + Character.digit(s.charAt(i+1), 16));
+        }
+        return data;
+    }
+
+    private static String bytesToHex(byte[] bytes) {
+        StringBuilder sb = new StringBuilder();
+        for (byte b : bytes) {
+            sb.append(String.format("%02X ", b));
+        }
+        return sb.toString().trim();
+    }
+}

+ 1 - 1
ruoyi-admin/src/main/resources/application-druid.yml

@@ -8,7 +8,7 @@ spring:
             master:
                 url: jdbc:mysql://localhost:3306/huimv-tuzai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
                 username: root
-                password: root
+                password: hm123456
             # 从库数据源
             slave:
                 # 从数据源开关/默认关闭

+ 4 - 4
ruoyi-admin/src/main/resources/application.yml

@@ -7,8 +7,8 @@ ruoyi:
   # 版权年份
   copyrightYear: 2025
   # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
-  profile: D:/ruoyi/uploadPath
-  #profile: /home/tuzai-file/uploadPath
+  #profile: D:/ruoyi/uploadPath
+  profile: /home/tuzai-file/uploadPath
 
   # 获取ip地址开关
   addressEnabled: false
@@ -18,7 +18,7 @@ ruoyi:
 # 开发环境配置
 server:
   # 服务器的HTTP端口,默认为8080
-  port: 8080
+  port: 8088
   servlet:
     # 应用的访问路径
     context-path: /
@@ -76,7 +76,7 @@ spring:
     # 数据库索引
     database: 10
     # 密码
-    password:
+    password: hm123456
     # 连接超时时间
     timeout: 10s
     lettuce:

+ 62 - 0
ruoyi-common/pom.xml

@@ -57,6 +57,7 @@
         <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-databind</artifactId>
+            <version>2.13.4.2</version>
         </dependency>
         
         <!-- 阿里JSON解析器 -->
@@ -119,6 +120,67 @@
             <artifactId>javax.servlet-api</artifactId>
         </dependency>
 
+        <!--PDF表格解析-->
+        <!-- Tabula 核心库 -->
+        <dependency>
+            <groupId>technology.tabula</groupId>
+            <artifactId>tabula</artifactId>
+            <version>1.0.5</version>
+        </dependency>
+
+        <!-- PDFBox (Tabula 依赖) -->
+        <dependency>
+            <groupId>org.apache.pdfbox</groupId>
+            <artifactId>pdfbox</artifactId>
+            <version>2.0.27</version>
+        </dependency>
+
+        <!-- Commons CLI (Tabula 依赖) -->
+        <dependency>
+            <groupId>commons-cli</groupId>
+            <artifactId>commons-cli</artifactId>
+            <version>1.4</version>
+        </dependency>
+
+        <!-- Commons CSV (Tabula 依赖) -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-csv</artifactId>
+            <version>1.8</version>
+        </dependency>
+
+        <!-- Jackson (Tabula 依赖) -->
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>2.12.3</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.pdfbox</groupId>
+            <artifactId>pdfbox</artifactId>
+            <version>2.0.27</version>
+        </dependency>
+        <!-- Maven 依赖 -->
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.8.16</version> <!-- 使用最新版本 -->
+        </dependency>
+
+        <!-- QR Code generation -->
+        <dependency>
+            <groupId>com.google.zxing</groupId>
+            <artifactId>core</artifactId>
+            <version>3.5.1</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.zxing</groupId>
+            <artifactId>javase</artifactId>
+            <version>3.5.1</version>
+        </dependency>
+
+
     </dependencies>
 
 </project>

+ 1 - 1
ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java

@@ -181,7 +181,7 @@ public @interface Excel
 
     public enum ColumnType
     {
-        NUMERIC(0), STRING(1), IMAGE(2), TEXT(3);
+        NUMERIC(0), STRING(1), IMAGE(2), TEXT(3), QRCODE(4);//增加二维码导出类型
         private final int value;
 
         ColumnType(int value)

+ 15 - 0
ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java

@@ -41,4 +41,19 @@ public class CacheConstants
      * 登录账户密码错误次数 redis key
      */
     public static final String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
+
+    /**
+     * nfid识别器 cache key
+     */
+    public static final String APP_NFID_READER = "nfid_reader:";
+
+    /**
+     * 吊钩-芯片 cache key
+     */
+    public static final String APP_HOOK_EPC = "hook_epc:";
+
+    /**
+     * 吊钩绑定详情 cache key
+     */
+    public static final String APP_HOOK_BIND = "hook_bind:";
 }

+ 0 - 7
ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java

@@ -184,13 +184,6 @@ public class BaseController
         return getLoginUser().getUserId();
     }
 
-    /**
-     * 获取登录部门id
-     */
-    public Long getDeptId()
-    {
-        return getLoginUser().getDeptId();
-    }
 
     /**
      * 获取登录用户名

+ 1 - 4
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java

@@ -95,7 +95,7 @@ public class SysRole extends BaseEntity
     }
 
     @NotBlank(message = "角色名称不能为空")
-    @Size(min = 0, max = 30, message = "角色名称长度不能超过30个字符")
+    @Size(min = 0, max = 10, message = "角色名称输入超出最大长度限制(10位)")
     public String getRoleName()
     {
         return roleName;
@@ -106,8 +106,6 @@ public class SysRole extends BaseEntity
         this.roleName = roleName;
     }
 
-    @NotBlank(message = "权限字符不能为空")
-    @Size(min = 0, max = 100, message = "权限字符长度不能超过100个字符")
     public String getRoleKey()
     {
         return roleKey;
@@ -118,7 +116,6 @@ public class SysRole extends BaseEntity
         this.roleKey = roleKey;
     }
 
-    @NotNull(message = "显示顺序不能为空")
     public Integer getRoleSort()
     {
         return roleSort;

+ 14 - 42
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java

@@ -25,15 +25,11 @@ public class SysUser extends BaseEntity
     @Excel(name = "用户序号", type = Type.EXPORT, cellType = ColumnType.NUMERIC, prompt = "用户编号")
     private Long userId;
 
-    /** 部门ID */
-    @Excel(name = "部门编号", type = Type.IMPORT)
-    private Long deptId;
-
     /** 用户账号 */
     @Excel(name = "登录名称")
     private String userName;
 
-    /** 用户称 */
+    /** 用户称 */
     @Excel(name = "用户名称")
     private String nickName;
 
@@ -70,12 +66,8 @@ public class SysUser extends BaseEntity
     @Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT)
     private Date loginDate;
 
-    /** 部门对象 */
-    @Excels({
-        @Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT),
-        @Excel(name = "部门负责人", targetAttr = "leader", type = Type.EXPORT)
-    })
-    private SysDept dept;
+    /** 当前使用的角色对象 */
+    private SysRole role;
 
     /** 角色对象 */
     private List<SysRole> roles;
@@ -83,9 +75,6 @@ public class SysUser extends BaseEntity
     /** 角色组 */
     private Long[] roleIds;
 
-    /** 岗位组 */
-    private Long[] postIds;
-
     /** 角色ID */
     private Long roleId;
 
@@ -119,18 +108,10 @@ public class SysUser extends BaseEntity
         return userId != null && 1L == userId;
     }
 
-    public Long getDeptId()
-    {
-        return deptId;
-    }
-
-    public void setDeptId(Long deptId)
-    {
-        this.deptId = deptId;
-    }
 
-    @Xss(message = "用户昵称不能包含脚本字符")
-    @Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符")
+    @Xss(message = "用户名称不能包含脚本字符")
+    @NotBlank(message = "用户名称不能为空")
+    @Size(min = 0, max = 10, message = "用户名称输入超出最大长度限制(10位)")
     public String getNickName()
     {
         return nickName;
@@ -143,7 +124,7 @@ public class SysUser extends BaseEntity
 
     @Xss(message = "用户账号不能包含脚本字符")
     @NotBlank(message = "用户账号不能为空")
-    @Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符")
+    @Size(min = 0, max = 10, message = "用户账号输入超出最大长度限制(10位)")
     public String getUserName()
     {
         return userName;
@@ -197,6 +178,8 @@ public class SysUser extends BaseEntity
         this.avatar = avatar;
     }
 
+    @NotBlank(message = "用户密码不能为空")
+    @Size(min = 0, max = 10, message = "用户密码输入超出最大长度限制(10位)")
     public String getPassword()
     {
         return password;
@@ -247,14 +230,14 @@ public class SysUser extends BaseEntity
         this.loginDate = loginDate;
     }
 
-    public SysDept getDept()
+    public SysRole getRole()
     {
-        return dept;
+        return role;
     }
 
-    public void setDept(SysDept dept)
+    public void setRole(SysRole role)
     {
-        this.dept = dept;
+        this.role = role;
     }
 
     public List<SysRole> getRoles()
@@ -277,16 +260,7 @@ public class SysUser extends BaseEntity
         this.roleIds = roleIds;
     }
 
-    public Long[] getPostIds()
-    {
-        return postIds;
-    }
-
-    public void setPostIds(Long[] postIds)
-    {
-        this.postIds = postIds;
-    }
-
+    @NotNull(message = "角色名称不能为空")
     public Long getRoleId()
     {
         return roleId;
@@ -301,7 +275,6 @@ public class SysUser extends BaseEntity
     public String toString() {
         return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
             .append("userId", getUserId())
-            .append("deptId", getDeptId())
             .append("userName", getUserName())
             .append("nickName", getNickName())
             .append("email", getEmail())
@@ -318,7 +291,6 @@ public class SysUser extends BaseEntity
             .append("updateBy", getUpdateBy())
             .append("updateTime", getUpdateTime())
             .append("remark", getRemark())
-            .append("dept", getDept())
             .toString();
     }
 }

+ 1 - 16
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java

@@ -21,10 +21,6 @@ public class LoginUser implements UserDetails
      */
     private Long userId;
 
-    /**
-     * 部门ID
-     */
-    private Long deptId;
 
     /**
      * 用户唯一标识
@@ -81,10 +77,9 @@ public class LoginUser implements UserDetails
         this.permissions = permissions;
     }
 
-    public LoginUser(Long userId, Long deptId, SysUser user, Set<String> permissions)
+    public LoginUser(Long userId,  SysUser user, Set<String> permissions)
     {
         this.userId = userId;
-        this.deptId = deptId;
         this.user = user;
         this.permissions = permissions;
     }
@@ -99,16 +94,6 @@ public class LoginUser implements UserDetails
         this.userId = userId;
     }
 
-    public Long getDeptId()
-    {
-        return deptId;
-    }
-
-    public void setDeptId(Long deptId)
-    {
-        this.deptId = deptId;
-    }
-
     public String getToken()
     {
         return token;

+ 67 - 0
ruoyi-common/src/main/java/com/ruoyi/common/server/EnvInputServer.java

@@ -0,0 +1,67 @@
+package com.ruoyi.common.server;
+
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class EnvInputServer {
+    @Autowired
+    private EnvInputServerHandler serverHandler;
+    //监听端口
+    private int port = 3729;
+    //创建构造方法
+    public EnvInputServer(){
+    }
+
+    public static void main(String[] args) throws InterruptedException {
+        new EnvInputServer().run();
+    }
+/**
+ *
+ * 功能描述: 启动方法前台多个服务  处理多个线程
+ *
+ * @param:
+ * @return:
+ * @auther: LiGang
+ * @date: 2019/3/26 11:31
+ */
+    /**
+     * 启动流程
+     */
+    public   void run() throws InterruptedException {
+        //配置服务端线程组
+        EventLoopGroup bossGroup=new NioEventLoopGroup();
+        EventLoopGroup workGroup=new NioEventLoopGroup();
+
+        try{
+            //引导整个server的启动
+            ServerBootstrap serverBootstrap = new ServerBootstrap();
+            serverBootstrap.group(bossGroup,workGroup)
+                    .channel(NioServerSocketChannel.class)    //指定处理的连接类型
+                    .childHandler(new ChannelInitializer<SocketChannel>() {
+                        @Override
+                        protected void initChannel(SocketChannel socketChannel) throws Exception {
+                            System.out.println("连接建立");
+                            socketChannel.pipeline().addLast(serverHandler);
+                        }
+                    });
+            System.out.println("# 耳标及采集器设备数据接收服务器已经启动,监听端口(Port):"+port);
+            System.out.println("# 准备接收数据:");
+            //绑定端口,同步等待成功
+            ChannelFuture cf = serverBootstrap.bind(port).sync();
+            // 等待服务端监听端口关闭
+            cf.channel().closeFuture().sync();
+        }finally {
+            //优雅的退出
+            bossGroup.shutdownGracefully();
+            workGroup.shutdownGracefully();
+        }
+    }
+}

+ 251 - 0
ruoyi-common/src/main/java/com/ruoyi/common/server/EnvInputServerHandler.java

@@ -0,0 +1,251 @@
+package com.ruoyi.common.server;
+
+
+import cn.hutool.core.util.ObjectUtil;
+import com.ruoyi.common.utils.ModBusUtils;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.util.Date;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+
+
+/**
+ * @Project : huimv.shiwan
+ * @Package : com.huimv.biosafety.uface.controller
+ * @Description : TODO
+ * @Version : 1.0
+ * @Author : ZhuoNing
+ * @Create : 2020-12-25
+ **/
+@ChannelHandler.Sharable
+@Component
+public class EnvInputServerHandler extends ChannelInboundHandlerAdapter {
+    private static final Logger log = LoggerFactory.getLogger(EnvInputServerHandler.class);
+    private StringBuilder askTextSb = null;
+
+    @Autowired
+    private RedisTemplate<String,String> redisTemplate;
+
+
+    private Map<String, String> channelMap = new ConcurrentHashMap<>();
+
+    @Override
+    public void channelActive(ChannelHandlerContext ctx) throws Exception {
+        // 当客户端连接时,打印出客户端的 IP 地址
+        System.out.println("连接成功");
+        ByteBuf bufff = Unpooled.buffer();
+        bufff.writeBytes(hexString2Bytes("5A000101000000DCE5"));
+        ctx.writeAndFlush(bufff);
+        super.channelActive(ctx);
+    }
+
+    // 设备数据的前缀
+    private static final String DEVICE_PREFIX = "device:";
+    private  static Integer INDEX = 1;
+    //
+    public void appendClientAsk(String text) {
+        if (this.askTextSb == null) {
+            askTextSb = new StringBuilder();
+        }
+        askTextSb.append(text);
+    }
+    @Override
+    public  void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+
+        ByteBuf byteBuf = (ByteBuf) msg;
+        byte[] bytes = new byte[byteBuf.readableBytes()];
+        byteBuf.readBytes(bytes);
+        String str = ModBusUtils.bytes2HexString(bytes);
+        System.out.println("收到的数据:"+str);
+        if (!str.startsWith("5A 00")){
+            System.out.println("数据错误:"+str);
+            return;
+        }
+
+        if (bytes.length >80 &&  bytes.length<90){
+            int startIndex = 9;
+            int length = 20;
+            char[] asciiChars = new char[length];
+            for (int i = startIndex; i <  startIndex + length; i++) {
+                asciiChars[i - startIndex] = (char) (bytes[i] & 0xFF); // 使用 & 0xFF 来确保正确处理可能的负值
+            }
+            String asciiString = new String(asciiChars);
+            // 输出结果
+            System.out.println("ASCII String: " + asciiString);
+            String key = ctx.channel().id().asLongText();
+            channelMap.put(key,asciiString);
+            return;
+        }
+
+        //Netty需要用ByteBuf传输
+        ByteBuf bufff = Unpooled.buffer();
+        if (bytes.length < 20 &&bytes.length > 9 ){
+            bufff.writeBytes(hexString2Bytes("5A0001021000080000000"+INDEX+"01020006ED08"));
+            INDEX++;
+            if (INDEX > 4){
+                INDEX =1;
+            }
+        }
+        ctx.writeAndFlush(bufff);
+        String mapKey = ctx.channel().id().asLongText();
+        String clientip = channelMap.get(mapKey);
+        System.out.println(clientip + "-clientip");
+        if(bytes.length   > 49){
+            Date now = new Date();
+            String[] s = str.split(" ");
+            StringBuilder epc = new StringBuilder();
+            for (int i = 9; i < 9 + Integer.parseInt(s[8], 16); i++) {
+                epc.append(s[i]);
+            }
+            //String tian = s[23];
+            String key = DEVICE_PREFIX + epc;
+            System.out.println(epc + "-epc");
+            long timeDifferenceMillis ;
+            if (redisTemplate.hasKey(key)) {
+                String storedTimestampStr = redisTemplate.opsForValue().get(key);
+                if (storedTimestampStr != null) {
+                    long storedTimeMillis = Long.parseLong(storedTimestampStr);
+                    // 计算时间差(毫秒)
+                     timeDifferenceMillis = System.currentTimeMillis() - storedTimeMillis;
+                    //小于一分钟,更新时间戳
+                    if (timeDifferenceMillis < 60 * 1000) {
+                        redisTemplate.opsForValue().set(key, String.valueOf(System.currentTimeMillis()));
+                        redisTemplate.expire(key,6,TimeUnit.HOURS);
+                        System.out.println("时间小于一分钟,更新时间戳");
+                        return;
+                    }else {
+                        redisTemplate.delete(key);
+                    }
+                } else {
+                    // 如果键不存在,可以抛出一个异常或者返回一个特定的值
+                    throw new RuntimeException("Timestamp key not found in Redis");
+                }
+
+            } else {
+
+                System.out.println("存储");
+                return;
+            }
+
+
+            }
+
+
+        //停止读卡
+//        bufff.writeBytes(hexString2Bytes("5A000102FF0000885A"));
+//        ctx.writeAndFlush(bufff);
+
+        super.channelRead(ctx, msg);
+    }
+
+    public   static boolean isStartOfToday(Date date) {
+        // 创建一个示例的LocalDateTime对象
+        LocalDateTime exampleTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
+        // 获取今天的开始时间
+        LocalDateTime todayStart = LocalDateTime.of(LocalDateTime.now().toLocalDate(), LocalTime.MIDNIGHT);
+
+        // 比较给定的时间和今天的开始时间
+        if (exampleTime.isAfter(todayStart)) {
+            System.out.println("给定的时间大于今天的开始时间");
+            return true;
+        } else {
+            System.out.println("给定的时间不大于今天的开始时间");
+            return false;
+        }
+    }
+    public  boolean isTimeBetween(LocalTime startTime, LocalTime endTime) {
+        LocalDateTime now = LocalDateTime.now();
+
+        // 获取当前日期的00:00和23:59:59
+        LocalDateTime startOfDay = now.withHour(0).withMinute(0).withSecond(0).withNano(0);
+        LocalDateTime endOfDay = startOfDay.plusDays(1).minusSeconds(1);
+
+        // 创建表示时间段的开始和结束时间的LocalDateTime对象
+        LocalDateTime startDateTime = LocalDateTime.of(now.toLocalDate(), startTime);
+        LocalDateTime endDateTime = LocalDateTime.of(now.toLocalDate(), endTime);
+
+        // 判断当前时间是否在两个时间段之一内
+        if (endDateTime.isBefore(startDateTime)) {
+            // 时间段跨越午夜,分两部分判断
+            return (now.isAfter(startDateTime) && now.isBefore(endOfDay)) ||
+                    (now.isAfter(startOfDay) && now.isBefore(endDateTime));
+        } else {
+            // 时间段在同一天内,直接判断
+            return now.isAfter(startDateTime) && now.isBefore(endDateTime);
+        }
+    }
+    @Override
+    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
+        Channel channel = ctx.channel();
+        String key = channel.id().asLongText(); // 或者使用其他唯一标识符
+        System.out.println("退出-->"+key);
+        channelMap.remove(key);
+        super.channelInactive(ctx);
+    }
+    public static byte[] hexString2Bytes(String src) {
+
+        int l = src.length() / 2;
+
+        byte[] ret = new byte[l];
+
+        for (int i = 0; i < l; i++) {
+
+            ret[i] = (byte) Integer.valueOf(src.substring(i * 2, i * 2 + 2), 16).byteValue();
+
+        }
+
+        return ret;
+
+    }
+
+
+
+
+
+    @Override
+    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
+
+//        if (true){
+//            ctx.writeAndFlush(Unpooled.copiedBuffer(new byte[]{1, 2, 3}));
+//        }
+
+//        if (askTextSb.toString().indexOf("end") != -1) {
+//            // {处理客户端消息}
+
+
+//            handleClientAskCmd(askTextSb.toString(), ctx);
+//            //清空重置;
+//            askTextSb.delete(0, askTextSb.length());
+//        }
+    }
+
+    @Override
+    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+        if (cause.getMessage().indexOf("Connection reset") != -1) {
+            log.info("相关采集器设备正在重启:" + cause.toString());
+        }
+        ctx.close();
+    }
+
+    //应答
+    public void answerCmd(String answerText, ChannelHandlerContext ctx) {
+        ctx.writeAndFlush(Unpooled.copiedBuffer(answerText.getBytes()));
+    }
+
+
+}

+ 55 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/ConvertUtil.java

@@ -0,0 +1,55 @@
+package com.ruoyi.common.utils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ConvertUtil {
+    private static final Map<Character, Integer> digitMap = new HashMap<>();
+    private static final Map<Character, Integer> unitMap = new HashMap<>();
+
+    static {
+        // 数字映射
+        digitMap.put('零', 0);
+        digitMap.put('壹', 1);
+        digitMap.put('贰', 2);
+        digitMap.put('叁', 3);
+        digitMap.put('肆', 4);
+        digitMap.put('伍', 5);
+        digitMap.put('陆', 6);
+        digitMap.put('柒', 7);
+        digitMap.put('捌', 8);
+        digitMap.put('玖', 9);
+
+        // 单位映射
+        unitMap.put('拾', 10);
+        unitMap.put('佰', 100);
+        unitMap.put('仟', 1000);
+        unitMap.put('万', 10000);
+    }
+
+    public static int convertChineseNum(String chineseNumber) {
+        int result = 0;
+        int temp = 0;
+        int prevDigit = 0;
+
+        for (int i = 0; i < chineseNumber.length(); i++) {
+            char c = chineseNumber.charAt(i);
+
+            if (digitMap.containsKey(c)) {
+                prevDigit = digitMap.get(c);
+                temp = temp * 10 + prevDigit;
+            } else if (unitMap.containsKey(c)) {
+                int unit = unitMap.get(c);
+                if (unit == 10000) {
+                    result = (result + temp) * unit;
+                    temp = 0;
+                } else {
+                    temp += prevDigit * (unit - 1);
+                }
+                prevDigit = 0;
+            }
+        }
+
+        return result + temp;
+    }
+}

+ 61 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/FindUtil.java

@@ -0,0 +1,61 @@
+package com.ruoyi.common.utils;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.ArrayList;
+import java.util.List;
+public class FindUtil {
+    private static final String PHONE_REGEX = "1[3-9]\\d{9}";
+    private static final Pattern PHONE_PATTERN = Pattern.compile(PHONE_REGEX);
+    private static final Pattern ADDR_PATTERN = Pattern.compile("^(?=.*省)(?=.*市)(?=.*,).*$");
+    // 匹配省市开头的正则表达式
+    private static final Pattern ADDRESS_START_PATTERN =
+            Pattern.compile("^([^,]+省|[^,]+自治区|[^,]+直辖市|[^,]+市),[^,]+市(?:,|$)");
+    public static int findFirstPhoneNumberIndex(String[] array) {
+        for (int i = 0; i < array.length; i++) {
+            if (PHONE_PATTERN.matcher(array[i]).matches()) {
+                return i;
+            }
+        }
+        return -1; // 未找到
+    }
+    public static int findFirstAddrIndex(String[] array) {
+        for (int i = 0; i < array.length; i++) {
+            if (isPDFAddr(array[i])) {
+                return i;
+            }
+        }
+        return -1; // 未找到
+    }
+    public static boolean isPDFAddr(String addr) {
+        return ADDR_PATTERN.matcher(addr).matches();
+    }
+
+
+    public static List<String> extractAddresses(String[] fragments) {
+        List<String> addresses = new ArrayList<>();
+        StringBuilder currentAddress = null;
+
+        for (String fragment : fragments) {
+            Matcher matcher = ADDRESS_START_PATTERN.matcher(fragment);
+            if (matcher.find()) {
+                // 发现新地址开始
+                if (currentAddress != null) {
+                    addresses.add(currentAddress.toString());
+                }
+                currentAddress = new StringBuilder(fragment);
+            }
+            else if (currentAddress != null) {
+                // 继续拼接当前地址
+                currentAddress.append(fragment);
+            }
+        }
+
+        // 添加最后一个地址
+        if (currentAddress != null) {
+            addresses.add(currentAddress.toString());
+        }
+
+        return addresses;
+    }
+}

+ 27 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/HexUtil.java

@@ -0,0 +1,27 @@
+package com.ruoyi.common.utils;
+
+public class HexUtil {
+    private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
+
+    public static String bytesToHex(byte[] bytes) {
+        if (bytes == null) return "null";
+        char[] hexChars = new char[bytes.length * 2];
+        for (int j = 0; j < bytes.length; j++) {
+            int v = bytes[j] & 0xFF;
+            hexChars[j * 2] = HEX_ARRAY[v >>> 4];
+            hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
+        }
+        return new String(hexChars);
+    }
+
+    public static byte[] hexToBytes(String s) {
+        int len = s.length();
+        byte[] data = new byte[len / 2];
+        for (int i = 0; i < len; i += 2) {
+            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+                    + Character.digit(s.charAt(i+1), 16));
+        }
+        return data;
+    }
+
+}

+ 51 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/ModBusUtils.java

@@ -0,0 +1,51 @@
+package com.ruoyi.common.utils;
+
+/**
+ * TODO
+ *
+ * @author linfeng
+ * @date 2022/12/8 16:04
+ */
+public class ModBusUtils {
+
+    public static char byteToASCLL(byte b) {
+        return (char) b;
+    }
+
+
+    /*
+     * 字节数组转16进制字符串
+     */
+    public static String bytes2HexString(byte[] b) {
+        String r = "";
+        for (int i = 0; i < b.length; i++) {
+            String hex = Integer.toHexString(b[i] & 0xFF);
+            if (hex.length() == 1) {
+                hex = '0' + hex;
+            }
+            r += hex.toUpperCase() + " ";
+        }
+        return r;
+    }
+    public static byte[] hexStr2Bytes(String src) {
+        src = src.replaceAll(" ", "");
+        System.out.println(src);
+        int m = 0, n = 0;
+        int l = src.length() / 2;
+        byte[] ret = new byte[l];
+        for (int i = 0; i < l; i++) {
+            m = i * 2 + 1;
+            n = m + 1;
+            String sss = "0x" + src.substring(i * 2, m) + src.substring(m, n);
+            try {
+                ret[i] = Byte.decode(sss);
+            } catch (Exception e) {
+                // TODO: handle exception
+                int s = Integer.decode(sss);
+                ret[i] = (byte)s;
+            }
+        }
+        return ret;
+    }
+}
+

+ 21 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/NumberUtil.java

@@ -0,0 +1,21 @@
+package com.ruoyi.common.utils;
+
+public class NumberUtil {
+    /**
+     * 安全获取Integer值,null时返回0
+     * @param number Integer对象
+     * @return int值,null时返回0
+     */
+    public static int getIntValue(Integer number) {
+        return number != null ? number : 0;
+    }
+
+    /**
+     * 安全获取Long值,null时返回0L
+     * @param number Long对象
+     * @return long值,null时返回0L
+     */
+    public static long getLongValue(Long number) {
+        return number != null ? number : 0L;
+    }
+}

+ 159 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/PdfParseUtil.java

@@ -0,0 +1,159 @@
+package com.ruoyi.common.utils;
+import cn.hutool.core.convert.NumberChineseFormatter;
+import org.apache.pdfbox.text.PDFTextStripper;
+import org.springframework.web.multipart.MultipartFile;
+import technology.tabula.*;
+import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class PdfParseUtil {
+    public static Map<String, Object> extractPdfContent(MultipartFile multipartFile) throws IOException {
+        // 1. 转换MultipartFile为临时File
+        File pdfFile = convertMultipartToFile(multipartFile);
+
+        // 2. 执行提取
+        try (PDDocument document = PDDocument.load(pdfFile)) {
+            Map<String, Object> result = new LinkedHashMap<>();
+
+            // 提取第一页表单数据
+            Map<String, String> formData =  extractFormData(document);
+            Map<String, String> tableData = new LinkedHashMap<>();
+            // 提取第二页表格数据(如果存在)
+            if (document.getNumberOfPages() >= 2) {
+                tableData =  extractTableData(document, 2);
+            }
+
+            // 合并
+            result.putAll(formData);
+            result.putAll(tableData);
+            return result;
+        } finally {
+            // 3. 删除临时文件
+            Files.deleteIfExists(pdfFile.toPath());
+        }
+    }
+    private static File convertMultipartToFile(MultipartFile multipartFile) throws IOException {
+        File tempFile = Files.createTempFile("pdf-", ".pdf").toFile();
+        try (InputStream inputStream = multipartFile.getInputStream()) {
+            Files.copy(inputStream, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
+        }
+        return tempFile;
+    }
+
+    private static Map<String, String> extractFormData(PDDocument document) throws IOException {
+        PDFTextStripper stripper = new PDFTextStripper();
+        stripper.setStartPage(1);
+        stripper.setEndPage(1);
+        String text = stripper.getText(document);
+        return parseFormText(text);
+    }
+
+
+    public static Map<String, String> extractTableData(PDDocument document, int pageNumber) throws IOException {
+        Map<String, String> tableData = new LinkedHashMap<>();
+        ObjectExtractor extractor = new ObjectExtractor(document);
+        SpreadsheetExtractionAlgorithm algorithm = new SpreadsheetExtractionAlgorithm();
+//        Page page = extractor.extract(pageNumber);
+//        return algorithm.extract(page);
+        List<Table> tables = new ArrayList<>();
+        PageIterator pages = extractor.extract();
+
+        while (pages.hasNext()) {
+            Page page = pages.next();
+            tables.addAll(algorithm.extract(page));
+        }
+        List<List<List<String>>> parseData =  tables.stream()
+                .map(PdfParseUtil::convertTableToData)
+                .collect(Collectors.toList());
+        String animalCertNo = "";
+        String animalEartags = "";
+        if (parseData.size()>0){
+            animalCertNo = Optional.ofNullable(parseData)
+                    .filter(list -> list.size() > 0)
+                    .map(list -> list.get(0))
+                    .filter(list -> list.size() > 0)
+                    .map(list -> list.get(0))
+                    .filter(list -> list.size() > 1)
+                    .map(list -> list.get(1)).orElse("");
+        }
+         for (int i = 0; i < parseData.size(); i++) {
+             int finalI = i;
+             animalEartags = Optional.ofNullable(parseData)
+                     .filter(list -> list.size() > finalI)
+                     .map(list -> list.get(finalI))
+                     .filter(list -> list.size() > 2)
+                     .map(list -> list.get(2))
+                     .filter(list -> list.size() > 0)
+                     .map(list -> list.get(0)).orElse("");
+         }
+
+        animalEartags = animalEartags.replaceAll("[\\n\\r]", "");
+        if (!parseData.isEmpty() && parseData.get(0).size() > 1) {
+            tableData.put("animalCertNo", animalCertNo);
+            tableData.put("animalEartags", animalEartags);
+        }
+        return tableData;
+    }
+    private static Map<String, String> parseFormText(String text) {
+        Map<String, String> formData = new LinkedHashMap<>();
+        text = text.replaceAll("\r\n|\n", "\n"); //windows识别是\r\n分割的,linux识别是\n分割 统一替换兼容使用 \n
+        String[] lines = text.split("\n");
+        if (lines.length < 11) {
+            return formData;//少于这个长度说明PDF解析内容不够
+        }
+        formData.put("animalCertNo",lines[0].replaceAll("No.", ""));//备用动物检疫证号
+        formData.put("cargoOwner",lines[1]);//货主
+        formData.put("companyNo",lines[2]);//主体识别号
+        formData.put("cargoOwnerPhone",lines[3]);//货主联系方式
+        formData.put("animalCategory",lines[4]);//动物种类
+        formData.put("amount", String.valueOf(lines[5].isEmpty() ?0: NumberChineseFormatter.chineseToNumber(lines[5].substring(0,lines[5].length() - 1))));//数量
+        formData.put("units", lines[5].isEmpty() ?"":lines[5].substring(lines[5].length() - 1));//单位
+        //第二步
+        String[] newLines = Arrays.copyOfRange(lines, 6, lines.length);
+        if (newLines.length == 0) {
+            return formData;
+        }
+        int index = FindUtil.findFirstPhoneNumberIndex(newLines);//根据第二个手机号码的位置为参照点
+        if (index == -1) {
+            return formData;
+        }
+        formData.put("carrierPhone",index>0 ? newLines[index] : "");//承运人联系方式
+        formData.put("carrier",index-2>0 ? newLines[index-2] : "");//承运人
+        formData.put("useto",index-1>0 ? newLines[index-1] : "");//用途
+        StringBuilder animalEartags = new StringBuilder();//备用耳标号
+        for(int i = index+1;i<newLines.length;i++) {
+            //从第二个手机号码的位置往后读取
+            if(newLines[i] != null && newLines[i].matches("^[0-9]+(,[0-9]+)*$")){
+                animalEartags.append(newLines[i]);
+            }
+
+        }
+        formData.put("animalEartags",animalEartags.toString());//备用耳标号,防止没有第二页的情况读不到耳标号,比如头数很少的情况
+
+        //formData.put("remark",newLines.length>index+2?newLines[index+2] : "");//备注  备注经常没有,不容易获取
+        //第三步,启运地址和到达地址
+        String[] newAddrLines = Arrays.copyOfRange(newLines, 0, index-2);
+        if (newAddrLines.length == 0) {
+            return formData;
+        }
+        List<String> addrArr = FindUtil.extractAddresses(newAddrLines);
+        formData.put("fromPlace",addrArr.size()==2 ? addrArr.get(0) : "");//启运地点
+        formData.put("toPlace",addrArr.size()==2 ? addrArr.get(1) : "");//到达地点
+        return formData;
+    }
+    public static List<List<String>> convertTableToData(Table table) {
+        return table.getRows()
+                .stream()
+                .map(row -> row.stream()
+                        .map(RectangularTextContainer::getText)
+                        .collect(Collectors.toList()))
+                .collect(Collectors.toList());
+    }
+}

+ 16 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/QRCodeUtil.java

@@ -0,0 +1,16 @@
+package com.ruoyi.common.utils;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.client.j2se.MatrixToImageWriter;
+import com.google.zxing.common.BitMatrix;
+import com.google.zxing.qrcode.QRCodeWriter;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+
+import static com.ruoyi.common.utils.poi.ExcelUtil.log;
+
+public class QRCodeUtil {
+
+}

+ 0 - 15
ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java

@@ -37,21 +37,6 @@ public class SecurityUtils
     }
 
     /**
-     * 获取部门ID
-     **/
-    public static Long getDeptId()
-    {
-        try
-        {
-            return getLoginUser().getDeptId();
-        }
-        catch (Exception e)
-        {
-            throw new ServiceException("获取部门ID异常", HttpStatus.UNAUTHORIZED);
-        }
-    }
-
-    /**
      * 获取用户账户
      **/
     public static String getUsername()

+ 6 - 3
ruoyi-common/src/main/java/com/ruoyi/common/utils/TimeUtil.java

@@ -27,10 +27,13 @@ public class TimeUtil {
      * @return Date数组,[0]=当天开始时间,[1]=当天结束时间
      */
     public static Date[] getTodayRangeWithCurrentTime() {
-        LocalDateTime now = currentDateTime();
+        ZonedDateTime startOfDay = LocalDate.now().atStartOfDay(ZoneId.systemDefault());
+        ZonedDateTime endOfDay = LocalDate.now()
+                .atTime(23, 59, 59)
+                .atZone(ZoneId.systemDefault());
         return new Date[]{
-                toDate(now),
-                toDate(now)
+                Date.from(startOfDay.toInstant()),
+                Date.from(endOfDay.toInstant())
         };
     }
 

+ 21 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/jsonUtil.java

@@ -0,0 +1,21 @@
+package com.ruoyi.common.utils;
+
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+
+import java.util.*;
+
+public class jsonUtil {
+    public static boolean checkForDuplicateFields(JsonNode jsonArray, String fieldName) {
+        Set<JsonNode> fieldValues = new HashSet<>();
+
+        for (JsonNode obj : jsonArray) {
+            JsonNode value = obj.get(fieldName);
+            if (value != null && !fieldValues.add(value)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}

+ 47 - 6
ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java

@@ -1,10 +1,7 @@
 package com.ruoyi.common.utils.poi;
 
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
+import java.awt.image.BufferedImage;
+import java.io.*;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.ParameterizedType;
@@ -23,7 +20,14 @@ import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
 import java.util.stream.Collectors;
+import javax.imageio.ImageIO;
 import javax.servlet.http.HttpServletResponse;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.client.j2se.MatrixToImageWriter;
+import com.google.zxing.common.BitMatrix;
+import com.google.zxing.qrcode.QRCodeWriter;
+import com.ruoyi.common.utils.QRCodeUtil;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.RegExUtils;
 import org.apache.commons.lang3.reflect.FieldUtils;
@@ -93,7 +97,7 @@ import com.ruoyi.common.utils.reflect.ReflectUtils;
  */
 public class ExcelUtil<T>
 {
-    private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);
+    public static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);
 
     public static final String FORMULA_REGEX_STR = "=|-|\\+|@";
 
@@ -1045,6 +1049,22 @@ public class ExcelUtil<T>
                         cell.getSheet().getWorkbook().addPicture(data, getImageType(data)));
             }
         }
+        else if (ColumnType.QRCODE == attr.cellType()) {  // 新增二维码类型处理
+            String qrContent = Convert.toStr(value);
+            if (StringUtils.isNotEmpty(qrContent)) {
+                byte[] qrCodeBytes = generateQRCode(qrContent, 100, 100);//目前设置默认宽高
+                if (qrCodeBytes != null) {
+                    // 设置行高以匹配二维码高度(单位:点)
+                    cell.getRow().setHeightInPoints(100 / 1.5f); // 调整除数以获得最佳比例
+
+                    ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0,
+                            (short) cell.getColumnIndex(), cell.getRow().getRowNum(),
+                            (short) (cell.getColumnIndex() + 1), cell.getRow().getRowNum() + 1);
+                    getDrawingPatriarch(cell.getSheet()).createPicture(anchor,
+                            cell.getSheet().getWorkbook().addPicture(qrCodeBytes, Workbook.PICTURE_TYPE_PNG));
+                }
+            }
+        }
     }
 
     /**
@@ -1897,4 +1917,25 @@ public class ExcelUtil<T>
         }
         return method;
     }
+
+    /**
+     * 生成二维码图片字节数组
+     * @param content 二维码内容
+     * @param width 宽度
+     * @param height 高度
+     * @return 二维码图片字节数组
+     */
+    private byte[] generateQRCode(String content, int width, int height) {
+        try {
+            QRCodeWriter qrCodeWriter = new QRCodeWriter();
+            BitMatrix bitMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, width, height);
+            BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(bitMatrix);
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            ImageIO.write(bufferedImage, "png", baos);
+            return baos.toByteArray();
+        } catch (Exception e) {
+            log.error("生成二维码失败", e);
+            return null;
+        }
+    }
 }

+ 0 - 8
ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java

@@ -129,14 +129,6 @@ public class DataScopeAspect
                     sqlString.append(StringUtils.format(" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias, role.getRoleId()));
                 }
             }
-            else if (DATA_SCOPE_DEPT.equals(dataScope))
-            {
-                sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));
-            }
-            else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope))
-            {
-                sqlString.append(StringUtils.format(" OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )", deptAlias, user.getDeptId(), user.getDeptId()));
-            }
             else if (DATA_SCOPE_SELF.equals(dataScope))
             {
                 if (StringUtils.isNotBlank(userAlias))

+ 0 - 4
ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java

@@ -100,10 +100,6 @@ public class LogAspect
             {
                 operLog.setOperName(loginUser.getUsername());
                 SysUser currentUser = loginUser.getUser();
-                if (StringUtils.isNotNull(currentUser) && StringUtils.isNotNull(currentUser.getDept()))
-                {
-                    operLog.setDeptName(currentUser.getDept().getDeptName());
-                }
             }
 
             if (e != null)

+ 18 - 0
ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java

@@ -1,14 +1,26 @@
 package com.ruoyi.framework.config;
 
+import cn.hutool.core.thread.ThreadFactoryBuilder;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.cache.annotation.CachingConfigurerSupport;
 import org.springframework.cache.annotation.EnableCaching;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.connection.RedisPassword;
+import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
+import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
 import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.SetOperations;
+import org.springframework.data.redis.core.StreamOperations;
+import org.springframework.data.redis.core.ZSetOperations;
 import org.springframework.data.redis.core.script.DefaultRedisScript;
+import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
 /**
  * redis配置
  * 
@@ -36,6 +48,11 @@ public class RedisConfig extends CachingConfigurerSupport
         template.setHashValueSerializer(serializer);
 
         template.afterPropertiesSet();
+
+        // 必须设置这些属性才能支持Stream操作
+        template.setEnableTransactionSupport(true);
+        template.setEnableDefaultSerializer(false);
+        template.afterPropertiesSet();
         return template;
     }
 
@@ -66,4 +83,5 @@ public class RedisConfig extends CachingConfigurerSupport
                 "end\n" +
                 "return tonumber(current);";
     }
+
 }

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

@@ -111,7 +111,7 @@ public class SecurityConfig
             .authorizeHttpRequests((requests) -> {
                 permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll());
                 // 对于登录login 注册register 验证码captchaImage 允许匿名访问
-                requests.antMatchers("/login", "/loginNoCaptcha","/register", "/captchaImage").permitAll()
+                requests.antMatchers("/login", "/loginNoCaptcha","/register", "/captchaImage","/common/addBatch").permitAll()
                     // 静态资源,可匿名访问
                     .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
                     .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()

+ 1 - 1
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java

@@ -61,6 +61,6 @@ public class UserDetailsServiceImpl implements UserDetailsService
 
     public UserDetails createLoginUser(SysUser user)
     {
-        return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
+        return new LoginUser(user.getUserId(), user, permissionService.getMenuPermission(user));
     }
 }

+ 33 - 0
ruoyi-system/src/main/java/com/ruoyi/app/DTO/DailyEntranceAmountDTO.java

@@ -0,0 +1,33 @@
+package com.ruoyi.app.DTO;
+
+import java.math.BigDecimal;
+
+public class DailyEntranceAmountDTO {
+    private Long illnessDeadAmountSum;
+    private Long illnessDiseaseAmountSum;
+    private Long entranceAmountSum;
+
+    public Long getIllnessDeadAmountSum() {
+        return illnessDeadAmountSum;
+    }
+
+    public void setIllnessDeadAmountSum(Long illnessDeadAmountSum) {
+        this.illnessDeadAmountSum = illnessDeadAmountSum;
+    }
+
+    public Long getIllnessDiseaseAmountSum() {
+        return illnessDiseaseAmountSum;
+    }
+
+    public void setIllnessDiseaseAmountSum(Long illnessDiseaseAmountSum) {
+        this.illnessDiseaseAmountSum = illnessDiseaseAmountSum;
+    }
+
+    public Long getEntranceAmountSum() {
+        return entranceAmountSum;
+    }
+
+    public void setEntranceAmountSum(Long entranceAmountSum) {
+        this.entranceAmountSum = entranceAmountSum;
+    }
+}

+ 3 - 0
ruoyi-system/src/main/java/com/ruoyi/app/DTO/EntranceReportDTO.java

@@ -1,8 +1,11 @@
 package com.ruoyi.app.DTO;
 
+import com.fasterxml.jackson.annotation.JsonFormat;
+
 import java.math.BigDecimal;
 
 public class EntranceReportDTO {
+    @JsonFormat(pattern = "yyyy-MM-dd")
     private String entranceTime;
     private String animalCertNo;
     private String animalEartags;

+ 24 - 0
ruoyi-system/src/main/java/com/ruoyi/app/DTO/HookBindBatchListDTO.java

@@ -1,13 +1,18 @@
 package com.ruoyi.app.DTO;
 
+import com.fasterxml.jackson.annotation.JsonFormat;
+
 import java.util.Date;
 
 public class HookBindBatchListDTO {
     private String batchNo;
+    private String groupId;
     private String slaughterCode;
     private String hookNoList;
     private Long total;
     private Long distributeBatchId;
+    private String isBind;
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date bindTime;
     private String purchaserName;
     private String supplierName;
@@ -23,6 +28,16 @@ public class HookBindBatchListDTO {
         return batchNo;
     }
 
+    public void setGroupId(String groupId)
+    {
+        this.groupId = groupId;
+    }
+
+    public String getGroupId()
+    {
+        return groupId;
+    }
+
     public void setSlaughterCode(String slaughterCode)
     {
         this.slaughterCode = slaughterCode;
@@ -63,6 +78,15 @@ public class HookBindBatchListDTO {
         return distributeBatchId;
     }
 
+    public void setIsBind(String isBind)
+    {
+        this.isBind = isBind;
+    }
+
+    public String getIsBind()
+    {
+        return isBind;
+    }
 
     public void setBindTime(Date bindTime)
     {

+ 1 - 0
ruoyi-system/src/main/java/com/ruoyi/app/DTO/PorkProduceDTO.java

@@ -11,6 +11,7 @@ public class PorkProduceDTO {
     private String productName;
 
     /** 生产时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date produceTime;
 
     /** 血码 */

+ 4 - 0
ruoyi-system/src/main/java/com/ruoyi/app/DTO/ProductTraceDTO.java

@@ -1,11 +1,15 @@
 package com.ruoyi.app.DTO;
 
+import com.fasterxml.jackson.annotation.JsonFormat;
+
 import java.math.BigDecimal;
 import java.util.List;
 
 public class ProductTraceDTO {
     private Long entranceBatchId;
     private String animalCertNo;
+
+    @JsonFormat(pattern = "yyyy-MM-dd")
     private String entranceTime;
     private String cargoOwner;
     private String companyNo;

+ 4 - 0
ruoyi-system/src/main/java/com/ruoyi/app/DTO/SlaughterBatchDTO.java

@@ -1,10 +1,14 @@
 package com.ruoyi.app.DTO;
 
+import com.fasterxml.jackson.annotation.JsonFormat;
+
 import java.math.BigDecimal;
 import java.util.Date;
 
 public class SlaughterBatchDTO {
     private Long id;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date slaughterTime;
     private String salePlace;
     private String meatCert;

+ 61 - 0
ruoyi-system/src/main/java/com/ruoyi/app/DTO/SlaughterRelationDTO.java

@@ -0,0 +1,61 @@
+package com.ruoyi.app.DTO;
+
+import com.ruoyi.common.annotation.Excel;
+
+public class SlaughterRelationDTO {
+    /** 血码编号 */
+    @Excel(name = "血码编号")
+    private String slaughterCode;
+
+    /** 关联供应商 */
+    @Excel(name = "关联供应商")
+    private String supplierName;
+
+    /** 关联肉商 */
+    @Excel(name = "关联肉商")
+    private String purchaserName;
+
+    /** 二维码 */
+    @Excel(name = "二维码",cellType =  Excel.ColumnType.QRCODE)
+    private String qrcode;
+
+    public void setSlaughterCode(String slaughterCode)
+    {
+        this.slaughterCode = slaughterCode;
+    }
+
+    public String getSlaughterCode()
+    {
+        return slaughterCode;
+    }
+
+    public void setSupplierName(String supplierName)
+    {
+        this.supplierName = supplierName;
+    }
+
+    public String getSupplierName()
+    {
+        return supplierName;
+    }
+
+    public void setPurchaserName(String purchaserName)
+    {
+        this.purchaserName = purchaserName;
+    }
+
+    public String getPurchaserName()
+    {
+        return purchaserName;
+    }
+
+    public void setQrcode(String qrcode)
+    {
+        this.qrcode = qrcode;
+    }
+
+    public String getQrcode()
+    {
+        return qrcode;
+    }
+}

+ 4 - 0
ruoyi-system/src/main/java/com/ruoyi/app/DTO/SlaughterReportDTO.java

@@ -1,10 +1,14 @@
 package com.ruoyi.app.DTO;
 
+import com.fasterxml.jackson.annotation.JsonFormat;
+
 import java.math.BigDecimal;
 import java.util.Date;
 
 public class SlaughterReportDTO {
     private Long id;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date slaughterTime;
     private String salePlace;
     private String meatCert;

+ 49 - 0
ruoyi-system/src/main/java/com/ruoyi/app/DTO/ValidSlaughterCodeDTO.java

@@ -0,0 +1,49 @@
+package com.ruoyi.app.DTO;
+
+public class ValidSlaughterCodeDTO {
+    private String purchaserNo;
+    private String supplierNo;
+    private String purchaserName;
+    private String supplierName;
+    private String slaughterCode;
+
+    public String getPurchaserNo() {
+        return purchaserNo;
+    }
+
+    public void setPurchaserNo(String purchaserNo) {
+        this.purchaserNo = purchaserNo;
+    }
+
+    public String getSupplierNo() {
+        return supplierNo;
+    }
+
+    public void setSupplierNo(String supplierNo) {
+        this.supplierNo = supplierNo;
+    }
+
+    public String getPurchaserName() {
+        return purchaserName;
+    }
+
+    public void setPurchaserName(String purchaserName) {
+        this.purchaserName = purchaserName;
+    }
+
+    public String getSupplierName() {
+        return supplierName;
+    }
+
+    public void setSupplierName(String supplierName) {
+        this.supplierName = supplierName;
+    }
+
+    public String getSlaughterCode() {
+        return slaughterCode;
+    }
+
+    public void setSlaughterCode(String slaughterCode) {
+        this.slaughterCode = slaughterCode;
+    }
+}

+ 3 - 0
ruoyi-system/src/main/java/com/ruoyi/app/domain/DeadDisposal.java

@@ -6,6 +6,7 @@ import com.ruoyi.common.annotation.Excel;
 import com.ruoyi.common.core.domain.BaseEntity;
 
 import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
 
 /**
  * 死淘处理方式对象 dead_disposal
@@ -47,6 +48,7 @@ public class DeadDisposal extends BaseEntity
     }
 
     @NotBlank(message = "处理原因不能为空")
+    @Size(min = 1, max = 20, message = "处理原因输入超出最大长度限制(20位)")
     public String getDealReason() 
     {
         return dealReason;
@@ -58,6 +60,7 @@ public class DeadDisposal extends BaseEntity
     }
 
     @NotBlank(message = "处理方式不能为空")
+    @Size(min = 1, max = 50, message = "处理原因输入超出最大长度限制(50位)")
     public String getDealWay() 
     {
         return dealWay;

+ 7 - 7
ruoyi-system/src/main/java/com/ruoyi/app/domain/DistributeBatch.java

@@ -6,8 +6,7 @@ import org.apache.commons.lang3.builder.ToStringStyle;
 import com.ruoyi.common.annotation.Excel;
 import com.ruoyi.common.core.domain.BaseEntity;
 
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.NotNull;
+import javax.validation.constraints.*;
 
 /**
  * 分销批次对象 distribute_batch
@@ -72,7 +71,7 @@ public class DistributeBatch extends BaseEntity
         this.entranceBatchId = entranceBatchId;
     }
 
-    @NotNull(message = "入场批次ID不能为空")
+    @NotNull(message = "不存在入场信息")
     public Long getEntranceBatchId() 
     {
         return entranceBatchId;
@@ -111,13 +110,12 @@ public class DistributeBatch extends BaseEntity
         return purchaserId;
     }
 
-    public void setAmount(Integer amount) 
+    public void setAmount(Integer amount)
     {
         this.amount = amount;
     }
 
-    @NotNull(message = "数量不能为空")
-    public Integer getAmount() 
+    public Integer getAmount()
     {
         return amount;
     }
@@ -127,7 +125,9 @@ public class DistributeBatch extends BaseEntity
         this.weight = weight;
     }
 
-    @NotNull(message = "重量不能为空")
+    @DecimalMin(value = "0.01", inclusive = true, message = "重量输入超出设定范围限制(0.01~99999.99)")
+    @DecimalMax(value = "99999.99", inclusive = true, message = "重量输入超出设定范围限制(0.01~99999.99)")
+    @Digits(integer = 5, fraction = 2, message = "重量输入的整数部分不能超过5位,小数部分不能超过2位")
     public BigDecimal getWeight() 
     {
         return weight;

+ 21 - 21
ruoyi-system/src/main/java/com/ruoyi/app/domain/DryLossRatio.java

@@ -33,12 +33,12 @@ public class DryLossRatio extends BaseEntity
     /** 开始时间 */
     @JsonFormat(pattern = "yyyy-MM-dd")
     @Excel(name = "开始时间", width = 30, dateFormat = "yyyy-MM-dd")
-    private Date startTime;
+    private String startTime;
 
-    /** 结束时间 */
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @Excel(name = "结束时间", width = 30, dateFormat = "yyyy-MM-dd")
-    private Date endTime;
+//    /** 结束时间 */
+//    @JsonFormat(pattern = "yyyy-MM-dd")
+//    @Excel(name = "结束时间", width = 30, dateFormat = "yyyy-MM-dd")
+//    private Date endTime;
 
     /** 删除标志 */
     private String delFlag;
@@ -59,35 +59,35 @@ public class DryLossRatio extends BaseEntity
     }
 
     @NotNull(message = "干损比例不能为空")
-    @DecimalMin(value = "0.00", inclusive = true, message = "干损比例不能小于0.00")
-    @DecimalMax(value = "99.99", inclusive = true, message = "干损比例不能大于99.99")
-    @Digits(integer = 2, fraction = 2, message = "干损比例的整数部分不能超过2位,小数部分不能超过2位")
+    @DecimalMin(value = "0.01", inclusive = true, message = "干损比例输入超出设定范围限制(0.01~99.99)")
+    @DecimalMax(value = "99.99", inclusive = true, message = "干损比例输入超出设定范围限制(0.01~99.99)")
+    @Digits(integer = 2, fraction = 2, message = "干损比例输入的整数部分不能超过2位,小数部分不能超过2位")
     public BigDecimal getDryLossRatio() 
     {
         return dryLossRatio;
     }
 
-    public void setStartTime(Date startTime) 
+    public void setStartTime(String startTime)
     {
         this.startTime = startTime;
     }
 
     @NotNull(message = "开始时间不能为空")
-    public Date getStartTime() 
+    public String getStartTime()
     {
         return startTime;
     }
 
-    public void setEndTime(Date endTime) 
-    {
-        this.endTime = endTime;
-    }
-
-    @NotNull(message = "结束时间不能为空")
-    public Date getEndTime() 
-    {
-        return endTime;
-    }
+//    public void setEndTime(Date endTime)
+//    {
+//        this.endTime = endTime;
+//    }
+//
+//    //目前需求不需要结束时间
+//    public Date getEndTime()
+//    {
+//        return endTime;
+//    }
 
     public void setDelFlag(String delFlag) 
     {
@@ -105,7 +105,7 @@ public class DryLossRatio extends BaseEntity
             .append("id", getId())
             .append("dryLossRatio", getDryLossRatio())
             .append("startTime", getStartTime())
-            .append("endTime", getEndTime())
+           // .append("endTime", getEndTime())
             .append("remark", getRemark())
             .append("createTime", getCreateTime())
             .append("createBy", getCreateBy())

+ 65 - 0
ruoyi-system/src/main/java/com/ruoyi/app/domain/EntranceBatch.java

@@ -8,6 +8,8 @@ import org.apache.commons.lang3.builder.ToStringStyle;
 import com.ruoyi.common.annotation.Excel;
 import com.ruoyi.common.core.domain.BaseEntity;
 
+import javax.validation.constraints.*;
+
 /**
  * 入场批次对象 entrance_batch
  * 
@@ -30,6 +32,10 @@ public class EntranceBatch extends BaseEntity
     @Excel(name = "进场时间", width = 30, dateFormat = "yyyy-MM-dd")
     private Date entranceTime;
 
+    /** 产地:三选一:1-本市、2-市外、3-省外,默认本市 */
+    @Excel(name = "产地:三选一:1-本市、2-市外、3-省外,默认本市")
+    private String originPlace;
+
     /** 动物品种 */
     @Excel(name = "动物品种")
     private String variety;
@@ -102,6 +108,10 @@ public class EntranceBatch extends BaseEntity
     @Excel(name = "牲畜耳标号")
     private String animalEartags;
 
+    /** 备注 */
+    @Excel(name = "备注")
+    private String remark;
+
     /** 删除标志 */
     private String delFlag;
 
@@ -124,6 +134,7 @@ public class EntranceBatch extends BaseEntity
         this.supplierId = supplierId;
     }
 
+    @NotNull(message = "供应商不能为空")
     public Long getSupplierId() 
     {
         return supplierId;
@@ -134,16 +145,29 @@ public class EntranceBatch extends BaseEntity
         this.entranceTime = entranceTime;
     }
 
+    @NotNull(message = "进场时间不能为空")
     public Date getEntranceTime() 
     {
         return entranceTime;
     }
 
+    public void setOriginPlace(String originPlace)
+    {
+        this.originPlace = originPlace;
+    }
+
+    @NotBlank(message = "产地不能为空")
+    public String getOriginPlace()
+    {
+        return originPlace;
+    }
+
     public void setVariety(String variety) 
     {
         this.variety = variety;
     }
 
+    @NotBlank(message = "品种不能为空")
     public String getVariety() 
     {
         return variety;
@@ -154,6 +178,7 @@ public class EntranceBatch extends BaseEntity
         this.transportVehicle = transportVehicle;
     }
 
+    @Size(min = 0, max = 10, message = "运输车牌号输入超出最大长度限制(10位)")
     public String getTransportVehicle() 
     {
         return transportVehicle;
@@ -164,6 +189,9 @@ public class EntranceBatch extends BaseEntity
         this.weight = weight;
     }
 
+    @DecimalMin(value = "0.01", inclusive = true, message = "重量输入超出设定范围限制(0.01~99999.99)")
+    @DecimalMax(value = "99999.99", inclusive = true, message = "重量输入超出设定范围限制(0.01~99999.99)")
+    @Digits(integer = 5, fraction = 2, message = "重量输入的整数部分不能超过5位,小数部分不能超过2位")
     public BigDecimal getWeight() 
     {
         return weight;
@@ -184,6 +212,8 @@ public class EntranceBatch extends BaseEntity
         this.animalCertNo = animalCertNo;
     }
 
+    @NotBlank(message = "检疫证号不能为空")
+    @Pattern(regexp = "^\\d{11}$", message = "检疫证号格式输入错误")
     public String getAnimalCertNo()
     {
         return animalCertNo;
@@ -204,6 +234,8 @@ public class EntranceBatch extends BaseEntity
         this.cargoOwner = cargoOwner;
     }
 
+    @NotBlank(message = "货主不能为空")
+    @Size(min = 1, max = 30, message = "货主输入超出最大长度限制(30位)")
     public String getCargoOwner() 
     {
         return cargoOwner;
@@ -214,6 +246,8 @@ public class EntranceBatch extends BaseEntity
         this.companyNo = companyNo;
     }
 
+    @NotBlank(message = "主体识别号不能为空")
+    @Size(min = 18, max = 18, message = "主体识别号输入超出最大长度限制(18位)")
     public String getCompanyNo() 
     {
         return companyNo;
@@ -224,6 +258,8 @@ public class EntranceBatch extends BaseEntity
         this.cargoOwnerPhone = cargoOwnerPhone;
     }
 
+    @NotBlank(message = "联系方式不能为空")
+    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "联系方式格式输入错误")
     public String getCargoOwnerPhone() 
     {
         return cargoOwnerPhone;
@@ -234,6 +270,8 @@ public class EntranceBatch extends BaseEntity
         this.animalCategory = animalCategory;
     }
 
+    @NotBlank(message = "动物种类不能为空")
+    @Size(min = 1, max = 10, message = "动物种类输入超出最大长度限制(10位)")
     public String getAnimalCategory() 
     {
         return animalCategory;
@@ -244,6 +282,9 @@ public class EntranceBatch extends BaseEntity
         this.amount = amount;
     }
 
+    @NotNull(message = "数量不能为空")
+    @Min(value = 1, message = "数量输入超出设定范围限制(1~999)")
+    @Max(value = 999, message = "数量输入超出设定范围限制(1~999)")
     public Integer getAmount() 
     {
         return amount;
@@ -254,6 +295,7 @@ public class EntranceBatch extends BaseEntity
         this.units = units;
     }
 
+    @NotBlank(message = "单位不能为空")
     public String getUnits() 
     {
         return units;
@@ -264,6 +306,8 @@ public class EntranceBatch extends BaseEntity
         this.useto = useto;
     }
 
+    @NotBlank(message = "用途不能为空")
+    @Size(min = 1, max = 10, message = "用途输入超出最大长度限制(10位)")
     public String getUseto()
     {
         return useto;
@@ -274,6 +318,8 @@ public class EntranceBatch extends BaseEntity
         this.fromPlace = fromPlace;
     }
 
+    @NotBlank(message = "启运地点不能为空")
+    @Size(min = 1, max = 50, message = "启运地点输入超出最大长度限制(50位)")
     public String getFromPlace() 
     {
         return fromPlace;
@@ -284,6 +330,8 @@ public class EntranceBatch extends BaseEntity
         this.toPlace = toPlace;
     }
 
+    @NotBlank(message = "到达地点不能为空")
+    @Size(min = 1, max = 50, message = "到达地点输入超出最大长度限制(50位)")
     public String getToPlace() 
     {
         return toPlace;
@@ -294,6 +342,8 @@ public class EntranceBatch extends BaseEntity
         this.carrier = carrier;
     }
 
+    @NotBlank(message = "承运人不能为空")
+    @Size(min = 1, max = 30, message = "承运人输入超出最大长度限制(30位)")
     public String getCarrier() 
     {
         return carrier;
@@ -304,6 +354,8 @@ public class EntranceBatch extends BaseEntity
         this.carrierPhone = carrierPhone;
     }
 
+    @NotBlank(message = "联系方式不能为空")
+    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "联系方式格式输入错误")
     public String getCarrierPhone() 
     {
         return carrierPhone;
@@ -314,11 +366,24 @@ public class EntranceBatch extends BaseEntity
         this.animalEartags = animalEartags;
     }
 
+    @NotBlank(message = "耳标号不能为空")
+    @Size(min = 15, max = 5000, message = "耳标号格式输入错误")
     public String getAnimalEartags() 
     {
         return animalEartags;
     }
 
+    public void setRemark(String remark)
+    {
+        this.remark = remark;
+    }
+
+    @Size(min = 0, max = 50, message = "备注输入超出最大长度限制(50位)")
+    public String getRemark()
+    {
+        return remark;
+    }
+
     public void setDelFlag(String delFlag) 
     {
         this.delFlag = delFlag;

+ 7 - 0
ruoyi-system/src/main/java/com/ruoyi/app/domain/EntranceInspection.java

@@ -5,6 +5,10 @@ import org.apache.commons.lang3.builder.ToStringStyle;
 import com.ruoyi.common.annotation.Excel;
 import com.ruoyi.common.core.domain.BaseEntity;
 
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
 /**
  * 入场检验对象 entrance_inspection
  * 
@@ -64,6 +68,7 @@ public class EntranceInspection extends BaseEntity
         this.entranceBatchId = entranceBatchId;
     }
 
+    @NotNull(message = "不存在入场信息")
     public Long getEntranceBatchId() 
     {
         return entranceBatchId;
@@ -114,6 +119,7 @@ public class EntranceInspection extends BaseEntity
         this.otherRemark = otherRemark;
     }
 
+    @Size(min = 0, max = 50, message = "其他输入超出最大长度限制(50位)")
     public String getOtherRemark() 
     {
         return otherRemark;
@@ -124,6 +130,7 @@ public class EntranceInspection extends BaseEntity
         this.inspectionDetail = inspectionDetail;
     }
 
+    @NotBlank(message = "生猪检验检疫信息不能为空")
     public String getInspectionDetail() 
     {
         return inspectionDetail;

+ 13 - 0
ruoyi-system/src/main/java/com/ruoyi/app/domain/HarmlessTreatment.java

@@ -6,6 +6,8 @@ import org.apache.commons.lang3.builder.ToStringStyle;
 import com.ruoyi.common.annotation.Excel;
 import com.ruoyi.common.core.domain.BaseEntity;
 
+import javax.validation.constraints.*;
+
 /**
  * 无害化处理对象 harmless_treatment
  * 
@@ -69,6 +71,7 @@ public class HarmlessTreatment extends BaseEntity
         this.entranceBatchId = entranceBatchId;
     }
 
+    @NotNull(message = "不存在入场信息")
     public Long getEntranceBatchId() 
     {
         return entranceBatchId;
@@ -79,6 +82,8 @@ public class HarmlessTreatment extends BaseEntity
         this.illnessDeadAmount = illnessDeadAmount;
     }
 
+    @Min(value = 0, message = "病死头数输入超出设定范围限制(0~999)")
+    @Max(value = 999, message = "病死头数输入超出设定范围限制(0~999)")
     public Integer getIllnessDeadAmount() 
     {
         return illnessDeadAmount;
@@ -89,6 +94,8 @@ public class HarmlessTreatment extends BaseEntity
         this.illnessDiseaseAmount = illnessDiseaseAmount;
     }
 
+    @Min(value = 0, message = "病害头数输入超出设定范围限制(0~999)")
+    @Max(value = 999, message = "病害头数输入超出设定范围限制(0~999)")
     public Integer getIllnessDiseaseAmount() 
     {
         return illnessDiseaseAmount;
@@ -99,6 +106,8 @@ public class HarmlessTreatment extends BaseEntity
         this.snapKillAmount = snapKillAmount;
     }
 
+    @Min(value = 0, message = "急宰头数输入超出设定范围限制(0~999)")
+    @Max(value = 999, message = "急宰头数输入超出设定范围限制(0~999)")
     public Integer getSnapKillAmount() 
     {
         return snapKillAmount;
@@ -109,6 +118,9 @@ public class HarmlessTreatment extends BaseEntity
         this.unqualifiedWeight = unqualifiedWeight;
     }
 
+    @DecimalMin(value = "0", inclusive = true, message = "不合格产品重量输入超出设定范围限制(0~99999.99)")
+    @DecimalMax(value = "99999.99", inclusive = true, message = "不合格产品重量输入超出设定范围限制(0.01~99999.99)")
+    @Digits(integer = 5, fraction = 2, message = "不合格产品重量输入的整数部分不能超过5位,小数部分不能超过2位")
     public BigDecimal getUnqualifiedWeight() 
     {
         return unqualifiedWeight;
@@ -119,6 +131,7 @@ public class HarmlessTreatment extends BaseEntity
         this.illnessPigsDetail = illnessPigsDetail;
     }
 
+    @Size(min = 0, max = 3000, message = "无害化处理生猪详情输入超出最大长度限制(3000位)")
     public String getIllnessPigsDetail() 
     {
         return illnessPigsDetail;

+ 4 - 3
ruoyi-system/src/main/java/com/ruoyi/app/domain/Hook.java

@@ -48,6 +48,7 @@ public class Hook extends BaseEntity
     }
 
     @NotBlank(message = "吊钩类型不能为空")
+    @Size(min = 1, max = 10, message = "吊钩类型输入超出最大长度限制(10位)")
     public String getHookName() 
     {
         return hookName;
@@ -59,9 +60,9 @@ public class Hook extends BaseEntity
     }
 
     @NotNull(message = "吊钩扣重不能为空")
-    @DecimalMin(value = "0.00", inclusive = true, message = "吊钩扣重不能小于0.00")
-    @DecimalMax(value = "999.99", inclusive = true, message = "吊钩扣重不能大于999.99")
-    @Digits(integer = 3, fraction = 2, message = "吊钩扣重的整数部分不能超过3位,小数部分不能超过2位")
+    @DecimalMin(value = "0.01", inclusive = true, message = "吊钩扣重输入超出设定范围限制(0.01~50.00)")
+    @DecimalMax(value = "50.00", inclusive = true, message = "吊钩扣重输入超出设定范围限制(0.01~50.00)")
+    @Digits(integer = 2, fraction = 2, message = "吊钩扣重输入的整数部分不能超过2位,小数部分不能超过2位")
     public BigDecimal getHookWeight() 
     {
         return hookWeight;

+ 22 - 0
ruoyi-system/src/main/java/com/ruoyi/app/domain/HookBind.java

@@ -1,5 +1,6 @@
 package com.ruoyi.app.domain;
 
+import com.fasterxml.jackson.annotation.JsonFormat;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
 import com.ruoyi.common.annotation.Excel;
@@ -18,6 +19,11 @@ public class HookBind extends BaseEntity
 {
     private static final long serialVersionUID = 1L;
 
+    //‘0’-未绑定,‘1’-已绑定
+    public static final String IS_BIND = "1";
+
+    public static final String NOT_BIND = "0";
+
     /** ID */
     private Long id;
 
@@ -25,6 +31,10 @@ public class HookBind extends BaseEntity
     @Excel(name = "批次号")
     private String batchNo;
 
+    /** 识别器序列号 */
+    @Excel(name = "识别器序列号")
+    private String deviceSerial;
+
     /** 挂钩号 */
     @Excel(name = "吊钩号")
     private String hookNo;
@@ -42,6 +52,7 @@ public class HookBind extends BaseEntity
     private String isBind;
 
     /** 绑定时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     @Excel(name = "绑定时间")
     private Date bindTime;
 
@@ -58,6 +69,16 @@ public class HookBind extends BaseEntity
         return id;
     }
 
+    public void setDeviceSerial(String deviceSerial)
+    {
+        this.deviceSerial = deviceSerial;
+    }
+
+    public String getDeviceSerial()
+    {
+        return deviceSerial;
+    }
+
     public void setHookNo(String hookNo)
     {
         this.hookNo = hookNo;
@@ -135,6 +156,7 @@ public class HookBind extends BaseEntity
         return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
             .append("id", getId())
             .append("batchNo", getBatchNo())
+            .append("deviceSerial", getDeviceSerial())
             .append("hookNo", getHookNo())
             .append("batchNo", getBatchNo())
             .append("distributeBatchId", getDistributeBatchId())

+ 93 - 0
ruoyi-system/src/main/java/com/ruoyi/app/domain/HookRegister.java

@@ -0,0 +1,93 @@
+package com.ruoyi.app.domain;
+
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Size;
+
+/**
+ * 吊钩注册对象 HookRegister
+ *
+ * @author coede
+ * @date 2025-04-18
+ */
+public class HookRegister extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** ID */
+    private Long id;
+
+    /** 吊钩编号 */
+    @Excel(name = "吊钩编号")
+    private String hookNo;
+
+    /** 吊钩编号 */
+    @Excel(name = "芯片编号")
+    private String epcNo;
+
+    /** 删除标志 */
+    private String delFlag;
+
+    public void setId(Long id)
+    {
+        this.id = id;
+    }
+
+    public Long getId()
+    {
+        return id;
+    }
+
+    public void setHookNo(String hookNo)
+    {
+        this.hookNo = hookNo;
+    }
+
+    @NotBlank(message = "吊钩编号不能为空")
+    @Pattern(regexp = "^\\d{1,4}$", message = "吊钩编号超出最大长度限制(4位数字)")
+    public String getHookNo()
+    {
+        return hookNo;
+    }
+
+    public void setEpcNo(String epcNo)
+    {
+        this.epcNo = epcNo;
+    }
+
+    @NotBlank(message = "芯片编号不能为空")
+    @Pattern(regexp = "^[a-zA-Z0-9]{24}$", message = "芯片编号输入限制24位数字或字母")
+    public String getEpcNo()
+    {
+        return epcNo;
+    }
+
+    public void setDelFlag(String delFlag)
+    {
+        this.delFlag = delFlag;
+    }
+
+    public String getDelFlag()
+    {
+        return delFlag;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("id", getId())
+                .append("hookNo", getHookNo())
+                .append("epcNo", getEpcNo())
+                .append("createTime", getCreateTime())
+                .append("createBy", getCreateBy())
+                .append("updateTime", getUpdateTime())
+                .append("updateBy", getUpdateBy())
+                .append("delFlag", getDelFlag())
+                .toString();
+    }
+}

+ 3 - 0
ruoyi-system/src/main/java/com/ruoyi/app/domain/InspectionItem.java

@@ -6,6 +6,7 @@ import com.ruoyi.common.annotation.Excel;
 import com.ruoyi.common.core.domain.BaseEntity;
 
 import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
 import java.util.List;
 import java.util.Map;
 
@@ -49,6 +50,7 @@ public class InspectionItem extends BaseEntity
     }
 
     @NotBlank(message = "项目名称不能为空")
+    @Size(min = 1, max = 10, message = "项目名称输入超出最大长度限制(10位)")
     public String getItemName() 
     {
         return itemName;
@@ -60,6 +62,7 @@ public class InspectionItem extends BaseEntity
     }
 
     @NotBlank(message = "检查结果不能为空")
+    @Size(min = 1, max = 1000, message = "全部检查结果输入超出最大长度限制(1000位)")
     public String getResult()
     {
         return result;

+ 12 - 0
ruoyi-system/src/main/java/com/ruoyi/app/domain/Monitor.java

@@ -5,6 +5,11 @@ import org.apache.commons.lang3.builder.ToStringStyle;
 import com.ruoyi.common.annotation.Excel;
 import com.ruoyi.common.core.domain.BaseEntity;
 
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Size;
+
 /**
  * 监控设备对象 monitor
  * 
@@ -54,6 +59,8 @@ public class Monitor extends BaseEntity
         this.monitorName = monitorName;
     }
 
+    @NotBlank(message = "监控名称不能为空")
+    @Size(min = 1, max = 10, message = "监控名称输入超出最大长度限制(10位)")
     public String getMonitorName() 
     {
         return monitorName;
@@ -64,6 +71,7 @@ public class Monitor extends BaseEntity
         this.regionId = regionId;
     }
 
+    @NotNull(message = "区域名称不能为空")
     public Long getRegionId()
     {
         return regionId;
@@ -74,6 +82,7 @@ public class Monitor extends BaseEntity
         this.monitorBrand = monitorBrand;
     }
 
+    @Size(min = 0, max = 10, message = "设备品牌输入超出最大长度限制(10位)")
     public String getMonitorBrand() 
     {
         return monitorBrand;
@@ -84,6 +93,9 @@ public class Monitor extends BaseEntity
         this.ipAddr = ipAddr;
     }
 
+    @NotBlank(message = "IP不能为空")
+    @Pattern(regexp = "^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$",
+            message = "IPv4地址格式输入错误")
     public String getIpAddr() 
     {
         return ipAddr;

+ 116 - 0
ruoyi-system/src/main/java/com/ruoyi/app/domain/NFIDReader.java

@@ -0,0 +1,116 @@
+package com.ruoyi.app.domain;
+
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+import java.util.Date;
+
+public class NFIDReader {
+
+    //‘0’-离线,‘1’-在线,‘2’-异常
+    public static final String STATUS_INLINE = "1";
+
+    public static final String STATUS_OFFLINE = "0";
+
+    public static final String STATUS_ERROR = "2";
+
+    //‘bind’-吊钩绑定,‘weight’-白条称重
+    public static final String BIND_SPOT = "bind";
+
+    public static final String WEIGHT_SPOT = "weight";
+
+
+    /**
+     * ID
+     */
+    private Long id;
+    /**
+     * 设备序列号
+     */
+    @Excel(name = "设备序列号")
+    private String deviceSerial;
+
+    /**
+     * 设备名称
+     */
+    @Excel(name = "设备名称")
+    private String deviceName;
+
+    /**
+     * 设备点位:‘a’-吊钩绑定,‘b’-白条称重
+     */
+    @Excel(name = "设备点位:‘bind’-吊钩绑定,‘weight’-白条称重")
+    private String deviceSpot;
+
+    /**
+     * 最近活跃时间
+     */
+    @Excel(name = "最近活跃时间")
+    private Date lastActiveTime;
+
+    /**
+     * 状态
+     */
+    @Excel(name = "状态")
+    private String status;
+
+    public Long getId()
+    {
+        return id;
+    }
+
+    public void setId(Long id)
+    {
+        this.id = id;
+    }
+
+    public String getDeviceSerial()
+    {
+        return deviceSerial;
+    }
+
+    public void setDeviceSerial(String deviceSerial)
+    {
+        this.deviceSerial = deviceSerial;
+    }
+
+    public String getDeviceName()
+    {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName)
+    {
+        this.deviceName = deviceName;
+    }
+
+    public String getDeviceSpot()
+    {
+        return deviceSpot;
+    }
+
+    public void setDeviceSpot(String deviceSpot)
+    {
+        this.deviceSpot = deviceSpot;
+    }
+
+    public Date getLastActiveTime()
+    {
+        return lastActiveTime;
+    }
+
+    public void setLastActiveTime(Date lastActiveTime)
+    {
+        this.lastActiveTime = lastActiveTime;
+    }
+
+    public String getStatus()
+    {
+        return status;
+    }
+
+    public void setStatus(String status)
+    {
+        this.status = status;
+    }
+}

+ 4 - 2
ruoyi-system/src/main/java/com/ruoyi/app/domain/PigCategory.java

@@ -6,6 +6,7 @@ import com.ruoyi.common.annotation.Excel;
 import com.ruoyi.common.core.domain.BaseEntity;
 
 import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
 
 /**
  * 生猪分类对象 pig_category
@@ -21,7 +22,7 @@ public class PigCategory extends BaseEntity
     private Long id;
 
     /** 分类名称 */
-    @Excel(name = "分类名称")
+    @Excel(name = "品种名称")
     private String categoryName;
 
     /** 删除标志 */
@@ -42,7 +43,8 @@ public class PigCategory extends BaseEntity
         this.categoryName = categoryName;
     }
 
-    @NotBlank(message = "分类名称不能为空")
+    @NotBlank(message = "品种名称不能为空")
+    @Size(min = 1, max = 10, message = "品种名称输入超出最大长度限制(10位)")
     public String getCategoryName() 
     {
         return categoryName;

+ 5 - 1
ruoyi-system/src/main/java/com/ruoyi/app/domain/Pigpen.java

@@ -5,7 +5,7 @@ import org.apache.commons.lang3.builder.ToStringStyle;
 import com.ruoyi.common.annotation.Excel;
 import com.ruoyi.common.core.domain.BaseEntity;
 
-import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.*;
 
 /**
  * 待宰圈对象 pigpen
@@ -48,6 +48,8 @@ public class Pigpen extends BaseEntity
     }
 
     @NotBlank(message = "待宰圈号不能为空")
+    @Size(min = 1, max = 3, message = "待宰圈号输入超出最大长度限制(3位)")
+    @Pattern(regexp = "^\\d+$", message = "待宰圈号必须全部是数字")
     public String getPigpenName() 
     {
         return pigpenName;
@@ -58,6 +60,8 @@ public class Pigpen extends BaseEntity
         this.maxCapacity = maxCapacity;
     }
 
+    @Min(value = 1, message = "最大容量输入超出设定范围限制(1~999)")
+    @Max(value = 999, message = "最大容量输入超出设定范围限制(1~999)")
     public Integer getMaxCapacity() 
     {
         return maxCapacity;

+ 13 - 2
ruoyi-system/src/main/java/com/ruoyi/app/domain/PorkOtherProduce.java

@@ -8,6 +8,8 @@ import org.apache.commons.lang3.builder.ToStringStyle;
 import com.ruoyi.common.annotation.Excel;
 import com.ruoyi.common.core.domain.BaseEntity;
 
+import javax.validation.constraints.*;
+
 /**
  * 猪头生产记录对象 pork_head_produce
  * 
@@ -26,8 +28,8 @@ public class PorkOtherProduce extends BaseEntity
     private String productName;
 
     /** 生产时间 */
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @Excel(name = "生产时间", width = 30, dateFormat = "yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "生产时间", width = 30)
     private Date produceTime;
 
     /** 血码 */
@@ -68,6 +70,7 @@ public class PorkOtherProduce extends BaseEntity
         this.productName = productName;
     }
 
+    @NotBlank(message = "产品名称不能为空")
     public String getProductName() 
     {
         return productName;
@@ -78,6 +81,7 @@ public class PorkOtherProduce extends BaseEntity
         this.produceTime = produceTime;
     }
 
+    @NotNull(message = "屠宰时间不能为空")
     public Date getProduceTime() 
     {
         return produceTime;
@@ -88,6 +92,7 @@ public class PorkOtherProduce extends BaseEntity
         this.slaughterCode = slaughterCode;
     }
 
+    @NotBlank(message = "血码不能为空")
     public String getSlaughterCode() 
     {
         return slaughterCode;
@@ -98,6 +103,7 @@ public class PorkOtherProduce extends BaseEntity
         this.distributeBatchId = distributeBatchId;
     }
 
+    @NotNull(message = "检疫证号不能为空")  //这里i提示检疫证号,实际是分销批次
     public Long getDistributeBatchId() 
     {
         return distributeBatchId;
@@ -108,6 +114,7 @@ public class PorkOtherProduce extends BaseEntity
         this.entranceBatchId = entranceBatchId;
     }
 
+    @NotNull(message = "检疫证号不能为空")  //这里i提示检疫证号,实际是入场批次
     public Long getEntranceBatchId() 
     {
         return entranceBatchId;
@@ -128,6 +135,10 @@ public class PorkOtherProduce extends BaseEntity
         this.finalWeight = finalWeight;
     }
 
+    @NotNull(message = "重量不能为空")
+    @DecimalMin(value = "0.01", inclusive = true, message = "重量输入超出设定范围限制(0.01~99999.99)")
+    @DecimalMax(value = "99999.99", inclusive = true, message = "重量输入超出设定范围限制(0.01~99999.99)")
+    @Digits(integer = 5, fraction = 2, message = "重量输入的整数部分不能超过5位,小数部分不能超过2位")
     public BigDecimal getFinalWeight() 
     {
         return finalWeight;

+ 2 - 2
ruoyi-system/src/main/java/com/ruoyi/app/domain/PorkRedoffalProduce.java

@@ -26,8 +26,8 @@ public class PorkRedoffalProduce extends BaseEntity
     private String productName;
 
     /** 生产时间 */
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @Excel(name = "生产时间", width = 30, dateFormat = "yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "生产时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
     private Date produceTime;
 
     /** 血码 */

+ 18 - 2
ruoyi-system/src/main/java/com/ruoyi/app/domain/PorkSideProduce.java

@@ -18,6 +18,8 @@ public class PorkSideProduce extends BaseEntity
 {
     private static final long serialVersionUID = 1L;
 
+    public static final String DEFAULT_NAME = "白条";
+
     /** ID */
     private Long id;
 
@@ -26,10 +28,14 @@ public class PorkSideProduce extends BaseEntity
     private String productName;
 
     /** 生产时间 */
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @Excel(name = "生产时间", width = 30, dateFormat = "yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "生产时间", width = 30)
     private Date produceTime;
 
+    /** 识别器序列号 */
+    @Excel(name = "识别器序列号")
+    private String deviceSerial;
+
     /** 吊钩号 */
     @Excel(name = "吊钩号")
     private String hookNo;
@@ -99,6 +105,16 @@ public class PorkSideProduce extends BaseEntity
         return produceTime;
     }
 
+    public void setDeviceSerial(String deviceSerial)
+    {
+        this.deviceSerial = deviceSerial;
+    }
+
+    public String getDeviceSerial()
+    {
+        return deviceSerial;
+    }
+
     public void setHookNo(String hookNo) 
     {
         this.hookNo = hookNo;

+ 2 - 2
ruoyi-system/src/main/java/com/ruoyi/app/domain/PorkWhiteoffalProduce.java

@@ -26,8 +26,8 @@ public class PorkWhiteoffalProduce extends BaseEntity
     private String productName;
 
     /** 生产时间 */
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @Excel(name = "生产时间", width = 30, dateFormat = "yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "生产时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
     private Date produceTime;
 
     /** 血码 */

+ 2 - 0
ruoyi-system/src/main/java/com/ruoyi/app/domain/ProductCategory.java

@@ -6,6 +6,7 @@ import com.ruoyi.common.annotation.Excel;
 import com.ruoyi.common.core.domain.BaseEntity;
 
 import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
 
 /**
  * 产品分类对象 product_category
@@ -43,6 +44,7 @@ public class ProductCategory extends BaseEntity
     }
 
     @NotBlank(message = "产品名称不能为空")
+    @Size(min = 1, max = 10, message = "产品名称输入超出最大长度限制(10位)")
     public String getProductName() 
     {
         return productName;

+ 26 - 2
ruoyi-system/src/main/java/com/ruoyi/app/domain/Purchaser.java

@@ -4,8 +4,10 @@ import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
 import com.ruoyi.common.annotation.Excel;
 import com.ruoyi.common.core.domain.BaseEntity;
+import org.hibernate.validator.constraints.Length;
 
 import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Pattern;
 import javax.validation.constraints.Size;
 
 /**
@@ -21,6 +23,10 @@ public class Purchaser extends BaseEntity
     /** ID */
     private Long id;
 
+    /** 肉商编号 */
+    @Excel(name = "肉商编号")
+    private String purchaserNo;
+
     /** 肉商名称 */
     @Excel(name = "肉商名称")
     private String purchaserName;
@@ -58,12 +64,25 @@ public class Purchaser extends BaseEntity
         return id;
     }
 
+    public void setPurchaserNo(String purchaserNo)
+    {
+        this.purchaserNo = purchaserNo;
+    }
+
+    @NotBlank(message = "肉商编号不能为空")
+    @Size(min = 1, max = 3, message = "肉商编号输入超出最大长度限制(30位)")
+    public String getPurchaserNo()
+    {
+        return purchaserNo;
+    }
+
     public void setPurchaserName(String purchaserName) 
     {
         this.purchaserName = purchaserName;
     }
 
     @NotBlank(message = "肉商名称不能为空")
+    @Size(min = 1, max = 30, message = "肉商名称输入超出最大长度限制(30位)")
     public String getPurchaserName() 
     {
         return purchaserName;
@@ -74,6 +93,9 @@ public class Purchaser extends BaseEntity
         this.idNumber = idNumber;
     }
 
+    @Length(min = 0, max = 18, message = "身份证号格式输入错误")
+    @Pattern(regexp = "(^$|^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[0-9Xx]$)",
+            message = "身份证号格式输入错误")
     public String getIdNumber() 
     {
         return idNumber;
@@ -85,7 +107,7 @@ public class Purchaser extends BaseEntity
     }
 
     @NotBlank(message = "联系电话不能为空")
-    @Size(min = 0, max = 11, message = "联系电话长度不能超过11个字符")
+    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "联系电话格式输入错误")
     public String getPhone() 
     {
         return phone;
@@ -96,6 +118,7 @@ public class Purchaser extends BaseEntity
         this.businessPlace = businessPlace;
     }
 
+    @Size(min = 0, max = 50, message = "经营场所输入超出最大长度限制(50位)")
     public String getBusinessPlace() 
     {
         return businessPlace;
@@ -117,7 +140,7 @@ public class Purchaser extends BaseEntity
         this.region = region;
     }
 
-    @NotBlank(message = "所在市县不能为空")
+    @NotBlank(message = "所在市县不能为空")
     public String getRegion() 
     {
         return region;
@@ -137,6 +160,7 @@ public class Purchaser extends BaseEntity
     public String toString() {
         return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
             .append("id", getId())
+            .append("purchaserNo", getPurchaserNo())
             .append("purchaserName", getPurchaserName())
             .append("idNumber", getIdNumber())
             .append("phone", getPhone())

+ 5 - 0
ruoyi-system/src/main/java/com/ruoyi/app/domain/Region.java

@@ -5,6 +5,9 @@ import org.apache.commons.lang3.builder.ToStringStyle;
 import com.ruoyi.common.annotation.Excel;
 import com.ruoyi.common.core.domain.BaseEntity;
 
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+
 /**
  * 区域对象 region
  * 
@@ -40,6 +43,8 @@ public class Region extends BaseEntity
         this.regionName = regionName;
     }
 
+    @NotBlank(message = "区域名称不能为空")
+    @Size(min = 1, max = 10, message = "区域名称输入超出最大长度限制(10位)")
     public String getRegionName() 
     {
         return regionName;

+ 9 - 2
ruoyi-system/src/main/java/com/ruoyi/app/domain/SlaughterBatch.java

@@ -7,6 +7,9 @@ import org.apache.commons.lang3.builder.ToStringStyle;
 import com.ruoyi.common.annotation.Excel;
 import com.ruoyi.common.core.domain.BaseEntity;
 
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+
 /**
  * 屠宰批次对象 slaughter_batch
  * 
@@ -21,8 +24,8 @@ public class SlaughterBatch extends BaseEntity
     private Long id;
 
     /** 屠宰日期 */
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @Excel(name = "屠宰日期", width = 30, dateFormat = "yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "屠宰日期", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
     private Date slaughterTime;
 
     /** 分销批次ID */
@@ -103,6 +106,8 @@ public class SlaughterBatch extends BaseEntity
         this.meatCert = meatCert;
     }
 
+    @NotBlank(message = "肉品品质检验合格证号不能为空")
+    @Size(min = 9, max = 9, message = "肉品品质检验合格证号格式输入错误(9位数字)")
     public String getMeatCert() 
     {
         return meatCert;
@@ -113,6 +118,8 @@ public class SlaughterBatch extends BaseEntity
         this.animalCert = animalCert;
     }
 
+    @NotBlank(message = "动物检疫合格证号不能为空")
+    @Size(min = 10, max = 10, message = "动物检疫合格证号格式输入错误(10位数字)")
     public String getAnimalCert() 
     {
         return animalCert;

+ 4 - 3
ruoyi-system/src/main/java/com/ruoyi/app/domain/SlaughterRelation.java

@@ -8,6 +8,7 @@ import com.ruoyi.common.core.domain.BaseEntity;
 
 import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
 import javax.validation.constraints.Size;
 
 /**
@@ -59,7 +60,7 @@ public class SlaughterRelation extends BaseEntity
     }
 
     @NotBlank(message = "血码编号不能为空")
-    @Size(min = 3, max = 10, message = "血码编号长度必须在3到10之间")
+    @Pattern(regexp = "^[A-Za-z]{1}\\d{3}$",message = "血码编号格式输入错误")
     public String getSlaughterCode() 
     {
         return slaughterCode;
@@ -70,7 +71,7 @@ public class SlaughterRelation extends BaseEntity
         this.supplierId = supplierId;
     }
 
-    @NotNull(message = "供应商ID不能为空")
+    @NotNull(message = "关联供应商不能为空")
     public Long getSupplierId() 
     {
         return supplierId;
@@ -81,7 +82,7 @@ public class SlaughterRelation extends BaseEntity
         this.purchaserId = purchaserId;
     }
 
-    @NotNull(message = "肉商ID不能为空")
+    @NotNull(message = "关联肉商不能为空")
     public Long getPurchaserId() 
     {
         return purchaserId;

+ 25 - 12
ruoyi-system/src/main/java/com/ruoyi/app/domain/Staff.java

@@ -7,10 +7,8 @@ import org.apache.commons.lang3.builder.ToStringStyle;
 import com.ruoyi.common.annotation.Excel;
 import com.ruoyi.common.core.domain.BaseEntity;
 
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.NotEmpty;
-import javax.validation.constraints.NotNull;
-import javax.validation.constraints.Size;
+import javax.validation.constraints.*;
+import java.util.List;
 
 /**
  * 人员对象 staff
@@ -33,6 +31,8 @@ public class Staff extends BaseEntity
     @Excel(name = "岗位ID")
     private Long postId;
 
+    private Long[] postIds;
+
     /** 手机号码 */
     @Excel(name = "手机号码")
     private String phone;
@@ -49,7 +49,7 @@ public class Staff extends BaseEntity
     @Excel(name = "健康证明")
     private String healthCert;
 
-    private SysPost post;
+    private List<SysPost> posts;
 
     /** 删除标志 */
     private String delFlag;
@@ -70,6 +70,7 @@ public class Staff extends BaseEntity
     }
 
     @NotBlank(message = "姓名不能为空")
+    @Size(min = 1, max = 10, message = "姓名输入超出最大长度限制(10位)")
     public String getRealname() 
     {
         return realname;
@@ -80,19 +81,29 @@ public class Staff extends BaseEntity
         this.postId = postId;
     }
 
-    @NotNull(message = "岗位不能为空")
     public Long getPostId() 
     {
         return postId;
     }
 
+    public void setPostIds(Long[] postIds)
+    {
+        this.postIds = postIds;
+    }
+
+    @NotNull(message = "岗位不能为空")
+    public Long[] getPostIds()
+    {
+        return postIds;
+    }
+
     public void setPhone(String phone) 
     {
         this.phone = phone;
     }
 
-    @NotBlank(message = "联系方式不能为空")
-    @Size(min = 0, max = 11, message = "联系方式长度不能超过11个字符")
+    @NotBlank(message = "联系电话不能为空")
+    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "联系电话格式输入错误")
     public String getPhone() 
     {
         return phone;
@@ -103,6 +114,7 @@ public class Staff extends BaseEntity
         this.technicalTitle = technicalTitle;
     }
 
+    @Size(min = 0, max = 10, message = "技术职称输入超出最大长度限制(10位)")
     public String getTechnicalTitle() 
     {
         return technicalTitle;
@@ -139,14 +151,14 @@ public class Staff extends BaseEntity
     }
 
 
-    public SysPost getPost()
+    public List<SysPost> getPosts()
     {
-        return post;
+        return posts;
     }
 
-    public void setPost(SysPost post)
+    public void setPosts(List<SysPost> posts)
     {
-        this.post = post;
+        this.posts = posts;
     }
 
     @Override
@@ -164,6 +176,7 @@ public class Staff extends BaseEntity
             .append("updateTime", getUpdateTime())
             .append("updateBy", getUpdateBy())
             .append("delFlag", getDelFlag())
+            .append("posts", getPosts())
             .toString();
     }
 }

+ 46 - 0
ruoyi-system/src/main/java/com/ruoyi/app/domain/StaffPost.java

@@ -0,0 +1,46 @@
+package com.ruoyi.app.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * 人员和岗位关联
+ * 
+ * @author ruoyi
+ */
+public class StaffPost
+{
+    /** 人员ID */
+    private Long staffId;
+    
+    /** 岗位ID */
+    private Long postId;
+
+    public Long getStaffId()
+    {
+        return staffId;
+    }
+
+    public void setStaffId(Long userId)
+    {
+        this.staffId = userId;
+    }
+
+    public Long getPostId()
+    {
+        return postId;
+    }
+
+    public void setPostId(Long postId)
+    {
+        this.postId = postId;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("staffId", getStaffId())
+            .append("postId", getPostId())
+            .toString();
+    }
+}

+ 23 - 3
ruoyi-system/src/main/java/com/ruoyi/app/domain/Supplier.java

@@ -7,6 +7,7 @@ import com.ruoyi.common.core.domain.BaseEntity;
 
 import javax.validation.constraints.Email;
 import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Pattern;
 import javax.validation.constraints.Size;
 
 /**
@@ -22,6 +23,10 @@ public class Supplier extends BaseEntity
     /** ID */
     private Long id;
 
+    /** 供应商编号 */
+    @Excel(name = "供应商编号")
+    private String supplierNo;
+
     /** 供应商名称 */
     @Excel(name = "供应商名称")
     private String supplierName;
@@ -67,12 +72,25 @@ public class Supplier extends BaseEntity
         return id;
     }
 
+    public void setSupplierNo(String supplierNo)
+    {
+        this.supplierNo = supplierNo;
+    }
+
+    @NotBlank(message = "供应商编号不能为空")
+    @Size(min = 1, max = 3, message = "供应商名称输入超出最大长度限制(3位)")
+    public String getSupplierNo()
+    {
+        return supplierNo;
+    }
+
     public void setSupplierName(String supplierName) 
     {
         this.supplierName = supplierName;
     }
 
     @NotBlank(message = "供应商名称不能为空")
+    @Size(min = 1, max = 30, message = "供应商名称输入超出最大长度限制(30位)")
     public String getSupplierName() 
     {
         return supplierName;
@@ -84,7 +102,7 @@ public class Supplier extends BaseEntity
     }
 
     @NotBlank(message = "联系电话不能为空")
-    @Size(min = 0, max = 11, message = "联系电话长度不能超过11个字符")
+    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "联系电话格式输入错误")
     public String getphone() 
     {
         return phone;
@@ -106,6 +124,7 @@ public class Supplier extends BaseEntity
         this.businessPlace = businessPlace;
     }
 
+    @Size(min = 0, max = 50, message = "经营地点输入超出最大长度限制(50位)")
     public String getBusinessPlace() 
     {
         return businessPlace;
@@ -116,7 +135,6 @@ public class Supplier extends BaseEntity
         this.originPlace = originPlace;
     }
 
-    @NotBlank(message = "产地不能为空")
     public String getOriginPlace() 
     {
         return originPlace;
@@ -136,7 +154,7 @@ public class Supplier extends BaseEntity
     {
         this.evaluate = evaluate;
     }
-
+    @NotBlank(message = "评价不能为空")
     public String getEvaluate() 
     {
         return evaluate;
@@ -147,6 +165,7 @@ public class Supplier extends BaseEntity
         this.inBlacklist = inBlacklist;
     }
 
+    @NotBlank(message = "黑名单状态不能为空")
     public String getInBlacklist() 
     {
         return inBlacklist;
@@ -166,6 +185,7 @@ public class Supplier extends BaseEntity
     public String toString() {
         return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
             .append("id", getId())
+            .append("supplierNo", getSupplierNo())
             .append("supplierName", getSupplierName())
             .append("phone", getphone())
             .append("supplySpecies", getSupplySpecies())

+ 0 - 0
ruoyi-system/src/main/java/com/ruoyi/app/domain/request/AddHookBindBatch.java


部分文件因为文件数量过多而无法显示