# 大屏 — 首页统计 — 技术方案

> 依据：同目录 `大屏首页功能需求.md`；数据来自养殖产业、流通交易、服务预约、补贴发放、养殖标准五类子表、科技资源与实战培训等**既有表**。本模块为**大屏只读看板**，无业务台账 CRUD。

---

## 1. 技术架构

| 项 | 说明 |
| --- | --- |
| **后端** | RuoYi **v3.9.2**（**springboot2** 分支）：JDK 8、Spring Boot 2.x、Spring MVC、MyBatis、Druid |
| **数据库** | MySQL **5.7.39**，InnoDB，`utf8mb4` |
| **前端** | 大屏独立首页（`ruoyi-screen`）；**切换 `statYear`** 拉看板主数据，养殖标准**分页**单独请求；存栏变动/出栏统计图表见 **§4.1** |
| **代码包** | `com.ruoyi.web.modules.screen`（`HomeScreenController` / `IHomeScreenService` / `vo` / `support`） |

**分层**：`Controller` → `IHomeScreenService`（口径编排、按 **Y** 计算统计日）→ 扩展 Mapper / 复用 `BreedingIndustryStatsMapper` + `BreedingIndustryCalculator`（只读）。

| 场景 | 行为 |
| --- | --- |
| 进入 / 切换 `statYear` | 调用 **§3.1** + **§3.2**（`pageNum=1`） |
| 标准列表翻页 / 切 Tab | 仅 **§3.2** |
| 数据权限 | **全县**聚合：牦牛、牧场取全部 `biz_status=1` 且 `del_flag=0` 的牧场 ID（与疫病风险大屏一致，**不按**登录用户牧场过滤）；草场全县 `del_flag=0` |
| 统计日 | `Y = 当前年` → `statDate = 今日`；`Y` 为历史年 → `statDate = Y-12-31`（时点、月末还原、年出栏上界均据此） |
| 主数据三项 | 供应商 / 承销商 / 交易市场**实时快照**，**不**随 `statYear` 变 |
| 滚动 12 月图表 | 存栏变动、出栏统计、预约堆叠、培训趋势；锚点 = 当前 `YearMonth`；**不**随 `statYear` 变 |
| 按月图表（Y 年内） | 已无（预约/培训已并入滚动 12 月） |
| 性能 | 默认实时聚合；可选 **§2.3** 缓存表 |

**依赖表（只读）**

| 表 | 用途 |
| --- | --- |
| `biz_yak_asset` / `biz_pasture` / `biz_grassland` | 产业总览、存栏趋势、年龄结构、出栏、草场 |
| `biz_supplier` / `biz_distributor` / `biz_trade_market` | 流通主数据条数（实时） |
| `biz_service_appointment` | 线下服务预约 |
| `biz_subsidy_grant_record` | 惠农补贴 |
| `biz_breeding_standard` 等 5 张标准表 | 养殖标准分页列表 |
| `biz_tech_resource` | 视频课程（`004008`） |
| `biz_practical_training` | 实战培训场次与报名趋势 |
| `biz_yak_herd_inventory` | 产业总览存栏（所选年最大月）、存栏变动、年龄结构、地图标注 |
| `biz_yak_outbound_report` | 产业总览出栏（所选年最大月）、出栏统计、地图标注 |
| `biz_farmer_household` | 产业总览农牧户（所选年最大月全县村级 `household_count` 合计） |
| `biz_cooperative_development` | 产业总览合作社（所选年最大月记录条数） |
| `biz_family_ranch` | 产业总览家庭牧场（所选年最大月记录条数） |
| `biz_large_livestock_farmer` | 产业总览养殖大户（所选年最大月记录条数） |
| `biz_livestock_ownership_household` | 产业总览有畜户数（所选年最大月 `with_livestock_household_count` 合计） |
| `sys_dept` | 地图标注 — 乡镇列表（`parent_id=100` 且 `order_num>12`） |

---

## 2. 数据库设计

### 2.1 本模块业务表

**无新增业务台账表。** DDL 以各业务 `sql/*.sql` 为准。

### 2.2 公共参数

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

| 边界 | 表达式 |
| --- | --- |
| 年区间起 | `Y-01-01 00:00:00` |
| 年区间止（年内累计） | `Y` 为当前年：`statDate 23:59:59`；历史年：`Y-12-31 23:59:59` |
| 按月分组键 | `MONTH(日期字段)`，应用层补全 1～12 |

### 2.3 可选表 `biz_home_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 查询口径（按表）

#### 牦牛填报（大屏首页存栏/出栏/年龄/趋势/地图）

