Browse Source

数字畜牧一张图

wwh 1 month ago
parent
commit
612c647aa4

+ 3 - 3
baqing-admin/src/main/java/com/ruoyi/web/modules/screen/domain/vo/HomeScreenIndustryOverviewVo.java

@@ -6,11 +6,11 @@ import java.math.BigDecimal;
6 6
  */
7 7
 public class HomeScreenIndustryOverviewVo
8 8
 {
9
-    /** 截止 statDate 牦牛存栏总头数 */
9
+    /** 产业总览「牦牛存栏总量」(头):上一年全县存栏填报 `yak_total` 合计;字段名沿用 `inventoryTotal` */
10 10
     private int inventoryTotal;
11
-    /** 当年出栏总头数 */
11
+    /** 产业总览「牦牛年出栏量」(头):当年全县出栏填报 `yak_outbound_count` 合计;字段名沿用 `annualOutbound` */
12 12
     private int annualOutbound;
13
-    /** 有效牧场数 */
13
+    /** 产业总览「农牧户」展示位(户):当年全县出栏填报 `farmer_household_count` 合计;字段名沿用 `pastureCount` */
14 14
     private int pastureCount;
15 15
     /** 草场块数 */
16 16
     private int grasslandCount;

+ 9 - 0
baqing-admin/src/main/java/com/ruoyi/web/modules/screen/mapper/HomeScreenStatsMapper.java

@@ -70,4 +70,13 @@ public interface HomeScreenStatsMapper
70 70
     List<HomeScreenTownMapMarkerVo> selectTownMapMarkers(
71 71
             @Param("herdStatYear") int herdStatYear,
72 72
             @Param("outboundStatYear") int outboundStatYear);
73
+
74
+    /** 指定年份全县乡镇牦牛存栏填报合计({@code biz_yak_herd_inventory.yak_total}) */
75
+    int sumHerdInventoryYakTotalByStatYear(@Param("statYear") int statYear);
76
+
77
+    /** 指定年份全县乡镇牦牛出栏填报合计({@code biz_yak_outbound_report.yak_outbound_count}) */
78
+    int sumOutboundReportYakCountByStatYear(@Param("statYear") int statYear);
79
+
80
+    /** 指定年份全县乡镇农牧户户数填报合计({@code biz_yak_outbound_report.farmer_household_count}) */
81
+    int sumOutboundReportFarmerHouseholdCountByStatYear(@Param("statYear") int statYear);
73 82
 }

+ 17 - 10
baqing-admin/src/main/java/com/ruoyi/web/modules/screen/service/impl/HomeScreenServiceImpl.java

@@ -68,19 +68,26 @@ public class HomeScreenServiceImpl implements IHomeScreenService
68 68
         overview.setSupplierCount(homeScreenStatsMapper.countSupplierForScreen());
69 69
         overview.setDistributorCount(homeScreenStatsMapper.countDistributorForScreen());
70 70
         overview.setTradeMarketCount(homeScreenStatsMapper.countTradeMarketForScreen());
71
-        overview.setPastureCount(allowedPastureIds.isEmpty()
72
-                ? 0
73
-                : breedingIndustryStatsMapper.countPastureInScope(allowedPastureIds));
71
+        // 原有效牧场数量口径(暂保留调用,产业总览 pastureCount 已改用农牧户填报合计)
72
+        if (!allowedPastureIds.isEmpty())
73
+        {
74
+            breedingIndustryStatsMapper.countPastureInScope(allowedPastureIds);
75
+        }
74 76
         overview.setGrasslandCount(breedingIndustryStatsMapper.countGrassland());
75 77
         BigDecimal area = breedingIndustryStatsMapper.sumGrasslandAreaMu();
76 78
         overview.setGrasslandAreaMu(area != null ? area.setScale(2, RoundingMode.HALF_UP) : BigDecimal.ZERO);
77 79
 
80
+        // 产业总览三项:填报合计填入既有字段(字段名不变);原快照/资产口径见下方暂保留调用
81
+        int currentCalendarYear = Year.now().getValue();
82
+        overview.setInventoryTotal(homeScreenStatsMapper.sumHerdInventoryYakTotalByStatYear(currentCalendarYear - 1));
83
+        overview.setAnnualOutbound(homeScreenStatsMapper.sumOutboundReportYakCountByStatYear(currentCalendarYear));
84
+        overview.setPastureCount(
85
+                homeScreenStatsMapper.sumOutboundReportFarmerHouseholdCountByStatYear(currentCalendarYear));
86
+
78 87
         HomeScreenInventoryChangeVo inventoryChange = new HomeScreenInventoryChangeVo();
