4 コミット ef2fbf5d37 ... 837f5d03f0

作者 SHA1 メッセージ 日付
  wwh 837f5d03f0 暂存 1 ヶ月 前
  wwh 8af95a92af Merge remote-tracking branch 'origin/master' 1 ヶ月 前
  wwh 42f69fc5cf 暂存 1 ヶ月 前
  unknown 7948fd1265 2025-05-22 1 ヶ月 前
100 ファイル変更6142 行追加0 行削除
  1. 150 0
      app-admin/pom.xml
  2. 28 0
      app-admin/src/main/java/com/ruoyi/RuoYiApplication.java
  3. 0 0
      app-admin/src/main/java/com/ruoyi/RuoYiServletInitializer.java
  4. 81 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/DataReportController.java
  5. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/DataStatisticsController.java
  6. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/DeadDisposalController.java
  7. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/DistributeBatchController.java
  8. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/DryLossRatioController.java
  9. 131 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/EntranceBatchController.java
  10. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/EntranceInspectionController.java
  11. 138 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/HarmlessTreatmentController.java
  12. 226 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/HookBindController.java
  13. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/HookController.java
  14. 128 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/HookRegisterController.java
  15. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/InspectionItemController.java
  16. 212 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/MonitorController.java
  17. 184 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/NFIDReadRecordController.java
  18. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/NFIDReaderController.java
  19. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/PigCategoryController.java
  20. 137 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/PigpenController.java
  21. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/PorkOtherProduceController.java
  22. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/PorkSideProduceController.java
  23. 101 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/PorkSideProduceRecordController.java
  24. 133 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/ProductCategoryController.java
  25. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/ProductTraceController.java
  26. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/PurchaserController.java
  27. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/RegionController.java
  28. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/SlaughterBatchController.java
  29. 226 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/SlaughterRelationController.java
  30. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/StaffController.java
  31. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/app/SupplierController.java
  32. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java
  33. 218 0
      app-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
  34. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java
  35. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/monitor/ServerController.java
  36. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java
  37. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java
  38. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java
  39. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java
  40. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java
  41. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java
  42. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java
  43. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java
  44. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
  45. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java
  46. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java
  47. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java
  48. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java
  49. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java
  50. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
  51. 0 0
      app-admin/src/main/java/com/ruoyi/web/controller/tool/TestController.java
  52. 0 0
      app-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java
  53. 158 0
      app-admin/src/main/java/com/ruoyi/web/core/nfid/ClientHandler.java
  54. 0 0
      app-admin/src/main/java/com/ruoyi/web/core/nfid/DeviceSessionManager.java
  55. 348 0
      app-admin/src/main/java/com/ruoyi/web/core/nfid/MultiReaderNFIDProcessor.java
  56. 322 0
      app-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDFrameParser.java
  57. 0 0
      app-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDRedisData.java
  58. 0 0
      app-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDServer.java
  59. 0 0
      app-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDTestClient.java
  60. 0 0
      app-admin/src/main/java/com/ruoyi/web/core/nfid/NFIDTestClient1.java
  61. 37 0
      app-admin/src/main/java/com/ruoyi/web/core/wvp/ApiResponseParser.java
  62. 107 0
      app-admin/src/main/java/com/ruoyi/web/core/wvp/DeviceHandler.java
  63. 70 0
      app-admin/src/main/java/com/ruoyi/web/core/wvp/JsonParser.java
  64. 127 0
      app-admin/src/main/java/com/ruoyi/web/core/wvp/SessionHandler.java
  65. 38 0
      app-admin/src/main/java/com/ruoyi/web/core/wvp/domain/ApiResponse.java
  66. 612 0
      app-admin/src/main/java/com/ruoyi/web/core/wvp/domain/DeviceChannelExtend.java
  67. 15 0
      app-admin/src/main/java/com/ruoyi/web/core/wvp/domain/DeviceChannelList.java
  68. 170 0
      app-admin/src/main/java/com/ruoyi/web/core/wvp/domain/Login.java
  69. 72 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsCheckDeviceController.java
  70. 71 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsCheckInstrumentController.java
  71. 71 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsCheckProjectController.java
  72. 76 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsDeviceMaintenanceController.java
  73. 72 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsDisinfectController.java
  74. 71 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsDisinfectManageController.java
  75. 77 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsDistributionController.java
  76. 74 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsDivideCircleController.java
  77. 75 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsDrugCheckController.java
  78. 92 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsDrugController.java
  79. 76 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsInStockController.java
  80. 76 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsInstrumentMaintenanceController.java
  81. 73 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsMaterialController.java
  82. 74 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsOtherProduceController.java
  83. 76 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsOutStockController.java
  84. 20 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsPatrolController.java
  85. 75 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsProduceCheckController.java
  86. 74 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsProduceRecallController.java
  87. 113 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsRestInspectionController.java
  88. 73 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsSampleController.java
  89. 43 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsStockController.java
  90. 20 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsStoreController.java
  91. 20 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsTransportController.java
  92. 73 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsWorkshopController.java
  93. 58 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/entity/JsCheckDevice.java
  94. 58 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/entity/JsCheckInstrument.java
  95. 52 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/entity/JsCheckProject.java
  96. 53 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/entity/JsDeviceMaintenance.java
  97. 60 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/entity/JsDisinfect.java
  98. 53 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/entity/JsDisinfectManage.java
  99. 74 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/entity/JsDistribution.java
  100. 0 0
      app-admin/src/main/java/com/ruoyi/web/v2/v1/entity/JsDivideCircle.java

+ 150 - 0
app-admin/pom.xml

@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>ruoyi</artifactId>
+        <groupId>com.ruoyi</groupId>
+        <version>3.8.9</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>jar</packaging>
+    <artifactId>app-admin</artifactId>
+
+    <description>
+        web服务入口
+    </description>
+
+    <dependencies>
+
+        <!-- spring-boot-devtools -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+            <optional>true</optional> <!-- 表示依赖不会传递 -->
+        </dependency>
+
+        <!-- swagger3-->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-boot-starter</artifactId>
+        </dependency>
+
+        <!-- 防止进入swagger页面报类型转换错误,排除3.0.0中的引用,手动增加1.6.2版本 -->
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-models</artifactId>
+            <version>1.6.2</version>
+        </dependency>
+
+         <!-- Mysql驱动包 -->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+
+        <!-- 核心模块-->
+        <dependency>
+            <groupId>com.ruoyi</groupId>
+            <artifactId>app-framework</artifactId>
+        </dependency>
+
+        <!-- 定时任务-->
+        <dependency>
+            <groupId>com.ruoyi</groupId>
+            <artifactId>app-quartz</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>
+
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.7.11</version>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+            <version>3.4.2</version>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-extension</artifactId>
+            <version>3.4.2</version>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-generator</artifactId>
+            <version>3.2.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+
+        <dependency>
+            <groupId>com.jcraft</groupId>
+            <artifactId>jsch</artifactId>
+            <version>0.1.54</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.5.15</version>
+                <configuration>
+                    <fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>   
+                <groupId>org.apache.maven.plugins</groupId>   
+                <artifactId>maven-war-plugin</artifactId>   
+                <version>3.1.0</version>   
+                <configuration>
+                    <failOnMissingWebXml>false</failOnMissingWebXml>
+                    <warName>${project.artifactId}</warName>
+                </configuration>   
+           </plugin>   
+        </plugins>
+        <finalName>${project.artifactId}</finalName>
+
+     <!--   <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+            </resource>
+            <resource>
+                <directory>src/main/java</directory>
+                <includes>
+                    <include>**/*.xml</include>
+                </includes>
+                <filtering>false</filtering>
+            </resource>
+        </resources>-->
+
+    </build>
+
+</project>

+ 28 - 0
app-admin/src/main/java/com/ruoyi/RuoYiApplication.java

@@ -0,0 +1,28 @@
+package com.ruoyi;
+
+import com.ruoyi.common.server.EnvInputServer;
+import com.ruoyi.web.core.nfid.NFIDServer;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.context.ApplicationContext;
+
+/**
+ * 启动程序
+ * 
+ * @author ruoyi
+ */
+@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
+@MapperScan("com.ruoyi.web.v2.v1.mapper")
+public class RuoYiApplication
+{
+    public static void main(String[] args) throws Exception
+    {
+        // System.setProperty("spring.devtools.restart.enabled", "false");
+        ApplicationContext applicationContext = SpringApplication.run(RuoYiApplication.class, args);
+        applicationContext.getBean(NFIDServer.class).start();
+        // EnvInputServer
+        //applicationContext.getBean(EnvInputServer.class).run();
+    }
+}

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


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

@@ -0,0 +1,81 @@
+package com.ruoyi.web.controller.app;
+
+import com.ruoyi.app.DTO.EntranceReportDTO;
+import com.ruoyi.app.DTO.PurchaserProduceTotalDTO;
+import com.ruoyi.app.DTO.SlaughterReportDTO;
+import com.ruoyi.app.domain.request.ReqEntranceReport;
+
+import com.ruoyi.app.domain.request.ReqGetPorkSideProduceRecord;
+import com.ruoyi.app.domain.request.ReqSlaughterReport;
+import com.ruoyi.app.service.IDataReportService;
+
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.page.TableDataInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * 数据报表Controller
+ *
+ * @author coede
+ * @date 2025-03-31
+ */
+@RestController
+@RequestMapping("/app/dataReport")
+public class DataReportController extends BaseController {
+    @Autowired
+    private IDataReportService dataReportService;
+
+    /**
+     * 获取入场报表
+     */
+    @PreAuthorize("@ss.hasPermi('app:dataReport:getEntranceReport')")
+    @GetMapping(value = "/getEntranceReport")
+    public TableDataInfo getEntranceReport(ReqEntranceReport reqEntranceReport)
+    {
+        startPage();
+        List<EntranceReportDTO> list = dataReportService.selectEntranceReport(reqEntranceReport);
+        return getDataTable(list);
+    }
+
+    /**
+     * 获取检查检疫无害化报表
+     */
+    @PreAuthorize("@ss.hasPermi('app:dataReport:getInspectionReport')")
+    @GetMapping(value = "/getInspectionReport")
+    public TableDataInfo getInspectionReport(ReqEntranceReport reqEntranceReport)
+    {
+        startPage();
+        List<EntranceReportDTO> list = dataReportService.selectEntranceReport(reqEntranceReport);
+        return getDataTable(list);
+    }
+
+    /**
+     * 获取生产报表
+     */
+    @PreAuthorize("@ss.hasPermi('app:dataReport:getSlaughterReport')")
+    @GetMapping(value = "/getSlaughterReport")
+    public TableDataInfo getSlaughterReport(ReqSlaughterReport reqSlaughterReport)
+    {
+        startPage();
+        List<SlaughterReportDTO> list = dataReportService.selectSlaughterReport(reqSlaughterReport);
+        return getDataTable(list);
+    }
+
+    /**
+     * 获取称重统计
+     */
+    @PreAuthorize("@ss.hasPermi('app:dataReport:getWeightReport')")
+    @GetMapping(value = "/getWeightReport")
+    public TableDataInfo getWeightReport(ReqGetPorkSideProduceRecord req)
+    {
+        startPage();
+        List<PurchaserProduceTotalDTO> list = dataReportService.selectPurchaserProduceTotal(req);
+        return getDataTable(list);
+    }
+}

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


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


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


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


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

@@ -0,0 +1,131 @@
+package com.ruoyi.web.controller.app;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+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;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.app.domain.EntranceBatch;
+import com.ruoyi.app.service.IEntranceBatchService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 入场批次Controller
+ * 
+ * @author coede
+ * @date 2025-03-19
+ */
+@RestController
+@RequestMapping("/app/entranceBatch")
+public class EntranceBatchController extends BaseController
+{
+    @Autowired
+    private IEntranceBatchService entranceBatchService;
+
+    /**
+     * 查询入场批次列表
+     */
+    @PreAuthorize("@ss.hasPermi('app:entranceBatch:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(EntranceBatch entranceBatch)
+    {
+        startPage();
+        List<EntranceBatch> list = entranceBatchService.selectEntranceBatchList(entranceBatch);
+        return getDataTable(list);
+    }
+
+    /**
+     * 查询入场批次列表
+     */
+    @PreAuthorize("@ss.hasPermi('app:entranceBatch:page')")
+    @GetMapping("/page")
+    public TableDataInfo page(EntranceBatch entranceBatch)
+    {
+        List<EntranceBatch> list = entranceBatchService.selectEntranceBatchList(entranceBatch);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出入场批次列表
+     */
+    @PreAuthorize("@ss.hasPermi('app:entranceBatch:export')")
+    @Log(title = "入场批次", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, EntranceBatch entranceBatch)
+    {
+        List<EntranceBatch> list = entranceBatchService.selectEntranceBatchList(entranceBatch);
+        ExcelUtil<EntranceBatch> util = new ExcelUtil<EntranceBatch>(EntranceBatch.class);
+        util.exportExcel(response, list, "入场批次数据");
+    }
+
+    /**
+     * 获取入场批次详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('app:entranceBatch:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return success(entranceBatchService.selectEntranceBatchById(id));
+    }
+
+    /**
+     * 新增入场批次
+     */
+    @PreAuthorize("@ss.hasPermi('app:entranceBatch:add')")
+    @Log(title = "入场批次", businessType = BusinessType.INSERT)
+    @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));
+    }
+
+    /**
+     * 修改入场批次
+     */
+    @PreAuthorize("@ss.hasPermi('app:entranceBatch:edit')")
+    @Log(title = "入场批次", businessType = BusinessType.UPDATE)
+    @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));
+    }
+
+    /**
+     * 删除入场批次
+     */
+    @PreAuthorize("@ss.hasPermi('app:entranceBatch:remove')")
+    @Log(title = "入场批次", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(entranceBatchService.deleteEntranceBatchByIds(ids));
+    }
+}

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


+ 138 - 0
app-admin/src/main/java/com/ruoyi/web/controller/app/HarmlessTreatmentController.java

