wwh преди 1 седмица
родител
ревизия
638cb5ba0e
променени са 14 файла, в които са добавени 1053 реда и са изтрити 2 реда
  1. 81 0
      baqing-admin/src/main/java/com/ruoyi/web/modules/screen/controller/LivestockResourceScreenController.java
  2. 82 0
      baqing-admin/src/main/java/com/ruoyi/web/modules/screen/domain/vo/LivestockResourceProductOutputListItemVo.java
  3. 96 0
      baqing-admin/src/main/java/com/ruoyi/web/modules/screen/domain/vo/LivestockResourceThreeAssetsProblemListItemVo.java
  4. 94 0
      baqing-admin/src/main/java/com/ruoyi/web/modules/screen/domain/vo/LivestockResourceVaccinationListItemVo.java
  5. 32 0
      baqing-admin/src/main/java/com/ruoyi/web/modules/screen/domain/vo/LivestockResourceVetCountListItemVo.java
  6. 7 0
      baqing-admin/src/main/java/com/ruoyi/web/modules/screen/mapper/LivestockResourceScreenMapper.java
  7. 32 0
      baqing-admin/src/main/java/com/ruoyi/web/modules/screen/service/ILivestockResourceScreenService.java
  8. 89 0
      baqing-admin/src/main/java/com/ruoyi/web/modules/screen/service/impl/LivestockResourceScreenServiceImpl.java
  9. 124 0
      baqing-admin/src/main/java/com/ruoyi/web/modules/screen/support/LivestockResourceScreenSupport.java
  10. 15 0
      baqing-admin/src/main/resources/mapper/screen/LivestockResourceScreenMapper.xml
  11. 113 0
      baqing-admin/src/test/java/com/ruoyi/web/modules/screen/controller/LivestockResourceScreenControllerApiTest.java
  12. 111 0
      baqing-admin/src/test/java/com/ruoyi/web/modules/screen/service/impl/LivestockResourceScreenServiceImplTest.java
  13. 48 0
      baqing-admin/src/test/java/com/ruoyi/web/modules/screen/support/LivestockResourceScreenSupportTest.java
  14. 129 2
      doc/大屏/畜牧资源/大屏畜牧资源技术方案.md

+ 81 - 0
baqing-admin/src/main/java/com/ruoyi/web/modules/screen/controller/LivestockResourceScreenController.java

@@ -1,5 +1,6 @@
1 1
 package com.ruoyi.web.modules.screen.controller;
2 2
 
3
+import java.util.List;
3 4
 import org.springframework.beans.factory.annotation.Autowired;
4 5
 import org.springframework.web.bind.annotation.GetMapping;
5 6
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -7,6 +8,11 @@ import org.springframework.web.bind.annotation.RequestParam;
7 8
 import org.springframework.web.bind.annotation.RestController;
8 9
 import com.ruoyi.common.core.controller.BaseController;
9 10
 import com.ruoyi.common.core.domain.AjaxResult;
11
+import com.ruoyi.common.core.page.TableDataInfo;
12
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceProductOutputListItemVo;
13
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceThreeAssetsProblemListItemVo;
14
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceVaccinationListItemVo;
15
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceVetCountListItemVo;
10 16
 import com.ruoyi.web.modules.screen.service.ILivestockResourceScreenService;
11 17
 
12 18
 /**
@@ -34,4 +40,79 @@ public class LivestockResourceScreenController extends BaseController
34 40
     {
35 41
         return success(livestockResourceScreenService.loadDashboard(statYear));
36 42
     }
43
+
44
+    /**
45
+     * 三资具体问题上报情况明细(分页);按上报时间倒序。
46
+     * <p>
47
+     * 查询条件:所属年份(可选,默认当前自然年)、所属乡镇、所属村。
48
+     * 数据源 {@code biz_three_assets_problem_report}。
49
+     * </p>
50
+     */
51
+    @GetMapping("/threeAssetsProblemReports")
52
+    public TableDataInfo threeAssetsProblemReports(
53
+            @RequestParam(value = "statYear", required = false) Integer statYear,
54
+            @RequestParam(value = "townDeptId", required = false) Long townDeptId,
55
+            @RequestParam(value = "villageDeptId", required = false) Long villageDeptId)
56
+    {
57
+        startPage();
58
+        List<LivestockResourceThreeAssetsProblemListItemVo> list =
59
+                livestockResourceScreenService.listThreeAssetsProblemReports(statYear, townDeptId, villageDeptId);
60
+        return getDataTable(list);
61
+    }
62
+
63
+    /**
64
+     * 畜牧产品产量数据明细(分页);按所属年月倒序。
65
+     * <p>
66
+     * 查询条件:所属年份(可选,默认当前自然年)、所属月份(可选,默认当前自然月)、所属乡镇、所属村。
67
+     * 数据源 {@code biz_livestock_product_output}。
68
+     * </p>
69
+     */
70
+    @GetMapping("/productOutputs")
71
+    public TableDataInfo productOutputs(
72
+            @RequestParam(value = "statYear", required = false) Integer statYear,
73
+            @RequestParam(value = "statMonth", required = false) Integer statMonth,
74
+            @RequestParam(value = "townDeptId", required = false) Long townDeptId,
75
+            @RequestParam(value = "villageDeptId", required = false) Long villageDeptId)
76
+    {
77
+        startPage();
78
+        List<LivestockResourceProductOutputListItemVo> list =
79
+                livestockResourceScreenService.listProductOutputs(statYear, statMonth, townDeptId, villageDeptId);
80
+        return getDataTable(list);
81
+    }
82
+
83
+    /**
84
+     * 疫苗接种情况明细(分页);按所属年月倒序。
85
+     * <p>
86
+     * 查询条件:所属年份(可选,默认当前自然年)、所属月份(可选,默认当前自然月)、所属乡镇、所属村。
87
+     * 数据源 {@code biz_vaccination_data}。
88
+     * </p>
89
+     */
90
+    @GetMapping("/vaccinationData")
91
+    public TableDataInfo vaccinationData(
92
+            @RequestParam(value = "statYear", required = false) Integer statYear,
93
+            @RequestParam(value = "statMonth", required = false) Integer statMonth,
94
+            @RequestParam(value = "townDeptId", required = false) Long townDeptId,
95
+            @RequestParam(value = "villageDeptId", required = false) Long villageDeptId)
96
+    {
97
+        startPage();
98
+        List<LivestockResourceVaccinationListItemVo> list =
99
+                livestockResourceScreenService.listVaccinationData(statYear, statMonth, townDeptId, villageDeptId);
100
+        return getDataTable(list);
101
+    }
102
+
103
+    /**
104
+     * 兽医数量明细(分页);按乡镇汇总人数。
105
+     * <p>
106
+     * 查询条件:所属乡镇(可选)。
107
+     * 数据源 {@code biz_medical_resource},口径 {@code resource_type=004001} 且 {@code del_flag=0}。
108
+     * </p>
109
+     */
110
+    @GetMapping("/vetCounts")
111
+    public TableDataInfo vetCounts(
112
+            @RequestParam(value = "townDeptId", required = false) Long townDeptId)
113
+    {
114
+        startPage();
115
+        List<LivestockResourceVetCountListItemVo> list = livestockResourceScreenService.listVetCounts(townDeptId);
116
+        return getDataTable(list);
117
+    }
37 118
 }

+ 82 - 0
baqing-admin/src/main/java/com/ruoyi/web/modules/screen/domain/vo/LivestockResourceProductOutputListItemVo.java

