# 大屏 — 畜牧资源统计 — 技术方案

> 依据：同目录 `大屏畜牧资源功能需求.md` v1.4。核心总览取农村三资与畜牧产品产量；其余区块为 AI 诊断既有表。本模块为**大屏只读看板**；**不**统计移动端「畜牧资源」资讯视图 `v_livestock_resource`。

---

## 1. 技术架构

| 项 | 说明 |
| --- | --- |
| **后端** | RuoYi **v3.9.2**（**springboot2** 分支）：JDK 8、Spring Boot 2.x、Spring MVC、MyBatis、Druid |
| **数据库** | MySQL **5.7.39**，InnoDB，`utf8mb4` |
| **前端** | `ruoyi-screen` 畜牧资源专题页（`/livestock-resources`）；**切换 `statYear`** 拉取看板主数据（本期**单接口**） |
| **代码包** | `com.ruoyi.web.modules.screen`（`LivestockResourceScreenController` / `ILivestockResourceScreenService` / `vo` / `support`） |

**分层**：`Controller` → `ILivestockResourceScreenService`（口径编排、`statDate`/`statDateTime`）→ `LivestockResourceScreenMapper`（只读 SQL）+ `LivestockResourceScreenSupport`（7 日/24 小时补点、分类归一、占比、分档、关键词）。

| 场景 | 行为 |
| --- | --- |
| 进入 / 切换 `statYear` | 调用 **§3.1** |
| 数据权限 | **全县**聚合；不按提问人/机构过滤 |
| 统计日 `statDate` | 复用 `HomeScreenSupport.resolveStatDate(Y)`：`Y`=当前年 → 今日（`Asia/Shanghai`）；历史年 → `Y-12-31` |
| 统计时刻 `statDateTime` | 请求时 `LocalDateTime.now(Asia/Shanghai)`；响应回显用 |
| 年内上界 | 会话 `create_time`；AI 消息 **`create_time`** ≤ `statDate 23:59:59`（当前年） |
| 「今日」四项 | 仅当 `Y` = 当前自然年时按 `statDate` 自然日统计；否则固定 **0** |
| 用户结构 | `biz_consult_user` **全表快照**，**不**随 `Y` 变 |
| 7 日 / 分时 | 7 日以 `statDate` 滚动；分时为 **距 statDateTime 最近 24 整点小时**，**与 Y 无关** |
| 已隐藏会话 | **不**过滤 `vet_visible`（对齐功能需求 **§2.18#2**） |
| 性能 | 默认实时聚合；可选 **§2.3** 缓存表 |

**依赖表（只读）**

| 表 | 用途 |
| --- | --- |
| `biz_consult_session` | AI 会话数、用户去重、7 日/24 小时会话、分档分母 |
| `biz_consult_message` | 提问量（AI 回复）、耗时、分类、状态、关键词语料 |
| `biz_consult_user` | 新老用户结构 |
| `biz_rural_three_assets` | 核心总览 + 农村三资区块：经营性/非经营性/固定资产 |
| `biz_livestock_product_output` | 核心总览 + 产量月度趋势 |
| `biz_vaccination_data` | 核心总览 + 疫苗接种区块 |
| `biz_three_assets_problem_report` | 三资具体问题上报按等级 |
| `biz_medical_resource` | 核心总览：兽医人数 |
| `biz_tech_service_personnel` | 核心总览：科技特派员、农业事业单位 |

**业务常量（与 `ConsultSessionRules` / `AiConsultConstants` 一致）**

| 常量 | 值 |
| --- | --- |
| `consult_type` AI 问诊 | `2` |
| `sender_role` 提问人 / AI | `1` / `3` |
| AI 消息 `sender_user_id` | `0` |
| `msg_type` 文本 | `1` |
| 提问分类编码 | `1`～`4`（养殖技巧/疾病诊疗/用药指导/设备操作） |

---

## 2. 数据库设计

### 2.1 本模块业务表

**无新增业务台账表。** DDL：`sql/biz_consult_session.sql`、`sql/biz_consult_message.sql`、`sql/biz_consult_user.sql`。

> 当前问诊表**无** `del_flag`；纳入条件为：`consult_type=2` 的会话及其消息。已隐藏（`vet_visible=0`）**仍统计**。