@@ -0,0 +1,138 @@
+package com.ruoyi.web.controller.app;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.ruoyi.app.domain.EntranceBatch;
+import com.ruoyi.app.service.IEntranceBatchService;
+import com.ruoyi.web.v2.v1.entity.JsDivideCircle;
+import com.ruoyi.web.v2.v1.service.IJsDivideCircleService;
+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;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.app.domain.HarmlessTreatment;
+import com.ruoyi.app.service.IHarmlessTreatmentService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 无害化处理Controller
+ * 
+ * @author coede
+ * @date 2025-03-19
+ */
+@RestController
+@RequestMapping("/app/harmlessTreatment")
+public class HarmlessTreatmentController extends BaseController
+{
+    @Autowired
+    private IHarmlessTreatmentService harmlessTreatmentService;
+    @Autowired
+    private IJsDivideCircleService divideCircleService;
+    @Autowired
+    private IEntranceBatchService entranceBatchService;
+
+    /**
+     * 查询无害化处理列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(HarmlessTreatment harmlessTreatment)
+    {
+        startPage();
+        List<HarmlessTreatment> list = harmlessTreatmentService.selectHarmlessTreatmentList(harmlessTreatment);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出无害化处理列表
+     */
+    @PreAuthorize("@ss.hasPermi('app:harmlessTreatment:export')")
+    @Log(title = "无害化处理", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, HarmlessTreatment harmlessTreatment)
+    {
+        List<HarmlessTreatment> list = harmlessTreatmentService.selectHarmlessTreatmentList(harmlessTreatment);
+        ExcelUtil<HarmlessTreatment> util = new ExcelUtil<HarmlessTreatment>(HarmlessTreatment.class);
+        util.exportExcel(response, list, "无害化处理数据");
+    }
+
+    /**
+     * 获取无害化处理详细信息
+     */
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return success(harmlessTreatmentService.selectHarmlessTreatmentById(id));
+    }
+
+    /**
+     * 新增无害化处理
+     */
+    @PreAuthorize("@ss.hasPermi('app:harmlessTreatment:add')")
+    @Log(title = "无害化处理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated  @RequestBody HarmlessTreatment harmlessTreatment)
+    {
+        //判断全部数量是否超出了入场数量
+        if(!harmlessTreatmentService.checkTotalLessThanAmount(harmlessTreatment)){
+            return error("新增无害化处理失败,病死头数、病害头数、途亡头数或急宰头数输入错误");
+        }
+        harmlessTreatment.setCreateBy(getUsername());
+        return toAjax(harmlessTreatmentService.insertHarmlessTreatment(harmlessTreatment));
+    }
+
+    /**
+     * 修改无害化处理
+     */
+    @PreAuthorize("@ss.hasPermi('app:harmlessTreatment:edit')")
+    @Log(title = "无害化处理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody HarmlessTreatment harmlessTreatment)
+    {
+        //判断全部数量是否超出了入场数量
+        if(!harmlessTreatmentService.checkTotalLessThanAmount(harmlessTreatment)){
+            return error("修改无害化处理失败,病死头数、病害头数、途亡头数或急宰头数输入错误");
+        }
+        //判断是否填写分圈
+        EntranceBatch entranceBatch = entranceBatchService.selectEntranceBatchById(harmlessTreatment.getEntranceBatchId());
+        int count = divideCircleService.count(new QueryWrapper<JsDivideCircle>().eq("animal_cert_no", entranceBatch.getAnimalCertNo()));
+        if (count != 0) {
+            return error("已经填写分圈,不可修改无害化处理");
+        }
+        harmlessTreatment.setUpdateBy(getUsername());
+        return toAjax(harmlessTreatmentService.updateHarmlessTreatment(harmlessTreatment));
+    }
+
+    /**
+     * 删除无害化处理
+     */
+    @PreAuthorize("@ss.hasPermi('app:harmlessTreatment:remove')")
+    @Log(title = "无害化处理", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        //判断是否填写分圈
+        for (Long id : ids) {
+            HarmlessTreatment harmlessTreatment = harmlessTreatmentService.selectHarmlessTreatmentById(id);
+            EntranceBatch entranceBatch = entranceBatchService.selectEntranceBatchById(harmlessTreatment.getEntranceBatchId());
+            int count = divideCircleService.count(new QueryWrapper<JsDivideCircle>().eq("animal_cert_no", entranceBatch.getAnimalCertNo()));
+            if (count != 0) {
+                return error("已经填写分圈,不可修改无害化处理");
+            }
+        }
+        return toAjax(harmlessTreatmentService.deleteHarmlessTreatmentByIds(ids));
+    }
+}

+ 226 - 0
app-admin/src/main/java/com/ruoyi/web/controller/app/HookBindController.java

@@ -0,0 +1,226 @@
+package com.ruoyi.web.controller.app;
+
+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 com.ruoyi.common.utils.uuid.IdUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+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;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.app.domain.HookBind;
+import com.ruoyi.app.service.IHookBindService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+import static com.ruoyi.common.utils.uuid.IdUtils.fastSimpleUUID;
+
+/**
+ * 吊钩绑定Controller
+ * 
+ * @author coede
+ * @date 2025-03-19
+ */
+@Api("吊钩绑定信息管理")
+@RestController
+@RequestMapping("/app/hookBind")
+public class HookBindController extends BaseController
+{
+    @Autowired
+    private IHookBindService hookBindService;
+
+    /**
+     * 查询吊钩绑定列表
+     */
+    @ApiOperation("查询吊钩绑定列表")
+    @GetMapping("/list")
+    public TableDataInfo list(HookBind hookBind)
+    {
+        startPage();
+        List<HookBind> list = hookBindService.selectHookBindList(hookBind);
+        return getDataTable(list);
+    }
+
+    /**
+     * 按批次查询吊钩绑定列表
+     */
+    @ApiOperation("按批次查询吊钩绑定列表")
+    @GetMapping("/batchList")
+    public TableDataInfo batchList(ReqHookBindList req)
+    {
+        startPage();
+        List<HookBindBatchListDTO> list = hookBindService.selectHookBindListByBatch(req);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出吊钩绑定列表
+     */
+    @ApiOperation("导出吊钩绑定列表")
+    @PreAuthorize("@ss.hasPermi('app:hookBind:export')")
+    @Log(title = "吊钩绑定", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, HookBind hookBind)
+    {
+        List<HookBind> list = hookBindService.selectHookBindList(hookBind);
+        ExcelUtil<HookBind> util = new ExcelUtil<HookBind>(HookBind.class);
+        util.exportExcel(response, list, "吊钩绑定数据");
+    }
+
+    /**
+     * 获取吊钩绑定详细信息
+     */
+    @ApiOperation("获取吊钩绑定详细信息")
+    @GetMapping(value = "/group")
+    public AjaxResult getGroupInfo(@Validated ReqHookBindDetail req)
+    {
+        return success(hookBindService.selectHookBindByBatch(req.getBatchNo()));
+    }
+
+    /**
+     * 获取吊钩绑定详细信息
+     */
+    @ApiOperation("获取吊钩绑定详细信息")
+    @GetMapping(value = "/detail/{hookNo}")
+    public AjaxResult getDetail(@PathVariable("hookNo") String hookNo)
+    {
+        return success(hookBindService.selectHookBindOnlyDetail(hookNo));
+    }
+
+    /**
+     * 新增吊钩绑定 暂时不用
+     */
+    @ApiOperation("新增吊钩绑定 暂时不用")
+    @PreAuthorize("@ss.hasPermi('app:hookBind:add')")
+    @Log(title = "吊钩绑定", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated  @RequestBody HookBind hookBind)
+    {
+        hookBind.setCreateBy(getUsername());
+        return toAjax(hookBindService.insertHookBind(hookBind));
+    }
+
+    /**
+     * 新增吊钩批量绑定
+     */
+    @ApiOperation("新增吊钩批量绑定")
+    @PreAuthorize("@ss.hasPermi('app:hookBind:add')")
+    @Log(title = "吊钩绑定", businessType = BusinessType.INSERT)
+    @PostMapping("/addBatch")
+    public AjaxResult addBatch(@Validated  @RequestBody AddHookBindBatch req)
+    {
+        try {
+            //生成新对象
+            List<HookBind> hookBindArr = new ArrayList<>();
+            String batchNo = fastSimpleUUID();
+            //先判断本身数组内是否有重复的
+            Set<String> uniqueIds = new HashSet<>();
+
+            for (String hook : req.getHookNoListArr()) {
+                //noinspection ConstantConditions  忽略错误的IDEA提示
+                if (!uniqueIds.add(hook)) {
+                    return error("新增吊钩批量绑定,本次添加存在相同的吊钩号");
+                }
+                HookBind hookBind = new HookBind();
+                hookBind.setBatchNo(batchNo);
+                hookBind.setHookNo(hook);
+                hookBind.setBindTime(req.getBindTime());
+                hookBind.setDistributeBatchId(req.getDistributeBatchId());
+                hookBind.setSlaughterCode(req.getSlaughterCode());
+                hookBind.setCreateTime(DateUtils.getNowDate());
+                hookBind.setCreateBy(getUsername());
+
+                //未传绑定时间默认当前时间
+                if (req.getBindTime() == null) {
+                    hookBind.setBindTime(DateUtils.getNowDate());
+                }else{
+                    hookBind.setBindTime(req.getBindTime());
+                }
+                hookBindArr.add(hookBind);
+            }
+            //校验数据库的
+            for (HookBind hookBind : hookBindArr) {
+
+                HookBind check = hookBindService.checkHookNoUnique(hookBind);
+                if (StringUtils.isNotNull(check)) {
+                    return error("新增吊钩批量绑定失败,'" + check.getHookNo() + "'同一时间已存在绑定");
+                }
+            }
+            return toAjax(hookBindService.insertHookBindBatch(hookBindArr,req.getHookNoListArr()));
+        }catch(Exception e) {
+                return error("新增吊钩批量绑定失败:"+e.getMessage());
+        }
+    }
+
+    /**
+     * 修改吊钩绑定
+     */
+    @ApiOperation("修改吊钩绑定")
+    @PreAuthorize("@ss.hasPermi('app:hookBind:edit')")
+    @Log(title = "吊钩绑定", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody HookBind hookBind)
+    {
+
+        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("删除吊钩绑定")
+    @PreAuthorize("@ss.hasPermi('app:hookBind:remove')")
+    @Log(title = "吊钩绑定", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{batchNos}")
+    public AjaxResult remove(@PathVariable String[] batchNos)
+    {
+        return toAjax(hookBindService.deleteHookBindByIds(batchNos));
+    }
+
+    /**
+     * 清除吊钩绑定关系-不删除数据只是将绑定关系设置为未绑定
+     */
+    @ApiOperation("清除吊钩绑定关系")
+    @PreAuthorize("@ss.hasPermi('app:hookBind:clean')")
+    @Log(title = "吊钩绑定", businessType = BusinessType.UPDATE)
+    @PostMapping("/cleanBind")
+    public AjaxResult cleanBind()
+    {
+        return AjaxResult.success(hookBindService.cleanHookBind());
+    }
+}

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


+ 128 - 0
app-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);
+    }
+}

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


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

@@ -0,0 +1,212 @@
+package com.ruoyi.web.controller.app;
+
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.servlet.http.HttpServletResponse;
+
+import com.ruoyi.app.domain.request.ReqMonitorAction;
+import com.ruoyi.web.core.wvp.domain.DeviceChannelExtend;
+import com.ruoyi.common.utils.DateUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.app.domain.Monitor;
+import com.ruoyi.app.service.IMonitorService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.web.core.wvp.DeviceHandler;
+
+/**
+ * 监控设备Controller
+ * 
+ * @author coede
+ * @date 2025-03-19
+ */
+@Api("监控设备信息管理")
+@RestController
+@RequestMapping("/app/monitor")
+public class MonitorController extends BaseController
+{
+    @Autowired
+    private IMonitorService monitorService;
+
+    @Autowired
+    private DeviceHandler deviceHandler;
+
+    public static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);
+    /**
+     * 查询监控设备列表
+     */
+    @ApiOperation("查询监控设备列表")
+    @PreAuthorize("@ss.hasPermi('app:monitor:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(Monitor monitor)
+    {
+        startPage();
+        List<Monitor> list = monitorService.selectMonitorList(monitor);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出监控设备列表
+     */
+    @ApiOperation("导出监控设备列表")
+    @PreAuthorize("@ss.hasPermi('app:monitor:export')")
+    @Log(title = "监控设备", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, Monitor monitor)
+    {
+        List<Monitor> list = monitorService.selectMonitorList(monitor);
+        ExcelUtil<Monitor> util = new ExcelUtil<Monitor>(Monitor.class);
+        util.exportExcel(response, list, "监控设备数据");
+    }
+
+    /**
+     * 获取监控设备详细信息
+     */
+    @ApiOperation("获取监控设备详细信息")
+    @PreAuthorize("@ss.hasPermi('app:monitor:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return success(monitorService.selectMonitorById(id));
+    }
+
+    /**
+     * 新增监控设备
+     */
+    @ApiOperation("新增监控设备")
+    @PreAuthorize("@ss.hasPermi('app:monitor:add')")
+    @Log(title = "监控设备", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated  @RequestBody Monitor monitor)
+    {
+        if (!monitorService.checkMonitorNameUnique(monitor))
+        {
+            return error("新增监控设备'" + monitor.getMonitorName() + "'失败,列表中存在重复的监控名称");
+        }
+        monitor.setCreateBy(getUsername());
+        return toAjax(monitorService.insertMonitor(monitor));
+    }
+
+    /**
+     * 同步监控设备
+     */
+    @ApiOperation("同步监控设备")
+    @PreAuthorize("@ss.hasPermi('app:monitor:sync')")
+    @Log(title = "监控设备", businessType = BusinessType.INSERT)
+    @PostMapping("/sync")
+    public AjaxResult sync()
+    {
+        try {
+            //获取WVP所有的设备通道
+            List<DeviceChannelExtend> channelList = deviceHandler.getDeviceList();
+            Date now = DateUtils.getNowDate();
+            List<Monitor> monitorArr = channelList.stream()
+                    .map(item -> {
+                        Monitor monitor = new Monitor();
+                        monitor.setMonitorName(item.getName());
+                        monitor.setIpAddr(item.getIpAddress());
+                        monitor.setMonitorBrand(item.getManufacture());
+                        monitor.setDeviceId(item.getDeviceId());
+                        monitor.setChannelId(item.getChannelId());
+                        monitor.setCreateTime(now);
+                        monitor.setCreateBy(getUsername());
+                        return monitor;
+                    })
+                    .collect(Collectors.toList());
+            return toAjax(monitorService.syncMonitor(monitorArr));
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return error("同步失败");
+        }
+    }
+
+    /**
+     * 修改监控设备
+     */
+    @ApiOperation("修改监控设备")
+    @PreAuthorize("@ss.hasPermi('app:monitor:edit')")
+    @Log(title = "监控设备", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody Monitor monitor)
+    {
+        if (!monitorService.checkMonitorNameUnique(monitor))
+        {
+            return error("修改监控设备'" + monitor.getMonitorName() + "'失败,列表中存在重复的监控名称");
+        }
+        monitor.setUpdateBy(getUsername());
+        return toAjax(monitorService.updateMonitor(monitor));
+    }
+
+    /**
+     * 删除监控设备
+     */
+    @ApiOperation("删除监控设备")
+    @PreAuthorize("@ss.hasPermi('app:monitor:remove')")
+    @Log(title = "监控设备", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(monitorService.deleteMonitorByIds(ids));
+    }
+
+    /**
+     * 播放监控设备
+     */
+    @ApiOperation("播放监控设备")
+    @PreAuthorize("@ss.hasPermi('app:monitor:playStart')")
+    @Log(title = "监控设备", businessType = BusinessType.OTHER)
+    @PostMapping("/playStart")
+    public AjaxResult playStart(@Validated @RequestBody ReqMonitorAction req)
+    {
+        try{
+        Object res = deviceHandler.playOrStop(DeviceHandler.VIDEO_PLAY_START,req.getDeviceId(),req.getChannelId());
+            if (res != null){
+                return AjaxResult.success(res);
+            }else{
+                throw new RuntimeException("无视频信息,请重试");
+            }
+        }catch (Exception e){
+            return error("播放失败:"+e.getMessage());
+        }
+    }
+
+    /**
+     * 停止监控设备
+     */
+    @ApiOperation("停止监控设备")
+    @PreAuthorize("@ss.hasPermi('app:monitor:playStop')")
+    @Log(title = "监控设备", businessType = BusinessType.OTHER)
+    @PostMapping("/playStop")
+    public AjaxResult playStop(@Validated @RequestBody ReqMonitorAction req)
+    {
+        try{
+            Object res = deviceHandler.playOrStop(DeviceHandler.VIDEO_PLAY_STOP,req.getDeviceId(),req.getChannelId());
+            if (res != null){
+                return AjaxResult.success(res);
+            }else{
+                throw new RuntimeException("无视频信息,请重试");
+            }
+        }catch (Exception e){
+            return error("停止失败:"+e.getMessage());
+        }
+    }
+}

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

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

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


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


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

@@ -0,0 +1,137 @@
+package com.ruoyi.web.controller.app;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+
+import com.ruoyi.app.domain.PigCategory;
+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;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.app.domain.Pigpen;
+import com.ruoyi.app.service.IPigpenService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 待宰圈Controller
+ * 
+ * @author coede
+ * @date 2025-03-19
+ */
+@RestController
+@RequestMapping("/app/pigpen")
+public class PigpenController extends BaseController
+{
+    @Autowired
+    private IPigpenService pigpenService;
+
+    /**
+     * 查询待宰圈列表
+     */
+    @PreAuthorize("@ss.hasPermi('app:pigpen:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(Pigpen pigpen)
+    {
+        startPage();
+        List<Pigpen> list = pigpenService.selectPigpenList(pigpen);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出待宰圈列表
+     */
+    @PreAuthorize("@ss.hasPermi('app:pigpen:export')")
+    @Log(title = "待宰圈", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, Pigpen pigpen)
+    {
+        List<Pigpen> list = pigpenService.selectPigpenList(pigpen);
+        ExcelUtil<Pigpen> util = new ExcelUtil<Pigpen>(Pigpen.class);
+        util.exportExcel(response, list, "待宰圈数据");
+    }
+
+    /**
+     * 获取待宰圈详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('app:pigpen:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return success(pigpenService.selectPigpenById(id));
+    }
+
+    /**
+     * 新增待宰圈
+     */
+    @PreAuthorize("@ss.hasPermi('app:pigpen:add')")
+    @Log(title = "待宰圈", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody Pigpen pigpen)
+    {
+        if (!pigpenService.checkPigpenNameUnique(pigpen))
+        {
+            return error("新增待宰圈'" + pigpen.getPigpenName() + "'失败,列表中存在重复的待宰圈号");
+        }
+        pigpen.setCreateBy(getUsername());
+        return toAjax(pigpenService.insertPigpen(pigpen));
+    }
+
+    /**
+     * 修改待宰圈
+     */
+    @PreAuthorize("@ss.hasPermi('app:pigpen:edit')")
+    @Log(title = "待宰圈", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody Pigpen pigpen)
+    {
+        if (!pigpenService.checkPigpenNameUnique(pigpen))
+        {
+            return error("修改待宰圈'" + pigpen.getPigpenName() + "'失败,列表中存在重复的待宰圈号");
+        }
+        if (pigpen.getIsUse() != 0) {
+            return error("修改待宰圈失败,待宰圈正在使用");
+        }
+        pigpen.setUpdateBy(getUsername());
+        return toAjax(pigpenService.updatePigpen(pigpen));
+    }
+
+    /**
+     * 删除待宰圈
+     */
+    @PreAuthorize("@ss.hasPermi('app:pigpen:remove')")
+    @Log(title = "待宰圈", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        for (Long id : ids) {
+            Pigpen pigpen = pigpenService.selectPigpenById(id);
+            if (pigpen.getIsUse() != 0) {
+                return error("删除待宰圈失败,待宰圈正在使用");
+            }
+        }
+        return toAjax(pigpenService.deletePigpenByIds(ids));
+    }
+
+    /**
+     * 获取待宰圈选择框列表
+     */
+    @GetMapping("/optionselect")
+    public AjaxResult optionselect()
+    {
+        Pigpen pigpen = new Pigpen();
+        List<Pigpen> list = pigpenService.selectPigpenList(pigpen);
+        return success(list);
+    }
+}

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


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


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

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

+ 133 - 0
app-admin/src/main/java/com/ruoyi/web/controller/app/ProductCategoryController.java

@@ -0,0 +1,133 @@
+package com.ruoyi.web.controller.app;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+
+import com.ruoyi.app.domain.Pigpen;
+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;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.app.domain.ProductCategory;
+import com.ruoyi.app.service.IProductCategoryService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 产品分类Controller
+ * 
+ * @author coede
+ * @date 2025-03-19
+ */
+@RestController
+@RequestMapping("/app/productCategory")
+public class ProductCategoryController extends BaseController
+{
+    @Autowired
+    private IProductCategoryService productCategoryService;
+
+    /**
+     * 查询产品分类列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(ProductCategory productCategory)
+    {
+        startPage();
+        List<ProductCategory> list = productCategoryService.selectProductCategoryList(productCategory);
+        return getDataTable(list);
+    }
+
+    @GetMapping("/page")
+    public TableDataInfo page(ProductCategory productCategory)
+    {
+        List<ProductCategory> list = productCategoryService.selectProductCategoryList(productCategory);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出产品分类列表
+     */
+    @PreAuthorize("@ss.hasPermi('app:productCategory:export')")
+    @Log(title = "产品分类", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, ProductCategory productCategory)
+    {
+        List<ProductCategory> list = productCategoryService.selectProductCategoryList(productCategory);
+        ExcelUtil<ProductCategory> util = new ExcelUtil<ProductCategory>(ProductCategory.class);
+        util.exportExcel(response, list, "产品分类数据");
+    }
+
+    /**
+     * 获取产品分类详细信息
+     */
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return success(productCategoryService.selectProductCategoryById(id));
+    }
+
+    /**
+     * 新增产品分类
+     */
+    @PreAuthorize("@ss.hasPermi('app:productCategory:add')")
+    @Log(title = "产品分类", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody ProductCategory productCategory)
+    {
+        if (!productCategoryService.checkProductNameUnique(productCategory))
+        {
+            return error("新增产品分类'" + productCategory.getProductName() + "'失败,列表中存在重复的产品名称");
+        }
+        productCategory.setCreateBy(getUsername());
+        return toAjax(productCategoryService.insertProductCategory(productCategory));
+    }
+
+    /**
+     * 修改产品分类
+     */
+    @PreAuthorize("@ss.hasPermi('app:productCategory:edit')")
+    @Log(title = "产品分类", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody ProductCategory productCategory)
+    {
+        if (!productCategoryService.checkProductNameUnique(productCategory))
+        {
+            return error("修改产品分类'" + productCategory.getProductName() + "'失败,列表中存在重复的产品名称");
+        }
+        productCategory.setUpdateBy(getUsername());
+        return toAjax(productCategoryService.updateProductCategory(productCategory));
+    }
+
+    /**
+     * 删除产品分类
+     */
+    @PreAuthorize("@ss.hasPermi('app:productCategory:remove')")
+    @Log(title = "产品分类", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(productCategoryService.deleteProductCategoryByIds(ids));
+    }
+
+    /**
+     * 获取待宰圈选择框列表
+     */
+    @GetMapping("/optionselect")
+    public AjaxResult optionselect()
+    {
+        ProductCategory productCategory = new ProductCategory();
+        List<ProductCategory> list = productCategoryService.selectProductCategoryList(productCategory);
+        return success(list);
+    }
+}

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


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


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


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


+ 226 - 0
app-admin/src/main/java/com/ruoyi/web/controller/app/SlaughterRelationController.java

@@ -0,0 +1,226 @@
+package com.ruoyi.web.controller.app;
+
+import java.util.HashSet;
+import java.util.List;
+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.request.ReqSlaughterRelation;
+import com.ruoyi.app.domain.response.RespGetSlaughterRelation;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.StringUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+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;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.app.domain.SlaughterRelation;
+import com.ruoyi.app.service.ISlaughterRelationService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 血码关系Controller
+ * 
+ * @author coede
+ * @date 2025-03-19
+ */
+@Api("血码关系信息管理")
+@RestController
+@RequestMapping("/app/slaughterRelation")
+public class SlaughterRelationController extends BaseController
+{
+    @Autowired
+    private ISlaughterRelationService slaughterRelationService;
+
+    /**
+     * 供应商血码数量列表
+     */
+    @ApiOperation("供应商血码数量列表")
+    @GetMapping("/supplierList")
+    public TableDataInfo supplierList(ReqGetSlaughterRelation req)
+    {
+        startPage();
+        List<RespGetSlaughterRelation> list = slaughterRelationService.selectSupplierList(req);
+        return getDataTable(list);
+    }
+
+    /**
+     * 查询血码关系列表
+     */
+    @ApiOperation("查询血码关系列表")
+    @GetMapping("/list")
+    public TableDataInfo list(ReqSlaughterRelation req)
+    {
+        startPage();
+        List<SlaughterRelation> list = slaughterRelationService.selectSlaughterRelationList(req);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出血码关系列表
+     */
+    @ApiOperation("导出血码关系列表")
+    @PreAuthorize("@ss.hasPermi('app:slaughterRelation:export')")
+    @Log(title = "血码关系", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, ExportSlaughterRelation req)
+    {
+        List<SlaughterRelationDTO> list = slaughterRelationService.exportSlaughterRelationList(req);
+        list.forEach(item -> item.setQrcode(item.getSlaughterCode()));
+        ExcelUtil<SlaughterRelationDTO> util = new ExcelUtil<>(SlaughterRelationDTO.class);
+        util.exportExcel(response, list, "血码关系数据");
+    }
+
+    /**
+     * 获取血码关系详细信息
+     */
+    @ApiOperation("获取血码关系详细信息")
+    @PreAuthorize("@ss.hasPermi('app:slaughterRelation:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return success(slaughterRelationService.selectSlaughterRelationById(id));
+    }
+
+    /**
+     * 新增血码关系
+     */
+    @ApiOperation("新增血码关系")
+    @PreAuthorize("@ss.hasPermi('app:slaughterRelation:add')")
+    @Log(title = "血码关系", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SlaughterRelation slaughterRelation)
+    {
+        if (!slaughterRelationService.checkCodeUnique(slaughterRelation))
+        {
+            return error("新增血码关系失败,血码'" + slaughterRelation.getSlaughterCode() + "'已存在");
+        }
+        SlaughterRelation check = slaughterRelationService.checkPurchaserUnique(slaughterRelation);
+        if (StringUtils.isNotNull(check))
+        {
+            Purchaser purchaser = check.getPurchaser();
+            return error("新增血码关系失败,该供应商下肉商'" + purchaser.getPurchaserName() + "'已存在");
+        }
+        slaughterRelation.setCreateBy(getUsername());
+        return toAjax(slaughterRelationService.insertSlaughterRelation(slaughterRelation));
+    }
+
+    /**
+     * 批量新增血码关系
+     */
+    @ApiOperation("批量新增血码关系")
+    @PreAuthorize("@ss.hasPermi('app:slaughterRelation:add')")
+    @Log(title = "血码关系", businessType = BusinessType.INSERT)
+    @PostMapping(value = "/addBatch")
+    public AjaxResult addBatch(@Validated @RequestBody AddSlaughterRelationBatch req)
+    {
+        //生成新对象
+        List<SlaughterRelation> relationArr = req.getRelationArr().stream()
+                .map(item -> {
+                    SlaughterRelation newrelation = new SlaughterRelation();
+                    newrelation.setPurchaserId(item.getPurchaserId());
+                    newrelation.setSlaughterCode(item.getSlaughterCode());
+                    newrelation.setSupplierId(req.getSupplierId());
+                    newrelation.setCreateTime(DateUtils.getNowDate());
+                    newrelation.setCreateBy(getUsername());
+                    return newrelation;
+                })
+                .collect(Collectors.toList());
+        //先判断本身数组内是否有重复的
+        Set<String> uniqueIds = new HashSet<>();
+        Set<String> uniqueCodes = new HashSet<>();
+        for (SlaughterRelation relation : relationArr) {
+            String key = String.valueOf(relation.getPurchaserId());
+            //noinspection ConstantConditions  忽略错误的IDEA提示
+            if (!uniqueIds.add(key)) {
+                return error("新增血码关系失败,存在同一肉商配置多个血码的情况");
+            }
+            String code = relation.getSlaughterCode();
+            //noinspection ConstantConditions  忽略错误的IDEA提示
+            if (!uniqueCodes.add(code)) {
+                return error("新增血码关系失败,存在多个肉商配置同一血码的情况");
+            }
+        }
+        //校验数据库的
+        for (SlaughterRelation relation : relationArr) {
+
+            if (!slaughterRelationService.checkCodeUnique(relation))
+            {
+                return error("新增血码关系失败,血码'" + relation.getSlaughterCode() + "'已存在");
+            }
+            SlaughterRelation check = slaughterRelationService.checkPurchaserUnique(relation);
+            if (StringUtils.isNotNull(check))
+            {
+                Purchaser purchaser = check.getPurchaser();
+                return error("新增血码关系失败,该供应商下肉商'" + purchaser.getPurchaserName() + "'已存在");
+            }
+        }
+        return toAjax(slaughterRelationService.insertSlaughterRelationBatch(relationArr));
+    }
+
+    /**
+     * 修改血码关系
+     */
+    @ApiOperation("修改血码关系")
+    @PreAuthorize("@ss.hasPermi('app:slaughterRelation:edit')")
+    @Log(title = "血码关系", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SlaughterRelation slaughterRelation)
+    {
+        if (!slaughterRelationService.checkCodeUnique(slaughterRelation))
+        {
+            return error("修改血码关系失败,血码'" + slaughterRelation.getSlaughterCode() + "'已存在");
+        }
+        SlaughterRelation check = slaughterRelationService.checkPurchaserUnique(slaughterRelation);
+        if (StringUtils.isNotNull(check) && check.getId().longValue() != slaughterRelation.getId().longValue())
+        {
+            Purchaser purchaser = check.getPurchaser();
+            return error("修改血码关系失败,该供应商下肉商'" + purchaser.getPurchaserName() + "'已存在");
+        }
+        slaughterRelation.setUpdateBy(getUsername());
+        return toAjax(slaughterRelationService.updateSlaughterRelation(slaughterRelation));
+    }
+
+    /**
+     * 删除血码关系
+     */
+    @ApiOperation("删除血码关系")
+    @PreAuthorize("@ss.hasPermi('app:slaughterRelation:remove')")
+    @Log(title = "血码关系", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(slaughterRelationService.deleteSlaughterRelationByIds(ids));
+    }
+
+    /**
+     * 查询全部血码关系列表
+     */
+    @ApiOperation("查询全部血码关系列表")
+    @GetMapping("/optionselect")
+    public AjaxResult optionselect(ReqSlaughterRelation req)
+    {
+
+        List<SlaughterRelation> list = slaughterRelationService.selectSlaughterRelationList(req);
+        return success(list);
+    }
+}

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


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


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


+ 218 - 0
app-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java

@@ -0,0 +1,218 @@
+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.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;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.utils.StringUtils;
+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;
+
+/**
+ * 通用请求处理
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/common")
+public class CommonController
+{
+    private static final Logger log = LoggerFactory.getLogger(CommonController.class);
+
+    @Autowired
+    private ServerConfig serverConfig;
+
+    private static final String FILE_DELIMETER = ",";
+
+    /**
+     * 通用下载请求
+     * 
+     * @param fileName 文件名称
+     * @param delete 是否删除
+     */
+    @GetMapping("/download")
+    public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request)
+    {
+        try
+        {
+            if (!FileUtils.checkAllowDownload(fileName))
+            {
+                throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName));
+            }
+            String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
+            String filePath = RuoYiConfig.getDownloadPath() + fileName;
+
+            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
+            FileUtils.setAttachmentResponseHeader(response, realFileName);
+            FileUtils.writeBytes(filePath, response.getOutputStream());
+            if (delete)
+            {
+                FileUtils.deleteFile(filePath);
+            }
+        }
+        catch (Exception e)
+        {
+            log.error("下载文件失败", e);
+        }
+    }
+
+    /**
+     * 通用上传请求(单个)
+     */
+    @PostMapping("/upload")
+    public AjaxResult uploadFile(MultipartFile file) throws Exception
+    {
+        try
+        {
+            // 上传文件路径
+            String filePath = RuoYiConfig.getUploadPath();
+            // 上传并返回新文件名称
+            String fileName = FileUploadUtils.upload(filePath, file);
+            String url = serverConfig.getUrl() + fileName;
+            AjaxResult ajax = AjaxResult.success();
+            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());
+        }
+    }
+
+    /**
+     * 上传PDF文件并解析
+     */
+    @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")
+    public AjaxResult uploadFiles(List<MultipartFile> files) throws Exception
+    {
+        try
+        {
+            // 上传文件路径
+            String filePath = RuoYiConfig.getUploadPath();
+            List<String> urls = new ArrayList<String>();
+            List<String> fileNames = new ArrayList<String>();
+            List<String> newFileNames = new ArrayList<String>();
+            List<String> originalFilenames = new ArrayList<String>();
+            for (MultipartFile file : files)
+            {
+                // 上传并返回新文件名称
+                String fileName = FileUploadUtils.upload(filePath, file);
+                String url = serverConfig.getUrl() + fileName;
+                urls.add(url);
+                fileNames.add(fileName);
+                newFileNames.add(FileUtils.getName(fileName));
+                originalFilenames.add(file.getOriginalFilename());
+            }
+            AjaxResult ajax = AjaxResult.success();
+            ajax.put("urls", StringUtils.join(urls, FILE_DELIMETER));
+            ajax.put("fileNames", StringUtils.join(fileNames, FILE_DELIMETER));
+            ajax.put("newFileNames", StringUtils.join(newFileNames, FILE_DELIMETER));
+            ajax.put("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMETER));
+            return ajax;
+        }
+        catch (Exception e)
+        {
+            return AjaxResult.error(e.getMessage());
+        }
+    }
+
+    /**
+     * 本地资源通用下载
+     */
+    @GetMapping("/download/resource")
+    public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response)
+            throws Exception
+    {
+        try
+        {
+            if (!FileUtils.checkAllowDownload(resource))
+            {
+                throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", resource));
+            }
+            // 本地资源路径
+            String localPath = RuoYiConfig.getProfile();
+            // 数据库资源地址
+            String downloadPath = localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX);
+            // 下载名称
+            String downloadName = StringUtils.substringAfterLast(downloadPath, "/");
+            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
+            FileUtils.setAttachmentResponseHeader(response, downloadName);
+            FileUtils.writeBytes(downloadPath, response.getOutputStream());
+        }
+        catch (Exception e)
+        {
+            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);
+    }
+}

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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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