@@ -0,0 +1,82 @@
1
+package com.ruoyi.web.modules.screen.domain.vo;
2
+
3
+import java.math.BigDecimal;
4
+
5
+/**
6
+ * 大屏畜牧资源 — 畜牧产品产量数据明细行。
7
+ */
8
+public class LivestockResourceProductOutputListItemVo
9
+{
10
+    /** 所属年份 */
11
+    private Integer statYear;
12
+    /** 所属月份 */
13
+    private Integer statMonth;
14
+    /** 乡镇名称 */
15
+    private String townName;
16
+    /** 村名称 */
17
+    private String villageName;
18
+    /** 肉产量(万吨) */
19
+    private BigDecimal meatOutput;
20
+    /** 奶产量(万吨) */
21
+    private BigDecimal milkOutput;
22
+
23
+    public Integer getStatYear()
24
+    {
25
+        return statYear;
26
+    }
27
+
28
+    public void setStatYear(Integer statYear)
29
+    {
30
+        this.statYear = statYear;
31
+    }
32
+
33
+    public Integer getStatMonth()
34
+    {
35
+        return statMonth;
36
+    }
37
+
38
+    public void setStatMonth(Integer statMonth)
39
+    {
40
+        this.statMonth = statMonth;
41
+    }
42
+
43
+    public String getTownName()
44
+    {
45
+        return townName;
46
+    }
47
+
48
+    public void setTownName(String townName)
49
+    {
50
+        this.townName = townName;
51
+    }
52
+
53
+    public String getVillageName()
54
+    {
55
+        return villageName;
56
+    }
57
+
58
+    public void setVillageName(String villageName)
59
+    {
60
+        this.villageName = villageName;
61
+    }
62
+
63
+    public BigDecimal getMeatOutput()
64
+    {
65
+        return meatOutput;
66
+    }
67
+
68
+    public void setMeatOutput(BigDecimal meatOutput)
69
+    {
70
+        this.meatOutput = meatOutput;
71
+    }
72
+
73
+    public BigDecimal getMilkOutput()
74
+    {
75
+        return milkOutput;
76
+    }
77
+
78
+    public void setMilkOutput(BigDecimal milkOutput)
79
+    {
80
+        this.milkOutput = milkOutput;
81
+    }
82
+}

+ 96 - 0
baqing-admin/src/main/java/com/ruoyi/web/modules/screen/domain/vo/LivestockResourceThreeAssetsProblemListItemVo.java

@@ -0,0 +1,96 @@
1
+package com.ruoyi.web.modules.screen.domain.vo;
2
+
3
+import java.util.Date;
4
+import com.fasterxml.jackson.annotation.JsonFormat;
5
+
6
+/**
7
+ * 大屏畜牧资源 — 三资具体问题上报明细行。
8
+ */
9
+public class LivestockResourceThreeAssetsProblemListItemVo
10
+{
11
+    /** 上报时间 */
12
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
13
+    private Date reportTime;
14
+    /** 乡镇名称 */
15
+    private String townName;
16
+    /** 村名称 */
17
+    private String villageName;
18
+    /** 问题等级编码:general / key / major */
19
+    private String problemLevel;
20
+    /** 问题等级名称:一般 / 重点 / 重大 */
21
+    private String problemLevelName;
22
+    /** 问题详细描述 */
23
+    private String problemDetail;
24
+    /** 处理结果 */
25
+    private String handleResult;
26
+
27
+    public Date getReportTime()
28
+    {
29
+        return reportTime;
30
+    }
31
+
32
+    public void setReportTime(Date reportTime)
33
+    {
34
+        this.reportTime = reportTime;
35
+    }
36
+
37
+    public String getTownName()
38
+    {
39
+        return townName;
40
+    }
41
+
42
+    public void setTownName(String townName)
43
+    {
44
+        this.townName = townName;
45
+    }
46
+
47
+    public String getVillageName()
48
+    {
49
+        return villageName;
50
+    }
51
+
52
+    public void setVillageName(String villageName)
53
+    {
54
+        this.villageName = villageName;
55
+    }
56
+
57
+    public String getProblemLevel()
58
+    {
59
+        return problemLevel;
60
+    }
61
+
62
+    public void setProblemLevel(String problemLevel)
63
+    {
64
+        this.problemLevel = problemLevel;
65
+    }
66
+
67
+    public String getProblemLevelName()
68
+    {
69
+        return problemLevelName;
70
+    }
71
+
72
+    public void setProblemLevelName(String problemLevelName)
73
+    {
74
+        this.problemLevelName = problemLevelName;
75
+    }
76
+
77
+    public String getProblemDetail()
78
+    {
79
+        return problemDetail;
80
+    }
81
+
82
+    public void setProblemDetail(String problemDetail)
83
+    {
84
+        this.problemDetail = problemDetail;
85
+    }
86
+
87
+    public String getHandleResult()
88
+    {
89
+        return handleResult;
90
+    }
91
+
92
+    public void setHandleResult(String handleResult)
93
+    {
94
+        this.handleResult = handleResult;
95
+    }
96
+}

+ 94 - 0
baqing-admin/src/main/java/com/ruoyi/web/modules/screen/domain/vo/LivestockResourceVaccinationListItemVo.java

@@ -0,0 +1,94 @@
1
+package com.ruoyi.web.modules.screen.domain.vo;
2
+
3
+import java.math.BigDecimal;
4
+
5
+/**
6
+ * 大屏畜牧资源 — 疫苗接种情况明细行。
7
+ */
8
+public class LivestockResourceVaccinationListItemVo
9
+{
10
+    /** 所属年份 */
11
+    private Integer statYear;
12
+    /** 所属月份 */
13
+    private Integer statMonth;
14
+    /** 乡镇名称 */
15
+    private String townName;
16
+    /** 村名称 */
17
+    private String villageName;
18
+    /** 应免数(头) */
19
+    private Integer shouldVaccinateCount;
20
+    /** 实免数(头) */
21
+    private Integer actualVaccinateCount;
22
+    /** 免疫率 %,2 位小数 */
23
+    private BigDecimal immunityRate;
24
+
25
+    public Integer getStatYear()
26
+    {
27
+        return statYear;
28
+    }
29
+
30
+    public void setStatYear(Integer statYear)
31
+    {
32
+        this.statYear = statYear;
33
+    }
34
+
35
+    public Integer getStatMonth()
36
+    {
37
+        return statMonth;
38
+    }
39
+
40
+    public void setStatMonth(Integer statMonth)
41
+    {
42
+        this.statMonth = statMonth;
43
+    }
44
+
45
+    public String getTownName()
46
+    {
47
+        return townName;
48
+    }
49
+
50
+    public void setTownName(String townName)
51
+    {
52
+        this.townName = townName;
53
+    }
54
+
55
+    public String getVillageName()
56
+    {
57
+        return villageName;
58
+    }
59
+
60
+    public void setVillageName(String villageName)
61
+    {
62
+        this.villageName = villageName;
63
+    }
64
+
65
+    public Integer getShouldVaccinateCount()
66
+    {
67
+        return shouldVaccinateCount;
68
+    }
69
+
70
+    public void setShouldVaccinateCount(Integer shouldVaccinateCount)
71
+    {
72
+        this.shouldVaccinateCount = shouldVaccinateCount;
73
+    }
74
+
75
+    public Integer getActualVaccinateCount()
76
+    {
77
+        return actualVaccinateCount;
78
+    }
79
+
80
+    public void setActualVaccinateCount(Integer actualVaccinateCount)
81
+    {
82
+        this.actualVaccinateCount = actualVaccinateCount;
83
+    }
84
+
85
+    public BigDecimal getImmunityRate()
86
+    {
87
+        return immunityRate;
88
+    }
89
+
90
+    public void setImmunityRate(BigDecimal immunityRate)
91
+    {
92
+        this.immunityRate = immunityRate;
93
+    }
94
+}

+ 32 - 0
baqing-admin/src/main/java/com/ruoyi/web/modules/screen/domain/vo/LivestockResourceVetCountListItemVo.java

