Explorar o código

对接畜牧监控

wwh hai 1 mes
pai
achega
00cc592b65

+ 1 - 1
baqing-admin/src/main/java/com/ruoyi/web/modules/video/domain/BizLivestockMonitor.java

@@ -45,7 +45,7 @@ public class BizLivestockMonitor extends BaseEntity
45
     /** 所属主体主键,与 {@code ownerType} 对应 */
45
     /** 所属主体主键,与 {@code ownerType} 对应 */
46
     private Long ownerId;
46
     private Long ownerId;
47
 
47
 
48
-    /** 主体名称冗余,便于列表展示;同步时可能仅写入 farmName 文本 */
48
+    /** 主体名称冗余,便于列表展示;同步时由 farmName 匹配牧场或保留文本 */
49
     private String ownerName;
49
     private String ownerName;
50
 
50
 
51
     /** 圈舍名称,同步自第三方 {@code enclosureName},可选 */
51
     /** 圈舍名称,同步自第三方 {@code enclosureName},可选 */

+ 1 - 1
baqing-admin/src/main/java/com/ruoyi/web/modules/video/domain/dto/OpenCameraDto.java

@@ -14,7 +14,7 @@ public class OpenCameraDto
14
     /** 设备名称,落库 monitor_name */
14
     /** 设备名称,落库 monitor_name */
15
     private String deviceName;
15
     private String deviceName;
16
 
16
 
17
-    /** 养殖场名称,落库 owner_name 冗余 */
17
+    /** 养殖场名称,同步时按名称匹配 {@code biz_pasture} 绑定 owner */
18
     private String farmName;
18
     private String farmName;
19
 
19
 
20
     /** 圈舍名称,落库 enclosure_name */
20
     /** 圈舍名称,落库 enclosure_name */

+ 39 - 6
baqing-admin/src/main/java/com/ruoyi/web/modules/video/service/LivestockMonitorSyncTxService.java

@@ -7,6 +7,8 @@ import org.springframework.transaction.annotation.Propagation;
7
 import org.springframework.transaction.annotation.Transactional;
7
 import org.springframework.transaction.annotation.Transactional;
8
 import com.ruoyi.common.exception.ServiceException;
8
 import com.ruoyi.common.exception.ServiceException;
9
 import com.ruoyi.common.utils.StringUtils;
9
 import com.ruoyi.common.utils.StringUtils;
10
+import com.ruoyi.web.modules.industryservice.domain.BizPasture;
11
+import com.ruoyi.web.modules.industryservice.mapper.BizPastureMapper;
10
 import com.ruoyi.web.modules.video.domain.BizLivestockMonitor;
12
 import com.ruoyi.web.modules.video.domain.BizLivestockMonitor;
11
 import com.ruoyi.web.modules.video.domain.dto.OpenCameraDto;
13
 import com.ruoyi.web.modules.video.domain.dto.OpenCameraDto;
12
 import com.ruoyi.web.modules.video.mapper.BizLivestockMonitorMapper;
14
 import com.ruoyi.web.modules.video.mapper.BizLivestockMonitorMapper;
@@ -20,11 +22,11 @@ import com.ruoyi.web.modules.video.support.LivestockMonitorSyncRules;
20
  * <ul>
22
  * <ul>
21
  *   <li>{@code cameraId} → {@code monitor_id}</li>
23
  *   <li>{@code cameraId} → {@code monitor_id}</li>
22
  *   <li>{@code deviceName} → {@code monitor_name}(空则「监控+id」,超长截断至 10 字)</li>
24
  *   <li>{@code deviceName} → {@code monitor_name}(空则「监控+id」,超长截断至 10 字)</li>
23
- *   <li>{@code farmName} → {@code owner_name}(仅文本,不绑定 owner_type/id)</li>
25
+ *   <li>{@code farmName} → 按名称查 {@code biz_pasture},匹配则 {@code owner_type=1}、{@code owner_id}、{@code owner_name}</li>
24
  *   <li>{@code enclosureName} → {@code enclosure_name}</li>
26
  *   <li>{@code enclosureName} → {@code enclosure_name}</li>
25
  *   <li>{@code videoSource} → {@code video_source}(小写校验 wvp/ys7/url)</li>
27
  *   <li>{@code videoSource} → {@code video_source}(小写校验 wvp/ys7/url)</li>
26
  * </ul>
28
  * </ul>
27
- * 更新时保留本地 {@code owner_type}、{@code owner_id}、{@code install_location}。
29
+ * 更新时保留本地 {@code install_location};主体信息随第三方 {@code farmName} 重新解析
28
  * 每条记录 {@code REQUIRES_NEW} 独立事务,单条失败不影响其它行。
30
  * 每条记录 {@code REQUIRES_NEW} 独立事务,单条失败不影响其它行。
29
  * </p>
31
  * </p>
30
  */
32
  */
@@ -34,6 +36,9 @@ public class LivestockMonitorSyncTxService
34
     @Autowired
36
     @Autowired
35
     private BizLivestockMonitorMapper bizLivestockMonitorMapper;
