# 牦牛存栏数据填报 — 功能需求

## 1. 文档说明

| 项 | 说明 |
| --- | --- |
| 模块名称 | 牦牛存栏数据填报 |
| 目标 | 按**村 × 所属年月**填报、导入、维护县域牦牛存栏畜群结构统计数据，**每月导入一次**当月存栏；支撑养殖产业看板、监管报表及历史对比 |
| 关联系统 | 业务后台（增删改查、Excel 导入/导出）；组织机构 `sys_dept`（乡镇、村） |
| 修订依据 | 业务模板 `牦牛存栏数据填报.xlsx` / `yak_herd_inventory_import_template.xlsx`；按村填报与交接表字段对齐 |

本文档仅描述**功能需求与业务规则**，不涉及库表字段命名、接口路径、技术栈选型及实现细节（见同目录技术方案）。

---

## 2. 术语与统计口径

### 2.1 填报粒度

- 一条记录表示：**某一自然年、某一自然月、某一行政村**的牦牛存栏汇总数据。  
- 保存时根据所选村反推**所属乡镇**并冗余存储乡镇名称。  
- 同一「所属年份 + 所属月份 + 所属村」在系统中**仅允许一条记录**（物理删除后可重新填报）。  
- **填报频率**：每个自然月导入/维护一次当月存栏快照；导入按唯一键（年+月+村）**存在则更新、不存在则插入**。

### 2.2 所属年份

| 规则 | 说明 |
| --- | --- |
| 可选范围 | **当前自然年**起向前共 **6 个自然年**（含当年） |
| 示例 | 若统计日为 2026 年，可选：2026、2025、2024、2023、2022、2021 |
| 展示 | 列表、表单、导入、导出时均以**四位年份**展示与存储 |

### 2.2.1 所属月份

| 规则 | 说明 |
| --- | --- |
| 取值范围 | **1～12**（自然月） |
| 填报限制 | **不可填报未来月份**（相对服务器当前年月） |
| 展示 | 列表、表单、导入、导出均以「**N 月**」展示 |

### 2.3 所属乡镇

| 规则 | 说明 |
| --- | --- |
| 数据来源 | `sys_dept` 组织树**二级节点** |
| 纳入条件 | `parent_id` 为县级根节点（与现有数据一致时为 `100`），且 `order_num > 12`，且 `del_flag = '0'`、`status = '0'` |
| 展示名 | 使用 `sys_dept.dept_name` |
| 填报方式 | **表单不单独选择乡镇**；由所属村反推写入 |

本期乡镇名单与 `sql/sys_dept_import_town.sql` 一致（10 个乡镇/镇）。

### 2.4 所属村

| 规则 | 说明 |
| --- | --- |
| 数据来源 | `sys_dept` 组织树**三级节点**（父级为 **§2.3** 合法乡镇） |
| 必填 | 新增、修改、导入时**必须**能解析到有效村 |
| 展示 | 列表展示所属乡镇、所属村；表单以**县→乡镇→村**树选择村（仅叶子可选） |
| 校验 | 村必须属于合法乡镇；保存时回写 `town_dept_id` / `town_name` / `village_name` |

### 2.5 存栏指标含义

各存栏数字段均为**非负整数**（头），允许为空（未填报）；若填写则 **≥ 0**。

**手工录入明细**（表单可编辑）：

| 业务字段 | 说明 |
| --- | --- |
| 村居数 | 纳入统计的村居数量（模板列「村居」） |
| 牧户数 | 从事牧业生产的牧户数量 |
| 种公牛存栏数 | 种用公牛（头） |
| 公牛/阉畜存栏数 | 除种公牛外的公牛及阉畜（头） |
| 0～1.5 岁幼畜存栏数 | 母牛幼畜（不含 1.5 岁） |
| 1.5 岁以上成畜存栏数 | 母牛成畜（含 1.5 岁） |
| 产奶母牛存栏数 | 产奶母牛（头） |
| 能繁母牛存栏数 | 能繁母牛（头） |
| 羊总存栏数 | 羊总数（头） |
| 产奶羊存栏数 | 产奶羊（头） |
| 保险牦牛存栏数 | 参保牦牛（头） |

