Procházet zdrojové kódy

对接畜牧监控

wwh před 1 měsícem
rodič
revize
7e787079f4

+ 23 - 20
doc/视频监控系统/对接畜牧监控/对接畜牧监控前端技术方案.md

@@ -1,6 +1,6 @@
1 1
 # 对接畜牧监控 — 前端技术方案
2 2
 
3
-> 依据:`畜牧监控功能需求.md`(v1.1)、`畜牧监控技术方案.md`;布局对齐 `techService/knowledge/index.vue`、`tradeMarket/marketStall/index.vue`(双 `el-card`);字段 **小驼峰**。
3
+> 依据:`畜牧监控功能需求.md`(v1.1 + v1.2)、`畜牧监控技术方案.md`(v1.2);布局对齐 `dataModel/pasture/index.vue`(双 `el-card` + 同步按钮);字段 **小驼峰**。
4 4
 
5 5
 ---
6 6
 
@@ -11,7 +11,7 @@
11 11
 | **Vue 路径** | `ruoyi-ui/src/views/videoSurveillance/livestockMonitor/index.vue` |
12 12
 | **组件名** | `VideoSurveillanceLivestockMonitor` |
13 13
 | **菜单配置** | 组件路径:`videoSurveillance/livestockMonitor/index`(「视频监控系统」目录下) |
14
-| **权限前缀** | `videoSurveillance:livestockMonitor:list\|query\|add\|edit\|remove` |
14
+| **权限前缀** | `videoSurveillance:livestockMonitor:list\|query\|add\|edit\|remove\|sync` |
15 15
 
16 16
 ---
17 17
 
@@ -30,16 +30,18 @@
30 30
 | `updateLivestockMonitor` | PUT | `/` |
31 31
 | `delLivestockMonitor` | DELETE | `/{ids}` |
32 32
 | `listLivestockMonitorOwnerOptions` | GET | `/ownerOptions?keyword=` |
33
+| `syncLivestockMonitor` | POST | `/sync`(第三方同步) |
33 34
 
34 35
 ---
35 36
 
36 37
 ## 3. 页面结构
37 38
 
38
-1. **筛选区**:监控名称(模糊);所属主体(`ownerOptions` 远程下拉,精确成对 `ownerType`+`ownerId`);搜索、重置、新增。  
39
-2. **列表区**:监控名称、所属主体(类型 `el-tag` + 名称)、安装位置;**无 IP 列**。  
40
-3. **操作列**:查看实时监控(`msgWarning` 提示本期未开放)、查看、编辑、删除。  
41
-4. **新增/编辑弹窗**:监控名称、所属主体、安装位置、IP;确定/取消。  
42
-5. **查看弹窗**:全部字段含 IP、审计信息;有编辑权限时可跳转编辑。
39
+1. **筛选区**:监控名称(模糊);所属主体(`ownerOptions` 远程下拉);**搜索**、**重置**、**同步**(`sync` 权限)、**新增**。  
40
+2. **同步提示**:同步成功后展示「最近同步时间」摘要行(与牧场管理一致)。  
41
+3. **列表区**:监控名称、所属主体(类型 `el-tag` + 名称)、安装位置。  
42
+4. **操作列**:查看实时监控(占位提示)、查看、编辑、删除。  
43
+5. **新增/编辑弹窗**:监控名称、所属主体、安装位置等(与后端字段对齐;历史原型 IP 字段已废弃)。  
44
+6. **查看弹窗**:只读详情 + 审计信息。
43 45
 
44 46
 ---
45 47
 
@@ -48,13 +50,11 @@
48 50
 | 规则 | 实现 |
49 51
 | --- | --- |
50 52
 | 主体下拉 | `ownerType-ownerId` 复合 value;`listLivestockMonitorOwnerOptions`;`remote` + 300ms 防抖 |
51
-| 列表主体筛选 | `queryOwnerKey` 解析为 `ownerType`、`ownerId` 提交 |
52
-| 监控名称/安装位置 | trim;1~10 字 |
53
-| IP | IPv4 正则;≤20 字符 |
54
-| 名称/IP 唯一 | **不**前端校验重复 |
53
+| 列表主体筛选 | `queryOwnerKey` 解析为 `ownerType`、`ownerId` |
54
+| 第三方同步 | `handleSync` → `runSyncWithLoading(() => syncLivestockMonitor())`;展示 insert/update/fail 统计 |
55
+| 同步 loading | `videoSurveillanceLocaleMixin.runSyncWithLoading` + `vsCommon('syncLoading')` |
55 56
 | 实时监控 | `handleLiveView` → `$modal.msgWarning(msgLiveNotOpen)` |
56 57
 | 删除 | 二次确认后 `delLivestockMonitor(id)` |
57
-| 编辑回填 | `ensureOwnerOptionInList` 保证当前主体在选项中 |
58 58
 
59 59
 ---
60 60
 
@@ -62,19 +62,20 @@
62 62
 
63 63
 | 项 | 说明 |
64 64
 | --- | --- |
65
-| **语言包** | `videoSurveillance.livestockMonitor`、`videoSurveillance.common`、`videoSurveillance.status` |
65
+| **语言包** | `videoSurveillance.livestockMonitor`、`videoSurveillance.common` |
66 66
 | **文件** | `lang/zh/videoSurveillance.js`、`lang/bo/videoSurveillance.js` |
67
-| **Mixin** | `videoSurveillanceLocaleMixin`,`vsNs = 'livestockMonitor'`,`vsT` / `vsCommon` |
68
-| **注册** | `lang/zh-CN.js`、`lang/bo.js` 引入 `videoSurveillance` |
67
+| **Mixin** | `videoSurveillanceLocaleMixin`:`vsNs = 'livestockMonitor'`,`vsT` / `vsCommon`,`runSyncWithLoading` |
68
+| **同步文案** | `btnSync`、`syncSummary`、`syncTimeHint`;`common.syncLoading` |
69 69
 
70 70
 ---
71 71
 
72 72
 ## 6. 联调说明
73 73
 
74
-1. 部署 `BizLivestockMonitorController` 及 `biz_livestock_monitor` 表。  
75
-2. 预置正常状态养殖主体、交易市场,供 `ownerOptions` 使用。  
76
-3. 菜单组件 `videoSurveillance/livestockMonitor/index`,权限与后端 §4 一致。  
77
-4. 验证:名称模糊、主体精确筛选、CRUD、列表无 IP、详情有 IP、实时监控提示、双语切换。
74
+1. 部署后端及 `biz_livestock_monitor` 表(见 `sql/biz_livestock_monitor.sql`)。  
75
+2. 菜单增加按钮权限 `videoSurveillance:livestockMonitor:sync`。  
76
+3. 配置 `third-party.farming`:`mode=stub` 联调(样例 JSON);生产 `mode=http` + `base-url`。  
77
+4. 点击 **同步**:先 upsert 监控列表,再写入 `video_url`;失败明细在 `failMessages` 中展示。  
78
+5. 验证:CRUD、筛选、同步按钮、双语切换。
78 79
 
79 80
 ---
80 81
 
@@ -93,4 +94,6 @@
93 94
 
94 95
 | 版本 | 说明 |
95 96
 | --- | --- |
96
-| 1.0 | 初版:监控点位 CRUD;主体合并远程下拉;列表无 IP;实时监控占位提示;汉藏 i18n |
97
+| 1.0 | 初版:监控点位 CRUD;主体合并远程下拉;汉藏 i18n |
98
+| 1.1 | 对齐后端:移除 IP 字段依赖;列表无 IP |
99
+| 1.2 | 增加 **同步** 按钮与 `syncLivestockMonitor`;`runSyncWithLoading`;同步结果提示 |

+ 17 - 2
doc/视频监控系统/对接畜牧监控/畜牧监控功能需求.md

@@ -57,17 +57,30 @@
57 57
 | 查看监控 | 只读详情;**§5.4** |
58 58
 | 删除监控 | 逻辑删除;**§5.5** |
59 59
 | 列表/行内入口 | 「查看实时监控」入口保留,**§5.6**(能力本期不实现) |
60
+| 第三方同步 | 从生产管理系统拉取监控列表与播放地址;**§3.3** |
60 61
 
61 62
 ### 3.2 本期不实现
62 63
 
63 64
 | 项 | 说明 |
64 65
 | --- | --- |
65
-| **查看实时监控** | 不拉流、不嵌入播放器、不对接第三方视频平台;见 **§5.6** |
66
+| **查看实时监控** | 不拉流、不嵌入播放器;见 **§5.6** |
66 67
 | 批量导入导出 | 未要求 |
67 68
 | 地图选点、经纬度维护 | 未要求 |
68 69
 | 监控在线状态探测、告警、录像回放 | 未要求 |
69 70
 | 移动端监控查看 | 未要求 |
70 71
 
72
+### 3.3 第三方同步(v1.2)
73
+
74
+| 能力 | 说明 |
75
+| --- | --- |
76
+| 同步入口 | 列表页 **同步** 按钮(需按钮权限) |
77
+| 数据来源 | 第三方「查询监控数据」「获取监控视频播放地址」 |
78
+| 落库规则 | 以**摄像头 ID**为键新增或更新;播放地址写入**视频播放地址** |
79
+| 失败处理 | 单条失败不阻断整批;完成后提示新增/更新/失败条数 |
80
+| 与手工登记 | 同步后可继续编辑主体、安装位置;再次同步覆盖第三方映射字段 |
81
+
82
+**同步写入的核心字段**:摄像头 ID、监控名称、圈舍、视频来源、视频播放地址、第三方主体名称(冗余)。
83
+
71 84
 ---
72 85
 
73 86
 ## 4. 业务流程
@@ -233,6 +246,7 @@ flowchart TD
233 246
 | 编辑 | 修改未删除记录 |
234 247
 | 删除 | 逻辑删除 |
235 248
 | 查看实时监控 | 入口可见;**无实际播放权限要求**(本期不播放) |
249
+| 第三方同步 | 从生产管理系统拉取监控列表与播放地址(v1.2) |
236 250
 
237 251
 列表级按钮与行内操作须受平台**菜单与按钮权限**控制;无权限时不展示或禁用,与若依惯例一致(具体权限命名由技术方案定义,本文不展开)。
238 252
 
@@ -244,7 +258,7 @@ flowchart TD
244 258
 | --- | --- |
245 259
 | **牧场管理** | 提供「养殖主体」主数据;仅有效主体可被关联 |
246 260
 | **交易市场管理** | 提供「交易市场」主数据;仅有效市场可被关联 |
247
-| **视频监控平台(规划)** | 本期仅维护点位台账;实时流、设备状态等由后续对接需求定义 |
261
+| **视频监控平台(规划)** | v1.2 已通过开放接口同步点位与播放地址;实时播放页仍待后续迭代 |
248 262
 | **养殖产业数据 / 大屏等** | 本期**无**直接引用;若未来按主体统计监控路数,口径以本文台账为准 |
249 263
 
250 264
 ---
@@ -278,3 +292,4 @@ flowchart TD
278 292
 | --- | --- |
279 293
 | 1.0 | 依据草稿与原型整理:监控点位 CRUD、主体双源下拉、列表筛选、实时监控本期不实现;剔除库表/接口/技术栈描述 |
280 294
 | 1.1 | 评审确认:列表不展示 IP;筛选/表单主体下拉一致且仅「正常」主数据;本期不校验名称/IP 唯一;实时监控采用可点击提示方案 |
295
+| 1.2 | **第三方同步**(§3.3):拉取监控点位与播放地址;字段扩展为摄像头 ID、圈舍、视频来源、播放地址;移除 IP;主体与安装位置可选 |

+ 149 - 154
doc/视频监控系统/对接畜牧监控/畜牧监控技术方案.md

@@ -1,6 +1,6 @@
1 1
 # 畜牧监控 — 技术方案
2 2
 
3
-> 依据:同目录 `畜牧监控功能需求.md`(v1.1)。监控点位 **CRUD** + **逻辑删除**;列表**名称模糊**、**所属主体精确**筛选;**不含**实时拉流;主体下拉为养殖主体(正常)+ 交易市场(正常)合并选项。
3
+> 依据:同目录 `畜牧监控功能需求.md`(v1.1 + v1.2 第三方同步扩展)。监控点位 **CRUD** + **逻辑删除** + **第三方同步**;列表**名称模糊**、**所属主体精确**筛选;主体下拉为养殖主体(正常)+ 交易市场(正常)合并选项;播放地址由同步接口写入 `video_url`
4 4
 
5 5
 ---
6 6
 
@@ -10,22 +10,24 @@
10 10
 | --- | --- |
11 11
 | **后端** | RuoYi **v3.9.2**(**springboot2** 分支):JDK 8、Spring Boot 2.x、Spring MVC、MyBatis、Druid |
12 12
 | **数据库** | MySQL **5.7.39**,InnoDB,`utf8mb4` |
13
-| **前端** | 若依 Vue2;「查看实时监控」本期仅前端 `Message` 提示,无播放接口 |
13
+| **前端** | 若依 Vue2;「查看实时监控」本期仅前端 `Message` 提示,无播放页 |
14
+| **第三方** | 与牧场管理共用 `third-party.farming` 配置;开放接口鉴权 `X-App-Key` / `X-App-Secret` |
14 15
 
15
-**分层**:`Controller` → `Service`(`LivestockMonitorValidation`、主体有效性校验)→ `Mapper`/XML → `domain`。
16
+**分层**:`Controller` → `Service`(`LivestockMonitorValidation`、主体有效性校验)→ `Mapper`/XML → `domain`;同步编排见 `LivestockMonitorSyncService`
16 17
 
17
-**代码包(建议)**:`com.ruoyi.web.modules.video`
18
+**代码包**:`com.ruoyi.web.modules.video`
18 19
 
19 20
 **业务摘要**
20 21
 
21 22
 | 场景 | 行为 |
22 23
 | --- | --- |
23
-| 新增 | 校验字段;校验主体存在且 `del_flag=0`、状态为正常;冗余 `owner_name`;`del_flag=0` |
24
-| 修改 | 全字段可改;可更换主体类型与 ID;更新 `owner_name` |
25
-| 列表/详情 | 仅 `del_flag=0`;排序 `create_time DESC, id DESC`;列表**不返回** `ipAddress` 亦可(前端不展示列即可,接口可带) |
24
+| 新增 | 校验字段;若填写主体则校验存在且正常;冗余 `owner_name`;`del_flag=0` |
25
+| 修改 | 全字段可改;可更换主体;更新 `owner_name` |
26
+| 列表/详情 | 仅 `del_flag=0`;排序 `create_time DESC, id DESC` |
26 27
 | 列表筛选 | `monitor_name` 模糊;`owner_type` + `owner_id` **精确**(成对) |
27
-| 删除 | `del_flag=2`;**不**校验下游视频平台引用 |
28
-| 唯一性 | **不**校验名称、IP 重复(对齐需求 v1.1) |
28
+| 删除 | `del_flag=2`;**不**校验下游引用 |
29
+| 第三方同步 | 拉取监控列表 upsert(按 `monitor_id`);再逐条拉取播放地址更新 `video_url` |
30
+| 唯一性 | **不**校验名称重复;同步以 `monitor_id` 为 upsert 键 |
29 31
 
30 32
 ---
31 33
 
@@ -33,56 +35,41 @@
33 35
 
34 36
 ### 2.1 表 `biz_livestock_monitor`(畜牧监控点位)
35 37
 
36
-| 字段 | 类型 | 非空 | 默认值 | 说明 |
37
-| --- | --- | --- | --- | --- |
38
-| `id` | `bigint(20)` | Y | 自增 | 主键 |
39
-| `monitor_name` | `varchar(32)` | Y | — | 监控名称(**1~10** 字) |
40
-| `owner_type` | `tinyint(4)` | Y | — | 所属主体类型,见 **§2.3** |
41
-| `owner_id` | `bigint(20)` | Y | — | 主体主键:`biz_pasture.id` 或 `biz_trade_market.id` |
42
-| `owner_name` | `varchar(64)` | Y | — | 主体名称冗余(登记/修改时快照,列表展示用) |
43
-| `install_location` | `varchar(32)` | Y | — | 安装位置(**1~10** 字) |
44
-| `ip_address` | `varchar(20)` | Y | — | IPv4 接入地址(**≤20** 字符) |
45
-| `del_flag` | `char(1)` | Y | `'0'` | `0` 存在 `2` 删除 |
46
-| `create_by` / `create_time` / `update_by` / `update_time` | 若依惯例 | — | — | 审计 |
47
-
48
-**索引**:`PRIMARY KEY (id)`;`KEY idx_monitor_name (monitor_name)`;`KEY idx_owner (owner_type, owner_id)`;`KEY idx_create_time (create_time)`;`KEY idx_del_flag (del_flag)`。
49
-
50
-> 不设 `(monitor_name)` / `(ip_address)` 唯一索引(需求允许重复)。
51
-
52
-### 2.2 DDL(MySQL 5.7)
53
-
54
-```sql
55
-CREATE TABLE `biz_livestock_monitor` (
56
-  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
57
-  `monitor_name` varchar(32) NOT NULL COMMENT '监控名称',
58
-  `owner_type` tinyint(4) NOT NULL COMMENT '1养殖主体 2交易市场',
59
-  `owner_id` bigint(20) NOT NULL COMMENT '主体ID',
60
-  `owner_name` varchar(64) NOT NULL COMMENT '主体名称冗余',
61
-  `install_location` varchar(32) NOT NULL COMMENT '安装位置',
62
-  `ip_address` varchar(20) NOT NULL COMMENT 'IP地址IPv4',
63
-  `del_flag` char(1) NOT NULL DEFAULT '0' COMMENT '0存在 2删除',
64
-  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
65
-  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
66
-  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
67
-  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
68
-  PRIMARY KEY (`id`),
69
-  KEY `idx_monitor_name` (`monitor_name`),
70
-  KEY `idx_owner` (`owner_type`, `owner_id`),
71
-  KEY `idx_create_time` (`create_time`),
72
-  KEY `idx_del_flag` (`del_flag`)
73
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='畜牧监控点位';
74
-```
75
-
76
-初始化脚本建议路径:`sql/biz_livestock_monitor.sql`。
77
-
78
-### 2.3 枚举
38
+| 字段 | 类型 | 非空 | 说明 |
39
+| --- | --- | --- | --- |
40
+| `id` | `bigint(20)` | Y | 主键 |
41
+| `monitor_id` | `varchar(32)` | Y | 摄像头 ID(第三方 `cameraId`,同步 upsert 键) |
42
+| `monitor_name` | `varchar(32)` | Y | 监控名称(**1~10** 字) |
43
+| `owner_type` | `tinyint(4)` | N | 1 养殖主体 / 2 交易市场 |
44
+| `owner_id` | `bigint(20)` | N | 主体主键 |
45
+| `owner_name` | `varchar(64)` | N | 主体名称冗余 |
46
+| `enclosure_name` | `varchar(64)` | N | 圈舍 |
47
+| `install_location` | `varchar(32)` | N | 安装位置(**≤10** 字) |
48
+| `video_source` | `varchar(32)` | Y | 视频来源:`wvp` / `ys7` / `url` |
49
+| `video_url` | `varchar(512)` | N | 视频播放地址(同步写入) |
50
+| `del_flag` | `char(1)` | Y | `0` 存在 `2` 删除 |
51
+| 审计字段 | 若依惯例 | — | `create_by` / `create_time` / `update_by` / `update_time` |
52
+
53
+**索引**:`PRIMARY KEY (id)`;`KEY idx_monitor_id (monitor_id)`;`KEY idx_monitor_name`;`KEY idx_owner`;`KEY idx_create_time`;`KEY idx_del_flag`。
54
+
55
+> 已移除历史字段 `ip_address`。DDL 与升级脚本见 `sql/biz_livestock_monitor.sql`。
56
+
57
+### 2.2 枚举
79 58
 
80 59
 **所属主体类型 `owner_type`**
81 60
 
82 61
 | 值 | 含义 | 关联表 |
83 62
 | --- | --- | --- |
84
-| 1 | 养殖主体 | `biz_pasture`(`biz_status=1` 且 `del_flag=0` 可选) |
85
-| 2 | 交易市场 | `biz_trade_market`(`operate_status=1` 且 `del_flag=0` 可选) |
63
+| 1 | 养殖主体 | `biz_pasture`(`biz_status=1` 且 `del_flag=0`) |
64
+| 2 | 交易市场 | `biz_trade_market`(`operate_status=1` 且 `del_flag=0`) |
65
+
66
+**视频来源 `video_source`**
67
+
68
+| 值 | 含义 |
69
+| --- | --- |
70
+| wvp | WVP 平台 |
71
+| ys7 | 萤石云 |
72
+| url | 直链 URL |
86 73
 
87 74
 **删除标记 `del_flag`**
88 75
 
@@ -91,18 +78,16 @@ CREATE TABLE `biz_livestock_monitor` (
91 78
 | 0 | 正常 |
92 79
 | 2 | 已逻辑删除 |
93 80
 
94
-### 2.4 主体主数据校验(Service)
81
+### 2.3 主体主数据校验(Service)
95 82
 
96
-保存/修改时:
83
+保存/修改时,**仅当** `owner_type` 与 `owner_id` **均非空**时校验
97 84
 
98
-| `owner_type` | 校验 SQL 要点 |
85
+| `owner_type` | 校验要点 |
99 86
 | --- | --- |
100 87
 | 1 | `biz_pasture`:`id=#{ownerId}` AND `del_flag='0'` AND `biz_status=1` |
101 88
 | 2 | `biz_trade_market`:`id=#{ownerId}` AND `del_flag='0'` AND `operate_status=1` |
102 89
 
103
-失败:`ServiceException`,如「所属主体不存在或已停用」。
104
-
105
-`owner_name` 取自主数据 `pasture_name` / `market_name` 写入冗余字段。
90
+仅填其一则报「所属主体信息不完整」。两者皆空则主体字段置空。
106 91
 
107 92
 ---
108 93
 
@@ -110,7 +95,7 @@ CREATE TABLE `biz_livestock_monitor` (
110 95
 
111 96
 **统一响应**:`AjaxResult` / `TableDataInfo`(`code`、`msg`、`rows`/`data`)。
112 97
 
113
-**权限标识**:`videoSurveillance:livestockMonitor:list|query|add|edit|remove`
98
+**权限标识**:`videoSurveillance:livestockMonitor:list|query|add|edit|remove|sync`
114 99
 
115 100
 **Base Path**:`/videoSurveillance/livestockMonitor`
116 101
 
@@ -122,149 +107,157 @@ CREATE TABLE `biz_livestock_monitor` (
122 107
 | 3.4 | 修改 | PUT | `/` | `edit` |
123 108
 | 3.5 | 删除 | DELETE | `/{ids}` | `remove` |
124 109
 | 3.6 | 所属主体选项 | GET | `/ownerOptions` | `list` |
125
-
126
-> 完整路径示例:`GET /videoSurveillance/livestockMonitor/list`。
110
+| 3.7 | 第三方同步 | POST | `/sync` | `sync` |
127 111
 
128 112
 ### 3.1 列表 `GET /list`
129 113
 
130
-**Query**
114
+**Query**:`pageNum`、`pageSize`、`monitorName`(模糊)、`ownerType`+`ownerId`(成对精确)。
131 115
 
132
-| 参数 | 类型 | 必填 | 说明 |
133
-| --- | --- | --- | --- |
134
-| `pageNum` / `pageSize` | int | N | 默认 `1` / `20` |
135
-| `monitorName` | string | N | 名称**模糊**:`monitor_name LIKE %value%`(trim 后) |
136
-| `ownerType` | int | N | `1` / `2`;与 `ownerId` **成对**使用 |
137
-| `ownerId` | long | N | **精确**:`owner_type` + `owner_id` 同时匹配 |
116
+**列表行(驼峰)**:`id`、`monitorId`、`monitorName`、`ownerType`、`ownerTypeName`、`ownerId`、`ownerName`、`enclosureName`、`installLocation`、`videoSource`、`videoSourceName`、`videoUrl`、`createTime`。
138 117
 
139
-**列表行(驼峰)**
118
+### 3.2 详情 `GET /{id}`
140 119
 
141
-| 字段 | 说明 |
142
-| --- | --- |
143
-| `id` | 主键 |
144
-| `monitorName` | 监控名称 |
145
-| `ownerType` | 1 / 2 |
146
-| `ownerTypeName` | 养殖主体 / 交易市场(字典或 Service 填充) |
147
-| `ownerId` | 主体 ID |
148
-| `ownerName` | 冗余展示名 |
149
-| `installLocation` | 安装位置 |
150
-| `createTime` | 创建时间 |
120
+返回上述字段及审计字段;仅 `del_flag=0`。
151 121
 
152
-> 列表**可不返回** `ipAddress`(与需求「列表不展示 IP」一致);详情与编辑回显须含 `ipAddress`。
122
+### 3.3 新增 / 3.4 修改
153 123
 
154
-**排序**:`create_time DESC, id DESC`。
124
+**Body(驼峰)**
155 125
 
156
-### 3.2 详情 `GET /{id}`
126
+| 字段 | 必填 | 说明 |
127
+| --- | --- | --- |
128
+| `id` | 修改必填 | 主键 |
129
+| `monitorId` | Y | 摄像头 ID,≤32 字符 |
130
+| `monitorName` | Y | 1~10 字 |
131
+| `ownerType` / `ownerId` | N | 成对可选 |
132
+| `enclosureName` | N | ≤64 字符 |
133
+| `installLocation` | N | ≤10 字符 |
134
+| `videoSource` | Y | `wvp` / `ys7` / `url` |
135
+| `videoUrl` | N | ≤512 字符 |
157 136
 
158
-**`data`**:`id`、`monitorName`、`ownerType`、`ownerTypeName`、`ownerId`、`ownerName`、`installLocation`、`ipAddress`、审计字段。
137
+### 3.5 删除 `DELETE /{ids}`
159 138
 
160
-仅 `del_flag=0`;否则失败「记录不存在或已删除」。
139
+逻辑删除,`del_flag='2'`
161 140
 
162
-### 3.3 新增 `POST /`
141
+### 3.6 所属主体选项 `GET /ownerOptions`
163 142
 
164
-### 3.4 修改 `PUT /`
143
+**Query**:`keyword`(可选,模糊)。
165 144
 
166
-**Body(驼峰)**
145
+**响应 `data[]`**:`ownerType`、`ownerTypeName`、`ownerId`、`ownerName`。
167 146
 
168
-| 字段 | 新增 | 修改 | 说明 |
169
-| --- | --- | --- | --- |
170
-| `id` | — | Y | 主键 |
171
-| `monitorName` | Y | Y | 1~10 字,trim |
172
-| `ownerType` | Y | Y | `1` / `2` |
173
-| `ownerId` | Y | Y | 对应主表主键 |
174
-| `installLocation` | Y | Y | 1~10 字 |
175
-| `ipAddress` | Y | Y | IPv4;≤20 字符 |
147
+### 3.7 第三方同步 `POST /sync`
176 148
 
177
-保存时 Service 解析并写入 `owner_name`(前端**不必**传 `ownerName`,传了也以库内主数据为准覆盖)。
149
+**说明**:从第三方生产管理系统拉取监控点位并落库,再按摄像头 ID 拉取播放地址。编排类 `LivestockMonitorSyncService`;返回 `YakAssetSyncResultVo`(与牧场同步结构一致)。
178 150
 
179
-### 3.5 删除 `DELETE /{ids}`
151
+**响应 `data`**
180 152
 
181
-- 路径参数:逗号分隔 id,与若依惯例一致。  
182
-- `UPDATE … SET del_flag='2' WHERE id IN (…) AND del_flag='0'`。  
183
-- 已删 id 忽略或返回 0 条,与项目其他台账一致。
153
+| 字段 | 说明 |
154
+| --- | --- |
155
+| `insertCount` | 新增条数 |
156
+| `updateCount` | 更新条数 |
157
+| `failCount` | 失败条数(含列表落库失败与播放地址失败) |
158
+| `failMessages` | 失败明细;播放地址失败键名为 `{monitorId}(play-url): …` |
159
+| `syncTime` | 同步完成时间 |
184 160
 
185
-### 3.6 所属主体选项 `GET /ownerOptions`
161
+**并发**:同步进行中再次调用返回「正在同步,请稍候」。
186 162
 
187
-供列表筛选、新增/编辑下拉(合并数据源,支持模糊搜索)。
163
+### 3.8 服务端校验(`LivestockMonitorValidation`)
188 164
 
189
-**Query**
165
+| 项 | 规则 |
166
+| --- | --- |
167
+| 摄像头 ID | 非空;≤32 字符 |
168
+| 监控名称 | trim 后 1~10 字 |
169
+| 视频来源 | 非空;∈ {wvp, ys7, url} |
170
+| 圈舍 | 可选;≤64 字符 |
171
+| 安装位置 | 可选;≤10 字符 |
172
+| 播放地址 | 可选;≤512 字符 |
173
+| 主体 | 成对可选;填则 §2.3 校验 |
190 174
 
191
-| 参数 | 类型 | 必填 | 说明 |
192
-| --- | --- | --- | --- |
193
-| `keyword` | string | N | 对 `pasture_name` / `market_name` **模糊**;空则返回前 N 条(建议各表最多 200,合并后按名称排序) |
175
+### 3.9 第三方开放接口(Apifox)
194 176
 
195
-**响应 `data`:数组项**
177
+与牧场、牦牛档案等同源,配置前缀 **`third-party.farming`**:
196 178
 
197
-| 字段 | 说明 |
179
+| 配置项 | 说明 |
198 180
 | --- | --- |
199
-| `ownerType` | `1` / `2` |
200
-| `ownerTypeName` | 养殖主体 / 交易市场 |
201
-| `ownerId` | 主键 |
202
-| `ownerName` | 展示名称 |
181
+| `enabled` | 是否允许同步 |
182
+| `mode` | `stub`(classpath 样例)/ `http`(远程) |
183
+| `base-url` | 第三方根地址 |
184
+| `app-key` / `app-secret` | 请求头鉴权 |
185
+| `page-size` | 分页大小(上限 200) |
203 186
 
204
-**数据来源(服务端合并)**
187
+**阶段一:查询监控数据**
205 188
 
206
-1. `biz_pasture`:`del_flag='0'` AND `biz_status=1`;`keyword` 非空时 `pasture_name LIKE`。  
207
-2. `biz_trade_market`:`del_flag='0'` AND `operate_status=1`;`keyword` 非空时 `market_name LIKE`。
189
+- `GET /open-api/v1/iot/cameras`
190
+- Query:`pageNum`、`pageSize`;可选 `farmId`、`enclosureId`、`updatedAfter`
191
+- 响应:`OpenApiResponse<OpenApiPageResult<OpenCameraDto>>`,`code=0` 成功
192
+- 单条 `records[]` 字段映射:
208 193
 
209
-> 亦可由前端分别调 `GET /dataModel/pasture/list` 与 `GET /livestock/tradeMarket/list` 自行合并;**推荐**本接口以减少权限与字段差异。
194
+| 第三方字段 | 本地字段 |
195
+| --- | --- |
196
+| `cameraId` | `monitor_id` |
197
+| `deviceName` | `monitor_name`(超长截断至 10 字) |
198
+| `farmName` | `owner_name` |
199
+| `enclosureName` | `enclosure_name` |
200
+| `videoSource` | `video_source` |
210 201
 
211
-### 3.7 服务端校验(`LivestockMonitorValidation`)
202
+**阶段二:获取监控视频播放地址**
212 203
 
213
-| 项 | 规则 |
204
+- `GET /open-api/v1/iot/cameras/{cameraId}/play-url`
205
+- 响应 `data`:`cameraId`、`videoSource`、`videoUrl`
206
+- 本地:`UPDATE … SET video_url=? WHERE monitor_id=? AND del_flag='0'`
207
+
208
+**实现类**
209
+
210
+| 类 | 职责 |
214 211
 | --- | --- |
215
-| 监控名称 | trim 后 1~10 字;非纯空白 |
216
-| 安装位置 | trim 后 1~10 字 |
217
-| IP | IPv4 正则;长度 ≤20;不支持 IPv6/域名 |
218
-| 主体 | `ownerType`∈{1,2};`ownerId` 非空;**§2.4** 存在且正常 |
219
-| 名称/IP 唯一 | **不校验** |
220
-| 删除 | 记录存在且 `del_flag=0` |
212
+| `ThirdPartyCameraClient` / `ThirdPartyCameraClientImpl` | HTTP / stub 拉取 |
213
+| `LivestockMonitorSyncService` | 同步编排、防重入 |
214
+| `LivestockMonitorSyncTxService` | 单条 upsert、单条更新 `video_url`(`REQUIRES_NEW`) |
215
+| `ThirdPartyFarmingHttpSupport` | 共用 RestTemplate、鉴权头(`industryservice` 包) |
221 216
 
222
-### 3.8 Mapper 约定
217
+**Stub 样例**
223 218
 
224
-- 列表/详情条件均带 `del_flag='0'`。  
225
-- 模糊:`AND monitor_name LIKE CONCAT('%', #{monitorName}, '%')`  
226
-- 主体精确:`AND owner_type = #{ownerType} AND owner_id = #{ownerId}`(两参数均非空时)  
227
-- 逻辑删除:`UPDATE biz_livestock_monitor SET del_flag='2', update_by=?, update_time=? WHERE …`
219
+- `thirdparty/stub-cameras.json` — 监控列表
220
+- `thirdparty/stub-camera-play-urls.json` — 播放地址
228 221
 
229
-### 3.9 实时监控(本期)
222
+### 3.10 实时监控(本期)
230 223
 
231
-- **无**后端接口;列表「查看实时监控」由前端 `this.$modal.msgWarning('实时监控功能暂未开放…')` 处理
224
+- **无**独立播放接口;列表「查看实时监控」由前端 `msgLiveNotOpen` 提示
232 225
 
233 226
 ---
234 227
 
235 228
 ## 4. 菜单与权限(示例)
236 229
 
237
-| 类型 | 名称 | 权限标识 | 组件路径 |
238
-| --- | --- | --- | --- |
239
-| 目录 | 视频监控系统 | — | — |
240
-| 菜单 | 畜牧监控 | `videoSurveillance:livestockMonitor:list` | `videoSurveillance/livestockMonitor/index` |
241
-| 按钮 | 查询 | `videoSurveillance:livestockMonitor:query` | — |
242
-| 按钮 | 新增 | `videoSurveillance:livestockMonitor:add` | — |
243
-| 按钮 | 修改 | `videoSurveillance:livestockMonitor:edit` | — |
244
-| 按钮 | 删除 | `videoSurveillance:livestockMonitor:remove` | — |
230
+| 类型 | 名称 | 权限标识 |
231
+| --- | --- | --- |
232
+| 目录 | 视频监控系统 | — |
233
+| 菜单 | 畜牧监控 | `videoSurveillance:livestockMonitor:list` |
234
+| 按钮 | 查询 | `videoSurveillance:livestockMonitor:query` |
235
+| 按钮 | 新增 | `videoSurveillance:livestockMonitor:add` |
236
+| 按钮 | 修改 | `videoSurveillance:livestockMonitor:edit` |
237
+| 按钮 | 删除 | `videoSurveillance:livestockMonitor:remove` |
238
+| 按钮 | 同步 | `videoSurveillance:livestockMonitor:sync` |
245 239
 
246
-挂载「视频监控系统」菜单目录下;与 `livestock/*`、`dataModel/*` 路径前缀区分。
240
+组件路径:`videoSurveillance/livestockMonitor/index`
247 241
 
248 242
 ---
249 243
 
250 244
 ## 5. 模块关联
251 245
 
252
-| 模块 | 表 / 接口 | 关系 |
253
-| --- | --- | --- |
254
-| 牧场管理 | `biz_pasture` | `owner_type=1`;选项与校验 `biz_status=1` |
255
-| 交易市场管理 | `biz_trade_market` | `owner_type=2`;选项与校验 `operate_status=1` |
256
-| 用户管理 | `sys_user` | 本期无 `sys_user_id`;删除用户时若扩展引用 `biz_livestock_monitor.sys_user_id` 另议(**本期无**) |
246
+| 模块 | 关系 |
247
+| --- | --- |
248
+| 牧场管理 | `owner_type=1`;第三方同步养殖场列表同源配置 |
249
+| 交易市场管理 | `owner_type=2` |
250
+| 第三方生产管理系统 | 监控列表 + 播放地址开放接口 |
257 251
 
258 252
 ---
259 253
 
260 254
 ## 6. 交付清单
261 255
 
262
-- [ ] `sql/biz_livestock_monitor.sql`、菜单权限 SQL  
263
-- [ ] `BizLivestockMonitor`、`LivestockMonitorMapper`/XML、`LivestockMonitorService`、`BizLivestockMonitorController`  
264
-- [ ] `LivestockMonitorValidation`、`ownerOptions` 合并查询  
265
-- [ ] 前端 `videoSurveillance/livestockMonitor/index.vue`、`api/videoSurveillance/livestockMonitor.js`  
266
-- [ ] 单元测试(校验、主体停用、列表 SQL)  
267
-- [ ] MockMvc(list 筛选、CRUD、删除)
256
+- [x] `sql/biz_livestock_monitor.sql`
257
+- [x] `BizLivestockMonitor`、`BizLivestockMonitorMapper`/XML、`BizLivestockMonitorServiceImpl`、`BizLivestockMonitorController`
258
+- [x] `LivestockMonitorValidation`、`LivestockMonitorSyncService`、`ThirdPartyCameraClientImpl`
259
+- [x] 前端 `livestockMonitor/index.vue`、`livestockMonitor.js`、同步按钮
260
+- [x] 单元测试 / MockMvc(含 `/sync`)
268 261
 
269 262
 ---
270 263
 
@@ -272,4 +265,6 @@ CREATE TABLE `biz_livestock_monitor` (
272 265
 
273 266
 | 版本 | 说明 |
274 267
 | --- | --- |
275
-| 1.0 | 初稿:对齐功能需求 v1.1;`biz_livestock_monitor`;CRUD + `ownerOptions`;无实时流接口 |
268
+| 1.0 | 初稿:CRUD + `ownerOptions`;含 `ip_address` |
269
+| 1.1 | 表结构:`monitor_id`、`enclosure_name`、`video_source`、`video_url`;移除 `ip_address`;主体/安装位置可选 |
270
+| 1.2 | 第三方同步:`POST /sync`;对接 `/iot/cameras` 与 `/iot/cameras/{id}/play-url`;复用 `third-party.farming` |

+ 67 - 55
doc/视频监控系统/对接畜牧监控/畜牧监控测试用例.md

@@ -1,9 +1,9 @@
1 1
 # 畜牧监控 — 测试用例
2 2
 
3
-> 依据:`畜牧监控功能需求.md`(v1.1)、`畜牧监控技术方案.md`(v1.0
3
+> 依据:`畜牧监控功能需求.md`(v1.2)、`畜牧监控技术方案.md`(v1.2
4 4
 > **接口 Base Path**:`/videoSurveillance/livestockMonitor`;鉴权与若依一致(Cookie / Token)。
5 5
 
6
-**通用前置(无特殊说明)**:具备本模块权限的账号已登录(`videoSurveillance:livestockMonitor:list|query|add|edit|remove`)。主数据宜预置:
6
+**通用前置(无特殊说明)**:具备本模块权限的账号已登录(`videoSurveillance:livestockMonitor:list|query|add|edit|remove|sync`)。主数据宜预置:
7 7
 
8 8
 | 样本 | 类型 | 名称 | 状态 | 用途 |
9 9
 | --- | --- | --- | --- | --- |
@@ -14,13 +14,15 @@
14 14
 
15 15
 `biz_livestock_monitor`(`del_flag=0`):
16 16
 
17
-| 样本 | 监控名称 | 所属主体 | 安装位置 | IP | 要点 |
18
-| --- | --- | --- | --- | --- | --- |
19
-| **C1** | 圈舍监控1 | P1 | 1号圈舍 | 192.168.1.101 | 列表/改删主样本 |
20
-| **C2** | 东门监控 | M1 | 东门入口 | 192.168.2.10 | 交易市场主体 |
21
-| **C3** | 圈舍监控1 | P1 | 2号圈舍 | 192.168.1.101 | 与 C1 **同名同 IP**(唯一性不校验) |
17
+| 样本 | 监控名称 | monitor_id | 所属主体 | 圈舍 | 视频来源 | 要点 |
18
+| --- | --- | --- | --- | --- | --- | --- |
19
+| **C1** | 圈舍监控1 | 50001 | P1 | 1号圈舍 | wvp | 列表/改删主样本 |
20
+| **C2** | 东门监控 | 50002 | M1 | 东门 | ys7 | 交易市场主体 |
21
+| **C3** | 圈舍监控1 | 50003 | P1 | 2号圈舍 | wvp | 与 C1 **同名**(唯一性不校验) |
22 22
 
23
-**合法新增 Body 示例**:`monitorName=测试监控`,`ownerType=1`,`ownerId={P1.id}`,`installLocation=1号栏`,`ipAddress=192.168.0.88`。
23
+**合法新增 Body 示例**:`monitorId=50099`,`monitorName=测试监控`,`videoSource=wvp`,`ownerType=1`,`ownerId={P1.id}`,`enclosureName=1号栏`,`installLocation=1号栏`。
24
+
25
+**第三方同步 stub**:`thirdparty/stub-cameras.json` + `stub-camera-play-urls.json`;配置 `third-party.farming.mode=stub`。
24 26
 
25 27
 **界面(UI)测试**:**Playwright** + **Chromium**(`channel: 'chrome'` 使用本机 **Google Chrome**)。
26 28
 
@@ -32,21 +34,26 @@
32 34
 | --- | --- | --- | --- | --- | --- | --- | --- | --- |
33 35
 | ZCZX-XMJK-UT-001 | 参数校验 | 监控名称 | 单元测试 | JUnit5 | §3.7 | 无 | 空、纯空白、11 字、10 字 trim | 空/空白/超长失败;合法通过 |
34 36
 | ZCZX-XMJK-UT-002 | 参数校验 | 安装位置 | 单元测试 | JUnit5 | §3.7 | 无 | 空、11 字、10 字 | 空/超长失败;通过 |
35
-| ZCZX-XMJK-UT-003 | 参数校验 | IPv4 | 单元测试 | JUnit5 | §3.7、需求 §5.2 | 无 | `256.1.1.1`、`abc`、`192.168.1.1`、21 字符 | 非法/超长失败;合法通过 |
36
-| ZCZX-XMJK-UT-004 | 参数校验 | 主体类型 | 单元测试 | JUnit5 | §2.3 | 无 | `ownerType=0/3`;`1/2` | 非法失败;1/2 进入后续校验 |
37
-| ZCZX-XMJK-UT-005 | 主体校验 | 养殖主体正常 | 单元测试 | JUnit5+Mockito | §2.4 | Mock P1 存在且正常 | `validateOwner(1,P1.id)` | 通过;可解析 `ownerName` |
38
-| ZCZX-XMJK-UT-006 | 主体校验 | 牧场停业 | 单元测试 | JUnit5+Mockito | 需求 §2.2 | Mock P2 | `validateOwner(1,P2.id)` | 失败;主体不存在或已停用 |
39
-| ZCZX-XMJK-UT-007 | 主体校验 | 市场正常 | 单元测试 | JUnit5+Mockito | §2.4 | Mock M1 | `validateOwner(2,M1.id)` | 通过 |
40
-| ZCZX-XMJK-UT-008 | 主体校验 | 市场注销 | 单元测试 | JUnit5+Mockito | §2.4 | Mock M2 | `validateOwner(2,M2.id)` | 失败 |
41
-| ZCZX-XMJK-UT-009 | 唯一性 | 名称/IP 可重复 | 单元测试 | JUnit5+Mockito | 需求 §5.2 | 库已有 C1 | 再 `validateRowForSave` 同名同 IP | 通过(不抛唯一性异常) |
42
-| ZCZX-XMJK-UT-010 | Service | 新增冗余主体名 | 单元测试 | JUnit5+Mockito | §2.4 | Mock 主数据 | `insert` 合法行 | `owner_name` 与主数据名称一致 |
43
-| ZCZX-XMJK-UT-011 | Service | 逻辑删除 | 单元测试 | JUnit5+Mockito | §3.5 | Mock Mapper | `remove(id)` | `del_flag=2` |
44
-| ZCZX-XMJK-UT-012 | Service | 已删不可改 | 单元测试 | JUnit5+Mockito | 需求 §5.3 | `del_flag=2` | `update` | 失败 |
45
-| ZCZX-XMJK-UT-013 | ownerOptions | 仅正常主体 | 单元测试 | JUnit5+Mockito | §3.6 | 库含 P1/P2/M1/M2 | `listOwnerOptions(null)` | 仅含 P1、M1;不含停业/注销 |
46
-| ZCZX-XMJK-UT-014 | ownerOptions | 关键字模糊 | 单元测试 | JUnit5+Mockito | §3.6 | 有 P1「巴青」 | `keyword=巴青` | 含 P1;不含无关主体 |
47
-| ZCZX-XMJK-UT-015 | Mapper | 名称模糊 SQL | 单元测试 | JUnit5 | §3.8 | 审阅 XML | `monitor_name LIKE CONCAT` |
48
-| ZCZX-XMJK-UT-016 | Mapper | 主体精确 SQL | 单元测试 | JUnit5 | §3.8 | 审阅 XML | `owner_type` AND `owner_id` 成对 |
49
-| ZCZX-XMJK-UT-017 | Mapper | 列表范围 | 单元测试 | JUnit5 | §3.8 | 审阅 XML | `del_flag='0'`;`create_time DESC, id DESC` |
37
+| ZCZX-XMJK-UT-003 | 参数校验 | 视频来源 | 单元测试 | JUnit5 | §3.8 | 无 | 空、非法值、wvp/ys7/url | 非法失败;合法通过 |
38
+| ZCZX-XMJK-UT-004 | 参数校验 | 摄像头 ID | 单元测试 | JUnit5 | §3.8 | 无 | 空、33 字、合法 | 空/超长失败;通过 |
39
+| ZCZX-XMJK-UT-005 | 参数校验 | 主体类型 | 单元测试 | JUnit5 | §2.2 | 无 | `ownerType=0/3`;`1/2` | 非法失败;1/2 进入后续校验 |
40
+| ZCZX-XMJK-UT-006 | 主体校验 | 养殖主体正常 | 单元测试 | JUnit5+Mockito | §2.3 | Mock P1 存在且正常 | `validateOwner(1,P1.id)` | 通过;可解析 `ownerName` |
41
+| ZCZX-XMJK-UT-007 | 主体校验 | 牧场停业 | 单元测试 | JUnit5+Mockito | 需求 §2.2 | Mock P2 | `validateOwner(1,P2.id)` | 失败;主体不存在或已停用 |
42
+| ZCZX-XMJK-UT-008 | 主体校验 | 市场正常 | 单元测试 | JUnit5+Mockito | §2.3 | Mock M1 | `validateOwner(2,M1.id)` | 通过 |
43
+| ZCZX-XMJK-UT-009 | 主体校验 | 市场注销 | 单元测试 | JUnit5+Mockito | §2.3 | Mock M2 | `validateOwner(2,M2.id)` | 失败 |
44
+| ZCZX-XMJK-UT-010 | 唯一性 | 名称可重复 | 单元测试 | JUnit5+Mockito | 需求 | 库已有 C1 | 再 `validateRowForSave` 同名 | 通过 |
45
+| ZCZX-XMJK-UT-011 | Service | 新增冗余主体名 | 单元测试 | JUnit5+Mockito | §2.3 | Mock 主数据 | `insert` 合法行 | `owner_name` 与主数据名称一致 |
46
+| ZCZX-XMJK-UT-012 | Service | 逻辑删除 | 单元测试 | JUnit5+Mockito | §3.5 | Mock Mapper | `remove(id)` | `del_flag=2` |
47
+| ZCZX-XMJK-UT-013 | Service | 已删不可改 | 单元测试 | JUnit5+Mockito | 需求 §5.3 | `del_flag=2` | `update` | 失败 |
48
+| ZCZX-XMJK-UT-014 | ownerOptions | 仅正常主体 | 单元测试 | JUnit5+Mockito | §3.6 | 库含 P1/P2/M1/M2 | `listOwnerOptions(null)` | 仅含 P1、M1 |
49
+| ZCZX-XMJK-UT-015 | ownerOptions | 关键字模糊 | 单元测试 | JUnit5+Mockito | §3.6 | 有 P1「巴青」 | `keyword=巴青` | 含 P1 |
50
+| ZCZX-XMJK-UT-016 | Mapper | 名称模糊 SQL | 单元测试 | JUnit5 | §3.8 | 审阅 XML | `monitor_name LIKE CONCAT` |
51
+| ZCZX-XMJK-UT-017 | Mapper | 主体精确 SQL | 单元测试 | JUnit5 | §3.8 | 审阅 XML | `owner_type` AND `owner_id` 成对 |
52
+| ZCZX-XMJK-UT-018 | Mapper | 列表范围 | 单元测试 | JUnit5 | §3.8 | 审阅 XML | `del_flag='0'`;含 `monitor_id`、`video_url` |
53
+| ZCZX-XMJK-UT-019 | 第三方同步 | 空列表 | 单元测试 | JUnit5+Mockito | §3.7 | stub 空 | `syncFromThirdParty` | insert/update=0 |
54
+| ZCZX-XMJK-UT-020 | 第三方同步 | 新增与更新 | 单元测试 | JUnit5+Mockito | §3.7 | 2 条摄像头 | `sync` | insert=1, update=1 |
55
+| ZCZX-XMJK-UT-021 | 第三方同步 | 并发拒绝 | 单元测试 | JUnit5+Mockito | §3.7 | 同步进行中 | 再次 `sync` | 「正在同步,请稍候」 |
56
+| ZCZX-XMJK-UT-022 | 第三方同步 | 播放地址失败 | 单元测试 | JUnit5+Mockito | §3.9 | play-url 异常 | `sync` | failCount+1;列表仍成功 |
50 57
 
51 58
 ---
52 59
 
@@ -59,7 +66,7 @@
59 66
 | ZCZX-XMJK-API-003 | 列表 | 主体精确 | 接口测试 | Postman | §5.1 | 有 C2 | `ownerType=2&ownerId={M1.id}` | 仅含 C2 |
60 67
 | ZCZX-XMJK-API-004 | 列表 | 组合筛选 | 接口测试 | Postman | §5.1 | 有 C1 | `monitorName=圈舍`+P1 主体参数 | 含 C1、C3 |
61 68
 | ZCZX-XMJK-API-005 | 列表 | 不含已删除 | 接口测试 | Postman | §5.5 | 某 id 已删 | `GET /list` | 无该 id |
62
-| ZCZX-XMJK-API-006 | 列表 | 列表无 IP 字段 | 接口测试 | Postman | 需求 §5.1 | 有 C1 | `GET /list` 看 `rows[0]` | 行对象无 `ipAddress` 或前端不使用(以实现为准) |
69
+| ZCZX-XMJK-API-006 | 列表 | 含视频字段 | 接口测试 | Postman | §3.1 | 有 C1 | `GET /list` | 行含 `monitorId`、`videoSource`、`videoUrl` |
63 70
 | ZCZX-XMJK-API-007 | ownerOptions | 全量选项 | 接口测试 | Postman | §3.6 | 有 P1/M1 | `GET /ownerOptions` | `code=200`;项含 `ownerType/ownerId/ownerName` |
64 71
 | ZCZX-XMJK-API-008 | ownerOptions | 关键字 | 接口测试 | Postman | §3.6 | 有 P1 | `keyword=巴青` | 含 P1 |
65 72
 | ZCZX-XMJK-API-009 | 新增 | 养殖主体监控 | 接口测试 | Postman | §5.2 | 已登录 | `POST` 合法 Body 绑 P1 | `code=200`;`ownerName` 与 P1 一致 |
@@ -67,12 +74,12 @@
67 74
 | ZCZX-XMJK-API-011 | 新增 | 同名同 IP 允许 | 接口测试 | Postman | 需求 §5.2 | 已有 C1 | `POST` 与 C1 同名同 IP | `code=200`(第二条) |
68 75
 | ZCZX-XMJK-API-012 | 新增 | 缺监控名称 | 接口测试 | Postman | §5.2 | 已登录 | 缺 `monitorName` | 失败 |
69 76
 | ZCZX-XMJK-API-013 | 新增 | 名称超长 | 接口测试 | Postman | §5.2 | 已登录 | `monitorName` 11 字 | 失败 |
70
-| ZCZX-XMJK-API-014 | 新增 | IP 非法 | 接口测试 | Postman | §5.2 | 已登录 | `ipAddress=999.1.1.1` | 失败;msg 含 IP |
71
-| ZCZX-XMJK-API-015 | 新增 | 停业牧场主体 | 接口测试 | Postman | §2.2 | 已登录 | `ownerType=1`+P2.id | 失败;主体不存在或已停用 |
77
+| ZCZX-XMJK-API-014 | 新增 | 视频来源非法 | 接口测试 | Postman | §3.8 | 已登录 | `videoSource=invalid` | 失败 |
78
+| ZCZX-XMJK-API-015 | 新增 | 停业牧场主体 | 接口测试 | Postman | §2.2 | 已登录 | `ownerType=1`+P2.id | 失败 |
72 79
 | ZCZX-XMJK-API-016 | 新增 | 注销市场主体 | 接口测试 | Postman | §2.2 | 已登录 | `ownerType=2`+M2.id | 失败 |
73
-| ZCZX-XMJK-API-017 | 详情 | 有效 id 含 IP | 接口测试 | Postman | §5.4 | 有 C1 | `GET /{id}` | 含 `ipAddress`、主体类型名称 |
80
+| ZCZX-XMJK-API-017 | 详情 | 有效 id | 接口测试 | Postman | §3.2 | 有 C1 | `GET /{id}` | 含 `monitorId`、`videoUrl`、主体类型名称 |
74 81
 | ZCZX-XMJK-API-018 | 详情 | 已删/不存在 | 接口测试 | Postman | §8 | 已登录 | 已删或 999999 | 失败;记录不存在或已删除 |
75
-| ZCZX-XMJK-API-019 | 修改 | 改安装位置与 IP | 接口测试 | Postman | §5.3 | 有 C1 | `PUT` 改 `installLocation`、`ipAddress` | 成功;详情已更新 |
82
+| ZCZX-XMJK-API-019 | 修改 | 改圈舍与播放地址 | 接口测试 | Postman | §3.4 | 有 C1 | `PUT` 改 `enclosureName`、`videoUrl` | 成功 |
76 83
 | ZCZX-XMJK-API-020 | 修改 | 更换主体 | 接口测试 | Postman | §5.3 | 有 C1 | `PUT` 改绑 M1(type=2) | 成功;`ownerName` 更新为市场名 |
77 84
 | ZCZX-XMJK-API-021 | 修改 | 已删记录 | 接口测试 | Postman | §5.3 | C1 已删 | `PUT` | 失败 |
78 85
 | ZCZX-XMJK-API-022 | 删除 | 单条逻辑删 | 接口测试 | Postman | §5.5 | 新建行无依赖 | `DELETE /{id}` | 成功;`list` 不可见 |
@@ -82,7 +89,10 @@
82 89
 | ZCZX-XMJK-API-026 | 鉴权 | 未登录 | 接口测试 | curl | 安全 | 无 Token | `GET /list` | 401 或统一未登录 |
83 90
 | ZCZX-XMJK-API-027 | 权限 | 无新增 | 接口测试 | Postman | §6 | 仅 list | `POST` | 无权限失败 |
84 91
 | ZCZX-XMJK-API-028 | 权限 | 无删除 | 接口测试 | Postman | §6 | 无 remove | `DELETE` | 无权限失败 |
85
-| ZCZX-XMJK-API-029 | 响应 | 失败可读 | 接口测试 | Postman | §8 | 已登录 | 触发缺名称、IP 错、停业主体 | `msg` 可区分场景 |
92
+| ZCZX-XMJK-API-029 | 同步 | stub 全量同步 | 接口测试 | Postman | §3.7 | `mode=stub` | `POST /sync` | `insertCount`+`updateCount`≥0;`video_url` 有值 |
93
+| ZCZX-XMJK-API-030 | 同步 | 并发拒绝 | 接口测试 | Postman | §3.7 | 同步进行中 | 再次 `POST /sync` | 失败;正在同步 |
94
+| ZCZX-XMJK-API-031 | 同步 | 无 sync 权限 | 接口测试 | Postman | §4 | 无 sync | `POST /sync` | 无权限失败 |
95
+| ZCZX-XMJK-API-032 | 响应 | 失败可读 | 接口测试 | Postman | §8 | 已登录 | 触发缺名称、非法 videoSource | `msg` 可区分场景 |
86 96
 
87 97
 ---
88 98
 
@@ -97,21 +107,20 @@
97 107
 | ZCZX-XMJK-UI-003 | 列表 | 主体筛选 | UI 测试 | Playwright+Chrome | §5.1 | 有 C2 | 所属主体选 M1→搜索 | 仅 C2 |
98 108
 | ZCZX-XMJK-UI-004 | 列表 | 重置 | UI 测试 | Playwright+Chrome | §5.1 | 已筛选 | 搜索→**重置** | 条件清空;列表恢复 |
99 109
 | ZCZX-XMJK-UI-005 | 列表 | 未点搜索不筛 | UI 测试 | Playwright+Chrome | 平台惯例 | 有数据 | 仅改名称不点搜索 | 列表不变 |
100
-| ZCZX-XMJK-UI-006 | 新增 | 必填与 IP 字段 | UI 测试 | Playwright+Chrome | §5.2 | 有 add | 新增→选 P1→填名称/位置/IP→确定 | 成功;列表见新行 |
110
+| ZCZX-XMJK-UI-006 | 同步 | stub 同步 | UI 测试 | Playwright+Chrome | §3.3 | 有 sync | 点击**同步** | 成功提示;列表出现 stub 数据 |
101 111
 | ZCZX-XMJK-UI-007 | 新增 | 主体下拉模糊 | UI 测试 | Playwright+Chrome | §2.2 | 有 P1 | 所属主体输入「巴青」 | 可选 P1;显示类型标签 |
102
-| ZCZX-XMJK-UI-008 | 新增 | 缺必填校验 | UI 测试 | Playwright+Chrome | §5.2 | 新增弹窗 | 不选主体或空名称→确定 | 校验失败;弹窗不关闭 |
103
-| ZCZX-XMJK-UI-009 | 新增 | IP 非法 | UI 测试 | Playwright+Chrome | §5.2 | 新增 | IP 填 `abc`→确定 | 提示 IP 格式错误 |
104
-| ZCZX-XMJK-UI-010 | 新增 | 名称超 10 字 | UI 测试 | Playwright+Chrome | §5.2 | 新增 | 名称输入超 10 字 | `maxlength` 或保存失败 |
105
-| ZCZX-XMJK-UI-011 | 新增 | 取消 | UI 测试 | Playwright+Chrome | §5.2 | 新增 | 填一半→取消 | 无新行 |
106
-| ZCZX-XMJK-UI-012 | 查看 | 详情含 IP | UI 测试 | Playwright+Chrome | §5.4 | 有 C1 | 点击**查看** | 只读;含 IP、主体类型;无编辑控件或只读 |
107
-| ZCZX-XMJK-UI-013 | 编辑 | 修改字段 | UI 测试 | Playwright+Chrome | §5.3 | 有 C1 | 编辑→改安装位置→保存 | 列表/详情已更新 |
108
-| ZCZX-XMJK-UI-014 | 编辑 | 更换主体 | UI 测试 | Playwright+Chrome | §5.3 | 有 C1 | 编辑→改选 M1→保存 | 所属主体显示为 M1 |
109
-| ZCZX-XMJK-UI-015 | 删除 | 确认删除 | UI 测试 | Playwright+Chrome | §5.5 | 无依赖新行 | 删除→确认 | 行消失 |
110
-| ZCZX-XMJK-UI-016 | 删除 | 取消删除 | UI 测试 | Playwright+Chrome | §5.5 | 任意行 | 删除→取消 | 行仍在 |
111
-| ZCZX-XMJK-UI-017 | 实时监控 | 点击提示 | UI 测试 | Playwright+Chrome | §5.6 v1.1 | 有 C1 | 点击**查看实时监控** | 弹出「实时监控功能暂未开放…」;无播放页 |
112
-| ZCZX-XMJK-UI-018 | 权限 | 只读角色 | UI 测试 | Playwright+Chrome | §6 | 仅 list/query | 进入模块 | 无新增/编辑/删除按钮 |
113
-| ZCZX-XMJK-UI-019 | 端到端 | 全流程 | UI 集成 | Playwright+Chrome | §4 | 权限齐备 | 新增→搜索→查看→编辑→删 | 无报错 |
114
-| ZCZX-XMJK-UI-020 | 主体 | 停业不可选 | UI 测试 | Playwright+Chrome | §2.2 | 有 P2 停业 | 新增→主体下拉搜 P2 | 无选项或不可选 |
112
+| ZCZX-XMJK-UI-008 | 新增 | 缺必填校验 | UI 测试 | Playwright+Chrome | §5.2 | 新增弹窗 | 空名称或未选 videoSource→确定 | 校验失败;弹窗不关闭 |
113
+| ZCZX-XMJK-UI-009 | 新增 | 名称超 10 字 | UI 测试 | Playwright+Chrome | §5.2 | 新增 | 名称输入超 10 字 | `maxlength` 或保存失败 |
114
+| ZCZX-XMJK-UI-010 | 新增 | 取消 | UI 测试 | Playwright+Chrome | §5.2 | 新增 | 填一半→取消 | 无新行 |
115
+| ZCZX-XMJK-UI-011 | 查看 | 详情只读 | UI 测试 | Playwright+Chrome | §5.4 | 有 C1 | 点击**查看** | 只读;含主体类型 |
116
+| ZCZX-XMJK-UI-012 | 编辑 | 修改字段 | UI 测试 | Playwright+Chrome | §5.3 | 有 C1 | 编辑→改安装位置→保存 | 列表/详情已更新 |
117
+| ZCZX-XMJK-UI-013 | 编辑 | 更换主体 | UI 测试 | Playwright+Chrome | §5.3 | 有 C1 | 编辑→改选 M1→保存 | 所属主体显示为 M1 |
118
+| ZCZX-XMJK-UI-014 | 删除 | 确认删除 | UI 测试 | Playwright+Chrome | §5.5 | 无依赖新行 | 删除→确认 | 行消失 |
119
+| ZCZX-XMJK-UI-015 | 删除 | 取消删除 | UI 测试 | Playwright+Chrome | §5.5 | 任意行 | 删除→取消 | 行仍在 |
120
+| ZCZX-XMJK-UI-016 | 实时监控 | 点击提示 | UI 测试 | Playwright+Chrome | §5.6 | 有 C1 | 点击**查看实时监控** | 弹出「实时监控功能暂未开放…」 |
121
+| ZCZX-XMJK-UI-017 | 权限 | 只读角色 | UI 测试 | Playwright+Chrome | §6 | 仅 list/query | 进入模块 | 无新增/编辑/删除/同步按钮 |
122
+| ZCZX-XMJK-UI-018 | 端到端 | 全流程 | UI 集成 | Playwright+Chrome | §4 | 权限齐备 | 同步→搜索→查看→编辑→删 | 无报错 |
123
+| ZCZX-XMJK-UI-019 | 主体 | 停业不可选 | UI 测试 | Playwright+Chrome | §2.2 | 有 P2 停业 | 新增→主体下拉搜 P2 | 无选项或不可选 |
115 124
 
116 125
 ---
117 126
 
@@ -121,7 +130,8 @@
121 130
 - 配置:`use: { channel: 'chrome', locale: 'zh-CN', baseURL: 'http://localhost:80' }`;`storageState` 复用登录态。  
122 131
 - 路由:`page.goto('/videoSurveillance/livestockMonitor')`(以菜单 `component` 为准)。  
123 132
 - 筛选:`page.getByPlaceholder('请输入监控名称').fill('圈舍')`;所属主体用 `el-select` + 远程搜索。  
124
-- 新增:`page.getByRole('button', { name: '新增' }).click()`;填名称、选主体、安装位置、IP;`确定`。  
133
+- 同步:`page.getByRole('button', { name: '同步' }).click()`;`expect(page.getByText('同步完成')).toBeVisible()`。  
134
+- 新增:`page.getByRole('button', { name: '新增' }).click()`;填 `monitorId`、名称、视频来源等;`确定`。  
125 135
 - 实时监控:`page.getByRole('button', { name: '查看实时监控' }).first().click()`;`expect(page.getByText('实时监控功能暂未开放')).toBeVisible()`。
126 136
 
127 137
 ---
@@ -130,16 +140,17 @@
130 140
 
131 141
 | 类别 | 单元 UT | 接口 API | 界面 UI |
132 142
 | --- | --- | --- | --- |
133
-| 正常 CRUD | UT-010 | API-009~010、017、019~020、025 | UI-006、012~014、019 |
134
-| 列表筛选 | UT-015~017 | API-001~004 | UI-002~005 |
135
-| 主体约束 | UT-005~008、013~014 | API-007~008、015~016 | UI-007、020 |
136
-| 字段校验 | UT-001~004 | API-012~014 | UI-008~010 |
137
-| 唯一性不校验 | UT-009 | API-011 | — |
138
-| 逻辑删除 | UT-011~012 | API-005、022~024 | UI-015~016 |
139
-| 实时监控占位 | — | — | UI-017 |
140
-| 鉴权权限 | — | API-026~028 | UI-018 |
141
-| ownerOptions | UT-013~014 | API-007~008 | UI-007 |
142
-| 列表无 IP | — | API-006 | UI-001、012 |
143
+| 正常 CRUD | UT-011 | API-009~010、017、019~020、025 | UI-011~013、018 |
144
+| 列表筛选 | UT-016~018 | API-001~004 | UI-002~005 |
145
+| 主体约束 | UT-006~009、014~015 | API-007~008、015~016 | UI-007、019 |
146
+| 字段校验 | UT-001~005 | API-012~014 | UI-008~009 |
147
+| 唯一性不校验 | UT-010 | API-011 | — |
148
+| 逻辑删除 | UT-012~013 | API-005、022~024 | UI-014~015 |
149
+| 第三方同步 | UT-019~022 | API-029~031 | UI-006 |
150
+| 实时监控占位 | — | — | UI-016 |
151
+| 鉴权权限 | — | API-026~028、031 | UI-017 |
152
+| ownerOptions | UT-014~015 | API-007~008 | UI-007 |
153
+| 视频字段 | UT-003~004 | API-006 | UI-001 |
143 154
 
144 155
 ---
145 156
 
@@ -147,4 +158,5 @@
147 158
 
148 159
 | 版本 | 说明 |
149 160
 | --- | --- |
150
-| 1.0 | 初稿:对齐功能需求 v1.1、技术方案 v1.0;UT/API/UI 共 66 条;Playwright+Chrome |
161
+| 1.0 | 初稿:对齐功能需求 v1.1、技术方案 v1.0;UT/API/UI;Playwright+Chrome |
162
+| 1.1 | 对齐 v1.2 实现:新字段、移除 IP;增加第三方同步 UT/API/UI 用例 |

+ 1 - 0
sql/biz_livestock_monitor.sql

@@ -1,5 +1,5 @@
1 1
 -- 畜牧监控点位
2
+-- 业务说明见 doc/视频监控系统/对接畜牧监控/畜牧监控技术方案.md(v1.2)
2 3
 
3 4
 CREATE TABLE IF NOT EXISTS `biz_livestock_monitor` (
4 5
   `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',