西藏巴青项目

养殖产业数据技术方案.md 16KB

养殖产业数据 — 技术方案

依据:同目录 养殖产业数据功能需求.md。本期为只读看板:全页指标由既有台账聚合计算,无业务台账 CRUD、无第三方同步接口。


1. 技术架构

说明
后端 RuoYi v3.9.2springboot2 分支):JDK 8、Spring Boot 2.x、Spring MVC、MyBatis、Druid
数据库 MySQL 5.7.39,InnoDB,utf8mb4
前端 若依 Vue2;见 养殖产业数据前端技术方案.md
时区 Asia/Shanghai(自然年、统计日、预警时间范围)

分层ControllerIBreedingIndustryDashboardService(口径编排、数据权限)→ BreedingIndustryStatsMapper(聚合 SQL)→ 既有 biz_* 表。

代码位置(建议)baqing-admincom.ruoyi.web.modules.industryserviceBreedingIndustryDashboardControllerBreedingIndustryStatsMapper、VO)。

场景 行为
看板加载/刷新 一次请求返回四块数据;statDate 取服务器当前日期
数据权限 Service 注入用户可见 pastureId 列表;牦牛、预警按 §2.2 过滤;草场全县台账不按牧场过滤
月末存栏趋势(档案) 历史能力保留于 BreedingIndustryCalculator看板趋势已改填报表,见 §2.11
存栏变动/年龄/趋势 复用 HomeScreenStatsMapper + HomeScreenSupport 滚动 12 月逻辑,与大屏一致
性能 数据量大时启用 §2.3 可选快照表 + 短 TTL 缓存;本期可先实时聚合;月末 12 点目标 ≤3s(1 万级档案,评审可调)

依赖模块(只读)

模块
biz_pasture 牧场管理
biz_grassland 草场管理
biz_yak_asset 牦牛资产档案
biz_yak_disease_warning 牦牛疾病预警
biz_yak_herd_inventory 牦牛存栏数据填报(存栏变动、年龄结构、总览存栏)
biz_yak_outbound_report 牦牛出栏数据填报(总览出栏、农牧户)

2. 数据库设计

2.1 设计原则

本模块不新增业务台账表;指标均通过对上表 SELECT 聚合 得到,口径以功能需求 §2 为准。

2.2 数据源与字段映射

biz_pasture(牧场数量)

指标 SQL 条件要点
牧场数量 del_flag='0' AND biz_status=1 AND id IN (可见牧场ID集合)

biz_grassland(草场数量、面积、可用/使用中、退化占比)

指标 SQL 条件要点
草场数量 del_flag='0'
草场面积 SUM(area_mu)area_mu IS NOT NULL
可用草场 del_flag='0' AND degradation_level IN (1,2)(1未退化 2轻度)
使用中草场 del_flag='0' AND (utilization_type IN (2,3) OR (utilization_type=1 AND 统计日 NOT BETWEEN grazing_ban_start_date AND grazing_ban_end_date))
退化分组 GROUP BY degradation_level(1~5)

枚举(与草场管理一致)

字段 含义
degradation_level 1~5 未退化、轻度、中度、重度、极重度
utilization_type 1/2/3 禁牧、轮牧、全年放牧

biz_yak_asset(存栏、出栏、性别、年龄、月趋势)

指标 SQL 条件要点
当前存栏 del_flag='0' AND pasture_id IN (...) AND pasture_id IS NOT NULL AND asset_status=1
年出栏 同上牧场范围 AND asset_status=4 AND status_change_date 在当年且 ≤ 统计日 AND status_change_date IS NOT NULL
公牛/母牛 在存栏集合上 gender='公' / gender='母'
未标注性别 存栏总量 − 公牛 − 母牛
年龄分档 在存栏集合上按 age_months(或 birth_date 计算月龄)分 0~6、7~12、≥13
月末存栏 对每条档案用 §2.2 月末存栏判定(见下),非仅 asset_status=1