79 88
         if (allowedPastureIds.isEmpty())
80 89
         {
81 90
             // 无有效牧场时牦牛相关区块全部置零
82
-            overview.setInventoryTotal(0);
83
-            overview.setAnnualOutbound(0);
84 91
             inventoryChange.setBullCount(0);
85 92
             inventoryChange.setCowCount(0);
86 93
             inventoryChange.setUnknownGenderCount(0);
@@ -91,14 +98,14 @@ public class HomeScreenServiceImpl implements IHomeScreenService
91 98
         }
92 99
         else
93 100
         {
94
-            int inventoryTotal = HomeScreenSupport.countInventoryAtDate(snapshots, statDate);
101
+            // 原时点存栏口径(暂保留,供存栏变动/年龄结构等区块使用)
102
+            int inventoryTotalAtDate = HomeScreenSupport.countInventoryAtDate(snapshots, statDate);
95 103
             int[] gender = HomeScreenSupport.countGenderAtDate(snapshots, statDate);
96
-            overview.setInventoryTotal(inventoryTotal);
97
-            overview.setAnnualOutbound(breedingIndustryStatsMapper.countAnnualOutbound(
98
-                    allowedPastureIds, yearStart, yearEnd));
104
+            // 原资产出栏口径(暂保留调用)
105
+            breedingIndustryStatsMapper.countAnnualOutbound(allowedPastureIds, yearStart, yearEnd);
99 106
             inventoryChange.setBullCount(gender[0]);
100 107
             inventoryChange.setCowCount(gender[1]);
101
-            inventoryChange.setUnknownGenderCount(Math.max(0, inventoryTotal - gender[0] - gender[1]));
108
+            inventoryChange.setUnknownGenderCount(Math.max(0, inventoryTotalAtDate - gender[0] - gender[1]));
102 109
             inventoryChange.setMonthlyTrend(HomeScreenSupport.buildBullCowMonthlyTrend(snapshots, statDate));
103 110
             vo.setAgeStructure(HomeScreenSupport.buildAgeStructureAtDate(snapshots, statDate));
104 111
             vo.setOutboundMonthly(HomeScreenSupport.buildOutboundMonthly(

+ 18 - 0
baqing-admin/src/main/resources/mapper/screen/HomeScreenStatsMapper.xml

@@ -163,4 +163,22 @@
163 163
           and d.status = '0'
164 164
         order by d.order_num asc, d.dept_id asc
165 165
     </select>
166
+
167
+    <select id="sumHerdInventoryYakTotalByStatYear" resultType="int">
168
+        select coalesce(sum(yak_total), 0)
169
+        from biz_yak_herd_inventory
170
+        where stat_year = #{statYear}
171
+    </select>
172
+
173
+    <select id="sumOutboundReportYakCountByStatYear" resultType="int">
174
+        select coalesce(sum(yak_outbound_count), 0)
175
+        from biz_yak_outbound_report
176
+        where stat_year = #{statYear}
177
+    </select>
178
+
179
+    <select id="sumOutboundReportFarmerHouseholdCountByStatYear" resultType="int">
180
+        select coalesce(sum(farmer_household_count), 0)
181
+        from biz_yak_outbound_report
182
+        where stat_year = #{statYear}
183
+    </select>
166 184
 </mapper>

+ 3 - 0
baqing-admin/src/test/java/com/ruoyi/web/modules/screen/mapper/HomeScreenStatsMapperXmlTest.java

@@ -26,6 +26,9 @@ class HomeScreenStatsMapperXmlTest
26 26
         assertTrue(xml.contains("biz_subsidy_grant_record"));
27 27
         assertTrue(xml.contains("biz_yak_herd_inventory"));
28 28
         assertTrue(xml.contains("biz_yak_outbound_report"));
29
+        assertTrue(xml.contains("sumHerdInventoryYakTotalByStatYear"));
30
+        assertTrue(xml.contains("sumOutboundReportYakCountByStatYear"));
31
+        assertTrue(xml.contains("sumOutboundReportFarmerHouseholdCountByStatYear"));
29 32
         assertTrue(xml.contains("status not in (2, 3)"));
30 33
     }
31 34
 }

+ 42 - 0
baqing-admin/src/test/java/com/ruoyi/web/modules/screen/service/impl/HomeScreenServiceImplTest.java

@@ -5,6 +5,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
5 5
 import static org.mockito.ArgumentMatchers.eq;
6 6
 import static org.mockito.ArgumentMatchers.any;
7 7
 import static org.mockito.ArgumentMatchers.anyList;
8
+import static org.mockito.Mockito.lenient;
8 9
 import static org.mockito.Mockito.when;
9 10
 
10 11
 import java.math.BigDecimal;
@@ -109,6 +110,37 @@ class HomeScreenServiceImplTest
109 110
         assertEquals(50, vo.getMarkers().get(0).getYakOutboundCount().intValue());
110 111
     }
