wwh 1 tydzień temu
rodzic
commit
593cd54e5f

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

@@ -36,7 +36,7 @@ public class HomeScreenDashboardVo
36 36
     private List<HomeScreenNamedCountItemVo> cooperativeBusinessModel;
37 37
     /** 农牧户分类 */
38 38
     private List<HomeScreenNamedCountItemVo> farmerHouseholdClassification;
39
-    /** 人均收入:距当前最近 5 年趋势(农村可支配收入 / 脱贫人均纯收入) */
39
+    /** 人均收入:以库中最大所属年为终点的最近 5 年趋势(农村可支配收入 / 脱贫人均纯收入) */
40 40
     private List<HomeScreenPerCapitaIncomeYearVo> perCapitaIncomeTrend;
41 41
     /** 草场可用/在用及退化等级分布 */
42 42
     private HomeScreenGrasslandVo grassland;

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

@@ -227,6 +227,9 @@ public interface HomeScreenStatsMapper
227 227
     List<HomeScreenDisposableIncomeYearDto> selectDisposableIncomeByYearRange(
228 228
             @Param("startYear") int startYear, @Param("endYear") int endYear);
229 229
 
230
+    /** 可支配收入填报最大所属年份;无数据返回 null */
231
+    Integer selectLatestDisposableIncomeStatYear();
232
+
230 233
     /**
231 234
      * 牦牛存出栏情况明细:按 {@code (stat_year, stat_month, village_dept_id)} 关联存栏/出栏填报;
232 235
      * 按年、月倒序。缺一侧时存栏或出栏计为 0。

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

@@ -254,12 +254,19 @@ public class HomeScreenServiceImpl implements IHomeScreenService
254 254
                     homeScreenStatsMapper.countFarmerHouseholdClassByStatYearMonth(
255 255
                             yearFarmerHousehold.getStatYear(), yearFarmerHousehold.getStatMonth())));
256 256
         }
257
-        // 人均收入:距当前最近 5 年(与所选年无关)
258
-        int incomeEndYear = HomeScreenSupport.currentYearMonth().getYear();
259
-        int incomeStartYear = incomeEndYear - 4;
260
-        vo.setPerCapitaIncomeTrend(HomeScreenSupport.buildPerCapitaIncomeTrend(
261
-                homeScreenStatsMapper.selectDisposableIncomeByYearRange(incomeStartYear, incomeEndYear),
262
-                incomeEndYear));
257
+        // 人均收入:以库中最大所属年为终点,向前共 5 年(与所选年无关)
258
+        Integer incomeEndYear = homeScreenStatsMapper.selectLatestDisposableIncomeStatYear();
259
+        if (incomeEndYear == null)
260
+        {
261
+            vo.setPerCapitaIncomeTrend(Collections.emptyList());
262
+        }
263
+        else
264
+        {
265
+            int incomeStartYear = incomeEndYear - 4;
266
+            vo.setPerCapitaIncomeTrend(HomeScreenSupport.buildPerCapitaIncomeTrend(
267
+                    homeScreenStatsMapper.selectDisposableIncomeByYearRange(incomeStartYear, incomeEndYear),
268
+                    incomeEndYear));
269
+        }
263 270
 
264 271
         YearMonth anchor = HomeScreenSupport.currentYearMonth();
265 272
         int startYm = HomeScreenSupport.yearMonthKey(anchor.minusMonths(11));

+ 1 - 0
baqing-admin/src/main/java/com/ruoyi/web/modules/screen/support/HomeScreenSupport.java

@@ -777,6 +777,7 @@ public final class HomeScreenSupport
777 777
 
778 778
     /**
779 779
      * 人均收入最近 5 年趋势(含 endYear 往前共 5 年);缺年补 0;单位元。
780
+     * {@code endYear} 应为库中可支配收入最大所属年。
780 781
      */
781 782
     public static List<HomeScreenPerCapitaIncomeYearVo> buildPerCapitaIncomeTrend(
782 783
             List<HomeScreenDisposableIncomeYearDto> rows, int endYear)

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

@@ -550,6 +550,11 @@
550 550
         order by stat_year
551 551
     </select>
552 552
 