| 指标 | 要点 |
| --- | --- |
| 所选年最大填报月 | `stat_year = Y` 时 `MAX(stat_month)`；存栏 / 出栏 / 农牧户表**可不同月**；产业总览三项、地图标注用此口径 |
| 最近填报年月 | 全库 `MAX(stat_year, stat_month)`；存栏变动/年龄用此口径（若已改为所选年则见对应章节） |
| 产业总览三项 | 所选年最大月全县 `yak_total` / `yak_outbound_count` / `farmer_household_count` |
| 存栏变动 header | 最近年月全县 `bull_total`、`cow_total`、`yak_total` |
| 滚动 12 月存栏趋势 | `biz_yak_herd_inventory` 按 `stat_year+stat_month` 全县 `bull_total`/`cow_total` 合计 |
| 滚动 12 月出栏 | `biz_yak_outbound_report` 按 `stat_year+stat_month` 全县 `yak_outbound_count` 合计 |
| 年龄结构 | 最近年月母牛两档：`cow_young_count`（0～1.5 岁）、`cow_adult_count`（1.5 岁以上） |
| 地图标注 | 所选年各自最大填报月下，按乡镇 `SUM(yak_total)` / `SUM(yak_outbound_count)` |

#### 养殖产业档案（草场等，复用 Mapper）

实现复用 `BreedingIndustryStatsMapper`；大屏传入**全县** `allowedPastureIds`（全部正常牧场 ID）。

| 指标 | 要点 |
| --- | --- |
| 草场 | `del_flag=0`；面积 `SUM(area_mu)`；可用/使用中/退化分组同养殖产业 |

> 首页**不含**预警牦牛；不查 `biz_yak_disease_warning`。

#### 流通主数据（**实时**，与 **Y** 无关）

| 表 | 指标 | 条件 |
| --- | --- | --- |
| `biz_supplier` | 供应商数 | `del_flag='0'` |
| `biz_distributor` | 承销商数 | `del_flag='0'` |
| `biz_trade_market` | 交易市场数 | `del_flag='0'` AND `operate_status=1` |

#### 服务预约 `biz_service_appointment`

| 项 | 条件 |
| --- | --- |
| 按年 | `appoint_date >= Y-01-01` AND `appoint_date <= Y-12-31` |
| 状态 | `status NOT IN (2,3)`（排除已拒绝、已取消）；表无 `del_flag` |
| 分类 | `provider_type`：`1` 兽医 → 展示「兽医人员」；`3` 专家 →「专家人员」；`2` 机构 →「诊疗机构」 |
| 统计 | 每条记录计 **1** 人次；年度卡片为三类合计；按月 `GROUP BY MONTH(appoint_date), provider_type` |

#### 补贴发放 `biz_subsidy_grant_record`

| 项 | 条件 |
| --- | --- |
| 按年 | `grant_date` 在 **Y** 年内（含起止日） |
| 分组 | `subsidy_type`：`1` 农业生产、`2` 住房基建、`3` 民生保障 |
| 指标 | `SUM(subsidy_amount)`；服务端换算 **万元**（÷10000，保留 2 位小数） |

#### 农技课堂

| 指标 | 表 | 条件 |
| --- | --- | --- |
| 课程视频数 | `biz_tech_resource` | `del_flag='0'` AND `publish_status=1` AND `resource_type='004008'` AND `publish_time` 落在 **Y** 年 |
| 实战培训场次 | `biz_practical_training` | `del_flag='0'` AND `publish_status=1` AND `publish_time` 落在 **Y** 年 |
| 培训内容合计 | — | 视频数 + 场次数（应用层相加） |

#### 实战培训报名趋势 `biz_practical_training`

| 系列 | 条件 |
| --- | --- |
| 活动数/月 | `del_flag='0'` AND `publish_status=1` AND `YEAR(training_time)=Y` AND `MONTH(training_time)=m` → `COUNT(*)` |
| 报名人数/月 | 同上月的培训行，`SUM(actual_enrolled_count)` |
| 无培训 | `hasTrainingData=false`（**§3.1**），前端走空态，**不**强行全 0 曲线 |

#### 养殖标准（分页，**§3.2**）

**纳入**：`publish_status=1`；`DATE(create_time)` 落在 **Y** 年内（与功能需求 **§2.9** 一致）。

**Tab → 物理表与 `standard_type` 白名单**

| `category`（请求枚举） | 表 | `standard_type IN` |
| --- | --- | --- |
| `BREEDING_MGMT` | `biz_breeding_standard` | `001001`,`001002`,`001003`,`001004` |
| `FEEDING` | `biz_feeding_standard` | `001005`,`001006` |
| `EQUIPMENT` | `biz_equipment_work_standard` | `001007`,`001008`,`001009`,`001010` |
| `TREATMENT` | `biz_epidemic_treatment_standard` | `001013` |
| `GROWTH` | `biz_growth_slaughter_standard` | `001011`,`001012` |