111 112
 
113
+    @Test
114
+    @DisplayName("DP-SY-UT-027 产业总览存栏出栏取自填报合计")
115
+    void ut027_overviewFromReportTables()
116
+    {
117
+        int currentYear = Year.now().getValue();
118
+        stubBreedingWithOneYak();
119
+        stubOtherBlocks();
120
+        when(homeScreenStatsMapper.sumHerdInventoryYakTotalByStatYear(eq(currentYear - 1))).thenReturn(50000);
121
+        when(homeScreenStatsMapper.sumOutboundReportYakCountByStatYear(eq(currentYear))).thenReturn(3200);
122
+
123
+        HomeScreenDashboardVo vo = service.loadDashboard("2024");
124
+
125
+        assertEquals(50000, vo.getIndustryOverview().getInventoryTotal());
126
+        assertEquals(3200, vo.getIndustryOverview().getAnnualOutbound());
127
+    }
128
+
129
+    @Test
130
+    @DisplayName("DP-SY-UT-028 产业总览农牧户取自出栏填报合计")
131
+    void ut028_farmerHouseholdFromReportTable()
132
+    {
133
+        int currentYear = Year.now().getValue();
134
+        stubBreedingWithOneYak();
135
+        stubOtherBlocks();
136
+        when(homeScreenStatsMapper.sumOutboundReportFarmerHouseholdCountByStatYear(eq(currentYear)))
137
+                .thenReturn(8988);
138
+
139
+        HomeScreenDashboardVo vo = service.loadDashboard("2025");
140
+
141
+        assertEquals(8988, vo.getIndustryOverview().getPastureCount());
142
+    }
143
+
112 144
     private void stubBreedingEmpty()
113 145
     {
114 146
         when(breedingIndustryStatsMapper.selectActivePastureIds()).thenReturn(Collections.singletonList(1L));
@@ -122,6 +154,11 @@ class HomeScreenServiceImplTest
122 154
         when(breedingIndustryStatsMapper.selectDegradationGroupCounts()).thenReturn(Collections.emptyList());
123 155
         when(homeScreenStatsMapper.selectOutboundCountByMonth(anyList(), any(), any()))
124 156
                 .thenReturn(Collections.emptyList());
157
+        int currentYear = Year.now().getValue();
158
+        lenient().when(homeScreenStatsMapper.sumHerdInventoryYakTotalByStatYear(eq(currentYear - 1))).thenReturn(0);
159
+        lenient().when(homeScreenStatsMapper.sumOutboundReportYakCountByStatYear(eq(currentYear))).thenReturn(0);
160
+        lenient().when(homeScreenStatsMapper.sumOutboundReportFarmerHouseholdCountByStatYear(eq(currentYear)))
161
+                .thenReturn(0);
125 162
     }
126 163
 
127 164
     private void stubBreedingWithOneYak()
@@ -143,6 +180,11 @@ class HomeScreenServiceImplTest
143 180
         when(breedingIndustryStatsMapper.selectDegradationGroupCounts()).thenReturn(Collections.emptyList());
144 181
         when(homeScreenStatsMapper.selectOutboundCountByMonth(anyList(), any(), any()))
145 182
                 .thenReturn(Collections.emptyList());
183
+        int currentYear = Year.now().getValue();
184
+        lenient().when(homeScreenStatsMapper.sumHerdInventoryYakTotalByStatYear(eq(currentYear - 1))).thenReturn(0);
185
+        lenient().when(homeScreenStatsMapper.sumOutboundReportYakCountByStatYear(eq(currentYear))).thenReturn(0);
186
+        lenient().when(homeScreenStatsMapper.sumOutboundReportFarmerHouseholdCountByStatYear(eq(currentYear)))
187
+                .thenReturn(0);
146 188
     }
147 189
 
148 190
     private void stubOtherBlocks()

+ 3 - 3
doc/大屏/首页/大屏首页功能需求.md

@@ -266,9 +266,9 @@ flowchart TB
266 266
 
267 267
 | 序号 | 指标名称 | 单位 | 统计口径 |
268 268
 | --- | --- | --- | --- |