553
+    <select id="selectLatestDisposableIncomeStatYear" resultType="java.lang.Integer">
554
+        select max(stat_year)
555
+        from biz_disposable_income
556
+    </select>
557
+
553 558
     <!-- 牦牛存出栏情况明细:唯一键关联;支持跨年全量翻页(年月可选不过滤) -->
554 559
     <sql id="yakInventoryOutboundHerdFilter">
555 560
         <if test="statYear != null">

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

@@ -36,6 +36,7 @@ class HomeScreenStatsMapperXmlTest
36 36
         assertTrue(xml.contains("countCooperativeBusinessModelByStatYearMonth"));
37 37
         assertTrue(xml.contains("countFarmerHouseholdClassByStatYearMonth"));
38 38
         assertTrue(xml.contains("selectDisposableIncomeByYearRange"));
39
+        assertTrue(xml.contains("selectLatestDisposableIncomeStatYear"));
39 40
         assertTrue(xml.contains("biz_disposable_income"));
40 41
         assertTrue(xml.contains("rural_disposable_income"));
41 42
         assertTrue(xml.contains("business_model"));

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

@@ -829,13 +829,14 @@ class HomeScreenServiceImplTest
829 829
     }
830 830
 
831 831
     @Test
832
-    @DisplayName("DP-SY-UT-037 人均收入取距当前最近5年")
832
+    @DisplayName("DP-SY-UT-037 人均收入取库中最大所属年向前共5年")
833 833
     void ut037_perCapitaIncomeTrend()
834 834
     {
835 835
         stubGrasslandAndReport();
836 836
         stubOtherBlocks();
837
-        int endYear = java.time.YearMonth.now(java.time.ZoneId.of("Asia/Shanghai")).getYear();
837
+        int endYear = 2024;
838 838
         int startYear = endYear - 4;
839
+        when(homeScreenStatsMapper.selectLatestDisposableIncomeStatYear()).thenReturn(endYear);
839 840
         HomeScreenDisposableIncomeYearDto row = new HomeScreenDisposableIncomeYearDto();
840 841
         row.setStatYear(endYear);
841 842
         row.setRuralDisposableIncome(new BigDecimal("10000"));
@@ -843,14 +844,28 @@ class HomeScreenServiceImplTest
843 844
         when(homeScreenStatsMapper.selectDisposableIncomeByYearRange(startYear, endYear))
844 845
                 .thenReturn(Collections.singletonList(row));
845 846
 
846
-        HomeScreenDashboardVo vo = service.loadDashboard(String.valueOf(endYear));
847
+        HomeScreenDashboardVo vo = service.loadDashboard("2026");
847 848
 
848 849
         assertEquals(5, vo.getPerCapitaIncomeTrend().size());
849 850
         assertEquals(endYear, vo.getPerCapitaIncomeTrend().get(4).getStatYear());
851
+        assertEquals(startYear, vo.getPerCapitaIncomeTrend().get(0).getStatYear());
850 852
         assertEquals(0, new BigDecimal("10000.00").compareTo(
851 853
                 vo.getPerCapitaIncomeTrend().get(4).getRuralDisposableIncome()));
852 854
     }
853 855
 
856
+    @Test
857
+    @DisplayName("DP-SY-UT-037b 人均收入库中无数据则趋势为空")
858
+    void ut037b_perCapitaIncomeTrendEmpty()
859
+    {
860
+        stubGrasslandAndReport();
861
+        stubOtherBlocks();
862
+        when(homeScreenStatsMapper.selectLatestDisposableIncomeStatYear()).thenReturn(null);
863
+
864
+        HomeScreenDashboardVo vo = service.loadDashboard("2026");
865
+
866
+        assertEquals(0, vo.getPerCapitaIncomeTrend().size());
867
+    }
868
+
854 869
     @Test
855 870
     @DisplayName("DP-SY-UT-028 产业总览农牧户取所选年最大填报月")
856 871
     void ut028_farmerHouseholdFromReportTable()
@@ -938,6 +953,7 @@ class HomeScreenServiceImplTest
938 953
                 .thenReturn(Collections.emptyList());
939 954
         lenient().when(homeScreenStatsMapper.selectDisposableIncomeByYearRange(any(Integer.class), any(Integer.class)))
940 955
                 .thenReturn(Collections.emptyList());