排序：`create_time DESC, id DESC`。

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

| 表 | 建议 |
| --- | --- |
| `biz_yak_asset` | `(pasture_id, del_flag, asset_status)`、`status_change_date` |
| `biz_service_appointment` | 沿用 `idx_appoint_date`、`idx_provider` |
| `biz_subsidy_grant_record` | 沿用 `idx_grant_date`、`idx_subsidy_type` |
| `biz_tech_resource` | `(resource_type, publish_status, publish_time)` |
| `biz_practical_training` | 沿用 `idx_training_time`、`idx_publish` |
| 各 `biz_*_standard` | 沿用 `idx_create_time`、`idx_type` |

### 2.6 Mapper 扩展（建议）

| Mapper | 方法 | 说明 |
| --- | --- | --- |
| `HomeScreenStatsMapper` | `selectLatestHerdInventoryStatPeriodByYear`、`selectLatestOutboundReportStatPeriodByYear`、`selectLatestFarmerHouseholdStatPeriodByYear`、`sumFarmerHouseholdCountByStatYearMonth`、`selectLatestHerdInventoryStatPeriod`、`selectLatestOutboundReportStatPeriod`、`selectHerdInventoryBullCowByYearMonthRange`、`selectOutboundReportYakCountByYearMonthRange`、`selectTownMapMarkers` 等 | 填报表聚合 |
| `BreedingIndustryStatsMapper` | （复用） | 草场统计 |
| `BizSupplierMapper` / `BizDistributorMapper` / `BizTradeMarketMapper` | `countForScreen()` | 主数据条数 |
| `BizServiceAppointmentMapper` | `selectStatsByYear(int y)` | 返回 appoint_date、provider_type 明细或按月聚合行 |
| `BizSubsidyGrantRecordMapper` | `sumAmountByTypeForYear(int y)` | 三类金额 |
| `BizTechResourceMapper` | `countPublishedVideoByYear(int y)` | `004008` |
| `BizPracticalTrainingMapper` | `countPublishedByYear` / `selectPublishedByYear` | 场次与按月趋势 |
| `HomeScreenStandardMapper` | `selectListForScreen(category, y, ...)` | 按 **§2.4** Tab 路由到对应表 |

> 大屏首页牦牛趋势/出栏**不**调用 `BreedingIndustryCalculator` 月末还原；填报缺月由 `HomeScreenSupport.buildRolling12Month*` 补 0。

---

## 3. 接口设计

**统一响应**：`AjaxResult`（`code` / `msg` / `data`）；标准列表用 `TableDataInfo`（`rows` / `total`）。

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

**Base Path**：`/bigScreen/home`

| # | 说明 | Method | URI | 权限 |
| --- | --- | --- | --- | --- |
| 3.1 | 看板主数据（除标准分页外全部区块） | GET | `/bigScreen/home/dashboard` | `bigScreen:home:query` |
| 3.2 | 养殖标准分页列表 | GET | `/bigScreen/home/standards` | 同上 |
| 3.3 | 地图标注（乡镇存栏/出栏） | GET | `/bigScreen/home/townMapMarkers` | 同上 |
| 3.4 | 草畜失衡预警明细 | GET | `/bigScreen/home/grassLivestockImbalanceWarnings` | 同上 |
| 3.5 | 人均收入情况明细 | GET | `/bigScreen/home/perCapitaIncomes` | 同上 |
| 3.6 | 农牧户数据明细（**草场面积明细复用本接口**） | GET | `/bigScreen/home/farmerHouseholds` | 同上 |
| 3.7 | 合作社发展数据明细 | GET | `/bigScreen/home/cooperativeDevelopments` | 同上 |
| 3.8 | 家庭牧场数据明细 | GET | `/bigScreen/home/familyRanches` | 同上 |
| 3.9 | 养殖大户数据明细 | GET | `/bigScreen/home/largeLivestockFarmers` | 同上 |
| 3.10 | 牦牛出栏数据明细 | GET | `/bigScreen/home/yakOutboundReports` | 同上 |
| 3.11 | 牦牛存栏数据明细 | GET | `/bigScreen/home/yakHerdInventories` | 同上 |
| 3.12 | 有无畜户数据明细 | GET | `/bigScreen/home/livestockOwnershipHouseholds` | 同上 |
| 3.13 | 牦牛存出栏情况明细 | GET | `/bigScreen/home/yakInventoryOutbounds` | 同上 |
| 3.14 | 养殖主体数量明细 | GET | `/bigScreen/home/breedingEntityQuantities` | 同上 |
| 3.15 | 乡镇列表 | GET | `/bigScreen/home/townOptions` | 同上 |
| 3.16 | 村树结构 | GET | `/bigScreen/home/villageTree` | 同上 |