### 2.2 时间边界（公共参数）

记 `statYear = Y`，`statDate`、`statDateTime` 见 **§1**。

| 边界 | 表达式 |
| --- | --- |
| 年区间起 | `Y-01-01 00:00:00` |
| 年区间止（会话 `create_time`、AI 消息 `create_time`） | `statDate 23:59:59` |
| 统计日区间 | `statDate 00:00:00` ～ `statDate 23:59:59` |
| 近 7 日 | `[statDate − 6 日 00:00:00, statDate 23:59:59]` |
| 最近 24 小时 | `[floor(statDateTime 到整点) − 23 小时, floor(statDateTime 到整点) + 59 分 59 秒]`；SQL 按 `DATE_FORMAT(create_time,'%Y%m%d%H')` 分组 |

**会话别名（下文）**：`s` = `biz_consult_session`，条件 `s.consult_type = 2`。  
**AI 消息别名**：`m_ai` = `biz_consult_message`，`m_ai.sender_role = 3 AND m_ai.sender_user_id = 0`，且 `EXISTS` 关联 `s.id = m_ai.session_id`。  
**提问人消息别名**：`m_ask` = `biz_consult_message`，`m_ask.sender_role = 1`，且关联 AI 会话 `s`。

### 2.3 可选表 `biz_livestock_resource_screen_cache`（性能优化）

**非本期必建。**

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `id` | `bigint(20)` | 主键 |
| `stat_year` | `int(11)` | 统计年份 |
| `payload_json` | `mediumtext` | **§3.1** 响应 JSON |
| `expire_time` | `datetime` | 过期时间 |
| `create_time` | `datetime` | 写入时间 |

**索引**：`UNIQUE uk_stat_year (stat_year)`。TTL **1～5 分钟**。

### 2.4 查询口径（按表）

#### 2.4.1 核心总览

| 指标 | 数据源与 SQL 要点 | 与 `statYear` |
| --- | --- | --- |
| 经营性固定资产（万元） | `biz_rural_three_assets`：`SUM(operating_fixed_assets)`，全县各村 | **不**随 Y 变 |
| 非经营性固定资产（万元） | 同上：`SUM(non_operating_fixed_assets)` | **不**随 Y 变 |
| 肉产量（万吨） | `biz_livestock_product_output`：所选年 **最大 `stat_month`** 全县 `SUM(meat_output)` | 随 Y |
| 奶产量（万吨） | 同上：`SUM(milk_output)` | 随 Y |
| 免疫率（%） | `biz_vaccination_data`：所选年最大月 `(SUM(实免)/SUM(应免))×100`，2 位小数；应免和为 0 → **0.00** | 随 Y |
| 兽医（人） | `biz_medical_resource`：`resource_type='004001'` 且 `del_flag='0'` 计数 | **不**随 Y 变 |
| 科技特派员（人） | `biz_tech_service_personnel.envoy_total_count`（单例 id=1） | **不**随 Y 变 |
| 农业事业单位（人） | 同上 `agri_total_count` | **不**随 Y 变 |

无填报月或无行时对应产量/免疫率为 **0**；固定资产/人员无行时为 **0**。

#### 2.4.2 近 7 日活跃度

| 维度 | SQL 要点 |
| --- | --- |
| 会话数/日 | `DATE(s.create_time)` 分组，`COUNT(s.id)` |
| 提问量/日 | `DATE(m_ai.create_time)` 分组，`COUNT(m_ai.id)` |

应用层：固定输出 **7** 个点（`statDate−6` … `statDate`），缺日补 **0**。

#### 2.4.3 用户结构 `biz_consult_user`

| 类型 | 条件 |
| --- | --- |
| 新用户 | `DATEDIFF(last_use_time, first_use_time) <= 180` |
| 老用户 | `> 180` |

`COUNT(*)` 各一类；占比 = 人数 / (新+老)，**不**加 `Y` 条件。

#### 2.4.4 提问分类 / 模型调用 / 热点榜（同源）