@@ -0,0 +1,32 @@
1
+package com.ruoyi.web.modules.screen.domain.vo;
2
+
3
+/**
4
+ * 大屏畜牧资源 — 兽医数量明细行(按乡镇汇总)。
5
+ */
6
+public class LivestockResourceVetCountListItemVo
7
+{
8
+    /** 乡镇名称 */
9
+    private String townName;
10
+    /** 兽医数量(人) */
11
+    private Long vetCount;
12
+
13
+    public String getTownName()
14
+    {
15
+        return townName;
16
+    }
17
+
18
+    public void setTownName(String townName)
19
+    {
20
+        this.townName = townName;
21
+    }
22
+
23
+    public Long getVetCount()
24
+    {
25
+        return vetCount;
26
+    }
27
+
28
+    public void setVetCount(Long vetCount)
29
+    {
30
+        this.vetCount = vetCount;
31
+    }
32
+}

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

@@ -15,6 +15,7 @@ import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceThreeAssetsSumDt
15 15
 import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceTechPersonnelDto;
16 16
 import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceUserStructureDto;
17 17
 import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceVaccinationSumDto;
18
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceVetCountListItemVo;
18 19
 
19 20
 /**
20 21
  * 大屏畜牧资源统计只读 Mapper。
@@ -52,6 +53,12 @@ public interface LivestockResourceScreenMapper
52 53
     /** 兽医人员数:resource_type=004001 且未删除 */
53 54
     Long countVetMedicalResource();
54 55
 
56
+    /**
57
+     * 兽医人数按乡镇汇总(resource_type=004001 且未删除);可选按乡镇筛选。
58
+     * <p>按部门 order_num、乡镇 ID 升序。</p>
59
+     */
60
+    List<LivestockResourceVetCountListItemVo> selectVetCountByTown(@Param("townDeptId") Long townDeptId);
61
+
55 62
     /** 诊疗机构数:resource_type=004003 且未删除 */
56 63
     Long countMedicalOrgResource();
57 64
 

+ 32 - 0
baqing-admin/src/main/java/com/ruoyi/web/modules/screen/service/ILivestockResourceScreenService.java

@@ -1,6 +1,11 @@
1 1
 package com.ruoyi.web.modules.screen.service;
2 2
 
3
+import java.util.List;
3 4
 import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceDashboardVo;
5
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceProductOutputListItemVo;
6
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceThreeAssetsProblemListItemVo;
7
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceVaccinationListItemVo;
8
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceVetCountListItemVo;
4 9
 
5 10
 /**
6 11
  * 大屏畜牧资源统计服务。
@@ -9,4 +14,31 @@ public interface ILivestockResourceScreenService
9 14
 {
10 15
     /** 畜牧资源看板(产业与培训相关区块;AI 问诊九区块已屏蔽) */
11 16
     LivestockResourceDashboardVo loadDashboard(String statYear);
17
+
18
+    /**
19
+     * 三资具体问题上报明细(分页;按上报时间倒序)。
20
+     * <p>所属年份未传时默认当前自然年;乡镇、村可选。</p>
21
+     */
22
+    List<LivestockResourceThreeAssetsProblemListItemVo> listThreeAssetsProblemReports(
23
+            Integer statYear, Long townDeptId, Long villageDeptId);
24
+
25
+    /**
26
+     * 畜牧产品产量数据明细(分页;按所属年月倒序)。
27
+     * <p>所属年份/月份未传时默认当前自然年月;乡镇、村可选。</p>
28
+     */
29
+    List<LivestockResourceProductOutputListItemVo> listProductOutputs(
30
+            Integer statYear, Integer statMonth, Long townDeptId, Long villageDeptId);
31
+
32
+    /**
33
+     * 疫苗接种情况明细(分页;按所属年月倒序)。
34
+     * <p>所属年份/月份未传时默认当前自然年月;乡镇、村可选。</p>
35
+     */
36
+    List<LivestockResourceVaccinationListItemVo> listVaccinationData(
37
+            Integer statYear, Integer statMonth, Long townDeptId, Long villageDeptId);
38
+
39
+    /**
40
+     * 兽医数量明细(分页;按乡镇汇总)。
41
+     * <p>所属乡镇可选;口径同总览:resource_type=004001 且 del_flag=0。</p>
42
+     */
43
+    List<LivestockResourceVetCountListItemVo> listVetCounts(Long townDeptId);
12 44
 }

+ 89 - 0
baqing-admin/src/main/java/com/ruoyi/web/modules/screen/service/impl/LivestockResourceScreenServiceImpl.java

@@ -2,10 +2,19 @@ package com.ruoyi.web.modules.screen.service.impl;
2 2
 
3 3
 import java.time.LocalDate;
4 4
 import java.time.LocalDateTime;
5
+import java.time.YearMonth;
5 6
 import java.time.ZoneId;
7
+import java.util.Collections;
6 8
 import java.util.Date;
9
+import java.util.List;
7 10
 import org.springframework.beans.factory.annotation.Autowired;
8 11
 import org.springframework.stereotype.Service;
12
+import com.ruoyi.web.modules.industryservice.domain.BizLivestockProductOutput;
13
+import com.ruoyi.web.modules.industryservice.domain.BizThreeAssetsProblemReport;
14
+import com.ruoyi.web.modules.industryservice.domain.BizVaccinationData;
15
+import com.ruoyi.web.modules.industryservice.mapper.BizLivestockProductOutputMapper;
16
+import com.ruoyi.web.modules.industryservice.mapper.BizThreeAssetsProblemReportMapper;
17
+import com.ruoyi.web.modules.industryservice.mapper.BizVaccinationDataMapper;
9 18
 import com.ruoyi.web.modules.industryservice.support.BreedingIndustryRules;
10 19
 import com.ruoyi.web.modules.prosperity.support.AchievementReportValidation;
11 20
 import com.ruoyi.web.modules.screen.domain.dto.HomeScreenStatPeriodDto;
@@ -15,6 +24,10 @@ import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceThreeAssetsSumDt
15 24
 import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceVaccinationSumDto;
16 25
 import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceDashboardVo;
17 26
 import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceOverviewVo;
27
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceProductOutputListItemVo;
28
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceThreeAssetsProblemListItemVo;
29
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceVaccinationListItemVo;
30
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceVetCountListItemVo;
18 31
 import com.ruoyi.web.modules.screen.mapper.HomeScreenStatsMapper;
19 32
 import com.ruoyi.web.modules.screen.mapper.LivestockResourceScreenMapper;
20 33
 import com.ruoyi.web.modules.screen.service.ILivestockResourceScreenService;
@@ -37,6 +50,15 @@ public class LivestockResourceScreenServiceImpl implements ILivestockResourceScr
37 50
     @Autowired
38 51
     private HomeScreenStatsMapper homeScreenStatsMapper;
39 52
 
53
+    @Autowired
54
+    private BizThreeAssetsProblemReportMapper bizThreeAssetsProblemReportMapper;
55
+
56
+    @Autowired
57
+    private BizLivestockProductOutputMapper bizLivestockProductOutputMapper;
58
+
59
+    @Autowired
60
+    private BizVaccinationDataMapper bizVaccinationDataMapper;
61
+
40 62
     @Override
41 63
     public LivestockResourceDashboardVo loadDashboard(String statYear)
42 64
     {
@@ -90,6 +112,73 @@ public class LivestockResourceScreenServiceImpl implements ILivestockResourceScr
90 112
         return vo;
91 113
     }
92 114
 