asset_status1 正常 2 死淘 3 丢失 4 出栏。

月末时点计入存栏(单头判定,记月末日为 M

计入 ⇔ del_flag='0'
      AND pasture_id IN (可见牧场)
      AND pasture_id IS NOT NULL
      AND NOT (asset_status IN (2,3,4) AND status_change_date IS NOT NULL AND status_change_date <= M)
      AND asset_status 可识别(1 或 2/3/4 且 change_date > M)

当前月:M 替换为 统计日

biz_yak_disease_warning(预警牦牛数量)

-- 口径示意:当年 1/1 0:00 ~ 统计日 23:59:59,去重 yak_no,牦牛须在纳入集合内
SELECT COUNT(DISTINCT w.yak_no)
FROM biz_yak_disease_warning w
INNER JOIN biz_yak_asset y ON y.yak_no = w.yak_no AND y.del_flag = '0'
WHERE w.alert_time >= ? AND w.alert_time <= ?
  AND y.pasture_id IN (...)
  AND y.pasture_id IS NOT NULL;

2.3 可选表 biz_breeding_dashboard_cache(性能优化)

数据量较大或刷新慢时启用;非本期必建

字段 类型 说明
id bigint(20) 主键
scope_key varchar(64) 权限范围键,如 alluser:{userId}
stat_date date 统计日
payload_json mediumtext 看板完整 JSON(与 §3.2 data 结构一致)
expire_time datetime 过期时间
create_time datetime 写入时间

索引UNIQUE uk_scope_stat (scope_key, stat_date)

刷新时:先查未过期缓存命中则直接返回;否则实时计算后 UPSERT。TTL 建议 5~15 分钟(可配置)。

2.4 索引建议(既有表)

若统计偏慢,确认已存在(sql/biz_yak_asset.sql 等已含大部分):

建议索引
biz_yak_asset (pasture_id, del_flag, asset_status)status_change_date
biz_yak_disease_warning (alert_time)(yak_no, alert_time)
biz_grassland (del_flag, degradation_level)(del_flag, utilization_type)
biz_pasture (del_flag, biz_status)

2.5 可选缓存表 DDL

CREATE TABLE IF NOT EXISTS `biz_breeding_dashboard_cache` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `scope_key` varchar(64) NOT NULL COMMENT '权限范围键',
  `stat_date` date NOT NULL COMMENT '统计日',
  `payload_json` mediumtext NOT NULL COMMENT '看板JSON',
  `expire_time` datetime NOT NULL COMMENT '过期时间',
  `create_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_scope_stat` (`scope_key`,`stat_date`),
  KEY `idx_expire_time` (`expire_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='养殖产业看板缓存(可选)';

2.6 数据权限实现

与「牦牛疾病预警」列表一致:聚合前解析可见牧场 ID 集合 allowedPastureIds,传入 BreedingIndustryStatsMapperIN (...) 条件(牦牛、预警、牧场数量);草场统计不加牧场条件。

建议类com.ruoyi.web.modules.industryservice.support.BreedingIndustryPastureScope(或复用后续统一的 IndustryPastureScopeHelper)。

步骤 说明
1 查询 biz_pasturedel_flag='0' AND biz_status=1,得到候选 ID 列表
2 按当前登录用户应用项目数据权限(部门/角色自定义范围,与预警 allowedPastureIds 同源);县级全量角色得到全部候选 ID
3 将结果写入统计上下文 BreedingIndustryStatsContext.allowedPastureIds

三种语义(实现须区分)

allowedPastureIds 牦牛 / 预警 / 牧场数 草场
null(未限制,全量管理员) 候选列表 = 步骤 1 全部正常牧场 ID 全县 del_flag=0
非空列表 pasture_id IN (...)pasture_id IS NOT NULL 不变
空列表 [](有权限框架但无可见牧场) 牦牛类、预警、牧场数 均为 0 仍全县统计

Controller 示例

List<Long> allowed = pastureScope.resolveAllowedPastureIds();
return success(dashboardService.loadDashboard(allowed, forceRefresh));

Mapper 约定:与 BizYakDiseaseWarningMapper.xml 相同写法——仅当 allowedPastureIds != null && size > 0 时追加 pasture_id in (...);全量管理员传完整 ID 列表(勿传 null 跳过牦牛过滤,以免误统计 pasture_id 为空的档案)。

预警biz_yak_disease_warningbiz_yak_assetyak_no 关联后,再限制 y.pasture_id IN (...)(见 §2.2 SQL)。


3. 接口设计

统一响应AjaxResultcode / msg / data)。

权限dataModel:breedingIndustry:query(查看与刷新共用)。

Base Path/dataModel/breedingIndustry

本期仅 1 个业务接口;不提供 POST/PUT/DELETE 维护接口。

# 说明 Method URI 权限
3.1 看板全量数据 GET /dashboard query

前端进入页与点击「刷新」均调用 3.1

3.1.1 Query

参数 类型 必填 说明
forceRefresh boolean N 默认 falsetrue 时跳过 §2.3 缓存

3.1.2 响应 data 结构

节点 类型 说明
statDate string 统计日 yyyy-MM-dd
statYear int 当前自然年,如 2026
overview object 产业总览 §3.1.3
inventoryChange object 牦牛存栏变动 §3.1.4
ageStructure array 年龄结构 §3.1.5
grassland object 草场类型占比 §3.1.6

3.1.3 overview

字段 类型 说明
inventoryTotal int 牦牛存栏总量(头);biz_yak_herd_inventory 最近填报年月全县 yak_total 合计
annualOutbound int 牦牛年出栏量(头);biz_yak_outbound_report 最近填报年月全县 yak_outbound_count 合计
warningYakCount int 预警牦牛数量(头);§2.5 档案口径
pastureCount int 农牧户(户);biz_yak_outbound_report 最近填报年月全县 farmer_household_count 合计
grasslandCount int 草场数量(个)
grasslandAreaMu decimal 草场面积(亩)

3.1.4 inventoryChange

字段 类型 说明
bullCount int 公牛数量(头);最近填报年月全县 bull_total 合计
cowCount int 母牛数量(头);最近填报年月全县 cow_total 合计
unknownGenderCount int 固定 0(不展示未标注性别)
monthlyTrend array 滚动最近 12 自然月;固定 12

monthlyTrend[] 元素:

字段 类型 说明
statYear int 所属自然年
month int 所属月份 1~12
bullCount int 该月全县公牛合计;无数据为 0
cowCount int 该月全县母牛合计;无数据为 0

3.1.5 ageStructure[]

字段 类型 说明
bandCode string COW_U1 / COW_1_3 / COW_3_12 / COW_O12
bandLabel string 1岁以下 / 1~3岁 / 3~12岁 / 12岁以上
count int 头数
ratio decimal 占比 0~100 数值,保留 1 位小数

四档固定返回(count 为 0 也返回);与大屏年龄结构一致。

3.1.6 grassland

字段 类型 说明
availableCount int 可用草场(个)
inUseCount int 使用中草场(个)
degradationStats array 退化等级统计

degradationStats[] 元素:

字段 类型 说明
degradationLevel int 1~5
degradationLabel string 未退化、轻度…
count int 个数
ratio decimal 占比 %(同 ageStructure

五档固定返回;count 之和应等于 overview.grasslandCount

3.1.7 响应示例(节选)

{
  "code": 200,
  "msg": "操作成功",
  "data": {
    "statDate": "2026-05-20",
    "statYear": 2026,
    "overview": {
      "inventoryTotal": 120,
      "annualOutbound": 8,
      "warningYakCount": 5,
      "pastureCount": 12,
      "grasslandCount": 80,
      "grasslandAreaMu": 12500.50
    },
    "inventoryChange": {
      "bullCount": 45,
      "cowCount": 60,
      "unknownGenderCount": 0,
      "monthlyTrend": [
        { "statYear": 2025, "month": 8, "bullCount": 40, "cowCount": 55 },
        { "statYear": 2026, "month": 5, "bullCount": 45, "cowCount": 60 }
      ]
    },
    "ageStructure": [
      { "bandCode": "COW_U1", "bandLabel": "1岁以下", "count": 30, "ratio": 25.0 }
    ],
    "grassland": {
      "availableCount": 50,
      "inUseCount": 40,
      "degradationStats": [
        { "degradationLevel": 1, "degradationLabel": "未退化", "count": 30, "ratio": 37.5 }
      ]
    }
  }
}

3.1.8 异常与校验

场景 处理
无查询权限 403 或 AjaxResult.error 无权限
聚合异常 AjaxResult.error("加载失败,请稍后重试")data 为空
可见牧场为空 牦牛类指标均为 0;草场类仍按全县统计
刷新中重复点击 前端防重;后端可选短锁(与资产同步类似)

4. 实现要点(摘要)

说明
月龄 COALESCE(age_months, TIMESTAMPDIFF(MONTH, birth_date, statDate))birth_date 空则 0
性别 入库值 trim 后精确匹配 /;第三方若写「公牛」「母牛」等,Service 层归一后再统计
存栏变动/年龄/趋势 HomeScreenStatsMapper + HomeScreenSupport.buildRolling12MonthBullCowTrend / buildCowAgeStructureFromHerdReportBreedingIndustryDashboardSupport 做 VO 转换
总览填报三项 overview.inventoryTotal / annualOutbound / pastureCount 取各表最近填报年月全县合计
预警 仍用 biz_yak_asset + biz_yak_disease_warning,按 §2.9 可见牧场过滤
比率 ratio = count * 100.0 / NULLIF(total, 0),分母为 0 时 ratio=0
月末性能 优先 1 条 SQL + CASE WHEN 按月末分组,或 Java 循环 12 次;超过 3s 启用 §2.3 缓存
日志 看板接口可 @Log(title="养殖产业数据", businessType=OTHER) 或仅记录慢查询

前端:见同目录 养殖产业数据前端技术方案.md


5. 菜单与权限(示例)

类型 名称 权限标识
目录/菜单 养殖产业数据 dataModel:breedingIndustry:query
按钮 刷新(与查看共用) dataModel:breedingIndustry:query

组件路径:livestockIndustry/breedingIndustry/index(挂载「产业数据模型」或同级目录,与菜单配置一致)。

sys_menu 示例(menu_id 按环境递增)

-- 父菜单 parent_id 替换为「产业数据模型」实际 ID
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES ('养殖产业数据', {parentId}, 10, 'breedingIndustry', 'livestockIndustry/breedingIndustry/index', 1, 0, 'C', '0', '0', 'dataModel:breedingIndustry:query', 'chart', 'admin', sysdate(), '养殖产业看板');

本期 add/edit/remove/sync 按钮权限。


6. 需求追溯

功能需求 技术落点
§5.2 产业总览 overview + §2.2 SQL
§5.3 存栏变动 inventoryChange + 填报表滚动 12 月(与大屏一致)
§5.4 年龄结构 ageStructure 母牛四档(填报最近年月)
§5.5 草场占比 grassland
§5.1 刷新 3.1 forceRefresh
§2.9 数据权限 §2.6 BreedingIndustryPastureScope(仅预警等档案类指标)
§2.5 预警 §2.2 warning SQL

7. 修订记录

版本 日期 说明
1.2 2026-07-04 存栏变动/年龄/趋势改 biz_yak_herd_inventory 填报表;滚动 12 月;与大屏字段对齐
1.1 (既有) 总览三项改填报合计