前端：切换 `statYear` → **3.1** + **3.2**（`pageNum=1`）+ **3.3**；仅翻页 / 切 Tab → **3.2**；进入首页 → **3.1** + **3.2** + **3.3**。

---

### 3.1 看板主数据

#### Query

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

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

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `statYear` | int | 回显 |
| `statDate` | string | 统计时点 `yyyy-MM-dd` |
| `availableYears` | int[] | 各业务表出现过的年份并集 + 当前年，降序 |
| `industryOverview` | object | 产业总览八项 **§3.1.1** |
| `ageStructure` | array | 年龄结构 **§3.1.3** |
| `herdInventoryStructure` | array | 畜群存栏结构 |
| `yakInventoryStructure` | array | 牦牛存栏结构 |
| `livestockOutboundStructure` | array | 牲畜出栏结构 |
| `selfConsumption` | object | 自食情况 |
| `familyRanchFinance` / `largeLivestockFarmerFinance` | object | 企业年度收入与补助 |
| `cooperativeBusinessModel` | array | 合作社经营模式分类 |
| `townSubsidyTotals` | array | 各乡镇补助合计：`townDeptId` / `townName` / `subsidyTotal`（所选年最大填报月，村级 `subsidy_total` 按乡镇求和；单位元） |
| ~~`farmerHouseholdClassification`~~ | ~~array~~ | ~~农牧户分类（本期不返回）~~ |
| `perCapitaIncomeTrend` | array | 人均收入近 5 年 |

> **已屏蔽（不再返回）：** `inventoryChange`（牦牛存栏变动）、`outboundMonthly`（牦牛出栏月度）、`grassland`（草场类型占比）、`subsidy`（惠农补贴发放）；产业总览内 `supplierCount`/`distributorCount`/`tradeMarketCount`/`grasslandCount`；以及此前迁出的预约/农技课堂/培训。

#### 3.1.1 `industryOverview`

| 字段 | 说明 |
| --- | --- |
| `inventoryTotal` | 牦牛存栏（头），所选年 **Y** 内最大填报月全县村级 `yak_total` 合计 |
| `annualOutbound` | 年出栏（头），所选年 **Y** 内最大填报月全县村级 `yak_outbound_count` 合计 |
| `pastureCount` | 农牧户（户），所选年 **Y** 内 `biz_farmer_household` 最大填报月全县村级 `household_count` 合计 |
| `cooperativeCount` | 合作社（个），所选年 **Y** 内 `biz_cooperative_development` 最大填报月记录条数 |
| `familyRanchCount` | 家庭牧场（个），所选年 **Y** 内 `biz_family_ranch` 最大填报月记录条数 |
| `largeLivestockFarmerCount` | 养殖大户（个），所选年 **Y** 内 `biz_large_livestock_farmer` 最大填报月记录条数 |
| `withLivestockHouseholdCount` | 有畜户数（户），所选年 **Y** 内 `biz_livestock_ownership_household` 最大填报月全县村级 `with_livestock_household_count` 合计 |
| `grasslandAreaMu` | 草场面积（亩），所选年 **Y** 内 `biz_farmer_household` 最大填报月全县村级 `pasture_contract_area` 合计 |

> **已屏蔽（不再返回）：** `grasslandCount`、`supplierCount`、`distributorCount`、`tradeMarketCount`。

#### 3.1.2 `inventoryChange`（已屏蔽）

| 字段 | 说明 |
| --- | --- |
| `bullCount` / `cowCount` / `unknownGenderCount` | 存栏表**最近填报年月**全县公/母/`yak_total` 合计 |
| `monthlyTrend` | 所选年填报**最大月 N** → 输出 **N** 条（1～N）；区间内缺月补 0；无填报为空 |

`monthlyTrend[]`：

| 字段 | 说明 |
| --- | --- |
| `statYear` | 所属自然年 |
| `month` | 所属月份 1～12 |
| `bullCount` / `cowCount` | 该 `statYear-month` 全县填报合计；无数据为 **0** |

#### 3.1.3 `ageStructure[]`

| 字段 | 说明 |
| --- | --- |
| `bandCode` | `COW_YOUNG` / `COW_ADULT` |
| `bandLabel` | `0～1.5岁幼畜` / `1.5岁以上成畜` |
| `count` / `ratio` | 头数；占比 **0～100** 数值 |

两档固定返回；无存栏时 `count=0`，`ratio=0`。对齐存栏填报 `cow_young_count` / `cow_adult_count`。

#### 3.1.4 `outboundMonthly[]`

| 字段 | 说明 |
| --- | --- |
| `statYear` | 所属自然年 |
| `month` | 所属月份 1～12 |
| `outboundCount` | 该月全县出栏头数；区间内无填报为 **0** |