37
     private BizLivestockMonitorMapper bizLivestockMonitorMapper;
36
 
38
 
39
+    @Autowired
40
+    private BizPastureMapper bizPastureMapper;
41
+
37
     /**
42
     /**
38
      * 持久化一条第三方监控记录。
43
      * 持久化一条第三方监控记录。
39
      *
44
      *
@@ -61,7 +66,7 @@ public class LivestockMonitorSyncTxService
61
         row.setMonitorName(resolveMonitorName(dto.getDeviceName(), monitorId));
66
         row.setMonitorName(resolveMonitorName(dto.getDeviceName(), monitorId));
62
         row.setEnclosureName(trimToNull(dto.getEnclosureName(), 64));
67
         row.setEnclosureName(trimToNull(dto.getEnclosureName(), 64));
63
         row.setVideoSource(videoSource);
68
         row.setVideoSource(videoSource);
64
-        row.setOwnerName(trimToNull(dto.getFarmName(), 64));
69
+        applyOwnerFromFarmName(row, dto.getFarmName());
65
         row.setDelFlag(LivestockMonitorRules.DEL_FLAG_NORMAL);
70
         row.setDelFlag(LivestockMonitorRules.DEL_FLAG_NORMAL);
66
         row.setUpdateBy(syncBy);
71
         row.setUpdateBy(syncBy);
67
 
72
 
@@ -75,9 +80,7 @@ public class LivestockMonitorSyncTxService
75
             return true;
80
             return true;
76
         }
81
         }
77
         row.setId(existing.getId());
82
         row.setId(existing.getId());
78
-        // 更新时保留本地维护字段,避免覆盖手工登记的主体与安装位置
79
-        row.setOwnerType(existing.getOwnerType());
80
-        row.setOwnerId(existing.getOwnerId());
83
+        // 更新时保留安装位置;主体随 farmName 重新匹配牧场
81
         row.setInstallLocation(existing.getInstallLocation());
84
         row.setInstallLocation(existing.getInstallLocation());
82
         row.setCreateTime(existing.getCreateTime());
85
         row.setCreateTime(existing.getCreateTime());
83
         row.setCreateBy(existing.getCreateBy());
86
         row.setCreateBy(existing.getCreateBy());
@@ -117,6 +120,36 @@ public class LivestockMonitorSyncTxService
117
         return name;
120
         return name;
118
     }
121
     }
119
 
122
 
123
+    /**
124
+     * 按第三方 farmName 精确匹配 {@code biz_pasture.pasture_name},命中则绑定养殖主体。
125
+     */
126
+    private void applyOwnerFromFarmName(BizLivestockMonitor row, String farmName)
127
+    {
128
+        String name = StringUtils.trim(farmName);
129
+        if (StringUtils.isEmpty(name))
130
+        {
131
+            row.setOwnerType(null);
132
+            row.setOwnerId(null);
133
+            row.setOwnerName(null);
134
+            return;
135
+        }
136
+        if (name.length() > 64)
137
+        {
138
+            name = name.substring(0, 64);
139
+        }
140
+        BizPasture pasture = bizPastureMapper.selectBizPastureByExactName(name);
141
+        if (pasture != null)
142
+        {
143
+            row.setOwnerType(LivestockMonitorRules.OWNER_TYPE_PASTURE);
144
+            row.setOwnerId(pasture.getId());
145
+            row.setOwnerName(pasture.getPastureName());
146
+            return;
147
+        }
148
+        row.setOwnerType(null);
149
+        row.setOwnerId(null);
150
+        row.setOwnerName(name);
151
+    }
152
+
120
     private static String trimToNull(String value, int maxLen)
153
     private static String trimToNull(String value, int maxLen)