| 项 | 条件 |
| --- | --- |
| 统计行 | `m_ai`（`sender_role=3`、`sender_user_id=0`），`create_time` ∈ 年区间 |
| 分类键 | 同会话内 `send_time ≤ m_ai.send_time` 的最近提问人消息 `ai_category`；空 → `UNCAT` |
| 条数 | `GROUP BY` 分类键 `COUNT(*)`；`MAX(m_ai.create_time)` 供热点二次排序 |
| 占比 | 分类 AI 回复条数 / **当年全部 AI 回复** × 100 |
| 热点 Top5 | 条数降序；同分按 `lastEventTime` 降序；取 **5** |

#### 2.4.5 分时使用热度（最近 24 小时）

| 维度 | SQL 要点 |
| --- | --- |
| 会话 | `s.create_time` ∈ 24h 窗口，`GROUP BY DATE_FORMAT(create_time,'%Y%m%d%H')` |
| 提问量 | `m_ai.create_time` ∈ 24h 窗口，同上分组 |

应用层：固定 **24** 桶（锚点整点向前 23 小时）；`bucketStart`=`HH:mm`；`bucketDateTime`=`yyyy-MM-dd HH:mm`；`hourlyHeat.windowEnd` = 锚点整点 `yyyy-MM-dd HH:mm`。

#### 2.4.6 单次会话提问数量分布

子查询：按 `session_id` 统计年内 `m_ai` 条数 `reply_cnt`，再分档：

| 档位 code | `reply_cnt` |
| --- | --- |
| `LIGHT` | 1～2 |
| `NORMAL` | 3～4 |
| `ACTIVE` | 5～10 |
| `DEEP` | >10 |

`COUNT(session_id)` / 年内会话总数 → 占比；四档固定返回，无数据为 0。

#### 2.4.7 会话状态分布

| 状态 | 条件 |
| --- | --- |
| `OK` 正常应答 | `m_ai.cost_time IS NOT NULL`（**含 0**） |
| `FAIL` 调用失败 | `m_ai.cost_time IS NULL` |

年内 `COUNT(*)` 及占比；两者之和 = 年内 AI 消息总数。

#### 2.4.8 高频关键词

| 项 | 条件 |
| --- | --- |
| 语料 | `m_ask.msg_type = 1`，`m_ask.content` 非空，`m_ask.send_time` ∈ 年区间 |
| 处理 | `LivestockResourceScreenSupport.extractTopKeywords(texts, 30)`：分词 + 停用词（`application.yml` 可配路径或内置短表） |

### 2.5 索引建议（既有表）

| 表 | 建议 |
| --- | --- |
| `biz_consult_session` | `(consult_type, create_time)`、`(consult_type, update_time)` |
| `biz_consult_message` | `(session_id, sender_role, create_time)`、`(create_time, sender_role)` |

### 2.6 Mapper 方法（建议）

| Mapper | 方法 | 说明 |
| --- | --- | --- |
| `LivestockResourceScreenMapper` | `selectOverview(...)` | 总览 8 项（可拆 2～3 条 SQL） |
| | `selectDailySessionCounts(start, end)` | 7 日会话 |
| | `selectDailyAiReplyCounts(start, end)` | 7 日提问量 |
| | `selectUserStructure()` | 新老用户 |
| | `selectAskerCategoryCounts(yearStart, yearEnd)` | AI 回复按分类键聚合 |
| | `selectAiReplyTotal(yearStart, yearEnd)` | 分类占比分母（年内 AI 回复总数） |
| | `selectHourlySessionCounts(windowStart, windowEnd)` | 最近 24h 会话 |
| | `selectHourlyAiReplyCounts(windowStart, windowEnd)` | 最近 24h 提问量 |
| | `selectSessionReplyBuckets(yearStart, yearEnd)` | 四档会话数 |
| | `selectYearSessionTotal(yearStart, yearEnd)` | 年内会话总数 |
| | `selectAiReplyStatusCounts(yearStart, yearEnd)` | 正常/失败 |
| | `selectTextAskerContents(yearStart, yearEnd)` | 关键词语料 |
| | `selectDistinctSessionYears()` | 可选年份下拉 |

XML：`mapper/screen/LivestockResourceScreenMapper.xml`。

---

## 3. 接口设计

**统一响应**：`AjaxResult`（`code` / `msg` / `data`）。

**Base Path**：`/bigScreen/livestockResource`

**权限标识（示例）**：`bigScreen:livestockResource:query`