**系统计算字段**（保存时自动计算；新增/编辑表单**不展示**；详情与列表相关列展示）：

| 业务字段 | 计算规则 |
| --- | --- |
| 公牛合计 | 种公牛 + 公牛/阉畜 |
| 母牛合计 | 0～1.5 岁幼畜 + 1.5 岁以上成畜 |
| 奶牛合计 | 产奶母牛 + 能繁母牛 |
| 牦牛总存栏 | 公牛合计 + 母牛合计 + 保险牦牛 |
| 总合计 | 牦牛总存栏 + 奶牛合计 + 羊总存栏 |
| 总量（牦牛+羊） | 公牛合计 + 母牛合计 + 保险牦牛 + 羊总存栏 |

导入时若 Excel 中合计列与按明细重算结果不一致，**以系统重算为准**落库，并可返回**非阻断警告**。

---

## 3. 功能范围

**本期实现：**

| 能力 | 说明 |
| --- | --- |
| 分页列表 | 按所属年份、所属月份、所属乡镇、所属村筛选；见 **§5.1** |
| 新增 | 手工填报一条村**年月**数据；见 **§5.2** |
| 修改 | 编辑已有记录；见 **§5.3** |
| 删除 | 物理删除；见 **§5.4** |
| 详情 | 查看全部字段（含计算字段）；见 **§5.5** |
| Excel 导入 | 按模板批量导入**指定填报年月**下各村数据（按唯一键 upsert）；见 **§5.6** |
| Excel 导出 | 按**指定所属年月**导出该月已填报村数据；见 **§5.7** |
| 村树下拉 | 县→乡镇→村树；见 **§5.2** |

**本期不实现：**

- 审批流、版本对比、自动从生物资产台账汇总  

---

## 4. 业务流程

```mermaid
flowchart TD
    A[选择所属年月] --> B{录入方式}
    B -->|手工| C[选择所属村并填写明细指标]
    B -->|导入| D[上传 Excel 模板]
    B -->|导出| X[下载该月已填报 Excel]
    C --> E[保存并自动计算合计]
    D --> F[解析并匹配乡镇+村]
    F --> G[删除该年月旧数据后批量新增]
    E --> J[列表查询/详情]
    G --> J
    X --> J
```

---

## 5. 详细功能需求

### 5.1 列表查询

**筛选**

| 条件 | 规则 |
| --- | --- |
| 所属年份 | 选填；**精确**匹配；下拉范围为 **§2.2** |
| 所属月份 | 选填；**精确**匹配（1～12）；**列表进入时不默认选中** |
| 所属乡镇 | 选填；精确匹配 `town_dept_id` |
| 所属村 | 选填；树选择 `village_dept_id` |

**列表规则**

- 默认每页 **20** 条；排序：**所属年份倒序**、**所属月份倒序**，同年同月按乡镇、村排序。  
- 支持**重置**筛选。

**列表展示列**

| 列名 | 说明 |
| --- | --- |
| 所属年份 | `stat_year` |
| 所属月份 | `stat_month`（展示为「N 月」） |
| 所属乡镇 | `town_name` |
| 所属村 | `village_name` |
| 村居数 | `village_count` |
| 牧户数 | `herdsman_household_count` |
| 存栏数 | `yak_total`（牦牛总存栏） |
| 公牛存栏数 | `bull_total` |
| 母牛存栏数 | `cow_total` |
| 操作 | 查看、修改、删除 |

---

### 5.2 新增