@@ -0,0 +1,158 @@
+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"));
+        //识别器连接后发送读取标签指令
+        sendReadResponseFrame(ctx);
+        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,bytes);
+            }
+        } finally {
+            ReferenceCountUtil.release(msg); // 释放ByteBuf
+        }
+    }
+
+    private void processFrames(ChannelHandlerContext ctx, List<NFIDFrameParser.NFIDFrame> frames,byte[] bytes) {
+        for (NFIDFrameParser.NFIDFrame frame : frames) {
+            // 记录接收到的帧
+           //System.out.println("Received frame: " + frame);
+
+//            // 检查是否可以发送读取
+//            if (NFIDFrameParser.isReadResponseRequiredFrame(frame)) {
+//                //发送读取指令
+//                sendReadResponseFrame(ctx);
+//            }
+            // 检查是否需要发送连接状态确认的响应
+            if (NFIDFrameParser.isStatusResponseRequiredFrame(frame)) {
+                //发送响应指令
+                sendStatusResponseFrame(ctx,bytes);
+            }
+
+            // 检查是否读写器信息帧
+            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("")) {
+//                        System.out.println("天线:"+ctx.channel().id().asLongText());
+                        processor.receiveTag(tag, reader);
+                    }
+                }
+            }
+        }
+
+        // 通知帧处理器
+       // frameHandler.handleFrames(frames, ctx);
+    }
+
+    //向读写器发送读取指令
+    private void sendReadResponseFrame(ChannelHandlerContext ctx) {
+        int index = responseIndex.getAndUpdate(i -> i < 4 ? i + 1 : 1);
+        byte[] response = NFIDFrameParser.generateReadResponseFrame(index);
+        ctx.writeAndFlush(Unpooled.wrappedBuffer(response));
+        System.out.println("Sent read response frame with index: " + index);
+    }
+
+    //向读写器发送状态确认指令
+    private void sendStatusResponseFrame(ChannelHandlerContext ctx,byte[] bytes) {
+        ctx.writeAndFlush(Unpooled.wrappedBuffer(bytes));
+       // System.out.println("Sent status confirm response frame" );
+    }
+
+    @Override
+    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);
+    }
+
+}

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


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