所选年填报**最大月 N** → 输出 **N** 条（1～N）；区间内缺月补 0；无填报为空。规则同 **§3.1.2** `monthlyTrend`。

#### 3.1.5 `grassland`

| 字段 | 说明 |
| --- | --- |
| `availableCount` / `inUseCount` | 可用 / 使用中（个） |
| `degradationStats[]` | `degradationLevel`(1～5)、`degradationLabel`、`count`、`ratio`（% 数值） |

五档固定返回。

#### 3.1.6 `appointment`

| 字段 | 说明 |
| --- | --- |
| `annualVetCount` / `annualExpertCount` / `annualOrgCount` | 三类年度合计 |
| `monthlyStacked[]` | 固定 **12** 条；滚动最近 12 自然月；**不**随 `statYear` 变 |

`monthlyStacked[]`：`statYear`、`month`、`vetCount`、`expertCount`、`orgCount`（缺月各计数为 **0**）。

#### 3.1.7 `subsidy`

| 字段 | 说明 |
| --- | --- |
| `typeStats[]` | 固定 3 条：`subsidyType`(1～3)、`subsidyTypeName`、`amountWan`（万元） |
| `hasSubsidyData` | **Y** 年是否存在任一条发放记录 |

#### 3.1.8 `agriClassroom`

| 字段 | 说明 |
| --- | --- |
| `videoCourseCount` | 视频课程数 |
| `practicalTrainingCount` | 实战培训场次 |
| `trainingContentTotal` | 二者之和 |
| `hasAgriData` | 两项是否均为 0 |

#### 3.1.9 `trainingTrend`

| 字段 | 说明 |
| --- | --- |
| `hasTrainingData` | 滚动 12 月窗口内是否存在已发布且 `training_time` 落在窗口内的培训 |
| `monthly[]` | 固定 **12** 条；`statYear`、`month`、`activityCount`、`enrolledCount` |

`hasTrainingData=false` 时 `monthly` 仍为 12 条全 0（前端以 `hasTrainingData` 走空态）。

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

```json
{
  "statYear": 2026,
  "statDate": "2026-05-20",
  "availableYears": [2026, 2025],
  "industryOverview": {
    "inventoryTotal": 120,
    "annualOutbound": 8,
    "pastureCount": 12,
    "grasslandCount": 80,
    "grasslandAreaMu": 12500.50,
    "supplierCount": 5,
    "distributorCount": 3,
    "tradeMarketCount": 2
  },
  "inventoryChange": {
    "bullCount": 45,
    "cowCount": 60,
    "unknownGenderCount": 15,
    "monthlyTrend": [
      { "statYear": 2025, "month": 8, "bullCount": 40, "cowCount": 55 },
      { "statYear": 2026, "month": 7, "bullCount": 45, "cowCount": 60 }
    ]
  },
  "outboundMonthly": [
    { "statYear": 2025, "month": 8, "outboundCount": 0 },
    { "statYear": 2026, "month": 5, "outboundCount": 88 }
  ],
  "appointment": {
    "annualVetCount": 10,
    "annualExpertCount": 5,
    "annualOrgCount": 8,
    "monthlyStacked": [{ "month": 1, "vetCount": 2, "expertCount": 1, "orgCount": 0 }]
  },
  "trainingTrend": { "hasTrainingData": true, "monthly": [{ "month": 3, "activityCount": 1, "enrolledCount": 20 }] }
}
```

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

```
1. year = parseStatYear(statYear); statDate = resolveStatDate(year)
2. anchor = YearMonth.now(Asia/Shanghai); startYm/endYm = 锚点向前 11 月～锚点（yyyyMM）
3. latestHerd / latestOutbound = 各表最近 stat_year+stat_month
4. industryOverview 三项 = 最近年月全县合计（与 year 无关）
5. inventoryChange header + ageStructure = latestHerd 年月全县合计
6. monthlyTrend = buildRolling12MonthBullCowTrend(selectHerd...Range(startYm,endYm), anchor)
7. outboundMonthly = buildRolling12MonthOutbound(selectOutbound...Range(startYm,endYm), anchor)
8. grassland / tradeCounts / appointment / subsidy / agri / training = 按 year 或实时（同前）
9. return AjaxResult.success(vo)
```

---

### 3.2 养殖标准分页列表

#### Query

| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `statYear` | string | Y | 同 **3.1** |
| `category` | string | Y | `BREEDING_MGMT` / `FEEDING` / `EQUIPMENT` / `TREATMENT` / `GROWTH` |
| `pageNum` | int | N | 默认 `1` |
| `pageSize` | int | N | 默认 `10`；建议 **5～10** |

#### 响应