| # | 说明 | Method | URI |
| --- | --- | --- | --- |
| 3.1 | 看板主数据 | GET | `/bigScreen/livestockResource/dashboard` |
| 3.2 | 三资具体问题上报明细 | GET | `/bigScreen/livestockResource/threeAssetsProblemReports` |
| 3.3 | 畜牧产品产量数据明细 | GET | `/bigScreen/livestockResource/productOutputs` |
| 3.4 | 疫苗接种情况明细 | GET | `/bigScreen/livestockResource/vaccinationData` |
| 3.5 | 兽医数量明细 | GET | `/bigScreen/livestockResource/vetCounts` |

前端：进入页 / 切换 `statYear` / 刷新 → **3.1**；点问题上报区块看明细 → **3.2**；点产量区块看明细 → **3.3**；点疫苗区块看明细 → **3.4**；点兽医指标看明细 → **3.5**。

---

### 3.1 看板主数据

#### Query

| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `statYear` | string | Y | 四位年份；非法 → 业务异常（`AchievementReportValidation.parseStatYear`） |
| `forceRefresh` | boolean | N | 默认 `false`；`true` 时跳过 **§2.3** 缓存 |

#### 响应 `data`（顶层）

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `statYear` | int | 回显 |
| `statDate` | string | `yyyy-MM-dd` |
| `statDateTime` | string | `yyyy-MM-dd HH:mm:ss`，24h 窗口终点 |
| `availableYears` | int[] | `biz_consult_session` 在 `consult_type=2` 下 `YEAR(create_time)` 并集 + 当前年，降序 |
| `overview` | object | 核心总览 **§3.1.1** |
| `ruralThreeAssets` | object | 农村三资数据 |
| `problemReportShare` | object | 三资问题上报按等级 |
| `productOutputTrend` | object | 畜牧产品产量月度趋势 |
| `vaccinationOverview` | object | 疫苗接种免疫率 |
| `appointment` | object | 线下服务预约：三项台账人数/机构数（不随年）；`monthlyStacked` 为所选年 1～最大月预约次数 |
| `techEnvoyStructure` | object | 科技特派员：党员/其他、男/女占比与人数 |
| `agriUnitStructure` | object | 农业事业单位：员级/初级/中级/高级/管理级人数 |
| `agriClassroom` | object | 农技课堂（自首页迁入） |
| `trainingTrend` | object | 实战培训报名：所选年 1～库中最大月；`monthly[].statYear/month/activityCount/enrolledCount` |

> **已屏蔽（不再返回）：** `activityTrend`、`userStructure`、`categoryShare`、`modelCallAnalysis`、`hourlyHeat`、`sessionReplyDistribution`、`replyStatusDistribution`、`hotTopics`、`topKeywords`。

#### 3.1.1 `overview`

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `operatingFixedAssets` | decimal | 经营性固定资产（万元），2 位小数 |
| `nonOperatingFixedAssets` | decimal | 非经营性固定资产（万元），2 位小数 |
| `meatOutput` | decimal | 肉产量（万吨），所选年最大填报月全县合计，4 位小数 |
| `milkOutput` | decimal | 奶产量（万吨），同上 |
| `immunityRate` | decimal | 免疫率（%），所选年最大填报月 (实免和/应免和)×100，2 位小数 |
| `vetCount` | long | 兽医人数（`004001` 且未删除） |
| `techEnvoyCount` | long | 科技特派员总人数 |
| `agriUnitCount` | long | 农业事业单位总人数 |

#### 3.1.1a `ruralThreeAssets`

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `operatingFixedAssets` / `nonOperatingFixedAssets` / `fixedAssets` | decimal | 全县合计（万元），2 位小数；不随年变 |

#### 3.1.1b `problemReportShare`

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `totalCount` | long | 所选年上报总次数 |
| `items[]` | array | `levelCode`/`levelName`/`count`/`ratio`（一般/重点/重大） |

#### 3.1.1c `productOutputTrend`

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `maxMonth` | int\|null | 所选年最大填报月 |
| `monthlySeries[]` | array | 1～N：`month`/`meatOutput`/`milkOutput`（万吨，4 位） |