@@ -0,0 +1,348 @@
+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.NFIDReadRecord;
+import com.ruoyi.app.domain.PorkSideProduce;
+import com.ruoyi.app.service.*;
+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 = 1000;
+    private static final long TAG_EXPIRY_MS = 6*60*60*1000;
+    private static final int DISRUPTOR_BUFFER_SIZE = 1024 * 8;
+
+    @Autowired
+    private RedisTemplate redisTemplate;
+
+    @Autowired
+    private IHookRegisterService hookRegisterService;
+
+    @Autowired
+    private INFIDReaderService NFIDReaderService;
+
+    @Autowired
+    private IHookBindService hookBindService;
+
+    @Autowired
+    private INFIDReadRecordService NFIDReadRecordService;
+
+    @Autowired
+    private IPorkSideProduceService porkSideProduceService;
+
+    @PreDestroy
+    public void destroy()
+    {
+        disruptor.shutdown();
+        flushAllBuffers();
+    }
+
+    // 数据结构
+    //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 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);
+        }
+    }
+
+    /**
+     * 处理标签事件
+     */
+    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) {
+        //2025-05-008修改逻辑,产品需求吊钩绑定识别不直接添加绑定记录,改为先添加识别记录,在吊钩绑定页面收到选择识别记录
+        //生成新对象
+        List<NFIDReadRecord> recordList = records.stream()
+                .map(item -> {
+                    NFIDReadRecord record = new NFIDReadRecord();
+                    record.setEpcNo(item.tagId);
+                    record.setHookNo(hookRegisterService.selectHookNoByEpcNo(item.tagId));
+                    record.setDeviceSerial(item.readerId);
+                    record.setCreateTime(item.detectionTime);
+                    return record;
+                })
+                .collect(Collectors.toList());
+        NFIDReadRecordService.insertNFIDReadRecordBatch(recordList);
+    }
+
+    //白条称重
+    private void saveWeight(List<TagRecord> records) {
+        //生成新对象
+        List<PorkSideProduce> porkSideProduces = records.stream()
+                .map(item -> {
+                    PorkSideProduce porkSideProduce = new PorkSideProduce();
+                    porkSideProduce.setEpcNo(item.tagId);
+                    porkSideProduce.setHookNo(hookRegisterService.selectHookNoByEpcNo(item.tagId));
+                    porkSideProduce.setDeviceSerial(item.readerId);
+                    porkSideProduce.setProduceTime(item.detectionTime);
+                    porkSideProduce.setCreateTime(item.detectionTime);
+                    porkSideProduce.setProductName(PorkSideProduce.DEFAULT_NAME);
+
+                    if(!Objects.equals(porkSideProduce.getHookNo(), "")){
+                        //获取吊钩绑定关联信息
+                        HookBindDetailDTO hookBindDetail = hookBindService.selectHookBindDetail(porkSideProduce.getHookNo());
+                        porkSideProduce.setEntranceBatchId(hookBindDetail.getEntranceBatchId());
+                        porkSideProduce.setDistributeBatchId(hookBindDetail.getDistributeBatchId());
+                        porkSideProduce.setSlaughterCode(hookBindDetail.getSlaughterCode());
+                    }
+                    return porkSideProduce;
+                })
+                .collect(Collectors.toList());
+        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());
+        }
+    }
+}

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

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

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


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


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


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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

+ 72 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsCheckDeviceController.java

@@ -0,0 +1,72 @@
+package com.ruoyi.web.v2.v1.controller;
+
+
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.web.v2.v1.entity.JsCheckDevice;
+import com.ruoyi.web.v2.v1.entity.JsCheckProject;
+import com.ruoyi.web.v2.v1.service.IJsCheckDeviceService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+import static com.ruoyi.common.core.domain.AjaxResult.success;
+
+/**
+ * <p>
+ * v2.0设备档案管理 前端控制器
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-21
+ */
+@RestController
+@RequestMapping("/js-check-device")
+@Api("2.0设备档案管理")
+public class JsCheckDeviceController {
+
+    @Autowired
+    private IJsCheckDeviceService deviceService;
+
+    @ApiOperation("设备档案管理添加")
+    @PostMapping("/add")
+    public AjaxResult add(@RequestBody JsCheckDevice checkDevice){
+        return deviceService.add(checkDevice);
+    }
+
+    @ApiOperation("设备档案管理修改")
+    @PostMapping("/edit")
+    public AjaxResult edit(@RequestBody JsCheckDevice checkDevice){
+        return deviceService.edit(checkDevice);
+    }
+
+    @ApiOperation("设备档案管理删除")
+    @PostMapping("/delete")
+    public AjaxResult delete(@RequestBody Map<String, String> paramsMap) {
+        String ids = paramsMap.get("ids");
+        return deviceService.delete(ids);
+    }
+
+    @ApiOperation("设备档案管理列表")
+    @PostMapping("/list")
+    public AjaxResult listAll(){
+        return deviceService.listAll();
+    }
+
+    @ApiOperation("设备档案管理分页")
+    @GetMapping("/page")
+    public AjaxResult page(@RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize
+            , @RequestParam(value = "deviceNum", required = false) String deviceNum,
+                           @RequestParam(value = "deviceName", required = false) String deviceName) {
+        return deviceService.page(pageNum, pageSize, deviceNum,deviceName);
+    }
+
+    @ApiOperation("设备档案管理详情")
+    @PostMapping("/listById")
+    public AjaxResult listById(@RequestBody Map<String, String> paramsMap){
+        String id = paramsMap.get("id");
+        return success(deviceService.getById(id));
+    }
+}