`TableDataInfo`：`rows` 为 **§3.2.1** 数组，`total` 为当前 Tab 下符合条件的总数。

**不提供**大屏专用 `GET /standards/{id}`；行内详情字段一次返回（对齐共同富裕列表约定）。

#### 3.2.1 `rows[]`

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `id` | long | 标准 ID |
| `standardName` | string | 标准名称 |
| `standardType` | string | 类型编码 |
| `standardTypeName` | string | 类型展示名（字典/资讯类别） |
| `introduction` | string | 简介 |
| `contentFileUrl` | string | 正文附件 URL |
| `coverFileUrl` | string | 封面 URL，可空 |
| `createTime` | string | 创建时间 |
| `publishTime` | string | 发布时间 |

默认排序：`create_time DESC, id DESC`。

---

### 3.3 地图标注

#### Query

| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `statYear` | string | 是 | 统计年份 **Y**，如 `2026` |

存栏/出栏各取所选年内**最大 `stat_month`**（两表可不同月）：

| 字段 | 说明 |
| --- | --- |
| `herdStatYear` / `herdStatMonth` | 存栏表所选年内最大填报年月 |
| `outboundStatYear` / `outboundStatMonth` | 出栏表所选年内最大填报年月 |

#### 响应 `data`

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `herdStatYear` | int | 存栏数据填报年（可空） |
| `herdStatMonth` | int | 存栏数据填报月（可空） |
| `outboundStatYear` | int | 出栏数据填报年（可空） |
| `outboundStatMonth` | int | 出栏数据填报月（可空） |
| `markers` | array | 乡镇标注列表，见下表 |

`markers[]`：

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `townDeptId` | long | 所属乡镇 `dept_id`（`sys_dept`） |
| `townName` | string | 乡镇名称 |
| `yakInventoryCount` | int | 牦牛存栏数（头），该乡镇下各村 `yak_total` 合计；无填报为 **0** |
| `yakOutboundCount` | int | 牦牛出栏数（头），该乡镇下各村 `yak_outbound_count` 合计；无填报为 **0** |

#### 乡镇范围

与牦牛存栏/出栏填报模块一致：`sys_dept` 中 `parent_id = 100`、`order_num > 12`、`del_flag = '0'`、`status = '0'`，按 `order_num`、`dept_id` 升序。

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

```
1. year = parseStatYear(statYear)
2. yearHerd = selectLatestHerdInventoryStatPeriodByYear(year)
3. yearOutbound = selectLatestOutboundReportStatPeriodByYear(year)
4. markers = selectTownMapMarkers(herdYear, herdMonth, outboundYear, outboundMonth)
   （按 town_dept_id 汇总各村合计；无年月时该侧为 0）
5. return AjaxResult.success(vo)
```

---

### 3.5 人均收入情况明细

#### Query

| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `statYear` | int | N | 所属年份；**未传不过滤（跨年按年倒序）** |
| `pageNum` / `pageSize` | int | N | 分页（PageHelper） |

排序：`stat_year DESC, id DESC`。

数据源：`biz_disposable_income`。

#### 响应 `rows[]`

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `statYear` | int | 年份 |
| `ruralDisposableIncome` | decimal | 农村居民人均可支配收入（元） |
| `incomeIncrease` | decimal | 增幅（元） |
| `incomeGrowthRate` | decimal | 增速（%） |
| `povertyNetIncome` | decimal | 脱贫人口人均纯收入（元） |

---

### 3.6 农牧户数据明细（草场面积明细复用）

> **草场面积数据明细**不另开接口，直接调用本接口；产业总览草场面积取自同表 `pasture_contract_area`（全县最大月合计），明细行内字段为 `pastureContractArea`（及禁牧/草畜平衡等面积相关列）。

#### Query

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

排序：`stat_year DESC, stat_month DESC, …`（与填报列表一致）。

数据源：`biz_farmer_household`（全县口径，清空 dataScope）。

#### 响应 `rows[]`

返回填报全部业务字段，含：`id`、`statYear`、`statMonth`、`townDeptId`、`townName`、`villageDeptId`、`villageName`、`householdCount`、`populationCount`、`pastureContractArea`、`grazingBanArea`、`grassBalanceArea`、`approvedCarryingCapacity`、`yearEndStockSheepUnit`、`isPureHerder`、`isNoLivestock`、`isExtinctHousehold`、`isOverloadHerder`、`needCap`、`needFloor`、`grazingBanSubsidy`、`grassBalanceReward`、`subsidyRewardSubtotal`、`afterCapFloorSubsidy`、`villageSupervisorSubsidy`、`subsidyTotal`。

---

### 3.7～3.9 合作社 / 家庭牧场 / 养殖大户数据明细

#### Query（三者相同）

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