115
+    @Override
116
+    public List<LivestockResourceThreeAssetsProblemListItemVo> listThreeAssetsProblemReports(
117
+            Integer statYear, Long townDeptId, Long villageDeptId)
118
+    {
119
+        int year = statYear != null ? statYear : HomeScreenSupport.currentYearMonth().getYear();
120
+        LocalDate yearStart = LocalDate.of(year, 1, 1);
121
+        LocalDate yearEnd = LocalDate.of(year, 12, 31);
122
+
123
+        BizThreeAssetsProblemReport query = new BizThreeAssetsProblemReport();
124
+        query.setTownDeptId(townDeptId);
125
+        query.setVillageDeptId(villageDeptId);
126
+        query.setBeginReportTime(toDate(yearStart));
127
+        query.setEndReportTime(toDate(yearEnd));
128
+        // 大屏全县口径,清空 dataScope
129
+        query.getParams().put("dataScope", "");
130
+        List<BizThreeAssetsProblemReport> rows =
131
+                bizThreeAssetsProblemReportMapper.selectBizThreeAssetsProblemReportList(query);
132
+        return LivestockResourceScreenSupport.buildThreeAssetsProblemListItems(rows);
133
+    }
134
+
135
+    @Override
136
+    public List<LivestockResourceProductOutputListItemVo> listProductOutputs(
137
+            Integer statYear, Integer statMonth, Long townDeptId, Long villageDeptId)
138
+    {
139
+        YearMonth current = HomeScreenSupport.currentYearMonth();
140
+        int year = statYear != null ? statYear : current.getYear();
141
+        int month = statMonth != null ? statMonth : current.getMonthValue();
142
+
143
+        BizLivestockProductOutput query = new BizLivestockProductOutput();
144
+        query.setStatYear(year);
145
+        query.setStatMonth(month);
146
+        query.setTownDeptId(townDeptId);
147
+        query.setVillageDeptId(villageDeptId);
148
+        // 大屏全县口径,清空 dataScope
149
+        query.getParams().put("dataScope", "");
150
+        List<BizLivestockProductOutput> rows =
151
+                bizLivestockProductOutputMapper.selectBizLivestockProductOutputList(query);
152
+        return LivestockResourceScreenSupport.buildProductOutputListItems(rows);
153
+    }
154
+
155
+    @Override
156
+    public List<LivestockResourceVaccinationListItemVo> listVaccinationData(
157
+            Integer statYear, Integer statMonth, Long townDeptId, Long villageDeptId)
158
+    {
159
+        YearMonth current = HomeScreenSupport.currentYearMonth();
160
+        int year = statYear != null ? statYear : current.getYear();
161
+        int month = statMonth != null ? statMonth : current.getMonthValue();
162
+
163
+        BizVaccinationData query = new BizVaccinationData();
164
+        query.setStatYear(year);
165
+        query.setStatMonth(month);
166
+        query.setTownDeptId(townDeptId);
167
+        query.setVillageDeptId(villageDeptId);
168
+        // 大屏全县口径,清空 dataScope
169
+        query.getParams().put("dataScope", "");
170
+        List<BizVaccinationData> rows = bizVaccinationDataMapper.selectBizVaccinationDataList(query);
171
+        return LivestockResourceScreenSupport.buildVaccinationListItems(rows);
172
+    }
173
+
174
+    @Override
175
+    public List<LivestockResourceVetCountListItemVo> listVetCounts(Long townDeptId)
176
+    {
177
+        List<LivestockResourceVetCountListItemVo> rows =
178
+                livestockResourceScreenMapper.selectVetCountByTown(townDeptId);
179
+        return rows != null ? rows : Collections.emptyList();
180
+    }
181
+
93 182
     private LivestockResourceProductOutputSumDto resolveProductOutputSum(int year)