269
-| 1 | 牦牛存栏总量 | 头 | **§2.5** 时点存栏 |
270
-| 2 | 牦牛年出栏量 | 头 | **§2.5** 年内出栏 |
271
-| 3 | 牧场数量 | 个 | **§2.5** |
269
+| 1 | 牦牛存栏总量 | 头 | `biz_yak_herd_inventory.yak_total` 全县乡镇合计;统计年 = **当前自然年 − 1**;接口字段沿用 **`inventoryTotal`** |
270
+| 2 | 牦牛年出栏量 | 头 | `biz_yak_outbound_report.yak_outbound_count` 全县乡镇合计;统计年 = **当前自然年**;接口字段沿用 **`annualOutbound`** |
271
+| 3 | 农牧户 | 户 | `biz_yak_outbound_report.farmer_household_count` 全县乡镇合计;统计年 = **当前自然年**;接口字段沿用 **`pastureCount`** |
272 272
 | 4 | 草场数量 | 个 | **§2.5** |
273 273
 | 5 | 草场面积 | 亩 | **§2.5** |
274 274
 | 6 | 供应商数量 | 个 | **§2.6** 实时快照 |

+ 6 - 4
doc/大屏/首页/大屏首页技术方案.md

@@ -222,9 +222,10 @@
222 222
 
223 223
 | 字段 | 说明 |
224 224
 | --- | --- |
225
-| `inventoryTotal` | 牦牛存栏(头),时点 |
226
-| `annualOutbound` | 年出栏(头),**Y** 年内 |
227
-| `pastureCount` / `grasslandCount` / `grasslandAreaMu` | 牧场、草场、面积 |
225
+| `inventoryTotal` | 牦牛存栏(头),`biz_yak_herd_inventory` 全县 `yak_total` 合计;年份 = 当前自然年 **− 1**;**字段名不变** |
226
+| `annualOutbound` | 年出栏(头),`biz_yak_outbound_report` 全县 `yak_outbound_count` 合计;年份 = 当前自然年;**字段名不变** |
227
+| `pastureCount` | 农牧户(户),`biz_yak_outbound_report` 全县 `farmer_household_count` 合计;年份 = 当前自然年;**字段名不变** |
228
+| `grasslandCount` / `grasslandAreaMu` | 草场、面积 |
228 229
 | `supplierCount` / `distributorCount` / `tradeMarketCount` | 流通三项**实时**快照 |
229 230
 
230 231
 #### 3.1.2 `inventoryChange`
@@ -344,7 +345,8 @@
344 345
 7. agriClassroom = tech video count + training publish count by year
345 346
 8. trainingTrend = training by month; hasTrainingData
346 347
 9. availableYears = union(distinct years from各源表, current year)
347
-10. return AjaxResult.success(vo)
348
+10. industryOverview 填报合计填入既有字段:`inventoryTotal` / `annualOutbound` / `pastureCount`(农牧户);原牧场/快照口径在 Service 内暂保留
349
+11. return AjaxResult.success(vo)
348 350
 ```
349 351
 
350 352
 ---

+ 2 - 0
doc/大屏/首页/大屏首页测试用例.md

@@ -77,6 +77,8 @@
77 77
 | DP-SY-UT-024 | 约束 | 无标准详情接口 | 单元测试 | JUnit5 | §5.9 | 检查 Controller 映射 | 无 `GET .../standards/{id}` | 仅列表分页 |
78 78
 | DP-SY-UT-025 | 缓存 | forceRefresh | 单元测试 | JUnit5 | 技术§2.3 | 启用缓存未过期 | `loadDashboard(2026,true)` | 跳过缓存重新聚合 |
79 79
 | DP-SY-UT-026 | 地图标注 | 年份与字段 | 单元测试 | JUnit5 | §5.12 | Mock Mapper 返回 1 乡镇 | `loadTownMapMarkers()` | `herdStatYear=当前年-1`;`outboundStatYear=当前年`;含 `townDeptId`/`townName`/存栏/出栏 |
80
+| DP-SY-UT-027 | 产业总览 | 填报合计 | 单元测试 | JUnit5 | §5.2 | Mock 填报合计 | `loadDashboard` | `inventoryTotal`/`annualOutbound` 取自填报表;与 **Y** 无关 |
81
+| DP-SY-UT-028 | 产业总览 | 农牧户合计 | 单元测试 | JUnit5 | §5.2 | Mock 出栏填报农牧户户数 | `loadDashboard` | `pastureCount` 为当年全县农牧户合计(字段名不变) |
80 82
 
81 83
 ---
82 84