121
     {
154
     {
122
         String text = StringUtils.trim(value);
155
         String text = StringUtils.trim(value);

+ 1 - 1
baqing-admin/src/main/java/com/ruoyi/web/modules/video/support/LivestockMonitorOwnerResolver.java

@@ -17,7 +17,7 @@ import com.ruoyi.web.modules.video.domain.BizLivestockMonitor;
17
  * <p>
17
  * <p>
18
  * 手工保存时根据 {@code ownerType} + {@code ownerId} 查库校验主体有效,
18
  * 手工保存时根据 {@code ownerType} + {@code ownerId} 查库校验主体有效,
19
  * 并将展示名称写入 {@code owner_name} 冗余字段(列表无需再 join 牧场/市场表)。
19
  * 并将展示名称写入 {@code owner_name} 冗余字段(列表无需再 join 牧场/市场表)。
20
- * 第三方同步仅写入 {@code farmName} 到 {@code owner_name},不自动绑定 {@code owner_type/id}。
20
+ * 第三方同步时按 {@code farmName} 查 {@code biz_pasture} 自动绑定 {@code owner_type=1}、{@code owner_id}。
21
  * </p>
21
  * </p>
22
  */
22
  */
23
 @Component
23
 @Component

+ 86 - 0
baqing-admin/src/test/java/com/ruoyi/web/modules/video/service/LivestockMonitorSyncTxServiceTest.java

@@ -0,0 +1,86 @@
1
+package com.ruoyi.web.modules.video.service;
2
+
3
+import static org.junit.jupiter.api.Assertions.assertEquals;
4
+import static org.junit.jupiter.api.Assertions.assertNull;
5
+import static org.mockito.ArgumentMatchers.any;
6
+import static org.mockito.Mockito.verify;
7
+import static org.mockito.Mockito.when;
8
+
9
+import java.util.Date;
10
+import org.junit.jupiter.api.DisplayName;
11
+import org.junit.jupiter.api.Test;
12
+import org.junit.jupiter.api.extension.ExtendWith;
13
+import org.mockito.ArgumentCaptor;
14
+import org.mockito.InjectMocks;
15
+import org.mockito.Mock;
16
+import org.mockito.junit.jupiter.MockitoExtension;
17
+import com.ruoyi.web.modules.industryservice.domain.BizPasture;
18
+import com.ruoyi.web.modules.industryservice.mapper.BizPastureMapper;
19
+import com.ruoyi.web.modules.video.domain.BizLivestockMonitor;
20
+import com.ruoyi.web.modules.video.domain.dto.OpenCameraDto;
21
+import com.ruoyi.web.modules.video.mapper.BizLivestockMonitorMapper;
22
+import com.ruoyi.web.modules.video.support.LivestockMonitorRules;
23
+
24
+@ExtendWith(MockitoExtension.class)
25
+@DisplayName("畜牧监控同步落库")
26
+class LivestockMonitorSyncTxServiceTest
27
+{
28
+    @Mock
29
+    private BizLivestockMonitorMapper bizLivestockMonitorMapper;
30
+
31
+    @Mock
32
+    private BizPastureMapper bizPastureMapper;
33
+
34
+    @InjectMocks
35
+    private LivestockMonitorSyncTxService livestockMonitorSyncTxService;
36
+
37
+    @Test
38
+    @DisplayName("farmName 匹配牧场时写入 owner_type=1 与 owner_id")
39
+    void persistCameraResolvesPastureOwner()
40
+    {
41
+        OpenCameraDto dto = new OpenCameraDto();
42
+        dto.setCameraId(50001L);
43
+        dto.setDeviceName("1号圈舍监控");
44
+        dto.setFarmName("示范牧场");
45
+        dto.setVideoSource("wvp");
46
+        when(bizLivestockMonitorMapper.selectBizLivestockMonitorByMonitorId("50001")).thenReturn(null);
47
+        BizPasture pasture = new BizPasture();
48
+        pasture.setId(101L);
49
+        pasture.setPastureName("示范牧场");
50
+        when(bizPastureMapper.selectBizPastureByExactName("示范牧场")).thenReturn(pasture);
51
+        when(bizLivestockMonitorMapper.insertBizLivestockMonitor(any())).thenReturn(1);
52
+
53
+        boolean inserted = livestockMonitorSyncTxService.persistCamera(dto, new Date(), "admin");
54
+        assertEquals(true, inserted);
55
+
56
+        ArgumentCaptor<BizLivestockMonitor> captor = ArgumentCaptor.forClass(BizLivestockMonitor.class);
57
+        verify(bizLivestockMonitorMapper).insertBizLivestockMonitor(captor.capture());
58
+        BizLivestockMonitor row = captor.getValue();
59
+        assertEquals(LivestockMonitorRules.OWNER_TYPE_PASTURE, row.getOwnerType());
60
+        assertEquals(101L, row.getOwnerId());
61
+        assertEquals("示范牧场", row.getOwnerName());
62
+    }
63
+
64
+    @Test
65
+    @DisplayName("farmName 未匹配牧场时仅保留 owner_name 文本")
66
+    void persistCameraFarmNameWithoutPasture()
67
+    {
68
+        OpenCameraDto dto = new OpenCameraDto();
69
+        dto.setCameraId(50002L);
70
+        dto.setDeviceName("入口监控");
71
+        dto.setFarmName("未知牧场");
72
+        dto.setVideoSource("ys7");
73
+        when(bizLivestockMonitorMapper.selectBizLivestockMonitorByMonitorId("50002")).thenReturn(null);
74
+        when(bizPastureMapper.selectBizPastureByExactName("未知牧场")).thenReturn(null);
75
+        when(bizLivestockMonitorMapper.insertBizLivestockMonitor(any())).thenReturn(1);
76
+
77
+        livestockMonitorSyncTxService.persistCamera(dto, new Date(), "admin");
78
+
79
+        ArgumentCaptor<BizLivestockMonitor> captor = ArgumentCaptor.forClass(BizLivestockMonitor.class);
80
+        verify(bizLivestockMonitorMapper).insertBizLivestockMonitor(captor.capture());
81
+        BizLivestockMonitor row = captor.getValue();
82
+        assertNull(row.getOwnerType());
83
+        assertNull(row.getOwnerId());
84
+        assertEquals("未知牧场", row.getOwnerName());
85
+    }
86
+}