西藏巴青项目

牦牛存栏数据填报技术方案.md 12KB

牦牛存栏数据填报 — 技术方案

依据:同目录 牦牛存栏数据填报功能需求.md;模板 E:\luhao\工作交接\巴青项目\农牧数据\农业农村和科技水利局-业务办\畜群结构\2026年.xlsx(第一个 Sheet)。


1. 技术架构

说明
后端 RuoYi v3.9.2(springboot2):JDK 8、Spring Boot 2.x、Spring MVC、MyBatis、Druid
数据库 MySQL 5.7.39,InnoDB,utf8mb4
前端 若依 Vue2 + Element UI
Excel Apache POI 或项目已有 EasyExcel(与若依导入规范一致)
组织 sys_dept 乡镇字典;SysDeptMapper 查询二级节点

分层BizYakHerdInventoryControllerIBizYakHerdInventoryServiceBizYakHerdInventoryMapperdomain;Excel 由 YakHerdInventoryExcelParser(导入解析)、YakHerdInventoryExcelExporter(按年导出)承担。

代码位置baqing-admincom.ruoyi.web.modules.industryservice(与产业数据模型同包)。

模板文件baqing-admin/src/main/resources/templates/yak_herd_inventory_import_template.xlsx(导入、导出、下载模板共用)。


2. 数据库设计

2.1 表 biz_yak_herd_inventory(牦牛存栏数据填报)

字段 类型 非空 说明
id bigint(20) Y 主键
stat_year int(11) Y 所属年份(自然年)
stat_month int(11) Y 所属月份(1~12)
town_dept_id bigint(20) Y 所属乡镇,sys_dept.dept_id
town_name varchar(64) Y 乡镇名称冗余,便于列表展示
village_dept_id bigint(20) N 预留所属村居,sys_dept.dept_id(乡镇下三级节点)
village_name varchar(128) N 预留所属村居名称冗余
village_count int(11) N 村居数
herdsman_household_count int(11) N 牧户数
yak_total int(11) N 牦牛存栏数
bull_total int(11) N 公牛存栏数
cow_total int(11) N 母牛存栏数
breeding_bull_count int(11) N 种公牛存栏数
bull_castrated_count int(11) N 公牛/阉畜存栏数
cow_under_1_count int(11) N 1 岁以下母牛存栏数
cow_1_3_count int(11) N 1~3 岁母牛存栏数
cow_3_12_count int(11) N 3~12 岁母牛存栏数
cow_over_12_count int(11) N 12 岁以上母牛存栏数
create_by / create_time 审计
update_by / update_time 审计
remark varchar(500) N 备注

说明:本表不使用逻辑删除,无 del_flag 字段;删除操作为物理删除。

索引与约束

  • UNIQUE uk_year_month_town (stat_year, stat_month, town_dept_id) — 年月+乡镇唯一,支撑导入 upsert。
  • KEY idx_stat_year_month (stat_year, stat_month)
  • KEY idx_town_dept_id (town_dept_id)

DDL 文件sql/biz_yak_herd_inventory.sql(新库);已有库执行 sql/biz_yak_herd_inventory_stat_month.sql(历史行 stat_month 默认 12)。