#### 3.1.1d `vaccinationOverview`

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `statMonth` | int\|null | 最大填报月 |
| `immunityRate` | decimal | 免疫率 %，2 位 |
| `shouldVaccinateCount` / `actualVaccinateCount` | long | 应免/实免合计 |

#### 3.1.1e `appointment`

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `annualVetCount` | int | 兽医人员数：`biz_medical_resource` `resource_type=004001` 且 `del_flag=0`；**不**随年变 |
| `annualExpertCount` | int | 专家人员数：`biz_tech_resource` `resource_type=004005` 且 `del_flag=0`；**不**随年变 |
| `annualOrgCount` | int | 诊疗机构数：`biz_medical_resource` `resource_type=004003` 且 `del_flag=0`；**不**随年变 |
| `monthlyStacked[]` | array | 所选年 1～最大月：`statYear`/`month`/`vetCount`/`expertCount`/`orgCount`（预约次数，排除 status 2/3） |

#### 3.1.2 `activityTrend`

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `dailySeries` | array | 固定 **7** 条 |

`dailySeries[]`：

| 字段 | 说明 |
| --- | --- |
| `date` | `yyyy-MM-dd` |
| `sessionCount` | 会话数 |
| `questionCount` | 提问量（AI 回复） |

#### 3.1.3 `userStructure`

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `newUserCount` | long | 新用户 |
| `oldUserCount` | long | 老用户 |
| `newUserRatio` | decimal | 占比 0～100 |
| `oldUserRatio` | decimal | 占比 0～100 |

#### 3.1.4 `categoryShare`

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `totalAskerMessages` | long | 分母：年内全部 **AI 回复**（字段名沿用，与提问人无关） |
| `items` | array | 分类项 |

`items[]`：`categoryCode`、`categoryName`、`count`、`ratio`（0～100，1 位小数）。固定含 `1`～`4` + `UNCAT`（未分类），无数据 `count=0`。

#### 3.1.5 `modelCallAnalysis[]`

与 `categoryShare.items` **同源**（可复用引用）：`categoryCode`、`categoryName`、`count`。展示为柱状图时前端取 `count`。

#### 3.1.6 `hourlyHeat`

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `windowEnd` | string | 锚点整点 `yyyy-MM-dd HH:mm` |
| `hourlySeries` | array | 固定 **24** 条 |

`hourlySeries[]`：`bucketStart`（`HH:mm`）、`bucketDateTime`（`yyyy-MM-dd HH:mm`，悬停）、`sessionCount`、`questionCount`。

#### 3.1.7 `sessionReplyDistribution[]`

固定 **4** 条。

| 字段 | 说明 |
| --- | --- |
| `bandCode` | `LIGHT` / `NORMAL` / `ACTIVE` / `DEEP` |
| `bandName` | 轻度 / 一般 / 活跃 / 深度 |
| `sessionCount` | 会话数 |
| `ratio` | 占年内会话总数 % |

#### 3.1.8 `replyStatusDistribution`

| 字段 | 说明 |
| --- | --- |
| `totalAiReplies` | 年内 AI 回复总数 |
| `items` | 固定 2 条：`OK`（正常应答）、`FAIL`（调用失败），含 `count`、`ratio` |

#### 3.1.9 `hotTopics[]`

最多 **5** 条：`categoryCode`、`categoryName`、`count`、`ratio`，按 `ratio` 或 `count` 降序。

#### 3.1.10 `topKeywords[]`

最多 **30** 条：`keyword`、`count`。

#### 响应示例（节选）

```json
{
  "statYear": 2026,
  "statDate": "2026-05-20",
  "statDateTime": "2026-05-20 15:30:00",
  "overview": {
    "operatingFixedAssets": 100.50,
    "nonOperatingFixedAssets": 200.25,
    "meatOutput": 1.2000,
    "milkOutput": 3.4000,
    "immunityRate": 90.00,
    "vetCount": 15,
    "techEnvoyCount": 30,
    "agriUnitCount": 40
  },
  "activityTrend": {
    "dailySeries": [
      { "date": "2026-05-14", "sessionCount": 3, "questionCount": 10 }
    ]
  },
  "categoryShare": {
    "totalAskerMessages": 500,
    "items": [
      { "categoryCode": "2", "categoryName": "疾病诊疗", "count": 200, "ratio": 40.0 }
    ]
  }
}
```