+ 71 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsCheckInstrumentController.java

@@ -0,0 +1,71 @@
+package com.ruoyi.web.v2.v1.controller;
+
+
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.web.v2.v1.entity.JsCheckDevice;
+import com.ruoyi.web.v2.v1.entity.JsCheckInstrument;
+import com.ruoyi.web.v2.v1.service.IJsCheckInstrumentService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+import static com.ruoyi.common.core.domain.AjaxResult.success;
+
+/**
+ * <p>
+ * v2.0检验仪器管理 前端控制器
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-21
+ */
+@RestController
+@RequestMapping("/js-check-instrument")
+@Api("2.0检验仪器管理")
+public class JsCheckInstrumentController {
+
+    @Autowired
+    private IJsCheckInstrumentService instrumentService;
+    
+    @ApiOperation("检验仪器管理添加")
+    @PostMapping("/add")
+    public AjaxResult add(@RequestBody JsCheckInstrument checkDevice){
+        return instrumentService.add(checkDevice);
+    }
+
+    @ApiOperation("检验仪器管理修改")
+    @PostMapping("/edit")
+    public AjaxResult edit(@RequestBody JsCheckInstrument checkDevice){
+        return instrumentService.edit(checkDevice);
+    }
+
+    @ApiOperation("检验仪器管理删除")
+    @PostMapping("/delete")
+    public AjaxResult delete(@RequestBody Map<String, String> paramsMap) {
+        String ids = paramsMap.get("ids");
+        return instrumentService.delete(ids);
+    }
+
+    @ApiOperation("检验仪器管理列表")
+    @PostMapping("/list")
+    public AjaxResult listAll(){
+        return instrumentService.listAll();
+    }
+
+    @ApiOperation("检验仪器管理分页")
+    @GetMapping("/page")
+    public AjaxResult page(@RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize
+            , @RequestParam(value = "deviceNum", required = false) String deviceNum,
+                           @RequestParam(value = "deviceName", required = false) String deviceName) {
+        return instrumentService.page(pageNum, pageSize, deviceNum,deviceName);
+    }
+    @ApiOperation("检验仪器管理详情")
+    @PostMapping("/listById")
+    public AjaxResult listById(@RequestBody Map<String, String> paramsMap){
+        String id = paramsMap.get("id");
+        return success(instrumentService.getById(id));
+    }
+}

+ 71 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsCheckProjectController.java

@@ -0,0 +1,71 @@
+package com.ruoyi.web.v2.v1.controller;
+
+
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.web.v2.v1.entity.JsCheckProject;
+import com.ruoyi.web.v2.v1.entity.JsDisinfectManage;
+import com.ruoyi.web.v2.v1.service.IJsCheckProjectService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+import static com.ruoyi.common.core.domain.AjaxResult.success;
+
+/**
+ * <p>
+ * 2.0检验项目管理 前端控制器
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-20
+ */
+@RestController
+@RequestMapping("/js-check-project")
+@Api("2.0检验项目管理")
+public class JsCheckProjectController {
+
+    @Autowired
+    private IJsCheckProjectService projectService;
+
+    @ApiOperation("检验项目管理添加")
+    @PostMapping("/add")
+    public AjaxResult add(@RequestBody JsCheckProject checkProject){
+        return projectService.add(checkProject);
+    }
+
+    @ApiOperation("检验项目管理修改")
+    @PostMapping("/edit")
+    public AjaxResult edit(@RequestBody JsCheckProject checkProject){
+        return projectService.edit(checkProject);
+    }
+
+    @ApiOperation("检验项目管理删除")
+    @PostMapping("/delete")
+    public AjaxResult delete(@RequestBody Map<String, String> paramsMap) {
+        String ids = paramsMap.get("ids");
+        return projectService.delete(ids);
+    }
+
+    @ApiOperation("检验项目管理列表")
+    @PostMapping("/list")
+    public AjaxResult listAll(){
+        return projectService.listAll();
+    }
+
+    @ApiOperation("检验项目管理分页")
+    @GetMapping("/page")
+    public AjaxResult page(@RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize
+            , @RequestParam(value = "projectName", required = false) String projectName) {
+        return projectService.page(pageNum, pageSize, projectName);
+    }
+
+    @ApiOperation("检验项目管理详情")
+    @PostMapping("/listById")
+    public AjaxResult listById(@RequestBody Map<String, String> paramsMap){
+        String id = paramsMap.get("id");
+        return success(projectService.getById(id));
+    }
+}

+ 76 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsDeviceMaintenanceController.java

@@ -0,0 +1,76 @@
+package com.ruoyi.web.v2.v1.controller;
+
+
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.web.v2.v1.entity.JsDeviceMaintenance;
+import com.ruoyi.web.v2.v1.entity.JsProduceCheck;
+import com.ruoyi.web.v2.v1.service.IJsDeviceMaintenanceService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+import static com.ruoyi.common.core.domain.AjaxResult.success;
+
+/**
+ * <p>
+ * v2.0设备维护登记 前端控制器
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-23
+ */
+@RestController
+@RequestMapping("/js-device-maintenance")
+@Api("2.0设备维护登记")
+public class JsDeviceMaintenanceController {
+
+    @Autowired
+    private IJsDeviceMaintenanceService deviceMaintenanceService;
+
+
+    @ApiOperation("设备维护登记添加")
+    @PostMapping("/add")
+    public AjaxResult add(@RequestBody JsDeviceMaintenance deviceMaintenance) {
+        return deviceMaintenanceService.add(deviceMaintenance);
+    }
+
+    @ApiOperation("设备维护登记修改")
+    @PostMapping("/edit")
+    public AjaxResult edit(@RequestBody JsDeviceMaintenance deviceMaintenance) {
+        return deviceMaintenanceService.edit(deviceMaintenance);
+    }
+
+    @ApiOperation("设备维护登记删除")
+    @PostMapping("/delete")
+    public AjaxResult delete(@RequestBody Map<String, String> paramsMap) {
+        String ids = paramsMap.get("ids");
+        return deviceMaintenanceService.delete(ids);
+    }
+
+    @ApiOperation("设备维护登记列表")
+    @PostMapping("/list")
+    public AjaxResult listAll() {
+        return deviceMaintenanceService.listAll();
+    }
+
+    @ApiOperation("设备维护登记分页")
+    @GetMapping("/page")
+    public AjaxResult page(@RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize
+            , @RequestParam(value = "startTime", required = false) String startTime
+            , @RequestParam(value = "endTime", required = false) String endTime
+            , @RequestParam(value = "deviceNum", required = false) String deviceNum
+            , @RequestParam(value = "deviceName", required = false) String deviceName) {
+
+        return deviceMaintenanceService.page(pageNum, pageSize, startTime, endTime, deviceNum,deviceName);
+    }
+
+    @ApiOperation("设备维护登记详情")
+    @PostMapping("/listById")
+    public AjaxResult listById(@RequestBody Map<String, String> paramsMap) {
+        String id = paramsMap.get("id");
+        return success(deviceMaintenanceService.getById(id));
+    }
+}

+ 72 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsDisinfectController.java

@@ -0,0 +1,72 @@
+package com.ruoyi.web.v2.v1.controller;
+
+
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.web.v2.v1.entity.JsCheckInstrument;
+import com.ruoyi.web.v2.v1.entity.JsDisinfect;
+import com.ruoyi.web.v2.v1.service.IJsDisinfectService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+import static com.ruoyi.common.core.domain.AjaxResult.success;
+
+/**
+ * <p>
+ * v2.0消毒登记 前端控制器
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-22
+ */
+@RestController
+@RequestMapping("/js-disinfect")
+@Api("2.0消毒登记")
+public class JsDisinfectController {
+
+    @Autowired
+    private IJsDisinfectService disinfectService;
+
+    @ApiOperation("消毒登记管理添加")
+    @PostMapping("/add")
+    public AjaxResult add(@RequestBody JsDisinfect disinfect){
+        return disinfectService.add(disinfect);
+    }
+
+    @ApiOperation("消毒登记管理修改")
+    @PostMapping("/edit")
+    public AjaxResult edit(@RequestBody JsDisinfect disinfect){
+        return disinfectService.edit(disinfect);
+    }
+
+    @ApiOperation("消毒登记管理删除")
+    @PostMapping("/delete")
+    public AjaxResult delete(@RequestBody Map<String, String> paramsMap) {
+        String ids = paramsMap.get("ids");
+        return disinfectService.delete(ids);
+    }
+
+    @ApiOperation("消毒登记管理列表")
+    @PostMapping("/list")
+    public AjaxResult listAll(){
+        return disinfectService.listAll();
+    }
+
+    @ApiOperation("消毒登记管理分页")
+    @GetMapping("/page")
+    public AjaxResult page(@RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize
+            , @RequestParam(value = "startTime", required = false) String startTime
+            , @RequestParam(value = "endTime", required = false) String endTime,
+                           @RequestParam(value = "disinfectLocation", required = false) String disinfectLocation) {
+        return disinfectService.page(pageNum, pageSize, startTime,endTime,disinfectLocation);
+    }
+    @ApiOperation("消毒登记管理详情")
+    @PostMapping("/listById")
+    public AjaxResult listById(@RequestBody Map<String, String> paramsMap){
+        String id = paramsMap.get("id");
+        return success(disinfectService.getById(id));
+    }
+}

+ 71 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsDisinfectManageController.java

@@ -0,0 +1,71 @@
+package com.ruoyi.web.v2.v1.controller;
+
+
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.web.v2.v1.entity.JsDisinfectManage;
+import com.ruoyi.web.v2.v1.service.IJsDisinfectManageService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+import static com.ruoyi.common.core.domain.AjaxResult.success;
+
+/**
+ * <p>
+ * 2.0消毒方式管理 前端控制器
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-20
+ */
+@RestController
+@RequestMapping("/js-disinfect-manage")
+@Api("2.0消毒方式管理")
+public class JsDisinfectManageController extends BaseController {
+
+    @Autowired
+    private IJsDisinfectManageService disinfectManageService;
+
+    @ApiOperation("消毒方式管理添加")
+    @PostMapping("/add")
+    public AjaxResult add(@RequestBody JsDisinfectManage jsDisinfectManage){
+        return disinfectManageService.add(jsDisinfectManage);
+    }
+
+    @ApiOperation("消毒方式管理修改")
+    @PostMapping("/edit")
+    public AjaxResult edit(@RequestBody JsDisinfectManage jsDisinfectManage){
+        return disinfectManageService.edit(jsDisinfectManage);
+    }
+
+    @ApiOperation("消毒方式管理删除")
+    @PostMapping("/delete")
+    public AjaxResult delete(@RequestBody Map<String, String> paramsMap) {
+        String ids = paramsMap.get("ids");
+        return disinfectManageService.delete(ids);
+    }
+
+    @ApiOperation("消毒方式管理列表")
+    @PostMapping("/list")
+    public AjaxResult listAll(){
+        return disinfectManageService.listAll();
+    }
+
+    @ApiOperation("消毒方式管理分页")
+    @GetMapping("/page")
+    public AjaxResult page(@RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize
+            , @RequestParam(value = "disinfectMethod", required = false) String disinfectMethod) {
+        return disinfectManageService.page(pageNum, pageSize, disinfectMethod);
+    }
+    @ApiOperation("消毒方式管理详情")
+    @PostMapping("/listById")
+    public AjaxResult listById(@RequestBody Map<String, String> paramsMap){
+        String id = paramsMap.get("id");
+        return success(disinfectManageService.getById(id));
+    }
+}

+ 77 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsDistributionController.java

@@ -0,0 +1,77 @@
+package com.ruoyi.web.v2.v1.controller;
+
+
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.web.v2.v1.entity.JsDeviceMaintenance;
+import com.ruoyi.web.v2.v1.entity.JsDistribution;
+import com.ruoyi.web.v2.v1.service.IJsDistributionService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+import static com.ruoyi.common.core.domain.AjaxResult.success;
+
+/**
+ * <p>
+ * v2.0分销登记 前端控制器
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-26
+ */
+@RestController
+@RequestMapping("/js-distribution")
+@Api("2.0分销登记")
+public class JsDistributionController {
+
+    @Autowired
+    private IJsDistributionService distributionService;
+
+    @ApiOperation("分销登记添加")
+    @PostMapping("/add")
+    public AjaxResult add(@RequestBody JsDistribution distribution) {
+        return distributionService.add(distribution);
+    }
+
+    @ApiOperation("分销登记修改")
+    @PostMapping("/edit")
+    public AjaxResult edit(@RequestBody JsDistribution distribution) {
+        return distributionService.edit(distribution);
+    }
+
+    @ApiOperation("分销登记删除")
+    @PostMapping("/delete")
+    public AjaxResult delete(@RequestBody Map<String, String> paramsMap) {
+        String ids = paramsMap.get("ids");
+        return distributionService.delete(ids);
+    }
+
+    @ApiOperation("分销登记列表")
+    @PostMapping("/list")
+    public AjaxResult listAll() {
+        return distributionService.listAll();
+    }
+
+    @ApiOperation("分销登记分页")
+    @GetMapping("/page")
+    public AjaxResult page(@RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize
+            , @RequestParam(value = "startTime", required = false) String startTime
+            , @RequestParam(value = "endTime", required = false) String endTime
+            , @RequestParam(value = "supplierId", required = false) Integer supplierId
+            , @RequestParam(value = "purchaserId", required = false) Integer purchaserId
+            , @RequestParam(value = "animalCertNo", required = false) Integer animalCertNo) {
+
+        return distributionService.page(pageNum, pageSize, startTime, endTime,supplierId,purchaserId,animalCertNo);
+    }
+
+    @ApiOperation("分销登记详情")
+    @PostMapping("/listById")
+    public AjaxResult listById(@RequestBody Map<String, String> paramsMap) {
+        String id = paramsMap.get("id");
+        return success(distributionService.getById(id));
+    }
+
+}