2.2 乡镇字典查询(sys_dept

SELECT dept_id, dept_name, order_num
FROM sys_dept
WHERE parent_id = 100
  AND order_num > 12
  AND del_flag = '0'
  AND status = '0'
ORDER BY order_num;

前端乡镇下拉、导入匹配均调用封装方法 TownDeptSupport.listReportTowns()(名称与根 parent_id 可配置化 ruoyi.town-dept-parent-id=100ruoyi.town-dept-min-order-num=12)。

2.3 可选年份

// 当前年起向前 5 年,共 6 个
int current = Year.now().getValue();
for (int y = current; y >= current - 5; y--) { ... }

2.3 可选月份

YakHerdInventoryMonthSupport.resolveMonthOptions() 返回 1~12validateStatPeriod(year, month) 校验年份在 §2.2 范围内、月份合法且非未来月


3. 接口设计

Base Path/dataModel/yakHerdInventory

权限前缀dataModel:yakHerdInventory

# 说明 Method URI 权限
3.1 分页列表 GET /list list
3.2 详情 GET /{id} query
3.3 新增 POST / add
3.4 修改 PUT / edit
3.5 删除 DELETE /{ids} remove
3.6 乡镇下拉 GET /townOptions list
3.7 年份下拉 GET /yearOptions list
3.7.1 月份下拉 GET /monthOptions list
3.8 导入 POST /importData import
3.9 下载导入模板 GET /importTemplate import
3.10 按年月导出 GET /export export

3.1.1 列表 Query

参数 类型 说明
pageNum / pageSize int 默认 1 / 20
statYear int 所属年份,精确
statMonth int 所属月份(1~12),精确
townDeptId long 所属乡镇 dept_id,精确

列表 VO 字段(列标题与需求 §5.1 一致):

列标题 字段
所属年份 statYear
所属月份 statMonth
乡镇 townName
村居数 villageCount
牧户数 herdsmanHouseholdCount
存栏数 yakTotal
公牛存栏数 bullTotal
母牛存栏数 cowTotal

3.2.1 详情

返回 BizYakHerdInventory 全字段(驼峰),含预留村居、分龄母牛、种公牛、阉畜、备注及 createBy / createTime / updateBy / updateTime 等。

3.3.1 新增/修改 Body

字段 必填 校验
statYear Y yearOptions 范围内
statMonth Y 1~12;不可为未来月
townDeptId Y 须在乡镇字典内
villageDeptId N 预留;若填写须为有效 sys_dept.dept_id,且 parent_id = townDeptId(可选校验)
villageName N 预留村居名称
*Count N >= 0 整数
id 修改必填

唯一性countByYearMonthAndTownExcludeId(statYear, statMonth, townDeptId, excludeId) > 0 则拒绝(手工新增/修改);导入走 upsert,不受此限。

3.8 导入

请求multipart/form-data

参数 必填 说明
file Y .xlsx(如 牦牛存栏数据.xlsx
statYear Y 填报年份
statMonth Y 填报月份(1~12)

Upsert 规则BizYakHerdInventoryServiceImpl.upsertImportRow):

步骤 说明
1 statYear + statMonth + townDeptId 查询 selectByYearMonthAndTown
2 无记录 → insertinsertCount++
3 有记录 → updateBizYakHerdInventory 全字段覆盖;updateCount++

同一文件对同一填报年月多次导入:各乡镇行均为更新,不产生重复有效记录。

响应 data

字段 说明
insertCount 新增条数
updateCount 更新条数
failCount 失败条数
failMessages 第8行[杂色镇]: 乡镇未识别
warnMessages 分龄加总与母牛合计不一致等警告(可选)

3.8.1 Excel 第一个 Sheet 解析约定(2026年.xlsx

约定
Sheet workbook.getSheetAt(0)
标题行 前若干行为「巴青县…畜群结构…统计表」及填表说明,自动扫描首列含「序号」且相邻列含「乡镇」的行作为表头行 headerRow
数据行 headerRow + 1 起至「乡镇」列为空
列映射(默认,实施对照模板微调)
列号(0-based) Excel 列 实体字段
1 B 乡镇(按 dept_name 解析 townDeptId
2 C villageCount
3 D herdsmanHouseholdCount
4 E yakTotal(存栏数)
5 F 与 E 同值(牦牛公母分类合计)
6 G bullTotal(公牛(头))
7 H cowTotal(牦牛公母分类 — 母牛(头))
8 I 与 G 同值(公牛区块合计)
9 J breedingBullCount
10 K bullCastratedCount
11 L cowTotal
12 M cowUnder1Count
13 N cow13Count
14 O cow312Count
15 P cowOver12Count
16 Q remark

数据区起始行:headerRow + 3(表头行由「序号」「乡镇」自动识别)。模板存在合并单元格,列号以代码常量为准。

导入事务:逐乡镇独立处理,单乡镇失败不影响其余。

3.10 按年月导出

请求GET /export?statYear=2026&statMonth=7

参数 必填 说明
statYear Y 导出年份,须在 yearOptions 范围内
statMonth Y 导出月份(1~12);须通过 validateStatPeriod

响应application/vnd.openxmlformats-officedocument.spreadsheetml.sheet 文件流;文件名 {statYear}年{statMonth}月牦牛存栏数据.xlsx

实现BizYakHerdInventoryServiceImpl.exportByYearMonthYakHerdInventoryExcelExporter.export

  1. 加载 classpath 模板 YakHerdInventoryExcelExporter.TEMPLATE_CLASSPATH
  2. 替换表头中的四位年份为 statYear
  3. 查询 stat_year = statYear AND stat_month = statMonth 的全部记录,按 town_dept_id 建 Map
  4. 遍历 TownDeptSupport.listReportTowns(),逐乡镇写行;无数据则仅写乡镇名
  5. 末行写「合计」,对已填报乡镇数值列求和

与 3.9 区别/importTemplate 返回空白模板;/export 返回填充后的全县报表。


4. 前端设计(要点)

说明
路径 ruoyi-ui/src/views/dataModel/yakHerdInventory/index.vue
API ruoyi-ui/src/api/dataModel/yakHerdInventory.js
列表 年份、月份、乡镇筛选;进入页面不默认年月;列:所属年份、所属月份、乡镇、村居数、牧户数、存栏数、公牛/母牛存栏数
详情 抽屉/对话框只读展示全部字段
表单 抽屉或对话框;年份/月份/乡镇下拉;新增默认当前年月;数字 el-input-number :min="0" :precision="0"
导入 先选「填报年份」「填报月份」(默认当前年月)→ 上传 → 展示导入结果摘要
模板下载 GET /importTemplate;空白模板
导出 弹窗选年月(默认当前年月)→ GET /export?statYear=&statMonth=

5. 菜单与权限(示例)

类型 名称 权限标识
菜单 牦牛存栏数据填报 dataModel:yakHerdInventory:list
按钮 查询 dataModel:yakHerdInventory:query
按钮 新增 dataModel:yakHerdInventory:add
按钮 修改 dataModel:yakHerdInventory:edit
按钮 删除 dataModel:yakHerdInventory:remove
按钮 导入 dataModel:yakHerdInventory:import
按钮 导出 dataModel:yakHerdInventory:export

挂载目录:产业数据模型及服务。菜单 SQL 见 sql/biz_sys_menu_yak_herd_inventory.sql


6. 与养殖产业数据看板 / 大屏的关系

「养殖产业数据」看板、大屏首页产业总览中的全县存栏合计、地图乡镇存栏标注,读取 biz_yak_herd_inventory 时:

场景 口径
年度全县合计 stat_year = 当前自然年 − 1stat_month = 12YakHerdInventoryRules.YEAR_END_STAT_MONTH
地图乡镇存栏 同上:herdStatYear = 当前年 − 1herdStatMonth = 12

避免同一年多个月份重复累加。月度明细在本模块列表按年月筛选查看。


7. 交付清单

  • sql/biz_yak_herd_inventory.sql
  • BizYakHerdInventory Domain / Mapper / XML / Service / Controller
  • YakHerdInventoryExcelParser + YakHerdInventoryExcelExporter
  • TownDeptSupport 乡镇字典
  • 前端列表/表单/导入/导出
  • 单元测试 + 导入/导出集成测试(yak_herd_inventory_2026.xlsx

8. 修订记录

版本 说明
1.0 初稿:表结构、CRUD、导入、sys_dept 乡镇、年份前推 5 年
1.1 增加预留字段 village_dept_id(非必填)
1.2 实现按年份导出全县乡镇 Excel;列映射与代码对齐;交付清单勾选
1.3 导入 upsert:selectByYearAndTown + updateBizYakHerdInventory;支持重复导入
1.4 取消逻辑删除:无 del_flagdeleteBizYakHerdInventoryByIds 物理删除;uk_year_town 唯一约束
1.5 按年月填报:stat_monthuk_year_month_townYakHerdInventoryMonthSupport;导入/导出/列表/CRUD 支持月份;大屏年度汇总取 12 月