| 项 | 要求 |
| --- | --- |
| 必填 | **所属年份**、**所属月份**、**所属村** |
| 选填 | 村居数、牧户数及 **§2.5** 全部手工明细字段、备注 |
| 村 | 树形仅可选村叶子；选定后系统反推乡镇 |
| 默认值 | 打开新增弹窗时，所属年份、所属月份**默认当前年月**（可改） |
| 唯一性 | 同年同月同村已存在有效记录时**禁止新增**，提示「该年该月该村已填报」 |
| 计算字段 | 表单**不展示**；保存时服务端按 **§2.5** 重算 |
| 数字 | 选填项若填写须为非负整数；**产奶羊存栏数与羊总存栏数均填写时，产奶羊须小于羊总** |

---

### 5.3 修改

| 项 | 要求 |
| --- | --- |
| 可改字段 | 除主键外均可改；**所属年份、所属月份、所属村**修改后仍须满足唯一性 |
| 必填 | 所属年份、所属月份、所属村保持必填 |
| 计算字段 | 保存时重新计算 |

---

### 5.4 删除

| 项 | 要求 |
| --- | --- |
| 方式 | **物理删除** |
| 确认 | 删除前二次确认 |
| 效果 | 记录从库中移除；同年同月同村可重新新增或导入 |

---

### 5.5 详情

| 项 | 要求 |
| --- | --- |
| 入口 | 列表「查看」 |
| 内容 | 展示**全部字段**：所属年月、乡镇、村、全部明细与**计算合计**、备注及创建/更新审计信息 |
| 模式 | 只读 |

---

### 5.6 Excel 导入

| 项 | 要求 |
| --- | --- |
| 模板来源 | `yak_herd_inventory_import_template.xlsx`（与交接表畜群结构列一致） |
| 填报年月 | 导入前用户**必须选择**「填报年份」「填报月份」；文件中不写年月时以所选为准 |
| 解析范围 | 识别含「序号」「乡镇」的表头行；数据从 `headerRow + 3` 起；乡镇为空或「合计」行终止 |
| 乡镇/村匹配 | Excel「乡镇」「村」列与 `sys_dept.dept_name` **精确匹配**（trim 后）；村须属于该乡镇 |
| 唯一键 | **所属年份 + 所属月份 + 所属村（`village_dept_id`）** |
| 合并策略 | **按唯一键 upsert**：校验全部解析行成功后，按 `(年,月,村)` 存在则 `update`、不存在则 `insert` |
| 结果反馈 | 返回 `insertCount`、失败条数及失败明细；合计不一致时返回 `warnMessages` |
| 文件限制 | `.xlsx`；大小上限与项目统一上传限制一致 |
| 列映射 | 见技术方案 **§3.8.1** |

**模板主要列（与导入模板对齐）**

| 列序 | 表头（约） | 映射 |
| --- | --- | --- |
| A | 序号 | 忽略 |
| B | 乡镇 | 匹配乡镇 |
| C | 村 | 匹配村 |
| D | 村居 | 村居数 |
| E | 牧户 | 牧户数 |
| F | 总合计（头） | Excel 合计对照（警告用） |
| G～I | 牦牛公母分类合计/公牛/母牛 | Excel 合计对照 |
| J | 保险 | 保险牦牛 |
| K～M | 公牛合计/种公牛/阉畜 | 种公牛、阉畜为录入；合计对照 |
| N～P | 母牛合计/幼畜/成畜 | 幼畜、成畜为录入 |
| Q～S | 奶牛合计/产奶/能繁 | 产奶、能繁为录入 |
| T～U | 羊总数/产奶羊 | 羊、产奶羊 |
| V | 总量（牦牛+羊） | Excel 合计对照 |

---

### 5.7 Excel 导出