956
+        lenient().when(homeScreenStatsMapper.selectLatestDisposableIncomeStatYear()).thenReturn(null);
941 957
         lenient().when(homeScreenStatsMapper.selectHerdInventoryBullCowByYearMonthRange(any(Integer.class), any(Integer.class)))
942 958
                 .thenReturn(Collections.emptyList());
943 959
         lenient().when(homeScreenStatsMapper.selectOutboundReportYakCountByYearMonthRange(any(Integer.class), any(Integer.class)))

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

@@ -88,7 +88,7 @@
88 88
 | **企业年度收入与补助-养殖大户** | 所选年 **Y** 内 `biz_large_livestock_farmer` 最大填报月全县同上四项合计;柱状图;单位**万元**;字段 **`largeLivestockFarmerFinance`** |
89 89
 | **合作社经营模式分类** | 所选年 **Y** 内 `biz_cooperative_development` 最大填报月按 `business_model` 计数(整村/股份/联合/多种经营/公司型/其他);饼图;单位**个**;字段 **`cooperativeBusinessModel`** |
90 90
 | **农牧户分类** | 所选年 **Y** 内 `biz_farmer_household` 最大填报月各分类标记为「是」的村级记录数(纯牧户/无畜户/绝户/超载牧户/需要封顶/需要保底);柱状图;单位**个**;字段 **`farmerHouseholdClassification`** |
91
-| **人均收入** | `biz_disposable_income` 距**当前年**最近 5 年(含当前年)双折线:农村居民人均可支配收入、脱贫人口人均纯收入;缺年补 0;单位**元**;**不随所选年 Y 切换**;字段 **`perCapitaIncomeTrend`** |
91
+| **人均收入** | `biz_disposable_income` 以库中**最大所属年**为终点向前共 5 年双折线:农村居民人均可支配收入、脱贫人口人均纯收入;缺年补 0;无数据则空;单位**元**;**不随所选年 Y 切换**;字段 **`perCapitaIncomeTrend`** |
92 92
 | **人均收入明细** | 独立接口分页查询 `biz_disposable_income`;条件:所属年份(可选,**默认当前年**);按**所属年份倒序**;返回年份、农村居民人均可支配收入、增幅、增速、脱贫人口人均纯收入 |
93 93
 | **农牧户数据明细** | 独立接口分页查询 `biz_farmer_household`;条件:年(可选,**默认当前年**)、月(可选,**默认当前月**)、乡镇、村;按**年、月倒序**;返回全部业务列表字段 |
94 94
 | **草场面积数据明细** | **复用**农牧户数据明细接口(同表同条件;面积字段含 `pasture_contract_area` 等);**不另开**独立接口 |
@@ -503,6 +503,7 @@ flowchart TB
503 503
 
504 504
 | 版本 | 日期 | 说明 |
505 505
 | --- | --- | --- |
506
+| 1.19 | 2026-07-24 | 人均收入趋势改为以库中最大所属年为终点的最近 5 年 |
506 507
 | 1.18 | 2026-07-24 | 牦牛月度出栏趋势改为按填报最大月 N 输出 1~N 月(区间缺月补 0) |
507 508
 | 1.17 | 2026-07-23 | 公母牛月度存栏趋势改为按填报最大月 N 输出 1~N 月(区间缺月补 0) |
508 509
 | 1.16 | 2026-07-23 | 新增大屏乡镇列表、村树接口(全县口径) |

+ 1 - 0
doc/大屏/首页/大屏首页技术方案.md

@@ -663,6 +663,7 @@ SQL 示例:`sql/big_screen_home_perm.sql`(挂载「大屏」父菜单下)
663 663
 
664 664
 | 版本 | 日期 | 说明 |
665 665
 | --- | --- | --- |
666
+| 1.20 | 2026-07-24 | 人均收入 `perCapitaIncomeTrend`:以库中最大所属年为终点向前 5 年 |
666 667
 | 1.19 | 2026-07-24 | 出栏 `outboundMonthly`:按填报最大月 N 输出 1~N |
667 668
 | 1.18 | 2026-07-23 | 公母牛 `monthlyTrend`:按填报最大月 N 输出 1~N |
668 669
 | 1.17 | 2026-07-23 | 新增大屏 `/townOptions`、`/villageTree`(全县口径) |