排序：`stat_year DESC, stat_month DESC, …`（与各自填报列表一致）。全县口径，清空 `dataScope`。

| # | URI | 数据源 | 响应 |
| --- | --- | --- | --- |
| 3.7 | `/cooperativeDevelopments` | `biz_cooperative_development` | 全部业务字段（含 `cooperativeName`、`businessModel` 等） |
| 3.8 | `/familyRanches` | `biz_family_ranch` | 全部业务字段（含 `enterpriseName`、收入支出补助等） |
| 3.9 | `/largeLivestockFarmers` | `biz_large_livestock_farmer` | 全部业务字段（含 `enterpriseName`、存栏出栏草场等） |
| 3.10 | `/yakOutboundReports` | `biz_yak_outbound_report` | 全部业务字段（含出栏六畜、自食三项等） |
| 3.11 | `/yakHerdInventories` | `biz_yak_herd_inventory` | 全部业务字段（含公母牛/奶牛/羊/保险等） |
| 3.12 | `/livestockOwnershipHouseholds` | `biz_livestock_ownership_household` | 全部业务字段（有畜/无畜户数人数劳动力等） |

查询条件与 3.6 相同：年/月未传不过滤，乡镇/村可选；按年、月倒序；全县口径清空 dataScope。

### 3.13 牦牛存出栏情况明细

#### Query

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

关联：`biz_yak_herd_inventory` 为主表 `LEFT JOIN` `biz_yak_outbound_report`（唯一键 `(stat_year, stat_month, village_dept_id)`），`UNION ALL` 补仅出栏侧有数据的行；缺一侧时对应计数为 0。

排序：`stat_year DESC, stat_month DESC, town_dept_id ASC, village_dept_id ASC`（对齐唯一键，利于索引序）。

性能说明：条件下推至基表；关联走 `uk_year_month_village`；跨年全量时仍建议控制 `pageSize`，超深 offset 会随页码增大变慢。

#### 响应 `rows[]`

| 字段 | 说明 |
| --- | --- |
| `statYear` / `statMonth` | 年份、月份 |
| `townDeptId` / `townName` | 乡镇 |
| `villageDeptId` / `villageName` | 村 |
| `yakTotal` | 牦牛总存栏数（头） |
| `yakOutboundCount` | 牦牛总出栏数（头） |

### 3.14 养殖主体数量明细

#### Query

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

关联：村×年月键集 = `biz_farmer_household` ∪ `biz_cooperative_development` ∪ `biz_family_ranch` ∪ `biz_large_livestock_farmer`（以 `(stat_year, stat_month, village_dept_id)` 为键）。合作社/家庭牧场/养殖大户为农牧户不同组织形式；**任一形式有填报即可出列，其余数量为 0**。

排序：`stat_year DESC, stat_month DESC, town_dept_id ASC, village_dept_id ASC`。

性能：四表键集 UNION + 分组计数 JOIN（走各表村年月唯一/索引）；PageHelper 对结果集分页，支持跨多年全量翻页。

#### 响应 `rows[]`

| 字段 | 说明 |
| --- | --- |
| `statYear` / `statMonth` | 年份、月份 |
| `townDeptId` / `townName` | 乡镇 |
| `villageDeptId` / `villageName` | 村 |
| `farmerHouseholdCount` | 农牧户数（户） |
| `cooperativeCount` | 合作社（个） |
| `familyRanchCount` | 家庭牧场（个） |
| `largeLivestockFarmerCount` | 养殖大户（个） |

### 3.15 乡镇列表

无 Query。响应 `data[]`：`deptId`、`deptName`、`orderNum`。全县填报乡镇（与地图标注乡镇口径一致），**不按**登录人数据权限收窄。

### 3.16 村树结构

无 Query。响应 `data[]` 为 `TreeSelect`：县（根）→ 乡镇 → 村；仅叶子村为筛选目标。全县口径。

---

## 4. 前端实现要点

**工程**：`ruoyi-screen/src/views/home/`（`index.vue`、`chartOptions.js`）。

### 4.1 滚动 12 月图表（存栏 / 出栏 / 预约 / 培训）

| 项 | 实现 |
| --- | --- |
| 数据字段 | `monthlyTrend[]`、`outboundMonthly[]`、`appointment.monthlyStacked[]`、`trainingTrend.monthly[]` |
| 排序 | 按 `statYear`、`month` 升序 |
| 横轴 | **仅月份**（`8月`）；`chartOptions.js` |
| Tooltip | **完整年月**（`2025年8月`）+ 数值 |
| 与 `statYear` | 切换年份**不**改变上述图表数据窗口 |

---

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

| 类型 | 名称 | 权限标识 |
| --- | --- | --- |
| 菜单 | 大屏首页 | `bigScreen:home:query` |

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