#### 服务端逻辑（摘要）

```
1. year = parseStatYear(statYear)
2. statDate = resolveStatDate(year); statDateTime = now(Shanghai)
3. yearStart/end, dayStart/end, sevenStart, window24Start = Support.bounds(...)
4. overview = 三资 SUM + 所选年产量最大月 SUM(meat/milk)
5. activityTrend = Mapper 7日 + buildDailySeries(7, statDate)
6. userStructure = Mapper 新老 + ratio
7. category = Mapper 分类 + total；categoryShare/modelCall/hotTopics = Support.buildCategoryViews(...)
8. hourlyHeat = Mapper 24h + buildHourlySeries(24, statDateTime)
9. sessionReplyDistribution = Mapper 分档 + ratio
10. replyStatusDistribution = Mapper OK/FAIL + ratio
11. topKeywords = Support.extractTopKeywords(Mapper 文本语料, 30)
12. availableYears = distinct session years ∪ current year
13. return AjaxResult.success(vo)
```

---

### 3.2 三资具体问题上报明细

**URI**：`GET /bigScreen/livestockResource/threeAssetsProblemReports`  
**分页**：若依 `startPage()` / `TableDataInfo`（`pageNum`/`pageSize`）  
**排序**：`report_time` 倒序（同表既有 list SQL）

#### Query

| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `statYear` | int | N | 所属年份；**未传不过滤**；传入则按 `report_time` 落在该年 1-1～12-31 |
| `townDeptId` | long | N | 所属乡镇 |
| `villageDeptId` | long | N | 所属村 |
| `pageNum` / `pageSize` | int | N | 分页 |

#### 响应 `rows[]`

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `reportTime` | string | 上报时间 `yyyy-MM-dd HH:mm:ss` |
| `townName` | string | 乡镇 |
| `villageName` | string | 村 |
| `problemLevel` | string | 等级编码 `general`/`key`/`major` |
| `problemLevelName` | string | 等级名称 一般/重点/重大 |
| `problemDetail` | string | 问题详细描述 |
| `handleResult` | string | 处理结果 |

数据源：`biz_three_assets_problem_report`；大屏全县口径（清空 `dataScope`）。

---

### 3.3 畜牧产品产量数据明细

**URI**：`GET /bigScreen/livestockResource/productOutputs`  
**分页**：若依 `startPage()` / `TableDataInfo`（`pageNum`/`pageSize`）  
**排序**：`stat_year`、`stat_month` 倒序（同表既有 list SQL）

#### Query

| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `statYear` | int | N | 所属年份；**未传不过滤（支持跨多年全量翻页）** |
| `statMonth` | int | N | 所属月份；未传不过滤 |
| `townDeptId` | long | N | 所属乡镇 |
| `villageDeptId` | long | N | 所属村 |
| `pageNum` / `pageSize` | int | N | 分页 |

#### 响应 `rows[]`

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `statYear` | int | 所属年份 |
| `statMonth` | int | 所属月份 |
| `townName` | string | 乡镇 |
| `villageName` | string | 村 |
| `meatOutput` | number | 肉产量（万吨），4 位小数 |
| `milkOutput` | number | 奶产量（万吨），4 位小数 |

数据源：`biz_livestock_product_output`；大屏全县口径（清空 `dataScope`）。

---

### 3.4 疫苗接种情况明细

**URI**：`GET /bigScreen/livestockResource/vaccinationData`  
**分页**：若依 `startPage()` / `TableDataInfo`（`pageNum`/`pageSize`）  
**排序**：`stat_year`、`stat_month` 倒序（同表既有 list SQL）

#### Query

| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `statYear` | int | N | 所属年份；**未传不过滤（支持跨多年全量翻页）** |
| `statMonth` | int | N | 所属月份；未传不过滤 |
| `townDeptId` | long | N | 所属乡镇 |
| `villageDeptId` | long | N | 所属村 |
| `pageNum` / `pageSize` | int | N | 分页 |

#### 响应 `rows[]`

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `statYear` | int | 所属年份 |
| `statMonth` | int | 所属月份 |
| `townName` | string | 乡镇 |
| `villageName` | string | 村 |
| `shouldVaccinateCount` | int | 应免数（头） |
| `actualVaccinateCount` | int | 实免数（头） |
| `immunityRate` | number | 免疫率 %，2 位小数；(实免/应免)×100 |