+ 74 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsDivideCircleController.java

@@ -0,0 +1,74 @@
+package com.ruoyi.web.v2.v1.controller;
+
+
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.web.v2.v1.entity.JsCheckInstrument;
+import com.ruoyi.web.v2.v1.entity.JsDivideCircle;
+import com.ruoyi.web.v2.v1.service.IJsDivideCircleService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+import static com.ruoyi.common.core.domain.AjaxResult.success;
+
+/**
+ * <p>
+ * v2.0分圈登记 前端控制器
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-22
+ */
+@RestController
+@RequestMapping("/js-divide-circle")
+@Api("2.0分圈登记")
+public class JsDivideCircleController {
+
+    @Autowired
+    private IJsDivideCircleService divideCircleService;
+
+    @ApiOperation("分圈登记添加")
+    @PostMapping("/add")
+    public AjaxResult add(@RequestBody JsDivideCircle divideCircle) {
+        return divideCircleService.add(divideCircle);
+    }
+
+    @ApiOperation("分圈登记修改")
+    @PostMapping("/edit")
+    public AjaxResult edit(@RequestBody JsDivideCircle divideCircle) {
+        return divideCircleService.edit(divideCircle);
+    }
+
+    @ApiOperation("分圈登记删除")
+    @PostMapping("/delete")
+    public AjaxResult delete(@RequestBody Map<String, String> paramsMap) {
+        String ids = paramsMap.get("ids");
+        return divideCircleService.delete(ids);
+    }
+
+    @ApiOperation("分圈登记列表")
+    @PostMapping("/list")
+    public AjaxResult listAll() {
+        return divideCircleService.listAll();
+    }
+
+    @ApiOperation("分圈登记分页")
+    @GetMapping("/page")
+    public AjaxResult page(@RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize
+            , @RequestParam(value = "startTime", required = false) String startTime
+            , @RequestParam(value = "endTime", required = false) String endTime
+            , @RequestParam(value = "pigpenName", required = false) String pigpenName) {
+
+        return divideCircleService.page(pageNum, pageSize, startTime, endTime, pigpenName);
+    }
+
+    @ApiOperation("分圈登记详情")
+    @PostMapping("/listById")
+    public AjaxResult listById(@RequestBody Map<String, String> paramsMap) {
+        String id = paramsMap.get("id");
+        return success(divideCircleService.getById(id));
+    }
+}

+ 75 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsDrugCheckController.java

@@ -0,0 +1,75 @@
+package com.ruoyi.web.v2.v1.controller;
+
+
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.web.v2.v1.entity.JsDivideCircle;
+import com.ruoyi.web.v2.v1.entity.JsDrugCheck;
+import com.ruoyi.web.v2.v1.service.IJsDrugCheckService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+import static com.ruoyi.common.core.domain.AjaxResult.success;
+
+/**
+ * <p>
+ * v2.0违禁药物登记 前端控制器
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-22
+ */
+@RestController
+@RequestMapping("/js-drug-check")
+@Api("2.0违禁药物登记")
+public class JsDrugCheckController {
+
+    @Autowired
+    private IJsDrugCheckService drugCheckService;
+
+
+    @ApiOperation("违禁药物登记添加")
+    @PostMapping("/add")
+    public AjaxResult add(@RequestBody JsDrugCheck drugCheck) {
+        return drugCheckService.add(drugCheck);
+    }
+
+    @ApiOperation("违禁药物登记修改")
+    @PostMapping("/edit")
+    public AjaxResult edit(@RequestBody JsDrugCheck drugCheck) {
+        return drugCheckService.edit(drugCheck);
+    }
+
+    @ApiOperation("违禁药物登记删除")
+    @PostMapping("/delete")
+    public AjaxResult delete(@RequestBody Map<String, String> paramsMap) {
+        String ids = paramsMap.get("ids");
+        return drugCheckService.delete(ids);
+    }
+
+    @ApiOperation("违禁药物登记列表")
+    @PostMapping("/list")
+    public AjaxResult listAll() {
+        return drugCheckService.listAll();
+    }
+
+    @ApiOperation("违禁药物登记分页")
+    @GetMapping("/page")
+    public AjaxResult page(@RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize
+            , @RequestParam(value = "startTime", required = false) String startTime
+            , @RequestParam(value = "endTime", required = false) String endTime
+            , @RequestParam(value = "animalCertNo", required = false) String animalCertNo) {
+
+        return drugCheckService.page(pageNum, pageSize, startTime, endTime, animalCertNo);
+    }
+
+    @ApiOperation("违禁药物登记详情")
+    @PostMapping("/listById")
+    public AjaxResult listById(@RequestBody Map<String, String> paramsMap) {
+        String id = paramsMap.get("id");
+        return success(drugCheckService.getById(id));
+    }
+}

+ 92 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsDrugController.java

@@ -0,0 +1,92 @@
+package com.ruoyi.web.v2.v1.controller;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.web.v2.v1.entity.JsCheckProject;
+import com.ruoyi.web.v2.v1.entity.JsDrug;
+import com.ruoyi.web.v2.v1.service.IJsDrugService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+import static com.ruoyi.common.core.domain.AjaxResult.error;
+import static com.ruoyi.common.core.domain.AjaxResult.success;
+
+/**
+ * <p>
+ * v2.0违禁药物名称 前端控制器
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-21
+ */
+@RestController
+@RequestMapping("/js-drug")
+@Api("2.0违禁药物名称")
+public class JsDrugController {
+
+    @Autowired
+    private IJsDrugService drugService;
+
+    @ApiOperation("违禁药物管理添加")
+    @PostMapping("/add")
+    public AjaxResult add(@RequestBody JsDrug jsDrug){
+        int i = drugService.count(new QueryWrapper<JsDrug>().eq("drug_name", jsDrug.getDrugName()));
+        if (i != 0) {
+            return error("该违禁药物已存在");
+        }
+        drugService.save(jsDrug);
+        return success();
+    }
+
+    @ApiOperation("违禁药物管理修改")
+    @PostMapping("/edit")
+    public AjaxResult edit(@RequestBody JsDrug jsDrug){
+        int i = drugService.count(new QueryWrapper<JsDrug>().eq("drug_name", jsDrug.getDrugName()).ne("id",jsDrug.getId()));
+        if (i != 0) {
+            return error("该违禁药物已存在");
+        }
+        drugService.updateById(jsDrug);
+        return success();
+    }
+
+    @ApiOperation("违禁药物管理删除")
+    @PostMapping("/delete")
+    public AjaxResult delete(@RequestBody Map<String, String> paramsMap) {
+        String ids = paramsMap.get("ids");
+        String[] split = ids.split(",");
+        for (String s : split) {
+            drugService.removeById(s);
+        }
+        return success();
+    }
+
+    @ApiOperation("违禁药物管理列表")
+    @PostMapping("/list")
+    public AjaxResult listAll(){
+        return success(drugService.list());
+    }
+
+    @ApiOperation("违禁药物管理分页")
+    @GetMapping("/page")
+    public AjaxResult page(@RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize
+            , @RequestParam(value = "drugName", required = false) String drugName) {
+        Page<JsDrug> page = new Page<>(pageNum, pageSize);
+        QueryWrapper<JsDrug> queryWrapper = new QueryWrapper<>();
+        queryWrapper.like(StringUtils.isNotEmpty(drugName), "drug_name", drugName);
+        return success(drugService.page(page, queryWrapper));
+    }
+
+    @ApiOperation("违禁药物管理详情")
+    @PostMapping("/listById")
+    public AjaxResult listById(@RequestBody Map<String, String> paramsMap){
+        String id = paramsMap.get("id");
+        return success(drugService.getById(id));
+    }
+}

+ 76 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsInStockController.java

@@ -0,0 +1,76 @@
+package com.ruoyi.web.v2.v1.controller;
+
+
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.web.v2.v1.entity.JsDeviceMaintenance;
+import com.ruoyi.web.v2.v1.entity.JsInStock;
+import com.ruoyi.web.v2.v1.service.IJsInStockService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+import static com.ruoyi.common.core.domain.AjaxResult.success;
+
+/**
+ * <p>
+ * v2.0物料入库 前端控制器
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-23
+ */
+@RestController
+@RequestMapping("/js-in-stock")
+@Api("2.0物料入库")
+public class JsInStockController {
+
+    @Autowired
+    private IJsInStockService inStockService;
+
+    @ApiOperation("物料入库添加")
+    @PostMapping("/add")
+    public AjaxResult add(@RequestBody JsInStock inStock) {
+        return inStockService.add(inStock);
+    }
+
+    @ApiOperation("物料入库修改")
+    @PostMapping("/edit")
+    public AjaxResult edit(@RequestBody JsInStock inStock) {
+        return inStockService.edit(inStock);
+    }
+
+//    @ApiOperation("物料入库删除")
+//    @PostMapping("/delete")
+//    public AjaxResult delete(@RequestBody Map<String, String> paramsMap) {
+//        String ids = paramsMap.get("ids");
+//        return inStockService.delete(ids);
+//    }
+
+    @ApiOperation("物料入库列表")
+    @PostMapping("/list")
+    public AjaxResult listAll() {
+        return inStockService.listAll();
+    }
+
+    @ApiOperation("物料入库分页")
+    @GetMapping("/page")
+    public AjaxResult page(@RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize
+            , @RequestParam(value = "startTime", required = false) String startTime
+            , @RequestParam(value = "endTime", required = false) String endTime
+            , @RequestParam(value = "materialBatch", required = false) String materialBatch
+            , @RequestParam(value = "materialName", required = false) String materialName
+            , @RequestParam(value = "materialType", required = false) Integer materialType) {
+
+        return inStockService.page(pageNum, pageSize, startTime, endTime, materialBatch,materialName,materialType);
+    }
+
+    @ApiOperation("物料入库详情")
+    @PostMapping("/listById")
+    public AjaxResult listById(@RequestBody Map<String, String> paramsMap) {
+        String id = paramsMap.get("id");
+        return success(inStockService.getById(id));
+    }
+}

+ 76 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsInstrumentMaintenanceController.java

@@ -0,0 +1,76 @@
+package com.ruoyi.web.v2.v1.controller;
+
+
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.web.v2.v1.entity.JsDeviceMaintenance;
+import com.ruoyi.web.v2.v1.entity.JsInstrumentMaintenance;
+import com.ruoyi.web.v2.v1.service.IJsInstrumentMaintenanceService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+import static com.ruoyi.common.core.domain.AjaxResult.success;
+
+/**
+ * <p>
+ * v2.0检验仪器维护登记 前端控制器
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-23
+ */
+@RestController
+@RequestMapping("/js-instrument-maintenance")
+@Api("2.0检验仪器维护登记")
+public class JsInstrumentMaintenanceController {
+
+    @Autowired
+    private IJsInstrumentMaintenanceService maintenanceService;
+
+
+    @ApiOperation("检验仪器维护登记添加")
+    @PostMapping("/add")
+    public AjaxResult add(@RequestBody JsInstrumentMaintenance deviceMaintenance) {
+        return maintenanceService.add(deviceMaintenance);
+    }
+
+    @ApiOperation("检验仪器维护登记修改")
+    @PostMapping("/edit")
+    public AjaxResult edit(@RequestBody JsInstrumentMaintenance deviceMaintenance) {
+        return maintenanceService.edit(deviceMaintenance);
+    }
+
+    @ApiOperation("检验仪器维护登记删除")
+    @PostMapping("/delete")
+    public AjaxResult delete(@RequestBody Map<String, String> paramsMap) {
+        String ids = paramsMap.get("ids");
+        return maintenanceService.delete(ids);
+    }
+
+    @ApiOperation("检验仪器维护登记列表")
+    @PostMapping("/list")
+    public AjaxResult listAll() {
+        return maintenanceService.listAll();
+    }
+
+    @ApiOperation("检验仪器维护登记分页")
+    @GetMapping("/page")
+    public AjaxResult page(@RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize
+            , @RequestParam(value = "startTime", required = false) String startTime
+            , @RequestParam(value = "endTime", required = false) String endTime
+            , @RequestParam(value = "deviceNum", required = false) String deviceNum
+            , @RequestParam(value = "deviceName", required = false) String deviceName) {
+
+        return maintenanceService.page(pageNum, pageSize, startTime, endTime, deviceNum,deviceName);
+    }
+
+    @ApiOperation("检验仪器维护登记详情")
+    @PostMapping("/listById")
+    public AjaxResult listById(@RequestBody Map<String, String> paramsMap) {
+        String id = paramsMap.get("id");
+        return success(maintenanceService.getById(id));
+    }
+}

+ 73 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsMaterialController.java

