依据:同目录
牦牛出栏数据填报功能需求.md;模板E:\luhao\工作交接\巴青项目\农牧数据\农业农村和科技水利局-业务办\牲畜数据.xlsx第 6 个 Sheet(2026 年度出栏及自食统计表)。
| 项 | 说明 |
|---|---|
| 后端 | 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(与「牦牛存栏数据填报」一致) |
| 组织 | sys_dept 乡镇字典;复用 TownDeptSupport |
分层:BizYakOutboundReportController → IBizYakOutboundReportService → BizYakOutboundReportMapper → domain;Excel 由 YakOutboundReportExcelParser(导入解析)、YakOutboundReportExcelExporter(按年月导出)承担。
代码位置:baqing-admin → com.ruoyi.web.modules.industryservice(与产业数据模型同包)。
模板文件:baqing-admin/src/main/resources/templates/yak_outbound_report_import_template.xlsx(导入、导出、下载模板共用)。
参考实现:BizYakHerdInventory*、YakHerdInventoryMonthSupport、TownDeptSupport(存栏填报模块,年月模式一致)。
biz_yak_outbound_report(牦牛出栏数据填报)| 字段 | 类型 | 非空 | 说明 |
|---|---|---|---|
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 | 乡镇名称冗余 |
farmer_household_count |
int(11) |
N | 农牧户户数 |
farmer_population_count |
int(11) |
N | 农牧户人数 |
yak_outbound_count |
int(11) |
N | 牦牛出栏数(头) |
cattle_outbound_count |
int(11) |
N | 黄牛/奶牛/犏牛出栏数(头) |
sheep_outbound_count |
int(11) |
N | 绵羊出栏数(只) |
goat_outbound_count |
int(11) |
N | 山羊出栏数(只) |
horse_mule_outbound_count |
int(11) |
N | 马骡出栏数(匹) |
donkey_outbound_count |
int(11) |
N | 驴出栏数(头) |
self_consumption_cattle_count |
int(11) |
N | 自食牛头数(头) |
self_consumption_sheep_count |
int(11) |
N | 自食绵羊只数(只) |
self_consumption_goat_count |
int(11) |
N | 自食山羊只数(只) |
create_by / create_time |
— | — | 审计 |
update_by / update_time |
— | — | 审计 |
remark |
varchar(500) |
N | 备注 |
说明:本表不使用逻辑删除,无 del_flag;删除为物理 DELETE。
索引与约束
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_outbound_report.sql(新库,已含 stat_month)。
已有库升级(v1.1 按年表 uk_year_town):增加 stat_month 列(历史行默认 12),调整唯一键为 uk_year_month_town(实施阶段提供迁移 SQL,模式同存栏模块)。
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()、requireReportTown(deptId)。
乡镇别名(导入):模板「扎色镇」→ sys_dept「杂色镇」,在 YakOutboundReportExcelParser.resolveTownDeptId 或 TownDeptSupport 扩展 normalizeTownName。
与存栏模块一致:复用 YakHerdInventoryYearSupport.resolveYearOptions(),返回当前年起向前 5 年共 6 个年份。
复用 YakHerdInventoryMonthSupport.resolveMonthOptions() 返回 1~12;validateStatPeriod(year, month) 校验年份在 §2.3 范围内、月份合法且非未来月。出栏校验类 YakOutboundReportValidation 亦调用该 Support。
Base Path:/dataModel/yakOutboundReport
权限前缀:dataModel:yakOutboundReport
| # | 说明 | 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.8 | 月份下拉 | GET | /monthOptions |
list |
| 3.9 | 导入 | POST | /importData |
import |
| 3.10 | 下载导入模板 | GET | /importTemplate |
import |
| 3.11 | 按年月导出 | GET | /export |
export |
| 参数 | 类型 | 说明 |
|---|---|---|
pageNum / pageSize |
int | 默认 1 / 20 |
statYear |
int | 所属年份,精确 |
statMonth |
int | 所属月份(1~12),精确 |
townDeptId |
long | 所属乡镇 dept_id,精确 |
列表 VO
| 列标题 | 字段 |
|---|---|
| 所属年份 | statYear |
| 所属月份 | statMonth |
| 所属乡镇 | townName |
| 农牧户户数 | farmerHouseholdCount |
| 农牧户人数 | farmerPopulationCount |
| 牦牛出栏数 | yakOutboundCount |
| 自食情况(牛) | selfConsumptionCattleCount |
返回需求 §5.5 指定字段(驼峰):
statYear、statMonth、townName、farmerHouseholdCount、farmerPopulationCount、yakOutboundCount、selfConsumptionCattleCount
可选附带 id、townDeptId 供前端跳转修改。
| 字段 | 必填 | 校验 |
|---|---|---|
statYear |
Y | 在 yearOptions 范围内 |
statMonth |
Y | 1~12;非未来月 |
townDeptId |
Y | 须在乡镇字典内 |
farmerHouseholdCount 等数量字段 |
N | >= 0 整数 |
id |
修改必填 | — |
唯一性(手工新增):countByYearMonthAndTownExcludeId > 0 则拒绝,提示「该年该月该乡镇已填报」。导入走 upsert。
DELETE FROM biz_yak_outbound_report WHERE id IN (...),物理删除。
请求:multipart/form-data
| 参数 | 必填 | 说明 |
|---|---|---|
file |
Y | .xlsx |
statYear |
Y | 填报年份 |
statMonth |
Y | 填报月份(1~12) |
Upsert(BizYakOutboundReportServiceImpl.upsertImportRow):
selectByYearMonthAndTown(statYear, statMonth, townDeptId)insert;有记录 → update 全字段覆盖同一文件对同一填报年月多次导入:各乡镇行均为更新,不产生重复有效记录。
响应 data:insertCount、updateCount、failCount、failMessages、warnMessages(自食大于出栏等)
| 项 | 约定 |
|---|---|
| Sheet | workbook.getSheetAt(5)(第 6 个 Sheet,0-based 索引 5) |
| 表头识别 | 扫描含「乡镇」且同行含「户数」「牦牛」的行;数据自 headerRow + 1 起 |
| 终止行 | 乡镇为空,或乡镇名为「合计」 |
| 列映射(0-based) |
| 列号 | 实体字段 |
|---|---|
| 1 | 乡镇 → townDeptId / townName |
| 2 | farmerHouseholdCount |
| 3 | farmerPopulationCount |
| 4 | yakOutboundCount |
| 5 | cattleOutboundCount |
| 6 | sheepOutboundCount |
| 7 | goatOutboundCount |
| 8 | horseMuleOutboundCount |
| 9 | donkeyOutboundCount |
| 10 | 跳过(出栏小计) |
| 11 | selfConsumptionCattleCount |
| 12 | selfConsumptionSheepCount |
| 13 | selfConsumptionGoatCount |
| 14 | 跳过(自食小计) |
| 15 | remark |
模板存在合并单元格,部分行 POI 读列可能错位;解析器宜按表头行固定列号读取,并对空单元格按 0 或 null 处理(与存栏导入一致)。
导入事务:逐乡镇独立处理,单乡镇失败不影响其余。
请求:GET /export?statYear=2026&statMonth=7
| 参数 | 必填 | 说明 |
|---|---|---|
statYear |
Y | 导出年份,须在 yearOptions 范围内 |
statMonth |
Y | 导出月份(1~12);须通过 validateStatPeriod |
响应:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet 文件流;文件名 {statYear}年{statMonth}月牦牛出栏数据.xlsx。
实现:BizYakOutboundReportServiceImpl.exportByYearMonth → YakOutboundReportExcelExporter.export:
YakOutboundReportExcelExporter.TEMPLATE_CLASSPATHYakOutboundReportExcelParser.resolveSheet)statYear(含标题行与「年牲畜出栏数」表头区块;年份与「年」之间允许空格){年份后两位}年出栏(如 2024 → 24年出栏)stat_year = statYear AND stat_month = statMonth 的全部记录,按 town_dept_id 建 MapTownDeptSupport.listReportTowns(),逐乡镇写行;无数据则仅写乡镇名与 3.10 区别:/importTemplate 返回空白模板;/export 返回填充后的全县报表。
| 项 | 说明 |
|---|---|
| 路径 | ruoyi-ui/src/views/dataModel/yakOutboundReport/index.vue |
| API | ruoyi-ui/src/api/dataModel/yakOutboundReport.js |
| 列表 | 年份、月份、乡镇筛选;进入页面不默认年月;列:所属年份、所属月份、所属乡镇、农牧户户数、农牧户人数、牦牛出栏数、自食情况(牛) |
| 详情 | 对话框只读,展示 §5.5 七字段(含月份) |
| 表单 | 新增/修改展示全部数量字段;年份/月份/乡镇下拉;新增默认当前年月;el-input-number :min="0" :precision="0" |
| 导入 | 先选「填报年份」「填报月份」(默认当前年月)→ 上传 → 展示导入结果摘要 |
| 模板下载 | GET /importTemplate;空白模板 |
| 导出 | 弹窗选年月(默认当前年月)→ GET /export?statYear=&statMonth= |
| 类型 | 名称 | 权限标识 |
|---|---|---|
| 菜单 | 牦牛出栏数据填报 | dataModel:yakOutboundReport:list |
| 按钮 | 查询 | dataModel:yakOutboundReport:query |
| 按钮 | 新增 | dataModel:yakOutboundReport:add |
| 按钮 | 修改 | dataModel:yakOutboundReport:edit |
| 按钮 | 删除 | dataModel:yakOutboundReport:remove |
| 按钮 | 导入 | dataModel:yakOutboundReport:import |
| 按钮 | 导出 | dataModel:yakOutboundReport:export |
挂载目录:产业数据模型及服务。菜单 SQL:sql/biz_sys_menu_yak_outbound_report.sql(实施阶段)。
| 模块 | 表 | 模板 Sheet | 业务含义 |
|---|---|---|---|
| 牦牛存栏数据填报 | biz_yak_herd_inventory |
牲畜数据.xlsx 第 1 Sheet(畜群结构) |
月末存栏结构 |
| 牦牛出栏数据填报 | biz_yak_outbound_report |
牲畜数据.xlsx 第 6 Sheet |
月度出栏及自食 |
两模块共用 TownDeptSupport、年份范围规则、YakHerdInventoryMonthSupport 年月校验、导入 upsert 模式;本期不实现跨表校验(如出栏数不大于存栏数)。
产业总览中「牦牛出栏数」「农牧户户数」等字段当前仍通过 HomeScreenStatsMapper.sumOutboundReport*ByStatYear 仅按 stat_year 汇总,不按月份过滤。同一年存在多个月份填报时可能重复累加;后续单独设计看板口径,本模块按年月维护明细。
sql/biz_yak_outbound_report.sql(含 stat_month)BizYakOutboundReport Domain / Mapper / XML / Service / ControllerYakOutboundReportExcelParser + YakOutboundReportExcelExporter + 导入模板 xlsx(第 6 Sheet)TownDeptSupport、YakHerdInventoryYearSupport、YakHerdInventoryMonthSupportsql/biz_sys_menu_yak_outbound_report.sql| 版本 | 说明 |
|---|---|
| 1.0 | 初稿:表结构、CRUD、第 6 Sheet 导入、物理删除、乡镇字典 |
| 1.1 | 实现按年份导出全县乡镇 Excel;YakOutboundReportExcelExporter |
| 1.2 | 按年月填报:stat_month;uk_year_month_town;/monthOptions;导入/导出/CRUD 支持月份;复用 YakHerdInventoryMonthSupport |