数据源：`biz_vaccination_data`；大屏全县口径（清空 `dataScope`）。

---

### 3.5 兽医数量明细

**URI**：`GET /bigScreen/livestockResource/vetCounts`  
**分页**：若依 `startPage()` / `TableDataInfo`（`pageNum`/`pageSize`）  
**排序**：乡镇部门 `order_num`、`town_dept_id` 升序  
**粒度**：按乡镇汇总人数（非人员明细行）

#### Query

| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `townDeptId` | long | N | 所属乡镇 |
| `pageNum` / `pageSize` | int | N | 分页 |

#### 响应 `rows[]`

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `townName` | string | 乡镇 |
| `vetCount` | long | 数量（人） |

数据源：`biz_medical_resource`；口径 `resource_type='004001'` 且 `del_flag='0'`（与总览兽医人数一致）。

---

## 4. 菜单与权限（示例）

| 类型 | 名称 | 权限标识 |
| --- | --- | --- |
| 菜单 | 大屏畜牧资源 | `bigScreen:livestockResource:query` |

SQL 示例：`sql/big_screen_livestock_resource_perm.sql`（挂载「大屏」父菜单下）。

---

## 5. 交付清单

- [x] `LivestockResourceScreenController` + `ILivestockResourceScreenService` + VO + `LivestockResourceScreenSupport`
- [x] `LivestockResourceScreenMapper` + XML（**§2.6**）
- [ ] `ruoyi-screen` 对接 `GET /bigScreen/livestockResource/dashboard`（本期不改前端）
- [x] 单元测试：历史年今日为 0、7 日补 0、统计日 24 桶、分类占比、耗时含 0
- [x] 接口测试：MockMvc `dashboard`
- [ ] 菜单权限 SQL；依赖 `biz_consult_user`、消息 `cost_time`/`ai_category` 字段已上线

---

## 6. 修订记录

| 版本 | 日期 | 说明 |
| --- | --- | --- |
| 1.17 | 2026-08-18 | 明细分页年份未传一律不过滤：`/threeAssetsProblemReports`、`/productOutputs`、`/vaccinationData` |
| 1.16 | 2026-08-18 | `/productOutputs`、`/vaccinationData`：月份未传不过滤（该年全年）；年份未传仍默认当前年 |
| 1.15 | 2026-07-24 | 新增兽医数量明细分页接口 `/vetCounts`（按乡镇汇总） |
| 1.13 | 2026-07-24 | 新增畜牧产品产量数据明细分页接口 `/productOutputs` |
| 1.12 | 2026-07-24 | 新增三资具体问题上报明细分页接口 `/threeAssetsProblemReports` |
| 1.11 | 2026-07-24 | 看板屏蔽 AI 问诊九区块：活跃度/用户结构/分类/模型调用/分时/会话分布/状态/热门/关键词 |
| 1.10 | 2026-07-24 | 线下服务预约三项汇总改为资源台账：兽医 004001、机构 004003、专家 004005 |
| 1.9 | 2026-07-24 | 线下服务预约月度改为所选年 1～最大月 |
| 1.8 | 2026-07-24 | 实战培训报名改为所选年 1～最大月；前端横轴仅月、悬停显年月 |
| 1.7 | 2026-07-24 | 迁入线下预约/农技课堂/实战培训；新增科技特派员双层结构、农业事业单位职级柱图 |
| 1.6 | 2026-07-24 | 新增农村三资/问题上报/产量趋势/疫苗接种四区块 |
| 1.5 | 2026-07-24 | 核心总览扩展为 8 项：增免疫率、兽医、科技特派员、农业事业单位 |
| 1.4 | 2026-07-24 | 核心总览改为三资固定资产 + 所选年最大月肉/奶产量 |
| 1.0 | 2026-05-20 | 初稿：无新表；单接口十区块；对齐 `大屏畜牧资源功能需求.md` v1.1 |
| 1.2 | 2026-05-20 | 对齐草稿：今日活跃 `update_time`、日新增双时间、AI 回复+分类归因、统计日 0～23 时分、`create_time` 消息归属 |