@@ -0,0 +1,73 @@
+package com.ruoyi.web.v2.v1.controller;
+
+
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.web.v2.v1.entity.JsMaterial;
+import com.ruoyi.web.v2.v1.entity.JsWorkshop;
+import com.ruoyi.web.v2.v1.service.IJsMaterialService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.models.auth.In;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+import static com.ruoyi.common.core.domain.AjaxResult.success;
+
+/**
+ * <p>
+ * v2.0物料管理 前端控制器
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-21
+ */
+@RestController
+@RequestMapping("/js-material")
+@Api("2.0物料管理")
+public class JsMaterialController {
+
+    @Autowired
+    private IJsMaterialService materialService;
+
+    @ApiOperation("物料管理添加")
+    @PostMapping("/add")
+    public AjaxResult add(@RequestBody JsMaterial material){
+        return materialService.add(material);
+    }
+
+    @ApiOperation("物料管理修改")
+    @PostMapping("/edit")
+    public AjaxResult edit(@RequestBody JsMaterial material){
+        return materialService.edit(material);
+    }
+
+    @ApiOperation("物料管理删除")
+    @PostMapping("/delete")
+    public AjaxResult delete(@RequestBody Map<String, String> paramsMap) {
+        String ids = paramsMap.get("ids");
+        return materialService.delete(ids);
+    }
+
+    @ApiOperation("物料管理列表")
+    @PostMapping("/list")
+    public AjaxResult listAll(){
+        return materialService.listAll();
+    }
+
+    @ApiOperation("物料管理分页")
+    @GetMapping("/page")
+    public AjaxResult page(@RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize
+            , @RequestParam(value = "materialName", required = false) String materialName
+            ,@RequestParam(value = "materialType", required = false) Integer materialType) {
+        return materialService.page(pageNum, pageSize, materialName,materialType);
+    }
+
+    @ApiOperation("物料管理详情")
+    @PostMapping("/listById")
+    public AjaxResult listById(@RequestBody Map<String, String> paramsMap){
+        String id = paramsMap.get("id");
+        return success(materialService.getById(id));
+    }
+}

+ 74 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsOtherProduceController.java

@@ -0,0 +1,74 @@
+package com.ruoyi.web.v2.v1.controller;
+
+
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.web.v2.v1.entity.JsDistribution;
+import com.ruoyi.web.v2.v1.entity.JsOtherProduce;
+import com.ruoyi.web.v2.v1.service.IJsOtherProduceService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+import static com.ruoyi.common.core.domain.AjaxResult.success;
+
+/**
+ * <p>
+ * v2.0其他产品记录 前端控制器
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-26
+ */
+@RestController
+@RequestMapping("/js-other-produce")
+@Api("2.0其他产品记录")
+public class JsOtherProduceController {
+
+    @Autowired
+    private IJsOtherProduceService otherProduceService;
+
+    @ApiOperation("其他产品记录添加")
+    @PostMapping("/add")
+    public AjaxResult add(@RequestBody JsOtherProduce otherProduce) {
+        return otherProduceService.add(otherProduce);
+    }
+
+    @ApiOperation("其他产品记录修改")
+    @PostMapping("/edit")
+    public AjaxResult edit(@RequestBody JsOtherProduce otherProduce) {
+        return otherProduceService.edit(otherProduce);
+    }
+
+    @ApiOperation("其他产品记录删除")
+    @PostMapping("/delete")
+    public AjaxResult delete(@RequestBody Map<String, String> paramsMap) {
+        String ids = paramsMap.get("ids");
+        return otherProduceService.delete(ids);
+    }
+
+    @ApiOperation("其他产品记录列表")
+    @PostMapping("/list")
+    public AjaxResult listAll() {
+        return otherProduceService.listAll();
+    }
+
+    @ApiOperation("其他产品记录分页")
+    @GetMapping("/page")
+    public AjaxResult page(@RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize
+            , @RequestParam(value = "startTime", required = false) String startTime
+            , @RequestParam(value = "endTime", required = false) String endTime
+            , @RequestParam(value = "produceName", required = false) String produceName) {
+        return otherProduceService.page(pageNum, pageSize, startTime, endTime,produceName);
+    }
+
+    @ApiOperation("其他产品记录详情")
+    @PostMapping("/listById")
+    public AjaxResult listById(@RequestBody Map<String, String> paramsMap) {
+        String id = paramsMap.get("id");
+        return success(otherProduceService.getById(id));
+    }
+
+}

+ 76 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsOutStockController.java

@@ -0,0 +1,76 @@
+package com.ruoyi.web.v2.v1.controller;
+
+
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.web.v2.v1.entity.JsInStock;
+import com.ruoyi.web.v2.v1.entity.JsOutStock;
+import com.ruoyi.web.v2.v1.service.IJsOutStockService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+import static com.ruoyi.common.core.domain.AjaxResult.success;
+
+/**
+ * <p>
+ * v2.0物料领用 前端控制器
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-23
+ */
+@RestController
+@RequestMapping("/js-out-stock")
+@Api("2.0物料领用")
+public class JsOutStockController {
+
+    @Autowired
+    private IJsOutStockService outStockService;
+
+    @ApiOperation("物料领用添加")
+    @PostMapping("/add")
+    public AjaxResult add(@RequestBody JsOutStock outStock) {
+        return outStockService.add(outStock);
+    }
+
+    @ApiOperation("物料领用修改")
+    @PostMapping("/edit")
+    public AjaxResult edit(@RequestBody JsOutStock outStock) {
+        return outStockService.edit(outStock);
+    }
+
+//    @ApiOperation("物料领用删除")
+//    @PostMapping("/delete")
+//    public AjaxResult delete(@RequestBody Map<String, String> paramsMap) {
+//        String ids = paramsMap.get("ids");
+//        return outStockService.delete(ids);
+//    }
+
+    @ApiOperation("物料领用列表")
+    @PostMapping("/list")
+    public AjaxResult listAll() {
+        return outStockService.listAll();
+    }
+
+    @ApiOperation("物料领用分页")
+    @GetMapping("/page")
+    public AjaxResult page(@RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize
+            , @RequestParam(value = "startTime", required = false) String startTime
+            , @RequestParam(value = "endTime", required = false) String endTime
+            , @RequestParam(value = "materialBatch", required = false) String materialBatch
+            , @RequestParam(value = "materialName", required = false) String materialName
+            , @RequestParam(value = "materialType", required = false) Integer materialType) {
+
+        return outStockService.page(pageNum, pageSize, startTime, endTime, materialBatch,materialName,materialType);
+    }
+
+    @ApiOperation("物料领用详情")
+    @PostMapping("/listById")
+    public AjaxResult listById(@RequestBody Map<String, String> paramsMap) {
+        String id = paramsMap.get("id");
+        return success(outStockService.getById(id));
+    }
+}

+ 20 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsPatrolController.java

@@ -0,0 +1,20 @@
+package com.ruoyi.web.v2.v1.controller;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ * v2.0质量巡查 前端控制器
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-26
+ */
+@RestController
+@RequestMapping("/js-patrol")
+public class JsPatrolController {
+
+}

+ 75 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsProduceCheckController.java

@@ -0,0 +1,75 @@
+package com.ruoyi.web.v2.v1.controller;
+
+
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.web.v2.v1.entity.JsDrugCheck;
+import com.ruoyi.web.v2.v1.entity.JsProduceCheck;
+import com.ruoyi.web.v2.v1.service.IJsProduceCheckService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+import static com.ruoyi.common.core.domain.AjaxResult.success;
+
+/**
+ * <p>
+ * v2.0生产检验检疫登记 前端控制器
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-23
+ */
+@RestController
+@RequestMapping("/js-produce-check")
+@Api("2.0生产检验检疫登记")
+public class JsProduceCheckController {
+
+    @Autowired
+    private IJsProduceCheckService produceCheckService;
+
+
+    @ApiOperation("生产检验检疫登记添加")
+    @PostMapping("/add")
+    public AjaxResult add(@RequestBody JsProduceCheck produceCheck) {
+        return produceCheckService.add(produceCheck);
+    }
+
+    @ApiOperation("生产检验检疫登记修改")
+    @PostMapping("/edit")
+    public AjaxResult edit(@RequestBody JsProduceCheck produceCheck) {
+        return produceCheckService.edit(produceCheck);
+    }
+
+    @ApiOperation("生产检验检疫登记删除")
+    @PostMapping("/delete")
+    public AjaxResult delete(@RequestBody Map<String, String> paramsMap) {
+        String ids = paramsMap.get("ids");
+        return produceCheckService.delete(ids);
+    }
+
+    @ApiOperation("生产检验检疫登记列表")
+    @PostMapping("/list")
+    public AjaxResult listAll() {
+        return produceCheckService.listAll();
+    }
+
+    @ApiOperation("生产检验检疫登记分页")
+    @GetMapping("/page")
+    public AjaxResult page(@RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize
+            , @RequestParam(value = "startTime", required = false) String startTime
+            , @RequestParam(value = "endTime", required = false) String endTime
+            , @RequestParam(value = "animalCertNo", required = false) String animalCertNo) {
+
+        return produceCheckService.page(pageNum, pageSize, startTime, endTime, animalCertNo);
+    }
+
+    @ApiOperation("生产检验检疫登记详情")
+    @PostMapping("/listById")
+    public AjaxResult listById(@RequestBody Map<String, String> paramsMap) {
+        String id = paramsMap.get("id");
+        return success(produceCheckService.getById(id));
+    }
+}

+ 74 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsProduceRecallController.java

@@ -0,0 +1,74 @@
+package com.ruoyi.web.v2.v1.controller;
+
+
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.web.v2.v1.entity.JsOtherProduce;
+import com.ruoyi.web.v2.v1.entity.JsProduceRecall;
+import com.ruoyi.web.v2.v1.service.IJsProduceRecallService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+import static com.ruoyi.common.core.domain.AjaxResult.success;
+
+/**
+ * <p>
+ * v2.0产品召回 前端控制器
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-26
+ */
+@RestController
+@RequestMapping("/js-produce-recall")
+@Api("2.0产品召回")
+public class JsProduceRecallController {
+
+    @Autowired
+    private IJsProduceRecallService recallService;
+
+    @ApiOperation("产品召回添加")
+    @PostMapping("/add")
+    public AjaxResult add(@RequestBody JsProduceRecall produceRecall) {
+        return recallService.add(produceRecall);
+    }
+
+    @ApiOperation("产品召回修改")
+    @PostMapping("/edit")
+    public AjaxResult edit(@RequestBody JsProduceRecall produceRecall) {
+        return recallService.edit(produceRecall);
+    }
+
+    @ApiOperation("产品召回删除")
+    @PostMapping("/delete")
+    public AjaxResult delete(@RequestBody Map<String, String> paramsMap) {
+        String ids = paramsMap.get("ids");
+        return recallService.delete(ids);
+    }
+
+    @ApiOperation("产品召回列表")
+    @PostMapping("/list")
+    public AjaxResult listAll() {
+        return recallService.listAll();
+    }
+
+    @ApiOperation("产品召回分页")
+    @GetMapping("/page")
+    public AjaxResult page(@RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize
+            , @RequestParam(value = "startTime", required = false) String startTime
+            , @RequestParam(value = "endTime", required = false) String endTime
+            , @RequestParam(value = "produceName", required = false) String produceName) {
+        return recallService.page(pageNum, pageSize, startTime, endTime,produceName);
+    }
+
+    @ApiOperation("产品召回详情")
+    @PostMapping("/listById")
+    public AjaxResult listById(@RequestBody Map<String, String> paramsMap) {
+        String id = paramsMap.get("id");
+        return success(recallService.getById(id));
+    }
+
+}

+ 113 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsRestInspectionController.java

@@ -0,0 +1,113 @@
+package com.ruoyi.web.v2.v1.controller;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.web.v2.v1.entity.JsDivideCircle;
+import com.ruoyi.web.v2.v1.entity.JsRestInspection;
+import com.ruoyi.web.v2.v1.service.IJsRestInspectionService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.models.auth.In;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.util.Map;
+
+import static com.ruoyi.common.core.domain.AjaxResult.success;
+
+/**
+ * <p>
+ * v2.0静养巡查登记 前端控制器
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-22
+ */
+@RestController
+@RequestMapping("/js-rest-inspection")
+@Api("2.0静养巡查登记")
+public class JsRestInspectionController {
+
+    @Autowired
+    private IJsRestInspectionService inspectionService;
+/*
+    @ApiOperation("静养巡查添加")
+    @PostMapping("/add")
+    public AjaxResult add(@RequestParam(value = "restInspectionTime") String restInspectionTime
+            , @RequestParam(value = "pigpenName") String pigpenName, @RequestParam(value = "files") MultipartFile files
+            , @RequestParam(value = "restInspectionContent") String restInspectionContent
+            , @RequestParam(value = "handle") String handle
+            , @RequestParam(value = "dealAmount") Integer dealAmount, @RequestParam(value = "userName") String userName
+            , @RequestParam(value = "divideCircleId") Integer divideCircleId) throws IOException {
+        return inspectionService.add(restInspectionTime, pigpenName, files, restInspectionContent, handle, dealAmount, userName, divideCircleId);
+    }
+
+    @ApiOperation("静养巡查修改")
+    @PostMapping("/edit")
+    public AjaxResult edit(@RequestParam(value = "restInspectionTime") String restInspectionTime
+            , @RequestParam(value = "files") MultipartFile files
+            , @RequestParam(value = "restInspectionContent") String restInspectionContent
+            , @RequestParam(value = "handle") String handle
+            , @RequestParam(value = "dealAmount") Integer dealAmount, @RequestParam(value = "userName") String userName
+            , @RequestParam(value = "id") Integer id) throws IOException {
+        return inspectionService.edit(id, restInspectionTime, files, restInspectionContent, handle, dealAmount, userName);
+    }*/
+
+    @ApiOperation("静养巡查添加")
+    @PostMapping("/add")
+    public AjaxResult add(@RequestBody JsRestInspection restInspection) throws IOException {
+        return inspectionService.add(restInspection);
+    }
+
+    @ApiOperation("静养巡查修改")
+    @PostMapping("/edit")
+    public AjaxResult edit(@RequestBody JsRestInspection restInspection) throws IOException {
+        return inspectionService.edit(restInspection);
+    }
+
+    @ApiOperation("静养巡查删除")
+    @PostMapping("/delete")
+    public AjaxResult delete(@RequestBody Map<String, String> paramsMap) {
+        String ids = paramsMap.get("ids");
+        return inspectionService.delete(ids);
+    }
+
+    @ApiOperation("静养巡查列表")
+    @PostMapping("/list")
+    public AjaxResult listAll() {
+        return inspectionService.listAll();
+    }
+
+    @ApiOperation("静养巡查分页")
+    @GetMapping("/page")
+    public AjaxResult page(@RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize
+            , @RequestParam(value = "startTime", required = false) String startTime
+            , @RequestParam(value = "endTime", required = false) String endTime
+            , @RequestParam(value = "pigpenName", required = false) String pigpenName) {
+
+        return inspectionService.page(pageNum, pageSize, startTime, endTime, pigpenName);
+    }
+
+    @ApiOperation("静养巡查详情")
+    @PostMapping("/listById")
+    public AjaxResult listById(@RequestBody Map<String, String> paramsMap) {
+        String id = paramsMap.get("id");
+        return success(inspectionService.getById(id));
+    }
+
+    @ApiOperation("静养巡查详情通过传分圈id")
+    @PostMapping("/listByDivideCircleId")
+    public AjaxResult listByDivideCircleId(@RequestBody Map<String, String> paramsMap) {
+        String pageNum = paramsMap.get("pageNum");
+        String pageSize = paramsMap.get("pageSize");
+        String id = paramsMap.get("id");
+        Page<JsRestInspection> page = new Page<>(Integer.parseInt(pageNum), Integer.parseInt(pageSize));
+        QueryWrapper<JsRestInspection> queryWrapper = new QueryWrapper<>();
+        queryWrapper.in("divide_circle_id",id);
+        return success(inspectionService.page(page, queryWrapper));
+    }
+}