---

## 6. 交付清单

- [ ] `HomeScreenController` + `IHomeScreenService` + VO + `HomeScreenSupport`
- [ ] 复用 `BreedingIndustryStatsMapper` / `BreedingIndustryCalculator`（按 **Y** 与全县牧场）
- [ ] 预约、补贴、标准、科技资源、实战培训 Mapper 扩展（**§2.6**）
- [ ] 单元测试：滚动 12 月补 0、`statYear`+`month`、主数据不随 **Y** 变、地图所选年最大填报月
- [ ] 接口测试：`/bigScreen/home/dashboard`、`/standards`、`/townMapMarkers`
- [ ] 菜单权限 SQL；依赖各业务表 DDL 已执行

---

## 7. 修订记录

| 版本 | 日期 | 说明 |
| --- | --- | --- |
| 1.26 | 2026-08-18 | 屏蔽 `farmerHouseholdClassification`；新增看板 `townSubsidyTotals`（所选年最大月按乡镇汇总 `subsidy_total`） |
| 1.25 | 2026-08-18 | 首页明细分页：年份未传一律不过滤（跨年全量翻页）；含人均收入/农牧户/合作社/家庭牧场/养殖大户/出栏/存栏/有无畜户 |
| 1.24 | 2026-08-18 | 首页明细分页：月份未传一律不过滤；含合作社/家庭牧场/养殖大户/出栏/存栏/有无畜户（农牧户已在 1.23） |
| 1.23 | 2026-08-18 | `/farmerHouseholds`：月份未传不过滤（该年全年按月倒序）；年份未传仍默认当前年 |
| 1.21 | 2026-07-24 | 看板屏蔽：`subsidy`、`grassland`、`outboundMonthly`、`inventoryChange` |
| 1.20 | 2026-07-24 | 人均收入 `perCapitaIncomeTrend`：以库中最大所属年为终点向前 5 年 |
| 1.19 | 2026-07-24 | 出栏 `outboundMonthly`：按填报最大月 N 输出 1～N |
| 1.18 | 2026-07-23 | 公母牛 `monthlyTrend`：按填报最大月 N 输出 1～N |
| 1.17 | 2026-07-23 | 新增大屏 `/townOptions`、`/villageTree`（全县口径） |
| 1.16 | 2026-07-23 | 新增养殖主体数量明细分页接口 `/breedingEntityQuantities` |
| 1.15 | 2026-07-23 | `/yakInventoryOutbounds`：年月未传不过滤；SQL 改为存栏主表 LEFT JOIN + UNION ALL 补仅出栏 |
| 1.14 | 2026-07-23 | 新增牦牛存出栏情况明细分页接口 `/yakInventoryOutbounds` |
| 1.13 | 2026-07-23 | 明确草场面积数据明细复用 `/farmerHouseholds`，不另开接口 |
| 1.12 | 2026-07-23 | 新增牦牛出栏/存栏、有无畜户明细分页接口 |
| 1.11 | 2026-07-23 | 新增合作社/家庭牧场/养殖大户明细分页接口 |
| 1.10 | 2026-07-23 | 新增农牧户数据明细分页接口 `/farmerHouseholds`（默认当前年月、按时间倒序） |
| 1.9 | 2026-07-23 | 新增人均收入情况明细分页接口 `/perCapitaIncomes`（默认当前年、按年倒序） |
| 1.8 | 2026-07-23 | 地图标注改为所选年最大填报月按乡镇汇总；`townMapMarkers` 增 `statYear` 与填报月字段 |
| 1.7 | 2026-07-23 | 有畜户数、草场面积改为填报表所选年最大月合计 |
| 1.6 | 2026-07-23 | 产业总览增合作社/家庭牧场/养殖大户（所选年最大填报月记录数） |
| 1.5 | 2026-07-23 | 产业总览农牧户改 `biz_farmer_household` 所选年最大填报月村级合计 |
| 1.4 | 2026-07-23 | 产业总览存栏/出栏改为所选年最大填报月全县村级合计 |
| 1.3 | 2026-07-17 | 年龄结构两档 `COW_YOUNG`/`COW_ADULT`，字段 `cow_young_count`/`cow_adult_count` |
| 1.2 | 2026-07-04 | 预约堆叠、培训趋势改滚动 12 月 + statYear；前端横轴/Tooltip 与存栏出栏一致 |
| 1.1 | 2026-07-04 | 存栏/出栏改填报表滚动 12 月；VO 增 `statYear`；年龄四档；地图/总览最近填报年月；§4 前端横轴/Tooltip |
| 1.0 | 2026-05-20 | 初稿：无新表；双接口；对齐 `大屏首页功能需求.md` v1.0 |