| 项 | 要求 |
| --- | --- |
| 入口 | 列表页「导出」 |
| 导出年月 | 用户**必须选择**「所属年份」「所属月份」；弹窗打开时**默认当前年月** |
| 所属乡镇 | **可选**；与列表筛选一致，可清空；不选则导出该年月全部乡镇 |
| 导出范围 | 该年月库内**已填报的村记录**（可按乡镇过滤），**不是**强制补全全县所有乡镇空行 |
| 模板 | 与导入共用：`yak_herd_inventory_import_template.xlsx` |
| 填充规则 | 标题中的年、月替换为所选年月；填表人为当前登录用户；**填表时间**为导出当日的当前年月 |
| 合计行 | 数据区末行「合计」：合并**序号+乡镇+村**三列；自**村居**起各数值列对数据行**按列求和**并写入 |
| 空行 | 合计行之后不保留模板多余空行 |
| 文件格式 | `.xlsx`；文件名示例：`2026年7月牦牛存栏数据.xlsx` |
| 与导入关系 | 列结构与导入模板一致，可再次导入（同年月同村将 upsert 更新） |

**与「下载模板」区别**：「下载模板」为空白/样例模板；「导出」为按库内**指定年月**数据填充后的报表。

---

## 6. 权限矩阵

| 操作 | 建议权限 |
| --- | --- |
| 列表查询 | `dataModel:yakHerdInventory:list` |
| 详情 | `dataModel:yakHerdInventory:query` |
| 新增 | `dataModel:yakHerdInventory:add` |
| 修改 | `dataModel:yakHerdInventory:edit` |
| 删除 | `dataModel:yakHerdInventory:remove` |
| 导入 | `dataModel:yakHerdInventory:import` |
| 导出 | `dataModel:yakHerdInventory:export` |

数据权限：县级管理员可见全县；乡镇账号仅可见本乡镇数据（若启用部门数据权限，按 `town_dept_id` 与登录用户 `dept_id` 过滤）。

---

## 7. 提示与错误约定

- 必填项未填、年份/月份/村不合法、同年同月同村重复、**未来月份**  
- 导入：文件格式错误、乡镇/村无法匹配、数字非整数、无有效数据行  
- 导出：未选年月、年月不在可选范围  
- 删除成功/失败、导入失败（展示明细）  

采用项目统一 `AjaxResult` 文案风格，**不约定** HTTP 状态码细节。

---

## 8. 非功能需求（建议）

| 类别 | 建议 |
| --- | --- |
| 性能 | 列表分页；导入单次以全县村行数为上限 |
| 审计 | 记录创建人、创建时间、更新人、更新时间 |
| 口径 | 母牛年龄两档边界以业务模板为准（0～1.5 / 1.5+） |
| 扩展 | 与「养殖产业数据」看板、大屏年龄结构（两档）联动 |

---

## 9. 需求追溯

| 能力 | 章节 |
| --- | --- |
| 表字段与必填 | §2、§5.2 |
| 年份向前 5 年 | §2.2 |
| 月份 1～12、不可填未来月 | §2.2.1 |
| 乡镇/村 sys_dept | §2.3、§2.4 |
| 增删改查 | §5.1～5.5 |
| Excel 导入按唯一键 upsert | §5.6 |
| Excel 导出与合计行（可选乡镇） | §5.7 |
| 计算字段 | §2.5、§5.2、§5.5 |

---

## 10. 修订记录

| 版本 | 说明 |
| --- | --- |
| 1.0 | 初稿 |
| 1.1 | 增加 `village_dept_id` 预留字段；列表列「乡镇」「存栏数」 |
| 1.2 | 增加 **§5.7 按年份导出** 全县乡镇 Excel；权限 `export` |
| 1.3 | 明确导入 upsert：唯一键「年份+乡镇」；重复导入更新 |
| 1.4 | 取消逻辑删除：表无 `del_flag`，删除为物理删除；唯一约束 `uk_year_town` |
| 1.5 | **按年月填报**：增加 `stat_month`；唯一键「年+月+乡镇」；每月导入一次 |
| 1.6 | **按村填报**：唯一键「年+月+村」；表单只选村；字段对齐新模板（幼畜/成畜、奶牛、羊、保险等）；导入年月全量覆盖；导出合计按列求和；计算字段仅详情展示 |
| 1.8 | 后端校验：产奶羊存栏数须小于羊总存栏数（两者均非空） |
| 1.7 | 导入改为按 `(年,月,村)` upsert；导出增加可选所属乡镇筛选 |