+ 73 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsSampleController.java

@@ -0,0 +1,73 @@
+package com.ruoyi.web.v2.v1.controller;
+
+
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.web.v2.v1.entity.JsSample;
+import com.ruoyi.web.v2.v1.entity.JsWorkshop;
+import com.ruoyi.web.v2.v1.service.IJsSampleService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+import static com.ruoyi.common.core.domain.AjaxResult.success;
+
+/**
+ * <p>
+ * v2.0样品留存登记 前端控制器
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-23
+ */
+@RestController
+@RequestMapping("/js-sample")
+@Api("2.0样品留存登记")
+public class JsSampleController {
+
+    @Autowired
+    private IJsSampleService sampleService;
+
+    @ApiOperation("样品留存登记添加")
+    @PostMapping("/add")
+    public AjaxResult add(@RequestBody JsSample sample){
+        return sampleService.add(sample);
+    }
+
+    @ApiOperation("样品留存登记修改")
+    @PostMapping("/edit")
+    public AjaxResult edit(@RequestBody JsSample sample){
+        return sampleService.edit(sample);
+    }
+
+    @ApiOperation("样品留存登记删除")
+    @PostMapping("/delete")
+    public AjaxResult delete(@RequestBody Map<String, String> paramsMap) {
+        String ids = paramsMap.get("ids");
+        return sampleService.delete(ids);
+    }
+
+    @ApiOperation("样品留存登记列表")
+    @PostMapping("/list")
+    public AjaxResult listAll(){
+        return sampleService.listAll();
+    }
+
+    @ApiOperation("样品留存登记分页")
+    @GetMapping("/page")
+    public AjaxResult page(@RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize
+            , @RequestParam(value = "startTime", required = false) String startTime
+            ,@RequestParam(value = "endTime", required = false) String endTime
+            ,@RequestParam(value = "sampleNum", required = false) String sampleNum) {
+        return sampleService.page(pageNum, pageSize, startTime,endTime,sampleNum);
+    }
+
+    @ApiOperation("样品留存登记详情")
+    @PostMapping("/listById")
+    public AjaxResult listById(@RequestBody Map<String, String> paramsMap){
+        String id = paramsMap.get("id");
+        return success(sampleService.getById(id));
+    }
+}

+ 43 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsStockController.java

@@ -0,0 +1,43 @@
+package com.ruoyi.web.v2.v1.controller;
+
+
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.web.v2.v1.service.IJsStockService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * <p>
+ * v2.0库存管理 前端控制器
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-23
+ */
+@RestController
+@RequestMapping("/js-stock")
+@Api("2.0库存管理")
+public class JsStockController {
+
+    @Autowired
+    private IJsStockService stockService;
+
+    @ApiOperation("库存管理列表")
+    @PostMapping("/list")
+    public AjaxResult listAll() {
+        return stockService.listAll();
+    }
+
+    @ApiOperation("库存管理分页")
+    @GetMapping("/page")
+    public AjaxResult page(@RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize
+            , @RequestParam(value = "materialBatch", required = false) String materialBatch
+            , @RequestParam(value = "materialName", required = false) String materialName
+            , @RequestParam(value = "materialType", required = false) Integer materialType) {
+
+        return stockService.page(pageNum, pageSize, materialBatch,materialName,materialType);
+    }
+
+}

+ 20 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsStoreController.java

@@ -0,0 +1,20 @@
+package com.ruoyi.web.v2.v1.controller;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ * v2.0无害化暂存 前端控制器
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-26
+ */
+@RestController
+@RequestMapping("/js-store")
+public class JsStoreController {
+
+}

+ 20 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsTransportController.java

@@ -0,0 +1,20 @@
+package com.ruoyi.web.v2.v1.controller;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ * v2.0无害化转运 前端控制器
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-26
+ */
+@RestController
+@RequestMapping("/js-transport")
+public class JsTransportController {
+
+}

+ 73 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/controller/JsWorkshopController.java

@@ -0,0 +1,73 @@
+package com.ruoyi.web.v2.v1.controller;
+
+
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.web.v2.v1.entity.JsCheckProject;
+import com.ruoyi.web.v2.v1.entity.JsWorkshop;
+import com.ruoyi.web.v2.v1.service.IJsWorkshopService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+import static com.ruoyi.common.core.domain.AjaxResult.success;
+
+/**
+ * <p>
+ * v2.0生产车间管理 前端控制器
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-21
+ */
+@RestController
+@RequestMapping("/js-workshop")
+@Api("2.0生产车间管理")
+public class JsWorkshopController {
+
+    @Autowired
+    private IJsWorkshopService workshopService;
+
+    @ApiOperation("生产车间管理管理添加")
+    @PostMapping("/add")
+    public AjaxResult add(@RequestBody JsWorkshop workshop){
+        return workshopService.add(workshop);
+    }
+
+    @ApiOperation("生产车间管理管理修改")
+    @PostMapping("/edit")
+    public AjaxResult edit(@RequestBody JsWorkshop workshop){
+        return workshopService.edit(workshop);
+    }
+
+    @ApiOperation("生产车间管理管理删除")
+    @PostMapping("/delete")
+    public AjaxResult delete(@RequestBody Map<String, String> paramsMap) {
+        String ids = paramsMap.get("ids");
+        return workshopService.delete(ids);
+    }
+
+    @ApiOperation("生产车间管理管理列表")
+    @PostMapping("/list")
+    public AjaxResult listAll(){
+        return workshopService.listAll();
+    }
+
+    @ApiOperation("生产车间管理管理分页")
+    @GetMapping("/page")
+    public AjaxResult page(@RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize
+            , @RequestParam(value = "workshopName", required = false) String workshopName
+            ,@RequestParam(value = "workshopNum", required = false) String workshopNum
+            ,@RequestParam(value = "workshopType", required = false) String workshopType) {
+        return workshopService.page(pageNum, pageSize, workshopName,workshopNum,workshopType);
+    }
+
+    @ApiOperation("生产车间管理管理详情")
+    @PostMapping("/listById")
+    public AjaxResult listById(@RequestBody Map<String, String> paramsMap){
+        String id = paramsMap.get("id");
+        return success(workshopService.getById(id));
+    }
+}

+ 58 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/entity/JsCheckDevice.java

@@ -0,0 +1,58 @@
+package com.ruoyi.web.v2.v1.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import java.util.Date;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * v2.0设备档案管理
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-21
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("js_check_device")
+@ApiModel(value="JsCheckDevice对象", description="v2.0设备档案管理")
+public class JsCheckDevice implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @ApiModelProperty(value = "设备编号")
+    private String deviceNum;
+
+    @ApiModelProperty(value = "设备名称")
+    private String deviceName;
+
+    @ApiModelProperty(value = "型号")
+    private String model;
+
+    @ApiModelProperty(value = "厂家")
+    private String manufacturer;
+
+    @ApiModelProperty(value = "投入使用日期")
+    private String investmentTime;
+
+    @ApiModelProperty(value = "联系电话")
+    private String phone;
+
+    @ApiModelProperty(value = "联系人")
+    private String userName;
+
+
+}

+ 58 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/entity/JsCheckInstrument.java

@@ -0,0 +1,58 @@
+package com.ruoyi.web.v2.v1.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import java.util.Date;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * v2.0检验仪器管理
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-21
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("js_check_instrument")
+@ApiModel(value="JsCheckInstrument对象", description="v2.0检验仪器管理")
+public class JsCheckInstrument implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @ApiModelProperty(value = "仪器编号")
+    private String deviceNum;
+
+    @ApiModelProperty(value = "仪器名称")
+    private String deviceName;
+
+    @ApiModelProperty(value = "型号")
+    private String model;
+
+    @ApiModelProperty(value = "厂家")
+    private String manufacturer;
+
+    @ApiModelProperty(value = "投入使用日期")
+    private String investmentTime;
+
+    @ApiModelProperty(value = "联系电话")
+    private String phone;
+
+    @ApiModelProperty(value = "联系人")
+    private String userName;
+
+
+}

+ 52 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/entity/JsCheckProject.java

@@ -0,0 +1,52 @@
+package com.ruoyi.web.v2.v1.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import java.util.Date;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 2.0检验项目管理
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-20
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("js_check_project")
+@ApiModel(value="JsCheckProject对象", description="2.0检验项目管理")
+public class JsCheckProject implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @ApiModelProperty(value = "项目名称")
+    private String projectName;
+
+    @ApiModelProperty(value = "检验内容")
+    private String checkContent;
+
+    @ApiModelProperty(value = "检验方法")
+    private String checkMethod;
+
+    @ApiModelProperty(value = "结果选项0正常1异常")
+    private Integer result;
+
+    @ApiModelProperty(value = "检验时间")
+    private String createTime;
+
+
+}

+ 53 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/entity/JsDeviceMaintenance.java

@@ -0,0 +1,53 @@
+package com.ruoyi.web.v2.v1.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * v2.0设备维护登记
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-23
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("js_device_maintenance")
+@ApiModel(value="JsDeviceMaintenance对象", description="v2.0设备维护登记")
+public class JsDeviceMaintenance implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @ApiModelProperty(value = "维护时间")
+    private String maintenanceTime;
+
+    @ApiModelProperty(value = "设备编号")
+    private String deviceNum;
+
+    @ApiModelProperty(value = "设备名称")
+    private String deviceName;
+
+    @ApiModelProperty(value = "维护项目")
+    private String maintenanceProject;
+
+    @ApiModelProperty(value = "维护情况描述")
+    private String maintenanceSituation;
+
+    @ApiModelProperty(value = "责任人")
+    private String userName;
+
+
+}

+ 60 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/entity/JsDisinfect.java

@@ -0,0 +1,60 @@
+package com.ruoyi.web.v2.v1.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * v2.0消毒登记
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-22
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("js_disinfect")
+@ApiModel(value="JsDisinfect对象", description="v2.0消毒登记")
+public class JsDisinfect implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @ApiModelProperty(value = "消毒时间")
+    private String disinfectTime;
+
+
+    @ApiModelProperty(value = "消毒位置")
+    private String disinfectLocation;
+
+    @ApiModelProperty(value = "待宰间")
+    private String pigpenName;
+
+    @ApiModelProperty(value = "车牌号")
+    private String car;
+
+    @ApiModelProperty(value = "消毒方式")
+    private String disinfectMethod;
+
+    @ApiModelProperty(value = "消毒药剂")
+    private String disinfectDose;
+
+    @ApiModelProperty(value = "消毒人员")
+    private String disinfectUser;
+
+    @ApiModelProperty(value = "备注")
+    private String remark;
+
+
+}

+ 53 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/entity/JsDisinfectManage.java

@@ -0,0 +1,53 @@
+package com.ruoyi.web.v2.v1.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.io.Serializable;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiModelProperty;
+import io.swagger.annotations.SwaggerDefinition;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 2.0消毒方式管理
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-20
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("js_disinfect_manage")
+public class JsDisinfectManage implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 消毒方法
+     */
+    @ApiModelProperty(value = "消毒方法")
+    private String disinfectMethod;
+
+    /**
+     * 消毒药剂
+     */
+    @ApiModelProperty(value = "消毒药剂")
+    private String disinfectDose;
+
+    /**
+     * 备注
+     */
+    @ApiModelProperty(value = "备注")
+    private String remark;
+
+
+}

+ 74 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/entity/JsDistribution.java

@@ -0,0 +1,74 @@
+package com.ruoyi.web.v2.v1.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * v2.0分销登记
+ * </p>
+ *
+ * @author author
+ * @since 2025-05-26
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("js_distribution")
+@ApiModel(value="JsDistribution对象", description="v2.0分销登记")
+public class JsDistribution implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @ApiModelProperty(value = "分销时间")
+    private String distributionTime;
+
+    @ApiModelProperty(value = "供应商id")
+    private Integer supplierId;
+
+    @ApiModelProperty(value = "供应商名称")
+    private String supplierName;
+
+    @ApiModelProperty(value = "检疫证号")
+    private String animalCertNo;
+
+    @ApiModelProperty(value = "肉商id")
+    private Integer purchaserId;
+
+    @ApiModelProperty(value = "肉商")
+    private String purchaserName;
+
+    @ApiModelProperty(value = "产品名称")
+    private String produceName;
+
+    @ApiModelProperty(value = "数量")
+    private String amount;
+
+    @ApiModelProperty(value = "吊钩类型")
+    private String hookType;
+
+    @ApiModelProperty(value = "吊钩扣重")
+    private String hookWeight;
+
+    @ApiModelProperty(value = "称显重量")
+    private String weight;
+
+    @ApiModelProperty(value = "干损重量")
+    private String dryWeight;
+
+    @ApiModelProperty(value = "宰后重量")
+    private String afterWeight;
+
+
+}

+ 0 - 0
app-admin/src/main/java/com/ruoyi/web/v2/v1/entity/JsDivideCircle.java


この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません