# 牦牛疾病预警 — 技术方案 > 依据:同目录 `牦牛疾病预警功能需求.md`。本期 **列表 + 详情只读** + **第三方同步写入**;无手工增删改接口。 --- ## 1. 技术架构 | 项 | 说明 | | --- | --- | | **后端** | RuoYi **v3.9.2**(**springboot2** 分支):JDK 8、Spring Boot 2.x、Spring MVC、MyBatis、Druid | | **数据库** | MySQL **5.7.39**,InnoDB,`utf8mb4` | | **前端** | 若依 Vue2(本方案不展开) | | **第三方** | HTTP 客户端(与牦牛资产同源或独立告警接口);`application.yml` 配置地址、鉴权、超时 | | **关联表** | `biz_pasture`(牧场映射 `pasture_id`);`biz_yak_asset`(`yak_no` 关联,非强外键) | **分层**:`Controller` → `YakDiseaseWarningSyncService`(拉取三类健康源 → 落库 → `YakDiseaseWarningAnalyzer` 分析生成预警)→ `IBizYakDiseaseWarningService`(查询、数据权限)→ `Mapper`/XML → `domain`。 **代码位置(建议)**:`baqing-admin` → `com.ruoyi.web.modules.industryservice`(与牧场、牦牛资产同包)。 | 场景 | 行为 | | --- | --- | | 健康源同步 | 分页拉取检疫/诊疗/养殖过程 OpenAPI;以 `external_id`(`Q:`/`D:`/`B:` + 第三方 ID)**唯一** upsert 至 `biz_yak_health_source_record` | | 预警生成 | 对 `analyzed_flag=0` 记录集中分析;检疫异常/阳性、诊疗同区同日 ≥3 条写入 `biz_yak_disease_warning`;分析后标记源记录已分析 | | 预警生成 | 健康源分析后**插入**预警记录;源记录 `analyzed_flag=1` 后不再重复分析 | | 列表/详情 | 无 `del_flag` 删除需求;全量展示有效同步记录;排序 `alert_time DESC, id DESC` | | 日期筛选 | `startDate`/`endDate`(`yyyy-MM-dd`)转当日 00:00:00~23:59:59(`Asia/Shanghai`) | | 牧场权限 | 列表/详情/移动端按用户可见 `pasture_id` 过滤(`@DataScope` 或 Service 注入牧场 ID 集合) | | 并发同步 | 接口加锁(`synchronized` / Redis 锁),防重复点击 | --- ## 2. 数据库设计 ### 2.1 表 `biz_yak_disease_warning`(牦牛疾病预警) | 字段 | 类型 | 非空 | 说明 | | --- | --- | --- | --- | | `id` | `bigint(20)` | Y | 主键 | | `yak_no` | `varchar(64)` | Y | 牦牛编号 | | `pasture_id` | `bigint(20)` | N | 映射 `biz_pasture.id` 成功时写入 | | `pasture_name` | `varchar(128)` | N | 所属牧场名称(冗余展示) | | `alert_time` | `datetime` | Y | 预警时间 | | `alert_message` | `varchar(1024)` | Y | 预警信息(自然语言全文) | | `warning_type` | `tinyint(4)` | N | 预警类型 **§2.2**;列表可不展示 | | `measured_value` | `varchar(128)` | N | 实测值描述,如 `39.8℃` | | `reference_range` | `varchar(128)` | N | 参考范围描述 | | `device_no` | `varchar(64)` | N | 设备/耳标编号(第三方有则存) | | `collect_time` | `datetime` | N | 指标采集时间 | | `yak_avatar_url` | `varchar(512)` | N | 牦牛头像 URL(移动端展示) | | `data_source` | `varchar(32)` | N | 数据来源,默认 `third_party` | | `last_sync_time` | `datetime` | N | 本条最近同步时间 | | `create_time` / `update_time` | `datetime` | — | 审计 | **索引** | 索引 | 字段 | 用途 | | --- | --- | --- | | `PRIMARY` | `id` | 主键 | | `KEY idx_alert_time` | `alert_time` | 列表排序、日期范围 | | `KEY idx_pasture_time` | `pasture_id`, `alert_time` | 牧场 + 时间筛选 | | `KEY idx_yak_no` | `yak_no` | 关联档案、产业统计去重 | | `KEY idx_yak_alert_time` | `yak_no`, `alert_time` | 按牛统计周期内预警 | ### 2.2 枚举 `warning_type`(可选入库) | 值 | 含义 | | --- | --- | | `1` | 体温异常 | | `2` | 运动量异常 | | `3` | 检疫集中预警 | | `4` | 诊疗集中预警 | | `9` | 其他 | 第三方无类型码时,仅写 `alert_message`,`warning_type` 可空或由文案解析填充。 ### 2.3 DDL(MySQL 5.7) ```sql CREATE TABLE `biz_yak_disease_warning` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', `yak_no` varchar(64) NOT NULL COMMENT '牦牛编号', `pasture_id` bigint(20) DEFAULT NULL COMMENT '牧场ID', `pasture_name` varchar(128) DEFAULT NULL COMMENT '所属牧场名称', `alert_time` datetime NOT NULL COMMENT '预警时间', `alert_message` varchar(1024) NOT NULL COMMENT '预警信息', `warning_type` tinyint(4) DEFAULT NULL COMMENT '1体温 2运动量 3检疫集中 4诊疗集中 9其他', `measured_value` varchar(128) DEFAULT NULL COMMENT '实测值', `reference_range` varchar(128) DEFAULT NULL COMMENT '参考范围', `device_no` varchar(64) DEFAULT NULL COMMENT '设备编号', `collect_time` datetime DEFAULT NULL COMMENT '采集时间', `yak_avatar_url` varchar(512) DEFAULT NULL COMMENT '头像URL', `data_source` varchar(32) DEFAULT 'local_analysis' COMMENT '数据来源', `last_sync_time` datetime DEFAULT NULL COMMENT '最近同步时间', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `update_time` datetime DEFAULT NULL COMMENT '更新时间', PRIMARY KEY (`id`), KEY `idx_alert_time` (`alert_time`), KEY `idx_pasture_time` (`pasture_id`,`alert_time`), KEY `idx_yak_no` (`yak_no`), KEY `idx_yak_alert_time` (`yak_no`,`alert_time`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='牦牛疾病预警'; ``` **可选**:`biz_yak_warning_sync_log`(同步批次日志:操作人、起止时间、新增/更新/失败条数 JSON),与资产档案同步日志模式一致。 ### 2.4 表 `biz_yak_health_source_record`(健康源数据) 第三方检疫/诊疗/养殖过程记录落库表;同步后由 `YakDiseaseWarningAnalyzer` 分析,分析完毕置 `analyzed_flag=1`。 | 字段 | 类型 | 说明 | | --- | --- | --- | | `id` | bigint | 主键 | | `external_id` | varchar(64) | 唯一键,`Q:`/`D:`/`B:` + 第三方 ID | | `record_type` | tinyint | `1` 检疫、`2` 诊疗、`3` 养殖过程 | | `record_time` | datetime | 业务时间 | | `region_key` | varchar(128) | 地区键(县+乡镇或牧场),集中判断分组 | | `farm_id` / `farm_name` | — | 第三方农场 | | `yak_no` | varchar(64) | 耳标/场内编号 | | `result_code` / `result_text` | — | 检疫结果、病种、过程类型等 | | `analyzed_flag` | char(1) | `0` 未分析 / `1` 已分析 | | `last_sync_time` | datetime | 最近同步时间 | DDL 见 `sql/biz_yak_health_source_record.sql`。 ### 2.5 产业统计引用(只读) 「养殖产业数据」预警牦牛头数: ```sql -- 示例:周期内去重头数(周期参数由统计模块传入) SELECT COUNT(DISTINCT yak_no) FROM biz_yak_disease_warning WHERE alert_time >= ? AND alert_time < ? AND (pasture_id IN (?) OR ? IS NULL); ``` --- ## 3. 接口设计 **统一响应**:`AjaxResult`(`code` / `msg` / `data`)或分页 `TableDataInfo`(`rows` / `total`)。 **权限标识**:`dataModel:yakDiseaseWarning:list|query|sync` **后台 Base Path**:`/dataModel/yakDiseaseWarning` | # | 说明 | Method | URI | 权限 | 要点 | | --- | --- | --- | --- | --- | --- | | 3.1 | 分页列表 | GET | `/list` | `list` | Query **§3.1.1**;牧场数据权限 | | 3.2 | 预警详情 | GET | `/{id}` | `query` | 全字段;越权牧场返回业务失败 | | 3.3 | 第三方同步 | POST | `/sync` | `sync` | 返回 **§3.3.1**;`@Log` | | 3.4 | 牧场下拉(复用) | GET | `/dataModel/pasture/list` | `dataModel:pasture:list` | 前端筛选用;`pageSize` 放大或专用精简接口 | 本期**不提供** `POST/PUT/DELETE` 预警维护接口。 #### 3.1.1 列表 Query | 参数 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `pageNum` / `pageSize` | int | N | 默认 `1` / `20` | | `startDate` | string | N | 预警开始日 `yyyy-MM-dd`;空不过滤 | | `endDate` | string | N | 预警结束日 `yyyy-MM-dd`;空不过滤 | | `pastureId` | long | N | 所属牧场 **精确**匹配 `pasture_id` | **服务端校验** | 规则 | 处理 | | --- | --- | | `startDate` > `endDate` | `AjaxResult.error("开始日期不能晚于结束日期")` | | 仅 `startDate` | `alert_time >= startDate 00:00:00` 且 `<= 当日 23:59:59`(结束缺省为今天) | | 仅 `endDate` | `alert_time <= endDate 23:59:59` | | 均为空 | 不按日期过滤 | **列表 `rows[]` 字段(驼峰)** | 字段 | 对应列 | | --- | --- | | `id` | 主键 | | `alertTime` | 预警时间 | | `yakNo` | 牦牛编号 | | `pastureName` | 所属牧场 | | `alertMessage` | 预警信息 | 排序:`alert_time DESC, id DESC`。 #### 3.2.1 详情响应 `data` | 字段 | 说明 | | --- | --- | | 列表字段 | `id`、`yakNo`、`pastureId`、`pastureName`、`alertTime`、`alertMessage` | | 扩展字段 | `warningType`、`measuredValue`、`referenceRange`、`deviceNo`、`collectTime`、`yakAvatarUrl` | | 元数据 | `dataSource`、`lastSyncTime`、`createTime`、`updateTime` | | 可选 | `yakAssetId`:按 `yak_no` 查 `biz_yak_asset` 有则返回,供前端跳转档案 | 记录不存在或牧场越权:`msg` 如「预警记录不存在」/「无权查看该预警」。 #### 3.3.1 同步响应 `data` | 字段 | 说明 | | --- | --- | | `insertCount` | 新增条数 | | `updateCount` | 更新条数 | | `failCount` | 失败条数 | | `failMessages` | 失败摘要(可选,最多 N 条) | | `syncTime` | 完成时间 | 同步中重复请求:返回「正在同步,请稍候」。 --- ### 3.5 移动端接口 **Base Path**:`/app/healthAlert`(与界面「健康预警」一致) | # | 说明 | Method | URI | 鉴权 | 要点 | | --- | --- | --- | --- | --- | --- | | M1 | 预警列表 | GET | `/list` | 登录 Token | Query 仅 `pageNum`/`pageSize`;**同 §3.1 牧场数据权限**;排序同后台 | | M2 | 预警详情 | GET | `/{id}` | 登录 Token | **本期可选**;原型列表直显全文时可不做 | **M1 `rows[]` 建议字段**:`id`、`yakNo`、`alertTime`、`alertMessage`、`yakAvatarUrl`(无则前端占位图)。 本期移动端**不提供** `startDate`/`pastureId` 筛选(见功能需求 §5.5 扩展项)。 --- ## 4. 第三方同步(实现要点) | 项 | 说明 | | --- | --- | | 配置键 | `third-party.farming`(与牧场、牦牛资产同源:`base-url`、`app-key`、`app-secret`、超时) | | 客户端 | `ThirdPartyHealthRecordClient`:`fetchQuarantineRecords()`、`fetchDiagnosisRecords()`、`fetchBreedingProcessRecords()` | | OpenAPI 路径 | `/open-api/v1/farming/quarantine-records`、`diagnosis-records`、`breeding-process-records`(以 Apifox 为准) | | 映射 | `HealthRecordOpenApiMapper` → `BizYakHealthSourceRecord`;`YakHealthSourceRecordSyncTxService` 按 `external_id` upsert | | 分析 | `YakDiseaseWarningAnalyzer`:检疫同 `region_key`+自然日异常/阳性 ≥3 → `warning_type=3`;诊疗同组 ≥3 → `warning_type=4`;养殖过程仅 `markAnalyzed` | | 阈值 | `YakDiseaseWarningAnalysisRules.CONCENTRATION_THRESHOLD = 3` | | 预警入库 | `YakDiseaseWarningSyncTxService.persistAlert`;牧场名精确匹配 `biz_pasture.pasture_name` | | 文案 | 集中预警由分析器生成 `alert_message`;体温/运动量类仍可按实测值拼接 | | 失败策略 | 单条源记录失败记 `failCount`;第三方整体不可用抛异常且**不清库** | | Stub | `thirdparty/stub-quarantine-records.json` 等(`third-party.farming.stub-enabled=true`) | | 与资产同步 | `POST /sync` **仅**健康源 + 分析预警;资产需单独调用 `/dataModel/yakAsset/sync` | --- ## 5. 菜单与权限(示例) | 类型 | 名称 | 权限标识 | | --- | --- | --- | | 菜单 | 牦牛疾病预警 | `dataModel:yakDiseaseWarning:list` | | 按钮 | 查询 | `dataModel:yakDiseaseWarning:query` | | 按钮 | 同步 | `dataModel:yakDiseaseWarning:sync` | 组件路径建议:`dataModel/yakDiseaseWarning/index`(挂载「产业数据模型及体系」目录)。 移动端菜单/路由由小程序或 H5 工程配置,**不依赖**上述后台菜单权限;接口走登录态 + 牧场数据范围。 --- ## 6. 类清单与交付 | 交付项 | 说明 | | --- | --- | | `sql/biz_yak_disease_warning.sql` | 预警表建表脚本 | | `sql/biz_yak_health_source_record.sql` | 健康源表建表脚本 | | `BizYakHealthSourceRecord` + Mapper | 源记录 CRUD、未分析查询、标记已分析 | | `ThirdPartyHealthRecordClient`、`HealthRecordOpenApiMapper` | 三类 OpenAPI 拉取与映射 | | `YakHealthSourceRecordSyncTxService`、`YakDiseaseWarningAnalyzer` | 源记录 upsert 与规则分析 | | `YakDiseaseWarningSyncService` | 编排:拉源 → 落库 → 分析 | | `BizYakDiseaseWarning` + Mapper | 预警列表、详情 | | `IBizYakDiseaseWarningService`、`BizYakDiseaseWarningController` | 查询、同步接口 | | 单元测试 / MockMvc | 日期边界、源同步、分析阈值、同步幂等、越权详情 | --- ## 7. 修订记录 | 版本 | 日期 | 说明 | | --- | --- | --- | | 1.0 | 2026-05-21 | 初版:单表 + 后台/移动端接口 + 第三方同步 | | 1.1 | 2026-05-20 | 对齐草稿:三类健康源 OpenAPI 落库 + 集中分析生成预警;新增 `biz_yak_health_source_record`;预警类型 3/4 |