94 183
     {
95 184
         HomeScreenStatPeriodDto period =

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

@@ -21,6 +21,9 @@ import java.util.Set;
21 21
 import java.util.regex.Matcher;
22 22
 import java.util.regex.Pattern;
23 23
 import com.ruoyi.web.modules.diagnosis.support.AiConsultConstants;
24
+import com.ruoyi.web.modules.industryservice.domain.BizLivestockProductOutput;
25
+import com.ruoyi.web.modules.industryservice.domain.BizThreeAssetsProblemReport;
26
+import com.ruoyi.web.modules.industryservice.domain.BizVaccinationData;
24 27
 import com.ruoyi.web.modules.industryservice.support.BreedingIndustryRules;
25 28
 import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceBandCountDto;
26 29
 import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceCategoryCountDto;
@@ -43,6 +46,7 @@ import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceKeywordVo;
43 46
 import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceOverviewVo;
44 47
 import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceProblemLevelItemVo;
45 48
 import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceProblemReportShareVo;
49
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceProductOutputListItemVo;
46 50
 import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceProductOutputMonthPointVo;
47 51
 import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceProductOutputTrendVo;
48 52
 import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceReplyStatusVo;
@@ -51,7 +55,9 @@ import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceSessionBandVo;
51 55
 import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceShareItemVo;
52 56
 import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceStatusItemVo;
53 57
 import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceTechEnvoyStructureVo;
58
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceThreeAssetsProblemListItemVo;
54 59
 import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceUserStructureVo;
60
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceVaccinationListItemVo;
55 61
 import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceVaccinationOverviewVo;
56 62
 
57 63
 /**
@@ -194,6 +200,124 @@ public final class LivestockResourceScreenSupport
194 200
         return vo;
195 201
     }
196 202
 
203
+    /** 三资具体问题上报明细分页行 */
204
+    public static List<LivestockResourceThreeAssetsProblemListItemVo> buildThreeAssetsProblemListItems(
205
+            List<BizThreeAssetsProblemReport> rows)
206
+    {
207
+        if (rows == null || rows.isEmpty())
208
+        {
209
+            return Collections.emptyList();
210
+        }
211
+        List<LivestockResourceThreeAssetsProblemListItemVo> result = new ArrayList<>(rows.size());
212
+        for (BizThreeAssetsProblemReport row : rows)
213
+        {
214
+            if (row == null)
215
+            {
216
+                continue;
217
+            }
218
+            LivestockResourceThreeAssetsProblemListItemVo item = new LivestockResourceThreeAssetsProblemListItemVo();
219
+            item.setReportTime(row.getReportTime());
220
+            item.setTownName(row.getTownName());
221
+            item.setVillageName(row.getVillageName());
222
+            item.setProblemLevel(row.getProblemLevel());
223
+            item.setProblemLevelName(resolveProblemLevelName(row.getProblemLevel()));
224
+            item.setProblemDetail(row.getProblemDetail());
225
+            item.setHandleResult(row.getHandleResult());
226
+            result.add(item);
227
+        }
228
+        return result;
229
+    }
230
+
231
+    public static String resolveProblemLevelName(String levelCode)
232
+    {
233
+        if (LivestockResourceScreenRules.PROBLEM_LEVEL_GENERAL.equals(levelCode))
234
+        {
235
+            return "一般";
236
+        }
237
+        if (LivestockResourceScreenRules.PROBLEM_LEVEL_KEY.equals(levelCode))
238
+        {
239
+            return "重点";
240
+        }
241
+        if (LivestockResourceScreenRules.PROBLEM_LEVEL_MAJOR.equals(levelCode))
242
+        {
243
+            return "重大";
244
+        }
245
+        return levelCode;
246
+    }
247
+
248
+    /** 畜牧产品产量明细分页行 */
249
+    public static List<LivestockResourceProductOutputListItemVo> buildProductOutputListItems(
250
+            List<BizLivestockProductOutput> rows)
251
+    {
252
+        if (rows == null || rows.isEmpty())
253
+        {
254
+            return Collections.emptyList();
255
+        }
256
+        List<LivestockResourceProductOutputListItemVo> result = new ArrayList<>(rows.size());
257
+        for (BizLivestockProductOutput row : rows)
258
+        {
259
+            if (row == null)
260
+            {
261
+                continue;
262
+            }
263
+            LivestockResourceProductOutputListItemVo item = new LivestockResourceProductOutputListItemVo();
264
+            item.setStatYear(row.getStatYear());
265
+            item.setStatMonth(row.getStatMonth());
266
+            item.setTownName(row.getTownName());
267
+            item.setVillageName(row.getVillageName());
268
+            item.setMeatOutput(scaleOutput(row.getMeatOutput()));
269
+            item.setMilkOutput(scaleOutput(row.getMilkOutput()));
270
+            result.add(item);
271
+        }
272
+        return result;
273
+    }
274
+
275
+    /** 疫苗接种情况明细分页行 */
276
+    public static List<LivestockResourceVaccinationListItemVo> buildVaccinationListItems(
277
+            List<BizVaccinationData> rows)
278
+    {
279
+        if (rows == null || rows.isEmpty())
280
+        {
281
+            return Collections.emptyList();
282
+        }
283
+        List<LivestockResourceVaccinationListItemVo> result = new ArrayList<>(rows.size());
284
+        for (BizVaccinationData row : rows)
285
+        {
286
+            if (row == null)
287
+            {
288
+                continue;
289
+            }
290
+            LivestockResourceVaccinationListItemVo item = new LivestockResourceVaccinationListItemVo();
291
+            item.setStatYear(row.getStatYear());
292
+            item.setStatMonth(row.getStatMonth());
293
+            item.setTownName(row.getTownName());
294
+            item.setVillageName(row.getVillageName());
295
+            item.setShouldVaccinateCount(row.getShouldVaccinateCount());
296
+            item.setActualVaccinateCount(row.getActualVaccinateCount());
297
+            item.setImmunityRate(resolveRowImmunityRate(row));
298
+            result.add(item);
299
+        }
300
+        return result;
301
+    }
302
+
303
+    /** 单行免疫率:优先用落库值;为空则按应免/实免重算(应免≤0 时 0.00) */
304
+    public static BigDecimal resolveRowImmunityRate(BizVaccinationData row)
305
+    {
306
+        if (row != null && row.getImmunityRate() != null)
307
+        {
308
+            return row.getImmunityRate().setScale(2, RoundingMode.HALF_UP);
309
+        }
310
+        int should = row != null && row.getShouldVaccinateCount() != null ? row.getShouldVaccinateCount() : 0;
311
+        int actual = row != null && row.getActualVaccinateCount() != null ? row.getActualVaccinateCount() : 0;
312
+        if (should <= 0)
313
+        {
314
+            return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
315
+        }
316
+        return BigDecimal.valueOf(actual)
317
+                .multiply(BigDecimal.valueOf(100))
318
+                .divide(BigDecimal.valueOf(should), 2, RoundingMode.HALF_UP);
319
+    }
320
+
197 321
     /** 畜牧产品产量:1~maxMonth 肉/奶对比;无最大月则空序列 */
198 322
     public static LivestockResourceProductOutputTrendVo buildProductOutputTrend(
199 323
             Integer maxMonth, List<LivestockResourceProductOutputMonthDto> rows)

+ 15 - 0
baqing-admin/src/main/resources/mapper/screen/LivestockResourceScreenMapper.xml

@@ -96,6 +96,21 @@
96 96
           and del_flag = '0'
97 97
     </select>
98 98
 
99
+    <select id="selectVetCountByTown"
100
+            resultType="com.ruoyi.web.modules.screen.domain.vo.LivestockResourceVetCountListItemVo">
101
+        select r.town_name as townName,
102
+               count(1) as vetCount
103
+        from biz_medical_resource r
104
+        left join sys_dept d on r.town_dept_id = d.dept_id
105
+        where r.resource_type = '004001'
106
+          and r.del_flag = '0'
107
+        <if test="townDeptId != null">
108
+            and r.town_dept_id = #{townDeptId}
109
+        </if>
110
+        group by r.town_dept_id, r.town_name, d.order_num
111
+        order by ifnull(d.order_num, 999999) asc, r.town_dept_id asc
112
+    </select>
113
+
99 114
     <select id="countMedicalOrgResource" resultType="long">
100 115
         select count(1)
101 116
         from biz_medical_resource

+ 113 - 0
baqing-admin/src/test/java/com/ruoyi/web/modules/screen/controller/LivestockResourceScreenControllerApiTest.java

@@ -1,5 +1,6 @@
1 1
 package com.ruoyi.web.modules.screen.controller;
2 2
 
3
+import static org.mockito.ArgumentMatchers.eq;
3 4
 import static org.mockito.Mockito.when;
4 5
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
5 6
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
@@ -7,6 +8,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
7 8
 
8 9
 import java.math.BigDecimal;
9 10
 import java.util.Arrays;
11
+import java.util.Collections;
10 12
 import java.util.HashSet;
11 13
 import java.util.Set;
12 14
 import org.junit.jupiter.api.AfterEach;
@@ -23,11 +25,16 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio
23 25
 import org.springframework.security.core.context.SecurityContextHolder;
24 26
 import org.springframework.test.web.servlet.MockMvc;
25 27
 import org.springframework.test.web.servlet.setup.MockMvcBuilders;
28
+import com.github.pagehelper.PageHelper;
26 29
 import com.ruoyi.common.constant.Constants;
27 30
 import com.ruoyi.common.core.domain.entity.SysUser;
28 31
 import com.ruoyi.common.core.domain.model.LoginUser;
29 32
 import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceDashboardVo;
30 33
 import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceOverviewVo;
34
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceProductOutputListItemVo;
35
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceThreeAssetsProblemListItemVo;
36
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceVaccinationListItemVo;
37
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceVetCountListItemVo;
31 38
 import com.ruoyi.web.modules.screen.service.ILivestockResourceScreenService;
32 39
 
33 40
 /**
@@ -57,6 +64,7 @@ class LivestockResourceScreenControllerApiTest
57 64
     void tearDown()
58 65
     {
59 66
         SecurityContextHolder.clearContext();
67
+        PageHelper.clearPage();
60 68
     }
61 69
 
62 70
     @Test
@@ -73,6 +81,111 @@ class LivestockResourceScreenControllerApiTest
73 81
                 .andExpect(jsonPath("$.data.overview.vetCount").value(15));
74 82
     }
75 83
 
84
+    @Test
85
+    @DisplayName("DP-XM-API-025 GET threeAssetsProblemReports 明细分页")
86
+    void api025_threeAssetsProblemReports() throws Exception
87
+    {
88
+        LivestockResourceThreeAssetsProblemListItemVo item = new LivestockResourceThreeAssetsProblemListItemVo();
89
+        item.setTownName("巴青镇");
90
+        item.setVillageName("某村");
91
+        item.setProblemLevel("general");
92
+        item.setProblemLevelName("一般");
93
+        item.setProblemDetail("描述");
94
+        item.setHandleResult("处理中");
95
+        when(livestockResourceScreenService.listThreeAssetsProblemReports(eq(2026), eq(101L), eq(201L)))
96
+                .thenReturn(Collections.singletonList(item));
97
+        mockMvc.perform(get("/bigScreen/livestockResource/threeAssetsProblemReports")
98
+                        .param("statYear", "2026")
99
+                        .param("townDeptId", "101")
100
+                        .param("villageDeptId", "201")
101
+                        .param("pageNum", "1")
102
+                        .param("pageSize", "10"))
103
+                .andExpect(status().isOk())
104
+                .andExpect(jsonPath("$.code").value(200))
105
+                .andExpect(jsonPath("$.rows[0].townName").value("巴青镇"))
106
+                .andExpect(jsonPath("$.rows[0].problemLevelName").value("一般"))
107
+                .andExpect(jsonPath("$.rows[0].problemDetail").value("描述"));
108
+    }
109
+
110
+    @Test
111
+    @DisplayName("DP-XM-API-026 GET productOutputs 明细分页")
112
+    void api026_productOutputs() throws Exception
113
+    {
114
+        LivestockResourceProductOutputListItemVo item = new LivestockResourceProductOutputListItemVo();
115
+        item.setStatYear(2026);
116
+        item.setStatMonth(7);
117
+        item.setTownName("巴青镇");
118
+        item.setVillageName("某村");
119
+        item.setMeatOutput(new BigDecimal("1.2000"));
120
+        item.setMilkOutput(new BigDecimal("3.4000"));
121
+        when(livestockResourceScreenService.listProductOutputs(eq(2026), eq(7), eq(101L), eq(201L)))
122
+                .thenReturn(Collections.singletonList(item));
123
+        mockMvc.perform(get("/bigScreen/livestockResource/productOutputs")
124
+                        .param("statYear", "2026")
125
+                        .param("statMonth", "7")
126
+                        .param("townDeptId", "101")
127
+                        .param("villageDeptId", "201")
128
+                        .param("pageNum", "1")
129
+                        .param("pageSize", "10"))
130
+                .andExpect(status().isOk())
131
+                .andExpect(jsonPath("$.code").value(200))
132
+                .andExpect(jsonPath("$.rows[0].statYear").value(2026))
133
+                .andExpect(jsonPath("$.rows[0].statMonth").value(7))
134
+                .andExpect(jsonPath("$.rows[0].townName").value("巴青镇"))
135
+                .andExpect(jsonPath("$.rows[0].meatOutput").value(1.2))
136
+                .andExpect(jsonPath("$.rows[0].milkOutput").value(3.4));
137
+    }
138
+
139
+    @Test
140
+    @DisplayName("DP-XM-API-027 GET vaccinationData 明细分页")
141
+    void api027_vaccinationData() throws Exception
142
+    {
143
+        LivestockResourceVaccinationListItemVo item = new LivestockResourceVaccinationListItemVo();
144
+        item.setStatYear(2026);
145
+        item.setStatMonth(7);
146
+        item.setTownName("巴青镇");
147
+        item.setVillageName("某村");
148
+        item.setShouldVaccinateCount(100);
149
+        item.setActualVaccinateCount(80);
150
+        item.setImmunityRate(new BigDecimal("80.00"));
151
+        when(livestockResourceScreenService.listVaccinationData(eq(2026), eq(7), eq(101L), eq(201L)))
152
+                .thenReturn(Collections.singletonList(item));
153
+        mockMvc.perform(get("/bigScreen/livestockResource/vaccinationData")
154
+                        .param("statYear", "2026")
155
+                        .param("statMonth", "7")
156
+                        .param("townDeptId", "101")
157
+                        .param("villageDeptId", "201")
158
+                        .param("pageNum", "1")
159
+                        .param("pageSize", "10"))
160
+                .andExpect(status().isOk())
161
+                .andExpect(jsonPath("$.code").value(200))
162
+                .andExpect(jsonPath("$.rows[0].statYear").value(2026))
163
+                .andExpect(jsonPath("$.rows[0].statMonth").value(7))
164
+                .andExpect(jsonPath("$.rows[0].townName").value("巴青镇"))
165
+                .andExpect(jsonPath("$.rows[0].shouldVaccinateCount").value(100))
166
+                .andExpect(jsonPath("$.rows[0].actualVaccinateCount").value(80))
167
+                .andExpect(jsonPath("$.rows[0].immunityRate").value(80.0));
168
+    }
169
+
170
+    @Test
171
+    @DisplayName("DP-XM-API-028 GET vetCounts 按乡镇汇总")
172
+    void api028_vetCounts() throws Exception
173
+    {
174
+        LivestockResourceVetCountListItemVo item = new LivestockResourceVetCountListItemVo();
175
+        item.setTownName("巴青镇");
176
+        item.setVetCount(15L);
177
+        when(livestockResourceScreenService.listVetCounts(eq(101L)))
178
+                .thenReturn(Collections.singletonList(item));
179
+        mockMvc.perform(get("/bigScreen/livestockResource/vetCounts")
180
+                        .param("townDeptId", "101")
181
+                        .param("pageNum", "1")
182
+                        .param("pageSize", "10"))
183
+                .andExpect(status().isOk())
184
+                .andExpect(jsonPath("$.code").value(200))
185
+                .andExpect(jsonPath("$.rows[0].townName").value("巴青镇"))
186
+                .andExpect(jsonPath("$.rows[0].vetCount").value(15));
187
+    }
188
+
76 189
     @Test
77 190
     @DisplayName("DP-XM-API-024 statYear 回显")
78 191
     void api024_statYearEcho() throws Exception

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

@@ -16,12 +16,22 @@ import org.junit.jupiter.api.extension.ExtendWith;
16 16
 import org.mockito.InjectMocks;
17 17
 import org.mockito.Mock;
18 18
 import org.mockito.junit.jupiter.MockitoExtension;
19
+import com.ruoyi.web.modules.industryservice.domain.BizLivestockProductOutput;
20
+import com.ruoyi.web.modules.industryservice.domain.BizThreeAssetsProblemReport;
21
+import com.ruoyi.web.modules.industryservice.domain.BizVaccinationData;
22
+import com.ruoyi.web.modules.industryservice.mapper.BizLivestockProductOutputMapper;
23
+import com.ruoyi.web.modules.industryservice.mapper.BizThreeAssetsProblemReportMapper;
24
+import com.ruoyi.web.modules.industryservice.mapper.BizVaccinationDataMapper;
19 25
 import com.ruoyi.web.modules.screen.domain.dto.HomeScreenStatPeriodDto;
20 26
 import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceProductOutputSumDto;
21 27
 import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceTechPersonnelDto;
22 28
 import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceThreeAssetsSumDto;
23 29
 import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceVaccinationSumDto;
24 30
 import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceDashboardVo;
31
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceProductOutputListItemVo;
32
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceThreeAssetsProblemListItemVo;
33
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceVaccinationListItemVo;
34
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceVetCountListItemVo;
25 35
 import com.ruoyi.web.modules.screen.mapper.HomeScreenStatsMapper;
26 36
 import com.ruoyi.web.modules.screen.mapper.LivestockResourceScreenMapper;
27 37
 
@@ -35,6 +45,15 @@ class LivestockResourceScreenServiceImplTest
35 45
     @Mock
36 46
     private HomeScreenStatsMapper homeScreenStatsMapper;
37 47
 
48
+    @Mock
49
+    private BizThreeAssetsProblemReportMapper bizThreeAssetsProblemReportMapper;
50
+
51
+    @Mock
52
+    private BizLivestockProductOutputMapper bizLivestockProductOutputMapper;
53
+
54
+    @Mock
55
+    private BizVaccinationDataMapper bizVaccinationDataMapper;
56
+
38 57
     @InjectMocks
39 58
     private LivestockResourceScreenServiceImpl service;
40 59
 
@@ -159,4 +178,96 @@ class LivestockResourceScreenServiceImplTest
159 178
         assertEquals(new BigDecimal("0.00"), vo.getVaccinationOverview().getImmunityRate());
160 179
         assertEquals("2020-12-31", vo.getStatDate());
161 180
     }
181
+
182
+    @Test
183
+    @DisplayName("三资问题上报明细默认当前年并组装字段")
184
+    void listThreeAssetsProblemReports()
185
+    {
186
+        BizThreeAssetsProblemReport row = new BizThreeAssetsProblemReport();
187
+        row.setTownName("巴青镇");
188
+        row.setVillageName("某村");
189
+        row.setProblemLevel("key");
190
+        row.setProblemDetail("道路硬化问题");
191
+        row.setHandleResult("已整改");
192
+        when(bizThreeAssetsProblemReportMapper.selectBizThreeAssetsProblemReportList(any()))
193
+                .thenReturn(Collections.singletonList(row));
194
+
195
+        java.util.List<LivestockResourceThreeAssetsProblemListItemVo> list =
196
+                service.listThreeAssetsProblemReports(2026, 101L, 201L);
197
+        assertEquals(1, list.size());
198
+        assertEquals("巴青镇", list.get(0).getTownName());
199
+        assertEquals("某村", list.get(0).getVillageName());
200
+        assertEquals("key", list.get(0).getProblemLevel());
201
+        assertEquals("重点", list.get(0).getProblemLevelName());
202
+        assertEquals("道路硬化问题", list.get(0).getProblemDetail());
203
+        assertEquals("已整改", list.get(0).getHandleResult());
204
+    }
205
+
206
+    @Test
207
+    @DisplayName("DP-XM-UT-009 产量明细分页")
208
+    void listProductOutputs()
209
+    {
210
+        BizLivestockProductOutput row = new BizLivestockProductOutput();
211
+        row.setStatYear(2026);
212
+        row.setStatMonth(7);
213
+        row.setTownName("巴青镇");
214
+        row.setVillageName("某村");
215
+        row.setMeatOutput(new BigDecimal("1.2"));
216
+        row.setMilkOutput(new BigDecimal("3.4"));
217
+        when(bizLivestockProductOutputMapper.selectBizLivestockProductOutputList(any()))
218
+                .thenReturn(Collections.singletonList(row));
219
+
220
+        java.util.List<LivestockResourceProductOutputListItemVo> list =
221
+                service.listProductOutputs(2026, 7, 101L, 201L);
222
+        assertEquals(1, list.size());
223
+        assertEquals(2026, list.get(0).getStatYear());
224
+        assertEquals(7, list.get(0).getStatMonth());
225
+        assertEquals("巴青镇", list.get(0).getTownName());
226
+        assertEquals("某村", list.get(0).getVillageName());
227
+        assertEquals(new BigDecimal("1.2000"), list.get(0).getMeatOutput());
228
+        assertEquals(new BigDecimal("3.4000"), list.get(0).getMilkOutput());
229
+    }
230
+
231
+    @Test
232
+    @DisplayName("DP-XM-UT-010 疫苗接种明细分页")
233
+    void listVaccinationData()
234
+    {
235
+        BizVaccinationData row = new BizVaccinationData();
236
+        row.setStatYear(2026);
237
+        row.setStatMonth(7);
238
+        row.setTownName("巴青镇");
239
+        row.setVillageName("某村");
240
+        row.setShouldVaccinateCount(100);
241
+        row.setActualVaccinateCount(80);
242
+        row.setImmunityRate(new BigDecimal("80.00"));
243
+        when(bizVaccinationDataMapper.selectBizVaccinationDataList(any()))
244
+                .thenReturn(Collections.singletonList(row));
245
+
246
+        java.util.List<LivestockResourceVaccinationListItemVo> list =
247
+                service.listVaccinationData(2026, 7, 101L, 201L);
248
+        assertEquals(1, list.size());
249
+        assertEquals(2026, list.get(0).getStatYear());
250
+        assertEquals(7, list.get(0).getStatMonth());
251
+        assertEquals("巴青镇", list.get(0).getTownName());
252
+        assertEquals("某村", list.get(0).getVillageName());
253
+        assertEquals(100, list.get(0).getShouldVaccinateCount());
254
+        assertEquals(80, list.get(0).getActualVaccinateCount());
255
+        assertEquals(new BigDecimal("80.00"), list.get(0).getImmunityRate());
256
+    }
257
+
258
+    @Test
259
+    @DisplayName("DP-XM-UT-011 兽医数量按乡镇汇总")
260
+    void listVetCounts()
261
+    {
262
+        LivestockResourceVetCountListItemVo row = new LivestockResourceVetCountListItemVo();
263
+        row.setTownName("巴青镇");
264
+        row.setVetCount(15L);
265
+        when(livestockResourceScreenMapper.selectVetCountByTown(eq(101L)))
266
+                .thenReturn(Collections.singletonList(row));
267
+
268
+        java.util.List<LivestockResourceVetCountListItemVo> list = service.listVetCounts(101L);
269
+        assertEquals(1, list.size());
270
+        assertEquals("巴青镇", list.get(0).getTownName());
271
+        assertEquals(15L, list.get(0).getVetCount());
272
+    }
162 273
 }

+ 48 - 0
baqing-admin/src/test/java/com/ruoyi/web/modules/screen/support/LivestockResourceScreenSupportTest.java

@@ -28,9 +28,12 @@ import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceCategoryShareVo;
28 28
 import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceHourlyHeatVo;
29 29
 import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceOverviewVo;
30 30
 import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceProblemReportShareVo;
31
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceProductOutputListItemVo;
31 32
 import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceProductOutputTrendVo;
32 33
 import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceReplyStatusVo;
33 34
 import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceTechEnvoyStructureVo;
35
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceThreeAssetsProblemListItemVo;
36
+import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceVaccinationListItemVo;
34 37
 import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceVaccinationOverviewVo;
35 38
 
36 39
 /**
@@ -110,6 +113,51 @@ class LivestockResourceScreenSupportTest
110 113
         assertEquals(3, share.getItems().size());
111 114
         assertEquals(new BigDecimal("100.0"), share.getItems().get(1).getRatio());
112 115
 
116
+        com.ruoyi.web.modules.industryservice.domain.BizThreeAssetsProblemReport problem =
117
+                new com.ruoyi.web.modules.industryservice.domain.BizThreeAssetsProblemReport();
118
+        problem.setTownName("巴青镇");
119
+        problem.setVillageName("某村");
120
+        problem.setProblemLevel("major");
121
+        problem.setProblemDetail("详情");
122
+        problem.setHandleResult("已处理");
123
+        LivestockResourceThreeAssetsProblemListItemVo problemItem =
124
+                LivestockResourceScreenSupport.buildThreeAssetsProblemListItems(
125
+                        Collections.singletonList(problem)).get(0);
126
+        assertEquals("巴青镇", problemItem.getTownName());
127
+        assertEquals("重大", problemItem.getProblemLevelName());
128
+        assertEquals("详情", problemItem.getProblemDetail());
129
+
130
+        com.ruoyi.web.modules.industryservice.domain.BizLivestockProductOutput output =
131
+                new com.ruoyi.web.modules.industryservice.domain.BizLivestockProductOutput();
132
+        output.setStatYear(2026);
133
+        output.setStatMonth(7);
134
+        output.setTownName("巴青镇");
135
+        output.setVillageName("某村");
136
+        output.setMeatOutput(new BigDecimal("1.2"));
137
+        output.setMilkOutput(new BigDecimal("3.4"));
138
+        LivestockResourceProductOutputListItemVo outputItem =
139
+                LivestockResourceScreenSupport.buildProductOutputListItems(
140
+                        Collections.singletonList(output)).get(0);
141
+        assertEquals(2026, outputItem.getStatYear());
142
+        assertEquals(7, outputItem.getStatMonth());
143
+        assertEquals(new BigDecimal("1.2000"), outputItem.getMeatOutput());
144
+        assertEquals(new BigDecimal("3.4000"), outputItem.getMilkOutput());
145
+
146
+        com.ruoyi.web.modules.industryservice.domain.BizVaccinationData vaccRow =
147
+                new com.ruoyi.web.modules.industryservice.domain.BizVaccinationData();
148
+        vaccRow.setStatYear(2026);
149
+        vaccRow.setStatMonth(7);
150
+        vaccRow.setTownName("巴青镇");
151
+        vaccRow.setVillageName("某村");
152
+        vaccRow.setShouldVaccinateCount(100);
153
+        vaccRow.setActualVaccinateCount(80);
154
+        LivestockResourceVaccinationListItemVo vaccItem =
155
+                LivestockResourceScreenSupport.buildVaccinationListItems(
156
+                        Collections.singletonList(vaccRow)).get(0);
157
+        assertEquals(100, vaccItem.getShouldVaccinateCount());
158
+        assertEquals(80, vaccItem.getActualVaccinateCount());
159
+        assertEquals(new BigDecimal("80.00"), vaccItem.getImmunityRate());
160
+
113 161
         LivestockResourceProductOutputMonthDto m3 = new LivestockResourceProductOutputMonthDto();
114 162
         m3.setStatMonth(3);
115 163
         m3.setMeatOutput(new BigDecimal("1"));

+ 129 - 2
doc/大屏/畜牧资源/大屏畜牧资源技术方案.md

@@ -214,9 +214,13 @@ XML:`mapper/screen/LivestockResourceScreenMapper.xml`。
214 214
 
215 215
 | # | 说明 | Method | URI |
216 216
 | --- | --- | --- | --- |
217
-| 3.1 | 看板主数据(十区块合一) | GET | `/bigScreen/livestockResource/dashboard` |
217
+| 3.1 | 看板主数据 | GET | `/bigScreen/livestockResource/dashboard` |
218
+| 3.2 | 三资具体问题上报明细 | GET | `/bigScreen/livestockResource/threeAssetsProblemReports` |
219
+| 3.3 | 畜牧产品产量数据明细 | GET | `/bigScreen/livestockResource/productOutputs` |
220
+| 3.4 | 疫苗接种情况明细 | GET | `/bigScreen/livestockResource/vaccinationData` |
221
+| 3.5 | 兽医数量明细 | GET | `/bigScreen/livestockResource/vetCounts` |
218 222
 
219
-前端:进入页 / 切换 `statYear` / 刷新 → 仅 **3.1**。
223
+前端:进入页 / 切换 `statYear` / 刷新 → **3.1**;点问题上报区块看明细 → **3.2**;点产量区块看明细 → **3.3**;点疫苗区块看明细 → **3.4**;点兽医指标看明细 → **3.5**。
220 224
 
221 225
 ---
222 226
 
@@ -422,6 +426,125 @@ XML:`mapper/screen/LivestockResourceScreenMapper.xml`。
422 426
 
423 427
 ---
424 428
 
429
+### 3.2 三资具体问题上报明细
430
+
431
+**URI**:`GET /bigScreen/livestockResource/threeAssetsProblemReports`  
432
+**分页**:若依 `startPage()` / `TableDataInfo`(`pageNum`/`pageSize`)  
433
+**排序**:`report_time` 倒序(同表既有 list SQL)
434
+
435
+#### Query
436
+
437
+| 参数 | 类型 | 必填 | 说明 |
438
+| --- | --- | --- | --- |
439
+| `statYear` | int | N | 所属年份;未传默认**当前自然年**;按 `report_time` 落在该年 1-1~12-31 |
440
+| `townDeptId` | long | N | 所属乡镇 |
441
+| `villageDeptId` | long | N | 所属村 |
442
+| `pageNum` / `pageSize` | int | N | 分页 |
443
+
444
+#### 响应 `rows[]`
445
+
446
+| 字段 | 类型 | 说明 |
447
+| --- | --- | --- |
448
+| `reportTime` | string | 上报时间 `yyyy-MM-dd HH:mm:ss` |
449
+| `townName` | string | 乡镇 |
450
+| `villageName` | string | 村 |
451
+| `problemLevel` | string | 等级编码 `general`/`key`/`major` |
452
+| `problemLevelName` | string | 等级名称 一般/重点/重大 |
453
+| `problemDetail` | string | 问题详细描述 |
454
+| `handleResult` | string | 处理结果 |
455
+
456
+数据源:`biz_three_assets_problem_report`;大屏全县口径(清空 `dataScope`)。
457
+
458
+---
459
+
460
+### 3.3 畜牧产品产量数据明细
461
+
462
+**URI**:`GET /bigScreen/livestockResource/productOutputs`  
463
+**分页**:若依 `startPage()` / `TableDataInfo`(`pageNum`/`pageSize`)  
464
+**排序**:`stat_year`、`stat_month` 倒序(同表既有 list SQL)
465
+
466
+#### Query
467
+
468
+| 参数 | 类型 | 必填 | 说明 |
469
+| --- | --- | --- | --- |
470
+| `statYear` | int | N | 所属年份;未传默认**当前自然年** |
471
+| `statMonth` | int | N | 所属月份;未传默认**当前自然月** |
472
+| `townDeptId` | long | N | 所属乡镇 |
473
+| `villageDeptId` | long | N | 所属村 |
474
+| `pageNum` / `pageSize` | int | N | 分页 |
475
+
476
+#### 响应 `rows[]`
477
+
478
+| 字段 | 类型 | 说明 |
479
+| --- | --- | --- |
480
+| `statYear` | int | 所属年份 |
481
+| `statMonth` | int | 所属月份 |
482
+| `townName` | string | 乡镇 |
483
+| `villageName` | string | 村 |
484
+| `meatOutput` | number | 肉产量(万吨),4 位小数 |
485
+| `milkOutput` | number | 奶产量(万吨),4 位小数 |
486
+
487
+数据源:`biz_livestock_product_output`;大屏全县口径(清空 `dataScope`)。
488
+
489
+---
490
+
491
+### 3.4 疫苗接种情况明细
492
+
493
+**URI**:`GET /bigScreen/livestockResource/vaccinationData`  
494
+**分页**:若依 `startPage()` / `TableDataInfo`(`pageNum`/`pageSize`)  
495
+**排序**:`stat_year`、`stat_month` 倒序(同表既有 list SQL)
496
+
497
+#### Query
498
+
499
+| 参数 | 类型 | 必填 | 说明 |
500
+| --- | --- | --- | --- |
501
+| `statYear` | int | N | 所属年份;未传默认**当前自然年** |
502
+| `statMonth` | int | N | 所属月份;未传默认**当前自然月** |
503
+| `townDeptId` | long | N | 所属乡镇 |
504
+| `villageDeptId` | long | N | 所属村 |
505
+| `pageNum` / `pageSize` | int | N | 分页 |
506
+
507
+#### 响应 `rows[]`
508
+
509
+| 字段 | 类型 | 说明 |
510
+| --- | --- | --- |
511
+| `statYear` | int | 所属年份 |
512
+| `statMonth` | int | 所属月份 |
513
+| `townName` | string | 乡镇 |
514
+| `villageName` | string | 村 |
515
+| `shouldVaccinateCount` | int | 应免数(头) |
516
+| `actualVaccinateCount` | int | 实免数(头) |
517
+| `immunityRate` | number | 免疫率 %,2 位小数;(实免/应免)×100 |
518
+
519
+数据源:`biz_vaccination_data`;大屏全县口径(清空 `dataScope`)。
520
+
521
+---
522
+
523
+### 3.5 兽医数量明细
524
+
525
+**URI**:`GET /bigScreen/livestockResource/vetCounts`  
526
+**分页**:若依 `startPage()` / `TableDataInfo`(`pageNum`/`pageSize`)  
527
+**排序**:乡镇部门 `order_num`、`town_dept_id` 升序  
528
+**粒度**:按乡镇汇总人数(非人员明细行)
529
+
530
+#### Query
531
+
532
+| 参数 | 类型 | 必填 | 说明 |
533
+| --- | --- | --- | --- |
534
+| `townDeptId` | long | N | 所属乡镇 |
535
+| `pageNum` / `pageSize` | int | N | 分页 |
536
+
537
+#### 响应 `rows[]`
538
+
539
+| 字段 | 类型 | 说明 |
540
+| --- | --- | --- |
541
+| `townName` | string | 乡镇 |
542
+| `vetCount` | long | 数量(人) |
543
+
544
+数据源:`biz_medical_resource`;口径 `resource_type='004001'` 且 `del_flag='0'`(与总览兽医人数一致)。
545
+
546
+---
547
+
425 548
 ## 4. 菜单与权限(示例)
426 549
 
427 550
 | 类型 | 名称 | 权限标识 |
@@ -447,6 +570,10 @@ SQL 示例:`sql/big_screen_livestock_resource_perm.sql`(挂载「大屏」
447 570
 
448 571
 | 版本 | 日期 | 说明 |
449 572
 | --- | --- | --- |
573
+| 1.15 | 2026-07-24 | 新增兽医数量明细分页接口 `/vetCounts`(按乡镇汇总) |
574
+| 1.14 | 2026-07-24 | 新增疫苗接种情况明细分页接口 `/vaccinationData` |
575
+| 1.13 | 2026-07-24 | 新增畜牧产品产量数据明细分页接口 `/productOutputs` |
576
+| 1.12 | 2026-07-24 | 新增三资具体问题上报明细分页接口 `/threeAssetsProblemReports` |
450 577
 | 1.11 | 2026-07-24 | 看板屏蔽 AI 问诊九区块:活跃度/用户结构/分类/模型调用/分时/会话分布/状态/热门/关键词 |
451 578
 | 1.10 | 2026-07-24 | 线下服务预约三项汇总改为资源台账:兽医 004001、机构 004003、专家 004005 |
452 579
 | 1.9 | 2026-07-24 | 线下服务预约月度改为所选年 1~最大月 |